diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000000..0d0be3be9b --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,21 @@ +name: linux + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Prepare + run: cmake -B ${{github.workspace}}/build -DDEBUG=1 -DTESTS=1 + + - name: Build & Test + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --target Experimental diff --git a/.gitignore b/.gitignore index fd7106669d..773dcd56ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,17 @@ /.project *.pyc */__pycache__ -private/ +private*/ *~ \#* .\#* *.mo CMakeLists.txt.user -user/ +user*/ +build/ +.cproject +.settings/ +/.vscode +/.idea +cmake-build-debug/ + diff --git a/CMakeLists.txt b/CMakeLists.txt index a1eb081db8..021733e076 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -28,12 +28,17 @@ ############################################################################ # Validate CMake version. -cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) if(COMMAND CMAKE_POLICY) cmake_policy(SET CMP0003 NEW) endif(COMMAND CMAKE_POLICY) +# Required C++ Standard. +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + include(cmake/Toolchain.cmake) ########################################################################## @@ -43,10 +48,10 @@ project("DUNE") set(PROJECT_NAME "DUNE: Unified Navigation Environment") set(PROJECT_SHORT_NAME "DUNE") set(PROJECT_VENDOR "Universidade do Porto - LSTS") -set(PROJECT_COPYRIGHT "Copyright (C) 2007-2017 - ${PROJECT_VENDOR}") +set(PROJECT_COPYRIGHT "Copyright (C) 2007-2023 - ${PROJECT_VENDOR}") set(PROJECT_CONTACT "DUNE ") -set(PROJECT_VERSION_YEAR "2017") -set(PROJECT_VERSION_MONTH "01") +set(PROJECT_VERSION_YEAR "2022") +set(PROJECT_VERSION_MONTH "04") set(PROJECT_VERSION_PATCH "0") set(PROJECT_VERSION_RCN "0") @@ -88,8 +93,12 @@ dune_option(JS "Enable support for SpiderMonkey javascript engine") dune_option(XENETH "Enable support for the Xeneth SDK") dune_option(BLUEVIEW "Enable support for the BlueView SDK") dune_option(OPENCV "Enable support for OpenCV") +dune_option(POINTGREY "Enable support for POINTGREY") +dune_option(EXIV2 "Enable support for Exiv2") dune_option(NO_RTTI "Disable support for RTTI") dune_option(UEYE "Enable support for IDS uEye cameras") +dune_option(H5CPP "Enable support for hdf5 format i/o using the h5cpp library") +dune_option(ELLIPSOIDAL "Enable ellipsoidal coordinates in (WGS84) displace") # Internationalization. include(${PROJECT_SOURCE_DIR}/cmake/I18N.cmake) @@ -159,6 +168,10 @@ file(GLOB_RECURSE DUNE_CORE_HEADERS "${PROJECT_SOURCE_DIR}/src/DUNE/*.hpp" file(GLOB_RECURSE DUNE_CORE_DEFS "${PROJECT_SOURCE_DIR}/src/DUNE/*.def") string(REPLACE ";" " " DUNE_CORE_HEADERS_STRING "${DUNE_CORE_HEADERS}") +file(GLOB_RECURSE USER_CORE_SOURCES "${PROJECT_SOURCE_DIR}/user*/src/USER/*.cpp") +file(GLOB_RECURSE USER_CORE_HEADERS "${PROJECT_SOURCE_DIR}/user*/src/USER/*.hpp") +string(REPLACE ";" " " USER_CORE_HEADERS_STRING "${USER_CORE_HEADERS}") + configure_file(${PROJECT_SOURCE_DIR}/src/DUNE/Config.hpp.in ${DUNE_GENERATED}/src/DUNE/Config.hpp) @@ -167,7 +180,7 @@ install(FILES ${DUNE_GENERATED}/src/DUNE/Config.hpp include(${PROJECT_SOURCE_DIR}/cmake/Version.cmake) -set_source_files_properties(${DUNE_CORE_SOURCES} +set_source_files_properties(${DUNE_CORE_SOURCES} ${USER_CORE_SOURCES} PROPERTIES COMPILE_FLAGS "${DUNE_CXX_FLAGS} ${DUNE_CXX_FLAGS_STRICT}") if(DUNE_OS_WINDOWS) @@ -178,7 +191,7 @@ if(DUNE_OS_WINDOWS) ${DUNE_GENERATED}/src/DUNE/Version.rc) endif(DUNE_OS_WINDOWS) -foreach(header ${DUNE_CORE_HEADERS}) +foreach(header ${DUNE_CORE_HEADERS} ${USER_CORE_HEADERS}) string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/" "" header ${header}) string(REGEX REPLACE "src" "include" destination ${header}) get_filename_component(destination ${destination} PATH) @@ -192,29 +205,31 @@ foreach(extlib ${extlibs}) endforeach(extlib ${extlibs}) # Private Libraries. -file(GLOB extlibs ${PROJECT_SOURCE_DIR}/private/vendor/libraries/*/Library.cmake) +file(GLOB extlibs ${PROJECT_SOURCE_DIR}/private*/vendor/libraries/*/Library.cmake) foreach(extlib ${extlibs}) include(${extlib}) endforeach(extlib ${extlibs}) # User Libraries. -file(GLOB extlibs ${PROJECT_SOURCE_DIR}/user/vendor/libraries/*/Library.cmake) +file(GLOB extlibs ${PROJECT_SOURCE_DIR}/user*/vendor/libraries/*/Library.cmake) foreach(extlib ${extlibs}) include(${extlib}) endforeach(extlib ${extlibs}) -include_directories(${DUNE_GENERATED}/src ${PROJECT_SOURCE_DIR}/src ${DUNE_VENDOR_INCS_DIR}) +file(GLOB DUNE_SOURCE_USER ${PROJECT_SOURCE_DIR}/user*/src) +include_directories(${DUNE_GENERATED}/src ${PROJECT_SOURCE_DIR}/src ${DUNE_SOURCE_USER} ${DUNE_VENDOR_INCS_DIR}) link_directories(${DUNE_VENDOR_LIBS_DIR}) set(DUNE_CORE_FILES ${DUNE_CORE_SOURCES} ${DUNE_VENDOR_FILES}) +set(USER_CORE_FILES ${USER_CORE_SOURCES} ${USER_VENDOR_FILES}) if(DUNE_SHARED) message(STATUS "Building shared library") - add_library(dune-core SHARED ${DUNE_CORE_FILES}) + add_library(dune-core SHARED ${DUNE_CORE_FILES} ${USER_CORE_FILES} ) set_target_properties(dune-core PROPERTIES DEFINE_SYMBOL DUNE_DLL_EXPORT) target_link_libraries(dune-core ${DUNE_SYS_LIBS}) else(DUNE_SHARED) message(STATUS "Building static library") - add_library(dune-core STATIC ${DUNE_CORE_FILES}) + add_library(dune-core STATIC ${DUNE_CORE_FILES} ${USER_CORE_FILES} ) if(DUNE_CXX_MICROSOFT AND DUNE_CPU_X86) if(DUNE_CPU_32B) set_target_properties(dune-core PROPERTIES STATIC_LIBRARY_FLAGS "/machine:x86") @@ -226,6 +241,11 @@ endif(DUNE_SHARED) add_dependencies(dune-core dune-version) +# WGS84 Coordinate Type +if(ELLIPSOIDAL) + add_definitions(-DDUNE_ELLIPSOIDAL_DISPLACE) +endif(ELLIPSOIDAL) + ########################################################################## # Tasks # ########################################################################## @@ -325,6 +345,11 @@ install(DIRECTORY www DESTINATION .) # Install configuration files. install(DIRECTORY etc DESTINATION .) +if(EXISTS "${PROJECT_SOURCE_DIR}/private/etc/") + # Install private configuration files. + install(DIRECTORY private/etc DESTINATION ./private/) +endif(EXISTS "${PROJECT_SOURCE_DIR}/private/etc/") + if(EXISTS "${PROJECT_SOURCE_DIR}/user/etc/") # Install user configuration files. install(DIRECTORY user/etc DESTINATION ./user/) diff --git a/CTestConfig.cmake b/CTestConfig.cmake index 5a9472c2a9..ee1acac332 100644 --- a/CTestConfig.cmake +++ b/CTestConfig.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/LICENCE.md b/LICENCE.md index 51a8a7c3d4..0e118b4492 100644 --- a/LICENCE.md +++ b/LICENCE.md @@ -1,7 +1,7 @@ DUNE: Unified Navigation Environment ==================================== -DUNE © Universidade do Porto - Faculdade de Engenharia 2007-2017. +DUNE Copyright © 2007-2023 Universidade do Porto - Faculdade de Engenharia. Commercial Licence Usage ------------------------ diff --git a/README.md b/README.md index 366fe7ddba..2279b18ffe 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,6 @@ DUNE: Unified Navigation Environment ====================================== DUNE: Unified Navigation Environment is a runtime environment for unmanned systems on-board software. It is used to write generic embedded software at the heart of the system, e.g. code or control, navigation, communication, sensor and actuator access, etc. It provides an operating-system and architecture independent platform abstraction layer, written in C++, enhancing portability among different CPU architectures and operating systems. + +[![Build Status](https://travis-ci.org/LSTS/dune.svg?branch=master)](https://travis-ci.org/LSTS/dune) +[![Build status](https://ci.appveyor.com/api/projects/status/tdcdgyf408u4y0ng?svg=true)](https://ci.appveyor.com/project/zepinto/dune) diff --git a/cmake/Architecture.cmake b/cmake/Architecture.cmake index f791b1cb36..c2763f83af 100644 --- a/cmake/Architecture.cmake +++ b/cmake/Architecture.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/CXXLibrary.cmake b/cmake/CXXLibrary.cmake index 053ac9788d..168c64e835 100644 --- a/cmake/CXXLibrary.cmake +++ b/cmake/CXXLibrary.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Compiler.cmake b/cmake/Compiler.cmake index 0a9c4e5bd6..629c2df485 100644 --- a/cmake/Compiler.cmake +++ b/cmake/Compiler.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -72,7 +72,7 @@ macro(dune_probe_cxx) if(NOT DUNE_CXX_NAME) check_symbol_exists(__GNUC__ stdio.h DUNE_CXX_GNU) if(DUNE_CXX_GNU) - exec_program(${CMAKE_CXX_COMPILER} ARGS -dumpversion OUTPUT_VARIABLE verinfo) + exec_program(${CMAKE_CXX_COMPILER} ARGS -dumpfullversion -dumpversion OUTPUT_VARIABLE verinfo) string(REPLACE "." ";" gxxver ${verinfo}) list(GET gxxver 0 gxxmaj) list(GET gxxver 1 gxxmin) diff --git a/cmake/Functions.cmake b/cmake/Functions.cmake index d0a71f178e..481e5fe694 100644 --- a/cmake/Functions.cmake +++ b/cmake/Functions.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Headers.cmake b/cmake/Headers.cmake index 611d0bc5ac..449e60b3b2 100644 --- a/cmake/Headers.cmake +++ b/cmake/Headers.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -130,6 +130,7 @@ macro(dune_probe_headers) dune_test_header(sys/vfs.h) dune_test_header(sys/statvfs.h) dune_test_header(sys/syscall.h) + dune_test_header(sys/reboot.h) dune_test_header(termios.h) dune_test_header(unistd.h) dune_test_header(windows.h) @@ -148,6 +149,7 @@ macro(dune_probe_headers) dune_test_header(libintl.h) dune_test_header(syslog.h) dune_test_header(float.h) + dune_test_header(linux/pps.h) # A few systems/libraries have non self contained headers (notably # OpenBSD and RTEMS), to overcome this we perform the following diff --git a/cmake/I18N.cmake b/cmake/I18N.cmake index 8042535b0d..74a408a3ec 100644 --- a/cmake/I18N.cmake +++ b/cmake/I18N.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -53,10 +53,10 @@ endif(DUNE_PROGRAM_PYTHON) if(DUNE_PROGRAM_XGETTEXT) file(GLOB_RECURSE headers "${PROJECT_SOURCE_DIR}/src/*.hpp") file(GLOB_RECURSE sources "${PROJECT_SOURCE_DIR}/src/*.cpp") - file(GLOB_RECURSE private_headers "${PROJECT_SOURCE_DIR}/private/src/*.hpp") - file(GLOB_RECURSE private_sources "${PROJECT_SOURCE_DIR}/private/src/*.cpp") - file(GLOB_RECURSE user_headers "${PROJECT_SOURCE_DIR}/user/src/*.hpp") - file(GLOB_RECURSE user_sources "${PROJECT_SOURCE_DIR}/user/src/*.cpp") + file(GLOB_RECURSE private_headers "${PROJECT_SOURCE_DIR}/private*/src/*.hpp") + file(GLOB_RECURSE private_sources "${PROJECT_SOURCE_DIR}/private*/src/*.cpp") + file(GLOB_RECURSE user_headers "${PROJECT_SOURCE_DIR}/user*/src/*.hpp") + file(GLOB_RECURSE user_sources "${PROJECT_SOURCE_DIR}/user*/src/*.cpp") file(GLOB_RECURSE texts "${PROJECT_SOURCE_DIR}/i18n/*.txt") add_custom_target(i18n_extract diff --git a/cmake/IMC.cmake b/cmake/IMC.cmake index 13b34cfbc7..a434576d3b 100644 --- a/cmake/IMC.cmake +++ b/cmake/IMC.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/BVTSDK.cmake b/cmake/Libraries/BVTSDK.cmake index 018af5e4b3..443cdbe9ba 100644 --- a/cmake/Libraries/BVTSDK.cmake +++ b/cmake/Libraries/BVTSDK.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/DC1394.cmake b/cmake/Libraries/DC1394.cmake index 5ca83bebd4..eee9b6483d 100644 --- a/cmake/Libraries/DC1394.cmake +++ b/cmake/Libraries/DC1394.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/Exiv2.cmake b/cmake/Libraries/Exiv2.cmake new file mode 100644 index 0000000000..77ae8cad2a --- /dev/null +++ b/cmake/Libraries/Exiv2.cmake @@ -0,0 +1,50 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ + +if(EXIV2) + find_library(EXIV2_LIBRARY NAMES exiv2 PATHS /usr/lib) + + if(${EXIV2_LIBRARY} STRLESS "libexiv2.so") + # Exiv2 Present + set(DUNE_SYS_HAS_EXIV2 1 CACHE INTERNAL "Exiv2 library") + set(DUNE_USING_EXIV2 1 CACHE INTERNAL "Exiv2 library") + + # FIND_PACKAGE(Exiv2 REQUIRED) + dune_add_lib(exiv2) + + # Check Header + dune_test_header(exiv2/exiv2.hpp) + + else() + # Exiv2 not found on the system. + message(SEND_ERROR "Exiv2 was not found on the system.") + set(DUNE_SYS_HAS_EXIV2 0 CACHE INTERNAL "Exiv2 library") + set(DUNE_USING_EXIV2 0 CACHE INTERNAL "Exiv2 library") + + endif() + +endif(EXIV2) diff --git a/cmake/Libraries/FTD2XX.cmake b/cmake/Libraries/FTD2XX.cmake index da818832e3..174724f9bb 100644 --- a/cmake/Libraries/FTD2XX.cmake +++ b/cmake/Libraries/FTD2XX.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # diff --git a/cmake/Libraries/JPEG.cmake b/cmake/Libraries/JPEG.cmake index 3fe476c870..2c19aa2bdb 100644 --- a/cmake/Libraries/JPEG.cmake +++ b/cmake/Libraries/JPEG.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/MCCUSB.cmake b/cmake/Libraries/MCCUSB.cmake index c9df314386..dfade51b0b 100644 --- a/cmake/Libraries/MCCUSB.cmake +++ b/cmake/Libraries/MCCUSB.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # diff --git a/cmake/Libraries/OpenCV.cmake b/cmake/Libraries/OpenCV.cmake index 9710789c68..d060b761df 100644 --- a/cmake/Libraries/OpenCV.cmake +++ b/cmake/Libraries/OpenCV.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/Phidget.cmake b/cmake/Libraries/Phidget.cmake index 63b7229286..60f9d0c601 100644 --- a/cmake/Libraries/Phidget.cmake +++ b/cmake/Libraries/Phidget.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/PointGrey.cmake b/cmake/Libraries/PointGrey.cmake new file mode 100644 index 0000000000..979c0e0807 --- /dev/null +++ b/cmake/Libraries/PointGrey.cmake @@ -0,0 +1,51 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ + +if(POINTGREY) + CHECK_LIBRARY_EXISTS(flycapture-c GetInternal "" HAVE_LIB_FLYCAPTURE) + + if(HAVE_LIB_FLYCAPTURE) + # FlyCapture Present + set(DUNE_SYS_HAS_FLYCAPTURE 1 CACHE INTERNAL "FlyCapture library") + set(DUNE_USING_FLYCAPTURE 1 CACHE INTERNAL "FlyCapture library") + + + dune_add_lib(flycapture) + dune_add_lib(flycapture-c) + + # Check Header + dune_test_header(flycapture/FlyCapture2.h) + dune_test_header(flycapture/FlyCapture2_C.h) + + else(HAVE_LIB_FLYCAPTURE) + # FlyCapture not found on the system. + message(SEND_ERROR "FlyCapture was not found on the system.") + set(DUNE_SYS_HAS_FLYCAPTURE 0 CACHE INTERNAL "FlyCapture library") + set(DUNE_USING_FLYCAPTURE 0 CACHE INTERNAL "FlyCapture library") + endif(HAVE_LIB_FLYCAPTURE) + +endif(POINTGREY) diff --git a/cmake/Libraries/Qt5.cmake b/cmake/Libraries/Qt5.cmake index d9066a45b2..c8f09e4133 100644 --- a/cmake/Libraries/Qt5.cmake +++ b/cmake/Libraries/Qt5.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/SpiderMonkey.cmake b/cmake/Libraries/SpiderMonkey.cmake index b12da3b15e..84b5dc82fb 100644 --- a/cmake/Libraries/SpiderMonkey.cmake +++ b/cmake/Libraries/SpiderMonkey.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/Swiftnav.cmake b/cmake/Libraries/Swiftnav.cmake index 61eb85db6d..10b2a609d0 100644 --- a/cmake/Libraries/Swiftnav.cmake +++ b/cmake/Libraries/Swiftnav.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/V4L2.cmake b/cmake/Libraries/V4L2.cmake index f4fa6087f1..4c795c473b 100644 --- a/cmake/Libraries/V4L2.cmake +++ b/cmake/Libraries/V4L2.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/Xeneth.cmake b/cmake/Libraries/Xeneth.cmake index f4ffc5304a..a4008dee06 100644 --- a/cmake/Libraries/Xeneth.cmake +++ b/cmake/Libraries/Xeneth.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Libraries/h5cpp.cmake b/cmake/Libraries/h5cpp.cmake new file mode 100644 index 0000000000..d5f358296d --- /dev/null +++ b/cmake/Libraries/h5cpp.cmake @@ -0,0 +1,49 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Miguel Aguiar # +############################################################################ + +if(H5CPP) + find_package(h5cpp) + + if(${h5cpp_FOUND}) + dune_add_lib(h5cpp) + add_definitions(-DDUNE_H5CPP_ENABLED) + set(DUNE_USING_H5CPP + 1 + CACHE INTERNAL + "libh5cpp") + else() + message(SEND_ERROR "Library h5cpp not found on this system. " + "See https://github.com/ess-dmsc/h5cpp for installation " + "instructions.") + set(DUNE_USING_H5CPP + 0 + CACHE INTERNAL + "libh5cpp") + endif() +endif(H5CPP) diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake index 56403fcff5..11072b5102 100644 --- a/cmake/Macros.cmake +++ b/cmake/Macros.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/MinGW.cmake b/cmake/MinGW.cmake index 6aadd919e4..7329a64e71 100644 --- a/cmake/MinGW.cmake +++ b/cmake/MinGW.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/OperatingSystem.cmake b/cmake/OperatingSystem.cmake index 08eb7d65ed..b68e2f2ecf 100644 --- a/cmake/OperatingSystem.cmake +++ b/cmake/OperatingSystem.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Programs.cmake b/cmake/Programs.cmake index 36ab1be813..0d56dd604c 100644 --- a/cmake/Programs.cmake +++ b/cmake/Programs.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/SystemLibraries.cmake b/cmake/SystemLibraries.cmake index c79770f312..beaa9000b5 100644 --- a/cmake/SystemLibraries.cmake +++ b/cmake/SystemLibraries.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Tasks.cmake b/cmake/Tasks.cmake index 891f413253..fd1567c6fc 100644 --- a/cmake/Tasks.cmake +++ b/cmake/Tasks.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -171,8 +171,16 @@ if(TASK_FILE) endif() else(TASK_FILE) dune_add_tasks(${PROJECT_SOURCE_DIR}/src) - dune_add_tasks(${PROJECT_SOURCE_DIR}/private/src) - dune_add_tasks(${PROJECT_SOURCE_DIR}/user/src) + # Adding private folders. + file(GLOB privdir ${PROJECT_SOURCE_DIR}/private*/) + foreach(privdir ${privdir}) + dune_add_tasks(${privdir}/src) + endforeach(privdir ${privdir}) + # Adding user folders. + file(GLOB userdir ${PROJECT_SOURCE_DIR}/user*/) + foreach(userdir ${userdir}) + dune_add_tasks(${userdir}/src) + endforeach(userdir ${userdir}) endif(TASK_FILE) list(SORT DUNE_TASKS_ENABLED) diff --git a/cmake/Toolchain.cmake b/cmake/Toolchain.cmake index 5059221561..7c80bb3be6 100644 --- a/cmake/Toolchain.cmake +++ b/cmake/Toolchain.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -114,3 +114,7 @@ if(CROSS) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) endif(CROSS) + +if (DEFINED ENV{STRIP}) + set(CMAKE_STRIP "$ENV{STRIP}") +endif() diff --git a/cmake/Types.cmake b/cmake/Types.cmake index 3062b31ea2..e61c64863e 100644 --- a/cmake/Types.cmake +++ b/cmake/Types.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/cmake/Version.cmake b/cmake/Version.cmake index 27e1b6c9bb..5927927f97 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -75,7 +75,10 @@ if(DUNE_VERSION_TPL AND DUNE_VERSION_OUT) else() set(DUNE_CORE_SOURCES ${DUNE_CORE_SOURCES} ${DUNE_GENERATED}/src/DUNE/Version.cpp) - file(WRITE "${DUNE_GENERATED}/src/DUNE/Version.cpp" "") + + if(NOT EXISTS "${DUNE_GENERATED}/src/DUNE/Version.cpp") + file(WRITE "${DUNE_GENERATED}/src/DUNE/Version.cpp" "") + endif() add_custom_target(dune-version COMMAND ${CMAKE_COMMAND} diff --git a/etc/adamastor.ini b/etc/adamastor.ini index 7069838b77..62c828e9e2 100644 --- a/etc/adamastor.ini +++ b/etc/adamastor.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -154,8 +154,6 @@ Entity Label = Medium Entity Label - Medium Sensor = Medium Sensor Vehicle Type = UUV Initialization Time = 30.0 -Wet Data Timeout = 3.0 -Wet Data Threshold = 1.0 GPS Timeout = 2.0 [Navigation.AUV.Navigation] @@ -185,8 +183,7 @@ Power Channel 17 - Name = N/C (DVL) Power Channel 17 - State = 0 [Sensors.GPS] -Serial Port - Device = /dev/uart/13 -Serial Port - Baud Rate = 57600 +IO Port - Device = uart:///dev/uart/13:57600 [Sensors.Imagenex881A] Invert Orientation Angle = true diff --git a/etc/aero-01.ini b/etc/aero-01.ini index c70fc28d58..b0974221fe 100644 --- a/etc/aero-01.ini +++ b/etc/aero-01.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/auv/basic.ini b/etc/auv/basic.ini index e6f511d3fe..01590f0387 100644 --- a/etc/auv/basic.ini +++ b/etc/auv/basic.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -29,6 +29,7 @@ [Require ../common/micromodem-addresses.ini] [Require ../common/narrow-band-transponders.ini] [Require ../common/evologics-addresses.ini] +[Require ../common/gsm-addresses.ini] [Require ../common/transports.ini] [Require ../hardware/power-consumption.ini] [Require plans.ini] @@ -39,4 +40,4 @@ [Require maneuvers.ini] [Require monitors.ini] [Require supervisors.ini] -[Require general.ini] +[Require general.ini] \ No newline at end of file diff --git a/etc/auv/control.ini b/etc/auv/control.ini index 41a4bfa707..37f78f3bed 100644 --- a/etc/auv/control.ini +++ b/etc/auv/control.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -61,6 +61,7 @@ Enable roll controller = true Roll PID Gains = 2.1, 0.0, 0.4 Roll Integral Limit = -1.0 Depth PID Gains = 0.6, 0.0, 0.7 +Altitude PID Gains = 0.8, 0.0, 0.7 Depth Integral Limit = -1.0 Use Fixed Depth Offset = false Depth Offset = 0.2 @@ -73,7 +74,7 @@ Pitch Integral Limit = -1.0 Heading PID Gains = 1.5, 0.0, 0.0 Heading Integral Limit = -1.0 Maximum Heading Rate = 30.0 -Heading Rate PID Gains = 1.6, 0.0, 0.8 +Heading Rate PID Gains = 1.2, 0.0, 0.0 Heading Rate Integral Limit = -1.0 Maximum Fin Rotation = 25.0 Force Pitch At Surface = true @@ -93,6 +94,39 @@ Roll Compensation -- Offset Angle = 0.0 Roll Compensation -- Use Speed = false Roll Compensation -- Speed Bounds = 1.0, 1.8 Roll Compensation -- Speed Gain = 0.5 +Altitude Control -- Filter Weights = -1.27482175e-06,-3.65738774e-06, + -1.17070428e-05,-3.11243736e-05, + -7.00674137e-05,-1.39508991e-04, + -2.52830535e-04,-4.24392614e-04, + -6.66914986e-04,-9.87650957e-04, + -1.38354874e-03,-1.83583825e-03, + -2.30473202e-03,-2.72513810e-03, + -3.00439909e-03,-3.02304749e-03, + -2.63937080e-03,-1.69820293e-03, + -4.38264254e-05,2.46375916e-03, + 5.93058693e-03,1.04104220e-02, + 1.58886929e-02,2.22710063e-02, + 2.93783362e-02,3.69503802e-02, + 4.46577048e-02,5.21222453e-02, + 5.89446365e-02,6.47358766e-02, + 6.91501237e-02,7.19151017e-02, + 7.28567216e-02,7.19151017e-02, + 6.91501237e-02,6.47358766e-02, + 5.89446365e-02,5.21222453e-02, + 4.46577048e-02,3.69503802e-02, + 2.93783362e-02,2.22710063e-02, + 1.58886929e-02,1.04104220e-02, + 5.93058693e-03,2.46375916e-03, + -4.38264254e-05,-1.69820293e-03, + -2.63937080e-03,-3.02304749e-03, + -3.00439909e-03,-2.72513810e-03, + -2.30473202e-03,-1.83583825e-03, + -1.38354874e-03,-9.87650957e-04, + -6.66914986e-04,-4.24392614e-04, + -2.52830535e-04,-1.39508991e-04, + -7.00674137e-05,-3.11243736e-05, + -1.17070428e-05,-3.65738774e-06, + -1.27482175e-06 [Control.AUV.LMI] Enabled = Never diff --git a/etc/auv/general.ini b/etc/auv/general.ini index a11f84bb4d..34389a676d 100644 --- a/etc/auv/general.ini +++ b/etc/auv/general.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/auv/maneuvers.ini b/etc/auv/maneuvers.ini index 844886eacf..1a780801ee 100644 --- a/etc/auv/maneuvers.ini +++ b/etc/auv/maneuvers.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -90,8 +90,9 @@ Max Step Actuation = 10 [Maneuver.CommsRelay] Enabled = Always Entity Label = Communications Relay Maneuver -Loitering Radius = 0 -Depth = 0 +Loitering Radius = 10.0 +Z Value = 0.0 +Z Mode = None [Maneuver.CompassCalibration] Enabled = Always diff --git a/etc/auv/monitors.ini b/etc/auv/monitors.ini index c08dd7d40c..0740d2b3a0 100644 --- a/etc/auv/monitors.ini +++ b/etc/auv/monitors.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -102,6 +102,8 @@ Very Cold Model Temperature = -20.0 Very Cold Model Current = 1.35 Warning Level = 35 Error Level = 20 +Voltage Error Level = -1 +Voltage Threshold Error Level = 0.5 Low Confidence Level = 60.0 Acceptable Temperature = 20.0 @@ -126,6 +128,7 @@ Maximum Consecutive Transitions = 3 Default Monitoring = Attitude, Daemon, GPS, + Logger, Navigation, Operational Limits, Path Control @@ -184,7 +187,8 @@ Entity Label - Medium Sensor = Medium Sensor Vehicle Type = UUV Initialization Time = 20.0 Wet Data Timeout = 3.0 -Wet Data Threshold = 1.0 +Salinity Threshold = 1.0 +Sound Speed Threshold = 1000.0 GPS Timeout = 2.0 Vehicle Sub-Type = None diff --git a/etc/auv/navigation.ini b/etc/auv/navigation.ini index f3eb950280..1cf33bf668 100644 --- a/etc/auv/navigation.ini +++ b/etc/auv/navigation.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -42,7 +42,7 @@ Entity Label - Compass = AHRS Entity Label - IMU = IMU Reject all LBL ranges = false Depth Sensor = true -GPS timeout = 1.5 +GPS timeout = 2.0 DVL timeout = 3.0 Altitude timeout = 5.0 Depth timeout = 5.0 diff --git a/etc/auv/plans.ini b/etc/auv/plans.ini index 26f184a505..ada95d96dc 100644 --- a/etc/auv/plans.ini +++ b/etc/auv/plans.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/auv/simulator.ini b/etc/auv/simulator.ini index 59aa7d423a..8e396c4405 100644 --- a/etc/auv/simulator.ini +++ b/etc/auv/simulator.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -37,8 +37,8 @@ Enabled = Simulation Execution Frequency = 100 Entity Label = Simulation Engine -Stream Speed North = 0.0 -Stream Speed East = 0.0 +Time Multiplier = 1.0 +Entity Label - Stream Velocity Source = Stream Velocity Simulator [Simulators.GPS] Enabled = Simulation @@ -122,11 +122,6 @@ Maximum Rate = 333.3 Generate Faults = false Fault Time = 10.0 -[Simulators.UnderwaterAcoustics] -Enabled = Never -Entity Label = Underwater Acoustics Simulator -Trace = 0 - [Simulators.Docking] Enabled = Never Entity Label = Docking @@ -156,3 +151,13 @@ Name of message to produce = SoundSpeed Value at peak = 1522 Value away from peak = 1500 Invalid at Surface = true + +[Simulators.StreamVelocity] +Enabled = Simulation +Entity Label = Stream Velocity Simulator +Default Speed North = 0.0 +Default Speed East = 0.0 +Default Speed Down = 0.0 +Stream Velocity Source = Constant +# Stream Velocity Source = Gridded 2D Model Data +Execution Frequency = 1 diff --git a/etc/auv/supervisors.ini b/etc/auv/supervisors.ini index 3167d98817..67f7b191c7 100644 --- a/etc/auv/supervisors.ini +++ b/etc/auv/supervisors.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/auv/transports.ini b/etc/auv/transports.ini index 72bd2fe995..41b9d96cf6 100644 --- a/etc/auv/transports.ini +++ b/etc/auv/transports.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -40,6 +40,9 @@ Contact Timeout = 30 Dynamic Nodes = true Local Messages Only = false Transports = AcousticOperation, + AcousticRequest, + AcousticStatus, + AcousticSystems, AlignmentState, CpuUsage, DevCalibrationControl, @@ -60,6 +63,7 @@ Transports = AcousticOperation, LblConfig, LogBookEntry, LogBookControl, + ManeuverDone, OperationalLimits, PathControlState, PlanControl, @@ -73,14 +77,30 @@ Transports = AcousticOperation, Rpm, RSSI, SadcReadings, + Salinity, SimulatedState, + SmsRequest, + SmsStatus, + SoiCommand, + SoiState, + SonarData, + StateReport, StorageUsage, + TCPRequest, + TCPStatus, Temperature, TextMessage, + TransmissionRequest, + TransmissionStatus, TrexObservation, TrexOperation, TrexToken, TrexPlan, + Turbidity, + UamTxFrame, + UamRxFrame, + UamTxStatus, + UamRxRange, UsblAnglesExtended, UsblPositionExtended, UsblFixExtended, @@ -91,7 +111,7 @@ Transports = AcousticOperation, Voltage Filtered Entities = CpuUsage:Daemon, Distance:Altimeter+DVL Filtered+Echo Sounder, - Temperature:CTD+Depth Sensor, + Temperature:CTD+Depth Sensor+CTD Simulator, Voltage:Batteries+Rhodamine+Turbidity+Chlorophyll Rate Limiters = AlignmentState:0.5, CpuUsage:0.2, @@ -126,6 +146,8 @@ Transports = Abort, Acceleration, AcousticLink, AcousticOperation, + AcousticRequest, + AcousticStatus, AllocatedControlTorques, AlignmentState, AngularVelocity, @@ -159,6 +181,7 @@ Transports = Abort, EmergencyControl, EmergencyControlState, EntityActivationState, + EntityInfo, EntityList, EntityMonitoringState, EntityParameters, @@ -188,6 +211,7 @@ Transports = Abort, Loiter, ManeuverControlState, MagneticField, + ManeuverDone, NavigationData, NavigationUncertainty, OperationalLimits, @@ -222,17 +246,25 @@ Transports = Abort, RSSI, Salinity, SadcReadings, + SimAcousticMessage, SaveEntityParameters, ServoPosition, SetEntityParameters, SetServoPosition, SetThrusterActuation, + SoiCommand, + SoiState, SonarData, SimulatedState, Sms, + SmsRequest, + SmsStatus, SoundSpeed, + StateReport, StationKeeping, StopManeuver, + TCPRequest, + TCPStatus, Teleoperation, TeleoperationDone, Temperature, @@ -241,6 +273,8 @@ Transports = Abort, TrexOperation, TrexPlan, TrexToken, + TransmissionRequest, + TransmissionStatus, TransportBindings, Turbidity, UamRxFrame, @@ -288,18 +322,76 @@ Transports = DevCalibrationControl, RemoteActionsRequest [Transports.TCP.Server/SlaveCPU] -Enabled = Never +Enabled = Always Entity Label = TCP to Slave CPU Announce Service = false Port = 9999 -Transports = LoggingControl, +Transports = EntityParameters, EstimatedState, - QueryEntityParameters, - SetEntityParameters, + GpsFix, + PathControlState, + Heartbeat, + LoggingControl, PopEntityParameters, - PushEntityParameters, - EntityParameters, PowerOperation, PowerChannelState, + Pulse, + PushEntityParameters, QueryEntityInfo, - SoundSpeed + QueryEntityParameters, + SaveEntityParameters, + SetEntityParameters, + SoundSpeed, + VehicleMedium, + LogBookEntry, + ManeuverDone + +[Transports.TCP.Server/BackSeat] +Enabled = Always +Entity Label = Back Seat TCP Server +Announce Service = false +Debug Level = None +Activation Time = 0 +Deactivation Time = 0 +Execution Priority = 10 +Port = 6006 +Trace - Incoming Messages = false +Trace - Outgoing Messages = false +Transports = Announce, + Abort, + AcousticLink, + AlignmentState, + EntityParameters, + EstimatedState, + FollowRefState, + FuelLevel, + FollowRefState, + GpsFix, + IridiumTxStatus, + PathControlState, + PlanControl, + PlanControlState, + PlanDB, + ReportControl, + Salinity, + SoiCommand, + SoiPlan, + Temperature, + TextMessage, + TransmissionStatus, + UamRxFrame, + UamTxStatus, + VehicleMedium, + VehicleState +Filtered Entities = Temperature:CTD+OEMX+CTD Simulator + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM + +[Transports.TCPOnDemand] +Enabled = Always +Entity Label = TCP On Demand diff --git a/etc/buv-petinga-1.ini b/etc/buv-petinga-1.ini new file mode 100644 index 0000000000..f3e91ebab3 --- /dev/null +++ b/etc/buv-petinga-1.ini @@ -0,0 +1,160 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Teixeira # +############################################################################ +# BUV-Petinga-1 configuration file # +############################################################################ + +[Require auv/basic.ini] +[Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/gps-lc2m.ini] +[Require hardware/lctr-a6xx/gsm-lc2m.ini] +[Require hardware/lctr-a6xx/micromodem.ini] +[Require hardware/lctr-a6xx/limu.ini] +[Require hardware/lctr-a6xx/scrtv4.ini] + +############################################################################ +# Vehicle specific overrides # +############################################################################ +[General] +Vehicle = buv-petinga-1 +Absolute Maximum Depth = 105 +Absolute Minimum Altitude = 1.2 +Battery Packs = 3 +Battery Capacity = 525 +Power Model -- Conversion - Watt = 0, 14, 20, 54, 70 +Power Model -- Conversion - RPM = 0, 500, 850, 1250, 1400 +Speed Conversion -- Actuation = 0, 36, 46 +Speed Conversion -- RPM = 0, 900, 1150 +Speed Conversion -- MPS = 0, 1, 1.3 +Maximum Absolute Speed = 1.6 +Hardware List = LSTS PCTLv2, + LSTS LIMUv1, + IEI PM-LX2-800W, + Ubiquiti PicoStation M2HP, + TP-LINK SF1008D, + GSM/UMTS/HDSPA, + WHOI MicroModem, + U-blox EVK-6H, + Keller-33x + +[Control.AUV.Allocator] +Fin effect Rpm minimum value = 200 +Fin effect Velocity dependent = true +Fin effect Velocity dependent unit = RPM +Fin effect minimum Meter Per Second value = 0.2 +Roll not velocity dependent = true +k pitch = 1.35 +k roll = 1.0 +k yaw = 2.0 + +[Control.AUV.Attitude] +Roll PID Gains = 0.4, 0.05, 0.3 +Roll Compensation -- Use Speed = true +Roll Compensation -- Speed Gain = 0.2 +Roll Integral Limit = 5.0 +Depth PID Gains = 0.65, 0.015, 0.7 +Depth Integral Limit = 5 +Heading Rate PID Gains = 1.2, 0.0, 0.0 +Pitch PID Gains = 1.325, 0.0, 0.0 + + +[Monitors.Entities] +Default Monitoring = Attitude, + Daemon, + GPS, + Navigation, + Operational Limits, + Path Control +Default Monitoring -- Hardware = AHRS, + Clock, + Collisions, + Fuel, + Leak Sensor, + Motor Controller, + Servo Controller + +[Monitors.FuelLevel] +Capacity Decay Factor = 10.0 +Voltage Error Level = 24.5 +Voltage Threshold Error Level = 0.5 + +# to be corrected +[Navigation.AUV.Navigation] +GPS Maximum HACC = 40.0 +Distance Between LBL and GPS = 0.98 +Abort if Uncertainty Exceeded = false +Activate speed to rpm estimation limit = true +Depth sensor localization in x axis = 0.64 +Rpm to speed estimation = true +speed to rpm estimation percentage limit = 15 + +[Sensors.MLBL] +Address Section = Micromodem Addresses - DMSMW + +[Simulators.Environment] +Simulate - Bottom Distance = false +Simulate - Forward Distance = false + +[Power.PCTLv2] +ADC Reference Voltage = 1.083 +Serial Port - Device = /dev/uart/10 +Power Channel 2 - Name = AHRS +Power Channel 2 - State = 1 +Power Channel 3 - Name = N/C (+12V_5) +Power Channel 3 - State = 0 +Power Channel 5 - Name = N/C (Bout_2) +Power Channel 5 - State = 0 +Power Channel 7 - Name = N/C (Bout_4) +Power Channel 7 - State = 0 +Power Channel 10 - Name = Switch Ethernet +Power Channel 10 - State = 1 +Power Channel 17 - Name = N/C (DVL) +Power Channel 17 - State = 0 +Power Channel 15 - Name = N/C (+12V_2) +Power Channel 15 - State = 0 +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor +Leak 1 - Medium Sensor = false + +[Monitors.Clock] +Enabled = Hardware + +[Supervisors.ClockPPS] +Enabled = Never + +[Monitors.Emergency] +Enabled = Always + +# Enable if conventional tail +[Require hardware/lctr-a6xx/broom-36v.ini] +[Actuators.Broom] +Enabled = Hardware + +[Actuators.SCRTv4] +Enabled = Hardware diff --git a/etc/caravela.ini b/etc/caravela.ini index ae2fd83086..7bc585e068 100644 --- a/etc/caravela.ini +++ b/etc/caravela.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2015 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # @@ -237,8 +237,7 @@ Motor 3 - Orientation = 1 [Sensors.GPS] Enabled = Hardware Entity Label = GPS -Serial Port - Device = /dev/uart/8 -Serial Port - Baud Rate = 115200 +IO Port - Device = uart:///dev/uart/8:115200 Sentence Order = GPZDA, GPGGA, GPRMC, GPVTG [Sensors.LIMU] @@ -246,14 +245,13 @@ Hard-Iron Calibration = 0.0590, -0.0907, 0.0000 [Sensors.Imagenex837B] X-Axis Distance to GPS = -0.14 -IPv4 Address = 192.168.0.2 -TCP Port = 4040 +IO Port - Device = tcp://192.168.0.2:4040 Auto Gain Mode = false [Sensors.Imagenex852] Sonar position = 0.02, 0.00, 0.62 Sonar orientation = 0, -90, 0 -Serial Port - Device = /dev/uart/9 +IO Port - Device = uart:///dev/uart/9 Automatic Activation = false [Require hardware/lctr-a6xx/sch311x.ini] @@ -343,7 +341,7 @@ Enabled = Hardware IPv4 Address = 10.0.50.5 [Transports.UAN] -Enabled = Hardware +Enabled = Always Entity Label = Acoustic Access Controller Enable Reports = true diff --git a/etc/common/drip.ini b/etc/common/drip.ini new file mode 100644 index 0000000000..c9ffc49f04 --- /dev/null +++ b/etc/common/drip.ini @@ -0,0 +1,49 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# DRiP-specific Configurations # +############################################################################ + +[Control.Path.VectorField] +Enabled = Never + +[Control.Path.PurePursuit] +Enabled = Always +Entity Label = Path Control +Cross-track -- Monitor = false + +[Transports.TCP.Server/BackSeat] +Enabled = Always + +[Maneuver.Multiplexer] +PopUp -- Report at PopUps = true + +[Maneuver.FollowReference.AUV] +Horizontal Tolerance = 15.0 +Loitering Radius = 15.0 + diff --git a/etc/common/evologics-addresses.ini b/etc/common/evologics-addresses.ini index b40259c8ce..9913510e2a 100644 --- a/etc/common/evologics-addresses.ini +++ b/etc/common/evologics-addresses.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -32,13 +32,20 @@ lauv-noptilus-1 = 1 lauv-noptilus-2 = 2 lauv-noptilus-3 = 3 lauv-xtreme-2 = 4 -caravela = 5 +manta-11 = 5 manta-rugged = 6 manta-1 = 7 manta-2 = 8 manta-3 = 9 -lauv-arpao = 10 -manta-11 = 11 +lauv-nemo-1 = 10 +manta-rugged-2 = 11 manta-12 = 12 manta-21 = 13 broadcast = 14 + +[Evologics Addresses - DMSMW] +lauv-seacon-3 = 10 +manta-dmsmw-01 = 11 +manta-dmsmw-02 = 12 +manta-dmsmw-03 = 13 +broadcast = 14 diff --git a/etc/common/gsm-addresses.ini b/etc/common/gsm-addresses.ini new file mode 100644 index 0000000000..a684147dae --- /dev/null +++ b/etc/common/gsm-addresses.ini @@ -0,0 +1,42 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Seruca # +############################################################################ +# Ex: lauv-noptilus-1 = +35196******* # +############################################################################ + +[GSM Addresses] +lauv-noptilus-1 = +351969349133 +lauv-noptilus-2 = +351925978180 +lauv-noptilus-3 = +351966575686 +lauv-xplore-1 = +351964085112 +lauv-xplore-2 = +351965655424 +lauv-xplore-3 = +351964039469 +lauv-xplore-4 = +351964093243 +lauv-xplore-5 = +351964125235 +lauv-nemo-1 = +351924176966 +lauv-xtreme-2 = +351968761421 diff --git a/etc/common/imc-addresses.ini b/etc/common/imc-addresses.ini index a545feb0a5..741182878d 100644 --- a/etc/common/imc-addresses.ini +++ b/etc/common/imc-addresses.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -46,11 +46,17 @@ lauv-noptilus-3 = 0x001C lauv-lsts-1 = 0x001D lauv-xplore-1 = 0x001E lauv-xplore-2 = 0x001F +lauv-xplore-3 = 0x0020 +lauv-xplore-4 = 0x0021 +lauv-xplore-5 = 0x0022 +lauv-nemo-1 = 0x0023 lauv-simulator-1 = 0x00D1 rov-ies = 0x0401 adamastor = 0x0402 +squirtle = 0x0403 swordfish = 0x0801 caravela = 0x0802 +otter = 0x0803 hermes = 0x08c1 hermes-desired = 0x08c2 hermes-target = 0x08c3 @@ -72,7 +78,11 @@ mariner-01 = 0x0c20 mariner-02 = 0x0c21 x2o-01 = 0x0c22 x2o-02 = 0x0c23 +firefly = 0x0c24 +titan = 0x0c25 vtol-01 = 0x0c2a +vtol-02 = 0x0c2b +vtol-03 = 0x0c2c hexa-00 = 0x0c30 alfa-02 = 0x0c32 alfa-03 = 0x0c33 @@ -100,7 +110,12 @@ form-leader-03 = 0x0cf3 form-leader-04 = 0x0cf4 form-leader-05 = 0x0cf5 form-leader-06 = 0x0cf6 +turbot = 0x2000 +sparus2 = 0x2001 +eqe = 0x2002 +lauv-harald = 0x200d lrauv-sim = 0x2300 +buv-petinga-1 = 0x2400 ntnu-hexa-testbed = 0x2c00 ntnu-hexa-001 = 0x2c01 ntnu-hexa-002 = 0x2c02 @@ -123,6 +138,16 @@ ntnu-penguin-001 = 0x2c41 ntnu-penguin-002 = 0x2c42 ntnu-penguin-003 = 0x2c43 ntnu-penguin-004 = 0x2c44 +ntnu-bixler-001 = 0x2c4a +ntnu-bixler-002 = 0x2c4b +ntnu-bixler-003 = 0x2c4c +ntnu-cruisermini-001 = 0x2c51 +ntnu-cruisermini-002 = 0x2c52 +ntnu-cruisermini-003 = 0x2c53 +ntnu-cruisermini-004 = 0x2c54 +ntnu-cruisermini-005 = 0x2c55 +ntnu-cruisermini-006 = 0x2c56 +wg-sv3-127 = 0x2801 ccu-lsts-1-1 = 0x4101 ccu-lsts-1-14 = 0x410E ccu-lsts-1-20 = 0x4114 @@ -135,6 +160,15 @@ lauv-seacon-1-aux = 0x6002 lauv-noptilus-3-aux = 0x6003 lauv-xtreme-2-aux = 0x6004 caravela-aux = 0x6005 +lauv-xtreme-2-cpu-cam = 0x6006 +x8-06-aux = 0x6007 +lauv-noptilus-2-cpu-cam = 0x6008 +lauv-noptilus-3-cpu-cam = 0x6009 +lauv-seacon-3-aux = 0x6010 +lauv-seacon-3-cpu-cam = 0x6011 +lauv-seacon-2-aux = 0x6012 +lauv-seacon-2-cpu-cam = 0x6013 +otter-aux = 0x6014 star = 0x8000 benthos-mgateway = 0x8010 manta-1 = 0x8012 @@ -151,12 +185,17 @@ manta-21 = 0x8026 manta-dmsmw-02 = 0x8027 manta-dmsmw-03 = 0x8028 manta-rugged = 0x8029 +manta-rugged-2 = 0x802a +manta-uk-01 = 0x802b +manta-uk-02 = 0x802c nest-1 = 0x8030 piccolo-gs1 = 0x8040 piccolo-gs2 = 0x8041 piccolo-gs3 = 0x8042 ais-1 = 0x8070 ais-2 = 0x8071 +bridgebox-1 = 0x8081 +bridgebox-2 = 0x8082 spot-01 = 0x8401 spot-02 = 0x8402 spot-03 = 0x8403 @@ -192,7 +231,10 @@ esp-bruce = 0x84a9 wavy-0 = 0x8500 wavy-1 = 0x8501 wavy-2 = 0x8502 +ntnu-autonaut = 0x8803 +ntnu-autonaut-L3 = 0x8804 ntnu-nest-01 = 0x9001 ntnu-nest-02 = 0x9002 +manta-sabuvis = 0x9501 broadcast = 0xFFF0 null = 0xFFFF diff --git a/etc/common/maneuvers.ini b/etc/common/maneuvers.ini index 71d41d6bcb..2b8cad494d 100644 --- a/etc/common/maneuvers.ini +++ b/etc/common/maneuvers.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -45,6 +45,8 @@ Entity Label -- Elevator = Elevator Maneuver Entity Label -- PopUp = Pop Up Maneuver Entity Label -- Dislodge = Dislodge Maneuver Entity Label -- Launch = Launch Maneuver +Entity Label -- Takeoff = Takeoff Maneuver +Entity Label -- Land = Land Maneuver Loiter -- Minimum Radius = 10.0 [Maneuver.Teleoperation] diff --git a/etc/common/micromodem-addresses.ini b/etc/common/micromodem-addresses.ini index 96a505fb6c..329cef2816 100644 --- a/etc/common/micromodem-addresses.ini +++ b/etc/common/micromodem-addresses.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,19 +30,21 @@ [Micromodem Addresses] lauv-xplore-1 = 1 lauv-xplore-2 = 2 -caravela = 3 -manta-1 = 4 +manta-rugged = 3 +manta-rugged-2 = 4 manta-2 = 5 manta-11 = 6 manta-12 = 7 manta-21 = 8 -adamastor = 14 +manta-1 = 12 +manta-3 = 13 + [Micromodem Addresses - DMSMW] lauv-seacon-1 = 9 lauv-seacon-2 = 10 -lauv-seacon-3 = 11 manta-dmsmw-01 = 12 manta-dmsmw-02 = 13 manta-dmsmw-03 = 14 +buv-petinga-1 = 15 diff --git a/etc/common/narrow-band-transponders.ini b/etc/common/narrow-band-transponders.ini index 506bb8f19e..a80a5d9826 100644 --- a/etc/common/narrow-band-transponders.ini +++ b/etc/common/narrow-band-transponders.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/common/plans.ini b/etc/common/plans.ini index a71d306109..5912b45e8f 100644 --- a/etc/common/plans.ini +++ b/etc/common/plans.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/common/pure-pursuit.ini b/etc/common/pure-pursuit.ini new file mode 100644 index 0000000000..632d1f3ca4 --- /dev/null +++ b/etc/common/pure-pursuit.ini @@ -0,0 +1,37 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ + +[Control.Path.VectorField] +Enabled = Never + +[Control.Path.PurePursuit] +Enabled = Always +Entity Label = Path Control +Cross-track -- Monitor = false + diff --git a/etc/common/seatrac-addresses.ini b/etc/common/seatrac-addresses.ini index df5ada22e2..32d8a9ab56 100644 --- a/etc/common/seatrac-addresses.ini +++ b/etc/common/seatrac-addresses.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -35,6 +35,12 @@ manta-11 = 4 manta-12 = 5 manta-21 = 6 manta-rugged = 7 -caravela = 8 +manta-rugged-2 = 8 +x2o-01 = 9 +x2o-02 = 10 +lauv-nemo-1 = 11 +titan = 12 +id-13 = 13 +id-14 = 14 +id-15 = 15 broadcast = 0 - diff --git a/etc/common/transports.ini b/etc/common/transports.ini index 289956868c..92d6484f9e 100644 --- a/etc/common/transports.ini +++ b/etc/common/transports.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -88,7 +88,7 @@ Enable Multicast = 1 Enable Broadcast = 1 Multicast Address = 224.0.75.69 Ports = 30100, 30101, 30102, 30103, 30104 -Ignored Interfaces = eth0:prv +Ignored Interfaces = eth0:prv, eth1:prv [Transports.Discovery] Enabled = Hardware, Simulation diff --git a/etc/common/trex.ini b/etc/common/trex.ini index d71cb41230..d40aaa89fe 100644 --- a/etc/common/trex.ini +++ b/etc/common/trex.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/common/vsim-models.ini b/etc/common/vsim-models.ini index 34f9196bba..f42a193f6f 100644 --- a/etc/common/vsim-models.ini +++ b/etc/common/vsim-models.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/ardupilot-testbed.ini b/etc/development/ardupilot-testbed.ini index 71f1389204..a89639eaf6 100644 --- a/etc/development/ardupilot-testbed.ini +++ b/etc/development/ardupilot-testbed.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/cdc3/cdc3-addresses.ini b/etc/development/cdc3/cdc3-addresses.ini new file mode 100644 index 0000000000..b25534d0fd --- /dev/null +++ b/etc/development/cdc3/cdc3-addresses.ini @@ -0,0 +1,69 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Paulo Dias # +############################################################################ + +[IMC Addresses] +#lauv-nemo-1 = 0x0023 #(35) +iver-3055 = 0x2010 #(8208) +mr-uh = 0x2810 #(10256) +seabed-uh = 0x9510 #(38160) +#titan = 0x0c25 #(3109) + +[Seatrac Addresses CDC3] +broadcast = 0 +manta-1 = 1 +manta-2 = 2 +manta-3 = 3 +manta-11 = 4 +manta-12 = 5 +manta-21 = 6 +manta-rugged = 7 +mr-uh = 8 +iver-3055 = 9 +seabed-uh = 10 +lauv-nemo-1 = 11 +titan = 12 +manta-rugged-2 = 13 +id-14 = 14 +id-15 = 15 + +[Evologics Addresses] +broadcast = 14 +manta-11 = 5 +lauv-nemo-1 = 10 +lauv-noptilus-1 = 1 +lauv-noptilus-2 = 2 +lauv-noptilus-3 = 3 +lauv-xtreme-2 = 4 +manta-1 = 7 +manta-12 = 12 +manta-2 = 8 +manta-21 = 13 +manta-3 = 9 +manta-rugged = 6 +manta-rugged-2 = 11 diff --git a/etc/development/cdc3/cdc3-lauv-nemo-1.ini b/etc/development/cdc3/cdc3-lauv-nemo-1.ini new file mode 100644 index 0000000000..bf696bd288 --- /dev/null +++ b/etc/development/cdc3/cdc3-lauv-nemo-1.ini @@ -0,0 +1,83 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# Lauv-nemo-1 extra configurations for CDC3 Exercise # +############################################################################ + +[Require cdc3-addresses.ini] + +[Simulators.CDC3] +Enabled = simulation +Entity Label = CDC3 Acomms Simulator +Destination = iver-3055 +Debug Level = Debug +Period -- Enable = -1 +Period -- Report = -1 +Period -- RetaskMission = 1 +Period -- RetaskWaypoint = -1 +Period -- TargetOfInterest = -1 +Override Location = True +Retask Mission ID = 1 +Enable Message Ordinal = 3 +Enable Value = 2 + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM +#Acoustic Address Section = Evologics Addresses +Acoustic Address Section = Seatrac Addresses CDC3 +Debug Level = Debug + +[Transports.Seatrac] +Enabled = Hardware +#Serial Port - Device = tcp://10.0.30.21:1001 +#Use Internal Pressure Sensor for Medium = false +#Transmit Only Underwater = false +Debug Level = Debug +Address Section = Seatrac Addresses CDC3 + +[Transports.Evologics] +Enabled = Never +IPv4 Address = 127.0.0.1 +Firmware version = 2.0 + +[Transports.SerialOverTCP/Evologics] +Enabled = Never +Serial Port - Device = /dev/ttyUSB1 +Debug Level = Debug + + +[Transports.UDP] +Static Destinations = 127.0.0.1:6969, 127.0.0.1:6970, 127.0.0.1:6971, 127.0.0.1:6972, + 10.0.10.63:6969, 10.0.10.63:6970, 10.0.10.63:6971, 10.0.10.63:6972 +[Transports.UAN] +#Address Section = Evologics Addresses +Address Section = Seatrac Addresses CDC3 \ No newline at end of file diff --git a/etc/development/cdc3/cdc3-seatrac_uart.ini b/etc/development/cdc3/cdc3-seatrac_uart.ini new file mode 100644 index 0000000000..8ed47347cb --- /dev/null +++ b/etc/development/cdc3/cdc3-seatrac_uart.ini @@ -0,0 +1,61 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# Extra configurations for CDC3 Exercise # +############################################################################ + +[Require ../lctr-a6xx/seatrac.ini] +[Require ../../development/cdc3/cdc3-addresses.ini] + +[Sensors.MLBLTracker] +Enabled = Never + +[Transports.Evologics] +Enabled = Never + +[Power.MCBv2] +Power Channel 6 - Name = Seatrac modem +Power Channel 6 - State = 1 + +[Transports.UAN] +Enabled = Hardware +Entity Label = Acoustic Access Controller +USBL Node -- Period = 15 +USBL Node -- Enabled = false +USBL Node -- Absolute Fix = false +USBL Node -- Quick, No Range = false + +[Transports.Seatrac] +Serial Port - Device = /dev/uart/1 +Pressure Sensor Mode = true +Address Section = Seatrac Addresses CDC3 +Debug Level = Debug + +[UserInterfaces.MantaPanel] +Sections of System Addresses = Seatrac Addresses + +[Transports.CommManager] +Acoustic Address Section = Seatrac Addresses CDC3 diff --git a/etc/development/cdc3/cdc3-titan.ini b/etc/development/cdc3/cdc3-titan.ini new file mode 100644 index 0000000000..f275b06bb0 --- /dev/null +++ b/etc/development/cdc3/cdc3-titan.ini @@ -0,0 +1,101 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# Titan OctaQuadcopter extra configurations for CDC3 Exercise # +############################################################################ + +[Require ../../uav/seatrac.ini] +[Require cdc3-addresses.ini] +#[Require hardware/acoustic-modems/evologics_ip_1.ini] + +[Simulators.CDC3] +Enabled = Never +Entity Label = CDC3 Acomms Simulator +Destination = titan +Debug Level = Debug +Period -- Enable = -1 +Period -- Report = -1 +Period -- RetaskMission = -1 +Period -- RetaskWaypoint = -1 +Period -- TargetOfInterest = -1 +Override Location = True +Retask Mission ID = 1 +Enable Message Ordinal = 3 +Enable Value = 2 + +[Transports.Seatrac] +Enabled = Always +#Serial Port - Device = tcp://10.0.30.21:1001 +#Serial Port - Device = /dev/ttyUSB1 +#Pressure Sensor Mode = true +#Use Internal Pressure Sensor for Medium = true +#Transmit Only Underwater = true +Debug Level = Debug +Address Section = Seatrac Addresses CDC3 + +[Transports.Evologics] +Enabled = Never +#IPv4 Address = 127.0.0.1 + +[Transports.CommManager] +Acoustic Address Section = Seatrac Addresses CDC3 +#Acoustic Address Section = Evologics Addresses +Debug Level = Debug +Iridium Reports Period = 0 #disable Iridium reports + +[Transports.Logging] +Transports+ = AcousticRequest, + AcousticStatus, + StateReport +[Supervisors.Reporter] +Acoustic Reports = true +Acoustic Reports Periodicity = 180.0 +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Enabled = Hardware +Entity Label = Report Supervisor +Execution Priority = 10 +Radio Reports = false +Radio Reports Periodicity = 3 + + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Debug Level = Debug +#Address Section = Evologics Addresses +Address Section = Seatrac Addresses CDC3 + +[Transports.UDP] +Static Destinations = 127.0.0.1:6969, 127.0.0.1:6970, 127.0.0.1:6971, 127.0.0.1:6972 +Transports+ = AcousticRequest, + AcousticStatus, + StateReport + diff --git a/etc/development/cdc3/seabed-uh.ini b/etc/development/cdc3/seabed-uh.ini new file mode 100644 index 0000000000..7ba0caf4e4 --- /dev/null +++ b/etc/development/cdc3/seabed-uh.ini @@ -0,0 +1,116 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Require ../../auv/basic.ini] +[Require ../../auv/simulator.ini] +[Require ../../common/imc-addresses.ini] +[Require ../../common/transports.ini] +[Require ../../auv/transports.ini] + +[Require cdc3-addresses.ini] + +[General] +Vehicle = seabed-uh + +[Transports.Announce] +System Type = uuv + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM +Acoustic Address Section = Seatrac Addresses CDC3 +Debug Level = Debug + +[Transports.TCPOnDemand] +Enabled = Always +Entity Label = TCP On Demand + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Debug Level = Debug + +[Transports.UDP] +Static Destinations = 127.0.0.1:6969, 127.0.0.1:6970, 127.0.0.1:6971, 127.0.0.1:6972 + +### Seatrac ################################################### +[Require ../../hardware/lctr-a6xx/seatrac.ini] + +[Transports.Seatrac] +Enabled = Hardware +Debug Level = Debug +Serial Port - Device = /dev/ttyUSB0 +#Serial Port - Baud Rate = 115200 +Transmit Only Underwater = false +#Address Section = Seatrac Addresses +Address Section = Seatrac Addresses CDC3 +Max Range = 1000 +#Pressure Sensor Mode = true +Use Internal Pressure Sensor for Medium = false +#USBL Mode = true +Enhanced USBL = false + +[Transports.SerialOverTCP/Seatrac] +Enabled = Never +Entity Label = Seatrac TCP +TCP - Port = 1001 +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 115200 +#Debug Level = Debug + +### Simulation ################################################# + +[Simulators.CDC3] +Enabled = Never +Entity Label = CDC3 Acomms Simulator +Destination = lauv-nemo-1 +Debug Level = Debug +Period -- Enable = -1 +Period -- Report = 1 +Period -- RetaskMission = -1 +Period -- RetaskWaypoint = -1 +Period -- TargetOfInterest = -1 +Override Location = True +Retask Mission ID = 1 +Enable Message Ordinal = 3 +Enable Value = 2 + +[Supervisors.Reporter] +Enabled = Always +Entity Label = Report Supervisor +Debug Level = None +Acoustic Reports = true +Acoustic Reports Periodicity = 30.0 + +[Simulators.GPS] +Initial Position = 21.432383, -157.790085 diff --git a/etc/development/cdc3/seatrac-iver-3055.ini b/etc/development/cdc3/seatrac-iver-3055.ini new file mode 100644 index 0000000000..a4b9d46acd --- /dev/null +++ b/etc/development/cdc3/seatrac-iver-3055.ini @@ -0,0 +1,91 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Paulo Dias # +############################################################################ + +[Require ../../common/imc-addresses.ini] +[Require ../../common/transports.ini] +[Require ../../auv/transports.ini] + +[Require cdc3-addresses.ini] + +[General] +Vehicle = iver-3055 + +[Transports.Announce] +System Type = uuv + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM +Acoustic Address Section = Seatrac Addresses CDC3 +Debug Level = Debug + +[Transports.TCPOnDemand] +Enabled = Always +Entity Label = TCP On Demand + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Debug Level = Debug + +[Transports.UDP] +Static Destinations = 127.0.0.1:6969, 127.0.0.1:6970, 127.0.0.1:6971, 127.0.0.1:6972 + +### Seatrac ################################################### +[Require ../../hardware/lctr-a6xx/seatrac.ini] + +[Transports.Seatrac] +Enabled = Hardware +Debug Level = Debug +Serial Port - Device = /dev/ttyUSB0 +#Serial Port - Baud Rate = 115200 +Transmit Only Underwater = false +#Address Section = Seatrac Addresses +Address Section = Seatrac Addresses CDC3 +Max Range = 1000 +#Pressure Sensor Mode = true +Use Internal Pressure Sensor for Medium = false +#USBL Mode = true +Enhanced USBL = false + +[Transports.SerialOverTCP/Seatrac] +Enabled = Never +Entity Label = Seatrac TCP +TCP - Port = 1001 +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 115200 +#Debug Level = Debug + +############################################################ + + diff --git a/etc/development/cdc3/seatrac-mr-uh.ini b/etc/development/cdc3/seatrac-mr-uh.ini new file mode 100644 index 0000000000..ac89aa8e6e --- /dev/null +++ b/etc/development/cdc3/seatrac-mr-uh.ini @@ -0,0 +1,90 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Paulo Dias # +############################################################################ + +[Require ../../common/imc-addresses.ini] +[Require ../../common/transports.ini] +[Require ../../auv/transports.ini] + +[Require cdc3-addresses.ini] + +[General] +Vehicle = mr-uh + +[Transports.Announce] +System Type = usv + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM +Acoustic Address Section = Seatrac Addresses CDC3 +Debug Level = Debug + +[Transports.TCPOnDemand] +Enabled = Always +Entity Label = TCP On Demand + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Debug Level = Debug + +[Transports.UDP] +Static Destinations = 127.0.0.1:6969, 127.0.0.1:6970, 127.0.0.1:6971, 127.0.0.1:6972 + +### Seatrac ################################################### +[Require ../../hardware/lctr-a6xx/seatrac.ini] + +[Transports.Seatrac] +Enabled = Hardware +Debug Level = Debug +Serial Port - Device = /dev/ttyUSB0 +#Serial Port - Baud Rate = 115200 +Transmit Only Underwater = false +#Address Section = Seatrac Addresses +Address Section = Seatrac Addresses CDC3 +Max Range = 1000 +#Pressure Sensor Mode = true +Use Internal Pressure Sensor for Medium = false +#USBL Mode = true +Enhanced USBL = false + +[Transports.SerialOverTCP/Seatrac] +Enabled = Never +Entity Label = Seatrac TCP +TCP - Port = 1001 +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 115200 +#Debug Level = Debug + +############################################################ + diff --git a/etc/development/cdc3/seatrac-node-1.ini b/etc/development/cdc3/seatrac-node-1.ini new file mode 100644 index 0000000000..83026d5ae6 --- /dev/null +++ b/etc/development/cdc3/seatrac-node-1.ini @@ -0,0 +1,88 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Paulo Dias # +############################################################################ + +[Require ../../common/imc-addresses.ini] +[Require ../../common/transports.ini] +[Require ../../auv/transports.ini] + +[Require cdc3-addresses.ini] + +[General] +Vehicle = usv-uh + +[Transports.Announce] +System Type = usv + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM + +[Transports.TCPOnDemand] +Enabled = Always +Entity Label = TCP On Demand + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Debug Level = Debug + +### Seatrac ################################################### +[Require ../../hardware/lctr-a6xx/seatrac.ini] + +[Transports.Seatrac] +Enabled = Hardware +Debug Level = Debug +#Serial Port - Device = tcp://127.0.0.1:1001 +Serial Port - Device = tcp://10.0.30.12:1001 +#Serial Port - Device = /dev/uart/10 +#Serial Port - Baud Rate = 115200 +Transmit Only Underwater = false +#Address Section = Seatrac Addresses +Address Section = Seatrac Addresses CDC3 +#Max Range = 1000 +#Pressure Sensor Mode = true +#Use Internal Pressure Sensor for Medium = true +#USBL Mode = true +#Enhanced USBL = true + +[Transports.SerialOverTCP/Seatrac] +Enabled = Never +Entity Label = Seatrac TCP +TCP - Port = 1001 +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 115200 +#Debug Level = Debug + +############################################################ + + diff --git a/etc/development/fred.ini b/etc/development/fred.ini index ab3f516e27..dc53268df8 100644 --- a/etc/development/fred.ini +++ b/etc/development/fred.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/lauv-seacon-1-seatrac.ini b/etc/development/lauv-seacon-1-seatrac.ini index 97f573a8ea..47cc5fc34e 100644 --- a/etc/development/lauv-seacon-1-seatrac.ini +++ b/etc/development/lauv-seacon-1-seatrac.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/luemb.ini b/etc/development/luemb.ini index 98f7e1dea2..833a9f7a4c 100644 --- a/etc/development/luemb.ini +++ b/etc/development/luemb.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/manta-1-seatrac.ini b/etc/development/manta-1-seatrac.ini index ef5121f9e7..f60a5ac754 100644 --- a/etc/development/manta-1-seatrac.ini +++ b/etc/development/manta-1-seatrac.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/novatel.ini b/etc/development/novatel.ini new file mode 100644 index 0000000000..daf39e9af3 --- /dev/null +++ b/etc/development/novatel.ini @@ -0,0 +1,51 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Ricardo Falcão # +############################################################################ + +[Require ../common/transports.ini] + +[Sensors.GPS] +Enabled = Always +Debug Level = Trace +Entity Label = GPS +IO Port - Device = uart:///dev/ttyUSB0:115200 +Initialization String 0 - Command = UNLOGALL THISPORT_ALL\r\n +Initialization String 1 - Command = LOG GPZDA ONTIME 1\r\n +Initialization String 2 - Command = LOG GPGGA ONTIME 1\r\n +Initialization String 3 - Command = LOG GPRMC ONTIME 1\r\n +Initialization String 4 - Command = LOG GPVTG ONTIME 1\r\n +Initialization String 5 - Command = LOG BESTPOSA ONTIME 1\r\n +Initialization String 6 - Command = LOG RAWEPHEMA ONNEW\r\n +Initialization String 7 - Command = LOG RANGEA ONTIME 1\r\n +Sentence Order = GPZDA, GPGGA, GPRMC, GPVTG +Novatel SBAS = true + +[Transports.Logging] +Enabled = Always +Entity Label = Logger +Transports = GpsFix,EulerAngles,AngularVelocity,LogBookEntry,DevDataText diff --git a/etc/development/np2-fast.ini b/etc/development/np2-fast.ini new file mode 100644 index 0000000000..5c26cc570d --- /dev/null +++ b/etc/development/np2-fast.ini @@ -0,0 +1,36 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Noptilus-2 25x faster than real time. # +############################################################################ + +[Require ../lauv-noptilus-2.ini] + +[Simulators.VSIM] +Time Multiplier = 25 + +[Monitors.Entities] +Default Monitoring = \ No newline at end of file diff --git a/etc/development/pps.ini b/etc/development/pps.ini index a101893915..96dfb0c2ac 100644 --- a/etc/development/pps.ini +++ b/etc/development/pps.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -32,8 +32,7 @@ [Sensors.GPS] Enabled = Hardware Entity Label = GPS -Serial Port - Device = /dev/ttyACM0 -Serial Port - Baud Rate = 115200 +IO Port - Device = uart:///dev/ttyACM0:115200 Sentence Order = GPVTG, GPZDA, PUBX Initialization String 0 - Command = $PUBX,40,VTG,1,1,1,1,1,1\r\n Initialization String 1 - Command = $PUBX,40,ZDA,1,1,1,1,1,1\r\n diff --git a/etc/development/seatrac_tcp_only.ini b/etc/development/seatrac_tcp_only.ini new file mode 100644 index 0000000000..45df46fe9d --- /dev/null +++ b/etc/development/seatrac_tcp_only.ini @@ -0,0 +1,73 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Paulo Dias # +############################################################################ +#[Require ../hardware/lctr-a9xx.ini] + +[General] +Vehicle = manta-1111 + +[Power.MCBv2] +Drive LCD = true +Power Channel 2 - Name = Iridium +Power Channel 2 - State = 0 + + +[Transports.IridiumSBD] +Enabled = Never + +[Transports.Iridium] +Enabled = Never + +#[Require hardware/acoustic-modems/uModem_ip_100.ini] +#[Require hardware/acoustic-modems/uModem_ip_101.ini] +#[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/seatrac_ip_200.ini] +#[Require hardware/acoustic-modems/seatrac_uart.ini] +#[Require hardware/acoustic-modems/evologics_ip_1.ini] +#[Require hardware/acoustic-modems/evologics_ip_2.ini] +#[Require hardware/acoustic-modems/evologics_ip_4.ini] +#[Require hardware/acoustic-modems/evologics_ip_5.ini] + +[Sensors.MLBLTracker] +Enabled = Never + +[Transports.Evologics] +Enabled = Never + +[Transports.Seatrac] +Enabled = Never + +[Power.MCBv2] +Power Channel 6 - Name = Seatrac modem +Power Channel 6 - State = 1 + +[Transports.SerialOverTCP/Seatrac] +Enabled = Hardware +Entity Label = Seatrac TCP +TCP - Port = 1001 +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 115200 +#Debug Level = Debug diff --git a/etc/development/seatrac_test.ini b/etc/development/seatrac_test.ini new file mode 100644 index 0000000000..031249a0ac --- /dev/null +++ b/etc/development/seatrac_test.ini @@ -0,0 +1,75 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Teixeira # +############################################################################ +# LAUV Seacon 1 configuration file # +############################################################################ +[Require ../hardware/lctr-a6xx/seatrac.ini] +[Require ../hardware/lctr-a6xx/microstrain3dmgx1.ini] + +[General] +Vehicle = caravela + +[Sensors.Microstrain3DMGX1] +Debug Level = Spew + + [Transports.Seatrac] + Enabled = Always + Debug Level = Debug + AHRS Mode = true + Pressure Sensor Mode = true + Serial Port - Device = tcp://10.0.50.200:5000 + AHRS Rotation Matrix = 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 +Hard-Iron Calibration = 0.0, 0.0, 0.0 + +[Transports.Logging] +Enabled = Always +Entity Label = Logger +Flush Interval = 5 +LSF Compression Method = none +Transports = Depth, + Pressure, + SoundSpeed, + Temperature, + EulerAngles, + Acceleration, + AngularVelocity, + MagneticField, + DevDataText, + UamRxFrame, + UamTxFrame, + UamTxStatus, + UamRxRange, + UsblAnglesExtended, + UsblPositionExtended, + UsblFixExtended, + UsblModem, + UsblConfig, + SaveEntityParameters, + SetEntityParameters, + EntityParameter, + Voltage \ No newline at end of file diff --git a/etc/development/seruca.ini b/etc/development/seruca.ini new file mode 100644 index 0000000000..9331354361 Binary files /dev/null and b/etc/development/seruca.ini differ diff --git a/etc/development/tatui-testbed.ini b/etc/development/tatui-testbed.ini index abf66fbb70..54f2115575 100644 --- a/etc/development/tatui-testbed.ini +++ b/etc/development/tatui-testbed.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/trex.ini b/etc/development/trex.ini index 0d95e43846..8c6ebcbbc4 100644 --- a/etc/development/trex.ini +++ b/etc/development/trex.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/development/xp1-hil.ini b/etc/development/xp1-hil.ini new file mode 100644 index 0000000000..166ce89747 --- /dev/null +++ b/etc/development/xp1-hil.ini @@ -0,0 +1,85 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 1 with forced hardware comms and fins # +############################################################################ + +[Require ../lauv-xplore-1.ini] + +[Power.PCTLv2] +Enabled = Always + +[Actuators.SCRTv4] +Enabled = Always + +[UserInterfaces.LEDs] +Enabled = Always + +[Transports.IridiumSBD] +Enabled = Always + +[Transports.GSM] +Enabled = Always +Serial Port - Device = /dev/ttyACM1 +Serial Port - Baud Rate = 115200 +Reply Timeout = 2.0 +RSSI Periodicity = 10 +Read SMS Periodicity = 10 +SMS Send Timeout = 60 + +[Supervisors.Reporter] +Enabled = Always + +[Monitors.Emergency] +Enabled = Always +Entity Label = Emergency Monitor +Execution Frequency = 1.0 +Execution Priority = 10 +Active = true +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Lost Communications Timeout = 300 +Expiration Time - Abort SMS = 30 +Expiration Time - Lost Communications = 30 +SMS Recipient Number = +351914785889 +Transmission Interface = Both +Debug Level = None + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Control.Path.VectorField] +Enabled = Never + +[Control.Path.PurePursuit] +Enabled = Always +Entity Label = Path Control +Cross-track -- Monitor = false diff --git a/etc/development/xp1-soi.ini b/etc/development/xp1-soi.ini new file mode 100644 index 0000000000..2ab7423897 --- /dev/null +++ b/etc/development/xp1-soi.ini @@ -0,0 +1,49 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 1 SOI-specific simulation # +############################################################################ + +[Require ../lauv-xplore-1.ini] + +[Require ../common/drip.ini] + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Simulators.Iridium] +Enabled = Simulation +Entity Label = Iridium Simulator +Server Address = localhost +Server Port = 9090 +Debug Level = Debug + +[Transports.UDP] +Underwater Communications = false +Always Transmitted Messages = SimulatedState diff --git a/etc/development/xp1-trex.ini b/etc/development/xp1-trex.ini new file mode 100644 index 0000000000..0543509418 --- /dev/null +++ b/etc/development/xp1-trex.ini @@ -0,0 +1,53 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 1 simulation with T-REX support # +############################################################################ + +[Require ../lauv-xplore-1.ini] + +[Require ../common/trex.ini] + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Simulators.Iridium] +Enabled = Simulation +Entity Label = Iridium Simulator +Server Address = ripples-web.appspot.com +Server Port = 80 +Debug Level = Debug + +[Transports.UDP] +Underwater Communications = false +Always Transmitted Messages = SimulatedState + +[Autonomy.TREX] +TREX ID = 65001 +Debug Level = Debug diff --git a/etc/development/xp2-hil.ini b/etc/development/xp2-hil.ini new file mode 100644 index 0000000000..20b1cc5323 --- /dev/null +++ b/etc/development/xp2-hil.ini @@ -0,0 +1,85 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 2 with forced hardware comms and fins # +############################################################################ + +[Require ../lauv-xplore-2.ini] + +[Power.PCTLv2] +Enabled = Always + +[Actuators.SCRTv4] +Enabled = Always + +[UserInterfaces.LEDs] +Enabled = Always + +[Transports.IridiumSBD] +Enabled = Always + +[Transports.GSM] +Enabled = Always +Serial Port - Device = /dev/ttyACM1 +Serial Port - Baud Rate = 115200 +Reply Timeout = 2.0 +RSSI Periodicity = 10 +Read SMS Periodicity = 10 +SMS Send Timeout = 60 + +[Supervisors.Reporter] +Enabled = Always + +[Monitors.Emergency] +Enabled = Always +Entity Label = Emergency Monitor +Execution Frequency = 1.0 +Execution Priority = 10 +Active = true +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Lost Communications Timeout = 300 +Expiration Time - Abort SMS = 30 +Expiration Time - Lost Communications = 30 +SMS Recipient Number = +351914785889 +Transmission Interface = Both +Debug Level = None + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Control.Path.VectorField] +Enabled = Never + +[Control.Path.PurePursuit] +Enabled = Always +Entity Label = Path Control +Cross-track -- Monitor = false diff --git a/etc/development/xp2-soi.ini b/etc/development/xp2-soi.ini new file mode 100644 index 0000000000..ba473823b4 --- /dev/null +++ b/etc/development/xp2-soi.ini @@ -0,0 +1,52 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 2 SOI-specific simulation # +############################################################################ + +[Require ../lauv-xplore-2.ini] + +[Require ../common/drip.ini] + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Simulators.Iridium] +Enabled = Simulation +Entity Label = Iridium Simulator +Server Address = localhost +Server Port = 9090 +Debug Level = Debug + +[Transports.TCP.Server/BackSeat] +Port = 6007 + +[Transports.UDP] +Underwater Communications = false +Always Transmitted Messages = SimulatedState diff --git a/etc/development/xp2-trex.ini b/etc/development/xp2-trex.ini new file mode 100644 index 0000000000..4084374053 --- /dev/null +++ b/etc/development/xp2-trex.ini @@ -0,0 +1,53 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 2 simulation with T-REX support # +############################################################################ + +[Require ../lauv-xplore-2.ini] + +[Require ../common/trex.ini] + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Simulators.Iridium] +Enabled = Simulation +Entity Label = Iridium Simulator +Server Address = ripples-web.appspot.com +Server Port = 80 +Debug Level = Debug + +[Transports.UDP] +Underwater Communications = false +Always Transmitted Messages = SimulatedState + +[Autonomy.TREX] +TREX ID = 65002 +Debug Level = Debug \ No newline at end of file diff --git a/etc/development/xp3-hil.ini b/etc/development/xp3-hil.ini new file mode 100644 index 0000000000..f8e0c85c16 --- /dev/null +++ b/etc/development/xp3-hil.ini @@ -0,0 +1,85 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 3 with forced hardware comms and fins # +############################################################################ + +[Require ../lauv-xplore-3.ini] + +[Power.PCTLv2] +Enabled = Always + +[Actuators.SCRTv4] +Enabled = Always + +[UserInterfaces.LEDs] +Enabled = Always + +[Transports.IridiumSBD] +Enabled = Always + +[Transports.GSM] +Enabled = Always +Serial Port - Device = /dev/ttyACM1 +Serial Port - Baud Rate = 115200 +Reply Timeout = 2.0 +RSSI Periodicity = 10 +Read SMS Periodicity = 10 +SMS Send Timeout = 60 + +[Supervisors.Reporter] +Enabled = Always + +[Monitors.Emergency] +Enabled = Always +Entity Label = Emergency Monitor +Execution Frequency = 1.0 +Execution Priority = 10 +Active = true +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Lost Communications Timeout = 300 +Expiration Time - Abort SMS = 30 +Expiration Time - Lost Communications = 30 +SMS Recipient Number = +351914785889 +Transmission Interface = Both +Debug Level = None + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Control.Path.VectorField] +Enabled = Never + +[Control.Path.PurePursuit] +Enabled = Always +Entity Label = Path Control +Cross-track -- Monitor = false diff --git a/etc/development/xp4-hil.ini b/etc/development/xp4-hil.ini new file mode 100644 index 0000000000..e415245c92 --- /dev/null +++ b/etc/development/xp4-hil.ini @@ -0,0 +1,85 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 4 with forced hardware comms and fins # +############################################################################ + +[Require ../lauv-xplore-4.ini] + +[Power.PCTLv2] +Enabled = Always + +[Actuators.SCRTv4] +Enabled = Always + +[UserInterfaces.LEDs] +Enabled = Always + +[Transports.IridiumSBD] +Enabled = Always + +[Transports.GSM] +Enabled = Always +Serial Port - Device = /dev/ttyACM1 +Serial Port - Baud Rate = 115200 +Reply Timeout = 2.0 +RSSI Periodicity = 10 +Read SMS Periodicity = 10 +SMS Send Timeout = 60 + +[Supervisors.Reporter] +Enabled = Always + +[Monitors.Emergency] +Enabled = Always +Entity Label = Emergency Monitor +Execution Frequency = 1.0 +Execution Priority = 10 +Active = true +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Lost Communications Timeout = 300 +Expiration Time - Abort SMS = 30 +Expiration Time - Lost Communications = 30 +SMS Recipient Number = +351914785889 +Transmission Interface = Both +Debug Level = None + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Control.Path.VectorField] +Enabled = Never + +[Control.Path.PurePursuit] +Enabled = Always +Entity Label = Path Control +Cross-track -- Monitor = false diff --git a/etc/development/xp5-hil.ini b/etc/development/xp5-hil.ini new file mode 100644 index 0000000000..82d09b9377 --- /dev/null +++ b/etc/development/xp5-hil.ini @@ -0,0 +1,85 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Jose Pinto # +############################################################################ +# LAUV Xplore 5 with forced hardware comms and fins # +############################################################################ + +[Require ../lauv-xplore-5.ini] + +[Power.PCTLv2] +Enabled = Always + +[Actuators.SCRTv4] +Enabled = Always + +[UserInterfaces.LEDs] +Enabled = Always + +[Transports.IridiumSBD] +Enabled = Always + +[Transports.GSM] +Enabled = Always +Serial Port - Device = /dev/ttyACM1 +Serial Port - Baud Rate = 115200 +Reply Timeout = 2.0 +RSSI Periodicity = 10 +Read SMS Periodicity = 10 +SMS Send Timeout = 60 + +[Supervisors.Reporter] +Enabled = Always + +[Monitors.Emergency] +Enabled = Always +Entity Label = Emergency Monitor +Execution Frequency = 1.0 +Execution Priority = 10 +Active = true +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Lost Communications Timeout = 300 +Expiration Time - Abort SMS = 30 +Expiration Time - Lost Communications = 30 +SMS Recipient Number = +351914785889 +Transmission Interface = Both +Debug Level = None + +[Simulators.VSIM] +Stream Speed North = -0.3 +Stream Speed East = 0.1 + +[Control.Path.VectorField] +Enabled = Never + +[Control.Path.PurePursuit] +Enabled = Always +Entity Label = Path Control +Cross-track -- Monitor = false diff --git a/etc/hardware/acoustic-modems/evologics_ip_1.ini b/etc/hardware/acoustic-modems/evologics_ip_1.ini index 62d6386ebc..2cfd27ecf9 100644 --- a/etc/hardware/acoustic-modems/evologics_ip_1.ini +++ b/etc/hardware/acoustic-modems/evologics_ip_1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -36,8 +36,9 @@ Power Channel 7 - Name = Acoustic Modem Power Channel 7 - State = 1 [Transports.UAN] -Enabled = Hardware +Enabled = Always Entity Label = Acoustic Access Controller +Address Section = Evologics Addresses [Transports.Evologics] Enabled = Hardware @@ -47,5 +48,20 @@ Entity Label = Acoustic Modem TCP Port = 9200 Source Level - Control = true +[Transports.SerialOverTCP/Evologics] +Enabled = Never +Serial Port - Device = /dev/ttyUSB1 +Debug Level = Debug + [UserInterfaces.MantaPanel] Sections of System Addresses = Evologics Addresses + +# Simulators +[Simulators.AcousticModem] +Enabled = Simulation +Entity Label = Acoustic Modem Simulator +Modem Type = Evologics +Transmission Speed = 4000 + +# Uncomment to use Evologics simulator +# [Require ../../../private/etc/simulation/evologics-simulator.ini] diff --git a/etc/hardware/acoustic-modems/evologics_ip_19.ini b/etc/hardware/acoustic-modems/evologics_ip_19.ini new file mode 100644 index 0000000000..f720be36e9 --- /dev/null +++ b/etc/hardware/acoustic-modems/evologics_ip_19.ini @@ -0,0 +1,47 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Require evologics_ip_1.ini] + +[Transports.Evologics] +IPv4 Address = 10.0.50.19 +Address Section = Evologics Addresses - DMSMW + +[Transports.UAN] +Address Section = Evologics Addresses - DMSMW + +[Transports.CommManager] +Acoustic Address Section = Evologics Addresses - DMSMW + +[UserInterfaces.MantaPanel] +Sections of System Addresses = Evologics Addresses - DMSMW + +[Transports.Evologics/Simulator] +Address Section = Evologics Addresses - DMSMW + +[Simulators.EvoSimulator] +Address Section = Evologics Addresses - DMSMW diff --git a/etc/hardware/acoustic-modems/evologics_ip_2.ini b/etc/hardware/acoustic-modems/evologics_ip_2.ini index 438e7fb466..567c16c1e1 100644 --- a/etc/hardware/acoustic-modems/evologics_ip_2.ini +++ b/etc/hardware/acoustic-modems/evologics_ip_2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/acoustic-modems/evologics_ip_4.ini b/etc/hardware/acoustic-modems/evologics_ip_4.ini index dfdb969f9f..083e5eee5f 100644 --- a/etc/hardware/acoustic-modems/evologics_ip_4.ini +++ b/etc/hardware/acoustic-modems/evologics_ip_4.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/acoustic-modems/evologics_ip_5.ini b/etc/hardware/acoustic-modems/evologics_ip_5.ini index 104853eb00..f4afe93de5 100644 --- a/etc/hardware/acoustic-modems/evologics_ip_5.ini +++ b/etc/hardware/acoustic-modems/evologics_ip_5.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/acoustic-modems/evologics_ip_6.ini b/etc/hardware/acoustic-modems/evologics_ip_6.ini new file mode 100644 index 0000000000..71a8b4de6e --- /dev/null +++ b/etc/hardware/acoustic-modems/evologics_ip_6.ini @@ -0,0 +1,31 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Require evologics_ip_1.ini] + +[Transports.Evologics] +IPv4 Address = 10.0.50.6 diff --git a/etc/hardware/acoustic-modems/seatrac_ip_200.ini b/etc/hardware/acoustic-modems/seatrac_ip_200.ini index 2172a74250..1694e4d4d0 100644 --- a/etc/hardware/acoustic-modems/seatrac_ip_200.ini +++ b/etc/hardware/acoustic-modems/seatrac_ip_200.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -27,6 +27,13 @@ [Require seatrac_uart.ini] +[Power.MCBv2] +Power Channel 7 - Name = Seatrac modem +Power Channel 7 - State = 1 +Power Channel 6 - Name = N/C +Power Channel 6 - State = 1 + + [Transports.Seatrac] Serial Port - Device = tcp://10.0.50.200:5000 diff --git a/etc/hardware/acoustic-modems/seatrac_uart.ini b/etc/hardware/acoustic-modems/seatrac_uart.ini index f7373e79a3..51d429f7af 100644 --- a/etc/hardware/acoustic-modems/seatrac_uart.ini +++ b/etc/hardware/acoustic-modems/seatrac_uart.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,19 +30,25 @@ [Sensors.MLBLTracker] Enabled = Never -[Transports.Evologics] -Enabled = Never - [Power.MCBv2] Power Channel 6 - Name = Seatrac modem -Power Channel 6 - State = 1 +Power Channel 6 - State = 1 [Transports.UAN] Enabled = Hardware Entity Label = Acoustic Access Controller +USBL Node -- Period = 15 +USBL Node -- Enabled = false +USBL Node -- Absolute Fix = false +USBL Node -- Quick, No Range = false +Address Section = Seatrac Addresses [Transports.Seatrac] -Enabled = Hardware +Serial Port - Device = /dev/uart/1 +Pressure Sensor Mode = true +Address Section = Seatrac Addresses +Debug Level = Debug [UserInterfaces.MantaPanel] Sections of System Addresses = Seatrac Addresses + diff --git a/etc/hardware/acoustic-modems/uModem.ini b/etc/hardware/acoustic-modems/uModem.ini index 8118594875..49a808f755 100644 --- a/etc/hardware/acoustic-modems/uModem.ini +++ b/etc/hardware/acoustic-modems/uModem.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -35,6 +35,9 @@ Enabled = Never [Transports.Seatrac] Enabled = Never +[Transports.CommManager] +Acoustic Address Section = Micromodem Addresses + [Sensors.MLBLTracker] Enabled = Hardware Serial Port - Device = tcp://10.0.50.100:5000 diff --git a/etc/hardware/acoustic-modems/uModem_ip_100.ini b/etc/hardware/acoustic-modems/uModem_ip_100.ini index 697997fe76..4766fc3d53 100644 --- a/etc/hardware/acoustic-modems/uModem_ip_100.ini +++ b/etc/hardware/acoustic-modems/uModem_ip_100.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/acoustic-modems/uModem_ip_101.ini b/etc/hardware/acoustic-modems/uModem_ip_101.ini index 0a555468be..7811f259c8 100644 --- a/etc/hardware/acoustic-modems/uModem_ip_101.ini +++ b/etc/hardware/acoustic-modems/uModem_ip_101.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/acoustic-modems/uModem_ip_102.ini b/etc/hardware/acoustic-modems/uModem_ip_102.ini index 515e920675..cc49c305d7 100644 --- a/etc/hardware/acoustic-modems/uModem_ip_102.ini +++ b/etc/hardware/acoustic-modems/uModem_ip_102.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/acoustic-modems/uModem_ip_103.ini b/etc/hardware/acoustic-modems/uModem_ip_103.ini new file mode 100644 index 0000000000..5fa4b7492c --- /dev/null +++ b/etc/hardware/acoustic-modems/uModem_ip_103.ini @@ -0,0 +1,31 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ + +[Require uModem.ini] + +[Sensors.MLBLTracker] +Serial Port - Device = tcp://10.0.50.103:5000 diff --git a/etc/hardware/acoustic-modems/uModem_ip_104.ini b/etc/hardware/acoustic-modems/uModem_ip_104.ini new file mode 100644 index 0000000000..f853f947ff --- /dev/null +++ b/etc/hardware/acoustic-modems/uModem_ip_104.ini @@ -0,0 +1,38 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Require uModem.ini] + +[Sensors.MLBLTracker] +Serial Port - Device = tcp://10.0.50.104:5000 +Address Section = Micromodem Addresses - DMSMW + +[UserInterfaces.MantaPanel] +Sections of System Addresses = Micromodem Addresses - DMSMW + +[Transports.CommManager] +Acoustic Address Section = Micromodem Addresses - DMSMW diff --git a/etc/hardware/acoustic-modems/uModem_ip_105.ini b/etc/hardware/acoustic-modems/uModem_ip_105.ini new file mode 100644 index 0000000000..e3820d8082 --- /dev/null +++ b/etc/hardware/acoustic-modems/uModem_ip_105.ini @@ -0,0 +1,38 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Require uModem.ini] + +[Sensors.MLBLTracker] +Serial Port - Device = tcp://10.0.50.105:5000 +Address Section = Micromodem Addresses - DMSMW + +[UserInterfaces.MantaPanel] +Sections of System Addresses = Micromodem Addresses - DMSMW + +[Transports.CommManager] +Acoustic Address Section = Micromodem Addresses - DMSMW diff --git a/etc/hardware/lctr-a6xx/aim104multiio.ini b/etc/hardware/lctr-a6xx/aim104multiio.ini index 8c5f0ee0c9..7ce5f16a3d 100644 --- a/etc/hardware/lctr-a6xx/aim104multiio.ini +++ b/etc/hardware/lctr-a6xx/aim104multiio.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/amc.ini b/etc/hardware/lctr-a6xx/amc.ini index ed27ea6b0f..a583022ff5 100644 --- a/etc/hardware/lctr-a6xx/amc.ini +++ b/etc/hardware/lctr-a6xx/amc.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/basic.ini b/etc/hardware/lctr-a6xx/basic.ini index efa130454c..fa455f3ec1 100644 --- a/etc/hardware/lctr-a6xx/basic.ini +++ b/etc/hardware/lctr-a6xx/basic.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/batman.ini b/etc/hardware/lctr-a6xx/batman.ini new file mode 100644 index 0000000000..e0baea0de2 --- /dev/null +++ b/etc/hardware/lctr-a6xx/batman.ini @@ -0,0 +1,62 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: PGonçalves # +############################################################################ + +[Power.BATMANv2] +Enabled = Hardware +Entity Label = BATMAN +Debug Level = None +Serial Port - Device = /dev/ttyUSB0 +Serial Port - Baud Rate = 115200 +Input Timeout = 3.0 +Number of cells = 7 +Scale Factor A/Ah = 1.0 +Cell 1 - Entity Label = CELL 1 +Cell 2 - Entity Label = CELL 2 +Cell 3 - Entity Label = CELL 3 +Cell 4 - Entity Label = CELL 4 +Cell 5 - Entity Label = CELL 5 +Cell 6 - Entity Label = CELL 6 +Cell 7 - Entity Label = CELL 7 +Cell 8 - Entity Label = CELL 8 +Cell 9 - Entity Label = CELL 9 +Cell 10 - Entity Label = CELL 10 +Cell 11 - Entity Label = CELL 11 +Cell 12 - Entity Label = CELL 12 +Cell 13 - Entity Label = CELL 13 +Cell 14 - Entity Label = CELL 14 +Cell 15 - Entity Label = CELL 15 +Remaining Capacity - Entity Label = RCap +Full Capacity - Entity Label = FCap +Dispatch Fuel Level = true +Warning Level = 35 +Error Level = 20 +Error Voltage Value = 23 + +[Monitors.FuelLevel] +Enabled = Never diff --git a/etc/hardware/lctr-a6xx/broom-36v.ini b/etc/hardware/lctr-a6xx/broom-36v.ini index c410f9c01c..2db1265c1e 100644 --- a/etc/hardware/lctr-a6xx/broom-36v.ini +++ b/etc/hardware/lctr-a6xx/broom-36v.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/broom.ini b/etc/hardware/lctr-a6xx/broom.ini index 0ecee2d954..1ea000537c 100644 --- a/etc/hardware/lctr-a6xx/broom.ini +++ b/etc/hardware/lctr-a6xx/broom.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/cyclopsc7.ini b/etc/hardware/lctr-a6xx/cyclopsc7.ini index d93c712a89..858057c766 100644 --- a/etc/hardware/lctr-a6xx/cyclopsc7.ini +++ b/etc/hardware/lctr-a6xx/cyclopsc7.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/deepvision.ini b/etc/hardware/lctr-a6xx/deepvision.ini index 53b20f9a0e..bfad466bb8 100644 --- a/etc/hardware/lctr-a6xx/deepvision.ini +++ b/etc/hardware/lctr-a6xx/deepvision.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # diff --git a/etc/hardware/lctr-a6xx/doamv1.ini b/etc/hardware/lctr-a6xx/doamv1.ini index dcdf22de2b..44c7bd5179 100644 --- a/etc/hardware/lctr-a6xx/doamv1.ini +++ b/etc/hardware/lctr-a6xx/doamv1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/doamv2.ini b/etc/hardware/lctr-a6xx/doamv2.ini index b0d74d8ffe..6d9e245e06 100644 --- a/etc/hardware/lctr-a6xx/doamv2.ini +++ b/etc/hardware/lctr-a6xx/doamv2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/ecopuck.ini b/etc/hardware/lctr-a6xx/ecopuck.ini index ed17ed7773..6558735dbe 100644 --- a/etc/hardware/lctr-a6xx/ecopuck.ini +++ b/etc/hardware/lctr-a6xx/ecopuck.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # diff --git a/etc/hardware/lctr-a6xx/edgetech-2205.ini b/etc/hardware/lctr-a6xx/edgetech-2205.ini index 516c2af7dd..ec2db70ab2 100644 --- a/etc/hardware/lctr-a6xx/edgetech-2205.ini +++ b/etc/hardware/lctr-a6xx/edgetech-2205.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/evologics.ini b/etc/hardware/lctr-a6xx/evologics.ini index eb19c02b31..65fe4b6e48 100644 --- a/etc/hardware/lctr-a6xx/evologics.ini +++ b/etc/hardware/lctr-a6xx/evologics.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -34,3 +34,24 @@ TCP Port = 9200 Source Level = 1 Debug Level = None Source Level - Control = true + +[Transports.SerialOverTCP/Evologics] +Enabled = Never +Entity Label = Evologics SerialOverTCP +TCP - Port = 9200 +Serial Port - Device = /dev/ttyUSB1 +Serial Port - Baud Rate = 19200 +#Debug Level = Debug + +[Transports.UAN] +Address Section = Evologics Addresses + +# Simulators +[Simulators.AcousticModem] +Enabled = Simulation +Entity Label = Acoustic Modem Simulator +Modem Type = Evologics +Transmission Speed = 4000 + +# Uncomment to use Evologics simulator +# [Require ../../../private/etc/simulation/evologics-simulator.ini] \ No newline at end of file diff --git a/etc/hardware/lctr-a6xx/explorerdvl.ini b/etc/hardware/lctr-a6xx/explorerdvl.ini index 276e840762..e55f13813c 100644 --- a/etc/hardware/lctr-a6xx/explorerdvl.ini +++ b/etc/hardware/lctr-a6xx/explorerdvl.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/gps-lc2m.ini b/etc/hardware/lctr-a6xx/gps-lc2m.ini index 61cfb78af5..d36f9fc952 100644 --- a/etc/hardware/lctr-a6xx/gps-lc2m.ini +++ b/etc/hardware/lctr-a6xx/gps-lc2m.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,13 +30,12 @@ [Sensors.GPS] Enabled = Hardware Entity Label = GPS -Activation Time = 0 +Activation Time = 3 Deactivation Time = 0 Debug Level = None Execution Priority = 10 Input Timeout = 4.0 -Serial Port - Device = /dev/ttyACM2 -Serial Port - Baud Rate = 57600 +IO Port - Device = uart:///dev/ttyACM2:57600 Power Channel - Names = GPS, Communications Board Sentence Order = GPVTG, GPZDA, PUBX Initialization String 0 - Command = $PUBX,40,VTG,0,1,0,0,0,0\r\n diff --git a/etc/hardware/lctr-a6xx/gps.ini b/etc/hardware/lctr-a6xx/gps.ini index df0fc3d8da..fa4643952a 100644 --- a/etc/hardware/lctr-a6xx/gps.ini +++ b/etc/hardware/lctr-a6xx/gps.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,8 +30,8 @@ [Sensors.GPS] Enabled = Hardware Entity Label = GPS -Serial Port - Device = /dev/ttyACM0 -Serial Port - Baud Rate = 19200 +Activation Time = 3.0 +IO Port - Device = uart:///dev/ttyACM0:19200 Sentence Order = GPVTG, GPZDA, PUBX Initialization String 0 - Command = $PUBX,40,VTG,0,0,0,1,0,0\r\n Initialization String 1 - Command = $PUBX,40,ZDA,0,0,0,1,0,0\r\n diff --git a/etc/hardware/lctr-a6xx/gsm-lc2m.ini b/etc/hardware/lctr-a6xx/gsm-lc2m.ini index f04ef74da7..eb52a8897b 100644 --- a/etc/hardware/lctr-a6xx/gsm-lc2m.ini +++ b/etc/hardware/lctr-a6xx/gsm-lc2m.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -40,3 +40,4 @@ Reply Timeout = 2.0 RSSI Periodicity = 10 Read SMS Periodicity = 10 SMS Send Timeout = 60 +USSD code = 123 diff --git a/etc/hardware/lctr-a6xx/gsm.ini b/etc/hardware/lctr-a6xx/gsm.ini index 5f2dea0107..d1a30c005c 100644 --- a/etc/hardware/lctr-a6xx/gsm.ini +++ b/etc/hardware/lctr-a6xx/gsm.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/hg1700.ini b/etc/hardware/lctr-a6xx/hg1700.ini index 4854309685..2f0bc4f3c9 100644 --- a/etc/hardware/lctr-a6xx/hg1700.ini +++ b/etc/hardware/lctr-a6xx/hg1700.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -52,3 +52,5 @@ Standard Deviation - Angular Velocity = 0.05 Standard Deviation - Heading Offset = 0 Gyro Rate Bias = 0 Activation Control = true +Measures Euler Angles = false +Output Deltas = true \ No newline at end of file diff --git a/etc/hardware/lctr-a6xx/ifog.ini b/etc/hardware/lctr-a6xx/ifog.ini index 7ab4d22832..7c32f70374 100644 --- a/etc/hardware/lctr-a6xx/ifog.ini +++ b/etc/hardware/lctr-a6xx/ifog.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/imagenex837b.ini b/etc/hardware/lctr-a6xx/imagenex837b.ini index db0c631575..6ab75a8beb 100644 --- a/etc/hardware/lctr-a6xx/imagenex837b.ini +++ b/etc/hardware/lctr-a6xx/imagenex837b.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -33,8 +33,8 @@ Entity Label = Multibeam Active = false Active - Scope = maneuver Active - Visibility = user -IPv4 Address = 192.168.0.2 -TCP Port = 4040 +Activation Time = 3.0 +IO Port - Device = tcp://192.168.0.2:4040 Start Gain = 3 Absorption = 0.1 Data Points = 8000 diff --git a/etc/hardware/lctr-a6xx/imagenex852.ini b/etc/hardware/lctr-a6xx/imagenex852.ini index b6640aa853..0a610c08de 100644 --- a/etc/hardware/lctr-a6xx/imagenex852.ini +++ b/etc/hardware/lctr-a6xx/imagenex852.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -33,11 +33,11 @@ Entity Label = Echo Sounder Active = false Active - Scope = idle Active - Visibility = user -Activation Time = 0 +Activation Time = 3.0 Deactivation Time = 0 Debug Level = None Execution Priority = 10 -Serial Port - Device = /dev/uart/9 +IO Port - Device = uart:///dev/uart/9 Sampling Frequency = 5 Filter Median Elements = 7 Filter Threshold = 90 diff --git a/etc/hardware/lctr-a6xx/imagenex872.ini b/etc/hardware/lctr-a6xx/imagenex872.ini index 97f794440f..b76514d35f 100644 --- a/etc/hardware/lctr-a6xx/imagenex872.ini +++ b/etc/hardware/lctr-a6xx/imagenex872.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -33,13 +33,12 @@ Entity Label = Sidescan Active = false Active - Scope = maneuver Active - Visibility = user -Activation Time = 0 +Activation Time = 3.0 Deactivation Time = 0 Debug Level = None Execution Frequency = 1.0 Execution Priority = 10 -IPv4 Address = 192.168.0.5 -TCP Port = 4040 +IO Port - Device = tcp://192.168.0.5:4040 Data Gain = 20 Balance Gain = 30 Frequency = 770 diff --git a/etc/hardware/lctr-a6xx/imagenex881a.ini b/etc/hardware/lctr-a6xx/imagenex881a.ini index 2f2aeca673..a3e41c1d9b 100644 --- a/etc/hardware/lctr-a6xx/imagenex881a.ini +++ b/etc/hardware/lctr-a6xx/imagenex881a.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/iridiumsbd-lc2m.ini b/etc/hardware/lctr-a6xx/iridiumsbd-lc2m.ini index 77e2cc6830..66e6b73a31 100644 --- a/etc/hardware/lctr-a6xx/iridiumsbd-lc2m.ini +++ b/etc/hardware/lctr-a6xx/iridiumsbd-lc2m.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -29,9 +29,12 @@ [Transports.IridiumSBD] Enabled = Hardware +Debug Level = None Entity Label = Iridium Modem Serial Port - Device = /dev/ttyACM0 Serial Port - Baud Rate = 19200 +Use 9523N Module = false +Serial Port 9523 - Baud Rate = 115200 Mailbox Check - Periodicity = 1800 [Transports.Iridium] diff --git a/etc/hardware/lctr-a6xx/keller.ini b/etc/hardware/lctr-a6xx/keller.ini index e56932d70e..32d416e84f 100644 --- a/etc/hardware/lctr-a6xx/keller.ini +++ b/etc/hardware/lctr-a6xx/keller.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -29,15 +29,14 @@ [Sensors.Keller] Enabled = Hardware -Activation Time = 0 +Activation Time = 3.0 Deactivation Time = 0 Debug Level = None Execution Frequency = 10 Execution Priority = 10 Entity Label = Depth Sensor Entity Label - GPS = GPS -Serial Port - Device = /dev/uart/2 -Serial Port - Baud Rate = 9600 +IO Port - Device = uart:///dev/uart/2:9600 Serial Port - Local Echo = 1 Device Address = 250 Water Density = 1025.0 diff --git a/etc/hardware/lctr-a6xx/klein3500.ini b/etc/hardware/lctr-a6xx/klein3500.ini index 70c5e13853..7952242ea4 100644 --- a/etc/hardware/lctr-a6xx/klein3500.ini +++ b/etc/hardware/lctr-a6xx/klein3500.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -33,16 +33,17 @@ Entity Label = Sidescan Active = false Active - Scope = maneuver Active - Visibility = user -Activation Time = 80 -Deactivation Time = 0 +Activation Time = 90 +Deactivation Time = 10 Execution Priority = 10 Debug Level = None -Recording File Prefix = Data_ -Recording Path Prefix = /mnt/testData Power Channel = Private (Sidescan) -TCP Port = 4660 Range = 50 High-Frequency Channel = true Low-Frequency Channel = false -Pings Per File = 50000 -Output Trigger - Slave Entity Labels = DVL +Low-Frequency Bathymetry Channel = false +Bathymetry Channel Available = false +Pings Per File = 10000 +Device URL = tcp://192.168.0.81:4660 +NMEA Over UDP - Port = 24302 +NFS Logging = false diff --git a/etc/hardware/lctr-a6xx/led4r.ini b/etc/hardware/lctr-a6xx/led4r.ini index f4256a17ce..aad31e13c0 100644 --- a/etc/hardware/lctr-a6xx/led4r.ini +++ b/etc/hardware/lctr-a6xx/led4r.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/leds.ini b/etc/hardware/lctr-a6xx/leds.ini index d5c1b3eab8..5d8d9a4899 100644 --- a/etc/hardware/lctr-a6xx/leds.ini +++ b/etc/hardware/lctr-a6xx/leds.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/limu.ini b/etc/hardware/lctr-a6xx/limu.ini index 483be75670..5d155ede2e 100644 --- a/etc/hardware/lctr-a6xx/limu.ini +++ b/etc/hardware/lctr-a6xx/limu.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,9 +31,9 @@ Enabled = Hardware Execution Priority = 50 Entity Label = AHRS -Activation Time = 0 +Activation Time = 3.0 Deactivation Time = 0 -Serial Port - Device = /dev/uart/1 +IO Port - Device = uart:///dev/uart/1 Power Channel - Name = AHRS Output Frequency = 50 Debug Level = None diff --git a/etc/hardware/lctr-a6xx/lumenera.ini b/etc/hardware/lctr-a6xx/lumenera.ini index b70b39a8a7..862fae8b7d 100644 --- a/etc/hardware/lctr-a6xx/lumenera.ini +++ b/etc/hardware/lctr-a6xx/lumenera.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/mcc1608g.ini b/etc/hardware/lctr-a6xx/mcc1608g.ini index 0cff4af9db..78bc1ebe1b 100644 --- a/etc/hardware/lctr-a6xx/mcc1608g.ini +++ b/etc/hardware/lctr-a6xx/mcc1608g.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/mcd4r.ini b/etc/hardware/lctr-a6xx/mcd4r.ini index 3238fc479a..937c89cadc 100644 --- a/etc/hardware/lctr-a6xx/mcd4r.ini +++ b/etc/hardware/lctr-a6xx/mcd4r.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/metrecx.ini b/etc/hardware/lctr-a6xx/metrecx.ini index dd745c0943..9679da4d90 100644 --- a/etc/hardware/lctr-a6xx/metrecx.ini +++ b/etc/hardware/lctr-a6xx/metrecx.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -29,8 +29,8 @@ [Sensors.MetrecX] Enabled = Hardware Entity Label = Water Quality Sensor -Serial Port - Device = /dev/uart/7 -Serial Port - Baud Rate = 38400 +Activation Time = 3.0 +IO Port - Device = uart:///dev/uart/7:38400 Input Timeout = 10 Geopotential Anomaly = 0 PH Calibration Buffer = 7.0 diff --git a/etc/hardware/lctr-a6xx/micromodem.ini b/etc/hardware/lctr-a6xx/micromodem.ini index 36c710a51d..a830745323 100644 --- a/etc/hardware/lctr-a6xx/micromodem.ini +++ b/etc/hardware/lctr-a6xx/micromodem.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/microstrain3dmgx1.ini b/etc/hardware/lctr-a6xx/microstrain3dmgx1.ini new file mode 100644 index 0000000000..da299d70af --- /dev/null +++ b/etc/hardware/lctr-a6xx/microstrain3dmgx1.ini @@ -0,0 +1,46 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Teixeira # +############################################################################ + +[Sensors.Microstrain3DMGX1] +Enabled = Hardware +Debug Level = None +Entity Label = AHRS +Hard-Iron Calibration = -0.0050, -0.0640, 0.0000 +IMU Rotation Matrix = 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 + +Serial Port - Device = /dev/ttyUSB0 +Serial Port - Baud Rate = 38400 + +[Simulators.IMU/AHRS] +Enabled = Simulation +Entity Label = AHRS +Standard Deviation - Euler Angles = 0.05 +Standard Deviation - Angular Velocity = 0.05 +Standard Deviation - Heading Offset = 0 +Gyro Rate Bias = 0 diff --git a/etc/hardware/lctr-a6xx/microstrain3dmgx3.ini b/etc/hardware/lctr-a6xx/microstrain3dmgx3.ini index 68a3002c51..e283b9ab10 100644 --- a/etc/hardware/lctr-a6xx/microstrain3dmgx3.ini +++ b/etc/hardware/lctr-a6xx/microstrain3dmgx3.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,12 +31,11 @@ Enabled = Hardware Execution Frequency = 50 Execution Priority = 50 -Activation Time = 0 +Activation Time = 3.0 Deactivation Time = 0 Debug Level = None Entity Label = AHRS -Serial Port - Device = /dev/uart/1 -Serial Port - Baud Rate = 115200 +IO Port - Device = uart:///dev/uart/1:115200 Timeout - Error = 3.0 Timeout - Failure = 6.0 Hard-Iron Calibration = 0.0, 0.0, 0.0 diff --git a/etc/hardware/lctr-a6xx/microstrainmip.ini b/etc/hardware/lctr-a6xx/microstrainmip.ini index c6a90bfc1a..e1e94136c9 100644 --- a/etc/hardware/lctr-a6xx/microstrainmip.ini +++ b/etc/hardware/lctr-a6xx/microstrainmip.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/minisvs.ini b/etc/hardware/lctr-a6xx/minisvs.ini index f9e647a47e..270daea5d2 100644 --- a/etc/hardware/lctr-a6xx/minisvs.ini +++ b/etc/hardware/lctr-a6xx/minisvs.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/navquestdvl.ini b/etc/hardware/lctr-a6xx/navquestdvl.ini index eb28eb5d12..8db0d8f317 100644 --- a/etc/hardware/lctr-a6xx/navquestdvl.ini +++ b/etc/hardware/lctr-a6xx/navquestdvl.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/nortekdvl.ini b/etc/hardware/lctr-a6xx/nortekdvl.ini index f7324c5cfe..2aaf0b872b 100644 --- a/etc/hardware/lctr-a6xx/nortekdvl.ini +++ b/etc/hardware/lctr-a6xx/nortekdvl.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # @@ -30,18 +30,30 @@ Enabled = Hardware Entity Label = DVL Execution Priority = 10 -Activation Time = 40.0 +Activation Time = 50.0 Deactivation Time = 5.0 Debug Level = None +Active = false +Active - Scope = idle +Active - Visibility = developer +Device Orientation = 0, -90, 45 +Device Position = 0.50, 0, 0.20 IO Port - Device = tcp://10.0.10.247:9000 Serial Port - Baud Rate = 115200 Sampling Rate = 5.0 +Blanking Distance = 0.01 Enable Input Trigger = false +Input Trigger Type = TTLFALL Power Channel = Private (DVL) -Automatic Activation = true +Power Level = -2.0 +Type Activation = Always Hardware Debug Mode = false +Speed of Sound = 0 +Salinity = 35 +Additional Stream A = OFF +Additional Stream B = OFF +Discart Pressure measurements = 3 Current Profiler -- Enabled = false -Current Profiler -- Record File = CurrentProfile.ad2cp Current Profiler -- Get At Nth Ping = 20 Current Profiler -- Number of Cells = 10 Current Profiler -- Cell Size = 1.0 diff --git a/etc/hardware/lctr-a6xx/oemx.ini b/etc/hardware/lctr-a6xx/oemx.ini new file mode 100644 index 0000000000..9301b3a562 --- /dev/null +++ b/etc/hardware/lctr-a6xx/oemx.ini @@ -0,0 +1,43 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: PGonçalves # +############################################################################ + +[Sensors.OEMX] +Enabled = Hardware +Entity Label = OEMX +Debug Level = None +Serial Port - Device = /dev/ttyUSB1 +Serial Port - Baud Rate = 38400 +Primary Mount = Conductivity + #SoundSpeed + #Temperature +Secondary Mount = Pressure, + Temperature + #Turbidity +Input Timeout = 4 +Number of Samples/s = 1 diff --git a/etc/hardware/lctr-a6xx/optode4831.ini b/etc/hardware/lctr-a6xx/optode4831.ini index e83370f695..3d173e54d3 100644 --- a/etc/hardware/lctr-a6xx/optode4831.ini +++ b/etc/hardware/lctr-a6xx/optode4831.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # diff --git a/etc/hardware/lctr-a6xx/os5000.ini b/etc/hardware/lctr-a6xx/os5000.ini index ca6868e00e..c972a4fd3e 100644 --- a/etc/hardware/lctr-a6xx/os5000.ini +++ b/etc/hardware/lctr-a6xx/os5000.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,7 +30,7 @@ [Sensors.OS4000] Enabled = Hardware Entity Label = AHRS -Serial Port - Device = /dev/uart/1 -Serial Port - Baud Rate = 115200 +Activation Time = 3.0 +IO Port - Device = uart:///dev/uart/1:115200 Data Rate = 40 Data Timeout = 1.0 diff --git a/etc/hardware/lctr-a6xx/pctlv2.ini b/etc/hardware/lctr-a6xx/pctlv2.ini index 9ae6d67851..47141b4953 100644 --- a/etc/hardware/lctr-a6xx/pctlv2.ini +++ b/etc/hardware/lctr-a6xx/pctlv2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/psimar.ini b/etc/hardware/lctr-a6xx/psimar.ini index 8d87526282..27c9427a58 100644 --- a/etc/hardware/lctr-a6xx/psimar.ini +++ b/etc/hardware/lctr-a6xx/psimar.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/sadc.ini b/etc/hardware/lctr-a6xx/sadc.ini index 838df0a539..14cb5fff60 100644 --- a/etc/hardware/lctr-a6xx/sadc.ini +++ b/etc/hardware/lctr-a6xx/sadc.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/sch311x.ini b/etc/hardware/lctr-a6xx/sch311x.ini index 531ab09611..356e4ea7a9 100644 --- a/etc/hardware/lctr-a6xx/sch311x.ini +++ b/etc/hardware/lctr-a6xx/sch311x.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/scrtv4.ini b/etc/hardware/lctr-a6xx/scrtv4.ini index 33ced7a815..8b3c76c83d 100644 --- a/etc/hardware/lctr-a6xx/scrtv4.ini +++ b/etc/hardware/lctr-a6xx/scrtv4.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/seatrac.ini b/etc/hardware/lctr-a6xx/seatrac.ini index ab74c9ed2e..d68e397e91 100644 --- a/etc/hardware/lctr-a6xx/seatrac.ini +++ b/etc/hardware/lctr-a6xx/seatrac.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,11 +30,25 @@ [Require ../../common/seatrac-addresses.ini] [Transports.Seatrac] -Enabled = Never +Enabled = Hardware Debug Level = None Entity Label = Acoustic Modem -Serial Port - Device = /dev/uart/1 +Serial Port - Device = /dev/uart/10 Serial Port - Baud Rate = 115200 Activation Time = 3.5 Deactivation Time = 0 -Transmit Only Underwater = false +Transmit Only Underwater = true +Address Section = Seatrac Addresses +Max Range = 1000 +AHRS Mode = false +Pressure Sensor Mode = true +Use Internal Pressure Sensor for Medium = true +USBL Mode = true +Enhanced USBL = true +AHRS Rotation Matrix = 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 +Hard-Iron Calibration = 0.0, 0.0, 0.0 + +[Transports.UAN] +Address Section = Seatrac Addresses diff --git a/etc/hardware/lctr-a6xx/slavecpu.ini b/etc/hardware/lctr-a6xx/slavecpu.ini index c4572651fc..6e9f434e16 100644 --- a/etc/hardware/lctr-a6xx/slavecpu.ini +++ b/etc/hardware/lctr-a6xx/slavecpu.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/smartx.ini b/etc/hardware/lctr-a6xx/smartx.ini index 6f99acaebc..a26da845c1 100644 --- a/etc/hardware/lctr-a6xx/smartx.ini +++ b/etc/hardware/lctr-a6xx/smartx.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a6xx/sw100.ini b/etc/hardware/lctr-a6xx/sw100.ini index ef3c29c4ae..6d07e7ec7a 100644 --- a/etc/hardware/lctr-a6xx/sw100.ini +++ b/etc/hardware/lctr-a6xx/sw100.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,8 +30,9 @@ [Sensors.SW100] Enabled = Hardware Execution Frequency = 10 +Activation Time = 3.0 Entity Label = CTD -Serial Port - Device = /dev/uart/7 +IO Port - Device = uart:///dev/uart/7:9600 Depth Calibration = 1.0, -0.37 Data Timeout = 2.0 diff --git a/etc/hardware/lctr-a6xx/xchangesv.ini b/etc/hardware/lctr-a6xx/xchangesv.ini index b12ad0994f..fcdc135ef5 100644 --- a/etc/hardware/lctr-a6xx/xchangesv.ini +++ b/etc/hardware/lctr-a6xx/xchangesv.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,9 +30,9 @@ [Sensors.XchangeSV] Enabled = Hardware Entity Label = Sound Speed Sensor -Serial Port - Device = /dev/uart/7 -Serial Port - Baud Rate = 19200 +IO Port - Device = uart:///dev/uart/7:19200 Input Timeout = 4 +Activation Time = 3.0 [Simulators.Gaussian/SoundSpeed] Enabled = Simulation diff --git a/etc/hardware/lctr-a6xx/xr620ctd.ini b/etc/hardware/lctr-a6xx/xr620ctd.ini index 39470394a6..bf654817dc 100644 --- a/etc/hardware/lctr-a6xx/xr620ctd.ini +++ b/etc/hardware/lctr-a6xx/xr620ctd.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-a9xx.ini b/etc/hardware/lctr-a9xx.ini index 8b827ccaeb..d1850afc37 100644 --- a/etc/hardware/lctr-a9xx.ini +++ b/etc/hardware/lctr-a9xx.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -108,6 +108,8 @@ Power Channel 5 - Name = POE 1 Power Channel 5 - State = 1 Power Channel 6 - Name = Micromodem Power Channel 6 - State = 1 +Power Channel 7 - Name = Acoustic Modem +Power Channel 7 - State = 1 Power Channel 9 - Name = Ethernet Switch Power Channel 9 - State = 1 Power Channel 11 - Name = GPS @@ -118,7 +120,6 @@ Power Channel 13 - State = 1 # Not connected. Power Channel 1 - Name = N/C (+12V_S2) Power Channel 2 - Name = N/C (+12V_S1) -Power Channel 7 - Name = N/C (Bat_Out) Power Channel 10 - Name = N/C (HUB_3) Power Channel 14 - Name = N/C Power Channel 15 - Name = N/C @@ -129,8 +130,11 @@ Enabled = Always Entity Label = UDP Transports = Abort, AcousticOperation, + AcousticRequest, + AcousticStatus, AcousticSystemsQuery, AcousticSystems, + CommSystemsQuery, CpuUsage, Current, Depth, @@ -139,9 +143,11 @@ Transports = Abort, EntityParameters, EntityState, EstimatedState, + EulerAngles, FuelLevel, GpsFix, Heartbeat, + IndicatedSpeed, IridiumMsgRx, IridiumMsgTx, IridiumTxStatus, @@ -149,20 +155,34 @@ Transports = Abort, LblRangeAcceptance, LogBookControl, LoggingControl, + MagneticField, NavigationUncertainty, PlanControl, PlanControlState, RemoteSensorInfo, RSSI, + SetControlSurfaceDeflection, + SmsRequest, + SmsStatus, + StateReport, StorageUsage, + TelemetryMsg, Temperature, TextMessage, + TransmissionRequest, + TransmissionStatus, + UamTxFrame, + UamRxFrame, + UamTxStatus, + UamRxRange, UsblAnglesExtended, UsblPositionExtended, UsblFixExtended, UsblModem, UsblConfig, - Voltage + VehicleState, + Voltage, + VtolState Local Port = 6002 Print Incoming Messages = 0 Print Outgoing Messages = 0 @@ -173,17 +193,24 @@ Entity Label = Logger Flush Interval = 5 LSF Compression Method = none Transports = Abort, + Acceleration, + AngularVelocity, Announce, AcousticLink, AcousticOperation, + CommSystemsQuery, CpuUsage, Current, Depth, DevDataText, EntityList, EntityState, + EstimatedState, + FuelLevel, + EulerAngles, GpsFix, Heartbeat, + IndicatedSpeed, IridiumMsgRx, IridiumMsgTx, IridiumTxStatus, @@ -191,11 +218,20 @@ Transports = Abort, LblRangeAcceptance, LogBookControl, LogBookEntry, + LoggingControl, + MagneticField, + SetControlSurfaceDeflection, PlanControl, + PlanControlState, + Pressure, PowerChannelControl, RemoteSensorInfo, + ReportControl, RSSI, + SimAcousticMessage, + SoundSpeed, StorageUsage, + TelemetryMsg, Temperature, TextMessage, UamRxFrame, @@ -207,12 +243,15 @@ Transports = Abort, UsblFixExtended, UsblModem, UsblConfig, - Voltage + VehicleState, + Voltage, + VtolState + [Sensors.GPS] Enabled = Hardware +Activation Time = 3.0 Entity Label = GPS -Serial Port - Device = /dev/ttyACM0 -Serial Port - Baud Rate = 57600 +IO Port - Device = uart:///dev/ttyACM0:57600 Sentence Order = GPVTG, GPZDA, PUBX Initialization String 0 - Command = $PUBX,40,VTG,0,0,0,1\r\n Initialization String 1 - Command = $PUBX,40,ZDA,0,0,0,1\r\n @@ -224,6 +263,11 @@ Initialization String 6 - Command = $PUBX,40,RMC,0,0,0,0\r\n Initialization String 7 - Command = $PUBX,40,GGA,0,0,0,0\r\n Initialization String 8 - Command = $PUBX,40,GLL,0,0,0,0\r\n +[Simulators.GPS] +Enabled = Simulation +Entity Label = GPS +Initial Position = 41.1850, -8.7046 + [Supervisors.ClockPPS] Enabled = Hardware Entity Label = Clock @@ -232,6 +276,25 @@ PPS - Propagation Delay = 675 Execute On Synchronization = hwclock -w Debug Level = None +[Monitors.MantaFuelLevel] +Enabled = Hardware +Entity Label = Manta Fuel Level +Debug Level = None +Execution Frequency = 0.2 +Entity Label - FuelLevel = FuelLevel +Fuel Level 1 = 28.5 +Fuel Level 2 = 27.5 +Fuel Level 3 = 26.5 +Fuel Level 4 = 24.6 +Fuel Level 5 = 23.5 +Entity Label for Main Voltage = Main Board +Entity Label for Charger Current = Charger +Current Value Charger Reject = 0.05 +Fuel Percentage Warning = 40 +Fuel Percentage Auto Shutdown = 10 +Use Voltage Value = true +Fuel Voltage Warning = 23.5 +Fuel Voltage Auto Shutdown = 22.5 [Navigation.General.GPSNavigation] Enabled = Always @@ -248,8 +311,7 @@ Serial Port - Local Echo = 0 [Sensors.AIS] Enabled = Never Entity Label = AIS Receiver -Serial Port - Device = /dev/uart/2 -Serial Port - Baud Rate = 38400 +IO Port - Device = uart:///dev/uart/2:38400 [Transports.MobileInternet] Enabled = Hardware @@ -262,4 +324,54 @@ Enabled = Always Entity Label = Text Message Parser Activation Time = 0 Deactivation Time = 0 -Execution Priority = 10 \ No newline at end of file +Execution Priority = 10 + +[Transports.TCP.Server/BackSeat] +Enabled = Always +Entity Label = Back Seat TCP Server +Announce Service = true +Debug Level = None +Activation Time = 0 +Deactivation Time = 0 +Execution Priority = 10 +Port = 6006 +Trace - Incoming Messages = false +Trace - Outgoing Messages = false +Transports = Announce, + Abort, + AcousticLink, + AlignmentState, + EntityParameters, + EstimatedState, + FollowRefState, + FuelLevel, + FollowRefState, + GpsFix, + IridiumTxStatus, + PathControlState, + PlanControl, + PlanControlState, + PlanDB, + ReportControl, + Salinity, + SoiCommand, + SoiPlan, + Temperature, + TransmissionStatus, + UamRxFrame, + UamTxStatus, + VehicleMedium, + VehicleState +Filtered Entities = Temperature:CTD+OEMX + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM +Debug Level = Debug + +[Transports.TCPOnDemand] +Enabled = Always +Entity Label = TCP On Demand diff --git a/etc/hardware/lctr-b2xx/luemb.ini b/etc/hardware/lctr-b2xx/luemb.ini index 9e681df604..2bb0561629 100644 --- a/etc/hardware/lctr-b2xx/luemb.ini +++ b/etc/hardware/lctr-b2xx/luemb.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-rpi/apd.ini b/etc/hardware/lctr-rpi/apd.ini index 35d029fa35..63fa599a48 100644 --- a/etc/hardware/lctr-rpi/apd.ini +++ b/etc/hardware/lctr-rpi/apd.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/lctr-rpi/cpmb-h.ini b/etc/hardware/lctr-rpi/cpmb-h.ini new file mode 100644 index 0000000000..097b03de76 --- /dev/null +++ b/etc/hardware/lctr-rpi/cpmb-h.ini @@ -0,0 +1,71 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://www.lsts.pt/dune/licence. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Power.CPMBH] +Enabled = Always #Hardware +Entity Label = Power Board +Serial Port - Device = /dev/ttyUSB0 +ADC VDelta Offset = 0.035 +Debug Level = None + +# ADC Channels +ADC Channel 0 - Message = Voltage +ADC Channel 0 - Entity Label = Power Supply (+5VDC) +ADC Channel 0 - Conversion = 7.2, 0.0 + +ADC Channel 1 - Message = Voltage +ADC Channel 1 - Entity Label = Power Supply (+24VDC) +ADC Channel 1 - Conversion = 31.9, 0.0 + +ADC Channel 2 - Message = Voltage +ADC Channel 2 - Entity Label = Batteries +ADC Channel 2 - Conversion = 60.0, 0.0 + +ADC Channel 3 - Message = Current +ADC Channel 3 - Entity Label = Batteries +ADC Channel 3 - Conversion = 8.3, 0.0 + +# Power Channels +Power Channel 0 - Name = 5V C.3 (Raspberry Pi 4) +Power Channel 0 - State = 1 + +Power Channel 1 - Name = 5V C.4 (Pixhawk) +Power Channel 1 - State = 1 + +Power Channel 2 - Name = 24V C.2 (Acoustic Modem) +Power Channel 2 - State = 1 + +Power Channel 3 - Name = 24V C.3 (Switch SwitchBlox) +Power Channel 3 - State = 1 + +Power Channel 4 - Name = 24V C.4 (Mikrokit Groove) +Power Channel 4 - State = 1 + +Power Channel 5 - Name = 24V C.5 (24V Spare) +Power Channel 5 - State = 1 + diff --git a/etc/hardware/lctr-rpi/cpmb.ini b/etc/hardware/lctr-rpi/cpmb.ini new file mode 100644 index 0000000000..b08de6b6c7 --- /dev/null +++ b/etc/hardware/lctr-rpi/cpmb.ini @@ -0,0 +1,66 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://www.lsts.pt/dune/licence. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Power.CPMB] +Enabled = Hardware +Entity Label = Power Board +Serial Port - Device = /dev/ttyUSB0 +Debug Level = None + +# ADC Channels +ADC Channel 0 - Message = Current +ADC Channel 0 - Entity Label = Power Supply (+12VDC) +ADC Channel 0 - Conversion = 2.78, 0.0 + +ADC Channel 1 - Message = Voltage +ADC Channel 1 - Entity Label = Power Supply (+12VDC) +ADC Channel 1 - Conversion = 17.0, 0.0 + +ADC Channel 2 - Message = Current +ADC Channel 2 - Entity Label = Power Supply (+5VDC) +ADC Channel 2 - Conversion = 3.79, 0.0 + +ADC Channel 3 - Message = Voltage +ADC Channel 3 - Entity Label = Power Supply (+5VDC) +ADC Channel 3 - Conversion = 7.2, 0.0 + +# Power Channels +Power Channel 0 - Name = 5V C.3 (Photo Trigger) +Power Channel 0 - State = 0 + +Power Channel 1 - Name = 5V C.4 (5V Sensor) +Power Channel 1 - State = 1 + +Power Channel 2 - Name = 12V C.3 (12V Sensor) +Power Channel 2 - State = 1 + +Power Channel 3 - Name = Bat Out C.1 (Acoustic Modem) +Power Channel 3 - State = 1 + +Power Channel 4 - Name = Bat Out C.2 (Spare) +Power Channel 4 - State = 1 \ No newline at end of file diff --git a/etc/hardware/lctr-rpi/cpmbv2.ini b/etc/hardware/lctr-rpi/cpmbv2.ini new file mode 100644 index 0000000000..6f8f7b6d8a --- /dev/null +++ b/etc/hardware/lctr-rpi/cpmbv2.ini @@ -0,0 +1,83 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://www.lsts.pt/dune/licence. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Power.CPMBv2] +Enabled = Hardware +Entity Label = Power Board +Serial Port - Device = /dev/ttyUSB0 +Debug Level = None + +# ADC Channels +ADC Channel 0 - Message = Voltage +ADC Channel 0 - Entity Label = Power Supply (+5VDC) +ADC Channel 0 - Conversion = 7.2, 0.0 + +ADC Channel 1 - Message = Voltage +ADC Channel 1 - Entity Label = Power Supply (+12VDC) +ADC Channel 1 - Conversion = 17.0, 0.0 + +ADC Channel 2 - Message = Voltage +ADC Channel 2 - Entity Label = Power Supply (+24VDC) +ADC Channel 2 - Conversion = 31.9, 0.0 + +ADC Channel 3 - Message = Voltage +ADC Channel 3 - Entity Label = Batteries +ADC Channel 3 - Conversion = 60.0, 0.0 + +ADC Channel 4 - Message = Current +ADC Channel 4 - Entity Label = Batteries +ADC Channel 4 - Conversion = 8.3, 0.0 + +# Power Channels +Power Channel 0 - Name = 5V C.3 (5V Sensor) +Power Channel 0 - State = 1 + +Power Channel 1 - Name = 5V C.4 (5V Sensor) +Power Channel 1 - State = 1 + +Power Channel 2 - Name = 12V C.2 (12V Sensor) +Power Channel 2 - State = 1 + +Power Channel 3 - Name = 12V C.3 (12V Sensor) +Power Channel 3 - State = 1 + +Power Channel 4 - Name = 12V C.4 (12V Sensor) +Power Channel 4 - State = 1 + +Power Channel 5 - Name = 24V C.1 (Acoustic Modem) +Power Channel 5 - State = 1 + +Power Channel 6 - Name = 24V C.2 (Landing Gear) +Power Channel 6 - State = 1 + +Power Channel 7 - Name = Bat Out C.1 (Spare) +Power Channel 7 - State = 1 + +Power Channel 8 - Name = Bat Out C.2 (Spare) +Power Channel 8 - State = 1 + diff --git a/etc/hardware/lctr-rpi/thermalzone.ini b/etc/hardware/lctr-rpi/thermalzone.ini new file mode 100644 index 0000000000..58a6c8609c --- /dev/null +++ b/etc/hardware/lctr-rpi/thermalzone.ini @@ -0,0 +1,33 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: PGonçalves # +############################################################################ + +[Sensors.ThermalZone] +Enabled = Hardware +Entity Label = Thermal Zone +Execution Frequency = 1 +Path = /sys/class/thermal/thermal_zone0/temp +Entity Label - Temperature = Mainboard (Core) \ No newline at end of file diff --git a/etc/hardware/lumenera-offboard.ini b/etc/hardware/lumenera-offboard.ini index 570935e23d..d029086dd3 100644 --- a/etc/hardware/lumenera-offboard.ini +++ b/etc/hardware/lumenera-offboard.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/hardware/power-consumption.ini b/etc/hardware/power-consumption.ini index a886e995f1..adba618e2d 100644 --- a/etc/hardware/power-consumption.ini +++ b/etc/hardware/power-consumption.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -34,6 +34,8 @@ IEI PM-LX2-800W = On , On , Off , Off , 7.95 UDOO = On , Off , On , Off , 2.500, 0.000, Auxiliary CPU BeagleBone Black = On , Off , On , Off , 2.000, 2.000, Auxiliary CPU Raspberry Pi 2 = On , Off , On , Off , 3.000, 3.000, Auxiliary CPU +Raspberry Pi 3 = On , Off , On , Off , 3.000, 3.000, Auxiliary CPU +Raspberry Pi 4 = On , Off , On , Off , 3.000, 3.000, Auxiliary CPU Ubiquiti Ministation = On , On , Off , Off , 3.000, 3.000, None Ubiquiti PicoStation M2HP = On , On , Off , Off , 4.000, 4.000, None Asus GX1005B = On , On , Off , Off , 2.250, 2.250, None @@ -72,3 +74,4 @@ Imagenex 837 = Off , Off , On , Off , 5.00 BlueView MB2250 = Off , Off , On , Off , 32.000, 34.000, Multibeam DOAM = Off , Off , On , Off , 18.500, 0.000, Camera Module Lumenera = Off , Off , On , Off , 50.000, 0.000, Camera Module +IXBLUE Phins C3 = On , On , Off , Off , 10.500, 10.500, None diff --git a/etc/hardware/radio.ini b/etc/hardware/radio.ini new file mode 100644 index 0000000000..17b8079b2b --- /dev/null +++ b/etc/hardware/radio.ini @@ -0,0 +1,75 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Teixeira # +############################################################################ + +[Radio Addresses] +# max 256 systems +broadcast = 0 +x8-02 = 1 +x8-06 = 2 +x8-07 = 3 +x8-08 = 4 +x2o-01 = 5 +x2o-02 = 6 +vtol-01 = 7 +vtol-02 = 8 +vtol-03 = 9 +manta-1 = 10 +manta-11 = 11 +manta-12 = 12 +manta-2 = 13 +manta-21 = 14 +manta-3 = 15 +titan = 16 + +[Transports.Radio] +Enabled = Always +Active = false +Entity Label = Radio +Execution Priority = 50 +Debug Level = Spew +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 57600 +Mode of communication = Server +Address Section = Radio Addresses +Radio rssi report = false +Radio TDM report = false +Enable telemetry report = false +Radio Error correction = false +Mavlink framing = true +Air speed = 64 +Duty cycle = 100 +Number of channels = 10 +Vehicle to bind = vtol-03 +Radio power level = 30 +Enable UAV high speed report = false +UAV high speed Reports Periodicity = 1 + +[Transports.Radio] +#Radio Model = 3DR +Radio Model = RDFXXXxPtP diff --git a/etc/hardware/wifi-rssi.ini b/etc/hardware/wifi-rssi.ini index 4c7c98da80..ed4e2dfc0e 100644 --- a/etc/hardware/wifi-rssi.ini +++ b/etc/hardware/wifi-rssi.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/lauv-arpao.ini b/etc/lauv-arpao.ini index dd9ce15967..4977730bfb 100644 --- a/etc/lauv-arpao.ini +++ b/etc/lauv-arpao.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,6 +31,7 @@ [Require auv/basic.ini] [Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] [Require hardware/lctr-a6xx/gsm-lc2m.ini] [Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] @@ -73,9 +74,9 @@ MPS Integral Limit = 1500.0 MPS PID Gains = 0.0, 0.5, 0.0 [Monitors.Entities] -Default Monitoring -- Hardware = Clock, +Default Monitoring -- Hardware = BATMAN, + Clock, Collisions, - Fuel, Leak Sensor, Motor Controller, Servo Controller @@ -88,18 +89,26 @@ Debug Level = Spew #[Navigation.AUV.Navigation] todo +[Power.BATMANv2] +Serial Port - Device = /dev/uart/11 +Scale Factor A/Ah = 1.0 +Warning Level = 20 +Error Level = 15 + [Power.PCTLv2] Leak 0 - Entity Label = Medium Sensor Leak 0 - Medium Sensor = true Leak 1 - Entity Label = Leak Sensor +Minimum Operating Voltage = 18 +Wakeup Operating Voltage = 22 Power Channel 2 - Name = SADC -Power Channel 2 - State = 1 +Power Channel 2 - State = 0 Power Channel 10 - State = 0 Power Channel 5 - Name = N/C (Sidescan) Power Channel 5 - State = 0 Power Channel 7 - Name = N/C (Echo Sounder) Power Channel 7 - State = 0 -Power Channel 11 - Name = Private (Auxiliary CPU) +Power Channel 11 - Name = Auxiliary CPU Power Channel 11 - State = 1 Power Channel 13 - Name = N/C (AHRS) Power Channel 13 - State = 0 @@ -108,7 +117,7 @@ Power Channel 17 - State = 0 [Sensors.LIMU] Hard-Iron Calibration = 0.0146, -0.0515, 0.0 -Serial Port - Device = /dev/uart/1 +IO Port - Device = uart:///dev/uart/1 [Simulators.LBL] Wait for Ping Request = true @@ -137,20 +146,21 @@ Slave System Names = lauv-arpao-aux Slave System Name = lauv-arpao-aux Dispatch Power Operation = false -[Transports.TCP.Server/PlanSequence] +[Transports.TCP.Server/BackSeat] Enabled = Always -Entity Label = TCP Server Aux -Announce Service = false Port = 6003 -Transports = Abort, - PlanControlState, - VehicleState +[Transports.UDP] +Filtered Entities = CpuUsage:Daemon, + Distance:Altimeter+DVL Filtered+Echo Sounder, + Temperature:CTD+Depth Sensor+BATMAN, + Voltage:Batteries+Rhodamine+Turbidity+Chlorophyll+CELL 1+CELL 2+CELL 3+CELL 4+CELL 5+CELL 6+CELL 7+BATMAN, + Current:BATMAN+FCap+RCap [UserInterfaces.LEDs] Critical Entities = Leak Sensor [Sensors.CyclopsC7] -Enabled = Hardware +Enabled = Never Active = true CH 1 - Is Active = true CH 1 - Voltage Entity Label = Rhodamine @@ -158,7 +168,7 @@ CH 1 - Name of message to produce = RhodamineDye [Sensors.SADC] -Enabled = Hardware +Enabled = Never Serial Port - Device = /dev/uart/8 Sample Rate = 5 ADC 1 - Is Active = true diff --git a/etc/lauv-nemo-1.ini b/etc/lauv-nemo-1.ini new file mode 100644 index 0000000000..540c7ce658 --- /dev/null +++ b/etc/lauv-nemo-1.ini @@ -0,0 +1,226 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Teixeira # +############################################################################ +# LAUV Nemo configuration file # +############################################################################ + +[Require auv/basic.ini] +[Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/gps-lc2m.ini] +[Require hardware/lctr-a6xx/gsm-lc2m.ini] +[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] +[Require hardware/lctr-a6xx/scrtv4.ini] +[Require hardware/lctr-a6xx/evologics.ini] +[Require hardware/lctr-a6xx/limu.ini] +[Require hardware/lctr-a6xx/slavecpu.ini] +[Require hardware/lctr-a6xx/cyclopsc7.ini] +[Require hardware/lctr-a6xx/sadc.ini] +[Require hardware/lctr-a6xx/seatrac.ini] + +############################################################################ +# Vehicle specific overrides # +############################################################################ +[General] +Vehicle = lauv-nemo-1 +Absolute Maximum Depth = 50 +Absolute Minimum Altitude = 1.2 +Battery Packs = 3 +Battery Capacity = 525 +Power Model -- Conversion - Watt = 0, 14, 23.5, 50 +Power Model -- Conversion - RPM = 0, 500, 850, 1300 +Speed Conversion -- Actuation = 0, 36, 46 +Speed Conversion -- RPM = 0, 900, 1150 +Speed Conversion -- MPS = 0, 1, 1.3 +Maximum Absolute Speed = 1.6 + +[Control.AUV.Attitude] +Roll PID Gains = 0.7, 0.2, 0.3 +Roll Integral Limit = 5.0 +Pitch PID Gains = 2.0, 0.0, 0.3 +Depth PID Gains = 0.6, 0.01, 0.5 +Depth Integral Limit = 1.0 +Heading Rate PID Gains = 1.5, 0.0, 0.0 +Roll Compensation -- Use Speed = true +Roll Compensation -- Speed Bounds = 0.8, 1.8 +Roll Compensation -- Speed Gain = 0.5 +Pitch Angle At Surface = 15.0 + +[Control.AUV.Speed] +MPS Feedforward Gain = 750.0 +MPS Integral Limit = 1500.0 +MPS PID Gains = 0.0, 0.5, 0.0 + +[Monitors.Entities] +Default Monitoring -- Hardware = BATMAN, + Clock, + Collisions, + Leak Sensor, + Motor Controller, + Servo Controller + +[Navigation.AUV.Ranger] +Enabled = Always +Entity Label = Ranger +Ping Periodicity = 5 +Debug Level = Spew + +[Navigation.AUV.Navigation] +Depth sensor localization in x axis = 0.4 + +[Power.BATMANv2] +Serial Port - Device = /dev/uart/11 +Scale Factor A/Ah = 1.0 +Warning Level = 20 +Error Level = 15 + +[Power.PCTLv2] +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor +Minimum Operating Voltage = 18 +Wakeup Operating Voltage = 22 +Power Channel 2 - Name = SADC +Power Channel 2 - State = 0 +Power Channel 5 - Name = N/C (Sidescan) +Power Channel 5 - State = 0 +Power Channel 7 - Name = Seatrac +Power Channel 7 - State = 1 +Power Channel 10 - State = 0 +Power Channel 11 - Name = Auxiliary CPU +Power Channel 11 - State = 1 +Power Channel 13 - Name = N/C (AHRS) +Power Channel 13 - State = 0 +Power Channel 17 - Name = N/C (DVL) +Power Channel 17 - State = 0 + +[Sensors.LIMU] +Hard-Iron Calibration = -0.0848, 0.0336, 0.0 +IO Port - Device = uart:///dev/uart/8 + +[Sensors.GPS] +Sentence Order = GNVTG, GNZDA, GPVTG, GPZDA, + GLVTG, GLZDA, GAVTG, GAZDA, + GBVTG, GBZDA, PUBX + +[Simulators.LBL] +Wait for Ping Request = true + +[Transports.CommManager] +Enabled = Always +#Acoustic Address Section = Evologics Addresses +Acoustic Address Section = Seatrac Addresses +Debug Level = Debug + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +#Address Section = Evologics Addresses +Address Section = Seatrac Addresses + +[Transports.Evologics] +Enabled = Never +IPv4 Address = 10.0.10.65 + +[Transports.SerialOverTCP/Evologics] +Enabled = Never +Serial Port - Device = /dev/ttyUSB1 +Debug Level = Debug + +[Transports.Seatrac] +Enabled = Hardware +#Serial Port - Device = tcp://10.0.30.21:1001 +#Use Internal Pressure Sensor for Medium = false +#Transmit Only Underwater = false +Debug Level = Debug + +[Maneuver.RowsCoverage] +Enabled = Always + +[Monitors.Clock] +Enabled = Hardware + +[Supervisors.ClockPPS] +Enabled = Never + +[Supervisors.SlaveCPU] +Slave System Name = lauv-nemo-1-aux +Dispatch Power Operation = false + +[Transports.TCP.Server/BackSeat] +Enabled = Always +Port = 6003 + +[Transports.UDP] +Filtered Entities = CpuUsage:Daemon, + Distance:Altimeter+DVL Filtered+Echo Sounder, + Temperature:CTD+Depth Sensor+BATMAN, + Voltage:Batteries+Rhodamine+Turbidity+Chlorophyll+CELL 1+CELL 2+CELL 3+CELL 4+CELL 5+CELL 6+CELL 7+BATMAN, + Current:BATMAN+FCap+RCap + +[UserInterfaces.LEDs] +Critical Entities = Leak Sensor + +[Sensors.CyclopsC7] +Enabled = Never +Active = true +CH 1 - Is Active = true +CH 1 - Voltage Entity Label = Rhodamine +CH 1 - Name of message to produce = RhodamineDye +CH 2 - Is Active = true +CH 2 - Voltage Entity Label = Turbidity +CH 2 - Name of message to produce = Turbidity + +[Sensors.SADC] +Enabled = Never +Serial Port - Device = /dev/uart/8 +Sample Rate = 5 +ADC 1 - Is Active = true +ADC 1 - Entity Label = Rhodamine +ADC 2 - Is Active = true +ADC 2 - Entity Label = Turbidity + +[Transports.DataStore] +Enabled = Always +Entity Label = DataStore Transport +Acoustic Gateway = manta-2 +Acoustic Forward Period = 30 +Acoustic MTU = 120 +Messages = HistoricTelemetry:10, + HistoricEvent:20 + +[Sensors.DataStore] +Enabled = Always +Entity Label = DataStore Source +Log Events = false +#Telemetry Sample Period = 60 + +## CDC3 Exercise ## +#[Require development/cdc3/cdc3-lauv-nemo-1.ini] + diff --git a/etc/lauv-noptilus-1.ini b/etc/lauv-noptilus-1.ini index 6cc50e3f69..ec08a7167b 100644 --- a/etc/lauv-noptilus-1.ini +++ b/etc/lauv-noptilus-1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,18 +31,16 @@ [Require auv/basic.ini] [Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] [Require hardware/lctr-a6xx/evologics.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] [Require hardware/lctr-a6xx/gsm-lc2m.ini] -[Require hardware/lctr-a6xx/hg1700.ini] [Require hardware/lctr-a6xx/imagenex852.ini] [Require hardware/lctr-a6xx/imagenex872.ini] [Require hardware/lctr-a6xx/imagenex837b.ini] [Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] [Require hardware/lctr-a6xx/limu.ini] -[Require hardware/lctr-a6xx/minisvs.ini] [Require hardware/lctr-a6xx/navquestdvl.ini] -[Require hardware/lctr-a6xx/psimar.ini] [Require hardware/lctr-a6xx/scrtv4.ini] ############################################################################ @@ -79,28 +77,41 @@ Hardware List = LSTS PCTLv2, Imagenex 837 [Control.AUV.Attitude] -Roll PID Gains = 1.0, 0.0, 0.2 -Depth PID Gains = 0.4, 0.04, 0.6 -Depth Integral Limit = 5.0 +Roll PID Gains = 1.0, 0.02, 0.2 +Roll Integral Limit = 1.0 +Roll Compensation -- Use Speed = false +Depth PID Gains = 0.5, 0.06, 0.7 +Depth Integral Limit = 10.0 Heading Rate PID Gains = 1.2, 0.0, 0.0 +Heading PID Gains = 1.5, 0.0, 0.15 +Pitch Angle At Surface = 5.0 +Pitch PID Gains = 1.5, 0.09, 0.5 +Pitch Integral Limit = 1.0 +Altitude Control -- Enabled = true +Altitude Integral Limit = 6.0 +Altitude PID Gains = 2.0, 0.01, 4.0 [Control.Path.VectorField] Bottom Track -- Enabled = true [Monitors.Entities] -Default Monitoring -- Hardware = Clock, +Default Monitoring -- Hardware = BATMAN, + Clock, Collisions, DVL, - Fuel, - IMU, - Leak Sensor - Antenna, - Leak Sensor - Bottom, + Leak Sensor, + Logger, Motor Controller, Servo Controller, Sidescan [Monitors.FuelLevel] -Capacity Decay Factor = 10.0 +Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 + +[Monitors.Emergency] +Transmission Interface = GSM [Navigation.AUV.Ranger] Enabled = Always @@ -113,25 +124,60 @@ Distance Between DVL and CG = 0.36 Distance Between LBL and GPS = 1.09 Reject all LBL ranges = false +[Power.BATMANv2] +Serial Port - Device = /dev/ttyS10 +Scale Factor A/Ah = 1.2 +Warning Level = 20 +Error Level = 15 + [Power.PCTLv2] +Serial Port - Device = /dev/ttyS11 ADC Reference Voltage = 1.083 +Power Channel 10 - Name = Switch Ethernet +Power Channel 10 - State = 1 Power Channel 11 - Name = Private (Auxiliary CPU) Power Channel 11 - State = 0 -Power Channel 13 - Name = N/C (+5V_6) -Power Channel 13 - State = 0 +Power Channel 13 - Name = BATMAN +Power Channel 13 - State = 1 Power Channel 16 - Name = Private (IMU) Power Channel 16 - State = 0 +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor + +[Actuators.Broom] +Serial Port - Device = /dev/ttyS5 + +[Actuators.SCRTv4] +Serial Port - Device = /dev/ttyS4 + +[Sensors.Keller] +IO Port - Device = uart:///dev/ttyS2:9600 + +[Sensors.Imagenex852] +Enabled = Never +# Serial Port - Device = /dev/ttyS8 + +[Sensors.Imagenex837B] +X-Axis Distance to GPS = 1.0 +IO Port - Device = tcp://192.168.0.31:4040 +Power Channel = [Sensors.Imagenex872] -IPv4 Address = 192.168.0.51 +IO Port - Device = tcp://192.168.0.51:4040 [Sensors.LIMU] +IO Port - Device = uart:///dev/ttyS7 +Power Channel - Name = Hard-Iron Calibration = -0.0050, -0.0640, 0.0000 -Serial Port - Device = /dev/uart/8 [Sensors.NavQuestDVL] +Serial Port - Device = /dev/ttyS9 Device Position = 1.09, 0, 0.12 +[Sensors.SCH311X] +Enabled = Never + [Simulators.LBL] Wait for Ping Request = true @@ -139,7 +185,7 @@ Wait for Ping Request = true IPv4 Address = 10.0.10.85 [Transports.UAN] -Enabled = Hardware +Enabled = Always Entity Label = Acoustic Access Controller Enable Reports = true @@ -151,3 +197,7 @@ Enabled = Hardware [Supervisors.ClockPPS] Enabled = Never + +[Simulators.Gaussian/SoundSpeed] +Value at peak = 1522 +Value away from peak = 1500 diff --git a/etc/lauv-noptilus-2-cpu-cam.ini b/etc/lauv-noptilus-2-cpu-cam.ini new file mode 100644 index 0000000000..88745ba127 --- /dev/null +++ b/etc/lauv-noptilus-2-cpu-cam.ini @@ -0,0 +1,134 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ +# LAUV Noptilus 2 Camera CPU configuration file # +############################################################################ + +[Include common/imc-addresses.ini] +[Include hardware/lctr-rpi/thermalzone.ini] + +[General] +Vehicle = lauv-noptilus-2-cpu-cam + +[Vision.PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +System Name = lauv-noptilus-2 +#Led modes: Strobe, On, Off +Led Mode = Strobe +Power Channel - Strobe = Camera - Strobe +Copyright = LSTS-FEUP +Lens Model = 1/2 4mm F1.2-F11 - 4mm UC +Lens Make = www.edmundoptics.eu +Saved Images Dir = Photos +Number Frames/s = 3 +Split Photos = true +Number of photos to divide = 1000 +GPIO Driver Power = 17 +GPIO Strobe = 27 +Strobe Delay (us) = 10000 +Shutter Value (ms) = 8 +Activation Time = 60 +Deactivation Time = 5 + +[General] +CPU Usage - Maximum = 85 + +[Sensors.ThermalZone] +Entity Label = Mainboard Camera CPU +Entity Label - Temperature = Mainboard (Camera CPU) + +[Supervisors.Power] +Enabled = Hardware +Entity Label = Power Supervisor +Main Power Channel = System +Command - On Power Down = services syslog stop && + mount -o remount,ro /opt +Command - On Power Down Abort = mount -o remount,rw /opt && + services syslog restart + +[Transports.TCP.Client] +Enabled = Hardware +Entity Label = TCP to Master +Server - Address = 10.0.10.90 +Server - Port = 9999 +Trace - Incoming Messages = false +Trace - Outgoing Messages = false +Transports = EntityState, + EntityActivationState, + EntityInfo, + EntityParameters, + Heartbeat, + LogBookEntry, + LoggingControl, + Temperature + +[Transports.HTTP] +Enabled = Always +Entity Label = HTTP Server +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Port = 8080 +Threads = 5 +Transports = CpuUsage, + Current, + EntityState, + GpsFix, + Heartbeat, + Temperature, + Voltage, + EntityList + +[Transports.Logging] +Enabled = Always +Entity Label = Logger +Debug Level = None +Activation Time = 0 +Deactivation Time = 0 +Execution Priority = 2 +Flush Interval = 5 +LSF Compression Method = gzip +LSF Volume Size = 0 +Transports = CpuUsage, + EntityActivationState, + EntityList, + EntityMonitoringState, + EntityParameters, + EntityState, + EstimatedState, + GpsFix, + Heartbeat, + LogBookEntry, + PowerChannelControl, + PowerChannelState, + QueryEntityParameters, + SaveEntityParameters, + Temperature diff --git a/etc/lauv-noptilus-2.ini b/etc/lauv-noptilus-2.ini index 7d7d188642..a9cb2428e3 100644 --- a/etc/lauv-noptilus-2.ini +++ b/etc/lauv-noptilus-2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,6 +31,7 @@ [Require auv/basic.ini] [Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] [Require hardware/lctr-a6xx/edgetech-2205.ini] [Require hardware/lctr-a6xx/evologics.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] @@ -78,13 +79,18 @@ Hardware List = LSTS PCTLv2, [Control.AUV.Attitude] -Roll PID Gains = 1.0, 0.0, 0.2 -Depth PID Gains = 0.4, 0.05, 0.6 -Depth Integral Limit = 5.0 +Roll PID Gains = 1.0, 0.05, 0.2 +Roll Integral Limit = 2.0 +Depth PID Gains = 0.7, 0.2, 0.8 +Depth Integral Limit = 4.0 Heading Rate PID Gains = 1.5, 0.0, 0.0 +Heading PID Gains = 1.2, 0.0, 0.15 +Pitch Angle At Surface = 3.0 +Pitch PID Gains = 1.7, 0.2, 0.5 +Pitch Integral Limit = 5.0 Roll Compensation -- Use Offset = false Roll Compensation -- Offset Angle = -5.0 -Roll Compensation -- Use Speed = true +Roll Compensation -- Use Speed = false Roll Compensation -- Speed Bounds = 0.8, 1.7 Roll Compensation -- Speed Gain = 0.5 @@ -92,19 +98,23 @@ Roll Compensation -- Speed Gain = 0.5 Bottom Track -- Enabled = true [Monitors.Entities] -Default Monitoring -- Hardware = Clock, +Default Monitoring -- Hardware = BATMAN, + Clock, Collisions, DVL, - Fuel, IMU, - Leak Sensor - Antenna, - Leak Sensor - Bottom, + Leak Sensor, Motor Controller, Servo Controller, Sidescan [Monitors.FuelLevel] Capacity Decay Factor = 10.0 +Voltage Error Level = 24.5 +Voltage Threshold Error Level = 0.5 + +[Monitors.Emergency] +Transmission Interface = GSM [Navigation.AUV.Ranger] Enabled = Always @@ -118,23 +128,31 @@ Distance Between LBL and GPS = 1.09 [Power.PCTLv2] ADC Reference Voltage = 1.083 +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor Power Channel 2 - Name = Sound Velocity Sensor Power Channel 2 - State = 1 Power Channel 4 - Name = Evologics Power Channel 4 - State = 1 Power Channel 5 - Name = Private (Sidescan) Power Channel 5 - State = 0 +Power Channel 6 - Name = Private (Camera CPU) +Power Channel 6 - State = 0 Power Channel 11 - Name = Private (Auxiliary CPU) -Power Channel 11 - State = 0 -Power Channel 13 - Name = N/C (+5V_6) -Power Channel 13 - State = 0 +Power Channel 11 - State = 1 +Power Channel 13 - Name = BATMAN +Power Channel 13 - State = 1 [Sensors.Edgetech2205] IPv4 Address = 10.0.10.94 +[Sensors.GPS] +Sentence Order = GNVTG, GNZDA, GPVTG, GPZDA, GLVTG, GLZDA, PUBX + [Sensors.LIMU] Hard-Iron Calibration = 0.0585, 0.0246, 0.0 -Serial Port - Device = /dev/uart/8 +IO Port - Device = uart:///dev/uart/8 [Sensors.NavQuestDVL] Device Position = 1.09, 0, 0.12 @@ -142,16 +160,69 @@ Device Position = 1.09, 0, 0.12 [Simulators.LBL] Wait for Ping Request = true +[Power.BATMANv2] +Serial Port - Device = /dev/uart/11 +Scale Factor A/Ah = 2.0 +Warning Level = 20 +Error Level = 15 + [Transports.Evologics] IPv4 Address = 10.0.10.95 [Transports.UAN] -Enabled = Hardware +Enabled = Always Entity Label = Acoustic Access Controller Enable Reports = true +[Transports.FTP] +Enabled = Simulation + +[Transports.Announce] +Enabled = Simulation + +[Transports.Announce/Hardware] +Enabled = Hardware +Additional Services - External = ftp://10.0.10.93:30021/ +Entity Label = Service Announcer +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Debug Level = None +Execution Priority = 10 +Announcement Periodicity = 10 +Enable Loopback = 1 +Enable Multicast = 1 +Enable Broadcast = 1 +Multicast Address = 224.0.75.69 +Ports = 30100, 30101, 30102, 30103, 30104 +Ignored Interfaces = eth0:prv + +# Slave CPU +[Require hardware/lctr-a6xx/slavecpu.ini] +[Supervisors.SlaveCPU] +Slave System Name = lauv-noptilus-2-cpu-cam +Power Channel = Private (Camera CPU) +Dispatch Power Operation = true + [Monitors.Clock] Enabled = Hardware [Supervisors.ClockPPS] Enabled = Never + +# Camera delegator. +[Supervisors.Delegator/PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +Surrogate Task = Vision.PointGrey +Surrogate Section = Vision.PointGrey +Surrogate System = lauv-noptilus-2-cpu-cam +Surrogate Entity = Camera +Surrogate Power Channel = Private (Camera CPU) +Activation Time = 60 +Deactivation Time = 5 +Active = false +Active - Scope = maneuver +Active - Visibility = user +Execution Priority = 10 diff --git a/etc/lauv-noptilus-3-aux.ini b/etc/lauv-noptilus-3-cpu-cam.ini similarity index 92% rename from etc/lauv-noptilus-3-aux.ini rename to etc/lauv-noptilus-3-cpu-cam.ini index 9cff9ae1de..54724abf32 100644 --- a/etc/lauv-noptilus-3-aux.ini +++ b/etc/lauv-noptilus-3-cpu-cam.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,10 +30,10 @@ [Require lauv-seacon-1-aux.ini] [General] -Vehicle = lauv-noptilus-3-aux +Vehicle = lauv-noptilus-3-cpu-cam [Vision.Lumenera] -Camera IPv4 Address = 10.0.10.102 +Camera IPv4 Address = 10.0.10.106 [Transports.TCP.Client] Server - Address = 10.0.10.100 diff --git a/etc/lauv-noptilus-3.ini b/etc/lauv-noptilus-3.ini index 896908f6b5..2ba1a1320a 100644 --- a/etc/lauv-noptilus-3.ini +++ b/etc/lauv-noptilus-3.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,21 +31,21 @@ [Require auv/basic.ini] [Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] [Require hardware/lctr-a6xx/scrtv4.ini] +[Require hardware/lctr-a6xx/broom-36v.ini] [Require hardware/lctr-a6xx/evologics.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] [Require hardware/lctr-a6xx/gsm-lc2m.ini] [Require hardware/lctr-a6xx/hg1700.ini] -[Require hardware/lctr-a6xx/imagenex837b.ini] [Require hardware/lctr-a6xx/imagenex852.ini] -#[Require hardware/lctr-a6xx/imagenex872.ini] +[Require hardware/lctr-a6xx/imagenex872.ini] [Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] -[Require hardware/lctr-a6xx/limu.ini] [Require hardware/lctr-a6xx/lumenera.ini] [Require hardware/lctr-a6xx/navquestdvl.ini] [Require hardware/lctr-a6xx/psimar.ini] [Require hardware/lctr-a6xx/slavecpu.ini] -[Require hardware/lctr-a6xx/xchangesv.ini] +[Require hardware/lctr-a6xx/microstrain3dmgx3.ini] ############################################################################ # Vehicle specific overrides # @@ -76,38 +76,50 @@ Hardware List = LSTS PCTLv2, LSTS SCRTv4 + BMS-705MG, LinkQuest NavQuest 600 Micro, Honeywell HG1700, - Imagenex 837, Imagenex 852, Imagenex 872, AML SV Xchange, Lumenera [Control.AUV.Attitude] -Roll PID Gains = 0.7, 0.0, 0.2 -Depth PID Gains = 0.4, 0.05, 0.6 +Roll PID Gains = 1.0, 0.02, 0.2 +Roll Integral Limit = 1.0 +Depth PID Gains = 0.4, 0.05, 0.7 Depth Integral Limit = 10.0 Heading Rate PID Gains = 1.2, 0.0, 0.0 +Heading PID Gains = 1.0, 0.0, 0.0 +Pitch Angle At Surface = 5.0 +Pitch PID Gains = 1.55, 0.05, 0.6 +Pitch Integral Limit = 1.0 Roll Compensation -- Use Speed = true Roll Compensation -- Speed Bounds = 1.0, 1.8 Roll Compensation -- Speed Gain = 0.5 +Altitude Control -- Enabled = true +Altitude Integral Limit = 6.0 +Altitude PID Gains = 2.5, 0.005, 4.5 [Control.Path.VectorField] Bottom Track -- Enabled = true [Monitors.Entities] -Default Monitoring -- Hardware = Clock, +Default Monitoring -- Hardware = BATMAN, + Clock, Collisions, DVL, - Fuel, IMU, Leak Sensor - Antenna, Leak Sensor - Bottom, + Logger, Motor Controller, Servo Controller -# Sidescan [Monitors.FuelLevel] -Capacity Decay Factor = 10.0 +Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 + +[Monitors.Emergency] +Transmission Interface = GSM [Navigation.AUV.Ranger] Enabled = Always @@ -119,50 +131,80 @@ Debug Level = Spew Distance Between DVL and CG = 0.51 Distance Between LBL and GPS = 0.86 +[Power.BATMANv2] +Serial Port - Device = /dev/ttyS10 +Scale Factor A/Ah = 1.2 +Warning Level = 20 +Error Level = 15 + [Power.PCTLv2] +Serial Port - Device = /dev/ttyS11 ADC Reference Voltage = 1.083 Power Channel 2 - Name = Sound Velocity Sensor Power Channel 2 - State = 1 +Power Channel 3 - Name = N/C (+12V_5) +Power Channel 3 - State = 0 Power Channel 6 - Name = Private (Camera - CPU) Power Channel 6 - State = 0 -Power Channel 13 - Name = N/C (+5V_6) -Power Channel 13 - State = 0 - +Power Channel 10 - Name = AHRS +Power Channel 10 - State = 1 +Power Channel 11 - Name = CPU - AUX +Power Channel 11 - State = 0 +Power Channel 13 - Name = BATMAN +Power Channel 13 - State = 1 + +[Sensors.SCH311X] +Enabled = Never [Sensors.Imagenex837B] X-Axis Distance to GPS = 0.93 -IPv4 Address = 192.168.0.30 +IO Port - Device = tcp://192.168.0.30:4040 -[Sensors.Imagenex872] -IPv4 Address = 192.168.0.50 +[Sensors.Imagenex852] +Serial Port - Device = /dev/ttyS8 -[Sensors.LIMU] -Hard-Iron Calibration = 0.0480, 0.0186, 0.0 -Serial Port - Device = /dev/uart/8 +[Sensors.Imagenex872] +IO Port - Device = tcp://192.168.0.50:4040 [Sensors.NavQuestDVL] +Serial Port - Device = /dev/ttyS9 Device Position = 0.86, 0, 0.12 +[Sensors.Keller] +Serial Port - Device = /dev/ttyS2 + +[Actuators.SCRTv4] +Serial Port - Device = /dev/ttyS4 + +[Actuators.Broom] +Serial Port - Device = /dev/ttyS5 + [Simulators.LBL] Wait for Ping Request = true [Supervisors.SlaveCPU] -Slave System Name = lauv-noptilus-3-aux +Slave System Name = lauv-noptilus-3-cpu-cam [Supervisors.Power] -Slave System Names = lauv-noptilus-3-aux +Slave System Names = lauv-noptilus-3-cpu-cam [Transports.Evologics] IPv4 Address = 10.0.10.105 [Transports.UAN] -Enabled = Hardware +Enabled = Always Entity Label = Acoustic Access Controller Enable Reports = true +[Transports.TCP.Server/BackSeat] +Enabled = Never + +[Transports.TCP.Server/SlaveCPU] +Enabled = Always + [Vision.Lumenera] -Camera IPv4 Address = 10.0.10.102 +Camera IPv4 Address = 10.0.10.106 Slave Entities = Slave CPU, - lauv-noptilus-3-aux:Camera Backend + lauv-noptilus-3-cpu-cam:Camera Backend [Maneuver.RowsCoverage] Enabled = Always @@ -172,3 +214,6 @@ Enabled = Hardware [Supervisors.ClockPPS] Enabled = Never + +[Sensors.Microstrain3DMGX3] +Serial Port - Device = /dev/ttyS7 diff --git a/etc/lauv-seacon-1-aux.ini b/etc/lauv-seacon-1-aux.ini index 44cdab3224..ccdbb12785 100644 --- a/etc/lauv-seacon-1-aux.ini +++ b/etc/lauv-seacon-1-aux.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/lauv-seacon-1.ini b/etc/lauv-seacon-1.ini index f7a6fd1500..30b6387819 100644 --- a/etc/lauv-seacon-1.ini +++ b/etc/lauv-seacon-1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -80,7 +80,7 @@ Hardware List = LSTS PCTLv2, Lumenera [Control.AUV.Attitude] -Roll PID Gains = 1.0, 0.0, 0.2 +Roll PID Gains = 0.4, 0.0, 0.03 Depth PID Gains = 0.3, 0.05, 0.6 Depth Integral Limit = 5.0 Heading Rate PID Gains = 1.5, 0.0, 0.0 @@ -110,6 +110,7 @@ SMS Recipient Number = +351910012611 Default Monitoring -- Hardware = Clock, Collisions, DVL, + Echo Sounder, Fuel, IMU, Leak Sensor - Antenna, @@ -121,13 +122,19 @@ Default Monitoring -- Hardware = Clock, [Monitors.FuelLevel] Capacity Decay Factor = 10.0 +[Monitors.Emergency] +Transmission Interface = GSM + +[Maneuver.Multiplexer] +PopUp -- Minimum Satellites = 6 + [Navigation.AUV.Navigation] Distance Between DVL and CG = 0.47 Distance Between LBL and GPS = 0.91 Distance Between GPS and CG = 0.25 [Sensors.Imagenex872] -IPv4 Address = 192.168.0.53 +IO Port - Device = tcp://192.168.0.53:4040 [Sensors.Microstrain3DMGX3] Hard-Iron Calibration = -0.083292, -0.168589, 0.0 @@ -145,8 +152,8 @@ Simulate - Forward Distance = false ADC Reference Voltage = 1.08 Power Channel 3 - Name = N/C (+12V_5) Power Channel 3 - State = 0 -Power Channel 7 - Name = Private (Camera - CPU) -Power Channel 7 - State = 0 +Power Channel 7 - Name = CPU_bb +Power Channel 7 - State = 1 [Supervisors.SlaveCPU] Slave System Name = lauv-seacon-1-aux @@ -156,11 +163,45 @@ Slave System Names = lauv-seacon-1-aux [Vision.Lumenera] Camera IPv4 Address = 10.0.10.12 -Slave Entities = Slave CPU, - lauv-seacon-1-aux:Camera Backend +Slave Entities = lauv-seacon-1-aux:Camera Backend [Supervisors.ClockPPS] Enabled = Never [Monitors.Clock] Enabled = Hardware + +[Transports.TCP.Server/BackSeat] +Enabled = Always +Entity Label = Back Seat TCP Server +Announce Service = false +Debug Level = None +Activation Time = 0 +Deactivation Time = 0 +Execution Priority = 10 +Port = 6003 +Trace - Incoming Messages = false +Trace - Outgoing Messages = false +Transports = Abort, + AcousticLink, + Announce, + AlignmentState, + EntityParameters, + EstimatedState, + FuelLevel, + PathControlState, + PlanControl, + PlanControlState, + PlanDB, + FollowRefState, + GpsFix, + ReportControl, + Salinity, + Temperature, + UamRxFrame, + UamTxStatus, + VehicleMedium, + VehicleState + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] diff --git a/etc/lauv-seacon-2-aux.ini b/etc/lauv-seacon-2-aux.ini new file mode 100644 index 0000000000..1f4c3a1c5b --- /dev/null +++ b/etc/lauv-seacon-2-aux.ini @@ -0,0 +1,74 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# LAUV Seacon 2 auxiliary CPU configuration file # +############################################################################ + +[Include common/imc-addresses.ini] +[Require hardware/lctr-rpi/thermalzone.ini] +[Require ../private/etc/sensors/deepvision.ini] + +[General] +Vehicle = lauv-seacon-2-aux + +[Sensors.ThermalZone] +Entity Label = Mainboard Aux +Entity Label - Temperature = Mainboard (Auxiliary CPU) + +[Supervisors.Power] +Enabled = Hardware +Entity Label = Power Supervisor +Main Power Channel = System +Command - On Power Down = services syslog stop && + mount -o remount,ro /opt +Command - On Power Down Abort = mount -o remount,rw /opt && + services syslog restart + +[Transports.TCP.Client] +Enabled = Always +Entity Label = TCP to Master +Server - Address = 10.0.10.20 +Server - Port = 9999 +Transports = DevDataText, + EntityState, + EntityActivationState, + EntityInfo, + EntityParameters, + Heartbeat, + LogBookEntry, + LoggingControl, + PowerChannelControl, + PowerChannelState, + PulseDetectionControl, + SonarData, + Temperature + +[Sensors.DeepVisionOSM2] +Output Data Format = IMC +Log Prefix = ../lauv-seacon-2 +Trigger Delay = 20 \ No newline at end of file diff --git a/etc/lauv-seacon-2-cpu-cam.ini b/etc/lauv-seacon-2-cpu-cam.ini new file mode 100644 index 0000000000..0b2dcb8f47 --- /dev/null +++ b/etc/lauv-seacon-2-cpu-cam.ini @@ -0,0 +1,135 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +# Author: Maria Costa # +############################################################################ +# LAUV Seacon 2 Camera CPU configuration file # +############################################################################ + +[Include common/imc-addresses.ini] +[Require hardware/lctr-rpi/thermalzone.ini] + +[General] +Vehicle = lauv-seacon-2-cpu-cam + +[Vision.PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +System Name = lauv-seacon-2 +#Led modes: Strobe, On, Off +Led Mode = Strobe +Power Channel - Strobe = Camera - Strobe +Copyright = LSTS-FEUP +Lens Model = 1/2 4mm F1.2-F11 - 4mm UC +Lens Make = www.edmundoptics.eu +Saved Images Dir = Photos +Number Frames/s = 3 +Split Photos = true +Number of photos to divide = 1000 +GPIO Driver Power = 17 +GPIO Strobe = 27 +Strobe Delay (us) = 100000 +Shutter Value (ms) = 8 +Activation Time = 60 +Deactivation Time = 5 + +[General] +CPU Usage - Maximum = 85 + +[Sensors.ThermalZone] +Entity Label = Mainboard Camera CPU +Entity Label - Temperature = Mainboard (Camera CPU) + +[Supervisors.Power] +Enabled = Hardware +Entity Label = Power Supervisor +Main Power Channel = System +Command - On Power Down = services syslog stop && + mount -o remount,ro /opt +Command - On Power Down Abort = mount -o remount,rw /opt && + services syslog restart + +[Transports.TCP.Client] +Enabled = Hardware +Entity Label = TCP to Master +Server - Address = 10.0.10.20 +Server - Port = 9999 +Trace - Incoming Messages = false +Trace - Outgoing Messages = false +Transports = EntityState, + EntityActivationState, + EntityInfo, + EntityParameters, + Heartbeat, + LogBookEntry, + LoggingControl, + Temperature + +[Transports.HTTP] +Enabled = Always +Entity Label = HTTP Server +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Port = 8080 +Threads = 5 +Transports = CpuUsage, + Current, + EntityState, + GpsFix, + Heartbeat, + Temperature, + Voltage, + EntityList + +[Transports.Logging] +Enabled = Never +Entity Label = Logger +Debug Level = None +Activation Time = 0 +Deactivation Time = 0 +Execution Priority = 2 +Flush Interval = 5 +LSF Compression Method = gzip +LSF Volume Size = 0 +Transports = CpuUsage, + EntityActivationState, + EntityList, + EntityMonitoringState, + EntityParameters, + EntityState, + EstimatedState, + GpsFix, + Heartbeat, + LogBookEntry, + PowerChannelControl, + PowerChannelState, + QueryEntityParameters, + SaveEntityParameters, + Temperature diff --git a/etc/lauv-seacon-2.ini b/etc/lauv-seacon-2.ini index 3c12d2f051..5de5da2ec2 100644 --- a/etc/lauv-seacon-2.ini +++ b/etc/lauv-seacon-2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,16 +31,17 @@ [Require auv/basic.ini] [Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/broom-36v.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] [Require hardware/lctr-a6xx/gsm-lc2m.ini] -[Require hardware/lctr-a6xx/imagenex837b.ini] [Require hardware/lctr-a6xx/imagenex852.ini] -[Require hardware/lctr-a6xx/imagenex872.ini] +[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] [Require hardware/lctr-a6xx/micromodem.ini] [Require hardware/lctr-a6xx/microstrain3dmgx3.ini] -[Require hardware/lctr-a6xx/navquestdvl.ini] +[Require hardware/lctr-a6xx/nortekdvl.ini] [Require hardware/lctr-a6xx/scrtv4.ini] -[Require hardware/lctr-a6xx/xr620ctd.ini] +[Require hardware/lctr-a6xx/xchangesv.ini] ############################################################################ # Vehicle specific overrides # @@ -64,15 +65,13 @@ Hardware List = LSTS PCTLv2, GSM/UMTS/HDSPA, WHOI MicroModem, U-blox EVK-6H, - Keller-33x, Microstrain 3DM-GX3, + Nortek DVL 1MHz (Ethernet), LSTS BROOM + Motor, LSTS SCRTv4 + BMS-705MG, - LinkQuest NavQuest 600 Micro, - RBR XR-620CTD, - Imagenex 837, - Imagenex 852, - Imagenex 872 + Raspberry Pi 4, + AML SV Xchange, + Imagenex 852 [Control.AUV.Attitude] Roll PID Gains = 0.4, 0.0, 0.02 @@ -83,6 +82,9 @@ Depth PID Gains = 0.3, 0.05, 0.6 Depth Integral Limit = 5.0 Heading Rate PID Gains = 1.5, 0.0, 0.0 +[Control.Path.VectorField] +Bottom Track -- Enabled = true + [Control.AUV.RemoteOperation] Disable Analog Thrust = false # Aprox 2000 rpm @@ -113,37 +115,204 @@ Default Monitoring = Attitude, Operational Limits, Path Control Default Monitoring -- Hardware = AHRS, + BATMAN, Clock, Collisions, Fuel, - Leak Sensor - Antenna, - Leak Sensor - Bottom, + Leak Sensor, + Medium Sensor, Motor Controller, Servo Controller, - Sidescan + Navigation [Monitors.FuelLevel] Capacity Decay Factor = 10.0 +[Monitors.Servos] +Position Fault Detection = true + [Navigation.AUV.Navigation] Distance Between DVL and CG = 0.36 Distance Between LBL and GPS = 1.20 Distance Between GPS and CG = 0.25 -[Sensors.Imagenex837B] -X-Axis Distance to GPS = 1.08 -IPv4 Address = 192.168.0.31 +[Power.BATMANv2] +Serial Port - Device = /dev/uart/11 +Scale Factor A/Ah = 2.0 +Warning Level = 20 +Error Level = 15 + +[Power.PCTLv2] +ADC Reference Voltage = 1.101 +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor +Power Channel 1 - Name = N/C (+12V_3) +Power Channel 2 - Name = Sound Velocity Sensor +Power Channel 2 - State = 1 +Power Channel 3 - Name = N/C (+12V_5) +Power Channel 3 - State = 0 +Power Channel 4 - Name = INS +Power Channel 4 - State = 1 +Power Channel 5 - Name = N/C (Bout_2) +Power Channel 5 - State = 0 +Power Channel 6 - Name = Private (Camera CPU) +Power Channel 6 - State = 0 +Power Channel 7 - Name = Echo Sounder and Acoustic Modem +Power Channel 7 - State = 1 +Power Channel 10 - Name = Private (Ethernet Switch) +Power Channel 10 - State = 1 +Power Channel 11 - Name = Private (Auxiliary CPU) +Power Channel 11 - State = 1 +Power Channel 12 - Name = AHRS +Power Channel 12 - State = 1 +Power Channel 13 - Name = BATMAN +Power Channel 13 - State = 1 +Power Channel 15 - Name = Private (Sidescan) +Power Channel 15 - State = 0 +Power Channel 17 - Name = Private (DVL) +Power Channel 17 - State = 1 + +[Sensors.GPS] +IO Port - Device = uart:///dev/ttyACM2:57600 +Sentence Order = GNVTG, GNZDA, PUBX +Initialization String 0 - Command = $PUBX,40,VTG,0,1,0,0,0,0\r\n +Initialization String 1 - Command = $PUBX,40,ZDA,0,1,0,0,0,0\r\n +Initialization String 2 - Command = $PUBX,40,00,0,1,0,0,0,0\r\n +Initialization String 3 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 4 - Command = $PUBX,40,GSA,0,0,0,0,0,0\r\n +Initialization String 5 - Command = $PUBX,40,GSV,0,0,0,0,0,0\r\n +Initialization String 6 - Command = $PUBX,40,RMC,0,1,0,0,0,0\r\n +Initialization String 7 - Command = $PUBX,40,GGA,0,1,0,0,0,0\r\n +Initialization String 8 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 9 - Command = $PUBX,40,GST,0,1,0,0,0,0\r\n + +# SVS (using serial over TCP). +[Transports.SerialOverTCP/SVS] +Enabled = Hardware +Debug Level = None +Entity Label = SVS to TCP +Serial Port - Device = /dev/uart/7 +Serial Port - Baud Rate = 38400 +Serial Port - Canonical Input = true +TCP - Port = 8889 +Activation Time = 5 +Deactivation Time = 5 +Execution Priority = 10 -[Sensors.Imagenex872] -IPv4 Address = 192.168.0.5 +[Sensors.XchangeSV] +IO Port - Device = tcp://10.0.10.20:8889 +Power On Delay = 10 +Activation Time = 15 + +[Sensors.Keller] +Enabled = Never + +[Sensors.NortekDVL] +IO Port - Device = tcp://10.0.10.27:9000 +Enable Input Trigger = true +Device Orientation = 0, -90, 0 +Type Activation = Water +Additional Stream A = PD0 [Sensors.Microstrain3DMGX3] +IO Port - Device = uart:///dev/uart/1:115200 Hard-Iron Calibration = -0.070032, 0.032197, 0.0 [Sensors.MLBL] Address Section = Micromodem Addresses - DMSMW +Serial Port - Device = /dev/uart/10 -[Power.PCTLv2] -ADC Reference Voltage = 1.083 -Power Channel 3 - Name = N/C (+12V_5) -Power Channel 3 - State = 0 +[Transports.IridiumSBD] +Flush Iridium Queue = true + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Address Section = Micromodem Addresses - DMSMW + +[Transports.CommManager] +Acoustic Address Section = Micromodem Addresses - DMSMW + +[Transports.FTP] +Enabled = Simulation + +[Transports.Announce] +Enabled = Simulation + +[Transports.Announce/Hardware] +Enabled = Hardware +Additional Services - External = ftp://10.0.10.23:30021/ +Entity Label = Service Announcer +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Debug Level = None +Execution Priority = 10 +Announcement Periodicity = 10 +Enable Loopback = 1 +Enable Multicast = 1 +Enable Broadcast = 1 +Multicast Address = 224.0.75.69 +Ports = 30100, 30101, 30102, 30103, 30104 +Ignored Interfaces = eth0:prv + +# For DVL Calibration procedure uncomment below +#[Require testing/dvl-calibration.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] + +# Slave CPU +[Require hardware/lctr-a6xx/slavecpu.ini] +[Supervisors.SlaveCPU] +Slave System Name = lauv-seacon-2-cpu-cam +Power Channel = Private (Camera CPU) +Dispatch Power Operation = true + +[Supervisors.Power] +Slave System Names = lauv-seacon-2-aux + +[Monitors.Clock] +Enabled = Never + +[Supervisors.ClockPPS] +Enabled = Hardware +Entity Label = Clock +Execution Priority = 10 +PPS - Device = /dev/pps0 +Execute On Synchronization = /sbin/hwclock -w +Debug Level = None + +[Transports.TCP.Server/SlaveCPU] +Enabled = Always + +# Sidescan delegator. +[Supervisors.Delegator/Sidescan] +Enabled = Hardware +Activation Time = 40.0 +Deactivation Time = 15.0 +Entity Label = Sidescan +Debug Level = None +Surrogate Task = Sensors.DeepVisionOSM2 +Surrogate Section = Sensors.DeepVisionOSM2 +Surrogate System = lauv-seacon-2-aux +Surrogate Entity = Sidescan + +# Camera delegator. +[Supervisors.Delegator/PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +Surrogate Task = Vision.PointGrey +Surrogate Section = Vision.PointGrey +Surrogate System = lauv-seacon-2-cpu-cam +Surrogate Entity = Camera +Surrogate Power Channel = Private (Camera CPU) +Activation Time = 60 +Deactivation Time = 5 +Active = false +Active - Scope = maneuver +Active - Visibility = user +Execution Priority = 10 diff --git a/etc/lauv-seacon-3-aux.ini b/etc/lauv-seacon-3-aux.ini new file mode 100644 index 0000000000..62274d75c4 --- /dev/null +++ b/etc/lauv-seacon-3-aux.ini @@ -0,0 +1,80 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# LAUV Seacon 3 auxiliary CPU configuration file # +############################################################################ + +[Include common/imc-addresses.ini] +[Require hardware/lctr-rpi/thermalzone.ini] +[Require hardware/lctr-a6xx/klein3500.ini] + +[General] +Vehicle = lauv-seacon-3-aux + +[Sensors.ThermalZone] +Entity Label = Mainboard Aux +Entity Label - Temperature = Mainboard (Auxiliary CPU) + +[Supervisors.Power] +Enabled = Hardware +Entity Label = Power Supervisor +Main Power Channel = System +Command - On Power Down = services syslog stop && + mount -o remount,ro /opt +Command - On Power Down Abort = mount -o remount,rw /opt && + services syslog restart + +[Transports.TCP.Client] +Enabled = Always +Entity Label = TCP to Master +Server - Address = 10.0.10.30 +Server - Port = 9999 +Transports = DevDataText, + EntityState, + EntityActivationState, + EntityInfo, + EntityParameters, + Heartbeat, + LogBookEntry, + LoggingControl, + PowerChannelControl, + PowerChannelState, + PulseDetectionControl, + SonarData, + Temperature + +[Sensors.Klein3500] +Debug Level = None +NMEA Over UDP - Port = 24302 +Device URL = tcp://10.0.10.34:4660 +Bathymetry Channel Available = false +Data Server Port = 0 +Log Prefix = ../lauv-seacon-3 +Legacy PAUV = false +Limit PAUV Rate = false +Log NMEA Sentences = true \ No newline at end of file diff --git a/etc/lauv-seacon-3-cpu-cam.ini b/etc/lauv-seacon-3-cpu-cam.ini new file mode 100644 index 0000000000..6f1beaa7c1 --- /dev/null +++ b/etc/lauv-seacon-3-cpu-cam.ini @@ -0,0 +1,135 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +# Author: Maria Costa # +############################################################################ +# LAUV Seacon 3 Camera CPU configuration file # +############################################################################ + +[Include common/imc-addresses.ini] +[Require hardware/lctr-rpi/thermalzone.ini] + +[General] +Vehicle = lauv-seacon-3-cpu-cam + +[Vision.PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +System Name = lauv-seacon-3 +#Led modes: Strobe, On, Off +Led Mode = Strobe +Power Channel - Strobe = Camera - Strobe +Copyright = LSTS-FEUP +Lens Model = 1/2 4mm F1.2-F11 - 4mm UC +Lens Make = www.edmundoptics.eu +Saved Images Dir = Photos +Number Frames/s = 3 +Split Photos = true +Number of photos to divide = 1000 +GPIO Driver Power = 17 +GPIO Strobe = 27 +Strobe Delay (us) = 100000 +Shutter Value (ms) = 8 +Activation Time = 60 +Deactivation Time = 5 + +[General] +CPU Usage - Maximum = 85 + +[Sensors.ThermalZone] +Entity Label = Mainboard Camera CPU +Entity Label - Temperature = Mainboard (Camera CPU) + +[Supervisors.Power] +Enabled = Hardware +Entity Label = Power Supervisor +Main Power Channel = System +Command - On Power Down = services syslog stop && + mount -o remount,ro /opt +Command - On Power Down Abort = mount -o remount,rw /opt && + services syslog restart + +[Transports.TCP.Client] +Enabled = Hardware +Entity Label = TCP to Master +Server - Address = 10.0.10.30 +Server - Port = 9999 +Trace - Incoming Messages = false +Trace - Outgoing Messages = false +Transports = EntityState, + EntityActivationState, + EntityInfo, + EntityParameters, + Heartbeat, + LogBookEntry, + LoggingControl, + Temperature + +[Transports.HTTP] +Enabled = Always +Entity Label = HTTP Server +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Port = 8080 +Threads = 5 +Transports = CpuUsage, + Current, + EntityState, + GpsFix, + Heartbeat, + Temperature, + Voltage, + EntityList + +[Transports.Logging] +Enabled = Never +Entity Label = Logger +Debug Level = None +Activation Time = 0 +Deactivation Time = 0 +Execution Priority = 2 +Flush Interval = 5 +LSF Compression Method = gzip +LSF Volume Size = 0 +Transports = CpuUsage, + EntityActivationState, + EntityList, + EntityMonitoringState, + EntityParameters, + EntityState, + EstimatedState, + GpsFix, + Heartbeat, + LogBookEntry, + PowerChannelControl, + PowerChannelState, + QueryEntityParameters, + SaveEntityParameters, + Temperature diff --git a/etc/lauv-seacon-3.ini b/etc/lauv-seacon-3.ini index 64ed80dadf..bc4f77b9a4 100644 --- a/etc/lauv-seacon-3.ini +++ b/etc/lauv-seacon-3.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,13 +31,16 @@ [Require auv/basic.ini] [Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/evologics.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] [Require hardware/lctr-a6xx/gsm-lc2m.ini] [Require hardware/lctr-a6xx/imagenex852.ini] -[Require hardware/lctr-a6xx/micromodem.ini] -[Require hardware/lctr-a6xx/microstrain3dmgx3.ini] +[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] +[Require ../private/etc/sensors/ixblue.ini] +[Require hardware/lctr-a6xx/nortekdvl.ini] [Require hardware/lctr-a6xx/scrtv4.ini] -[Require hardware/lctr-a6xx/xr620ctd.ini] +[Require hardware/lctr-a6xx/xchangesv.ini] ############################################################################ # Vehicle specific overrides # @@ -59,23 +62,35 @@ Hardware List = LSTS PCTLv2, Ubiquiti PicoStation M2HP, TP-LINK SF1008D, GSM/UMTS/HDSPA, - WHOI MicroModem, + Evologics S2CR 18/34, U-blox EVK-6H, - Keller-33x, - Microstrain 3DM-GX3, + Klein UUV-3500, + Nortek DVL 1MHz (Ethernet), LSTS BROOM + Motor, LSTS SCRTv4 + BMS-705MG, - RBR XR-620CTD, - Imagenex 852 + Raspberry Pi 4, + AML SV Xchange, + Imagenex 852, + IXBLUE Phins C3 [Control.AUV.Attitude] -Roll PID Gains = 0.3, 0.05, 0.01 -Depth PID Gains = 0.3, 0.05, 0.6 -Depth Integral Limit = 5.0 -Heading Rate PID Gains = 1.5, 0.0, 0.0 -Roll Compensation -- Use Speed = true -Roll Compensation -- Speed Bounds = 0.8, 1.8 -Roll Compensation -- Speed Gain = 0.5 +Roll PID Gains = 0.7, 0.0, 0.2 +Depth PID Gains = 0.4, 0.05, 0.6 +Depth Integral Limit = 1.0 +Maximum Pitch Reference = 15.0 +Pitch PID Gains = 1.5, 0.25, 1.1 +Pitch Integral Limit = 5.0 +Maximum Pitch Actuation = 25.0 +Heading PID Gains = 1.5, 0.0, 0.0 +Maximum Heading Rate = 30.0 +Heading Rate PID Gains = 1.2, 0.0, 0.0 +Maximum Fin Rotation = 25.0 +Force Pitch At Surface = true +Pitch Angle At Surface = 10.0 +Log PID Parcels = true + +[Control.Path.VectorField] +Bottom Track -- Enabled = true [Control.AUV.RemoteOperation] Disable Analog Thrust = false @@ -101,35 +116,205 @@ Enabled = Never SMS Recipient Number = +351910012611 [Monitors.Entities] -Default Monitoring -- Hardware = AHRS, +Default Monitoring -- Hardware = BATMAN, Clock, - Collisions, - Fuel, - Leak Sensor - Antenna, - Leak Sensor - Bottom, + Leak Sensor, + Medium Sensor, Motor Controller, + Navigation, Servo Controller [Monitors.FuelLevel] -Capacity Decay Factor = 10.0 +Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 [Monitors.Servos] Position Fault Detection = true [Navigation.AUV.Navigation] -Distance Between DVL and CG = 0.36 -Distance Between LBL and GPS = 1.20 -Distance Between GPS and CG = 0.25 +Distance Between DVL and CG = 0.606 +Distance Between LBL and GPS = 0.80 +Distance Between GPS and CG = -0.461 + +[Power.BATMANv2] +Serial Port - Device = /dev/uart/11 +Scale Factor A/Ah = 2.0 +Warning Level = 20 +Error Level = 15 [Power.PCTLv2] ADC Reference Voltage = 1.101 +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor +Power Channel 1 - Name = N/C (+12V_3) +Power Channel 2 - Name = Sound Velocity Sensor +Power Channel 2 - State = 1 Power Channel 3 - Name = N/C (+12V_5) Power Channel 3 - State = 0 -Power Channel 5 - Name = N/C (Bout_2) +Power Channel 4 - Name = INS +Power Channel 4 - State = 1 +Power Channel 5 - Name = Private (Sidescan) Power Channel 5 - State = 0 +Power Channel 6 - Name = Private (Camera CPU) +Power Channel 6 - State = 0 +Power Channel 7 - Name = Echo Sounder and Acoustic Modem +Power Channel 11 - Name = Private (Auxiliary CPU) +Power Channel 11 - State = 1 +Power Channel 13 - Name = BATMAN +Power Channel 13 - State = 1 +Power Channel 15 - Name = N/C (+12V_2) +Power Channel 15 - State = 0 +Power Channel 17 - Name = Private (DVL) +Power Channel 17 - State = 1 + +[Sensors.GPS] +IO Port - Device = uart:///dev/ttyACM2:57600 +Sentence Order = GNVTG, GNZDA, PUBX +Initialization String 0 - Command = $PUBX,40,VTG,0,1,0,0,0,0\r\n +Initialization String 1 - Command = $PUBX,40,ZDA,0,1,0,0,0,0\r\n +Initialization String 2 - Command = $PUBX,40,00,0,1,0,0,0,0\r\n +Initialization String 3 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 4 - Command = $PUBX,40,GSA,0,0,0,0,0,0\r\n +Initialization String 5 - Command = $PUBX,40,GSV,0,0,0,0,0,0\r\n +Initialization String 6 - Command = $PUBX,40,RMC,0,1,0,0,0,0\r\n +Initialization String 7 - Command = $PUBX,40,GGA,0,1,0,0,0,0\r\n +Initialization String 8 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 9 - Command = $PUBX,40,GST,0,1,0,0,0,0\r\n + +# SVS (using serial over TCP). +[Transports.SerialOverTCP/SVS] +Enabled = Hardware +Debug Level = None +Entity Label = SVS to TCP +Serial Port - Device = /dev/uart/7 +Serial Port - Baud Rate = 38400 +Serial Port - Canonical Input = true +TCP - Port = 8889 +Activation Time = 5 +Deactivation Time = 5 +Execution Priority = 10 + +[Sensors.XchangeSV] +IO Port - Device = tcp://10.0.10.30:8889 +Power On Delay = 10 +Activation Time = 15 + +[Sensors.Keller] +Enabled = Never + +[Sensors.NortekDVL] +IO Port - Device = tcp://10.0.10.37:9000 +Enable Input Trigger = true +Device Orientation = 0, -90, 0 +Type Activation = Water +Additional Stream A = PD0 + +[Sensors.PhinsC3] +Lever Arm Depth = 0.120, 0.0, -0.056 + +[Transports.IridiumSBD] +Flush Iridium Queue = true + +[Transports.Evologics] +IPv4 Address = 10.0.10.35 +Address Section = Evologics Addresses - DMSMW + +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Address Section = Evologics Addresses - DMSMW + +[Transports.CommManager] +Acoustic Address Section = Evologics Addresses - DMSMW + +[Transports.Evologics/Simulator] +Address Section = Evologics Addresses - DMSMW + +[Transports.FTP] +Enabled = Simulation + +[Transports.Announce] +Enabled = Simulation + +[Transports.Announce/Hardware] +Enabled = Hardware +Additional Services - External = ftp://10.0.10.33:30021/ +Entity Label = Service Announcer +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Debug Level = None +Execution Priority = 10 +Announcement Periodicity = 10 +Enable Loopback = 1 +Enable Multicast = 1 +Enable Broadcast = 1 +Multicast Address = 224.0.75.69 +Ports = 30100, 30101, 30102, 30103, 30104 +Ignored Interfaces = eth0:prv + +# For DVL Calibration procedure uncomment below +#[Require testing/dvl-calibration.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-evologics.ini] + +# Slave CPU +[Require hardware/lctr-a6xx/slavecpu.ini] +[Supervisors.SlaveCPU] +Slave System Name = lauv-seacon-3-cpu-cam +Power Channel = Private (Camera CPU) +Dispatch Power Operation = true + +[Supervisors.Power] +Slave System Names = lauv-seacon-3-aux + +[Monitors.Clock] +Enabled = Never + +[Supervisors.ClockPPS] +Enabled = Hardware +Entity Label = Clock +Execution Priority = 10 +PPS - Device = /dev/pps0 +Execute On Synchronization = /sbin/hwclock -w +Debug Level = None + +[Transports.TCP.Server/SlaveCPU] +Enabled = Always -[Sensors.Microstrain3DMGX3] -Hard-Iron Calibration = 0.004097, 0.017165, 0.0 +# Sidescan delegator. +[Supervisors.Delegator/Klein3500] +Enabled = Hardware +Entity Label = Sidescan +Debug Level = None +Surrogate Task = Sensors.Klein3500 +Surrogate Section = Sensors.Klein3500 +Surrogate System = lauv-seacon-3-aux +Surrogate Entity = Sidescan +Activation Time = 90 +Deactivation Time = 10 +Active = false +Active - Scope = maneuver +Active - Visibility = user +Execution Priority = 10 -[Sensors.MLBL] -Address Section = Micromodem Addresses - DMSMW +# Camera delegator. +[Supervisors.Delegator/PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +Surrogate Task = Vision.PointGrey +Surrogate Section = Vision.PointGrey +Surrogate System = lauv-seacon-3-cpu-cam +Surrogate Entity = Camera +Surrogate Power Channel = Private (Camera CPU) +Activation Time = 60 +Deactivation Time = 5 +Active = false +Active - Scope = maneuver +Active - Visibility = user +Execution Priority = 10 diff --git a/etc/lauv-simulator-1.ini b/etc/lauv-simulator-1.ini index 1339685314..2cbb492099 100644 --- a/etc/lauv-simulator-1.ini +++ b/etc/lauv-simulator-1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/lauv-xplore-1.ini b/etc/lauv-xplore-1.ini index 2257d1a964..43f82eb406 100644 --- a/etc/lauv-xplore-1.ini +++ b/etc/lauv-xplore-1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,7 +31,8 @@ [Require auv/basic.ini] [Require hardware/lctr-a6xx/basic.ini] -[Require hardware/lctr-a6xx/broom-36v.ini] +#[Require hardware/lctr-a6xx/broom-36v.ini] +[Require hardware/lctr-a6xx/batman.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] [Require hardware/lctr-a6xx/gsm-lc2m.ini] [Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] @@ -39,14 +40,13 @@ [Require hardware/lctr-a6xx/microstrain3dmgx3.ini] [Require hardware/lctr-a6xx/scrtv4.ini] [Require hardware/lctr-a6xx/metrecx.ini] -[Require common/trex.ini] ############################################################################ # Vehicle specific overrides # ############################################################################ [General] Vehicle = lauv-xplore-1 -Absolute Maximum Depth = 60 +Absolute Maximum Depth = 105 Absolute Minimum Altitude = 1.2 Battery Packs = 8 Battery Capacity = 1400 @@ -70,18 +70,33 @@ Hardware List = LSTS PCTLv2, LSTS SCRTv4 + BMS-705MG, RBR XR-620CTD +[Control.AUV.Allocator] +Fin effect Rpm minimum value = 200 +Fin effect Velocity dependent = true +Fin effect Velocity dependent unit = RPM +Fin effect minimum Meter Per Second value = 0.2 +Roll not velocity dependent = true +k pitch = 1.35 +k roll = 1.0 +k yaw = 2.0 + [Control.AUV.Attitude] -Roll PID Gains = 0.7, 0.0, 0.2 +Roll PID Gains = 0.4, 0.05, 0.3 Roll Compensation -- Use Speed = true Roll Compensation -- Speed Gain = 0.2 -Depth PID Gains = 0.4, 0.05, 0.6 -Depth Integral Limit = 2.5 +Roll Integral Limit = 5.0 +Depth PID Gains = 0.65, 0.015, 0.7 +Depth Integral Limit = 5 Heading Rate PID Gains = 1.2, 0.0, 0.0 +Pitch PID Gains = 1.325, 0.0, 0.0 +Pitch Angle At Surface = 5.0 + [Monitors.Entities] Default Monitoring = Attitude, Daemon, GPS, + Navigation, Operational Limits, Path Control Default Monitoring -- Hardware = AHRS, @@ -95,12 +110,18 @@ Default Monitoring -- Hardware = AHRS, [Monitors.FuelLevel] Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 # to be corrected [Navigation.AUV.Navigation] GPS Maximum HACC = 40.0 Distance Between LBL and GPS = 0.98 Abort if Uncertainty Exceeded = false +Activate speed to rpm estimation limit = true +Depth sensor localization in x axis = 0.64 +Rpm to speed estimation = true +speed to rpm estimation percentage limit = 15 [Sensors.MetrecX] Digital Channel 1 - Message = Conductivity @@ -118,37 +139,56 @@ PH Slope = 0.634 Entity Label - Temperature Backup = Depth Sensor [Sensors.Microstrain3DMGX3] -Hard-Iron Calibration = -0.025859, 0.006891, 0.0 +Hard-Iron Calibration = -0.041908, 0.031712, 0.0 [Simulators.Environment] Simulate - Bottom Distance = false Simulate - Forward Distance = false +[Power.BATMANv2] +Serial Port - Device = /dev/uart/9 +Scale Factor A/Ah = 2.5 +Warning Level = 20 +Error Level = 15 + [Power.PCTLv2] ADC Reference Voltage = 1.083 +Power Channel 3 - Name = BATMAN +Power Channel 3 - State = 1 Power Channel 5 - Name = N/C (Bout_2) Power Channel 5 - State = 0 Power Channel 7 - Name = N/C (Bout_4) Power Channel 7 - State = 0 Power Channel 11 - Name = Auxiliary CPU -Power Channel 11 - State = 0 +Power Channel 11 - State = 1 Power Channel 17 - Name = N/C (DVL) Power Channel 17 - State = 0 -[Autonomy.TREX] -TREX ID = 65001 - -[Transports.UDP/TREX] -Static Destinations = 10.0.10.123:6969 -Announce Service = false - [Transports.LoggingDigest] Enabled = Hardware Entity Label = Logger (Digest) Sample Interval = 1 Flush Interval = 5 -Transports = EstimatedState, +Transports = EntityInfo, + EstimatedState, Temperature, Salinity, Conductivity, - Pressure \ No newline at end of file + Pressure + +[Monitors.Clock] +Enabled = Hardware + +[Supervisors.ClockPPS] +Enabled = Never + +[Monitors.Emergency] +Enabled = Always + +[Maneuver.Multiplexer] +PopUp -- Report at PopUps = true +YoYo -- Maximum Pitch Variation = 15 + +# Use pure pursuit path controller +#[Require common/pure-pursuit.ini] + diff --git a/etc/lauv-xplore-2.ini b/etc/lauv-xplore-2.ini index a76402eeca..a6765836ef 100644 --- a/etc/lauv-xplore-2.ini +++ b/etc/lauv-xplore-2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,25 +30,26 @@ ############################################################################ [Require auv/basic.ini] -[Require hardware/lctr-a6xx/aim104multiio.ini] [Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/broom-36v.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/cyclopsc7.ini] [Require hardware/lctr-a6xx/gps-lc2m.ini] [Require hardware/lctr-a6xx/gsm-lc2m.ini] +[Require hardware/lctr-a6xx/imagenex852.ini] [Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] [Require hardware/lctr-a6xx/micromodem.ini] [Require hardware/lctr-a6xx/microstrain3dmgx3.ini] +[Require hardware/lctr-a6xx/oemx.ini] [Require hardware/lctr-a6xx/scrtv4.ini] -[Require hardware/lctr-a6xx/xr620ctd.ini] -[Require hardware/lctr-a6xx/cyclopsc7.ini] [Require hardware/lctr-a6xx/sadc.ini] -[Require common/trex.ini] ############################################################################ # Vehicle specific overrides # ############################################################################ [General] Vehicle = lauv-xplore-2 -Absolute Maximum Depth = 60 +Absolute Maximum Depth = 105 Absolute Minimum Altitude = 1.2 Battery Packs = 8 Battery Capacity = 1400 @@ -67,30 +68,46 @@ Hardware List = LSTS PCTLv2, GSM/UMTS/HDSPA, WHOI MicroModem, U-blox EVK-6H, - Keller-33x, Microstrain 3DM-GX3, LSTS BROOM + Motor, LSTS SCRTv4 + BMS-705MG, - RBR XR-620CTD + RBR XR-620CTD, + Imagenex 852 +[Control.AUV.Allocator] +Fin effect Rpm minimum value = 200 +Fin effect Velocity dependent = true +Fin effect Velocity dependent unit = RPM +Fin effect minimum Meter Per Second value = 0.2 +Roll not velocity dependent = true +k pitch = 1.3 +k roll = 1.0 +k yaw = 2.0 [Control.AUV.Attitude] -Roll PID Gains = 0.7, 0.0, 0.2 -Roll Compensation -- Use Speed = true -Roll Compensation -- Speed Gain = 0.2 -Depth PID Gains = 0.4, 0.05, 0.6 -Depth Integral Limit = 2.5 +Depth Integral Limit = 5.0 +Depth PID Gains = 0.5, 0.008, 0.1 +Depth-to-pitch PID sampling rate relation = 2 Heading Rate PID Gains = 1.2, 0.0, 0.0 +Heading PID Gains = 1.5, 0.0, 0.15 +Maximum Pitch Reference = 12.0 +Pitch Angle At Surface = 5.0 +Pitch Integral Limit = 1.0 +Pitch PID Gains = 1.0, 0.0, 0.2 +Roll Compensation -- Use Speed = false +Roll Integral Limit = 5.0 +Roll PID Gains = 0.4, 0.05, 0.3 + [Monitors.Entities] Default Monitoring = Attitude, Daemon, GPS, + Navigation, Operational Limits, Path Control Default Monitoring -- Hardware = AHRS, Clock, Collisions, - Fuel, Leak Sensor - Antenna, Leak Sensor - Bottom, Motor Controller, @@ -98,12 +115,22 @@ Default Monitoring -- Hardware = AHRS, [Monitors.FuelLevel] Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 + +[Monitors.Medium] +# Reported sound speed in air is 1450... +Sound Speed Threshold = 1600 +# Ignore state of medium sensor +Entity Label - Medium Sensor = N/A # to be corrected [Navigation.AUV.Navigation] GPS Maximum HACC = 40.0 Distance Between LBL and GPS = 0.98 Abort if Uncertainty Exceeded = false +Entity Label - Depth = OEMX +#Entity Label - Altitude - Hardware = Echo Sounder #(if Echosounder at -90º) [Sensors.AIM104MultiIO] Enabled = Never @@ -112,36 +139,55 @@ ADC0 - Conversion = 1.0, 0.0 ADC0 - Entity Label = Chlorophyll Probe Voltage [Sensors.Microstrain3DMGX3] +#APDL Hard-Iron Calibration = 0.010155, 0.024699, 0.0 +#Sesimbra +#Hard-Iron Calibration = 0.005450, 0.013942, 0.0 + +[Sensors.Imagenex852] +IO Port - Device = uart:///dev/uart/10 + +[Sensors.OEMX] +Serial Port - Device = /dev/uart/7 +Serial Port - Baud Rate = 38400 +Primary Mount = Conductivity + #SoundSpeed + #Temperature +Secondary Mount = Pressure, + Temperature + #Turbidity [Simulators.Environment] Simulate - Bottom Distance = false Simulate - Forward Distance = false +[Power.BATMANv2] +Serial Port - Device = /dev/uart/9 +Scale Factor A/Ah = 2.5 +Warning Level = 20 +Error Level = 15 + [Power.PCTLv2] +Leak 0 - Entity Label = Leak Sensor - Bottom +Leak 0 - Medium Sensor = false +Leak 1 - Entity Label = Leak Sensor - Antenna +Leak 1 - Medium Sensor = false ADC Reference Voltage = 1.083 +Power Channel 2 - Name = OEMX Smart-x +Power Channel 2 - State = 1 Power Channel 3 - Name = SADC Power Channel 3 - State = 1 Power Channel 5 - Name = N/C (Bout_2) Power Channel 5 - State = 0 -Power Channel 7 - Name = N/C (Bout_4) -Power Channel 7 - State = 0 Power Channel 11 - Name = Auxiliary CPU -Power Channel 11 - State = 0 +Power Channel 11 - State = 1 Power Channel 12 - Name = Wet Sensor Probe Power Channel 12 - State = 0 -Power Channel 15 - Name = N/C (+12V_2) -Power Channel 15 - State = 0 +Power Channel 15 - Name = BATMAN +Power Channel 15 - State = 1 Power Channel 17 - Name = N/C (DVL) Power Channel 17 - State = 0 -[Autonomy.TREX] -TREX ID = 65002 - -[Transports.UDP/TREX] -Static Destinations = 10.0.10.133:6969 -Announce Service = false - [Transports.LoggingDigest] Enabled = Hardware Entity Label = Logger (Digest) @@ -153,6 +199,8 @@ Transports = EstimatedState, Conductivity, Pressure +[Sensors.Keller] +Enabled = Never [Sensors.CyclopsC7] Enabled = Hardware @@ -164,7 +212,6 @@ CH 2 - Is Active = true CH 2 - Voltage Entity Label = Chlorophyll CH 2 - Name of message to produce = Chlorophyll - [Sensors.SADC] Enabled = Hardware Serial Port - Device = /dev/uart/8 @@ -172,4 +219,19 @@ Sample Rate = 5 ADC 1 - Is Active = true ADC 1 - Entity Label = Turbidity ADC 2 - Is Active = true -ADC 2 - Entity Label = Chlorophyll \ No newline at end of file +ADC 2 - Entity Label = Chlorophyll + +[Sensors.Imagenex852] +Sonar orientation = 0, -45, 0 + +[Monitors.Clock] +Enabled = Hardware + +[Supervisors.ClockPPS] +Enabled = Never + +# Use pure pursuit path controller +#[Require common/pure-pursuit.ini] + +[Maneuver.Multiplexer] +PopUp -- Report at PopUps = true diff --git a/etc/lauv-xplore-3.ini b/etc/lauv-xplore-3.ini new file mode 100644 index 0000000000..bf0e6f1ad1 --- /dev/null +++ b/etc/lauv-xplore-3.ini @@ -0,0 +1,248 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ +# LAUV Xplore 3 configuration file # +############################################################################ + +[Require auv/basic.ini] +[Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/broom-36v.ini] +[Require hardware/lctr-a6xx/gps-lc2m.ini] +[Require hardware/lctr-a6xx/gsm-lc2m.ini] +[Require hardware/lctr-a6xx/limu.ini] +[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] +[Require hardware/lctr-a6xx/scrtv4.ini] +[Require hardware/lctr-a6xx/oemx.ini] +[Require hardware/lctr-rpi/thermalzone.ini] + +############################################################################ +# Vehicle specific overrides # +############################################################################ +[General] +Vehicle = lauv-xplore-3 +Absolute Maximum Depth = 105 +Absolute Minimum Altitude = 1.2 +Battery Packs = 8 +Battery Capacity = 1400 +Power Model -- Conversion - Watt = 0, 14, 20, 54, 70 +Power Model -- Conversion - RPM = 0, 500, 850, 1250, 1400 +Speed Conversion -- Actuation = 0, 36, 46 +Speed Conversion -- RPM = 0, 900, 1150 +Speed Conversion -- MPS = 0, 1, 1.3 +Maximum Absolute Speed = 2.1 +Hardware List = LSTS PCTLv2, + IEI PM-LX2-800W, + Raspberry Pi 2, + Ubiquiti PicoStation M2HP, + TP-LINK SF1008D, + GSM/UMTS/HDSPA, + U-blox EVK-6H, + Keller-33x, + LSTS BROOM + Motor, + LSTS SCRTv4 + BMS-705MG, + RBR XR-620CTD +[Control.AUV.Allocator] +Fin effect Rpm minimum value = 200 +Fin effect Velocity dependent = true +Fin effect Velocity dependent unit = RPM +Fin effect minimum Meter Per Second value = 0.2 +Roll not velocity dependent = true +k pitch = 1.3 +k roll = 2.0 +k yaw = 2.0 + +[Control.AUV.Attitude] +Depth Integral Limit = 5.0 +Depth PID Gains = 0.5, 0.008, 0.1 +Depth-to-pitch PID sampling rate relation = 2 +Maximum Pitch Reference = 15.0 +Pitch Integral Limit = 25.0 +Pitch PID Gains = 1.8, 0.0, 0.0 +Roll Integral Limit = 5.0 +Roll PID Gains = 0.4, 0.05, 0.3 +Roll Compensation -- Use Speed = false +Roll Compensation -- Speed Gain = 0.2 +Heading Rate PID Gains = 1.2, 0.0, 0.0 +Heading PID Gains = 1.5, 0.0, 0.15 +Pitch Angle At Surface = 5.0 + +[Control.AUV.RemoteOperation] +Pitch Reference = 5.0 + +[Monitors.Entities] +Default Monitoring = Attitude, + Daemon, + GPS, + Navigation, + Operational Limits, + Path Control +Default Monitoring -- Hardware = AHRS, + Clock, + Collisions, + BATMAN, + Leak Sensor 0, + Leak Sensor 1, + Motor Controller, + Servo Controller + +[Monitors.FuelLevel] +Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 + +# to be corrected +[Navigation.AUV.Navigation] +GPS Maximum HACC = 40.0 +Distance Between LBL and GPS = 0.98 +Abort if Uncertainty Exceeded = false +Activate speed to rpm estimation limit = true +Depth sensor localization in x axis = 0.92 +Rpm to speed estimation = true +speed to rpm estimation percentage limit= 15 + +[Simulators.Environment] +Simulate - Bottom Distance = false +Simulate - Forward Distance = false + +[Actuators.SCRTv4] +Serial Port - Device = /dev/ttyAMA2 + +[Actuators.Broom] +Serial Port - Device = /dev/ttyAMA3 + +[Sensors.SCH311X] +Enabled = Never + +[Sensors.ThermalZone] +Enabled = Hardware +Entity Label = Thermal Zone +Execution Frequency = 1 +Path = /sys/class/thermal/thermal_zone0/temp +Entity Label - Temperature = Mainboard (Core) + +[Sensors.Keller] +IO Port - Device = uart:///dev/ttyUSB4:9600 +Serial Port - Local Echo = 0 + +[Sensors.LIMU] +IO Port - Device = uart:///dev/ttyAMA1 +Power Channel - Name = +#APDL +Hard-Iron Calibration = 0.0771, -0.0336, 0.0 +#Sesimbra +Hard-Iron Calibration = 0.0246, -0.0308, 0.0 + +[Sensors.OEMX] +Serial Port - Device = /dev/ttyUSB1 +Serial Port - Baud Rate = 38400 +Primary Mount = Conductivity + #SoundSpeed + #Temperature +Secondary Mount = Pressure, + Temperature + #Turbidity + +[Power.BATMANv2] +Serial Port - Device = /dev/ttyAMA4 +Scale Factor A/Ah = 4.0 +Warning Level = 20 +Error Level = 15 + +[Power.PCTLv2] +Serial Port - Device = /dev/ttyUSB0 +ADC Reference Voltage = 1.083 +ADC Channel 0 - Entity Label = pctl - Bat +ADC Channel 1 - Entity Label = pctl - Bat +Leak 0 - Entity Label = Leak Sensor 0 +Leak 1 - Entity Label = Leak Sensor 1 +Minimum Operating Voltage = 18 +Wakeup Operating Voltage = 22 +Power Channel 2 - Name = OEMX Smart-x +Power Channel 2 - State = 1 +Power Channel 4 - Name = N/C (Bout_1) +Power Channel 4 - State = 0 +Power Channel 5 - Name = N/C (Bout_2) +Power Channel 5 - State = 0 +Power Channel 6 - Name = LC2M +Power Channel 6 - State = 1 +Power Channel 7 - Name = N/C (Bout_4) +Power Channel 7 - State = 0 +Power Channel 10 - Name = Switch Ethernet +Power Channel 10 - State = 1 +Power Channel 11 - Name = Auxiliary CPU +Power Channel 11 - State = 1 +Power Channel 13 - Name = N/C (+5V_6) +Power Channel 13 - State = 0 +Power Channel 15 - Name = BATMAN +Power Channel 15 - State = 1 +Power Channel 17 - Name = N/C (DVL) +Power Channel 17 - State = 0 + +[Transports.LoggingDigest] +Enabled = Hardware +Entity Label = Logger (Digest) +Sample Interval = 1 +Flush Interval = 5 +Transports = EntityInfo, + EstimatedState, + Temperature, + Salinity, + Conductivity, + Pressure + +[Transports.UDP] +Filtered Entities = CpuUsage:Daemon, + Distance:Altimeter+DVL Filtered+Echo Sounder, + Temperature:CTD+Depth Sensor+BATMAN, + Voltage:Batteries+Rhodamine+Turbidity+Chlorophyll+CELL 1+CELL 2+CELL 3+CELL 4+CELL 5+CELL 6+CELL 7+BATMAN, + Current:BATMAN+FCap+RCap + +[Monitors.Clock] +Enabled = Hardware + +[Supervisors.ClockPPS] +Enabled = Never + +[Monitors.Medium] +# Reported sound speed in air is 1450... +Sound Speed Threshold = 1600 +# Ignore state of medium sensor +Entity Label - Medium Sensor = OEMX + +# Use pure pursuit path controller +#[Require common/pure-pursuit.ini] + +[Maneuver.Multiplexer] +PopUp -- Report at PopUps = true + +[Sensors.GPS] +Power Channel - Names = GPS + +[Transports.Announce] +Ignored Interfaces = eth1:prv diff --git a/etc/lauv-xplore-4-aux.ini b/etc/lauv-xplore-4-aux.ini new file mode 100644 index 0000000000..447acea696 --- /dev/null +++ b/etc/lauv-xplore-4-aux.ini @@ -0,0 +1,53 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Paulo Dias # +############################################################################ +# LAUV Xplore 4 auxiliary CPU configuration file # +############################################################################ + +[Include common/imc-addresses.ini] +[Include hardware/wifi-rssi.ini] + +[General] +Vehicle = lauv-xplore-4-aux + +[IMC Addresses] +lauv-xplore-4-aux = 0x6010 + +[Transports.TCP.Client] +Enabled = Never +Entity Label = TCP to Master +Server - Address = 10.0.10.150 +Server - Port = 9999 +Transports = RSSI + +[Sensors.WifiRSSI] +Enabled = Hardware +Remote Hostname = 10.0.10.151 +Private Key File = ../../../../root/.ssh/id_rsa +Debug Level = None + diff --git a/etc/lauv-xplore-4.ini b/etc/lauv-xplore-4.ini new file mode 100644 index 0000000000..140e0e6075 --- /dev/null +++ b/etc/lauv-xplore-4.ini @@ -0,0 +1,227 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ +# LAUV Xplore 4 configuration file # +############################################################################ + +[Require auv/basic.ini] +[Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/broom-36v.ini] +[Require hardware/lctr-a6xx/gps-lc2m.ini] +[Require hardware/lctr-a6xx/gsm-lc2m.ini] +[Require hardware/lctr-a6xx/limu.ini] +[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] +[Require hardware/lctr-a6xx/scrtv4.ini] +[Require hardware/lctr-a6xx/oemx.ini] + +############################################################################ +# Vehicle specific overrides # +############################################################################ +[General] +Vehicle = lauv-xplore-4 +Absolute Maximum Depth = 105 +Absolute Minimum Altitude = 1.2 +Battery Packs = 8 +Battery Capacity = 1400 +Power Model -- Conversion - Watt = 0, 14, 20, 54, 70 +Power Model -- Conversion - RPM = 0, 500, 850, 1250, 1400 +Speed Conversion -- Actuation = 0, 36, 46 +Speed Conversion -- RPM = 0, 900, 1150 +Speed Conversion -- MPS = 0, 1, 1.3 +Maximum Absolute Speed = 2.1 +Hardware List = LSTS PCTLv2, + IEI PM-LX2-800W, + Raspberry Pi 2, + Ubiquiti PicoStation M2HP, + TP-LINK SF1008D, + GSM/UMTS/HDSPA, + U-blox EVK-6H, + Keller-33x, + LSTS BROOM + Motor, + LSTS SCRTv4 + BMS-705MG, + RBR XR-620CTD +[Control.AUV.Allocator] +Fin effect Rpm minimum value = 200 +Fin effect Velocity dependent = true +Fin effect Velocity dependent unit = RPM +Fin effect minimum Meter Per Second value = 0.2 +Roll not velocity dependent = true +k pitch = 1.3 +k roll = 2.0 +k yaw = 2.0 + +[Control.AUV.Attitude] +Depth Integral Limit = 5.0 +Depth PID Gains = 0.5, 0.008, 0.1 +Depth-to-pitch PID sampling rate relation = 2 +Maximum Pitch Reference = 15.0 +Pitch Integral Limit = 25.0 +Pitch PID Gains = 1.7, 0.0, 0.0 +Roll Integral Limit = 5.0 +Roll PID Gains = 0.4, 0.05, 0.3 +Roll Compensation -- Use Speed = false +Roll Compensation -- Speed Gain = 0.2 +Heading Rate PID Gains = 1.2, 0.0, 0.0 +Heading PID Gains = 1.5, 0.0, 0.15 +Pitch Angle At Surface = 5.0 + +[Control.AUV.RemoteOperation] +Pitch Reference = 5.0 + +[Monitors.Entities] +Default Monitoring = Attitude, + Daemon, + GPS, + Navigation, + Operational Limits, + Path Control +Default Monitoring -- Hardware = AHRS, + Clock, + Collisions, + BATMAN, + Medium Sensor, + Leak Sensor, + Motor Controller, + Servo Controller + +[Monitors.FuelLevel] +Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 + +# to be corrected +[Navigation.AUV.Navigation] +GPS Maximum HACC = 40.0 +Distance Between LBL and GPS = 0.98 +Abort if Uncertainty Exceeded = false +Activate speed to rpm estimation limit = true +Depth sensor localization in x axis = 0.92 +Rpm to speed estimation = true +speed to rpm estimation percentage limit= 15 + + + +[Simulators.Environment] +Simulate - Bottom Distance = false +Simulate - Forward Distance = false + +[Sensors.LIMU] +IO Port - Device = uart:///dev/uart/8 +#APDL +#Hard-Iron Calibration = 0.0110, -0.0456, 0.0 +#Sesimbra +Hard-Iron Calibration = 0.0217, -0.0473, 0.0 + +[Sensors.OEMX] +Serial Port - Device = /dev/uart/7 +Serial Port - Baud Rate = 38400 +Primary Mount = Conductivity + #SoundSpeed + #Temperature +Secondary Mount = Pressure, + Temperature + #Turbidity + +[Power.BATMANv2] +Serial Port - Device = /dev/uart/11 +Scale Factor A/Ah = 4.0 +Warning Level = 20 +Error Level = 15 + +[Power.PCTLv2] +ADC Reference Voltage = 1.083 +ADC Channel 0 - Entity Label = pctl - Bat +ADC Channel 1 - Entity Label = pctl - Bat +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor +Minimum Operating Voltage = 18 +Wakeup Operating Voltage = 22 +Power Channel 2 - Name = OEMX Smart-x +Power Channel 2 - State = 1 +Power Channel 4 - Name = N/C (Bout_1) +Power Channel 4 - State = 0 +Power Channel 5 - Name = N/C (Bout_2) +Power Channel 5 - State = 0 +Power Channel 6 - Name = LC2M +Power Channel 6 - State = 1 +Power Channel 7 - Name = N/C (Bout_4) +Power Channel 7 - State = 0 +Power Channel 10 - Name = Switch Ethernet +Power Channel 10 - State = 1 +Power Channel 11 - Name = Auxiliary CPU +Power Channel 11 - State = 1 +Power Channel 13 - Name = N/C (+5V_6) +Power Channel 13 - State = 0 +Power Channel 15 - Name = BATMAN +Power Channel 15 - State = 1 +Power Channel 17 - Name = N/C (DVL) +Power Channel 17 - State = 0 + + +[Transports.LoggingDigest] +Enabled = Hardware +Entity Label = Logger (Digest) +Sample Interval = 1 +Flush Interval = 5 +Transports = EntityInfo, + EstimatedState, + Temperature, + Salinity, + Conductivity, + Pressure + +[Transports.UDP] +Filtered Entities = CpuUsage:Daemon, + Distance:Altimeter+DVL Filtered+Echo Sounder, + Temperature:CTD+Depth Sensor+BATMAN, + Voltage:Batteries+Rhodamine+Turbidity+Chlorophyll+CELL 1+CELL 2+CELL 3+CELL 4+CELL 5+CELL 6+CELL 7+BATMAN, + Current:BATMAN+FCap+RCap + +[Monitors.Clock] +Enabled = Hardware + +[Supervisors.ClockPPS] +Enabled = Never + +[Monitors.Medium] +# Reported sound speed in air is 1450... +Sound Speed Threshold = 1600 +# Ignore state of medium sensor +Entity Label - Medium Sensor = N/A + +# Use pure pursuit path controller +#[Require common/pure-pursuit.ini] + +[Maneuver.Multiplexer] +PopUp -- Report at PopUps = true + +[Transports.TCP.Server/SlaveCPU] +Enabled = Hardware + diff --git a/etc/lauv-xplore-5.ini b/etc/lauv-xplore-5.ini new file mode 100644 index 0000000000..846c4cca7f --- /dev/null +++ b/etc/lauv-xplore-5.ini @@ -0,0 +1,246 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ +# LAUV Xplore 5 configuration file # +############################################################################ + +[Require auv/basic.ini] +[Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/broom-36v.ini] +[Require hardware/lctr-a6xx/gps-lc2m.ini] +[Require hardware/lctr-a6xx/gsm-lc2m.ini] +[Require hardware/lctr-a6xx/limu.ini] +[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] +[Require hardware/lctr-a6xx/scrtv4.ini] +[Require hardware/lctr-a6xx/oemx.ini] + +############################################################################ +# Vehicle specific overrides # +############################################################################ +[General] +Vehicle = lauv-xplore-5 +Absolute Maximum Depth = 105 +Absolute Minimum Altitude = 1.2 +Battery Packs = 8 +Battery Capacity = 1400 +Power Model -- Conversion - Watt = 0, 14, 20, 54, 70 +Power Model -- Conversion - RPM = 0, 500, 850, 1250, 1400 +Speed Conversion -- Actuation = 0, 36, 46 +Speed Conversion -- RPM = 0, 900, 1150 +Speed Conversion -- MPS = 0, 1, 1.3 +Maximum Absolute Speed = 2.1 +Hardware List = LSTS PCTLv2, + IEI PM-LX2-800W, + Raspberry Pi 2, + Ubiquiti PicoStation M2HP, + TP-LINK SF1008D, + GSM/UMTS/HDSPA, + U-blox EVK-6H, + Keller-33x, + LSTS BROOM + Motor, + LSTS SCRTv4 + BMS-705MG, + RBR XR-620CTD +[Control.AUV.Allocator] +Fin effect Rpm minimum value = 200 +Fin effect Velocity dependent = true +Fin effect Velocity dependent unit = RPM +Fin effect minimum Meter Per Second value = 0.2 +Roll not velocity dependent = true +k pitch = 1.3 +k roll = 2.0 +k yaw = 2.0 + +[Control.AUV.Attitude] +Depth Integral Limit = 5.0 +Depth PID Gains = 0.5, 0.008, 0.1 +Depth-to-pitch PID sampling rate relation = 2 +Maximum Pitch Reference = 15.0 +Pitch Integral Limit = 25.0 +Pitch PID Gains = 1.7, 0.0, 0.0 +Roll Integral Limit = 5.0 +Roll PID Gains = 0.4, 0.05, 0.3 +Roll Compensation -- Use Speed = false +Roll Compensation -- Speed Gain = 0.2 +Heading Rate PID Gains = 1.2, 0.0, 0.0 +Heading PID Gains = 1.5, 0.0, 0.15 +Pitch Angle At Surface = 5.0 + +[Control.AUV.RemoteOperation] +Pitch Reference = 5.0 + +[Monitors.Entities] +Default Monitoring = Attitude, + Daemon, + GPS, + Navigation, + Operational Limits, + Path Control +Default Monitoring -- Hardware = AHRS, + Clock, + Collisions, + BATMAN, + Medium Sensor, + Leak Sensor, + Motor Controller, + Servo Controller + +[Monitors.FuelLevel] +Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 + +# to be corrected +[Navigation.AUV.Navigation] +GPS Maximum HACC = 40.0 +Distance Between LBL and GPS = 0.98 +Abort if Uncertainty Exceeded = false +Activate speed to rpm estimation limit = true +Depth sensor localization in x axis = 0.92 +Rpm to speed estimation = true +speed to rpm estimation percentage limit= 15 + +[Simulators.Environment] +Simulate - Bottom Distance = false +Simulate - Forward Distance = false + +[Sensors.LIMU] +IO Port - Device = uart:///dev/ttyAMA1 +Power Channel - Name = +Hard-Iron Calibration = 0.0054, -0.0612, 0.0 + +[Sensors.GPS] +Power Channel - Names = GPS + +[Sensors.Keller] +IO Port - Device = uart:///dev/ttyUSB4:9600 +Serial Port - Local Echo = 0 + +[Sensors.OEMX] +Serial Port - Device = /dev/ttyUSB1 +Serial Port - Baud Rate = 38400 +Primary Mount = Conductivity + #SoundSpeed + #Temperature +Secondary Mount = Pressure, + Temperature + #Turbidity + +[Sensors.SCH311X] +Enabled = Never + +[Sensors.ThermalZone] +Enabled = Hardware +Entity Label = Thermal Zone +Execution Frequency = 1 +Path = /sys/class/thermal/thermal_zone0/temp +Entity Label - Temperature = Mainboard (Core) + +[Actuators.SCRTv4] +Serial Port - Device = /dev/ttyAMA2 + +[Actuators.Broom] +Serial Port - Device = /dev/ttyAMA3 + +[Power.BATMANv2] +Serial Port - Device = /dev/ttyAMA4 +Scale Factor A/Ah = 4.0 +Warning Level = 20 +Error Level = 15 + +[Power.PCTLv2] +Serial Port - Device = /dev/ttyUSB0 +ADC Reference Voltage = 1.083 +ADC Channel 0 - Entity Label = pctl - Bat +ADC Channel 1 - Entity Label = pctl - Bat +Leak 0 - Entity Label = Medium Sensor +Leak 0 - Medium Sensor = true +Leak 1 - Entity Label = Leak Sensor +Minimum Operating Voltage = 18 +Wakeup Operating Voltage = 22 +Power Channel 2 - Name = OEMX Smart-x +Power Channel 2 - State = 1 +Power Channel 4 - Name = N/C (Bout_1) +Power Channel 4 - State = 0 +Power Channel 5 - Name = N/C (Bout_2) +Power Channel 5 - State = 0 +Power Channel 6 - Name = LC2M +Power Channel 6 - State = 1 +Power Channel 7 - Name = N/C (Bout_4) +Power Channel 7 - State = 0 +Power Channel 10 - Name = Switch Ethernet +Power Channel 10 - State = 1 +Power Channel 11 - Name = Auxiliary CPU +Power Channel 11 - State = 1 +Power Channel 13 - Name = N/C (+5V_6) +Power Channel 13 - State = 0 +Power Channel 15 - Name = BATMAN +Power Channel 15 - State = 1 +Power Channel 17 - Name = N/C (DVL) +Power Channel 17 - State = 0 + + +[Transports.LoggingDigest] +Enabled = Hardware +Entity Label = Logger (Digest) +Sample Interval = 1 +Flush Interval = 5 +Transports = EntityInfo, + EstimatedState, + Temperature, + Salinity, + Conductivity, + Pressure + +[Transports.UDP] +Filtered Entities = CpuUsage:Daemon, + Distance:Altimeter+DVL Filtered+Echo Sounder, + Temperature:CTD+Depth Sensor+BATMAN, + Voltage:Batteries+Rhodamine+Turbidity+Chlorophyll+CELL 1+CELL 2+CELL 3+CELL 4+CELL 5+CELL 6+CELL 7+BATMAN, + Current:BATMAN+FCap+RCap + +[Monitors.Clock] +Enabled = Hardware + +[Supervisors.ClockPPS] +Enabled = Never + +[Monitors.Medium] +# Reported sound speed in air is 1450... +Sound Speed Threshold = 1600 +# Ignore state of medium sensor +Entity Label - Medium Sensor = N/A + +# Use pure pursuit path controller +#[Require common/pure-pursuit.ini] + +[Maneuver.Multiplexer] +PopUp -- Report at PopUps = true + +[Transports.Announce] +Ignored Interfaces = eth1:prv diff --git a/etc/lauv-xtreme-2-aux.ini b/etc/lauv-xtreme-2-aux.ini index 68804c16cf..67efc7f65c 100644 --- a/etc/lauv-xtreme-2-aux.ini +++ b/etc/lauv-xtreme-2-aux.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,6 +30,7 @@ ############################################################################ [Include common/imc-addresses.ini] +[Require hardware/lctr-a6xx/klein3500.ini] [General] Vehicle = lauv-xtreme-2-aux @@ -48,11 +49,24 @@ Enabled = Always Entity Label = TCP to Master Server - Address = 10.0.10.50 Server - Port = 9999 -Transports = Heartbeat, +Transports = EntityState, + EntityActivationState, + EntityInfo, + EntityParameters, + Heartbeat, + LogBookEntry, LoggingControl, PowerChannelControl, PowerChannelState, - EntityState, - EntityActivationState, - EntityInfo, - EntityParameters + PulseDetectionControl, + SonarData, + Temperature + +[Sensors.Klein3500] +Debug Level = None +NMEA Over UDP - Port = 24302 +Device URL = tcp://10.0.10.54:4660 +Bathymetry Channel Available = true +Data Server Port = 0 +Log Prefix = ../lauv-xtreme-2 +Legacy PAUV = true \ No newline at end of file diff --git a/etc/lauv-xtreme-2-cpu-cam.ini b/etc/lauv-xtreme-2-cpu-cam.ini new file mode 100644 index 0000000000..88855e5bc5 --- /dev/null +++ b/etc/lauv-xtreme-2-cpu-cam.ini @@ -0,0 +1,134 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ +# LAUV Extreme 2 Camera CPU configuration file # +############################################################################ + +[Include common/imc-addresses.ini] +[Include hardware/lctr-rpi/thermalzone.ini] + +[General] +Vehicle = lauv-xtreme-2-cpu-cam + +[Vision.PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +System Name = lauv-xtreme-2 +#Led modes: Strobe, On, Off +Led Mode = Strobe +Power Channel - Strobe = Camera - Strobe +Copyright = LSTS-FEUP +Lens Model = 1/2 4mm F1.2-F11 - 4mm UC +Lens Make = www.edmundoptics.eu +Saved Images Dir = Photos +Number Frames/s = 3 +Split Photos = true +Number of photos to divide = 1000 +GPIO Driver Power = 17 +GPIO Strobe = 27 +Strobe Delay (us) = 100000 +Shutter Value (ms) = 8 +Activation Time = 60 +Deactivation Time = 5 + +[General] +CPU Usage - Maximum = 85 + +[Sensors.ThermalZone] +Entity Label = Mainboard Camera CPU +Entity Label - Temperature = Mainboard (Camera CPU) + +[Supervisors.Power] +Enabled = Hardware +Entity Label = Power Supervisor +Main Power Channel = System +Command - On Power Down = services syslog stop && + mount -o remount,ro /opt +Command - On Power Down Abort = mount -o remount,rw /opt && + services syslog restart + +[Transports.TCP.Client] +Enabled = Hardware +Entity Label = TCP to Master +Server - Address = 10.0.10.50 +Server - Port = 9999 +Trace - Incoming Messages = false +Trace - Outgoing Messages = false +Transports = EntityState, + EntityActivationState, + EntityInfo, + EntityParameters, + Heartbeat, + LogBookEntry, + LoggingControl, + Temperature + +[Transports.HTTP] +Enabled = Always +Entity Label = HTTP Server +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Port = 8080 +Threads = 5 +Transports = CpuUsage, + Current, + EntityState, + GpsFix, + Heartbeat, + Temperature, + Voltage, + EntityList + +[Transports.Logging] +Enabled = Always +Entity Label = Logger +Debug Level = None +Activation Time = 0 +Deactivation Time = 0 +Execution Priority = 2 +Flush Interval = 5 +LSF Compression Method = gzip +LSF Volume Size = 0 +Transports = CpuUsage, + EntityActivationState, + EntityList, + EntityMonitoringState, + EntityParameters, + EntityState, + EstimatedState, + GpsFix, + Heartbeat, + LogBookEntry, + PowerChannelControl, + PowerChannelState, + QueryEntityParameters, + SaveEntityParameters, + Temperature diff --git a/etc/lauv-xtreme-2.ini b/etc/lauv-xtreme-2.ini index e05d83de3a..aee12d2607 100644 --- a/etc/lauv-xtreme-2.ini +++ b/etc/lauv-xtreme-2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,6 +30,20 @@ ############################################################################ [Require auv/basic.ini] +[Require hardware/lctr-a6xx/basic.ini] +[Require hardware/lctr-a6xx/broom.ini] +[Require hardware/lctr-a6xx/batman.ini] +[Require hardware/lctr-a6xx/evologics.ini] +[Require hardware/lctr-a6xx/gps-lc2m.ini] +[Require hardware/lctr-a6xx/gsm-lc2m.ini] +#[Require hardware/lctr-a6xx/imagenex852.ini] +[Require ../private/etc/sensors/imagenex852.ini] +[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] +[Require ../private/etc/sensors/ixblue.ini] +[Require hardware/lctr-a6xx/nortekdvl.ini] +[Require hardware/lctr-a6xx/scrtv4.ini] +[Require hardware/lctr-a6xx/xchangesv.ini] +[Require hardware/lctr-a6xx/klein3500.ini] ############################################################################ # Vehicle specific overrides # @@ -49,141 +63,297 @@ Maximum Absolute Speed = 1.6 Hardware List = LSTS PCTLv2, IEI PM-LX2-800W, Ubiquiti PicoStation M2HP, - Asus GX-D1051, + TP-LINK SF1008D, GSM/UMTS/HDSPA, Evologics S2CR 18/34, - Honeywell HG1700, U-blox EVK-6H, - Keller-33x, - LSTS LIMUv1, + Klein UUV-3500, + Nortek DVL 1MHz (Ethernet), LSTS BROOM + Motor, LSTS SCRTv4 + BMS-705MG, - Teledyne RDI ExplorerDVL, + Raspberry Pi 4, AML SV Xchange, - Imagenex 852, - Klein UUV-3500, - Raspberry Pi 2 + IXBLUE Phins C3 + +[Actuators.Broom] +Serial Port - Device = /dev/ttyS5 [Control.AUV.Attitude] -Roll PID Gains = 1.0, 0.0, 0.2 -Depth PID Gains = 0.3, 0.006, 0.6 -Depth Integral Limit = 0.03 -Heading Rate PID Gains = 1.0, 0.0, 0.0 +Roll PID Gains = 0.7, 0.0, 0.2 +Depth PID Gains = 0.4, 0.05, 0.6 +Depth Integral Limit = 1.0 +Maximum Pitch Reference = 15.0 +Pitch PID Gains = 1.5, 0.25, 1.1 +Pitch Integral Limit = 5.0 +Maximum Pitch Actuation = 25.0 +Heading PID Gains = 1.5, 0.0, 0.0 +Maximum Heading Rate = 30.0 +Heading Rate PID Gains = 1.2, 0.0, 0.0 +Maximum Fin Rotation = 25.0 +Force Pitch At Surface = true +Pitch Angle At Surface = 10.0 +Log PID Parcels = true [Control.Path.VectorField] Bottom Track -- Enabled = true +[Control.AUV.RemoteOperation] +Disable Analog Thrust = false +# Aprox 2000 rpm +Position of Horizontal Fins = -15.0 + +[Maneuver.CommsRelay] +Enabled = Never + +[Maneuver.FollowSystem] +Enabled = Never + +[Maneuver.FollowTrajectory] +Enabled = Never + +[Maneuver.VehicleFormation.SMC] +Enabled = Never + +[Maneuver.RowsCoverage] +Enabled = Never + +[Monitors.Emergency] +SMS Recipient Number = +351910012611 + +[Actuators.SCRTv4] +Enabled = Hardware +Serial Port - Device = /dev/ttyS4 + [Monitors.Entities] -Default Monitoring -- Hardware = Clock, - Collisions, +Default Monitoring -- Hardware = BATMAN, + Clock, DVL, - Fuel, - IMU, Leak Sensor, Motor Controller, Servo Controller [Monitors.FuelLevel] -Capacity Decay Factor = 10.0 +Capacity Decay Factor = 6.0 +Warning Level = 20 +Error Level = 15 -[Navigation.AUV.Navigation] -Distance Between DVL and CG = 0.41 +[Monitors.Servos] +Position Fault Detection = true -[Navigation.AUV.Ranger] -Enabled = Always -Entity Label = Ranger -Ping Periodicity = 5 -Debug Level = Spew +[Navigation.AUV.Navigation] +Distance Between DVL and CG = 0.606 +Distance Between LBL and GPS = 0.80 +Distance Between GPS and CG = -0.461 -[Transports.UAN] -Enabled = Hardware -Entity Label = Acoustic Access Controller -Enable Reports = true +[Power.BATMANv2] +Serial Port - Device = /dev/ttyS10 +Scale Factor A/Ah = 2.0 +Warning Level = 20 +Error Level = 15 -############################################################################ -# Hardware. # -############################################################################ +[Sensors.SCH311X] +Enabled = Never -[Require hardware/lctr-a6xx/sch311x.ini] -[Require hardware/lctr-a6xx/leds.ini] -[Require hardware/lctr-a6xx/broom.ini] -[Require hardware/lctr-a6xx/keller.ini] -[Require hardware/lctr-a6xx/gps-lc2m.ini] -[Require hardware/lctr-a6xx/gsm-lc2m.ini] -[Require hardware/lctr-a6xx/iridiumsbd-lc2m.ini] -[Require hardware/lctr-a6xx/imagenex852.ini] -[Require hardware/lctr-a6xx/xchangesv.ini] -[Require hardware/lctr-a6xx/psimar.ini] -[Require hardware/lctr-a6xx/scrtv4.ini] -[Require hardware/lctr-a6xx/hg1700.ini] +[Sensors.ThermalZone] +Enabled = Hardware +Entity Label = Thermal Zone +Execution Frequency = 1 +Path = /sys/class/hwmon/hwmon0/temp2_input +Entity Label - Temperature = Mainboard (Core) -[Require hardware/lctr-a6xx/pctlv2.ini] [Power.PCTLv2] +ADC Reference Voltage = 1.101 Leak 0 - Entity Label = Medium Sensor Leak 0 - Medium Sensor = true Leak 1 - Entity Label = Leak Sensor -ADC Reference Voltage = 1.098 -Power Channel 1 - Name = Magnetometer -Power Channel 1 - State = 0 -Power Channel 2 - Name = SVS +ADC Channel 1 - Conversion = 12.5, 0.0 +Power Channel 1 - Name = N/C (+12V_3) +Power Channel 2 - Name = Sound Velocity Sensor Power Channel 2 - State = 1 +Power Channel 3 - Name = N/C (+12V_5) +Power Channel 3 - State = 0 +Power Channel 4 - Name = INS +Power Channel 4 - State = 1 Power Channel 5 - Name = Private (Sidescan) Power Channel 5 - State = 0 +Power Channel 6 - Name = Private (Camera CPU) +Power Channel 6 - State = 0 +Power Channel 7 - Name = Echo Sounder and Acoustic Modem Power Channel 11 - Name = Private (Auxiliary CPU) Power Channel 11 - State = 1 -Power Channel 13 - Name = N/C (+5V_6) -Power Channel 13 - State = 0 +Power Channel 13 - Name = BATMAN +Power Channel 13 - State = 1 +Power Channel 15 - Name = N/C (+12V_2) +Power Channel 15 - State = 0 +Power Channel 17 - Name = Private (DVL) +Power Channel 17 - State = 1 +Serial Port - Device = /dev/ttyS11 + +[Sensors.GPS] +Enabled = Hardware +IO Port - Device = uart:///dev/ttyS7:57600 +Activation Time = 20.0 +Debug Level = None +Power Channel - Names = GPS +Post Power On Delay = 10.0 +Sentence Order = GNVTG, GNZDA, PUBX +Initialization String 0 - Command = $PUBX,40,VTG,0,1,0,0,0,0\r\n +Initialization String 1 - Command = $PUBX,40,ZDA,0,1,0,0,0,0\r\n +Initialization String 2 - Command = $PUBX,40,00,0,1,0,0,0,0\r\n +Initialization String 3 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 4 - Command = $PUBX,40,GSA,0,0,0,0,0,0\r\n +Initialization String 5 - Command = $PUBX,40,GSV,0,0,0,0,0,0\r\n +Initialization String 6 - Command = $PUBX,40,RMC,0,1,0,0,0,0\r\n +Initialization String 7 - Command = $PUBX,40,GGA,0,1,0,0,0,0\r\n +Initialization String 8 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 9 - Command = $PUBX,40,GST,0,1,0,0,0,0\r\n -[Require hardware/lctr-a6xx/limu.ini] -[Sensors.LIMU] -Hard-Iron Calibration = 0.0264, -0.0476, 0.0 -Serial Port - Device = /dev/uart/8 +# SVS (using serial over TCP). +[Transports.SerialOverTCP/SVS] +Enabled = Hardware +Debug Level = None +Entity Label = SVS to TCP +Serial Port - Device = /dev/ttyS6 +Serial Port - Baud Rate = 38400 +Serial Port - Canonical Input = true +TCP - Port = 8889 +Activation Time = 5 +Deactivation Time = 5 +Execution Priority = 10 -[Require hardware/lctr-a6xx/explorerdvl.ini] -[Sensors.ExplorerDVL] -Device Position = 0.78, 0, 0.12 +[Sensors.XchangeSV] +IO Port - Device = tcp://10.0.10.50:8889 +Power On Delay = 10 +Activation Time = 15 + +[Sensors.Keller] +Enabled = Never + +[Sensors.NortekDVL] +IO Port - Device = tcp://10.0.10.57:9000 +Enable Input Trigger = true +Device Orientation = 0, -90, 0 +Type Activation = Water +Additional Stream A = PD0 + +[Sensors.PhinsC3] +Power On Delay = 10.0 +Lever Arm Depth = 0.120, 0.0, -0.056 + +[Transports.IridiumSBD] +Flush Iridium Queue = true -[Require hardware/lctr-a6xx/evologics.ini] [Transports.Evologics] IPv4 Address = 10.0.10.55 -[Require hardware/lctr-a6xx/klein3500.ini] -[Sensors.Klein3500] -IPv4 Address = 10.0.10.54 +[Transports.UAN] +Enabled = Always +Entity Label = Acoustic Access Controller +Enable Reports = true +Address Section = Evologics Addresses - DMSMW -[Sensors.EmulatedGPS] +[Transports.CommManager] +Acoustic Address Section = Evologics Addresses - DMSMW + +[Transports.Evologics/Simulator] +Address Section = Evologics Addresses - DMSMW + +[Transports.FTP] +Enabled = Simulation + +[Transports.Announce] +Enabled = Simulation + +[Transports.Announce/Hardware] Enabled = Hardware -Entity Label = Emulated GPS -Serial Port - Device = /dev/uart/11 -Serial Port - Baud Rate = 4800 -Send Sentences on Pulse = true -Send ZDA = true -Send RMC = false -Send HDT = false -Send VTG = false +Additional Services - External = ftp://10.0.10.50:30021/ +Entity Label = Service Announcer +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Debug Level = None +Execution Priority = 10 +Announcement Periodicity = 10 +Enable Loopback = 1 +Enable Multicast = 1 +Enable Broadcast = 1 +Multicast Address = 224.0.75.69 +Ports = 30100, 30101, 30102, 30103, 30104 +Ignored Interfaces = eth0:prv + +# For DVL Calibration procedure uncomment below +#[Require testing/dvl-calibration.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-evologics.ini] # Slave CPU [Require hardware/lctr-a6xx/slavecpu.ini] [Supervisors.SlaveCPU] -Slave System Name = lauv-xtreme-2-aux -Dispatch Power Operation = false +Slave System Name = lauv-xtreme-2-cpu-cam +Power Channel = Private (Camera CPU) +Dispatch Power Operation = true [Supervisors.Power] -Slave System Names = lauv-xtreme-2-aux +Slave System Names = lauv-xtreme-2-cpu-cam [Monitors.Clock] Enabled = Never [Supervisors.ClockPPS] Enabled = Hardware +Entity Label = Clock +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Serial Port - Device = /dev/ttyS4 +PPS - Device = /dev/pps3 +PPS - Propagation Delay = 675 +PPS - Maximum Offset = 50 +GPS Offset Count = 10 +Execute On Synchronization = hwclock -w + +[Transports.TCP.Server/SlaveCPU] +Enabled = Always + +[Sensors.Klein3500] +Debug Level = None +Deactivation Time = 60 +NMEA Over UDP - Port = 24302 +Device URL = tcp://10.0.10.54:4660 +Bathymetry Channel Available = true +Data Server Port = 0 +Log Prefix = ../lauv-xtreme-2 +Legacy PAUV = true + +# Camera delegator. +[Supervisors.Delegator/PointGrey] +Enabled = Hardware +Entity Label = Camera +Debug Level = None +Surrogate Task = Vision.PointGrey +Surrogate Section = Vision.PointGrey +Surrogate System = lauv-xtreme-2-cpu-cam +Surrogate Entity = Camera +Surrogate Power Channel = Private (Camera CPU) +Activation Time = 60 +Deactivation Time = 5 +Active = false +Active - Scope = maneuver +Active - Visibility = user +Execution Priority = 10 -[Sensors.SCM] +[Sensors.Imagenex852v2] +IO Port - Device = uart:///dev/ttyS8 + +[Sensors.EmulatedGPS] Enabled = Hardware -Entity Label = Magnetometer -Serial Port - Device = /dev/uart/1 +Entity Label = Emulated GPS +Serial Port - Device = /dev/ttyS9 Serial Port - Baud Rate = 9600 -Debug Level = Spew -Activation Time = 5.0 -Deactivation Time = 0.0 -Power Channel = Magnetometer -Entity Label - Motor Current = Motor +Send Sentences on Pulse = true +Send ZDA = true +Send RMC = false +Send HDT = false +Send VTG = false \ No newline at end of file diff --git a/etc/manta-1.ini b/etc/manta-1.ini index 1990935901..cc5f47498e 100644 --- a/etc/manta-1.ini +++ b/etc/manta-1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -28,6 +28,7 @@ ############################################################################ [Require hardware/lctr-a9xx.ini] +[Require hardware/radio.ini] [General] Vehicle = manta-1 @@ -53,9 +54,16 @@ Device updates - Periodicity = 1200 #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] #[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] #[Require hardware/acoustic-modems/seatrac_ip_200.ini] #[Require hardware/acoustic-modems/seatrac_uart.ini] +#[Require development/cdc3/cdc3-seatrac_uart.ini] #[Require hardware/acoustic-modems/evologics_ip_1.ini] #[Require hardware/acoustic-modems/evologics_ip_2.ini] #[Require hardware/acoustic-modems/evologics_ip_4.ini] #[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-11.ini b/etc/manta-11.ini index 0c0ae241c8..0d9cad0ef4 100644 --- a/etc/manta-11.ini +++ b/etc/manta-11.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -28,20 +28,22 @@ ############################################################################ [Require hardware/lctr-a9xx.ini] +[Require hardware/radio.ini] [General] Vehicle = manta-11 [Power.MCBv2] Drive LCD = true -Power Channel 3 - State = 0 -Power Channel 7 - Name = Iridium + Acoustic Modem +Power Channel 7 - Name = Acoustic Modem Power Channel 7 - State = 1 +Power Channel 10 - Name = Iridium +Power Channel 10 - State = 1 [Transports.IridiumSBD] Enabled = Hardware Entity Label = Iridium Modem -Serial Port - Device = /dev/ttyACM1 +Serial Port - Device = /dev/ttyUSB0 Serial Port - Baud Rate = 19200 Mailbox Check - Periodicity = 1800 @@ -53,9 +55,16 @@ Device updates - Periodicity = 1200 #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] #[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] #[Require hardware/acoustic-modems/seatrac_ip_200.ini] #[Require hardware/acoustic-modems/seatrac_uart.ini] +#[Require development/cdc3/cdc3-seatrac_uart.ini] #[Require hardware/acoustic-modems/evologics_ip_1.ini] #[Require hardware/acoustic-modems/evologics_ip_2.ini] #[Require hardware/acoustic-modems/evologics_ip_4.ini] #[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-12.ini b/etc/manta-12.ini index 1b8d2612ea..c8a25970ba 100644 --- a/etc/manta-12.ini +++ b/etc/manta-12.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -28,6 +28,7 @@ ############################################################################ [Require hardware/lctr-a9xx.ini] +[Require hardware/radio.ini] [General] Vehicle = manta-12 @@ -46,7 +47,7 @@ Power Channel 10 - State = 1 [Transports.IridiumSBD] Enabled = Hardware Entity Label = Iridium Modem -Serial Port - Device = /dev/ttyACM1 +Serial Port - Device = /dev/ttyUSB0 Serial Port - Baud Rate = 19200 Mailbox Check - Periodicity = 1800 @@ -58,9 +59,16 @@ Device updates - Periodicity = 1200 #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] #[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] #[Require hardware/acoustic-modems/seatrac_ip_200.ini] #[Require hardware/acoustic-modems/seatrac_uart.ini] +#[Require development/cdc3/cdc3-seatrac_uart.ini] #[Require hardware/acoustic-modems/evologics_ip_1.ini] #[Require hardware/acoustic-modems/evologics_ip_2.ini] #[Require hardware/acoustic-modems/evologics_ip_4.ini] #[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-2.ini b/etc/manta-2.ini index d62e4be3a6..e96be7c72c 100644 --- a/etc/manta-2.ini +++ b/etc/manta-2.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -28,6 +28,7 @@ ############################################################################ [Require hardware/lctr-a9xx.ini] +[Require hardware/radio.ini] [General] Vehicle = manta-2 @@ -35,12 +36,12 @@ Vehicle = manta-2 [Power.MCBv2] Drive LCD = true Power Channel 10 - Name = Iridium -Power Channel 10 - State = 0 +Power Channel 10 - State = 1 [Transports.IridiumSBD] -Enabled = Never +Enabled = Hardware Entity Label = Iridium Modem -Serial Port - Device = /dev/ttyUSB3 +Serial Port - Device = /dev/ttyUSB0 Serial Port - Baud Rate = 19200 Mailbox Check - Periodicity = 1800 @@ -52,9 +53,16 @@ Device updates - Periodicity = 1200 #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] #[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] #[Require hardware/acoustic-modems/seatrac_ip_200.ini] #[Require hardware/acoustic-modems/seatrac_uart.ini] +#[Require development/cdc3/cdc3-seatrac_uart.ini] #[Require hardware/acoustic-modems/evologics_ip_1.ini] #[Require hardware/acoustic-modems/evologics_ip_2.ini] #[Require hardware/acoustic-modems/evologics_ip_4.ini] #[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-21.ini b/etc/manta-21.ini index 4f6a8ddc48..6043c2bba9 100644 --- a/etc/manta-21.ini +++ b/etc/manta-21.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -28,6 +28,7 @@ ############################################################################ [Require hardware/lctr-a9xx.ini] +[Require hardware/radio.ini] [General] Vehicle = manta-21 @@ -55,9 +56,16 @@ Device updates - Periodicity = 1200 #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] #[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] #[Require hardware/acoustic-modems/seatrac_ip_200.ini] #[Require hardware/acoustic-modems/seatrac_uart.ini] +#[Require development/cdc3/cdc3-seatrac_uart.ini] #[Require hardware/acoustic-modems/evologics_ip_1.ini] #[Require hardware/acoustic-modems/evologics_ip_2.ini] #[Require hardware/acoustic-modems/evologics_ip_4.ini] #[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-3.ini b/etc/manta-3.ini index 1a355963f7..a6ba27fe2c 100644 --- a/etc/manta-3.ini +++ b/etc/manta-3.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,7 +30,7 @@ ############################################################################ [Require hardware/lctr-a9xx.ini] -[Require hardware/lctr-a6xx/os5000.ini] +[Require hardware/radio.ini] [General] Vehicle = manta-3 @@ -38,12 +38,13 @@ Vehicle = manta-3 [Power.MCBv2] Drive LCD = true Power Channel 10 - Name = Iridium -Power Channel 10 - State = 0 +Power Channel 10 - State = 1 -[Sensors.OS4000] -Enabled = Hardware -Entity Label = AHRS -Serial Port - Device = /dev/ttyUSB0 +#[Require hardware/lctr-a6xx/os5000.ini] +#[Sensors.OS4000] +#Enabled = Never +#Entity Label = AHRS +#IO Port - Device = uart:///dev/ttyUSB0:115200 [Navigation.General.GPSNavigation] Enabled = Always @@ -52,53 +53,12 @@ Entity Label - GPS = GPS Entity Label - IMU = AHRS Entity Label - Yaw = AHRS -[Transports.Logging] -Transports = Abort, - Announce, - CpuUsage, - Current, - EntityList, - EntityState, - EstimatedState, - EulerAngles, - GpsFix, - Heartbeat, - LogBookControl, - LogBookEntry, - LoggingControl, - MagneticField, - SetControlSurfaceDeflection, - StorageUsage, - Temperature, - TextMessage, - Voltage - -[Transports.UDP] -Enabled = Always -Entity Label = UDP -Transports = Abort, - CpuUsage, - Current, - EntityList, - EstimatedState, - EulerAngles, - GpsFix, - Heartbeat, - LogBookControl, - LoggingControl, - MagneticField, - PlanControl, - SetControlSurfaceDeflection, - StorageUsage, - Temperature, - TextMessage, - Voltage [Actuators.FLIRPTU] Enabled = Never Entity Label = PTUD48 Execution Frequency = 5 -Serial Port - Device = /dev/ttyUSB0 +Serial Port - Device = /dev/uart/1 Serial Port - Baud Rate = 9600 PTU Model = D48 Pan Continuous = false @@ -114,27 +74,36 @@ Height = 60 Yaw Offset = 0 [Transports.MobileInternet] -Active = true +Active = false Serial Port - Device = /dev/ttyUSB1 [Transports.IridiumSBD] -Enabled = Never +Enabled = Hardware +Active = true Entity Label = Iridium Modem -Serial Port - Device = /dev/ttyUSB4 +Serial Port - Device = /dev/ttyUSB0 Serial Port - Baud Rate = 19200 Mailbox Check - Periodicity = 1800 [Transports.Iridium] -Enabled = Never +Enabled = Always Entity Label = Iridium Transport Device updates - Periodicity = 1200 + #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] #[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] #[Require hardware/acoustic-modems/seatrac_ip_200.ini] #[Require hardware/acoustic-modems/seatrac_uart.ini] +#[Require development/cdc3/cdc3-seatrac_uart.ini] #[Require hardware/acoustic-modems/evologics_ip_1.ini] #[Require hardware/acoustic-modems/evologics_ip_2.ini] #[Require hardware/acoustic-modems/evologics_ip_4.ini] #[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-dmsmw-01.ini b/etc/manta-dmsmw-01.ini index 5aab5e82a4..3b988d708a 100644 --- a/etc/manta-dmsmw-01.ini +++ b/etc/manta-dmsmw-01.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -36,20 +36,20 @@ Vehicle = manta-dmsmw-01 [Power.MCBv2] Drive LCD = true +Power Channel 6 - State = 0 +Power Channel 7 - Name = Acoustic Modem +Power Channel 7 - State = 1 [Sensors.MLBLTracker] +Enabled = Hardware +Entity Label = Acoustic Modem Address Section = Micromodem Addresses - DMSMW +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 19200 +GPIO - Transducer Detection = 157 [UserInterfaces.MantaPanel] -System Names = lauv-seacon-1, - lauv-seacon-2, - lauv-seacon-3, - benthos1, - benthos2, - benthos3, - benthos4, - benthos5, - benthos6 +Sections of System Addresses = Micromodem Addresses - DMSMW [Transports.Logging] Enabled = Never @@ -58,3 +58,8 @@ Enabled = Never GSM - User = vodafone GSM - Password = vodafone GSM - APN = net2.vodafone.pt + +#[Require hardware/acoustic-modems/uModem_ip_100.ini] +#[Require hardware/acoustic-modems/uModem_ip_104.ini] +#[Require hardware/acoustic-modems/uModem_ip_105.ini] +#[Require hardware/acoustic-modems/evologics_ip_19.ini] diff --git a/etc/manta-dmsmw-02.ini b/etc/manta-dmsmw-02.ini index ad4e06d173..e41f4532a6 100644 --- a/etc/manta-dmsmw-02.ini +++ b/etc/manta-dmsmw-02.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -36,28 +36,47 @@ Vehicle = manta-dmsmw-02 [Power.MCBv2] Drive LCD = true +Power Channel 7 - Name = Acoustic Modem +Power Channel 7 - State = 1 +Power Channel 10 - Name = Iridium +Power Channel 10 - State = 1 [Sensors.MLBLTracker] +Enabled = Hardware +Entity Label = Acoustic Modem Address Section = Micromodem Addresses - DMSMW +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 19200 +GPIO - Transducer Detection = 157 [UserInterfaces.LCD] Enabled = Never [UserInterfaces.MantaPanel] -System Names = lauv-seacon-1, - lauv-seacon-2, - lauv-seacon-3, - benthos1, - benthos2, - benthos3, - benthos4, - benthos5, - benthos6 +Sections of System Addresses = Micromodem Addresses - DMSMW + +[Transports.IridiumSBD] +Enabled = Hardware +Entity Label = Iridium Modem +Serial Port - Device = /dev/ttyUSB0 +Serial Port - Baud Rate = 19200 +Mailbox Check - Periodicity = 1800 + +[Transports.Iridium] +Enabled = Hardware +Entity Label = Iridium Transport +Device updates - Periodicity = 1200 [Transports.Logging] Enabled = Never [Transports.MobileInternet] +Serial Port - Device = /dev/ttyUSB1 GSM - User = vodafone GSM - Password = vodafone GSM - APN = net2.vodafone.pt + +#[Require hardware/acoustic-modems/uModem_ip_100.ini] +#[Require hardware/acoustic-modems/uModem_ip_104.ini] +#[Require hardware/acoustic-modems/uModem_ip_105.ini] +#[Require hardware/acoustic-modems/evologics_ip_19.ini] diff --git a/etc/manta-dmsmw-03.ini b/etc/manta-dmsmw-03.ini index e1132cf7c1..b4b4149591 100644 --- a/etc/manta-dmsmw-03.ini +++ b/etc/manta-dmsmw-03.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -40,28 +40,45 @@ Power Channel 1 - Name = Benthos Power Channel 1 - State = 1 Power Channel 2 - Name = WizNet Power Channel 2 - State = 1 +Power Channel 7 - Name = Acoustic Modem +Power Channel 7 - State = 1 +Power Channel 10 - Name = Iridium +Power Channel 10 - State = 1 [Sensors.MLBLTracker] +Enabled = Hardware +Entity Label = Acoustic Modem Address Section = Micromodem Addresses - DMSMW +GPIO - Transducer Detection = 157 [UserInterfaces.LCD] Enabled = Never [UserInterfaces.MantaPanel] -System Names = lauv-seacon-1, - lauv-seacon-2, - lauv-seacon-3, - benthos1, - benthos2, - benthos3, - benthos4, - benthos5, - benthos6 +Sections of System Addresses = Micromodem Addresses - DMSMW + +[Transports.IridiumSBD] +Enabled = Hardware +Entity Label = Iridium Modem +Serial Port - Device = /dev/ttyUSB0 +Serial Port - Baud Rate = 19200 +Mailbox Check - Periodicity = 1800 + +[Transports.Iridium] +Enabled = Hardware +Entity Label = Iridium Transport +Device updates - Periodicity = 1200 [Transports.Logging] Enabled = Never [Transports.MobileInternet] +Serial Port - Device = /dev/ttyUSB1 GSM - User = vodafone GSM - Password = vodafone GSM - APN = net2.vodafone.pt + +#[Require hardware/acoustic-modems/uModem_ip_100.ini] +#[Require hardware/acoustic-modems/uModem_ip_104.ini] +#[Require hardware/acoustic-modems/uModem_ip_105.ini] +#[Require hardware/acoustic-modems/evologics_ip_19.ini] diff --git a/etc/manta-rugged-2.ini b/etc/manta-rugged-2.ini new file mode 100644 index 0000000000..f413bf5c02 --- /dev/null +++ b/etc/manta-rugged-2.ini @@ -0,0 +1,70 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: José Braga # +############################################################################ +# Manta #25 Gateway configuration file # +############################################################################ + +[Require hardware/lctr-a9xx.ini] + +[General] +Vehicle = manta-rugged-2 + +[Power.MCBv2] +Drive LCD = true +Power Channel 10 - Name = Iridium +Power Channel 10 - State = 1 + +[Transports.IridiumSBD] +Enabled = Hardware +Entity Label = Iridium Modem +Serial Port - Device = /dev/ttyUSB0 +Serial Port - Baud Rate = 19200 +Mailbox Check - Periodicity = 720 + +[Transports.Iridium] +Enabled = Never +Entity Label = Iridium Transport +Device updates - Periodicity = 1200 + +[Transports.MobileInternet] +Serial Port - Device = /dev/ttyUSB1 + + +#[Require hardware/acoustic-modems/uModem_ip_100.ini] +#[Require hardware/acoustic-modems/uModem_ip_101.ini] +#[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] +#[Require hardware/acoustic-modems/seatrac_ip_200.ini] +#[Require hardware/acoustic-modems/evologics_ip_1.ini] +#[Require hardware/acoustic-modems/evologics_ip_2.ini] +#[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] + +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-rugged.ini b/etc/manta-rugged.ini index cf7c133727..bc55142cf8 100644 --- a/etc/manta-rugged.ini +++ b/etc/manta-rugged.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -51,12 +51,20 @@ Enabled = Never Entity Label = Iridium Transport Device updates - Periodicity = 1200 +[Transports.MobileInternet] +Serial Port - Device = /dev/ttyUSB1 + #[Require hardware/acoustic-modems/uModem_ip_100.ini] #[Require hardware/acoustic-modems/uModem_ip_101.ini] #[Require hardware/acoustic-modems/uModem_ip_102.ini] +#[Require hardware/acoustic-modems/uModem_ip_103.ini] #[Require hardware/acoustic-modems/seatrac_ip_200.ini] #[Require hardware/acoustic-modems/evologics_ip_1.ini] #[Require hardware/acoustic-modems/evologics_ip_2.ini] #[Require hardware/acoustic-modems/evologics_ip_5.ini] +#[Require hardware/acoustic-modems/evologics_ip_6.ini] +# For UPORTO / PT-NAVY joint exercises +#[Require testing/joint-umodem.ini] +#[Require testing/joint-evologics.ini] diff --git a/etc/manta-sabuvis.ini b/etc/manta-sabuvis.ini new file mode 100644 index 0000000000..744a4a871c --- /dev/null +++ b/etc/manta-sabuvis.ini @@ -0,0 +1,63 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Teixeira # +############################################################################ + +[Require hardware/lctr-a9xx.ini] + +[General] +Vehicle = manta-sabuvis + +[Power.MCBv2] +Drive LCD = true + +[Transports.MobileInternet] +Enabled = Never + +[Sensors.MLBLTracker] +Address Section = Micromodem Addresses - DMSMW +Enabled = Hardware +Entity Label = Acoustic Modem +Serial Port - Device = /dev/uart/1 +Serial Port - Baud Rate = 19200 +GPIO - Transducer Detection = 157 + + +[UserInterfaces.MantaPanel] +System Names = buv-petinga-1, + lauv-seacon-1, + lauv-seacon-2, + lauv-seacon-3, + benthos1, + benthos2, + benthos3, + benthos4, + benthos5, + benthos6 + +[Transports.Logging] +Enabled = Never diff --git a/etc/mariner-01.ini b/etc/mariner-01.ini index 625e9ce8a9..37cd3c3490 100644 --- a/etc/mariner-01.ini +++ b/etc/mariner-01.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,6 +30,7 @@ ############################################################################ [Require uav/ardupilot.ini] +[Require hardware/lctr-rpi/thermalzone.ini] [General] Vehicle = mariner-01 @@ -39,6 +40,25 @@ Altitude Threshold = 1 Vehicle Type = UAV Vehicle Sub-Type = Copter +[Actuators.PWM] +Enabled = Hardware +PinOut 0 = 23 +PinOut 1 = 24 +PinOut 2 = 25 +Operation Mode = Drop +#Gimbal [0, 1], Drop[2], Sample[0, 1, 2] +Entity Label = PWM + +[Maneuver.Multiplexer] +Drop -- Servo Id = 2 +Drop -- Servo Value = 3.14159 +Sample -- Syringe 0 Id = 0 +Sample -- Syringe 1 Id = 1 +Sample -- Syringe 2 Id = 2 +Sample -- Servo Open Value = 3.14159 +Sample -- Servo Close Value = 1.57079 +Sample -- Execution Tolerance = 50 + [Transports.SerialOverTCP] Enabled = Hardware Entity Label = Arduino Serial @@ -61,3 +81,11 @@ Seconds before Waypoint = 1 Copter - Minimum WP switch radius = 1 Convert MSL to WGS84 height = true IPv4 - Address = 10.0.20.125 + +[Maneuver.FollowReference.UAV] +Default Speed = 5 +Default Z = 90 + +[Maneuver.CommsRelay] +Z Value = 90 +Loitering Radius = 0 diff --git a/etc/mariner-02.ini b/etc/mariner-02.ini index 74d7f22693..dfddd93a62 100644 --- a/etc/mariner-02.ini +++ b/etc/mariner-02.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,6 +30,7 @@ ############################################################################ [Require uav/ardupilot.ini] +[Require hardware/lctr-rpi/thermalzone.ini] [General] Vehicle = mariner-02 @@ -45,6 +46,25 @@ Entity Label = Arduino Serial Serial Port - Device = /dev/ttyAMA0 Serial Port - Baud Rate = 57600 +[Actuators.PWM] +Enabled = Hardware +PinOut 0 = 23 +PinOut 1 = 24 +PinOut 2 = 25 +Operation Mode = Drop +#Gimbal [0, 1], Drop[2], Sample[0, 1, 2] +Entity Label = PWM + +[Maneuver.Multiplexer] +Drop -- Servo Id = 2 +Drop -- Servo Value = 3.14159 +Sample -- Syringe 0 Id = 0 +Sample -- Syringe 1 Id = 1 +Sample -- Syringe 2 Id = 2 +Sample -- Servo Open Value = 3.14159 +Sample -- Servo Close Value = 1.57079 +Sample -- Execution Tolerance = 50 + [Control.UAV.Ardupilot/Hardware] Enabled = Hardware Entity Label = Autopilot @@ -60,3 +80,11 @@ Loitering tolerance = 10 Seconds before Waypoint = 1 Copter - Minimum WP switch radius = 1 Convert MSL to WGS84 height = true + +[Maneuver.FollowReference.UAV] +Default Speed = 5 +Default Z = 90 + +[Maneuver.CommsRelay] +Z Value = 90 +Loitering Radius = 0 diff --git a/etc/nest-1.ini b/etc/nest-1.ini index 06e51981bb..2b9531d2a3 100644 --- a/etc/nest-1.ini +++ b/etc/nest-1.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2016 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -35,8 +35,7 @@ System Type = mobilesensor [Sensors.GPS] Enabled = Hardware Entity Label = GPS -Serial Port - Device = /dev/ttyACM0 -Serial Port - Baud Rate = 57600 +IO Port - Device = uart:///dev/ttyACM0:57600 Sentence Order = GPVTG, GPZDA, PUBX Initialization String 0 - Command = $PUBX,40,VTG,0,0,0,1\r\n Initialization String 1 - Command = $PUBX,40,ZDA,0,0,0,1\r\n diff --git a/etc/otter-aux.ini b/etc/otter-aux.ini new file mode 100644 index 0000000000..d0f36652cf --- /dev/null +++ b/etc/otter-aux.ini @@ -0,0 +1,74 @@ +############################################################################ +# Copyright 2007-2020 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Costa # +############################################################################ + +[Include common/imc-addresses.ini] +[Require common/transports.ini] +[Require auv/transports.ini] + +[General] +Vehicle = otter-aux + +[Transports.TCP.Client] +Enabled = Always +Trace - Incoming Messages = true +Entity Label = TCP to Master +Server - Address = 10.0.10.180 +Server - Port = 9999 +Transports = EntityState, + EntityActivationState, + EntityInfo, + EstimatedState, + FuelLevel, + Heartbeat, + LogBookEntry, + LoggingControl, + ManeuverDone, + PathControl, + PowerChannelControl, + PowerChannelState, + Temperature, + VehicleState + +[Transports.FTP] +Enabled = Always +Entity Label = FTP Server +[Transports.TCP.Server/BackSeat] +Enabled = Never + +[Transports.UDP] +Enabled = Never + +[Transports.TCP.Server/SlaveCPU] +Enabled = Never + +[Transports.TCPOnDemand] +Enabled = Never + +[Transports.CommManager] +Enabled = Never diff --git a/etc/otter.ini b/etc/otter.ini new file mode 100644 index 0000000000..d53fd15fd9 --- /dev/null +++ b/etc/otter.ini @@ -0,0 +1,497 @@ +############################################################################ +# Copyright 2007-2020 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Nikolai Lauvås (NTNU, Department of Engineering Cybernetics) # +# Author: Maria Costa (adaptation to LSTS Otter ASV) # +############################################################################ +# Otter ASV configuration file. # +############################################################################ +[require auv/basic.ini] +#[Require hardware/lctr-a6xx/slavecpu.ini] +[Require hardware/lctr-a6xx/limu.ini] +[Require hardware/lctr-a6xx/gsm.ini] +[Require common/imc-addresses.ini] +[Require common/transports.ini] +[Require common/vsim-models.ini] +[Require auv/transports.ini] +[Require auv/plans.ini] +[Require auv/maneuvers.ini] +[Require auv/supervisors.ini] +[Require auv/general.ini] +[Require auv/monitors.ini] + +############################################################################ +# General Parameters. # +############################################################################ + +[General] +Vehicle = otter +Vehicle Type = asv +Speed Conversion -- Actuation = 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 +Speed Conversion -- RPM = 0.0, 120, 240, 360, 480, 600, 720, 840, 960, 1080, 1200 +Speed Conversion -- MPS = 0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5 +Absolute Maximum Depth = 0 +Maximum Absolute Speed = 2.5 +Time Of Arrival Factor = 3.0 +CPU Usage - Maximum = 90 + +[Transports.Announce] +System Type = usv +Ignored Interfaces = eth0, wwan0, eth0:2, wlan0 + +[Transports.TCP.Server/SlaveCPU] +Enabled = Never +Entity Label = TCP to Slave CPU +Announce Service = false +Port = 9999 +Transports = PathControlState, + LoggingControl, + #EstimatedState, + QueryEntityParameters, + SetEntityParameters, + PopEntityParameters, + PushEntityParameters, + EntityParameters, + #PowerOperation, + #PowerChannelState, + QueryEntityInfo, + #SoundSpeed, + VehicleState + +[Transports.UDP] +Transports+ = RelativeHumidity, + WindSpeed + +[Transports.GSM] +Enabled = Never +Debug Level = None +Serial Port - Device = /dev/gsmmodem +Serial Port - Baud Rate = 9600 + + +############################################################################ +# Navigation. # +############################################################################ + +[Navigation.General.GPSNavigation] +Enabled = Always +Entity Label = Navigation +Entity Label - GPS = GPS +Entity Label - IMU = AHRS +Entity Label - Yaw = AHRS + +############################################################################ +# Control. # +############################################################################ + +[Control.ASV.HeadingAndSpeed] +Enabled = Always +Entity Label = Heading & Speed Controller +Maximum Thrust Actuation = 1.0 +Maximum Thrust Differential Actuation = 0.35 +Ramp Actuation Limit = 0.0 +Hardware RPMs Control = true +RPMs at Maximum Thrust = 1200 +RPMs PID Gains = 0, 0, 0 +RPMs Feedforward Gain = 0 +MPS PID Gains = 1.25, 1.0, 0.5 +MPS Integral Limit = 400.0 +MPS Feedforward Gain = 120.0 +Minimum RPM Limit = 250 +Maximum RPM Limit = 1200 +Maximum RPM Acceleration = 300 +Yaw PID Gains = 1.9, 0.0, 0.85 +Maximum Heading Error to Thrust = 30 +Entity Label - Port Motor = Motor - Port +Entity Label - Starboard Motor = Motor - Starboard +Share Saturation = true +Log PID Parcels = true +Debug Level = None + +[Control.Path.VectorField] +Enabled = Always +Entity Label = Path Control +Debug Level = None +Control Frequency = 10 +Along-track -- Monitor = false +Along-track -- Check Period = 20 +Along-track -- Minimum Speed = 0.05 +Along-track -- Minimum Yaw = 2 +Cross-track -- Monitor = false +Cross-track -- Nav. Unc. Factor = 1 +Cross-track -- Distance Limit = 25 +Cross-track -- Time Limit = 20 +Position Jump Threshold = 10.0 +Position Jump Time Factor = 0.5 +ETA Minimum Speed = 0.1 +New Reference Timeout = 5.0 +Course Control = false +Corridor -- Width = 2.0 +Corridor -- Entry Angle = 15 +Extended Control -- Enabled = false +Extended Control -- Controller Gain = 1.0 +Extended Control -- Turn Rate Gain = 1.0 +Bottom Track -- Enabled = false +Bottom Track -- Forward Samples = 7 +Bottom Track -- Safe Pitch = 35.0 +Bottom Track -- Minimum Range = 4.0 +Bottom Track -- Slope Hysteresis = 1.5 +Bottom Track -- Check Trend = false +Bottom Track -- Execution Frequency = 5 +Bottom Track -- Depth Avoidance = true +Bottom Track -- Admissible Altitude = 2.5 + +[Control.ASV.RemoteOperation] +Enabled = Always +Entity Label = Remote Control +Execution Frequency = 10 +Connection Timeout = 2.0 + +############################################################################ +# Maneuvers. # +############################################################################ + +[Maneuver.FollowSystem] +Enabled = Never + +[Maneuver.FollowTrajectory] +Enabled = Never + +[Maneuver.VehicleFormation.SMC] +Enabled = Never + +[Maneuver.FollowReference.AUV] +Enabled = Always +Entity Label = Follow Reference Maneuver +Horizontal Tolerance = 15.0 +Vertical Tolerance = 1.0 +Loitering Radius = 7.5 +Default Speed = 1.2 +Default Speed Units = m/s +Default Z = 0 +Default Z Units = DEPTH + +[Maneuver.RowsCoverage] +Enabled = Always +Entity Label = Rows Coverage Maneuver + +[Maneuver.Multiplexer] +Loiter -- Minimum Radius = 1.0 +StationKeeping -- Minimum Radius = 2.0 +############################################################################ +# Monitors # +############################################################################ + +[Monitors.Entities] +Enabled = Always +Entity Label = Entity Monitor +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Report Timeout = 5 +Transition Time Gap = 4.0 +Maximum Consecutive Transitions = 3 +Default Monitoring = Daemon, + GPS, + Heading & Speed Controller, + Logger, + Navigation, + Operational Limits, + Path Control + +Default Monitoring -- Hardware = Clock, + Motor Controller + +[Monitors.OperationalLimits] +Enabled = Always +Entity Label = Operational Limits +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Execution Frequency = 4 +Hysteresis Threshold - Maximum Depth = 0.3 +Hysteresis Threshold - Minimum Altitude = 0.3 +Minimum Depth to Check Altitude = 0.3 +Initial Setting - Maximum Altitude = -1 +Initial Setting - Maximum Depth = -1 +Initial Setting - Maximum Speed = -1 +Initial Setting - Maximum Vertical Rate = -1 +Initial Setting - Minimum Altitude = -1 +Initial Setting - Minimum Speed = -1 + +[Monitors.Emergency] +Enabled = Always +Entity Label = Emergency Monitor +Execution Frequency = 1.0 +Execution Priority = 10 +Active = false +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Lost Communications Timeout = 300 +Expiration Time - Abort SMS = 30 +Expiration Time - Lost Communications = 30 +SMS Recipient Number = +351912297429 +Transmission Interface = Both +Debug Level = None + +[Monitors.Clock] +Enabled = Hardware + +[Monitors.Medium] +Enabled = Hardware +Vehicle Type = ASV +Vehicle Medium = Water +Entity Label - Medium Sensor = Navigation #Navigation is being used here because Otter doesn't have any medium sensor. + +############################################################################ +# Supervisors # +############################################################################ + +[Supervisors.AUV.LostComms] +Enabled = Never +Entity Label = LostComms Supervisor ASV +Plan Name = lost_comms +Lost Comms Timeout = 30.0 +Debug Level = None + +[Supervisors.AUV.Assist] +Enabled = Never + +#[Supervisors.Delegator/DorisSampler] +#Enabled = Never +#Entity Label = Doris Sampler +#Debug Level = None +#Surrogate Task = Actuators.DorisSampler +#Surrogate Entity = Doris Sampler +#Activation Time = 0 +#Deactivation Time = 0 +#Active = true +#Active - Scope = maneuver +#Active - Visibility = user +#Execution Priority = 10 + +[Supervisors.StratoPIWatchdog] +Enabled = Hardware +Entity Label = Watchdog +Execution Frequency = 0.5 +TimeToggled = 0.25 + +[Supervisors.ClockPPS] +Enabled = Never + +#[Supervisors.SlaveCPU] +#Slave System Name = otter-aux + +############################################################################ +# Hardware. # +############################################################################ + +[Actuators.Torqeedo] +Enabled = Hardware +Execution Frequency = 40 +Debug Level = None +Entity Label = Torqeedo +CAN Port - Device = can0 +Power Channel H_MOT0 - Name = Starboardmotor_pwr +Power Channel H_MOT0 - State = 1 +Power Channel H_MOT1 - Name = Portmotor_pwr +Power Channel H_MOT1 - State = 1 +Power Channel H_VR0 - Name = Signal_Light +Power Channel H_VR0 - State = 1 +Power Channel H_AUX0 - Name = Meteostation_pwr +Power Channel H_AUX0 - State = 1 +Power Channel H_12V2 - Name = Novatel_SBAS_pwr +Power Channel H_12V2 - State = 1 +Power Channel H_12V3 - Name = AHRS_pwr +Power Channel H_12V3 - State = 1 +Motor write divider = 10 +Motor 0 - Label = Motor Port +Motor 1 - Label = Motor Starboard +Rail 0 - Label = Motor Port +Rail 1 - Label = Motor Starboard +Rail 2 - Label = Aux Rail +Rail 3 - Label = 12V Rail +Rail 4 - Label = Main CPU + +# To use with the signal light +# The Identifiers are separated by commas, so more can be implemented easily +# The patterns are given first by on/off(0/1) for each led, followed by how long in millis. The pattern loops/repeats. + +[UserInterfaces.LEDs] +Enabled = Never +Entity Label = Signal Light +Interface = GPIO +Identifiers = 26 +Critical Entities = Logger +Pattern - Normal = 1, 2000, 0, 2000 +Pattern - Fuel Low = 1, 200, 0, 200, 1, 200, 0, 2000 +Pattern - Plan Starting = 1, 200, 0, 2000 +Pattern - Plan Executing = 1, 500, 0, 500 +Pattern - Error = 1, 200, 0, 2000 +Pattern - Fatal Error = 1, 200, 0, 2000 +Pattern - Shutdown = 1, 200, 0, 2000 + +[Sensors.GPS] +Enabled = Hardware +Entity Label = GPS +Serial Port - Device = /dev/ttyUSB3 +Serial Port - Baud Rate = 115200 +Sentence Order = GPHDT, GPROT, GPHDM, GPGGA, GPVTG, GPZDA +Debug Level = None +Initialization String 0 - Command = $JASC,GPGGA,1\r\n +Initialization String 1 - Command = $JASC,GPVTG,1\r\n +Initialization String 2 - Command = $JASC,GPZDA,1\r\n +Initialization String 3 - Command = $JATT,NMEAHE,0\r\n +Initialization String 4 - Command = $JASC,GPROT,1\r\n +Initialization String 5 - Command = $JASC,GPHDT,1\r\n +Initialization String 6 - Command = $JASC,GPHDM,1\r\n +Initialization String 7 - Command = $JSAVE\r\n +Novatel SBAS = true + +[Sensors.V104setup] +Enabled = Never +Entity Label = V104_baud_setup +Serial Port - Device = /dev/ttyUSB0 +Serial Port - Baud Rate = 4800 +Debug Level = Spew +Initialization String 0 - Command = $JBAUD,19200\r\n + +[Sensors.LIMU] +Serial Port - Device = /dev/ttyUSB0 +Hard-Iron Calibration = -0.1180, 0.0084, 0.0 +Last Calibration Time = 2023-03-14 13:44 + +[Sensors.VantagePro2] +Enabled = Never +Entity Label = Weather Station +Serial Port - Device = /dev/ttyUSB1 +Serial Port - Baud Rate = 19200 + +[Sensors.Imagenex852] +Enabled = Hardware +Entity Label = Echo Sounder +Active = false +Active - Scope = idle +Active - Visibility = user +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Serial Port - Device = /dev/COM5 +Sampling Frequency = 5 +Filter Median Elements = 7 +Filter Threshold = 90 +Sonar orientation = 0, 0, 0 +Sonar position = 1, 0, 0 +Sound Speed on Water = 1500 +Use Device at Surface = true +Use Dynamic Sound Speed = false +Range = 30 +Start Gain = 20 +Pulse Length = 0.000030 +Profile Minimum Range = 0 +Data Points = 500 +Filter Enabled = true +Pattern Filter Enabled = true +Pattern Filter Difference = 50 +Automatic Activation = false + +[Sensors.Imagenex837B] +Enabled = Hardware +Entity Label = Multibeam +Active = false +Active - Scope = maneuver +Active - Visibility = user +IPv4 Address = 192.168.0.30 +TCP Port = 4040 +Start Gain = 3 +Absorption = 0.1 +Data Points = 8000 +Switch Delay = 0 +Range = 20 +Auto Gain Mode = true +Connector Pointing Aft = false +Output Data Format = 837 +Power Channel = Multibeam +Activation Time = 5 +Adaptive Range Modifier = true +Adaptive Range Modifier Additive Constant = 0 +Adaptive Range Modifier Multiplicative Constant = 2 +Adaptive Range Modifier Timer = 10 + +############################################################################ +# Simulators. # +############################################################################ + +# Vehicle simulator. +[Simulators.VSIM] +Enabled = Simulation +Entity Label = Simulation Engine +Entity Label - Stream Velocity Source = Stream Velocity Simulator +Execution Frequency = 25 + +[Simulators.StreamVelocity] +Enabled = Simulation +Entity Label = Stream Velocity Simulator +Default Speed North = 0.0 +Default Speed East = 0.0 +Default Speed Down = 0.0 +Stream Velocity Source = Constant +Execution Frequency = 1 + +# GPS simulator. +[Simulators.GPS] +Enabled = Simulation +Execution Frequency = 1 +Entity Label = GPS +Number of Satellites = 8 +HACC = 2 +HDOP = 0.9 +Activation Depth = 0.2 +Report Ground Velocity = false +Report Yaw = true +Initial Position = 41.1850, -8.7062 + +# Port motor. +[Simulators.Motor/Port] +Enabled = Simulation +Entity Label = Motor - Port +Execution Frequency = 20 +Thruster Act to RPM Factor = 100, 1200.0 +Thruster Id = 0 + +# Starboard motor. +[Simulators.Motor/Starboard] +Enabled = Simulation +Entity Label = Motor - Starboard +Execution Frequency = 20 +Thruster Act to RPM Factor = 100, 1200.0 +Thruster Id = 1 + diff --git a/etc/sedona.ini b/etc/sedona.ini index 239acdeb52..0e5886a0ba 100644 --- a/etc/sedona.ini +++ b/etc/sedona.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/simulation/bathymetry-apdl.ini b/etc/simulation/bathymetry-apdl.ini index dc176db816..cb35fccf35 100644 --- a/etc/simulation/bathymetry-apdl.ini +++ b/etc/simulation/bathymetry-apdl.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/simulation/uav.ini b/etc/simulation/uav.ini index b200aeeecc..71d3dbc709 100644 --- a/etc/simulation/uav.ini +++ b/etc/simulation/uav.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/ais.ini b/etc/testing/ais.ini index 060e71cf4c..9adc10c945 100644 --- a/etc/testing/ais.ini +++ b/etc/testing/ais.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -41,10 +41,9 @@ System Type = mobilesensor [Sensors.AIS] Enabled = Always Entity Label = AIS Receiver -# Serial Port - Device = tcp://10.0.100.1:8080 -# Serial Port - Device = /dev/ttyUSB0 -Serial Port - Device = tcp://10.0.100.2:5001 -Serial Port - Baud Rate = 38400 +# IO Port - Device = tcp://10.0.100.1:8080 +# IO Port - Device = uart:///dev/ttyUSB0:38400 +IO Port - Device = tcp://10.0.100.2:5001 [Transports.UDP] Enabled = Always diff --git a/etc/testing/docking.ini b/etc/testing/docking.ini index 2e3c7b74ac..b16c4da729 100644 --- a/etc/testing/docking.ini +++ b/etc/testing/docking.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/dvl-calibration.ini b/etc/testing/dvl-calibration.ini new file mode 100644 index 0000000000..b94d3e105d --- /dev/null +++ b/etc/testing/dvl-calibration.ini @@ -0,0 +1,71 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# DVL Calibration configurations for systems with iXblue PhinsC3 INS # +############################################################################ + +[Sensors.GPS] +Enabled = Never + +# GPS (using serial over TCP). +[Transports.SerialOverTCP/GPS] +Enabled = Hardware +Entity Label = GPS to TCP +Execution Priority = 10 +Debug Level = None +Serial Port - Device = /dev/ttyACM2 +Serial Port - Baud Rate = 57600 +TCP - Port = 8888 +Activation Time = 5 +Deactivation Time = 5 + +[Sensors.OSGNSS] +Enabled = Hardware +Entity Label = GPS +Activation Time = 0 +Deactivation Time = 0 +Debug Level = None +Execution Priority = 10 +Input Timeout = 4.0 +Serial Port - Device = tcp://10.0.10.30:8888 +Power Channel - Names = GPS, Communications Board +RTK - Role = Rover +RTK - IPv4 Address = 0.0.0.0 +RTK - Port = 29000 +Sentence Order = GNVTG, GNZDA, PUBX +Initialization String 0 - Command = $PUBX,40,VTG,0,1,0,0,0,0\r\n +Initialization String 1 - Command = $PUBX,40,ZDA,0,1,0,0,0,0\r\n +Initialization String 2 - Command = $PUBX,40,00,0,1,0,0,0,0\r\n +Initialization String 3 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 4 - Command = $PUBX,40,GSA,0,0,0,0,0,0\r\n +Initialization String 5 - Command = $PUBX,40,GSV,0,0,0,0,0,0\r\n +Initialization String 6 - Command = $PUBX,40,RMC,0,1,0,0,0,0\r\n +Initialization String 7 - Command = $PUBX,40,GGA,0,1,0,0,0,0\r\n +Initialization String 8 - Command = $PUBX,40,GLL,0,1,0,0,0,0\r\n +Initialization String 9 - Command = $PUBX,40,GST,0,1,0,0,0,0\r\n + diff --git a/etc/testing/joint-evologics.ini b/etc/testing/joint-evologics.ini new file mode 100644 index 0000000000..975aacdc32 --- /dev/null +++ b/etc/testing/joint-evologics.ini @@ -0,0 +1,57 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Evologics Addresses] +lauv-noptilus-1 = 1 +lauv-noptilus-2 = 2 +lauv-noptilus-3 = 3 +lauv-xtreme-2 = 4 +manta-11 = 5 +manta-rugged = 6 +manta-1 = 7 +manta-2 = 8 +manta-3 = 9 +lauv-seacon-3 = 10 +manta-rugged-2 = 11 +manta-12 = 12 +manta-21 = 13 +broadcast = 14 + +[Transports.Evologics] +Address Section = Evologics Addresses + +[Transports.UAN] +Address Section = Evologics Addresses + +[Transports.CommManager] +Acoustic Address Section = Evologics Addresses + +[Transports.Evologics/Simulator] +Address Section = Evologics Addresses + +[UserInterfaces.MantaPanel] +Sections of System Addresses = Evologics Addresses diff --git a/etc/testing/joint-umodem.ini b/etc/testing/joint-umodem.ini new file mode 100644 index 0000000000..edcebae1ae --- /dev/null +++ b/etc/testing/joint-umodem.ini @@ -0,0 +1,49 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ + +[Micromodem Addresses] +lauv-xplore-1 = 1 +lauv-xplore-2 = 2 +manta-rugged = 3 +manta-rugged-2 = 4 +manta-2 = 5 +manta-11 = 6 +manta-12 = 7 +manta-21 = 8 +lauv-seacon-1 = 9 +lauv-seacon-2 = 10 +manta-1 = 12 +manta-3 = 13 + +[Sensors.MLBL] +Address Section = Micromodem Addresses + +[Sensors.MLBLTracker] +Address Section = Micromodem Addresses + +[UserInterfaces.MantaPanel] +Sections of System Addresses = Micromodem Addresses diff --git a/etc/testing/piccolo.ini b/etc/testing/piccolo.ini index b6891c18f3..570470de98 100644 --- a/etc/testing/piccolo.ini +++ b/etc/testing/piccolo.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/compass_calibration.ini b/etc/testing/plans/compass_calibration.ini index 11ad49add8..8f3add7a9b 100644 --- a/etc/testing/plans/compass_calibration.ini +++ b/etc/testing/plans/compass_calibration.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/elevator.ini b/etc/testing/plans/elevator.ini index 02f8ecdded..0759693e4a 100644 --- a/etc/testing/plans/elevator.ini +++ b/etc/testing/plans/elevator.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/followpath.ini b/etc/testing/plans/followpath.ini index f47e7a8358..928d421c37 100644 --- a/etc/testing/plans/followpath.ini +++ b/etc/testing/plans/followpath.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/loiter.ini b/etc/testing/plans/loiter.ini index 0ef7ac1df8..0c1b5ce74e 100644 --- a/etc/testing/plans/loiter.ini +++ b/etc/testing/plans/loiter.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/mpsplan.ini b/etc/testing/plans/mpsplan.ini index 13f5e41d37..318b249899 100644 --- a/etc/testing/plans/mpsplan.ini +++ b/etc/testing/plans/mpsplan.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/popup.ini b/etc/testing/plans/popup.ini index a7342c6a45..a01b81bfcb 100644 --- a/etc/testing/plans/popup.ini +++ b/etc/testing/plans/popup.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/rows.ini b/etc/testing/plans/rows.ini index 5a612ab1a9..1876d6c1c5 100644 --- a/etc/testing/plans/rows.ini +++ b/etc/testing/plans/rows.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/station_keeping.ini b/etc/testing/plans/station_keeping.ini index b6be1e9b32..2160ad8e0b 100644 --- a/etc/testing/plans/station_keeping.ini +++ b/etc/testing/plans/station_keeping.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/straight_line.ini b/etc/testing/plans/straight_line.ini index 23a0085b67..2a6a013b4f 100644 --- a/etc/testing/plans/straight_line.ini +++ b/etc/testing/plans/straight_line.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/testplan.ini b/etc/testing/plans/testplan.ini index e4b74e795c..b6942015c3 100644 --- a/etc/testing/plans/testplan.ini +++ b/etc/testing/plans/testplan.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/plans/yoyo.ini b/etc/testing/plans/yoyo.ini index 1338aa7bf1..0c5e90d6a1 100644 --- a/etc/testing/plans/yoyo.ini +++ b/etc/testing/plans/yoyo.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/testing/replays/assist.ini b/etc/testing/replays/assist.ini index e2690df53c..3d3abea329 100644 --- a/etc/testing/replays/assist.ini +++ b/etc/testing/replays/assist.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -42,6 +42,7 @@ Vehicle = lauv-noptilus-1 [Transports.Replay] Enabled = Always Entity Label = Replay +Time Multiplier = 1.0 # NOTE: Add entity names that replay should consider/report on if necessary Entities = Batteries, Power Supply diff --git a/etc/testing/replays/btrack-replay.ini b/etc/testing/replays/btrack-replay.ini index c8e9f1c237..683b7cbd71 100644 --- a/etc/testing/replays/btrack-replay.ini +++ b/etc/testing/replays/btrack-replay.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -87,6 +87,7 @@ Log PID Parcels = true [Transports.Replay] Enabled = Always Entity Label = Replay +Time Multiplier = 1.0 # NOTE: Add entity names that replay should consider/report on if necessary Entities = Echo Sounder diff --git a/etc/testing/replays/control-replay.ini b/etc/testing/replays/control-replay.ini index 21cb8a723a..1718abde5d 100644 --- a/etc/testing/replays/control-replay.ini +++ b/etc/testing/replays/control-replay.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -92,6 +92,7 @@ Maximum Increase = 50 [Transports.Replay] Enabled = Always Entity Label = Replay +Time Multiplier = 1.0 # NOTE: Add entity names that replay should consider/report on if necessary Entities = SCRT diff --git a/etc/testing/replays/fuel-replay.ini b/etc/testing/replays/fuel-replay.ini index 129eba044c..7011a706d9 100644 --- a/etc/testing/replays/fuel-replay.ini +++ b/etc/testing/replays/fuel-replay.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -42,6 +42,7 @@ Vehicle = lauv-seacon-2 [Transports.Replay] Enabled = Always Entity Label = Replay +Time Multiplier = 1.0 # NOTE: Add entity names that replay should consider/report on if necessary Entities = Batteries, Power Supply diff --git a/etc/testing/replays/monitors-entities-replay.ini b/etc/testing/replays/monitors-entities-replay.ini index 9eeb655491..864fb28651 100644 --- a/etc/testing/replays/monitors-entities-replay.ini +++ b/etc/testing/replays/monitors-entities-replay.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -41,6 +41,7 @@ Vehicle = lauv-seacon-1 [Transports.Replay] Enabled = Always Entity Label = Replay +Time Multiplier = 1.0 # NOTE: Add entity names that replay should consider/report on if necessary Entities = DVL diff --git a/etc/testing/replays/servomonitor-replay.ini b/etc/testing/replays/servomonitor-replay.ini index 587b7fac77..05649a0eed 100644 --- a/etc/testing/replays/servomonitor-replay.ini +++ b/etc/testing/replays/servomonitor-replay.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -67,6 +67,7 @@ Entity Label - Current 3 = Servo Controller 3 [Transports.Replay] Enabled = Always Entity Label = Replay +Time Multiplier = 1.0 # NOTE: Add entity names that replay should consider/report on if necessary Entities = Allocator, diff --git a/etc/testing/replays/sgnav-replay.ini b/etc/testing/replays/sgnav-replay.ini index fcaa0f0ca6..b7b170471f 100644 --- a/etc/testing/replays/sgnav-replay.ini +++ b/etc/testing/replays/sgnav-replay.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -47,10 +47,13 @@ Distance Between GPS and CG = 0.25 [Transports.Replay] Enabled = Always Entity Label = Replay +Time Multiplier = 1.0 +Seconds to skip = 0.0 # NOTE: Add entity names that replay should consider Entities = Depth Sensor, AHRS, DVL, + DVL Filtered, DVL Beam 0, DVL Beam 1, DVL Beam 2, @@ -88,4 +91,4 @@ Replay Messages = AngularVelocity, # NOTE: Optionally set the starting replay file # Otherwise use: 'sendmsg 127.0.0.1 6002 ReplayControl 0 /Data.lsf' -# Load At Start = +Load At Start = /home/luis/workspace/logs/Navigation/OGs/2021-04-23_apdl/logs/lauv-noptilus-3/20210428/142022_navigation_test_fig8/Data.lsf diff --git a/etc/testing/tase.ini b/etc/testing/tase.ini index b6110ba378..b6b5c3c1b1 100644 --- a/etc/testing/tase.ini +++ b/etc/testing/tase.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/titan.ini b/etc/titan.ini new file mode 100644 index 0000000000..e727b04144 --- /dev/null +++ b/etc/titan.ini @@ -0,0 +1,79 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Manuel Ribeiro # +############################################################################ +# Titan OctaQuadcopter configuration file # +############################################################################ + +[Require uav/ardupilot.ini] +[Require hardware/lctr-rpi/cpmbv2.ini] +[Require hardware/lctr-rpi/thermalzone.ini] +[Require hardware/radio.ini] + +[General] +Vehicle = titan + +[Monitors.Medium] +Altitude Threshold = 1 +Vehicle Type = UAV +Vehicle Sub-Type = Copter + +[Transports.SerialOverTCP] +Enabled = Hardware +Entity Label = Arduino Serial +Serial Port - Device = /dev/ttyAMA0 +Serial Port - Baud Rate = 57600 + +[Control.UAV.Ardupilot/Hardware] +Enabled = Hardware +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 9999 +Communications Timeout = 10 +Ardupilot Tracker = True +Power Module = True +Telemetry Rate = 25 +Default altitude = 10.0 +Default loiter radius = -150.0 +Loitering tolerance = 10 +Seconds before Waypoint = 1 +Copter - Minimum WP switch radius = 1 +Convert MSL to WGS84 height = true +IPv4 - Address = 10.0.20.150 + +[Transports.Radio] +Active = false +Enable telemetry report = true +Mode of communication = Client +Serial Port - Device = /dev/ttyUSB2 +Enable UAV high speed report = true + +[Power.CPMBv2] +ADC VDelta Offset = 0.035 + +## CDC3 Exercise ## +#[Require development/cdc3/cdc3-titan.ini] diff --git a/etc/uav/ardupilot.ini b/etc/uav/ardupilot.ini index 27a99a886d..e20dfc6151 100644 --- a/etc/uav/ardupilot.ini +++ b/etc/uav/ardupilot.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/basic.ini b/etc/uav/basic.ini index 76890eca17..3530293f21 100644 --- a/etc/uav/basic.ini +++ b/etc/uav/basic.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/cameras.ini b/etc/uav/cameras.ini index dfdf70863d..7d86d499b0 100644 --- a/etc/uav/cameras.ini +++ b/etc/uav/cameras.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/control.ini b/etc/uav/control.ini index d4bd36d86a..864ef0cf85 100644 --- a/etc/uav/control.ini +++ b/etc/uav/control.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/dms.ini b/etc/uav/dms.ini new file mode 100644 index 0000000000..eae0c9d696 --- /dev/null +++ b/etc/uav/dms.ini @@ -0,0 +1,57 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Faculdade de Engenharia da # +# Universidade do Porto. For licensing terms, conditions, and further # +# information contact lsts@fe.up.pt. # +# # +# Modified European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the Modified # +# EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# https://github.com/LSTS/dune/blob/master/LICENCE.md and # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Pedro Gonçalves # +############################################################################ + +[Sensors.DMS] +Enabled = Hardware +Entity Label = DMS +Debug Level = None +Serial Port - Device = /dev/ttyUSB1 +Serial Port - Baud Rate = 57600 +Serial Port - TimeOut = 2.0 +ADC Reads - Entity Label = DMS +ADC Channels = 16 +#Min: 0, Max = 4.99 (volt) - Sensor 52 +DMS CH1 Baseline = 0.87 +DMS CH2 Baseline = 0.40 +DMS CH3 Baseline = 0.33 +DMS CH4 Baseline = 0.49 +DMS CH5 Baseline = 0.13 +DMS CH6 Baseline = 0.23 +DMS CH7 Baseline = 0.20 +DMS CH8 Baseline = 0.17 +DMS CH9 Baseline = 0.30 +DMS CH10 Baseline = 0.35 +DMS CH11 Baseline = 0.32 +DMS CH12 Baseline = 0.17 +DMS CH13 Baseline = 0.17 +DMS CH14 Baseline = 0.14 +DMS CH15 Baseline = 0.47 +DMS CH16 Baseline = 0.16 +Scale Factor Positive = 3.0 +Number Samples per s = 16 diff --git a/etc/uav/formation.ini b/etc/uav/formation.ini index e86537a30f..ac9a3cf1cd 100644 --- a/etc/uav/formation.ini +++ b/etc/uav/formation.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/maneuvers.ini b/etc/uav/maneuvers.ini index 15f036a7c8..d36a3e194b 100644 --- a/etc/uav/maneuvers.ini +++ b/etc/uav/maneuvers.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -49,4 +49,5 @@ Default Z = 150 Enabled = Always Entity Label = Communications Relay Maneuver Loitering Radius = 100 -Altitude = 150 \ No newline at end of file +Z Value = 100 +Z Mode = Height diff --git a/etc/uav/monitors.ini b/etc/uav/monitors.ini index 3799c26326..db704ad2fb 100644 --- a/etc/uav/monitors.ini +++ b/etc/uav/monitors.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/piccolo-addresses.ini b/etc/uav/piccolo-addresses.ini index d60b7b86ee..44a2387fc7 100644 --- a/etc/uav/piccolo-addresses.ini +++ b/etc/uav/piccolo-addresses.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/px4_test.ini b/etc/uav/px4_test.ini new file mode 100644 index 0000000000..c92b714a5e --- /dev/null +++ b/etc/uav/px4_test.ini @@ -0,0 +1,64 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Trent Lukaczyk # +############################################################################ +# PX4 Autopilot configuration file # +############################################################################ + +[Require ../common/imc-addresses.ini] +[Require ../common/transports.ini] +[Require transports.ini] + +[General] +Vehicle = vtol-01 + +[Profiles] +PX4-SIL = PX4 Software Simulation + +[Transports.SerialOverTCP] +Enabled = Hardware +Entity Label = UART Serial +Serial Port - Device = /dev/ttyACM0 +Serial Port - Baud Rate = 921600 + +[Control.UAV.PX4/Hardware] +Enabled = Hardware +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 9999 +Communications Timeout = 10 +Debug Level = None + +[Control.UAV.PX4/PX4-SIL] +Enabled = PX4-SIL +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 11345 +UDP - Address = 127.0.0.1 +UDP - Listen Port = 14540 +UDP - Port = 14557 +Communications Timeout = 10 +Debug Level = None +Use TCP (or UDP) = false diff --git a/etc/uav/seatrac.ini b/etc/uav/seatrac.ini new file mode 100644 index 0000000000..f45c43166a --- /dev/null +++ b/etc/uav/seatrac.ini @@ -0,0 +1,42 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: João Teixeira # +############################################################################ + +[Require ../hardware/lctr-a6xx/seatrac.ini] + +[Transports.UAN] +Enabled = Hardware +Entity Label = Acoustic Access Controller +USBL Node -- Period = 15 +USBL Node -- Enabled = false +USBL Node -- Absolute Fix = false +USBL Node -- Quick, No Range = false + +[Transports.Seatrac] +Enabled = Hardware +Serial Port - Device = /dev/ttyUSB1 +AHRS Mode = false +Pressure Sensor Mode = true diff --git a/etc/uav/simulator.ini b/etc/uav/simulator.ini index 0734b8bda6..f819f81c90 100644 --- a/etc/uav/simulator.ini +++ b/etc/uav/simulator.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/supervisors.ini b/etc/uav/supervisors.ini index 68832062a5..f369a407bf 100644 --- a/etc/uav/supervisors.ini +++ b/etc/uav/supervisors.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/uav/transports.ini b/etc/uav/transports.ini index de0d8cdce4..b94b0d541e 100644 --- a/etc/uav/transports.ini +++ b/etc/uav/transports.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -48,14 +48,20 @@ Enabled = Always Entity Label = Logger Flush Interval = 5 LSF Compression Method = gzip -Transports = Acceleration, +Transports = Abort, + Acceleration, + AcousticLink, + AcousticOperation, AngularVelocity, Announce, ApmStatus, + ArmingState, AutopilotMode, ControlLoops, + CommSystemsQuery, CpuUsage, Current, + Depth, DesiredHeading, DesiredPath, DesiredRoll, @@ -63,6 +69,9 @@ Transports = Acceleration, DesiredVerticalRate, DesiredZ, DevCalibrationControl, + DevDataText, + DmsDetection, + EulerAngles, EntityList, EntityState, EstimatedState, @@ -89,37 +98,66 @@ Transports = Acceleration, PowerChannelControl, Pressure, Reference, + ReportControl, Rpm, RSSI, + ServoPosition, SetControlSurfaceDeflection, + SetServoPosition, SetThrusterActuation, SimulatedState, + SoundSpeed, StopManeuver, StorageUsage, + TelemetryMsg, Temperature, + TextMessage, + Throttle, + TransmissionRequest, + TransmissionStatus, + TransportBindings, TrueSpeed, TrexObservation, TrexPlan, TrexToken, TrueSpeed, + UamRxFrame, + UamTxFrame, + UamTxStatus, + UamRxRange, + UsblAnglesExtended, + UsblPositionExtended, + UsblFixExtended, + UsblModem, + UsblConfig, VehicleCommand, VehicleMedium, VehicleState, - Voltage + Voltage, + VtolState [Transports.UDP] Enabled = Always Entity Label = UDP -Transports = Acceleration, +Transports = Abort, + Acceleration, AngularVelocity, + AcousticOperation, + AcousticSystemsQuery, + AcousticSystems, ApmStatus, + ArmingState, AutopilotMode, + CommSystemsQuery, CpuUsage, Current, + Depth, + Distance, DesiredPath, DesiredRoll, DesiredSpeed, DesiredVerticalRate, DesiredZ, + DmsDetection, EntityList, EntityParameters, EntityState, @@ -153,19 +191,38 @@ Transports = Acceleration, Rpm, RSSI, SaveEntityParameters, - ServoPosition, + ServoPosition, SetEntityParameters, SetServoPosition, SimulatedState, StorageUsage, Target, + TelemetryMsg, Temperature, + Throttle, + TransmissionRequest, + TransmissionStatus, TrexOperation, TrueSpeed, + TextMessage, + UamTxFrame, + UamRxFrame, + UamTxStatus, + UamRxRange, + UsblAnglesExtended, + UsblPositionExtended, + UsblFixExtended, + UsblModem, + UsblConfig, VehicleMedium, VehicleState, - Voltage -Filtered Entities = CpuUsage:Daemon + Voltage, + VtolState +Filtered Entities = CpuUsage:Daemon, + Voltage:Autopilot+DMS CH1+DMS CH2+DMS CH3+ + DMS CH4+DMS CH5+DMS CH6+DMS CH7+DMS CH8+DMS CH9+ + DMS CH10+DMS CH11+DMS CH12+DMS CH13+DMS CH14+DMS CH15+ + DMS CH16 Local Port = 6002 Print Incoming Messages = 0 Print Outgoing Messages = 0 @@ -202,3 +259,15 @@ Entity Label = Cache [Transports.LogBook] Enabled = Always Entity Label = Log Book + +[Transports.CommManager] +Enabled = Always +Entity Label = Communications Manager +Iridium Reports Period = 600 +Iridium - Entity Label = Iridium Modem +GSM - Entity Label = GSM + +[Transports.TCPOnDemand] +Enabled = Always +Entity Label = TCP On Demand + diff --git a/etc/uav/trex.ini b/etc/uav/trex.ini index 09cbc41ea7..73112931c2 100644 --- a/etc/uav/trex.ini +++ b/etc/uav/trex.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/vtol-01.ini b/etc/vtol-01.ini new file mode 100644 index 0000000000..104d304e79 --- /dev/null +++ b/etc/vtol-01.ini @@ -0,0 +1,76 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Trent Lukaczyk # +# Author: Maria Costa # +############################################################################ +# PX4 Autopilot configuration file # +############################################################################ + +[Require uav/basic.ini] +#[Require uav/dms.ini] + +[General] +Vehicle = vtol-01 + +[Profiles] +PX4-SIL = PX4 Software Simulation + +[Transports.SerialOverTCP] +Enabled = Hardware +Entity Label = UART Serial +Serial Port - Device = /dev/serial1 +Serial Port - Baud Rate = 115200 + +[Control.UAV.PX4/Hardware] +Enabled = Hardware +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 9999 +Communications Timeout = 10 +Use TCP (or UDP) = true +IPv4 - Address = 10.0.20.160 +Debug Level = Debug + +[Control.UAV.PX4/PX4-SIL] +Enabled = PX4-SIL +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 11345 +UDP - Address = 127.0.0.1 +UDP - Listen Port = 14540 +UDP - Port = 14557 +Communications Timeout = 10 +Debug Level = None +Use TCP (or UDP) = false +Debug Level = Debug + +[Monitors.Clock] +Enabled = Hardware, PX4-SIL +Entity Label = Clock + +[Monitors.Medium] +Altitude Threshold = 1 +Vehicle Type = UAV +Vehicle Sub-Type = Copter diff --git a/etc/vtol-02.ini b/etc/vtol-02.ini new file mode 100644 index 0000000000..27ccd6deeb --- /dev/null +++ b/etc/vtol-02.ini @@ -0,0 +1,83 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# PX4 Autopilot configuration file # +############################################################################ + +[Require uav/basic.ini] +#[Require uav/dms.ini] +[Require hardware/radio.ini] + +[General] +Vehicle = vtol-02 + +[Profiles] +PX4-SIL = PX4 Software Simulation + +[Transports.SerialOverTCP] +Enabled = Hardware +Entity Label = UART Serial +Serial Port - Device = /dev/serial1 +Serial Port - Baud Rate = 57600 + +[Control.UAV.PX4/Hardware] +Enabled = Hardware +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 9999 +Communications Timeout = 10 +Use TCP (or UDP) = true +IPv4 - Address = 10.0.20.165 +Debug Level = Debug + +[Control.UAV.PX4/PX4-SIL] +Enabled = PX4-SIL +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 11345 +UDP - Address = 127.0.0.1 +UDP - Listen Port = 14540 +UDP - Port = 14557 +Communications Timeout = 10 +Debug Level = None +Use TCP (or UDP) = false +Debug Level = Debug + +[Monitors.Clock] +Enabled = Hardware, PX4-SIL +Entity Label = Clock + +[Monitors.Medium] +Altitude Threshold = 1 +Vehicle Type = UAV +Vehicle Sub-Type = Copter + +[Transports.Radio] +Active = false +Enable telemetry report = true +Mode of communication = Client +Serial Port - Device = /dev/ttyUSB0 +Enable UAV high speed report = true diff --git a/etc/vtol-03.ini b/etc/vtol-03.ini new file mode 100644 index 0000000000..44424ee2e5 --- /dev/null +++ b/etc/vtol-03.ini @@ -0,0 +1,85 @@ +############################################################################ +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # +# Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # +############################################################################ +# This file is part of DUNE: Unified Navigation Environment. # +# # +# Commercial Licence Usage # +# Licencees holding valid commercial DUNE licences may use this file in # +# accordance with the commercial licence agreement provided with the # +# Software or, alternatively, in accordance with the terms contained in a # +# written agreement between you and Universidade do Porto. For licensing # +# terms, conditions, and further information contact lsts@fe.up.pt. # +# # +# European Union Public Licence - EUPL v.1.1 Usage # +# Alternatively, this file may be used under the terms of the EUPL, # +# Version 1.1 only (the "Licence"), appearing in the file LICENCE.md # +# included in the packaging of this file. You may not use this work # +# except in compliance with the Licence. Unless required by applicable # +# law or agreed to in writing, software distributed under the Licence is # +# distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF # +# ANY KIND, either express or implied. See the Licence for the specific # +# language governing permissions and limitations at # +# http://ec.europa.eu/idabc/eupl.html. # +############################################################################ +# Author: Maria Costa # +############################################################################ +# PX4 Autopilot configuration file # +############################################################################ + +[Require uav/basic.ini] +#[Require uav/dms.ini] +#[Require hardware/radio.ini] + +[General] +Vehicle = vtol-03 + +[Profiles] +PX4-SIL = PX4 Software Simulation + +[Transports.SerialOverTCP] +Enabled = Hardware +Entity Label = UART Serial +Serial Port - Device = /dev/serial1 +Serial Port - Baud Rate = 115200 + +[Control.UAV.PX4/Hardware] +Enabled = Hardware +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 9999 +Communications Timeout = 10 +Use TCP (or UDP) = true +IPv4 - Address = 10.0.20.170 +Debug Level = Debug + +[Control.UAV.PX4/PX4-SIL] +Enabled = PX4-SIL +Entity Label = Autopilot +TCP - Address = 127.0.0.1 +TCP - Port = 11345 +UDP - Address = 127.0.0.1 +UDP - Listen Port = 14540 +UDP - Port = 14557 +Communications Timeout = 10 +Debug Level = None +Use TCP (or UDP) = false +Send Full Plan to Autopilot = true +Debug Level = Debug + +[Monitors.Clock] +Enabled = Hardware, PX4-SIL +Entity Label = Clock + +[Monitors.Medium] +Altitude Threshold = 1 +Vehicle Type = UAV +Vehicle Sub-Type = Copter + +[Transports.Radio] +Active = true +Enable telemetry report = true +Mode of communication = Client +Serial Port - Device = /dev/ttyUSB0 +Enable UAV high speed report = true + diff --git a/etc/wmm/wmm.cof b/etc/wmm/wmm.cof index f4d2f409e8..7940efb460 100644 --- a/etc/wmm/wmm.cof +++ b/etc/wmm/wmm.cof @@ -1,93 +1,93 @@ - 2015.0 WMM-2015 12/15/2014 - 1 0 -29438.5 0.0 10.7 0.0 - 1 1 -1501.1 4796.2 17.9 -26.8 - 2 0 -2445.3 0.0 -8.6 0.0 - 2 1 3012.5 -2845.6 -3.3 -27.1 - 2 2 1676.6 -642.0 2.4 -13.3 - 3 0 1351.1 0.0 3.1 0.0 - 3 1 -2352.3 -115.3 -6.2 8.4 - 3 2 1225.6 245.0 -0.4 -0.4 - 3 3 581.9 -538.3 -10.4 2.3 - 4 0 907.2 0.0 -0.4 0.0 - 4 1 813.7 283.4 0.8 -0.6 - 4 2 120.3 -188.6 -9.2 5.3 - 4 3 -335.0 180.9 4.0 3.0 - 4 4 70.3 -329.5 -4.2 -5.3 - 5 0 -232.6 0.0 -0.2 0.0 - 5 1 360.1 47.4 0.1 0.4 - 5 2 192.4 196.9 -1.4 1.6 - 5 3 -141.0 -119.4 0.0 -1.1 - 5 4 -157.4 16.1 1.3 3.3 - 5 5 4.3 100.1 3.8 0.1 - 6 0 69.5 0.0 -0.5 0.0 - 6 1 67.4 -20.7 -0.2 0.0 - 6 2 72.8 33.2 -0.6 -2.2 - 6 3 -129.8 58.8 2.4 -0.7 - 6 4 -29.0 -66.5 -1.1 0.1 - 6 5 13.2 7.3 0.3 1.0 - 6 6 -70.9 62.5 1.5 1.3 - 7 0 81.6 0.0 0.2 0.0 - 7 1 -76.1 -54.1 -0.2 0.7 - 7 2 -6.8 -19.4 -0.4 0.5 - 7 3 51.9 5.6 1.3 -0.2 - 7 4 15.0 24.4 0.2 -0.1 - 7 5 9.3 3.3 -0.4 -0.7 - 7 6 -2.8 -27.5 -0.9 0.1 - 7 7 6.7 -2.3 0.3 0.1 - 8 0 24.0 0.0 0.0 0.0 - 8 1 8.6 10.2 0.1 -0.3 - 8 2 -16.9 -18.1 -0.5 0.3 - 8 3 -3.2 13.2 0.5 0.3 - 8 4 -20.6 -14.6 -0.2 0.6 - 8 5 13.3 16.2 0.4 -0.1 - 8 6 11.7 5.7 0.2 -0.2 - 8 7 -16.0 -9.1 -0.4 0.3 - 8 8 -2.0 2.2 0.3 0.0 - 9 0 5.4 0.0 0.0 0.0 - 9 1 8.8 -21.6 -0.1 -0.2 - 9 2 3.1 10.8 -0.1 -0.1 - 9 3 -3.1 11.7 0.4 -0.2 - 9 4 0.6 -6.8 -0.5 0.1 - 9 5 -13.3 -6.9 -0.2 0.1 - 9 6 -0.1 7.8 0.1 0.0 - 9 7 8.7 1.0 0.0 -0.2 - 9 8 -9.1 -3.9 -0.2 0.4 - 9 9 -10.5 8.5 -0.1 0.3 - 10 0 -1.9 0.0 0.0 0.0 - 10 1 -6.5 3.3 0.0 0.1 - 10 2 0.2 -0.3 -0.1 -0.1 - 10 3 0.6 4.6 0.3 0.0 - 10 4 -0.6 4.4 -0.1 0.0 - 10 5 1.7 -7.9 -0.1 -0.2 - 10 6 -0.7 -0.6 -0.1 0.1 - 10 7 2.1 -4.1 0.0 -0.1 - 10 8 2.3 -2.8 -0.2 -0.2 - 10 9 -1.8 -1.1 -0.1 0.1 - 10 10 -3.6 -8.7 -0.2 -0.1 - 11 0 3.1 0.0 0.0 0.0 - 11 1 -1.5 -0.1 0.0 0.0 - 11 2 -2.3 2.1 -0.1 0.1 - 11 3 2.1 -0.7 0.1 0.0 - 11 4 -0.9 -1.1 0.0 0.1 - 11 5 0.6 0.7 0.0 0.0 - 11 6 -0.7 -0.2 0.0 0.0 - 11 7 0.2 -2.1 0.0 0.1 - 11 8 1.7 -1.5 0.0 0.0 - 11 9 -0.2 -2.5 0.0 -0.1 - 11 10 0.4 -2.0 -0.1 0.0 - 11 11 3.5 -2.3 -0.1 -0.1 - 12 0 -2.0 0.0 0.1 0.0 - 12 1 -0.3 -1.0 0.0 0.0 - 12 2 0.4 0.5 0.0 0.0 - 12 3 1.3 1.8 0.1 -0.1 - 12 4 -0.9 -2.2 -0.1 0.0 - 12 5 0.9 0.3 0.0 0.0 - 12 6 0.1 0.7 0.1 0.0 - 12 7 0.5 -0.1 0.0 0.0 - 12 8 -0.4 0.3 0.0 0.0 - 12 9 -0.4 0.2 0.0 0.0 - 12 10 0.2 -0.9 0.0 0.0 - 12 11 -0.9 -0.2 0.0 0.0 - 12 12 0.0 0.7 0.0 0.0 -999999999999999999999999999999999999999999999999 -999999999999999999999999999999999999999999999999 + 2020.0 WMM-2020 12/10/2019 + 1 0 -29404.5 0.0 6.7 0.0 + 1 1 -1450.7 4652.9 7.7 -25.1 + 2 0 -2500.0 0.0 -11.5 0.0 + 2 1 2982.0 -2991.6 -7.1 -30.2 + 2 2 1676.8 -734.8 -2.2 -23.9 + 3 0 1363.9 0.0 2.8 0.0 + 3 1 -2381.0 -82.2 -6.2 5.7 + 3 2 1236.2 241.8 3.4 -1.0 + 3 3 525.7 -542.9 -12.2 1.1 + 4 0 903.1 0.0 -1.1 0.0 + 4 1 809.4 282.0 -1.6 0.2 + 4 2 86.2 -158.4 -6.0 6.9 + 4 3 -309.4 199.8 5.4 3.7 + 4 4 47.9 -350.1 -5.5 -5.6 + 5 0 -234.4 0.0 -0.3 0.0 + 5 1 363.1 47.7 0.6 0.1 + 5 2 187.8 208.4 -0.7 2.5 + 5 3 -140.7 -121.3 0.1 -0.9 + 5 4 -151.2 32.2 1.2 3.0 + 5 5 13.7 99.1 1.0 0.5 + 6 0 65.9 0.0 -0.6 0.0 + 6 1 65.6 -19.1 -0.4 0.1 + 6 2 73.0 25.0 0.5 -1.8 + 6 3 -121.5 52.7 1.4 -1.4 + 6 4 -36.2 -64.4 -1.4 0.9 + 6 5 13.5 9.0 -0.0 0.1 + 6 6 -64.7 68.1 0.8 1.0 + 7 0 80.6 0.0 -0.1 0.0 + 7 1 -76.8 -51.4 -0.3 0.5 + 7 2 -8.3 -16.8 -0.1 0.6 + 7 3 56.5 2.3 0.7 -0.7 + 7 4 15.8 23.5 0.2 -0.2 + 7 5 6.4 -2.2 -0.5 -1.2 + 7 6 -7.2 -27.2 -0.8 0.2 + 7 7 9.8 -1.9 1.0 0.3 + 8 0 23.6 0.0 -0.1 0.0 + 8 1 9.8 8.4 0.1 -0.3 + 8 2 -17.5 -15.3 -0.1 0.7 + 8 3 -0.4 12.8 0.5 -0.2 + 8 4 -21.1 -11.8 -0.1 0.5 + 8 5 15.3 14.9 0.4 -0.3 + 8 6 13.7 3.6 0.5 -0.5 + 8 7 -16.5 -6.9 0.0 0.4 + 8 8 -0.3 2.8 0.4 0.1 + 9 0 5.0 0.0 -0.1 0.0 + 9 1 8.2 -23.3 -0.2 -0.3 + 9 2 2.9 11.1 -0.0 0.2 + 9 3 -1.4 9.8 0.4 -0.4 + 9 4 -1.1 -5.1 -0.3 0.4 + 9 5 -13.3 -6.2 -0.0 0.1 + 9 6 1.1 7.8 0.3 -0.0 + 9 7 8.9 0.4 -0.0 -0.2 + 9 8 -9.3 -1.5 -0.0 0.5 + 9 9 -11.9 9.7 -0.4 0.2 + 10 0 -1.9 0.0 0.0 0.0 + 10 1 -6.2 3.4 -0.0 -0.0 + 10 2 -0.1 -0.2 -0.0 0.1 + 10 3 1.7 3.5 0.2 -0.3 + 10 4 -0.9 4.8 -0.1 0.1 + 10 5 0.6 -8.6 -0.2 -0.2 + 10 6 -0.9 -0.1 -0.0 0.1 + 10 7 1.9 -4.2 -0.1 -0.0 + 10 8 1.4 -3.4 -0.2 -0.1 + 10 9 -2.4 -0.1 -0.1 0.2 + 10 10 -3.9 -8.8 -0.0 -0.0 + 11 0 3.0 0.0 -0.0 0.0 + 11 1 -1.4 -0.0 -0.1 -0.0 + 11 2 -2.5 2.6 -0.0 0.1 + 11 3 2.4 -0.5 0.0 0.0 + 11 4 -0.9 -0.4 -0.0 0.2 + 11 5 0.3 0.6 -0.1 -0.0 + 11 6 -0.7 -0.2 0.0 0.0 + 11 7 -0.1 -1.7 -0.0 0.1 + 11 8 1.4 -1.6 -0.1 -0.0 + 11 9 -0.6 -3.0 -0.1 -0.1 + 11 10 0.2 -2.0 -0.1 0.0 + 11 11 3.1 -2.6 -0.1 -0.0 + 12 0 -2.0 0.0 0.0 0.0 + 12 1 -0.1 -1.2 -0.0 -0.0 + 12 2 0.5 0.5 -0.0 0.0 + 12 3 1.3 1.3 0.0 -0.1 + 12 4 -1.2 -1.8 -0.0 0.1 + 12 5 0.7 0.1 -0.0 -0.0 + 12 6 0.3 0.7 0.0 0.0 + 12 7 0.5 -0.1 -0.0 -0.0 + 12 8 -0.2 0.6 0.0 0.1 + 12 9 -0.5 0.2 -0.0 -0.0 + 12 10 0.1 -0.9 -0.0 -0.0 + 12 11 -1.1 -0.0 -0.0 0.0 + 12 12 -0.3 0.5 -0.1 -0.1 +999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999 diff --git a/etc/x2o-01.ini b/etc/x2o-01.ini index a675e7895a..c5473cd0b1 100644 --- a/etc/x2o-01.ini +++ b/etc/x2o-01.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,6 +30,8 @@ ############################################################################ [Require uav/ardupilot.ini] +[Require hardware/lctr-rpi/cpmb.ini] +[Require hardware/lctr-rpi/thermalzone.ini] [General] Vehicle = x2o-01 @@ -61,3 +63,7 @@ Seconds before Waypoint = 1 Copter - Minimum WP switch radius = 1 Convert MSL to WGS84 height = true IPv4 - Address = 10.0.20.140 + +#[Require uav/seatrac.ini] + + diff --git a/etc/x2o-02.ini b/etc/x2o-02.ini index 5c9163e2b0..f600122fe8 100644 --- a/etc/x2o-02.ini +++ b/etc/x2o-02.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -30,6 +30,8 @@ ############################################################################ [Require uav/ardupilot.ini] +[Require hardware/lctr-rpi/cpmb.ini] +[Require hardware/lctr-rpi/thermalzone.ini] [General] Vehicle = x2o-02 @@ -61,3 +63,7 @@ Seconds before Waypoint = 1 Copter - Minimum WP switch radius = 1 Convert MSL to WGS84 height = true IPv4 - Address = 10.0.20.145 + +#[Require uav/seatrac.ini] + + diff --git a/etc/x8-02.ini b/etc/x8-02.ini index 33ac321bec..201624e02a 100644 --- a/etc/x8-02.ini +++ b/etc/x8-02.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -32,7 +32,7 @@ ############################################################################ [Require uav/ardupilot.ini] - +[Require hardware/radio.ini] [General] Vehicle = x8-02 @@ -146,3 +146,10 @@ Entity Label = PTUTransport Local Port = 6020 Static Destinations = 10.0.30.3:6002 Transports = EstimatedState + +[Transports.Radio] +Active = false +Enable telemetry report = true +Mode of communication = Client +Serial Port - Device = /dev/ttyUSB0 +Enable UAV high speed report = true diff --git a/etc/x8-03.ini b/etc/x8-03.ini index da75da2c13..cca6f17482 100644 --- a/etc/x8-03.ini +++ b/etc/x8-03.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/x8-05.ini b/etc/x8-05.ini index 449359ae8c..6532bd6e26 100644 --- a/etc/x8-05.ini +++ b/etc/x8-05.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/etc/x8-06.ini b/etc/x8-06.ini index e68220cd96..a4c106f002 100644 --- a/etc/x8-06.ini +++ b/etc/x8-06.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,6 +31,7 @@ [Require hardware/lctr-b2xx/luemb.ini] [Require uav/ardupilot.ini] +[Require hardware/radio.ini] [Require uav/cameras.ini] [General] @@ -78,7 +79,7 @@ Longitudinal Acceleration Limit = 0.5 Vertical Slope Limit = 0.15 [Simulators.UAVAutopilot] -SimulatedState Filter = x8-03:UAV Simulator +SimulatedState Filter = x8-06:UAV Simulator [Vision.PhotoTrigger] Enabled = Hardware @@ -91,3 +92,11 @@ Entity Label = PTUTransport Local Port = 6020 Static Destinations = 10.0.30.3:6002 Transports = EstimatedState + +[Transports.Radio] +Active = false +Enable telemetry report = true +Mode of communication = Client +Serial Port - Device = /dev/ttyUSB0 +Enable UAV high speed report = true + diff --git a/etc/x8-07.ini b/etc/x8-07.ini index d02e064f24..ff3391156d 100644 --- a/etc/x8-07.ini +++ b/etc/x8-07.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -31,6 +31,7 @@ [Require hardware/lctr-b2xx/luemb.ini] [Require uav/ardupilot.ini] +[Require hardware/radio.ini] [Require uav/cameras.ini] [General] @@ -78,7 +79,7 @@ Longitudinal Acceleration Limit = 0.5 Vertical Slope Limit = 0.15 [Simulators.UAVAutopilot] -SimulatedState Filter = x8-03:UAV Simulator +SimulatedState Filter = x8-07:UAV Simulator [Vision.PhotoTrigger] Enabled = Hardware @@ -91,3 +92,10 @@ Entity Label = PTUTransport Local Port = 6020 Static Destinations = 10.0.30.3:6002 Transports = EstimatedState + +[Transports.Radio] +Active = false +Enable telemetry report = true +Mode of communication = Client +Serial Port - Device = /dev/ttyUSB0 +Enable UAV high speed report = true diff --git a/etc/x8-08.ini b/etc/x8-08.ini index 10909b0f6d..89696c1769 100644 --- a/etc/x8-08.ini +++ b/etc/x8-08.ini @@ -1,5 +1,5 @@ ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -29,9 +29,11 @@ # X8-Flying Wing configuration file # ############################################################################ -[Require hardware/lctr-rpi/apd.ini] [Require uav/ardupilot.ini] [Require uav/cameras.ini] +[Require hardware/radio.ini] +[Require hardware/lctr-rpi/apd.ini] +[Require hardware/lctr-rpi/thermalzone.ini] [General] Vehicle = x8-08 @@ -81,7 +83,7 @@ Longitudinal Acceleration Limit = 0.5 Vertical Slope Limit = 0.15 [Simulators.UAVAutopilot] -SimulatedState Filter = x8-03:UAV Simulator +SimulatedState Filter = x8-08:UAV Simulator [Vision.PhotoTrigger] Enabled = Hardware @@ -95,3 +97,11 @@ Entity Label = PTUTransport Local Port = 6020 Static Destinations = 10.0.30.3:6002 Transports = EstimatedState + +[Transports.Radio] +Active = false +Enable telemetry report = true +Mode of communication = Client +Serial Port - Device = /dev/ttyUSB0 +Enable UAV high speed report = true + diff --git a/i18n/dune.pot b/i18n/dune.pot index aae0a34c70..d299c30483 100644 --- a/i18n/dune.pot +++ b/i18n/dune.pot @@ -5,9 +5,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: DUNE 2016.10.0\n" +"Project-Id-Version: DUNE 2020.01.0\n" "Report-Msgid-Bugs-To: dune@lsts.pt\n" -"POT-Creation-Date: 2016-10-19 19:17+0100\n" +"POT-Creation-Date: 2020-01-10 19:01+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,2466 +16,2915 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Driver.hpp:126 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:47 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:59 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:129 +#, c-format +msgid "SIM card number: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:176 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:61 msgid "unknown error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Driver.hpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:186 #, c-format msgid "SMS transmission failed with error code %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/NodeAddress.hpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:381 +#, c-format +msgid "received IMC message of type %s via SMS" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:386 +msgid "Parsing unrecognized Base64 message as text" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/NodeAddress.hpp:64 #, c-format msgid "invalid address: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Exceptions.hpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Exceptions.hpp:49 #, c-format msgid "invalid SBD size %u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Exceptions.hpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Exceptions.hpp:60 #, c-format msgid "invalid SBD write %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:209 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:211 msgid "error ocurred while clearing MO buffer" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:220 msgid "error ocurred while clearing MT buffer" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:333 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:335 #, c-format msgid "invalid unsolicited string %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:349 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:351 msgid "new session result will overwrite previously unread value" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:404 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:406 msgid "error ocurred while clearing buffer" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:412 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:414 msgid "error ocurred while clearing the MOMSN" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Driver.hpp:197 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:250 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/AIS/Task.cpp:232 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:165 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:757 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MiniSVS/Task.cpp:136 +msgid "I/O error" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:121 msgid "request doesn't match" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:150 #, c-format msgid "reply to maneuver %s has timed out" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:150 msgid "stop" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:150 msgid "start" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:151 msgid "system may need maintenance" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:198 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:200 msgid "already executing, cannot start without stopping" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:234 -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:242 msgid "undefined state" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/PopUp.hpp:281 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/PopUp.hpp:283 msgid "relocated station keeping" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Dislodge.hpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Dislodge.hpp:202 msgid "dislodge failed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Dislodge.hpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Dislodge.hpp:270 msgid "trying again to dislodge" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/ScheduledGoto.hpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Sample.hpp:109 +msgid "sample failed" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/ScheduledGoto.hpp:111 msgid "Unable to reach destination on scheduled time." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Elevator.hpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Elevator.hpp:155 msgid "vertical progress is too slow" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/CommandLink.hpp:108 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/CommandLink.hpp:110 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:85 msgid "failed to set range" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/CommandLink.hpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/CommandLink.hpp:138 msgid "failed to get range" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/XR620CTD/Parser.hpp:201 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XR620CTD/Parser.hpp:203 #, c-format msgid "character value '%d' is not a valid nibble" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Reader.hpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:429 +msgid "failed to enter command mode" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:450 +msgid "failed to set sampling rate" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:111 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:139 +msgid "failed to enter monitor mode" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Reader.hpp:86 msgid "invalid read size" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.hpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.hpp:66 msgid "parse error: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:126 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:130 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:168 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:172 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:128 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:170 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:238 msgid "Total" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:131 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:133 msgid "Execution" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:132 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:220 msgid "Calibration" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:145 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:256 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:147 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:258 msgid "Maneuver " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:173 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:175 msgid "Hotel" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:176 msgid "Payload" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:175 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:177 msgid "Motion" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:176 -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:50 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:178 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:57 msgid "IMU" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:210 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:212 msgid "Prediction Error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:59 msgid "unexpected reply" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:69 msgid "timeout while reading reply" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:79 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:81 #, c-format msgid "buffer has %u bytes, needed %u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:94 #, c-format msgid "invalid checksum: should be %02X%02X but received %02X%02X" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:107 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/DataStore/Task.cpp:188 #, c-format msgid "invalid format: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Math/General.hpp:214 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Math/General.hpp:216 msgid "piecewise linear interpolation needs equally sized vectors" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Monitors/MotorCurrentMonitor.hpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Math/General.hpp:483 +msgid "Value out of range for finding factorial" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Monitors/MotorCurrentMonitor.hpp:54 msgid "motor monitor error: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Monitors/MotorCurrentMonitor.hpp:97 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Monitors/MotorCurrentMonitor.hpp:99 msgid "number of linear points is not even" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Exceptions.hpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Exceptions.hpp:65 #, c-format msgid "feature not implemented '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BeamFilter.hpp:221 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:93 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:96 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:112 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:129 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:132 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:135 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:138 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:210 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:213 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:222 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:225 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BeamFilter.hpp:225 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:95 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:98 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:131 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:137 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:140 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:212 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:224 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:227 msgid "invalid dimensions" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:117 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:182 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:200 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:246 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:258 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:180 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:234 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:243 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:252 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:261 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:270 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:286 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:295 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:311 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:320 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:248 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:260 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:182 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:245 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:254 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:263 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:272 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:288 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:313 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:322 msgid "invalid index" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/IMC/Exceptions.hpp:125 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/IMC/Exceptions.hpp:127 #, c-format msgid "invalid message size %u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/IMC/InlineMessage.hpp:103 -#: /home/maria/LSTS/dune/dune/src/DUNE/IMC/InlineMessage.hpp:112 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/IMC/InlineMessage.hpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/IMC/InlineMessage.hpp:114 msgid "dereference of null inline message" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.hpp:170 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.hpp:172 #, c-format msgid "yaw control mode %d not supported" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.hpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.hpp:182 #, c-format msgid "vertical control mode %d not supported" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:51 #, c-format msgid "unable to resolve hostname '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:60 #, c-format msgid "invalid network address '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:77 #, c-format msgid "network unreachable '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:86 #, c-format msgid "host unreachable '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:93 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:95 msgid "connection error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:103 msgid "connection closed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:111 msgid "connection timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:157 -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:159 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:198 msgid "DBG" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:170 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:172 msgid "ERR" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:181 msgid "WRN" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:190 msgid "MSG" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Parsers/PlanConfigParser.hpp:285 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/PlanConfigParser.hpp:287 #, c-format msgid "invalid z unit: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Parsers/Config.hpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/Config.hpp:143 #, c-format msgid "unable to convert the value under section '%s' option '%s' to the required type and no valid default was given" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:60 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:62 msgid "invalid entity label: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:66 msgid "entity labels cannot be empty" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:73 msgid "nonexistent entity label: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:80 msgid "invalid entity id: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:85 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:87 msgid "an unique id was already reserved for entity label: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:75 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:168 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:77 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:174 msgid "value is not of the correct type" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:94 msgid "possible values are not of the correct type" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:115 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:101 +msgid "minimum value is not of the correct type" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:110 +msgid "maximum value is not of the correct type" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:121 msgid "value is below minimum" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:121 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:127 msgid "value is above maximum" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:127 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:133 msgid "value not in values set" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:199 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:205 msgid "too few elements" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:205 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:211 msgid "too many elements" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Exceptions.hpp:100 -#: /home/maria/LSTS/dune/dune/src/Supervisors/Delegator/Task.cpp:106 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Exceptions.hpp:102 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Delegator/Task.cpp:108 #, c-format msgid "invalid task name '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Exceptions.hpp:113 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Exceptions.hpp:115 #, c-format msgid "invalid value '%s' for parameter '%s': '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/ParameterTable.hpp:80 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/ParameterTable.hpp:82 msgid "variable does not exist" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/System/Error.hpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/System/Error.hpp:176 msgid "retrieving system error messages is not supported" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/HTTPClient.hpp:122 -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/HTTPClient.hpp:178 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/StreamGeneratorFactory.hpp:77 +msgid "Unknown stream velocity source type." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Driver.hpp:218 +#, c-format +msgid "" +"Message sent: \n" +"%s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Driver.hpp:245 +#, c-format +msgid "Unexpected simulation message: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Driver.hpp:252 +#, c-format +msgid "Read error: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/HTTPClient.hpp:124 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/HTTPClient.hpp:180 msgid "timed out while waiting for reply" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/GVSP.hpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/GVSP.hpp:173 msgid "buffer overrun" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/GVSP.hpp:192 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/GVSP.hpp:194 msgid "null frame" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Main/Launcher.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Launcher.cpp:135 msgid "daemon process no longer exists" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Main/Launcher.cpp:169 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Launcher.cpp:171 msgid "execution aborted" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Main/Launcher.cpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Launcher.cpp:173 msgid "daemon crashed with signal " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Main/Daemon.cpp:164 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Daemon.cpp:183 msgid "stopping tasks" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Main/Daemon.cpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Daemon.cpp:194 msgid "unhandled exception" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Main/Daemon.cpp:251 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Daemon.cpp:280 msgid "ERROR: no configuration file was given, see options --config-list and --config-file\n" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Evologics/Task.cpp:519 -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:660 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Evologics/Task.cpp:521 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1086 #, c-format msgid "invalid system name %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/SerialOverTCP/Task.cpp:167 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/SerialOverTCP/Task.cpp:169 msgid "accepting connection request" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Iridium/Task.cpp:218 -msgid "error while parsing Iridium message" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Iridium/Task.cpp:230 +msgid "Parsing unrecognized iridium message as text" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCPOnDemand/Task.cpp:135 +msgid "TCPRequest timeout cannot be zero" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCPOnDemand/Task.cpp:141 +msgid "TCPRequest timeout cannot be less than current time" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCPOnDemand/Task.cpp:158 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:155 +#, c-format +msgid "connected to %u clients" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:199 msgid "operation not supported" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:204 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:237 msgid "is not a regular file" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:251 msgid "could not open" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:230 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:263 msgid "deserialization error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:237 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:270 msgid "empty LSF file" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:244 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:277 msgid "invalid LSF file for replay" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:269 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:315 msgid "started replay of" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:345 msgid "stopped replay" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/HTTP/Task.cpp:114 -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:120 -#: /home/maria/LSTS/dune/dune/src/Transports/FTP/Task.cpp:103 -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:253 -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/HTTP/Task.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:122 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/FTP/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:107 #, c-format msgid "listening on %s:%u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/HTTP/Task.cpp:142 -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:250 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/HTTP/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:258 msgid "failed to find one available port" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/UAN/Task.cpp:627 -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:244 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UAN/Task.cpp:795 +msgid "ignoring abort message addressed to other system" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UAN/Task.cpp:799 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:246 msgid "got abort request" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/UAN/Task.cpp:763 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:932 -msgid "start plan detected" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UAN/Task.cpp:873 +#, c-format +msgid "start plan detected with id: %s for 0x%02X" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Cache/Task.cpp:258 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Cache/Task.cpp:260 #, c-format msgid "failed to copy cache snapshot: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:161 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:437 -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:147 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1059 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:40 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:262 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:445 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1065 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:42 msgid "initializing" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:163 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:441 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:41 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:264 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:449 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:43 msgid "idle" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:165 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:443 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:42 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:266 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:451 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:44 msgid "active" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:167 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:445 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:453 msgid "serial port communication error, modem not responding" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:169 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:447 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:270 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:455 msgid "failed to configure modem, possible serial port communication error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:321 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:525 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:454 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:411 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:427 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:534 #, c-format msgid "modem address for agent '%s' is invalid" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:367 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:520 msgid "failed to configure device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:413 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:534 +#, c-format +msgid "Beacon id=%d | HW P#%d (rev#%d) serial#%d | FW P#%d v%d.%d.%d | App P#%d v%d.%d.%d | %s USBL beacon" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:592 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:658 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:441 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:374 +msgid "failed to set hard-iron correction factors" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:632 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:637 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:642 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:704 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:485 +msgid "different calibration parameters" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:706 msgid "Sending stopped: Communication out of water forbidden." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:473 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:719 +#, c-format +msgid "Send command to the acoustic modem %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:721 +msgid "Sent done" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:747 +#, c-format +msgid "Success transmission complete (part %d of %d) for ticket %d (in %f s)" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:757 +#, c-format +msgid "Sending (handleBinaryMessage) part %d of %d for ticket %d will take up to %f s for %d bytes" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:774 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1310 +#, c-format +msgid "Msg transmission complete for ticket %d (in %f s)" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:794 msgid "wrong message order" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:595 -msgid "Communication failed" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:919 +#, c-format +msgid "Error sending (handleCommunicationError) part %d of %d for ticket %d, resending" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:927 +#, c-format +msgid "Communication failed for ticket %d %d" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:935 +#, c-format +msgid "Next msg or part send to son for ticket %d with ERROR" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1055 +#, c-format +msgid "Received UamTxFrame with dst=0x%04X. Msg for system '%s'" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1071 +#, c-format +msgid "Creating ticket %d" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1076 +#, c-format +msgid "Sending UamTxStatus::UTS_INV_ADDR. Ticket %d died" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1095 +#, c-format +msgid "Sending UamTxStatus::UTS_BUSY. Ticket %d died" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1102 +#, c-format +msgid "Sending UamTxStatus::UTS_IP. Ticket %d being processed" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1118 +#, c-format +msgid "Configuration as %s %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:705 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1126 +#, c-format +msgid "Configuration as ONEWAY %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1135 msgid "device is busy" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:708 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1138 msgid "previous message failed, timeout detected" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:711 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1141 msgid "size mismatch" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:106 -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:243 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1145 #, c-format -msgid "failed to bind to port %u: %s" +msgid "Sending package %f s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:113 -msgid "could not bind server socket" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1146 +#, c-format +msgid "Sending (consume UamTxFrame) part %d of %d for ticket %d will take up to %f s for %d bytes" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1272 #, c-format -msgid "connected to %u clients" +msgid "Calc new timer (bytes %d | bit-rate %f | max-range %d m | multiplier %d) calculated to %f s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1291 +#, c-format +msgid "NOACK Success transmission complete (part %d of %d) for ticket %d (in %f s)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:254 -#: /home/maria/LSTS/dune/dune/src/Transports/FTP/Task.cpp:187 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1300 +#, c-format +msgid "Sending (checkTxOWAY) part %d of %d for ticket %d will take up to %f s for %d bytes" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1323 +#, c-format +msgid "ACK TIMEOUT: Msg transmission with ack for ticket %d timeout ACK. Lets bail with error!! (%f s > %f s)" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/CommManager/Task.cpp:201 +msgid "ERROR Initializing CommManager. Couldn't resolve GSM label." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/CommManager/Task.cpp:211 +msgid "ERROR Initializing CommManager. Couldn't resolve Iridium label." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:108 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:251 +#, c-format +msgid "failed to bind to port %u: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:115 +msgid "could not bind server socket" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:256 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/FTP/Task.cpp:189 #, c-format msgid "error accepting new client connection: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Client/Task.cpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Client/Task.cpp:86 #, c-format msgid "connected to %s:%u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Serial/Task.cpp:109 -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:255 -#: /home/maria/LSTS/dune/dune/src/Simulators/UnderwaterAcoustics/Task.cpp:388 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Serial/Task.cpp:111 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:359 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:257 #, c-format msgid "read error: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Serial/Task.cpp:115 -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Serial/Task.cpp:117 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:305 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:367 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:263 msgid "unknown read error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/LoggingDigest/Task.cpp:194 -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:412 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/LoggingDigest/Task.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:414 #, c-format msgid "failed to start log, check available storage: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:198 -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:205 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:265 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:226 msgid "input error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:206 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:294 msgid "SMS timeout cannot be zero" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:234 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:300 +msgid "Can only send 160 characters over SMS" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:305 +msgid "SMS sent to queue" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:344 +msgid "SMS timeout" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:345 +#, c-format +msgid "discarded expired SMS to recipient %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:360 +msgid "Error sending message over GSM modem" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:361 #, c-format -msgid "discarded expired SMS to recipient '%s'" +msgid "Error sending SMS to recipient %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:384 #, c-format msgid "failed to poll status: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:377 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:395 #, c-format msgid "activating transmission to node '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:400 #, c-format msgid "deactivating transmission to node '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Fragments/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Fragments/Task.cpp:107 #, c-format msgid "Removed incoming message from memory (%d fragments were still missing)." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:145 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:162 msgid "GSM/GPRS username" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:151 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:168 msgid "GSM/GPRS password" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:157 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:174 msgid "GSM/GPRS Access Point Name (APN)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:163 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:180 msgid "GSM/GPRS pin." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:298 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:360 msgid "failed to execute connect command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:310 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:376 msgid "failed to execute disconnect command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:340 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:406 msgid "failed to start NAT" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:350 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:416 msgid "failed to stop NAT" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:425 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:430 +msgid "failed to update dynamic DNS" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:510 #, c-format msgid "connected to the Internet with public address '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/LogBook/Task.cpp:98 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/LogBook/Task.cpp:100 msgid "cleared logbook" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/LogBook/Task.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/LogBook/Task.cpp:103 msgid "invalid or unsupported command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:125 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:133 msgid "task is shutting down" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:281 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:287 +msgid "Message sent successfully." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:304 #, c-format msgid "failed with error %u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:301 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:324 #, c-format msgid "invalid SBD message of size %u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:319 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:342 #, c-format msgid "transmission failed: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:187 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:407 +msgid "No message to be received or sent." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:189 #, c-format msgid "failed to remove cache snapshot: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:318 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:320 #, c-format msgid "log stopped '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:363 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:365 #, c-format msgid "log started '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:113 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:235 +msgid "UAV high speed Reports Periodicity" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:421 +msgid "Vehicle to bind is not define" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:434 +msgid "Invalid communication mode" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:453 +msgid "Invalid radio model" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:585 +#, c-format +msgid "No Radio device on port: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:603 +#, c-format +msgid "Radio configuration failed. Wrong parameter or device on port %s is not a radio " +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:115 msgid "no available ports to listen to advertisements" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:126 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:128 msgid "discarding spurious message" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:135 #, c-format msgid "discarding spurious message '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:190 #, c-format msgid "new node within range '%s' / %u / %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:199 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:201 #, c-format msgid "another node on this computer is advertising our node name '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:201 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:203 #, c-format msgid "another node on our network is advertising our node name '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv2/Task.cpp:177 -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:361 -#: /home/maria/LSTS/dune/dune/src/Supervisors/SlaveCPU/Task.cpp:150 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:451 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:577 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:386 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv2/Task.cpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:363 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/SlaveCPU/Task.cpp:152 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:453 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:579 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:386 msgid "failed to contact device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PSIMAR/Task.cpp:99 -#: /home/maria/LSTS/dune/dune/src/Power/LUEMB/Task.cpp:264 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:229 -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:200 -#: /home/maria/LSTS/dune/dune/src/Actuators/MCD4R/Task.cpp:340 -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:227 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:135 +msgid "Output pin - power status of raspberry" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:139 +msgid "Input signal pin to order powerdown of raspberry" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:143 +msgid "Power 3g output status pin" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:147 +msgid "Output pin signal: to enable or disble 3g" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:151 +msgid "Imput pin signal: to enable or disble 3g" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:155 +msgid "Wifi level output status pins" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:159 +msgid "Entity label of 'EntityState' Mobile Internet" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:165 +msgid "Time, in seconds, between RSSI polling." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:169 +msgid "LED wifi rssi threshold" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:437 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:196 +msgid "EntityState message without source entity" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:274 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:292 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:308 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:480 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:481 +msgid "trying connecting to board" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:152 +msgid "failed to get firmware version" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:288 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:293 +msgid "failed to init BatMan" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:304 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:309 +msgid "failed to start acquisition" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PSIMAR/Task.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/LUEMB/Task.cpp:266 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/MCD4R/Task.cpp:342 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:229 msgid "device is using unstable firmware" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PSIMAR/Task.cpp:101 -#: /home/maria/LSTS/dune/dune/src/Power/LUEMB/Task.cpp:266 -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:528 -#: /home/maria/LSTS/dune/dune/src/Power/MCBv2/Task.cpp:612 -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:310 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:231 -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:202 -#: /home/maria/LSTS/dune/dune/src/Actuators/MCD4R/Task.cpp:342 -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:712 -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:229 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PSIMAR/Task.cpp:103 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/LUEMB/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:530 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/MCBv2/Task.cpp:614 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:312 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:242 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:204 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/MCD4R/Task.cpp:344 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:714 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:231 #, c-format msgid "firmware version %u.%u.%u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:415 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMB/Task.cpp:239 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMBv2/Task.cpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/APD/Task.cpp:235 +msgid "Device is using unstable firmware!" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMB/Task.cpp:241 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMBv2/Task.cpp:242 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/APD/Task.cpp:237 +#, c-format +msgid "Firmware version %u.%u.%u" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMB/Task.cpp:334 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/APD/Task.cpp:330 +msgid "Failed to send frame to APD. Check connection!" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:417 msgid "failed to update EEPROM" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:486 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:488 msgid "power down sequence aborted" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:567 -#: /home/maria/LSTS/dune/dune/src/Power/MCBv2/Task.cpp:588 -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:455 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:569 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/MCBv2/Task.cpp:590 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:457 msgid "device reported" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:597 -#: /home/maria/LSTS/dune/dune/src/Monitors/Medium/Task.cpp:219 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:599 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:230 msgid "water" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:597 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:599 msgid "air" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:607 -#: /home/maria/LSTS/dune/dune/src/Simulators/Leaks/Task.cpp:132 -#: /home/maria/LSTS/dune/dune/src/Simulators/Leaks/Task.cpp:147 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:609 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Leaks/Task.cpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Leaks/Task.cpp:149 msgid "leak detected" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:614 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:616 msgid "no leak" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/APD/Task.cpp:233 -msgid "Device is using unstable firmware!" +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMBv2/Task.cpp:335 +msgid "Failed to send frame to CPMB_v2. Check connection!" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/APD/Task.cpp:235 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:254 +msgid "failed to configure strobe mode" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:258 #, c-format -msgid "Firmware version %u.%u.%u" +msgid "strobe mode set to: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/APD/Task.cpp:328 -msgid "Failed to send frame to APD. Check connection!" +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:258 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:18 +msgid "Camera" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:252 -msgid "failed to configure strobe mode" +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:232 +msgid "Water detected using medium sensor." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:256 -#, c-format -msgid "strobe mode set to: %s" +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:275 +msgid "Water detected using salinity threshold." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:256 -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:16 -msgid "Camera" +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:289 +msgid "Water detected using sound speed sensor." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Collisions/Task.cpp:211 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Collisions/Task.cpp:215 #, c-format msgid "failed to resolve entity '%s': %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Collisions/Task.cpp:366 -#: /home/maria/LSTS/dune/dune/src/Simulators/UnderwaterAcoustics/Task.cpp:253 -msgid "collision detected" +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Collisions/Task.cpp:374 +#, c-format +msgid "Collision detected: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:89 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:95 msgid "SMS Recipient Number" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:98 msgid "Phone number of the SMS recipient" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:105 msgid "Lost Communications Timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:305 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:379 +#, c-format +msgid "sending IridiumMsg (t:%u) to %s: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:388 #, c-format msgid "sending SMS (t:%u) to %s: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:364 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:366 #, c-format msgid "potential fault in servo #%d: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:395 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:397 #, c-format msgid "potential fault in servo #%d, current consumption above %0.1f A" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:431 -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:433 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:433 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:435 #, c-format msgid "servo #%d may require supervision" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Clock/Task.cpp:177 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Clock/Task.cpp:179 #, c-format msgid "adjusting CPU clock by %0.4f s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Clock/Task.cpp:214 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Clock/Task.cpp:216 msgid "failed to execute clock sync command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/FuelLevel/Task.cpp:219 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/FuelLevel/Task.cpp:243 msgid "invalid model" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Boot" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Normal" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Fault" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Failure" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:182 #, c-format msgid "can not monitor %s (%s), is there a task failure or a configuration error?" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:194 -msgid "EntityState message without source entity" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:220 #, c-format msgid "%s entity state is unstable (%s <-> %s), ignoring" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:228 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:230 #, c-format msgid "%s : State stabilized in %s | %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:254 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:256 msgid "reconfiguration command issued" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:267 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:269 msgid "invalid reconfiguration command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:305 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:307 #, c-format msgid "%s - monitoring enabled" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:311 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:313 #, c-format msgid "%s - current state not normal - %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:315 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:317 #, c-format msgid "%s - monitoring previously enabled" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:328 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:330 #, c-format msgid "%s - monitoring disabled" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:335 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:337 #, c-format msgid "%s - monitoring previously disabled" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:359 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:361 #, c-format msgid "entity %s: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:433 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:435 #, c-format msgid "%s -- status not reported after %0.2f seconds" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:436 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:438 #, c-format msgid "%s: entity state timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:262 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:264 #, c-format msgid "%s -- operational limit breached: %0.2f > %0.2f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:277 #, c-format msgid "%s -- operational limit now sane: %0.2f <= %0.2f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:353 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:355 msgid "minimum speed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:354 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:356 msgid "maximum speed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:355 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:357 msgid "depth" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:356 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:358 msgid "vertical rate" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:360 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:362 msgid "maximum altitude" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:361 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:363 msgid "minimum altitude" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:392 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:394 msgid "Operational Area" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:48 msgid "SERVICE" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:48 msgid "CALIBRATION" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:49 msgid "ERROR" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:49 msgid "MANEUVERING" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:50 msgid "EXTERNAL CONTROL" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:50 msgid "BOOT" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:210 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:212 #, c-format msgid "now in '%s' mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:356 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:358 msgid "entity errors cleared" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:360 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:362 #, c-format msgid "vehicle errors: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:425 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:427 msgid " maneuver error: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:487 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:489 msgid "cannot calibrate: vehicle is in external mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:505 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:507 #, c-format msgid "performing maneuver %s while calibrating" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:512 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:514 #, c-format msgid "calibrating vehicle for %u seconds" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:530 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:532 msgid "cannot stop calibration: vehicle is not calibrating" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:534 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:536 msgid "stopped calibration" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:550 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:552 msgid "no maneuver specified" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:558 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:560 msgid " maneuver cannot be started in current mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:567 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:569 msgid " maneuver started" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:598 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:979 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:610 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:600 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:985 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:613 msgid "OK" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:629 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:631 msgid "this vehicle does not allow for external control, disabling loops" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:644 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:646 msgid "maneuver request timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:649 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:651 msgid "calibration timed out" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Reporter/Task.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:70 msgid "Acoustic Reports" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Reporter/Task.cpp:69 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:75 msgid "Acoustic Reports Periodicity" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/AUV/Assist/Task.cpp:289 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:83 +msgid "Radio Reports" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:88 +msgid "Radio Reports Periodicity" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/AUV/Assist/Task.cpp:305 #, c-format msgid "failed to start %s plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Supervisors/AUV/LostComms/Task.cpp:317 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/AUV/LostComms/Task.cpp:317 msgid "starting lost comms plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Task.cpp:383 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Task.cpp:448 msgid "unsupported maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Task.cpp:392 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Task.cpp:457 msgid "wrong maneuver type" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowSystem/Task.cpp:304 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowSystem/Task.cpp:306 msgid "timeout to receive new remote info was exceeded." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/CompassCalibration/Task.cpp:183 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CompassCalibration/Task.cpp:185 msgid "insufficient data for calibration" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/CompassCalibration/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CompassCalibration/Task.cpp:190 #, c-format msgid "%s entity not calibrated. Calibration values with %d turns: %f, %f, 0.0" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/CompassCalibration/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CompassCalibration/Task.cpp:202 #, c-format msgid "forcing minimum of %.1f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/VehicleFormation/Coordinator/Task.cpp:1076 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/VehicleFormation/Coordinator/Task.cpp:1078 #, c-format msgid "Plan specification request failed with uncaught exception: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/CoverArea/Task.cpp:349 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CoverArea/Task.cpp:351 msgid "undefined area" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:116 msgid "forcing control in meters per second" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:122 msgid "provided trajectory is not feasible by the current vehicle!" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:242 msgid "first point must be timed at 0.0" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:251 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:253 msgid "required speed is above the maximum speed allowed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:257 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:259 #, c-format msgid "time difference between %d and %d is less than or equal to zero" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:153 msgid "waiting for first reference" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:223 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:228 #, c-format msgid "ignored reference from non-authorized source: %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:232 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:237 #, c-format msgid "ignored reference from non-authorized entity: %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:579 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:616 #, c-format msgid "Z reference changed to %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:588 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:625 #, c-format msgid "Speed reference changed to %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:594 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:631 #, c-format msgid "Loiter radius reference changed to %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:608 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:645 #, c-format msgid "loitering around (%f, %f, %f, %f)." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:619 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:656 #, c-format msgid "loitering (elevator) towards (%f, %f, %f, %f)." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:630 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:667 #, c-format msgid "going towards (%f, %f, %f)." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:635 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:676 #, c-format msgid "hovering next to (%f, %f)." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:391 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:306 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:682 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:723 +msgid "failed to stop device" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:315 +msgid "failed to read EEPROM#130" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:325 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:335 +msgid "failed to read EEPROM#230" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:485 +msgid "unexpected byte" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:690 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:466 +msgid "failed to read magnetic calibration parameters from device" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:716 +#, c-format +msgid "new hard-iron calibration parameters: %f, %f, %f" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:732 +msgid "failed to read magnetic calibration change report" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:399 msgid "Acoustic Feedback" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:392 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:400 msgid "None, Ranges, Full" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:439 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:447 msgid "waiting beacons configuration" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:449 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:457 msgid "failed to set modem address" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:623 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:591 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:632 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:591 msgid "dynamic sound speed corrections are disabled" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:692 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:701 msgid "received system restart request" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:698 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:707 msgid "restart request acknowledged" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:700 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:709 msgid "failed to acknowledge restart request" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:707 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:716 msgid "acoustic abort detected" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:717 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:726 msgid "abort acknowledged" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:719 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:728 msgid "failed to acknowledge abort" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:765 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:824 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:774 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:833 #, c-format msgid "discarded invalid range %0.2f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:938 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:942 +msgid "start plan detected" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:948 msgid "plan acknowledged" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:940 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:950 msgid "failed to acknowledge plan start" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:1018 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:1057 msgid "failed to ping beacons, modem seems busy" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/AIS/Task.cpp:230 -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:163 -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:744 -#: /home/maria/LSTS/dune/dune/src/Sensors/MiniSVS/Task.cpp:134 -msgid "I/O error" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:257 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:265 msgid "restarting to change transducer detection GPIO" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:296 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:304 #, c-format msgid "unable to use GPIO %d for transducer detection" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:390 msgid "transducer not connected" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:471 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:488 #, c-format msgid "unable to send plan %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:669 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:718 msgid "plan started" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:685 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:778 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:734 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:827 msgid "range to" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:797 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:877 #, c-format msgid "plan progress is %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:181 msgid "High-Frequency Channels" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:180 -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:182 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:198 msgid "None, Port, Starboard, Both" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:186 msgid "High-frequency subsystem channels" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:186 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:188 msgid "High-Frequency Range" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:193 -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:209 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:195 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:211 msgid "Enable high frequency subsystem" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:195 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:197 msgid "Low-Frequency Channels" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:202 msgid "Low-frequency subsystem channels" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:204 msgid "Low-Frequency Range" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:211 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:213 msgid "Range Multiplier" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:217 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:219 msgid "Range multiplier" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:270 -#: /home/maria/LSTS/dune/dune/src/Sensors/Genesys/Task.cpp:103 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:186 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:391 -#: /home/maria/LSTS/dune/dune/src/Simulators/AcousticModem/Task.cpp:93 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:212 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:272 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Genesys/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:393 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:215 msgid "restarting to change IPv4 address" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:273 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:218 msgid "restarting to change TCP command port" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:276 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:278 msgid "restarting to change TCP data port" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:934 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:362 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:595 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:936 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:364 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:601 msgid "failed to turn power on" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:943 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:371 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:604 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:945 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:373 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:610 msgid "failed to connect to device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:131 -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:424 -msgid "failed to enter command mode" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:134 -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:445 -msgid "failed to set sampling rate" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:137 -msgid "failed to enter monitor mode" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Sensors/SCH311X/Task.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SCH311X/Task.cpp:103 #, c-format msgid "file '%s' doesn't exist" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Genesys/Task.cpp:106 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:189 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:394 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Genesys/Task.cpp:108 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:191 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:396 msgid "restarting to change TCP port" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Genesys/Task.cpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Genesys/Task.cpp:111 msgid "restarting to change device address" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/AIM104MultiIO/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/AIM104MultiIO/Task.cpp:150 msgid "invalid message" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/AIM104MultiIO/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/AIM104MultiIO/Task.cpp:195 msgid "timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:423 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:356 -msgid "failed to set hard-iron correction factors" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:429 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:447 msgid "resetting device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:448 -msgid "failed to read magnetic calibration parameters from device" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:467 -msgid "different calibration parameters" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:512 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/MicrostrainMIP/Task.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:530 #, c-format msgid "new hard-iron calibration parameters: %f, %f, 0.0" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:591 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:531 -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:563 -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:863 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/MicrostrainMIP/Task.cpp:313 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:609 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:549 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:565 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:865 #, c-format msgid "%0.1f seconds without valid data" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:608 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:548 -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:580 -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:880 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/MicrostrainMIP/Task.cpp:330 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:626 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:566 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:582 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:882 #, c-format msgid "active | timeouts: %u | faults: %u | frequency: %u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:298 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:316 msgid "failed to configure output frequency" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:358 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:376 #, c-format msgid "new hard-iron calibration parameters: %.4f, %.4f, 0.0" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:448 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:248 +msgid "Requesting DMS readings" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:254 +msgid "Board DMS not operational" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:453 msgid "failed to start monitoring" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:468 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:473 msgid "failed to disable internal channels" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:494 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:499 msgid "failed to set water density" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:497 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:502 msgid "failed to set salinity" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:508 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:513 msgid "failed to set sound speed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:765 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:604 +#, c-format +msgid "unknown probe (%s)" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:778 msgid "mismatch between output and configuration" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:258 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:154 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:278 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:154 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:161 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/StarFish/Task.cpp:68 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:260 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:156 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:280 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:160 msgid "Range" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:266 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:146 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:148 msgid "Frequency" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:346 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex852/Task.cpp:290 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:348 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex852/Task.cpp:292 msgid "restarting to change UART device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/XR620CTD/Task.cpp:466 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XR620CTD/Task.cpp:468 #, c-format msgid "parse error: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:152 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:154 msgid "Operating frequency" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:162 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/StarFish/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:164 msgid "Operating range" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:288 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:290 msgid "failed to read header" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:293 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:295 msgid "failed to read data" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:299 msgid "failed to read footer" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/SW100/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SW100/Task.cpp:195 #, c-format msgid "depth offset is %0.2f m" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:154 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:156 msgid "Level the device and hit NEXT" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:159 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:161 msgid "Rotate the device and keep it levelled (rotation must last +20s)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:164 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:166 msgid "Device is calibrated" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:173 msgid "Calibration error, calibration procedure must be restarted" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:407 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:409 #, c-format msgid "Level the device and hit NEXT (Roll: %0.2f | Pitch: %0.2f)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex852/Task.cpp:259 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/ExplorerDVL/Task.cpp:166 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:225 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex852/Task.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/ExplorerDVL/Task.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:225 msgid "Automatic Activation" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:232 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Task.cpp:234 +msgid "failed to init CTD" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Task.cpp:274 +msgid "com error - get info" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Task.cpp:401 +#, c-format +msgid "CTD - Pressure calibrated (%f)" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:234 msgid "failed to configure trigger frequency" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:242 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:244 msgid "failed to turn on device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:356 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:358 #, c-format msgid "IMU failure: %04X" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:361 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:363 #, c-format msgid "data might be unreliable: %04X" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:202 #, c-format msgid "took too long to read data: %lu ms" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:207 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:209 #, c-format msgid "overrun of %lu ms" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:370 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:372 msgid "unable to enter configuration mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:376 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:378 msgid "unable to set output settings" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:384 msgid "unable to set output mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:388 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:390 msgid "unable to set SyncIn settings" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:394 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:396 msgid "unable to enter measurement mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:399 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:401 msgid "exceeded maximum consecutive CRC error count" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:477 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:479 msgid "device not initialized, initializing" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:483 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:485 #, c-format msgid "got exception %d for command %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:494 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:496 #, c-format msgid "initialized device: class=%d.%d firmware=%d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:500 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:502 #, c-format msgid "device serial number=%u" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:529 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:531 msgid "unable to initialize the device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:537 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:539 msgid "unable to retrieve the serial number" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:555 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:557 msgid "unable to zero the device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:234 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:238 msgid "no reply to command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:235 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:239 msgid "failed to setup device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:516 -msgid "invalid GPZDA sentence" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:543 +msgid "invalid ZDA sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:540 -msgid "invalid GPGGA sentence" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:567 +msgid "invalid GGA sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:588 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:615 msgid "invalid PUBX,00 sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:638 -msgid "invalid GPVTG sentence" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:665 +msgid "invalid VTG sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:662 -msgid "invalid GPHDT sentence" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:689 +msgid "invalid HDT sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:678 -msgid "invalid GPHDM sentence" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:705 +msgid "invalid HDM sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:696 -msgid "invalid GPROT sentence" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:723 +msgid "invalid ROT sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:715 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:742 msgid "invalid PSATHPR sentence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/UserInterfaces/MantaPanel/Task.cpp:315 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:309 +msgid "Requesting SADC readings" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:315 +msgid "Board SADC not operational" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:468 +msgid "no read error received" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:473 +msgid "none adc channel active, mistake config?" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/UserInterfaces/MantaPanel/Task.cpp:347 msgid "failed to execute power down command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:136 #, c-format msgid "TREX disconnected for more than %d seconds" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:202 msgid "Abort detected. Disabling TREX control..." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:217 msgid "Stop TREX detected. Disabling TREX control..." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:238 msgid "Restarting auxiliary CPU..." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:244 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:246 msgid "T-REX has been stopped." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:246 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:248 #, c-format msgid "Could not stop T-REX: %d." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TextActions/Task.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:411 +#, c-format +msgid "Unable to change emergency number to %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:514 #, c-format msgid "received SMS request to start plan '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TextActions/Task.cpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:539 +#, c-format +msgid "received SMS request to resume plan '%s' starting from maneuver '%s'" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:548 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Generator/Task.cpp:240 +msgid "Plan generated automatically" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:572 #, c-format msgid "got abort request from '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Navigation/General/LBL/Task.cpp:347 +#: /home/maria/LSTS/temp/dune-master/source/src/Navigation/General/LBL/Task.cpp:349 #, c-format msgid "corrected beacon #%d (x: %0.2f, y: %0.2f, std dev: %0.2f)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:247 +#: /home/maria/LSTS/temp/dune-master/source/src/Navigation/AUV/Navigation/Task.cpp:708 +msgid "navigation not aligned - Automatic IMU poweroff" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Navigation/AUV/Navigation/Task.cpp:753 +msgid "Nav: speed model invalid" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:249 #, c-format msgid "schedule: %s active on time, +%.1f seconds" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:250 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:252 #, c-format msgid "schedule: %s activation missed deadline, %.1f seconds" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:471 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:473 #, c-format msgid "schedule: entity label %s not found" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:739 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:741 #, c-format msgid "scheduled for: %.1f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:743 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:745 #, c-format msgid "END %s ---" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:69 msgid "plan: speed model invalid" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:80 #, c-format msgid "plan: power model invalid: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:385 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:387 msgid ": no maneuvers" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:400 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:402 msgid ": actual maneuver not specified" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:405 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:407 msgid ": maneuver is not supported" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:408 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:410 msgid ": maneuver depth beyond limits" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:436 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:438 msgid ": maneuver has no incoming transition and it's not the initial maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:447 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:449 msgid ": invalid start maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:523 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:525 #, c-format msgid "invalid maneuver id '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:56 msgid "Start Plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:56 msgid "Stop Plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:57 msgid "Load Plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:57 msgid "Get Plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:59 msgid "BLOCKED" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:59 msgid "READY" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:60 msgid "INITIALIZING" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:60 msgid "EXECUTING" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:231 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:233 msgid "restarting to relaunch plan parser" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:307 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:309 #, c-format msgid "failed to activate %s: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:437 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:439 msgid "vehicle ready" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:472 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:474 msgid "plan completed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:493 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:495 msgid "vehicle errors: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:528 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:530 msgid "vehicle in CALIBRATION mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:541 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:543 msgid "vehicle in EXTERNAL mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:585 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:591 #, c-format msgid "request -- %s (%s)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:591 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:597 msgid "engine not ready: entity state not normal" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:611 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:617 msgid "plan control operation not supported" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:627 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:633 msgid "cannot load plan now" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:635 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:641 msgid "plan load failed: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:644 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:650 msgid "plan parse failed: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:654 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:660 msgid "plan loaded" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:665 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:671 msgid "no plan is running" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:690 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:696 msgid "plan stopped" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:703 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:709 msgid "no plan is running, request ignored" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:746 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:333 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:406 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:441 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:472 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:752 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:336 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:409 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:444 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:475 msgid "undefined plan id" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:758 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:431 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:451 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:482 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:764 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:434 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:454 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:485 msgid "undefined plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:769 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:775 #, c-format msgid "failed loading from DB: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:843 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:849 msgid "plan initializing: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:893 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:899 msgid "cannot initialize plan in BLOCKED state" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:924 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:930 msgid ": invalid maneuver ID" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:931 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:937 msgid ": executing maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:950 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:956 #, c-format msgid "reply -- %s (%s) -- %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1008 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1014 #, c-format msgid "now in %s state" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1101 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1107 msgid "vehicle state timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1123 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1129 msgid "vehicle reply timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1132 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1138 msgid "cleared all requests" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Generator/Task.cpp:216 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Generator/Task.cpp:218 #, c-format msgid "Unable to generate plan using template %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/Generator/Task.cpp:238 -msgid "Plan generated automatically" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/Plan/Generator/Task.cpp:394 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Generator/Task.cpp:397 #, c-format msgid "generating plan from '%s' template..." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:75 msgid "set plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:75 msgid "delete plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:74 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:76 msgid "get plan" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:74 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:76 msgid "get plan info" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:77 msgid "clear database" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:77 msgid "database state" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:76 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:78 msgid "database initialization" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:139 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:141 #, c-format msgid "database file: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:169 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:171 msgid "initialization complete" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:223 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:225 #, c-format msgid "storing plan '%s' issued through a PlanControl request" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:253 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:255 msgid "unexpected message" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:266 -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:295 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:302 msgid "not active" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:296 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:299 msgid "unsupported operation" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:325 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:328 msgid "database is corrupt" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:341 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:344 msgid "no plan specification given" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:347 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:350 msgid "plan id mismatch" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:398 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:401 msgid "OK (updated)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:398 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:401 msgid "OK (new entry)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/ASV/HeadingAndSpeed/Task.cpp:459 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ASV/HeadingAndSpeed/Task.cpp:461 msgid "enabling" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/ASV/HeadingAndSpeed/Task.cpp:459 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ASV/HeadingAndSpeed/Task.cpp:461 msgid "disabling" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:54 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:65 msgid "Heading Rate" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:54 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:64 msgid "Heading" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:57 msgid "Surge" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:57 msgid "Sway" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Allocator/Task.cpp:87 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/LMI/Task.cpp:89 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:181 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Allocator/Task.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/LMI/Task.cpp:91 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:187 msgid "Maximum Fin Rotation" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Allocator/Task.cpp:90 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/LMI/Task.cpp:92 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Allocator/Task.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/LMI/Task.cpp:94 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:190 msgid "Maximum admissible fin rotation" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/LMI/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/LMI/Task.cpp:150 msgid "Gain matrix has invalid dimensions" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Diving/Task.cpp:478 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Diving/Task.cpp:480 msgid "failed to submerge" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:63 msgid "Roll" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:63 msgid "Pitch" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:62 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1163 -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:55 msgid "Depth" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:186 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:192 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:194 msgid "Enable roll controller" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/AntennaTracker/Task.cpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AntennaTracker/Task.cpp:101 #, c-format msgid "Target name is %s, with ID %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:475 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:512 msgid "Ardupilot interface initialized" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:480 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:523 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:372 msgid "Connection failed, retrying..." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:596 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:639 msgid "ArduPilot is in Manual mode, saving control loops." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:849 -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:253 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:889 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:253 msgid "speed control is NOT active" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:878 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:918 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:1107 msgid "ArduPilot is in Manual mode, saving desired path." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:884 -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:372 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:924 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:372 msgid "path control is NOT active" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:892 -msgid "ArduPilot in Auto mode but still in ground, performing takeoff first." +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:931 +msgid "ArduPilot in Auto mode, but still in ground! Add a takeoff waypoint to the plan." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:1217 +msgid "ArduPilot is in Manual mode, unable to perform automatic landing." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1454 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:1546 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:1048 msgid "Connection lost, retrying..." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1942 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:2039 msgid "Controlling an unknown vehicle type." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1946 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:2043 msgid "Controlling a fixed-wing vehicle." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1953 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:2050 msgid "Controlling a multirotor." msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:40 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:51 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:363 +msgid "PX4 interface initialized" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:556 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:620 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:678 +msgid "PX4 is in a Manual mode, saving desired path." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:42 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:53 msgid "invalid command" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:41 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:60 msgid "invalid command arguments" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:42 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:56 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/IntelHEX.cpp:107 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:65 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:44 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/IntelHEX.cpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:67 msgid "invalid checksum" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:43 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:45 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:54 msgid "lost synchronization" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:44 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:55 msgid "parser error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:45 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:56 msgid "data overrun" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:46 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:57 msgid "buffer overflow" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:58 msgid "invalid error code" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:69 msgid "failed to reset device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:79 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:81 msgid "failed to set bootloader parameters" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:137 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:139 msgid "failed to get firmware name" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:150 -msgid "failed to get firmware version" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:155 msgid "invalid firmware version" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:68 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:70 msgid "failed to enter bootloader" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:85 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:87 msgid "failed to jump to application" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:124 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:126 msgid "failed start upgrade procedure" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:135 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:137 msgid "failed to end upgrade procedure" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:156 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:158 msgid "failed to fill page chunk" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:166 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:168 msgid "failed to write flash page" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:198 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:200 msgid "failed to retrieve flash info" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:386 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:388 msgid "failed to synchronize with device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:405 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:407 msgid "failed to request current log name" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:420 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:422 msgid "failed to retrieve current log name" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:59 msgid "parser bug" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicModem.cpp:265 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicModem.cpp:267 #, c-format msgid "fragment: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/IntelHEX.cpp:61 -#: /home/maria/LSTS/dune/dune/src/DUNE/Algorithms/MD5.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/IntelHEX.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Algorithms/MD5.cpp:65 msgid "failed to open file" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Time/Clock.cpp:123 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:136 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:140 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Time/Clock.cpp:122 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:122 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:126 msgid "failed to set time" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Power/Model.cpp:118 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Power/Model.cpp:120 #, c-format msgid "invalid hardware part '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:45 msgid "activating" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:44 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:46 msgid "deactivating" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:45 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:47 msgid "input/output error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:48 msgid "internal error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:49 msgid "CPU usage is too high" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:50 msgid "fuel is running low" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:51 msgid "fuel level estimation is not reliable" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:50 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:52 msgid "fuel reserve" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:51 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:53 msgid "calibrating" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:54 msgid "calibrated" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:55 msgid "not aligned" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:56 msgid "aligning" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:57 msgid "aligned" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:58 msgid "powering down" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:59 msgid "communication error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:60 msgid "synchronized" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:59 -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:328 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:311 msgid "synchronizing" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:60 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:62 msgid "not synchronized" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:63 msgid "waiting for GPS fix" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:64 msgid "waiting for configuration of LBL beacons" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:65 msgid "waiting for solution to converge" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:66 msgid "missing data" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:66 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:68 msgid "invalid version" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:69 msgid "active but without bottom lock" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:68 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:70 msgid "no medium data: user must control device" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:69 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:71 msgid "active (no medium data: need user input)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:70 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:72 msgid "idle (no medium data: need user input)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:73 msgid "connecting" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:72 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:74 msgid "connected" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:49 msgid "Print this message and exit" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:50 msgid "Print the version information and exit" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:51 msgid "Print architecture information and exit" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:66 #, c-format msgid "short option '%s' already exists" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:69 #, c-format msgid "long option '%s' already exists" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:130 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:132 #, c-format msgid "" "Description:\n" @@ -2483,7 +2932,7 @@ msgid "" "\n" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:134 #, c-format msgid "" "Usage:\n" @@ -2491,1537 +2940,1662 @@ msgid "" "\n" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:135 msgid "Options:\n" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:161 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:163 #, c-format msgid "This program is built for %s\n" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:162 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:164 #, c-format msgid "Report bugs to %s\n" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:176 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:178 #, c-format msgid "unknown option '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:189 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:191 #, c-format msgid "missing argument for option '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/String.cpp:303 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/String.cpp:333 msgid "invalid escape sequence" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:151 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:153 msgid "matrix inversion error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:42 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:44 #, c-format msgid "position uncertainty is %0.2f m" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:60 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:62 msgid "Maximum Horizontal Position Variance" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:346 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:349 #, c-format msgid "received acceleration beyond range: %f, %f, %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:368 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:371 #, c-format msgid "received angular velocity beyond range: %f, %f, %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:458 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:461 #, c-format msgid "received euler angles beyond range: %f, %f, %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:486 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:489 #, c-format msgid "received euler angles delta beyond range: %f, %f, %f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1163 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1175 #, c-format msgid "no measurements available: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1175 msgid "Euler Angles" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicRemoteOperation.cpp:131 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicRemoteOperation.cpp:133 #, c-format msgid "teleoperation by %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:54 msgid "Idle" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:54 msgid "Tracking" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:55 msgid "LimitDepth" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:56 msgid "Unsafe" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:56 msgid "Avoiding" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:59 msgid "BottomTrack" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:377 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:378 msgid "depth is reaching unacceptable values, forcing depth control" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:543 -msgid "unable to avoid obstacle" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:554 -msgid "avoid obstacle" -msgstr "" - -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:612 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:594 msgid "Started braking" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:614 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:596 msgid "Stopped braking" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:48 msgid "no valid altitude measurements" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:178 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:180 #, c-format msgid "limiting depth to %.1f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:198 #, c-format msgid "limiting altitude to %.1f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:258 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:260 #, c-format msgid "invalid vertical control mode %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:270 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:272 msgid "timed out while waiting for vertical control mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:307 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:309 #, c-format msgid "water column not deep enough for altitude control ( %0.2f < %0.2f )" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:326 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:328 msgid "getting too close to maximum admissible depth" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:337 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:339 #, c-format msgid "invalid yaw control mode %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:349 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:351 msgid "timed out waiting for yaw control mode" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:438 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:372 +msgid "track length is too long" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:453 msgid "keep loitering" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:480 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:495 #, c-format msgid "path (lat/lon): %0.5f %0.5f to %0.5f %0.5f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:651 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:666 msgid "expected new path control reference" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:708 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:723 msgid "now loitering" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:847 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:853 msgid "along-track divergence error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:880 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:886 msgid "cross-track divergence error" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:961 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:967 msgid "waiting for position estimate from navigation" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:130 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:103 msgid "unable to create socket" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:169 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:186 msgid "unable to bind to socket" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:181 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:183 msgid "unable to connect" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:190 msgid "unable to listen" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:199 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:201 msgid "failed to accept connection" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:226 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:197 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:228 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:199 msgid "error receiving data" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:247 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:227 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:249 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:229 msgid "error sending data" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:346 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:348 msgid "unable to set receive timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:354 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:356 msgid "unable to set send timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:363 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:365 msgid "unable to get bound address" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:374 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:376 msgid "unable to get bound port" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:116 msgid "setting up socket" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/FragmentedMessage.cpp:66 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/FragmentedMessage.cpp:68 msgid "Invalid fragment received and it won't be processed." msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/FollowTrajectory.cpp:79 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:145 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/FollowTrajectory.cpp:81 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:147 msgid "too few trajectory points" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Elevate.cpp:53 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:50 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Circular.cpp:44 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/FigureEight.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Elevate.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Circular.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/FigureEight.cpp:56 #, c-format msgid "forcing minimum radius of %.1f" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Elevate.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Elevate.cpp:125 msgid "water column is not deep enough" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:98 #, c-format msgid "outside safe region (distance: %.1f m)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:120 #, c-format msgid "inside safe region (distance: %.1f m)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:154 msgid "invalid station keeping state" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/RowsStages.cpp:94 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/RowsStages.cpp:96 msgid "invalid maneuver parameters" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:69 msgid "parsing vehicle participants" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:80 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:82 msgid "invalid formation participant" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:94 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:96 msgid "repeated vehicles in participant list" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:108 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:110 msgid "not enough vehicles in formation (at least 2 are required)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:116 msgid "local vehicle is not part of formation" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Maneuver.cpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Maneuver.cpp:182 msgid "unsupported vertical reference" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Maneuver.cpp:186 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Maneuver.cpp:188 msgid "no valid value for altitude has been received yet,maneuver will not proceed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/BasicEntity.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:66 +msgid "HDF5Reader::HDF5Reader(): support for HDF5 i/o is not enabled." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:79 +msgid "HDF5Reader::HDF5Reader(): unable to open file." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:113 +msgid "HDF5Reader::getDataset(): The requested dataset does not exist." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:153 +msgid "HDF5Reader::getAttribute(): requested attribute does not exist." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/BasicEntity.cpp:48 msgid "entity label already set: " msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:65 msgid "Pure Hardware" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:66 msgid "Pure Simulation" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:67 msgid "Simulation with Hardware-in-the-loop" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:74 msgid "No description given" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:118 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:121 #, c-format msgid "system name: '%s' (%u)" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:122 #, c-format msgid "registered tasks: %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:123 #, c-format msgid "base folder: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:121 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:124 #, c-format msgid "configuration folder: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:122 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:125 #, c-format msgid "web server folder: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:126 #, c-format msgid "log folder: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:124 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:127 #, c-format msgid "library folder: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:128 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:131 #, c-format msgid "execution profiles: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:152 msgid "clean shutdown" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:158 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:167 #, c-format msgid "daemon running with maximum priority: %d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:162 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:171 msgid "daemon not running with maximum priority" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Parameter.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:223 +msgid "Got message to reboot system" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Parameter.cpp:73 msgid "invalid visibility string" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Parameter.cpp:89 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Parameter.cpp:91 msgid "invalid scope string" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Parameter.cpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Parameter.cpp:134 msgid "no available reader" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/SimpleTransport.cpp:79 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/SimpleTransport.cpp:81 #, c-format msgid "outgoing: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/SimpleTransport.cpp:111 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/SimpleTransport.cpp:113 #, c-format msgid "incoming: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/MessageFilter.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/MessageFilter.cpp:116 #, c-format msgid "invalid filter: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Periodic.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Periodic.cpp:50 msgid "Execution Frequency" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Periodic.cpp:51 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Periodic.cpp:53 msgid "Frequency at which task is executed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/ParameterTable.cpp:41 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/ParameterTable.cpp:43 msgid "invalid parameter" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Profiles.cpp:76 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Profiles.cpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Profiles.cpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Profiles.cpp:94 #, c-format msgid "no such profile name '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:69 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:229 msgid "Entity Label" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:75 msgid "Main entity label" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:77 msgid "Execution Priority" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:79 msgid "Execution priority" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:77 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:81 msgid "Activation Time" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:80 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:84 msgid "Deactivation Time" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:83 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:87 msgid "Debug Level" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:128 msgid "entity label is not configured" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:189 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:203 msgid "Active - Scope" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:207 msgid "Scoped of the 'Active' parameter" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:210 msgid "Active - Visibility" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:214 msgid "Visibility of the 'Active' parameter" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:216 msgid "Active" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:206 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:220 msgid "True to activate task, false otherwise" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:276 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:289 msgid "activation is not in progress" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:316 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:328 msgid "deactivation is not in progress" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:377 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:389 msgid "restarting" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:380 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:392 #, c-format msgid "restarting immediately due to error: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:394 #, c-format msgid "restarting in %u seconds due to error: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:399 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:411 #, c-format msgid "failed to update parameters: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:407 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:419 #, c-format msgid "task died with uncaught exception: %s: restarting" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:475 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:488 #, c-format msgid "updating entity parameters: %s: '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:695 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:708 #, c-format msgid "invalid parameter '%s'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:110 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:717 +#, c-format +msgid "unable to load parameters: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:112 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:190 msgid "unknown exception" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:151 msgid "stopping" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:151 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:153 msgid "stopped" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:155 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:157 #, c-format msgid "failed to join task %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:181 msgid "starting" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:256 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:258 #, c-format msgid "using %d%% of CPU, lowering the priority" msgstr "" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:263 #, c-format msgid "using %d%% of CPU, failed to lower the priority" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/SingleSIMCT01/Task.cpp:139 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/SingleSIMCT01/Task.cpp:141 msgid "invalid value for 'Motor Id'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/SingleSIMCT01/Task.cpp:142 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/SingleSIMCT01/Task.cpp:144 msgid "invalid value for 'Thruster Id'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:332 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:334 #, c-format msgid "AMC Motor %d - ERROR" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:348 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:350 msgid "AMC Motor ERROR" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:353 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:355 msgid "ALL MOTORS OK" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:435 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:437 msgid "Wrong parameter request" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:86 msgid "init" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:85 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:87 msgid "i2c" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:86 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:88 msgid "power" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:87 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:89 msgid "hall" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:88 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:90 msgid "rotor locked" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:89 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:91 msgid "mcu temperature" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:90 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:92 msgid "bridge temperature" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:91 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:93 msgid "motor temperature" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:365 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:367 msgid "Motor control mode must be one of 'none', 'voltage', 'current', 'rpm'" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:620 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:622 #, c-format msgid "device error: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:627 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:629 msgid "power is not good" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:631 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:633 msgid "device init error, requesting reset" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:641 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:643 msgid "CMD_ACTUATE Data size doesn't match!" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:666 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:668 msgid "CMD_CONFIG data size doesn't match!" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:676 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:678 msgid "CMD_CONFIG_DCYC data size doesn't match!" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:686 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:688 msgid "CMD_CONFIG_IADC data size doesn't match!" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:696 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:698 msgid "CMD_CONFIG_ERPM data size doesn't match!" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:838 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:840 #, c-format msgid "device reported: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:155 msgid "LED - Patterns" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:158 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:160 msgid "List of LED patterns" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:160 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:162 msgid "LED - Patterns Pulse Width" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:166 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:168 msgid "Pulse width for LED patterns" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:168 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:170 msgid "LED - External Driver" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:172 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:174 msgid "Enable external LED driver" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:176 msgid "LED - External Trigger" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:178 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:180 msgid "Enable external LED trigger" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:243 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:245 msgid "failed to get constant parameters" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:262 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:264 msgid "failed to set LED patterns" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:290 -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:293 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:292 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:295 msgid "failed to configure LED driver" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:296 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:298 msgid "failed to configure LED pattern pulse width" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/VSIM/Task.cpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/VSIM/Task.cpp:129 msgid "error loading world parameters." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/VSIM/Task.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/VSIM/Task.cpp:133 msgid "error loading vehicle parameters." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/Servos/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/VSIM/Task.cpp:194 +#, c-format +msgid "Setting stream velocity: %f m/s N : %f m/s E : %f m/s D" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Servos/Task.cpp:202 #, c-format msgid "fault triggered in servo #%d" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/Servos/Task.cpp:207 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Servos/Task.cpp:209 #, c-format msgid "servo #%d is no longer in fault" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/AcousticModem/Task.cpp:96 -msgid "restarting to change UDP port" +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp:59 +msgid "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): dimensions of velocity components do not match." msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/Docking/Task.cpp:275 -msgid "Success" +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp:65 +msgid "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): data must be three-dimensional (2D space + time)." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp:73 +msgid "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): data dimensions do not match grid dimensions." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:153 +#, c-format +msgid "Setting default stream velocity: %f m/s N : %f m/s E : %f m/s D" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:169 +#, c-format +msgid "" +"An error ocurred while accessing the stream velocity source:\n" +"\t%s\n" +"\tFalling back to constant stream velocity." +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:182 +#, c-format +msgid "Setting initial time delta to %f seconds" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/UnderwaterAcoustics/Task.cpp:381 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:209 #, c-format -msgid "unexpected simulation message: %s" +msgid "Stream velocity is %f m/s N : %f m/s E : %f m/s D" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Simulators/UAV/Task.cpp:431 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Task.cpp:283 +#, c-format +msgid "Unknown transmission status: %s" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Docking/Task.cpp:277 +msgid "Success" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/UAV/Task.cpp:433 #, c-format msgid "UAV simulation type: %s" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:401 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:403 msgid "failed to activate required entities" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:403 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:405 msgid "failed to configure camera" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:405 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:407 msgid "failed to start video streamming" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:407 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:409 msgid "activation timed out for unknown reason" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:449 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:451 msgid "failed to deactivate required entities" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:459 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:461 msgid "activated" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:467 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:469 msgid "stopped video stream" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:489 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:491 msgid "invalid entity" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:518 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:520 msgid "failed to start video stream" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:538 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:540 msgid "started video stream" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:629 -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:670 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:631 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:672 msgid "failed to set property" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:917 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:919 msgid "successfully configured camera" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/Task.cpp:454 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/Task.cpp:456 msgid "keep alive failed" msgstr "" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/Task.cpp:471 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/Task.cpp:473 #, c-format msgid "lost at least %d packets" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:87 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:70 msgid "failed to set standby" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:111 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:97 msgid "failed to set framing mode" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:219 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:205 msgid "failed to set recording file format" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:228 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:214 msgid "failed to set recording file ping count" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:286 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:272 msgid "failed to set recording file prefix" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:378 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:364 msgid "failed to start slave" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:388 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:374 msgid "failed to end slave" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:397 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:383 msgid "failed to open sonar" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:413 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:399 msgid "failed to close sonar" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:267 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:250 msgid "acquiring PPS signal" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:276 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:259 msgid "PPS signal acquired" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:286 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:269 msgid "clock is disciplined" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:293 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:276 #, c-format msgid "disciplining clock (%lld µs)" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:304 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:287 msgid "clock is synchronized" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:306 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:289 msgid "failed to set the hardware clock" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:321 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:304 #, c-format msgid "adjusting clock by %ld s" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:333 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:316 #, c-format msgid "clock is synchronized [%lld, %ld, %ld]" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:246 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:246 msgid "no gimbal data" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:424 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:424 msgid "error decoding gimbal georeference packet" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:448 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:448 msgid "error decoding gimbal version packet" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:452 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:452 #, c-format msgid "software version %d.%d.%d patch %d %4d-%02d-%02d" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:461 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:461 #, c-format msgid "hardware board - SN %0u FN %u rev %u config %u %u-%02u-%02u" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:472 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:472 #, c-format msgid "camera %d -- id: %u HFOV: [%0.2f, %0.2f]" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:144 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:144 #, c-format msgid "creating a TCP connection | %s %u" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:146 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:146 msgid "Piccolo interface initialized" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:168 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:168 #, c-format msgid "%s - deactivating" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:170 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:170 #, c-format msgid "%s - activating" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:183 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:183 msgid "tracker is NOT enabled" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:190 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:190 msgid "speed control" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:191 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:191 msgid "altitude control" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:192 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:192 msgid "bank control" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:193 msgid "heading control" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:194 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:194 msgid "vertical rate control" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:195 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:195 msgid "path control" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:274 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:274 msgid "altitude control is NOT active" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:280 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:280 msgid "Not a valid height reference" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:301 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:301 msgid "bank control is NOT active" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:322 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:322 msgid "heading control is NOT active" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:348 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:348 msgid "vertical rate control is NOT active" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:142 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:131 msgid "High-Frequency Channel" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:146 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:135 msgid "Enable high-frequency channel" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:137 msgid "Low-Frequency Channel" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:152 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:141 msgid "Enable low-frequency channel" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/ExplorerDVL/Task.cpp:160 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:219 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:143 +msgid "Low-Frequency Bathymetry Channel" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:147 +msgid "Enable low-frequency bathymetry channel" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/ExplorerDVL/Task.cpp:143 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:219 msgid "Use Device at Surface" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:26 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:26 msgid "failed to set continous mode" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:27 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:27 msgid "failed to set transducer face orientation" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:28 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:28 msgid "failed to set sampling frequency" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:418 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:430 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:418 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:430 msgid "failed to request current output formats" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:443 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:443 msgid "failed to configure output format" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:601 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:601 msgid "failed to start data sampling" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:615 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:615 msgid "failed to stop data sampling" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:624 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:624 msgid "failed to enable user-defined sound speed" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:631 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:631 msgid "failed to set initial sound speed" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:717 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:717 msgid "invalid sample" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:863 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:863 msgid "sensor data timeout" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:869 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:869 msgid "too many samples below threshold" msgstr "" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:904 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:904 msgid "rebooting" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:1 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:1 msgid "A/D Board" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:2 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:2 msgid "AHRS" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:3 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:3 msgid "AIS Receiver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:4 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:4 msgid "Acoustic Access Controller" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:5 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:5 msgid "Acoustic Modem" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:6 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:6 +msgid "Acoustic Modem Simulator" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:7 msgid "Allocator" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:7 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:8 msgid "Announce" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:8 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:9 msgid "Antenna Tracker" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:9 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:10 msgid "Arduino Serial" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:10 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:11 msgid "Attitude" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:11 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:12 msgid "Autopilot" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:12 -msgid "CPU" +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:13 +msgid "BATMAN" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:13 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:14 +msgid "Back Seat TCP Server" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:15 msgid "CTD" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:14 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:16 msgid "CTD Simulator" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:15 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:17 msgid "Cache" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:17 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:19 msgid "Camera Backend" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:18 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:20 msgid "Camera Module" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:19 -msgid "Chlorophyll Probe" -msgstr "" - -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:20 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:21 msgid "Clock" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:21 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:22 msgid "Collisions" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:22 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:23 +msgid "Communications Manager" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:24 msgid "Communications Relay Maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:23 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:25 msgid "Compass Calibration Maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:24 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:26 msgid "Cover Area" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:25 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:27 +msgid "CyclopsC7" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:28 msgid "DAQ" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:26 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:29 +msgid "DMS" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:30 msgid "DVL" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:27 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:31 +msgid "DataStore Source" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:32 +msgid "DataStore Transport" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:33 msgid "Depth Control" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:28 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:34 msgid "Depth Sensor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:29 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:35 msgid "Discovery" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:30 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:36 msgid "Diving" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:31 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:37 msgid "Docking" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:32 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:38 msgid "Echo Sounder" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:33 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:39 msgid "Emergency Monitor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:34 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:40 msgid "Emulated GPS" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:35 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:41 msgid "Entity Monitor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:36 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:42 msgid "Environment" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:37 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:43 +msgid "Evologics SerialOverTCP" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:44 msgid "FTP Server" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:38 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:45 msgid "Follow Reference" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:39 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:46 msgid "Follow Reference Maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:40 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:47 msgid "Follow System Maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:41 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:48 msgid "Formation Control" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:42 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:49 msgid "Formation Link" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:43 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:50 msgid "Fuel" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:44 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:51 msgid "GPS" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:45 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:52 msgid "GSM" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:46 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:53 msgid "HTTP Server" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:47 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:54 msgid "Heave Motor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:48 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:55 msgid "Height Control" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:49 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:56 msgid "Horizontal Plane Control" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:51 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:58 msgid "IMU Power Supply" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:52 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:59 msgid "Iridium Modem" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:53 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:60 msgid "Iridium Transport" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:54 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:61 msgid "LBL" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:55 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:62 msgid "LBL Estimator" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:56 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:63 msgid "LCD" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:57 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:64 msgid "LED Driver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:58 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:65 msgid "LEDs" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:59 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:66 msgid "Leak Simulator" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:60 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:67 msgid "Log Book" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:61 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:68 msgid "Logger" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:62 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:69 msgid "Lost Comms" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:63 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:70 msgid "Lost Comms Monitor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:64 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:71 msgid "MCD4R" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:65 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:72 +msgid "Magnetometer" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:73 msgid "Mainboard" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:66 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:74 msgid "Medium" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:67 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:75 msgid "Message Fragments" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:68 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:76 msgid "Mobile Internet" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:69 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:77 msgid "Motor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:70 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:78 msgid "Motor Controller" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:71 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:79 msgid "Multibeam" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:72 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:80 msgid "Multiplexer Maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:73 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:81 msgid "Navigation" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:74 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:82 +msgid "OEMX" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:83 msgid "Operational Limits" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:75 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:84 msgid "Oxygen Sensor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:76 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:85 msgid "PTUD48" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:77 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:86 msgid "PTUTransport" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:78 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:87 +msgid "PWM" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:88 msgid "Panel" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:79 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:89 msgid "Panel Buttons" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:80 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:90 msgid "Path Control" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:81 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:91 msgid "Path Control Leader" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:82 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:92 msgid "Pencil Beam" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:83 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:93 msgid "Photo Trigger" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:84 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:94 msgid "Plan Database" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:85 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:95 msgid "Plan Engine" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:86 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:96 msgid "Plan Generator" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:87 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:97 msgid "Port Bow Motor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:88 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:98 msgid "Port Stern Motor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:89 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:99 msgid "Power Board" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:90 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:100 msgid "Power Source" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:91 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:101 msgid "Power Supervisor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:92 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:102 msgid "Power Supply" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:93 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:103 +msgid "Radio" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:104 msgid "Ranger" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:94 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:105 msgid "Recovery Supervisor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:95 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:106 msgid "Remote Control" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:96 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:107 msgid "Remote Operation" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:97 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:108 msgid "Report Supervisor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:98 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:109 msgid "Rows Coverage Maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:99 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:110 +msgid "SADC" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:111 msgid "Service Announcer" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:100 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:112 msgid "Service Discovery" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:101 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:113 msgid "Servo Controller" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:102 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:114 msgid "Servo Monitor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:103 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:115 msgid "Servos" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:104 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:116 msgid "Sidescan" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:105 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:117 msgid "Simulation Engine" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:106 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:118 msgid "Slave CPU" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:107 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:119 msgid "Sound Speed Sensor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:108 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:120 msgid "Sound Speed Simulator" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:109 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:121 msgid "Speed Control" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:110 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:122 msgid "Starboard Bow Motor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:111 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:123 msgid "Starboard Stern Motor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:112 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:124 +msgid "Stream Velocity Simulator" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:125 +msgid "TCP On Demand" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:126 msgid "TCP Server" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:113 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:127 msgid "TCP to Camera CPU" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:114 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:128 msgid "TCP to Master" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:115 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:129 msgid "TCP to Slave CPU" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:116 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:130 msgid "TREX" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:117 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:131 msgid "Teleoperation Maneuver" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:118 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:132 msgid "Text Message Parser" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:119 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:133 +msgid "Thermal Zone" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:134 +msgid "UART Serial" +msgstr "" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:135 msgid "UAV Simulator" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:120 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:136 msgid "UAVCamera" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:121 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:137 msgid "UDP" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:122 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:138 msgid "UDP to TREX" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:123 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:139 msgid "USBL" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:124 -msgid "Underwater Acoustics Simulator" -msgstr "" - -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:125 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:140 msgid "Vehicle Supervisor" msgstr "" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:126 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:141 msgid "Water Quality Sensor" msgstr "" diff --git a/i18n/entity_labels.txt b/i18n/entity_labels.txt index a4aea62eb0..075490cbc5 100644 --- a/i18n/entity_labels.txt +++ b/i18n/entity_labels.txt @@ -3,27 +3,33 @@ DTR_RT("AHRS") DTR_RT("AIS Receiver") DTR_RT("Acoustic Access Controller") DTR_RT("Acoustic Modem") +DTR_RT("Acoustic Modem Simulator") DTR_RT("Allocator") DTR_RT("Announce") DTR_RT("Antenna Tracker") DTR_RT("Arduino Serial") DTR_RT("Attitude") DTR_RT("Autopilot") -DTR_RT("CPU") +DTR_RT("BATMAN") +DTR_RT("Back Seat TCP Server") DTR_RT("CTD") DTR_RT("CTD Simulator") DTR_RT("Cache") DTR_RT("Camera") DTR_RT("Camera Backend") DTR_RT("Camera Module") -DTR_RT("Chlorophyll Probe") DTR_RT("Clock") DTR_RT("Collisions") +DTR_RT("Communications Manager") DTR_RT("Communications Relay Maneuver") DTR_RT("Compass Calibration Maneuver") DTR_RT("Cover Area") +DTR_RT("CyclopsC7") DTR_RT("DAQ") +DTR_RT("DMS") DTR_RT("DVL") +DTR_RT("DataStore Source") +DTR_RT("DataStore Transport") DTR_RT("Depth Control") DTR_RT("Depth Sensor") DTR_RT("Discovery") @@ -34,6 +40,7 @@ DTR_RT("Emergency Monitor") DTR_RT("Emulated GPS") DTR_RT("Entity Monitor") DTR_RT("Environment") +DTR_RT("Evologics SerialOverTCP") DTR_RT("FTP Server") DTR_RT("Follow Reference") DTR_RT("Follow Reference Maneuver") @@ -62,6 +69,7 @@ DTR_RT("Logger") DTR_RT("Lost Comms") DTR_RT("Lost Comms Monitor") DTR_RT("MCD4R") +DTR_RT("Magnetometer") DTR_RT("Mainboard") DTR_RT("Medium") DTR_RT("Message Fragments") @@ -71,10 +79,12 @@ DTR_RT("Motor Controller") DTR_RT("Multibeam") DTR_RT("Multiplexer Maneuver") DTR_RT("Navigation") +DTR_RT("OEMX") DTR_RT("Operational Limits") DTR_RT("Oxygen Sensor") DTR_RT("PTUD48") DTR_RT("PTUTransport") +DTR_RT("PWM") DTR_RT("Panel") DTR_RT("Panel Buttons") DTR_RT("Path Control") @@ -90,12 +100,14 @@ DTR_RT("Power Board") DTR_RT("Power Source") DTR_RT("Power Supervisor") DTR_RT("Power Supply") +DTR_RT("Radio") DTR_RT("Ranger") DTR_RT("Recovery Supervisor") DTR_RT("Remote Control") DTR_RT("Remote Operation") DTR_RT("Report Supervisor") DTR_RT("Rows Coverage Maneuver") +DTR_RT("SADC") DTR_RT("Service Announcer") DTR_RT("Service Discovery") DTR_RT("Servo Controller") @@ -109,6 +121,8 @@ DTR_RT("Sound Speed Simulator") DTR_RT("Speed Control") DTR_RT("Starboard Bow Motor") DTR_RT("Starboard Stern Motor") +DTR_RT("Stream Velocity Simulator") +DTR_RT("TCP On Demand") DTR_RT("TCP Server") DTR_RT("TCP to Camera CPU") DTR_RT("TCP to Master") @@ -116,11 +130,12 @@ DTR_RT("TCP to Slave CPU") DTR_RT("TREX") DTR_RT("Teleoperation Maneuver") DTR_RT("Text Message Parser") +DTR_RT("Thermal Zone") +DTR_RT("UART Serial") DTR_RT("UAV Simulator") DTR_RT("UAVCamera") DTR_RT("UDP") DTR_RT("UDP to TREX") DTR_RT("USBL") -DTR_RT("Underwater Acoustics Simulator") DTR_RT("Vehicle Supervisor") DTR_RT("Water Quality Sensor") diff --git a/i18n/pt_PT/LC_MESSAGES/dune.po b/i18n/pt_PT/LC_MESSAGES/dune.po index 8a85638158..23fee48aa7 100644 --- a/i18n/pt_PT/LC_MESSAGES/dune.po +++ b/i18n/pt_PT/LC_MESSAGES/dune.po @@ -1,5 +1,5 @@ # ########################################################################## -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # # ########################################################################## # This file is part of DUNE: Unified Navigation Environment. # @@ -28,7 +28,7 @@ msgid "" msgstr "" "Project-Id-Version: DUNE\n" "Report-Msgid-Bugs-To: dune@lsts.pt\n" -"POT-Creation-Date: 2016-10-19 17:37+0100\n" +"POT-Creation-Date: 2020-01-10 19:01+0000\n" "PO-Revision-Date: 2015-12-16 11:34+0000\n" "Last-Translator: Ricardo Martins \n" "Language-Team: DUNE \n" @@ -39,2466 +39,2900 @@ msgstr "" "X-Generator: Poedit 1.8.6\n" "X-Poedit-SourceCharset: UTF-8\n" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Driver.hpp:126 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:47 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:59 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:129 +msgid "SIM card number: %s" +msgstr "número do cartão SIM: %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:176 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:61 msgid "unknown error" msgstr "erro desconhecido" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Driver.hpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:186 #, c-format msgid "SMS transmission failed with error code %d" msgstr "transmissão de SMS falhou com código de erro %d" -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/NodeAddress.hpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:381 +#, c-format +msgid "received IMC message of type %s via SMS" +msgstr "recebida mensagem IMC do tipo %s via SMS" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Driver.hpp:386 +msgid "Parsing unrecognized Base64 message as text" +msgstr "A analisar mensagem Base64 não reconhecida como texto" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/NodeAddress.hpp:64 #, c-format msgid "invalid address: '%s'" msgstr "endereço inválido: '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Exceptions.hpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Exceptions.hpp:49 #, c-format msgid "invalid SBD size %u" msgstr "tamanho SBD inválido %u" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Exceptions.hpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Exceptions.hpp:60 #, c-format msgid "invalid SBD write %s" msgstr "escrita de SBD inválida %s" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:209 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:211 msgid "error ocurred while clearing MO buffer" msgstr "ocorreu um erro ao limpar o espaço de memória MO" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:220 msgid "error ocurred while clearing MT buffer" msgstr "ocorreu um erro ao limpar o espaço de memória MT" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:333 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:335 #, c-format msgid "invalid unsolicited string %s" msgstr "palavra não solicitada inválida: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:349 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:351 msgid "new session result will overwrite previously unread value" msgstr "resultado nova sessão vai sobrepôr valor anterior não lido" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:404 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:406 msgid "error ocurred while clearing buffer" msgstr "ocorreu um erro a limpar espaço de memória" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Driver.hpp:412 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Driver.hpp:414 msgid "error ocurred while clearing the MOMSN" msgstr "ocorreu um erro ao limpar o MOMSN" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Driver.hpp:197 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:250 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/AIS/Task.cpp:232 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:165 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:757 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MiniSVS/Task.cpp:136 +msgid "I/O error" +msgstr "erro de entrada/saída" + +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:121 msgid "request doesn't match" msgstr "pedido não coincide" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:150 #, c-format msgid "reply to maneuver %s has timed out" msgstr "resposta à manobra %s excedeu timeout" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:150 msgid "stop" msgstr "parar" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:150 msgid "start" msgstr "arrancar" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:151 msgid "system may need maintenance" msgstr "sistema pode precisar de manutenção" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:198 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:200 msgid "already executing, cannot start without stopping" msgstr "já a executar, não é possível começar sem parar" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:234 -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/ManeuverSupervisor.hpp:242 msgid "undefined state" msgstr "estado indefinido" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/PopUp.hpp:281 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/PopUp.hpp:283 msgid "relocated station keeping" msgstr "posição estacionária relocalizada" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Dislodge.hpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Dislodge.hpp:202 msgid "dislodge failed" msgstr "libertação falhou" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Dislodge.hpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Dislodge.hpp:270 msgid "trying again to dislodge" msgstr "a tentar libertar novamente" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/ScheduledGoto.hpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Sample.hpp:109 +msgid "sample failed" +msgstr "amostra falhou" + +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/ScheduledGoto.hpp:111 msgid "Unable to reach destination on scheduled time." msgstr "Incapaz de atingir destino no tempo previsto." -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Elevator.hpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Elevator.hpp:155 msgid "vertical progress is too slow" msgstr "progresso na vertical é demasiado lento" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/CommandLink.hpp:108 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/CommandLink.hpp:110 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:85 msgid "failed to set range" msgstr "falha ao definir distância" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/CommandLink.hpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/CommandLink.hpp:138 msgid "failed to get range" msgstr "falha ao obter distância" -#: /home/maria/LSTS/dune/dune/src/Sensors/XR620CTD/Parser.hpp:201 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XR620CTD/Parser.hpp:203 #, c-format msgid "character value '%d' is not a valid nibble" msgstr "valor de caráter '%d' não é um \"nibble\" válido" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Reader.hpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:429 +msgid "failed to enter command mode" +msgstr "falha ao entrar em modo de comando" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:450 +msgid "failed to set sampling rate" +msgstr "falha ao configurar taxa de amostragem" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Driver.hpp:111 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XchangeSV/Task.cpp:139 +msgid "failed to enter monitor mode" +msgstr "falha ao entrar em modo de monitorização" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Reader.hpp:86 msgid "invalid read size" msgstr "tamanho de leitura inválido" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.hpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.hpp:66 msgid "parse error: " msgstr "erro ao processar: " -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:126 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:130 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:168 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:172 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:128 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:170 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:238 msgid "Total" msgstr "Total" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:131 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:133 msgid "Execution" msgstr "Execução" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:132 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:220 msgid "Calibration" msgstr "Calibração" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:145 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:256 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:147 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:258 msgid "Maneuver " msgstr "Manobra " -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:173 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:175 msgid "Hotel" msgstr "Hotel" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:176 msgid "Payload" msgstr "Payload" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:175 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:177 msgid "Motion" msgstr "Movimento" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:176 -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:50 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:178 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:57 msgid "IMU" msgstr "IMU" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Statistics.hpp:210 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Statistics.hpp:212 msgid "Prediction Error" msgstr "Erro de Previsão" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:59 msgid "unexpected reply" msgstr "resposta inesperada" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:69 msgid "timeout while reading reply" msgstr "tempo limite atingido ao ler resposta" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:79 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:81 #, c-format msgid "buffer has %u bytes, needed %u" msgstr "trama tem %u \"bytes\", devia ter %u" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:94 #, c-format msgid "invalid checksum: should be %02X%02X but received %02X%02X" msgstr "verificação inválida: devia ser %02X%02X, mas foi recebido %02X%02X" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/Exceptions.hpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/Exceptions.hpp:107 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/DataStore/Task.cpp:188 #, c-format msgid "invalid format: %s" msgstr "formato inválido: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Math/General.hpp:214 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Math/General.hpp:216 msgid "piecewise linear interpolation needs equally sized vectors" msgstr "interpolação linear por partes precisa de vetores de tamanho igual" -#: /home/maria/LSTS/dune/dune/src/DUNE/Monitors/MotorCurrentMonitor.hpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Math/General.hpp:483 +msgid "Value out of range for finding factorial" +msgstr "Valor fora dos limites para encontrar factorial" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Monitors/MotorCurrentMonitor.hpp:54 msgid "motor monitor error: " msgstr "erro no monitor do motor: " -#: /home/maria/LSTS/dune/dune/src/DUNE/Monitors/MotorCurrentMonitor.hpp:97 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Monitors/MotorCurrentMonitor.hpp:99 msgid "number of linear points is not even" msgstr "número de pontos não é par" -#: /home/maria/LSTS/dune/dune/src/DUNE/Exceptions.hpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Exceptions.hpp:65 #, c-format msgid "feature not implemented '%s'" msgstr "funcionalidade não implementada '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BeamFilter.hpp:221 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:93 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:96 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:112 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:129 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:132 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:135 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:138 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:210 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:213 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:222 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:225 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BeamFilter.hpp:225 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:95 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:98 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:131 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:137 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:140 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:212 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:224 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:227 msgid "invalid dimensions" msgstr "dimensões inválidas" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:117 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:182 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:200 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:246 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.hpp:258 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:180 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:234 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:243 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:252 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:261 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:270 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:286 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:295 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:311 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:320 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:248 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.hpp:260 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:182 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:245 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:254 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:263 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:272 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:288 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:313 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:322 msgid "invalid index" msgstr "índice inválido" -#: /home/maria/LSTS/dune/dune/src/DUNE/IMC/Exceptions.hpp:125 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/IMC/Exceptions.hpp:127 #, c-format msgid "invalid message size %u" msgstr "tamanho de mensagem inválido %u" -#: /home/maria/LSTS/dune/dune/src/DUNE/IMC/InlineMessage.hpp:103 -#: /home/maria/LSTS/dune/dune/src/DUNE/IMC/InlineMessage.hpp:112 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/IMC/InlineMessage.hpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/IMC/InlineMessage.hpp:114 msgid "dereference of null inline message" msgstr "acesso a mensagem \"inline\" nula" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.hpp:170 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.hpp:172 #, c-format msgid "yaw control mode %d not supported" msgstr "modo de controlo azimute %d não é suportado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.hpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.hpp:182 #, c-format msgid "vertical control mode %d not supported" msgstr "modo de controlo vertical %d não é suportado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:51 #, c-format msgid "unable to resolve hostname '%s'" msgstr "não foi possível resolver hostname '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:60 #, c-format msgid "invalid network address '%s'" msgstr "endereço de rede inválido '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:77 #, c-format msgid "network unreachable '%s'" msgstr "rede inacessível '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:86 #, c-format msgid "host unreachable '%s'" msgstr "anfitrião inacessível '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:93 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:95 msgid "connection error" msgstr "erro de ligação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:103 msgid "connection closed" msgstr "ligação terminada" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/Exceptions.hpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/Exceptions.hpp:111 msgid "connection timeout" msgstr "atingido tempo limite da ligação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:157 -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:159 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:198 msgid "DBG" msgstr "DPR" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:170 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:172 msgid "ERR" msgstr "ERR" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:181 msgid "WRN" msgstr "AVS" -#: /home/maria/LSTS/dune/dune/src/DUNE/Streams/Terminal.hpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Streams/Terminal.hpp:190 msgid "MSG" msgstr "MSG" -#: /home/maria/LSTS/dune/dune/src/DUNE/Parsers/PlanConfigParser.hpp:285 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/PlanConfigParser.hpp:287 #, c-format msgid "invalid z unit: %s" msgstr "unidade de Z inválida: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Parsers/Config.hpp:136 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/Config.hpp:143 #, c-format msgid "unable to convert the value under section '%s' option '%s' to the required type and no valid default was given" msgstr "incapaz de converter o valor da secção '%s' opção '%s' para o tipo exigido e não foi fornecido valor por defeito" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:60 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:62 msgid "invalid entity label: " msgstr "etiqueta de entidade inválida: " -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:66 msgid "entity labels cannot be empty" msgstr "etiqueta de entidades não podem ser vazias" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:73 msgid "nonexistent entity label: " msgstr "etiqueta de entidade inexistente: " -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:80 msgid "invalid entity id: " msgstr "identificação de identidade inválida: " -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/EntityDataBase.hpp:85 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/EntityDataBase.hpp:87 msgid "an unique id was already reserved for entity label: " msgstr "já tinha sido reservado um id único para a etiqueta de entidade: " -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:75 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:168 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:77 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:174 msgid "value is not of the correct type" msgstr "o valor não é do tipo correto" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:94 msgid "possible values are not of the correct type" msgstr "os valores possíveis não são do tipo correto" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:115 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:101 +msgid "minimum value is not of the correct type" +msgstr "valor mínimo não é do tipo correto" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:110 +msgid "maximum value is not of the correct type" +msgstr "valor máximo não é do tipo correto" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:121 msgid "value is below minimum" msgstr "valor abaixo do mínimo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:121 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:127 msgid "value is above maximum" msgstr "valor acima do máximo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:127 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:133 msgid "value not in values set" msgstr "valor não pertence ao conjunto de valores" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:199 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:205 msgid "too few elements" msgstr "número insuficiente de elementos" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/BasicParameterParser.hpp:205 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/BasicParameterParser.hpp:211 msgid "too many elements" msgstr "demasiados elementos" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Exceptions.hpp:100 -#: /home/maria/LSTS/dune/dune/src/Supervisors/Delegator/Task.cpp:106 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Exceptions.hpp:102 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Delegator/Task.cpp:108 #, c-format msgid "invalid task name '%s'" msgstr "nome de tarefa inválido '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Exceptions.hpp:113 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Exceptions.hpp:115 #, c-format msgid "invalid value '%s' for parameter '%s': '%s'" msgstr "valor inválido '%s' para parâmetro '%s': '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/ParameterTable.hpp:80 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/ParameterTable.hpp:82 msgid "variable does not exist" msgstr "variável inexistente" -#: /home/maria/LSTS/dune/dune/src/DUNE/System/Error.hpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/System/Error.hpp:176 msgid "retrieving system error messages is not supported" msgstr "receber mensagens de erro de sistema não suportado" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/HTTPClient.hpp:122 -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/HTTPClient.hpp:178 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/StreamGeneratorFactory.hpp:77 +msgid "Unknown stream velocity source type." +msgstr "Tipo de source do stream velocity desconhecido." + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Driver.hpp:218 +msgid "" +"Message sent: \n" +"%s" +msgstr "" +"Mensagem enviada: \n" +"%s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Driver.hpp:245 +msgid "Unexpected simulation message: %s" +msgstr "Mensagem de simulação inesperada: %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Driver.hpp:252 +msgid "Read error: %s" +msgstr "Erro de leitura: %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/HTTPClient.hpp:124 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/HTTPClient.hpp:180 msgid "timed out while waiting for reply" msgstr "tempo limite atingido à espera de resposta" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/GVSP.hpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/GVSP.hpp:173 msgid "buffer overrun" msgstr "espaço de dados excedido" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/GVSP.hpp:192 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/GVSP.hpp:194 msgid "null frame" msgstr "trama inválida" -#: /home/maria/LSTS/dune/dune/src/Main/Launcher.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Launcher.cpp:135 msgid "daemon process no longer exists" msgstr "processo de arranque não existe mais" -#: /home/maria/LSTS/dune/dune/src/Main/Launcher.cpp:169 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Launcher.cpp:171 msgid "execution aborted" msgstr "execução abortada" -#: /home/maria/LSTS/dune/dune/src/Main/Launcher.cpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Launcher.cpp:173 msgid "daemon crashed with signal " msgstr "processo de arranque caiu com sinal " -#: /home/maria/LSTS/dune/dune/src/Main/Daemon.cpp:164 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Daemon.cpp:183 msgid "stopping tasks" msgstr "a parar tarefas" -#: /home/maria/LSTS/dune/dune/src/Main/Daemon.cpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Daemon.cpp:194 msgid "unhandled exception" msgstr "exceção não tratada" -#: /home/maria/LSTS/dune/dune/src/Main/Daemon.cpp:251 +#: /home/maria/LSTS/temp/dune-master/source/src/Main/Daemon.cpp:280 msgid "ERROR: no configuration file was given, see options --config-list and --config-file\n" msgstr "ERRO: nenhum ficheiro de configuração foi dado, ver opções --config-list e --config-file\n" -#: /home/maria/LSTS/dune/dune/src/Transports/Evologics/Task.cpp:519 -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:660 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Evologics/Task.cpp:521 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1086 #, c-format msgid "invalid system name %s" msgstr "nome de sistema inválido %s" -#: /home/maria/LSTS/dune/dune/src/Transports/SerialOverTCP/Task.cpp:167 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/SerialOverTCP/Task.cpp:169 msgid "accepting connection request" msgstr "a aceitar pedido de ligação" -#: /home/maria/LSTS/dune/dune/src/Transports/Iridium/Task.cpp:218 -msgid "error while parsing Iridium message" -msgstr "erro ao interpretar mensagem Iridium" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Iridium/Task.cpp:230 +msgid "Parsing unrecognized iridium message as text" +msgstr "Parsing não reconhecido mensagem iridium como texto" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCPOnDemand/Task.cpp:135 +msgid "TCPRequest timeout cannot be zero" +msgstr "O timeout do TCPRequest não pode ser zero" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCPOnDemand/Task.cpp:141 +msgid "TCPRequest timeout cannot be less than current time" +msgstr "O timeout do TCPRequest não pode ser menor do que a hora actual" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCPOnDemand/Task.cpp:158 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:155 +#, c-format +msgid "connected to %u clients" +msgstr "ligado a %u clients" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:199 msgid "operation not supported" msgstr "operação não suportada" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:204 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:237 msgid "is not a regular file" msgstr "este ficheiro é irregular" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:251 msgid "could not open" msgstr "não foi possível abrir" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:230 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:263 msgid "deserialization error" msgstr "erro de desserialização" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:237 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:270 msgid "empty LSF file" msgstr "ficheiro LSF vazio" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:244 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:277 msgid "invalid LSF file for replay" msgstr "ficheiro LSF inválido para repetição" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:269 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:315 msgid "started replay of" msgstr "iniciou a repetição de" -#: /home/maria/LSTS/dune/dune/src/Transports/Replay/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Replay/Task.cpp:345 msgid "stopped replay" msgstr "repetição parada" -#: /home/maria/LSTS/dune/dune/src/Transports/HTTP/Task.cpp:114 -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:120 -#: /home/maria/LSTS/dune/dune/src/Transports/FTP/Task.cpp:103 -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:253 -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/HTTP/Task.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:122 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/FTP/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:107 #, c-format msgid "listening on %s:%u" msgstr "a ouvir em %s:%u" -#: /home/maria/LSTS/dune/dune/src/Transports/HTTP/Task.cpp:142 -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:250 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/HTTP/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:258 msgid "failed to find one available port" msgstr "não foi possível encontrar uma porta disponível" -#: /home/maria/LSTS/dune/dune/src/Transports/UAN/Task.cpp:627 -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:244 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UAN/Task.cpp:795 +msgid "ignoring abort message addressed to other system" +msgstr "a ignorar mensagem de abort endereçada a outros sistemas" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UAN/Task.cpp:799 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:246 msgid "got abort request" msgstr "recebido pedido abort" -#: /home/maria/LSTS/dune/dune/src/Transports/UAN/Task.cpp:763 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:932 -msgid "start plan detected" -msgstr "detetado arranque de plano" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UAN/Task.cpp:873 +msgid "start plan detected with id: %s for 0x%02X" +msgstr "detectado arranque de plano com id: %s for 0x%02X" -#: /home/maria/LSTS/dune/dune/src/Transports/Cache/Task.cpp:258 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Cache/Task.cpp:260 #, c-format msgid "failed to copy cache snapshot: %s" msgstr "falhou a copiar o snapshot da cache: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:161 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:437 -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:147 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1059 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:40 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:262 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:445 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1065 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:42 msgid "initializing" msgstr "a iniciar" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:163 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:441 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:41 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:264 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:449 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:43 msgid "idle" msgstr "em espera" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:165 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:443 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:42 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:266 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:451 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:44 msgid "active" msgstr "ativo" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:167 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:445 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:453 msgid "serial port communication error, modem not responding" msgstr "erro comunicação de porta série, modem não responde" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:169 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:447 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:270 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:455 msgid "failed to configure modem, possible serial port communication error" msgstr "falhou configuração de modem, possível erro de comunicação porta série" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:321 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:525 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:454 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:411 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:427 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:534 #, c-format msgid "modem address for agent '%s' is invalid" msgstr "endereço modem para agente '%s' é inválido" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:367 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:520 msgid "failed to configure device" msgstr "falha ao configurar dispositivo" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:413 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:534 +#, c-format +msgid "Beacon id=%d | HW P#%d (rev#%d) serial#%d | FW P#%d v%d.%d.%d | App P#%d v%d.%d.%d | %s USBL beacon" +msgstr "Beacon id=%d | HW P#%d (rev#%d) serial#%d | FW P#%d v%d.%d.%d | App P#%d v%d.%d.%d | %s USBL beacon" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:592 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:658 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:441 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:374 +msgid "failed to set hard-iron correction factors" +msgstr "falha ao definir factores de correção \"hard-iron\"" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:632 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:637 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:642 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:704 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:485 +msgid "different calibration parameters" +msgstr "valores de calibração diferentes" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:706 msgid "Sending stopped: Communication out of water forbidden." msgstr "Envio parado: Comunicação fora de água proíbida." -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:473 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:719 +#, c-format +msgid "Send command to the acoustic modem %s" +msgstr "Enviado comando para o modem acústico %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:721 +msgid "Sent done" +msgstr "Enviado terminado" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:747 +#, c-format +msgid "Success transmission complete (part %d of %d) for ticket %d (in %f s)" +msgstr "Transmissão completada com sucesso (parte %d de %d) para o bilhete %d (em %f s)" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:757 +#, c-format +msgid "Sending (handleBinaryMessage) part %d of %d for ticket %d will take up to %f s for %d bytes" +msgstr "A enviar (handleBinaryMessage) parte %d de %d para bilhete %d demorará %f s para %d bytes" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:774 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1310 +#, c-format +msgid "Msg transmission complete for ticket %d (in %f s)" +msgstr "Transmissão de mensagem completa para bilhete %d (em %f s)" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:794 msgid "wrong message order" msgstr "ordem de mensagens errada" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:595 -msgid "Communication failed" -msgstr "Falha de Comunicação" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:919 +#, c-format +msgid "Error sending (handleCommunicationError) part %d of %d for ticket %d, resending" +msgstr "Erro a enviar (handleCommunicationError) parte %d de %d para bilhete %d, a reenviar" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:927 +msgid "Communication failed for ticket %d %d" +msgstr "Falha comunicação para o bilhete %d %d" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:705 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:935 +#, c-format +msgid "Next msg or part send to son for ticket %d with ERROR" +msgstr "Próxima mensagem ou parte enviada para filho para bilhete %d com ERRO" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1055 +#, c-format +msgid "Received UamTxFrame with dst=0x%04X. Msg for system '%s'" +msgstr "Recebido UamTxFrame com dst=0x%04X. Mensagem para o systema '%s'" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1071 +#, c-format +msgid "Creating ticket %d" +msgstr "A criar bilhete %d" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1076 +#, c-format +msgid "Sending UamTxStatus::UTS_INV_ADDR. Ticket %d died" +msgstr "A enviar UamTxStatus::UTS_INV_ADDR. Bilhete %d extinto" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1095 +#, c-format +msgid "Sending UamTxStatus::UTS_BUSY. Ticket %d died" +msgstr "A enviar UamTxStatus::UTS_BUSY. Bilhete %d extinto" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1102 +#, c-format +msgid "Sending UamTxStatus::UTS_IP. Ticket %d being processed" +msgstr "A enviar UamTxStatus::UTS_IP. Bilhete %d a ser processado" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1118 +msgid "Configuration as %s %s" +msgstr "Configuração como %s %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1126 +msgid "Configuration as ONEWAY %s" +msgstr "Configuração definida como ONEWAY %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1135 msgid "device is busy" msgstr "dispositivo ocupado" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:708 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1138 msgid "previous message failed, timeout detected" msgstr "mensagem anterior falhou, detetado timeout" -#: /home/maria/LSTS/dune/dune/src/Transports/Seatrac/Task.cpp:711 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1141 msgid "size mismatch" msgstr "incompatibilidade de tamanho" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:106 -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:243 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1145 +#, c-format +msgid "Sending package %f s" +msgstr "A enviar pacote %f s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1146 +#, c-format +msgid "Sending (consume UamTxFrame) part %d of %d for ticket %d will take up to %f s for %d bytes" +msgstr "A enviar (consume UamTxFrame) parte %d de %d para bilhete %d demorará %f s para %d bytes" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1272 +#, c-format +msgid "Calc new timer (bytes %d | bit-rate %f | max-range %d m | multiplier %d) calculated to %f s" +msgstr "A calcular novo timer (bytes %d | bit-rate %f | max-range %d m | multiplier %d) calculado para %f s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1291 +#, c-format +msgid "NOACK Success transmission complete (part %d of %d) for ticket %d (in %f s)" +msgstr "NOACK transmissão concluída com sucesso (parte %d de %d) para bilhete %d (em %f s)" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1300 +#, c-format +msgid "Sending (checkTxOWAY) part %d of %d for ticket %d will take up to %f s for %d bytes" +msgstr "A enviar (checkTxOWAY) parte %d de %d para bilhete %d demorará %f s para %d bytes" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Seatrac/Task.cpp:1323 +#, c-format +msgid "ACK TIMEOUT: Msg transmission with ack for ticket %d timeout ACK. Lets bail with error!! (%f s > %f s)" +msgstr "ACK TIMEOUT: Transmissão de mensagem com ACK para bilhete %d timeout ACK. A saltar fora com erro!! (%f s > %f s)" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/CommManager/Task.cpp:201 +msgid "ERROR Initializing CommManager. Couldn't resolve GSM label." +msgstr "ERRO Inicialização CommManager. Etiqueta GSM por resolver." + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/CommManager/Task.cpp:211 +msgid "ERROR Initializing CommManager. Couldn't resolve Iridium label." +msgstr "ERRO Inicialização CommManager. Etiqueta Iridium por resolver." + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:108 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:251 #, c-format msgid "failed to bind to port %u: %s" msgstr "falhou a associar porto %u: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:113 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:115 msgid "could not bind server socket" msgstr "não foi possível associar socket do servidor" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:153 -#, c-format -msgid "connected to %u clients" -msgstr "ligado a %u clients" - -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Server/Task.cpp:254 -#: /home/maria/LSTS/dune/dune/src/Transports/FTP/Task.cpp:187 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Server/Task.cpp:256 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/FTP/Task.cpp:189 #, c-format msgid "error accepting new client connection: %s" msgstr "erro ao aceitar ligação a novo cliente: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/TCP/Client/Task.cpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/TCP/Client/Task.cpp:86 #, c-format msgid "connected to %s:%u" msgstr "ligado a %s:%u" -#: /home/maria/LSTS/dune/dune/src/Transports/Serial/Task.cpp:109 -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:255 -#: /home/maria/LSTS/dune/dune/src/Simulators/UnderwaterAcoustics/Task.cpp:388 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Serial/Task.cpp:111 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:359 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:257 #, c-format msgid "read error: %s" msgstr "erro de leitura: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/Serial/Task.cpp:115 -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Serial/Task.cpp:117 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:305 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:367 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:263 msgid "unknown read error" msgstr "erro de leitura desconhecido" -#: /home/maria/LSTS/dune/dune/src/Transports/LoggingDigest/Task.cpp:194 -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:412 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/LoggingDigest/Task.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:414 #, c-format msgid "failed to start log, check available storage: %s" msgstr "falha ao começar registo, verifique espaço disponível: %s'" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:198 -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:205 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:265 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:226 msgid "input error" msgstr "erro de entrada" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:206 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:294 msgid "SMS timeout cannot be zero" msgstr "o timeout da SMS não pode ser zero" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:234 -#, c-format -msgid "discarded expired SMS to recipient '%s'" -msgstr "descartada SMS expirada para o destinatário '%s'" +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:300 +msgid "Can only send 160 characters over SMS" +msgstr "Apenas 160 caracteres podem ser enviados por SMS" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:305 +msgid "SMS sent to queue" +msgstr "SMS enviada para fila" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:344 +msgid "SMS timeout" +msgstr "Timeout SMS" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:345 +msgid "discarded expired SMS to recipient %s" +msgstr "descartada SMS expirada para o destinatário %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:360 +msgid "Error sending message over GSM modem" +msgstr "Erro ao enviar mensagem pelo modem GSM" -#: /home/maria/LSTS/dune/dune/src/Transports/GSM/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:361 +msgid "Error sending SMS to recipient %s" +msgstr "Erro ao enviar SMS para o destinatário %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/GSM/Task.cpp:384 #, c-format msgid "failed to poll status: %s" msgstr "falha ao verificar estado: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:377 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:395 #, c-format msgid "activating transmission to node '%s'" msgstr "a ativar transmissão para o nó '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/UDP/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/UDP/Task.cpp:400 #, c-format msgid "deactivating transmission to node '%s'" msgstr "a desativar transmissão para o nó '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/Fragments/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Fragments/Task.cpp:107 #, c-format msgid "Removed incoming message from memory (%d fragments were still missing)." msgstr "Removida mensagem recebida da memória (ainda faltam %d fragmentos)." -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:145 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:162 msgid "GSM/GPRS username" msgstr "Nome de Utilizador GSM/GPRS" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:151 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:168 msgid "GSM/GPRS password" msgstr "Password GSM/GPRS" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:157 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:174 msgid "GSM/GPRS Access Point Name (APN)" msgstr "Nome do Ponto de Acesso (APN) GSM/GPRS" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:163 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:180 msgid "GSM/GPRS pin." msgstr "Pin GSM/GPRS." -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:298 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:360 msgid "failed to execute connect command" msgstr "falha ao executar comando de conexão" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:310 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:376 msgid "failed to execute disconnect command" msgstr "falha ao executar comando de desconexão" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:340 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:406 msgid "failed to start NAT" msgstr "falha ao arrancar NAT" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:350 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:416 msgid "failed to stop NAT" msgstr "falha ao parar NAT" -#: /home/maria/LSTS/dune/dune/src/Transports/MobileInternet/Task.cpp:425 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:430 +msgid "failed to update dynamic DNS" +msgstr "falha ao atualizar DNS dinâmico" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/MobileInternet/Task.cpp:510 #, c-format msgid "connected to the Internet with public address '%s'" msgstr "ligado à Internet com o endereço público '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/LogBook/Task.cpp:98 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/LogBook/Task.cpp:100 msgid "cleared logbook" msgstr "livro de registo limpo" -#: /home/maria/LSTS/dune/dune/src/Transports/LogBook/Task.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/LogBook/Task.cpp:103 msgid "invalid or unsupported command" msgstr "parâmetro inválido ou não suportado" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:125 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:133 msgid "task is shutting down" msgstr "a tarefa está a desligar" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:281 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:287 +msgid "Message sent successfully." +msgstr "Mensagem enviada com sucesso." + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:304 #, c-format msgid "failed with error %u" msgstr "falha com erro %u" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:301 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:324 #, c-format msgid "invalid SBD message of size %u" msgstr "tamanho de mensagem SBD inválido %u" -#: /home/maria/LSTS/dune/dune/src/Transports/IridiumSBD/Task.cpp:319 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:342 #, c-format msgid "transmission failed: %s" msgstr "transmissão falhada: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:187 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/IridiumSBD/Task.cpp:407 +msgid "No message to be received or sent." +msgstr "Nenhuma mensagem por receber ou enviar." + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:189 #, c-format msgid "failed to remove cache snapshot: %s" msgstr "falhou a remover o snapshots da cache: %s" -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:318 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:320 #, c-format msgid "log stopped '%s'" msgstr "registo parado '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/Logging/Task.cpp:363 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Logging/Task.cpp:365 #, c-format msgid "log started '%s'" msgstr "registo iniciado '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:113 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:235 +msgid "UAV high speed Reports Periodicity" +msgstr "Periodicidade relatórios UAV alta velocidade" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:421 +msgid "Vehicle to bind is not define" +msgstr "Veículo para conexão não está definido" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:434 +msgid "Invalid communication mode" +msgstr "Mode de comunicação inválido" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:453 +msgid "Invalid radio model" +msgstr "Modelo de rádio inválido" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:585 +msgid "No Radio device on port: %s" +msgstr "Nenhum dispositivo rádio na porta: %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Radio/Task.cpp:603 +#, c-format +msgid "Radio configuration failed. Wrong parameter or device on port %s is not a radio " +msgstr "Configuração do rádio falhou. Parâmetro errado ou dispositivo ligado na porta %s não é um rádio" + +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:115 msgid "no available ports to listen to advertisements" msgstr "não existem portas disponíveis para anúncios" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:126 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:128 msgid "discarding spurious message" msgstr "a descartar mensagem espúria" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:135 #, c-format msgid "discarding spurious message '%s'" msgstr "a descartar mensagem espúria '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:190 #, c-format msgid "new node within range '%s' / %u / %s" msgstr "novo nó ao alcance '%s' / %u / %s" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:199 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:201 #, c-format msgid "another node on this computer is advertising our node name '%s'" msgstr "outro nó neste computador está a anunciar o nosso nome '%s'" -#: /home/maria/LSTS/dune/dune/src/Transports/Discovery/Task.cpp:201 +#: /home/maria/LSTS/temp/dune-master/source/src/Transports/Discovery/Task.cpp:203 #, c-format msgid "another node on our network is advertising our node name '%s'" msgstr "outro nó na nossa rede está a anunciar o nosso nome '%s'" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv2/Task.cpp:177 -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:361 -#: /home/maria/LSTS/dune/dune/src/Supervisors/SlaveCPU/Task.cpp:150 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:451 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:577 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:386 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv2/Task.cpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:363 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/SlaveCPU/Task.cpp:152 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:453 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:579 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:386 msgid "failed to contact device" msgstr "falha ao contactar dispositivo" -#: /home/maria/LSTS/dune/dune/src/Power/PSIMAR/Task.cpp:99 -#: /home/maria/LSTS/dune/dune/src/Power/LUEMB/Task.cpp:264 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:229 -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:200 -#: /home/maria/LSTS/dune/dune/src/Actuators/MCD4R/Task.cpp:340 -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:227 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:135 +msgid "Output pin - power status of raspberry" +msgstr "Pin de output - estado de energia da raspberry" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:139 +msgid "Input signal pin to order powerdown of raspberry" +msgstr "Sinal de pin de input para desligar raspberry" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:143 +msgid "Power 3g output status pin" +msgstr "Pin de output do estado da energia do 3g" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:147 +msgid "Output pin signal: to enable or disble 3g" +msgstr "Sinal pin de output: ligar ou desligar 3g" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:151 +msgid "Imput pin signal: to enable or disble 3g" +msgstr "Sinal pin de input: ligar ou desligar 3g" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:155 +msgid "Wifi level output status pins" +msgstr "Estado dos pinos de output do nível do Wifi" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:159 +msgid "Entity label of 'EntityState' Mobile Internet" +msgstr "Etiqueta da entidade de 'EntityState' Mobile Internet" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:165 +msgid "Time, in seconds, between RSSI polling." +msgstr "Tempo, em segundos, entre RSSI polling." + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:169 +msgid "LED wifi rssi threshold" +msgstr "Limite rssi do LED wifi" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/OPCON/Task.cpp:437 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:196 +msgid "EntityState message without source entity" +msgstr "mensagem EntityState sem entidade de origem" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:274 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:292 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:308 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:480 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:481 +msgid "trying connecting to board" +msgstr "a tentar estabelecer comunicação" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:152 +msgid "failed to get firmware version" +msgstr "falha ao obter versão do firmware" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:288 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:293 +msgid "failed to init BatMan" +msgstr "falha ao inciar BatMan" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:304 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/BATMANv2/Task.cpp:309 +msgid "failed to start acquisition" +msgstr "falha ao iniciar aquisição" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PSIMAR/Task.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/LUEMB/Task.cpp:266 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/MCD4R/Task.cpp:342 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:229 msgid "device is using unstable firmware" msgstr "o dispositivo está a usar \"firmware\" instável" -#: /home/maria/LSTS/dune/dune/src/Power/PSIMAR/Task.cpp:101 -#: /home/maria/LSTS/dune/dune/src/Power/LUEMB/Task.cpp:266 -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:528 -#: /home/maria/LSTS/dune/dune/src/Power/MCBv2/Task.cpp:612 -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:310 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:231 -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:202 -#: /home/maria/LSTS/dune/dune/src/Actuators/MCD4R/Task.cpp:342 -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:712 -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:229 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PSIMAR/Task.cpp:103 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/LUEMB/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:530 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/MCBv2/Task.cpp:614 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:312 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:242 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:204 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/MCD4R/Task.cpp:344 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:714 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:231 #, c-format msgid "firmware version %u.%u.%u" msgstr "versão de \"firmware\": %u.%u.%u" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:415 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMB/Task.cpp:239 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMBv2/Task.cpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/APD/Task.cpp:235 +msgid "Device is using unstable firmware!" +msgstr "O dispositivo está a usar \"firmware\" instável!" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMB/Task.cpp:241 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMBv2/Task.cpp:242 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/APD/Task.cpp:237 +#, c-format +msgid "Firmware version %u.%u.%u" +msgstr "Versão de \"firmware\": %u.%u.%u" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMB/Task.cpp:334 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/APD/Task.cpp:330 +msgid "Failed to send frame to APD. Check connection!" +msgstr "Falhou envio de \"frame\" à APD. Verificar conexão!" + +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:417 msgid "failed to update EEPROM" msgstr "erro ao atualizar a EEPROM" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:486 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:488 msgid "power down sequence aborted" msgstr "sequencia de desligar interrompida" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:567 -#: /home/maria/LSTS/dune/dune/src/Power/MCBv2/Task.cpp:588 -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:455 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:569 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/MCBv2/Task.cpp:590 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:457 msgid "device reported" msgstr "o dispositivo reportou" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:597 -#: /home/maria/LSTS/dune/dune/src/Monitors/Medium/Task.cpp:219 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:599 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:230 msgid "water" msgstr "água" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:597 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:599 msgid "air" msgstr "ar" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:607 -#: /home/maria/LSTS/dune/dune/src/Simulators/Leaks/Task.cpp:132 -#: /home/maria/LSTS/dune/dune/src/Simulators/Leaks/Task.cpp:147 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:609 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Leaks/Task.cpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Leaks/Task.cpp:149 msgid "leak detected" msgstr "fuga detetada" -#: /home/maria/LSTS/dune/dune/src/Power/PCTLv2/Task.cpp:614 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/PCTLv2/Task.cpp:616 msgid "no leak" msgstr "sem fugas" -#: /home/maria/LSTS/dune/dune/src/Power/APD/Task.cpp:233 -msgid "Device is using unstable firmware!" -msgstr "O dispositivo está a usar \"firmware\" instável!" - -#: /home/maria/LSTS/dune/dune/src/Power/APD/Task.cpp:235 -#, c-format -msgid "Firmware version %u.%u.%u" -msgstr "Versão de \"firmware\": %u.%u.%u" - -#: /home/maria/LSTS/dune/dune/src/Power/APD/Task.cpp:328 -msgid "Failed to send frame to APD. Check connection!" -msgstr "Falhou envio de \"frame\" à APD. Verificar conexão!" +#: /home/maria/LSTS/temp/dune-master/source/src/Power/CPMBv2/Task.cpp:335 +msgid "Failed to send frame to CPMB_v2. Check connection!" +msgstr "Falhou envio de frame à CPMB_v2. Verificar conexão!" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:252 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:254 msgid "failed to configure strobe mode" msgstr "falhou a configurar modo de strobe" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:256 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:258 #, c-format msgid "strobe mode set to: %s" msgstr "modo de strobe configurado para: %s" -#: /home/maria/LSTS/dune/dune/src/Power/DOAMv1/Task.cpp:256 -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:16 +#: /home/maria/LSTS/temp/dune-master/source/src/Power/DOAMv1/Task.cpp:258 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:18 msgid "Camera" msgstr "Câmara" -#: /home/maria/LSTS/dune/dune/src/Monitors/Collisions/Task.cpp:211 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:232 +msgid "Water detected using medium sensor." +msgstr "Água detectada pelo sensor de medium." + +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:275 +msgid "Water detected using salinity threshold." +msgstr "Água detectada pelo limite de salinidade." + +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Medium/Task.cpp:289 +msgid "Water detected using sound speed sensor." +msgstr "Água detectada pelo sensor de soundspeed." + +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Collisions/Task.cpp:215 #, c-format msgid "failed to resolve entity '%s': %s" msgstr "erro ao resolver entidade '%s': %s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Collisions/Task.cpp:366 -#: /home/maria/LSTS/dune/dune/src/Simulators/UnderwaterAcoustics/Task.cpp:253 -msgid "collision detected" -msgstr "colisão detetada" +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Collisions/Task.cpp:374 +msgid "Collision detected: %s" +msgstr "Colisão detetada: %s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:89 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:95 msgid "SMS Recipient Number" msgstr "Número de Destino de Mensagens SMS" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:98 msgid "Phone number of the SMS recipient" msgstr "Número de telefone do destinatário de mensagens SMS" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:105 msgid "Lost Communications Timeout" msgstr "Timeout de Perda de Comunicações" -#: /home/maria/LSTS/dune/dune/src/Monitors/Emergency/Task.cpp:305 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:379 +msgid "sending IridiumMsg (t:%u) to %s: %s" +msgstr "a enviar IridiumMsg (t:%u) para %s: %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Emergency/Task.cpp:388 #, c-format msgid "sending SMS (t:%u) to %s: %s" msgstr "a enviar SMS (t:%u) para %s: %s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:364 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:366 #, c-format msgid "potential fault in servo #%d: %s" msgstr "possível falha no servo #%d: %s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:395 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:397 #, c-format msgid "potential fault in servo #%d, current consumption above %0.1f A" msgstr "possível falha no servo #%d, consumo de corrente acima de %0.1f A" -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:431 -#: /home/maria/LSTS/dune/dune/src/Monitors/Servos/Task.cpp:433 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:433 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Servos/Task.cpp:435 #, c-format msgid "servo #%d may require supervision" msgstr "servo #%d poderá precisar de supervisão" -#: /home/maria/LSTS/dune/dune/src/Monitors/Clock/Task.cpp:177 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Clock/Task.cpp:179 #, c-format msgid "adjusting CPU clock by %0.4f s" msgstr "a ajustar relógio do CPU em %0.4f s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Clock/Task.cpp:214 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Clock/Task.cpp:216 msgid "failed to execute clock sync command" msgstr "falha ao executar comando de sincronização" -#: /home/maria/LSTS/dune/dune/src/Monitors/FuelLevel/Task.cpp:219 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/FuelLevel/Task.cpp:243 msgid "invalid model" msgstr "modelo inválido" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Boot" msgstr "Arranque" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Normal" msgstr "Normal" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Fault" msgstr "Falha" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Error" msgstr "Erro" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:45 msgid "Failure" msgstr "Falha" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:182 #, c-format msgid "can not monitor %s (%s), is there a task failure or a configuration error?" msgstr "incapaz de monitorizar %s (%s), haverá falha na tarefa ou erro de configuração?" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:194 -msgid "EntityState message without source entity" -msgstr "mensagem EntityState sem entidade de origem" - -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:218 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:220 #, c-format msgid "%s entity state is unstable (%s <-> %s), ignoring" msgstr "%s estado da entidade instável (%s <-> %s), a ignorar" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:228 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:230 #, c-format msgid "%s : State stabilized in %s | %s" msgstr "%s : estado da entidade estabilizou em %s | %s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:254 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:256 msgid "reconfiguration command issued" msgstr "comando de reconfiguração emitido" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:267 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:269 msgid "invalid reconfiguration command" msgstr "comando de reconfiguração inválido" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:305 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:307 #, c-format msgid "%s - monitoring enabled" msgstr "%s - monitorização habilitada" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:311 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:313 #, c-format msgid "%s - current state not normal - %s" msgstr "%s - estado atual não normal - %s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:315 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:317 #, c-format msgid "%s - monitoring previously enabled" msgstr "%s - monitorização previamente habilitada" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:328 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:330 #, c-format msgid "%s - monitoring disabled" msgstr "%s - monitorização desabilitada" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:335 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:337 #, c-format msgid "%s - monitoring previously disabled" msgstr "%s - monitorização previamente desabilitada" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:359 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:361 #, c-format msgid "entity %s: %s" msgstr "entidade %s: %s" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:433 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:435 #, c-format msgid "%s -- status not reported after %0.2f seconds" msgstr "%s -- estado não foi reportado depois de %0.2f segundos" -#: /home/maria/LSTS/dune/dune/src/Monitors/Entities/Task.cpp:436 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/Entities/Task.cpp:438 #, c-format msgid "%s: entity state timeout" msgstr "%s: tempo limite excedido à espera do estado da entidade" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:262 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:264 #, c-format msgid "%s -- operational limit breached: %0.2f > %0.2f" msgstr "%s -- limite de operação violado: %0.2f > %0.2f" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:277 #, c-format msgid "%s -- operational limit now sane: %0.2f <= %0.2f" msgstr "%s -- limite de operação já está são: %0.2f <= %0.2f" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:353 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:355 msgid "minimum speed" msgstr "velocidade mínima" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:354 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:356 msgid "maximum speed" msgstr "velocidade máxima" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:355 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:357 msgid "depth" msgstr "profundidade" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:356 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:358 msgid "vertical rate" msgstr "taxa vertical" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:360 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:362 msgid "maximum altitude" msgstr "altitude máxima" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:361 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:363 msgid "minimum altitude" msgstr "altitude mínima" -#: /home/maria/LSTS/dune/dune/src/Monitors/OperationalLimits/Task.cpp:392 +#: /home/maria/LSTS/temp/dune-master/source/src/Monitors/OperationalLimits/Task.cpp:394 msgid "Operational Area" msgstr "Área Operacional" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:48 msgid "SERVICE" msgstr "SERVIÇO" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:48 msgid "CALIBRATION" msgstr "CALIBRAÇÂO" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:49 msgid "ERROR" msgstr "ERRO" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:49 msgid "MANEUVERING" msgstr "MANOBRAR" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:50 msgid "EXTERNAL CONTROL" msgstr "CONTROLO EXTERNO" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:50 msgid "BOOT" msgstr "ARRANQUE" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:210 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:212 #, c-format msgid "now in '%s' mode" msgstr "agora no modo '%s'" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:356 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:358 msgid "entity errors cleared" msgstr "erros de entidades limpos" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:360 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:362 #, c-format msgid "vehicle errors: %s" msgstr "erros do veículo: %s" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:425 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:427 msgid " maneuver error: " msgstr " erro de manobra:" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:487 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:489 msgid "cannot calibrate: vehicle is in external mode" msgstr "não é possível calibrar: veículo está em modo de controlo externo" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:505 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:507 #, c-format msgid "performing maneuver %s while calibrating" msgstr "a realizar manobra %s durante calibração" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:512 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:514 #, c-format msgid "calibrating vehicle for %u seconds" msgstr "a calibrar veículo por %u segundos" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:530 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:532 msgid "cannot stop calibration: vehicle is not calibrating" msgstr "não é possível parar calibração: veículo não está a calibrar" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:534 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:536 msgid "stopped calibration" msgstr "calibração parada" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:550 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:552 msgid "no maneuver specified" msgstr "nenhuma manobra foi especificada" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:558 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:560 msgid " maneuver cannot be started in current mode" msgstr " manobras não podem ser iniciadas no modo atual" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:567 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:569 msgid " maneuver started" msgstr " manobra começada" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:598 -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:979 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:610 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:600 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:985 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:613 msgid "OK" msgstr "OK" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:629 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:631 msgid "this vehicle does not allow for external control, disabling loops" msgstr "este veículo não permite controlo externo, a desabilitar malhas de controlo" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:644 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:646 msgid "maneuver request timeout" msgstr "pedido de manobra excedeu o tempo limite" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Vehicle/Task.cpp:649 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Vehicle/Task.cpp:651 msgid "calibration timed out" msgstr "tempo de calibração expirou" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Reporter/Task.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:70 msgid "Acoustic Reports" msgstr "Relatórios Acústicos" -#: /home/maria/LSTS/dune/dune/src/Supervisors/Reporter/Task.cpp:69 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:75 msgid "Acoustic Reports Periodicity" msgstr "Periodicidade de Relatórios Acústicos" -#: /home/maria/LSTS/dune/dune/src/Supervisors/AUV/Assist/Task.cpp:289 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:83 +msgid "Radio Reports" +msgstr "Relatórios de Rádio" + +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/Reporter/Task.cpp:88 +msgid "Radio Reports Periodicity" +msgstr "Periodicidade de relatórios de rádio" + +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/AUV/Assist/Task.cpp:305 #, c-format msgid "failed to start %s plan" msgstr "falha ao arrancar plano %s" -#: /home/maria/LSTS/dune/dune/src/Supervisors/AUV/LostComms/Task.cpp:317 +#: /home/maria/LSTS/temp/dune-master/source/src/Supervisors/AUV/LostComms/Task.cpp:317 msgid "starting lost comms plan" msgstr "iniciar plano perda comunicações: " -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Task.cpp:383 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Task.cpp:448 msgid "unsupported maneuver" msgstr "manobra não suportada" -#: /home/maria/LSTS/dune/dune/src/Maneuver/Multiplexer/Task.cpp:392 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/Multiplexer/Task.cpp:457 msgid "wrong maneuver type" msgstr "tipo de manobra errado" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowSystem/Task.cpp:304 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowSystem/Task.cpp:306 msgid "timeout to receive new remote info was exceeded." msgstr "excedido timeout para receber nova info remota." -#: /home/maria/LSTS/dune/dune/src/Maneuver/CompassCalibration/Task.cpp:183 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CompassCalibration/Task.cpp:185 msgid "insufficient data for calibration" msgstr "dados insuficientes para calibração" -#: /home/maria/LSTS/dune/dune/src/Maneuver/CompassCalibration/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CompassCalibration/Task.cpp:190 #, c-format msgid "%s entity not calibrated. Calibration values with %d turns: %f, %f, 0.0" msgstr "Entidade %s não calibrada. Valores de calibração para %d voltas: %f, %f, 0.0" -#: /home/maria/LSTS/dune/dune/src/Maneuver/CompassCalibration/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CompassCalibration/Task.cpp:202 #, c-format msgid "forcing minimum of %.1f" msgstr "a forçar mínimo de %.1f" -#: /home/maria/LSTS/dune/dune/src/Maneuver/VehicleFormation/Coordinator/Task.cpp:1076 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/VehicleFormation/Coordinator/Task.cpp:1078 #, c-format msgid "Plan specification request failed with uncaught exception: %s" msgstr "pedido de especificação de plano falhou com excepção não capturada: %s" -#: /home/maria/LSTS/dune/dune/src/Maneuver/CoverArea/Task.cpp:349 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/CoverArea/Task.cpp:351 msgid "undefined area" msgstr "área indefinida" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:116 msgid "forcing control in meters per second" msgstr "a forçar controlo em metros por segundo" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:122 msgid "provided trajectory is not feasible by the current vehicle!" msgstr "trajetória não é exequível pelo veículo atual!" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:240 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:242 msgid "first point must be timed at 0.0" msgstr "primeiro ponto tem de ser temporizado a 0.0" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:251 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:253 msgid "required speed is above the maximum speed allowed" msgstr "velocidade pedida é acima da máxima velocidade permitida" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowTrajectory/Task.cpp:257 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowTrajectory/Task.cpp:259 #, c-format msgid "time difference between %d and %d is less than or equal to zero" msgstr "diferença temporal entre %d e %d é menor ou igual a zero" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:153 msgid "waiting for first reference" msgstr "à espera da primeira referência" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:223 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:228 #, c-format msgid "ignored reference from non-authorized source: %d" msgstr "ignorada referência de origem não autorizada: %d" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:232 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:237 #, c-format msgid "ignored reference from non-authorized entity: %d" msgstr "ignorada referência de entidade não autorizada: %d" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:579 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:616 #, c-format msgid "Z reference changed to %f" msgstr "Referência Z mudada para %f" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:588 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:625 #, c-format msgid "Speed reference changed to %f" msgstr "Referência de velocidade mudada para %f" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:594 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:631 #, c-format msgid "Loiter radius reference changed to %f" msgstr "Referência de raio de loiter mudada para %f" -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:608 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:645 #, c-format msgid "loitering around (%f, %f, %f, %f)." msgstr "em loiter em torno de (%f, %f, %f, %f)." -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:619 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:656 #, c-format msgid "loitering (elevator) towards (%f, %f, %f, %f)." msgstr "em loiter (elevador) em direção a (%f, %f, %f, %f)." -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:630 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:667 #, c-format msgid "going towards (%f, %f, %f)." msgstr "a ir em direção (%f, %f, %f)." -#: /home/maria/LSTS/dune/dune/src/Maneuver/FollowReference/AUV/Task.cpp:635 +#: /home/maria/LSTS/temp/dune-master/source/src/Maneuver/FollowReference/AUV/Task.cpp:676 #, c-format msgid "hovering next to (%f, %f)." msgstr "a pairar perto de (%f,%f)." -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:391 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:306 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:682 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:723 +msgid "failed to stop device" +msgstr "falhou ao parar disposito" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:315 +msgid "failed to read EEPROM#130" +msgstr "falha ao ler EEPROM#130" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:325 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:335 +msgid "failed to read EEPROM#230" +msgstr "falha ao ler EEPROM#230" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:485 +msgid "unexpected byte" +msgstr "\"byte\" não esperado" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:690 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:466 +msgid "failed to read magnetic calibration parameters from device" +msgstr "falha ao ler parâmetros da calibração magnética do dispositivo" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:716 +msgid "new hard-iron calibration parameters: %f, %f, %f" +msgstr "novos parâmetros de calibração \"hard-iron\": %f, %f, %f" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX1/Task.cpp:732 +msgid "failed to read magnetic calibration change report" +msgstr "falha ao ler relatório de alterações da calibração magnética" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:399 msgid "Acoustic Feedback" msgstr "Feedback Acústico" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:392 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:400 msgid "None, Ranges, Full" msgstr "Nenhum, Distâncias, Completo" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:439 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:447 msgid "waiting beacons configuration" msgstr "à espera da configuração de transdutores" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:449 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:457 msgid "failed to set modem address" msgstr "falhou ao definir endereço modem" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:623 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:591 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:632 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:591 msgid "dynamic sound speed corrections are disabled" msgstr "correção dinâmica de velocidade do som está desativada" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:692 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:701 msgid "received system restart request" msgstr "recebido pedido para reiniciar sistema" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:698 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:707 msgid "restart request acknowledged" msgstr "reconhecido o pedido de reinicialização" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:700 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:709 msgid "failed to acknowledge restart request" msgstr "falhou reconhecimento ao pedido para reiniciar" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:707 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:716 msgid "acoustic abort detected" msgstr "detetado aborte acústico" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:717 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:726 msgid "abort acknowledged" msgstr "aborte recebido" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:719 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:728 msgid "failed to acknowledge abort" msgstr "falhou ao reconhecer aborte" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:765 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:824 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:774 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:833 #, c-format msgid "discarded invalid range %0.2f" msgstr "descartado range inválido %0.2f" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:938 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:942 +msgid "start plan detected" +msgstr "detetado arranque de plano" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:948 msgid "plan acknowledged" msgstr "plano reconhecido" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:940 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:950 msgid "failed to acknowledge plan start" msgstr "falha ao reconhecer aborte" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBL/Task.cpp:1018 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBL/Task.cpp:1057 msgid "failed to ping beacons, modem seems busy" msgstr "falha ao pingar transdutores, o modem parece ocupado" -#: /home/maria/LSTS/dune/dune/src/Sensors/AIS/Task.cpp:230 -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:163 -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:744 -#: /home/maria/LSTS/dune/dune/src/Sensors/MiniSVS/Task.cpp:134 -msgid "I/O error" -msgstr "erro de entrada/saída" - -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:257 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:265 msgid "restarting to change transducer detection GPIO" msgstr "a reiniciar para mudar o GPIO de deteção de transdutor" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:296 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:304 #, c-format msgid "unable to use GPIO %d for transducer detection" msgstr "incapaz de utilizar o GPIO %d para deteção de transdutor" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:390 msgid "transducer not connected" msgstr "transdutor não está ligado" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:471 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:488 #, c-format msgid "unable to send plan %s" msgstr "incapaz de enviar plano %s" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:669 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:718 msgid "plan started" msgstr "plano iniciado" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:685 -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:778 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:734 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:827 msgid "range to" msgstr "distância para" -#: /home/maria/LSTS/dune/dune/src/Sensors/MLBLTracker/Task.cpp:797 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MLBLTracker/Task.cpp:877 #, c-format msgid "plan progress is %f" msgstr "progresso do plano é %f" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:181 msgid "High-Frequency Channels" msgstr "Canais de Alta Frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:180 -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:182 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:198 msgid "None, Port, Starboard, Both" msgstr "Nenhum, Bombordo, Estibordo, Ambos" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:186 msgid "High-frequency subsystem channels" msgstr "Canais do subsistema de alta frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:186 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:188 msgid "High-Frequency Range" msgstr "Alcance de Alta-Frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:193 -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:209 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:195 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:211 msgid "Enable high frequency subsystem" msgstr "Habilitar subsistema de alta frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:195 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:197 msgid "Low-Frequency Channels" msgstr "Canais de Baixa Frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:202 msgid "Low-frequency subsystem channels" msgstr "Canais do subsistema de baixa frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:204 msgid "Low-Frequency Range" msgstr "Alcance de Baixa-Frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:211 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:213 msgid "Range Multiplier" msgstr "Multiplicador de Alcance" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:217 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:219 msgid "Range multiplier" msgstr "Multiplicador de alcance" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:270 -#: /home/maria/LSTS/dune/dune/src/Sensors/Genesys/Task.cpp:103 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:186 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:391 -#: /home/maria/LSTS/dune/dune/src/Simulators/AcousticModem/Task.cpp:93 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:212 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:272 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Genesys/Task.cpp:105 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:393 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:215 msgid "restarting to change IPv4 address" msgstr "a reiniciar para mudar o endereço IPv4" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:273 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:275 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:218 msgid "restarting to change TCP command port" msgstr "a reiniciar para mudar porta TCP de comandos" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:276 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:278 msgid "restarting to change TCP data port" msgstr "a reiniciar para mudar porta TCP de dados" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:934 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:362 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:595 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:936 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:364 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:601 msgid "failed to turn power on" msgstr "falha ao ligar dispositivo" -#: /home/maria/LSTS/dune/dune/src/Sensors/Edgetech2205/Task.cpp:943 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:371 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:604 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Edgetech2205/Task.cpp:945 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:373 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:610 msgid "failed to connect to device" msgstr "falha ao contactar dispositivo" -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:131 -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:424 -msgid "failed to enter command mode" -msgstr "falha ao entrar em modo de comando" - -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:134 -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:445 -msgid "failed to set sampling rate" -msgstr "falha ao configurar taxa de amostragem" - -#: /home/maria/LSTS/dune/dune/src/Sensors/XchangeSV/Task.cpp:137 -msgid "failed to enter monitor mode" -msgstr "falha ao entrar em modo de monitorização" - -#: /home/maria/LSTS/dune/dune/src/Sensors/SCH311X/Task.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SCH311X/Task.cpp:103 #, c-format msgid "file '%s' doesn't exist" msgstr "ficheiro '%s' não existe" -#: /home/maria/LSTS/dune/dune/src/Sensors/Genesys/Task.cpp:106 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:189 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:394 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Genesys/Task.cpp:108 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:191 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:396 msgid "restarting to change TCP port" msgstr "a reiniciar para mudar a porta TCP" -#: /home/maria/LSTS/dune/dune/src/Sensors/Genesys/Task.cpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Genesys/Task.cpp:111 msgid "restarting to change device address" msgstr "a reiniciar para mudar o endereço do dispositivo" -#: /home/maria/LSTS/dune/dune/src/Sensors/AIM104MultiIO/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/AIM104MultiIO/Task.cpp:150 msgid "invalid message" msgstr "mensagem inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/AIM104MultiIO/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/AIM104MultiIO/Task.cpp:195 msgid "timeout" msgstr "tempo limite" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:423 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:356 -msgid "failed to set hard-iron correction factors" -msgstr "falha ao definir fatores de correção \"hard-iron\"" - -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:429 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:447 msgid "resetting device" msgstr "a restabelecer dispositivo" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:448 -msgid "failed to read magnetic calibration parameters from device" -msgstr "falha ao ler parâmetros da calibração magnética do dispositivo" - -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:467 -msgid "different calibration parameters" -msgstr "valores de calibração diferentes" - -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:512 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/MicrostrainMIP/Task.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:530 #, c-format msgid "new hard-iron calibration parameters: %f, %f, 0.0" msgstr "novos parâmetros de calibração \"hard-iron\": %f, %f, 0.0" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:591 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:531 -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:563 -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:863 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/MicrostrainMIP/Task.cpp:313 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:609 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:549 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:565 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:865 #, c-format msgid "%0.1f seconds without valid data" msgstr "%0.1f segundos sem dados válidos" -#: /home/maria/LSTS/dune/dune/src/Sensors/Microstrain3DMGX3/Task.cpp:608 -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:548 -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:580 -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:880 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/MicrostrainMIP/Task.cpp:330 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Microstrain3DMGX3/Task.cpp:626 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:566 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:582 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:882 #, c-format msgid "active | timeouts: %u | faults: %u | frequency: %u" msgstr "activa | timeouts: %u | falhas: %u | frequência: %u" -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:298 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:316 msgid "failed to configure output frequency" msgstr "falha ao configurar frequência de saída" -#: /home/maria/LSTS/dune/dune/src/Sensors/LIMU/Task.cpp:358 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/LIMU/Task.cpp:376 #, c-format msgid "new hard-iron calibration parameters: %.4f, %.4f, 0.0" msgstr "novos parâmetros de calibração \"hard-iron\": %.4f, %.4f, 0.0" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:448 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:248 +msgid "Requesting DMS readings" +msgstr "A requisitar leituras DMS" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/DMS/Task.cpp:254 +msgid "Board DMS not operational" +msgstr "Datalogger DMS não operacional" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:453 msgid "failed to start monitoring" msgstr "falha ao iniciar captura" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:468 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:473 msgid "failed to disable internal channels" msgstr "falha ao desligar canais internos" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:494 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:499 msgid "failed to set water density" msgstr "falha ao definir densidade da água" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:497 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:502 msgid "failed to set salinity" msgstr "falha ao definir salinidade" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:508 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:513 msgid "failed to set sound speed" msgstr "falha ao definir velocidade do som" -#: /home/maria/LSTS/dune/dune/src/Sensors/MetrecX/Task.cpp:765 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:604 +msgid "unknown probe (%s)" +msgstr "sonda desconhecida (%s)" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MetrecX/Task.cpp:778 msgid "mismatch between output and configuration" msgstr "Incompatibilidade entre \"output\" e configuração" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:258 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:154 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex837B/Task.cpp:278 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:154 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:161 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/StarFish/Task.cpp:68 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:260 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:156 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex837B/Task.cpp:280 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:160 msgid "Range" msgstr "Alcance" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:266 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:146 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:148 msgid "Frequency" msgstr "Frequência" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex881A/Task.cpp:346 -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex852/Task.cpp:290 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex881A/Task.cpp:348 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex852/Task.cpp:292 msgid "restarting to change UART device" msgstr "a reiniciar para mudar dispositivo UART" -#: /home/maria/LSTS/dune/dune/src/Sensors/XR620CTD/Task.cpp:466 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/XR620CTD/Task.cpp:468 #, c-format msgid "parse error: %s" msgstr "processamento do erro: %s" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:152 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:154 msgid "Operating frequency" msgstr "Frequência de operação" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:162 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/StarFish/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:164 msgid "Operating range" msgstr "Alcance de operação" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:288 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:290 msgid "failed to read header" msgstr "falhou ao ler cabeçalho" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:293 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:295 msgid "failed to read data" msgstr "falhou ao ler dados" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex872/Task.cpp:297 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex872/Task.cpp:299 msgid "failed to read footer" msgstr "falhou ao ler footer" -#: /home/maria/LSTS/dune/dune/src/Sensors/SW100/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SW100/Task.cpp:195 #, c-format msgid "depth offset is %0.2f m" msgstr "compensação de profundidade de %0.2f m" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:154 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:156 msgid "Level the device and hit NEXT" msgstr "Nivele o dispositivo e pressione NEXT" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:159 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:161 msgid "Rotate the device and keep it levelled (rotation must last +20s)" msgstr "Rode o dispositivo e mantenha-o nivelado (a rotação tem de durar +20s)" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:164 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:166 msgid "Device is calibrated" msgstr "Dispositivo está calibrado" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:173 msgid "Calibration error, calibration procedure must be restarted" msgstr "Erro de calibração, é necessário reiniciar o processo de calibração" -#: /home/maria/LSTS/dune/dune/src/Sensors/OS4000/Task.cpp:407 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OS4000/Task.cpp:409 #, c-format msgid "Level the device and hit NEXT (Roll: %0.2f | Pitch: %0.2f)" msgstr "Nivele o dispositivo e clique NEXT (Roll: %0.2f | Pitch: %0.2f)" -#: /home/maria/LSTS/dune/dune/src/Sensors/Imagenex852/Task.cpp:259 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/ExplorerDVL/Task.cpp:166 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:225 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Imagenex852/Task.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/ExplorerDVL/Task.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:225 msgid "Automatic Activation" msgstr "Ativação Automática" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:232 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Task.cpp:234 +msgid "failed to init CTD" +msgstr "falha ao iniciar CTD" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Task.cpp:274 +msgid "com error - get info" +msgstr "com erro - a obter informação" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/OEMX/Task.cpp:401 +#, c-format +msgid "CTD - Pressure calibrated (%f)" +msgstr "CTD - Pressão calibrada (%f)" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:234 msgid "failed to configure trigger frequency" msgstr "falha ao configurar frequência de disparo" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:242 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:244 msgid "failed to turn on device" msgstr "falha ao ligar dispositivo" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:356 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:358 #, c-format msgid "IMU failure: %04X" msgstr "falha do IMU: %04X" -#: /home/maria/LSTS/dune/dune/src/Sensors/IFOG/Task.cpp:361 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/IFOG/Task.cpp:363 #, c-format msgid "data might be unreliable: %04X" msgstr "os dados podem não ser confiáveis: %04X" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:202 #, c-format msgid "took too long to read data: %lu ms" msgstr "demasiado tempo a ler dados: %lu ms" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:207 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:209 #, c-format msgid "overrun of %lu ms" msgstr "overrun de %lu ms" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:370 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:372 msgid "unable to enter configuration mode" msgstr "incapaz de entrar no modo de configuração" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:376 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:378 msgid "unable to set output settings" msgstr "incapaz de definir parâmetros de saída" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:384 msgid "unable to set output mode" msgstr "incapaz de configurar modo de saída" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:388 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:390 msgid "unable to set SyncIn settings" msgstr "incapaz de definir parâmetros SyncIn" -#: /home/maria/LSTS/dune/dune/src/Sensors/MTi/Task.cpp:394 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/MTi/Task.cpp:396 msgid "unable to enter measurement mode" msgstr "incapaz de entrar em modo de leitura" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:399 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:401 msgid "exceeded maximum consecutive CRC error count" msgstr "excedido número máximo de erros CRC consecutivos" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:477 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:479 msgid "device not initialized, initializing" msgstr "dispositivo não está inicializado, a inicializar" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:483 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:485 #, c-format msgid "got exception %d for command %d" msgstr "lançada exceção %d para o comando %d" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:494 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:496 #, c-format msgid "initialized device: class=%d.%d firmware=%d" msgstr "dispositivo inicializado: class=%d.%d firmware=%d" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:500 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:502 #, c-format msgid "device serial number=%u" msgstr "número de série do dispositivo=%u" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:529 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:531 msgid "unable to initialize the device" msgstr "falha ao inicializar dispositivo" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:537 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:539 msgid "unable to retrieve the serial number" msgstr "falha ao obter o número de série" -#: /home/maria/LSTS/dune/dune/src/Sensors/Keller/Task.cpp:555 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/Keller/Task.cpp:557 msgid "unable to zero the device" msgstr "incapaz de zerar o dispositivo" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:234 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:238 msgid "no reply to command" msgstr "sem resposta ao comando" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:235 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:239 msgid "failed to setup device" msgstr "inicialização do dispositivo falhou" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:516 -msgid "invalid GPZDA sentence" -msgstr "frase GPZDA é inválida" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:543 +msgid "invalid ZDA sentence" +msgstr "frase ZDA inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:540 -msgid "invalid GPGGA sentence" -msgstr "frase GPGGA é inválida" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:567 +msgid "invalid GGA sentence" +msgstr "frase GGA inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:588 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:615 msgid "invalid PUBX,00 sentence" msgstr "frase PUBX,00 é inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:638 -msgid "invalid GPVTG sentence" -msgstr "frase GPVTG é inválida" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:665 +msgid "invalid VTG sentence" +msgstr "frase VTG inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:662 -msgid "invalid GPHDT sentence" -msgstr "frase GPHDT é inválida" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:689 +msgid "invalid HDT sentence" +msgstr "frase HDT inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:678 -msgid "invalid GPHDM sentence" -msgstr "frase GPHDM é inválida" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:705 +msgid "invalid HDM sentence" +msgstr "frase HDM inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:696 -msgid "invalid GPROT sentence" -msgstr "frase GPROT é inválida" +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:723 +msgid "invalid ROT sentence" +msgstr "frase ROT inválida" -#: /home/maria/LSTS/dune/dune/src/Sensors/GPS/Task.cpp:715 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/GPS/Task.cpp:742 msgid "invalid PSATHPR sentence" msgstr "frase PSATHPR é inválida" -#: /home/maria/LSTS/dune/dune/src/UserInterfaces/MantaPanel/Task.cpp:315 +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:309 +msgid "Requesting SADC readings" +msgstr "A requisitar leituras SADC" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:315 +msgid "Board SADC not operational" +msgstr "SADC não operacional" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:468 +msgid "no read error received" +msgstr "nenhum erro de leitura recebido" + +#: /home/maria/LSTS/temp/dune-master/source/src/Sensors/SADC/Task.cpp:473 +msgid "none adc channel active, mistake config?" +msgstr "nenhum canal adc activo, configuração com erros?" + +#: /home/maria/LSTS/temp/dune-master/source/src/UserInterfaces/MantaPanel/Task.cpp:347 msgid "failed to execute power down command" msgstr "Falha ao executar comando de desligar" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:134 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:136 #, c-format msgid "TREX disconnected for more than %d seconds" msgstr "TREX desligado durante mais do que %d segundos" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:202 msgid "Abort detected. Disabling TREX control..." msgstr "Detetado aborte. A desabilitar controlo T-REX." -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:217 msgid "Stop TREX detected. Disabling TREX control..." msgstr "Detetada paragem no TREX. A desabilitar controlo T-REX." -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:236 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:238 msgid "Restarting auxiliary CPU..." msgstr "A reiniciar CPU auxiliar..." -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:244 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:246 msgid "T-REX has been stopped." msgstr "T-REX interrompido." -#: /home/maria/LSTS/dune/dune/src/Autonomy/TREX/Task.cpp:246 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TREX/Task.cpp:248 #, c-format msgid "Could not stop T-REX: %d." msgstr "Incapaz de parar T-REX: %d." -#: /home/maria/LSTS/dune/dune/src/Autonomy/TextActions/Task.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:411 +msgid "Unable to change emergency number to %s" +msgstr "Incapaz de alterar número de emergência para %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:514 #, c-format msgid "received SMS request to start plan '%s'" msgstr "recebido pedido por SMS para iniciar o plano '%s'" -#: /home/maria/LSTS/dune/dune/src/Autonomy/TextActions/Task.cpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:539 +msgid "received SMS request to resume plan '%s' starting from maneuver '%s'" +msgstr "recebido pedido por SMS para resumir o plano '%s' a começar a partir da manobra '%s'" + +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:548 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Generator/Task.cpp:240 +msgid "Plan generated automatically" +msgstr "Plano gerado automaticamente" + +#: /home/maria/LSTS/temp/dune-master/source/src/Autonomy/TextActions/Task.cpp:572 #, c-format msgid "got abort request from '%s'" msgstr "recebido pedido de abortar de '%s'" -#: /home/maria/LSTS/dune/dune/src/Navigation/General/LBL/Task.cpp:347 +#: /home/maria/LSTS/temp/dune-master/source/src/Navigation/General/LBL/Task.cpp:349 #, c-format msgid "corrected beacon #%d (x: %0.2f, y: %0.2f, std dev: %0.2f)" msgstr "\"beacon\" #%d corrigido (x: %0.2f, y: %0.2f, std dev: %0.2f)" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:247 +#: /home/maria/LSTS/temp/dune-master/source/src/Navigation/AUV/Navigation/Task.cpp:708 +msgid "navigation not aligned - Automatic IMU poweroff" +msgstr "navegação não alinhada - IMU a desligar automaticamente" + +#: /home/maria/LSTS/temp/dune-master/source/src/Navigation/AUV/Navigation/Task.cpp:753 +msgid "Nav: speed model invalid" +msgstr "Navegação: modelo de velocidade inválido" + +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:249 #, c-format msgid "schedule: %s active on time, +%.1f seconds" msgstr "ações: %s ativo atempadamente, +%.1f segundos" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:250 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:252 #, c-format msgid "schedule: %s activation missed deadline, %.1f seconds" msgstr "ações: %s ativação atrasada, %.1f segundos" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:471 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:473 #, c-format msgid "schedule: entity label %s not found" msgstr "ações: etiqueta de entidade %s não encontrada" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:739 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:741 #, c-format msgid "scheduled for: %.1f" msgstr "definido para: %.1f" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/ActionSchedule.cpp:743 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/ActionSchedule.cpp:745 #, c-format msgid "END %s ---" msgstr "FIM %s ---" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:69 msgid "plan: speed model invalid" msgstr "plano: modelo de velocidades inválido" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:80 #, c-format msgid "plan: power model invalid: %s" msgstr "plano: modelo de consumos inválido: %s" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:385 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:387 msgid ": no maneuvers" msgstr ": sem manobras" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:400 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:402 msgid ": actual maneuver not specified" msgstr ": manobra atual não especificada" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:405 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:407 msgid ": maneuver is not supported" msgstr ": manobra não suportada" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:408 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:410 msgid ": maneuver depth beyond limits" msgstr ": profundidade da manobra além dos limites" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:436 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:438 msgid ": maneuver has no incoming transition and it's not the initial maneuver" msgstr ": a manobra não sucede a nenhuma transição e não é a manobra inicial" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:447 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:449 msgid ": invalid start maneuver" msgstr ": manobra de início inválida" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Plan.cpp:523 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Plan.cpp:525 #, c-format msgid "invalid maneuver id '%s'" msgstr "identificador de manobra inválido '%s'" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:56 msgid "Start Plan" msgstr "Iniciar Plano" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:56 msgid "Stop Plan" msgstr "Parar Plano" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:57 msgid "Load Plan" msgstr "Plano Carregado" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:57 msgid "Get Plan" msgstr "Obter Plano" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:59 msgid "BLOCKED" msgstr "BLOQUEADO" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:59 msgid "READY" msgstr "PRONTO" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:60 msgid "INITIALIZING" msgstr "INICIALIZAÇÃO" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:60 msgid "EXECUTING" msgstr "EXECUÇÃO" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:231 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:233 msgid "restarting to relaunch plan parser" msgstr "a reiniciar para relançar o analisador de planos" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:307 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:309 #, c-format msgid "failed to activate %s: %s" msgstr "falha ao ativar %s: %s" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:437 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:439 msgid "vehicle ready" msgstr "veículo pronto" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:472 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:474 msgid "plan completed" msgstr "plano completado" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:493 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:495 msgid "vehicle errors: " msgstr "erros veículo: " -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:528 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:530 msgid "vehicle in CALIBRATION mode" msgstr "veículo em modo de calibração" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:541 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:543 msgid "vehicle in EXTERNAL mode" msgstr "veículo em modo EXTERNO" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:585 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:591 #, c-format msgid "request -- %s (%s)" msgstr "pedido -- %s (%s)" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:591 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:597 msgid "engine not ready: entity state not normal" msgstr "motor não está pronto: estado de entidade não normal" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:611 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:617 msgid "plan control operation not supported" msgstr "operação de controlo de plano não suportada" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:627 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:633 msgid "cannot load plan now" msgstr "incapaz de carregador plano agora" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:635 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:641 msgid "plan load failed: " msgstr "plano falhou ao carregar: " -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:644 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:650 msgid "plan parse failed: " msgstr "falha ao processar plano: " -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:654 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:660 msgid "plan loaded" msgstr "plano carregado" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:665 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:671 msgid "no plan is running" msgstr "nenhum plano a correr" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:690 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:696 msgid "plan stopped" msgstr "plano parado" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:703 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:709 msgid "no plan is running, request ignored" msgstr "nenhum plano a correr, pedido ignorado" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:746 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:333 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:406 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:441 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:472 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:752 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:336 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:409 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:444 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:475 msgid "undefined plan id" msgstr "plan ID indefinido" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:758 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:431 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:451 -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:482 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:764 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:434 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:454 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:485 msgid "undefined plan" msgstr "plano indefinido" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:769 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:775 #, c-format msgid "failed loading from DB: %s" msgstr "falha ao carregar da base de dados: %s" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:843 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:849 msgid "plan initializing: " msgstr "plano a iniciar: " -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:893 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:899 msgid "cannot initialize plan in BLOCKED state" msgstr "incapaz de iniciar plano em modo BLOQUEADO" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:924 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:930 msgid ": invalid maneuver ID" msgstr ": maneuver ID inválido" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:931 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:937 msgid ": executing maneuver" msgstr ": a executar manobra" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:950 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:956 #, c-format msgid "reply -- %s (%s) -- %s" msgstr "resposta -- %s (%s) -- %s" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1008 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1014 #, c-format msgid "now in %s state" msgstr "agora no estado %s" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1101 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1107 msgid "vehicle state timeout" msgstr "excedido tempo limite do estado do veículo" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1123 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1129 msgid "vehicle reply timeout" msgstr "excedido tempo limite da resposta do veículo" -#: /home/maria/LSTS/dune/dune/src/Plan/Engine/Task.cpp:1132 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Engine/Task.cpp:1138 msgid "cleared all requests" msgstr "todos os pedidos limpos" -#: /home/maria/LSTS/dune/dune/src/Plan/Generator/Task.cpp:216 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Generator/Task.cpp:218 #, c-format msgid "Unable to generate plan using template %s" msgstr "Incapaz de gerar plano usando modelo %s" -#: /home/maria/LSTS/dune/dune/src/Plan/Generator/Task.cpp:238 -msgid "Plan generated automatically" -msgstr "Plano gerado automaticamente" - -#: /home/maria/LSTS/dune/dune/src/Plan/Generator/Task.cpp:394 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/Generator/Task.cpp:397 #, c-format msgid "generating plan from '%s' template..." msgstr "a gerar plano a partir do modelo '%s'..." -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:75 msgid "set plan" msgstr "definir plano" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:75 msgid "delete plan" msgstr "apagar plano" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:74 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:76 msgid "get plan" msgstr "obter plano" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:74 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:76 msgid "get plan info" msgstr "obter informação de plano" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:77 msgid "clear database" msgstr "limpar base de dados" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:77 msgid "database state" msgstr "estado da base de dados" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:76 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:78 msgid "database initialization" msgstr "inicialização da base de dados" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:139 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:141 #, c-format msgid "database file: '%s'" msgstr "ficheiro de base de dados: '%s'" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:169 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:171 msgid "initialization complete" msgstr "inicialização completa" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:223 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:225 #, c-format msgid "storing plan '%s' issued through a PlanControl request" msgstr "a guardar plano '%s' pedido através do PlanControl" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:253 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:255 msgid "unexpected message" msgstr "mensagem não esperada" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:266 -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:295 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:268 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:302 msgid "not active" msgstr "inativo" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:296 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:299 msgid "unsupported operation" msgstr "operação não suportada" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:325 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:328 msgid "database is corrupt" msgstr "base de dados corrompida" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:341 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:344 msgid "no plan specification given" msgstr "especificação de plano não recebida" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:347 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:350 msgid "plan id mismatch" msgstr "incompatibilidade plan id" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:398 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:401 msgid "OK (updated)" msgstr "OK (atualizado)" -#: /home/maria/LSTS/dune/dune/src/Plan/DB/Task.cpp:398 +#: /home/maria/LSTS/temp/dune-master/source/src/Plan/DB/Task.cpp:401 msgid "OK (new entry)" msgstr "OK (nova entrada)" -#: /home/maria/LSTS/dune/dune/src/Control/ASV/HeadingAndSpeed/Task.cpp:459 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ASV/HeadingAndSpeed/Task.cpp:461 msgid "enabling" msgstr "a ativar" -#: /home/maria/LSTS/dune/dune/src/Control/ASV/HeadingAndSpeed/Task.cpp:459 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ASV/HeadingAndSpeed/Task.cpp:461 msgid "disabling" msgstr "a desativar" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:54 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:65 msgid "Heading Rate" msgstr "Rate de Orientação" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:54 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:64 msgid "Heading" msgstr "Orientação" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:57 msgid "Surge" msgstr "Movimento Frontal" -#: /home/maria/LSTS/dune/dune/src/Control/ROV/HorizontalPlane/Task.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/ROV/HorizontalPlane/Task.cpp:57 msgid "Sway" msgstr "Movimento Lateral" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Allocator/Task.cpp:87 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/LMI/Task.cpp:89 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:181 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Allocator/Task.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/LMI/Task.cpp:91 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:187 msgid "Maximum Fin Rotation" msgstr "Máxima Rotação de Lemes" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Allocator/Task.cpp:90 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/LMI/Task.cpp:92 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Allocator/Task.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/LMI/Task.cpp:94 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:190 msgid "Maximum admissible fin rotation" msgstr "Máxima rotação admissível de lemes" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/LMI/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/LMI/Task.cpp:150 msgid "Gain matrix has invalid dimensions" msgstr "Matriz de ganhos tem dimensões inválidas" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Diving/Task.cpp:478 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Diving/Task.cpp:480 msgid "failed to submerge" msgstr "submersão falhada" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:63 msgid "Roll" msgstr "Roll" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:63 msgid "Pitch" msgstr "Decaimento" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:62 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1163 -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:55 msgid "Depth" msgstr "Profundidade" -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:186 -#: /home/maria/LSTS/dune/dune/src/Control/AUV/Attitude/Task.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:192 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AUV/Attitude/Task.cpp:194 msgid "Enable roll controller" msgstr "Habilitar controlador de roll" -#: /home/maria/LSTS/dune/dune/src/Control/AntennaTracker/Task.cpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/AntennaTracker/Task.cpp:101 #, c-format msgid "Target name is %s, with ID %d" msgstr "Nome do alvo é %s, com ID %d" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:475 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:512 msgid "Ardupilot interface initialized" msgstr "Interface Ardupilot inicializada" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:480 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:523 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:372 msgid "Connection failed, retrying..." msgstr "Ligação falhou, a tentar novamente..." -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:596 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:639 msgid "ArduPilot is in Manual mode, saving control loops." msgstr "ArduPilot em modo manual, a gravar malhas de controlo." -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:849 -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:253 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:889 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:253 msgid "speed control is NOT active" msgstr "controlo de velocidade NÃO está ativo" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:878 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:918 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:1107 msgid "ArduPilot is in Manual mode, saving desired path." msgstr "ArduPilot em modo manual, a salvar caminho desejado." -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:884 -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:372 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:924 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:372 msgid "path control is NOT active" msgstr "controlo de caminho NÃO está ativo" -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:892 -msgid "ArduPilot in Auto mode but still in ground, performing takeoff first." -msgstr "ArduPilot em modo automático mas em Terra, a fazer takeoff primeiro" +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:931 +msgid "ArduPilot in Auto mode, but still in ground! Add a takeoff waypoint to the plan." +msgstr "ArduPilot no modo Auto, mas ainda em Terra! Adicioinar um waypoint de takeoff ao plano." -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1454 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:1217 +msgid "ArduPilot is in Manual mode, unable to perform automatic landing." +msgstr "ArduPilot no modo Manual, aterragem automática impossível de realizar." + +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:1546 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:1048 msgid "Connection lost, retrying..." msgstr "Ligação perdida, a tentar novamente..." -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1942 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:2039 msgid "Controlling an unknown vehicle type." msgstr "A controlar um tipo de veículo desconhecido." -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1946 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:2043 msgid "Controlling a fixed-wing vehicle." msgstr "A controlar veículo asa delta." -#: /home/maria/LSTS/dune/dune/src/Control/UAV/Ardupilot/Task.cpp:1953 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/Ardupilot/Task.cpp:2050 msgid "Controlling a multirotor." msgstr "A controlar um multirotor" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:40 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:51 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:363 +msgid "PX4 interface initialized" +msgstr "Interface PX4 inicializada" + +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:556 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:620 +#: /home/maria/LSTS/temp/dune-master/source/src/Control/UAV/PX4/Task.cpp:678 +msgid "PX4 is in a Manual mode, saving desired path." +msgstr "PX4 no modo manual, a salvar caminho desejado." + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:42 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:53 msgid "invalid command" msgstr "comando inválido" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:41 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:60 msgid "invalid command arguments" msgstr "argumentos de comando inválidos" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:42 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:56 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/IntelHEX.cpp:107 -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:65 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:44 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/IntelHEX.cpp:109 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:67 msgid "invalid checksum" msgstr "verificação inválido" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:43 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:45 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:54 msgid "lost synchronization" msgstr "sincronização perdida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:44 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:55 msgid "parser error" msgstr "erro do analisador" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:45 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:56 msgid "data overrun" msgstr "dados perdidos" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:46 -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:57 msgid "buffer overflow" msgstr "espaço de dados excedido" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Errors.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Errors.cpp:58 msgid "invalid error code" msgstr "código de erro inválido" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:69 msgid "failed to reset device" msgstr "falha ao restabelecer dispositivo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:79 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:81 msgid "failed to set bootloader parameters" msgstr "falha ao definir parâmetros do \"bootloader\"" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:137 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:139 msgid "failed to get firmware name" msgstr "falha ao obter nome do \"firmware\"" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:150 -msgid "failed to get firmware version" -msgstr "falha ao obter versão do \"firmware\"" - -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Interface.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Interface.cpp:155 msgid "invalid firmware version" msgstr "versão de \"firmware\" inválida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:68 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:70 msgid "failed to enter bootloader" msgstr "falhada entrada no \"bootloader\"" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:85 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:87 msgid "failed to jump to application" msgstr "falha ao saltar para aplicação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:124 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:126 msgid "failed start upgrade procedure" msgstr "falha ao iniciar procedimento de atualização" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:135 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:137 msgid "failed to end upgrade procedure" msgstr "falha ao sair de procedimento de atualização" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:156 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:158 msgid "failed to fill page chunk" msgstr "falha ao preencher porção de página" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:166 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:168 msgid "failed to write flash page" msgstr "falha ao escrever para página da \"flash\"" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/UCTK/Bootloader.cpp:198 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/UCTK/Bootloader.cpp:200 msgid "failed to retrieve flash info" msgstr "falha ao obter informação da \"flash\"" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:386 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:388 msgid "failed to synchronize with device" msgstr "falha ao sincronizar com o dispositivo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:405 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:407 msgid "failed to request current log name" msgstr "falha ao pedir nome do log atual" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicDeviceDriver.cpp:420 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicDeviceDriver.cpp:422 msgid "failed to retrieve current log name" msgstr "falha ao obter nome do log atual" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/LUCL/Protocol.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/LUCL/Protocol.cpp:59 msgid "parser bug" msgstr "defeito do analisador" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/BasicModem.cpp:265 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/BasicModem.cpp:267 #, c-format msgid "fragment: %s" msgstr "fragmento: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Hardware/IntelHEX.cpp:61 -#: /home/maria/LSTS/dune/dune/src/DUNE/Algorithms/MD5.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Hardware/IntelHEX.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Algorithms/MD5.cpp:65 msgid "failed to open file" msgstr "falha ao abrir ficheiro" -#: /home/maria/LSTS/dune/dune/src/DUNE/Time/Clock.cpp:123 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:136 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:140 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Time/Clock.cpp:122 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:122 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:126 msgid "failed to set time" msgstr "falha ao definir tempo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Power/Model.cpp:118 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Power/Model.cpp:120 #, c-format msgid "invalid hardware part '%s'" msgstr "component de hardware inválido '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:43 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:45 msgid "activating" msgstr "a ativar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:44 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:46 msgid "deactivating" msgstr "a desativar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:45 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:47 msgid "input/output error" msgstr "erro de entrada/saída" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:48 msgid "internal error" msgstr "erro interno" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:49 msgid "CPU usage is too high" msgstr "utilização do CPU é demasiado elevada" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:50 msgid "fuel is running low" msgstr "nível de energia baixo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:51 msgid "fuel level estimation is not reliable" msgstr "estimativa de nível de energia não é confiável" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:50 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:52 msgid "fuel reserve" msgstr "reserva de energia" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:51 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:53 msgid "calibrating" msgstr "a calibrar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:54 msgid "calibrated" msgstr "calibrado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:55 msgid "not aligned" msgstr "não alinhado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:56 msgid "aligning" msgstr "a alinhar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:57 msgid "aligned" msgstr "alinhado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:56 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:58 msgid "powering down" msgstr "a desligar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:59 msgid "communication error" msgstr "erro de comunicação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:58 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:60 msgid "synchronized" msgstr "sincronizado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:59 -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:328 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:311 msgid "synchronizing" msgstr "a sincronizar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:60 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:62 msgid "not synchronized" msgstr "não sincronizado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:61 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:63 msgid "waiting for GPS fix" msgstr "à espera de posição GPS" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:64 msgid "waiting for configuration of LBL beacons" msgstr "à espera da configuração de transdutores LBL" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:65 msgid "waiting for solution to converge" msgstr "à espera que a solução convirja" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:66 msgid "missing data" msgstr "dados em falta" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:66 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:68 msgid "invalid version" msgstr "versão inválida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:69 msgid "active but without bottom lock" msgstr "ativo mas sem \"bottom lock\"" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:68 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:70 msgid "no medium data: user must control device" msgstr "sem dados do meio: utilizador deve controlar dispositivo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:69 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:71 msgid "active (no medium data: need user input)" msgstr "ativo (sem dados do meio: controlo do utilizador" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:70 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:72 msgid "idle (no medium data: need user input)" msgstr "em espera (sem dados do meio: controlo do utilizador" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:73 msgid "connecting" msgstr "a conectar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Status/Messages.cpp:72 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Status/Messages.cpp:74 msgid "connected" msgstr "conectado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:47 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:49 msgid "Print this message and exit" msgstr "Imprime esta mensagem e sai" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:50 msgid "Print the version information and exit" msgstr "Imprime esta info de versão e sai" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:49 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:51 msgid "Print architecture information and exit" msgstr "Imprime info de arquitetura e sai" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:66 #, c-format msgid "short option '%s' already exists" msgstr "opção '%s' já existe" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:69 #, c-format msgid "long option '%s' already exists" msgstr "opção '%s' já existe" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:130 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:132 #, c-format msgid "" "Description:\n" @@ -2509,7 +2943,7 @@ msgstr "" " %s\n" "\n" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:134 #, c-format msgid "" "Usage:\n" @@ -2520,1541 +2954,1688 @@ msgstr "" " %s [opções]\n" "\n" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:133 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:135 msgid "Options:\n" msgstr "Opções:\n" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:161 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:163 #, c-format msgid "This program is built for %s\n" msgstr "Este programa foi compilado para %s\n" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:162 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:164 #, c-format msgid "Report bugs to %s\n" msgstr "Reportar erros para %s\n" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:176 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:178 #, c-format msgid "unknown option '%s'" msgstr "opção desconhecida '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/OptionParser.cpp:189 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/OptionParser.cpp:191 #, c-format msgid "missing argument for option '%s'" msgstr "argumento em falta para opção '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Utils/String.cpp:303 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Utils/String.cpp:333 msgid "invalid escape sequence" msgstr "sequência de escape invalida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/KalmanFilter.cpp:151 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/KalmanFilter.cpp:153 msgid "matrix inversion error" msgstr "erro de inversão de matriz" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:42 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:44 #, c-format msgid "position uncertainty is %0.2f m" msgstr "incerteza de posição é %0.2f m" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:60 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:62 msgid "Maximum Horizontal Position Variance" msgstr "Máxima Variância Horizontal de Posição" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:346 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:349 #, c-format msgid "received acceleration beyond range: %f, %f, %f" msgstr "aceleração recebida fora do \"range\": %f, %f, %f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:368 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:371 #, c-format msgid "received angular velocity beyond range: %f, %f, %f" msgstr "velocidade angular recebida fora do \"range\": %f, %f, %f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:458 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:461 #, c-format msgid "received euler angles beyond range: %f, %f, %f" msgstr "ângulos de euler recebidos fora do \"range\": %f, %f, %f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:486 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:489 #, c-format msgid "received euler angles delta beyond range: %f, %f, %f" msgstr "delta dos ângulos de euler recebido fora do \"range\": %f, %f, %f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1163 -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1175 #, c-format msgid "no measurements available: %s" msgstr "valores não disponíveis: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Navigation/BasicNavigation.cpp:1169 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Navigation/BasicNavigation.cpp:1175 msgid "Euler Angles" msgstr "Ângulos de Euler" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicRemoteOperation.cpp:131 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicRemoteOperation.cpp:133 #, c-format msgid "teleoperation by %s" msgstr "teleoperação por %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:54 msgid "Idle" msgstr "Em Espera" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:52 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:54 msgid "Tracking" msgstr "Seguimento" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:53 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:55 msgid "LimitDepth" msgstr "LimitaProfundidade" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:56 msgid "Unsafe" msgstr "Inseguro" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:56 msgid "Avoiding" msgstr "Desvio" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:57 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:59 msgid "BottomTrack" msgstr "SeguirFundo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:377 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:378 msgid "depth is reaching unacceptable values, forcing depth control" msgstr "demasiado profundo, a forçar controlo em profundidade" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:543 -msgid "unable to avoid obstacle" -msgstr "incapaz de evitar obstáculo" - -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:554 -msgid "avoid obstacle" -msgstr "evitar obstáculo" - -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:612 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:594 msgid "Started braking" msgstr "Início de travagem" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BottomTracker.cpp:614 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BottomTracker.cpp:596 msgid "Stopped braking" msgstr "Fim de travagem" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:48 msgid "no valid altitude measurements" msgstr "sem valores válidos de altitude" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:178 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:180 #, c-format msgid "limiting depth to %.1f" msgstr "a limitar profundidade a %.1f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:198 #, c-format msgid "limiting altitude to %.1f" msgstr "a limitar altitude a %.1f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:258 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:260 #, c-format msgid "invalid vertical control mode %d" msgstr "modo de controlo vertical inválido %d " -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:270 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:272 msgid "timed out while waiting for vertical control mode" msgstr "tempo limite atingido à espera de modo de controlo vertical" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:307 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:309 #, c-format msgid "water column not deep enough for altitude control ( %0.2f < %0.2f )" msgstr "coluna de água insuficiente para controlo de altitude ( %0.2f < %0.2f )" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:326 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:328 msgid "getting too close to maximum admissible depth" msgstr "demasiado próximo da profundidade máxima admissível" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:337 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:339 #, c-format msgid "invalid yaw control mode %d" msgstr "modo de controlo azimute %d inválido" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/BasicAutopilot.cpp:349 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/BasicAutopilot.cpp:351 msgid "timed out waiting for yaw control mode" msgstr "excedido tempo limite de espera por modo de controlo azimute" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:438 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:372 +msgid "track length is too long" +msgstr "comprimento do percurso é demasiado longo" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:453 msgid "keep loitering" msgstr "manter loiter" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:480 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:495 #, c-format msgid "path (lat/lon): %0.5f %0.5f to %0.5f %0.5f" msgstr "caminho (lat/lon): %0.5f %0.5f para %0.5f %0.5f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:651 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:666 msgid "expected new path control reference" msgstr "esperada nova referência de path control" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:708 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:723 msgid "now loitering" msgstr "a fazer loiter" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:847 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:853 msgid "along-track divergence error" msgstr "erro por divergência ao longo do caminho" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:880 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:886 msgid "cross-track divergence error" msgstr "erro por divergência perpendicular ao caminho" -#: /home/maria/LSTS/dune/dune/src/DUNE/Control/PathController.cpp:961 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Control/PathController.cpp:967 msgid "waiting for position estimate from navigation" msgstr "à espera de uma estimativa da posição pela navegação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:130 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:101 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:103 msgid "unable to create socket" msgstr "incapaz de criar socket" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:169 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:184 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:171 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:186 msgid "unable to bind to socket" msgstr "incapaz de ligar ao socket" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:181 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:183 msgid "unable to connect" msgstr "incapaz de conectar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:190 msgid "unable to listen" msgstr "incapaz de receber dados" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:199 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:201 msgid "failed to accept connection" msgstr "falhou ao aceitar conexão" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:226 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:197 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:228 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:199 msgid "error receiving data" msgstr "erro ao receber dados" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:247 -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:227 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:249 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:229 msgid "error sending data" msgstr "erro ao enviar dados" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:346 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:348 msgid "unable to set receive timeout" msgstr "incapaz de definir tempo limite de receção" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:354 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:356 msgid "unable to set send timeout" msgstr "incapaz de definir tempo limite de transmissão" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:363 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:365 msgid "unable to get bound address" msgstr "impossível obter endereço associado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/TCPSocket.cpp:374 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/TCPSocket.cpp:376 msgid "unable to get bound port" msgstr "impossível obter porta associada" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/UDPSocket.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/UDPSocket.cpp:116 msgid "setting up socket" msgstr "a definir socket" -#: /home/maria/LSTS/dune/dune/src/DUNE/Network/FragmentedMessage.cpp:66 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Network/FragmentedMessage.cpp:68 msgid "Invalid fragment received and it won't be processed." msgstr "Recibo fragmento inválido que não será processado." -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/FollowTrajectory.cpp:79 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:145 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/FollowTrajectory.cpp:81 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:147 msgid "too few trajectory points" msgstr "poucos pontos de trajetória" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Elevate.cpp:53 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:50 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Circular.cpp:44 -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/FigureEight.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Elevate.cpp:55 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:54 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Circular.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/FigureEight.cpp:56 #, c-format msgid "forcing minimum radius of %.1f" msgstr "a forçar raio mínimo de %.1f" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Elevate.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Elevate.cpp:125 msgid "water column is not deep enough" msgstr "coluna de água não é suficientemente profunda" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:99 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:98 #, c-format msgid "outside safe region (distance: %.1f m)" msgstr "fora região segura (distância: %.1f m)" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:120 #, c-format msgid "inside safe region (distance: %.1f m)" msgstr "dentro região segura (distância: %.1f m)" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/StationKeep.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/StationKeep.cpp:154 msgid "invalid station keeping state" msgstr "informação de posição estacionária inválida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/RowsStages.cpp:94 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/RowsStages.cpp:96 msgid "invalid maneuver parameters" msgstr "parâmetros da manobra inválidos" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:67 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:69 msgid "parsing vehicle participants" msgstr "receber veículos participantes" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:80 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:82 msgid "invalid formation participant" msgstr "informação de participante inválida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:94 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:96 msgid "repeated vehicles in participant list" msgstr "veículos repetidos na lista de participantes" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:108 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:110 msgid "not enough vehicles in formation (at least 2 are required)" msgstr "não existem veículos suficientes na formaçao (exigidos 2 no mínimo)" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/VehicleFormation.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/VehicleFormation.cpp:116 msgid "local vehicle is not part of formation" msgstr "veículo local não faz parte da formação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Maneuver.cpp:180 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Maneuver.cpp:182 msgid "unsupported vertical reference" msgstr "referência vertical não suportada" -#: /home/maria/LSTS/dune/dune/src/DUNE/Maneuvers/Maneuver.cpp:186 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Maneuvers/Maneuver.cpp:188 msgid "no valid value for altitude has been received yet,maneuver will not proceed" msgstr "não foi recebido valor de altitude válido, a manobra não irá prosseguir" -#: /home/maria/LSTS/dune/dune/src/DUNE/Entities/BasicEntity.cpp:46 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:66 +msgid "HDF5Reader::HDF5Reader(): support for HDF5 i/o is not enabled." +msgstr "HDF5Reader::HDF5Reader(): suporte para HDF5 i/o não activado." + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:79 +msgid "HDF5Reader::HDF5Reader(): unable to open file." +msgstr "HDF5Reader::HDF5Reader(): não foi possível abrir o ficheiro." + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:113 +msgid "HDF5Reader::getDataset(): The requested dataset does not exist." +msgstr "HDF5Reader::getDataset(): O dataset pedido não existe." + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Parsers/HDF5Reader.cpp:153 +msgid "HDF5Reader::getAttribute(): requested attribute does not exist." +msgstr "HDF5Reader::getAttribute(): atributo requisitado não existe." + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Entities/BasicEntity.cpp:48 msgid "entity label already set: " msgstr "etiqueta de entidades já definidas" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:62 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:65 msgid "Pure Hardware" msgstr "\"Hardware\" Puro" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:63 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:66 msgid "Pure Simulation" msgstr "Simulação Pura" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:64 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:67 msgid "Simulation with Hardware-in-the-loop" msgstr "Simulação com \"Hardware-in-the-loop\"" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:74 msgid "No description given" msgstr "Sem descrição" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:118 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:121 #, c-format msgid "system name: '%s' (%u)" msgstr "nome do sistema: '%s' (%u)" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:122 #, c-format msgid "registered tasks: %d" msgstr "tarefas registadas: %d" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:120 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:123 #, c-format msgid "base folder: '%s'" msgstr "diretório base: '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:121 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:124 #, c-format msgid "configuration folder: '%s'" msgstr "diretório de configuração: '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:122 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:125 #, c-format msgid "web server folder: '%s'" msgstr "diretório do servidor web: '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:126 #, c-format msgid "log folder: '%s'" msgstr "diretório de logs: '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:124 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:127 #, c-format msgid "library folder: '%s'" msgstr "diretório de bibliotecas: '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:128 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:131 #, c-format msgid "execution profiles: %s" msgstr "perfil de execução: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:152 msgid "clean shutdown" msgstr "encerramento limpo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:158 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:167 #, c-format msgid "daemon running with maximum priority: %d" msgstr "\"daemon\" a correr com prioridade máxima: %d" -#: /home/maria/LSTS/dune/dune/src/DUNE/Daemon.cpp:162 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:171 msgid "daemon not running with maximum priority" msgstr "\"daemon\" não está a correr com prioridade máxima" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Parameter.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Daemon.cpp:223 +msgid "Got message to reboot system" +msgstr "Recebida mensagem para reiniciar o sistema" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Parameter.cpp:73 msgid "invalid visibility string" msgstr "palavra de visibilidade inválida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Parameter.cpp:89 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Parameter.cpp:91 msgid "invalid scope string" msgstr "palavra de escopo inválida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Parameter.cpp:132 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Parameter.cpp:134 msgid "no available reader" msgstr "nenhum leitor disponível" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/SimpleTransport.cpp:79 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/SimpleTransport.cpp:81 #, c-format msgid "outgoing: %s" msgstr "a sair: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/SimpleTransport.cpp:111 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/SimpleTransport.cpp:113 #, c-format msgid "incoming: %s" msgstr "a chegar: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/MessageFilter.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/MessageFilter.cpp:116 #, c-format msgid "invalid filter: %s" msgstr "formato inválido: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Periodic.cpp:48 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Periodic.cpp:50 msgid "Execution Frequency" msgstr "Frequência de Execução" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Periodic.cpp:51 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Periodic.cpp:53 msgid "Frequency at which task is executed" msgstr "Frequência com que a tarefa é executada" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/ParameterTable.cpp:41 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/ParameterTable.cpp:43 msgid "invalid parameter" msgstr "parâmetro inválido" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Profiles.cpp:76 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Profiles.cpp:92 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Profiles.cpp:78 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Profiles.cpp:94 #, c-format msgid "no such profile name '%s'" msgstr "perfil inexistente '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:69 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:215 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:229 msgid "Entity Label" msgstr "Nome da Entidade" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:71 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:75 msgid "Main entity label" msgstr "Nome principal da entidade" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:73 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:77 msgid "Execution Priority" msgstr "Prioridade de Execução" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:75 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:79 msgid "Execution priority" msgstr "Prioridade de execução" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:77 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:81 msgid "Activation Time" msgstr "Tempo de Ativação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:80 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:84 msgid "Deactivation Time" msgstr "Tempo de Desativação" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:83 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:87 msgid "Debug Level" msgstr "Nível de Depuração" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:114 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:128 msgid "entity label is not configured" msgstr "etiqueta da entidade não foi configurado" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:189 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:203 msgid "Active - Scope" msgstr "Ativa - Escopo" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:207 msgid "Scoped of the 'Active' parameter" msgstr "Escopo do parâmetro 'Ativa'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:196 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:210 msgid "Active - Visibility" msgstr "Ativa - Visibilidade" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:214 msgid "Visibility of the 'Active' parameter" msgstr "Visibilidade do parâmetro 'Ativa'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:202 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:216 msgid "Active" msgstr "Ativa" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:206 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:220 msgid "True to activate task, false otherwise" msgstr "Verdadeiro para ativar tarefa, falso caso contrário" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:276 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:289 msgid "activation is not in progress" msgstr "ativação não está em progresso" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:316 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:328 msgid "deactivation is not in progress" msgstr "desativação não está em progresso" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:377 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:389 msgid "restarting" msgstr "a reiniciar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:380 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:392 #, c-format msgid "restarting immediately due to error: %s" msgstr "a reiniciar imediatamente devido a erro: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:382 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:394 #, c-format msgid "restarting in %u seconds due to error: %s" msgstr "a reiniciar em %u segundos devido a erro: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:399 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:411 #, c-format msgid "failed to update parameters: %s" msgstr "falha ao atualizar parâmetros: %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:407 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:419 #, c-format msgid "task died with uncaught exception: %s: restarting" msgstr "a tarefa morreu com uma exceção não apanhada: %s, a reiniciar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:475 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:488 #, c-format msgid "updating entity parameters: %s: '%s'" msgstr "a atualizar parâmetros de entidade: %s: '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Task.cpp:695 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:708 #, c-format msgid "invalid parameter '%s'" msgstr "parâmetro inválido '%s'" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:110 -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:188 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Task.cpp:717 +msgid "unable to load parameters: %s" +msgstr "falha ao carregar parâmetros: %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:112 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:190 msgid "unknown exception" msgstr "exceção desconhecida" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:149 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:151 msgid "stopping" msgstr "a parar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:151 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:153 msgid "stopped" msgstr "parada" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:155 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:157 #, c-format msgid "failed to join task %s" msgstr "falha ao unir tarefa %s" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:179 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:181 msgid "starting" msgstr "a iniciar" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:256 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:258 #, c-format msgid "using %d%% of CPU, lowering the priority" msgstr "a usar %d%% de CPU, a baixar prioridade" -#: /home/maria/LSTS/dune/dune/src/DUNE/Tasks/Manager.cpp:261 +#: /home/maria/LSTS/temp/dune-master/source/src/DUNE/Tasks/Manager.cpp:263 #, c-format msgid "using %d%% of CPU, failed to lower the priority" msgstr "a usar %d%% de CPU, tentativa de baixar prioridade falhou" -#: /home/maria/LSTS/dune/dune/src/Actuators/SingleSIMCT01/Task.cpp:139 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/SingleSIMCT01/Task.cpp:141 msgid "invalid value for 'Motor Id'" msgstr "valor inválido para 'Motor Id'" -#: /home/maria/LSTS/dune/dune/src/Actuators/SingleSIMCT01/Task.cpp:142 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/SingleSIMCT01/Task.cpp:144 msgid "invalid value for 'Thruster Id'" msgstr "valor inválido para 'Thruster Id'" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:332 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:334 #, c-format msgid "AMC Motor %d - ERROR" msgstr "Motor AMC %d - ERRO" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:348 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:350 msgid "AMC Motor ERROR" msgstr "ERRO Motor AMC" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:353 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:355 msgid "ALL MOTORS OK" msgstr "TODOS OS MOTORES OK" -#: /home/maria/LSTS/dune/dune/src/Actuators/AMC/Task.cpp:435 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/AMC/Task.cpp:437 msgid "Wrong parameter request" msgstr "Pedido de parâmetro errado" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:84 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:86 msgid "init" msgstr "inicialização" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:85 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:87 msgid "i2c" msgstr "i2c" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:86 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:88 msgid "power" msgstr "fonte de energia" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:87 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:89 msgid "hall" msgstr "sensores de hall" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:88 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:90 msgid "rotor locked" msgstr "rotor bloqueado" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:89 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:91 msgid "mcu temperature" msgstr "temperatura do mcu" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:90 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:92 msgid "bridge temperature" msgstr "temperatura da ponte" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:91 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:93 msgid "motor temperature" msgstr "temperatura do motor" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:365 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:367 msgid "Motor control mode must be one of 'none', 'voltage', 'current', 'rpm'" msgstr "Controlo de motor tem de ser feito através de 'none', 'voltage', 'current', 'rpm'" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:620 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:622 #, c-format msgid "device error: %s" msgstr "erro do dispositivo: %s" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:627 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:629 msgid "power is not good" msgstr "fonte de energia não está sã" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:631 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:633 msgid "device init error, requesting reset" msgstr "erro ao iniciar dispositivo, pedido reset" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:641 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:643 msgid "CMD_ACTUATE Data size doesn't match!" msgstr "CMD_ACTUATE Incompatibilidade tamanho Data" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:666 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:668 msgid "CMD_CONFIG data size doesn't match!" msgstr "CMD_CONFIG tamanho de dados não compatível!" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:676 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:678 msgid "CMD_CONFIG_DCYC data size doesn't match!" msgstr "CMD_CONFIG_DCYC tamanho de dados não compatível!" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:686 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:688 msgid "CMD_CONFIG_IADC data size doesn't match!" msgstr "CMD_CONFIG_IADC tamanho de dados não compatível!" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:696 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:698 msgid "CMD_CONFIG_ERPM data size doesn't match!" msgstr "CMD_CONFIG_ERPM tamanho de dados não compatível!" -#: /home/maria/LSTS/dune/dune/src/Actuators/Broom/Task.cpp:838 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/Broom/Task.cpp:840 #, c-format msgid "device reported: %s" msgstr "dispositivo reportado: %s" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:153 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:155 msgid "LED - Patterns" msgstr "LED - Padrões" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:158 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:160 msgid "List of LED patterns" msgstr "Lista de padrões de LEDs" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:160 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:162 msgid "LED - Patterns Pulse Width" msgstr "LED - Largura de Pulso dos Padrões" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:166 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:168 msgid "Pulse width for LED patterns" msgstr "Largura do pulso dos padrões de LEDs" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:168 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:170 msgid "LED - External Driver" msgstr "Controlador de LEDs" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:172 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:174 msgid "Enable external LED driver" msgstr "falha ao configurar controlador externo de LEDs" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:174 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:176 msgid "LED - External Trigger" msgstr "LED - Gatilho Externo" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:178 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:180 msgid "Enable external LED trigger" msgstr "falha ao configurar controlador externo de LEDs" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:243 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:245 msgid "failed to get constant parameters" msgstr "falha ao adquirir parâmetros constantes" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:262 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:264 msgid "failed to set LED patterns" msgstr "falha ao definir distância" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:290 -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:293 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:292 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:295 msgid "failed to configure LED driver" msgstr "falha ao configurar controlador externo de LEDs" -#: /home/maria/LSTS/dune/dune/src/Actuators/LED4R/Task.cpp:296 +#: /home/maria/LSTS/temp/dune-master/source/src/Actuators/LED4R/Task.cpp:298 msgid "failed to configure LED pattern pulse width" msgstr "falhou a configurar modo de strobe" -#: /home/maria/LSTS/dune/dune/src/Simulators/VSIM/Task.cpp:119 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/VSIM/Task.cpp:129 msgid "error loading world parameters." msgstr "erro ao carregar parâmetros do mundo." -#: /home/maria/LSTS/dune/dune/src/Simulators/VSIM/Task.cpp:123 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/VSIM/Task.cpp:133 msgid "error loading vehicle parameters." msgstr "erro ao carregar parâmetros de veículo." -#: /home/maria/LSTS/dune/dune/src/Simulators/Servos/Task.cpp:200 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/VSIM/Task.cpp:194 +#, c-format +msgid "Setting stream velocity: %f m/s N : %f m/s E : %f m/s D" +msgstr "Stream velocity configurada: %f m/s N : %f m/s E : %f m/s D" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Servos/Task.cpp:202 #, c-format msgid "fault triggered in servo #%d" msgstr "falha lançada no servo #%d" -#: /home/maria/LSTS/dune/dune/src/Simulators/Servos/Task.cpp:207 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Servos/Task.cpp:209 #, c-format msgid "servo #%d is no longer in fault" msgstr "servo #%d voltou ao estado normal" -#: /home/maria/LSTS/dune/dune/src/Simulators/AcousticModem/Task.cpp:96 -msgid "restarting to change UDP port" -msgstr "a reiniciar para mudar a porta UDP" +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp:59 +msgid "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): dimensions of velocity components do not match." +msgstr "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): dimensões dos componentes da velocidade não coincidem." -#: /home/maria/LSTS/dune/dune/src/Simulators/Docking/Task.cpp:275 -msgid "Success" -msgstr "Sucesso" +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp:65 +msgid "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): data must be three-dimensional (2D space + time)." +msgstr "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): dados têm que ser tridimensionais (espaço 2D + tempo)." + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp:73 +msgid "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): data dimensions do not match grid dimensions." +msgstr "Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator(): dimensions dos dados não coincidem com dimensões da grelha." + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:153 +#, c-format +msgid "Setting default stream velocity: %f m/s N : %f m/s E : %f m/s D" +msgstr "A configurar stream velocity default: %f m/s N : %f m/s E : %f m/s D" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:169 +#, c-format +msgid "" +"An error ocurred while accessing the stream velocity source:\n" +"\t%s\n" +"\tFalling back to constant stream velocity." +msgstr "" +"Um erro ocurreu durante o acesso ao stream velocity source:\n" +"\t%s\n" +"\tA retornar para stream velocity constante." -#: /home/maria/LSTS/dune/dune/src/Simulators/UnderwaterAcoustics/Task.cpp:381 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:182 #, c-format -msgid "unexpected simulation message: %s" -msgstr "mensagem de simulação inesperada: %s" +msgid "Setting initial time delta to %f seconds" +msgstr "A estabelecer time delta inicial para %f segundos" -#: /home/maria/LSTS/dune/dune/src/Simulators/UAV/Task.cpp:431 +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/StreamVelocity/Task.cpp:209 +#, c-format +msgid "Stream velocity is %f m/s N : %f m/s E : %f m/s D" +msgstr "Stream velocity é %f m/s N : %f m/s E : %f m/s D" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/AcousticModem/Task.cpp:283 +msgid "Unknown transmission status: %s" +msgstr "Estado da transmissão desconhecido: %s" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/Docking/Task.cpp:277 +msgid "Success" +msgstr "Sucesso" + +#: /home/maria/LSTS/temp/dune-master/source/src/Simulators/UAV/Task.cpp:433 #, c-format msgid "UAV simulation type: %s" msgstr "Tipo de simulação UAV: %s" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:401 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:403 msgid "failed to activate required entities" msgstr "falha ao ativar as entidades necessárias" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:403 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:405 msgid "failed to configure camera" msgstr "falha ao configurar câmara" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:405 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:407 msgid "failed to start video streamming" msgstr "falha ao iniciar \"stream\" vídeo" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:407 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:409 msgid "activation timed out for unknown reason" msgstr "ativação excedeu tempo limite por razão desconhecida" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:449 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:451 msgid "failed to deactivate required entities" msgstr "falha ao desativar as entidades necessárias" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:459 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:461 msgid "activated" msgstr "ativado" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:467 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:469 msgid "stopped video stream" msgstr "\"stream\" vídeo parado" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:489 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:491 msgid "invalid entity" msgstr "entidade inválida" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:518 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:520 msgid "failed to start video stream" msgstr "falha ao iniciar \"stream\" vídeo" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:538 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:540 msgid "started video stream" msgstr "\"stream\" vídeo iniciado" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:629 -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:670 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:631 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:672 msgid "failed to set property" msgstr "falha ao configurar propriedade" -#: /home/maria/LSTS/dune/dune/src/Vision/Lumenera/Task.cpp:917 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/Lumenera/Task.cpp:919 msgid "successfully configured camera" msgstr "câmara configurada com sucesso" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/Task.cpp:454 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/Task.cpp:456 msgid "keep alive failed" msgstr "falhou keep alive" -#: /home/maria/LSTS/dune/dune/src/Vision/DFK51BG02H/Task.cpp:471 +#: /home/maria/LSTS/temp/dune-master/source/src/Vision/DFK51BG02H/Task.cpp:473 #, c-format msgid "lost at least %d packets" msgstr "perda de pelo menos %d pacotes" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:87 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:70 msgid "failed to set standby" msgstr "falha ao colocar em espera" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:111 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:97 msgid "failed to set framing mode" msgstr "falha ao definir modo de framing" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:219 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:205 msgid "failed to set recording file format" msgstr "falha ao definir formato do ficheiro de gravação" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:228 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:214 msgid "failed to set recording file ping count" msgstr "falha ao definir numero de pings" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:286 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:272 msgid "failed to set recording file prefix" msgstr "falha ao definir prefixo de ficheiro de dados" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:378 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:364 msgid "failed to start slave" msgstr "falha ao arrancar escravo" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:388 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:374 msgid "failed to end slave" msgstr "falha ao terminar escravo" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:397 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:383 msgid "failed to open sonar" msgstr "falha ao abrir sonar" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/CommandLink.hpp:413 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/CommandLink.hpp:399 msgid "failed to close sonar" msgstr "falhou ao fechar sonar" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:267 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:250 msgid "acquiring PPS signal" msgstr "a adquirir sinal PPS" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:276 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:259 msgid "PPS signal acquired" msgstr "sinal PPS adquirido" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:286 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:269 msgid "clock is disciplined" msgstr "relógio está corrigido" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:293 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:276 #, c-format msgid "disciplining clock (%lld µs)" msgstr "a corrigir relógio (%lld µs)" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:304 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:287 msgid "clock is synchronized" msgstr "relógio sincronizado" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:306 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:289 msgid "failed to set the hardware clock" msgstr "falhou ao definir relógio no sistema" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:321 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:304 #, c-format msgid "adjusting clock by %ld s" msgstr "a ajustar relógio em %ld s" -#: /home/maria/LSTS/dune/dune/private/src/Supervisors/ClockPPS/Task.cpp:333 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Supervisors/ClockPPS/Task.cpp:316 #, c-format msgid "clock is synchronized [%lld, %ld, %ld]" msgstr "relógio sincronizado [%lld, %ld, %ld]" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:246 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:246 msgid "no gimbal data" msgstr "sem dados da gimbal" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:424 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:424 msgid "error decoding gimbal georeference packet" msgstr "erro ao descodificar dados de georeferênciação" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:448 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:448 msgid "error decoding gimbal version packet" msgstr "erro ao descodificar pacote com versão da gimbal" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:452 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:452 #, c-format msgid "software version %d.%d.%d patch %d %4d-%02d-%02d" msgstr "versão de software %d.%d.%d patch %d %4d-%02d-%02d" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:461 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:461 #, c-format msgid "hardware board - SN %0u FN %u rev %u config %u %u-%02u-%02u" msgstr "placa de hardware - SN %0u FN %u rev %u config %u %u-%02u-%02u" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/TASE/Task.cpp:472 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/TASE/Task.cpp:472 #, c-format msgid "camera %d -- id: %u HFOV: [%0.2f, %0.2f]" msgstr "câmara %d -- id: %u HFOV: [%0.2f, %0.2f]" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:144 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:144 #, c-format msgid "creating a TCP connection | %s %u" msgstr "a criar uma ligação TCP | %s %u" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:146 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:146 msgid "Piccolo interface initialized" msgstr "interface Piccolo inicializada" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:168 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:168 #, c-format msgid "%s - deactivating" msgstr "%s - a desativar" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:170 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:170 #, c-format msgid "%s - activating" msgstr "%s - a ativar" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:183 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:183 msgid "tracker is NOT enabled" msgstr "tracker NÃO está habilitado" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:190 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:190 msgid "speed control" msgstr "controlo de velocidade" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:191 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:191 msgid "altitude control" msgstr "controlo de altitude" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:192 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:192 msgid "bank control" msgstr "Controlo de Pranchamento" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:193 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:193 msgid "heading control" msgstr "controlo de orientação" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:194 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:194 msgid "vertical rate control" msgstr "controlo de taxa vertical" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:195 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:195 msgid "path control" msgstr "controlo de caminho" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:274 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:274 msgid "altitude control is NOT active" msgstr "controlo de altitude NÃO está ativo" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:280 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:280 msgid "Not a valid height reference" msgstr "Referência de altitude WGS não válida" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:301 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:301 msgid "bank control is NOT active" msgstr "controlo de bank NÃO está ativo" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:322 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:322 msgid "heading control is NOT active" msgstr "controlo de orientação NÃO está ativo" -#: /home/maria/LSTS/dune/dune/private/src/Piccolo/Task.cpp:348 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Piccolo/Task.cpp:348 msgid "vertical rate control is NOT active" msgstr "controlo de taxa vertical NÃO está ativo" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:142 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:131 msgid "High-Frequency Channel" msgstr "Canal de Alta Frequência" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:146 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:135 msgid "Enable high-frequency channel" msgstr "Habilitar canal de alta frequência" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:148 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:137 msgid "Low-Frequency Channel" msgstr "Canal de Baixa Frequência" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/Klein3500/Task.cpp:152 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:141 msgid "Enable low-frequency channel" msgstr "Habilitar canal de baixa frequência" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/ExplorerDVL/Task.cpp:160 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:219 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:143 +msgid "Low-Frequency Bathymetry Channel" +msgstr "Canal de baixa frequência de batimetria" + +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/Klein3500/Task.cpp:147 +msgid "Enable low-frequency bathymetry channel" +msgstr "Habilitar canal de baixa frequência de batimetria" + +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/ExplorerDVL/Task.cpp:143 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:219 msgid "Use Device at Surface" msgstr "Usar Dispositivo à Superfície" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:26 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:26 msgid "failed to set continous mode" msgstr "falhou a entrar em modo contínuo" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:27 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:27 msgid "failed to set transducer face orientation" msgstr "falha ao especificar orientação da face do transdutor" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:28 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:28 msgid "failed to set sampling frequency" msgstr "falha ao configurar taxa de amostragem" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:418 -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:430 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:418 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:430 msgid "failed to request current output formats" msgstr "falha ao pedir formatos de saída atuais" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:443 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:443 msgid "failed to configure output format" msgstr "falha ao configurar formate de saída" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:601 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:601 msgid "failed to start data sampling" msgstr "falha ao começar amostragem de dados" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:615 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:615 msgid "failed to stop data sampling" msgstr "falha ao parar amostragem de dados" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:624 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:624 msgid "failed to enable user-defined sound speed" msgstr "falhou ao habilitar a velocidade do som definida por utilizador" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:631 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:631 msgid "failed to set initial sound speed" msgstr "falha ao especificar velocidade do som inicial" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:717 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:717 msgid "invalid sample" msgstr "amostra inválida" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:863 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:863 msgid "sensor data timeout" msgstr "excedido o tempo limite dos dados do sensor" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:869 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:869 msgid "too many samples below threshold" msgstr "demasiadas amostras abaixo do limite" -#: /home/maria/LSTS/dune/dune/private/src/Sensors/NavQuestDVL/Task.cpp:904 +#: /home/maria/LSTS/temp/dune-master/source/private/src/Sensors/NavQuestDVL/Task.cpp:904 msgid "rebooting" msgstr "a reiniciar" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:1 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:1 msgid "A/D Board" msgstr "Placa A/D" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:2 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:2 msgid "AHRS" msgstr "AHRS" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:3 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:3 msgid "AIS Receiver" msgstr "Recetor AIS" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:4 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:4 msgid "Acoustic Access Controller" msgstr "Controlador de Acesso Acústico" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:5 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:5 msgid "Acoustic Modem" msgstr "Modem Acústico" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:6 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:6 +msgid "Acoustic Modem Simulator" +msgstr "Simulador de Modem Acústico" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:7 msgid "Allocator" msgstr "Alocador" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:7 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:8 msgid "Announce" msgstr "Anunciador" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:8 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:9 msgid "Antenna Tracker" msgstr "Tracker da Antena" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:9 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:10 msgid "Arduino Serial" msgstr "Arduino Série" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:10 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:11 msgid "Attitude" msgstr "Atitude" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:11 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:12 msgid "Autopilot" msgstr "Piloto Automático" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:12 -msgid "CPU" -msgstr "CPU" +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:13 +msgid "BATMAN" +msgstr "BATMAN" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:13 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:14 +msgid "Back Seat TCP Server" +msgstr "Servidor TCP de Back Seat" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:15 msgid "CTD" msgstr "CTD" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:14 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:16 msgid "CTD Simulator" msgstr "Simulador de CTD" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:15 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:17 msgid "Cache" msgstr "Acumulador" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:17 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:19 msgid "Camera Backend" msgstr "Câmara Backend" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:18 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:20 msgid "Camera Module" msgstr "Modulo da Câmara" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:19 -msgid "Chlorophyll Probe" -msgstr "Sonda de Clorofíla" - -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:20 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:21 msgid "Clock" msgstr "Relógio" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:21 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:22 msgid "Collisions" msgstr "Colisões" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:22 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:23 +msgid "Communications Manager" +msgstr "Gestor de Comunicações" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:24 msgid "Communications Relay Maneuver" msgstr "Manobra de Retransmissão de Comunicações" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:23 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:25 msgid "Compass Calibration Maneuver" msgstr "Manobra de Calibração de Bússola" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:24 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:26 msgid "Cover Area" msgstr "Cobre Área" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:25 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:27 +msgid "CyclopsC7" +msgstr "CyclopsC7" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:28 msgid "DAQ" -msgstr "Aquisição de Dados" +msgstr "DAQ" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:26 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:29 +msgid "DMS" +msgstr "DMS" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:30 msgid "DVL" msgstr "DVL" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:27 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:31 +msgid "DataStore Source" +msgstr "DataStore Source" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:32 +msgid "DataStore Transport" +msgstr "DataStore Transport" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:33 msgid "Depth Control" msgstr "Controlo de Profundidade" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:28 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:34 msgid "Depth Sensor" msgstr "Sensor de Profundidade" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:29 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:35 msgid "Discovery" msgstr "Descoberta" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:30 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:36 msgid "Diving" msgstr "Mergulho" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:31 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:37 msgid "Docking" -msgstr "Docagem" +msgstr "Docking" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:32 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:38 msgid "Echo Sounder" -msgstr "Ecobatímetro" +msgstr "Echo Sounder" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:33 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:39 msgid "Emergency Monitor" msgstr "Monitor de Emergências" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:34 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:40 msgid "Emulated GPS" msgstr "GPS Emulado" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:35 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:41 msgid "Entity Monitor" msgstr "Monitor de Entidades" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:36 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:42 msgid "Environment" msgstr "Ambiente" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:37 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:43 +msgid "Evologics SerialOverTCP" +msgstr "Evologics SerialOverTCP" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:44 msgid "FTP Server" msgstr "Servidor FTP" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:38 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:45 msgid "Follow Reference" msgstr "Seguimento de Referência" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:39 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:46 msgid "Follow Reference Maneuver" msgstr "Manobra Seguir Referência" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:40 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:47 msgid "Follow System Maneuver" msgstr "Manobra de Seguimento de Sistema" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:41 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:48 msgid "Formation Control" msgstr "Controlo de Formação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:42 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:49 msgid "Formation Link" msgstr "Link de Formação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:43 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:50 msgid "Fuel" msgstr "Energia" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:44 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:51 msgid "GPS" msgstr "GPS" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:45 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:52 msgid "GSM" msgstr "GSM" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:46 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:53 msgid "HTTP Server" msgstr "Servidor HTTP" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:47 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:54 msgid "Heave Motor" msgstr "Motor de Elevação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:48 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:55 msgid "Height Control" msgstr "Controlo de Altitude" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:49 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:56 msgid "Horizontal Plane Control" msgstr "Controlo no Plano Horizontal" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:51 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:58 msgid "IMU Power Supply" msgstr "Fonte de Energia do IMU" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:52 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:59 msgid "Iridium Modem" msgstr "Modem Iridium" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:53 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:60 msgid "Iridium Transport" msgstr "Transporte Iridium" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:54 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:61 msgid "LBL" msgstr "LBL" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:55 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:62 msgid "LBL Estimator" msgstr "Estimador LBL" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:56 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:63 msgid "LCD" msgstr "LCD" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:57 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:64 msgid "LED Driver" msgstr "Controlador de LEDs" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:58 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:65 msgid "LEDs" msgstr "LEDs" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:59 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:66 msgid "Leak Simulator" msgstr "Simulador de Fugas" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:60 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:67 msgid "Log Book" msgstr "Diário de Bordo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:61 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:68 msgid "Logger" msgstr "Registador" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:62 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:69 msgid "Lost Comms" msgstr "Perda de Comunicação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:63 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:70 msgid "Lost Comms Monitor" msgstr "Monitor de Perda de Comunicação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:64 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:71 msgid "MCD4R" msgstr "MCD4R" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:65 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:72 +msgid "Magnetometer" +msgstr "Magnetómetro" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:73 msgid "Mainboard" msgstr "Placa Principal" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:66 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:74 msgid "Medium" msgstr "Meio" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:67 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:75 msgid "Message Fragments" msgstr "Fragmentos de Mensagens" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:68 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:76 msgid "Mobile Internet" msgstr "Internet Móvel" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:69 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:77 msgid "Motor" msgstr "Motor" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:70 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:78 msgid "Motor Controller" msgstr "Controlador de Motor" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:71 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:79 msgid "Multibeam" msgstr "Sonar Multifeixe" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:72 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:80 msgid "Multiplexer Maneuver" msgstr "Manobra Multiplexer" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:73 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:81 msgid "Navigation" msgstr "Navegação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:74 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:82 +msgid "OEMX" +msgstr "OEMX" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:83 msgid "Operational Limits" msgstr "Limites de Operação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:75 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:84 msgid "Oxygen Sensor" msgstr "Sensor de Oxigénio" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:76 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:85 msgid "PTUD48" msgstr "PTUD48" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:77 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:86 msgid "PTUTransport" msgstr "PTUTransport" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:78 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:87 +msgid "PWM" +msgstr "PWM" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:88 msgid "Panel" msgstr "Painel" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:79 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:89 msgid "Panel Buttons" msgstr "Botões do Painel" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:80 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:90 msgid "Path Control" msgstr "Controlo de Caminho" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:81 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:91 msgid "Path Control Leader" msgstr "Líder de Controlo de Caminho" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:82 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:92 msgid "Pencil Beam" msgstr "Feixe de Distância" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:83 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:93 msgid "Photo Trigger" msgstr "Gatilho da Câmara" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:84 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:94 msgid "Plan Database" msgstr "Base de Dados de Planos" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:85 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:95 msgid "Plan Engine" msgstr "Motor de Planos" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:86 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:96 msgid "Plan Generator" msgstr "Gerador de Planos" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:87 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:97 msgid "Port Bow Motor" msgstr "Motor de Proa a Bombordo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:88 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:98 msgid "Port Stern Motor" msgstr "Motor de Popa a Bombordo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:89 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:99 msgid "Power Board" msgstr "Placa de Energia" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:90 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:100 msgid "Power Source" msgstr "Fonte de Energia" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:91 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:101 msgid "Power Supervisor" msgstr "Supervisor de Energia" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:92 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:102 msgid "Power Supply" msgstr "Fonte de Energia" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:93 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:103 +msgid "Radio" +msgstr "Rádio" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:104 msgid "Ranger" msgstr "Medidor de Distâncias" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:94 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:105 msgid "Recovery Supervisor" msgstr "Supervisor de Recuperação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:95 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:106 msgid "Remote Control" msgstr "Controlo Remoto" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:96 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:107 msgid "Remote Operation" msgstr "Operação Remota" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:97 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:108 msgid "Report Supervisor" msgstr "Supervisor de Relatórios" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:98 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:109 msgid "Rows Coverage Maneuver" msgstr "Manobra \"Rows Coverage\"" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:99 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:110 +msgid "SADC" +msgstr "SADC" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:111 msgid "Service Announcer" msgstr "Serviço de Anúncio" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:100 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:112 msgid "Service Discovery" msgstr "Descoberta de Serviços" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:101 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:113 msgid "Servo Controller" msgstr "Controlador de Servos" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:102 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:114 msgid "Servo Monitor" msgstr "Monitor de Servos" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:103 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:115 msgid "Servos" msgstr "Servos" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:104 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:116 msgid "Sidescan" msgstr "Sonar de Varrimento Lateral" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:105 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:117 msgid "Simulation Engine" msgstr "Motor de Simulação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:106 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:118 msgid "Slave CPU" msgstr "CPU Escravo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:107 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:119 msgid "Sound Speed Sensor" msgstr "Sensor de Velocidade do Som" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:108 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:120 msgid "Sound Speed Simulator" msgstr "Simulador de Velocidade do Som" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:109 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:121 msgid "Speed Control" msgstr "Controlo de Velocidade" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:110 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:122 msgid "Starboard Bow Motor" msgstr "Motor de Proa a Estibordo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:111 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:123 msgid "Starboard Stern Motor" msgstr "Motor de Popa a Estibordo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:112 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:124 +msgid "Stream Velocity Simulator" +msgstr "Simulador de Stream Velocity" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:125 +msgid "TCP On Demand" +msgstr "TCP por Demanda" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:126 msgid "TCP Server" msgstr "Servidor TCP" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:113 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:127 msgid "TCP to Camera CPU" msgstr "TCP para Computador da Câmara" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:114 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:128 msgid "TCP to Master" msgstr "TCP para o Mestre" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:115 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:129 msgid "TCP to Slave CPU" msgstr "TCP para CPU Escravo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:116 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:130 msgid "TREX" msgstr "TREX" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:117 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:131 msgid "Teleoperation Maneuver" msgstr "Manobra de Teleoperação" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:118 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:132 msgid "Text Message Parser" msgstr "Processador de Mensagens de Texto" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:119 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:133 +msgid "Thermal Zone" +msgstr "Zona Térmica" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:134 +msgid "UART Serial" +msgstr "UART Série" + +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:135 msgid "UAV Simulator" -msgstr "Simulador de AUV" +msgstr "Simulador de UAV" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:120 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:136 msgid "UAVCamera" msgstr "Câmara UAV" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:121 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:137 msgid "UDP" msgstr "UDP" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:122 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:138 msgid "UDP to TREX" msgstr "UDP para TREX" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:123 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:139 msgid "USBL" msgstr "USBL" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:124 -msgid "Underwater Acoustics Simulator" -msgstr "Simulador de Comunicação Acústica Subaquática" - -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:125 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:140 msgid "Vehicle Supervisor" msgstr "Supervisor de Veículo" -#: /home/maria/LSTS/dune/dune/i18n/entity_labels.txt:126 +#: /home/maria/LSTS/temp/dune-master/source/i18n/entity_labels.txt:141 msgid "Water Quality Sensor" msgstr "Sensor da Qualidade da Água" +#~ msgid "error while parsing Iridium message" +#~ msgstr "erro ao interpretar mensagem Iridium" + +#~ msgid "unable to avoid obstacle" +#~ msgstr "incapaz de evitar obstáculo" + +#~ msgid "avoid obstacle" +#~ msgstr "evitar obstáculo" + +#~ msgid "restarting to change UDP port" +#~ msgstr "a reiniciar para mudar a porta UDP" + +#~ msgid "CPU" +#~ msgstr "CPU" + +#~ msgid "Chlorophyll Probe" +#~ msgstr "Sonda de Clorofíla" + +#~ msgid "Underwater Acoustics Simulator" +#~ msgstr "Simulador de Comunicação Acústica Subaquática" + #~ msgid "Source Level" #~ msgstr "Nível da Fonte" @@ -4070,18 +4651,12 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "detected sensor '%s' with serial number '%s'" #~ msgstr "detetado sensor '%s' com número de série '%s'" -#~ msgid "failed to find valid device" -#~ msgstr "falha a encontrar dispositivo válido" - #~ msgid "failed to initialize USB library" #~ msgstr "falha ao inicializar biblioteca USB" #~ msgid "FPGA version: %02x.%02x" #~ msgstr "versão da FPGA: %02x.%02x" -#~ msgid "serial number: %s" -#~ msgstr "número de série: %s" - #~ msgid "failed to turn off internal channels" #~ msgstr "falha ao desligar canais internos" @@ -4142,18 +4717,6 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "exif data exceeds maximum segment size" #~ msgstr "dados exif excedem tamanho máximo do segmento" -#~ msgid "failed to stop device" -#~ msgstr "falhou ao parar disposito" - -#~ msgid "failed to read EEPROM#130" -#~ msgstr "falha ao ler EEPROM#130" - -#~ msgid "failed to read EEPROM#230" -#~ msgstr "falha ao ler EEPROM#230" - -#~ msgid "unexpected byte" -#~ msgstr "\"byte\" não esperado" - #~ msgid "unable to stop continuous output" #~ msgstr "incapaz de parar output contínuo" @@ -4175,9 +4738,6 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "timeout waiting for device response" #~ msgstr "tempo limite excedido à espera de resposta do dispositivo" -#~ msgid "Enable Reports" -#~ msgstr "Permitir Relatórios" - #~ msgid "messages doesn't fit in one frame" #~ msgstr "mensagens não cabem num única trama" @@ -4193,9 +4753,6 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "Rhodamine Simulator" #~ msgstr "Simulador de Rodamína" -#~ msgid "Thermal Zone" -#~ msgstr "Zona Térmica" - #~ msgid "firmware folder: '%s'" #~ msgstr "diretório de \"firmware\": '%s'" @@ -4229,18 +4786,12 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "no sonar head" #~ msgstr "sem cabeça do sonar" -#~ msgid "unable to change directory" -#~ msgstr "incapaz de mudar diretório" - #~ msgid "operation mode list labels and values have different sizes" #~ msgstr "lista de modos de operação e de valores têm tamanhos diferentes" #~ msgid "invalid opmode value (zero)" #~ msgstr "modo de operação inválido (zero)" -#~ msgid "Acoustic Modem Simulated" -#~ msgstr "Modem Acústico Simulado" - #~ msgid "CLRanger" #~ msgstr "CLRanger" @@ -4589,9 +5140,6 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "Report more verbose data acoustically" #~ msgstr "Reportar dados acusticamente verbosamente" -#~ msgid "Reports periodicity" -#~ msgstr "Periodicidade de relatórios" - #~ msgid "Broom" #~ msgstr "Broom" @@ -4937,9 +5485,6 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "GPS Timeout" #~ msgstr "Tempo Limite do GPS" -#~ msgid "GPS timeout" -#~ msgstr "Tempo limite do GPS" - #~ msgid "Hard-Iron Calibration" #~ msgstr "Calibração \"hard-iron\"" @@ -5030,9 +5575,6 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "waypoint %d is not a handover waypoint" #~ msgstr "waypoint %d não é um waypoint handover" -#~ msgid "configuration has been set" -#~ msgstr "configuração definida" - #~ msgid "PICCOLO SYSTEM RESET ! Info: %u %u %u %u" #~ msgstr "RESET SISTEMA PICCOLO ! Info: %u %u %u %u" @@ -5126,9 +5668,6 @@ msgstr "Sensor da Qualidade da Água" #~ msgid "units" #~ msgstr "unidades" -#~ msgid "%s done" -#~ msgstr "%s terminado" - #~ msgid "ascent" #~ msgstr "ascenção" diff --git a/programs/coarse_altitude.cpp b/programs/coarse_altitude.cpp index 8c8dda36a7..c56f79d455 100644 --- a/programs/coarse_altitude.cpp +++ b/programs/coarse_altitude.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/compass_calibration.cpp b/programs/compass_calibration.cpp index 8aab2c5ac4..0056735b8f 100644 --- a/programs/compass_calibration.cpp +++ b/programs/compass_calibration.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/distance_travelled.cpp b/programs/distance_travelled.cpp index 872b3e0661..29b3cb8762 100644 --- a/programs/distance_travelled.cpp +++ b/programs/distance_travelled.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/energy_consumed.cpp b/programs/energy_consumed.cpp index 19a4e76d41..e767dadfdb 100644 --- a/programs/energy_consumed.cpp +++ b/programs/energy_consumed.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/filter_log.cpp b/programs/filter_log.cpp index f8b59f0a1e..3183ff1b02 100644 --- a/programs/filter_log.cpp +++ b/programs/filter_log.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/fuel_replay.cpp b/programs/fuel_replay.cpp index 2482e8c494..741e0ae52b 100644 --- a/programs/fuel_replay.cpp +++ b/programs/fuel_replay.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/generators/imc/code.py b/programs/generators/imc/code.py index 8bbcbaacf1..713bba089a 100644 --- a/programs/generators/imc/code.py +++ b/programs/generators/imc/code.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/generators/imc/deps.py b/programs/generators/imc/deps.py index a6ac3995bb..50f8c183c9 100644 --- a/programs/generators/imc/deps.py +++ b/programs/generators/imc/deps.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/generators/imc/file.py b/programs/generators/imc/file.py index 7da44b1af8..e0a3e6ebe1 100644 --- a/programs/generators/imc/file.py +++ b/programs/generators/imc/file.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/generators/imc/utils.py b/programs/generators/imc/utils.py index 7be66de8fa..135ab4ced5 100644 --- a/programs/generators/imc/utils.py +++ b/programs/generators/imc/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -154,7 +154,13 @@ def abbrev_to_macro(abbrev, prefix = ''): # Compute MD5 sum. def compute_md5(imc_xml): - m = hashlib.md5() + try: + # To account for the need to use the not part of the upstream + # but needed in Red Hat Enterprise Linux and derivatives that + # need to call "hashlib.new('md5', usedforsecurity=False)" + m = hashlib.new('md5', usedforsecurity=False) + except TypeError: + m = hashlib.md5() m.update(open(imc_xml, 'rb').read()) return m.hexdigest() diff --git a/programs/generators/imc_addresses.py b/programs/generators/imc_addresses.py index e7b5efaba5..2a82347723 100644 --- a/programs/generators/imc_addresses.py +++ b/programs/generators/imc_addresses.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/generators/imc_blob.py b/programs/generators/imc_blob.py index 5cda03094f..0217f3e63f 100644 --- a/programs/generators/imc_blob.py +++ b/programs/generators/imc_blob.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -66,7 +66,7 @@ tree = ET.parse(args.xml) # Remove 'description' tags. -for parent in tree.getiterator(): +for parent in tree.iter(): for child in parent: if child.tag == 'description': parent.remove(child) diff --git a/programs/generators/imc_code.py b/programs/generators/imc_code.py index b98286bb14..092c62c46a 100644 --- a/programs/generators/imc_code.py +++ b/programs/generators/imc_code.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -108,7 +108,7 @@ def __init__(self, root, node, hpp, cpp, consts): public.append(f) # clone() - f = Function('clone', 'Message*', const = True, inline = True) + f = Function('clone', '%(abbrev)s*' % node.attrib, const = True, inline = True) f.body('return new %(abbrev)s(*this);' % node.attrib) public.append(f) diff --git a/programs/generators/imc_download.py b/programs/generators/imc_download.py index 23c6001ab2..3e0c7c1e37 100644 --- a/programs/generators/imc_download.py +++ b/programs/generators/imc_download.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/generators/imc_tests.py b/programs/generators/imc_tests.py index 53761494a7..df2a4aff63 100644 --- a/programs/generators/imc_tests.py +++ b/programs/generators/imc_tests.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -146,7 +146,7 @@ def fill_field(self, field): self._fd.append('%s.%s.assign("%s");' % (self._var, name, value)) elif type == 'rawdata': tname = self.make_temp() - self._fd.append('const char %s[] = {%s};' % (tname, self.make_array())) + self._fd.append('const signed char %s[] = {%s};' % (tname, self.make_array())) self._fd.append('{0}.{1}.assign({2}, {2} + sizeof({2}));'.format(self._var, name, tname)) elif type == 'message': self.set_message(name, field) diff --git a/programs/generators/status_codes.py b/programs/generators/status_codes.py index 5458468782..6e3b26e5c5 100644 --- a/programs/generators/status_codes.py +++ b/programs/generators/status_codes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/gps_phototrigger.cpp b/programs/gps_phototrigger.cpp index 4534160090..65724bcc0c 100644 --- a/programs/gps_phototrigger.cpp +++ b/programs/gps_phototrigger.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/gsmux/Fields.def b/programs/gsmux/Fields.def index 800060c6b5..fdcdd9ebd1 100644 --- a/programs/gsmux/Fields.def +++ b/programs/gsmux/Fields.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/gsmux/Filter.hpp b/programs/gsmux/Filter.hpp index bf3881b1d8..80dc6d8630 100644 --- a/programs/gsmux/Filter.hpp +++ b/programs/gsmux/Filter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/gsmux/Parser.hpp b/programs/gsmux/Parser.hpp index 430acec861..92cdc362a6 100644 --- a/programs/gsmux/Parser.hpp +++ b/programs/gsmux/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/gsmux/gsmux-tsv.cpp b/programs/gsmux/gsmux-tsv.cpp index 26fb9e463c..639eec1787 100644 --- a/programs/gsmux/gsmux-tsv.cpp +++ b/programs/gsmux/gsmux-tsv.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/gsmux/gsmux.cpp b/programs/gsmux/gsmux.cpp index 1c95664120..194b89f000 100644 --- a/programs/gsmux/gsmux.cpp +++ b/programs/gsmux/gsmux.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/scripts/dune-cdash-build.rb b/programs/scripts/dune-cdash-build.rb index 873e8e4fcc..ce978b382a 100644 --- a/programs/scripts/dune-cdash-build.rb +++ b/programs/scripts/dune-cdash-build.rb @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/scripts/dune-create-changelog.py b/programs/scripts/dune-create-changelog.py index bb797fab58..9744b0ebd1 100644 --- a/programs/scripts/dune-create-changelog.py +++ b/programs/scripts/dune-create-changelog.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/scripts/dune-create-params.py b/programs/scripts/dune-create-params.py index d5b4dc3409..5e4fcccdd0 100644 --- a/programs/scripts/dune-create-params.py +++ b/programs/scripts/dune-create-params.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/scripts/dune-create-task.py b/programs/scripts/dune-create-task.py index b2681792b5..15218e428e 100644 --- a/programs/scripts/dune-create-task.py +++ b/programs/scripts/dune-create-task.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -32,6 +32,13 @@ import os.path import argparse +# Task description. +DESCRIPTION = [ + '//! Insert short task description here.', + '//!', + '//! Insert explanation on task behaviour here.', + ] + # Task body. BODY = [ 'struct Task: public DUNE::Tasks::Task', @@ -84,6 +91,10 @@ def __init__(self, author, nss): self.add('#include ', '\n') for ns in nss: self.add('namespace ' + ns, '{') + if ns == nss[0]: + self.add(*DESCRIPTION) + line = ('//! @author ' + self._author) + self.add(line) self.add('using DUNE_NAMESPACES;', '\n') self.add(*BODY) for ns in self._nss: diff --git a/programs/scripts/dune-extract-elabels.py b/programs/scripts/dune-extract-elabels.py index aa845e7a72..d0fb7d6210 100644 --- a/programs/scripts/dune-extract-elabels.py +++ b/programs/scripts/dune-extract-elabels.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/scripts/dune-flightgear.sh b/programs/scripts/dune-flightgear.sh index 814e87a75f..0942af8898 100755 --- a/programs/scripts/dune-flightgear.sh +++ b/programs/scripts/dune-flightgear.sh @@ -1,6 +1,6 @@ #! /bin/sh ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/scripts/dune-maintainer-checks.py b/programs/scripts/dune-maintainer-checks.py index 91cc66030f..6e0247e55b 100644 --- a/programs/scripts/dune-maintainer-checks.py +++ b/programs/scripts/dune-maintainer-checks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/scripts/dune-make-docs.py b/programs/scripts/dune-make-docs.py index 254c1da62d..1b05757fbb 100644 --- a/programs/scripts/dune-make-docs.py +++ b/programs/scripts/dune-make-docs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # diff --git a/programs/scripts/dune-mobile-inet.sh b/programs/scripts/dune-mobile-inet.sh index 224fcc6372..49a09a4961 100644 --- a/programs/scripts/dune-mobile-inet.sh +++ b/programs/scripts/dune-mobile-inet.sh @@ -1,6 +1,6 @@ #! /bin/sh ############################################################################ -# Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia # +# Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia # # Laboratório de Sistemas e Tecnologia Subaquática (LSTS) # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # @@ -104,18 +104,16 @@ modem_probe() } # Update DynDNS IPv4 address. -# @param[in] ip IPv4 address. dyndns_update() { - echo $DYNDNS_USER $DYNDNS_PASS $DYNDNS_HOST - - if [ -z "$DYNDNS_USER" ] || [ -z "$DYNDNS_PASS" ] || [ -z "$DYNDNS_HOST" ]; then - return 0 + if [ -z "$DYNDNS_URL" ]; then + log err "DynDNS: Service URL not set." + exit 1 fi - - ip="$1" - url="http://$DYNDNS_USER:$DYNDNS_PASS@members.dyndns.org/nic/update?hostname=$DYNDNS_HOST&myip=$ip&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG" - wget "$url" -O - + + output=$(wget "$DYNDNS_URL" -O -) + log info "DynDNS: Updated successfully: $output" + exit 0 } ppp_start() @@ -239,6 +237,9 @@ stop() } case "$1" in + dyndns_update) + dyndns_update + ;; start) start ;; diff --git a/programs/scripts/dune-storage-ro-rw.sh b/programs/scripts/dune-storage-ro-rw.sh index 084a8bc153..9ae0a63557 100644 --- a/programs/scripts/dune-storage-ro-rw.sh +++ b/programs/scripts/dune-storage-ro-rw.sh @@ -1,6 +1,6 @@ #! /bin/sh ############################################################################ -# Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. # +# Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. # ############################################################################ # This file is part of DUNE: Unified Navigation Environment. # # # diff --git a/programs/surface_positions.cpp b/programs/surface_positions.cpp index e79c3ee4bb..831a3ea88f 100644 --- a/programs/surface_positions.cpp +++ b/programs/surface_positions.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/testPlan.cpp b/programs/testPlan.cpp index b92bd629e5..b23807c9b8 100644 --- a/programs/testPlan.cpp +++ b/programs/testPlan.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/test_rows.cpp b/programs/test_rows.cpp index b1bba617f5..fbe938c84e 100644 --- a/programs/test_rows.cpp +++ b/programs/test_rows.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/Test.hpp b/programs/tests/Test.hpp index c71d6df424..860180030f 100644 --- a/programs/tests/Test.hpp +++ b/programs/tests/Test.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_AtomicInteger.cpp b/programs/tests/test_AtomicInteger.cpp index 6b33d23f78..c7a7a3bbce 100644 --- a/programs/tests/test_AtomicInteger.cpp +++ b/programs/tests/test_AtomicInteger.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Base64.cpp b/programs/tests/test_Base64.cpp index 9b2873982a..a854794940 100644 --- a/programs/tests/test_Base64.cpp +++ b/programs/tests/test_Base64.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_BodyFixedFrame.cpp b/programs/tests/test_BodyFixedFrame.cpp index a31f070a00..0e1ee319c7 100644 --- a/programs/tests/test_BodyFixedFrame.cpp +++ b/programs/tests/test_BodyFixedFrame.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_CRC32.cpp b/programs/tests/test_CRC32.cpp new file mode 100644 index 0000000000..2456189971 --- /dev/null +++ b/programs/tests/test_CRC32.cpp @@ -0,0 +1,110 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Kristoffer Gryte * +//*************************************************************************** +// Test program for DUNE::Algorithms::CRC32 class. * +//*************************************************************************** +// ISO C++ headers +#include +#include + +// DUNE headers +#include +#include "Test.hpp" +/* // Gzip headers. */ +/* #include */ + +using namespace DUNE::Algorithms; + +int +main(int argc, char** argv) +{ + Test test("DUNE::Algorithms::CRC32"); + + // Tesed against http://www.sunshine2k.de/coding/javascript/crc/crc_js.html + const char* input_strings[] = + { + "a", + "abc", + "message digest", + "qwertyuiop", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + // default CRC32 settings + const uint32_t results[8] = + { + 0xE8B7BE43, + 0x352441C2, + 0x20159D7F, + 0x40C92C2D, + 0x4C2750BD, + 0x1FC2E6D2, + 0x7CA94A72 + }; + + const uint32_t results_no_reflect_data[8] = + { + 0xD6D9C998, + 0xCEDD3126, + 0xEAC093FD, + 0x3340D7ED, + 0x69C9FDEE, + 0x11842E05, + 0x699E1068 + }; + + uint32_t initial_crc = 0xFFFFFFFF; + uint8_t input[] = {0x01, 0x23, 0x45, 0x67};//, 0x89ABCDEF, 0x00000123}; + uint8_t input_stim[] = {0x93, 0x00, 0x26, 0x76, 0x00, 0x4c, 0x40, 0x00, 0x18, + 0xb3, 0x00, 0xff, 0xf2, 0x0c, 0xfd, 0x7e, 0x3b, 0x00, + 0x0c, 0xf8, 0x00, 0xff, 0xc0, 0x61, 0xeb, 0xe0, 0xdd, + 0x00, 0x32, 0x9d, 0x00, 0x39, 0x02, 0x04, 0x00, 0x00}; // should yield 0x97D4282A + + uint32_t stim_crc = CRC32::reflect(CRC32::compute((const uint8_t*)input_stim, sizeof(input_stim)/sizeof(uint8_t), true, ~initial_crc) ^ 0xFFFFFFFF, 32); + test.boolean("STIM CRC", stim_crc == 0x97D4282A); + /* uint32_t crc = crc32(0, (Bytef*)input, sizeof(input)/sizeof(uint8_t)); */ + /* test.boolean("1", crc == 0xFD2B0F7B); */ + + int n = sizeof(input_strings) / sizeof(const char*); + std::string testname; + for (int i = 0; i < n; ++i) + { + uint32_t crc = CRC32::compute((const uint8_t*)input_strings[i], std::strlen(input_strings[i]),false,0); + testname = "Standard, " + std::string(input_strings[i]); + test.boolean(testname.c_str(), crc == results[i]); + } + for (int i = 0; i < n; ++i) + { + uint32_t crc = CRC32::compute((const uint8_t*)input_strings[i], std::strlen(input_strings[i]),true,0); + testname = "No data reflection, " + std::string(input_strings[i]); + test.boolean(testname.c_str(), crc == results_no_reflect_data[i]); + } + return 0; +} diff --git a/programs/tests/test_CircularBuffer.cpp b/programs/tests/test_CircularBuffer.cpp index 21cd9e8548..01b3ab86cd 100644 --- a/programs/tests/test_CircularBuffer.cpp +++ b/programs/tests/test_CircularBuffer.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Database.cpp b/programs/tests/test_Database.cpp index 92fdc4086d..e6c4984f67 100644 --- a/programs/tests/test_Database.cpp +++ b/programs/tests/test_Database.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Delay.cpp b/programs/tests/test_Delay.cpp index a63499a1ad..d761317426 100644 --- a/programs/tests/test_Delay.cpp +++ b/programs/tests/test_Delay.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_IMC.cpp b/programs/tests/test_IMC.cpp index 889eb0cc65..1c762956f1 100644 --- a/programs/tests/test_IMC.cpp +++ b/programs/tests/test_IMC.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** // DUNE headers. @@ -45,14 +45,14 @@ main(void) { IMC::EntityState msg; - msg.setTimeStamp(0.274794768696); - msg.setSource(5432U); - msg.setSourceEntity(196U); - msg.setDestination(56274U); - msg.setDestinationEntity(94U); - msg.state = 176U; - msg.flags = 27U; - msg.description.assign("PRDOAFXEDKSHAJXPJQSGOPIJOHDXNTVNVGVIRPIKCRHVOEGMSQTPROONQGWNUQEWZRFXUKBPWKDLPTLFVBLVKAYIHMSQZVWCTQ"); + msg.setTimeStamp(0.5817737193741326); + msg.setSource(46916U); + msg.setSourceEntity(103U); + msg.setDestination(43300U); + msg.setDestinationEntity(211U); + msg.state = 61U; + msg.flags = 78U; + msg.description.assign("XABZDQJTNWEQOWUPMDVRKQOAHGEGZXUCIJHZUYHQAFQRLYCUFJIFXFRAZWVSAMXBYAFEIKMRJTFNCDVUTBHWPYSPQPBJMBDOYDJZPDJOXUBF"); try { @@ -71,14 +71,14 @@ main(void) { IMC::EntityState msg; - msg.setTimeStamp(0.263341271403); - msg.setSource(15507U); - msg.setSourceEntity(31U); - msg.setDestination(34966U); - msg.setDestinationEntity(204U); - msg.state = 80U; - msg.flags = 39U; - msg.description.assign("HSWXWKDLYIUKSKPNRQUVTOESUZKUVFXNQLD"); + msg.setTimeStamp(0.9859596086763418); + msg.setSource(49480U); + msg.setSourceEntity(109U); + msg.setDestination(61139U); + msg.setDestinationEntity(86U); + msg.state = 242U; + msg.flags = 181U; + msg.description.assign("NKCLTHEMLMQVJGRKZCYWQEIZUFXJKXKSNALEDEZBDFIFPELPPKCWVHDHTQYYFGNUYQEQMQELGJAGORRSOOUBNTSUDNZGZUTXIWWXUNOQUMVHFKNDPETDJAMSBSVIOYDSDHAHOMYMWMRLGHXPKSTVBPAOCZNPZPPAJEITYHCYQMCKCSLJSWGIGJJTBXIAZWAIXVUNWRDXKCQAHXVOGXFWCYV"); try { @@ -97,14 +97,14 @@ main(void) { IMC::EntityState msg; - msg.setTimeStamp(0.726164618364); - msg.setSource(46341U); - msg.setSourceEntity(78U); - msg.setDestination(110U); - msg.setDestinationEntity(223U); - msg.state = 220U; - msg.flags = 58U; - msg.description.assign("PUHWSGCXDGVFPMNR"); + msg.setTimeStamp(0.40310540914406123); + msg.setSource(30480U); + msg.setSourceEntity(37U); + msg.setDestination(25007U); + msg.setDestinationEntity(9U); + msg.state = 160U; + msg.flags = 242U; + msg.description.assign("VTPMSZXLTIBILOJULRKOFFKQNCBLEKGGFLFPXEFEMUKJNLSANPTCEJYJIBPTHIFTGRZOWBGYVHFGZOU"); try { @@ -123,11 +123,11 @@ main(void) { IMC::QueryEntityState msg; - msg.setTimeStamp(0.294216648307); - msg.setSource(33194U); - msg.setSourceEntity(159U); - msg.setDestination(15120U); - msg.setDestinationEntity(194U); + msg.setTimeStamp(0.9350393715079717); + msg.setSource(13738U); + msg.setSourceEntity(249U); + msg.setDestination(60171U); + msg.setDestinationEntity(195U); try { @@ -146,11 +146,11 @@ main(void) { IMC::QueryEntityState msg; - msg.setTimeStamp(0.188818215822); - msg.setSource(46098U); - msg.setSourceEntity(83U); - msg.setDestination(669U); - msg.setDestinationEntity(75U); + msg.setTimeStamp(0.6996190695769035); + msg.setSource(16626U); + msg.setSourceEntity(42U); + msg.setDestination(39063U); + msg.setDestinationEntity(42U); try { @@ -169,11 +169,11 @@ main(void) { IMC::QueryEntityState msg; - msg.setTimeStamp(0.762234158397); - msg.setSource(4775U); - msg.setSourceEntity(17U); - msg.setDestination(13439U); - msg.setDestinationEntity(145U); + msg.setTimeStamp(0.5096143852582605); + msg.setSource(7626U); + msg.setSourceEntity(194U); + msg.setDestination(46269U); + msg.setDestinationEntity(76U); try { @@ -192,16 +192,16 @@ main(void) { IMC::EntityInfo msg; - msg.setTimeStamp(0.872308257653); - msg.setSource(31992U); - msg.setSourceEntity(177U); - msg.setDestination(10988U); - msg.setDestinationEntity(63U); - msg.id = 249U; - msg.label.assign("XIJEIVKNSITEZPMVTDOPLABPZXPVRUEGMVGDGSVSSGNBHFIVRHAZQHDAUCWQLKWSBZBGTKZDYDWIRQNGVCHRCMHTEEKKSOPOLXVQMKZQJBNGUIEKMSITQJBRYAFFAJJRZQLCYOUFYQHJOXBXRYWILDSWYLPVSEMOWJUUENAAYCBKZMFGPJULOUTODCHPLMWVMLAAZIIOUFFHCKTZRYDWNCESGUFNJQYHFTXWXFG"); - msg.component.assign("BXOGKZQFEXRVJHJDHLPHXYTIIVVMMUXQZAJJPBTOLKEHNCWJEGCXPPWQBWFRHYBBSAUUAFCTHKYYGPTAGRMKFYFSQDDDSUEKJVWLTYGWRAQYNMBDNECVWXFIZRJFMVBUHKEWROOKGSNVUARRWKRDJLSALNHUGZVCIKHLTFNYNMNCOPLCJAKCBTZOIGBOPPO"); - msg.act_time = 63138U; - msg.deact_time = 55100U; + msg.setTimeStamp(0.3214153935669918); + msg.setSource(60683U); + msg.setSourceEntity(23U); + msg.setDestination(46155U); + msg.setDestinationEntity(225U); + msg.id = 84U; + msg.label.assign("OGVVIFOERGYFSYFXCJSZAMKVOMJWLUZQIVTABSODHTJVNJXJLXQBGDDYMNUAMEGOPSLNESHTFCJKTGXWEZBDABEZHANSCGZGNFVPWKONFNOTYBUBIORERMKJUBPZWEUHGUQHAIDDSRCPPUADSWCPEXNKRWLRHQRZAWUNXDUTHDQMNCAYFKZUIKYCEPQVYWTMLLYOILLHKKXIJRGTBXXHFZYCHORITDFQGPWMJVL"); + msg.component.assign("DWNAMJCAIAXZOJBCTCGVITFRJOJFCZLQEPDDALWOWRECPIZHFQSLRZYSUWFNKGVTYYLBZIMJECNSVOTTOLCKGOMNDBAEBYTQJWGXUWFDKODJSBGTEBUVXRIKYKSWPGDVZBEMDSRXJQQXPWGPMVLUPUKRCAMHRXCJSGWIXLASYNGXNYMIZWRKZHQBLDVYIHRYDUIHVFEHNLTKPNRHETEOFYQMKAPAONFZHPMBUFZJHSIOAEMGFQUNUQTQHKLVV"); + msg.act_time = 43255U; + msg.deact_time = 37111U; try { @@ -220,16 +220,16 @@ main(void) { IMC::EntityInfo msg; - msg.setTimeStamp(0.106278881852); - msg.setSource(7486U); - msg.setSourceEntity(76U); - msg.setDestination(8369U); - msg.setDestinationEntity(143U); - msg.id = 160U; - msg.label.assign("WRVBXGIFXOGPIPPFTJODYDHCURATEVOJEHMORCPKTPDYUVZNXCXLQKERJGUAMFBOKQSCRLISLUQLIIZXRNEBNZFJNHWSLXSCXGMSDSHVBLAUG"); - msg.component.assign("PWKUSVKANHSXBIGFGLEYDNCAGQOPEOSWMRLLJVWVZETPUHQUOVJEXDYGANRRIALZDQRSZZMBITFYFWVPUWTJCHIAMFYWMGOXOZPRKJYLKLUKKNCTCBDOUXBRIEFFV"); - msg.act_time = 15825U; - msg.deact_time = 21109U; + msg.setTimeStamp(0.48137303828042255); + msg.setSource(21693U); + msg.setSourceEntity(133U); + msg.setDestination(50415U); + msg.setDestinationEntity(36U); + msg.id = 205U; + msg.label.assign("UAZMLKEPFLOHDPTHOYTGGALPNBAKIYFRVOZJRUGJXXMDNWRJ"); + msg.component.assign("VMFPXSTMAKIAIXPWLMDGLVQRDNBOYCOFHYREAVPJFEMHBIJQRQLBQNNUOPRMUNZPSLDNGRQORHTFFIVJOZBVHMXGASGBCRTDJFJBJKOKNKGUSZACDWEFTDPLTPIZCHKWBGUQFYRKDJMUEZJEMERUGMKVNEXEVLRXYOSLSTBWBXWCDMYTZHHASFAXXTSJQNQLXGUWYPSPYJOZAUDCWNZIBVONQ"); + msg.act_time = 2200U; + msg.deact_time = 48612U; try { @@ -248,16 +248,16 @@ main(void) { IMC::EntityInfo msg; - msg.setTimeStamp(0.0632202186606); - msg.setSource(38245U); - msg.setSourceEntity(20U); - msg.setDestination(42838U); - msg.setDestinationEntity(239U); - msg.id = 210U; - msg.label.assign("ZERTQVBHICDVIHYVPGSOWBZAWUTPSVGPQWGETJAZLPITMVXBWOWOFMYGITJKRNOXCSSMYLQLSUEKJJCZKMIZFLQSZKWJHODAXYHRBJUPFPEKIHPHTCCWFRZXEXHMETICANT"); - msg.component.assign("QQWSFKYMFODZBQYQBKIMXFSOOZBBWWMMHEWDYGPHYHEUDPURBWZSGVCUTHYMEIGNKXLGOJTVOTQJWEWFSXZAUNWYVTEYBVNMKLINIOSZKQCBIPRCLRPHJTZGXGNHEIDCJDAKVAMYVTFELVIHCOPBDARURAHJRUGZLQQJALPZSZSGOLKXDRREKBJPLTCMWTXEIUFEYLNPIFAQMODNUADFSRZASVTCACMUWP"); - msg.act_time = 48103U; - msg.deact_time = 10541U; + msg.setTimeStamp(0.894372646156149); + msg.setSource(46021U); + msg.setSourceEntity(96U); + msg.setDestination(64067U); + msg.setDestinationEntity(206U); + msg.id = 149U; + msg.label.assign("EAUOJYBJHBNUBIIXHLTESAUJUAMYVJFZRSXINHRUSNYEXGAPA"); + msg.component.assign("QUDHUBVTYCMVTEROBLGXNPXWRDLGQBNKIXKVJCUPXQGLNLUSYSZPWKGTZSNXHBZIJTAGCUVLXFIKZTDQRMWZMSYNWNGTGWEZJNIBCBRKDDHACFHE"); + msg.act_time = 58808U; + msg.deact_time = 12721U; try { @@ -276,12 +276,12 @@ main(void) { IMC::QueryEntityInfo msg; - msg.setTimeStamp(0.927586443567); - msg.setSource(17076U); - msg.setSourceEntity(72U); - msg.setDestination(24212U); - msg.setDestinationEntity(60U); - msg.id = 156U; + msg.setTimeStamp(0.7368659216190047); + msg.setSource(23572U); + msg.setSourceEntity(66U); + msg.setDestination(28038U); + msg.setDestinationEntity(81U); + msg.id = 211U; try { @@ -300,12 +300,12 @@ main(void) { IMC::QueryEntityInfo msg; - msg.setTimeStamp(0.581229648784); - msg.setSource(36298U); - msg.setSourceEntity(11U); - msg.setDestination(49259U); - msg.setDestinationEntity(70U); - msg.id = 3U; + msg.setTimeStamp(0.790870075390898); + msg.setSource(37110U); + msg.setSourceEntity(170U); + msg.setDestination(52136U); + msg.setDestinationEntity(146U); + msg.id = 4U; try { @@ -324,12 +324,12 @@ main(void) { IMC::QueryEntityInfo msg; - msg.setTimeStamp(0.562193803724); - msg.setSource(32717U); - msg.setSourceEntity(11U); - msg.setDestination(53854U); - msg.setDestinationEntity(66U); - msg.id = 37U; + msg.setTimeStamp(0.27185583775788413); + msg.setSource(29012U); + msg.setSourceEntity(76U); + msg.setDestination(43422U); + msg.setDestinationEntity(193U); + msg.id = 211U; try { @@ -348,13 +348,13 @@ main(void) { IMC::EntityList msg; - msg.setTimeStamp(0.794773027998); - msg.setSource(3060U); - msg.setSourceEntity(94U); - msg.setDestination(40220U); - msg.setDestinationEntity(32U); - msg.op = 70U; - msg.list.assign("XWBKWTCEUMOAGFORPFXVLVICLOXGPYHSNLDXMGYJGKRQSWWABKXEKWOKZDDVTKFZTIQFJFPECCSHVSNCMTTPAWDJZQUYG"); + msg.setTimeStamp(0.66215930869617); + msg.setSource(11985U); + msg.setSourceEntity(72U); + msg.setDestination(2994U); + msg.setDestinationEntity(201U); + msg.op = 104U; + msg.list.assign("VBSQNKSFOBRVTXDVADPMOUSXYQCYJPXBEZWSWQWKAKJPFKDFDQEIRTRMLZFAHDHJCZLJVZSNWSDNIKDTCHRCDYL"); try { @@ -373,13 +373,13 @@ main(void) { IMC::EntityList msg; - msg.setTimeStamp(0.123032496615); - msg.setSource(10206U); - msg.setSourceEntity(214U); - msg.setDestination(41685U); - msg.setDestinationEntity(41U); - msg.op = 162U; - msg.list.assign("JWEBHHTNPOWCZHGSDHLRUTRBSVMOQOFBTFRNQIUFSKYCNMLWRLKAYAKKHAPVSVJQQOHJWXMMDXYYGNEQAWXZUQRLRUEG"); + msg.setTimeStamp(0.00699200052090776); + msg.setSource(47165U); + msg.setSourceEntity(138U); + msg.setDestination(49726U); + msg.setDestinationEntity(170U); + msg.op = 185U; + msg.list.assign("JUZKHJHINAUHEFAMLRRWVXJUILYPZVUPDCOFRKCETRVUGVQKDVPVPGFVPKHDBTZLVETOUISGXDGGTSWMISOTQNWBHMFTQXJGKLAHQDMKCYUEIWOQBNYSCLIZOURENCHGPLYQWEBNGERFEAJUYZSASHABREKIHYKQLJCSLXBWJTDTXNNGSZPKSAYVDDFHPMLBNCBCTYWWOWMOYMJBTADOEJSRNXMF"); try { @@ -398,13 +398,13 @@ main(void) { IMC::EntityList msg; - msg.setTimeStamp(0.718576578818); - msg.setSource(10912U); - msg.setSourceEntity(5U); - msg.setDestination(14240U); - msg.setDestinationEntity(82U); - msg.op = 144U; - msg.list.assign("UDVYMDOBGENMOZMAPDALDOBJIBMQBCOJFALTUSSCAUGOKICTBGUTAXEHJYISQTNMTONWHYGXLXOUKIWVSGKYHEZDELGQFTIJZCBQSCTRWNRVSXVHHYHNCXOKDSFQLZDLNJZHARNZMYPNQOTCKHUYPSMZZYWGJDWOFVIIXRILVEXXGPIARVEJPRPQCFXN"); + msg.setTimeStamp(0.19805216761322908); + msg.setSource(58121U); + msg.setSourceEntity(59U); + msg.setDestination(9671U); + msg.setDestinationEntity(25U); + msg.op = 154U; + msg.list.assign("SYALVCWRABMGRPHHNIDVHWPLFBAGKERBTPLXMJIFROWECYDWTJIXOSVQEQNWOIIDVPUQWGZYUBSWLBMNMTDHBQMIKHTICAZKCYREHYVHDLCUNQWPFYXNLQBSDRYNQKVNGUWAIPDLCVE"); try { @@ -423,12 +423,12 @@ main(void) { IMC::CpuUsage msg; - msg.setTimeStamp(0.831794313468); - msg.setSource(10600U); - msg.setSourceEntity(25U); - msg.setDestination(16138U); - msg.setDestinationEntity(5U); - msg.value = 55U; + msg.setTimeStamp(0.6272795091725364); + msg.setSource(3212U); + msg.setSourceEntity(27U); + msg.setDestination(34922U); + msg.setDestinationEntity(187U); + msg.value = 47U; try { @@ -447,12 +447,12 @@ main(void) { IMC::CpuUsage msg; - msg.setTimeStamp(0.30353492613); - msg.setSource(20012U); - msg.setSourceEntity(71U); - msg.setDestination(54820U); - msg.setDestinationEntity(78U); - msg.value = 87U; + msg.setTimeStamp(0.6485481957643597); + msg.setSource(32879U); + msg.setSourceEntity(85U); + msg.setDestination(38814U); + msg.setDestinationEntity(239U); + msg.value = 162U; try { @@ -471,12 +471,12 @@ main(void) { IMC::CpuUsage msg; - msg.setTimeStamp(0.998287850239); - msg.setSource(54115U); - msg.setSourceEntity(206U); - msg.setDestination(16645U); - msg.setDestinationEntity(61U); - msg.value = 25U; + msg.setTimeStamp(0.38745040481756843); + msg.setSource(59613U); + msg.setSourceEntity(51U); + msg.setDestination(65108U); + msg.setDestinationEntity(95U); + msg.value = 120U; try { @@ -495,13 +495,13 @@ main(void) { IMC::TransportBindings msg; - msg.setTimeStamp(0.526417827011); - msg.setSource(33362U); - msg.setSourceEntity(38U); - msg.setDestination(22914U); - msg.setDestinationEntity(213U); - msg.consumer.assign("VLLACJGUSVYUREPIULWEVMUUUNECTOTGHAPJMZOZDLCGYGIYYSL"); - msg.message_id = 2896U; + msg.setTimeStamp(0.08289197133651183); + msg.setSource(43574U); + msg.setSourceEntity(152U); + msg.setDestination(13214U); + msg.setDestinationEntity(108U); + msg.consumer.assign("OPOJBVYPRKQVRQQFYIDYGAWASPGTCASSTTEPFCTBNVQMVBLJUEBGVNGTNFYAJDYLSMJTEUORTGIGZCXMKVEIPISWLKBQUROBKNMVOXLAJWCMWDMJBRLACDHBUQQXKYEFLGUQCFSAERNTAUX"); + msg.message_id = 59362U; try { @@ -520,13 +520,13 @@ main(void) { IMC::TransportBindings msg; - msg.setTimeStamp(0.525312316276); - msg.setSource(5729U); - msg.setSourceEntity(80U); - msg.setDestination(22356U); - msg.setDestinationEntity(18U); - msg.consumer.assign("ZBSFDRXFRWAGTTBAGKADADLQKRZSTYFQEYPXOHUTKUSCEXXNEJMPNOBZNIQFRLCQRKJNEJMKSGIHPDVUPTJQYYUFTXDIGIRDEHFWNDNKCFWKNLVHSUVVOOOZKUAPNWMRTLSWSLMHCRVXFYGOLNRLZOEPLCQASXWFSGECMMYYIJKHLCMBTORQBIKBZJGZAICUIYLM"); - msg.message_id = 3811U; + msg.setTimeStamp(0.5824598390658435); + msg.setSource(45606U); + msg.setSourceEntity(95U); + msg.setDestination(33672U); + msg.setDestinationEntity(97U); + msg.consumer.assign("SQHKOYPCPFJEWDHTRAIIFPCJJC"); + msg.message_id = 43957U; try { @@ -545,13 +545,13 @@ main(void) { IMC::TransportBindings msg; - msg.setTimeStamp(0.0201411946146); - msg.setSource(1053U); - msg.setSourceEntity(18U); - msg.setDestination(17253U); - msg.setDestinationEntity(163U); - msg.consumer.assign("LWWYYPVGEXNPVLCTRYJAQYNRSZXGZFBKHNATSMKQUZJLMKYCBHCOPWHUUTVHXOQGREESTFHWBMBDLWGQBDSNFOVJNCYZAUVWFLLGYNILJM"); - msg.message_id = 11867U; + msg.setTimeStamp(0.1348166299418465); + msg.setSource(33533U); + msg.setSourceEntity(138U); + msg.setDestination(43570U); + msg.setDestinationEntity(115U); + msg.consumer.assign("HSJSHOQDGBYDECDOTXTPBHLRSEEAFBGDYYDUYKDSLLAGMIYFSTXWXCLRDJQFHVLUEACYBVBKVVOGJQXOXVLJSNWAFPZZNZLIRHCQUIECSLGFLVYWYYFK"); + msg.message_id = 51954U; try { @@ -570,11 +570,12 @@ main(void) { IMC::RestartSystem msg; - msg.setTimeStamp(0.92596755325); - msg.setSource(6780U); - msg.setSourceEntity(58U); - msg.setDestination(29663U); - msg.setDestinationEntity(83U); + msg.setTimeStamp(0.3373981934033079); + msg.setSource(43151U); + msg.setSourceEntity(217U); + msg.setDestination(48455U); + msg.setDestinationEntity(94U); + msg.type = 22U; try { @@ -593,11 +594,12 @@ main(void) { IMC::RestartSystem msg; - msg.setTimeStamp(0.446489821105); - msg.setSource(49734U); - msg.setSourceEntity(35U); - msg.setDestination(40301U); - msg.setDestinationEntity(88U); + msg.setTimeStamp(0.94627254035139); + msg.setSource(29651U); + msg.setSourceEntity(130U); + msg.setDestination(63459U); + msg.setDestinationEntity(109U); + msg.type = 130U; try { @@ -616,11 +618,12 @@ main(void) { IMC::RestartSystem msg; - msg.setTimeStamp(0.199816800554); - msg.setSource(5855U); - msg.setSourceEntity(236U); - msg.setDestination(57997U); - msg.setDestinationEntity(223U); + msg.setTimeStamp(0.5769239414099852); + msg.setSource(26150U); + msg.setSourceEntity(99U); + msg.setDestination(50218U); + msg.setDestinationEntity(234U); + msg.type = 62U; try { @@ -639,12 +642,12 @@ main(void) { IMC::DevCalibrationControl msg; - msg.setTimeStamp(0.521771041924); - msg.setSource(39509U); - msg.setSourceEntity(83U); - msg.setDestination(4640U); - msg.setDestinationEntity(1U); - msg.op = 203U; + msg.setTimeStamp(0.7421824721447448); + msg.setSource(2338U); + msg.setSourceEntity(41U); + msg.setDestination(34469U); + msg.setDestinationEntity(34U); + msg.op = 215U; try { @@ -663,12 +666,12 @@ main(void) { IMC::DevCalibrationControl msg; - msg.setTimeStamp(0.932823565235); - msg.setSource(48718U); - msg.setSourceEntity(47U); - msg.setDestination(51308U); - msg.setDestinationEntity(43U); - msg.op = 88U; + msg.setTimeStamp(0.4713219142684182); + msg.setSource(42045U); + msg.setSourceEntity(254U); + msg.setDestination(12690U); + msg.setDestinationEntity(86U); + msg.op = 228U; try { @@ -687,12 +690,12 @@ main(void) { IMC::DevCalibrationControl msg; - msg.setTimeStamp(0.333518186963); - msg.setSource(60873U); - msg.setSourceEntity(189U); - msg.setDestination(63455U); - msg.setDestinationEntity(103U); - msg.op = 99U; + msg.setTimeStamp(0.32443906569286785); + msg.setSource(60319U); + msg.setSourceEntity(114U); + msg.setDestination(60721U); + msg.setDestinationEntity(157U); + msg.op = 22U; try { @@ -711,15 +714,15 @@ main(void) { IMC::DevCalibrationState msg; - msg.setTimeStamp(0.181999275785); - msg.setSource(21389U); - msg.setSourceEntity(227U); - msg.setDestination(7497U); - msg.setDestinationEntity(160U); - msg.total_steps = 136U; - msg.step_number = 43U; - msg.step.assign("LHPLPNCXUWXCZNWICYBJQKQJVYMVPSRJHOZQAZRQUIHDICQIZDEBFCACWXSUIYTWALILXHPRTBYSKTMBGHSOMQEDUCWDLBKYVOGYSFNXEXCEABKTFNHHB"); - msg.flags = 173U; + msg.setTimeStamp(0.06466676243651104); + msg.setSource(2015U); + msg.setSourceEntity(95U); + msg.setDestination(54570U); + msg.setDestinationEntity(176U); + msg.total_steps = 166U; + msg.step_number = 165U; + msg.step.assign("VNUTMBMAHYGJHHOBYNBQJGMDLTCFKBOJYQOEQIDYFGLTPFRLVWTSZYPLGSBFGAKBHRMENOIPQTOWUGIZPFIUWESYSDRPOIOCMTDPJDRQVRUYNQWGGKADQJKLUOPTXRKUWFDLSBCIZUGHWQIAUZWNZVLXDEFHDFWNNTNHCRKALEMRVI"); + msg.flags = 216U; try { @@ -738,15 +741,15 @@ main(void) { IMC::DevCalibrationState msg; - msg.setTimeStamp(0.243344668896); - msg.setSource(8280U); - msg.setSourceEntity(172U); - msg.setDestination(3923U); - msg.setDestinationEntity(91U); - msg.total_steps = 249U; - msg.step_number = 156U; - msg.step.assign("PFUXNRLGBIHYNYOGYNQAKLHTQBRBMZLWXHWJIORIZZDFNTBVNDDQEKHZEXGACWWWMNOKPJTFYJIEESSGWDQAOPQEUZDUIBBSPJYMNKQRGVTGEHWHARJKTPBDAEVBMP"); - msg.flags = 69U; + msg.setTimeStamp(0.7660524085594497); + msg.setSource(47642U); + msg.setSourceEntity(29U); + msg.setDestination(25355U); + msg.setDestinationEntity(82U); + msg.total_steps = 108U; + msg.step_number = 237U; + msg.step.assign("FLWLFVZYONKDDEPAQNNDWWXGCQANTERUAHVNRTPESSPUAGYEHDYDXAWFNURDLPKQYSJBIRGBVKEHQWCTVVBPMXTTMQLYZAZXEFKMIFMHKRFJGPEHGTSDNOYGYZEVBGZREXOLLFFTKILPHOCCPLAXHOZUOXUAPMWOILJZGJKVWRGDFEWSBCDCISBZAUZVXTDLRRQIUNCSSAMMKOJJPQHBIWIOVVKIOXUJBCMHUGCJZIXJNMQYQFYSTSJBTRHK"); + msg.flags = 25U; try { @@ -765,15 +768,15 @@ main(void) { IMC::DevCalibrationState msg; - msg.setTimeStamp(0.479980496554); - msg.setSource(3075U); - msg.setSourceEntity(173U); - msg.setDestination(9867U); - msg.setDestinationEntity(136U); - msg.total_steps = 173U; - msg.step_number = 102U; - msg.step.assign("OOIKHNDTFBJPHDQHSNNNMJJTRCQXQHRKWJAUFHVZOOPFBPNCZBLLHIHXMSZGBEAVKNIRWALDGWCJYYZAIATQCJBIZVPMRTEXFJFXXKDXWGDDSEFFGTBLZJACCPSKUYHBDVGCCWTYIPWQMHFNOGLSDSIWRACEKOYIUBYDSQDU"); - msg.flags = 95U; + msg.setTimeStamp(0.7386595115768967); + msg.setSource(55439U); + msg.setSourceEntity(95U); + msg.setDestination(44755U); + msg.setDestinationEntity(190U); + msg.total_steps = 32U; + msg.step_number = 218U; + msg.step.assign("BTLHGYCICFVKPEDPSHQFWVCGYDHIAKHMVJABPZEULFSWWFFIODORRGXLFXRMQXTGZIQIXNTXJCQGRHQDNMEJHYOWHWEBGUVCKBNBPKEMAAFB"); + msg.flags = 52U; try { @@ -792,13 +795,13 @@ main(void) { IMC::EntityActivationState msg; - msg.setTimeStamp(0.983383309553); - msg.setSource(32964U); - msg.setSourceEntity(37U); - msg.setDestination(36286U); - msg.setDestinationEntity(73U); - msg.state = 197U; - msg.error.assign("FEDAREPGXVZHFMDIBCSRLRLLDTYHTSQAUDCNNKRQEAVMCCHBTOJTVVATQ"); + msg.setTimeStamp(0.09850613058829683); + msg.setSource(6355U); + msg.setSourceEntity(68U); + msg.setDestination(34726U); + msg.setDestinationEntity(208U); + msg.state = 53U; + msg.error.assign("NZTMFJBDPGMNLZCEZVNLJZVAPQWGBIMYYQWIPXAGWLHYWGXJMLHYFXLRUYJDSSCKHVGMCDAELFUOTU"); try { @@ -817,13 +820,13 @@ main(void) { IMC::EntityActivationState msg; - msg.setTimeStamp(0.89227088357); - msg.setSource(64240U); - msg.setSourceEntity(14U); - msg.setDestination(24617U); - msg.setDestinationEntity(177U); - msg.state = 32U; - msg.error.assign("EMDZBKJVHFAPAXGUVQUBCMPGHDGMCDGHQOZXDDSONSKOUUWINSWUHWDEFBRICXGBPDQHNZJLMCXFDIVLULRJRYVOVMXTCRBDSTYTCJMRWNBHZPTGVJLUVLYQAIEGXIOLSYPLXYLWOJIYUWBABCXNZWOKWSFGSFAVYRANPVGKZZHFWEYHGLQFUTKKHJXQMTNRSBEEEFRLJTSASZJQKYEMIFQJNZIETAROEIKYPBMHXFWTACPCDINV"); + msg.setTimeStamp(0.06924200223334243); + msg.setSource(42403U); + msg.setSourceEntity(17U); + msg.setDestination(12574U); + msg.setDestinationEntity(1U); + msg.state = 29U; + msg.error.assign("APEBPHYKYQRTLHECOOUINKZRDERIDRUJBSNVHAYIEIUAAJHNZFOEEBXEJZEKMUACYGTQIIXHAXOSSJMTMGHSXCJOKYT"); try { @@ -842,13 +845,13 @@ main(void) { IMC::EntityActivationState msg; - msg.setTimeStamp(0.359827302616); - msg.setSource(65102U); - msg.setSourceEntity(226U); - msg.setDestination(29705U); - msg.setDestinationEntity(171U); - msg.state = 47U; - msg.error.assign("AIZXZRJXSEWNIIPCHJRWOUWTSHEMABUDCNCAZZMVUHARZOVPSXBLFEPPKKWRYOVXXXPWKYYDRIFXBKMYIJXVRDLSHKSLHSVSBHCGH"); + msg.setTimeStamp(0.138407929503244); + msg.setSource(54534U); + msg.setSourceEntity(74U); + msg.setDestination(22118U); + msg.setDestinationEntity(37U); + msg.state = 142U; + msg.error.assign("YMWSPXATRQIMMVYSOWFZTYJBGEPGEOCKZUJKGDBVBVBTLPKGZYXNDANHLEPJZFHBMGHCIEYLNWYSAZQEMKCDWGYDOTXNOQJKHBTEPTOIJLMQSOJKUAQFGSVBMSDLUIREBXHOIBLJDUHQXVRNJVTQIWCAOOWFSCIHTXNIXYQUTASQZSRUPDQXKAESWDFRULIZMVJXCFNWWCGINMHPNACGUZAOEGRUPHPRLHDFRCBKKYZVRPEZFTAXDFVJWVKC"); try { @@ -867,11 +870,11 @@ main(void) { IMC::QueryEntityActivationState msg; - msg.setTimeStamp(0.54508342419); - msg.setSource(47335U); - msg.setSourceEntity(1U); - msg.setDestination(29584U); - msg.setDestinationEntity(167U); + msg.setTimeStamp(0.6986421848338126); + msg.setSource(57936U); + msg.setSourceEntity(133U); + msg.setDestination(1475U); + msg.setDestinationEntity(128U); try { @@ -890,11 +893,11 @@ main(void) { IMC::QueryEntityActivationState msg; - msg.setTimeStamp(0.0971944890443); - msg.setSource(57989U); - msg.setSourceEntity(166U); - msg.setDestination(19698U); - msg.setDestinationEntity(213U); + msg.setTimeStamp(0.5282218591267065); + msg.setSource(31810U); + msg.setSourceEntity(231U); + msg.setDestination(57994U); + msg.setDestinationEntity(228U); try { @@ -913,11 +916,11 @@ main(void) { IMC::QueryEntityActivationState msg; - msg.setTimeStamp(0.695757153257); - msg.setSource(16186U); - msg.setSourceEntity(103U); - msg.setDestination(9392U); - msg.setDestinationEntity(122U); + msg.setTimeStamp(0.6722485222763531); + msg.setSource(3920U); + msg.setSourceEntity(245U); + msg.setDestination(8020U); + msg.setDestinationEntity(182U); try { @@ -936,29 +939,29 @@ main(void) { IMC::VehicleOperationalLimits msg; - msg.setTimeStamp(0.947199648981); - msg.setSource(16254U); - msg.setSourceEntity(247U); - msg.setDestination(27990U); - msg.setDestinationEntity(89U); - msg.op = 250U; - msg.speed_min = 0.153433915151; - msg.speed_max = 0.205791531098; - msg.long_accel = 0.833692433144; - msg.alt_max_msl = 0.074610714086; - msg.dive_fraction_max = 0.371933489656; - msg.climb_fraction_max = 0.499416187105; - msg.bank_max = 0.569198803072; - msg.p_max = 0.999675651537; - msg.pitch_min = 0.935161501181; - msg.pitch_max = 0.698274648039; - msg.q_max = 0.35394704284; - msg.g_min = 0.712559761966; - msg.g_max = 0.0741664633988; - msg.g_lat_max = 0.810258706426; - msg.rpm_min = 0.597625233525; - msg.rpm_max = 0.315362373833; - msg.rpm_rate_max = 0.503361382279; + msg.setTimeStamp(0.8435944293689923); + msg.setSource(31571U); + msg.setSourceEntity(23U); + msg.setDestination(58308U); + msg.setDestinationEntity(250U); + msg.op = 14U; + msg.speed_min = 0.9632046917967989; + msg.speed_max = 0.15863246106196693; + msg.long_accel = 0.23551681468721297; + msg.alt_max_msl = 0.2572357874456055; + msg.dive_fraction_max = 0.2339908470210852; + msg.climb_fraction_max = 0.27404047092451544; + msg.bank_max = 0.40082550233582503; + msg.p_max = 0.7839050425255737; + msg.pitch_min = 0.8011341131755723; + msg.pitch_max = 0.03977231667921821; + msg.q_max = 0.4226607038731601; + msg.g_min = 0.5533795263919449; + msg.g_max = 0.8375447591289468; + msg.g_lat_max = 0.35408138969338365; + msg.rpm_min = 0.9626826492446106; + msg.rpm_max = 0.4760943843856539; + msg.rpm_rate_max = 0.5159681768601801; try { @@ -977,29 +980,29 @@ main(void) { IMC::VehicleOperationalLimits msg; - msg.setTimeStamp(0.631492522543); - msg.setSource(43620U); - msg.setSourceEntity(6U); - msg.setDestination(16535U); - msg.setDestinationEntity(234U); - msg.op = 74U; - msg.speed_min = 0.791308726345; - msg.speed_max = 0.693949628214; - msg.long_accel = 0.602526007754; - msg.alt_max_msl = 0.833179972974; - msg.dive_fraction_max = 0.617828018055; - msg.climb_fraction_max = 0.440988873016; - msg.bank_max = 0.390910701804; - msg.p_max = 0.0370217218249; - msg.pitch_min = 0.074949247761; - msg.pitch_max = 0.452126484927; - msg.q_max = 0.820360905183; - msg.g_min = 0.640110509861; - msg.g_max = 0.854196147349; - msg.g_lat_max = 0.140422862514; - msg.rpm_min = 0.252237942505; - msg.rpm_max = 0.254919374268; - msg.rpm_rate_max = 0.632278219477; + msg.setTimeStamp(0.625502151548203); + msg.setSource(54282U); + msg.setSourceEntity(49U); + msg.setDestination(1401U); + msg.setDestinationEntity(37U); + msg.op = 49U; + msg.speed_min = 0.8735185354655481; + msg.speed_max = 0.21396599234898306; + msg.long_accel = 0.5855371814891346; + msg.alt_max_msl = 0.73022528654633; + msg.dive_fraction_max = 0.8203335377994908; + msg.climb_fraction_max = 0.9217379202982594; + msg.bank_max = 0.5473038941074057; + msg.p_max = 0.7249360531150633; + msg.pitch_min = 0.19566765901784644; + msg.pitch_max = 0.3112461492687425; + msg.q_max = 0.09127028518202052; + msg.g_min = 0.6169865171313633; + msg.g_max = 0.8687826571791711; + msg.g_lat_max = 0.8939802254490511; + msg.rpm_min = 0.013922766196359015; + msg.rpm_max = 0.7787227983309275; + msg.rpm_rate_max = 0.7873607881297945; try { @@ -1018,29 +1021,29 @@ main(void) { IMC::VehicleOperationalLimits msg; - msg.setTimeStamp(0.90971829966); - msg.setSource(33051U); - msg.setSourceEntity(105U); - msg.setDestination(42035U); - msg.setDestinationEntity(29U); - msg.op = 229U; - msg.speed_min = 0.117699596565; - msg.speed_max = 0.846551149516; - msg.long_accel = 0.41429504903; - msg.alt_max_msl = 0.765714011536; - msg.dive_fraction_max = 0.165032707958; - msg.climb_fraction_max = 0.00897511372827; - msg.bank_max = 0.271319695729; - msg.p_max = 0.463750733715; - msg.pitch_min = 0.945895356461; - msg.pitch_max = 0.751830661156; - msg.q_max = 0.850725198117; - msg.g_min = 0.642846646257; - msg.g_max = 0.0762147009653; - msg.g_lat_max = 0.533874811944; - msg.rpm_min = 0.878518823021; - msg.rpm_max = 0.603329068857; - msg.rpm_rate_max = 0.391956839085; + msg.setTimeStamp(0.8318887822534093); + msg.setSource(33229U); + msg.setSourceEntity(38U); + msg.setDestination(30396U); + msg.setDestinationEntity(204U); + msg.op = 83U; + msg.speed_min = 0.5538121138652721; + msg.speed_max = 0.0027572854438003835; + msg.long_accel = 0.3164456821333693; + msg.alt_max_msl = 0.6389527812317277; + msg.dive_fraction_max = 0.99188678835884; + msg.climb_fraction_max = 0.0035214438875014187; + msg.bank_max = 0.9161301067689046; + msg.p_max = 0.8724455594755403; + msg.pitch_min = 0.5409119087272992; + msg.pitch_max = 0.621465289769884; + msg.q_max = 0.782199289515998; + msg.g_min = 0.17220586074420952; + msg.g_max = 0.6944538757409103; + msg.g_lat_max = 0.4851609437815235; + msg.rpm_min = 0.6548001162020247; + msg.rpm_max = 0.5705796817273833; + msg.rpm_rate_max = 0.11113940488144247; try { @@ -1059,20 +1062,16 @@ main(void) { IMC::MsgList msg; - msg.setTimeStamp(0.619293047012); - msg.setSource(47210U); - msg.setSourceEntity(191U); - msg.setDestination(2442U); - msg.setDestinationEntity(194U); - IMC::FollowPath tmp_msg_0; - tmp_msg_0.timeout = 58343U; - tmp_msg_0.lat = 0.174303455936; - tmp_msg_0.lon = 0.591608602236; - tmp_msg_0.z = 0.596206419125; - tmp_msg_0.z_units = 3U; - tmp_msg_0.speed = 0.248309296077; - tmp_msg_0.speed_units = 226U; - tmp_msg_0.custom.assign("HJQHTNTOIIDKJMKLRXCGAXXBTUVDRAPNYXSMSZWNYCLMBQEPBMFSBTUMOQHYKNJWZFRIMVZQEYVWJROFGMAYBKYWLFRTSQZPDORAQGQIDLGBLYHVQLHLLUHPCPEJJTZOAFYNREISVCZWVYEWBAZMEKSSKDGFPJUZNNLTFVQWSXNCEAODGHGWDVCROIPCTKUGCARITTIJWXSOVKMWHUZBXPZKBDINAUFQDHELGPCOPAXXCU"); + msg.setTimeStamp(0.09831617952846783); + msg.setSource(9388U); + msg.setSourceEntity(111U); + msg.setDestination(29643U); + msg.setDestinationEntity(40U); + IMC::UsblPosition tmp_msg_0; + tmp_msg_0.target = 47807U; + tmp_msg_0.x = 0.22645920445122825; + tmp_msg_0.y = 0.48849423933943936; + tmp_msg_0.z = 0.05252384869285609; msg.msgs.push_back(tmp_msg_0); try @@ -1092,11 +1091,11 @@ main(void) { IMC::MsgList msg; - msg.setTimeStamp(0.930202512376); - msg.setSource(64300U); - msg.setSourceEntity(248U); - msg.setDestination(55375U); - msg.setDestinationEntity(194U); + msg.setTimeStamp(0.026133720052678333); + msg.setSource(34336U); + msg.setSourceEntity(64U); + msg.setDestination(56662U); + msg.setDestinationEntity(166U); try { @@ -1115,11 +1114,11 @@ main(void) { IMC::MsgList msg; - msg.setTimeStamp(0.722506525755); - msg.setSource(62909U); - msg.setSourceEntity(230U); - msg.setDestination(40513U); - msg.setDestinationEntity(110U); + msg.setTimeStamp(0.007304676837776913); + msg.setSource(24483U); + msg.setSourceEntity(52U); + msg.setDestination(1467U); + msg.setDestinationEntity(83U); try { @@ -1138,29 +1137,29 @@ main(void) { IMC::SimulatedState msg; - msg.setTimeStamp(0.814627740955); - msg.setSource(17974U); - msg.setSourceEntity(113U); - msg.setDestination(56670U); - msg.setDestinationEntity(170U); - msg.lat = 0.175133224106; - msg.lon = 0.729303410758; - msg.height = 0.464012189109; - msg.x = 0.26293000223; - msg.y = 0.702340404532; - msg.z = 0.209410818304; - msg.phi = 0.445823037891; - msg.theta = 0.0832185583304; - msg.psi = 0.636380688341; - msg.u = 0.913598550551; - msg.v = 0.612122149402; - msg.w = 0.0176204706499; - msg.p = 0.00554832629142; - msg.q = 0.357574923863; - msg.r = 0.779815404613; - msg.svx = 0.827908334571; - msg.svy = 0.139475771015; - msg.svz = 0.582030808248; + msg.setTimeStamp(0.4175666694359872); + msg.setSource(38422U); + msg.setSourceEntity(225U); + msg.setDestination(41112U); + msg.setDestinationEntity(203U); + msg.lat = 0.016138182798323686; + msg.lon = 0.5521252182129349; + msg.height = 0.7608981521732066; + msg.x = 0.4018673032942274; + msg.y = 0.06202450995732289; + msg.z = 0.9354458761739118; + msg.phi = 0.8661333044513816; + msg.theta = 0.8027373891549058; + msg.psi = 0.720326394090798; + msg.u = 0.6889706073388485; + msg.v = 0.5208529426666679; + msg.w = 0.062227905791393145; + msg.p = 0.4063031039540932; + msg.q = 0.3763866688410089; + msg.r = 0.660574637314458; + msg.svx = 0.9334546552607185; + msg.svy = 0.516061366579993; + msg.svz = 0.09307330249237677; try { @@ -1179,29 +1178,29 @@ main(void) { IMC::SimulatedState msg; - msg.setTimeStamp(0.338100239522); - msg.setSource(12999U); - msg.setSourceEntity(149U); - msg.setDestination(35180U); - msg.setDestinationEntity(114U); - msg.lat = 0.800470503825; - msg.lon = 0.0834828005092; - msg.height = 0.247353439494; - msg.x = 0.140758337252; - msg.y = 0.404264859798; - msg.z = 0.616325640622; - msg.phi = 0.559446906024; - msg.theta = 0.850669183697; - msg.psi = 0.180778243412; - msg.u = 0.432650115634; - msg.v = 0.647650747457; - msg.w = 0.926186447865; - msg.p = 0.506209470492; - msg.q = 0.567720275063; - msg.r = 0.321334046365; - msg.svx = 0.620225728596; - msg.svy = 0.86398082326; - msg.svz = 0.596427230833; + msg.setTimeStamp(0.8901002456083656); + msg.setSource(13607U); + msg.setSourceEntity(179U); + msg.setDestination(34588U); + msg.setDestinationEntity(139U); + msg.lat = 0.7696135382820941; + msg.lon = 0.032418609946401444; + msg.height = 0.7281127798561918; + msg.x = 0.6908686378180979; + msg.y = 0.3217232168476747; + msg.z = 0.12395140017653206; + msg.phi = 0.4545559196063168; + msg.theta = 0.7425464219876722; + msg.psi = 0.5414320622305017; + msg.u = 0.6690602098816613; + msg.v = 0.7658469185106173; + msg.w = 0.0918089964718668; + msg.p = 0.7769159936205925; + msg.q = 0.05673737457279793; + msg.r = 0.7271899354581108; + msg.svx = 0.04823923945604702; + msg.svy = 0.25603275017217975; + msg.svz = 0.5332394541701294; try { @@ -1220,29 +1219,29 @@ main(void) { IMC::SimulatedState msg; - msg.setTimeStamp(0.927591070981); - msg.setSource(23088U); - msg.setSourceEntity(157U); - msg.setDestination(17086U); - msg.setDestinationEntity(172U); - msg.lat = 0.403339363802; - msg.lon = 0.16941736053; - msg.height = 0.203085364424; - msg.x = 0.688023202602; - msg.y = 0.349907398684; - msg.z = 0.465759363369; - msg.phi = 0.146916447947; - msg.theta = 0.109164538247; - msg.psi = 0.814255396682; - msg.u = 0.619569948514; - msg.v = 0.0392802195432; - msg.w = 0.158602620576; - msg.p = 0.625007008695; - msg.q = 0.795595093327; - msg.r = 0.306130477781; - msg.svx = 0.417995659163; - msg.svy = 0.217516962002; - msg.svz = 0.846703446426; + msg.setTimeStamp(0.6771465255878283); + msg.setSource(14923U); + msg.setSourceEntity(82U); + msg.setDestination(31389U); + msg.setDestinationEntity(130U); + msg.lat = 0.6614949869847906; + msg.lon = 0.8711256153146187; + msg.height = 0.5457763381656546; + msg.x = 0.8517254966611064; + msg.y = 0.5308290026020461; + msg.z = 0.9657125133611385; + msg.phi = 0.9883516843683586; + msg.theta = 0.9415734140599634; + msg.psi = 0.19076425825622711; + msg.u = 0.8388810411832502; + msg.v = 0.04015670587312781; + msg.w = 0.9520352656564522; + msg.p = 0.9245153932870328; + msg.q = 0.8523484101568696; + msg.r = 0.9909683109400763; + msg.svx = 0.23967274358252544; + msg.svy = 0.5794620486605891; + msg.svz = 0.598643019805661; try { @@ -1261,13 +1260,13 @@ main(void) { IMC::LeakSimulation msg; - msg.setTimeStamp(0.914554378597); - msg.setSource(51490U); - msg.setSourceEntity(101U); - msg.setDestination(35734U); - msg.setDestinationEntity(214U); - msg.op = 194U; - msg.entities.assign("PLFPXZXHLBWQBFNHJNZXOVQSSKWTTAAMFNXAPPKRWAXKIRBOXFSKPBPYYTUCBOELHGUOSHVZWITNDKUHETWYFMDKJVJSVTQPJFTRQKPAYSGLMLGLDBXOATIMMFZSGVNUOWZZDVXJTIJSDECEQ"); + msg.setTimeStamp(0.01871145409277486); + msg.setSource(4253U); + msg.setSourceEntity(202U); + msg.setDestination(29242U); + msg.setDestinationEntity(243U); + msg.op = 214U; + msg.entities.assign("NJGAPYBYBGNHQKLZTLIFHMYYPWRUDXSCEUYAQZVEMBRHSPRFADUSMVJUHQMFXQGZCNQUEULEIUCBFILCKOADSWJMJKTCGGPPYXOMGHFWNPRXPKVYJIOEONBUCGFGNLRIRXWEUUKADXBHBZSQHRXWBRS"); try { @@ -1286,13 +1285,13 @@ main(void) { IMC::LeakSimulation msg; - msg.setTimeStamp(0.800987635702); - msg.setSource(46546U); - msg.setSourceEntity(46U); - msg.setDestination(31553U); - msg.setDestinationEntity(206U); - msg.op = 150U; - msg.entities.assign("UWVHCDTIEYPVFUCFSOZIMTYUMCNTRMWANFSDWQZBAVTQOLPUOGGFJIXIIMMJFZKYZBICNJJHVDESSUCFKQLHAWAHXIKHTGOXDTMRZSNQNYROZVBGOGOJHWKHPWLRBJHUMKYBDVKDCPZTOMPBXECVN"); + msg.setTimeStamp(0.1183371702863546); + msg.setSource(53482U); + msg.setSourceEntity(99U); + msg.setDestination(57966U); + msg.setDestinationEntity(15U); + msg.op = 80U; + msg.entities.assign("HLYVFKCZFEUBRKOHTPYWIDFQGYSMHUXICHKVOLTAYVIREPCTZMFDJDDFEYMJDYQAIHFGONNGQRPLDTEWNLAIPJEYJURVOZJNFCKPQMCEJLOERYQWKVBNGEXXQSMJMMQGSDNMWKZCAJVWUGSFAGIUXWABFVSIUWNHCPBUXPBADTYHVOZKPMUBBSHE"); try { @@ -1311,13 +1310,13 @@ main(void) { IMC::LeakSimulation msg; - msg.setTimeStamp(0.379784878721); - msg.setSource(36128U); - msg.setSourceEntity(142U); - msg.setDestination(49502U); - msg.setDestinationEntity(134U); - msg.op = 56U; - msg.entities.assign("OUHQMTSFVECEDCALOXKYUNHTEDFJKEYJAABIOLXFTTSWOCHABHIVQYGVQRJQVBNOSZPLBCQFZPWIHZJEPKZDVLFSRDMKPHHGCGSSWJJCPINAVWDURXRNMCWPKRUGQFEYUJBLOTWHDYEZZOEZLSRDJNGWTLCXIRKGTLNOMQUPPHLB"); + msg.setTimeStamp(0.9702408454941421); + msg.setSource(29581U); + msg.setSourceEntity(166U); + msg.setDestination(30799U); + msg.setDestinationEntity(70U); + msg.op = 132U; + msg.entities.assign("QNWWNXCMKEWEGSXFBHOTFPYTKSRYKGZSQXXLQUQHIZCOBASXTUGPXECSIUJOTWAPEUYPFQIGQTLIBXFOEERLFHVLLMMMYWGLUBSCJZAOJALJRVKGLAGJPHQSMSLYAPHGCNUDVITSRDZEOIQNFZODACHUHYKZUIBNVPNEK"); try { @@ -1336,14 +1335,14 @@ main(void) { IMC::UASimulation msg; - msg.setTimeStamp(0.817196927334); - msg.setSource(9534U); - msg.setSourceEntity(90U); - msg.setDestination(3373U); - msg.setDestinationEntity(226U); - msg.type = 251U; - msg.speed = 2738U; - const char tmp_msg_0[] = {-60, 105, -47, 41, 74, -108, -120, 25, 113, -82, -15, -103, 29, 118, 13, -101, -31}; + msg.setTimeStamp(0.9789908302500878); + msg.setSource(51816U); + msg.setSourceEntity(133U); + msg.setDestination(39995U); + msg.setDestinationEntity(52U); + msg.type = 196U; + msg.speed = 30252U; + const signed char tmp_msg_0[] = {66, -95, 126, 33, -6, 108, -34, -62, -111, 95, 103, 39, 26, -7, 49, -13, 60, 108, -13, 82, 42, 112, -119, -80, 126, 46, -121, -64, 90, -107, 59, 71, 63, -100, 50, 101, -68, -22, 98, 121, -107, 45, -50, 52, -78, 11, -46, 12, 84, 47, -44, -102, 100, -22, -55, 91, -20, -89, -69, 65, -79, 117, -18, 65, -74, -116, 47, 2, 93, 78, 79, -3, 47, -105, -53, 120, -53, -6, 8, -26, 110, 60, 95, -2, 24, -44, 89, -97, 115, -122, -14, -93, -119, -118, 124, 121, -122, 30, 114, -98, -73, 117, 34, 82, 110, 5, 85, 59, 8, 114, 88, 60, -14, 95, -120, -13, 27, 63, -69, -11, 104, -120, 16, 100, 14, 91, -72, 9, 66, 35, -79, -90, -7, -127, -38, 34, 46, -103, -106, 73, 21, -117, 18, -56, 35, -55, 38, 80, -18, 123, 100, -70, -92, 47, 120, 99, -101, 85, -105, 59, 0, -49, -92, -100, -112, 4, -84, 31, -18, 104, 45, -97, -63, -29, 105, -111, -86, 116, 82, -113, 45, 123, 71, -51, -8, -63, 37, 7, -36, -42, -59, 61, -41, -97, -14, -38, -93, -11, -62, 124, 77, 96, -115, -81, -102, 11, 0, 78, 27, -49, -77, -91, 72, 6, -17, 25, -29, 98, -48, -67, -116, 62, 60, -56, 37, -8, 19, 108, 60, -98, -10, 70, -79, -91, 119, 66, 60, 30, 42, -6, 47, 53, -107, 91, -89, 62, -45, -52, 51, 1, 21, 9, 53}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -1363,14 +1362,14 @@ main(void) { IMC::UASimulation msg; - msg.setTimeStamp(0.343232459505); - msg.setSource(7682U); - msg.setSourceEntity(10U); - msg.setDestination(60563U); - msg.setDestinationEntity(43U); - msg.type = 138U; - msg.speed = 40252U; - const char tmp_msg_0[] = {-76, -45, 68, 116, -39, 104, 95, 70, -95, 3, -30, 4, 97, 83, 56, 36, 52, -113, 85, -74, 5, 44, 8, -28, -6, 77, -18, 20, -74, -103, -26, -32, -25, -43, -83, 31, -4, -25, 85, 51, 109, -109, 22, -72, 121, -112, -92, 7, 86, -96, -25, -115, -25, 90, -2, 23, -69, -100, 53, -46, 19, -98, -67, -69, 37, 54, 122, 31, 65, -3, -36, 114, 43, -69, -112, 22, -122, -82, 104, -60, -95, 75, 107, -45, 4, 84, -64, 76, 78, -66, 112, -77, 27, -39, 72, 124, -60, -102, 104, 3, -106, 112, -67, -124, 109, 82, -29, 113, -30, -46, -48, 61, 115, 122, 69, -6, -34, -87, 92, -46, 60, 106, 83, -59, 10, -115, -48}; + msg.setTimeStamp(0.4524101497850227); + msg.setSource(36744U); + msg.setSourceEntity(150U); + msg.setDestination(17837U); + msg.setDestinationEntity(200U); + msg.type = 145U; + msg.speed = 22848U; + const signed char tmp_msg_0[] = {-2, 25, 17, -59, -9, -4, -93, -67, 44, -7, 51, 119, -52, 41, -82, -89, -55, 16, -14, -86, 50, -57, -112, 34, -36, -67, 89, -88, 29, -54, 33, 0, -57, 15, 81, -86, -96, 119, 1, -81, 17, -57, 68, -3, 42, -38, 99, 27, 21, -42, -23, 115, 1, -32, 0, -73, -54, -121, -85, -121, 74, 44, 4, 0, -24, -6, -90, 35, 2, -92, -93, -118, -114, -32, -19, 59, 56, 31, 23, 74, 99, 26, 90, 91, 85, -70, 83, -88, 31, -93, -53, -100, 34, -115, 12, -32, 6, -4, -56, -114, -107, 42, -9, -11, -31, 61, -99, -76, 84, 23, 43, -49, -36, -76, 11, -91, 36, -94, 113, 13, -121, -35, 88, 107, 125, -125, 17, 99, -125, 92, 10, 62, 88, 83, 95, 101, -4, 78, 98, 63, 123, -120, 69, 67, 79, -116, -36, 124, 28, -22, 34, 20, -59, 53, -36, 69, -110, -22, -49, -3, -4, -112, -100, 106, -60, 13, 66, -3, -37, 76, -43, -101, -44, -7}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -1390,14 +1389,14 @@ main(void) { IMC::UASimulation msg; - msg.setTimeStamp(0.832866804309); - msg.setSource(37876U); - msg.setSourceEntity(195U); - msg.setDestination(33980U); - msg.setDestinationEntity(150U); - msg.type = 27U; - msg.speed = 9734U; - const char tmp_msg_0[] = {20, 22, 55, 90, 56, -49, -64, 65, -79, 21}; + msg.setTimeStamp(0.827027357855436); + msg.setSource(54765U); + msg.setSourceEntity(114U); + msg.setDestination(57150U); + msg.setDestinationEntity(66U); + msg.type = 62U; + msg.speed = 298U; + const signed char tmp_msg_0[] = {-102, 59, 57, -44, -21, -12, -3, -125, -122, -54, 107, -23, -113, -91, 88, 39, 29, -70, 115, 37, 96, 52, 109, 15, 95, 56, -40, -40, 106, 77, 90, 83, -106, 3, 22, -2, -34, -18, -81, 58, 99, 126, -7, -54, 97, -61, 64, -9, -68, 69, 76, -60, 67, 108, -43, 123, 87, 94, -1, 97, -58, 115, 97, 98, -106, 62, 103, -18, -76, 40, -61, 123, 96, -53, -93, 32, 25, -13, 109, -58}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -1417,14 +1416,14 @@ main(void) { IMC::DynamicsSimParam msg; - msg.setTimeStamp(0.047579047336); - msg.setSource(21876U); - msg.setSourceEntity(85U); - msg.setDestination(14402U); - msg.setDestinationEntity(153U); - msg.op = 71U; - msg.tas2acc_pgain = 0.685044729736; - msg.bank2p_pgain = 0.800216603098; + msg.setTimeStamp(0.9973411555773476); + msg.setSource(45966U); + msg.setSourceEntity(180U); + msg.setDestination(27021U); + msg.setDestinationEntity(229U); + msg.op = 169U; + msg.tas2acc_pgain = 0.4654679438216621; + msg.bank2p_pgain = 0.7263186886520872; try { @@ -1443,14 +1442,14 @@ main(void) { IMC::DynamicsSimParam msg; - msg.setTimeStamp(0.716484292073); - msg.setSource(63861U); - msg.setSourceEntity(64U); - msg.setDestination(45106U); - msg.setDestinationEntity(33U); - msg.op = 135U; - msg.tas2acc_pgain = 0.515614557628; - msg.bank2p_pgain = 0.85789959517; + msg.setTimeStamp(0.13283742964526457); + msg.setSource(6340U); + msg.setSourceEntity(247U); + msg.setDestination(11615U); + msg.setDestinationEntity(32U); + msg.op = 53U; + msg.tas2acc_pgain = 0.38886535352665386; + msg.bank2p_pgain = 0.07058295607509413; try { @@ -1469,14 +1468,14 @@ main(void) { IMC::DynamicsSimParam msg; - msg.setTimeStamp(0.793050727719); - msg.setSource(44434U); - msg.setSourceEntity(12U); - msg.setDestination(30712U); - msg.setDestinationEntity(124U); - msg.op = 60U; - msg.tas2acc_pgain = 0.739060024363; - msg.bank2p_pgain = 0.287531827818; + msg.setTimeStamp(0.12073776437766615); + msg.setSource(43417U); + msg.setSourceEntity(46U); + msg.setDestination(33569U); + msg.setDestinationEntity(209U); + msg.op = 166U; + msg.tas2acc_pgain = 0.20182081875072444; + msg.bank2p_pgain = 0.9748893203946627; try { @@ -1495,13 +1494,13 @@ main(void) { IMC::StorageUsage msg; - msg.setTimeStamp(0.0495750407943); - msg.setSource(31883U); - msg.setSourceEntity(41U); - msg.setDestination(8945U); - msg.setDestinationEntity(89U); - msg.available = 3127608657U; - msg.value = 106U; + msg.setTimeStamp(0.24994849705495914); + msg.setSource(39908U); + msg.setSourceEntity(134U); + msg.setDestination(41782U); + msg.setDestinationEntity(222U); + msg.available = 1958967582U; + msg.value = 96U; try { @@ -1520,13 +1519,13 @@ main(void) { IMC::StorageUsage msg; - msg.setTimeStamp(0.0473091964451); - msg.setSource(46972U); - msg.setSourceEntity(113U); - msg.setDestination(32335U); - msg.setDestinationEntity(216U); - msg.available = 1889304641U; - msg.value = 96U; + msg.setTimeStamp(0.9691174233506368); + msg.setSource(21464U); + msg.setSourceEntity(77U); + msg.setDestination(7673U); + msg.setDestinationEntity(219U); + msg.available = 3831006376U; + msg.value = 132U; try { @@ -1545,13 +1544,13 @@ main(void) { IMC::StorageUsage msg; - msg.setTimeStamp(0.501263967247); - msg.setSource(3691U); - msg.setSourceEntity(23U); - msg.setDestination(6462U); - msg.setDestinationEntity(15U); - msg.available = 3728561269U; - msg.value = 28U; + msg.setTimeStamp(0.6168232944257755); + msg.setSource(3369U); + msg.setSourceEntity(50U); + msg.setDestination(42900U); + msg.setDestinationEntity(65U); + msg.available = 2885140228U; + msg.value = 114U; try { @@ -1570,20 +1569,15 @@ main(void) { IMC::CacheControl msg; - msg.setTimeStamp(0.482084079642); - msg.setSource(52420U); - msg.setSourceEntity(123U); - msg.setDestination(1250U); - msg.setDestinationEntity(132U); - msg.op = 187U; - msg.snapshot.assign("EMHZBRQYPFXTBAGWWMSQMMIXLAKYETQPIKYUISZUNOQDCLEQHCOXXME"); - IMC::FormState tmp_msg_0; - tmp_msg_0.possimerr = 0.616915131081; - tmp_msg_0.converg = 0.157026541923; - tmp_msg_0.turbulence = 0.781636021882; - tmp_msg_0.possimmon = 172U; - tmp_msg_0.commmon = 231U; - tmp_msg_0.convergmon = 236U; + msg.setTimeStamp(0.41241228711669387); + msg.setSource(33383U); + msg.setSourceEntity(110U); + msg.setDestination(26548U); + msg.setDestinationEntity(150U); + msg.op = 85U; + msg.snapshot.assign("ZJJBKIYFFGMRZXWZDRHJUAYUYOIIPCWRBQQXTFLDAXLZAFHNDDYGPILGKBZIHHORUSAIQAEWTFVDTXDVZXOOCLPBLXYWZRRAMEPJGTUAAOCYFKRFHSUSWJMGWEJTGBDQBCLBONFVTUIPYWQEEEKNQFQMVZKSMM"); + IMC::Depth tmp_msg_0; + tmp_msg_0.value = 0.7516506963545743; msg.message.set(tmp_msg_0); try @@ -1603,16 +1597,34 @@ main(void) { IMC::CacheControl msg; - msg.setTimeStamp(0.433826662833); - msg.setSource(7043U); - msg.setSourceEntity(241U); - msg.setDestination(23198U); - msg.setDestinationEntity(245U); - msg.op = 201U; - msg.snapshot.assign("QLQBHWIIOJFXYWCBAPFJNIZRKXLONSWZIFPHTDHLOEERONMBEW"); - IMC::AnnounceService tmp_msg_0; - tmp_msg_0.service.assign("BKWVKUASNSOVYHHUXJKGTWBYBKHGATEYXKQIREYCGYPIKULLPTWQASAXRFDFIDCCRHXXJBPDSNVOOFVWJNAMAYQKVVXLLQHQGVJQGOZZXCBIRPOTRZNRSQGFGEIHNFWDAWCCFEZXKPJFEIMPHLMTIBPNZFZBHYBXIDUMMWLSDMBVELRORNTKZJWQLKWTPJMISIVUJFYHGOMDDEMZNDJSPCUWAEEYHOU"); - tmp_msg_0.service_type = 91U; + msg.setTimeStamp(0.08769390847732639); + msg.setSource(41762U); + msg.setSourceEntity(63U); + msg.setDestination(49544U); + msg.setDestinationEntity(66U); + msg.op = 73U; + msg.snapshot.assign("WENATDCMZWIGTHFXMOMWURMUXBBZHOFXALMWLILLPNIYFMYUPIVGDHAGOEQEQZWJSSCCCFCRPKQBHICWRGUQGUOKOSOJERLHTISKJNCEAAXOPCQPNHBHJWYUPSULHKVVSIOCMFREJGHDVDSKTBZAEXAXZEIFGLQUPKTPPYOZSTDJDTMIVBWBJYRFVKVVUBBATVSQAYHGDWIZRTRYRAXELKZVGMDCEXNZZJXSM"); + IMC::AcousticMessage tmp_msg_0; + IMC::AcousticMessage tmp_tmp_msg_0_0; + IMC::DmsDetection tmp_tmp_tmp_msg_0_0_0; + tmp_tmp_tmp_msg_0_0_0.ch01 = 0.3640742134586188; + tmp_tmp_tmp_msg_0_0_0.ch02 = 0.5072919257663303; + tmp_tmp_tmp_msg_0_0_0.ch03 = 0.12319356670645532; + tmp_tmp_tmp_msg_0_0_0.ch04 = 0.619921518675661; + tmp_tmp_tmp_msg_0_0_0.ch05 = 0.34700837412916485; + tmp_tmp_tmp_msg_0_0_0.ch06 = 0.5235536634751858; + tmp_tmp_tmp_msg_0_0_0.ch07 = 0.2444476975258546; + tmp_tmp_tmp_msg_0_0_0.ch08 = 0.033548758494103104; + tmp_tmp_tmp_msg_0_0_0.ch09 = 0.7894085718035747; + tmp_tmp_tmp_msg_0_0_0.ch10 = 0.8693503128948493; + tmp_tmp_tmp_msg_0_0_0.ch11 = 0.7613612371429342; + tmp_tmp_tmp_msg_0_0_0.ch12 = 0.1475235395849963; + tmp_tmp_tmp_msg_0_0_0.ch13 = 0.2298851214853097; + tmp_tmp_tmp_msg_0_0_0.ch14 = 0.6460502137573151; + tmp_tmp_tmp_msg_0_0_0.ch15 = 0.18418436804148786; + tmp_tmp_tmp_msg_0_0_0.ch16 = 0.30601757692038734; + tmp_tmp_msg_0_0.message.set(tmp_tmp_tmp_msg_0_0_0); + tmp_msg_0.message.set(tmp_tmp_msg_0_0); msg.message.set(tmp_msg_0); try @@ -1632,15 +1644,15 @@ main(void) { IMC::CacheControl msg; - msg.setTimeStamp(0.922604141369); - msg.setSource(11646U); - msg.setSourceEntity(141U); - msg.setDestination(21147U); - msg.setDestinationEntity(251U); - msg.op = 40U; - msg.snapshot.assign("NQLSMLUKUGLQNBECOIN"); - IMC::DepthOffset tmp_msg_0; - tmp_msg_0.value = 0.109514245789; + msg.setTimeStamp(0.5615807279576449); + msg.setSource(29162U); + msg.setSourceEntity(106U); + msg.setDestination(8222U); + msg.setDestinationEntity(234U); + msg.op = 97U; + msg.snapshot.assign("JLTBEJQMTMGHBCHMNLXVUNJQCDPUSRNDHLPJRNXZJMRWYQUIJNPCVORCUXYBGFJDGQKMWYETQBCFYSTZYDRUOKVRLDBATXXKYCUXEQOOHYZJQINBZOKIKZMOFZQOYIPRWSMBQHLCDOQWWLGDLCGVET"); + IMC::CrudeOil tmp_msg_0; + tmp_msg_0.value = 0.07687831104035014; msg.message.set(tmp_msg_0); try @@ -1660,13 +1672,13 @@ main(void) { IMC::LoggingControl msg; - msg.setTimeStamp(0.0527700157238); - msg.setSource(16871U); - msg.setSourceEntity(123U); - msg.setDestination(1903U); - msg.setDestinationEntity(128U); - msg.op = 21U; - msg.name.assign("CLHKPSZOCHLWUFBRITMAEWOTWUVMSKVMAWSKGNMHDGOMZYBKSWFLBOREQQCIADUJIWDYHFZGTZXKUVRQQICSWIRSWHTDJKKZBUJRJ"); + msg.setTimeStamp(0.22710320700566788); + msg.setSource(55105U); + msg.setSourceEntity(26U); + msg.setDestination(5959U); + msg.setDestinationEntity(29U); + msg.op = 35U; + msg.name.assign("VOEBRIKJTJSBNVADIGFPSFSHIKVBRUAFOEFBHQGEYGTEMMNXNNBCQXQGOFYBQHWZYCUZRTWMNQKJZHHDUJYDDJALKIAHKNMICHGJRSISLOXKOPDJUFWCFFYIOVWIDEL"); try { @@ -1685,13 +1697,13 @@ main(void) { IMC::LoggingControl msg; - msg.setTimeStamp(0.216520384412); - msg.setSource(47203U); + msg.setTimeStamp(0.7366391627428219); + msg.setSource(53759U); msg.setSourceEntity(25U); - msg.setDestination(2184U); - msg.setDestinationEntity(65U); - msg.op = 253U; - msg.name.assign("YPQJDGJPMXAYCFEWQREAKNVDBDZEBWTTHFPJGYZIPCUGIIYIGGVHQTVXWRDXOEMBBEREDLWDXDUSKIECZBWNTYNVGHDOZDKXXMAXLYKZLIGCYZAPXSQLNLWITLYORJTRJSHUZVQFLUBPKMQCIINFNBJWMHXWSUVPZUJMKJZTHFKJBANGRLQNGHANSF"); + msg.setDestination(26022U); + msg.setDestinationEntity(206U); + msg.op = 218U; + msg.name.assign("XPRZYLGWOEOMITWDPFCSRAYRHFHUCNSYLTICFXOYQFCFOKCBKDPALLTBZTGXTMNNRUOCPMXGJDNDLDUEZQKHWQWSOEBZMDFCUKPQWMRKLVRDYEHEXRTRYILSRNMGXZUOSUHBJMFHFPEJRMEAQMSKETZUJIBQCSJALK"); try { @@ -1710,13 +1722,13 @@ main(void) { IMC::LoggingControl msg; - msg.setTimeStamp(0.889185399414); - msg.setSource(8036U); - msg.setSourceEntity(194U); - msg.setDestination(32320U); - msg.setDestinationEntity(233U); - msg.op = 52U; - msg.name.assign("VUUWUABCYYTMYWHJHQAIKFPJYMUNTSJSALAGXPCDLWKWYCVTICFNYLMMBQIRWKHBFTOVWVMPFPCAZNZNRKZSHZUIVOCBMNDMPJHTUXERZJDQWXJGQINZEGHTGKCIR"); + msg.setTimeStamp(0.021964591947197798); + msg.setSource(4682U); + msg.setSourceEntity(38U); + msg.setDestination(208U); + msg.setDestinationEntity(65U); + msg.op = 97U; + msg.name.assign("SXMZBWNOLFPRZPPWUYXUUEWWOZKCFQGASAERHZJSGXCEMHZTDASYZIRXIFOTSBFJQTEZIMTCJDDSJVDNYFRKNRCWGKJIVKVHBPBEOAHVFJTFER"); try { @@ -1735,15 +1747,15 @@ main(void) { IMC::LogBookEntry msg; - msg.setTimeStamp(0.42892974979); - msg.setSource(14132U); - msg.setSourceEntity(47U); - msg.setDestination(41549U); - msg.setDestinationEntity(60U); - msg.type = 109U; - msg.htime = 0.993537194561; - msg.context.assign("BZRYLGYHOHDXNYQUETTJUFDSSXNIYVBSVPRAVAUJKPAARZIOGCAWUHKBEACKHPBGAALOLMFVKRCWPTEUMTVMBPZRZI"); - msg.text.assign("XJELBLCCLFCHKJSVMFMHNYZAQHDMZWWAXCFCKBRLZDOPKNTCYDHOARJBYYUXESRILXNRYHBZUMKATVMOTFBIZEKSHQGYVREMXDZXXKEPKXBWQSOTRGSLRWQNBGSAWPEVDKRTYPTENIIIUWQFJZNYDERZFDJVHTV"); + msg.setTimeStamp(0.31100495616604096); + msg.setSource(41744U); + msg.setSourceEntity(74U); + msg.setDestination(5612U); + msg.setDestinationEntity(163U); + msg.type = 81U; + msg.htime = 0.7497158844927722; + msg.context.assign("TMTSLEBRSXEOFKAQCMRXTBPXQBYVZHKPGOCUPKZSCEUDVTCFOWSKLYCPFYHNWJLKFJGFXDRIYGLHDEKUTLNSARDWOWEBFGQVOUIAGFVQGWVRSBAHQNOTGCZWSPMJYLJZWDBZRLGFCWTIOHVPKLXOPUMLYCR"); + msg.text.assign("VFFKYMGRRGIBKDJNBUTFNBOAFVQGGJWOWNBLUXATDKCQJSVOHIMERYUQDCBNWYVQKHTZRDAQYCPORIUKGCHFEEWJCSOTZSOAICXVQAEGJGRSYFAPWIBWXCPLNHXMSHAKGBTMDZKHNIAMBAYPVFGKTJPTRYFTZZLMUQIXLMNPJLIYU"); try { @@ -1762,15 +1774,15 @@ main(void) { IMC::LogBookEntry msg; - msg.setTimeStamp(0.733889196095); - msg.setSource(65207U); - msg.setSourceEntity(213U); - msg.setDestination(19117U); - msg.setDestinationEntity(116U); - msg.type = 30U; - msg.htime = 0.324910818088; - msg.context.assign("PMUEGWDIYABEFKZSDTFAFGYNTKNRYYACMLSBMRJOBSUXLGHWCBAXPUQPXKRUNWPAIOCHNCLPJFFCEJOKEFQPZDTYPFBCGVRGQALZXLNJCPJHIIFSX"); - msg.text.assign("PRWEICJWMAJROQFNWIBWFNETXYECAQQCZUSVBESZCHVEKLRYKBMSSKIRJPJZPCFUXAOMDNJUHNRUGYNDJDNEHRVQGMAAFIOYXILWBLFVOMCIUMUDSQLDUZPDGOUMTBIQWLBVXHZACUWSLNKZIDPAEFYGYMYCTOEBSRJCGAFZPXZGIPWETRFKRDHMBQVI"); + msg.setTimeStamp(0.44312162116495923); + msg.setSource(58631U); + msg.setSourceEntity(161U); + msg.setDestination(17638U); + msg.setDestinationEntity(197U); + msg.type = 71U; + msg.htime = 0.114663813697788; + msg.context.assign("IXVXMCLTRHUYQKOJUIBUEDGIHTUZDQKWBWEXYAFPQACMBFDMFPTRWUQOXXNICEOSKQVPCFOAZWLSITOCPZIBUSDFBWYJAWLGRRJMGDDZFEOAJFWQDRKRGMMJSGORHACHRGZXKXRPVJLWEYQVZJENGVLPNPYMSHUNTLYLCDTHAHNCYAUCMMXGBHUSETKNZVDBLXPFQNTIQGCVPVAGMEYSYUVBPQZAIOOLZWWJBZDEIEVNKOSKIHSKSYFF"); + msg.text.assign("UALHTKDWJBOJGMGBFHTRVUTLLBXJCOUTQKUKKLSETXXKHMDQGFJSPUZIJRNVBZPPEBOAIVYQDQQNVWAM"); try { @@ -1789,15 +1801,15 @@ main(void) { IMC::LogBookEntry msg; - msg.setTimeStamp(0.06946159919); - msg.setSource(26289U); - msg.setSourceEntity(251U); - msg.setDestination(40005U); - msg.setDestinationEntity(58U); - msg.type = 25U; - msg.htime = 0.194566416904; - msg.context.assign("QFPBFGCVKEOTRBOBOCOMLRHXZNSBTEJPXZIOWRQYUUQEEMNUGKDLWJJZTMMMUUELHFCVPUWLAAHZPZOSFNWQNVRKHBDKHGYQWMRSNAZYDPBTRXKSDQYCLIVOTHH"); - msg.text.assign("QOLIEYYXMGOGFAZALCQKPJOVQZNWMDIOAYCJPWSFUWGJJBNEUPIMHVLJTZTBQUACTSKJRBMOAWDMJMFAURTOOPXHCJYJDHSHQGQAQOREBKYYCIVXOMIZRCGDDDBUVUOPVILHSHNLZVSKPWAPDVUESMQKLHFCBYPHKDQGLEWHNSWREJXRNPVNKZFBFDTXZGRBEHCGMFLSERXTGUT"); + msg.setTimeStamp(0.20663729197801384); + msg.setSource(34999U); + msg.setSourceEntity(216U); + msg.setDestination(8456U); + msg.setDestinationEntity(147U); + msg.type = 238U; + msg.htime = 0.41302621475790613; + msg.context.assign("NJYWQNRUWAKKZSYSNUFXWIPZBJRFDVXZQQNSJIADKHRSWVPYPYOTKKDHVWJRELTZYHXOFAOIQEGDLFGUCDUGBZTUECHFUJRDGTLIZGVRBQHLGP"); + msg.text.assign("DOSDLSKDJIINDMBVJZVPJQQLRTVCFOJPYABWMQIKUDGFLHGZNRGMCYDHXIQLJLNNZCYBPKNVMEEGMOZSXFPOAVIFWYRAGFXQFEBQEFPKCXSTGHZCYYWIPNVCKENAKTMIDRWFHTINREOYAMFBSVJREOXPVXABWJMUJLSHQW"); try { @@ -1816,13 +1828,19 @@ main(void) { IMC::LogBookControl msg; - msg.setTimeStamp(0.249829195313); - msg.setSource(46070U); - msg.setSourceEntity(4U); - msg.setDestination(40647U); - msg.setDestinationEntity(117U); - msg.command = 141U; - msg.htime = 0.708468200109; + msg.setTimeStamp(0.30554490866068196); + msg.setSource(63560U); + msg.setSourceEntity(0U); + msg.setDestination(55776U); + msg.setDestinationEntity(132U); + msg.command = 11U; + msg.htime = 0.7368523139631289; + IMC::LogBookEntry tmp_msg_0; + tmp_msg_0.type = 146U; + tmp_msg_0.htime = 0.3304232858134235; + tmp_msg_0.context.assign("WPPNQHFLFCTDVOOVOGELWUZHHPCGFZGYPKWRDBSOWIZKMJDBAOFBGHFLBXMFYIZFXKTADWSYSBGQXTAKJSSRUIEUGCEXQVWBCQGDACLIEJKUWCZYQSVMLLJUJRLTRPBDGANTAQPQEXKJBMVVHIQPXEHNYUNZEWLCEMCIPSTNGNHYIYRYNYXAOKRFLLFONVBEZNDMUXCJHHDRGPXVQJTTSZCSFVEUNPAJKBWMMRWZUVMIMROQDKAOT"); + tmp_msg_0.text.assign("TIUOGNQSJJFQHWGBXLXIKVNWLMEUDOCZMHDCNJRHOEWFLSNDMVVXPBBUBBMBYJIXNJYXUPOTEDKYHCHIOFTDFZOOAMOVCDHFVLGVYAWPHBKZHUUJKAWRARHQETPKDGRXULFNSYKVQTKTIONXLLMEZWTRNXTWASVOSCLSWAYJPCJNQQQEBP"); + msg.msg.push_back(tmp_msg_0); try { @@ -1841,13 +1859,13 @@ main(void) { IMC::LogBookControl msg; - msg.setTimeStamp(0.780699163454); - msg.setSource(45874U); - msg.setSourceEntity(65U); - msg.setDestination(9159U); - msg.setDestinationEntity(227U); - msg.command = 124U; - msg.htime = 0.0539423393122; + msg.setTimeStamp(0.6996879237549278); + msg.setSource(8844U); + msg.setSourceEntity(78U); + msg.setDestination(26801U); + msg.setDestinationEntity(129U); + msg.command = 54U; + msg.htime = 0.40484630787479403; try { @@ -1866,18 +1884,18 @@ main(void) { IMC::LogBookControl msg; - msg.setTimeStamp(0.720330317902); - msg.setSource(61265U); - msg.setSourceEntity(251U); - msg.setDestination(6866U); - msg.setDestinationEntity(181U); - msg.command = 226U; - msg.htime = 0.377431549006; + msg.setTimeStamp(0.8864175176095255); + msg.setSource(1196U); + msg.setSourceEntity(197U); + msg.setDestination(48014U); + msg.setDestinationEntity(207U); + msg.command = 42U; + msg.htime = 0.9504018528031785; IMC::LogBookEntry tmp_msg_0; - tmp_msg_0.type = 48U; - tmp_msg_0.htime = 0.309877131626; - tmp_msg_0.context.assign("KBOBKBFRHRMIFHDIYLURCMQYVWFHDAVTLNVZFLNEIROQUCTWYQATVTLSWNMVNEZIRDJTYCPVGMEFAGLGSDPYRTEWEWXGMQQZSDLKHWJAEVBHTRHGCXIRNFC"); - tmp_msg_0.text.assign("WEXQAXIECTSPMHKZRYTGCZMJTFXQYOKQPYUNBNWYZLDNBQPFJQRXDF"); + tmp_msg_0.type = 51U; + tmp_msg_0.htime = 0.47928697433179535; + tmp_msg_0.context.assign("GHMEWGCOZCQALAVIQROJRJHZPMKJKNQAMQLKFAPFZVLZQKFPJCOSEYCHQHFJUUXWNLAOQPIBZZGGXBOXXJIADTMYTVUWSCQUSDKPDHVDBJRVSDBECSSLYXFCRXRDVUPYWTIULHCMGSVQGKIXTYUXTVBRIBKPZIOZUWDWINWXOULVTSWRNJFMYIHFEYJLBHPTZNEERUKSLNREDNIAKEHWGYOK"); + tmp_msg_0.text.assign("OXJZGMQBIDSMNVKCYBOWQARKOXMERRWSTVZRRHTUAIEADMGPPAGIFUWHJCHYBCEEALARBYSZHHFTDQGFPNIJY"); msg.msg.push_back(tmp_msg_0); try @@ -1897,13 +1915,13 @@ main(void) { IMC::ReplayControl msg; - msg.setTimeStamp(0.999295402196); - msg.setSource(1536U); - msg.setSourceEntity(22U); - msg.setDestination(53034U); - msg.setDestinationEntity(235U); - msg.op = 104U; - msg.file.assign("AANRUWEOEADIMVDWCEBYBDCNLJMUTOLRYORLASOLIHZKVKJACQKZFMIBPFTTUJYLVHQWGWVGQQJZBBGGAUDBWDKHIWOPRXCJWCIRLTWKSBQVXIMJSDGSYGKMNRJFQUZQIFPUTDPTXMZNFTPNWJVEDEYNHN"); + msg.setTimeStamp(0.8892269101550027); + msg.setSource(55505U); + msg.setSourceEntity(110U); + msg.setDestination(61105U); + msg.setDestinationEntity(222U); + msg.op = 204U; + msg.file.assign("JOWQPYADQWRSMLODUSSDDCYWGSXEHENIWOCSSFLFCPIPLOBLCAXTQBZRYNOYHVDPTDJOZXYKIJIZKXNTRGBQJFTTBUTFIXAHMNKLBREJPAXCVRBZNGVXQKQEQYKCFKXONEHJPCAFMONRTWAIEMPQKROHVGWULVWJAHQUCXEGESPRLLJYMTNGGKCDCGNPLFVVTKSERUHMJBJWIAIYKLUGHZSFZZFZGPDYZNDMMUITUVZWEBQWHORAIXBVVHUA"); try { @@ -1922,13 +1940,13 @@ main(void) { IMC::ReplayControl msg; - msg.setTimeStamp(0.614306676809); - msg.setSource(54142U); - msg.setSourceEntity(139U); - msg.setDestination(22387U); - msg.setDestinationEntity(195U); - msg.op = 148U; - msg.file.assign("TDJZNNOPKSVSFOHUZTJQLVWHOKONEVWZPNBXCLPETSTPXTOSNBTYVHMTZHPALMWLFQLKMDZSIKJJGHTKMOXWRFYWBLIGWJXERABVBJDHPSYQFMFRGC"); + msg.setTimeStamp(0.6669124422585723); + msg.setSource(62040U); + msg.setSourceEntity(165U); + msg.setDestination(17833U); + msg.setDestinationEntity(196U); + msg.op = 149U; + msg.file.assign("JKHZLNBOFNKUMLJCKYDFNCSHHKWDZXFLTGTWMLLGUOMJVHRQQVVNXXFOXCQCDTBLSPIXOSRRJYFOUYMPVTWCARNRHYVPTUSWICICQSZNSEAEJRSSZQBZJTKMSPKPUMV"); try { @@ -1947,13 +1965,13 @@ main(void) { IMC::ReplayControl msg; - msg.setTimeStamp(0.602204513771); - msg.setSource(22612U); - msg.setSourceEntity(5U); - msg.setDestination(52084U); - msg.setDestinationEntity(16U); - msg.op = 195U; - msg.file.assign("LBSJRCCCOOWEMWRPICUGPZFVDEMHNADAXDCRYGQQHGTHXIEMPBQVLUFTVPSQJLMIWKRSNPWIZLSGATONGKZOBZFXUVEQKQJXDXWKDHJERXUYYLHTDINBMOCTLMDMAAFPXWTINJKOLYOSVWNPFDFYHUSGKRUVZKJBHZR"); + msg.setTimeStamp(0.2071073261980455); + msg.setSource(33314U); + msg.setSourceEntity(122U); + msg.setDestination(24410U); + msg.setDestinationEntity(218U); + msg.op = 172U; + msg.file.assign("FUGKJYDBYUOTQJCXFGNTNURSELWCINVGOFTYXFQBKHEYEWPQIOSINOBPYBVJRPKVIYRNAZIZLRUMSTFOMQBTRSPMMIWMEHPMVSA"); try { @@ -1972,14 +1990,14 @@ main(void) { IMC::ClockControl msg; - msg.setTimeStamp(0.300697982348); - msg.setSource(16108U); - msg.setSourceEntity(10U); - msg.setDestination(41605U); - msg.setDestinationEntity(196U); - msg.op = 48U; - msg.clock = 0.627107468298; - msg.tz = -8; + msg.setTimeStamp(0.053249006468210514); + msg.setSource(14718U); + msg.setSourceEntity(74U); + msg.setDestination(60885U); + msg.setDestinationEntity(200U); + msg.op = 73U; + msg.clock = 0.06777663475569817; + msg.tz = -125; try { @@ -1998,14 +2016,14 @@ main(void) { IMC::ClockControl msg; - msg.setTimeStamp(0.0300582608597); - msg.setSource(35782U); - msg.setSourceEntity(135U); - msg.setDestination(39637U); - msg.setDestinationEntity(137U); - msg.op = 210U; - msg.clock = 0.121034948413; - msg.tz = 93; + msg.setTimeStamp(0.48987238834967994); + msg.setSource(28027U); + msg.setSourceEntity(174U); + msg.setDestination(26581U); + msg.setDestinationEntity(161U); + msg.op = 207U; + msg.clock = 0.7310021907743695; + msg.tz = -36; try { @@ -2024,14 +2042,14 @@ main(void) { IMC::ClockControl msg; - msg.setTimeStamp(0.0115466047994); - msg.setSource(41326U); - msg.setSourceEntity(149U); - msg.setDestination(1966U); - msg.setDestinationEntity(222U); - msg.op = 217U; - msg.clock = 0.368994430074; - msg.tz = 88; + msg.setTimeStamp(0.5851398307727187); + msg.setSource(11934U); + msg.setSourceEntity(37U); + msg.setDestination(63075U); + msg.setDestinationEntity(174U); + msg.op = 105U; + msg.clock = 0.4733639702611635; + msg.tz = 57; try { @@ -2050,14 +2068,14 @@ main(void) { IMC::HistoricCTD msg; - msg.setTimeStamp(0.962693647152); - msg.setSource(57114U); - msg.setSourceEntity(51U); - msg.setDestination(9593U); - msg.setDestinationEntity(23U); - msg.conductivity = 0.650202796391; - msg.temperature = 0.920952369645; - msg.depth = 0.144537844965; + msg.setTimeStamp(0.9893354235188334); + msg.setSource(17220U); + msg.setSourceEntity(63U); + msg.setDestination(39519U); + msg.setDestinationEntity(104U); + msg.conductivity = 0.8403653534150933; + msg.temperature = 0.7766911853888873; + msg.depth = 0.056295666977356884; try { @@ -2076,14 +2094,14 @@ main(void) { IMC::HistoricCTD msg; - msg.setTimeStamp(0.760722750221); - msg.setSource(28573U); - msg.setSourceEntity(197U); - msg.setDestination(64050U); - msg.setDestinationEntity(15U); - msg.conductivity = 0.364065135171; - msg.temperature = 0.897330920512; - msg.depth = 0.369197520223; + msg.setTimeStamp(0.75827439968588); + msg.setSource(14371U); + msg.setSourceEntity(201U); + msg.setDestination(35656U); + msg.setDestinationEntity(191U); + msg.conductivity = 0.9480217842741472; + msg.temperature = 0.4238577046526424; + msg.depth = 0.4845285090210023; try { @@ -2102,14 +2120,14 @@ main(void) { IMC::HistoricCTD msg; - msg.setTimeStamp(0.489838113319); - msg.setSource(35649U); - msg.setSourceEntity(75U); - msg.setDestination(7536U); - msg.setDestinationEntity(64U); - msg.conductivity = 0.62943904852; - msg.temperature = 0.46222812938; - msg.depth = 0.885249387628; + msg.setTimeStamp(0.2555142270771772); + msg.setSource(88U); + msg.setSourceEntity(11U); + msg.setDestination(15652U); + msg.setDestinationEntity(241U); + msg.conductivity = 0.7219732662447107; + msg.temperature = 0.8201293634697651; + msg.depth = 0.549210042414635; try { @@ -2128,16 +2146,16 @@ main(void) { IMC::HistoricTelemetry msg; - msg.setTimeStamp(0.328967549031); - msg.setSource(27989U); - msg.setSourceEntity(99U); - msg.setDestination(58194U); - msg.setDestinationEntity(156U); - msg.altitude = 0.424348734278; - msg.roll = 23180U; - msg.pitch = 20942U; - msg.yaw = 39246U; - msg.speed = 18302; + msg.setTimeStamp(0.14852906208522398); + msg.setSource(6016U); + msg.setSourceEntity(66U); + msg.setDestination(31683U); + msg.setDestinationEntity(3U); + msg.altitude = 0.03523689139131203; + msg.roll = 44273U; + msg.pitch = 54531U; + msg.yaw = 5472U; + msg.speed = -2267; try { @@ -2156,16 +2174,16 @@ main(void) { IMC::HistoricTelemetry msg; - msg.setTimeStamp(0.851686800464); - msg.setSource(46758U); - msg.setSourceEntity(25U); - msg.setDestination(3844U); - msg.setDestinationEntity(138U); - msg.altitude = 0.738556360205; - msg.roll = 25783U; - msg.pitch = 29447U; - msg.yaw = 62046U; - msg.speed = -7410; + msg.setTimeStamp(0.9401389229586694); + msg.setSource(25859U); + msg.setSourceEntity(185U); + msg.setDestination(27775U); + msg.setDestinationEntity(176U); + msg.altitude = 0.3484694587018353; + msg.roll = 47287U; + msg.pitch = 31276U; + msg.yaw = 14997U; + msg.speed = 9432; try { @@ -2184,16 +2202,16 @@ main(void) { IMC::HistoricTelemetry msg; - msg.setTimeStamp(0.338153756665); - msg.setSource(3443U); - msg.setSourceEntity(120U); - msg.setDestination(54824U); - msg.setDestinationEntity(170U); - msg.altitude = 0.754434766063; - msg.roll = 43079U; - msg.pitch = 17006U; - msg.yaw = 14874U; - msg.speed = 26818; + msg.setTimeStamp(0.3291218960920932); + msg.setSource(27686U); + msg.setSourceEntity(138U); + msg.setDestination(12012U); + msg.setDestinationEntity(175U); + msg.altitude = 0.6378442209656381; + msg.roll = 50150U; + msg.pitch = 31955U; + msg.yaw = 4039U; + msg.speed = 1346; try { @@ -2212,18 +2230,18 @@ main(void) { IMC::HistoricSonarData msg; - msg.setTimeStamp(0.713492506095); - msg.setSource(16104U); - msg.setSourceEntity(87U); - msg.setDestination(47096U); - msg.setDestinationEntity(160U); - msg.altitude = 0.578461170177; - msg.width = 0.808627575515; - msg.length = 0.0324541670288; - msg.bearing = 0.763383507975; - msg.pxl = 593; - msg.encoding = 11U; - const char tmp_msg_0[] = {89, -39, -49, 85, 120, 104, -126, 21, -31, 46, -40, -30, -60, 50, 125, -66, -123, 99, -105, -115, 115, 44, 70, -73, -72, 5, 11, -70, -99, 2, -93, -97, -32, 112, 99, 80, -9, -43, -96, 34, 68, -59, -74, 115, 29, 14, 61, -60, -75, 3, 28, -61, -68, 107, -33, 117, 81, -13, -96, -108, 2, -58, 19, 106, -101, -29, -49, -56, 83, 11, 41, -82, -100, 25, -1, 114, 31, 89, -5, 64, 117, -37, -71, -80, -86, -14, 104, -18, -73, 90, -8, 7, -107, -13, -13, -27, 16, 47, 117, -113, 63, 81, -43, -84, 46, 64, -60, -11, -92, -9, -46, 52, -3, 43, 78, -61, 49, 59, 40, -1, -92, 37, -35, 74, -121, -63, 90, -33, -16, -58, 48, -19, -91, -90, -86, -16, -45, 1, -17, -59, -41, 99, -71, 107, -21, -22, 54, -65, -9, 16, -120, -95, -55, 34, -114, -28, -102, 122, 120, -127, 90, 102, 75, 104, -94, -63, 117, -17, -44, 62, 123, 4, 41, 84, -5, -14, -73, 66, 27, -56, 59, 18, -49, 101, -50, -69, 96, 50, -122, 25, -75, 55, -106, -32, 58, 104, -124, 61, 94, 83, -104, 46, -37, 32, -100, -33, 14, 116, -120, 82, -29, 92}; + msg.setTimeStamp(0.23002856676352113); + msg.setSource(47842U); + msg.setSourceEntity(107U); + msg.setDestination(709U); + msg.setDestinationEntity(57U); + msg.altitude = 0.675738256866477; + msg.width = 0.19063124517515562; + msg.length = 0.10598344669670656; + msg.bearing = 0.8728459778570672; + msg.pxl = -19239; + msg.encoding = 225U; + const signed char tmp_msg_0[] = {-107, -116, 83, 37, -83, 61, -18, -90, -57, 99, 31, -16, -10, -97, 124, -81, -16, -29, 102, -15, -65, -27, -6, -10, 48, 109, 42, 74, 78, 53, 117, -67, -16, 68, -68, -73, 121, -77, 8, -35, 39, 68, 28, 80, 18, 111, 112, 105, -94, 94, -72, 22, -51, 31, -122, -16, 72, 96, 73, 73, 78, 81, -44, 33, -85, 125, 114, -1, -103, -37, 58, -98, -5, 106, -110, -72, -124, -43, -40, 112, -104, -58, 126, 87, 15, 19, 91, 40, -110, -15, 86, 112, 62, -74, 30, 55, 15, 119, -94, 35, 91, 19, -1, 96, -39, 100, -93, -78, -11, 88, 37, 107, 52, 40, -44, -107, -80, -35, -56, 19, -55, 18, 29, 4, 65, -76, -100, 70, -110, -56, 39, -78, 114, -27, 59, 61, -124, 44, 17, 0, -85, -102, -73, -34, 0, 103, 118}; msg.sonar_data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -2243,18 +2261,18 @@ main(void) { IMC::HistoricSonarData msg; - msg.setTimeStamp(0.846439819281); - msg.setSource(65221U); - msg.setSourceEntity(51U); - msg.setDestination(44884U); - msg.setDestinationEntity(0U); - msg.altitude = 0.393035263333; - msg.width = 0.175488462873; - msg.length = 0.626022562211; - msg.bearing = 0.498044284055; - msg.pxl = -3413; - msg.encoding = 164U; - const char tmp_msg_0[] = {109, 112, 29, 94, -81, -7, 56, 115, 102, 80, -3, -63, 47, -3, -65, -9, 70, -59, 124, -49, 123, 42, 30, 72, -28, -63, -126, -36, 9, -19, -103, 12, -40, -42, -33, -46, -81, 69, -78, 111, 70, 110, 49, 22, 78, 85, 110, 61, 100, 87, -57, -23, 124, -55, -53, -25, 66, -33, 10, -3, -75, -2, 17, -5, -118, 48, -46, 34, 9, -35, -27, -21, 37, 24, 81, 109, -33, -26, -115, -4, -56, -125, -9, -63, -49, 3, 5, -92, -6, -86, -103, -37, 39, 40, 22, -39, 101, 117, -35, -116, 65, -26, -55, -47, 64, 62, 126, 118, 89, -67, 49, 17, -4, -122, -71, -83, 78, -14, -103, 63, 81, 33, 37, -44, 31, -64}; + msg.setTimeStamp(0.45006802013120906); + msg.setSource(9475U); + msg.setSourceEntity(136U); + msg.setDestination(14192U); + msg.setDestinationEntity(239U); + msg.altitude = 0.5093366156379585; + msg.width = 0.08201408464572935; + msg.length = 0.6965088856488689; + msg.bearing = 0.6517197457282067; + msg.pxl = -18064; + msg.encoding = 127U; + const signed char tmp_msg_0[] = {94, -101, 66, -106, 33, 32, -82, 118, -22, -88, -120, -72, 89, 27, 97, -38, 124, 123, 93, -64, 48, 16, -41, -7, -46, 56, 111, -71, 101, -51, -99, -78, 113, -42, -61, -12, 118, 40, 113, 71, 10, 20, 4, 10, 8, 15, -25, -118, 56, 39, 55, -23, -99, -14, -41, 5, 22, -93, -76, 48, 29, -29, -25, 78, 93, -103, -70, -35, 123, -24, 52, 112, -51, -9, 103, 17, -35, 120, -116, -3, 26, 13, -78, 119, -59, 56, -119, -47, -72, 103, 92, 21, -12, 15, 45, 37, -108, -47, -19, -53, 115, -90, 32, 49, 1, -40, -10, -120, 3, -97, -18, -110, -79, 95, -47, -34, -59, 113, -126, 55, -11, -103}; msg.sonar_data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -2274,18 +2292,18 @@ main(void) { IMC::HistoricSonarData msg; - msg.setTimeStamp(0.146845352083); - msg.setSource(64578U); - msg.setSourceEntity(40U); - msg.setDestination(31742U); - msg.setDestinationEntity(237U); - msg.altitude = 0.708286952476; - msg.width = 0.109962841518; - msg.length = 0.4570061783; - msg.bearing = 0.538554331562; - msg.pxl = -21668; - msg.encoding = 179U; - const char tmp_msg_0[] = {-11, -42, -103, -60, -12, 95, 116, 79, 50, -121, -1, -95, -125, -3, -99, -1, 112, -109, -7, -103, -34, 92, 44, -16, 64, 35, -119, -43, 107, 115, 104, -84, 52, 80, 30, -49, -119, 98, 85, -114, -74, 110, -34, 30, 16, 78, -66, 20, -8, -45, -52, -36, -88, -33, 101, 107, 16, -91, -93}; + msg.setTimeStamp(0.34184470103134246); + msg.setSource(57270U); + msg.setSourceEntity(47U); + msg.setDestination(51865U); + msg.setDestinationEntity(54U); + msg.altitude = 0.17312276661918402; + msg.width = 0.10714871188689934; + msg.length = 0.1887266575010106; + msg.bearing = 0.2347742635485317; + msg.pxl = 28892; + msg.encoding = 161U; + const signed char tmp_msg_0[] = {-89, 41, -128, -12, 64, -19, -2, -124, 100, 58, -97, 64, -108, -62, 29, 103, -26, 1, 76, 72, -88, 71, -99, 69, -24, 44, 83, 16, 14, -58, 28, -124, 61, 11, -55, -107, 92, -17, 50, 8, 42, -24, -89, 101, -5, 108, 115, 31, -7, -20, 49, 108, -10, -108, -106, 95, 37, -75, 54, -63, 24, -82, 23, 80, 56, 114, -128, -50, 0, 64, -83, -49, 108, -99, -103, -1, -111, 20, -70, 97, 10, -106, -111, 44, -51, -30, -27, 119, 102, 95, -33, -66, 16, 102, 6, -90, 86, -62, -13, 102, -122, -7, 69, -77, -106, -76, -35, -15, -33, 105, -10, -120, -38, -103, 53, 44, 118, -81, -52, -100, -59, -52, 74, 10, -68, 75, 34, -21, -56, 122, -68, 46, 109, 12, -72, 47, 53, 113, -74, 81, 51, 85, -17, -41, 46, -81, 118, -108, -128, -34, -51, -74, -61, -54, 95, 41, -61, 10, 57, 117, -28, -93, -63, -62, 64, 5, 8, 5, -127, -115, -73, 126, 51, 113, 31, -89, 19, -83}; msg.sonar_data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -2305,13 +2323,13 @@ main(void) { IMC::HistoricEvent msg; - msg.setTimeStamp(0.948817242337); - msg.setSource(41291U); - msg.setSourceEntity(242U); - msg.setDestination(164U); - msg.setDestinationEntity(120U); - msg.text.assign("WTEMOQDCOUSIDYRPOTLAPOVXZHUGAYJAYCJPGUIWXFOBCAXJHLAWDZELQMUVWUKEPUQTELICQAIECTJAKQYLYMMPHGKSBWYYHIJNNFQQRMAHWBJMOQGSPKNOFVNRKZEDNWCJXXFKTETUXZSRFQVGFXBVRSHZDFCYMNLDSNKXMDKSDHHY"); - msg.type = 10U; + msg.setTimeStamp(0.021393199547966923); + msg.setSource(4768U); + msg.setSourceEntity(18U); + msg.setDestination(30153U); + msg.setDestinationEntity(105U); + msg.text.assign("MUWDCERKCXAWKRKOQDSBRXUIABGMTWLPXLSWPLYXXRWARFMTZERJLZLWBHBQPCJXFYIEWLTKJMDUKCTDZWSUPZIJGFIKZIMOODKVJQIXJVXVNYOOVLZIQRFLYRVFHGEOPBZ"); + msg.type = 109U; try { @@ -2330,13 +2348,13 @@ main(void) { IMC::HistoricEvent msg; - msg.setTimeStamp(0.456157595114); - msg.setSource(53549U); - msg.setSourceEntity(156U); - msg.setDestination(5761U); - msg.setDestinationEntity(217U); - msg.text.assign("ZVIXSPICWBAGMVOLHGNHBYGFVQDKCFHRWGISRYQJDFEUVKDTQDKYTOOGKYYRJWAUHVZECEAFECZFTHQGZEZVXMMCBVUTGLTTLUTCGSIDZUNWAMZCKKSAPPYVXPKAGLWYORZEMPUFRABJNIOQNMASXJEMSDBUDXRBAGWQNNIZEBFNFLFRYBHJSLXMYJKBLNHXN"); - msg.type = 216U; + msg.setTimeStamp(0.2024816585953897); + msg.setSource(53496U); + msg.setSourceEntity(62U); + msg.setDestination(24471U); + msg.setDestinationEntity(38U); + msg.text.assign("WSUXBPZLJYLFELYPQRFVJRDNODFMDFGHWIZTNGEXNOTDDHVGQGXMPQGQDTQEVHBPSYURKJEKHAIMCJMMCHBIQXOZKTLKFCPWMPKXJVOFTYXZQXLWOBNIFUMVQBAGFJRHSXOYEUGE"); + msg.type = 2U; try { @@ -2355,13 +2373,13 @@ main(void) { IMC::HistoricEvent msg; - msg.setTimeStamp(0.617220855948); - msg.setSource(10710U); - msg.setSourceEntity(96U); - msg.setDestination(21694U); - msg.setDestinationEntity(15U); - msg.text.assign("QCVSVFGGMPTOFSQFWHSDCVNKUZYKFWYCJSSANWNHZLGIBPKDQHIA"); - msg.type = 59U; + msg.setTimeStamp(0.32079761006757523); + msg.setSource(39944U); + msg.setSourceEntity(49U); + msg.setDestination(35611U); + msg.setDestinationEntity(94U); + msg.text.assign("ISAFOXWPSDZRQINRKKZOSEIKZRGQZYBSCAADORLKWHTJGLXMVJXSRSMVPDNCNLBDRVZUFJFTAPOMNBKYUJROMSNTYZNBVCZTHGYCRQFUAEFQHDIPVGPEWUDTBXWUKMQZBHLEWLAPMTKHUWGZKJTXWIXHLTYFDSIJNCJQKTDSZXOUCOHHWYECYQJPYBMPJVVGSDBGQFLLAJUGBXXAU"); + msg.type = 25U; try { @@ -2379,19 +2397,23 @@ main(void) } { - IMC::Heartbeat msg; - msg.setTimeStamp(0.226112503117); - msg.setSource(26056U); - msg.setSourceEntity(33U); - msg.setDestination(35123U); - msg.setDestinationEntity(237U); + IMC::VerticalProfile msg; + msg.setTimeStamp(0.3043112245942934); + msg.setSource(49719U); + msg.setSourceEntity(220U); + msg.setDestination(41471U); + msg.setDestinationEntity(134U); + msg.parameter = 248U; + msg.numsamples = 154U; + msg.lat = 0.8417044353399091; + msg.lon = 0.6194152113877547; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Heartbeat #0", msg == *msg_d); + test.boolean("VerticalProfile #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2402,19 +2424,23 @@ main(void) } { - IMC::Heartbeat msg; - msg.setTimeStamp(0.746738167585); - msg.setSource(39968U); - msg.setSourceEntity(241U); - msg.setDestination(11767U); - msg.setDestinationEntity(56U); + IMC::VerticalProfile msg; + msg.setTimeStamp(0.5664357706382073); + msg.setSource(26528U); + msg.setSourceEntity(131U); + msg.setDestination(42653U); + msg.setDestinationEntity(138U); + msg.parameter = 194U; + msg.numsamples = 71U; + msg.lat = 0.7933106958744012; + msg.lon = 0.33415406194784825; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Heartbeat #1", msg == *msg_d); + test.boolean("VerticalProfile #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2425,19 +2451,23 @@ main(void) } { - IMC::Heartbeat msg; - msg.setTimeStamp(0.710002432481); - msg.setSource(323U); - msg.setSourceEntity(34U); - msg.setDestination(48463U); - msg.setDestinationEntity(103U); + IMC::VerticalProfile msg; + msg.setTimeStamp(0.19928675920312333); + msg.setSource(41458U); + msg.setSourceEntity(165U); + msg.setDestination(64824U); + msg.setDestinationEntity(183U); + msg.parameter = 51U; + msg.numsamples = 57U; + msg.lat = 0.6107434247067253; + msg.lon = 0.31929901773024394; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Heartbeat #2", msg == *msg_d); + test.boolean("VerticalProfile #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2448,26 +2478,21 @@ main(void) } { - IMC::Announce msg; - msg.setTimeStamp(0.683034461971); - msg.setSource(14012U); - msg.setSourceEntity(72U); - msg.setDestination(49325U); - msg.setDestinationEntity(200U); - msg.sys_name.assign("OIIZVZWLRNIEAOOLFPRTVWHRTKQSCPAKWIGFVFMQJJBIMDAQWHWUUZIUKMYRXGUYMYZIJEVPHJPCXGKXLLNBWSHALXYKUCQNROSYAGMADTJQNWNVCIWLMHTVVTOXRUUULAPODHXCLUZQTGCGEMZVFNEJBZPCOMXXOHTBKBJSKAQFGYXSE"); - msg.sys_type = 33U; - msg.owner = 22460U; - msg.lat = 0.409046147195; - msg.lon = 0.105428976079; - msg.height = 0.687042208002; - msg.services.assign("ULDLKLEBMEFFHRGDPKVMPDTQCYJZDUPLRCVPEKSFISJWCXRVYFLCMIWDRNTEQAJGFPNFJAOGDAOAQXZSUIGHVRSSWHHXXGRBHXVWBZKJPOTOIUGESUYRXNDFMBJHHJLSWTATZVCZCNNYOFPTQVNQRYWYECKSLJWBGBUZGOVHOUWDBWJXABETKKDMFTNQWSXEIPYQUCAMMOAIVCHYMNQHOBKIKAXZAIXGMOLEIRTFUNQLUTNVPPRQZ"); + IMC::ProfileSample msg; + msg.setTimeStamp(0.6409462688884179); + msg.setSource(15497U); + msg.setSourceEntity(191U); + msg.setDestination(41266U); + msg.setDestinationEntity(98U); + msg.depth = 64473U; + msg.avg = 0.0966141834747214; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Announce #0", msg == *msg_d); + test.boolean("ProfileSample #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2478,26 +2503,21 @@ main(void) } { - IMC::Announce msg; - msg.setTimeStamp(0.336811107399); - msg.setSource(1967U); - msg.setSourceEntity(214U); - msg.setDestination(45360U); - msg.setDestinationEntity(90U); - msg.sys_name.assign("YPRFUOKHEFWUCUBWESRTSRYGTVAZGKNJJJCYLJSOFYPWGVRGKXUTWCNHDSBOQQAGCDOBLVFUZWAXBBONTCVBHKKKEU"); - msg.sys_type = 203U; - msg.owner = 7270U; - msg.lat = 0.149531430781; - msg.lon = 0.709501114074; - msg.height = 0.812636991696; - msg.services.assign("YAEURNZXUJMASKNFYHFWECNSUXZZYOZQJRLONPTSBRRXWWTOGVPXUWVGIHGKWHTFZHACJQHOHCB"); + IMC::ProfileSample msg; + msg.setTimeStamp(0.34725387183374945); + msg.setSource(35505U); + msg.setSourceEntity(50U); + msg.setDestination(64236U); + msg.setDestinationEntity(160U); + msg.depth = 2463U; + msg.avg = 0.7493931634429444; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Announce #1", msg == *msg_d); + test.boolean("ProfileSample #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2508,26 +2528,21 @@ main(void) } { - IMC::Announce msg; - msg.setTimeStamp(0.90092653162); - msg.setSource(24455U); - msg.setSourceEntity(24U); - msg.setDestination(5262U); - msg.setDestinationEntity(123U); - msg.sys_name.assign("LPGWBNMKPODTHELPSQYQTPXNRLFFVEXADTNAGBHXZQFJARGGGPIYPEMGQTKCXVRTZQQJHEYAWUYHFUIHYGXZYHBEKKAWWFTOLZBERAJXZLWHJLZIVCTBJFSDFCVRKOCNACAXGJTKVSWBPJVXMUUCFPGIJUSJUDMIVMJNZUMQIELCHSGYDMUEQLOSZPFDQHBWUFYSOUDIWKNOMMNN"); - msg.sys_type = 240U; - msg.owner = 17009U; - msg.lat = 0.122156687597; - msg.lon = 0.97569044099; - msg.height = 0.982731846766; - msg.services.assign("DEUBNCDOHNATQRRVVPEDNFRVZOUQWOXQOQQGFALAZPVEFQVRCVUSOZJNHMMWDMNASJYBTWYKIKVFMWNKJCIDOKTNCGEYHGIBGQNEQSKMLGCTRIUJFKSYUOZLIXZVOLMSJCQFLNKPBUCZHYXZBDAMPRIXXWHUZNBVGIGTBBHBGUOLWJHAPKSUWDTWHAIFXVJELLRZIREYECOKPTMTKRDYUCFJXJRSSAXHDLSMAB"); + IMC::ProfileSample msg; + msg.setTimeStamp(0.8164779346898359); + msg.setSource(35308U); + msg.setSourceEntity(126U); + msg.setDestination(10223U); + msg.setDestinationEntity(207U); + msg.depth = 5834U; + msg.avg = 0.9031884008861067; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Announce #2", msg == *msg_d); + test.boolean("ProfileSample #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2538,21 +2553,19 @@ main(void) } { - IMC::AnnounceService msg; - msg.setTimeStamp(0.128071622801); - msg.setSource(27504U); - msg.setSourceEntity(231U); - msg.setDestination(56933U); - msg.setDestinationEntity(91U); - msg.service.assign("QVRGDFTQKJJZBQHQPCKVSKGBPGBBPSZHBVQBAPRLSUDNRLZBCUGWCA"); - msg.service_type = 208U; + IMC::Heartbeat msg; + msg.setTimeStamp(0.30653990635383954); + msg.setSource(4923U); + msg.setSourceEntity(206U); + msg.setDestination(26238U); + msg.setDestinationEntity(3U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AnnounceService #0", msg == *msg_d); + test.boolean("Heartbeat #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2563,21 +2576,19 @@ main(void) } { - IMC::AnnounceService msg; - msg.setTimeStamp(0.877340160702); - msg.setSource(50527U); - msg.setSourceEntity(14U); - msg.setDestination(28281U); - msg.setDestinationEntity(106U); - msg.service.assign("BARSMXCXFQCJVTFXVKTYXLRVORHBKMNBPFHGZGJCYHRMWLSSAZNDGSCWUOJAGH"); - msg.service_type = 86U; + IMC::Heartbeat msg; + msg.setTimeStamp(0.3505760703794941); + msg.setSource(11814U); + msg.setSourceEntity(215U); + msg.setDestination(4664U); + msg.setDestinationEntity(238U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AnnounceService #1", msg == *msg_d); + test.boolean("Heartbeat #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2588,21 +2599,19 @@ main(void) } { - IMC::AnnounceService msg; - msg.setTimeStamp(0.0776658039469); - msg.setSource(31246U); - msg.setSourceEntity(104U); - msg.setDestination(49292U); - msg.setDestinationEntity(251U); - msg.service.assign("SXSFBUHYQJMALUAIBXTGWLTJNOLNMROBOADSCQYCDIBKIVGUADXFMCLXHDBLRIQUFKPZBWPMQPYYXNSTPYTCKVWKZNGNLHGGBMHXKFRLKDDIXTIADPWYKYGWZWZ"); - msg.service_type = 122U; + IMC::Heartbeat msg; + msg.setTimeStamp(0.7348227831239218); + msg.setSource(26874U); + msg.setSourceEntity(55U); + msg.setDestination(48925U); + msg.setDestinationEntity(77U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AnnounceService #2", msg == *msg_d); + test.boolean("Heartbeat #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2613,20 +2622,26 @@ main(void) } { - IMC::RSSI msg; - msg.setTimeStamp(0.994939712724); - msg.setSource(14899U); - msg.setSourceEntity(214U); - msg.setDestination(6503U); - msg.setDestinationEntity(6U); - msg.value = 0.741220525349; + IMC::Announce msg; + msg.setTimeStamp(0.4809172053070718); + msg.setSource(7088U); + msg.setSourceEntity(208U); + msg.setDestination(62597U); + msg.setDestinationEntity(57U); + msg.sys_name.assign("FGMJHIXVJECKWJQQTLZXBTSONRXVBMGHXURUPURZQTZHZFZOFWASLYBLURLXJXBKCECNIWDDVBHYLYRDXUMPNXFSPFCKNTLDFPHOPDOZYBEYGSHGPVEILHRTKEQNFFCATRDFBZEKZMBSYRODAPPJCWIKAHOA"); + msg.sys_type = 81U; + msg.owner = 13771U; + msg.lat = 0.3420203840880619; + msg.lon = 0.38833846156618956; + msg.height = 0.02638227095312473; + msg.services.assign("EKBBMZVLRTQQRGEYDTMNPWFEABNWSHICKNMDHKAYPDOYJGJZHCWIOTTJUFSUOTPFYSXFTESLNDFKYXRDNNQBVNWVOFOMBPDVCKTWARFXBATTRCOUJLLOQGZFPWLOHXUACIRCIOYGLCWAAAJEEPIHOUCIUQDZLQSJHMKBVGKRXZMXTZVFGSZBXXILQXAWSVKQ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RSSI #0", msg == *msg_d); + test.boolean("Announce #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2637,20 +2652,26 @@ main(void) } { - IMC::RSSI msg; - msg.setTimeStamp(0.852187213051); - msg.setSource(61355U); - msg.setSourceEntity(186U); - msg.setDestination(53089U); - msg.setDestinationEntity(61U); - msg.value = 0.459925994774; + IMC::Announce msg; + msg.setTimeStamp(0.4597458326135676); + msg.setSource(12023U); + msg.setSourceEntity(232U); + msg.setDestination(16613U); + msg.setDestinationEntity(248U); + msg.sys_name.assign("DUKVVGKLDGYCXZXTGLTPHLVKXPZVSNVPTJRBHDOUAXIKLSSTACSHKIBAJHJGTOEQJOIOCILBXTLXZGGNKWQZCRUYZHQUENREQQGBSUMEAPMWAFWRBVAIJKABPFNU"); + msg.sys_type = 40U; + msg.owner = 52837U; + msg.lat = 0.06109207243129866; + msg.lon = 0.9604474673554453; + msg.height = 0.9088322187930871; + msg.services.assign("RTAZPBFHVHYQISJWVVXLPSENCCLJSSJQIMNRGKIDQTN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RSSI #1", msg == *msg_d); + test.boolean("Announce #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2661,20 +2682,26 @@ main(void) } { - IMC::RSSI msg; - msg.setTimeStamp(0.122695583015); - msg.setSource(57314U); - msg.setSourceEntity(251U); - msg.setDestination(23185U); - msg.setDestinationEntity(247U); - msg.value = 0.11876637809; + IMC::Announce msg; + msg.setTimeStamp(0.6750115350770174); + msg.setSource(7390U); + msg.setSourceEntity(158U); + msg.setDestination(7321U); + msg.setDestinationEntity(53U); + msg.sys_name.assign("PNTIZWEASCSDGAUCXVPRTVYYWXJHJQKDJXFXFB"); + msg.sys_type = 208U; + msg.owner = 41166U; + msg.lat = 0.9873132444397702; + msg.lon = 0.634258336419589; + msg.height = 0.3006471849882433; + msg.services.assign("OHOHYGOOMKPWLRBXIKMSERYAKPIEXHPJRAYAYTSBXTXJOOCATYVUBIFYJGNHZXNKNVLAHWQZLHVEMVDHUSQKGQWWQLZGEIKWYTZCIHGPHCNACFBMIIAJDBEPKFSAITDRSHKNSWEPACDLMFJXJERRZWOJPLXWFCSDDMKQMQUB"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RSSI #2", msg == *msg_d); + test.boolean("Announce #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2685,20 +2712,21 @@ main(void) } { - IMC::VSWR msg; - msg.setTimeStamp(0.784819378677); - msg.setSource(38393U); - msg.setSourceEntity(232U); - msg.setDestination(61872U); - msg.setDestinationEntity(197U); - msg.value = 0.975042885083; + IMC::AnnounceService msg; + msg.setTimeStamp(0.35761761921262547); + msg.setSource(57403U); + msg.setSourceEntity(226U); + msg.setDestination(8216U); + msg.setDestinationEntity(213U); + msg.service.assign("POIWKRPFTSLJHLYWMBLGMVSAZZLNVODDXGNKEBCXKDTGEOGTDUOYEEPUHYTMRJMBLWJXBAKUUXIPNZUNQOECIVMEVTI"); + msg.service_type = 191U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VSWR #0", msg == *msg_d); + test.boolean("AnnounceService #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2709,20 +2737,21 @@ main(void) } { - IMC::VSWR msg; - msg.setTimeStamp(0.752367921203); - msg.setSource(13580U); - msg.setSourceEntity(187U); - msg.setDestination(42021U); - msg.setDestinationEntity(72U); - msg.value = 0.775845572355; + IMC::AnnounceService msg; + msg.setTimeStamp(0.829910626919996); + msg.setSource(14836U); + msg.setSourceEntity(154U); + msg.setDestination(7769U); + msg.setDestinationEntity(226U); + msg.service.assign("WJCDRNUCIOSQKAPZEVIFFDPDALHZHNYSPPZSSLATSZVWGHCAWBMQEYVIKTVUXQLTFICVFWMHQBVGYDDFTZBROXILQYTDNEFPEXNRYEOJFEARJMKPYGLAMIVYQGCXWOMFKQEYDQNHAMGYCSICOBXAERGDCXKJKJIFBDTRNOOQMUZXUUTHSUKRPAFUMVIBNZ"); + msg.service_type = 138U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VSWR #1", msg == *msg_d); + test.boolean("AnnounceService #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2733,20 +2762,21 @@ main(void) } { - IMC::VSWR msg; - msg.setTimeStamp(0.341767034641); - msg.setSource(24973U); - msg.setSourceEntity(169U); - msg.setDestination(39018U); - msg.setDestinationEntity(250U); - msg.value = 0.453331807216; + IMC::AnnounceService msg; + msg.setTimeStamp(0.6846625593428846); + msg.setSource(44062U); + msg.setSourceEntity(58U); + msg.setDestination(64688U); + msg.setDestinationEntity(216U); + msg.service.assign("MRHXAWUIMXQLJYBWWDGHBFATWSDISVGNPGNOERALTKRFQPNBNNNWSYTDWSJVPKXQKDCLDFEDCAKTVBJTZGOLZMFJ"); + msg.service_type = 82U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VSWR #2", msg == *msg_d); + test.boolean("AnnounceService #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2757,20 +2787,20 @@ main(void) } { - IMC::LinkLevel msg; - msg.setTimeStamp(0.304392265463); - msg.setSource(46965U); - msg.setSourceEntity(97U); - msg.setDestination(52169U); - msg.setDestinationEntity(64U); - msg.value = 0.991763172663; + IMC::RSSI msg; + msg.setTimeStamp(0.9062374181837335); + msg.setSource(52102U); + msg.setSourceEntity(74U); + msg.setDestination(62834U); + msg.setDestinationEntity(76U); + msg.value = 0.2814813535504026; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LinkLevel #0", msg == *msg_d); + test.boolean("RSSI #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2781,20 +2811,20 @@ main(void) } { - IMC::LinkLevel msg; - msg.setTimeStamp(0.772802061014); - msg.setSource(49354U); - msg.setSourceEntity(236U); - msg.setDestination(16864U); - msg.setDestinationEntity(59U); - msg.value = 0.42728863239; + IMC::RSSI msg; + msg.setTimeStamp(0.2233778943984086); + msg.setSource(26365U); + msg.setSourceEntity(9U); + msg.setDestination(27455U); + msg.setDestinationEntity(71U); + msg.value = 0.2587845613900861; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LinkLevel #1", msg == *msg_d); + test.boolean("RSSI #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2805,20 +2835,20 @@ main(void) } { - IMC::LinkLevel msg; - msg.setTimeStamp(0.393981584518); - msg.setSource(23390U); - msg.setSourceEntity(205U); - msg.setDestination(34592U); - msg.setDestinationEntity(0U); - msg.value = 0.1887912403; + IMC::RSSI msg; + msg.setTimeStamp(0.8077893123071515); + msg.setSource(6588U); + msg.setSourceEntity(17U); + msg.setDestination(59761U); + msg.setDestinationEntity(19U); + msg.value = 0.8429720520178613; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LinkLevel #2", msg == *msg_d); + test.boolean("RSSI #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2829,22 +2859,166 @@ main(void) } { - IMC::Sms msg; - msg.setTimeStamp(0.430838565658); - msg.setSource(54614U); - msg.setSourceEntity(94U); - msg.setDestination(46308U); - msg.setDestinationEntity(123U); - msg.number.assign("MEKLGOLCXUIZJZQTKPGFVJBGDWTIRAMIDYCESHRAJCECCOXGZDVCUFBDWQNEMYXJSVFHPYBAOFVQKRHHOIWTLIMGIRFNZDNNTDHPGTNPWKUQVMEYQCCZLEPBWBJXABHIXOBGEVIDZDSPLHOKPLLPRBGWMXOKFVUSTSLLQXEBEFNWUVGWQCPHFAMORRTNYYYXFVYAURUXHKD"); - msg.timeout = 14592U; - msg.contents.assign("GEDDFPXQHDNSOFAAEHSQMFNRVZAYLUXCX"); + IMC::VSWR msg; + msg.setTimeStamp(0.023273969500654967); + msg.setSource(28709U); + msg.setSourceEntity(43U); + msg.setDestination(8360U); + msg.setDestinationEntity(163U); + msg.value = 0.33131456429779793; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Sms #0", msg == *msg_d); + test.boolean("VSWR #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::VSWR msg; + msg.setTimeStamp(0.2607748868087747); + msg.setSource(35280U); + msg.setSourceEntity(48U); + msg.setDestination(9885U); + msg.setDestinationEntity(244U); + msg.value = 0.443369191100598; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("VSWR #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::VSWR msg; + msg.setTimeStamp(0.8399445011778337); + msg.setSource(61893U); + msg.setSourceEntity(236U); + msg.setDestination(15388U); + msg.setDestinationEntity(247U); + msg.value = 0.5571744908788199; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("VSWR #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::LinkLevel msg; + msg.setTimeStamp(0.1296561013027654); + msg.setSource(42203U); + msg.setSourceEntity(110U); + msg.setDestination(786U); + msg.setDestinationEntity(72U); + msg.value = 0.5345243305174562; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("LinkLevel #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::LinkLevel msg; + msg.setTimeStamp(0.3430951752774606); + msg.setSource(4878U); + msg.setSourceEntity(5U); + msg.setDestination(27679U); + msg.setDestinationEntity(47U); + msg.value = 0.021618136960678602; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("LinkLevel #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::LinkLevel msg; + msg.setTimeStamp(0.13700186159005057); + msg.setSource(60056U); + msg.setSourceEntity(142U); + msg.setDestination(1369U); + msg.setDestinationEntity(41U); + msg.value = 0.45995703960103285; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("LinkLevel #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Sms msg; + msg.setTimeStamp(0.7263664666808205); + msg.setSource(46153U); + msg.setSourceEntity(160U); + msg.setDestination(62082U); + msg.setDestinationEntity(135U); + msg.number.assign("HWCPCOOOQGSPBZCYDWRQHESKLLZEXEQTAWXSYOWZIPNDAB"); + msg.timeout = 453U; + msg.contents.assign("HRBPCRWHTQECLNFBQCFNPIIZLXEMRIPUFSYTYCTHQTCASOESNLBWGBGYBLFEJRRH"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Sms #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -2856,14 +3030,14 @@ main(void) { IMC::Sms msg; - msg.setTimeStamp(0.379057102234); - msg.setSource(23482U); - msg.setSourceEntity(221U); - msg.setDestination(6675U); - msg.setDestinationEntity(112U); - msg.number.assign("ZHXKUQJLOGRREPRUYHQFFAUJPZWAJMPWOGAUBPKDZZQDVOIJXMBOHCRJBQJCXWASZWALRTHQHXREEMSZVKQSZLPXQBMGGLFBEXZMDKMGZTBGDWIFHGTNYLLFPKISNKYORQCCCCNVIVNNWYOHAASOMFEFUXEGLNBABIVOOUTYKDSMFTVIUCPYKBWTAPNENXWIFCYYTHJAXSNIOLTFGBTWYDLW"); - msg.timeout = 13836U; - msg.contents.assign("LQXDUJVCCPDABIGYADKSSREKFWBHHAJEJNIDMURIROXIYQEQGONBIMKICSGZEMDJIVJPSLVQUEZZJKTINTHXZUSWZMWCUWYDWMBNOBNTVCSYAEPBHXMUMPNARWSDAKUVOMTHVLARPYZNWYGWQXORNLOXTNQZEILKGUBGCVXAYOFMCBXGFKY"); + msg.setTimeStamp(0.44860963151739885); + msg.setSource(28527U); + msg.setSourceEntity(143U); + msg.setDestination(15500U); + msg.setDestinationEntity(104U); + msg.number.assign("BHECVZOOSYPNYVDIUZHOENMBHPJQ"); + msg.timeout = 5395U; + msg.contents.assign("CILULXSJKWZAKUFSMCFMGIOEGVGBQNJNSKKYAVLOEVMWHLMGUSWTADRVUJEMJCZYXHMZHYXDYUBQTZQQMJHIPYFQFKPIDSNKCEIYTBWDXWKFYZNZTRLKGEVCCVOZACDEGYGUUUTAQTOQURTISMBPYAIALEBFPXNILJMUVRCHIRJSWBOORMJHDHXWJIXXRAQPKPGTROZFGZH"); try { @@ -2882,14 +3056,14 @@ main(void) { IMC::Sms msg; - msg.setTimeStamp(0.556298932461); - msg.setSource(43437U); - msg.setSourceEntity(2U); - msg.setDestination(34044U); - msg.setDestinationEntity(138U); - msg.number.assign("TGNNAJYMSFYZRLQKHMAXZHJVVUZNFJPG"); - msg.timeout = 31881U; - msg.contents.assign("WFQJLKVHANYUUHCDLYDQILSRKSIWPBVGUSIJPGKYQXRDDWNRFKGOEPEGBYKCFWJABEIESHRFQMSZMQNSVDS"); + msg.setTimeStamp(0.7284967024712662); + msg.setSource(12286U); + msg.setSourceEntity(175U); + msg.setDestination(53620U); + msg.setDestinationEntity(117U); + msg.number.assign("LTDNYHOLTZHPEDGFQFCKDYQLPLBZBFYNZMAJBKLNHZYRHCQYXEUMGAXCSJGMEWCDUYFPILZTHPHOQZRUXGTUAERABZDKXVXVUQMRBYLSAVB"); + msg.timeout = 2791U; + msg.contents.assign("LWOYLPZCYMKVIFSJMYSDOOYTGJSWRQMYMMJTSGEEBGWIQLIKHELYTUDXOOTAIEYNVMYTQKHDRQXFEQACUAIYCPBHJZDWLTFPXZQJRWHQCENVAXNCHAPXSPEKBPXZTMVAWBUVVMKZUJLHUEERHJJKISNCJJNOIBHUYDGRTRHXBVNFZAGOXCZVFWGBLU"); try { @@ -2908,15 +3082,15 @@ main(void) { IMC::SmsTx msg; - msg.setTimeStamp(0.356141472379); - msg.setSource(37132U); - msg.setSourceEntity(68U); - msg.setDestination(55251U); - msg.setDestinationEntity(61U); - msg.seq = 2031137008U; - msg.destination.assign("WIRUJZINVTJRBPMPHWDZVPLLNMIYVRISLSXFZMCIBKQXBRMBWXTABHFVRVEG"); - msg.timeout = 55335U; - const char tmp_msg_0[] = {-96, 18, 14, -1, 20, 48, 10, -51, 44, -76, 23, -58, 98, -7, 12, -125, 38, -32, -54, -94, 9, 86, -18, 56, -100, 118, 87, -10, -103, -63, -65, -58, -89, 76, 49, -28, -50, -24, -128, 79, -9, 33, 43, 78, -102, -102, 110, 120, -108, -85, 60, -124, 97, 58, 8, -1, -66, 71, 33, 18, -7, 56, 50, 115, -100, 32, 13, -96, 85, 111, -123, -46, 68, -100, 116, 40, -85, 32, 7, 73, 93, 82, -121, 61, 34, 113, 0, 87, -3, -41, -43, -9, 34}; + msg.setTimeStamp(0.1282018160185716); + msg.setSource(25944U); + msg.setSourceEntity(153U); + msg.setDestination(35865U); + msg.setDestinationEntity(60U); + msg.seq = 267562276U; + msg.destination.assign("FJSUEPBCXXFDHSPIIMJXQOXYAOXCRCGXIFHPAUPLXSZEQAHDMWPQGGVLFJSIZNOIHVDJOKTKCQUAMTLFYBTACIZTZEQROFQSDSJHYZIZUCVTBNRKELEBNAJRONSXRBDULWYVBDROSFHWGTUUENRHKGGBNIGNYPJYPKNUQVTBDSTLYWQSYYMVVMZRDEKEBHUTLL"); + msg.timeout = 46202U; + const signed char tmp_msg_0[] = {-66, 74, -60, 94, -38, 35, 24, 19, 82, 59, -73, 16, -117, 86, -97, -127, -79, 122, -115, -60, -103, 39, 30, -121, -39, 65, -92, 96, -120, 121, 8, 25, -109, 126, 73, -63, 89, 97, 1, 79, 85, 109, 7, -65, -113, -95, -68, -98, 63, -120, 54, 103, 83, -35, 98, -85, -11, -60, 116, -94, 112, -50, -17, -3, -18, 52, 13, -93, -97, -95, -46, 53, 66, -89, 39, -123, 64, 24, 96, -78, 1, 57, 81, 87, 21, -87, -43, 115, 37, 121, 24, -79, 113, -38, 31, -16, -58, -61, -122, -42, -92, 85, 60, -68, -126, -28, 43, 92, -97, -102, 80, 71, -63, 67, -114, -90, 111, 101, 91, -7, 0, 104, -99, -77, -61, -5, 87, 19, -112, 87, -31, 5, 40, 99, 25, -95, -77, 15, 44, 15, 14, 113, 3, -125, -104, 119, -56, 28, 48, -105, 125, -51, 60, -126, -53, -44, 45, 48, 100, 53, -76, -37, 15, -54, 98, 88, 43, -48, -10, 50, 104, 100, -58, -11, -25, 86, 8, 65, -18, 18, 26, 47, 66, -47, 119, 103, -35, -109, -85, 119, 9, -67, 18, 70, -125, 9, -6, 39, -20, 22, 57, -126, 67}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -2936,15 +3110,15 @@ main(void) { IMC::SmsTx msg; - msg.setTimeStamp(0.989026377809); - msg.setSource(50470U); - msg.setSourceEntity(17U); - msg.setDestination(26267U); - msg.setDestinationEntity(129U); - msg.seq = 4074623881U; - msg.destination.assign("QYQSXFMFISQIBFVCSKEXTEHWVXESCMHDGZHEXWDFMWUYFAJYCLNURINOPGJUGPAHOARUPIFIIVGWHVOSRLUFVRYVAWNLVDRTGDRKIMBBYJLLUNWQZPVQXLJGJJOIPANMUHRKUGVXZXUDADOHXEPAZIBBKSQCYDZOCMJEZCRNKCNNWHTTOAQLWMPTBCCCZFSXQ"); - msg.timeout = 52368U; - const char tmp_msg_0[] = {40, 125, -37, 19, 89, -104, -114, 39, -46, 119, -120, 23, -91, -126, 41, -79, 103, 92, -20, -107, -63, -63, -7, -21, -89, 62, 44, 91, 20, 21, -115, -127, -86, -93, 94, -17, 13, -59, -55, -65, -83, 98, -125, -4, 25, -93, 67, 113, 122, -13, 93, -28, 54, 53, 71, -96, -121, 88, -5, 85, -9, 68, -128, 1, 107, 112, 30, -23, -16, 75, 110, 48, 111, 66, 88, 47, 123, -19, 61, 82, -88, -60, -64, 121, -86, 27, -22, 116, -22, 77, 45, 107, 19, -63, -113, 122, 66, 3, -28, -77, -41, 44, 16, -10, -110, -25, -53, 97, 99, -111, 103, 56, -50, -38, -72, -45, 100, 65, -53, -92, -31, -9, 80, 60, -81, 126, -76, -33, -123, 25, -52, -113, -36, 42, 79, -105, -50, -107, -12, -34, -83, 58, 102, -88, -60, 20, -62, -97, 27, -12, 110, 47, -117, 113, -107, -32, -122, 117, -60, 100, -8, 83, 25, -62, -26, -43, -38, -51, 87, 24, -122, -21, 21, -16, 47, 29, -84, -60, 23, -49, -4, -34, -112, 85, 94, 78, 97, -13, -22, -101, 39, -63}; + msg.setTimeStamp(0.8519625771128777); + msg.setSource(8646U); + msg.setSourceEntity(211U); + msg.setDestination(59467U); + msg.setDestinationEntity(237U); + msg.seq = 2286902783U; + msg.destination.assign("QGZNBBXOYNMMRROMMZLUOHUKVPJZCVSARNXGFAAHPGRGKVTMJDNFXXKRTEQGXIYHSMOVOZCQIWWHGQWLLSLUTKWFPIZJMOXAYEBZDSGTPYUJWDCTRNQHZVTELLIUFZBNEUESTDADQWFUTPAFIZODSFFSLJNFAEHHWCYDARVTNVKQVBLFZHQLSNSHMIPBDPSUBICINIWECLMVBOBRJYROEKJDMTQPCKJBXHGO"); + msg.timeout = 65205U; + const signed char tmp_msg_0[] = {77, -28, -62, -101, -4, -34, -128, -125, -54, 11, -116, 36, 65, -31, 15, -98, -83, -100, 69, 118, 86, -116, -125, -38, 4, -75, 51, -14, -47, -13, 76, -66, 63, -118, 95, -110, 74, -34, 77, -76, -12, 101, -80, -116, 42, 79, 18, 53, 106, -8, -125, 49, 105, -80, 86, -102, 103, 3, -78, 60, -9, -17, 60, -5, 82, -65, -41, -120, 28, 64, -12, 15, 61, 77, -110, 122, -78, 2, 91, -6, 67, -128, 43, -78, 19, -123, 22, -54, 75, 65, 112, 38, -17, 69, 10, 93, 91, -33, 86, -41, -17, 10, 66, -92, -31, -98, -89, 56, -92, -34, -17, 123, -25, -18, -128, -91, -26, 89, 75, -84, 21, -62, 106, 0, -1, 50, -49, -95, -4, -119, -10, -87, 82, 80, 125, -103, 58, -110, -63, 14, -94, -50, -12, -6, 39, 97, -84, 84, -122, 91, 41, 41, -123, -36, 116, -41, 37, -102, 121, -55, -59, -55, 54, -56, 100, -96, -51, -26, -19, -68, -41, -39, -118, -123, -73, 49, -98, -93, -82, -70, 108, 87, -33, -117, 122, -88, -92, -13, 30, 109, 21, 105, -100, 38, -47, -30, -68, -34, -85, -111, 30, 35, 71, 81, -89, -23, -115, -9, -11, -36, -36, -57, -59, -3, -19, 125, 93, 49, -45, 51, 91, 49, -8, -68, -89, 9, -30, 27, -70, -73, 90, 95, -45, -79, -50, -50, -27, -79, 66, 21, 92}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -2964,15 +3138,15 @@ main(void) { IMC::SmsTx msg; - msg.setTimeStamp(0.0903635397548); - msg.setSource(7000U); - msg.setSourceEntity(56U); - msg.setDestination(2950U); - msg.setDestinationEntity(200U); - msg.seq = 425404585U; - msg.destination.assign("ZACIDGYFXBCVQVDPMIJIUWAWGDUMRQQQMHHRCFVRENLCWLPKWNSLKMBYOYZUNPFRFTJDRVBDSQOBYFLMHOGCZGNZCWDSIZZLSJAKJGTIBSHVHHDWQLKZYJYTRLDCQGCMWJUJXVNMIVQYNUQGBAEHMTILXTKVHYFKYRAAZNXGAWLKBJXQXEXBUPOXKPNFZRVAUEUBLCSAOY"); - msg.timeout = 29263U; - const char tmp_msg_0[] = {111, 64, 77, -73, -22, -126, -25, 93, -15, 31, 15, -61, 126, 90, 41, 103, -112, -75, -86, 81, 82, -53, 91, -15, -50, 95, -103, 97, 92, -38, -22, 32, -11, 122, 98, 57, 66, -95, 79, -97, 68, -65, -86, -123, -97, -91, -32, 74, 45, 66, -78, -86, 107, 66, -68, 27, -2, 126, 5, 44, -76, -95, 85, 114, -26, -128, 72, -39, 23, -126, 106, 72, -114, -101, -80, 111, -115, 19, 110, 19, -115, 78, -39, -78, -126, 111, -112, 40, 17, 87, -16, -38, 65, 62, 65, 67, 2, -111, -30, 125, 76, 43, -101, 57, -124, 59, -22, 5, -8, -5, 80, 89, 22, 32, 101, 18, 62, 6, 73, -37, 114, -116, -19, 19, -101, 81, 6, 12, 21, 7, 27, -75, -76, -111, 83, 33, -49, 54, -33, 86, -46, -3, 94, 60, 7, -39, 62, 85, -86, 94, -53, -127, 14, 31, -52, 26, -37, 115, -49, 80, 95, -62, 87, -94, 70, 124, -110, 70, 126, -40, 89, 104, -88, -39, 32, -14, 2, -3, 84, 11, 51, -76, -116, 58, 32, -68, 0, 32, 64, 119, 120, -30, 74, 79, 18, 10, -123, 39, 116, 10, 16, -13, 57, 86, -98, -47, -117, -113, 12, 84, 52, 71, -39, -88, 62, 90, 76, 59, -12, -72, 3, 107, -8, -4, 120, 93, 74, 10, -70, 90, 32, -38, -31, 21, 14, -118, 68, 100}; + msg.setTimeStamp(0.9826682261661536); + msg.setSource(34441U); + msg.setSourceEntity(75U); + msg.setDestination(60870U); + msg.setDestinationEntity(252U); + msg.seq = 1407284964U; + msg.destination.assign("GPWDXLNDCKCBCIGTVQTEHUVDYKBPNHGSFFORXINTHFRCZNUNDZMBKPKOKAMZLMASFSXSXIXYAVTYYWUJVZEYGEPMCEMKAHDDJBJQLBMGIJDDOJAROOLGUDUUFHGYXQTJFZWQMEBJSXILTAVHWZGHRNWIPPMSQQQPBVSPDFXKYCPWEMBNCXZFORGMW"); + msg.timeout = 3105U; + const signed char tmp_msg_0[] = {-102, 112, 45, -4, 64, 48, 49, -41, 41, 25, 106, -7, -40, -69, -95, -64, -103, 110, -113, -126, 50, 38, -53, 76, -87, -56, 110, -93, 3, 77, -100, 40, -50, 98, 4, 33, 120, 90, 33, -46, 90, -42, -26, 66, -80, -57, -9, -69, 116, -117, -105, -109, 26, -17, -79, -81, 60, 82, -55, 104, 0, 19, -22, -64, -101, -4, 57, 77, -63, 109, 37, 18, -28, 33, -111, 25, -73, -7, -1, -80, -110, -78, -44, 36, -110, -43, 114, 36, -30, 66, 52, -20, 118, 36, -112, 62, 97, -20, -117, -118, -112, -124, 112, -65, -106, -116, 23, -5, 45, 28, -46, 66, -61, 19, -29, -63, 57, 55, 97, -13, 108, 39, -122, 9, -101, -30, 17, 59, -57, 121, 7, 80, 12, -64, 13, -86, 59, -70, -16, 69, -112, -48, -53, -20, 48, -46, -60, -74, -88, -36, 49, -119, 38, -124, -27, -5, -30, -99, 89, 73, 79, -108, -123, 112}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -2992,13 +3166,13 @@ main(void) { IMC::SmsRx msg; - msg.setTimeStamp(0.21962694645); - msg.setSource(22742U); - msg.setSourceEntity(86U); - msg.setDestination(56833U); - msg.setDestinationEntity(131U); - msg.source.assign("CGWFVMMYANLUZBKSDGZRTXIPVBLEBJLFUUGPYTRLGQIEYBXJTZLMIEJQTKCAHETVPDSYNGPWOJNLHYIUHMQQSXFHZQY"); - const char tmp_msg_0[] = {86, 6, 75, 101, 18, 124, -6, 90, -104, -98, -73, -63, 118, -95, 31, 5, -7, 61, 20, 52, -124, 114, 34, 70, -37, -98, 24, 125, 21, 103, -70, 17, -82, 117, 12, -124, 83, -121, -46, -36, -101, -83, 91, 58, -70, 31, -111, 44, 27, 11, 8, -78, -110, 114, -99, -6, 67, 79, -35, -127, -95, -89, 21, -77, 122, 126, -113, 28, 106, -110, 72, 20, -11, -44, 108, 96, -20, 78, -12, 111, 24, -99, -115, -91, 69, -52, 32, 67, 107, 87, -25, -122, 42, -33, -2, -62, 33, -82, 60, -93, 96, -33, -107, -70, 43, -8, 81, -53, 25, -4, 109, -11, 97, 93, 21, -99, 83, -42, -56, -14, -100, -30, -53, -121, 71, 45, 115, 98, -82, -28, 58, -34, 59, -55, -31, 95, 117, -89, -113, 49, 49, 58, -21, 114, 24, -61, 110, -16, -23, 72, 113, -127, 41, 41, -105, 0, -12, 120, 25, -90, 47, -95, 16, -73, -115, -101, -7, -9, -69, -22, -32, -102, -113, -94, -30, 29, -124, 27, -8, -89, -113, 38, 33, 110, 120, 103, 104, 114, -73, 115, -123, -126, -12, -77, 87}; + msg.setTimeStamp(0.9287322094446862); + msg.setSource(50707U); + msg.setSourceEntity(164U); + msg.setDestination(18236U); + msg.setDestinationEntity(208U); + msg.source.assign("SPGFPZRJKZZKNJFCMTQVBYOZWVKBHNXYLBEJPMXNDWWXFYCXJGSSHSUPLZYMLKIUETFJYCSYSCQHQIOBBTRHEDISTIQLQZTVHZORDDCOMGMKZH"); + const signed char tmp_msg_0[] = {18, 53, -18, -72, -65, 65, -15, 39, 112, 60, -19, 104, -51}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3018,13 +3192,13 @@ main(void) { IMC::SmsRx msg; - msg.setTimeStamp(0.900472819593); - msg.setSource(62388U); - msg.setSourceEntity(59U); - msg.setDestination(22972U); - msg.setDestinationEntity(203U); - msg.source.assign("OGMNZVDSZHXONJOFVTTYZNEAMSEVXYANKPGKPDXMIOTPRJESEV"); - const char tmp_msg_0[] = {5, -115, 73, 29, -111, 8, -10, 38, 114, -23, 107, -97, 94, -9, 79, 91, -35, -43, -71, -108, 93, -30, 120, -48, -68, -121, 67, -97, -96, -43, 11, 4, 20, -29, 109, 12, -27, 25, 57, -45, -93, -31, 8, -61, 126, -61, -54, -18, -89, 77, -1, -37, -54, 18, -112, -56, 27, 27, -79, -16, -40, 100, 47, 41, -12, -123, 44, 23, 87, -67, 106, 111, -88, 93, -57, -80, -12, -34, 110, -60, 89, -91, -106, 22, 44, 97, -52, 42, 47, 54, -63, -111, 58, 95, -17, -72, -48, -67, 54, 121, 108, -94, 42, 105, 12, -125, 107, 69, -29, 81, -12, -51, 71, 111, 20, -64, -53, -127, -120, 38, 18, -113, -58, 20, -71, 99, 57, 58, 121, 77, -63, 114, 110, 18, 106, 0, 106, -93, 124, -6, -121, -119, -74, -126, -66, -77, 10, -14, -102, 72, 74, 97}; + msg.setTimeStamp(0.05867768985647526); + msg.setSource(23404U); + msg.setSourceEntity(20U); + msg.setDestination(41088U); + msg.setDestinationEntity(113U); + msg.source.assign("AGSHOOLLJQRUI"); + const signed char tmp_msg_0[] = {-127, 34, -43, 118, 70, 24, 5, 83, -7, -22, 126, 121, -97, 87, 95, 111, 26, -97, 104, 94, 36, -82, -54, -70, -79, -32, 72, 72, 45, 113, 67, 19, -58, -108, -14, 122, -97, 28, -87, -74, -75, 89, -7, 74, 67, 102, 16, -18, -47, 85, -70, -61, -67, -61, -8, -27, -66, 121, -102, -64, 1, -51, 14, -23, -6, 123, 24, 12, -7, -42, 62, 86, -121, -31, 98, -31, -23, 46, -128, 0, 43, -63, -33, 19, 123, -87, 102, -116, -117, 108, -62, -64, -17, -21, -112, 23, 34, 93, -112, -15, -117, 17, 66, 19, -113, -127, -60, -42, 95, -72, -18, 122, -40, -66, 112, -104, -113, 87, -49, 70, -76, -10, 12, 67, 34, 112, -110, 25, -12, 96, 24, -13, 108, 122, -28, 14, -85, -115, 109, -65, 48, 120, -85, 116, -107, -93, 24, -89, -74, -53, 44, -90, 30, -61, -28, 109, -91, 12, 16, -104, -42, 106, 86, -46, 95, 13, 106, 28, -35, -96, 12, 2, -29, 35, 118, 30, -115, 106, 77, 25, -77, 38, 1, 107, 120, -64, -14, 101, 25, -74, -32, 122, -86, -61, 23, 6, -20, -58, -15, 51, 9, 10, -91, 95, -77, -122, 114, -91, -36, -79, 41, 74, 31, -29, -59, -99, -127, 107, 23, 61, -101, 90, -39, 76, 11, -29, 58, -74, 9, -86, -95, 25, -89, 102, -113, 93, -79, -97, 54, -32, -45, -38}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3044,13 +3218,13 @@ main(void) { IMC::SmsRx msg; - msg.setTimeStamp(0.997913680789); - msg.setSource(12739U); - msg.setSourceEntity(96U); - msg.setDestination(18267U); - msg.setDestinationEntity(2U); - msg.source.assign("RJGFUDUWISOSPXGUAJIARTMYTIFUXSYGPHYOLMSGILZRCVSRDAJXDMHWBSIJOWDQKWWCRKHDLFYHRDVTDHJVYPZQTREZFGHNNPJCGNXWYNVCRXAAVLVGIKNBOCDBBBLBQKMIXLOJNBYEAZXQEWRXKUYLIOPGGHAVKHZBTWMHWMQQHKRMUJATWELIOUSFJMQFPNPXKYKYEGZUNEJMLCCAZESQFZDKZNXEDFQTLOCSMBTTVI"); - const char tmp_msg_0[] = {-63, -92, -117, -97, 37, -82, -106, -115, 84, -111, 50, 121, 73, -127, 66, 116, 59, -53, -16, 16, -60, 126, 47, 60, -49, -92, 81, -75, -65, 120, -65, -108, -45, -116, -63, -123, 105, -82, 73, -55, -19, 29, -9, 38, 103, -82, 42, -92, -1, 1, -44, -56, -47, 66, 97, -115, 98, -120, -84, -17, -78, 47, 98, -45, 19, -34, 20, -52, -126, 86, 105, 28, 38, -128, -122, 107, 106, -57, -75, -50, -44, -104, -18, -125, 1, 115, -127, 101, 74, -32, -58, 112, 112, -33}; + msg.setTimeStamp(0.24687831862841414); + msg.setSource(60278U); + msg.setSourceEntity(39U); + msg.setDestination(2071U); + msg.setDestinationEntity(147U); + msg.source.assign("QZBJNSOQWUYRYXEICWEIXFHIYX"); + const signed char tmp_msg_0[] = {114, 20, 81, 23, -15, -28, -79, -33, -104, 125, 102, 117, 12, 58, -89, 8, 97, -55, 94, -10, -55, 78, 33, 36, 17, 40, -52, 32, 22, -54, 38, 63}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3070,14 +3244,14 @@ main(void) { IMC::SmsState msg; - msg.setTimeStamp(0.131098630406); - msg.setSource(56457U); - msg.setSourceEntity(199U); - msg.setDestination(28603U); - msg.setDestinationEntity(36U); - msg.seq = 3982685360U; - msg.state = 183U; - msg.error.assign("HMRCBMYJIDWMRHHTONPJL"); + msg.setTimeStamp(0.8049476026209201); + msg.setSource(43460U); + msg.setSourceEntity(246U); + msg.setDestination(45926U); + msg.setDestinationEntity(125U); + msg.seq = 4095515352U; + msg.state = 32U; + msg.error.assign("SYQFJGXHUGVCEFCKSBJLEOBJJSNFDRQUGTRLJPKAPYLEICSSTZPHQAHWNKWWZQINDZJFIMRLGVDGTEOWHLTUXETTIHOPKSGVRUOXKMANBJXXTXVYIBVSOXMRDLQDBUURHFBCYVCNLARPZWRGZDYDOAUMHSHLZGYADBQIHQTMOQELXMMAIZACKQTZWYFVMXEUCGKFQNPCOFPRWUEBHAYWNKVJPIYFVD"); try { @@ -3096,14 +3270,14 @@ main(void) { IMC::SmsState msg; - msg.setTimeStamp(0.647153244987); - msg.setSource(50324U); - msg.setSourceEntity(99U); - msg.setDestination(6070U); - msg.setDestinationEntity(118U); - msg.seq = 1056932170U; - msg.state = 112U; - msg.error.assign("RLECTPMVBOIKKHFYNENAHJGETFIENNNUXOKZAGDWDJMZTLJSLQERXSOFVBBWVGKSJBLRJXVGLUOHCEQKYRWNAVZHAYJUTYWJESCRCKNNOOHVSASMGHTMCBMKUZNLZAAOWHFTSGYGQSSMBBZXKTIBHILXUWDPFTIYPQDSRXROPYEUPXZLZKCGWDYAV"); + msg.setTimeStamp(0.5499834444465905); + msg.setSource(44686U); + msg.setSourceEntity(180U); + msg.setDestination(43855U); + msg.setDestinationEntity(132U); + msg.seq = 550496262U; + msg.state = 204U; + msg.error.assign("VJTWNNIMULSTCRQTGEHQCQKAKVEPVRIYQHDIHGUMHGANNTOUCEUIXODTBJYKAIYZBLLG"); try { @@ -3122,14 +3296,14 @@ main(void) { IMC::SmsState msg; - msg.setTimeStamp(0.443709010441); - msg.setSource(10337U); - msg.setSourceEntity(80U); - msg.setDestination(57942U); - msg.setDestinationEntity(168U); - msg.seq = 2296695462U; - msg.state = 246U; - msg.error.assign("RMORQWLRJHNVCASYKWUHGCEVSGRNEICDOXUWWBZFXVLFPOTZNLKZJABQMLXYNMEVQRIUFRAWAFYDYWYNGJYLKMKZSINSPKITTCUHDXFQBVKJJBGZVYHEWXDSAGRCNMEFTQOXCGZJPFLXBHICVDUSTEIBIEODGGLSFPBBHANMHATQXJTQOQQMXCWVKUODJCRJWNFPVPWLXYOMAYUBKUI"); + msg.setTimeStamp(0.07422887312495285); + msg.setSource(49458U); + msg.setSourceEntity(103U); + msg.setDestination(14908U); + msg.setDestinationEntity(230U); + msg.seq = 465784404U; + msg.state = 152U; + msg.error.assign("CMTZVJUYXGQAAKWZFXZXNOKNTUOPORDLMEXURDSHWEAMQWZIFHUKOHXIOMKCIZPQBANTYFRHTLGZFUQYJBXZVFEDTLCEPSJZOSEVHIJNFGTYLENYJICFBFRPLCSIGXYSGVJGCEPUFVKERPWGTPXSBLNVNSDSAVMKKOCFEGHAAVUXHMZBMTIR"); try { @@ -3148,13 +3322,13 @@ main(void) { IMC::TextMessage msg; - msg.setTimeStamp(0.888229703249); - msg.setSource(33472U); - msg.setSourceEntity(6U); - msg.setDestination(64380U); - msg.setDestinationEntity(9U); - msg.origin.assign("NNKLIJGZECCOQRCEQJEVMEUCUEKDVSMFBYRTXZVABHIHVTMKRMRIEQEBYQMWXVKKUPMGLSZNNFVQHFAJOIHRRAKVVRZCQQHHZAYLATFYEBBKPUUJJQWGTAPXTMIAWDSOGDPPDJWYVY"); - msg.text.assign("EPTOPAMHUDKBCIJ"); + msg.setTimeStamp(0.4924427955180112); + msg.setSource(13070U); + msg.setSourceEntity(108U); + msg.setDestination(44376U); + msg.setDestinationEntity(150U); + msg.origin.assign("SDQVAJFLQQCPWTZGYLOYMRLFMHVENHNCSXNIOIHEYLTEHXTYIWEMDDVGVVNMYUZIXQTLLKCWJXRDDDCTEPXIWPTFOSKARVMHGVGTKLORSJLABCQJMZXSOBURVUFFPKZAZWW"); + msg.text.assign("UTUTYOXSZZTQGPQNDLRYOIHUITDFQKGBKIDJRVFBNGWKTGBHHBFVZMVIRNYMLGPJHGAWIJRMRDBSCRLWJUBSKMACLEWFDXSCOZEWWQYMINTFATOIGUXSIRYBHOLDOFZLAJYEEXKA"); try { @@ -3173,13 +3347,13 @@ main(void) { IMC::TextMessage msg; - msg.setTimeStamp(0.488476560608); - msg.setSource(63562U); - msg.setSourceEntity(221U); - msg.setDestination(40062U); - msg.setDestinationEntity(166U); - msg.origin.assign("PBMPSPIYTVXAYKJWCSICBQZVGJYWZACTHVIWLGSSEZEGMPJPGNMWAKHPVNXFACDRIWFUVYONJRWGNRDUFWMEKMCSLFNGEPTMRFVEQDXKKHETJVHQRSZWEHQHISYNQOMRODTATTOBVDFJOOVXLCJURZREGLZZUYBYZBAADDHLMTCGAIJZUPULOTXFCHYSALQIGOOSKUJDVBXTRFLMWPSAKBBXUYHBXXKBWIQZKUQDGJXQHIRUYM"); - msg.text.assign("SLNRUBFWRIBNJAOVSSLCSTRKHYRZZSXIVDPVWGINYDHFCQLVXLTMCQCTSWGPDCBSXDQLPQQYZJBHVUEBUAEBSCTWKFJOWBGAEJTKKOENQHTZFGWZVOHVJBNLPAJXQWEMPOMZRTZVOMGGNFIAQXIJRPDUXPJMPDZMFGHPGSAFUAWKOLIYYXRKCIJCHDCHMKBRMFGEI"); + msg.setTimeStamp(0.20938957231081534); + msg.setSource(38611U); + msg.setSourceEntity(130U); + msg.setDestination(8803U); + msg.setDestinationEntity(50U); + msg.origin.assign("IQPDLYAIBJSJECYCEAEFMVFXFEMJTMSLFLGUFSUACTBESUIKSDLQQNNIKHWZWNZZZGXBQYIJUKLVDZPZWHXHFYCBXCPJSSFNXCHZDOOCRKUXYNUHJASYIRVXRWQIQZRDCYOOGVGAMHLGDFBLVTKREWBTWAOUARJNEBNNYKKTGSXHOSRHXJGKIOURWNIEAMVTQVJHEPPQMM"); + msg.text.assign("AYEVETUXDFAWRLEDFGHMEBRWEBQLWBNPFODXYHXGZVRLYCRQYQRLPZMJXIVFBLOKWUVIHIUABKNTJSQBYXUJSTYIDKWARFTANZOTAYHVIOBIMFDGUJMIVVFEPNAJSVYKPHGZYACPEMRNONCWSZOXHGMWNJZMCFSCCFZNKLENHBGCTJHPRSXIOUFZWEYPINJLPQOTSUAKUQSLXKMCKQVS"); try { @@ -3198,13 +3372,13 @@ main(void) { IMC::TextMessage msg; - msg.setTimeStamp(0.76445229783); - msg.setSource(3915U); - msg.setSourceEntity(135U); - msg.setDestination(49814U); - msg.setDestinationEntity(118U); - msg.origin.assign("XNTYBCYDGWKEAQDINRTZXYZMFAWUVWMENMMRZVYPOIZHOTCMPEPSPHEGHURGOS"); - msg.text.assign("OIUWCDABJZYGNJYUXGVMTGLLDULCMQUCZWSUKMEWBFUESLUMHHVNBVBTWDSFPAOXIMVBXDIXKDXBATOBANETPILGKCJLRFSXZQTMZLPGMIYNOEQCGDWFQYNBQEPNDDICXAHXPHKLQZHHS"); + msg.setTimeStamp(0.8529898785895073); + msg.setSource(38728U); + msg.setSourceEntity(246U); + msg.setDestination(23999U); + msg.setDestinationEntity(96U); + msg.origin.assign("LEXNKFWBQHJKHYTWOGBIKUSCBZVYFIEKSBQHHRKTXURFTDWGBKVUCMQDMLBTGYCBUTJOLMCVLYJTINPVODSPNEGJSJCMNIXIJOAUMGGYEHLMICCDXNWODYBKPTSRLVQSMXVELETAOSG"); + msg.text.assign("KTIKDLMFKUMAGOMBTGVIVRRWUOJ"); try { @@ -3223,16 +3397,16 @@ main(void) { IMC::IridiumMsgRx msg; - msg.setTimeStamp(0.823459036782); - msg.setSource(24351U); - msg.setSourceEntity(237U); - msg.setDestination(16785U); - msg.setDestinationEntity(173U); - msg.origin.assign("INMVGKIHGUUDXWHMWFWXPWHOCBOBCTZABKHAANFRCXDUFAMUELEXOXDJDNYZYH"); - msg.htime = 0.624421183923; - msg.lat = 0.952332982784; - msg.lon = 0.165293857821; - const char tmp_msg_0[] = {15, -3, 42, 18, -53, 78, -50, 43, -80, 103, -43, -76, -85, 58, 115, 49, -84, -94, 97, -36, 19, 98, 124, 94, -63, 97, -121, -37, 80, 99, -58, -62, -107, 59, 32, -86, -44, 47, -45, 84, 65, 100, -101}; + msg.setTimeStamp(0.7074056482310258); + msg.setSource(39476U); + msg.setSourceEntity(20U); + msg.setDestination(6885U); + msg.setDestinationEntity(65U); + msg.origin.assign("FKLRTMBSQRJPQFGLNGXXWAPGUGXDJZVLWAVUJEKSUEQGKSUHJRIZFDGHOVOFRVJAGTWQHBMCKJDSGYBPMXBYFARDEHTESUMOLTKYOFZCCNUTFONDQPAYPTCGBVRKJ"); + msg.htime = 0.4524436848781538; + msg.lat = 0.8741451120167558; + msg.lon = 0.43940360395617306; + const signed char tmp_msg_0[] = {-60, 115, 118, -1, -29, -38, 80, -120, 101, -119, -90, 122, -122, 105, -125, -127, -68, -30, -67, 95, -108, 90, -61, 37, -61, -104, -125, 37, -70, -58, 112, -107, -18, 42, -49, 117, -42, -124, -116, 56, -98, 103, -37, -98, -88, -9, -74, -120, -83, 24, 20, -84, -102, -94, -77, -1, -39, -101, 93, -47, 85, -82, 30, 78, -94, 37, 114, 44, -89, -106, -66, 118, 94, -100, -34, -101, -88, 109, 100, 84, -119, -80, 11, -5, 75, 115, 49, 98, 33, -92, 91, -30, 25, 34, 102, 5, -69, 61, -92, -20, -45, 20, -51, -56, -44, -24, 46, -69, -115, -40, 105, 90, 93, -120, 117, -79, -47, -16, -21, -12, 96, 31, 41, -41, 50, 90, -97, -93, -11, -41, 45, 17, 42, 76, -59, 93, 54, 100, -52, 75, -100, -96, 51, 97, -72, -60, -81, -103, 34, 91, 39, -104, 43, 103, -107, -109, -4, -94, 34, -120, 36, 124, -122, -102, 59, 8, 78, 28, 8, -30, 38, 36, 80, 76, 5, 49, -79, 50, 117, -4, 2, -101, -107}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3252,16 +3426,16 @@ main(void) { IMC::IridiumMsgRx msg; - msg.setTimeStamp(0.406674528761); - msg.setSource(28400U); - msg.setSourceEntity(162U); - msg.setDestination(48781U); - msg.setDestinationEntity(12U); - msg.origin.assign("NVBGWJJCYLTVAXKKQHMAHUSXMWRRTWMCFEFUMTYNAPDWDPKVGOOAEBJIWTLKKQBFRUULCHYBIZRXRIZBDQQCAOCWYHKENAUIJTVQMSPIQHXEAQYONEYKGOXPKV"); - msg.htime = 0.446450487045; - msg.lat = 0.212204905563; - msg.lon = 0.239355376801; - const char tmp_msg_0[] = {54, -34, 59, 7, -95, 16, 40, -69, -60, -47, 77, -30, -11, 120, -67, 58, -46, -118, -128, -42, 106, 61, -37, -105, -119, -24, 20, 42, 63, 90, 61, -120, 73, -66, 120, -79, -58, 67, 109, 45, 94, 37, 9, -119, -118, -120, 78, 66, -9, -105, -3, 126, -26, 93, -52, 54, -18, -110, 26, -53, -34, 123, -94, -10, 27, 114, -56, -38, 118, -113, -40, -31, 51, -38, 119, -71, 3, 32, -100, 110, -19, -75, 15, 76, -12, -124, 48, 101, 29, -102, -104, 63, 115, 30, -58, 56, -33, 88, -114, 19, -79, 50, 38, -105, 81, 64, -87, -13, -54, -23, -23, -13, 21, -85, -87, -46, 110, 28, -127, 94, -2, 31, -72, -22, -18, 79, 42, 102, -19, -100, -63, 9, 98, 44, -91, -126, 64, -95, 43, -103, 107, -38, -38, 17, -5, 100, 66, 107, -83, 123, -51, 18, -68, -35, 102, 77, 67, 18, -54, -123, 69, -110, 3, 97, 22, -122, 56, -25, 20, -97, -86, -35, 82, -47, 22, 55, 17, -8, 88, 9, -69, -91, -68, 55, 19, -32, 105, -94, -116, 21, -35, 42, 99, -126, -3, -106, -11, -88, 21, -65, -110, 11, 59, -1, 59, 95, 59, -10, -20, -119, -2, -57, -99, 7, 109, -42, -89, -8, 29, 102, 11, 101, -103, -18, 117, 71, -4, 17, 96, 39, -125, -65, 80, 113, 123, 9, -41, -26, -46}; + msg.setTimeStamp(0.9018674956948657); + msg.setSource(4262U); + msg.setSourceEntity(250U); + msg.setDestination(42281U); + msg.setDestinationEntity(135U); + msg.origin.assign("QOHNRHVLTCSZYRUAXGXMBTASBJOZHDLERDSCVEZBOMNUAUOFAZHCROWIDWUKKFQAAVNPNMUEUYGATRSEKPHDWCOZYXTJNEJQDWXHXSTOUHFLIVJMOVRAZLXKAXGFBRIWVMDJZBSHXYFEQISQPCPCNCVHSTRYCVQMQPUBDNAWZBKRYDIWSYZEKGQTPMQEJILCGWBYJBIMEFPUYJXPDZTBFEOXNLGTMSQVCGLMIGGNKLRPKOINLKFVH"); + msg.htime = 0.9476584839412671; + msg.lat = 0.6666324994768963; + msg.lon = 0.8660452190721433; + const signed char tmp_msg_0[] = {-6, -47, 104, 33, -128, 72, -44, 126, -54, 120, 88, -54, -48, -127, 58, -47, -123, 3, -11, -104, -61, -127, -58, 104, -28, -93, 66, 50, -103, -86, -26, 14, 0, -104, 25}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3281,16 +3455,16 @@ main(void) { IMC::IridiumMsgRx msg; - msg.setTimeStamp(0.681392301452); - msg.setSource(9284U); - msg.setSourceEntity(170U); - msg.setDestination(17153U); - msg.setDestinationEntity(125U); - msg.origin.assign("RLPCLJCTECKXEPUGGWBEFBBYTMOFSIKJZRXYNAJILTHWEGPJUFBYMUWYRTNMWHQVXPUDEVRYQRPQVZKBVKZHHNX"); - msg.htime = 0.85595378469; - msg.lat = 0.524381072603; - msg.lon = 0.655997033595; - const char tmp_msg_0[] = {9, -41, -86, -9, 101, 85, -117, 17, -50, 23, -12, -123, -95, 68, 79, 38, -31, -85, 76, 84, 56, -108, -15, 72, 55, -27, 7, -75, 62, -50, 43, 86, -33, -106, 108, -13, -62, -7, -22, 41, 1, -44, -50, 90, -49, -33, -107, -59, 27, 11, 52, 61, 124, -75, -15, 116, 64, 84, -34, -45, -68, 9, 32, 16, 101, -44, 3, 3, -69, 114, -80, -53, -56, 63, -29, 123, 97, -68, -28, 121, -74, -10, 22, 100, 59, 57, 100, 14, -18, 46, 78, -119, 41, 112, 69, 104, -110, 12, -127, 23, -67, 11, 103, -73, -128, -20, 49, -91, -56, -47, 82, -38, 60, 78, 6, -86, 70, -109, 4, 87, 38, -70, 40, 71, 23, -45, 36, 7, -98, 91, 8, -108, -96, 83, -19, 2, 17, -93, -19, -43, -98, -107, -73, 113, -78, 111, 83, 10, 43, 110, -124, -48, -82, -25, -119, -56, 13, -68, -50, -99, -36, -84, -123, 55, 27, 50, 80, 88}; + msg.setTimeStamp(0.5842214545744819); + msg.setSource(6402U); + msg.setSourceEntity(160U); + msg.setDestination(41936U); + msg.setDestinationEntity(244U); + msg.origin.assign("DRNREOHCHBGGEGAMEQLYRICTJHHYHCUITJNCZOUORCADAMKQXPKVPSFXASJGVTBTSUTQYONIFQKKFRWNYAMPBYAXNVAGEPFNICVWBSQZJFOILISZIBLZQUKWGZALRJPOUDYHMEGYEUSPJBWKADLCKPXVHMZSWBKNTEDPY"); + msg.htime = 0.1336140845380981; + msg.lat = 0.7536857617678234; + msg.lon = 0.8078414947152363; + const signed char tmp_msg_0[] = {86, -58, 72, -62, -96, 51, 93, -116, 19, 85, 57, 59, 78, 23, 4, -31, -10, 23, 83, -24, 5, 41, -19, 93, -102, 113, 102, 86, -128, -14, -74, -95, 6, -38, 124, 46, 11, -51, -79, -61, -9, 45, 125, -37, -102, 52, -103, -106, 80, 65, -115, -23, 71, 23, 52, 64, -44, 108, -35, -42, -82, 56, 105, 37, -106, -77, -12, -111, -119, 18, 50, 53, -98, 6, -117, -98, -71, 84, -1, 34, -69, 56, 57, -112, -45, 111, -6, -8, -113, 0, -90, 101, -20, 23, 106, -59, -103, 113, -1, 72, 121, 104}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3310,15 +3484,15 @@ main(void) { IMC::IridiumMsgTx msg; - msg.setTimeStamp(0.336026683993); - msg.setSource(26482U); - msg.setSourceEntity(36U); - msg.setDestination(25811U); - msg.setDestinationEntity(23U); - msg.req_id = 64502U; - msg.ttl = 54633U; - msg.destination.assign("TXQXDQAQOZUPESEQGWZ"); - const char tmp_msg_0[] = {80, -88, 7, -14, -69, 33, 14, -3, -8, 59, 110, 15, 68, -99, 3, 92, 107, -108, 9, -42, -51, 20, -82, -67, 38, -90, -27, -1, -51, 90, 59, -46, 113, 42, 14, 117, 84, -71, 109, -102, -57, -79, 49, -101, -47, 59, -100, 43, -45, -5, -100, 68, -91, 17, 58, 109, 73, -7, -98, -82, -92, -127, -56, -17, -93, -15, -56, -27, -45, -37, 8, 124, -1, 14, 66, -48, 45, -61, -83, -88, -29, 100, -39, 60, -22, 42, 54, -105, 114, -91, 94, 0, -22, 84, 107, -28, -64, 106, -111, -64, 101, 3, 36, -64, 112, 38, -34, 12, 117, 98, 31, -115, -49, -111, 80, 85}; + msg.setTimeStamp(0.2530150327075187); + msg.setSource(3689U); + msg.setSourceEntity(136U); + msg.setDestination(11307U); + msg.setDestinationEntity(196U); + msg.req_id = 35788U; + msg.ttl = 15068U; + msg.destination.assign("SIFTAKJQXSPHDNRCYEKOIRIOJNAFLYMMDQEWSZOYRGRHBBKQMBDWLCKOWJXVQJHFFAKXZMZVPCZDSEUKVVKRNZWDFFFTBQOSVDTTTTNKJIWVUSXCKLLXXXMMYCYBRWEOLCWRLOHTBACOIRQCYHMNBLVCFNXMRUJGYWGUGHD"); + const signed char tmp_msg_0[] = {98, 105, 91, -49, -71, -75, -18, 18, 62, 44, -105, 9, 114, -79, 118, 10, -35, 70, -102, 19, 88, -2, -3, -32, 56, -14, 72, -85, 104, 66, -74, -20, 104, -97, -99, 4, -9, -103, -12, -79, -29, 56, 122, -71, -101, 60, -97, -7, 20, -107, -97, -128, 23, 81, 69, -80, 80, 48, -29, -77, 30, -37, -30, 67, -116, -120, -92, 125, 14, 107, -34, 81, -119, 82, -58, 110, 77, 6, 66, 77, -121, -63, 20, -88, 80, -99, 51, -93, -60, -108, 12, -124, 24, 59, 121, 90, 17, -46, -3, 102, -31, -34, 122, -13, 68, 7, 110, -17, 11, 34, 90, -4, 38, -41, 126, 124, 112, 78, -30, -114, 115, -60, 32, 26, 64, -76, 90, 63, 104, 111, -61, 57, -39, -124, -93, -25, 17, 12, 23, 53, 37, -74, -24, -72, -52, -50, -112, -107, 124, -39, -110, 51, 90, 112, -106, 41, 19, -128, 76, -121, -1, -11, 98, -5, -86, 98, -96, 16, 27, -44, -107, 111, 12, -72, -99, 33, 119, 3, -44, 67, 94, 101, 88, -65, 6, 67, 41, 47, -62, 110, 62, 87, 41, -64, 92, 110, 18, -98, 10, 115, -14, -14, 81, -4, 115, -28, -100, -93, 111, -6, 57, -97, 63, 115, 122, 101, -15, 17, 10, -27, 54, -50, -36, 19, -77, -54, -52, 71, 83, 57, 125, -65, 71, 121, -70, 0, 80, 101, 33, -118, -126, -117, -30, -3, -78}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3338,15 +3512,15 @@ main(void) { IMC::IridiumMsgTx msg; - msg.setTimeStamp(0.971676125907); - msg.setSource(64854U); - msg.setSourceEntity(138U); - msg.setDestination(40872U); - msg.setDestinationEntity(12U); - msg.req_id = 26478U; - msg.ttl = 36180U; - msg.destination.assign("TEPMPXFGDETJSNSQJQQNGOVXWOGPRYHJKWCQFLNXNRFBCRKNFWDFCYQIGHKCLVEGDA"); - const char tmp_msg_0[] = {126, 33, 92, 48, 29, -2, -21, -44, -11, 75, -72, -76, -87, -114, 22, 3, -63, -66, -36, -23, -35, 79, -124, 1, -118, 76, -123, 88, 63, 121, 2, 25, -11, -87, 45, 80, -106, 5, 61, -40, 52, -1, -83, -117, 75, -86, 109, 43, 120, 35, -112, -61, 68, -65, 123, 54, 30, 114, -126, 90, 20, -98, -119, -88, -12, -18, -18, -6, 32, -56, 17, 60, 104, -18, 118, -86, -48, -125, -99, -75, -81, 95, -112, 110, -126, 47, -90, -5, -23, -74, -106, -107, 47, 122, 13, -17, -89, 41, -119, -18}; + msg.setTimeStamp(0.6318801331577361); + msg.setSource(39084U); + msg.setSourceEntity(73U); + msg.setDestination(19546U); + msg.setDestinationEntity(242U); + msg.req_id = 600U; + msg.ttl = 28790U; + msg.destination.assign("HJLQDZIFCTFWAGOYEHDPLLUPLZGGXDGUBCHVLTLSZGJFZNIFUVYUJMZUYSTEAQDHASYFAYPXRWFNRIBXLZVTHCEMJWLJVNITHKOSBEJYRFJTWLIDFWHWPQSHIGNRIKAPXWASBBOGGTNOXRODXDKIVSYBAMCOCOVLEYWEK"); + const signed char tmp_msg_0[] = {-90, -47, -125, -9, 60, 100, -117, 88, -1, 27, -69, 96, -92, -80, 101, 28, 117, 10, 81, 126, 9, 90, -52, 1, -115, 7, 93, 28, 57, -92, 51, 66, -116, -81, -93, -93, -23, -7, -51, 94, 66, -13, -35, -100, -108, -20, 68, 36, -91, 82, -93, 5, 47, 9, -34, 28, 104, -123, 63, -121, 47, 67, 89, 32, 4, 122, 89, 101, -60, -50, -46, 40, 29, 49, -21, 51, 114, -69, 94, 0, -70, -72, -72, -125, 9, -55}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3366,15 +3540,15 @@ main(void) { IMC::IridiumMsgTx msg; - msg.setTimeStamp(0.911849048073); - msg.setSource(37269U); - msg.setSourceEntity(169U); - msg.setDestination(56661U); - msg.setDestinationEntity(183U); - msg.req_id = 1073U; - msg.ttl = 56969U; - msg.destination.assign("YWVJJONXKZNBKVJDZXRNBJTLGMVAQHGBTRWPWRDLCGISYUSFEOEUBAVNIEHNOLKCGTRHQLILLAKRQCEKDMTDMCICQYPQIFOYYWARTFPGTUPTCNSYQMZPYUOXLMVMLOBIBFUIAUJEHCALAJPBHNDUZTWJXMZPSEOHQADXSIJWXPDUDKKXYGVQFCWJOMIQPZWDOJBIDNOHREVSAKZ"); - const char tmp_msg_0[] = {27, -61, -116, -9, -7, 80, 65, -85, 55, 14, -68, -108, -24, -40, -41, 17, -23, 53, 46, -80, -4, 59, -28, -4, 85, 123, 1, -30, 74, -25, 33, -14, -63, 104, 61, -49, 25, -33, 79, 117, -58, 10, 26, 55, 9, -62, 72, 70, -122, -55, 72, 82, 5, -6, -2, -2, 110, 9, 23, 35, 33, 27, 20, -86, -20, -19, 5, 19, 73, 113, -91, 4, 67, 115, -30, 113, -12, 60, 9, 49, -65, -12, 23, 16, -31, -121, -89, -53, -29, 39, 77, -38, -60, -41, -58, 1, -117, 57, -116}; + msg.setTimeStamp(0.47427231918680623); + msg.setSource(27474U); + msg.setSourceEntity(165U); + msg.setDestination(14230U); + msg.setDestinationEntity(248U); + msg.req_id = 5325U; + msg.ttl = 12659U; + msg.destination.assign("JMQJHSEGDINCZZUOHPJKAQGYAONKIRBZWXHGEXVAHZBCOYWSBZYIRUTTOBWEAVMKWVUFDPGXXQFFFBAKCBVSMRCIIRZTYIXBLUSKTSRIAERMMWDTDGYDNSBDUEFDEAVYCMQVHECELHQMPGFOHHWOYJSMWRDUQTXLWUPLCTWRHJOQPEDUCOZKFBMLYVGXNPDPRWSAQRKTPLSBJQFGZKIFQYJMZLNNGESLVIUVLJPKXTF"); + const signed char tmp_msg_0[] = {44, 71, -126, -62, 32, -67, 67, 8, -103, 4, 68, 60, -72, -73, -72, 55, 71, 58, -2, 120, -31, 9, -40, 117, 88, -60, 107, 61, -97, 64, -99, 76, -29, 103, -125, -17, 96, -22, -48, -89, 43, 126, -14, -60, -49, 9, -98, -3, 70, 122, 30, -110, -6, -128, 29, -102, -94, -3, 80, -108, 42, -29, -71, 43, -121, -18, -98, -62, 63, 79, 48, 61, 1, 58, 84, 75, -83, 56, -27, -73, -105, -49, -19, -93, 39, -108, 15, -67, 96, -122, 91, -6, 117, -60, -12, 73, 75}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3394,14 +3568,14 @@ main(void) { IMC::IridiumTxStatus msg; - msg.setTimeStamp(0.343552509565); - msg.setSource(16943U); - msg.setSourceEntity(194U); - msg.setDestination(27981U); - msg.setDestinationEntity(118U); - msg.req_id = 24069U; - msg.status = 84U; - msg.text.assign("ZOQUADHLCFFEKAHEWKBAVLQBDKTLSYWLLJOGACHKHJNSCPKARKXEJUPYBOLWDXMGBUNXCTMWGMKZRFBTFHIMYYOXXDIZWHSGQTVLEJIEVSEYNRFWBUQHTGANUNWXCNPMIFIRWEZKLAIOPDSSMUEZGH"); + msg.setTimeStamp(0.04181358341105834); + msg.setSource(21804U); + msg.setSourceEntity(116U); + msg.setDestination(47634U); + msg.setDestinationEntity(43U); + msg.req_id = 39866U; + msg.status = 101U; + msg.text.assign("CHKMQMCWZVKXSAKDNUPOZOROVXBQPPQYDYEWHSHEJIYFXJIGTYADNEISCHAGZSBDNFBKMJJXBUUQIKHLQCWEFMRQUYKMNIZETNPSOHUOCGFQVXXGYTSLGWRDKXGYHMTSMJJPTNSIDZKIBBGZONEBGLNIDVUTHACFWJAWLROEBLLWCYKWURQLJCSBSCXVMAFLCRATJTIXUVHUZRMIENZGOTHOGZARFDMLNAFRDBZKPVOLT"); try { @@ -3420,14 +3594,14 @@ main(void) { IMC::IridiumTxStatus msg; - msg.setTimeStamp(0.382857486336); - msg.setSource(26669U); - msg.setSourceEntity(30U); - msg.setDestination(10273U); - msg.setDestinationEntity(251U); - msg.req_id = 597U; - msg.status = 167U; - msg.text.assign("CDJHONMMUTBWQJZKQCXATCMLFFWRJAUKCINRBDTURILMOSFQTPMKAWPBTEOULGFPNXHPBEFJXZDCDLOXAHWVVQSSYWXKMJILBMZAGXGIEKWVQDRGHIEWQCGSAPYNFJFRSVZWKHOHDPZRRNAJQVCBSJUVQDBXYYCNPKOEVLOAMAGNHBCTEOIGNSVSRFLKIBVZCZIHGMXUYRPUTYNEJPSGDYFJVEKWIHZXDUKOFXSYPTYGLUUQRBQTLZ"); + msg.setTimeStamp(0.4714860799607562); + msg.setSource(56482U); + msg.setSourceEntity(60U); + msg.setDestination(17091U); + msg.setDestinationEntity(101U); + msg.req_id = 1975U; + msg.status = 140U; + msg.text.assign("UTEXKDENDGTLPECWYFQQGYGTKAZPQXCDYJQRMEJKHI"); try { @@ -3446,14 +3620,14 @@ main(void) { IMC::IridiumTxStatus msg; - msg.setTimeStamp(0.790180651338); - msg.setSource(43555U); - msg.setSourceEntity(237U); - msg.setDestination(58379U); - msg.setDestinationEntity(233U); - msg.req_id = 12827U; - msg.status = 40U; - msg.text.assign("CYWOCUEJRQREDGXJURZDXTUMUNIVAXHAYDHJUCOHWVKDFBWTCBRSQTMBBQHPJTMIBTGXIFAWSSJMZQPSGCEOLHLIVDVMEWLKLOQXHFFJYAOFFLLCJUXDKORSWMDOLRNGTUHDZAAQFLKOYVNVCERUXYCPBAKHWGKUAXVNIIVTQQGNPSDAPZPNMGOKWSSGDYYBSMENLZFZHQPREMJNECKGBNYPIWTLZBGFSYJJXOEKNZZVARTEHI"); + msg.setTimeStamp(0.9327751659345338); + msg.setSource(38609U); + msg.setSourceEntity(218U); + msg.setDestination(3989U); + msg.setDestinationEntity(57U); + msg.req_id = 12322U; + msg.status = 25U; + msg.text.assign("VZUQKUJMNOPTOXSJ"); try { @@ -3472,13 +3646,13 @@ main(void) { IMC::GroupMembershipState msg; - msg.setTimeStamp(0.456461367089); - msg.setSource(49901U); - msg.setSourceEntity(151U); - msg.setDestination(63781U); - msg.setDestinationEntity(8U); - msg.group_name.assign("SBDROAKUBCKZGKNAKW"); - msg.links = 1442616109U; + msg.setTimeStamp(0.04949366290858126); + msg.setSource(8399U); + msg.setSourceEntity(155U); + msg.setDestination(51358U); + msg.setDestinationEntity(170U); + msg.group_name.assign("ECKKWSAMEHXATHZFHJIUBYAXKRTFPIOENIUORNUYWJVUWAWRFONEGPTKVWBOXOFGASBCCOMMTGYVQDQUQISJZJXGRYQCKODGXLSULVVDPBQYZZPHHCGQFDCJFHJTZDFWADNMHCPIKTNBIYFAYXRGYNAKPCZDKLSUXKFCVMHFMBBZHWRMQZJMSINYTAPLEMGPSIJN"); + msg.links = 2607594248U; try { @@ -3497,13 +3671,13 @@ main(void) { IMC::GroupMembershipState msg; - msg.setTimeStamp(0.380127384632); - msg.setSource(53540U); - msg.setSourceEntity(245U); - msg.setDestination(16183U); - msg.setDestinationEntity(35U); - msg.group_name.assign("WGTCVWKSESOLRRKSNNJDTFHNWNUAMDKBGJWAWEMLAMWSIXTJGQJCZRXIRYYHUKGVGJHLJDZMIQUISUYVKRIYQHXILQHCJVXKUBVEOPTRMUTEUAECTHDWLWAZURYVFBPGPOMFBNMDCJQXMQZFJASIDQPSCQOLODGVTQTXZZYRYESYHEMFDPXQVVFZAXYYPZUTDEBXEAFGBNSKLPPLUXKMHOGVWEDWCOAINRBFNPHFONCH"); - msg.links = 2616604285U; + msg.setTimeStamp(0.8029367579180662); + msg.setSource(18590U); + msg.setSourceEntity(45U); + msg.setDestination(39850U); + msg.setDestinationEntity(125U); + msg.group_name.assign("CHQJUTTAQIIFJBCBRUZAYRBZQNHFSJMSSDXBMSDEGPULIIN"); + msg.links = 2211686448U; try { @@ -3522,13 +3696,13 @@ main(void) { IMC::GroupMembershipState msg; - msg.setTimeStamp(0.631217006586); - msg.setSource(18401U); - msg.setSourceEntity(180U); - msg.setDestination(31348U); - msg.setDestinationEntity(217U); - msg.group_name.assign("TJKDOPSMHTOSDOTDZEXPJZJIIBFJWSRULHWKAFLXWXMCWRECEMXUPSRGIROCVBMLQVGGENDGJCYKSYYIOWAIDEAFRTEAHIYJUQMLXOZWVBOZFTCBVCTNLPQKWWRFUAVNHZWQXLKVTY"); - msg.links = 3144954071U; + msg.setTimeStamp(0.25056444415557366); + msg.setSource(7537U); + msg.setSourceEntity(65U); + msg.setDestination(56333U); + msg.setDestinationEntity(115U); + msg.group_name.assign("OTXATOSVQCECVGLLXOLGRKBNBAZWJVEPUMINWFPJJDORGEYNFZHZQYSYCMTNIWHYDZBMIUSHQGQAVBJIAACEJZPCZWMHYHOJFBFFXVONSBFJLGJQSQWKAPAWKRHFRKUXXIUWKTFINEBKITYEPWWVVPAJQILXVMDKY"); + msg.links = 1114583640U; try { @@ -3547,14 +3721,14 @@ main(void) { IMC::SystemGroup msg; - msg.setTimeStamp(0.21406164522); - msg.setSource(4662U); - msg.setSourceEntity(77U); - msg.setDestination(7261U); - msg.setDestinationEntity(238U); - msg.groupname.assign("LCPMBQOKYAJZGHLBABGNTRQKJLD"); - msg.action = 191U; - msg.grouplist.assign("TMXLVJCMBZNDOOZKFABIOWLOROLPQMPIKSKHZXHGDWLDNYPJTBCIDV"); + msg.setTimeStamp(0.658692417102732); + msg.setSource(27636U); + msg.setSourceEntity(129U); + msg.setDestination(55789U); + msg.setDestinationEntity(226U); + msg.groupname.assign("KBFDYJEEOXZUVQPDJTICFVFETIHNCIKRHIMCWSGSBXLDCZGTXJXGJKSQPBZDLYBYWGOUKROGICGANYPPAGTFOKWYHARRR"); + msg.action = 99U; + msg.grouplist.assign("AJWAVPZLBQKZECAHSXZQXFMFTJCVNBSCKJFHLIZWAJPGNOHHABQFVSBYBRKWDKRNTPEPYSJYFMJYGDNIRPDQLLCOOXMSEYBJTAQTRZDDEUSDFNIWVHMIEYLGYDQFEQUQBWLXZKJTVXHXNZPCPTEPORTHVHRCMPU"); try { @@ -3573,14 +3747,14 @@ main(void) { IMC::SystemGroup msg; - msg.setTimeStamp(0.36988512846); - msg.setSource(5814U); - msg.setSourceEntity(1U); - msg.setDestination(31484U); - msg.setDestinationEntity(123U); - msg.groupname.assign("KUZVSBFOJEDTMDNZNWJWILPNMHPULWDUKMVTVWWMHERVVVKLXNTAGSVAZSXRCCEDPUHHLZQZXCXLRIGONZKITJMRSRHRXYEQABTTIFKJDOCPYMABMYZPSWEAKQGUXHDMTTEFOEONHGYKGHXCJAABRFCIULQOKEGAFGOJJBWBPDQXDISWGUHIRYULECZAYP"); - msg.action = 64U; - msg.grouplist.assign("VXGQOWYZUZE"); + msg.setTimeStamp(0.16528127890976685); + msg.setSource(52238U); + msg.setSourceEntity(105U); + msg.setDestination(40635U); + msg.setDestinationEntity(67U); + msg.groupname.assign("UUYTEUCLOVKVJSWODHBBETNFUXFCQYVBMPYAMIFAICFEAFWZWSNOFJYGECYPVKLTUJPJAFZLKHQMPBQFFIXHJJDGVWINXXNTSSNDARXHCUPGVOSBYDJRLNPUVPKBOMHXEAXQLZLQOHNHAXXQRWEIYDOBKUSKJFWJBWQLSSCVKCRRWAMTWNZPJIEKDIODGOGA"); + msg.action = 235U; + msg.grouplist.assign("XTTOQRVHANUURHCXFIDTVKOHOCLXNXWFEIZKCHZFDSNOCOIUGBAVJFZDIOQPWZKHPBFJSZIGTYUWKCSJLG"); try { @@ -3599,14 +3773,14 @@ main(void) { IMC::SystemGroup msg; - msg.setTimeStamp(0.402061812975); - msg.setSource(8236U); - msg.setSourceEntity(103U); - msg.setDestination(8104U); - msg.setDestinationEntity(180U); - msg.groupname.assign("DPWVVYTSHLOQHTGJLICFZJQTVSCZEPWJHWMULNXHAAQXHWVTEGUHYIODJKEXPRGJTRUCIENSICZWBMTXQOZQVKUVLZBSLDFOAKBOBWLPXIFBMKXNVYFDUCORJKISUKMUQLPRRHS"); - msg.action = 25U; - msg.grouplist.assign("ABAJEGHGUTEYQNGJJXMZTARBQUBETLRTGLUJYDPZWYBSQUCAASHLHKDYDFKUJXPVVTXPAVHHCEZRXSXIYFLNQEHSPAYEZOEMCMJYHXDSDGVRFFBZWQRLJPGCMERXPZMZOKIIMNUCWIIVDODLOZLAFURKSSCSWYPNSTFMTXSHFECKIHYGNWXJIVKCJOZDCZRKNBMBGLRXCAFRUVFKGWDKWVTUNALOFTONNHIKOJUIMBQOWMWGQ"); + msg.setTimeStamp(0.388210181267181); + msg.setSource(64435U); + msg.setSourceEntity(62U); + msg.setDestination(25509U); + msg.setDestinationEntity(188U); + msg.groupname.assign("BPKTXIBFESTSHYUYTRWMZDVLHVPKQNUKXWALQFWXYOOOAJHWNAOBGRECCNACGDJOWHMLKEQI"); + msg.action = 207U; + msg.grouplist.assign("SUFSZGPDIXNHUPWMILQKQEQWYVOJOSPKXSGKXHOAJLGNOKDRKCPBDOUFORDNNPHRYFTHJA"); try { @@ -3625,13 +3799,13 @@ main(void) { IMC::LinkLatency msg; - msg.setTimeStamp(0.848739766412); - msg.setSource(29504U); - msg.setSourceEntity(192U); - msg.setDestination(41356U); - msg.setDestinationEntity(128U); - msg.value = 0.816591260029; - msg.sys_src = 26655U; + msg.setTimeStamp(0.19840883686616195); + msg.setSource(405U); + msg.setSourceEntity(143U); + msg.setDestination(7177U); + msg.setDestinationEntity(193U); + msg.value = 0.7967763975724983; + msg.sys_src = 23490U; try { @@ -3650,13 +3824,13 @@ main(void) { IMC::LinkLatency msg; - msg.setTimeStamp(0.664152188077); - msg.setSource(29262U); - msg.setSourceEntity(152U); - msg.setDestination(23133U); - msg.setDestinationEntity(183U); - msg.value = 0.0036031742951; - msg.sys_src = 13851U; + msg.setTimeStamp(0.4701364210839909); + msg.setSource(50888U); + msg.setSourceEntity(186U); + msg.setDestination(7106U); + msg.setDestinationEntity(14U); + msg.value = 0.9007207559098368; + msg.sys_src = 57756U; try { @@ -3675,13 +3849,13 @@ main(void) { IMC::LinkLatency msg; - msg.setTimeStamp(0.265609700781); - msg.setSource(40038U); - msg.setSourceEntity(232U); - msg.setDestination(21649U); - msg.setDestinationEntity(235U); - msg.value = 0.715318877422; - msg.sys_src = 61252U; + msg.setTimeStamp(0.45323708165548826); + msg.setSource(46800U); + msg.setSourceEntity(250U); + msg.setDestination(65352U); + msg.setDestinationEntity(20U); + msg.value = 0.7055581771584615; + msg.sys_src = 56398U; try { @@ -3700,13 +3874,13 @@ main(void) { IMC::ExtendedRSSI msg; - msg.setTimeStamp(0.519664584587); - msg.setSource(33331U); - msg.setSourceEntity(247U); - msg.setDestination(19951U); - msg.setDestinationEntity(163U); - msg.value = 0.282532793814; - msg.units = 163U; + msg.setTimeStamp(0.4809251447101923); + msg.setSource(16415U); + msg.setSourceEntity(142U); + msg.setDestination(29964U); + msg.setDestinationEntity(102U); + msg.value = 0.985304967588626; + msg.units = 20U; try { @@ -3725,13 +3899,13 @@ main(void) { IMC::ExtendedRSSI msg; - msg.setTimeStamp(0.109691969285); - msg.setSource(55220U); - msg.setSourceEntity(10U); - msg.setDestination(62919U); - msg.setDestinationEntity(204U); - msg.value = 0.732684411785; - msg.units = 189U; + msg.setTimeStamp(0.1938643431027126); + msg.setSource(15822U); + msg.setSourceEntity(44U); + msg.setDestination(46283U); + msg.setDestinationEntity(182U); + msg.value = 0.7856690314611527; + msg.units = 0U; try { @@ -3750,13 +3924,13 @@ main(void) { IMC::ExtendedRSSI msg; - msg.setTimeStamp(0.0153996008611); - msg.setSource(53452U); - msg.setSourceEntity(74U); - msg.setDestination(32390U); - msg.setDestinationEntity(160U); - msg.value = 0.411879659561; - msg.units = 240U; + msg.setTimeStamp(0.18841728104422528); + msg.setSource(6227U); + msg.setSourceEntity(207U); + msg.setDestination(43708U); + msg.setDestinationEntity(130U); + msg.value = 0.8538826152813898; + msg.units = 228U; try { @@ -3775,14 +3949,40 @@ main(void) { IMC::HistoricData msg; - msg.setTimeStamp(0.524791115188); - msg.setSource(47031U); - msg.setSourceEntity(75U); - msg.setDestination(16248U); - msg.setDestinationEntity(165U); - msg.base_lat = 0.213446473523; - msg.base_lon = 0.725789407759; - msg.base_time = 0.397217565632; + msg.setTimeStamp(0.3850651840086514); + msg.setSource(45986U); + msg.setSourceEntity(14U); + msg.setDestination(11295U); + msg.setDestinationEntity(163U); + msg.base_lat = 0.8800861734855188; + msg.base_lon = 0.575817431002486; + msg.base_time = 0.9120292250139246; + IMC::HistoricSample tmp_msg_0; + tmp_msg_0.sys_id = 39501U; + tmp_msg_0.priority = -90; + tmp_msg_0.x = -4829; + tmp_msg_0.y = 8793; + tmp_msg_0.z = 17454; + tmp_msg_0.t = -26892; + IMC::RowsCoverage tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.lat = 0.6134430541129029; + tmp_tmp_msg_0_0.lon = 0.5528561389852374; + tmp_tmp_msg_0_0.z = 0.8491818229786575; + tmp_tmp_msg_0_0.z_units = 222U; + tmp_tmp_msg_0_0.speed = 0.7015291545868183; + tmp_tmp_msg_0_0.speed_units = 248U; + tmp_tmp_msg_0_0.bearing = 0.4379435152923419; + tmp_tmp_msg_0_0.cross_angle = 0.34723334396100525; + tmp_tmp_msg_0_0.width = 0.8348113917108035; + tmp_tmp_msg_0_0.length = 0.1785358859904348; + tmp_tmp_msg_0_0.coff = 102U; + tmp_tmp_msg_0_0.angaperture = 0.06551192935034833; + tmp_tmp_msg_0_0.range = 22171U; + tmp_tmp_msg_0_0.overlap = 22U; + tmp_tmp_msg_0_0.flags = 119U; + tmp_tmp_msg_0_0.custom.assign("NYKPFXWPEMXEPSHHBXZQBPRKXPRMIGISBUWOSTKOPBCLFGQASCDNHZZXGQVDCTOZTLGKSHAJWIBUISFKERRVAAJGGVKUTKWVOYLLNDUCTLRVAMDESTCJBZGCEYBAFIMCAUWOPFDVAREDUHQLLGKQUWXIKTVPOGNPWOIEEJZNVMLXDWSIZFHYJUQJB"); + tmp_msg_0.sample.set(tmp_tmp_msg_0_0); + msg.data.push_back(tmp_msg_0); try { @@ -3801,14 +4001,26 @@ main(void) { IMC::HistoricData msg; - msg.setTimeStamp(0.815215125705); - msg.setSource(14340U); - msg.setSourceEntity(253U); - msg.setDestination(8851U); - msg.setDestinationEntity(206U); - msg.base_lat = 0.898253467377; - msg.base_lon = 0.71486147371; - msg.base_time = 0.569437763759; + msg.setTimeStamp(0.6613752331252203); + msg.setSource(36231U); + msg.setSourceEntity(193U); + msg.setDestination(20823U); + msg.setDestinationEntity(175U); + msg.base_lat = 0.47262373170344585; + msg.base_lon = 0.9428384165699791; + msg.base_time = 0.8997263771618768; + IMC::HistoricSample tmp_msg_0; + tmp_msg_0.sys_id = 14153U; + tmp_msg_0.priority = 20; + tmp_msg_0.x = 23112; + tmp_msg_0.y = -20870; + tmp_msg_0.z = 30983; + tmp_msg_0.t = 21614; + IMC::ReplayControl tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.op = 76U; + tmp_tmp_msg_0_0.file.assign("EXYYSJNFXQBLWXOUMRLDFTMSGUGVNGWXRXUVVQKABJSHFKWGBQQEXERQRNZDSEDDAUWMQCTPENEKKPUFNFRKRLIMKTSDPUOTOATMIIHACVBEHFYTAFLUHYFOYDRNHKCNOCJAISJGZCJBUPWBYJYSAUMZNOALZSCONCLQIPVGXIXZZMQILZHLZKPDHVJBSWCSH"); + tmp_msg_0.sample.set(tmp_tmp_msg_0_0); + msg.data.push_back(tmp_msg_0); try { @@ -3827,14 +4039,22 @@ main(void) { IMC::HistoricData msg; - msg.setTimeStamp(0.377484068218); - msg.setSource(53819U); - msg.setSourceEntity(86U); - msg.setDestination(32524U); - msg.setDestinationEntity(37U); - msg.base_lat = 0.639575866594; - msg.base_lon = 0.568678078583; - msg.base_time = 0.551460443202; + msg.setTimeStamp(0.017581880329141764); + msg.setSource(32146U); + msg.setSourceEntity(20U); + msg.setDestination(1277U); + msg.setDestinationEntity(226U); + msg.base_lat = 0.11234943249459861; + msg.base_lon = 0.7691813282873329; + msg.base_time = 0.5179222071336619; + IMC::RemoteCommand tmp_msg_0; + tmp_msg_0.original_source = 27753U; + tmp_msg_0.destination = 14799U; + tmp_msg_0.timeout = 0.10202502713412254; + IMC::RegisterManeuver tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.mid = 39650U; + tmp_msg_0.cmd.set(tmp_tmp_msg_0_0); + msg.data.push_back(tmp_msg_0); try { @@ -3853,15 +4073,15 @@ main(void) { IMC::CompressedHistory msg; - msg.setTimeStamp(0.0913345615185); - msg.setSource(15868U); - msg.setSourceEntity(106U); - msg.setDestination(25341U); - msg.setDestinationEntity(15U); - msg.base_lat = 0.864576424577; - msg.base_lon = 0.427779970716; - msg.base_time = 0.745489464607; - const char tmp_msg_0[] = {-72, 36, 7, 124, -37, 53, 126, -67, 41, -100, 104, 9, 75, 61, -35, 116, 14, -92, 4, 113, -111, 111, -87, 0, -88, -102, 124, 117, 74, -99, -113, -107, 77, 42, 83, -18, 24, 54, -42, 35, 117, -103, -50, -15, -127, -58, 4, 105, -14, 10, -74, -17, 56, 53, 7, 19, -29, -112, 8, -32, 114, 34, 104, -91, -101, 24, -48, -44, 49, 14, -4, -123, -44, -90, -47, -65, -98, -71, -12, 75, 119, 55, 4, 109, -117, -50}; + msg.setTimeStamp(0.037984385291137346); + msg.setSource(19841U); + msg.setSourceEntity(88U); + msg.setDestination(12769U); + msg.setDestinationEntity(86U); + msg.base_lat = 0.19621984027285433; + msg.base_lon = 0.8007792593626032; + msg.base_time = 0.04008606206240006; + const signed char tmp_msg_0[] = {18, -55, -125, 79, -22, 85, -115, -42, 39, 21, 100, 66, -36, 31, -11, -86, 96, 59, 126, -7, -63, -64, -63, -17, -88, -60, -122, -128, 56, -73, 77, 65, -59, -5, 63, -4, 39, -38, -44, 47, 96, 82, -99, 36, 22, 119, 96, 113, 125, 15, -48, -98, -7, -18, 92, 87, 26, 112, 57, -125, -113, 87, 70, -79, 115, -27, 38, -123, -16, -109, 108, 69, 117, -15, -117, -9, 20, 95, -95, 16, 24, 32, 43, 97, -48, 21, -80, -78, -60, -20, 65, 11, 1, 45, -58, -79, -64, -15, 25, -78, -46, -123, 76, 107, 62, -121, 40, -11, 10, 108, -82, -76, 121, 19, -127, 16, 87, -105, -107, -13, -107, 121, 73, 102, 64, 23, 57, 120, -20, 105, 95, 3, 43, -59, -128, -21, -85, -77, 60, -81, -44, 111, 28, -15, 49, 126, 61, -25, -57, -97, -118, 36, -8, -117, -19, -81, -7, 97, 48, -50, 98, -8, 89, 120, 10, 93, -49, -15, -124, -7, -91, -53, 50, -84, -116, 9, 46, 98, -128, -105, 30, 90, 7, 60, 31, 79, 122, -4, 5, -42, -81, -65, 105, 35, -124, -36, -116, 51, -90, 92, 34, -89, 37, 106, 70, -128, -89, -69, 111, -70, 75, -99, -74, -24, -105, -81, -99, -20, -7, -97, -104, 75, 107, -116, 71, 98, -15, -29, -95, -79, -1, -47, -120}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3881,15 +4101,15 @@ main(void) { IMC::CompressedHistory msg; - msg.setTimeStamp(0.5993519587); - msg.setSource(38278U); - msg.setSourceEntity(86U); - msg.setDestination(41627U); - msg.setDestinationEntity(63U); - msg.base_lat = 0.695553226654; - msg.base_lon = 0.881603176682; - msg.base_time = 0.973133999216; - const char tmp_msg_0[] = {-14, 60, -96, -99, 104, -21, -100, -96, -35, -51, -112, -73, -99, 75, -11, 119, 44, -52, 102, 8, -62, 126, -114, -69, -32, 90, -89, 72, 57, -17, 64, -55, -81, 111, -92, 4, 61, -53, 10, -35, -13, 29, -59, -78, 124, -51, -62, -120, -74, -27, 36, -78, 51, 3, -23, 1, 82, 46, -75}; + msg.setTimeStamp(0.1482076055289515); + msg.setSource(57501U); + msg.setSourceEntity(12U); + msg.setDestination(48705U); + msg.setDestinationEntity(232U); + msg.base_lat = 0.37620430734050403; + msg.base_lon = 0.046502661508380116; + msg.base_time = 0.3577789871800787; + const signed char tmp_msg_0[] = {6, 75, -59, 38, -102, 107, 62, -9, -13, -98, -60, -67, 33, -50, 11, 119, -63, 81, 20, -39, -7, -112, 80, -38, -122, 87, -99, 81, -70, 82, 8, 1, -116, 113, 25, 121, -58, 114, 14, -55, -7, 83, 71, 54, 102, -127, -37, 47, -43, 53, 52, 32, -13, -59, -118, -69, -37, 43, -76, -89, -37, -27, -30, -18, 31, -113, 63, -35, -21, 66, -10, 83, 24, 54, 9, -112, -15, -126, 58}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3909,15 +4129,15 @@ main(void) { IMC::CompressedHistory msg; - msg.setTimeStamp(0.778826012211); - msg.setSource(59132U); - msg.setSourceEntity(212U); - msg.setDestination(60702U); - msg.setDestinationEntity(241U); - msg.base_lat = 0.0938566488406; - msg.base_lon = 0.718470362986; - msg.base_time = 0.441661929902; - const char tmp_msg_0[] = {-37, -99, -54, -96, -25, 27, -3, -3, -7, 55, -127, -28, -18, 38, 90, 20, -52, -11, -49, 73, -24, -62, 74, 116, -8, 65, 121, -107, 16, 12, 54, -24, -102, 92, 107, 0, 99, -91, 51, -19, 28, 103, -94, 64, -87, 66, -119, 100, -119, 95, -7, -73, 125, -120, -80, 99, 36, -45, -106, -2, 4, -82, -46, -50, 124, 94, -126, 81, -59, -62, 6, 66, 1, -59, 85, -102, -9, 68, 20, -96, -125, -11, 2, -43, 21, 85, -80, -75, -118, 77, 74, -11, 32, -113, 18, -74, -109, 70, -29, -23, -41, 106, -111, -1, -28, 93, -6, 104, -45, 16, 81, 33, -114, -100, -95, -42, 109, 105, 73, 110, -125, -94, 119, -53, 37, 59, -6, 18, -8, -110, 45, 46, -67, 93, -100, 11, -38, -94, 76, 115, -93, -72, -55, -62, 74, 104, -96, 71, 91, 31, -48, 105, 115, -51, 58, 90, -68, 109, 112, -73, -112, 15, 78, 35, -17, 12, -65, 112, 46, 96, -4, -3, -3, 79, 33, -50, 29, 126, 90, 66}; + msg.setTimeStamp(0.1785773548200329); + msg.setSource(41487U); + msg.setSourceEntity(49U); + msg.setDestination(22832U); + msg.setDestinationEntity(23U); + msg.base_lat = 0.4355318283095011; + msg.base_lon = 0.31971712117307993; + msg.base_time = 0.40408568532295; + const signed char tmp_msg_0[] = {-13, 109, -34, 23, -36, -91, -128, 67, -62, -35, 44, -82, 84, 118, -85, -99, -14, 45, 57, 113, 86, 115, -122, -4, -7, 95, 42, 81, -43, -28, -31, -128, 1}; msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try @@ -3937,22 +4157,26 @@ main(void) { IMC::HistoricSample msg; - msg.setTimeStamp(0.123830018307); - msg.setSource(189U); - msg.setSourceEntity(20U); - msg.setDestination(42819U); - msg.setDestinationEntity(199U); - msg.sys_id = 19406U; - msg.priority = 88; - msg.x = -15409; - msg.y = -24923; - msg.z = 2990; - msg.t = -22333; - IMC::UASimulation tmp_msg_0; - tmp_msg_0.type = 2U; - tmp_msg_0.speed = 47013U; - const char tmp_tmp_msg_0_0[] = {30, -103, 61, -8, -10, -79, 113, -126, -93, -59, -115, 3, -112, 71, 30, -124, -88, -5, 58, 29, -19, 35, 29, -89, 43, 45, -7, 74, -99, 20, -57, 58, -92, -63, -53, -100, 31, -66, 60, 62, 83, -51, -19, 70, 29, -44, -32, 58, -113, -77, -25, -76, 85, 87}; - tmp_msg_0.data.assign(tmp_tmp_msg_0_0, tmp_tmp_msg_0_0 + sizeof(tmp_tmp_msg_0_0)); + msg.setTimeStamp(0.0674290447100121); + msg.setSource(44245U); + msg.setSourceEntity(11U); + msg.setDestination(2808U); + msg.setDestinationEntity(129U); + msg.sys_id = 20822U; + msg.priority = 116; + msg.x = -19305; + msg.y = 6848; + msg.z = -853; + msg.t = 14013; + IMC::FormationState tmp_msg_0; + tmp_msg_0.type = 140U; + tmp_msg_0.op = 217U; + tmp_msg_0.possimerr = 0.5348383661028872; + tmp_msg_0.converg = 0.3948875574760655; + tmp_msg_0.turbulence = 0.6135438338679581; + tmp_msg_0.possimmon = 151U; + tmp_msg_0.commmon = 220U; + tmp_msg_0.convergmon = 217U; msg.sample.set(tmp_msg_0); try @@ -3972,19 +4196,25 @@ main(void) { IMC::HistoricSample msg; - msg.setTimeStamp(0.105856629017); - msg.setSource(59455U); - msg.setSourceEntity(205U); - msg.setDestination(6868U); - msg.setDestinationEntity(37U); - msg.sys_id = 55586U; - msg.priority = -59; - msg.x = -21261; - msg.y = 1294; - msg.z = -11139; - msg.t = 28911; - IMC::DesiredHeadingRate tmp_msg_0; - tmp_msg_0.value = 0.0427729646661; + msg.setTimeStamp(0.6556465425425141); + msg.setSource(18136U); + msg.setSourceEntity(56U); + msg.setDestination(3243U); + msg.setDestinationEntity(59U); + msg.sys_id = 30357U; + msg.priority = 70; + msg.x = 2458; + msg.y = 32694; + msg.z = 27778; + msg.t = -11271; + IMC::RemoteSensorInfo tmp_msg_0; + tmp_msg_0.id.assign("DGTITUKWPZDCSVXMSQSHTAPQADKZSCJCYHFOLCFZTBHGZNZGVDDNITCILPUGFSXUEHWRRLYRCWWOEKQXXMNKSPTBJJFLTMTRMHXYOVMKGEXURKADVUINPASREQAERWENFKOLQJGWJOQVPVVZPKIYRCVABDMLINUBYSMYMXQJHUANMHYBFBHIZGKTYQMNIAL"); + tmp_msg_0.sensor_class.assign("HBTBSPQQVBZUHGRRJDXNMYEF"); + tmp_msg_0.lat = 0.09320707828136998; + tmp_msg_0.lon = 0.557520275120927; + tmp_msg_0.alt = 0.7581743404837717; + tmp_msg_0.heading = 0.0006510740692892147; + tmp_msg_0.data.assign("BGJDMGNTDFHGISOMLBSNOZPCCRFXBQHIEVHPUP"); msg.sample.set(tmp_msg_0); try @@ -4004,21 +4234,26 @@ main(void) { IMC::HistoricSample msg; - msg.setTimeStamp(0.704913128843); - msg.setSource(14077U); - msg.setSourceEntity(50U); - msg.setDestination(56727U); - msg.setDestinationEntity(209U); - msg.sys_id = 23809U; - msg.priority = 115; - msg.x = -14337; - msg.y = 3994; - msg.z = 14687; - msg.t = 19133; - IMC::SystemGroup tmp_msg_0; - tmp_msg_0.groupname.assign("FJWANUPERABONDQUNMJPQLEOSNLZHNVEQKOWJSLIPVVZFVQYSFJGUGFYUAEBVOIPSPRGMRRIXYWTXYIFCSPTDEXZKKAXJITDPMFWSFOQKWHYJGBEYC"); - tmp_msg_0.action = 211U; - tmp_msg_0.grouplist.assign("RHLRVYCLQWPIOFZEOSEFWJVGOZYOZJPCZFUSUUQAXHSOCTUNSKCUQZJQOHYGOPEFWSQFDJD"); + msg.setTimeStamp(0.6665685869646636); + msg.setSource(2912U); + msg.setSourceEntity(158U); + msg.setDestination(26193U); + msg.setDestinationEntity(178U); + msg.sys_id = 18471U; + msg.priority = 89; + msg.x = 1952; + msg.y = 9713; + msg.z = 25984; + msg.t = -12000; + IMC::FollowPoint tmp_msg_0; + tmp_msg_0.target.assign("HGGSTCICFNHIRXDWHNRDDOXEXJBLYDOMCBJEZVJTPMGQNBWFLEIZKUQIRHSCQASUIWDBFJOGGOZYAYAESYKZXDXXOLJZZGVGSLEAJDQMSUENIITJOLMJWK"); + tmp_msg_0.max_speed = 0.4061828029553801; + tmp_msg_0.speed_units = 74U; + tmp_msg_0.lat = 0.6264484990259092; + tmp_msg_0.lon = 0.13831891074146174; + tmp_msg_0.z = 0.41087282516070933; + tmp_msg_0.z_units = 107U; + tmp_msg_0.custom.assign("QNAWJDDLFGWMECHOOQDPPCSHOODEZSYZBXASIQRGXHXRCCSAZATXUXL"); msg.sample.set(tmp_msg_0); try @@ -4038,18 +4273,30 @@ main(void) { IMC::HistoricDataQuery msg; - msg.setTimeStamp(0.705711074092); - msg.setSource(20875U); - msg.setSourceEntity(209U); - msg.setDestination(54692U); - msg.setDestinationEntity(42U); - msg.req_id = 58539U; - msg.type = 181U; - msg.max_size = 24556U; + msg.setTimeStamp(0.2525041823750277); + msg.setSource(14871U); + msg.setSourceEntity(88U); + msg.setDestination(14252U); + msg.setDestinationEntity(60U); + msg.req_id = 11686U; + msg.type = 212U; + msg.max_size = 28996U; IMC::HistoricData tmp_msg_0; - tmp_msg_0.base_lat = 0.780210682861; - tmp_msg_0.base_lon = 0.756479844803; - tmp_msg_0.base_time = 0.535186869042; + tmp_msg_0.base_lat = 0.6410357065181017; + tmp_msg_0.base_lon = 0.5780429024419279; + tmp_msg_0.base_time = 0.8945120841695858; + IMC::HistoricSample tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.sys_id = 32343U; + tmp_tmp_msg_0_0.priority = 75; + tmp_tmp_msg_0_0.x = 1278; + tmp_tmp_msg_0_0.y = 10895; + tmp_tmp_msg_0_0.z = -3552; + tmp_tmp_msg_0_0.t = 30360; + IMC::LcdControl tmp_tmp_tmp_msg_0_0_0; + tmp_tmp_tmp_msg_0_0_0.op = 58U; + tmp_tmp_tmp_msg_0_0_0.text.assign("VQQADOJZNYEFUZKHOZLUMBDMNFEQJNPUCVBRCHCZMTJAOFNNDIGXTSPHQMKWXVSITK"); + tmp_tmp_msg_0_0.sample.set(tmp_tmp_tmp_msg_0_0_0); + tmp_msg_0.data.push_back(tmp_tmp_msg_0_0); msg.data.set(tmp_msg_0); try @@ -4069,26 +4316,24 @@ main(void) { IMC::HistoricDataQuery msg; - msg.setTimeStamp(0.85700878838); - msg.setSource(7295U); - msg.setSourceEntity(95U); - msg.setDestination(37562U); - msg.setDestinationEntity(53U); - msg.req_id = 3707U; - msg.type = 98U; - msg.max_size = 24587U; + msg.setTimeStamp(0.9186815754880846); + msg.setSource(58497U); + msg.setSourceEntity(177U); + msg.setDestination(2869U); + msg.setDestinationEntity(181U); + msg.req_id = 62440U; + msg.type = 242U; + msg.max_size = 27168U; IMC::HistoricData tmp_msg_0; - tmp_msg_0.base_lat = 0.744260739741; - tmp_msg_0.base_lon = 0.814230756654; - tmp_msg_0.base_time = 0.549733099473; + tmp_msg_0.base_lat = 0.9676608182630351; + tmp_msg_0.base_lon = 0.6623623702866902; + tmp_msg_0.base_time = 0.917406104469469; IMC::RemoteCommand tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.original_source = 25365U; - tmp_tmp_msg_0_0.destination = 16193U; - tmp_tmp_msg_0_0.timeout = 0.399170364172; - IMC::CompressedImage tmp_tmp_tmp_msg_0_0_0; - tmp_tmp_tmp_msg_0_0_0.frameid = 191U; - const char tmp_tmp_tmp_tmp_msg_0_0_0_0[] = {31, -127, 115, 0, -70, 25, -28, -25, 35, 59, -3, -66, 55, 17, 2, 92, 80, 121, 54, -58, 11, 87, -14, -95, -107, 95, 102, -84, 108, -59, 30, -33, -11, -69, 120, 79, 56, 117, -70, 85, -114, 124, -32, 71, -34, -29, 46, 87, -82, -63, 88, -67, 58, 65, 63, 100, 66, 65, 41, -70, 94, 38, -54, 61, -28, -19, 52, -18, 46, 110, -22, 118, -24, 93, 74, 97, 34, -40, 24, -52, 66, -95, -86, 22, 120, -52, 26, -84, 113, -31, 70, -79, -39, -92, -13, -1, 63, 96, 36, 53, 93, -59, 23, 34, 66, -71, -69, -55, 43, 119, -37, 95, -114, 29, 82, 94, 95, 41, 89, 60, 26, 16, 111, -97, -70, -23, 110, 104, -66, 68, 38, -31, -41, -76, 55, -56, -5, 13, 58, 37, -37, -88, 69, 93, 90, 105, -44, -78, 106, -107, -57, 74, 105, 119, 113, 23, 25, -6, 56, -47, -111, 8, -17, 60, 53, -7, -77, -37, 43, 5, 30, 8, 124, 121, 62, -8, -63, -78, 12, -18, -71, 104, 94, 47, 40, -20, 30, -108, 35, 29, 17, -43, -108, -48, -64, -128, -107, -19, 1, -88, 31, -3, -40, -31, 93, -111, -87, -73, -26, -73, -3, -60, 95, 47, 101, -17, -10, 13, -114, 33, 58, 70, 30, 57, 27, 67, -32, -121, -109, -14, 89, 70, -65, -45, -116, 25, 117, 40, -123, -71, -9, -27, 24, -114, 30, 42, -66, -108}; - tmp_tmp_tmp_msg_0_0_0.data.assign(tmp_tmp_tmp_tmp_msg_0_0_0_0, tmp_tmp_tmp_tmp_msg_0_0_0_0 + sizeof(tmp_tmp_tmp_tmp_msg_0_0_0_0)); + tmp_tmp_msg_0_0.original_source = 23370U; + tmp_tmp_msg_0_0.destination = 4860U; + tmp_tmp_msg_0_0.timeout = 0.059728603235698285; + IMC::DesiredRoll tmp_tmp_tmp_msg_0_0_0; + tmp_tmp_tmp_msg_0_0_0.value = 0.7110719982147172; tmp_tmp_msg_0_0.cmd.set(tmp_tmp_tmp_msg_0_0_0); tmp_msg_0.data.push_back(tmp_tmp_msg_0_0); msg.data.set(tmp_msg_0); @@ -4110,29 +4355,44 @@ main(void) { IMC::HistoricDataQuery msg; - msg.setTimeStamp(0.700478505608); - msg.setSource(48900U); - msg.setSourceEntity(205U); - msg.setDestination(14809U); - msg.setDestinationEntity(202U); - msg.req_id = 36171U; - msg.type = 138U; - msg.max_size = 62173U; + msg.setTimeStamp(0.47431600993830236); + msg.setSource(52916U); + msg.setSourceEntity(227U); + msg.setDestination(20268U); + msg.setDestinationEntity(46U); + msg.req_id = 38700U; + msg.type = 71U; + msg.max_size = 19470U; IMC::HistoricData tmp_msg_0; - tmp_msg_0.base_lat = 0.267031006021; - tmp_msg_0.base_lon = 0.454391960907; - tmp_msg_0.base_time = 0.707522306913; - IMC::HistoricSample tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.sys_id = 46443U; - tmp_tmp_msg_0_0.priority = 90; - tmp_tmp_msg_0_0.x = -30588; - tmp_tmp_msg_0_0.y = -268; - tmp_tmp_msg_0_0.z = -7550; - tmp_tmp_msg_0_0.t = 30920; - IMC::ButtonEvent tmp_tmp_tmp_msg_0_0_0; - tmp_tmp_tmp_msg_0_0_0.button = 248U; - tmp_tmp_tmp_msg_0_0_0.value = 109U; - tmp_tmp_msg_0_0.sample.set(tmp_tmp_tmp_msg_0_0_0); + tmp_msg_0.base_lat = 0.28139536786624986; + tmp_msg_0.base_lon = 0.23546635894088153; + tmp_msg_0.base_time = 0.49033354483089653; + IMC::RemoteCommand tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.original_source = 64624U; + tmp_tmp_msg_0_0.destination = 30273U; + tmp_tmp_msg_0_0.timeout = 0.39626416962205446; + IMC::TransmissionRequest tmp_tmp_tmp_msg_0_0_0; + tmp_tmp_tmp_msg_0_0_0.req_id = 16919U; + tmp_tmp_tmp_msg_0_0_0.comm_mean = 27U; + tmp_tmp_tmp_msg_0_0_0.destination.assign("HVRDGZCEJUUFHOIPRJNGGWFCWAPWQIWPCRYGWRKXQCZYYZFZJAXTVSDTFLELAPBNTUNDLMYJDSPOUHCFTEOQECBHEEBQDRMGKBTLMXSZEKGANQTRNMDIJSIK"); + tmp_tmp_tmp_msg_0_0_0.deadline = 0.5742505500515553; + tmp_tmp_tmp_msg_0_0_0.range = 0.8814783432825184; + tmp_tmp_tmp_msg_0_0_0.data_mode = 18U; + IMC::ReportedState tmp_tmp_tmp_tmp_msg_0_0_0_0; + tmp_tmp_tmp_tmp_msg_0_0_0_0.lat = 0.8776686257327635; + tmp_tmp_tmp_tmp_msg_0_0_0_0.lon = 0.5036361661662236; + tmp_tmp_tmp_tmp_msg_0_0_0_0.depth = 0.5016573376070613; + tmp_tmp_tmp_tmp_msg_0_0_0_0.roll = 0.8204410197133125; + tmp_tmp_tmp_tmp_msg_0_0_0_0.pitch = 0.941633205695714; + tmp_tmp_tmp_tmp_msg_0_0_0_0.yaw = 0.5890076482470271; + tmp_tmp_tmp_tmp_msg_0_0_0_0.rcp_time = 0.024506988888214787; + tmp_tmp_tmp_tmp_msg_0_0_0_0.sid.assign("BRKGPMEHRIKICYLHWENBPSZGCIMIGAXXNLWDUQAZGOTNLTELQDKSBBHIDSJVVUYJSLYJECIIYTJQNPOOBOWDYQSUKDXHVVRWFGSJLHWQSRK"); + tmp_tmp_tmp_tmp_msg_0_0_0_0.s_type = 160U; + tmp_tmp_tmp_msg_0_0_0.msg_data.set(tmp_tmp_tmp_tmp_msg_0_0_0_0); + tmp_tmp_tmp_msg_0_0_0.txt_data.assign("HGOZSWUJPHUUZHQFGCTJJHPZNFHGXIBDZAAVRKNMDWPUGDEFUFKKPZCJHOTBWIBDCYLRJOXVHXELGIVMAXQGAY"); + const signed char tmp_tmp_tmp_tmp_msg_0_0_0_1[] = {62, -93, -68, 34, -39, -37, -110, 37, -109, 25, 1, -47, 23, -104, -111, 60, -34, 66, 75, -41, 69, -30, 24, 10, -75, -90, -93, -9, -56, 25, 111, 71, -59, -65, -86, -100, -112, 120, 111, 97, 39, -95, 53, 14, 39, 86, 21, 40, 23, 116, 18, 78, 56, -92, 58, -54, -82, -115, -9, 76, 8, 120, -24, 119, -50, -25, -80, 61, 56, 120, -31, -67, -2, -120, 126, 80, -123, -93, -4, -77, -104, -48, 115, 54, -114, -24, 124, -9, 32, 43, 19, -123, -19, -31, 121, -112, -4, 102, -28, 113, -67, 32, -6, -127, 7, -32, -78, 4, 8, -111, -21, 82, -78, 118, -105, -35, -106, 101, -61, 18, 76, 122, -47, 114, -29, -9, 58, 104, -125, -88, -14, 79, 88, 5, -27, 94, 107}; + tmp_tmp_tmp_msg_0_0_0.raw_data.assign(tmp_tmp_tmp_tmp_msg_0_0_0_1, tmp_tmp_tmp_tmp_msg_0_0_0_1 + sizeof(tmp_tmp_tmp_tmp_msg_0_0_0_1)); + tmp_tmp_msg_0_0.cmd.set(tmp_tmp_tmp_msg_0_0_0); tmp_msg_0.data.push_back(tmp_tmp_msg_0_0); msg.data.set(tmp_msg_0); @@ -4153,21 +4413,33 @@ main(void) { IMC::RemoteCommand msg; - msg.setTimeStamp(0.6448608638); - msg.setSource(21742U); - msg.setSourceEntity(217U); - msg.setDestination(58253U); - msg.setDestinationEntity(70U); - msg.original_source = 6077U; - msg.destination = 1911U; - msg.timeout = 0.121886208944; - IMC::AcousticOperation tmp_msg_0; - tmp_msg_0.op = 109U; - tmp_msg_0.system.assign("KLDIEGWPTASDBRUCUDOBHIZNPNXZPAYIECHGGGBBRVZNNJRYEQPZCFEMENQZXYKPIIAEFSVIUKHDWAFMXVMKCGTYWSVWCQIOJLUUVFLIRQMSYLEFMXCDTFXLAOZIDEEUARWKAXKJKBRVBYPQFSQJTUHPLNKBJVXXEALWNOPKZXLOQM"); - tmp_msg_0.range = 0.253862779891; - IMC::PopEntityParameters tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.name.assign("ZGOVWKQAZXHBQNQGUCAEWPGPPFDNPHYUJJIMSAGNEHHNZLFSAVEDVTITKVWKEOBSIMWRUJDADNOCPRJGJVSWIUXUK"); - tmp_msg_0.msg.set(tmp_tmp_msg_0_0); + msg.setTimeStamp(0.93125486728959); + msg.setSource(54967U); + msg.setSourceEntity(1U); + msg.setDestination(37984U); + msg.setDestinationEntity(200U); + msg.original_source = 52046U; + msg.destination = 44518U; + msg.timeout = 0.9951946051358378; + IMC::SimulatedState tmp_msg_0; + tmp_msg_0.lat = 0.38694887903209263; + tmp_msg_0.lon = 0.35776395674302985; + tmp_msg_0.height = 0.1723844216190319; + tmp_msg_0.x = 0.12427510175171896; + tmp_msg_0.y = 0.23203935088834393; + tmp_msg_0.z = 0.05571839211232421; + tmp_msg_0.phi = 0.1573500167594677; + tmp_msg_0.theta = 0.8444302129707072; + tmp_msg_0.psi = 0.22754831140806042; + tmp_msg_0.u = 0.2531340357587677; + tmp_msg_0.v = 0.7805683957882386; + tmp_msg_0.w = 0.6600330246385909; + tmp_msg_0.p = 0.8704809555771055; + tmp_msg_0.q = 0.5387493088967754; + tmp_msg_0.r = 0.06118716384091927; + tmp_msg_0.svx = 0.5500652950282248; + tmp_msg_0.svy = 0.0944405649168858; + tmp_msg_0.svz = 0.1881280344908356; msg.cmd.set(tmp_msg_0); try @@ -4187,20 +4459,15 @@ main(void) { IMC::RemoteCommand msg; - msg.setTimeStamp(0.860073199463); - msg.setSource(3158U); - msg.setSourceEntity(129U); - msg.setDestination(61613U); - msg.setDestinationEntity(157U); - msg.original_source = 10449U; - msg.destination = 13712U; - msg.timeout = 0.916089883826; - IMC::CompressedHistory tmp_msg_0; - tmp_msg_0.base_lat = 0.145094757389; - tmp_msg_0.base_lon = 0.122523585112; - tmp_msg_0.base_time = 0.0967306675989; - const char tmp_tmp_msg_0_0[] = {-120, 23, -97, 12, -68, -92, 14, 109, -115, 116, 10, -66, -47, -34, -67, -30, 92, -57, 1, 68, 7, 49, -90}; - tmp_msg_0.data.assign(tmp_tmp_msg_0_0, tmp_tmp_msg_0_0 + sizeof(tmp_tmp_msg_0_0)); + msg.setTimeStamp(0.8601567341403737); + msg.setSource(7500U); + msg.setSourceEntity(80U); + msg.setDestination(993U); + msg.setDestinationEntity(125U); + msg.original_source = 46211U; + msg.destination = 59058U; + msg.timeout = 0.8804530572885328; + IMC::QueryPowerChannelState tmp_msg_0; msg.cmd.set(tmp_msg_0); try @@ -4220,19 +4487,15 @@ main(void) { IMC::RemoteCommand msg; - msg.setTimeStamp(0.586236832992); - msg.setSource(13609U); - msg.setSourceEntity(253U); - msg.setDestination(17828U); - msg.setDestinationEntity(203U); - msg.original_source = 31308U; - msg.destination = 15327U; - msg.timeout = 0.631958854715; - IMC::PlanGeneration tmp_msg_0; - tmp_msg_0.cmd = 96U; - tmp_msg_0.op = 2U; - tmp_msg_0.plan_id.assign("MYLWJKKZVMATTOEFYMSZFLZDKZBVLVDILMGAQDXWQFPGGNNNRRWUECJEYIGSKLHCCZHZVCGZMKMMQTFXVOBFCPHQAYBVLVSUQCFIMAJWTSXCHRWDNZGIAPVSGTIWIYQJNPGOJQXAAHWYOSXJRXQAHFHEKEQRUEOXNDWRNHULERAVDIGQZOCBKBTDOPUBTNITXF"); - tmp_msg_0.params.assign("VTGQYNBWRZURJYTYQWDVPBWMIQLFNUZGPRRTPCXGGPZLIQRYZJERVVULFKEHMLULIZGFEYJDCLNHEICBIRHCKQXVUWUXDWUDMTRKBCJVBMHZMBXOZNACJZRLSFVPNOIEEAIOCWYWVLDGHGSXTWADWZCXBJUYHJAFFDPJRKQMTKLYWXQBDKTXGOSEOAFHAAPDKSSOIOAPJKTHEFGCKPITNNABSVVHMMOYTYOGSNCKHESFMDESMUQBUNXLQAS"); + msg.setTimeStamp(0.3599759607555325); + msg.setSource(39373U); + msg.setSourceEntity(150U); + msg.setDestination(13634U); + msg.setDestinationEntity(140U); + msg.original_source = 23464U; + msg.destination = 21059U; + msg.timeout = 0.3803319106801668; + IMC::MsgList tmp_msg_0; msg.cmd.set(tmp_msg_0); try @@ -4251,21 +4514,23 @@ main(void) } { - IMC::LblRange msg; - msg.setTimeStamp(0.529822382672); - msg.setSource(24552U); - msg.setSourceEntity(8U); - msg.setDestination(6830U); - msg.setDestinationEntity(232U); - msg.id = 78U; - msg.range = 0.994185351278; + IMC::CommSystemsQuery msg; + msg.setTimeStamp(0.511798575997064); + msg.setSource(29937U); + msg.setSourceEntity(234U); + msg.setDestination(21590U); + msg.setDestinationEntity(153U); + msg.type = 143U; + msg.comm_interface = 5004U; + msg.model = 47546U; + msg.list.assign("TOXERQTWYYGEMDLCMRXUMETNJWJSHSNVOUSKDSSZRFQWVYENNAUCLNGWGRFHHJJQBVLHPVDOYXMBZWHJHVDESBCHPZKQWUSLYUIPHQNGXQFRXUNAMIFBDCNQPNVQRAPNPDCWPOFZIFXTQBGJPRDAICYITJFFVKOEKBMLXBKKOBLJTZPSYICOZYXYEVAGJRCKFTYLGMGMDZK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblRange #0", msg == *msg_d); + test.boolean("CommSystemsQuery #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4276,21 +4541,23 @@ main(void) } { - IMC::LblRange msg; - msg.setTimeStamp(0.384306095409); - msg.setSource(62052U); - msg.setSourceEntity(92U); - msg.setDestination(8381U); - msg.setDestinationEntity(72U); - msg.id = 224U; - msg.range = 0.326607594153; + IMC::CommSystemsQuery msg; + msg.setTimeStamp(0.20883741479204865); + msg.setSource(32926U); + msg.setSourceEntity(111U); + msg.setDestination(50825U); + msg.setDestinationEntity(120U); + msg.type = 17U; + msg.comm_interface = 30932U; + msg.model = 51306U; + msg.list.assign("OOSDJWKCBADZRRTOXYCRWZAYDAMWKZCZTXVOLJFLBRHNLITLCJSXLRXPYDLCKABNDPRAVFMOPEZEEJOIPIHHJTVXQBINDUHPUOBBBGYEJNZHDKKPLFDPCSEHSWJUWZCIB"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblRange #1", msg == *msg_d); + test.boolean("CommSystemsQuery #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4301,21 +4568,23 @@ main(void) } { - IMC::LblRange msg; - msg.setTimeStamp(0.731325772788); - msg.setSource(13384U); - msg.setSourceEntity(122U); - msg.setDestination(17721U); - msg.setDestinationEntity(1U); - msg.id = 238U; - msg.range = 0.355337682946; + IMC::CommSystemsQuery msg; + msg.setTimeStamp(0.19521030129161987); + msg.setSource(60698U); + msg.setSourceEntity(44U); + msg.setDestination(41164U); + msg.setDestinationEntity(195U); + msg.type = 233U; + msg.comm_interface = 38406U; + msg.model = 25511U; + msg.list.assign("PNLQSAXHCALIMJZCRKCYGFOXMKUOBDZGEHQMRXVRMYHAQYVEISHOJXULMFYQRZPPDUOEOGIFCKUBWPGXKSHJTSLURLEMAUCNQGIOLUXJFOJBQHSWZLDMXNFWCKZJGAJWTW"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblRange #2", msg == *msg_d); + test.boolean("CommSystemsQuery #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4326,26 +4595,29 @@ main(void) } { - IMC::LblBeacon msg; - msg.setTimeStamp(0.24385315123); - msg.setSource(40813U); - msg.setSourceEntity(101U); - msg.setDestination(37568U); - msg.setDestinationEntity(159U); - msg.beacon.assign("ZKAAIMECENEWQFDMNFYEGEJMKKHXWBXAFPXUCHUOMYHELNFOUQLDSRARRBITTITJFSHZESVKAZBCHZMWGBALLXZWJFRVLKIPVFAYJSIVSICATLJUSBPQUYOUDOXJGTXXDCAKRUMEHOYPPLLBVRM"); - msg.lat = 0.41006556601; - msg.lon = 0.308916069176; - msg.depth = 0.746518986866; - msg.query_channel = 129U; - msg.reply_channel = 113U; - msg.transponder_delay = 111U; + IMC::TelemetryMsg msg; + msg.setTimeStamp(0.7372351354659586); + msg.setSource(44295U); + msg.setSourceEntity(37U); + msg.setDestination(23343U); + msg.setDestinationEntity(233U); + msg.type = 199U; + msg.req_id = 2998171365U; + msg.ttl = 25897U; + msg.code = 78U; + msg.destination.assign("KRHHXYHXNJMPKRWWVVLOFBRSMUSBTKTHDWVLFOSKAYGWUKMZQVWIDOBXSYJCPAOCJNQZIVCGGCZQGNTCEIFLYJRDXUFUPJVIPIVSNPXYPSOL"); + msg.source.assign("LXRNNOPMKHOZIDRWEEEMGNEOKPKOHQDYIHSZSVBALTNMXUJQQYAINDCMEHLKOAQOVESYHUFTQYMOLABGUGJIMTUHHSGRIWJXWJBJSIRSHCPDLXXGYCMXUPWPVKJMZZEGFSTYDNSGRLZPHQTFOHEYCPQBKFWNFBAEUCVXXNFCYWFAKXXLACWIKCMMJTCNNZUOWGBZQDLUATZYRPCDFPSGZBRWUVFJDIVWFBAIKJDJDBGTYLUVARORLTER"); + msg.acknowledge = 137U; + msg.status = 221U; + const signed char tmp_msg_0[] = {-113, 117, -65, -95, 56, 111, -63, 113, 47, 5, 108, -75, -3, 84, 47, -66, -11, -18, -14, 47, 9, 72, -10, -56, 9, -3, -4, 80, 121, -28, -128, -48, -104, -102, 118, 40, 83, 90, -106, -22, 62, 27, -53, 88, -118, -4, 6, -104, 52, -91, -57, 99, -9, -105, 52, 72, -96, -5, -61, -26, -94, -13, 27, -50, -114, -80, 88, 100, -15, -98, -113, 16, -64, -53, -27, 49, -51, -124, 24, -99, 0, -78, -107, -88, -70, 23, 113, 88, 78, 6, 79, 0, -76, -56, 42, 40, -41, -101, -21, 85, 81, -80, 96, 102, 91}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblBeacon #0", msg == *msg_d); + test.boolean("TelemetryMsg #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4356,26 +4628,29 @@ main(void) } { - IMC::LblBeacon msg; - msg.setTimeStamp(0.0387962960611); - msg.setSource(57983U); - msg.setSourceEntity(229U); - msg.setDestination(28893U); - msg.setDestinationEntity(102U); - msg.beacon.assign("HCLVKTINAHEWODXQYDZBTBOQNNHLHBMMFOSCRTRVWRPIZZITGSMTEMOZFQNLNNWSFAWVXLYNBSMBELZPUCDPEJRTZDPMYZGJYVFFULTHKRUKLEUCPKGGAXBGCHJVGRLNIZMJSUGONSUTXOBYQSTXQCAEVDUFHCOBMFCVTEQPFPIYDQAJSORHCJSWDYWIRKNIWLELEIYJWQGBAXQJMIQU"); - msg.lat = 0.338249322219; - msg.lon = 0.794969531345; - msg.depth = 0.831575913988; - msg.query_channel = 19U; - msg.reply_channel = 215U; - msg.transponder_delay = 123U; + IMC::TelemetryMsg msg; + msg.setTimeStamp(0.2881490629978486); + msg.setSource(5212U); + msg.setSourceEntity(155U); + msg.setDestination(6542U); + msg.setDestinationEntity(105U); + msg.type = 176U; + msg.req_id = 917646573U; + msg.ttl = 63626U; + msg.code = 75U; + msg.destination.assign("ATVFZHXAZLAKSWDPETOPXUFVBSSANDBQTQRPQVATSUDRIIXLTMNGYJERZTDNDONBGGVGHCVIXAGLTOOZWFRMJXGPBMQEBVAPKMJKOKBYUDNLXLUSUOYIFORUQVMHJFCJUD"); + msg.source.assign("YOLWIOSNIBTBNTWYJNOPCDJLQKHJEGXOLSQYVVBYLIBESVBMQQTTFXMWXUDYIKWJRTWZQ"); + msg.acknowledge = 32U; + msg.status = 59U; + const signed char tmp_msg_0[] = {-31, 45, 74, 25, 96, 103, 78, -7, 105, -83, 68, -53, -72, -24, 70, -40, -73, 67, 81, -109, -73, 6, -109, -63, -122, -28, -77, -75, -124, -52, 35, -65, 112, 64, -77, -96, -46, -38, -74, -100, -38, 27, 21, -49, 88, 74, 87, 2, 22, 45, 66, 59, 64, -1, 97, -122, -101, -80, 23, 50, 43, 21, 57, 57, -17, 27, 32, 66, -82, 106, -8, -63, 92, 101, 92, 7, 69, 64, -34, -38, -13, 61, 119, -26, -123, -84, -115, -82, -14, -85, -9, -99, -93, 67, 19, 87, -109, -30, 101, 90, 21, 71, 45, -111, 14, 33, -125, 110, 58, -17, 60, -36, -7, 29, 98, 36, 69, -40, 2, -86, -22, 55, 115, -97, -18, 12, 25, -71, -41, -2, -63, 67, -26, 55, 103, 16, 4, -55, 49, -98, -118, -74, 20, -63, 84, -19, -1, 122, 75, -27, 104, 3, -58, -50, 123, 115, 64, -86, -4, -14, 91, -66, -74, -2, 13, 54, -36, 88, 14, -126, -34, -49, -65, -26, 74, 99, -32, 55, 55, 69, -61, 38, 93, -30, 2, -55, -6, 30, 55, -5, -64, 92, 53, -85, 104, -118, 88, -101, 10, -104, -67, -38, -101, -73, 106, 78, -97, -53, 108, -38, 82, 73, -63, 87, -115, -83, 116, -18, -58, 49, -108, 124, -54, -87, 77, 62, 62, -90, 40, 81, 75, 125, 51, -102, 109, -121, 107, 97, -52, -105, -64, 56, 73, -106, 79, -53, 64}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblBeacon #1", msg == *msg_d); + test.boolean("TelemetryMsg #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4386,26 +4661,29 @@ main(void) } { - IMC::LblBeacon msg; - msg.setTimeStamp(0.0111396928108); - msg.setSource(16690U); - msg.setSourceEntity(5U); - msg.setDestination(51009U); - msg.setDestinationEntity(76U); - msg.beacon.assign("LJPQRGGKBONNWORGZUSKRYXEDHFTKPMCSVOCS"); - msg.lat = 0.540849880421; - msg.lon = 0.104680869771; - msg.depth = 0.552146451396; - msg.query_channel = 188U; - msg.reply_channel = 71U; - msg.transponder_delay = 17U; + IMC::TelemetryMsg msg; + msg.setTimeStamp(0.3020815248049068); + msg.setSource(57958U); + msg.setSourceEntity(113U); + msg.setDestination(37129U); + msg.setDestinationEntity(226U); + msg.type = 4U; + msg.req_id = 67505384U; + msg.ttl = 52393U; + msg.code = 140U; + msg.destination.assign("LYDBKTWUHGIWZXMXNRCGAEGCURTAIJRQKPBURYKSPYEYSFIAVLTDTTGCEQUEQESHZXIFRNXRKGDXVUOIGHFCXPGHFTQJXVDZNVDHYGNUCDBOAOMASAYUMBOYVQYOHBOEKHOFMRBQGMQJMOKCSXERWWAPLWTZJMQCBPIPRZTSVNBESAIWO"); + msg.source.assign("LWNHSQURQBMESJPMDXLBWOGLPLEIAWVLVPRTVBDJGANXIJDSKTHXUUAITEGDBLTOZIHFZIFYFVYKXJQHPD"); + msg.acknowledge = 35U; + msg.status = 189U; + const signed char tmp_msg_0[] = {-8, -64, -100, 23, 9, -16, 18, -59, 124, -128, -70, -43, -74, 106, -113, -5, -66, -72, -89, 125, -28, 37, -16, -88, 92, -43, 45, -29, 23, 28, 97, -103, 115, -82, -80, -43, 36, -115, -120, -83, -57, -45, -101, -87, -6, 66, -19, 125, 107, 18, 4, -121, 31, 49, 20, -81, 42, 18, -10, -114, -29, 33, 48, 14, -64, 38, 2, 85, 110, 45, 101, 85, -31, 115, -43, 99, -45, 63, -38, 91, 95, -55, 80, 23, 102, 94, -27}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblBeacon #2", msg == *msg_d); + test.boolean("TelemetryMsg #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4416,20 +4694,21 @@ main(void) } { - IMC::LblConfig msg; - msg.setTimeStamp(0.744000988323); - msg.setSource(31732U); - msg.setSourceEntity(202U); - msg.setDestination(54581U); - msg.setDestinationEntity(151U); - msg.op = 154U; + IMC::LblRange msg; + msg.setTimeStamp(0.7474028604376334); + msg.setSource(35320U); + msg.setSourceEntity(249U); + msg.setDestination(58149U); + msg.setDestinationEntity(213U); + msg.id = 52U; + msg.range = 0.574746101744071; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblConfig #0", msg == *msg_d); + test.boolean("LblRange #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4440,29 +4719,21 @@ main(void) } { - IMC::LblConfig msg; - msg.setTimeStamp(0.80705692441); - msg.setSource(23767U); - msg.setSourceEntity(62U); - msg.setDestination(7094U); - msg.setDestinationEntity(37U); - msg.op = 97U; - IMC::LblBeacon tmp_msg_0; - tmp_msg_0.beacon.assign("JQUCACXUNQITAQIGUHKEJZOVOJWGOUABMJOIPCQGAVNUTYSYNVJATYLRJZXNULGDLKHCUNVXXUZWPLTTGWGVLFHFEORYBLRHLDPRGPEWQWJESSLENDZYDRWFVGQREIBWCYCZKIMAFYKPCTTSMXRNFEKIUORDETNYWLZITKIMBKODTBBMHSSAHZDLCHSNA"); - tmp_msg_0.lat = 0.303496379148; - tmp_msg_0.lon = 0.736685977318; - tmp_msg_0.depth = 0.630882018721; - tmp_msg_0.query_channel = 74U; - tmp_msg_0.reply_channel = 161U; - tmp_msg_0.transponder_delay = 194U; - msg.beacons.push_back(tmp_msg_0); + IMC::LblRange msg; + msg.setTimeStamp(0.34208143940055225); + msg.setSource(56368U); + msg.setSourceEntity(132U); + msg.setDestination(52901U); + msg.setDestinationEntity(66U); + msg.id = 149U; + msg.range = 0.3443875657961267; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblConfig #1", msg == *msg_d); + test.boolean("LblRange #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4473,29 +4744,21 @@ main(void) } { - IMC::LblConfig msg; - msg.setTimeStamp(0.695997539558); - msg.setSource(6406U); - msg.setSourceEntity(70U); - msg.setDestination(61284U); - msg.setDestinationEntity(214U); - msg.op = 222U; - IMC::LblBeacon tmp_msg_0; - tmp_msg_0.beacon.assign("LZCERKOPORTRNNONTOMYLUVUCOQZJCAGGWSEBKWEQGSBVXQAAPYFPRKXEYZSRMQWXPUWJSAOZKVYEPZCFLCMFRQLHZPILIVNCYJUJXNCHHHNSWAVOVFNGUVNYDKDUWBLRIBDVQZMORFJXBQEYGTHODGCCTJDKZHEXXTGXIBKPBUYAFZHZWWB"); - tmp_msg_0.lat = 0.383878503151; - tmp_msg_0.lon = 0.974761391532; - tmp_msg_0.depth = 0.860975697726; - tmp_msg_0.query_channel = 17U; - tmp_msg_0.reply_channel = 37U; - tmp_msg_0.transponder_delay = 239U; - msg.beacons.push_back(tmp_msg_0); + IMC::LblRange msg; + msg.setTimeStamp(0.336623083945892); + msg.setSource(65170U); + msg.setSourceEntity(75U); + msg.setDestination(11989U); + msg.setDestinationEntity(180U); + msg.id = 159U; + msg.range = 0.9644396194600644; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblConfig #2", msg == *msg_d); + test.boolean("LblRange #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4506,29 +4769,26 @@ main(void) } { - IMC::AcousticMessage msg; - msg.setTimeStamp(0.612736284481); - msg.setSource(56708U); - msg.setSourceEntity(247U); - msg.setDestination(25117U); - msg.setDestinationEntity(254U); - IMC::HistoricSonarData tmp_msg_0; - tmp_msg_0.altitude = 0.996289817626; - tmp_msg_0.width = 0.481595327212; - tmp_msg_0.length = 0.557859969322; - tmp_msg_0.bearing = 0.308314517568; - tmp_msg_0.pxl = -17000; - tmp_msg_0.encoding = 65U; - const char tmp_tmp_msg_0_0[] = {-32, -118, -114, -76, -21, 74, -100, 53, -72, 73}; - tmp_msg_0.sonar_data.assign(tmp_tmp_msg_0_0, tmp_tmp_msg_0_0 + sizeof(tmp_tmp_msg_0_0)); - msg.message.set(tmp_msg_0); + IMC::LblBeacon msg; + msg.setTimeStamp(0.4254551404677366); + msg.setSource(24284U); + msg.setSourceEntity(88U); + msg.setDestination(15096U); + msg.setDestinationEntity(72U); + msg.beacon.assign("JMRPGNEWDXRYCHUMAOYSQAGLQBEXMLCHZAQUNKOBWLVTWGRPMPIUBFXWYOTNPQVBCSIMPVYOSBNVDUVQKGESSCLGVXUVGQHNSLHJFBOPUCNWVTLBTYAJLWMZVPRJFNMSGNKKQBEAKHRZJK"); + msg.lat = 0.7872583644491215; + msg.lon = 0.6883088660092739; + msg.depth = 0.5433394894988198; + msg.query_channel = 218U; + msg.reply_channel = 22U; + msg.transponder_delay = 128U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticMessage #0", msg == *msg_d); + test.boolean("LblBeacon #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4539,35 +4799,26 @@ main(void) } { - IMC::AcousticMessage msg; - msg.setTimeStamp(0.635875622119); - msg.setSource(10230U); - msg.setSourceEntity(173U); - msg.setDestination(20082U); - msg.setDestinationEntity(95U); - IMC::FormationPlanExecution tmp_msg_0; - tmp_msg_0.group_name.assign("TISDOVLQIAGPRMIEDRFBVXHAKPDKPQATZGILLCPCBOEFSKHBOBBDNLGSLPFSPXMYFJFIUOIUKFZNHVMROUURVOFZTKGKQLQMWQVXYQSERUHVUOCXNLGYGJDNGPAANAZTYKLDJDMVCPLSAVPMEYWOLAANXGRUGXXMI"); - tmp_msg_0.formation_name.assign("TWLUFROJBFYTALEEYZLAGSPCI"); - tmp_msg_0.plan_id.assign("YBPQZEJAGEWVXSWFNEHGSZXSTFIRKDJCFSVDBRIXBTMILDOBKNADWFXSUCCCZVBXIPZDRHOSDVYMLIMTZTLEWEMNHCGCRKKXBWQUKLTXAFRBCJWJBGHVSAJOPHFL"); - tmp_msg_0.description.assign("RBNEFDPHMQWTHPYBZKUXXLIRQFDAXJVQJECHLFGDPQGPHLZYGYGGBGZRDTMDLWHVREZOOMTDQCAFSCVGESEMFXIQKXLDV"); - tmp_msg_0.leader_speed = 0.0793717674403; - tmp_msg_0.leader_bank_lim = 0.163097145777; - tmp_msg_0.pos_sim_err_lim = 0.99558022177; - tmp_msg_0.pos_sim_err_wrn = 0.997946641928; - tmp_msg_0.pos_sim_err_timeout = 50509U; - tmp_msg_0.converg_max = 0.331607368568; - tmp_msg_0.converg_timeout = 57791U; - tmp_msg_0.comms_timeout = 31735U; - tmp_msg_0.turb_lim = 0.399775623443; - tmp_msg_0.custom.assign("KJVYONQTQBSZIWDVNFPWTQUEKUBVYAIJHKJPTUNMHVWWQEBERGAXNCRTXPRGLBZUEFGJNRSUVSFLQMMFDUMZQPVKGKYZUNPXOLCIUNAKWXTCMHOWZEONQHRTGVSATHLZKDWFCEYOIZZKOLWBKXLGMGCCRJYYVIRHNMIDZOAUVIXJ"); - msg.message.set(tmp_msg_0); + IMC::LblBeacon msg; + msg.setTimeStamp(0.17102641624603432); + msg.setSource(32345U); + msg.setSourceEntity(84U); + msg.setDestination(35518U); + msg.setDestinationEntity(12U); + msg.beacon.assign("NKMAWTRBIIOCLKRBRZPFSUDONRJHPCKWM"); + msg.lat = 0.043136289722294885; + msg.lon = 0.08594220919451334; + msg.depth = 0.9547565070442685; + msg.query_channel = 93U; + msg.reply_channel = 140U; + msg.transponder_delay = 236U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticMessage #1", msg == *msg_d); + test.boolean("LblBeacon #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4578,24 +4829,26 @@ main(void) } { - IMC::AcousticMessage msg; - msg.setTimeStamp(0.988308709281); - msg.setSource(18956U); - msg.setSourceEntity(38U); - msg.setDestination(31135U); - msg.setDestinationEntity(25U); - IMC::TrexCommand tmp_msg_0; - tmp_msg_0.command = 149U; - tmp_msg_0.goal_id.assign("CMHYYUHUKVVHWJLCVZTMXFDRXKBMOOPCTZCAKRDCPFQBWJOQPLLRZSUZONAEMJWMJTQBIQBPBZJEXIGHTYDXJGHRMUDWILIEJHKY"); - tmp_msg_0.goal_xml.assign("PGYNYKOBSFLUBWMPU"); - msg.message.set(tmp_msg_0); + IMC::LblBeacon msg; + msg.setTimeStamp(0.6179881751619775); + msg.setSource(39107U); + msg.setSourceEntity(99U); + msg.setDestination(41116U); + msg.setDestinationEntity(2U); + msg.beacon.assign("MCGJHZBMVGBSFWSRGAKSIUECZEWUDNMKZMWMDGBVGKVZQNZOQCFETKORHOUJLAYYFYKADDBHHUQNEJQDERCXPGYABLXVWQDWTUPSCJYWSB"); + msg.lat = 0.1589998158239755; + msg.lon = 0.8255485717745017; + msg.depth = 0.005008171227103064; + msg.query_channel = 200U; + msg.reply_channel = 124U; + msg.transponder_delay = 109U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticMessage #2", msg == *msg_d); + test.boolean("LblBeacon #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4606,26 +4859,20 @@ main(void) } { - IMC::AcousticOperation msg; - msg.setTimeStamp(0.446649727576); - msg.setSource(58717U); - msg.setSourceEntity(171U); - msg.setDestination(6966U); - msg.setDestinationEntity(151U); - msg.op = 222U; - msg.system.assign("VYSUYATMXYTGONEQCJXHLWWFCXIHAFPWKSDMQNUYKGRTETQKREMFUIDAEGVRJCFGOHSWWRICXPGJQOQLSTJUHKMDPUPRVUOBILFEMUQKBFLXCXGZEYSOIDYZEAKSWXBKHDQELXKDRULDMWVZXEBRLPIVEYCBZZWVNCVHPQYKNFDNYSNGNAMOMARLTDJNAKFZCSILNPVQWAZJZGSRJIDOPYBCBHTRVQNHABXPZAIJ"); - msg.range = 0.834632106176; - IMC::SetControlSurfaceDeflection tmp_msg_0; - tmp_msg_0.id = 158U; - tmp_msg_0.angle = 0.192697187488; - msg.msg.set(tmp_msg_0); + IMC::LblConfig msg; + msg.setTimeStamp(0.2232374077619501); + msg.setSource(52085U); + msg.setSourceEntity(132U); + msg.setDestination(30604U); + msg.setDestinationEntity(214U); + msg.op = 37U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticOperation #0", msg == *msg_d); + test.boolean("LblConfig #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4636,25 +4883,20 @@ main(void) } { - IMC::AcousticOperation msg; - msg.setTimeStamp(0.961611549739); - msg.setSource(47050U); - msg.setSourceEntity(68U); - msg.setDestination(11943U); - msg.setDestinationEntity(201U); - msg.op = 203U; - msg.system.assign("RILFPXUUEFUSYIIGGYQOKHLGFUTSCIHTBXMDTRAVXNRLCJGTCTHESTCVRIPDFNZNYKQYGDMENSAQOKAICKIJRBRMYDKGDHVBCIQFRYPPZWEKGHTBSANLZSVV"); - msg.range = 0.948256721184; - IMC::Salinity tmp_msg_0; - tmp_msg_0.value = 0.177474607361; - msg.msg.set(tmp_msg_0); + IMC::LblConfig msg; + msg.setTimeStamp(0.4520760528444431); + msg.setSource(295U); + msg.setSourceEntity(74U); + msg.setDestination(51427U); + msg.setDestinationEntity(105U); + msg.op = 23U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticOperation #1", msg == *msg_d); + test.boolean("LblConfig #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4665,24 +4907,29 @@ main(void) } { - IMC::AcousticOperation msg; - msg.setTimeStamp(0.721649833942); - msg.setSource(38047U); - msg.setSourceEntity(63U); - msg.setDestination(13081U); - msg.setDestinationEntity(147U); - msg.op = 89U; - msg.system.assign("JVZTFWNAFOHVPAJOEEAHWYQUMTSINJSCBBIWIEIQOBTAUMEFYSDQQDRFLTMDLONCWDLEQKTTKXJSDJUJAFYFCGLKGZJKODNFIUYXKYAQPREHXMHDBBEDACZWLPTQIVVUNCLXRHZXJBRIQFNVXXUKOMOEVRXDCHAKGGOLVPCMWIUDHTIKJSETXUSUZZPBMZRKPRQAPUAMZNRJLFBYCWKSGHMSHYCFPNZVIYBNWLOWEGVSGLC"); - msg.range = 0.75434956101; - IMC::QueryPowerChannelState tmp_msg_0; - msg.msg.set(tmp_msg_0); + IMC::LblConfig msg; + msg.setTimeStamp(0.13901268629657704); + msg.setSource(50419U); + msg.setSourceEntity(19U); + msg.setDestination(22170U); + msg.setDestinationEntity(252U); + msg.op = 187U; + IMC::LblBeacon tmp_msg_0; + tmp_msg_0.beacon.assign("LEVKORFVYJMILCOOEGQZSENICNKBAYNRRTMRVLWFOJPYJGEBPCJJCMXEBQDBMUUSGQMYSYCTVUUWKNLTEOVHXCSEKK"); + tmp_msg_0.lat = 0.018026565822912066; + tmp_msg_0.lon = 0.056156416722770164; + tmp_msg_0.depth = 0.013324053536291736; + tmp_msg_0.query_channel = 89U; + tmp_msg_0.reply_channel = 85U; + tmp_msg_0.transponder_delay = 174U; + msg.beacons.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticOperation #2", msg == *msg_d); + test.boolean("LblConfig #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4693,19 +4940,28 @@ main(void) } { - IMC::AcousticSystemsQuery msg; - msg.setTimeStamp(0.939840957335); - msg.setSource(29467U); - msg.setSourceEntity(230U); - msg.setDestination(41331U); - msg.setDestinationEntity(240U); + IMC::AcousticMessage msg; + msg.setTimeStamp(0.9534442714598276); + msg.setSource(11043U); + msg.setSourceEntity(103U); + msg.setDestination(60708U); + msg.setDestinationEntity(4U); + IMC::CacheControl tmp_msg_0; + tmp_msg_0.op = 33U; + tmp_msg_0.snapshot.assign("JDKQQRSYLFVEJZOMDPXXEMPMDWIUNXCXWEISTTACPOXESFICZKRVBAHZQYVLKZCDPQZVGXMAZNEHKDKVIODCWKWUPIQOWOUNOGBCPHQBYDMYCJLPFZXKYPXQWTEOSIVUJQHYBRFWGSSLGALIGSJZHHGTJMMRBOMJDMHXBTNAAFKLGHATREUVIBFYNLHLFWHRUPAUCCSKYFDGCBRLONNVETSAMXIFNBVFKQVBEEYZWUYGWSGJJRNTQTO"); + IMC::SmsStatus tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.req_id = 10493U; + tmp_tmp_msg_0_0.status = 244U; + tmp_tmp_msg_0_0.info.assign("WNEXUOZQPIBBZTLACQHDHZVSPTGGZDTZDSVTLJAOMDZYYEMRNTZUIQRJHKSERILXBXLCFQTEDFEIXWUHBKQRCWQXFSSMJRRLAVWLUFKUPFJUBLJPIVBGOEYEXQKYCBOGPUSFYEUHGHEQDAAWKZFIHHGOIDGHKCWSAMVCQ"); + tmp_msg_0.message.set(tmp_tmp_msg_0_0); + msg.message.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticSystemsQuery #0", msg == *msg_d); + test.boolean("AcousticMessage #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4716,19 +4972,23 @@ main(void) } { - IMC::AcousticSystemsQuery msg; - msg.setTimeStamp(0.0180630051075); - msg.setSource(6531U); - msg.setSourceEntity(3U); - msg.setDestination(4156U); - msg.setDestinationEntity(22U); + IMC::AcousticMessage msg; + msg.setTimeStamp(0.9377556257339317); + msg.setSource(35964U); + msg.setSourceEntity(198U); + msg.setDestination(41708U); + msg.setDestinationEntity(254U); + IMC::PowerChannelState tmp_msg_0; + tmp_msg_0.name.assign("SHSOOFWYYYBINRKNNPCWYJPVFMVDBBWPYVWXLHZ"); + tmp_msg_0.state = 245U; + msg.message.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticSystemsQuery #1", msg == *msg_d); + test.boolean("AcousticMessage #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4739,19 +4999,39 @@ main(void) } { - IMC::AcousticSystemsQuery msg; - msg.setTimeStamp(0.173214972013); - msg.setSource(36387U); - msg.setSourceEntity(59U); - msg.setDestination(41760U); - msg.setDestinationEntity(156U); + IMC::AcousticMessage msg; + msg.setTimeStamp(0.4734485334775248); + msg.setSource(57193U); + msg.setSourceEntity(210U); + msg.setDestination(40904U); + msg.setDestinationEntity(254U); + IMC::SimulatedState tmp_msg_0; + tmp_msg_0.lat = 0.5141464009344372; + tmp_msg_0.lon = 0.3370212733599627; + tmp_msg_0.height = 0.7578766235038937; + tmp_msg_0.x = 0.11736587450583669; + tmp_msg_0.y = 0.7530210780264026; + tmp_msg_0.z = 0.2878995285481615; + tmp_msg_0.phi = 0.40315216984656876; + tmp_msg_0.theta = 0.3669622362362416; + tmp_msg_0.psi = 0.11156254438843927; + tmp_msg_0.u = 0.7391905414991358; + tmp_msg_0.v = 0.4449608807122931; + tmp_msg_0.w = 0.6252677383781813; + tmp_msg_0.p = 0.4149107754274767; + tmp_msg_0.q = 0.1572254647118312; + tmp_msg_0.r = 0.06545852319158751; + tmp_msg_0.svx = 0.2830559372232335; + tmp_msg_0.svy = 0.5591681772408365; + tmp_msg_0.svz = 0.1078425659955935; + msg.message.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticSystemsQuery #2", msg == *msg_d); + test.boolean("AcousticMessage #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4762,20 +5042,31 @@ main(void) } { - IMC::AcousticSystems msg; - msg.setTimeStamp(0.373474432949); - msg.setSource(57356U); - msg.setSourceEntity(145U); - msg.setDestination(1531U); - msg.setDestinationEntity(48U); - msg.list.assign("TFUUFRINDPSYJBPERXUZHWNYMIUTWMDDSPJGGJSRNRILIHGJMVBQNOJAPZTGAXEANUFTZDZTTVXGQLWCQGBVGEHCBGEOSQNQCKVXPHLKOCRUSWSQNMSXFHMTEKKCKBVYUVOOKPFHNJLYEEVZNQTRIQKXLOFMJYERQYNHCBPEXFG"); + IMC::SimAcousticMessage msg; + msg.setTimeStamp(0.21704225390506504); + msg.setSource(62267U); + msg.setSourceEntity(168U); + msg.setDestination(37472U); + msg.setDestinationEntity(224U); + msg.lat = 0.3445403236519421; + msg.lon = 0.21802129374050672; + msg.depth = 0.8589203855842753; + msg.sentence.assign("TRSXDHXSTGLZNSMKOVCWZRSBPAJDSNDIKGPGWEYHUMXPMWMUTORFYDEZRGEOHEJLLZTHSIYVXRFZQJZFTTNQPVNFHCLERQJBHDKMKHQJBSALKGNGWCKVZMQFOYPQIIZOGKIAJRASDIDLIXWWCXJOWUWIUFAPHEKSFQVDYRJYYUPGSULUEARNJFQBRMBNTVMOVBQILQYKJULCCNPGATACPLYNBFDFAYKXGNEPWACZBEXTBVOOTC"); + msg.txtime = 0.08508110299934268; + msg.modem_type.assign("KLQTJSOYECMKTOKZMCWMSKKVPPUZPRFIIRXNHYUJBQFEJPXENTAZCBJNFADVGMXYXMNBECCKIEWRSQDTAPEXVDQFKLILAKFUAVZGCJZRFDUNTRBQBQNDOJDOQWEVKPZNCDHMHFARVLBHOWIWALXXJNWGZJQSJMHUGXTYILQSDAVVKYAHWTSDPYGCZBHXSYULULYVBO"); + msg.sys_src.assign("VURLTNZVXPRZKPFBGTMZKPKHOFIBYLIMNHXXSVXOTQBXKJOZHPIGBWPFTMARLYBODNWQCLAWCAJKTBCUARTJGKFWHQFEEXNVPDJMZJKCYUJSKQMEIMCZMVXGQQUUSYKUEHMLAYVIDGIQWGSNCSVMRSCXROIOWEDCPQFHDPWUHGTANAXURBD"); + msg.seq = 37552U; + msg.sys_dst.assign("LTRLFFLSIBNXDRSWVQCHVDEZPXCQRYABMPUFYBBKEVRNKKPWJAPOMOMHPXBXYTISNSPNGAUGMFEIAKKTHALZXLRGSHPNGVNFMJJXCHCHTXWKEPDJTSQKOQHRNMWGCZHYWVCAOSCGFQMDYDVYCTUNQQVUMUYFI"); + msg.flags = 159U; + const signed char tmp_msg_0[] = {39, -47, 101, -4, -22, 122, 93, 44, -78, 39, -86, 62, 78, -37, -16, 20, 77, 82, -19, 40, -38, -4, 74, -111, 122, 124, 126, -105, 118, 110, -73, 17, 38, -71, -29, 108, 101, -87, -13, 21, -93, -23, 112, -33, -28, 69, -7, -49, -52, 56, -93, -24, 124, 87, 45, -76, 10, 25, 8, -105, -119, -1, 95, -14, -81, -53, 105, 77, 91, 71, -25, 55, -97, -94, -11, 42, -60, 125, 112, 124, 8, -11, -31, 11, 113, -59, -32, 12, -64, -110, 71, -116, -72, -58, 64, 78, 6, -54, 45, 106, 45, 17, -19, -10, -96, -78, -2, 62, -102, -87, 48, 43, -115, 92, 47, 12, -94, -116, -22, -18, 115, -102, 11, 41, 81, -114, 78, 72, -86, 123, 1, 10, -73, 106, 30, -40, -68, -113, 109, -68, -47, 118, -28, -68, 5, -128, 12, -83, 72, 17, 97, 97, 92, -2}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticSystems #0", msg == *msg_d); + test.boolean("SimAcousticMessage #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4786,20 +5077,31 @@ main(void) } { - IMC::AcousticSystems msg; - msg.setTimeStamp(0.762100743619); - msg.setSource(36973U); - msg.setSourceEntity(158U); - msg.setDestination(40760U); - msg.setDestinationEntity(112U); - msg.list.assign("XXNDMWTUAZZELBAOPVUTENVTQAQZKMBCKPSOUKXJODZNSFYMADDRTMXQGHUNOQEKNHHFUSSBJLBVAGPFWWKJSYXIDHRUBPTHQIKIQPDAFFCKFZHLZVDFIGXMLAEDCZXLPXLBYHPIRTFWQFGNMYFWYVCBICCGZRIGHZEVCGECUVCBQ"); + IMC::SimAcousticMessage msg; + msg.setTimeStamp(0.992755309476024); + msg.setSource(64327U); + msg.setSourceEntity(2U); + msg.setDestination(8442U); + msg.setDestinationEntity(24U); + msg.lat = 0.9909335013245163; + msg.lon = 0.6753305210977248; + msg.depth = 0.5989731083897307; + msg.sentence.assign("ILIEGKNLVMIGCUNNSLKLHCAQXJPKTOXYJZXCJXWZINFFIUSGFYHBAVWTDSGGRAGPZVMFKXNSDNPMZDJJMRRHMEWOOIWCVAOBRVEWAEFBDUVAROJOSXBDKQVHTZQPPFMQUYNMRHQEILEBJKXEHRNLWTUYQBFHLMYWOLCEUYDHQCDRZIGLYPSXJNBOSCQZDYCLDAXFUVWTQTPVKFCBFEKKCPUTJDTMHSWMJGZSBATUZOZIYYAWG"); + msg.txtime = 0.6340783181925927; + msg.modem_type.assign("MWCJKFHQMXXLACGNLJYKBBLKAGMFAUNYCDGKMTFXNPWXSZRWLVOCPTGIHICFVLBHWFVPGSTPDVCPTADEEBMDMGFTAEUADSHZZBWNUHHVGJAOMRHOJIFEQRWAJRPRYOUYZ"); + msg.sys_src.assign("SCVEXDCBJVPWJRJMSTAAKNHUQTIUBIILDSQYOBMHGECKMUETADLJMKIDULSTHPCNPNFHKUVIQLLLQRVEKCSEEYRZZELF"); + msg.seq = 7234U; + msg.sys_dst.assign("MKZQWZFBUPDFZBKBXYUGNSOCANGLIEKQVBXOAVLZCJRWNDHUDUYBNACWKKIXVYXCJJMRIETXMEPAN"); + msg.flags = 200U; + const signed char tmp_msg_0[] = {-3, 73, -94, 70, -104, -78, -19, -42, -96, -74, -84, -99, 25, 28, 72, 61, -93, -96, 121, 1, 100, -33, 113, 14, 31, -43, -58, -66, 88, -84, -103, 62, -13, 110, -10, -24, -59, 18, -103, 104, 44, -114, 80, 60, -2, 32, 100, 6, -13, -54, -119, 39, -7, 36, -46, -88, -16, -102, -53, -64, -66, 36, -86, 125, 34, 67, -116, -113, -98, -46, 116, 92, 17, -98, 74, -93, 117, -70, 103, -33, -44, -125, 0, 6, -97, -88, 29, 71, -69, -6, -4, 2, 108, -50, -78, 16, 56, 76, -95, 97, 68, 65, 26, 115, 118, -16, 24, -20, 51, -50, 70, -126, -105, 70, 81, 113, 31, -32, 83, 79, -7, 15, -112, -9, -82, 93, 52, -70, -97, 26, 68, -106, 102, -24, 69, 106, -117, 67, 122, 1, -102, 6, -24, 51, 47, -63, 84, 116, -70, 13, -88}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticSystems #1", msg == *msg_d); + test.boolean("SimAcousticMessage #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4810,20 +5112,31 @@ main(void) } { - IMC::AcousticSystems msg; - msg.setTimeStamp(0.326745376305); - msg.setSource(24596U); - msg.setSourceEntity(204U); - msg.setDestination(43117U); - msg.setDestinationEntity(178U); - msg.list.assign("GKICBXDEGBZPZCPWDVYHLDIEKKGRSJSAVMSLRMAUAZDJDHCOWUGQQVGOGCKAVBLVLGQNFKCWNZZXSFTUSFDXEWVJBJ"); + IMC::SimAcousticMessage msg; + msg.setTimeStamp(0.7397752703051079); + msg.setSource(3401U); + msg.setSourceEntity(146U); + msg.setDestination(47473U); + msg.setDestinationEntity(173U); + msg.lat = 0.3299867646754171; + msg.lon = 0.5557707352979111; + msg.depth = 0.4814471777780359; + msg.sentence.assign("NAHWZHZIXPQFQVSULYHJDEFMPCAQDLAMBKEQESYGOFTYTMWJTQZJLCNHYNZHVBSTISGXCRECULMLRVNUYBVKRDYIDPVHVGOZUIZTPAXYLJILXXMFQMCGAXN"); + msg.txtime = 0.9963804543912456; + msg.modem_type.assign("FJDOCVUYPXDKJQHIVECBBVSHNNBKCFFYMXQYFFVQLWLTYNQJZWBFHAKRLNNREJJTSJEISQMNDXZCDRVWCMJKTFOXEGIVFPGNUNLEMNGRCWJSZRWDUYRWIVGBMJMPMMSTAFKQIOSPBLXUTZAOHLWVATOUOAMWPTJIFBGRYEZCYISBWXABOPIHXLGRYDCHULO"); + msg.sys_src.assign("QLOCVHYWTTZGVGPNHROTMJEBIZCCTHDAIXXVJMMLUS"); + msg.seq = 35301U; + msg.sys_dst.assign("ENUWYPUHOCQCDRPJHDCNWXPRA"); + msg.flags = 226U; + const signed char tmp_msg_0[] = {-101, -124, -37, 86, -21, 4, 83, -94, -89, -33, 2, 79, 23, -109, -65, -47, 1, -6, 4, 21, -34, -100, -26, 68, -35, -4, 42, 85, 40, 95, 61, -54, -5, -48, 105, 118, -33, 17, 89, 100, -36, 0, -32, 125, 120, 109, -66, -44, 59, -49, -92, -120, -111, -103, -63, 32, -48, 22, 44, -100, 101, -68, 115, 106, -42, -36, -33, -31, -102, 58, 19, -113, -29, 97, -35, -104, -121, 8, -19, -24, -30, -5, -92, -75, -43, 87, -62, -97, -78, -49, -94, -78, 42, 109, -7, 36, 66, -39, 69, -117, -120, -85, 57, -69, -114}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticSystems #2", msg == *msg_d); + test.boolean("SimAcousticMessage #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4834,22 +5147,33 @@ main(void) } { - IMC::AcousticLink msg; - msg.setTimeStamp(0.69580911738); - msg.setSource(39130U); - msg.setSourceEntity(62U); - msg.setDestination(43386U); - msg.setDestinationEntity(65U); - msg.peer.assign("QAZOFNQFBMYQGESWVDIFVCBMZRJDJEPXRAVRKASTWRGGEUVYKYIOSLQRMASYHUISKSGHVYPUMXQIXQJMPJYLHQIOZWHNXTZLCGSJZUMXZZDXYINAKWLLRFACNIOUDFUSYHIVUIEHTEOUN"); - msg.rssi = 0.349204600934; - msg.integrity = 824U; + IMC::AcousticOperation msg; + msg.setTimeStamp(0.5113950578220701); + msg.setSource(30778U); + msg.setSourceEntity(179U); + msg.setDestination(36320U); + msg.setDestinationEntity(126U); + msg.op = 60U; + msg.system.assign("XHLLQQXFOSZWOENGUKHYMDNFJIMAEFIIQGOBCUPLBCVAXSWQVAMTBNGCZJFKJNORJRRVJGVPTKGEKFRFJUJRDMYYLUAGAZWVUNCVMUWOOACTZLCNYTZALVEXXQOPGEMINBTHDWWPOGMEJPEHQFWGNWCDTDRLYWYHBXPXTNVPLRKMJECEMUUEHZQTXIOBNAKDIIADSQHPZRKSYP"); + msg.range = 0.30755289118606266; + IMC::NavigationData tmp_msg_0; + tmp_msg_0.bias_psi = 0.3783130106980779; + tmp_msg_0.bias_r = 0.15248730585793346; + tmp_msg_0.cog = 0.8017306612085516; + tmp_msg_0.cyaw = 0.9543347097013891; + tmp_msg_0.lbl_rej_level = 0.28970674367635085; + tmp_msg_0.gps_rej_level = 0.7276464162065712; + tmp_msg_0.custom_x = 0.5862049529799718; + tmp_msg_0.custom_y = 0.23934603786782926; + tmp_msg_0.custom_z = 0.7936086999297833; + msg.msg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticLink #0", msg == *msg_d); + test.boolean("AcousticOperation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4860,22 +5184,26 @@ main(void) } { - IMC::AcousticLink msg; - msg.setTimeStamp(0.959113098873); - msg.setSource(7092U); - msg.setSourceEntity(57U); - msg.setDestination(2965U); - msg.setDestinationEntity(201U); - msg.peer.assign("OXUDFTSAPMZCKHQMXHQYYIZCQLQJLFEYUGYJPNSNOJVMQUAJZHWMCBYEXOMGHSTDHZWKNQXWXPDJXAQQQJGGXLTZFEMCPJGDTVWSMTZRVPWMCRTLDLASPNUIDNFIAYWCECDBTVFPKAGJUELVQDYRAOKNLEHLGRELZIUTIVRIRBHBICBRYKUVOFJOERFKZSF"); - msg.rssi = 0.150357411053; - msg.integrity = 54968U; + IMC::AcousticOperation msg; + msg.setTimeStamp(0.9510788584726414); + msg.setSource(19392U); + msg.setSourceEntity(104U); + msg.setDestination(33484U); + msg.setDestinationEntity(21U); + msg.op = 3U; + msg.system.assign("BHODNMNWJBVEXSFPMMUPVTTHLCCFXOINJXHXRJKPICRVSMYGQESUYZVOFOLKNFLGIPCGZCJWCZJZYDNPYMKDWROUNXLILBQSLTBXWQAECPSSQQFHGQSAUY"); + msg.range = 0.9544252080003643; + IMC::IoEvent tmp_msg_0; + tmp_msg_0.type = 28U; + tmp_msg_0.error.assign("LNMHQGWHOFDXWWVKTXOOMCETFCAQPMTHPCKBXREDHEFUAIYGJUXTVTYWSLVJOFOFPDZLMFVUXNNBQTDQRZAAUPMBLIRNOSEWYSNBGZNKXICEHAVVNJPMQRNNEKQYYXAQYUDRSGCGWZFEJBDYBLRQNVTUIQCJTPKAHKGMSMJKJGICAUBCLBKXHVPADPJLRREWRQFDZIHIBUTVSLPWXKGZMYZWHVWSJTOIIAMODOPFZGIHFUJCSX"); + msg.msg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticLink #1", msg == *msg_d); + test.boolean("AcousticOperation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4886,22 +5214,26 @@ main(void) } { - IMC::AcousticLink msg; - msg.setTimeStamp(0.989325825221); - msg.setSource(27849U); - msg.setSourceEntity(105U); - msg.setDestination(11419U); - msg.setDestinationEntity(101U); - msg.peer.assign("FXCRBEVNOCAQYWDUPSPNOHJVEODBTABCKGDWVSIWLJPEYFGAQWOIXJGRTTHTSUQSGHXOMPRI"); - msg.rssi = 0.330652177563; - msg.integrity = 46006U; + IMC::AcousticOperation msg; + msg.setTimeStamp(0.9188451592961979); + msg.setSource(19421U); + msg.setSourceEntity(214U); + msg.setDestination(1131U); + msg.setDestinationEntity(156U); + msg.op = 190U; + msg.system.assign("UOJNJDUHUZYCLIQFHZQVLEX"); + msg.range = 0.6732970513544247; + IMC::EntityList tmp_msg_0; + tmp_msg_0.op = 212U; + tmp_msg_0.list.assign("MMGKGQXRYZLPLWVVBOKHRGFVAGFWFMMTILMZDWALFCEETLXGDZNWISNTDQLWNHNZXOPDJSUEYOESKEVWOOHWANJLQXDIKZJCNCXEKTPVOCSKEJRBTAWPXJRKYBYVOMKIZYLVFGWNYANUJBOCAGBUSQRSMYOVUANE"); + msg.msg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AcousticLink #2", msg == *msg_d); + test.boolean("AcousticOperation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4912,20 +5244,19 @@ main(void) } { - IMC::Rpm msg; - msg.setTimeStamp(0.223428534596); - msg.setSource(29894U); - msg.setSourceEntity(249U); - msg.setDestination(21887U); - msg.setDestinationEntity(62U); - msg.value = 14523; + IMC::AcousticSystemsQuery msg; + msg.setTimeStamp(0.8055155385020406); + msg.setSource(54146U); + msg.setSourceEntity(39U); + msg.setDestination(22188U); + msg.setDestinationEntity(182U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Rpm #0", msg == *msg_d); + test.boolean("AcousticSystemsQuery #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4936,20 +5267,19 @@ main(void) } { - IMC::Rpm msg; - msg.setTimeStamp(0.933068958932); - msg.setSource(27472U); - msg.setSourceEntity(187U); - msg.setDestination(51025U); - msg.setDestinationEntity(86U); - msg.value = 19482; + IMC::AcousticSystemsQuery msg; + msg.setTimeStamp(0.2682389451281123); + msg.setSource(47950U); + msg.setSourceEntity(172U); + msg.setDestination(1605U); + msg.setDestinationEntity(201U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Rpm #1", msg == *msg_d); + test.boolean("AcousticSystemsQuery #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4960,20 +5290,19 @@ main(void) } { - IMC::Rpm msg; - msg.setTimeStamp(0.917273282592); - msg.setSource(22755U); - msg.setSourceEntity(64U); - msg.setDestination(1386U); - msg.setDestinationEntity(89U); - msg.value = 32604; + IMC::AcousticSystemsQuery msg; + msg.setTimeStamp(0.3683107233826276); + msg.setSource(30779U); + msg.setSourceEntity(132U); + msg.setDestination(55366U); + msg.setDestinationEntity(134U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Rpm #2", msg == *msg_d); + test.boolean("AcousticSystemsQuery #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -4984,20 +5313,20 @@ main(void) } { - IMC::Voltage msg; - msg.setTimeStamp(0.191964568877); - msg.setSource(6230U); - msg.setSourceEntity(13U); - msg.setDestination(33582U); - msg.setDestinationEntity(159U); - msg.value = 0.408632702115; + IMC::AcousticSystems msg; + msg.setTimeStamp(0.918733240636606); + msg.setSource(42783U); + msg.setSourceEntity(201U); + msg.setDestination(36122U); + msg.setDestinationEntity(225U); + msg.list.assign("RCQKHVQTWYICBIPPEDNGDWLCCYWPDFPUQVCTIRUAUEXQOOAYSUPGLAWPVSAADOXMYRHVQXXVGGVNSZBOIHKWJITYFMKGCTAXQBXJPJBFWAJRIDTASUJCNLXZHMOFGMNJMDYFXTWHBIZHUYEONNLIXYSAFUJCBVKDLPIKFQERMBKHRDGWFITCMTUSSQLTZHYHCJBJRKRDHVGLAOEXWRNLREOBZEKMZKPYFMB"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Voltage #0", msg == *msg_d); + test.boolean("AcousticSystems #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5008,20 +5337,20 @@ main(void) } { - IMC::Voltage msg; - msg.setTimeStamp(0.633800455857); - msg.setSource(887U); - msg.setSourceEntity(207U); - msg.setDestination(60338U); - msg.setDestinationEntity(177U); - msg.value = 0.133942297524; + IMC::AcousticSystems msg; + msg.setTimeStamp(0.7399446193361634); + msg.setSource(48308U); + msg.setSourceEntity(202U); + msg.setDestination(27215U); + msg.setDestinationEntity(156U); + msg.list.assign("IUBXNZODVLMNPTIIVEXCJTAKYMBZLGZTTHSZEGOJSRUDCBPZNMKTGJFMFZUHSQELJISVJLDUWYOAPFRCBGCTFWVQWRLRJASQXZXAOAPYHWKKBSIRALQMERDEYHRHHRGQFJDINWWXYMLNOCJVSQNGNTDQDBVFZRKNXUQGKEOTIBPVPHLKGBEWOFCWICAOMDCUPHHJXUOEYNMHPWVSOASXMSYFQUDBULQZUFKNKZTCMEIYYWJDVAGTBALIVYEFC"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Voltage #1", msg == *msg_d); + test.boolean("AcousticSystems #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5032,20 +5361,20 @@ main(void) } { - IMC::Voltage msg; - msg.setTimeStamp(0.836265670844); - msg.setSource(60265U); - msg.setSourceEntity(145U); - msg.setDestination(31753U); - msg.setDestinationEntity(110U); - msg.value = 0.793097957613; + IMC::AcousticSystems msg; + msg.setTimeStamp(0.07837201119538029); + msg.setSource(59056U); + msg.setSourceEntity(208U); + msg.setDestination(39921U); + msg.setDestinationEntity(86U); + msg.list.assign("NSIMFYDDZCOFGKDTXYOVIOVUEFTVWIXHOGONBOWLKSGYEKXLTPZQLNOPWQTIPSEGFANMWKPCYXCEEHBLHWQILMRFJTQSQJDGJTBVXZDRAJREABYPAYVNMIBAEJGVBHIDBNDZCRLFWSQWKPSVWPTIZDUBEMSAULOZAY"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Voltage #2", msg == *msg_d); + test.boolean("AcousticSystems #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5056,20 +5385,22 @@ main(void) } { - IMC::Current msg; - msg.setTimeStamp(0.856134838781); - msg.setSource(17826U); - msg.setSourceEntity(38U); - msg.setDestination(42366U); - msg.setDestinationEntity(3U); - msg.value = 0.784686309719; + IMC::AcousticLink msg; + msg.setTimeStamp(0.0695669557939016); + msg.setSource(44999U); + msg.setSourceEntity(150U); + msg.setDestination(41533U); + msg.setDestinationEntity(150U); + msg.peer.assign("YDPDHBKZTYSROLJADIPTMOWZGFVSPEDYMIOJMYSFPGEAYRKETUBRFXPKVTAHXENDFBDZNQUHNHSFCACTIXLMYZMGOYQTRCEWDQVGGGPRDHIIJITRJEERATSMQGZQRKALEJUTSJUBYWMQKGQJASSXM"); + msg.rssi = 0.8553072916579975; + msg.integrity = 28020U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Current #0", msg == *msg_d); + test.boolean("AcousticLink #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5080,20 +5411,22 @@ main(void) } { - IMC::Current msg; - msg.setTimeStamp(0.471844088876); - msg.setSource(47377U); - msg.setSourceEntity(16U); - msg.setDestination(12664U); - msg.setDestinationEntity(251U); - msg.value = 0.456275210184; + IMC::AcousticLink msg; + msg.setTimeStamp(0.9966945510567295); + msg.setSource(13829U); + msg.setSourceEntity(45U); + msg.setDestination(3759U); + msg.setDestinationEntity(9U); + msg.peer.assign("PLKGHUOYMFLNUATHAIGJKPBPVMCIDOTARBXGFPDTTZXTWOZSMENLAYJBZVPQYQBIKZWMTLHFCSZIRJSBXYNLEFUFMHUCILUGISHCSEMSKHNAKGWGHDHONVATWFMTFZKQOWMDBSZPRYTRR"); + msg.rssi = 0.44033879470834125; + msg.integrity = 29749U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Current #1", msg == *msg_d); + test.boolean("AcousticLink #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5104,20 +5437,22 @@ main(void) } { - IMC::Current msg; - msg.setTimeStamp(0.266509362186); - msg.setSource(19908U); - msg.setSourceEntity(226U); - msg.setDestination(34431U); - msg.setDestinationEntity(215U); - msg.value = 0.16385290503; + IMC::AcousticLink msg; + msg.setTimeStamp(0.5494991987255474); + msg.setSource(6006U); + msg.setSourceEntity(108U); + msg.setDestination(43370U); + msg.setDestinationEntity(98U); + msg.peer.assign("APGTUMIWRQJRTGVWYJQXWCOWNGQEYHGPZMGNUNNGUKBKKEJHDPKFJSEECZRJMQZIIFVBQITRBRAOTRDJVANAKOPXESFCGFANGXMEBHHDHYDCLLBKPMURYFOFWNDHYWTRSTINSWNNYJUWMCXFGI"); + msg.rssi = 0.30787246334608764; + msg.integrity = 3046U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Current #2", msg == *msg_d); + test.boolean("AcousticLink #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5128,35 +5463,38 @@ main(void) } { - IMC::GpsFix msg; - msg.setTimeStamp(0.960774435757); - msg.setSource(32115U); - msg.setSourceEntity(168U); - msg.setDestination(45058U); - msg.setDestinationEntity(25U); - msg.validity = 18877U; - msg.type = 169U; - msg.utc_year = 45353U; - msg.utc_month = 169U; - msg.utc_day = 220U; - msg.utc_time = 0.442671554297; - msg.lat = 0.770611017475; - msg.lon = 0.335491834456; - msg.height = 0.536978175236; - msg.satellites = 28U; - msg.cog = 0.0950203105618; - msg.sog = 0.098392178641; - msg.hdop = 0.174342926994; - msg.vdop = 0.501700964395; - msg.hacc = 0.326656511704; - msg.vacc = 0.315446343113; + IMC::AcousticRequest msg; + msg.setTimeStamp(0.26094910427378626); + msg.setSource(31961U); + msg.setSourceEntity(122U); + msg.setDestination(21580U); + msg.setDestinationEntity(50U); + msg.req_id = 52575U; + msg.destination.assign("OJJOTQYDDETQISKQUPMEWUUGIBZKYQQYJFPAIIVDNCZFYDYLVYXAUHNLBVWIURRWMKEPVDADBAXTOSQKNBXXOPNMJQZMTKFATURSYEFPHDLHEXACHGTRGZFUVWTRKXPMITFFWBGNAIYNWKFVOUCAMCMRSINHEOUZLZWNHQTGVVIKZSLWALQXNREMSMLKEYDRSSBGVPPHLCIB"); + msg.timeout = 0.23153631900258875; + msg.range = 0.4352310576945444; + msg.type = 139U; + IMC::Elevator tmp_msg_0; + tmp_msg_0.timeout = 26950U; + tmp_msg_0.flags = 109U; + tmp_msg_0.lat = 0.7617233616446761; + tmp_msg_0.lon = 0.52947819597267; + tmp_msg_0.start_z = 0.2652818418154127; + tmp_msg_0.start_z_units = 39U; + tmp_msg_0.end_z = 0.24218617890597582; + tmp_msg_0.end_z_units = 96U; + tmp_msg_0.radius = 0.8860654773242922; + tmp_msg_0.speed = 0.3509942584666865; + tmp_msg_0.speed_units = 29U; + tmp_msg_0.custom.assign("AYEYXEHEYDRWKFHDCYSJJNMONCJVPJRIRZXSCZIVXHQEWXMBNSDRPVAPMGCOHDTKFTRITLZTOXBHTJGPBZWVMFKSNBHILZSEANBYWFKBWLQPLEINKYDUQIHLDFVNCDKPXMTZDAOBCCCONBTFBOXXKSZAEGQHUYBNWGFDTTMEYEQQIUOGCSUVHU"); + msg.msg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFix #0", msg == *msg_d); + test.boolean("AcousticRequest #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5167,35 +5505,29 @@ main(void) } { - IMC::GpsFix msg; - msg.setTimeStamp(0.0888669986923); - msg.setSource(25616U); - msg.setSourceEntity(93U); - msg.setDestination(53176U); - msg.setDestinationEntity(232U); - msg.validity = 48191U; - msg.type = 170U; - msg.utc_year = 56051U; - msg.utc_month = 144U; - msg.utc_day = 230U; - msg.utc_time = 0.793719323406; - msg.lat = 0.645813679736; - msg.lon = 0.766356252206; - msg.height = 0.485772161784; - msg.satellites = 212U; - msg.cog = 0.520090185125; - msg.sog = 0.210059702438; - msg.hdop = 0.370169233158; - msg.vdop = 0.800843672462; - msg.hacc = 0.0223237010067; - msg.vacc = 0.786843985627; + IMC::AcousticRequest msg; + msg.setTimeStamp(0.911566276490739); + msg.setSource(10693U); + msg.setSourceEntity(242U); + msg.setDestination(18783U); + msg.setDestinationEntity(93U); + msg.req_id = 46410U; + msg.destination.assign("JULISOMHLRELINUSIDIOWKAOHZRAOAFZGVXNXDLOMSDXNGCBGCBJHCTVFDWYNH"); + msg.timeout = 0.9679019126282836; + msg.range = 0.8795845879172941; + msg.type = 89U; + IMC::AcousticLink tmp_msg_0; + tmp_msg_0.peer.assign("CRQYZNDWIYTHEKXZFEEWVKEOAELRRUGCYEALQLLVQTXHBJHOSBFTLXCHRWOTVFVWNYOTQOFPPWVKJPLKNXCGPHWBAZFPSXUGDZGAYQSJCHRBGHQGUYJQZIWOZSMCDPZRBHMAPLAMKJXMKBZMVMOIRITFKDTMFNXV"); + tmp_msg_0.rssi = 0.9036863296496341; + tmp_msg_0.integrity = 27255U; + msg.msg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFix #1", msg == *msg_d); + test.boolean("AcousticRequest #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5206,35 +5538,36 @@ main(void) } { - IMC::GpsFix msg; - msg.setTimeStamp(0.223508778139); - msg.setSource(46534U); - msg.setSourceEntity(93U); - msg.setDestination(1155U); - msg.setDestinationEntity(28U); - msg.validity = 26643U; - msg.type = 107U; - msg.utc_year = 64027U; - msg.utc_month = 4U; - msg.utc_day = 83U; - msg.utc_time = 0.449432236421; - msg.lat = 0.766647157424; - msg.lon = 0.395748349695; - msg.height = 0.865092298681; - msg.satellites = 212U; - msg.cog = 0.520225043501; - msg.sog = 0.0650950261996; - msg.hdop = 0.585157566145; - msg.vdop = 0.571200918257; - msg.hacc = 0.644639855943; - msg.vacc = 0.591872295475; + IMC::AcousticRequest msg; + msg.setTimeStamp(0.8707069334801927); + msg.setSource(877U); + msg.setSourceEntity(63U); + msg.setDestination(50623U); + msg.setDestinationEntity(113U); + msg.req_id = 25098U; + msg.destination.assign("OKUBSALUCIEPYBQZBOOMXWLLGDSQZYJCGNUOFOBBYPZGMNGSKUGGQQJYKFYNFNTBKYQIOPIYJKRZRFETLWSEXSMNVQLILNENGDEZTHIRLHPKPPJTHWEMCAFYXDBKVMEPBHDVMHAWSICRCFVVPXNBAUZOMNUZTQJOWOWUTQINEYHDVJ"); + msg.timeout = 0.4134229132468229; + msg.range = 0.21138052087571846; + msg.type = 19U; + IMC::AutonomousSection tmp_msg_0; + tmp_msg_0.lat = 0.5550080340883131; + tmp_msg_0.lon = 0.6159408808430965; + tmp_msg_0.speed = 0.48724087153306817; + tmp_msg_0.speed_units = 210U; + tmp_msg_0.limits = 151U; + tmp_msg_0.max_depth = 0.6881290268822042; + tmp_msg_0.min_alt = 0.5611600921513481; + tmp_msg_0.time_limit = 0.07606401267642693; + tmp_msg_0.controller.assign("APQUIHMHSFSIDLBDXNWYACVJFBGJCZBEMYKUXVDUECZPIURKSTRCMOQPPTLZHTDEIKMPZIGIOIKUEJTAYIOTFNLGOSUJNSJMAHJQVWORRBQGJZKEUGXESMVXZELNXCWCAVXZCOULENK"); + tmp_msg_0.custom.assign("PXPFRJZWWACRVJGMPGGCTCLOZWUNKVPXUDMJUKQYNYOMKYQVDHRCAFCAENSOATPKULYOTRBOIBAGHCUULIFSSVIJRKEXYWPDGEBVDRPRUZDMQQYHHWQNJTLVHVPGSMFXWMFBMIAXTXATBPQXTKKDNBWIUZMIZKCJINJTOWBJXIS"); + msg.msg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFix #2", msg == *msg_d); + test.boolean("AcousticRequest #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5245,24 +5578,24 @@ main(void) } { - IMC::EulerAngles msg; - msg.setTimeStamp(0.445175095692); - msg.setSource(54753U); - msg.setSourceEntity(213U); - msg.setDestination(29697U); - msg.setDestinationEntity(96U); - msg.time = 0.493073604286; - msg.phi = 0.213778595416; - msg.theta = 0.197244963754; - msg.psi = 0.726418606597; - msg.psi_magnetic = 0.216141148255; + IMC::AcousticStatus msg; + msg.setTimeStamp(0.10471894108227486); + msg.setSource(46709U); + msg.setSourceEntity(72U); + msg.setDestination(47445U); + msg.setDestinationEntity(29U); + msg.req_id = 19780U; + msg.type = 177U; + msg.status = 226U; + msg.info.assign("PKXTJVYPCSGVCAFQUDIRIMIDTEGQNHUIKESHBQWHQUHUZOIYHEONTLXJXZWMBZVOFAWJSSQWJHMQZTDFENAJRCTCLLKKMRYRPIJEJYXSLUBFIUZLAPFWCCEAKRB"); + msg.range = 0.6696258386775483; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EulerAngles #0", msg == *msg_d); + test.boolean("AcousticStatus #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5273,24 +5606,24 @@ main(void) } { - IMC::EulerAngles msg; - msg.setTimeStamp(0.534937936178); - msg.setSource(38708U); - msg.setSourceEntity(214U); - msg.setDestination(29206U); - msg.setDestinationEntity(21U); - msg.time = 0.305392262703; - msg.phi = 0.423758550824; - msg.theta = 0.255236620566; - msg.psi = 0.772844707692; - msg.psi_magnetic = 0.298135412768; + IMC::AcousticStatus msg; + msg.setTimeStamp(0.2890461949814973); + msg.setSource(27799U); + msg.setSourceEntity(233U); + msg.setDestination(62114U); + msg.setDestinationEntity(155U); + msg.req_id = 11290U; + msg.type = 213U; + msg.status = 126U; + msg.info.assign("CLYCQGQGMQUUXAJFKBTTNVSGTSCHYJVOCXYFRRRSPBPGDINEWNIFNAWZQORPATRDDNGWDJNZYTRFMJXHHZXTVEBJKELTYIUAHYZXVPUTHSODOEMDDISSMYQKPUHJJQAXBLOLANLGWKMWJUQKEHZHVECWWZDOLFKZXFFELKBWR"); + msg.range = 0.18379934366587647; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EulerAngles #1", msg == *msg_d); + test.boolean("AcousticStatus #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5301,24 +5634,24 @@ main(void) } { - IMC::EulerAngles msg; - msg.setTimeStamp(0.663510191114); - msg.setSource(44507U); - msg.setSourceEntity(224U); - msg.setDestination(11926U); - msg.setDestinationEntity(244U); - msg.time = 0.27296462189; - msg.phi = 0.818837707701; - msg.theta = 0.484085210252; - msg.psi = 0.420296979672; - msg.psi_magnetic = 0.0885293546783; + IMC::AcousticStatus msg; + msg.setTimeStamp(0.3549065706226048); + msg.setSource(59834U); + msg.setSourceEntity(139U); + msg.setDestination(27771U); + msg.setDestinationEntity(85U); + msg.req_id = 9227U; + msg.type = 19U; + msg.status = 55U; + msg.info.assign("AJUVSQPCPRQHEFJUWNXYVEDAXUDHHSBKDYCZMDNBKPEJQQCJAWRMJCOOUYINGPTOQZGQWKDDZLFPBYTZVWVCNBLZMTOAMNXCFURXGOFEJMZPSAYYFSLPBITIQWZXG"); + msg.range = 0.9925857424625026; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EulerAngles #2", msg == *msg_d); + test.boolean("AcousticStatus #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5329,24 +5662,20 @@ main(void) } { - IMC::EulerAnglesDelta msg; - msg.setTimeStamp(0.318912925421); - msg.setSource(1292U); - msg.setSourceEntity(38U); - msg.setDestination(19305U); - msg.setDestinationEntity(12U); - msg.time = 0.148964519763; - msg.x = 0.344256935628; - msg.y = 0.618212498876; - msg.z = 0.122945965219; - msg.timestep = 0.256670111374; + IMC::Rpm msg; + msg.setTimeStamp(0.3689762403101723); + msg.setSource(64805U); + msg.setSourceEntity(121U); + msg.setDestination(42524U); + msg.setDestinationEntity(82U); + msg.value = -31797; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EulerAnglesDelta #0", msg == *msg_d); + test.boolean("Rpm #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5357,24 +5686,20 @@ main(void) } { - IMC::EulerAnglesDelta msg; - msg.setTimeStamp(0.431628757358); - msg.setSource(44868U); - msg.setSourceEntity(80U); - msg.setDestination(16968U); - msg.setDestinationEntity(39U); - msg.time = 0.4808515084; - msg.x = 0.979458771258; - msg.y = 0.459528607887; - msg.z = 0.648719840342; - msg.timestep = 0.969162759806; + IMC::Rpm msg; + msg.setTimeStamp(0.12472331554750515); + msg.setSource(32162U); + msg.setSourceEntity(158U); + msg.setDestination(41308U); + msg.setDestinationEntity(243U); + msg.value = 29580; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EulerAnglesDelta #1", msg == *msg_d); + test.boolean("Rpm #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5385,24 +5710,20 @@ main(void) } { - IMC::EulerAnglesDelta msg; - msg.setTimeStamp(0.735344588363); - msg.setSource(31983U); - msg.setSourceEntity(121U); - msg.setDestination(18421U); - msg.setDestinationEntity(220U); - msg.time = 0.665843702394; - msg.x = 0.757974058; - msg.y = 0.601169396034; - msg.z = 0.449163467297; - msg.timestep = 0.977986601047; + IMC::Rpm msg; + msg.setTimeStamp(0.1150430871628173); + msg.setSource(50965U); + msg.setSourceEntity(100U); + msg.setDestination(31752U); + msg.setDestinationEntity(223U); + msg.value = 14200; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EulerAnglesDelta #2", msg == *msg_d); + test.boolean("Rpm #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5413,23 +5734,20 @@ main(void) } { - IMC::AngularVelocity msg; - msg.setTimeStamp(0.819256923329); - msg.setSource(12758U); - msg.setSourceEntity(157U); - msg.setDestination(29890U); - msg.setDestinationEntity(94U); - msg.time = 0.836809076344; - msg.x = 0.486890817491; - msg.y = 0.985207212186; - msg.z = 0.207299767202; + IMC::Voltage msg; + msg.setTimeStamp(0.40314326729907757); + msg.setSource(35178U); + msg.setSourceEntity(201U); + msg.setDestination(31058U); + msg.setDestinationEntity(246U); + msg.value = 0.9892940724246004; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AngularVelocity #0", msg == *msg_d); + test.boolean("Voltage #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5440,23 +5758,20 @@ main(void) } { - IMC::AngularVelocity msg; - msg.setTimeStamp(0.374864163287); - msg.setSource(59603U); - msg.setSourceEntity(73U); - msg.setDestination(10306U); - msg.setDestinationEntity(195U); - msg.time = 0.0346015217562; - msg.x = 0.0770805139343; - msg.y = 0.729316985454; - msg.z = 0.347729074522; + IMC::Voltage msg; + msg.setTimeStamp(0.5646085023644836); + msg.setSource(46149U); + msg.setSourceEntity(202U); + msg.setDestination(19522U); + msg.setDestinationEntity(80U); + msg.value = 0.9439881398208931; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AngularVelocity #1", msg == *msg_d); + test.boolean("Voltage #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5467,23 +5782,20 @@ main(void) } { - IMC::AngularVelocity msg; - msg.setTimeStamp(0.524330899608); - msg.setSource(14624U); - msg.setSourceEntity(72U); - msg.setDestination(55962U); - msg.setDestinationEntity(109U); - msg.time = 0.699039355394; - msg.x = 0.799873420058; - msg.y = 0.0983028864623; - msg.z = 0.870762903881; + IMC::Voltage msg; + msg.setTimeStamp(0.20631026570458566); + msg.setSource(57784U); + msg.setSourceEntity(10U); + msg.setDestination(28120U); + msg.setDestinationEntity(233U); + msg.value = 0.06226071759497909; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AngularVelocity #2", msg == *msg_d); + test.boolean("Voltage #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5494,23 +5806,20 @@ main(void) } { - IMC::Acceleration msg; - msg.setTimeStamp(0.44550350907); - msg.setSource(42993U); - msg.setSourceEntity(193U); - msg.setDestination(58108U); - msg.setDestinationEntity(188U); - msg.time = 0.0331503040144; - msg.x = 0.811704635301; - msg.y = 0.430477690182; - msg.z = 0.417412957226; + IMC::Current msg; + msg.setTimeStamp(0.32299298423397715); + msg.setSource(20129U); + msg.setSourceEntity(39U); + msg.setDestination(157U); + msg.setDestinationEntity(18U); + msg.value = 0.09768720667025133; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Acceleration #0", msg == *msg_d); + test.boolean("Current #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5521,23 +5830,20 @@ main(void) } { - IMC::Acceleration msg; - msg.setTimeStamp(0.70878956662); - msg.setSource(57318U); - msg.setSourceEntity(70U); - msg.setDestination(20113U); - msg.setDestinationEntity(83U); - msg.time = 0.920541173198; - msg.x = 0.391430370191; - msg.y = 0.992689193705; - msg.z = 0.702274089405; + IMC::Current msg; + msg.setTimeStamp(0.5769313149978436); + msg.setSource(59301U); + msg.setSourceEntity(246U); + msg.setDestination(19893U); + msg.setDestinationEntity(172U); + msg.value = 0.7463699842614898; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Acceleration #1", msg == *msg_d); + test.boolean("Current #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5548,23 +5854,20 @@ main(void) } { - IMC::Acceleration msg; - msg.setTimeStamp(0.383354766885); - msg.setSource(43087U); - msg.setSourceEntity(188U); - msg.setDestination(46872U); - msg.setDestinationEntity(253U); - msg.time = 0.863249099372; - msg.x = 0.0429424438686; - msg.y = 0.821206697009; - msg.z = 0.825070831953; + IMC::Current msg; + msg.setTimeStamp(0.7865830097126928); + msg.setSource(51570U); + msg.setSourceEntity(149U); + msg.setDestination(32879U); + msg.setDestinationEntity(209U); + msg.value = 0.6181340886784962; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Acceleration #2", msg == *msg_d); + test.boolean("Current #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5575,23 +5878,35 @@ main(void) } { - IMC::MagneticField msg; - msg.setTimeStamp(0.991856276264); - msg.setSource(23935U); - msg.setSourceEntity(240U); - msg.setDestination(11321U); - msg.setDestinationEntity(18U); - msg.time = 0.496462930107; - msg.x = 0.513114325733; - msg.y = 0.272101094043; - msg.z = 0.882140854881; + IMC::GpsFix msg; + msg.setTimeStamp(0.45191552743429975); + msg.setSource(56934U); + msg.setSourceEntity(101U); + msg.setDestination(336U); + msg.setDestinationEntity(210U); + msg.validity = 286U; + msg.type = 72U; + msg.utc_year = 42349U; + msg.utc_month = 160U; + msg.utc_day = 108U; + msg.utc_time = 0.46484663093958; + msg.lat = 0.08952236468576757; + msg.lon = 0.18783819257428302; + msg.height = 0.26275842700529517; + msg.satellites = 173U; + msg.cog = 0.2878887494978549; + msg.sog = 0.4509798069828642; + msg.hdop = 0.38775728006447774; + msg.vdop = 0.5548920326883303; + msg.hacc = 0.8662006041934159; + msg.vacc = 0.551684949188017; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MagneticField #0", msg == *msg_d); + test.boolean("GpsFix #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5602,23 +5917,35 @@ main(void) } { - IMC::MagneticField msg; - msg.setTimeStamp(0.278719213924); - msg.setSource(61523U); - msg.setSourceEntity(100U); - msg.setDestination(53076U); - msg.setDestinationEntity(82U); - msg.time = 0.742753765771; - msg.x = 0.569037229268; - msg.y = 0.321416992332; - msg.z = 0.803502278223; + IMC::GpsFix msg; + msg.setTimeStamp(0.25233626505911577); + msg.setSource(16535U); + msg.setSourceEntity(56U); + msg.setDestination(54943U); + msg.setDestinationEntity(106U); + msg.validity = 50238U; + msg.type = 75U; + msg.utc_year = 8488U; + msg.utc_month = 68U; + msg.utc_day = 204U; + msg.utc_time = 0.4746089224161316; + msg.lat = 0.2770182908550869; + msg.lon = 0.9458659467174215; + msg.height = 0.6785241891918737; + msg.satellites = 136U; + msg.cog = 0.38895516578092537; + msg.sog = 0.16068031964827378; + msg.hdop = 0.5557655617039909; + msg.vdop = 0.2700763469820783; + msg.hacc = 0.1126986622943974; + msg.vacc = 0.24253971405639074; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MagneticField #1", msg == *msg_d); + test.boolean("GpsFix #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5629,23 +5956,35 @@ main(void) } { - IMC::MagneticField msg; - msg.setTimeStamp(0.519209001446); - msg.setSource(50993U); - msg.setSourceEntity(134U); - msg.setDestination(42519U); - msg.setDestinationEntity(199U); - msg.time = 0.334904889294; - msg.x = 0.871049201765; - msg.y = 0.460721733857; - msg.z = 0.770698946606; + IMC::GpsFix msg; + msg.setTimeStamp(0.10321421943173081); + msg.setSource(25068U); + msg.setSourceEntity(4U); + msg.setDestination(31774U); + msg.setDestinationEntity(7U); + msg.validity = 64876U; + msg.type = 121U; + msg.utc_year = 32360U; + msg.utc_month = 69U; + msg.utc_day = 250U; + msg.utc_time = 0.5900188747645925; + msg.lat = 0.5146027192771614; + msg.lon = 0.6507463761693408; + msg.height = 0.22192289144774946; + msg.satellites = 123U; + msg.cog = 0.8652667088703901; + msg.sog = 0.1907348341848657; + msg.hdop = 0.788269206474709; + msg.vdop = 0.6110958377460053; + msg.hacc = 0.5143186018273573; + msg.vacc = 0.5938388738418959; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MagneticField #2", msg == *msg_d); + test.boolean("GpsFix #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5656,23 +5995,24 @@ main(void) } { - IMC::GroundVelocity msg; - msg.setTimeStamp(0.377663013624); - msg.setSource(30639U); - msg.setSourceEntity(99U); - msg.setDestination(32001U); - msg.setDestinationEntity(229U); - msg.validity = 128U; - msg.x = 0.747130428768; - msg.y = 0.510072097048; - msg.z = 0.194868094979; + IMC::EulerAngles msg; + msg.setTimeStamp(0.3070531003514284); + msg.setSource(14972U); + msg.setSourceEntity(84U); + msg.setDestination(18037U); + msg.setDestinationEntity(170U); + msg.time = 0.8397292453385845; + msg.phi = 0.3038014261428652; + msg.theta = 0.2552739669270494; + msg.psi = 0.559734709416579; + msg.psi_magnetic = 0.8426268127661365; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GroundVelocity #0", msg == *msg_d); + test.boolean("EulerAngles #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5683,23 +6023,24 @@ main(void) } { - IMC::GroundVelocity msg; - msg.setTimeStamp(0.623956269765); - msg.setSource(53140U); - msg.setSourceEntity(231U); - msg.setDestination(58695U); - msg.setDestinationEntity(36U); - msg.validity = 139U; - msg.x = 0.621170551496; - msg.y = 0.534950419594; - msg.z = 0.323381059445; + IMC::EulerAngles msg; + msg.setTimeStamp(0.10555892079491469); + msg.setSource(62328U); + msg.setSourceEntity(102U); + msg.setDestination(1629U); + msg.setDestinationEntity(110U); + msg.time = 0.3779363086540629; + msg.phi = 0.5390620302016912; + msg.theta = 0.7120022218952606; + msg.psi = 0.7031501126504656; + msg.psi_magnetic = 0.12647611410056947; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GroundVelocity #1", msg == *msg_d); + test.boolean("EulerAngles #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5710,23 +6051,24 @@ main(void) } { - IMC::GroundVelocity msg; - msg.setTimeStamp(0.112361228365); - msg.setSource(34569U); - msg.setSourceEntity(179U); - msg.setDestination(42539U); - msg.setDestinationEntity(84U); - msg.validity = 231U; - msg.x = 0.10102454066; - msg.y = 0.410638294884; - msg.z = 0.25152474021; + IMC::EulerAngles msg; + msg.setTimeStamp(0.9569357316738492); + msg.setSource(10534U); + msg.setSourceEntity(101U); + msg.setDestination(61145U); + msg.setDestinationEntity(136U); + msg.time = 0.5917293276281608; + msg.phi = 0.34769985833264694; + msg.theta = 0.8498173424622605; + msg.psi = 0.0659640978546816; + msg.psi_magnetic = 0.3760601318206923; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GroundVelocity #2", msg == *msg_d); + test.boolean("EulerAngles #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5737,23 +6079,24 @@ main(void) } { - IMC::WaterVelocity msg; - msg.setTimeStamp(0.856705782535); - msg.setSource(49752U); - msg.setSourceEntity(183U); - msg.setDestination(53801U); - msg.setDestinationEntity(58U); - msg.validity = 4U; - msg.x = 0.367159445046; - msg.y = 0.639288345651; - msg.z = 0.0343286246786; + IMC::EulerAnglesDelta msg; + msg.setTimeStamp(0.5751101664407225); + msg.setSource(28791U); + msg.setSourceEntity(74U); + msg.setDestination(45134U); + msg.setDestinationEntity(18U); + msg.time = 0.3608555371873535; + msg.x = 0.35581707348159086; + msg.y = 0.8384804512443212; + msg.z = 0.006646533451016068; + msg.timestep = 0.7746075166875118; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WaterVelocity #0", msg == *msg_d); + test.boolean("EulerAnglesDelta #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5764,23 +6107,24 @@ main(void) } { - IMC::WaterVelocity msg; - msg.setTimeStamp(0.150835394047); - msg.setSource(63851U); - msg.setSourceEntity(79U); - msg.setDestination(6783U); - msg.setDestinationEntity(146U); - msg.validity = 244U; - msg.x = 0.10771185848; - msg.y = 0.190744814567; - msg.z = 0.955157946669; + IMC::EulerAnglesDelta msg; + msg.setTimeStamp(0.8155665615596982); + msg.setSource(33286U); + msg.setSourceEntity(37U); + msg.setDestination(55683U); + msg.setDestinationEntity(65U); + msg.time = 0.3852806124451298; + msg.x = 0.03247621518509092; + msg.y = 0.09004803135800532; + msg.z = 0.5959871512503156; + msg.timestep = 0.9743430674746454; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WaterVelocity #1", msg == *msg_d); + test.boolean("EulerAnglesDelta #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5791,23 +6135,24 @@ main(void) } { - IMC::WaterVelocity msg; - msg.setTimeStamp(0.0284820672485); - msg.setSource(28649U); - msg.setSourceEntity(178U); - msg.setDestination(14163U); - msg.setDestinationEntity(59U); - msg.validity = 93U; - msg.x = 0.717185801369; - msg.y = 0.912669899741; - msg.z = 0.566502383605; + IMC::EulerAnglesDelta msg; + msg.setTimeStamp(0.5680760834358114); + msg.setSource(25983U); + msg.setSourceEntity(181U); + msg.setDestination(20409U); + msg.setDestinationEntity(86U); + msg.time = 0.1579969072887938; + msg.x = 0.16407913297916388; + msg.y = 0.711277777175283; + msg.z = 0.872404566124503; + msg.timestep = 0.6676068161574331; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WaterVelocity #2", msg == *msg_d); + test.boolean("EulerAnglesDelta #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5818,23 +6163,23 @@ main(void) } { - IMC::VelocityDelta msg; - msg.setTimeStamp(0.423118354587); - msg.setSource(23365U); - msg.setSourceEntity(159U); - msg.setDestination(59149U); - msg.setDestinationEntity(158U); - msg.time = 0.0591407383174; - msg.x = 0.132649740806; - msg.y = 0.524304228917; - msg.z = 0.160698377642; + IMC::AngularVelocity msg; + msg.setTimeStamp(0.9899591656429957); + msg.setSource(39911U); + msg.setSourceEntity(115U); + msg.setDestination(40262U); + msg.setDestinationEntity(228U); + msg.time = 0.7697672919080241; + msg.x = 0.10373657886727405; + msg.y = 0.10842025556295576; + msg.z = 0.697251790694831; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VelocityDelta #0", msg == *msg_d); + test.boolean("AngularVelocity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5845,23 +6190,23 @@ main(void) } { - IMC::VelocityDelta msg; - msg.setTimeStamp(0.496034864129); - msg.setSource(23522U); - msg.setSourceEntity(191U); - msg.setDestination(42263U); - msg.setDestinationEntity(244U); - msg.time = 0.553677020444; - msg.x = 0.956701521102; - msg.y = 0.137927863684; - msg.z = 0.531459593919; + IMC::AngularVelocity msg; + msg.setTimeStamp(0.02200828846655767); + msg.setSource(32758U); + msg.setSourceEntity(131U); + msg.setDestination(39573U); + msg.setDestinationEntity(172U); + msg.time = 0.8086803554963335; + msg.x = 0.02383271707283552; + msg.y = 0.6931952101481191; + msg.z = 0.31467904912125066; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VelocityDelta #1", msg == *msg_d); + test.boolean("AngularVelocity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5872,23 +6217,23 @@ main(void) } { - IMC::VelocityDelta msg; - msg.setTimeStamp(0.490155292531); - msg.setSource(17567U); - msg.setSourceEntity(133U); - msg.setDestination(40046U); - msg.setDestinationEntity(136U); - msg.time = 0.766853464143; - msg.x = 0.340105358304; - msg.y = 0.21285140104; - msg.z = 0.233464975851; + IMC::AngularVelocity msg; + msg.setTimeStamp(0.21754378720387413); + msg.setSource(14496U); + msg.setSourceEntity(156U); + msg.setDestination(28873U); + msg.setDestinationEntity(200U); + msg.time = 0.10726617217618661; + msg.x = 0.0725569156046908; + msg.y = 0.050707766683017796; + msg.z = 0.7822260881661788; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VelocityDelta #2", msg == *msg_d); + test.boolean("AngularVelocity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5899,33 +6244,23 @@ main(void) } { - IMC::Distance msg; - msg.setTimeStamp(0.591768408094); - msg.setSource(46714U); - msg.setSourceEntity(12U); - msg.setDestination(20251U); - msg.setDestinationEntity(147U); - msg.validity = 84U; - IMC::DeviceState tmp_msg_0; - tmp_msg_0.x = 0.915524335801; - tmp_msg_0.y = 0.773656647494; - tmp_msg_0.z = 0.519807277815; - tmp_msg_0.phi = 0.470849494799; - tmp_msg_0.theta = 0.784149285362; - tmp_msg_0.psi = 0.863476407578; - msg.location.push_back(tmp_msg_0); - IMC::BeamConfig tmp_msg_1; - tmp_msg_1.beam_width = 0.451185450616; - tmp_msg_1.beam_height = 0.946028146738; - msg.beam_config.push_back(tmp_msg_1); - msg.value = 0.230685763199; + IMC::Acceleration msg; + msg.setTimeStamp(0.4205194011475629); + msg.setSource(13185U); + msg.setSourceEntity(158U); + msg.setDestination(29676U); + msg.setDestinationEntity(179U); + msg.time = 0.5650699837319937; + msg.x = 0.5182572428387051; + msg.y = 0.9572929687197138; + msg.z = 0.40337048309535173; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Distance #0", msg == *msg_d); + test.boolean("Acceleration #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5936,21 +6271,23 @@ main(void) } { - IMC::Distance msg; - msg.setTimeStamp(0.771208225515); - msg.setSource(43522U); - msg.setSourceEntity(23U); - msg.setDestination(60516U); - msg.setDestinationEntity(179U); - msg.validity = 237U; - msg.value = 0.0648511096656; + IMC::Acceleration msg; + msg.setTimeStamp(0.737681800998243); + msg.setSource(2398U); + msg.setSourceEntity(161U); + msg.setDestination(63488U); + msg.setDestinationEntity(43U); + msg.time = 0.6633952476034362; + msg.x = 0.9223240609327209; + msg.y = 0.00884810987797513; + msg.z = 0.2563866010240372; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Distance #1", msg == *msg_d); + test.boolean("Acceleration #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5961,29 +6298,23 @@ main(void) } { - IMC::Distance msg; - msg.setTimeStamp(0.763721550996); - msg.setSource(30238U); - msg.setSourceEntity(204U); - msg.setDestination(15295U); - msg.setDestinationEntity(66U); - msg.validity = 226U; - IMC::DeviceState tmp_msg_0; - tmp_msg_0.x = 0.0653251396343; - tmp_msg_0.y = 0.422403339976; - tmp_msg_0.z = 0.904350369023; - tmp_msg_0.phi = 0.495731349547; - tmp_msg_0.theta = 0.439726694304; - tmp_msg_0.psi = 0.0679381165993; - msg.location.push_back(tmp_msg_0); - msg.value = 0.226184059192; + IMC::Acceleration msg; + msg.setTimeStamp(0.38835621405510456); + msg.setSource(21683U); + msg.setSourceEntity(193U); + msg.setDestination(15711U); + msg.setDestinationEntity(98U); + msg.time = 0.33484088268107515; + msg.x = 0.7712307218842028; + msg.y = 0.33922261636087814; + msg.z = 0.10912487708606988; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Distance #2", msg == *msg_d); + test.boolean("Acceleration #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -5994,20 +6325,23 @@ main(void) } { - IMC::Temperature msg; - msg.setTimeStamp(0.941305184996); - msg.setSource(20635U); - msg.setSourceEntity(143U); - msg.setDestination(31114U); - msg.setDestinationEntity(136U); - msg.value = 0.651767666485; + IMC::MagneticField msg; + msg.setTimeStamp(0.132189541719424); + msg.setSource(4599U); + msg.setSourceEntity(79U); + msg.setDestination(21007U); + msg.setDestinationEntity(14U); + msg.time = 0.9686614030820592; + msg.x = 0.3880108418225685; + msg.y = 0.11906682439114524; + msg.z = 0.08216496923092464; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Temperature #0", msg == *msg_d); + test.boolean("MagneticField #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6018,20 +6352,23 @@ main(void) } { - IMC::Temperature msg; - msg.setTimeStamp(0.958202135905); - msg.setSource(3918U); - msg.setSourceEntity(215U); - msg.setDestination(11257U); - msg.setDestinationEntity(26U); - msg.value = 0.414050012096; + IMC::MagneticField msg; + msg.setTimeStamp(0.24414633551622233); + msg.setSource(61116U); + msg.setSourceEntity(66U); + msg.setDestination(60818U); + msg.setDestinationEntity(146U); + msg.time = 0.920068627801746; + msg.x = 0.7187658773230994; + msg.y = 0.37898396709503324; + msg.z = 0.9312012436904539; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Temperature #1", msg == *msg_d); + test.boolean("MagneticField #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6042,20 +6379,23 @@ main(void) } { - IMC::Temperature msg; - msg.setTimeStamp(0.62403011729); - msg.setSource(46060U); - msg.setSourceEntity(225U); - msg.setDestination(50007U); - msg.setDestinationEntity(35U); - msg.value = 0.261469414442; + IMC::MagneticField msg; + msg.setTimeStamp(0.5903655037103254); + msg.setSource(15602U); + msg.setSourceEntity(66U); + msg.setDestination(60161U); + msg.setDestinationEntity(157U); + msg.time = 0.6338932654219156; + msg.x = 0.6392583790309815; + msg.y = 0.5203231949741738; + msg.z = 0.09958368669048157; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Temperature #2", msg == *msg_d); + test.boolean("MagneticField #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6066,20 +6406,23 @@ main(void) } { - IMC::Pressure msg; - msg.setTimeStamp(0.949496119614); - msg.setSource(47944U); - msg.setSourceEntity(129U); - msg.setDestination(36597U); - msg.setDestinationEntity(28U); - msg.value = 0.141032485007; + IMC::GroundVelocity msg; + msg.setTimeStamp(0.9471931988234252); + msg.setSource(18926U); + msg.setSourceEntity(87U); + msg.setDestination(4680U); + msg.setDestinationEntity(202U); + msg.validity = 99U; + msg.x = 0.3354196156027581; + msg.y = 0.8903090339848138; + msg.z = 0.8130953441660494; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Pressure #0", msg == *msg_d); + test.boolean("GroundVelocity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6090,20 +6433,23 @@ main(void) } { - IMC::Pressure msg; - msg.setTimeStamp(0.99435848579); - msg.setSource(13738U); - msg.setSourceEntity(205U); - msg.setDestination(22649U); - msg.setDestinationEntity(143U); - msg.value = 0.946639132938; + IMC::GroundVelocity msg; + msg.setTimeStamp(0.14914622158524782); + msg.setSource(56628U); + msg.setSourceEntity(215U); + msg.setDestination(26885U); + msg.setDestinationEntity(216U); + msg.validity = 154U; + msg.x = 0.9667376413276983; + msg.y = 0.5838403771603153; + msg.z = 0.7695523142733628; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Pressure #1", msg == *msg_d); + test.boolean("GroundVelocity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6114,20 +6460,23 @@ main(void) } { - IMC::Pressure msg; - msg.setTimeStamp(0.544907662689); - msg.setSource(63204U); - msg.setSourceEntity(16U); - msg.setDestination(63963U); - msg.setDestinationEntity(131U); - msg.value = 0.817401223497; + IMC::GroundVelocity msg; + msg.setTimeStamp(0.2923561320854803); + msg.setSource(53679U); + msg.setSourceEntity(54U); + msg.setDestination(65433U); + msg.setDestinationEntity(254U); + msg.validity = 226U; + msg.x = 0.8439636144985665; + msg.y = 0.1423941874046447; + msg.z = 0.9576047570695433; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Pressure #2", msg == *msg_d); + test.boolean("GroundVelocity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6138,20 +6487,23 @@ main(void) } { - IMC::Depth msg; - msg.setTimeStamp(0.375478287007); - msg.setSource(58988U); - msg.setSourceEntity(14U); - msg.setDestination(56302U); - msg.setDestinationEntity(188U); - msg.value = 0.830628853936; + IMC::WaterVelocity msg; + msg.setTimeStamp(0.9522255790152854); + msg.setSource(28473U); + msg.setSourceEntity(25U); + msg.setDestination(51698U); + msg.setDestinationEntity(49U); + msg.validity = 121U; + msg.x = 0.22230819082293152; + msg.y = 0.04190383138160769; + msg.z = 0.7725837643616084; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Depth #0", msg == *msg_d); + test.boolean("WaterVelocity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6162,20 +6514,23 @@ main(void) } { - IMC::Depth msg; - msg.setTimeStamp(0.0592048497408); - msg.setSource(31895U); - msg.setSourceEntity(177U); - msg.setDestination(10996U); - msg.setDestinationEntity(26U); - msg.value = 0.717897891711; + IMC::WaterVelocity msg; + msg.setTimeStamp(0.44622304995610285); + msg.setSource(37757U); + msg.setSourceEntity(23U); + msg.setDestination(28066U); + msg.setDestinationEntity(88U); + msg.validity = 104U; + msg.x = 0.1631159426119252; + msg.y = 0.4128926268730929; + msg.z = 0.5136209117641759; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Depth #1", msg == *msg_d); + test.boolean("WaterVelocity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6186,20 +6541,23 @@ main(void) } { - IMC::Depth msg; - msg.setTimeStamp(0.952552921412); - msg.setSource(28143U); - msg.setSourceEntity(254U); - msg.setDestination(27685U); - msg.setDestinationEntity(192U); - msg.value = 0.615131687659; + IMC::WaterVelocity msg; + msg.setTimeStamp(0.45155682428833943); + msg.setSource(30666U); + msg.setSourceEntity(186U); + msg.setDestination(37726U); + msg.setDestinationEntity(123U); + msg.validity = 28U; + msg.x = 0.45091292456963716; + msg.y = 0.7835543571948793; + msg.z = 0.884502798826779; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Depth #2", msg == *msg_d); + test.boolean("WaterVelocity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6210,20 +6568,23 @@ main(void) } { - IMC::DepthOffset msg; - msg.setTimeStamp(0.740262385261); - msg.setSource(50900U); - msg.setSourceEntity(103U); - msg.setDestination(63364U); - msg.setDestinationEntity(214U); - msg.value = 0.90473026305; + IMC::VelocityDelta msg; + msg.setTimeStamp(0.6118874295242809); + msg.setSource(52100U); + msg.setSourceEntity(71U); + msg.setDestination(41054U); + msg.setDestinationEntity(217U); + msg.time = 0.752804907323554; + msg.x = 0.2366842300720028; + msg.y = 0.6687066028598392; + msg.z = 0.4700928147755036; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DepthOffset #0", msg == *msg_d); + test.boolean("VelocityDelta #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6234,20 +6595,23 @@ main(void) } { - IMC::DepthOffset msg; - msg.setTimeStamp(0.0419467733868); - msg.setSource(22553U); - msg.setSourceEntity(59U); - msg.setDestination(50802U); - msg.setDestinationEntity(183U); - msg.value = 0.787737221041; + IMC::VelocityDelta msg; + msg.setTimeStamp(0.30146746851079886); + msg.setSource(36567U); + msg.setSourceEntity(189U); + msg.setDestination(7035U); + msg.setDestinationEntity(164U); + msg.time = 0.6591977447800457; + msg.x = 0.5683265107592083; + msg.y = 0.8241167186653425; + msg.z = 0.34900599998660564; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DepthOffset #1", msg == *msg_d); + test.boolean("VelocityDelta #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6258,20 +6622,23 @@ main(void) } { - IMC::DepthOffset msg; - msg.setTimeStamp(0.956762095039); - msg.setSource(6902U); - msg.setSourceEntity(31U); - msg.setDestination(44672U); - msg.setDestinationEntity(218U); - msg.value = 0.277474058262; + IMC::VelocityDelta msg; + msg.setTimeStamp(0.6807918834282952); + msg.setSource(48518U); + msg.setSourceEntity(20U); + msg.setDestination(49565U); + msg.setDestinationEntity(144U); + msg.time = 0.04177255415672754; + msg.x = 0.9876154382486418; + msg.y = 0.6221972368086023; + msg.z = 0.14561118329093892; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DepthOffset #2", msg == *msg_d); + test.boolean("VelocityDelta #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6282,20 +6649,29 @@ main(void) } { - IMC::SoundSpeed msg; - msg.setTimeStamp(0.88418671675); - msg.setSource(17661U); - msg.setSourceEntity(167U); - msg.setDestination(2668U); - msg.setDestinationEntity(234U); - msg.value = 0.504178375082; + IMC::Distance msg; + msg.setTimeStamp(0.21677577116007862); + msg.setSource(22313U); + msg.setSourceEntity(127U); + msg.setDestination(15093U); + msg.setDestinationEntity(26U); + msg.validity = 202U; + IMC::DeviceState tmp_msg_0; + tmp_msg_0.x = 0.13604194881777298; + tmp_msg_0.y = 0.22083705740718884; + tmp_msg_0.z = 0.5641868375389383; + tmp_msg_0.phi = 0.7815863831980894; + tmp_msg_0.theta = 0.2890100976964659; + tmp_msg_0.psi = 0.13812787041841645; + msg.location.push_back(tmp_msg_0); + msg.value = 0.5965146092890702; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SoundSpeed #0", msg == *msg_d); + test.boolean("Distance #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6306,20 +6682,25 @@ main(void) } { - IMC::SoundSpeed msg; - msg.setTimeStamp(0.499910382875); - msg.setSource(56346U); - msg.setSourceEntity(49U); - msg.setDestination(40525U); - msg.setDestinationEntity(185U); - msg.value = 0.669039876459; + IMC::Distance msg; + msg.setTimeStamp(0.4409033782228795); + msg.setSource(35544U); + msg.setSourceEntity(152U); + msg.setDestination(60551U); + msg.setDestinationEntity(200U); + msg.validity = 118U; + IMC::BeamConfig tmp_msg_0; + tmp_msg_0.beam_width = 0.8897010875871296; + tmp_msg_0.beam_height = 0.32052249225687346; + msg.beam_config.push_back(tmp_msg_0); + msg.value = 0.04036013079749157; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SoundSpeed #1", msg == *msg_d); + test.boolean("Distance #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6330,20 +6711,29 @@ main(void) } { - IMC::SoundSpeed msg; - msg.setTimeStamp(0.432371034272); - msg.setSource(43410U); - msg.setSourceEntity(47U); - msg.setDestination(47194U); - msg.setDestinationEntity(168U); - msg.value = 0.377119442235; + IMC::Distance msg; + msg.setTimeStamp(0.053578555219052526); + msg.setSource(24239U); + msg.setSourceEntity(7U); + msg.setDestination(19757U); + msg.setDestinationEntity(221U); + msg.validity = 231U; + IMC::DeviceState tmp_msg_0; + tmp_msg_0.x = 0.8860548838816901; + tmp_msg_0.y = 0.14142956815231345; + tmp_msg_0.z = 0.17245180142718985; + tmp_msg_0.phi = 0.35248044988557425; + tmp_msg_0.theta = 0.4034095902680874; + tmp_msg_0.psi = 0.049294736303719944; + msg.location.push_back(tmp_msg_0); + msg.value = 0.35852701884995297; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SoundSpeed #2", msg == *msg_d); + test.boolean("Distance #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6354,20 +6744,20 @@ main(void) } { - IMC::WaterDensity msg; - msg.setTimeStamp(0.100474299732); - msg.setSource(49804U); - msg.setSourceEntity(43U); - msg.setDestination(42802U); - msg.setDestinationEntity(218U); - msg.value = 0.318878429204; + IMC::Temperature msg; + msg.setTimeStamp(0.7836911907670686); + msg.setSource(64614U); + msg.setSourceEntity(32U); + msg.setDestination(14347U); + msg.setDestinationEntity(183U); + msg.value = 0.04172523429313346; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WaterDensity #0", msg == *msg_d); + test.boolean("Temperature #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6378,20 +6768,20 @@ main(void) } { - IMC::WaterDensity msg; - msg.setTimeStamp(0.981033412636); - msg.setSource(47095U); - msg.setSourceEntity(235U); - msg.setDestination(8969U); - msg.setDestinationEntity(103U); - msg.value = 0.098634416492; + IMC::Temperature msg; + msg.setTimeStamp(0.21665240632538507); + msg.setSource(23993U); + msg.setSourceEntity(133U); + msg.setDestination(58318U); + msg.setDestinationEntity(49U); + msg.value = 0.42810069421111097; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WaterDensity #1", msg == *msg_d); + test.boolean("Temperature #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6402,20 +6792,20 @@ main(void) } { - IMC::WaterDensity msg; - msg.setTimeStamp(0.458627593416); - msg.setSource(51185U); - msg.setSourceEntity(242U); - msg.setDestination(37973U); - msg.setDestinationEntity(148U); - msg.value = 0.818103417599; + IMC::Temperature msg; + msg.setTimeStamp(0.05664059755437478); + msg.setSource(23920U); + msg.setSourceEntity(145U); + msg.setDestination(37933U); + msg.setDestinationEntity(4U); + msg.value = 0.2844391589241443; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WaterDensity #2", msg == *msg_d); + test.boolean("Temperature #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6426,20 +6816,20 @@ main(void) } { - IMC::Conductivity msg; - msg.setTimeStamp(0.445343305936); - msg.setSource(1168U); - msg.setSourceEntity(162U); - msg.setDestination(1896U); - msg.setDestinationEntity(43U); - msg.value = 0.735252433383; + IMC::Pressure msg; + msg.setTimeStamp(0.8146438740024579); + msg.setSource(32751U); + msg.setSourceEntity(158U); + msg.setDestination(35544U); + msg.setDestinationEntity(68U); + msg.value = 0.7575314903166751; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Conductivity #0", msg == *msg_d); + test.boolean("Pressure #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6450,20 +6840,20 @@ main(void) } { - IMC::Conductivity msg; - msg.setTimeStamp(0.211590001085); - msg.setSource(56380U); - msg.setSourceEntity(202U); - msg.setDestination(55846U); - msg.setDestinationEntity(201U); - msg.value = 0.848082015032; + IMC::Pressure msg; + msg.setTimeStamp(0.1802164453779962); + msg.setSource(26195U); + msg.setSourceEntity(157U); + msg.setDestination(22967U); + msg.setDestinationEntity(78U); + msg.value = 0.781849251753175; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Conductivity #1", msg == *msg_d); + test.boolean("Pressure #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6474,20 +6864,20 @@ main(void) } { - IMC::Conductivity msg; - msg.setTimeStamp(0.50467960474); - msg.setSource(18569U); - msg.setSourceEntity(181U); - msg.setDestination(13130U); - msg.setDestinationEntity(245U); - msg.value = 0.750358693175; - + IMC::Pressure msg; + msg.setTimeStamp(0.40240909688262216); + msg.setSource(54847U); + msg.setSourceEntity(198U); + msg.setDestination(45273U); + msg.setDestinationEntity(54U); + msg.value = 0.10830594201275523; + try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Conductivity #2", msg == *msg_d); + test.boolean("Pressure #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6498,20 +6888,20 @@ main(void) } { - IMC::Salinity msg; - msg.setTimeStamp(0.38538898326); - msg.setSource(30692U); - msg.setSourceEntity(194U); - msg.setDestination(62500U); - msg.setDestinationEntity(98U); - msg.value = 0.788652150217; + IMC::Depth msg; + msg.setTimeStamp(0.9513601862619977); + msg.setSource(60625U); + msg.setSourceEntity(21U); + msg.setDestination(14934U); + msg.setDestinationEntity(83U); + msg.value = 0.9545073764603526; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Salinity #0", msg == *msg_d); + test.boolean("Depth #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6522,20 +6912,20 @@ main(void) } { - IMC::Salinity msg; - msg.setTimeStamp(0.829106532001); - msg.setSource(27354U); - msg.setSourceEntity(212U); - msg.setDestination(57569U); - msg.setDestinationEntity(121U); - msg.value = 0.921508391743; + IMC::Depth msg; + msg.setTimeStamp(0.8646596099108116); + msg.setSource(43537U); + msg.setSourceEntity(39U); + msg.setDestination(13949U); + msg.setDestinationEntity(52U); + msg.value = 0.23244317657094504; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Salinity #1", msg == *msg_d); + test.boolean("Depth #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6546,20 +6936,20 @@ main(void) } { - IMC::Salinity msg; - msg.setTimeStamp(0.527178044438); - msg.setSource(22208U); - msg.setSourceEntity(95U); - msg.setDestination(5302U); - msg.setDestinationEntity(12U); - msg.value = 0.550777902411; + IMC::Depth msg; + msg.setTimeStamp(0.3259126788161343); + msg.setSource(37855U); + msg.setSourceEntity(87U); + msg.setDestination(15265U); + msg.setDestinationEntity(38U); + msg.value = 0.7384296837219012; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Salinity #2", msg == *msg_d); + test.boolean("Depth #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6570,22 +6960,20 @@ main(void) } { - IMC::WindSpeed msg; - msg.setTimeStamp(0.433232078546); - msg.setSource(43591U); - msg.setSourceEntity(205U); - msg.setDestination(19365U); - msg.setDestinationEntity(24U); - msg.direction = 0.908196606013; - msg.speed = 0.516543592839; - msg.turbulence = 0.640357108315; + IMC::DepthOffset msg; + msg.setTimeStamp(0.3929832173590333); + msg.setSource(16684U); + msg.setSourceEntity(31U); + msg.setDestination(28919U); + msg.setDestinationEntity(0U); + msg.value = 0.641970371936879; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WindSpeed #0", msg == *msg_d); + test.boolean("DepthOffset #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6596,22 +6984,20 @@ main(void) } { - IMC::WindSpeed msg; - msg.setTimeStamp(0.863379939733); - msg.setSource(9768U); - msg.setSourceEntity(226U); - msg.setDestination(15054U); - msg.setDestinationEntity(25U); - msg.direction = 0.410739594963; - msg.speed = 0.510630680011; - msg.turbulence = 0.751961060607; + IMC::DepthOffset msg; + msg.setTimeStamp(0.34796965527642876); + msg.setSource(46524U); + msg.setSourceEntity(125U); + msg.setDestination(10894U); + msg.setDestinationEntity(12U); + msg.value = 0.7261920840113799; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WindSpeed #1", msg == *msg_d); + test.boolean("DepthOffset #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6622,22 +7008,20 @@ main(void) } { - IMC::WindSpeed msg; - msg.setTimeStamp(0.0735897467167); - msg.setSource(34474U); - msg.setSourceEntity(171U); - msg.setDestination(32375U); - msg.setDestinationEntity(194U); - msg.direction = 0.293900923045; - msg.speed = 0.817676684493; - msg.turbulence = 0.354078492453; + IMC::DepthOffset msg; + msg.setTimeStamp(0.6476991214146006); + msg.setSource(14010U); + msg.setSourceEntity(183U); + msg.setDestination(60104U); + msg.setDestinationEntity(42U); + msg.value = 0.5010958566941798; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("WindSpeed #2", msg == *msg_d); + test.boolean("DepthOffset #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6648,20 +7032,20 @@ main(void) } { - IMC::RelativeHumidity msg; - msg.setTimeStamp(0.794567389837); - msg.setSource(49947U); - msg.setSourceEntity(18U); - msg.setDestination(10761U); - msg.setDestinationEntity(99U); - msg.value = 0.376518356388; + IMC::SoundSpeed msg; + msg.setTimeStamp(0.6711356653152264); + msg.setSource(58045U); + msg.setSourceEntity(173U); + msg.setDestination(34063U); + msg.setDestinationEntity(32U); + msg.value = 0.29449651685901557; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RelativeHumidity #0", msg == *msg_d); + test.boolean("SoundSpeed #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6672,20 +7056,20 @@ main(void) } { - IMC::RelativeHumidity msg; - msg.setTimeStamp(0.37177431119); - msg.setSource(3240U); - msg.setSourceEntity(244U); - msg.setDestination(63490U); - msg.setDestinationEntity(215U); - msg.value = 0.191710947243; + IMC::SoundSpeed msg; + msg.setTimeStamp(0.8587202926477042); + msg.setSource(32593U); + msg.setSourceEntity(115U); + msg.setDestination(15154U); + msg.setDestinationEntity(39U); + msg.value = 0.020341421958598782; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RelativeHumidity #1", msg == *msg_d); + test.boolean("SoundSpeed #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6696,20 +7080,20 @@ main(void) } { - IMC::RelativeHumidity msg; - msg.setTimeStamp(0.874958322901); - msg.setSource(22287U); - msg.setSourceEntity(207U); - msg.setDestination(21454U); - msg.setDestinationEntity(111U); - msg.value = 0.329319060559; + IMC::SoundSpeed msg; + msg.setTimeStamp(0.8086026570877959); + msg.setSource(51423U); + msg.setSourceEntity(26U); + msg.setDestination(53763U); + msg.setDestinationEntity(185U); + msg.value = 0.4483687152330579; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RelativeHumidity #2", msg == *msg_d); + test.boolean("SoundSpeed #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6720,20 +7104,20 @@ main(void) } { - IMC::DevDataText msg; - msg.setTimeStamp(0.996276829659); - msg.setSource(31781U); - msg.setSourceEntity(248U); - msg.setDestination(58473U); - msg.setDestinationEntity(219U); - msg.value.assign("MVQQUEEWRCETLBYMGALSPTNGWAIVHRWISBDSPOMVLCYUQHXVWYVUWWBOLUWNUHNKXKOOILXOSLERJJSOIGQDD"); + IMC::WaterDensity msg; + msg.setTimeStamp(0.3027653667620793); + msg.setSource(49858U); + msg.setSourceEntity(63U); + msg.setDestination(44173U); + msg.setDestinationEntity(164U); + msg.value = 0.012438406585645434; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DevDataText #0", msg == *msg_d); + test.boolean("WaterDensity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6744,20 +7128,20 @@ main(void) } { - IMC::DevDataText msg; - msg.setTimeStamp(0.635757019599); - msg.setSource(4334U); - msg.setSourceEntity(30U); - msg.setDestination(61633U); - msg.setDestinationEntity(13U); - msg.value.assign("KLQJMCXPXUCSQAGDJHUZJYNHTIHGRYAPGNTSUINZCBZUYVPHJEZMGCDQTMSYUVXZIVBRWTGEJTRNJLYFRHPGLNTXEWACZKIWYFMYRARSZSBFCQBDPEAAUKYIWCLIMSFLKEGDDIHNNERDTT"); + IMC::WaterDensity msg; + msg.setTimeStamp(0.8705728947914491); + msg.setSource(17484U); + msg.setSourceEntity(11U); + msg.setDestination(17670U); + msg.setDestinationEntity(143U); + msg.value = 0.6506142686575859; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DevDataText #1", msg == *msg_d); + test.boolean("WaterDensity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6768,20 +7152,20 @@ main(void) } { - IMC::DevDataText msg; - msg.setTimeStamp(0.240609192662); - msg.setSource(7901U); - msg.setSourceEntity(161U); - msg.setDestination(36940U); - msg.setDestinationEntity(32U); - msg.value.assign("DWMUGZBQPEKUNQ"); + IMC::WaterDensity msg; + msg.setTimeStamp(0.13480224158493093); + msg.setSource(19428U); + msg.setSourceEntity(46U); + msg.setDestination(232U); + msg.setDestinationEntity(226U); + msg.value = 0.18316138985061015; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DevDataText #2", msg == *msg_d); + test.boolean("WaterDensity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6792,21 +7176,20 @@ main(void) } { - IMC::DevDataBinary msg; - msg.setTimeStamp(0.471280882419); - msg.setSource(20418U); - msg.setSourceEntity(110U); - msg.setDestination(41608U); - msg.setDestinationEntity(41U); - const char tmp_msg_0[] = {-22, -100, -73, 85, 123, 63, 38, -101, -97, 19, -124, -27, 36, -44, 11, 62, 55, -103, 18, -12, 98, -82, 2, 19, 112, -97, -66, 82, 110, -106, -56, -20, 123, 71, 8, -70, -41, 92, -12, 20, 24, -5, 35, 85, -81, 76, -48, 106, 53, -1, -125, 46, 106, -64, 73, -101, 92, -97, 95, 110, 96, -15, 19, 56, 56, 31, -4, 9, 22, -87, 117, -73, -21, -100, 13, 117, 46, 96, 31, -6, -86, -16, 67, 81, -80, 67, -33, 126, 112, 21, -87, -73, -25, -22, 68, 71, -38, 84, 95, 70, 78, -29, 28, 6, -15, -18, -112, 31, 11, -55, -85, -50, 87, 78, 97, 28, -59, -99, -16, -43, 22, 13, -116, -29, 36, -12, 67, 30, 54, -106, 44, -87, -43, 16, 90, 41, 44, -55, 58, 1, 34, -119, -10, 108, 113, -125, -33, 52, -16, 16, -11, 30, 59, -63, -12, -106, -52, -73, 110, -124}; - msg.value.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::Conductivity msg; + msg.setTimeStamp(0.6481677937993655); + msg.setSource(316U); + msg.setSourceEntity(98U); + msg.setDestination(6040U); + msg.setDestinationEntity(19U); + msg.value = 0.43560918652042846; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DevDataBinary #0", msg == *msg_d); + test.boolean("Conductivity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6817,21 +7200,20 @@ main(void) } { - IMC::DevDataBinary msg; - msg.setTimeStamp(0.722600636325); - msg.setSource(19814U); - msg.setSourceEntity(171U); - msg.setDestination(31867U); - msg.setDestinationEntity(16U); - const char tmp_msg_0[] = {-63, 1, 78, -9, -79, 46, 25, -83, 77, 31, -42, -28, -22, -92, 19, -30, -35, -59, 51, -21, 70, -91, 3, -47, 12, 115, -73, -49, 5, 118, -31, 94, -76, 116, 64, 2, -61, 96, 90, -89, 95, -84, -90, -124, 30, 90, -114, -29, 79, 106, 109, 100, 110, 92, -8, -24, 13, -105, -59, -128, -102, 8, 103, -110, 23, -2, 101, -33, 47, 30, 40, -59, 10, -104, 4, -5, 18, -66, -96, 21, 117, 114, -38, -88, -114, -122, -62, 52, -8, 54, 116, 15, 26, -97, -84, -22, 42, -128, 36, -59, -35, -9, 1, -116, 67, 102, -33, 108, 0, 84, -125, 113, -8, 46, 37, 115, 120, 76, 47, -98, 26, -53, -106, -67, -66, -10, -29, 8, 69, -50, -57, 85, -122}; - msg.value.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::Conductivity msg; + msg.setTimeStamp(0.0923591743260137); + msg.setSource(10364U); + msg.setSourceEntity(150U); + msg.setDestination(46604U); + msg.setDestinationEntity(174U); + msg.value = 0.5250291319883135; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DevDataBinary #1", msg == *msg_d); + test.boolean("Conductivity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6842,21 +7224,20 @@ main(void) } { - IMC::DevDataBinary msg; - msg.setTimeStamp(0.291327491612); - msg.setSource(15321U); - msg.setSourceEntity(135U); - msg.setDestination(40112U); - msg.setDestinationEntity(112U); - const char tmp_msg_0[] = {-63, 109, -43, 30, -16, -53, 40, 111, -52, -27, 83, -45, 20, -32, -28, -102, -119, 21, -5, -81, -13, 73, 39, 8, -11, 101, -82, 69, 5, 76, -24, 49, 31, 20, -25, -2, 72, 125, -47, -116, 107, -10, 43, 70, -44, -10, -104, 76, -112, 26, 6, -45, 45, -58, -38, 12, -128, -83, 82, 86, 95, 86, -14, -49, -75, 29, 17, 18, 42, -79, 81, 31, -39, -126, 91, 44, 65, 70, 34, -58, -7, -37, 2, -116, 12, -2, 23, -8, -99, 85, 96, 83, 65, 19, -80, 15, -75, 104, -92, -33, -33, -50, 100, 48, 107, 72, 75, -41, -59, 115, 15, -49, -47, 60, -33, -76, 42, 10, -125, -104, -72, -12, -37, -46, -72, -20, -71, 122, -67, -74, 122, 43, -27, -70, 108, -117, 28, -114, 111, 118, -69, -113, 115, 20, -46, -55, -87, -57, 12, 49, 120, 31, -88, -85, 85, -32, -118, -49, 16, 38, 119, 101, 89, -87, 62, 89, 76, 20, 58, 3, -18, 119, 67, 64, 93, -112, -81, -18, -113, 82, -24, 49, -74, 124, -54, 92}; - msg.value.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::Conductivity msg; + msg.setTimeStamp(0.24710993229222744); + msg.setSource(13702U); + msg.setSourceEntity(209U); + msg.setDestination(62389U); + msg.setDestinationEntity(66U); + msg.value = 0.21470357027129616; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DevDataBinary #2", msg == *msg_d); + test.boolean("Conductivity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6867,27 +7248,20 @@ main(void) } { - IMC::SonarData msg; - msg.setTimeStamp(0.293602030832); - msg.setSource(53230U); - msg.setSourceEntity(118U); - msg.setDestination(61873U); - msg.setDestinationEntity(166U); - msg.type = 23U; - msg.frequency = 2807232752U; - msg.min_range = 24266U; - msg.max_range = 37332U; - msg.bits_per_point = 9U; - msg.scale_factor = 0.992089201553; - const char tmp_msg_0[] = {18, -49, 90, -108, 88, 12, 29, 56, 70, 32, -91, 24, 15, 41, 34, -41, 60, 61, 33, 68, 56, 6, 2, -100, 94, -58, 70, -31, 16, -69, -58, 0, -8, -36, 124, 120, -66, 16, -16, -81, 101, -8, -106, -54, 122, 32, 41, 23, -54, -55, 112, -127, 46, -121, 61, -35, 89, -41, 41, -36, -107, 22, 42, -27, -81, 114, -110, -53, 31, 46, 117, -52, 62, 75, 16, -4, -53, 27, 109, -127, -5, 78, 50, -62, -76, 24, -31, -31, -122, 38, -12, -78, 75, -41, 33, 113, -65, 4, 69, 48, -15, -5, 125, -123, 99, 29, 119, -100, -69, -87, 0, -55, 8, 110, -19, -52, 53, -112, 118, 2, 121, -127, -8, -11, -87, 63, 37, -117, 78, 73, 93, 104, -104, -123, -36, 67, 76, 10, -93, 104, 0, 108, -13, -91, -68, 66, 6, 58, 46, 20, -57, 41, 113, 118, 53, -9, -38, 105, -76, 100, -44, -65, -34, 58, -76, -120, -16, -98, 114, -63, -56, 0, 79, -48, -36, 10, -126, -67, 65, 20, 69, -69, 54, -3, 99, -24, -40, 96, 24, 103, 90, -44, 22, -112, 34, 1, 109, -5, -53, -80, -10}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::Salinity msg; + msg.setTimeStamp(0.6664551771733184); + msg.setSource(39316U); + msg.setSourceEntity(131U); + msg.setDestination(14254U); + msg.setDestinationEntity(21U); + msg.value = 0.09606467655508444; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SonarData #0", msg == *msg_d); + test.boolean("Salinity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6898,31 +7272,20 @@ main(void) } { - IMC::SonarData msg; - msg.setTimeStamp(0.322118100887); - msg.setSource(35807U); - msg.setSourceEntity(66U); - msg.setDestination(5436U); - msg.setDestinationEntity(73U); - msg.type = 243U; - msg.frequency = 897366357U; - msg.min_range = 18925U; - msg.max_range = 46976U; - msg.bits_per_point = 167U; - msg.scale_factor = 0.137128097812; - IMC::BeamConfig tmp_msg_0; - tmp_msg_0.beam_width = 0.450496853683; - tmp_msg_0.beam_height = 0.459442649287; - msg.beam_config.push_back(tmp_msg_0); - const char tmp_msg_1[] = {-85, -88, 51, 9, 8, 31, 34, 20, -99, 1, 72}; - msg.data.assign(tmp_msg_1, tmp_msg_1 + sizeof(tmp_msg_1)); + IMC::Salinity msg; + msg.setTimeStamp(0.04435876006211037); + msg.setSource(42385U); + msg.setSourceEntity(91U); + msg.setDestination(4894U); + msg.setDestinationEntity(173U); + msg.value = 0.6827477905705668; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SonarData #1", msg == *msg_d); + test.boolean("Salinity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6933,31 +7296,20 @@ main(void) } { - IMC::SonarData msg; - msg.setTimeStamp(0.0505326365929); - msg.setSource(1707U); - msg.setSourceEntity(101U); - msg.setDestination(35495U); - msg.setDestinationEntity(30U); - msg.type = 72U; - msg.frequency = 1259720337U; - msg.min_range = 39891U; - msg.max_range = 63930U; - msg.bits_per_point = 178U; - msg.scale_factor = 0.554274646892; - IMC::BeamConfig tmp_msg_0; - tmp_msg_0.beam_width = 0.0610641246493; - tmp_msg_0.beam_height = 0.368536174073; - msg.beam_config.push_back(tmp_msg_0); - const char tmp_msg_1[] = {84, 51, -123, 79, 84, 28, 82, 52, 74, -4, -15, -116, 89, -103, 83, -86, 74, 61, 122, 121, 124, -84, 61, -2, -32, -55, -82, -2, -46, 125, 84, -81, -25, 43, 23, 85, -19, 33, -53, -96, 106, -49, 98, 124, -30, 64, 52, -45, 9, -48, 27, 99, -29, 28, 15, -71, 89, 31}; - msg.data.assign(tmp_msg_1, tmp_msg_1 + sizeof(tmp_msg_1)); + IMC::Salinity msg; + msg.setTimeStamp(0.5273938241437274); + msg.setSource(17597U); + msg.setSourceEntity(50U); + msg.setDestination(45042U); + msg.setDestinationEntity(192U); + msg.value = 0.1244442321147845; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SonarData #2", msg == *msg_d); + test.boolean("Salinity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6968,19 +7320,22 @@ main(void) } { - IMC::Pulse msg; - msg.setTimeStamp(0.773486680674); - msg.setSource(5087U); - msg.setSourceEntity(211U); - msg.setDestination(39301U); - msg.setDestinationEntity(226U); + IMC::WindSpeed msg; + msg.setTimeStamp(0.6022082343037667); + msg.setSource(55056U); + msg.setSourceEntity(70U); + msg.setDestination(7539U); + msg.setDestinationEntity(216U); + msg.direction = 0.06376080545685148; + msg.speed = 0.22144122726686477; + msg.turbulence = 0.9049517470561211; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Pulse #0", msg == *msg_d); + test.boolean("WindSpeed #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -6991,19 +7346,22 @@ main(void) } { - IMC::Pulse msg; - msg.setTimeStamp(0.757914188544); - msg.setSource(34099U); - msg.setSourceEntity(221U); - msg.setDestination(178U); - msg.setDestinationEntity(104U); + IMC::WindSpeed msg; + msg.setTimeStamp(0.2947325697026949); + msg.setSource(18508U); + msg.setSourceEntity(192U); + msg.setDestination(42823U); + msg.setDestinationEntity(51U); + msg.direction = 0.27467601467599734; + msg.speed = 0.5063835581521003; + msg.turbulence = 0.8408001963717953; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Pulse #1", msg == *msg_d); + test.boolean("WindSpeed #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7014,19 +7372,22 @@ main(void) } { - IMC::Pulse msg; - msg.setTimeStamp(0.767896431891); - msg.setSource(36485U); - msg.setSourceEntity(23U); - msg.setDestination(28653U); - msg.setDestinationEntity(180U); + IMC::WindSpeed msg; + msg.setTimeStamp(0.18282256269564); + msg.setSource(54202U); + msg.setSourceEntity(163U); + msg.setDestination(60292U); + msg.setDestinationEntity(94U); + msg.direction = 0.6573700533548301; + msg.speed = 0.028333401574582973; + msg.turbulence = 0.6072787574221291; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Pulse #2", msg == *msg_d); + test.boolean("WindSpeed #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7037,20 +7398,20 @@ main(void) } { - IMC::PulseDetectionControl msg; - msg.setTimeStamp(0.178517129661); - msg.setSource(20506U); - msg.setSourceEntity(24U); - msg.setDestination(36459U); - msg.setDestinationEntity(77U); - msg.op = 163U; + IMC::RelativeHumidity msg; + msg.setTimeStamp(0.1400504273545612); + msg.setSource(50713U); + msg.setSourceEntity(156U); + msg.setDestination(60246U); + msg.setDestinationEntity(129U); + msg.value = 0.5982108839755652; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PulseDetectionControl #0", msg == *msg_d); + test.boolean("RelativeHumidity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7061,20 +7422,20 @@ main(void) } { - IMC::PulseDetectionControl msg; - msg.setTimeStamp(0.515025964691); - msg.setSource(63498U); - msg.setSourceEntity(111U); - msg.setDestination(28429U); - msg.setDestinationEntity(31U); - msg.op = 79U; + IMC::RelativeHumidity msg; + msg.setTimeStamp(0.5194816510497912); + msg.setSource(35605U); + msg.setSourceEntity(204U); + msg.setDestination(8995U); + msg.setDestinationEntity(137U); + msg.value = 0.6471293095321898; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PulseDetectionControl #1", msg == *msg_d); + test.boolean("RelativeHumidity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7085,20 +7446,20 @@ main(void) } { - IMC::PulseDetectionControl msg; - msg.setTimeStamp(0.106588090555); - msg.setSource(49795U); - msg.setSourceEntity(107U); - msg.setDestination(22062U); - msg.setDestinationEntity(71U); - msg.op = 63U; + IMC::RelativeHumidity msg; + msg.setTimeStamp(0.15689464292167954); + msg.setSource(38471U); + msg.setSourceEntity(233U); + msg.setDestination(17196U); + msg.setDestinationEntity(139U); + msg.value = 0.6257738018737101; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PulseDetectionControl #2", msg == *msg_d); + test.boolean("RelativeHumidity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7109,22 +7470,20 @@ main(void) } { - IMC::FuelLevel msg; - msg.setTimeStamp(0.242487668725); - msg.setSource(56154U); - msg.setSourceEntity(254U); - msg.setDestination(595U); - msg.setDestinationEntity(245U); - msg.value = 0.703263186014; - msg.confidence = 0.60392194625; - msg.opmodes.assign("IUMIMNGHYBVGSHLCYKZBWPBWAWQKJTAROZBHIEUUCZTMIEENINWLCXKEFYJMDENQIPTQNZMMUUAJIIFBNLWZRHJZPDZOKDRBFXTFEWRYSCDRCEJBAFXCD"); + IMC::DevDataText msg; + msg.setTimeStamp(0.5767890580069481); + msg.setSource(48066U); + msg.setSourceEntity(117U); + msg.setDestination(11862U); + msg.setDestinationEntity(174U); + msg.value.assign("ZKYAJRCUIRWMFOWVOIZKFXISDUWRPUFANJGNCIBRWPSKIJMEJPCHTDTJPLETDFRMYVTAJIXKZXFALGE"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FuelLevel #0", msg == *msg_d); + test.boolean("DevDataText #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7135,22 +7494,20 @@ main(void) } { - IMC::FuelLevel msg; - msg.setTimeStamp(0.825535436497); - msg.setSource(47340U); - msg.setSourceEntity(12U); - msg.setDestination(62368U); - msg.setDestinationEntity(36U); - msg.value = 0.540524460098; - msg.confidence = 0.421652641934; - msg.opmodes.assign("ROEXRKOHZLBQPXTAZGHUWETZFLJKJCBKYLJGDPOVSXVMUVUDMNENKJWACUVJQQBTHGIEPLSTKYADFEXWXREFNSADZACYILHHKDBRHVWJEZSLUCYJSGDGTJHUZAQPCLWTFLMVRMOWSHUJANSINKFGLPOYFUICMLZPQMBKQZFPNTQTRYBINGRCIMAVTHRPQIVYWMBONMGSGGXWJCDOYWQVYYXCIDFVBNETOPAPNHDQRORBDA"); + IMC::DevDataText msg; + msg.setTimeStamp(0.6027032530331173); + msg.setSource(18478U); + msg.setSourceEntity(76U); + msg.setDestination(57884U); + msg.setDestinationEntity(193U); + msg.value.assign("GHTQNHFXYBLCSWZDROXVXXOANVRCVDSFZDTS"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FuelLevel #1", msg == *msg_d); + test.boolean("DevDataText #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7161,22 +7518,20 @@ main(void) } { - IMC::FuelLevel msg; - msg.setTimeStamp(0.721041145147); - msg.setSource(38187U); - msg.setSourceEntity(44U); - msg.setDestination(21027U); - msg.setDestinationEntity(110U); - msg.value = 0.0305914785566; - msg.confidence = 0.283353226807; - msg.opmodes.assign("CGHKAAMLAKKHRXCGWIFSJGNQIZZUYXTPPYZFSSTSIESSRQTLMXMLENOHEBAEHARNBQMDJIBNRZYTYJM"); + IMC::DevDataText msg; + msg.setTimeStamp(0.27787471888457915); + msg.setSource(12932U); + msg.setSourceEntity(220U); + msg.setDestination(65042U); + msg.setDestinationEntity(16U); + msg.value.assign("LDYDUFXXVZHDQKTMOJGKWIMOQAVCRLHVOZUTWYNWNQKLGSINDJWBYIJADIUCBNDBWUVPRLFZTBIOCAOHYZAHSLCHPSICEGURHMHEQNLQJJOSJGVVBEJIFEMGUGTYKZVYWYGECXHTISBPZRQIRFRXQ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FuelLevel #2", msg == *msg_d); + test.boolean("DevDataText #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7187,34 +7542,21 @@ main(void) } { - IMC::GpsNavData msg; - msg.setTimeStamp(0.297710650673); - msg.setSource(49219U); - msg.setSourceEntity(22U); - msg.setDestination(23517U); - msg.setDestinationEntity(50U); - msg.itow = 2245243975U; - msg.lat = 0.784787943749; - msg.lon = 0.8928004062; - msg.height_ell = 0.00292392372407; - msg.height_sea = 0.234438861371; - msg.hacc = 0.00094403560495; - msg.vacc = 0.546304001971; - msg.vel_n = 0.521115869941; - msg.vel_e = 0.123657654295; - msg.vel_d = 0.3993426776; - msg.speed = 0.557776569005; - msg.gspeed = 0.135323587936; - msg.heading = 0.315468399485; - msg.sacc = 0.188537070553; - msg.cacc = 0.466582163925; + IMC::DevDataBinary msg; + msg.setTimeStamp(0.1465662778856308); + msg.setSource(43828U); + msg.setSourceEntity(234U); + msg.setDestination(54496U); + msg.setDestinationEntity(168U); + const signed char tmp_msg_0[] = {16, 62, -80, 26, 33, -102, -12, -3, 7, 1, -25, -16, 27, 37, -39, 0, 72, 66, 84, -22, -115, -57, -112, 23, 68, 118, -14, -116, -98, -41, -112, -82, -83, -102, -27, 29, 73, -37, 40, 97, -1, -112, 26, 25, -70, 61, 4, -87, 107, 25, -56, -22, -18, -27, -63, -51, 19, -117, -116, 102, -15, 81, -117, 31, 60, -104, -94, -120, -69, 26, 4, -54, -64, -111, 37, 22, 120, -68, -112, -71, 91, -26, -91, 50, 96, 73, -116, -113, 103, -101, -85, 95, -103, 48, -69, 36, -48, -36, -55, -122, -103, -12, 124, -98, -112, 5, 70, 99, 95, -52, 19, -108, 110, -71, 35, 113, 111, 41, 15, 23, -8, 43, 108, 64, -122, -54, 64, 98, -51, 25, 49, 16, -8, 8, -102, -71, 70, -94, -89, 119, -93, -111, -126, -26, -64, -4, 47, -64, -84, 18, 60, 69, 52, -83, 75, -74, 108, -91, -49, 65, 91}; + msg.value.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsNavData #0", msg == *msg_d); + test.boolean("DevDataBinary #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7225,34 +7567,21 @@ main(void) } { - IMC::GpsNavData msg; - msg.setTimeStamp(0.458947243849); - msg.setSource(35412U); - msg.setSourceEntity(205U); - msg.setDestination(45049U); - msg.setDestinationEntity(26U); - msg.itow = 3368875045U; - msg.lat = 0.641771364535; - msg.lon = 0.783862305992; - msg.height_ell = 0.47449047699; - msg.height_sea = 0.097789949234; - msg.hacc = 0.599698270372; - msg.vacc = 0.213091862613; - msg.vel_n = 0.589480790257; - msg.vel_e = 0.931303246854; - msg.vel_d = 0.586008439403; - msg.speed = 0.601482371278; - msg.gspeed = 0.26690934788; - msg.heading = 0.215906905624; - msg.sacc = 0.277360167432; - msg.cacc = 0.0500502254909; + IMC::DevDataBinary msg; + msg.setTimeStamp(0.8710879082033159); + msg.setSource(11138U); + msg.setSourceEntity(84U); + msg.setDestination(41948U); + msg.setDestinationEntity(240U); + const signed char tmp_msg_0[] = {-83, -51, -37, -67, -81, -34, 79, -118, -13, -108, 76, 119, 35, -101, -128, -32, -62, -24, 4, -15, -34, -21, 44, -34, 17, 110, -8, -90, -117, -13, 116, 90, 30, 28, -123, 126, -93, 96, 76, -59, 95, 103, -48}; + msg.value.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsNavData #1", msg == *msg_d); + test.boolean("DevDataBinary #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7263,34 +7592,21 @@ main(void) } { - IMC::GpsNavData msg; - msg.setTimeStamp(0.62941507184); - msg.setSource(1053U); - msg.setSourceEntity(236U); - msg.setDestination(21815U); - msg.setDestinationEntity(106U); - msg.itow = 936639078U; - msg.lat = 0.46601374835; - msg.lon = 0.484507375449; - msg.height_ell = 0.64581763078; - msg.height_sea = 0.746467346714; - msg.hacc = 0.125373354134; - msg.vacc = 0.368415444683; - msg.vel_n = 0.768429247669; - msg.vel_e = 0.949567946125; - msg.vel_d = 0.580308084962; - msg.speed = 0.0528294635981; - msg.gspeed = 0.743286307302; - msg.heading = 0.366162926095; - msg.sacc = 0.0980605383105; - msg.cacc = 0.464779725458; + IMC::DevDataBinary msg; + msg.setTimeStamp(0.46445290681562934); + msg.setSource(3750U); + msg.setSourceEntity(199U); + msg.setDestination(15542U); + msg.setDestinationEntity(103U); + const signed char tmp_msg_0[] = {-101, -26, -79, -7, -55, 32, 98, -110, -101, 36, 91, 47, -19, 78, -12, 103, -107, 14, -54, -85, 78, -28, 29, -41, 87, 45, 98, -29, -70, 78, -8, 1, 90, 118, -11, 70, -26, 116, -108, 36, 27, 33, -83, 18, 45, -104, -62, 30, 93, 77, -95, -61, -120, -9, -122, 98, -31, -51, -33, -128, -60, -59, 44, -126, -32, 41, 27, -67, 125, 48, 65, 50, 82, -41, 56, -7, 90, -98, -105, 21, -62, 116, -37, 16, 100, 52, -113, 61, -47, 92, -84, 97, -104, -87, -72, 10, 68, 78, -23, 123, 124, -86, 1, 25, -127, 119, 11, -25, -83, 66, 42, 50, -106, 50, -42, -109, 6, 50, 62, 26, -124, -114, -122, -72, 44, -124, 94, -97, 45, -32, -91, 124, -118, 54, 52, 96, -101, -29, 66, -65, -31, 121, -94, -117, 74, -121, -81, 2, 44, -84, 5, -24, 30, 38, -87, 6, -98, -83, 68, -19, -78, -43, 42, 82, -23, -14, 108, 111, 11, 123, -112, -98, 70, -32, -25, 23, 112, -55, 90, -52, -79, 10, -29, -20, -108, 80, -17, 41, -10, -13, 27, 2, 53, -39, 115, 115, 1, -25, 33, -124, 47, -68, 117, 54, 63, 26, 115, -58, 83, -125, 54, -64, 92, -49, 97, -82, -101, -51, -93, -109, -9, -90}; + msg.value.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsNavData #2", msg == *msg_d); + test.boolean("DevDataBinary #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7301,21 +7617,20 @@ main(void) } { - IMC::ServoPosition msg; - msg.setTimeStamp(0.346298745625); - msg.setSource(28754U); - msg.setSourceEntity(102U); - msg.setDestination(16440U); - msg.setDestinationEntity(58U); - msg.id = 170U; - msg.value = 0.775284706781; + IMC::Force msg; + msg.setTimeStamp(0.5109641604817229); + msg.setSource(61369U); + msg.setSourceEntity(30U); + msg.setDestination(14750U); + msg.setDestinationEntity(184U); + msg.value = 0.40244569465831626; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ServoPosition #0", msg == *msg_d); + test.boolean("Force #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7326,21 +7641,20 @@ main(void) } { - IMC::ServoPosition msg; - msg.setTimeStamp(0.120346290536); - msg.setSource(20740U); - msg.setSourceEntity(24U); - msg.setDestination(19828U); - msg.setDestinationEntity(242U); - msg.id = 78U; - msg.value = 0.0419897503888; + IMC::Force msg; + msg.setTimeStamp(0.18093162901765347); + msg.setSource(13601U); + msg.setSourceEntity(97U); + msg.setDestination(37309U); + msg.setDestinationEntity(134U); + msg.value = 0.5045489668352058; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ServoPosition #1", msg == *msg_d); + test.boolean("Force #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7351,21 +7665,20 @@ main(void) } { - IMC::ServoPosition msg; - msg.setTimeStamp(0.931665660276); - msg.setSource(3718U); - msg.setSourceEntity(106U); - msg.setDestination(38900U); - msg.setDestinationEntity(68U); - msg.id = 189U; - msg.value = 0.953466999124; + IMC::Force msg; + msg.setTimeStamp(0.6117972205355162); + msg.setSource(9137U); + msg.setSourceEntity(174U); + msg.setDestination(31221U); + msg.setDestinationEntity(136U); + msg.value = 0.11222523413214203; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ServoPosition #2", msg == *msg_d); + test.boolean("Force #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7376,25 +7689,27 @@ main(void) } { - IMC::DeviceState msg; - msg.setTimeStamp(0.903099802131); - msg.setSource(48339U); - msg.setSourceEntity(91U); - msg.setDestination(39064U); - msg.setDestinationEntity(203U); - msg.x = 0.109583607719; - msg.y = 0.167424038645; - msg.z = 0.0176769700127; - msg.phi = 0.0403378053972; - msg.theta = 0.206051599753; - msg.psi = 0.487552168539; + IMC::SonarData msg; + msg.setTimeStamp(0.5977155220846052); + msg.setSource(19920U); + msg.setSourceEntity(69U); + msg.setDestination(39474U); + msg.setDestinationEntity(21U); + msg.type = 142U; + msg.frequency = 4181707963U; + msg.min_range = 12135U; + msg.max_range = 20628U; + msg.bits_per_point = 82U; + msg.scale_factor = 0.3953981726571608; + const signed char tmp_msg_0[] = {42, 110, -27, -62, -69, 109, -11, -19, -16, 53, -5, -26, 19, -25, 123, 104, 48, 110, 68, -122, -21, -90, 52, 58, -83, 107, -62, 119, 12, 82, 93, -36, -48, -88, -64, 8, -90, -83, -74, 119, -4, 28, -9, -108, -95, -6, -5, -95, 106, -97, -110, -96, 55, -58, 103, 25, 31, -87, 4, -14, 32, 65, 83, -76, -7, -122, 119, 61, 50, -70, 77, 120, -98, 75, -100, -26, 25, -74, 87, -119, 67, -106, 24, 10, 110, -113, -26, -33, -28, -34, -99, 105, 68, 111, -8, 71, 112, -95, 107, -120, -108, 103, 9, -23, -17, 120, -51, 114, 28, -94, -73, 95, -31, 12, 58, 12, -47, -116, 111, -91, -46, 67, -114, 32, 49, -71, -93, -68, 126, 69, -28, -121, 73, -46, 41, 39, 111, 81, -2, 0, 78, -75, -114, 87, -22, 107, -116, 52, 50, -124, 116, -47, -31, 8, -112, 82, -90, 45, 119, -127, -106, -10, 116, 66, 82, 61, -68, -67, -37, -85, 123, 8, 20, 52, -39, 4, -109, -23, -79, 93, 50, -6, 11}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DeviceState #0", msg == *msg_d); + test.boolean("SonarData #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7405,25 +7720,31 @@ main(void) } { - IMC::DeviceState msg; - msg.setTimeStamp(0.979770170461); - msg.setSource(35731U); - msg.setSourceEntity(90U); - msg.setDestination(12959U); - msg.setDestinationEntity(238U); - msg.x = 0.672361002646; - msg.y = 0.767452757715; - msg.z = 0.559035330504; - msg.phi = 0.873733098837; - msg.theta = 0.0410675984385; - msg.psi = 0.462916004234; + IMC::SonarData msg; + msg.setTimeStamp(0.8189156131145215); + msg.setSource(19616U); + msg.setSourceEntity(137U); + msg.setDestination(15375U); + msg.setDestinationEntity(146U); + msg.type = 44U; + msg.frequency = 4256755751U; + msg.min_range = 5853U; + msg.max_range = 32625U; + msg.bits_per_point = 84U; + msg.scale_factor = 0.011735532616893085; + IMC::BeamConfig tmp_msg_0; + tmp_msg_0.beam_width = 0.30267656700532364; + tmp_msg_0.beam_height = 0.19546222540910663; + msg.beam_config.push_back(tmp_msg_0); + const signed char tmp_msg_1[] = {-1, 23, -118, 104, 109, -5, 118, 61, 4, 23, -116, -23, 118, 45, -101, 58, 62, -56, -78, 107, -59, 32, -97, 20, 84, -80, -17, -15, -19, 6, -82, 39, -27, 97, -73, 90, -80, 112, 2, -125, 51, 76, -16, 61, -93, -40, -109, 50, 98, 5, -42, 104, 107, 48, 81, -67, -29, -67, -120, -69, -38, 47, -54, -66, -75, -57, -37, -69, 29, -112, -71, -112, -66, -8, -1, 45, -101, 8, -84, -105, -18, 126, -125, -38, 47, -120, -59, 48, 50, 65, -67, -80, 97, 98, -30, -110, -79, -89, -88, 47, -11}; + msg.data.assign(tmp_msg_1, tmp_msg_1 + sizeof(tmp_msg_1)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DeviceState #1", msg == *msg_d); + test.boolean("SonarData #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7434,25 +7755,27 @@ main(void) } { - IMC::DeviceState msg; - msg.setTimeStamp(0.170676089463); - msg.setSource(52827U); - msg.setSourceEntity(148U); - msg.setDestination(398U); - msg.setDestinationEntity(252U); - msg.x = 0.393225110691; - msg.y = 0.592056083555; - msg.z = 0.0493515613859; - msg.phi = 0.285640850815; - msg.theta = 0.885631635996; - msg.psi = 0.977644494158; + IMC::SonarData msg; + msg.setTimeStamp(0.3513715795084864); + msg.setSource(61583U); + msg.setSourceEntity(96U); + msg.setDestination(26018U); + msg.setDestinationEntity(164U); + msg.type = 45U; + msg.frequency = 3723693035U; + msg.min_range = 49199U; + msg.max_range = 11840U; + msg.bits_per_point = 48U; + msg.scale_factor = 0.9224399321921956; + const signed char tmp_msg_0[] = {81, -46, -110, -117, -48, 65, 8, -36, -38, 98, 6, -58, -61, 94, -3, -1, -43, 92, -117, 76, -25, 11, -14, 28, -30, -74, 117, -2, 10, 8, 21, -32, -74, -23, 55, 83, 79, -49, 95, 91, -35, 21, -34, -57, -104, -115, 101, 124, 46, 96, -21, 19, -120, -114, 95, -16, -127, -91, 17, 0, -24, 50, 86, 124, 107, 77, -48, 29, -50, 52, -39, 91, -108, -48, 100, -24, -83, 87, 6, 50, -35, -20, 116, 13, -78, 42, -34, 99, 125, -23, -48, -46, -127, -47, -95, -69, -32, -79, 14, 52, 96, -80, -31, 3, 27, 19, 123, 70, -43, 29, 107, -65, 4, -122, -42, 101, -47, 77, 55, -62, -14, 47, 94, -46, 9, 33, -32, -10, -51, 14, -70, 126, 68, 9, 16, 37, -67, 63, -127, -109, 2, 98, 123, 36, 22, -120, -80, 64, 29, -58, 104, 18, -115, 80, 70, -47, -64, -15, 31, 46, 102, -124, -42, 27, 7, 99, -64, -90, -102, 76, 25, 88, 16, 7, -126, -16, -17, -55, -115, -20, -116, -39, -57, 62, -25, 4, -125, -90, -6, 58, 16, -124, -62, -65, -8, -34, -12, 40, 75, -52, -69, 74, 62, 125, 110, 10, 109, -88, -42, 0, 41, -48, -51, 108, 120, 4, 107, 81, -1, -124, 48, -120, 91, -112, 82, -116, -108, 86, -75, 44, 114, 36, -127, -106, -109}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DeviceState #2", msg == *msg_d); + test.boolean("SonarData #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7463,21 +7786,19 @@ main(void) } { - IMC::BeamConfig msg; - msg.setTimeStamp(0.0680427515511); - msg.setSource(29845U); - msg.setSourceEntity(28U); - msg.setDestination(63728U); - msg.setDestinationEntity(53U); - msg.beam_width = 0.673475715404; - msg.beam_height = 0.698428323737; + IMC::Pulse msg; + msg.setTimeStamp(0.31234080106733964); + msg.setSource(27733U); + msg.setSourceEntity(23U); + msg.setDestination(64178U); + msg.setDestinationEntity(48U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("BeamConfig #0", msg == *msg_d); + test.boolean("Pulse #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7488,21 +7809,19 @@ main(void) } { - IMC::BeamConfig msg; - msg.setTimeStamp(0.024027769157); - msg.setSource(1382U); - msg.setSourceEntity(209U); - msg.setDestination(489U); - msg.setDestinationEntity(177U); - msg.beam_width = 0.0383726799339; - msg.beam_height = 0.774337041873; + IMC::Pulse msg; + msg.setTimeStamp(0.07320386993341688); + msg.setSource(19277U); + msg.setSourceEntity(237U); + msg.setDestination(3278U); + msg.setDestinationEntity(247U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("BeamConfig #1", msg == *msg_d); + test.boolean("Pulse #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7513,21 +7832,19 @@ main(void) } { - IMC::BeamConfig msg; - msg.setTimeStamp(0.535618933844); - msg.setSource(23626U); - msg.setSourceEntity(183U); - msg.setDestination(37126U); - msg.setDestinationEntity(234U); - msg.beam_width = 0.510784069422; - msg.beam_height = 0.837031652307; + IMC::Pulse msg; + msg.setTimeStamp(0.588839660766349); + msg.setSource(65038U); + msg.setSourceEntity(172U); + msg.setDestination(30084U); + msg.setDestinationEntity(246U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("BeamConfig #2", msg == *msg_d); + test.boolean("Pulse #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7538,20 +7855,20 @@ main(void) } { - IMC::DataSanity msg; - msg.setTimeStamp(0.245795209372); - msg.setSource(29299U); - msg.setSourceEntity(252U); - msg.setDestination(62810U); - msg.setDestinationEntity(76U); - msg.sane = 254U; + IMC::PulseDetectionControl msg; + msg.setTimeStamp(0.7484455547872935); + msg.setSource(18288U); + msg.setSourceEntity(150U); + msg.setDestination(45460U); + msg.setDestinationEntity(28U); + msg.op = 142U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DataSanity #0", msg == *msg_d); + test.boolean("PulseDetectionControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7562,20 +7879,20 @@ main(void) } { - IMC::DataSanity msg; - msg.setTimeStamp(0.397391824978); - msg.setSource(62598U); - msg.setSourceEntity(62U); - msg.setDestination(53063U); - msg.setDestinationEntity(71U); - msg.sane = 160U; + IMC::PulseDetectionControl msg; + msg.setTimeStamp(0.3542865647255026); + msg.setSource(61942U); + msg.setSourceEntity(157U); + msg.setDestination(27883U); + msg.setDestinationEntity(227U); + msg.op = 75U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DataSanity #1", msg == *msg_d); + test.boolean("PulseDetectionControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7586,20 +7903,20 @@ main(void) } { - IMC::DataSanity msg; - msg.setTimeStamp(0.895191329128); - msg.setSource(3245U); - msg.setSourceEntity(52U); - msg.setDestination(56566U); - msg.setDestinationEntity(221U); - msg.sane = 232U; + IMC::PulseDetectionControl msg; + msg.setTimeStamp(0.9477741180767332); + msg.setSource(4437U); + msg.setSourceEntity(131U); + msg.setDestination(61322U); + msg.setDestinationEntity(76U); + msg.op = 40U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DataSanity #2", msg == *msg_d); + test.boolean("PulseDetectionControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7610,20 +7927,22 @@ main(void) } { - IMC::RhodamineDye msg; - msg.setTimeStamp(0.891205210005); - msg.setSource(61726U); - msg.setSourceEntity(21U); - msg.setDestination(45616U); - msg.setDestinationEntity(146U); - msg.value = 0.749760499994; + IMC::FuelLevel msg; + msg.setTimeStamp(0.3933230021611306); + msg.setSource(34590U); + msg.setSourceEntity(9U); + msg.setDestination(60339U); + msg.setDestinationEntity(180U); + msg.value = 0.9717877536202794; + msg.confidence = 0.2196960434992954; + msg.opmodes.assign("UDQGNTOMPUULMRYVFDDPUMWHPHVGSZXVCALINMRBXJMZAKCPVTTEBYETZYPKFSVILEDGTNQAMRZHCIHWIPTUQWSBWZQK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RhodamineDye #0", msg == *msg_d); + test.boolean("FuelLevel #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7634,20 +7953,22 @@ main(void) } { - IMC::RhodamineDye msg; - msg.setTimeStamp(0.0837491201897); - msg.setSource(44392U); - msg.setSourceEntity(39U); - msg.setDestination(28281U); - msg.setDestinationEntity(119U); - msg.value = 0.582435886116; + IMC::FuelLevel msg; + msg.setTimeStamp(0.9097027304690345); + msg.setSource(50617U); + msg.setSourceEntity(207U); + msg.setDestination(64857U); + msg.setDestinationEntity(50U); + msg.value = 0.24723302332732833; + msg.confidence = 0.9919422406628295; + msg.opmodes.assign("FAVFBZOVQXMATGNRJSXLXEXKYZGDSWVTPSVQOUURWPPJEBKKYCRJOHHINQJRFDERYBYKCTQYDJFNEIOEDAZGVEJZRWGXQJWUNIHQDHKULDMOYWPMJIZWBJMCNNFIKOMHYFXMWPNLTDLQEQADNLYRAOGFLITRARTQVSUVFZNHIILZPSSOKUVBIWMVBMFBGLBUEZPHBRXSAAWZBTKGWQDFYECLSGUGTUEPCXDTUNCHZXCCYCMSHI"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RhodamineDye #1", msg == *msg_d); + test.boolean("FuelLevel #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7658,20 +7979,22 @@ main(void) } { - IMC::RhodamineDye msg; - msg.setTimeStamp(0.220013387919); - msg.setSource(53453U); - msg.setSourceEntity(2U); - msg.setDestination(5030U); - msg.setDestinationEntity(200U); - msg.value = 0.67005544851; + IMC::FuelLevel msg; + msg.setTimeStamp(0.30723208493512966); + msg.setSource(53916U); + msg.setSourceEntity(62U); + msg.setDestination(15411U); + msg.setDestinationEntity(49U); + msg.value = 0.3741684894609767; + msg.confidence = 0.956313654011796; + msg.opmodes.assign("FZBMDQMLYMGTDKGEVWNPIHVCCABFJRLGLBWFXCWPJREPOPLAWWEULHAAKQVLENSYYZDFECBPBJMSYBSRXRUCVRDPIPZUPEGVJSOZIRQJKHRTXUMWPNQNOYTWOKLJTJYCFOQBHXLYAEGATISDMVGDGFPZHTVMZXLZENFFUISAIZKYIOWVNHTWZCUXIXOTAJG"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RhodamineDye #2", msg == *msg_d); + test.boolean("FuelLevel #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7682,20 +8005,34 @@ main(void) } { - IMC::CrudeOil msg; - msg.setTimeStamp(0.21309677298); - msg.setSource(7647U); - msg.setSourceEntity(217U); - msg.setDestination(5159U); - msg.setDestinationEntity(90U); - msg.value = 0.724659952371; + IMC::GpsNavData msg; + msg.setTimeStamp(0.42491299499923374); + msg.setSource(22681U); + msg.setSourceEntity(154U); + msg.setDestination(403U); + msg.setDestinationEntity(71U); + msg.itow = 339514475U; + msg.lat = 0.7840111534558256; + msg.lon = 0.9053706341727514; + msg.height_ell = 0.06246954952346073; + msg.height_sea = 0.11783711670713082; + msg.hacc = 0.361926149487949; + msg.vacc = 0.0015778051052134368; + msg.vel_n = 0.9999828028585801; + msg.vel_e = 0.933111789739063; + msg.vel_d = 0.13205726117147132; + msg.speed = 0.3349715001479663; + msg.gspeed = 0.010628019665857913; + msg.heading = 0.8936780597455929; + msg.sacc = 0.8514410526995387; + msg.cacc = 0.0612879693523104; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CrudeOil #0", msg == *msg_d); + test.boolean("GpsNavData #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7706,20 +8043,34 @@ main(void) } { - IMC::CrudeOil msg; - msg.setTimeStamp(0.0268975536771); - msg.setSource(4303U); - msg.setSourceEntity(86U); - msg.setDestination(2654U); - msg.setDestinationEntity(93U); - msg.value = 0.132726149142; + IMC::GpsNavData msg; + msg.setTimeStamp(0.2658584943236526); + msg.setSource(7642U); + msg.setSourceEntity(58U); + msg.setDestination(53U); + msg.setDestinationEntity(89U); + msg.itow = 2880289641U; + msg.lat = 0.13845105320111217; + msg.lon = 0.14584097223337045; + msg.height_ell = 0.3081065659922837; + msg.height_sea = 0.7142512235536721; + msg.hacc = 0.5724730261189012; + msg.vacc = 0.4310752625501806; + msg.vel_n = 0.15596282897805647; + msg.vel_e = 0.8584766210315897; + msg.vel_d = 0.9194972841347482; + msg.speed = 0.19765840223590503; + msg.gspeed = 0.5591913960772937; + msg.heading = 0.8221896335640168; + msg.sacc = 0.20399783425112217; + msg.cacc = 0.04753250175109924; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CrudeOil #1", msg == *msg_d); + test.boolean("GpsNavData #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7730,20 +8081,34 @@ main(void) } { - IMC::CrudeOil msg; - msg.setTimeStamp(0.889958347933); - msg.setSource(37253U); - msg.setSourceEntity(98U); - msg.setDestination(27168U); - msg.setDestinationEntity(82U); - msg.value = 0.226559078187; + IMC::GpsNavData msg; + msg.setTimeStamp(0.8042731088637282); + msg.setSource(18826U); + msg.setSourceEntity(97U); + msg.setDestination(1871U); + msg.setDestinationEntity(219U); + msg.itow = 419610403U; + msg.lat = 0.6864064927062579; + msg.lon = 0.8352605615941668; + msg.height_ell = 0.06462273562459497; + msg.height_sea = 0.9749763052994146; + msg.hacc = 0.015483590772674027; + msg.vacc = 0.8173487080646394; + msg.vel_n = 0.9536028397969434; + msg.vel_e = 0.3452142598742586; + msg.vel_d = 0.3496709808550097; + msg.speed = 0.8985232223094323; + msg.gspeed = 0.9711862830056645; + msg.heading = 0.901665284383881; + msg.sacc = 0.3328937049154995; + msg.cacc = 0.677697476976413; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CrudeOil #2", msg == *msg_d); + test.boolean("GpsNavData #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7754,20 +8119,21 @@ main(void) } { - IMC::FineOil msg; - msg.setTimeStamp(0.0533846301754); - msg.setSource(62510U); - msg.setSourceEntity(104U); - msg.setDestination(52888U); - msg.setDestinationEntity(164U); - msg.value = 0.840837093191; + IMC::ServoPosition msg; + msg.setTimeStamp(0.3070747048928497); + msg.setSource(36541U); + msg.setSourceEntity(53U); + msg.setDestination(40424U); + msg.setDestinationEntity(195U); + msg.id = 196U; + msg.value = 0.10188008394574555; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FineOil #0", msg == *msg_d); + test.boolean("ServoPosition #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7778,20 +8144,21 @@ main(void) } { - IMC::FineOil msg; - msg.setTimeStamp(0.808289529245); - msg.setSource(23670U); - msg.setSourceEntity(119U); - msg.setDestination(25127U); - msg.setDestinationEntity(197U); - msg.value = 0.712131518431; + IMC::ServoPosition msg; + msg.setTimeStamp(0.3518750524987937); + msg.setSource(35607U); + msg.setSourceEntity(215U); + msg.setDestination(15454U); + msg.setDestinationEntity(189U); + msg.id = 218U; + msg.value = 0.6313030919825227; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FineOil #1", msg == *msg_d); + test.boolean("ServoPosition #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7802,20 +8169,21 @@ main(void) } { - IMC::FineOil msg; - msg.setTimeStamp(0.879848044765); - msg.setSource(52974U); - msg.setSourceEntity(46U); - msg.setDestination(12013U); - msg.setDestinationEntity(234U); - msg.value = 0.738426390861; + IMC::ServoPosition msg; + msg.setTimeStamp(0.11837543559317187); + msg.setSource(2350U); + msg.setSourceEntity(129U); + msg.setDestination(33092U); + msg.setDestinationEntity(97U); + msg.id = 177U; + msg.value = 0.6254244914647555; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FineOil #2", msg == *msg_d); + test.boolean("ServoPosition #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7826,20 +8194,25 @@ main(void) } { - IMC::Turbidity msg; - msg.setTimeStamp(0.826036472458); - msg.setSource(38351U); - msg.setSourceEntity(25U); - msg.setDestination(53560U); - msg.setDestinationEntity(156U); - msg.value = 0.297848335709; + IMC::DeviceState msg; + msg.setTimeStamp(0.6565622762138931); + msg.setSource(9492U); + msg.setSourceEntity(189U); + msg.setDestination(18063U); + msg.setDestinationEntity(100U); + msg.x = 0.4563344221222291; + msg.y = 0.8859756091049883; + msg.z = 0.07901246042895782; + msg.phi = 0.31041578890405974; + msg.theta = 0.1182394300388443; + msg.psi = 0.2133752476829731; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Turbidity #0", msg == *msg_d); + test.boolean("DeviceState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7850,20 +8223,25 @@ main(void) } { - IMC::Turbidity msg; - msg.setTimeStamp(0.766013883059); - msg.setSource(38525U); - msg.setSourceEntity(38U); - msg.setDestination(461U); - msg.setDestinationEntity(27U); - msg.value = 0.0100598299673; + IMC::DeviceState msg; + msg.setTimeStamp(0.7319437766581401); + msg.setSource(21579U); + msg.setSourceEntity(236U); + msg.setDestination(39194U); + msg.setDestinationEntity(15U); + msg.x = 0.9788918516926447; + msg.y = 0.3664593757943788; + msg.z = 0.3614221266300949; + msg.phi = 0.5000022285268; + msg.theta = 0.13363252257408875; + msg.psi = 0.3817340948088125; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Turbidity #1", msg == *msg_d); + test.boolean("DeviceState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7874,20 +8252,25 @@ main(void) } { - IMC::Turbidity msg; - msg.setTimeStamp(0.717354344396); - msg.setSource(31758U); - msg.setSourceEntity(219U); - msg.setDestination(20104U); - msg.setDestinationEntity(8U); - msg.value = 0.0839940547162; + IMC::DeviceState msg; + msg.setTimeStamp(0.04100319716284073); + msg.setSource(58274U); + msg.setSourceEntity(152U); + msg.setDestination(6178U); + msg.setDestinationEntity(206U); + msg.x = 0.4709475124838661; + msg.y = 0.8501711187426987; + msg.z = 0.12316313949983415; + msg.phi = 0.42541206966903866; + msg.theta = 0.6906558374264101; + msg.psi = 0.09742703404987807; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Turbidity #2", msg == *msg_d); + test.boolean("DeviceState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7898,20 +8281,21 @@ main(void) } { - IMC::Chlorophyll msg; - msg.setTimeStamp(0.179909434665); - msg.setSource(63811U); - msg.setSourceEntity(163U); - msg.setDestination(4253U); - msg.setDestinationEntity(160U); - msg.value = 0.500705806459; + IMC::BeamConfig msg; + msg.setTimeStamp(0.2818505535160387); + msg.setSource(56763U); + msg.setSourceEntity(113U); + msg.setDestination(14618U); + msg.setDestinationEntity(47U); + msg.beam_width = 0.26891415239420435; + msg.beam_height = 0.9648867554467591; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Chlorophyll #0", msg == *msg_d); + test.boolean("BeamConfig #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7922,20 +8306,21 @@ main(void) } { - IMC::Chlorophyll msg; - msg.setTimeStamp(0.120127813293); - msg.setSource(64082U); - msg.setSourceEntity(30U); - msg.setDestination(1710U); - msg.setDestinationEntity(179U); - msg.value = 0.687332433356; + IMC::BeamConfig msg; + msg.setTimeStamp(0.4611556008044033); + msg.setSource(21172U); + msg.setSourceEntity(63U); + msg.setDestination(38494U); + msg.setDestinationEntity(176U); + msg.beam_width = 0.08075564424845127; + msg.beam_height = 0.0841304153985386; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Chlorophyll #1", msg == *msg_d); + test.boolean("BeamConfig #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7946,20 +8331,21 @@ main(void) } { - IMC::Chlorophyll msg; - msg.setTimeStamp(0.976499312068); - msg.setSource(44337U); - msg.setSourceEntity(227U); - msg.setDestination(7960U); - msg.setDestinationEntity(19U); - msg.value = 0.548342686925; + IMC::BeamConfig msg; + msg.setTimeStamp(0.875507190846325); + msg.setSource(31162U); + msg.setSourceEntity(132U); + msg.setDestination(14233U); + msg.setDestinationEntity(254U); + msg.beam_width = 0.8162539248871022; + msg.beam_height = 0.15220135455973993; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Chlorophyll #2", msg == *msg_d); + test.boolean("BeamConfig #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7970,20 +8356,20 @@ main(void) } { - IMC::Fluorescein msg; - msg.setTimeStamp(0.77894765355); - msg.setSource(58606U); - msg.setSourceEntity(26U); - msg.setDestination(19422U); - msg.setDestinationEntity(49U); - msg.value = 0.0797219004653; + IMC::DataSanity msg; + msg.setTimeStamp(0.23189490340012398); + msg.setSource(21964U); + msg.setSourceEntity(6U); + msg.setDestination(33920U); + msg.setDestinationEntity(55U); + msg.sane = 231U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Fluorescein #0", msg == *msg_d); + test.boolean("DataSanity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -7994,20 +8380,20 @@ main(void) } { - IMC::Fluorescein msg; - msg.setTimeStamp(0.163463060658); - msg.setSource(63817U); - msg.setSourceEntity(12U); - msg.setDestination(7020U); - msg.setDestinationEntity(170U); - msg.value = 0.444713269103; + IMC::DataSanity msg; + msg.setTimeStamp(0.7285049423719075); + msg.setSource(17349U); + msg.setSourceEntity(81U); + msg.setDestination(38590U); + msg.setDestinationEntity(113U); + msg.sane = 134U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Fluorescein #1", msg == *msg_d); + test.boolean("DataSanity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8018,20 +8404,20 @@ main(void) } { - IMC::Fluorescein msg; - msg.setTimeStamp(0.0312637309489); - msg.setSource(23739U); - msg.setSourceEntity(210U); - msg.setDestination(6464U); - msg.setDestinationEntity(146U); - msg.value = 0.115067797859; + IMC::DataSanity msg; + msg.setTimeStamp(0.6851425886230629); + msg.setSource(61169U); + msg.setSourceEntity(34U); + msg.setDestination(23514U); + msg.setDestinationEntity(153U); + msg.sane = 173U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Fluorescein #2", msg == *msg_d); + test.boolean("DataSanity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8042,20 +8428,20 @@ main(void) } { - IMC::Phycocyanin msg; - msg.setTimeStamp(0.486326244837); - msg.setSource(41500U); - msg.setSourceEntity(188U); - msg.setDestination(64492U); - msg.setDestinationEntity(222U); - msg.value = 0.827878224095; + IMC::RhodamineDye msg; + msg.setTimeStamp(0.3321267823953712); + msg.setSource(45260U); + msg.setSourceEntity(230U); + msg.setDestination(1047U); + msg.setDestinationEntity(44U); + msg.value = 0.5462913101945791; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Phycocyanin #0", msg == *msg_d); + test.boolean("RhodamineDye #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8066,20 +8452,20 @@ main(void) } { - IMC::Phycocyanin msg; - msg.setTimeStamp(0.0231338827699); - msg.setSource(41608U); - msg.setSourceEntity(243U); - msg.setDestination(23325U); - msg.setDestinationEntity(250U); - msg.value = 0.728703038435; + IMC::RhodamineDye msg; + msg.setTimeStamp(0.6397890432070166); + msg.setSource(7023U); + msg.setSourceEntity(5U); + msg.setDestination(15953U); + msg.setDestinationEntity(55U); + msg.value = 0.9884995596803866; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Phycocyanin #1", msg == *msg_d); + test.boolean("RhodamineDye #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8090,20 +8476,20 @@ main(void) } { - IMC::Phycocyanin msg; - msg.setTimeStamp(0.690446180851); - msg.setSource(41820U); - msg.setSourceEntity(185U); - msg.setDestination(15415U); - msg.setDestinationEntity(144U); - msg.value = 0.674989737482; + IMC::RhodamineDye msg; + msg.setTimeStamp(0.21071967522961843); + msg.setSource(20606U); + msg.setSourceEntity(67U); + msg.setDestination(16206U); + msg.setDestinationEntity(61U); + msg.value = 0.3811947801131319; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Phycocyanin #2", msg == *msg_d); + test.boolean("RhodamineDye #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8114,20 +8500,20 @@ main(void) } { - IMC::Phycoerythrin msg; - msg.setTimeStamp(0.203878103047); - msg.setSource(7271U); - msg.setSourceEntity(242U); - msg.setDestination(44646U); - msg.setDestinationEntity(56U); - msg.value = 0.0859300481924; + IMC::CrudeOil msg; + msg.setTimeStamp(0.35911315561946044); + msg.setSource(4379U); + msg.setSourceEntity(204U); + msg.setDestination(25170U); + msg.setDestinationEntity(187U); + msg.value = 0.9441549252990359; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Phycoerythrin #0", msg == *msg_d); + test.boolean("CrudeOil #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8138,20 +8524,20 @@ main(void) } { - IMC::Phycoerythrin msg; - msg.setTimeStamp(0.495547890368); - msg.setSource(65461U); - msg.setSourceEntity(238U); - msg.setDestination(42683U); - msg.setDestinationEntity(204U); - msg.value = 0.197686287913; + IMC::CrudeOil msg; + msg.setTimeStamp(0.5128424210599606); + msg.setSource(15073U); + msg.setSourceEntity(125U); + msg.setDestination(31030U); + msg.setDestinationEntity(166U); + msg.value = 0.9484218581864302; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Phycoerythrin #1", msg == *msg_d); + test.boolean("CrudeOil #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8162,20 +8548,20 @@ main(void) } { - IMC::Phycoerythrin msg; - msg.setTimeStamp(0.204665315873); - msg.setSource(22174U); - msg.setSourceEntity(113U); - msg.setDestination(63460U); - msg.setDestinationEntity(103U); - msg.value = 0.105374562777; + IMC::CrudeOil msg; + msg.setTimeStamp(0.9141089723330054); + msg.setSource(45852U); + msg.setSourceEntity(94U); + msg.setDestination(1078U); + msg.setDestinationEntity(177U); + msg.value = 0.2890622254651075; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Phycoerythrin #2", msg == *msg_d); + test.boolean("CrudeOil #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8186,34 +8572,20 @@ main(void) } { - IMC::GpsFixRtk msg; - msg.setTimeStamp(0.838649306482); - msg.setSource(10411U); - msg.setSourceEntity(188U); - msg.setDestination(16844U); - msg.setDestinationEntity(175U); - msg.validity = 23214U; - msg.type = 114U; - msg.tow = 664589024U; - msg.base_lat = 0.726149835921; - msg.base_lon = 0.437969583308; - msg.base_height = 0.904049750437; - msg.n = 0.929879869637; - msg.e = 0.860088095184; - msg.d = 0.388434555828; - msg.v_n = 0.357966899476; - msg.v_e = 0.434720008274; - msg.v_d = 0.131211941858; - msg.satellites = 104U; - msg.iar_hyp = 57013U; - msg.iar_ratio = 0.21320087564; + IMC::FineOil msg; + msg.setTimeStamp(0.1666746649027101); + msg.setSource(20971U); + msg.setSourceEntity(144U); + msg.setDestination(38015U); + msg.setDestinationEntity(198U); + msg.value = 0.7732414175511793; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFixRtk #0", msg == *msg_d); + test.boolean("FineOil #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8224,34 +8596,20 @@ main(void) } { - IMC::GpsFixRtk msg; - msg.setTimeStamp(0.917406012385); - msg.setSource(61624U); - msg.setSourceEntity(199U); - msg.setDestination(40568U); - msg.setDestinationEntity(52U); - msg.validity = 21419U; - msg.type = 171U; - msg.tow = 3750325581U; - msg.base_lat = 0.402589042999; - msg.base_lon = 0.229776238716; - msg.base_height = 0.904849534606; - msg.n = 0.616347214604; - msg.e = 0.656937639901; - msg.d = 0.884395885188; - msg.v_n = 0.564611177106; - msg.v_e = 0.671289014703; - msg.v_d = 0.433519424375; - msg.satellites = 223U; - msg.iar_hyp = 5142U; - msg.iar_ratio = 0.496047794126; + IMC::FineOil msg; + msg.setTimeStamp(0.9129273035427576); + msg.setSource(14841U); + msg.setSourceEntity(202U); + msg.setDestination(22047U); + msg.setDestinationEntity(129U); + msg.value = 0.4669297382362083; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFixRtk #1", msg == *msg_d); + test.boolean("FineOil #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8262,34 +8620,20 @@ main(void) } { - IMC::GpsFixRtk msg; - msg.setTimeStamp(0.426825909607); - msg.setSource(471U); - msg.setSourceEntity(184U); - msg.setDestination(10527U); - msg.setDestinationEntity(3U); - msg.validity = 8466U; - msg.type = 207U; - msg.tow = 2267244938U; - msg.base_lat = 0.0779727289142; - msg.base_lon = 0.301977053478; - msg.base_height = 0.0161989752064; - msg.n = 0.718453121737; - msg.e = 0.0843968533398; - msg.d = 0.219467726762; - msg.v_n = 0.704460391646; - msg.v_e = 0.174662132118; - msg.v_d = 0.198527505676; - msg.satellites = 29U; - msg.iar_hyp = 34779U; - msg.iar_ratio = 0.181543731343; + IMC::FineOil msg; + msg.setTimeStamp(0.737165708885107); + msg.setSource(4929U); + msg.setSourceEntity(95U); + msg.setDestination(15878U); + msg.setDestinationEntity(157U); + msg.value = 0.662006163524692; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFixRtk #2", msg == *msg_d); + test.boolean("FineOil #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8300,42 +8644,20 @@ main(void) } { - IMC::ExternalNavData msg; - msg.setTimeStamp(0.458593193918); - msg.setSource(58055U); - msg.setSourceEntity(145U); - msg.setDestination(39949U); - msg.setDestinationEntity(164U); - IMC::EstimatedState tmp_msg_0; - tmp_msg_0.lat = 0.682272266849; - tmp_msg_0.lon = 0.361360995744; - tmp_msg_0.height = 0.317018743666; - tmp_msg_0.x = 0.997491697622; - tmp_msg_0.y = 0.239021803347; - tmp_msg_0.z = 0.383934837295; - tmp_msg_0.phi = 0.440382895054; - tmp_msg_0.theta = 0.848329543032; - tmp_msg_0.psi = 0.137013462748; - tmp_msg_0.u = 0.885284992625; - tmp_msg_0.v = 0.448611247211; - tmp_msg_0.w = 0.643905896409; - tmp_msg_0.vx = 0.228368238013; - tmp_msg_0.vy = 0.249941340085; - tmp_msg_0.vz = 0.962728895716; - tmp_msg_0.p = 0.962843425652; - tmp_msg_0.q = 0.506276983106; - tmp_msg_0.r = 0.0412876969097; - tmp_msg_0.depth = 0.397526616141; - tmp_msg_0.alt = 0.523945963269; - msg.state.set(tmp_msg_0); - msg.type = 105U; + IMC::Turbidity msg; + msg.setTimeStamp(0.18825066398081514); + msg.setSource(59444U); + msg.setSourceEntity(152U); + msg.setDestination(14583U); + msg.setDestinationEntity(119U); + msg.value = 0.07867170396308898; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ExternalNavData #0", msg == *msg_d); + test.boolean("Turbidity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8346,42 +8668,20 @@ main(void) } { - IMC::ExternalNavData msg; - msg.setTimeStamp(0.680989085826); - msg.setSource(32710U); - msg.setSourceEntity(176U); - msg.setDestination(48118U); - msg.setDestinationEntity(10U); - IMC::EstimatedState tmp_msg_0; - tmp_msg_0.lat = 0.437206935672; - tmp_msg_0.lon = 0.168756796782; - tmp_msg_0.height = 0.574933059721; - tmp_msg_0.x = 0.737085928692; - tmp_msg_0.y = 0.36904330748; - tmp_msg_0.z = 0.522033364487; - tmp_msg_0.phi = 0.105208994592; - tmp_msg_0.theta = 0.259501807789; - tmp_msg_0.psi = 0.849927746366; - tmp_msg_0.u = 0.864683389276; - tmp_msg_0.v = 0.533575496236; - tmp_msg_0.w = 0.624676152797; - tmp_msg_0.vx = 0.837064100835; - tmp_msg_0.vy = 0.616676377416; - tmp_msg_0.vz = 0.630175648439; - tmp_msg_0.p = 0.00838729755924; - tmp_msg_0.q = 0.283858621838; - tmp_msg_0.r = 0.51490630548; - tmp_msg_0.depth = 0.0921183568017; - tmp_msg_0.alt = 0.59611235205; - msg.state.set(tmp_msg_0); - msg.type = 127U; + IMC::Turbidity msg; + msg.setTimeStamp(0.8436371086439798); + msg.setSource(21021U); + msg.setSourceEntity(151U); + msg.setDestination(10381U); + msg.setDestinationEntity(244U); + msg.value = 0.3438058378797664; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ExternalNavData #1", msg == *msg_d); + test.boolean("Turbidity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8392,42 +8692,20 @@ main(void) } { - IMC::ExternalNavData msg; - msg.setTimeStamp(0.0787078947415); - msg.setSource(18944U); - msg.setSourceEntity(145U); - msg.setDestination(39544U); - msg.setDestinationEntity(202U); - IMC::EstimatedState tmp_msg_0; - tmp_msg_0.lat = 0.199295578957; - tmp_msg_0.lon = 0.317652374425; - tmp_msg_0.height = 0.201663757242; - tmp_msg_0.x = 0.361650266678; - tmp_msg_0.y = 0.487794610656; - tmp_msg_0.z = 0.550055730428; - tmp_msg_0.phi = 0.716205703411; - tmp_msg_0.theta = 0.46679784788; - tmp_msg_0.psi = 0.78728300681; - tmp_msg_0.u = 0.0550253445288; - tmp_msg_0.v = 0.337549661197; - tmp_msg_0.w = 0.774724285986; - tmp_msg_0.vx = 0.886669991847; - tmp_msg_0.vy = 0.328998844458; - tmp_msg_0.vz = 0.224101844792; - tmp_msg_0.p = 0.243760927253; - tmp_msg_0.q = 0.306131831721; - tmp_msg_0.r = 0.760865026988; - tmp_msg_0.depth = 0.912734608181; - tmp_msg_0.alt = 0.428966099864; - msg.state.set(tmp_msg_0); - msg.type = 198U; + IMC::Turbidity msg; + msg.setTimeStamp(0.6481843938249441); + msg.setSource(980U); + msg.setSourceEntity(38U); + msg.setDestination(45281U); + msg.setDestinationEntity(158U); + msg.value = 0.5759094736534902; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ExternalNavData #2", msg == *msg_d); + test.boolean("Turbidity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8438,20 +8716,20 @@ main(void) } { - IMC::DissolvedOxygen msg; - msg.setTimeStamp(0.339231851728); - msg.setSource(8223U); - msg.setSourceEntity(140U); - msg.setDestination(1711U); - msg.setDestinationEntity(243U); - msg.value = 0.325024210034; + IMC::Chlorophyll msg; + msg.setTimeStamp(0.31581360581144613); + msg.setSource(47435U); + msg.setSourceEntity(213U); + msg.setDestination(47500U); + msg.setDestinationEntity(188U); + msg.value = 0.9360933798089451; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DissolvedOxygen #0", msg == *msg_d); + test.boolean("Chlorophyll #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8462,20 +8740,20 @@ main(void) } { - IMC::DissolvedOxygen msg; - msg.setTimeStamp(0.97247853112); - msg.setSource(32163U); - msg.setSourceEntity(158U); - msg.setDestination(17540U); - msg.setDestinationEntity(119U); - msg.value = 0.435006390464; + IMC::Chlorophyll msg; + msg.setTimeStamp(0.4044264433936645); + msg.setSource(40257U); + msg.setSourceEntity(52U); + msg.setDestination(41778U); + msg.setDestinationEntity(143U); + msg.value = 0.5107202251769287; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DissolvedOxygen #1", msg == *msg_d); + test.boolean("Chlorophyll #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8486,20 +8764,20 @@ main(void) } { - IMC::DissolvedOxygen msg; - msg.setTimeStamp(0.395884016083); - msg.setSource(4562U); - msg.setSourceEntity(151U); - msg.setDestination(34852U); - msg.setDestinationEntity(73U); - msg.value = 0.0760210797798; + IMC::Chlorophyll msg; + msg.setTimeStamp(0.34630553614589343); + msg.setSource(4783U); + msg.setSourceEntity(54U); + msg.setDestination(46638U); + msg.setDestinationEntity(179U); + msg.value = 0.9662147516981202; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DissolvedOxygen #2", msg == *msg_d); + test.boolean("Chlorophyll #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8510,20 +8788,20 @@ main(void) } { - IMC::AirSaturation msg; - msg.setTimeStamp(0.654313689067); - msg.setSource(48486U); - msg.setSourceEntity(236U); - msg.setDestination(14988U); - msg.setDestinationEntity(251U); - msg.value = 0.453540472846; + IMC::Fluorescein msg; + msg.setTimeStamp(0.8098504772104715); + msg.setSource(14448U); + msg.setSourceEntity(75U); + msg.setDestination(43585U); + msg.setDestinationEntity(22U); + msg.value = 0.28839329896087174; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AirSaturation #0", msg == *msg_d); + test.boolean("Fluorescein #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8534,20 +8812,20 @@ main(void) } { - IMC::AirSaturation msg; - msg.setTimeStamp(0.217881331462); - msg.setSource(24126U); - msg.setSourceEntity(61U); - msg.setDestination(20771U); - msg.setDestinationEntity(32U); - msg.value = 0.491179705303; + IMC::Fluorescein msg; + msg.setTimeStamp(0.8495367102288781); + msg.setSource(38481U); + msg.setSourceEntity(25U); + msg.setDestination(61683U); + msg.setDestinationEntity(234U); + msg.value = 0.4912660219295072; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AirSaturation #1", msg == *msg_d); + test.boolean("Fluorescein #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8558,20 +8836,20 @@ main(void) } { - IMC::AirSaturation msg; - msg.setTimeStamp(0.24482984382); - msg.setSource(9182U); - msg.setSourceEntity(131U); - msg.setDestination(11287U); - msg.setDestinationEntity(59U); - msg.value = 0.537805202745; + IMC::Fluorescein msg; + msg.setTimeStamp(0.6440770545471469); + msg.setSource(39241U); + msg.setSourceEntity(205U); + msg.setDestination(26785U); + msg.setDestinationEntity(120U); + msg.value = 0.43342381826053344; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AirSaturation #2", msg == *msg_d); + test.boolean("Fluorescein #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8582,20 +8860,20 @@ main(void) } { - IMC::Throttle msg; - msg.setTimeStamp(0.332599833006); - msg.setSource(49964U); - msg.setSourceEntity(32U); - msg.setDestination(3914U); - msg.setDestinationEntity(47U); - msg.value = 0.0421462008274; + IMC::Phycocyanin msg; + msg.setTimeStamp(0.08515342784916702); + msg.setSource(48476U); + msg.setSourceEntity(122U); + msg.setDestination(17962U); + msg.setDestinationEntity(98U); + msg.value = 0.2145084084466815; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Throttle #0", msg == *msg_d); + test.boolean("Phycocyanin #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8606,20 +8884,20 @@ main(void) } { - IMC::Throttle msg; - msg.setTimeStamp(0.991328866696); - msg.setSource(30956U); - msg.setSourceEntity(254U); - msg.setDestination(33421U); - msg.setDestinationEntity(183U); - msg.value = 0.15256669159; + IMC::Phycocyanin msg; + msg.setTimeStamp(0.16969222419980245); + msg.setSource(42405U); + msg.setSourceEntity(108U); + msg.setDestination(2393U); + msg.setDestinationEntity(242U); + msg.value = 0.3991430645257582; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Throttle #1", msg == *msg_d); + test.boolean("Phycocyanin #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8630,20 +8908,20 @@ main(void) } { - IMC::Throttle msg; - msg.setTimeStamp(0.083785078344); - msg.setSource(10708U); - msg.setSourceEntity(50U); - msg.setDestination(10535U); - msg.setDestinationEntity(12U); - msg.value = 0.612668725181; + IMC::Phycocyanin msg; + msg.setTimeStamp(0.15512004890381426); + msg.setSource(55748U); + msg.setSourceEntity(231U); + msg.setDestination(9638U); + msg.setDestinationEntity(88U); + msg.value = 0.6390438882534336; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Throttle #2", msg == *msg_d); + test.boolean("Phycocyanin #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8654,20 +8932,20 @@ main(void) } { - IMC::PH msg; - msg.setTimeStamp(0.589843380146); - msg.setSource(56199U); - msg.setSourceEntity(40U); - msg.setDestination(23844U); - msg.setDestinationEntity(205U); - msg.value = 0.165712247134; + IMC::Phycoerythrin msg; + msg.setTimeStamp(0.8360700020117686); + msg.setSource(9373U); + msg.setSourceEntity(201U); + msg.setDestination(36453U); + msg.setDestinationEntity(193U); + msg.value = 0.5814626551432042; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PH #0", msg == *msg_d); + test.boolean("Phycoerythrin #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8678,20 +8956,20 @@ main(void) } { - IMC::PH msg; - msg.setTimeStamp(0.678307127894); - msg.setSource(39615U); - msg.setSourceEntity(70U); - msg.setDestination(831U); - msg.setDestinationEntity(223U); - msg.value = 0.721279029975; + IMC::Phycoerythrin msg; + msg.setTimeStamp(0.8322327871118722); + msg.setSource(1312U); + msg.setSourceEntity(62U); + msg.setDestination(1618U); + msg.setDestinationEntity(23U); + msg.value = 0.5718530234687547; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PH #1", msg == *msg_d); + test.boolean("Phycoerythrin #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8702,20 +8980,20 @@ main(void) } { - IMC::PH msg; - msg.setTimeStamp(0.398408298359); - msg.setSource(29022U); - msg.setSourceEntity(161U); - msg.setDestination(4157U); - msg.setDestinationEntity(5U); - msg.value = 0.242288146491; + IMC::Phycoerythrin msg; + msg.setTimeStamp(0.5694652082223495); + msg.setSource(39323U); + msg.setSourceEntity(164U); + msg.setDestination(56158U); + msg.setDestinationEntity(45U); + msg.value = 0.7869608979255573; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PH #2", msg == *msg_d); + test.boolean("Phycoerythrin #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8726,20 +9004,34 @@ main(void) } { - IMC::Redox msg; - msg.setTimeStamp(0.196977336269); - msg.setSource(49923U); - msg.setSourceEntity(223U); - msg.setDestination(1007U); - msg.setDestinationEntity(224U); - msg.value = 0.126290389247; + IMC::GpsFixRtk msg; + msg.setTimeStamp(0.6772711824537555); + msg.setSource(24459U); + msg.setSourceEntity(203U); + msg.setDestination(56675U); + msg.setDestinationEntity(195U); + msg.validity = 55541U; + msg.type = 171U; + msg.tow = 4260677362U; + msg.base_lat = 0.9943493335491745; + msg.base_lon = 0.4768202756717468; + msg.base_height = 0.15091047869905483; + msg.n = 0.22177332843965536; + msg.e = 0.05414133076149652; + msg.d = 0.23155340729666163; + msg.v_n = 0.8986969875213465; + msg.v_e = 0.08059552288560512; + msg.v_d = 0.38197275772550954; + msg.satellites = 204U; + msg.iar_hyp = 7868U; + msg.iar_ratio = 0.5639052107799684; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Redox #0", msg == *msg_d); + test.boolean("GpsFixRtk #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8750,20 +9042,34 @@ main(void) } { - IMC::Redox msg; - msg.setTimeStamp(0.398465478785); - msg.setSource(35827U); - msg.setSourceEntity(6U); - msg.setDestination(10037U); - msg.setDestinationEntity(87U); - msg.value = 0.0268369124991; + IMC::GpsFixRtk msg; + msg.setTimeStamp(0.16592317066056772); + msg.setSource(54453U); + msg.setSourceEntity(123U); + msg.setDestination(5276U); + msg.setDestinationEntity(51U); + msg.validity = 8037U; + msg.type = 54U; + msg.tow = 3175736958U; + msg.base_lat = 0.3390558338141334; + msg.base_lon = 0.6872119700256817; + msg.base_height = 0.04362468979091938; + msg.n = 0.6131355329839974; + msg.e = 0.6893642423452251; + msg.d = 0.3016041250919309; + msg.v_n = 0.7094156728811478; + msg.v_e = 0.028423708346622667; + msg.v_d = 0.829005481188145; + msg.satellites = 52U; + msg.iar_hyp = 7559U; + msg.iar_ratio = 0.9396917390867389; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Redox #1", msg == *msg_d); + test.boolean("GpsFixRtk #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8774,20 +9080,34 @@ main(void) } { - IMC::Redox msg; - msg.setTimeStamp(0.675653307632); - msg.setSource(53394U); - msg.setSourceEntity(38U); - msg.setDestination(2138U); - msg.setDestinationEntity(21U); - msg.value = 0.643498102642; + IMC::GpsFixRtk msg; + msg.setTimeStamp(0.8213794146719803); + msg.setSource(45296U); + msg.setSourceEntity(167U); + msg.setDestination(60005U); + msg.setDestinationEntity(89U); + msg.validity = 35703U; + msg.type = 251U; + msg.tow = 2058602252U; + msg.base_lat = 0.3827299498070158; + msg.base_lon = 0.6800520865611044; + msg.base_height = 0.825068832631597; + msg.n = 0.5679623906758572; + msg.e = 0.5590245330587973; + msg.d = 0.2623179469076069; + msg.v_n = 0.9170651615806132; + msg.v_e = 0.3285948571829763; + msg.v_d = 0.7165182113197945; + msg.satellites = 184U; + msg.iar_hyp = 31120U; + msg.iar_ratio = 0.4730999796160914; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Redox #2", msg == *msg_d); + test.boolean("GpsFixRtk #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8798,22 +9118,42 @@ main(void) } { - IMC::CameraZoom msg; - msg.setTimeStamp(0.0859979808115); - msg.setSource(19614U); - msg.setSourceEntity(3U); - msg.setDestination(31981U); - msg.setDestinationEntity(119U); - msg.id = 130U; - msg.zoom = 192U; - msg.action = 163U; + IMC::ExternalNavData msg; + msg.setTimeStamp(0.5880500372004869); + msg.setSource(19571U); + msg.setSourceEntity(247U); + msg.setDestination(27099U); + msg.setDestinationEntity(245U); + IMC::EstimatedState tmp_msg_0; + tmp_msg_0.lat = 0.6380049870571478; + tmp_msg_0.lon = 0.362795284720277; + tmp_msg_0.height = 0.08824622307120844; + tmp_msg_0.x = 0.597585493216239; + tmp_msg_0.y = 0.5224798508558515; + tmp_msg_0.z = 0.12136032924002271; + tmp_msg_0.phi = 0.24974914031110562; + tmp_msg_0.theta = 0.9446413345802197; + tmp_msg_0.psi = 0.2513941945222239; + tmp_msg_0.u = 0.4540199398155318; + tmp_msg_0.v = 0.6063842177908926; + tmp_msg_0.w = 0.5177132237407042; + tmp_msg_0.vx = 0.49949588641477294; + tmp_msg_0.vy = 0.8219362832556131; + tmp_msg_0.vz = 0.8819839060778761; + tmp_msg_0.p = 0.3317781605079698; + tmp_msg_0.q = 0.25374973009890045; + tmp_msg_0.r = 0.1951686836203913; + tmp_msg_0.depth = 0.491310568714999; + tmp_msg_0.alt = 0.06934509786651089; + msg.state.set(tmp_msg_0); + msg.type = 89U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CameraZoom #0", msg == *msg_d); + test.boolean("ExternalNavData #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8824,22 +9164,42 @@ main(void) } { - IMC::CameraZoom msg; - msg.setTimeStamp(0.319089520878); - msg.setSource(23105U); - msg.setSourceEntity(34U); - msg.setDestination(27080U); - msg.setDestinationEntity(48U); - msg.id = 88U; - msg.zoom = 140U; - msg.action = 2U; + IMC::ExternalNavData msg; + msg.setTimeStamp(0.1681059867736715); + msg.setSource(574U); + msg.setSourceEntity(166U); + msg.setDestination(1502U); + msg.setDestinationEntity(40U); + IMC::EstimatedState tmp_msg_0; + tmp_msg_0.lat = 0.7512723754137122; + tmp_msg_0.lon = 0.3204502217009738; + tmp_msg_0.height = 0.5816771561181002; + tmp_msg_0.x = 0.6444728432140953; + tmp_msg_0.y = 0.37153162782499616; + tmp_msg_0.z = 0.7126172063944255; + tmp_msg_0.phi = 0.6161166907173973; + tmp_msg_0.theta = 0.0289099632204467; + tmp_msg_0.psi = 0.28813668974506157; + tmp_msg_0.u = 0.667075368626627; + tmp_msg_0.v = 0.7006522653824998; + tmp_msg_0.w = 0.5252109111784004; + tmp_msg_0.vx = 0.4423328041366956; + tmp_msg_0.vy = 0.26307568117642033; + tmp_msg_0.vz = 0.044776712879293634; + tmp_msg_0.p = 0.0011318419030411642; + tmp_msg_0.q = 0.4607623045849639; + tmp_msg_0.r = 0.20094400471994; + tmp_msg_0.depth = 0.9903836258894031; + tmp_msg_0.alt = 0.3507049323371152; + msg.state.set(tmp_msg_0); + msg.type = 161U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CameraZoom #1", msg == *msg_d); + test.boolean("ExternalNavData #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8850,22 +9210,42 @@ main(void) } { - IMC::CameraZoom msg; - msg.setTimeStamp(0.0314043635825); - msg.setSource(39441U); - msg.setSourceEntity(127U); - msg.setDestination(31205U); - msg.setDestinationEntity(225U); - msg.id = 13U; - msg.zoom = 180U; - msg.action = 92U; + IMC::ExternalNavData msg; + msg.setTimeStamp(0.06276480811243401); + msg.setSource(58418U); + msg.setSourceEntity(122U); + msg.setDestination(40707U); + msg.setDestinationEntity(189U); + IMC::EstimatedState tmp_msg_0; + tmp_msg_0.lat = 0.40505873051403973; + tmp_msg_0.lon = 0.9917620222355435; + tmp_msg_0.height = 0.10361046594589252; + tmp_msg_0.x = 0.6043578782049405; + tmp_msg_0.y = 0.4232042284626423; + tmp_msg_0.z = 0.009036644481786094; + tmp_msg_0.phi = 0.14180419972565617; + tmp_msg_0.theta = 0.6370159385661484; + tmp_msg_0.psi = 0.6748793268953951; + tmp_msg_0.u = 0.5456859423253357; + tmp_msg_0.v = 0.4545615525739485; + tmp_msg_0.w = 0.8067291734932579; + tmp_msg_0.vx = 0.2782624112902513; + tmp_msg_0.vy = 0.9117878648980521; + tmp_msg_0.vz = 0.5233060601045002; + tmp_msg_0.p = 0.8084653418181846; + tmp_msg_0.q = 0.4813830901373054; + tmp_msg_0.r = 0.7226230627808943; + tmp_msg_0.depth = 0.8281684702650342; + tmp_msg_0.alt = 0.34041647454298984; + msg.state.set(tmp_msg_0); + msg.type = 97U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CameraZoom #2", msg == *msg_d); + test.boolean("ExternalNavData #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8876,21 +9256,20 @@ main(void) } { - IMC::SetThrusterActuation msg; - msg.setTimeStamp(0.233308892627); - msg.setSource(60366U); - msg.setSourceEntity(178U); - msg.setDestination(31991U); - msg.setDestinationEntity(45U); - msg.id = 153U; - msg.value = 0.951012844419; + IMC::DissolvedOxygen msg; + msg.setTimeStamp(0.7002052819072249); + msg.setSource(13312U); + msg.setSourceEntity(22U); + msg.setDestination(11984U); + msg.setDestinationEntity(236U); + msg.value = 0.051927009234397525; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetThrusterActuation #0", msg == *msg_d); + test.boolean("DissolvedOxygen #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8901,21 +9280,20 @@ main(void) } { - IMC::SetThrusterActuation msg; - msg.setTimeStamp(0.250891783244); - msg.setSource(33415U); - msg.setSourceEntity(36U); - msg.setDestination(30863U); - msg.setDestinationEntity(199U); - msg.id = 30U; - msg.value = 0.606498689723; + IMC::DissolvedOxygen msg; + msg.setTimeStamp(0.7836121558698521); + msg.setSource(12312U); + msg.setSourceEntity(67U); + msg.setDestination(64745U); + msg.setDestinationEntity(245U); + msg.value = 0.4168542450921855; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetThrusterActuation #1", msg == *msg_d); + test.boolean("DissolvedOxygen #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8926,21 +9304,20 @@ main(void) } { - IMC::SetThrusterActuation msg; - msg.setTimeStamp(0.127345564574); - msg.setSource(52738U); - msg.setSourceEntity(122U); - msg.setDestination(14314U); - msg.setDestinationEntity(167U); - msg.id = 63U; - msg.value = 0.978615634982; - - try + IMC::DissolvedOxygen msg; + msg.setTimeStamp(0.28664387069372654); + msg.setSource(2131U); + msg.setSourceEntity(146U); + msg.setDestination(41220U); + msg.setDestinationEntity(84U); + msg.value = 0.04101442241289455; + + try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetThrusterActuation #2", msg == *msg_d); + test.boolean("DissolvedOxygen #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8951,21 +9328,20 @@ main(void) } { - IMC::SetServoPosition msg; - msg.setTimeStamp(0.675014759472); - msg.setSource(23685U); - msg.setSourceEntity(38U); - msg.setDestination(16218U); - msg.setDestinationEntity(52U); - msg.id = 117U; - msg.value = 0.58712783128; + IMC::AirSaturation msg; + msg.setTimeStamp(0.5794335049120496); + msg.setSource(9178U); + msg.setSourceEntity(236U); + msg.setDestination(30846U); + msg.setDestinationEntity(0U); + msg.value = 0.5695166204988226; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetServoPosition #0", msg == *msg_d); + test.boolean("AirSaturation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -8976,21 +9352,20 @@ main(void) } { - IMC::SetServoPosition msg; - msg.setTimeStamp(0.825081962429); - msg.setSource(30116U); - msg.setSourceEntity(93U); - msg.setDestination(13046U); - msg.setDestinationEntity(164U); - msg.id = 92U; - msg.value = 0.926792090702; + IMC::AirSaturation msg; + msg.setTimeStamp(0.2999565427785694); + msg.setSource(51318U); + msg.setSourceEntity(204U); + msg.setDestination(47939U); + msg.setDestinationEntity(35U); + msg.value = 0.7462560927271057; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetServoPosition #1", msg == *msg_d); + test.boolean("AirSaturation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9001,21 +9376,20 @@ main(void) } { - IMC::SetServoPosition msg; - msg.setTimeStamp(0.0137109533685); - msg.setSource(62329U); - msg.setSourceEntity(73U); - msg.setDestination(22974U); - msg.setDestinationEntity(167U); - msg.id = 229U; - msg.value = 0.571254271658; + IMC::AirSaturation msg; + msg.setTimeStamp(0.8031685710386754); + msg.setSource(54938U); + msg.setSourceEntity(104U); + msg.setDestination(25403U); + msg.setDestinationEntity(112U); + msg.value = 0.8723060500284445; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetServoPosition #2", msg == *msg_d); + test.boolean("AirSaturation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9026,21 +9400,20 @@ main(void) } { - IMC::SetControlSurfaceDeflection msg; - msg.setTimeStamp(0.253481807976); - msg.setSource(52417U); - msg.setSourceEntity(166U); - msg.setDestination(62055U); - msg.setDestinationEntity(217U); - msg.id = 169U; - msg.angle = 0.931569390745; + IMC::Throttle msg; + msg.setTimeStamp(0.8060181342938251); + msg.setSource(60754U); + msg.setSourceEntity(89U); + msg.setDestination(49063U); + msg.setDestinationEntity(163U); + msg.value = 0.023655809695921404; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetControlSurfaceDeflection #0", msg == *msg_d); + test.boolean("Throttle #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9051,21 +9424,20 @@ main(void) } { - IMC::SetControlSurfaceDeflection msg; - msg.setTimeStamp(0.0682914515224); - msg.setSource(34009U); - msg.setSourceEntity(212U); - msg.setDestination(28133U); - msg.setDestinationEntity(143U); - msg.id = 253U; - msg.angle = 0.692073208819; + IMC::Throttle msg; + msg.setTimeStamp(0.661792505529623); + msg.setSource(55230U); + msg.setSourceEntity(83U); + msg.setDestination(50429U); + msg.setDestinationEntity(97U); + msg.value = 0.6502045559397537; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetControlSurfaceDeflection #1", msg == *msg_d); + test.boolean("Throttle #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9076,21 +9448,20 @@ main(void) } { - IMC::SetControlSurfaceDeflection msg; - msg.setTimeStamp(0.196521667087); - msg.setSource(39956U); - msg.setSourceEntity(163U); - msg.setDestination(37795U); - msg.setDestinationEntity(31U); - msg.id = 136U; - msg.angle = 0.169675113331; + IMC::Throttle msg; + msg.setTimeStamp(0.08426104379556665); + msg.setSource(34384U); + msg.setSourceEntity(40U); + msg.setDestination(41781U); + msg.setDestinationEntity(180U); + msg.value = 0.314300743449456; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetControlSurfaceDeflection #2", msg == *msg_d); + test.boolean("Throttle #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9101,21 +9472,20 @@ main(void) } { - IMC::RemoteActionsRequest msg; - msg.setTimeStamp(0.741734635066); - msg.setSource(56759U); - msg.setSourceEntity(143U); - msg.setDestination(23359U); - msg.setDestinationEntity(94U); - msg.op = 103U; - msg.actions.assign("OWMASGTNPYNAKNRXMAIQXAECGGHWAIXCNFMFLNZFJSAJOUDFX"); + IMC::PH msg; + msg.setTimeStamp(0.7726045916200784); + msg.setSource(36065U); + msg.setSourceEntity(144U); + msg.setDestination(49558U); + msg.setDestinationEntity(1U); + msg.value = 0.49453166128800263; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteActionsRequest #0", msg == *msg_d); + test.boolean("PH #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9126,21 +9496,20 @@ main(void) } { - IMC::RemoteActionsRequest msg; - msg.setTimeStamp(0.218077268435); - msg.setSource(53696U); - msg.setSourceEntity(118U); - msg.setDestination(19280U); - msg.setDestinationEntity(234U); - msg.op = 33U; - msg.actions.assign("KETZHCBRXWTHITTQCWMELVFFVYGEJVQOSKUYJYMKPINGUXVNSSIZOMPBJGGVANHDNGSDKOOKBHMBPDTRAUUGDMVQERQXCUISDFWTVNGZCWNJTFWQZPOQRLTNMTXARRWKFRABPXXIFKJKDXREPOJWXHFEMOEUO"); + IMC::PH msg; + msg.setTimeStamp(0.07620414820334953); + msg.setSource(7028U); + msg.setSourceEntity(10U); + msg.setDestination(28366U); + msg.setDestinationEntity(160U); + msg.value = 0.5531921572030697; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteActionsRequest #1", msg == *msg_d); + test.boolean("PH #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9151,21 +9520,20 @@ main(void) } { - IMC::RemoteActionsRequest msg; - msg.setTimeStamp(0.733737138951); - msg.setSource(57042U); - msg.setSourceEntity(173U); - msg.setDestination(63326U); - msg.setDestinationEntity(239U); - msg.op = 156U; - msg.actions.assign("TXDXWHPBUXACKAJMOWPDBBKIJNDCSVQNSRDOAUFQARZWGOHGGZEPNNUBLDVEQWLRXFNSMHPTHIDLLYOMBIYWUBGSHUYFVFLGEJVTQLZCBHLVWAUUSJCSWDSQFPN"); + IMC::PH msg; + msg.setTimeStamp(0.8078164520265538); + msg.setSource(45148U); + msg.setSourceEntity(11U); + msg.setDestination(44462U); + msg.setDestinationEntity(169U); + msg.value = 0.9720541902935086; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteActionsRequest #2", msg == *msg_d); + test.boolean("PH #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9176,20 +9544,20 @@ main(void) } { - IMC::RemoteActions msg; - msg.setTimeStamp(0.836134488361); - msg.setSource(40172U); - msg.setSourceEntity(190U); - msg.setDestination(20127U); - msg.setDestinationEntity(46U); - msg.actions.assign("GBYFEDDVUZQGFCXOABLNMYBSOCYZUWTECGMFUHXOFSIZZIZADRTOHHKEPCSXSDJZDDKRUCBBJADELMCPIGULAAWZZOVCSIIQRGITBNIPFFNXMLHEVGNMJNSABXXRXJNVMFOHQYWITVIVKWWOVSRLPUBKNDCJTAOGUQSKRGZJFLCPJURSAQBMVHPHRHFEPNNGGTUPENTXTILU"); + IMC::Redox msg; + msg.setTimeStamp(0.9496925007214696); + msg.setSource(7212U); + msg.setSourceEntity(5U); + msg.setDestination(32650U); + msg.setDestinationEntity(30U); + msg.value = 0.1244556933630303; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteActions #0", msg == *msg_d); + test.boolean("Redox #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9200,20 +9568,20 @@ main(void) } { - IMC::RemoteActions msg; - msg.setTimeStamp(0.102889204085); - msg.setSource(35845U); - msg.setSourceEntity(205U); - msg.setDestination(39407U); - msg.setDestinationEntity(116U); - msg.actions.assign("VSVPXGJHCFBDHZTVADDYXECDNKQGQUCZAEZUWJJMRCMVNLTYAPMWJUMDSPAOL"); + IMC::Redox msg; + msg.setTimeStamp(0.9434964555876809); + msg.setSource(39723U); + msg.setSourceEntity(31U); + msg.setDestination(4561U); + msg.setDestinationEntity(196U); + msg.value = 0.01110698460849524; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteActions #1", msg == *msg_d); + test.boolean("Redox #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9224,20 +9592,20 @@ main(void) } { - IMC::RemoteActions msg; - msg.setTimeStamp(0.0357341609571); - msg.setSource(26683U); - msg.setSourceEntity(0U); - msg.setDestination(25086U); - msg.setDestinationEntity(196U); - msg.actions.assign("LBVDGFOAPLUMJIPKNFKIVRMPUZCRLVSRDCFUUSJNACCBENNSEKPZABAYFZGRBEKZKXOTGIYAWTICFYOYSADKIAEWAYUEYZXRMQBXGTHTFJBIOONJHGZMXUKYPMNHVZVCCPMLGQHJAJTTMZEPGPLDLRWVLWMQOIHWEQVHYRFVBOS"); + IMC::Redox msg; + msg.setTimeStamp(0.4672016346115645); + msg.setSource(7187U); + msg.setSourceEntity(64U); + msg.setDestination(27458U); + msg.setDestinationEntity(124U); + msg.value = 0.6727073324388948; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteActions #2", msg == *msg_d); + test.boolean("Redox #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9248,21 +9616,22 @@ main(void) } { - IMC::ButtonEvent msg; - msg.setTimeStamp(0.564779644715); - msg.setSource(14810U); - msg.setSourceEntity(117U); - msg.setDestination(59605U); - msg.setDestinationEntity(17U); - msg.button = 76U; - msg.value = 80U; + IMC::CameraZoom msg; + msg.setTimeStamp(0.9666774591846642); + msg.setSource(18163U); + msg.setSourceEntity(74U); + msg.setDestination(63205U); + msg.setDestinationEntity(198U); + msg.id = 9U; + msg.zoom = 113U; + msg.action = 75U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ButtonEvent #0", msg == *msg_d); + test.boolean("CameraZoom #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9273,21 +9642,22 @@ main(void) } { - IMC::ButtonEvent msg; - msg.setTimeStamp(0.652219872636); - msg.setSource(19261U); - msg.setSourceEntity(150U); - msg.setDestination(24779U); - msg.setDestinationEntity(31U); - msg.button = 185U; - msg.value = 36U; + IMC::CameraZoom msg; + msg.setTimeStamp(0.5515195429414181); + msg.setSource(61030U); + msg.setSourceEntity(17U); + msg.setDestination(22279U); + msg.setDestinationEntity(109U); + msg.id = 3U; + msg.zoom = 240U; + msg.action = 161U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ButtonEvent #1", msg == *msg_d); + test.boolean("CameraZoom #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9298,21 +9668,22 @@ main(void) } { - IMC::ButtonEvent msg; - msg.setTimeStamp(0.825517259691); - msg.setSource(45962U); - msg.setSourceEntity(89U); - msg.setDestination(34110U); - msg.setDestinationEntity(28U); - msg.button = 88U; - msg.value = 102U; + IMC::CameraZoom msg; + msg.setTimeStamp(0.9438479814877957); + msg.setSource(32357U); + msg.setSourceEntity(164U); + msg.setDestination(4518U); + msg.setDestinationEntity(217U); + msg.id = 225U; + msg.zoom = 107U; + msg.action = 3U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ButtonEvent #2", msg == *msg_d); + test.boolean("CameraZoom #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9323,21 +9694,21 @@ main(void) } { - IMC::LcdControl msg; - msg.setTimeStamp(0.244357084588); - msg.setSource(1923U); - msg.setSourceEntity(75U); - msg.setDestination(1226U); - msg.setDestinationEntity(214U); - msg.op = 105U; - msg.text.assign("UEITQPEDUPAFFOADDPHXKLHKCFSRNWNKLJKQBAXBIRMXTZCGSBPUYGZBUIIBZ"); + IMC::SetThrusterActuation msg; + msg.setTimeStamp(0.9569986544783335); + msg.setSource(1849U); + msg.setSourceEntity(38U); + msg.setDestination(31895U); + msg.setDestinationEntity(37U); + msg.id = 194U; + msg.value = 0.9298443308280284; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LcdControl #0", msg == *msg_d); + test.boolean("SetThrusterActuation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9348,21 +9719,21 @@ main(void) } { - IMC::LcdControl msg; - msg.setTimeStamp(0.8535353414); - msg.setSource(61830U); - msg.setSourceEntity(164U); - msg.setDestination(31486U); - msg.setDestinationEntity(93U); - msg.op = 66U; - msg.text.assign("DJEIGMTVEJSPMHBQTLZBVAQWDMSMPFNRLXSWKBRVWIPJCDJXIHNLSEFXJIKYXGNQNHTAWCWCUDKONKFRBTYGVCHKLOIGAGYUFPCIRFJTMAOGSBVWQAXZVUMRYZPTSCXLYTKXCZBBOVAYUYYTEDXPOHGWUAORIISRXIFZNHLGDFMCXQBPOPMOZHKJHEUAOEZDQ"); + IMC::SetThrusterActuation msg; + msg.setTimeStamp(0.03667864948928701); + msg.setSource(262U); + msg.setSourceEntity(232U); + msg.setDestination(50739U); + msg.setDestinationEntity(235U); + msg.id = 133U; + msg.value = 0.5856734988443679; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LcdControl #1", msg == *msg_d); + test.boolean("SetThrusterActuation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9373,21 +9744,21 @@ main(void) } { - IMC::LcdControl msg; - msg.setTimeStamp(0.558147700565); - msg.setSource(22644U); - msg.setSourceEntity(47U); - msg.setDestination(8901U); - msg.setDestinationEntity(204U); - msg.op = 72U; - msg.text.assign("FIPSQXUAPTQQGOXGINYTPMMRZDUGGVQAASVNVJRFPWIROHUDZ"); + IMC::SetThrusterActuation msg; + msg.setTimeStamp(0.541131851975396); + msg.setSource(41273U); + msg.setSourceEntity(40U); + msg.setDestination(27013U); + msg.setDestinationEntity(49U); + msg.id = 186U; + msg.value = 0.6226118496909172; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LcdControl #2", msg == *msg_d); + test.boolean("SetThrusterActuation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9398,22 +9769,21 @@ main(void) } { - IMC::PowerOperation msg; - msg.setTimeStamp(0.843500282952); - msg.setSource(28324U); - msg.setSourceEntity(135U); - msg.setDestination(34660U); - msg.setDestinationEntity(25U); - msg.op = 59U; - msg.time_remain = 0.727365434997; - msg.sched_time = 0.809881265677; + IMC::SetServoPosition msg; + msg.setTimeStamp(0.6041206061150617); + msg.setSource(47655U); + msg.setSourceEntity(92U); + msg.setDestination(50263U); + msg.setDestinationEntity(103U); + msg.id = 142U; + msg.value = 0.7708743654312927; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerOperation #0", msg == *msg_d); + test.boolean("SetServoPosition #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9424,22 +9794,21 @@ main(void) } { - IMC::PowerOperation msg; - msg.setTimeStamp(0.913054130486); - msg.setSource(57426U); - msg.setSourceEntity(125U); - msg.setDestination(6512U); - msg.setDestinationEntity(44U); - msg.op = 184U; - msg.time_remain = 0.0424847739349; - msg.sched_time = 0.930360463128; + IMC::SetServoPosition msg; + msg.setTimeStamp(0.7376973434307852); + msg.setSource(9998U); + msg.setSourceEntity(75U); + msg.setDestination(53017U); + msg.setDestinationEntity(206U); + msg.id = 163U; + msg.value = 0.5359370300643934; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerOperation #1", msg == *msg_d); + test.boolean("SetServoPosition #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9450,22 +9819,21 @@ main(void) } { - IMC::PowerOperation msg; - msg.setTimeStamp(0.673508893762); - msg.setSource(55811U); - msg.setSourceEntity(28U); - msg.setDestination(32321U); - msg.setDestinationEntity(139U); - msg.op = 96U; - msg.time_remain = 0.260028307521; - msg.sched_time = 0.615126655466; + IMC::SetServoPosition msg; + msg.setTimeStamp(0.031911570149464996); + msg.setSource(52985U); + msg.setSourceEntity(250U); + msg.setDestination(21571U); + msg.setDestinationEntity(127U); + msg.id = 181U; + msg.value = 0.06062458185089503; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerOperation #2", msg == *msg_d); + test.boolean("SetServoPosition #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9476,22 +9844,21 @@ main(void) } { - IMC::PowerChannelControl msg; - msg.setTimeStamp(0.0771021695394); - msg.setSource(54687U); - msg.setSourceEntity(107U); - msg.setDestination(2955U); - msg.setDestinationEntity(74U); - msg.name.assign("LWYJPALARMEESBKNXDISLYZPEFFBAWBYDCCLDOLWQOTWREHPJMZJQVILHDWAYCVLNCUKEYHKXROXBMGBICVXWCSGKTJMMUKXBNSLNIIMFUGJAFDUZOGRPYEMFGZPVFVEZTQNPUMQO"); - msg.op = 146U; - msg.sched_time = 0.8121711611; + IMC::SetControlSurfaceDeflection msg; + msg.setTimeStamp(0.4638628107178947); + msg.setSource(38743U); + msg.setSourceEntity(75U); + msg.setDestination(7862U); + msg.setDestinationEntity(81U); + msg.id = 228U; + msg.angle = 0.9748387226295138; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerChannelControl #0", msg == *msg_d); + test.boolean("SetControlSurfaceDeflection #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9502,22 +9869,21 @@ main(void) } { - IMC::PowerChannelControl msg; - msg.setTimeStamp(0.726756806779); - msg.setSource(20074U); - msg.setSourceEntity(217U); - msg.setDestination(13454U); - msg.setDestinationEntity(182U); - msg.name.assign("VPRBJCFKOCKXMDEUPYASRURQBAVENTENDQAYAIZIBTQALQXMHPHPLXOTXFVHS"); - msg.op = 211U; - msg.sched_time = 0.85106796337; + IMC::SetControlSurfaceDeflection msg; + msg.setTimeStamp(0.8277196475307522); + msg.setSource(3521U); + msg.setSourceEntity(225U); + msg.setDestination(60184U); + msg.setDestinationEntity(144U); + msg.id = 167U; + msg.angle = 0.08777533429257789; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerChannelControl #1", msg == *msg_d); + test.boolean("SetControlSurfaceDeflection #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9528,22 +9894,21 @@ main(void) } { - IMC::PowerChannelControl msg; - msg.setTimeStamp(0.0933866561913); - msg.setSource(3239U); - msg.setSourceEntity(88U); - msg.setDestination(39144U); - msg.setDestinationEntity(138U); - msg.name.assign("GNSGQMRVYFIGCCXCWMTBMYIRWSFRVOXNPLOFLONOIXAVZSJIPUGOHUZFTKHMIMBBDGLGJIXMOEPZE"); - msg.op = 87U; - msg.sched_time = 0.548827152116; + IMC::SetControlSurfaceDeflection msg; + msg.setTimeStamp(0.3029619213401181); + msg.setSource(56469U); + msg.setSourceEntity(213U); + msg.setDestination(65229U); + msg.setDestinationEntity(23U); + msg.id = 180U; + msg.angle = 0.5192050156176319; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerChannelControl #2", msg == *msg_d); + test.boolean("SetControlSurfaceDeflection #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9554,19 +9919,21 @@ main(void) } { - IMC::QueryPowerChannelState msg; - msg.setTimeStamp(0.994482676048); - msg.setSource(43865U); - msg.setSourceEntity(41U); - msg.setDestination(9712U); - msg.setDestinationEntity(160U); + IMC::RemoteActionsRequest msg; + msg.setTimeStamp(0.662246841913244); + msg.setSource(14235U); + msg.setSourceEntity(169U); + msg.setDestination(54181U); + msg.setDestinationEntity(124U); + msg.op = 170U; + msg.actions.assign("CTANQNSIKBFQLXGOIKDFYHMLFNZKLZMDPKLMPNOJK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryPowerChannelState #0", msg == *msg_d); + test.boolean("RemoteActionsRequest #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9577,19 +9944,21 @@ main(void) } { - IMC::QueryPowerChannelState msg; - msg.setTimeStamp(0.621643356688); - msg.setSource(45837U); - msg.setSourceEntity(167U); - msg.setDestination(29433U); - msg.setDestinationEntity(37U); + IMC::RemoteActionsRequest msg; + msg.setTimeStamp(0.5468007144603139); + msg.setSource(60120U); + msg.setSourceEntity(141U); + msg.setDestination(13406U); + msg.setDestinationEntity(148U); + msg.op = 101U; + msg.actions.assign("TTLCGCIQBPLPWUUOVQFGHJPEM"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryPowerChannelState #1", msg == *msg_d); + test.boolean("RemoteActionsRequest #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9600,19 +9969,21 @@ main(void) } { - IMC::QueryPowerChannelState msg; - msg.setTimeStamp(0.069706088374); - msg.setSource(34418U); - msg.setSourceEntity(21U); - msg.setDestination(41678U); - msg.setDestinationEntity(218U); + IMC::RemoteActionsRequest msg; + msg.setTimeStamp(0.46455369457150064); + msg.setSource(12922U); + msg.setSourceEntity(24U); + msg.setDestination(49376U); + msg.setDestinationEntity(133U); + msg.op = 81U; + msg.actions.assign("XVYOCHLHUIMJRVBOTYJSGGWHCFDYJFWXNOMPMFKKUWEIKATYWQAGSC"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryPowerChannelState #2", msg == *msg_d); + test.boolean("RemoteActionsRequest #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9623,21 +9994,20 @@ main(void) } { - IMC::PowerChannelState msg; - msg.setTimeStamp(0.527158893863); - msg.setSource(35304U); - msg.setSourceEntity(206U); - msg.setDestination(52863U); - msg.setDestinationEntity(236U); - msg.name.assign("OWBVTWNIOLJXTANAUYCGUWZINCMKHDVSGDKXAOLHMKWAQMV"); - msg.state = 12U; + IMC::RemoteActions msg; + msg.setTimeStamp(0.41493499817329127); + msg.setSource(37599U); + msg.setSourceEntity(3U); + msg.setDestination(61296U); + msg.setDestinationEntity(219U); + msg.actions.assign("KGQAROOADZCZALMKAQSEYLPJQW"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerChannelState #0", msg == *msg_d); + test.boolean("RemoteActions #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9648,21 +10018,20 @@ main(void) } { - IMC::PowerChannelState msg; - msg.setTimeStamp(0.667857218678); - msg.setSource(42949U); - msg.setSourceEntity(198U); - msg.setDestination(57910U); - msg.setDestinationEntity(27U); - msg.name.assign("AKJDUZGSJHCBFHHGWDYITJPMZGLRVBEMBWXALKTSCQVCUEEN"); - msg.state = 215U; + IMC::RemoteActions msg; + msg.setTimeStamp(0.20615910527895653); + msg.setSource(42042U); + msg.setSourceEntity(109U); + msg.setDestination(52733U); + msg.setDestinationEntity(100U); + msg.actions.assign("OTYSLWQEBSOBCZRVIANHQEWNFABOKKCRPREOYEEZYTOJHHYCWAXLHUFXYSHGILYATAZYZWKIIOXHLCMOVPCDKWCBRNZOQFJYFNZLWOTXLDAQKWEUSKGARBKNGGFMUZULIJCISARSZVJFPNLFSRDGIBFVSZFOPBPXTAXTRHUCJNIPAN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerChannelState #1", msg == *msg_d); + test.boolean("RemoteActions #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9673,21 +10042,20 @@ main(void) } { - IMC::PowerChannelState msg; - msg.setTimeStamp(0.502939724699); - msg.setSource(38945U); - msg.setSourceEntity(102U); - msg.setDestination(29635U); - msg.setDestinationEntity(200U); - msg.name.assign("BCXMLNXITTDIEGNPIXMELBWGWQJUIKKFHUCZHVJFTJVVFDJJTYASDAQYZIDQCQTMLTXNWBRWFUCWWSRLLUVQZXOHZAYSFZZGAIKQBLGGTTZSQNKRYJAKVUMNWLOHAOBXPPYKEFCGSUEOWNXPYQPYVOSMXPJOEVDWMIMYYDRRBXGCORGHKFZOHCNRCEEIHJVTHSRUQENDOGVBSRAKMFUKBJPYBNZZPLEHPFJXCQLBAURDMIPWVOSL"); - msg.state = 126U; + IMC::RemoteActions msg; + msg.setTimeStamp(0.8198453997622991); + msg.setSource(36429U); + msg.setSourceEntity(31U); + msg.setDestination(54455U); + msg.setDestinationEntity(107U); + msg.actions.assign("BYQEODVJCVWCPLORYOFAVTIZGROGRSQCSATHWWKBAZKCBMBZLUDUYVXXXVMSKIHDCREUQHIXKKZODXHBLVJKXPMKSZJHHKMJRFPLWPNWIFTYTLNFGRUOSVYOSDUWYPQMQZQGNGRDFFKPQPRBVEYGXSCXHICMNOELQIWBPVTUAPJAEVZLIJBINNJDUJAQCDTGFSSRN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PowerChannelState #2", msg == *msg_d); + test.boolean("RemoteActions #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9698,21 +10066,21 @@ main(void) } { - IMC::LedBrightness msg; - msg.setTimeStamp(0.334623971768); - msg.setSource(15554U); - msg.setSourceEntity(100U); - msg.setDestination(49048U); - msg.setDestinationEntity(14U); - msg.name.assign("ALHODIZUBEHAJBTKMLQLGAPZHRJKQDIGRGJWQJSAEKNVDWLZZK"); - msg.value = 225U; + IMC::ButtonEvent msg; + msg.setTimeStamp(0.8392773865598234); + msg.setSource(52655U); + msg.setSourceEntity(249U); + msg.setDestination(21291U); + msg.setDestinationEntity(4U); + msg.button = 156U; + msg.value = 253U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LedBrightness #0", msg == *msg_d); + test.boolean("ButtonEvent #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9723,21 +10091,21 @@ main(void) } { - IMC::LedBrightness msg; - msg.setTimeStamp(0.754176010059); - msg.setSource(29307U); - msg.setSourceEntity(185U); - msg.setDestination(17303U); - msg.setDestinationEntity(208U); - msg.name.assign("UZDYQGIOEOHNXLXJPUJKRVXBXFXAXZGSQHYSOLSNGVZBCJSPGREJNTAOMLAQESDQDWKVZLDWTCCTYMCHYBFRQVGODAIFJWRPWDHWLUAMTYEHVLVUFZMHISCAWSMKNCRJDNOMIRHLENJCBOPFAATSTUIHPREKVYDPXIPKLAFVUXMBETIINQLZHQYDGQYPACGFLBSYRZTKBDMUGBIWXRVFT"); - msg.value = 116U; + IMC::ButtonEvent msg; + msg.setTimeStamp(0.35083844008030685); + msg.setSource(45553U); + msg.setSourceEntity(41U); + msg.setDestination(33144U); + msg.setDestinationEntity(26U); + msg.button = 105U; + msg.value = 150U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LedBrightness #1", msg == *msg_d); + test.boolean("ButtonEvent #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9748,21 +10116,21 @@ main(void) } { - IMC::LedBrightness msg; - msg.setTimeStamp(0.869668300765); - msg.setSource(48273U); - msg.setSourceEntity(16U); - msg.setDestination(34468U); - msg.setDestinationEntity(87U); - msg.name.assign("YDPOIJBWFQAKVMEKCFSIPGRSVXKUEMQAVBCUZYVZKASCXSTWETLRFPTXRIFZFYRUWALEFTXBQWTZHSDSXMLMFCZTOYJKKMNJSVZLJGNWWSEBIVHQJAMCWNRRILGZGHZPBAIZGTYYKRMLONNYDMXMDCKSGNLTYEHVWPQUGDHNFCAXTJVBTIDN"); - msg.value = 24U; + IMC::ButtonEvent msg; + msg.setTimeStamp(0.9044503509213007); + msg.setSource(31842U); + msg.setSourceEntity(84U); + msg.setDestination(60798U); + msg.setDestinationEntity(138U); + msg.button = 92U; + msg.value = 199U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LedBrightness #2", msg == *msg_d); + test.boolean("ButtonEvent #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9773,20 +10141,21 @@ main(void) } { - IMC::QueryLedBrightness msg; - msg.setTimeStamp(0.915795966048); - msg.setSource(58671U); - msg.setSourceEntity(161U); - msg.setDestination(53521U); - msg.setDestinationEntity(47U); - msg.name.assign("ALXUGFJQAXBYFUZUISCJBUZEKPTZSHTITZYBGWAEEEJLDQVPPWFHPVMYEWAWOTVFNQSYFHMKIMNIGSODRRMAHFFVEDMWAPPIXJVAZSTKXTYHWYOIGRBDCUVRIWSGPKOVCYDKZNXUUBKFRRQOTEVRZKGBQQUSRPTYLJANMKNXMROSCCWZCUDZHWDGENLTAMLOOQUNCXCOIFNKSLJHLP"); + IMC::LcdControl msg; + msg.setTimeStamp(0.4121264110501559); + msg.setSource(21305U); + msg.setSourceEntity(113U); + msg.setDestination(17116U); + msg.setDestinationEntity(92U); + msg.op = 105U; + msg.text.assign("TURNIHJCZPIRKAZRKHSQABOFJWOXOLZUAWSV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryLedBrightness #0", msg == *msg_d); + test.boolean("LcdControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9797,20 +10166,21 @@ main(void) } { - IMC::QueryLedBrightness msg; - msg.setTimeStamp(0.103158350201); - msg.setSource(31670U); - msg.setSourceEntity(186U); - msg.setDestination(33967U); - msg.setDestinationEntity(226U); - msg.name.assign("WTKHJEBSZVZQVDAKNJEAGIHXJRPPPHZQVBRBPRJOAAXGTIGBJDHKRLRLQBMZLGIOJNXNFXOFIQVBXSZTYIWYEGFVIYVTRNMKCAPQUBMIXHVFADZPBMWGCEIZPFCCOUNNYFKUSFYDSROWGENXDKAOWGFRLTEHATHYYWJWTFCFCSUNYYIXTSSZILAZQRME"); + IMC::LcdControl msg; + msg.setTimeStamp(0.0671680546758936); + msg.setSource(43872U); + msg.setSourceEntity(169U); + msg.setDestination(4658U); + msg.setDestinationEntity(9U); + msg.op = 135U; + msg.text.assign("WZHWZDIVVCTGQXOXSONAHTRTQDZCQXTOAYODXVYEPIGSPQVRTOGDUPFUBHZKJTEMYGSHFVXLBONGXREIFIJXULZKCXQYNFQMYZJEBVAOKBGPZNSWJZPCLDDMAYGBUKLZBNEMLDQRWWTUPBJTYRENLYTYDMNMIIXUKABBINMVHQHATWFMMPEQYJFVVELASFWWOGRHREJGNJCWBLSD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryLedBrightness #1", msg == *msg_d); + test.boolean("LcdControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9821,20 +10191,21 @@ main(void) } { - IMC::QueryLedBrightness msg; - msg.setTimeStamp(0.719449543281); - msg.setSource(4258U); - msg.setSourceEntity(183U); - msg.setDestination(23609U); - msg.setDestinationEntity(77U); - msg.name.assign("FYOENWKYHEDATIJNXKXGQMWMGRGRFJKSETEGAFIZRCBFNIRGMUYOOLAHIPDVLXSZJKCPXTXDXPTTQSHKJMYFHCOUQICBBNQQTLPTIWSDCSWOAZHXUQGCFCCZOQJSWQJYVHOEVNLEVDVSN"); + IMC::LcdControl msg; + msg.setTimeStamp(0.26321319716705815); + msg.setSource(17636U); + msg.setSourceEntity(50U); + msg.setDestination(51081U); + msg.setDestinationEntity(245U); + msg.op = 15U; + msg.text.assign("UQDMWBSSPZPJDHIHMRLHCXFUTHCQYOWQCJEMEDXEPIQAOIMUDNDNNBLJVIRQFXJZLZYLQGPAKLOKYWRYJCSCTWYBFFPDWAWSXKPLEUGWKBFJSIURQVUKTKGXCKOKITPFAUHQOZDANFVSOYUBOGIVJTGQJBOOYMJMNRMZWISLHYFACXLMGRVGTTQYWGTVHBXNRJGDMIHRZDAULTVBAECLEVPWFEZYXXFCCHRNXSMZDPKEHNNRZB"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryLedBrightness #2", msg == *msg_d); + test.boolean("LcdControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9845,21 +10216,22 @@ main(void) } { - IMC::SetLedBrightness msg; - msg.setTimeStamp(0.721900587156); - msg.setSource(19343U); - msg.setSourceEntity(247U); - msg.setDestination(36191U); - msg.setDestinationEntity(76U); - msg.name.assign("FRQTGIMGHMJFQYLRSCFAWNDTWZRBAQHFRT"); - msg.value = 49U; + IMC::PowerOperation msg; + msg.setTimeStamp(0.12050746452345162); + msg.setSource(47005U); + msg.setSourceEntity(2U); + msg.setDestination(20044U); + msg.setDestinationEntity(252U); + msg.op = 232U; + msg.time_remain = 0.8830273434063644; + msg.sched_time = 0.7053302461894689; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetLedBrightness #0", msg == *msg_d); + test.boolean("PowerOperation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9870,21 +10242,22 @@ main(void) } { - IMC::SetLedBrightness msg; - msg.setTimeStamp(0.258574349241); - msg.setSource(22397U); - msg.setSourceEntity(230U); - msg.setDestination(59959U); - msg.setDestinationEntity(234U); - msg.name.assign("WWGJZYDAKUUBQVAJPJBRDAQWOIQAPLOSAZLIHKVHCPVXDCDXYQOJNIMCNNWTEKBYBTRUTFVDZRMNCUGCQRQOSBGLKMPK"); - msg.value = 30U; + IMC::PowerOperation msg; + msg.setTimeStamp(0.4509364619802224); + msg.setSource(56862U); + msg.setSourceEntity(223U); + msg.setDestination(41424U); + msg.setDestinationEntity(123U); + msg.op = 126U; + msg.time_remain = 0.24701232640933457; + msg.sched_time = 0.7419797860272671; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetLedBrightness #1", msg == *msg_d); + test.boolean("PowerOperation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9895,21 +10268,22 @@ main(void) } { - IMC::SetLedBrightness msg; - msg.setTimeStamp(0.624788476846); - msg.setSource(31012U); - msg.setSourceEntity(77U); - msg.setDestination(19986U); - msg.setDestinationEntity(74U); - msg.name.assign("WANKOOKYVOHWLKH"); - msg.value = 110U; + IMC::PowerOperation msg; + msg.setTimeStamp(0.07342913622078229); + msg.setSource(4955U); + msg.setSourceEntity(58U); + msg.setDestination(57764U); + msg.setDestinationEntity(36U); + msg.op = 184U; + msg.time_remain = 0.309424085636142; + msg.sched_time = 0.46864735436533556; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetLedBrightness #2", msg == *msg_d); + test.boolean("PowerOperation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9920,22 +10294,22 @@ main(void) } { - IMC::SetPWM msg; - msg.setTimeStamp(0.382779947105); - msg.setSource(22168U); - msg.setSourceEntity(205U); - msg.setDestination(51026U); - msg.setDestinationEntity(92U); - msg.id = 88U; - msg.period = 3541042619U; - msg.duty_cycle = 3554887416U; + IMC::PowerChannelControl msg; + msg.setTimeStamp(0.2957141837596029); + msg.setSource(58813U); + msg.setSourceEntity(96U); + msg.setDestination(41358U); + msg.setDestinationEntity(93U); + msg.name.assign("FMXFTYUXBMSZLVBICNWMSSQHRGMZARDGEBINLHKMMGZVSEQYVGIRIPDXRTCRXBCEAEGSFKLJGJDLOYXKDYRVWOAQDDGUAMZUBKBCLZIUEHEULISFQQFWOHSRRBNYFEYGJPWHYHAZJNPBAPDNQTTVWJBYUEDNTLOXWIVVPCCZJYOHFDTJ"); + msg.op = 62U; + msg.sched_time = 0.8257258876541913; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetPWM #0", msg == *msg_d); + test.boolean("PowerChannelControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9946,22 +10320,22 @@ main(void) } { - IMC::SetPWM msg; - msg.setTimeStamp(0.818698897668); - msg.setSource(17508U); - msg.setSourceEntity(229U); - msg.setDestination(47035U); - msg.setDestinationEntity(171U); - msg.id = 226U; - msg.period = 2020999413U; - msg.duty_cycle = 107764526U; + IMC::PowerChannelControl msg; + msg.setTimeStamp(0.5084658579929535); + msg.setSource(45601U); + msg.setSourceEntity(246U); + msg.setDestination(40940U); + msg.setDestinationEntity(220U); + msg.name.assign("XPGGTJRKBEEYEDBTJCOUVOFZKZOGCIOZRUCAVWGHBEHKLJHJXTOYIZVMVFPQIUMYKJXPJAN"); + msg.op = 199U; + msg.sched_time = 0.09087845088002078; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetPWM #1", msg == *msg_d); + test.boolean("PowerChannelControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9972,22 +10346,22 @@ main(void) } { - IMC::SetPWM msg; - msg.setTimeStamp(0.130409602403); - msg.setSource(30190U); - msg.setSourceEntity(154U); - msg.setDestination(37132U); - msg.setDestinationEntity(243U); - msg.id = 59U; - msg.period = 3363978933U; - msg.duty_cycle = 778034209U; + IMC::PowerChannelControl msg; + msg.setTimeStamp(0.5522839012872274); + msg.setSource(3783U); + msg.setSourceEntity(210U); + msg.setDestination(3173U); + msg.setDestinationEntity(67U); + msg.name.assign("CVARHAXYIDBOINHGCHJAGOQRXZCDCEROGAXAEAGVPGJAUWCVTBJLWQDZEQOLJQ"); + msg.op = 222U; + msg.sched_time = 0.2800050249987035; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetPWM #2", msg == *msg_d); + test.boolean("PowerChannelControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -9998,22 +10372,19 @@ main(void) } { - IMC::PWM msg; - msg.setTimeStamp(0.991893540916); - msg.setSource(43146U); - msg.setSourceEntity(103U); - msg.setDestination(1769U); - msg.setDestinationEntity(100U); - msg.id = 136U; - msg.period = 3072360788U; - msg.duty_cycle = 21731486U; + IMC::QueryPowerChannelState msg; + msg.setTimeStamp(0.45662098748450564); + msg.setSource(64537U); + msg.setSourceEntity(208U); + msg.setDestination(31798U); + msg.setDestinationEntity(117U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PWM #0", msg == *msg_d); + test.boolean("QueryPowerChannelState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10024,22 +10395,19 @@ main(void) } { - IMC::PWM msg; - msg.setTimeStamp(0.739930475936); - msg.setSource(9440U); - msg.setSourceEntity(140U); - msg.setDestination(39615U); - msg.setDestinationEntity(214U); - msg.id = 242U; - msg.period = 3511625011U; - msg.duty_cycle = 3354534521U; + IMC::QueryPowerChannelState msg; + msg.setTimeStamp(0.8103400212603956); + msg.setSource(46630U); + msg.setSourceEntity(3U); + msg.setDestination(53984U); + msg.setDestinationEntity(150U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PWM #1", msg == *msg_d); + test.boolean("QueryPowerChannelState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10050,22 +10418,19 @@ main(void) } { - IMC::PWM msg; - msg.setTimeStamp(0.0840398256071); - msg.setSource(22478U); - msg.setSourceEntity(63U); - msg.setDestination(30433U); - msg.setDestinationEntity(240U); - msg.id = 61U; - msg.period = 2854833247U; - msg.duty_cycle = 2432944564U; + IMC::QueryPowerChannelState msg; + msg.setTimeStamp(0.14883627789673193); + msg.setSource(64347U); + msg.setSourceEntity(75U); + msg.setDestination(2349U); + msg.setDestinationEntity(55U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PWM #2", msg == *msg_d); + test.boolean("QueryPowerChannelState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10076,39 +10441,21 @@ main(void) } { - IMC::EstimatedState msg; - msg.setTimeStamp(0.836624620643); - msg.setSource(36858U); - msg.setSourceEntity(164U); - msg.setDestination(59907U); - msg.setDestinationEntity(18U); - msg.lat = 0.588233155787; - msg.lon = 0.0378696913107; - msg.height = 0.866115193002; - msg.x = 0.693523670638; - msg.y = 0.579368938037; - msg.z = 0.62881544576; - msg.phi = 0.0704848206376; - msg.theta = 0.926305768933; - msg.psi = 0.806846429647; - msg.u = 0.881918112412; - msg.v = 0.295671346569; - msg.w = 0.623266652383; - msg.vx = 0.416158027176; - msg.vy = 0.878081043179; - msg.vz = 0.442181266319; - msg.p = 0.470155827172; - msg.q = 0.912002221252; - msg.r = 0.977197120042; - msg.depth = 0.20512303668; - msg.alt = 0.241124998204; + IMC::PowerChannelState msg; + msg.setTimeStamp(0.1291632399686672); + msg.setSource(59279U); + msg.setSourceEntity(214U); + msg.setDestination(48388U); + msg.setDestinationEntity(44U); + msg.name.assign("BZOEPNDITLCWQXRJAHSJKOHKDUUJNWNLBXQKWRJBQREVZICKYIGYGPVRIGVSHFQKAZSESYLNEZMOEKTXVRMVQOFQMWTBSYRX"); + msg.state = 98U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EstimatedState #0", msg == *msg_d); + test.boolean("PowerChannelState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10119,39 +10466,21 @@ main(void) } { - IMC::EstimatedState msg; - msg.setTimeStamp(0.382936903608); - msg.setSource(61805U); - msg.setSourceEntity(93U); - msg.setDestination(48289U); - msg.setDestinationEntity(126U); - msg.lat = 0.88391489318; - msg.lon = 0.948561011893; - msg.height = 0.949981656884; - msg.x = 0.643599821009; - msg.y = 0.13383297229; - msg.z = 0.377072108378; - msg.phi = 0.469801389893; - msg.theta = 0.718164141907; - msg.psi = 0.341375181639; - msg.u = 0.656941744528; - msg.v = 0.759807923281; - msg.w = 0.080912715769; - msg.vx = 0.0734424906912; - msg.vy = 0.0291865241443; - msg.vz = 0.739676895075; - msg.p = 0.132286007199; - msg.q = 0.405410547234; - msg.r = 0.350624513529; - msg.depth = 0.72062811425; - msg.alt = 0.50934379399; + IMC::PowerChannelState msg; + msg.setTimeStamp(0.8218298195118201); + msg.setSource(39206U); + msg.setSourceEntity(241U); + msg.setDestination(33726U); + msg.setDestinationEntity(155U); + msg.name.assign("KGWTCCABKPOJOYUFHTUMEVZQMLUIBHDXZIXLMVIJPZRGOLKWGOGECJUBLHCESNWRLQZAZIRFYFYAGMQHMOIOTBNLXFSDKEDYJNIZUMQIMIJOGPWVVPHUQFETNVQJFFBASLSRDNTHLJSEGKJYXOGRKSZEYINHQCPCXOWXDHQNC"); + msg.state = 152U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EstimatedState #1", msg == *msg_d); + test.boolean("PowerChannelState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10162,39 +10491,21 @@ main(void) } { - IMC::EstimatedState msg; - msg.setTimeStamp(0.502188413618); - msg.setSource(12028U); - msg.setSourceEntity(163U); - msg.setDestination(31878U); - msg.setDestinationEntity(125U); - msg.lat = 0.842839435349; - msg.lon = 0.532158905538; - msg.height = 0.322225211786; - msg.x = 0.9960581286; - msg.y = 0.665323394075; - msg.z = 0.649248391304; - msg.phi = 0.592200648337; - msg.theta = 0.794185109109; - msg.psi = 0.680084256775; - msg.u = 0.407623801543; - msg.v = 0.133139765855; - msg.w = 0.734933237378; - msg.vx = 0.702536273595; - msg.vy = 0.976311233523; - msg.vz = 0.0164945885646; - msg.p = 0.327283928848; - msg.q = 0.202171569907; - msg.r = 0.664343316346; - msg.depth = 0.630732639881; - msg.alt = 0.826630975989; + IMC::PowerChannelState msg; + msg.setTimeStamp(0.8884971195475733); + msg.setSource(20758U); + msg.setSourceEntity(18U); + msg.setDestination(52144U); + msg.setDestinationEntity(22U); + msg.name.assign("EAGZLLOXNUFXCGYTVBQWKXNMUDCQAUQQNMJIFNESCYWCQDASLVQHHNWYSQGXGRVJYXOEMMPVVUJJPKATDHRXKPLBEXKJMJSGWIRECEIWLWTWSIPHDIOUYFBMAWAZIFZLYJGDBCHWUNRIFXHTR"); + msg.state = 14U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EstimatedState #2", msg == *msg_d); + test.boolean("PowerChannelState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10205,22 +10516,21 @@ main(void) } { - IMC::EstimatedStreamVelocity msg; - msg.setTimeStamp(0.883475248318); - msg.setSource(55327U); - msg.setSourceEntity(3U); - msg.setDestination(5547U); - msg.setDestinationEntity(166U); - msg.x = 0.859696587719; - msg.y = 0.923580405404; - msg.z = 0.536041864946; + IMC::LedBrightness msg; + msg.setTimeStamp(0.5890518910531974); + msg.setSource(61349U); + msg.setSourceEntity(71U); + msg.setDestination(43689U); + msg.setDestinationEntity(186U); + msg.name.assign("KFBDUMCZPSSBXTFFFYCGTGISAZJAPQCXBWGOXJRCTXZQFWYORZIABIRQKUSXEKTUPKIIQGEWYMXIMALHVMZKPIRULGXDLHHYRJMHLBKSJYFVMSHRHQWQNHWVUWAJNHCPTURVDLCHJOTTOGDVUEWCEATJLQEEZJRVBJLONDCOAKYQZAVVMXOZETBSXDJSMNKQMSGL"); + msg.value = 177U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EstimatedStreamVelocity #0", msg == *msg_d); + test.boolean("LedBrightness #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10231,22 +10541,21 @@ main(void) } { - IMC::EstimatedStreamVelocity msg; - msg.setTimeStamp(0.027849318579); - msg.setSource(48601U); - msg.setSourceEntity(119U); - msg.setDestination(49725U); - msg.setDestinationEntity(95U); - msg.x = 0.678787535518; - msg.y = 0.856383272641; - msg.z = 0.683665038545; + IMC::LedBrightness msg; + msg.setTimeStamp(0.6376986115740099); + msg.setSource(22341U); + msg.setSourceEntity(101U); + msg.setDestination(2292U); + msg.setDestinationEntity(213U); + msg.name.assign("SMQLPGOCKZDNLQXNDSSJDIDSBWKUMBETPZVTRMYUHQGKWPSAPNXNVBXWFIBGMBWTYQKHHOHCHVRVFMFABMWXWGCSKODOLYTLXAYNWSJFPUOMIIDPIOUEQAWDCCEUFAXBXEGNFNQVEAOUPEOERUN"); + msg.value = 67U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EstimatedStreamVelocity #1", msg == *msg_d); + test.boolean("LedBrightness #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10257,22 +10566,21 @@ main(void) } { - IMC::EstimatedStreamVelocity msg; - msg.setTimeStamp(0.347569055728); - msg.setSource(4189U); - msg.setSourceEntity(236U); - msg.setDestination(35541U); - msg.setDestinationEntity(106U); - msg.x = 0.722451704732; - msg.y = 0.498215680077; - msg.z = 0.686837366007; + IMC::LedBrightness msg; + msg.setTimeStamp(0.24129686711036702); + msg.setSource(33748U); + msg.setSourceEntity(176U); + msg.setDestination(43448U); + msg.setDestinationEntity(97U); + msg.name.assign("NJMJRKEILIZDAMOIVKFDIENSZQYJBACXGSLMFNWHNCOHVFCYIN"); + msg.value = 21U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EstimatedStreamVelocity #2", msg == *msg_d); + test.boolean("LedBrightness #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10283,20 +10591,20 @@ main(void) } { - IMC::IndicatedSpeed msg; - msg.setTimeStamp(0.454679674419); - msg.setSource(42813U); - msg.setSourceEntity(108U); - msg.setDestination(48310U); - msg.setDestinationEntity(14U); - msg.value = 0.091664734656; + IMC::QueryLedBrightness msg; + msg.setTimeStamp(0.3453344697517191); + msg.setSource(28444U); + msg.setSourceEntity(166U); + msg.setDestination(37467U); + msg.setDestinationEntity(186U); + msg.name.assign("ROXDVDWACGSLWXJPFQZANLIEOIAHJOQMXDXGUESMQUONHPJLKFFG"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IndicatedSpeed #0", msg == *msg_d); + test.boolean("QueryLedBrightness #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10307,20 +10615,20 @@ main(void) } { - IMC::IndicatedSpeed msg; - msg.setTimeStamp(0.909563103612); - msg.setSource(63696U); - msg.setSourceEntity(80U); - msg.setDestination(8805U); - msg.setDestinationEntity(173U); - msg.value = 0.980689069278; + IMC::QueryLedBrightness msg; + msg.setTimeStamp(0.79628299834984); + msg.setSource(17931U); + msg.setSourceEntity(229U); + msg.setDestination(1051U); + msg.setDestinationEntity(65U); + msg.name.assign("LZRIPKXQUHOB"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IndicatedSpeed #1", msg == *msg_d); + test.boolean("QueryLedBrightness #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10331,20 +10639,20 @@ main(void) } { - IMC::IndicatedSpeed msg; - msg.setTimeStamp(0.501616172302); - msg.setSource(31363U); - msg.setSourceEntity(89U); - msg.setDestination(30953U); - msg.setDestinationEntity(88U); - msg.value = 0.831021542578; + IMC::QueryLedBrightness msg; + msg.setTimeStamp(0.9159274430594652); + msg.setSource(55383U); + msg.setSourceEntity(1U); + msg.setDestination(1386U); + msg.setDestinationEntity(194U); + msg.name.assign("CEWZRLCVFMWWOCAVCXOZTRCGHDNYVRKNSROPXSSEAIWPJVULVIMGZDMSXKKVRAZMBPREUIRQDGOLLWQWJCOSCERDQAVLQNYXIQKGOZRCEBNMHYGXAKIUXHT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IndicatedSpeed #2", msg == *msg_d); + test.boolean("QueryLedBrightness #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10355,20 +10663,21 @@ main(void) } { - IMC::TrueSpeed msg; - msg.setTimeStamp(0.302550756097); - msg.setSource(34988U); - msg.setSourceEntity(186U); - msg.setDestination(8043U); - msg.setDestinationEntity(192U); - msg.value = 0.206274342458; + IMC::SetLedBrightness msg; + msg.setTimeStamp(0.4091690170455946); + msg.setSource(64061U); + msg.setSourceEntity(194U); + msg.setDestination(18881U); + msg.setDestinationEntity(127U); + msg.name.assign("VPRTGCWBKBUZQTYXFTTJUOKHQZFYQSZBNJUGRVNZPGBYSJDXAJYXBWHLZLGBCLNWYHPWUQELXICKLPNHCIAENXQHJNCLJHKJRIOQVFOGYKUJPQ"); + msg.value = 177U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrueSpeed #0", msg == *msg_d); + test.boolean("SetLedBrightness #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10379,20 +10688,21 @@ main(void) } { - IMC::TrueSpeed msg; - msg.setTimeStamp(0.838201206986); - msg.setSource(4286U); - msg.setSourceEntity(60U); - msg.setDestination(51290U); - msg.setDestinationEntity(49U); - msg.value = 0.57505090455; + IMC::SetLedBrightness msg; + msg.setTimeStamp(0.7103859568507707); + msg.setSource(36070U); + msg.setSourceEntity(61U); + msg.setDestination(46684U); + msg.setDestinationEntity(118U); + msg.name.assign("MNSVAMPMANPKRTJIVBYQBXPQPHEVTCRAJQTVKAHEKCUTHGVLFJOXDTZEEHKRLINDUYMJILCIWGDRCERCJHXHCXGKFPRAQGLIXCNMIATDWNLWOXOFGSY"); + msg.value = 41U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrueSpeed #1", msg == *msg_d); + test.boolean("SetLedBrightness #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10403,20 +10713,21 @@ main(void) } { - IMC::TrueSpeed msg; - msg.setTimeStamp(0.30592710394); - msg.setSource(30646U); - msg.setSourceEntity(236U); - msg.setDestination(47153U); - msg.setDestinationEntity(129U); - msg.value = 0.838513382782; + IMC::SetLedBrightness msg; + msg.setTimeStamp(0.02449969158153209); + msg.setSource(39617U); + msg.setSourceEntity(206U); + msg.setDestination(44530U); + msg.setDestinationEntity(200U); + msg.name.assign("RKNXBYVKKMSTCPDMFEZHIVZGPZJONRTHBL"); + msg.value = 18U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrueSpeed #2", msg == *msg_d); + test.boolean("SetLedBrightness #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10427,33 +10738,22 @@ main(void) } { - IMC::NavigationUncertainty msg; - msg.setTimeStamp(0.834968478887); - msg.setSource(1372U); - msg.setSourceEntity(55U); - msg.setDestination(25333U); - msg.setDestinationEntity(229U); - msg.x = 0.708629399575; - msg.y = 0.64440593016; - msg.z = 0.0647454627156; - msg.phi = 0.636331869131; - msg.theta = 0.102143727992; - msg.psi = 0.220908253434; - msg.p = 0.612858412008; - msg.q = 0.884822645177; - msg.r = 0.384895227839; - msg.u = 0.269581793481; - msg.v = 0.0264121151166; - msg.w = 0.186568142321; - msg.bias_psi = 0.846723412799; - msg.bias_r = 0.661012188836; + IMC::SetPWM msg; + msg.setTimeStamp(0.6842073338550382); + msg.setSource(6969U); + msg.setSourceEntity(153U); + msg.setDestination(43437U); + msg.setDestinationEntity(217U); + msg.id = 210U; + msg.period = 1280193775U; + msg.duty_cycle = 167469222U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NavigationUncertainty #0", msg == *msg_d); + test.boolean("SetPWM #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10464,33 +10764,22 @@ main(void) } { - IMC::NavigationUncertainty msg; - msg.setTimeStamp(0.922988219372); - msg.setSource(40739U); - msg.setSourceEntity(204U); - msg.setDestination(48434U); - msg.setDestinationEntity(66U); - msg.x = 0.339267043656; - msg.y = 0.510193698131; - msg.z = 0.907728161903; - msg.phi = 0.931170382477; - msg.theta = 0.625499070075; - msg.psi = 0.335251940936; - msg.p = 0.243034907268; - msg.q = 0.200482036889; - msg.r = 0.458358416771; - msg.u = 0.150028670556; - msg.v = 0.888220449122; - msg.w = 0.0185536222549; - msg.bias_psi = 0.681494436812; - msg.bias_r = 0.926854278973; + IMC::SetPWM msg; + msg.setTimeStamp(0.15773663318750475); + msg.setSource(2252U); + msg.setSourceEntity(33U); + msg.setDestination(42840U); + msg.setDestinationEntity(40U); + msg.id = 133U; + msg.period = 1509878794U; + msg.duty_cycle = 768236959U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NavigationUncertainty #1", msg == *msg_d); + test.boolean("SetPWM #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10501,33 +10790,22 @@ main(void) } { - IMC::NavigationUncertainty msg; - msg.setTimeStamp(0.344441997944); - msg.setSource(5994U); - msg.setSourceEntity(52U); - msg.setDestination(38187U); - msg.setDestinationEntity(69U); - msg.x = 0.00986624701008; - msg.y = 0.332243497389; - msg.z = 0.428517817881; - msg.phi = 0.717316872037; - msg.theta = 0.0683605941932; - msg.psi = 0.0407029452539; - msg.p = 0.34938176022; - msg.q = 0.7529444881; - msg.r = 0.871280620381; - msg.u = 0.203104537736; - msg.v = 0.0503793768024; - msg.w = 0.703950022617; - msg.bias_psi = 0.911534887423; - msg.bias_r = 0.036352920847; + IMC::SetPWM msg; + msg.setTimeStamp(0.5375284935829404); + msg.setSource(49288U); + msg.setSourceEntity(194U); + msg.setDestination(50774U); + msg.setDestinationEntity(239U); + msg.id = 216U; + msg.period = 661928003U; + msg.duty_cycle = 541330623U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NavigationUncertainty #2", msg == *msg_d); + test.boolean("SetPWM #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10538,28 +10816,22 @@ main(void) } { - IMC::NavigationData msg; - msg.setTimeStamp(0.972324689984); - msg.setSource(28026U); - msg.setSourceEntity(212U); - msg.setDestination(26810U); - msg.setDestinationEntity(219U); - msg.bias_psi = 0.122631550197; - msg.bias_r = 0.47097301875; - msg.cog = 0.0542495700727; - msg.cyaw = 0.0579074277928; - msg.lbl_rej_level = 0.620885370762; - msg.gps_rej_level = 0.532332521143; - msg.custom_x = 0.714455607872; - msg.custom_y = 0.00347108817487; - msg.custom_z = 0.982114104582; + IMC::PWM msg; + msg.setTimeStamp(0.741085235764107); + msg.setSource(54624U); + msg.setSourceEntity(60U); + msg.setDestination(34809U); + msg.setDestinationEntity(127U); + msg.id = 37U; + msg.period = 1873383715U; + msg.duty_cycle = 2415106283U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NavigationData #0", msg == *msg_d); + test.boolean("PWM #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10570,28 +10842,22 @@ main(void) } { - IMC::NavigationData msg; - msg.setTimeStamp(0.121858767851); - msg.setSource(9354U); - msg.setSourceEntity(30U); - msg.setDestination(12872U); - msg.setDestinationEntity(44U); - msg.bias_psi = 0.694663094776; - msg.bias_r = 0.869249115899; - msg.cog = 0.421702879857; - msg.cyaw = 0.818460459891; - msg.lbl_rej_level = 0.532659846466; - msg.gps_rej_level = 0.243767814286; - msg.custom_x = 0.427933518718; - msg.custom_y = 0.353071971673; - msg.custom_z = 0.180656985251; + IMC::PWM msg; + msg.setTimeStamp(0.33778342865484956); + msg.setSource(22611U); + msg.setSourceEntity(147U); + msg.setDestination(8073U); + msg.setDestinationEntity(100U); + msg.id = 151U; + msg.period = 3566467667U; + msg.duty_cycle = 266390605U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NavigationData #1", msg == *msg_d); + test.boolean("PWM #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10602,28 +10868,22 @@ main(void) } { - IMC::NavigationData msg; - msg.setTimeStamp(0.481598796356); - msg.setSource(42085U); - msg.setSourceEntity(190U); - msg.setDestination(23388U); - msg.setDestinationEntity(227U); - msg.bias_psi = 0.0664640617435; - msg.bias_r = 0.285789808593; - msg.cog = 0.00694720599657; - msg.cyaw = 0.854386226282; - msg.lbl_rej_level = 0.867279167819; - msg.gps_rej_level = 0.537889193453; - msg.custom_x = 0.0876222641666; - msg.custom_y = 0.115584623797; - msg.custom_z = 0.407471769859; - + IMC::PWM msg; + msg.setTimeStamp(0.184114069354401); + msg.setSource(58181U); + msg.setSourceEntity(144U); + msg.setDestination(49411U); + msg.setDestinationEntity(21U); + msg.id = 131U; + msg.period = 3376667015U; + msg.duty_cycle = 2867229019U; + try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NavigationData #2", msg == *msg_d); + test.boolean("PWM #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10634,21 +10894,39 @@ main(void) } { - IMC::GpsFixRejection msg; - msg.setTimeStamp(0.00287035806439); - msg.setSource(12808U); - msg.setSourceEntity(142U); - msg.setDestination(35349U); - msg.setDestinationEntity(125U); - msg.utc_time = 0.724676644781; - msg.reason = 18U; + IMC::EstimatedState msg; + msg.setTimeStamp(0.1524287704842654); + msg.setSource(37973U); + msg.setSourceEntity(252U); + msg.setDestination(48786U); + msg.setDestinationEntity(188U); + msg.lat = 0.40656252189406983; + msg.lon = 0.7925324161658751; + msg.height = 0.8392806882299162; + msg.x = 0.6629773748740103; + msg.y = 0.8194720547051207; + msg.z = 0.1187789654578274; + msg.phi = 0.27606846860117007; + msg.theta = 0.5646740146706719; + msg.psi = 0.23782743374803272; + msg.u = 0.1833360657998706; + msg.v = 0.8140360944430776; + msg.w = 0.581565464157542; + msg.vx = 0.8958495271870918; + msg.vy = 0.530856651363685; + msg.vz = 0.2089579910012037; + msg.p = 0.5913952184909713; + msg.q = 0.748364716869815; + msg.r = 0.5742669000693638; + msg.depth = 0.5708902720076167; + msg.alt = 0.8907935414039169; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFixRejection #0", msg == *msg_d); + test.boolean("EstimatedState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10659,21 +10937,39 @@ main(void) } { - IMC::GpsFixRejection msg; - msg.setTimeStamp(0.968066357606); - msg.setSource(42974U); - msg.setSourceEntity(32U); - msg.setDestination(1262U); - msg.setDestinationEntity(34U); - msg.utc_time = 0.640122443756; - msg.reason = 54U; + IMC::EstimatedState msg; + msg.setTimeStamp(0.30112656229457); + msg.setSource(9592U); + msg.setSourceEntity(39U); + msg.setDestination(34810U); + msg.setDestinationEntity(90U); + msg.lat = 0.4983234781305673; + msg.lon = 0.3238222078992814; + msg.height = 0.846445628040765; + msg.x = 0.25896642920124935; + msg.y = 0.5381406516120878; + msg.z = 0.2539186409589388; + msg.phi = 0.8118906422241993; + msg.theta = 0.09858290719363005; + msg.psi = 0.5856691115277193; + msg.u = 0.5211481723040908; + msg.v = 0.12487713268894196; + msg.w = 0.12271741749836274; + msg.vx = 0.888623761681313; + msg.vy = 0.1490684653665758; + msg.vz = 0.2247548327193588; + msg.p = 0.8339994476142621; + msg.q = 0.3529503027558285; + msg.r = 0.20823726354768113; + msg.depth = 0.34023059332309225; + msg.alt = 0.9946083099700638; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFixRejection #1", msg == *msg_d); + test.boolean("EstimatedState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10684,21 +10980,39 @@ main(void) } { - IMC::GpsFixRejection msg; - msg.setTimeStamp(0.0078703951099); - msg.setSource(12515U); - msg.setSourceEntity(174U); - msg.setDestination(42631U); - msg.setDestinationEntity(125U); - msg.utc_time = 0.314059523062; - msg.reason = 11U; + IMC::EstimatedState msg; + msg.setTimeStamp(0.6275315981095747); + msg.setSource(61439U); + msg.setSourceEntity(192U); + msg.setDestination(45907U); + msg.setDestinationEntity(216U); + msg.lat = 0.917243294207395; + msg.lon = 0.23057897828221308; + msg.height = 0.9012982176138327; + msg.x = 0.6636006175349007; + msg.y = 0.20387465873330435; + msg.z = 0.3689224467067188; + msg.phi = 0.7520247079406764; + msg.theta = 0.7423686488957502; + msg.psi = 0.846039151143489; + msg.u = 0.8087935814419026; + msg.v = 0.061969906248651285; + msg.w = 0.07406159626294517; + msg.vx = 0.11902990016713055; + msg.vy = 0.9920467778200217; + msg.vz = 0.43182908217259786; + msg.p = 0.16766477328381246; + msg.q = 0.2678846392173625; + msg.r = 0.9788261004273415; + msg.depth = 0.7157721436789506; + msg.alt = 0.9666887090132861; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GpsFixRejection #2", msg == *msg_d); + test.boolean("EstimatedState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10709,22 +11023,22 @@ main(void) } { - IMC::LblRangeAcceptance msg; - msg.setTimeStamp(0.133804277456); - msg.setSource(25810U); - msg.setSourceEntity(201U); - msg.setDestination(4941U); - msg.setDestinationEntity(228U); - msg.id = 93U; - msg.range = 0.668989542606; - msg.acceptance = 124U; + IMC::EstimatedStreamVelocity msg; + msg.setTimeStamp(0.01445230589292168); + msg.setSource(19317U); + msg.setSourceEntity(32U); + msg.setDestination(41546U); + msg.setDestinationEntity(201U); + msg.x = 0.9508929212403431; + msg.y = 0.987083789010241; + msg.z = 0.5410184090588275; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblRangeAcceptance #0", msg == *msg_d); + test.boolean("EstimatedStreamVelocity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10735,22 +11049,22 @@ main(void) } { - IMC::LblRangeAcceptance msg; - msg.setTimeStamp(0.373345747663); - msg.setSource(25812U); - msg.setSourceEntity(215U); - msg.setDestination(22190U); - msg.setDestinationEntity(158U); - msg.id = 222U; - msg.range = 0.157616559472; - msg.acceptance = 146U; + IMC::EstimatedStreamVelocity msg; + msg.setTimeStamp(0.13132264839684615); + msg.setSource(34360U); + msg.setSourceEntity(5U); + msg.setDestination(59033U); + msg.setDestinationEntity(132U); + msg.x = 0.4742221332007245; + msg.y = 0.3138668677807599; + msg.z = 0.03822219776129543; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblRangeAcceptance #1", msg == *msg_d); + test.boolean("EstimatedStreamVelocity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10761,22 +11075,22 @@ main(void) } { - IMC::LblRangeAcceptance msg; - msg.setTimeStamp(0.308464314782); - msg.setSource(3088U); - msg.setSourceEntity(2U); - msg.setDestination(32787U); - msg.setDestinationEntity(137U); - msg.id = 110U; - msg.range = 0.898334412822; - msg.acceptance = 152U; + IMC::EstimatedStreamVelocity msg; + msg.setTimeStamp(0.010965688126520101); + msg.setSource(21501U); + msg.setSourceEntity(238U); + msg.setDestination(36753U); + msg.setDestinationEntity(252U); + msg.x = 0.6615813850760814; + msg.y = 0.8635972490281826; + msg.z = 0.8345833863544322; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblRangeAcceptance #2", msg == *msg_d); + test.boolean("EstimatedStreamVelocity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10787,23 +11101,20 @@ main(void) } { - IMC::DvlRejection msg; - msg.setTimeStamp(0.136266445851); - msg.setSource(50185U); - msg.setSourceEntity(47U); - msg.setDestination(5955U); - msg.setDestinationEntity(57U); - msg.type = 0U; - msg.reason = 30U; - msg.value = 0.512703467067; - msg.timestep = 0.638784974119; + IMC::IndicatedSpeed msg; + msg.setTimeStamp(0.07685251773381574); + msg.setSource(29872U); + msg.setSourceEntity(127U); + msg.setDestination(19158U); + msg.setDestinationEntity(25U); + msg.value = 0.9861474758858838; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DvlRejection #0", msg == *msg_d); + test.boolean("IndicatedSpeed #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10814,23 +11125,20 @@ main(void) } { - IMC::DvlRejection msg; - msg.setTimeStamp(0.949735855819); - msg.setSource(41965U); - msg.setSourceEntity(88U); - msg.setDestination(13957U); - msg.setDestinationEntity(183U); - msg.type = 88U; - msg.reason = 238U; - msg.value = 0.401057795315; - msg.timestep = 0.667230422975; + IMC::IndicatedSpeed msg; + msg.setTimeStamp(0.10642329538558482); + msg.setSource(64257U); + msg.setSourceEntity(130U); + msg.setDestination(48060U); + msg.setDestinationEntity(206U); + msg.value = 0.6603666332503807; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DvlRejection #1", msg == *msg_d); + test.boolean("IndicatedSpeed #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10841,23 +11149,20 @@ main(void) } { - IMC::DvlRejection msg; - msg.setTimeStamp(0.548304476502); - msg.setSource(19496U); - msg.setSourceEntity(14U); - msg.setDestination(51759U); - msg.setDestinationEntity(249U); - msg.type = 63U; - msg.reason = 153U; - msg.value = 0.722238697982; - msg.timestep = 0.198647134145; + IMC::IndicatedSpeed msg; + msg.setTimeStamp(0.6838215358931833); + msg.setSource(60076U); + msg.setSourceEntity(215U); + msg.setDestination(15214U); + msg.setDestinationEntity(55U); + msg.value = 0.19104976194411105; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DvlRejection #2", msg == *msg_d); + test.boolean("IndicatedSpeed #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10868,33 +11173,20 @@ main(void) } { - IMC::LblEstimate msg; - msg.setTimeStamp(0.40831469064); - msg.setSource(25706U); - msg.setSourceEntity(227U); - msg.setDestination(41811U); - msg.setDestinationEntity(6U); - IMC::LblBeacon tmp_msg_0; - tmp_msg_0.beacon.assign("ITCCWHLOGHDMBXXNWNTEYSFOKLYMQTZMHWFEWLLGWGDSEAUPMTVGVKRSRZNUEKDGAOSUUPTXAEVKKKQCODZIJWBIAIYWRNSXSHMPJBGOMUXCFHPEUJCOIWSCTXEZIYKJZDAYLQYZZVUHPXAFZTJTGNTIUADJBMXKJRKUMGJPXBHDBOGOYLBIYTWOCMJGBFFVNQQLQCFRUNCLVQNWDRBSVMJOARXEZZPVEDHRIPNLLSCAREHPYPQQQFNFAIYKH"); - tmp_msg_0.lat = 0.724171776638; - tmp_msg_0.lon = 0.798067143035; - tmp_msg_0.depth = 0.227181319206; - tmp_msg_0.query_channel = 59U; - tmp_msg_0.reply_channel = 101U; - tmp_msg_0.transponder_delay = 164U; - msg.beacon.set(tmp_msg_0); - msg.x = 0.569951858401; - msg.y = 0.0582587012083; - msg.var_x = 0.47868395799; - msg.var_y = 0.951951909781; - msg.distance = 0.193900715913; + IMC::TrueSpeed msg; + msg.setTimeStamp(0.6969648997067688); + msg.setSource(57516U); + msg.setSourceEntity(213U); + msg.setDestination(10017U); + msg.setDestinationEntity(182U); + msg.value = 0.040633067570631676; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblEstimate #0", msg == *msg_d); + test.boolean("TrueSpeed #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10905,33 +11197,20 @@ main(void) } { - IMC::LblEstimate msg; - msg.setTimeStamp(0.418137074846); - msg.setSource(35180U); - msg.setSourceEntity(136U); - msg.setDestination(18015U); - msg.setDestinationEntity(25U); - IMC::LblBeacon tmp_msg_0; - tmp_msg_0.beacon.assign("SAIYOUTRTFXBNLRTXYNGENROKXQEDCXVBINSCZFOEDZPVPEZKQUFWJLYWUPDFKVKNTVKYVXGVYMELUMQETSLMSZOZEBHGQLHLJRPYJTTFACWAWQSCMBWHYNQDZKVFDTXKUFMYKGHESJZUBWRBPUCQQRIFWCWUTOPDGAHJEVGMDPYMIOOA"); - tmp_msg_0.lat = 0.281592214277; - tmp_msg_0.lon = 0.528129420208; - tmp_msg_0.depth = 0.796201945179; - tmp_msg_0.query_channel = 17U; - tmp_msg_0.reply_channel = 56U; - tmp_msg_0.transponder_delay = 130U; - msg.beacon.set(tmp_msg_0); - msg.x = 0.207891072714; - msg.y = 0.585909393091; - msg.var_x = 0.0682539569828; - msg.var_y = 0.061573643251; - msg.distance = 0.505842461095; + IMC::TrueSpeed msg; + msg.setTimeStamp(0.47294714805368565); + msg.setSource(14189U); + msg.setSourceEntity(175U); + msg.setDestination(62680U); + msg.setDestinationEntity(16U); + msg.value = 0.016831228916724283; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblEstimate #1", msg == *msg_d); + test.boolean("TrueSpeed #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10942,33 +11221,20 @@ main(void) } { - IMC::LblEstimate msg; - msg.setTimeStamp(0.861898529296); - msg.setSource(7744U); - msg.setSourceEntity(77U); - msg.setDestination(28182U); - msg.setDestinationEntity(197U); - IMC::LblBeacon tmp_msg_0; - tmp_msg_0.beacon.assign("VTPRJJUERWMINTRJCNXFZFMLSCDHHOCYMNEWVWXPQKWAIPJELRFCGBGESRUBNVGQMYAEBNAFEHFQWBBZCTQDZDKJGMNGZOMXWVGBEJSULHMTBQYICCUDEJQKHWXVHYNCZMFYRTXPQUGVOLGMPZSYAOPOZTBIKWPIHNOJFNCOAKMOBDLLTRFXSVLIDXFPKLSOZBXKKRIUQRRVQXKUGE"); - tmp_msg_0.lat = 0.636015325495; - tmp_msg_0.lon = 0.601203127859; - tmp_msg_0.depth = 0.934214615689; - tmp_msg_0.query_channel = 126U; - tmp_msg_0.reply_channel = 248U; - tmp_msg_0.transponder_delay = 237U; - msg.beacon.set(tmp_msg_0); - msg.x = 0.147365655193; - msg.y = 0.873119108978; - msg.var_x = 0.0172497833036; - msg.var_y = 0.142391222714; - msg.distance = 0.837395378847; + IMC::TrueSpeed msg; + msg.setTimeStamp(0.9563225011805778); + msg.setSource(60453U); + msg.setSourceEntity(98U); + msg.setDestination(43895U); + msg.setDestinationEntity(172U); + msg.value = 0.2812579028785953; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LblEstimate #2", msg == *msg_d); + test.boolean("TrueSpeed #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -10979,20 +11245,33 @@ main(void) } { - IMC::AlignmentState msg; - msg.setTimeStamp(0.181437866674); - msg.setSource(9533U); - msg.setSourceEntity(55U); - msg.setDestination(18722U); - msg.setDestinationEntity(170U); - msg.state = 19U; + IMC::NavigationUncertainty msg; + msg.setTimeStamp(0.24076432436849327); + msg.setSource(33728U); + msg.setSourceEntity(75U); + msg.setDestination(7624U); + msg.setDestinationEntity(72U); + msg.x = 0.1677554308549497; + msg.y = 0.6609013216107681; + msg.z = 0.6887110514282938; + msg.phi = 0.21910737366710464; + msg.theta = 0.9756918537267368; + msg.psi = 0.2132533743373768; + msg.p = 0.2650999621866039; + msg.q = 0.9410244930118905; + msg.r = 0.1754036371361214; + msg.u = 0.13766373730513404; + msg.v = 0.9316472398795623; + msg.w = 0.2849705980928089; + msg.bias_psi = 0.1779991592708844; + msg.bias_r = 0.3530320385817681; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AlignmentState #0", msg == *msg_d); + test.boolean("NavigationUncertainty #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11003,20 +11282,33 @@ main(void) } { - IMC::AlignmentState msg; - msg.setTimeStamp(0.314780644443); - msg.setSource(15547U); - msg.setSourceEntity(254U); - msg.setDestination(39322U); - msg.setDestinationEntity(150U); - msg.state = 116U; + IMC::NavigationUncertainty msg; + msg.setTimeStamp(0.6640042695183153); + msg.setSource(34694U); + msg.setSourceEntity(134U); + msg.setDestination(37938U); + msg.setDestinationEntity(2U); + msg.x = 0.2769127258543782; + msg.y = 0.12019840268056403; + msg.z = 0.8293920972541344; + msg.phi = 0.15917286917661666; + msg.theta = 0.9210242605990249; + msg.psi = 0.015246112258965439; + msg.p = 0.502509638692418; + msg.q = 0.6854694530094547; + msg.r = 0.8384498034002833; + msg.u = 0.2914888266276706; + msg.v = 0.6086915252095673; + msg.w = 0.30134038237658056; + msg.bias_psi = 0.39324785163859766; + msg.bias_r = 0.39794889894325935; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AlignmentState #1", msg == *msg_d); + test.boolean("NavigationUncertainty #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11027,20 +11319,33 @@ main(void) } { - IMC::AlignmentState msg; - msg.setTimeStamp(0.876889863301); - msg.setSource(9911U); - msg.setSourceEntity(91U); - msg.setDestination(11153U); - msg.setDestinationEntity(251U); - msg.state = 161U; + IMC::NavigationUncertainty msg; + msg.setTimeStamp(0.004255845717839435); + msg.setSource(23739U); + msg.setSourceEntity(89U); + msg.setDestination(45005U); + msg.setDestinationEntity(101U); + msg.x = 0.843780744967364; + msg.y = 0.9677774833694445; + msg.z = 0.954270099028828; + msg.phi = 0.02661430471231241; + msg.theta = 0.9191623694127468; + msg.psi = 0.6471962898401761; + msg.p = 0.9625463159690372; + msg.q = 0.6230246111639361; + msg.r = 0.5920805592901441; + msg.u = 0.6809386070372616; + msg.v = 0.5463172781944108; + msg.w = 0.6199796279219063; + msg.bias_psi = 0.9584103111731809; + msg.bias_r = 0.9795117955327375; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AlignmentState #2", msg == *msg_d); + test.boolean("NavigationUncertainty #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11051,22 +11356,28 @@ main(void) } { - IMC::GroupStreamVelocity msg; - msg.setTimeStamp(0.6937442695); - msg.setSource(40353U); - msg.setSourceEntity(190U); - msg.setDestination(5904U); - msg.setDestinationEntity(158U); - msg.x = 0.954866556314; - msg.y = 0.46728110555; - msg.z = 0.0867534227458; + IMC::NavigationData msg; + msg.setTimeStamp(0.8739293057366632); + msg.setSource(10645U); + msg.setSourceEntity(207U); + msg.setDestination(61031U); + msg.setDestinationEntity(205U); + msg.bias_psi = 0.02681836411356786; + msg.bias_r = 0.23818187896500354; + msg.cog = 0.7018478118246025; + msg.cyaw = 0.2922345791265789; + msg.lbl_rej_level = 0.17750835054757008; + msg.gps_rej_level = 0.4476033720896796; + msg.custom_x = 0.15183311229130947; + msg.custom_y = 0.7313039461380434; + msg.custom_z = 0.8418958325968573; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GroupStreamVelocity #0", msg == *msg_d); + test.boolean("NavigationData #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11077,22 +11388,28 @@ main(void) } { - IMC::GroupStreamVelocity msg; - msg.setTimeStamp(0.188982987686); - msg.setSource(28687U); - msg.setSourceEntity(103U); - msg.setDestination(11446U); - msg.setDestinationEntity(71U); - msg.x = 0.868451542692; - msg.y = 0.539824816185; - msg.z = 0.163192437225; + IMC::NavigationData msg; + msg.setTimeStamp(0.8294138067301232); + msg.setSource(33837U); + msg.setSourceEntity(219U); + msg.setDestination(47425U); + msg.setDestinationEntity(42U); + msg.bias_psi = 0.08612645345702674; + msg.bias_r = 0.1083716015664421; + msg.cog = 0.7878772702895043; + msg.cyaw = 0.14096978362951162; + msg.lbl_rej_level = 0.09394372745469792; + msg.gps_rej_level = 0.959552741795397; + msg.custom_x = 0.4286846078715144; + msg.custom_y = 0.9991427159391025; + msg.custom_z = 0.18634207700780647; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GroupStreamVelocity #1", msg == *msg_d); + test.boolean("NavigationData #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11103,22 +11420,28 @@ main(void) } { - IMC::GroupStreamVelocity msg; - msg.setTimeStamp(0.511413491343); - msg.setSource(53217U); - msg.setSourceEntity(105U); - msg.setDestination(29162U); - msg.setDestinationEntity(29U); - msg.x = 0.41529497794; - msg.y = 0.473968942054; - msg.z = 0.162024568372; + IMC::NavigationData msg; + msg.setTimeStamp(0.7824425975519026); + msg.setSource(14190U); + msg.setSourceEntity(79U); + msg.setDestination(63035U); + msg.setDestinationEntity(136U); + msg.bias_psi = 0.7628294067116013; + msg.bias_r = 0.7454360705732634; + msg.cog = 0.3008760460680794; + msg.cyaw = 0.883292013960557; + msg.lbl_rej_level = 0.5105320099855073; + msg.gps_rej_level = 0.4916491771774346; + msg.custom_x = 0.1880645149712239; + msg.custom_y = 0.5831791752946616; + msg.custom_z = 0.1096542092884899; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GroupStreamVelocity #2", msg == *msg_d); + test.boolean("NavigationData #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11129,22 +11452,21 @@ main(void) } { - IMC::Airflow msg; - msg.setTimeStamp(0.00217712345065); - msg.setSource(56745U); - msg.setSourceEntity(21U); - msg.setDestination(29137U); - msg.setDestinationEntity(209U); - msg.va = 0.846237447968; - msg.aoa = 0.347852308456; - msg.ssa = 0.697029927475; + IMC::GpsFixRejection msg; + msg.setTimeStamp(0.003545585875984192); + msg.setSource(23246U); + msg.setSourceEntity(125U); + msg.setDestination(61046U); + msg.setDestinationEntity(52U); + msg.utc_time = 0.8877329785976672; + msg.reason = 32U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Airflow #0", msg == *msg_d); + test.boolean("GpsFixRejection #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11155,22 +11477,21 @@ main(void) } { - IMC::Airflow msg; - msg.setTimeStamp(0.986422149707); - msg.setSource(45856U); - msg.setSourceEntity(216U); - msg.setDestination(65444U); - msg.setDestinationEntity(129U); - msg.va = 0.54129122737; - msg.aoa = 0.294203752142; - msg.ssa = 0.557012788516; + IMC::GpsFixRejection msg; + msg.setTimeStamp(0.8013722531151954); + msg.setSource(12536U); + msg.setSourceEntity(46U); + msg.setDestination(38714U); + msg.setDestinationEntity(198U); + msg.utc_time = 0.2627613155888555; + msg.reason = 205U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Airflow #1", msg == *msg_d); + test.boolean("GpsFixRejection #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11181,22 +11502,21 @@ main(void) } { - IMC::Airflow msg; - msg.setTimeStamp(0.59046834851); - msg.setSource(61517U); - msg.setSourceEntity(97U); - msg.setDestination(12956U); - msg.setDestinationEntity(159U); - msg.va = 0.418116891122; - msg.aoa = 0.632104566802; - msg.ssa = 0.874129657524; + IMC::GpsFixRejection msg; + msg.setTimeStamp(0.7014649832047934); + msg.setSource(56274U); + msg.setSourceEntity(5U); + msg.setDestination(11737U); + msg.setDestinationEntity(151U); + msg.utc_time = 0.8413651878811064; + msg.reason = 237U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Airflow #2", msg == *msg_d); + test.boolean("GpsFixRejection #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11207,20 +11527,22 @@ main(void) } { - IMC::DesiredHeading msg; - msg.setTimeStamp(0.300391995374); - msg.setSource(14504U); - msg.setSourceEntity(163U); - msg.setDestination(24185U); - msg.setDestinationEntity(148U); - msg.value = 0.895020530203; + IMC::LblRangeAcceptance msg; + msg.setTimeStamp(0.9470443103398072); + msg.setSource(50673U); + msg.setSourceEntity(136U); + msg.setDestination(28015U); + msg.setDestinationEntity(97U); + msg.id = 108U; + msg.range = 0.9275758938026755; + msg.acceptance = 101U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredHeading #0", msg == *msg_d); + test.boolean("LblRangeAcceptance #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11231,20 +11553,22 @@ main(void) } { - IMC::DesiredHeading msg; - msg.setTimeStamp(0.928352925685); - msg.setSource(64977U); - msg.setSourceEntity(96U); - msg.setDestination(6060U); - msg.setDestinationEntity(154U); - msg.value = 0.949455414359; + IMC::LblRangeAcceptance msg; + msg.setTimeStamp(0.5426565769278695); + msg.setSource(48682U); + msg.setSourceEntity(17U); + msg.setDestination(60945U); + msg.setDestinationEntity(206U); + msg.id = 30U; + msg.range = 0.7279244057280947; + msg.acceptance = 38U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredHeading #1", msg == *msg_d); + test.boolean("LblRangeAcceptance #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11255,20 +11579,22 @@ main(void) } { - IMC::DesiredHeading msg; - msg.setTimeStamp(0.926505067406); - msg.setSource(59997U); - msg.setSourceEntity(221U); - msg.setDestination(31141U); - msg.setDestinationEntity(193U); - msg.value = 0.815019171695; + IMC::LblRangeAcceptance msg; + msg.setTimeStamp(0.18642177847581254); + msg.setSource(42652U); + msg.setSourceEntity(63U); + msg.setDestination(33006U); + msg.setDestinationEntity(15U); + msg.id = 93U; + msg.range = 0.6984194262070157; + msg.acceptance = 107U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredHeading #2", msg == *msg_d); + test.boolean("LblRangeAcceptance #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11279,21 +11605,23 @@ main(void) } { - IMC::DesiredZ msg; - msg.setTimeStamp(0.594910804376); - msg.setSource(54615U); - msg.setSourceEntity(249U); - msg.setDestination(63887U); - msg.setDestinationEntity(105U); - msg.value = 0.911950718328; - msg.z_units = 247U; + IMC::DvlRejection msg; + msg.setTimeStamp(0.07842996328180485); + msg.setSource(27200U); + msg.setSourceEntity(181U); + msg.setDestination(36399U); + msg.setDestinationEntity(31U); + msg.type = 94U; + msg.reason = 35U; + msg.value = 0.1229017456441166; + msg.timestep = 0.8423196148666311; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredZ #0", msg == *msg_d); + test.boolean("DvlRejection #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11304,21 +11632,23 @@ main(void) } { - IMC::DesiredZ msg; - msg.setTimeStamp(0.843989739139); - msg.setSource(29833U); - msg.setSourceEntity(33U); - msg.setDestination(64766U); - msg.setDestinationEntity(20U); - msg.value = 0.505853280452; - msg.z_units = 196U; + IMC::DvlRejection msg; + msg.setTimeStamp(0.7511045718069647); + msg.setSource(32763U); + msg.setSourceEntity(251U); + msg.setDestination(36244U); + msg.setDestinationEntity(67U); + msg.type = 185U; + msg.reason = 232U; + msg.value = 0.8456759234641745; + msg.timestep = 0.43640893164321626; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredZ #1", msg == *msg_d); + test.boolean("DvlRejection #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11329,21 +11659,23 @@ main(void) } { - IMC::DesiredZ msg; - msg.setTimeStamp(0.243414424011); - msg.setSource(16660U); - msg.setSourceEntity(222U); - msg.setDestination(7995U); - msg.setDestinationEntity(10U); - msg.value = 0.66652899879; - msg.z_units = 2U; + IMC::DvlRejection msg; + msg.setTimeStamp(0.7630432936795443); + msg.setSource(56881U); + msg.setSourceEntity(234U); + msg.setDestination(65069U); + msg.setDestinationEntity(145U); + msg.type = 140U; + msg.reason = 132U; + msg.value = 0.680891915543549; + msg.timestep = 0.5281217551731788; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredZ #2", msg == *msg_d); + test.boolean("DvlRejection #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11354,21 +11686,33 @@ main(void) } { - IMC::DesiredSpeed msg; - msg.setTimeStamp(0.246461669068); - msg.setSource(3198U); - msg.setSourceEntity(104U); - msg.setDestination(8364U); - msg.setDestinationEntity(55U); - msg.value = 0.62329198728; - msg.speed_units = 15U; + IMC::LblEstimate msg; + msg.setTimeStamp(0.7238180973303145); + msg.setSource(51581U); + msg.setSourceEntity(225U); + msg.setDestination(54632U); + msg.setDestinationEntity(249U); + IMC::LblBeacon tmp_msg_0; + tmp_msg_0.beacon.assign("PJHCRQUOCUTUDVQFEJJBNPQUAGSALVRVEEGAWI"); + tmp_msg_0.lat = 0.3682418484610184; + tmp_msg_0.lon = 0.7140411956718918; + tmp_msg_0.depth = 0.9294375949447897; + tmp_msg_0.query_channel = 144U; + tmp_msg_0.reply_channel = 199U; + tmp_msg_0.transponder_delay = 163U; + msg.beacon.set(tmp_msg_0); + msg.x = 0.7082491061686018; + msg.y = 0.6474931777129094; + msg.var_x = 0.48052369795824235; + msg.var_y = 0.546634958302607; + msg.distance = 0.05579944927162084; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredSpeed #0", msg == *msg_d); + test.boolean("LblEstimate #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11379,21 +11723,33 @@ main(void) } { - IMC::DesiredSpeed msg; - msg.setTimeStamp(0.115404906378); - msg.setSource(1152U); - msg.setSourceEntity(112U); - msg.setDestination(25861U); - msg.setDestinationEntity(192U); - msg.value = 0.0995753739007; - msg.speed_units = 110U; + IMC::LblEstimate msg; + msg.setTimeStamp(0.978259251278217); + msg.setSource(3519U); + msg.setSourceEntity(162U); + msg.setDestination(18573U); + msg.setDestinationEntity(252U); + IMC::LblBeacon tmp_msg_0; + tmp_msg_0.beacon.assign("RKEDQBFTIAUKTQXFYXITMZWXIYFWHURWWSYGBISFEHSPFPUMVTVVKZYDZGFNSVEQOMIEENPGDBLBZOZHDGZSBINJCLJA"); + tmp_msg_0.lat = 0.21501134517850495; + tmp_msg_0.lon = 0.45375598337350553; + tmp_msg_0.depth = 0.6155263324733775; + tmp_msg_0.query_channel = 107U; + tmp_msg_0.reply_channel = 149U; + tmp_msg_0.transponder_delay = 82U; + msg.beacon.set(tmp_msg_0); + msg.x = 0.886742054244853; + msg.y = 0.2705662166426952; + msg.var_x = 0.6651359640702856; + msg.var_y = 0.9652960377877386; + msg.distance = 0.6214125401843219; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredSpeed #1", msg == *msg_d); + test.boolean("LblEstimate #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11404,21 +11760,33 @@ main(void) } { - IMC::DesiredSpeed msg; - msg.setTimeStamp(0.624994662662); - msg.setSource(54593U); - msg.setSourceEntity(101U); - msg.setDestination(64821U); - msg.setDestinationEntity(170U); - msg.value = 0.946172045341; - msg.speed_units = 192U; + IMC::LblEstimate msg; + msg.setTimeStamp(0.41316554506594216); + msg.setSource(54522U); + msg.setSourceEntity(249U); + msg.setDestination(14099U); + msg.setDestinationEntity(169U); + IMC::LblBeacon tmp_msg_0; + tmp_msg_0.beacon.assign("MCDBEJHRIFGJZPCIKVXIEVZVDZIRHXGSQDOFNISPRCCWVPIYAEDPKCSAHENFNAHAYTSAKBDWXERVQYSBTJWFOTUUEZBJASMBLXTPXGUNRLWFQCPJXIWBVHPQYXUUCZOEUSTXMZOKOEJTSPQVVHFEUKTLMDALYAWBJFYYKILPUGVUTSCOHCXNVBLRRGQUNAJOFIGPTWHGQMXYYLQMWLQDKDHWTMOIBZROGCNLJAWDNJZGKHQEMRMNZZDKRFMK"); + tmp_msg_0.lat = 0.6366290093836339; + tmp_msg_0.lon = 0.10998837365755332; + tmp_msg_0.depth = 0.9648930118573209; + tmp_msg_0.query_channel = 225U; + tmp_msg_0.reply_channel = 123U; + tmp_msg_0.transponder_delay = 241U; + msg.beacon.set(tmp_msg_0); + msg.x = 0.5233152029216649; + msg.y = 0.36525518171765636; + msg.var_x = 0.46027316066444734; + msg.var_y = 0.0419653396391535; + msg.distance = 0.6984881481374092; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredSpeed #2", msg == *msg_d); + test.boolean("LblEstimate #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11429,20 +11797,20 @@ main(void) } { - IMC::DesiredRoll msg; - msg.setTimeStamp(0.740726392072); - msg.setSource(3885U); - msg.setSourceEntity(215U); - msg.setDestination(42832U); - msg.setDestinationEntity(183U); - msg.value = 0.706556887392; + IMC::AlignmentState msg; + msg.setTimeStamp(0.6923958983258054); + msg.setSource(22083U); + msg.setSourceEntity(199U); + msg.setDestination(35471U); + msg.setDestinationEntity(212U); + msg.state = 126U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredRoll #0", msg == *msg_d); + test.boolean("AlignmentState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11453,20 +11821,20 @@ main(void) } { - IMC::DesiredRoll msg; - msg.setTimeStamp(0.483467660556); - msg.setSource(30251U); - msg.setSourceEntity(130U); - msg.setDestination(32197U); - msg.setDestinationEntity(172U); - msg.value = 0.24275911903; + IMC::AlignmentState msg; + msg.setTimeStamp(0.5344289263442178); + msg.setSource(54376U); + msg.setSourceEntity(203U); + msg.setDestination(30415U); + msg.setDestinationEntity(216U); + msg.state = 34U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredRoll #1", msg == *msg_d); + test.boolean("AlignmentState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11477,20 +11845,20 @@ main(void) } { - IMC::DesiredRoll msg; - msg.setTimeStamp(0.812503891468); - msg.setSource(35326U); - msg.setSourceEntity(18U); - msg.setDestination(3014U); - msg.setDestinationEntity(50U); - msg.value = 0.865825231415; + IMC::AlignmentState msg; + msg.setTimeStamp(0.24384584760630423); + msg.setSource(26392U); + msg.setSourceEntity(28U); + msg.setDestination(56349U); + msg.setDestinationEntity(198U); + msg.state = 107U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredRoll #2", msg == *msg_d); + test.boolean("AlignmentState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11501,20 +11869,22 @@ main(void) } { - IMC::DesiredPitch msg; - msg.setTimeStamp(0.529773823162); - msg.setSource(41563U); - msg.setSourceEntity(108U); - msg.setDestination(15878U); - msg.setDestinationEntity(71U); - msg.value = 0.14548294613; + IMC::GroupStreamVelocity msg; + msg.setTimeStamp(0.9066498279828816); + msg.setSource(6668U); + msg.setSourceEntity(80U); + msg.setDestination(62169U); + msg.setDestinationEntity(145U); + msg.x = 0.1447277617559426; + msg.y = 0.027969338640107644; + msg.z = 0.028534750586534985; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredPitch #0", msg == *msg_d); + test.boolean("GroupStreamVelocity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11525,20 +11895,22 @@ main(void) } { - IMC::DesiredPitch msg; - msg.setTimeStamp(0.507798098926); - msg.setSource(6801U); - msg.setSourceEntity(164U); - msg.setDestination(31138U); - msg.setDestinationEntity(245U); - msg.value = 0.773502039905; + IMC::GroupStreamVelocity msg; + msg.setTimeStamp(0.23876968301628898); + msg.setSource(24844U); + msg.setSourceEntity(144U); + msg.setDestination(29576U); + msg.setDestinationEntity(223U); + msg.x = 0.2949386553311819; + msg.y = 0.331720019850856; + msg.z = 0.5485913787821054; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredPitch #1", msg == *msg_d); + test.boolean("GroupStreamVelocity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11549,20 +11921,22 @@ main(void) } { - IMC::DesiredPitch msg; - msg.setTimeStamp(0.471162026829); - msg.setSource(40486U); - msg.setSourceEntity(55U); - msg.setDestination(22999U); - msg.setDestinationEntity(202U); - msg.value = 0.611902432272; + IMC::GroupStreamVelocity msg; + msg.setTimeStamp(0.08220113627466885); + msg.setSource(59147U); + msg.setSourceEntity(96U); + msg.setDestination(64611U); + msg.setDestinationEntity(248U); + msg.x = 0.6708071854047095; + msg.y = 0.9028473755823921; + msg.z = 0.5999072729686002; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredPitch #2", msg == *msg_d); + test.boolean("GroupStreamVelocity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11573,20 +11947,22 @@ main(void) } { - IMC::DesiredVerticalRate msg; - msg.setTimeStamp(0.477557181983); - msg.setSource(58828U); - msg.setSourceEntity(8U); - msg.setDestination(9717U); - msg.setDestinationEntity(95U); - msg.value = 0.0590055539132; + IMC::Airflow msg; + msg.setTimeStamp(0.8045101700614037); + msg.setSource(47803U); + msg.setSourceEntity(252U); + msg.setDestination(51441U); + msg.setDestinationEntity(90U); + msg.va = 0.4711448989024918; + msg.aoa = 0.19511824272539402; + msg.ssa = 0.5551201596068803; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredVerticalRate #0", msg == *msg_d); + test.boolean("Airflow #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11597,20 +11973,22 @@ main(void) } { - IMC::DesiredVerticalRate msg; - msg.setTimeStamp(0.493556365649); - msg.setSource(45941U); - msg.setSourceEntity(243U); - msg.setDestination(1557U); - msg.setDestinationEntity(119U); - msg.value = 0.798988029549; + IMC::Airflow msg; + msg.setTimeStamp(0.9628436095133681); + msg.setSource(21268U); + msg.setSourceEntity(193U); + msg.setDestination(32346U); + msg.setDestinationEntity(141U); + msg.va = 0.5527491301275858; + msg.aoa = 0.6298884062241754; + msg.ssa = 0.13915873686470992; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredVerticalRate #1", msg == *msg_d); + test.boolean("Airflow #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11621,20 +11999,22 @@ main(void) } { - IMC::DesiredVerticalRate msg; - msg.setTimeStamp(0.243434420347); - msg.setSource(37633U); - msg.setSourceEntity(233U); - msg.setDestination(37639U); - msg.setDestinationEntity(213U); - msg.value = 0.321972150742; + IMC::Airflow msg; + msg.setTimeStamp(0.7158872683995019); + msg.setSource(36278U); + msg.setSourceEntity(19U); + msg.setDestination(6284U); + msg.setDestinationEntity(238U); + msg.va = 0.08644489801539179; + msg.aoa = 0.24581227299765795; + msg.ssa = 0.14222769241056432; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredVerticalRate #2", msg == *msg_d); + test.boolean("Airflow #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11645,32 +12025,20 @@ main(void) } { - IMC::DesiredPath msg; - msg.setTimeStamp(0.0380928798752); - msg.setSource(32696U); - msg.setSourceEntity(26U); - msg.setDestination(45380U); - msg.setDestinationEntity(114U); - msg.path_ref = 4216051037U; - msg.start_lat = 0.218783889361; - msg.start_lon = 0.727608784811; - msg.start_z = 0.0977961361318; - msg.start_z_units = 153U; - msg.end_lat = 0.195687058345; - msg.end_lon = 0.270926553812; - msg.end_z = 0.311570371122; - msg.end_z_units = 43U; - msg.speed = 0.550769146642; - msg.speed_units = 228U; - msg.lradius = 0.294390482317; - msg.flags = 185U; + IMC::DesiredHeading msg; + msg.setTimeStamp(0.46368070732596744); + msg.setSource(7050U); + msg.setSourceEntity(22U); + msg.setDestination(40690U); + msg.setDestinationEntity(211U); + msg.value = 0.7782193506835509; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredPath #0", msg == *msg_d); + test.boolean("DesiredHeading #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11681,32 +12049,20 @@ main(void) } { - IMC::DesiredPath msg; - msg.setTimeStamp(0.323980516081); - msg.setSource(49785U); - msg.setSourceEntity(175U); - msg.setDestination(27060U); - msg.setDestinationEntity(43U); - msg.path_ref = 1867992548U; - msg.start_lat = 0.898639293702; - msg.start_lon = 0.4046249994; - msg.start_z = 0.74585186882; - msg.start_z_units = 165U; - msg.end_lat = 0.426476255303; - msg.end_lon = 0.644649850578; - msg.end_z = 0.753481322539; - msg.end_z_units = 179U; - msg.speed = 0.118100371179; - msg.speed_units = 64U; - msg.lradius = 0.518313154906; - msg.flags = 56U; + IMC::DesiredHeading msg; + msg.setTimeStamp(0.33632893649175744); + msg.setSource(49427U); + msg.setSourceEntity(127U); + msg.setDestination(20515U); + msg.setDestinationEntity(11U); + msg.value = 0.22884152108695943; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredPath #1", msg == *msg_d); + test.boolean("DesiredHeading #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11717,32 +12073,20 @@ main(void) } { - IMC::DesiredPath msg; - msg.setTimeStamp(0.726293217953); - msg.setSource(50814U); - msg.setSourceEntity(140U); - msg.setDestination(23370U); - msg.setDestinationEntity(182U); - msg.path_ref = 1535680144U; - msg.start_lat = 0.025211596212; - msg.start_lon = 0.944618573417; - msg.start_z = 0.745834403431; - msg.start_z_units = 32U; - msg.end_lat = 0.930647551172; - msg.end_lon = 0.626249872021; - msg.end_z = 0.192714516593; - msg.end_z_units = 143U; - msg.speed = 0.785297675557; - msg.speed_units = 229U; - msg.lradius = 0.215132209453; - msg.flags = 124U; + IMC::DesiredHeading msg; + msg.setTimeStamp(0.8060149743281885); + msg.setSource(13411U); + msg.setSourceEntity(134U); + msg.setDestination(5316U); + msg.setDestinationEntity(38U); + msg.value = 0.1887755352235293; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredPath #2", msg == *msg_d); + test.boolean("DesiredHeading #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11753,26 +12097,21 @@ main(void) } { - IMC::DesiredControl msg; - msg.setTimeStamp(0.0104399147371); - msg.setSource(61336U); - msg.setSourceEntity(200U); - msg.setDestination(54794U); - msg.setDestinationEntity(179U); - msg.x = 0.464442519215; - msg.y = 0.492662276311; - msg.z = 0.198804956615; - msg.k = 0.423381336611; - msg.m = 0.0202212330561; - msg.n = 0.511522959961; - msg.flags = 122U; + IMC::DesiredZ msg; + msg.setTimeStamp(0.5705572730979644); + msg.setSource(43162U); + msg.setSourceEntity(83U); + msg.setDestination(52135U); + msg.setDestinationEntity(88U); + msg.value = 0.5906233156402529; + msg.z_units = 32U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredControl #0", msg == *msg_d); + test.boolean("DesiredZ #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11783,26 +12122,21 @@ main(void) } { - IMC::DesiredControl msg; - msg.setTimeStamp(0.490284687715); - msg.setSource(42595U); - msg.setSourceEntity(190U); - msg.setDestination(44123U); - msg.setDestinationEntity(169U); - msg.x = 0.120102316531; - msg.y = 0.78464856979; - msg.z = 0.541730178307; - msg.k = 0.953417527323; - msg.m = 0.16470284693; - msg.n = 0.683057566949; - msg.flags = 27U; + IMC::DesiredZ msg; + msg.setTimeStamp(0.7766842679291888); + msg.setSource(61705U); + msg.setSourceEntity(73U); + msg.setDestination(40973U); + msg.setDestinationEntity(148U); + msg.value = 0.7576776848732747; + msg.z_units = 51U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredControl #1", msg == *msg_d); + test.boolean("DesiredZ #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11813,26 +12147,21 @@ main(void) } { - IMC::DesiredControl msg; - msg.setTimeStamp(0.386928561075); - msg.setSource(9432U); - msg.setSourceEntity(209U); - msg.setDestination(26948U); - msg.setDestinationEntity(85U); - msg.x = 0.776508666681; - msg.y = 0.728444931014; - msg.z = 0.0134091654658; - msg.k = 0.475008058148; - msg.m = 0.678471964871; - msg.n = 0.753692040515; - msg.flags = 136U; + IMC::DesiredZ msg; + msg.setTimeStamp(0.5499682431552406); + msg.setSource(28612U); + msg.setSourceEntity(24U); + msg.setDestination(61494U); + msg.setDestinationEntity(242U); + msg.value = 0.006336459503546554; + msg.z_units = 142U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredControl #2", msg == *msg_d); + test.boolean("DesiredZ #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11843,20 +12172,21 @@ main(void) } { - IMC::DesiredHeadingRate msg; - msg.setTimeStamp(0.428035031343); - msg.setSource(36844U); - msg.setSourceEntity(136U); - msg.setDestination(54214U); - msg.setDestinationEntity(45U); - msg.value = 0.927665040135; + IMC::DesiredSpeed msg; + msg.setTimeStamp(0.7047679420075623); + msg.setSource(21736U); + msg.setSourceEntity(186U); + msg.setDestination(54692U); + msg.setDestinationEntity(242U); + msg.value = 0.5532738699656133; + msg.speed_units = 232U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredHeadingRate #0", msg == *msg_d); + test.boolean("DesiredSpeed #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11867,20 +12197,21 @@ main(void) } { - IMC::DesiredHeadingRate msg; - msg.setTimeStamp(0.997118697346); - msg.setSource(59004U); - msg.setSourceEntity(224U); - msg.setDestination(4450U); - msg.setDestinationEntity(132U); - msg.value = 0.477571758751; + IMC::DesiredSpeed msg; + msg.setTimeStamp(0.7507528983490588); + msg.setSource(20683U); + msg.setSourceEntity(208U); + msg.setDestination(56019U); + msg.setDestinationEntity(60U); + msg.value = 0.5496270696888932; + msg.speed_units = 121U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredHeadingRate #1", msg == *msg_d); + test.boolean("DesiredSpeed #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11891,20 +12222,21 @@ main(void) } { - IMC::DesiredHeadingRate msg; - msg.setTimeStamp(0.0489122179278); - msg.setSource(21515U); - msg.setSourceEntity(147U); - msg.setDestination(37220U); - msg.setDestinationEntity(152U); - msg.value = 0.526309286; + IMC::DesiredSpeed msg; + msg.setTimeStamp(0.8471282614897412); + msg.setSource(53490U); + msg.setSourceEntity(126U); + msg.setDestination(34939U); + msg.setDestinationEntity(240U); + msg.value = 0.1430217691815857; + msg.speed_units = 174U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredHeadingRate #2", msg == *msg_d); + test.boolean("DesiredSpeed #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11915,26 +12247,20 @@ main(void) } { - IMC::DesiredVelocity msg; - msg.setTimeStamp(0.144251933284); - msg.setSource(31295U); - msg.setSourceEntity(142U); - msg.setDestination(20130U); - msg.setDestinationEntity(175U); - msg.u = 0.0324699309297; - msg.v = 0.901050608393; - msg.w = 0.307726246444; - msg.p = 0.160992459742; - msg.q = 0.266472390752; - msg.r = 0.13810311207; - msg.flags = 215U; + IMC::DesiredRoll msg; + msg.setTimeStamp(0.7168263345264282); + msg.setSource(19414U); + msg.setSourceEntity(197U); + msg.setDestination(41980U); + msg.setDestinationEntity(82U); + msg.value = 0.874777051233851; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredVelocity #0", msg == *msg_d); + test.boolean("DesiredRoll #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11945,26 +12271,20 @@ main(void) } { - IMC::DesiredVelocity msg; - msg.setTimeStamp(0.61004502097); - msg.setSource(57920U); - msg.setSourceEntity(222U); - msg.setDestination(47361U); - msg.setDestinationEntity(174U); - msg.u = 0.178073756286; - msg.v = 0.318058923382; - msg.w = 0.291649329514; - msg.p = 0.948351948615; - msg.q = 0.400537771721; - msg.r = 0.964046944813; - msg.flags = 129U; + IMC::DesiredRoll msg; + msg.setTimeStamp(0.9020316768502605); + msg.setSource(19867U); + msg.setSourceEntity(50U); + msg.setDestination(20669U); + msg.setDestinationEntity(120U); + msg.value = 0.175925740444402; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredVelocity #1", msg == *msg_d); + test.boolean("DesiredRoll #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -11975,26 +12295,20 @@ main(void) } { - IMC::DesiredVelocity msg; - msg.setTimeStamp(0.64345527536); - msg.setSource(53745U); - msg.setSourceEntity(54U); - msg.setDestination(64507U); - msg.setDestinationEntity(252U); - msg.u = 0.642842630193; - msg.v = 0.514624862235; - msg.w = 0.610515143655; - msg.p = 0.997315753803; - msg.q = 0.87414509577; - msg.r = 0.972643890342; - msg.flags = 253U; + IMC::DesiredRoll msg; + msg.setTimeStamp(0.15675198097828213); + msg.setSource(48852U); + msg.setSourceEntity(125U); + msg.setDestination(30791U); + msg.setDestinationEntity(60U); + msg.value = 0.8905578912406691; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredVelocity #2", msg == *msg_d); + test.boolean("DesiredRoll #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12005,38 +12319,20 @@ main(void) } { - IMC::PathControlState msg; - msg.setTimeStamp(0.771970571953); - msg.setSource(60934U); - msg.setSourceEntity(1U); - msg.setDestination(65350U); - msg.setDestinationEntity(123U); - msg.path_ref = 2283736703U; - msg.start_lat = 0.0828821370479; - msg.start_lon = 0.857291508292; - msg.start_z = 0.740028168754; - msg.start_z_units = 121U; - msg.end_lat = 0.949610468734; - msg.end_lon = 0.966254088583; - msg.end_z = 0.34629051915; - msg.end_z_units = 84U; - msg.lradius = 0.765302642606; - msg.flags = 38U; - msg.x = 0.904458967843; - msg.y = 0.158407404228; - msg.z = 0.262786746135; - msg.vx = 0.452835217166; - msg.vy = 0.8515498328; - msg.vz = 0.159179947879; - msg.course_error = 0.871073703881; - msg.eta = 12524U; + IMC::DesiredPitch msg; + msg.setTimeStamp(0.00952274464006131); + msg.setSource(59907U); + msg.setSourceEntity(245U); + msg.setDestination(26177U); + msg.setDestinationEntity(87U); + msg.value = 0.3407306186015854; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PathControlState #0", msg == *msg_d); + test.boolean("DesiredPitch #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12047,38 +12343,20 @@ main(void) } { - IMC::PathControlState msg; - msg.setTimeStamp(0.216023144297); - msg.setSource(27256U); - msg.setSourceEntity(17U); - msg.setDestination(28725U); - msg.setDestinationEntity(48U); - msg.path_ref = 2550891437U; - msg.start_lat = 0.134640151367; - msg.start_lon = 0.691386744125; - msg.start_z = 0.304292228599; - msg.start_z_units = 114U; - msg.end_lat = 0.121766137593; - msg.end_lon = 0.120209774931; - msg.end_z = 0.45538132262; - msg.end_z_units = 27U; - msg.lradius = 0.369500823615; - msg.flags = 95U; - msg.x = 0.226019694065; - msg.y = 0.273971291013; - msg.z = 0.201970600828; - msg.vx = 0.206059876815; - msg.vy = 0.0121472239761; - msg.vz = 0.560615439486; - msg.course_error = 0.545693758705; - msg.eta = 50455U; + IMC::DesiredPitch msg; + msg.setTimeStamp(0.0016907799595337059); + msg.setSource(27992U); + msg.setSourceEntity(26U); + msg.setDestination(46293U); + msg.setDestinationEntity(98U); + msg.value = 0.47674607081507625; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PathControlState #1", msg == *msg_d); + test.boolean("DesiredPitch #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12089,38 +12367,20 @@ main(void) } { - IMC::PathControlState msg; - msg.setTimeStamp(0.206185361617); - msg.setSource(35868U); - msg.setSourceEntity(142U); - msg.setDestination(28404U); - msg.setDestinationEntity(95U); - msg.path_ref = 471283836U; - msg.start_lat = 0.634579008127; - msg.start_lon = 0.87746829373; - msg.start_z = 0.417665306888; - msg.start_z_units = 160U; - msg.end_lat = 0.400594419036; - msg.end_lon = 0.194710966462; - msg.end_z = 0.768385899947; - msg.end_z_units = 241U; - msg.lradius = 0.951847529727; - msg.flags = 179U; - msg.x = 0.878596524956; - msg.y = 0.616707144339; - msg.z = 0.193269521799; - msg.vx = 0.904866220344; - msg.vy = 0.27050668514; - msg.vz = 0.737913846052; - msg.course_error = 0.790881341713; - msg.eta = 3958U; + IMC::DesiredPitch msg; + msg.setTimeStamp(0.0839909238872667); + msg.setSource(12340U); + msg.setSourceEntity(66U); + msg.setDestination(6343U); + msg.setDestinationEntity(242U); + msg.value = 0.9507546056110656; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PathControlState #2", msg == *msg_d); + test.boolean("DesiredPitch #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12131,22 +12391,20 @@ main(void) } { - IMC::AllocatedControlTorques msg; - msg.setTimeStamp(0.365745299989); - msg.setSource(56090U); - msg.setSourceEntity(74U); - msg.setDestination(41904U); - msg.setDestinationEntity(108U); - msg.k = 0.149652742069; - msg.m = 0.709414030692; - msg.n = 0.590613342731; + IMC::DesiredVerticalRate msg; + msg.setTimeStamp(0.8543095453498426); + msg.setSource(49754U); + msg.setSourceEntity(237U); + msg.setDestination(36916U); + msg.setDestinationEntity(42U); + msg.value = 0.06900382009756578; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AllocatedControlTorques #0", msg == *msg_d); + test.boolean("DesiredVerticalRate #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12157,22 +12415,20 @@ main(void) } { - IMC::AllocatedControlTorques msg; - msg.setTimeStamp(0.201835644427); - msg.setSource(37476U); - msg.setSourceEntity(180U); - msg.setDestination(59752U); - msg.setDestinationEntity(100U); - msg.k = 0.155482230722; - msg.m = 0.84175532031; - msg.n = 0.348771070428; + IMC::DesiredVerticalRate msg; + msg.setTimeStamp(0.7083117503703033); + msg.setSource(58154U); + msg.setSourceEntity(203U); + msg.setDestination(40962U); + msg.setDestinationEntity(172U); + msg.value = 0.17085609933589763; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AllocatedControlTorques #1", msg == *msg_d); + test.boolean("DesiredVerticalRate #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12183,22 +12439,20 @@ main(void) } { - IMC::AllocatedControlTorques msg; - msg.setTimeStamp(0.614291175907); - msg.setSource(65516U); - msg.setSourceEntity(216U); - msg.setDestination(26265U); - msg.setDestinationEntity(238U); - msg.k = 0.492259919844; - msg.m = 0.246515553798; - msg.n = 0.472003290325; + IMC::DesiredVerticalRate msg; + msg.setTimeStamp(0.5083104202857897); + msg.setSource(12116U); + msg.setSourceEntity(221U); + msg.setDestination(63377U); + msg.setDestinationEntity(61U); + msg.value = 0.012585234747942708; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AllocatedControlTorques #2", msg == *msg_d); + test.boolean("DesiredVerticalRate #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12209,23 +12463,32 @@ main(void) } { - IMC::ControlParcel msg; - msg.setTimeStamp(0.885627558324); - msg.setSource(4220U); - msg.setSourceEntity(9U); - msg.setDestination(29838U); - msg.setDestinationEntity(150U); - msg.p = 0.98698676142; - msg.i = 0.797561040909; - msg.d = 0.892753614684; - msg.a = 0.580794068346; + IMC::DesiredPath msg; + msg.setTimeStamp(0.3087946811639837); + msg.setSource(30294U); + msg.setSourceEntity(217U); + msg.setDestination(23488U); + msg.setDestinationEntity(131U); + msg.path_ref = 4003786481U; + msg.start_lat = 0.08859200658736144; + msg.start_lon = 0.7540180116712997; + msg.start_z = 0.8533975022653449; + msg.start_z_units = 4U; + msg.end_lat = 0.23346248512217505; + msg.end_lon = 0.9143670858196918; + msg.end_z = 0.38063752443168897; + msg.end_z_units = 105U; + msg.speed = 0.1451691824069704; + msg.speed_units = 146U; + msg.lradius = 0.667244232910593; + msg.flags = 95U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ControlParcel #0", msg == *msg_d); + test.boolean("DesiredPath #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12236,23 +12499,32 @@ main(void) } { - IMC::ControlParcel msg; - msg.setTimeStamp(0.602306772567); - msg.setSource(15052U); - msg.setSourceEntity(36U); - msg.setDestination(64970U); - msg.setDestinationEntity(244U); - msg.p = 0.178819188868; - msg.i = 0.252473167498; - msg.d = 0.726049003629; - msg.a = 0.178839635821; + IMC::DesiredPath msg; + msg.setTimeStamp(0.6023077469098883); + msg.setSource(60459U); + msg.setSourceEntity(114U); + msg.setDestination(28209U); + msg.setDestinationEntity(183U); + msg.path_ref = 1515621940U; + msg.start_lat = 0.25643030102619824; + msg.start_lon = 0.588380025159458; + msg.start_z = 0.9007012272754823; + msg.start_z_units = 204U; + msg.end_lat = 0.8310120835683036; + msg.end_lon = 0.3341585292198772; + msg.end_z = 0.13860976615164844; + msg.end_z_units = 34U; + msg.speed = 0.05865865043232099; + msg.speed_units = 138U; + msg.lradius = 0.5766928670426071; + msg.flags = 230U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ControlParcel #1", msg == *msg_d); + test.boolean("DesiredPath #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12263,23 +12535,32 @@ main(void) } { - IMC::ControlParcel msg; - msg.setTimeStamp(0.247680100149); - msg.setSource(38592U); - msg.setSourceEntity(25U); - msg.setDestination(43182U); - msg.setDestinationEntity(186U); - msg.p = 0.719038448763; - msg.i = 0.495838891091; - msg.d = 0.353049174642; - msg.a = 0.952612418711; + IMC::DesiredPath msg; + msg.setTimeStamp(0.294393758294464); + msg.setSource(1450U); + msg.setSourceEntity(69U); + msg.setDestination(41670U); + msg.setDestinationEntity(142U); + msg.path_ref = 1904286212U; + msg.start_lat = 0.6927156967008794; + msg.start_lon = 0.16485999069600887; + msg.start_z = 0.45347275501517836; + msg.start_z_units = 126U; + msg.end_lat = 0.6432008694157234; + msg.end_lon = 0.3998692688745972; + msg.end_z = 0.9312052104084063; + msg.end_z_units = 121U; + msg.speed = 0.895446731982122; + msg.speed_units = 69U; + msg.lradius = 0.9697506210481783; + msg.flags = 109U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ControlParcel #2", msg == *msg_d); + test.boolean("DesiredPath #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12290,20 +12571,26 @@ main(void) } { - IMC::Brake msg; - msg.setTimeStamp(0.168655067479); - msg.setSource(39916U); - msg.setSourceEntity(126U); - msg.setDestination(3369U); - msg.setDestinationEntity(15U); - msg.op = 20U; + IMC::DesiredControl msg; + msg.setTimeStamp(0.014906547858910213); + msg.setSource(13000U); + msg.setSourceEntity(227U); + msg.setDestination(39581U); + msg.setDestinationEntity(23U); + msg.x = 0.8959609588943612; + msg.y = 0.5576104989475432; + msg.z = 0.8641774462715807; + msg.k = 0.6084687061343481; + msg.m = 0.7144369854999914; + msg.n = 0.5400381305404959; + msg.flags = 149U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Brake #0", msg == *msg_d); + test.boolean("DesiredControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12314,20 +12601,26 @@ main(void) } { - IMC::Brake msg; - msg.setTimeStamp(0.854303876154); - msg.setSource(41430U); - msg.setSourceEntity(40U); - msg.setDestination(46594U); - msg.setDestinationEntity(124U); - msg.op = 40U; + IMC::DesiredControl msg; + msg.setTimeStamp(0.025620358778440933); + msg.setSource(50420U); + msg.setSourceEntity(163U); + msg.setDestination(45024U); + msg.setDestinationEntity(245U); + msg.x = 0.6027810610806795; + msg.y = 0.4716930454597684; + msg.z = 0.14484359014837822; + msg.k = 0.8295420762272182; + msg.m = 0.45176154418354975; + msg.n = 0.5649478317902744; + msg.flags = 168U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Brake #1", msg == *msg_d); + test.boolean("DesiredControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12338,20 +12631,26 @@ main(void) } { - IMC::Brake msg; - msg.setTimeStamp(0.789531061187); - msg.setSource(2629U); - msg.setSourceEntity(72U); - msg.setDestination(19290U); - msg.setDestinationEntity(142U); - msg.op = 248U; + IMC::DesiredControl msg; + msg.setTimeStamp(0.6851094049844114); + msg.setSource(26711U); + msg.setSourceEntity(146U); + msg.setDestination(35854U); + msg.setDestinationEntity(51U); + msg.x = 0.2048089407957997; + msg.y = 0.42498001118126316; + msg.z = 0.5798817930766045; + msg.k = 0.8115698284077901; + msg.m = 0.5970880034953786; + msg.n = 0.2691002533564443; + msg.flags = 114U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Brake #2", msg == *msg_d); + test.boolean("DesiredControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12362,29 +12661,20 @@ main(void) } { - IMC::DesiredLinearState msg; - msg.setTimeStamp(0.977771965671); - msg.setSource(49260U); - msg.setSourceEntity(64U); - msg.setDestination(38040U); - msg.setDestinationEntity(239U); - msg.x = 0.735380470707; - msg.y = 0.553004497857; - msg.z = 0.883462856742; - msg.vx = 0.631213098798; - msg.vy = 0.545781226664; - msg.vz = 0.470206940436; - msg.ax = 0.505562498628; - msg.ay = 0.77174721015; - msg.az = 0.693911183597; - msg.flags = 24441U; + IMC::DesiredHeadingRate msg; + msg.setTimeStamp(0.39355066370491876); + msg.setSource(38272U); + msg.setSourceEntity(151U); + msg.setDestination(15462U); + msg.setDestinationEntity(218U); + msg.value = 0.9700711332842729; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredLinearState #0", msg == *msg_d); + test.boolean("DesiredHeadingRate #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12395,29 +12685,20 @@ main(void) } { - IMC::DesiredLinearState msg; - msg.setTimeStamp(0.937017615078); - msg.setSource(53360U); - msg.setSourceEntity(54U); - msg.setDestination(41002U); - msg.setDestinationEntity(32U); - msg.x = 0.811257427617; - msg.y = 0.71211945932; - msg.z = 0.263572022078; - msg.vx = 0.4891794172; - msg.vy = 0.586982517254; - msg.vz = 0.950053223683; - msg.ax = 0.778249228986; - msg.ay = 0.563676071501; - msg.az = 0.643995685523; - msg.flags = 42836U; + IMC::DesiredHeadingRate msg; + msg.setTimeStamp(0.5296392224149035); + msg.setSource(6928U); + msg.setSourceEntity(103U); + msg.setDestination(54326U); + msg.setDestinationEntity(232U); + msg.value = 0.9594284983838244; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredLinearState #1", msg == *msg_d); + test.boolean("DesiredHeadingRate #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12428,29 +12709,20 @@ main(void) } { - IMC::DesiredLinearState msg; - msg.setTimeStamp(0.731013363261); - msg.setSource(15659U); - msg.setSourceEntity(101U); - msg.setDestination(19083U); - msg.setDestinationEntity(168U); - msg.x = 0.376564393104; - msg.y = 0.513568157952; - msg.z = 0.714743739293; - msg.vx = 0.885820216809; - msg.vy = 0.346670795006; - msg.vz = 0.471734046345; - msg.ax = 0.473313076376; - msg.ay = 0.706922447464; - msg.az = 0.587647647975; - msg.flags = 60953U; + IMC::DesiredHeadingRate msg; + msg.setTimeStamp(0.5880153423136962); + msg.setSource(40518U); + msg.setSourceEntity(10U); + msg.setDestination(24497U); + msg.setDestinationEntity(176U); + msg.value = 0.5075718881358954; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredLinearState #2", msg == *msg_d); + test.boolean("DesiredHeadingRate #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12461,20 +12733,26 @@ main(void) } { - IMC::DesiredThrottle msg; - msg.setTimeStamp(0.315256839807); - msg.setSource(13750U); - msg.setSourceEntity(249U); - msg.setDestination(63413U); - msg.setDestinationEntity(202U); - msg.value = 0.668192950808; + IMC::DesiredVelocity msg; + msg.setTimeStamp(0.4900208583941634); + msg.setSource(8586U); + msg.setSourceEntity(196U); + msg.setDestination(63536U); + msg.setDestinationEntity(191U); + msg.u = 0.9693689279134975; + msg.v = 0.8711754269620112; + msg.w = 0.6089895534588199; + msg.p = 0.20070216738054836; + msg.q = 0.01925060201802342; + msg.r = 0.5962136831243379; + msg.flags = 109U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredThrottle #0", msg == *msg_d); + test.boolean("DesiredVelocity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12485,20 +12763,26 @@ main(void) } { - IMC::DesiredThrottle msg; - msg.setTimeStamp(0.406806440933); - msg.setSource(36329U); - msg.setSourceEntity(228U); - msg.setDestination(18U); - msg.setDestinationEntity(126U); - msg.value = 0.486642593827; + IMC::DesiredVelocity msg; + msg.setTimeStamp(0.46191538123006015); + msg.setSource(59844U); + msg.setSourceEntity(73U); + msg.setDestination(48059U); + msg.setDestinationEntity(141U); + msg.u = 0.5405559382020403; + msg.v = 0.04603017440940693; + msg.w = 0.46891357864723526; + msg.p = 0.15322545027324008; + msg.q = 0.24222460884073538; + msg.r = 0.3071791718561322; + msg.flags = 86U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredThrottle #1", msg == *msg_d); + test.boolean("DesiredVelocity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12509,20 +12793,26 @@ main(void) } { - IMC::DesiredThrottle msg; - msg.setTimeStamp(0.422582247239); - msg.setSource(65121U); - msg.setSourceEntity(223U); - msg.setDestination(55500U); - msg.setDestinationEntity(80U); - msg.value = 0.957617064952; + IMC::DesiredVelocity msg; + msg.setTimeStamp(0.4586389211013102); + msg.setSource(9938U); + msg.setSourceEntity(144U); + msg.setDestination(26906U); + msg.setDestinationEntity(105U); + msg.u = 0.41642131316820485; + msg.v = 0.6691855240312737; + msg.w = 0.42369751734273453; + msg.p = 0.418857660108477; + msg.q = 0.8514359086109083; + msg.r = 0.9635623231089153; + msg.flags = 186U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DesiredThrottle #2", msg == *msg_d); + test.boolean("DesiredVelocity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12533,30 +12823,38 @@ main(void) } { - IMC::Goto msg; - msg.setTimeStamp(0.0633000029698); - msg.setSource(21906U); - msg.setSourceEntity(168U); - msg.setDestination(39109U); - msg.setDestinationEntity(13U); - msg.timeout = 54468U; - msg.lat = 0.912064714323; - msg.lon = 0.371461452193; - msg.z = 0.981398275711; - msg.z_units = 36U; - msg.speed = 0.948725703933; - msg.speed_units = 108U; - msg.roll = 0.218071365082; - msg.pitch = 0.54537109243; - msg.yaw = 0.703678528233; - msg.custom.assign("RDDTMOPJQUZUIIZJCXDWLZALKFYJBXJMWESYSZVDTBCHZZMVQGMQKUQMCGROBANDDYQEVTHBTWLHAXWUFKNAXVLIJSPBOIPYJUVAXNLRWETUQQOXQLOCYGDWHLMCOWPHMGIVIUALJAHCTCDAJTRXETRIVZOEUPBFEPHYKWQXOHCEZEBJAFWYCFVNZILEYMGYFKBBSHRPRGNTSUWNNUSZINNKGD"); + IMC::PathControlState msg; + msg.setTimeStamp(0.1877301766328543); + msg.setSource(63952U); + msg.setSourceEntity(139U); + msg.setDestination(27239U); + msg.setDestinationEntity(35U); + msg.path_ref = 663457101U; + msg.start_lat = 0.9357359818928688; + msg.start_lon = 0.8325624193166236; + msg.start_z = 0.8541947524086003; + msg.start_z_units = 211U; + msg.end_lat = 0.6213274503278201; + msg.end_lon = 0.774489774733465; + msg.end_z = 0.34817722903337867; + msg.end_z_units = 225U; + msg.lradius = 0.04258038132781461; + msg.flags = 43U; + msg.x = 0.1771259036677827; + msg.y = 0.7499575459848922; + msg.z = 0.12818094779786304; + msg.vx = 0.8394493002787009; + msg.vy = 0.758577210385852; + msg.vz = 0.3885262044317004; + msg.course_error = 0.07775869509354594; + msg.eta = 1413U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Goto #0", msg == *msg_d); + test.boolean("PathControlState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12567,30 +12865,38 @@ main(void) } { - IMC::Goto msg; - msg.setTimeStamp(0.605412443873); - msg.setSource(34410U); - msg.setSourceEntity(135U); - msg.setDestination(13185U); - msg.setDestinationEntity(124U); - msg.timeout = 25658U; - msg.lat = 0.480011003235; - msg.lon = 0.598836746745; - msg.z = 0.811226642846; - msg.z_units = 36U; - msg.speed = 0.459643450203; - msg.speed_units = 247U; - msg.roll = 0.629731341233; - msg.pitch = 0.432567274607; - msg.yaw = 0.923111487504; - msg.custom.assign("OYNWLGXKUBKVLCQYDFKPTVCZUIMIFBRIAQQXIZRNFSXOVUK"); + IMC::PathControlState msg; + msg.setTimeStamp(0.6396501700802734); + msg.setSource(51509U); + msg.setSourceEntity(15U); + msg.setDestination(2453U); + msg.setDestinationEntity(159U); + msg.path_ref = 3131072113U; + msg.start_lat = 0.4919573541280884; + msg.start_lon = 0.38732566551638437; + msg.start_z = 0.38992371540109116; + msg.start_z_units = 33U; + msg.end_lat = 0.6743716958604975; + msg.end_lon = 0.037578308292050666; + msg.end_z = 0.44457531007527484; + msg.end_z_units = 247U; + msg.lradius = 0.6354351221923927; + msg.flags = 18U; + msg.x = 0.0612701840535288; + msg.y = 0.932717446094505; + msg.z = 0.16176719943475482; + msg.vx = 0.3194871841939041; + msg.vy = 0.8378023201035426; + msg.vz = 0.11473005333626218; + msg.course_error = 0.8175665045455772; + msg.eta = 47870U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Goto #1", msg == *msg_d); + test.boolean("PathControlState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12601,30 +12907,38 @@ main(void) } { - IMC::Goto msg; - msg.setTimeStamp(0.367141613953); - msg.setSource(34090U); - msg.setSourceEntity(69U); - msg.setDestination(17543U); - msg.setDestinationEntity(112U); - msg.timeout = 28286U; - msg.lat = 0.475139025345; - msg.lon = 0.802275092582; - msg.z = 0.947340316317; - msg.z_units = 80U; - msg.speed = 0.22400606088; - msg.speed_units = 245U; - msg.roll = 0.847208179924; - msg.pitch = 0.633238568324; - msg.yaw = 0.459327834327; - msg.custom.assign("QTJEUKZLPZLKEICZZFAWTNKQCCAEBSNHHDWAOHWUBBDNFLMYVXVODBCRJBYRUUVNGHTOZQSPCUGBDKMD"); + IMC::PathControlState msg; + msg.setTimeStamp(0.9077568406501512); + msg.setSource(35770U); + msg.setSourceEntity(121U); + msg.setDestination(61673U); + msg.setDestinationEntity(174U); + msg.path_ref = 1566938099U; + msg.start_lat = 0.8280187738882733; + msg.start_lon = 0.520471449277481; + msg.start_z = 0.044225830628638496; + msg.start_z_units = 121U; + msg.end_lat = 0.3020513437159077; + msg.end_lon = 0.4720935168966125; + msg.end_z = 0.10974256996952925; + msg.end_z_units = 200U; + msg.lradius = 0.10469961625443014; + msg.flags = 45U; + msg.x = 0.9769413594292203; + msg.y = 0.854981007166185; + msg.z = 0.03521716428947219; + msg.vx = 0.9228280925132059; + msg.vy = 0.6958129480576782; + msg.vz = 0.018610864267455285; + msg.course_error = 0.03156702777791587; + msg.eta = 38763U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Goto #2", msg == *msg_d); + test.boolean("PathControlState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12635,30 +12949,22 @@ main(void) } { - IMC::PopUp msg; - msg.setTimeStamp(0.134717320971); - msg.setSource(43695U); - msg.setSourceEntity(29U); - msg.setDestination(40613U); - msg.setDestinationEntity(173U); - msg.timeout = 9466U; - msg.lat = 0.0677244057272; - msg.lon = 0.202150977429; - msg.z = 0.107481766703; - msg.z_units = 122U; - msg.speed = 0.548926222427; - msg.speed_units = 101U; - msg.duration = 25373U; - msg.radius = 0.649384860446; - msg.flags = 68U; - msg.custom.assign("PCGLVHFNOAMQLVAKPJDCLSFPDQRAVEIVNPOEHRIB"); + IMC::AllocatedControlTorques msg; + msg.setTimeStamp(0.8626567340008001); + msg.setSource(48354U); + msg.setSourceEntity(12U); + msg.setDestination(56816U); + msg.setDestinationEntity(229U); + msg.k = 0.8058524169451321; + msg.m = 0.5269531706424525; + msg.n = 0.14882463110682942; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PopUp #0", msg == *msg_d); + test.boolean("AllocatedControlTorques #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12669,30 +12975,22 @@ main(void) } { - IMC::PopUp msg; - msg.setTimeStamp(0.191115268387); - msg.setSource(34333U); - msg.setSourceEntity(206U); - msg.setDestination(9000U); - msg.setDestinationEntity(79U); - msg.timeout = 22503U; - msg.lat = 0.876426357821; - msg.lon = 0.953406991406; - msg.z = 0.839450692841; - msg.z_units = 102U; - msg.speed = 0.974065685297; - msg.speed_units = 107U; - msg.duration = 4852U; - msg.radius = 0.843610409984; - msg.flags = 189U; - msg.custom.assign("WOTASRBANJHZSLHWHAGBXJHKLVCJIOGOLMRZLLGHXPKAZSNMMQJZQKUHODXWUNWJCNDQPVVFYOCHRAWYBCPUFDUTYGBQXCUEPKSVZKDPLYCPTWTKNGJFRTAWMRXQNBKDBVIHIEUFNVMLZZRRFGGQMMGXSSRNDVWQ"); + IMC::AllocatedControlTorques msg; + msg.setTimeStamp(0.281221569086503); + msg.setSource(12868U); + msg.setSourceEntity(3U); + msg.setDestination(51261U); + msg.setDestinationEntity(31U); + msg.k = 0.12224866303650406; + msg.m = 0.8577419381426618; + msg.n = 0.23072678510825406; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PopUp #1", msg == *msg_d); + test.boolean("AllocatedControlTorques #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12703,30 +13001,22 @@ main(void) } { - IMC::PopUp msg; - msg.setTimeStamp(0.686943366736); - msg.setSource(31173U); - msg.setSourceEntity(243U); - msg.setDestination(32796U); - msg.setDestinationEntity(70U); - msg.timeout = 19116U; - msg.lat = 0.168292229895; - msg.lon = 0.861126885798; - msg.z = 0.528495058633; - msg.z_units = 65U; - msg.speed = 0.517992374652; - msg.speed_units = 19U; - msg.duration = 27969U; - msg.radius = 0.228665769926; - msg.flags = 215U; - msg.custom.assign("MOLQRMEFDPBTSJXXUYLAIRCFQXEVAUCGLODMHKQCETUEFRGPWNXJTVYIHQCCEUTTBOASQCTYBHRNKWADXJNPCWKIBBUOFZVBLVHHNSLGUKAWOHGIMEJSNUGEKRVPMJMVLVAEJAIVEDGZYZOBSPSOSDIYLDWANPSGOTSDRVPKHTPFJNMKXUPLYWAQDJKDXBTZHKCYIXPGHZJKZVZDBFQIIWQNWAUFUTLWRLXOYYXOCINNHQEFSGZQJM"); + IMC::AllocatedControlTorques msg; + msg.setTimeStamp(0.19368286861173534); + msg.setSource(51801U); + msg.setSourceEntity(75U); + msg.setDestination(34761U); + msg.setDestinationEntity(184U); + msg.k = 0.07610415214067434; + msg.m = 0.808813502340482; + msg.n = 0.3325943111144649; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PopUp #2", msg == *msg_d); + test.boolean("AllocatedControlTorques #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12737,20 +13027,23 @@ main(void) } { - IMC::Teleoperation msg; - msg.setTimeStamp(0.0909631659104); - msg.setSource(60469U); - msg.setSourceEntity(22U); - msg.setDestination(16178U); - msg.setDestinationEntity(22U); - msg.custom.assign("WVYOQOSOBUXEASKWVYVTCQDDZ"); + IMC::ControlParcel msg; + msg.setTimeStamp(0.6198868183240873); + msg.setSource(60237U); + msg.setSourceEntity(55U); + msg.setDestination(17907U); + msg.setDestinationEntity(233U); + msg.p = 0.9136213949740171; + msg.i = 0.9667060356563645; + msg.d = 0.015284655689211335; + msg.a = 0.21983575295340607; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Teleoperation #0", msg == *msg_d); + test.boolean("ControlParcel #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12761,20 +13054,23 @@ main(void) } { - IMC::Teleoperation msg; - msg.setTimeStamp(0.251380978626); - msg.setSource(42591U); - msg.setSourceEntity(223U); - msg.setDestination(22416U); - msg.setDestinationEntity(119U); - msg.custom.assign("HREZWCMGXPWRPKTMCEMUXXXOANNHRLGVTPZJOBFPJRYDZSXDNLUWJSMKVMATARFQYCPRYGZXOLUKXDKWPHLMVNIHDHUOAJCQTHVPRYFTFTDGEDKABGOBTIICBCQVTTFYYJYQQL"); + IMC::ControlParcel msg; + msg.setTimeStamp(0.3098540149655574); + msg.setSource(18008U); + msg.setSourceEntity(97U); + msg.setDestination(58117U); + msg.setDestinationEntity(245U); + msg.p = 0.8185580747402402; + msg.i = 0.7286936486591519; + msg.d = 0.06397506847787127; + msg.a = 0.31472605777398155; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Teleoperation #1", msg == *msg_d); + test.boolean("ControlParcel #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12785,20 +13081,23 @@ main(void) } { - IMC::Teleoperation msg; - msg.setTimeStamp(0.147333126944); - msg.setSource(7U); - msg.setSourceEntity(251U); - msg.setDestination(22025U); - msg.setDestinationEntity(44U); - msg.custom.assign("OEDJUJYTPGTXGWFJHCROGZVUOPZWTASXMDQALAL"); + IMC::ControlParcel msg; + msg.setTimeStamp(0.060174612932698435); + msg.setSource(4201U); + msg.setSourceEntity(30U); + msg.setDestination(51241U); + msg.setDestinationEntity(200U); + msg.p = 0.6986095702578274; + msg.i = 0.6357330008722762; + msg.d = 0.7105219027343724; + msg.a = 0.10579069985127765; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Teleoperation #2", msg == *msg_d); + test.boolean("ControlParcel #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12809,33 +13108,20 @@ main(void) } { - IMC::Loiter msg; - msg.setTimeStamp(0.941378579839); - msg.setSource(3271U); - msg.setSourceEntity(113U); - msg.setDestination(65285U); - msg.setDestinationEntity(222U); - msg.timeout = 4265U; - msg.lat = 0.817759966407; - msg.lon = 0.580636413426; - msg.z = 0.830771791412; - msg.z_units = 104U; - msg.duration = 55847U; - msg.speed = 0.538537935499; - msg.speed_units = 103U; - msg.type = 56U; - msg.radius = 0.105989022048; - msg.length = 0.308282215539; - msg.bearing = 0.183594236616; - msg.direction = 107U; - msg.custom.assign("PLTATWVZQHTFZHFZKXATXHEVWYFKJN"); + IMC::Brake msg; + msg.setTimeStamp(0.24394514748421414); + msg.setSource(49438U); + msg.setSourceEntity(25U); + msg.setDestination(53082U); + msg.setDestinationEntity(181U); + msg.op = 77U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Loiter #0", msg == *msg_d); + test.boolean("Brake #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12846,33 +13132,20 @@ main(void) } { - IMC::Loiter msg; - msg.setTimeStamp(0.665784495894); - msg.setSource(18923U); - msg.setSourceEntity(203U); - msg.setDestination(10572U); - msg.setDestinationEntity(58U); - msg.timeout = 65033U; - msg.lat = 0.921958984523; - msg.lon = 0.000791239844215; - msg.z = 0.682891984583; - msg.z_units = 217U; - msg.duration = 10401U; - msg.speed = 0.736143043205; - msg.speed_units = 30U; - msg.type = 188U; - msg.radius = 0.727877581238; - msg.length = 0.780362382181; - msg.bearing = 0.88753973788; - msg.direction = 55U; - msg.custom.assign("MZEHRUBGJTTHCEFKRSXMOITVTVAPBRVQZHBUWSOZORENCKCOXEREQTMYJZENPNWNQUMBLADUPAXSDPMAOTUMLVKCCBYYEVIYBHSIELFNPKIVHWTGGFWHMHBDNUESRJJBQKQWKLWBFPUDCXCGJRQPHQZVOVKNLIYRDZJXADSAWRYGWSLPLYUDZAXIDGJICPVEWTCCVNRILZFNF"); + IMC::Brake msg; + msg.setTimeStamp(0.2893989130439165); + msg.setSource(21062U); + msg.setSourceEntity(89U); + msg.setDestination(24721U); + msg.setDestinationEntity(231U); + msg.op = 211U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Loiter #1", msg == *msg_d); + test.boolean("Brake #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12883,33 +13156,20 @@ main(void) } { - IMC::Loiter msg; - msg.setTimeStamp(0.957486258099); - msg.setSource(37654U); - msg.setSourceEntity(156U); - msg.setDestination(29494U); - msg.setDestinationEntity(176U); - msg.timeout = 29644U; - msg.lat = 0.780220865516; - msg.lon = 0.658002537722; - msg.z = 0.619258591963; - msg.z_units = 158U; - msg.duration = 56692U; - msg.speed = 0.947516813521; - msg.speed_units = 48U; - msg.type = 146U; - msg.radius = 0.324348258402; - msg.length = 0.656315548932; - msg.bearing = 0.520133966006; - msg.direction = 170U; - msg.custom.assign("TSPGWGBNPYWTEREOBOVSPYSIAXAEUHURSPLTRRFXAGOISCPMJQXNCMPDFKRNIIHTHETMOXJGKBZOFCFPYYBDOOBIOUREVXELGZLF"); + IMC::Brake msg; + msg.setTimeStamp(0.2555546714330056); + msg.setSource(3554U); + msg.setSourceEntity(167U); + msg.setDestination(15139U); + msg.setDestinationEntity(143U); + msg.op = 133U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Loiter #2", msg == *msg_d); + test.boolean("Brake #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12920,21 +13180,29 @@ main(void) } { - IMC::IdleManeuver msg; - msg.setTimeStamp(0.372258342376); - msg.setSource(63485U); - msg.setSourceEntity(38U); - msg.setDestination(31628U); - msg.setDestinationEntity(99U); - msg.duration = 6195U; - msg.custom.assign("FQVZZAOTWHFLYPSOILIDBUKPQNROECBSERHJATOQDAVNUDAIMTUGRUETESKZWUDG"); + IMC::DesiredLinearState msg; + msg.setTimeStamp(0.680805424499292); + msg.setSource(35837U); + msg.setSourceEntity(118U); + msg.setDestination(60285U); + msg.setDestinationEntity(239U); + msg.x = 0.4844652216850439; + msg.y = 0.9320296980296968; + msg.z = 0.8880095015271715; + msg.vx = 0.3726057789439373; + msg.vy = 0.14243802275338036; + msg.vz = 0.3314227622085162; + msg.ax = 0.9252665784602528; + msg.ay = 0.7565735241581442; + msg.az = 0.5982054109118928; + msg.flags = 42019U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IdleManeuver #0", msg == *msg_d); + test.boolean("DesiredLinearState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12945,21 +13213,29 @@ main(void) } { - IMC::IdleManeuver msg; - msg.setTimeStamp(0.319653369901); - msg.setSource(34629U); - msg.setSourceEntity(79U); - msg.setDestination(18551U); - msg.setDestinationEntity(15U); - msg.duration = 18202U; - msg.custom.assign("BVABFXXLZMQOLPPYNSOPZALJPBGUKAJKYDVDNNWJXLWINWTRTWEDQGTQGWORYRULGDCWICKQCCHHMRNAQIHVIJDWGGOKHZOSOFISMEUVXKXFPHCEPNOSOPFRUMZCFTZHPYPYBZ"); + IMC::DesiredLinearState msg; + msg.setTimeStamp(0.842214702353041); + msg.setSource(14264U); + msg.setSourceEntity(242U); + msg.setDestination(17465U); + msg.setDestinationEntity(34U); + msg.x = 0.5939033077466063; + msg.y = 0.005117495881239775; + msg.z = 0.35963341678181726; + msg.vx = 0.5513135470576979; + msg.vy = 0.8557417259621988; + msg.vz = 0.0643199360442277; + msg.ax = 0.8031603686395637; + msg.ay = 0.4129229869830051; + msg.az = 0.022298320197042476; + msg.flags = 20598U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IdleManeuver #1", msg == *msg_d); + test.boolean("DesiredLinearState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12970,21 +13246,29 @@ main(void) } { - IMC::IdleManeuver msg; - msg.setTimeStamp(0.956146275994); - msg.setSource(84U); - msg.setSourceEntity(183U); - msg.setDestination(60424U); - msg.setDestinationEntity(33U); - msg.duration = 45283U; - msg.custom.assign("PJPSLLBRZVEQPYUIKAMTIZEGBYKWFLAETJTBXSIKMSJYTZINLVXBDXVTJHEMJBHAWDGZVFC"); + IMC::DesiredLinearState msg; + msg.setTimeStamp(0.380407377053565); + msg.setSource(47821U); + msg.setSourceEntity(78U); + msg.setDestination(3274U); + msg.setDestinationEntity(143U); + msg.x = 0.9657916939911094; + msg.y = 0.5667113282264062; + msg.z = 0.701449646448496; + msg.vx = 0.005629383234565299; + msg.vy = 0.558254985559439; + msg.vz = 0.6717800383236341; + msg.ax = 0.03865364104332436; + msg.ay = 0.34965225578295; + msg.az = 0.8527263298112007; + msg.flags = 19053U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IdleManeuver #2", msg == *msg_d); + test.boolean("DesiredLinearState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -12995,36 +13279,20 @@ main(void) } { - IMC::LowLevelControl msg; - msg.setTimeStamp(0.310757202702); - msg.setSource(25017U); - msg.setSourceEntity(189U); - msg.setDestination(24639U); - msg.setDestinationEntity(251U); - IMC::DesiredPath tmp_msg_0; - tmp_msg_0.path_ref = 1109216561U; - tmp_msg_0.start_lat = 0.377061837621; - tmp_msg_0.start_lon = 0.503795739281; - tmp_msg_0.start_z = 0.882639516006; - tmp_msg_0.start_z_units = 81U; - tmp_msg_0.end_lat = 0.125215757446; - tmp_msg_0.end_lon = 0.651811858902; - tmp_msg_0.end_z = 0.283871577207; - tmp_msg_0.end_z_units = 47U; - tmp_msg_0.speed = 0.209590280811; - tmp_msg_0.speed_units = 160U; - tmp_msg_0.lradius = 0.0807683258572; - tmp_msg_0.flags = 148U; - msg.control.set(tmp_msg_0); - msg.duration = 7991U; - msg.custom.assign("LWDRRKJKYUNAGQFYNCZALQDWGUUMACZVKQYJEFPCSLGJHOIRMQCYBRFOGIUBDHVNJADCGFASKTZHEDNEDCKJMB"); + IMC::DesiredThrottle msg; + msg.setTimeStamp(0.22666868820614883); + msg.setSource(60228U); + msg.setSourceEntity(232U); + msg.setDestination(20177U); + msg.setDestinationEntity(68U); + msg.value = 0.689356020612277; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LowLevelControl #0", msg == *msg_d); + test.boolean("DesiredThrottle #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13035,24 +13303,20 @@ main(void) } { - IMC::LowLevelControl msg; - msg.setTimeStamp(0.379355668016); - msg.setSource(45843U); - msg.setSourceEntity(98U); - msg.setDestination(63500U); - msg.setDestinationEntity(226U); - IMC::DesiredPitch tmp_msg_0; - tmp_msg_0.value = 0.344416219818; - msg.control.set(tmp_msg_0); - msg.duration = 14586U; - msg.custom.assign("RHFTPVPNJJVGBDZUNFKPRKXHUKEZRBKLUITHQOIPZXZJTGFTVJACHQCKHVXIDMIULJQVOZUYSMQFPHPLADDLMTPFMECKCANFLYSYDWGVCBNHOIYTQPATFWIZODGOSEHTEDRRVCUREDLWNBOSVQAZWGCZBGKXYQCEFWMXTYWFMMAISKGIJTAOAYSNXOWHDWXLRKCXNSLMGFUBNJGU"); + IMC::DesiredThrottle msg; + msg.setTimeStamp(0.4754906655350225); + msg.setSource(19079U); + msg.setSourceEntity(102U); + msg.setDestination(33574U); + msg.setDestinationEntity(45U); + msg.value = 0.9694288171189364; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LowLevelControl #1", msg == *msg_d); + test.boolean("DesiredThrottle #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13063,24 +13327,20 @@ main(void) } { - IMC::LowLevelControl msg; - msg.setTimeStamp(0.766523110327); - msg.setSource(2647U); - msg.setSourceEntity(122U); - msg.setDestination(21904U); - msg.setDestinationEntity(9U); - IMC::DesiredThrottle tmp_msg_0; - tmp_msg_0.value = 0.392332697704; - msg.control.set(tmp_msg_0); - msg.duration = 33118U; - msg.custom.assign("TKGYVFXFFBSGKAHYDXVRUOKIIQOSRKPDKOIZBFLOVCKLODAAOMEIHHYZULATJAWKRRIZMONNBXNHDMNATVZGDZYPNLFAGYUXPWIELPIDWSUTJY"); + IMC::DesiredThrottle msg; + msg.setTimeStamp(0.08533198753124671); + msg.setSource(19716U); + msg.setSourceEntity(134U); + msg.setDestination(6314U); + msg.setDestinationEntity(35U); + msg.value = 0.3886395811470831; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LowLevelControl #2", msg == *msg_d); + test.boolean("DesiredThrottle #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13091,35 +13351,30 @@ main(void) } { - IMC::Rows msg; - msg.setTimeStamp(0.970664122462); - msg.setSource(29070U); - msg.setSourceEntity(104U); - msg.setDestination(21135U); - msg.setDestinationEntity(85U); - msg.timeout = 21695U; - msg.lat = 0.881304383467; - msg.lon = 0.569081286644; - msg.z = 0.0554303981025; - msg.z_units = 228U; - msg.speed = 0.369115402811; - msg.speed_units = 254U; - msg.bearing = 0.277560991928; - msg.cross_angle = 0.270550879169; - msg.width = 0.91675778275; - msg.length = 0.496194399224; - msg.hstep = 0.73370488769; - msg.coff = 231U; - msg.alternation = 100U; - msg.flags = 215U; - msg.custom.assign("GEDWEQXPJCEQQGFZZVWSHXMPBSTPRCBPBOKGOUJALRFGINVOCE"); + IMC::Goto msg; + msg.setTimeStamp(0.8838394474721666); + msg.setSource(44263U); + msg.setSourceEntity(66U); + msg.setDestination(62535U); + msg.setDestinationEntity(52U); + msg.timeout = 19468U; + msg.lat = 0.9365850298027723; + msg.lon = 0.7043935382427533; + msg.z = 0.923035160377859; + msg.z_units = 134U; + msg.speed = 0.14473470048478598; + msg.speed_units = 147U; + msg.roll = 0.2691938186653996; + msg.pitch = 0.2944192163916114; + msg.yaw = 0.6150936695285373; + msg.custom.assign("UWMFOERFQNJHRDSVMBBTTEEWNZCTFFCOASQQIZREISELH"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Rows #0", msg == *msg_d); + test.boolean("Goto #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13130,35 +13385,30 @@ main(void) } { - IMC::Rows msg; - msg.setTimeStamp(0.951316892423); - msg.setSource(11833U); - msg.setSourceEntity(137U); - msg.setDestination(35027U); - msg.setDestinationEntity(134U); - msg.timeout = 35497U; - msg.lat = 0.484486801449; - msg.lon = 0.674639194636; - msg.z = 0.643061236938; - msg.z_units = 69U; - msg.speed = 0.53681095403; - msg.speed_units = 188U; - msg.bearing = 0.155751127521; - msg.cross_angle = 0.60106828322; - msg.width = 0.448621839869; - msg.length = 0.428655680063; - msg.hstep = 0.478050572541; - msg.coff = 199U; - msg.alternation = 151U; - msg.flags = 14U; - msg.custom.assign("JMUHRDOHGUMMXYUKBJSATPRLDOYRQAIMZHOQQUACPRNRBNTGEDKIUXDGNKJWBZVDOHNIBEGOMVQVCIHTHVPCSXTKAWIBXRLTAYIENNCRSPDHXMMKWFJJFIBZQLFWZERJBKPVZCCEEPPWMTLFQDLQXYSBTGSPPFWMOYQSIEJWZLBAMSVUCIHWNWFFZVKFUCDSALGGUASFTLAVXTZLKOSVXCIBXHVOCEZYRUJPANYNQYELDK"); + IMC::Goto msg; + msg.setTimeStamp(0.662486639748536); + msg.setSource(1219U); + msg.setSourceEntity(172U); + msg.setDestination(35182U); + msg.setDestinationEntity(99U); + msg.timeout = 13068U; + msg.lat = 0.8471518875184195; + msg.lon = 0.6672522602875384; + msg.z = 0.6079910441530799; + msg.z_units = 146U; + msg.speed = 0.8730422836707139; + msg.speed_units = 194U; + msg.roll = 0.09153336183739702; + msg.pitch = 0.28497514975689986; + msg.yaw = 0.8052392382825116; + msg.custom.assign("KDTAYYEEEJJWOIMTASSDGFUOWULEFSTZBQFOPHCIYCFHPZWZNGIUWHOBUFCZXXYLRVSJKQHMPSJWMSVPQBVKBZQHHYJ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Rows #1", msg == *msg_d); + test.boolean("Goto #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13169,35 +13419,30 @@ main(void) } { - IMC::Rows msg; - msg.setTimeStamp(0.95745201982); - msg.setSource(28429U); - msg.setSourceEntity(101U); - msg.setDestination(4846U); - msg.setDestinationEntity(68U); - msg.timeout = 39557U; - msg.lat = 0.492591375748; - msg.lon = 0.627360903571; - msg.z = 0.876161792908; - msg.z_units = 45U; - msg.speed = 0.332461015369; - msg.speed_units = 230U; - msg.bearing = 0.778585081442; - msg.cross_angle = 0.58514199608; - msg.width = 0.339664415674; - msg.length = 0.228637895303; - msg.hstep = 0.460136849253; - msg.coff = 163U; - msg.alternation = 41U; - msg.flags = 45U; - msg.custom.assign("HVAPQGVOSJXIARVVEYRSQJMBDSZATSUTWDMGNLWUTBMJZKSKPHTCGADSJDVQLGJYZRHTDAFEOYKMLNYMXFXAOXQJIBKXKYFBSEZYPFXCIZBNRDVCNWMUGZNEUWI"); + IMC::Goto msg; + msg.setTimeStamp(0.47182729269707435); + msg.setSource(62264U); + msg.setSourceEntity(76U); + msg.setDestination(13817U); + msg.setDestinationEntity(111U); + msg.timeout = 50470U; + msg.lat = 0.4917615634770407; + msg.lon = 0.28988210708889284; + msg.z = 0.9263308652204533; + msg.z_units = 117U; + msg.speed = 0.2541756388536627; + msg.speed_units = 58U; + msg.roll = 0.10570746759323502; + msg.pitch = 0.25380352597299694; + msg.yaw = 0.4927378439646859; + msg.custom.assign("UZPNNGTDZGGJVVFDQZDTSXCJEWUHWYHQFCEOLRBMLHKCWRRZDKHRHXBYTKSVSMRVWICXXGVLGPYXSATXFKCULVUZVYIUY"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Rows #2", msg == *msg_d); + test.boolean("Goto #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13208,32 +13453,30 @@ main(void) } { - IMC::FollowPath msg; - msg.setTimeStamp(0.560873193363); - msg.setSource(13258U); - msg.setSourceEntity(165U); - msg.setDestination(50773U); - msg.setDestinationEntity(127U); - msg.timeout = 54060U; - msg.lat = 0.205032765356; - msg.lon = 0.372668490774; - msg.z = 0.0412140464391; - msg.z_units = 235U; - msg.speed = 0.383512073061; - msg.speed_units = 127U; - IMC::PathPoint tmp_msg_0; - tmp_msg_0.x = 0.452754793911; - tmp_msg_0.y = 0.0732713024112; - tmp_msg_0.z = 0.339735574711; - msg.points.push_back(tmp_msg_0); - msg.custom.assign("FSLCKNNXTIZGOCFAQGWJOBWXHKFJUIADWSDBJSVDAFVXOXDININKZZGSXHHTLLOUCQQYABCSVPNUJMZWWQROJAVJCLHXPUPMLKWBMPDYFIUAYTCWFOUBEYEUBDUKPVGZXNJIQGDQKMOY"); + IMC::PopUp msg; + msg.setTimeStamp(0.7918834299709295); + msg.setSource(4628U); + msg.setSourceEntity(124U); + msg.setDestination(7169U); + msg.setDestinationEntity(106U); + msg.timeout = 6602U; + msg.lat = 0.19071026326662133; + msg.lon = 0.21555100908614422; + msg.z = 0.8857051293378001; + msg.z_units = 33U; + msg.speed = 0.27924826627427435; + msg.speed_units = 126U; + msg.duration = 3348U; + msg.radius = 0.17708414028604258; + msg.flags = 33U; + msg.custom.assign("SFKLVFANQXBGACTHODKKSWZXQMEFJSBMEOEZESQRJHWBIIACENDXRYRNYVZOBZATGGFCIGQKNUWBVWPOHIJBVDSZJTAKLMRSLNATFKFRSGFWPCXKUIQLRRZSOSTQTKOTENXIGFUKXTOQLPDUOZQILPRUDHZMIVPGVEAEGPWYVUYXBMBWYCIJRPLYJSLAMPDHHHGKXEWCPMANIJBWQQVNFYJMMWDTERTCJMGXXHDHUOZJBFVDYPZYLAVLU"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowPath #0", msg == *msg_d); + test.boolean("PopUp #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13244,27 +13487,30 @@ main(void) } { - IMC::FollowPath msg; - msg.setTimeStamp(0.176679767913); - msg.setSource(53674U); - msg.setSourceEntity(83U); - msg.setDestination(35994U); - msg.setDestinationEntity(106U); - msg.timeout = 63919U; - msg.lat = 0.152843781769; - msg.lon = 0.897648923558; - msg.z = 0.386502316343; - msg.z_units = 50U; - msg.speed = 0.755313731236; - msg.speed_units = 31U; - msg.custom.assign("FZVPRGORHCNXUENYKFSKTUJDCXBYHMRSWYQYGDPAVDZZXPLMFRZYOEEPQAQTNRZDTWLSYKDFCBDCHDXNRPXWNHKBBHJWRVUVAHJRFEWQGWXVLBGRSWOOZMXQMMUTOWTDLXIKLAZCNEXGNUMGKGOQQIIKDOYLL"); + IMC::PopUp msg; + msg.setTimeStamp(0.6983444808079964); + msg.setSource(11786U); + msg.setSourceEntity(154U); + msg.setDestination(56551U); + msg.setDestinationEntity(86U); + msg.timeout = 31127U; + msg.lat = 0.3957973812524306; + msg.lon = 0.052701172376080296; + msg.z = 0.8285766942422508; + msg.z_units = 246U; + msg.speed = 0.9884173610445963; + msg.speed_units = 187U; + msg.duration = 14996U; + msg.radius = 0.8082406854310799; + msg.flags = 102U; + msg.custom.assign("RGQNQRSSFHUJGOLXFNFCYWPX"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowPath #1", msg == *msg_d); + test.boolean("PopUp #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13275,27 +13521,30 @@ main(void) } { - IMC::FollowPath msg; - msg.setTimeStamp(0.465837319638); - msg.setSource(44996U); - msg.setSourceEntity(58U); - msg.setDestination(48326U); - msg.setDestinationEntity(166U); - msg.timeout = 45738U; - msg.lat = 0.147057192054; - msg.lon = 0.998395777715; - msg.z = 0.276292337621; - msg.z_units = 138U; - msg.speed = 0.636886495108; - msg.speed_units = 217U; - msg.custom.assign("TKKWIMMDQROIZLEJBQHBBEVDENGYXVWYMBRKGRTRQFCZAVCBSFDXDLLJQOOQFHSZZOIZDAXNUAENKWUGBAJYEUMVOYHUBZJPFPKMFOTUXHHMCVYMVRJAIEMRLHLWQPFERNFKKCGFOBUAXSLMEHFTCPRSMNRJLIQYGZAYZSCKCYVGHSPJWFQWNDT"); + IMC::PopUp msg; + msg.setTimeStamp(0.5711708801305134); + msg.setSource(11566U); + msg.setSourceEntity(55U); + msg.setDestination(60140U); + msg.setDestinationEntity(191U); + msg.timeout = 47477U; + msg.lat = 0.27049138937676775; + msg.lon = 0.010852075665724215; + msg.z = 0.6963621429699264; + msg.z_units = 73U; + msg.speed = 0.3608678561821639; + msg.speed_units = 246U; + msg.duration = 43870U; + msg.radius = 0.18320004114714705; + msg.flags = 123U; + msg.custom.assign("QFDYIUCQZHQEGVLGUHKACRFKWAFDLXAZXYFIOUMXQGWWAMBMUOTSMOSVPHPWDNMPRHCHESJRWXVHNQELJUKQGENJVEWOATFUZTQYJCTJLXYKGZWHOUJUHOGGCGRCRNYXDVFAUYZOKDEISKKBEZDMBVBPDNRYCTKEAIUKRBSCYVSBIRVCRXVPMBHMIZOZLMTXSL"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowPath #2", msg == *msg_d); + test.boolean("PopUp #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13306,22 +13555,20 @@ main(void) } { - IMC::PathPoint msg; - msg.setTimeStamp(0.900796536324); - msg.setSource(21694U); - msg.setSourceEntity(159U); - msg.setDestination(2226U); - msg.setDestinationEntity(228U); - msg.x = 0.259083798196; - msg.y = 0.878220412348; - msg.z = 0.27877407717; + IMC::Teleoperation msg; + msg.setTimeStamp(0.44340121244403075); + msg.setSource(64564U); + msg.setSourceEntity(182U); + msg.setDestination(10986U); + msg.setDestinationEntity(23U); + msg.custom.assign("DCWPAHMFCLXBLBDJZVSKTJQGWKCDZIUNIYYWUPKXXBRCXGJHULGYALNGLRSZPILXSMHHQUJMDZRDBEFOJRFSQUEISOVTSOWYOTFNKJVAIADFJRCWREYVBZOTHZNVUREMOCQYUYNSBKXQILPPRKNADWHNMGPNFFXRHETWZTXECLIYOZZPAMIMKDTEIVFUWUVJKQKWBOWQN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PathPoint #0", msg == *msg_d); + test.boolean("Teleoperation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13332,22 +13579,20 @@ main(void) } { - IMC::PathPoint msg; - msg.setTimeStamp(0.937272153448); - msg.setSource(27806U); - msg.setSourceEntity(142U); - msg.setDestination(39658U); - msg.setDestinationEntity(65U); - msg.x = 0.229429202635; - msg.y = 0.112976518924; - msg.z = 0.0133605826608; + IMC::Teleoperation msg; + msg.setTimeStamp(0.6724862999370498); + msg.setSource(17178U); + msg.setSourceEntity(5U); + msg.setDestination(46520U); + msg.setDestinationEntity(148U); + msg.custom.assign("UHILVSNNJYKJKCYTLYXFZMPMNGYIDVDWPPQQSFEZHBARZBAOATWNENJBWOXNTXULDKLFBJTRQCKWXRASOGPBGAMWCVENCFZUYZTVOKKMMKYVESOPEKJFYQDT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PathPoint #1", msg == *msg_d); + test.boolean("Teleoperation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13358,22 +13603,20 @@ main(void) } { - IMC::PathPoint msg; - msg.setTimeStamp(0.480227263779); - msg.setSource(54189U); - msg.setSourceEntity(129U); - msg.setDestination(50932U); - msg.setDestinationEntity(222U); - msg.x = 0.464894459674; - msg.y = 0.235500699256; - msg.z = 0.600784934953; + IMC::Teleoperation msg; + msg.setTimeStamp(0.9725721172359347); + msg.setSource(23922U); + msg.setSourceEntity(19U); + msg.setDestination(8656U); + msg.setDestinationEntity(202U); + msg.custom.assign("XFOYUVJOPAKDUOBGVAEQUZZZARVCNWDWPFJNMFNAPXHPSYGQQQPWDTIUKWYASFIQSRPTBRLQLTTENBWZWZLRKBIVDKUMRCNTMXRMLGSEQLXCUKECPZGWFGSIIDNTQFVAZKYXBVHSEBSNQERXHNSOCDTMOUFHGITLJPJLXGMNEOIHHRHCZNDFTBDCPIJOOFBUZLVXGOXJOVGTCJYSSYUCZVAYBVKLIUKWKKMYHJDWCGMWHRIEEABXRJQFL"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PathPoint #2", msg == *msg_d); + test.boolean("Teleoperation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13384,29 +13627,33 @@ main(void) } { - IMC::YoYo msg; - msg.setTimeStamp(0.175361119225); - msg.setSource(36359U); - msg.setSourceEntity(208U); - msg.setDestination(5591U); - msg.setDestinationEntity(96U); - msg.timeout = 31865U; - msg.lat = 0.523056940805; - msg.lon = 0.609813539546; - msg.z = 0.773361759613; - msg.z_units = 186U; - msg.amplitude = 0.425063836348; - msg.pitch = 0.92308932727; - msg.speed = 0.0198999921864; - msg.speed_units = 121U; - msg.custom.assign("RUGKDVQQSTKZHEUCCMAYGQJLXSFFIBDGRVITOUCIJTWZAXNOAJJPTZGFSFPPXBHKTHRCBVKRPCNWNOIQSVDNVWEOPTBEWKRWXEZUGRVNZKGPDHNHAELEFPRKIHUXYCIMHLXXDQJDSZJCCCQMLYEOQYNORUTQWJFYISDWLFJIOAVZKEFBWUJMSDMQISZZFMGBXUVLVLYANAZYDVKPYBLERSH"); + IMC::Loiter msg; + msg.setTimeStamp(0.8144643587385352); + msg.setSource(34667U); + msg.setSourceEntity(233U); + msg.setDestination(54829U); + msg.setDestinationEntity(23U); + msg.timeout = 18273U; + msg.lat = 0.04525099939163668; + msg.lon = 0.15518709824933663; + msg.z = 0.9531154894966015; + msg.z_units = 15U; + msg.duration = 23423U; + msg.speed = 0.24324964456932918; + msg.speed_units = 212U; + msg.type = 110U; + msg.radius = 0.6199049850034617; + msg.length = 0.9669385746458147; + msg.bearing = 0.43280264273175983; + msg.direction = 146U; + msg.custom.assign("JUCHCLNVSARFIELYYQTGXGVGUYWETNKDQLNMAQTHEPUPJZEFVSJHOLUWHRFYEMFBVWSSKRYDVLPHTPGNRHBMAXWMZYTBAHXFAVHGWPGDFXEGSLZMLTOPDGJHSIJBIWWXALIBCUNXBNCBTQURSKODWKPYUXUQIICGIPXKWREFKVDCQXDBFJBNAQLJOVWCNCXVJGMYITOCPRKKOFRNCSZEUTD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("YoYo #0", msg == *msg_d); + test.boolean("Loiter #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13417,29 +13664,33 @@ main(void) } { - IMC::YoYo msg; - msg.setTimeStamp(0.661959490145); - msg.setSource(55810U); - msg.setSourceEntity(16U); - msg.setDestination(36700U); - msg.setDestinationEntity(42U); - msg.timeout = 9027U; - msg.lat = 0.560666467721; - msg.lon = 0.0286525638075; - msg.z = 0.874493568052; - msg.z_units = 205U; - msg.amplitude = 0.562620983227; - msg.pitch = 0.832369149348; - msg.speed = 0.56600362995; + IMC::Loiter msg; + msg.setTimeStamp(0.9102090325672876); + msg.setSource(53597U); + msg.setSourceEntity(158U); + msg.setDestination(33382U); + msg.setDestinationEntity(223U); + msg.timeout = 55929U; + msg.lat = 0.8626432053105506; + msg.lon = 0.17721884934374177; + msg.z = 0.26263198050045833; + msg.z_units = 172U; + msg.duration = 26256U; + msg.speed = 0.6988657533774766; msg.speed_units = 162U; - msg.custom.assign("LXJLHZZXPZQISOMYDTJFEBOJVWXWCYFJCGEZAYUHQVOWVMJXVJRAIIIKVDSHKBONBKZCKDQTLNWCAUATJEIAHDOOGOZYCSHPWQLQUUGCNLTWUMVANFTYFMVSMLAUCXRRRGWRXFOJEFBIUSRCICYMKMVP"); + msg.type = 24U; + msg.radius = 0.5595813444091557; + msg.length = 0.37662243973782195; + msg.bearing = 0.29210143789613763; + msg.direction = 207U; + msg.custom.assign("XAOOQDJGVCVAWUGCJJSBXKXICISJYGFRQFTJIOYTUPDGDMVOWJUZZFZWLZBPDMOLQKFVPLGIVTJMWRUEZWVZEFMPCXNXIEOYMMMXEHYLETBQDSHLRYBXKQSLJEBYCSQQBIWCUZPHARRPNUCHKZBM"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("YoYo #1", msg == *msg_d); + test.boolean("Loiter #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13450,29 +13701,33 @@ main(void) } { - IMC::YoYo msg; - msg.setTimeStamp(0.664679064439); - msg.setSource(25821U); - msg.setSourceEntity(238U); - msg.setDestination(16531U); - msg.setDestinationEntity(28U); - msg.timeout = 49572U; - msg.lat = 0.363752293811; - msg.lon = 0.677797206411; - msg.z = 0.260357460102; - msg.z_units = 156U; - msg.amplitude = 0.59241649115; - msg.pitch = 0.636441600632; - msg.speed = 0.152913604402; - msg.speed_units = 27U; - msg.custom.assign("MPPTKBZOTONJUWKJJBFRZDATCFHQNQKMVNWMTZCAFMXPEEVYYGLQMNYNHSMDWHXXYNLXAKMFXJWWPOCPOWZJSGRWQVRUBGULSZKBEYYHSGYTUTIZZWXHVNJTEHDARFRCPCBCVXFNEMHGLOACDVBOPNGZPZUFOVVSDFNDJEJHCRLKTSTUGOTHRGQGXOISRKLWDIMQSBMUXPYEOJYQUILPUHCDAIXAKIDVKUSLBIQSYBEE"); + IMC::Loiter msg; + msg.setTimeStamp(0.8817752284701789); + msg.setSource(26616U); + msg.setSourceEntity(72U); + msg.setDestination(11482U); + msg.setDestinationEntity(226U); + msg.timeout = 21558U; + msg.lat = 0.1576429530005461; + msg.lon = 0.34534847389469714; + msg.z = 0.824555561687992; + msg.z_units = 17U; + msg.duration = 36679U; + msg.speed = 0.9953151229326196; + msg.speed_units = 52U; + msg.type = 91U; + msg.radius = 0.2185952149804844; + msg.length = 0.6260702968287392; + msg.bearing = 0.6172427146531433; + msg.direction = 180U; + msg.custom.assign("RWXKBIGFPRCTAMWTHSBVMJONAOWAHPYCPUOKBBBNRENMGZKLXTFFJTOVGVFQKSIVQFZPYLLZRMYGKHRXSSFEQOLJYNAYKJEZPXDXGLJXZAVTISSSBPFXIUUQYQEPNDMSIFUGWHLIROWPGJZEJMDKCVWAXGDMHZTMNXUKGWJJAYQAHDQHMXNDHZLRALDOEQSTKVQDF"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("YoYo #2", msg == *msg_d); + test.boolean("Loiter #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13483,19 +13738,21 @@ main(void) } { - IMC::TeleoperationDone msg; - msg.setTimeStamp(0.719085429915); - msg.setSource(41816U); - msg.setSourceEntity(149U); - msg.setDestination(52948U); - msg.setDestinationEntity(67U); + IMC::IdleManeuver msg; + msg.setTimeStamp(0.5638673806181099); + msg.setSource(12493U); + msg.setSourceEntity(48U); + msg.setDestination(26444U); + msg.setDestinationEntity(154U); + msg.duration = 2175U; + msg.custom.assign("PDZHHXXHKFQWKOIDCTZRBHJGJLPPJFLYWEYSEGOABVMT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TeleoperationDone #0", msg == *msg_d); + test.boolean("IdleManeuver #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13506,19 +13763,21 @@ main(void) } { - IMC::TeleoperationDone msg; - msg.setTimeStamp(0.957282327203); - msg.setSource(55380U); - msg.setSourceEntity(98U); - msg.setDestination(22803U); - msg.setDestinationEntity(76U); + IMC::IdleManeuver msg; + msg.setTimeStamp(0.019578530707817676); + msg.setSource(9603U); + msg.setSourceEntity(157U); + msg.setDestination(1732U); + msg.setDestinationEntity(39U); + msg.duration = 60767U; + msg.custom.assign("UWGOMHZVETXNALAHTCNJVXDMGGYBMSWULETAYFZTUPWSF"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TeleoperationDone #1", msg == *msg_d); + test.boolean("IdleManeuver #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13529,19 +13788,21 @@ main(void) } { - IMC::TeleoperationDone msg; - msg.setTimeStamp(0.378307796393); - msg.setSource(37594U); - msg.setSourceEntity(12U); - msg.setDestination(47797U); - msg.setDestinationEntity(106U); + IMC::IdleManeuver msg; + msg.setTimeStamp(0.27060000533387596); + msg.setSource(39053U); + msg.setSourceEntity(213U); + msg.setDestination(58943U); + msg.setDestinationEntity(76U); + msg.duration = 51253U; + msg.custom.assign("FLMURSUDUNTVUVXGGIPZUEUWVJWRZPXCZLFOQJQNJWASVLYSEEMRBOOCANQABVINWKFWXHIVFOWHDKDKTWBAPGTEYTZFGAKOKMTWIJMTHAOXYBXETLSVFESJNUDSCIYGMNMSCOQLQPXJNKASRBHLFEQUKDPUTGOCQRZXDBFHZUZLRZYBZDPDWLVRLREGHERKHIQJJFAGPNYIGCDHNFTEDJYHXN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TeleoperationDone #2", msg == *msg_d); + test.boolean("IdleManeuver #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13552,28 +13813,25 @@ main(void) } { - IMC::StationKeeping msg; - msg.setTimeStamp(0.0261811666613); - msg.setSource(42636U); - msg.setSourceEntity(12U); - msg.setDestination(52438U); - msg.setDestinationEntity(165U); - msg.lat = 0.598125917469; - msg.lon = 0.837465846953; - msg.z = 0.0140324020231; - msg.z_units = 200U; - msg.radius = 0.703631823021; - msg.duration = 25351U; - msg.speed = 0.452178988193; - msg.speed_units = 249U; - msg.custom.assign("XVJZCRWJVKZLKBAYJBLOKUTMYKLATBCOCRTWFUPAFPMMDVMIJHYZPAUTOIFWUCUIICQCHXSEGGLZGIEYSRKLGAVXMJONEYUSMPTTNEFMIBFGNCBSJOAAQNDQCUWDKBO"); + IMC::LowLevelControl msg; + msg.setTimeStamp(0.38267579641425253); + msg.setSource(34487U); + msg.setSourceEntity(66U); + msg.setDestination(42765U); + msg.setDestinationEntity(150U); + IMC::DesiredSpeed tmp_msg_0; + tmp_msg_0.value = 0.6828771578394928; + tmp_msg_0.speed_units = 203U; + msg.control.set(tmp_msg_0); + msg.duration = 8217U; + msg.custom.assign("JUBHNULCLARYTVKAYTGFJDTJ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("StationKeeping #0", msg == *msg_d); + test.boolean("LowLevelControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13584,28 +13842,25 @@ main(void) } { - IMC::StationKeeping msg; - msg.setTimeStamp(0.458905308455); - msg.setSource(21256U); - msg.setSourceEntity(213U); - msg.setDestination(46874U); - msg.setDestinationEntity(65U); - msg.lat = 0.950234773418; - msg.lon = 0.0962693744565; - msg.z = 0.789368078452; - msg.z_units = 105U; - msg.radius = 0.0875574071854; - msg.duration = 36848U; - msg.speed = 0.00178063302117; - msg.speed_units = 144U; - msg.custom.assign("WFCYCOGRNJKAYYXCMVQEPUNARJT"); + IMC::LowLevelControl msg; + msg.setTimeStamp(0.17653255424194259); + msg.setSource(19089U); + msg.setSourceEntity(155U); + msg.setDestination(23150U); + msg.setDestinationEntity(143U); + IMC::DesiredZ tmp_msg_0; + tmp_msg_0.value = 0.4937350528425902; + tmp_msg_0.z_units = 95U; + msg.control.set(tmp_msg_0); + msg.duration = 6900U; + msg.custom.assign("UQMCIGDVREFZEKTPTTFYEPPVZQNWINFENSNSXVXTBMCJRGYEOKFAWMZSOKRBPHMLLCFFIOXIKUMCTGLMCLERAFJDSUQODGFJECBNQGDSNJBJDHUPYFAMLQKMEQBOOWYYQBBWHAVIQJHZSMRSKAPTJZUOVRBFJDJZULCQDASXWBYWHKLLTLXRVIYNWRPDZVAKOXEIP"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("StationKeeping #1", msg == *msg_d); + test.boolean("LowLevelControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13616,28 +13871,24 @@ main(void) } { - IMC::StationKeeping msg; - msg.setTimeStamp(0.0596994623919); - msg.setSource(3516U); - msg.setSourceEntity(45U); - msg.setDestination(63952U); - msg.setDestinationEntity(160U); - msg.lat = 0.564214992338; - msg.lon = 0.0321287030848; - msg.z = 0.421459997972; - msg.z_units = 70U; - msg.radius = 0.21448356418; - msg.duration = 39445U; - msg.speed = 0.744567839987; - msg.speed_units = 31U; - msg.custom.assign("UIHXKJKUBWFOWEWKLPOPDQVJIBBVRKFHQJZWLOIYDJGAVGVPLTAJBETZGKOMXPILJUARDGIOFDYIUMSZAQFKQCODCNXZSAMBEFQU"); + IMC::LowLevelControl msg; + msg.setTimeStamp(0.851949207841212); + msg.setSource(13851U); + msg.setSourceEntity(54U); + msg.setDestination(46283U); + msg.setDestinationEntity(118U); + IMC::DesiredRoll tmp_msg_0; + tmp_msg_0.value = 0.29617753211813325; + msg.control.set(tmp_msg_0); + msg.duration = 60713U; + msg.custom.assign("UZMVCNKQTMWRKRCFSYDMHAMQRYZSILNGKUYXNVLQSJHPUYZUDYGXRXECLEBYEOPSRUZDTWHTBALTIPUIJPTKSVJJOKNAAKQOJYDAOVZOKBFHXSCCGJGGAFTWGJCSDFMAMARRJWYOXQHDXMCWIXTHWRDFSJK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("StationKeeping #2", msg == *msg_d); + test.boolean("LowLevelControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13648,31 +13899,35 @@ main(void) } { - IMC::Elevator msg; - msg.setTimeStamp(0.956322962656); - msg.setSource(51306U); - msg.setSourceEntity(196U); - msg.setDestination(51926U); - msg.setDestinationEntity(76U); - msg.timeout = 11450U; - msg.flags = 130U; - msg.lat = 0.0356190815391; - msg.lon = 0.268554666459; - msg.start_z = 0.754452578637; - msg.start_z_units = 121U; - msg.end_z = 0.571641267471; - msg.end_z_units = 55U; - msg.radius = 0.574566628519; - msg.speed = 0.712365756866; - msg.speed_units = 212U; - msg.custom.assign("DVXKYKFJSUZTRRCVVIAKULZHBOJZMBOOZYJBWADGAXPNMMASTRKKHIQBJHWMVHXCKQQVZHGZIIGNCOSFBXHNUBCUACUZVOFMAKXA"); + IMC::Rows msg; + msg.setTimeStamp(0.3639810856800828); + msg.setSource(33782U); + msg.setSourceEntity(118U); + msg.setDestination(34596U); + msg.setDestinationEntity(108U); + msg.timeout = 57830U; + msg.lat = 0.3930642195620221; + msg.lon = 0.15380104333682587; + msg.z = 0.7049603748493564; + msg.z_units = 116U; + msg.speed = 0.3846627568373674; + msg.speed_units = 223U; + msg.bearing = 0.7844786976765965; + msg.cross_angle = 0.9967589960129825; + msg.width = 0.6397399928597285; + msg.length = 0.1643927368462249; + msg.hstep = 0.1953779514222015; + msg.coff = 52U; + msg.alternation = 128U; + msg.flags = 103U; + msg.custom.assign("KOLJHDBYIHGDWYEUWRQTJHIIHCRBOSIIYRXVTKPXCVXKLBPATUNNMXBYLEGWCNFCQWAWQGBSGRCSYEVRKLDMTRNBZTOWEMILCAJEJZXHQHNZMFYZREJXUFOVQND"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Elevator #0", msg == *msg_d); + test.boolean("Rows #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13683,31 +13938,35 @@ main(void) } { - IMC::Elevator msg; - msg.setTimeStamp(0.865427750423); - msg.setSource(26804U); - msg.setSourceEntity(30U); - msg.setDestination(9607U); - msg.setDestinationEntity(247U); - msg.timeout = 46686U; - msg.flags = 240U; - msg.lat = 0.641789106695; - msg.lon = 0.342788395605; - msg.start_z = 0.492525706858; - msg.start_z_units = 123U; - msg.end_z = 0.94983180012; - msg.end_z_units = 190U; - msg.radius = 0.339314013598; - msg.speed = 0.8831904125; - msg.speed_units = 75U; - msg.custom.assign("LSDVYFRIACHNPEXJQLNWKXETVFLIHPODAHZTWD"); + IMC::Rows msg; + msg.setTimeStamp(0.031707104119938934); + msg.setSource(12925U); + msg.setSourceEntity(186U); + msg.setDestination(63947U); + msg.setDestinationEntity(9U); + msg.timeout = 65090U; + msg.lat = 0.13010250706478488; + msg.lon = 0.003576425842764741; + msg.z = 0.9409064539917361; + msg.z_units = 44U; + msg.speed = 0.28527604453821076; + msg.speed_units = 140U; + msg.bearing = 0.24909573100026772; + msg.cross_angle = 0.04889916905008751; + msg.width = 0.7447088283631572; + msg.length = 0.4830166358201584; + msg.hstep = 0.9325784735518988; + msg.coff = 190U; + msg.alternation = 141U; + msg.flags = 23U; + msg.custom.assign("PSSDNGAGHBYOWOKRWHAZZMJUXHDSYTWYGEOUGJKSBRPTOLNFLGWXVCAJGNLKNCGYIDKHXCOUQYCMPBERYZJFBCGRSDOZTQJQEUJQMEMZHLVRYHPOZIEWEKVNRSFLZNIWADDLLNMPQFOZASFUVCUPWUQNTSFXBUJUTMRDPFIHEOSMZQDVFSBXQTTJVVAMVXPAJGVFNHQOGMTJLAKTC"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Elevator #1", msg == *msg_d); + test.boolean("Rows #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13718,31 +13977,35 @@ main(void) } { - IMC::Elevator msg; - msg.setTimeStamp(0.846359274546); - msg.setSource(9685U); - msg.setSourceEntity(118U); - msg.setDestination(53962U); - msg.setDestinationEntity(167U); - msg.timeout = 4906U; - msg.flags = 12U; - msg.lat = 0.397413968085; - msg.lon = 0.350284793466; - msg.start_z = 0.0815968682103; - msg.start_z_units = 117U; - msg.end_z = 0.0593314182363; - msg.end_z_units = 107U; - msg.radius = 0.880386074971; - msg.speed = 0.86365511196; - msg.speed_units = 67U; - msg.custom.assign("CJKLUWRQSFMKKEYIQCPPVGADMNNIHSBCPSSFBYSLDBCPMUZTGIBXLGWCJXNGOMEJQARYUQGPFITJWEMVHASBZEWQVYHPEOBTLLXBZTRUWNVWNVAFRKMHJJHTDOSUYWHVXZBXHQNYUEFXOXZBWLKOPTVRVTEDRF"); + IMC::Rows msg; + msg.setTimeStamp(0.4543415021721461); + msg.setSource(12944U); + msg.setSourceEntity(101U); + msg.setDestination(54753U); + msg.setDestinationEntity(193U); + msg.timeout = 34245U; + msg.lat = 0.4796796698572954; + msg.lon = 0.6736207543083684; + msg.z = 0.6899613884778667; + msg.z_units = 86U; + msg.speed = 0.05017825239869744; + msg.speed_units = 193U; + msg.bearing = 0.43785511835531987; + msg.cross_angle = 0.5814942948507548; + msg.width = 0.21663910440988077; + msg.length = 0.367827943610202; + msg.hstep = 0.4335918543302193; + msg.coff = 70U; + msg.alternation = 119U; + msg.flags = 132U; + msg.custom.assign("ZMEQHCNRKUHEJXZLBRWVCYJTESYZVXNLOXDXNKQWJBOGYLVDSJMDQVCUCF"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Elevator #2", msg == *msg_d); + test.boolean("Rows #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13753,33 +14016,32 @@ main(void) } { - IMC::FollowTrajectory msg; - msg.setTimeStamp(0.603217128639); - msg.setSource(30503U); - msg.setSourceEntity(244U); - msg.setDestination(22847U); - msg.setDestinationEntity(94U); - msg.timeout = 52178U; - msg.lat = 0.99281951928; - msg.lon = 0.134359419309; - msg.z = 0.572065916329; - msg.z_units = 221U; - msg.speed = 0.964948666191; - msg.speed_units = 130U; - IMC::TrajectoryPoint tmp_msg_0; - tmp_msg_0.x = 0.486265166811; - tmp_msg_0.y = 0.231164274926; - tmp_msg_0.z = 0.231605674426; - tmp_msg_0.t = 0.871670608747; + IMC::FollowPath msg; + msg.setTimeStamp(0.44354327779435376); + msg.setSource(18259U); + msg.setSourceEntity(188U); + msg.setDestination(15736U); + msg.setDestinationEntity(234U); + msg.timeout = 21107U; + msg.lat = 0.9540818113937206; + msg.lon = 0.9558683376896129; + msg.z = 0.03597611163714931; + msg.z_units = 243U; + msg.speed = 0.0004661364586469041; + msg.speed_units = 192U; + IMC::PathPoint tmp_msg_0; + tmp_msg_0.x = 0.3293351620184991; + tmp_msg_0.y = 0.40838279565672564; + tmp_msg_0.z = 0.7716424228972752; msg.points.push_back(tmp_msg_0); - msg.custom.assign("ESKSOMGWTKYGFCXNQQDDBDZHXLQAQYHIUAGKBIIY"); + msg.custom.assign("YIWHQKMMHZLAFYBGINKCHMSIIXZFZLYRJOPBCYKPVYNMNAVVXLTAZHEYVDCIMHXOURRKRKEESTZUCZWDODPRPLNWFEQOLSXGERCXUQXGISCQZYJUJQSBFNGRMJFXSTBXVASOLPJOECWVCMZNMQBBNBVBSFHDIFYKRKHIGHCYTGUIJPQNZOAPEOXJCDQUWDRAAGJWMTOV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowTrajectory #0", msg == *msg_d); + test.boolean("FollowPath #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13790,27 +14052,32 @@ main(void) } { - IMC::FollowTrajectory msg; - msg.setTimeStamp(0.516832126397); - msg.setSource(2900U); - msg.setSourceEntity(202U); - msg.setDestination(32293U); - msg.setDestinationEntity(55U); - msg.timeout = 18548U; - msg.lat = 0.612312925536; - msg.lon = 0.973974145897; - msg.z = 0.635402082033; - msg.z_units = 192U; - msg.speed = 0.592098324714; - msg.speed_units = 26U; - msg.custom.assign("YEDFGYWNPMVRRX"); + IMC::FollowPath msg; + msg.setTimeStamp(0.324132014572744); + msg.setSource(53410U); + msg.setSourceEntity(122U); + msg.setDestination(11956U); + msg.setDestinationEntity(246U); + msg.timeout = 9352U; + msg.lat = 0.5790775011793001; + msg.lon = 0.3001576792249143; + msg.z = 0.6216995836675036; + msg.z_units = 199U; + msg.speed = 0.22074887979467184; + msg.speed_units = 195U; + IMC::PathPoint tmp_msg_0; + tmp_msg_0.x = 0.26617329535894363; + tmp_msg_0.y = 0.562523262048102; + tmp_msg_0.z = 0.47867602311157764; + msg.points.push_back(tmp_msg_0); + msg.custom.assign("SNJYKLOPEEHWCHPYEVYMIZPODDHGDENRTTAJQMFNZYOXPDSGZQYLUTUL"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowTrajectory #1", msg == *msg_d); + test.boolean("FollowPath #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13821,27 +14088,32 @@ main(void) } { - IMC::FollowTrajectory msg; - msg.setTimeStamp(0.286636084105); - msg.setSource(12732U); - msg.setSourceEntity(130U); - msg.setDestination(35485U); - msg.setDestinationEntity(193U); - msg.timeout = 58609U; - msg.lat = 0.383353027033; - msg.lon = 0.783991541318; - msg.z = 0.180279327833; - msg.z_units = 20U; - msg.speed = 0.325861139337; - msg.speed_units = 3U; - msg.custom.assign("KZASENTKPKXELKYAW"); + IMC::FollowPath msg; + msg.setTimeStamp(0.03544388102248597); + msg.setSource(9051U); + msg.setSourceEntity(13U); + msg.setDestination(32906U); + msg.setDestinationEntity(137U); + msg.timeout = 58946U; + msg.lat = 0.03473669227377596; + msg.lon = 0.7977706231034949; + msg.z = 0.6189084395036322; + msg.z_units = 113U; + msg.speed = 0.07356448851132347; + msg.speed_units = 176U; + IMC::PathPoint tmp_msg_0; + tmp_msg_0.x = 0.22804616551364498; + tmp_msg_0.y = 0.584800195698573; + tmp_msg_0.z = 0.6843491790133588; + msg.points.push_back(tmp_msg_0); + msg.custom.assign("RJQTHOXYSMQFNJHUMBEGCLBQICJFAEZKXCNTBZAXTLEGDHRMOXSLKHJRDZWUIVGWWJ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowTrajectory #2", msg == *msg_d); + test.boolean("FollowPath #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13852,23 +14124,22 @@ main(void) } { - IMC::TrajectoryPoint msg; - msg.setTimeStamp(0.747254012036); - msg.setSource(49633U); - msg.setSourceEntity(203U); - msg.setDestination(45355U); - msg.setDestinationEntity(245U); - msg.x = 0.684957710907; - msg.y = 0.0158351900459; - msg.z = 0.514550035115; - msg.t = 0.366889141284; + IMC::PathPoint msg; + msg.setTimeStamp(0.7229998349075151); + msg.setSource(4351U); + msg.setSourceEntity(44U); + msg.setDestination(37359U); + msg.setDestinationEntity(26U); + msg.x = 0.1631403075380442; + msg.y = 0.19970734838868154; + msg.z = 0.8705445519886209; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrajectoryPoint #0", msg == *msg_d); + test.boolean("PathPoint #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13879,23 +14150,22 @@ main(void) } { - IMC::TrajectoryPoint msg; - msg.setTimeStamp(0.346585861874); - msg.setSource(16373U); - msg.setSourceEntity(249U); - msg.setDestination(23750U); - msg.setDestinationEntity(2U); - msg.x = 0.613362355367; - msg.y = 0.159501547005; - msg.z = 0.259978264865; - msg.t = 0.328741220199; + IMC::PathPoint msg; + msg.setTimeStamp(0.7141356931744498); + msg.setSource(58381U); + msg.setSourceEntity(53U); + msg.setDestination(42662U); + msg.setDestinationEntity(139U); + msg.x = 0.9102793236771549; + msg.y = 0.011475523265480625; + msg.z = 0.6529514874633995; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrajectoryPoint #1", msg == *msg_d); + test.boolean("PathPoint #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13906,23 +14176,22 @@ main(void) } { - IMC::TrajectoryPoint msg; - msg.setTimeStamp(0.0698355797257); - msg.setSource(20033U); - msg.setSourceEntity(83U); - msg.setDestination(47779U); - msg.setDestinationEntity(19U); - msg.x = 0.34307011526; - msg.y = 0.171966571015; - msg.z = 0.710685326245; - msg.t = 0.637621563777; + IMC::PathPoint msg; + msg.setTimeStamp(0.5340435502045323); + msg.setSource(13566U); + msg.setSourceEntity(243U); + msg.setDestination(56009U); + msg.setDestinationEntity(130U); + msg.x = 0.28744184857712085; + msg.y = 0.8082162356570374; + msg.z = 0.016748457370898917; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrajectoryPoint #2", msg == *msg_d); + test.boolean("PathPoint #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13933,22 +14202,29 @@ main(void) } { - IMC::CustomManeuver msg; - msg.setTimeStamp(0.259591184616); - msg.setSource(46773U); - msg.setSourceEntity(69U); - msg.setDestination(59344U); - msg.setDestinationEntity(100U); - msg.timeout = 26536U; - msg.name.assign("HWOMGBNEEXNKWDZJVZVBYAQABUAMPTOGUNTFSTIDHNDQPKJ"); - msg.custom.assign("ARSSUZBPVCFSRJERFGFNAIMXVI"); + IMC::YoYo msg; + msg.setTimeStamp(0.37884129031646563); + msg.setSource(17724U); + msg.setSourceEntity(183U); + msg.setDestination(62754U); + msg.setDestinationEntity(54U); + msg.timeout = 19850U; + msg.lat = 0.7257181525610432; + msg.lon = 0.13601905370325396; + msg.z = 0.08568371914526629; + msg.z_units = 213U; + msg.amplitude = 0.19454951290576028; + msg.pitch = 0.27972782140550334; + msg.speed = 0.40708118559401574; + msg.speed_units = 200U; + msg.custom.assign("GYRNUMPBZOZZLFFKYTOGLAYVIOIEXDPLJJAEQRXISWWJIRIUXKRHIGQQTDASCNTWDZBQTXRACIYZLRPSDXABBLHCBXAPKDUKEGQFBDSKQOJYLEAQEBVFONYKMULRMDXJHPWLTOEDZXKVJUAMNKCVEFEEHQSZUMKGCMBIHHWUSGHCCHZGDYFCRTIFASFJVNOOJZNAVPNNMITFYJUJRVCSMFCVTRWLQMXNMKVYOQWH"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CustomManeuver #0", msg == *msg_d); + test.boolean("YoYo #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13959,22 +14235,29 @@ main(void) } { - IMC::CustomManeuver msg; - msg.setTimeStamp(0.212599040035); - msg.setSource(21434U); - msg.setSourceEntity(163U); - msg.setDestination(34573U); - msg.setDestinationEntity(232U); - msg.timeout = 28401U; - msg.name.assign("SMVNWDEKTJZEKCRZYHUWOGTOPGMCINTTAFKNHNPAYGVBMXRSDLERJEEYVNJWPJNDXIDTYAPESTAIEDGSRQMRJWITOMZMHJPLQMVOKUXBKOFIQKUZIGMTK"); - msg.custom.assign("IODOMLWHXYMRZLYDGYCGQAPSXRBUJBDUUSWMZFXUUEKRKTXBKLDUAMHILOHICTPBGRCJOGTJAEWKYVAHNTNKOPCSTCXSFMYIEKYTZRUISPDWF"); + IMC::YoYo msg; + msg.setTimeStamp(0.7693232394520889); + msg.setSource(18494U); + msg.setSourceEntity(122U); + msg.setDestination(34528U); + msg.setDestinationEntity(135U); + msg.timeout = 28271U; + msg.lat = 0.7930226498794812; + msg.lon = 0.32059550254185176; + msg.z = 0.2866744957766918; + msg.z_units = 138U; + msg.amplitude = 0.6406128909105002; + msg.pitch = 0.8358583862734408; + msg.speed = 0.8343738469299605; + msg.speed_units = 78U; + msg.custom.assign("BLQORBCVWFVISLPWIFONMTBQTDPNTABGNZHWAOULVVNNELTJWOPGXUWVEZGJYZPYAMDYZWYTJRDNJUVXPISEBJIXQISNEVYRHROPDLBEWMHOYADZJZQCKSVKUVYIMKZAOKOMEC"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CustomManeuver #1", msg == *msg_d); + test.boolean("YoYo #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -13985,22 +14268,29 @@ main(void) } { - IMC::CustomManeuver msg; - msg.setTimeStamp(0.620306768871); - msg.setSource(20734U); - msg.setSourceEntity(37U); - msg.setDestination(20139U); - msg.setDestinationEntity(30U); - msg.timeout = 36129U; - msg.name.assign("OJHVNVXWNRBDOAVANFYDSGEUZWRXQSPTVAPMQNMIFKTHEMJTZRNWNFQATKWVBZYHHXHWMDYFVHRRSKZDGLKSGAISQVSIQYOFOODGXSGBBIMYMTOLMUJLZLHLYPQJEUJMYXIENLGUWFEYBAOLJEHQCTNQLTKSIBRRXUVXJKVRIKCPOPTEPPLURGZGDBNKJJXCZLPDWIZEAIHHXYQFZ"); - msg.custom.assign("HETSOICKLYFECGIMAYWFSQLNLBRUPZNQTCEQZKJRMQPEJUQRHVNSQLXBCZFAPFHVTGHDDYTWTJGHBGRLBFUVOZZXDOXOTJIRRPYVZXUWAPCKPCYVZKPMYTDEKNYAAJIXIHHRLCQEAYEDBITSJTDNUFCQGJMPCSMAUNUWNXGFBQ"); + IMC::YoYo msg; + msg.setTimeStamp(0.7172417793334176); + msg.setSource(32844U); + msg.setSourceEntity(145U); + msg.setDestination(56176U); + msg.setDestinationEntity(55U); + msg.timeout = 36556U; + msg.lat = 0.503684712088505; + msg.lon = 0.09667590587592734; + msg.z = 0.2700031784297743; + msg.z_units = 18U; + msg.amplitude = 0.14501138563249805; + msg.pitch = 0.11252126825245501; + msg.speed = 0.14870819595554885; + msg.speed_units = 112U; + msg.custom.assign("PTJGQLBSEYQJKYOMSKJAUNUTZSVWVPWNZKMWFVIBIWDXHSFWPUTPZFIXZXBJSGYGGIOXVHROAADONXADUGRQMAQLKQIVSFQRXLTRFPOLDBFHCNJGKBRLCYCTADUMCLHZBEJXTOQZBRKVDKMMEMBNGATVHHESPCENWJDPCZJYCQIVQWENEOEYDUBMN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CustomManeuver #2", msg == *msg_d); + test.boolean("YoYo #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14011,39 +14301,19 @@ main(void) } { - IMC::VehicleFormation msg; - msg.setTimeStamp(0.107070359334); - msg.setSource(51160U); - msg.setSourceEntity(34U); - msg.setDestination(1741U); - msg.setDestinationEntity(238U); - msg.lat = 0.186677551559; - msg.lon = 0.543186453508; - msg.z = 0.495999685082; - msg.z_units = 253U; - msg.speed = 0.601706136369; - msg.speed_units = 16U; - IMC::TrajectoryPoint tmp_msg_0; - tmp_msg_0.x = 0.291291422941; - tmp_msg_0.y = 0.908682780514; - tmp_msg_0.z = 0.663875335715; - tmp_msg_0.t = 0.466474793691; - msg.points.push_back(tmp_msg_0); - IMC::VehicleFormationParticipant tmp_msg_1; - tmp_msg_1.vid = 34518U; - tmp_msg_1.off_x = 0.655164609814; - tmp_msg_1.off_y = 0.664968023381; - tmp_msg_1.off_z = 0.440565755473; - msg.participants.push_back(tmp_msg_1); - msg.start_time = 0.272328819047; - msg.custom.assign("MNXGXIPBMOSZGBGHQZEJCRUUNQMAPKHXKXWERDBTWZJZPAIDITVNVBGTMQFWODLUVVJOULVXBVDFAVMFXCTDUNMYSMRANKOZGFGJAVDHIZORNQQHDDFWSZOKLDPZLPRQGHUJWUQGTWYNJRHCMUMAZCQCMLHYYCLEBNCOTHKQKXLRPJBNLLAAVSTOPAICTSSIJYFFIXPTWPSIRGZEFBEWSFKEJWGRIBBRCSEFYKCS"); + IMC::TeleoperationDone msg; + msg.setTimeStamp(0.43652678623883223); + msg.setSource(33048U); + msg.setSourceEntity(69U); + msg.setDestination(12136U); + msg.setDestinationEntity(27U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleFormation #0", msg == *msg_d); + test.boolean("TeleoperationDone #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14054,33 +14324,19 @@ main(void) } { - IMC::VehicleFormation msg; - msg.setTimeStamp(0.567127280779); - msg.setSource(8199U); - msg.setSourceEntity(104U); - msg.setDestination(9496U); - msg.setDestinationEntity(122U); - msg.lat = 0.536848769261; - msg.lon = 0.336668725974; - msg.z = 0.290312195983; - msg.z_units = 139U; - msg.speed = 0.0539869858756; - msg.speed_units = 209U; - IMC::VehicleFormationParticipant tmp_msg_0; - tmp_msg_0.vid = 16282U; - tmp_msg_0.off_x = 0.301629755383; - tmp_msg_0.off_y = 0.451875124874; - tmp_msg_0.off_z = 0.650447590489; - msg.participants.push_back(tmp_msg_0); - msg.start_time = 0.186631416901; - msg.custom.assign("OQTGQUQPHVHFZRBFMBXFAZAEOVHMCNSQMZVSDFHKIVFYIJKKYNCLEYAFIDTNYGKSETSNVMDYBWTELEIUIXLVTRXCBSQXTADCBYANJZRVBZULMYCBLUKZTXPSH"); + IMC::TeleoperationDone msg; + msg.setTimeStamp(0.593283932613614); + msg.setSource(37133U); + msg.setSourceEntity(157U); + msg.setDestination(47978U); + msg.setDestinationEntity(138U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleFormation #1", msg == *msg_d); + test.boolean("TeleoperationDone #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14091,39 +14347,19 @@ main(void) } { - IMC::VehicleFormation msg; - msg.setTimeStamp(0.866256747402); - msg.setSource(14548U); - msg.setSourceEntity(77U); - msg.setDestination(35814U); - msg.setDestinationEntity(181U); - msg.lat = 0.307346076992; - msg.lon = 0.74547746684; - msg.z = 0.878839533674; - msg.z_units = 197U; - msg.speed = 0.253559279143; - msg.speed_units = 112U; - IMC::TrajectoryPoint tmp_msg_0; - tmp_msg_0.x = 0.146134342334; - tmp_msg_0.y = 0.0122829062345; - tmp_msg_0.z = 0.700942469864; - tmp_msg_0.t = 0.483421538714; - msg.points.push_back(tmp_msg_0); - IMC::VehicleFormationParticipant tmp_msg_1; - tmp_msg_1.vid = 44235U; - tmp_msg_1.off_x = 0.703103772758; - tmp_msg_1.off_y = 0.0912499573985; - tmp_msg_1.off_z = 0.126578039413; - msg.participants.push_back(tmp_msg_1); - msg.start_time = 0.0384156414482; - msg.custom.assign("WECVBXAREFHGBDLYILVARNSDIDONLAMXRYHYEDEHQYIJNXIWIZWVVKUFGQCMXCZLEVSUKKWSKQCFTRZVS"); + IMC::TeleoperationDone msg; + msg.setTimeStamp(0.8636457288685475); + msg.setSource(37303U); + msg.setSourceEntity(71U); + msg.setDestination(27711U); + msg.setDestinationEntity(66U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleFormation #2", msg == *msg_d); + test.boolean("TeleoperationDone #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14134,23 +14370,28 @@ main(void) } { - IMC::VehicleFormationParticipant msg; - msg.setTimeStamp(0.795122378024); - msg.setSource(29787U); - msg.setSourceEntity(43U); - msg.setDestination(22346U); - msg.setDestinationEntity(94U); - msg.vid = 9524U; - msg.off_x = 0.0315293668435; - msg.off_y = 0.788088201683; - msg.off_z = 0.560088530684; + IMC::StationKeeping msg; + msg.setTimeStamp(0.38595294554831394); + msg.setSource(5352U); + msg.setSourceEntity(241U); + msg.setDestination(58217U); + msg.setDestinationEntity(76U); + msg.lat = 0.410851732389523; + msg.lon = 0.11648458573345055; + msg.z = 0.9227492511605997; + msg.z_units = 211U; + msg.radius = 0.39094574003206184; + msg.duration = 50125U; + msg.speed = 0.6012228199679747; + msg.speed_units = 70U; + msg.custom.assign("VMHUMSYZDYSMXVOQETVQEFUVDLGNGERNVXJBWTJLKRQIJXONTGCWORDCYLMAKBDLXVPEQDNWSOPPDMKZWHURHBCHNKGJHWROBFKYAZFLYTIFBAPYOHPCLIATMAFKGEKUNJAUQLUPNCQHSRYADZDFTWVUBKIZQGJPGOFADYOQYCUYGCZUVJXRXXFTGMAEIXZLVTCENOBCSMKSKOEMTAP"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleFormationParticipant #0", msg == *msg_d); + test.boolean("StationKeeping #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14161,23 +14402,28 @@ main(void) } { - IMC::VehicleFormationParticipant msg; - msg.setTimeStamp(0.449565366151); - msg.setSource(31875U); - msg.setSourceEntity(237U); - msg.setDestination(19779U); - msg.setDestinationEntity(193U); - msg.vid = 26730U; - msg.off_x = 0.762963637125; - msg.off_y = 0.609459939276; - msg.off_z = 0.927500865724; + IMC::StationKeeping msg; + msg.setTimeStamp(0.8623411306045059); + msg.setSource(29060U); + msg.setSourceEntity(31U); + msg.setDestination(6613U); + msg.setDestinationEntity(10U); + msg.lat = 0.7627432426687548; + msg.lon = 0.3997172203079764; + msg.z = 0.29484146553682733; + msg.z_units = 128U; + msg.radius = 0.9959881850408556; + msg.duration = 5075U; + msg.speed = 0.39448483140946655; + msg.speed_units = 174U; + msg.custom.assign("JKSDVCIBLSHRXGQFOJEACVZCFQYBSNPDZEASLFPILRPKNNEPQNOGDIFKJXVAKSMFDBGKYRWHOZWCMXSEJEAGMXQGRRWTOHXJERMDIOQMYHZQGPBLWVSNMUDRKEUTNQJXRKECYAXJWTILQPDFUNPMNLGMYHTGJA"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleFormationParticipant #1", msg == *msg_d); + test.boolean("StationKeeping #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14188,23 +14434,28 @@ main(void) } { - IMC::VehicleFormationParticipant msg; - msg.setTimeStamp(0.303906264546); - msg.setSource(18543U); - msg.setSourceEntity(162U); - msg.setDestination(52985U); - msg.setDestinationEntity(36U); - msg.vid = 4545U; - msg.off_x = 0.798715171815; - msg.off_y = 0.461440999958; - msg.off_z = 0.644250965234; + IMC::StationKeeping msg; + msg.setTimeStamp(0.44937326498599595); + msg.setSource(21523U); + msg.setSourceEntity(201U); + msg.setDestination(61319U); + msg.setDestinationEntity(39U); + msg.lat = 0.9808489734744943; + msg.lon = 0.7370314142641136; + msg.z = 0.78881924853001; + msg.z_units = 140U; + msg.radius = 0.8560136856762413; + msg.duration = 19679U; + msg.speed = 0.29306426106404093; + msg.speed_units = 62U; + msg.custom.assign("GLMBTUYNGXNKKFUWSQYPYWAXMGWICVZRASRTYMIAXYOZMSZOHZLIGSFRXZIIDDYWCBJAJQLPBZGBUTCSOCJCKBVFZMPJJDIXUMANVJVBIUDTXMRWTNSBXPKEQJZSERFPRLDFNKBQTTXQCVGFKWNEMAQHGEQAAVDCFOVNDTCRKHYQ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleFormationParticipant #2", msg == *msg_d); + test.boolean("StationKeeping #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14215,19 +14466,31 @@ main(void) } { - IMC::StopManeuver msg; - msg.setTimeStamp(0.679062461727); - msg.setSource(45781U); - msg.setSourceEntity(195U); - msg.setDestination(44813U); - msg.setDestinationEntity(18U); + IMC::Elevator msg; + msg.setTimeStamp(0.977993982439533); + msg.setSource(40395U); + msg.setSourceEntity(98U); + msg.setDestination(19673U); + msg.setDestinationEntity(28U); + msg.timeout = 19673U; + msg.flags = 195U; + msg.lat = 0.7177067102958072; + msg.lon = 0.6414070486159302; + msg.start_z = 0.8000330706514096; + msg.start_z_units = 201U; + msg.end_z = 0.008136567898510805; + msg.end_z_units = 198U; + msg.radius = 0.28246245029258443; + msg.speed = 0.3605497040290899; + msg.speed_units = 53U; + msg.custom.assign("PMZUVRNOQEEEJFRXVCQNHQQKLFAXUQIEWOUEZSCEJEQIMTFEDZWKQUYPIYFYOUFGGLYILCPRYUMXDDWMADZVRSWTHDLLOKTTTLICEBCJLRZBYWFMQGMKFJSFZDXXVOODCKDUVINOYXYUVGDBWMNSK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("StopManeuver #0", msg == *msg_d); + test.boolean("Elevator #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14238,19 +14501,31 @@ main(void) } { - IMC::StopManeuver msg; - msg.setTimeStamp(0.260059226043); - msg.setSource(21644U); - msg.setSourceEntity(244U); - msg.setDestination(27353U); - msg.setDestinationEntity(68U); + IMC::Elevator msg; + msg.setTimeStamp(0.8526783887738867); + msg.setSource(20950U); + msg.setSourceEntity(19U); + msg.setDestination(23893U); + msg.setDestinationEntity(98U); + msg.timeout = 21863U; + msg.flags = 195U; + msg.lat = 0.9652114842662524; + msg.lon = 0.061069191452236105; + msg.start_z = 0.2255319650380222; + msg.start_z_units = 244U; + msg.end_z = 0.8730039751998596; + msg.end_z_units = 54U; + msg.radius = 0.913153567523836; + msg.speed = 0.6798531863538438; + msg.speed_units = 197U; + msg.custom.assign("XYUKQOXHZTTRBDZNXKACKHWJDNXSIMLKIJEXZPEVLCYYPWZXZABGAJCNOLLQLYNBPFDGRADQGNTDLWOIDTEUEXKPCBERBJSPTLPOFMPHWGOVNTAIEYGFOHUCSQNVAKTTILFFUWBZSYIIVQDLGYECBNQMQRZKBZHRODSJEJRAMHSVGTPDWUXRCMZJJVNCQGMVCYFSUVBUKEEMN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("StopManeuver #1", msg == *msg_d); + test.boolean("Elevator #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14261,19 +14536,31 @@ main(void) } { - IMC::StopManeuver msg; - msg.setTimeStamp(0.776211850955); - msg.setSource(57349U); - msg.setSourceEntity(13U); - msg.setDestination(36663U); - msg.setDestinationEntity(196U); + IMC::Elevator msg; + msg.setTimeStamp(0.14364841275220097); + msg.setSource(25057U); + msg.setSourceEntity(64U); + msg.setDestination(4819U); + msg.setDestinationEntity(14U); + msg.timeout = 50098U; + msg.flags = 62U; + msg.lat = 0.31043272474877814; + msg.lon = 0.9846224670900159; + msg.start_z = 0.8280357689557516; + msg.start_z_units = 5U; + msg.end_z = 0.9821283088705597; + msg.end_z_units = 12U; + msg.radius = 0.6781413921789724; + msg.speed = 0.26925456365731715; + msg.speed_units = 106U; + msg.custom.assign("OYJWCTUNKNIKRDHMDVCCKMRSZNMXUQGIIFCXME"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("StopManeuver #2", msg == *msg_d); + test.boolean("Elevator #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14284,20 +14571,33 @@ main(void) } { - IMC::RegisterManeuver msg; - msg.setTimeStamp(0.845895536973); - msg.setSource(34245U); - msg.setSourceEntity(238U); - msg.setDestination(1748U); - msg.setDestinationEntity(12U); - msg.mid = 38831U; + IMC::FollowTrajectory msg; + msg.setTimeStamp(0.9093313914318832); + msg.setSource(45506U); + msg.setSourceEntity(18U); + msg.setDestination(17060U); + msg.setDestinationEntity(231U); + msg.timeout = 26703U; + msg.lat = 0.3162417008903099; + msg.lon = 0.7565068863224954; + msg.z = 0.6046234777890444; + msg.z_units = 178U; + msg.speed = 0.6178637674314175; + msg.speed_units = 198U; + IMC::TrajectoryPoint tmp_msg_0; + tmp_msg_0.x = 0.925994575101993; + tmp_msg_0.y = 0.23952987701069506; + tmp_msg_0.z = 0.4407485231555023; + tmp_msg_0.t = 0.9194903525635603; + msg.points.push_back(tmp_msg_0); + msg.custom.assign("OBAZTLJVCPSECUNHEMMLDTNZWJUZBWWTOMWJYLUKVUAFVFGQBLBZASKXBZRBCOWBNRUSLIOEZHRHAPMYXUODLRQXFEHHDFGTHGTMMHZCMNGRWDFPJGYQRXPACKYDWSVYCC"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RegisterManeuver #0", msg == *msg_d); + test.boolean("FollowTrajectory #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14308,20 +14608,27 @@ main(void) } { - IMC::RegisterManeuver msg; - msg.setTimeStamp(0.831444642251); - msg.setSource(54287U); - msg.setSourceEntity(98U); - msg.setDestination(38850U); - msg.setDestinationEntity(37U); - msg.mid = 52889U; + IMC::FollowTrajectory msg; + msg.setTimeStamp(0.1030713433117234); + msg.setSource(16918U); + msg.setSourceEntity(13U); + msg.setDestination(18532U); + msg.setDestinationEntity(26U); + msg.timeout = 64003U; + msg.lat = 0.1170798400342089; + msg.lon = 0.2725593999240272; + msg.z = 0.48417393865409375; + msg.z_units = 20U; + msg.speed = 0.08561508752804547; + msg.speed_units = 188U; + msg.custom.assign("XYGEPAAKXQENITXBCYHPHAWRUSFSYHDAAQAEYQMGSYTZYFAPOZGIPNJLUKPURYHNTKNDQPTGCRVWBKARXFMRFBNDSASLCFYQURSHKDHMXPUTDRUVGQVOWKVJDEHDOUJQZIEGFVNTUVOXCKZFMTEZCKEVJGOKXRSRPQLSTFZOHULZBMSQTXPJJTJVWBCYWDWQOUBBCD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RegisterManeuver #1", msg == *msg_d); + test.boolean("FollowTrajectory #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14332,20 +14639,27 @@ main(void) } { - IMC::RegisterManeuver msg; - msg.setTimeStamp(0.602070919622); - msg.setSource(777U); - msg.setSourceEntity(80U); - msg.setDestination(18262U); - msg.setDestinationEntity(91U); - msg.mid = 25376U; + IMC::FollowTrajectory msg; + msg.setTimeStamp(0.9623098887540594); + msg.setSource(10906U); + msg.setSourceEntity(186U); + msg.setDestination(38226U); + msg.setDestinationEntity(219U); + msg.timeout = 7067U; + msg.lat = 0.9617929932776859; + msg.lon = 0.15311642706500717; + msg.z = 0.5135193007488009; + msg.z_units = 207U; + msg.speed = 0.36570281168595953; + msg.speed_units = 170U; + msg.custom.assign("ULIOYZMONAVJBFILECRTSJNABGBMCGBJTYSBYFPTCVUOIPDJHKPPAYHCSYJKMVNOKHXPOHUVSZMDEMTMWUTZTAURVJPHRNAXPXWIBMKTSVJBWQYXOWUEIQECIFTURFHLNIJGBVWDQSLCQWZFFQFEKLLADEEF"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RegisterManeuver #2", msg == *msg_d); + test.boolean("FollowTrajectory #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14356,22 +14670,23 @@ main(void) } { - IMC::ManeuverControlState msg; - msg.setTimeStamp(0.434836302116); - msg.setSource(26574U); - msg.setSourceEntity(113U); - msg.setDestination(56858U); - msg.setDestinationEntity(113U); - msg.state = 209U; - msg.eta = 15446U; - msg.info.assign("OBKGKRCWUBTOYEEKLWROPWVTEFNJYALULCLVC"); + IMC::TrajectoryPoint msg; + msg.setTimeStamp(0.8768705393269945); + msg.setSource(39162U); + msg.setSourceEntity(137U); + msg.setDestination(59129U); + msg.setDestinationEntity(95U); + msg.x = 0.35911880477943803; + msg.y = 0.8974339913478178; + msg.z = 0.4084506322812108; + msg.t = 0.10565177365743406; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ManeuverControlState #0", msg == *msg_d); + test.boolean("TrajectoryPoint #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14382,22 +14697,23 @@ main(void) } { - IMC::ManeuverControlState msg; - msg.setTimeStamp(0.314391643211); - msg.setSource(912U); - msg.setSourceEntity(216U); - msg.setDestination(37088U); - msg.setDestinationEntity(209U); - msg.state = 146U; - msg.eta = 8956U; - msg.info.assign("ATNIOZYMDUNELXAJJKQQSMCKNDTBSZTUFQCXJNWGRXYLGEWUCPOQIFYPWSHFDINIAVNYCAMPHQWMTOOLJXUFZKJVVRCJVGUMLVKRSZBHODMSWCBHHXWPAXRQDYELGPOQOCPIKGGKMTTGEKJPRFZFSXEZDTAGDUWIMNWBPBVDCBQZXFNTMVIY"); + IMC::TrajectoryPoint msg; + msg.setTimeStamp(0.9071133702587071); + msg.setSource(37451U); + msg.setSourceEntity(60U); + msg.setDestination(21646U); + msg.setDestinationEntity(5U); + msg.x = 0.18840541608022565; + msg.y = 0.3998984522124416; + msg.z = 0.808398216001414; + msg.t = 0.5914633339482861; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ManeuverControlState #1", msg == *msg_d); + test.boolean("TrajectoryPoint #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14408,22 +14724,23 @@ main(void) } { - IMC::ManeuverControlState msg; - msg.setTimeStamp(0.471813119951); - msg.setSource(9850U); - msg.setSourceEntity(13U); - msg.setDestination(30288U); - msg.setDestinationEntity(19U); - msg.state = 198U; - msg.eta = 49526U; - msg.info.assign("RJNBBVJVTVYUKXQIIHEFNOCNWXDZUGSJHDVFALNJMNYKBEDGTXTSPBYYINCJIDKTAPRXILLTADW"); + IMC::TrajectoryPoint msg; + msg.setTimeStamp(0.4035409388951309); + msg.setSource(26655U); + msg.setSourceEntity(190U); + msg.setDestination(51496U); + msg.setDestinationEntity(20U); + msg.x = 0.2327096150201774; + msg.y = 0.4561101927582375; + msg.z = 0.3937562685312621; + msg.t = 0.07645198065083392; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ManeuverControlState #2", msg == *msg_d); + test.boolean("TrajectoryPoint #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14434,27 +14751,22 @@ main(void) } { - IMC::FollowSystem msg; - msg.setTimeStamp(0.294534163084); - msg.setSource(19547U); - msg.setSourceEntity(202U); - msg.setDestination(28513U); - msg.setDestinationEntity(128U); - msg.system = 2426U; - msg.duration = 57497U; - msg.speed = 0.122569684779; - msg.speed_units = 45U; - msg.x = 0.398942286264; - msg.y = 0.420556312593; - msg.z = 0.714929285448; - msg.z_units = 183U; + IMC::CustomManeuver msg; + msg.setTimeStamp(0.8144589018184754); + msg.setSource(37690U); + msg.setSourceEntity(5U); + msg.setDestination(49995U); + msg.setDestinationEntity(32U); + msg.timeout = 54111U; + msg.name.assign("KQCQZEEHAKICLZIHXIZVYADESXTJJYSYUDVBSKMFJEUY"); + msg.custom.assign("GDBNZMMPUDURJZIQATVQFUKPTWQFSSYYKNZCUIOUBBFNLSZESBKOCQATKRKEFPD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowSystem #0", msg == *msg_d); + test.boolean("CustomManeuver #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14465,27 +14777,22 @@ main(void) } { - IMC::FollowSystem msg; - msg.setTimeStamp(0.614446616914); - msg.setSource(32756U); - msg.setSourceEntity(221U); - msg.setDestination(42422U); - msg.setDestinationEntity(83U); - msg.system = 10476U; - msg.duration = 54769U; - msg.speed = 0.274854358088; - msg.speed_units = 50U; - msg.x = 0.29024197145; - msg.y = 0.0192871204389; - msg.z = 0.509250629688; - msg.z_units = 101U; + IMC::CustomManeuver msg; + msg.setTimeStamp(0.8165495777692628); + msg.setSource(64494U); + msg.setSourceEntity(196U); + msg.setDestination(1713U); + msg.setDestinationEntity(150U); + msg.timeout = 26776U; + msg.name.assign("MBLNTOHXYFTRIQQQHJKCUJSGOLQDXTARSSEDJUUYJEKXYHZPOVSWCWRQJNVXOYXVFMFRCQPAYNRCDZQGNKTMCEJAUKIPJFSJXPOHMGENGABVHDWKLBGTZNZLLHRSVICRYOAIMMRAMWPDWGUQAZVFLQVHMVDDSITDUIZYTOFFAHABREEIIA"); + msg.custom.assign("VMGIKFLFOPRUWODWJXYIJEIYQRQCNROZMGYBFVDKNLAURZRSXDCSXBTNATDMNIXDBWMOBTQATLGJPQAIPDRSUVKWCVXGALBIZVDXWVAPIJDKYSLNFIMYZVD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowSystem #1", msg == *msg_d); + test.boolean("CustomManeuver #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14496,27 +14803,22 @@ main(void) } { - IMC::FollowSystem msg; - msg.setTimeStamp(0.336260372863); - msg.setSource(63416U); - msg.setSourceEntity(94U); - msg.setDestination(19899U); - msg.setDestinationEntity(126U); - msg.system = 38298U; - msg.duration = 55232U; - msg.speed = 0.915659666405; - msg.speed_units = 59U; - msg.x = 0.835241174314; - msg.y = 0.0433111710395; - msg.z = 0.403030224903; - msg.z_units = 18U; + IMC::CustomManeuver msg; + msg.setTimeStamp(0.5811303400565889); + msg.setSource(4118U); + msg.setSourceEntity(35U); + msg.setDestination(11500U); + msg.setDestinationEntity(66U); + msg.timeout = 13738U; + msg.name.assign("XUJNGMCYWJXYGCYQZLXRQNIHPFDJX"); + msg.custom.assign("DVCDQCHURZTBPCMHTBBIVKWHXKOWDXWVTUPLCLRNYQNQYVPNKFPAZIMPINXAO"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowSystem #2", msg == *msg_d); + test.boolean("CustomManeuver #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14527,27 +14829,33 @@ main(void) } { - IMC::CommsRelay msg; - msg.setTimeStamp(0.487312335463); - msg.setSource(14467U); - msg.setSourceEntity(198U); - msg.setDestination(54370U); - msg.setDestinationEntity(117U); - msg.lat = 0.930539682906; - msg.lon = 0.9248241052; - msg.speed = 0.515942570833; - msg.speed_units = 23U; - msg.duration = 14422U; - msg.sys_a = 6397U; - msg.sys_b = 46820U; - msg.move_threshold = 0.342307983257; + IMC::VehicleFormation msg; + msg.setTimeStamp(0.24805198810863882); + msg.setSource(37415U); + msg.setSourceEntity(48U); + msg.setDestination(22191U); + msg.setDestinationEntity(70U); + msg.lat = 0.5288809810079443; + msg.lon = 0.5229380255771551; + msg.z = 0.8904927828212853; + msg.z_units = 35U; + msg.speed = 0.33456568059906056; + msg.speed_units = 57U; + IMC::TrajectoryPoint tmp_msg_0; + tmp_msg_0.x = 0.13539880025254536; + tmp_msg_0.y = 0.1136626933522874; + tmp_msg_0.z = 0.9045027896600567; + tmp_msg_0.t = 0.7334088633633193; + msg.points.push_back(tmp_msg_0); + msg.start_time = 0.25159912965745135; + msg.custom.assign("WLDLRLXFHFVQKPFBEZFOTDXSCJIPVBTVUMVWQTPKZZQIDPCNJVWEGEMHXGBBFVAUOHMYGKMQRNWONVMQJJDKRWTJUIOJMIXNPZLKPQAGBOPIYSWJYSFOEONWJFTNDUYIDGCFELGZHUXCNIGZYAAXYSDRTMAYCIEOMHEUXSHRGUFGLSKBSZUNTKHFIEQWPQUBTLACGQKCZXAQHAHXEDYWVJDVS"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CommsRelay #0", msg == *msg_d); + test.boolean("VehicleFormation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14558,27 +14866,33 @@ main(void) } { - IMC::CommsRelay msg; - msg.setTimeStamp(0.886226798508); - msg.setSource(41034U); - msg.setSourceEntity(14U); - msg.setDestination(9066U); - msg.setDestinationEntity(180U); - msg.lat = 0.562609612554; - msg.lon = 0.991032363078; - msg.speed = 0.321939689308; - msg.speed_units = 232U; - msg.duration = 9210U; - msg.sys_a = 65010U; - msg.sys_b = 52247U; - msg.move_threshold = 0.660670357073; + IMC::VehicleFormation msg; + msg.setTimeStamp(0.3128982598445935); + msg.setSource(25102U); + msg.setSourceEntity(49U); + msg.setDestination(5937U); + msg.setDestinationEntity(203U); + msg.lat = 0.6502552450163235; + msg.lon = 0.940415742892014; + msg.z = 0.14624308785635565; + msg.z_units = 140U; + msg.speed = 0.5592238701031914; + msg.speed_units = 179U; + IMC::VehicleFormationParticipant tmp_msg_0; + tmp_msg_0.vid = 24947U; + tmp_msg_0.off_x = 0.8857436186241592; + tmp_msg_0.off_y = 0.7100114966988292; + tmp_msg_0.off_z = 0.05638599474887729; + msg.participants.push_back(tmp_msg_0); + msg.start_time = 0.29689819865052836; + msg.custom.assign("CKXNZFKUUHJHLCKESQQUSHIMCTODGGEIOGWHADBGFMNLRTPNWILTSQULARVZRFKNOQOQQPFAXSGJGJCBPYTCJANWEFERHCYNEDAKZUWOACYITSQLVYYDSWRMUOVVDKDYZYPZQJVMHTWWVXJLPPXUQAFMMYIRIDUOKYEWHIDZZDPMIPUBODYGBKTNCXRBSSLVHJP"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CommsRelay #1", msg == *msg_d); + test.boolean("VehicleFormation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14589,27 +14903,27 @@ main(void) } { - IMC::CommsRelay msg; - msg.setTimeStamp(0.446477661751); - msg.setSource(5774U); - msg.setSourceEntity(238U); - msg.setDestination(60150U); - msg.setDestinationEntity(58U); - msg.lat = 0.369225548718; - msg.lon = 0.336339971633; - msg.speed = 0.629906895033; - msg.speed_units = 117U; - msg.duration = 33188U; - msg.sys_a = 48965U; - msg.sys_b = 48281U; - msg.move_threshold = 0.240976450016; + IMC::VehicleFormation msg; + msg.setTimeStamp(0.43285243479361246); + msg.setSource(21947U); + msg.setSourceEntity(244U); + msg.setDestination(28086U); + msg.setDestinationEntity(129U); + msg.lat = 0.32927134129019886; + msg.lon = 0.9084503743009171; + msg.z = 0.006038239580326343; + msg.z_units = 143U; + msg.speed = 0.17662194872453196; + msg.speed_units = 231U; + msg.start_time = 0.6454241189519558; + msg.custom.assign("IRWFVRMPEVACNFBLTGUSNPTCQYEFDFSSDNYZBTMWWCREBPTJHVYDSPEDIQQJLHKGHGKABNYYZPQQTHAQONJRQBQEGECTRMSKCYKOKJMIZFZPZIJLWSAIJULZUHMSOPUIJPWZXLJWBNDFCRNHLYXDAOEKIXUBGX"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CommsRelay #2", msg == *msg_d); + test.boolean("VehicleFormation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14620,26 +14934,23 @@ main(void) } { - IMC::CoverArea msg; - msg.setTimeStamp(0.343486930529); - msg.setSource(34404U); - msg.setSourceEntity(31U); - msg.setDestination(55509U); - msg.setDestinationEntity(18U); - msg.lat = 0.00475160536674; - msg.lon = 0.428278692328; - msg.z = 0.936342328986; - msg.z_units = 12U; - msg.speed = 0.898445893349; - msg.speed_units = 196U; - msg.custom.assign("DIDCPULFEBOMSNSAMUNYJRVYAINDDEABXHIUHJWXYRMRLFIZESOLOJCKJHDCWQIAWVZMJLQJAOQTFSDIKXVXYYFCELCLAMURPSPMHNHTFQGJVZBXPTQHSPDHKBKTMNGNMTEKVWWYPFRIFLTNPDXTOLVAEKVEVKUXQCNGSYFUDFLRUGZUORKBTBAPRYEZBRIBASHNJQXKYBZCPOWGZVM"); + IMC::VehicleFormationParticipant msg; + msg.setTimeStamp(0.7030505525906733); + msg.setSource(33700U); + msg.setSourceEntity(200U); + msg.setDestination(33876U); + msg.setDestinationEntity(148U); + msg.vid = 56188U; + msg.off_x = 0.010217647622957404; + msg.off_y = 0.4548690722500843; + msg.off_z = 0.6996122184078093; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CoverArea #0", msg == *msg_d); + test.boolean("VehicleFormationParticipant #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14650,26 +14961,23 @@ main(void) } { - IMC::CoverArea msg; - msg.setTimeStamp(0.735859308879); - msg.setSource(16179U); - msg.setSourceEntity(225U); - msg.setDestination(42115U); - msg.setDestinationEntity(114U); - msg.lat = 0.146224222196; - msg.lon = 0.712318190847; - msg.z = 0.0995226681998; - msg.z_units = 107U; - msg.speed = 0.717909152409; - msg.speed_units = 189U; - msg.custom.assign("FSWNQXQZCWRCVVNDCNQQQUUHCQDFKLHEVDSROOYCSRGPSHTNEPGYREDIMUKIQOTBNALOGOZNVCOZUUFRKTXHIFZFSABXYVJVKIGXLYTTYLHXZEJKTGNCEHUDGTANBGWLDZGXHBIRQQSKMHPAZIAJ"); + IMC::VehicleFormationParticipant msg; + msg.setTimeStamp(0.09521762936377975); + msg.setSource(48612U); + msg.setSourceEntity(149U); + msg.setDestination(36491U); + msg.setDestinationEntity(4U); + msg.vid = 54762U; + msg.off_x = 0.6960205847388377; + msg.off_y = 0.7013284480620061; + msg.off_z = 0.2612734579222685; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CoverArea #1", msg == *msg_d); + test.boolean("VehicleFormationParticipant #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14680,26 +14988,23 @@ main(void) } { - IMC::CoverArea msg; - msg.setTimeStamp(0.0322710305055); - msg.setSource(14444U); - msg.setSourceEntity(139U); - msg.setDestination(20107U); - msg.setDestinationEntity(57U); - msg.lat = 0.369310824155; - msg.lon = 0.870984240994; - msg.z = 0.97405281804; - msg.z_units = 29U; - msg.speed = 0.433105650515; - msg.speed_units = 220U; - msg.custom.assign("HDIOZODRAMOSGWLHVFZBOXNVCMHXSSAVIBSWPQUIIDZWWMSJKNJEKOLBMNAHYWHPLTTUKYIJFUYMXGZPBVPAJCVNQYLYFINUNIAXAHUGCVRZAGNKGSKXDPSZMAHJWQEE"); + IMC::VehicleFormationParticipant msg; + msg.setTimeStamp(0.2596956376476799); + msg.setSource(1904U); + msg.setSourceEntity(183U); + msg.setDestination(21798U); + msg.setDestinationEntity(234U); + msg.vid = 49171U; + msg.off_x = 0.7669446933923546; + msg.off_y = 0.955457235333899; + msg.off_z = 0.2584002833664757; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CoverArea #2", msg == *msg_d); + test.boolean("VehicleFormationParticipant #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14710,21 +15015,19 @@ main(void) } { - IMC::PolygonVertex msg; - msg.setTimeStamp(0.444944171028); - msg.setSource(38756U); - msg.setSourceEntity(68U); - msg.setDestination(26182U); - msg.setDestinationEntity(159U); - msg.lat = 0.524852398731; - msg.lon = 0.126115286065; + IMC::StopManeuver msg; + msg.setTimeStamp(0.0409185202733926); + msg.setSource(40813U); + msg.setSourceEntity(112U); + msg.setDestination(1398U); + msg.setDestinationEntity(213U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PolygonVertex #0", msg == *msg_d); + test.boolean("StopManeuver #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14735,21 +15038,19 @@ main(void) } { - IMC::PolygonVertex msg; - msg.setTimeStamp(0.729379053485); - msg.setSource(4155U); + IMC::StopManeuver msg; + msg.setTimeStamp(0.5310199906532755); + msg.setSource(50736U); msg.setSourceEntity(159U); - msg.setDestination(18332U); - msg.setDestinationEntity(63U); - msg.lat = 0.353055766629; - msg.lon = 0.056396500057; + msg.setDestination(50588U); + msg.setDestinationEntity(156U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PolygonVertex #1", msg == *msg_d); + test.boolean("StopManeuver #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14760,21 +15061,19 @@ main(void) } { - IMC::PolygonVertex msg; - msg.setTimeStamp(0.351502017052); - msg.setSource(58045U); - msg.setSourceEntity(247U); - msg.setDestination(55027U); - msg.setDestinationEntity(12U); - msg.lat = 0.552831089218; - msg.lon = 0.558324165773; + IMC::StopManeuver msg; + msg.setTimeStamp(0.9601382987824155); + msg.setSource(11967U); + msg.setSourceEntity(175U); + msg.setDestination(33788U); + msg.setDestinationEntity(41U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PolygonVertex #2", msg == *msg_d); + test.boolean("StopManeuver #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14785,32 +15084,20 @@ main(void) } { - IMC::CompassCalibration msg; - msg.setTimeStamp(0.111122084649); - msg.setSource(29303U); - msg.setSourceEntity(140U); - msg.setDestination(28972U); - msg.setDestinationEntity(54U); - msg.timeout = 15066U; - msg.lat = 0.549173909143; - msg.lon = 0.406849427382; - msg.z = 0.514581517082; - msg.z_units = 56U; - msg.pitch = 0.283423512961; - msg.amplitude = 0.885886836236; - msg.duration = 19381U; - msg.speed = 0.665854907989; - msg.speed_units = 176U; - msg.radius = 0.56601581409; - msg.direction = 214U; - msg.custom.assign("QXNLRLXXVXLBRCUURHHGMUPOTEORJASVBOIWMGEDBJNABXHTZHOSCYTRZS"); + IMC::RegisterManeuver msg; + msg.setTimeStamp(0.8846831437031246); + msg.setSource(5930U); + msg.setSourceEntity(35U); + msg.setDestination(27205U); + msg.setDestinationEntity(19U); + msg.mid = 25051U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CompassCalibration #0", msg == *msg_d); + test.boolean("RegisterManeuver #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14821,32 +15108,20 @@ main(void) } { - IMC::CompassCalibration msg; - msg.setTimeStamp(0.605741297723); - msg.setSource(28043U); - msg.setSourceEntity(134U); - msg.setDestination(44797U); - msg.setDestinationEntity(19U); - msg.timeout = 24796U; - msg.lat = 0.545509368439; - msg.lon = 0.371208226028; - msg.z = 0.490881701233; - msg.z_units = 184U; - msg.pitch = 0.836207007959; - msg.amplitude = 0.206316712654; - msg.duration = 35894U; - msg.speed = 0.787178908134; - msg.speed_units = 45U; - msg.radius = 0.333536122051; - msg.direction = 86U; - msg.custom.assign("QAIYBCWOFFELJZHVAQHWYRBJOAOEUMBHPTQWDQUMSIFDRWRSSVGRGMGXSXBYSOZZJUKGUCKCVGFRUKICVJVETKNMYPQMRWTBDPVVTLBUXFFSCK"); + IMC::RegisterManeuver msg; + msg.setTimeStamp(0.46879336162593177); + msg.setSource(47980U); + msg.setSourceEntity(100U); + msg.setDestination(53687U); + msg.setDestinationEntity(53U); + msg.mid = 43185U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CompassCalibration #1", msg == *msg_d); + test.boolean("RegisterManeuver #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14857,32 +15132,20 @@ main(void) } { - IMC::CompassCalibration msg; - msg.setTimeStamp(0.538009993391); - msg.setSource(27907U); - msg.setSourceEntity(215U); - msg.setDestination(60111U); - msg.setDestinationEntity(104U); - msg.timeout = 41995U; - msg.lat = 0.467106808645; - msg.lon = 0.504391179263; - msg.z = 0.800023834229; - msg.z_units = 91U; - msg.pitch = 0.52980699994; - msg.amplitude = 0.512009277561; - msg.duration = 18472U; - msg.speed = 0.579913358432; - msg.speed_units = 46U; - msg.radius = 0.418765479198; - msg.direction = 142U; - msg.custom.assign("DGXCRGQJAOMYAVCNSZKVPVUFDITPMSITYTGKOPYFJUZDIWFVXPSEBHCZWRBKUBYMDUEZAJTPIUPTOBDCFSGQALONPWAPQJGJKEWCTHIZWCHLRFKOMKWUVBCJELHFUFIOXUILRUAMRADLNHBUNMREQMQXQLBBWXQZLIJEGKJHLIEOBNTFAWRVDNFJKMDVYZSHKLRTMXCSOFVHJOYHXTIPRGAVNSWTXVHSPLNQZSRNGEZYYZKDECYCEGA"); + IMC::RegisterManeuver msg; + msg.setTimeStamp(0.7354168677962412); + msg.setSource(25939U); + msg.setSourceEntity(58U); + msg.setDestination(20111U); + msg.setDestinationEntity(230U); + msg.mid = 64894U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CompassCalibration #2", msg == *msg_d); + test.boolean("RegisterManeuver #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14893,22 +15156,22 @@ main(void) } { - IMC::FormationParameters msg; - msg.setTimeStamp(0.672145850771); - msg.setSource(21199U); - msg.setSourceEntity(128U); - msg.setDestination(21271U); - msg.setDestinationEntity(180U); - msg.formation_name.assign("ZJSCXQXGEMQRLCRDBQAATKIGHZGNZEZAIHEWXQZROOUJGLVAJRNCEXFOTAXYBHUXPFCUJHYLDLWUBMUTMFPIVQSVVEMEJZBRXOYGHKYPKTBDNCDNQFOUVDYLWFLPRBIIYPAIBDOLPVZVTSJWHJRQOVMZHHMHEJYSOUTNQFGPLAIKUJSNKWZVSFWFARSMYGVUKKKQFPISUS"); - msg.reference_frame = 7U; - msg.custom.assign("CXHKGBZHSAPEDSLZGG"); + IMC::ManeuverControlState msg; + msg.setTimeStamp(0.8308723054428221); + msg.setSource(42122U); + msg.setSourceEntity(41U); + msg.setDestination(40296U); + msg.setDestinationEntity(199U); + msg.state = 216U; + msg.eta = 2825U; + msg.info.assign("BNTEZXYJEAVOITOBIPKTVRCIVIDCQOGVEKEIHLWQKTLYAJAWRRZHOABGEFBKMKSLTENFUNWSJKMNSHJOXXHPBQVGLPNGYDZAFPRVDOQODPDBBGXM"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationParameters #0", msg == *msg_d); + test.boolean("ManeuverControlState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14919,22 +15182,22 @@ main(void) } { - IMC::FormationParameters msg; - msg.setTimeStamp(0.6891783396); - msg.setSource(7495U); - msg.setSourceEntity(21U); - msg.setDestination(61817U); - msg.setDestinationEntity(161U); - msg.formation_name.assign("LWSQNLNRKQAJLFUWUCMTHPMVHSSPZPHPMGJRXKJUKWQPVSVTANYDHEZIBYZVISEGONPNBNHHFXMSEEAOTDXGNYRJXPQIXCMVQAKXATMAMOUODFAQSDBINDZKDHHUBDZIUFOTKYLVXKJVOLUOOXKJACEAEWWTXBLXJHELYYJERRGJWBGDBI"); - msg.reference_frame = 65U; - msg.custom.assign("VZMDNBWARIXFIBYSULNDPLUTTBHZILRMEYKJQJEXFXYSKWSNAXISVMNIYHPBTVZUKFIGGRFAPQHKXEDBUIDHSTRMSISHDRAQMLMMGALEYUPEPOHONCZVLE"); + IMC::ManeuverControlState msg; + msg.setTimeStamp(0.9209787522780899); + msg.setSource(32710U); + msg.setSourceEntity(70U); + msg.setDestination(4895U); + msg.setDestinationEntity(82U); + msg.state = 12U; + msg.eta = 11369U; + msg.info.assign("VUYMHABNNEIOZGNUULGEBOZAMRKPRDEAVNZAPWZKOYPCKRJHCNSLCXLCTVGKKGFLFSJWFFCGBMYAJIOJRMVHPHQKYSPGVGYYISDNFBZXIEEDGUICXDXKSLGCETPHXZVONITPQDDFTXQMTIWSQJFQWORGWEBZMZPSOLDJDWPJARVRMTXUYIEUAWTNRHAODCEVQYJWOBBRPUYCBHXQIKDAJYLATXBWSKXLFURSQIZNBQVMJLET"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationParameters #1", msg == *msg_d); + test.boolean("ManeuverControlState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14945,22 +15208,2632 @@ main(void) } { - IMC::FormationParameters msg; - msg.setTimeStamp(0.561621888428); - msg.setSource(48687U); - msg.setSourceEntity(236U); - msg.setDestination(23634U); - msg.setDestinationEntity(60U); - msg.formation_name.assign("UZABTPNXZFKDTJFCISVBTEHJQQOOLKFCGXPEBZXGULVAJRMQEWRMAUDLYCYKHMNWIAZREETEXIKIRURAWJMVHBGLNMDNVXQECPCYXOBJSFIQYRGFWQY"); + IMC::ManeuverControlState msg; + msg.setTimeStamp(0.6894664835685961); + msg.setSource(11664U); + msg.setSourceEntity(28U); + msg.setDestination(45090U); + msg.setDestinationEntity(131U); + msg.state = 197U; + msg.eta = 58659U; + msg.info.assign("MXNMANEJYMEACNIICUXCCEOFZLQGAQXJMGZWHHYBTAZDFCGCRISJQNLVBSTCDRHQZQPPSAZRQMWSROOTDNOKTHFVCXBYZIWMPJKFJVPZSOONPIEEQBPPUUYEEGBFBVIGYPWZRNTTUIVZDPWAVXGCMLJMRNWKGUTJWDUMZKKGEWFRSUAGDBSHTLAUOIOLXCVSV"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("ManeuverControlState #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowSystem msg; + msg.setTimeStamp(0.39845077896010517); + msg.setSource(14718U); + msg.setSourceEntity(229U); + msg.setDestination(57942U); + msg.setDestinationEntity(215U); + msg.system = 4590U; + msg.duration = 46317U; + msg.speed = 0.3064759571803519; + msg.speed_units = 31U; + msg.x = 0.7498849143138154; + msg.y = 0.709130137374102; + msg.z = 0.5052630708209754; + msg.z_units = 153U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowSystem #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowSystem msg; + msg.setTimeStamp(0.1792441893809854); + msg.setSource(3014U); + msg.setSourceEntity(124U); + msg.setDestination(15071U); + msg.setDestinationEntity(159U); + msg.system = 14894U; + msg.duration = 19673U; + msg.speed = 0.4153446880160483; + msg.speed_units = 167U; + msg.x = 0.0914647346987073; + msg.y = 0.8699326991176565; + msg.z = 0.7783533343857935; + msg.z_units = 22U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowSystem #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowSystem msg; + msg.setTimeStamp(0.8792361858072916); + msg.setSource(52719U); + msg.setSourceEntity(228U); + msg.setDestination(24612U); + msg.setDestinationEntity(43U); + msg.system = 16286U; + msg.duration = 57013U; + msg.speed = 0.7168498609642444; + msg.speed_units = 220U; + msg.x = 0.1417609952269513; + msg.y = 0.7264761154220678; + msg.z = 0.23762178165149261; + msg.z_units = 108U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowSystem #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CommsRelay msg; + msg.setTimeStamp(0.7114390129111942); + msg.setSource(32094U); + msg.setSourceEntity(148U); + msg.setDestination(39549U); + msg.setDestinationEntity(206U); + msg.lat = 0.9623362108571127; + msg.lon = 0.6100364675704768; + msg.speed = 0.2167823171662253; + msg.speed_units = 205U; + msg.duration = 54434U; + msg.sys_a = 11822U; + msg.sys_b = 10716U; + msg.move_threshold = 0.17780973222316054; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CommsRelay #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CommsRelay msg; + msg.setTimeStamp(0.39698275269795635); + msg.setSource(19696U); + msg.setSourceEntity(253U); + msg.setDestination(15036U); + msg.setDestinationEntity(7U); + msg.lat = 0.7205601267133684; + msg.lon = 0.7632347995048284; + msg.speed = 0.40946149278370825; + msg.speed_units = 201U; + msg.duration = 15844U; + msg.sys_a = 9001U; + msg.sys_b = 29845U; + msg.move_threshold = 0.243098569118825; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CommsRelay #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CommsRelay msg; + msg.setTimeStamp(0.5649650493330989); + msg.setSource(7684U); + msg.setSourceEntity(253U); + msg.setDestination(50716U); + msg.setDestinationEntity(68U); + msg.lat = 0.3135381745786727; + msg.lon = 0.5325434737070277; + msg.speed = 0.3190635814119638; + msg.speed_units = 58U; + msg.duration = 9245U; + msg.sys_a = 39916U; + msg.sys_b = 30107U; + msg.move_threshold = 0.8405134963197067; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CommsRelay #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CoverArea msg; + msg.setTimeStamp(0.944067389904379); + msg.setSource(29133U); + msg.setSourceEntity(73U); + msg.setDestination(12074U); + msg.setDestinationEntity(157U); + msg.lat = 0.18495114883235952; + msg.lon = 0.3191563907897724; + msg.z = 0.17195639896479964; + msg.z_units = 91U; + msg.speed = 0.8089812239190073; + msg.speed_units = 6U; + msg.custom.assign("QJLWFWIPPUDBBHFCKLAKTNEMMURGYNPMOSOJGFYTVIYBXYJVHUQGQRYMXZNFOODQZDTNSMYOESTHIDBTQLFDNAUDBGIZOJDPTLIAGQ"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CoverArea #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CoverArea msg; + msg.setTimeStamp(0.6190442948493297); + msg.setSource(21359U); + msg.setSourceEntity(207U); + msg.setDestination(22088U); + msg.setDestinationEntity(111U); + msg.lat = 0.36963454073881663; + msg.lon = 0.21423511173518883; + msg.z = 0.4145662250160774; + msg.z_units = 17U; + msg.speed = 0.46947877269428406; + msg.speed_units = 181U; + msg.custom.assign("MJHINIKWIGZTNDBNHMWAYDHCJIEHBLUCAJXSGSWEZPNYUQTSOIPYZUHYYRCCDMUPFTOAMOVPWHVAEQWAUJTSOFKKXOPCZZUCRKGSLXQPVFQONFPARLPLYNQNQSNXRMKWBCMDKFUUEREDCJHRQBRBDVQHGJWBNNXVFTBLLQXTMEUVIGTGSFJEWRKGLIVDPBDZMTYECDYSPTQKMFIVGIVDKKXFYUVTSZAAJJACL"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CoverArea #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CoverArea msg; + msg.setTimeStamp(0.1477709360626186); + msg.setSource(20866U); + msg.setSourceEntity(121U); + msg.setDestination(28023U); + msg.setDestinationEntity(183U); + msg.lat = 0.193238392196462; + msg.lon = 0.5570486810887906; + msg.z = 0.8970439366641427; + msg.z_units = 64U; + msg.speed = 0.10448022642751953; + msg.speed_units = 32U; + msg.custom.assign("AIQVRENHXZREMJOHXSFTADRZELJKWSFAZLIKXBAWRGZZDMOFPYFSQJSVLFGTPGPWNDCTWETYUBNCAKIVCKNDYXLPZBXKBGTTKZPRMECOFPCOSVQASPLQMMCPQANYJQRCYDGBHDHXMMHKEUJXRWMWBRNNONVUTSUDVWFITPLHIHEVSBIWALEXHFDULZUQSLJXWBUVJCOV"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CoverArea #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::PolygonVertex msg; + msg.setTimeStamp(0.05343067505771404); + msg.setSource(53947U); + msg.setSourceEntity(22U); + msg.setDestination(63710U); + msg.setDestinationEntity(80U); + msg.lat = 0.6572098015482657; + msg.lon = 0.4253504462823746; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("PolygonVertex #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::PolygonVertex msg; + msg.setTimeStamp(0.6869713660715995); + msg.setSource(42809U); + msg.setSourceEntity(164U); + msg.setDestination(3674U); + msg.setDestinationEntity(26U); + msg.lat = 0.7580623790994835; + msg.lon = 0.7793166985583598; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("PolygonVertex #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::PolygonVertex msg; + msg.setTimeStamp(0.2509080612485236); + msg.setSource(8298U); + msg.setSourceEntity(129U); + msg.setDestination(63467U); + msg.setDestinationEntity(221U); + msg.lat = 0.6631972840452077; + msg.lon = 0.5860327606216033; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("PolygonVertex #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CompassCalibration msg; + msg.setTimeStamp(0.5474260661374658); + msg.setSource(40199U); + msg.setSourceEntity(110U); + msg.setDestination(22074U); + msg.setDestinationEntity(85U); + msg.timeout = 37742U; + msg.lat = 0.8027241470734573; + msg.lon = 0.8934097736411242; + msg.z = 0.939263824841119; + msg.z_units = 211U; + msg.pitch = 0.15742724162056243; + msg.amplitude = 0.8831493988003073; + msg.duration = 9073U; + msg.speed = 0.6203322432480738; + msg.speed_units = 83U; + msg.radius = 0.4490819767281288; + msg.direction = 156U; + msg.custom.assign("KZBBLPQPEFPUMTNEIMWDPAOIOIOCEXSARHDJZHOVXSMCBKGKPJXRYEOXHBZMEJLRBHYVWQNWPVKVRGLZYCNNFBDZAZBRYDQZRFCEFHRJNAMDWXZMSLSPNJLINKTMIAWFXYSYHQLQFHCTDDDSUWYJPOCTRGFKMAOEXCIVBUSN"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CompassCalibration #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CompassCalibration msg; + msg.setTimeStamp(0.3306966667108031); + msg.setSource(27340U); + msg.setSourceEntity(225U); + msg.setDestination(23060U); + msg.setDestinationEntity(24U); + msg.timeout = 59854U; + msg.lat = 0.5831526538710474; + msg.lon = 0.7465825094725737; + msg.z = 0.6305186837780509; + msg.z_units = 200U; + msg.pitch = 0.08233345271254922; + msg.amplitude = 0.5007804073923272; + msg.duration = 31745U; + msg.speed = 0.3694387523081042; + msg.speed_units = 62U; + msg.radius = 0.6049182789374129; + msg.direction = 235U; + msg.custom.assign("NGPDVUYYFRUVLJDXDAZXLTHWWCEQOMZCSWCPYDKGVRCELBEPJNCIRODGOLKCQNZRZTJSMDSMTUFOYUNBAXBOLYRJDDJEOYHKLFFDKMPIFXITSZAHIPHCYBXEEWBVGERRUQVPSGNHPLTTAQNBHHRCTZKTFLTSFJAJMUOLZMYAKEKRQQNAAGFNIWIOI"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CompassCalibration #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::CompassCalibration msg; + msg.setTimeStamp(0.5886728310313564); + msg.setSource(21946U); + msg.setSourceEntity(33U); + msg.setDestination(65136U); + msg.setDestinationEntity(90U); + msg.timeout = 42392U; + msg.lat = 0.02686118002806126; + msg.lon = 0.5338153058750652; + msg.z = 0.1939804401122358; + msg.z_units = 161U; + msg.pitch = 0.46617259212541773; + msg.amplitude = 0.6757468806310897; + msg.duration = 6096U; + msg.speed = 0.6177702184248086; + msg.speed_units = 168U; + msg.radius = 0.12613052212648868; + msg.direction = 104U; + msg.custom.assign("TJLEDULWJWSTBGKCGFKEOAVAJLIEMHXJEBPNZRKMAQRBQEHTMFEUIZARMCHQPIVBWBLPTGXXUGMROMFCDFFRBYDVHLKN"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("CompassCalibration #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationParameters msg; + msg.setTimeStamp(0.6201631711399175); + msg.setSource(6394U); + msg.setSourceEntity(226U); + msg.setDestination(64691U); + msg.setDestinationEntity(222U); + msg.formation_name.assign("DIOTPBMFVAYAGVCCFPVBGAEHNCAMZJLMRTENRGIKLWSFWQCYWOPUZCHUNSIKQEGEFSULWTRO"); + msg.reference_frame = 60U; + IMC::VehicleFormationParticipant tmp_msg_0; + tmp_msg_0.vid = 1860U; + tmp_msg_0.off_x = 0.5865915644747534; + tmp_msg_0.off_y = 0.19077364260487428; + tmp_msg_0.off_z = 0.9797986247526929; + msg.participants.push_back(tmp_msg_0); + msg.custom.assign("EAOGXQCDQPHAYELAKKSQHVWOIHZTJVQSLVJGFTYBHJJACDOBPNTIRBVYITRXFFGSJFPLGZWOKCKJUOPLLCYKXUEVKVXFIRBCNFZFWXKOAZIQTYREUCDVYBIFYTHBMBPETDZIGSBXNHVLHNUJXQCLXOOEM"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationParameters #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationParameters msg; + msg.setTimeStamp(0.4569213766808541); + msg.setSource(13316U); + msg.setSourceEntity(101U); + msg.setDestination(23217U); + msg.setDestinationEntity(222U); + msg.formation_name.assign("UJRFAGLSKPQVZONAFMYOYVKZUYYRVZBUZWNHBMJPCFPWSDSRQSKQGXWAGRPIYKCTQIPESIHTXWOBGFLLHVURHSWASCRLJIPAZLDWOEWRNRXFBYRXMYHMELZOJEBXDKCJYODBYKBQCZJPKCEPEDBDRGLUPHTSCCGJIHJIEXXMEFKNUNQONHYNWIAWVZTVFVKBONALMNJLXODUHADATQJFSUMIWZVKFQOSGIXEFLNXQMUGVVIHGME"); msg.reference_frame = 125U; - msg.custom.assign("IOPZPSWLHNEAPETBZEYRPDNQRIBMBIYHRCEGMOBZWNWEUNNTUSMOALAQFYVUBRJFIQVIHEDUDNAKHHBRHJMDCZOWXERUYWZTQBVPHYUXAXKPLADXOSIEFBLERGSZHCL"); + IMC::VehicleFormationParticipant tmp_msg_0; + tmp_msg_0.vid = 35548U; + tmp_msg_0.off_x = 0.977962056336479; + tmp_msg_0.off_y = 0.2562325628834461; + tmp_msg_0.off_z = 0.8787874402107564; + msg.participants.push_back(tmp_msg_0); + msg.custom.assign("FLZKYAWLQXEANWKHDLCGZZVLOIQKCRQDNDPTRDGWGIHQYWCBCTINXYDSQMVXRRVQMKYNBOKPARCYWHNIJHNUZDFJSOQETJFWBGAAFXESPULJORZBQTGVPRFTYHIUMUHPXHKSSTZDBAFXOASFLGRFBYYTACKENQSMXJTPGMNZOCLEMEVZUSMTXZHDLEFBAGFKIHYUJWCZOOIPVOLBVNCPIMT"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationParameters #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationParameters msg; + msg.setTimeStamp(0.3249656097041034); + msg.setSource(11726U); + msg.setSourceEntity(251U); + msg.setDestination(5892U); + msg.setDestinationEntity(27U); + msg.formation_name.assign("YXLWYMZCCEQDKEABIWIHFYUPWCJNZNLGSKMHIUTOISADSDSBDLBYZJKUTPHPWOZNCHMJMXOUVBOAHRBVBEPJLGOIBEGWPZYEMHZRXJRPTKHYLRQQELOUCBVSGPFCWDMJLPXRMANUARBWSIRYQKJNQSRCFJVXVFYFCXFQKJFSMGLTUGNHKWWKRAOGEVIBVIDEKUMTDFGUUQADKCIAZXFFCNHTTSIVTJNGV"); + msg.reference_frame = 106U; + msg.custom.assign("GBDYNZYNGBWMRWPHAFHKTMIQVRHDVTNVDGCTHMKFTEAFXEYHOYTYLEPCDMMOHQZJUADZKUPIULQMQKJBTRSRAYCQOCMJAAJFKNXVQRTKZCSONHPWUWMBRZIYDWLHLBPLQKFUNXXICKCUOYEXALWSZPNZIS"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationParameters #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationPlanExecution msg; + msg.setTimeStamp(0.46291440914230775); + msg.setSource(6654U); + msg.setSourceEntity(15U); + msg.setDestination(13353U); + msg.setDestinationEntity(148U); + msg.group_name.assign("YVXDSDCTVFECLKLKLEUSWFXCFABLMYNNWAKEOQCNFBGTENDKJGTBWEKZODWQTASVFNXPSLGKDMEUCHUYBUKVOFHJMJQMUCX"); + msg.formation_name.assign("PFCGUVCDTVGCCNLNBVTVNBZRLEJXAGBNEGBIMNVJKMWGWWJJZGNIMXUXSFAJPXEABKUIJHYXZUQIHOYRSRXHSZDRDCHZFLUVNDPJBYFADUIOFUKLOHKGTYNDYBNZLYCFQM"); + msg.plan_id.assign("OJFJQWQWSHLGIXDWCMDLSMTKSBIFZGQFUIVXBXRIJDOBNAOMKRFFQ"); + msg.description.assign("HDBNRJXHQZAWTFLTGQSTWGPYSOTEPVUFQAIGIOFJLNRAMGLZQRLXZYJKHNPLIVESWWKKGRNONFDCPDAN"); + msg.leader_speed = 0.5755732526907854; + msg.leader_bank_lim = 0.5380111307566166; + msg.pos_sim_err_lim = 0.5198872331455838; + msg.pos_sim_err_wrn = 0.4293898311871145; + msg.pos_sim_err_timeout = 43146U; + msg.converg_max = 0.7183653706097998; + msg.converg_timeout = 43323U; + msg.comms_timeout = 39028U; + msg.turb_lim = 0.40471142196744025; + msg.custom.assign("UCNFHJKELGJMNWYCSKZBAXCXMAVILHVNLWWTRTRAGOYDNULBQNPNYIDIRUPPOLZIUFEGYDBOUIKESGLHOMDLJPQQMWZIKTAYRKBDWUNQPBSMRBTXCXNQGVXJKNVFORJZXATCQRZYPGJMDSJIQJELTWWABKSQGYVWAEV"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationPlanExecution #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationPlanExecution msg; + msg.setTimeStamp(0.5800049507754171); + msg.setSource(53439U); + msg.setSourceEntity(169U); + msg.setDestination(8346U); + msg.setDestinationEntity(14U); + msg.group_name.assign("SBUCUZCOCMCIYRJSKUDGONWLEIHBVMBPLMSPQACPQQSFWKBMVSEUDDYNRFNLADLZUGWEGQXJFQBMXNHFVTARFSKHGOWYHTEZQXIQWBPLOSAWSDRCTKEQAYZOJQXVHHHPCNXKFAERVZNYGDBPNRLGTWTIJAGUOUMHHGIWTEFMUXDEOITMRRXACLVVXOPJYESTVJLPTMNJGEWIPHNBBOZPIRGYAZYZNTC"); + msg.formation_name.assign("KRTREXLINSVRXJMYBJMNNOHXYNGBHVJTTCJHNVFKAXQAXVWOKUHSSDPFQXIFBHHTOZRBIFRWMMABZUCCMWZYQELOSISLFXVTBGPRQOENDDCJEBTEQXLRJOZNMQYYECIQALUEXUYZDGQRTADKKDPOIRWTKAPDEZEZFUSMURAGWV"); + msg.plan_id.assign("BTSGQUVAZCTKFEYNRZWEVEWAXMTDTZLYFTXSYQJMWOZBHMARCJTKWBPDYAOQDQPIXPLLGUNBDLLFHBAFRZHNUMVQWXJIUBTDZBARGXRVXWIVXUQHKOYHDRVSWGDVNXKZOC"); + msg.description.assign("YLRNMALVZGIOMEGHNAAUCVJXGPWNBGQKMRWXDFPWFDIOJPUMPJHDEDPJQHGQELUGHCHOQMYBJSCDRLLXSLEPUMAZFRTBCKJZTUKBYZARXITOKBKHWTGYODTPDGNWSMAHWVQJKUPSNCRFIVSFVFQNALMDYFNFSGREICTJVYWPVSIRMLLZOCXISJYWXAXRKOEYIZWRXYTEVEBBZUCSCWQZOAOGKHTPEBUFTNJVODBEIVXZDUNMQLUKXTBQFZAH"); + msg.leader_speed = 0.16926365998141057; + msg.leader_bank_lim = 0.922588792682339; + msg.pos_sim_err_lim = 0.5700058136138683; + msg.pos_sim_err_wrn = 0.4896079143798454; + msg.pos_sim_err_timeout = 10056U; + msg.converg_max = 0.23886649423367; + msg.converg_timeout = 25731U; + msg.comms_timeout = 1528U; + msg.turb_lim = 0.9863580354951599; + msg.custom.assign("AJNFBCEJHQFJVRBYCXLPGEATIYAFTTYYHPVCDKKSSHHOPDRSLSUCJMMWUXWDZYLNWZKAIGOYFFBZLRXABXMARHXAFVJIGIQUPZHRFNWESKIXPIOQJMYR"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationPlanExecution #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationPlanExecution msg; + msg.setTimeStamp(0.8334280700371034); + msg.setSource(11913U); + msg.setSourceEntity(175U); + msg.setDestination(61780U); + msg.setDestinationEntity(134U); + msg.group_name.assign("VXJZNQJDCGXFETHCEZOBHMGAECKXRZYETCBCBZOVPYANNKDZ"); + msg.formation_name.assign("KFTVQRCASZWEERHZLOWJRGZPBRRWSBHFURULAPWAOJMZYGNSOGDCJQVAGCGLDXPRT"); + msg.plan_id.assign("XFMYNDPFSUQNLWSTTSKZJXAHQLVXOPLLEPEKOUPEUVDAAYZJBXBUZCDPRTZGXIZTIEGLUTTAWSAQHMWGXPVKKTTQZROUXYDZCAFKOBNIHLXIKNEWNFOHYCWHCVDOQDRGZEDFIAKSBGJWRJGMRQRJRCLSZRFCEMWAEHXMQVMQBHOHMCBSNJUEVNJZUXFYFYAIEJLIUNWVNUOQKWBTYWDOMPVRFBDYBQIPVL"); + msg.description.assign("KTIZLIFVNXCASQNLMXTCEAFUUJICPBQFHURGZAXLCABYBZZITPIKDKSCPUXXTEHHBDYZEVCRLMKOYMQFPLXWQT"); + msg.leader_speed = 0.9396682663667851; + msg.leader_bank_lim = 0.887299949003322; + msg.pos_sim_err_lim = 0.7495331483255507; + msg.pos_sim_err_wrn = 0.45903090452729756; + msg.pos_sim_err_timeout = 14199U; + msg.converg_max = 0.18111823062010834; + msg.converg_timeout = 61908U; + msg.comms_timeout = 4565U; + msg.turb_lim = 0.7689132534219776; + msg.custom.assign("CIEDQBGXPIXQQBIJNXYKHAWSCOKYHNSDSFHKPYEBTVZGUWTQGLTQTHLMFIKGBTKBWVVCADQLVGZTQZAYXPWTGAFFETPILJNKDYCMQRIXBFAAJPPBRABLXDIRUESDJVYZHNPJZEMYNUIMQKWTWROWLJMXVSYDRNYLUVCJEUVKRJRNNXJLDEHUDFOBMPRGINZAUFKSCOMFHOPCZSTXNSSECGHWLOWV"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationPlanExecution #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowReference msg; + msg.setTimeStamp(0.8908721900239461); + msg.setSource(33014U); + msg.setSourceEntity(210U); + msg.setDestination(12552U); + msg.setDestinationEntity(180U); + msg.control_src = 63240U; + msg.control_ent = 176U; + msg.timeout = 0.7210635041999716; + msg.loiter_radius = 0.7120236281471767; + msg.altitude_interval = 0.3513577923406517; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowReference #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowReference msg; + msg.setTimeStamp(0.7305726786451512); + msg.setSource(24915U); + msg.setSourceEntity(178U); + msg.setDestination(48199U); + msg.setDestinationEntity(240U); + msg.control_src = 46230U; + msg.control_ent = 205U; + msg.timeout = 0.07747801998420278; + msg.loiter_radius = 0.23783222579837038; + msg.altitude_interval = 0.3120181903358108; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowReference #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowReference msg; + msg.setTimeStamp(0.1851065686417689); + msg.setSource(28964U); + msg.setSourceEntity(69U); + msg.setDestination(13940U); + msg.setDestinationEntity(230U); + msg.control_src = 32544U; + msg.control_ent = 239U; + msg.timeout = 0.6787412294533387; + msg.loiter_radius = 0.5443521382494624; + msg.altitude_interval = 0.7014272109734214; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowReference #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Reference msg; + msg.setTimeStamp(0.23734463105681192); + msg.setSource(18799U); + msg.setSourceEntity(154U); + msg.setDestination(61396U); + msg.setDestinationEntity(123U); + msg.flags = 44U; + IMC::DesiredSpeed tmp_msg_0; + tmp_msg_0.value = 0.09882341322050525; + tmp_msg_0.speed_units = 250U; + msg.speed.set(tmp_msg_0); + IMC::DesiredZ tmp_msg_1; + tmp_msg_1.value = 0.7485418987798892; + tmp_msg_1.z_units = 203U; + msg.z.set(tmp_msg_1); + msg.lat = 0.685158008299975; + msg.lon = 0.5278678896592215; + msg.radius = 0.9307161171487137; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Reference #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Reference msg; + msg.setTimeStamp(0.8589958221615835); + msg.setSource(19563U); + msg.setSourceEntity(1U); + msg.setDestination(36772U); + msg.setDestinationEntity(214U); + msg.flags = 68U; + IMC::DesiredSpeed tmp_msg_0; + tmp_msg_0.value = 0.5755399499496078; + tmp_msg_0.speed_units = 170U; + msg.speed.set(tmp_msg_0); + IMC::DesiredZ tmp_msg_1; + tmp_msg_1.value = 0.7534358917687205; + tmp_msg_1.z_units = 34U; + msg.z.set(tmp_msg_1); + msg.lat = 0.6452128754722826; + msg.lon = 0.07263512150516549; + msg.radius = 0.6991757571589722; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Reference #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Reference msg; + msg.setTimeStamp(0.4303421101343645); + msg.setSource(28350U); + msg.setSourceEntity(244U); + msg.setDestination(5903U); + msg.setDestinationEntity(176U); + msg.flags = 135U; + IMC::DesiredSpeed tmp_msg_0; + tmp_msg_0.value = 0.35544223722951496; + tmp_msg_0.speed_units = 176U; + msg.speed.set(tmp_msg_0); + IMC::DesiredZ tmp_msg_1; + tmp_msg_1.value = 0.801983233683542; + tmp_msg_1.z_units = 52U; + msg.z.set(tmp_msg_1); + msg.lat = 0.5030224410300238; + msg.lon = 0.06314261724203984; + msg.radius = 0.2671995322466202; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Reference #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowRefState msg; + msg.setTimeStamp(0.45208963487483333); + msg.setSource(12136U); + msg.setSourceEntity(118U); + msg.setDestination(53314U); + msg.setDestinationEntity(65U); + msg.control_src = 16467U; + msg.control_ent = 178U; + IMC::Reference tmp_msg_0; + tmp_msg_0.flags = 244U; + IMC::DesiredSpeed tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.value = 0.07940672374257385; + tmp_tmp_msg_0_0.speed_units = 220U; + tmp_msg_0.speed.set(tmp_tmp_msg_0_0); + IMC::DesiredZ tmp_tmp_msg_0_1; + tmp_tmp_msg_0_1.value = 0.7740685345511913; + tmp_tmp_msg_0_1.z_units = 42U; + tmp_msg_0.z.set(tmp_tmp_msg_0_1); + tmp_msg_0.lat = 0.7311651260118374; + tmp_msg_0.lon = 0.44712966701044654; + tmp_msg_0.radius = 0.865903895590249; + msg.reference.set(tmp_msg_0); + msg.state = 144U; + msg.proximity = 225U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowRefState #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowRefState msg; + msg.setTimeStamp(0.9928819710454607); + msg.setSource(37178U); + msg.setSourceEntity(185U); + msg.setDestination(39121U); + msg.setDestinationEntity(205U); + msg.control_src = 12997U; + msg.control_ent = 72U; + IMC::Reference tmp_msg_0; + tmp_msg_0.flags = 136U; + IMC::DesiredSpeed tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.value = 0.8239421341756638; + tmp_tmp_msg_0_0.speed_units = 144U; + tmp_msg_0.speed.set(tmp_tmp_msg_0_0); + IMC::DesiredZ tmp_tmp_msg_0_1; + tmp_tmp_msg_0_1.value = 0.4857448602785186; + tmp_tmp_msg_0_1.z_units = 249U; + tmp_msg_0.z.set(tmp_tmp_msg_0_1); + tmp_msg_0.lat = 0.9642723409313487; + tmp_msg_0.lon = 0.06694108766709694; + tmp_msg_0.radius = 0.5291916095459962; + msg.reference.set(tmp_msg_0); + msg.state = 135U; + msg.proximity = 200U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowRefState #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowRefState msg; + msg.setTimeStamp(0.66364020664302); + msg.setSource(11982U); + msg.setSourceEntity(215U); + msg.setDestination(3690U); + msg.setDestinationEntity(80U); + msg.control_src = 54343U; + msg.control_ent = 203U; + IMC::Reference tmp_msg_0; + tmp_msg_0.flags = 139U; + IMC::DesiredSpeed tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.value = 0.1313367581601208; + tmp_tmp_msg_0_0.speed_units = 29U; + tmp_msg_0.speed.set(tmp_tmp_msg_0_0); + IMC::DesiredZ tmp_tmp_msg_0_1; + tmp_tmp_msg_0_1.value = 0.6168158849224055; + tmp_tmp_msg_0_1.z_units = 85U; + tmp_msg_0.z.set(tmp_tmp_msg_0_1); + tmp_msg_0.lat = 0.3831624000654099; + tmp_msg_0.lon = 0.12842833372435503; + tmp_msg_0.radius = 0.8304054917157843; + msg.reference.set(tmp_msg_0); + msg.state = 115U; + msg.proximity = 31U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowRefState #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationMonitor msg; + msg.setTimeStamp(0.7712855200360571); + msg.setSource(41048U); + msg.setSourceEntity(161U); + msg.setDestination(51454U); + msg.setDestinationEntity(197U); + msg.ax_cmd = 0.17288723207331635; + msg.ay_cmd = 0.929689574410976; + msg.az_cmd = 0.2494782885662582; + msg.ax_des = 0.9635924103702863; + msg.ay_des = 0.9809366796545589; + msg.az_des = 0.8087468239222143; + msg.virt_err_x = 0.08245563905980502; + msg.virt_err_y = 0.5875183425124263; + msg.virt_err_z = 0.2101889469288728; + msg.surf_fdbk_x = 0.8980438075897792; + msg.surf_fdbk_y = 0.15696776451945194; + msg.surf_fdbk_z = 0.8013128746080583; + msg.surf_unkn_x = 0.16566162813836127; + msg.surf_unkn_y = 0.5362811087977589; + msg.surf_unkn_z = 0.9843126063266912; + msg.ss_x = 0.6113275861818308; + msg.ss_y = 0.8958134951995164; + msg.ss_z = 0.8763904501469881; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationMonitor #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationMonitor msg; + msg.setTimeStamp(0.3008042139745394); + msg.setSource(28017U); + msg.setSourceEntity(254U); + msg.setDestination(58770U); + msg.setDestinationEntity(140U); + msg.ax_cmd = 0.16402394780957574; + msg.ay_cmd = 0.7769179429060873; + msg.az_cmd = 0.8341107082170185; + msg.ax_des = 0.20232049741168268; + msg.ay_des = 0.4741273251601683; + msg.az_des = 0.00984575361757034; + msg.virt_err_x = 0.2964075289898682; + msg.virt_err_y = 0.23549740771306582; + msg.virt_err_z = 0.5656060478685917; + msg.surf_fdbk_x = 0.6645778365331118; + msg.surf_fdbk_y = 0.9246015248764259; + msg.surf_fdbk_z = 0.470797053811579; + msg.surf_unkn_x = 0.6088593537796716; + msg.surf_unkn_y = 0.5907044572202054; + msg.surf_unkn_z = 0.20419543409853957; + msg.ss_x = 0.2969604796332713; + msg.ss_y = 0.2441198424663421; + msg.ss_z = 0.9227424286264588; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationMonitor #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FormationMonitor msg; + msg.setTimeStamp(0.47025305749077684); + msg.setSource(50328U); + msg.setSourceEntity(250U); + msg.setDestination(5049U); + msg.setDestinationEntity(30U); + msg.ax_cmd = 0.27033669939701066; + msg.ay_cmd = 0.934258163490123; + msg.az_cmd = 0.8099984729253408; + msg.ax_des = 0.27050704321967844; + msg.ay_des = 0.3708487298961548; + msg.az_des = 0.9911609073087837; + msg.virt_err_x = 0.00044104524137356105; + msg.virt_err_y = 0.8958327374002322; + msg.virt_err_z = 0.8143102604470215; + msg.surf_fdbk_x = 0.609744599990489; + msg.surf_fdbk_y = 0.16271265552941783; + msg.surf_fdbk_z = 0.1556163330580541; + msg.surf_unkn_x = 0.2996522863475556; + msg.surf_unkn_y = 0.8449263660036991; + msg.surf_unkn_z = 0.25599568989939514; + msg.ss_x = 0.4261064814522926; + msg.ss_y = 0.8411446907436214; + msg.ss_z = 0.13946787655090476; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FormationMonitor #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::RelativeState msg; + msg.setTimeStamp(0.03940508169877732); + msg.setSource(6399U); + msg.setSourceEntity(210U); + msg.setDestination(23232U); + msg.setDestinationEntity(91U); + msg.s_id.assign("KFSVIUFAWNCBFPWBIMAKTPAGJYIPAJBXMHMMFOIHLUZFINQFNQVKYLEICEGUGKJHBTOOXJODQOXAULFBJ"); + msg.dist = 0.8346928101055424; + msg.err = 0.2671452990318476; + msg.ctrl_imp = 0.9616537847862326; + msg.rel_dir_x = 0.15610749801612878; + msg.rel_dir_y = 0.6795597713510101; + msg.rel_dir_z = 0.130346491647214; + msg.err_x = 0.00962969863580354; + msg.err_y = 0.09355459539576827; + msg.err_z = 0.2739223666631567; + msg.rf_err_x = 0.34378806972413745; + msg.rf_err_y = 0.2950197193117281; + msg.rf_err_z = 0.957745181034868; + msg.rf_err_vx = 0.10165999383356739; + msg.rf_err_vy = 0.9123314483226483; + msg.rf_err_vz = 0.4813897676751715; + msg.ss_x = 0.5389742549889617; + msg.ss_y = 0.05555500111624967; + msg.ss_z = 0.939378280867693; + msg.virt_err_x = 0.02775271351131514; + msg.virt_err_y = 0.0484299036668524; + msg.virt_err_z = 0.70952039083627; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("RelativeState #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::RelativeState msg; + msg.setTimeStamp(0.07453769305319313); + msg.setSource(47722U); + msg.setSourceEntity(143U); + msg.setDestination(49889U); + msg.setDestinationEntity(101U); + msg.s_id.assign("CAIZZHMNABENHKAOZZJPLDKDQSMLFNWLFBTUDKGKJIXFPJIUUIJJOESBMDWEPVRPXWKPWYSZKOHBZUSQEZZCFKDGZUCEGNQCLCLYCNWWWUHBQSCAMBFHMQXWRATQDBYMMOHDUYHEAOJYSBXEVTHNIFYLHVCEQGSDSLKGVTRSOHSENNIVFTEPKXPYLYTJWDGRRRIJ"); + msg.dist = 0.6130810041205567; + msg.err = 0.5982329010385244; + msg.ctrl_imp = 0.25105934285380194; + msg.rel_dir_x = 0.6720768238939387; + msg.rel_dir_y = 0.45271927497001896; + msg.rel_dir_z = 0.36294691543445967; + msg.err_x = 0.240979240293143; + msg.err_y = 0.9759538287897621; + msg.err_z = 0.42254465486668513; + msg.rf_err_x = 0.8302764633216141; + msg.rf_err_y = 0.014165282534211343; + msg.rf_err_z = 0.26346655432584465; + msg.rf_err_vx = 0.126266289955122; + msg.rf_err_vy = 0.4795091141632086; + msg.rf_err_vz = 0.5231579999716373; + msg.ss_x = 0.9911281500101079; + msg.ss_y = 0.23860315142581912; + msg.ss_z = 0.8895403739834206; + msg.virt_err_x = 0.14702925962103142; + msg.virt_err_y = 0.35448714204613385; + msg.virt_err_z = 0.5173068449285103; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("RelativeState #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::RelativeState msg; + msg.setTimeStamp(0.0424640311527783); + msg.setSource(2627U); + msg.setSourceEntity(115U); + msg.setDestination(34036U); + msg.setDestinationEntity(130U); + msg.s_id.assign("MMFVJYTGYPKRZUMQBFSIXRKLMPSZCXGVMZHINYGEHTQSYUSNJYHLIVVGIQTRNOAOYCOKPSVEBXCWPLIFWHBSVGKELFSQMFUFDERXEKHRDFKOVXJEWHRCWBYSRBPDIHNGDQJZKFVZOBCDFENDAQ"); + msg.dist = 0.9581560761003207; + msg.err = 0.8226697358750906; + msg.ctrl_imp = 0.13148788430639657; + msg.rel_dir_x = 0.010156660365207348; + msg.rel_dir_y = 0.05733824280829258; + msg.rel_dir_z = 0.7111408266854305; + msg.err_x = 0.21754007309297696; + msg.err_y = 0.8301877132408452; + msg.err_z = 0.1460749083466355; + msg.rf_err_x = 0.7381763605780315; + msg.rf_err_y = 0.684241346901216; + msg.rf_err_z = 0.03553124255513873; + msg.rf_err_vx = 0.22013507369815133; + msg.rf_err_vy = 0.10146709690815126; + msg.rf_err_vz = 0.40336565312990824; + msg.ss_x = 0.959590474372605; + msg.ss_y = 0.34114313437735044; + msg.ss_z = 0.35245344034609905; + msg.virt_err_x = 0.6385076026571113; + msg.virt_err_y = 0.3708342606769053; + msg.virt_err_z = 0.23422574150986375; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("RelativeState #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Dislodge msg; + msg.setTimeStamp(0.6354892732110595); + msg.setSource(26022U); + msg.setSourceEntity(230U); + msg.setDestination(1520U); + msg.setDestinationEntity(73U); + msg.timeout = 53248U; + msg.rpm = 0.8138321287509556; + msg.direction = 109U; + msg.custom.assign("DWZFGGIAOBJIBCNVEQVBCWXIYYFMTPBVLAURXASOSFZVUJEQVPOPTFLOJBUMZQERYTKRFHRXJGZQQNSOKYIJCSJDZDLGNSQHTDLHBWULCXNXGGDAAWNARDMQYSXLXHJKECCOWMZUWCJNQDHZGENRUFWKYKFSWZNKSTSHPJXLANIFKBRYAPAXCROBILHTPYHRWZLGWHBVABPEHGVOMLQVQUEP"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Dislodge #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Dislodge msg; + msg.setTimeStamp(0.0018347494060736436); + msg.setSource(17743U); + msg.setSourceEntity(33U); + msg.setDestination(12789U); + msg.setDestinationEntity(239U); + msg.timeout = 29645U; + msg.rpm = 0.6041898113592462; + msg.direction = 146U; + msg.custom.assign("TXMYRNJHPBHYDQOLITSXNTNTJYVMBDSNNOBQBFVDZXOAEFDLSRLGABGNDPVSDJYFGCEVKIKUQDJHXIKEGRTBJMLRMCRUDLWZDUESPCSNZFQELOHKGXAUAEAGMWJBUVBTXXQUUQQPCPOKEW"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Dislodge #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Dislodge msg; + msg.setTimeStamp(0.5173762587026872); + msg.setSource(47677U); + msg.setSourceEntity(111U); + msg.setDestination(42558U); + msg.setDestinationEntity(227U); + msg.timeout = 38657U; + msg.rpm = 0.3251208230764463; + msg.direction = 190U; + msg.custom.assign("VQWEYSTHRLMQJXSQGNSCDLTWKSEMAHVGDYYJWEBCABFRNMWPFHSUABFWGBYHOSMPDOATHXTMOIKKDROV"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Dislodge #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Formation msg; + msg.setTimeStamp(0.41185228813561525); + msg.setSource(26905U); + msg.setSourceEntity(158U); + msg.setDestination(45250U); + msg.setDestinationEntity(111U); + msg.formation_name.assign("JPLDUSHRJQNGBAGMZPNMOZBKXLPUIOEJONDAQCCBMJTIRUSSPMWBNONTWMJHLTYXRWLDYSVWOYDNFTTZQMFELRYCOJYOPGNDVZAGVGEXFFHTEFBGJTGYWBYWHSDLSJWPRANNEWVXFEXKIQPGSLRDZTHQXEUCSXFCIKHUBLMYGVZUIGYUYRN"); + msg.type = 28U; + msg.op = 121U; + msg.group_name.assign("LCZBGVUHXKRSYDKIZNLXJTEISTCRFWOMPYYLAKUHZRTCBTBWYQFNQPDNWKGDBYUCSWFNLIRIAGXOOEKQCNLQQJXIUYTYIGPXZPVWZAFBESLVXJKPEYMKOEULOLITLNQ"); + msg.plan_id.assign("DVBWPXSYCUFURMKETVFNEHVRUZIWEHHRPYWAPZEOYFLZMSISXKVNTAKXGKOTXTBDOMRFJJZQDMKCCOTLJZZXVPSJERHNNZTVIRLOLFBRDXSOUSQQYUGFDBATZCJDFUIXHHKQMFDVWLHWYDQZOKHEEATCNJASGGPJBQDVBXGOJLLBHCPUU"); + msg.description.assign("ONNFCRGQIBXLDLGUIBKHDOCFKGPYAOLMNCMSNIWQVZVSSBQQGVEPVPSIATKMVZJRJSEPRHSDPGMAJSTXZRCMOKVLQFRDGWYGHCOTPLARPKXDFHMRXTDLZIWGZQBYDTXVMBHDYBBFOYCHYZSNCEMVIJUVTCTJQPOENHHJIAEGOXZUWOTNXEVYUZKJCUWYUUBOQ"); + msg.reference_frame = 77U; + IMC::VehicleFormationParticipant tmp_msg_0; + tmp_msg_0.vid = 41876U; + tmp_msg_0.off_x = 0.4462098335846265; + tmp_msg_0.off_y = 0.09781774959421485; + tmp_msg_0.off_z = 0.3264107536301053; + msg.participants.push_back(tmp_msg_0); + msg.leader_bank_lim = 0.8126991998218277; + msg.leader_speed_min = 0.12394376402196494; + msg.leader_speed_max = 0.6142371527343125; + msg.leader_alt_min = 0.9703355216248212; + msg.leader_alt_max = 0.7358681850615111; + msg.pos_sim_err_lim = 0.37371840842518855; + msg.pos_sim_err_wrn = 0.9695350810265844; + msg.pos_sim_err_timeout = 52915U; + msg.converg_max = 0.06761836841657376; + msg.converg_timeout = 43299U; + msg.comms_timeout = 56213U; + msg.turb_lim = 0.7752408680873735; + msg.custom.assign("QCYKGWOHUEMAPAEFZGHRBVIZLZOIBIIODMUWKSIBQXMIQKDKCRQSLNKGCPCTJBBLMHAJSDEXHHLPHVDCFOPIOMLTURFDFDZYEERLGREYUAUBMVTNQEOFTQGTSYCLABONVPVJOLZYPVYAHAUFZFNNJJSGNXCQWGTDXFFBWWDDJSWEPHPFCKQUTMUKVVEMZ"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Formation #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Formation msg; + msg.setTimeStamp(0.311614616692626); + msg.setSource(10562U); + msg.setSourceEntity(76U); + msg.setDestination(2870U); + msg.setDestinationEntity(22U); + msg.formation_name.assign("SXCMPUGYFWWNLKLYASGAORIPKLERLQMVFXLBJKRIOTZDUKTJMVJRHUOPLVUPBKDCKOAIZOPZCIWSTQGFESVBMPTQSDZYFWGDKTEWBDRVNDFXEYLATXJENSYDNYMCGAATETSJHJBRAHPFOUJEZQGAULDWTUJQXMUNXLCWMBCSUPBLSYOZNJMOGWXQIVWXVBHA"); + msg.type = 121U; + msg.op = 151U; + msg.group_name.assign("QHXDPWQDPFXOQQCZVYDTGULHVNMSKPNDYEKJUSAEKRMXEYWCAGKWENCLNYFIHZVJHYYJVMBWBQZBCHBVFIPXFWCWRREJQDLIMHREZJBTNOBATGCEGFVRPSJLHTTSSLMZLMVPUYBVFAAMCAYTNKGFFZOIKCMDOOOSSJAJUZWZXULWIHJXTLKMXEQXEQSGRIBKPNGXVCOWPTBNPA"); + msg.plan_id.assign("DIPWVKABERBYUOQWJJDKCPITYCQDUFZBSYMEGQLAJPLJGBAOSIGUEZGOZYUHNIFPUVPHOYWYXUJCFKAJRGTMMKWNTKTQZBIDEEQLVIGWPDQJMEJHZAMBDSXMBVDRCGGNSFTJZCYCXSANHXOZSAFX"); + msg.description.assign("CKATRXTPLXGAGDSCWIQGVJBHDNVKVCBSCHVKSZHWKLSMQVCEDDYPHJUMSNBMMYYKCYOTLRTFHPNSRIWAWPMPXBEGHOABWZEXTBRNROGAIJHDTLKOGULGFYXOFBMDQRIODW"); + msg.reference_frame = 223U; + IMC::VehicleFormationParticipant tmp_msg_0; + tmp_msg_0.vid = 8221U; + tmp_msg_0.off_x = 0.4573024972163763; + tmp_msg_0.off_y = 0.9298822296226588; + tmp_msg_0.off_z = 0.06421821315529819; + msg.participants.push_back(tmp_msg_0); + msg.leader_bank_lim = 0.69193426549253; + msg.leader_speed_min = 0.6327920526872534; + msg.leader_speed_max = 0.444738581280984; + msg.leader_alt_min = 0.05597869828944024; + msg.leader_alt_max = 0.4009348276630349; + msg.pos_sim_err_lim = 0.03666738353632759; + msg.pos_sim_err_wrn = 0.48762513008459907; + msg.pos_sim_err_timeout = 7342U; + msg.converg_max = 0.07786536956853285; + msg.converg_timeout = 61339U; + msg.comms_timeout = 8970U; + msg.turb_lim = 0.7535888199170098; + msg.custom.assign("CGDIBJKWMHQHZEMBZYQENRUWUCFNRKJWZQNJIDIQKQDXPUYYIBMMHNQZ"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Formation #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Formation msg; + msg.setTimeStamp(0.8905192543404069); + msg.setSource(59884U); + msg.setSourceEntity(253U); + msg.setDestination(58309U); + msg.setDestinationEntity(143U); + msg.formation_name.assign("XUFIRSEDTTT"); + msg.type = 20U; + msg.op = 250U; + msg.group_name.assign("XJIYULAXLIQFHVRSGMPOIKLRVLBEMEFTXJDAAREMGCJHKODSOVBRIICOTFYGTATPLKWXPF"); + msg.plan_id.assign("ELOTHTATOFJACMSBGBWCQA"); + msg.description.assign("AKDEYYADBAKRSFRCRGUVGNGKHQTMELQHHDMUHBMHYGWDEKWPJWJACEVRQUUZNUFWSOGUHHVISYQZACRXWCENSZLRITBPMLYCKVJKEEDPFSPGWWQWRVGNNZIGOYYCJJFEYVNTAMGFDLIJAJOSYMHQABOTMVCKMMPFAZYSINKXGZOXCHPKIEWDJLXMZXDRFZFUFQJCLWDBIXIXOHTTNLTRAPSVBPZSLCXQIIVJOSOT"); + msg.reference_frame = 124U; + msg.leader_bank_lim = 0.12015277565074511; + msg.leader_speed_min = 0.13808383860247386; + msg.leader_speed_max = 0.6404546342653095; + msg.leader_alt_min = 0.498324426675787; + msg.leader_alt_max = 0.40038424492168334; + msg.pos_sim_err_lim = 0.8714055124393105; + msg.pos_sim_err_wrn = 0.39887675935690026; + msg.pos_sim_err_timeout = 18516U; + msg.converg_max = 0.029056461593649052; + msg.converg_timeout = 53319U; + msg.comms_timeout = 26114U; + msg.turb_lim = 0.3477262930007109; + msg.custom.assign("RKNABOMTCIMERQLLBGBNWUDCMKNTTAWFSLGVDKVJYJOGUFDEHXGKMQXY"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Formation #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Launch msg; + msg.setTimeStamp(0.9329369553145829); + msg.setSource(38353U); + msg.setSourceEntity(86U); + msg.setDestination(13366U); + msg.setDestinationEntity(109U); + msg.timeout = 63361U; + msg.lat = 0.9743962894707909; + msg.lon = 0.5173953968701378; + msg.z = 0.5096626915726544; + msg.z_units = 173U; + msg.speed = 0.596185773525646; + msg.speed_units = 118U; + msg.custom.assign("UZFTZJGWWMSANKRBEEOEYDUOMTPNQYOCLRGXJWVMLKDJDLYUOVVHHCHNHZBUJGVRTYRDPGDVXDSOBFNNUISNLEWTPRAPYIMKSPBRPEEJCCBFIGMRZDINAYXOLOFFBHAWLSIKHCREBQDOKCUNVMOXMQUANHRWIPKIMVRSYBGVJCLKXUMALQTQFQFLMAIWCCIISAGDPZQCYKSJXOXPTW"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Launch #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Launch msg; + msg.setTimeStamp(0.6346501007552984); + msg.setSource(39036U); + msg.setSourceEntity(42U); + msg.setDestination(33238U); + msg.setDestinationEntity(6U); + msg.timeout = 25933U; + msg.lat = 0.3388043019589867; + msg.lon = 0.20182428944475483; + msg.z = 0.6888224486468998; + msg.z_units = 169U; + msg.speed = 0.48590384921445584; + msg.speed_units = 97U; + msg.custom.assign("TRJZFJAJOVCPSPEJTNCXEILWPIMNCSBDMKIGBOBLFRBWOQHNRJTKFQALRQGSVZSXQOTVEORPWMZUDOJFUHIFUDVHCANYPHCSRBXMEHJKNKEFYYFRCDYYDGBJUQTGENZVXRWYTBUZZVTRUHKUUGOWAXGCDQNPPTLMEHKCQZCFIYHACNKAANTVYSXHGDSYDVWIJXLIQWUMGLUHK"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Launch #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Launch msg; + msg.setTimeStamp(0.7065245119250558); + msg.setSource(8543U); + msg.setSourceEntity(248U); + msg.setDestination(51023U); + msg.setDestinationEntity(200U); + msg.timeout = 65405U; + msg.lat = 0.5925310388501684; + msg.lon = 0.6422154411923967; + msg.z = 0.8907292863404903; + msg.z_units = 24U; + msg.speed = 0.5797372864664457; + msg.speed_units = 174U; + msg.custom.assign("FQNIBMOWGEFTGYDJOCOFGJKHPEDBXGFSQVSMKEBKITGCUZSHJLXPUQDCIZZNVYRJIAUEMBEAZXRCHROBONARPMIWFLZJSLQDVKEINGWKZDAXCEQGONSNXRQVZXORUCWAFXPTRRVWHGWLAAFSGIXRVTTIMVJH"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Launch #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Drop msg; + msg.setTimeStamp(0.7766274023132042); + msg.setSource(4267U); + msg.setSourceEntity(241U); + msg.setDestination(8177U); + msg.setDestinationEntity(155U); + msg.timeout = 54530U; + msg.lat = 0.23635050039238104; + msg.lon = 0.8925322244180833; + msg.z = 0.07604761208089106; + msg.z_units = 31U; + msg.speed = 0.371096573047887; + msg.speed_units = 182U; + msg.custom.assign("TRFCTWLNIIHWHTVWVHUTBYJSWRYVURJXXPEOMLJAXDGYPAECOBNLAVCMJTTNIHTJAWGFIYCXRLMAUBQEVGCXOECSNNFDUYNHRQXICXMMVWJSTPIUTFJUMNOVFKSHAOFOZILEYOEXPPWKKYBQ"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Drop #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Drop msg; + msg.setTimeStamp(0.965476492730401); + msg.setSource(59711U); + msg.setSourceEntity(221U); + msg.setDestination(34942U); + msg.setDestinationEntity(217U); + msg.timeout = 7565U; + msg.lat = 0.21297044436515677; + msg.lon = 0.8155493839586212; + msg.z = 0.5071849956430674; + msg.z_units = 153U; + msg.speed = 0.19644587767788535; + msg.speed_units = 199U; + msg.custom.assign("EJSPIDPBFVXDOHEIIFYVWOKUEZOYHAMKNGEBCKMGASCDBCWVUQJKTAC"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Drop #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Drop msg; + msg.setTimeStamp(0.6341576876353943); + msg.setSource(56402U); + msg.setSourceEntity(220U); + msg.setDestination(28887U); + msg.setDestinationEntity(111U); + msg.timeout = 7528U; + msg.lat = 0.6388813523901069; + msg.lon = 0.5206446372266947; + msg.z = 0.9094973580873756; + msg.z_units = 157U; + msg.speed = 0.9748568819810481; + msg.speed_units = 88U; + msg.custom.assign("BYNNTDJXUWKFQLJFRUOOJVEMDADGOPTVBOMKKLCQTNQELLTEHADHWODQPISYCHPKWYIKBSSIWBUEHNBLRZJXZMGPXAWQQDXSJSZOICYCWPVGRQSTENTXFRJVGALPJFXOIEDLFSBYZWMZHWXQMXYTKCVURKTHFTNQJBKOEBYSTUGNUU"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Drop #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::ScheduledGoto msg; + msg.setTimeStamp(0.751739950680939); + msg.setSource(5725U); + msg.setSourceEntity(138U); + msg.setDestination(57502U); + msg.setDestinationEntity(154U); + msg.arrival_time = 0.46797192706440083; + msg.lat = 0.4161925619974025; + msg.lon = 0.3974639562717296; + msg.z = 0.846353689217134; + msg.z_units = 130U; + msg.travel_z = 0.46328176215005445; + msg.travel_z_units = 232U; + msg.delayed = 185U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("ScheduledGoto #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::ScheduledGoto msg; + msg.setTimeStamp(0.905948189407995); + msg.setSource(42942U); + msg.setSourceEntity(188U); + msg.setDestination(20242U); + msg.setDestinationEntity(133U); + msg.arrival_time = 0.46788778464760095; + msg.lat = 0.6813032485452565; + msg.lon = 0.6012299889864594; + msg.z = 0.47443166273132575; + msg.z_units = 163U; + msg.travel_z = 0.9687513328734288; + msg.travel_z_units = 236U; + msg.delayed = 220U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("ScheduledGoto #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::ScheduledGoto msg; + msg.setTimeStamp(0.24955340351946997); + msg.setSource(37775U); + msg.setSourceEntity(137U); + msg.setDestination(28381U); + msg.setDestinationEntity(248U); + msg.arrival_time = 0.3751454816213926; + msg.lat = 0.22182204510213055; + msg.lon = 0.9214506492321197; + msg.z = 0.9144364704856476; + msg.z_units = 16U; + msg.travel_z = 0.6836405402530776; + msg.travel_z_units = 6U; + msg.delayed = 151U; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("ScheduledGoto #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::RowsCoverage msg; + msg.setTimeStamp(0.5363894464145627); + msg.setSource(41362U); + msg.setSourceEntity(16U); + msg.setDestination(22999U); + msg.setDestinationEntity(250U); + msg.lat = 0.7487747736230703; + msg.lon = 0.6625406854782033; + msg.z = 0.022721796990016974; + msg.z_units = 68U; + msg.speed = 0.2153156592924942; + msg.speed_units = 253U; + msg.bearing = 0.1263120098272722; + msg.cross_angle = 0.3115557173576109; + msg.width = 0.3279541348053221; + msg.length = 0.1166279706569533; + msg.coff = 133U; + msg.angaperture = 0.2921178881720098; + msg.range = 50344U; + msg.overlap = 126U; + msg.flags = 56U; + msg.custom.assign("HJNPUGXZJMWHDZDAQVXNJLGQADJMYDYIUXPB"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("RowsCoverage #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::RowsCoverage msg; + msg.setTimeStamp(0.3361380271112695); + msg.setSource(45350U); + msg.setSourceEntity(118U); + msg.setDestination(39090U); + msg.setDestinationEntity(202U); + msg.lat = 0.7646955117824791; + msg.lon = 0.162733571866587; + msg.z = 0.7857397817297243; + msg.z_units = 187U; + msg.speed = 0.9824208639370493; + msg.speed_units = 33U; + msg.bearing = 0.7274743615238827; + msg.cross_angle = 0.7600813022288663; + msg.width = 0.9181739065796516; + msg.length = 0.9966134407386781; + msg.coff = 252U; + msg.angaperture = 0.42565306935796077; + msg.range = 46732U; + msg.overlap = 184U; + msg.flags = 209U; + msg.custom.assign("ISYPXZQBAJWKOMPGBVKUNRUBOMDHZAQPWEUVDTKPMCBQGQCHINLZFGNWFRAOYZJVRSHLWLVYOSEQBSAIULRDZKCTGGKKVMXPWVNUTFXPWRCDYIYNOECAGGLLQIVXGHIYWMMSDCSJWZUMWEDTJTEIVBK"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("RowsCoverage #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::RowsCoverage msg; + msg.setTimeStamp(0.03135801938348626); + msg.setSource(21670U); + msg.setSourceEntity(132U); + msg.setDestination(50092U); + msg.setDestinationEntity(106U); + msg.lat = 0.13496618968741525; + msg.lon = 0.48236570666122025; + msg.z = 0.1966989678541029; + msg.z_units = 205U; + msg.speed = 0.3409834429608892; + msg.speed_units = 191U; + msg.bearing = 0.13668189913218076; + msg.cross_angle = 0.1039615369587158; + msg.width = 0.08755731888944185; + msg.length = 0.6853203207245592; + msg.coff = 100U; + msg.angaperture = 0.13162505256879597; + msg.range = 40753U; + msg.overlap = 232U; + msg.flags = 104U; + msg.custom.assign("LCFYKGOKPL"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("RowsCoverage #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Sample msg; + msg.setTimeStamp(0.5010103378942462); + msg.setSource(38181U); + msg.setSourceEntity(177U); + msg.setDestination(18708U); + msg.setDestinationEntity(204U); + msg.timeout = 15360U; + msg.lat = 0.4168163338025265; + msg.lon = 0.31699218660115813; + msg.z = 0.1686894685850331; + msg.z_units = 77U; + msg.speed = 0.6382253208712317; + msg.speed_units = 63U; + msg.syringe0 = 124U; + msg.syringe1 = 103U; + msg.syringe2 = 181U; + msg.custom.assign("PGZGULWLQCCHWLDRGCQSCBWYCQUQE"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Sample #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Sample msg; + msg.setTimeStamp(0.4985627618819698); + msg.setSource(4635U); + msg.setSourceEntity(131U); + msg.setDestination(58776U); + msg.setDestinationEntity(238U); + msg.timeout = 26747U; + msg.lat = 0.909853159956721; + msg.lon = 0.2193898714707343; + msg.z = 0.22797231019736552; + msg.z_units = 244U; + msg.speed = 0.4458464456075364; + msg.speed_units = 11U; + msg.syringe0 = 132U; + msg.syringe1 = 96U; + msg.syringe2 = 147U; + msg.custom.assign("FTIEZFCMJFNHGNHJLZQPFZDNCAMHBYCVOOGUWIVVIXRASBRKDFVQKQGXNMHGWMCCQJYRUWCUMIXAIGDRBTXWXAKTJDPARWVTXKUOJYETPPCILSDEPZUVOSQJGUSTWOJSZSLLBIYQSWHPELWQSHZCQFBBZAAESSZDERKIPFYDLOIEKXPCFJMHEURBNYGMLURHNDOVNLAITHVGWNYXNK"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Sample #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Sample msg; + msg.setTimeStamp(0.36283241955268486); + msg.setSource(42989U); + msg.setSourceEntity(47U); + msg.setDestination(47616U); + msg.setDestinationEntity(251U); + msg.timeout = 41737U; + msg.lat = 0.3005563355241542; + msg.lon = 0.8387940006999689; + msg.z = 0.9082443279298217; + msg.z_units = 41U; + msg.speed = 0.48536463719640943; + msg.speed_units = 211U; + msg.syringe0 = 205U; + msg.syringe1 = 132U; + msg.syringe2 = 233U; + msg.custom.assign("PMXMVPSJUFALVVLCTOGGHVJIKKCTZRASULLMUBRNZMKGYXOZWAXMGBKXAIUI"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Sample #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::ImageTracking msg; + msg.setTimeStamp(0.9707018036581293); + msg.setSource(24681U); + msg.setSourceEntity(1U); + msg.setDestination(15951U); + msg.setDestinationEntity(122U); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("ImageTracking #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::ImageTracking msg; + msg.setTimeStamp(0.40265149525026367); + msg.setSource(56097U); + msg.setSourceEntity(185U); + msg.setDestination(8674U); + msg.setDestinationEntity(29U); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("ImageTracking #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::ImageTracking msg; + msg.setTimeStamp(0.088563931010465); + msg.setSource(30391U); + msg.setSourceEntity(54U); + msg.setDestination(4248U); + msg.setDestinationEntity(131U); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("ImageTracking #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Takeoff msg; + msg.setTimeStamp(0.4165247326807888); + msg.setSource(31652U); + msg.setSourceEntity(47U); + msg.setDestination(55034U); + msg.setDestinationEntity(214U); + msg.lat = 0.8497386205171548; + msg.lon = 0.7019083012237274; + msg.z = 0.962280123639115; + msg.z_units = 71U; + msg.speed = 0.825975853359857; + msg.speed_units = 156U; + msg.takeoff_pitch = 0.2451556134294387; + msg.custom.assign("TZXGPFZCMKSCWWZHMIQBWTRWBGOXUVOHVNSPCCKXJMKRIEIPLSEAOAKFPRBENRNYOMVFTEUZDKBLEWDHMMMUJPVUVIITMJDQHNQSQGEGUXUDZJWAITRJWXNAJACUOPATFPRHPXGHONBUKLZGVTKDXDZKBBMESJOGOPSCHWHILADQATFUCCESBYLWNRVEDY"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Takeoff #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Takeoff msg; + msg.setTimeStamp(0.5259237791314866); + msg.setSource(12281U); + msg.setSourceEntity(121U); + msg.setDestination(58602U); + msg.setDestinationEntity(164U); + msg.lat = 0.9761958375438667; + msg.lon = 0.6639573004639227; + msg.z = 0.03453814568832181; + msg.z_units = 148U; + msg.speed = 0.22928657715315137; + msg.speed_units = 69U; + msg.takeoff_pitch = 0.8250540190190359; + msg.custom.assign("DKMUNCJRWSTPHUSUWBUHFQZQZPZEMQLDZHERKLWOMKAWRAKGXTWEFGEBEVVLEMBMTRJRMPAQKNSOAQOUECIQBCHNUFDXFWMYDBWVXHJIIDIVCXTFRTWXIRLEACAGKPFJROHVZJQIJXSYDSEPPAQGYIQPTYSRGHVUCBGBHPOHKFMYXJHLNJSSCOGTANZIFMLTWWJLOKTFICGNOCNUTLPSYPEXOIUVYBLOZVSZUVDNACVZDQJRYBZBDGK"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Takeoff #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Takeoff msg; + msg.setTimeStamp(0.30180765834860823); + msg.setSource(55630U); + msg.setSourceEntity(6U); + msg.setDestination(36397U); + msg.setDestinationEntity(207U); + msg.lat = 0.5123113510693047; + msg.lon = 0.1924350042684685; + msg.z = 0.8152793869865422; + msg.z_units = 225U; + msg.speed = 0.4783009466942668; + msg.speed_units = 239U; + msg.takeoff_pitch = 0.9577359461339848; + msg.custom.assign("DSCTXAGWEFMILPAFJ"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Takeoff #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Land msg; + msg.setTimeStamp(0.3547421519747418); + msg.setSource(58964U); + msg.setSourceEntity(141U); + msg.setDestination(43100U); + msg.setDestinationEntity(132U); + msg.lat = 0.36473896651832605; + msg.lon = 0.17561523743781782; + msg.z = 0.8040175848220273; + msg.z_units = 220U; + msg.speed = 0.09253692369797073; + msg.speed_units = 173U; + msg.abort_z = 0.3889115888310467; + msg.bearing = 0.12891365594919768; + msg.glide_slope = 235U; + msg.glide_slope_alt = 0.11723377836442794; + msg.custom.assign("CEXTYCYJIPZPHQRLRUOSIBKGIHANFNSSLOVMKIOMWXWNNVDQCYMXTJXNLOUAKIJNJRQYNJMFTEKWIBFQJBMEKGHRYBVPQFSUJWAFOMMBRPCHPXWZTRNMLCXRALHIDDUESSRZMHRVMDXDJAIGYPOLPSFYXZYCEHHQUVFIUWISGYHHKQVRGUJGEVDQXWKNTDYALKZWGZELZPSUTG"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Land #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Land msg; + msg.setTimeStamp(0.6238212256584367); + msg.setSource(56655U); + msg.setSourceEntity(114U); + msg.setDestination(47945U); + msg.setDestinationEntity(201U); + msg.lat = 0.5102273446399366; + msg.lon = 0.8115510148835025; + msg.z = 0.9029731528020182; + msg.z_units = 152U; + msg.speed = 0.1970138532847574; + msg.speed_units = 88U; + msg.abort_z = 0.02635792121502034; + msg.bearing = 0.9698760010267136; + msg.glide_slope = 14U; + msg.glide_slope_alt = 0.32527661751844306; + msg.custom.assign("DPBNKJDRIJAFCETEUNMASMSHJCRKXGGOECMLXGJZEYNJHLZRGWOQDRCBWQVRKEVNZYMPFTIXWJHRUALYICFKWWAPJLDOADPVKPBGNEWNKHBNDFGFUMVDXVLITZTXYGHYRTFUHELDSSGETBIDXTSEMXHUPCQPQBLFCFSBWXICCAPTVWZVQIOKVIE"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Land #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Land msg; + msg.setTimeStamp(0.5087120798907686); + msg.setSource(23773U); + msg.setSourceEntity(1U); + msg.setDestination(46827U); + msg.setDestinationEntity(21U); + msg.lat = 0.006160837349811543; + msg.lon = 0.3234342745564064; + msg.z = 0.4580429958945752; + msg.z_units = 176U; + msg.speed = 0.47804835124466905; + msg.speed_units = 9U; + msg.abort_z = 0.9097534271278765; + msg.bearing = 0.8524543536524039; + msg.glide_slope = 250U; + msg.glide_slope_alt = 0.07950858198766941; + msg.custom.assign("YICXUBPFVGZZOCNEXTDMKENYPMTYLUAAHUTKJUOGWSILACGAIODBUVDKNJQIUQBXYDXDSBZDUKGYYXNNLRQEIBXHJZGTKOHEN"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Land #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::AutonomousSection msg; + msg.setTimeStamp(0.7359853077690667); + msg.setSource(40512U); + msg.setSourceEntity(253U); + msg.setDestination(9936U); + msg.setDestinationEntity(249U); + msg.lat = 0.43856854673946066; + msg.lon = 0.6481747506604872; + msg.speed = 0.4909681890343124; + msg.speed_units = 21U; + msg.limits = 101U; + msg.max_depth = 0.42627779068598437; + msg.min_alt = 0.7367291452465724; + msg.time_limit = 0.15710850487149963; + IMC::PolygonVertex tmp_msg_0; + tmp_msg_0.lat = 0.9908677439561095; + tmp_msg_0.lon = 0.41226217401911525; + msg.area_limits.push_back(tmp_msg_0); + msg.controller.assign("RRHIQVTPQVJXFISZOJZBQMAFHXMGAYQZGZIENLTUIVGWPNURY"); + msg.custom.assign("UNULYSUQZVKRYZALAXCROLWJPWZFBFKPTRTLKUVYDJPJQKEVFFPXSVYLZEVTWEELAXPGACJPXQJMQWFYOWNIJGCFPNQGOBWXLGEGSJGSYIQUINACMZLJHTMVQLDNTEXFSSIHERHIBIZPVKUMXZOZ"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("AutonomousSection #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::AutonomousSection msg; + msg.setTimeStamp(0.0070881849610938685); + msg.setSource(63496U); + msg.setSourceEntity(94U); + msg.setDestination(25596U); + msg.setDestinationEntity(175U); + msg.lat = 0.07974515108986702; + msg.lon = 0.6371621395914432; + msg.speed = 0.7674095410138451; + msg.speed_units = 101U; + msg.limits = 35U; + msg.max_depth = 0.9168384458002209; + msg.min_alt = 0.2857527552899244; + msg.time_limit = 0.01335796970520553; + IMC::PolygonVertex tmp_msg_0; + tmp_msg_0.lat = 0.20700484812636455; + tmp_msg_0.lon = 0.8786290753965581; + msg.area_limits.push_back(tmp_msg_0); + msg.controller.assign("DEEBUOVBNVPEFOAZTQPZNTYBQKJSSWZYFKIVADVOGXQECJKMGHBDIAKWJLTRCDHUVPIGHUOHWORWBVNJVCXPJCFBVDFJYMHLHCAQGMQWUUMEYGCXTFZELBAXKSSKSLXYNZFAGWEPLNTZFYYEXHCMRQPLOIIW"); + msg.custom.assign("ZOSFKPMFNUMCQFQGADWKBIGYFNRNIXOHQVEDXNLTTBSTSJGPUZUMTKNMPLAYPXVQQTQXZWDXODLMSOSMHWTYLEDKCCKYVHHECGGGFTPRWJKJJOUUJXZNIRBCGOSKSAVAHXIVAGYZPWPDADEYPEISBBDNFLULWMWXCQWRLOBXJJWBURUSPXJYK"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("AutonomousSection #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::AutonomousSection msg; + msg.setTimeStamp(0.6973179816179287); + msg.setSource(50931U); + msg.setSourceEntity(169U); + msg.setDestination(40882U); + msg.setDestinationEntity(48U); + msg.lat = 0.3363610143976955; + msg.lon = 0.5129592247291345; + msg.speed = 0.6036301773757702; + msg.speed_units = 61U; + msg.limits = 179U; + msg.max_depth = 0.9590953527630126; + msg.min_alt = 0.15273378299248797; + msg.time_limit = 0.6777607559626254; + IMC::PolygonVertex tmp_msg_0; + tmp_msg_0.lat = 0.04793222482688719; + tmp_msg_0.lon = 0.6604069210267964; + msg.area_limits.push_back(tmp_msg_0); + msg.controller.assign("UEYFIYNBKUMYWQJPIAJAYNLULHUCGJBPUOT"); + msg.custom.assign("NCVFSJGCSLPANSXUDYOFYZFHNMMJCMITYSRDGWZDEOKLOYCWTEVURRDMVQZJMBJBTKPYPYLHXGLULZVPPXSKQCOEFOKGSJFTUDKQIAVVFNEKJIGVYHDUGMNOEQZQJBFIAHIXKECMUODOSPKMANGGQNXDPXUAIZOQPEVRNHHD"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("AutonomousSection #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowPoint msg; + msg.setTimeStamp(0.24886057030182684); + msg.setSource(32415U); + msg.setSourceEntity(219U); + msg.setDestination(29552U); + msg.setDestinationEntity(121U); + msg.target.assign("XSLRTQYTXLGFCNWCDLVTJSTMXAIZ"); + msg.max_speed = 0.8838458498836826; + msg.speed_units = 153U; + msg.lat = 0.480846845652373; + msg.lon = 0.9225445109366713; + msg.z = 0.4314143165349963; + msg.z_units = 12U; + msg.custom.assign("OZUBFYLPNIELFEGOHTDKMGWCNETJSNLIKGXINRVCSVQJIMZYQWFIDSMMRFGSNLXAMTTSMCZIOORKEPVIMPAMWIDIYOHAFWTPDGRZGUPICLUTVEFQRSJFOCJRXSUJEFHXZAXULRMTPGVSQXNHJCDLWEXFTTOWRWTWBYK"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowPoint #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowPoint msg; + msg.setTimeStamp(0.8121624619357954); + msg.setSource(62859U); + msg.setSourceEntity(130U); + msg.setDestination(10772U); + msg.setDestinationEntity(212U); + msg.target.assign("RMBQTLTQLDEV"); + msg.max_speed = 0.12192330179820088; + msg.speed_units = 100U; + msg.lat = 0.3935682038659245; + msg.lon = 0.3662669772761846; + msg.z = 0.15142699638258783; + msg.z_units = 52U; + msg.custom.assign("EEXTERRNHIFEIHCKUQBXOCCHJBOUNCMPFIWMMRYRTKBSBNWNSHCFJAUEYNSMOGLMBNCIKIVIAXJJELPYOKIOUDGZWXTOZFPYTALHTRCVGEDPKZWUIOBCEBCIZLVQFHLVJQQEAJYZZJNIKLRCQVDGSOGNHOAQLAJLYUQGXVMPGWDUNPSGASJVDHDADZAYTDXGYFRKBTMPMKQKM"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowPoint #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::FollowPoint msg; + msg.setTimeStamp(0.5995048969924468); + msg.setSource(18206U); + msg.setSourceEntity(208U); + msg.setDestination(51678U); + msg.setDestinationEntity(83U); + msg.target.assign("JLJJKDPPZRDVBUMZZOSVFZHIWQUQDOICUTSHVGYRXWAVQRNZIPMFPAMKOJUDLDOJDLQTIWTOUQRZRQ"); + msg.max_speed = 0.2339705822624305; + msg.speed_units = 21U; + msg.lat = 0.5302454707236798; + msg.lon = 0.42621299646740285; + msg.z = 0.24761651056002476; + msg.z_units = 123U; + msg.custom.assign("FUWZGPDPPGGDSNZUJBRYYWALQMGABCZKSZDXXHDFIZSUAVHIZRUJWVAYFKGEDFDCGSTHEGVMTXAXIHCOYRXLQAWXHPVKIYVELJQOTYOTRBNMNLLBCYXTDROSQNZMJPUETBWJALZSFZOUCKIMNSFFNPQNQXIKEMETMJVCLGRFAJUOHOOMBXTCEERDDN"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("FollowPoint #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Alignment msg; + msg.setTimeStamp(0.3280208854533786); + msg.setSource(60752U); + msg.setSourceEntity(137U); + msg.setDestination(36575U); + msg.setDestinationEntity(183U); + msg.timeout = 9856U; + msg.lat = 0.6530386578567201; + msg.lon = 0.7647127619007041; + msg.speed = 0.5230988089679387; + msg.speed_units = 74U; + msg.custom.assign("HIJGWJCHLCGHJEFNUUUZCCLRNKMRVHSTKXAUBBAANYBGDJVPTXIVQXIUBIWFBGXFDQRZMMMESHEOXHYTODTRFTDYBEWVMGWKDVIAJOIPBDPWUJNCIIGMMLVZAWNNACECLTXJTKKNPQDQOZFHTJQPRRWPJFUPSPGFRLMZGQSZOZYYSCWQYDZJNOFQUAXREIAYXOYLHDSBKIVAMKCQTLWVCRRLS"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Alignment #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Alignment msg; + msg.setTimeStamp(0.09920751307400344); + msg.setSource(44687U); + msg.setSourceEntity(33U); + msg.setDestination(26367U); + msg.setDestinationEntity(225U); + msg.timeout = 65001U; + msg.lat = 0.9799210339851169; + msg.lon = 0.16746821500423925; + msg.speed = 0.13268345066242215; + msg.speed_units = 73U; + msg.custom.assign("KILGZQATNSRYTIEIXDNHGANQSKEUZCAXPYBGMVVIHXITOOOPDHSJTQWLBVLNXWJVJMOHOWFGJAOSICRCFBAHRPCDWYLXKGQPBXXPFJJSEYDYGINZTXFSLPEUNOXMIKZDIUVBPRHRZGDMHEVWNUZXJUQAUSBMWLRGBVUAOEHZQCAOVVKBTZHKKWJYEDCGADC"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Alignment #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::Alignment msg; + msg.setTimeStamp(0.2929588547471056); + msg.setSource(23300U); + msg.setSourceEntity(164U); + msg.setDestination(30748U); + msg.setDestinationEntity(71U); + msg.timeout = 9774U; + msg.lat = 0.23279200626150398; + msg.lon = 0.43813585079334627; + msg.speed = 0.07218227563251334; + msg.speed_units = 167U; + msg.custom.assign("UTWDPFQPDTOXHYDIYMUDIEDCFOWEIKHBRSRCCYLXFTDIADXZZYIHXBKGNTPICUQWNQMLBFMHJEPYJYRFKIHSCLVTQJGKHKTHVBILGFOHUEZZYMPNWPUBENZSIEXTNABJIWQQBWEMZMOLQBKEAJNMKYOMWKUJAVXDANJRUXCHZLHGVVDMK"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("Alignment #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::StationKeepingExtended msg; + msg.setTimeStamp(0.32910059474393927); + msg.setSource(44986U); + msg.setSourceEntity(28U); + msg.setDestination(37921U); + msg.setDestinationEntity(164U); + msg.lat = 0.4128670094861939; + msg.lon = 0.107998145214388; + msg.z = 0.7767463112577598; + msg.z_units = 165U; + msg.radius = 0.06199593668523462; + msg.duration = 36094U; + msg.speed = 0.5655331375632644; + msg.speed_units = 89U; + msg.popup_period = 1611U; + msg.popup_duration = 28688U; + msg.flags = 133U; + msg.custom.assign("IQCECGZZGBURXVFYDULWDOJSEVEAQRYRKERWUCYSBHAISRENFIUROMTOSYTVOFAPSDVPHHXMOIXAJTTNJZGYYMMZAGAFQVRWPUKWRKCVLVMFNKZTIGZEIULJMWEFLHSAZTMDYCXHQOBXNIPUUBRJC"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("StationKeepingExtended #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::StationKeepingExtended msg; + msg.setTimeStamp(0.22572676092976107); + msg.setSource(33547U); + msg.setSourceEntity(35U); + msg.setDestination(26714U); + msg.setDestinationEntity(157U); + msg.lat = 0.21214925049639088; + msg.lon = 0.06132028235215514; + msg.z = 0.7863920488963632; + msg.z_units = 11U; + msg.radius = 0.16585365613567893; + msg.duration = 24715U; + msg.speed = 0.49905264112206127; + msg.speed_units = 11U; + msg.popup_period = 35692U; + msg.popup_duration = 44216U; + msg.flags = 66U; + msg.custom.assign("ZZISCZCQXKIYDXOSXBHRKWGBMONBLINSRYGGHVNHPFHEJEJXISAYFXEJTLOPWCU"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationParameters #2", msg == *msg_d); + test.boolean("StationKeepingExtended #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::StationKeepingExtended msg; + msg.setTimeStamp(0.0687278750277951); + msg.setSource(41635U); + msg.setSourceEntity(111U); + msg.setDestination(37333U); + msg.setDestinationEntity(28U); + msg.lat = 0.16662948132534217; + msg.lon = 0.6931244628712232; + msg.z = 0.8647237427069427; + msg.z_units = 1U; + msg.radius = 0.847992702882808; + msg.duration = 11387U; + msg.speed = 0.4343524656683194; + msg.speed_units = 143U; + msg.popup_period = 47864U; + msg.popup_duration = 51938U; + msg.flags = 190U; + msg.custom.assign("XALJZIQQHNPWSVDFNQIZYUFSFTJRALJDEMSNHACPRLVLMHWDGKRUTGSJQPKHMGIGVBEHXKXEEPLHZPAXTCUTYRKSZXBMPQZUOZWEOHFYFAAWEUMNHXSARWJVIMGMVVXNSVWNBICOXNPDIYPTWOMXJQNAEBGWOBUPGQEZTHGVIAJJUYLLCTYIMYQZO"); + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("StationKeepingExtended #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -14971,33 +17844,19 @@ main(void) } { - IMC::FormationPlanExecution msg; - msg.setTimeStamp(0.1212706045); - msg.setSource(40232U); - msg.setSourceEntity(23U); - msg.setDestination(30803U); - msg.setDestinationEntity(226U); - msg.group_name.assign("OJFEFPZSHJOUPPEBESOHAXZX"); - msg.formation_name.assign("WYWFPGCVPTPORELSTZKONLMMVNJVHRYWYQWYLUXSOLBTQGGPAABGVISHCOCUFVARXYIWEPTAQLRESRHNBAZXWSEUAFHVMGEURKKGZEGSDPDFTYVKNJRFF"); - msg.plan_id.assign("QYJKFABTELWDWQLRWRWTPUMYUXSVRYNLEAHHPCHHCVWJYCECZDXBZWTLKDTBHIRGLOHFGCUTCEGJHBXLWKVOCYHFCNQOKU"); - msg.description.assign("YRGSLUTXZXKGLHJITDBBIRGJPLXPOXAXNFJEIWTHHCJOPVQNUWVREXIDHUCYYYFNOPKNOEKFGZNGLIOJCMJEDNJBLZFMA"); - msg.leader_speed = 0.318988591438; - msg.leader_bank_lim = 0.896750845779; - msg.pos_sim_err_lim = 0.855331861448; - msg.pos_sim_err_wrn = 0.166662923775; - msg.pos_sim_err_timeout = 37520U; - msg.converg_max = 0.450082745894; - msg.converg_timeout = 51741U; - msg.comms_timeout = 53914U; - msg.turb_lim = 0.0611888191091; - msg.custom.assign("XRHOGHADJBCCHJUVWZNVQUKTYHEBAKAZVSUEQAPWXPXQDIPQEJJLVUKDYSSVDZBFFIUOENTPSLTEQVKDYCKSLKWWBPO"); + IMC::ManeuverDone msg; + msg.setTimeStamp(0.08210201968451358); + msg.setSource(28590U); + msg.setSourceEntity(170U); + msg.setDestination(20707U); + msg.setDestinationEntity(149U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationPlanExecution #0", msg == *msg_d); + test.boolean("ManeuverDone #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15008,33 +17867,19 @@ main(void) } { - IMC::FormationPlanExecution msg; - msg.setTimeStamp(0.844365204509); - msg.setSource(32869U); - msg.setSourceEntity(253U); - msg.setDestination(10043U); + IMC::ManeuverDone msg; + msg.setTimeStamp(0.9774008183632936); + msg.setSource(25710U); + msg.setSourceEntity(68U); + msg.setDestination(4261U); msg.setDestinationEntity(179U); - msg.group_name.assign("FKJBULPCMISKGMSXAOHJRFWYBVAYHDKQQMGILUGCRNTFWOKBDZFIMLPOZWP"); - msg.formation_name.assign("RHEHZZXPIEUGWFJPJ"); - msg.plan_id.assign("CFKGPREBEWAJXWQFZIWDXUCCAJJHVPSDGSAJYBRSATIURFLMKGWYPCMURDTTNOBNUEUMTEMBODVTIINDGOCMYHKGAQTVVLFBUWPRJAWMXDZWLHHXZOXQZJTYSDQQQXSEOIJNMNLLHURSAGKXWGKYKHVSWZNEGMUKAYLEVPRHEOKZBTRZHTDQBZAZIYYHAWNEPVPXOUOLQSXFPBHFBMM"); - msg.description.assign("YGWEAHRISDQJNGFZBUSKSDKFLJTWTPLDEOIIKXISCGSHCY"); - msg.leader_speed = 0.470672408115; - msg.leader_bank_lim = 0.239287162207; - msg.pos_sim_err_lim = 0.589711903485; - msg.pos_sim_err_wrn = 0.158469790826; - msg.pos_sim_err_timeout = 12515U; - msg.converg_max = 0.671157553524; - msg.converg_timeout = 30051U; - msg.comms_timeout = 54741U; - msg.turb_lim = 0.0823289786589; - msg.custom.assign("YPZMBMDOAMKGUNUDVXVTQRXOKZVPGCKSCPGJMEYIXQBIUEKUTLVPECLEIRGGYHDOTAJINDJRXPZYHFKRSVRXQPGPZCELRYRBVIKUBEWGYNBHFJOTTLLRBUKBDANZEJ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationPlanExecution #1", msg == *msg_d); + test.boolean("ManeuverDone #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15045,33 +17890,19 @@ main(void) } { - IMC::FormationPlanExecution msg; - msg.setTimeStamp(0.484468104734); - msg.setSource(63784U); - msg.setSourceEntity(149U); - msg.setDestination(48587U); - msg.setDestinationEntity(92U); - msg.group_name.assign("CAHFLTZQROQNOSKYJULPMVRICSLICMOJFDBKTJKEWQKWCHLVNNTDZUNSXERDHTXKIDUSARFYPGHOGOBXCVGFWXAZESYNPIUVEKEXHQEMGFEIJALSJNXUWTOBUFLUJMUXEUIDOFZCPIMWCSAAAWEYBDVGKHBTJOTJWFVBGYZAPFVHYDGYXPZOWDNYJULLFTRQNPGQQCSQGTMCZJWLLZYRBDR"); - msg.formation_name.assign("WIJUWGXKKGHTGSTJHQNHZUNBMWIKTKSRQWOIEAJAULFJCBHUZPRDLTNKQYTRZJLCTFEGBDREWVCAHVDUADLVRRDTEUSGYTNCPCCOEBELOOWOBGBAIPPADMXWHVNRJODFHXSBZJKQUZQZHCUXNXZBQFMSPWGLFRYMGVDZQPBLDSNNJXCYXPIVNIOPGMSUMHVQFKC"); - msg.plan_id.assign("IJEYHKDVVAWGSEWBZPYWQPUCHYFYZAJGFXIVIPVMXMVZAGTXKEVJPCSSMTYSLDZKSUWEMFRBUTHSTQUGORSRONRBALGXTJYTYENCMQCNRAJCNIKJJYOOHDHDBKSVC"); - msg.description.assign("LGBEWGJDLKNWXAVTKOYTCIYAPQBXPOGVUQDMPDCJPXMBBLPNGFWGMTLSMJOIZYSCWUBNHDXYIHJGXTOJBREZYKTHAVVUHBBOTJSZMPHOMIYKNUXDRKMLAVFMOMQJVJRCAACRXXWQHRDPKPBCNUJKHGYFCGOEULVAHENIPRTZQVZQRKRZEQWVFFSNTAUCIHUMXLTPKSSELNXZELZLBYKYTJESQRIUYWQCZFHSIAWANVZUDSSGFWIEED"); - msg.leader_speed = 0.476687537393; - msg.leader_bank_lim = 0.909157266478; - msg.pos_sim_err_lim = 0.0770197870544; - msg.pos_sim_err_wrn = 0.281731298617; - msg.pos_sim_err_timeout = 2391U; - msg.converg_max = 0.889345817231; - msg.converg_timeout = 44957U; - msg.comms_timeout = 51987U; - msg.turb_lim = 0.127812676816; - msg.custom.assign("YULFCOWIXSHAKAVAXLYXOHUXCBPJJAOUBETDJCFCWSOYJJGTXQBLGDVTLACWEGPEKKHBRKIXJKMVMOABSNXCCHKOQFDVNGOT"); + IMC::ManeuverDone msg; + msg.setTimeStamp(0.7206902233986748); + msg.setSource(22435U); + msg.setSourceEntity(131U); + msg.setDestination(5660U); + msg.setDestinationEntity(3U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationPlanExecution #2", msg == *msg_d); + test.boolean("ManeuverDone #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15082,24 +17913,30 @@ main(void) } { - IMC::FollowReference msg; - msg.setTimeStamp(0.700935547715); - msg.setSource(34977U); - msg.setSourceEntity(247U); - msg.setDestination(30246U); - msg.setDestinationEntity(179U); - msg.control_src = 63913U; - msg.control_ent = 21U; - msg.timeout = 0.0774397540784; - msg.loiter_radius = 0.44710614131; - msg.altitude_interval = 0.0932143935738; + IMC::Magnetometer msg; + msg.setTimeStamp(0.8145874328474876); + msg.setSource(44595U); + msg.setSourceEntity(102U); + msg.setDestination(40894U); + msg.setDestinationEntity(59U); + msg.timeout = 45071U; + msg.lat = 0.6189795398518885; + msg.lon = 0.6181021242089141; + msg.z = 0.4550034175893878; + msg.z_units = 201U; + msg.speed = 0.20361479119054204; + msg.speed_units = 163U; + msg.bearing = 0.263436588591629; + msg.width = 0.3545930055124731; + msg.direction = 189U; + msg.custom.assign("TKUKFYMWHSWRFXYMCMZVXKRSXUWEOIQJFATBBUYZGCNTVURDDBSPVLIBLZEASCQDFXJDHOEWSSPYHNMYTXGTVXCJDPZYMYNGZOCNHENLKBOUINORHMVFJCHAUQUHRBIKMQBFJWCKKFDJWVNXIGQXUQRRQQVJUIRIGQHLRQWBPKGLHYKNEKATSTMJTVSXGDLOGWJEADULPYFYGDNJZVOCLCEAZCZ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowReference #0", msg == *msg_d); + test.boolean("Magnetometer #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15110,24 +17947,30 @@ main(void) } { - IMC::FollowReference msg; - msg.setTimeStamp(0.617317128115); - msg.setSource(10990U); - msg.setSourceEntity(110U); - msg.setDestination(65448U); - msg.setDestinationEntity(23U); - msg.control_src = 45670U; - msg.control_ent = 61U; - msg.timeout = 0.51507556671; - msg.loiter_radius = 0.813760497852; - msg.altitude_interval = 0.673303867901; + IMC::Magnetometer msg; + msg.setTimeStamp(0.40509713878325027); + msg.setSource(43522U); + msg.setSourceEntity(3U); + msg.setDestination(6039U); + msg.setDestinationEntity(127U); + msg.timeout = 43636U; + msg.lat = 0.31561944148829446; + msg.lon = 0.1562232141893488; + msg.z = 0.18685531605241545; + msg.z_units = 185U; + msg.speed = 0.8106706133609977; + msg.speed_units = 115U; + msg.bearing = 0.2597935539714673; + msg.width = 0.696337092929198; + msg.direction = 34U; + msg.custom.assign("GPXGPBTZCSJQXTANDUWMDUPFEYJYFBNJQWURHRREWTVZPJDITYVONOKAIMZPYUKJITCKIVINMHOYQOQODFVEVSRZBNSVCSNUPBRLKLQJAD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowReference #1", msg == *msg_d); + test.boolean("Magnetometer #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15138,24 +17981,30 @@ main(void) } { - IMC::FollowReference msg; - msg.setTimeStamp(0.578349785902); - msg.setSource(63060U); - msg.setSourceEntity(20U); - msg.setDestination(39846U); - msg.setDestinationEntity(144U); - msg.control_src = 53575U; - msg.control_ent = 108U; - msg.timeout = 0.0734031626263; - msg.loiter_radius = 0.804884229484; - msg.altitude_interval = 0.723516404301; + IMC::Magnetometer msg; + msg.setTimeStamp(0.8586343989082601); + msg.setSource(22551U); + msg.setSourceEntity(135U); + msg.setDestination(38196U); + msg.setDestinationEntity(153U); + msg.timeout = 62136U; + msg.lat = 0.5875072632442895; + msg.lon = 0.05711819992159217; + msg.z = 0.14270707032686247; + msg.z_units = 51U; + msg.speed = 0.6415944034476679; + msg.speed_units = 211U; + msg.bearing = 0.8207107111526397; + msg.width = 0.24284422780828108; + msg.direction = 174U; + msg.custom.assign("XDRLGBYASCGRZUEPWFSXIEPAMXAHVEJLOBWDAH"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowReference #2", msg == *msg_d); + test.boolean("Magnetometer #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15166,31 +18015,29 @@ main(void) } { - IMC::Reference msg; - msg.setTimeStamp(0.866570586672); - msg.setSource(42687U); - msg.setSourceEntity(241U); - msg.setDestination(34558U); - msg.setDestinationEntity(15U); - msg.flags = 20U; - IMC::DesiredSpeed tmp_msg_0; - tmp_msg_0.value = 0.787367162951; - tmp_msg_0.speed_units = 85U; - msg.speed.set(tmp_msg_0); - IMC::DesiredZ tmp_msg_1; - tmp_msg_1.value = 0.0237790267248; - tmp_msg_1.z_units = 150U; - msg.z.set(tmp_msg_1); - msg.lat = 0.955486971141; - msg.lon = 0.310772232478; - msg.radius = 0.895723107144; + IMC::VehicleState msg; + msg.setTimeStamp(0.1908574680038222); + msg.setSource(4168U); + msg.setSourceEntity(14U); + msg.setDestination(54971U); + msg.setDestinationEntity(182U); + msg.op_mode = 81U; + msg.error_count = 109U; + msg.error_ents.assign("IHDQMKSWPJHDHAWBZRYOQWQVIKEZOEOPFSVUFXQYILGHVWKHVEMCBFRGSLSMDBPRMOXORVMLGDHCAEGUPUJQMFZYBFMGQESDUSUTLCIFAYCXKNVEJYMITPSZIBYJJWZXFTAFOCFOSESMYXWVNJJKPTBLRGIDHGJQGOAPXANKGTICQUZ"); + msg.maneuver_type = 51335U; + msg.maneuver_stime = 0.9732266381558082; + msg.maneuver_eta = 20840U; + msg.control_loops = 587224942U; + msg.flags = 122U; + msg.last_error.assign("QPIFDTDKKMTKAFFNVGRLPSWZKYXFCKMTPFCVYITQBIOALYECSURWZOOBNHEWVRTBUEQRKFQBWADZLPMDGNTSZMXPUQGWXIJJOEPTPMLCGNUUMYOZKRCRCWVHAIWJSRMYPHKY"); + msg.last_error_time = 0.30671266293916355; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Reference #0", msg == *msg_d); + test.boolean("VehicleState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15201,31 +18048,29 @@ main(void) } { - IMC::Reference msg; - msg.setTimeStamp(0.50235103943); - msg.setSource(38622U); - msg.setSourceEntity(94U); - msg.setDestination(1258U); - msg.setDestinationEntity(69U); - msg.flags = 93U; - IMC::DesiredSpeed tmp_msg_0; - tmp_msg_0.value = 0.511921618981; - tmp_msg_0.speed_units = 33U; - msg.speed.set(tmp_msg_0); - IMC::DesiredZ tmp_msg_1; - tmp_msg_1.value = 0.956174094121; - tmp_msg_1.z_units = 42U; - msg.z.set(tmp_msg_1); - msg.lat = 0.502896842684; - msg.lon = 0.582112593124; - msg.radius = 0.617899197704; + IMC::VehicleState msg; + msg.setTimeStamp(0.8935901778661564); + msg.setSource(239U); + msg.setSourceEntity(163U); + msg.setDestination(29926U); + msg.setDestinationEntity(146U); + msg.op_mode = 104U; + msg.error_count = 43U; + msg.error_ents.assign("JCRTXVQUVEADUGDAEOJUPSSMTPBQHCBPTXMRNNXYFUDTWZZQSVYJEFHXOBUBYTIUHKUJRQCAUCA"); + msg.maneuver_type = 22015U; + msg.maneuver_stime = 0.22389786739250395; + msg.maneuver_eta = 2129U; + msg.control_loops = 2443915018U; + msg.flags = 176U; + msg.last_error.assign("PHCPXPRCWDXONVOLWRBITAQCTOVICHCMZHYFWIVLGBVEJAGUBFEPHVUAILBZQJIMYNXZJOSKWFYEBDCBG"); + msg.last_error_time = 0.6478723742244061; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Reference #1", msg == *msg_d); + test.boolean("VehicleState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15236,31 +18081,29 @@ main(void) } { - IMC::Reference msg; - msg.setTimeStamp(0.937853334724); - msg.setSource(38412U); - msg.setSourceEntity(145U); - msg.setDestination(5162U); - msg.setDestinationEntity(26U); - msg.flags = 112U; - IMC::DesiredSpeed tmp_msg_0; - tmp_msg_0.value = 0.856584649202; - tmp_msg_0.speed_units = 201U; - msg.speed.set(tmp_msg_0); - IMC::DesiredZ tmp_msg_1; - tmp_msg_1.value = 0.758947193389; - tmp_msg_1.z_units = 186U; - msg.z.set(tmp_msg_1); - msg.lat = 0.482323887455; - msg.lon = 0.945421977537; - msg.radius = 0.0761956751722; + IMC::VehicleState msg; + msg.setTimeStamp(0.27448879610069055); + msg.setSource(33462U); + msg.setSourceEntity(77U); + msg.setDestination(58501U); + msg.setDestinationEntity(82U); + msg.op_mode = 158U; + msg.error_count = 2U; + msg.error_ents.assign("SYZETTGSRTFKKGHQCEXICVRANZYUJZIXDLLQYSOPKBVOXGUFLYOJYNMFWFNYBJMEBRKTQCQZAQMEGDBWHRRRIPDDEHDOZUOCPHKVHGLSZDBUWSWPOMAJCXGNCZMJTWCAIFIUVPHHZ"); + msg.maneuver_type = 51790U; + msg.maneuver_stime = 0.9944155435709571; + msg.maneuver_eta = 24796U; + msg.control_loops = 2829422680U; + msg.flags = 209U; + msg.last_error.assign("VXMYIBMAMBFAKKPVOHAOXFSZPULJISAQKIRDSJYLPZYTITZLLGLCNFBNRPVPWEIUDVGKQLBOPANJHSDGQTRCIBHZRUWODBJKVQXQTZTHPQRSWFFOQCEMUMEJTOGLTEQWIKNNOJGAWJEX"); + msg.last_error_time = 0.7832554612601113; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Reference #2", msg == *msg_d); + test.boolean("VehicleState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15271,37 +18114,34 @@ main(void) } { - IMC::FollowRefState msg; - msg.setTimeStamp(0.170867344502); - msg.setSource(46892U); - msg.setSourceEntity(134U); - msg.setDestination(17121U); - msg.setDestinationEntity(13U); - msg.control_src = 5593U; - msg.control_ent = 220U; - IMC::Reference tmp_msg_0; - tmp_msg_0.flags = 186U; - IMC::DesiredSpeed tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.value = 0.408617137666; - tmp_tmp_msg_0_0.speed_units = 7U; - tmp_msg_0.speed.set(tmp_tmp_msg_0_0); - IMC::DesiredZ tmp_tmp_msg_0_1; - tmp_tmp_msg_0_1.value = 0.39924889013; - tmp_tmp_msg_0_1.z_units = 157U; - tmp_msg_0.z.set(tmp_tmp_msg_0_1); - tmp_msg_0.lat = 0.484453532157; - tmp_msg_0.lon = 0.984948194465; - tmp_msg_0.radius = 0.645095722736; - msg.reference.set(tmp_msg_0); - msg.state = 7U; - msg.proximity = 141U; + IMC::VehicleCommand msg; + msg.setTimeStamp(0.5695724247579744); + msg.setSource(17398U); + msg.setSourceEntity(107U); + msg.setDestination(31372U); + msg.setDestinationEntity(253U); + msg.type = 110U; + msg.request_id = 29789U; + msg.command = 232U; + IMC::FollowPoint tmp_msg_0; + tmp_msg_0.target.assign("CHBGKVEXRFGGHUMXGGFFWKKXBLWUPFIBUMPQLXBQBGOSMFVUUIZQIZNTCJCQYHKJYSORIDIHALWRNTJBZOZJWXPMYDRDSSEUYUJNAOAEBFIFOIAZWWOMCVNXIRBHTVAXPTDCSLHGZPLAPVJVZXNDMUCNMFJYLCHQ"); + tmp_msg_0.max_speed = 0.7766784376210709; + tmp_msg_0.speed_units = 64U; + tmp_msg_0.lat = 0.2521606761094032; + tmp_msg_0.lon = 0.5934351070234666; + tmp_msg_0.z = 0.7486849805809412; + tmp_msg_0.z_units = 220U; + tmp_msg_0.custom.assign("STIYDSTVBVQVUPOKRIWFTZLFOWCMDZEGOKIJTUWFWCNQZHXJJKMKBSIIYTUAJASWXGPDTAPFLHKZJXUVGOPMDAQZFXPXUXACVYJERLYOKNEFWMKQSNBUCLOVNNXQYAQVLGGDWHNDLVHQJKXMADRCONMGLLEDQ"); + msg.maneuver.set(tmp_msg_0); + msg.calib_time = 15930U; + msg.info.assign("SABUTDANSFXYKLAIDFFANSQTGLDDMKWZVCBLZNFWLTEGIRBNBPJYJXKHUUQEDPCPELUFVHIGGOCPHTRNELCMNRECUOQKBLSJBKHSISZRCUDYRDPHZRBGSRYTCFJTBECLDUHOXSTAQOLUQFZAPWGPOTQMVWLVMEIRTMHEAHFXNKRXKPSYXNJUYFXQMIZBJOCIVGZVANOGV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowRefState #0", msg == *msg_d); + test.boolean("VehicleCommand #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15312,37 +18152,34 @@ main(void) } { - IMC::FollowRefState msg; - msg.setTimeStamp(0.737840985325); - msg.setSource(14557U); - msg.setSourceEntity(87U); - msg.setDestination(61762U); - msg.setDestinationEntity(66U); - msg.control_src = 1500U; - msg.control_ent = 185U; - IMC::Reference tmp_msg_0; - tmp_msg_0.flags = 102U; - IMC::DesiredSpeed tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.value = 0.774510947029; - tmp_tmp_msg_0_0.speed_units = 216U; - tmp_msg_0.speed.set(tmp_tmp_msg_0_0); - IMC::DesiredZ tmp_tmp_msg_0_1; - tmp_tmp_msg_0_1.value = 0.071757800763; - tmp_tmp_msg_0_1.z_units = 42U; - tmp_msg_0.z.set(tmp_tmp_msg_0_1); - tmp_msg_0.lat = 0.0688140883088; - tmp_msg_0.lon = 0.230582263383; - tmp_msg_0.radius = 0.598980460342; - msg.reference.set(tmp_msg_0); - msg.state = 43U; - msg.proximity = 193U; + IMC::VehicleCommand msg; + msg.setTimeStamp(0.18545142179231378); + msg.setSource(47230U); + msg.setSourceEntity(234U); + msg.setDestination(47791U); + msg.setDestinationEntity(211U); + msg.type = 81U; + msg.request_id = 21832U; + msg.command = 173U; + IMC::Drop tmp_msg_0; + tmp_msg_0.timeout = 5320U; + tmp_msg_0.lat = 0.46281464817097784; + tmp_msg_0.lon = 0.5500279786851878; + tmp_msg_0.z = 0.8703867645669982; + tmp_msg_0.z_units = 177U; + tmp_msg_0.speed = 0.2697873858162899; + tmp_msg_0.speed_units = 130U; + tmp_msg_0.custom.assign("FNIRPAYIZLITGFFWMOSCTSCDBLQONILNZDNVGIXXUMXPGRIONEBWWNTMSRGZYCHQRWCDGDFEWMNEYBHZPTAKBDBGESHRMPKQEZNVXDJV"); + msg.maneuver.set(tmp_msg_0); + msg.calib_time = 41920U; + msg.info.assign("OGCLQYFSVKUEHNHPKVDAQQJAPBPKWCUOAMIWSZRVNQOFWHRHXIYJEQDBFQZIJCLIJUEBHIVTNTDCGTSYXMBFOSCNZUXAGJFGBFCLVQJHFHTBOLWGMCUWPMWZRTXPTEYWNKLHPMOBHLMGKV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowRefState #1", msg == *msg_d); + test.boolean("VehicleCommand #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15353,37 +18190,39 @@ main(void) } { - IMC::FollowRefState msg; - msg.setTimeStamp(0.582552401087); - msg.setSource(53311U); - msg.setSourceEntity(1U); - msg.setDestination(34109U); - msg.setDestinationEntity(81U); - msg.control_src = 39653U; - msg.control_ent = 158U; - IMC::Reference tmp_msg_0; - tmp_msg_0.flags = 134U; - IMC::DesiredSpeed tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.value = 0.541934098405; - tmp_tmp_msg_0_0.speed_units = 110U; - tmp_msg_0.speed.set(tmp_tmp_msg_0_0); - IMC::DesiredZ tmp_tmp_msg_0_1; - tmp_tmp_msg_0_1.value = 0.15653229975; - tmp_tmp_msg_0_1.z_units = 57U; - tmp_msg_0.z.set(tmp_tmp_msg_0_1); - tmp_msg_0.lat = 0.205251598789; - tmp_msg_0.lon = 0.927011768562; - tmp_msg_0.radius = 0.471150303479; - msg.reference.set(tmp_msg_0); - msg.state = 90U; - msg.proximity = 55U; + IMC::VehicleCommand msg; + msg.setTimeStamp(0.025321061406891388); + msg.setSource(24698U); + msg.setSourceEntity(83U); + msg.setDestination(16879U); + msg.setDestinationEntity(10U); + msg.type = 12U; + msg.request_id = 26880U; + msg.command = 96U; + IMC::CompassCalibration tmp_msg_0; + tmp_msg_0.timeout = 48719U; + tmp_msg_0.lat = 0.840369982749548; + tmp_msg_0.lon = 0.5930736031154851; + tmp_msg_0.z = 0.6425785670821367; + tmp_msg_0.z_units = 123U; + tmp_msg_0.pitch = 0.49654104369478413; + tmp_msg_0.amplitude = 0.5851870486268193; + tmp_msg_0.duration = 62906U; + tmp_msg_0.speed = 0.07863847135808066; + tmp_msg_0.speed_units = 153U; + tmp_msg_0.radius = 0.3808894806079226; + tmp_msg_0.direction = 98U; + tmp_msg_0.custom.assign("URRVNWRSHOYEZFYAWTJNLORJJMUHWLVKNAVWVRIGCZDDFPWSSEOEQHEEPIMGDYHRACOLRSSXGBFXCANBJITFCBIUMZTGZWJONZNCCHBAMPFTZUBTDJSGGTUDFBWIXEHTGSOFGPPMHYDM"); + msg.maneuver.set(tmp_msg_0); + msg.calib_time = 13210U; + msg.info.assign("VLWTTBFWEVNEAWDJFPRLKYULIJOIWUVESKALCGXAFJAXZSNKZWCUQUHMXJYHHYJPBYIHGKTBKAXWG"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowRefState #2", msg == *msg_d); + test.boolean("VehicleCommand #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15394,61 +18233,21 @@ main(void) } { - IMC::FormationMonitor msg; - msg.setTimeStamp(0.291555761144); - msg.setSource(35096U); - msg.setSourceEntity(164U); - msg.setDestination(16417U); - msg.setDestinationEntity(92U); - msg.ax_cmd = 0.632798341368; - msg.ay_cmd = 0.626757041208; - msg.az_cmd = 0.490804329083; - msg.ax_des = 0.469936148118; - msg.ay_des = 0.275337818653; - msg.az_des = 0.470758927854; - msg.virt_err_x = 0.282641728371; - msg.virt_err_y = 0.56934674681; - msg.virt_err_z = 0.945974661137; - msg.surf_fdbk_x = 0.0317585077427; - msg.surf_fdbk_y = 0.0576061819127; - msg.surf_fdbk_z = 0.883577755553; - msg.surf_unkn_x = 0.333717830206; - msg.surf_unkn_y = 0.563542873359; - msg.surf_unkn_z = 0.561057953769; - msg.ss_x = 0.758196391359; - msg.ss_y = 0.20304443304; - msg.ss_z = 0.946220992101; - IMC::RelativeState tmp_msg_0; - tmp_msg_0.s_id.assign("IJXUSJUNHBRGMSOYCCHMMYTWFQIDDNBSTWKBNALARYPHPGRJPDNOPBHLWSXCEZBJQSMUFKXYBVUKTKUZFPOGVWZDFQCHYJAVCFWGUVLZFTZOVPDRNLSFLAYEKCQDXRQDJEECJZSOZLCIMPWVZAWYHATBVEDXOBQTHTOIQZDMMNLIRINWMTLSRVSGFGPRYVVHNHERRJOLKTIAXZEXAOCQKFXBAKHJOE"); - tmp_msg_0.dist = 0.456448312282; - tmp_msg_0.err = 0.391233715362; - tmp_msg_0.ctrl_imp = 0.213322956573; - tmp_msg_0.rel_dir_x = 0.59610089407; - tmp_msg_0.rel_dir_y = 0.551726754816; - tmp_msg_0.rel_dir_z = 0.690261063976; - tmp_msg_0.err_x = 0.119817942506; - tmp_msg_0.err_y = 0.37112888658; - tmp_msg_0.err_z = 0.749385748188; - tmp_msg_0.rf_err_x = 0.180618622109; - tmp_msg_0.rf_err_y = 0.389479767211; - tmp_msg_0.rf_err_z = 0.825932280018; - tmp_msg_0.rf_err_vx = 0.57560489329; - tmp_msg_0.rf_err_vy = 0.421915122325; - tmp_msg_0.rf_err_vz = 0.729822481504; - tmp_msg_0.ss_x = 0.173398806154; - tmp_msg_0.ss_y = 0.793186502851; - tmp_msg_0.ss_z = 0.690067599815; - tmp_msg_0.virt_err_x = 0.272741513634; - tmp_msg_0.virt_err_y = 0.886895066931; - tmp_msg_0.virt_err_z = 0.835155350108; - msg.rel_state.push_back(tmp_msg_0); + IMC::MonitorEntityState msg; + msg.setTimeStamp(0.845291519779282); + msg.setSource(16710U); + msg.setSourceEntity(220U); + msg.setDestination(64012U); + msg.setDestinationEntity(147U); + msg.command = 66U; + msg.entities.assign("OGLEQUDXMGMAVREPXMAMJVXLCDUPHDIN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationMonitor #0", msg == *msg_d); + test.boolean("MonitorEntityState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15459,61 +18258,21 @@ main(void) } { - IMC::FormationMonitor msg; - msg.setTimeStamp(0.358181005436); - msg.setSource(33458U); - msg.setSourceEntity(47U); - msg.setDestination(53148U); - msg.setDestinationEntity(49U); - msg.ax_cmd = 0.630729801574; - msg.ay_cmd = 0.964783763426; - msg.az_cmd = 0.385523624307; - msg.ax_des = 0.0533169498034; - msg.ay_des = 0.722085183509; - msg.az_des = 0.226164409844; - msg.virt_err_x = 0.684760733825; - msg.virt_err_y = 0.659348777213; - msg.virt_err_z = 0.375844454119; - msg.surf_fdbk_x = 0.266491362677; - msg.surf_fdbk_y = 0.0920565475156; - msg.surf_fdbk_z = 0.803054701983; - msg.surf_unkn_x = 0.890871493161; - msg.surf_unkn_y = 0.870690832499; - msg.surf_unkn_z = 0.55567237301; - msg.ss_x = 0.974247620058; - msg.ss_y = 0.850667673525; - msg.ss_z = 0.043863600139; - IMC::RelativeState tmp_msg_0; - tmp_msg_0.s_id.assign("EFREWVGFPACSSHFAESDMVXFHJOBUAPBRIMUUGYZYLDKABOIZMXSTJVDDGVSKPCJKYPXWQZVFFBTQCZRWKDHWQXULXJTGESASCTTQNZPQJFRWZNLXBZBAVMNEUGCISMDBRNDTCSAKUMHARUZRVYXRZIETKCNGMSLNDPOPIXQVL"); - tmp_msg_0.dist = 0.836767857241; - tmp_msg_0.err = 0.498492167565; - tmp_msg_0.ctrl_imp = 0.956583602815; - tmp_msg_0.rel_dir_x = 0.504046319976; - tmp_msg_0.rel_dir_y = 0.177456107477; - tmp_msg_0.rel_dir_z = 0.32372143355; - tmp_msg_0.err_x = 0.183099400908; - tmp_msg_0.err_y = 0.0335906522426; - tmp_msg_0.err_z = 0.878603304177; - tmp_msg_0.rf_err_x = 0.293611178571; - tmp_msg_0.rf_err_y = 0.475765955527; - tmp_msg_0.rf_err_z = 0.88926574957; - tmp_msg_0.rf_err_vx = 0.985727077819; - tmp_msg_0.rf_err_vy = 0.911561041611; - tmp_msg_0.rf_err_vz = 0.648098722882; - tmp_msg_0.ss_x = 0.373595736711; - tmp_msg_0.ss_y = 0.0892092734746; - tmp_msg_0.ss_z = 0.820064060911; - tmp_msg_0.virt_err_x = 0.0882720133515; - tmp_msg_0.virt_err_y = 0.411660209696; - tmp_msg_0.virt_err_z = 0.732685279121; - msg.rel_state.push_back(tmp_msg_0); + IMC::MonitorEntityState msg; + msg.setTimeStamp(0.439441860360808); + msg.setSource(62104U); + msg.setSourceEntity(230U); + msg.setDestination(48360U); + msg.setDestinationEntity(75U); + msg.command = 56U; + msg.entities.assign("BNKXYTTEDDNSXGLLLJRYFHDBTQHSOIQOEVMGPDNWJESAFBUGBZYBPHCOSONTFRGJCQQYBVUDFQHVCRPLVKDNOZMVZDJIMVLFMSAEQZHUQUGZKGJBHKHLTVHRVWEKAMKMXXUIOPZUALXFMDZHKQPQKTYCCCSLNJKYBOLRATWUGXEUTBFYWVYPAJANCNYIRWMBNFWFOAUTEFSWJJGPCMXHU"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationMonitor #1", msg == *msg_d); + test.boolean("MonitorEntityState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15524,61 +18283,21 @@ main(void) } { - IMC::FormationMonitor msg; - msg.setTimeStamp(0.84147316008); - msg.setSource(54866U); - msg.setSourceEntity(97U); - msg.setDestination(15795U); - msg.setDestinationEntity(37U); - msg.ax_cmd = 0.470045203385; - msg.ay_cmd = 0.729464249559; - msg.az_cmd = 0.0373287700087; - msg.ax_des = 0.150392820235; - msg.ay_des = 0.562479539505; - msg.az_des = 0.592344805933; - msg.virt_err_x = 0.429725591472; - msg.virt_err_y = 0.544077493522; - msg.virt_err_z = 0.974863971606; - msg.surf_fdbk_x = 0.249236081162; - msg.surf_fdbk_y = 0.0880876098867; - msg.surf_fdbk_z = 0.651091331602; - msg.surf_unkn_x = 0.59919557793; - msg.surf_unkn_y = 0.623804926503; - msg.surf_unkn_z = 0.929547196441; - msg.ss_x = 0.48241136516; - msg.ss_y = 0.458267481169; - msg.ss_z = 0.915772553965; - IMC::RelativeState tmp_msg_0; - tmp_msg_0.s_id.assign("GLPDGOSBGEDKQOCLQBVBIYFTFJHAWNQDVVPGGBPLAAMGCLHUWHQVDMZKVVYKJONUSJXRUMMZJEZJPBXDTBVJRWIXALATSJCVOFCSJRENXIKISPDDFXFLBEFTEWWPZLOTRGVQSHXTETFNZWEYGDBJU"); - tmp_msg_0.dist = 0.51392265691; - tmp_msg_0.err = 0.202713954336; - tmp_msg_0.ctrl_imp = 0.917233903077; - tmp_msg_0.rel_dir_x = 0.956415712678; - tmp_msg_0.rel_dir_y = 0.01037723185; - tmp_msg_0.rel_dir_z = 0.474817865456; - tmp_msg_0.err_x = 0.63494530483; - tmp_msg_0.err_y = 0.930202630849; - tmp_msg_0.err_z = 0.360261768864; - tmp_msg_0.rf_err_x = 0.943507859469; - tmp_msg_0.rf_err_y = 0.18341648129; - tmp_msg_0.rf_err_z = 0.675561679827; - tmp_msg_0.rf_err_vx = 0.398368293466; - tmp_msg_0.rf_err_vy = 0.679026870444; - tmp_msg_0.rf_err_vz = 0.784843823926; - tmp_msg_0.ss_x = 0.36025902485; - tmp_msg_0.ss_y = 0.974707231831; - tmp_msg_0.ss_z = 0.10378507328; - tmp_msg_0.virt_err_x = 0.515242244839; - tmp_msg_0.virt_err_y = 0.777859928764; - tmp_msg_0.virt_err_z = 0.968179837947; - msg.rel_state.push_back(tmp_msg_0); + IMC::MonitorEntityState msg; + msg.setTimeStamp(0.24173495451231464); + msg.setSource(36980U); + msg.setSourceEntity(18U); + msg.setDestination(43744U); + msg.setDestinationEntity(213U); + msg.command = 112U; + msg.entities.assign("KKAXFVUPAGZWZUOSRYFVDOIEKXDDWTIISYFCXYICKIHIWTMWEFXULGNUDZSWPUGJBACBEJFBVJWMOBTMGCBNUTJNHVXXVPLOJWDSTZRZKLZCSHSUOYQEEBFEELGHECPNXISNQJSGVOXMJONTEGAOQGBVDIRU"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationMonitor #2", msg == *msg_d); + test.boolean("MonitorEntityState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15589,41 +18308,27 @@ main(void) } { - IMC::RelativeState msg; - msg.setTimeStamp(0.624260672946); - msg.setSource(113U); - msg.setSourceEntity(116U); - msg.setDestination(37555U); - msg.setDestinationEntity(10U); - msg.s_id.assign("ZORUZHVPJLBUHFRSLGQJEGDRPMKCZVCGVWDSOMDHSBXVNLOBFJXUIQWYPDQRUXEOHUIPVXNSBKVAJOMFVGREYQCTVBHGDTJLDCCEEIRFPEAETSLYEYKTMTNZGMJCENZVZXQLTO"); - msg.dist = 0.52079566825; - msg.err = 0.804000928358; - msg.ctrl_imp = 0.408633121582; - msg.rel_dir_x = 0.135492701377; - msg.rel_dir_y = 0.209543410798; - msg.rel_dir_z = 0.259302376597; - msg.err_x = 0.823854229796; - msg.err_y = 0.730246761056; - msg.err_z = 0.950533925043; - msg.rf_err_x = 0.791967998262; - msg.rf_err_y = 0.874475941944; - msg.rf_err_z = 0.566960750136; - msg.rf_err_vx = 0.655389515928; - msg.rf_err_vy = 0.17296240999; - msg.rf_err_vz = 0.465933554926; - msg.ss_x = 0.442081290234; - msg.ss_y = 0.844670556402; - msg.ss_z = 0.0431757709242; - msg.virt_err_x = 0.848266515857; - msg.virt_err_y = 0.988592200275; - msg.virt_err_z = 0.54149206824; + IMC::EntityMonitoringState msg; + msg.setTimeStamp(0.022524581872234162); + msg.setSource(13300U); + msg.setSourceEntity(113U); + msg.setDestination(27341U); + msg.setDestinationEntity(57U); + msg.mcount = 230U; + msg.mnames.assign("ZIOEBJVSQCHDKCLTCGUMLBNWFZQTDUZOIXSJ"); + msg.ecount = 101U; + msg.enames.assign("TOHWEIKIBSQSTDDEQPBMXSCAAVRWMUQJIXWWPQDFOYSHBLKPVCZAFSXDKUNIGASVNJUEGGLZBQHRQULWPNMUBDNHEMPAMTCIYFKZAPFUHWLGOTCRJHEUMDEGFPSVOTGRXYKJSIINCETZYQWPJZ"); + msg.ccount = 130U; + msg.cnames.assign("AGMEUVTCNQBZIYTIMKEAKCVSTSPXJQUMDSFJESMWZCUGOFZBHKGHHUQOLZLPRBPFKTICGKPMAWCAPDRUCRITWVNRQUWSSGOXDBWZILVHNERJCMNYKKYJ"); + msg.last_error.assign("EGVTCEQIOBBNWKPAOFVTLZEPBBHHMQSVMKCBCOBZBFVHDAJHVQNFGMFFNGXTPELJPNCHMLCTKFKQJCOLZJAWUHFNPOMIQKESZQL"); + msg.last_error_time = 0.9808401444543052; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RelativeState #0", msg == *msg_d); + test.boolean("EntityMonitoringState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15634,41 +18339,27 @@ main(void) } { - IMC::RelativeState msg; - msg.setTimeStamp(0.632727795132); - msg.setSource(50678U); - msg.setSourceEntity(121U); - msg.setDestination(20045U); - msg.setDestinationEntity(214U); - msg.s_id.assign("LKWGUHGCABZZAGTEUWCOIYVDESRPBLOWPWQJDDHXHNQUTRBZSXSYQFOKXXCOTJKRJXGLJLPVECTIBGNZMPZIWPYFUXRSQGKMXYTYOGKMJLJDDHPEEDSNLWNQOVFBZYUBJAPSPILIFXDUVJLFCSTYIJSPWSVHMEHXRYDNEAVMAHKNNSVYFIZBFGFEYKZHLHCQRWOUVEMZVAFGTCNQCUWBDOU"); - msg.dist = 0.444743179209; - msg.err = 0.704402798697; - msg.ctrl_imp = 0.337755244051; - msg.rel_dir_x = 0.288270197432; - msg.rel_dir_y = 0.44653810265; - msg.rel_dir_z = 0.592907697573; - msg.err_x = 0.440543637078; - msg.err_y = 0.436583337418; - msg.err_z = 0.973576947989; - msg.rf_err_x = 0.567267920185; - msg.rf_err_y = 0.755639186233; - msg.rf_err_z = 0.991624894343; - msg.rf_err_vx = 0.488817599246; - msg.rf_err_vy = 0.264576993979; - msg.rf_err_vz = 0.537487146325; - msg.ss_x = 0.828968809456; - msg.ss_y = 0.383424014; - msg.ss_z = 0.297930690612; - msg.virt_err_x = 0.649075280207; - msg.virt_err_y = 0.81891815828; - msg.virt_err_z = 0.975092331151; + IMC::EntityMonitoringState msg; + msg.setTimeStamp(0.5056248309343168); + msg.setSource(36597U); + msg.setSourceEntity(208U); + msg.setDestination(59155U); + msg.setDestinationEntity(51U); + msg.mcount = 59U; + msg.mnames.assign("KZPATUHHXFSYZLDKBHGRIEUXGVCQJWMVKYFKOVVZUMWXQZWATOPUEYNUTCTASSPPOGLK"); + msg.ecount = 105U; + msg.enames.assign("CXVKMZYFDTWIKTGSKABNYXDDPLBHZZPOEHAERDADPTJULGHWMSPVEWFGIRZGOAHGSRKNQGLJIRCGVTJTLXLTUUEICKAJRQPLFOBLVPZFTVMSLFYWNQADDIAIBBQCVFOKRUJXQIZNJSEKWMICEIMCSOCNUFWQPCWTHDBBHHEOXZWJFFYVPUKQ"); + msg.ccount = 86U; + msg.cnames.assign("EYUXDYVBXZTVAJABVUIWTXMZKIQVCIUMZDHBHLEZNWJNFSKCLECYGFPSSFRYSXBAAPLONMPHFUBUHFNCWUKOREXQTNWVSIBJCVIYZLJDTOPQUSPTOMMHJZQLBTEO"); + msg.last_error.assign("OJZAGHVOTJSQNMLWCDYMVKAMICHMNJWRLQJHIZIGVKZAGDSFCCUNOKIVNKBBJSCHWYZHDDWLPGBLXREHBOTPQGCQHXPKSDVBNXSWDGDXYYAXQWPXAJ"); + msg.last_error_time = 0.4571175247990442; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RelativeState #1", msg == *msg_d); + test.boolean("EntityMonitoringState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15679,41 +18370,27 @@ main(void) } { - IMC::RelativeState msg; - msg.setTimeStamp(0.972549934032); - msg.setSource(5600U); - msg.setSourceEntity(7U); - msg.setDestination(39476U); - msg.setDestinationEntity(101U); - msg.s_id.assign("KHQRVGHDHOVEFIAMPWGKIGYGPTKTMXESQZTLEKIKRAKCLUZJCOXOXILIGRXIECXDVRMOPASFEPMXVJBMWLFWJBMPUXBKJYDRRMGXCAIWQRUJTZVCEKFPQOCXDTANLCJOSWNULPOGDGCTZZFTYLHEZBMQALMSJUNNSFTMAXFQHNWPLNDUVAJBUENUYRKNSIJTBODDHZGFIIQAVYBDVYOZNWYVQRLSHYUTYNKSSVHFC"); - msg.dist = 0.957101750812; - msg.err = 0.754143759912; - msg.ctrl_imp = 0.377878219134; - msg.rel_dir_x = 0.518294435233; - msg.rel_dir_y = 0.313084137757; - msg.rel_dir_z = 0.989258383414; - msg.err_x = 0.679283307068; - msg.err_y = 0.288354190628; - msg.err_z = 0.98868482766; - msg.rf_err_x = 0.309939651085; - msg.rf_err_y = 0.893768386046; - msg.rf_err_z = 0.628138825154; - msg.rf_err_vx = 0.525973691828; - msg.rf_err_vy = 0.914299681086; - msg.rf_err_vz = 0.404004825379; - msg.ss_x = 0.817347913981; - msg.ss_y = 0.687174468309; - msg.ss_z = 0.201505301489; - msg.virt_err_x = 0.854909041681; - msg.virt_err_y = 0.613853117718; - msg.virt_err_z = 0.0332774690162; + IMC::EntityMonitoringState msg; + msg.setTimeStamp(0.6890635098915567); + msg.setSource(45134U); + msg.setSourceEntity(120U); + msg.setDestination(63610U); + msg.setDestinationEntity(175U); + msg.mcount = 168U; + msg.mnames.assign("PQFHBRCCPIVTUTBYXNLKGAMPKHB"); + msg.ecount = 148U; + msg.enames.assign("IGREQZHIMSJIPRMWGWYAYOOHBNTBNZSDPBHC"); + msg.ccount = 17U; + msg.cnames.assign("PUHXHGYWTISUUDFCJJCJDBAEPDWJGOCVWKXBDRWHLINIDFKCTCZKYBTLYMNGZGLEFQQLSRLTKQMPOGAQVPJWZUIGSFBPVZXUEHUJLJEXKKEBEVYFQSLRHTEQSLOXRFAZNXRAGWHHIDYWQIF"); + msg.last_error.assign("FLRUHJYNCEFRMISG"); + msg.last_error_time = 0.9061128043912401; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RelativeState #2", msg == *msg_d); + test.boolean("EntityMonitoringState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15724,23 +18401,124 @@ main(void) } { - IMC::Dislodge msg; - msg.setTimeStamp(0.0456640317142); - msg.setSource(50846U); - msg.setSourceEntity(0U); - msg.setDestination(65021U); - msg.setDestinationEntity(233U); - msg.timeout = 6835U; - msg.rpm = 0.666484513299; - msg.direction = 21U; - msg.custom.assign("RBHHLOLFQKANYFSUCKTVUYTGTIEVWEUOECGMJYGWBZMRBJGOXFSYZSBJMWGOEVSLGUVOPPXYPXMBZBYFPOPNHKQITKXUXPIOLWZTHDRCNSJWOHIKOEWYCYMESXVSUIQKMNAUWLLAQBW"); + IMC::OperationalLimits msg; + msg.setTimeStamp(0.6309501537072268); + msg.setSource(60552U); + msg.setSourceEntity(179U); + msg.setDestination(3051U); + msg.setDestinationEntity(54U); + msg.mask = 241U; + msg.max_depth = 0.5510437776604844; + msg.min_altitude = 0.9106361574129062; + msg.max_altitude = 0.44389835441296144; + msg.min_speed = 0.49504042119745895; + msg.max_speed = 0.31836147473391085; + msg.max_vrate = 0.8913394384499975; + msg.lat = 0.033885269830694065; + msg.lon = 0.73211542226827; + msg.orientation = 0.07622255223511931; + msg.width = 0.9152635926199594; + msg.length = 0.9837183680524976; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("OperationalLimits #0", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #0", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::OperationalLimits msg; + msg.setTimeStamp(0.39844479172092895); + msg.setSource(13927U); + msg.setSourceEntity(180U); + msg.setDestination(50484U); + msg.setDestinationEntity(238U); + msg.mask = 180U; + msg.max_depth = 0.9459617907189222; + msg.min_altitude = 0.81807062888111; + msg.max_altitude = 0.4629734919670826; + msg.min_speed = 0.2784635200542104; + msg.max_speed = 0.5923679510935451; + msg.max_vrate = 0.6200660386575132; + msg.lat = 0.43438114809449024; + msg.lon = 0.05490725399601892; + msg.orientation = 0.7431621011594958; + msg.width = 0.2523725685471012; + msg.length = 0.5376287084994271; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("OperationalLimits #1", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #1", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::OperationalLimits msg; + msg.setTimeStamp(0.7758845569296151); + msg.setSource(36981U); + msg.setSourceEntity(117U); + msg.setDestination(54056U); + msg.setDestinationEntity(83U); + msg.mask = 167U; + msg.max_depth = 0.2008878489855499; + msg.min_altitude = 0.711405797665944; + msg.max_altitude = 0.3028441271988165; + msg.min_speed = 0.9382923155140912; + msg.max_speed = 0.7213698176596167; + msg.max_vrate = 0.21808845164973556; + msg.lat = 0.09210746375177459; + msg.lon = 0.9922879593757237; + msg.orientation = 0.9422547927245397; + msg.width = 0.6689389856280568; + msg.length = 0.9427338690979448; + + try + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(&msg, bfr); + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); + test.boolean("OperationalLimits #2", msg == *msg_d); + delete msg_d; + } + catch (IMC::InvalidMessageSize& e) + { + (void)e; + test.boolean("msg #2", msg.getSerializationSize() > DUNE_IMC_CONST_MAX_SIZE); + } + } + + { + IMC::GetOperationalLimits msg; + msg.setTimeStamp(0.4894970295393777); + msg.setSource(3606U); + msg.setSourceEntity(193U); + msg.setDestination(5764U); + msg.setDestinationEntity(134U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Dislodge #0", msg == *msg_d); + test.boolean("GetOperationalLimits #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15751,23 +18529,19 @@ main(void) } { - IMC::Dislodge msg; - msg.setTimeStamp(0.460588085852); - msg.setSource(32703U); - msg.setSourceEntity(91U); - msg.setDestination(42023U); - msg.setDestinationEntity(154U); - msg.timeout = 30603U; - msg.rpm = 0.687765442879; - msg.direction = 171U; - msg.custom.assign("CFGKAPOPVPPTQGXRSBBOSZWQPBIKGYUDAUDWXDHCHDGTPRMKPNYKKWPXMNEUOSLVDQJEIABAILDLVVZWLCMYCOCWH"); + IMC::GetOperationalLimits msg; + msg.setTimeStamp(0.30170774751039375); + msg.setSource(6441U); + msg.setSourceEntity(79U); + msg.setDestination(63394U); + msg.setDestinationEntity(223U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Dislodge #1", msg == *msg_d); + test.boolean("GetOperationalLimits #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15778,23 +18552,19 @@ main(void) } { - IMC::Dislodge msg; - msg.setTimeStamp(0.474029750383); - msg.setSource(51613U); - msg.setSourceEntity(97U); - msg.setDestination(16126U); - msg.setDestinationEntity(192U); - msg.timeout = 44159U; - msg.rpm = 0.73405588702; - msg.direction = 35U; - msg.custom.assign("CMBAXEUZDLBOBKYFCPXRQKTUVIDADZHWJMEZNKGCUCJBJEXNVRAWYRVQUOHMZERAFWIQFPVH"); + IMC::GetOperationalLimits msg; + msg.setTimeStamp(0.5778078961389375); + msg.setSource(32007U); + msg.setSourceEntity(33U); + msg.setDestination(31367U); + msg.setDestinationEntity(23U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Dislodge #2", msg == *msg_d); + test.boolean("GetOperationalLimits #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15805,39 +18575,20 @@ main(void) } { - IMC::Formation msg; - msg.setTimeStamp(0.735979714844); - msg.setSource(51258U); - msg.setSourceEntity(96U); - msg.setDestination(491U); - msg.setDestinationEntity(85U); - msg.formation_name.assign("YQTKGZGYHNGDLHAOTWRQHPGJVCYPBDUPRDFXLENOHNIIXAEHLJMJJGQCTRQFKMOPELYWSA"); - msg.type = 19U; - msg.op = 60U; - msg.group_name.assign("QMKVSWYZPMWDFAHYEQEAGABPNGRGJAZMIZZRCFLOWMXBESGOSQQJVOGNXTNNWVCSAPIDVMTZTHEIAXOFTKYZHHLOJ"); - msg.plan_id.assign("JUYDLKUBZBGBXZBELOSLLZIEBSTAZHATRJDPQGHGYWCOSOZQWMLNTGVRISZMONNSCXHIXXCMIEKYUCSDPAJHAPDGTSHMIRELQKERHQQCXVIVPKYRWHZKSMMPLXPEEFQIXOMUBTTYXCLCDUWYFLGVQNOPMAVKWLDFTW"); - msg.description.assign("FGCAXWCSNJIRKNEFXXXYKWUHFOBIRVPTMNWMHFMQBZZBXELBGPSLJCVHIJERVHILMMHHDWDOPZLUEKOVQHNZLPDTYNSGQSJYPDGQPIRLOXTUFNZG"); - msg.reference_frame = 182U; - msg.leader_bank_lim = 0.501459822855; - msg.leader_speed_min = 0.605096098965; - msg.leader_speed_max = 0.797563889045; - msg.leader_alt_min = 0.103421474784; - msg.leader_alt_max = 0.354781760294; - msg.pos_sim_err_lim = 0.574678543068; - msg.pos_sim_err_wrn = 0.767198764316; - msg.pos_sim_err_timeout = 52432U; - msg.converg_max = 0.530776315183; - msg.converg_timeout = 59739U; - msg.comms_timeout = 35230U; - msg.turb_lim = 0.94967409416; - msg.custom.assign("XACNOVDKEUJVGTUJXCLDNGSJIXTCTJRAYFHRJMERXZHLSRNGYCUVYFSMFIMLKPJBEKALGSNIJXFPIQDBHPCDPARBLDN"); + IMC::Calibration msg; + msg.setTimeStamp(0.562751728794509); + msg.setSource(63857U); + msg.setSourceEntity(19U); + msg.setDestination(38532U); + msg.setDestinationEntity(205U); + msg.duration = 26812U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Formation #0", msg == *msg_d); + test.boolean("Calibration #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15848,39 +18599,20 @@ main(void) } { - IMC::Formation msg; - msg.setTimeStamp(0.205678364306); - msg.setSource(6823U); - msg.setSourceEntity(42U); - msg.setDestination(42601U); - msg.setDestinationEntity(65U); - msg.formation_name.assign("FXYRQSLGNRPPEIBJJTGWEQIMWNNBVQBBTFPUEOTDWKGDGWDMUF"); - msg.type = 229U; - msg.op = 130U; - msg.group_name.assign("LCUIBQKRHSNGQHEEKYXRBCWQVJQXBCFQHVEEOSDFGILOUKKLJJDOQFIFMMGNZXTFTCBIHYLRPTYBHNVWBCSDSHWJCHKSDGFPTZYGEBXCDOWAUSEKZQMOJMXAJVDPLRGZZNAEALSVBFCMWAEAAWUWXRPLNZTAPOVVTV"); - msg.plan_id.assign("QPNJUBCTCZYZJXKAFMFTFUTKYOBPNISXSWPHYBNQRHWIRNMGQMLWIZIUVRJPYHUBXSJQAVBDLWESFRPBXZMEUGABKZSIYXMBZKYVAMHUWESRRFJIJIKEAVQEPNTMTDHOLNEVLSANRCGOUUXKFOVMWAGRLZSGDWOKKVGVWCDTDQAZIDZYD"); - msg.description.assign("KAMXQHQGTGPRAMBVDITUTFVISBXFJNHYINUXVUMIMVPGDKURWAXLNVWJOYVXGZHKEQAORRIPOWWXZFGXZPFJOZDRSEWMMNYYNBCTSSTIPLSSIJJFWUBOGDLPBZ"); - msg.reference_frame = 27U; - msg.leader_bank_lim = 0.685345573824; - msg.leader_speed_min = 0.820110573708; - msg.leader_speed_max = 0.344867322058; - msg.leader_alt_min = 0.35231061493; - msg.leader_alt_max = 0.526645347887; - msg.pos_sim_err_lim = 0.497022066622; - msg.pos_sim_err_wrn = 0.29834636861; - msg.pos_sim_err_timeout = 17512U; - msg.converg_max = 0.81585596746; - msg.converg_timeout = 27732U; - msg.comms_timeout = 17155U; - msg.turb_lim = 0.123792118162; - msg.custom.assign("OYALTIXZWGDNXMIHPEWRPAPFCZQKGRHTEDXBSGIJYZAKBSAEXLEKRIWNO"); + IMC::Calibration msg; + msg.setTimeStamp(0.7681907083209452); + msg.setSource(19716U); + msg.setSourceEntity(162U); + msg.setDestination(52386U); + msg.setDestinationEntity(34U); + msg.duration = 42358U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Formation #1", msg == *msg_d); + test.boolean("Calibration #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15891,45 +18623,20 @@ main(void) } { - IMC::Formation msg; - msg.setTimeStamp(0.920223395662); - msg.setSource(14049U); - msg.setSourceEntity(22U); - msg.setDestination(7934U); - msg.setDestinationEntity(107U); - msg.formation_name.assign("EIWITGMEEHJDRHQSFVQRRNWRUBABDYMPNPTGYWKVOASXLTWQKVASOQOYDWEGWVEYZFZCJIJVHZNEQDPGLBZUMRUTYFFCIXLXWBPTKUQLXHRSUPNOTPBAEOQOVYTAHSADBHMZJFIELCIBSMZKJSMQJPTCLNDVGXZKRYKSJHHZKLTOJDKARMBCLLDGKIEHMNSVCI"); - msg.type = 100U; - msg.op = 74U; - msg.group_name.assign("RAXLLBNPFZPOTZHDCMGWMXADDKWTMKXDFFBFSAPKGBCOUGKOEMWUZARQPBUDRVFZTGEVRTGQQHTJVHNEOYXNIHOVIOQLRWMXCLGVNZQXZDLNNHLKKJYYYSGBTTFOJEAPIQBGESBPPNIISYAR"); - msg.plan_id.assign("AHUEQXPTVAYAMTEFWIHEPKKDCXLNGYHVCSUGQJZZOYDIDTSFQYSRRQCHBBBXIRRUDJEVOSGPBNAGMOHMCKHBRAWVIRHPLUUOVUIPGFWCKXZCDMDMNAZDBLRPXBFTNJOFFIFNIEOBJHMCMSWERRLQSGFPZNTOQSTZEXQVWNMDCUFYLKPJITYIJKKXUMU"); - msg.description.assign("QHIQEARDBPDEEJRLJKIBFFPOGOPMHEMDSHTYEMIZRSJNBTUEKTVIK"); - msg.reference_frame = 48U; - IMC::VehicleFormationParticipant tmp_msg_0; - tmp_msg_0.vid = 6607U; - tmp_msg_0.off_x = 0.949978724511; - tmp_msg_0.off_y = 0.129548496376; - tmp_msg_0.off_z = 0.173825973479; - msg.participants.push_back(tmp_msg_0); - msg.leader_bank_lim = 0.996519404016; - msg.leader_speed_min = 0.423741346579; - msg.leader_speed_max = 0.801379517221; - msg.leader_alt_min = 0.536925707352; - msg.leader_alt_max = 0.279250482146; - msg.pos_sim_err_lim = 0.494005527661; - msg.pos_sim_err_wrn = 0.313162050633; - msg.pos_sim_err_timeout = 2681U; - msg.converg_max = 0.877453388394; - msg.converg_timeout = 23011U; - msg.comms_timeout = 18138U; - msg.turb_lim = 0.310249160977; - msg.custom.assign("OIIYOODXDCWEX"); + IMC::Calibration msg; + msg.setTimeStamp(0.8042771111417897); + msg.setSource(9806U); + msg.setSourceEntity(204U); + msg.setDestination(35463U); + msg.setDestinationEntity(164U); + msg.duration = 6667U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Formation #2", msg == *msg_d); + test.boolean("Calibration #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15940,27 +18647,22 @@ main(void) } { - IMC::Launch msg; - msg.setTimeStamp(0.0625478911186); - msg.setSource(37904U); - msg.setSourceEntity(25U); - msg.setDestination(7798U); - msg.setDestinationEntity(218U); - msg.timeout = 48718U; - msg.lat = 0.920794650291; - msg.lon = 0.142630682774; - msg.z = 0.883603530531; - msg.z_units = 41U; - msg.speed = 0.160708231358; - msg.speed_units = 194U; - msg.custom.assign("QPVLSJYWHGLECVSGAPNWCXMRASSGXDEF"); + IMC::ControlLoops msg; + msg.setTimeStamp(0.034073618833550756); + msg.setSource(64580U); + msg.setSourceEntity(229U); + msg.setDestination(35872U); + msg.setDestinationEntity(83U); + msg.enable = 172U; + msg.mask = 2553671047U; + msg.scope_ref = 490137270U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Launch #0", msg == *msg_d); + test.boolean("ControlLoops #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -15971,27 +18673,22 @@ main(void) } { - IMC::Launch msg; - msg.setTimeStamp(0.610290480307); - msg.setSource(54073U); - msg.setSourceEntity(86U); - msg.setDestination(42409U); - msg.setDestinationEntity(78U); - msg.timeout = 6573U; - msg.lat = 0.794891817261; - msg.lon = 0.645987274847; - msg.z = 0.405096848416; - msg.z_units = 66U; - msg.speed = 0.0445594106124; - msg.speed_units = 250U; - msg.custom.assign("JGPBYXCRXWGACHZHFLGTTAXQYNXZQJPGGVBQSMRDBUAIRMNJLVTQFRHGIZUYZXEUSIOZLRAJJKPVNDYBCNIQKMVARSLAZTCUOFDZCBBWHRQPEJCGPYMLMJBVAUAVJNRMCGRSWHOOXFNSWOOWTUXBIFFEYKUDDMVFPKFXSYPWDDVHIJECTEZOXGID"); + IMC::ControlLoops msg; + msg.setTimeStamp(0.027002564229231862); + msg.setSource(23360U); + msg.setSourceEntity(87U); + msg.setDestination(61886U); + msg.setDestinationEntity(230U); + msg.enable = 212U; + msg.mask = 675467256U; + msg.scope_ref = 739469522U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Launch #1", msg == *msg_d); + test.boolean("ControlLoops #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16002,27 +18699,22 @@ main(void) } { - IMC::Launch msg; - msg.setTimeStamp(0.316721593845); - msg.setSource(5701U); - msg.setSourceEntity(132U); - msg.setDestination(25571U); - msg.setDestinationEntity(23U); - msg.timeout = 40349U; - msg.lat = 0.395693676296; - msg.lon = 0.508559371818; - msg.z = 0.7154204335; - msg.z_units = 190U; - msg.speed = 0.427716539554; - msg.speed_units = 121U; - msg.custom.assign("MUYEPTCHCJJYTLFCGMOOSPCZNXHGBNNUJJAVHDUUZHTQSNDVMWOYEVCZHGEDUWFZOILBNIROSLXVJTGAAEEBRLIGOLDLDVRZUHBHITBJFIRWGN"); + IMC::ControlLoops msg; + msg.setTimeStamp(0.8733402748101637); + msg.setSource(41520U); + msg.setSourceEntity(11U); + msg.setDestination(17659U); + msg.setDestinationEntity(1U); + msg.enable = 133U; + msg.mask = 702665135U; + msg.scope_ref = 3703983423U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Launch #2", msg == *msg_d); + test.boolean("ControlLoops #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16033,27 +18725,20 @@ main(void) } { - IMC::Drop msg; - msg.setTimeStamp(0.715556059215); - msg.setSource(12498U); - msg.setSourceEntity(215U); - msg.setDestination(42059U); - msg.setDestinationEntity(242U); - msg.timeout = 56356U; - msg.lat = 0.979432644806; - msg.lon = 0.834082357026; - msg.z = 0.772945763965; - msg.z_units = 193U; - msg.speed = 0.773922803945; - msg.speed_units = 36U; - msg.custom.assign("WGQFUPIPMRPBAZIPZVWXKQSXVHTNJYBVKSZINFJMGHTHRHCJSUIMVVHJCTUGUKSMRBWJRVRWGKMTVTLFOAQIJFOWQZNQU"); + IMC::VehicleMedium msg; + msg.setTimeStamp(0.432518149669743); + msg.setSource(29166U); + msg.setSourceEntity(55U); + msg.setDestination(41649U); + msg.setDestinationEntity(247U); + msg.medium = 128U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Drop #0", msg == *msg_d); + test.boolean("VehicleMedium #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16064,27 +18749,20 @@ main(void) } { - IMC::Drop msg; - msg.setTimeStamp(0.273512392398); - msg.setSource(25443U); - msg.setSourceEntity(135U); - msg.setDestination(52876U); - msg.setDestinationEntity(201U); - msg.timeout = 57580U; - msg.lat = 0.978923239438; - msg.lon = 0.433559168481; - msg.z = 0.416939732583; - msg.z_units = 79U; - msg.speed = 0.709068499651; - msg.speed_units = 147U; - msg.custom.assign("JZTXWSLAVHCZELORKQBHXKLCWBZEPPVCMGOAHUHRQGLGMKNSWYHHYZSEWUMDXZTXKTGNUUPWFISWBZZNYLLDRNMJYOEOIYDKOLVNERUQTFTBGAKFU"); + IMC::VehicleMedium msg; + msg.setTimeStamp(0.4721794876689034); + msg.setSource(23961U); + msg.setSourceEntity(15U); + msg.setDestination(18016U); + msg.setDestinationEntity(87U); + msg.medium = 111U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Drop #1", msg == *msg_d); + test.boolean("VehicleMedium #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16095,27 +18773,20 @@ main(void) } { - IMC::Drop msg; - msg.setTimeStamp(0.614700966733); - msg.setSource(39648U); - msg.setSourceEntity(220U); - msg.setDestination(20702U); - msg.setDestinationEntity(18U); - msg.timeout = 57238U; - msg.lat = 0.996191582951; - msg.lon = 0.205882523214; - msg.z = 0.99670578493; - msg.z_units = 132U; - msg.speed = 0.684079088059; - msg.speed_units = 171U; - msg.custom.assign("SKJNWBEUPWEBHRPNEJFTEBZYZPOPBRGPJAWCIUCSFJJORENAPFCEDNPEYJSVJTFDDQHSJLXLWIZRYGJDLMDDKIAHGSXKKSLGCVXMUKATCVNESJWZXAIVLYBVBORKBOAGNVRGUOGXRZIUWMCLXFWQHBBPSXHALZUFUZCDYUAPTZGZKTPQQOWKHXVYHQNISVBGGXYVCEOMDFFQVKXITTEKLONMAQIYMMIWOHNHURCYZ"); + IMC::VehicleMedium msg; + msg.setTimeStamp(0.18758421649329504); + msg.setSource(4879U); + msg.setSourceEntity(114U); + msg.setDestination(21886U); + msg.setDestinationEntity(244U); + msg.medium = 252U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Drop #2", msg == *msg_d); + test.boolean("VehicleMedium #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16126,27 +18797,21 @@ main(void) } { - IMC::ScheduledGoto msg; - msg.setTimeStamp(0.14424314816); - msg.setSource(44790U); - msg.setSourceEntity(19U); - msg.setDestination(34611U); - msg.setDestinationEntity(49U); - msg.arrival_time = 0.699766356497; - msg.lat = 0.808707661908; - msg.lon = 0.788312596912; - msg.z = 0.142518224094; - msg.z_units = 52U; - msg.travel_z = 0.59334532361; - msg.travel_z_units = 212U; - msg.delayed = 59U; + IMC::Collision msg; + msg.setTimeStamp(0.7041814927790766); + msg.setSource(12031U); + msg.setSourceEntity(213U); + msg.setDestination(6385U); + msg.setDestinationEntity(41U); + msg.value = 0.5109846198398045; + msg.type = 110U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ScheduledGoto #0", msg == *msg_d); + test.boolean("Collision #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16157,27 +18822,21 @@ main(void) } { - IMC::ScheduledGoto msg; - msg.setTimeStamp(0.184303999343); - msg.setSource(49745U); - msg.setSourceEntity(177U); - msg.setDestination(37992U); - msg.setDestinationEntity(228U); - msg.arrival_time = 0.344170168272; - msg.lat = 0.496745473937; - msg.lon = 0.809311047138; - msg.z = 0.95230254372; - msg.z_units = 127U; - msg.travel_z = 0.975171693878; - msg.travel_z_units = 61U; - msg.delayed = 67U; + IMC::Collision msg; + msg.setTimeStamp(0.5106172342454471); + msg.setSource(33107U); + msg.setSourceEntity(252U); + msg.setDestination(39251U); + msg.setDestinationEntity(195U); + msg.value = 0.30406755202226954; + msg.type = 86U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ScheduledGoto #1", msg == *msg_d); + test.boolean("Collision #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16188,27 +18847,21 @@ main(void) } { - IMC::ScheduledGoto msg; - msg.setTimeStamp(0.363166446913); - msg.setSource(21380U); - msg.setSourceEntity(99U); - msg.setDestination(59096U); - msg.setDestinationEntity(226U); - msg.arrival_time = 0.0448347456579; - msg.lat = 0.987510446506; - msg.lon = 0.465936446573; - msg.z = 0.295574582805; - msg.z_units = 132U; - msg.travel_z = 0.82197363066; - msg.travel_z_units = 87U; - msg.delayed = 174U; + IMC::Collision msg; + msg.setTimeStamp(0.9175850852612695); + msg.setSource(30789U); + msg.setSourceEntity(235U); + msg.setDestination(43678U); + msg.setDestinationEntity(243U); + msg.value = 0.2113596511204796; + msg.type = 19U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ScheduledGoto #2", msg == *msg_d); + test.boolean("Collision #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16219,35 +18872,25 @@ main(void) } { - IMC::RowsCoverage msg; - msg.setTimeStamp(0.0186251341527); - msg.setSource(53046U); - msg.setSourceEntity(181U); - msg.setDestination(30022U); - msg.setDestinationEntity(174U); - msg.lat = 0.903476357247; - msg.lon = 0.17144136588; - msg.z = 0.331020067984; - msg.z_units = 56U; - msg.speed = 0.838381644644; - msg.speed_units = 22U; - msg.bearing = 0.202649675125; - msg.cross_angle = 0.0958197877718; - msg.width = 0.993892774615; - msg.length = 0.471411197375; - msg.coff = 37U; - msg.angaperture = 0.761955602934; - msg.range = 53386U; - msg.overlap = 102U; - msg.flags = 10U; - msg.custom.assign("SBQQIPASGBJNQVHCFYHMPIQKSMLLRTDXPBOWIPNTCDVZYJRPIZEJDBLIGXWXAUUAJMNJOGLRDFZCQDHLKPGRJUSQJGGEBWXZFUSAAVIMKSXPSKOWWPUOWRUNLVQHUVSFVZKKRJXABEQFHOTHFZSQALCTTVZKNOJEFHKBCT"); + IMC::FormState msg; + msg.setTimeStamp(0.024231475154145365); + msg.setSource(38320U); + msg.setSourceEntity(61U); + msg.setDestination(31595U); + msg.setDestinationEntity(96U); + msg.possimerr = 0.7509249781168157; + msg.converg = 0.3139743650924818; + msg.turbulence = 0.4564011926714935; + msg.possimmon = 203U; + msg.commmon = 182U; + msg.convergmon = 78U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RowsCoverage #0", msg == *msg_d); + test.boolean("FormState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16258,35 +18901,25 @@ main(void) } { - IMC::RowsCoverage msg; - msg.setTimeStamp(0.658335638681); - msg.setSource(14072U); - msg.setSourceEntity(219U); - msg.setDestination(52003U); - msg.setDestinationEntity(183U); - msg.lat = 0.187066198741; - msg.lon = 0.0814239552079; - msg.z = 0.306278595407; - msg.z_units = 227U; - msg.speed = 0.00333088251379; - msg.speed_units = 156U; - msg.bearing = 0.763415950679; - msg.cross_angle = 0.988956770461; - msg.width = 0.841404347151; - msg.length = 0.706171759777; - msg.coff = 152U; - msg.angaperture = 0.698086381997; - msg.range = 28849U; - msg.overlap = 251U; - msg.flags = 24U; - msg.custom.assign("AMAQJIJUZDXKTQWSTSCBCFWSVUXWOWDIQNJAIPNJHFDTECIGUEOWPHPNDUPNYPHWPEILXVLVQZMUNVAFJYAZBGFYEADORFMCFGR"); + IMC::FormState msg; + msg.setTimeStamp(0.3745522520132897); + msg.setSource(17384U); + msg.setSourceEntity(84U); + msg.setDestination(15801U); + msg.setDestinationEntity(118U); + msg.possimerr = 0.08513277202028546; + msg.converg = 0.734937071959321; + msg.turbulence = 0.9362083470836066; + msg.possimmon = 72U; + msg.commmon = 244U; + msg.convergmon = 124U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RowsCoverage #1", msg == *msg_d); + test.boolean("FormState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16297,35 +18930,25 @@ main(void) } { - IMC::RowsCoverage msg; - msg.setTimeStamp(0.559019358218); - msg.setSource(39831U); - msg.setSourceEntity(30U); - msg.setDestination(32016U); - msg.setDestinationEntity(15U); - msg.lat = 0.893434550383; - msg.lon = 0.471624220351; - msg.z = 0.268988579184; - msg.z_units = 214U; - msg.speed = 0.0296308049449; - msg.speed_units = 3U; - msg.bearing = 0.929721762302; - msg.cross_angle = 0.771388877616; - msg.width = 0.254105083449; - msg.length = 0.614479691489; - msg.coff = 64U; - msg.angaperture = 0.701581735863; - msg.range = 25527U; - msg.overlap = 163U; - msg.flags = 192U; - msg.custom.assign("BFMRGVVNYGESRDLYFNHCZYIFOGTUKHOIDLMWFXEBVGIMSXCAWXTEVRBQRHSPJJCIKAPBJVAYWLZXVVSPKZHZDCMTHBUPBDITFZWBWCTXRFIPMOOTFEGPNWMCLEJATKFZFWORHTJKJSXTYVAEAUNKYDVN"); + IMC::FormState msg; + msg.setTimeStamp(0.5102148500334016); + msg.setSource(63848U); + msg.setSourceEntity(82U); + msg.setDestination(29543U); + msg.setDestinationEntity(202U); + msg.possimerr = 0.19698331909612965; + msg.converg = 0.4774637782038377; + msg.turbulence = 0.2557910363115057; + msg.possimmon = 176U; + msg.commmon = 230U; + msg.convergmon = 66U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RowsCoverage #2", msg == *msg_d); + test.boolean("FormState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16336,30 +18959,21 @@ main(void) } { - IMC::Sample msg; - msg.setTimeStamp(0.0798177487175); - msg.setSource(33389U); - msg.setSourceEntity(242U); - msg.setDestination(29002U); - msg.setDestinationEntity(233U); - msg.timeout = 3336U; - msg.lat = 0.211689497092; - msg.lon = 0.0728421437398; - msg.z = 0.755849746688; - msg.z_units = 68U; - msg.speed = 0.613962681685; - msg.speed_units = 171U; - msg.syringe0 = 11U; - msg.syringe1 = 5U; - msg.syringe2 = 32U; - msg.custom.assign("PCPSVEHXUGDRJECGBBCXKWWMZRAUWLEBNAMZPQJOQNQTDWZKOQOXXYGRDVJZMHGMFAFCYIWLKSIEQSOWFFPLJSFNHTCWUAHFQADPPYNGSEHWJLSKFSHKFNIEASKIRGQIRLBQKVXXBYVLUGSIVTXYZUBQBXKCBTDEFGVJUYUJDKIXVROSMZWMAOUZYQPHTVNDLUGTAJNIMIRRYONZCHCTNYVCWLHGEF"); + IMC::AutopilotMode msg; + msg.setTimeStamp(0.09513177149076901); + msg.setSource(49943U); + msg.setSourceEntity(151U); + msg.setDestination(19208U); + msg.setDestinationEntity(54U); + msg.autonomy = 143U; + msg.mode.assign("VIRVJJJPTNXNMFYJLPIXCNUOEIAGFDYMODWBPRMPRFLBZLXBBMOWZKYWYWNGOFVGODQQELPBXIVALSXQUJHMLNQUZIVFLLMORZRAXEVGDKJTASAXFTJEATWKRPFZAGOCCTVHGQBKUIHBDIUNQXBUVVMSJIHKICQSDTHYMBNKPHREDSRYEKDQOGZCSHYFWQTWDHUTMWICWZCSAEUAFJUAKGXSCMTYGSLTOEPNQOEH"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Sample #0", msg == *msg_d); + test.boolean("AutopilotMode #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16370,30 +18984,21 @@ main(void) } { - IMC::Sample msg; - msg.setTimeStamp(0.521298247155); - msg.setSource(28579U); - msg.setSourceEntity(7U); - msg.setDestination(51421U); - msg.setDestinationEntity(20U); - msg.timeout = 21878U; - msg.lat = 0.650293713601; - msg.lon = 0.276052075128; - msg.z = 0.0609032781897; - msg.z_units = 194U; - msg.speed = 0.786988984118; - msg.speed_units = 207U; - msg.syringe0 = 71U; - msg.syringe1 = 120U; - msg.syringe2 = 87U; - msg.custom.assign("BDODXVCDBAWTCBDUFEZAXGWXUTFOYVAJYQEFLNWCOEBFCNOHWXKCPTRIBIHMMCACGPGSFQZTTMDQOJBYCPUOBZPARLTZIPXKIHENVHKEMMSSXGNTFICNQFRVTWGUOKZWDBUADAZVQJYXGFULLFMZIEZGRPNAWHBJ"); + IMC::AutopilotMode msg; + msg.setTimeStamp(0.8280495990401854); + msg.setSource(22865U); + msg.setSourceEntity(45U); + msg.setDestination(32784U); + msg.setDestinationEntity(241U); + msg.autonomy = 20U; + msg.mode.assign("CXGGMHEOLQSDMLMSLFFJUVUDTPNQNUKNYJYMHEDKRIXTXVPDAVYQYAYTSLIBCSVOTVKXRCAZGDSWKMENYWJMRRUMLBHGPJECHEBXJOPJDQFBZYARUZISOUXJNTPYFFFTG"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Sample #1", msg == *msg_d); + test.boolean("AutopilotMode #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16404,30 +19009,21 @@ main(void) } { - IMC::Sample msg; - msg.setTimeStamp(0.0878141597493); - msg.setSource(65410U); - msg.setSourceEntity(80U); - msg.setDestination(23702U); - msg.setDestinationEntity(183U); - msg.timeout = 20655U; - msg.lat = 0.361985220188; - msg.lon = 0.724807169689; - msg.z = 0.0954651498243; - msg.z_units = 4U; - msg.speed = 0.262003929566; - msg.speed_units = 22U; - msg.syringe0 = 51U; - msg.syringe1 = 244U; - msg.syringe2 = 188U; - msg.custom.assign("LGECUYCKTBRSXLXAFPMZTXTXDKMGNWHXTUJESOJKNDHWYPMWSPDDBGVUNTPLEIVRILOPIWDMDUFKFSQDKBCEOXYYCDVHBZTEOYGMPCALGNVEKBUKUQJOTBHZOJYVWBXFVIXZFFOEPLPYSAYJGFNAOBCQMWVRUVJNWZHNIRSLRAZESRTZFCRQJNQLCWCMVUM"); + IMC::AutopilotMode msg; + msg.setTimeStamp(0.14497981925280368); + msg.setSource(48918U); + msg.setSourceEntity(211U); + msg.setDestination(37847U); + msg.setDestinationEntity(4U); + msg.autonomy = 88U; + msg.mode.assign("IZWDZZGTCGKTTOXZCI"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Sample #2", msg == *msg_d); + test.boolean("AutopilotMode #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16438,19 +19034,27 @@ main(void) } { - IMC::ImageTracking msg; - msg.setTimeStamp(0.979281267742); - msg.setSource(27289U); - msg.setSourceEntity(104U); - msg.setDestination(12613U); - msg.setDestinationEntity(237U); + IMC::FormationState msg; + msg.setTimeStamp(0.08380031001654131); + msg.setSource(35913U); + msg.setSourceEntity(75U); + msg.setDestination(50871U); + msg.setDestinationEntity(111U); + msg.type = 107U; + msg.op = 67U; + msg.possimerr = 0.28248101532980485; + msg.converg = 0.6707351327997094; + msg.turbulence = 0.048126960791320506; + msg.possimmon = 161U; + msg.commmon = 30U; + msg.convergmon = 126U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ImageTracking #0", msg == *msg_d); + test.boolean("FormationState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16461,19 +19065,27 @@ main(void) } { - IMC::ImageTracking msg; - msg.setTimeStamp(0.426437798151); - msg.setSource(30286U); - msg.setSourceEntity(45U); - msg.setDestination(24041U); - msg.setDestinationEntity(14U); + IMC::FormationState msg; + msg.setTimeStamp(0.16496328560324935); + msg.setSource(36988U); + msg.setSourceEntity(91U); + msg.setDestination(28572U); + msg.setDestinationEntity(44U); + msg.type = 162U; + msg.op = 50U; + msg.possimerr = 0.26016653589660277; + msg.converg = 0.686016765413093; + msg.turbulence = 0.6343544826472256; + msg.possimmon = 98U; + msg.commmon = 140U; + msg.convergmon = 39U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ImageTracking #1", msg == *msg_d); + test.boolean("FormationState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16484,19 +19096,27 @@ main(void) } { - IMC::ImageTracking msg; - msg.setTimeStamp(0.587647362862); - msg.setSource(29667U); - msg.setSourceEntity(101U); - msg.setDestination(36666U); - msg.setDestinationEntity(202U); + IMC::FormationState msg; + msg.setTimeStamp(0.05169967148361709); + msg.setSource(16126U); + msg.setSourceEntity(17U); + msg.setDestination(5182U); + msg.setDestinationEntity(37U); + msg.type = 2U; + msg.op = 154U; + msg.possimerr = 0.4968781112656181; + msg.converg = 0.7523707716181846; + msg.turbulence = 0.3922883883855821; + msg.possimmon = 146U; + msg.commmon = 12U; + msg.convergmon = 148U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ImageTracking #2", msg == *msg_d); + test.boolean("FormationState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16507,27 +19127,23 @@ main(void) } { - IMC::Takeoff msg; - msg.setTimeStamp(0.153190133839); - msg.setSource(22386U); - msg.setSourceEntity(192U); - msg.setDestination(1183U); - msg.setDestinationEntity(195U); - msg.lat = 0.276355240273; - msg.lon = 0.333478166692; - msg.z = 0.691051573983; - msg.z_units = 97U; - msg.speed = 0.00228561429991; - msg.speed_units = 96U; - msg.takeoff_pitch = 0.621974512924; - msg.custom.assign("EMZGCLTZABOWLNEHCKMXXZKHMGEBEUQAKHLIVIGROMDCXDUSJWHXWAJOGGQSDMSMVUNSPSFCNBHCFQOSEZILZDDNMDSUJIYBICRJFOLRREGKKVWVCPSAYTFJJTBDTRUUNKUHMNFQPGDWUQVYQCLIOVHJBOUGRHFIXHBXFWTRIAEKLWCBAJLUVZYNKZYVFLXBYYVBSENRQAFDZPQYPWLANGPYAXPRJADZYIVTSTENWPKWZMQQFTOPT"); + IMC::ReportControl msg; + msg.setTimeStamp(0.4175539003744637); + msg.setSource(41098U); + msg.setSourceEntity(128U); + msg.setDestination(58497U); + msg.setDestinationEntity(49U); + msg.op = 248U; + msg.comm_interface = 12U; + msg.period = 4290U; + msg.sys_dst.assign("ANURPMIAELR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Takeoff #0", msg == *msg_d); + test.boolean("ReportControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16538,27 +19154,23 @@ main(void) } { - IMC::Takeoff msg; - msg.setTimeStamp(0.564354294493); - msg.setSource(45586U); - msg.setSourceEntity(227U); - msg.setDestination(35093U); - msg.setDestinationEntity(196U); - msg.lat = 0.434411434585; - msg.lon = 0.0409758004304; - msg.z = 0.506141893824; - msg.z_units = 191U; - msg.speed = 0.512642195902; - msg.speed_units = 54U; - msg.takeoff_pitch = 0.497055644985; - msg.custom.assign("OBAYBDGURPXORHDHOFGPBELFVDNVSJYCSHDREBCRCGAKGFQQYSENCSXJYJKSHJIXOMWCXDEQVQKWFDWZIJIVUCNDHNKPWPBKXGOZGPMOPTJEGUUKDYUIYZZGCAIEEFJAINXPMKZAND"); + IMC::ReportControl msg; + msg.setTimeStamp(0.6476857612683977); + msg.setSource(1227U); + msg.setSourceEntity(53U); + msg.setDestination(1412U); + msg.setDestinationEntity(211U); + msg.op = 104U; + msg.comm_interface = 136U; + msg.period = 25214U; + msg.sys_dst.assign("SPZAHZSRWSLPGGHZFXFPFJISEYBTUUTJOWRGETGOCMFDCUABOMXWHYRXWZIVHMGCTRXQNKLSSVUYZXMAPAPFZRXIHTRYDCBLHIAJDJLNSREBCJDGBIYCQOKVEOLVDYLYLXQOWCQNIGTJAVYEFWPKDYSDKNTBZTXGZIBQVKEHVKKCHJQAJVIUDHEGZ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Takeoff #1", msg == *msg_d); + test.boolean("ReportControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16569,27 +19181,23 @@ main(void) } { - IMC::Takeoff msg; - msg.setTimeStamp(0.526940388022); - msg.setSource(56303U); - msg.setSourceEntity(3U); - msg.setDestination(33320U); - msg.setDestinationEntity(140U); - msg.lat = 0.866469866606; - msg.lon = 0.286977098866; - msg.z = 0.952949492286; - msg.z_units = 66U; - msg.speed = 0.515296136002; - msg.speed_units = 107U; - msg.takeoff_pitch = 0.631924526616; - msg.custom.assign("UXVAYQMWTYJHVLNSBXDEIDLJCVXKTFUSQJSIV"); + IMC::ReportControl msg; + msg.setTimeStamp(0.044545322900033324); + msg.setSource(65018U); + msg.setSourceEntity(101U); + msg.setDestination(30057U); + msg.setDestinationEntity(114U); + msg.op = 196U; + msg.comm_interface = 18U; + msg.period = 11615U; + msg.sys_dst.assign("KYCKUORHGHJEMITIWSULPEZEHJJPBCVMSFOTQISPAPQGLKNTQNHSWMAAAPFCLRTGNEOBDYBIWDJUVBYZFISVFHXXPSVUBNVXNKMRMYRYTGYFIRZBSBZPHWHCUXQZRXEWWZSWLITKKKVDTNDFDJLCQYVQAATQVHOTOOWMECRAQTKMXFEULHGRJDSGZZVYLCPJIDIDQKCOQARRANPEIEUGGDPULOFYXYFL"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Takeoff #2", msg == *msg_d); + test.boolean("ReportControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16600,30 +19208,29 @@ main(void) } { - IMC::Land msg; - msg.setTimeStamp(0.143260084879); - msg.setSource(40311U); - msg.setSourceEntity(224U); - msg.setDestination(20268U); - msg.setDestinationEntity(144U); - msg.lat = 0.0364582647685; - msg.lon = 0.180845475926; - msg.z = 0.72859323398; - msg.z_units = 202U; - msg.speed = 0.214585024083; - msg.speed_units = 202U; - msg.abort_z = 0.678554685359; - msg.bearing = 0.345243545565; - msg.glide_slope = 37U; - msg.glide_slope_alt = 0.918224101284; - msg.custom.assign("TWLWXYAKHRTAPFGSKCDOFCBDAMRXSECHEOAIOXDYJQYHVUZOGITFOEGVAZEZYUZAJGJZQKYIQJVDODDTUHVKHDERKQSNTIMPQXOYWRTCFWMSVOQAEIHXQUWKFFVTPBRQYDRLSPBOUFIAJSZQMPWMXJZCKMVNHCYTRIGVSATWNHHMLLBWQSZFMGBGBERIEFNAMNCVLNWRBYDICNLGKNUYSOGXJXZHSJUIUDGWRPVTLUXKKU"); + IMC::StateReport msg; + msg.setTimeStamp(0.8326490854976077); + msg.setSource(39251U); + msg.setSourceEntity(15U); + msg.setDestination(24081U); + msg.setDestinationEntity(183U); + msg.stime = 3765107891U; + msg.latitude = 0.5830377511189216; + msg.longitude = 0.21066535514979223; + msg.altitude = 13059U; + msg.depth = 36202U; + msg.heading = 46905U; + msg.speed = -21509; + msg.fuel = -73; + msg.exec_state = 61; + msg.plan_checksum = 1125U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Land #0", msg == *msg_d); + test.boolean("StateReport #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16634,30 +19241,29 @@ main(void) } { - IMC::Land msg; - msg.setTimeStamp(0.557787116396); - msg.setSource(8690U); - msg.setSourceEntity(170U); - msg.setDestination(48064U); - msg.setDestinationEntity(186U); - msg.lat = 0.274956844996; - msg.lon = 0.85180805603; - msg.z = 0.907685270469; - msg.z_units = 162U; - msg.speed = 0.726884651171; - msg.speed_units = 75U; - msg.abort_z = 0.714562327562; - msg.bearing = 0.306390386103; - msg.glide_slope = 145U; - msg.glide_slope_alt = 0.0359343350972; - msg.custom.assign("HWQRFAUDTPJRYKFZQJYZDMFDWWWYOIFJECOFMPLCTKXIOVDKGVQRNQYKYMBORAPXPUWATQSBHNUZRBGCKHMGUJVXHCVILLFWECENQXQLHLHVQBLUSJMCZTTBLFBSJEEEMAXWVKBLNLIZRAMCUOVAOVKTHSTBIDSPYDGVSUTNZVEEUCCKPWMCPAMKWFTYXJSHNRURQBXIGDZOALHKDIZBSGGTQINXZNJ"); + IMC::StateReport msg; + msg.setTimeStamp(0.9147004290232714); + msg.setSource(19570U); + msg.setSourceEntity(23U); + msg.setDestination(4065U); + msg.setDestinationEntity(157U); + msg.stime = 1959086028U; + msg.latitude = 0.5077848016690969; + msg.longitude = 0.8409160938469067; + msg.altitude = 43660U; + msg.depth = 56486U; + msg.heading = 22545U; + msg.speed = -3348; + msg.fuel = -1; + msg.exec_state = -19; + msg.plan_checksum = 19783U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Land #1", msg == *msg_d); + test.boolean("StateReport #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16668,30 +19274,29 @@ main(void) } { - IMC::Land msg; - msg.setTimeStamp(0.197694805452); - msg.setSource(50421U); - msg.setSourceEntity(82U); - msg.setDestination(4171U); - msg.setDestinationEntity(195U); - msg.lat = 0.52654217502; - msg.lon = 0.81475476763; - msg.z = 0.853584545985; - msg.z_units = 184U; - msg.speed = 0.86886308683; - msg.speed_units = 52U; - msg.abort_z = 0.0430551993132; - msg.bearing = 0.248797405948; - msg.glide_slope = 124U; - msg.glide_slope_alt = 0.920388972732; - msg.custom.assign("TRSCZHGJLHQRIFOLBTESLLGRATEYJVGZXLHYDWTRNBEKSLAMPSIORJFBNBVMAW"); + IMC::StateReport msg; + msg.setTimeStamp(0.016008018045276073); + msg.setSource(8322U); + msg.setSourceEntity(253U); + msg.setDestination(32247U); + msg.setDestinationEntity(150U); + msg.stime = 828955104U; + msg.latitude = 0.26259297725858033; + msg.longitude = 0.554767583190569; + msg.altitude = 7609U; + msg.depth = 2917U; + msg.heading = 53449U; + msg.speed = 21358; + msg.fuel = -56; + msg.exec_state = 7; + msg.plan_checksum = 19408U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Land #2", msg == *msg_d); + test.boolean("StateReport #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16701,34 +19306,33 @@ main(void) } } - { - IMC::AutonomousSection msg; - msg.setTimeStamp(0.880474415446); - msg.setSource(42944U); - msg.setSourceEntity(229U); - msg.setDestination(18238U); - msg.setDestinationEntity(240U); - msg.lat = 0.929816538654; - msg.lon = 0.591807141799; - msg.speed = 0.800654761974; - msg.speed_units = 87U; - msg.limits = 32U; - msg.max_depth = 0.603463034496; - msg.min_alt = 0.295258365054; - msg.time_limit = 0.477634193483; - IMC::PolygonVertex tmp_msg_0; - tmp_msg_0.lat = 0.921452448383; - tmp_msg_0.lon = 0.0811592253891; - msg.area_limits.push_back(tmp_msg_0); - msg.controller.assign("MWNWXCCSHLUCEIMJTYSIJKWUOFDLNMCQMLJYCGIISVAQALPBA"); - msg.custom.assign("OMFLRBICNNJLBMLAAZSQGQHGEIPEDEOWFOWAQSTNRUFAWKKJNNYLKEZQVDTZUWLZIDXXUHZPMSVYBACMNZZQECBVYIWHWVJDLVNBDFKEOTCTMGHXBUEKZHOPIKSDCGQHVARJCMXNMCD"); - + { + IMC::TransmissionRequest msg; + msg.setTimeStamp(0.3882584918889296); + msg.setSource(17366U); + msg.setSourceEntity(127U); + msg.setDestination(33288U); + msg.setDestinationEntity(13U); + msg.req_id = 43699U; + msg.comm_mean = 182U; + msg.destination.assign("ITYUBFRTZMGBKLFTUWRMRCONOXTKKIXAMSHPPZPTFLLJPLXPUWZEJGOMOSNCVSYUUIKBRCDQEVXIZJBVCYKGEWGOCGAZHSFAPSFAERVTDABYFHSRHVWRNGIJYDCJCJJTZITOUYHBXUWYJRSEFJPNLGPVEHEDQWSBAMMGDTPDXDKKYNUCQKFWNOEAFHZNKUEQT"); + msg.deadline = 0.3050611500655467; + msg.range = 0.3444969315928329; + msg.data_mode = 132U; + IMC::AnnounceService tmp_msg_0; + tmp_msg_0.service.assign("EILPDAHPYWHCARBIVUQPPFTXPJNAGKWJYLOKDFBKLFMUDBZGXIYSAMVLGBWVS"); + tmp_msg_0.service_type = 123U; + msg.msg_data.set(tmp_msg_0); + msg.txt_data.assign("MSVBERSZQOWHZLCFBLQVUNPWLZNKKDTTJCSRCNEOZAZPCZYLWNZFZGFXEMAQYVXGVUUQTARPTA"); + const signed char tmp_msg_1[] = {-113, -51, -71, 42, 121, -106, -66, 26, 25, -64, -63, 14, 11, 115, -1, 111, -60, 38, -23, 62, 82, 53, -88, -122, -123, -83, -78, -118, -20, -99, -89, -106, 61, -112, -119, -61, -122, -91, -42, -58, -115, 91, 80, 97, -95, 40, -20, -24, -19, -12, -22, -62, 88, -50, -20, -42, 81, 126, 30, -19, -24, 96, -68, -28, -80, 57, 121, -81, 120, 11, -69, 79, -40, -101, -4, 109, -19, 38, 121, 113, -128, -94, -21, 36, -36, -121, -57, 34, -70, 10, -85, -119, 71, -89, -123, -70, 72, 76, 102, -1, -94, 19, 86, 9, 15, 13, -104, -126, 115, -44, 123, 104, -71, 25}; + msg.raw_data.assign(tmp_msg_1, tmp_msg_1 + sizeof(tmp_msg_1)); + try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AutonomousSection #0", msg == *msg_d); + test.boolean("TransmissionRequest #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16739,33 +19343,43 @@ main(void) } { - IMC::AutonomousSection msg; - msg.setTimeStamp(0.824560126581); - msg.setSource(61009U); - msg.setSourceEntity(57U); - msg.setDestination(31981U); - msg.setDestinationEntity(253U); - msg.lat = 0.803030939318; - msg.lon = 0.514887668582; - msg.speed = 0.176009957989; - msg.speed_units = 237U; - msg.limits = 49U; - msg.max_depth = 0.817306746361; - msg.min_alt = 0.0749618535176; - msg.time_limit = 0.105834080445; - IMC::PolygonVertex tmp_msg_0; - tmp_msg_0.lat = 0.850676654734; - tmp_msg_0.lon = 0.299198404797; - msg.area_limits.push_back(tmp_msg_0); - msg.controller.assign("UPGBMSVCDTWZANJAFKGHASFXTMGMDALXXKORBDRVZCPGYDNSUEMEVO"); - msg.custom.assign("EEZDYJVNMOPVKTDDGBHUUICVL"); + IMC::TransmissionRequest msg; + msg.setTimeStamp(0.780186076890062); + msg.setSource(3470U); + msg.setSourceEntity(123U); + msg.setDestination(64960U); + msg.setDestinationEntity(254U); + msg.req_id = 29836U; + msg.comm_mean = 176U; + msg.destination.assign("SKSQNHNZIEDKFGJMDLDFURWX"); + msg.deadline = 0.8095987097252902; + msg.range = 0.8440183097881834; + msg.data_mode = 240U; + IMC::CompassCalibration tmp_msg_0; + tmp_msg_0.timeout = 31033U; + tmp_msg_0.lat = 0.11814132124160581; + tmp_msg_0.lon = 0.10007789098903586; + tmp_msg_0.z = 0.7182039673851365; + tmp_msg_0.z_units = 23U; + tmp_msg_0.pitch = 0.5326958783543031; + tmp_msg_0.amplitude = 0.23334886983756065; + tmp_msg_0.duration = 65321U; + tmp_msg_0.speed = 0.8765711715531737; + tmp_msg_0.speed_units = 252U; + tmp_msg_0.radius = 0.8507993092238308; + tmp_msg_0.direction = 97U; + tmp_msg_0.custom.assign("QIHCJRRZBOEYCXMALBQQKMNSVPCXJITAGYDZWMUDGVWSINRXEWZNQSCDGUSSWDOPKLMXRIYGABPJWBGF"); + msg.msg_data.set(tmp_msg_0); + msg.txt_data.assign("DKJHCEAXEZFDOLNRZPAIBCTWVH"); + const signed char tmp_msg_1[] = {20, -115, 80, -6, 19, -94, -73, 31, 85, 101, -20, -114, 27, -32, 69, 35, 14, -72, 92, -112, 26, -57, 45, 4, -50, -3, 117, 14, 46, -118, -10, 28, -123, -98, 78, -94, 89, -30, 84, 48, 9, 74, 71, -56, -4, -79, -64, -74, 100, 16, -25, -65, -82, 12, -55, 116, -34, 33, 4, -73, -124, 113, 58, -119, -126, -66, -122, -21, -83, -34, 68, 92, -101, -35, 6, -125, 56, -112, 95, 89, -67, -21, -78, -36, 121, 81, 23, -101, 43, 51, 77, 53, -63, 73, -84, -94, 26, -74, -24, 30, 104, -27, -124, 6, 11, 47, 0, -9, -79, 118, -60, -11, -47, 67, -63, -124, 55, 88, -8, -39, 40, 22, 38, 35, 11, -114, 92, -116, 30, 81, 74, 53, -42, -85, 93, 22, 16, -75, -94, 11, -28, 5, 108, -126, 74, 58, 108, 115, -76, 13, -90, -45, -90, 58, 102, -118, 3, -118, 70, -29, -42, -60, 71, 85, -47, 105, 48, -42, -87, -115, -36, 62, -121, 78, -99, 81, -41, 25, -115, 20, -65, -117, 108, -86, -37, 10, -20, -28, 122, -117, -11, 42, -7, -26, -41, -62, -11, -127, -94, 110, 63, -65, 12, -86, -40, -77, 9, 75, -86, -121, -55, -52, 25, 21, 51, -108, 99, -57, 32, 79, 117, -42, -21, 52, -45, -92, -115, -88, 83, -25, 72, -12, 109, -45, 25, -42, -91, -121, -109, -36, 105, 27, 24, 119, 22, -25, 72}; + msg.raw_data.assign(tmp_msg_1, tmp_msg_1 + sizeof(tmp_msg_1)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AutonomousSection #1", msg == *msg_d); + test.boolean("TransmissionRequest #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16776,29 +19390,37 @@ main(void) } { - IMC::AutonomousSection msg; - msg.setTimeStamp(0.981499288533); - msg.setSource(27381U); - msg.setSourceEntity(48U); - msg.setDestination(50445U); - msg.setDestinationEntity(171U); - msg.lat = 0.0356900613589; - msg.lon = 0.732230354006; - msg.speed = 0.0194013278676; - msg.speed_units = 239U; - msg.limits = 107U; - msg.max_depth = 0.930610814481; - msg.min_alt = 0.539349402181; - msg.time_limit = 0.176276821869; - msg.controller.assign("LTLOSXSAWIUAUSENEOGODRJJLRCKANQPLCMXMGBIFAQWWRCBIRSPXZTOSNZWCZCWZCFHWVEGFPEEUEDDXJDNKLGTKVAGVXBX"); - msg.custom.assign("FMUCWTNLNWG"); + IMC::TransmissionRequest msg; + msg.setTimeStamp(0.5374157057918701); + msg.setSource(58833U); + msg.setSourceEntity(28U); + msg.setDestination(50903U); + msg.setDestinationEntity(228U); + msg.req_id = 40082U; + msg.comm_mean = 95U; + msg.destination.assign("WSJGJVODKQVCGPLTCKJESRRMDHPUDGGEHYGFUYQJNSZAYRXSQBYMYUKZIIBPOHBLCOFPLNUTWDASFXLWVXHHPXPVZIIKVCVDDADWITAOCWRBVIQJEJDEPBGXPMCMNNDUCUECIOANVKXSKEDLAVNHKPIYZLRXZORABWZRKEZXAIMHZBQSBUTYOFLMXMQYULWFASXGKSTZAJMRTVBQUWCGQNZ"); + msg.deadline = 0.798977758171559; + msg.range = 0.5679086987730692; + msg.data_mode = 240U; + IMC::RemoteCommand tmp_msg_0; + tmp_msg_0.original_source = 23756U; + tmp_msg_0.destination = 6614U; + tmp_msg_0.timeout = 0.7946824140589818; + IMC::SessionStatus tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.sessid = 4044146924U; + tmp_tmp_msg_0_0.status = 1U; + tmp_msg_0.cmd.set(tmp_tmp_msg_0_0); + msg.msg_data.set(tmp_msg_0); + msg.txt_data.assign("YSAOEVAJFWLRALUDQOMMLGQMOJMGHEWIOPTUDHKSDXIEFVNSPQFMXUZQKGVAWXYHVKGTOLDYWRASSSNSJZILMHVAUVIYPKCCYRRHEMUZDVINSVVNTLDFTXTDEJCDQAAYWGPNQERKIBRBUYOKQFCYNBFNFEPZZXBZXTDIBIZWGCKHJVCPXHKSFTHFUQGQKPOJGJLOKGHARUTHSIMBCOPBNWLIJ"); + const signed char tmp_msg_1[] = {-6, 88, -82, -41, 6, 71, 98, 68, -7, -110, 31, -28, 60, -123, -123, -58, -42, 29, 42, 34, -83, -92, 0, -86, -46, -18, -111, 120, -119, 61, 4, -107, -60, -74, 126, 4, 35, 22, -60, 98, 102, 56, 5, 122, -26, -6, 100, 1, 108, 4, -72, 62, 103, -29, 68, -9, 79, 62, 76, 118, 74, 75, 120, 4, -20, 121, -64, -125, -98, 14, 2, 0, 27, 36, -27, -107, 100, -65, -115, 78, -54, -50, 110, 9, 39, 49, -107, 11, 39, -43, 111, -74, 101, -5, 7, 23, 43, 39, 118, -108, 63, -97, 8, -98, -126, 90, -19, 35, -3, 112, 14, -89, 36, 91, 23, 43, 62, -125, -102, -35, 115, 48, -53, 113, -125, -17, 90, 90, 21, -84, 59, -27, -74, -80, 67, 32, 120, -112, -67, 109, -38, 41, 98, 111, 116, -92, 20, -97, 32, 11, 26, 57, -117, -18, -114, -88, -117, 33, -56, -108, 123, -17, 119, -105, 3, 24, 71, -46, 121, -79, 61, 33, -30, 104, -53, -8, -19, 32, 15, 118, 79, -40, -40, 26, 79, -107, -41, -48, -55, -24, 68, -101, 117, 103, 4, -20, -8, 68, 125, 32, 111, -1, 84, 122, 37, 43, -11, -81, -40, 83, -82, 16, 70, -47, 18, 13, 58, 97, -16, 19, -1, 68, 47, -23, -21, 1, 50, -109, -54, 61, -106, -45}; + msg.raw_data.assign(tmp_msg_1, tmp_msg_1 + sizeof(tmp_msg_1)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AutonomousSection #2", msg == *msg_d); + test.boolean("TransmissionRequest #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16809,27 +19431,23 @@ main(void) } { - IMC::FollowPoint msg; - msg.setTimeStamp(0.33014191505); - msg.setSource(50012U); - msg.setSourceEntity(225U); - msg.setDestination(33047U); - msg.setDestinationEntity(38U); - msg.target.assign("LBFRGLMZBAYCUODFKEKJPOECIYPETGIRNWYMHGCLCYHMURODFALRCEZLFUGWXMVFJIQWALIJTKPHNGFSGIKCUJXNBCBLNHTDZPKOTONIHVMWSQWWVJZKXNQRQDMQZRIDSYJGGKSZAYAYNEUOPOEOQAUPSEVUFZZTSOXPZCUTJCSJFDMKRSFSWQDXNHYXIVGHILDSYQENKILCPTMVXJQTVKLRADHTRGRFBWABBZXTOBYVNBAVHXXMQWUH"); - msg.max_speed = 0.162909468828; - msg.speed_units = 175U; - msg.lat = 0.898041989316; - msg.lon = 0.465701690161; - msg.z = 0.659334146276; - msg.z_units = 230U; - msg.custom.assign("SOFYDGPMBXWIXNWKWQEBDVMTBCLZALXUNMYW"); + IMC::TransmissionStatus msg; + msg.setTimeStamp(0.9778122418656787); + msg.setSource(37967U); + msg.setSourceEntity(24U); + msg.setDestination(44847U); + msg.setDestinationEntity(225U); + msg.req_id = 7533U; + msg.status = 239U; + msg.range = 0.5906995689502266; + msg.info.assign("TSYTQMISBDAUNVYMJZKYUKSUQZXTTFDCZDKKSIVHXZADHKYFOXOR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowPoint #0", msg == *msg_d); + test.boolean("TransmissionStatus #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16840,27 +19458,23 @@ main(void) } { - IMC::FollowPoint msg; - msg.setTimeStamp(0.64286664083); - msg.setSource(16935U); - msg.setSourceEntity(222U); - msg.setDestination(44188U); - msg.setDestinationEntity(213U); - msg.target.assign("ITDBLFGGZUKYWNIJMBSKPHOOLBMKASBXCFKJLDEMNNOUEZBHWONVGGSGNIOCCUGYLTTJDHLRMWKHMIAYTEPZUJAXFERGTKUNRNROPLEUIFXZOWWPQIZZSQMEPTVETVJQHKQAYDLZQUNQXRDJAHM"); - msg.max_speed = 0.146840303444; - msg.speed_units = 15U; - msg.lat = 0.133216496066; - msg.lon = 0.117490559338; - msg.z = 0.917643382371; - msg.z_units = 173U; - msg.custom.assign("LPTCJVJRVRIYPJLEBANFZAXKSWZUEFDUZESQFYTSMFHCNVJCSRAKHWWGKIHIDUDZOICQXPDPFYJKTWKKYFGBVZUEKDCFAVRUOHHQGCSHTQZEMQJKJLVXWBGVQBKDWBHUJGUPDMM"); + IMC::TransmissionStatus msg; + msg.setTimeStamp(0.7363574192175659); + msg.setSource(27298U); + msg.setSourceEntity(234U); + msg.setDestination(55707U); + msg.setDestinationEntity(107U); + msg.req_id = 23273U; + msg.status = 125U; + msg.range = 0.5538482353847346; + msg.info.assign("XEKOSZPWCTZMMTVZBXSPLMJERHSUGRRWVIEIFQPCDGKWONYADGZTPIDZKIPAXITAAROCEAHWSHONHECANAVQUKGKJPZFUQJKJNFZSZGUYEMNRJPEYIRDFYI"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowPoint #1", msg == *msg_d); + test.boolean("TransmissionStatus #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16871,27 +19485,23 @@ main(void) } { - IMC::FollowPoint msg; - msg.setTimeStamp(0.964683230173); - msg.setSource(8385U); - msg.setSourceEntity(74U); - msg.setDestination(36007U); - msg.setDestinationEntity(47U); - msg.target.assign("ANCOYVVPGMBEFOHWUNHTAWUOLUHXFWIQSLSIOCNFGVZJLNXZZMZOJBTNZLUYIIQMHUARKSURKADKKZQREVFGRDCMFGPYNAAHTGDBBYRVFCVGAFFNPXIXFWNLJOMMXMKJOVKVPQIEWBPEEQWLBPHXSXZRTUCIDPJMJYYYETGZLKXGIJYHBDQWXKZLWUSSSGINETPCPETQQWUTWS"); - msg.max_speed = 0.792042924353; - msg.speed_units = 8U; - msg.lat = 0.165672432179; - msg.lon = 0.803361504446; - msg.z = 0.571532834865; - msg.z_units = 239U; - msg.custom.assign("BYBLASGFYGIHYPBULOSBPLEMJWIDPCWCQRIEBQRBDKHAAEFYDXZOKLWTDGTCFNFQ"); + IMC::TransmissionStatus msg; + msg.setTimeStamp(0.28614774650032293); + msg.setSource(36263U); + msg.setSourceEntity(88U); + msg.setDestination(5291U); + msg.setDestinationEntity(246U); + msg.req_id = 35122U; + msg.status = 133U; + msg.range = 0.4472938505251739; + msg.info.assign("QEELLIRKRHBOXRIFMFWTHSVKKLWRDWCWZGGTLKAZGQSJFDIKBYJBXPICBVOMYFFRYBVWWLTEJQZPTXHIJMJZVAUJFNUQTGSEUNUGXPAUYTRXUOTTHFPQYHGOSZWEKN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FollowPoint #2", msg == *msg_d); + test.boolean("TransmissionStatus #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16902,29 +19512,23 @@ main(void) } { - IMC::VehicleState msg; - msg.setTimeStamp(0.842838840615); - msg.setSource(11297U); - msg.setSourceEntity(89U); - msg.setDestination(63367U); - msg.setDestinationEntity(127U); - msg.op_mode = 176U; - msg.error_count = 39U; - msg.error_ents.assign("ZSVPOFDWCMBYEDRNOMHJJHBATUQEEVCGIGDSMYPBIYDDSIIENVNCHCCATAYGYHZXNIUCWWKXKFPPLPDSBVMOTAJJJTAWMTFRDEXPXWHOBUWABWO"); - msg.maneuver_type = 64442U; - msg.maneuver_stime = 0.982097971504; - msg.maneuver_eta = 30456U; - msg.control_loops = 2466548578U; - msg.flags = 173U; - msg.last_error.assign("XRJGTJLDWIBIKGQBTJZEDFLYQMXGUIILBEXGUWUFHANPMUS"); - msg.last_error_time = 0.45632744603; + IMC::SmsRequest msg; + msg.setTimeStamp(0.07337646790191599); + msg.setSource(3963U); + msg.setSourceEntity(28U); + msg.setDestination(58185U); + msg.setDestinationEntity(123U); + msg.req_id = 1822U; + msg.destination.assign("TTUQCOVQMGUKAXULYAHJGDSJWCWBPYLSBJW"); + msg.timeout = 0.35131027998449016; + msg.sms_text.assign("IEPMKITBKKTNAPUGRHITKBZHLDDWFILYQAGOFEBRTPDMQGRIVPROTCULSAXHWVHOHE"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleState #0", msg == *msg_d); + test.boolean("SmsRequest #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16935,29 +19539,23 @@ main(void) } { - IMC::VehicleState msg; - msg.setTimeStamp(0.350768008327); - msg.setSource(52070U); - msg.setSourceEntity(92U); - msg.setDestination(36273U); - msg.setDestinationEntity(200U); - msg.op_mode = 151U; - msg.error_count = 88U; - msg.error_ents.assign("OGRNYXLNLMPMMXVQJDGEJUUUYSLJTZUHKHQLZQCBDVRPENQIQQSGTDIEGRGZOEU"); - msg.maneuver_type = 59603U; - msg.maneuver_stime = 0.111977732871; - msg.maneuver_eta = 27549U; - msg.control_loops = 3695950237U; - msg.flags = 198U; - msg.last_error.assign("QGXRPCFQPSBTJOBHOZWVCMEKTSBTVAHCFHJQCYEGORHQPVAIDRFFWNXNXOWWKCBRNMYUOKCDJTZZFOSNAQONPSBAOREFAERSVUIKQIYXZIZZEWLJMQELYBVGAUSSHHLDBEVIDBFXMTMRAJJLDBIGQEPXXLFGDUZCPZZMNAYCXXYWVUWTIYIMJD"); - msg.last_error_time = 0.097964057034; + IMC::SmsRequest msg; + msg.setTimeStamp(0.8965892280434145); + msg.setSource(37458U); + msg.setSourceEntity(190U); + msg.setDestination(9239U); + msg.setDestinationEntity(128U); + msg.req_id = 61627U; + msg.destination.assign("MQJTOXORVNFUDCUHOGLJGXNUSVYJSWKKHTFNRUPNATHCOCLUDSKGSZHKYPUYKLDDABIICPVYDFEZQWKHPFCIVBLZDMEJBWRJS"); + msg.timeout = 0.21581745495917737; + msg.sms_text.assign("CRZEZHUYYOWMKCYGIPEKNDZEFFMSVZHKNBTYEAMPYRQSRZPCFGWXSSIVPVHYTHNCTLUEDITEGNJBGVOFLJVBHWJJMOCSSANGDHMXDJFWEIGTLQEWARLRKUQGSPMAKPVUWFXS"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleState #1", msg == *msg_d); + test.boolean("SmsRequest #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -16968,29 +19566,23 @@ main(void) } { - IMC::VehicleState msg; - msg.setTimeStamp(0.996544907898); - msg.setSource(10531U); - msg.setSourceEntity(94U); - msg.setDestination(26698U); - msg.setDestinationEntity(250U); - msg.op_mode = 29U; - msg.error_count = 218U; - msg.error_ents.assign("QIYUECNIHNOJNJEVWHBHUJZXCOTRXRACZSQFJKRVQPMRBDTXPFGSWBFNFGPLJSOULZHUNIEBVGEXZAFDBNIIPTWJZ"); - msg.maneuver_type = 35674U; - msg.maneuver_stime = 0.920756642174; - msg.maneuver_eta = 27555U; - msg.control_loops = 666442757U; - msg.flags = 66U; - msg.last_error.assign("DUFPFHLLRSZVSMMGUPFQGGAGULCOIXBKOJKTFHZGRKLIHIANSYCQAVZIKXDOTTDMDMHRTGFNLUYBSDBGZSPGRITBXWCSQGWBUEYEBWKJQNEXCIQHMEXYEHLQWBWVJDSEEVTAPWATAYOJPVUKJAQTUWKSMPUDOLMQODZHNMYZVIJCCRDXIEZNRCYPVFNOZBCKQOBVYLZRIY"); - msg.last_error_time = 0.596324557823; + IMC::SmsRequest msg; + msg.setTimeStamp(0.7800516491746393); + msg.setSource(63646U); + msg.setSourceEntity(130U); + msg.setDestination(58523U); + msg.setDestinationEntity(70U); + msg.req_id = 9078U; + msg.destination.assign("NVUUABEXBMLSHLPGZKPQWIHAJUBYXTYXGNNJHBIMMATEBTZPTJXACLXIXCWHIDSJDEIYZGCDPFEPVNKUSRVHANPKXRRPWXTIFWFYTSLMVVVZYDFGQHYKMMHVYENBQQCDTOAVUQBEHMWNSONLTLRDGXBZAFDUSWKOAFJFVKNTEOCRWRKOLZGGFOJJSUMPEW"); + msg.timeout = 0.7647981074061625; + msg.sms_text.assign("JQHZWXCDEHLNVJMEKEQNBIIIRTZFDO"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleState #2", msg == *msg_d); + test.boolean("SmsRequest #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17001,34 +19593,22 @@ main(void) } { - IMC::VehicleCommand msg; - msg.setTimeStamp(0.365490470947); - msg.setSource(44593U); - msg.setSourceEntity(133U); - msg.setDestination(58279U); - msg.setDestinationEntity(3U); - msg.type = 194U; - msg.request_id = 51498U; - msg.command = 144U; - IMC::FollowPoint tmp_msg_0; - tmp_msg_0.target.assign("OGPFEFOAJHBWZLLWCGMTPKXBKNTAFNMYCSPUNYZVYUEXBYVJECWXLLRXBFVYCJBLSTGHGROXRCSWRDHSKMYEQWWXRFWNODGRSHGVJZJPDUQOHTNFJIDTMLESEZILYIHZNLDUOAIQHKXZPHNWQTPBSBUGPFNLIBRKHRZNZMGXSAMSCSJELMNWVKIQKAXECGQJKFMOAACFEQTUOYYPIEQVZJFDUCD"); - tmp_msg_0.max_speed = 0.709728087282; - tmp_msg_0.speed_units = 236U; - tmp_msg_0.lat = 0.509095362049; - tmp_msg_0.lon = 0.516345364728; - tmp_msg_0.z = 0.913676411854; - tmp_msg_0.z_units = 45U; - tmp_msg_0.custom.assign("WBZPYHTJSANMVRZH"); - msg.maneuver.set(tmp_msg_0); - msg.calib_time = 50692U; - msg.info.assign("LLPGXOUTQWXXHWBNLZNDUPUSMTRFMIINJXGE"); + IMC::SmsStatus msg; + msg.setTimeStamp(0.6080561486256888); + msg.setSource(23505U); + msg.setSourceEntity(120U); + msg.setDestination(31436U); + msg.setDestinationEntity(120U); + msg.req_id = 31392U; + msg.status = 253U; + msg.info.assign("QSBNSERQQFVVAYBNRTVORMGMCIKQIVQBMAVEDMYUENSAMWOCUFYVEDPBWWJYKCQDYESRJXLHBUPHRZPCPOGHAIXJCVKEUSTUFTNZLPEGZDJJYSAZCTGWEMMIOBLQLGFQKHVXLMXJFOUKP"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleCommand #0", msg == *msg_d); + test.boolean("SmsStatus #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17039,39 +19619,22 @@ main(void) } { - IMC::VehicleCommand msg; - msg.setTimeStamp(0.547219662291); - msg.setSource(8107U); - msg.setSourceEntity(240U); - msg.setDestination(34511U); - msg.setDestinationEntity(105U); - msg.type = 133U; - msg.request_id = 27680U; - msg.command = 168U; - IMC::CompassCalibration tmp_msg_0; - tmp_msg_0.timeout = 46193U; - tmp_msg_0.lat = 0.765544640011; - tmp_msg_0.lon = 0.66042396488; - tmp_msg_0.z = 0.727751962025; - tmp_msg_0.z_units = 52U; - tmp_msg_0.pitch = 0.647174676357; - tmp_msg_0.amplitude = 0.929972550889; - tmp_msg_0.duration = 35546U; - tmp_msg_0.speed = 0.631977133017; - tmp_msg_0.speed_units = 84U; - tmp_msg_0.radius = 0.574209105706; - tmp_msg_0.direction = 80U; - tmp_msg_0.custom.assign("IKZPVMXXCQQECZSWABVYGSUOKAPRMLHQPACJSOOPDCXUBLWEJPAXVJHJLWTWDNMFRTWHOVTAOWUVWGRPXZXRWYHHKQEZKDUMDDBMCFBYWFJHDRVXJLTHIGKASEUBOMYLOCMTIQECBYXIZTUIJDEFKGCIUDNZLZTLMKNCJAEJLAHONBEQIVL"); - msg.maneuver.set(tmp_msg_0); - msg.calib_time = 47532U; - msg.info.assign("GZVPYTWCVZWJRUHGZYBZFVQFKKVHPBNHODANYXQWOVMHLWVSREOTDRIQMYVJQRLEKRFTPKUN"); + IMC::SmsStatus msg; + msg.setTimeStamp(0.970621211394535); + msg.setSource(1769U); + msg.setSourceEntity(14U); + msg.setDestination(37365U); + msg.setDestinationEntity(203U); + msg.req_id = 47460U; + msg.status = 151U; + msg.info.assign("SXGAMHFYRWUIHTOXIBASOVMQZPMLXVSRSDTJJLUVPDNBATEMRKTQBSWOGEWIZTMEVRKTLQOFKHQWETLZGXWNCLLVOUZWZEJSUQTTZOUEYLQASHDDCZHHVIKYOECCQYGQFKMOLUPGJNPXUJNQIKIFCCDCKHHJFSWJVUZJRBAYMOUSDIBLZMRGDYRBDMGYSFPKVAQFNEK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleCommand #1", msg == *msg_d); + test.boolean("SmsStatus #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17082,28 +19645,22 @@ main(void) } { - IMC::VehicleCommand msg; - msg.setTimeStamp(0.381183170992); - msg.setSource(9256U); - msg.setSourceEntity(21U); - msg.setDestination(19507U); - msg.setDestinationEntity(224U); - msg.type = 145U; - msg.request_id = 29886U; - msg.command = 72U; - IMC::IdleManeuver tmp_msg_0; - tmp_msg_0.duration = 22936U; - tmp_msg_0.custom.assign("CPCIBBRWAKASEPZXVVRSKMICXGMUQHOLMJDMTGDULVJTKXOHMHVCZNDFAUFZYVLJKXCIZWUQTIIQYGEPRBLLAFBDATQWHXJPNKXMEKVZTIRRDZUUUNXBOIOCEHOPBIGSPSGVXARWDPNDENWFOHG"); - msg.maneuver.set(tmp_msg_0); - msg.calib_time = 23850U; - msg.info.assign("UYPRTAAWJIKBOGNQODYSBOULRBLWGKLJNQFAUYXTUIZIXHVMVTNDVZBXZLJYLUGONYBZFETSELRQJMSXQTSAUTDMWZGRCEGITNVZHFCKGUMFHMCEWFDSXZSVAPIQZUJAJKBELGJFHDDVILVVQPWRCBJKQEXKVYKOISPFBKRRHRYMECWSZCNJBXHOPRBHNTDJOEHEXNMIVWCWNGRICIPKAYOHQTLCKOMWNFSMPL"); + IMC::SmsStatus msg; + msg.setTimeStamp(0.5070583399547103); + msg.setSource(28344U); + msg.setSourceEntity(104U); + msg.setDestination(40443U); + msg.setDestinationEntity(112U); + msg.req_id = 7489U; + msg.status = 169U; + msg.info.assign("MEDCNYHUHOILTZZURPJFBEIVOESIPXJIIBSDNMZYMUGPGRADUXUWKTERUFBKEDFNLUFMDRZSHNYQESDQSLYOSSORVPAJENCWSBWVNKFTLPZEMJQKXJRGYEGZXNBBGYKRAGVGTHQLCOOJWTFBRBFNXCUQHOCAQQCOFQC"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleCommand #2", msg == *msg_d); + test.boolean("SmsStatus #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17114,21 +19671,20 @@ main(void) } { - IMC::MonitorEntityState msg; - msg.setTimeStamp(0.59954439565); - msg.setSource(41221U); - msg.setSourceEntity(29U); - msg.setDestination(6997U); - msg.setDestinationEntity(0U); - msg.command = 60U; - msg.entities.assign("DRFWZCUYASZOBPBQIJENYFSDAQOSWIAOAAFKTGMQHBLPWKQCHBYBTWVNSEERCNTUGOQYZDSICPUGIVHEXLRMNBVGIKPCGNOQMOZFAOAWHLAWLEAMPRQFJKXORICANXKWDGLPJRVDYKEUBDRBCSTYJQUFJHHMXKGXXUTTFZYLSUZBFGCJHNQLXNYEPNZGZOMWZETFYVXDLSLFPTMJGBMVRNDJMT"); + IMC::VtolState msg; + msg.setTimeStamp(0.22243732504123548); + msg.setSource(17592U); + msg.setSourceEntity(210U); + msg.setDestination(45096U); + msg.setDestinationEntity(179U); + msg.state = 122U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MonitorEntityState #0", msg == *msg_d); + test.boolean("VtolState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17139,21 +19695,20 @@ main(void) } { - IMC::MonitorEntityState msg; - msg.setTimeStamp(0.465301533689); - msg.setSource(44054U); - msg.setSourceEntity(42U); - msg.setDestination(6024U); - msg.setDestinationEntity(183U); - msg.command = 170U; - msg.entities.assign("QUNDFJBNDPVPXIFTCYXMGKICCZKVIACTELQSVBQEMKWPEASIUKZFFMDUYJYVJLQBXOHGYCEAHOTBZANMTMQHYJNYFBOVHFHDERIGZAUIJUHSNEZGGFPDWRFYIPLSXSPSBMWIQDMQJFSWVGZRJOZVHKRCRLWVFBUD"); + IMC::VtolState msg; + msg.setTimeStamp(0.9656859059381023); + msg.setSource(215U); + msg.setSourceEntity(102U); + msg.setDestination(45343U); + msg.setDestinationEntity(152U); + msg.state = 167U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MonitorEntityState #1", msg == *msg_d); + test.boolean("VtolState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17164,21 +19719,20 @@ main(void) } { - IMC::MonitorEntityState msg; - msg.setTimeStamp(0.784061266864); - msg.setSource(31237U); - msg.setSourceEntity(101U); - msg.setDestination(43986U); - msg.setDestinationEntity(181U); - msg.command = 174U; - msg.entities.assign("NCWUVFMJSYLIJDASBRYAPEHJHLQMOZOVKTMOEHPVZXOYRWLJCVZIECCGYADDEPUGRTILFVIINAJQKVTGVHCNKYBFKUJSTHNWWBHPJBPRPTDTEYVDCXNMSXVLKBJXWUIZH"); + IMC::VtolState msg; + msg.setTimeStamp(0.9913879097520566); + msg.setSource(32364U); + msg.setSourceEntity(102U); + msg.setDestination(60583U); + msg.setDestinationEntity(220U); + msg.state = 203U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MonitorEntityState #2", msg == *msg_d); + test.boolean("VtolState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17189,27 +19743,20 @@ main(void) } { - IMC::EntityMonitoringState msg; - msg.setTimeStamp(0.0746233054807); - msg.setSource(17210U); - msg.setSourceEntity(89U); - msg.setDestination(25644U); - msg.setDestinationEntity(228U); - msg.mcount = 188U; - msg.mnames.assign("JRXJCREZGOBAMJUEGXXBYBMMYEFVDJTXMUSIPVFIHBLJHASFNEYKAQLNRQOOQIWKBXNODZPQUGVZSBWLWBRLRVQZXPOYPSTFHZFJPJKVQTUYDRUWSILFUKI"); - msg.ecount = 231U; - msg.enames.assign("CSMNZEIMBLQBGZIIABYUSMFUOLFQZMBKYAEMVGULFDJTBFBCT"); - msg.ccount = 11U; - msg.cnames.assign("SQIPCXDUAATENYKBSTRIBCNJURISJXJRMSVJEWATHFDLEVHLEOEAMECWGAXBEUQHCGYURWZIFYCDVU"); - msg.last_error.assign("ICDXFUYLCOVSTFHLWZGGBRBYKJTRMVEBZGJJGNAQWUNZPKSGALPGTKCAGYKDYGZWWFFDYBTCNMVQOTWXCBQOEPEIFAIVSFNHXTRZOHRZUAXCSKMHEMTPUEVIRVBDTQSUCXAIHXIAPEKNNXMEDMLCPOOJSKQAVVLWIUIVWFBSKMPUXXESIHWLKPJLLISEWFRBPKOYSPVMZFQADREDOXCZCDYDLQTOBNZDMHYFG"); - msg.last_error_time = 0.576076905399; + IMC::ArmingState msg; + msg.setTimeStamp(0.6220156315757316); + msg.setSource(11853U); + msg.setSourceEntity(54U); + msg.setDestination(48237U); + msg.setDestinationEntity(182U); + msg.state = 152U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityMonitoringState #0", msg == *msg_d); + test.boolean("ArmingState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17220,27 +19767,20 @@ main(void) } { - IMC::EntityMonitoringState msg; - msg.setTimeStamp(0.269312357895); - msg.setSource(51992U); - msg.setSourceEntity(128U); - msg.setDestination(8648U); - msg.setDestinationEntity(233U); - msg.mcount = 6U; - msg.mnames.assign("OKSTQTEZYGNLOBIUTDKNMWFORJXEYMAWDIXBONEZUBNCGNWCSVMMGFEZCAVAUJPSETOXBJLCKGTNHBXVDXQRHJEBNSLGTHUHTCSDRUH"); - msg.ecount = 182U; - msg.enames.assign("IIDAIEZRHUYMEVFHHPL"); - msg.ccount = 42U; - msg.cnames.assign("KYLQGSBGJIKPZTISPXKDNMCZOOVFUZHIBBCZALJGUOJSLJEFYOWMPARIMUQMWCAWKMDRAODVNDAKLXDKRBFGDPEFVUVZEYXJPXHABSFMZVOWMDNQXCHFBGTLSJKHUTFCVCTVBYLFPTIEJZWQINNGDHJNSAXQHINMWTYZVWRSLOFHZWRKNESQQNQEUEBA"); - msg.last_error.assign("STMPLUIEXTRTKMHORINICFYGRWLQNWTCLYUEENVHGZFIFGUPKCRAESKFHVCWUIANSAXJJZQUKWNWKOBMABTREQAKDWTVZNMLHOWJZJXUEPTQRYODMDQJNSDESCUXBCL"); - msg.last_error_time = 0.281767220296; + IMC::ArmingState msg; + msg.setTimeStamp(0.5521176833653298); + msg.setSource(56323U); + msg.setSourceEntity(139U); + msg.setDestination(28499U); + msg.setDestinationEntity(229U); + msg.state = 66U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityMonitoringState #1", msg == *msg_d); + test.boolean("ArmingState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17251,27 +19791,20 @@ main(void) } { - IMC::EntityMonitoringState msg; - msg.setTimeStamp(0.690323295323); - msg.setSource(35267U); - msg.setSourceEntity(196U); - msg.setDestination(40834U); - msg.setDestinationEntity(19U); - msg.mcount = 209U; - msg.mnames.assign("PWRMSEWIBSTJOHIAIMLQWXXKLRCUNUAN"); - msg.ecount = 129U; - msg.enames.assign("MKXGRNNMLUEMFWFUZQKOCGNAJFQTPCUZNVSWTUDEWFVHMTAQKWRODRBWLBEGZHFJKAPDOSGKBUPSSAIUZIMTBRDPCLEHJDKH"); - msg.ccount = 124U; - msg.cnames.assign("VZTICRGPDDVSCPCXGWAVNKEKYEQNPZPMABBZPDOIACVGFWTUCIRFQBKORTEJJHEMYWRBXEETFQVSLJOIJKXPNOGLDQ"); - msg.last_error.assign("IPPEMLEOODCVBMGKBLJKVANNFQEYF"); - msg.last_error_time = 0.130628750004; + IMC::ArmingState msg; + msg.setTimeStamp(0.7709569595102478); + msg.setSource(45468U); + msg.setSourceEntity(130U); + msg.setDestination(56894U); + msg.setDestinationEntity(65U); + msg.state = 125U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityMonitoringState #2", msg == *msg_d); + test.boolean("ArmingState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17282,31 +19815,25 @@ main(void) } { - IMC::OperationalLimits msg; - msg.setTimeStamp(0.296352482632); - msg.setSource(6082U); - msg.setSourceEntity(109U); - msg.setDestination(19231U); - msg.setDestinationEntity(194U); - msg.mask = 82U; - msg.max_depth = 0.571543555118; - msg.min_altitude = 0.138375196228; - msg.max_altitude = 0.162831400796; - msg.min_speed = 0.443852040777; - msg.max_speed = 0.767886528379; - msg.max_vrate = 0.348790541057; - msg.lat = 0.645831618271; - msg.lon = 0.903249482413; - msg.orientation = 0.128789997063; - msg.width = 0.175771871131; - msg.length = 0.525014062141; + IMC::TCPRequest msg; + msg.setTimeStamp(0.7515049960646696); + msg.setSource(42666U); + msg.setSourceEntity(212U); + msg.setDestination(42418U); + msg.setDestinationEntity(128U); + msg.req_id = 36091U; + msg.destination.assign("UXQACGICGOQTTADFRTSXHRPKGZIVDGTUSLSQYZJMQSGFJUVAOPKBZZDYHBLJPUZHKSPVVCRXPDSDEJVPKLKWFBAGGRJDIVKXVUNWTYFPPPQEYHWSKKMQBAIMNBCFCAVENZGWUXROUMFH"); + msg.timeout = 0.5114960254270131; + IMC::WaterDensity tmp_msg_0; + tmp_msg_0.value = 0.13468499004210133; + msg.msg_data.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("OperationalLimits #0", msg == *msg_d); + test.boolean("TCPRequest #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17317,31 +19844,28 @@ main(void) } { - IMC::OperationalLimits msg; - msg.setTimeStamp(0.750631201867); - msg.setSource(17732U); - msg.setSourceEntity(92U); - msg.setDestination(3670U); - msg.setDestinationEntity(91U); - msg.mask = 175U; - msg.max_depth = 0.0386033563905; - msg.min_altitude = 0.411041109082; - msg.max_altitude = 0.74733726799; - msg.min_speed = 0.231510028703; - msg.max_speed = 0.732240357802; - msg.max_vrate = 0.148833768436; - msg.lat = 0.95289467598; - msg.lon = 0.930578096683; - msg.orientation = 0.635274451319; - msg.width = 0.494708387164; - msg.length = 0.0782728268478; + IMC::TCPRequest msg; + msg.setTimeStamp(0.840220767607039); + msg.setSource(5477U); + msg.setSourceEntity(105U); + msg.setDestination(57907U); + msg.setDestinationEntity(21U); + msg.req_id = 45888U; + msg.destination.assign("GHQDCXAQZECVTIZACZOSDNNACDEGRAMBOZFLHAXVLJGZITGFVBFQMYOKQFLNXUPVCTBUEFFAZIBRQYHKWKGXVQKYZRORJQMSYNTWXJMRXYTUGUHTIUCJZVEYTNVPAPKPFNVWYHWPOWLERGOIOJPUH"); + msg.timeout = 0.1963657418504856; + IMC::DevCalibrationState tmp_msg_0; + tmp_msg_0.total_steps = 87U; + tmp_msg_0.step_number = 121U; + tmp_msg_0.step.assign("EKYAHEUSOUIWWZGDFIUCLRPENTTZMHXOWOBRSHHFGIDEFJQVEQJQCXPVZQKIEORRIWYDTLOP"); + tmp_msg_0.flags = 54U; + msg.msg_data.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("OperationalLimits #1", msg == *msg_d); + test.boolean("TCPRequest #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17352,31 +19876,24 @@ main(void) } { - IMC::OperationalLimits msg; - msg.setTimeStamp(0.554734017952); - msg.setSource(25282U); - msg.setSourceEntity(29U); - msg.setDestination(42633U); - msg.setDestinationEntity(22U); - msg.mask = 40U; - msg.max_depth = 0.347757500067; - msg.min_altitude = 0.304698371081; - msg.max_altitude = 0.906414841726; - msg.min_speed = 0.855811038617; - msg.max_speed = 0.643755556925; - msg.max_vrate = 0.808465904123; - msg.lat = 0.667652593396; - msg.lon = 0.81690593822; - msg.orientation = 0.922394843426; - msg.width = 0.622872754711; - msg.length = 0.55874162325; + IMC::TCPRequest msg; + msg.setTimeStamp(0.1044085926216135); + msg.setSource(8518U); + msg.setSourceEntity(78U); + msg.setDestination(22521U); + msg.setDestinationEntity(109U); + msg.req_id = 41238U; + msg.destination.assign("DJIPLUUFAZACQDTMVBPOJNZJUNXJSEHNXSWLPGFFADIFJTRMRZASCNAIJSWSTEQKRLESGCIVYXCNFKCQHEZVPHGZKQAMFEGWJRWNYRABPIRVXOBBYGGTUEMDLHWXHQRVFBNHONGRYMLXQPTDLJCOGXCHWBBMLDTKZTQAFVBKLMHKVMQYOXNSPUOIWMSYGSHEBDCOIJSGNOREWKCDEIRQKYYALJZWEHZVCZKPWTOUZTUIPQXFAMPBYLDUDUFK"); + msg.timeout = 0.004970345844775403; + IMC::QueryPowerChannelState tmp_msg_0; + msg.msg_data.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("OperationalLimits #2", msg == *msg_d); + test.boolean("TCPRequest #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17387,19 +19904,22 @@ main(void) } { - IMC::GetOperationalLimits msg; - msg.setTimeStamp(0.324453355654); - msg.setSource(56924U); - msg.setSourceEntity(5U); - msg.setDestination(14471U); - msg.setDestinationEntity(174U); + IMC::TCPStatus msg; + msg.setTimeStamp(0.19431657098307797); + msg.setSource(31207U); + msg.setSourceEntity(168U); + msg.setDestination(9365U); + msg.setDestinationEntity(114U); + msg.req_id = 5252U; + msg.status = 166U; + msg.info.assign("ZEPJFUNTEMGJMUDMXLNXWMONMFYTDCRCEYBLVFHQBPAAJYZQGCKQAPONLVHSHKBRRDRTBLTFIAUMQWTBWQTKKNBRSAERXZTISGKAKGPFHRVCRPUSZLOHKPXCISPBXDWYWVEOOAVIOGGNWRUCYLYNHUXFJZAIIFSJGZ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetOperationalLimits #0", msg == *msg_d); + test.boolean("TCPStatus #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17410,19 +19930,22 @@ main(void) } { - IMC::GetOperationalLimits msg; - msg.setTimeStamp(0.614082684907); - msg.setSource(20148U); - msg.setSourceEntity(88U); - msg.setDestination(16955U); - msg.setDestinationEntity(127U); + IMC::TCPStatus msg; + msg.setTimeStamp(0.8407995487202578); + msg.setSource(29867U); + msg.setSourceEntity(223U); + msg.setDestination(44246U); + msg.setDestinationEntity(238U); + msg.req_id = 17172U; + msg.status = 63U; + msg.info.assign("VXOYLTYPEVSXKKNJCERRJLZNXHAIRNWXRVRFSDSLICBQPJQXYOTWRDEMMBEPHJZOBKTGQJKGURULKRJIHTIGVHHXSGKLPSUWZAHDEFOSEPKMHFICQELUILWAZVZCGTGHBJDFWDZMCNVBFBLTZNSIPHZLZEWXVXFAPWEMVOGNQCDUGFADFDKYYUWVQHMMYOXKPNMQJIEMSBUFFUJKAQBTLNTYOWSAAGCWYPNOUXTAQCGOYMRTDR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetOperationalLimits #1", msg == *msg_d); + test.boolean("TCPStatus #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17433,19 +19956,22 @@ main(void) } { - IMC::GetOperationalLimits msg; - msg.setTimeStamp(0.085036128597); - msg.setSource(887U); - msg.setSourceEntity(174U); - msg.setDestination(15283U); - msg.setDestinationEntity(190U); + IMC::TCPStatus msg; + msg.setTimeStamp(0.27240278057062495); + msg.setSource(25812U); + msg.setSourceEntity(127U); + msg.setDestination(25257U); + msg.setDestinationEntity(178U); + msg.req_id = 58741U; + msg.status = 71U; + msg.info.assign("QJBLQSCIDWQQAAFYARJJXEAFKAEEOREZBDELRNTXNYUSOBENVKGZFYCYXFRWHCYZ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetOperationalLimits #2", msg == *msg_d); + test.boolean("TCPStatus #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17456,20 +19982,19 @@ main(void) } { - IMC::Calibration msg; - msg.setTimeStamp(0.119214107769); - msg.setSource(53838U); - msg.setSourceEntity(18U); - msg.setDestination(51472U); - msg.setDestinationEntity(98U); - msg.duration = 36969U; + IMC::Abort msg; + msg.setTimeStamp(0.9609913662471705); + msg.setSource(41234U); + msg.setSourceEntity(155U); + msg.setDestination(31601U); + msg.setDestinationEntity(90U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Calibration #0", msg == *msg_d); + test.boolean("Abort #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17480,20 +20005,19 @@ main(void) } { - IMC::Calibration msg; - msg.setTimeStamp(0.962780701125); - msg.setSource(4559U); - msg.setSourceEntity(187U); - msg.setDestination(40151U); - msg.setDestinationEntity(117U); - msg.duration = 53579U; + IMC::Abort msg; + msg.setTimeStamp(0.8971661986074398); + msg.setSource(8345U); + msg.setSourceEntity(21U); + msg.setDestination(19595U); + msg.setDestinationEntity(25U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Calibration #1", msg == *msg_d); + test.boolean("Abort #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17504,20 +20028,19 @@ main(void) } { - IMC::Calibration msg; - msg.setTimeStamp(0.692039217194); - msg.setSource(6501U); - msg.setSourceEntity(241U); - msg.setDestination(61550U); - msg.setDestinationEntity(80U); - msg.duration = 45944U; + IMC::Abort msg; + msg.setTimeStamp(0.4013959399194381); + msg.setSource(35271U); + msg.setSourceEntity(130U); + msg.setDestination(30029U); + msg.setDestinationEntity(10U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Calibration #2", msg == *msg_d); + test.boolean("Abort #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17528,22 +20051,69 @@ main(void) } { - IMC::ControlLoops msg; - msg.setTimeStamp(0.196670303314); - msg.setSource(41262U); - msg.setSourceEntity(234U); - msg.setDestination(13962U); - msg.setDestinationEntity(150U); - msg.enable = 85U; - msg.mask = 1349985552U; - msg.scope_ref = 3566988146U; + IMC::PlanSpecification msg; + msg.setTimeStamp(0.08880438819182457); + msg.setSource(2024U); + msg.setSourceEntity(135U); + msg.setDestination(25033U); + msg.setDestinationEntity(239U); + msg.plan_id.assign("LPSTQHLHWCPHYRFSVJNHPNEUQXWGUUKHAZNUFAFBGHLTLOFKQAEGITNPGFXXXIWRCTJDLDJBDCWHJKFLELSJDZAROKBUTEHGBKVVKAQRERCFQULJOHEMODLGHXQRCLGASAYKRVAYCFWIDXUICIIYQQZAWEBMFBGPACZDZOUKVDYIMBISJYWZPPYGDZEINNTRRQPVZPYYMBFXVMDVQSGKMCWXEMUSOSBNORIZJETXTTVPCMSBMTJU"); + msg.description.assign("WRUPNRDHWWNTZDIKLAZULMSXHKFHSWHYKGPAZSLBQVQMSHRUUGCYGWTKHOYVKIIFTPBVXQBCMTMJDVDTDVJZRDEM"); + msg.vnamespace.assign("TRMZKGHLEIMYMHDQXGPQGMWXNEZFMCTOCBWLGZZAKCYWEXPLQJUNQCEPIJNPHTHBTBSGGUVJDEKBANAKTPSHUJZMRLFQCIQJFYGBVHDFFVKOSOAXWFVDDIUPCUFSDMSSNUYKXVULJXMWPOWQARGBZRZULIJWKROOWGEDNEJVOSNVURFLSNIYX"); + msg.start_man_id.assign("EFHLQQWKGELDCYTQFIPUTSERCWFERARZYBSBSPGGQIHTYDGAPGZNIPIDTODEELMNFQTXCSEFANCFR"); + IMC::PlanManeuver tmp_msg_0; + tmp_msg_0.maneuver_id.assign("VMGQTFYRTAVTPMKBOABPDBKQRPNHEBASIZHPDHNDHQADRQXMJKMKCAHNHMAIFTWSSBGXHPWEIGOSLHJISJOJXUSDRERFFLDQANMCFMCLHIXYVJPESBLSK"); + IMC::YoYo tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.timeout = 13758U; + tmp_tmp_msg_0_0.lat = 0.8438471508456921; + tmp_tmp_msg_0_0.lon = 0.052463268726073875; + tmp_tmp_msg_0_0.z = 0.31065512775594484; + tmp_tmp_msg_0_0.z_units = 64U; + tmp_tmp_msg_0_0.amplitude = 0.9812271470356071; + tmp_tmp_msg_0_0.pitch = 0.6476425245996948; + tmp_tmp_msg_0_0.speed = 0.736069056453985; + tmp_tmp_msg_0_0.speed_units = 214U; + tmp_tmp_msg_0_0.custom.assign("YEOOVZLGSOFKQAGLWDMVQGFXXHWIYSIFUZSTSOXTLFNWVQFMPCCVIZTNXWRDDOUDVGFR"); + tmp_msg_0.data.set(tmp_tmp_msg_0_0); + IMC::Temperature tmp_tmp_msg_0_1; + tmp_tmp_msg_0_1.value = 0.2797453218561434; + tmp_msg_0.end_actions.push_back(tmp_tmp_msg_0_1); + msg.maneuvers.push_back(tmp_msg_0); + IMC::LeaderState tmp_msg_1; + tmp_msg_1.group_name.assign("BTZQFTPUYFVEZMWJWLLRSCSCTBTJEVCMJCKHTFPTYINBJKIWEWHKNHMSNRPUDQJLULDAGZASLESQZOAEALVXYLIHOBTPXFIUPYHWXVXMQBJIORISSKFHXXOEXYWZGURQHUNQZCPGKAA"); + tmp_msg_1.op = 105U; + tmp_msg_1.lat = 0.554041122440794; + tmp_msg_1.lon = 0.009989804764155119; + tmp_msg_1.height = 0.47707786574086775; + tmp_msg_1.x = 0.7925454071119441; + tmp_msg_1.y = 0.2330992442877038; + tmp_msg_1.z = 0.6422654496120013; + tmp_msg_1.phi = 0.9263849373065274; + tmp_msg_1.theta = 0.387520563528992; + tmp_msg_1.psi = 0.0065164923027795085; + tmp_msg_1.vx = 0.017946201440068088; + tmp_msg_1.vy = 0.1963950985456938; + tmp_msg_1.vz = 0.12062447218711814; + tmp_msg_1.p = 0.5306271396761406; + tmp_msg_1.q = 0.07292168785931896; + tmp_msg_1.r = 0.32356451897506533; + tmp_msg_1.svx = 0.3812566824551976; + tmp_msg_1.svy = 0.8292404465920218; + tmp_msg_1.svz = 0.8291103079961202; + msg.start_actions.push_back(tmp_msg_1); + IMC::MagneticField tmp_msg_2; + tmp_msg_2.time = 0.39489983847581434; + tmp_msg_2.x = 0.38298736048607096; + tmp_msg_2.y = 0.4316855860338953; + tmp_msg_2.z = 0.08046269333463874; + msg.end_actions.push_back(tmp_msg_2); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ControlLoops #0", msg == *msg_d); + test.boolean("PlanSpecification #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17554,22 +20124,55 @@ main(void) } { - IMC::ControlLoops msg; - msg.setTimeStamp(0.0356563296193); - msg.setSource(38504U); - msg.setSourceEntity(44U); - msg.setDestination(9242U); - msg.setDestinationEntity(37U); - msg.enable = 35U; - msg.mask = 1927852664U; - msg.scope_ref = 1802554211U; + IMC::PlanSpecification msg; + msg.setTimeStamp(0.9758760387861335); + msg.setSource(10930U); + msg.setSourceEntity(104U); + msg.setDestination(38105U); + msg.setDestinationEntity(207U); + msg.plan_id.assign("MGPBHXSBWTLNZDGUDYPEYOCSKVHILYUASAJIERHK"); + msg.description.assign("ZIHRCTRSJBAFNPPMO"); + msg.vnamespace.assign("JLWQHNVLJUMVDBHGPSZQFCKSLVSNWCCTXOSACBEWGZKJWWQREBIIZAICQDNJGTZYSPUTAQELOBITJPYHYYRFSEXGUJEOKVFXOGGNNPFQUOXDYVMRGTHWAVFSOBMQKL"); + msg.start_man_id.assign("WHCQGBPDPBQNBVSYVVREFUJRNFQVECYGKZZXSJHZDXEBUMYCQVIRGEAANHNHZUMBNPOMOHETWDFMMVNZLSTUBBIRYIZGLKMCFAWSLYWDIQIJEYQGYIGSARPCGWSDLAVBQUOUFKTLPFTCTKGCRJLXZQPWHLAHRIFOOXOJEORGIDBGYPFANQTL"); + IMC::PlanManeuver tmp_msg_0; + tmp_msg_0.maneuver_id.assign("VAKOGMQUWAOZTIORDFEJSCSLNJELMDWYJCWIWUGBNEYHEXYJTJFWKTXOQDGTSGCNPMJKKJVFLXPDZYHXYWKIKYNTPFBAWUUQONRVGXRFCTRUNMDACAEUHETHEFEQXVBACOPHVRQBCBOAZGFNDDGZ"); + IMC::YoYo tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.timeout = 60671U; + tmp_tmp_msg_0_0.lat = 0.8315343659656026; + tmp_tmp_msg_0_0.lon = 0.3520584190804946; + tmp_tmp_msg_0_0.z = 0.9662777755040404; + tmp_tmp_msg_0_0.z_units = 15U; + tmp_tmp_msg_0_0.amplitude = 0.8417744207944498; + tmp_tmp_msg_0_0.pitch = 0.6974099933404374; + tmp_tmp_msg_0_0.speed = 0.33590271653211257; + tmp_tmp_msg_0_0.speed_units = 93U; + tmp_tmp_msg_0_0.custom.assign("BXNZFPCBPTXLJVFWYSREUBUEGTLTOFKANAVCATRQAAXQQFLJBHPIUKXNUWWSHMFYIPURXJIOVNZWINWYDLQHEDRRTQYMUCUDQFTCNBIDAKGGKHDYDRCGHKGXCOYJAZVKMHQUNCYJSSJPSBFDGJSVIWEZZKGKM"); + tmp_msg_0.data.set(tmp_tmp_msg_0_0); + IMC::SetImageCoords tmp_tmp_msg_0_1; + tmp_tmp_msg_0_1.camid = 122U; + tmp_tmp_msg_0_1.x = 39869U; + tmp_tmp_msg_0_1.y = 17511U; + tmp_msg_0.start_actions.push_back(tmp_tmp_msg_0_1); + msg.maneuvers.push_back(tmp_msg_0); + IMC::GetWorldCoordinates tmp_msg_1; + tmp_msg_1.tracking = 246U; + tmp_msg_1.lat = 0.9611995928397791; + tmp_msg_1.lon = 0.7643495451387091; + tmp_msg_1.x = 0.054826301115840526; + tmp_msg_1.y = 0.6341123667470534; + tmp_msg_1.z = 0.16893909748566216; + msg.start_actions.push_back(tmp_msg_1); + IMC::LcdControl tmp_msg_2; + tmp_msg_2.op = 223U; + tmp_msg_2.text.assign("DXFAKVKDBYGCGTQDDWTFNQKCOYGUSRFUOYAGJITWXATBYWREVKNSRHMIRKMZKLVRGIPEWPIXLYJSQIFWAXWZYNTQCD"); + msg.end_actions.push_back(tmp_msg_2); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ControlLoops #1", msg == *msg_d); + test.boolean("PlanSpecification #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17580,22 +20183,43 @@ main(void) } { - IMC::ControlLoops msg; - msg.setTimeStamp(0.33772887309); - msg.setSource(48891U); - msg.setSourceEntity(231U); - msg.setDestination(6824U); - msg.setDestinationEntity(180U); - msg.enable = 50U; - msg.mask = 144637533U; - msg.scope_ref = 1647527343U; + IMC::PlanSpecification msg; + msg.setTimeStamp(0.5859923118024346); + msg.setSource(6548U); + msg.setSourceEntity(142U); + msg.setDestination(9914U); + msg.setDestinationEntity(46U); + msg.plan_id.assign("QOXIXWYSMCQEICBNYZSIFBUDWUAKHRJWBEOGTSQFVMIMYOQUOUPQUOLGKBAYIIFVDXASSCYTKGYZXTSJJWOZJGXZNROUWJDELBPZDUTVGLTORRFDI"); + msg.description.assign("ZOQFSVEEYQVBZJRTIKHTBGNGBKUKXSRDBEAOMKUNTOGJEHDAPBLVTGGXPMHVXCRIFWZEBRNQMEXXIIZCLITIZVYZFHZRPEDNVHWYQPDSPSJURYJBAFAFCHLVQLCUPNYHIZQQJWGSQJTSTWUOUFLXOLSWOHBEYRMHIKEVRWPNFCOXKDUAKNYSEGAMPOQGRCWJLARYCIJYXOFYV"); + msg.vnamespace.assign("RPMJWNHVORDZIUQYHZWELITSKRWNGNCZXOMVFAACXGQITUBMTAGFPPDUNLQWGFIUSUUAWWCKMEFKDERKYPAMJIGOAXZPBJYMXCLDJQLJACJZQTDVYHEYZVVBTGHIHYDNKPVZELTS"); + msg.start_man_id.assign("UPSBXZWGURGCKHKMYKVENPCDMFRDOXWQHQKMSIN"); + IMC::VehicleOperationalLimits tmp_msg_0; + tmp_msg_0.op = 0U; + tmp_msg_0.speed_min = 0.2448892118149697; + tmp_msg_0.speed_max = 0.9302481438310589; + tmp_msg_0.long_accel = 0.7074541064980013; + tmp_msg_0.alt_max_msl = 0.36194897350590705; + tmp_msg_0.dive_fraction_max = 0.15213651879400159; + tmp_msg_0.climb_fraction_max = 0.554492111103034; + tmp_msg_0.bank_max = 0.9644582711167634; + tmp_msg_0.p_max = 0.5732731948177218; + tmp_msg_0.pitch_min = 0.8925184156377961; + tmp_msg_0.pitch_max = 0.5964646540626505; + tmp_msg_0.q_max = 0.2436070856779904; + tmp_msg_0.g_min = 0.38077185728520013; + tmp_msg_0.g_max = 0.31049538667746035; + tmp_msg_0.g_lat_max = 0.4818442599200651; + tmp_msg_0.rpm_min = 0.13900124687820237; + tmp_msg_0.rpm_max = 0.4566377532964331; + tmp_msg_0.rpm_rate_max = 0.039341045559337595; + msg.start_actions.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ControlLoops #2", msg == *msg_d); + test.boolean("PlanSpecification #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17606,20 +20230,40 @@ main(void) } { - IMC::VehicleMedium msg; - msg.setTimeStamp(0.988140223881); - msg.setSource(59979U); - msg.setSourceEntity(163U); - msg.setDestination(57003U); - msg.setDestinationEntity(192U); - msg.medium = 9U; + IMC::PlanManeuver msg; + msg.setTimeStamp(0.5810979389879797); + msg.setSource(16159U); + msg.setSourceEntity(237U); + msg.setDestination(57897U); + msg.setDestinationEntity(79U); + msg.maneuver_id.assign("BABRFKGETWVFVQGABIMHLOQBDKYGYWAOHLVSPYLWETHXGXUTXHHICMYODHWRGPHZIZIBISTNCKYQZJJQPDVCXTZVAXZHJUFSDZVWZQVAGPUXSAJAYFPKEFXCVNXQHWMOERBNRRGBJWEIJJOIRKEBFPCDKUPRCKTWZCKPFJOXEDUMSRUYNMNDYCCRSIQLSTOBRSTIWPGUDLJAVALUMHUYKFZASNZDXNCFDIEMFKEEGLQOSGVMNPBQLLTWO"); + IMC::YoYo tmp_msg_0; + tmp_msg_0.timeout = 62580U; + tmp_msg_0.lat = 0.03520525788355544; + tmp_msg_0.lon = 0.2666053063189462; + tmp_msg_0.z = 0.10825560408907497; + tmp_msg_0.z_units = 26U; + tmp_msg_0.amplitude = 0.6592887042738714; + tmp_msg_0.pitch = 0.8161691386029079; + tmp_msg_0.speed = 0.7375679918995836; + tmp_msg_0.speed_units = 71U; + tmp_msg_0.custom.assign("LFZXGJPZIQCYECGUPYSYRCIYMRZCFIWTFVOTZLRWDTQZWYPMZMVUQNOKDACTEASPVWZYEGWHSZGNLBJIKUCPDTKDOJUXFNKXBOHKVLPHHDMULRUAPLUETRSOICLKZNXDNIIXVANJHSZRQOAAIKPYRSBTXCJNFELGNXTVBFPFQIKSSJOJRUKDAOHTXFJVPQABMDVUEMSREXMOVUYWBLHYNFHQGTBKAHODBMRE"); + msg.data.set(tmp_msg_0); + IMC::FormState tmp_msg_1; + tmp_msg_1.possimerr = 0.8690649935357806; + tmp_msg_1.converg = 0.493195431167768; + tmp_msg_1.turbulence = 0.8377424811820794; + tmp_msg_1.possimmon = 253U; + tmp_msg_1.commmon = 168U; + tmp_msg_1.convergmon = 194U; + msg.start_actions.push_back(tmp_msg_1); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleMedium #0", msg == *msg_d); + test.boolean("PlanManeuver #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17630,20 +20274,44 @@ main(void) } { - IMC::VehicleMedium msg; - msg.setTimeStamp(0.908621525398); - msg.setSource(44021U); - msg.setSourceEntity(183U); - msg.setDestination(45501U); - msg.setDestinationEntity(4U); - msg.medium = 149U; + IMC::PlanManeuver msg; + msg.setTimeStamp(0.9144577017235159); + msg.setSource(52092U); + msg.setSourceEntity(181U); + msg.setDestination(27459U); + msg.setDestinationEntity(30U); + msg.maneuver_id.assign("MWLSQRZBLGANIPUBZJJCSLNMCHCZYPXNZUF"); + IMC::Takeoff tmp_msg_0; + tmp_msg_0.lat = 0.2787318693149796; + tmp_msg_0.lon = 0.7155124741948657; + tmp_msg_0.z = 0.7716197638750744; + tmp_msg_0.z_units = 139U; + tmp_msg_0.speed = 0.059370767858305196; + tmp_msg_0.speed_units = 13U; + tmp_msg_0.takeoff_pitch = 0.9523795530123856; + tmp_msg_0.custom.assign("WCVZDRMUGKXCWIUNYSJQHUPEXQFCXRBGTKDXRYWYLIJCFFLHPTXSUNNEJJJBLFGZMTGEEOEAWNNOYAMBPCXDOGZOAJADMWAHITIKHUJXALTMSOQEKAARHWAXRWYBPNNZRQDCRPLHPNFWJZSWVMBOOFYHYDNHCTWYLKUZTGSVLQXBEQRUZTIVSUNKBVFPSZBOHGJDDQDUQYBKEKCJLVIEMVSMF"); + msg.data.set(tmp_msg_0); + IMC::DevCalibrationState tmp_msg_1; + tmp_msg_1.total_steps = 143U; + tmp_msg_1.step_number = 185U; + tmp_msg_1.step.assign("NDIRKCQXHGNPYDFRKQEMXRZOLWZYCMQKLCJXYLTEKNFMZIAQKPTAECTVLCURNBASNNATZYYYYXUALJKZUQQHBOLGMJSZHYAIAWIEIMHFUDZKVHTPUSOZBXGVIMGETJVPWBUMREWOSVPKWUUBAVFSDHTXTDOICGHHNRBWQFPRIVXOHJCYFSGESBFCVNNFLWRPDPLDPEBGXCYU"); + tmp_msg_1.flags = 228U; + msg.start_actions.push_back(tmp_msg_1); + IMC::GetWorldCoordinates tmp_msg_2; + tmp_msg_2.tracking = 187U; + tmp_msg_2.lat = 0.5509513881279048; + tmp_msg_2.lon = 0.6465546216481133; + tmp_msg_2.x = 0.8035133087976103; + tmp_msg_2.y = 0.027073668101487258; + tmp_msg_2.z = 0.34467523296842306; + msg.end_actions.push_back(tmp_msg_2); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleMedium #1", msg == *msg_d); + test.boolean("PlanManeuver #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17654,20 +20322,35 @@ main(void) } { - IMC::VehicleMedium msg; - msg.setTimeStamp(0.671543259092); - msg.setSource(46288U); - msg.setSourceEntity(11U); - msg.setDestination(56522U); - msg.setDestinationEntity(206U); - msg.medium = 85U; + IMC::PlanManeuver msg; + msg.setTimeStamp(0.46554454944296497); + msg.setSource(14710U); + msg.setSourceEntity(229U); + msg.setDestination(41734U); + msg.setDestinationEntity(252U); + msg.maneuver_id.assign("NBOCKVNTPGALANLOW"); + IMC::Drop tmp_msg_0; + tmp_msg_0.timeout = 47155U; + tmp_msg_0.lat = 0.6635182156280218; + tmp_msg_0.lon = 0.7529823910447674; + tmp_msg_0.z = 0.28699305628857363; + tmp_msg_0.z_units = 23U; + tmp_msg_0.speed = 0.3807232457823515; + tmp_msg_0.speed_units = 129U; + tmp_msg_0.custom.assign("IWDNXRMEATZEQDFUCSKPAPXAJBILYECQOGBUVFIJLJDHTUEUMSWUTAJQGPWHHKUEQAWDOORJGPYSCALCISHQKRVVXVMNXVDHBYWRZJURJQLWWFBMEWZGPZCZEYYHMNAM"); + msg.data.set(tmp_msg_0); + IMC::QueryEntityParameters tmp_msg_1; + tmp_msg_1.name.assign("NZFTZSGELLMESAAPEIEPIMPGZSLNOCJ"); + tmp_msg_1.visibility.assign("UHFYNLHENCJSESEQTZMJSWCIBQAENGYPRIMYAZDICAGPQHBBUZCJWPNSPMHKSERFGXQVQRCKWSDINZJDHGDTZKADOGPPYFVVBPZLQAUMBDUCWSFXBOVEOWJXIVARHNTLFACFZKXMVHXEOLDYXVOBAXZGSYRZDVHUDQMCIJX"); + tmp_msg_1.scope.assign("UCKLNKTPACIRASIVXNXSBFZITEGRNENYLEQHDMODJGRRZFZCTKHUXNRLNINSPCLQEOVKFYYKJTTQDJGPDKVZXXHXPXBWUGUAEZPQAIWMFNQBAHDVMWJURQHJHWBXMSJCGOWFYBSEKKJTOKUWVPILTSPCRXEYCGQSBQFGZIAZBSMYJWMOUWRTITPLJLIUHDYPS"); + msg.end_actions.push_back(tmp_msg_1); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleMedium #2", msg == *msg_d); + test.boolean("PlanManeuver #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17678,21 +20361,29 @@ main(void) } { - IMC::Collision msg; - msg.setTimeStamp(0.855711038557); - msg.setSource(38997U); - msg.setSourceEntity(241U); - msg.setDestination(31351U); - msg.setDestinationEntity(172U); - msg.value = 0.897018103075; - msg.type = 182U; + IMC::PlanTransition msg; + msg.setTimeStamp(0.46790163581787425); + msg.setSource(44365U); + msg.setSourceEntity(138U); + msg.setDestination(12828U); + msg.setDestinationEntity(72U); + msg.source_man.assign("ZUYMEACPPTHYFEXUOVLINFDYSMVAVZPWQTLXMIBBWBCSZBTY"); + msg.dest_man.assign("TOUPBMLZTWHYUQGUSUCGFFPFAVPKDIQZPYIPBYNXDMVEMHRTWDKHEFESSNSBJPICLRAGURQZBXCSWUJEYNAARNFRYKGXMDZRWAHVBAOHIAPIGCMKLSQSYTJHAZGFIRDMWQAUVWKROQMONFTGFI"); + msg.conditions.assign("UQHGJEBHZENMODKOVXVTDVOQHHHPTYALUAYALMVUUXSJYMJUKQOELEGGDCKNXPFWXERZACRLWTQUAWDBYBYGSDFHHUGGTICMNOLOKYNEWTQWVXPIVYKSYDISLWQJJMXSQCCZTENRNRBZXGSKIRSVTOFIZXHJRMNLZPVMVAFRKXOTEIYSUHWPCFSAFBPFODNEHRCAPBZPDQNZBWUJFMALXFRALWIRTSUGCJCDTQJZYKBWDMM"); + IMC::FollowReference tmp_msg_0; + tmp_msg_0.control_src = 65016U; + tmp_msg_0.control_ent = 221U; + tmp_msg_0.timeout = 0.6688016274935662; + tmp_msg_0.loiter_radius = 0.8187660711662047; + tmp_msg_0.altitude_interval = 0.17363015346956268; + msg.actions.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Collision #0", msg == *msg_d); + test.boolean("PlanTransition #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17703,21 +20394,28 @@ main(void) } { - IMC::Collision msg; - msg.setTimeStamp(0.818709053855); - msg.setSource(51030U); - msg.setSourceEntity(217U); - msg.setDestination(3542U); - msg.setDestinationEntity(91U); - msg.value = 0.224342019449; - msg.type = 224U; + IMC::PlanTransition msg; + msg.setTimeStamp(0.6009623193218823); + msg.setSource(13147U); + msg.setSourceEntity(95U); + msg.setDestination(30187U); + msg.setDestinationEntity(115U); + msg.source_man.assign("MOOURJPYLCERMGTXEDDCIZVHPJNXTSTQVQUINGJGIHCJDETTAKKYYGLPBNJEFSSWCPEJHXFGWXRMZWPTZWPSOBBCREMXRIPSEHVWBVXLLKGELUQAQBYQOYHQMOALZRQXLYGANWBQUZFFTNOVLNOGFFCOXRGCVSGIURFZHVJXVBJAFKBNPLZUF"); + msg.dest_man.assign("QYBMGQLMRHSCRHQSBLOCTCOIKIEGDXICYENPQYDOPHHBYWUWERZAEATHKPNKXFUZMYSEHOLKBEAAXHFKKBVRLTYLWFRCZJTXHNOCPMXQSDXGVRDXHJMNCSGVUTVPFZDFOFOXNEQCIJWFLCAXYIZIUDVEMKJBSDOMSDGNCRNEULAPWZVLSYUPTNYVOQGALUQYHKDREPIPJBRNZZGJVKQGJ"); + msg.conditions.assign("WOXFSKSDLXEWRKETZWKAMQVKAKKAOVOYYTCVYBHPKMCINWEVIUTWGBYUHLDQJDBTYNQCTCVBMHGJMKPBAFTZTFRQIRQDUKMAPLMSUOEFSEIINYQZCNAPKNFWWF"); + IMC::VehicleFormationParticipant tmp_msg_0; + tmp_msg_0.vid = 5256U; + tmp_msg_0.off_x = 0.5654062459319174; + tmp_msg_0.off_y = 0.9326465667820468; + tmp_msg_0.off_z = 0.6392873625882433; + msg.actions.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Collision #1", msg == *msg_d); + test.boolean("PlanTransition #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17728,21 +20426,22 @@ main(void) } { - IMC::Collision msg; - msg.setTimeStamp(0.957786728009); - msg.setSource(53351U); - msg.setSourceEntity(51U); - msg.setDestination(10644U); - msg.setDestinationEntity(167U); - msg.value = 0.673164912495; - msg.type = 17U; + IMC::PlanTransition msg; + msg.setTimeStamp(0.34852291887343256); + msg.setSource(10886U); + msg.setSourceEntity(163U); + msg.setDestination(22240U); + msg.setDestinationEntity(93U); + msg.source_man.assign("BDFKZBXTLSUZSLBNMYPDMKNTUEDDCHZ"); + msg.dest_man.assign("MZOSRXFVLTZZDLUILICDJRTNJXHQGAKUPZLGGZDVANXNBQPUCKRJGVEVMYKABPSWSNKJPFTVIWEHQMIOBEBQYCYLTJPNQZAIEDLKUYIHRKSKICODYHQOMVOMNTNKBYAHRMVFCWXVNGRCOMFFHRAGZDFYMTBRSEDLUUVJBKYSYBWFCRWCADFTWOJP"); + msg.conditions.assign("RYNCBHPILDQOLZBXRWETLCXYAVIURJFGZOIJEUUBEFKGMDKNQVWUNMGYAQCCUVOKSEYEFJKDIRZWAHPRHYSQDZEOAQFJRCFONXWICLSTUBWBBNWVASFMXDRSGWIWYGLHCJSRWGHDZQBEUVEOBTKOZHKMZKPJSTOFEVIFYARNIXZLYPYLZQVQATNOGIV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Collision #2", msg == *msg_d); + test.boolean("PlanTransition #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17753,25 +20452,72 @@ main(void) } { - IMC::FormState msg; - msg.setTimeStamp(0.494424438229); - msg.setSource(43141U); - msg.setSourceEntity(118U); - msg.setDestination(43229U); - msg.setDestinationEntity(44U); - msg.possimerr = 0.529494633904; - msg.converg = 0.756160491746; - msg.turbulence = 0.501514800659; - msg.possimmon = 91U; - msg.commmon = 78U; - msg.convergmon = 246U; + IMC::EmergencyControl msg; + msg.setTimeStamp(0.6878036226890601); + msg.setSource(2409U); + msg.setSourceEntity(15U); + msg.setDestination(4237U); + msg.setDestinationEntity(187U); + msg.command = 180U; + IMC::PlanSpecification tmp_msg_0; + tmp_msg_0.plan_id.assign("OHBXRFPRBETDJDLEDTKC"); + tmp_msg_0.description.assign("FSNIGAVBSEJZMHFNRCDETAROZUBZPQYYEBPDKXIKTUGLPMNJYWDMSKYXUSAHFWDZPSUYGHFIQXNJLTXAPXGRLIRGFWTENKKHCQVIRTEQECITBQNLOAMCYSJLDEJRDKJXCYQTMVIUQAKOXNGNWFWMHDLJAVDCVCIMPBQETYERHWSXFOYJURGOMRFPKNZCSTNG"); + tmp_msg_0.vnamespace.assign("YSRRGJOHUJFMPFQLGTYNFGJZDAWDUFBAFWPLMTFSSMNCTLRKLZJSXACVNZEECXNZWKZBLIIKRVHUSIDYLWRIXVNVXLXTSJHMWCUHAPCPMVOTKRYLDJPZBQCOOVAFWPGIYTHODEIZSQE"); + IMC::PlanVariable tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.name.assign("NGZTDCTAVIRXJJYRSUMTKZDMAPOXJDVSZYHFZNYQYYXO"); + tmp_tmp_msg_0_0.value.assign("ZMHGDNSXORJVMJYKBPLFOUKILARENLHOMNUUJKEEQLHPQVOTCLXUFUPDVARIBJNFJCBVCJPBGYRDKHTBLNZTIESXNDMFCESOIXZVZPZCKGWFYNRLIJUXGEZAPRUQYXGQYMMTKFDIWHPDJKCLNAGWJWAHSVTYVGOGABOBPSMMFVXEQIMVSZEWHHXDWWTBIJWLBSGLUDQNAZYQTAHNHDAKRKIPCOCFRRXAZTTSYWEYFBOWRSCCOQESIGTKVPUUXM"); + tmp_tmp_msg_0_0.type = 197U; + tmp_tmp_msg_0_0.access = 84U; + tmp_msg_0.variables.push_back(tmp_tmp_msg_0_0); + tmp_msg_0.start_man_id.assign("CVUTMDFAARWENTMDULOJYJZBWIGIWAYFLYLXYJQEMVYMHTKGAMZXMDBVTPHMOPSKDAEUYSISRFCGDZXOBLSYKEUPIRUVQRLCDCGITCXIFDSVDGNPFLPQPESZFAEGWQUJTKNOGZAKHDWDTNAWHAECXRHYHZVLXRJZNMBFINQOXJBNSRLHOLWVBVOFPOSCIHKVINUZTC"); + IMC::PlanManeuver tmp_tmp_msg_0_1; + tmp_tmp_msg_0_1.maneuver_id.assign("PYUQZNWJNIHOY"); + IMC::FormationPlanExecution tmp_tmp_tmp_msg_0_1_0; + tmp_tmp_tmp_msg_0_1_0.group_name.assign("ZDXNLZQPAKJRFJOSBWAFSUEHMYWFJNUCGHXSOWCQINFQFDGCTWOVXNIRPIXDHUWCBQIKXAOQBYVPTJXZAYWOAUHQNQRBTGRDJYA"); + tmp_tmp_tmp_msg_0_1_0.formation_name.assign("ZZGIZAFUPKAJKKVXIDAWRHVOPYBMPVTQRIJBLTZDJNNEDGUSXORTCPNVHIYLNCOFUJMPRZWQQGQXLVXKEKSAYYDBBFLAI"); + tmp_tmp_tmp_msg_0_1_0.plan_id.assign("XWTPKYUQSDPCTTZIKJCAWGOKLJTKORGVBMVKVCKNYDBQLVDFJAZQACSWVDFUYQAPNAZYHUEOTDXXGIMNLQRTSWVSGJYIKJMAECZUDPFWWORPEBMOOFXIBSMFOHQIHDLGUECQLCRYTGWJVCJWAXJDTVPSTFXILFYBZGLSMRUWJGEOZOAIRHFNHFENE"); + tmp_tmp_tmp_msg_0_1_0.description.assign("UOYVLPVPDBDFPPADCLOVMRCNXQHFKMHWPTXAIAZNJGJSFTPTQLWESZGOHEGIENKNTEZPVUXMGBXTCCNEVJLGDDIXIFOMTKBBVWIQTVUTFWLKRIZLNSZPUAUQDGXCVYKQYNZABOHPHRBVQDVYKSLWXITAQRLLUMERHHHBMHGSSMAIAKOQSMDGONUUJAEJQFXRNWSMTGSFJB"); + tmp_tmp_tmp_msg_0_1_0.leader_speed = 0.13237373299142152; + tmp_tmp_tmp_msg_0_1_0.leader_bank_lim = 0.6668499869789678; + tmp_tmp_tmp_msg_0_1_0.pos_sim_err_lim = 0.9459555109594018; + tmp_tmp_tmp_msg_0_1_0.pos_sim_err_wrn = 0.00986049864683558; + tmp_tmp_tmp_msg_0_1_0.pos_sim_err_timeout = 23836U; + tmp_tmp_tmp_msg_0_1_0.converg_max = 0.6476812107438952; + tmp_tmp_tmp_msg_0_1_0.converg_timeout = 22723U; + tmp_tmp_tmp_msg_0_1_0.comms_timeout = 4580U; + tmp_tmp_tmp_msg_0_1_0.turb_lim = 0.19921187391422046; + tmp_tmp_tmp_msg_0_1_0.custom.assign("UYHDHVGLRRBWGSXQMARZDRFZUDQ"); + tmp_tmp_msg_0_1.data.set(tmp_tmp_tmp_msg_0_1_0); + IMC::Event tmp_tmp_tmp_msg_0_1_1; + tmp_tmp_tmp_msg_0_1_1.topic.assign("WEIRAYGWSSJMNEXFLZCUKLQUQNYDKFGQCRHRLTQCYMWUAEEPCKOBIYHZLFAXMVDMALRYGTCDZTDJWFCLZYVCRSUAJUQBHOVKGMSERZQIPNNXMEUXFTKSBXFQGZWZRXLOXRLUMOTSUSYEJZDJGWS"); + tmp_tmp_tmp_msg_0_1_1.data.assign("LBFKPASBTMVEGJXSDDOPTTVMRVOJTJDIGCKKDFNALKOUILIQQKOWGEXKPOBPBMOIHCJPCWLMWRDVKRMSZUJWVPVCLAPGGFUZKUDHESDCTXRJH"); + tmp_tmp_msg_0_1.end_actions.push_back(tmp_tmp_tmp_msg_0_1_1); + tmp_msg_0.maneuvers.push_back(tmp_tmp_msg_0_1); + IMC::TransmissionRequest tmp_tmp_msg_0_2; + tmp_tmp_msg_0_2.req_id = 40752U; + tmp_tmp_msg_0_2.comm_mean = 53U; + tmp_tmp_msg_0_2.destination.assign("ZTQHUZYWTCBRVKDXUWDPNCMXNWOMEUHNVSCZGXGCUSRONYBDDYABWHYWLICKGLVMSBFJUKHXTHSHOHSAJP"); + tmp_tmp_msg_0_2.deadline = 0.15472264817732173; + tmp_tmp_msg_0_2.range = 0.4754129365426588; + tmp_tmp_msg_0_2.data_mode = 211U; + IMC::Dislodge tmp_tmp_tmp_msg_0_2_0; + tmp_tmp_tmp_msg_0_2_0.timeout = 14820U; + tmp_tmp_tmp_msg_0_2_0.rpm = 0.6264196688924017; + tmp_tmp_tmp_msg_0_2_0.direction = 68U; + tmp_tmp_tmp_msg_0_2_0.custom.assign("XSWHTNAGXZJTDWRSYPLPEESSRFNGUIZHGZFY"); + tmp_tmp_msg_0_2.msg_data.set(tmp_tmp_tmp_msg_0_2_0); + tmp_tmp_msg_0_2.txt_data.assign("VHCBPUYWEKCQONTWKEHZVBBJHSJCXBKJULDXTQMPZZWYKCYNODBUHUGCGINICJPXKSNPQAVAYEXSOMNSZIGTEYDJOUWOVLMWSDQNVCLOFMINBHBLOVBQEOKAGMASUHFNXVPEXSQIFPVEJHETZCZRAZTXRPXREROAUYZAMCUPMRFFYDQMFNXFQMWGKXDRSIGVSHVZPTLHKGQHRJGPALJIRWYTRWFSIQBABGROIJLUDD"); + const signed char tmp_tmp_tmp_msg_0_2_1[] = {-99, -23, -52, -32, -101, 104, -15, 44, 61, -77, 39, 92, 59, -36, 112, -37, -82, -119, 54, -122, -32, 56, -17, 112, -50, -64, 8, -7, 29, -84, -82, -65, -52, -2, -68, 22, -29, -65, -54, -119, -6, -50, -82, -116, 59, 45, 100, -63, -112, 118, 78, 23, 23, 82, 45, 56, 65, 3, 0, -69, -84, -32, 82, 55, -124, 81, -23, 67, 16, -70, 45, -17, -2, -114, 33, 81, 109, -20, -77, 19, 54, -66, -45, -96, -60, -126, -76, 93, -2, -34, -112, -32, 2, -74, -13, -86, -115, 13, 5, 39, 27, 95, 118, 63, 33, 111, -89, 75, -87, 20, 93, 69, 23, -55, 80, 90, -11, 57, 54, 23, -115, 126, -56, -85, 74, -100, -62, 22, 7, 79, 101, -21, 54, 88, -104, -91, -25, 63, 5, 57, -9, -47, -115, 124, 5, -77, -19, -80, 51, 117, -26, 22, -64, -74, 51, 60, 83, -112, 76, 73, 97, -32, 35, -111, 112, -26, -127, -77, -58, -44, 126, -125, 37, -32, -80, -50, 111, 116, 7, 109, -90, 71, -41, 70, -58, -3, 122, 62, -47, -87, 58, 71, 6, -119, 64, 0}; + tmp_tmp_msg_0_2.raw_data.assign(tmp_tmp_tmp_msg_0_2_1, tmp_tmp_tmp_msg_0_2_1 + sizeof(tmp_tmp_tmp_msg_0_2_1)); + tmp_msg_0.end_actions.push_back(tmp_tmp_msg_0_2); + msg.plan.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormState #0", msg == *msg_d); + test.boolean("EmergencyControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17782,25 +20528,42 @@ main(void) } { - IMC::FormState msg; - msg.setTimeStamp(0.0932573147223); - msg.setSource(18584U); - msg.setSourceEntity(208U); - msg.setDestination(61090U); - msg.setDestinationEntity(63U); - msg.possimerr = 0.000162536633172; - msg.converg = 0.796529829765; - msg.turbulence = 0.716775143153; - msg.possimmon = 85U; - msg.commmon = 76U; - msg.convergmon = 135U; + IMC::EmergencyControl msg; + msg.setTimeStamp(0.6034439111258917); + msg.setSource(48817U); + msg.setSourceEntity(35U); + msg.setDestination(30549U); + msg.setDestinationEntity(57U); + msg.command = 113U; + IMC::PlanSpecification tmp_msg_0; + tmp_msg_0.plan_id.assign("NHTSYMXDJBPEXXMEAKYREANXVHOBHQHCTI"); + tmp_msg_0.description.assign("VIIHNJZIQABMEOSKYAZLRVLLHLNDSSWHEQPXVKIHTGHSYOBKOQRJTTJUCSPZWRCXBJLNYEGMNTXQWBDDJUQCEGVRACPHMLSEYTFPSFZZQUBTGATBKQPWIERTBBMFUVAMHUYZYVWAIEEFPJRJZOSM"); + tmp_msg_0.vnamespace.assign("XUTGEIVYUDRFSBZJSTAIJCCJQQDKMITAHAMKTDRYNRCHSIWOFNBAODVLXSXQSJNJNAXTHRYVIVEOIWLPQBOGENCJ"); + IMC::PlanVariable tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.name.assign("DYKWVGMASYGRSMIEDDQVPKIZCBAOGGGKEZGOOVJ"); + tmp_tmp_msg_0_0.value.assign("KMFMLFERDXTGZQJUGOBGYGPXDHMICSFKXYJEHYIKHFTNGSRHNVOZAIEUADUWYTKHMHDHQNQWGCZATVSXCQPVRJYJTTACDNMTODPILBJOICHUVUOTJPNAFKDWXUCSNPKBZOVQKXWBFVYPBINMRWQUCPBJIXWRAUQBWOQIMPEJLJGSMRRKMKVYVWCNOR"); + tmp_tmp_msg_0_0.type = 22U; + tmp_tmp_msg_0_0.access = 123U; + tmp_msg_0.variables.push_back(tmp_tmp_msg_0_0); + tmp_msg_0.start_man_id.assign("RZMDQTZXYVLDGLQDTBJFAKUOYGPIEAABYNHIPUICJKUJXBLNOSVVXHYCTDHCNUQR"); + IMC::PlanTransition tmp_tmp_msg_0_1; + tmp_tmp_msg_0_1.source_man.assign("ATOBSPFJCTQDXMOPEDAXOKZEFHJKQRAZCEOCNHJAULKTDUM"); + tmp_tmp_msg_0_1.dest_man.assign("YOVDEXMDCHJXTSOFZJSYEXVJNUWCOUFIJFDKVKIEWBOICAJVEWQHIVVPSZPYBOJULFIRHSLVYPOQYRDHEJWBLTPVSOWTPNJNINAGDVUX"); + tmp_tmp_msg_0_1.conditions.assign("PNMTXFSXJEFAOKHVAXBVGONGSDWIKKQSFILFDATIAKTVJRFUQUXXCIGWZCOCLNWRASKSFUOCSKHAPYJMTZBDRHTEGIYVQPGMQMDPPUMZSVRXLDWPYJVMRVOOHRNJBZJZKB"); + tmp_msg_0.transitions.push_back(tmp_tmp_msg_0_1); + IMC::Sms tmp_tmp_msg_0_2; + tmp_tmp_msg_0_2.number.assign("LNRCYQRKKOUQCAPHGNEJCUJPGYEZIYIQKZKHCMXFACBVHJWOAHGWLLTPDTOGVATSSYKYIIZDXAWHGFEGTVDNTSERXPLWOEAJFUKIZLBQZFUBYRKPRYYZPHBMDWYWKNSSJPMTUWKBPCJBFMQFEPQCVDXEQXGMTEIRBCOANDVJMVERMIERSL"); + tmp_tmp_msg_0_2.timeout = 965U; + tmp_tmp_msg_0_2.contents.assign("ZFEIQCIFRBACEGIUXXJTWZLNQOOMXHWAMQEVAJSJMOQVCYURWRZHNSQRYSIZMISAWQVEAYIFPYHFLHXEITPZCZH"); + tmp_msg_0.start_actions.push_back(tmp_tmp_msg_0_2); + msg.plan.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormState #1", msg == *msg_d); + test.boolean("EmergencyControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17811,25 +20574,36 @@ main(void) } { - IMC::FormState msg; - msg.setTimeStamp(0.462776363806); - msg.setSource(26692U); - msg.setSourceEntity(52U); - msg.setDestination(50960U); - msg.setDestinationEntity(181U); - msg.possimerr = 0.0727619145594; - msg.converg = 0.0420714435581; - msg.turbulence = 0.217850960172; - msg.possimmon = 98U; - msg.commmon = 85U; - msg.convergmon = 99U; + IMC::EmergencyControl msg; + msg.setTimeStamp(0.16265227586755138); + msg.setSource(58450U); + msg.setSourceEntity(123U); + msg.setDestination(2194U); + msg.setDestinationEntity(107U); + msg.command = 83U; + IMC::PlanSpecification tmp_msg_0; + tmp_msg_0.plan_id.assign("ZSKVPISOAEWSTPMLUJTDXNMQNUXPPMTJNEOJPXETZSRHFMCFKNYEPUTYJNFZHUYAHCFHDIIQJRBCTHWVOOWLAVDRUVNGULZECGYOFCGEZIZKLXOWMHBLTYGZBAWYWUWQZRQVYKHDABUBIUIVQVJIBPLXIDKTEFCNJBSLP"); + tmp_msg_0.description.assign("QPCXCYSGBWNUEYTQYJVKMHBUTLFWUPCFPXREDMGHXBGQUMWKNEUPZOVIADFLXOAZGGECLKSCMJJRUDFFXQZJGPFBAUKVZTXHEIGIHWQYCMNWXZNOYDRLWEUQHSJZAIDOSBIMTAOLLSVMDRNSKVDTMHILJHHPADSVONEKPZZFJBYRCSV"); + tmp_msg_0.vnamespace.assign("HEALOKDUIDBAVWHFEWGWEOGIACWYDHDHSNZPRZNVQZUMHKVTUCWVEZHMDSTDASBSFCULGXZIMMLHNASTCWMMPIRBYBALDLTAOPCLVLQXPRKILOYRNXUVXEBKENYMBFTGQZCPGWJ"); + tmp_msg_0.start_man_id.assign("RMSGWWSNHTGBZFFYQVYZADFOMYXIUDVVVKRYJPDPMMBZWLFZTQBTRXKBNGHPDFJIEQNENHUQCLVGVGQJEMBELOARVOKDYWJZHOOLVWVWXJMFSISGCUPTUKM"); + IMC::FollowSystem tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.system = 33793U; + tmp_tmp_msg_0_0.duration = 28003U; + tmp_tmp_msg_0_0.speed = 0.004954096849310474; + tmp_tmp_msg_0_0.speed_units = 55U; + tmp_tmp_msg_0_0.x = 0.3768629681634649; + tmp_tmp_msg_0_0.y = 0.04309357674912795; + tmp_tmp_msg_0_0.z = 0.2576316358565919; + tmp_tmp_msg_0_0.z_units = 30U; + tmp_msg_0.start_actions.push_back(tmp_tmp_msg_0_0); + msg.plan.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormState #2", msg == *msg_d); + test.boolean("EmergencyControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17840,21 +20614,22 @@ main(void) } { - IMC::AutopilotMode msg; - msg.setTimeStamp(0.479008392759); - msg.setSource(18521U); - msg.setSourceEntity(127U); - msg.setDestination(7257U); - msg.setDestinationEntity(252U); - msg.autonomy = 107U; - msg.mode.assign("MKWYOKHWBRHVRNTHGQVYVPMEFQTFQELXXSDFSEHFUEOYRTDHPNUIYHEXPFLWAIMYZTLGZDJPDSBAGCQACUEVHLSOILJMACZKJELKZRJPDUGWNDJYFRAJBTLQWUUKBOZUXFOJJSYHKZOHEHUSSCMFQTXGMXPCTUZCTSAVOBYMDBOOWNRLCPEQIDDAWJXCIZKGKVJQXWVOQLMRBSGTZKRABSYNGWFRIXVKIUPVFWIGXNT"); + IMC::EmergencyControlState msg; + msg.setTimeStamp(0.9008607436826991); + msg.setSource(37135U); + msg.setSourceEntity(239U); + msg.setDestination(39431U); + msg.setDestinationEntity(6U); + msg.state = 148U; + msg.plan_id.assign("GVXKFATGLJYNKLHPPUKMMQBSDPOHTZCUWMVETXWOTXULBEEZOPXNJTZVFNEMNRSFYSWJGQGEIGWPFGIK"); + msg.comm_level = 30U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AutopilotMode #0", msg == *msg_d); + test.boolean("EmergencyControlState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17865,21 +20640,22 @@ main(void) } { - IMC::AutopilotMode msg; - msg.setTimeStamp(0.811897981787); - msg.setSource(49977U); - msg.setSourceEntity(83U); - msg.setDestination(64913U); - msg.setDestinationEntity(59U); - msg.autonomy = 5U; - msg.mode.assign("SLSBTFULJKHW"); + IMC::EmergencyControlState msg; + msg.setTimeStamp(0.33834261053015335); + msg.setSource(47983U); + msg.setSourceEntity(175U); + msg.setDestination(58915U); + msg.setDestinationEntity(207U); + msg.state = 173U; + msg.plan_id.assign("JZRDGCTHFCWTGYGQWDQVDJNURXDVGKRUIJNQNBSKXALCBOOUUNBUYQPHPONGMGIYDOUOHFSPSAVIDKPEGHLKPZCAUJCMXIPZFEHAKAUHQP"); + msg.comm_level = 112U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AutopilotMode #1", msg == *msg_d); + test.boolean("EmergencyControlState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17890,21 +20666,22 @@ main(void) } { - IMC::AutopilotMode msg; - msg.setTimeStamp(0.443791539538); - msg.setSource(49188U); - msg.setSourceEntity(110U); - msg.setDestination(55500U); - msg.setDestinationEntity(221U); - msg.autonomy = 55U; - msg.mode.assign("AQXXXHKDNSNIAHNVKLJZABOBDDIKOGZTARHLPEPMLLNQXMXFITV"); + IMC::EmergencyControlState msg; + msg.setTimeStamp(0.7518613541589836); + msg.setSource(64665U); + msg.setSourceEntity(210U); + msg.setDestination(10268U); + msg.setDestinationEntity(153U); + msg.state = 194U; + msg.plan_id.assign("LEGXEGASTKORLOLDETKCVVBGVYRGIDHRRZWZQABZMBWPEOVEQNCNXOFDZJKCYHAYZFIIWKXVCJQBQQOJCZPMAKKVCEBMLNWJEWSRFYVUNJNWSCLTLYHGBZJLPAWLVREDM"); + msg.comm_level = 64U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("AutopilotMode #2", msg == *msg_d); + test.boolean("EmergencyControlState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17915,27 +20692,29 @@ main(void) } { - IMC::FormationState msg; - msg.setTimeStamp(0.209940922078); - msg.setSource(18308U); - msg.setSourceEntity(179U); - msg.setDestination(16762U); - msg.setDestinationEntity(18U); - msg.type = 119U; - msg.op = 168U; - msg.possimerr = 0.407291261017; - msg.converg = 0.328485985646; - msg.turbulence = 0.0476572861096; - msg.possimmon = 67U; - msg.commmon = 173U; - msg.convergmon = 114U; + IMC::PlanDB msg; + msg.setTimeStamp(0.8722702745793229); + msg.setSource(23415U); + msg.setSourceEntity(223U); + msg.setDestination(44630U); + msg.setDestinationEntity(60U); + msg.type = 52U; + msg.op = 205U; + msg.request_id = 15818U; + msg.plan_id.assign("THKUURDXTBRUQSOOEJMFBBIDBATWYUJGFJGSPEVNOCJXLHQXLEFNUCDHYGEPBUIVOEDQNQGSWVTAKJLFVQNNCWTCJRXROKICNEHWIPAUFHMHWLAMHQDSYUCAHYDPYIXSFBDBNPLZYXOTCBGFVKWLXZQZKYCUQCQMAJOPZVREESRWEZGSAOKMNSBJDJ"); + IMC::SetPWM tmp_msg_0; + tmp_msg_0.id = 88U; + tmp_msg_0.period = 319180053U; + tmp_msg_0.duty_cycle = 227314587U; + msg.arg.set(tmp_msg_0); + msg.info.assign("TCDQQRJIZCKUHWOTPKHGANEZTCDGVZQUHOSVIPTZIPUJIDSKYJOHTKMQSLWPPFIUOLQZNBDPMHELVTJGGFBXSGSVLDAFLPKJGOYMNBRREAUJWMELNYYOHFQRKWRETHKCFBMMCQEMYIMAVJWDSQXJTGGOCUVMIVFKYMULSHHCVWPUWAZXCIVDXPGZQAROYUSXVTFUSYADJXYIBXNJAE"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationState #0", msg == *msg_d); + test.boolean("PlanDB #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17946,27 +20725,28 @@ main(void) } { - IMC::FormationState msg; - msg.setTimeStamp(0.99646335832); - msg.setSource(34463U); - msg.setSourceEntity(164U); - msg.setDestination(51727U); - msg.setDestinationEntity(198U); - msg.type = 80U; - msg.op = 72U; - msg.possimerr = 0.342181553834; - msg.converg = 0.408238470921; - msg.turbulence = 0.737927131577; - msg.possimmon = 35U; - msg.commmon = 237U; - msg.convergmon = 46U; + IMC::PlanDB msg; + msg.setTimeStamp(0.416644264857181); + msg.setSource(3472U); + msg.setSourceEntity(62U); + msg.setDestination(42219U); + msg.setDestinationEntity(190U); + msg.type = 110U; + msg.op = 161U; + msg.request_id = 36735U; + msg.plan_id.assign("RPKPGVOJNSPXHVBMYYNPTVKUZXKBROPOZAEGXTQYDOAQKLCEKDXMBMGSTLPNXAFJGFFPENLCLWJMRUZBNZWVVXOCFTGQZTSYABHYSNVEFEZJZXJHJBITZSIFVMDKETTNGREWQDHUZRBRMQKHSCFGMWXVJNYPCUATAWLQHHNDWHSIWMJHKHCGACSQXQKPIYMEWCUEGOCIULUUDATOLNIFYYDBVRDKDUEBFQRFJLIJMBQOLR"); + IMC::EntityParameter tmp_msg_0; + tmp_msg_0.name.assign("HPWDWXLOPSGUVJJQLDURWCVHRMPUHOUFQSPGRKSLIDCYREYVAMNXOYIDTGSXEXYHBSNQTXTQKXIXBSMBUBUWTJEZUFJZANJOWEDYCDRYDXWKVVOVBPHJHIKVDMEEILZUZHGGMRMFSUAYRCPNFBOWMCJFNRTETAQLFTNFZPPTOKBYFEWQBHVCMNWCCQZGKAKEQQZXKSGLKRWKIJRNMGPPNIOMNATQGGDOILVLJFCEZSAIOSBVLIBUAYAHLAFJX"); + tmp_msg_0.value.assign("ACYWBSDGLIFNWQQADPRBOZUFIJDEYMWRMVTBINHJIAVGEOJSQRGKOLRCDYUPEOLGLNJBTGNUVBGGELSXPMHZMHUFYEFBQMJANXGBXZ"); + msg.arg.set(tmp_msg_0); + msg.info.assign("FPIQZEFNMIYTNEPMPZNYHPUROGOGIREBULCBSJCUFNOSJPGJFZRZMCXPFHOWHGUOHQVVODWBEENWTKHXCGUKQKDZENUMAUVEURSHTVIBFQQWAYVWGPGXMGDDVHXVYLBQCWSJQXJKLKTADBFXDRPSALZTLHBICQFLDBNWQDJYLSSTNPAJWAASLXBLCPGTODRFFNUVRJKYKMQCRRTYIMWZKHHZN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationState #1", msg == *msg_d); + test.boolean("PlanDB #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -17977,27 +20757,27 @@ main(void) } { - IMC::FormationState msg; - msg.setTimeStamp(0.365236879021); - msg.setSource(7725U); - msg.setSourceEntity(181U); - msg.setDestination(65444U); - msg.setDestinationEntity(116U); - msg.type = 4U; - msg.op = 143U; - msg.possimerr = 0.581339948162; - msg.converg = 0.0209667096652; - msg.turbulence = 0.938153492668; - msg.possimmon = 125U; - msg.commmon = 155U; - msg.convergmon = 110U; + IMC::PlanDB msg; + msg.setTimeStamp(0.6702752785210621); + msg.setSource(23900U); + msg.setSourceEntity(152U); + msg.setDestination(61315U); + msg.setDestinationEntity(86U); + msg.type = 18U; + msg.op = 167U; + msg.request_id = 1485U; + msg.plan_id.assign("LSKAYYQYPRXTWVFBPHHLLRMJPIVSZZBXZFMWSRKDVEQNYMDPEAKRTPMPQXHKWHNPRCZXQGJAWMKHHOKZUVMYESCRKMEGABNFNHODCKDALMMBNIWRIVYT"); + IMC::DesiredHeading tmp_msg_0; + tmp_msg_0.value = 0.7171059775916255; + msg.arg.set(tmp_msg_0); + msg.info.assign("PTMZHLEEBEGBFLSXDXWDAQIWREBCTKSKOCUOZACMQLVEEQRKCFYQUEGPYXRQJJTIYHMNVURYZHSSAPLQKLFHTJUGLDWRBABWHXTYRJDMEOAHNAJWMBWCCHSMZXSNXCIYHXUYDRIGANUYLZPIIIJNGNFMYGYVOPUSNUZRDXIGECVKRJBMNZJTNKOMVHBVLOAUFWFQTOBTOMQASTGQKWDFVDESCJFBPGKZIRFF"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationState #2", msg == *msg_d); + test.boolean("PlanDB #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18008,23 +20788,26 @@ main(void) } { - IMC::ReportControl msg; - msg.setTimeStamp(0.794824065726); - msg.setSource(17042U); - msg.setSourceEntity(8U); - msg.setDestination(26395U); - msg.setDestinationEntity(224U); - msg.op = 75U; - msg.comm_interface = 78U; - msg.period = 54324U; - msg.sys_dst.assign("OBXTWGJUAMAFCEAOHVMRDJOKBEKVODITPFUSSTBLXJHNKQSKRRGCVSSCNHRRUUSCFGIKLQTYYLYVYZJTNBPMHFVUBUFEDCZMUFVRZJPAZGABXSXWEXMZLHNWFRTKALNEOOYWDQQOOCLKTFWXNSXERTPDLAXZYIZJTDYYTNEABDEXHXRQVKPPFGLWNVGUNLQHCIKMDWVCRHJPWIMNQPGQBIGMIIQC"); + IMC::PlanDBState msg; + msg.setTimeStamp(0.4679579196492176); + msg.setSource(38318U); + msg.setSourceEntity(103U); + msg.setDestination(36381U); + msg.setDestinationEntity(9U); + msg.plan_count = 49450U; + msg.plan_size = 1982243226U; + msg.change_time = 0.4911702258150118; + msg.change_sid = 25707U; + msg.change_sname.assign("QAVIWLNAWSQNJWVLMJZSAEHKPKEXQMPKCLFXSKOCIBXNYKOERWJWNLDEUIUDHBMFAAKNKSNTVJVWC"); + const signed char tmp_msg_0[] = {-11, 9, 58, -2, 9, 82, 105, -32, 25, -6, 73, 70, -55, -12, -128, -53, -90, 52, 42, 45, -38, -24, -108, -120, 42, -36, -60, 102, 72, 4, -63, -16, 18, -18, -40, -128, 68, -115, 88, -30, -111, 62, 11, -97, 42, 44, 108, 111, -32, -115, -40, 66, 69, -40, -41, 116, -70, -83, 2, -1, -83, -6, 18, 114, 8, -45, 86, 21, -61, -89, 32, -74, 2, -12, 16, -54, -25, 45, -40, -16, -123, 15, 75, -113, -58, 28, -128, 72, 75, -78, -93, -3, 117, 2, -125, 14, 61, 101, -6, 114, -31, -106, 71, -29, -13, 111, 88, -95, 87, 38, -14, -63, 66, 46, 39, -25, -37, 119, 7, 32, 103, 1, -82, -18, -104, 119, -61, 96, -125, 95, -70, -81, 42, 76, 96, -47, 59, 101, 24, 33, -83, 16, -118, 25, 89, 98, 70, -128, -84, 126, 50, -50, -80, -119, 103, -86, 91, -109, 15, -111, 75, -67, 77, -6, -48, 48, -107, -20, 83, 33, -41, 75, -120, 41, 97, 68, -112, 38, -8, -1, -43, 45, -45, -24, 29, 16, -16, -34, -43, -96, 105, -78, 34, -31, -56, 62, 84, -69, 87, -85, -15}; + msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ReportControl #0", msg == *msg_d); + test.boolean("PlanDBState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18035,23 +20818,35 @@ main(void) } { - IMC::ReportControl msg; - msg.setTimeStamp(0.621248872645); - msg.setSource(26772U); - msg.setSourceEntity(178U); - msg.setDestination(52559U); - msg.setDestinationEntity(8U); - msg.op = 168U; - msg.comm_interface = 211U; - msg.period = 52902U; - msg.sys_dst.assign("OCVFZJGNDEUBBGGCUHEJVIYKUFSECYUOSVHMBHGVQFLCXVDKLRTOSGWVZPVNMGFKPBZSZNDGUCQZPKVNCNTQPYPSIEXADTICWRSFVQFOOTARRIORTHWJSEXPUAUY"); + IMC::PlanDBState msg; + msg.setTimeStamp(0.43585764092617885); + msg.setSource(39084U); + msg.setSourceEntity(38U); + msg.setDestination(1103U); + msg.setDestinationEntity(7U); + msg.plan_count = 25542U; + msg.plan_size = 3554328232U; + msg.change_time = 0.28906084612556115; + msg.change_sid = 49233U; + msg.change_sname.assign("DPFAOBAYHNBJTZVTGCLEMNGSCLNGPAMFXVEWVDFBOLMBVNPFJAOPGRQWMRPKBSXKWOTWAYYEQSQRHJXGPXXYTIISQRREUBDJNDDDZTUJCUIGUWAUBMZEMKPQUAOXHSILDTBSPNEHVNCBWQXIDSMOQCKLKMWZUHRCUPIGHFHYCEGLRFXIYQGJRXFLVIJZL"); + const signed char tmp_msg_0[] = {-76, -104, 100, -3, 46, 114, 67, 62, -124, -21, 49, -44, -91, 114, 3, 104, -69, 23, 52, 80, -4, 50, -46, -105, -82, -116, -104, 56, -61, 83, -113, 68, 95, 4, 56, 18, -112, 120, 18, -20, 109, -54, 12, 107, 1, -88, -33, -123, 92, 93, 68, -105, -24, 43, -63, -11, 106, 62, -47, -13, 42, 92, -84, -27, -97, 43, -56, -67, 52, 57, 19, 69, 12, -126, 47, 75, -18, -4, -51, 41, 106, -110, 76, -6, 45, -9, 120, 36, 38, 85, -96, 125, -18, -30, -110, 30, 84, 111, 84, 75, -124, -21, 41, -122, 61, -82, 68, 109, -69, -108, -95, -67, 50, -9, -44, -116, 59, -6, 120, 81, -118, 83, -65, -47, -15, 107, -100, -128, -111, -44, -98, 95, -26, 61, 1, -21, 61, 30, 107, 73, -48, 92, 21, 73, -16, -53, -3, -45, 22, -115, 123, 60, 46, 5, 33, 54, -46, 22, -124, -88, -68, 41, 90, 80, -95, 101, 68, -120, 111, -116, -123, -18, 65, 8, 37, 29, 51, -95, -95, -115, 7, 87, -91, -90, 101, 23, -102, 25, 81, 114, 54, -46, -49, -21, -113, -106, 30, -9, -49, -124, -89, -84, -8, 1, 33, 123, -90, 27, 6, -49, -89, -55, 55, -97, -18, -98, -100, 102, 36, -82, -26, -74, 43, 98, 34, -110, -22, -90, 90, 85, 30, 21, 45, -17, 77, 18, -49, -69, 44, -88, -4, 88, 23, 61, -65, -117}; + msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::PlanDBInformation tmp_msg_1; + tmp_msg_1.plan_id.assign("CBPGJRJIXVTOEBFMBQWXNGOIRXNNRQDKJWXDXPXZGKSJUAXATTFLCPSRDEWXOHDASHRHABBPMNPSCYTUMDETGFNUYOFASYMANVWIJYLVKCYSOGSTSPJ"); + tmp_msg_1.plan_size = 14428U; + tmp_msg_1.change_time = 0.3102070620535661; + tmp_msg_1.change_sid = 51299U; + tmp_msg_1.change_sname.assign("JVUUHRIERUCKCGQTLCZEKWMZAFNAESXTVDRTCDWDUMBNLQPSFURXBPVKOBXHPLGIBRQZGMAJQBHPVUGOMOYZGBQYACPXZOIJXCTQAJIBTKHDFUSBKSAGFLNPUTRIPTKKLXOQGYXRBXIKVQQHMWERKLVFJJOPSOPWJSJMAVDVIGEEUDOLJFXDWEZDYWLTPALSHRTCDJVHVYYNRNGIHYFICYNAMKFBOFIU"); + const signed char tmp_tmp_msg_1_0[] = {40, 112, 44, -96, -30, -54, -18, 109, 79, 82, -73, -75, 45, 17, 30, -56, -66, 89, 120, -87, 48, -87, -23, -57, 74, 18, 19, 52, 47, -68, -99, 98, 49, -109, 2, 110, 89, -105, 10, 63, -20, -87, -10, 61, -58, -96, 33, -3, 34, 40, 2, 82, 29, -37, -54, -11, 78, 107, 27, -51, 24, 80, 62, 8, -111, -128, 48, 80, -103, -85, 44, -60, 52, 30, 90, 40, -126, 10, -114, -25, -69, 116, -106, 74, 28, 110, -119, -65, 74, -125, 28, -122, -87, 12, 25, -17, -26, 30, 91, 121, -122, -17, -106, 20, -96, 80, -59, -5, -56, 73, 21, -48, 96, 84, -121, 90, 126, 89, -7, -116, 81, -42, -8, 104, 1, 74, -24, -25, 26, -111, 100, -30, -37, 87, 36, -77, -101, -95, -26, -29, -108, -45, 90, 3, -72, 85, 120, 12, -48, 103, 9, -71, 29, -44, -21, -15, -54, 14, 84, -7, -84, -38, 33, 117, -72, 74, 49, 110, 92, 106, -36, -8, 57, 113, -5, 47, 0, -26, 88, 51}; + tmp_msg_1.md5.assign(tmp_tmp_msg_1_0, tmp_tmp_msg_1_0 + sizeof(tmp_tmp_msg_1_0)); + msg.plans_info.push_back(tmp_msg_1); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ReportControl #1", msg == *msg_d); + test.boolean("PlanDBState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18062,23 +20857,26 @@ main(void) } { - IMC::ReportControl msg; - msg.setTimeStamp(0.230179056881); - msg.setSource(6877U); - msg.setSourceEntity(155U); - msg.setDestination(28510U); - msg.setDestinationEntity(42U); - msg.op = 234U; - msg.comm_interface = 235U; - msg.period = 4317U; - msg.sys_dst.assign("QWFMDVEZMOOAQYTAEBEMPQKWGFYDGFXLQYKROHRNJCUFZHFDZGNDQCZRVAIUQWPLUZENNCCJKBVOUSINVTKLNGQCFRHHUFYJSZWYAUVOHEPEZISLMBMPIGRLOAPIJB"); + IMC::PlanDBState msg; + msg.setTimeStamp(0.9110131770594029); + msg.setSource(7644U); + msg.setSourceEntity(3U); + msg.setDestination(49264U); + msg.setDestinationEntity(105U); + msg.plan_count = 52732U; + msg.plan_size = 2259383719U; + msg.change_time = 0.08393277392076526; + msg.change_sid = 20804U; + msg.change_sname.assign("FKCPVGHJIDSPPZNZALSQEYOBZTFODHRVSBMPNBRJTIHEOGFBLJTXFKLOXYYZUEHDKXGZMWPTOJWKWNYBNCNUUYLRQWXBDQDLMGIONCAASEUGRZYMSSLPPGVIZUAQXSRSHCYOYKFENGTRMEKLCRUJMFQRVODEZVJSKCAMMQHDDWXHFCITBTAVFLVHTEQTWCWQIAGQOAUXBPLQZMYKUKIXKNGEROM"); + const signed char tmp_msg_0[] = {-12, 119, 55, 50, -28, -88, -74, 66, 42, 39, -10, 114, -85, -60, -124, -10, 60, -48, 3, -19, 103, 58, 110, 4, 1, -7, 46, -52, -82, -24, -82, 15, -42, -7, -36, -110, -124, -123, 62, 76, -43, -58, 1, -101, -75, -113, -71, 105, 0, 15, -37, 102, -86, -27, -28, 79, 105, 61, -25, 69, -97, -75, 1, -60, 108, 83, 117, 83, -19, 28, 29, -111, 38, 92, -68, -69, 48, -95, 90, 11, 87, 126, 75, -96, -118, 122, 101, -31, -114, 98}; + msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ReportControl #2", msg == *msg_d); + test.boolean("PlanDBState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18089,19 +20887,26 @@ main(void) } { - IMC::Abort msg; - msg.setTimeStamp(0.895214030811); - msg.setSource(15654U); - msg.setSourceEntity(201U); - msg.setDestination(19995U); - msg.setDestinationEntity(31U); + IMC::PlanDBInformation msg; + msg.setTimeStamp(0.6606221518286989); + msg.setSource(64923U); + msg.setSourceEntity(207U); + msg.setDestination(15015U); + msg.setDestinationEntity(229U); + msg.plan_id.assign("EDUDXYFTPPEVBNJFHQQBWGYKSDLJDIFNKXODVJPGZYZEZAXNOXBQCLGSNICWDFUQOARHBUMQVJRWMBHDKRKVXZCRKGDLWSJIJTIXGCUCZISNYCMRBZRQPCLYGTSJIGZSVQOPNLMTAEGYWXTYFRJESKFELUYPDTKAWUSOXHECPHIIGZZVOORNRAHKOGPMBSHUVTXAHULPMSBRXVVHUJPMCYWLOVNAAIYETMMZQLBTJTMNKWWENWFCFQA"); + msg.plan_size = 47580U; + msg.change_time = 0.7645349841219223; + msg.change_sid = 8202U; + msg.change_sname.assign("AIDTEZLLCUSJGPBVMMTMHPDSZAXLEOABQJXCHLUUEEKJDYEOKQTOQPOAHTEIKWYLUFDVYQGBJMVNFWCFRGFTROIGDCKPYPZXYNPNQASFNEISHDHRGXLZOTGUPTIEYFKGWRRRYAGCQSQAAXSDZMFYCKPZQV"); + const signed char tmp_msg_0[] = {19, 5, 19, -48, -48, 102, -22, 58, 71, -58, 80, 118, -52, 27, 38, 121, 7, -123, -105, -57, 50, 108, -27, 124, -42, -71, -112, 116, -49, -57, 98, -86, 23, 108, -32, 122, -21, -28, 120, 1, 61, -15, -18, -72, 74, -18, 110, -107, -57, -49, -37, -8, 126, -2, 5, 102, 2, -37, 29, -100, 99, 83, -80, 42, 84, 30, 22, 72, -91, -44, -78, -77, -29, -37, 55, -17, 77, 58, 59, -110, 74, 1, -55, 58, -9, 93, 62, 13, 85, 4, -42, -6, 107, 20, 82, 111, -127, -84, 110, -83, 99, 86, -49, -115, 96, 62, 11, -20, 19, -4, 38, 19, 11, -52, -26, -18, 25, 86, -66, 50, 96, -16, 111, -60, 76, -28, 23, -128, 58, -108, 50, 19, 79, 89, 11, 83, 17, 3, 83, 22, -84, 74, 22, -106, -8, -118, -11, 24, -29, -18, -78, 93, -36, -48, 116, 60, -111, -44, -87, 30, -128, 99, 122, -121, -110, -3, 3, -80, -79, -49, 125, 60, -34, -85, -49, 40, -110, -79}; + msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Abort #0", msg == *msg_d); + test.boolean("PlanDBInformation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18112,19 +20917,26 @@ main(void) } { - IMC::Abort msg; - msg.setTimeStamp(0.131032853588); - msg.setSource(63065U); - msg.setSourceEntity(152U); - msg.setDestination(7103U); - msg.setDestinationEntity(82U); + IMC::PlanDBInformation msg; + msg.setTimeStamp(0.008884000638250678); + msg.setSource(2949U); + msg.setSourceEntity(165U); + msg.setDestination(25743U); + msg.setDestinationEntity(34U); + msg.plan_id.assign("HQSQHYDCCVCKIOVIQBXNZWNEXUOZXUTWHRDGRPVBDEBAIVRCERWNTTWQKDEMOCZGJIURIADMHLVWKKKPXAJZFCKNOLQVGQLB"); + msg.plan_size = 52542U; + msg.change_time = 0.4336250937124747; + msg.change_sid = 54891U; + msg.change_sname.assign("LOOWEOSIXRVTNAXPBNIDDKJJAYFZAFUHUSSOQIIEIGOLTADGHLCKMMFPLBBWHEWZUCNEZCVSABJUVBPUGEJVLOKBSQRAQAYNZZSTDTNGDQMFGHFTCYWKYDMXXNPQMKNQDRJUFCIIXHEWECMQLHEUQVUZYSLABXZNRAPRVZSOWKYPRKTNOKXFKQPIZGDGXSAVRDRIGLGWMTDKHYWFOCX"); + const signed char tmp_msg_0[] = {48, 25, 111, 18, -88, -23, 63, 32, -6, -32, 30, -24, -38, 28, -37, 35, -13, -27, 85, -12, -53, 41, 9, 5, -36, 74, -2, -7, 33, -105, -97, -120, 35, 72, -113, 86, -33, -76, 66, 53, -60, -53, -58, 100, 25, 72, 24, -39, -112, -87, 78, 63, -119, 90, 79, 87, 104, 116, 8, 118, 70, -17, 57, -20, 77, -11, -33, 50, -47, 7, -78, -45, 17, 61, 52, -92, -21, 70, 24, 33, -25, -58, 58, -100, -112, 33, -29, 74, 112, 43, 32, 120, -20, -78, 40, -126, -128, 90, -111, -4, -81, -105, -4, 115, -25, 60, -37, 104, -47, 65, -3, -124, -114, 89, 56, 121, -99, 7, 31, -60, 53, -120, -104, -90, -29, -41, -54, 73, 1, 61, -128, 103, 38, 55, 11, -122, -38, 16, -91, 92, 80, -112, 123, 13, -90, -17, -19, -39}; + msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Abort #1", msg == *msg_d); + test.boolean("PlanDBInformation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18135,19 +20947,26 @@ main(void) } { - IMC::Abort msg; - msg.setTimeStamp(0.506359554299); - msg.setSource(18248U); - msg.setSourceEntity(152U); - msg.setDestination(57964U); - msg.setDestinationEntity(203U); + IMC::PlanDBInformation msg; + msg.setTimeStamp(0.6029902555730854); + msg.setSource(56767U); + msg.setSourceEntity(42U); + msg.setDestination(25574U); + msg.setDestinationEntity(99U); + msg.plan_id.assign("MNEGEASKOBZVHPWEQASXNAWRDLTYICCNWFBNTSQEXAXHMGUVAHJXEDCMOBKFOFIDKZXLHFYVKQBCBUKATJYJGJNPDKQIVIZDNJMLOQHTMSFUSBFXJBLODHCBPLROXQLRNMVSWNDHSDGJUDSYYLRVWPZGIWKCTURICAJBLWF"); + msg.plan_size = 33698U; + msg.change_time = 0.6575837527800863; + msg.change_sid = 44811U; + msg.change_sname.assign("JSALGYCLAKG"); + const signed char tmp_msg_0[] = {49, 19, -81, -90, -35, -120, -87, 77, -95, 37, 32, 68, 27, -14, 12, -61, -54, 35, 115, -112, -101, 18, -117, 121, 0, -70, -54, -58, -25, -85, -112, -13, -25, -121, 5, 15, 55, 53, -104, 14, 107, -108, 15, 58, -29, 72, 83, -15, 79, -48, 39, -27, -123, 125, 18, -25, 66, -60, -27, -109, 108, 28, -42, -121, -33, -82, 113, -60, -90, 106, 87, 66, 122, -128, 60, -101, -16, 67, 105, 81, 12, 21, 92, -85, -17, -14, 124, 40, -106, 114, -89, -96, 14, 104, 75, -14, 100, -29, -59, -11, -116, 99, 13, -105, 14, -40, 93, 48, -64, -56, -38, 70, 104, 0, 18, -66, 48, 101, 72, -108, -31, 106, -82, -94, 85, -41, 6, 42, -25, 21, -120, -122, -33, -32, 37, 72, 40, -44, -121, -12, -33, 112, -25, 69, -62, 106, 87, -128, -29, 98, 41, -89, 19, 126, -127, 92, 106, 106, -96, 100, 23, 56, 61, -13, -88, 18, -25, 56, -63, -89, 25, 6, 45, 46, 112, -100, 88, 107, 11, -98, 83, -56, 110, -62, -128, -55, 65, -56, 31, 40, 85, 38, -128, 22, -22, -43, 49, 54, -41, -93, -113, -18, 36, -68, 60, 43, -44, 40, -11, -41, 104, 42, 112, 61}; + msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Abort #2", msg == *msg_d); + test.boolean("PlanDBInformation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18158,30 +20977,32 @@ main(void) } { - IMC::PlanSpecification msg; - msg.setTimeStamp(0.258984106225); - msg.setSource(31243U); - msg.setSourceEntity(102U); - msg.setDestination(61423U); - msg.setDestinationEntity(22U); - msg.plan_id.assign("YHJVSCDOYGCILBVJJQCPGXZLFMOTMKFNXGTQEVZEENRFQTTOKRYVLLEMKUNPABYRAAVTUZDXMFCPWSBEUBTKLVDZBUROW"); - msg.description.assign("IAPXNEBJRDFLDRPMJHTAJKVTKEFVQDCKPENERRKHZLWCSBAWJIXAWAIUZNGUUNNSFIURHMMLVLALYGZYLMHCOIYBRIZYXQNZTQWVHJVMPITVQCGZYNBRUKYHKQMASQJQPEWVOTQWDOKCBGOFXPJKFCQBBPW"); - msg.vnamespace.assign("XAZJKUUSCHQCZ"); - msg.start_man_id.assign("QYVUFWNUDOSLSLIJFBJMPETSGYBKAXMFZMRQXFKNOBBIPLGHLARCYEA"); - IMC::Pulse tmp_msg_0; - msg.start_actions.push_back(tmp_msg_0); - IMC::PathPoint tmp_msg_1; - tmp_msg_1.x = 0.644452892263; - tmp_msg_1.y = 0.970442986583; - tmp_msg_1.z = 0.175988613979; - msg.end_actions.push_back(tmp_msg_1); + IMC::PlanControl msg; + msg.setTimeStamp(0.40624750351806116); + msg.setSource(34538U); + msg.setSourceEntity(116U); + msg.setDestination(63307U); + msg.setDestinationEntity(46U); + msg.type = 166U; + msg.op = 147U; + msg.request_id = 4601U; + msg.plan_id.assign("EFVDVNLSXIWNUAYDDPOHWGCSCXSGYBKJWYHAGBLMRPTERNMGEULHCATIINMKWENJHBVWJOLUSOCSPZPUJUZLHVHIKFQNASMENZBFKDOSKQFEMIHDOK"); + msg.flags = 17302U; + IMC::HistoricTelemetry tmp_msg_0; + tmp_msg_0.altitude = 0.29918738712113435; + tmp_msg_0.roll = 31459U; + tmp_msg_0.pitch = 20225U; + tmp_msg_0.yaw = 44442U; + tmp_msg_0.speed = 25771; + msg.arg.set(tmp_msg_0); + msg.info.assign("VDCPSUYLTXLWSMDJPZAAWQQTXYUGOJKWMIPUKHGFPHITTIBFZSCXKVBZXPMGDJOKCLNEYFVNDBKOIKNHXAUFEAHRRCORSCVIQCVYVOBQODFMVNSZXTYMRDBSFR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanSpecification #0", msg == *msg_d); + test.boolean("PlanControl #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18192,39 +21013,28 @@ main(void) } { - IMC::PlanSpecification msg; - msg.setTimeStamp(0.463556837956); - msg.setSource(12330U); - msg.setSourceEntity(177U); - msg.setDestination(932U); - msg.setDestinationEntity(130U); - msg.plan_id.assign("WEPESZYGHBROOCBTGILYQVQMSZFKA"); - msg.description.assign("OTSEILIJAEPYXOSGYBELOXRCECUROZHFJALTYOFCYZNLBCQAOJCUJUGYSEDUZBKBRLGMHXLKSBWKPWFMMAYVDGMTJYFIFRCSAMPUR"); - msg.vnamespace.assign("PDYJHCCMVXSNJKYFAMTRGJMRUVHGWSRWLVLBKORCDIGPBYNUNSDTSAFPEXQXXUMSAEBOXHAYEMDZPWHNLHUCLOEDUIAVTPQQUZVJKRLVDFFPVPXDTKSZFZRLEBWKTIOYHGBHOBBZODXQWCJVCYPMISJCBFAJEYATHSQNZTYJWLVKTENQLTFFJKFPEJCNHFLGXNRZITCGYBRO"); - IMC::PlanVariable tmp_msg_0; - tmp_msg_0.name.assign("DEPPRGZGHFPYKBHVFPBBNVTVUBOTTCZUBWTDBGIVONA"); - tmp_msg_0.value.assign("YTEBKQRUWXMPLQNGBDWDEQCKHBDBIEPBWFFFKSVOWVRHTAFMCQKQBXZRYGGGDZTHBJEWJBYYNRIKMVFRJXWOSMKCGVLNZIAVYEHHJSFXCEUKRSUZYSILNLHTHLDXITGUTRMSHOCJNIVSHZAZLGFFGWKPRXMBOVAO"); - tmp_msg_0.type = 12U; - tmp_msg_0.access = 44U; - msg.variables.push_back(tmp_msg_0); - msg.start_man_id.assign("UOWNSWMCGD"); - IMC::PlanTransition tmp_msg_1; - tmp_msg_1.source_man.assign("PMTOQELUKBJHFMSIXE"); - tmp_msg_1.dest_man.assign("ZFUHETVYDJRILZNCZGMVCBXDHTGBTTBSNALQOHOQIFEIRBXRMZHFEFJOOJGKVXPJLSNPWKZNZOKKKVXPMCACKORWBMWAQRGBPDNKYNJENSCRCIXMRAHLPLGJGXNGCQXSWIUOVQLVEYUPDHYFFTUTNZZEUDCFEIAXQYVJVF"); - tmp_msg_1.conditions.assign("OZWGNNMFJSBIJGGNDDTWVXYGXX"); - msg.transitions.push_back(tmp_msg_1); - IMC::AcousticLink tmp_msg_2; - tmp_msg_2.peer.assign("KPBWBNOVYRZAFCRUDPGDCUWLQXTPYQYBCAVTYOTCFXFSGAOYOQSECOGNBAONKQXLLIPHASUBXHFYLZTRWTHZLGWRFYCINVBQMKQEHVOJAINJREKUELTSPJRUWJBGSHDZAKKNEKMMPDPKWVCDVAGQMTDBVXDNHORKJZTNQLPBFIZWSFTEADSXMECAJSMCTHZEFGL"); - tmp_msg_2.rssi = 0.736607589618; - tmp_msg_2.integrity = 60617U; - msg.start_actions.push_back(tmp_msg_2); + IMC::PlanControl msg; + msg.setTimeStamp(0.652821687756017); + msg.setSource(19232U); + msg.setSourceEntity(83U); + msg.setDestination(15464U); + msg.setDestinationEntity(83U); + msg.type = 214U; + msg.op = 244U; + msg.request_id = 1350U; + msg.plan_id.assign("TBPPDBOUTAWWYLDHAFCSUNSHKJNXZKIZAXEQYHBUKWIDDPEFWIVWEESFMRYLTBBGLWZVPGGIUUKWUINVGFTZLLNLCAXRUCMETEDAAOGZCIROEXTQPINBGJMVQQSRDNKXYEJXJBDWQFYGNOSFSKJWMSATRQDPLSHDTZYKUYAGQDCJHMKHEXNLULOFQOXCPHFCWGZJOLIJAOR"); + msg.flags = 50204U; + IMC::DesiredVerticalRate tmp_msg_0; + tmp_msg_0.value = 0.8871622457846082; + msg.arg.set(tmp_msg_0); + msg.info.assign("FBWGTARCUQNMIFWTAABMFOBZJVQXJHHYLAIQVCPZTNYEXFVWFZNDFJIKOUNSKQRXENWSIWZAYCILPYVMZTLCIDCWHRCCHKTTSRPAWSIYUGOWGKJWDOWTQFYRXCSLLJZZJPBBOMNODVNLXITEODNNKGVSVHREGBJSQKSQMJFAUMUGAGEVINEZQPDMTSFKMKDEUXFQKYYSAPPHKCBULDJQMDUVXUCHRJEPGAPRLPBEBIHHYXEUOTLXHG"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanSpecification #1", msg == *msg_d); + test.boolean("PlanControl #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18235,42 +21045,27 @@ main(void) } { - IMC::PlanSpecification msg; - msg.setTimeStamp(0.583480243532); - msg.setSource(41969U); - msg.setSourceEntity(4U); - msg.setDestination(59475U); - msg.setDestinationEntity(226U); - msg.plan_id.assign("IWUWNXDWITTDQYQZURAKCWXOKY"); - msg.description.assign("SDKBMHAVOVOCUKSIVGGVMWFTKZWJIGTLIEKTLUKEWSHGEBSDAZENOQTZCOJOXIJNDHBMYMWBHIWGAGDJFNVDRPIPUREBQVUREWTJMYLJYUMLLF"); - msg.vnamespace.assign("KGDZLAOBJGQPKZWWUMAWTSPTLMJPDUDRKSZFJZLYZPULOY"); - IMC::PlanVariable tmp_msg_0; - tmp_msg_0.name.assign("GYCQVPGEUAGAWDWMEEAPJAHAXWCWQBPMEMDWRFJVKLIEFCUYGQVGFKRKVZSLXAQKTWHRLNCRFZNGZKDPZAIJEBIZWDJBZMSYQAIGBPAKEXHRZNBTFNTNYFOXLSGXBOHSBZWPFBXBNMUOCYITOIRHSQPYHADWVFJUXROXUSNDGTJTIWODVURVMSNBLESUMJVHIQMCZUHXHMYJCPHQCEQKOJLYJNYRYNTRFL"); - tmp_msg_0.value.assign("PCUSTMPACHXZNRBXHOUFNAITTUQSPUMWKJECPDXWSGABJHJLXPKBSZXNNJKDBEYWPCPHWIIGVELOUTVVARUPLTNEEZXAWZYMDMABKDVXSVXMQOSRDHDCZTVTYORJCZLMYNTVNYZFWFBUDLOAROO"); - tmp_msg_0.type = 176U; - tmp_msg_0.access = 250U; - msg.variables.push_back(tmp_msg_0); - msg.start_man_id.assign("OIRBEXCNEGZCTZSVDLTDRVVTKWBFMZVBUCKFRMNRZUOGEXQVYWGAPLKBQQWCUJBMMVWPVLZXOOZPIOTQKDYSZXDXNJEMSPXWSDISICJITSADBJHUGMBWLAHUXSQZJVZ"); - IMC::PlanTransition tmp_msg_1; - tmp_msg_1.source_man.assign("VEKWVKTGUFCABQBEHONGNUDUYVBUAANGMBDXYPIUZJRIVXLFQMTOAEIJEJOBTCPJIQZQPAKSGKFADPCLZGRWAJQZRVHXITMWFDEFSPDBDJDXDHYPLKUFIBPVILBKSWLNCMHQWSAGHLVRTQYZPMHNBUNWZEGLRSRFXJEKQWOZWVHT"); - tmp_msg_1.dest_man.assign("UMNBYDESOSYBMSXWQKMGQUFWOMHXGYECIAUFTOICADSYEPOTQICCMGAKPZHAMZJTUDFGUTNYAWNHLNSICVWUKRPNFBLRXEKWXDHBYTJJIKGTOJJXZKTUXUZBNDPBGWAZLIDFOZLSRKJEPRRZCILBOEACYPLDFHMLQQYTZYBMTQKHEFWBJLZERRYVXSLSVPBZOGCH"); - tmp_msg_1.conditions.assign("DJMUYLOQHKXAUOPPZZKZTNYOTCYHEQJHWFSJ"); - msg.transitions.push_back(tmp_msg_1); - IMC::UsblFixExtended tmp_msg_2; - tmp_msg_2.target.assign("WGMLCUCNKDOEXQYROJUSIKAPNRBVIGQTHLITCNPZBNHPGLPMIXJPMWNDMQFRKSKZIBUQFEKZDHJCSXXIPOONEEWMWEAVEPKWBSKUGJGLWBQNQXSXNIIYUNBWDDDYLVBJLJTRSTTKEHJYATIZYRMFG"); - tmp_msg_2.lat = 0.593768610186; - tmp_msg_2.lon = 0.2977772871; - tmp_msg_2.z_units = 137U; - tmp_msg_2.z = 0.595619295221; - tmp_msg_2.accuracy = 0.479290900037; - msg.end_actions.push_back(tmp_msg_2); + IMC::PlanControl msg; + msg.setTimeStamp(0.7697003222268091); + msg.setSource(61903U); + msg.setSourceEntity(224U); + msg.setDestination(57635U); + msg.setDestinationEntity(70U); + msg.type = 42U; + msg.op = 8U; + msg.request_id = 61068U; + msg.plan_id.assign("MMBFXWGAXCSNJTMGGJPDHPAIEPGETSWTBRBXYXOZXYLLWSNHKAVYBOKWEZCKCTWTOAUXSQDIRIUPJERMTGXFFYQMCZCSUEILVERBPCOAWVKNGZJNJSDUNOIGZGJJXSXTVXJVSPHGBKUJFDYCPHVCTNCLCWYDHQERRDZAQQFITLPBWMYDLKBDEHWEYLZOAURVHUVKKRILOQFQNONZTAVSLUJPMPFOUVNDRWHQRMKHIMBUQNK"); + msg.flags = 6512U; + IMC::ImageTracking tmp_msg_0; + msg.arg.set(tmp_msg_0); + msg.info.assign("EUPKVRUANQEXZVRFXOKSKBVISVULDAKJCPEIQTZAWGWFFTVANNJHCQQABELLMYZCJYNMAVEIEOYOXPJDPOCLM"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanSpecification #2", msg == *msg_d); + test.boolean("PlanControl #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18281,38 +21076,27 @@ main(void) } { - IMC::PlanManeuver msg; - msg.setTimeStamp(0.679819824288); - msg.setSource(14285U); - msg.setSourceEntity(43U); - msg.setDestination(1764U); - msg.setDestinationEntity(5U); - msg.maneuver_id.assign("WFTIXTBIOHCHJBUTVCWEUZCVXFZZRBKSUTIACULZMYDFKXTBLGNEBUPAJLGBVPTUGDXKHLCBWDEYOBNJSDHPEVRKIENWJZEQROAMZEPCOEIHORMLRPCVQCLDSRMDDKWUZWRSVSOXJJTMODYQKMATFFGSNJWUAIQOVFRGFZBPYKXWTLXYZNWHEKPQLPODRNAGGMCCQFHLZASFKNJGVUYEOGWBHQMQSSRMH"); - IMC::Land tmp_msg_0; - tmp_msg_0.lat = 0.165999124682; - tmp_msg_0.lon = 0.355539358966; - tmp_msg_0.z = 0.208163612756; - tmp_msg_0.z_units = 9U; - tmp_msg_0.speed = 0.0904969622837; - tmp_msg_0.speed_units = 242U; - tmp_msg_0.abort_z = 0.632723203214; - tmp_msg_0.bearing = 0.73244002991; - tmp_msg_0.glide_slope = 100U; - tmp_msg_0.glide_slope_alt = 0.823472783175; - tmp_msg_0.custom.assign("LAOHZWIOXNRUSAEQJMLKLIOQCYSAIEJYPIGHGSMYWZTKQPVEWKBJEAHQZIIDCDSIDQKVWMNYTUXYXVOTJCXTXPEBEOSZSJXOGZBQBIUKOUGDJZMCPHWMCQLXDBZAPPFWIRHERFKRVHVGTEUHPKFSFFUBDPRUTMDOGCMZWQQZFBVNPFSRAMKJLWAXBLJKHTTOTNVLSACNGHMLUX"); - msg.data.set(tmp_msg_0); - IMC::PowerOperation tmp_msg_1; - tmp_msg_1.op = 190U; - tmp_msg_1.time_remain = 0.931969074551; - tmp_msg_1.sched_time = 0.497080204698; - msg.end_actions.push_back(tmp_msg_1); + IMC::PlanControlState msg; + msg.setTimeStamp(0.24187393352922482); + msg.setSource(29018U); + msg.setSourceEntity(183U); + msg.setDestination(50811U); + msg.setDestinationEntity(191U); + msg.state = 51U; + msg.plan_id.assign("WBPIQCODZTZGMUYZEAJUXWWPKJHKWUSXOGJBUYHENTYDUIORXVRRWLESBRBECFHKBWPIUHZYSDZJCXILIKAAADIMSRAYRLCGFKO"); + msg.plan_eta = -629325464; + msg.plan_progress = 0.6781428134014473; + msg.man_id.assign("FMWESBLEFPLOANXCCKAJWLCLGKDKGZVYCBJJZOLNCPBZPZHHWGOSRQYCTUZZDKSRVTHUJENYJMUBCNULILZ"); + msg.man_type = 46603U; + msg.man_eta = -389880664; + msg.last_outcome = 60U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanManeuver #0", msg == *msg_d); + test.boolean("PlanControlState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18323,25 +21107,27 @@ main(void) } { - IMC::PlanManeuver msg; - msg.setTimeStamp(0.7291500656); - msg.setSource(34201U); - msg.setSourceEntity(120U); - msg.setDestination(6207U); - msg.setDestinationEntity(183U); - msg.maneuver_id.assign("WWBIPLHDKDRCVXLJVZBCMLEPNEJZCDWQGZKMFCRSVZZNGAAUOOQNDHBIVEDKQG"); - IMC::CustomManeuver tmp_msg_0; - tmp_msg_0.timeout = 43199U; - tmp_msg_0.name.assign("GQUUFAELRIKSVVESRHVVWBODAQRJKJHIOFVGJZPHZNNGRYEBPDHAESDCWCSJWHYPBXJLUVMUXZIYXBPUMEAVGDXXRDISFZEJWIOXOKZLKTWAKDCGTKLERHQRTBCWKQGJDVZGPPMOIESNRLPRDYPAYQFBICKJWYHSSANUTPDUNRPVLHMFLFNJXFQUSWYYQTLMFEMBXCDNNTCXSOTQCCMBINTTGGMBLKOOWZAMUOHTUHQOLAFGNZXCBIV"); - tmp_msg_0.custom.assign("IZFSEPHUCWKYVSJEYSHKVWOZTFTMPBLZCRHEJWANVOVJCKWQLUCMDJDYKQDVNEVCZXAFZKENAODYRHKHPTGGMRJLZOJEBUBDYFAITSLXLZGHVQGBBLVMKODURQPUISUVDXNMJRBTIWZGHOCLXSBADWBGQXX"); - msg.data.set(tmp_msg_0); + IMC::PlanControlState msg; + msg.setTimeStamp(0.9638486918068094); + msg.setSource(2413U); + msg.setSourceEntity(10U); + msg.setDestination(9187U); + msg.setDestinationEntity(237U); + msg.state = 203U; + msg.plan_id.assign("FDZSWOSYLXFOIYKGJ"); + msg.plan_eta = 1181100550; + msg.plan_progress = 0.326406161348867; + msg.man_id.assign("UPBJAMVBJXOFEHNHFRIGSGTHTJIFDJLHCFVNEAXASNMBARQTOAVFGRRPEYZOHSPLSCWRUIMSIKDQEBEKFZXUPTVFSVJOVTAHXCQXZLNFTHNICBVLJBMGIZCXHCZUMLMALUUNHYCCWSFOOTMYVKZJURRSGQYZYDZPNKLYZUABRYKQQWBKWYRIWFDMKXYDHWEGXWLLGBTUJVIPNDYOXBJEX"); + msg.man_type = 18247U; + msg.man_eta = 785994956; + msg.last_outcome = 108U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanManeuver #1", msg == *msg_d); + test.boolean("PlanControlState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18352,36 +21138,27 @@ main(void) } { - IMC::PlanManeuver msg; - msg.setTimeStamp(0.56320471847); - msg.setSource(46860U); - msg.setSourceEntity(249U); - msg.setDestination(26742U); - msg.setDestinationEntity(244U); - msg.maneuver_id.assign("BWIGBZPRVJWFZXUHFGMLSKYHTKLHLNOGWAOMAOLIYHCOQTFNBDHBUCUROHZAEEXLMJDKWQJUXPPDJAEYJYCCLWCGMNNVRQVZIMSQGHNZUOPFSJQVZBRHPXSISYHVADJNWDM"); - IMC::StationKeeping tmp_msg_0; - tmp_msg_0.lat = 0.906116322988; - tmp_msg_0.lon = 0.0747889649308; - tmp_msg_0.z = 0.969039561819; - tmp_msg_0.z_units = 85U; - tmp_msg_0.radius = 0.227847224432; - tmp_msg_0.duration = 25584U; - tmp_msg_0.speed = 0.825506562349; - tmp_msg_0.speed_units = 56U; - tmp_msg_0.custom.assign("JRVYXRKEHIWVUWUBYGWOWUCTRGOJQLTFKBCCNLQEYJXFPSXOQIZDMFQCDLIVUIEPKQHSBBVEBVDIZDEDMBMORNMRFYZOEUSMACGTWVPLDQGTVSNJZQYHPB"); - msg.data.set(tmp_msg_0); - IMC::QueryEntityParameters tmp_msg_1; - tmp_msg_1.name.assign("RRTFLRCXOHBWQKSCCIJUPJLRCOMKZBJLKJETOTACSMIVKOASFBVCUBFUDPWSHHOZXLGWGNGPUZWQFFSUUZTUBHDDFQBGPMVAMHPGXIFQJVGMOECPFUHXEWREAGYVXYFXRQYAPPVYADHQVKHOWEJRVIINCFXKRLYRZZLPNUOZEYKJTXVDTICITEEKLZDBLJYAKGNEMI"); - tmp_msg_1.visibility.assign("RKLAYFKXMOFVMLHJSDIBYEBNZQVTIZLGYQFEHKQCSAXRQRRIFLSOEJNBRISQQJFTAPVBXEOGCQYUWNWRNJYWUANEVCPQPKACGWUAXHOPHJDRLDCVCSPAXXFTFRUOCVNJEOUHGMYBOTNOIH"); - tmp_msg_1.scope.assign("CHOZVFMXDNGUIBINXBHOQZKDTLURPBAJFONBDTLTHWOWLUJPFRVAVGQWHXMRXNFBAQHDWTSEJZSJAQA"); - msg.end_actions.push_back(tmp_msg_1); + IMC::PlanControlState msg; + msg.setTimeStamp(0.6555833212651793); + msg.setSource(56903U); + msg.setSourceEntity(144U); + msg.setDestination(63503U); + msg.setDestinationEntity(230U); + msg.state = 183U; + msg.plan_id.assign("GRMMQVOFZOJTIQNJRLQWMKSGOKEJEHXNVLBYPVWDMAEDZLUNOSWRXTBCMFTLWVULWCTJTHWRZIUCYJYKUQPQLLMPKIGPPXBHANGZEABIIOYOJDVJRWJEPNHSXVCODXGHGCZOAPUKDAFJCWKUSZTYYHCGKQLKH"); + msg.plan_eta = 1556622509; + msg.plan_progress = 0.7188685773510513; + msg.man_id.assign("GUIPUZJKETMSBKIAYMDKZVYNEFHWKMOFIKGNGUSXYYMRAECVIU"); + msg.man_type = 35350U; + msg.man_eta = 862135614; + msg.last_outcome = 19U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanManeuver #2", msg == *msg_d); + test.boolean("PlanControlState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18392,25 +21169,23 @@ main(void) } { - IMC::PlanTransition msg; - msg.setTimeStamp(0.233150290386); - msg.setSource(60729U); - msg.setSourceEntity(104U); - msg.setDestination(53911U); - msg.setDestinationEntity(120U); - msg.source_man.assign("JLBXALZUYQBAEMVSCOCVAJZRBFMPFNSEUNFBOSDJQWP"); - msg.dest_man.assign("XNCNEICTGCUXCVRHHEFRS"); - msg.conditions.assign("HAADNSJFPQTSOHYZXUDMSIYQWICHGNAKEAYNWLYWGEDLXXOUTSEHUPRXJUOTBTDIRPDRZKCBQOXBIXAWKCEWJDPGWIIQKRVQZGMRSAOAVOGCMZKMCAXOVYVTVQHPDRUN"); - IMC::Temperature tmp_msg_0; - tmp_msg_0.value = 0.165532929349; - msg.actions.push_back(tmp_msg_0); + IMC::PlanVariable msg; + msg.setTimeStamp(0.0670037262029558); + msg.setSource(60068U); + msg.setSourceEntity(107U); + msg.setDestination(52230U); + msg.setDestinationEntity(90U); + msg.name.assign("FQJURCWSGMUCNVZUWRAEDGPAUTBVBGINFXNQDVYELIWGKJZLEFBAXYSPMXQNENBKDJDADNCUIALGSNPYHGQEOFUOLDOGHMLYSXEZXSWQJAFUMSZIKIHHMOIFIRRUVSPFTOKCVCRDQLKDSVZZIKHJYTQWWCGBMDVJWKGXYGAXTYEVKMHHPRMRCATTCIJPZCWJKNNBXKVAEQTAQXQLHDPMSBPFEOTZMXBLOCVLYZTSOBOEYRUJRYNFBUHI"); + msg.value.assign("SQIADWOLVHLXNZNGZYTMNPBUCRZCSVAMVPSR"); + msg.type = 24U; + msg.access = 118U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanTransition #0", msg == *msg_d); + test.boolean("PlanVariable #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18421,22 +21196,23 @@ main(void) } { - IMC::PlanTransition msg; - msg.setTimeStamp(0.0477491488578); - msg.setSource(1143U); - msg.setSourceEntity(93U); - msg.setDestination(32537U); - msg.setDestinationEntity(85U); - msg.source_man.assign("YYRFMZCJJUACFGGRRSCHOHZTAHEUMPPEXOQ"); - msg.dest_man.assign("TOKGIYPRFEOCVPJXTDHCXIUHNQSDGVLEYIHPMEVFKPSNBLMAASYSAOZJRCQEJTLRGUERJSNBLJJWBVWIMRENPGAGZFDGKDRSKMUJXCZHQQCYNQZOIILHUSTOURYYSCUBBQPHEWRLPDWOKXJXAMAGLFEVZWMZMOCRDDVZXWPNVIOXAKDVDBTTISUSQEQFGGFWNWBPVKTHXBUAYCQXWHHJCYMKV"); - msg.conditions.assign("RFVXYRRHZNZMOEDRGCSHPBFZYCHHOCQYIXXVICSVYQVBKCMBUNFEKQSPTAULIDHPPMYHCKWJJAGRNYTTTTWXMZFVIIOFSTEACKMAOEMYENTUSXAKJ"); + IMC::PlanVariable msg; + msg.setTimeStamp(0.8584213684032449); + msg.setSource(6930U); + msg.setSourceEntity(116U); + msg.setDestination(52752U); + msg.setDestinationEntity(250U); + msg.name.assign("IQETTLLLKFKYOUDOWORTKKZWZNGPQOTCYWVZBKUCPXQRUZVKQRRILQAGRNNYOAAHKASDLHXEJPRFALVDBPDZEXXUJPCOXLWMFCMFEQNYWXPRIEJNNAMFBISAIIFVNCOYJLLUZGM"); + msg.value.assign("EZRLNESNPAXXCATWUDHQAETTBCRQJSCREYWDY"); + msg.type = 47U; + msg.access = 170U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanTransition #1", msg == *msg_d); + test.boolean("PlanVariable #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18447,22 +21223,23 @@ main(void) } { - IMC::PlanTransition msg; - msg.setTimeStamp(0.339097126384); - msg.setSource(32667U); - msg.setSourceEntity(199U); - msg.setDestination(37920U); - msg.setDestinationEntity(138U); - msg.source_man.assign("ASYRVOTXLMEYWGJKOZFINFHJDVBRKPDRFEJFFLXLTXQYTAEUURQCURODWCDZVPQOYSFGQGMUEZDGTLKHHRJJBIDKTSXLRIAIWXMYOKOHINHVNXESYCRQ"); - msg.dest_man.assign("LQKLZQOMPKAPAVSKIOVCNPNQZWXASCLVBWCGBKGPXOBNBLKWGXLGMZWPFIHNOSMSOBBWFERBSCLHZZXWPBMGTJFZTRUJPMETTEHWXSGHLQUAEWPISCTQKTRHVCUVRUBQQYHIFSJRYVDDMYVGAJYVDIDSRMMVRAAFNLHOIURXFLNGEQUFGCSOJIDMKGZIDHNWQJJYUODAFZTJKDQ"); - msg.conditions.assign("FHXDUDRJNIEAOWYKBUTOODMSKXYFWKBDVLTWHOICCUHILOKMFGQNBHCQGNPZEFSLHUYYZZTLVORQJPXECKRNSLRFUITHGLITDJLFHLASAEYBWQVUCVGXYRZPRZHJLJCGNDMACJBBYBIEJFAVAIWEMJKMNQNNGZBSQCHYRAKSVXOWTWRZBVWQPPSCMKGEZQCFTPOUKFDKMVGPMGVXXQJTMIHZSEUOIGRYDVYPJASSRZTBXUQDUFWLIXNADPWTPO"); + IMC::PlanVariable msg; + msg.setTimeStamp(0.7851155080447252); + msg.setSource(65251U); + msg.setSourceEntity(93U); + msg.setDestination(55655U); + msg.setDestinationEntity(3U); + msg.name.assign("XMDIRFKWINLHZIQOZEIUPVVXSHKSYULLGESTTQZZSEUVJKIUEWQOHTPXAGUTWMIHAFEACAQAVTXPYBZYQKJEDXXBRCFFMZQEJOSJWFYVWWFRDQVDABZKROGBUENMLMLRGHUSSFHLACTRBAEGNDORURJSXGLVZQKBYMWDQIFNPAJJOVPWPKNMOGKTCBFDCBDMNOFHT"); + msg.value.assign("DMYLYONLJEVGDVGIQVXZBHPAVPIUUHUZSCTCOZDVIRTOVMMGRSKA"); + msg.type = 167U; + msg.access = 215U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanTransition #2", msg == *msg_d); + test.boolean("PlanVariable #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18473,37 +21250,23 @@ main(void) } { - IMC::EmergencyControl msg; - msg.setTimeStamp(0.503145808583); - msg.setSource(10513U); - msg.setSourceEntity(209U); - msg.setDestination(9787U); - msg.setDestinationEntity(47U); - msg.command = 15U; - IMC::PlanSpecification tmp_msg_0; - tmp_msg_0.plan_id.assign("CCFOXVUGDLZGMOCJCFUKPJEYAHSQANDKRTFTBXSYVUXHA"); - tmp_msg_0.description.assign("GNLKHRMLXYEJRPMDSNBHUYOMGKQFFWLIMQISJDEVTKREPBLZMIXRKZPXOATBQYWSEHJVUJFRRZXCYUNKZGBAPOLLWBPDTQNSLEEPVQYOBZIQTJZGAUCHXPAKVXAQOWEITNKUZMYRTCMIHDSWWUAMQBYRPASNQHJRAYCTYFDPGYHVUOBGBFNDJODOCKOFMSUTHDGGIZLXDWUNZCXJCVFXVKSZSOIAVECBSJVDMWNJHLXIWITRPLCHFETGFAE"); - tmp_msg_0.vnamespace.assign("WCYTLLEHXWCIWHIFOALLGWJZSHOYZENTWBUFUKHRRIJNDXOBZTOZCYYFVAECTHNJQYWOFFFJIQAYRSPIWVNNNUNGPOLMVFACEFQTJCESUSWOXDCNUGSDBHIVXPSQUVDLCIHRMEGPGQVOEXOZEXZJJQUEPRHKXAVBTBIVXXRUKMTQGFPBQQMFADPYTYBYDKPUMPOTKZHLALMVVZEKJGYBHUIGSRGSDJIRGWLAMKN"); - tmp_msg_0.start_man_id.assign("PCWPOAHQQGYKZVMZOOMWQCUNXMRBRZTWLKFBPKNDZSAGURDOVAVPVULRMEQHFTDLGPIYHINQISAPZHJDBFEZXLNSKKWNWCRKEJEI"); - IMC::PlanTransition tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.source_man.assign("UPVJUZSAAYLDVURKZFIRMWKSMYRFCUHLKVRJZVBTQBXWGUTOYPPIEUCGBDEOZMUKGFNXDOUMYUMRAHPQCGJEFFHDJISPALXWGHQWLMGJQNMFID"); - tmp_tmp_msg_0_0.dest_man.assign("DWLNDUSJXRJJEGORYDMYMIPCBWLMLOAJHUVRZJQKPASBQUMQSKXMKUTHPDMVFKHVQTGPVPHBQRTWGFYWXNQDGOWTLOUPOHICFAKEJYBTHYOXDMYNKLJETUHLPOOJNVTDYLAFSKROFPXERVHQEHNNDCIBEXCARCPLIWTVYRUJXGACBZRWKOEVFIIZVECYLLMGKAWIASFZIBSSZGGQBZYTZKEZWEBCFGHPNFNJMAGWISIRXNXSFTZUZUQDDUXSQC"); - tmp_tmp_msg_0_0.conditions.assign("WZLEXZNVVLYYMKVVBPOELHT"); - tmp_msg_0.transitions.push_back(tmp_tmp_msg_0_0); - IMC::GroundVelocity tmp_tmp_msg_0_1; - tmp_tmp_msg_0_1.validity = 150U; - tmp_tmp_msg_0_1.x = 0.393978713507; - tmp_tmp_msg_0_1.y = 0.0681755778108; - tmp_tmp_msg_0_1.z = 0.323645131729; - tmp_msg_0.start_actions.push_back(tmp_tmp_msg_0_1); - msg.plan.set(tmp_msg_0); + IMC::PlanGeneration msg; + msg.setTimeStamp(0.6546612923352447); + msg.setSource(49246U); + msg.setSourceEntity(245U); + msg.setDestination(17866U); + msg.setDestinationEntity(65U); + msg.cmd = 124U; + msg.op = 33U; + msg.plan_id.assign("GRGPWKSRSNGTANHLFQLQDZYATUDXFCDKQCTBZVTSWJWXLUPAJXOBUZKNIMJWZZKIBPBXFOKJYGLHNJGHHBZTYSODBPHMWGVRPCUN"); + msg.params.assign("YKVIWMPHRFZRCHUBQADNPWZFIGYSTXVDBNWZGKJUHBHBNUCLNLXZQHYXYBDRALGDIZSKOOWLEVGUAJCGQXPNARWHMMMAISTBRSFNGDXENMXFTYOCESSCCTKQJOYANNKJGBFNOGQQIR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EmergencyControl #0", msg == *msg_d); + test.boolean("PlanGeneration #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18513,44 +21276,24 @@ main(void) } } - { - IMC::EmergencyControl msg; - msg.setTimeStamp(0.753037901668); - msg.setSource(17356U); - msg.setSourceEntity(196U); - msg.setDestination(40651U); - msg.setDestinationEntity(37U); - msg.command = 11U; - IMC::PlanSpecification tmp_msg_0; - tmp_msg_0.plan_id.assign("EQVLRUONXKHUNHMFPMBXFUEKCGREJMPWETBWHABVWXUBTPTKQGRYJWPYDSWCY"); - tmp_msg_0.description.assign("XBJONJLXFTVWVHIZPGLRIOCFYDXQLIUUSBPVIQK"); - tmp_msg_0.vnamespace.assign("FVLYCZIHHIRTHDPYAQBPFQSWAYJRLAOSTDFATDQBUSLGGJZNBJRGOYNUXIEMEDMICVHIOMFTEZXUMXXOPSUETVJCDMLUAPGSQYHBKZQHOMWBYWOPPGSSBDUCQICFBMKAVWWUPZ"); - tmp_msg_0.start_man_id.assign("VNAJEJPSINUCKMLZNUEHJFRRIXZKHCHQJKULMTRDFFYFMNUE"); - IMC::PlanManeuver tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.maneuver_id.assign("INDXKWCVSNYQTRQALSBITAPAHZYIQMZLKUFCACHOJWVCNTMIJLXRKBCCHNFONSLKDPDPKXMYEBFXUIKOPZRAVQZPUETNZJTQXEGUUBANNKGGZEQYVJTDRKJNEIUUMHHFRSQDRDZQVOLZNDHTWSRYXUSOLPWHMVBSRLXAOBFXQHSBXORVOBUCOVACMLGWYBEYGIFFAJR"); - IMC::VehicleFormation tmp_tmp_tmp_msg_0_0_0; - tmp_tmp_tmp_msg_0_0_0.lat = 0.326969415104; - tmp_tmp_tmp_msg_0_0_0.lon = 0.508209931973; - tmp_tmp_tmp_msg_0_0_0.z = 0.986135746252; - tmp_tmp_tmp_msg_0_0_0.z_units = 147U; - tmp_tmp_tmp_msg_0_0_0.speed = 0.480811796897; - tmp_tmp_tmp_msg_0_0_0.speed_units = 200U; - tmp_tmp_tmp_msg_0_0_0.start_time = 0.267580700694; - tmp_tmp_tmp_msg_0_0_0.custom.assign("YPXHNLKIEVNVCG"); - tmp_tmp_msg_0_0.data.set(tmp_tmp_tmp_msg_0_0_0); - tmp_msg_0.maneuvers.push_back(tmp_tmp_msg_0_0); - IMC::AnnounceService tmp_tmp_msg_0_1; - tmp_tmp_msg_0_1.service.assign("TMCVRLVQMNBKCHPEHJHPQTUZGOQDHFODJYBWEVQFGFTIGBWILBPMIXWLN"); - tmp_tmp_msg_0_1.service_type = 227U; - tmp_msg_0.start_actions.push_back(tmp_tmp_msg_0_1); - msg.plan.set(tmp_msg_0); + { + IMC::PlanGeneration msg; + msg.setTimeStamp(0.8727662181841886); + msg.setSource(26960U); + msg.setSourceEntity(201U); + msg.setDestination(21341U); + msg.setDestinationEntity(206U); + msg.cmd = 63U; + msg.op = 119U; + msg.plan_id.assign("GMSCUBTHQSFGAEYXUYJOFMPIYHDWBHHUHVAPSNBZDJJPDKPJZYAIRUQCPDXNZZOWYRROTCXJFXNEN"); + msg.params.assign("JQQPRLGNTSPOLGCBFHZZTPNFJCIBXQHKFDWNTRMFEHBPZKAXGSAUUJEDIRBZLKIGHHFCGXJKWEMHLIRCQODRAUSTMPYGVDXGENCOSMNBLQFUGFJV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EmergencyControl #1", msg == *msg_d); + test.boolean("PlanGeneration #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18561,46 +21304,23 @@ main(void) } { - IMC::EmergencyControl msg; - msg.setTimeStamp(0.671748293617); - msg.setSource(26097U); - msg.setSourceEntity(214U); - msg.setDestination(55399U); - msg.setDestinationEntity(142U); - msg.command = 34U; - IMC::PlanSpecification tmp_msg_0; - tmp_msg_0.plan_id.assign("BVWMXOZHCZGQSQRUXJDWVWQVYZVIAIRURPFLBBQTJPLJEQKIDQBCMDCMSWAANLCZNVHYZUEFXINCVFAUIABMXLERFBOFJXYRHMUHUMBWGRNGXIEHPYZWOSTHJYLCYPDNDHULZRTTKDHEHKSUQFFTNDWITMYWTTVDXBCETJDNIRWKLPRMSFPOPOQOSTVZSFBKZGMLOKEYVSGCUPAYNALGMEZJXKIOKCVEOEXUHYXJFB"); - tmp_msg_0.description.assign("DTIGWOZAWAMXIEPRGFGZMDJYAZOMTSBULGKLVDDZYDPSHHLBQYLFFANSCWVXCQSHVJDISVGICXKCHEUTTUASOPEXNCYNWIWBEINYBECCNFOKGVSVGWATJRURMKOMDRPCQJSBVZYBYBRFKAHZQEQUUWAFPGKQTIJPDBJKDWJKHOYGOPRTSFONQLNZPZJZIUIEMJRMREXECLLNMYMVXKXLNQJTHQPUXNVLUTWBHFFSU"); - tmp_msg_0.vnamespace.assign("ILWSMHRIZDZTYPGRERKXTBWLANRCPDZOFLUARFIJOXJBUGGNQYEBSIQXDNQYMCZQVMCFXISALRWZEPIJFXLYDTPJKAMQUZWMWCELKGJGBFFCAZKVVWMUNWUVDXDNSKXRTQIHJLOIWPYOQ"); - tmp_msg_0.start_man_id.assign("YEQJDDFPLXRWCTNLQBYFPRGLNOYCFUHQKSHXGWTSNXZHQGSTMBWTOTTVXCCGJSMIFUMAVJUWAKUPINSVJHZNPODINKHVOQKAAQKAOKQGRLOYQQUPDEYXTJJDYOOZXZDEJLZWLUBATBZBFRCRPKDDVNUIZCO"); - IMC::PlanManeuver tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.maneuver_id.assign("TBUPDCORXNMIKAOIYUADOQVQGNKDJVJCTXTDJHMQGGPSULKBGKORCBRVCYAEKDSWMTLQEHRXIZGXPCNZUKSBFVHWAFIHIELSRZRGSGBEYBLZAHOZOJHHYMEWKALWIZSJKFELTBTXDPNMMLNQYWXJOFQCRUQFHDUAPPQYFMWDYNJWNWZOJSMATFHMOCPIMBKEYRCJIVVTPUZCYQDALPRUSUETVWQENXFSBGNVXDFUCXAVJRPL"); - IMC::LowLevelControl tmp_tmp_tmp_msg_0_0_0; - IMC::DesiredPitch tmp_tmp_tmp_tmp_msg_0_0_0_0; - tmp_tmp_tmp_tmp_msg_0_0_0_0.value = 0.420566351242; - tmp_tmp_tmp_msg_0_0_0.control.set(tmp_tmp_tmp_tmp_msg_0_0_0_0); - tmp_tmp_tmp_msg_0_0_0.duration = 19631U; - tmp_tmp_tmp_msg_0_0_0.custom.assign("OINIRASIFXJJFLBROEXSSKGZNCDGCWRZXNLTDGBMKBSFROHYADKCBEYWCEHPGPHUAKGYUQLBKPFFNIKFUNMJTOTGEMDMMZQLPBUAZCUYUPCIZVRZSQSBEYMXIHMPZVIJEWXWVDRLYNHNAIRFEBKCYVHGEOLKXWKMCOLIAMQBHEOQULCAPNAYNFVWVJVDRWJSPIWZFRPTLXJTPFSEQVDQYDJUHQUATRQZHUSTCOGNVBWXDXJT"); - tmp_tmp_msg_0_0.data.set(tmp_tmp_tmp_msg_0_0_0); - tmp_msg_0.maneuvers.push_back(tmp_tmp_msg_0_0); - IMC::PlanTransition tmp_tmp_msg_0_1; - tmp_tmp_msg_0_1.source_man.assign("YNKWCVXYIJHEFMVJGYOUWQVCQYQBKDRQLBHFMPTULOUSLFKIUHWXPAXYYNFTETTXD"); - tmp_tmp_msg_0_1.dest_man.assign("PSOQCHDVHWIDFDSZARCPMBBVQTNRICNZTQEZQSQGBYUZSXLAMOJRSPTVFETUOYXKCKHPPBREPJ"); - tmp_tmp_msg_0_1.conditions.assign("LYYVTPHGNGPWXZSWHHYP"); - IMC::Pulse tmp_tmp_tmp_msg_0_1_0; - tmp_tmp_msg_0_1.actions.push_back(tmp_tmp_tmp_msg_0_1_0); - tmp_msg_0.transitions.push_back(tmp_tmp_msg_0_1); - IMC::TrexPlan tmp_tmp_msg_0_2; - tmp_tmp_msg_0_2.reactor.assign("BNXMUOIZUEPRXERRKRDOQLKSQATCINTXEUDVDMGONZRVKQXBTMISFXWSYUVKRZASXLDGNWWYKQTIRIHJVVNUWMCVJMICAEFEVDZEZTYOPKGWUQGWOHBILBYPCYTDPCTHHRFKASGQDLDTZXVQVHPQSPYHXAFJAYMPQBAMFTFOJBRJIGCUKGZWQPEEUANLJAIOLBASSWFJJS"); - tmp_msg_0.end_actions.push_back(tmp_tmp_msg_0_2); - msg.plan.set(tmp_msg_0); + IMC::PlanGeneration msg; + msg.setTimeStamp(0.18862026651149144); + msg.setSource(16422U); + msg.setSourceEntity(182U); + msg.setDestination(29487U); + msg.setDestinationEntity(77U); + msg.cmd = 107U; + msg.op = 232U; + msg.plan_id.assign("ZKYWAUHNCJXQZBVGFZOVSWVTAAEZEVROBKSFEIYMBRTGFBJAPBILSEIBWIALXHMUTMKLSTENYYQSHYZIKAZXIJWQEMIJGVCYHMBQHIAYNBPXZDRZJPGOCTPOFCFKWHOALNCBJLUCQXLCYTDKQXDQRNWGXDHHLPVSEOOMHPGIOMKQNUWB"); + msg.params.assign("WIBMEBNMLVLZMEJSFKHOHZSVAQWPRKRADQVOCSDPFGEXTHRIXJMQHIJTOYCDFOTIGONEVKUYBSBEQCLQPARHNTEYGNXGLUGTYRTLUR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EmergencyControl #2", msg == *msg_d); + test.boolean("PlanGeneration #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18611,22 +21331,39 @@ main(void) } { - IMC::EmergencyControlState msg; - msg.setTimeStamp(0.391140269318); - msg.setSource(61092U); - msg.setSourceEntity(244U); - msg.setDestination(21781U); - msg.setDestinationEntity(11U); - msg.state = 204U; - msg.plan_id.assign("XTNIRNJVEAEFWVTNAQMJOIECZKYBZGOPBGXFBRVAJABUOHMVPPUVJDXWEHURXCKQDKXTFOJFDUZGQCKDGSCWEPOBBFTRQBZNOWSGWZXLAFLMVUQRTNAZQTSNHIGMSFBXAKGSKYPCQWGUJECLJTMIEPWOWMCNJFMCHQDYKOZSOIVNDQFYZAISYKGRMHLLIXCTUDL"); - msg.comm_level = 249U; + IMC::LeaderState msg; + msg.setTimeStamp(0.9649855485774678); + msg.setSource(35348U); + msg.setSourceEntity(155U); + msg.setDestination(48468U); + msg.setDestinationEntity(109U); + msg.group_name.assign("XJZMRDUSUEZJEOOCGPEWLEFGPMXQYBPWVDYGNPKKVVTWCLGGNJMUHMBLZAPMFMUDSEKVTXIWFQVVNSDNTTOIWMKTVQYPILVBENXPAYTWASURROTLYURNUTQGNDFHYVIAKQQJIDEDKZBECDWYIHBIJGRZJXWZASOYRMQQOUWPKXIHHZNJDHKPSZGECOAFHUYAAJUHXSDZKLINPFRXJTQBFAXCBCLXQTRLSRMOBBALWFFOHJMGS"); + msg.op = 15U; + msg.lat = 0.36781337071798914; + msg.lon = 0.41024210199688893; + msg.height = 0.8875788994165655; + msg.x = 0.30837568950898087; + msg.y = 0.2960141088801507; + msg.z = 0.04660277832509707; + msg.phi = 0.8342193810065863; + msg.theta = 0.7508757241780255; + msg.psi = 0.4077858095960447; + msg.vx = 0.06689472170140542; + msg.vy = 0.852657407565394; + msg.vz = 0.3478267843812164; + msg.p = 0.34805166271635646; + msg.q = 0.3068372556408072; + msg.r = 0.650437418130653; + msg.svx = 0.5274224925828358; + msg.svy = 0.6923899828563189; + msg.svz = 0.937743289385441; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EmergencyControlState #0", msg == *msg_d); + test.boolean("LeaderState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18637,22 +21374,39 @@ main(void) } { - IMC::EmergencyControlState msg; - msg.setTimeStamp(0.785116635172); - msg.setSource(55831U); - msg.setSourceEntity(42U); - msg.setDestination(15088U); - msg.setDestinationEntity(144U); - msg.state = 107U; - msg.plan_id.assign("LFHABTNACNCRGJCOKYDRMLULWSBKZYXIBFPXTRNMZSBHCLADQBZWCZERTJHIDSFCUOMGHFNDEDWIRDARJOEVJUGHAEQMXQQNWWMURVPJLHPIFNVTVXVZOMKILONPJDRVTBEGMKQVGOVUPVTTGGHNPSRREISYXKAFDZSYKBASJFWUAKFSJTYCTUIMUEIUFZXJILTNEWLCPQOGJZBPOBGNIFSAYQYLDKDWXCWYHZEOYGV"); - msg.comm_level = 210U; + IMC::LeaderState msg; + msg.setTimeStamp(0.12993489287717908); + msg.setSource(45790U); + msg.setSourceEntity(76U); + msg.setDestination(20327U); + msg.setDestinationEntity(26U); + msg.group_name.assign("EYJVBGSEMQALZSWCLMDRHDPLWVFNEGTAXOUDXWMMPUNETRGWTHBCXQDUZDFUSCXBVTZBJAQBRUPVYPCJCNNUNJCFJSKHZIOJOMGAIEYMFYYSLFHNVLYYEHXOWDHSLBBMWYMSSDZRSNNWGQYEFTRQZZKQHLC"); + msg.op = 5U; + msg.lat = 0.32517510020888607; + msg.lon = 0.47088955965825685; + msg.height = 0.7218144704575788; + msg.x = 0.9960532813775682; + msg.y = 0.07673898826755232; + msg.z = 0.1354836024545324; + msg.phi = 0.38528690676310073; + msg.theta = 0.05613903921464747; + msg.psi = 0.2534435285403468; + msg.vx = 0.6250428844642739; + msg.vy = 0.3441964782421343; + msg.vz = 0.1868281486998854; + msg.p = 0.06649337367964969; + msg.q = 0.8671575193100425; + msg.r = 0.16455280700077657; + msg.svx = 0.19165096779869184; + msg.svy = 0.7509819662665753; + msg.svz = 0.21281879552672833; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EmergencyControlState #1", msg == *msg_d); + test.boolean("LeaderState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18663,22 +21417,39 @@ main(void) } { - IMC::EmergencyControlState msg; - msg.setTimeStamp(0.887692429032); - msg.setSource(37320U); - msg.setSourceEntity(191U); - msg.setDestination(6727U); - msg.setDestinationEntity(13U); - msg.state = 55U; - msg.plan_id.assign("VHRRJTATQOZKZSNCBGGDCZPQWVJDWNBUKKWGIVBYLKMBQKYVQEYLRQDNTQFPAVDCPOVJGRGXTZZCUHMLLFQIVLUBSNHNBWSJSHLJHTSCXAZAEFFFLNTLDBILPYKEHMPDRUBXIQUWDIBCEPCGUESCAORORFOTFQRUG"); - msg.comm_level = 251U; + IMC::LeaderState msg; + msg.setTimeStamp(0.11815116294491346); + msg.setSource(23560U); + msg.setSourceEntity(159U); + msg.setDestination(59753U); + msg.setDestinationEntity(45U); + msg.group_name.assign("RMGGSHTRTWYUCCOXVALQXYEPNIDDCTBTNRIGEJLUBPMYSIDWXDQULIEZUKTHTCFLIAOTWJNHTNXLJHAEGQZBIXFCVKSQXCQCGHMKABUHKNOSPOFBMYELIOHHARGIKDCBNKMYEORZHAWQVQYWVPJUVEFSIFKLQWZYMRVXODNWEBOOSCPKUQNADPTASMNAPJRFTHWGFMCDQLVSZDDJVJMRGLIZFYUSULZKUBRVPFSOMKBAFGZBGNZEWWRJYJXPYJ"); + msg.op = 222U; + msg.lat = 0.19682463957075924; + msg.lon = 0.23952121575695717; + msg.height = 0.35777140479749914; + msg.x = 0.11959040424925516; + msg.y = 0.42820451915351754; + msg.z = 0.6245604003943326; + msg.phi = 0.4053914291835766; + msg.theta = 0.7663610217665686; + msg.psi = 0.39823779007930504; + msg.vx = 0.0065790191323019664; + msg.vy = 0.9106486312420407; + msg.vz = 0.726474338914805; + msg.p = 0.18808030673048415; + msg.q = 0.655891346868051; + msg.r = 0.21014550832202195; + msg.svx = 0.03722705207409249; + msg.svy = 0.7451498462935837; + msg.svz = 0.47723006035603; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EmergencyControlState #2", msg == *msg_d); + test.boolean("LeaderState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18689,27 +21460,26 @@ main(void) } { - IMC::PlanDB msg; - msg.setTimeStamp(0.574705092136); - msg.setSource(25906U); - msg.setSourceEntity(26U); - msg.setDestination(50605U); - msg.setDestinationEntity(106U); - msg.type = 145U; - msg.op = 179U; - msg.request_id = 62390U; - msg.plan_id.assign("FYEEGSEPISFOICOKYLQPRUSGTSDXRKOXXZNRCPJLVHZWBTTMVDVFOUDUGITTMKEAHBEFHDGLPUANLHLGMHYWFBSYURGKYXJRRDNHSKAFZLHPGNASQGUWWSEKCWPJXWDJDIQREMAUALQCLJIXMIXYJQMIZBKXMIYRQZEIACRMZNSTUPVATOXNEAMCBLVAHIZJBEKQWXDGNOPZBVZHOQDYR"); - IMC::DesiredThrottle tmp_msg_0; - tmp_msg_0.value = 0.787051987368; - msg.arg.set(tmp_msg_0); - msg.info.assign("ZQRHEDCLDGFOYKVJFMMHDZINRPNMSCODQBXPBQIFQMOQVJMSIAMGIMTMELULJNGLPSTVLXCVRBKLAZROJTFUQFIUKSXBZDIODAVGUKUITXWPVJLKXSJZBCRIYKBPPGYUZFNTAOWWCBBZUEE"); + IMC::PlanStatistics msg; + msg.setTimeStamp(0.05852012472293455); + msg.setSource(55983U); + msg.setSourceEntity(2U); + msg.setDestination(2627U); + msg.setDestinationEntity(118U); + msg.plan_id.assign("GAQZQVSFBGFMZUXCRRMFKVTLJUVXNGDUDCMZKVHYPTQPWNEGJAKCIIGXKEKJCRLUTWGCYMPIJUSPNASVJNCLNSZFJOFYBYMQEDYZWKNAQLOHWWXDOHMCBTBLXTBVIMPWHQGVSPFEJTROYPEBDVXLFIDZJYSUUAOKKPAJDIEREENZSXGGXOCESKWYMTQJHIABLHYMTGCCTURHRHIDIQOWDS"); + msg.type = 52U; + msg.properties = 140U; + msg.durations.assign("ZSPPJNKIMHLNBRVGIAMXOFBEIVWL"); + msg.distances.assign("QOMURZFCILNJRBBVGJOVBLKEPSWHQDTEXIGQB"); + msg.actions.assign("UAIOAGJWVJZMAPHHXDRHSTIXNYFEHFXVITEDTKUDCCHDGUPEDQSCEXERGFZUFWANYFFZPULBZHSLKXMKBKGIFNJHRVNJBMXJBPWDQNHLHCXAEZVMWXOMBPMDYJECZKWVEVQYBFIWTNZCSTLCSUPNKROTLJZISRJQLGASKFNGHWIILPMQAAMQUGLYKAKPDZ"); + msg.fuel.assign("NECUIYIUNZYXZFUJPSMRQMHMKDCEGRGCPUZIUEUZDRBJYOTQIVKWKKSDLLABCXUPDWCIQRKIUZDZKTXXAOPFPVJHRNITFWWEGXJPOCQNBLLATRRDVSBDMFLYMKHPKJPBJAWFALHVYEBRVXEZJVYBFMSJTOKEPHCZB"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDB #0", msg == *msg_d); + test.boolean("PlanStatistics #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18720,29 +21490,26 @@ main(void) } { - IMC::PlanDB msg; - msg.setTimeStamp(0.0100726263878); - msg.setSource(53168U); - msg.setSourceEntity(146U); - msg.setDestination(14624U); - msg.setDestinationEntity(121U); - msg.type = 11U; - msg.op = 202U; - msg.request_id = 2432U; - msg.plan_id.assign("DBZPVCWIXSALRMJCHOSGZIMXOWJHVYTELVXKWAUBYGIJDRSVCQTKPSFCYVRAQSLHXXWUXXECDQRNQJFTBLDKMOOJGOHBFZUMFNLULZDYUVGEEZQUASQFJNEGZNRETQKWMZSHUTRQPKEINPNYPWWHRGVCVJLIKPOTOXLMMKPCNCEYXWGB"); - IMC::UamRxRange tmp_msg_0; - tmp_msg_0.seq = 51485U; - tmp_msg_0.sys.assign("HQDKQHJDPEXUKZSBVCAEXYZQJTTORSFJPGNYYTEVRNYSVSXCUQBCCWOFMAIJSLCPGRZXAWAZBSXZSNRPOKKMKGAUHNCLIGLKLJWIXMYUUESG"); - tmp_msg_0.value = 0.678938689672; - msg.arg.set(tmp_msg_0); - msg.info.assign("XMIPUTHDDBVQOMTQVD"); + IMC::PlanStatistics msg; + msg.setTimeStamp(0.6015955871051042); + msg.setSource(61425U); + msg.setSourceEntity(22U); + msg.setDestination(3503U); + msg.setDestinationEntity(62U); + msg.plan_id.assign("YMIWYDBWSKFFBFPINKADPSQVPNOQZZTRHSXNKTTPVPOXRHCYQLXGVAMFOSLJJWJXIRRAEZYSAJ"); + msg.type = 130U; + msg.properties = 164U; + msg.durations.assign("OHSOMMIKVAWFSCFCCBSNPPEQTPFPIDWDDHURCKJZIYZKCUSORJOUNSBTFBPDMYEJLMWYRNSRGUXSZTOOLVLQOHSNXKXEBMQ"); + msg.distances.assign("GYKXGKJRWKPAGDUIGUOQPCQHPWLRNFGWBQHLRZRJWYCAAFOJZSUDFXSMNYIJBWTAAEQYIDTRKURECDROYXQZTHNZG"); + msg.actions.assign("KOXHEGTMAINENHKTWQXGTSJMGOBZZBXZEHPITOFPECXMORZNTJYAEDKCYVAOQVLRHBFZTQBDPZOWJZFKIDDBUAKLVYJPNFNIGKZYXVPKSMOKJREUBUXGSLRXROQSIRVKNYUCQWTSQCPECWWIRA"); + msg.fuel.assign("OLSAEQZDTUUZVIMRBDOQPUYBMNXQXXETVEYRUKOTQMUGWIAASYQLNVTVIZGCYJHXEWIEGIWOGPBXXDHAZRZBKFHSZHBCNQCFTRNYYUWTSCEZYNAHFDHPOCHCPARSUPGBPGFLMKFCXXSJDCLNDVLN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDB #1", msg == *msg_d); + test.boolean("PlanStatistics #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18753,29 +21520,26 @@ main(void) } { - IMC::PlanDB msg; - msg.setTimeStamp(0.831127551662); - msg.setSource(45430U); - msg.setSourceEntity(245U); - msg.setDestination(63787U); - msg.setDestinationEntity(198U); - msg.type = 147U; - msg.op = 75U; - msg.request_id = 28614U; - msg.plan_id.assign("PBPOVETDEVCZDZXZVGH"); - IMC::CompressedImage tmp_msg_0; - tmp_msg_0.frameid = 157U; - const char tmp_tmp_msg_0_0[] = {-7, 8, 78, 14, 94, -14, 114, -18, 79, -128, 3, 24, -50, -89, -128, 16, -49, -6, -91, 53, -39, -16, 22, -63, 33, -123, -118, 123, -50, 10, -23, 26, -82, -16, 124, -11, -8, -124, 100, 121, -81, -2, 123, -87, -92, 44, -112, -66, 70, 120, -78, 5, 61, 62, 96, 79, -21, 106, 76, 101, 84, 61, 92, 29, 24, 5, -10, -113, 88, 49, 3, -1, -111, -107, 125, -25, -34, 108, -60, -19, -117, -80, -107, -44, 45, -84, 80, -28, -20, -12, 95, 79, 39, -103, 97, -3, 87, -20, -65, 29, 120, -95, 116, -74, 11, -67, 67, 91, -23, 39, 75, 67, 16, 30, -64, -44, -61, -53, 20, -61, -88, -99, -98, 8, 65, 117, 72, -77, -68}; - tmp_msg_0.data.assign(tmp_tmp_msg_0_0, tmp_tmp_msg_0_0 + sizeof(tmp_tmp_msg_0_0)); - msg.arg.set(tmp_msg_0); - msg.info.assign("GJNMECEWZKZOJWQOCATXVYRTUYROJHHVRHVINBFKZWDSUMLJFEAXVBVKQGMFZYFKMBBQOAQSCHMUPUXAQSQZTXLVKQYGCAVCYUAWHEDIVTWROGWNIQMMLYLHWENLFXFKOXKRNZLDVZQDHOAGYPPBHEAZLIC"); + IMC::PlanStatistics msg; + msg.setTimeStamp(0.4712941164426936); + msg.setSource(64164U); + msg.setSourceEntity(112U); + msg.setDestination(15334U); + msg.setDestinationEntity(2U); + msg.plan_id.assign("XYSQLPYSQZGYMBARKVJARWEWCKIAAJTJLBHULNMXGVDWUTIWQQMNFHREDZMWLWHUWOKQHZGZXUMICMECGRXDOUULCRUHDEIPLDLPUDNXVFIZIBPMHTYQKBKVYBJWJ"); + msg.type = 6U; + msg.properties = 25U; + msg.durations.assign("MUMOCYYWEDJEASZZYIOIUVGZMTGYRGGIVRBQMWLBVKTXQPFWPVBRCXPEWBVAIMFTMQNSGFAXJSMWQYBBNJFJMSDTHKVHIDEQLJKKERDXYZBCDVECXQJTRKHGHNSAUYTOANZZIPWHCSAZDPPUBKOFTUHGUZDJTGBHXWSRUKUDNEQTOQVCOXPLZPAUQRK"); + msg.distances.assign("SPWVUDXVFZOZMSHFMWBBAGGIOKQWZWCSG"); + msg.actions.assign("JCAPJRVKGULZJVURUGAKYDHPUNVPTZSJXPQQXLWUPCXKTCFSURZMMLHHLYNREEFQKEW"); + msg.fuel.assign("CGSFYLUMYKYRQWUZOIKBHAHQSZHMOHUVCMYBYDGQSGFXGGDCPUPYBLUGRXLBFODUXJSYNRQHBUWAZCJAPXTIWLKQITWNKTQMXUKWQWBOTLBIAVDKJEEETYQENVRAGJBZZHFINZKRXFSFIVIOVONKMLJJPKONHVWOYNGPAOAEEOEFDMJQDEHJTPFWSITTDWVXGALQS"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDB #2", msg == *msg_d); + test.boolean("PlanStatistics #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18786,26 +21550,28 @@ main(void) } { - IMC::PlanDBState msg; - msg.setTimeStamp(0.889447943903); - msg.setSource(53908U); - msg.setSourceEntity(91U); - msg.setDestination(44699U); - msg.setDestinationEntity(217U); - msg.plan_count = 58668U; - msg.plan_size = 1753216222U; - msg.change_time = 0.696862590237; - msg.change_sid = 4502U; - msg.change_sname.assign("CPCROESVJWTWIJNBQEHZSYUVFCKJDOHRQ"); - const char tmp_msg_0[] = {98, -104, 21, 35, -111, 25, -119, -19, -119, 30, -44, -52, -15, -48, 87, -60, -123, -81, -108, -77, -23, -17, 4, -65, -22, -128, 74, -26, 100, 125, 21, -88, 98, 0, 17, -57, -1, 30, -73, 112, -48, 24, 48, -52}; - msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::ReportedState msg; + msg.setTimeStamp(0.012320621933248566); + msg.setSource(31765U); + msg.setSourceEntity(202U); + msg.setDestination(4001U); + msg.setDestinationEntity(54U); + msg.lat = 0.980907051829262; + msg.lon = 0.21278259014979817; + msg.depth = 0.10491700599584441; + msg.roll = 0.9324979250538603; + msg.pitch = 0.8373155976980332; + msg.yaw = 0.7981304539115822; + msg.rcp_time = 0.7501173354874248; + msg.sid.assign("MFMSGNCAJQKOPPKYRJQESDKROHIYAZSXXTFQGIBEQZSAUXWJNQDUQEYFLWGHOZNMKHHNPEUCBJEWLFDUVZKDDEBFUAXRQPPJTMTLZMEFTZWKVEDIIGOUSYFDLWCZJVPHTXATCNWBOLZLEMCNSUBNWLBYUXTKAQFKMXAPSWLOYKDMUOCJQPYEJGLNGHHMJCSDFSQ"); + msg.s_type = 29U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDBState #0", msg == *msg_d); + test.boolean("ReportedState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18816,26 +21582,28 @@ main(void) } { - IMC::PlanDBState msg; - msg.setTimeStamp(0.213171900348); - msg.setSource(17848U); - msg.setSourceEntity(61U); - msg.setDestination(15531U); - msg.setDestinationEntity(134U); - msg.plan_count = 39392U; - msg.plan_size = 3921312340U; - msg.change_time = 0.328992362091; - msg.change_sid = 1748U; - msg.change_sname.assign("RPMDBKPRPHDISTVOUFVGVDIESOQGORFZHUQYHRXALHLTPWZBVQRCEFIVLKZQTIBSJMVXOGEMUQCITAKPCZADZLGSABJAVSKRHWH"); - const char tmp_msg_0[] = {-19, 1, 28, -42, 51, -42, 92, -112, -83, -98, 95, 78, 84, -52, 8, -79, -90, -4, -40, 10, -92, -60, -73, 108, 7, 59, -110, -86, 92, -126, 76, 103, 100, -36, 40, 81, -21, -70, 81}; - msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::ReportedState msg; + msg.setTimeStamp(0.5607005318904938); + msg.setSource(37532U); + msg.setSourceEntity(156U); + msg.setDestination(64688U); + msg.setDestinationEntity(246U); + msg.lat = 0.24511332611771097; + msg.lon = 0.8629877619165197; + msg.depth = 0.17304382693839226; + msg.roll = 0.409021593562532; + msg.pitch = 0.9386970805523027; + msg.yaw = 0.5904838902920061; + msg.rcp_time = 0.7606884478177615; + msg.sid.assign("LUOTBOJBHGNDTEOQQEFREMLWEDHUHVSCCXCNCLEWMPVRTKSFZTHAICJESKLBSXEANVHRFIXUYKHJWOMWXGBMHCGBSPPGVPQJUJITDKRBXSDXAVIECGXCQMNPOUCVMUMRPAQZFQUHKOGI"); + msg.s_type = 156U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDBState #1", msg == *msg_d); + test.boolean("ReportedState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18846,26 +21614,28 @@ main(void) } { - IMC::PlanDBState msg; - msg.setTimeStamp(0.991411946781); - msg.setSource(26633U); - msg.setSourceEntity(36U); - msg.setDestination(55898U); - msg.setDestinationEntity(85U); - msg.plan_count = 17755U; - msg.plan_size = 521850528U; - msg.change_time = 0.338765252705; - msg.change_sid = 32912U; - msg.change_sname.assign("CHUEUMMOKWLSJWBQEUMSZKJQCVYVABNCFXKWTHINODPNYNTVNVBSPYLMVFLSCERLANZHOFSWBDUFOBTIGISWIKZGOAAJXUOKDRRSGYUVZYMEMMHJKDYVTTPDQZKZFXHCXOBWC"); - const char tmp_msg_0[] = {6, -40, -85, 86, -13, -38, 103, -5, -47, -113, 20, -21, 19, 111, -62, -108, 114, 85, -123, -43, -16, 4, 0, 43, 48, 117, -2, -3, 83, 117, 126, -13, -3, -34, -19, -71, 66, 85, 73, -80, 112, -59, 47, -38, -56, -23, -76, 24, -79, -79, -44, 91, -58, 21, 67, 61, -2, 67, 3, 34, -59, -22, -79, -90, -84, 13, -94, -96, 60, -36, -35, 91, 45, -67, -85, -20, 67, -108, -97, -107}; - msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::ReportedState msg; + msg.setTimeStamp(0.5863525472471837); + msg.setSource(36719U); + msg.setSourceEntity(210U); + msg.setDestination(15871U); + msg.setDestinationEntity(158U); + msg.lat = 0.6297654534779364; + msg.lon = 0.11582484114317326; + msg.depth = 0.05184358758924246; + msg.roll = 0.23603671987989017; + msg.pitch = 0.24350157689744845; + msg.yaw = 0.28379713425128816; + msg.rcp_time = 0.07106823933500817; + msg.sid.assign("MTHQZCPFLGJXDWRXJEQTZHFIIVVCHIUNOLLNTASSCBVERFUWNBKYECMZMGKLSBJKQKWBTIBMYNVVAOCIGOPXZFDSODALNOBJZHGQDKHTUQWJWVYSKVFFOFTKKTWQMOPPRPPPUFBEHW"); + msg.s_type = 148U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDBState #2", msg == *msg_d); + test.boolean("ReportedState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18876,26 +21646,26 @@ main(void) } { - IMC::PlanDBInformation msg; - msg.setTimeStamp(0.599574210571); - msg.setSource(8211U); - msg.setSourceEntity(142U); - msg.setDestination(47820U); - msg.setDestinationEntity(236U); - msg.plan_id.assign("MMIZNXDERESXQEGWZXNBUEAYHOIIGLDK"); - msg.plan_size = 4512U; - msg.change_time = 0.664044172106; - msg.change_sid = 17308U; - msg.change_sname.assign("HJUTUDMACNQZIWFWCJZHPCLHBXNNAB"); - const char tmp_msg_0[] = {-82, -70, -6, 34, 93, 9, 28, -16, 83, -93, -122, -69, 41, -23, -127, -48, -104, -99, 78, -13, 95, 117, 43, -89, 94, 109, -38, 9, -75, 31, 43, 94, 41, -22, 57, 62, -62, 39, -14, 73, -44, 59, 67, -27, -110, -36, -90, -33, -125, -1, 112, 29, 69, 42, -12, 99, -26, 82, 100, -125, 47, -83, -55, 18, 37, 38, -94, -89, 70, 74, 11, 38, 20, 99, 118, 4, -56, -15, -62, 56, 62, -76, -62, -51, -16, 87, 98, 119, 109, -118, 50, 17, -66, -115, 57, 70, -65, 23, -44, -113}; - msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::RemoteSensorInfo msg; + msg.setTimeStamp(0.4482545799498229); + msg.setSource(40780U); + msg.setSourceEntity(43U); + msg.setDestination(42287U); + msg.setDestinationEntity(24U); + msg.id.assign("KCRVIOFJQBEGXWIZNLQXPPMPACYZDNRQDJXVLHMJKNLUIKREBTLUPGRBQKUAPZOFSUJPRUMFXJBOXGYT"); + msg.sensor_class.assign("CJLYCZTDETWZDXOGBGOAHPCBTSCGBSXCODBVFKAWPOZILTEQSPXUUIRCQTLEHWVXQZUIHXSIMRVRWJINOAYBPX"); + msg.lat = 0.20117844628792347; + msg.lon = 0.2952608513730822; + msg.alt = 0.0449667106453393; + msg.heading = 0.1258132572038988; + msg.data.assign("QRXRCJDWPKFBZXSCAFZJYYABZYFPKGQYGDFIJGLFNKOVVMUWMVAICVHIOUOZNCKESDRBYBWLHOJZXXVKNCWCWOSZAFQEHNUTHPDDBRYPLAQTORVGWEYDCYRIIBVLBCAVEMQLXXLIYAHDGGGBSXJRWQMHGFIMQZGMQKEPPPIBTHTUUHUEWMTDLUJYPWFVNSJEOTVBQKSEXGOFTNCNNSDZRK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDBInformation #0", msg == *msg_d); + test.boolean("RemoteSensorInfo #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18906,26 +21676,26 @@ main(void) } { - IMC::PlanDBInformation msg; - msg.setTimeStamp(0.644883602624); - msg.setSource(23983U); - msg.setSourceEntity(52U); - msg.setDestination(12191U); - msg.setDestinationEntity(218U); - msg.plan_id.assign("WTBGBDJBWHHKTNPLIMOTMQQLEQLSKCKXUBRSWAXLWZRVQWKYIMUFGYCDECSOCFONOANPXWZMZVSGGNEURGNFXASOPYTANKJYALZPXKWWHQECXUMXJDVPUSAOPNMROJLYHVEIFGGVXBZDMMYRQYISPTBHJCQKUDRZRFKEIGHEMWCFFLRDQIIDFUSBVGVUAYQVZTKPMIDYBDZJTOYVPHBOZEBUXNACOHRATEF"); - msg.plan_size = 54873U; - msg.change_time = 0.438465184847; - msg.change_sid = 9143U; - msg.change_sname.assign("WLYIRKTTDYQHSQGZRROYJSQTBEEJXRXFDKUNVGVYKAXTUUAMOHMQKXSJOECQJOTGPJCUPCZYBODZDJGLXVVIOMCCCDFVFMINRJLMKBURXYZYWMQBALBDLECEIKIPWFR"); - const char tmp_msg_0[] = {-87, -68, -123, -123, -98, -93, -79, -36, 126, 104, 9, 107, 8, 85, -1, 60, -51, 40, -60, 24}; - msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::RemoteSensorInfo msg; + msg.setTimeStamp(0.5262285852045177); + msg.setSource(56429U); + msg.setSourceEntity(187U); + msg.setDestination(57587U); + msg.setDestinationEntity(9U); + msg.id.assign("DUCJEPGHCSOMARDRUTXSFLNWJBLBJCLLYPVVCXZCVYQXERXNSKMVUPCAOHBCPASWQHFFBZDDCGSTTNMEMBHLZWNUKTOBOUVWDEHTNBRMREGTNPFEOIKANKRIMYRDUFYFWIFHSKJOTUOWORIRRYNSZVJCQPQDQADEILQWQLJDAWBPIGHMHZDIZBGNJFLTYPOJXVPGYCVYBLHJGHXKAISXKOYMMIWXTUPNZZVEQAJQYGVTAUEIAXWZFKQGU"); + msg.sensor_class.assign("VGVMGYBZFEQEUGKLMZHTSKUIDCDYCNVJIBLYRCIARWLIRWASSMBFDXTJVMSAYMNEHUUUSKNEGXOHFKUCVXTMRBAIOFQRCQWGXIMKKOZSNLLPPKJUWTBIKABDQPPANXFDSJQKCPMGBSZSIHYYNAZHTWVTZVNEJTJWITREHFEIMYXWXFQFHPGZHONFRXPEVHQBAYJWKLAURDNLBQDVCOXDLJOEDYZ"); + msg.lat = 0.03866874027166223; + msg.lon = 0.362475055184143; + msg.alt = 0.04973174194496566; + msg.heading = 0.9977501300103451; + msg.data.assign("XGZAOYVZAWGSCQGQQKSUCXMCWEFRGJHNMCMJPKECHAIGSZKGDUZYRSWMFRTRJZJNWRVCFYWNYIKCHYRIASBIXDYOUPLDBNDWXFLVVOPBTBPZFCTBNWHDDTLHXENGOUBFUEEJSPALDLZQZSHJYIWTYKQSXAT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDBInformation #1", msg == *msg_d); + test.boolean("RemoteSensorInfo #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18936,26 +21706,26 @@ main(void) } { - IMC::PlanDBInformation msg; - msg.setTimeStamp(0.113645935218); - msg.setSource(57474U); - msg.setSourceEntity(21U); - msg.setDestination(20914U); - msg.setDestinationEntity(232U); - msg.plan_id.assign("TSNUEDLAOXEW"); - msg.plan_size = 21833U; - msg.change_time = 0.965227058276; - msg.change_sid = 4519U; - msg.change_sname.assign("IYTJDSVJSDSUJKGMHJFMOBWYZRRDKFIURIUPNXOTAVKTEGWODBDAFKIUGOMRRAELSVEJNWYVRYZHWKGNWOHHOKCNFAMQANTVWGYZEOVUACSSCJLNRGZLRLMTAUWXZQSKEZNZREHTDPKKNXVBUAYOCQUAILLCYZBYANBFFBHC"); - const char tmp_msg_0[] = {-87, 46, 45, 57, 1, 20, -45, 111, -107, 45, 109, 92, 115, -104, 15, -80, -2, -38, 16, -16, 49, -123, 126, -67, -100, -76, -86, -91, -94, -14, -103, 15, -99, -72, 58, -103, -114, -115, -27, -54, -53, -38, 70, 120, -64, 25, -88, -56, 11, 97, -57, -96, 47, -27, -120, 106, 108, 34, 96, 103, 110, 57, -61, 67, -37, 100, -60, 91, -112, -45, -44, -65, 116, 103, 82, 42, -103, 56, 71, -63, -58, 17, -15, 39, 35, -90, -27, -60, -127, 45, -43, 75, 99, 4, -89, -40, 98, -64, -105, 126, 108, 55, 20, 124, 118, -58, -121, -18, -34, 94, 23, -70, 109, 29, -8, -110, 122, 121, 71, 110, -23, -38, 85, 18, 29, -79, -108, -97, -36, -102, -77, -101, -77, 31, -105, -61, 50, -118, 66, 76, -91, 20, 104, 52, -74, 44, 9, 7, -18, -12, 13, -108, 61, 1, 14, -33, -74, 53, 86, -6, 96, 62, 120, 56, -126, -105, -49, 117, 74, -4, -33, 121, 8, -63, 120, 43, -95, -48, 58, 117, -105, 19, 7, 5, -3, -33, 120, -120, 96, 82, -50, -114, -20, 121, 98, 65, -65, -85, 42, 101, -86, 78, -63}; - msg.md5.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::RemoteSensorInfo msg; + msg.setTimeStamp(0.20453517781798247); + msg.setSource(5962U); + msg.setSourceEntity(41U); + msg.setDestination(20913U); + msg.setDestinationEntity(128U); + msg.id.assign("RLTKSVNEZYGAMUXWFAHIWWMAKRFOZNVVNAQMCFCAHVCWUQUADYICJQOEDSXDVBUWOCIMKEMHPAJCFGQARUBQLBFIKJLJOWPLWOKSLXMMYSUPDFJXBNHETRHDJQHXZNXEJBH"); + msg.sensor_class.assign("FZBRNSPQCJWUBRWHLWYTQOTVXBBIVQGPGGEMOSNJQURKEBPYKVMLVYHEOUFROSZFJRKUPWCFYKOBNTFCIBALDQWASALFBAYKPIPHXTHNJTSGHYMFAUMXVQWORZMIAZHTZDQAENKPDKFPEJUGXLNAT"); + msg.lat = 0.2591793930968235; + msg.lon = 0.6897057736698965; + msg.alt = 0.9439360728562025; + msg.heading = 0.8585321036321099; + msg.data.assign("PWYFDOSUFQNGBQZFHFGAAYDUKMOONLKNREVRICCSLOYNWTSSSOMPJEGVUBHEXDAZBZXKBQASDLXDLCQPXKMAYXXSEECGZAUUKOBLMRUOXLIGCYJJEGLNEATJPWEBWFTEPZVHBCUDJXDYIJRGTALQWYFMCFHUYNW"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanDBInformation #2", msg == *msg_d); + test.boolean("RemoteSensorInfo #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -18966,45 +21736,32 @@ main(void) } { - IMC::PlanControl msg; - msg.setTimeStamp(0.612833761422); - msg.setSource(16355U); - msg.setSourceEntity(166U); - msg.setDestination(29666U); - msg.setDestinationEntity(47U); - msg.type = 21U; - msg.op = 220U; - msg.request_id = 33060U; - msg.plan_id.assign("UBSGOUZQEAYAIWYVXPOVGGILUSRLRXAGMJNSBGJSYLCHHAWQJVPBXFNZMCQZKRVYMRQKWVGESPIWFJJEYDCRMKAPMCWTTZCNAXNXHTJUPHKDMVDBKXXPDHGHZETAITAVRTXSOMMFYCPBSSPROOEFFEDHIQWNNOCEZGGSUVJYANUWYRBPYCFYLOBGEEIFPDTFOHHLRBDUUDXDLDWTWQQQ"); - msg.flags = 62431U; - IMC::SimulatedState tmp_msg_0; - tmp_msg_0.lat = 0.899011118251; - tmp_msg_0.lon = 0.403996511128; - tmp_msg_0.height = 0.115488855777; - tmp_msg_0.x = 0.83031742217; - tmp_msg_0.y = 0.108951639581; - tmp_msg_0.z = 0.77635057837; - tmp_msg_0.phi = 0.135640931383; - tmp_msg_0.theta = 0.21070692887; - tmp_msg_0.psi = 0.274546225809; - tmp_msg_0.u = 0.447636319055; - tmp_msg_0.v = 0.247762556912; - tmp_msg_0.w = 0.262356301692; - tmp_msg_0.p = 0.0597205046817; - tmp_msg_0.q = 0.090906338882; - tmp_msg_0.r = 0.0582758350331; - tmp_msg_0.svx = 0.889070794044; - tmp_msg_0.svy = 0.976488800512; - tmp_msg_0.svz = 0.823470008258; - msg.arg.set(tmp_msg_0); - msg.info.assign("AEXSVCZPWWQHQWITRVGCUUERNFJZQFPYYVSUWXCBSIPXLQYSXINEZNYJMKLIMBHFLJOVWROMULTBGZRHDXECBCTIVQIRWGLFGHOSUMGFHCB"); + IMC::Map msg; + msg.setTimeStamp(0.18998885892447248); + msg.setSource(32834U); + msg.setSourceEntity(254U); + msg.setDestination(17944U); + msg.setDestinationEntity(240U); + msg.id.assign("RZACXTIOPQWXCUOJQDCBRESLXODBMELFDFYKOIDOSODROOSEVCLFZAFZKVFRSAHJXAKORDKUXCOTAVUIQGRVCTGGYHJEMJZFFDTBJCBJLKARBUYUIJXYMHNZNNHYRITGGQ"); + IMC::MapFeature tmp_msg_0; + tmp_msg_0.id.assign("ZADDHZOYIKIQVCQFLLYLYPBBRSBPHGSSZTIAUYEPWCEQTOJYCQQNZMUWLJEISBFZRLTEUPQBWNYKMBHHEUXXRWXFHZLXKVAZUHNUKSMFTXQ"); + tmp_msg_0.feature_type = 19U; + tmp_msg_0.rgb_red = 235U; + tmp_msg_0.rgb_green = 208U; + tmp_msg_0.rgb_blue = 85U; + IMC::MapPoint tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.lat = 0.5639261878056188; + tmp_tmp_msg_0_0.lon = 0.12935102589631164; + tmp_tmp_msg_0_0.alt = 0.19050782133341604; + tmp_msg_0.feature.push_back(tmp_tmp_msg_0_0); + msg.features.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanControl #0", msg == *msg_d); + test.boolean("Map #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19015,29 +21772,27 @@ main(void) } { - IMC::PlanControl msg; - msg.setTimeStamp(0.517215683465); - msg.setSource(18469U); - msg.setSourceEntity(146U); - msg.setDestination(61401U); - msg.setDestinationEntity(251U); - msg.type = 141U; - msg.op = 57U; - msg.request_id = 10090U; - msg.plan_id.assign("XAIGJEAXDLACHBSJJSTFHFLWNXDYPNTWFPRIREOHCSYBTZJAKZQVEVFDWHQMCISTKMMGJUMWXUZKNPHJRVDMMXOJMIDLLFKPATIYWUJGXSKOOCAIWLCVQNCYABLRJTONHUEYKRVLYERZJHCQUBDBGCYNNRFYGBDRYGZNIPIQZUZSMGQLYEMGCOPBVBPFVEAUDQKFNKXNKTDLMTWWLHSOUZXIUQQXWPDSTOZOEVAROFEZ"); - msg.flags = 50027U; - IMC::IoEvent tmp_msg_0; - tmp_msg_0.type = 103U; - tmp_msg_0.error.assign("YSIGLZGDXDCVECRNONON"); - msg.arg.set(tmp_msg_0); - msg.info.assign("XIFZSZYPRELDMAMIOAIEYIVLXPBSAZLQKHQJBBSIYNTHAOEZVAQGPRMSGBNOSKIXHETGYTQWEWSTJSZJHGVTXNXJYWJFSMPFAWFEUPM"); + IMC::Map msg; + msg.setTimeStamp(0.055353244745645847); + msg.setSource(30531U); + msg.setSourceEntity(137U); + msg.setDestination(39085U); + msg.setDestinationEntity(62U); + msg.id.assign("TQOGNDOZAHOFIBZMPBNBRCFZZYPUSECGEPIHJAKTLMIGNQOWEEDGEMPJMUXPXYWXXPSFYVHXAVDIHKWTBAWXWRKQFAJWPSEVQCVKO"); + IMC::MapFeature tmp_msg_0; + tmp_msg_0.id.assign("WYLPIPELTXKLAFEDDRPMSXAFAZLXPSYFDNPUFGVSICJKLQQYAECZMBGXRORJRGOBGVEDCBQNLOYZABAJQIWLFKRMPZNQTNGCCNYTFOJIXUERMRBWNTHUYYHIESRHNSAGRSJXRBHCTUCTVHWHGFEMBKVNVJOGYVPDFWLDMBISOIVLDTJWUHCEZWHUKQUHOUJSVSMPDJWAMAFCFZEYI"); + tmp_msg_0.feature_type = 0U; + tmp_msg_0.rgb_red = 143U; + tmp_msg_0.rgb_green = 163U; + tmp_msg_0.rgb_blue = 31U; + msg.features.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanControl #1", msg == *msg_d); + test.boolean("Map #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19048,33 +21803,20 @@ main(void) } { - IMC::PlanControl msg; - msg.setTimeStamp(0.105418865489); - msg.setSource(48127U); - msg.setSourceEntity(130U); - msg.setDestination(57593U); - msg.setDestinationEntity(210U); - msg.type = 159U; - msg.op = 147U; - msg.request_id = 21729U; - msg.plan_id.assign("KTGWBRQFNWGGZODJMFEAJMZUZNTNDNGOAHGEYMLCQCMXHVAKEQLWUPJRPQAOXHDNCUMIOYLBUVPGTIJXQUJNDIFNSWBIJCRYWN"); - msg.flags = 9876U; - IMC::FormCtrlParam tmp_msg_0; - tmp_msg_0.action = 53U; - tmp_msg_0.longain = 0.932229084602; - tmp_msg_0.latgain = 0.312878296795; - tmp_msg_0.bondthick = 2306687418U; - tmp_msg_0.leadgain = 0.619685722734; - tmp_msg_0.deconflgain = 0.650889740026; - msg.arg.set(tmp_msg_0); - msg.info.assign("NBLURAEFJNBJCSKTYLQMWAYVDZUJNMBPVSRHSNYGXEXDNICGOR"); + IMC::Map msg; + msg.setTimeStamp(0.27011337658296686); + msg.setSource(24730U); + msg.setSourceEntity(164U); + msg.setDestination(16633U); + msg.setDestinationEntity(65U); + msg.id.assign("XSDYVOWPASARVFNPGENYQFZPTLXTANPNZDKCFEVQSFBDGJZTXXSXRYRTAZGUJRQHAZJLOPQUKXKSHOKRHLKWMEGZZDRJNUQWUJGMMOBVLDLBBCVGDWILQMWXCQOWBKIOACUFVFSOFJHCJVCIBYYGOLLBNMGQYPPNHUWVTMIINSNEBETFHVSKYTSCRRAZOYWHFUJIZIDQBCRDDMBCTERPUAUEAJGTITHDLA"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanControl #2", msg == *msg_d); + test.boolean("Map #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19085,27 +21827,24 @@ main(void) } { - IMC::PlanControlState msg; - msg.setTimeStamp(0.435401499762); - msg.setSource(24003U); - msg.setSourceEntity(140U); - msg.setDestination(41479U); - msg.setDestinationEntity(177U); - msg.state = 213U; - msg.plan_id.assign("IZCZCSSQHKMR"); - msg.plan_eta = -2118631220; - msg.plan_progress = 0.804610477827; - msg.man_id.assign("ZROZEBCHMVINMLOFIQUVBJNPBRBTEUNQCSXCNGPQEJVLYOTGJXGKPRUSWZLDHAJDDPGXAWBMONWFPTYHGZYSGIXKLZVH"); - msg.man_type = 8870U; - msg.man_eta = -1729337104; - msg.last_outcome = 224U; + IMC::MapFeature msg; + msg.setTimeStamp(0.0009705933960423296); + msg.setSource(5051U); + msg.setSourceEntity(143U); + msg.setDestination(52318U); + msg.setDestinationEntity(35U); + msg.id.assign("LSVGGDXTTZGYHSEVIXHVNHMWNKUSFJSIODCIEKONZSOKJLOFPMDZPCJLBEFJDXDGTJWZJBNJGGMIQXRDMYZTMYYDAQYOWNVBGBTSJQTBYHTFDLZMORTQYOMARFESRXRBQXQUGUPTGCHHNANRJFBIAUHKCKP"); + msg.feature_type = 228U; + msg.rgb_red = 76U; + msg.rgb_green = 197U; + msg.rgb_blue = 168U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanControlState #0", msg == *msg_d); + test.boolean("MapFeature #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19116,27 +21855,24 @@ main(void) } { - IMC::PlanControlState msg; - msg.setTimeStamp(0.477764140623); - msg.setSource(43165U); - msg.setSourceEntity(125U); - msg.setDestination(16370U); - msg.setDestinationEntity(248U); - msg.state = 117U; - msg.plan_id.assign("JOYDHWOFNEAZFUGNOHYNYCZGRIIJSNRMAUMJUAKMEZXUNPJLYXFPZOUNZXHTFJHSXWLTCGGWUKBXFLCXGLTQZHIIPWIBBDZXIBEMIWHYKMEETIBOAACQJUDJRFEESIHVVMQDVGFBQZOUTWJCVLAOMRVFQGBYXUSKQXHFBMCTSP"); - msg.plan_eta = -1628534366; - msg.plan_progress = 0.225509005006; - msg.man_id.assign("DROQBTPNEJGRNAGTNGPZFOHYNUPCIBFPUALVRXITBPTZIOCKIAKVHSSGXHHLFNUWKMICXDUJNYZTURFMEGKFZX"); - msg.man_type = 27232U; - msg.man_eta = 2029417694; - msg.last_outcome = 179U; + IMC::MapFeature msg; + msg.setTimeStamp(0.146678523907673); + msg.setSource(64687U); + msg.setSourceEntity(166U); + msg.setDestination(7774U); + msg.setDestinationEntity(85U); + msg.id.assign("HTFWFIAUPCOXNVMOWVZOGTTWLISJUVPTZOYXHSCMSNRHFQCEBDKQAOJMQZEPQCIJFTLWJEVUSOHPAZECBTINNCBRUAQKFPMKTSYYRZKHFXUGYWMPRCBZUDWBZYDZUAHXIEXTONXEPKJMBLLTUOMLAQXQGUVGGWHQLGCVSY"); + msg.feature_type = 64U; + msg.rgb_red = 89U; + msg.rgb_green = 234U; + msg.rgb_blue = 168U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanControlState #1", msg == *msg_d); + test.boolean("MapFeature #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19147,27 +21883,29 @@ main(void) } { - IMC::PlanControlState msg; - msg.setTimeStamp(0.443581176764); - msg.setSource(45936U); - msg.setSourceEntity(158U); - msg.setDestination(1924U); + IMC::MapFeature msg; + msg.setTimeStamp(0.8588231367236764); + msg.setSource(17904U); + msg.setSourceEntity(182U); + msg.setDestination(38843U); msg.setDestinationEntity(223U); - msg.state = 185U; - msg.plan_id.assign("BYBCKWZIKXESXFJQWFPUHNZHZXODJGBHSTAOAFBDJQAMBZNNNTBDHSLRRIDTUXRMZCCFQGCGBKHMBFEAPRJUNEZPLUYYHUUNUXXIMXJFOVLYLLLSVYYIAOHIZOVK"); - msg.plan_eta = 1201682701; - msg.plan_progress = 0.946786045386; - msg.man_id.assign("PNWSOUXNOXBGHISPNRWGKIIZAAQFDQPGYHAMWKVRSLPLHECITBONYCTEXQIBVHLOEIEKCZXHL"); - msg.man_type = 29806U; - msg.man_eta = 469952552; - msg.last_outcome = 26U; + msg.id.assign("XMINCOGGRTRYHJDCHPZAUHXZBLSZILOLDAEVAOIPYEPNSLQBEWUVUSDFXDXUWSQJAYAYBLNBCBOEXZTDTPTKVFBAOZWCZPOGHQDGCIJUYPCVRLYATNMMNTWZTIJXVOKXAQFSFGNVFHHHIKYDTXWZHAJXIEVPKQIPLESMJCEKNMIUKKBFONFQVFZ"); + msg.feature_type = 87U; + msg.rgb_red = 61U; + msg.rgb_green = 113U; + msg.rgb_blue = 230U; + IMC::MapPoint tmp_msg_0; + tmp_msg_0.lat = 0.3535856179947109; + tmp_msg_0.lon = 0.2937493816732778; + tmp_msg_0.alt = 0.18646738016214826; + msg.feature.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanControlState #2", msg == *msg_d); + test.boolean("MapFeature #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19178,23 +21916,22 @@ main(void) } { - IMC::PlanVariable msg; - msg.setTimeStamp(0.497326657333); - msg.setSource(21602U); - msg.setSourceEntity(140U); - msg.setDestination(63847U); - msg.setDestinationEntity(7U); - msg.name.assign("HKPAXZDUIOMZVQKJKUAXCRPHRBPCAQZUONVGMUTCAHZMHMWSCTBURTFSJGYBRHBBWFGUTNWXTHGFKNWITLCJYJCAGZPAQIEZLNFKQECXOXVIZDLKSKQRVQLPZVNUOFSRUVDFYYMMJBNXDITDOWNEAHMJBOPFQVGDPXJLRNZKWMHJUAEZYQRIDESFVBJWFCA"); - msg.value.assign("ISXXTQPRULIPMHXAYDJRFFTVOL"); - msg.type = 209U; - msg.access = 141U; + IMC::MapPoint msg; + msg.setTimeStamp(0.21406892857517978); + msg.setSource(10178U); + msg.setSourceEntity(178U); + msg.setDestination(34332U); + msg.setDestinationEntity(42U); + msg.lat = 0.494136877827142; + msg.lon = 0.23255203669980762; + msg.alt = 0.500957804595508; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanVariable #0", msg == *msg_d); + test.boolean("MapPoint #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19205,23 +21942,22 @@ main(void) } { - IMC::PlanVariable msg; - msg.setTimeStamp(0.84664130469); - msg.setSource(52469U); - msg.setSourceEntity(55U); - msg.setDestination(18690U); - msg.setDestinationEntity(229U); - msg.name.assign("IHCGAGUHIOUKETPRDBVLVPIOPBKDZMDJLCAKHADUETKVTSBPCWUXTRXLXVFODQSXUXXSCQVFZEZJXHEZJUWCJVAIGVBCQGTEWUSDQRYHKORIKPPQEAYZZLMLAGNWJHJMMJBZYOIYRWRTVYDIJQQWPDGMTGRDWNSFZMVUNHVCOYZSQCKRPMYLXDCIQHEIFAKLJWRSHXNOAYEBNGBMT"); - msg.value.assign("MJQQKCXHYYOBTSTDVVLMKHJZQBTOAOIOBXFIGYSJJSUNFHTFVNLZVQPPSAIBMRUW"); - msg.type = 129U; - msg.access = 196U; + IMC::MapPoint msg; + msg.setTimeStamp(0.5232100120369928); + msg.setSource(6730U); + msg.setSourceEntity(137U); + msg.setDestination(65307U); + msg.setDestinationEntity(208U); + msg.lat = 0.3201908660269832; + msg.lon = 0.048529688138004956; + msg.alt = 0.29784246701502837; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanVariable #1", msg == *msg_d); + test.boolean("MapPoint #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19232,23 +21968,22 @@ main(void) } { - IMC::PlanVariable msg; - msg.setTimeStamp(0.847964853284); - msg.setSource(17679U); - msg.setSourceEntity(80U); - msg.setDestination(65396U); - msg.setDestinationEntity(133U); - msg.name.assign("FIIRZRNMXUFAHMSBLBSKBESSMSUYEQYFORSQNYPWXOAXLVVFVPSTWIERCDENUYJWOXCBUKSRXGKSVBKWTDWNZNVGPYHQJAYPNYGCAALIKDVWQLUYTDILTWXDCAMTGUCOZRJTVORPPDZGTQVIYAJFEBZZLXQLAOBZMHQTLPEUMFHKYOIHBHIRMZDDTNQFCHEUWPZRHZQCMIC"); - msg.value.assign("WKRDOKIYVIEERXKVRXSSRULNNMINKPRFKBZFZFUNXHZHBQPOEVGWISJPIZNGYPJLRWCFJTATXVCPFAUAKRSPQXOQHVQACSSRVVDIVHYJPTMRJTDMIHZEVBYGECWWJBIUWNBZAPTGUGDOXOELYTAGJBABQLBQMGTDYBYDCHMESXNAKLZVKFGJGRQTDWDCTTCIQEXCJIQFXDJHECWYEHLFQZZHO"); - msg.type = 45U; - msg.access = 113U; + IMC::MapPoint msg; + msg.setTimeStamp(0.9563798572218648); + msg.setSource(61558U); + msg.setSourceEntity(237U); + msg.setDestination(338U); + msg.setDestinationEntity(50U); + msg.lat = 0.8194586365197448; + msg.lon = 0.9805202958127647; + msg.alt = 0.2976383266778425; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanVariable #2", msg == *msg_d); + test.boolean("MapPoint #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19259,23 +21994,25 @@ main(void) } { - IMC::PlanGeneration msg; - msg.setTimeStamp(0.959609970102); - msg.setSource(38798U); - msg.setSourceEntity(206U); - msg.setDestination(14651U); - msg.setDestinationEntity(115U); - msg.cmd = 18U; - msg.op = 27U; - msg.plan_id.assign("RLSMHGMHXHUQWKVEBSVHZQHWJOUIWCTBNMWDGLGOQCOVNDRAWRAXWBSUSJLKJHDTTWXRYTFDPLFYFVKNLOIXSLEUYJYDCLKAPQPNVZURUQSR"); - msg.params.assign("LXFMGTWQSYYSLKQIDDRZJERPJHFZXTFYNPMXJFPNYAMQIQGDLBMGIQSUZFVNTJMKUOLSTAOMCHJVNUFITORJABTIHGBGDKEBVESFNLCGWPPZYXUCDTNOLTGYHQUUPXWRZERAAXVZVBTSLNARCLJBKWRZANWOLZHVFEYZJYRJCYOXWMEIKOXOIEHQQKVPUBKWGRWKCUGKMAAURABKOS"); + IMC::CcuEvent msg; + msg.setTimeStamp(0.33417113328800174); + msg.setSource(51761U); + msg.setSourceEntity(111U); + msg.setDestination(38965U); + msg.setDestinationEntity(241U); + msg.type = 92U; + msg.id.assign("RFYACCIOJVGUOEYXNSAPLXTKQZAWPUWZUGLHSERKWQYN"); + IMC::SetControlSurfaceDeflection tmp_msg_0; + tmp_msg_0.id = 42U; + tmp_msg_0.angle = 0.870583045405273; + msg.arg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanGeneration #0", msg == *msg_d); + test.boolean("CcuEvent #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19286,23 +22023,23 @@ main(void) } { - IMC::PlanGeneration msg; - msg.setTimeStamp(0.728248624058); - msg.setSource(59670U); - msg.setSourceEntity(231U); - msg.setDestination(21277U); - msg.setDestinationEntity(126U); - msg.cmd = 207U; - msg.op = 158U; - msg.plan_id.assign("SHZJDCSGOMLNAHGYZIGBZB"); - msg.params.assign("GNXKSTLRVDXCBAVABTBYKJPOLLCGERYSMZSUYOFKMFOAXGXOLSDBVQTCQVXXRZOCJMFPZWAMR"); + IMC::CcuEvent msg; + msg.setTimeStamp(0.9650653882911536); + msg.setSource(33126U); + msg.setSourceEntity(57U); + msg.setDestination(59731U); + msg.setDestinationEntity(231U); + msg.type = 85U; + msg.id.assign("IGCGZOKMBCMTGMTKPMPSVRPDNFMZELZJJVGJODBCTYQCVOFHGIJLEQACBMBVKGKWXRRDRIWMFTUCCUSYQIRQJIIMYQTJPYNVDYELDJIJKTVWKNLZVNKLEFSYPVGIXTSOTYQ"); + IMC::QueryEntityState tmp_msg_0; + msg.arg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanGeneration #1", msg == *msg_d); + test.boolean("CcuEvent #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19313,23 +22050,24 @@ main(void) } { - IMC::PlanGeneration msg; - msg.setTimeStamp(0.403391511924); - msg.setSource(31504U); - msg.setSourceEntity(227U); - msg.setDestination(49458U); - msg.setDestinationEntity(144U); - msg.cmd = 77U; - msg.op = 62U; - msg.plan_id.assign("YXDSZQGQEMEIASSMRTCJUGHYAIGYFGJWOGSBWPWNWVELEHTFNPWPINFCZERKXOFSTZARCPFEBRAAXRCCTUWXZDFDJOSZMHLKMKPAIDTPQQBGTYPLNSQMCIIQSMTJUMZLRBHFJRDVAVMPQKDXCHNCZJKBBYNU"); - msg.params.assign("IBJTLCZYJNCPZMRZBGKNPEDSXBILPWWVUWQRRUTAWJXUMETKKTUFBTRCXDCWMOCEDTYWZEHFHSJJVBDDIPSHNNOQYVUTRALLNOAPXAAMCFTHBOOGQNGFWSSOYIPJJPHLHSKQXKKHXFAXSVZYYSCNQIWEYDWBBFRKQLPVW"); + IMC::CcuEvent msg; + msg.setTimeStamp(0.7871298942185126); + msg.setSource(61008U); + msg.setSourceEntity(108U); + msg.setDestination(33911U); + msg.setDestinationEntity(67U); + msg.type = 221U; + msg.id.assign("NRDANTMBCPAQPQOIMNIFZOTICLZWVNMWKPCCQSMJWFKSWBRHIPLNKZDVWHFPYBDLYXXNGTBZAFZPUSSXMUEBTHENOIJAKWNVXHLOSLFGRXYOAXMPJXARXQE"); + IMC::Conductivity tmp_msg_0; + tmp_msg_0.value = 0.27403187392253325; + msg.arg.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanGeneration #2", msg == *msg_d); + test.boolean("CcuEvent #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19340,39 +22078,29 @@ main(void) } { - IMC::LeaderState msg; - msg.setTimeStamp(0.0985489837203); - msg.setSource(36910U); - msg.setSourceEntity(59U); - msg.setDestination(4483U); - msg.setDestinationEntity(0U); - msg.group_name.assign("BGPDASWGHBJXTUVRIAYVZXYUBSXYIAFYNZISIJVFEVLQGREJETERRZKGJOKFPGJINXBDKSQOYXPMLKQWHDMDLCUNMPXPYIXACXCWRIGFNRQLSYTLOSCFVWKICNVZDMSCYFUENNYVYBDOHLHTHKBJWQWAFSIXUGLCQJNMADWTNKMPUECPBSPZTARRZWWHERMCUTZSTKAEMHNOLOKGELZVBMHUTQBWOOJDHCQQVKGJTPODBAFEZAROFXMDHUZF"); - msg.op = 24U; - msg.lat = 0.0759734169716; - msg.lon = 0.721724040743; - msg.height = 0.777118088461; - msg.x = 0.0484600003043; - msg.y = 0.94271768566; - msg.z = 0.324385749212; - msg.phi = 0.405318092395; - msg.theta = 0.803158103067; - msg.psi = 0.282290094034; - msg.vx = 0.939048195083; - msg.vy = 0.898313663106; - msg.vz = 0.293270434677; - msg.p = 0.427697078124; - msg.q = 0.58722470571; - msg.r = 0.287714496779; - msg.svx = 0.432297244705; - msg.svy = 0.320992588912; - msg.svz = 0.772708058483; + IMC::VehicleLinks msg; + msg.setTimeStamp(0.6697062669155557); + msg.setSource(9690U); + msg.setSourceEntity(202U); + msg.setDestination(50470U); + msg.setDestinationEntity(157U); + msg.localname.assign("MUPMNXMLOBRYJPLHYGBEPYTUYKJQGKCLZMVICSOLYNCFQNQKXKATWVWASVUVFWJPMBFMPTZHEGWVFTZWDNWFNAYLHXRVKZGPAUSFNTXEUZZHHVYOSDEILBHGLFFNITSBJPBMMWXDKEVSETJUBLZDZXWPDZZBOVIGUDBCURYBUCOPXDEQIRLLEOJJJKGRIRXODFIJDOHEAACSKSENGQAFGOKRTCNQQUMIIHRSTCQWMJQXCADPYYSAHI"); + IMC::Announce tmp_msg_0; + tmp_msg_0.sys_name.assign("AFLQICKBZYQVYXKDYXBPCLCWCDXXPNIEAYURTGSMTNHWYQTQCUFZFVZRHUIDJCSBBUZNJKXAZDHCHYZBVNXXDHVEUJGREBYHJPZRUKLHVORHGCGWITOIUSNAGVAKFLLODDYPSJREMUWWGYISPUKIPQXOZIWVJZDSKVLNJOSRALRMTQTOMQFGMHPJTEFWITUTEARWNIDGLZEBPMEXALMOADNYFSPLGVNEOSTB"); + tmp_msg_0.sys_type = 239U; + tmp_msg_0.owner = 40268U; + tmp_msg_0.lat = 0.6895493887345557; + tmp_msg_0.lon = 0.09268369426887457; + tmp_msg_0.height = 0.2994823197602876; + tmp_msg_0.services.assign("VVXPSHYYSOOQNXXLTVEZSWSJMBY"); + msg.links.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LeaderState #0", msg == *msg_d); + test.boolean("VehicleLinks #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19382,40 +22110,30 @@ main(void) } } - { - IMC::LeaderState msg; - msg.setTimeStamp(0.668523212611); - msg.setSource(48442U); - msg.setSourceEntity(184U); - msg.setDestination(30991U); - msg.setDestinationEntity(43U); - msg.group_name.assign("HVCYUZLHTKQGIDRNIWOXUTVEMVWFIBBLQUPPDNYQEVOVNDFKZKWKJZSTDFUXRMPPXGAUOQEMVAFABFYEBZACGGULWXRRMELSABFF"); - msg.op = 161U; - msg.lat = 0.0433373350486; - msg.lon = 0.164751907455; - msg.height = 0.0292614959605; - msg.x = 0.861732236966; - msg.y = 0.541146047938; - msg.z = 0.446390080763; - msg.phi = 0.127637043994; - msg.theta = 0.974815037103; - msg.psi = 0.460633090742; - msg.vx = 0.769875122463; - msg.vy = 0.15851049203; - msg.vz = 0.547973857525; - msg.p = 0.728227994581; - msg.q = 0.013583780387; - msg.r = 0.952183702093; - msg.svx = 0.454351845056; - msg.svy = 0.691538945069; - msg.svz = 0.493526758944; - + { + IMC::VehicleLinks msg; + msg.setTimeStamp(0.3158553434568422); + msg.setSource(46962U); + msg.setSourceEntity(178U); + msg.setDestination(15548U); + msg.setDestinationEntity(185U); + msg.localname.assign("OAHZEEXHJCSGJVJIDHMJCTPZNNBIGMDGYXUKQSKPCZGMBOAUTUGRPIYLFQDXPAXZZWKTMNLLUTWOENXWZOANYRSSGRNKOFIYFIDIDBOHRFKD"); + IMC::Announce tmp_msg_0; + tmp_msg_0.sys_name.assign("NHULYJMGYQTPTVIEJXAWSECKNBEYXKNVFGFLEOMGAYFHSCEENCCGRCKSPBSPJGTRZOKPPJQBPTZKRKNTPOXLNBGVOWDTGS"); + tmp_msg_0.sys_type = 28U; + tmp_msg_0.owner = 2964U; + tmp_msg_0.lat = 0.7829432664224975; + tmp_msg_0.lon = 0.11118243448636644; + tmp_msg_0.height = 0.9835775994408258; + tmp_msg_0.services.assign("UZBITSHBMTUVEHFJMQ"); + msg.links.push_back(tmp_msg_0); + try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LeaderState #1", msg == *msg_d); + test.boolean("VehicleLinks #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19426,39 +22144,29 @@ main(void) } { - IMC::LeaderState msg; - msg.setTimeStamp(0.294215900178); - msg.setSource(186U); - msg.setSourceEntity(39U); - msg.setDestination(10649U); - msg.setDestinationEntity(93U); - msg.group_name.assign("KBCLOQACYKMOPHMKRGXTQVEKOHVSWYLZWSBAFBCCPOINRMEIIJNVCXZWROVSVQCNLHIXMFJDVTUWDPJEJUQEAOZBYGMINFWPSJZJTWXYAMYFRWHTESGOTEBZQJFRVBFXGYLLHCQJQKSUPTZLOSTDBRHHVZCPRYGVQFFSKIZXDN"); - msg.op = 75U; - msg.lat = 0.1087620152; - msg.lon = 0.797350707036; - msg.height = 0.391075467204; - msg.x = 0.670188516856; - msg.y = 0.215783132859; - msg.z = 0.614047422357; - msg.phi = 0.828671725557; - msg.theta = 0.822428653681; - msg.psi = 0.646259775875; - msg.vx = 0.577943583113; - msg.vy = 0.70059739657; - msg.vz = 0.875996560393; - msg.p = 0.290358503127; - msg.q = 0.504387803547; - msg.r = 0.450512106731; - msg.svx = 0.79705421203; - msg.svy = 0.576326110172; - msg.svz = 0.886031703063; + IMC::VehicleLinks msg; + msg.setTimeStamp(0.7911972560879309); + msg.setSource(44673U); + msg.setSourceEntity(78U); + msg.setDestination(1197U); + msg.setDestinationEntity(213U); + msg.localname.assign("KVPGMGKWDARQETKLXOMIWTHRYWCRWKSOOCPNUWQEEUGQOUGBNXMWNMOVVBKVSPTOOJLHOACNBJGTFVHMISIDMIZBRHNUCFYEYRACBEIAJJWOTDBEYAQF"); + IMC::Announce tmp_msg_0; + tmp_msg_0.sys_name.assign("AEDBFXUASCJHUTZPUCRQWQSEQIKQEDAXMUKYSBNPNGZRMOIJPMYNSYGQMPDXCSMRIVXYGOQYTKRMKHSOTEFAGOZETANQPEHDLIHHOLCOWKWTIHRBLDZSLYNRYFBDTHMIZVOCUFJVVYNJDPUFJCHPRKUTLFXGBWXUQKYOQBZGRCSORVLAFKPCQXGPKAVWBWZBEZEZAVNUNJBFSLUWWVLJLIDCGNVHNJ"); + tmp_msg_0.sys_type = 146U; + tmp_msg_0.owner = 10342U; + tmp_msg_0.lat = 0.80537825212045; + tmp_msg_0.lon = 0.16594956937090866; + tmp_msg_0.height = 0.6714454268965349; + tmp_msg_0.services.assign("NQYLBNNMQPTIFVCXLCVKRWEKGHSQEKSWRPWZYUBGEYRETFDTYUJAVIVOHDWABORVWKXGKHHJZXMCBGELJBAKHMLZRPCTMTTNXUYKNYGIVUZFDMDSDCYATOAJDENDOINQPRPUMJVDQQBJUOSYBAZ"); + msg.links.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("LeaderState #2", msg == *msg_d); + test.boolean("VehicleLinks #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19469,26 +22177,22 @@ main(void) } { - IMC::PlanStatistics msg; - msg.setTimeStamp(0.809534229325); - msg.setSource(61155U); - msg.setSourceEntity(102U); - msg.setDestination(55298U); - msg.setDestinationEntity(186U); - msg.plan_id.assign("ULXDQDBYOWOKGVJRMEUBSARGWF"); - msg.type = 228U; - msg.properties = 181U; - msg.durations.assign("HPZMHMVVTPSPSDENGRPYMOMJBZRTWHQFILARBFFWVOJFXWUIXLQDEFCUIWLVSOUH"); - msg.distances.assign("ICVAGRLHARXTILABNGPVRDMETSQMKHYLGYFPWTPLVIMSSACBRQKUWGSMQHFYDNXNBDXDWGYUQQHGMVJFXAZL"); - msg.actions.assign("HSPVTEPPGZTCISRFIJOHNMLCKZYLLXCTNXKNTWWBQLOXOOAIQUJYHGEZROXIVKWPQUJAKZQHQNCVRXXOFKBSSDNUYBAMWNRVMOYLMPRTEBUUDTBUTJVZMWLZKACBJWXIFGPDEYYXHGLVCDFZVISXPLUBECAAVBBOQVERSITDRQWYNFGEGLKNEKXQYCPMZDZPQHOKDTHSFESLMAIFHSNWARVYJMHJWRUDNIDBF"); - msg.fuel.assign("ABWGKBDMGHPEWZRSCIOWNKEODEPHWXJNKNZHWQATWGQOKFISWZNBCPILYLUPABCMKMVETARLBBCFWREJHERPMNAJRJVNOIRKZLQRTHETFOQQIYTJJXGEXUGCNRDUASTBTQZNFHQXOVTQL"); + IMC::TrexObservation msg; + msg.setTimeStamp(0.578557861448806); + msg.setSource(6507U); + msg.setSourceEntity(33U); + msg.setDestination(57026U); + msg.setDestinationEntity(104U); + msg.timeline.assign("VAKDPDEFUFWDSEYHJEPVLPSXNCHXJCWLEFCJJKQKJHZGVOUTOVWYGBKMKJOAPZOVKARGPXFVORQMWMFMUFGSNOI"); + msg.predicate.assign("LOFEHMAWMJGGZDZSMXSSTPZQVYZRBBUBIVNHILGUKPINHQWGTWUFVGSNUKNIUWMLBGDNKVFATKHWZDFAQMEBBILQACCDJCENTXYFBEETWRYFOZAYWXEPLKNUBJZPADTDRSRXSHIXHCSIQJHLKSXNPXSOWELCFUJDQLJ"); + msg.attributes.assign("NIAPUNUDVWCLHCZKOXRSMLYWLCMTKRLJMFLQEMRQXWOELUTBEZNIZFTXJYPPBTYXFTXTGNNNNKWPPKJMRJWCEGLGKYKUIHSDJCJQMSVFDVWQELEDBACEZHMLFNRMPPOSIYBEAPXKGYCSGKXXWZRQUBNMOVPWAQQWQAHFQGVHDFTTAAYIJUVVOZTGVJDMFXDHDGRVJCS"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanStatistics #0", msg == *msg_d); + test.boolean("TrexObservation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19499,26 +22203,22 @@ main(void) } { - IMC::PlanStatistics msg; - msg.setTimeStamp(0.930333558739); - msg.setSource(35721U); - msg.setSourceEntity(93U); - msg.setDestination(22933U); - msg.setDestinationEntity(184U); - msg.plan_id.assign("WUQIKKDPMPPNOTCZDSPVFKCQIGRFGTQHOHWBRZZTETTIDDTKGUUDLJJCOXAXFBOWNHMJSHCOIGCYLJAQQUXYOLYXILAASVSUBIDYKRVBEBVOXWSZPWOEVNRQTNYZTSKFPEQFHWNPAUI"); - msg.type = 71U; - msg.properties = 82U; - msg.durations.assign("IOXEQXGSLNOWLZNBFMUFJGUWWZARPLQBTHQWDVFIVEUCXUOGXDTNLAQRHVLCPKQLBYGPTIIMDZBJSPTJZWPSMFHAYKVWURMEYPOOUDECPFEKFBSNUBAZHJOKTVSCAMOTEMOVJRRCZRKDMZ"); - msg.distances.assign("OXTXBAQTYJEQWIYAYZZBTYJNPDNNEMHPFUKOHVU"); - msg.actions.assign("ZNUZNWSBHUVIMXYQVEGDYQGFMCURRXSJFHXKBKEXSSNKKIKRZUPJHQSICICELEXXPMZSLBE"); - msg.fuel.assign("ZSAMJOVUNCAKPQCEMBWSRGUGXQANHUBNTUINFDXR"); + IMC::TrexObservation msg; + msg.setTimeStamp(0.15573167181907788); + msg.setSource(36970U); + msg.setSourceEntity(159U); + msg.setDestination(60539U); + msg.setDestinationEntity(246U); + msg.timeline.assign("DVQQHCOSMMEWBYDLKVHKGLWDAHZNAUMEHNHJPFLZCZKDXZZTGCELYFWRMVTSUXSEWYHYOKYDIRJPCIMXVCJRXFQAMTRQYTNVJADIWMABIJBXYSSIQIHDOSENLOCXFRVGQICLNZGXOBFABFSKCNRPWUTZBQUUQDOPTNZRIWYQUJYOEXMKJNHOLR"); + msg.predicate.assign("EOSPYAZMHTDEHPQDTYPHIDRSYUBYEYHEVMXE"); + msg.attributes.assign("ECLZVOMUHPSDQMBEHOFVPQWMDXWICGLNYZRFWPLLIBQSNBFZQHMTUYHMVGUSIFIEYKRGVTTWAFIJVVGVJACSPBZKGSKZYPDZYLDRRLUDRQSPMIKHGAGONNATPBXXIBSDHNCADOPDKIITHLOJRSUCXHCJRBNMYQFGEHNUQAWTTKQWARTKSFOCZNUKCGQPDEAXJMJXZMYZEJVCWXGORUXJNELDWQWONCSFLOMAVUKJWREXB"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanStatistics #1", msg == *msg_d); + test.boolean("TrexObservation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19529,26 +22229,22 @@ main(void) } { - IMC::PlanStatistics msg; - msg.setTimeStamp(0.993772560736); - msg.setSource(34077U); - msg.setSourceEntity(16U); - msg.setDestination(25975U); - msg.setDestinationEntity(71U); - msg.plan_id.assign("NDNDJAFMSAYLEWLEJUPJQXWPHCBEKLNAAWPWNSBRGDVKWXUOOQKRRCHTBHUCBQILIVQDSEKBIMCTFVCASOZECBABZUSLK"); - msg.type = 117U; - msg.properties = 61U; - msg.durations.assign("JWVTEURZJRKKEZESQIGVYEWRKZCSKZGYGJWSBYXMHLAYSUKMJUEDOIJQBKMHZRTCEXFRJKZPQCRFKSRNADLPUHNLLFNCHXYLMDOLDPFHIBLMBOWTWGVICBMVNXBBVVMCULAMDCZBIVUSFNXNWJTYRPXKNQNDFOWEOSGPVQFTOURCOIQTXYEXLTYZPHNADAICUPGFGJPJTDGKAOURACTSMFXASWNMSHFHYDZHIAVGEAQQ"); - msg.distances.assign("KNJJDWVFWKRAPJQGJYRDZWL"); - msg.actions.assign("SPOTEEEFKDSBQDSXILYYYOWPQSYFOIRZNWJSPSAHLVUNQPQPMXLLWYSARQIVGIXNVUXAKQMFEGCAUPTDTDNOGCIMRJCDPFHFJXUWSYKZEOHIMIVZZHZOUJXYQGGLAWNNITIHATMVFTVDALHHWQRSGNHRUCBXHQNBBUKMLOBIWEMKSABCHWPZAJOJEFNLJX"); - msg.fuel.assign("LRAFZDHCRDXVVYXTDJZPTMIJQRLGROZUZUFTZFUSQECIKCKPMICSBARXXKAKLNPILQGMUUGBVHILDIOZXTNHYVWWWWUSJUHVCGAANENWOVFLAMWFBEZXYOQMRUOTPKJOGTGWHVOERMPVYNGGAMFBWOKGJWPPLTDOTEJIPDBTNBYCKEKQSZYQHDNHPSYFRYYOHCDXQENQFYAXSIEICBMUMKLCEXADJVWTEQQKZAIBUPBSRZJNRHHBFL"); + IMC::TrexObservation msg; + msg.setTimeStamp(0.2052626091121108); + msg.setSource(28698U); + msg.setSourceEntity(230U); + msg.setDestination(28797U); + msg.setDestinationEntity(142U); + msg.timeline.assign("WIZABTFPXMJLNXXMKLOCNTWCOKVOAHSVBKZZOKKFEFQDIBSHKVDHRFEGTCXAWPHXFYYAGEQIYRHSKZSDRPXBMVXOMTAEUK"); + msg.predicate.assign("CHQDOOYDWQEXTAKACRPCSMIDFSKTFAAFSNPFZPEDISOWQRPXPIHQLVJEKMPSUEVXGGNUDUYXYNRIFIXBUWOTLQZEOGRUUNZHZSREVHVPRKXTFAM"); + msg.attributes.assign("ZSLHVOTUVBWJPRLNPGDLENIKVVLMABODYVEDJNYTWXCURZIYYQMQFBWMFOYIQKXQSOLPHKFZUKKTTCBOODJHMGMTJYFTGSQWEXUGVLARKQUAAQWUNMQRYNDKEBYTKODOFCNUXYWWREGZAHIUHPCJKDGUOSSFFIFVPQ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PlanStatistics #2", msg == *msg_d); + test.boolean("TrexObservation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19559,28 +22255,22 @@ main(void) } { - IMC::ReportedState msg; - msg.setTimeStamp(0.424207901306); - msg.setSource(19U); - msg.setSourceEntity(225U); - msg.setDestination(55445U); - msg.setDestinationEntity(1U); - msg.lat = 0.0162634079763; - msg.lon = 0.356176609932; - msg.depth = 0.926746060922; - msg.roll = 0.297210545391; - msg.pitch = 0.871453551187; - msg.yaw = 0.747317502053; - msg.rcp_time = 0.939351093544; - msg.sid.assign("VEIISHYGLPSZIFSUCULQCINVATVBNJFJUWNXGNZZDWBIGGRCOYPNVHSAGKKQOBZRDXTGGMOBWMWKVYQFEDUZQJPHOKMTAMROERHEGYQNTWCYNZMXVUJWSFORRIAENPBVHGYAARTHJIDSCSAEBWOYBLIUFZWMHFYPFSOTRKMTYIYXLXEDXRCSLI"); - msg.s_type = 241U; + IMC::TrexCommand msg; + msg.setTimeStamp(0.20220912591531903); + msg.setSource(58235U); + msg.setSourceEntity(163U); + msg.setDestination(48976U); + msg.setDestinationEntity(20U); + msg.command = 125U; + msg.goal_id.assign("CFMRRKNVXECQRISTWXXJJYDILTUVTFCRFHEQNGNDBUFAQFXREMZXJJYBZRLOUIPIOMWAJCCGGXYRCPYUOFJWHAS"); + msg.goal_xml.assign("UWIITHYWFUYNWQSZPHXCSSWEBMURELJWIYEGUJHPMFAFVKMTEGMGSCXRTLNKGHOPEUXXMHCBPFRFNGRNRFJNPOQUDAUVYFGDZHBMKRATSVZADVZGBQAYBCWXWIOEYRLZTSULYNKCBAQZEVMOASJAVRDQLZXNOHUSGLORQOVJSIDXAYLMQDZBCKFBIMCCBKJLFGNTPXQZPHXDYOZTWGXWJKFAPTJEDOKVVVTREQBULIJISPNDO"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ReportedState #0", msg == *msg_d); + test.boolean("TrexCommand #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19591,28 +22281,22 @@ main(void) } { - IMC::ReportedState msg; - msg.setTimeStamp(0.311462461821); - msg.setSource(29431U); - msg.setSourceEntity(222U); - msg.setDestination(17949U); - msg.setDestinationEntity(122U); - msg.lat = 0.830815044549; - msg.lon = 0.909569460621; - msg.depth = 0.49941603734; - msg.roll = 0.727529282312; - msg.pitch = 0.689603046849; - msg.yaw = 0.121385862043; - msg.rcp_time = 0.772411789401; - msg.sid.assign("QZBHPZXZRZXEBFFSGLZEEK"); - msg.s_type = 197U; + IMC::TrexCommand msg; + msg.setTimeStamp(0.6020766394839171); + msg.setSource(63585U); + msg.setSourceEntity(62U); + msg.setDestination(64617U); + msg.setDestinationEntity(191U); + msg.command = 40U; + msg.goal_id.assign("EVIQNLOJFBFHVKYSOKRDNGVCMDLAOYGKXHSXHUTPOTIKZNCFZCORVBQGDRNDFUBYWDUNCRPPDDOMTBHDJMMHNLXYCWHVELSPAJXGLXECTUKQQXDNVPZSZKIWAWYVDLWEUTQLEBMATBXTJFPEQOMWTCASSVQSHZLEQHSPRGZLIFUJWLIWOFRGKMEXNEONTZQFQJBUWJMGJYRCAEMJUAOIAHUVXPIYTYCFRKJHSGGBBUSIZFVRIYWXKYGIM"); + msg.goal_xml.assign("XHICEKARJGLTSHHNPFOWXEEQOZBOREZJSR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ReportedState #1", msg == *msg_d); + test.boolean("TrexCommand #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19623,28 +22307,22 @@ main(void) } { - IMC::ReportedState msg; - msg.setTimeStamp(0.552218566452); - msg.setSource(45590U); - msg.setSourceEntity(253U); - msg.setDestination(29306U); - msg.setDestinationEntity(1U); - msg.lat = 0.162683562931; - msg.lon = 0.826925850513; - msg.depth = 0.521516755973; - msg.roll = 0.822317388102; - msg.pitch = 0.65725784858; - msg.yaw = 0.717714848219; - msg.rcp_time = 0.315007873567; - msg.sid.assign("QVTSSKCYZKMUXKADZWAGEHGADNFWEUHZCRVDKMAYRDOKILUXUPPGYFOQFCWGNPBXSHITBOCRATGVMZTHMTUBNEK"); - msg.s_type = 96U; + IMC::TrexCommand msg; + msg.setTimeStamp(0.9826830637238195); + msg.setSource(9381U); + msg.setSourceEntity(131U); + msg.setDestination(11169U); + msg.setDestinationEntity(64U); + msg.command = 194U; + msg.goal_id.assign("KMPTXYIHJIYKJFNURFZGDMBUUANUZZPLXRUEAYXHHSFYNKYNWQQTSENDDLCMYPEOQHFNOZIJTKAVHBJSOOTTLLDRXIYTTWMEPJGKBQAZGXMPAWFSNDWZUJRHBJKBGARCVDWMZUJCOLGVQEWILWYWDOZCHYIPFDCARSDRUJKCIRGWTXVKIVQTSA"); + msg.goal_xml.assign("GLPKZHOCKKVSQFMNEMXDLXBTLJXQZOCPXWXCPHRNGLDPMSUQJQIZJSLDIEAUFKRDKBBRLFOBLOPANRWFYVBIWJGADRLAHKTUESOVIGUKEPSXCUBPYTVMAQJJCITHBBDCOONVZMFNKCHHPSGYYUBWTJWSJLIZEMGHEYHGDNNEWJZPRES"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ReportedState #2", msg == *msg_d); + test.boolean("TrexCommand #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19655,26 +22333,31 @@ main(void) } { - IMC::RemoteSensorInfo msg; - msg.setTimeStamp(0.179393399376); - msg.setSource(50954U); - msg.setSourceEntity(25U); - msg.setDestination(31201U); - msg.setDestinationEntity(147U); - msg.id.assign("QMEDHZAGUDAOJSJWRVZSHUCHDQLWMVXWXINEJIGVZWFLCZSRKTKKAVHFRXFCWAMGOLYKYICBOFYPCPOMVMTDCYGHPPSJKSYOBABRQLPPUUGQGMGHPZXEDHETUJREGZHIDYONBRTXOADPTVSYFEJUTFMKBXZJSQNFZAXNTBXBCLNJFPDYNMNVYXSVJIFUILUBQQNFQMORNXAVICVHTOSZEYJEZQBM"); - msg.sensor_class.assign("MUCFOPPOQGEQJEHONOOTAVXRFYJDFKDCLSWKHLJHZVKGNAEMFMBLEBSFZJVOPTRWSJMBDNNWQPYCCAIGIVGPCEGDKEXRAPZYYVSGJCVANINDHQWQCAKCNTKSLRSLMTVRA"); - msg.lat = 0.477346654862; - msg.lon = 0.563920446825; - msg.alt = 0.596581700426; - msg.heading = 0.880304425381; - msg.data.assign("WGVHLXWQBKWOJAHHFHASQKDOASKQVISSMPOVQOIUXRMWFROCMDSBTVGIRGYHBTFPQOJESIPXQPKCQ"); + IMC::TrexOperation msg; + msg.setTimeStamp(0.7419308345329764); + msg.setSource(18802U); + msg.setSourceEntity(240U); + msg.setDestination(23553U); + msg.setDestinationEntity(242U); + msg.op = 118U; + msg.goal_id.assign("JRGRAMZETGHIOEZXLRLIZLXEVAXMCWSXCTKDNHSPTLILKOBJVQIDWRRZEFYJVCUMMTYUNSJZOFXNMLGPSSXDJXFHYJVUGPMRMLARTPYEDQAKRTVFWZJYFOBJBQLMPEONUQFGXGDDKAHOKOVICRBLIYSKUAADWISPYUXQVBCRUOYHFBDTGHIUMWLINHPKAQHEAQVVENTNPPTCNHWFUSAQKBYXKWJPMGEOBUFBSOZCZCDIDWZFWCBG"); + IMC::TrexToken tmp_msg_0; + tmp_msg_0.timeline.assign("SEJBXNFQHNGYZXOZOQSDOEMIPQLRYPVAEDLFOTGQTSPKCMHRCPXGFKYTUJGCVFJTDFQLENLYGYJUJFDDAIZNGCVVJKYQVOIVQWCCAQWRKWRXDRXHSBTAMONEXVRCLRJEABONZWHLAPI"); + tmp_msg_0.predicate.assign("CDJCRCHKLJWNVLFPSDMBUYSXJIVBYSFYFYGBPAGLJELLHJQQWXKCBYFEZHIVXPULRCLZKVJTVMQWNGRGADTTAOWVFRMBOORYETAHMDTRKEGCULRISTNPJNRFJWXWVBUDFSUSZXQFOBIZODWGXYK"); + IMC::TrexAttribute tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.name.assign("USGMHOHFVLBQRKLBMUZNLFLOPVIARXQATIAHEZRCBTVEFDNPDMZILEDHMXSLPNERSSZOERRJJUDVJWRSTJWTDQVTJNDFTIZVYAFRJGKOLOVXDEFGGIPUQIEZNQTGMHSRGYNKSTWCXYHFNVMWYOAQAXNDPWCAKUYXTIRHYBYTWXJWWKUBFCWUOEELLHG"); + tmp_tmp_msg_0_0.attr_type = 105U; + tmp_tmp_msg_0_0.min.assign("DLGWCIILQUUKOOEVQMRIINVASDBTSLXVHSZREHZPTBONXLXREJMRMUPQUQKNLIIGUUOAOPWTHD"); + tmp_tmp_msg_0_0.max.assign("HMJPESHJREPVVAAYDKECHKJNSRXTKZOWXUALNVAVFORCLYLSHTOJWQIUNOLFJDXNTPKPOBVDSMZCMHGEGDYFCTMEYZRDJTFPXAZJGBQLNUMGWTNPABQFWWDKHFVNOCANOIVUPXDTZXGIARUFVXYUKYKCCKRTYSLZQFDZJHBYIIFZLVJDOMZLCESRIYOQIXEMEPXYWQFUBSWQXRNHBLHGISAPKQEVSGGCIMDBRMRWLGIZKQSHPW"); + tmp_msg_0.attributes.push_back(tmp_tmp_msg_0_0); + msg.token.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteSensorInfo #0", msg == *msg_d); + test.boolean("TrexOperation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19685,26 +22368,25 @@ main(void) } { - IMC::RemoteSensorInfo msg; - msg.setTimeStamp(0.368140546958); - msg.setSource(12893U); - msg.setSourceEntity(162U); - msg.setDestination(52419U); - msg.setDestinationEntity(198U); - msg.id.assign("PFCYRJWVJOOAANIUGBGXUMMHPENDPOPXBSDRWSWMZYISPBFFYPVSEKNFVWBLANDNUJTYTPIJRGXSKNMAOIQHLIQMQGOLBTQHMSYWBNGKESCEGHTFEGHQAIIAJXOZNLCTHMDVGDUQCAIAZBEQUVXFSWZMYMZCIXCYNKUXKQHTLKPVLZCUCRIDXVYZGRLVKFQRRKQU"); - msg.sensor_class.assign("LDIQZGZNXPVQGAZYXTZHZNYIXRROHQQCXTHRAZYPDAWXLWNITALETOVYBNMTZRHBCMVJNWBVEGOSDBQKJVIUICSJFLWKFWZLBFHJPEVDVFXCURKF"); - msg.lat = 0.797935002481; - msg.lon = 0.769610956887; - msg.alt = 0.326373322906; - msg.heading = 0.267090371756; - msg.data.assign("AXYKFNWGUCVUTOFBMGIANXUBRKVQDWLZMHJVEKBXXFYHQYVDNGPXMCDPZVDZRZKSUPBBWLFEREUCGMOWJMKLTTHASBUIGQPTONQMVQRZICFFBRCPABTDIYHFJZJPNUFQAHIMFKZJXYGDEIHYLXDDW"); + IMC::TrexOperation msg; + msg.setTimeStamp(0.620171691040935); + msg.setSource(999U); + msg.setSourceEntity(155U); + msg.setDestination(11735U); + msg.setDestinationEntity(165U); + msg.op = 120U; + msg.goal_id.assign("OCCBFLMNEDMWHKRVNJSYTIFOIBQYIEJHYVEMTLVRVWLNPCZCQCHVYKQNOTGVODPRFMXGSGKTUJTXANFPLZRBTHPLOUBUZWSFGUEXOGWZRPYUSVAAIEDYN"); + IMC::TrexToken tmp_msg_0; + tmp_msg_0.timeline.assign("MKKWEHCMBJMWUUPOZYGKMFAUMAFMDXHDRRQHRJCDZJNPNBZYCPQOTETVDHMELGRKQIP"); + tmp_msg_0.predicate.assign("QIPYQAWPFQWJBKDQGMTCNSEJNHLOLZEOWUJZMHTDCQPTDBRHCHWKHRFUXUSKKCPCDJOZDNOXIUDRJPPSHAMVFRUPXBBGUFHYMYGTZUXLVASBXWFLMDFKIXIACLYAAOTHZMSHEWGGIVKIEMGTJYRZNOIYGURVBAQEXJLUIYGJOEODTZSVTCWVIQALYUPMRAXHBWXSBTJRCWNWCZNVQTEZL"); + msg.token.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteSensorInfo #1", msg == *msg_d); + test.boolean("TrexOperation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19715,26 +22397,31 @@ main(void) } { - IMC::RemoteSensorInfo msg; - msg.setTimeStamp(0.616392026952); - msg.setSource(11419U); - msg.setSourceEntity(122U); - msg.setDestination(12721U); - msg.setDestinationEntity(159U); - msg.id.assign("QLXCXHZRMWHYMQNMFSFECPYBUYPQDWIUUOFZVSVSGENJAFDDIERPBOTUSSDHQRFHTWNWUGKSZXTPBGXNCSPXLVNNJCQYBMFK"); - msg.sensor_class.assign("GCZQMBZBPTLCYQDFCUZKUHUHSTWFNNXQNBDITLXHRCSVF"); - msg.lat = 0.610120953831; - msg.lon = 0.468529895223; - msg.alt = 0.507934953173; - msg.heading = 0.355330116611; - msg.data.assign("HQDVNXONUGPETWZSXAOAQSEWSKEJCJENYXIPZGHIIMPTPLWCCRSQEMNDMAOKCYTUJHHYDBLLUZTFRHPXBPFYWUKKEXVOFVNQXDHBLWVPRDMLSHBVJXMLUWAZLEIYKRGOSJJZGPSBRTZFCNOKPDYEAHVGQBGFOXCEVZFCLRHGIJLISYGAAJBDNLWQMNRBWCFROZMADIJTIIZOZKVDFKIUWCXUGVRWTUDQFBMMNQOKK"); + IMC::TrexOperation msg; + msg.setTimeStamp(0.989851450159224); + msg.setSource(45710U); + msg.setSourceEntity(227U); + msg.setDestination(34123U); + msg.setDestinationEntity(203U); + msg.op = 212U; + msg.goal_id.assign("VWEPHROOHIBKLPWNEGPTAAECXZYLKQBDCUXKTBETTVXTIKMRJLWJVEPIOJHIJIHBFOVSLWBDDZVRIDJTAHJVMAOJXWDVRCKPEXHZCDSMMYUBXHSNZMPUQFEPQCCUKWI"); + IMC::TrexToken tmp_msg_0; + tmp_msg_0.timeline.assign("VQLDIZGMTHCHUSBNSLYSUOENYWYDPTFJOTCNNEQQYUPWMIPWUOTHAAGGABGABLDCURRBKRTPLYCZJMOEEFXCDDQXDUWUKGVMXVOPFCWBIHPEKQICNPZOQJWKEVFBXNVEZGLSWPZMVJARGIEJLZEHSVSWRCMZOBCBMHMNDMMOLGWNFYIJFYSXFTDXGVYYHUSRLTHVT"); + tmp_msg_0.predicate.assign("OMOVJGOZAJORJQTPCFDBQAPZCMALHGTASIVELORPKIZQLYAFWEUDDFGBVHWBTLZMNYSDTTSUQDTGEWBUVIEIFGILPQNHZQVXNFFYEQUIKJDOBMJLKEZRHAXCPRKWPKWAUJMUGRSWWQGFQQWSTBBCVEKOEDCJTRCRYNIUCMLSGCYEMBZKEYOHNGVPUPMDINSNMKJFLMYHKSLXXZJ"); + IMC::TrexAttribute tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.name.assign("STKDONIZZJQRLLLYDAXVKLFWUCQGWBIOZBVNWBTDPHYIVAEJSSZLCARKGBKIYMTWAJXPOXLRDHSETOWPVCMBGLMHHQOFYJERKGEEFIUIGBRMATDPZHCEDUKNFVGVRSTXEJIOCYLHXNZAHQDQAMBDNJRTSVKTKFXUBEDXZLMVAZIRIGCJYYP"); + tmp_tmp_msg_0_0.attr_type = 45U; + tmp_tmp_msg_0_0.min.assign("UVJMBAXGWZNFNWLADAAUGHNVKKLUIJAQO"); + tmp_tmp_msg_0_0.max.assign("ANYVAYWXIFTOZODYFZFWCXMGVZUM"); + tmp_msg_0.attributes.push_back(tmp_tmp_msg_0_0); + msg.token.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteSensorInfo #2", msg == *msg_d); + test.boolean("TrexOperation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19745,32 +22432,23 @@ main(void) } { - IMC::Map msg; - msg.setTimeStamp(0.376665767269); - msg.setSource(43588U); - msg.setSourceEntity(121U); - msg.setDestination(14306U); - msg.setDestinationEntity(75U); - msg.id.assign("VALLJDUCIZRCXLPXHSVQDRVSEVIKOQPIGKTNAANRBVTJUPNGPSVWYSJFPWJHAFMFEWQBAYKDJREDJKURUBWZPIVHSQGKFWOZSHSWBDQVYUEUKTRLHDBGFJVHMBBENYVRZGNOZQNOGGCCBXMKDDEYME"); - IMC::MapFeature tmp_msg_0; - tmp_msg_0.id.assign("LLOIDFOVUYQYALRIKXNFKAFKYWRWAFIGGQSXBDOOIXSFZJPNHQPVRWOKNGCVJABKAGQZYQEGLDMQJUMRHBZUCMXUNBYRQRTZDARZTTHIXCPWHGCFTMKUEBECTFJBCGBVUDPFISKDQIMGCQPSEECLUHPYQXJEIVJVYTJXAZHNZMGAZETHGTJWYSYODVIMLPLIYWVFKESHWAOMCMWOLDJTHTPVFDHVBXREPBKZWSUDNNMKCPLJLAEOSXZOBRR"); - tmp_msg_0.feature_type = 6U; - tmp_msg_0.rgb_red = 224U; - tmp_msg_0.rgb_green = 168U; - tmp_msg_0.rgb_blue = 230U; - IMC::MapPoint tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.lat = 0.342533334418; - tmp_tmp_msg_0_0.lon = 0.736451061125; - tmp_tmp_msg_0_0.alt = 0.15175930065; - tmp_msg_0.feature.push_back(tmp_tmp_msg_0_0); - msg.features.push_back(tmp_msg_0); + IMC::TrexAttribute msg; + msg.setTimeStamp(0.9433569428349904); + msg.setSource(65385U); + msg.setSourceEntity(49U); + msg.setDestination(34572U); + msg.setDestinationEntity(193U); + msg.name.assign("DROXZQAHGAMGTEALEOCJNNKRXLOBAIURCEXQFYGWMAAPNUBJJDVKPBINZSOYJKIDQUFDJIDJILEAGOLCIGZSRVEHZIHUXXCUPDUEVCHSMSAYFHCPLDCYBVBCTVJRYFKSLKHZVCWKQFGOXXHPZDWEBKYMMHJKBMBQPJNVWSUAYQTRFSFTPEJTGUOWXNVSMWLQIEBZLNEPMFZWFTZXI"); + msg.attr_type = 36U; + msg.min.assign("KYEEFUNQGWLEKIPPYILLVJRRPEPWTEIXIQGSNEUTKZCUTQ"); + msg.max.assign("SQJMEFFFPVJZCCJXSYGRIASEQKBJOUPLBWBUKGLAALINWVYIKOLODEHEDYRJIEBBYGXZLAIUHSNVISHVMDNRCPCLAGSKRZTHBZOSUVEQDCPTVWAGCGMVZOPNWWEVXMPOLXHDTORWWTSORFQNFVEKMKURXYGNGCCKOFOAZFFLQBIRUTMKAZAKTEZLXXPNDUISNUTQGTWINMYCMU"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Map #0", msg == *msg_d); + test.boolean("TrexAttribute #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19781,20 +22459,23 @@ main(void) } { - IMC::Map msg; - msg.setTimeStamp(0.18810698973); - msg.setSource(18971U); - msg.setSourceEntity(8U); - msg.setDestination(19030U); - msg.setDestinationEntity(175U); - msg.id.assign("TXRDGJWBZHPOFRYFUTGCPNQFVBIGEDAPPTPMKPZEPOXABUTVIGTLYQQSTOBOAESENYKXQHWVSBXJSNQHBBLUSVXCDQJPSWPAVZIMMNHRFYLZKOYDKKYMOXFUYSRYHRCFOMNKLCCDRZJDSGSQKMGZWIUGAPBUFKRJURLERIVKNMXHONTJDWLQTZGKCDZHABHWZODUVNNSEXHIIRCZWMOFCVETMTFUAH"); + IMC::TrexAttribute msg; + msg.setTimeStamp(0.37544888663451503); + msg.setSource(32949U); + msg.setSourceEntity(207U); + msg.setDestination(43805U); + msg.setDestinationEntity(246U); + msg.name.assign("FSOHQRFWQZIMEMSCSQXOTIUMGYSEUJPDQKLELOSFBXKRESLQCNLZKXTNJKDVOTPISWCILN"); + msg.attr_type = 180U; + msg.min.assign("IXXTQLWQYBPRJLAOMFNEVGTAQZVBBSNORARVAIDKMNVPACBVDKTMPVHESWBFZDPMURRKULHSYLVXMKYVCHBFKLWDWEWXQKZRHHTEOECZIZLYRGYEUHNDKXTPJGOSZRIFJMJYPGUGIPKACDOULIBJXAQFSBTLAOBUXIZCSQQDLJSEBFJCYFNNUAWJKWIYGACPOXOWEPQYONECWWFZMITMEQVPIRYNZUMLXCFJSGRHDFT"); + msg.max.assign("KVLPXHQHDDGAIBNPT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Map #1", msg == *msg_d); + test.boolean("TrexAttribute #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19805,20 +22486,23 @@ main(void) } { - IMC::Map msg; - msg.setTimeStamp(0.864373149127); - msg.setSource(22342U); - msg.setSourceEntity(218U); - msg.setDestination(58942U); - msg.setDestinationEntity(174U); - msg.id.assign("OOKCWIEJKGYDPQKJHQHDSUEYHDENQFSYGTJFFLQGMGIKATDYVQTRBRWTLDIBOEGXPRKXHKNGMAOATMURYNVCCFPZPISJVLCKF"); + IMC::TrexAttribute msg; + msg.setTimeStamp(0.3662804185204095); + msg.setSource(2324U); + msg.setSourceEntity(65U); + msg.setDestination(58572U); + msg.setDestinationEntity(72U); + msg.name.assign("SORTWGRKXZPMXDZUVQBCZYRYRMPOIJAFOHKADIMSHHJBNFYOCILFHTTMQSVELJEYHYXMGHDJVCJXIKSTXWSAIZARZJFMLGKTDBPARSJQWABQKIFZSHBXUYWZWUGKLPQPCCWVBEHQXYESGRBCEUIKHPDVWGVBDOVOFQLKM"); + msg.attr_type = 11U; + msg.min.assign("QLPGVLSSMIDFXAXTKPDOTHOQLNIEVRJRLDDMHCEGWMSYYRIGGLGDRNNB"); + msg.max.assign("PQXDZYKAZSOJALQRNZNSKSBMFJZBPNKIPHXZNJXPGEBILUAJIDOUNTEQTZWHVUMJODXHGZCBVMJDMFACACAPMKQIVLVPEMHACKNOYBYVMYEIGSQWGURWWTD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Map #2", msg == *msg_d); + test.boolean("TrexAttribute #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19829,29 +22513,21 @@ main(void) } { - IMC::MapFeature msg; - msg.setTimeStamp(0.477085253851); - msg.setSource(53683U); - msg.setSourceEntity(74U); - msg.setDestination(33385U); - msg.setDestinationEntity(174U); - msg.id.assign("ZFUTQMGROOISERJNFHTGYFTPHDITVNMQHPLB"); - msg.feature_type = 144U; - msg.rgb_red = 145U; - msg.rgb_green = 174U; - msg.rgb_blue = 243U; - IMC::MapPoint tmp_msg_0; - tmp_msg_0.lat = 0.0662573846184; - tmp_msg_0.lon = 0.353584883189; - tmp_msg_0.alt = 0.631854644163; - msg.feature.push_back(tmp_msg_0); + IMC::TrexToken msg; + msg.setTimeStamp(0.014368816315152855); + msg.setSource(63091U); + msg.setSourceEntity(195U); + msg.setDestination(41920U); + msg.setDestinationEntity(99U); + msg.timeline.assign("RNRXPBHEHRCTWQALWHTVBUCZPYNOBHOAXVLGJAMVIHIQOAYDYYJ"); + msg.predicate.assign("TUOFNICXVCBYPJBGCIMHBGSOBVEUFWOKODJAAPEESZDHHNYVARYRLPYZIMWQIAFTFSTPVGK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MapFeature #0", msg == *msg_d); + test.boolean("TrexToken #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19862,24 +22538,21 @@ main(void) } { - IMC::MapFeature msg; - msg.setTimeStamp(0.410378345644); - msg.setSource(57181U); - msg.setSourceEntity(197U); - msg.setDestination(21495U); - msg.setDestinationEntity(249U); - msg.id.assign("VBNHYTSULNQMYLPLXFJFXENADLHWYASZDKOIBZXISPEBSDBCUHDMOMMZNMRBEARKRVNPDWVJTBFUQQQJTWSJRPYUFXUGGOREVBWNHNWAYXPMEHGTYUZFWXYZAXCBMGBAYRZFEEOKFWYDSOUGPRFEFSZIHHVQVHAODCLYETQJLSKRCTKNQZGLRCMCOKJWGCKTIAIMIPVUCOKNZFDXLCLSPJCKSIGQXAP"); - msg.feature_type = 201U; - msg.rgb_red = 246U; - msg.rgb_green = 166U; - msg.rgb_blue = 155U; + IMC::TrexToken msg; + msg.setTimeStamp(0.39994672036187884); + msg.setSource(46083U); + msg.setSourceEntity(30U); + msg.setDestination(29222U); + msg.setDestinationEntity(187U); + msg.timeline.assign("GLJTQPATJIZWOYDKHOQJQNHAUWPXNJKGGGDTMCCTZRBEEFKRLIQGYWKSAGSCEONPTZHFHYLJSOBUCAAZEYDLFBDJWPLYLWUMMZNXSIXFILVIYFFKOBXARNNQVXVCDRWXSCZOUYJDSZVCCDMERZUOBQLMEUEPGMAYSYEKNRRNESSBPHPXMUBAMWZDBFVFJMPQPAGHFIOXIXKBSVPTW"); + msg.predicate.assign("CAJOTRKLAXYPHTOZFHYVEIWXFMYKUHSQPQPTGZKLRVXXMKVJEIGKNNSJAMEOODSEJOLFTMABYXBMDZCPQROKNSNCYPAMOKWHWJRYD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MapFeature #1", msg == *msg_d); + test.boolean("TrexToken #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19890,29 +22563,27 @@ main(void) } { - IMC::MapFeature msg; - msg.setTimeStamp(0.437170209816); - msg.setSource(2404U); - msg.setSourceEntity(210U); - msg.setDestination(22448U); - msg.setDestinationEntity(47U); - msg.id.assign("LKWPQJFPQHJBSAJWYWZAXMZGLLETWIVXIZPGNTOCUBIESKYBDWMDNVUVIFTALBTLHSMSGDINDWKOFXKDZPLWKTRFBZUYRQHCAZURAVLOEWPATDFICEJXCNPEVCRBROAMDMTAJBHHUDHRUDQZGXXRSVGEIOYCPZMLXYKTAKUUEIWRGZNQXQFOCHKRIBHHXLNGJSQNFYOBHDTIZSFVBMYCXJARPVLMSYEFPO"); - msg.feature_type = 137U; - msg.rgb_red = 11U; - msg.rgb_green = 80U; - msg.rgb_blue = 165U; - IMC::MapPoint tmp_msg_0; - tmp_msg_0.lat = 0.787153237859; - tmp_msg_0.lon = 0.0668666236676; - tmp_msg_0.alt = 0.496662273764; - msg.feature.push_back(tmp_msg_0); + IMC::TrexToken msg; + msg.setTimeStamp(0.4922406281059192); + msg.setSource(26252U); + msg.setSourceEntity(186U); + msg.setDestination(37556U); + msg.setDestinationEntity(119U); + msg.timeline.assign("PGFFPOIOACKMMCMLSFPTAWQKIRXLBLYNJRZSJQAQXBUPYWYNJAZMAFXHMUSNGECUDUSLNOKXYVHITDIKIODTEQRMLORYNVNKMWZGAITLTQNPNVRXBYQDXVVBVHQOOHRXGULEGRFRBSSRWJTFQQWZACUMWOLONWKETHXXWZACAFECJHCFBKUSDIEYV"); + msg.predicate.assign("BQZOPQDAKIWGHAOMSZBFXYESVILHDQEDXDMQOEGSYNKOSXBUVOEBVJFYPZCBFYDITHUXSSMTRPLSMNFDGGLLSRJRICLKZXPAVVBJVINEKUUELYNQ"); + IMC::TrexAttribute tmp_msg_0; + tmp_msg_0.name.assign("KTEZSXVIBXRWSBZMQCIYLKXUCVZHFMISXOCMFWDCRLKHQIBVTGZMIWOPBZVJLQDGDDEYTSOXLOAZOBTTSWYNBGJEFARQPMNJHUTXYDEEYIJPNB"); + tmp_msg_0.attr_type = 30U; + tmp_msg_0.min.assign("GDSQOVSMJGXTDKEHRTKTNHCBDJRIJVMFKGZBAZXFPGVZCLBNIIWTKYMVLMACHOUEJEVAGPEZSMOETAWKLIAJHGSZHEJHADDXLXFIETFUKZFYHXYJPGMLBTVGLPOBKSQCWYXVWXTZXEVTRSUOVNOWJOIKVBUNWZYPLHUWDCANRLHWUKMEEOIYQBIUDFUQXBFRMDPRCRMFLXQQQUFAOZWZIAUYLPBDNNOKNSRJTSRNIQRPQGCGJ"); + tmp_msg_0.max.assign("GDVTBYXWUBPIQPNBXZLYCGYQZFUEKEDSSRWKASYGNYIKWFMOVOEJOAPZTOGJNFSXNZTMVFWXRCFDFUJIVKXLHOXHNOJDWAIUCMVPWDFYQAFQWZEXLWKJORLXQSHXJHFGSASVDLLAMPZIKRTANBRZUSZLTJZIPPAHBMNBECTGIHOSDBDUDZT"); + msg.attributes.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MapFeature #2", msg == *msg_d); + test.boolean("TrexToken #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19923,22 +22594,20 @@ main(void) } { - IMC::MapPoint msg; - msg.setTimeStamp(0.0739400638704); - msg.setSource(2952U); - msg.setSourceEntity(161U); - msg.setDestination(8275U); - msg.setDestinationEntity(84U); - msg.lat = 0.889508916474; - msg.lon = 0.275202859223; - msg.alt = 0.979318293077; + IMC::TrexPlan msg; + msg.setTimeStamp(0.8688721311070952); + msg.setSource(45362U); + msg.setSourceEntity(236U); + msg.setDestination(40045U); + msg.setDestinationEntity(75U); + msg.reactor.assign("GNUTYYESCHQLXKTCZRULAKZTSUWQJQZBHNVVDZXUBIDSGIXRHZIFWVCHSLNIAVWYXJSLZLBVFAHPBZPOFKOQRJORMDMMMPGCLNPKLQQWRKMHOWGZYNUDBJEDDCVASOFITXRZRUEEACTOPDNIZUNKVPKMYDGBTXBVHYLKXEHTBFMNCTMETDJBCAFFCAENFWSTGANAVYJOREJBUHEQXLIIGF"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MapPoint #0", msg == *msg_d); + test.boolean("TrexPlan #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19949,22 +22618,20 @@ main(void) } { - IMC::MapPoint msg; - msg.setTimeStamp(0.861385824175); - msg.setSource(49298U); - msg.setSourceEntity(58U); - msg.setDestination(44389U); - msg.setDestinationEntity(198U); - msg.lat = 0.0860085561111; - msg.lon = 0.793561801524; - msg.alt = 0.025918494702; + IMC::TrexPlan msg; + msg.setTimeStamp(0.16625266724981014); + msg.setSource(44139U); + msg.setSourceEntity(213U); + msg.setDestination(64838U); + msg.setDestinationEntity(36U); + msg.reactor.assign("OHKTUOIUMXKQBAZRLRUHAIYHJGVWNHDTPWDBDGGASWVQXUMPMWAUSSFQHWJXSQGXELZXQZDZLGBXZOEEYRWHBNFJELXIIPAUZCSRKSLZFQKYYRPPEETPWBFSDLLJPJGUYTADBVTCYVIKRBRQCNEIUUGWOTJQPCDK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MapPoint #1", msg == *msg_d); + test.boolean("TrexPlan #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -19975,22 +22642,20 @@ main(void) } { - IMC::MapPoint msg; - msg.setTimeStamp(0.0054276873232); - msg.setSource(58828U); - msg.setSourceEntity(249U); - msg.setDestination(40915U); - msg.setDestinationEntity(67U); - msg.lat = 0.968668387639; - msg.lon = 0.355977223876; - msg.alt = 0.6033422785; + IMC::TrexPlan msg; + msg.setTimeStamp(0.729382177687637); + msg.setSource(37783U); + msg.setSourceEntity(9U); + msg.setDestination(65092U); + msg.setDestinationEntity(104U); + msg.reactor.assign("RJZDQPSXIMJ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MapPoint #2", msg == *msg_d); + test.boolean("TrexPlan #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20001,26 +22666,21 @@ main(void) } { - IMC::CcuEvent msg; - msg.setTimeStamp(0.446080054345); - msg.setSource(62791U); - msg.setSourceEntity(132U); - msg.setDestination(60102U); - msg.setDestinationEntity(40U); - msg.type = 49U; - msg.id.assign("MVCGFZFYJFVZMPMWTRHCZGHVTDRNPYVDSWWBLMODPSULOJHRXYANFCCZYYCWJTOBRQFHRTDSDTVIQVXBMKRLKIEOIOKNGHXIYZSKROVXAYCBXYWLZWWLIPHIXCJSAOEIEQSMUULUETTFNKWIDADNGKQZCJIVGBFUQGMABCJOTEYPNJAQWMEPGHJNMXLMLNXZJPDDGUHCLKHEPXSNBA"); - IMC::DynamicsSimParam tmp_msg_0; - tmp_msg_0.op = 105U; - tmp_msg_0.tas2acc_pgain = 0.864493294842; - tmp_msg_0.bank2p_pgain = 0.588214318262; - msg.arg.set(tmp_msg_0); + IMC::Event msg; + msg.setTimeStamp(0.48835863644734623); + msg.setSource(63891U); + msg.setSourceEntity(147U); + msg.setDestination(35949U); + msg.setDestinationEntity(225U); + msg.topic.assign("KCEEVZPNGAHYBLXSFPOVHE"); + msg.data.assign("BSTTMCMMLWHVQPONURYNJUDDXFVFZOROQWWHGHAWXPDDKZBQDSQNEGFUGYNDMTFUZTW"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CcuEvent #0", msg == *msg_d); + test.boolean("Event #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20031,25 +22691,21 @@ main(void) } { - IMC::CcuEvent msg; - msg.setTimeStamp(0.814592175897); - msg.setSource(56271U); - msg.setSourceEntity(220U); - msg.setDestination(41647U); - msg.setDestinationEntity(139U); - msg.type = 165U; - msg.id.assign("QLULQEXUVLLVIMVJHKJKOWTMICDTAGRPQVMONQUCPCANHZNFPFCXUNRGACGBYAKTFZXKFOZRRPXJNXEGIOIXRFQYTSIZHQUSRTTFNMKGSISMKHAIYGOCSVTWLBLEZNNDJHWEWHDMHAHWVVTUDOEOEXJMBIYYWPNXLGYDDKUWWZBJUAJEBBJAXT"); - IMC::LedBrightness tmp_msg_0; - tmp_msg_0.name.assign("ZPOOPPFBBEVKBGLXFVNVRIHTPMAKFJUEOYPTESKPQQRHQEXGASNPBXCLTJLJTAUOYIGKMVOEKFXIJNFAAUPCDL"); - tmp_msg_0.value = 246U; - msg.arg.set(tmp_msg_0); + IMC::Event msg; + msg.setTimeStamp(0.09907937208133721); + msg.setSource(57358U); + msg.setSourceEntity(54U); + msg.setDestination(18939U); + msg.setDestinationEntity(80U); + msg.topic.assign("DEZGKXAGIZVWIJSKXFEBYWRNHDXCCSDQXOQCIAJQXKBTUTBFREJNQMMCFTGSCPRZNYUJDFWUITPNCDPSJONJCAEBXG"); + msg.data.assign("QANLMCFQLFVUUDRZGTYUBCROUUCDAJDQWWMLLNWOKZKHNRYLREVPTSBRPHMKVOGNNLDNMFCXSNQMDWHGABOBDTMAVEUFVQXLOTNEGTHCPAXFSYINIZPJNJAQOGDYXZYXGQWMOZ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CcuEvent #1", msg == *msg_d); + test.boolean("Event #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20060,31 +22716,21 @@ main(void) } { - IMC::CcuEvent msg; - msg.setTimeStamp(0.292921410446); - msg.setSource(60192U); - msg.setSourceEntity(97U); - msg.setDestination(14294U); - msg.setDestinationEntity(108U); - msg.type = 106U; - msg.id.assign("TEGZBKWSSWYOHMKUULCUNXEWHZDAOVBAOIHGZLMJYUGBLSGVMTXFQLSLGVJWUVOHDODEWEXNRQCLPRYEKMGQTIIAKXRFAPKQNAREPSKJ"); - IMC::ScheduledGoto tmp_msg_0; - tmp_msg_0.arrival_time = 0.0684486250767; - tmp_msg_0.lat = 0.458167225324; - tmp_msg_0.lon = 0.212607276338; - tmp_msg_0.z = 0.325805898441; - tmp_msg_0.z_units = 228U; - tmp_msg_0.travel_z = 0.205883793724; - tmp_msg_0.travel_z_units = 106U; - tmp_msg_0.delayed = 217U; - msg.arg.set(tmp_msg_0); + IMC::Event msg; + msg.setTimeStamp(0.3087276493549772); + msg.setSource(47495U); + msg.setSourceEntity(237U); + msg.setDestination(13830U); + msg.setDestinationEntity(64U); + msg.topic.assign("CBZVRWGCTJPAWLGQFPWXEDRIXIIXXUUVJHJQWVUJEYWQGOFFAIUFTJBKCVLRMBQXZGDNYOHJKMBPXTFZHKASMUEISGDRVOCTPNIUIKVZTHUMKTEZVRBEOWADZZEMGNYCLZQYGMBMLBXQRJCGPNERAZYCGQLFDMLRRSDFKPXMSIOVWJAJOOBOLSKVUDPLDDYHFQPTUCASQLTYJBHBVNOHHWFXNEWXASGTYAHKNTSENEQACSIYDIHCWMK"); + msg.data.assign("HNQVFXSONGZBAHYRT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CcuEvent #2", msg == *msg_d); + test.boolean("Event #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20095,20 +22741,22 @@ main(void) } { - IMC::VehicleLinks msg; - msg.setTimeStamp(0.737058776268); - msg.setSource(60195U); - msg.setSourceEntity(22U); - msg.setDestination(1911U); - msg.setDestinationEntity(143U); - msg.localname.assign("BPUBRFJQBMBMAXWGSHTZWGGVLDYIPIANFUWOTSEZLTHKTYVRIXIQYYWDXUXYQCNZBMDJRMHXIUSOOSPHLWHFQPAOEPIULQECEBLCLKVXWDKFZCSJFKGDQSDNXAZOBFFGYUZJACJDHYAAJGZBPRMECXGENTGNCVYXMFWDTLIUNRZVCPEQCGPPLVYTQMRSNROKWKOBLJVAICOHVKMJDUVTHXOTSNKRMZWSZRDHEABYUVAOMEPUNIJQHKRFEKQS"); + IMC::CompressedImage msg; + msg.setTimeStamp(0.05770132178398335); + msg.setSource(58893U); + msg.setSourceEntity(69U); + msg.setDestination(29988U); + msg.setDestinationEntity(26U); + msg.frameid = 58U; + const signed char tmp_msg_0[] = {-18, -117, -96, 56, 8, -21, -70, 83, -12, -82, -106, -90, 52, -30, 17, -62, -78, 53, -53, -118, 101, -124, -42, -93, -118, 113, -40, -76, 2, 4, 90}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleLinks #0", msg == *msg_d); + test.boolean("CompressedImage #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20119,29 +22767,22 @@ main(void) } { - IMC::VehicleLinks msg; - msg.setTimeStamp(0.600769690866); - msg.setSource(61464U); - msg.setSourceEntity(108U); - msg.setDestination(18741U); - msg.setDestinationEntity(146U); - msg.localname.assign("XSSVJLCQJEPBIMRXBTKEPYKRLPGGKIPQDQSUAWENXUVJRBMJRPXDMVCAHNGJYRVNQKTCIHQ"); - IMC::Announce tmp_msg_0; - tmp_msg_0.sys_name.assign("JHHLMEEXTAYBUKSVNLGSU"); - tmp_msg_0.sys_type = 175U; - tmp_msg_0.owner = 53965U; - tmp_msg_0.lat = 0.840400389152; - tmp_msg_0.lon = 0.173325654326; - tmp_msg_0.height = 0.381308597873; - tmp_msg_0.services.assign("SMDGRQGETRVAQXYTGRSUKCVGBEJAXGODJODNZYJLTDKNJKKBWEZMKTVWQVWFLKGJUCYTNIZWGOYYFTNUHVPHI"); - msg.links.push_back(tmp_msg_0); + IMC::CompressedImage msg; + msg.setTimeStamp(0.1640280337774923); + msg.setSource(61640U); + msg.setSourceEntity(175U); + msg.setDestination(21302U); + msg.setDestinationEntity(173U); + msg.frameid = 155U; + const signed char tmp_msg_0[] = {-29, -8, -49, 84, -91, 50, 63, 63, -101, 92, 75, 113, 84, 85, 87, 20, -37, -20, 72, 48, -11, -53, 81, -80, -69, 69, 15, 116, -101, -112, -54, 96, -126, 95, -23, -49, -6, 56, 44, -111, 39, 95, -28, -33, 8, -77, 57, -88, -40, 70, 13, -55, 121, -7, 24, 21, -83, 105, 103, -16, -111, -101, -25, -25, 99, 99, 101, -78, 29, -50, 120, -84, 55, -70, 20}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleLinks #1", msg == *msg_d); + test.boolean("CompressedImage #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20152,29 +22793,22 @@ main(void) } { - IMC::VehicleLinks msg; - msg.setTimeStamp(0.413479506052); - msg.setSource(7891U); - msg.setSourceEntity(10U); - msg.setDestination(23384U); - msg.setDestinationEntity(29U); - msg.localname.assign("TCZJSILESIZDXFEGRXFAPYRQGZIKWUYUBKDABJMSAWIWBKOCALRCPLTYYTHRJCWUIFWIKMAYYSVOGRJKKEVSXHTXQEDUOMUGAJWLFQXKOHLVOMKOIVVLHMMHEOAMZVREJEDUYVAWXJTCDRIDTHCXXQGQMUEGOJIIKPUVDGYROPZBFSRNNCWBFLTDAVJNZNNAPBNZMUGLGQFLYPVCJSFQBEOKXQNNEBDBHZHMZRNTSLPQGFXYTSPP"); - IMC::Announce tmp_msg_0; - tmp_msg_0.sys_name.assign("MUNZJDXKEXFSPQSZTXPLTUNOAVJDRGGJGHRCYIBRMEVBQCVCWGDIKOYPOEUQKGUVOHZSCFOUUQHJPWDVLXFMGJDVYBEFQNNRJEWPCQA"); - tmp_msg_0.sys_type = 247U; - tmp_msg_0.owner = 5303U; - tmp_msg_0.lat = 0.413199566795; - tmp_msg_0.lon = 0.613469177904; - tmp_msg_0.height = 0.868022581732; - tmp_msg_0.services.assign("JZTNIQTBBDMWMPGPEFRGTZXADPOUAMSJEZVWGVJALGPFOAWSWLJVATKPCLRDPUIPXQYNCQYNBRHCOYRGVIIFJHWZWQZFEGJQTEDPQBFUEVINSXUCDORYGUDSAHAMAPXLIJDECBVCHKXXTVJTYQLQYD"); - msg.links.push_back(tmp_msg_0); + IMC::CompressedImage msg; + msg.setTimeStamp(0.39638786123081093); + msg.setSource(28620U); + msg.setSourceEntity(188U); + msg.setDestination(802U); + msg.setDestinationEntity(224U); + msg.frameid = 94U; + const signed char tmp_msg_0[] = {-102, 20, -74, 48, 105, 119, 21, -99, 0, -105, -68, 26, 90, 9, 85, -62, -5, 16, -110, 60, -31, 122, 15, 124, -105, 78, -87, -71, 29, -119, 84, -101, -44, -81, 103, 108, 59, -25, -93, -54, -63, 27, -39, 114, -16, 24, 74, 81, -18, -9, 115, -37, 87, -6, 34, 51, -97, -73, 75, -84, -10, 73, 81, -64}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("VehicleLinks #2", msg == *msg_d); + test.boolean("CompressedImage #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20185,22 +22819,23 @@ main(void) } { - IMC::TrexObservation msg; - msg.setTimeStamp(0.66358612868); - msg.setSource(37521U); - msg.setSourceEntity(101U); - msg.setDestination(49884U); - msg.setDestinationEntity(38U); - msg.timeline.assign("HJJTDXUSDUQPXANVBLQNTXHYHAZAQQKEVBCAOSAYBWGWAUJMHYTRJQOAYRBKZXEXBWXCSMZZBOVSLOWCDNEZOQHMMLPNJQPBPUENGUWLYRGL"); - msg.predicate.assign("VJVWKITNTHDKHWGSGXPCKBAZSGWXCQXBSFZAQETFIJBDYCOEYFUGBCVDHXPXLCYFVJHHINRDPMOTRIRAAKIMUUOJXURPLMEHDJEFSNNLXRYWUULYNPMEWBIQICKTGMBFWJDVCZVYFEMYSFHZLLPFOHKEAGTWHBJXPOARLUQIZNARTOWCQDBALQTAKJADWYRGISMLOMXZYJMVZRZGWVNQLNYPPUZNIRU"); - msg.attributes.assign("BKUVMCOQPHZLSIMCQKDPNJFJGXVHOAIGDLUYKGYXQSEZQSMJJSKNWKOCCDZZPDQNFKMRKTNNENXVHHQWHZPWECOUEGKJXVUFFYFAGDLOQBRXOBFEBRDUYTZMSUSGJZRPDSDIYABNVNLNPTGXJYRZLGTITJOKZSWEWIBTKLILLBCYUMPSAUWRYRPREFOMFARHCJVGPSIWWHEQMHFVXPVWMXY"); + IMC::ImageTxSettings msg; + msg.setTimeStamp(0.02238651389799451); + msg.setSource(14497U); + msg.setSourceEntity(80U); + msg.setDestination(19981U); + msg.setDestinationEntity(110U); + msg.fps = 172U; + msg.quality = 19U; + msg.reps = 98U; + msg.tsize = 144U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexObservation #0", msg == *msg_d); + test.boolean("ImageTxSettings #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20211,22 +22846,23 @@ main(void) } { - IMC::TrexObservation msg; - msg.setTimeStamp(0.336690797558); - msg.setSource(51482U); - msg.setSourceEntity(66U); - msg.setDestination(44536U); - msg.setDestinationEntity(127U); - msg.timeline.assign("YBSIVGDKRJBUKSSFFCREHYSZBGWLIYIYNURCVBABAZGAZIFXNNQFKMWWBTRVDGAQGAOUJRDSVYPZQFWEOLENXHNMSRVLKLXYDXNLKQLUYULPJMSBQEWTETPFPVRCIDZIOQJCSXKMWMJWUHVIMQFUOSKHBZYODACPPFWTOQTHAPAJMIXVTGEPETIRBEOVKHNSCW"); - msg.predicate.assign("EMQFNULUXKTKGTWNETKW"); - msg.attributes.assign("JWCYTVVFNBDEWEPQCDKCCTITNOJHUFXYZPNXZVOZVMONPULECYFRIDQCMNUEXGAAOSGRCSZNFYGQXRURUNBVRLOFXIUIAYERIWNRAMJKCOQGMBIUKSQBHDBWTZXMHWKLVIIDAOPLKDILJFDJPOGTQFVEEOZCPZTHRHSLPSJLDGKPWTVKLQYBGDYKJBUGHAFWXEKAWRTEYQQNBPBN"); + IMC::ImageTxSettings msg; + msg.setTimeStamp(0.8453190175007368); + msg.setSource(39225U); + msg.setSourceEntity(2U); + msg.setDestination(24003U); + msg.setDestinationEntity(104U); + msg.fps = 214U; + msg.quality = 149U; + msg.reps = 191U; + msg.tsize = 78U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexObservation #1", msg == *msg_d); + test.boolean("ImageTxSettings #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20237,22 +22873,23 @@ main(void) } { - IMC::TrexObservation msg; - msg.setTimeStamp(0.338838985346); - msg.setSource(58938U); - msg.setSourceEntity(172U); - msg.setDestination(13218U); - msg.setDestinationEntity(139U); - msg.timeline.assign("PDUSWGXWJBHOIUEXUNIDEWXKPIEYIBUOHSWLFWQHORMQNVDBDDHKLOSJCGGLVINGKVUBZTVGWXBKJIRHIZFIJRMACKCCSUATGQMKHYOXMZCDCBUYNUYTGCDLJOWBRFJMVZPOLMMAZGELIAAQSLZTCYCAKYRLNOJEAPLNVGPNQJZEFBSDTMZVXMFEAXQQFCHTNSFHRFPOUWIEJTHJPAMPBSKRUKZPFTYDVAXFSBRYQNTRROQWZELS"); - msg.predicate.assign("KTAHBMDVFJPPNKZZCMCBOJLRIWVUNLYJYNBBHZGUYEHXSZGTAGQORIVATGPQTOFVIISAMSXPMOHRUSIDCLGIAUUWTOQNMLQWMPWYMIJNWBSAVUNVZKWCWLLHXXCEPDDGRTHGFFEABFSOIVPOFHUDYKYABZCKHCFBAYKYFBJTJQWCQEEDJLMMKECMXOJZYEPGSWSGUTKPTXDJREFRJWNQDOCYARZRQUDHIHVSXVDZKNVRBXXLGULTXKFR"); - msg.attributes.assign("FEVANHYVDXBFLGDEPVQRIGHJFPCRYVKPLWPAIOXPRQZCNMNUUDGIJHZRMRMJTXGUIQMMBAWGTBEOTSKZYBFJUNEXSNWCFSLRVVTCIZOQNSHULUXTLVZZTLHWATNAHSKJCXYDRGKDSAIWFCOVJTKDIOJCKEEZKNLWR"); + IMC::ImageTxSettings msg; + msg.setTimeStamp(0.4520197131494267); + msg.setSource(42219U); + msg.setSourceEntity(109U); + msg.setDestination(49672U); + msg.setDestinationEntity(136U); + msg.fps = 29U; + msg.quality = 176U; + msg.reps = 227U; + msg.tsize = 80U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexObservation #2", msg == *msg_d); + test.boolean("ImageTxSettings #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20263,22 +22900,24 @@ main(void) } { - IMC::TrexCommand msg; - msg.setTimeStamp(0.748711956512); - msg.setSource(10693U); - msg.setSourceEntity(92U); - msg.setDestination(7754U); - msg.setDestinationEntity(251U); - msg.command = 33U; - msg.goal_id.assign("LGYJJMIOOMEPRELXFOTAZBNBAX"); - msg.goal_xml.assign("MNECVIDZHISMXQZSCCXLKOAXCFHDQUWVNYCDJEXNXAIESAHKNBXUSKMGGUXFBFZYXVYOCKKFYVMKTJFCDWEQHCAGVOYUYOJWYZLHBDSURJIGOMAIRNRPZAEPDRW"); + IMC::RemoteState msg; + msg.setTimeStamp(0.2572806756260919); + msg.setSource(30277U); + msg.setSourceEntity(116U); + msg.setDestination(19257U); + msg.setDestinationEntity(231U); + msg.lat = 0.7790188513754648; + msg.lon = 0.8450631063151339; + msg.depth = 29U; + msg.speed = 0.6325043253304486; + msg.psi = 0.5359755595897294; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexCommand #0", msg == *msg_d); + test.boolean("RemoteState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20289,22 +22928,24 @@ main(void) } { - IMC::TrexCommand msg; - msg.setTimeStamp(0.820009955373); - msg.setSource(16125U); - msg.setSourceEntity(106U); - msg.setDestination(42544U); - msg.setDestinationEntity(253U); - msg.command = 215U; - msg.goal_id.assign("NLUDHLAIVZPJUVRTTXF"); - msg.goal_xml.assign("EMTIIPOGUTUQHUQYKZKHDDDJAHRONVBMOUFFPWSAVDRVHGESFOGIMAVXVGAYPYMWELYZATUXQJBCNYUCSKMYAKBSYCDJV"); + IMC::RemoteState msg; + msg.setTimeStamp(0.4874000540391151); + msg.setSource(13171U); + msg.setSourceEntity(41U); + msg.setDestination(26918U); + msg.setDestinationEntity(217U); + msg.lat = 0.5720973854609025; + msg.lon = 0.03391032448912401; + msg.depth = 64U; + msg.speed = 0.053912871330200285; + msg.psi = 0.1802006910302718; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexCommand #1", msg == *msg_d); + test.boolean("RemoteState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20315,22 +22956,24 @@ main(void) } { - IMC::TrexCommand msg; - msg.setTimeStamp(0.051876799274); - msg.setSource(62862U); - msg.setSourceEntity(182U); - msg.setDestination(59616U); - msg.setDestinationEntity(40U); - msg.command = 57U; - msg.goal_id.assign("KBDMDJSBADHJKMQHLVUILBQFXNIJQUPGPNWRXGQEDV"); - msg.goal_xml.assign("JQWVINHHOCWPOJVQIHXKEZJYKZDLMKBFKHXQEIGNTKSNLPEKYIGRRVNAEUTRGAWAPMVNMNFPPOSURDRLOOXUDZXKSTDJRRICTZLAGHBYQHRQEVACBPLAUAWYATGFSDHIRIWFMJCFDMWMABGSOXPNPGPUTMPSLZYSFTSVQJUWFCMEFVZOUBQXGIBEOBIDEBXLOBCSXLLFBECWLYWZDAZJOYTVYCXFRJUTZHVNQYEIHYUXNHTZKGQKSJDKW"); + IMC::RemoteState msg; + msg.setTimeStamp(0.22535754857248036); + msg.setSource(42118U); + msg.setSourceEntity(3U); + msg.setDestination(48264U); + msg.setDestinationEntity(200U); + msg.lat = 0.8210531823403335; + msg.lon = 0.19000788924173728; + msg.depth = 215U; + msg.speed = 0.3720459365126557; + msg.psi = 0.021723617798964256; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexCommand #2", msg == *msg_d); + test.boolean("RemoteState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20341,25 +22984,26 @@ main(void) } { - IMC::TrexOperation msg; - msg.setTimeStamp(0.0513879561665); - msg.setSource(11408U); - msg.setSourceEntity(64U); - msg.setDestination(56259U); - msg.setDestinationEntity(246U); - msg.op = 219U; - msg.goal_id.assign("METVCXYGOJXYKYHUVRPIZTLRNCZUBSOLVWZUOUPJGZZPVBWQCJVURTNERPYEDVALDOQHRJPAZQNAIXEGPPGEENRLYOZWKSWHIOPLCHLINHKGXUMKSYFKGGFRAQWDFBQQDAJATCCRPQQNMTXMFIGHRJC"); - IMC::TrexToken tmp_msg_0; - tmp_msg_0.timeline.assign("HKDXANNPODMSGITUTTKJDFONRDJXLFWHQHVBSAGZGZYIVIQMSSXQSSMOEEZEDGPVFMENBRQOGUUTPAOBKKQNYOWLURXCMYLJQGWMFLBPWWCARYTIZDGANYVFNJJCEAHDMBRUUOIUWHVELWWXERYJKDWSKAHVIJMDOXLTGCBKYHGIAUPVZLZWZHKEALXMQQFZZCXPOKHBRPBXUGUQBPKCRXTYTTTENZFFSRYVMLPPJAINNSLHERCFVBFQC"); - tmp_msg_0.predicate.assign("REBVFEXDDPZXUHMXARKDTDGJCOBNFTDQWBZTBWULQBIU"); - msg.token.set(tmp_msg_0); + IMC::Target msg; + msg.setTimeStamp(0.2445045872159638); + msg.setSource(42451U); + msg.setSourceEntity(171U); + msg.setDestination(9127U); + msg.setDestinationEntity(10U); + msg.label.assign("OHRIFYHKNBFELLIGTABTQAJBDQODLSUIGPPCQCIBFNRFYUZEENKBRKGVBZIMLGVNPHKGDHCXXOTEMFRQEUQAWLPDQRPFJDEZPCKEMJVUGWHAJYGFLNOJZTAJZARJDUKZVARDMBSMEVKNUMHYTQWBKNXPOVXLLGJHOHCWXMBXOFQCRVCJDLPAWSNQDYXMWEYLSNSKWW"); + msg.lat = 0.47865242740352365; + msg.lon = 0.9243386319243372; + msg.z = 0.5298202898864727; + msg.z_units = 174U; + msg.cog = 0.8150235184530245; + msg.sog = 0.5163401859809047; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexOperation #0", msg == *msg_d); + test.boolean("Target #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20370,25 +23014,26 @@ main(void) } { - IMC::TrexOperation msg; - msg.setTimeStamp(0.44968383242); - msg.setSource(5766U); - msg.setSourceEntity(222U); - msg.setDestination(48101U); - msg.setDestinationEntity(226U); - msg.op = 43U; - msg.goal_id.assign("GRBRXEDVNXSFOHRDTNFQRPAWQMKOJCZSJSZWFGEZUFLPLCSYEYZYCVPYRKGIFHCLBKGJASHEDWWUIDQTTTKCEPXUXNRBAQAKHRDITADCUVXWGINQROUTQQXOIPBWFOVTPMSWOKIGDHMOAEKPIFBLHSBHLQKJWLGTPSTRFVZJMHQDJMUZEGFIVALBMRFZKUXVHWAGDGZEYNA"); - IMC::TrexToken tmp_msg_0; - tmp_msg_0.timeline.assign("FQFBVOAFGAKJLYEXFGDZNETONGPSZAYRRJZZIQKKBYCWWXBWJBTBQIOSYVJYLBEHYLJJEUVHCFNUCRJRHWJGDNOAHALIDUHTGEZBHSQDOFQTPOISAPWGHHPNMMYP"); - tmp_msg_0.predicate.assign("FHDBUATLTWRHBMXEFLVNMUSMSSIEAKKYWGXCOJAUUUBHZRQVPKIGZNQEWCSTTXKPFVOHSGGPVRIPYGSZMCIZRVUJNQXBKZZDOCTWLEJXPBCKWLFZTGIWDLYBHTUOFDCIBGTMYJBRYPERASDXDJNRVMEWYTFWXBMAAONELUOOUCRKFMMTDOHRCMZPKNEVNVYFZHWDGSVPQHBOWKFZGNYDJCNYGXJIN"); - msg.token.set(tmp_msg_0); + IMC::Target msg; + msg.setTimeStamp(0.6185423156228472); + msg.setSource(63856U); + msg.setSourceEntity(146U); + msg.setDestination(25642U); + msg.setDestinationEntity(12U); + msg.label.assign("MNSKJSIHXTKMYNBURRSRGEFCOTWCOYCAYPMXNDSLPAYSOTCJTSDDZA"); + msg.lat = 0.7982774785035168; + msg.lon = 0.8924999065403779; + msg.z = 0.533564249912207; + msg.z_units = 197U; + msg.cog = 0.09569062091790737; + msg.sog = 0.08406525654550223; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexOperation #1", msg == *msg_d); + test.boolean("Target #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20399,31 +23044,26 @@ main(void) } { - IMC::TrexOperation msg; - msg.setTimeStamp(0.243744553191); - msg.setSource(34685U); - msg.setSourceEntity(16U); - msg.setDestination(12796U); - msg.setDestinationEntity(137U); - msg.op = 19U; - msg.goal_id.assign("ARQKZRXYQGJDFMLJTUXYDUIRASTDEKBNVZHHDCZLJLFJZEKPVXWKIFCLVYXEDKINAYHNTEZQVHOVJFPBPTWWSHKBWEMGBMBCSNVH"); - IMC::TrexToken tmp_msg_0; - tmp_msg_0.timeline.assign("TVRQQGRFLXAUUXHUWNHYEMPNYBGRTMOAKBDBYHKEDVCTGYMEANORNMXIZGYXSCGDGPVPUAVQDDTQWODPNSTFKMZNIUZONLHJIJXQWFBRSTTWSENLIKOHLAAFXLLMZWDEJOCHVSKTKVVMEQGLMYZBLRMGCYOUWSHFTOXRTIYIQWEKZDRACFJKHBPJMR"); - tmp_msg_0.predicate.assign("HARNNLQHKYGOIGSGWMRGDBVKAGAHPPNJIKVCJNAIROXMOPUUTYSDYXKQWEXCBYOFYZFFSBVTKZBYZTEDOCYD"); - IMC::TrexAttribute tmp_tmp_msg_0_0; - tmp_tmp_msg_0_0.name.assign("FLEBMUSSLVVTCWCWTOQRHSFBKVCPPSCCQQKIFYVJUQJIHNIYDOEEZAQCJJPWSAJXIJBNJHKVWQPBNRZPEPQPBHUZZOESRROSNLYD"); - tmp_tmp_msg_0_0.attr_type = 231U; - tmp_tmp_msg_0_0.min.assign("TFPMSRXDECVZCFSZUUVMBWCFIBMGWWIVJOGMOLTUFNOEHQXRDVGPUDQARLMOQZBJATEEEHACNJFWZPDUICYGGOAKCTPJVRGDIZQLHGDCXWPZVDHMKXKKWTLZYLHBKQDXGKCYFIBBZXLX"); - tmp_tmp_msg_0_0.max.assign("UXFDGGIISLFPYIRLXFQPEFCHSBZEYTKVZQTTLCSYOXNYUEODGLBGYEIWVDWTXWRFTBDDKZZZMQUNNUCLWNEAI"); - tmp_msg_0.attributes.push_back(tmp_tmp_msg_0_0); - msg.token.set(tmp_msg_0); + IMC::Target msg; + msg.setTimeStamp(0.2944106735248332); + msg.setSource(45844U); + msg.setSourceEntity(217U); + msg.setDestination(11084U); + msg.setDestinationEntity(57U); + msg.label.assign("AGCGCQCYLRBJYDQSYMDDGVXREMOMYOPMEHPFHGEQHUUBTBAZKMFQWNUZSXWBXDMMIZZRKCRYSRPSERXDPZPIHTUTKZUVONFXKEHHSSENYWICLLLXXKOVNGIUCGMPGFEOFBLLAUOTRKLNDDVJATGQGJNJGNSPHZTQLJFBIPWWHBREKIWZJSQNYLBWWJOOAYSATFIVOBFJCJUAARVXEPFLYHMXZDKDMVWIBUVCTP"); + msg.lat = 0.022904476330382395; + msg.lon = 0.747894089731254; + msg.z = 0.7610639666230489; + msg.z_units = 178U; + msg.cog = 0.9903412140353889; + msg.sog = 0.3495173567399572; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexOperation #2", msg == *msg_d); + test.boolean("Target #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20434,23 +23074,21 @@ main(void) } { - IMC::TrexAttribute msg; - msg.setTimeStamp(0.797473209723); - msg.setSource(52821U); - msg.setSourceEntity(3U); - msg.setDestination(12206U); - msg.setDestinationEntity(230U); - msg.name.assign("KETOIFKHJARLECYYZIZUSJZBQQBUZIDPQQPJKQRTHLVALOVISNFYOWJDNWDJQRWRSPQCFVLMZOARGBDYDYXMNISVXJGOFBHWYAJGSHQCVLOEGVHXFHTUCMLTUPZTAGPCXBGDPRERCXBOXEFUZKGBNFOMEVMPIGAKMVINWADIZURJOTCNSYLSVDSPWPHNFREC"); - msg.attr_type = 78U; - msg.min.assign("DHEUCTDRBHCXEBYKDJHKHZXPQDWARIMLEPCDEAHA"); - msg.max.assign("IDXOWQTYRJGVRYUBZFWRIDFEJOKGXGNPLINWKUHAJESEHGBSZZLHWXWCSYDGLWCKMKZXLZEOZSQMISUOBYVLHVJKDTOPPLOCHVBPVRSXJZBMTJFCAEEGKTMMACQNPDNFMDYYBWIPENAAIOCPYFLHAZCJSUWDKRLIPYXQQXGLFVYDHXJUMRQSVFBRZTYVSBTKPRFOBGOEHOQEBMZADNUEAGNAPFTQTUUXMKUMGJTNCXDUINWRJCCVWTVSQ"); + IMC::EntityParameter msg; + msg.setTimeStamp(0.8754607813883944); + msg.setSource(7378U); + msg.setSourceEntity(112U); + msg.setDestination(23478U); + msg.setDestinationEntity(223U); + msg.name.assign("JPCZDHECWJMVMGFQKNXIADQDXGVWWBYTXRKPLTSAEGKVGJDUBCCOHQUMPAQFFEXXQUPZOFGIUKPDAMGKRZUROLWTIOVROLTRARMPIPJHCWEMOZZHKHNXIYQLKDHVCRLBNQMLEYWPUFATAUHBAVFMJCWDCBGVNVGBSVEZWMBSLONJNDRZXUKTLOAIJCJELSZSJBYEHYDWUPNFIGNBNYZGDAQHO"); + msg.value.assign("LWXCGPYPFLVGCYUKERBRQBTYIDJAXBHUJXBPLNQWXVKVJDOSTWSJGFATVCDEXSHLIZWZJAJHLSZVPVLHGKYXDMHLZJQZZTDFKEQDGCLIDGUSWICMHRABFKEJTFBOXXUUYOMKMUSLKJNOHTFGOBFPRZIDNFQWQZGESIUWTIOEJRPEKPMQZRVVLIMYCKKEWRTWUTDOERFCUFAHUZONNNDWNP"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexAttribute #0", msg == *msg_d); + test.boolean("EntityParameter #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20461,23 +23099,21 @@ main(void) } { - IMC::TrexAttribute msg; - msg.setTimeStamp(0.10443837191); - msg.setSource(13564U); - msg.setSourceEntity(129U); - msg.setDestination(34090U); - msg.setDestinationEntity(77U); - msg.name.assign("CRSXVDZFDOBLALKVM"); - msg.attr_type = 218U; - msg.min.assign("IOBYPNWVGJVOHGNOWDNQWROQQRJUFWKDWCBOBURYYZTLTTNCBBFKKP"); - msg.max.assign("FCFQSVPRVPSOIKPCJFMLFPTSLTBQNANCNXAAXNGTJRKQKLQNDDOUDIHYARVTHVXDMWRETODHWBCNSFEMUAXGLSHWUVXNWXDYYQPHEAITGZIZTSKEIALMHJMJXRKMGOZJUBBBQDOKIEZCHBQMJUUCHAFGYHIGYZKCPANUQWBLLZGZJEEXYIOSTUVHGWODKWBBMTRSJPALMRK"); + IMC::EntityParameter msg; + msg.setTimeStamp(0.7405241298824071); + msg.setSource(37197U); + msg.setSourceEntity(171U); + msg.setDestination(49198U); + msg.setDestinationEntity(254U); + msg.name.assign("UYMFJXJZSHWCOAWYQZVFBGUSYLERDMJHBVBSFHGKROTJWPIXQICDYJOCGDZHXMLCLGQUSME"); + msg.value.assign("SEZHBKMILUEHWYZRKHYEUIFZUFIDBKUTGCDMQFYMQGXPWU"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexAttribute #1", msg == *msg_d); + test.boolean("EntityParameter #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20488,23 +23124,21 @@ main(void) } { - IMC::TrexAttribute msg; - msg.setTimeStamp(0.488742224801); - msg.setSource(19731U); - msg.setSourceEntity(105U); - msg.setDestination(13290U); - msg.setDestinationEntity(110U); - msg.name.assign("GTNZMVXYXVIXFSIBLNIXGWBDADQWZPFOAGABPXDSQKSJLWZFXTIMSMFJMUICNNNERNTYHKCJRXFPMCIYZQAAEGYKCHBLJWNFYGBTKFNUYKKEUOVWEUMHHCHVFJ"); - msg.attr_type = 63U; - msg.min.assign("SBJYDAJWXMEOHCNWLJMHZMRQJPXCEYDNXRQDIXFGVJTTMSMWEAGSTNIETJMSULAHOOAETKXEYGHDXDWDHEZLYBXZNPYSHURHLFIBPLIFDPZIDIGAWXRQUOYJRUFSUXKOCKKKZNCZSIVZJJELWQTAHTNGBCOAZEGGPBGFM"); - msg.max.assign("WKISDORCTBPYBLDVETZJNDFFRQUXGBMVVUALEZCRUMYEQGKZVYWYDPTYYHRYZPHVODNBBLKBFXHKJKUBALFBECSBSVQXSKUJZZPSONGIMUWPNEQCQESISPZKTGMZWPXZJVF"); + IMC::EntityParameter msg; + msg.setTimeStamp(0.459990398722011); + msg.setSource(48686U); + msg.setSourceEntity(26U); + msg.setDestination(2698U); + msg.setDestinationEntity(234U); + msg.name.assign("FIAEPPNGTBDXFVWEVZZOWSMGOKQKDFYTDXXJUWGPWJEMYRWAKSZDBZQHVACTPDLYZTHSCQEERIJYJIIVEIEDHJWOVTNBXMFUTZKRFYNZGRLNYMXBKKUUPOHNKFTQXNNRJCPZXCGOSNVGOLSQKRPOILCTBRUAARVLDTAIGMZOOQDMVYGKOGGQMBENJQLEJZLUCLPMXNSA"); + msg.value.assign("OMVLNVJQMOSRXSWPQIRQTTXHLHKYCHQGOIKNKTHWZBGIOBJYLVDNGGKZLYHGIYFEZVMAFENKQBPERCGECOYDLJEMUFGASUHCYWI"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexAttribute #2", msg == *msg_d); + test.boolean("EntityParameter #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20515,27 +23149,24 @@ main(void) } { - IMC::TrexToken msg; - msg.setTimeStamp(0.83717144209); - msg.setSource(53125U); - msg.setSourceEntity(136U); - msg.setDestination(28753U); - msg.setDestinationEntity(40U); - msg.timeline.assign("MTQKIFDARQQXELBVWVITMWA"); - msg.predicate.assign("UEMFGMAFRAXFVEGGLVSZGEDKDBVGQNLYZMNKRGFQYRUKWAQKDEXMTNAFFEHBXJDWTSMUKOROQTYWZPELTJOTQCWFJNHCIVPYWHCFGPTRMSWZIOLWTYTQSBRSKHUHLAQMQIKCRZELJ"); - IMC::TrexAttribute tmp_msg_0; - tmp_msg_0.name.assign("SEOVDQGUYFXORSGDYWCEMDOFNMJVQPURZNNLAVWCTATPCAXQEXJXIQUZBRHXSKCXHDCNRKLRCVOLTMJVPRJDZJGWDRKHCLEVPOFAYHOQKEVWMOYQGDCTQFBHTFVLLPYPKKUIXHHAY"); - tmp_msg_0.attr_type = 18U; - tmp_msg_0.min.assign("FXFPCLBXAJHBZOOOBBBKGNSWYNSSOJMNDVJWQEDQHPBRBWKZYRUNIVMMFRFJGHLIHWDVWTZKWARQUEXSDZOCYHKSFVRQUNXKYWFILSQKRXPJRDT"); - tmp_msg_0.max.assign("OBDZEKRDSPIXWPLGELLFXYAY"); - msg.attributes.push_back(tmp_msg_0); + IMC::EntityParameters msg; + msg.setTimeStamp(0.6900009661519426); + msg.setSource(64089U); + msg.setSourceEntity(137U); + msg.setDestination(41668U); + msg.setDestinationEntity(95U); + msg.name.assign("NOJNWXKHRXETSIQFEWYZNBBLXBXDTSDEOYFBJDGQTMUHIVUZLZHHKSHPYWVRKHJJTNSULJLGDQTYIUTEXMXWQNYBABDSMAKRQFZUEEPFGFANMODHBWKRBMUYBCZVTCOJLGMBDXIHQRGQDWMMFVAUISUPVRJHMTGVCNSIAJGWF"); + IMC::EntityParameter tmp_msg_0; + tmp_msg_0.name.assign("ENIGKTKMNYSRCZIEGFQPXNJOJAQVRZIOOOQDQNOMYBSZJHKFWFYAAIMENXUPXQFUVBUGMNLEZDWVGFXZQTSYTBMZZEXSHPBVKLKCJPLQVFDEEYDAGSEWWGJCRPASNJNQBLODTSPZYRXIOMQCDXMRKUAUKKYSVICTTHJNSEBVHSLJKFLAVDVXAWQBWORBLPHYFNGHJUDWFBMIPDAUUMICGCMXW"); + tmp_msg_0.value.assign("QOIJBFUKGUNUWTPTKWKNQEASRICOHHVYPCWYZZMUMWKPLVVKPUUWABNEZTWEMNKTRRVDIDNDYTQTSMPJSBFJGJRZBVCYGSJGXQVLQGOOQAWKXUEEXCAYUOFZLDTXRAZKDXPBYSNTFSIPFBFAMHADKEXCJASYOMJLTINDYMILNGCEAJFFOVDBHGVFPZQRLXPERGLJEHHYQNXKFZLBRRIJICVSWHGXCDOLUSO"); + msg.params.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexToken #0", msg == *msg_d); + test.boolean("EntityParameters #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20546,21 +23177,20 @@ main(void) } { - IMC::TrexToken msg; - msg.setTimeStamp(0.147941281227); - msg.setSource(7224U); - msg.setSourceEntity(97U); - msg.setDestination(42854U); - msg.setDestinationEntity(244U); - msg.timeline.assign("AVHBWNWQSAICSGQRARRBKMRCYTGBBDDAQYSMJJWANHINJKSRWUZUBTLGQFRUFPGXYOJLKGCKLLQNEKZQTUFOVXOXZROXPCPOBTDUEVXELHPCUEMZQVWMGHBVIOGIMAUXZZMCKTDWVYLIFKOYBQUYIDOIJC"); - msg.predicate.assign("MFMONHCOMJYLCGUSECEZTMFETHEE"); + IMC::EntityParameters msg; + msg.setTimeStamp(0.49248257002693185); + msg.setSource(170U); + msg.setSourceEntity(212U); + msg.setDestination(57526U); + msg.setDestinationEntity(88U); + msg.name.assign("BPOFNPXABJMHRFFZSAWXRVZMAOHEWBTKCIEPVJXM"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexToken #1", msg == *msg_d); + test.boolean("EntityParameters #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20571,27 +23201,24 @@ main(void) } { - IMC::TrexToken msg; - msg.setTimeStamp(0.777044257464); - msg.setSource(17247U); - msg.setSourceEntity(155U); - msg.setDestination(41814U); - msg.setDestinationEntity(92U); - msg.timeline.assign("RTBOBGOMTCUAQIPYYDUAPPKNXVQNJQJXGNWKLOMUCVPNFHCAWIRSMVLJLRFXAGOGTRWEXGUIMXPQZCDQSAJSZXDOOMHKXCBLSEKWSLJOTKQIXIGIIYYZHKNHBGVFOMFITZWHTOE"); - msg.predicate.assign("OZKNCKFCBBSANVXXTJDWSKZWJUOSXNNSITJVAQUZYLIQXXEBZROERDOOJQACJXWUADRYVPIVMNKAIHTRJUXVMNNLSYPIHYZPBGZMRHL"); - IMC::TrexAttribute tmp_msg_0; - tmp_msg_0.name.assign("XNTGFCXZNHKPEFZXBQQEWIAZZRIIFSVWJWURMMACHDCVFQYUIEBLBXCCQVUKXRMGKATSGOKVYIEJZJWLMFSWSTXFNQMZTYUYEMUXFQGPVIDJPTZCD"); - tmp_msg_0.attr_type = 49U; - tmp_msg_0.min.assign("CSPWNUPTYBWDXTVWPEORXHOLGEYJMLIFEDOWWQAMRJTOZKAFONMAUJKFSGLOLPDRMJBVVDWTUNHYRHAPQPSJWZDMEIHGKYEVSZBFDTYYINVUKFQNRCVZXTMDUPQHOPYKEZUUMPSHZCZEEUGJSJBWYASKIQSXAMBVYNHGZCFVNM"); - tmp_msg_0.max.assign("NOKEFAENUGGZJOXVK"); - msg.attributes.push_back(tmp_msg_0); + IMC::EntityParameters msg; + msg.setTimeStamp(0.5562254686919966); + msg.setSource(46096U); + msg.setSourceEntity(208U); + msg.setDestination(16358U); + msg.setDestinationEntity(60U); + msg.name.assign("ZRXBLARKBUJQFHZZOJICNYXFYCKWOUUEOCRLBPHODTRZWSICSOAINIMRKMFGXOBVEZBMIYTTWSWVSVNOJGPBYHOPHVXIDLQEQSMZMRSUNOMQWNGFXAZPZKUXMXCAPUZRRVYHNNGSAFTPFVYBTGYTLJMGALDAXVFMXEPQPLDEDGBIJPWJLHIVDTIWRQUKDCKIXJLEGHAKANWNOGTQHYVTGBEYDQCSWQNQJALLKUECHUJDEKYFTCFUDCJMKZ"); + IMC::EntityParameter tmp_msg_0; + tmp_msg_0.name.assign("RMNVBAVHBXMWEQALOMTUJIFWJACJTXKEWMRALNOZUQCRDLDTGDDYKEOTNHGPQOEUITLSPMFSHXAWCKHGJOZKUOSBPNPQCXIWXHVBWMVRPAVERHZGHQICGYKQZWVCPEDWMXPEITDLGPJSSIFKLKZIUCUNDUTOZNEUCDFAQLCQFLTZXROGXXRVCSNOHSZJMBWJKKAYBFVLYMYN"); + tmp_msg_0.value.assign("RJZQBMYFASVYHEJUVKPUMPBDCZPUCDTLWLGLPSQEEQLZHUIIBDDKKVXQXNQDRBGOICGCCFXXMWGHNZSSQRARHGBHGRRQKIWEOJJVVFVXXAMRUTTRHFRBGMYGGUFQWJOKOKOSTVHHOZHFYWWWKYEBAYCAAWDLULASJTFSJYXZFIWDRLSZPMTNTDSCYOHOFATMEGIAPZIYIVPSYBUMNLIMCNZBXPEDLNPETTIUBNVJNKZJKLDCWUMFKEA"); + msg.params.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexToken #2", msg == *msg_d); + test.boolean("EntityParameters #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20602,20 +23229,22 @@ main(void) } { - IMC::TrexPlan msg; - msg.setTimeStamp(0.882163917033); - msg.setSource(23884U); - msg.setSourceEntity(191U); - msg.setDestination(13470U); - msg.setDestinationEntity(16U); - msg.reactor.assign("JFPNRZTBMJHNIOSSAXVOEVMLZPDBMJKHJEGPADHPLMJHECOPYGEEQCYEPTUXQGZJWVBISYIYWZUDCNNK"); + IMC::QueryEntityParameters msg; + msg.setTimeStamp(0.26365269656029366); + msg.setSource(9734U); + msg.setSourceEntity(92U); + msg.setDestination(18114U); + msg.setDestinationEntity(118U); + msg.name.assign("ZHSDUFSJBDRLQTBPHGQESZWZW"); + msg.visibility.assign("ZNZFAXFBMKOEYSNQPXFVUEMH"); + msg.scope.assign("SYPKOCTXGZRPFSNEDYHTBNIAQYPCUROHMAOENQUFQXVWGRNUJGVXIFPBETXNODHRSSZMGBVTNHLYUTTZXKENLUQSWLWMRAWUYBCFJLFUCEIRKEJRAMBOXKTZJCFASPDGCTWGKEQKHJGVXZCLKBIZDBOHHUEJTDQFIVIUXAOKDCSKSCMEFYJDLXOAPNERORDHWPVMYDHG"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexPlan #0", msg == *msg_d); + test.boolean("QueryEntityParameters #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20626,20 +23255,22 @@ main(void) } { - IMC::TrexPlan msg; - msg.setTimeStamp(0.562376947946); - msg.setSource(29527U); - msg.setSourceEntity(168U); - msg.setDestination(7847U); - msg.setDestinationEntity(168U); - msg.reactor.assign("IKSTQVNMYLYCAOYRADDGKRLEXDVTVPJIUHMQKWXGZAZWVBKMPZNXMOMBIELYVFLQJHPRNHPONJJUSOVWQMCDUJZBRNGOUXGSPFYHROCLXTDWMQRVMTTIRZYCFYOITZPSTZMTBJWYKIEJ"); + IMC::QueryEntityParameters msg; + msg.setTimeStamp(0.9806198922661449); + msg.setSource(47893U); + msg.setSourceEntity(177U); + msg.setDestination(16383U); + msg.setDestinationEntity(181U); + msg.name.assign("ZAENHCUYJISBCYGKUAWCRJWRRHTHPFMOBPXHYMDXUHLIMKZRNGAZSJSLDLATVZWVSRWVMKNOKFTOVFSDNDBUHGLLZSEIXCGSQQIXDTUXNHSSYKGMPCZPCHODOWQUQFDVA"); + msg.visibility.assign("MEPZMLGLKRICACSYHRFSQZPXBFVWWUZRLFTAQFTPEEMVDPNYOCBMBCYPNS"); + msg.scope.assign("OHPEEGBMRLWYKGVUEMQPRSZRXTMAPCACFSACGCLYSWNORXHNNKCKUKFSPQYLSGLNNZNWUWHTXAFVHDBOZRLIAMZ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexPlan #1", msg == *msg_d); + test.boolean("QueryEntityParameters #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20650,20 +23281,22 @@ main(void) } { - IMC::TrexPlan msg; - msg.setTimeStamp(0.542780757538); - msg.setSource(49840U); - msg.setSourceEntity(5U); - msg.setDestination(31033U); - msg.setDestinationEntity(130U); - msg.reactor.assign("JHAZLUDSXAPCVXKBNWMJNQLBJIEZOFEZGDDJNHZRKAKREXGDXVUWENTFUQIDHIXIUJCMPZQYGVHO"); + IMC::QueryEntityParameters msg; + msg.setTimeStamp(0.9280401440229031); + msg.setSource(2834U); + msg.setSourceEntity(111U); + msg.setDestination(15456U); + msg.setDestinationEntity(36U); + msg.name.assign("VQFZCIRNJBOQVNWEVCQYRXILUOUJENZOPIVFXTRELDKSRFLSHOORIVGNMKPDLTAMENJKVDYMDKMMUCQRCNKUPCRWYHHJLZZSWBZPZAZUMVFONMVFADJYJRGYWWDPJZJWATWSAEWDMKYBSBCKH"); + msg.visibility.assign("QQQGYSHNSZXAYFYSIOMTAMCOQHEUDRXCAYGKUBPHBYWMIMKWLXTAMHOQTDOAVURNJGZJIALGAGLJXFFIULQIBZVAXGVQSYFIFDJWTPCYEBEZKAVLERLBCDOWSRMNTEWBPBYKVLGDFCXFQKOFNDLFEQWPAYOJRHZPEEXXUUZVPRIRGURNNKBPGMZINHIQNBRCKRSTCMCSIHWTVYOEDNBWUOUHSTJGEZPDKVCMSJVKT"); + msg.scope.assign("OWXUQIMOTZOSZOJCCCQAWGJDKNLKCLTPZKXGLJVPNKV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("TrexPlan #2", msg == *msg_d); + test.boolean("QueryEntityParameters #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20674,21 +23307,20 @@ main(void) } { - IMC::Event msg; - msg.setTimeStamp(0.327665823326); - msg.setSource(44560U); - msg.setSourceEntity(36U); - msg.setDestination(28240U); - msg.setDestinationEntity(217U); - msg.topic.assign("AEVNSRYLKRUGGEFWGLAAAHMIDNWQCTKHVDPYQXOBDKUMIYSBARKJUCTYFDDZYIVAFGAJAVDTJUUEZRZLKWGWMPQIEXMUJLX"); - msg.data.assign("JCPBIFGOJDTGMYKOBXLIZPSHXJVCQKEINMIKZFPDBDSPXHOKHSCFEKMXRRUAPXGWGDIBRFJQPHSH"); + IMC::SetEntityParameters msg; + msg.setTimeStamp(0.8640272084708024); + msg.setSource(63804U); + msg.setSourceEntity(135U); + msg.setDestination(52673U); + msg.setDestinationEntity(39U); + msg.name.assign("FWKQJUYBKXNZFMCVHNMRTEJULJBNFJCACFRPSVDMKL"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Event #0", msg == *msg_d); + test.boolean("SetEntityParameters #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20699,21 +23331,24 @@ main(void) } { - IMC::Event msg; - msg.setTimeStamp(0.271268997063); - msg.setSource(4023U); - msg.setSourceEntity(198U); - msg.setDestination(5649U); - msg.setDestinationEntity(232U); - msg.topic.assign("PLHWQNQRJUAFISVLEXNOEFNPZNBBWASBGJEVISGBMBTUJGCYVLLJPYEJXCFFRTVCDCPCMFHIRFYDHXUEUHPKDXAUTWNNSMBZRXPMMXOBKOIQPZKVNEJQUNDDGUKRSJEQWG"); - msg.data.assign("HCCQHDUZVISADWOXAWBBDMFTAHJLTONJKTZGBEOYVLJXMDZGNYGIRTPYNNHVHVDLXMYPWTICQYDPEWFZNWKNLWOEXZSFUPSIAQBZLRXRGTMDPOICEMISUKQMSGLHQXAMFXQEZWZEGEYMJFRJRORUFFWXIMBRDMYHGQUBOAKWKCSCCIOLICKUSETYAUYPZVXQXKQHTSVEJLRCJDUFBTKNHVQBNPKGRYCBLTIKFAZVWGJ"); + IMC::SetEntityParameters msg; + msg.setTimeStamp(0.009664640224232746); + msg.setSource(8626U); + msg.setSourceEntity(66U); + msg.setDestination(60036U); + msg.setDestinationEntity(7U); + msg.name.assign("SLMPREFYSKUYYCRCCFOIBTCFNHPJWJSAZKYKVIDZRMOPSNPHOSKRHPBGZNJQAIMJTQGSARHNLXZLTCKMJHKDAAHFYWDNCQBDQQHOITMDVBCDFXEZUD"); + IMC::EntityParameter tmp_msg_0; + tmp_msg_0.name.assign("WIBTGACEUQJKMIOAKYFJJCUBLVNWOYLLGBPLTLKQSAAUQTWDCLCSVEQXTXAQIZMWXZUHVMLZVHEORWZVNPYNWYJEDFMFYNCFEDAIPRYHHSKPTHKVSPIWINSMXZFOZYQTPJHOJJAGJEVQKUYCLQIJXNSTUMNDDNNGXBTRPVC"); + tmp_msg_0.value.assign("QPBGMBWAGXUQURJTAVDGJWFHASLKTKYIPJJVHRFEZOHQWQIOTFWLIYLJPFDEMOSRBDCBCRYBEZEGICTBKERVLWOFKMYNVLXLBNBWLQKITJAZAXZGCSZEOMVQSZFKFUYICQWUZJCCPNTTRNRHYZGJTVSMEXXORUUSDKXGADVRXMWAIOAHHZLNBDLPFTGDKV"); + msg.params.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Event #1", msg == *msg_d); + test.boolean("SetEntityParameters #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20724,21 +23359,24 @@ main(void) } { - IMC::Event msg; - msg.setTimeStamp(0.141437972257); - msg.setSource(11194U); - msg.setSourceEntity(106U); - msg.setDestination(51039U); - msg.setDestinationEntity(25U); - msg.topic.assign("XSEEITOJCULBILZAZWXMXOXPPZTIGYWATTNFOGMBCBDJJIYLZXNMDMDXXHZTGPLJIBFGWUDOEJHHBKRRKFFYAMQOPFKCCPCILZTYXSTVUAABGIVKDGFDESIYCEJNMTSRSZQR"); - msg.data.assign("EESDWIQJLKOBRMZSPVRIZSCQQMWWDGIEVJBVKXBULBYXAGAMIZQLPQFISAHGTYNHGRMMUGDYNVXHTGNJQHLOSFNYPLCDRNURWMOXJRKZSBZKXEJZQFKBMADHWCQDFKAOLINTFUYUYATXZFCCZKOCEZGWXXNKVVBFSFVYRXFONMPMIAOBTSWUXHETHTYTVCBOVAKJJINLRAWZBUQ"); + IMC::SetEntityParameters msg; + msg.setTimeStamp(0.815765079070906); + msg.setSource(11218U); + msg.setSourceEntity(132U); + msg.setDestination(64470U); + msg.setDestinationEntity(108U); + msg.name.assign("SXUKNHPITJTEABAJYICDLVCPFXHOOXEJWFIHARDNSBTTIBCIBCMGZHDMFJPCTIKBPABOJBIARNUKWGORHGQWJYETQADLJFJXUPDMODCZWLNE"); + IMC::EntityParameter tmp_msg_0; + tmp_msg_0.name.assign("IHZODWBNFLHPSVMCVBWGFOMWJRKSCRGLFYLPMEZUCORCTHMCDBHSCQURNIITAOKLCNJOFUWFVBUNVQMOBXLHTUDDBXLOVZXIBHXKJAWSGKXWSPNKVYPTMXMESQDVUCWKTQIYCGTTAKWRNGDZIAGMERHOXAHEXGIYTLQNFIZYSVJAIJJGYZVRXFCWLPFIZYQYANUZULPBHVJHYFJTTPQONKEQESDKRWPQFBD"); + tmp_msg_0.value.assign("WAERIIBUWJEBXQCIPANDQIOGGWHDAXOSDEBBVRPMMHSVFF"); + msg.params.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Event #2", msg == *msg_d); + test.boolean("SetEntityParameters #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20749,22 +23387,20 @@ main(void) } { - IMC::CompressedImage msg; - msg.setTimeStamp(0.248744110055); - msg.setSource(62736U); - msg.setSourceEntity(6U); - msg.setDestination(705U); - msg.setDestinationEntity(113U); - msg.frameid = 241U; - const char tmp_msg_0[] = {62, -28, 25, 79, -58, 38, 114, 55, -123, 54, -38, 31, 25, -89, -64, -49, -18, 9, 42, -37, -10, 13, -38, 38, -10, -54, 67, 18, 0, 51, 110, 94, -62, -30, 104, 66, -50, -10, -110, -50, -107, -34, 66, -123, 26, 95, 46, 100, -65, 23, -121, 16, 78, 103, 12, -117, -81, -3, -18, 99, -9, -74, -15, -43, -36, 19, -94, -11, 68, -66, -74, 116, 71, -88, -32, -107, -13, -114, 58, -119, 39, -11, 20, -76, 93, 96, 85, 85, -21, -101, 106, 90, 113, 75, 125}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::SaveEntityParameters msg; + msg.setTimeStamp(0.8856336016218564); + msg.setSource(56955U); + msg.setSourceEntity(99U); + msg.setDestination(65246U); + msg.setDestinationEntity(110U); + msg.name.assign("RIPBCHNHGDNCBWAUZREKGWRKCLLNBUOUPXLRDTKKCOUSEVOZOSMEZUTQQXIQSQWTWYMFFLNOSNAPNXJPNXNRVIZHAFSHQDCMDYGMWXLQGEEWMKFFARZPNSOATKBHFODQEZVLXKVHFBMAJTXFMJDUVGYAJIAVGULYOAPXASX"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CompressedImage #0", msg == *msg_d); + test.boolean("SaveEntityParameters #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20775,22 +23411,20 @@ main(void) } { - IMC::CompressedImage msg; - msg.setTimeStamp(0.57647879185); - msg.setSource(16191U); - msg.setSourceEntity(46U); - msg.setDestination(5733U); - msg.setDestinationEntity(203U); - msg.frameid = 154U; - const char tmp_msg_0[] = {51, 38, -96, -89, 81, 6, -107, -125, 0, -105, 65, -77, 40, -33, 49, 61, -77, -25, 90, -108, 58, 73, -46, 3, -68, 106, 2, -47, 67, -101, 88, -127, -2, 2, -51, -123, 28, 76, -112, -98, 45, 51, -87, -80, -26, -73, -37, -116, -90, -84, -39, 49, -41, -55, -6, 109, -122, 31, -37, 25, 29, -115, -31, 82, 30, 8, -22, 48, 23, -95, -47, -11, 37, 32, 78, 18, 108, 88, 15, 14, 80, -126, -73, -52, 96, -113, 105, -44, -52, 105, -4, -118, -109, -120, 83, 40, 39, 53, 44, -23, -43, 6, 96, 101, 117, 61, 70, -48, -85, 116, -1, 122, 23, 97, 108, 51, -102, 2, -53, -2, -30, -105, 102, 35, -54, -35, -98, -124, -76, -126, 49, 43, 84, 55, -82, 43, 1, -13, 62, -63, 71, 115, -80, -117, -34, -108, 66, 19, 77, -53, -105, -67, -85, -57, -56, -108, -117, 55, -98, -37, -7, -79, 24}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::SaveEntityParameters msg; + msg.setTimeStamp(0.899410404092009); + msg.setSource(6937U); + msg.setSourceEntity(97U); + msg.setDestination(1271U); + msg.setDestinationEntity(83U); + msg.name.assign("NYDNUSXXKGXNGKZMYDQZMDYOVNGMASWWXHOAXCPVFVCVROWTEMEVBGMIJIUFFGKNUMJJVLXTJXGPHANSPYKYAOPZEIZHOGHSYIKSLBTTGPDQCHTLVQBHLXFIMCNJWJPBPUKOQMFYRJZVQEUKBFIEWEICHEKPHYBWRTBPQGABUQBLRAWJMIBCLUFROWXNZLSEDQTKGAFDHCEFWUAYDHZDVSQKWMEQSZCDZYT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CompressedImage #1", msg == *msg_d); + test.boolean("SaveEntityParameters #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20801,22 +23435,20 @@ main(void) } { - IMC::CompressedImage msg; - msg.setTimeStamp(0.653303569596); - msg.setSource(23116U); - msg.setSourceEntity(83U); - msg.setDestination(48932U); - msg.setDestinationEntity(251U); - msg.frameid = 175U; - const char tmp_msg_0[] = {14, -79, -27, 47, 22, 13, 40, -127, 90, -125, 76, 120, -61, -21, 68, -99, -60, 125, -83, -73, 31, 28, 79, -47, -32, 85, -12, -46, -47, -1, 101, 58, 1, 56, 19, -54, -32, 42, -95, -20, -18, -121, -82, 61, -16, -89, -62, -16, -81, 55, -106, -83, 125, -30, 7, 58, 46, 88, -62, 99, -121, -14, -106, 125, 28, -102, 57, 90, 20, -39, -111, -88, 104, -37, -24, 46, 95, -92, -114, 62, -120, 71, 49, -105, -52, -69, -101, -37, 49, 112, -46, 83, 26, -102, -39, 57, 100, -61, 88, 97, 107, 94, -122, -96, 70, -94, -81, 57, 8, -61, -29, 13, 73, -116, 71, 40, 45, -42, -125, -89, -73, 9, -49, 103, -86, 95, -58, -56, -90, 123, -39, 63, 49, -7, -100, 35, -31, 89, -78, -105, -49, 5, -90, 28, -12, 52, 93, -27, 18, 83, 105, 63, -70, -38, 97, 27, -33, -71, 67, -48, 88, 11, 64, 94, -46, -120, 91, -74, 106, -122, -2, 66, -1, 82, -84, -42, 3, -15, -97, -38, -94, -81, -113, -5, 71}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::SaveEntityParameters msg; + msg.setTimeStamp(0.4208258251292558); + msg.setSource(39790U); + msg.setSourceEntity(175U); + msg.setDestination(56680U); + msg.setDestinationEntity(165U); + msg.name.assign("ZKUGWHBZRYQNPJLOWLXWLIEDQZGCTUJGUALQOBEKFELPSVGFSMKEGOIDSEANAAQYTIYOZBAQYOKFURGYSBAEJMFTTSDVRZOSFUXKNLHHDNLMOXWANPMDOSXPKTKMYZBPMWTPVQCCPGKWRFUMRWNMXZYGKITFYLTLQRTXJXXOCLPZIWBVAEPIUCP"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CompressedImage #2", msg == *msg_d); + test.boolean("SaveEntityParameters #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20827,23 +23459,20 @@ main(void) } { - IMC::ImageTxSettings msg; - msg.setTimeStamp(0.887114996947); - msg.setSource(24928U); - msg.setSourceEntity(22U); - msg.setDestination(35900U); - msg.setDestinationEntity(180U); - msg.fps = 78U; - msg.quality = 89U; - msg.reps = 152U; - msg.tsize = 28U; + IMC::CreateSession msg; + msg.setTimeStamp(0.15922802828382077); + msg.setSource(32033U); + msg.setSourceEntity(39U); + msg.setDestination(63069U); + msg.setDestinationEntity(29U); + msg.timeout = 773271541U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ImageTxSettings #0", msg == *msg_d); + test.boolean("CreateSession #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20854,23 +23483,20 @@ main(void) } { - IMC::ImageTxSettings msg; - msg.setTimeStamp(0.66159511712); - msg.setSource(25747U); - msg.setSourceEntity(150U); - msg.setDestination(3652U); - msg.setDestinationEntity(70U); - msg.fps = 118U; - msg.quality = 195U; - msg.reps = 229U; - msg.tsize = 209U; + IMC::CreateSession msg; + msg.setTimeStamp(0.4165766887591231); + msg.setSource(36511U); + msg.setSourceEntity(153U); + msg.setDestination(18111U); + msg.setDestinationEntity(32U); + msg.timeout = 4229020065U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ImageTxSettings #1", msg == *msg_d); + test.boolean("CreateSession #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20881,23 +23507,20 @@ main(void) } { - IMC::ImageTxSettings msg; - msg.setTimeStamp(0.774372658616); - msg.setSource(38157U); - msg.setSourceEntity(211U); - msg.setDestination(6916U); - msg.setDestinationEntity(211U); - msg.fps = 1U; - msg.quality = 138U; - msg.reps = 188U; - msg.tsize = 54U; + IMC::CreateSession msg; + msg.setTimeStamp(0.15731534081169507); + msg.setSource(61037U); + msg.setSourceEntity(69U); + msg.setDestination(46243U); + msg.setDestinationEntity(54U); + msg.timeout = 3632575672U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ImageTxSettings #2", msg == *msg_d); + test.boolean("CreateSession #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20908,24 +23531,20 @@ main(void) } { - IMC::RemoteState msg; - msg.setTimeStamp(0.338473252671); - msg.setSource(56136U); - msg.setSourceEntity(51U); - msg.setDestination(26854U); - msg.setDestinationEntity(35U); - msg.lat = 0.806861599152; - msg.lon = 0.182067785492; - msg.depth = 24U; - msg.speed = 0.239924446673; - msg.psi = 0.508178343267; + IMC::CloseSession msg; + msg.setTimeStamp(0.8216266252850603); + msg.setSource(41595U); + msg.setSourceEntity(187U); + msg.setDestination(39983U); + msg.setDestinationEntity(60U); + msg.sessid = 24947789U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteState #0", msg == *msg_d); + test.boolean("CloseSession #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20936,24 +23555,20 @@ main(void) } { - IMC::RemoteState msg; - msg.setTimeStamp(0.724429431438); - msg.setSource(61946U); - msg.setSourceEntity(2U); - msg.setDestination(51713U); - msg.setDestinationEntity(19U); - msg.lat = 0.251163306725; - msg.lon = 0.523161555681; - msg.depth = 21U; - msg.speed = 0.587925350906; - msg.psi = 0.761639217679; + IMC::CloseSession msg; + msg.setTimeStamp(0.6898639887424276); + msg.setSource(40041U); + msg.setSourceEntity(240U); + msg.setDestination(17834U); + msg.setDestinationEntity(128U); + msg.sessid = 4048653080U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteState #1", msg == *msg_d); + test.boolean("CloseSession #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20964,24 +23579,20 @@ main(void) } { - IMC::RemoteState msg; - msg.setTimeStamp(0.248404573159); - msg.setSource(768U); - msg.setSourceEntity(102U); - msg.setDestination(18051U); - msg.setDestinationEntity(36U); - msg.lat = 0.142811448128; - msg.lon = 0.415559411187; - msg.depth = 107U; - msg.speed = 0.200061677556; - msg.psi = 0.415720663566; + IMC::CloseSession msg; + msg.setTimeStamp(0.14051814533876028); + msg.setSource(14083U); + msg.setSourceEntity(197U); + msg.setDestination(37111U); + msg.setDestinationEntity(163U); + msg.sessid = 1495243667U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("RemoteState #2", msg == *msg_d); + test.boolean("CloseSession #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -20992,26 +23603,21 @@ main(void) } { - IMC::Target msg; - msg.setTimeStamp(0.326381188755); - msg.setSource(17030U); - msg.setSourceEntity(142U); - msg.setDestination(16424U); - msg.setDestinationEntity(186U); - msg.label.assign("GHHHBZGVWFGFUVSCYKBLFUXEUTAYGGDMESARRYGCOCBYZIEAXCIDOGWMCBLDKBQBLSYUZZOIXXJPFJBWDOKPIQTNPWATCTNN"); - msg.lat = 0.262085418616; - msg.lon = 0.255827346152; - msg.z = 0.879172514802; - msg.z_units = 254U; - msg.cog = 0.043481375145; - msg.sog = 0.471444470304; + IMC::SessionSubscription msg; + msg.setTimeStamp(0.3998422223284561); + msg.setSource(6506U); + msg.setSourceEntity(82U); + msg.setDestination(55214U); + msg.setDestinationEntity(230U); + msg.sessid = 290240069U; + msg.messages.assign("XQWKVJDZSJBIQMTWDBESGUYOQXUIZHXJELGFTSBOHQOUMMKDSCEBIZRILGINCFKNLFGEEXVDVJXUTFBPHQKFNJILDMUTSAGGCRVNIVTYAORWMCNCYVMLMPXRNCIAEWD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Target #0", msg == *msg_d); + test.boolean("SessionSubscription #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21022,26 +23628,21 @@ main(void) } { - IMC::Target msg; - msg.setTimeStamp(0.605139452933); - msg.setSource(36543U); - msg.setSourceEntity(133U); - msg.setDestination(23088U); - msg.setDestinationEntity(168U); - msg.label.assign("AVOKHCIOHNBUFDWVXKDYLHUFCCAPKEYWMWNGPQNJFCNQZJHXBAVEDMWPOJLLRACPTLARQBYSKJLYGPGXKECTRPQODBHWVDEVSLAZCQTJSYNFKRSAGUYQRUKYVJGGSTAZZCGDQIJTXHOXNCTWFWDQKEBURDIOIFLTVIEUMLEZROHTRMCPZONVPFRNBTAWPIRJIESGMEHMIGISQBWHNFQONVEDDUBXUUIPLYYYWXXFJKSZMSHMFKXGVZLU"); - msg.lat = 0.683111093854; - msg.lon = 0.264263314913; - msg.z = 0.556906775729; - msg.z_units = 49U; - msg.cog = 0.54357992501; - msg.sog = 0.449338089936; + IMC::SessionSubscription msg; + msg.setTimeStamp(0.5729324076420017); + msg.setSource(53334U); + msg.setSourceEntity(124U); + msg.setDestination(48808U); + msg.setDestinationEntity(40U); + msg.sessid = 2781645730U; + msg.messages.assign("YEOAXKLGNWBEIZMKRNW"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Target #1", msg == *msg_d); + test.boolean("SessionSubscription #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21052,26 +23653,21 @@ main(void) } { - IMC::Target msg; - msg.setTimeStamp(0.335232287515); - msg.setSource(25716U); - msg.setSourceEntity(192U); - msg.setDestination(23539U); - msg.setDestinationEntity(77U); - msg.label.assign("VAIGSNUPMWZQJUTYQULKLJGIBEXTZHPSPNTZMMAPXGRECKPSMWQZQHOJCJOBAERDILGLVBFZFOXJUEGOWHTYVKNKQCWQIPJRATBVRJUVGPDMQNLCWKRIIIFNAGXHGSESWDIUSBZHMSATJCFDQXTWMWRJREFEVLDZQL"); - msg.lat = 0.800700209428; - msg.lon = 0.671255144728; - msg.z = 0.642317186885; - msg.z_units = 47U; - msg.cog = 0.839665777132; - msg.sog = 0.391674097217; + IMC::SessionSubscription msg; + msg.setTimeStamp(0.1140746794634313); + msg.setSource(9534U); + msg.setSourceEntity(103U); + msg.setDestination(35090U); + msg.setDestinationEntity(110U); + msg.sessid = 857450971U; + msg.messages.assign("SBMJIFNOPPBXQUAYGSCKPOGLDDFOLOBMCRARSYMZAEIOCAKGSPVIDEFATCBFYECFCMELIIKKHWDHTOHJXGGLNXMIMQWZEGLGXXDTBPKKJMJHQZJYNEQFSBZLTEX"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Target #2", msg == *msg_d); + test.boolean("SessionSubscription #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21082,21 +23678,20 @@ main(void) } { - IMC::EntityParameter msg; - msg.setTimeStamp(0.321049938837); - msg.setSource(45443U); - msg.setSourceEntity(14U); - msg.setDestination(5145U); - msg.setDestinationEntity(222U); - msg.name.assign("EWQEYWSNUQ"); - msg.value.assign("KWJXUZJFWKRYCEJTFRRUUURTNERDYZDNISGTYNOWGWWAXNVQZZVQEPMIBTRLSLMQDGXNFIIBKXHJYIOPSNBWRUDDHQKKQBNYLAHLPSTQKKSEIMKSO"); + IMC::SessionKeepAlive msg; + msg.setTimeStamp(0.5294262180428639); + msg.setSource(8338U); + msg.setSourceEntity(96U); + msg.setDestination(33300U); + msg.setDestinationEntity(253U); + msg.sessid = 1709102626U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityParameter #0", msg == *msg_d); + test.boolean("SessionKeepAlive #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21107,21 +23702,20 @@ main(void) } { - IMC::EntityParameter msg; - msg.setTimeStamp(0.173401014759); - msg.setSource(7895U); - msg.setSourceEntity(83U); - msg.setDestination(43960U); - msg.setDestinationEntity(35U); - msg.name.assign("UNBLWFNYXAVVSKFIXJQDMUUULUROSBTTHVKADVJOGDCXLYJGBBGQMKILBYQYRSYYDEOPNXIHCMZGSPVIVKHPDUREZBNKJITCFSTKFGDUZZNMJAFYCSWCIVUINQGWERELFNHZWXRMHFLYUZMPCLMMHFVPKXCEGXPEDJPMJBHZQGOIOKOXDOKEXRBGRRWOWQSQSLPJTPWHSM"); - msg.value.assign("OMAMFPIXXIDZKNTDZORRQSTENDIDCFPZGKSWPFTTWOMULPIAGWJTLMSXXHSLRAJCKDYQGFUZKFYXDWJBVLLERYTKLYBNWOOFMNQFBNZKBSXUCBDZVUHCHNPZGLMTJJNOQHXCEYQVQCRYIENJSUDEGEOAAUTAKHPWDBAQVGYPXQGGCAFEVYPJSMVQOIHAIMIJ"); + IMC::SessionKeepAlive msg; + msg.setTimeStamp(0.43683948655793103); + msg.setSource(31043U); + msg.setSourceEntity(114U); + msg.setDestination(10499U); + msg.setDestinationEntity(9U); + msg.sessid = 1136453585U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityParameter #1", msg == *msg_d); + test.boolean("SessionKeepAlive #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21132,21 +23726,20 @@ main(void) } { - IMC::EntityParameter msg; - msg.setTimeStamp(0.0726380724355); - msg.setSource(28358U); - msg.setSourceEntity(251U); - msg.setDestination(30123U); - msg.setDestinationEntity(217U); - msg.name.assign("OIJAYOMOLKFEZBJBOSRNQVWSRKNPCAFDCVZLB"); - msg.value.assign("OPJDZRZRHEZSLDUGPEHHWWJMWGNJCBBEDOMCOALZMKSSTKIZXJJHONYGSGZLPEVMYGFAXUBXLTSRWPSTVAEIMFSMSXJCMERRWENVJGNJABIGFRGQULZKPBNULFVQRDDBTVMNRCUGCQYDFRZYOYAFTYKXKPWFYDAIKEZPIWXJWLOIHXUTLTSXMPGCHBPUHIV"); + IMC::SessionKeepAlive msg; + msg.setTimeStamp(0.08548570579791526); + msg.setSource(51690U); + msg.setSourceEntity(172U); + msg.setDestination(24699U); + msg.setDestinationEntity(155U); + msg.sessid = 1918010976U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityParameter #2", msg == *msg_d); + test.boolean("SessionKeepAlive #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21157,24 +23750,21 @@ main(void) } { - IMC::EntityParameters msg; - msg.setTimeStamp(0.672389716721); - msg.setSource(40544U); + IMC::SessionStatus msg; + msg.setTimeStamp(0.0255067344609774); + msg.setSource(51325U); msg.setSourceEntity(156U); - msg.setDestination(38094U); - msg.setDestinationEntity(98U); - msg.name.assign("MQMXWCRSFMRBZJRFUFJUTYGPJNXJEMKSQOSCZZVAVDAHTYECJENLVTDONOAMTEBOHHXEEMBGJKKVYFTFLCIEKUZOQGDMBHPZZFUQXXQVDRXCKNZYTCJWYBXYISSLKRQLAWILABWWLNMPZGNWIXFOYRDHLIDHPBRYADBKHTGSPHTPWSBWLKPIACWPQFGCETQFLRSTJVGOOMFPNIURMSVGLAIARUKJDYCOOQEUUZD"); - IMC::EntityParameter tmp_msg_0; - tmp_msg_0.name.assign("SRQZLVFXEIGHUIVKKUCPPKBTCYIVEBZYKTOWSNMKCTWMIAJHHVDENJOTNEAQAUCDUAZQQEKFLMLOJXDCPZPWMMLSREYNCXRGZZPZBYTFFRNPC"); - tmp_msg_0.value.assign("OWDKJOKVBOYQFBWJYVEUKOEIGQEWOGWZHMVUXHCHNYTQADUAGOZSBHLTBCLUSNPHWCBPRTEIRCYZWZUYPKPGYPKINDTQGLUUPTCKRWLBRMLXRQNKZJJFQBGZIPSGNQCNNVHHXEAUZFKLYXSZRALMHFAYIKDEFTAISWIBDGBRFPJDANYMMJXYCMZDUAWLORQJXDNQIXCMLJKAWLRVFRDZCFVIOJTHTSSXNJEFTEOFMEOSBXXC"); - msg.params.push_back(tmp_msg_0); + msg.setDestination(15332U); + msg.setDestinationEntity(246U); + msg.sessid = 2153428306U; + msg.status = 67U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityParameters #0", msg == *msg_d); + test.boolean("SessionStatus #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21185,24 +23775,21 @@ main(void) } { - IMC::EntityParameters msg; - msg.setTimeStamp(0.393443790069); - msg.setSource(31333U); - msg.setSourceEntity(140U); - msg.setDestination(48075U); - msg.setDestinationEntity(220U); - msg.name.assign("NRERHWWKPQJJFGUBEARMLCAGRXVIVMEPTFIZOXEYDTLUJCPKEGTXPCIDKCWJBGWYKFJOCZSYMQOHQMZUITLRNZYLNQIJOUGFIZRRENABJABMSCVQZQAOCEHOVDWXBWSIALAVHSJNVTLDUDOXDPGHZMNOHHUSKXGPTFITPKSQUYRXYNAQZUOEBKXZDBJXVLWYZBJCLYQMBNQTGMRDEHNVKFWLYPVCTXWFO"); - IMC::EntityParameter tmp_msg_0; - tmp_msg_0.name.assign("FCNSYNVEYZOFNOBSLOCFZGWXPYSREGQOGUSMWKRPSXHJCCMJZNMVGLEHPWDWRCYCHHAGTMGCHQAAUNRDFRJKSNSUPGXBUWETLKIJFEOQGUPWMQETLYADZRBXTHYVVBFMLHNJFQXCNZIDDLKDKHLVGXDOBTPKJZCVRMWZVYIBZBMVJM"); - tmp_msg_0.value.assign("RSJSMZHAFPNDQJAMZZBCGOPAHAFIBXBJATHRNOWGSKWLQYCIZVVPLVRTDARUEMEPPONAODMWQTDUKOCYENPGFJTDYHZNVGTFQCFUCYKHGJNQBFLBOJVKXVRIFIHMPPHCVMTTJKIKJEWYEDNZWWAUZNMVIBMLXSJLDZOXZKQKJQYSEMSXXEMAORLVQPFIXFQBLEFWREGAH"); - msg.params.push_back(tmp_msg_0); + IMC::SessionStatus msg; + msg.setTimeStamp(0.08497235720870933); + msg.setSource(20208U); + msg.setSourceEntity(137U); + msg.setDestination(30786U); + msg.setDestinationEntity(207U); + msg.sessid = 2849472934U; + msg.status = 53U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityParameters #1", msg == *msg_d); + test.boolean("SessionStatus #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21213,20 +23800,21 @@ main(void) } { - IMC::EntityParameters msg; - msg.setTimeStamp(0.402137484965); - msg.setSource(321U); - msg.setSourceEntity(210U); - msg.setDestination(35890U); - msg.setDestinationEntity(119U); - msg.name.assign("ZNMPLQJYBPDIJMCDID"); + IMC::SessionStatus msg; + msg.setTimeStamp(0.06246740972996834); + msg.setSource(12177U); + msg.setSourceEntity(63U); + msg.setDestination(16231U); + msg.setDestinationEntity(172U); + msg.sessid = 424603508U; + msg.status = 52U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("EntityParameters #2", msg == *msg_d); + test.boolean("SessionStatus #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21237,22 +23825,20 @@ main(void) } { - IMC::QueryEntityParameters msg; - msg.setTimeStamp(0.92874138437); - msg.setSource(45184U); - msg.setSourceEntity(18U); - msg.setDestination(63693U); - msg.setDestinationEntity(1U); - msg.name.assign("OIWPWLTUVHDFPDLFVSYBQBNNQNXGJHLCRQIQFCLPGMBKQKOJKFZCVKNBGQXCXTMMPAVMNJKDPFTVYGIHXFMSUFSJSELKLUMLXOEUUMUFOLDCBERQAAZMEGZPKECBEZYKZEDWWYYAHZMLUOJBVPXVLQPYSNTTOCYZYJQHRVRXCBTRIZHSMWDCOJUODWWEDNIEPXUIAIRNBOSNHHJKNRJJHR"); - msg.visibility.assign("UZXVPYNLYPXNLWINYZ"); - msg.scope.assign("IGRRCIUSAQMFSBFNDWNABZKMHYZXLVWBCQEZZECRIXLBMRWMBXGVKYVFIHQIWGDAKCDJQNMESOHTEPOZTFBWJGAIJZLYAZXXRUDBXBYDFODTXWRTVUHWVFSGNUPQEFNYOLCYPTVLYPRRHQHGIUMNSUPICASLRSDCCZKBMOEAHUKTUQBZTJTRZUKFCIUQKVHMSGTHVJDEOFWDLLKOKNWJACPMOXMNJNJNVJGQKHPEPPY"); + IMC::PushEntityParameters msg; + msg.setTimeStamp(0.7326774888111637); + msg.setSource(3484U); + msg.setSourceEntity(75U); + msg.setDestination(43327U); + msg.setDestinationEntity(213U); + msg.name.assign("VCMPLYOWWFQNHDTJWIAQJXRPVXRFXDHTLSPKVOEFYJQINOZFLGSDCBPXWZVOBKNWCEIYCELPABQQEMWXMFBKHGCSUNJAOPMLDINL"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryEntityParameters #0", msg == *msg_d); + test.boolean("PushEntityParameters #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21263,22 +23849,20 @@ main(void) } { - IMC::QueryEntityParameters msg; - msg.setTimeStamp(0.41716500892); - msg.setSource(31187U); - msg.setSourceEntity(180U); - msg.setDestination(63020U); - msg.setDestinationEntity(169U); - msg.name.assign("MBRPAKAUGCILLFMLKQBNUHPZGVUEXVGWDMJSXSYLYBBICUPRATEEBZUVAYYO"); - msg.visibility.assign("GZJVEJLTMLKRDBKYPTVOTCPNNLZDDCGGRGUIVXIKINILGVNXSZAOGSBVMDGBUCPHTOLPQRYHSWWZSRAAQWPBENMPSJRBSFYAMYTQZZZAJEXDFFLHMCOMMLSUHRFNZPGBLNEUQAIJNYYKDXNZCTONFAKPUEYCDHAMXLQGXVW"); - msg.scope.assign("KLABDLDEDHSMKZPUXXMJMFHJOXPFGHIUGSTIFTYNKCYPJAOPDFLRFEQUFWEYEJMMVHAEHXGHXKWMYVVCOUCHWRGMPZQXKWQNDUDKQRDAEYGPRSELJRKTDOKBMBIIVGVOQZYNZVERXSTDBTSFRHVXXTZASRUMAUNMOJTQGQWJBFZWNWNASACPJLYXZCSWFIIQTLJ"); + IMC::PushEntityParameters msg; + msg.setTimeStamp(0.2859962982651284); + msg.setSource(41559U); + msg.setSourceEntity(42U); + msg.setDestination(59148U); + msg.setDestinationEntity(168U); + msg.name.assign("BIOZRBLKYHUKUCVALCQSGTGOZTVSROEDAYNZYLDKPBMHCMEVTNRMIVSSUBICJFFULQIVIEGICQPLIVGNAUKAWDPFRXDHUOXVJCPTSARVEJTYPWWFLJXMFXWRABZRXMLCEHLABTUWEJHDUWWCHXPZFEHRMQKRYKKLPOKGTXNIIYBHEFMYSPDMXJT"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryEntityParameters #1", msg == *msg_d); + test.boolean("PushEntityParameters #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21289,22 +23873,20 @@ main(void) } { - IMC::QueryEntityParameters msg; - msg.setTimeStamp(0.497948382567); - msg.setSource(59400U); - msg.setSourceEntity(139U); - msg.setDestination(57250U); - msg.setDestinationEntity(197U); - msg.name.assign("IVHZSINOMXDJIHPJJJIVSFRHCTAZQIAPJBRYSKOWEBPTJOAQCUCTKJEKTLGDXVQSTYURUAEEBXSZWEWFIKEFNXFOVRACWMQJCUHXOCOFCZTPIHUNJJLPTXQZQWOCMDNNHYKRUPXPZDAQGDKHIWAUGXSTLMIVDBC"); - msg.visibility.assign("MGMXUTSFFOURGZNSEGBAAVDQCPGZCYLEXWTPWWDEAFGNMDOJUDINGJUXRIMFPTNPBKTOC"); - msg.scope.assign("HTDIXRZPCISJXKWGZSFYOWGYGIMAVNYUZZHMUVNDVHCCDLAULWIVYAZRPLYGOGKOLJLDIUINDATIFSZEMAJGVNSQZMATXWOAPFCXFMAGUKQCDORLHTBSCJRWDXNKZJJWRRHS"); + IMC::PushEntityParameters msg; + msg.setTimeStamp(0.14173524885570654); + msg.setSource(52604U); + msg.setSourceEntity(11U); + msg.setDestination(41923U); + msg.setDestinationEntity(34U); + msg.name.assign("UJKEXZVZRIYXDNZEKLTQAUYHEKXAJTQJOWGGKQOPHAAVXQFAHSAUAJHVMWKZIIBHCDOHERMBCFKEGWICERISCOOSFEFKTGWNZAPAXQRPJUDDUFURGBQNILQNDSBRMPYQLYMOVBPFLCJWCKUZPCSCLNVITLELNDLWZNMBJMJ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("QueryEntityParameters #2", msg == *msg_d); + test.boolean("PushEntityParameters #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21315,24 +23897,20 @@ main(void) } { - IMC::SetEntityParameters msg; - msg.setTimeStamp(0.743122925254); - msg.setSource(21146U); - msg.setSourceEntity(114U); - msg.setDestination(8090U); - msg.setDestinationEntity(171U); - msg.name.assign("NXZRJQFGQJVCADBDVJIILGDBWSGASBXSHBDFRKIGMHNBUTLNLRQQTVUPHVIMOESDXLAGUWVTNZPOVCNFHIHTSBTHLUXCAOFYNDADWCIZKFQTZCMKZEMURBJCTYGJKPOIMEHEQQJXBODUDZJJ"); - IMC::EntityParameter tmp_msg_0; - tmp_msg_0.name.assign("GJDFKVOJHUOCZBQSSCXUUTQZTNWMPSTQUWIFGLRRVSXOYKOVLDUHSKMOMQRTIVYRRDCLMLWODDTUIFAWPXFZEGHGKTQLGNNPMRWTAADLEXCRCNGFLQXEYBEULJKLAGVKJIHRPNCAZWKWJWYANSPRSTBCMLVBPMQGXJINQVKXXNHFBUCMTYFJHCBVONYEEHMNIAYOSTHXWZOUZSAEVQZDZPBVIXJIHGFYGFQKZE"); - tmp_msg_0.value.assign("DPSXQLHOAJJKTNSPCALPLITIBPUMWRNGDHTODNZPZOFKYYLELWOYZDRMKUGMUQJUZLPHTXJYFQNMOFEZTQRZMTJVAGCIWSOVVXYCYQCCCFBEFERDVFRWBBNKIUKDSLUQAFIFWBQPMBHNTSGIDKAMJPVKKSJAZRYCIPXGVRKHWYEBEYI"); - msg.params.push_back(tmp_msg_0); + IMC::PopEntityParameters msg; + msg.setTimeStamp(0.35957501770289335); + msg.setSource(12559U); + msg.setSourceEntity(116U); + msg.setDestination(36060U); + msg.setDestinationEntity(56U); + msg.name.assign("OJNFASUCUNKKJHKAYULOV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetEntityParameters #0", msg == *msg_d); + test.boolean("PopEntityParameters #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21343,24 +23921,20 @@ main(void) } { - IMC::SetEntityParameters msg; - msg.setTimeStamp(0.162821612996); - msg.setSource(23433U); - msg.setSourceEntity(80U); - msg.setDestination(28884U); - msg.setDestinationEntity(0U); - msg.name.assign("JGSONAJDKTVSWHQQDGQGNXAGTERMXRXUKQUHBOJCQSDCFOM"); - IMC::EntityParameter tmp_msg_0; - tmp_msg_0.name.assign("FXZHYMUSMRWLQZHPSYERDHLXAYVZDWWKXJELZOLBAUSBJUCDPJXUDKEPIWTQOTMVOTYKQZUICCVNNEQFCJLWR"); - tmp_msg_0.value.assign("HUKXNKPYQSWVDSRUTBAFQYRDIXOCRAXLXCOOOIHBJVQXHCQPMXHJJVDUCGVRWYWPRHALOTZEEPAYXEFVQFIP"); - msg.params.push_back(tmp_msg_0); + IMC::PopEntityParameters msg; + msg.setTimeStamp(0.8988573113989706); + msg.setSource(45871U); + msg.setSourceEntity(88U); + msg.setDestination(54035U); + msg.setDestinationEntity(210U); + msg.name.assign("UWZVCWGFIYIVNICMEXYFPXYLHMGIIZYKENJHBRXSVLVQCWUBWBAHDPWUVJMRTHPRLLDPBSXGNGSQEGURPMDOHOMPTIUUWFWWBREKMNMFPLESCALUXBQJDWVTDNQEYFIGQELNQRSCVTOSAKFTIRZTZVYOQUAVCHZSADBOKOUIXATWSJZLPKJDXZKEVZCIFYFMTHCJGSTEKDRJELKXCGOMBPQAJGQNYOCQKMBYJKHJARDXHBFHTRFNYODOLUZAPG"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetEntityParameters #1", msg == *msg_d); + test.boolean("PopEntityParameters #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21371,24 +23945,20 @@ main(void) } { - IMC::SetEntityParameters msg; - msg.setTimeStamp(0.549871775876); - msg.setSource(11468U); - msg.setSourceEntity(58U); - msg.setDestination(3871U); - msg.setDestinationEntity(37U); - msg.name.assign("VAVJAAUDDIUAVTAQHGIVHPRFHNBGQWKDHMRSRMCWPLJKFAHXQYYPCLFLBBAYMDDUSOQGKOVFHJDWHRKBMRBDTBRFSSTCIIIWMBFSRTZOXLNSUOOZOJJRKBJPZLCDUUINAXQXPKJSMZUTYJRGLREPBVAVOOPWQXQLMMETGMDCUTKDIKQVHIGHGAZEYTXVMWGLSEPEFEZQILVWOCCWQFGUEXNJNYEYXCZBZYENUSZPGFOHIN"); - IMC::EntityParameter tmp_msg_0; - tmp_msg_0.name.assign("WHXSGXMOYIEJBDKESLXQYVZVTKSBGNSXDAJNJOPAPGHOZDJSAGNZWGRVQUTZNSKCTCLTTTGAAJXRSONBVQMWTRFUYHOMBCWHKYMHXFHECMKOESZKUDIFXEBQILFOBFAVQYQKNGT"); - tmp_msg_0.value.assign("UFBEUFLJXIQEZQXLEFCUZORHDITHSDALVEARRIEJPRWMSRTJJGOCXXKVTXQGNCRIJAPDXIZQPUZCYRNHTTQONSCFEXECLEPBVGJDHYNLEXWYVBWLWMSWHDLPQHHGTKAJA"); - msg.params.push_back(tmp_msg_0); + IMC::PopEntityParameters msg; + msg.setTimeStamp(0.3090388401004579); + msg.setSource(18173U); + msg.setSourceEntity(27U); + msg.setDestination(13178U); + msg.setDestinationEntity(117U); + msg.name.assign("PLIOISWVRMBEUKAGFDLUHFMTZHCUGFQLTZNJEKTSVPOQQMILGNMZBYVDKCHITDYBXNNOSDHNWCIRKKSSFGAEKIYYAECVITGSLXVUGRBVSDZOHAPPREGWTJMFBVYWQALEMXMNKRXWZHJRSSAJTXMDLWONMTXUIJQJVDYHMAJDPHUAROGDENCWFEWHCOIOTZYXBKDWRLXCYHBPWCGPEFEFR"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetEntityParameters #2", msg == *msg_d); + test.boolean("PopEntityParameters #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21399,20 +23969,21 @@ main(void) } { - IMC::SaveEntityParameters msg; - msg.setTimeStamp(0.229076482911); - msg.setSource(64553U); - msg.setSourceEntity(78U); - msg.setDestination(64955U); - msg.setDestinationEntity(201U); - msg.name.assign("AXVJILMHBTAGXZLDDSBSMSNEMPFIFXAXQJCMVRPIQHSIXKMXOZSZRGECMMUOKTHZOAKPMJCRUVMVLAUCGGGWICCZFYBWQIBLVWYUZAIDNNKWEERDFGKBNOYFQDQWZUGAYVFIKHNQHXPFWHWVYVUJKETCEVLXRNFUDTISLPTHBUBYJRXS"); + IMC::IoEvent msg; + msg.setTimeStamp(0.559014544244117); + msg.setSource(16698U); + msg.setSourceEntity(67U); + msg.setDestination(50214U); + msg.setDestinationEntity(215U); + msg.type = 76U; + msg.error.assign("AAPOZSZGWDOAWAHVXFHREHPKKISQKPWXJDVGWBZDCVNESIKWYLHRYUXPECROFZETUMXGMBAFHBRITUSJHMNIAICVPNAJQTNUGRISBGWLJVJJBPLOONECKAUTKNEQLGHFDHYYDRWQNKJYIUUXQRAYDQGFOABNWXQDTYFITCUMLPD"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SaveEntityParameters #0", msg == *msg_d); + test.boolean("IoEvent #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21423,20 +23994,21 @@ main(void) } { - IMC::SaveEntityParameters msg; - msg.setTimeStamp(0.00352923093875); - msg.setSource(45094U); - msg.setSourceEntity(159U); - msg.setDestination(46921U); - msg.setDestinationEntity(0U); - msg.name.assign("EWXRBTKIVCFOIYARZVSOUQYKUVFUBNXFJLMGOODXMHRGBQPLYFUMFRUAUCHPQEBOKNRJNPGU"); + IMC::IoEvent msg; + msg.setTimeStamp(0.9559478822314377); + msg.setSource(6659U); + msg.setSourceEntity(209U); + msg.setDestination(5171U); + msg.setDestinationEntity(203U); + msg.type = 119U; + msg.error.assign("JLBUBDGUTXQFOCKVLZLVCFTYHCAYEWSOTJSSWAC"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SaveEntityParameters #1", msg == *msg_d); + test.boolean("IoEvent #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21447,20 +24019,21 @@ main(void) } { - IMC::SaveEntityParameters msg; - msg.setTimeStamp(0.925823277462); - msg.setSource(20981U); - msg.setSourceEntity(2U); - msg.setDestination(58339U); - msg.setDestinationEntity(95U); - msg.name.assign("YPRAKPFSBRVYUQTWSCKFLSMJZYIKPFYGJOHFRVDFUBTEFAOYXWKNGRIGHTVXBKPLSCVPILWAQNIDOAXEINCGTNMNVMBWKZZRNKLBSXAQFLRJHXUJBXOQIDDUXGJSNWLGGQKHZVMWACYCACHHERWDRWZ"); + IMC::IoEvent msg; + msg.setTimeStamp(0.7656853120411125); + msg.setSource(41510U); + msg.setSourceEntity(170U); + msg.setDestination(53409U); + msg.setDestinationEntity(163U); + msg.type = 89U; + msg.error.assign("NFENJWUMUXLIBLIOQHBYGHYYSOCOQALSFDDTOTKHHKFWGIJFWGINMUWASERQHLNOXAMWBXRLDLIYPLYTZRPPRZAZJGYMXQZWIAXKXFMXGFMNFIUYQSFOJVJBZNZVQCPBWTWPHTDBGRBCYCOHTDK"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SaveEntityParameters #2", msg == *msg_d); + test.boolean("IoEvent #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21471,20 +24044,24 @@ main(void) } { - IMC::CreateSession msg; - msg.setTimeStamp(0.412940338528); - msg.setSource(63026U); - msg.setSourceEntity(37U); - msg.setDestination(40121U); - msg.setDestinationEntity(186U); - msg.timeout = 1623725789U; + IMC::UamTxFrame msg; + msg.setTimeStamp(0.013733411634701986); + msg.setSource(22888U); + msg.setSourceEntity(203U); + msg.setDestination(15091U); + msg.setDestinationEntity(49U); + msg.seq = 50925U; + msg.sys_dst.assign("GMNMLVSWLVUXDJEYEGMUZOVTXURGSOHUKIYIGIUMIPDDYRHEVWBQFOYCJXLAMBNWLHCJCMAXQKNCHUKRHCVOBKKLWHGESFRTMLKILY"); + msg.flags = 149U; + const signed char tmp_msg_0[] = {104, -97, 39, -68, -121, 11, 83, 3, -128, 16, 112, -33, -10, -98, 23, -12, -9, 52, -56, 86, 37, -21, -66, -78, 94, 93, 50, 46, 115, -82, -36, -109, 74, -50, -45, -109, -66, 80, -38, -50, 1, 9, 97, 10, -100, 115, -34, -80, -128, 125, -116, 112, -28, -22, 1, 22, -125, -52, -20, 112, 31, -118, -58, 9, -82, 110, -86, 95, -8, 4, -22, 1, -84, 123, 101, 41, 93, -26, 87, -86, -110, -13, 17, 70, -123, -71, 56, -125, 50, -68, -27, 18, 41, -32, 31, -19, 117, -70, 40, -78, -39, 106, -35, 68, 94, -26, 29, 58, 27, -21, 103, -7, -102, -105, 120, -60, -127, -67, -21, 9, 73, -54, -73, -57, -6, 118, -46, -100}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CreateSession #0", msg == *msg_d); + test.boolean("UamTxFrame #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21495,20 +24072,24 @@ main(void) } { - IMC::CreateSession msg; - msg.setTimeStamp(0.894557693512); - msg.setSource(49078U); - msg.setSourceEntity(186U); - msg.setDestination(22021U); - msg.setDestinationEntity(103U); - msg.timeout = 2547890545U; + IMC::UamTxFrame msg; + msg.setTimeStamp(0.5293702543658314); + msg.setSource(33878U); + msg.setSourceEntity(124U); + msg.setDestination(44030U); + msg.setDestinationEntity(69U); + msg.seq = 55720U; + msg.sys_dst.assign("UGJFDIQNECWDNYZZFCCQVHAVIAMQELDQBTBIYBXNGFLXJGFEFDQZXPEGWWIOQKQAITMHZUPITRMRYRVOLLEOFOOHMMETYNOHDGVTFSZWSCMUWSCKXEIMVRKJJNHMPSXPGGUAUBSTFUSULPKSXJJTDWSLYRGRYMCYVCVONSVYIUDCRRXBZAJQN"); + msg.flags = 50U; + const signed char tmp_msg_0[] = {115, 58, -44, 96, -92, 10, 110, -20, -9, 89, -62, 91, 98, 11, 5}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CreateSession #1", msg == *msg_d); + test.boolean("UamTxFrame #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21519,20 +24100,24 @@ main(void) } { - IMC::CreateSession msg; - msg.setTimeStamp(0.182612353377); - msg.setSource(12236U); - msg.setSourceEntity(93U); - msg.setDestination(54852U); - msg.setDestinationEntity(53U); - msg.timeout = 3427534556U; + IMC::UamTxFrame msg; + msg.setTimeStamp(0.25335186413500155); + msg.setSource(39196U); + msg.setSourceEntity(48U); + msg.setDestination(1003U); + msg.setDestinationEntity(75U); + msg.seq = 36421U; + msg.sys_dst.assign("NYKMWWJRJHCXDCUZICYRKIZBXVBYYUWUQOOJILAFZXNDMGEIAYTISFTKZYMJGARQOZYVKAATOHHTJKGWAWZEVBDMVXWVWRTSNXOUCWEPRKDNWMWIFDMXXEJLOYULHFEZLQDLBGLBCJQKBSTQESUDONHAAOJFEGAKQDEGCPYMPGNBFZIPYIPI"); + msg.flags = 51U; + const signed char tmp_msg_0[] = {-28, 3, 53, -44, -17, 11, 84, -106, 26, -21, -57, -33, 117, -96, -62, 119, -90, -57, 58, -42, -125, 77, -69, 66, -73, 28, 12, -44, 17, 75, 15, -35, 7, -91, -28, -100, -96, -30, 82, -42}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CreateSession #2", msg == *msg_d); + test.boolean("UamTxFrame #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21543,20 +24128,24 @@ main(void) } { - IMC::CloseSession msg; - msg.setTimeStamp(0.415904062475); - msg.setSource(46311U); - msg.setSourceEntity(76U); - msg.setDestination(5013U); - msg.setDestinationEntity(169U); - msg.sessid = 1193071327U; + IMC::UamRxFrame msg; + msg.setTimeStamp(0.6397055664888649); + msg.setSource(63623U); + msg.setSourceEntity(64U); + msg.setDestination(33551U); + msg.setDestinationEntity(205U); + msg.sys_src.assign("CYPMRGYAISYIPNJXACDDHBGUMYICCNIIVQEELGOOYSTMXPWRFDFDEJRNARQPDVOEHTVNNCVRBTHAKDKFLWEPTPGSVSYCQHYOKCITDVI"); + msg.sys_dst.assign("LFVJWOUEGPSZRLCTYDPGLBWKLSHBCNVSIMDPLIWWRDJYOXJINDFJHI"); + msg.flags = 61U; + const signed char tmp_msg_0[] = {90, 73, 40, 122, 79, 63, 32, 1, -2, -103, -114, 78, -116, -95, 55, -21, 62, -6, -115, -19, 35, -1, 105, 107, 84, 79, -68, -30, 54, 55, 81, -70, 117, -124, 72, -42, 5, 2, 37, 87, 114, 86, 19, -26, 77, 91, 33, -81, 126, 79, 71, 62, 79, -45, -98, -76, 10, 88, 29, 42, -117, 69, 104, 49, 75, -8, -71, 27, -49, -109, 31, -16, -14, 37, -99, 69, 77, 32, 8, -33, -77, -16, 9, -17, -32, 42, 70}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CloseSession #0", msg == *msg_d); + test.boolean("UamRxFrame #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21567,20 +24156,24 @@ main(void) } { - IMC::CloseSession msg; - msg.setTimeStamp(0.833037527186); - msg.setSource(36334U); - msg.setSourceEntity(231U); - msg.setDestination(949U); - msg.setDestinationEntity(43U); - msg.sessid = 1844327970U; + IMC::UamRxFrame msg; + msg.setTimeStamp(0.003208785503095668); + msg.setSource(14387U); + msg.setSourceEntity(173U); + msg.setDestination(19869U); + msg.setDestinationEntity(145U); + msg.sys_src.assign("XOIEBFZNESX"); + msg.sys_dst.assign("UVJEJMRCURUOSTPRBAPAUDMCIRODCTYHQZWDSGVLWQKNNHXZNVAJKFBHWCEUVQTPRWZBZLFGBOGNZVGEWZSGZGAIBQZAMYPWTJCIRAHCAQIYLMYVCMYEXFDQNLXJSWCIPJTYKKNIOKBRNOMQPXJBSNTLIAVLDZESHXFMPHYOAHJFJQFFLVODPWTLKWFIEKUPQOMWZDVXOUHHRVTEEJGDCDRBKUSXIABHDBUFEXUYSXNMSOIFEQKXYLYRPKLG"); + msg.flags = 181U; + const signed char tmp_msg_0[] = {-97, -75, -110, 123, -53, -32, -111, -102, 33, -86, -3, -81, 19, -39, -49, -26, -89, -126, 16, -105, -122, 101, 62, -13, 8, 29, -75, -27, -36, 8, 61, 47, -125, -54, -36, 52, -109, -70, 89, 6, -94, -64, 37, 93, 124, 108, 119, 43, -66, -3, -59, 19, -14, 115, -69, 93, 101, -41, 16, -36, 96, 32, -77, 13, -10, -40, -26, 27, 77, 80, 77, 86, -77, -95, 74, -84, 35, 38, -12, 9, 7, -13, 92, -100, 45, -127, -126, -13, -105, 20, 40, -120, 16, -80, 22, -16, -84}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CloseSession #1", msg == *msg_d); + test.boolean("UamRxFrame #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21591,20 +24184,24 @@ main(void) } { - IMC::CloseSession msg; - msg.setTimeStamp(0.185608754636); - msg.setSource(57511U); - msg.setSourceEntity(148U); - msg.setDestination(10195U); - msg.setDestinationEntity(106U); - msg.sessid = 1268340872U; + IMC::UamRxFrame msg; + msg.setTimeStamp(0.5402993389995465); + msg.setSource(39204U); + msg.setSourceEntity(79U); + msg.setDestination(33541U); + msg.setDestinationEntity(128U); + msg.sys_src.assign("UXCYSCUFOHZSMHBRYGFITQIHOIFHIQKVVL"); + msg.sys_dst.assign("EUNRWLDLKLSXPTMUEFTGCKXQTAAZWZANOIPOFUWELNGIWCZSABCPFMAXMIHSZNMNVQBEIOPBEIQDNDNHDZVYDJQKYGSIFAKCKGDSRNQUTJPQJSPUTKGH"); + msg.flags = 88U; + const signed char tmp_msg_0[] = {-94, 45, -57, 23, -27, -53, 3, -54, 70, -10, 35, 96, 110, 114, 73, 5, 28, -67, 43, -89, -79, -19, -64, -45, 60, -105, 97, -8, -27, -65, -58, 8, -96, 95, -92, 37, -118, -24, 51, -10, -126, 56, -114, 2, -62, -54, -127, 39, 11, 123, -77, -56, 92, -26, 50, -25, -86, -42, 43, 70, -7, 17, 20, -57, 104, -28, -46, -40, -120, 5, -9, -66, -128, -9, -107, 97, -110, 33, -17, -7, -30, 88, -27, -88, 91, 26, -9, -125, -49, 49, 118, 71, -31, -11, 106, 64, -37, -102, -32, 6, -18, 41, -123, -95, 60, -83, -43, -119, -97, 39, 11, -2, 85, -45, -48, -94, 95, -41, -11, -110, 60, -51, -105, 72, -7, -39, 67, 77, 5, -56, 57, 80, -71, -79, -85, 29, 116, -68, 46, -78, 22, -71, 95, -67, 26, 85, -4, -38, 102, -104, -43, 29, 61, 7, 89, 36, -9, -37, -11, 81, -21, -38, 28, 50, -86, 59, 115, 68, 120, 42, 80, -79, 56, 73, 39, 71, -108, 34, -23, -19, -14, -100, 59, 110, -34, 52, -79, -48, 43, 81, -128, 75, -109, 4, -80, 0, 3, 54, 28, 11, 104, -13, 54, 53, 10, 75, 16, 123, 113, 90, 106, -10, 92, -19, -117, 13, -66, 15, -89, -92, 62, -57, 11, -14, -47, 60, -53, 86, -82, 22, -61, -49, 60, -92, 48, -17, 36, 123, -14, 54, -65}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("CloseSession #2", msg == *msg_d); + test.boolean("UamRxFrame #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21615,21 +24212,22 @@ main(void) } { - IMC::SessionSubscription msg; - msg.setTimeStamp(0.837594184367); - msg.setSource(61147U); - msg.setSourceEntity(9U); - msg.setDestination(27426U); - msg.setDestinationEntity(38U); - msg.sessid = 1410708505U; - msg.messages.assign("BFANNSZHIDUKULIZZQIAYBBYPTYLMUNWBSBGLFGXAKZIYWJJODAMEDOUJVNMDFMAJEHEOUCKTNCGRQZTGXRBCDELKEJTSATPNOAYLXQYCOAPMTYMHWUFVKOVBGCRYCEFXWULQJPSEFWVKOVJISCNRXFVMJUCQZQGHNBWRJVCKXFTWDHHBYMESELFQLOMZQXTPXSPONIRXVMPZZ"); + IMC::UamTxStatus msg; + msg.setTimeStamp(0.9732958051449393); + msg.setSource(53117U); + msg.setSourceEntity(253U); + msg.setDestination(20272U); + msg.setDestinationEntity(205U); + msg.seq = 46546U; + msg.value = 184U; + msg.error.assign("RFOWEZXAGOWFIAEWLXGHNDLLMJEOALVYDTWBDXMPIBBFHSBJSNCVYUQWWPRSYNHGSUQQFFYIMZYKHKKXLEAAWNCSKKTAVDCPAIDTPGVZMNJJHKA"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionSubscription #0", msg == *msg_d); + test.boolean("UamTxStatus #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21640,21 +24238,22 @@ main(void) } { - IMC::SessionSubscription msg; - msg.setTimeStamp(0.256025998673); - msg.setSource(47341U); - msg.setSourceEntity(237U); - msg.setDestination(55525U); - msg.setDestinationEntity(16U); - msg.sessid = 1898616555U; - msg.messages.assign("UIXHFOBUNXBMTUOKNPHYKSTVQJYDPEWTZEVAUZIRGBYGTPSCDRAJKCMEFQDHXVXGSYLEBZYZWAMKZFJAFVIWSYWZMYXVCYAKKBZDCQNHRFJHTBOWWNDREFVVDQAOOMMBIUKDSS"); + IMC::UamTxStatus msg; + msg.setTimeStamp(0.023106540851340895); + msg.setSource(40515U); + msg.setSourceEntity(235U); + msg.setDestination(31871U); + msg.setDestinationEntity(190U); + msg.seq = 28103U; + msg.value = 18U; + msg.error.assign("EIKBBYWZLGZCCYBXLCKDTLUBYVRBMWMEOZBOAN"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionSubscription #1", msg == *msg_d); + test.boolean("UamTxStatus #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21665,21 +24264,22 @@ main(void) } { - IMC::SessionSubscription msg; - msg.setTimeStamp(0.90784866951); - msg.setSource(23311U); - msg.setSourceEntity(188U); - msg.setDestination(5263U); - msg.setDestinationEntity(162U); - msg.sessid = 3418967313U; - msg.messages.assign("RIHRPLWEAUCHDUYTOYTPARJVRFUMMUZWKNTFDTDFUOSSZBZPXCTFQLXCGWAHDKLHURMQYDTESQEDFUGWCBOUHBOWMOZCNRETOYKGMISXQYNVIVVMEONKIYL"); + IMC::UamTxStatus msg; + msg.setTimeStamp(0.5635397615140549); + msg.setSource(43832U); + msg.setSourceEntity(8U); + msg.setDestination(55088U); + msg.setDestinationEntity(225U); + msg.seq = 16304U; + msg.value = 202U; + msg.error.assign("PKOSLMANEEWAYUDYQYTILM"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionSubscription #2", msg == *msg_d); + test.boolean("UamTxStatus #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21690,20 +24290,22 @@ main(void) } { - IMC::SessionKeepAlive msg; - msg.setTimeStamp(0.0291680943728); - msg.setSource(1711U); - msg.setSourceEntity(222U); - msg.setDestination(8393U); - msg.setDestinationEntity(25U); - msg.sessid = 323953218U; + IMC::UamRxRange msg; + msg.setTimeStamp(0.35541939067567174); + msg.setSource(45688U); + msg.setSourceEntity(85U); + msg.setDestination(50814U); + msg.setDestinationEntity(11U); + msg.seq = 49403U; + msg.sys.assign("BUPBUAPAJLCVKNAOAKAVQWLMILNDZTLNFJPJZNCSZGNMDLNEYHWQZPYWRDRHVXNICDSEYMQZXFPMQFCHWQRZDKQKMPJTNQZEJTXLCTLBGTMXZGRQCNYBSVOJSHISAUIHDYCOBKKJUTGBFUHAALRXDOOEIIVKSDKMFWUVISRSEEYTAIITYOCGRBWWOVFTWSGHFMUZGTZEMLGWKCBVENRPOGYLFBXHQHXOMDKYPXRVREHJEDUXUGQXPJOAUJB"); + msg.value = 0.8752632812340203; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionKeepAlive #0", msg == *msg_d); + test.boolean("UamRxRange #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21714,20 +24316,22 @@ main(void) } { - IMC::SessionKeepAlive msg; - msg.setTimeStamp(0.352197279127); - msg.setSource(27850U); - msg.setSourceEntity(159U); - msg.setDestination(19586U); - msg.setDestinationEntity(78U); - msg.sessid = 2581858483U; + IMC::UamRxRange msg; + msg.setTimeStamp(0.5915889329777652); + msg.setSource(33611U); + msg.setSourceEntity(46U); + msg.setDestination(35635U); + msg.setDestinationEntity(52U); + msg.seq = 34558U; + msg.sys.assign("JIGTJNYDABQZXFTYXHTZOYQFORGRWVWNEVAEEYUPTWUJPMWREVCXWSSCDPIPWTV"); + msg.value = 0.7923080626869724; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionKeepAlive #1", msg == *msg_d); + test.boolean("UamRxRange #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21738,20 +24342,22 @@ main(void) } { - IMC::SessionKeepAlive msg; - msg.setTimeStamp(0.722715036678); - msg.setSource(57698U); - msg.setSourceEntity(90U); - msg.setDestination(32508U); - msg.setDestinationEntity(119U); - msg.sessid = 4048942142U; + IMC::UamRxRange msg; + msg.setTimeStamp(0.04341267061960774); + msg.setSource(16707U); + msg.setSourceEntity(79U); + msg.setDestination(17301U); + msg.setDestinationEntity(121U); + msg.seq = 41528U; + msg.sys.assign("DPHWKSNOZNTEYSYNVBQNFCEKUXPXWHCUBLQGQXAFQEVMXBSXZRZFCJTCTAVGQWRVLTWVMEHOYKRCVPJOEXCXELLZNSAAMKUENALWPTWQFFJEVUUYMMZFFUIHTCPQIIGSTCIKVGPOMJKOLOGIAWPZWKDISGCBJQXSMBGXSDHDDRQZQGTLFONPXULYHKMTGENRFDOUDPBDRURGNDR"); + msg.value = 0.12712032746084467; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionKeepAlive #2", msg == *msg_d); + test.boolean("UamRxRange #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21762,21 +24368,22 @@ main(void) } { - IMC::SessionStatus msg; - msg.setTimeStamp(0.539572018445); - msg.setSource(54921U); - msg.setSourceEntity(51U); - msg.setDestination(12615U); - msg.setDestinationEntity(56U); - msg.sessid = 924725505U; - msg.status = 248U; + IMC::UamTxRange msg; + msg.setTimeStamp(0.8411694182338392); + msg.setSource(18127U); + msg.setSourceEntity(33U); + msg.setDestination(31694U); + msg.setDestinationEntity(194U); + msg.seq = 18559U; + msg.sys_dst.assign("PKCPXWARPMIQUUCNTQZEI"); + msg.timeout = 0.1331782570432718; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionStatus #0", msg == *msg_d); + test.boolean("UamTxRange #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21787,21 +24394,22 @@ main(void) } { - IMC::SessionStatus msg; - msg.setTimeStamp(0.0808365266309); - msg.setSource(41064U); - msg.setSourceEntity(251U); - msg.setDestination(61221U); - msg.setDestinationEntity(115U); - msg.sessid = 1822970040U; - msg.status = 160U; + IMC::UamTxRange msg; + msg.setTimeStamp(0.21643102711612328); + msg.setSource(16906U); + msg.setSourceEntity(223U); + msg.setDestination(1215U); + msg.setDestinationEntity(142U); + msg.seq = 472U; + msg.sys_dst.assign("KPSUOMIXYQXBLDZVUTIRSFLNQOMIRO"); + msg.timeout = 0.5513128516277815; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionStatus #1", msg == *msg_d); + test.boolean("UamTxRange #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21812,21 +24420,22 @@ main(void) } { - IMC::SessionStatus msg; - msg.setTimeStamp(0.0409697702878); - msg.setSource(8437U); - msg.setSourceEntity(133U); - msg.setDestination(38022U); - msg.setDestinationEntity(203U); - msg.sessid = 1607952386U; - msg.status = 136U; + IMC::UamTxRange msg; + msg.setTimeStamp(0.6005447116611345); + msg.setSource(57718U); + msg.setSourceEntity(74U); + msg.setDestination(37012U); + msg.setDestinationEntity(19U); + msg.seq = 42300U; + msg.sys_dst.assign("PNEILMCNHBGZZXDLVQBMFAQXTMRHCOAKTKGZHGYJFJUNEGCDYONWGAMUDGVJWPHHXYODMTFKEDCSLPUEBBFYTOLKEOZVAIBKGRHJSNHPLVBEQTQFUTHJRSGIKZOVZCCTIRMYXWUDWIXRWPJAPM"); + msg.timeout = 0.6749645038566477; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SessionStatus #2", msg == *msg_d); + test.boolean("UamTxRange #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21837,20 +24446,25 @@ main(void) } { - IMC::PushEntityParameters msg; - msg.setTimeStamp(0.0631081294462); - msg.setSource(1361U); - msg.setSourceEntity(145U); - msg.setDestination(10041U); - msg.setDestinationEntity(33U); - msg.name.assign("KFTLSEIJXCOBNANOPNNQXXVOEQJZFEGMICZTSQESVLRALPPBFVUPNZHUNQAYAPEXTWRTCQFJYAUHYYZWXMPGSJSXCQHRUGDGKQLMRJADWWXNYTQ"); + IMC::FormCtrlParam msg; + msg.setTimeStamp(0.9071539461329863); + msg.setSource(30406U); + msg.setSourceEntity(54U); + msg.setDestination(32094U); + msg.setDestinationEntity(145U); + msg.action = 39U; + msg.longain = 0.17396049085456033; + msg.latgain = 0.24727040840830283; + msg.bondthick = 851388060U; + msg.leadgain = 0.3662968889860567; + msg.deconflgain = 0.5886541013772869; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PushEntityParameters #0", msg == *msg_d); + test.boolean("FormCtrlParam #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21861,20 +24475,25 @@ main(void) } { - IMC::PushEntityParameters msg; - msg.setTimeStamp(0.841005422874); - msg.setSource(12814U); - msg.setSourceEntity(130U); - msg.setDestination(11887U); - msg.setDestinationEntity(19U); - msg.name.assign("BZRSELWFRBLXFWQFPWPFJMHNRYVHKALFDAUPNCVPYZYHQDNHDBCGGIAOXCACBSEATTEBDMKPSRYYD"); + IMC::FormCtrlParam msg; + msg.setTimeStamp(0.7678438713164384); + msg.setSource(25697U); + msg.setSourceEntity(5U); + msg.setDestination(61877U); + msg.setDestinationEntity(108U); + msg.action = 87U; + msg.longain = 0.7442541715113196; + msg.latgain = 0.740187272181964; + msg.bondthick = 1956356686U; + msg.leadgain = 0.785403257112356; + msg.deconflgain = 0.31682137248778064; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PushEntityParameters #1", msg == *msg_d); + test.boolean("FormCtrlParam #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21885,20 +24504,25 @@ main(void) } { - IMC::PushEntityParameters msg; - msg.setTimeStamp(0.757733207942); - msg.setSource(4311U); - msg.setSourceEntity(79U); - msg.setDestination(31891U); - msg.setDestinationEntity(142U); - msg.name.assign("PNXUADRPMLCEVLGBQUXNOECRRSSKJMLCMKXISEVBXVPIEZIWKGKCHEEGORRQQVIBYHFDRNKIJBPWYMZHHATNBJRXFXOTIIIEJRACGXHSLGILUQBUTZVSWPOHGVPAZVBUMFLVTQZOKAPCEYSFNMNPHQTEWLAOZETHDMOKPBSDOZDJWMRLUKWWFWHVFZYRQYNTTXATAFNYJUXBJAUUCPSGFDMBGFCFSWDYNYYJUIMQOYKCSZGQCDKLQGJDXNW"); + IMC::FormCtrlParam msg; + msg.setTimeStamp(0.4364258897095772); + msg.setSource(4626U); + msg.setSourceEntity(70U); + msg.setDestination(46812U); + msg.setDestinationEntity(134U); + msg.action = 207U; + msg.longain = 0.7042322995405857; + msg.latgain = 0.9547274269040431; + msg.bondthick = 2930073437U; + msg.leadgain = 0.46055080739901366; + msg.deconflgain = 0.363675389084095; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PushEntityParameters #2", msg == *msg_d); + test.boolean("FormCtrlParam #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21909,20 +24533,22 @@ main(void) } { - IMC::PopEntityParameters msg; - msg.setTimeStamp(0.646970477982); - msg.setSource(18650U); - msg.setSourceEntity(201U); - msg.setDestination(14494U); - msg.setDestinationEntity(63U); - msg.name.assign("BJWLLITEZUBCKUDLNZPHRRYYHIGYFGYCZSQVOMIOAEMNJFBGGQRXMBICEVUPVVOLCHSZTHDRKUYHDBATQITLVZTHFWFGRBBQDASPALNSONVKJGJALENKBFWAUYFTPXTHXYDEWOCCPTQKYDPYFYWQTJNTDQOWDNZSHSDMIKKNGNORRJMMBIGKECEIEGXZMWVAZPJFCJXIUOEZQHKSBQUOVWGVMEXX"); + IMC::FormationEval msg; + msg.setTimeStamp(0.9553282178102691); + msg.setSource(40077U); + msg.setSourceEntity(156U); + msg.setDestination(27613U); + msg.setDestinationEntity(97U); + msg.err_mean = 0.903219563587974; + msg.dist_min_abs = 0.6900537508542746; + msg.dist_min_mean = 0.3432063752648187; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PopEntityParameters #0", msg == *msg_d); + test.boolean("FormationEval #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21933,20 +24559,22 @@ main(void) } { - IMC::PopEntityParameters msg; - msg.setTimeStamp(0.324383909462); - msg.setSource(53784U); - msg.setSourceEntity(176U); - msg.setDestination(33101U); - msg.setDestinationEntity(216U); - msg.name.assign("UMAXFLGYJWPUADXMJCPHDKJRVEFJQJWHZTZBIIAFRVLYKXEZHHWMSMRWRIQKPVVLUAUORCYACTHYPYURKNNOOBYQKSFKLSRPNTBFXQDMORQEJPTDLGYCVFNNONPRHIKZDIXGBVMLXNSSIBNBFBHMGWZVEVMACBKRIGWWCE"); + IMC::FormationEval msg; + msg.setTimeStamp(0.7132152356996572); + msg.setSource(11652U); + msg.setSourceEntity(253U); + msg.setDestination(3215U); + msg.setDestinationEntity(213U); + msg.err_mean = 0.840184845955166; + msg.dist_min_abs = 0.016557914868573165; + msg.dist_min_mean = 0.18863823476308428; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PopEntityParameters #1", msg == *msg_d); + test.boolean("FormationEval #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21957,20 +24585,22 @@ main(void) } { - IMC::PopEntityParameters msg; - msg.setTimeStamp(0.655811238396); - msg.setSource(2782U); - msg.setSourceEntity(80U); - msg.setDestination(40019U); - msg.setDestinationEntity(134U); - msg.name.assign("VFJHOKAYTGWLSVEOOFAJYBFCMKUNFSGUTATXRKBUKGKYDVXSHZSZAAMDCRHAHRCGKFHPBYXOVBGJFEBSBIZLVPTZLDJIVRLENNOTOIITWADQQQSLHMKCYDRWZPYVOYNVPBNQUSZPPURMNDDUUOQFMUHGUWUDERCXDNM"); + IMC::FormationEval msg; + msg.setTimeStamp(0.31126312232965003); + msg.setSource(20401U); + msg.setSourceEntity(66U); + msg.setDestination(45098U); + msg.setDestinationEntity(8U); + msg.err_mean = 0.9859638868998907; + msg.dist_min_abs = 0.7740277598356184; + msg.dist_min_mean = 0.6359628043331725; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("PopEntityParameters #2", msg == *msg_d); + test.boolean("FormationEval #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -21981,21 +24611,30 @@ main(void) } { - IMC::IoEvent msg; - msg.setTimeStamp(0.342959064644); - msg.setSource(43935U); - msg.setSourceEntity(176U); - msg.setDestination(23817U); - msg.setDestinationEntity(180U); - msg.type = 84U; - msg.error.assign("KQTFGHEGPSWOQVCXZSACRECKQSCRUAHNDLECRULWXTHGVOZMDEVMZKFEOFIMPBUVTENJPEXZJSOKFAWUPXXTOLPYJQVHWAKCYHQKGUJTYPAPQCRLYGKFIPUZOTILBFYKQBCARIRVMINDVDJMNFULSNBTPNXWUYFDXZKDHSPYI"); + IMC::FormationControlParams msg; + msg.setTimeStamp(0.5899662674512015); + msg.setSource(65254U); + msg.setSourceEntity(68U); + msg.setDestination(59932U); + msg.setDestinationEntity(15U); + msg.action = 129U; + msg.lon_gain = 0.17311572797511088; + msg.lat_gain = 0.010614025444940611; + msg.bond_thick = 0.7117217734304795; + msg.lead_gain = 0.6949434224921671; + msg.deconfl_gain = 0.45563770352653876; + msg.accel_switch_gain = 0.6439037621495336; + msg.safe_dist = 0.6088260740578023; + msg.deconflict_offset = 0.6887260318040901; + msg.accel_safe_margin = 0.05595414727589987; + msg.accel_lim_x = 0.5990941380162108; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IoEvent #0", msg == *msg_d); + test.boolean("FormationControlParams #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22006,21 +24645,30 @@ main(void) } { - IMC::IoEvent msg; - msg.setTimeStamp(0.615466387655); - msg.setSource(61189U); - msg.setSourceEntity(145U); - msg.setDestination(37739U); - msg.setDestinationEntity(114U); - msg.type = 45U; - msg.error.assign("QSACJIUPQMFJRVSXGVHLSBLFAVVFIBPBAZWQPXNDCNFOWHTRTJETLLTFTFXUMJWQJBNNGVUNUKOADZQMZCRYRKESEWWB"); + IMC::FormationControlParams msg; + msg.setTimeStamp(0.10458347904777743); + msg.setSource(41106U); + msg.setSourceEntity(170U); + msg.setDestination(59484U); + msg.setDestinationEntity(240U); + msg.action = 85U; + msg.lon_gain = 0.6805479269101893; + msg.lat_gain = 0.5427578727308592; + msg.bond_thick = 0.47226283198848673; + msg.lead_gain = 0.24712985635331275; + msg.deconfl_gain = 0.14447815768170147; + msg.accel_switch_gain = 0.4826821384678479; + msg.safe_dist = 0.9174000383632299; + msg.deconflict_offset = 0.5412675208288195; + msg.accel_safe_margin = 0.6996306358931451; + msg.accel_lim_x = 0.6690710821894601; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IoEvent #1", msg == *msg_d); + test.boolean("FormationControlParams #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22031,21 +24679,30 @@ main(void) } { - IMC::IoEvent msg; - msg.setTimeStamp(0.64204980253); - msg.setSource(55103U); - msg.setSourceEntity(33U); - msg.setDestination(56340U); - msg.setDestinationEntity(225U); - msg.type = 210U; - msg.error.assign("KWAOPZKGMBMKBCMKGHEMNQZCJPQAIRDJJJYOXIVDAQGOC"); + IMC::FormationControlParams msg; + msg.setTimeStamp(0.8788131930187848); + msg.setSource(7962U); + msg.setSourceEntity(76U); + msg.setDestination(61441U); + msg.setDestinationEntity(142U); + msg.action = 109U; + msg.lon_gain = 0.995170954489543; + msg.lat_gain = 0.23441833255867395; + msg.bond_thick = 0.9853967068728545; + msg.lead_gain = 0.16528243429556544; + msg.deconfl_gain = 0.4774546826359458; + msg.accel_switch_gain = 0.4918581464786119; + msg.safe_dist = 0.054425493985511; + msg.deconflict_offset = 0.095037324445857; + msg.accel_safe_margin = 0.13428649165841544; + msg.accel_lim_x = 0.28241911499550776; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("IoEvent #2", msg == *msg_d); + test.boolean("FormationControlParams #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22056,24 +24713,39 @@ main(void) } { - IMC::UamTxFrame msg; - msg.setTimeStamp(0.667581065039); - msg.setSource(35284U); - msg.setSourceEntity(211U); - msg.setDestination(40U); - msg.setDestinationEntity(132U); - msg.seq = 42095U; - msg.sys_dst.assign("YQZGOLIIXISBIWERHSUHNLCROJKLCKPSFAJMHHYPOGVIBWXNNIIUJ"); - msg.flags = 118U; - const char tmp_msg_0[] = {38, 52, -113, -34, 95, 85, 85, -74, 89, -81, 60, -64, 77, -60, -127, 121, 98, 115, -127, 27, 58, 106, -71, -51, 66, -106, 113, 49, 22, 14, 32, 62, -56, -23, -111, -113, 71, -108, 12, 84, 92, 103, 7, 92, 25, 39, -51, -115, 90, -91, 32, -35, -84, -20, 31, 86, -32, 93, -62, -105, -69, -28, -63, 41, 82, 82, -3, 126, 9, -34, -38, -48, -122, 37, -96, 37, 50, -120, -89, 98, -112, 85, -68, -91, -78, -10, -22, -2, -40, -84, -112, 68, -110, -25, -16, -110, -31, 1, 2, 97, 58, -7, -74, 15, -78, -122, -36, -74, -126, 107, -114, 63, -116, -114, -101, -70, -37, -86, 21, 94, 42, 112, 91, 112, -56, -76, -49, 9, -107, -58, 90, 110, -55, 78, -90, 112, 38, -101, 62, -49, 110, 94, 49, 15, 67, 71, -16, -56, 92, 45, -27, -71, -102, -30, 31, -10, -67, -105, -67, 50, -122, 19, -91, -12, 7, -116, 123, -114, 41, 31, -17, -103, 75, 59, 124, -72, -22, -38, 118, -17, 117, -118, 47, 123, -7, 49, -84, -40, -14, -44, -95, -4, 45, 51, -9, -34, 88, -54, 3}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::FormationEvaluation msg; + msg.setTimeStamp(0.9875505423961943); + msg.setSource(16719U); + msg.setSourceEntity(20U); + msg.setDestination(10237U); + msg.setDestinationEntity(171U); + msg.type = 32U; + msg.op = 84U; + msg.err_mean = 0.5729389886234104; + msg.dist_min_abs = 0.10798380799223872; + msg.dist_min_mean = 0.13448981784354797; + msg.roll_rate_mean = 0.7740477031850196; + msg.time = 0.806491408452869; + IMC::FormationControlParams tmp_msg_0; + tmp_msg_0.action = 247U; + tmp_msg_0.lon_gain = 0.4045343911753806; + tmp_msg_0.lat_gain = 0.48203348306491955; + tmp_msg_0.bond_thick = 0.46504030764504545; + tmp_msg_0.lead_gain = 0.8433756305332183; + tmp_msg_0.deconfl_gain = 0.33909399438067134; + tmp_msg_0.accel_switch_gain = 0.9956818118835309; + tmp_msg_0.safe_dist = 0.05461781788082243; + tmp_msg_0.deconflict_offset = 0.6932926764036854; + tmp_msg_0.accel_safe_margin = 0.4653975500607317; + tmp_msg_0.accel_lim_x = 0.16935515374742427; + msg.controlparams.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamTxFrame #0", msg == *msg_d); + test.boolean("FormationEvaluation #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22084,24 +24756,39 @@ main(void) } { - IMC::UamTxFrame msg; - msg.setTimeStamp(0.647679992179); - msg.setSource(58753U); - msg.setSourceEntity(249U); - msg.setDestination(39201U); - msg.setDestinationEntity(124U); - msg.seq = 20547U; - msg.sys_dst.assign("SOVCSJESYMCNFDNBSHTQROWBPZXESUPJPDGAZJXGHABCFITBLWTJHXAJFFACXKWQPBLROCMEXEZZHIRKOUSAYKHAUNQKVIBRCZYIYFCLUJAMMHWTPRBWXMGLUIWNLDZMQIZGKXBWWCKTRGRKWTIQHAEOYTZCGUEZDOUZQTAOPUDBYSBKMQVEYJLSLJRHDHRSOFVULVWOTYNTVENFKDXALEPJVNDGV"); - msg.flags = 55U; - const char tmp_msg_0[] = {-56, -84, 4, 107, 58, -31, -90, 27, -115, 28, -53, 106, -122, 13, -105, -61, -5, 6, -109, 92, 81, 121, 125, -9, 66, 13, -28, 14, -119, -45, -24, -57, -127, 23, -111, -17, -13, 65, -25, -38, 2, 57, -95, -75, -57, -49, 32, 121, 71, -4, 27, 63, -79, 119, 6, 19, -73, -84, 86, -97, 34, -87, -32, -9, 111, -50, 10, 53, -34, -84, 64, 123, -63, 75, 104, -80, 21, -35, 12, -56, -57, 100, -48, 71, 31, 12, -102, 111, 66, -40, 6, -46, -36, 102, -24, 46, -86, 27, 112, -117, -59, 86, -100, 20, -12, -34, 105, 45, -5, 59, 18, -40, -62, -34, -42, 59, 117, 71, 65, -39, -13, -38, -56, 57, 98, 18, -92, -66, -127, 26, -119, 41, 35, 53, -89, -45, 94, 60, 93, -4, 22, -71, -78, 41, -59, -94, 93, -42, -115, -92, 25, 57, -5, -108, 89, -43, 95, -109, -3, 11, 93, 89, -108, 25, 100, -26, 16, 88, 67, -91, 11, 29, -60, 11, 17, 39, -128, -124, -82, -47, -45}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::FormationEvaluation msg; + msg.setTimeStamp(0.42162891579402484); + msg.setSource(21103U); + msg.setSourceEntity(224U); + msg.setDestination(16929U); + msg.setDestinationEntity(89U); + msg.type = 223U; + msg.op = 159U; + msg.err_mean = 0.009596691745802577; + msg.dist_min_abs = 0.7348375005539751; + msg.dist_min_mean = 0.13387687953185057; + msg.roll_rate_mean = 0.5549174728473653; + msg.time = 0.06996499134030432; + IMC::FormationControlParams tmp_msg_0; + tmp_msg_0.action = 203U; + tmp_msg_0.lon_gain = 0.6662753173377709; + tmp_msg_0.lat_gain = 0.9003264262897059; + tmp_msg_0.bond_thick = 0.3663278807187248; + tmp_msg_0.lead_gain = 0.4331011262861424; + tmp_msg_0.deconfl_gain = 0.720681118843653; + tmp_msg_0.accel_switch_gain = 0.551865010107434; + tmp_msg_0.safe_dist = 0.8496957354798321; + tmp_msg_0.deconflict_offset = 0.7283232683125527; + tmp_msg_0.accel_safe_margin = 0.6706920490393616; + tmp_msg_0.accel_lim_x = 0.32440249038233016; + msg.controlparams.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamTxFrame #1", msg == *msg_d); + test.boolean("FormationEvaluation #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22112,24 +24799,39 @@ main(void) } { - IMC::UamTxFrame msg; - msg.setTimeStamp(0.203897352614); - msg.setSource(1860U); - msg.setSourceEntity(129U); - msg.setDestination(36192U); - msg.setDestinationEntity(163U); - msg.seq = 59781U; - msg.sys_dst.assign("LJDXFMUSNOAEUBGGOITSUTCNJIQDYQLIBMJHOHGCGZWTVVTCFZGLMDGXPMVJNPEZCRBPAXZCTQJJUWRIENYQPPWCYYQTUZTICOVAFWCYDUOSTIQRXHJFQUABZFUXWJRKMEDPLKSPOHSKNBXKMXBNXMYETELDKNLOEWLWFGJAFNREHKKFHEVFSXBZTEGHAPIKLALRIGPSDQNAWZFIJ"); - msg.flags = 203U; - const char tmp_msg_0[] = {91, 1, 105, -22, 20, 38, -70, -25, 8, -100, 32, -83, 125, -76, 6, -40, -12, 35, -84, 18, -1, -104, 5, -99, 32, 27, -23, -126, 28, -51, 0, 64, 14, -4, 36, 35, 67, -87, -61, 97, 35, -69, 6, 61, 13, -87, 123, -77, -25, 10, 74, -125, 15, 119, -2, -6, 69, 78, -95, 80, 49, -97, -39, 46, -112, -74, -47, -15, 10, -19, -56, -119, -23, -88, -85, -111, -71, 21, -14}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::FormationEvaluation msg; + msg.setTimeStamp(0.5309549410390421); + msg.setSource(17838U); + msg.setSourceEntity(254U); + msg.setDestination(13600U); + msg.setDestinationEntity(33U); + msg.type = 61U; + msg.op = 153U; + msg.err_mean = 0.980444737322315; + msg.dist_min_abs = 0.5756172498162945; + msg.dist_min_mean = 0.9539723210517397; + msg.roll_rate_mean = 0.17794348698236906; + msg.time = 0.07138976657387286; + IMC::FormationControlParams tmp_msg_0; + tmp_msg_0.action = 126U; + tmp_msg_0.lon_gain = 0.018594066461939285; + tmp_msg_0.lat_gain = 0.8067609009182901; + tmp_msg_0.bond_thick = 0.26627303886182885; + tmp_msg_0.lead_gain = 0.5793228022913557; + tmp_msg_0.deconfl_gain = 0.39240042724250856; + tmp_msg_0.accel_switch_gain = 0.9448970151214322; + tmp_msg_0.safe_dist = 0.5673520309017079; + tmp_msg_0.deconflict_offset = 0.5477416884538437; + tmp_msg_0.accel_safe_margin = 0.006235092865366498; + tmp_msg_0.accel_lim_x = 0.6971081385702009; + msg.controlparams.set(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamTxFrame #2", msg == *msg_d); + test.boolean("FormationEvaluation #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22140,24 +24842,23 @@ main(void) } { - IMC::UamRxFrame msg; - msg.setTimeStamp(0.934918373103); - msg.setSource(283U); - msg.setSourceEntity(161U); - msg.setDestination(34296U); - msg.setDestinationEntity(174U); - msg.sys_src.assign("FALRYJAOKEXPNQZBIIYXGLEPRFOPCRNPCLIUWWUNOFCZUTDKIZAOBYGMURS"); - msg.sys_dst.assign("LLXWVPAMWIMZSTRCZHEQOJQKYMZFNAMSUQDRRPSUZXCFTVJIJACDDXMBHYYOGOQXFOXHAWDTPVYNEYHVEKVWSOIV"); - msg.flags = 151U; - const char tmp_msg_0[] = {85, -92, -29, -5, 60, -82, 116, 91, -29, -44, 5, -58, -79, 70, -47, -81, -33, 122, -87, 105, 122, 94, -42, 44, -65, 54, -46, 33, -42, -112, 98, -75}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::SoiWaypoint msg; + msg.setTimeStamp(0.23800267260973795); + msg.setSource(55495U); + msg.setSourceEntity(99U); + msg.setDestination(18755U); + msg.setDestinationEntity(110U); + msg.lat = 0.7063937951217114; + msg.lon = 0.5030866080552908; + msg.eta = 1543425764U; + msg.duration = 63333U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamRxFrame #0", msg == *msg_d); + test.boolean("SoiWaypoint #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22168,24 +24869,23 @@ main(void) } { - IMC::UamRxFrame msg; - msg.setTimeStamp(0.593788728693); - msg.setSource(12319U); - msg.setSourceEntity(29U); - msg.setDestination(43348U); - msg.setDestinationEntity(32U); - msg.sys_src.assign("FAQRQZVCTMLIWRDZGTTJUOJAMBGTXDMSIYMRPDCYGIYMVPBDUPWXAWOTSDGJEEEPUBHQDISVPTNGFZMI"); - msg.sys_dst.assign("RPCNYCNXXQQSLUIUHMKQWDYHJOLNHLLCJKDEWFXVPKEBKDHOITBRJD"); - msg.flags = 69U; - const char tmp_msg_0[] = {46, 37, -51, 50, 69, 47, -76, 26, -8, -124, 93, -112, -42, 102, -55, 126, 5, 104, 86, -87, -114, -87, -60, -56, -104, -45, 126, -123, 67, 16, -126, -94, -1, 94, 111, 57, -104, 103, -7, -76, 34, 22, -30, -93, -18, 8, -56, 72, -73, 69, 4, -56, -26, -52, 93, 57, -14, 91, 8, -32, 90, -3, 88, 99, -45, 33, 76, -127, -52, 1, 6, -34, -24, 114, -6, 124, 13, -16, 104, -96, 28, 32, 67, -5, 8, 16, -116, 101, 85, 72, -67, -82, -99, -94, -128, -111, 32, 53, 20, -13, 97, 62, -32, 62, -53, -37, -20, 67, 91, 8, 19, 32, -98, -108, 112, 99, -54, -85, 106, -9, -44, -53, 16, 4, -1, 60, -52, -96, -100, -107, 3, 90, -84, -82, 49, -11, -33, -57, 25, 46, -21, 43, -86, 7, -52, 111, 82, -95, -9, -62, 67, -92, 44, 112, -32, 100, 82, -119, 113, -51, -33, 22, -62, -3, 35, -123, -114, -82, 64, 73, 79, 54, -72, -81, 75, -25, 39, -118, -65, 9, -57, -111, 46, -20, 120, 6, -127, 15, 13, 92, -55, 21, -30, 43, 65, 106, -82, -42, 12, 15, 86, 59, -45, 25, 34, 24, 78, 65, 90, -3, 102, -49, 31, -40, 71, -107, 10, -120, 9, -117, 42, 115, -30, -18, -21, 74, 59, 120, 17, -33, -117, -38, 3, 101, 59, 7, -113, -30, -51, 120, -102, 125, -126, 70, -53, -6, 86, -106, -117, 24, 107, 76}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::SoiWaypoint msg; + msg.setTimeStamp(0.4697107244619644); + msg.setSource(50508U); + msg.setSourceEntity(16U); + msg.setDestination(18215U); + msg.setDestinationEntity(211U); + msg.lat = 0.09851082637068576; + msg.lon = 0.008344758119089302; + msg.eta = 3325002494U; + msg.duration = 2941U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamRxFrame #1", msg == *msg_d); + test.boolean("SoiWaypoint #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22196,24 +24896,23 @@ main(void) } { - IMC::UamRxFrame msg; - msg.setTimeStamp(0.374491908981); - msg.setSource(54724U); - msg.setSourceEntity(179U); - msg.setDestination(13659U); - msg.setDestinationEntity(30U); - msg.sys_src.assign("MWLUCSEDYSKDZZUUOSIPOUOXMCQRLFWQOOCCFNRKXWLJIAEVESZIFPGQGVVYTNY"); - msg.sys_dst.assign("HEYYFGYFVCTDEUHTXRWQBOFKBMLQWNBRZNOYDPPRBWNCZFCTBIITQTLZDSDPKEQINOBVAGFCDWOCAIKBWRHOLUJKLQVXRJIFDASSBTKHIEYSMEORGFSKYZUMSXPI"); - msg.flags = 116U; - const char tmp_msg_0[] = {70, -23, -7, -27, -29, -71, 9, 76, -109, -39, -32, 60, 78, -41, 13, -40, 61, 122, -19, 113, 80, -78, -70, 58, -126, -39, 48, 55, -70, 49, 83, 49, -2, -86, -100, 58, 18, -43, -54, -48, -88, 4, 41, -57, -96, 59, -38, -3, -11, 55, -96, -70, 32, 125, -91, 1, 35, 45, -44, -125, 35}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::SoiWaypoint msg; + msg.setTimeStamp(0.22406431600529564); + msg.setSource(62156U); + msg.setSourceEntity(46U); + msg.setDestination(59809U); + msg.setDestinationEntity(106U); + msg.lat = 0.6072793282468171; + msg.lon = 0.14805984885717838; + msg.eta = 343076440U; + msg.duration = 22174U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamRxFrame #2", msg == *msg_d); + test.boolean("SoiWaypoint #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22224,22 +24923,20 @@ main(void) } { - IMC::UamTxStatus msg; - msg.setTimeStamp(0.708747305167); - msg.setSource(56686U); - msg.setSourceEntity(234U); - msg.setDestination(9056U); - msg.setDestinationEntity(62U); - msg.seq = 11750U; - msg.value = 240U; - msg.error.assign("TRBWQCIXYMHNEIWGPZUYWDQXSLEQJDZMTUYVBDM"); + IMC::SoiPlan msg; + msg.setTimeStamp(0.6192153957742724); + msg.setSource(12322U); + msg.setSourceEntity(153U); + msg.setDestination(26230U); + msg.setDestinationEntity(245U); + msg.plan_id = 30894U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamTxStatus #0", msg == *msg_d); + test.boolean("SoiPlan #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22250,22 +24947,20 @@ main(void) } { - IMC::UamTxStatus msg; - msg.setTimeStamp(0.391218502787); - msg.setSource(62849U); - msg.setSourceEntity(230U); - msg.setDestination(7444U); - msg.setDestinationEntity(179U); - msg.seq = 23278U; - msg.value = 85U; - msg.error.assign("RDZOTQZQZXPWUJGYAULAXADYIEYHFKWNTLDNZASLKRJTPNCHBUUOKBJIWYSNOBGWOUTXWKVSVRWSUVCUZEDSMEGGWINZPFKVOQQOVLJTQXHV"); + IMC::SoiPlan msg; + msg.setTimeStamp(0.2672266276778077); + msg.setSource(62119U); + msg.setSourceEntity(118U); + msg.setDestination(24777U); + msg.setDestinationEntity(211U); + msg.plan_id = 50369U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamTxStatus #1", msg == *msg_d); + test.boolean("SoiPlan #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22276,22 +24971,26 @@ main(void) } { - IMC::UamTxStatus msg; - msg.setTimeStamp(0.478496280526); - msg.setSource(45776U); - msg.setSourceEntity(90U); - msg.setDestination(47782U); - msg.setDestinationEntity(197U); - msg.seq = 48044U; - msg.value = 115U; - msg.error.assign("JJAIZPOZQTZDCXDBRJOJLKBDCGKDOSXGFLPNVVUFFSBUWGLOTGBBRUSWGB"); + IMC::SoiPlan msg; + msg.setTimeStamp(0.7248153194890126); + msg.setSource(27482U); + msg.setSourceEntity(87U); + msg.setDestination(56902U); + msg.setDestinationEntity(193U); + msg.plan_id = 18178U; + IMC::SoiWaypoint tmp_msg_0; + tmp_msg_0.lat = 0.8596140087219488; + tmp_msg_0.lon = 0.08888666855063987; + tmp_msg_0.eta = 1503965149U; + tmp_msg_0.duration = 38887U; + msg.waypoints.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamTxStatus #2", msg == *msg_d); + test.boolean("SoiPlan #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22302,22 +25001,32 @@ main(void) } { - IMC::UamRxRange msg; - msg.setTimeStamp(0.0326081187353); - msg.setSource(14907U); - msg.setSourceEntity(184U); - msg.setDestination(28624U); - msg.setDestinationEntity(10U); - msg.seq = 29667U; - msg.sys.assign("NNZSXOEGRLZAKYKQUNOCEPBEHBSFVIXKJVCXIEAZQWKJYYXJRMVSNGWOOGAAQBKCTBECHDTCREHBBMUPXMPXMUNSYGUXHOHWNIAYQDNDDRPFJEFRSLHSKPTRGLJWGUIMLOCFMWOPYWZATVQRJCUENFAHYTJFVFLPPURVTZDZYWTCQBBNZNQEIA"); - msg.value = 0.694665783158; + IMC::SoiCommand msg; + msg.setTimeStamp(0.8608825499917806); + msg.setSource(16437U); + msg.setSourceEntity(125U); + msg.setDestination(51715U); + msg.setDestinationEntity(107U); + msg.type = 14U; + msg.command = 149U; + msg.settings.assign("YRYWFLMALHGAGLBFXZADJNLBIFVBRNKMLTUSOBAZEBJSQHFJBNXHYPDUTSZJPNGOIUXNTKEXIGOQREVTPEVTWRHPOAWOTKJRSWFVMWIHUQYJLPMRIVNSCYCPEPZVSMQVRZYZAOMIDBENKVTWCJBZFCWOQKIUIAKMGVFFWKQGIXJXCBQXCKQNNHXCLBDYPOJAKTHYUEGSODURRSJH"); + IMC::SoiPlan tmp_msg_0; + tmp_msg_0.plan_id = 50106U; + IMC::SoiWaypoint tmp_tmp_msg_0_0; + tmp_tmp_msg_0_0.lat = 0.14153861512380217; + tmp_tmp_msg_0_0.lon = 0.31942479750832087; + tmp_tmp_msg_0_0.eta = 1091990271U; + tmp_tmp_msg_0_0.duration = 29728U; + tmp_msg_0.waypoints.push_back(tmp_tmp_msg_0_0); + msg.plan.set(tmp_msg_0); + msg.info.assign("EPOLGSQDVLUEGIQ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamRxRange #0", msg == *msg_d); + test.boolean("SoiCommand #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22328,22 +25037,26 @@ main(void) } { - IMC::UamRxRange msg; - msg.setTimeStamp(0.428962289353); - msg.setSource(41566U); - msg.setSourceEntity(232U); - msg.setDestination(16211U); - msg.setDestinationEntity(71U); - msg.seq = 19823U; - msg.sys.assign("XCDNBTWKGNOPSAEMDNUDEGNPBLMVTJTHFTWKYCFBAPHDRBIQOIDMEVYILXJZGFH"); - msg.value = 0.855815213511; + IMC::SoiCommand msg; + msg.setTimeStamp(0.8625885922818103); + msg.setSource(47465U); + msg.setSourceEntity(145U); + msg.setDestination(36825U); + msg.setDestinationEntity(148U); + msg.type = 232U; + msg.command = 237U; + msg.settings.assign("TUVYZFBDPOLYOVITBJPBDCFKWIKHPGMXAZCROVKTJRDRVLSLBFFOUENJOGAWHDJLUVFIWCDDDPKPCGC"); + IMC::SoiPlan tmp_msg_0; + tmp_msg_0.plan_id = 38234U; + msg.plan.set(tmp_msg_0); + msg.info.assign("BBNOVADGUYYKQRLOJGVDGQBRWUYJXLICONQLIDBCOWRXSXCKAEFJPHZFZRKKMVRKXOQTCSZODNJKKGOWJFBTGQVSZNYIHUBHATHXJDEGWPMFYWOTVLPXLHMYGDUGECIPBHADJFZASDNFVMXUHGXGAFMHIYJPETMVISIUUMCUJDUSRBATWINXRSHSVRNSLMQCBLTMTPWIENEUQEOLYKLQVPHFWYLKTXORPPZVZZJFZKEISNQBCTAWED"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamRxRange #1", msg == *msg_d); + test.boolean("SoiCommand #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22354,22 +25067,26 @@ main(void) } { - IMC::UamRxRange msg; - msg.setTimeStamp(0.410108472346); - msg.setSource(14480U); - msg.setSourceEntity(52U); - msg.setDestination(6137U); - msg.setDestinationEntity(232U); - msg.seq = 29636U; - msg.sys.assign("HBVUOEHKEUNGRBUTDWWGZJLANTPJJNECUKCLVOSEAUTKFGDVUVCARFCULZZNSPYCJ"); - msg.value = 0.828626336334; + IMC::SoiCommand msg; + msg.setTimeStamp(0.8884841596963196); + msg.setSource(50480U); + msg.setSourceEntity(56U); + msg.setDestination(44652U); + msg.setDestinationEntity(174U); + msg.type = 55U; + msg.command = 148U; + msg.settings.assign("MSGOJWCQNWVKYUDRLFHNUWHKGTJDAECALQAUOLPZEISZKVLPEKNYFDRITMOYGZFSYAHIAMRKJUVOBNXPDFHGXEONJEYLFQKTAPXMPTNSYCEAXHBOMFLGBGUSQHLRUOZUDXPDL"); + IMC::SoiPlan tmp_msg_0; + tmp_msg_0.plan_id = 48366U; + msg.plan.set(tmp_msg_0); + msg.info.assign("TEIFIGBGAORNEV"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UamRxRange #2", msg == *msg_d); + test.boolean("SoiCommand #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22380,25 +25097,23 @@ main(void) } { - IMC::FormCtrlParam msg; - msg.setTimeStamp(0.0853571591213); - msg.setSource(64631U); - msg.setSourceEntity(36U); - msg.setDestination(43572U); - msg.setDestinationEntity(235U); - msg.action = 32U; - msg.longain = 0.202513308249; - msg.latgain = 0.468994812949; - msg.bondthick = 142277416U; - msg.leadgain = 0.865951770787; - msg.deconflgain = 0.429595183456; + IMC::SoiState msg; + msg.setTimeStamp(0.7747799517719577); + msg.setSource(23713U); + msg.setSourceEntity(189U); + msg.setDestination(63074U); + msg.setDestinationEntity(99U); + msg.state = 241U; + msg.plan_id = 12983U; + msg.wpt_id = 138U; + msg.settings_chk = 60026U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormCtrlParam #0", msg == *msg_d); + test.boolean("SoiState #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22409,25 +25124,23 @@ main(void) } { - IMC::FormCtrlParam msg; - msg.setTimeStamp(0.433755254329); - msg.setSource(32334U); - msg.setSourceEntity(195U); - msg.setDestination(56805U); - msg.setDestinationEntity(24U); - msg.action = 114U; - msg.longain = 0.536083136242; - msg.latgain = 0.217899177004; - msg.bondthick = 583275541U; - msg.leadgain = 0.168337622336; - msg.deconflgain = 0.890115024616; + IMC::SoiState msg; + msg.setTimeStamp(0.14156841694586852); + msg.setSource(10502U); + msg.setSourceEntity(223U); + msg.setDestination(7272U); + msg.setDestinationEntity(151U); + msg.state = 2U; + msg.plan_id = 64189U; + msg.wpt_id = 158U; + msg.settings_chk = 49729U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormCtrlParam #1", msg == *msg_d); + test.boolean("SoiState #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22438,25 +25151,23 @@ main(void) } { - IMC::FormCtrlParam msg; - msg.setTimeStamp(0.746867474164); - msg.setSource(28098U); - msg.setSourceEntity(168U); - msg.setDestination(1433U); - msg.setDestinationEntity(160U); - msg.action = 162U; - msg.longain = 0.79670640076; - msg.latgain = 0.0183717793527; - msg.bondthick = 754649630U; - msg.leadgain = 0.17593534239; - msg.deconflgain = 0.643024758461; + IMC::SoiState msg; + msg.setTimeStamp(0.1705498516296734); + msg.setSource(16003U); + msg.setSourceEntity(182U); + msg.setDestination(44269U); + msg.setDestinationEntity(235U); + msg.state = 136U; + msg.plan_id = 28105U; + msg.wpt_id = 195U; + msg.settings_chk = 7067U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormCtrlParam #2", msg == *msg_d); + test.boolean("SoiState #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22467,22 +25178,24 @@ main(void) } { - IMC::FormationEval msg; - msg.setTimeStamp(0.75400179707); - msg.setSource(41056U); - msg.setSourceEntity(176U); - msg.setDestination(44556U); - msg.setDestinationEntity(102U); - msg.err_mean = 0.951707631389; - msg.dist_min_abs = 0.534250173185; - msg.dist_min_mean = 0.311481431409; + IMC::MessagePart msg; + msg.setTimeStamp(0.742342947192623); + msg.setSource(38845U); + msg.setSourceEntity(193U); + msg.setDestination(63776U); + msg.setDestinationEntity(243U); + msg.uid = 18U; + msg.frag_number = 34U; + msg.num_frags = 141U; + const signed char tmp_msg_0[] = {118, -44, -49, 15, -64, -58, 122, -24, 116, 64, 29, 71, -56, -87, -48, -40, -53, -16, 125, 29, 14, 31, 72, 79, 22, 35, -30, -25, -80, -115, -106, -14, -98, 125, -16, -49, -48, 126, 37, 83, -104, -60, -103, 74, -15, 104, -82, -77, 67, 81, -75, -34, 115, -12, 98, 90, 37, 9, 67, 109, 50, -49, 112, 1, -82, 6, 12, -15, 16, -82, -116, -119, 52, -59, -50, 98, -88, 34, 124, 17, -40, 37, 35, 78, 87, -71, 102, -51, -98, -10, -39, -125, 21, 19, 89, -98, 112, -116, -59, -109, 32, -51, -12, -114, 99, 66, -83, 64, -20, -76, -41, -100}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationEval #0", msg == *msg_d); + test.boolean("MessagePart #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22493,22 +25206,24 @@ main(void) } { - IMC::FormationEval msg; - msg.setTimeStamp(0.183407543968); - msg.setSource(35282U); - msg.setSourceEntity(230U); - msg.setDestination(55015U); - msg.setDestinationEntity(187U); - msg.err_mean = 0.761487916197; - msg.dist_min_abs = 0.1765715065; - msg.dist_min_mean = 0.753649655748; + IMC::MessagePart msg; + msg.setTimeStamp(0.09197579848480475); + msg.setSource(29087U); + msg.setSourceEntity(8U); + msg.setDestination(31709U); + msg.setDestinationEntity(63U); + msg.uid = 239U; + msg.frag_number = 72U; + msg.num_frags = 42U; + const signed char tmp_msg_0[] = {75, -108, 75, 33, -80, -24, 117, -21, 50, -44, 30, 46, 35, -68, 92, 1, -18, 111, 10, -47, 68, -73, -62, 125, -36, -117, 77, 81, 21, -119, -1, -27, 40, 21, -55, -92, 112, -7, -56, 121, -108, 77, -106, -92, 39, 122, -74, -19, 69, 108, -87, 86, 43, -89, 49, 63, 59, 90, -113, -78, 98, 59, -10, -7, 42, -127, -67, -109, 110, 79, 51, -123, -25, 3, 106, 117, -33, -100, -104, 41, 66, 105, 8, 93, -6, 11, -75, -113, 99, -65, 71, 2, 74, -2, -88, -97, -30, 60, -97, 117, 91, -6, 111, 90, 121, -69, 40, -126, 25, -49, -127, -13, 122, -48, 79, 2, 29, -110, -117, 76, -31, -90, 56, 83, 53, -50, -22, 18, 38, -86, -82, -103, 48, 27, -1, -43, -73, -112, -74, -75, -22, 24, 37, -112, 97, 32, -73, 8, 73, 98, -31, -41, 115, 102, 16, -92, 39, -5, 111, 91, -28, -40, 86, -43, 54, 103, -1, -10, 10, -43, -13, -70, -44, -14, -79, -77, -123, -96, -66, -79}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationEval #1", msg == *msg_d); + test.boolean("MessagePart #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22519,22 +25234,24 @@ main(void) } { - IMC::FormationEval msg; - msg.setTimeStamp(0.0205423278054); - msg.setSource(35308U); - msg.setSourceEntity(75U); - msg.setDestination(62605U); - msg.setDestinationEntity(212U); - msg.err_mean = 0.583306236704; - msg.dist_min_abs = 0.278965084935; - msg.dist_min_mean = 0.954292715486; + IMC::MessagePart msg; + msg.setTimeStamp(0.6662930149102327); + msg.setSource(41039U); + msg.setSourceEntity(30U); + msg.setDestination(18922U); + msg.setDestinationEntity(232U); + msg.uid = 174U; + msg.frag_number = 82U; + msg.num_frags = 181U; + const signed char tmp_msg_0[] = {56, 112, -71, 58, 4, 114, -76, -36, -5, 62, 84, 47}; + msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationEval #2", msg == *msg_d); + test.boolean("MessagePart #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22545,30 +25262,22 @@ main(void) } { - IMC::FormationControlParams msg; - msg.setTimeStamp(0.647454414593); - msg.setSource(44238U); - msg.setSourceEntity(185U); - msg.setDestination(28829U); - msg.setDestinationEntity(214U); - msg.action = 230U; - msg.lon_gain = 0.500585191126; - msg.lat_gain = 0.996800176009; - msg.bond_thick = 0.881815171738; - msg.lead_gain = 0.67691249203; - msg.deconfl_gain = 0.0371557827181; - msg.accel_switch_gain = 0.865943827977; - msg.safe_dist = 0.988580999563; - msg.deconflict_offset = 0.710758768183; - msg.accel_safe_margin = 0.981876827851; - msg.accel_lim_x = 0.141373089153; + IMC::NeptusBlob msg; + msg.setTimeStamp(0.3482069806356066); + msg.setSource(59064U); + msg.setSourceEntity(87U); + msg.setDestination(21491U); + msg.setDestinationEntity(219U); + msg.content_type.assign("BKTJDLZDJBZ"); + const signed char tmp_msg_0[] = {-16, 104, -5, 76, 3, -122, -31, 8, -31, -22, 90, 83, -81, -6, -102, 56, 36, 53, 118, 123, -13, -25, 71, 73, 100, -25, 14, 119, -61, 34, -39, 29, -62, -115, -23, -32, 111, -65, 75, -73, 25, -46, -68, 87, 92, 68, 36, -60, -52, -48, 87, -53, 13, 72, -81, -125, -71, -96, 65, 64, 78, 109, 80, -88, -81, 124, -38, -28, -63, -22, -98, 54, 3, -123, 90, 121, -2, -110, -68, 19, -28, 65, 51, 38, 53, -5, 45, -85, 53, 85, 120, -74, 71, 31, 53, 63, 23, 95, -46, -123, 77, -56, -75, 9, 122, -94, 98, 34, -24, -111, -117, 108, 108, -7, 18, -52, -63, -118, 47, -75, -106, -76, -47, 117, 50, -83, -39, 39, 44, -92, 65, 97, -50, -1, -64, -37, 94, -38, 45, -23, 27, 110, -15, -93, -5, 105, 61, -98, 46, -54, -85, -90, 73, 83, -17, 9, -12, -36, 75, 112, -21, 2, 4, 31, 79, 104, -15, 95, 0, -45, 19, -21, -83, 47, -114, -46, -15, 117, -79, 107, -37, 77, 13, 110, 42, 48, -88, -76, -75, -42, -14, 87, 101, -86, -47, 50}; + msg.content.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationControlParams #0", msg == *msg_d); + test.boolean("NeptusBlob #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22579,30 +25288,22 @@ main(void) } { - IMC::FormationControlParams msg; - msg.setTimeStamp(0.429576954735); - msg.setSource(62972U); - msg.setSourceEntity(56U); - msg.setDestination(48862U); - msg.setDestinationEntity(181U); - msg.action = 72U; - msg.lon_gain = 0.393501925273; - msg.lat_gain = 0.396571610111; - msg.bond_thick = 0.632263728593; - msg.lead_gain = 0.994217813529; - msg.deconfl_gain = 0.168880088369; - msg.accel_switch_gain = 0.0915869953742; - msg.safe_dist = 0.194524845267; - msg.deconflict_offset = 0.17919843556; - msg.accel_safe_margin = 0.0982854227646; - msg.accel_lim_x = 0.266415259261; + IMC::NeptusBlob msg; + msg.setTimeStamp(0.7975683511844079); + msg.setSource(37393U); + msg.setSourceEntity(17U); + msg.setDestination(56879U); + msg.setDestinationEntity(137U); + msg.content_type.assign("MJOMHXGROBVRTSTYPRNUAVVVLOKGCTAWAYUQWRZIJYBQIKNCTFRKZPMVCSGRONRXNWQWQMUTWPWODMQAVBBHLUHKNIFEOOTMQBPBWFPBOGEDPUVBWWMZGYJXDHSNZ"); + const signed char tmp_msg_0[] = {-67, 27, -68, -29, 105, 116, -22, -71, 30, 12, -67, -2, 103, -69, 18, -106, -37, 123, 50, -86, 117, 82, 77, 120, -98, 40, 80, -20, 38, 49, 72, -87, -21, -32, -48, 40, 56, 7, 100, 74, -39, 53, 1, -82, 100, -7, -104, 95, -50, 87, 63, -93, -51, -43, 54, 23, 62, 14, -127, -8, 35, -122, 55, 49, 43, -96, 92, 83, 7, -117, 30, 84, -22, 3, 57, -104, 119, 116, -89, -87, 64, -3, 61, 38, 35, 48, 2, 83, 87, 27, -16, -33, -116, 15, -30, -125, 44, 78, -123}; + msg.content.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationControlParams #1", msg == *msg_d); + test.boolean("NeptusBlob #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22613,30 +25314,22 @@ main(void) } { - IMC::FormationControlParams msg; - msg.setTimeStamp(0.770847287132); - msg.setSource(59365U); - msg.setSourceEntity(204U); - msg.setDestination(53551U); - msg.setDestinationEntity(186U); - msg.action = 162U; - msg.lon_gain = 0.992996268882; - msg.lat_gain = 0.546842588255; - msg.bond_thick = 0.561339475758; - msg.lead_gain = 0.275088201238; - msg.deconfl_gain = 0.678113116406; - msg.accel_switch_gain = 0.641235439894; - msg.safe_dist = 0.305700872104; - msg.deconflict_offset = 0.75955341397; - msg.accel_safe_margin = 0.956088923099; - msg.accel_lim_x = 0.117945027914; + IMC::NeptusBlob msg; + msg.setTimeStamp(0.728316666253619); + msg.setSource(32803U); + msg.setSourceEntity(110U); + msg.setDestination(7027U); + msg.setDestinationEntity(219U); + msg.content_type.assign("PNDCRMFZLQCWRYWNXHAMJFLTPKIHFGYAGLDVNEFQMPJGDMSVXRGDESUDGTSIMTCALCLHKWBGAHWSBFLYQ"); + const signed char tmp_msg_0[] = {82, 58, 88, 101, 58, 49, 68, 4, -69, 79, -74, -88, 60, 124, -58, 53, 52, 102, 46, 31, 47, 65, 60, 89, -90, 80, -86, -69, -56, 118, 4, 16, 123, 115, -65, 37, -95, -128, 101, -75, 103, -20, -52, 88, -118, -112, -94, -47, -75, -1, 29, -96, -75, 101, 47, -10, 123, -107, 55, -113, 48, -30, -72, 90, -82, 83, -84, -29, -10, -87, -33, 103, -126, 77, -48, 74, -69, -107, 14, -107, -79, 48, -32, 2, -114, 52, 62, -126, -119, -37, 59, -59, 81, 101, 121, -14, -65, 99, -16, 31, -34, 48, -8, -122, -30, -13, 68, 89, 100, -121, 43, -117, -102, -100, -13, 44, 68, 117, 107, 64, -123, -13, 82, -6, -123}; + msg.content.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationControlParams #2", msg == *msg_d); + test.boolean("NeptusBlob #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22647,39 +25340,19 @@ main(void) } { - IMC::FormationEvaluation msg; - msg.setTimeStamp(0.889944342395); - msg.setSource(32657U); - msg.setSourceEntity(23U); - msg.setDestination(17712U); - msg.setDestinationEntity(230U); - msg.type = 2U; - msg.op = 208U; - msg.err_mean = 0.509950505741; - msg.dist_min_abs = 0.599223361239; - msg.dist_min_mean = 0.240013897386; - msg.roll_rate_mean = 0.895859387568; - msg.time = 0.0632941092342; - IMC::FormationControlParams tmp_msg_0; - tmp_msg_0.action = 212U; - tmp_msg_0.lon_gain = 0.90514666381; - tmp_msg_0.lat_gain = 0.383804608839; - tmp_msg_0.bond_thick = 0.683233537322; - tmp_msg_0.lead_gain = 0.934280884477; - tmp_msg_0.deconfl_gain = 0.761693318191; - tmp_msg_0.accel_switch_gain = 0.114584135379; - tmp_msg_0.safe_dist = 0.624397416639; - tmp_msg_0.deconflict_offset = 0.127920795381; - tmp_msg_0.accel_safe_margin = 0.857408905575; - tmp_msg_0.accel_lim_x = 0.345624881682; - msg.controlparams.set(tmp_msg_0); + IMC::Aborted msg; + msg.setTimeStamp(0.8810458507186466); + msg.setSource(36899U); + msg.setSourceEntity(218U); + msg.setDestination(39887U); + msg.setDestinationEntity(102U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationEvaluation #0", msg == *msg_d); + test.boolean("Aborted #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22690,39 +25363,19 @@ main(void) } { - IMC::FormationEvaluation msg; - msg.setTimeStamp(0.758773681353); - msg.setSource(42919U); - msg.setSourceEntity(144U); - msg.setDestination(46919U); - msg.setDestinationEntity(110U); - msg.type = 88U; - msg.op = 168U; - msg.err_mean = 0.974236026577; - msg.dist_min_abs = 0.595918185134; - msg.dist_min_mean = 0.742640573343; - msg.roll_rate_mean = 0.902569384849; - msg.time = 0.670137805906; - IMC::FormationControlParams tmp_msg_0; - tmp_msg_0.action = 29U; - tmp_msg_0.lon_gain = 0.285273835716; - tmp_msg_0.lat_gain = 0.217180661559; - tmp_msg_0.bond_thick = 0.602678988618; - tmp_msg_0.lead_gain = 0.959170829443; - tmp_msg_0.deconfl_gain = 0.657019383611; - tmp_msg_0.accel_switch_gain = 0.745867602041; - tmp_msg_0.safe_dist = 0.178386610624; - tmp_msg_0.deconflict_offset = 0.643918900276; - tmp_msg_0.accel_safe_margin = 0.237044667287; - tmp_msg_0.accel_lim_x = 0.673245762262; - msg.controlparams.set(tmp_msg_0); + IMC::Aborted msg; + msg.setTimeStamp(0.33462714934591964); + msg.setSource(24809U); + msg.setSourceEntity(226U); + msg.setDestination(6819U); + msg.setDestinationEntity(57U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationEvaluation #1", msg == *msg_d); + test.boolean("Aborted #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22733,39 +25386,19 @@ main(void) } { - IMC::FormationEvaluation msg; - msg.setTimeStamp(0.842374871373); - msg.setSource(43307U); - msg.setSourceEntity(142U); - msg.setDestination(63581U); - msg.setDestinationEntity(87U); - msg.type = 233U; - msg.op = 189U; - msg.err_mean = 0.618020458529; - msg.dist_min_abs = 0.0451454197717; - msg.dist_min_mean = 0.742140355825; - msg.roll_rate_mean = 0.446931561104; - msg.time = 0.483732297601; - IMC::FormationControlParams tmp_msg_0; - tmp_msg_0.action = 41U; - tmp_msg_0.lon_gain = 0.716275016656; - tmp_msg_0.lat_gain = 0.923665944045; - tmp_msg_0.bond_thick = 0.0752335097039; - tmp_msg_0.lead_gain = 0.890732912628; - tmp_msg_0.deconfl_gain = 0.755851318263; - tmp_msg_0.accel_switch_gain = 0.249378651382; - tmp_msg_0.safe_dist = 0.0315396039888; - tmp_msg_0.deconflict_offset = 0.18596737169; - tmp_msg_0.accel_safe_margin = 0.238309665555; - tmp_msg_0.accel_lim_x = 0.038967760918; - msg.controlparams.set(tmp_msg_0); + IMC::Aborted msg; + msg.setTimeStamp(0.7634982448280602); + msg.setSource(27123U); + msg.setSourceEntity(120U); + msg.setDestination(24073U); + msg.setDestinationEntity(195U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("FormationEvaluation #2", msg == *msg_d); + test.boolean("Aborted #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22776,24 +25409,22 @@ main(void) } { - IMC::MessagePart msg; - msg.setTimeStamp(0.92639659287); - msg.setSource(46516U); - msg.setSourceEntity(20U); - msg.setDestination(55299U); - msg.setDestinationEntity(122U); - msg.uid = 235U; - msg.frag_number = 110U; - msg.num_frags = 16U; - const char tmp_msg_0[] = {58, -80, 78, -2, 41, -59, -91, -51, -59, -70, -54, 23, -7, 26, 31, 6, -97, 8, -42, 98, -7, -44, 20, 104, -48, 84, 40, 18, -13, 115, 60, 111, 30, -71, -114, 24, -68, -39, -40, -68, 45, 116, 30, -126, 64, -121, -33, -48, 46, 87, 14, 10, 7, -63, -51, 68, 97, 112, -23, -48, 41, 73, -71, -85, -80, 32, 97, 75, 0, 109, 73, 90, -19, 87, 98, -8, -59, 83, 95, 92, 65, 78, 60, -97, 14, 97, -58, -23, -89, 99, -44, -9, -64, 79, -88, 82, 67, -83, 95, 93, 12, 99, 3, -124, 0}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::UsblAngles msg; + msg.setTimeStamp(0.3984550126536436); + msg.setSource(47457U); + msg.setSourceEntity(87U); + msg.setDestination(51424U); + msg.setDestinationEntity(18U); + msg.target = 41263U; + msg.bearing = 0.6162025026305417; + msg.elevation = 0.9040434746952583; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MessagePart #0", msg == *msg_d); + test.boolean("UsblAngles #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22804,24 +25435,22 @@ main(void) } { - IMC::MessagePart msg; - msg.setTimeStamp(0.979358809447); - msg.setSource(40048U); - msg.setSourceEntity(150U); - msg.setDestination(57539U); - msg.setDestinationEntity(138U); - msg.uid = 37U; - msg.frag_number = 220U; - msg.num_frags = 7U; - const char tmp_msg_0[] = {-100, -9, 0, 53, -89, -68, 110, 56, 109, 55, -110, -117, 46, 93, -13, -76, -94, -20, 126, 59, -114, 45, -105, -31, -82, -85, -52, -75, -122, 12, -94, -30, -31, -7, 13, -58, -63, -6, -14, 55, -105, -63, -16, 118, -59, -21, 71, -48, 104, 118, 37, -48, -58, -38, 65, -11, 76, -6, 70, -5, -120, -106, 48, -117, -73, 98, 14, 72, 76, -111, 92, -122, 88, 88, -67, 65, 14, -77, 11, 114, 7, -116, -82, 44, -91, 114, 122, 66, 20, -107, -16, 98, 80, -36, 16, -43, 46, 41, 24, -122, 115, 54, 79, -98, 116, -53, 88, 84, 75, -9, -39, 115, 119, -111, 39, -46, -4, 77, 43, 92, -73, -58, -97, 103, -43, -42, -107, -43, 25, 39, 105, -21, -33, -89, -46, 90, 61, 45, 7, -70, 106, -112, 97, -5, -114, -115, -61, -39, -57, 51, 91, -118, 24, -4, -34, 4, -79, 101, 2, -53, -21, -94, 102, 109, 93, 122, -116, -112, -122, -102, 73, -117, -96, -89, -2, -25, 116, 103, -34, 96, 87}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::UsblAngles msg; + msg.setTimeStamp(0.0967732576633672); + msg.setSource(62656U); + msg.setSourceEntity(237U); + msg.setDestination(2036U); + msg.setDestinationEntity(1U); + msg.target = 14331U; + msg.bearing = 0.25204984568015043; + msg.elevation = 0.7571308033353829; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MessagePart #1", msg == *msg_d); + test.boolean("UsblAngles #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22832,24 +25461,22 @@ main(void) } { - IMC::MessagePart msg; - msg.setTimeStamp(0.999129474947); - msg.setSource(56402U); - msg.setSourceEntity(184U); - msg.setDestination(22006U); - msg.setDestinationEntity(97U); - msg.uid = 19U; - msg.frag_number = 47U; - msg.num_frags = 216U; - const char tmp_msg_0[] = {-35, 54, 18, 120, -108, 105, 54, -37, 78, 71, 7, -65, 85, -58, -96, 53, -67, 85, -72, 51, 74, 75, -20, 124, -21, -91, 30, -56, 105, 113, 55, -92, -89, 106, 101, 44, -65, 39, -97, -61, -84, 41, 80, 97, -12, -70, 120, 87, -84, -38, -53, -71, -28, -20, -20, -89, -40, 10, -64, 50, -115, 112, 9, -117, -37, -24, 108, -47, 63, -98, 51, 20, 122, -92, 17, 96, 33, -10, -126, 42, -81, -96, -59, -71, -114, -23, 98, 0, -122, -119, 70, -123, 123, -73, 23, -42, -72, 41, 10, 91, 92, -43, -122, 94, 45, 88, -40, 124, 58, -70, -40, -70, 48, -36, -66, -23, 73, -32, 72, -106, -43, -110, 99, -108, -59, 89, -24, -41, -43, -54, 80, 64, -47, 122, 121, -94, 5, 60, 85, -93, 108, -61, -90, -106, -32, 53, 2, 42, -27, -7, 117, 56, 73, -55, 13, -31, -42, 78, -14, 115, 71, 16}; - msg.data.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::UsblAngles msg; + msg.setTimeStamp(0.6581046517500989); + msg.setSource(23133U); + msg.setSourceEntity(150U); + msg.setDestination(43472U); + msg.setDestinationEntity(0U); + msg.target = 19081U; + msg.bearing = 0.4820714871288354; + msg.elevation = 0.34315565522182834; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("MessagePart #2", msg == *msg_d); + test.boolean("UsblAngles #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22860,22 +25487,23 @@ main(void) } { - IMC::NeptusBlob msg; - msg.setTimeStamp(0.64623832306); - msg.setSource(12382U); - msg.setSourceEntity(90U); - msg.setDestination(57361U); - msg.setDestinationEntity(219U); - msg.content_type.assign("VCGHPYXOFFSISFOTCBCVKRZDTNDJQZDOXLVINTYORZRRFXTGTIEXTWXAVSCAMCNDYVYPOCGTOXXQBEBESQKONRLLALHALBAWUGNPBQGDNZOUSSNQSJKSYZLRMEUFMXBPUNWHPLUQTYLAQLDIJGHCFTJFVEDUXOBKZABRJEKVJKMHQNNKADICAQAJUIPIBFGKHGJKHVI"); - const char tmp_msg_0[] = {48, 49, -98, 66, 55, -22, -122, 108, -47, 44, -88, -124, 17, -119, 123, 70, 93, 29, -121, -59, 87, -93, 106, 38, 69, -51, 40, -98, 25, 73, 73, -100, -74, 101, 104, -29, 39, -63, -105, 41, -97, 58, -106, 123, -13, -22, 95}; - msg.content.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::UsblPosition msg; + msg.setTimeStamp(0.2577689256280403); + msg.setSource(8686U); + msg.setSourceEntity(9U); + msg.setDestination(62736U); + msg.setDestinationEntity(136U); + msg.target = 52799U; + msg.x = 0.17423924524136403; + msg.y = 0.4492631919495865; + msg.z = 0.9347548089736651; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NeptusBlob #0", msg == *msg_d); + test.boolean("UsblPosition #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22886,22 +25514,23 @@ main(void) } { - IMC::NeptusBlob msg; - msg.setTimeStamp(0.286895884126); - msg.setSource(23664U); - msg.setSourceEntity(131U); - msg.setDestination(39252U); - msg.setDestinationEntity(182U); - msg.content_type.assign("ILAJDAWCSAKYSZGPJNQSKFGCODMQVNVGTVQAMKZZLMURUHYINAJGDMCZOVYFPNTWHMDFUYMPDQTTYIAJVWKJWSCTGPHBEEIUFIAGXHEOWELVXBOILWULNOPFFKKMAJYHZYWJSPCZBENBNHCSZUFPSCDEVSGDRVDIOAVTXCPROTRVERNPOXBBWQORRHUIFXBQSGKIXGXSDTTJPWYYORLKZRXTGMFYFULLNQKNXZHELBMWZUCQIMCJQHUEEBB"); - const char tmp_msg_0[] = {20, -69, -67, -40, -78, -28, -90, 121, 42, 38, -81, -60, -21, -78, 11, 79, 95, 51, 96, 59, 44, -3, -55, -69, 58, 111, 103, -35, -8, 40, 27, 61, -14, 119, 75, -84, -65, 94, 79, 24, -21, -124, 6, -27, -91, 60, -52, 18, -64, -90, -11, -27, 24, 21, 39, 29, -86, -28, 110, -76, -87, 40, -76, -95, -110, -6, -2, -112, 32, 18, -59, 63, -120, 125, 27, -128, 84, -99, -48, -17, 116, -77, 71, -68, -65, 48, -16, -30, -25, 22, -98, -79, 24, -60, 43, -44, -99, -66, 63, -29, 19, 77, -65, 116, -109, 6, -104, 92, -114, 8, -13, 1, 44, 16, -20, -104, 122, -5, -83, 64, -81, -100, -82, 20, -118, -100, 71, 11, 125, 57, -127, 29, -119, 0, -68, -68, 88, 96, 19, 41, 108, 30, 110, -21, -86, -1, 15, 100, -44, -68, 1, -28, 77, -119}; - msg.content.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::UsblPosition msg; + msg.setTimeStamp(0.9885711321392944); + msg.setSource(1921U); + msg.setSourceEntity(153U); + msg.setDestination(30458U); + msg.setDestinationEntity(51U); + msg.target = 61718U; + msg.x = 0.27481495470913175; + msg.y = 0.942546724371498; + msg.z = 0.31810172518563695; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NeptusBlob #1", msg == *msg_d); + test.boolean("UsblPosition #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22912,22 +25541,23 @@ main(void) } { - IMC::NeptusBlob msg; - msg.setTimeStamp(0.436389777383); - msg.setSource(14135U); - msg.setSourceEntity(198U); - msg.setDestination(25216U); - msg.setDestinationEntity(57U); - msg.content_type.assign("HFOBSIVWKISYKMJIJASWOYGNUZXTAWXHKYDPURBECCAIBZQELCLZMSBVCAAORDHUXGENDUGSUFQKEIYIWMTWKBYMBZXRVAOTDFAPMQRVPRZECZ"); - const char tmp_msg_0[] = {-65, 66, -123, 77, 96, 56, -33, -44, 99, -127, 93, 22, -80, 115, -60, 86, -108, -91, 31, -13, -67, 120, 40, 20, -88, 6, 37, 21, 15, -35, -107, -91, -2, 44, -94, -114, 92, -97, -59, 92, 34, -40, -100, 69, 75, -86, -82, -75, 47, -80, 13, 34, -127, 9, -50, -55, -88, -125, 119, -4, -23, 86, 91, -99, 64, 110, -111, -36, -60, -85, 42, -37, -33, -92, -121, 47, 123, -99, -40, 54, 108, 41, 82, -108, -104, -122, -124, 23, -74, 125, -63, 58, -64, 98, 18, -103, 32, -57, -124, 43, -60, -6, -58, -94, -69, 111, -115, -32, -30, 33, -75, 18, -110, -19, 92, -89, 100, -108, 121, -123, 2, 116, 91, 99, 32, 20, 124, 93, -86, 114, 123, 38, -26, -83, 21, 33, -85, -57, 50, -117, 103, 91, 107, 113, -115, 113, -10, -63, -39, -64, 41, 89, 97, -61, 11, -108, 21, -49, -54, -60, -46, 59, 11, 32, -60, -122, 100, -125, 21, 121, -2, -78, -25, 58, -50, -100, -51, 31, 18, 30, 20, 91, 56, -67, 1, -52, 37, 123, 96, -42, 61, -111, -102, 15, 75, -121, 116, -127, -86, 16, -85, 98, -64, -43, -11, 5, -60, 19, -104, -25, -92, 70, 115, -39, 5, 61, -111, -116, 73, -120, 36, 12, 91, 6, 84, 8, -45, -93, 84, -115, 71, 13, 126, -35, 51, -95, 78, -3, 8, -33, 88, 35, -22, -6, -126, 114, 8}; - msg.content.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::UsblPosition msg; + msg.setTimeStamp(0.37645055987747256); + msg.setSource(8286U); + msg.setSourceEntity(139U); + msg.setDestination(39110U); + msg.setDestinationEntity(194U); + msg.target = 61701U; + msg.x = 0.9250903606064241; + msg.y = 0.611578078640005; + msg.z = 0.8037267244540537; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("NeptusBlob #2", msg == *msg_d); + test.boolean("UsblPosition #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22938,19 +25568,24 @@ main(void) } { - IMC::Aborted msg; - msg.setTimeStamp(0.589517396668); - msg.setSource(35267U); - msg.setSourceEntity(206U); - msg.setDestination(57946U); - msg.setDestinationEntity(115U); + IMC::UsblFix msg; + msg.setTimeStamp(0.22603451186755075); + msg.setSource(6140U); + msg.setSourceEntity(86U); + msg.setDestination(25720U); + msg.setDestinationEntity(129U); + msg.target = 2325U; + msg.lat = 0.010796851358610304; + msg.lon = 0.3404179303192394; + msg.z_units = 7U; + msg.z = 0.26640224464545403; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Aborted #0", msg == *msg_d); + test.boolean("UsblFix #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22961,19 +25596,24 @@ main(void) } { - IMC::Aborted msg; - msg.setTimeStamp(0.72280199822); - msg.setSource(16358U); - msg.setSourceEntity(216U); - msg.setDestination(35063U); - msg.setDestinationEntity(112U); + IMC::UsblFix msg; + msg.setTimeStamp(0.42523898705386975); + msg.setSource(32036U); + msg.setSourceEntity(87U); + msg.setDestination(1319U); + msg.setDestinationEntity(124U); + msg.target = 35451U; + msg.lat = 0.9136032391139104; + msg.lon = 0.9807731727716384; + msg.z_units = 250U; + msg.z = 0.4109350154981123; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Aborted #1", msg == *msg_d); + test.boolean("UsblFix #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -22984,19 +25624,24 @@ main(void) } { - IMC::Aborted msg; - msg.setTimeStamp(0.655624882358); - msg.setSource(35676U); - msg.setSourceEntity(236U); - msg.setDestination(17123U); - msg.setDestinationEntity(79U); + IMC::UsblFix msg; + msg.setTimeStamp(0.39265215762818095); + msg.setSource(47455U); + msg.setSourceEntity(57U); + msg.setDestination(56485U); + msg.setDestinationEntity(100U); + msg.target = 43451U; + msg.lat = 0.05393919950489845; + msg.lon = 0.759382037807919; + msg.z_units = 209U; + msg.z = 0.6389968375725321; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Aborted #2", msg == *msg_d); + test.boolean("UsblFix #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23007,22 +25652,22 @@ main(void) } { - IMC::UsblAngles msg; - msg.setTimeStamp(0.418040528522); - msg.setSource(38959U); - msg.setSourceEntity(61U); - msg.setDestination(58018U); - msg.setDestinationEntity(57U); - msg.target = 44525U; - msg.bearing = 0.680876959502; - msg.elevation = 0.102949844895; + IMC::ParametersXml msg; + msg.setTimeStamp(0.7145476353821256); + msg.setSource(47291U); + msg.setSourceEntity(210U); + msg.setDestination(47772U); + msg.setDestinationEntity(53U); + msg.locale.assign("OPAJNCYTTXWMBWYQWGUJZDJFCFWZLLOVJUTSZYPQYIOFRCNMRCDFXVMZCCRGQ"); + const signed char tmp_msg_0[] = {-5, -10, 124, -111, 33, 59, 119, 8, -105, 121, -38, 104, 110, -43, -20, -64, 107, -19, -70, -81, 27, 102, -1, 62, 123, -105, -120, -8, 90, -103, -12, -80, -127, 21, 98, 115, -16, -15, -88, -114, -98, 61, -45, -128, 14, 87, -47, 43, 46, -118, -56, -84, 93, 100, -42, 30, -90, 67, 64, -59, 18, 123, 9, 10, -42, -11, 106, -61, 0, 84, -35, -84, 100, 59, -17, 19, 46, -7, -121, -93, -41, -63, -53, -78, -48, -81, 105, 30, -9, -116, 100, 114, 43, 109, 0, -98, 27, -37, -46, 5, 7, -107, 93, -45, 39, 95, -2, 6, 11, 117, -25, 109, 113, -33, 115, 48, 6, 29, 89, -17, 67, -81, -54, -1, 111, -46, -66, 74, 68, -53, 16, 58, 35, -118, -13, 102, 98, -17, -44, 89, 41, 74, 119, -70}; + msg.config.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblAngles #0", msg == *msg_d); + test.boolean("ParametersXml #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23033,22 +25678,22 @@ main(void) } { - IMC::UsblAngles msg; - msg.setTimeStamp(0.268543767078); - msg.setSource(23311U); - msg.setSourceEntity(156U); - msg.setDestination(24401U); - msg.setDestinationEntity(68U); - msg.target = 16870U; - msg.bearing = 0.66470812183; - msg.elevation = 0.732665407045; + IMC::ParametersXml msg; + msg.setTimeStamp(0.5168023771984732); + msg.setSource(39332U); + msg.setSourceEntity(210U); + msg.setDestination(28497U); + msg.setDestinationEntity(27U); + msg.locale.assign("FRKBQLUCIDXYDLDNUYCYJHDFUOYBBKUPBFMGQJEOZLYTYWIRASJHSPWUDJHMXOFSSJXXIVPJDTJELXIEVSKXMWXPRENPLOBIJLR"); + const signed char tmp_msg_0[] = {-73, -68, 125, -66, -40, 124, 117, 122, -87, -31, 79, 58, -105, 19, -22, -99, -102, 68, -12, 126, 36, 8, 37, -128, 46, 39, -96, 110, 108, -30, -105, 110, 67, 60, -7, 39, 76, -61, -87, 117, 30, -101, 8, 24, -76, -106, -14, 63, 29, -100, 74, 28, 65, -107, 11, 48, 44, -123, 14, 69, 91, 48, 73, 63, -1, 39, -83, 0, -55, -112, -109, 76, 75, -28, 62, 124, -9, 41, 102, 66, -65, -6, 40, 54, -114, -120, 36, -104, 83, 67, -91, 18, 26, -91, 42, 45, 40, -42, -12, 16, -26, -86, 80, -3, -66, 51, -30, 73, -107, -92, -3, -22, 115, -126, 119, -125, -77, 72, 73, 87, 125, -100, 26, -122, 76, 121, 85, -99, 45, 75, 104, -96, -111, -75, -108, -110, 97, 114, -124, 8, -28, 102, -102, 113, 84, -52, -114, -62, 24, 8, 78, -95}; + msg.config.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblAngles #1", msg == *msg_d); + test.boolean("ParametersXml #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23059,22 +25704,22 @@ main(void) } { - IMC::UsblAngles msg; - msg.setTimeStamp(0.885486968803); - msg.setSource(62815U); - msg.setSourceEntity(153U); - msg.setDestination(10630U); - msg.setDestinationEntity(91U); - msg.target = 53896U; - msg.bearing = 0.930941861494; - msg.elevation = 0.286862970904; + IMC::ParametersXml msg; + msg.setTimeStamp(0.7426408452052733); + msg.setSource(62232U); + msg.setSourceEntity(80U); + msg.setDestination(15432U); + msg.setDestinationEntity(222U); + msg.locale.assign("NQMJIVBZGEINTROCRZWUQYQBTPGLVETZLAFYTKUHSTFAYNFZZIRGKVLHEXZEGXFREQJSJOCUW"); + const signed char tmp_msg_0[] = {-43, -124, 100, 106, -38, -68, 47, -62, 114, 109, 126, -74, -1, 19, -108, -119, -26, 26, 100, 91, 115, -94, -84, 39, -54, 70, -88, -15, -75, -64, 51, 51, 51, -11, -123, -7, 29, -24, -61, -17, 18, -111, -101, -77, -6, 78, 15, 126, 113, -69, 108, -66, 85, -68, 23, -78, -64, -36, 121, 117, -94, -64, 80, 53, 85, -111, 51, 59, -9, -73, -48, -102, -43, -37, -123, -113, -92, -80, -28, -57, -123, 8, 38, 86, -95, -59, -9, 44, -5, 100, -114, -60, 57, 40, -40, 105, 90, -17, 81, 62, -38, 38, -66, -22, -68, 77, -102, 45, 43, 36, 42, -20, -118, -4, -70, 101, 33, 7, -47, -65, 87, -65, 46, 91, -7, 78, 51, -32, 30, 50, -38, 110, 68, 76, 15, 55, -53, -69, 124, 27, 96, -103, 60, -122, -125, -77, 61, -120, -57, -121, -12, 39, 2, 32, 28, 72, -76, 51, -108, -83, 23, 124, 21, -77, -91, 8, 18, 121, -114, 8, -18, -55, -40, 80, 54, 43, -18, 92, 117, -113, -21, -30, -112, 50, -9, -67, -45, 9}; + msg.config.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblAngles #2", msg == *msg_d); + test.boolean("ParametersXml #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23085,23 +25730,19 @@ main(void) } { - IMC::UsblPosition msg; - msg.setTimeStamp(0.962985326336); - msg.setSource(13471U); - msg.setSourceEntity(105U); - msg.setDestination(11563U); - msg.setDestinationEntity(157U); - msg.target = 39864U; - msg.x = 0.674523125996; - msg.y = 0.0853043687025; - msg.z = 0.277672366246; + IMC::GetParametersXml msg; + msg.setTimeStamp(0.721014208527625); + msg.setSource(10640U); + msg.setSourceEntity(195U); + msg.setDestination(14650U); + msg.setDestinationEntity(8U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblPosition #0", msg == *msg_d); + test.boolean("GetParametersXml #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23112,23 +25753,19 @@ main(void) } { - IMC::UsblPosition msg; - msg.setTimeStamp(0.326401072815); - msg.setSource(54051U); - msg.setSourceEntity(198U); - msg.setDestination(58339U); - msg.setDestinationEntity(54U); - msg.target = 4290U; - msg.x = 0.981551821421; - msg.y = 0.442619206508; - msg.z = 0.137988776544; + IMC::GetParametersXml msg; + msg.setTimeStamp(0.011604001647227968); + msg.setSource(61557U); + msg.setSourceEntity(47U); + msg.setDestination(60270U); + msg.setDestinationEntity(170U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblPosition #1", msg == *msg_d); + test.boolean("GetParametersXml #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23139,23 +25776,19 @@ main(void) } { - IMC::UsblPosition msg; - msg.setTimeStamp(0.933583585817); - msg.setSource(63032U); - msg.setSourceEntity(170U); - msg.setDestination(64737U); - msg.setDestinationEntity(106U); - msg.target = 42732U; - msg.x = 0.399095702252; - msg.y = 0.474350330161; - msg.z = 0.171130458689; + IMC::GetParametersXml msg; + msg.setTimeStamp(0.7362436229239887); + msg.setSource(63231U); + msg.setSourceEntity(54U); + msg.setDestination(5263U); + msg.setDestinationEntity(236U); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblPosition #2", msg == *msg_d); + test.boolean("GetParametersXml #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23166,24 +25799,22 @@ main(void) } { - IMC::UsblFix msg; - msg.setTimeStamp(0.198086503739); - msg.setSource(60260U); - msg.setSourceEntity(213U); - msg.setDestination(23662U); - msg.setDestinationEntity(220U); - msg.target = 36038U; - msg.lat = 0.314246232673; - msg.lon = 0.474577293612; - msg.z_units = 195U; - msg.z = 0.576304992301; + IMC::SetImageCoords msg; + msg.setTimeStamp(0.5039114659148458); + msg.setSource(58859U); + msg.setSourceEntity(18U); + msg.setDestination(30618U); + msg.setDestinationEntity(185U); + msg.camid = 54U; + msg.x = 2537U; + msg.y = 61030U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblFix #0", msg == *msg_d); + test.boolean("SetImageCoords #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23194,24 +25825,22 @@ main(void) } { - IMC::UsblFix msg; - msg.setTimeStamp(0.83436018148); - msg.setSource(3809U); - msg.setSourceEntity(136U); - msg.setDestination(3770U); - msg.setDestinationEntity(231U); - msg.target = 1765U; - msg.lat = 0.39013895399; - msg.lon = 0.824791671305; - msg.z_units = 235U; - msg.z = 0.219176022411; + IMC::SetImageCoords msg; + msg.setTimeStamp(0.8162861403426671); + msg.setSource(32429U); + msg.setSourceEntity(134U); + msg.setDestination(48223U); + msg.setDestinationEntity(140U); + msg.camid = 226U; + msg.x = 15017U; + msg.y = 39824U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblFix #1", msg == *msg_d); + test.boolean("SetImageCoords #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23222,24 +25851,22 @@ main(void) } { - IMC::UsblFix msg; - msg.setTimeStamp(0.437372663312); - msg.setSource(15644U); - msg.setSourceEntity(164U); - msg.setDestination(37654U); - msg.setDestinationEntity(197U); - msg.target = 46438U; - msg.lat = 0.723286661692; - msg.lon = 0.336982749301; - msg.z_units = 194U; - msg.z = 0.089132254737; + IMC::SetImageCoords msg; + msg.setTimeStamp(0.8355960606783601); + msg.setSource(40899U); + msg.setSourceEntity(4U); + msg.setDestination(9410U); + msg.setDestinationEntity(84U); + msg.camid = 204U; + msg.x = 38185U; + msg.y = 61787U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblFix #2", msg == *msg_d); + test.boolean("SetImageCoords #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23250,22 +25877,22 @@ main(void) } { - IMC::ParametersXml msg; - msg.setTimeStamp(0.0686258496663); - msg.setSource(1751U); - msg.setSourceEntity(83U); - msg.setDestination(50527U); - msg.setDestinationEntity(23U); - msg.locale.assign("PXVEJXEISPMFETESAWMQUTYXHQRZGNOIPLUNQMKWCYRKEIHXIUYZND"); - const char tmp_msg_0[] = {-21, 95, -117, -114, -62, 87, -48, 76, 12, 104, -82, 59, 86, 75, -1, -83, -92, 29, -24, 23, 99, -92, -47, -105, -73, 119, 121, 54, -53, 75, 102, 117, -78, -10, 34, -18, -77, 34, -5, 71, -66, 104, -9, 100, 83, -77, -86, 112, -15, 56, 0, -37, 114, -125, -65, -81, -78, 14, 57, -9, -104, 82, -114, 60, 34, 72, -40, 116, -70, -24, -31, -111, 27, 52, 12, 25, -34, 101, 80, 28, 29, -128, -80, 30, 8, -117, -125, -23, 29, 97, -90, 49, 76, 35, -62, -15, 95, 59, 50, -1, 126, 101, 66, 56, -59, -87, 118, -95, 80, 119, 68, 87, -20, -70, -11, 113, -33, -52, -4, -101, -93, 65, -67, -91, 17, -124, 69, -118, -29, -91, -28, -69, -72, -96, -80, 90, -39, 40, 0, 55, -114, -28, 28, 11, 31, -6, -3, -106, 126, 100, 91, 50, 97, -29, -109, 121, -36, -102, 3, -103, 29, 35, -106, -83, 74, 48, -99, -52, -69, -118, -44, 58, 51, -41, -120, -30, -36, 38, 88, 49, -44, 31, 45, -19, -64, -2, -52, 13, 86, 77, 91, -3, -41, 57, 65, 66, 30, -58, 87, 117, 117, -1, 110, 113, -6, -79, -114, 61, 34, 23, 30, -113, 110, 100, 52, -96, -121, 37, -57, 89, -80, 9, -6, 13, 100, -90, -77, -2, -105, -70, 7, -89, -122, -123, -125, -31, 101, 17, -91, -45, 89, 88}; - msg.config.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::GetImageCoords msg; + msg.setTimeStamp(0.5798034618611773); + msg.setSource(18562U); + msg.setSourceEntity(202U); + msg.setDestination(42395U); + msg.setDestinationEntity(190U); + msg.camid = 79U; + msg.x = 14509U; + msg.y = 12498U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ParametersXml #0", msg == *msg_d); + test.boolean("GetImageCoords #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23276,22 +25903,22 @@ main(void) } { - IMC::ParametersXml msg; - msg.setTimeStamp(0.428493975427); - msg.setSource(58431U); - msg.setSourceEntity(30U); - msg.setDestination(51049U); - msg.setDestinationEntity(218U); - msg.locale.assign("POFWBPNAAJLZXVJJUGOQFLYLTEYRSCQPYIJHTZHWMLICUOEDTIKMXEGWS"); - const char tmp_msg_0[] = {20, -77, -55, 101, 1, -9, -40, -124, 111, -125, 79, -106, -65, 85, -51, -27, -31, 37, 119, 84, 78, -38, 54, -45, 57, -15, -38, -75, 50, 8, -122, 87, 76, -93, 83, 13, 35, 13, 124, 34, 50, -35, 35, 26, -2, -73, 101, -11, 42, -10, -43, 9, -63, 46, 116, -80, -55, 75, -112, 4, -39}; - msg.config.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::GetImageCoords msg; + msg.setTimeStamp(0.6326457663757332); + msg.setSource(4599U); + msg.setSourceEntity(108U); + msg.setDestination(39992U); + msg.setDestinationEntity(201U); + msg.camid = 1U; + msg.x = 14972U; + msg.y = 40695U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ParametersXml #1", msg == *msg_d); + test.boolean("GetImageCoords #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23302,22 +25929,22 @@ main(void) } { - IMC::ParametersXml msg; - msg.setTimeStamp(0.295346969039); - msg.setSource(5234U); - msg.setSourceEntity(54U); - msg.setDestination(47562U); - msg.setDestinationEntity(90U); - msg.locale.assign("QSSNTYKHIJYFPQOPKDFVUOIVOYAUVMKMXTTXQZQMOOZGBN"); - const char tmp_msg_0[] = {-105, -73, -5, 102, 86, 94, 63, 49, 62, 57, -104, -1, -97, 114, -70, 115, 46, 93, 86, -64, 81, -24, -121, -118, -114, -59, 110, 10, 125, 65, -127, 70, 59, 93, -81, -79, -44, 42, 84, 49, -74, -52, -53, -100, -90, -80, -111, 107, 86, 73, -30, -80, -71, -88, -106, -33, -28, -34, -25, -113, -4, 103, -42, 20, -111, 56, 13, 49, 109, -90, 24, -4, -66, 48, -105, -98, 52, -67, 58, -46, -90, -3, -52, -19, -84, -57, 79, 87, -102, -74, -69, 77, 97, -10, -53, 53, -126, -61, 33, -95, -20}; - msg.config.assign(tmp_msg_0, tmp_msg_0 + sizeof(tmp_msg_0)); + IMC::GetImageCoords msg; + msg.setTimeStamp(0.46379827222373793); + msg.setSource(24297U); + msg.setSourceEntity(240U); + msg.setDestination(1669U); + msg.setDestinationEntity(144U); + msg.camid = 35U; + msg.x = 24117U; + msg.y = 44409U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ParametersXml #2", msg == *msg_d); + test.boolean("GetImageCoords #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23328,19 +25955,25 @@ main(void) } { - IMC::GetParametersXml msg; - msg.setTimeStamp(0.706767836523); - msg.setSource(54141U); - msg.setSourceEntity(39U); - msg.setDestination(8355U); - msg.setDestinationEntity(157U); + IMC::GetWorldCoordinates msg; + msg.setTimeStamp(0.6029736078357169); + msg.setSource(30107U); + msg.setSourceEntity(115U); + msg.setDestination(61048U); + msg.setDestinationEntity(75U); + msg.tracking = 86U; + msg.lat = 0.8436335507488552; + msg.lon = 0.4830769291138598; + msg.x = 0.16712147048426518; + msg.y = 0.6836662739922298; + msg.z = 0.550352698319298; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetParametersXml #0", msg == *msg_d); + test.boolean("GetWorldCoordinates #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23351,19 +25984,25 @@ main(void) } { - IMC::GetParametersXml msg; - msg.setTimeStamp(0.997509128093); - msg.setSource(51714U); - msg.setSourceEntity(131U); - msg.setDestination(8711U); - msg.setDestinationEntity(19U); + IMC::GetWorldCoordinates msg; + msg.setTimeStamp(0.9288444762927703); + msg.setSource(2795U); + msg.setSourceEntity(5U); + msg.setDestination(15254U); + msg.setDestinationEntity(248U); + msg.tracking = 198U; + msg.lat = 0.8846292954122275; + msg.lon = 0.02776757788462836; + msg.x = 0.8557699562554645; + msg.y = 0.29583963021779947; + msg.z = 0.6838929846086028; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetParametersXml #1", msg == *msg_d); + test.boolean("GetWorldCoordinates #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23374,19 +26013,25 @@ main(void) } { - IMC::GetParametersXml msg; - msg.setTimeStamp(0.868045801194); - msg.setSource(45341U); - msg.setSourceEntity(240U); - msg.setDestination(18150U); - msg.setDestinationEntity(167U); + IMC::GetWorldCoordinates msg; + msg.setTimeStamp(0.11442692272790689); + msg.setSource(37115U); + msg.setSourceEntity(23U); + msg.setDestination(23229U); + msg.setDestinationEntity(54U); + msg.tracking = 41U; + msg.lat = 0.19553226994113693; + msg.lon = 0.7115057763095805; + msg.x = 0.4988516399527291; + msg.y = 0.7574194949667606; + msg.z = 0.6255652502661341; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetParametersXml #2", msg == *msg_d); + test.boolean("GetWorldCoordinates #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23397,22 +26042,28 @@ main(void) } { - IMC::SetImageCoords msg; - msg.setTimeStamp(0.855464822145); - msg.setSource(45613U); - msg.setSourceEntity(69U); - msg.setDestination(50286U); - msg.setDestinationEntity(151U); - msg.camid = 181U; - msg.x = 3135U; - msg.y = 45705U; + IMC::UsblAnglesExtended msg; + msg.setTimeStamp(0.3549163444270619); + msg.setSource(2993U); + msg.setSourceEntity(33U); + msg.setDestination(64048U); + msg.setDestinationEntity(160U); + msg.target.assign("JUWPSDQYYCEDEYCEMSRQMBMVUBTDLPOSEGYMSKRADLZKDFMKNZIWBJFRKTVXNBVQLXUTYGARRDJOVALKYBWFNFUPCALFOUOVRHFEAZWVQXVKHXUWUFQRAHSWIMOBLOCZDSBTOCHPEDGGTDREXTKQHNYNNMKOQVVZZZLXYCIEFWUMMNOI"); + msg.lbearing = 0.8994593578743187; + msg.lelevation = 0.42312643997086963; + msg.bearing = 0.4835532676212657; + msg.elevation = 0.9144257503097709; + msg.phi = 0.276034640640873; + msg.theta = 0.5521556141989512; + msg.psi = 0.5014317114140882; + msg.accuracy = 0.1028638441269426; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetImageCoords #0", msg == *msg_d); + test.boolean("UsblAnglesExtended #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23423,22 +26074,28 @@ main(void) } { - IMC::SetImageCoords msg; - msg.setTimeStamp(0.217010772719); - msg.setSource(41300U); - msg.setSourceEntity(202U); - msg.setDestination(14693U); - msg.setDestinationEntity(52U); - msg.camid = 113U; - msg.x = 57739U; - msg.y = 28694U; + IMC::UsblAnglesExtended msg; + msg.setTimeStamp(0.5723511852041121); + msg.setSource(59890U); + msg.setSourceEntity(49U); + msg.setDestination(33552U); + msg.setDestinationEntity(193U); + msg.target.assign("YQQZCPXIPBLXRCKSAJENYEMMXVEBFQCSUSLEUVUMKJSOWHXBDKFYINTMNFWTVKWJKQBUZWIHRXDCTHGHCILMMXWOHZEQWZTILRPTEJWWGFHUVYGNNRVMKLOISIPSDKY"); + msg.lbearing = 0.47197863680725827; + msg.lelevation = 0.9552915680870245; + msg.bearing = 0.66026660338498; + msg.elevation = 0.5695357619828793; + msg.phi = 0.6374400783834167; + msg.theta = 0.42899253485855215; + msg.psi = 0.10491749771973602; + msg.accuracy = 0.7093130554208835; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetImageCoords #1", msg == *msg_d); + test.boolean("UsblAnglesExtended #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23449,22 +26106,28 @@ main(void) } { - IMC::SetImageCoords msg; - msg.setTimeStamp(0.27044601753); - msg.setSource(54183U); - msg.setSourceEntity(97U); - msg.setDestination(60142U); - msg.setDestinationEntity(104U); - msg.camid = 158U; - msg.x = 27987U; - msg.y = 28722U; + IMC::UsblAnglesExtended msg; + msg.setTimeStamp(0.6833635488502986); + msg.setSource(3054U); + msg.setSourceEntity(90U); + msg.setDestination(16536U); + msg.setDestinationEntity(106U); + msg.target.assign("UCHPQFQEEBBDXKNKNQUCEGOZTXSSYEEJWGRSNJVAZTKGEIRVCHBLZBNVCWJQUDGGSBKIJUBLXFJFJDELYIFHMXMLZJGHVNLVXNPZRTHOCSIVXPJIKVUOTMSOSKWMGEFISDQPFWXDGVRVPZXQZYGAUQPAKRYCRDWAMFYPLHATMYTZYIUGQYZTLKQFNHJCVLBBKAIURWANFDHBQPIIYAOSDMNNCDJCZRUOWBYTR"); + msg.lbearing = 0.10390336593104998; + msg.lelevation = 0.4483776189582388; + msg.bearing = 0.8830565496371435; + msg.elevation = 0.5255056780935725; + msg.phi = 0.5989551849396707; + msg.theta = 0.1076426635462503; + msg.psi = 0.7334447697074711; + msg.accuracy = 0.05601829564889638; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SetImageCoords #2", msg == *msg_d); + test.boolean("UsblAnglesExtended #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23475,22 +26138,30 @@ main(void) } { - IMC::GetImageCoords msg; - msg.setTimeStamp(0.667971715648); - msg.setSource(56949U); - msg.setSourceEntity(210U); - msg.setDestination(56888U); - msg.setDestinationEntity(57U); - msg.camid = 48U; - msg.x = 36042U; - msg.y = 11108U; + IMC::UsblPositionExtended msg; + msg.setTimeStamp(0.19445001356675107); + msg.setSource(61855U); + msg.setSourceEntity(182U); + msg.setDestination(4047U); + msg.setDestinationEntity(97U); + msg.target.assign("EOEEBGGTIGKRFDTJUUENMDHNZSRJZTQPTVOWLVWQHZAHYWSWWEAEDALCBBNGXJYFPPCYGBYAIMUGERZWJKIOWNICKU"); + msg.x = 0.6713173900285674; + msg.y = 0.6876007366033856; + msg.z = 0.4252470375516896; + msg.n = 0.8725497822383171; + msg.e = 0.6201971601782074; + msg.d = 0.4958938207121353; + msg.phi = 0.7000841328062549; + msg.theta = 0.9439678489453964; + msg.psi = 0.32223614094090625; + msg.accuracy = 0.40906191529947167; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetImageCoords #0", msg == *msg_d); + test.boolean("UsblPositionExtended #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23501,22 +26172,30 @@ main(void) } { - IMC::GetImageCoords msg; - msg.setTimeStamp(0.989052432243); - msg.setSource(45442U); - msg.setSourceEntity(7U); - msg.setDestination(42721U); - msg.setDestinationEntity(97U); - msg.camid = 58U; - msg.x = 61758U; - msg.y = 41664U; + IMC::UsblPositionExtended msg; + msg.setTimeStamp(0.6182188789651092); + msg.setSource(23090U); + msg.setSourceEntity(161U); + msg.setDestination(49384U); + msg.setDestinationEntity(163U); + msg.target.assign("WKDZTYPMTVUWFUUTPNNKQVHBHARVSDIJTHKIAZQYRHNJJUEWYVOHXNYXRPJMAVCISPUBUKFOJEGWLLCLVICMKXEFQNWWZMZEFDGPGQYMXCPDBRDXSRMJFSRAACXKYRBDOPXCZLHQSDLMXMFGLOOWPTQBWGTBIOODSDILNGRQVH"); + msg.x = 0.4518237119006947; + msg.y = 0.4349914124249262; + msg.z = 0.8028044364395301; + msg.n = 0.4113231341527046; + msg.e = 0.7176014654782904; + msg.d = 0.14808276717476432; + msg.phi = 0.32833955583689656; + msg.theta = 0.5762800154425168; + msg.psi = 0.5252818895760223; + msg.accuracy = 0.17661060037097165; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetImageCoords #1", msg == *msg_d); + test.boolean("UsblPositionExtended #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23527,22 +26206,30 @@ main(void) } { - IMC::GetImageCoords msg; - msg.setTimeStamp(0.43439547681); - msg.setSource(65258U); - msg.setSourceEntity(253U); - msg.setDestination(14204U); - msg.setDestinationEntity(77U); - msg.camid = 149U; - msg.x = 30035U; - msg.y = 13660U; + IMC::UsblPositionExtended msg; + msg.setTimeStamp(0.9523357482597657); + msg.setSource(62959U); + msg.setSourceEntity(210U); + msg.setDestination(53267U); + msg.setDestinationEntity(139U); + msg.target.assign("XDLKKCRTSMAQUKBRXYYKQAYAFSXNEFZQLBSGLWZCLDZOGKYZLDPLIHXFMMECJEBVRYIEEVOPOSOUDNVTVTMGGEJWDGJYGIXXDEHQWMBPFRONJBYPTXUMNATICLQONZCPHUHDBZRUDPTTANLKUOJKMGVWXSIJRKRJUEJALGBIGIZPSZLAQRRMBAUCUQSFWWZJWSECHSOQFHCCFCPMNVKIDIPSNFYHN"); + msg.x = 0.1883854787127962; + msg.y = 0.2958262773046083; + msg.z = 0.1453257571204647; + msg.n = 0.6000027091548118; + msg.e = 0.04676583907109588; + msg.d = 0.9906374141799102; + msg.phi = 0.17941080474105064; + msg.theta = 0.8263673145809342; + msg.psi = 0.4001965611283981; + msg.accuracy = 0.9077395374565385; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetImageCoords #2", msg == *msg_d); + test.boolean("UsblPositionExtended #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23553,25 +26240,25 @@ main(void) } { - IMC::GetWorldCoordinates msg; - msg.setTimeStamp(0.374099512977); - msg.setSource(63751U); - msg.setSourceEntity(22U); - msg.setDestination(47716U); - msg.setDestinationEntity(157U); - msg.tracking = 214U; - msg.lat = 0.826724397583; - msg.lon = 0.0270388111872; - msg.x = 0.146279202083; - msg.y = 0.855408722061; - msg.z = 0.784984894321; + IMC::UsblFixExtended msg; + msg.setTimeStamp(0.7148189684642868); + msg.setSource(15467U); + msg.setSourceEntity(67U); + msg.setDestination(14860U); + msg.setDestinationEntity(97U); + msg.target.assign("TVNRYFMBAQGPMEJYDOSFXDFPQIFYJFLM"); + msg.lat = 0.9655846552017894; + msg.lon = 0.49396419172381156; + msg.z_units = 153U; + msg.z = 0.8994089334455873; + msg.accuracy = 0.19054098307678147; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetWorldCoordinates #0", msg == *msg_d); + test.boolean("UsblFixExtended #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23582,25 +26269,25 @@ main(void) } { - IMC::GetWorldCoordinates msg; - msg.setTimeStamp(0.312180800371); - msg.setSource(33471U); - msg.setSourceEntity(140U); - msg.setDestination(12386U); - msg.setDestinationEntity(166U); - msg.tracking = 12U; - msg.lat = 0.271094845108; - msg.lon = 0.959847388357; - msg.x = 0.27252910144; - msg.y = 0.0625135707308; - msg.z = 0.327582226523; + IMC::UsblFixExtended msg; + msg.setTimeStamp(0.39375664301251034); + msg.setSource(4608U); + msg.setSourceEntity(114U); + msg.setDestination(30610U); + msg.setDestinationEntity(196U); + msg.target.assign("JAYISRYYTGNMXCBLSQMUXHWVZFEDHITVXBURUZYYINAEFAGOEFMUGDIJAJGBXFWTKUTPIJEXKLTNKTUYFPHMUZZWGVRTDOJVWPPQXFFAHJKFDLPWQVBYLSIVSNCNTQDKTLRDCHXMPWOZAEUEQOSQZLWBRADKBECLIMYNLKRCHOKGZQEBKORZINDNFPQVCDRCHPJHV"); + msg.lat = 0.23036029718757633; + msg.lon = 0.38395433290273495; + msg.z_units = 186U; + msg.z = 0.74594478014882; + msg.accuracy = 0.9169911363968806; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetWorldCoordinates #1", msg == *msg_d); + test.boolean("UsblFixExtended #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23611,25 +26298,25 @@ main(void) } { - IMC::GetWorldCoordinates msg; - msg.setTimeStamp(0.52159674908); - msg.setSource(37151U); - msg.setSourceEntity(224U); - msg.setDestination(12544U); - msg.setDestinationEntity(65U); - msg.tracking = 104U; - msg.lat = 0.191228845652; - msg.lon = 0.761190051264; - msg.x = 0.84439013793; - msg.y = 0.740519368561; - msg.z = 0.108632821846; + IMC::UsblFixExtended msg; + msg.setTimeStamp(0.6793907739231716); + msg.setSource(19203U); + msg.setSourceEntity(141U); + msg.setDestination(65249U); + msg.setDestinationEntity(121U); + msg.target.assign("CVYJSPJEFRLVVVITPCZDZVINHMUWFJSPMZYNKNOAXTRMDOEXMIXCCMOTJLALQSWXWOMPZMGYFHKDYGHMGURQUITDFFYCAGLNPRLOAJDIVQUJBCWEUSZRABHQICLPRXVYTZLGYXHVZKKUPKXPCGIBITUWSQEKUPWVOFAYHDHGKRKPJTJTDARDREQXBGO"); + msg.lat = 0.20232359082626905; + msg.lon = 0.9173907931763776; + msg.z_units = 250U; + msg.z = 0.573961756577939; + msg.accuracy = 0.7905627073892988; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("GetWorldCoordinates #2", msg == *msg_d); + test.boolean("UsblFixExtended #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23640,28 +26327,24 @@ main(void) } { - IMC::UsblAnglesExtended msg; - msg.setTimeStamp(0.113621275349); - msg.setSource(43424U); - msg.setSourceEntity(204U); - msg.setDestination(25003U); - msg.setDestinationEntity(107U); - msg.target.assign("COCYXDJVYSAQFSJVHCAMKGZUNHPWHCMYLIRGMUICKBTMRSQWFWZPALRZBAOKVEXNDTRSDHJFOIVCJYOIQZMISLPBAHLQVETSFYHBWECPDEUSXIOSJJUZVWFJHKHJKVBNWFTTGTLPYA"); - msg.lbearing = 0.470111854564; - msg.lelevation = 0.0835261807645; - msg.bearing = 0.515378208876; - msg.elevation = 0.115953436886; - msg.phi = 0.723801352483; - msg.theta = 0.600551148249; - msg.psi = 0.027514230642; - msg.accuracy = 0.610605070292; + IMC::UsblModem msg; + msg.setTimeStamp(0.12573053001278545); + msg.setSource(20750U); + msg.setSourceEntity(19U); + msg.setDestination(14389U); + msg.setDestinationEntity(91U); + msg.name.assign("WBZLUEJTDUIQGGCMZDUNLXGYGWIJJBKXPKDZWPBHAPBSZYCRSLICLLGHTVAXNWJNOOPYPAMHFKYLQWZIVOVMGJRAVAKNCCBBFCLKRYYEJKYUNSRGMJROZXQSA"); + msg.lat = 0.1697271326111276; + msg.lon = 0.736045598338645; + msg.z = 0.9270170764109025; + msg.z_units = 137U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblAnglesExtended #0", msg == *msg_d); + test.boolean("UsblModem #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23672,28 +26355,24 @@ main(void) } { - IMC::UsblAnglesExtended msg; - msg.setTimeStamp(0.745215303898); - msg.setSource(63233U); - msg.setSourceEntity(234U); - msg.setDestination(11452U); - msg.setDestinationEntity(23U); - msg.target.assign("WRDTIIFJFCYXTZMQVPDJFKEAMPGNTPJFDSFJLCIQIGSQIOSGDNY"); - msg.lbearing = 0.253832496856; - msg.lelevation = 0.956037091014; - msg.bearing = 0.0839549451268; - msg.elevation = 0.127812871564; - msg.phi = 0.57514519884; - msg.theta = 0.742818519417; - msg.psi = 0.512194246956; - msg.accuracy = 0.420748881677; + IMC::UsblModem msg; + msg.setTimeStamp(0.9623557401174836); + msg.setSource(19624U); + msg.setSourceEntity(169U); + msg.setDestination(13554U); + msg.setDestinationEntity(199U); + msg.name.assign("XCVKKHDEUEIHAYSKXVRJSCLBRADPQITIZZOSIXBZ"); + msg.lat = 0.7010081352191992; + msg.lon = 0.38671120450377705; + msg.z = 0.07700473483695214; + msg.z_units = 215U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblAnglesExtended #1", msg == *msg_d); + test.boolean("UsblModem #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23704,28 +26383,24 @@ main(void) } { - IMC::UsblAnglesExtended msg; - msg.setTimeStamp(0.619595374456); - msg.setSource(8562U); - msg.setSourceEntity(75U); - msg.setDestination(61007U); - msg.setDestinationEntity(198U); - msg.target.assign("TQBDUUWLOYRRNDCAMTNZJMGAQSKEOJDGGRKVDTZNQLLPFIRCUOMMKZLARKSGXPNIZFAOWZHHNVLCXMPYQUOAYEIFEKWAXKBDQDNCHGDWJIHEWUQXCHXVQGTJVYBQBRGEVMHLCXMSCRSPE"); - msg.lbearing = 0.761920240006; - msg.lelevation = 0.933736505538; - msg.bearing = 0.177602980822; - msg.elevation = 0.986892126684; - msg.phi = 0.00939827158527; - msg.theta = 0.583459704809; - msg.psi = 0.200844134575; - msg.accuracy = 0.436986041297; + IMC::UsblModem msg; + msg.setTimeStamp(0.17356709523752845); + msg.setSource(57392U); + msg.setSourceEntity(229U); + msg.setDestination(18789U); + msg.setDestinationEntity(168U); + msg.name.assign("SKLMIDLGNUXSAZUGKQKFTAVBESGNOACXTWFDKMNXMDOQBPGHCSOGPHLTVQAORHCRJELCXDIBECLYZSTJNZBIVPWFEEASQRMSCWOXPDYTWWJMSIHUDIYYRIONISJYLWMZXLBNHYBFWZHZHGDTQQFKRZXVAVFMBTZUBHWYUAOVSIDFTBZVTQYREUGQHMKZPPJMNCXOAKRTUHNJ"); + msg.lat = 0.3831347740798011; + msg.lon = 0.13752863774241497; + msg.z = 0.0790916008512027; + msg.z_units = 45U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblAnglesExtended #2", msg == *msg_d); + test.boolean("UsblModem #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23736,30 +26411,27 @@ main(void) } { - IMC::UsblPositionExtended msg; - msg.setTimeStamp(0.249385923282); - msg.setSource(7546U); - msg.setSourceEntity(244U); - msg.setDestination(15224U); - msg.setDestinationEntity(119U); - msg.target.assign("ZKMNQKYSIJQRFELQHNZRLHFXPOJPHMAODACVXUCMJWEXLZSPICUTWBSXTPKOFXQLSSCOYTBWGUJCOKMCGTYVNISBOLERVVWKCHIFRVLESQYIZERDJNIIZYBAGTXDWWSKRDTPYULVTKOUAVZEUDZWQGBDDFJJDYMRYKAUVNIVMEYOKKHPOPTGCXAALUBDQXQFHBHDCSVIHJINCSYGHNAAWMFPBLZNPEURMMGPBJGXGTEWMZL"); - msg.x = 0.127859345949; - msg.y = 0.492205832001; - msg.z = 0.0630953994968; - msg.n = 0.0692041358109; - msg.e = 0.860726783676; - msg.d = 0.286576648869; - msg.phi = 0.331376699927; - msg.theta = 0.451145665297; - msg.psi = 0.621362159401; - msg.accuracy = 0.115231770158; + IMC::UsblConfig msg; + msg.setTimeStamp(0.1578302030784694); + msg.setSource(23329U); + msg.setSourceEntity(199U); + msg.setDestination(13423U); + msg.setDestinationEntity(28U); + msg.op = 43U; + IMC::UsblModem tmp_msg_0; + tmp_msg_0.name.assign("JNAPHAGTXUEJKROKLSRQDUVMXBCC"); + tmp_msg_0.lat = 0.8286357870794371; + tmp_msg_0.lon = 0.7264792709574703; + tmp_msg_0.z = 0.9272551763968896; + tmp_msg_0.z_units = 46U; + msg.modems.push_back(tmp_msg_0); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblPositionExtended #0", msg == *msg_d); + test.boolean("UsblConfig #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23770,30 +26442,20 @@ main(void) } { - IMC::UsblPositionExtended msg; - msg.setTimeStamp(0.296732857654); - msg.setSource(33689U); - msg.setSourceEntity(13U); - msg.setDestination(42768U); - msg.setDestinationEntity(61U); - msg.target.assign("VTISOTSBTRFUQVDBWEHMLNANYHOMGFPEDWPAOZNXPGQUCZYLMHTDRNWCHSMHPECDFFKNJPTTLJTENKVLBEWHYAXGZDSCVOTXDURZLDAJAQOYKIEWAQHBWBRXVKPJVCLOUFOJPOUJUGPKHCAALXQXKFTKZGIGMEGKSEUEYRIQEBBBMRXFQNOW"); - msg.x = 0.763161460673; - msg.y = 0.0457818864557; - msg.z = 0.930144456612; - msg.n = 0.766739260493; - msg.e = 0.433272285605; - msg.d = 0.471427416392; - msg.phi = 0.110630926645; - msg.theta = 0.0552132080421; - msg.psi = 0.478288974559; - msg.accuracy = 0.416797581432; + IMC::UsblConfig msg; + msg.setTimeStamp(0.6305960616574815); + msg.setSource(36472U); + msg.setSourceEntity(153U); + msg.setDestination(60951U); + msg.setDestinationEntity(197U); + msg.op = 93U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblPositionExtended #1", msg == *msg_d); + test.boolean("UsblConfig #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23804,30 +26466,20 @@ main(void) } { - IMC::UsblPositionExtended msg; - msg.setTimeStamp(0.655749245708); - msg.setSource(8627U); - msg.setSourceEntity(176U); - msg.setDestination(8240U); - msg.setDestinationEntity(10U); - msg.target.assign("NAPEPLXLEJYELMQRAOVCTDRTPEZMMHMJTAINB"); - msg.x = 0.156158885396; - msg.y = 0.846375534291; - msg.z = 0.249073211329; - msg.n = 0.814639763947; - msg.e = 0.318914286639; - msg.d = 0.586785317386; - msg.phi = 0.484610933047; - msg.theta = 0.945226173238; - msg.psi = 0.00356155554771; - msg.accuracy = 0.924947042923; + IMC::UsblConfig msg; + msg.setTimeStamp(0.48729255221742585); + msg.setSource(55708U); + msg.setSourceEntity(67U); + msg.setDestination(16003U); + msg.setDestinationEntity(87U); + msg.op = 199U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblPositionExtended #2", msg == *msg_d); + test.boolean("UsblConfig #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23838,25 +26490,21 @@ main(void) } { - IMC::UsblFixExtended msg; - msg.setTimeStamp(0.92335646767); - msg.setSource(12333U); - msg.setSourceEntity(170U); - msg.setDestination(46496U); - msg.setDestinationEntity(149U); - msg.target.assign("IHUCJLFYLFFPCQLHGGTZRQWFOYNSXLAYAWFHAQLXOCJPOAMLMESXZJCHCBHBUDNOAEGSDJKTBYUVIVEDOCOCUFYJULPNIEDNPTZDHNVMANNGKPGPWZVPGCWEKHSSQYSMILTKUEHYRQIKWLNXGBSYQBZVRUKZEQDECVMKXIFIMOWDRXDKUGQUBETGIVNBQWJYDRKBFSTWUSLZTMOZJAHJWBZEMJPPIAQRTIOSX"); - msg.lat = 0.513785435511; - msg.lon = 0.236988005404; - msg.z_units = 204U; - msg.z = 0.783597626017; - msg.accuracy = 0.0157693480854; + IMC::DissolvedOrganicMatter msg; + msg.setTimeStamp(0.1847462670062745); + msg.setSource(5394U); + msg.setSourceEntity(220U); + msg.setDestination(55872U); + msg.setDestinationEntity(189U); + msg.value = 0.37564833343664084; + msg.type = 77U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblFixExtended #0", msg == *msg_d); + test.boolean("DissolvedOrganicMatter #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23867,25 +26515,21 @@ main(void) } { - IMC::UsblFixExtended msg; - msg.setTimeStamp(0.335349968648); - msg.setSource(16327U); - msg.setSourceEntity(248U); - msg.setDestination(36899U); - msg.setDestinationEntity(78U); - msg.target.assign("CGFEQXOXWOST"); - msg.lat = 0.297466299345; - msg.lon = 0.832882367579; - msg.z_units = 245U; - msg.z = 0.0908629029381; - msg.accuracy = 0.595671951823; + IMC::DissolvedOrganicMatter msg; + msg.setTimeStamp(0.8972232525322826); + msg.setSource(51302U); + msg.setSourceEntity(247U); + msg.setDestination(56338U); + msg.setDestinationEntity(241U); + msg.value = 0.8486852716828538; + msg.type = 64U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblFixExtended #1", msg == *msg_d); + test.boolean("DissolvedOrganicMatter #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23896,25 +26540,21 @@ main(void) } { - IMC::UsblFixExtended msg; - msg.setTimeStamp(0.827599850234); - msg.setSource(45279U); - msg.setSourceEntity(192U); - msg.setDestination(19385U); - msg.setDestinationEntity(165U); - msg.target.assign("BRAWFPIBNHENYKAAOLGUHOQLIDOSEVEBEGYJZVFQKJWWWMZTUWCOIERICPMYGYFZVXJBWZLSRTPNHSOBTBNUPZUNHXTQIRODBVPNYJWLURXDDKXOIPQWFKSZDJLQIALHYYOLUAZGMNCKGFNQGMMEAHPBINREDFNGJSYCOBFHYKVWRCGUFAQXDKETFVXQHIJFVJRQUJTMUCDRHCSSSXEWMZPOMHIBLXVLSZQPMGGRVAVYJXZKCKAXSCLTU"); - msg.lat = 0.492744747654; - msg.lon = 0.893949333535; - msg.z_units = 183U; - msg.z = 0.84719060428; - msg.accuracy = 0.250804682374; + IMC::DissolvedOrganicMatter msg; + msg.setTimeStamp(0.7616939068508631); + msg.setSource(7202U); + msg.setSourceEntity(64U); + msg.setDestination(11208U); + msg.setDestinationEntity(230U); + msg.value = 0.7011380985470108; + msg.type = 105U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblFixExtended #2", msg == *msg_d); + test.boolean("DissolvedOrganicMatter #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23925,24 +26565,20 @@ main(void) } { - IMC::UsblModem msg; - msg.setTimeStamp(0.606293327663); - msg.setSource(40603U); - msg.setSourceEntity(42U); - msg.setDestination(41986U); - msg.setDestinationEntity(98U); - msg.name.assign("KOMTFJYKNZICSVVORUSDHVTOXLEUEOKQPAAHWVJFBJREGSQHMKTEDPINAPASWLYKCTFJNFDURFDEGRNPDCTDUHBMEXCFQYGXBZGBTNLKVMZMQGQMDCIUZFSJRVWAPKZLYUKWIAWICSEBBJPPNUVMZS"); - msg.lat = 0.223402621938; - msg.lon = 0.311097474685; - msg.z = 0.90874785459; - msg.z_units = 121U; + IMC::OpticalBackscatter msg; + msg.setTimeStamp(0.48203083622361387); + msg.setSource(4481U); + msg.setSourceEntity(32U); + msg.setDestination(30343U); + msg.setDestinationEntity(56U); + msg.value = 0.14105999560792026; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblModem #0", msg == *msg_d); + test.boolean("OpticalBackscatter #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23953,24 +26589,20 @@ main(void) } { - IMC::UsblModem msg; - msg.setTimeStamp(0.540663895411); - msg.setSource(36109U); - msg.setSourceEntity(133U); - msg.setDestination(16794U); - msg.setDestinationEntity(46U); - msg.name.assign("IILICLEVUFBYDXQBSGYKWDD"); - msg.lat = 0.428643332259; - msg.lon = 0.813805968024; - msg.z = 0.526936000456; - msg.z_units = 197U; + IMC::OpticalBackscatter msg; + msg.setTimeStamp(0.7171931533194484); + msg.setSource(59169U); + msg.setSourceEntity(161U); + msg.setDestination(59206U); + msg.setDestinationEntity(85U); + msg.value = 0.2109212585418242; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblModem #1", msg == *msg_d); + test.boolean("OpticalBackscatter #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -23981,24 +26613,20 @@ main(void) } { - IMC::UsblModem msg; - msg.setTimeStamp(0.750313851274); - msg.setSource(51320U); - msg.setSourceEntity(36U); - msg.setDestination(15382U); - msg.setDestinationEntity(161U); - msg.name.assign("XYLCLNFUAGMHHBSGMXUUFNPMPIPCBFETYEZWSQARAJFVSGERRTOMHQQCFBGEVMIOASEAJYCLWFYBTIDBTPQJWWGXWGUIGYOHGLZZNJHQTAMVJLKYVQJPRGDICHENUVKQOPKNUXMFBKKOVFKMKPIDWWUDGCRKLBOEANLHZJETJROKSRTHYIYQATDNNFYXCEZPPEZDRUXUTOW"); - msg.lat = 0.287689510962; - msg.lon = 0.354692119459; - msg.z = 0.983228840953; - msg.z_units = 83U; + IMC::OpticalBackscatter msg; + msg.setTimeStamp(0.7864453620333174); + msg.setSource(10907U); + msg.setSourceEntity(57U); + msg.setDestination(27947U); + msg.setDestinationEntity(149U); + msg.value = 0.18642831173667984; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblModem #2", msg == *msg_d); + test.boolean("OpticalBackscatter #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24009,20 +26637,35 @@ main(void) } { - IMC::UsblConfig msg; - msg.setTimeStamp(0.565534614794); - msg.setSource(56910U); - msg.setSourceEntity(192U); - msg.setDestination(20429U); - msg.setDestinationEntity(78U); - msg.op = 10U; + IMC::Tachograph msg; + msg.setTimeStamp(0.5197224196627132); + msg.setSource(8017U); + msg.setSourceEntity(37U); + msg.setDestination(8526U); + msg.setDestinationEntity(166U); + msg.timestamp_last_service = 0.28535226786110635; + msg.time_next_service = 0.23964579591548585; + msg.time_motor_next_service = 0.5765740406800968; + msg.time_idle_ground = 0.9566279470572888; + msg.time_idle_air = 0.15901546512252684; + msg.time_idle_water = 0.6750457484665362; + msg.time_idle_underwater = 0.46818590514977465; + msg.time_idle_unknown = 0.6608298824272412; + msg.time_motor_ground = 0.11282680074667195; + msg.time_motor_air = 0.43083798511400917; + msg.time_motor_water = 0.9658137932701907; + msg.time_motor_underwater = 0.04136403314333381; + msg.time_motor_unknown = 0.6448961846874023; + msg.rpm_min = 470; + msg.rpm_max = -26531; + msg.depth_max = 0.541359325986403; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblConfig #0", msg == *msg_d); + test.boolean("Tachograph #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24033,20 +26676,35 @@ main(void) } { - IMC::UsblConfig msg; - msg.setTimeStamp(0.282490503278); - msg.setSource(17396U); - msg.setSourceEntity(148U); - msg.setDestination(8320U); - msg.setDestinationEntity(57U); - msg.op = 145U; + IMC::Tachograph msg; + msg.setTimeStamp(0.008449088924916026); + msg.setSource(45614U); + msg.setSourceEntity(129U); + msg.setDestination(36202U); + msg.setDestinationEntity(192U); + msg.timestamp_last_service = 0.06098543163576442; + msg.time_next_service = 0.5747117264465155; + msg.time_motor_next_service = 0.49453380092912635; + msg.time_idle_ground = 0.46937341532154375; + msg.time_idle_air = 0.9113778310784825; + msg.time_idle_water = 0.8090628228419589; + msg.time_idle_underwater = 0.748179272533326; + msg.time_idle_unknown = 0.5688566325290749; + msg.time_motor_ground = 0.7563781746437257; + msg.time_motor_air = 0.2697317986559342; + msg.time_motor_water = 0.34458383215114985; + msg.time_motor_underwater = 0.938637812064432; + msg.time_motor_unknown = 0.14978746718146008; + msg.rpm_min = -11505; + msg.rpm_max = 7721; + msg.depth_max = 0.7389906536545229; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblConfig #1", msg == *msg_d); + test.boolean("Tachograph #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24057,20 +26715,35 @@ main(void) } { - IMC::UsblConfig msg; - msg.setTimeStamp(0.384979555877); - msg.setSource(29419U); - msg.setSourceEntity(172U); - msg.setDestination(51051U); - msg.setDestinationEntity(8U); - msg.op = 150U; + IMC::Tachograph msg; + msg.setTimeStamp(0.947439165356211); + msg.setSource(65360U); + msg.setSourceEntity(45U); + msg.setDestination(30405U); + msg.setDestinationEntity(115U); + msg.timestamp_last_service = 0.9976626198085472; + msg.time_next_service = 0.668338573679112; + msg.time_motor_next_service = 0.2231069122747461; + msg.time_idle_ground = 0.6021039789555874; + msg.time_idle_air = 0.6479489516246562; + msg.time_idle_water = 0.5458840636400204; + msg.time_idle_underwater = 0.0745236214038626; + msg.time_idle_unknown = 0.3374896454674635; + msg.time_motor_ground = 0.3023075757105207; + msg.time_motor_air = 0.050705215849745966; + msg.time_motor_water = 0.19074148056895868; + msg.time_motor_underwater = 0.8963715153265511; + msg.time_motor_unknown = 0.5118226159935709; + msg.rpm_min = 22379; + msg.rpm_max = 4354; + msg.depth_max = 0.3500455891078934; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("UsblConfig #2", msg == *msg_d); + test.boolean("Tachograph #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24081,21 +26754,21 @@ main(void) } { - IMC::DissolvedOrganicMatter msg; - msg.setTimeStamp(0.359988731445); - msg.setSource(62779U); - msg.setSourceEntity(52U); - msg.setDestination(56269U); - msg.setDestinationEntity(22U); - msg.value = 0.816431750183; - msg.type = 178U; + IMC::ApmStatus msg; + msg.setTimeStamp(0.4569092528958302); + msg.setSource(45966U); + msg.setSourceEntity(157U); + msg.setDestination(51867U); + msg.setDestinationEntity(79U); + msg.severity = 42U; + msg.text.assign("HFZROJNRZLDCXSQWCNVCPFUWGISAHGEUGPKWLYOPCTGFJDUGVPASBVKPTWCWYZULMVZLJBHXZCSKRJIPWEMNRCIDNLJUFRVMFRWZBCMQOYHUYZDSQZKDNOAMXMRAQLGIBEKSKAEJIQCDJVPREVNUINAFVIXBDBTMFTFKLTBY"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DissolvedOrganicMatter #0", msg == *msg_d); + test.boolean("ApmStatus #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24106,21 +26779,21 @@ main(void) } { - IMC::DissolvedOrganicMatter msg; - msg.setTimeStamp(0.100231235481); - msg.setSource(49349U); - msg.setSourceEntity(224U); - msg.setDestination(50693U); - msg.setDestinationEntity(71U); - msg.value = 0.647298337344; - msg.type = 179U; + IMC::ApmStatus msg; + msg.setTimeStamp(0.3761481875209711); + msg.setSource(14696U); + msg.setSourceEntity(173U); + msg.setDestination(24152U); + msg.setDestinationEntity(179U); + msg.severity = 66U; + msg.text.assign("CPUDLJWSCMRASUTOMAGEECTHBAOQTFLVYFNYEPXWDVIEGPYHXETQDVWKYVZZOLFACDKSLAJMTZ"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DissolvedOrganicMatter #1", msg == *msg_d); + test.boolean("ApmStatus #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24131,21 +26804,21 @@ main(void) } { - IMC::DissolvedOrganicMatter msg; - msg.setTimeStamp(0.990409250375); - msg.setSource(47180U); - msg.setSourceEntity(91U); - msg.setDestination(43658U); - msg.setDestinationEntity(62U); - msg.value = 0.415082324044; - msg.type = 158U; + IMC::ApmStatus msg; + msg.setTimeStamp(0.3041118078918562); + msg.setSource(11688U); + msg.setSourceEntity(64U); + msg.setDestination(64516U); + msg.setDestinationEntity(177U); + msg.severity = 118U; + msg.text.assign("PQFRXFACXIDBDGTBEVUUQKPWEUCQQGNQETIOZADINZRHVYAJWCVFKUMARIXNEGXKSLJKPUVOHAMIQBTX"); try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("DissolvedOrganicMatter #2", msg == *msg_d); + test.boolean("ApmStatus #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24156,20 +26829,22 @@ main(void) } { - IMC::OpticalBackscatter msg; - msg.setTimeStamp(0.457520264184); - msg.setSource(28351U); - msg.setSourceEntity(96U); - msg.setDestination(56627U); - msg.setDestinationEntity(204U); - msg.value = 0.198802433482; + IMC::SadcReadings msg; + msg.setTimeStamp(0.024913725145137233); + msg.setSource(4810U); + msg.setSourceEntity(6U); + msg.setDestination(37473U); + msg.setDestinationEntity(185U); + msg.channel = 52; + msg.value = 2026887074; + msg.gain = 160U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("OpticalBackscatter #0", msg == *msg_d); + test.boolean("SadcReadings #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24180,20 +26855,22 @@ main(void) } { - IMC::OpticalBackscatter msg; - msg.setTimeStamp(0.687517908798); - msg.setSource(15038U); - msg.setSourceEntity(33U); - msg.setDestination(14434U); - msg.setDestinationEntity(181U); - msg.value = 0.982121048065; + IMC::SadcReadings msg; + msg.setTimeStamp(0.5631802040364042); + msg.setSource(18048U); + msg.setSourceEntity(68U); + msg.setDestination(18391U); + msg.setDestinationEntity(128U); + msg.channel = 51; + msg.value = 85284651; + msg.gain = 230U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("OpticalBackscatter #1", msg == *msg_d); + test.boolean("SadcReadings #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24204,20 +26881,22 @@ main(void) } { - IMC::OpticalBackscatter msg; - msg.setTimeStamp(0.0410691426017); - msg.setSource(29184U); - msg.setSourceEntity(239U); - msg.setDestination(31796U); - msg.setDestinationEntity(174U); - msg.value = 0.185574358249; + IMC::SadcReadings msg; + msg.setTimeStamp(0.6224645240970245); + msg.setSource(64506U); + msg.setSourceEntity(88U); + msg.setDestination(25777U); + msg.setDestinationEntity(249U); + msg.channel = 6; + msg.value = 1257501472; + msg.gain = 54U; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("OpticalBackscatter #2", msg == *msg_d); + test.boolean("SadcReadings #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24228,35 +26907,35 @@ main(void) } { - IMC::Tachograph msg; - msg.setTimeStamp(0.0352705764773); - msg.setSource(11008U); - msg.setSourceEntity(177U); - msg.setDestination(21093U); - msg.setDestinationEntity(167U); - msg.timestamp_last_service = 0.234424596024; - msg.time_next_service = 0.00113581555275; - msg.time_motor_next_service = 0.11808363707; - msg.time_idle_ground = 0.839107139569; - msg.time_idle_air = 0.617394021562; - msg.time_idle_water = 0.908850266566; - msg.time_idle_underwater = 0.262286649884; - msg.time_idle_unknown = 0.585938370605; - msg.time_motor_ground = 0.351542177933; - msg.time_motor_air = 0.311508067675; - msg.time_motor_water = 0.781289106865; - msg.time_motor_underwater = 0.0240315350009; - msg.time_motor_unknown = 0.988308623385; - msg.rpm_min = 23266; - msg.rpm_max = 15239; - msg.depth_max = 0.623970554145; + IMC::DmsDetection msg; + msg.setTimeStamp(0.6937680698829578); + msg.setSource(43892U); + msg.setSourceEntity(243U); + msg.setDestination(15528U); + msg.setDestinationEntity(233U); + msg.ch01 = 0.650851989740834; + msg.ch02 = 0.9851809075518625; + msg.ch03 = 0.9653938383481981; + msg.ch04 = 0.1245686666570992; + msg.ch05 = 0.19051058491885964; + msg.ch06 = 0.43231766563182406; + msg.ch07 = 0.7225676840012624; + msg.ch08 = 0.5417763464779433; + msg.ch09 = 0.342922236023253; + msg.ch10 = 0.6804113700818891; + msg.ch11 = 0.20854048136179326; + msg.ch12 = 0.01788501061493375; + msg.ch13 = 0.362282209136513; + msg.ch14 = 0.9688409754770053; + msg.ch15 = 0.5363074913218693; + msg.ch16 = 0.0844173156420639; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Tachograph #0", msg == *msg_d); + test.boolean("DmsDetection #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24267,35 +26946,35 @@ main(void) } { - IMC::Tachograph msg; - msg.setTimeStamp(0.752480343738); - msg.setSource(28205U); - msg.setSourceEntity(51U); - msg.setDestination(7048U); - msg.setDestinationEntity(151U); - msg.timestamp_last_service = 0.930399221687; - msg.time_next_service = 0.196062160246; - msg.time_motor_next_service = 0.416890392791; - msg.time_idle_ground = 0.788079983168; - msg.time_idle_air = 0.334604207563; - msg.time_idle_water = 0.816590142667; - msg.time_idle_underwater = 0.599355166623; - msg.time_idle_unknown = 0.19004612548; - msg.time_motor_ground = 0.201892987055; - msg.time_motor_air = 0.0784608523362; - msg.time_motor_water = 0.505686643735; - msg.time_motor_underwater = 0.0687088501371; - msg.time_motor_unknown = 0.974977252642; - msg.rpm_min = 18485; - msg.rpm_max = -26313; - msg.depth_max = 0.444433220813; + IMC::DmsDetection msg; + msg.setTimeStamp(0.451807111933371); + msg.setSource(28745U); + msg.setSourceEntity(240U); + msg.setDestination(29603U); + msg.setDestinationEntity(138U); + msg.ch01 = 0.2890315203435462; + msg.ch02 = 0.46842533685700516; + msg.ch03 = 0.21718304177827097; + msg.ch04 = 0.6352225793742938; + msg.ch05 = 0.30067261728368755; + msg.ch06 = 0.11946817609842209; + msg.ch07 = 0.9003332053313239; + msg.ch08 = 0.5516572869922296; + msg.ch09 = 0.7613048662416829; + msg.ch10 = 0.24216526703581087; + msg.ch11 = 0.7854313989567842; + msg.ch12 = 0.6077630707419741; + msg.ch13 = 0.465287384326877; + msg.ch14 = 0.543104751945495; + msg.ch15 = 0.06291967953039812; + msg.ch16 = 0.6179575260853929; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Tachograph #1", msg == *msg_d); + test.boolean("DmsDetection #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24306,35 +26985,35 @@ main(void) } { - IMC::Tachograph msg; - msg.setTimeStamp(0.369856055604); - msg.setSource(20990U); - msg.setSourceEntity(191U); - msg.setDestination(50307U); - msg.setDestinationEntity(120U); - msg.timestamp_last_service = 0.212435968196; - msg.time_next_service = 0.612945951835; - msg.time_motor_next_service = 0.946598488532; - msg.time_idle_ground = 0.357611417413; - msg.time_idle_air = 0.960066116526; - msg.time_idle_water = 0.307563357757; - msg.time_idle_underwater = 0.900646569263; - msg.time_idle_unknown = 0.572685174162; - msg.time_motor_ground = 0.183476871761; - msg.time_motor_air = 0.922125935884; - msg.time_motor_water = 0.385570529832; - msg.time_motor_underwater = 0.883971182777; - msg.time_motor_unknown = 0.962857802524; - msg.rpm_min = -2477; - msg.rpm_max = -26405; - msg.depth_max = 0.910225336512; + IMC::DmsDetection msg; + msg.setTimeStamp(0.7539843210283375); + msg.setSource(42348U); + msg.setSourceEntity(45U); + msg.setDestination(54085U); + msg.setDestinationEntity(249U); + msg.ch01 = 0.4472137007588126; + msg.ch02 = 0.7060654129934343; + msg.ch03 = 0.2873183330272937; + msg.ch04 = 0.970600635362109; + msg.ch05 = 0.16485410781324583; + msg.ch06 = 0.5251732229791671; + msg.ch07 = 0.42181613130366624; + msg.ch08 = 0.4682522854279909; + msg.ch09 = 0.0350843691750371; + msg.ch10 = 0.18723608527661817; + msg.ch11 = 0.19170164549216095; + msg.ch12 = 0.6567188617010591; + msg.ch13 = 0.7792308378205925; + msg.ch14 = 0.4500005638764816; + msg.ch15 = 0.5337127056506727; + msg.ch16 = 0.8955015826532181; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("Tachograph #2", msg == *msg_d); + test.boolean("DmsDetection #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24345,21 +27024,25 @@ main(void) } { - IMC::ApmStatus msg; - msg.setTimeStamp(0.0499361912581); - msg.setSource(57742U); - msg.setSourceEntity(127U); - msg.setDestination(41575U); - msg.setDestinationEntity(67U); - msg.severity = 23U; - msg.text.assign("KPKWNUUHAOXKWGWKTHFHXXLGHNGTVMCTNWQYGLMJRUIPFBAAHQMSRUKQCWFQGDOBHQCYODSXZBWINBEXKAFUZGYILPRRYVDDVRZLCDXEPIZDPEQSQMZBEBNOOXCFXNGWUJYYHWBMMNPU"); + IMC::HomePosition msg; + msg.setTimeStamp(0.2893867807055561); + msg.setSource(21969U); + msg.setSourceEntity(77U); + msg.setDestination(9105U); + msg.setDestinationEntity(134U); + msg.op = 204U; + msg.lat = 0.9673590068927819; + msg.lon = 0.24224966177100837; + msg.height = 0.01261226159293416; + msg.depth = 0.8326011865763283; + msg.alt = 0.21317017210051026; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ApmStatus #0", msg == *msg_d); + test.boolean("HomePosition #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24370,21 +27053,25 @@ main(void) } { - IMC::ApmStatus msg; - msg.setTimeStamp(0.556808635393); - msg.setSource(15958U); - msg.setSourceEntity(139U); - msg.setDestination(22228U); - msg.setDestinationEntity(109U); - msg.severity = 58U; - msg.text.assign("UQWFOYTUDXTUMHOONMDZJQHXPIJOWQORHHHNPSVSJEOVHTDXLKKVPOXUZDKBLEAQMKLZWQXFWOJPQJIAFZIMKGUEEYLZGFCTXELJKDCGNTLBBRWGWYUOEKSRYVAPYRDQPXLCMKRXDJVCD"); + IMC::HomePosition msg; + msg.setTimeStamp(0.6036455819353294); + msg.setSource(11288U); + msg.setSourceEntity(28U); + msg.setDestination(20635U); + msg.setDestinationEntity(193U); + msg.op = 179U; + msg.lat = 0.7003262840780964; + msg.lon = 0.2554308920113758; + msg.height = 0.2591334786596562; + msg.depth = 0.8289684958306904; + msg.alt = 0.5933042055355421; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ApmStatus #1", msg == *msg_d); + test.boolean("HomePosition #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24395,21 +27082,25 @@ main(void) } { - IMC::ApmStatus msg; - msg.setTimeStamp(0.255566262639); - msg.setSource(26963U); - msg.setSourceEntity(178U); - msg.setDestination(62610U); - msg.setDestinationEntity(147U); - msg.severity = 92U; - msg.text.assign("CRJDMKDYWINLLBAZLZBXQIOJDBTHHMVWYADXFWIBEPSHWPYGYBBDHNXXFSENASTWUJCSDZEDLXADMFCZLSJSHUTYFZXCUUJONBKACLIPPCCMGUAHPQNHVOOAGVGRMKLKVSGQWVC"); + IMC::HomePosition msg; + msg.setTimeStamp(0.46911182652737415); + msg.setSource(48273U); + msg.setSourceEntity(179U); + msg.setDestination(58272U); + msg.setDestinationEntity(84U); + msg.op = 191U; + msg.lat = 0.10393879956361174; + msg.lon = 0.6321332530577997; + msg.height = 0.8140033109952832; + msg.depth = 0.6545620233382236; + msg.alt = 0.2678863208306299; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("ApmStatus #2", msg == *msg_d); + test.boolean("HomePosition #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24420,22 +27111,20 @@ main(void) } { - IMC::SadcReadings msg; - msg.setTimeStamp(0.861519710472); - msg.setSource(52958U); - msg.setSourceEntity(83U); - msg.setDestination(61228U); - msg.setDestinationEntity(247U); - msg.channel = 44; - msg.value = 1319739654; - msg.gain = 151U; + IMC::TotalMagIntensity msg; + msg.setTimeStamp(0.38814053908065405); + msg.setSource(61267U); + msg.setSourceEntity(160U); + msg.setDestination(63930U); + msg.setDestinationEntity(23U); + msg.value = 0.2231501774793293; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SadcReadings #0", msg == *msg_d); + test.boolean("TotalMagIntensity #0", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24446,22 +27135,20 @@ main(void) } { - IMC::SadcReadings msg; - msg.setTimeStamp(0.764638068073); - msg.setSource(61792U); - msg.setSourceEntity(130U); - msg.setDestination(5262U); - msg.setDestinationEntity(37U); - msg.channel = 49; - msg.value = -969213033; - msg.gain = 99U; + IMC::TotalMagIntensity msg; + msg.setTimeStamp(0.027595158360099403); + msg.setSource(7489U); + msg.setSourceEntity(12U); + msg.setDestination(56264U); + msg.setDestinationEntity(221U); + msg.value = 0.17595714995250178; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SadcReadings #1", msg == *msg_d); + test.boolean("TotalMagIntensity #1", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) @@ -24472,22 +27159,20 @@ main(void) } { - IMC::SadcReadings msg; - msg.setTimeStamp(0.32578256308); - msg.setSource(59071U); - msg.setSourceEntity(3U); - msg.setDestination(16035U); - msg.setDestinationEntity(107U); - msg.channel = 90; - msg.value = -1402789353; - msg.gain = 64U; + IMC::TotalMagIntensity msg; + msg.setTimeStamp(0.4961884103175541); + msg.setSource(59547U); + msg.setSourceEntity(207U); + msg.setDestination(11084U); + msg.setDestinationEntity(150U); + msg.value = 0.1560036903477422; try { Utils::ByteBuffer bfr; IMC::Packet::serialize(&msg, bfr); IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), bfr.getSize()); - test.boolean("SadcReadings #2", msg == *msg_d); + test.boolean("TotalMagIntensity #2", msg == *msg_d); delete msg_d; } catch (IMC::InvalidMessageSize& e) diff --git a/programs/tests/test_MD5.cpp b/programs/tests/test_MD5.cpp index 3f1b2a7bc0..91fdf92351 100644 --- a/programs/tests/test_MD5.cpp +++ b/programs/tests/test_MD5.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Mutex.cpp b/programs/tests/test_Mutex.cpp index e15a188af2..8898890a42 100644 --- a/programs/tests/test_Mutex.cpp +++ b/programs/tests/test_Mutex.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Network.cpp b/programs/tests/test_Network.cpp index a7838bf91c..641b569591 100644 --- a/programs/tests/test_Network.cpp +++ b/programs/tests/test_Network.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Optimization.cpp b/programs/tests/test_Optimization.cpp index 4f6fca3de6..fe37cb95af 100644 --- a/programs/tests/test_Optimization.cpp +++ b/programs/tests/test_Optimization.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Path.cpp b/programs/tests/test_Path.cpp index d003ee9b77..1db227639f 100644 --- a/programs/tests/test_Path.cpp +++ b/programs/tests/test_Path.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_PeriodicDelay.cpp b/programs/tests/test_PeriodicDelay.cpp index 1b1937a812..56366fcaf6 100644 --- a/programs/tests/test_PeriodicDelay.cpp +++ b/programs/tests/test_PeriodicDelay.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Quaternion.cpp b/programs/tests/test_Quaternion.cpp new file mode 100644 index 0000000000..c44ec72130 --- /dev/null +++ b/programs/tests/test_Quaternion.cpp @@ -0,0 +1,369 @@ +#include +#include +#include +#include + +#include "Test.hpp" + +#include +#include +#include +#include + + + +using DUNE::Math::c_pi; +using DUNE::Math::c_half_pi; +using DUNE::Math::Matrix; +using DUNE::Math::Quaternion; +using DUNE::Math::EulerAnglesZyx; + + + +bool almostEqual(double a, double b, double max_error = 1e-12); +bool almostEqual(const Matrix& a, const Matrix& b, double max_error = 1e-12); +bool almostEqual(const Quaternion& a, const Quaternion& b, double max_error = 1e-12); +bool almostEqual(const EulerAnglesZyx& a, const EulerAnglesZyx& b, double max_error = 1e-12); + + + +int main() +{ + Test test("Math::Quaternion"); + + { + // Test default constructor. + const Quaternion quat; + const double data[] = {1, 0, 0, 0}; + const Matrix matrix(data, 4, 1); + test.boolean("Quaternion()", quat.matrix() == matrix); + } + + { + // Test std::vector constructor. + const double data[] = {-1, 2, -3, 4}; + const std::vector vector(data, data + sizeof(data) / sizeof(double)); + const Quaternion quat(vector); + const Matrix matrix(data, 4, 1); + test.boolean("Quaternion(std::vector)", quat.matrix() == matrix); + } + + { + // Test std::vector constructor (bad vector length). + const double data[] = {1, 2, 3, 4, 5}; + const std::vector vector(data, data + sizeof(data) / sizeof(double)); + std::string error_message(""); + try + { + Quaternion quat(vector); + } + catch (std::invalid_argument& e) + { + error_message = e.what(); + } + test.boolean("Quaternion(std::vector) exception", + error_message == "vector must have length 4"); + } + + { + // Test Matrix constructor. + const double data[] = {1, 2, 3, 4}; + const Matrix matrix(data, 4, 1); + const Quaternion quat(matrix); + test.boolean("Quaternion(Matrix)", quat.matrix() == matrix); + } + + { + // Test Matrix constructor (bad matrix size). + const Matrix matrix(5, 1); + std::string error_message(""); + try + { + Quaternion quat(matrix); + } + catch (std::invalid_argument& e) + { + error_message = e.what(); + } + test.boolean("Quaternion(Matrix) exception", error_message == "matrix must have size 4x1"); + } + + { + // Test w, x, y z constructor and getters. + const double data[] = {-1, 2, -3, 4}; + const std::vector vector(data, data + sizeof(data) / sizeof(double)); + const Quaternion quat(vector); + const Matrix matrix(data, 4, 1); + test.boolean("Quaternion(w, x, y, z)", quat.matrix() == matrix); + test.boolean("w()", quat.w() == data[0]); + test.boolean("x()", quat.x() == data[1]); + test.boolean("y()", quat.y() == data[2]); + test.boolean("z()", quat.z() == data[3]); + } + + { + // Test vec() getter. + const double data[] = {2, -3, 4}; + const Quaternion quat(-1, data[0], data[1], data[2]); + const Matrix vec(data, 3, 1); + test.boolean("vec()", quat.vec() == vec); + } + + { + // Test EulerAnglesZyx constructor. + const EulerAnglesZyx euler(0.1, -0.1, -2.7); + const Quaternion quat_from_euler(euler); + const Quaternion quat_expected(0.2209, -0.0378, -0.0596, -0.9727); + test.boolean("Quaternion(EulerAnglesZyx)", almostEqual(quat_from_euler, quat_expected, 0.0001)); + } + + { + // Test identity(). + const Quaternion quat_identity; + Quaternion quat_arbitrary(-1, 2, -3, 4); + const bool not_identity = quat_arbitrary != quat_identity; + quat_arbitrary.identity(); + const bool is_identity = quat_arbitrary == quat_identity; + test.boolean("identity()", not_identity && is_identity); + } + + { + // Test operator<<. + const Quaternion q; + std::stringstream ss; + ss << q; + test.boolean("operator<<", ss.str() == "1 \n0 \n0 \n0 \n"); + } + + { + // Test transpose(). + const Quaternion quat(-1, 2, -3, 4); + const Matrix quat_transpose = transpose(quat); + test.boolean("transpose()", transpose(quat.matrix()) == quat_transpose); + } + + { + // Test conjugate(). + const Quaternion quat(-1, 2, -3, 4); + const Quaternion result = conjugate(quat); + const Quaternion expected = Quaternion(-1, -2, 3, -4); + test.boolean("conjugate()", result == expected); + } + + { + // Test inverse(). + const Quaternion quat(1, -2, 3, -4); + const Quaternion result = inverse(quat); + const Quaternion expected = Quaternion(1, 2, -3, 4); + test.boolean("inverse()", result == expected); + } + + { + // Test norm(). + const Quaternion quat(-1, 2, -3, 4); + const double norm = 5.47722557505166113457; + test.boolean("norm()", almostEqual(quat.norm(), norm)); + } + + { + // Test normalize(). + Quaternion quat(-1, 2, -3, 4); + quat.normalize(); + test.boolean("normalize()", almostEqual(quat.norm(), 1.0)); + } + + { + // Test normalized(). + const Quaternion quat(1, 1, 1, 1); + const Quaternion quat_normalized = quat.normalized(); + test.boolean("normalized()", almostEqual(quat_normalized.norm(), 1.0)); + } + + { + // Test rotationMatrix(). + const Quaternion quat(1, 2, -3, -4); + const double data[] = { + -.6667, -.1333, -.7333, + -.6667, -.3333, .6667, + -.3333, .9333, .1333, + }; + const Matrix R_from_quat = quat.rotationMatrix(); + const Matrix R_expected = Matrix(data, 3, 3); + test.boolean("rotationMatrix()", almostEqual(R_from_quat, R_expected, 0.0001)); + } + + { + // Test angVelTransform(). + const Quaternion quat(2, 4, 6, 8); + const double data[] = { + -2, -3, -4, + 1, -4, 3, + 4, 1, -2, + -3, 2, 1, + }; + const Matrix T(data, 4, 3); + test.boolean("angVelTransform()", quat.angVelTransform() == T); + } + + { + // Test operator*=. + const Quaternion factor1(-1, 2, -3, 4); + const Quaternion factor2(-5, 6, -7, 8); + const Quaternion product(-60, -12, 30, -24); + test.boolean("operator*=", factor1 * factor2 == product); + } + + { + // Test operator==. + const Quaternion q1(-1, 2, -3, 4); + Quaternion q2(-5, 6, -7, 8); + const bool are_inequal = !(q1 == q2); + q2 = q1; + const bool are_equal = q1 == q2; + test.boolean("operator==", are_inequal && are_equal); + } + + { + // Test operator!=. + const Quaternion q1(-1, 2, -3, 4); + Quaternion q2(-5, 6, -7, 8); + const bool are_inequal = q1 != q2; + q2 = q1; + const bool are_equal = !(q1 != q2); + test.boolean("operator!=", are_inequal && are_equal); + } + + { + // Test operator*(Quaternion, Matrix). + const Quaternion factor1(-1, 2, -3, 4); + const double data1[] = {-5, 6, -7, 8}; + const Matrix factor2(data1, 1, 4); + const double data2[] = { + 5, -6, 7, -8, + -10, 12, -14, 16, + 15, -18, 21, -24, + -20, 24, -28, 32, + }; + const Matrix product(data2, 4, 4); + test.boolean("operator*(Quaternion, Matrix)", factor1 * factor2 == product); + } + + { + // Test operator*(Matrix, Quaternion). + const double data1[] = { + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16, + }; + const Matrix factor1(data1, 4, 4); + const Quaternion factor2(1, -2, 3, -4); + const double data2[] = {-10, -18, -26, -34}; + const Matrix product(data2, 4, 1); + test.boolean("operator*(Matrix, Quaternion)", factor1 * factor2 == product); + } + + { + // Test EulerAnglesZyx(Quaternion). + const Quaternion quat(0.8453, -0.1785, 0.2583, 0.4322); + const EulerAnglesZyx eul_from_quat(quat); + const EulerAnglesZyx eul_expected(-0.09748, 0.63234, 0.91338); + test.boolean("EulerAnglesZyx(Quaternion)", almostEqual(eul_from_quat, eul_expected, 0.0001)); + } + + { + // Test conversion from quaternion to euler angles to quaternion. + bool all_good = true; + const double step = 0.3; // With step = 0.3, the below code runs roughly 2000 iterations. + + for (double w = -1; w <= 1; w += step) + { + for (double x = -1; x <= 1; x += step) + { + for (double y = -1; y <= 1; y += step) + { + for (double z = -1; z <= 1; z += step) + { + const Quaternion q1 = Quaternion(w, x, y, z).normalized(); + const EulerAnglesZyx eul(q1); + + // Euler angle conversion invalid for pitch near +/- pi/2. + if (almostEqual(std::fabs(eul.pitch), c_half_pi, 1e-6)) + continue; + + const Quaternion q2(eul); + + const bool equivalent_quaternions = almostEqual(q1, q2) || almostEqual(q1, -q2); + if (!equivalent_quaternions) + all_good = false; + } + } + } + } + test.boolean("quat -> eul -> quat", all_good); + } + + { + // Test conversion from euler angles to quaternion to euler angles. + bool all_good = true; + const double step = c_pi/8; + + for (double yaw = -c_pi + step; yaw < c_pi; yaw += step) + { + for (double pitch = -c_half_pi + step; pitch < c_half_pi; pitch += step) + { + for (double roll = -c_pi + step; roll < c_pi; roll += step) + { + const EulerAnglesZyx eul1(roll, pitch, yaw); + const Quaternion quat(eul1); + const EulerAnglesZyx eul2(quat); + if (!almostEqual(eul1, eul2)) + all_good = false; + } + } + } + test.boolean("eul -> quat -> eul", all_good); + } + + { + // Test that a quaternion and its negation represent the same rotation. + const Quaternion q1 = Quaternion(1, 2, 3, 4).normalized(); + const EulerAnglesZyx eul1(q1); + const EulerAnglesZyx eul2(-q1); + test.boolean("q == -q", almostEqual(eul1, eul2)); + } + + return 0; +} + + + +bool almostEqual(double a, double b, double max_error) +{ + return std::fabs(a - b) < max_error; +} + +bool almostEqual(const Matrix& a, const Matrix& b, double max_error) +{ + if (a.rows() != b.rows() || a.columns() != b.columns()) + return false; + + Matrix diff = a - b; + for (int i = 0; i < diff.size(); ++i) + if (std::fabs(diff(i)) > max_error) + return false; + + return true; +} + +bool almostEqual(const Quaternion& a, const Quaternion& b, double max_error) +{ + return almostEqual(a.matrix(), b.matrix(), max_error); +} + +bool almostEqual(const EulerAnglesZyx& a, const EulerAnglesZyx& b, double max_error) +{ + return almostEqual(a.roll, b.roll, max_error) + && almostEqual(a.pitch, b.pitch, max_error) + && almostEqual(a.yaw, b.yaw, max_error); +} diff --git a/programs/tests/test_Random.cpp b/programs/tests/test_Random.cpp index 73c8710969..1b66ceb870 100644 --- a/programs/tests/test_Random.cpp +++ b/programs/tests/test_Random.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_StateMachine.cpp b/programs/tests/test_StateMachine.cpp index 7630848af3..670dfea1d8 100644 --- a/programs/tests/test_StateMachine.cpp +++ b/programs/tests/test_StateMachine.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_String.cpp b/programs/tests/test_String.cpp index 78137108e1..20e723c06e 100644 --- a/programs/tests/test_String.cpp +++ b/programs/tests/test_String.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_System.cpp b/programs/tests/test_System.cpp index 10325b1faa..62530eaf7f 100644 --- a/programs/tests/test_System.cpp +++ b/programs/tests/test_System.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_Thread.cpp b/programs/tests/test_Thread.cpp index a028f131ab..d8ead6b221 100644 --- a/programs/tests/test_Thread.cpp +++ b/programs/tests/test_Thread.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/tests/test_factorial.cpp b/programs/tests/test_factorial.cpp new file mode 100644 index 0000000000..3c0e8eec00 --- /dev/null +++ b/programs/tests/test_factorial.cpp @@ -0,0 +1,76 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Kristoffer Gryte * +//*************************************************************************** + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include + +using DUNE_NAMESPACES; + +// Local headers. +#include "Test.hpp" + + +int +main(void) +{ + Test test("Factorial"); + + { + test.boolean("factorial(0)", Math::factorial(0) == 1); + test.boolean("factorial(1)", Math::factorial(1) == 1); + test.boolean("factorial(2)", Math::factorial(2) == 2); + test.boolean("factorial(5)", Math::factorial(5) == 120); + test.boolean("factorial(170)", Math::factorial(170) == 7.257415615307994E+306); + test.boolean("factorial(90)/factorial(89)", std::fabs(Math::factorial(90)/Math::factorial(89) - 90) < 1e-9); + test.boolean("factorial(170)/factorial(169)", std::fabs(Math::factorial(170)/Math::factorial(169) - 170) < 1e-9); + try + { + Math::factorial(-1) == 1; + test.failed("factorial out of bounds, low"); + } + catch (std::exception& e) + { + test.passed(DUNE::Utils::String::str("factorial out of bounds, low: %s", e.what()).c_str()); + } + try + { + Math::factorial(171) == 1; + test.failed("factorial out of bounds, high"); + } + catch (std::exception& e) + { + test.passed(DUNE::Utils::String::str("factorial out of bounds, high: %s", e.what()).c_str()); + } + } + + return 0; +} diff --git a/programs/usbl_evaluation.cpp b/programs/usbl_evaluation.cpp index ebf3a84bb3..36616f2f99 100644 --- a/programs/usbl_evaluation.cpp +++ b/programs/usbl_evaluation.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/programs/utils/dune-activate.cpp b/programs/utils/dune-activate.cpp index 93e0023de5..645e5fc23c 100644 --- a/programs/utils/dune-activate.cpp +++ b/programs/utils/dune-activate.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-config-check.cpp b/programs/utils/dune-config-check.cpp index 253a9b93b3..70df50683f 100644 --- a/programs/utils/dune-config-check.cpp +++ b/programs/utils/dune-config-check.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-lsf2jpg.cpp b/programs/utils/dune-lsf2jpg.cpp index 76d8e5e892..e95e621e23 100644 --- a/programs/utils/dune-lsf2jpg.cpp +++ b/programs/utils/dune-lsf2jpg.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-lsfreplay.cpp b/programs/utils/dune-lsfreplay.cpp index 064b4fe8fb..a53a9806b5 100644 --- a/programs/utils/dune-lsfreplay.cpp +++ b/programs/utils/dune-lsfreplay.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-lucb.cpp b/programs/utils/dune-lucb.cpp index 0b9fd107bb..c6da8f549b 100644 --- a/programs/utils/dune-lucb.cpp +++ b/programs/utils/dune-lucb.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-lucl-talk.cpp b/programs/utils/dune-lucl-talk.cpp index 790368fee3..db192034a0 100644 --- a/programs/utils/dune-lucl-talk.cpp +++ b/programs/utils/dune-lucl-talk.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-md5.cpp b/programs/utils/dune-md5.cpp index 8e8843e86e..1e5d34eedb 100644 --- a/programs/utils/dune-md5.cpp +++ b/programs/utils/dune-md5.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-sendmsg.cpp b/programs/utils/dune-sendmsg.cpp index f9841e9437..4da40ad48a 100644 --- a/programs/utils/dune-sendmsg.cpp +++ b/programs/utils/dune-sendmsg.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -32,6 +32,7 @@ #include #include #include +#include // DUNE headers. #include @@ -39,6 +40,99 @@ using DUNE_NAMESPACES; using namespace std; +void recursive(IMC::TransmissionRequest* tmsg, int count) +{ + if(count == 0){ + IMC::Abort* abort = new IMC::Abort; + tmsg->msg_data.set(abort->clone()); + } + else{ + tmsg->msg_data.set(tmsg->clone()); + recursive((IMC::TransmissionRequest*)tmsg->msg_data.get(),--count); + } + +} + +void createRandomMsg(IMC::TransmissionRequest* tmsg) +{ + + int type = rand() % 6; + + switch (type) + { + case 0: + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_GSM; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_TEXT; + tmsg->txt_data = "Pos"; + tmsg->destination = "+351912037728"; + + break; + + case 1: + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_ABORT; + + break; + case 2: + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_RANGE; + + break; + case 3: + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + + recursive(tmsg, (rand() % 5)); + + break; + case 4: + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_WIFI; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + + recursive(tmsg, (rand() % 5)); + + break; + case 5: + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_GSM; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + tmsg->destination = "+351912037728"; + recursive(tmsg, (rand() % 5)); + + break; + + } + +} + +void logMsg(char ** argv, int argc) +{ + fprintf(stdout, "Processing message width %d arguments:",argc); + fprintf(stdout, "\n system host ip -> %s",argv[1]); + fprintf(stdout, "\n system host port -> %s",argv[2]); + fprintf(stdout, "\n message / test -> %s",argv[3]); +} + +void logSystemDuneID(unsigned short& sh,char ** argv) +{ + sh = (unsigned short) strtoul(argv[4], NULL, 0); + fprintf(stdout, "\n system host dune ID -> %d",sh); +} + +void logNumberOfMessages(unsigned short& count, char ** argv, int argc){ + if(argc >=7){ + try + { + count = (unsigned short)strtoul(argv[6], NULL, 0); + } + catch (std::runtime_error& e) + { + } + + } + fprintf(stdout, "\n number of messages to transmit -> %d",count); + +} + int main(int argc, char** argv) { @@ -70,9 +164,13 @@ main(int argc, char** argv) fprintf(stdout, " RestartSystem\n"); fprintf(stdout, " [S]: SaveEntityParameters, SetEntityParameters, SetLedBrightness, SetServoPosition,\n"); fprintf(stdout, " SetThrusterActuation, Sms, SoundSpeed\n"); - fprintf(stdout, " [T]: Target, TeleoperationDone, Temperature, TextMessage, TrexCommand\n"); + fprintf(stdout, " [T]: Target, TeleoperationDone, Temperature, TextMessage, TransmissionRequest, TrexCommand\n"); fprintf(stdout, " [U]: UASimulation\n"); fprintf(stdout, " [V]: VehicleCommand, VehicleMedium\n"); + fprintf(stdout, "\n"); + fprintf(stdout, "Available Scaled Tests:\n"); + fprintf(stdout, " [T]: teste_abort, teste_any, teste_random, teste_range, teste_sms, teste_wifi_1\n"); + return 1; } @@ -100,6 +198,8 @@ main(int argc, char** argv) } IMC::Message* msg = NULL; + std::list* msg_list = new std::list(); + if (strcmp(argv[3], "Abort") == 0) { @@ -775,6 +875,33 @@ main(int argc, char** argv) } } + if(strcmp(argv[3], "TransmissionRequest") == 0) + { + uint16_t id = 0; + unsigned short sh = (unsigned short) strtoul(argv[4], NULL, 0); + + for(int i=0; i<1; i++){ + IMC::TransmissionRequest* tmsg = new IMC::TransmissionRequest; + + IMC::Abort* abort = new IMC::Abort; + + tmsg->setSource(sh); + tmsg->setDestination(sh); + tmsg->destination = argv[5]; + tmsg->deadline = Time::Clock::getSinceEpoch() + 200; + tmsg->req_id = id; + id++; + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + + recursive(tmsg,5); + + msg_list->push_back(tmsg); + + } + + } + if (strcmp(argv[3], "TrexCommand") == 0) { IMC::TrexCommand* tmsg = new IMC::TrexCommand; @@ -829,12 +956,382 @@ main(int argc, char** argv) tmsg->medium = atoi(argv[4]); } - if (msg == NULL) + double delay=0; + if(strcmp(argv[3], "teste_wifi_1") == 0) + { + if (argc < 6){ + fprintf(stderr, "Error: missing arguments..."); + fprintf(stderr, "\n arg1 : ip (ex: 127.0.0.1)"); + fprintf(stderr, "\n arg2 : port (ex: 6002)"); + fprintf(stderr, "\n arg3 : testingmessage (ex: testewifi_1)"); + fprintf(stderr, "\n arg4 : system_receiver_id (ex: 26)"); + fprintf(stderr, "\n arg5 : system_destination_name (ex: lauv-noptilus-1)"); + fprintf(stderr, "\n arg6 (optional) : number_of_messages (ex: 5)"); + fprintf(stderr, "\n arg7 (optional) : set_delay_between_messages (ex: 3.5)"); + fprintf(stderr, "\n"); + + return 0; + } + + logMsg(argv,argc); + + uint16_t id = 0; + + unsigned short sh=0; + logSystemDuneID(sh,argv); + + fprintf(stdout, "\n destination of message -> %s",argv[5]); + unsigned short count = 1; + logNumberOfMessages(count,argv,argc); + + if(argc == 8){ + delay = -atof(argv[7]); + } + fprintf(stdout, "\n delay between transmissions -> %lf",-delay); + fprintf(stdout, "\n\n"); + + for(int i=0; isetSource(sh); + tmsg->setDestination(sh); + tmsg->destination = argv[5]; + tmsg->deadline = Time::Clock::getSinceEpoch() + (-delay * (i+1)) + 40; + tmsg->req_id = id; + id++; + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_WIFI; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + + recursive(tmsg,3); + + msg_list->push_back(tmsg); + + } + + } + + if(strcmp(argv[3], "teste_any") == 0) + { + if (argc < 6){ + fprintf(stderr, "Error: missing arguments..."); + fprintf(stderr, "\n arg1 : ip (ex: 127.0.0.1)"); + fprintf(stderr, "\n arg2 : port (ex: 6002)"); + fprintf(stderr, "\n arg3 : testingmessage (ex: testewifi_1)"); + fprintf(stderr, "\n arg4 : system_receiver_id (ex: 26)"); + fprintf(stderr, "\n arg5 : system_destination_name (ex: lauv-noptilus-1)"); + fprintf(stderr, "\n arg6 (optional) : number_of_messages (ex: 5)"); + fprintf(stderr, "\n arg7 (optional) : set_delay_between_messages (ex: 3.5)"); + fprintf(stderr, "\n"); + + return 0; + } + + logMsg(argv,argc); + + uint16_t id = 0; + + unsigned short sh=0; + logSystemDuneID(sh,argv); + + fprintf(stdout, "\n destination of message -> %s",argv[5]); + unsigned short count = 1; + logNumberOfMessages(count,argv,argc); + + if(argc == 8){ + delay = -atof(argv[7]); + } + fprintf(stdout, "\n delay between transmissions -> %lf",-delay); + fprintf(stdout, "\n\n"); + + for(int i=0; isetSource(sh); + tmsg->setDestination(sh); + tmsg->destination = argv[5]; + tmsg->deadline = Time::Clock::getSinceEpoch() + (-delay * (i+1)) + rand() % 15; + tmsg->req_id = id; + id++; + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_ANY; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + + IMC::DevDataText tm; + + + char numberstring[(((sizeof i) * CHAR_BIT) + 2)/3 + 2]; + sprintf(numberstring, "%d", i); + + tm.value = std::string("teste any: ") + numberstring; + tmsg->msg_data.set(tm); + + msg_list->push_back(tmsg); + + } + + } + + if(strcmp(argv[3], "teste_range") == 0) + { + if (argc < 6){ + fprintf(stderr, "Error: missing arguments..."); + fprintf(stderr, "\n arg1 : ip (ex: 127.0.0.1)"); + fprintf(stderr, "\n arg2 : port (ex: 6002)"); + fprintf(stderr, "\n arg3 : testingmessage (ex: teste_range)"); + fprintf(stderr, "\n arg4 : system_receiver_id (ex: 26)"); + fprintf(stderr, "\n arg5 : system_destination_name (ex: lauv-noptilus-1)"); + fprintf(stderr, "\n arg6 (optional) : number_of_messages (ex: 5)"); + fprintf(stderr, "\n arg7 (optional) : set_delay_between_messages (ex: 3.5)"); + fprintf(stderr, "\n"); + return 0; + } + logMsg(argv,argc); + + uint16_t id = 0; + + unsigned short sh=0; + logSystemDuneID(sh,argv); + + fprintf(stdout, "\n destination of message -> %s",argv[5]); + unsigned short count = 1; + logNumberOfMessages(count,argv,argc); + + if(argc == 8){ + delay = -atof(argv[7]); + } + fprintf(stdout, "\n delay between transmissions -> %lf",-delay); + fprintf(stdout, "\n\n"); + + + for(int i=0; isetSource(sh); + tmsg->setDestination(sh); + tmsg->destination = argv[5]; + tmsg->deadline = Time::Clock::getSinceEpoch() + (-delay*(i+1)) +5; + tmsg->req_id = id; + id++; + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_RANGE; + + msg_list->push_back(tmsg); + + } + + } + if(strcmp(argv[3], "teste_abort") == 0) + { + if (argc < 6){ + fprintf(stderr, "Error: missing arguments..."); + fprintf(stderr, "\n arg1 : ip (ex: 127.0.0.1)"); + fprintf(stderr, "\n arg2 : port (ex: 6002)"); + fprintf(stderr, "\n arg3 : testingmessage (ex: teste_abort)"); + fprintf(stderr, "\n arg4 : system_receiver_id (ex: 26)"); + fprintf(stderr, "\n arg5 : system_destination_name (ex: lauv-noptilus-1)"); + fprintf(stderr, "\n arg6 (optional) : number_of_messages (ex: 5)"); + fprintf(stderr, "\n arg7 (optional) : set_delay_between_messages (ex: 3.5)"); + fprintf(stderr, "\n"); + return 0; + } + logMsg(argv,argc); + + uint16_t id = 0; + + unsigned short sh=0; + logSystemDuneID(sh,argv); + + fprintf(stdout, "\n destination of message -> %s",argv[5]); + unsigned short count = 1; + logNumberOfMessages(count,argv,argc); + + if(argc == 8){ + delay = -atof(argv[7]); + } + fprintf(stdout, "\n delay between transmissions -> %lf",-delay); + fprintf(stdout, "\n\n"); + + + for(int i=0; isetSource(sh); + tmsg->setDestination(sh); + tmsg->destination = argv[5]; + tmsg->deadline = Time::Clock::getSinceEpoch() + (-delay*(i+1)) +5; + tmsg->req_id = id; + id++; + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_ABORT; + + msg_list->push_back(tmsg); + + } + + } + if(strcmp(argv[3], "teste_sms") == 0) + { + if (argc < 6){ + fprintf(stderr, "Error: missing arguments..."); + fprintf(stderr, "\n arg1 : ip (ex: 127.0.0.1)"); + fprintf(stderr, "\n arg2 : port (ex: 6002)"); + fprintf(stderr, "\n arg3 : testingmessage (ex: teste_sms)"); + fprintf(stderr, "\n arg4 : system_receiver_id (ex: 26)"); + fprintf(stderr, "\n arg5 : system_destination_name (ex: lauv-noptilus-1)"); + fprintf(stderr, "\n arg6 (optional) : number_of_messages (ex: 5)"); + fprintf(stderr, "\n arg7 (optional) : set_delay_between_messages (ex: 3.5)"); + fprintf(stderr, "\n"); + return 0; + } + logMsg(argv,argc); + + uint16_t id = 0; + + unsigned short sh=0; + logSystemDuneID(sh,argv); + + fprintf(stdout, "\n destination of message -> %s",argv[5]); + unsigned short count = 1; + logNumberOfMessages(count,argv,argc); + + if(argc == 8){ + delay = -atof(argv[7]); + } + fprintf(stdout, "\n delay between transmissions -> %lf",-delay); + fprintf(stdout, "\n\n"); + + for(int i=0; isetSource(sh); + tmsg->setDestination(sh); + tmsg->destination = argv[5]; + tmsg->deadline = Time::Clock::getSinceEpoch() + (-delay*(i+1)) +5; + tmsg->req_id = id; + id++; + tmsg->comm_mean = IMC::TransmissionRequest::CMEAN_GSM; + tmsg->data_mode = IMC::TransmissionRequest::DMODE_TEXT; + tmsg->txt_data = "Pos"; + + msg_list->push_back(tmsg); + + } + + } + + if(strcmp(argv[3], "teste_random") == 0){ + + + if (argc < 6){ + fprintf(stderr, "Error: missing arguments..."); + fprintf(stderr, "\n arg1 : ip (ex: 127.0.0.1)"); + fprintf(stderr, "\n arg2 : port (ex: 6002)"); + fprintf(stderr, "\n arg3 : testingmessage (ex: teste_random)"); + fprintf(stderr, "\n arg4 : system_receiver_id (ex: 26)"); + fprintf(stderr, "\n arg5 : system_destination_name (ex: lauv-noptilus-1)"); + fprintf(stderr, "\n arg6 (optional) : number_of_messages (ex: 5)"); + fprintf(stderr, "\n arg7 (optional) : set_delay_between_messages (ex: 3.5)"); + fprintf(stderr, "\n"); + return 0; + } + logMsg(argv,argc); + + uint16_t id = 0; + + unsigned short sh=0; + logSystemDuneID(sh,argv); + + fprintf(stdout, "\n destination of message -> %s",argv[5]); + unsigned short count = 1; + logNumberOfMessages(count,argv,argc); + + if(argc == 8){ + delay = atof(argv[7]); + } + fprintf(stdout, "\n delay between transmissions -> %lf",delay); + fprintf(stdout, "\n\n"); + + + for(int i=0; isetSource(sh); + tmsg->setDestination(sh); + tmsg->destination = argv[5]; + tmsg->deadline = Time::Clock::getSinceEpoch() + (delay*(i+1)) +5; + tmsg->req_id = id; + id++; + createRandomMsg(tmsg); + + msg_list->push_back(tmsg); + + } + + } + + + + if (msg == NULL && msg_list->empty()) { fprintf(stderr, "ERROR: unknown message '%s'\n", argv[3]); return 1; } + if(!msg_list->empty()){ + int delay_copy = Math::round(delay * 1000); + + IMC::Message* aux; + + int list_size = msg_list->size(); + for(unsigned int i=0; i < (unsigned int)list_size; i++) + { + + if(delay>0){ + int dl = rand() % delay_copy + 1; + sleep(dl); + } + else{ + sleep(-delay); + + } + + aux=msg_list->front(); + msg_list->pop_front(); + + aux->setTimeStamp(); + + uint8_t bfr[1024] = {0}; + uint16_t rv = IMC::Packet::serialize(aux, bfr, sizeof(bfr)); + + UDPSocket sock; + try + { + sock.write(bfr, rv, dest, port); + aux->toText(cerr); + } + catch (std::runtime_error& e) + { + std::cerr << "ERROR: " << e.what() << std::endl; + return 1; + } + + if (aux != NULL) + { + delete aux; + aux = NULL; + } + + } + + + return 0; + } + + msg->setTimeStamp(); uint8_t bfr[1024] = {0}; @@ -866,3 +1363,5 @@ main(int argc, char** argv) return 0; } + + diff --git a/programs/utils/dune-uctk.cpp b/programs/utils/dune-uctk.cpp index c654dea187..cea298af64 100644 --- a/programs/utils/dune-uctk.cpp +++ b/programs/utils/dune-uctk.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/utils/dune-wgs84.cpp b/programs/utils/dune-wgs84.cpp index 0e6c937320..cfa2da1b6f 100644 --- a/programs/utils/dune-wgs84.cpp +++ b/programs/utils/dune-wgs84.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/video-client/GraphicsScene.cpp b/programs/video-client/GraphicsScene.cpp index e91db9b0fe..b19230b4bf 100644 --- a/programs/video-client/GraphicsScene.cpp +++ b/programs/video-client/GraphicsScene.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/video-client/GraphicsScene.hpp b/programs/video-client/GraphicsScene.hpp index 8506905525..df533865eb 100644 --- a/programs/video-client/GraphicsScene.hpp +++ b/programs/video-client/GraphicsScene.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/video-client/Main.cpp b/programs/video-client/Main.cpp index e9e4566b72..bd365bf7d8 100644 --- a/programs/video-client/Main.cpp +++ b/programs/video-client/Main.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/video-client/VideoClient.cpp b/programs/video-client/VideoClient.cpp index ed67a10e0f..f31aadbd3c 100644 --- a/programs/video-client/VideoClient.cpp +++ b/programs/video-client/VideoClient.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/programs/video-client/VideoClient.hpp b/programs/video-client/VideoClient.hpp index 7606630d17..78e5bbda9e 100644 --- a/programs/video-client/VideoClient.hpp +++ b/programs/video-client/VideoClient.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/AMC/Parser.hpp b/src/Actuators/AMC/Parser.hpp index 6a3b1b408a..94d004c436 100644 --- a/src/Actuators/AMC/Parser.hpp +++ b/src/Actuators/AMC/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/AMC/Task.cpp b/src/Actuators/AMC/Task.cpp index 4729e1818c..aa89635176 100644 --- a/src/Actuators/AMC/Task.cpp +++ b/src/Actuators/AMC/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/Broom/Task.cpp b/src/Actuators/Broom/Task.cpp index 1235d478ce..e53bdc731e 100644 --- a/src/Actuators/Broom/Task.cpp +++ b/src/Actuators/Broom/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/FLIRPTU/Task.cpp b/src/Actuators/FLIRPTU/Task.cpp index 7f4453c0ad..331ed80edc 100644 --- a/src/Actuators/FLIRPTU/Task.cpp +++ b/src/Actuators/FLIRPTU/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/LED4R/Task.cpp b/src/Actuators/LED4R/Task.cpp index 78efad1a89..2a0dcea815 100644 --- a/src/Actuators/LED4R/Task.cpp +++ b/src/Actuators/LED4R/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/MCD4R/Task.cpp b/src/Actuators/MCD4R/Task.cpp index 4463ed01a6..dbe21f54a8 100644 --- a/src/Actuators/MCD4R/Task.cpp +++ b/src/Actuators/MCD4R/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/MicroCamD/Task.cpp b/src/Actuators/MicroCamD/Task.cpp index 5982f731e3..57bbd0b3b4 100644 --- a/src/Actuators/MicroCamD/Task.cpp +++ b/src/Actuators/MicroCamD/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/PWM/ServoPWM.hpp b/src/Actuators/PWM/ServoPWM.hpp new file mode 100644 index 0000000000..0fd6d0b240 --- /dev/null +++ b/src/Actuators/PWM/ServoPWM.hpp @@ -0,0 +1,267 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: PGonçalves * +//*************************************************************************** + +#ifndef ACTUATORS_SERVOPWM_HPP_INCLUDED_ +#define ACTUATORS_SERVOPWM_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include +#include + +// DUNE headers. +#include + +// Import namespaces. +using DUNE_NAMESPACES; + +namespace Actuators +{ + namespace PWM + { + class ServoPwm: public Thread + { + public: + int m_gpio; + double m_value; + bool m_gpio_state; + bool m_refresh; + + ServoPwm(DUNE::Tasks::Task* task, int gpio, double value, bool refresh): + m_task(task) + { + m_gpio = gpio; + m_value = value; + m_gpio_state = false; + m_refresh = refresh; + } + + //! Destructor. + ~ServoPwm(void) + { + closeConfigServo(); + } + + void + SetPwmValue( double _value) + { + m_value = _value; + m_update_angle = true; + } + + bool + CheckGPIOSate(void) + { + if(m_gpio_state) + return true; + + return false; + } + + private: + void + run(void) + { + c_time_delayms = 19500; + wdog_tout = 0.02; + m_wdog.setTop(wdog_tout); + while(!inicServo( m_gpio ) && !isStopping()) + { + Delay::wait(1); + } + m_gpio_state = true; + m_update_angle = true; + + while (!isStopping()) + { + if (m_refresh) + refreshPWM(m_value); + else if(!m_refresh && m_update_angle) + setAngleServomotor(m_value); + else + Delay::waitUsec(500); + } + } + + //!Set angle to servomotor + void + setAngleServomotor( double angle ) + { + m_gpio_state = true; + int cntRefreshservo = 0; + degAngle = DUNE::Math::Angles::degrees(std::abs(angle)); + if (degAngle < 0) + degAngle = 0; + if (degAngle > 180) + degAngle = 180; + + valueUP = (10 * degAngle) + 600; + + while (cntRefreshservo < 200 && !isStopping() && m_gpio_state) + { + if ((myOutputHandle = fopen(GPIOValue, "rb+")) == NULL) + { + m_task->err("ERROR PinOut %d", m_gpio); + m_gpio_state = false; + } + strcpy(setValue, "1"); // Set value high + fwrite(&setValue, sizeof(char), 1, myOutputHandle); + fclose(myOutputHandle); + Delay::waitUsec(valueUP); + // Set output to low + if ((myOutputHandle = fopen(GPIOValue, "rb+")) == NULL) + { + m_task->err("ERROR PinOut %d", m_gpio); + m_gpio_state = false; + } + strcpy(setValue, "0"); // Set value low + fwrite(&setValue, sizeof(char), 1, myOutputHandle); + fclose(myOutputHandle);; + Delay::waitUsec(20000 - valueUP); + + cntRefreshservo++; + } + + if (m_gpio_state) + m_update_angle = false; + } + + //!Inic of config to pinout of servomotor + bool + inicServo(int gpioPin) + { + sprintf(GPIOString, "%d", gpioPin); + sprintf(GPIOValue, "/sys/class/gpio/gpio%d/value", gpioPin); + sprintf(GPIODirection, "/sys/class/gpio/gpio%d/direction", gpioPin); + // Export the pin + if ((myOutputHandle = fopen("/sys/class/gpio/export", "ab")) == NULL) + { + m_task->err("Unable to export GPIO pin (%d)", m_gpio); + return false; + } + strcpy(setValue, GPIOString); + fwrite(&setValue, sizeof(char), 2, myOutputHandle); + fclose(myOutputHandle); + // Set direction of the pin to an output + if ((myOutputHandle = fopen(GPIODirection, "rb+")) == NULL) + { + m_task->err("Unable to open direction handle (%d)", m_gpio); + return false; + } + strcpy(setValue,"out"); + fwrite(&setValue, sizeof(char), 3, myOutputHandle); + fclose(myOutputHandle); + + return true; + } + + //!Close PinOut config + bool + closeConfigServo(void) + { + // Unexport the pin + if ((myOutputHandle = fopen("/sys/class/gpio/unexport", "ab")) == NULL) + { + m_task->err("Unable to unexport GPIO pin (%d)", m_gpio); + return false; + } + strcpy(setValue, GPIOString); + fwrite(&setValue, sizeof(char), 2, myOutputHandle); + fclose(myOutputHandle); + + return true; + } + + void + refreshPWM( double angle ) + { + m_gpio_state = true; + m_wdog.reset(); + degAngle = DUNE::Math::Angles::degrees(std::abs(angle)); + + if(degAngle < 0) + degAngle = 0; + if(degAngle > 180) + degAngle = 180; + + valueUP = (10 * degAngle) + 600; + + if ((myOutputHandle = fopen(GPIOValue, "rb+")) == NULL) + { + m_task->err("Unable to open value handle (%d)", m_gpio); + m_gpio_state = false; + } + strcpy(setValue, "1"); // Set value high + fwrite(&setValue, sizeof(char), 1, myOutputHandle); + fclose(myOutputHandle); + Delay::waitUsec(valueUP); + // Set output to low + if ((myOutputHandle = fopen(GPIOValue, "rb+")) == NULL) + { + m_task->err("Unable to open value handle (%d)", m_gpio); + m_gpio_state = false; + } + strcpy(setValue, "0"); // Set value low + fwrite(&setValue, sizeof(char), 1, myOutputHandle); + fclose(myOutputHandle); + + while(!m_wdog.overflow()) + { + Delay::waitUsec(20); + } + } + + //! Parent task. + DUNE::Tasks::Task* m_task; + //Handle of servo pinout + FILE *myOutputHandle; + //Mode in/out of pinout + char setValue[4]; + char GPIODirection[64]; + //Name of pin to use + char GPIOString[4]; + //Value to put in pinout + char GPIOValue[64]; + //! Time of delay to refresh in miliseconds + int c_time_delayms; + //! Value of angle in degrees + int degAngle; + //! Time to kept in high value + int valueUP; + //! Watchdog timeout. + double wdog_tout; + //! Watchdog. + Counter m_wdog; + //! State of setAngle function + bool m_update_angle; + }; + } +} + +#endif diff --git a/src/Actuators/PWM/Task.cmake b/src/Actuators/PWM/Task.cmake new file mode 100644 index 0000000000..caa2e228b0 --- /dev/null +++ b/src/Actuators/PWM/Task.cmake @@ -0,0 +1,4 @@ +# This task is Linux specific. +if(NOT DUNE_OS_LINUX) + set(TASK_ENABLED FALSE) +endif(NOT DUNE_OS_LINUX) diff --git a/src/Actuators/PWM/Task.cpp b/src/Actuators/PWM/Task.cpp new file mode 100644 index 0000000000..a45d314edc --- /dev/null +++ b/src/Actuators/PWM/Task.cpp @@ -0,0 +1,229 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: PGonçalves * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include + +//Local headers +#include "ServoPWM.hpp" + +namespace Actuators +{ + namespace PWM + { + using DUNE_NAMESPACES; + + static const unsigned int c_max_pwm = 3; + static const std::string c_mode_operation[] = {"Gimbal", "Drop", "Sample"}; + + struct Task: public DUNE::Tasks::Task + { + //!Variables + struct Arguments + { + //! PinOut for pwm + int port_io[c_max_pwm]; + //! Operation Mode + std::string operation_mode; + }; + + Arguments m_args; + //! Servo 0 + ServoPwm* m_servo_0; + //! Servo 1 + ServoPwm* m_servo_1; + //! Servo 2 + ServoPwm* m_servo_2; + //! State of update msg servo position + bool updateMsg; + //! Value of servo position in deg + double valuePos; + //! ID servo + uint8_t idServo; + //! Wrong operation mode + bool m_wrong_mode; + //! State of pwm + bool m_pwm_state; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_servo_0(NULL), + m_servo_1(NULL), + m_servo_2(NULL) + { + for(unsigned int i = 0; i < c_max_pwm; ++i) + { + std::string option = String::str("PinOut %u", i); + param(option, m_args.port_io[i]) + .defaultValue("") + .description("Port IO for Output PWM."); + } + + param("Operation Mode", m_args.operation_mode) + .defaultValue("") + .description("Operation Mode."); + + bind(this); + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + if ( m_args.operation_mode == c_mode_operation[0]) + { + m_servo_0 = new ServoPwm(this, m_args.port_io[0], 1.308997, true); + m_servo_0->start(); + m_servo_1 = new ServoPwm(this, m_args.port_io[1], 1.308997, true); + m_servo_1->start(); + m_wrong_mode = false; + } + else if (m_args.operation_mode == c_mode_operation[1]) + { + m_servo_2 = new ServoPwm(this, m_args.port_io[2], 1.308997, false); + m_servo_2->start(); + m_wrong_mode = false; + } + else if (m_args.operation_mode == c_mode_operation[2]) + { + m_servo_0 = new ServoPwm(this, m_args.port_io[0], 3.141593, false); + m_servo_0->start(); + m_servo_1 = new ServoPwm(this, m_args.port_io[1], 3.141593, false); + m_servo_1->start(); + m_servo_2 = new ServoPwm(this, m_args.port_io[2], 3.141593, false); + m_servo_2->start(); + m_wrong_mode = false; + } + else + m_wrong_mode = true; + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_servo_0 != NULL) + { + m_servo_0->stopAndJoin(); + delete m_servo_0; + m_servo_0 = NULL; + } + if (m_servo_1 != NULL) + { + m_servo_1->stopAndJoin(); + delete m_servo_1; + m_servo_1 = NULL; + } + if (m_servo_2 != NULL) + { + m_servo_2->stopAndJoin(); + delete m_servo_2; + m_servo_2 = NULL; + } + } + + void + consume(const IMC::SetServoPosition* msg) + { + m_pwm_state = true; + valuePos = msg->value; + idServo = msg->id; + if (!m_wrong_mode) + { + if(idServo == 0) + { + //war("SERVO 0: %f", valuePos); + m_servo_0->SetPwmValue(valuePos); + if(!m_servo_0->CheckGPIOSate()) + m_pwm_state = false; + } + else if(idServo == 1) + { + //war("SERVO 1: %f", valuePos); + m_servo_1->SetPwmValue(valuePos); + if(!m_servo_1->CheckGPIOSate()) + m_pwm_state = false; + } + else if(idServo == 2) + { + //war("SERVO 2: %f", valuePos); + m_servo_2->SetPwmValue(valuePos); + if(!m_servo_2->CheckGPIOSate()) + m_pwm_state = false; + } + } + else + + if (!m_pwm_state) + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + + updateMsg = true; + } + + //! Main loop. + void + onMain(void) + { + IMC::ServoPosition msgServoPos; + + if (m_wrong_mode) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_MISSING_DATA); + err("Error in config file"); + } + else + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(m_args.operation_mode.c_str())); + } + + while (!stopping()) + { + if(updateMsg) + { + msgServoPos.value = valuePos; + msgServoPos.id = idServo; + dispatch(msgServoPos); + updateMsg = false; + } + + waitForMessages(1.0); + } + } + }; + } +} +DUNE_TASK diff --git a/src/Actuators/SCRTv4/Listener.hpp b/src/Actuators/SCRTv4/Listener.hpp index daa65d2337..91c68a0eb7 100644 --- a/src/Actuators/SCRTv4/Listener.hpp +++ b/src/Actuators/SCRTv4/Listener.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/SCRTv4/Task.cpp b/src/Actuators/SCRTv4/Task.cpp index 9bc1a36bd0..eb353f794b 100644 --- a/src/Actuators/SCRTv4/Task.cpp +++ b/src/Actuators/SCRTv4/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/SIMCT01/Task.cpp b/src/Actuators/SIMCT01/Task.cpp index 94a2bfb077..4b438dd8c9 100644 --- a/src/Actuators/SIMCT01/Task.cpp +++ b/src/Actuators/SIMCT01/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Actuators/SingleSIMCT01/Task.cpp b/src/Actuators/SingleSIMCT01/Task.cpp index 98aabfb73c..ed6ec8b7b9 100644 --- a/src/Actuators/SingleSIMCT01/Task.cpp +++ b/src/Actuators/SingleSIMCT01/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/UnderwaterAcoustics/Task.cmake b/src/Actuators/Torqeedo/Task.cmake similarity index 100% rename from src/Simulators/UnderwaterAcoustics/Task.cmake rename to src/Actuators/Torqeedo/Task.cmake diff --git a/src/Actuators/Torqeedo/Task.cpp b/src/Actuators/Torqeedo/Task.cpp new file mode 100644 index 0000000000..44115aa7f6 --- /dev/null +++ b/src/Actuators/Torqeedo/Task.cpp @@ -0,0 +1,673 @@ +//*************************************************************************** +// Copyright 2007-2020 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Nikolai Lauvås (NTNU, Department of Engineering Cybernetics) * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +// DUNE headers. +#include +#include + +#define ADDR_SOURCE 0xfe +#define ADDR_TQIF 0xab +namespace Actuators +{ + //! This task acts as a bridge between the Maritime Robotics(MR) Interface card to Torqeedo motors and batteries, and DUNE with IMC messages + //! Messages are sent to the motors periodically, at least once per/second, or else motors stops(see msg_tq_motor_set in mr_can.h from MR) + //! + //! Reads and writes CAN frames to a buffer that is sent to Hardware::SocketCAN. + //! @author Nikolai Lauvås + namespace Torqeedo + { + using DUNE_NAMESPACES; + //! Maximum number of batteries connected to the Torqeedo board + static const unsigned c_num_batteries = 4; + //! Number of power channels + static const unsigned c_pwrs_count = 10; + //! Number of power rails + static const unsigned c_pwr_rails_count = 5; + //! Number of motors + static const unsigned c_motors = 2; + enum torqeedo_msg_identifiers_t + { + MSG_TEXT = 0, + MSG_CAP_AMP = 1, + MSG_CAP_WATT = 2, + MSG_RAIL = 3, + MSG_HOUSEKEEPING = 4, + MSG_TEMPERATURE = 5, + MSG_ID = 6, + MSG_BATCELLS = 7, + MSG_OUTPUTS = 8, + MSG_OUTPUT_SET = 9, + MSG_UPTIME = 10, + MSG_BOOTLOADER = 11, + MSG_TQ_MOTOR_DRIVE = 12, + MSG_TQ_MOTOR_SET = 13, + MSG_TQ_BAT_STATUS = 14, + MSG_TQ_BATCTL = 15, + MSG_TQ_MOTOR_STATUS_BITS = 16, + MSG_RESET = 17, + MSG_WINCH_TELEMETRY = 18, + MSG_WINCH_COMMAND = 19, + MSG_WINCH_MOVING = 20, + MSG_ID_V2 = 21 + }; + + enum torqeedo_power_rails_t + { + R_H_MOT0 = 0, + R_H_MOT1 = 1, + R_H_AUX0 = 2, + R_H_AUX1 = 2, + R_H_12V1 = 3, + R_H_12V2 = 3, + R_H_12V3 = 3, + R_H_VR0 = 3, + R_H_VR1 = 3, + R_H_5V = 4 + }; + enum torqeedo_power_channels_t + { + CH_H_MOT0 = 0, + CH_H_MOT1 = 0, + CH_H_AUX0 = 0, + CH_H_AUX1 = 1, + CH_H_12V1 = 0, + CH_H_12V2 = 1, + CH_H_12V3 = 2, + CH_H_VR0 = 3, + CH_H_VR1 = 4, + CH_H_5V = 0 + }; + struct Arguments + { + //! CAN bus device name + std::string can_dev; + //! Power channels names. + std::string pwr_names[c_pwrs_count]; + //! Initial power channels states. + unsigned pwr_states[c_pwrs_count]; + //! Write to motor every motor_write_divider times task is run + unsigned int motor_write_divider; + //! Motor labels + std::string motor_labels[c_motors]; + //! Rails labels + std::string rail_labels[c_pwr_rails_count]; + }; + //! Power Channel data structure. + struct PowerChannel + { + torqeedo_power_rails_t rail; + torqeedo_power_channels_t channel; + IMC::PowerChannelState::StateEnum state; + }; + struct Task: public DUNE::Tasks::Periodic + { + //! Is there unsent power control messages + bool m_unsent_power_parameters; + //! Most recent throttle values. + unsigned int motor_send_counter; + // Datatype for storing power lines and states + typedef std::map PowerChannelMap; + //! Power channels by name. + PowerChannelMap m_pwr_chs; + //! Batteries Entities + unsigned m_battery_eid[c_num_batteries]; + //! Motors Entities + unsigned m_motor_eid[c_motors]; + //! Power Rail Entities + unsigned m_power_rail_eid[c_pwr_rails_count]; + //! Most recent throttle values. + int16_t motor0_throttle, motor1_throttle; + //! CAN connection variable + Hardware::SocketCAN* m_can; + //! CAN buffer used for storing and sending messages + char m_can_bfr[9]; + //! Task arguments. + Arguments m_args; + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Periodic(name, ctx), + m_unsent_power_parameters(false), + motor_send_counter(0), + motor0_throttle(0), + motor1_throttle(0), + m_can(NULL) + { + param("CAN Port - Device", m_args.can_dev) + .defaultValue("") + .description("CAN port used to communicate with the Torqeedo board."); + + param("Motor write divider", m_args.motor_write_divider) + .defaultValue("20") + .description("Write to motor every motor_write_divider times task is run"); + + char power_channel_pcb_labels[c_pwrs_count][8] = {"H_MOT0\0","H_MOT1\0","H_AUX0\0","H_AUX1\0","H_12V1\0","H_12V2\0","H_12V3\0","H_VR0\0","H_VR1\0","H_5V\0"}; + for (unsigned i= 0; i < c_pwrs_count; i++) + { + std::string option = String::str("Power Channel %s - Name", power_channel_pcb_labels[i]); + param(option, m_args.pwr_names[i]); + + option = String::str("Power Channel %s - State", power_channel_pcb_labels[i]); + param(option, m_args.pwr_states[i]) + .defaultValue("0"); + } + + for (unsigned i= 0; i < c_motors; i++) + { + std::string option = String::str("Motor %d - Label", i); + param(option, m_args.motor_labels[i]); + } + + for (unsigned i= 0; i < c_pwr_rails_count; i++) + { + std::string option = String::str("Rail %d - Label", i); + param(option, m_args.rail_labels[i]); + } + + // Register handler routines. + bind(this); + bind(this); + bind(this); + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + inf(DTR("Update parameters")); + if(m_pwr_chs.size() != 0) { + m_pwr_chs.clear(); + m_unsent_power_parameters = true; + } + // Set up powerchannels + PowerChannel pcs[c_pwrs_count]; + pcs[0] = {R_H_MOT0, CH_H_MOT0, IMC::PowerChannelState::PCS_OFF}; + pcs[1] = {R_H_MOT1, CH_H_MOT1, IMC::PowerChannelState::PCS_OFF}; + pcs[2] = {R_H_AUX0, CH_H_AUX0, IMC::PowerChannelState::PCS_OFF}; + pcs[3] = {R_H_AUX1, CH_H_AUX1, IMC::PowerChannelState::PCS_OFF}; + pcs[4] = {R_H_12V1, CH_H_12V1, IMC::PowerChannelState::PCS_OFF}; + pcs[5] = {R_H_12V2, CH_H_12V2, IMC::PowerChannelState::PCS_OFF}; + pcs[6] = {R_H_12V3, CH_H_12V3, IMC::PowerChannelState::PCS_OFF}; + pcs[7] = {R_H_VR0, CH_H_VR0, IMC::PowerChannelState::PCS_OFF}; + pcs[8] = {R_H_VR1, CH_H_VR1, IMC::PowerChannelState::PCS_OFF}; + pcs[9] = {R_H_5V, CH_H_5V, IMC::PowerChannelState::PCS_OFF}; + for (unsigned i = 0; i < c_pwrs_count; i++) + { + if(m_args.pwr_states[i]) { + pcs[i].state = IMC::PowerChannelState::PCS_ON; + } + if(!(m_args.pwr_names[i].empty())) { + m_pwr_chs[m_args.pwr_names[i]] = pcs[i]; + } + } + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + std::string label = getEntityLabel(); + + for (unsigned i = 0; i < c_motors; i++) + { + m_motor_eid[i] = getEid(m_args.motor_labels[i]); + } + + for (unsigned i = 0; i < c_num_batteries; i++) + { + m_battery_eid[i] = getEid(label + " - Battery " + std::to_string(i)); + } + + for (unsigned i = 0; i < c_pwr_rails_count; i++) + { + m_power_rail_eid[i] = getEid(m_args.rail_labels[i]); + } + } + + unsigned + getEid(std::string label) + { + unsigned eid = 0; + try + { + eid = resolveEntity(label); + } + catch (Entities::EntityDataBase::NonexistentLabel& e) + { + (void)e; + eid = reserveEntity(label); + } + + return eid; + } + + //! Resolve entity names. + void + onEntityResolution(void) + { + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + try { + m_can = new Hardware::SocketCAN(m_args.can_dev, SocketCAN::CAN_BASIC_EFF); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + catch(std::runtime_error& e) { + cri(DTR("Could not open CAN: %s"), e.what()); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_IO_ERROR); + } + } + + void sendPowerChannelMessages() { + for (PowerChannelMap::iterator itr = m_pwr_chs.begin(); itr != m_pwr_chs.end(); ++itr) + { + sendSetPower(itr->second); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + spew(DTR("Init resources")); + if(m_can != NULL) { + sendPowerChannelMessages(); + } + } + + //! Release resources. + void + onResourceRelease(void) + { + try { + Memory::clear(m_can); + } + catch(std::runtime_error& e) { + err(DTR("Could not clear CAN: %s"), e.what()); + } + } + + void + consume(const IMC::QueryPowerChannelState* msg) + { + (void)msg; + + IMC::PowerChannelState m_pwr_ch; + + for (PowerChannelMap::iterator itr = m_pwr_chs.begin(); itr != m_pwr_chs.end(); ++itr) + { + if(!(itr->first.empty())) + { + m_pwr_ch.name = itr->first; + m_pwr_ch.state = itr->second.state; + dispatch(m_pwr_ch); + } + } + } + + //! Consume SetThrusterActuation messages + void + consume(const IMC::SetThrusterActuation* msg) + { + switch (msg->id) + { + case 0: + motor0_throttle = int16_t(1000 * msg->value); + break; + case 1: + motor1_throttle = int16_t(1000 * msg->value); + break; + } + } + + //! Consume PowerChannelControl messages, forward them to CAN bus + void + consume(const IMC::PowerChannelControl* msg) + { + PowerChannelMap::const_iterator itr = m_pwr_chs.find(msg->name); + if (itr == m_pwr_chs.end()) + return; + + IMC::PowerChannelControl::OperationEnum op = static_cast(msg->op); + if (op == IMC::PowerChannelControl::PCC_OP_TURN_ON) + m_pwr_chs[msg->name].state = IMC::PowerChannelState::PCS_ON; + else if (op == IMC::PowerChannelControl::PCC_OP_TURN_OFF) + m_pwr_chs[msg->name].state = IMC::PowerChannelState::PCS_OFF; + else + war("Chosen power state not implemented."); + sendSetPower(m_pwr_chs[msg->name]); + } + + //! Convenience/readability function for combining two char inputs to one uint16_t + uint16_t + combine2charToUint16(char most_significant, char least_significant) + { + return (uint16_t)(most_significant << 8) | least_significant; + } + + //! Convenience/readability function for combining two char inputs to one int16_t + int16_t + combine2charToInt16(char most_significant, char least_significant) + { + return (int16_t)(most_significant << 8) | least_significant; + } + + //! Parses a received MSG_TQ_BAT_STATUS from CAN bus buffer and sends relevant data to IMC + void + parseMSG_TQ_BAT_STATUS() + { + uint8_t bat_idx = m_can_bfr[0]; + uint8_t temp_C = m_can_bfr[1]; + uint16_t voltage_raw = combine2charToUint16(m_can_bfr[3], m_can_bfr[2]); + uint16_t current_raw = combine2charToUint16(m_can_bfr[5], m_can_bfr[4]); + uint8_t soc = m_can_bfr[6]; // State of charge + uint8_t err_code = m_can_bfr[7]; + + fp32_t voltage = fp32_t(voltage_raw) * 0.01; + fp32_t current = fp32_t(current_raw) * 0.1; + trace("MSG_TQ_BAT_STATUS: Batt#%d - Charge: %d; Voltage %0.2fV; Current: %0.1fA; Temp: %d, Error: %d", + bat_idx, soc, voltage, current, temp_C, err_code); + + IMC::Temperature temp_msg; + temp_msg.setSourceEntity(m_battery_eid[bat_idx]); + temp_msg.value = fp32_t(temp_C); + dispatch(temp_msg); + + IMC::Voltage voltage_msg; + voltage_msg.setSourceEntity(m_battery_eid[bat_idx]); + voltage_msg.value = voltage; + dispatch(voltage_msg); + + IMC::Current current_msg; + current_msg.setSourceEntity(m_battery_eid[bat_idx]); + current_msg.value = current; + dispatch(current_msg); + + IMC::FuelLevel level_msg; + level_msg.setSourceEntity(m_battery_eid[bat_idx]); + level_msg.value = fp32_t(soc); + dispatch(level_msg); + } + + //! Parses a received MSG_RAIL from CAN bus buffer and sends relevant data to IMC + void + parseMSG_RAIL(uint32_t id) + { + if(id == 0x0030abff) + { + uint8_t rail_idx = m_can_bfr[0]; + ///Voltage (mV) + uint16_t voltage_mV = combine2charToUint16(m_can_bfr[2], m_can_bfr[1]); + ///Current (mA) TODO: Should this be int32_t? signed in mrcan + int32_t current_mA = (int32_t)0 | (m_can_bfr[5] << 16) | (m_can_bfr[4] << 8) | m_can_bfr[3]; + ///Electronic fuse trip current (A*2) + uint8_t fuse_halfamps = m_can_bfr[6]; + char flags = m_can_bfr[7]; + + fp32_t voltage_V = fp32_t(voltage_mV) * 0.001; + fp32_t current_A = fp32_t(current_mA) * 0.001; + trace("MSG_RAIL: Rail#%d - Voltage: %0.3fV, Current: %f A, fuse_halfamps: %u, flags: %02X", rail_idx, voltage_V, current_A, fuse_halfamps, flags); + + IMC::Voltage voltage_msg; + voltage_msg.setSourceEntity(m_power_rail_eid[rail_idx]); + voltage_msg.value = voltage_V; + dispatch(voltage_msg); + + IMC::Current current_msg; + current_msg.setSourceEntity(m_power_rail_eid[rail_idx]); + current_msg.value = current_A; + dispatch(current_msg); + } + else + { + debug("Wrong message index: %08x", id); + } + } + + //! Parses a received MSG_TQ_MOTOR_DRIVE from CAN bus buffer and sends relevant data to IMC + void + parseMSG_TQ_MOTOR_DRIVE() + { + uint8_t mot_idx = m_can_bfr[0]; + /// Power in whole watts + uint16_t power = combine2charToUint16(m_can_bfr[2], m_can_bfr[1]); + /// PCB temperature in tenths of degrees celsius + int16_t temp_raw = combine2charToInt16(m_can_bfr[4], m_can_bfr[3]); + /// Divide by 7 (gear ratio) to get propeller RPM + uint16_t rpm_raw = combine2charToUint16(m_can_bfr[6], m_can_bfr[5]); + + fp32_t temp = fp32_t(temp_raw) * 0.1; + int16_t rpm = (int16_t)rpm_raw / 7; // Rounds down to nearest whole number + + inf("MSG_TQ_MOTOR_DRIVE: Motor#%d - Power: %dW; Temp %0.1fC; RPM: %d", + mot_idx, power, temp, rpm); + + IMC::Temperature temp_msg; + temp_msg.setSourceEntity(m_motor_eid[mot_idx]); + temp_msg.value = temp; + dispatch(temp_msg); + + IMC::Rpm rpm_msg; + rpm_msg.setSourceEntity(m_motor_eid[mot_idx]); + rpm_msg.value = rpm; + dispatch(rpm_msg); + } + + //! Parses a received MSG_TEXT and displays it + void + parseMSG_TEXT() + { + spew("MSG_TEXT: %s", m_can_bfr); + } + + //! Parses a received MSG_TQ_BATCTL from CAN bus buffer and makes it available for spew debug + void + parseMSG_TQ_BATCTL() + { + uint8_t motor_index = m_can_bfr[0]; // MAY need to be masked, only 4 last bits id, rest reserved + uint8_t master_error = m_can_bfr[1]; + uint8_t error_count = m_can_bfr[2]; + uint8_t firmware_ver = m_can_bfr[3]; + spew(DTR("MSG_TQ_BATCTL: Motor#%u - Master error: %u; Error count %u; Firmware version: %u"), + motor_index, master_error, error_count, firmware_ver); + } + + //! Parses a received MSG_OUTPUTS from CAN bus buffer and makes it available for spew debug + void + parseMSG_OUTPUTS() + { + uint8_t rail_index = m_can_bfr[0]; + uint32_t states = (m_can_bfr[4] << 24) | (m_can_bfr[3] << 16) | (m_can_bfr[2] << 8) | m_can_bfr[1]; + spew(DTR("MSG_OUTPUTS: Rail#%u - Master error: %08X;"), + rail_index, states); + } + + //! Parses a received MSG_UPTIME from CAN bus buffer and makes it available for spew debug + void + parseMSG_UPTIME() + { + uint32_t uptime_s = (uint32_t)0 | (m_can_bfr[2] << 16) | (m_can_bfr[1] << 8) | m_can_bfr[0]; + uint8_t last_reset_case = m_can_bfr[3]; + spew(DTR("MSG_UPTIME: Uptime#%ds; Last reset case: %01X;"), + uptime_s, last_reset_case); + } + + //! Parses a received MSG_ID_V2 from CAN bus buffer and makes it available for spew debug + void + parseMSG_ID_V2() + { + uint16_t company = combine2charToUint16(m_can_bfr[1], m_can_bfr[0]); + uint16_t product = combine2charToUint16(m_can_bfr[3], m_can_bfr[2]); + uint16_t serial_number = combine2charToUint16(m_can_bfr[5], m_can_bfr[4]); + uint16_t firmware_version = combine2charToUint16(m_can_bfr[7], m_can_bfr[6]); + spew(DTR("MSG_ID_V2: Company#%d; Product: %d; Serial number: %d; Firmware: %d;"), + company, product, serial_number, firmware_version); + } + + //! Parses a received MSG_TQ_MOTOR_STATUS_BITS from CAN bus buffer and makes it available for spew debug + void + parseMSG_TQ_MOTOR_STATUS_BITS() + { + uint8_t motor_index = m_can_bfr[0]; + uint16_t errors = combine2charToUint16(m_can_bfr[2], m_can_bfr[1]); + uint8_t status = m_can_bfr[3]; + spew(DTR("MSG_TQ_MOTOR_STATUS_BITS: Motor#%u - Errors: %u; Status %u"), + motor_index, errors, status); + } + //! Tries to read a message from CAN bus, if successful, call relevant parser + void + readCanMessage() + { + // Read message + uint32_t id; + if (Poll::poll(*m_can, 0.01)) { + m_can->readString(m_can_bfr, sizeof(m_can_bfr)); + id = m_can->getRXID(); + } else { + return; + } + + // Extract message identifier + uint8_t msg_id = uint8_t(id >> 20); + // Parse message + switch(msg_id) { + case MSG_TEXT: + parseMSG_TEXT(); + break; + case MSG_RAIL: + parseMSG_RAIL(id); + break; + case MSG_TQ_MOTOR_DRIVE: + parseMSG_TQ_MOTOR_DRIVE(); + break; + case MSG_TQ_BAT_STATUS: + parseMSG_TQ_BAT_STATUS(); + break; + case MSG_TQ_BATCTL: + parseMSG_TQ_BATCTL(); + break; + case MSG_OUTPUTS: + parseMSG_OUTPUTS(); + break; + case MSG_UPTIME: + parseMSG_UPTIME(); + break; + case MSG_ID_V2: + parseMSG_ID_V2(); + break; + case MSG_TQ_MOTOR_STATUS_BITS: + parseMSG_TQ_MOTOR_STATUS_BITS(); + break; + case MSG_CAP_AMP: + case MSG_CAP_WATT: + case MSG_HOUSEKEEPING: + case MSG_TEMPERATURE: + case MSG_ID: + case MSG_BATCELLS: + case MSG_OUTPUT_SET: + case MSG_BOOTLOADER: + case MSG_TQ_MOTOR_SET: + case MSG_RESET: + case MSG_WINCH_TELEMETRY: + case MSG_WINCH_COMMAND: + case MSG_WINCH_MOVING: + + debug(DTR("Known unimplemented MSG type received: %08X"), id); + break; + default: + inf(DTR("Unknown CAN MSG received: %08X"), id); + } + } + + //! Compiles a CAN id in a format supported by the Torqeedo interface board + uint32_t + prepareTorqeedoCANID(torqeedo_msg_identifiers_t msg_id) + { + return uint32_t(ADDR_TQIF | (ADDR_SOURCE << 8) | (msg_id << 20)); + } + + //! Sends MSG_OUTPUT_SET to CAN bus + void + sendSetPower(PowerChannel pc) + { // Dont send struct, send pointer or something + m_can_bfr[0] = pc.rail; + m_can_bfr[1] = pc.channel; + if(pc.state == IMC::PowerChannelState::PCS_OFF) { + m_can_bfr[2] = 0; + } else { + m_can_bfr[2] = 1; + } + m_can->setTXID(prepareTorqeedoCANID(MSG_OUTPUT_SET)); + m_can->write(m_can_bfr, 3); + } + + //! Sends MSG_TQ_MOTOR_SET to CAN bus + void + sendSetMotorThrottle( int16_t motor0, int16_t motor1) + { + m_can_bfr[0] = (char)(motor0 & 0x00FF); + m_can_bfr[1] = (char)((motor0 & 0xFF00) >> 8); + m_can_bfr[2] = (char)(motor1 & 0x00FF); + m_can_bfr[3] = (char)((motor1 & 0xFF00) >> 8); + + inf(DTR("CAN_MOTOR_MSG_SENT: %d, %d"), motor0, motor1); + + m_can->setTXID(prepareTorqeedoCANID(MSG_TQ_MOTOR_SET)); + m_can->write(m_can_bfr, 4); + } + + //! Main loop. + void + task(void) + { + if(m_can != NULL) { + waitForMessages(0.005); + motor_send_counter++; + if(motor_send_counter >= m_args.motor_write_divider) { + sendSetMotorThrottle(motor0_throttle, motor1_throttle); + motor_send_counter = 0; + } else if(m_unsent_power_parameters) { + sendPowerChannelMessages(); + m_unsent_power_parameters = false; + } else { + readCanMessage(); + } + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Autonomy/OnEvent/Sampler.hpp b/src/Autonomy/OnEvent/Sampler.hpp index a1560d6ede..d58476b5d6 100644 --- a/src/Autonomy/OnEvent/Sampler.hpp +++ b/src/Autonomy/OnEvent/Sampler.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Autonomy/OnEvent/Task.cpp b/src/Autonomy/OnEvent/Task.cpp index 13f28c6ff1..c7907dc636 100644 --- a/src/Autonomy/OnEvent/Task.cpp +++ b/src/Autonomy/OnEvent/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Autonomy/TREX/Task.cpp b/src/Autonomy/TREX/Task.cpp index 618fba8353..fffbffb025 100644 --- a/src/Autonomy/TREX/Task.cpp +++ b/src/Autonomy/TREX/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -307,7 +307,7 @@ namespace Autonomy startPlan.arg.set(spec); startPlan.request_id = 0; startPlan.flags = 0; - + startPlan.setDestination(m_ctx.resolver.id()); dispatch(startPlan); } diff --git a/src/Autonomy/TextActions/Task.cpp b/src/Autonomy/TextActions/Task.cpp index 6a32abacc4..93a9df76e1 100644 --- a/src/Autonomy/TextActions/Task.cpp +++ b/src/Autonomy/TextActions/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -35,16 +35,62 @@ namespace Autonomy { + //! This task processes incoming text messages which may + //! be resulting from received SMSes or Iridium commands. namespace TextActions { using DUNE_NAMESPACES; struct Task: public DUNE::Tasks::Task { + //! last received PlanControlState + IMC::PlanControlState* m_pcs; + //! last received VehicleState + IMC::VehicleState* m_vstate; + //! last received message + IMC::TextMessage* m_last; + //! Transmission request id + int m_reqid; + //! Plan database file. + Path m_db_file; + + + //! %Task arguments + struct Arguments + { + //! timeout, in seconds, for replies + int reply_timeout; + //! URL for documentation + std::string help_url; + //! List of valid commands (does not reply to anything else) + std::vector valid_cmds; + + } m_args; + Task(const std::string & name, Tasks::Context& ctx): - DUNE::Tasks::Task(name, ctx) + DUNE::Tasks::Task(name, ctx), + m_pcs(NULL), + m_vstate(NULL), + m_last(NULL), + m_reqid(0) { + param("Reply timeout", m_args.reply_timeout) + .defaultValue("60") + .minimumValue("30"); + + param("Documentation URL", m_args.help_url) + .defaultValue("https://bit.ly/2LZ0EOc"); + + param("Valid Commands", m_args.valid_cmds) + .defaultValue("abort,dislodge,dive,errors,info,force,go,help,phone,reboot,sk,start,surface"); + + m_db_file = m_ctx.dir_db / "Plan.db"; + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); } void @@ -54,26 +100,480 @@ namespace Autonomy } void - handlePlanCommand(const std::string& origin, const std::string& args) + onResourceRelease() override + { + Memory::clear(m_pcs); + Memory::clear(m_vstate); + Memory::clear(m_last); + } + + void + consume(const IMC::PlanControlState * msg) + { + Memory::replace(m_pcs, msg->clone()); + } + + void + consume(const IMC::VehicleState * msg) + { + Memory::replace(m_vstate, msg->clone()); + } + + void + consume(const IMC::TextMessage* msg) + { + inf("Processing text message from %s: '%s'", msg->origin.c_str(), + sanitize(msg->text).c_str()); + Memory::replace(m_last, msg->clone()); + std::istringstream iss(msg->text); + std::string cmd, args; + splitCommand(msg->text, cmd, args); + handleCommand(msg->origin, cmd, args); + } + + //! Handles responses from PlanGeneration requests + void + consume(const IMC::PlanGeneration* msg) + { + if (m_last == NULL) + return; + + std::stringstream ss; + + if (msg->op == PlanGeneration::OP_SUCCESS) + { + if (msg->params.empty()) + ss << "Started: '" << msg->plan_id << "'."; + else + ss << "Started: '" << msg->plan_id << " " << msg->params << "'."; + + reply(m_last->origin, ss.str()); + } + else if (msg->op == PlanGeneration::OP_ERROR) + { + if (std::find(m_args.valid_cmds.begin(), m_args.valid_cmds.end(), + msg->plan_id) != m_args.valid_cmds.end()) + { + ss << "Parser error: '" << msg->params << "'."; + reply(m_last->origin, ss.str()); + } + } + } + + ///! Handles responses from PlanControl requests + // + // If the last command failed send that info to the user. + void + consume(const IMC::PlanControl* msg) + { + if (m_last == NULL) + return; + + std::string last_cmd, args; + splitCommand(m_last->text, last_cmd, args); + + // if the last command was a "start" or "force", + // then the argument is the plan identifier + if (last_cmd == "start" || last_cmd == "force") + last_cmd = args; + + if (last_cmd == msg->plan_id) + { + // if the last plan request failed then send a reply to the user. + if (msg->op == PlanControl::PC_START && msg->type == PlanControl::PC_FAILURE) + { + std::stringstream ss; + ss << "Failed to exec " << msg->plan_id <<": " << msg->info << "."; + reply(m_last->origin, ss.str()); + } + } + } + + bool + retrievePlan(const std::string& plan_id, IMC::PlanSpecification& ps) + { + try + { + Database::Connection db(m_db_file.c_str(), Database::Connection::CF_RDONLY); + Database::Statement get_plan_stmt("select data from Plan where plan_id=?", db); + get_plan_stmt << plan_id; + if (!get_plan_stmt.execute()) + { + return false; + } + + Database::Blob data; + get_plan_stmt >> data; + ps.deserializeFields((const uint8_t*)&data[0], data.size()); + + } + catch (std::runtime_error& e) + { + return false; + } + + return true; + } + + PlanSpecification + splitPlan(const std::string& plan_id, const std::string& man_id) + { + PlanSpecification ps; + std::map maneuvers; + std::map transitions; + + ps.clear(); + if (!retrievePlan(plan_id, ps)) + { + throw std::invalid_argument("Invalid plan id"); + } + + for (PlanManeuver *man : ps.maneuvers) + { + maneuvers[man->maneuver_id] = man; + } + + for (PlanTransition *pt : ps.transitions) + { + transitions[pt->source_man] = pt; + } + + PlanSpecification newSpec; + newSpec.end_actions = ps.end_actions; + newSpec.start_actions = ps.start_actions; + newSpec.variables = ps.variables; + newSpec.vnamespace = ps.vnamespace; + newSpec.description = ps.description; + newSpec.plan_id = ps.plan_id + "-" + man_id; + newSpec.start_man_id = man_id; + + + std::string cur_man = man_id; + while(!cur_man.empty()) { + if (maneuvers.find(cur_man) == maneuvers.end()) + { + throw std::invalid_argument("Invalid maneuver id"); + } + + newSpec.maneuvers.push_back(maneuvers[cur_man]); + if (transitions.find(cur_man) == transitions.end()) + { + cur_man = ""; + } + else + { + PlanTransition *pt = transitions[cur_man]; + newSpec.transitions.push_back(pt); + cur_man = pt->dest_man; + } + } + + return newSpec; + } + + + //! Checks if a string is a phone number + bool + checkNumber(const std::string& str) + { + std::string::const_iterator it = str.begin(); + if(String::startsWith(str,"+") && str.size() > 1) + it++; + else if(String::startsWith(str,"+") && str.size() <= 1) + return false; + while (it != str.end() && std::isdigit(*it)) + ++it; + return !str.empty() && it == str.end(); + } + + /**! Splits the text into command and arguments + * \param[in] text The text to be split + * \param[out] cmd The first word of the text + * \param[out] args The remaining text or empty string if text has just one word. + */ + void + splitCommand(const std::string& text, std::string& cmd, std::string& args) + { + cmd = sanitize(text); + size_t pos = cmd.find(" "); + + if (pos != std::string::npos) + { + args = cmd.substr(pos + 1); + cmd = cmd.substr(0, pos); + } + + std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower); + + if (!args.empty()) + inf("Command is '%s', Argument is '%s'", cmd.c_str(), args.c_str()); + } + + //! Send back a reply to a TextMessage's origin + //! \param origin the original sender + //! \param text the text to be sent back to the sender + void + reply(const std::string& origin, const std::string& text) { + TransmissionRequest req; + req.setDestination(m_ctx.resolver.id()); + req.data_mode = TransmissionRequest::DMODE_TEXT; + req.txt_data = text; + req.deadline = Clock::getSinceEpoch() + m_args.reply_timeout; + req.req_id = ++m_reqid; + + // if request was sent over sms + if (origin.find("+") == 0) + { + req.comm_mean = TransmissionRequest::CMEAN_GSM; + req.destination = origin; + inf("Replying to %s: '%s'", req.destination.c_str(), req.txt_data.c_str()); + dispatch(req); + } + else if (origin == "iridium") + { + req.comm_mean = TransmissionRequest::CMEAN_SATELLITE; + req.destination = ""; + inf("Replying via Iridium: '%s'", req.txt_data.c_str()); + dispatch(req); + } + else if (String::startsWith(origin, "acoustic/")) + { + if (origin.length() < 10) + { + war("Bad acoustic origin: %s", origin.c_str()); + return; + } + IMC::TextMessage inner; + inner.text = text; + req.comm_mean = TransmissionRequest::CMEAN_ACOUSTIC; + req.data_mode = TransmissionRequest::DMODE_INLINEMSG; + req.txt_data = ""; + req.msg_data.set(&inner); + req.destination = origin.substr(9); + dispatch(req); + } + else + war("Not replying as origin is not addressable: '%s'.", + origin.c_str()); + } + + //! Parse incoming command and run it. + //! \param origin The original sender + //! \param cmd The command to be executed + //! \param args The arguments of the command (if any) + void + handleCommand(const std::string& origin, const std::string& cmd, const std::string& args) + { + if (cmd == "start") + handleStartCommand(origin, args, false); + else if (cmd == "force") + handleStartCommand(origin, args, true); + else if (cmd == "abort") + handleAbortCommand(origin, args); + else if (cmd == "errors") + handleErrorsCommand(origin); + else if (cmd == "info") + handleInfoCommand(origin); + else if (cmd == "help") + handleHelpCommand(origin); + else if (cmd == "reboot") + handleRebootCommand(origin, args); + else if (cmd == "phone") + handleChangeNumCommand(origin, args); + else if (cmd == "resume") + handleResumeCommand(origin, args, false); + else + handlePlanGeneratorCommand(origin, cmd, args); + } + + //! Execute command 'ERRORS' + void + handleErrorsCommand(const std::string& origin) + { + std::stringstream ss; + + if (m_vstate != NULL) + { + if (m_vstate->error_count > 0) { + ss << (int) m_vstate->error_count << " errors: " << m_vstate->error_ents; + reply(origin, ss.str()); + } + else + reply(origin, "Vehicle has no reported errors."); + } + } + + //!Execute command 'phone' for the one in args or for origin if the args is null + void + handleChangeNumCommand(const std::string& origin,const std::string& args) + { + std::string newNum,foo; + std::stringstream ss; + if(args.empty()) + newNum = origin; + else { + splitCommand(args,newNum,foo); //retrieves the first arg + newNum = sanitize(newNum); + if(!checkNumber(newNum)) + { + war(DTR("Unable to change emergency number to %s"),newNum.c_str()); + ss << "Unable to change emergency number, " << "see " << m_args.help_url << "."; + reply(origin,ss.str()); + return; //Not a valid phone number + } + } + IMC::EntityParameter parmeter; + parmeter.name = "SMS Recipient Number"; + parmeter.value = newNum; + IMC::SetEntityParameters params; + params.name = "Emergency Monitor"; + params.params.push_back(parmeter); + dispatch(params, DF_LOOP_BACK); + ss << "Changed emergency number " << " to " << newNum; + reply(origin,ss.str()); + } + + //! Execute command 'INFO' + void + handleInfoCommand(const std::string& origin) + { + std::stringstream ss; + if (m_pcs == NULL || m_vstate == NULL) + { + war("Not replying as no state messages are available."); + return; + } + + bool executing = m_pcs->state == PlanControlState::PCS_EXECUTING; + bool initializing = m_pcs->state == PlanControlState::PCS_INITIALIZING; + bool succeeded = m_pcs->last_outcome == PlanControlState::LPO_SUCCESS && + (m_pcs->state == PlanControlState::PCS_READY); + bool ready = m_pcs->last_outcome == PlanControlState::LPO_NONE && + (m_pcs->state == PlanControlState::PCS_READY); + + if (executing) + { + ss << "Executing " << m_pcs->plan_id << "::" << m_pcs->man_id << " | ETA: "; + + if (m_pcs->plan_eta != -1) + ss << m_pcs->plan_eta << "s / " << std::fixed << std::setprecision(1) << m_pcs->plan_progress << "%."; + else + ss << "N/D."; + } + else if (initializing) + ss << "Initializing " << m_pcs->plan_id << "."; + else if (ready) + ss << "Vehicle is ready."; + else if (succeeded) + ss << "Finished " << m_pcs->plan_id << "."; + else + ss << "Failed to exec " << m_pcs->plan_id <<": " << m_vstate->last_error << "."; + + reply(origin, ss.str()); + } + + //! Execute command 'REBOOT' + void + handleRebootCommand(const std::string& origin, const std::string& args) + { + char what[32]; + std::sscanf(args.c_str(), "%s", what); + RestartSystem msg; + if (!strcmp(what, "dune")) + { + war("Restarting DUNE requested by %s", origin.c_str()); + reply(origin, "Restarting DUNE."); + msg.type = RestartSystem::RSTYPE_DUNE; + dispatch(msg); + } + else if (!strcmp(what, "aux")) + { + war("Restarting Auxiliary CPU requested by %s", origin.c_str()); + reply(origin, "Restarting Auxiliary CPU."); + PowerChannelControl pcc; + pcc.op = PowerChannelControl::PCC_OP_RESTART; + pcc.name = "Auxiliary CPU"; + dispatch(pcc); + } + else + { + war("Restarting Main CPU requested by %s", origin.c_str()); + reply(origin, "Restarting."); + msg.type = RestartSystem::RSTYPE_SYSTEM; + dispatch(msg); + } + } + + //! Execute command 'START' + void + handleStartCommand(const std::string& origin, const std::string& args, bool ignore_errors = true) { // Plan control message! IMC::PlanControl pc; pc.type = IMC::PlanControl::PC_REQUEST; pc.op = IMC::PlanControl::PC_START; - pc.flags = IMC::PlanControl::FLG_IGNORE_ERRORS; - + if (ignore_errors) + pc.flags = IMC::PlanControl::FLG_IGNORE_ERRORS; + pc.setDestination(m_ctx.resolver.id()); char plan_id[32]; std::sscanf(args.c_str(), "%s", plan_id); pc.plan_id = plan_id; inf(DTR("received SMS request to start plan '%s'"), sanitize(pc.plan_id).c_str()); + std::stringstream ss; + ss << "Started execution of " << plan_id; + if (ignore_errors) + ss << " ignoring errors."; + else + ss << "."; + reply(origin, ss.str()); // Send the plan start request dispatch(pc); (void)origin; } + + //! Execute command 'RESUME' + void + handleResumeCommand(const std::string& origin, const std::string& args, bool ignore_errors = true) + { + char plan_id[32]; + char man_id[32]; + + std::sscanf(args.c_str(), "%s %s", plan_id, man_id); + + inf(DTR("received SMS request to resume plan '%s' starting from maneuver '%s'"), + sanitize(plan_id).c_str(), sanitize(man_id).c_str()); + + std::stringstream ss; + + try { + PlanSpecification spec = splitPlan(sanitize(plan_id), sanitize(man_id)); + IMC::PlanControl pcontrol; + pcontrol.arg.set(spec); + pcontrol.info = DTR("Plan generated automatically"); + pcontrol.type = IMC::PlanControl::PC_REQUEST; + pcontrol.op = IMC::PlanControl::PC_START; + pcontrol.plan_id = spec.plan_id; + pcontrol.setDestination(m_ctx.resolver.id()); + if (ignore_errors) + pcontrol.flags = IMC::PlanControl::FLG_CALIBRATE | IMC::PlanControl::FLG_IGNORE_ERRORS; + else + pcontrol.flags = IMC::PlanControl::FLG_CALIBRATE; + + dispatch(pcontrol); + ss << "Resuming plan " << sanitize(plan_id) << " from maneuver " << spec.start_man_id << "."; + reply(origin, ss.str()); + } + catch (std::exception& e) { + ss << "Error processing resume: " << e.what() << "."; + reply(origin, ss.str()); + } + } + + //! Execute command 'ABORT' void handleAbortCommand(const std::string& origin, const std::string& args) { @@ -81,57 +581,35 @@ namespace Autonomy IMC::Abort abort; abort.setDestination(getSystemId()); dispatch(abort); + reply(origin, "Aborted."); (void)args; } + //! Execute command 'HELP' void - handlePlanGeneratorCommand(const std::string& origin, const std::string& args) + handleHelpCommand(const std::string& origin) { - IMC::PlanGeneration pg; - std::istringstream iss(args); - std::string temp, tlist; - getline(iss, temp, ' '); - if (iss.str().size() > temp.size()) - tlist = std::string(iss.str(), temp.size()+1, iss.str().size() - temp.size()+1); + std::stringstream ss; + ss << "For a list of valid commands see " << m_args.help_url << "."; + reply(origin, ss.str()); + } - //TupleList tlist(msg->params, "=", ";", true); - //TupleList t(tlist, "=", ",", true); + //! Sends a PlanGeneration request resulting from an unknown command. + void + handlePlanGeneratorCommand(const std::string& origin, const std::string& cmd, const std::string& args) + { + IMC::PlanGeneration pg; pg.cmd = IMC::PlanGeneration::CMD_EXECUTE; pg.op = IMC::PlanGeneration::OP_REQUEST; - pg.params = tlist; - pg.plan_id = temp; + pg.plan_id = cmd; + pg.params = args; dispatch(pg); (void)origin; } - void - consume(const IMC::TextMessage* msg) - { - inf("processing text message from %s: \"%s\"", msg->origin.c_str(), sanitize(msg->text).c_str()); - std::istringstream iss(msg->text); - std::string cmd, args = ""; - getline(iss, cmd, ' '); - if (iss.str().size() > cmd.size()) - args = std::string(iss.str(), cmd.size()+1, iss.str().size() - cmd.size()+1); - //std::transform(cmd, cmd, cmd, ::tolower); - spew("command is %s, args are %s", cmd.c_str(), args.c_str()); - - if (cmd == "plan") - { - handlePlanCommand(msg->origin, args); - } - else if (cmd == "abort") - { - handleAbortCommand(msg->origin, args); - } - else - { - handlePlanGeneratorCommand(msg->origin, msg->text); - } - } void onMain(void) diff --git a/src/Control/ASV/HeadingAndSpeed/Task.cpp b/src/Control/ASV/HeadingAndSpeed/Task.cpp index 3dc185e01e..866a0f0c20 100644 --- a/src/Control/ASV/HeadingAndSpeed/Task.cpp +++ b/src/Control/ASV/HeadingAndSpeed/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/ASV/RemoteOperation/Task.cpp b/src/Control/ASV/RemoteOperation/Task.cpp index 6c97e0f3b8..0bcc918612 100644 --- a/src/Control/ASV/RemoteOperation/Task.cpp +++ b/src/Control/ASV/RemoteOperation/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -129,10 +129,13 @@ namespace Control m_speed = Math::trimValue(m_speed, -1.0 , 1.0); double hdng = (tuples.get("Heading", 0)) / 127.0; - double leftThrust = m_speed; + /*double leftThrust = m_speed; double rightThrust = m_speed; leftThrust *= 1+hdng*2; - rightThrust *= 1-hdng*2; + rightThrust *= 1-hdng*2;*/ + double leftThrust = m_speed + hdng; + double rightThrust = m_speed - hdng; + m_thrust[0].value = Math::trimValue(leftThrust, -1.0, 1.0); m_thrust[1].value = Math::trimValue(rightThrust, -1.0, 1.0); diff --git a/src/Control/AUV/Allocator/Task.cpp b/src/Control/AUV/Allocator/Task.cpp index f87592c2ce..d234f64177 100644 --- a/src/Control/AUV/Allocator/Task.cpp +++ b/src/Control/AUV/Allocator/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -33,6 +33,9 @@ // DUNE headers. #include +#define MS_AVG_SIZE 150 +#define RPM_AVG_SIZE 15 + namespace Control { namespace AUV @@ -58,6 +61,26 @@ namespace Control double max_fin_rate; //! ServoPosition label std::string spos_label; + //! Fins effect velocity dependent + bool velocity_dependent; + //! Fins effect velocity dependent + std::string velocity_dependent_unit; + //! minimum RPM value + double rpm_minimum; + //! Minimum Meter Per Second value + double ms_minimum; + //! Max RPM value + double max_rpm; + //! Max Meter Per Second value + double max_ms; + //! K pitch + double k_pitch; + //! K roll + double k_roll; + //! K yaw + double k_yaw; + //! + bool roll_not_velocity_dependent; }; struct Task: public DUNE::Tasks::Task @@ -68,6 +91,10 @@ namespace Control IMC::SetServoPosition m_last[c_fins]; //! Allocated torques feedback message. IMC::AllocatedControlTorques m_allocated; + //! Last lats EstimatedState + IMC::EstimatedState * m_last_estimated_state; + //! Last lats Rpm + IMC::Rpm * m_last_rpm; //! Braking bool m_braking; //! Entity id for the servo position messages @@ -80,9 +107,13 @@ namespace Control Time::Delta m_delta; //! Task arguments. Arguments m_args; + Math::MovingAverage* m_avg_ms ; + Math::MovingAverage* m_avg_rpm; Task(const std::string& name, Tasks::Context& ctx): Tasks::Task(name, ctx), + m_last_estimated_state(NULL), + m_last_rpm(NULL), m_braking(false), m_scope_ref(0) { @@ -106,6 +137,25 @@ namespace Control .units(Units::NewtonMeterPerRadian) .description("Fin effect N"); + param("Fin effect Velocity dependent", m_args.velocity_dependent) + .defaultValue("false") + .description("Fin effect Velocity dependent"); + + param("Fin effect Velocity dependent unit", m_args.velocity_dependent_unit) + .defaultValue("RPM") + .values("RPM, MeterPerSecond") + .description("Fin effect Velocity dependent unit"); + + param("Fin effect Rpm minimum value", m_args.rpm_minimum) + .defaultValue("200") + .units(Units::RPM) + .description("Fin effect Rpm Minimum value"); + + param("Fin effect minimum Meter Per Second value", m_args.ms_minimum) + .defaultValue("0.2") + .units(Units::MeterPerSecond) + .description("Fin effect Meter Per Second minimum value"); + param("Pitch Up Brake", m_args.pitch_brake) .defaultValue("false") .description("Pitch up when braking"); @@ -121,18 +171,45 @@ namespace Control .units(Units::DegreePerSecond) .description("Maximum rotation rate allowed by the servo"); + param("k roll", m_args.k_roll) + .defaultValue("1.0") + .minimumValue("0.0") + .description("k roll - Velocity dependent pitch fin effect "); + + param("k pitch", m_args.k_pitch) + .defaultValue("1.0") + .minimumValue("0.0") + .description("k pitch - Velocity dependent pitch fin effect "); + + param("k yaw", m_args.k_yaw) + .defaultValue("1.0") + .minimumValue("0.0") + .description("k yaw - Velocity dependent pitch fin effect "); + + param("Roll not velocity dependent", m_args.roll_not_velocity_dependent) + .defaultValue("false") + .description("Roll not velocity dependent"); + + + param("Entity Label - Servo Position", m_args.spos_label) .defaultValue("") .description("Label of the servo position message to compute produced torque"); + m_ctx.config.get("General", "Maximum Underwater RPMs", "1700.0", m_args.max_rpm); + m_ctx.config.get("General","Maximum Absolute Speed" , "2.0", m_args.max_ms); // Initialize main entity state. setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - + m_avg_ms = new Math::MovingAverage(150); + m_avg_rpm = new Math::MovingAverage(10); // Register handler routines. bind(this); bind(this); bind(this); bind(this); + bind(this); + bind(this); + } void @@ -163,7 +240,16 @@ namespace Control m_braking = false; requestDeactivation(); } - + //! Release resources. + void + onResourceRelease(void) + { + Memory::clear(m_last_estimated_state); + Memory::clear(m_last_rpm); + Memory::clear(m_avg_ms); + Memory::clear(m_avg_rpm); + + } void onResourceInitialization(void) { @@ -176,6 +262,18 @@ namespace Control m_last[i].id = i; m_servo_pos[i] = 0.0; } + m_avg_ms = new Math::MovingAverage(MS_AVG_SIZE); + m_avg_rpm = new Math::MovingAverage(RPM_AVG_SIZE); + + for (int i = 0; i < RPM_AVG_SIZE; i++) + { + m_avg_rpm->update(m_args.rpm_minimum/1000); + } + for (int i = 0; i < MS_AVG_SIZE; i++) + { + m_avg_ms->update(m_args.ms_minimum); + } + } //! Resolve entities for messages @@ -276,6 +374,23 @@ namespace Control allocate(0, 0, 0); } + void + consume(const IMC::EstimatedState* msg) + { + if (msg->getSource() != getSystemId()) + return; + Memory::clear(m_last_estimated_state); + m_last_estimated_state =static_cast(msg->clone()); + } + + void + consume(const IMC::Rpm* msg) + { + if (msg->getSource() != getSystemId()) + return; + Memory::clear(m_last_rpm); + m_last_rpm = static_cast(msg->clone()); + } //! Allocate desired control torques on the fins //! @param[in] k desired control torque in roll //! @param[in] m desired control torque in pitch @@ -286,9 +401,43 @@ namespace Control float ang; float roll_margin_vfins; float roll_margin_hfins; + double rpm_m = m_args.rpm_minimum ; + double m_s = m_args.ms_minimum; + double rpm = rpm_m/1000, m_s_m = m_s; + float angroll = 0 ; + if(m_last_rpm!=NULL) + { + rpm_m = (double)m_last_rpm->value; + trimValueMod( rpm_m , m_args.rpm_minimum, m_args.max_rpm); + rpm_m =rpm_m /1000; + m_avg_rpm->update(rpm_m); + rpm = m_avg_rpm->mean(); + } + + if(m_last_estimated_state!=NULL) + { + m_s_m = (double) m_last_estimated_state->u; + trimValueMod( m_s_m , m_args.ms_minimum, m_args.max_ms); + m_avg_ms->update(m_s_m); + m_s = m_avg_ms->mean(); + } // Allocate N - ang = (n / m_args.conv[2]) * 0.5; + if(!m_args.velocity_dependent) + { + ang = (n / m_args.conv[2]) * 0.5; + } + else + { + if(m_args.velocity_dependent_unit == "RPM") + { + ang = m_args.k_yaw * (n / (m_args.conv[2]* rpm *rpm)) * 0.5; + } + else + { + ang = m_args.k_yaw * (n / (m_args.conv[2]* m_s *m_s)) * 0.5; + } + } if (trimValueMod(ang, -m_args.max_fin_rot, m_args.max_fin_rot)) { @@ -302,10 +451,39 @@ namespace Control m_fins[0].value = -ang; m_fins[3].value = -ang; - m_allocated.n = ang * m_args.conv[2] * 2.0; + + if(m_args.velocity_dependent) + { + if(m_args.velocity_dependent_unit == "RPM") + { + m_allocated.n = m_args.k_yaw * m_args.conv[2]* rpm *rpm * 2.0; + } + else + { + m_allocated.n = m_args.k_yaw * m_args.conv[2]* m_s * m_s * 2.0; + } + } + else + { + m_allocated.n = ang * m_args.conv[2] * 2.0; + } // Allocate M - ang = (m / m_args.conv[1]) * 0.5; + if(m_args.velocity_dependent) + { + if(m_args.velocity_dependent_unit == "RPM") + { + ang = m_args.k_pitch * (m / (m_args.conv[1]* rpm *rpm)) * 0.5; + } + else + { + ang = m_args.k_pitch * (m /(m_args.conv[1]* m_s *m_s)) * 0.5; + } + } + else + { + ang = (m / m_args.conv[1]) * 0.5; + } if (trimValueMod(ang, -m_args.max_fin_rot, m_args.max_fin_rot)) { @@ -319,11 +497,42 @@ namespace Control m_fins[1].value = -ang; m_fins[2].value = -ang; + + if(m_args.velocity_dependent) + { + if(m_args.velocity_dependent_unit == "RPM") + { + m_allocated.m = m_args.k_pitch * m_args.conv[1]* rpm *rpm * 2.0; + } + else + { + m_allocated.m = m_args.k_pitch * m_args.conv[1]* m_s * m_s * 2.0; + } + } + else + { m_allocated.m = ang * m_args.conv[1] * 2.0; + } // Allocate K // Attempt to distribute evenly by the four fins - ang = (k / m_args.conv[0]) / c_fins; + if(m_args.velocity_dependent && m_args.roll_not_velocity_dependent == false) + { + if(m_args.velocity_dependent_unit == "RPM") + { + ang = m_args.k_roll * (k / (m_args.conv[0] * rpm *rpm)) / c_fins; + angroll = ang; + } + else + { + ang = m_args.k_roll * (k / (m_args.conv[0] * m_s * m_s)) / c_fins; + angroll = ang; + } + } + else + { + ang = (k / m_args.conv[0]) / c_fins; + } // Determine the maximum angle for even distribution ang = trimValue(ang, -roll_margin_hfins, roll_margin_hfins); @@ -334,30 +543,74 @@ namespace Control m_fins[0].value -= ang; m_fins[3].value += ang; - // Remove the used up margin from the avaliable margins - roll_margin_hfins -= std::abs(ang); - roll_margin_vfins -= std::abs(ang); - m_allocated.k = ang * m_args.conv[0] * c_fins; + // Remove the used up margin from the avaliable margins + roll_margin_hfins -= std::abs(ang); + roll_margin_vfins -= std::abs(ang); - // Check where to place the remaining roll torque - ang = ((k - m_allocated.k) / m_args.conv[0]) * 0.5; - if (roll_margin_hfins > 0) + if(m_args.velocity_dependent && m_args.roll_not_velocity_dependent == false) { - ang = trimValue(ang, -roll_margin_hfins, roll_margin_hfins); - - m_fins[1].value += ang; - m_fins[2].value -= ang; - m_allocated.k += ang * m_args.conv[0] * 2.0; + ang = angroll - ang; + + if(m_args.velocity_dependent_unit == "RPM") + { + if (roll_margin_hfins > 0) + { + ang = trimValue(ang, -roll_margin_hfins, roll_margin_hfins); + + m_fins[1].value += ang; + m_fins[2].value -= ang; + } + else if (roll_margin_vfins > 0) + { + ang = trimValue(ang, -roll_margin_vfins, roll_margin_vfins); + + m_fins[0].value -= ang; + m_fins[3].value += ang; + } + m_allocated.k = m_args.conv[0]* rpm * rpm * c_fins; + } + else + { + if (roll_margin_hfins > 0) + { + ang = trimValue(ang, -roll_margin_hfins, roll_margin_hfins); + + m_fins[1].value += ang; + m_fins[2].value -= ang; + } + else if (roll_margin_vfins > 0) + { + ang = trimValue(ang, -roll_margin_vfins, roll_margin_vfins); + + m_fins[0].value -= ang; + m_fins[3].value += ang; + } + m_allocated.k = m_args.conv[0]* m_s * m_s * c_fins; + } } - else if (roll_margin_vfins > 0) + else { - ang = trimValue(ang, -roll_margin_vfins, roll_margin_vfins); + m_allocated.k = ang * m_args.conv[0] * c_fins; - m_fins[0].value -= ang; - m_fins[3].value += ang; - m_allocated.k += ang * m_args.conv[0] * 2.0; - } + // Check where to place the remaining roll torque + ang = ((k - m_allocated.k) / m_args.conv[0]) * 0.5; + if (roll_margin_hfins > 0) + { + ang = trimValue(ang, -roll_margin_hfins, roll_margin_hfins); + m_fins[1].value += ang; + m_fins[2].value -= ang; + m_allocated.k += ang * m_args.conv[0] * 2.0; + } + else if (roll_margin_vfins > 0) + { + ang = trimValue(ang, -roll_margin_vfins, roll_margin_vfins); + + m_fins[0].value -= ang; + m_fins[3].value += ang; + m_allocated.k += ang * m_args.conv[0] * 2.0; + } + } dispatchAllFins(); dispatch(m_allocated); diff --git a/src/Control/AUV/Attitude/Task.cpp b/src/Control/AUV/Attitude/Task.cpp index 810d519c91..15c6f58f68 100644 --- a/src/Control/AUV/Attitude/Task.cpp +++ b/src/Control/AUV/Attitude/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -31,6 +31,7 @@ // ISO C++ 98 headers. #include +#include #include #include @@ -60,11 +61,13 @@ namespace Control //! Required loops. static const uint32_t c_required = IMC::CL_TORQUE; //! Loops names. - static const std::string c_loop_name[] = {DTR_RT("Roll"), DTR_RT("Pitch"), - DTR_RT("Depth"), DTR_RT("Heading"), - DTR_RT("Heading Rate")}; + static const std::string c_loop_name[] + = { DTR_RT("Roll"), DTR_RT("Pitch"), DTR_RT("Depth"), + DTR_RT("Altitude"), DTR_RT("Heading"), DTR_RT("Heading Rate") }; //! Loops units. - static const unsigned c_loop_unit[] = {Units::Degree, Units::Degree, Units::Degree, Units::DegreePerSecond, Units::Degree}; + static const unsigned c_loop_unit[] + = { Units::Degree, Units::Degree, Units::Degree, + Units::Degree, Units::DegreePerSecond, Units::Degree }; enum Loops { @@ -74,6 +77,8 @@ namespace Control LP_PITCH, //! Depth loop. LP_DEPTH, + //! Altitude loop. + LP_ALT, //! Heading loop. LP_HEADING, //! Heading rate loop. @@ -138,6 +143,12 @@ namespace Control float depth_threshold; //! Roll speed compensation. RollCompensation rc; + //! + int sampling_rate_relation; + //! Weights of the vertical reference filter. + std::vector vref_filt_weights; + //! Enable dedicated altitude controller. + bool altitude_control; }; struct Task: public DUNE::Control::BasicAutopilot @@ -161,10 +172,22 @@ namespace Control //! Task Arguments. Arguments m_args; + int m_sampling_rate_relation; + + //! Smoothed altitude reference. + std::unique_ptr> m_vref; + //! Derivative of the altitude reference. + Math::Derivative m_vref_d; + //! Derivative of the pitch reference. + Math::Derivative m_pref_d; + Task(const std::string& name, Tasks::Context& ctx): DUNE::Control::BasicAutopilot(name, ctx, c_controllable, c_required), m_ca(NULL), - m_extra_pitch(false) + m_extra_pitch(false), + m_vref(nullptr), + m_vref_d(), + m_pref_d() { // Load controller gains and integral limits. for (unsigned i = 0; i < LP_MAX_LOOPS; ++i) @@ -311,6 +334,20 @@ namespace Control .maximumValue("2.0") .description("Roll's minimum proportional gain in speed compensation"); + param("Depth-to-pitch PID sampling rate relation", m_args.sampling_rate_relation) + .defaultValue("1") + .minimumValue("1") + .maximumValue("5") + .description("Depth-to-pitch sampling rate relation"); + + param("Altitude Control -- Filter Weights", m_args.vref_filt_weights) + .description("Impulse response of the FIR filter used to smooth the " + "depth reference during altitude control."); + + param("Altitude Control -- Enabled", m_args.altitude_control) + .defaultValue("false") + .description("Enable dedicated altitude controller."); + m_ctx.config.get("General", "Underwater Depth Threshold", "0.3", m_args.depth_threshold); } @@ -319,6 +356,7 @@ namespace Control onResourceInitialization(void) { BasicAutopilot::onResourceInitialization(); + } //! Acquire resources. @@ -329,6 +367,8 @@ namespace Control if (m_ca_args.enabled) m_ca = new CoarseAltitude(&m_ca_args); + + m_vref = std::make_unique>(m_args.vref_filt_weights); } //! Release Resources. @@ -336,6 +376,7 @@ namespace Control onResourceRelease(void) { Memory::clear(m_ca); + m_vref.reset(); BasicAutopilot::onResourceRelease(); } @@ -405,6 +446,7 @@ namespace Control } initializePIDs(); + m_sampling_rate_relation = m_args.sampling_rate_relation; } //! Initialize PID related variables. @@ -415,6 +457,7 @@ namespace Control output_limits[LP_ROLL] = m_args.max_fin_rot; output_limits[LP_PITCH] = m_args.max_pitch_act; output_limits[LP_DEPTH] = m_args.max_pitch; + output_limits[LP_ALT] = m_args.max_pitch; output_limits[LP_HEADING] = m_args.max_hrate; output_limits[LP_HRATE] = m_args.max_fin_rot; @@ -437,6 +480,12 @@ namespace Control { BasicAutopilot::reset(); + if (m_vref) + m_vref->clear(); + + m_vref_d.clear(); + m_pref_d.clear(); + for (unsigned i = 0; i < LP_MAX_LOOPS; ++i) m_pid[i].reset(); } @@ -523,7 +572,6 @@ namespace Control { case VERTICAL_MODE_DEPTH: z_error = getVerticalRef() - msg->depth; - if (getVerticalRef() < m_args.depth_threshold) { if (m_args.force_pitch && std::fabs(z_error) < m_args.depth_threshold) @@ -536,11 +584,15 @@ namespace Control case VERTICAL_MODE_ALTITUDE: if (msg->alt < m_args.min_dvl_alt && msg->depth < m_args.min_dvl_depth) { + m_vref->clear(); + m_vref_d.clear(); + z_error = c_min_depth_ref; } else { float bfd = getBottomFollowDepth(); + m_vref->update(bfd); if (m_ca != NULL) { @@ -567,55 +619,95 @@ namespace Control if (use_offset) z_error += m_args.depth_offset; - if (!surface) + // Depth-to-pitch PID sampling rate relation + m_sampling_rate_relation++; + + if (m_sampling_rate_relation >= m_args.sampling_rate_relation) { - // extra pitch. - if (m_extra_pitch) + m_sampling_rate_relation = 0; + + if (!surface) { - // remove extra pitch. - if (std::fabs(z_error) < m_args.zref_extra - c_depth_hyst || - std::fabs(m_hrate_ref.value) > Angles::radians(c_max_hrate)) + // extra pitch. + if (m_extra_pitch) + { + // remove extra pitch. + if (std::fabs(z_error) < m_args.zref_extra - c_depth_hyst + || std::fabs(m_hrate_ref.value) + > Angles::radians(c_max_hrate)) + { + m_extra_pitch = false; + m_pid[LP_DEPTH].setOutputLimits(-m_args.max_pitch, + m_args.max_pitch); + m_pid[LP_ALT].setOutputLimits(-m_args.max_pitch, + m_args.max_pitch); + } + } + else { - m_extra_pitch = false; - m_pid[LP_DEPTH].setOutputLimits(-m_args.max_pitch, m_args.max_pitch); + // add extra pitch. + if ((std::fabs(z_error) > m_args.zref_extra) + && (m_args.extra_pitch > 0.0) + && std::fabs(m_hrate_ref.value) + < Angles::radians(c_max_hrate)) + { + m_extra_pitch = true; + float pitch = m_args.max_pitch + m_args.extra_pitch; + m_pid[LP_DEPTH].setOutputLimits(-pitch, pitch); + m_pid[LP_ALT].setOutputLimits(-pitch, pitch); + } + } + + const float z_rate + = -sin(msg->theta) * msg->u + + cos(msg->theta) + * (sin(msg->phi) * msg->v + cos(msg->phi) * msg->w); + + // Positive depth rate implies negative pitch, so the PID output + // is inverted. + if (getVerticalMode() == VERTICAL_MODE_DEPTH + || !m_args.altitude_control) + { + cmd = -m_pid[LP_DEPTH].step(timestep, z_error, -z_rate); + } + else + { + const float ref_rate = m_vref_d.update(m_vref->get()); + cmd + = -m_pid[LP_ALT].step(timestep, z_error, ref_rate - z_rate); } } else { - // add extra pitch. - if ((std::fabs(z_error) > m_args.zref_extra) && (m_args.extra_pitch > 0.0) - && std::fabs(m_hrate_ref.value) < Angles::radians(c_max_hrate)) - { - m_extra_pitch = true; - float pitch = m_args.max_pitch + m_args.extra_pitch; - m_pid[LP_DEPTH].setOutputLimits(-pitch, pitch); - } + cmd = m_args.surface_pitch; } - double val = -(-sin(msg->theta) * msg->u + cos(msg->theta) * - (sin(msg->phi) * msg->v + cos(msg->phi) * msg->w)); - - // Positive depth implies negative pitch - cmd = -m_pid[LP_DEPTH].step(timestep, z_error, val); + // Log the desired pitch + m_pitch_ref.value = cmd; + dispatch(m_pitch_ref); } else { - cmd = m_args.surface_pitch; + cmd = m_pitch_ref.value; + dispatch(m_pitch_ref); } - - // Log the desired pitch - m_pitch_ref.value = cmd; - dispatch(m_pitch_ref); } - //Now, track pitch + // Now, track pitch float pitch_err = (cmd - msg->theta); // With attitude compensation we use a different approach if (m_args.error_attitude) return pitch_err; - cmd = m_pid[LP_PITCH].step(timestep, pitch_err, -(msg->q * cos(msg->phi) - msg->r * sin(msg->phi))); + const float ref_rate = m_pref_d.update(cmd); + const float pitch_rate + = msg->q * cos(msg->phi) - msg->r * sin(msg->phi); + + cmd = m_args.altitude_control ? + m_pid[LP_PITCH].step(timestep, pitch_err, ref_rate - pitch_rate) : + m_pid[LP_PITCH].step(timestep, pitch_err, -pitch_rate); + return cmd; } diff --git a/src/Control/AUV/Diving/Task.cpp b/src/Control/AUV/Diving/Task.cpp index a6266c2e44..d5797bc8f2 100644 --- a/src/Control/AUV/Diving/Task.cpp +++ b/src/Control/AUV/Diving/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/AUV/LMI/Task.cpp b/src/Control/AUV/LMI/Task.cpp index d9f2f5ccf3..7e2c034076 100644 --- a/src/Control/AUV/LMI/Task.cpp +++ b/src/Control/AUV/LMI/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/AUV/RemoteOperation/Task.cpp b/src/Control/AUV/RemoteOperation/Task.cpp index 6bf6449f92..e1f8234ffa 100644 --- a/src/Control/AUV/RemoteOperation/Task.cpp +++ b/src/Control/AUV/RemoteOperation/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/AUV/Speed/Task.cpp b/src/Control/AUV/Speed/Task.cpp index e8525caa46..92611d0eac 100644 --- a/src/Control/AUV/Speed/Task.cpp +++ b/src/Control/AUV/Speed/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/AntennaTracker/Task.cpp b/src/Control/AntennaTracker/Task.cpp index 0c80a783a9..895694e954 100644 --- a/src/Control/AntennaTracker/Task.cpp +++ b/src/Control/AntennaTracker/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/Path/Height/Task.cpp b/src/Control/Path/Height/Task.cpp index 2475281794..971857ab34 100644 --- a/src/Control/Path/Height/Task.cpp +++ b/src/Control/Path/Height/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -158,10 +158,15 @@ namespace Control } void - onEntityResolution(void) + onResourceRelease(void) { - spew("Entity resolution."); + Memory::clear(m_cmd_flt); + Memory::clear(m_state_flt); + } + void + onResourceAcquisition(void) + { // Process the systems allowed to define DesiredZ m_cmd_flt = new Tasks::SourceFilter(*this, true, m_args.cmd_src, "DesiredZ"); // Process the systems allowed to pass the EstimatedState diff --git a/src/Control/Path/ILOS/Task.cpp b/src/Control/Path/ILOS/Task.cpp index 335b20a019..a307f89849 100644 --- a/src/Control/Path/ILOS/Task.cpp +++ b/src/Control/Path/ILOS/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/Path/LOSnSMC/Task.cpp b/src/Control/Path/LOSnSMC/Task.cpp index 9bb5fc7a0a..bb4c5ca267 100644 --- a/src/Control/Path/LOSnSMC/Task.cpp +++ b/src/Control/Path/LOSnSMC/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/Path/PurePursuit/Task.cpp b/src/Control/Path/PurePursuit/Task.cpp index bc164a766b..3286ad6191 100644 --- a/src/Control/Path/PurePursuit/Task.cpp +++ b/src/Control/Path/PurePursuit/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -68,6 +68,13 @@ namespace Control enableControlLoops(IMC::CL_YAW); } + void + onPathDeactivation(void) + { + // Deactivate heading controller. + disableControlLoops(IMC::CL_YAW); + } + void step(const IMC::EstimatedState& state, const TrackingState& ts) { diff --git a/src/Control/Path/VectorField/Task.cpp b/src/Control/Path/VectorField/Task.cpp index 7a359f99a8..4a37b16bd4 100644 --- a/src/Control/Path/VectorField/Task.cpp +++ b/src/Control/Path/VectorField/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/ROV/Depth/Task.cpp b/src/Control/ROV/Depth/Task.cpp index f8986dd3d4..910f6b6e48 100644 --- a/src/Control/ROV/Depth/Task.cpp +++ b/src/Control/ROV/Depth/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/ROV/HorizontalPlane/Task.cpp b/src/Control/ROV/HorizontalPlane/Task.cpp index 4f8d3f21fe..2f892189e3 100644 --- a/src/Control/ROV/HorizontalPlane/Task.cpp +++ b/src/Control/ROV/HorizontalPlane/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/ROV/RemoteOperation/DistanceTracking.hpp b/src/Control/ROV/RemoteOperation/DistanceTracking.hpp index 3c2ef61ce1..21d57bb585 100644 --- a/src/Control/ROV/RemoteOperation/DistanceTracking.hpp +++ b/src/Control/ROV/RemoteOperation/DistanceTracking.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/ROV/RemoteOperation/Task.cpp b/src/Control/ROV/RemoteOperation/Task.cpp index 5a1c659a0b..d04af2778d 100644 --- a/src/Control/ROV/RemoteOperation/Task.cpp +++ b/src/Control/ROV/RemoteOperation/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/UAV/Ardupilot/Task.cmake b/src/Control/UAV/Ardupilot/Task.cmake index e69de29bb2..556db360b0 100644 --- a/src/Control/UAV/Ardupilot/Task.cmake +++ b/src/Control/UAV/Ardupilot/Task.cmake @@ -0,0 +1,25 @@ +macro(task_files_hook) + set(MAVLINK_CFLAGS "") + + check_cxx_compiler_flag(-Wno-address-of-packed-member _has_wnoaddress_of_packed_member) + if(_has_wnoaddress_of_packed_member) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-address-of-packed-member") + endif() + + check_cxx_compiler_flag(-Wno-ignored-qualifiers _has_wnoignored_qualifiers) + if(_has_wnoignored_qualifiers) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-ignored-qualifiers") + endif() + + check_cxx_compiler_flag(-Wno-array-bounds _has_wnoarray_bounds) + if(_has_wnoarray_bounds) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-array-bounds") + endif() + + check_cxx_compiler_flag(-Wno-stringop-overread _has_wnostringop_overread) + if(_has_wnostringop_overread) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-stringop-overread") + endif() + + set(cxx_flags "${cxx_flags} ${MAVLINK_CFLAGS}") +endmacro(task_files_hook) diff --git a/src/Control/UAV/Ardupilot/Task.cpp b/src/Control/UAV/Ardupilot/Task.cpp index 0dcaa998c4..50bc25e2b6 100644 --- a/src/Control/UAV/Ardupilot/Task.cpp +++ b/src/Control/UAV/Ardupilot/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,6 +28,7 @@ // Author: Eduardo Marques * // Author: Ricardo Martins * // Author: Joao Fortuna * +// Author: Maria Costa * //*************************************************************************** // ISO C++ 98 headers. @@ -136,7 +137,7 @@ namespace Control //! Has Power Module bool pwrm; //! WP seconds before reach - int secs; + float secs; //! WP Copter: Minimum wp switch radius float cp_wp_radius; //! RC setup @@ -150,10 +151,14 @@ namespace Control std::string form_fl_ent; //! Convert MSL to WGS84 height bool convert_msl; + //! Default pitch angle for automatic takeoff + float takeoff_pitch; //! Enter loiter mode when in idle bool loiter_idle; //! Dispatch ExternalNavData rather than EstimatedState bool use_external_nav; + //! Temperature of ESC failure (degrees) + float esc_temp; }; struct Task: public DUNE::Tasks::Task @@ -201,6 +206,8 @@ namespace Control bool m_reboot; //! Flag indicating MSL-WGS84 offset has already been calculated. bool m_offset_st; + //! WGS84 height on ground + float m_href; //! External control bool m_external; //! Current waypoint @@ -232,6 +239,8 @@ namespace Control std::queue m_mission_items; //! Desired gimbal angles float m_gb_pan, m_gb_tilt, m_gb_retract; + //! Flag to signal if a land maneuver occured + bool m_land; Task(const std::string& name, Tasks::Context& ctx): Tasks::Task(name, ctx), @@ -243,6 +252,7 @@ namespace Control m_hae_offset(0.0), m_reboot(true), m_offset_st(false), + m_href(0), m_external(true), m_current_wp(0), m_critical(false), @@ -260,7 +270,8 @@ namespace Control m_dspeed(20), m_vehicle_type(VEHICLE_UNKNOWN), m_service(false), - m_last_wp(0) + m_last_wp(0), + m_land(false) { param("Communications Timeout", m_args.comm_timeout) .minimumValue("1") @@ -284,7 +295,7 @@ namespace Control .description("Address for connection to Ardupilot"); param("IPv4 - Address", m_args.ip) - .defaultValue("") + .defaultValue("0.0.0.0") .description("Address for neptus connection to Ardupilot"); param("Telemetry Rate", m_args.trate) @@ -298,7 +309,7 @@ namespace Control .description("Altitude to be used if desired Z has no units"); param("Default loiter radius", m_args.lradius) - .defaultValue("-150.0") + .defaultValue("-100.0") .units(Units::Meter) .description("Loiter radius used in LoiterHere (idle)"); @@ -401,6 +412,10 @@ namespace Control .defaultValue("false") .description("Convert altitude extracted from the Ardupilot to WGS84 height"); + param("Takeoff Pitch", m_args.takeoff_pitch) + .defaultValue("13") + .description("Default pitch angle for automatic takeoff, in degrees."); + param("Loiter in Idle", m_args.loiter_idle) .defaultValue("true") .description("Loiter when in idle."); @@ -409,6 +424,10 @@ namespace Control .defaultValue("false") .description("Dispatch ExternalNavData instead of EstimatedState"); + param("Temperature of ESC failure (degrees)", m_args.esc_temp) + .defaultValue("70.0") + .description("Temperature of ESC failure (degrees)."); + // Setup packet handlers // IMPORTANT: set up function to handle each type of MAVLINK packet here m_mlh[MAVLINK_MSG_ID_ATTITUDE] = &Task::handleAttitudePacket; @@ -419,7 +438,7 @@ namespace Control m_mlh[MAVLINK_MSG_ID_WIND] = &Task::handleWindPacket; m_mlh[MAVLINK_MSG_ID_COMMAND_ACK] = &Task::handleCmdAckPacket; m_mlh[MAVLINK_MSG_ID_MISSION_ACK] = &Task::handleMissionAckPacket; - m_mlh[MAVLINK_MSG_ID_MISSION_CURRENT] = &Task::handleMissionCurrentPacket; + //m_mlh[MAVLINK_MSG_ID_MISSION_CURRENT] = &Task::handleMissionCurrentPacket; m_mlh[MAVLINK_MSG_ID_STATUSTEXT] = &Task::handleStatusTextPacket; m_mlh[MAVLINK_MSG_ID_HEARTBEAT] = &Task::handleHeartbeatPacket; m_mlh[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT] = &Task::handleNavControllerPacket; @@ -427,7 +446,7 @@ namespace Control m_mlh[MAVLINK_MSG_ID_SYS_STATUS] = &Task::handleSystemStatusPacket; m_mlh[MAVLINK_MSG_ID_VFR_HUD] = &Task::handleHUDPacket; m_mlh[MAVLINK_MSG_ID_SYSTEM_TIME] = &Task::handleSystemTimePacket; - m_mlh[MAVLINK_MSG_ID_MISSION_REQUEST] = &Task::handleMissionRequestPacket; + //m_mlh[MAVLINK_MSG_ID_MISSION_REQUEST] = &Task::handleMissionRequestPacket; m_mlh[MAVLINK_MSG_ID_RAW_IMU] = &Task::handleImuRaw; // Setup processing of IMC messages @@ -444,6 +463,8 @@ namespace Control bind(this); bind(this); bind(this); + bind(this); + bind(this); //! Misc. initialization m_last_pkt_time = 0; //! time of last packet from Ardupilot @@ -489,6 +510,12 @@ namespace Control m_TCP_sock->setNoDelay(true); setupRate(m_args.trate); inf(DTR("Ardupilot interface initialized")); + + // Clear previous mission on autopilot + mavlink_msg_mission_clear_all_pack(255, 0, &m_msg, m_sysid, 0); + uint16_t n = mavlink_msg_to_send_buffer(m_buf, &m_msg); + sendData(m_buf, n); + debug("Cleared mission in ardupilot."); } catch (...) { @@ -626,10 +653,7 @@ namespace Control } if (!(m_args.ardu_tracker) && (cloops->mask & IMC::CL_ROLL)) - { - onUpdateParameters(); activateFBW(); - } } else { @@ -774,14 +798,14 @@ namespace Control { // Copters must first be set to guided as of AC 3.2 uint8_t buf[512]; - mavlink_message_t* msg = new mavlink_message_t; + mavlink_message_t msg; - mavlink_msg_set_mode_pack(255, 0, msg, + mavlink_msg_set_mode_pack(255, 0, &msg, m_sysid, 1, CP_MODE_GUIDED); - uint16_t n = mavlink_msg_to_send_buffer(buf, msg); + uint16_t n = mavlink_msg_to_send_buffer(buf, &msg); sendData(buf, n); debug("Guided MODE on ardupilot is set"); } @@ -901,50 +925,29 @@ namespace Control return; } - //! In Auto mode but still in ground, performing takeoff first + //! In Auto mode but still in ground - warns operator to add takeoff to the plan. if (m_ground) { - - inf(DTR("ArduPilot in Auto mode but still in ground, performing takeoff first.")); - if (m_vehicle_type == VEHICLE_COPTER) - { - takeoff_copter(path); - } - else { - takeoff_plane(path); - } + war(DTR("ArduPilot in Auto mode, but still in ground! Add a takeoff waypoint to the plan.")); return; } uint8_t buf[512]; mavlink_message_t msg; + uint16_t n; - if(m_vehicle_type == VEHICLE_COPTER) + if (!((m_mode == CP_MODE_GUIDED) || (m_mode == PL_MODE_GUIDED))) { // Copters must first be set to guided as of AC 3.2 - // Disabled, as this is not - - mavlink_msg_set_mode_pack(255, 0, &msg, - m_sysid, - 1, - CP_MODE_GUIDED); //! DUNE mode on arducopter is 12 - - uint16_t n = mavlink_msg_to_send_buffer(buf, &msg); - sendData(buf, n); - debug("Guided MODE on ardupilot is set"); - } - - if(m_vehicle_type == VEHICLE_FIXEDWING) - { // Planes must first be set to guided as of AP 3.3.0 + uint8_t mode = (m_vehicle_type == VEHICLE_COPTER) ? (uint8_t)CP_MODE_GUIDED : (uint8_t)PL_MODE_GUIDED; mavlink_msg_set_mode_pack(255, 0, &msg, m_sysid, 1, - PL_MODE_GUIDED); - - uint16_t n = mavlink_msg_to_send_buffer(buf, &msg); + mode); + n = mavlink_msg_to_send_buffer(buf, &msg); sendData(buf, n); - debug("Guided MODE on ardupilot is set"); + debug("Guided MODE on ardupilot is set."); } //! Setting airspeed parameter @@ -966,7 +969,7 @@ namespace Control (int)(path->speed * 100), //! Parameter value MAV_PARAM_TYPE_INT16); //! Parameter type } - int n = mavlink_msg_to_send_buffer(buf, &msg); + n = mavlink_msg_to_send_buffer(buf, &msg); sendData(buf, n); //! Setting loiter radius parameter @@ -987,7 +990,6 @@ namespace Control float alt = (path->end_z_units & IMC::Z_NONE) ? m_args.alt : (float)path->end_z; //! Destination - if (m_vehicle_type == VEHICLE_COPTER) { mavlink_msg_mission_item_pack(255, 0, &msg, @@ -1053,148 +1055,133 @@ namespace Control } void - takeoff_copter(const IMC::DesiredPath* dpath) + consume(const IMC::Takeoff* tkoff) { - /* As of AC 3.1, we can now send takeoff as a guided command. */ - // We need to be in guided for this to work. - - // Altitude in WGS84 - float alt = (dpath->end_z_units & IMC::Z_NONE) ? m_args.alt : (float) dpath->end_z; - - // Convert altitude to geoid height (MSL). - sendCommandPacket(MAV_CMD_NAV_TAKEOFF, 0, 0, 0, 0, 0, 0, alt - m_hae_offset); + IMC::DesiredPath path; - m_pcs.start_lat = m_lat; - m_pcs.start_lon = m_lon; - m_pcs.start_z = getHeight(); - m_pcs.start_z_units = IMC::Z_HEIGHT; + path.start_lat = m_lat; + path.start_lon = m_lon; + path.start_z = getHeight(); + path.start_z_units = IMC::Z_HEIGHT; - m_pcs.end_lat = dpath->end_lat; - m_pcs.end_lon = dpath->end_lon; + path.end_lat = tkoff->lat; + path.end_lon = tkoff->lon; + path.end_z = tkoff->z; + path.end_z_units = tkoff->z_units; - m_pcs.end_z = alt; - m_pcs.end_z_units = IMC::Z_HEIGHT; - m_pcs.flags = PathControlState::FL_3DTRACK | PathControlState::FL_CCLOCKW; - m_pcs.flags &= dpath->flags; - m_pcs.lradius = dpath->lradius; - m_pcs.path_ref = dpath->path_ref; + // Trigger automatic takeoff + (m_vehicle_type == VEHICLE_COPTER) ? autoTakeoff(&path, 0) : autoTakeoff(&path, tkoff->takeoff_pitch); + } - dispatch(m_pcs); + void + consume(const IMC::Land* land) + { + if(!(m_dpath.flags & IMC::DesiredPath::FL_LAND)) + { + debug("\n\r Land consume: doesn't have order to issue command yet!"); + return; + } - debug("Takeoff command sent to Ardupilot"); + // Trigger automatic landing + autoLand(land); } void - takeoff_plane(const IMC::DesiredPath* dpath) + autoTakeoff(const IMC::DesiredPath* dpath, float pitch) { - uint8_t buf[512]; - int seq = 1; - + // Local variables + uint8_t buf[512], mode; + uint16_t n; mavlink_message_t msg; - mavlink_msg_param_set_pack(255, 0, &msg, - m_sysid, //! target_system System ID - 0, //! target_component Component ID - "WP_LOITER_RAD", //! Parameter name - dpath->flags & DesiredPath::FL_CCLOCKW ? (-1 * dpath->lradius) : (dpath->lradius), //! Parameter value - MAV_PARAM_TYPE_INT16); //! Parameter type - - uint16_t n = mavlink_msg_to_send_buffer(buf, &msg); - sendData(buf, n); - - mavlink_msg_param_set_pack(255, 0, &msg, - m_sysid, //! target_system System ID - 0, //! target_component Component ID - "TRIM_ARSPD_CM", //! Parameter name - (int)(dpath->speed * 100), //! Parameter value - MAV_PARAM_TYPE_INT16); //! Parameter type - + // Clear previous mission on autopilot + mavlink_msg_mission_clear_all_pack(255, 0, &msg, m_sysid, 0); n = mavlink_msg_to_send_buffer(buf, &msg); sendData(buf, n); + debug("Cleared mission in ardupilot."); - mavlink_msg_mission_count_pack(255, 0, &msg, - m_sysid, //! target_system System ID - 0, //! target_component Component ID - 4); //! size of Mission + // Check if in manual mode + if (m_external) + { + m_dpath = *dpath; + inf(DTR("ArduPilot is in Manual mode, saving desired path.")); + return; + } + // Set mode GUIDED. + mode = (m_vehicle_type == VEHICLE_COPTER) ? (uint8_t)CP_MODE_GUIDED : (uint8_t)PL_MODE_GUIDED; + mavlink_msg_set_mode_pack(255, 0, &msg, + m_sysid, + 1, + mode); n = mavlink_msg_to_send_buffer(buf, &msg); sendData(buf, n); + debug("Guided MODE on ardupilot is set."); - mavlink_msg_mission_write_partial_list_pack(255, 0, &msg, - m_sysid, //! target_system System ID - 0, //! target_component Component ID - seq, //! start_index Start index, 0 by default and smaller / equal to the largest index of the current onboard list - seq+2); //! end_index End index, equal or greater than start index - - m_mission_items.push(msg); - - sendMissionItem(false); - - //! Current position - mavlink_msg_mission_item_pack(255, 0, &msg, - m_sysid, //! target_system System ID - 0, //! target_component Component ID - seq++, //! seq Sequence - MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h - MAV_CMD_NAV_TAKEOFF, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h - 1, //! current false:0, true:1 - 1, //! autocontinue autocontinue to next wp - 5, //! Pitch - 0, //! Altitude - 0, //! Not used - 0, //! Not used - 0, //! x PARAM5 / local: x position, global: latitude - 0, //! y PARAM6 / y position: global: longitude - m_hae_msl + 10);//! z PARAM7 / z position: global: altitude - - m_mission_items.push(msg); - -// //! Desired speed -// mavlink_msg_mission_item_pack(255, 0, &msg, -// m_sysid, //! target_system System ID -// 0, //! target_component Component ID -// seq++, //! seq Sequence -// MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h -// MAV_CMD_DO_CHANGE_SPEED, //! command The scheduled action for the MISSION. see MAV_CMD in common.xml MAVLink specs -// 0, //! current false:0, true:1 -// 1, //! autocontinue autocontinue to next wp -// 0, //! Speed type (0=Airspeed, 1=Ground Speed) -// (float)(dpath->speed_units == IMC::SUNITS_METERS_PS ? dpath->speed : -1), //! Speed (m/s, -1 indicates no change) -// (float)(dpath->speed_units == IMC::SUNITS_PERCENTAGE ? dpath->speed : -1), //! Throttle ( Percent, -1 indicates no change) -// 0, //! Not used -// 0, //! Not used -// 0, //! Not used -// 0);//! Not used -// -// m_mission_items.push(msg); + // Send takeoff command to ardupilot + if (m_vehicle_type == VEHICLE_COPTER) + sendCommandPacket(MAV_CMD_NAV_TAKEOFF, (float)Angles::degrees(pitch), 0, 0, 0, 0, 0, dpath->end_z - m_href); + else + { + // Send Mission Count + mavlink_msg_mission_count_pack(255, 0, &msg, m_sysid, 0, 2); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); - //! Destination - mavlink_msg_mission_item_pack(255, 0, &msg, - m_sysid, //! target_system System ID - 0, //! target_component Component ID - seq++, //! seq Sequence - MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h - (dpath->lradius ? MAV_CMD_NAV_LOITER_UNLIM : MAV_CMD_NAV_WAYPOINT), //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h - 0, //! current false:0, true:1 - 0, //! autocontinue autocontinue to next wp - 0, //! Not used - 0, //! Not used - 0, //! Not used - 0, //! Not used - (float)Angles::degrees(dpath->end_lat), //! x PARAM5 / local: x position, global: latitude - (float)Angles::degrees(dpath->end_lon), //! y PARAM6 / y position: global: longitude - (float)(dpath->end_z) - m_hae_offset);//! z PARAM7 / z position: global: altitude + // Send Write Partial List + mavlink_msg_mission_write_partial_list_pack(255, 0, &msg, m_sysid, 0, 1, 1); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); - m_mission_items.push(msg); + // Set Home as current position + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + 0, //! seq Sequence + MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + MAV_CMD_DO_SET_HOME, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 0, //! current false:0, true:1, guided mode:2 + 0, //! autocontinue to next wp + 1, //! Location: current=1, specificed=0 + 0, //! Not used + 0, //! Not used + 0, //! Not used + 0, //! Latitude + 0, //! Longitude + 0);//! z PARAM7 / z position: global: altitude + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); - mavlink_msg_mission_set_current_pack(255, 0, &msg, - m_sysid, - 0, - 1); + // Send Mission Item + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + 1, //! seq Sequence + MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + MAV_CMD_NAV_TAKEOFF, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 0, //! current false:0, true:1, guided mode:2 + 1, //! autocontinue to next wp + (float)Angles::degrees(pitch), //! Pitch Angle (not used for COPTER) + 0, //! Not used + 0, //! Not used + 0, //! Not used + (float)Angles::degrees(dpath->end_lat), //! Latitude + (float)Angles::degrees(dpath->end_lon), //! Longitude + dpath->end_z - m_hae_offset);//! z PARAM7 / z position: global: altitude + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); - n = mavlink_msg_to_send_buffer(buf, &msg); - sendData(buf, n); + // Set AUTO mode + mavlink_msg_set_mode_pack(255, 0, &msg, + m_sysid, + 1, + PL_MODE_AUTO); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + debug("Auto MODE on ardupilot is set"); + } + // Update PathControlState m_pcs.start_lat = m_lat; m_pcs.start_lon = m_lon; m_pcs.start_z = getHeight(); @@ -1202,11 +1189,9 @@ namespace Control m_pcs.end_lat = dpath->end_lat; m_pcs.end_lon = dpath->end_lon; + m_pcs.end_z = dpath->end_z; + m_pcs.end_z_units = dpath->end_z_units; - float alt = (dpath->end_z_units & IMC::Z_NONE) ? m_args.alt : (float)dpath->end_z; - - m_pcs.end_z = alt; - m_pcs.end_z_units = IMC::Z_HEIGHT; m_pcs.flags = PathControlState::FL_3DTRACK | PathControlState::FL_CCLOCKW; m_pcs.flags &= dpath->flags; m_pcs.lradius = dpath->lradius; @@ -1214,7 +1199,87 @@ namespace Control dispatch(m_pcs); - debug("Waypoint packet sent to Ardupilot"); + // Debug output message + debug("Takeoff command sent to Ardupilot."); + } + + void + autoLand(const IMC::Land* land) + { + // Local variables + uint8_t buf[512], mode; + uint16_t n; + mavlink_message_t msg; + + // Check if in manual mode + if (m_external) + { + inf(DTR("ArduPilot is in Manual mode, unable to perform automatic landing.")); + return; + } + + // Send land command to ardupilot + if (m_vehicle_type == VEHICLE_COPTER) + { + // Set LAND mode. + mode = (uint8_t)CP_MODE_LAND; + mavlink_msg_set_mode_pack(255, 0, &msg, + m_sysid, + 1, + mode); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + debug("Land MODE on ardupilot is set."); + + // Send LAND command. + sendCommandPacket(MAV_CMD_NAV_LAND, land->abort_z - m_href, 0, 0, 0, (float)Angles::degrees(land->lat), (float)Angles::degrees(land->lon), 0); + } + else + { + // Send Mission Count + mavlink_msg_mission_count_pack(255, 0, &msg, m_sysid, 0, 2); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Send Write Partial List + mavlink_msg_mission_write_partial_list_pack(255, 0, &msg, m_sysid, 0, 1, 1); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Send Mission Item + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + 1, //! seq Sequence + MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + MAV_CMD_NAV_LAND, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 0, //! current false:0, true:1, guided mode:2 + 0, //! autocontinue to next wp + land->abort_z - m_hae_offset, //! Abort Altitude + 0, //! Not used + 0, //! Not used + 0, //! Not used + (float)Angles::degrees(land->lat), //! Touchdown Latitude + (float)Angles::degrees(land->lon), //! Touchdown Longitude + land->z - m_hae_offset); //! z PARAM7 / z position: global: altitude + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Set AUTO mode. + mode = (uint8_t)PL_MODE_AUTO; + mavlink_msg_set_mode_pack(255, 0, &msg, + m_sysid, + 1, + mode); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + debug("Auto MODE on ardupilot is set."); + } + + m_land = true; + + // Debug output message + debug("Land command sent to Ardupilot."); } void @@ -1282,6 +1347,17 @@ namespace Control if (!m_ground) m_offset_st = false; + + if (m_ground && m_land && m_external) + { + // Clear previous mission on autopilot + mavlink_msg_mission_clear_all_pack(255, 0, &m_msg, m_sysid, 0); + uint16_t n = mavlink_msg_to_send_buffer(m_buf, &m_msg); + sendData(m_buf, n); + debug("Cleared mission in ardupilot."); + + m_land = false; + } } void @@ -1539,7 +1615,7 @@ namespace Control switch ((int)m_msg.msgid) { default: - debug("UNDEF: %u", m_msg.msgid); + trace("UNDEF: %u", m_msg.msgid); break; case MAVLINK_MSG_ID_HEARTBEAT: trace("HEARTBEAT"); @@ -1695,25 +1771,30 @@ namespace Control double tstamp = Clock::getSinceEpoch(); IMC::Acceleration acce; - acce.x = raw.xacc; - acce.y = raw.yacc; - acce.z = raw.zacc; + // raw_imu acc unit is in milli gs + // g used in AP is 9.80665 (see libraries/AP_Math/definitions.h) + acce.x = raw.xacc*0.001*9.80665; + acce.y = raw.yacc*0.001*9.80665; + acce.z = raw.zacc*0.001*9.80665; acce.setTimeStamp(tstamp); - dispatch(acce); + dispatch(acce, DF_KEEP_TIME); + // raw_imu ars unit is milli rad/s IMC::AngularVelocity avel; - avel.x = raw.xgyro; - avel.y = raw.ygyro; - avel.z = raw.zgyro; + avel.x = raw.xgyro*0.001; + avel.y = raw.ygyro*0.001; + avel.z = raw.zgyro*0.001; avel.setTimeStamp(tstamp); - dispatch(avel); + dispatch(avel, DF_KEEP_TIME); + // raw_imu mag unit is milli Tesla + // IMC mag unit is Gauss = 10^-4 Tesla IMC::MagneticField magn; - magn.x = raw.xmag; - magn.y = raw.ymag; - magn.z = raw.zmag; + magn.x = raw.xmag*0.1; + magn.y = raw.ymag*0.1; + magn.z = raw.zmag*0.1; magn.setTimeStamp(tstamp); - dispatch(magn); + dispatch(magn, DF_KEEP_TIME); } void @@ -1738,12 +1819,16 @@ namespace Control m_hae_offset = wmm.height(m_lat, m_lon); m_reboot = false; m_offset_st = true; + debug("Height offset at %3.10f/%3.10f is %f", Angles::degrees(m_lat), Angles::degrees(m_lon), m_hae_offset); } } - else + else if (m_args.convert_msl == false) { m_hae_offset = 0; + m_offset_st = false; + debug("Height offset set to zero (convert?%d, gpstype: %d)",m_args.convert_msl, m_fix.type); } + //else: m_args.convert_msl is true, but we do not have/have lost GPS: leave m_hae_offset as is m_estate.lat = m_lat; m_estate.lon = m_lon; @@ -1755,7 +1840,7 @@ namespace Control m_estate.vx = 1e-02 * gp.vx; m_estate.vy = 1e-02 * gp.vy; - m_estate.vz = -1e-02 * gp.vz; + m_estate.vz = 1e-02 * gp.vz; // Note: the following will yield body-fixed *ground* velocity // Maybe this can be fixed w/IAS readings (anyway not too important) @@ -1765,6 +1850,10 @@ namespace Control m_estate.alt = (double) gp.relative_alt * 1e-3; //AGL (relative to home altitude) m_estate.depth = -1; + + // Save WGS84 height on the ground + if(m_ground) + m_href = m_estate.height; } float @@ -1822,6 +1911,14 @@ namespace Control m_pressure.value = sc_press.press_abs; m_temp.value = 0.01 * sc_press.temperature; + if(m_temp.value >= (m_args.esc_temp - 5)) + { + if(m_temp.value >= m_args.esc_temp) + err("Autopilot temperature reached %fºC! ESC will shutdown!!!", m_temp.value); + else + war("Autopilot temperature at %fºC! ESC shuts down around %fºC.", m_temp.value, m_args.esc_temp); + } + dispatch(m_pressure); dispatch(m_temp); } @@ -1896,28 +1993,6 @@ namespace Control m_last_wp = 0; } - void - handleMissionCurrentPacket(const mavlink_message_t* msg) - { - mavlink_mission_current_t miss_curr; - - mavlink_msg_mission_current_decode(msg, &miss_curr); - m_current_wp = miss_curr.seq; - trace("Current mission item: %d", miss_curr.seq); - - uint8_t buf[512]; - - mavlink_message_t msg_out; - - mavlink_msg_mission_request_pack(255, 0, &msg_out, - m_sysid, //! target_system System ID - 0, //! target_component Component ID - m_current_wp); //! Mission item to request - - uint16_t n = mavlink_msg_to_send_buffer(buf, &msg_out); - sendData(buf, n); - } - void handleStatusTextPacket(const mavlink_message_t* msg) { @@ -2007,12 +2082,6 @@ namespace Control trace("LOITER"); m_external = false; break; - case CP_MODE_LAND: - mode.autonomy = IMC::AutopilotMode::AL_MANUAL; - mode.mode = "LAND"; - trace("LAND"); - m_external = true; - break; case CP_MODE_DUNE: mode.autonomy = IMC::AutopilotMode::AL_AUTO; mode.mode = "DUNE"; @@ -2025,6 +2094,12 @@ namespace Control trace("GUIDED"); m_external = false; break; + case CP_MODE_LAND: + mode.autonomy = IMC::AutopilotMode::AL_AUTO; + mode.mode = "LAND"; + trace("LAND"); + m_external = false; + break; } } else @@ -2042,8 +2117,6 @@ namespace Control if (m_mode == PL_MODE_STABILIZE) mode.mode = "STABILIZE"; - if (m_mode == PL_MODE_RTL) - mode.mode = "RTL"; if (m_mode == PL_MODE_CIRCLE) mode.mode = "CIRCLE"; if (m_mode == PL_MODE_AUTOTUNE) @@ -2093,6 +2166,11 @@ namespace Control m_external = false; m_critical = false; break; + case PL_MODE_RTL: + mode.autonomy = IMC::AutopilotMode::AL_AUTO; + mode.mode = "RTL"; + trace("RTL"); + m_external = false; } } @@ -2110,8 +2188,10 @@ namespace Control IMC::DesiredHeading d_head; IMC::DesiredZ d_z; - // As wp_dist is an integer, we calculate distance manually. - float copter_distance = 0; + // As wp_dist is an integer, and to avoid timing problems with the wp_dist + // not being updated directly after a WP is accepted (sometimes causing two WPs + // to be accepted at the "same" time), we calculate distance manually. + float wp_distance = 0; if (m_vehicle_type == VEHICLE_COPTER) { @@ -2129,13 +2209,30 @@ namespace Control m_dpath.end_lat, m_dpath.end_lon, alt, &destination(0), &destination(1), &destination(2)); - copter_distance = (destination - current_pos).norm_2(); + wp_distance = (destination - current_pos).norm_2(); + } + else + { + //Fixed-wing: do not care about height + // Calc distance between desired location and current location + Matrix destination = Matrix(2, 1, 0.0); + Matrix current_pos = Matrix(2, 1, 0.0); + current_pos(0) = m_estate.x; + current_pos(1) = m_estate.y; + + float alt = (m_dpath.end_z_units & IMC::Z_NONE) ? m_args.alt : (float)m_dpath.end_z; + + WGS84::displacement(m_estate.lat, m_estate.lon, m_estate.height, + m_dpath.end_lat, m_dpath.end_lon, alt, + &destination(0), &destination(1)); - // Store mavlink distance. - nav_out.wp_dist = (uint16_t) copter_distance; - trace("Copter waypoint dist now: %0.2f", copter_distance); + wp_distance = (destination - current_pos).norm_2(); } + // Store mavlink distance. + if(!m_service) + nav_out.wp_dist = (uint16_t) wp_distance; + d_roll.value = Angles::radians(nav_out.nav_roll); d_pitch.value = Angles::radians(nav_out.nav_pitch); d_head.value = Angles::radians(nav_out.nav_bearing); @@ -2160,12 +2257,12 @@ namespace Control if (m_vehicle_type == VEHICLE_COPTER) is_valid_mode = (m_mode == CP_MODE_GUIDED || (m_mode == CP_MODE_AUTO )) ? true : false; else - is_valid_mode = (m_mode == 15 || (m_mode == 10 && m_current_wp == 3)) ? true : false; + is_valid_mode = (m_mode == PL_MODE_GUIDED || (m_mode == PL_MODE_AUTO && m_current_wp == 3)) ? true : false; // Check Loiter tolerance if (m_vehicle_type == VEHICLE_COPTER) { - if ((copter_distance <= m_args.ltolerance) + if ((wp_distance <= m_args.ltolerance) && is_valid_mode) { m_pcs.flags |= PathControlState::FL_LOITERING; @@ -2173,8 +2270,8 @@ namespace Control } else { - if ((nav_out.wp_dist <= m_desired_radius + m_args.ltolerance) - && (nav_out.wp_dist >= m_desired_radius - m_args.ltolerance) + if ((wp_distance <= m_desired_radius + m_args.ltolerance) + && (wp_distance >= m_desired_radius - m_args.ltolerance) && is_valid_mode) { m_pcs.flags |= PathControlState::FL_LOITERING; @@ -2187,30 +2284,37 @@ namespace Control if (m_vehicle_type == VEHICLE_COPTER) { is_near = (!m_changing_wp - && (copter_distance <= m_args.secs * m_gnd_speed - || copter_distance <= m_args.cp_wp_radius) + && (wp_distance <= m_args.secs * m_gnd_speed + || wp_distance <= m_args.cp_wp_radius) && is_valid_mode && since_last_wp > 1.0); } else { + /* TODO: check ground speed? */ is_near = (!m_changing_wp - && (nav_out.wp_dist <= m_desired_radius + m_args.secs * m_gnd_speed) - && (nav_out.wp_dist >= m_desired_radius - m_args.secs * m_gnd_speed) + && (wp_distance <= m_desired_radius + m_args.secs * m_gnd_speed) + && (wp_distance >= m_desired_radius - m_args.secs * m_gnd_speed) && is_valid_mode && since_last_wp > 1.0); } if (is_near) { + spew("Is near! dist: %f, rad: %d, gs: %d",wp_distance, m_desired_radius,m_gnd_speed); m_pcs.flags |= PathControlState::FL_NEAR; } - if (m_last_wp && since_last_wp > 1.5) + // last sent WP took too long. lost? Try again + if (m_changing_wp && since_last_wp > 1.5) + { + war("WP sent to AP not confirmed. Trying to resend"); receive(&m_dpath); + } + m_pcs.y = nav_out.xtrack_error; if (m_gnd_speed) - m_pcs.eta = nav_out.wp_dist / m_gnd_speed; + m_pcs.eta = wp_distance / m_gnd_speed; dispatch(m_pcs); } @@ -2244,13 +2348,16 @@ namespace Control IMC::IndicatedSpeed ias; IMC::TrueSpeed gs; + IMC::Throttle thr; ias.value = (fp64_t)vfr_hud.airspeed; gs.value = (fp64_t)vfr_hud.groundspeed; m_gnd_speed = (int)vfr_hud.groundspeed; + thr.value = (uint16_t)vfr_hud.throttle; dispatch(ias); dispatch(gs); + dispatch(thr); } void @@ -2274,17 +2381,6 @@ namespace Control if (!m_args.hitl) dispatch(m_fix); } - - void - handleMissionRequestPacket(const mavlink_message_t* msg) - { - mavlink_mission_request_t mission_request; - mavlink_msg_mission_request_decode(msg, &mission_request); - - debug("Requesting item #%d", mission_request.seq); - - sendMissionItem(true); - } }; } } diff --git a/src/Control/UAV/LOS/Task.cpp b/src/Control/UAV/LOS/Task.cpp index 555923c339..110efd8ebc 100644 --- a/src/Control/UAV/LOS/Task.cpp +++ b/src/Control/UAV/LOS/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Control/UAV/PX4/Task.cmake b/src/Control/UAV/PX4/Task.cmake new file mode 100644 index 0000000000..556db360b0 --- /dev/null +++ b/src/Control/UAV/PX4/Task.cmake @@ -0,0 +1,25 @@ +macro(task_files_hook) + set(MAVLINK_CFLAGS "") + + check_cxx_compiler_flag(-Wno-address-of-packed-member _has_wnoaddress_of_packed_member) + if(_has_wnoaddress_of_packed_member) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-address-of-packed-member") + endif() + + check_cxx_compiler_flag(-Wno-ignored-qualifiers _has_wnoignored_qualifiers) + if(_has_wnoignored_qualifiers) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-ignored-qualifiers") + endif() + + check_cxx_compiler_flag(-Wno-array-bounds _has_wnoarray_bounds) + if(_has_wnoarray_bounds) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-array-bounds") + endif() + + check_cxx_compiler_flag(-Wno-stringop-overread _has_wnostringop_overread) + if(_has_wnostringop_overread) + set(MAVLINK_CFLAGS "${MAVLINK_CFLAGS} -Wno-stringop-overread") + endif() + + set(cxx_flags "${cxx_flags} ${MAVLINK_CFLAGS}") +endmacro(task_files_hook) diff --git a/src/Control/UAV/PX4/Task.cpp b/src/Control/UAV/PX4/Task.cpp new file mode 100644 index 0000000000..72cc430c26 --- /dev/null +++ b/src/Control/UAV/PX4/Task.cpp @@ -0,0 +1,1561 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Trent Lukaczyk * +// Author: Maria Costa * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include +#include +#include + +// DUNE headers. +#include + +// MAVLink headers. +#include + + +namespace Control +{ + namespace UAV + { + namespace PX4 + { + using DUNE_NAMESPACES; + + //! List of PX4 Modes + //! From px4_custom_mode.h in PX4/Firmware git repository. + enum PX4_Modes + { + PX4_CUSTOM_MAIN_MODE_MANUAL = 1, + PX4_CUSTOM_MAIN_MODE_ALTCTL, + PX4_CUSTOM_MAIN_MODE_POSCTL, + PX4_CUSTOM_MAIN_MODE_AUTO, + PX4_CUSTOM_MAIN_MODE_ACRO, + PX4_CUSTOM_MAIN_MODE_OFFBOARD, + PX4_CUSTOM_MAIN_MODE_STABILIZED, + PX4_CUSTOM_MAIN_MODE_RATTITUDE + }; + + //! List of PX4 Auto Sub-Modes + enum PX4_subModes + { + PX4_CUSTOM_SUB_MODE_AUTO_READY = 1, + PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF, + PX4_CUSTOM_SUB_MODE_AUTO_LOITER, + PX4_CUSTOM_SUB_MODE_AUTO_MISSION, + PX4_CUSTOM_SUB_MODE_AUTO_RTL, + PX4_CUSTOM_SUB_MODE_AUTO_LAND, + PX4_CUSTOM_SUB_MODE_AUTO_RTGS, + PX4_CUSTOM_SUB_MODE_AUTO_FOLLOW_TARGET + }; + + //! VTOL States + enum VTOL_State + { + MAV_VTOL_STATE_UNDEFINED, // MAV is not configured as VTOL + MAV_VTOL_STATE_TRANSITION_TO_FW, // VTOL is in transition from multicopter to fixed-wing + MAV_VTOL_STATE_TRANSITION_TO_MC, // VTOL is in transition from fixed-wing to multicopter + MAV_VTOL_STATE_MC, // VTOL is in multicopter state + MAV_VTOL_STATE_FW // VTOL is in fixed-wing state + }; + + //! %Task arguments. + struct Arguments + { + //! Communications timeout + uint8_t comm_timeout; + //! TCP Port + uint16_t TCP_port; + //! TCP Address + Address TCP_addr; + //! Use UDP Port + uint16_t UDP_listen_port; + //! UDP Port + uint16_t UDP_port; + //! Use TCP or UDP + bool tcp_or_udp; + //! UDP Address + Address UDP_addr; + //! IPv4 Address + Address ip; + //! Transition to FW + bool transition_fw; + //! Transition to MC + bool transition_mc; + //! WP Threshold for FW + float threshold_fw; + //! WP Threshold for MC + float threshold_mc; + //! Mavlink phototrigger + bool mavlink_phototrigger; + //! Debug GCS Heartbeat + bool heartbeat; + //! Moving Home + bool moving_home; + //! Basestation (Moving Home) + std::string basestation; + //! Home Position Update (Moving Home) + uint8_t home_update; + //! Send full plan option + bool full_plan; + }; + + + struct Task: public DUNE::Tasks::Task + { + //! Task arguments. + Arguments m_args; + //! Type definition for PX4 packet handler. + typedef void (Task::* PktHandler)(const mavlink_message_t* msg); + typedef std::map PktHandlerMap; + //! PX4 packet handling + PktHandlerMap m_mlh; + //! Flag of mission mode + bool m_mission; + //! Height offset between MSL and WGS84 + float m_hae_offset; + //! Flag to signal if MSL-WGS84 offset has already been calculated. + bool m_offset; + //! Loiter maneuver duration + int m_duration; + //! Vehicle State is "Maneuver" + bool m_maneuver; + //! Signals if a plan was started + bool m_start; + //! Signals if maneuver is a takeoff or landing + bool m_tkoff_land; + + //! TCP socket + Network::TCPSocket* m_TCP_sock; + //! UDP socket + Network::UDPSocket* m_UDP_sock; + + //! System ID + uint8_t m_sysid; + //! Parser Variables + mavlink_message_t m_msg; + uint8_t m_buf[512]; + //! VTOL State + VTOL_State m_vtol_state; + //! Moving Home timer + Time::Counter m_timer; + + //! Mavlink Timeouts + bool m_error_missing; + double m_last_pkt_time; + double m_last_wp; + + //! GPS Fix message + IMC::GpsFix m_fix; + //! Estimated state message. + IMC::EstimatedState m_estate; + //! DesiredPath message + IMC::DesiredPath m_dpath; + //! PathControlState message + IMC::PathControlState m_pcs; + //! AutopilotMode message + IMC::AutopilotMode m_mode; + //! TrueSpeed message + IMC::TrueSpeed m_groundspeed; + //! ControlLoops message + IMC::ControlLoops m_cloops; + //! PlanSpecification message + IMC::PlanSpecification m_pspec; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_mission(false), + m_hae_offset(0.0), + m_offset(false), + m_duration(0), + m_maneuver(false), + m_start(false), + m_tkoff_land(false), + m_TCP_sock(NULL), + m_UDP_sock(NULL), + m_sysid(1), + m_vtol_state(MAV_VTOL_STATE_UNDEFINED), + m_error_missing(false), + m_last_wp(0) + { + param("Communications Timeout", m_args.comm_timeout) + .minimumValue("1") + .maximumValue("60") + .defaultValue("10") + .units(Units::Second) + .description("Ardupilot communications timeout"); + + param("TCP - Port", m_args.TCP_port) + .defaultValue("5760") + .description("Port for connection to Ardupilot"); + + param("TCP - Address", m_args.TCP_addr) + .defaultValue("127.0.0.1") + .description("Address for connection to Ardupilot"); + + param("UDP - Listen Port", m_args.UDP_listen_port) + .defaultValue("14557") + .description("Port for connection from Ardupilot"); + + param("UDP - Port", m_args.UDP_port) + .defaultValue("14556") + .description("Port for connection to Ardupilot"); + + param("UDP - Address", m_args.UDP_addr) + .defaultValue("127.0.0.1") + .description("Address for connection to Ardupilot"); + + param("Use TCP (or UDP)", m_args.tcp_or_udp) + .defaultValue("true") + .description("Ardupilot communications timeout"); + + param("IPv4 - Address", m_args.ip) + .defaultValue("10.0.20.160") + .description("Address for neptus connection to PX4."); + + param("Transition to FW", m_args.transition_fw) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .scope(Tasks::Parameter::SCOPE_MANEUVER) + .defaultValue("false") + .description("Transition from multi-copter to fixed-wing."); + + param("Transition to MC", m_args.transition_mc) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .scope(Tasks::Parameter::SCOPE_MANEUVER) + .defaultValue("false") + .description("Transition from fixed-wing to multi-copter."); + + param("WP Threshold for FW", m_args.threshold_fw) + .units(Units::Meter) + .defaultValue("100") + .description("Distance (in meters) from the waypoint at which it's considered reached, for fixed-wing mode."); + + param("WP Threshold for MC", m_args.threshold_mc) + .units(Units::Meter) + .defaultValue("10") + .description("Distance (in meters) from the waypoint at which it's considered reached, for multi-copter mode."); + + param("FLIR Duo R", m_args.mavlink_phototrigger) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .scope(Tasks::Parameter::SCOPE_MANEUVER) + .defaultValue("false") + .description("Mavlink phototrigger enable/disbale."); + + param("GCS Heartbeat", m_args.heartbeat) + .defaultValue("true") + .description("Produce GCS heartbeat (for debugging purposes)."); + + param("Moving Home", m_args.moving_home) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("false") + .description("Enable/Disable moving basestation feature."); + + param("Basestation", m_args.basestation) + .defaultValue("manta-3") + .description("System to consider as the basestation for moving home feature."); + + param("Home Position Update", m_args.home_update) + .defaultValue("60") + .description("Period of home position update (if moving home enabled), in seconds"); + + param("Send Full Plan to Autopilot", m_args.full_plan) + .defaultValue("false") + .description("If true the full plan will be sent to the autopilot, instead of only the next waypoint."); + + + // Setup packet handlers + // IMPORTANT: set up function to handle each type of MAVLINK packet here + m_mlh[MAVLINK_MSG_ID_ATTITUDE] = &Task::handleAttitudePacket; + m_mlh[MAVLINK_MSG_ID_GLOBAL_POSITION_INT] = &Task::handlePositionPacket; + m_mlh[MAVLINK_MSG_ID_HWSTATUS] = &Task::handleHWStatusPacket; + m_mlh[MAVLINK_MSG_ID_SCALED_PRESSURE] = &Task::handleScaledPressurePacket; + m_mlh[MAVLINK_MSG_ID_GPS_RAW_INT] = &Task::handleRawGPSPacket; + m_mlh[MAVLINK_MSG_ID_WIND] = &Task::handleWindPacket; + m_mlh[MAVLINK_MSG_ID_STATUSTEXT] = &Task::handleStatusTextPacket; + m_mlh[MAVLINK_MSG_ID_HEARTBEAT] = &Task::handleHeartbeatPacket; + m_mlh[MAVLINK_MSG_ID_SYS_STATUS] = &Task::handleSystemStatusPacket; + m_mlh[MAVLINK_MSG_ID_VFR_HUD] = &Task::handleHUDPacket; + m_mlh[MAVLINK_MSG_ID_SYSTEM_TIME] = &Task::handleSystemTimePacket; + m_mlh[MAVLINK_MSG_ID_RAW_IMU] = &Task::handleImuRaw; + m_mlh[MAVLINK_MSG_ID_EXTENDED_SYS_STATE] = &Task::handleExtendedStatePacket; + m_mlh[MAVLINK_MSG_ID_MISSION_ACK] = &Task::handleMissionAckPacket; + m_mlh[MAVLINK_MSG_ID_MISSION_ITEM_REACHED] = &Task::handleMissionItemReachedPacket; + m_mlh[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT] = &Task::handleNavControllerPacket; + + // Setup processing of IMC messages + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + + //! Misc. initialization + m_last_pkt_time = 0; //! time of last packet from Ardupilot + m_estate.clear(); + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + openConnection(); + + // Announce IPv4 address to allow neptus to load/write PX4 parameters + std::stringstream os; + os << "mavlink+tcp://" << m_args.ip << ":" << m_args.TCP_port << "/"; + + IMC::AnnounceService announce; + announce.service = os.str(); + announce.service_type = IMC::AnnounceService::SRV_TYPE_EXTERNAL; + dispatch(announce); + } + + void + openConnection(void) + { + try + { + if (m_args.tcp_or_udp) + { + m_TCP_sock = new TCPSocket; + m_TCP_sock->connect(m_args.TCP_addr, m_args.TCP_port); + m_TCP_sock->setNoDelay(true); + } + else + { + m_UDP_sock = new UDPSocket; + m_UDP_sock->bind(m_args.UDP_listen_port, Address::Any, false); + } + inf(DTR("PX4 interface initialized")); + + // Clear previous mission on PX4 + clearMission(); + } + catch (...) + { + Memory::clear(m_TCP_sock); + Memory::clear(m_UDP_sock); + war(DTR("Connection failed, retrying...")); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_COM_ERROR); + } + } + + //! Release resources. + void + onResourceRelease(void) + { + Memory::clear(m_TCP_sock); + Memory::clear(m_UDP_sock); + } + + void + onUpdateParameters(void) + { + // Mavlink Phototrigger + if(paramChanged(m_args.mavlink_phototrigger)) + { + if(m_args.mavlink_phototrigger) + { + // Issue command to start phototrigger + mavlink_msg_command_long_pack(m_sysid, 0, &m_msg, m_sysid, MAV_COMP_ID_CAMERA, MAV_CMD_IMAGE_START_CAPTURE, 0, 1, 0, 2, 0, 0, 0, 0); + inf("Sent IMAGE_START_CAPTURE command."); + } + else + { + // Issue command to stop phototrigger + mavlink_msg_command_long_pack(m_sysid, 0, &m_msg, m_sysid, MAV_COMP_ID_CAMERA, MAV_CMD_IMAGE_STOP_CAPTURE, 0, 0, 0, 0, 0, 0, 0, 0); + inf("Sent IMAGE_STOP_CAPTURE command."); + } + + uint16_t n = mavlink_msg_to_send_buffer(m_buf, &m_msg); + sendData(m_buf, n); + } + + // Moving Home + if(paramChanged(m_args.moving_home) && m_args.moving_home) + m_timer.setTop(m_args.home_update); + } + + void + consume(const IMC::AutopilotMode* msg) + { + // Arm/Disarm + if (msg->mode.compare("ARM") == 0) + sendCommandPacket(MAV_CMD_COMPONENT_ARM_DISARM, 1); + + if (msg->mode.compare("DISARM") == 0) + sendCommandPacket(MAV_CMD_COMPONENT_ARM_DISARM, 0); + + (void)msg; + } + + void + clearMission(void) + { + // Clear previous mission on PX4 + mavlink_msg_mission_clear_all_pack(255, 0, &m_msg, m_sysid, 0); + uint16_t n = mavlink_msg_to_send_buffer(m_buf, &m_msg); + sendData(m_buf, n); + } + + void + sendCommandPacket(uint16_t cmd, float arg1=0, float arg2=0, float arg3=0, float arg4=0, float arg5=0, float arg6=0, float arg7=0) + { + uint8_t buf[512]; + + mavlink_message_t msg; + + trace("%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f %0.2f", arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + mavlink_msg_command_long_pack(255, 0, &msg, m_sysid, 0, cmd, 0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + uint16_t n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + } + + void + consume(const IMC::DevCalibrationControl* msg) + { + // Set ground pressure (used for Planes) + if (msg->op == IMC::DevCalibrationControl::DCAL_START) + sendCommandPacket(MAV_CMD_PREFLIGHT_CALIBRATION, 0, 0, 0, 0, 0, 2, 0); + + (void)msg; + } + + void + consume(const IMC::ControlLoops* cloops) + { + m_cloops = *cloops; + + // Set LOITER mode if in AUTO and no plan. + if(!cloops->enable && m_mode.autonomy == IMC::AutopilotMode::AL_AUTO && !m_mission + && !m_maneuver && std::strcmp(m_mode.mode.c_str(), "LAND")) + { + if(std::strcmp(m_mode.mode.c_str(), "LOITER")) + { + inf("Setting LOITER mode."); + clearMission(); + m_pcs.clear(); + dispatch(m_pcs); + sendCommandPacket(MAV_CMD_DO_SET_MODE, MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, PX4_CUSTOM_MAIN_MODE_AUTO,PX4_CUSTOM_SUB_MODE_AUTO_LOITER); + m_mission = false; + m_start = false; + m_tkoff_land = false; + } + } + } + + void + consume(const IMC::PlanControl* msg) + { + switch (msg->op) + { + case IMC::PlanControl::PC_STOP: + spew("PC_STOP"); + m_mission = false; + m_start = false; + m_tkoff_land = false; + if(std::strcmp(m_mode.mode.c_str(), "LOITER")) + { + clearMission(); + sendCommandPacket(MAV_CMD_DO_SET_MODE, MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, PX4_CUSTOM_MAIN_MODE_AUTO,PX4_CUSTOM_SUB_MODE_AUTO_LOITER); + inf("Setting LOITER mode."); + } + break; + case IMC::PlanControl::PC_START: + spew("PC_START"); + m_mission = false; + m_start = true; + break; + default: + break; + } + } + + void + consume(const IMC::PlanSpecification* msg) + { + m_pspec = *msg; + } + + void + consume(const IMC::Loiter* msg) + { + m_duration = msg->duration; + } + + void + consume(const IMC::VehicleState* msg) + { + m_maneuver = (msg->op_mode == IMC::VehicleState::VS_MANEUVER); + } + + void + consume(const IMC::Announce* msg) + { + if(std::strcmp(m_args.basestation.c_str(), msg->sys_name.c_str())) + return; + + if(m_timer.overflow() && m_args.moving_home) + { + sendCommandPacket(MAV_CMD_DO_SET_HOME, 0, 0, 0, 0, (float)Angles::degrees(msg->lat), (float)Angles::degrees(msg->lon), msg->height); + m_timer.reset(); + inf("Basestation Update: %f, %f, %f", (float)Angles::degrees(msg->lat), (float)Angles::degrees(msg->lon), msg->height); + } + } + + void + consume(const IMC::Takeoff* tkoff) + { + // Local Variables + uint8_t buf[512]; + uint16_t n; + mavlink_message_t msg; + + // Clear previous mission + clearMission(); + + // Check if in AUTO mode + if(m_mode.autonomy != IMC::AutopilotMode::AL_AUTO) + { + inf(DTR("PX4 is in a Manual mode, saving desired path.")); + return; + } + + m_tkoff_land = true; + + // Setting Desired Airspeed + sendCommandPacket(MAV_CMD_DO_CHANGE_SPEED, 0, tkoff->speed, 0, 0, 0, 0, 0); + + // Send Mission Count + mavlink_msg_mission_count_pack(255, 0, &msg, m_sysid, 0, 1); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Send Mission Item + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + 0, //! seq Sequence + MAV_FRAME_GLOBAL_RELATIVE_ALT, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + MAV_CMD_NAV_TAKEOFF, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 1, //! current false:0, true:1, guided mode:2 + 1, //! autocontinue to next wp + 0, //! Used only in MAV_CMD_NAV_LOITER_TIME + 0, //! Not used + 0, //! If <0, then CCW loiter + 0, //! Not used + (float)Angles::degrees(tkoff->lat), //! x PARAM5 / local: x position, global: latitude + (float)Angles::degrees(tkoff->lon), //! y PARAM6 / y position: global: longitude + tkoff->z);//! z PARAM7 / z position: global: altitude + + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Set AUTO mode and TAKEOFF submode + sendCommandPacket(MAV_CMD_DO_SET_MODE, MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, PX4_CUSTOM_MAIN_MODE_AUTO, PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF); + inf("Setting TAKEOFF mode."); + + // Update PathControlState + m_pcs.start_lat = m_estate.lat; + m_pcs.start_lon = m_estate.lon; + m_pcs.start_z = m_estate.alt; + m_pcs.start_z_units = IMC::Z_ALTITUDE; + + m_pcs.end_lat = m_estate.lat; + m_pcs.end_lon = m_estate.lon; + m_pcs.end_z = m_estate.alt; + m_pcs.end_z_units = IMC::Z_ALTITUDE; + + m_pcs.flags = PathControlState::FL_3DTRACK | PathControlState::FL_CCLOCKW; + dispatch(m_pcs); + } + + void + consume(const IMC::Land* land) + { + // Local variables + uint8_t buf[512]; + uint16_t n; + mavlink_message_t msg; + + // Check if in AUTO mode + if(m_mode.autonomy != IMC::AutopilotMode::AL_AUTO) + { + inf(DTR("PX4 is in a Manual mode, saving desired path.")); + return; + } + + // Clear previous mission + clearMission(); + m_tkoff_land = true; + + // Check if it has order to send to PX4 LAND command + if(!(m_dpath.flags & IMC::DesiredPath::FL_LAND)) + { + debug("\n\r Land consume: doesn't have order to issue command yet!"); + return; + } + + // Setting Desired Airspeed + sendCommandPacket(MAV_CMD_DO_CHANGE_SPEED, 0, land->speed, 0, 0, 0, 0, 0); + + // Send Mission Count + mavlink_msg_mission_count_pack(255, 0, &msg, m_sysid, 0, 1); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Send Mission Item + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + 0, //! seq Sequence + MAV_FRAME_GLOBAL_RELATIVE_ALT, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + MAV_CMD_NAV_LAND, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 1, //! current false:0, true:1, guided mode:2 + 1, //! autocontinue to next wp + land->abort_z, //! Used only in MAV_CMD_NAV_LOITER_TIME + 0, //! Not used + 0, //! If <0, then CCW loiter + 0, //! Not used + (float)Angles::degrees(land->lat), //! x PARAM5 / local: x position, global: latitude + (float)Angles::degrees(land->lon), //! y PARAM6 / y position: global: longitude + 0);//! z PARAM7 / z position: global: altitude + + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Set AUTO mode and LAND submode + sendCommandPacket(MAV_CMD_DO_SET_MODE, MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, PX4_CUSTOM_MAIN_MODE_AUTO, PX4_CUSTOM_SUB_MODE_AUTO_LAND); + inf("Setting LAND mode."); + + m_tkoff_land = false; + } + + //! Message for AUTO(MISSION) control (using PX4's controllers) + void + consume(const IMC::DesiredPath* path) + { + // Check if in AUTO mode + if(m_mode.autonomy != IMC::AutopilotMode::AL_AUTO) + { + m_dpath = *path; + inf(DTR("PX4 is in a Manual mode, saving desired path.")); + return; + } + + uint8_t buf[512]; + mavlink_message_t msg; + uint16_t n; + + if(!m_mission) + { + m_mission = true; + + // Check if transition was required + if(m_args.transition_fw && (m_vtol_state == MAV_VTOL_STATE_MC)) + { + // Command transition to plane + sendCommandPacket(MAV_CMD_DO_VTOL_TRANSITION, MAV_VTOL_STATE_FW); + war("Transition to Fixed-Wing."); + } + if(m_args.transition_mc && (m_vtol_state == MAV_VTOL_STATE_FW)) + { + // Command transition to copter + sendCommandPacket(MAV_CMD_DO_VTOL_TRANSITION, MAV_VTOL_STATE_MC); + war("Transition to Multi-Copter."); + } + + // Check if waypoint is a loiter + uint16_t command; float param_radius = 0; bool altitude; + if(!path->lradius){ + command = MAV_CMD_NAV_WAYPOINT; param_radius = 0;} + else + { + if (!m_duration) + command = MAV_CMD_NAV_LOITER_UNLIM; + else + command = MAV_CMD_NAV_LOITER_TIME; + param_radius = path->flags & DesiredPath::FL_CCLOCKW ? (-1 * path->lradius) : (path->lradius); + } + + // Check if plan is in Altitude or Height + altitude = (path->end_z_units == IMC::Z_ALTITUDE) ? true : false; + + // Setting Desired Airspeed + sendCommandPacket(MAV_CMD_DO_CHANGE_SPEED, 0, path->speed, 0, 0, 0, 0, 0); + + if(!m_args.full_plan || m_tkoff_land) + { + // Send Mission Count + mavlink_msg_mission_count_pack(255, 0, &msg, m_sysid, 0, 1); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Send Mission Item + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + 0, //! seq Sequence + altitude ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + command, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 1, //! current false:0, true:1, guided mode:2 + 1, //! autocontinue to next wp + m_duration, //! Used only in MAV_CMD_NAV_LOITER_TIME + 0, //! Not used + param_radius, //! If <0, then CCW loiter + 0, //! Not used + (float) Angles::degrees(path->end_lat), //! x PARAM5 / local: x position, global: latitude + (float) Angles::degrees(path->end_lon), //! y PARAM6 / y position: global: longitude + altitude ? path->end_z : path->end_z - m_hae_offset);//! z PARAM7 / z position: global: altitude + + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + } + else if(m_start) // Send Full Plan to Autopilot + { + // Clear previous mission + //clearMission(); + m_start = false; + + // Send Mission Count + mavlink_msg_mission_count_pack(255, 0, &msg, m_sysid, 0, (uint16_t)m_pspec.maneuvers.size()); + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + // Retrieve and send mission items + std::vector::const_iterator itr; + unsigned i=0; + for (itr = m_pspec.maneuvers.begin(); itr != m_pspec.maneuvers.end(); itr++, i++) + { + switch ((*itr)->data.get()->getId()) + { + case DUNE_IMC_GOTO: + { + debug("GOTO"); + const IMC::Goto *man_goto = static_cast((*itr)->data.get()); + + // Send Mission Item + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + i, //! seq Sequence + (man_goto->z_units == IMC::Z_ALTITUDE) ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + MAV_CMD_NAV_WAYPOINT, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 0, //! current false:0, true:1, guided mode:2 + 1, //! autocontinue to next wp + 0, //! Used only in MAV_CMD_NAV_LOITER_TIME + 0, //! Not used + (m_vtol_state == MAV_VTOL_STATE_FW) ? param_radius : 0, //! If <0, then CCW loiter + 0, //! Not used + (float) Angles::degrees(man_goto->lat), //! x PARAM5 / local: x position, global: latitude + (float) Angles::degrees(man_goto->lon), //! y PARAM6 / y position: global: longitude + (man_goto->z_units == IMC::Z_ALTITUDE) ? man_goto->z : man_goto->z - m_hae_offset);//! z PARAM7 / z position: global: altitude + + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + //delete man_goto; + break; + } + case DUNE_IMC_LOITER: + { + debug("LOITER"); + const IMC::Loiter *man_loiter = static_cast((*itr)->data.get()); + + // Send Mission Item + mavlink_msg_mission_item_pack(255, 0, &msg, + m_sysid, //! target_system System ID + 0, //! target_component Component ID + i, //! seq Sequence + (man_loiter->z_units == IMC::Z_ALTITUDE) ? MAV_FRAME_GLOBAL_RELATIVE_ALT : MAV_FRAME_GLOBAL, //! frame The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h + m_duration ? MAV_CMD_NAV_LOITER_TIME : MAV_CMD_NAV_LOITER_UNLIM, //! command The scheduled action for the MISSION. see MAV_CMD in ardupilotmega.h + 0, //! current false:0, true:1, guided mode:2 + 1, //! autocontinue to next wp + m_duration ? man_loiter->duration : 0, //! Used only in MAV_CMD_NAV_LOITER_TIME + 0, //! Not used + path->flags & DesiredPath::FL_CCLOCKW ? (-1 * man_loiter->radius) : (man_loiter->radius), //! If <0, then CCW loiter + 0, //! Not used + (float) Angles::degrees(man_loiter->lat), //! x PARAM5 / local: x position, global: latitude + (float) Angles::degrees(man_loiter->lon), //! y PARAM6 / y position: global: longitude + (man_loiter->z_units == IMC::Z_ALTITUDE) ? man_loiter->z : man_loiter->z - m_hae_offset);//! z PARAM7 / z position: global: altitude + + n = mavlink_msg_to_send_buffer(buf, &msg); + sendData(buf, n); + + //delete man_loiter; + break; + } + default: + err("Full Plan option only has support for GoTo and Loiter maneuvers currently."); + sendCommandPacket(MAV_CMD_DO_SET_MODE, MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, PX4_CUSTOM_MAIN_MODE_AUTO, PX4_CUSTOM_SUB_MODE_AUTO_LOITER); + inf("Setting LOITER mode."); + //m_tkoff_land = false; + return; + //break; + } + } + + inf("Full plan loaded to autopilot!"); + //TODO: Check if plan is cyclic (add support for plan transitions) + //TODO: Add support for other maneuvers: Takeoff, Land, Rows, ... + } + + // Set AUTO mode and MISSION submode + if(std::strcmp(m_mode.mode.c_str(), "MISSION")) + { + sendCommandPacket(MAV_CMD_DO_SET_MODE, MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, PX4_CUSTOM_MAIN_MODE_AUTO, PX4_CUSTOM_SUB_MODE_AUTO_MISSION); + inf("Setting MISSION mode."); + } + + //! Dispatch PathControlState + m_pcs.start_lat = m_estate.lat; + m_pcs.start_lon = m_estate.lon; + m_pcs.start_z = altitude ? m_estate.alt : m_estate.height; + m_pcs.start_z_units = altitude ? IMC::Z_ALTITUDE : IMC::Z_HEIGHT; + m_pcs.end_lat = path->end_lat; + m_pcs.end_lon = path->end_lon; + m_pcs.end_z = path->end_z_units; + m_pcs.end_z_units = altitude ? IMC::Z_ALTITUDE : IMC::Z_HEIGHT; + m_pcs.flags = PathControlState::FL_3DTRACK | PathControlState::FL_CCLOCKW; + m_pcs.flags &= path->flags; + m_pcs.lradius = path->lradius; + m_pcs.path_ref = path->path_ref; + + dispatch(m_pcs); + + // Update WP info + m_last_wp = Clock::get(); + m_duration = 0; + } + // Save DesiredPath + m_dpath = *path; + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + // Handle Autopilot data + if (m_TCP_sock || m_UDP_sock) + { + handleArdupilotData(); + } + else + { + Time::Delay::wait(0.5); + openConnection(); + } + + if (!m_error_missing) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + + // Handle IMC messages from bus + consumeMessages(); + } + } + + + void + handleArdupilotData(void) + { + mavlink_status_t status; + + double now = Clock::get(); + int counter = 0; + + while (poll(0.01) && counter < 100) + { + counter++; + + int n = receiveData(m_buf, sizeof(m_buf)); + if (n < 0) + { + debug("Receive error"); + break; + } + + // time stamp! + now = Clock::get(); + + // for each packet + for (int i = 0; i < n; i++) + { + int rv = mavlink_parse_char(MAVLINK_COMM_0, m_buf[i], &m_msg, &status); + + // check if parsing failed + checkParseState(status); + + // handle the parsed packet + if (rv) + { + spew("RECEIVED: %u", m_msg.msgid); + + // pull the handler + PktHandler h = m_mlh[m_msg.msgid]; + + // no handler + if (!h) + { + spew("UNDEF: %u", m_msg.msgid); + continue; // Ignore this packet + } + + // Call handler + (this->*h)(&m_msg); + m_sysid = m_msg.sysid; + + m_last_pkt_time = now; + } // end: handle the parsed packet + + } // end: for each packet + } // end: poll for packets + + + // check for timeout + if (now - m_last_pkt_time >= m_args.comm_timeout) + { + if (!m_error_missing) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_MISSING_DATA); + m_error_missing = true; + } + } + else + m_error_missing = false; + } + + void + checkParseState(mavlink_status_t& status) + { + // parsing failed + if (status.packet_rx_drop_count) + { + switch(status.parse_state) + { + case MAVLINK_PARSE_STATE_IDLE: + spew("failed at state IDLE"); + break; + case MAVLINK_PARSE_STATE_GOT_STX: + spew("failed at state GOT_STX"); + break; + case MAVLINK_PARSE_STATE_GOT_LENGTH: + spew("failed at state GOT_LENGTH"); + break; + case MAVLINK_PARSE_STATE_GOT_SYSID: + spew("failed at state GOT_SYSID"); + break; + case MAVLINK_PARSE_STATE_GOT_COMPID: + spew("failed at state GOT_COMPID"); + break; + case MAVLINK_PARSE_STATE_GOT_MSGID: + spew("failed at state GOT_MSGID"); + break; + case MAVLINK_PARSE_STATE_GOT_PAYLOAD: + spew("failed at state GOT_PAYLOAD"); + break; + case MAVLINK_PARSE_STATE_GOT_CRC1: + spew("failed at state GOT_CRC1"); + break; + default: + spew("failed OTHER"); + } + } // if parsing failed + } + + + // Serial Over TCP Polling + bool + poll(double timeout) + { + if (m_TCP_sock != NULL) + return Poll::poll(*m_TCP_sock, timeout); + + if (m_UDP_sock != NULL) + return Poll::poll(*m_UDP_sock, timeout); + + return false; + } + + int + sendData(uint8_t* bfr, int size) + { + if (m_TCP_sock) + { + trace("Sending something"); + return m_TCP_sock->write((char*)bfr, size); + } + else if (m_UDP_sock) + { + trace("Sending something"); + return m_UDP_sock->write(bfr, size, m_args.UDP_addr, m_args.UDP_port); + } + return 0; + } + + int + receiveData(uint8_t* buf, size_t blen) + { + if (m_TCP_sock || m_UDP_sock) + { + try + { + if (m_TCP_sock) + return m_TCP_sock->read(buf, blen); + if (m_UDP_sock) + return m_UDP_sock->read(buf, blen, &m_args.UDP_addr, &m_args.UDP_listen_port); + } + catch (std::runtime_error& e) + { + err("%s", e.what()); + war(DTR("Connection lost, retrying...")); + Memory::clear(m_TCP_sock); + Memory::clear(m_UDP_sock); + + if (m_args.tcp_or_udp) + { + m_TCP_sock = new Network::TCPSocket; + m_TCP_sock->connect(m_args.TCP_addr, m_args.TCP_port); + } + else + { + m_UDP_sock = new UDPSocket; + m_UDP_sock->bind(m_args.UDP_listen_port, Address::Any, false); + } + return 0; + } + } + return 0; + } + + + // PACKET HANDLERS + void + handleAttitudePacket(const mavlink_message_t* msg) + { + spew("ATTITUDE"); + + mavlink_attitude_t att; + + mavlink_msg_attitude_decode(msg, &att); + m_estate.phi = att.roll; + m_estate.theta = att.pitch; + m_estate.psi = att.yaw; + m_estate.p = att.rollspeed; + m_estate.q = att.pitchspeed; + m_estate.r = att.yawspeed; + + dispatch(m_estate); + } + + void + handleImuRaw(const mavlink_message_t* msg) + { + spew("IMU_RAW"); + + mavlink_raw_imu_t raw; + mavlink_msg_raw_imu_decode(msg, &raw); + + double tstamp = Clock::getSinceEpoch(); + + IMC::Acceleration acce; + acce.x = raw.xacc; + acce.y = raw.yacc; + acce.z = raw.zacc; + acce.setTimeStamp(tstamp); + dispatch(acce); + + IMC::AngularVelocity avel; + avel.x = raw.xgyro; + avel.y = raw.ygyro; + avel.z = raw.zgyro; + avel.setTimeStamp(tstamp); + dispatch(avel); + + IMC::MagneticField magn; + magn.x = raw.xmag; + magn.y = raw.ymag; + magn.z = raw.zmag; + magn.setTimeStamp(tstamp); + dispatch(magn); + } + + void + handlePositionPacket(const mavlink_message_t* msg) + { + spew("POSITION"); + + mavlink_global_position_int_t gp; + mavlink_msg_global_position_int_decode(msg, &gp); + + m_estate.lat = Angles::radians((double)gp.lat * 1e-07); + m_estate.lon = Angles::radians((double)gp.lon * 1e-07); + + // Calculate WGS84 height + if(!m_offset && m_fix.type == IMC::GpsFix::GFT_STANDALONE) + { + Coordinates::WMM wmm(m_ctx.dir_cfg); + m_hae_offset = wmm.height(m_estate.lat, m_estate.lon); + m_offset = true; + } + m_estate.height = (double) gp.alt * 1e-3 + m_hae_offset; // WGS84 + + m_estate.x = 0; + m_estate.y = 0; + m_estate.z = 0; + + m_estate.vx = 1e-02 * gp.vx; + m_estate.vy = 1e-02 * gp.vy; + m_estate.vz = -1e-02 * gp.vz; + + // Note: the following will yield body-fixed *ground* velocity + // Maybe this can be fixed w/IAS readings (anyway not too important) + BodyFixedFrame::toBodyFrame(m_estate.phi, m_estate.theta, m_estate.psi, + m_estate.vx, m_estate.vy, m_estate.vz, + &m_estate.u, &m_estate.v, &m_estate.w); + + m_estate.alt = (double) gp.relative_alt * 1e-3; //AGL (relative to home altitude) + m_estate.depth = -1; + + dispatch(m_estate); + } + + void + handleHWStatusPacket(const mavlink_message_t* msg) + { + spew("HW_STATUS"); + + mavlink_hwstatus_t hw_status; + IMC::Voltage volt; + + mavlink_msg_hwstatus_decode(msg, &hw_status); + + volt.value = 0.001 * hw_status.Vcc; + + dispatch(volt); + } + + void + handleSystemStatusPacket(const mavlink_message_t* msg) + { + spew("SYSTEM_STATUS"); + + mavlink_sys_status_t sys_status; + IMC::Voltage volt; + IMC::Current curr; + IMC::FuelLevel fuel; + + mavlink_msg_sys_status_decode(msg, &sys_status); + + volt.value = 0.001 * (float)sys_status.voltage_battery; + curr.value = 0.01 * (float)sys_status.current_battery; + fuel.value = (float)sys_status.battery_remaining; + + dispatch(volt); + dispatch(curr); + dispatch(fuel); + } + + void + handleScaledPressurePacket(const mavlink_message_t* msg) + { + spew("PRESSURE"); + + mavlink_scaled_pressure_t sc_press; + IMC::Pressure pressure; + IMC::Temperature temp; + + mavlink_msg_scaled_pressure_decode(msg, &sc_press); + + pressure.value = sc_press.press_abs; + temp.value = 0.01 * sc_press.temperature; + + dispatch(pressure); + dispatch(temp); + } + + void + handleWindPacket(const mavlink_message_t* msg) + { + spew("WIND"); + + mavlink_wind_t wind; + IMC::EstimatedStreamVelocity stream; + + mavlink_msg_wind_decode(msg, &wind); + + double wind_dir_rad = wind.direction * Math::c_pi / 180; + + stream.x = -std::cos(wind_dir_rad) * wind.speed; + stream.y = -std::sin(wind_dir_rad) * wind.speed; + stream.z = wind.speed_z; + + dispatch(stream); + } + + void + handleStatusTextPacket(const mavlink_message_t* msg) + { + spew("TEXT"); + mavlink_statustext_t stat_tex; + IMC::ApmStatus px4_status; + + mavlink_msg_statustext_decode(msg, &stat_tex); + px4_status.severity = stat_tex.severity; + px4_status.text = stat_tex.text; + + inf("PX4 Status: %.*s", 50, stat_tex.text); + dispatch(px4_status); + } + + void + handleHeartbeatPacket(const mavlink_message_t* msg) + { + spew("HEARTBEAT"); + + uint16_t n; + mavlink_heartbeat_t hbt; + mavlink_msg_heartbeat_decode(msg, &hbt); + IMC::ArmingState arming; + + // Check if it's a CAMERA heartbeat (Autopilot Heartbeat: #21 - HW || #22 - SITL) + if ((static_cast(hbt.type) != 21) && (static_cast(hbt.type) != 22)) + { + trace("Camera Heartbeat #%d", hbt.type); + return; + } + + // Send GCS heartbeat (debug purposes) + if(m_args.heartbeat) + { + mavlink_msg_heartbeat_pack(255, 0, &m_msg, MAV_TYPE_GCS, 0, 0, 0, 0); + n = mavlink_msg_to_send_buffer(m_buf, &m_msg); + sendData(m_buf, n); + spew("GCS Heartbeat"); + } + + if (hbt.system_status == MAV_STATE_CRITICAL) + war("PX4 failsafe active"); + + // Update motors current ArmingState + if (hbt.base_mode & MAV_MODE_FLAG_SAFETY_ARMED) + arming.state = IMC::ArmingState::MOTORS_ARMED; + else + arming.state = IMC::ArmingState::MOTORS_DISARMED; + dispatch(arming); + + uint8_t px4_mode = hbt.custom_mode >> 16; + uint8_t px4_submode = hbt.custom_mode >> 24; + + switch(px4_mode) + { + // Manual Modes + case PX4_CUSTOM_MAIN_MODE_MANUAL: + m_mode.autonomy = IMC::AutopilotMode::AL_MANUAL; + m_mode.mode = "MANUAL"; + trace("MANUAL"); + break; + case PX4_CUSTOM_MAIN_MODE_STABILIZED: + m_mode.autonomy = IMC::AutopilotMode::AL_MANUAL; + m_mode.mode = "STABILIZE"; + trace("STABILIZE"); + break; + case PX4_CUSTOM_MAIN_MODE_ACRO: + m_mode.autonomy = IMC::AutopilotMode::AL_MANUAL; + m_mode.mode = "ACRO"; + trace("ACRO"); + break; + case PX4_CUSTOM_MAIN_MODE_RATTITUDE: + m_mode.autonomy = IMC::AutopilotMode::AL_MANUAL; + m_mode.mode = "RATTITUDE"; + trace("RATTITUDE"); + break; + + // Assisted Modes + case PX4_CUSTOM_MAIN_MODE_ALTCTL: + m_mode.autonomy = IMC::AutopilotMode::AL_ASSISTED; + m_mode.mode = "ALTCTL"; + trace("ALTCTL"); + break; + case PX4_CUSTOM_MAIN_MODE_POSCTL: + m_mode.autonomy = IMC::AutopilotMode::AL_ASSISTED; + m_mode.mode = "POSCTL"; + trace("POSCTL"); + break; + + // Auto Modes + case PX4_CUSTOM_MAIN_MODE_AUTO: + m_mode.autonomy = IMC::AutopilotMode::AL_AUTO; + // Check submode + switch(px4_submode) + { + case PX4_CUSTOM_SUB_MODE_AUTO_LOITER: + m_mode.mode = "LOITER"; + trace("LOITER"); + break; + case PX4_CUSTOM_SUB_MODE_AUTO_RTL: + m_mode.mode = "RTL"; + trace("RTL"); + //TODO if in RTL get home and update PCC ? + break; + case PX4_CUSTOM_SUB_MODE_AUTO_MISSION: + if(m_dpath.end_lat) + { + receive(&m_cloops); + receive(&m_dpath); + } + m_mode.mode = "MISSION"; + trace("MISSION"); + break; + case PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF: + m_mode.mode = "TAKEOFF"; + trace("TAKEOFF"); + break; + case PX4_CUSTOM_SUB_MODE_AUTO_LAND: + m_mode.mode = "LAND"; + trace("LAND"); + break; + case PX4_CUSTOM_SUB_MODE_AUTO_FOLLOW_TARGET: + m_mode.mode = "GUIDED"; + trace("GUIDED"); + break; + default: + m_mode.mode = "AUTO"; + trace("AUTO"); + break; + } + break; + case PX4_CUSTOM_MAIN_MODE_OFFBOARD: + m_mode.autonomy = IMC::AutopilotMode::AL_AUTO; + m_mode.mode = "OFFBOARD"; + trace("OFFBOARD"); + break; + + // Default + default: + m_mode.autonomy = IMC::AutopilotMode::AL_MANUAL; + m_mode.mode = "UNKNOWN"; + break; + } + + dispatch(m_mode); + } + + void + handleHUDPacket(const mavlink_message_t* msg) + { + spew("HUD"); + + IMC::IndicatedSpeed ias; + mavlink_vfr_hud_t vfr_hud; + mavlink_msg_vfr_hud_decode(msg, &vfr_hud); + + ias.value = (fp64_t)vfr_hud.airspeed; + m_groundspeed.value = (fp64_t)vfr_hud.groundspeed; + + dispatch(ias); + dispatch(m_groundspeed); + } + + void + handleRawGPSPacket(const mavlink_message_t* msg) + { + spew("GPS_RAW"); + + mavlink_gps_raw_int_t gps_raw; + + mavlink_msg_gps_raw_int_decode(msg, &gps_raw); + + m_fix.cog = Angles::radians((double)gps_raw.cog * 0.01); + m_fix.sog = (float)gps_raw.vel * 0.01; + m_fix.hdop = (float)gps_raw.eph * 0.01; + m_fix.vdop = (float)gps_raw.epv * 0.01; + m_fix.lat = Angles::radians((double)gps_raw.lat * 1e-07); + m_fix.lon = Angles::radians((double)gps_raw.lon * 1e-07); + m_fix.height = (double)gps_raw.alt * 0.001; + m_fix.satellites = gps_raw.satellites_visible; + + m_fix.validity = 0; + if (gps_raw.fix_type > 1) + { + m_fix.validity |= IMC::GpsFix::GFV_VALID_POS; + m_fix.type = IMC::GpsFix::GFT_STANDALONE; + } + else + m_fix.type = IMC::GpsFix::GFT_DEAD_RECKONING; + + if (gps_raw.fix_type == 3) + { + m_fix.validity |= IMC::GpsFix::GFV_VALID_VDOP; + m_fix.vdop = 5; + } + } + + void + handleSystemTimePacket(const mavlink_message_t* msg) + { + spew("SYSTEM_TIME"); + + mavlink_system_time_t sys_time; + mavlink_msg_system_time_decode(msg, &sys_time); + + time_t t = sys_time.time_unix_usec / 1000000; + struct tm* utc; + utc = gmtime(&t); + + m_fix.utc_time = utc->tm_hour * 3600 + utc->tm_min * 60 + utc->tm_sec + (sys_time.time_unix_usec % 1000000) * 1e-6; + m_fix.utc_year = utc->tm_year + 1900; + m_fix.utc_month = utc->tm_mon +1; + m_fix.utc_day = utc->tm_mday; + + if (m_fix.utc_year>2014) + m_fix.validity |= (IMC::GpsFix::GFV_VALID_TIME | IMC::GpsFix::GFV_VALID_DATE); + + dispatch(m_fix); + } + + void + handleExtendedStatePacket(const mavlink_message_t* msg) + { + spew("EXTENDED_SYSTEM_STATE"); + + IMC::VtolState vtol; + mavlink_extended_sys_state_t extended_state; + mavlink_msg_extended_sys_state_decode(msg, &extended_state); + + // Update vtol state + m_vtol_state = (VTOL_State)extended_state.vtol_state; + + // Dispatch vtol state + vtol.state = m_vtol_state; + dispatch(vtol); + } + + void + handleMissionAckPacket(const mavlink_message_t* msg) + { + spew("MISSION_ACK"); + mavlink_mission_ack_t ack; + + mavlink_msg_mission_ack_decode(msg, &ack); + debug("Mission received, result is %d", ack.type); + + m_last_wp = 0; + } + + void + handleMissionItemReachedPacket(const mavlink_message_t* msg) + { + spew("MISSION_ITEM_REACHED"); + mavlink_mission_item_reached_t reached; + + mavlink_msg_mission_item_reached_decode(msg, &reached); + debug("Mission item %d reached.", reached.seq); + + // Check if timed loiter finished + if(m_mission && m_dpath.lradius) + { + sendCommandPacket(MAV_CMD_DO_SET_MODE, MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, PX4_CUSTOM_MAIN_MODE_AUTO, PX4_CUSTOM_SUB_MODE_AUTO_LOITER); + clearMission(); + m_mission = false; + m_start = false; + debug("Timed loiter ended."); + } + } + + void + handleNavControllerPacket(const mavlink_message_t* msg) + { + //TODO review and simplify. + spew("NAV_CONTROLLER"); + + mavlink_nav_controller_output_t nav_out; + mavlink_msg_nav_controller_output_decode(msg, &nav_out); + spew("WP Dist: %d", nav_out.wp_dist); //NOT WORKING PROPERLY IN COPTER + + float distance = 0; + Matrix destination = Matrix(3, 1, 0.0); + Matrix current_pos = Matrix(3, 1, 0.0); + current_pos(0) = m_estate.x; + current_pos(1) = m_estate.y; + current_pos(2) = m_estate.z; + + float alt = (m_dpath.end_z_units == IMC::Z_ALTITUDE) ? m_estate.alt : m_estate.height; + + WGS84::displacement(m_estate.lat, m_estate.lon, alt, + m_dpath.end_lat, m_dpath.end_lon, m_dpath.end_z, + &destination(0), &destination(1), &destination(2)); + + distance = (destination - current_pos).norm_2(); + nav_out.wp_dist = (uint16_t)distance; + + float since_last_wp = Clock::get() - m_last_wp; + int threshold; + + if(m_vtol_state == MAV_VTOL_STATE_FW) + threshold = m_args.threshold_fw; + else + threshold = m_args.threshold_mc; + + if(nav_out.wp_dist < threshold) + { + if(m_dpath.lradius > 0) + return; + + trace("FL_NEAR!"); + m_pcs.flags |= PathControlState::FL_NEAR; + m_mission = false; + } + + if (m_last_wp && since_last_wp > 1.5) + receive(&m_dpath); + + if (m_groundspeed.value) + m_pcs.eta = nav_out.wp_dist / m_groundspeed.value; + + if (std::strcmp(m_mode.mode.c_str(), "LOITER") && m_mode.autonomy == 2) + dispatch(m_pcs); + } + }; + } + } +} + +DUNE_TASK diff --git a/src/Control/UAV/RemoteOperation/Task.cpp b/src/Control/UAV/RemoteOperation/Task.cpp index 42ca425a4e..e8046cd690 100644 --- a/src/Control/UAV/RemoteOperation/Task.cpp +++ b/src/Control/UAV/RemoteOperation/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms.hpp b/src/DUNE/Algorithms.hpp index 264c2ba3b7..afa5f097d8 100644 --- a/src/DUNE/Algorithms.hpp +++ b/src/DUNE/Algorithms.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/Base64.cpp b/src/DUNE/Algorithms/Base64.cpp index f8ea8157c1..d6322bf4fd 100644 --- a/src/DUNE/Algorithms/Base64.cpp +++ b/src/DUNE/Algorithms/Base64.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -31,6 +31,8 @@ #include #include #include +#include + // DUNE headers. #include @@ -43,6 +45,8 @@ namespace DUNE static const std::string c_b64_en = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; + //! Base64 regular expression + static const char* c_b64_regex = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$"; //! Base64 decoding table. static const unsigned char c_b64_de[] = @@ -60,6 +64,14 @@ namespace DUNE 66,66,66,66,66,66 }; + //! Verify if string is a valid Base64 + bool + Base64::validBase64(const char* str) + { + std::basic_regex b64_expr(c_b64_regex, std::regex_constants::extended); + return (std::regex_match(str, b64_expr)); + } + //! Encode a sequence of bytes in Base64. std::string Base64::encode(const unsigned char* bytes, size_t len) diff --git a/src/DUNE/Algorithms/Base64.hpp b/src/DUNE/Algorithms/Base64.hpp index e29d2cf61a..fe58403d19 100644 --- a/src/DUNE/Algorithms/Base64.hpp +++ b/src/DUNE/Algorithms/Base64.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -99,6 +99,22 @@ namespace DUNE //! @return Base64 encoded string. static std::string decode(const unsigned char* bytes, size_t len); + + //! Verify if a string is decoded in Base64. + //! @param[in] str source string. + //! @return true if string is decoded in Base64. + static bool + validBase64(const std::string& str) + { + return validBase64((str.c_str())); + } + + //! Verify if a string is decoded in Base64. + //! @param[in] str source string. + //! @return true if string is decoded in Base64. + static bool + validBase64(const char* str); + }; } } diff --git a/src/DUNE/Algorithms/CRC16.cpp b/src/DUNE/Algorithms/CRC16.cpp index dc35e8a7b7..f1cf7cf564 100644 --- a/src/DUNE/Algorithms/CRC16.cpp +++ b/src/DUNE/Algorithms/CRC16.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/CRC16.hpp b/src/DUNE/Algorithms/CRC16.hpp index fc6f4cdbfe..bb0f9905fe 100644 --- a/src/DUNE/Algorithms/CRC16.hpp +++ b/src/DUNE/Algorithms/CRC16.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/CRC32.cpp b/src/DUNE/Algorithms/CRC32.cpp new file mode 100644 index 0000000000..ad3666ccb1 --- /dev/null +++ b/src/DUNE/Algorithms/CRC32.cpp @@ -0,0 +1,75 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Kristoffer Gryte based on work by Gary S. Brown * +// http://c.snippets.org/snip_lister.php?fname=crc_32.c * +//*************************************************************************** + +// DUNE headers. +#include + +namespace DUNE +{ + namespace Algorithms + { + /* CRC polynomial 0x04C11DB7 */ + const uint32_t c_crc32_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + } +} diff --git a/src/DUNE/Algorithms/CRC32.hpp b/src/DUNE/Algorithms/CRC32.hpp new file mode 100644 index 0000000000..0f8bcf264f --- /dev/null +++ b/src/DUNE/Algorithms/CRC32.hpp @@ -0,0 +1,96 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Kristoffer Gryte based on work by Ricardo Martins and * +// Gary S. Brown http://c.snippets.org/snip_lister.php?fname=crc_32.c * +//*************************************************************************** + +#ifndef DUNE_ALGORITHMS_CRC32_HPP_INCLUDED_ +#define DUNE_ALGORITHMS_CRC32_HPP_INCLUDED_ + +// DUNE headers. +#include + +namespace DUNE +{ + namespace Algorithms + { + // Export DLL Symbol. + class DUNE_DLL_SYM CRC32; + + extern const uint32_t c_crc32_table[256]; + + //! CRC-32 Algorithm. + //! The polynomial used is x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + 1 (0x04C11DB7) + class CRC32 + { + public: + + // From https://barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code + // Reflect the data around the center bit + static inline uint32_t + reflect(uint32_t data, const uint8_t len) + { + uint32_t reflection = 0; + + for (uint8_t bit = 0; bit < len; ++bit) + { + if (data & 0x01) + { + reflection |= (1 << ((len - 1) - bit)); + } + + data = (data >> 1); + } + + return reflection; + } + //! Compute the CRC-32 of a given data buffer. + //! @param buffer data buffer. + //! @param len data buffer length. + //! @param do_reflect if true, the intermediate results are reflected + //! @param crc CRC-32 value to update. + //! @return computed CRC-32. + static inline uint32_t + compute(const uint8_t *buf, const uint8_t len, bool do_reflect, uint32_t crc=0) + { + + const uint8_t *end; + uint8_t data; + + crc = ~crc; + for (end = buf + len; buf < end; ++buf) + { + data = do_reflect? reflect(*buf,8) : *buf; + crc = c_crc32_table[(crc ^ data) & 0xff] ^ (crc >> 8); + } + return ~crc; + } + }; + } +} + +#endif diff --git a/src/DUNE/Algorithms/CRC8.hpp b/src/DUNE/Algorithms/CRC8.hpp index fed0a6f36e..99ddc67fe3 100644 --- a/src/DUNE/Algorithms/CRC8.hpp +++ b/src/DUNE/Algorithms/CRC8.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/FletcherChecksum.hpp b/src/DUNE/Algorithms/FletcherChecksum.hpp index 87377de7c6..5d84bbfa50 100644 --- a/src/DUNE/Algorithms/FletcherChecksum.hpp +++ b/src/DUNE/Algorithms/FletcherChecksum.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/MD5.cpp b/src/DUNE/Algorithms/MD5.cpp index 0bf47ee8a0..361b1f482f 100644 --- a/src/DUNE/Algorithms/MD5.cpp +++ b/src/DUNE/Algorithms/MD5.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/MD5.hpp b/src/DUNE/Algorithms/MD5.hpp index e2a8733f02..20607f3dcc 100644 --- a/src/DUNE/Algorithms/MD5.hpp +++ b/src/DUNE/Algorithms/MD5.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/UNESCO1983.cpp b/src/DUNE/Algorithms/UNESCO1983.cpp index 11ec2e7b7e..34e358d387 100644 --- a/src/DUNE/Algorithms/UNESCO1983.cpp +++ b/src/DUNE/Algorithms/UNESCO1983.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/UNESCO1983.hpp b/src/DUNE/Algorithms/UNESCO1983.hpp index 92fb57ca23..4cf6aa21d6 100644 --- a/src/DUNE/Algorithms/UNESCO1983.hpp +++ b/src/DUNE/Algorithms/UNESCO1983.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Algorithms/XORChecksum.hpp b/src/DUNE/Algorithms/XORChecksum.hpp index 4dc4272594..31e84c2870 100644 --- a/src/DUNE/Algorithms/XORChecksum.hpp +++ b/src/DUNE/Algorithms/XORChecksum.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Casts.hpp b/src/DUNE/Casts.hpp index b00ea2022b..c88762b090 100644 --- a/src/DUNE/Casts.hpp +++ b/src/DUNE/Casts.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression.hpp b/src/DUNE/Compression.hpp index 8dccc99b0d..c3dc48579e 100644 --- a/src/DUNE/Compression.hpp +++ b/src/DUNE/Compression.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Bzip2Compressor.cpp b/src/DUNE/Compression/Bzip2Compressor.cpp index ff6a6a578f..aca9b19c5e 100644 --- a/src/DUNE/Compression/Bzip2Compressor.cpp +++ b/src/DUNE/Compression/Bzip2Compressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Bzip2Compressor.hpp b/src/DUNE/Compression/Bzip2Compressor.hpp index 5ef86efa33..ba63fd67ef 100644 --- a/src/DUNE/Compression/Bzip2Compressor.hpp +++ b/src/DUNE/Compression/Bzip2Compressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Bzip2Decompressor.cpp b/src/DUNE/Compression/Bzip2Decompressor.cpp index 14948943a4..af3e980224 100644 --- a/src/DUNE/Compression/Bzip2Decompressor.cpp +++ b/src/DUNE/Compression/Bzip2Decompressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Bzip2Decompressor.hpp b/src/DUNE/Compression/Bzip2Decompressor.hpp index 684c148ca7..11a746b8e7 100644 --- a/src/DUNE/Compression/Bzip2Decompressor.hpp +++ b/src/DUNE/Compression/Bzip2Decompressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Compressor.cpp b/src/DUNE/Compression/Compressor.cpp index 061d0dfcf9..514abf7168 100644 --- a/src/DUNE/Compression/Compressor.cpp +++ b/src/DUNE/Compression/Compressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Compressor.hpp b/src/DUNE/Compression/Compressor.hpp index 41792a4a7a..c52d976c46 100644 --- a/src/DUNE/Compression/Compressor.hpp +++ b/src/DUNE/Compression/Compressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Decompressor.cpp b/src/DUNE/Compression/Decompressor.cpp index 4bf5f18ac4..1518c00003 100644 --- a/src/DUNE/Compression/Decompressor.cpp +++ b/src/DUNE/Compression/Decompressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Decompressor.hpp b/src/DUNE/Compression/Decompressor.hpp index 6abaf12831..003296cfe8 100644 --- a/src/DUNE/Compression/Decompressor.hpp +++ b/src/DUNE/Compression/Decompressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Exceptions.hpp b/src/DUNE/Compression/Exceptions.hpp index 95e5300097..97f27f6eef 100644 --- a/src/DUNE/Compression/Exceptions.hpp +++ b/src/DUNE/Compression/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Factory.cpp b/src/DUNE/Compression/Factory.cpp index 3c33d63a18..1645e0ebd8 100644 --- a/src/DUNE/Compression/Factory.cpp +++ b/src/DUNE/Compression/Factory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Factory.hpp b/src/DUNE/Compression/Factory.hpp index c798d146c8..b5e9857dd2 100644 --- a/src/DUNE/Compression/Factory.hpp +++ b/src/DUNE/Compression/Factory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/FileInput.hpp b/src/DUNE/Compression/FileInput.hpp index 92b4e4600d..7a9809294e 100644 --- a/src/DUNE/Compression/FileInput.hpp +++ b/src/DUNE/Compression/FileInput.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/FileOutput.hpp b/src/DUNE/Compression/FileOutput.hpp index bb095d8810..b8a3f3ba6a 100644 --- a/src/DUNE/Compression/FileOutput.hpp +++ b/src/DUNE/Compression/FileOutput.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/FilterInput.hpp b/src/DUNE/Compression/FilterInput.hpp index df1d20be0e..4fa2e526ec 100644 --- a/src/DUNE/Compression/FilterInput.hpp +++ b/src/DUNE/Compression/FilterInput.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/FilterOutput.hpp b/src/DUNE/Compression/FilterOutput.hpp index 83619f7e55..b64cfdccd9 100644 --- a/src/DUNE/Compression/FilterOutput.hpp +++ b/src/DUNE/Compression/FilterOutput.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/GzipCompressor.cpp b/src/DUNE/Compression/GzipCompressor.cpp index b0e23fd4fd..4769c7ebff 100644 --- a/src/DUNE/Compression/GzipCompressor.cpp +++ b/src/DUNE/Compression/GzipCompressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/GzipCompressor.hpp b/src/DUNE/Compression/GzipCompressor.hpp index 2219ebce64..9cf74ff2d0 100644 --- a/src/DUNE/Compression/GzipCompressor.hpp +++ b/src/DUNE/Compression/GzipCompressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/Methods.hpp b/src/DUNE/Compression/Methods.hpp index f89e1f5134..aecad159da 100644 --- a/src/DUNE/Compression/Methods.hpp +++ b/src/DUNE/Compression/Methods.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/StreamBuffer.cpp b/src/DUNE/Compression/StreamBuffer.cpp index e9a7844834..745b49f097 100644 --- a/src/DUNE/Compression/StreamBuffer.cpp +++ b/src/DUNE/Compression/StreamBuffer.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/StreamBuffer.hpp b/src/DUNE/Compression/StreamBuffer.hpp index 2c5f072d4c..0525bae924 100644 --- a/src/DUNE/Compression/StreamBuffer.hpp +++ b/src/DUNE/Compression/StreamBuffer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/ZlibCompressor.cpp b/src/DUNE/Compression/ZlibCompressor.cpp index 067a9eb115..13c3a9188f 100644 --- a/src/DUNE/Compression/ZlibCompressor.cpp +++ b/src/DUNE/Compression/ZlibCompressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/ZlibCompressor.hpp b/src/DUNE/Compression/ZlibCompressor.hpp index 97a13d5a94..a61a713ebb 100644 --- a/src/DUNE/Compression/ZlibCompressor.hpp +++ b/src/DUNE/Compression/ZlibCompressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/ZlibDecompressor.cpp b/src/DUNE/Compression/ZlibDecompressor.cpp index 22c4e321ba..8894007f77 100644 --- a/src/DUNE/Compression/ZlibDecompressor.cpp +++ b/src/DUNE/Compression/ZlibDecompressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Compression/ZlibDecompressor.hpp b/src/DUNE/Compression/ZlibDecompressor.hpp index 8e040f69db..65aee24832 100644 --- a/src/DUNE/Compression/ZlibDecompressor.hpp +++ b/src/DUNE/Compression/ZlibDecompressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency.hpp b/src/DUNE/Concurrency.hpp index 26546bd09c..b23dd5be31 100644 --- a/src/DUNE/Concurrency.hpp +++ b/src/DUNE/Concurrency.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/AtomicCounter.hpp b/src/DUNE/Concurrency/AtomicCounter.hpp index 5b66b06691..00dc367c95 100644 --- a/src/DUNE/Concurrency/AtomicCounter.hpp +++ b/src/DUNE/Concurrency/AtomicCounter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/AtomicInteger.hpp b/src/DUNE/Concurrency/AtomicInteger.hpp index 82927d6a03..4fa40c745f 100644 --- a/src/DUNE/Concurrency/AtomicInteger.hpp +++ b/src/DUNE/Concurrency/AtomicInteger.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Barrier.cpp b/src/DUNE/Concurrency/Barrier.cpp index 3325ead58d..dbe792c790 100644 --- a/src/DUNE/Concurrency/Barrier.cpp +++ b/src/DUNE/Concurrency/Barrier.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Barrier.hpp b/src/DUNE/Concurrency/Barrier.hpp index eab9181bcd..9483c0359e 100644 --- a/src/DUNE/Concurrency/Barrier.hpp +++ b/src/DUNE/Concurrency/Barrier.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Condition.cpp b/src/DUNE/Concurrency/Condition.cpp index 61d4a7553f..f8a0635818 100644 --- a/src/DUNE/Concurrency/Condition.cpp +++ b/src/DUNE/Concurrency/Condition.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -96,7 +96,13 @@ namespace DUNE if (t > 0) { - t += m_clock_monotonic ? Time::Clock::get() : Time::Clock::getSinceEpoch(); + if (Time::Clock::getTimeMultiplier() != 1.0) + { + t /= Time::Clock::getTimeMultiplier(); + t += m_clock_monotonic ? Time::Clock::getRT() : Time::Clock::getSinceEpochRT(); + } + else + t += m_clock_monotonic ? Time::Clock::get() : Time::Clock::getSinceEpoch(); timespec ts = DUNE_TIMESPEC_INIT_SEC_FP(t); rv = pthread_cond_timedwait(&m_cond, &m_mutex, &ts); diff --git a/src/DUNE/Concurrency/Condition.hpp b/src/DUNE/Concurrency/Condition.hpp index cb185c7bc4..b778fa49aa 100644 --- a/src/DUNE/Concurrency/Condition.hpp +++ b/src/DUNE/Concurrency/Condition.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Constants.hpp b/src/DUNE/Concurrency/Constants.hpp index 34df70f9b3..357964d2ea 100644 --- a/src/DUNE/Concurrency/Constants.hpp +++ b/src/DUNE/Concurrency/Constants.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Exceptions.hpp b/src/DUNE/Concurrency/Exceptions.hpp index 7ba0ad0348..296a5c74f0 100644 --- a/src/DUNE/Concurrency/Exceptions.hpp +++ b/src/DUNE/Concurrency/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Initializer.cpp b/src/DUNE/Concurrency/Initializer.cpp index 8a2d84fb36..fe113fc697 100644 --- a/src/DUNE/Concurrency/Initializer.cpp +++ b/src/DUNE/Concurrency/Initializer.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Initializer.hpp b/src/DUNE/Concurrency/Initializer.hpp index d759383d4c..1690f4b1fb 100644 --- a/src/DUNE/Concurrency/Initializer.hpp +++ b/src/DUNE/Concurrency/Initializer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Mutex.cpp b/src/DUNE/Concurrency/Mutex.cpp index 57e0c9f956..26df537a5e 100644 --- a/src/DUNE/Concurrency/Mutex.cpp +++ b/src/DUNE/Concurrency/Mutex.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Mutex.hpp b/src/DUNE/Concurrency/Mutex.hpp index ca0524b0b4..43d461912b 100644 --- a/src/DUNE/Concurrency/Mutex.hpp +++ b/src/DUNE/Concurrency/Mutex.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Process.cpp b/src/DUNE/Concurrency/Process.cpp index f2717d85e1..da50ebb4c9 100644 --- a/src/DUNE/Concurrency/Process.cpp +++ b/src/DUNE/Concurrency/Process.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Process.hpp b/src/DUNE/Concurrency/Process.hpp index 0c7831f4a7..d62a384145 100644 --- a/src/DUNE/Concurrency/Process.hpp +++ b/src/DUNE/Concurrency/Process.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/RWLock.cpp b/src/DUNE/Concurrency/RWLock.cpp index 00b48e3963..db877a7fae 100644 --- a/src/DUNE/Concurrency/RWLock.cpp +++ b/src/DUNE/Concurrency/RWLock.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/RWLock.hpp b/src/DUNE/Concurrency/RWLock.hpp index 6e5a2fd6a5..b5a91b7350 100644 --- a/src/DUNE/Concurrency/RWLock.hpp +++ b/src/DUNE/Concurrency/RWLock.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/RawTLS.cpp b/src/DUNE/Concurrency/RawTLS.cpp index c6020d865e..41cd21ecab 100644 --- a/src/DUNE/Concurrency/RawTLS.cpp +++ b/src/DUNE/Concurrency/RawTLS.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/RawTLS.hpp b/src/DUNE/Concurrency/RawTLS.hpp index b6b528d928..fbddd0cada 100644 --- a/src/DUNE/Concurrency/RawTLS.hpp +++ b/src/DUNE/Concurrency/RawTLS.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Runnable.hpp b/src/DUNE/Concurrency/Runnable.hpp index 5ecb24b450..206d655f0a 100644 --- a/src/DUNE/Concurrency/Runnable.hpp +++ b/src/DUNE/Concurrency/Runnable.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Scheduler.cpp b/src/DUNE/Concurrency/Scheduler.cpp index 4da660cf85..4bb4e9416c 100644 --- a/src/DUNE/Concurrency/Scheduler.cpp +++ b/src/DUNE/Concurrency/Scheduler.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Scheduler.hpp b/src/DUNE/Concurrency/Scheduler.hpp index 6ff54a621d..494602b496 100644 --- a/src/DUNE/Concurrency/Scheduler.hpp +++ b/src/DUNE/Concurrency/Scheduler.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/ScopedCondition.hpp b/src/DUNE/Concurrency/ScopedCondition.hpp index e3eaa28b36..84830bb46c 100644 --- a/src/DUNE/Concurrency/ScopedCondition.hpp +++ b/src/DUNE/Concurrency/ScopedCondition.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/ScopedMutex.hpp b/src/DUNE/Concurrency/ScopedMutex.hpp index 7b747897c3..5f97e031f9 100644 --- a/src/DUNE/Concurrency/ScopedMutex.hpp +++ b/src/DUNE/Concurrency/ScopedMutex.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/ScopedRWLock.hpp b/src/DUNE/Concurrency/ScopedRWLock.hpp index 6df9534e84..c626a32fa9 100644 --- a/src/DUNE/Concurrency/ScopedRWLock.hpp +++ b/src/DUNE/Concurrency/ScopedRWLock.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/ScopedSemaphore.hpp b/src/DUNE/Concurrency/ScopedSemaphore.hpp index 9d63538885..45cb5ce810 100644 --- a/src/DUNE/Concurrency/ScopedSemaphore.hpp +++ b/src/DUNE/Concurrency/ScopedSemaphore.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Semaphore.cpp b/src/DUNE/Concurrency/Semaphore.cpp index eb21d3d6c8..fe50ea0a51 100644 --- a/src/DUNE/Concurrency/Semaphore.cpp +++ b/src/DUNE/Concurrency/Semaphore.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Semaphore.hpp b/src/DUNE/Concurrency/Semaphore.hpp index 1428a61d1a..7cd414d00a 100644 --- a/src/DUNE/Concurrency/Semaphore.hpp +++ b/src/DUNE/Concurrency/Semaphore.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/SharedMemory.cpp b/src/DUNE/Concurrency/SharedMemory.cpp index ec02dffa7b..174615033c 100644 --- a/src/DUNE/Concurrency/SharedMemory.cpp +++ b/src/DUNE/Concurrency/SharedMemory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/SharedMemory.hpp b/src/DUNE/Concurrency/SharedMemory.hpp index f9df1df6c3..63aec7eaf9 100644 --- a/src/DUNE/Concurrency/SharedMemory.hpp +++ b/src/DUNE/Concurrency/SharedMemory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/TLS.hpp b/src/DUNE/Concurrency/TLS.hpp index 88b0b7889f..f8460ad30f 100644 --- a/src/DUNE/Concurrency/TLS.hpp +++ b/src/DUNE/Concurrency/TLS.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/TSQueue.hpp b/src/DUNE/Concurrency/TSQueue.hpp index cabd07589c..c9b7d5fa71 100644 --- a/src/DUNE/Concurrency/TSQueue.hpp +++ b/src/DUNE/Concurrency/TSQueue.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -77,9 +77,28 @@ namespace DUNE m_queue.pop(); return v; } + return 0; } + //! Retrieve the first element of the queue and removes it from + //! the queue. + //! @param[in,out] value where to store the popped value. + //! @return true if an element was popped, false otherwise. + bool + pop(T& value) + { + ScopedCondition l(m_cond); + if (m_queue.size() > 0) + { + value = m_queue.front(); + m_queue.pop(); + return true; + } + + return false; + } + //! Wait for items to be available. //! @param timeout timeout in seconds, use a negative number to wait forever. //! @return true if at least one element is available, false diff --git a/src/DUNE/Concurrency/Thread.cpp b/src/DUNE/Concurrency/Thread.cpp index afe723fc25..7726bb4c39 100644 --- a/src/DUNE/Concurrency/Thread.cpp +++ b/src/DUNE/Concurrency/Thread.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Concurrency/Thread.hpp b/src/DUNE/Concurrency/Thread.hpp index f9c96d2174..1638a9e6b5 100644 --- a/src/DUNE/Concurrency/Thread.hpp +++ b/src/DUNE/Concurrency/Thread.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Config.hpp.in b/src/DUNE/Config.hpp.in index db6f9a68cb..9442691d68 100644 --- a/src/DUNE/Config.hpp.in +++ b/src/DUNE/Config.hpp.in @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control.hpp b/src/DUNE/Control.hpp index aa50dae8cf..ea1395bcc6 100644 --- a/src/DUNE/Control.hpp +++ b/src/DUNE/Control.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/AUVModel.cpp b/src/DUNE/Control/AUVModel.cpp index b4de814c7f..0bcc95fcd0 100644 --- a/src/DUNE/Control/AUVModel.cpp +++ b/src/DUNE/Control/AUVModel.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/AUVModel.hpp b/src/DUNE/Control/AUVModel.hpp index d8a36b68c5..a44b6a5306 100644 --- a/src/DUNE/Control/AUVModel.hpp +++ b/src/DUNE/Control/AUVModel.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/BasicAutopilot.cpp b/src/DUNE/Control/BasicAutopilot.cpp index 0eff1d46d6..5e2f52527a 100644 --- a/src/DUNE/Control/BasicAutopilot.cpp +++ b/src/DUNE/Control/BasicAutopilot.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/BasicAutopilot.hpp b/src/DUNE/Control/BasicAutopilot.hpp index 06fba5fda2..84b76027fe 100644 --- a/src/DUNE/Control/BasicAutopilot.hpp +++ b/src/DUNE/Control/BasicAutopilot.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/BasicRemoteOperation.cpp b/src/DUNE/Control/BasicRemoteOperation.cpp index 12ab67d178..faad270840 100644 --- a/src/DUNE/Control/BasicRemoteOperation.cpp +++ b/src/DUNE/Control/BasicRemoteOperation.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -59,11 +59,15 @@ namespace DUNE false); param("Connection Timeout", m_connection_timeout) - .defaultValue("1.0") - .units(Units::Second); + .defaultValue("1.0") + .units(Units::Second); addActionButton("Exit"); + param("Additional Actions", m_additional_actions) + .defaultValue("") + .description("Actions to be added to remote actions list (comma separated in the form Action:Type)"); + m_actions.op = IMC::RemoteActionsRequest::OP_REPORT; // Register handler routines. @@ -143,9 +147,52 @@ namespace DUNE } } + void + BasicRemoteOperation::setupAdditionalActions(const std::vector& additional_actions) + { + for (unsigned int i = 0; i < additional_actions.size(); ++i) + { + if (Utils::String::ltrim(additional_actions[i]).size() < 3) + continue; + + std::vector parts; + Utils::String::split(additional_actions[i], ":", parts); + + if (parts.size() != 2) continue; + + std::string action_name = parts[0]; + action_name = Utils::String::ltrim(action_name); + action_name = Utils::String::rtrim(action_name); + if (action_name.empty()) continue; + + std::string type_lowercase = parts[1]; + type_lowercase = Utils::String::ltrim(type_lowercase); + type_lowercase = Utils::String::rtrim(type_lowercase); + Utils::String::toLowerCase(type_lowercase); + + if (!type_lowercase.compare("button")) + { + addActionButton(action_name); + } + else if (!type_lowercase.compare("axis")) + { + addActionAxis(action_name); + } + else if (!type_lowercase.compare("slider")) + { + addActionSlider(action_name); + } + else if (!type_lowercase.compare("halfslider")) + { + addActionHalfSlider(action_name); + } + } + } + void BasicRemoteOperation::onResourceInitialization(void) { + setupAdditionalActions(m_additional_actions); setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); } diff --git a/src/DUNE/Control/BasicRemoteOperation.hpp b/src/DUNE/Control/BasicRemoteOperation.hpp index 5cfff9380a..ffc2f5dfc7 100644 --- a/src/DUNE/Control/BasicRemoteOperation.hpp +++ b/src/DUNE/Control/BasicRemoteOperation.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -79,6 +79,18 @@ namespace DUNE addRemoteAction(action, "Axis"); } + void + addActionSlider(const std::string& action) + { + addRemoteAction(action, "Slider"); + } + + void + addActionHalfSlider(const std::string& action) + { + addRemoteAction(action, "HalfSlider"); + } + void setConnectionTimeout(const float tout) { @@ -91,6 +103,9 @@ namespace DUNE (void)message; } + void + setupAdditionalActions(const std::vector& additional_actions); + virtual void onConnectionTimeout(void) { } @@ -146,6 +161,8 @@ namespace DUNE IMC::RemoteActionsRequest m_actions; //! Control loops last reference uint32_t m_scope_ref; + //! Additional Remote Operation Actions + std::vector m_additional_actions; //! IMC ID of the teleoperation source uint16_t m_teleop_src; diff --git a/src/DUNE/Control/BasicUAVAutopilot.cpp b/src/DUNE/Control/BasicUAVAutopilot.cpp index 3dadfd1b8a..51aeeeea7f 100644 --- a/src/DUNE/Control/BasicUAVAutopilot.cpp +++ b/src/DUNE/Control/BasicUAVAutopilot.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/BasicUAVAutopilot.hpp b/src/DUNE/Control/BasicUAVAutopilot.hpp index d284a55a7a..89071b460b 100644 --- a/src/DUNE/Control/BasicUAVAutopilot.hpp +++ b/src/DUNE/Control/BasicUAVAutopilot.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/BottomTracker.cpp b/src/DUNE/Control/BottomTracker.cpp index efdc3ffc85..dd54032e4e 100644 --- a/src/DUNE/Control/BottomTracker.cpp +++ b/src/DUNE/Control/BottomTracker.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -51,9 +51,13 @@ static const float c_depth_hyst = 0.5; static const float c_alt_hyst = 0.2; //! State to string for debug messages -static const std::string c_str_states[] = {DTR_RT("Idle"), DTR_RT("Tracking"), - DTR_RT("Depth"), DTR_RT("LimitDepth"), - DTR_RT("Unsafe"), DTR_RT("Avoiding")}; +static const std::string c_str_states[] = {DTR_RT("Idle"), + DTR_RT("Tracking"), + DTR_RT("Depth"), + DTR_RT("LimitDepthMax"), + DTR_RT("LimitDepthMin"), + DTR_RT("Unsafe"), + DTR_RT("Avoiding")}; //! Bottom tracker name static const std::string c_bt_name = DTR_RT("BottomTrack"); @@ -255,7 +259,8 @@ namespace DUNE else onIdle(); break; - case SM_LIMITDEPTH: + case SM_LIMITDEPTH_MAX: // fall-through + case SM_LIMITDEPTH_MIN: onLimitDepth(); break; case SM_UNSAFE: @@ -377,8 +382,20 @@ namespace DUNE { info(DTR("depth is reaching unacceptable values, forcing depth control")); m_forced = FC_DEPTH; - dispatchLimitDepth(); - m_mstate = SM_LIMITDEPTH; + dispatchLimitDepth(true); + m_mstate = SM_LIMITDEPTH_MAX; + return; + } + + // altitude reference below minimum depth + // not enforced when forcing altitude control. + if (m_args->min_depth > 0 && m_forced != FC_ALTITUDE && z_ref <= m_args->min_depth) + { + info(String::str("depth is too low: %.2f, forcing depth control.", + z_ref)); + m_forced = FC_DEPTH; + dispatchLimitDepth(false); + m_mstate = SM_LIMITDEPTH_MIN; return; } } @@ -444,11 +461,18 @@ namespace DUNE return; } + float const z_ref = getReverseZ(); + // can we switch back ? - if (isAltitudeValid() && getReverseZ() < m_args->depth_limit && - m_estate.depth < m_args->depth_limit + c_depth_hyst) + if (isAltitudeValid() && + (((m_mstate == SM_LIMITDEPTH_MAX) && + (z_ref < m_args->depth_limit && + m_estate.depth < m_args->depth_limit + c_depth_hyst)) || + (m_mstate == SM_LIMITDEPTH_MIN && + (z_ref > m_args->min_depth + c_depth_hyst && + m_estate.depth > m_args->min_depth - c_depth_hyst)))) { - debug("limit depth: depth is no longer near the limit -> tracking"); + info("limit depth: depth is no longer near the limit -> tracking"); m_forced = FC_NONE; m_mstate = SM_TRACKING; @@ -616,10 +640,10 @@ namespace DUNE } void - BottomTracker::dispatchLimitDepth(void) const + BottomTracker::dispatchLimitDepth(bool max_depth) const { IMC::DesiredZ limit_depth; - limit_depth.value = m_args->depth_limit; + limit_depth.value = max_depth ? m_args->depth_limit : m_args->min_depth; limit_depth.z_units = IMC::Z_DEPTH; m_args->entity->dispatch(limit_depth); debug(String::str("dispatching limit depth: %.2f", limit_depth.value)); diff --git a/src/DUNE/Control/BottomTracker.hpp b/src/DUNE/Control/BottomTracker.hpp index fb25ea4a92..5e919d6208 100644 --- a/src/DUNE/Control/BottomTracker.hpp +++ b/src/DUNE/Control/BottomTracker.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -60,6 +60,8 @@ namespace DUNE float safe_pitch; //! Minimum admissible altitude for bottom tracking. float min_alt; + //! Minimum admissible depth for bottom tracking. + float min_depth; //! Minimum admissible forward range for bottom tracking. float min_range; //! Depth limit for tracking bottom. @@ -136,8 +138,10 @@ namespace DUNE SM_TRACKING, //! Depth control. SM_DEPTH, - //! On limit depth control. - SM_LIMITDEPTH, + //! On limit depth control (enforce maximum depth). + SM_LIMITDEPTH_MAX, + //! On limit depth control (enforce minimum depth). + SM_LIMITDEPTH_MIN, //! In an unsafe yet controllable state. SM_UNSAFE, //! Avoiding unsurpassable obstacle. @@ -203,8 +207,9 @@ namespace DUNE dispatchSafeDepth(void) const; //! Dispatch absolute limit for desired depth message. + //! @param[in] max_depth dispatch maximum or minimum depth limit void - dispatchLimitDepth(void) const; + dispatchLimitDepth(bool max_depth) const; //! Dispatch same altitude. void diff --git a/src/DUNE/Control/CoarseAltitude.cpp b/src/DUNE/Control/CoarseAltitude.cpp index a1e193e0cb..c82f2cbe23 100644 --- a/src/DUNE/Control/CoarseAltitude.cpp +++ b/src/DUNE/Control/CoarseAltitude.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/CoarseAltitude.hpp b/src/DUNE/Control/CoarseAltitude.hpp index 717026a10b..c12ae01abc 100644 --- a/src/DUNE/Control/CoarseAltitude.hpp +++ b/src/DUNE/Control/CoarseAltitude.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/DiscretePID.cpp b/src/DUNE/Control/DiscretePID.cpp index c49f125271..8a15ad5199 100644 --- a/src/DUNE/Control/DiscretePID.cpp +++ b/src/DUNE/Control/DiscretePID.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/DiscretePID.hpp b/src/DUNE/Control/DiscretePID.hpp index fb2b482c7b..112d58e702 100644 --- a/src/DUNE/Control/DiscretePID.hpp +++ b/src/DUNE/Control/DiscretePID.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/LinearSystem.cpp b/src/DUNE/Control/LinearSystem.cpp index bffec976ac..a1e13bec4b 100644 --- a/src/DUNE/Control/LinearSystem.cpp +++ b/src/DUNE/Control/LinearSystem.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/LinearSystem.hpp b/src/DUNE/Control/LinearSystem.hpp index 300ea9ecd5..678f01641a 100644 --- a/src/DUNE/Control/LinearSystem.hpp +++ b/src/DUNE/Control/LinearSystem.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/PathController.cpp b/src/DUNE/Control/PathController.cpp index 41e3610362..6da0a69a35 100644 --- a/src/DUNE/Control/PathController.cpp +++ b/src/DUNE/Control/PathController.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -27,9 +27,6 @@ // Author: Eduardo Marques * //*************************************************************************** -// ISO C++ 98 headers. -#include - // DUNE headers. #include #include @@ -157,12 +154,14 @@ namespace DUNE param("Bottom Track -- Safe Pitch", m_btd.args.safe_pitch) .defaultValue("15.0") .units(Units::Degree) - .description("Safe pitch angle to perform bottom tracking"); + .description("Safe pitch angle to perform bottom tracking. " + "Reboot BottomTracker to update."); param("Bottom Track -- Slope Hysteresis", m_btd.args.slope_hyst) .defaultValue("1.5") .units(Units::Degree) - .description("Slope hysteresis when recovering from avoidance"); + .description("Slope hysteresis when recovering from avoidance. " + "Reboot BottomTracker to update."); param("Bottom Track -- Minimum Range", m_btd.args.min_range) .defaultValue("4.0") @@ -176,7 +175,8 @@ namespace DUNE param("Bottom Track -- Execution Frequency", m_btd.args.control_period) .defaultValue("5") .units(Units::Hertz) - .description("Bottom tracker's execution frequency"); + .description("Bottom tracker's execution frequency. " + "Reboot BottomTracker to update."); param("Bottom Track -- Depth Avoidance", m_btd.args.depth_avoid) .defaultValue("true") @@ -187,6 +187,18 @@ namespace DUNE .units(Units::Meter) .description("Admissible altitude when doing depth control"); + param("Bottom Track -- Minimum Depth", m_btd.args.min_depth) + .defaultValue("0.0") + .units(Units::Meter) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .scope(Tasks::Parameter::SCOPE_MANEUVER) + .description("Minimum depth to maintain during bottom tracking"); + + param("Maximum Track Length", m_max_track_length) + .defaultValue("25000") + .units(Units::Meter) + .description("Maximum admissible track length"); + m_ctx.config.get("General", "Absolute Maximum Depth", "50.0", m_btd.args.depth_limit); m_btd.args.depth_limit -= c_depth_margin; @@ -294,14 +306,84 @@ namespace DUNE { if (!isActive()) { - err(DTR("not active")); + war(DTR("not active")); + return; + } + + const double now = Clock::get(); + const bool no_start = setStartPoint(now, dpath); + setEndPoint(dpath); + + Coordinates::getBearingAndRange(m_ts.start, m_ts.end, + &m_ts.track_bearing, &m_ts.track_length); + + if (m_max_track_length > 0 && m_ts.track_length > m_max_track_length) + { + signalError(DTR("track length is too long")); return; } - double now = Clock::get(); + // Re-initializing tracking state values + m_ts.start_time = now; + m_ts.end_time = -1; + m_ts.now = m_ts.start_time; + m_ts.delta = 0; + m_tracking = true; + + // Reset monitors disable due to navigation jump + // if current desired path does not have fixed start location + if (no_start) + m_jump_monitors = false; + + setControlLoops(dpath); + handleLoiter(dpath); + + updateTrackingState(); + reportPathControlState(true); + updateEntityState(); + + inf(DTR("path (lat/lon): %0.5f %0.5f to %0.5f %0.5f"), + Angles::degrees(m_pcs.start_lat), Angles::degrees(m_pcs.start_lon), + Angles::degrees(m_pcs.end_lat), Angles::degrees(m_pcs.end_lon)); + + trace("state (lat/lon) %0.5f %0.5f" + " | path (x,y,z) %0.2f, %0.2f, %0.2f to %0.2f, %0.2f, %0.2f" + " | length(m) / bearing (dg): %0.2f / %0.2f" + " | state (x,y,z) %0.2f,%0.2f,%0.2f" + " | track pos (x,y,z): %0.2f, %0.2f, %0.2f" + " | course error (dg): %0.2f", + Angles::degrees(m_estate.lat), Angles::degrees(m_estate.lon), + m_ts.start.x, m_ts.start.y, m_ts.start.z, + m_ts.end.x, m_ts.end.y, m_ts.end.z, + m_ts.track_length, Angles::degrees(m_ts.track_bearing), + m_estate.x, m_estate.y, m_estate.z, + m_ts.track_pos.x, m_ts.track_pos.y, m_ts.track_pos.z, + Angles::degrees(m_ts.course_error)); + + if (m_atm.enabled) + { + // Initialize along-track monitoring data. + m_atm.diverging = false; + m_atm.time = m_ts.now + m_atm.period; + m_atm.last_err = m_ts.track_pos.x; + m_atm.last_course_err = std::fabs(m_ts.course_error); + } + + if (m_ctm.enabled) + { + // Initialize cross-track monitoring data. + m_ctm.diverging = false; + } + + // Call path startup handler. + onPathStartup(m_estate, m_ts); + } + + bool + PathController::setStartPoint(double now, const IMC::DesiredPath* dpath) + { m_pcs.flags = 0; m_pcs.path_ref = dpath->path_ref; - bool no_start = false; if (dpath->flags & IMC::DesiredPath::FL_START) { @@ -309,34 +391,44 @@ namespace DUNE m_pcs.start_lon = dpath->start_lon; m_pcs.start_z = dpath->start_z; m_pcs.start_z_units = dpath->start_z_units; + + return false; } - else if ((!m_tracking && now - m_ts.end_time > 1) || - (!m_ts.nearby && !m_ts.loitering) || - (dpath->flags & IMC::DesiredPath::FL_DIRECT) != 0) + + if ((!m_tracking && now - m_ts.end_time > 1) || + (!m_ts.nearby && !m_ts.loitering) || + (dpath->flags & IMC::DesiredPath::FL_DIRECT) != 0) { m_pcs.start_lat = m_estate.lat; m_pcs.start_lon = m_estate.lon; Coordinates::toWGS84(m_estate, m_pcs.start_lat, m_pcs.start_lon); - m_pcs.start_z = m_estate.z; + m_pcs.start_z = m_estate.height - m_estate.z; + m_pcs.start_z_units = dpath->start_z_units; - no_start = true; - } - else - { - m_pcs.start_lat = m_pcs.end_lat; - m_pcs.start_lon = m_pcs.end_lon; - m_pcs.start_z = m_pcs.end_z; - m_pcs.start_z_units = m_pcs.end_z_units; + return true; } + m_pcs.start_lat = m_pcs.end_lat; + m_pcs.start_lon = m_pcs.end_lon; + m_pcs.start_z = m_pcs.end_z; + m_pcs.start_z_units = m_pcs.end_z_units; + + return false; + } + + void + PathController::setEndPoint(const IMC::DesiredPath* dpath) + { WGS84::displacement(m_estate.lat, m_estate.lon, 0, m_pcs.start_lat, m_pcs.start_lon, 0, &m_ts.start.x, &m_ts.start.y); m_ts.start.z = m_pcs.start_z; + m_ts.start.z_units = m_pcs.start_z_units; - if ((dpath->flags & IMC::DesiredPath::FL_LOITER_CURR) != 0 && dpath->lradius > 0) + if ((dpath->flags & IMC::DesiredPath::FL_LOITER_CURR) != 0 && + dpath->lradius > 0) { m_pcs.end_lat = m_estate.lat; m_pcs.end_lon = m_estate.lon; @@ -357,28 +449,19 @@ namespace DUNE m_pcs.end_lat, m_pcs.end_lon, 0, &m_ts.end.x, &m_ts.end.y); m_ts.end.z = m_pcs.end_z; + m_ts.end.z_units = m_pcs.end_z_units; + } - Coordinates::getBearingAndRange(m_ts.start, m_ts.end, - &m_ts.track_bearing, &m_ts.track_length); - - // Re-initializing tracking state values - m_ts.start_time = now; - m_ts.end_time = -1; - m_ts.now = m_ts.start_time; - m_ts.delta = 0; - m_tracking = true; - - // Reset monitors disable due to navigation jump - // if current desired path does not have fixed start location - if (no_start) - m_jump_monitors = false; - + void + PathController::setControlLoops(const IMC::DesiredPath* dpath) + { // Send altitude or depth references, unless NO_Z flag is set // or controller wishes to handle depth/altitude in a specific manner if (!hasSpecificZControl() && !(dpath->flags & IMC::DesiredPath::FL_NO_Z)) { m_ts.z_control = true; - if (dpath->end_z_units == IMC::Z_ALTITUDE || dpath->end_z_units == IMC::Z_HEIGHT) + if (dpath->end_z_units == IMC::Z_ALTITUDE || + dpath->end_z_units == IMC::Z_HEIGHT) { disableControlLoops(IMC::CL_DEPTH); enableControlLoops(IMC::CL_ALTITUDE); @@ -410,27 +493,22 @@ namespace DUNE enableControlLoops(IMC::CL_SPEED); dispatch(m_speed, Tasks::DF_LOOP_BACK); + } - // Loiter handling + void + PathController::handleLoiter(const IMC::DesiredPath* dpath) + { m_ts.loiter.radius = dpath->lradius; - m_ts.loiter.clockwise = (dpath->flags & IMC::DesiredPath::FL_CCLOCKW) == 0; + m_ts.loiter.clockwise = + (dpath->flags & IMC::DesiredPath::FL_CCLOCKW) == 0; if (m_ts.loiter.radius > 0) { m_ts.loiter.center = m_ts.end; - double course_err; - course_err = std::fabs(Angles::normalizeRadian(m_estate.psi - m_ts.track_bearing)); - double sign; - - double range = c_lkeep_distance + 1.0; - - // if we're already loitering - if (m_ts.loitering) - { - double dummy; - Coordinates::getBearingAndRange(m_ts.end, m_ts.loiter.center, &dummy, &range); - } + const double range = + m_ts.loitering ? Coordinates::getRange(m_ts.end, m_ts.loiter.center) + : c_lkeep_distance + 1.0; // loiter's center has not changed much and vehicle is close to circle if (range < c_lkeep_distance && m_ts.loitering && @@ -442,14 +520,19 @@ namespace DUNE // avoid singularities (very close to loiter center) else if (m_ts.track_length < c_ldistance) { - Coordinates::setBearingAndRange(m_ts.loiter.center, m_estate.psi, - m_ts.loiter.radius, m_ts.end); + Coordinates::setBearingAndRange( + m_ts.loiter.center, m_estate.psi, m_ts.loiter.radius, m_ts.end); m_ts.loitering = false; m_ts.nearby = false; } else { + const double course_err = std::fabs( + Angles::normalizeRadian(m_estate.psi - m_ts.track_bearing)); + + double sign; + // if inside the circle and turned inwards if ((m_ts.track_length <= m_ts.loiter.radius * c_lsize_factor) && (course_err < Math::c_half_pi)) @@ -457,63 +540,24 @@ namespace DUNE else sign = m_ts.loiter.clockwise ? -1.0 : 1.0; - Coordinates::setBearingAndRange(m_ts.loiter.center, - m_ts.track_bearing + sign * Math::c_half_pi, - m_ts.loiter.radius, - m_ts.end); + Coordinates::setBearingAndRange( + m_ts.loiter.center, + m_ts.track_bearing + sign * Math::c_half_pi, + m_ts.loiter.radius, + m_ts.end); m_ts.loitering = false; m_ts.nearby = false; } - Coordinates::getBearingAndRange(m_ts.start, m_ts.end, - &m_ts.track_bearing, &m_ts.track_length); + Coordinates::getBearingAndRange( + m_ts.start, m_ts.end, &m_ts.track_bearing, &m_ts.track_length); } else { m_ts.loitering = false; m_ts.nearby = false; } - - updateTrackingState(); - reportPathControlState(true); - updateEntityState(); - - inf(DTR("path (lat/lon): %0.5f %0.5f to %0.5f %0.5f"), - Angles::degrees(m_pcs.start_lat), Angles::degrees(m_pcs.start_lon), - Angles::degrees(m_pcs.end_lat), Angles::degrees(m_pcs.end_lon)); - - trace("state (lat/lon) %0.5f %0.5f" - " | path (x,y,z) %0.2f, %0.2f, %0.2f to %0.2f, %0.2f, %0.2f" - " | length(m) / bearing (dg): %0.2f / %0.2f" - " | state (x,y,z) %0.2f,%0.2f,%0.2f" - " | track pos (x,y,z): %0.2f, %0.2f, %0.2f" - " | course error (dg): %0.2f", - Angles::degrees(m_estate.lat), Angles::degrees(m_estate.lon), - m_ts.start.x, m_ts.start.y, m_ts.start.z, - m_ts.end.x, m_ts.end.y, m_ts.end.z, - m_ts.track_length, Angles::degrees(m_ts.track_bearing), - m_estate.x, m_estate.y, m_estate.z, - m_ts.track_pos.x, m_ts.track_pos.y, m_ts.track_pos.z, - Angles::degrees(m_ts.course_error)); - - if (m_atm.enabled) - { - // Initialize along-track monitoring data. - m_atm.diverging = false; - m_atm.time = m_ts.now + m_atm.period; - m_atm.last_err = m_ts.track_pos.x; - m_atm.last_course_err = std::fabs(m_ts.course_error); - } - - if (m_ctm.enabled) - { - // Initialize cross-track monitoring data. - m_ctm.diverging = false; - } - - // Call path startup handler. - onPathStartup(m_estate, m_ts); } void @@ -552,25 +596,7 @@ namespace DUNE if (isTrackingBottom()) { - try - { - m_btrack->onEstimatedState(es); - } - catch (std::runtime_error& e) - { - // If braking then stop braking - if (m_braking) - { - IMC::Brake brk; - brk.op = IMC::Brake::OP_STOP; - dispatch(brk); - - m_braking = false; - } - - signalError(e.what()); - return; - } + m_btrack->onEstimatedState(es); } if (m_setup) @@ -579,20 +605,6 @@ namespace DUNE updateEntityState(); } - bool change_ref = false; - double lat = 0.0; - double lon = 0.0; - - // Save different LLH reference. - if (es->lat != m_estate.lat || - es->lon != m_estate.lon || - es->height != m_estate.height) - { - change_ref = true; - lat = es->lat; - lon = es->lon; - } - // Save previous EstimatedState values IMC::EstimatedState prev_estate = m_estate; @@ -602,6 +614,10 @@ namespace DUNE if (!isActive() || m_error || !m_tracking) return; + const bool change_ref = + (m_estate.lat != prev_estate.lat || m_estate.lon != prev_estate.lon || + m_estate.height != prev_estate.height); + // If navigation jumped, disable path monitors for an amount time // proportional to the size of the navigation jump (by m_jump_factor) if (!m_jump_monitors) @@ -613,7 +629,7 @@ namespace DUNE m_jump_monitors = true; // Limit the distance - float top = trimValue(dist / m_jump_factor, 0, c_max_jump_time); + const float top = trimValue(dist / m_jump_factor, 0, c_max_jump_time); m_jump_timer.setTop(top); debug("disabling monitors, navigation jumped %.1f meters", dist); @@ -632,6 +648,9 @@ namespace DUNE // Apply new LLH reference. if (change_ref) { + const double lat = m_estate.lat; + const double lon = m_estate.lon; + WGS84::displacement(lat, lon, 0, m_pcs.start_lat, m_pcs.start_lon, 0, &m_ts.start.x, &m_ts.start.y); @@ -640,7 +659,7 @@ namespace DUNE &m_ts.end.x, &m_ts.end.y); } - double now = Clock::get(); + const double now = Clock::get(); if (now < m_ts.now + m_cperiod) return; @@ -654,7 +673,7 @@ namespace DUNE return; } - bool prev_nearby = m_ts.nearby; + const bool prev_nearby = m_ts.nearby; updateTrackingState(); @@ -665,6 +684,20 @@ namespace DUNE else loiter(*es, m_ts); + handleMonitors(); + + if (!m_ts.loitering && m_ts.nearby && m_ts.loiter.radius > 0) + { + m_ts.end = m_ts.loiter.center; + m_ts.loitering = true; + m_ts.nearby = false; + inf(DTR("now loitering")); + } + } + + void + PathController::handleMonitors(void) + { // If we're braking or there has been a jump in the navigation // filter then do not check for errors in monitoring if ((m_braking && !m_brake_timer.overflow()) || m_jump_monitors) @@ -701,14 +734,6 @@ namespace DUNE if (m_ctm.enabled) monitorCrossTrackError(); } - - if (!m_ts.loitering && m_ts.nearby && m_ts.loiter.radius > 0) - { - m_ts.end = m_ts.loiter.center; - m_ts.loitering = true; - m_ts.nearby = false; - inf(DTR("now loitering")); - } } void @@ -720,24 +745,18 @@ namespace DUNE // Ground course and speed m_ts.course = m_ts.cc ? std::atan2(m_estate.vy, m_estate.vx) : m_estate.psi; m_ts.speed = m_ts.cc ? Math::norm(m_estate.vx, m_estate.vy) : m_estate.u; + m_ts.vertical_speed = m_estate.vz; if (!m_ts.loitering) { getTrackPosition(m_estate, &m_ts.track_pos.x, &m_ts.track_pos.y); + // vertical-track + m_ts.track_pos.z = m_ts.end.z - getZ(static_cast(m_ts.end.z_units)); m_ts.course_error = Angles::normalizeRadian(m_ts.course - m_ts.track_bearing); - float errx = std::abs(m_ts.track_length - m_ts.track_pos.x); - float erry = std::abs(m_ts.track_pos.y); - float s = std::max((double)m_eta_min_speed, m_ts.speed); - - if (errx <= erry && erry < c_erry_factor * m_time_factor * s) - m_ts.eta = errx / s; - else - m_ts.eta = Math::norm(errx, erry) / s; - - m_ts.eta = std::min(65535.0, m_ts.eta - m_time_factor); + m_ts.eta = getEta(m_ts); - bool was_nearby = m_ts.nearby; + const bool was_nearby = m_ts.nearby; if (!m_ts.nearby && m_ts.eta <= 0) { @@ -753,19 +772,20 @@ namespace DUNE { m_ts.track_pos.x = 0; m_ts.track_pos.y = m_ts.range - m_ts.loiter.radius; + m_ts.track_pos.z = m_ts.end.z - getZ(static_cast(m_ts.end.z_units)); if (m_ts.loiter.clockwise) m_ts.track_pos.y = -m_ts.track_pos.y; - double ang_increment = (m_ts.loiter.clockwise ? - Math::c_half_pi : -Math::c_half_pi); + const double ang_increment = + m_ts.loiter.clockwise ? Math::c_half_pi : -Math::c_half_pi; + m_ts.course_error = m_ts.course - m_ts.los_angle + ang_increment; m_ts.course_error = Angles::normalizeRadian(m_ts.course_error); m_ts.eta = 0; m_ts.nearby = false; } - m_ts.track_pos.z = m_estate.z - m_ts.end.z; // vertical-track m_ts.track_vel.x = m_ts.speed * std::cos(m_ts.course_error); // along-track m_ts.track_vel.y = m_ts.speed * std::sin(m_ts.course_error); // cross-track m_ts.track_vel.z = std::sin(m_estate.theta) * m_estate.vz; // vertical-track @@ -774,7 +794,7 @@ namespace DUNE bool PathController::navigationJumped(const IMC::EstimatedState* new_state, const IMC::EstimatedState* old_state, - float &distance, bool change_ref) + float& distance, bool change_ref) { if (change_ref) { @@ -867,7 +887,7 @@ namespace DUNE void PathController::monitorCrossTrackError(void) { - double d = std::fabs(m_ts.track_pos.y); + const double d = std::fabs(m_ts.track_pos.y); if (d >= m_ctm.distance_limit + m_ctm.nav_uncertainty) { @@ -906,8 +926,8 @@ namespace DUNE if (!(cloops->mask & IMC::CL_PATH)) return; - bool was = isActive(); - bool will = cloops->enable == IMC::ControlLoops::CL_ENABLE; + const bool was = isActive(); + const bool will = cloops->enable == IMC::ControlLoops::CL_ENABLE; if (was != will) { @@ -1046,6 +1066,36 @@ namespace DUNE step(state, lts); } + double + PathController::getEta(const TrackingState& ts) + { + const float errx = std::abs(ts.track_length - ts.track_pos.x); + const float erry = std::abs(ts.track_pos.y); + const float time_factor = getTimeFactor(); + const float speed = getSpeed(); + + const double eta = + errx <= erry && erry < c_erry_factor * time_factor * speed + ? errx / speed + : Math::norm(errx, erry) / speed; + + return std::min(65535.0, eta - time_factor); + } + + + double + PathController::getZ(IMC::ZUnits unit) + { + if (unit == IMC::Z_HEIGHT) + return m_estate.height; + + if (unit == IMC::Z_ALTITUDE) + return m_estate.alt; + + if (unit == IMC::Z_DEPTH) + return m_estate.depth; + } + void PathController::deactivateBottomTracker(void) { diff --git a/src/DUNE/Control/PathController.hpp b/src/DUNE/Control/PathController.hpp index 3f9b2cf049..a7cf669a16 100644 --- a/src/DUNE/Control/PathController.hpp +++ b/src/DUNE/Control/PathController.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -32,7 +32,6 @@ // ISO C++ 98 headers. #include -#include // DUNE headers. #include @@ -157,6 +156,7 @@ namespace DUNE double x; double y; double z; + uint8_t z_units; } start, end; //! bearing from start to end. @@ -172,6 +172,8 @@ namespace DUNE //! current ground speed if course control enabled, //! body-fixed frame u speed otherwise. double speed; + //! Vertical speed. + double vertical_speed; //! course error in relation to track bearing. double course_error; @@ -243,6 +245,27 @@ namespace DUNE return false; } + //! Default implementation for calculating estimated time of arrival, + //! that can be overridden to change how maneuver completion is signalized. + //! @param ts the current tracking state + //! @param time_factor for time of arrival factor + //! @param speed + //! @return the calculated estimated time of arrival + virtual double + getEta(const TrackingState& ts); + + float + getSpeed(void) const + { + return std::max((double)m_eta_min_speed, m_ts.speed); + } + + float + getTimeFactor(void) const + { + return m_time_factor; + } + //! Signal an error. //! This method should be used by subclasses to signal an error condition. //! @param msg error message @@ -297,6 +320,20 @@ namespace DUNE void updateTrackingState(void); + // Helper functions for consume(const IMC::DesiredPath*) + bool + setStartPoint(double now, const IMC::DesiredPath* dpath); + void + setEndPoint(const IMC::DesiredPath* dpath); + void + setControlLoops(const IMC::DesiredPath* dpath); + void + handleLoiter(const IMC::DesiredPath* dpath); + + // Helper function for consume(const IMC::EstimatedState*) + void + handleMonitors(void); + //! Test if there has been a jump in navigation //! @param[in] new_state newly received EstimatedState //! @param[in] old_state newly received EstimatedState @@ -306,7 +343,7 @@ namespace DUNE bool navigationJumped(const IMC::EstimatedState* new_state, const IMC::EstimatedState* old_state, - float &distance, bool change_ref); + float& distance, bool change_ref); //! Monitor along track error and update variables void @@ -336,11 +373,17 @@ namespace DUNE //! @param[out] y y coordinate relatively to path template inline void - getTrackPosition(const T& coord, double* x, double* y = 0) + getTrackPosition(const T& coord, double* x, double* y = 0) const { Coordinates::getTrackPosition(m_ts.start, m_ts.track_bearing, coord, x, y); } + //! Get EstimatedState vertical position, based on ZUnits + //! @param unit Coordenate unit + //! @return EstimatedSate vertical position + double + getZ(IMC::ZUnits unit); + //! Deactivate bottom tracker void deactivateBottomTracker(void); @@ -348,7 +391,7 @@ namespace DUNE //! Is the system performing bottom tracking ? //! @return true if it is bottom tracking, false otherwise. bool - isTrackingBottom(void) + isTrackingBottom(void) const { return m_btd.enabled && (m_btrack != NULL); } @@ -458,6 +501,8 @@ namespace DUNE BottomTracker* m_btrack; //! Control loops last reference uint32_t m_scope_ref; + //! Maximum admitted track length + double m_max_track_length; }; } } diff --git a/src/DUNE/Control/ProxyPathController.cpp b/src/DUNE/Control/ProxyPathController.cpp index 1f6295f6e8..5a3f3a666b 100644 --- a/src/DUNE/Control/ProxyPathController.cpp +++ b/src/DUNE/Control/ProxyPathController.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/ProxyPathController.hpp b/src/DUNE/Control/ProxyPathController.hpp index a626320d03..06d6a55059 100644 --- a/src/DUNE/Control/ProxyPathController.hpp +++ b/src/DUNE/Control/ProxyPathController.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/SlopeData.hpp b/src/DUNE/Control/SlopeData.hpp index 4dbfccc76a..f2b0a421a1 100644 --- a/src/DUNE/Control/SlopeData.hpp +++ b/src/DUNE/Control/SlopeData.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Control/YoYoMotion.hpp b/src/DUNE/Control/YoYoMotion.hpp index 73323a32fb..5aaa6490ed 100644 --- a/src/DUNE/Control/YoYoMotion.hpp +++ b/src/DUNE/Control/YoYoMotion.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Coordinates.hpp b/src/DUNE/Coordinates.hpp index 757b4d0bed..6b42285bf9 100644 --- a/src/DUNE/Coordinates.hpp +++ b/src/DUNE/Coordinates.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Coordinates/BodyFixedFrame.hpp b/src/DUNE/Coordinates/BodyFixedFrame.hpp index 59c1a0553b..a582fa1305 100644 --- a/src/DUNE/Coordinates/BodyFixedFrame.hpp +++ b/src/DUNE/Coordinates/BodyFixedFrame.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Coordinates/General.cpp b/src/DUNE/Coordinates/General.cpp index cbec7f680a..0a0903056a 100644 --- a/src/DUNE/Coordinates/General.cpp +++ b/src/DUNE/Coordinates/General.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -103,5 +103,43 @@ namespace DUNE return Utils::String::str("%03d%02d.%05d,%c", std::abs(lon_deg), lon_min, lon_min_frac, (lon_deg >= 0) ? 'E' : 'W'); } + + double + NMEAToLatitude(const std::string& str) + { + int lat_deg = 0; + double lat_min = 0.0; + char hemisphere; + + if (str[4] != '.') + return -1.0; + + if (std::sscanf(str.c_str(), "%02d%lf,%c", &lat_deg, &lat_min, &hemisphere) != 3) + return -1.0; + + if (hemisphere == 'S') + lat_deg *= -1; + + return Math::Angles::normalizeRadian(Math::Angles::radians(Math::Angles::convertDMSToDecimal(lat_deg, lat_min))); + } + + double + NMEAToLongitude(const std::string& str) + { + int lon_deg = 0; + double lon_min = 0.0; + char hemisphere; + + if (str[5] != '.') + return -1.0; + + if (std::sscanf(str.c_str(), "%03d%lf,%c", &lon_deg, &lon_min, &hemisphere) != 3) + return -1.0; + + if (hemisphere == 'W') + lon_deg *= -1; + + return Math::Angles::normalizeRadian(Math::Angles::radians(Math::Angles::convertDMSToDecimal(lon_deg, lon_min))); + } } } diff --git a/src/DUNE/Coordinates/General.hpp b/src/DUNE/Coordinates/General.hpp index 2e7d8eeb19..05c5e322a9 100644 --- a/src/DUNE/Coordinates/General.hpp +++ b/src/DUNE/Coordinates/General.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -31,6 +31,7 @@ #define DUNE_COORDINATES_GENERAL_HPP_INCLUDED_ // ISO C++ 98 headers. +#include #include // DUNE headers. @@ -140,7 +141,7 @@ namespace DUNE //! @param y optional cross-track position on exit template void - getTrackPosition(const A& origin, double orientation, const B& point, double* x, double* y = 0) + getTrackPosition(const A& origin, double orientation, const B& point, double* x, double* y = nullptr) { double b, r; @@ -207,6 +208,18 @@ namespace DUNE //! @return NMEA formatted longitude. std::string longitudeToNMEA(double longitude); + + //! Convert NMEA latitude to latitude in radians. + //! @param[in] str NMEA formatted latitude. + //! @return latitude in radians. + double + NMEAToLatitude(const std::string& str); + + //! Convert NMEA longitude to longitude in radians. + //! @param[in] str NMEA formatted longitude. + //! @return longitude in radians. + double + NMEAToLongitude(const std::string& str); } } diff --git a/src/DUNE/Coordinates/UTM.cpp b/src/DUNE/Coordinates/UTM.cpp index bc1c400850..8ea3bce097 100644 --- a/src/DUNE/Coordinates/UTM.cpp +++ b/src/DUNE/Coordinates/UTM.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Coordinates/UTM.hpp b/src/DUNE/Coordinates/UTM.hpp index 671995a56a..9b7e5b68a2 100644 --- a/src/DUNE/Coordinates/UTM.hpp +++ b/src/DUNE/Coordinates/UTM.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Coordinates/WGS84.hpp b/src/DUNE/Coordinates/WGS84.hpp index 8e83dc6ab2..f8e2462b10 100644 --- a/src/DUNE/Coordinates/WGS84.hpp +++ b/src/DUNE/Coordinates/WGS84.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -182,7 +182,15 @@ namespace DUNE toECEF(*lat, *lon, *hae, &x, &y, &z); // Compute Geocentric latitude - double phi = std::atan2(z, std::sqrt(x * x + y * y)); + double p = std::sqrt(x * x + y * y); +#if defined(DUNE_ELLIPSOIDAL_DISPLACE) + // Use elliptical coordinates + double N = computeRn(*lat); + double phi = std::atan2(z,p*(1 - c_wgs84_e2 * N / (N + *hae))); +#else + // Use spherical coordinates + double phi = std::atan2(z,p); +#endif // Compute all needed sine and cosine terms for conversion. double slon = std::sin(*lon); @@ -285,7 +293,6 @@ namespace DUNE getNEBearingAndRange(lat1, lon1, lat2, lon2, azimuth, &tmp); } - private: //! Convert WGS-84 coordinates to ECEF (Earch Center Earth Fixed) coordinates. //! //! @param[in] lat WGS-84 latitude (rad). @@ -313,7 +320,7 @@ namespace DUNE *z = (((1.0 - c_wgs84_e2) * rn) + hae) * sin_lat; } - //! Convert ECEF (x,y,z) to WGS-84 (lat, lon, hae). + //! Convert ECEF (x,y,z) to WGS-84 (lat, lon, hae) using non-iterative solution. //! //! @param[in] x ECEF x coordinate (m). //! @param[in] y ECEF y coordinate (m). @@ -331,22 +338,14 @@ namespace DUNE double p = std::sqrt(x * x + y * y); *lon = std::atan2(y, x); - *lat = std::atan2(z / p, 0.01); - double n = computeRn(*lat); - *hae = p / std::cos(*lat) - n; - double old_hae = -1e-9; - double num = z / p; - - while (std::fabs(*hae - old_hae) > 1e-4) - { - old_hae = *hae; - double den = 1 - c_wgs84_e2 * n / (n + *hae); - *lat = std::atan2(num, den); - n = computeRn(*lat); - *hae = p / std::cos(*lat) - n; - } + double theta = std::atan2(c_wgs84_a * z, p * c_wgs84_b); + double num = z + c_wgs84_ep2 * c_wgs84_b * std::pow(std::sin(theta), 3.0); + double den = p - c_wgs84_e2 * c_wgs84_a * std::pow(std::cos(theta), 3.0); + *lat = std::atan2(num, den); + *hae = p / std::cos(*lat) - computeRn(*lat); } + private: //! Compute the radius of curvature in the prime vertical (Rn). //! //! @param[in] lat WGS-84 latitude (rad). diff --git a/src/DUNE/Coordinates/WMM.cpp b/src/DUNE/Coordinates/WMM.cpp index f2b80559db..3fae7b6dde 100644 --- a/src/DUNE/Coordinates/WMM.cpp +++ b/src/DUNE/Coordinates/WMM.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Coordinates/WMM.hpp b/src/DUNE/Coordinates/WMM.hpp index d1d227acf6..8bdd9ec958 100644 --- a/src/DUNE/Coordinates/WMM.hpp +++ b/src/DUNE/Coordinates/WMM.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/DUNE.hpp b/src/DUNE/DUNE.hpp index 1351a27e57..c6e6da6921 100644 --- a/src/DUNE/DUNE.hpp +++ b/src/DUNE/DUNE.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Daemon.cpp b/src/DUNE/Daemon.cpp index a2f32fc0bc..d5240246cc 100644 --- a/src/DUNE/Daemon.cpp +++ b/src/DUNE/Daemon.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -49,7 +49,8 @@ namespace DUNE Daemon::Daemon(DUNE::Tasks::Context& ctx, const std::string& profiles): DUNE::Tasks::Task("Daemon", ctx), m_tman(NULL), - m_fs_capacity(0) + m_fs_capacity(0), + call_reboot(false) { // Retrieve known IMC addresses. std::vector addrs = m_ctx.config.options("IMC Addresses"); @@ -151,6 +152,12 @@ namespace DUNE inf(DTR("clean shutdown")); } + bool + Daemon::callReboot(void) + { + return call_reboot; + } + void Daemon::onResourceInitialization(void) { @@ -192,7 +199,7 @@ namespace DUNE IMC::MessageList::const_iterator itr = msg->params.begin(); for ( ; itr != msg->params.end(); ++itr) { - if (m_ctx.config.get(task_name, (*itr)->name) != (*itr)->value) + if (m_ctx.original_cfg.get(task_name, (*itr)->name) != (*itr)->value) m_scfg.set(task_name, (*itr)->name, (*itr)->value); } @@ -210,7 +217,11 @@ namespace DUNE void Daemon::consume(const IMC::RestartSystem* msg) { - (void)msg; + if (msg -> type == IMC::RestartSystem::RSTYPE_SYSTEM) + { + call_reboot = true; + inf(DTR("Got message to reboot system")); + } stop(); } diff --git a/src/DUNE/Daemon.hpp b/src/DUNE/Daemon.hpp index 523f51b4f5..056b3557e6 100644 --- a/src/DUNE/Daemon.hpp +++ b/src/DUNE/Daemon.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -65,6 +65,9 @@ namespace DUNE ~Daemon(void); + bool + callReboot(void); + void onResourceInitialization(void); @@ -105,6 +108,8 @@ namespace DUNE int m_cpu_max_usage; //! Overall CPU usage - moving average. Math::MovingAverage* m_cpu_avg; + //! Signal system reboot + bool call_reboot; void measureCpuUsage(void); diff --git a/src/DUNE/Database.hpp b/src/DUNE/Database.hpp index be382cf77e..a9e6a34e91 100644 --- a/src/DUNE/Database.hpp +++ b/src/DUNE/Database.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Database/Connection.cpp b/src/DUNE/Database/Connection.cpp index 41fd6b28a5..0d1ee3ad23 100644 --- a/src/DUNE/Database/Connection.cpp +++ b/src/DUNE/Database/Connection.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Database/Connection.hpp b/src/DUNE/Database/Connection.hpp index 491a39e859..ead1c12ab4 100644 --- a/src/DUNE/Database/Connection.hpp +++ b/src/DUNE/Database/Connection.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Database/General.hpp b/src/DUNE/Database/General.hpp index bb28e40b01..915ce3683e 100644 --- a/src/DUNE/Database/General.hpp +++ b/src/DUNE/Database/General.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Database/Statement.cpp b/src/DUNE/Database/Statement.cpp index 876e36f64e..e4aa315dfc 100644 --- a/src/DUNE/Database/Statement.cpp +++ b/src/DUNE/Database/Statement.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Database/Statement.hpp b/src/DUNE/Database/Statement.hpp index 6f098c29ec..5f9ac93ff6 100644 --- a/src/DUNE/Database/Statement.hpp +++ b/src/DUNE/Database/Statement.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Entities.hpp b/src/DUNE/Entities.hpp index 7508079e6e..a122bdb23e 100644 --- a/src/DUNE/Entities.hpp +++ b/src/DUNE/Entities.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Entities/BasicEntity.cpp b/src/DUNE/Entities/BasicEntity.cpp index e00a01b3a0..b671ac2c3f 100644 --- a/src/DUNE/Entities/BasicEntity.cpp +++ b/src/DUNE/Entities/BasicEntity.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Entities/BasicEntity.hpp b/src/DUNE/Entities/BasicEntity.hpp index 517628fd1f..094fab9ed9 100644 --- a/src/DUNE/Entities/BasicEntity.hpp +++ b/src/DUNE/Entities/BasicEntity.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -121,7 +121,7 @@ namespace DUNE //! @param[in] label string to be compared against. //! @return true if the label and the string match, false otherwise. bool - operator==(const std::string label) + operator==(const std::string label) const { return getLabel() == label; } @@ -130,7 +130,7 @@ namespace DUNE //! @param[in] id integer to use for comparison. //! @return true if the entity id and the integer match, false otherwise. bool - operator==(unsigned int id) + operator==(unsigned int id) const { return getId() == id; } diff --git a/src/DUNE/Entities/EntityDataBase.hpp b/src/DUNE/Entities/EntityDataBase.hpp index eaa9f46f2f..795b17f88d 100644 --- a/src/DUNE/Entities/EntityDataBase.hpp +++ b/src/DUNE/Entities/EntityDataBase.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Entities/EntityUtils.cpp b/src/DUNE/Entities/EntityUtils.cpp index 01d57b501a..df92ccf62a 100644 --- a/src/DUNE/Entities/EntityUtils.cpp +++ b/src/DUNE/Entities/EntityUtils.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Entities/EntityUtils.hpp b/src/DUNE/Entities/EntityUtils.hpp index 98b6c5870d..c7c3517036 100644 --- a/src/DUNE/Entities/EntityUtils.hpp +++ b/src/DUNE/Entities/EntityUtils.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Entities/StatefulEntity.cpp b/src/DUNE/Entities/StatefulEntity.cpp index 323004b503..d4d29c785b 100644 --- a/src/DUNE/Entities/StatefulEntity.cpp +++ b/src/DUNE/Entities/StatefulEntity.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -77,7 +77,7 @@ namespace DUNE dispatch(m_act_state); } - void + bool StatefulEntity::requestActivation(void) { if (m_act_state.state != IMC::EntityActivationState::EAS_INACTIVE) @@ -99,15 +99,16 @@ namespace DUNE } dispatch(m_act_state); - return; + return false; } m_next_act_state = NAS_SAME; m_act_state.state = IMC::EntityActivationState::EAS_ACT_IP; dispatch(m_act_state); + return true; } - void + bool StatefulEntity::requestDeactivation(void) { if (m_act_state.state != IMC::EntityActivationState::EAS_ACTIVE) @@ -129,12 +130,13 @@ namespace DUNE } dispatch(m_act_state); - return; + return false; } m_next_act_state = NAS_SAME; m_act_state.state = IMC::EntityActivationState::EAS_DEACT_IP; dispatch(m_act_state); + return true; } void diff --git a/src/DUNE/Entities/StatefulEntity.hpp b/src/DUNE/Entities/StatefulEntity.hpp index 44154bbe10..1f31e73e16 100644 --- a/src/DUNE/Entities/StatefulEntity.hpp +++ b/src/DUNE/Entities/StatefulEntity.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -142,11 +142,11 @@ namespace DUNE } //! Request entity activation - void + bool requestActivation(void); //! Request entity deactivation - void + bool requestDeactivation(void); //! Mark the activation as unsuccessful. diff --git a/src/DUNE/Exceptions.hpp b/src/DUNE/Exceptions.hpp index b82ed66ba7..e50650c081 100644 --- a/src/DUNE/Exceptions.hpp +++ b/src/DUNE/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/FileSystem.hpp b/src/DUNE/FileSystem.hpp index 6167cddd59..684902af19 100644 --- a/src/DUNE/FileSystem.hpp +++ b/src/DUNE/FileSystem.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/FileSystem/Directory.cpp b/src/DUNE/FileSystem/Directory.cpp index 88db915e98..983a5f5638 100644 --- a/src/DUNE/FileSystem/Directory.cpp +++ b/src/DUNE/FileSystem/Directory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/FileSystem/Directory.hpp b/src/DUNE/FileSystem/Directory.hpp index d32a836589..348c9ef50c 100644 --- a/src/DUNE/FileSystem/Directory.hpp +++ b/src/DUNE/FileSystem/Directory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/FileSystem/Exceptions.hpp b/src/DUNE/FileSystem/Exceptions.hpp index 855228e002..de3e1b56b2 100644 --- a/src/DUNE/FileSystem/Exceptions.hpp +++ b/src/DUNE/FileSystem/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/FileSystem/FileLock.hpp b/src/DUNE/FileSystem/FileLock.hpp index 9350ea2fc9..9b684da8d9 100644 --- a/src/DUNE/FileSystem/FileLock.hpp +++ b/src/DUNE/FileSystem/FileLock.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/FileSystem/Path.cpp b/src/DUNE/FileSystem/Path.cpp index 92b279539b..4bd019fb8c 100644 --- a/src/DUNE/FileSystem/Path.cpp +++ b/src/DUNE/FileSystem/Path.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/FileSystem/Path.hpp b/src/DUNE/FileSystem/Path.hpp index db97f8cb46..699e8bb962 100644 --- a/src/DUNE/FileSystem/Path.hpp +++ b/src/DUNE/FileSystem/Path.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware.hpp b/src/DUNE/Hardware.hpp index e690999c62..575ba939c3 100644 --- a/src/DUNE/Hardware.hpp +++ b/src/DUNE/Hardware.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -55,5 +55,7 @@ namespace DUNE #include #include #include +#include +#include #endif diff --git a/src/DUNE/Hardware/BasicDeviceDriver.cpp b/src/DUNE/Hardware/BasicDeviceDriver.cpp index 25443c6d5e..1266164bfe 100644 --- a/src/DUNE/Hardware/BasicDeviceDriver.cpp +++ b/src/DUNE/Hardware/BasicDeviceDriver.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * @@ -39,15 +39,24 @@ namespace DUNE { using DUNE_NAMESPACES; - BasicDeviceDriver::BasicDeviceDriver(const std::string& name, Tasks::Context& ctx): - Tasks::Task(name, ctx), - m_sm_state(SM_IDLE), - m_log_opened(false), - m_log_name_pending(false), - m_post_power_on_delay(0.0), - m_power_off_delay(0.0), - m_fault_count(0), - m_timeout_count(0) + //! Log file prefix. + static const char *c_log_prefix = "Data_"; + + BasicDeviceDriver::BasicDeviceDriver( const std::string &name, Tasks::Context &ctx ) : + Tasks::Task(name, ctx), + m_sm_state(SM_IDLE), + m_wait_msg_timeout(0.0), + m_log_opened(false), + m_log_name_pending(false), + m_post_power_on_delay(0.0), + m_power_on_delay(0.0), + m_power_off_delay(0.0), + m_fault_count(0), + m_timeout_count(0), + m_restart(false), + m_restart_delay(0.0), + m_read_period(0.0), + m_uri() { bind(this); bind(this); @@ -65,6 +74,71 @@ namespace DUNE BasicDeviceDriver::onResourceInitialization(void) { setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + + if (getActivationTime() == 0.0) + war("Activation Time set to 0.0! Please set a positive time."); + } + + IO::Handle * + BasicDeviceDriver::openDeviceHandle(const std::string &device) + { + IO::Handle *handle = openSocketTCP(device); + if (handle == nullptr) + handle = openUART(device); + + if (handle != nullptr) + handle->flush(); + + return handle; + } + + IO::Handle * + BasicDeviceDriver::openUART(const std::string &device) + { + char uart[128] = {0}; + unsigned baud = 0; + + // Save device URI + m_uri = device; + trace("[UART] >> attempting URI: %s", device.c_str()); + + if (std::sscanf(device.c_str(), "uart://%[^:]:%u", uart, &baud) != 2) + return nullptr; + + return new SerialPort(uart, baud); + } + + IO::Handle * + BasicDeviceDriver::openSocketTCP(const std::string &device) + { + char addr[128] = {0}; + unsigned port = 0; + + // Save device URI + m_uri = device; + trace("[TCP] >> attempting URI: %s", device.c_str()); + + if (std::sscanf(device.c_str(), "tcp://%[^:]:%u", addr, &port) != 2) + return nullptr; + + TCPSocket *sock = nullptr; + + try + { + sock = new TCPSocket(); + sock->setKeepAlive(true); + sock->setNoDelay(true); + sock->setSendTimeout(1.0); + sock->setReceiveTimeout(1.0); + sock->connect(addr, port); + } + catch (...) + { + Memory::clear(sock); + throw; + } + + return sock; } void @@ -100,6 +174,9 @@ namespace DUNE void BasicDeviceDriver::onRequestActivation(void) { + debug("activating"); + if (getEntityState() <= IMC::EntityState::ESTA_NORMAL) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVATING); queueState(SM_ACT_BEGIN); } @@ -107,19 +184,46 @@ namespace DUNE BasicDeviceDriver::connect(void) { Counter timer(1.0); + bool rv = false; try { trace("connecting..."); - return onConnect(); + rv = onConnect(); } catch (...) { double delay = timer.getRemaining(); if (delay > 0.0) Delay::wait(delay); + + return false; } - return false; + if (rv) + trace("connected"); + + return rv; + } + + bool + BasicDeviceDriver::synchronize(void) + { + bool rv = false; + try + { + trace("synchronizing..."); + rv = onSynchronize(); + } + catch(const std::runtime_error& e) + { + err("synchronization failure: %s", e.what()); + return false; + } + + if (rv) + trace("synchronized"); + + return rv; } void @@ -127,27 +231,54 @@ namespace DUNE { activationFailed(message); turnPowerOff(); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + err("%s", message.c_str()); + setEntityState(IMC::EntityState::ESTA_FAILURE, message); + } + + void + BasicDeviceDriver::restart(void) + { + m_restart_timer.setTop(m_restart_delay); + queueState(SM_RESTART_WAIT); + } + + void + BasicDeviceDriver::requestRestart() + { + m_restart = true; + if (getCurrentState() >= SM_ACT_DONE) + requestDeactivation(); + else + restart(); } void BasicDeviceDriver::onRequestDeactivation(void) { + setEntityState(getEntityState(), Status::CODE_DEACTIVATING); + debug("deactivating"); queueState(SM_DEACT_BEGIN); } void BasicDeviceDriver::disconnect(void) { - debug("disconnecting"); - onDisconnect(); - debug("disconnected"); + trace("disconnecting..."); + try + { + onDisconnect(); + trace("disconnected"); + } + catch(const std::runtime_error& e) + { + err("disconnect failure: %s", e.what()); + } } void BasicDeviceDriver::onDeactivation(void) { - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + setEntityState(getEntityState(), Status::CODE_IDLE); debug("deactivation complete"); } @@ -162,8 +293,9 @@ namespace DUNE void BasicDeviceDriver::initializeDevice(void) { - debug("initializing device"); + trace("initializing..."); onInitializeDevice(); + trace("initialized"); } //! Request the name of the current log file. @@ -173,7 +305,7 @@ namespace DUNE if (!enableLogControl()) return; - debug("requesting current log path"); + trace("requesting current log path"); IMC::LoggingControl lc; lc.op = IMC::LoggingControl::COP_REQUEST_CURRENT_NAME; dispatch(lc); @@ -183,7 +315,7 @@ namespace DUNE void BasicDeviceDriver::consume(const IMC::EstimatedState* msg) { - if (msg->getSource() != getSystemId()) + if (discardEstimatedState(msg)) return; if (!isActive()) @@ -198,6 +330,9 @@ namespace DUNE if (!enableLogControl()) return; + if (discardLoggingControl(msg)) + return; + switch (msg->op) { case IMC::LoggingControl::COP_CURRENT_NAME: @@ -244,7 +379,9 @@ namespace DUNE closeLog(); + trace("opening log file"); onOpenLog(path); + trace("log file opened"); m_log_opened = true; } @@ -258,12 +395,32 @@ namespace DUNE if (!m_log_opened) return; - debug("closing log file"); + trace("closing log file"); onCloseLog(); - debug("log file closed"); + trace("log file closed"); m_log_opened = false; } + FileSystem::Path + BasicDeviceDriver::getUnusedLogPath(const FileSystem::Path &path, const std::string &extension) + { + double now = Clock::getSinceEpoch(); + + while (true) + { + std::string log_name(c_log_prefix); + log_name.append(Format::getDateSafe(now) + Format::getTimeSafe(now)); + log_name.append("."); + log_name.append(extension); + + Path file_path = m_ctx.dir_log / path / log_name; + if (!file_path.exists()) + return file_path; + + now += 1.0; + } + } + //! Consume power channel state messages. //! @param[in] msg power channel state. void @@ -277,9 +434,9 @@ namespace DUNE bool old_state = itr->second; itr->second = (msg->state == IMC::PowerChannelState::PCS_ON); if (!old_state && itr->second) - debug("device %s is powered", msg->name.c_str()); + trace("device %s is powered", msg->name.c_str()); else if (old_state && !itr->second) - debug("device %s is no longer powered", msg->name.c_str()); + trace("device %s is no longer powered", msg->name.c_str()); } //! Power-on device. @@ -336,13 +493,37 @@ namespace DUNE { // Wait for activation. case SM_IDLE: + idle(); break; // Begin activation sequence. case SM_ACT_BEGIN: - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVATING); m_wdog.setTop(getActivationTime()); - queueState(SM_ACT_POWER_ON); + if (m_power_channels.empty()) + { + m_power_on_timer.setTop(m_post_power_on_delay); + queueState(SM_ACT_DEV_WAIT); + } + else + { + if (m_power_on_delay > 0.0) + { + m_power_on_timer.setTop(m_power_on_delay); + queueState(SM_ACT_POWER_ON_DELAY); + } + else + { + queueState(SM_ACT_POWER_ON); + } + } + break; + + // Delay before turning power on. + case SM_ACT_POWER_ON_DELAY: + if ( m_power_on_timer.overflow() ) + { + queueState( SM_ACT_POWER_ON ); + } break; // Turn power on. @@ -361,7 +542,12 @@ namespace DUNE if (m_wdog.overflow()) { - failActivation(DTR("failed to turn power on")); + std::string msg = "Activation timeout - turn power on: "; + for (auto p : m_power_channels) + if (!p.second) + msg += p.first + " "; + + failActivation(DTR(msg.c_str())); queueState(SM_IDLE); } break; @@ -370,7 +556,9 @@ namespace DUNE case SM_ACT_DEV_WAIT: if (m_wdog.overflow()) { - failActivation(DTR("failed to connect to device")); + std::string msg = "Activation timeout - connect to device: "; + msg += m_uri; + failActivation(DTR(msg.c_str())); queueState(SM_IDLE); } else if (m_power_on_timer.overflow()) @@ -385,7 +573,7 @@ namespace DUNE case SM_ACT_DEV_SYNC: if (m_wdog.overflow()) { - failActivation(DTR("failed to synchronize with device")); + failActivation(DTR("Activation timeout - synchronize with device")); queueState(SM_IDLE); } else @@ -404,7 +592,7 @@ namespace DUNE case SM_ACT_LOG_REQUEST: if (m_wdog.overflow()) { - failActivation(DTR("failed to request current log name")); + failActivation(DTR("Activation timeout - request current log name")); queueState(SM_IDLE); } else @@ -419,7 +607,7 @@ namespace DUNE case SM_ACT_LOG_WAIT: if (m_wdog.overflow()) { - failActivation(DTR("failed to retrieve current log name")); + failActivation(DTR("Activation timeout - retrieve current log name")); queueState(SM_IDLE); } else @@ -431,20 +619,34 @@ namespace DUNE // Activation procedure is complete. case SM_ACT_DONE: - activate(); + try + { + activate(); + } + catch(const std::runtime_error& e) + { + activationFailed(e.what()); // NOT calling failActivation to move into DEACT_BEGIN + requestRestart(); + break; + } + + m_read_timer.setTop(m_read_period); queueState(SM_ACT_SAMPLE); break; // Read samples. case SM_ACT_SAMPLE: - readSample(); + if (m_read_timer.overflow()) + { + m_read_timer.setTop(m_read_period); + readSample(); + } break; // Start deactivation procedure. case SM_DEACT_BEGIN: - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_DEACTIVATING); - m_wdog.setTop(getDeactivationTime()); - queueState(SM_DEACT_DISCONNECT); + m_wdog.setTop( getDeactivationTime() ); + queueState( SM_DEACT_DISCONNECT ); break; // Gracefully disconnect from device. @@ -454,9 +656,16 @@ namespace DUNE if (enableLogControl()) closeLog(); - m_power_off_timer.setTop(m_power_off_delay); + if (m_power_channels.empty()) + { + queueState(SM_DEACT_DONE); + } + else + { + m_power_off_timer.setTop(m_power_off_delay); + queueState(SM_DEACT_POWER_OFF); + } - queueState(SM_DEACT_POWER_OFF); break; // Turn power off. @@ -476,20 +685,29 @@ namespace DUNE // Deactivation is complete. case SM_DEACT_DONE: - deactivate(); - queueState(SM_IDLE); - break; - } - } + try + { + deactivate(); + } + catch (const std::runtime_error& e) + { + err("failed deactivation: %s", e.what()); + } - bool - BasicDeviceDriver::synchronize(void) - { - bool rv = onSynchronize(); - if (rv) - debug("device is synchronized"); + if (m_restart) + restart(); + else + queueState(SM_IDLE); + break; - return rv; + case SM_RESTART_WAIT: + if (m_restart_timer.overflow()) + { + m_restart = false; + requestActivation(); + } + break; + } } bool @@ -523,24 +741,48 @@ namespace DUNE } void - BasicDeviceDriver::onMain(void) + BasicDeviceDriver::wait(double duration) { - while (!stopping()) + Counter wdog(duration); + while (!wdog.overflow()) { - if (isActive()) - consumeMessages(); - else if (hasQueuedStates()) - updateStateMachine(); - else - waitForMessages(1.0); + double delay = wdog.getRemaining(); + if (delay <= 0) + break; + + waitForMessages(delay); + } + } + + void + BasicDeviceDriver::step() + { + if (!isActive()) + waitForMessages(1.0); + else if (m_read_period > 0.0) + waitForMessages(m_read_timer.getRemaining()); + else if (m_wait_msg_timeout > 0.0) + waitForMessages(m_wait_msg_timeout); + else + consumeMessages(); + + updateStateMachine(); + } + void + BasicDeviceDriver::onMain() + { + while (!stopping()) + { try { - updateStateMachine(); + step(); } - catch (std::runtime_error& e) + catch (std::runtime_error &e) { - throw RestartNeeded(e.what(), 5); + war("%s", e.what()); + setEntityState(IMC::EntityState::ESTA_ERROR, e.what()); + requestRestart(); } } } diff --git a/src/DUNE/Hardware/BasicDeviceDriver.hpp b/src/DUNE/Hardware/BasicDeviceDriver.hpp index 47e32be47c..9f3f125e80 100644 --- a/src/DUNE/Hardware/BasicDeviceDriver.hpp +++ b/src/DUNE/Hardware/BasicDeviceDriver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * @@ -67,6 +67,41 @@ namespace DUNE consume(const IMC::PowerChannelState* msg); protected: + //! Create an I/O handle given an URI. + //! + //! @param[in] uri URI. + //! + //! @return I/O handle. + IO::Handle* + openDeviceHandle(const std::string& uri); + + //! Create an I/O handle given a serial port URI. + //! + //! @param[in] uri URI of the form: uart://DEVICE:BAUD + //! + //! @return I/O handle. + IO::Handle* + openUART(const std::string& uri); + + //! Create an I/O handle given a TCP port URI. + //! + //! @param[in] uri URI of the form: tcp://HOST:PORT + //! + //! @return I/O handle. + IO::Handle* + openSocketTCP(const std::string& uri); + + //! Set the amount of time to wait before powering up the device. + //! @param[in] value delay in second. + void + setPowerOnDelay(double value) + { + if (value < 0) + value = 0; + + m_power_on_delay = value; + } + //! Set the amount of time to wait before powering down the device. //! @param[in] value delay in second. void @@ -98,9 +133,14 @@ namespace DUNE void addPowerChannelName(const std::string& name) { - m_power_channels.insert(std::make_pair(name, false)); + if (!name.empty()) + m_power_channels.insert(std::make_pair(name, false)); } + virtual void + onIdle(void) + { } + virtual bool onConnect(void) = 0; @@ -131,9 +171,32 @@ namespace DUNE virtual void onCloseLog(void); + FileSystem::Path + getUnusedLogPath(const FileSystem::Path& path, const std::string& extension); + virtual void onInitializeDevice(void) = 0; + //! Test if the estimated state message should be discarded. + //! @param[in] msg estimated state message. + //! @return true to discard message, false otherwise. + virtual bool + discardEstimatedState(const IMC::EstimatedState* msg) + { + return msg->getSource() != getSystemId(); + } + + //! Test if the logging control message should be discarded. + //! @param[in] msg logging control message. + //! @return true to discard message, false otherwise. + virtual bool + discardLoggingControl(const IMC::LoggingControl* msg) + { + (void)msg; + + return false; + } + void clearFaultCount(void) { @@ -146,6 +209,47 @@ namespace DUNE m_timeout_count = 0; } + //! Suspend execution for a given amount of time while only consume + //! messages. + //! + //! @param[in] duration amount of time to wait in second. + void + wait(double duration); + + void + setRestartDelay(double seconds) + { + m_restart_delay = seconds; + } + + // Set state machine to restart + void + restart(void); + + // Request a restart + void + requestRestart(); + + //! Set the data read period. + //! @param[in] freq polling frequency, in hertz. + void + setReadFrequency(double freq) + { + m_read_period = freq > 0.0 ? 1.0/freq : 0.0; + } + + //! If set, task uses waitForMessages with specified timeout + //! insted of consumeMessages. + //! @param[in] timeout waitForMessages timeout. + void + setWaitForMessages(double timeout) + { + if (timeout < 0.0) + return; + + m_wait_msg_timeout = timeout; + } + private: //! Finite state machine states. enum StateMachineStates @@ -154,6 +258,8 @@ namespace DUNE SM_IDLE, //! Start activation sequence. SM_ACT_BEGIN, + //! Delay before turning power on. + SM_ACT_POWER_ON_DELAY, //! Turn power on. SM_ACT_POWER_ON, //! Wait for power to be turned on. @@ -179,7 +285,9 @@ namespace DUNE //! Wait for power to be turned off. SM_DEACT_POWER_WAIT, //! Deactivation sequence is complete. - SM_DEACT_DONE + SM_DEACT_DONE, + //! Wait for restart delay. + SM_RESTART_WAIT }; //! Watchdog timer. @@ -188,6 +296,8 @@ namespace DUNE StateMachineStates m_sm_state; //! State machine state queue. std::queue m_sm_state_queue; + //! Timeout used when forcing waitForMessage. + double m_wait_msg_timeout; //! Power channel names and states. std::map m_power_channels; //! True if log is opened. @@ -200,18 +310,32 @@ namespace DUNE double m_post_power_on_delay; //! Power-off timer. DUNE::Time::Counter m_power_off_timer; + //! Power-on delay. + double m_power_on_delay; //! Power-off delay. double m_power_off_delay; //! Fault count. unsigned m_fault_count; //! Timeout count. unsigned m_timeout_count; + //! True to restart activation when idle. + bool m_restart; + //! Restart delay in seconds. + double m_restart_delay; + //! Restart timer. + DUNE::Time::Counter m_restart_timer; + //! Data read period in seconds. + double m_read_period; + //! Data read timer. + DUNE::Time::Counter m_read_timer; + //! Device URI. + std::string m_uri; void - onResourceRelease(void); + onResourceRelease(void) override; void - onResourceInitialization(void); + onResourceInitialization(void) override; //! Push a new state to the state queue. //! @param[in] state state machine state. @@ -233,11 +357,17 @@ namespace DUNE StateMachineStates dequeueState(void); + void + idle(void) + { + onIdle(); + } + void initializeDevice(void); void - onRequestActivation(void); + onRequestActivation(void) override; bool connect(void); @@ -246,16 +376,16 @@ namespace DUNE failActivation(const std::string& message); void - onRequestDeactivation(void); + onRequestDeactivation(void) override; void disconnect(void); void - onDeactivation(void); + onDeactivation(void) override; void - onActivation(void); + onActivation(void) override; //! Request the name of the current log file. void @@ -297,7 +427,10 @@ namespace DUNE updateStateMachine(void); void - onMain(void); + step(void); + + void + onMain(void) override; }; } } diff --git a/src/DUNE/Hardware/BasicModem.cpp b/src/DUNE/Hardware/BasicModem.cpp index 02d6870656..f07ddd0cb5 100644 --- a/src/DUNE/Hardware/BasicModem.cpp +++ b/src/DUNE/Hardware/BasicModem.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -27,16 +27,19 @@ // Author: Ricardo Martins * //*************************************************************************** +// ISO C++ headers. +#include + // DUNE headers. #include -#include -#include +#include +#include +#include #include #include #include -#include -#include -#include +#include +#include namespace DUNE { @@ -114,8 +117,6 @@ namespace DUNE m_line_trim = enable; } - //! Test if ISU is busy performing an SBD session. - //! @return true if ISU is busy, false otherwise. bool BasicModem::isBusy(void) { @@ -127,13 +128,13 @@ namespace DUNE BasicModem::setBusy(bool value) { Concurrency::ScopedMutex l(m_mutex); + if (m_busy != value) + getTask()->debug("modem %s", value ? "busy" : "idle"); m_busy = value; if (m_busy && (m_tx_rate_max >= 0)) m_tx_rate_timer.reset(); } - //! Test if ISU is cooling down. - //! @return true if ISU is cooling down, false otherwise. bool BasicModem::isCooling(void) { @@ -172,6 +173,37 @@ namespace DUNE { Concurrency::ScopedMutex l(m_mutex); m_read_mode = mode; + if (mode == READ_MODE_LINE) { + if (m_bytes.size() > 0) { // if have bytes in queue, transfer to lines + getTask()->spew( + "There are %d bytes in the queue bytes. Convert to queue of lines.", + m_bytes.size()); + while (m_bytes.size() > 0) { + uint8_t byte = 0; + m_bytes.pop(byte); + m_chars.push(byte); + } + std::string line = ""; + while (!m_chars.empty()) { + if (!processInput(line)) + continue; + + if (line.empty()) + continue; + + if (!handleUnsolicited(line)) { + m_lines.push(line); + line = ""; + } + } + } + } else { + if (m_lines.size()) { + getTask()->err( + "There are %d lines in the queue. Convert to queue of bytes.", + m_lines.size()); + } + } } void @@ -183,6 +215,11 @@ namespace DUNE void BasicModem::send(const std::string& str) { + IMC::DevDataText txt; + txt.value = str; + txt.setDestination(getTask()->getSystemId()); + getTask()->dispatch(txt); + getTask()->trace("send: %s", Streams::sanitize(str).c_str()); sendRaw((uint8_t*)str.c_str(), str.size()); } @@ -221,10 +258,12 @@ namespace DUNE { unsigned bytes_read = 0; - while (!timer.overflow()) - { - if (m_bytes.waitForItems(timer.getRemaining())) - data[bytes_read++] = m_bytes.pop(); + while (!timer.overflow()) { + if (m_bytes.waitForItems(timer.getRemaining())) { + uint8_t byte = 0; + if (m_bytes.pop(byte)) + data[bytes_read++] = byte; + } if (bytes_read == data_size) return; @@ -243,7 +282,7 @@ namespace DUNE char c = m_chars.front(); m_chars.pop(); - m_line.push_back(c); + m_line.push_back(c); //!@fixme: concurrency hazard. if (c == m_line_term_in[m_line_term_idx]) @@ -256,10 +295,6 @@ namespace DUNE break; } } - else - { - - } } if (isFragment(m_line)) @@ -345,10 +380,8 @@ namespace DUNE try { rv = m_handle->read(bfr, sizeof(bfr)); - } - catch (...) - { - m_task->war("%s", Status::getString(Status::CODE_IO_ERROR)); + } catch (std::runtime_error &e) { + m_task->war("%s: %s", Status::getString(Status::CODE_IO_ERROR), e.what()); break; } diff --git a/src/DUNE/Hardware/BasicModem.hpp b/src/DUNE/Hardware/BasicModem.hpp index 4a23bb6149..0ccd5a3a0a 100644 --- a/src/DUNE/Hardware/BasicModem.hpp +++ b/src/DUNE/Hardware/BasicModem.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -30,8 +30,9 @@ #ifndef DUNE_HARDWARE_BASIC_MODEM_HPP_INCLUDED_ #define DUNE_HARDWARE_BASIC_MODEM_HPP_INCLUDED_ -// ISO C++ 98 headers. +// ISO C++ headers. #include +#include // DUNE headers. #include @@ -226,7 +227,7 @@ namespace DUNE processInput(std::string& str); void - run(void); + run() override; }; } } diff --git a/src/DUNE/Hardware/Buttons.cpp b/src/DUNE/Hardware/Buttons.cpp index 188c6597f7..dd76f8aee5 100644 --- a/src/DUNE/Hardware/Buttons.cpp +++ b/src/DUNE/Hardware/Buttons.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/Buttons.hpp b/src/DUNE/Hardware/Buttons.hpp index 37f19ef144..0ec51fa1fa 100644 --- a/src/DUNE/Hardware/Buttons.hpp +++ b/src/DUNE/Hardware/Buttons.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/ESCC.cpp b/src/DUNE/Hardware/ESCC.cpp index d998c761bd..055141649a 100644 --- a/src/DUNE/Hardware/ESCC.cpp +++ b/src/DUNE/Hardware/ESCC.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/ESCC.hpp b/src/DUNE/Hardware/ESCC.hpp index b7c5bd5d1a..cab1cb8533 100644 --- a/src/DUNE/Hardware/ESCC.hpp +++ b/src/DUNE/Hardware/ESCC.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/Exceptions.hpp b/src/DUNE/Hardware/Exceptions.hpp index be45308107..7cb4650439 100644 --- a/src/DUNE/Hardware/Exceptions.hpp +++ b/src/DUNE/Hardware/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/GPIO.cpp b/src/DUNE/Hardware/GPIO.cpp index 7df8fd1e98..eef89afe5c 100644 --- a/src/DUNE/Hardware/GPIO.cpp +++ b/src/DUNE/Hardware/GPIO.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/GPIO.hpp b/src/DUNE/Hardware/GPIO.hpp index e8f4fa9ab6..3cc61bfc52 100644 --- a/src/DUNE/Hardware/GPIO.hpp +++ b/src/DUNE/Hardware/GPIO.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -82,6 +82,12 @@ namespace DUNE getValue(void); private: + //! Disallow copy constructor. + GPIO(const GPIO&); + + //! Disallow copy assignment. + GPIO& operator=(const GPIO&); + //! GPIO number. unsigned int m_number; //! GPIO direction. diff --git a/src/DUNE/Hardware/HayesModem.cpp b/src/DUNE/Hardware/HayesModem.cpp index 39ebc960cf..c686a0ed91 100644 --- a/src/DUNE/Hardware/HayesModem.cpp +++ b/src/DUNE/Hardware/HayesModem.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/HayesModem.hpp b/src/DUNE/Hardware/HayesModem.hpp index 9a527799c2..e75840bd71 100644 --- a/src/DUNE/Hardware/HayesModem.hpp +++ b/src/DUNE/Hardware/HayesModem.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/I2C.cpp b/src/DUNE/Hardware/I2C.cpp index a14e0d92ae..056c77dd43 100644 --- a/src/DUNE/Hardware/I2C.cpp +++ b/src/DUNE/Hardware/I2C.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/I2C.hpp b/src/DUNE/Hardware/I2C.hpp index 3270a8b686..442f5eebbd 100644 --- a/src/DUNE/Hardware/I2C.hpp +++ b/src/DUNE/Hardware/I2C.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/IOPort.cpp b/src/DUNE/Hardware/IOPort.cpp index ff3725c3a2..dcc74b22b6 100644 --- a/src/DUNE/Hardware/IOPort.cpp +++ b/src/DUNE/Hardware/IOPort.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/IOPort.hpp b/src/DUNE/Hardware/IOPort.hpp index 64d79b0e53..f30a3650af 100644 --- a/src/DUNE/Hardware/IOPort.hpp +++ b/src/DUNE/Hardware/IOPort.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/IntelHEX.cpp b/src/DUNE/Hardware/IntelHEX.cpp index 126e96082c..8b8549279f 100644 --- a/src/DUNE/Hardware/IntelHEX.cpp +++ b/src/DUNE/Hardware/IntelHEX.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/IntelHEX.hpp b/src/DUNE/Hardware/IntelHEX.hpp index acd0f9b922..73e9ebea2f 100644 --- a/src/DUNE/Hardware/IntelHEX.hpp +++ b/src/DUNE/Hardware/IntelHEX.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/LUCL/BootLoader.cpp b/src/DUNE/Hardware/LUCL/BootLoader.cpp index 9e54f091b3..bb6f99a99e 100644 --- a/src/DUNE/Hardware/LUCL/BootLoader.cpp +++ b/src/DUNE/Hardware/LUCL/BootLoader.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/LUCL/BootLoader.hpp b/src/DUNE/Hardware/LUCL/BootLoader.hpp index 665ecf1031..c56cfa6c16 100644 --- a/src/DUNE/Hardware/LUCL/BootLoader.hpp +++ b/src/DUNE/Hardware/LUCL/BootLoader.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/LUCL/Command.hpp b/src/DUNE/Hardware/LUCL/Command.hpp index 473a62cf48..602db0eab2 100644 --- a/src/DUNE/Hardware/LUCL/Command.hpp +++ b/src/DUNE/Hardware/LUCL/Command.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/LUCL/CommandType.hpp b/src/DUNE/Hardware/LUCL/CommandType.hpp index 3273f4e994..1d9bfa8658 100644 --- a/src/DUNE/Hardware/LUCL/CommandType.hpp +++ b/src/DUNE/Hardware/LUCL/CommandType.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/LUCL/Protocol.cpp b/src/DUNE/Hardware/LUCL/Protocol.cpp index 8056f9f1e6..16ebcc5680 100644 --- a/src/DUNE/Hardware/LUCL/Protocol.cpp +++ b/src/DUNE/Hardware/LUCL/Protocol.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/LUCL/Protocol.hpp b/src/DUNE/Hardware/LUCL/Protocol.hpp index 4e9d1243d6..9dc7fb9db9 100644 --- a/src/DUNE/Hardware/LUCL/Protocol.hpp +++ b/src/DUNE/Hardware/LUCL/Protocol.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/LUCL/ProtocolParser.hpp b/src/DUNE/Hardware/LUCL/ProtocolParser.hpp index 11830d7d96..23dbab3429 100644 --- a/src/DUNE/Hardware/LUCL/ProtocolParser.hpp +++ b/src/DUNE/Hardware/LUCL/ProtocolParser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/PWM.cpp b/src/DUNE/Hardware/PWM.cpp new file mode 100644 index 0000000000..5b2b85f4f3 --- /dev/null +++ b/src/DUNE/Hardware/PWM.cpp @@ -0,0 +1,183 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Kristoffer Gryte * +//*************************************************************************** + +#include +#include + +#include +#include +#include + +#include + +namespace DUNE +{ + namespace Hardware + { + using DUNE::System::Error; + using DUNE::Utils::String; + + PWM::PWM() + { + PWM(0); + } + + PWM::PWM(const unsigned pwm_number) + { + PWM(pwm_number, "/sys/class/pwm/pwmchip0/"); + } + + PWM::PWM(const unsigned pwm_number, const std::string& chip_path): + m_pwm_number(pwm_number), + m_chip_path(chip_path) + { +# if defined(DUNE_OS_LINUX) + writeToFile(m_chip_path + "export", m_pwm_number); + + const std::string prefix = m_chip_path + "pwm" + String::str(m_pwm_number); + m_file_duty_cycle_path = prefix + "/duty_cycle"; + m_file_period_path = prefix + "/period"; + m_file_enable_path = prefix + "/enable"; + + enable(); +# else + throw Error("unimplemented feature", "DUNE::Hardware::PWM"); +# endif + } + + PWM::~PWM() + { +# if defined(DUNE_OS_LINUX) + try + { + writeToFile(m_chip_path + "unexport", m_pwm_number); + } + catch (std::exception& e) + { + DUNE_ERR("DUNE::Hardware::PWM", e.what()); + } +# endif + } + + void + PWM::setFrequency(const float frequency_hertz) + { + const float period_seconds = 1 / frequency_hertz; + setPeriod(period_seconds); + } + + void + PWM::setPeriod(const float period_seconds) + { + const unsigned period_nanoseconds = period_seconds * 1e9; + setPeriod(period_nanoseconds); + } + + void + PWM::setPeriod(const unsigned period_nanoseconds) + { +# if defined(DUNE_OS_LINUX) + writeToFile(m_file_period_path, period_nanoseconds); +# endif + m_period_nanoseconds = period_nanoseconds; + } + + void + PWM::setDutyCyclePercentage(const float duty_cycle_percentage) + { + const float duty_cycle_normalized = duty_cycle_percentage * 0.01; + setDutyCycleNormalized(duty_cycle_normalized); + } + + void + PWM::setDutyCycleNormalized(const float duty_cycle_normalized) + { + const unsigned pulse_width_nanoseconds = m_period_nanoseconds * duty_cycle_normalized; + setPulseWidth(pulse_width_nanoseconds); + } + + void + PWM::setPulseWidth(const float pulse_width_seconds) + { + const unsigned pulse_width_nanoseconds = pulse_width_seconds * 1e9; + setPulseWidth(pulse_width_nanoseconds); + } + + void + PWM::setPulseWidth(unsigned pulse_width_nanoseconds) + { + if (pulse_width_nanoseconds > m_period_nanoseconds) + pulse_width_nanoseconds = m_period_nanoseconds; + +# if defined(DUNE_OS_LINUX) + writeToFile(m_file_duty_cycle_path, pulse_width_nanoseconds); +# else + throw Error("unimplemented feature", "DUNE::Hardware::PWM"); +# endif + } + + void + PWM::enable() + { +# if defined(DUNE_OS_LINUX) + writeToFile(m_file_enable_path, 1); +# else + throw Error("unimplemented feature", "DUNE::Hardware::PWM"); +# endif + } + + void + PWM::disable() + { +# if defined(DUNE_OS_LINUX) + writeToFile(m_file_enable_path, 0); +# else + throw Error("unimplemented feature", "DUNE::Hardware::PWM"); +# endif + } + +# if defined(DUNE_OS_LINUX) + void + PWM::writeToFile(const std::string& file, unsigned value) + { + writeToFile(file, String::str(value)); + } + + void + PWM::writeToFile(const std::string& file, const std::string& value) + { + std::FILE* fd = std::fopen(file.c_str(), "w"); + if (fd == 0) + throw Error(errno, "unable to export PWM " + file, value); + std::fputs(value.c_str(), fd); + std::fclose(fd); + } +# endif + } +} diff --git a/src/DUNE/Hardware/PWM.hpp b/src/DUNE/Hardware/PWM.hpp new file mode 100644 index 0000000000..6ced971054 --- /dev/null +++ b/src/DUNE/Hardware/PWM.hpp @@ -0,0 +1,80 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Kristoffer Gryte * +//*************************************************************************** + +#ifndef DUNE_HARDWARE_PWM_HPP_INCLUDED_ +#define DUNE_HARDWARE_PWM_HPP_INCLUDED_ + +#include + +namespace DUNE +{ + namespace Hardware + { + class DUNE_DLL_SYM PWM; + + class PWM + { + public: + PWM(); + PWM(unsigned pwm_number); + PWM(unsigned pwm_number, const std::string& chip_path); + ~PWM(); + + // You'll only need one of these + void setFrequency(float frequency_hertz); + void setPeriod(float period_seconds); + + void setDutyCyclePercentage(float duty_cycle_percentage); + void setDutyCycleNormalized(float duty_cycle_normalized); + void setPulseWidth(float pulse_width_seconds); + + void enable(); + void disable(); + + private: + unsigned m_pwm_number; + std::string m_chip_path; + unsigned m_period_nanoseconds; + + void setPeriod(unsigned period_nanoseconds); + void setPulseWidth(unsigned active_time_nanoseconds); + +# if defined(DUNE_OS_LINUX) + std::string m_file_duty_cycle_path; + std::string m_file_period_path; + std::string m_file_enable_path; + + static void writeToFile(const std::string& file, unsigned value); + static void writeToFile(const std::string& file, const std::string& value); +# endif + }; + } +} + +#endif diff --git a/src/DUNE/Hardware/SerialPort.cpp b/src/DUNE/Hardware/SerialPort.cpp index 651dc2ebba..e312b36fbd 100644 --- a/src/DUNE/Hardware/SerialPort.cpp +++ b/src/DUNE/Hardware/SerialPort.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -96,6 +96,9 @@ static std::pair brate_pairs[] = # if defined(B921600) , std::pair(921600, B921600) # endif +# if defined(B1000000) + , std::pair(1000000, B1000000) +# endif # if defined(B3000000) , std::pair(3000000, B3000000) # endif @@ -185,10 +188,17 @@ namespace DUNE return devs; } - SerialPort::SerialPort(const std::string& device, int baudrate, Parity parity, StopBits stopbits, DataBits databits, bool block) + SerialPort::SerialPort(const std::string& device, int baudrate, Parity parity, StopBits stopbits, DataBits databits, bool block, bool readonly) { #if defined(DUNE_OS_POSIX) - m_handle = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); + if(readonly) + { + m_handle = open(device.c_str(), O_RDONLY | O_NOCTTY | O_NONBLOCK); + } + else + { + m_handle = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); + } if (m_handle == -1) { diff --git a/src/DUNE/Hardware/SerialPort.hpp b/src/DUNE/Hardware/SerialPort.hpp index 63ba519e10..5a9a90c426 100644 --- a/src/DUNE/Hardware/SerialPort.hpp +++ b/src/DUNE/Hardware/SerialPort.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -127,7 +127,7 @@ namespace DUNE //! @param databits number of data bits. //! @param block false enable non-blocking I/O. //! @throw SerialPortError. - SerialPort(const std::string& device, int baudrate = 38400, Parity parity = SP_PARITY_NONE, StopBits stopbits = SP_STOPBITS_1, DataBits databits = SP_DATABITS_8, bool block = false); + SerialPort(const std::string& device, int baudrate = 38400, Parity parity = SP_PARITY_NONE, StopBits stopbits = SP_STOPBITS_1, DataBits databits = SP_DATABITS_8, bool block = false, bool readonly = false); //! Serial port destructor. ~SerialPort(void); diff --git a/src/DUNE/Hardware/SocketCAN.cpp b/src/DUNE/Hardware/SocketCAN.cpp new file mode 100644 index 0000000000..13aa3b7545 --- /dev/null +++ b/src/DUNE/Hardware/SocketCAN.cpp @@ -0,0 +1,235 @@ +//*************************************************************************** +// Copyright 2007-2020 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Nikolai Lauvås (NTNU, Department of Engineering Cybernetics) * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include +#include +#include +#include + +// DUNE headers. +#include +#include + +#if defined(DUNE_OS_LINUX) +// CAN interface haders. +#include +#include +#include +#include + +#include + +#include +#include +#include +#else + throw Error("unimplemented feature", "DUNE::Hardware::SocketCAN"); +#endif + +#define CAN_SFF_MASK 0x000007FFU // standard frame format (SFF) +#define CAN_EFF_MASK 0x1FFFFFFFU // extended frame format (EFF) + +namespace DUNE +{ + namespace Hardware + { +#if defined(DUNE_OS_LINUX) + SocketCAN::SocketCAN(const std::string& can_dev, can_frame_t frame_type) + { + can_frame_type = frame_type; + m_can_socket = ::socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (m_can_socket < 0) { + throw Error("Error while opening socket for CANbus", System::Error::getLastMessage()); //TODO: Check + } + + int enable, rc; + switch(can_frame_type) { + case CAN_BASIC_SFF: + break; + case CAN_BASIC_EFF: + break; + case CAN_FD: + enable = 1; + rc = ::setsockopt(m_can_socket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable, sizeof (enable)); + if (rc == -1) + throw Error("Failed to enable FD frames", System::Error::getLastMessage()); //TODO: Check + break; + default: + throw Error("Frame type not recognized", System::Error::getLastMessage()); + } + + std::strncpy(m_ifr.ifr_name, can_dev.c_str(), IFNAMSIZ); + + + if(::ioctl(m_can_socket, SIOCGIFFLAGS, &m_ifr) < 0) { + throw Error("Could not read SIOCGIFFLAGS with ioctl", System::Error::getLastMessage()); + } + if ( !(m_ifr.ifr_flags & IFF_UP) ) { + throw Error("CAN network is down", System::Error::getLastMessage()); + } + + // Get the index of the network interface + if (::ioctl(m_can_socket, SIOCGIFINDEX, &m_ifr) == -1) + throw Error("Coult not get interface index with ioctl", System::Error::getLastMessage()); + + // Bind the socket to the network interface + m_addr.can_family = AF_CAN; + m_addr.can_ifindex = m_ifr.ifr_ifindex; + rc = ::bind(m_can_socket, reinterpret_cast (&m_addr), sizeof (m_addr)); + + if (rc == -1) + throw Error("Could not bind CAN socket", System::Error::getLastMessage()); //TODO: Check + } + + //! Serial port destructor. + SocketCAN::~SocketCAN(void) + { + if (::close(m_can_socket) == -1) + throw Error("Could not close CAN port", System::Error::getLastMessage()); //TODO: Check + } + + void SocketCAN::setTXID(uint32_t id) { + cantxid = id | CAN_EFF_FLAG; // TODO: Check if similar for SFF(CAN_SFF_FLAG does not exist) + } + uint32_t SocketCAN::getRXID() { + switch(can_frame_type) { + case CAN_BASIC_SFF: + return canrxid & CAN_SFF_MASK; // TODO: Check for SFF + break; + case CAN_BASIC_EFF: + return canrxid & CAN_EFF_MASK; + break; + case CAN_FD: + return canrxid & CAN_EFF_MASK; + break; + default: + throw Error("Frame type not recognized", System::Error::getLastMessage()); + } + return 0; + } + + size_t SocketCAN::readHexString(char* bfr, size_t length) { + size_t readSize = readString(bfr, length); + std::stringstream ss; + ss << std::internal // fill between the prefix and the number + << std::setfill('0') << std::uppercase; // fill with 0s + ss << std::hex << std::setw(8) << int(getRXID()) << "#"; + + for(size_t i=0; i < readSize; i++) { + ss << std::hex << std::setw(2) << int(bfr[i]); + } + std::string out = ss.str(); + strncpy(bfr, out.c_str(), out.length()+1); // +1 because of '\0 added in c_str' + + return out.length()+1; + } + + size_t + SocketCAN::doWrite(const uint8_t* bfr, size_t size) { // TODO: Add exceptions + int writtenBytes; + switch(can_frame_type) { + case CAN_BASIC_SFF: + case CAN_BASIC_EFF: + struct can_frame frame; + frame.can_dlc = size; + frame.can_id = cantxid; + memcpy(frame.data, bfr, size); + writtenBytes = ::write(m_can_socket, &frame, CAN_MTU); + break; + case CAN_FD: + struct canfd_frame fdframe; + fdframe.len = size; + fdframe.can_id = cantxid; + memcpy(fdframe.data, bfr, size); + writtenBytes = ::write(m_can_socket, &fdframe, CANFD_MTU); + break; + default: + throw Error("Frame type not recognized", System::Error::getLastMessage()); + } + return size; + } + + size_t + SocketCAN::doRead(uint8_t* bfr, size_t size) { //TODO: Add timeout + int numBytes; + switch(can_frame_type) { + case CAN_BASIC_EFF: + case CAN_BASIC_SFF: + struct can_frame frame; + numBytes = ::read(m_can_socket, &frame, CAN_MTU); + if(numBytes) { + for(uint8_t i=0; i +#include + +#if defined(DUNE_OS_LINUX) +#include +#include +#else + throw Error("Unimplemented feature", "DUNE::Hardware::SocketCAN"); +#endif + + +namespace DUNE +{ + namespace Hardware + { + // Export DLL Symbol. + class DUNE_DLL_SYM SocketCAN; + + //! The SocketCAN class encapsulates CAN access. + class SocketCAN: public IO::Handle + { + public: + class Error: public std::runtime_error + { + public: + Error(std::string op, std::string msg): + std::runtime_error("Socket CAN error (" + op + "): " + msg) + { } + }; +#if defined(DUNE_OS_LINUX) + enum can_frame_t { + CAN_BASIC_SFF = 0, + CAN_BASIC_EFF = 1, + CAN_FD = 2 + }; + //! SocketCAN constructor. + SocketCAN(const std::string& can_dev, can_frame_t frame_type); + + //! Socket CAN destructor. + ~SocketCAN(void); + + void setTXID(uint32_t id); + uint32_t getRXID(); + size_t readHexString(char* bfr, size_t length); + //size_t writeHexString(const char* cstr); + private: + //! CAN connection variables. + struct sockaddr_can m_addr; + struct ifreq m_ifr; + int m_can_socket; + can_frame_t can_frame_type; + uint32_t cantxid = 0; + uint32_t canrxid = 0; + + IO::NativeHandle + doGetNative(void) const + { + return m_can_socket; // Makes Poll::poll work + } + + size_t + doWrite(const uint8_t* bfr, size_t size); + + size_t + doRead(uint8_t* bfr, size_t size); + + //! Flush input buffer, discarding all of it's contents. + void + doFlushInput(void); + + //! Flush output buffer, aborting output. + void + doFlushOutput(void); + + //! Flush both input and output buffers. + void + doFlush(void); +#else + throw Error("Unimplemented feature", "DUNE::Hardware::SocketCAN"); +#endif + }; + } +} + + +#endif diff --git a/src/DUNE/Hardware/UCTK/Bootloader.cpp b/src/DUNE/Hardware/UCTK/Bootloader.cpp index b51e0c91e4..8a425740c1 100644 --- a/src/DUNE/Hardware/UCTK/Bootloader.cpp +++ b/src/DUNE/Hardware/UCTK/Bootloader.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Bootloader.hpp b/src/DUNE/Hardware/UCTK/Bootloader.hpp index 5603be453b..92e1935c2a 100644 --- a/src/DUNE/Hardware/UCTK/Bootloader.hpp +++ b/src/DUNE/Hardware/UCTK/Bootloader.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Constants.hpp b/src/DUNE/Hardware/UCTK/Constants.hpp index a4ec3bdefb..0303b5f249 100644 --- a/src/DUNE/Hardware/UCTK/Constants.hpp +++ b/src/DUNE/Hardware/UCTK/Constants.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Errors.cpp b/src/DUNE/Hardware/UCTK/Errors.cpp index 0d9ea0cd59..35903602cb 100644 --- a/src/DUNE/Hardware/UCTK/Errors.cpp +++ b/src/DUNE/Hardware/UCTK/Errors.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Errors.hpp b/src/DUNE/Hardware/UCTK/Errors.hpp index 72ce59be96..ba1e18cb43 100644 --- a/src/DUNE/Hardware/UCTK/Errors.hpp +++ b/src/DUNE/Hardware/UCTK/Errors.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/FirmwareInfo.hpp b/src/DUNE/Hardware/UCTK/FirmwareInfo.hpp index 5343adeb10..03719a8da1 100644 --- a/src/DUNE/Hardware/UCTK/FirmwareInfo.hpp +++ b/src/DUNE/Hardware/UCTK/FirmwareInfo.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Frame.hpp b/src/DUNE/Hardware/UCTK/Frame.hpp index f41af267e9..1b0a3c1ed4 100644 --- a/src/DUNE/Hardware/UCTK/Frame.hpp +++ b/src/DUNE/Hardware/UCTK/Frame.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Interface.cpp b/src/DUNE/Hardware/UCTK/Interface.cpp index 89d7552153..749379c27f 100644 --- a/src/DUNE/Hardware/UCTK/Interface.cpp +++ b/src/DUNE/Hardware/UCTK/Interface.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Interface.hpp b/src/DUNE/Hardware/UCTK/Interface.hpp index 36a0d7c179..ada703ac99 100644 --- a/src/DUNE/Hardware/UCTK/Interface.hpp +++ b/src/DUNE/Hardware/UCTK/Interface.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Hardware/UCTK/Parser.hpp b/src/DUNE/Hardware/UCTK/Parser.hpp index 391ff19b23..d5157399c8 100644 --- a/src/DUNE/Hardware/UCTK/Parser.hpp +++ b/src/DUNE/Hardware/UCTK/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/I18N.cpp b/src/DUNE/I18N.cpp index 663600467e..23bb7e14af 100644 --- a/src/DUNE/I18N.cpp +++ b/src/DUNE/I18N.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/I18N.hpp b/src/DUNE/I18N.hpp index 1c3b0668fe..32a2614778 100644 --- a/src/DUNE/I18N.hpp +++ b/src/DUNE/I18N.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC.hpp b/src/DUNE/IMC.hpp index aeb96a5e1b..f6859d3017 100644 --- a/src/DUNE/IMC.hpp +++ b/src/DUNE/IMC.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/AddressResolver.cpp b/src/DUNE/IMC/AddressResolver.cpp index 2e087eee78..da97d34898 100644 --- a/src/DUNE/IMC/AddressResolver.cpp +++ b/src/DUNE/IMC/AddressResolver.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/AddressResolver.hpp b/src/DUNE/IMC/AddressResolver.hpp index ed016b162c..b33b9d48d1 100644 --- a/src/DUNE/IMC/AddressResolver.hpp +++ b/src/DUNE/IMC/AddressResolver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Bitfields.hpp b/src/DUNE/IMC/Bitfields.hpp index 11cbab8691..fd03d09004 100644 --- a/src/DUNE/IMC/Bitfields.hpp +++ b/src/DUNE/IMC/Bitfields.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** #ifndef DUNE_IMC_BITFIELDS_HPP_INCLUDED_ diff --git a/src/DUNE/IMC/Blob.cpp b/src/DUNE/IMC/Blob.cpp index 30fdc83d3b..93674570bb 100644 --- a/src/DUNE/IMC/Blob.cpp +++ b/src/DUNE/IMC/Blob.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** // DUNE headers. @@ -41,2517 +41,2897 @@ namespace DUNE static const unsigned char c_imc_blob[] = { 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, - 0x74, 0x6d, 0x70, 0x32, 0x31, 0x4f, 0x4f, 0x68, 0x78, 0x00, - 0xed, 0xbd, 0xd9, 0x72, 0xe3, 0x48, 0x92, 0x36, 0x7a, 0xdd, - 0xf3, 0x14, 0xb0, 0x3c, 0x36, 0x76, 0xb2, 0xcc, 0x26, 0x4b, - 0xfb, 0x36, 0x36, 0x3d, 0xbf, 0x41, 0x24, 0x28, 0xf1, 0x4f, - 0x6e, 0xcd, 0x45, 0x99, 0xca, 0x1b, 0x1a, 0x44, 0x84, 0x24, - 0x4c, 0x82, 0x00, 0x0b, 0x00, 0x25, 0x51, 0x4f, 0x75, 0x6e, - 0xe6, 0x05, 0xfa, 0xc9, 0x4e, 0xac, 0x88, 0x05, 0x5b, 0x60, - 0x51, 0x66, 0x56, 0xb5, 0xaa, 0xda, 0xaa, 0x45, 0x20, 0xe0, - 0xb1, 0x79, 0x78, 0x78, 0x78, 0xb8, 0x7f, 0xfe, 0x5f, 0xff, - 0xe7, 0x65, 0xed, 0x19, 0x4f, 0x20, 0x8c, 0xdc, 0xc0, 0xff, - 0xfb, 0x87, 0x83, 0xdf, 0xf7, 0x3f, 0x18, 0xc0, 0x5f, 0x05, - 0x8e, 0xeb, 0x3f, 0xfc, 0xfd, 0xc3, 0x62, 0xde, 0xfb, 0x74, - 0xfe, 0xe1, 0xff, 0xfc, 0xf7, 0xbf, 0xfd, 0xd7, 0x1a, 0x44, - 0x91, 0xfd, 0x00, 0x22, 0x03, 0x16, 0xf7, 0xa3, 0xff, 0x7c, - 0x89, 0xdc, 0xbf, 0x7f, 0x78, 0x8c, 0xe3, 0xcd, 0x7f, 0xee, - 0xed, 0x3d, 0x3f, 0x3f, 0xff, 0xfe, 0x7c, 0xf4, 0x7b, 0x10, - 0x3e, 0xec, 0x1d, 0xee, 0xef, 0x1f, 0xec, 0x7d, 0x1d, 0x0e, - 0x66, 0xab, 0x47, 0xb0, 0xb6, 0x3f, 0xb9, 0x7e, 0x14, 0xdb, - 0xfe, 0x0a, 0x7c, 0x30, 0xbc, 0xc0, 0x7f, 0xf8, 0xe4, 0xdb, - 0x6b, 0xf0, 0xf7, 0x0f, 0x7d, 0x3f, 0x06, 0xa1, 0x31, 0x0c, - 0x9c, 0xad, 0x07, 0x8c, 0x4e, 0xb0, 0x5e, 0x6f, 0x7d, 0x77, - 0x65, 0xc7, 0xb0, 0xfa, 0x0f, 0x06, 0x2d, 0x31, 0xec, 0x7c, - 0xe0, 0x4d, 0x3a, 0xf9, 0xfd, 0xf8, 0xf7, 0x83, 0x83, 0x0f, - 0x06, 0xac, 0xf2, 0x3f, 0xfd, 0x60, 0x04, 0x4b, 0x44, 0x1b, - 0x7b, 0x05, 0x48, 0x15, 0x83, 0x80, 0x7c, 0x8a, 0x3f, 0xfa, - 0xfd, 0x25, 0x72, 0x3e, 0xfc, 0xf7, 0xbf, 0xfd, 0x9b, 0x61, - 0xfc, 0x57, 0xbc, 0xdb, 0x80, 0xe8, 0xbf, 0xe1, 0x5f, 0xf4, - 0x6f, 0x4a, 0xd9, 0xf5, 0xe3, 0xf3, 0x65, 0xfc, 0xc1, 0x88, - 0xdc, 0x57, 0xf8, 0xeb, 0xe0, 0x03, 0x29, 0x01, 0xcb, 0xec, - 0xa1, 0x42, 0xe9, 0xf2, 0xdb, 0xaa, 0x1f, 0xc0, 0xf2, 0x07, - 0xa7, 0xfc, 0x83, 0x43, 0xad, 0x1a, 0xaa, 0x7d, 0x01, 0x3f, - 0x38, 0x3a, 0xe4, 0x1f, 0x1c, 0x6b, 0x55, 0x51, 0xed, 0x0b, - 0xf8, 0xc1, 0xe9, 0x31, 0xff, 0xe0, 0xbc, 0xf4, 0x83, 0xfb, - 0x4d, 0xb5, 0x0a, 0xee, 0x37, 0xd5, 0xe8, 0x87, 0xf6, 0xb3, - 0x63, 0xc7, 0x76, 0x69, 0xb9, 0x8d, 0x67, 0xc3, 0xb6, 0x83, - 0x97, 0xb8, 0xb4, 0x24, 0xe5, 0x67, 0xdd, 0x72, 0x9f, 0x3c, - 0x37, 0xca, 0x22, 0x4a, 0xfe, 0x8a, 0x08, 0xd3, 0x45, 0x20, - 0x74, 0x6d, 0xcf, 0x7d, 0xc5, 0x1c, 0xf9, 0xa7, 0xea, 0x84, - 0xd2, 0x72, 0xf4, 0x0c, 0xae, 0xca, 0x98, 0xad, 0x20, 0xf4, - 0xb7, 0x61, 0xdf, 0xdd, 0x85, 0xe0, 0xe9, 0xef, 0x1f, 0x4c, - 0xb6, 0x4c, 0xcd, 0xf5, 0x06, 0x84, 0x70, 0x6d, 0xef, 0x65, - 0x95, 0xba, 0x73, 0x63, 0x56, 0xee, 0x12, 0xfd, 0x99, 0x5d, - 0x68, 0x13, 0x09, 0x85, 0x22, 0x03, 0xd2, 0x33, 0x22, 0xb0, - 0x0a, 0x7c, 0x27, 0xef, 0x83, 0x5d, 0x0c, 0x92, 0x2f, 0xf0, - 0xdf, 0x99, 0xc5, 0x1e, 0x58, 0x99, 0xab, 0xd0, 0x7e, 0x72, - 0xe3, 0x9d, 0x61, 0xaf, 0x56, 0xc0, 0x03, 0x21, 0x95, 0x32, - 0x99, 0xdf, 0x38, 0x6b, 0xf6, 0x51, 0x17, 0xac, 0xdc, 0x35, - 0x80, 0x42, 0x2a, 0xaf, 0xe4, 0xa5, 0x58, 0xf2, 0x0e, 0x78, - 0xb9, 0xe5, 0xf6, 0xd6, 0x4a, 0x49, 0xdc, 0xc3, 0x62, 0xda, - 0xd7, 0xaf, 0xea, 0x37, 0x8f, 0x20, 0x8c, 0x5f, 0x73, 0xca, - 0xff, 0xf3, 0xff, 0xe3, 0xa5, 0x1f, 0x42, 0x00, 0x72, 0x8b, - 0x75, 0xe4, 0x72, 0x46, 0x07, 0x78, 0x91, 0xbb, 0x8d, 0x72, - 0xca, 0x5f, 0x25, 0x03, 0x68, 0x6f, 0xa3, 0xbc, 0x42, 0x8f, - 0x13, 0x9b, 0x15, 0xbb, 0x06, 0xab, 0x38, 0xd8, 0xd8, 0xd1, - 0xca, 0xce, 0x1b, 0x0c, 0xde, 0xad, 0xeb, 0x82, 0xee, 0x7c, - 0x7f, 0xd8, 0x5b, 0xa3, 0x7f, 0x59, 0xd9, 0xcf, 0xae, 0x17, - 0x3c, 0x84, 0xf6, 0x1a, 0x8f, 0xdb, 0x6a, 0x7b, 0xe7, 0xae, - 0xd0, 0xe8, 0xe5, 0x32, 0xdd, 0xd0, 0x4d, 0xa6, 0x66, 0x08, - 0xee, 0xdc, 0xbb, 0x7c, 0x0e, 0x59, 0xf3, 0x72, 0xf9, 0x93, - 0xb1, 0xde, 0x8b, 0xa4, 0x62, 0xe5, 0xfc, 0x09, 0xbf, 0xc8, - 0xfc, 0xe6, 0x8f, 0xad, 0x1d, 0x82, 0x92, 0x4f, 0xf9, 0x77, - 0xae, 0x07, 0x17, 0x6a, 0x51, 0xd9, 0x7f, 0xfe, 0xaf, 0x50, - 0x78, 0x15, 0x06, 0x85, 0x85, 0x67, 0x7c, 0x38, 0x67, 0x2e, - 0x58, 0x03, 0x3f, 0x2a, 0xe5, 0xc2, 0x51, 0xf2, 0xc5, 0x08, - 0x3c, 0xc7, 0x81, 0x5f, 0x5c, 0x78, 0xbe, 0xe0, 0xa5, 0x37, - 0x8f, 0xc0, 0x0b, 0xd0, 0x14, 0xc1, 0x99, 0x9a, 0x6f, 0xc3, - 0x3b, 0xd7, 0x41, 0xcb, 0x6f, 0xe1, 0xe7, 0x8a, 0x80, 0x91, - 0x5c, 0x53, 0x4e, 0x29, 0xce, 0x69, 0x93, 0x22, 0x26, 0xfb, - 0xf7, 0xa4, 0x14, 0x08, 0x57, 0xc0, 0xcf, 0xab, 0x73, 0x32, - 0x19, 0x72, 0x72, 0x21, 0x95, 0x3b, 0x6b, 0x34, 0xea, 0xf9, - 0x0d, 0x98, 0x5c, 0xa6, 0x3f, 0xb9, 0x2b, 0xfc, 0xe4, 0x80, - 0x8f, 0x7b, 0xdf, 0x47, 0xda, 0x0c, 0x30, 0x8a, 0x98, 0x6d, - 0xf3, 0x92, 0x54, 0xe0, 0xbe, 0xe4, 0xca, 0x94, 0x7f, 0xfe, - 0xef, 0xc3, 0xde, 0x40, 0x9a, 0xfb, 0x64, 0x79, 0x78, 0x6e, - 0x3e, 0xf1, 0x7f, 0xfe, 0xef, 0x50, 0xfa, 0x68, 0x1d, 0x78, - 0x76, 0x5e, 0xd9, 0xd0, 0x76, 0x58, 0xd9, 0xa9, 0xed, 0xb8, - 0xb6, 0x9f, 0x5f, 0x8e, 0xf3, 0x3a, 0x29, 0x59, 0xbe, 0x40, - 0xc2, 0x4d, 0x32, 0x28, 0x53, 0xf0, 0x14, 0x78, 0x5b, 0x24, - 0x91, 0xd9, 0x04, 0xf8, 0xdb, 0xdc, 0xf5, 0x0a, 0xbf, 0x13, - 0x2a, 0xcb, 0xfc, 0xb2, 0xbc, 0xf2, 0x84, 0xc0, 0xac, 0xa8, - 0xd4, 0x0d, 0x2b, 0x75, 0x13, 0x78, 0x79, 0x1c, 0x64, 0xf9, - 0xdb, 0x35, 0xda, 0x4e, 0x40, 0x32, 0x54, 0xec, 0x09, 0x6c, - 0x94, 0x11, 0xdc, 0x1b, 0x68, 0x03, 0x7f, 0x80, 0xed, 0x79, - 0xb2, 0xbd, 0x2d, 0xc8, 0x13, 0xa0, 0x03, 0xb4, 0x1d, 0xd3, - 0xef, 0x91, 0x22, 0x6c, 0xc3, 0xe6, 0x6f, 0x6c, 0x4c, 0xd6, - 0x40, 0x5b, 0x35, 0x22, 0x54, 0x48, 0x00, 0x6e, 0x9a, 0xf7, - 0x2e, 0xf0, 0x1c, 0x61, 0x13, 0x35, 0xe8, 0x83, 0xcc, 0xf2, - 0xf3, 0xed, 0xc6, 0x03, 0x62, 0xad, 0x03, 0x5a, 0xcb, 0x77, - 0xb0, 0xdb, 0xc3, 0x35, 0x19, 0x31, 0x2a, 0x12, 0x09, 0x4a, - 0x02, 0x22, 0x40, 0x94, 0x04, 0xaa, 0x11, 0xa0, 0xbf, 0x01, - 0xef, 0x2d, 0xd3, 0x11, 0x1c, 0x70, 0xcf, 0xdb, 0x15, 0x04, - 0x1e, 0xb0, 0x13, 0x7d, 0x9e, 0xfe, 0x34, 0x6e, 0x50, 0x0d, - 0x1f, 0x8c, 0x4d, 0x08, 0xee, 0xdd, 0x17, 0xf8, 0x78, 0x3c, - 0x1e, 0xf0, 0x8a, 0x48, 0xf5, 0x8c, 0x42, 0xcf, 0x1c, 0xcc, - 0xac, 0x0f, 0x86, 0xeb, 0xfc, 0xfd, 0xc3, 0x3e, 0x23, 0xd3, - 0xb3, 0xbd, 0x88, 0xf3, 0x47, 0xea, 0x93, 0xf9, 0x74, 0x41, - 0xbf, 0x38, 0x60, 0x5f, 0xcc, 0xc3, 0xad, 0xc0, 0x50, 0x7b, - 0xb0, 0x89, 0xb8, 0xf9, 0x4a, 0x6b, 0x3b, 0x81, 0x1f, 0x87, - 0x81, 0xe7, 0x01, 0x07, 0x1e, 0x4a, 0x00, 0x9f, 0x10, 0xf6, - 0xd4, 0x20, 0x8f, 0x59, 0xb3, 0x3b, 0xf3, 0xc1, 0xb0, 0x9b, - 0xd7, 0xee, 0xa9, 0x35, 0xe8, 0x8f, 0xfe, 0xb1, 0xe8, 0xcf, - 0xae, 0x97, 0xd7, 0xe6, 0xa8, 0x3b, 0xee, 0xf5, 0x96, 0xb0, - 0xbc, 0xd2, 0x91, 0x29, 0xf0, 0x5c, 0xff, 0x8f, 0xad, 0x1b, - 0x3d, 0x1a, 0x7b, 0xc6, 0xb5, 0xed, 0x3b, 0xc1, 0xfd, 0xbd, - 0x41, 0xeb, 0xcb, 0xef, 0xdf, 0xd4, 0xfa, 0xc7, 0xc2, 0x9a, - 0xcd, 0x39, 0xbd, 0x03, 0x4e, 0xef, 0x0f, 0xc8, 0x23, 0x71, - 0x39, 0x89, 0xf1, 0x8d, 0x35, 0x9d, 0xf6, 0xbb, 0x16, 0xa7, - 0x71, 0xc8, 0x68, 0x8c, 0xa1, 0x84, 0x0a, 0x5d, 0x07, 0xa4, - 0x88, 0xe4, 0x0e, 0xdb, 0x6c, 0x03, 0x80, 0x83, 0x24, 0x3b, - 0x5f, 0x56, 0xe8, 0x89, 0x41, 0x1f, 0xb1, 0xe1, 0x9a, 0x2d, - 0x46, 0xfd, 0xf9, 0x2c, 0x6f, 0xbc, 0x86, 0xd6, 0xdc, 0x9a, - 0xce, 0x96, 0x93, 0x99, 0x32, 0x44, 0x58, 0x52, 0x66, 0x2a, - 0x84, 0xe9, 0x71, 0x41, 0xd2, 0x5c, 0x1e, 0x0f, 0xf4, 0x24, - 0xaf, 0xf8, 0xc4, 0x9a, 0x76, 0xac, 0xd1, 0xdc, 0xbc, 0xb2, - 0x94, 0x11, 0xa0, 0x7b, 0x06, 0xd2, 0xa7, 0xcb, 0xfb, 0xbe, - 0x8b, 0x62, 0xb0, 0x9e, 0x43, 0xfd, 0x39, 0xe9, 0x3b, 0x7e, - 0x62, 0x90, 0x47, 0x49, 0xdf, 0x6f, 0x67, 0x73, 0x6b, 0x38, - 0xbf, 0x9d, 0x58, 0x79, 0xfd, 0xef, 0x74, 0x16, 0x4a, 0xcf, - 0xf1, 0x93, 0xbc, 0xc6, 0x5f, 0x2f, 0x86, 0xe6, 0x68, 0x66, - 0x8d, 0x66, 0xe3, 0xa9, 0xd2, 0xe7, 0xeb, 0xed, 0xda, 0xf6, - 0x3f, 0x6d, 0x82, 0x30, 0xb6, 0xef, 0xe0, 0xb9, 0x7a, 0x06, - 0xb7, 0xf9, 0x20, 0xcc, 0x27, 0xb4, 0x58, 0xdc, 0x28, 0xdd, - 0xc7, 0x4f, 0x72, 0x8b, 0xcf, 0x68, 0xf1, 0xa3, 0xa4, 0xf8, - 0xac, 0xa8, 0xb8, 0x49, 0x8b, 0x1f, 0x27, 0xc5, 0xcd, 0xa2, - 0xe2, 0x57, 0xb4, 0xf8, 0x49, 0x52, 0xfc, 0xaa, 0xa0, 0xf8, - 0x6c, 0x6e, 0xce, 0xfb, 0x1d, 0x71, 0x14, 0x4e, 0x93, 0x59, - 0x88, 0xa1, 0x4c, 0x5a, 0x41, 0x96, 0x29, 0xee, 0xfd, 0x70, - 0x7c, 0xd9, 0x1f, 0x58, 0x22, 0x85, 0xb3, 0x84, 0xf1, 0x02, - 0xb8, 0xab, 0x83, 0x52, 0x0a, 0x5f, 0x66, 0x23, 0xf2, 0xe1, - 0x39, 0xfb, 0xf0, 0x8b, 0x1b, 0xc2, 0x23, 0x46, 0x14, 0xd1, - 0xa1, 0x37, 0x46, 0x20, 0x7e, 0x0e, 0xc2, 0xef, 0xe5, 0xbc, - 0xf4, 0x4d, 0x5a, 0x43, 0xdf, 0xd4, 0xf5, 0xf3, 0x2d, 0x8f, - 0x75, 0x46, 0xe3, 0x91, 0x2a, 0x21, 0x47, 0x81, 0x5f, 0x20, - 0x20, 0xbb, 0xd6, 0x64, 0x7e, 0xad, 0xb0, 0x4d, 0x17, 0x6c, - 0xe2, 0xc7, 0xfc, 0x4f, 0xcc, 0xc1, 0xbc, 0x3f, 0x5f, 0x74, - 0xd5, 0xa5, 0x62, 0x7a, 0xb1, 0x1b, 0x6f, 0x9d, 0x82, 0xba, - 0xae, 0xad, 0xfe, 0xd5, 0xf5, 0x5c, 0xe1, 0x99, 0x6b, 0xe0, - 0x3e, 0x3c, 0xc6, 0xe5, 0x23, 0x32, 0x9d, 0xcd, 0xfa, 0xd2, - 0xa0, 0xa0, 0x07, 0xea, 0xb8, 0xe0, 0x42, 0x45, 0xa2, 0x05, - 0x1d, 0xd3, 0xa4, 0xd1, 0x51, 0x4f, 0x6b, 0xa5, 0xa2, 0xe1, - 0xa0, 0x8e, 0x68, 0x80, 0x9c, 0x2e, 0xca, 0x05, 0xf8, 0x53, - 0x11, 0x0a, 0xa8, 0x40, 0x81, 0x44, 0xe8, 0xf5, 0xbf, 0x5a, - 0xdd, 0x2f, 0xfd, 0xd1, 0x95, 0xba, 0xfb, 0x41, 0xad, 0xd0, - 0xf9, 0xf4, 0xc5, 0xf5, 0x1f, 0xf2, 0x3b, 0xd0, 0x19, 0x4f, - 0xa0, 0x38, 0x55, 0x1a, 0xdf, 0x09, 0x36, 0xa2, 0x62, 0x98, - 0xfa, 0xe8, 0x66, 0x3e, 0x56, 0x37, 0x83, 0x9b, 0x38, 0xbd, - 0x01, 0xa0, 0x3f, 0xe4, 0x6d, 0x1f, 0x3d, 0xba, 0xa3, 0x1a, - 0x48, 0x96, 0x16, 0xd0, 0x19, 0x04, 0xc1, 0x26, 0x1a, 0xda, - 0xd1, 0x77, 0x65, 0x4f, 0x35, 0xf0, 0x0b, 0x83, 0xbc, 0x49, - 0xb6, 0xd5, 0x81, 0x06, 0xa3, 0xbf, 0xec, 0xd3, 0x7f, 0xf4, - 0x38, 0x7e, 0x62, 0x32, 0x86, 0x4f, 0xbe, 0xe4, 0x73, 0x6a, - 0xc7, 0x8f, 0xe5, 0x3b, 0xe6, 0xdc, 0x1a, 0x58, 0x63, 0xc8, - 0x17, 0x50, 0xe2, 0x8c, 0x47, 0x0a, 0xa9, 0x64, 0xb8, 0xe6, - 0x70, 0xe1, 0x07, 0x1b, 0xa6, 0xfd, 0x95, 0xd2, 0x94, 0x17, - 0x55, 0x42, 0xee, 0x58, 0x5d, 0x5d, 0xe5, 0x94, 0x84, 0x15, - 0x9d, 0x90, 0x39, 0x97, 0x96, 0xb6, 0x86, 0x5a, 0x31, 0x1e, - 0x0c, 0x64, 0x12, 0x07, 0x5c, 0x51, 0x81, 0xfa, 0x4f, 0x39, - 0x85, 0x49, 0x7f, 0xde, 0x51, 0x5a, 0x71, 0xb8, 0xcf, 0x0f, - 0x33, 0xf1, 0x4a, 0xa3, 0x15, 0xb7, 0xe6, 0x17, 0x99, 0xc2, - 0x71, 0x42, 0xe1, 0xd6, 0x7e, 0x2e, 0xff, 0x7e, 0x36, 0xb1, - 0xac, 0xae, 0x4c, 0xe1, 0x7c, 0x5f, 0xd6, 0x4b, 0x74, 0xda, - 0xb0, 0x84, 0x13, 0x2d, 0xcf, 0xcb, 0xc1, 0xbe, 0xd4, 0x90, - 0x29, 0x54, 0xce, 0xcb, 0x29, 0x41, 0x35, 0x0b, 0xee, 0x50, - 0xe6, 0x20, 0x4d, 0xee, 0x90, 0x93, 0xbb, 0x01, 0x21, 0xdc, - 0xab, 0x6c, 0x4f, 0x93, 0xe6, 0x7c, 0x3c, 0xfd, 0xc7, 0x42, - 0x26, 0x76, 0xcc, 0x89, 0xcd, 0x83, 0x10, 0xea, 0x80, 0xe5, - 0x54, 0x7a, 0x63, 0x28, 0xe2, 0x24, 0x22, 0xe7, 0x9c, 0x48, - 0x2f, 0x80, 0x62, 0x4e, 0xa7, 0x77, 0x83, 0x71, 0xa7, 0x3f, - 0xbf, 0x15, 0xc9, 0x1c, 0xec, 0x8b, 0x1d, 0xf3, 0x82, 0x15, - 0x3a, 0xf6, 0x97, 0xf7, 0xe9, 0x7a, 0x3a, 0x9e, 0xcf, 0x07, - 0x52, 0x83, 0x0e, 0x05, 0x4a, 0xf3, 0xc7, 0x30, 0x88, 0x63, - 0x4f, 0xa3, 0x4d, 0xd6, 0x57, 0x28, 0xf8, 0x46, 0x66, 0xc2, - 0xc9, 0xc7, 0x8a, 0x9c, 0x58, 0xf8, 0xd1, 0x06, 0x8a, 0x7f, - 0x28, 0xab, 0x1c, 0xc3, 0x7a, 0x81, 0xf2, 0xd0, 0xb7, 0x35, - 0x38, 0x7b, 0x34, 0x5e, 0x32, 0x95, 0x99, 0x11, 0x3e, 0x4f, - 0x0b, 0xa0, 0x4f, 0x01, 0xd1, 0x9d, 0xb1, 0xe2, 0xb5, 0x2a, - 0x5f, 0xfd, 0x49, 0x23, 0x7b, 0xf4, 0x1f, 0xbe, 0xf0, 0x35, - 0xd4, 0xee, 0xf1, 0x66, 0xe0, 0xae, 0xe1, 0x4e, 0x28, 0xca, - 0xd5, 0x31, 0x13, 0x3e, 0xb0, 0x53, 0xe4, 0xad, 0x22, 0x5c, - 0xc7, 0x93, 0x5c, 0xe9, 0x3a, 0x34, 0xbf, 0x2e, 0x65, 0x39, - 0x92, 0x88, 0xc8, 0xa1, 0xfd, 0xe2, 0xae, 0xb7, 0x6b, 0xa3, - 0x44, 0x49, 0x18, 0xf6, 0x47, 0x4b, 0x28, 0xd3, 0x92, 0xef, - 0x0f, 0xb9, 0xa9, 0xc1, 0xc7, 0xdf, 0x97, 0xab, 0x0b, 0xa8, - 0x11, 0x22, 0x89, 0x63, 0xb5, 0x09, 0x1a, 0x24, 0x60, 0x2b, - 0x64, 0x29, 0x70, 0xae, 0xb6, 0x03, 0xcb, 0x81, 0xe2, 0x46, - 0x48, 0x14, 0xb8, 0x20, 0x64, 0xcd, 0xd0, 0xa0, 0x70, 0x23, - 0xae, 0xf9, 0xc3, 0x14, 0x05, 0x69, 0xd5, 0x17, 0x70, 0xc9, - 0xd4, 0x32, 0x39, 0x2f, 0xa7, 0xe6, 0xd9, 0x30, 0x43, 0x60, - 0x67, 0xed, 0xd0, 0xc2, 0x7e, 0x8c, 0x7e, 0x33, 0xc3, 0xff, - 0x43, 0x18, 0x6c, 0x37, 0x6c, 0x8f, 0x96, 0x1e, 0xf2, 0xb6, - 0xdb, 0x3e, 0xd8, 0x3e, 0x21, 0x45, 0x81, 0x35, 0x98, 0xfe, - 0x4e, 0x5a, 0xc8, 0xbe, 0xc3, 0x17, 0x0b, 0x89, 0xa5, 0x38, - 0x88, 0x03, 0xb1, 0x1b, 0x99, 0x85, 0x26, 0xc1, 0x66, 0xb1, - 0x29, 0x2d, 0x25, 0x6d, 0xa3, 0xa5, 0xa5, 0x07, 0xf6, 0xd6, - 0x5f, 0x3d, 0x96, 0x17, 0x0b, 0x5c, 0x45, 0xfb, 0xc9, 0x2c, - 0xd6, 0x77, 0x3c, 0xc0, 0x47, 0xa0, 0x94, 0xe6, 0xf3, 0x00, - 0x3c, 0x01, 0x2f, 0x43, 0x7e, 0x64, 0x96, 0x9f, 0x06, 0xcf, - 0x51, 0x69, 0xa1, 0x1e, 0xdc, 0x6b, 0x83, 0x67, 0xa4, 0x95, - 0x94, 0x16, 0xbd, 0x0d, 0x6e, 0xcb, 0xc7, 0x1c, 0x1f, 0x85, - 0x02, 0xff, 0x33, 0x00, 0x1b, 0x45, 0x67, 0xcc, 0x2c, 0x6e, - 0x79, 0xe0, 0xc9, 0x8e, 0x83, 0x50, 0xb3, 0x9d, 0xf3, 0xd0, - 0xfe, 0x1f, 0x64, 0xf3, 0x0f, 0x77, 0xa5, 0x1f, 0x74, 0xb6, - 0x51, 0x1c, 0xac, 0xb5, 0x07, 0xf7, 0x06, 0x3c, 0xba, 0x2b, - 0x0f, 0xc0, 0xbd, 0x68, 0xad, 0xc7, 0x08, 0x9d, 0x60, 0xbd, - 0xb1, 0xa3, 0xa8, 0x63, 0x7b, 0xee, 0x5d, 0xa8, 0xfb, 0x09, - 0x6c, 0x89, 0xb4, 0x84, 0x8a, 0x7b, 0x3b, 0x05, 0xf7, 0x20, - 0x04, 0xf8, 0x22, 0xbb, 0xbc, 0x31, 0xeb, 0x68, 0x0a, 0x3c, - 0x7b, 0xa7, 0x41, 0x9a, 0xf6, 0x70, 0xe2, 0xd9, 0xbe, 0xf5, - 0x02, 0x56, 0x5b, 0xad, 0xb6, 0x77, 0xdd, 0xc8, 0x0b, 0x9c, - 0x87, 0xf2, 0xa6, 0x74, 0xc3, 0xa0, 0x7c, 0xcd, 0xcd, 0xec, - 0xf5, 0xc6, 0x2b, 0xa7, 0x85, 0x2e, 0xdb, 0xd1, 0x7d, 0xbd, - 0xa3, 0xb5, 0xdc, 0x11, 0xbf, 0xe3, 0x21, 0xb6, 0x35, 0x9a, - 0xd9, 0x5f, 0xc3, 0x47, 0x90, 0x9d, 0x56, 0xdf, 0x75, 0xd8, - 0x74, 0x6e, 0x7f, 0x07, 0xc1, 0xfd, 0xbd, 0x86, 0x74, 0x90, - 0x4d, 0x46, 0x99, 0x85, 0xcc, 0x6d, 0x1c, 0xf8, 0xc1, 0x3a, - 0xd8, 0x46, 0x33, 0xc8, 0xcb, 0x3a, 0x83, 0x4f, 0x17, 0x69, - 0xe0, 0x8a, 0x77, 0x0b, 0x7b, 0x92, 0x40, 0x65, 0x7b, 0x76, - 0xb6, 0x94, 0xa5, 0x22, 0x03, 0x5b, 0x7b, 0x7d, 0x47, 0x3d, - 0x17, 0xb1, 0xc7, 0x25, 0x13, 0x0b, 0x22, 0x37, 0x04, 0xce, - 0xb7, 0x72, 0x0e, 0x20, 0x05, 0xaf, 0x81, 0xed, 0xe8, 0x8c, - 0x2d, 0x2d, 0x8e, 0x94, 0x7e, 0xdd, 0xb2, 0x58, 0xbb, 0xd7, - 0x2d, 0x9c, 0xda, 0x3c, 0x0b, 0x29, 0xeb, 0x08, 0x42, 0x5a, - 0x96, 0xa9, 0x89, 0xf5, 0xa6, 0x64, 0x0a, 0xd6, 0x41, 0x0c, - 0xba, 0xe8, 0x66, 0x3e, 0xb1, 0xa7, 0x26, 0x4f, 0x4a, 0x18, - 0x1d, 0x17, 0x4c, 0x26, 0xb3, 0xa4, 0xb5, 0xd7, 0x2e, 0x14, - 0x84, 0xa1, 0xbb, 0x52, 0xd6, 0x5c, 0xaa, 0xb1, 0xa9, 0x47, - 0x74, 0x33, 0xbf, 0xf7, 0xec, 0x07, 0xb6, 0x87, 0xa3, 0xbf, - 0xf9, 0xd5, 0x11, 0x08, 0xdd, 0xc0, 0x71, 0x57, 0x82, 0xb9, - 0x82, 0xfe, 0xde, 0xcb, 0x2a, 0xee, 0x00, 0xa8, 0x16, 0xae, - 0xc4, 0xcb, 0x8b, 0xae, 0xf0, 0x64, 0x8f, 0x34, 0x80, 0x56, - 0x86, 0xfe, 0x7e, 0x84, 0xfc, 0x03, 0x42, 0x46, 0x09, 0x69, - 0x17, 0xfc, 0x46, 0x65, 0xe7, 0xc3, 0x5a, 0xee, 0x91, 0x69, - 0xe2, 0xef, 0x1f, 0x62, 0x6c, 0x6d, 0x67, 0xe6, 0x50, 0xb8, - 0x39, 0x87, 0x81, 0x4f, 0x5d, 0x0a, 0x8c, 0xd1, 0x76, 0x7d, - 0x87, 0x84, 0x3f, 0x1a, 0x10, 0xd1, 0xe9, 0x05, 0x6b, 0x3d, - 0x58, 0x17, 0xb6, 0x4e, 0x44, 0xb7, 0x11, 0x5c, 0x4d, 0x66, - 0x95, 0xeb, 0x07, 0xd7, 0xe1, 0x56, 0x62, 0x3c, 0x4a, 0x46, - 0xdf, 0x01, 0x7e, 0x0c, 0x95, 0xfb, 0x55, 0x61, 0x65, 0x3a, - 0xd4, 0x91, 0x43, 0x8a, 0x4a, 0x9d, 0x3c, 0x53, 0x5b, 0x8e, - 0x6e, 0x43, 0xa8, 0x43, 0x82, 0x0e, 0xe1, 0xd8, 0x85, 0x53, - 0x1a, 0xc3, 0x99, 0x4f, 0xce, 0x36, 0xf0, 0x81, 0x41, 0x9f, - 0x10, 0xda, 0xcc, 0x29, 0x86, 0x50, 0x8e, 0xf4, 0xda, 0x1b, - 0x26, 0xb3, 0x3e, 0x0b, 0xb6, 0xe8, 0xf8, 0x66, 0x3a, 0x4e, - 0x08, 0xd0, 0x9d, 0x7d, 0x9d, 0xde, 0x87, 0xab, 0x25, 0xbe, - 0x36, 0x95, 0x28, 0x5a, 0x70, 0x6c, 0xe3, 0x9d, 0x48, 0xf0, - 0x5c, 0x93, 0x9e, 0xc3, 0x6f, 0x9a, 0xe0, 0x52, 0x8d, 0x5d, - 0x9f, 0x2a, 0xaf, 0x0d, 0x9a, 0x08, 0x49, 0x8a, 0x4d, 0x14, - 0xc9, 0x6a, 0xb7, 0xf3, 0xbf, 0xf6, 0x18, 0x4b, 0xe3, 0x65, - 0x15, 0xc0, 0x35, 0x9c, 0xcd, 0xde, 0xab, 0x70, 0x75, 0x90, - 0xd8, 0x96, 0x3b, 0x8f, 0x60, 0xf5, 0xdd, 0x98, 0x41, 0x1d, - 0xfe, 0x63, 0x67, 0xda, 0xf9, 0x74, 0x70, 0xfa, 0xa9, 0x7f, - 0x39, 0xfc, 0x4d, 0xa7, 0x13, 0xf0, 0x4f, 0x5a, 0x07, 0xfa, - 0x21, 0xe9, 0xe2, 0xb2, 0x28, 0xba, 0x42, 0xbf, 0x3a, 0x01, - 0xf2, 0x6f, 0x58, 0xdb, 0xf0, 0xd8, 0x76, 0x7c, 0xf1, 0x01, - 0x5d, 0x6e, 0x8a, 0xb7, 0x03, 0x81, 0xe8, 0xfc, 0x90, 0xf1, - 0xf5, 0x0c, 0x9e, 0x32, 0x3c, 0xaa, 0x05, 0x61, 0x1a, 0x17, - 0x8c, 0xc6, 0x09, 0xb7, 0x87, 0x08, 0x65, 0x8a, 0x48, 0x41, - 0x69, 0x85, 0x77, 0x70, 0x4c, 0xe7, 0x20, 0x69, 0x8c, 0x60, - 0x12, 0x49, 0x8a, 0x14, 0x90, 0xa1, 0x86, 0x70, 0xbc, 0x03, - 0x11, 0x4a, 0x49, 0x93, 0x0e, 0x78, 0x9b, 0xc4, 0x52, 0x05, - 0xc4, 0xcc, 0x15, 0xdc, 0xad, 0xe1, 0x01, 0x2a, 0x45, 0xf4, - 0x30, 0x69, 0x9e, 0x60, 0x62, 0x61, 0xa5, 0x0d, 0x4d, 0xea, - 0xc4, 0x74, 0x1f, 0x31, 0x92, 0x49, 0x3b, 0x0f, 0x85, 0xb1, - 0x63, 0x45, 0x0a, 0x1b, 0x19, 0x6f, 0xc5, 0x29, 0x38, 0x4a, - 0xda, 0x76, 0x24, 0xb6, 0x2d, 0x29, 0x54, 0x34, 0x78, 0xf6, - 0x93, 0xfb, 0x20, 0xd1, 0x4a, 0x1a, 0x75, 0x24, 0x0c, 0x9e, - 0x50, 0xaa, 0x80, 0xd8, 0xd5, 0xd6, 0x75, 0x88, 0x3b, 0x26, - 0xe1, 0xae, 0xa4, 0x59, 0x82, 0x21, 0x89, 0x97, 0x29, 0x20, - 0xc4, 0x94, 0x79, 0x3e, 0xfc, 0xc7, 0x49, 0xb3, 0x8e, 0x4f, - 0xf6, 0xd5, 0x23, 0x64, 0xd9, 0xb0, 0x53, 0x95, 0x7f, 0xb6, - 0x85, 0x1b, 0xd9, 0x93, 0x1b, 0xf1, 0xce, 0x9e, 0x1c, 0x73, - 0xe6, 0x15, 0xcc, 0x4b, 0xb8, 0xb4, 0x21, 0x15, 0x2f, 0xa0, - 0x8e, 0xd4, 0xeb, 0x0c, 0xd2, 0x7c, 0x5d, 0xf0, 0x06, 0xa3, - 0xa2, 0xda, 0x74, 0x3b, 0xab, 0x2d, 0xa5, 0x75, 0x9a, 0x34, - 0xf3, 0x74, 0x3f, 0xf3, 0x1e, 0x2f, 0x93, 0x49, 0x88, 0xf2, - 0xb9, 0x63, 0x34, 0x92, 0xf6, 0x9c, 0xf2, 0xf6, 0xf0, 0x32, - 0x45, 0xa3, 0x27, 0x76, 0xeb, 0x2c, 0x69, 0xca, 0x99, 0x30, - 0x62, 0xe5, 0x9d, 0x61, 0x36, 0x31, 0x46, 0x26, 0x69, 0xcd, - 0x19, 0x6f, 0x0d, 0x2f, 0x53, 0x40, 0xa8, 0x8b, 0x0e, 0xc6, - 0xc1, 0x66, 0x8d, 0x65, 0x34, 0x11, 0x40, 0xa8, 0x21, 0x98, - 0x96, 0x60, 0x6a, 0x94, 0x8a, 0x15, 0x0d, 0x32, 0x3e, 0x3c, - 0xb2, 0x31, 0x3a, 0x39, 0x39, 0x3a, 0xe6, 0x42, 0x88, 0x0f, - 0x35, 0x2d, 0x44, 0x55, 0x17, 0x41, 0x67, 0x12, 0x6c, 0x20, - 0x82, 0xef, 0x06, 0xda, 0x26, 0xd0, 0xf1, 0x18, 0x28, 0x37, - 0x25, 0xe4, 0x8d, 0x41, 0x5f, 0x45, 0x78, 0xf7, 0xfb, 0xfb, - 0x87, 0x27, 0xc2, 0x6f, 0x1f, 0xb2, 0x77, 0x4c, 0x52, 0x96, - 0xdf, 0x3e, 0x0a, 0x17, 0x3d, 0xd6, 0x6c, 0x6e, 0xaa, 0xbb, - 0x11, 0xdd, 0xdc, 0x05, 0xff, 0x91, 0x1c, 0x03, 0xd0, 0xe5, - 0x78, 0x3c, 0x57, 0x6e, 0x80, 0x2e, 0xe1, 0x26, 0x12, 0xc5, - 0xa1, 0xbd, 0xd9, 0x14, 0x5e, 0x02, 0x8d, 0xc6, 0xd3, 0xa1, - 0xa9, 0xba, 0x08, 0x8c, 0xd0, 0x61, 0xd3, 0x33, 0xc6, 0x59, - 0xe6, 0x15, 0xd5, 0xf3, 0x62, 0xc1, 0x0c, 0x71, 0x87, 0xdc, - 0xf3, 0x62, 0x2b, 0xb8, 0xc2, 0xa4, 0x8d, 0xaf, 0xd3, 0x29, - 0xbb, 0x47, 0x4d, 0xee, 0xfa, 0xac, 0x30, 0x2c, 0xba, 0x3f, - 0xed, 0x99, 0xfd, 0xc1, 0x62, 0x6a, 0x29, 0xb7, 0xc4, 0x3d, - 0xdb, 0xf5, 0xb6, 0xe2, 0x06, 0x57, 0xa0, 0x08, 0x60, 0x05, - 0x35, 0xf9, 0x90, 0xfc, 0x48, 0x46, 0xbe, 0x37, 0xc8, 0x1b, - 0xf9, 0xc4, 0x65, 0xa6, 0xe8, 0x86, 0x7d, 0xd9, 0x1f, 0xcd, - 0xad, 0xe9, 0x8d, 0x35, 0x92, 0x6e, 0x7d, 0xe4, 0xbb, 0x76, - 0x03, 0xfb, 0xb1, 0x3f, 0x21, 0xc5, 0x13, 0xea, 0x1e, 0xc8, - 0x05, 0x03, 0x1d, 0x45, 0xb4, 0x9a, 0xee, 0x80, 0x68, 0x15, - 0xba, 0x1b, 0xd1, 0xe5, 0x1d, 0x19, 0x31, 0x3c, 0xe4, 0x9c, - 0x17, 0xdb, 0xe1, 0xce, 0x90, 0x0a, 0x90, 0x6e, 0x64, 0x39, - 0x05, 0x0b, 0x0a, 0x06, 0x65, 0x72, 0xc9, 0xea, 0x97, 0xd4, - 0xf7, 0x8f, 0x2d, 0x08, 0x77, 0x12, 0xdb, 0xe3, 0xc1, 0x13, - 0x0f, 0x0e, 0xd2, 0x74, 0xe3, 0xf2, 0x86, 0xb4, 0x1a, 0x94, - 0xa3, 0x4a, 0x76, 0x3d, 0xe4, 0x8b, 0xbe, 0x7f, 0x1f, 0xa8, - 0xcc, 0x40, 0x48, 0xa1, 0x37, 0x89, 0x55, 0x47, 0x6b, 0x79, - 0xb9, 0x8e, 0x4a, 0x82, 0x6a, 0xfa, 0xb2, 0x7a, 0xaf, 0xab, - 0x8f, 0x7a, 0x36, 0xbe, 0xff, 0xa5, 0xbe, 0x4f, 0xe4, 0x87, - 0xc6, 0xf0, 0xa6, 0xf5, 0x42, 0x38, 0x5b, 0x81, 0x2f, 0xa8, - 0xa1, 0x1d, 0xf6, 0x00, 0xff, 0xae, 0x47, 0xd4, 0x5e, 0xc5, - 0x4b, 0x74, 0x4a, 0x10, 0x14, 0x04, 0xf7, 0x89, 0x68, 0xb6, - 0x73, 0x77, 0x9d, 0x7b, 0x02, 0xd1, 0x3b, 0x27, 0x38, 0x40, - 0x25, 0xdf, 0x45, 0x4f, 0x6a, 0x57, 0xa0, 0xcf, 0x71, 0x9c, - 0x1d, 0x8e, 0x33, 0xf9, 0x2b, 0x93, 0x29, 0x56, 0x70, 0x6f, - 0x7d, 0x03, 0x86, 0xd0, 0xe2, 0x5f, 0xe2, 0x1f, 0x27, 0xb9, - 0xa3, 0xd0, 0xba, 0xc8, 0x1b, 0x2d, 0xc6, 0x0d, 0x92, 0x73, - 0x9e, 0x60, 0xd1, 0xe6, 0xb7, 0x31, 0xb5, 0xb7, 0x85, 0xa9, - 0x35, 0x19, 0x4f, 0xe7, 0x29, 0x7f, 0x32, 0xe4, 0xf7, 0x93, - 0x2f, 0x6c, 0xff, 0xb1, 0xb0, 0xa6, 0xb7, 0xca, 0x86, 0x80, - 0xe7, 0x40, 0x4b, 0x5a, 0x79, 0x82, 0xbf, 0x20, 0xf9, 0x5b, - 0xe5, 0x6e, 0xda, 0x7a, 0xee, 0x5d, 0x58, 0x7d, 0xe8, 0x3b, - 0x9b, 0xed, 0x02, 0x87, 0x32, 0x64, 0x8b, 0xa6, 0xc4, 0x3d, - 0xa7, 0x33, 0x59, 0x18, 0xb4, 0xa0, 0xd6, 0x3c, 0x3c, 0x11, - 0x97, 0x43, 0x72, 0xee, 0x10, 0xae, 0x03, 0x71, 0xe5, 0x1b, - 0xc1, 0xad, 0x23, 0x73, 0x3e, 0xfe, 0xbd, 0x46, 0x4f, 0xe6, - 0xa1, 0xed, 0x47, 0x68, 0x3e, 0x2e, 0x5d, 0x1f, 0x99, 0xdd, - 0x22, 0xc5, 0x4f, 0x28, 0x79, 0x6f, 0xf0, 0x02, 0x5a, 0x5d, - 0x59, 0x05, 0x7e, 0x84, 0xd8, 0x43, 0x30, 0x1a, 0xe2, 0xdf, - 0x0d, 0x44, 0x0e, 0x6d, 0xfb, 0x32, 0xdf, 0xa2, 0xa2, 0x67, - 0x46, 0x29, 0x19, 0x92, 0x29, 0xb2, 0x7c, 0x84, 0x31, 0x71, - 0x91, 0x23, 0xc3, 0x71, 0xc1, 0x79, 0x17, 0xbf, 0x33, 0xd8, - 0xcb, 0x0c, 0x09, 0x50, 0x4c, 0x1c, 0x6a, 0x92, 0x82, 0xe9, - 0x3f, 0xb9, 0x92, 0xc1, 0xcc, 0x7e, 0x28, 0xa8, 0x9b, 0x2e, - 0xba, 0xda, 0xe6, 0x05, 0xf9, 0xe5, 0xaf, 0x32, 0xf8, 0xff, - 0x91, 0x2b, 0x7b, 0xf8, 0x9a, 0x1e, 0xa7, 0xd7, 0x74, 0xb7, - 0x83, 0x74, 0xae, 0x9a, 0xab, 0x1a, 0x2a, 0x8a, 0xa9, 0x45, - 0x3d, 0x43, 0xc3, 0x92, 0x7c, 0x80, 0x86, 0x01, 0x7f, 0x93, - 0x4b, 0x01, 0x09, 0x15, 0x69, 0x85, 0xc3, 0xb3, 0xf9, 0xa6, - 0xc2, 0xf7, 0xd6, 0x64, 0x39, 0xb2, 0xbe, 0xce, 0xd3, 0x4e, - 0x91, 0x48, 0x3c, 0xc3, 0x03, 0xf4, 0x4b, 0x2c, 0x0d, 0xdf, - 0x2c, 0x06, 0x15, 0xa9, 0x4f, 0xa6, 0xd6, 0x4d, 0x7f, 0xbc, - 0x98, 0x29, 0xba, 0x01, 0xab, 0x61, 0x02, 0x4b, 0xba, 0xf0, - 0xb8, 0xae, 0x5d, 0x8b, 0x3e, 0xff, 0xc9, 0x2c, 0x22, 0x6a, - 0xfe, 0x47, 0x05, 0x0c, 0x92, 0x7d, 0x0c, 0xc8, 0x67, 0x8f, - 0x38, 0x88, 0x6d, 0x6f, 0x09, 0xb9, 0x98, 0x07, 0x35, 0xcd, - 0xd1, 0x23, 0xdc, 0x89, 0xa8, 0x8e, 0xba, 0x82, 0x68, 0x2d, - 0x7d, 0x6a, 0xcc, 0x64, 0x47, 0x9d, 0x30, 0x44, 0x6a, 0x06, - 0xa2, 0x99, 0x61, 0xe7, 0xac, 0x42, 0x59, 0x30, 0xa1, 0x55, - 0x52, 0x36, 0x2b, 0x69, 0xe2, 0xdd, 0xce, 0xac, 0xa6, 0x22, - 0xce, 0xd8, 0x65, 0x39, 0x1a, 0xcf, 0x97, 0xb3, 0xc5, 0x04, - 0xed, 0x7b, 0xc2, 0xe5, 0x3e, 0xf7, 0xe3, 0x62, 0x7c, 0x43, - 0x86, 0x24, 0x88, 0xd1, 0x01, 0x1e, 0xc9, 0x57, 0x61, 0xb9, - 0x95, 0xf1, 0x27, 0x62, 0xfc, 0x9c, 0x7a, 0x0e, 0xb9, 0x81, - 0xea, 0x25, 0x6e, 0x52, 0xc7, 0x17, 0xb3, 0x3f, 0xef, 0x8f, - 0xae, 0x96, 0x9d, 0xf1, 0x68, 0x3e, 0x1d, 0x0f, 0xd2, 0xae, - 0x0e, 0x5f, 0x6c, 0x37, 0x86, 0xdb, 0x81, 0x51, 0x20, 0xab, - 0x74, 0xeb, 0x12, 0x0e, 0x64, 0xa2, 0x1f, 0x84, 0x48, 0x92, - 0x9c, 0xcf, 0x74, 0x09, 0x76, 0xc6, 0xc3, 0xc9, 0xc0, 0x9a, - 0x67, 0xb9, 0x46, 0x88, 0x44, 0x27, 0x61, 0xb0, 0x02, 0x0e, - 0x3c, 0xc1, 0x19, 0xe4, 0x3c, 0x53, 0x30, 0x3e, 0x55, 0xb5, - 0x32, 0xae, 0x0d, 0x8b, 0xeb, 0xf7, 0x58, 0xd1, 0xd0, 0x04, - 0x9d, 0xb9, 0xea, 0xf2, 0x2d, 0x3c, 0xc9, 0x9b, 0xb3, 0xda, - 0xb2, 0xbd, 0x3f, 0x32, 0x3b, 0xf3, 0xfe, 0x8d, 0xea, 0xaa, - 0x4b, 0x1b, 0xec, 0x46, 0x50, 0x01, 0xc6, 0x8a, 0x38, 0xd0, - 0x9e, 0x0c, 0x91, 0xde, 0x41, 0x9a, 0x9e, 0x59, 0x99, 0xda, - 0xb2, 0x3f, 0x51, 0x1d, 0x7c, 0xf9, 0x38, 0xba, 0x78, 0x5a, - 0x1f, 0xb0, 0xc1, 0xbe, 0x0a, 0xcd, 0x6e, 0xe2, 0xb5, 0x79, - 0x94, 0x41, 0xb5, 0x94, 0x3f, 0x32, 0x69, 0x22, 0xab, 0x81, - 0x72, 0x96, 0x10, 0x68, 0x22, 0xeb, 0x41, 0x05, 0x82, 0x5d, - 0x4b, 0xec, 0xfa, 0x49, 0xe6, 0xb9, 0xa8, 0x5f, 0xa3, 0xf3, - 0x84, 0x2e, 0xef, 0xfe, 0x69, 0x26, 0xe5, 0xea, 0x03, 0x40, - 0xe8, 0xf2, 0x21, 0x38, 0xcb, 0xa4, 0x5b, 0x3c, 0x08, 0x45, - 0x62, 0x1c, 0x10, 0x8b, 0x8d, 0x64, 0xbe, 0x69, 0xd5, 0xf6, - 0x90, 0xbd, 0x84, 0x4f, 0x32, 0x4f, 0x85, 0x95, 0x16, 0x72, - 0x71, 0x0b, 0xa8, 0xbd, 0x58, 0xf0, 0x91, 0x23, 0x2e, 0x72, - 0xb4, 0xfe, 0x53, 0xd5, 0xae, 0x9c, 0x76, 0xa6, 0xab, 0xa5, - 0x23, 0x9a, 0x2b, 0x12, 0x0b, 0xe6, 0x1b, 0xf1, 0x23, 0x30, - 0xe8, 0x87, 0x46, 0x20, 0x10, 0xf7, 0x28, 0xf1, 0x56, 0x8e, - 0x85, 0x38, 0x36, 0x28, 0x75, 0x2e, 0xc4, 0x71, 0x41, 0x05, - 0x5e, 0xb3, 0xd6, 0x5c, 0x55, 0x1a, 0x41, 0x5c, 0x14, 0x81, - 0xc4, 0x0f, 0x9f, 0x87, 0x39, 0x87, 0xcf, 0x42, 0xad, 0x03, - 0x39, 0x00, 0x2c, 0xd7, 0xae, 0xaf, 0xde, 0x6a, 0x31, 0x07, - 0xbd, 0x88, 0x78, 0x08, 0xb0, 0xeb, 0x50, 0x82, 0x29, 0x40, - 0xc6, 0x00, 0x85, 0xff, 0x69, 0x69, 0x36, 0xa4, 0x0e, 0xfb, - 0x25, 0x55, 0x07, 0x75, 0xc0, 0x6b, 0xa1, 0x0e, 0x04, 0x66, - 0xb1, 0xc4, 0x21, 0xe5, 0x6a, 0x25, 0x03, 0xf8, 0x06, 0xf9, - 0x29, 0xba, 0x68, 0x7e, 0xd7, 0xb4, 0x46, 0x39, 0xf8, 0x3c, - 0xa7, 0x62, 0xcd, 0xaa, 0x6d, 0x2f, 0x46, 0x9d, 0x5b, 0xae, - 0x23, 0x2f, 0xaf, 0x83, 0xc3, 0xd9, 0xc0, 0xb0, 0x13, 0x77, - 0xc9, 0xcc, 0xea, 0xf4, 0x4c, 0x46, 0x70, 0x17, 0x59, 0xde, - 0x87, 0x36, 0xe6, 0xe3, 0xa2, 0x11, 0xed, 0xc2, 0x82, 0xc4, - 0x89, 0x99, 0x38, 0x5a, 0xf7, 0xe8, 0x37, 0x4a, 0xe5, 0x5a, - 0x86, 0x35, 0xb8, 0x26, 0xee, 0xb4, 0x2a, 0xed, 0xa0, 0x92, - 0x2d, 0xd5, 0x7a, 0x67, 0xfb, 0xdf, 0xb3, 0xea, 0xba, 0x84, - 0xcf, 0xc9, 0x2a, 0xcd, 0x1e, 0x47, 0x14, 0x29, 0xab, 0x43, - 0x7f, 0x93, 0x4b, 0x1c, 0x2d, 0xea, 0x92, 0x1a, 0x34, 0x19, - 0x63, 0x83, 0x3c, 0x71, 0xc8, 0xda, 0x92, 0xd7, 0x14, 0x7e, - 0x61, 0xd8, 0xfe, 0x83, 0x07, 0x1a, 0xf6, 0x82, 0xd4, 0x60, - 0xbf, 0xa8, 0x53, 0xd1, 0x5a, 0x0d, 0x7f, 0x14, 0x4d, 0x38, - 0xa9, 0x25, 0xc4, 0x7b, 0x41, 0xb3, 0xa1, 0x7a, 0xa0, 0x22, - 0x08, 0xd9, 0x84, 0x52, 0x22, 0xc8, 0x0b, 0x6c, 0xc7, 0xb8, - 0xb7, 0x57, 0x31, 0xdf, 0xfe, 0xe4, 0x7a, 0x1e, 0x74, 0xeb, - 0xc8, 0xef, 0x4a, 0x6b, 0x75, 0x78, 0x76, 0x5c, 0x58, 0x0f, - 0x1c, 0xac, 0x10, 0x6d, 0x34, 0xed, 0xd4, 0x17, 0x6e, 0xd6, - 0x45, 0xc2, 0x7b, 0x3a, 0x19, 0x46, 0x39, 0x53, 0xb3, 0x59, - 0xeb, 0x57, 0x90, 0xdf, 0x9d, 0x76, 0x2a, 0x40, 0x1c, 0x54, - 0x52, 0x4b, 0x11, 0x97, 0x6d, 0x72, 0x36, 0x89, 0x12, 0x25, - 0x64, 0x18, 0x3d, 0x70, 0xbb, 0xb2, 0xe0, 0x15, 0x4e, 0x8b, - 0x09, 0x56, 0x53, 0xd5, 0x44, 0x17, 0x3d, 0x44, 0x4a, 0xe9, - 0x64, 0x10, 0x24, 0x58, 0x17, 0x76, 0xfb, 0x29, 0x36, 0x23, - 0xab, 0x25, 0xd4, 0xf9, 0x03, 0x38, 0x82, 0x12, 0x96, 0x72, - 0x0d, 0x81, 0xf2, 0xb4, 0xca, 0x2d, 0x28, 0xfc, 0x82, 0xd9, - 0x58, 0x7f, 0x3f, 0x39, 0xdb, 0x3f, 0xbb, 0x38, 0x3d, 0x3a, - 0x3c, 0x3d, 0xbb, 0x38, 0x3e, 0xbf, 0x38, 0x3d, 0xa5, 0xe3, - 0xfc, 0x29, 0xeb, 0x0d, 0xbb, 0x88, 0xa1, 0xf1, 0x4e, 0x1f, - 0xbf, 0x5c, 0xcd, 0x3e, 0x9d, 0x1f, 0xff, 0x96, 0xed, 0x10, - 0xa5, 0x2b, 0x45, 0x3c, 0xee, 0x2b, 0xf1, 0xfb, 0xc1, 0xf1, - 0xc1, 0xc9, 0xc5, 0xe1, 0xe9, 0xc9, 0xd1, 0xc9, 0xf9, 0xc5, - 0xd9, 0xc5, 0x11, 0x6b, 0x4b, 0xc6, 0x0b, 0x79, 0xff, 0x6e, - 0xab, 0x2d, 0x8f, 0x34, 0xe2, 0x51, 0x8c, 0x7f, 0xcc, 0x20, - 0x5d, 0x7d, 0x73, 0x4e, 0x84, 0xf0, 0xf8, 0xfe, 0x3e, 0x02, - 0xb1, 0xe1, 0x43, 0x1d, 0xec, 0xd1, 0xf8, 0xb8, 0x6e, 0x44, - 0x74, 0xa7, 0x10, 0x05, 0x76, 0x14, 0x37, 0xa5, 0xf9, 0xaa, - 0xd0, 0x74, 0x82, 0x67, 0xbf, 0x29, 0xcd, 0xcd, 0xa3, 0x5b, - 0x7b, 0x86, 0xa7, 0x41, 0x4c, 0x41, 0x1a, 0x9e, 0x40, 0x68, - 0xbc, 0x18, 0x70, 0xd5, 0x47, 0xcd, 0x76, 0x2d, 0xa8, 0xde, - 0x23, 0xd7, 0xd1, 0x0c, 0xf6, 0xbf, 0xd8, 0xcf, 0x66, 0xfe, - 0x8b, 0xfd, 0xec, 0xd6, 0xec, 0x5a, 0x68, 0xcd, 0x26, 0x6a, - 0x6b, 0x6c, 0x5e, 0x5b, 0x68, 0xcd, 0x96, 0xfb, 0x2e, 0x38, - 0xbb, 0x4f, 0x38, 0x84, 0xd5, 0x78, 0x79, 0x81, 0xe2, 0xce, - 0x07, 0x76, 0x68, 0xb0, 0x40, 0xb1, 0x66, 0xda, 0xf8, 0x53, - 0x46, 0x1d, 0xbb, 0x5d, 0xbb, 0x75, 0x3c, 0x67, 0xd4, 0xf1, - 0xfa, 0xda, 0x6e, 0x1d, 0x9b, 0xda, 0xf3, 0x66, 0xfa, 0x0f, - 0x50, 0x68, 0xf3, 0x76, 0x20, 0x9b, 0xcd, 0x4b, 0x53, 0x2d, - 0xe9, 0x8f, 0x56, 0x9b, 0xb3, 0x6b, 0xda, 0x9c, 0xb0, 0xd5, - 0xe6, 0xbc, 0x36, 0x6d, 0x4e, 0xf4, 0xf4, 0xc2, 0x6d, 0x85, - 0x21, 0xb0, 0xd7, 0x9c, 0xfc, 0x57, 0xe3, 0xe3, 0x08, 0x49, - 0xe3, 0xdf, 0x1a, 0x1e, 0x64, 0x9f, 0x76, 0x79, 0x35, 0xdc, - 0x1a, 0x1f, 0x2d, 0x28, 0x9a, 0x1b, 0x57, 0xf0, 0x9a, 0x57, - 0xc1, 0x37, 0xe3, 0x63, 0x17, 0xca, 0xe9, 0x6a, 0x15, 0x94, - 0x68, 0x40, 0x03, 0x60, 0x7f, 0x17, 0x1d, 0x4f, 0xb1, 0xde, - 0x91, 0xd8, 0x1d, 0xd0, 0x5b, 0x43, 0x78, 0x5d, 0xfd, 0x02, - 0x6e, 0x30, 0xeb, 0x0f, 0x6b, 0xdb, 0x4f, 0xc6, 0x28, 0x08, - 0x53, 0xb2, 0x9d, 0xa0, 0x06, 0x45, 0xc6, 0x58, 0x0e, 0x35, - 0x51, 0x3e, 0x1a, 0x29, 0xc6, 0x13, 0xfa, 0x8d, 0xaf, 0x65, - 0x0c, 0x41, 0xf7, 0xab, 0xb1, 0x0b, 0x22, 0x69, 0x04, 0xac, - 0xe4, 0x61, 0x73, 0xcb, 0xdb, 0xc2, 0x4c, 0x0d, 0x37, 0x07, - 0xfb, 0xf0, 0x1d, 0x10, 0x3e, 0xa3, 0xe3, 0x81, 0xc1, 0x7c, - 0x64, 0xa3, 0xd2, 0xe1, 0x8f, 0x05, 0x58, 0x03, 0x15, 0xd2, - 0xa0, 0xbe, 0x7d, 0xbc, 0x6b, 0xce, 0x4d, 0x15, 0xa8, 0xc1, - 0x8e, 0x6d, 0x03, 0xdf, 0x93, 0xaf, 0xdd, 0x28, 0x2a, 0xf4, - 0x56, 0x9b, 0x24, 0x40, 0x09, 0xfc, 0x42, 0xa8, 0xd0, 0x3b, - 0x0e, 0x7d, 0xb0, 0x9c, 0x5a, 0x93, 0xc1, 0xad, 0x7a, 0xd3, - 0x89, 0xee, 0x5e, 0xa6, 0x60, 0xe3, 0xed, 0xf4, 0x6d, 0x59, - 0xd2, 0x9d, 0x3e, 0x6d, 0x2b, 0x8b, 0x11, 0xcd, 0x89, 0x17, - 0xd8, 0x68, 0xfa, 0xeb, 0x08, 0xe1, 0x28, 0x24, 0x34, 0x85, - 0xd0, 0x4b, 0x63, 0x48, 0x6a, 0x5f, 0x82, 0xee, 0x20, 0x35, - 0x38, 0xcd, 0x70, 0x96, 0x27, 0x76, 0x68, 0xd3, 0x7b, 0xf8, - 0x13, 0x7e, 0x03, 0x4a, 0xdf, 0x0b, 0x6c, 0x60, 0xe0, 0x82, - 0x18, 0x89, 0xa7, 0x9a, 0xb5, 0x33, 0x71, 0xd1, 0xcd, 0x24, - 0xf5, 0xaf, 0x63, 0xf0, 0x8c, 0xed, 0xe8, 0xd0, 0x5e, 0xad, - 0x96, 0x9b, 0x07, 0x9b, 0x1b, 0x66, 0xe6, 0xe6, 0xcc, 0x88, - 0x03, 0x43, 0x32, 0x15, 0x9a, 0x82, 0x89, 0xd0, 0xb8, 0xc2, - 0x85, 0x6b, 0x59, 0xb1, 0x0e, 0x37, 0x72, 0x5d, 0xd8, 0xc8, - 0x04, 0x2b, 0xc3, 0xff, 0x8f, 0x8d, 0x65, 0x7a, 0xc4, 0x35, - 0x8e, 0x91, 0xc4, 0xf3, 0xbf, 0xc8, 0x69, 0x27, 0x1d, 0x27, - 0x50, 0xc9, 0x75, 0xc7, 0x7e, 0xb2, 0x5d, 0x0f, 0xc5, 0xd4, - 0x27, 0x3c, 0xc6, 0x1f, 0x70, 0xae, 0x11, 0x37, 0x26, 0x04, - 0xff, 0xa8, 0xa5, 0x31, 0x16, 0x38, 0x05, 0xb5, 0xe8, 0x09, - 0xd4, 0xb1, 0x57, 0x8f, 0x40, 0x76, 0x48, 0xe1, 0xd7, 0xd6, - 0xf8, 0x65, 0x23, 0x27, 0x14, 0x16, 0x34, 0x98, 0xb1, 0x17, - 0x76, 0x1a, 0xac, 0xac, 0xd9, 0x7c, 0x3c, 0xb5, 0x52, 0xbe, - 0x28, 0x62, 0xd8, 0x49, 0xea, 0x93, 0xc1, 0xd8, 0xec, 0xaa, - 0x5b, 0x61, 0x60, 0x17, 0xc4, 0xc9, 0x77, 0x06, 0x96, 0x39, - 0x55, 0x96, 0x55, 0xc7, 0x03, 0x76, 0x58, 0x08, 0x6d, 0x73, - 0xab, 0x5c, 0x27, 0x76, 0x82, 0xcd, 0xce, 0x98, 0xf9, 0xf6, - 0x26, 0x7a, 0x0c, 0xe2, 0xe2, 0x2f, 0x97, 0xec, 0x02, 0x5b, - 0xb9, 0x3d, 0x64, 0x5f, 0x1b, 0x98, 0x16, 0xbb, 0x93, 0xd3, - 0xdb, 0x00, 0x92, 0x8a, 0x15, 0x52, 0x0e, 0x0f, 0x49, 0x6a, - 0xe4, 0x95, 0xa5, 0x58, 0x7d, 0x14, 0xa3, 0x4f, 0x1d, 0x0d, - 0x2c, 0x78, 0x78, 0x80, 0x9b, 0x9c, 0xc2, 0x91, 0x87, 0x7c, - 0xca, 0xf0, 0xeb, 0x5f, 0x91, 0x27, 0x19, 0xf4, 0x5d, 0x96, - 0x9f, 0x14, 0x03, 0xbf, 0xc3, 0xfe, 0x52, 0x08, 0xcb, 0x90, - 0xf6, 0xa3, 0x82, 0x73, 0x92, 0xc9, 0x3d, 0x3e, 0x0e, 0xd4, - 0xd1, 0xc0, 0x64, 0x2b, 0xdc, 0xd2, 0xf2, 0xa6, 0x8e, 0x27, - 0xa9, 0x8d, 0x83, 0xb4, 0x94, 0x93, 0xae, 0xe4, 0xa0, 0x35, - 0x9e, 0x4c, 0x58, 0x2b, 0x8f, 0xd2, 0xad, 0x0c, 0x36, 0x9b, - 0x1a, 0xad, 0xec, 0x2c, 0xa6, 0x53, 0x6b, 0x34, 0x5f, 0x8e, - 0xcc, 0xa1, 0xba, 0x34, 0x12, 0x50, 0x41, 0xea, 0x71, 0x04, - 0xab, 0x32, 0x10, 0xf8, 0xba, 0xbe, 0xcf, 0x48, 0x8a, 0xf6, - 0x89, 0xea, 0xc5, 0x54, 0x46, 0xb3, 0x68, 0x95, 0x10, 0xaf, - 0xc7, 0x64, 0x18, 0x0c, 0xec, 0xce, 0x6d, 0xec, 0x19, 0x24, - 0x70, 0xb8, 0xb9, 0xfa, 0x0c, 0x69, 0x5e, 0x06, 0xc1, 0x77, - 0xa8, 0x91, 0x23, 0x3f, 0x59, 0xb2, 0x56, 0xc4, 0x71, 0x37, - 0xd0, 0x5b, 0x83, 0xbe, 0xd6, 0x77, 0x12, 0xcb, 0xd5, 0xa1, - 0x07, 0x97, 0x48, 0x37, 0xa9, 0xed, 0x64, 0xd2, 0x1b, 0x2b, - 0xeb, 0x42, 0xf2, 0xab, 0xce, 0x85, 0xb1, 0x33, 0xa7, 0xa3, - 0xb4, 0x06, 0xfd, 0xc5, 0x0e, 0xfd, 0x42, 0x25, 0x5a, 0xf0, - 0x2f, 0x3a, 0xd4, 0x0c, 0xf8, 0xe8, 0x4c, 0xfb, 0x18, 0x12, - 0x49, 0x95, 0xe1, 0xa1, 0x8b, 0xe1, 0x50, 0x8a, 0x30, 0xae, - 0x2e, 0x17, 0x57, 0x0a, 0x6f, 0x76, 0xc1, 0xdd, 0xf6, 0x41, - 0x4b, 0x4a, 0x3f, 0x8a, 0x2e, 0xef, 0x73, 0x1e, 0x83, 0x5b, - 0x3f, 0xe2, 0x16, 0x01, 0xfc, 0x60, 0xa7, 0x67, 0x2e, 0xf1, - 0xf0, 0xcf, 0x3a, 0x92, 0x5e, 0x24, 0x34, 0xd7, 0xa5, 0xa2, - 0xc7, 0xb7, 0x8a, 0x94, 0x3f, 0x4e, 0x71, 0x6e, 0x4a, 0xcc, - 0x43, 0x9e, 0xfd, 0x8f, 0x12, 0x07, 0x64, 0x05, 0xb4, 0x80, - 0xfe, 0xe4, 0x1c, 0xdc, 0xa9, 0xcd, 0xc0, 0x57, 0x96, 0x2a, - 0xd7, 0xaf, 0x80, 0xbe, 0xf7, 0xab, 0xa0, 0x4f, 0x1c, 0xc8, - 0xfa, 0x84, 0x2e, 0x05, 0x58, 0xff, 0x12, 0x72, 0xb5, 0xc2, - 0xd3, 0xb0, 0x0d, 0xc4, 0x51, 0x2e, 0xaa, 0x20, 0x59, 0x93, - 0xa3, 0xe5, 0x91, 0x70, 0x62, 0x80, 0xa7, 0xca, 0x1a, 0x32, - 0xae, 0x7d, 0xee, 0x5d, 0x47, 0x28, 0x62, 0x53, 0x40, 0x27, - 0x50, 0x05, 0x9d, 0xc6, 0x4d, 0x53, 0x1d, 0x07, 0x70, 0xc8, - 0xd1, 0x3b, 0x85, 0x25, 0x4f, 0xc4, 0xe1, 0xb1, 0x77, 0x8a, - 0x93, 0x63, 0x15, 0xd3, 0xcf, 0xb4, 0x91, 0xba, 0x9b, 0xe7, - 0x7a, 0x5d, 0x80, 0x3f, 0x9a, 0xed, 0x6b, 0x5d, 0x00, 0x43, - 0xb8, 0x98, 0xa5, 0xd0, 0x66, 0xed, 0x6d, 0x11, 0x98, 0xf1, - 0xd4, 0x9a, 0x2d, 0x86, 0x56, 0x8a, 0x8f, 0x90, 0xc3, 0xbf, - 0x5e, 0x74, 0x9c, 0xcb, 0xcf, 0x4d, 0x3d, 0x04, 0x68, 0x3a, - 0x0f, 0x0c, 0x32, 0xce, 0x6d, 0xc8, 0x98, 0x8e, 0x17, 0xac, - 0x54, 0x09, 0xc3, 0xe3, 0xe4, 0xd1, 0x4b, 0x2e, 0x5e, 0x60, - 0x37, 0x9d, 0x4f, 0x77, 0xbb, 0xa6, 0xfe, 0xf5, 0x8d, 0x8e, - 0x34, 0xb7, 0xa3, 0xce, 0xd2, 0xfa, 0x6a, 0x75, 0x54, 0x1f, - 0x4c, 0x0c, 0xba, 0x03, 0x0c, 0x04, 0x56, 0xf1, 0xbb, 0xbe, - 0x26, 0x86, 0xa8, 0x49, 0xf6, 0x87, 0x14, 0x10, 0x73, 0x0d, - 0x82, 0x92, 0x16, 0x7a, 0x28, 0xc2, 0x68, 0xfc, 0x5e, 0x59, - 0x07, 0xc5, 0x04, 0x33, 0xfc, 0x2f, 0x09, 0x35, 0x07, 0x41, - 0x66, 0x6a, 0x93, 0x82, 0x72, 0x71, 0xfe, 0x4d, 0x3d, 0x35, - 0x41, 0xb1, 0x88, 0xa4, 0xd1, 0x2b, 0xa4, 0x64, 0x54, 0x24, - 0x25, 0xb4, 0xeb, 0x44, 0x94, 0x6c, 0x98, 0x16, 0x24, 0xbc, - 0xdd, 0xd4, 0x11, 0x94, 0x2b, 0xc4, 0x73, 0x12, 0x03, 0x36, - 0x11, 0x92, 0x28, 0x3d, 0x05, 0x41, 0x00, 0x48, 0x6e, 0x17, - 0x0e, 0x8f, 0xd4, 0xc6, 0xb2, 0x0a, 0x6a, 0x47, 0x9b, 0x31, - 0x38, 0x98, 0xce, 0x9c, 0x9d, 0x3d, 0xf6, 0x13, 0x97, 0x4e, - 0xf6, 0xce, 0xc0, 0x2f, 0xd5, 0x25, 0x94, 0x1b, 0x1f, 0xe4, - 0x6c, 0x91, 0xdb, 0x24, 0xbe, 0x89, 0x4a, 0xb4, 0x13, 0xe1, - 0x59, 0x96, 0x31, 0x1f, 0x67, 0x87, 0xd8, 0xcb, 0xd1, 0x4e, - 0xd6, 0x78, 0x1d, 0xe2, 0x88, 0x5c, 0xa6, 0xa4, 0x08, 0x8f, - 0xb2, 0xc8, 0xe1, 0x44, 0x23, 0x7b, 0x39, 0x21, 0x88, 0x18, - 0x45, 0x50, 0xc2, 0x1d, 0xce, 0xbe, 0x03, 0xce, 0x72, 0x65, - 0xc8, 0x1d, 0x3e, 0x84, 0x1a, 0x87, 0x12, 0x4e, 0x24, 0x4a, - 0xfa, 0x79, 0x6a, 0x10, 0x85, 0x22, 0x7a, 0x43, 0xc9, 0xdd, - 0xe7, 0x54, 0xbc, 0xe3, 0xa2, 0x06, 0xa7, 0xef, 0xac, 0x30, - 0x92, 0x12, 0x87, 0x52, 0xad, 0x05, 0x78, 0xb2, 0x21, 0x10, - 0x4b, 0x02, 0x9a, 0x6a, 0x2d, 0x32, 0x3b, 0xfb, 0x59, 0xc0, - 0x31, 0xad, 0x87, 0x0e, 0x23, 0x9a, 0xbc, 0x25, 0x2b, 0xb7, - 0x62, 0xe4, 0x76, 0x2a, 0x4e, 0xe1, 0x2c, 0xf0, 0xed, 0x90, - 0x58, 0xb9, 0xc9, 0x14, 0x5e, 0xa4, 0xa6, 0x10, 0x17, 0x31, - 0x48, 0x99, 0x1f, 0x3a, 0x87, 0xcf, 0xae, 0xc3, 0xb9, 0xf6, - 0x0b, 0xf9, 0x51, 0x89, 0x80, 0x07, 0xfc, 0x07, 0x4e, 0x61, - 0x40, 0x7f, 0x55, 0x22, 0x71, 0x07, 0x35, 0x59, 0x7c, 0x1e, - 0xa3, 0x46, 0x5d, 0xf6, 0x53, 0x26, 0x92, 0xfd, 0xed, 0xe6, - 0xc5, 0x93, 0xf2, 0x8a, 0x44, 0xc6, 0x04, 0x84, 0xf8, 0xe2, - 0x5a, 0x9d, 0x3c, 0x1d, 0x16, 0x60, 0x99, 0xe1, 0x78, 0xd4, - 0x01, 0xfb, 0x9d, 0x84, 0x4a, 0x8c, 0xea, 0x1f, 0x02, 0xe0, - 0xce, 0xb0, 0xbc, 0xbc, 0x9d, 0x5b, 0xcb, 0x89, 0x35, 0x5d, - 0x4e, 0xfa, 0x5f, 0x2d, 0x35, 0x71, 0xc2, 0x18, 0xee, 0x11, - 0x28, 0xed, 0x13, 0xee, 0x83, 0x9c, 0x26, 0x25, 0xad, 0x74, - 0xa5, 0x2f, 0x86, 0x46, 0x57, 0x06, 0x8a, 0xdc, 0x46, 0xde, - 0xfc, 0xc0, 0x31, 0xdc, 0xb5, 0x02, 0x4f, 0x27, 0x7f, 0xff, - 0x7f, 0x27, 0xd6, 0x95, 0xb2, 0x1b, 0xa3, 0x47, 0xf9, 0x14, - 0x0a, 0x97, 0x0e, 0x62, 0xdf, 0xa5, 0x78, 0xa9, 0x23, 0xf0, - 0x7c, 0xd3, 0x9b, 0x1d, 0xb6, 0x48, 0xac, 0x27, 0x1c, 0x91, - 0x8e, 0xfb, 0xcc, 0xe3, 0x73, 0x92, 0x25, 0x44, 0x5f, 0xeb, - 0xad, 0x1e, 0xf1, 0x64, 0x4a, 0x3f, 0x4c, 0x45, 0xfd, 0xee, - 0x95, 0x5a, 0x38, 0xf0, 0x97, 0x0a, 0xfc, 0xb9, 0x45, 0xd0, - 0xcf, 0x7f, 0xb4, 0xa5, 0x43, 0x30, 0x59, 0x1c, 0x64, 0x9b, - 0x2c, 0x2a, 0x5d, 0x7f, 0x5c, 0xc3, 0x35, 0x18, 0xc3, 0x75, - 0x19, 0xe7, 0xdd, 0x7d, 0x70, 0x97, 0x3a, 0xa1, 0x68, 0xed, - 0x18, 0x06, 0xd3, 0xf7, 0x83, 0x2d, 0x46, 0xe5, 0x21, 0xc4, - 0x0f, 0xb8, 0x73, 0x03, 0x7b, 0xa1, 0x1f, 0xe8, 0xb4, 0x8b, - 0x96, 0xa2, 0xf1, 0x8c, 0x66, 0xae, 0x18, 0xd5, 0x8e, 0x22, - 0x46, 0x04, 0xc9, 0xac, 0x23, 0x7c, 0xf8, 0x4f, 0x0e, 0xb8, - 0x2f, 0x4d, 0x90, 0xa1, 0x3d, 0xf9, 0x05, 0xd5, 0x06, 0xcf, - 0xbe, 0x14, 0x0c, 0x4d, 0x0c, 0xcf, 0xe4, 0x61, 0x8d, 0xdd, - 0xad, 0x25, 0x1f, 0x46, 0xe2, 0xdb, 0xf7, 0x2b, 0x78, 0x30, - 0xb6, 0xd1, 0x92, 0x4c, 0xff, 0x45, 0x95, 0x70, 0x75, 0x07, - 0xbe, 0x08, 0x01, 0x2c, 0xad, 0x80, 0x90, 0x8f, 0x89, 0xfd, - 0x6e, 0x7e, 0x36, 0x65, 0x2b, 0x82, 0xd2, 0x64, 0x2b, 0xe6, - 0x50, 0x5d, 0x31, 0x46, 0x52, 0x40, 0x0f, 0xe8, 0x87, 0x95, - 0x96, 0x5a, 0x5c, 0x73, 0xc1, 0x90, 0x8f, 0x97, 0xa2, 0xa8, - 0xa4, 0x04, 0x95, 0xfc, 0x31, 0xd3, 0x9b, 0x65, 0x81, 0xb4, - 0x2c, 0x0b, 0xa1, 0x55, 0x41, 0xd1, 0xf9, 0xed, 0x63, 0x0a, - 0xca, 0x29, 0xe3, 0x4e, 0xaf, 0x23, 0x7c, 0x28, 0x5c, 0x12, - 0x49, 0xd9, 0xd7, 0xf4, 0x2d, 0x40, 0xb3, 0x59, 0x9f, 0x4d, - 0x85, 0x60, 0xcf, 0x58, 0x01, 0x14, 0x3b, 0x32, 0x73, 0x1f, - 0x7c, 0x1c, 0x27, 0x1d, 0x62, 0xed, 0xa8, 0x06, 0x4e, 0x4c, - 0xce, 0x8d, 0x2e, 0x4d, 0x38, 0x95, 0xc5, 0xa8, 0x75, 0x2e, - 0x74, 0x6f, 0x66, 0x5f, 0xd8, 0x16, 0x72, 0x72, 0x2c, 0x66, - 0x09, 0x43, 0x85, 0xe0, 0x21, 0x1d, 0xc3, 0x39, 0x18, 0x5f, - 0x6c, 0x12, 0x0e, 0xe3, 0x06, 0xd5, 0x1a, 0x9f, 0xdf, 0xe4, - 0x1a, 0x46, 0x60, 0xd7, 0xff, 0x8e, 0x21, 0xaa, 0x59, 0x73, - 0x4f, 0x78, 0xc6, 0x2f, 0xff, 0xbb, 0x41, 0x5f, 0xfd, 0xac, - 0xd6, 0xcd, 0x50, 0xae, 0x43, 0xba, 0x6d, 0x8a, 0x60, 0xa4, - 0xa4, 0xa9, 0x3c, 0x99, 0xcf, 0x70, 0xa6, 0xd9, 0x46, 0x39, - 0x46, 0x5e, 0x0e, 0x8b, 0xaf, 0x68, 0x91, 0x87, 0xa7, 0xfb, - 0x60, 0x1b, 0x8b, 0x87, 0x7d, 0xfc, 0xb3, 0xc6, 0x86, 0x82, - 0x2f, 0x0a, 0x7c, 0x9e, 0xc4, 0xa6, 0x93, 0xfc, 0x6e, 0x2e, - 0xe4, 0xe0, 0x08, 0xce, 0x5f, 0xd8, 0x80, 0x9d, 0x09, 0x03, - 0xc6, 0xdc, 0xa6, 0xe2, 0x2a, 0x0a, 0x01, 0xf8, 0x83, 0x4b, - 0xa1, 0x3f, 0xb6, 0x08, 0xe7, 0x3a, 0x03, 0x5a, 0x40, 0xdb, - 0x0f, 0x45, 0xba, 0xff, 0x4e, 0xa1, 0x74, 0xbe, 0xe9, 0xb4, - 0x54, 0x83, 0x44, 0x6a, 0xdd, 0xc5, 0x0a, 0xce, 0xca, 0x34, - 0x99, 0x95, 0x73, 0x71, 0x56, 0xa8, 0xa4, 0xd3, 0xdd, 0x6b, - 0x70, 0x21, 0x19, 0x85, 0xb5, 0xde, 0xb8, 0xbd, 0x49, 0x1f, - 0xa5, 0xe8, 0xdd, 0x0b, 0xb1, 0x9b, 0x95, 0x90, 0xf3, 0xda, - 0xe5, 0xba, 0xa2, 0xf0, 0x7d, 0x2c, 0x48, 0x6a, 0x9e, 0x37, - 0xcc, 0x4e, 0xc7, 0x9a, 0x70, 0xe0, 0x03, 0xee, 0xef, 0xb6, - 0x02, 0x9b, 0xb8, 0x28, 0x17, 0xc4, 0xd4, 0xfa, 0xbf, 0x56, - 0x27, 0xed, 0x57, 0x30, 0x05, 0x08, 0x37, 0xbf, 0xe8, 0x43, - 0x8c, 0x3d, 0x37, 0x5d, 0x4c, 0xd2, 0xd6, 0x60, 0x8c, 0x38, - 0x17, 0x6e, 0x8b, 0xeb, 0x55, 0xa0, 0x1a, 0x8e, 0x64, 0x84, - 0xb9, 0xe2, 0x9a, 0xbb, 0x03, 0xd5, 0x0b, 0x00, 0xe5, 0x45, - 0x28, 0x4a, 0xb9, 0x68, 0x8e, 0x66, 0xc3, 0xfe, 0x7c, 0x9e, - 0xdc, 0x21, 0x9f, 0x28, 0x2e, 0x91, 0x71, 0x5c, 0x78, 0x91, - 0x3c, 0xb5, 0x3a, 0x56, 0xff, 0x26, 0xf9, 0xfa, 0x54, 0xd6, - 0x0c, 0x24, 0xdc, 0xd0, 0x4a, 0x91, 0xeb, 0x86, 0xe2, 0x34, - 0xa3, 0x9e, 0x5a, 0xcb, 0x30, 0x9c, 0x60, 0xc9, 0x84, 0x02, - 0x89, 0x12, 0xdf, 0x17, 0xef, 0x69, 0x39, 0x79, 0x3d, 0x30, - 0xb0, 0xd0, 0x7d, 0xe0, 0x3e, 0x79, 0x63, 0xfa, 0xeb, 0x57, - 0xb9, 0x30, 0xee, 0x87, 0xae, 0xe3, 0x6e, 0xd7, 0xc3, 0xe8, - 0x21, 0x11, 0x5e, 0x67, 0xfb, 0x8a, 0x8a, 0xe6, 0x18, 0xb4, - 0x54, 0x6e, 0xcf, 0x0b, 0xae, 0x75, 0x32, 0x7a, 0x9f, 0x81, - 0x2f, 0x55, 0x6d, 0x20, 0xda, 0xbf, 0x19, 0xc5, 0xe7, 0x3f, - 0xe5, 0x30, 0x27, 0xe4, 0x7d, 0xc8, 0x3b, 0x45, 0xe5, 0x59, - 0xfd, 0xf8, 0xe6, 0xc7, 0x4f, 0x64, 0xf5, 0xc9, 0xb5, 0x2f, - 0xc7, 0xf9, 0xac, 0x27, 0x8a, 0xc4, 0xd9, 0x81, 0xba, 0x78, - 0x1b, 0xcc, 0x7a, 0x08, 0xfe, 0x10, 0x60, 0xc5, 0xd8, 0xc5, - 0x58, 0x35, 0x58, 0xb1, 0x34, 0xfb, 0xc7, 0x9e, 0x04, 0x9f, - 0x1e, 0x07, 0x86, 0x87, 0xb7, 0xd5, 0x66, 0xd0, 0x88, 0x45, - 0xfa, 0x4a, 0x63, 0x4e, 0x7d, 0xb3, 0xa9, 0x9b, 0xbf, 0xa0, - 0x6d, 0x6e, 0xcb, 0x70, 0x2c, 0xce, 0xf8, 0x36, 0x41, 0x27, - 0x4d, 0xf6, 0x4a, 0xa7, 0x65, 0x7f, 0xee, 0x04, 0x46, 0xb4, - 0x15, 0x7c, 0x9b, 0x46, 0x80, 0x5f, 0x52, 0x7a, 0xdd, 0xf9, - 0x57, 0x94, 0xdf, 0x73, 0x51, 0x7f, 0xc7, 0x1e, 0x7f, 0x56, - 0x2f, 0xe7, 0xb7, 0x70, 0xb3, 0x8e, 0xa2, 0xfb, 0xad, 0xe7, - 0x19, 0xb1, 0x56, 0x54, 0x41, 0xae, 0x7f, 0x93, 0xf1, 0xfc, - 0x88, 0x2e, 0xd3, 0xe3, 0x70, 0x87, 0x4e, 0x7a, 0x90, 0xfd, - 0x62, 0xb6, 0x52, 0x12, 0xa7, 0xcd, 0x02, 0x10, 0xc6, 0x45, - 0x6a, 0x53, 0x66, 0xf1, 0xbf, 0x8f, 0x76, 0x64, 0xdc, 0x01, - 0xe0, 0x1b, 0x70, 0x94, 0xb7, 0x50, 0xda, 0xc2, 0xf3, 0xaf, - 0x66, 0x53, 0xd9, 0x16, 0xac, 0xec, 0xdb, 0x8c, 0xb0, 0x1b, - 0x19, 0x2b, 0xe2, 0x6c, 0xe7, 0xed, 0x60, 0x0d, 0xb8, 0xd5, - 0x6c, 0x67, 0x2e, 0x52, 0x05, 0xac, 0xaf, 0x93, 0xfe, 0x94, - 0x35, 0xf7, 0x44, 0xa1, 0xfa, 0xff, 0x46, 0xc6, 0x7c, 0x3e, - 0xc0, 0x8d, 0x06, 0x2f, 0x1b, 0x04, 0x7b, 0xfb, 0x7b, 0x72, - 0xee, 0x40, 0xbc, 0xb6, 0x42, 0x00, 0xe2, 0x28, 0x73, 0xf2, - 0xef, 0x7a, 0x5e, 0xf2, 0xc2, 0xa6, 0x46, 0x59, 0x22, 0x7b, - 0x6f, 0xd3, 0xda, 0xbb, 0x09, 0x40, 0x39, 0x40, 0x8a, 0x64, - 0xf4, 0xe8, 0x6e, 0x8a, 0x00, 0x6f, 0x0f, 0x78, 0x8a, 0x40, - 0xfc, 0x95, 0xc1, 0x3f, 0x53, 0x55, 0xd9, 0x52, 0xe7, 0x28, - 0x0c, 0x3a, 0x2d, 0xd9, 0x55, 0x09, 0xc9, 0xfa, 0x66, 0x55, - 0x0f, 0x9e, 0xd4, 0x23, 0xd1, 0xd9, 0x0a, 0x2e, 0x00, 0x9a, - 0xe0, 0x02, 0x1d, 0xe2, 0x23, 0xc3, 0x8c, 0x22, 0x94, 0x4c, - 0x8c, 0x9f, 0xa9, 0x8a, 0x14, 0xe6, 0x32, 0xb5, 0x1e, 0x5b, - 0x67, 0x71, 0x93, 0xd9, 0xd8, 0x1c, 0x28, 0x96, 0x5b, 0xf2, - 0x32, 0xb3, 0xa9, 0x14, 0xaa, 0xbe, 0xbd, 0xbe, 0x9b, 0x2b, - 0x51, 0x1c, 0x13, 0x6a, 0x38, 0x57, 0x39, 0x7b, 0xd1, 0x42, - 0x08, 0x49, 0xd7, 0x8d, 0xd4, 0xb8, 0x23, 0x37, 0xba, 0xb3, - 0x8b, 0x52, 0x4d, 0xe3, 0x60, 0x91, 0x0a, 0xe1, 0x23, 0xe8, - 0x88, 0x93, 0xe5, 0x02, 0x5c, 0xa0, 0xbd, 0x3f, 0x3e, 0xa8, - 0x7a, 0xfb, 0xa3, 0xed, 0x17, 0xc9, 0x95, 0x29, 0xd8, 0xa4, - 0x3c, 0x77, 0x8b, 0xe1, 0x60, 0x7b, 0xe1, 0x4a, 0x59, 0xd7, - 0x38, 0xf1, 0xa3, 0xd6, 0x5a, 0xc5, 0x53, 0x21, 0x66, 0x90, - 0x27, 0xcc, 0x11, 0xe1, 0xb9, 0xa6, 0x00, 0xb9, 0x2d, 0xf8, - 0x30, 0x22, 0xf3, 0x15, 0x9c, 0x3b, 0x7f, 0xc5, 0x6e, 0xf5, - 0xcf, 0x0f, 0x65, 0x03, 0x16, 0x7d, 0x59, 0x68, 0x0c, 0x94, - 0xe0, 0x1d, 0x0a, 0x4c, 0x81, 0x91, 0xf6, 0x2d, 0x87, 0x90, - 0x6d, 0x45, 0x5a, 0x90, 0x91, 0x41, 0x53, 0xa5, 0xd0, 0xa5, - 0xd2, 0xef, 0xb6, 0x80, 0x9a, 0x8a, 0x6c, 0xb4, 0xbe, 0x03, - 0x1c, 0xc1, 0x74, 0x7a, 0x7e, 0x24, 0x1a, 0x70, 0xd1, 0x4b, - 0xa3, 0x75, 0x1b, 0x6a, 0x25, 0x43, 0x5f, 0x3a, 0xe0, 0x9b, - 0x24, 0x69, 0xe6, 0x17, 0x41, 0x85, 0xb9, 0x9c, 0x6b, 0x5c, - 0x03, 0x69, 0xde, 0x85, 0x0a, 0xde, 0x04, 0xe7, 0xc7, 0xa9, - 0xab, 0x50, 0x1c, 0x60, 0x38, 0x83, 0x7b, 0x01, 0xc8, 0x09, - 0x6c, 0xbb, 0xb3, 0x23, 0xb0, 0x14, 0x4e, 0x04, 0x97, 0xf0, - 0xb7, 0xc1, 0x8e, 0x05, 0x79, 0x9e, 0x2f, 0x9a, 0x51, 0x5a, - 0x88, 0x72, 0xe0, 0xcb, 0x94, 0xd9, 0x11, 0xa1, 0x84, 0x74, - 0x29, 0x61, 0xf1, 0x54, 0x84, 0x29, 0x67, 0x1c, 0x8d, 0xaa, - 0xb3, 0x3e, 0x51, 0x61, 0x65, 0xaf, 0xd1, 0x74, 0xd6, 0x2c, - 0x51, 0xb9, 0x2d, 0x45, 0x26, 0x49, 0xbb, 0x14, 0x26, 0xd7, - 0xea, 0x64, 0x96, 0x92, 0x85, 0x7f, 0x22, 0x1a, 0x30, 0xe8, - 0xc5, 0xfb, 0xfb, 0x44, 0x36, 0x99, 0xc8, 0x36, 0xcf, 0x22, - 0x6a, 0x4e, 0x33, 0x32, 0x67, 0xa7, 0x39, 0x2b, 0x8e, 0x14, - 0xca, 0x15, 0xaf, 0xfc, 0xb8, 0x41, 0xac, 0x04, 0x48, 0x9e, - 0x51, 0x81, 0xea, 0xd4, 0xf3, 0x9d, 0x82, 0xda, 0x5e, 0x28, - 0xb8, 0xc3, 0x4d, 0x92, 0xdf, 0x65, 0xbe, 0x7b, 0xf9, 0x80, - 0x2b, 0x5f, 0x8d, 0x00, 0x23, 0x99, 0xe4, 0xf8, 0x3e, 0x55, - 0x44, 0x5a, 0xb9, 0x6d, 0x83, 0x5a, 0x12, 0xc7, 0xff, 0xad, - 0x98, 0x9a, 0xa3, 0x47, 0x4e, 0x32, 0xb3, 0x17, 0x53, 0xcc, - 0x61, 0xbb, 0xf4, 0xec, 0x52, 0xf6, 0x10, 0xe2, 0xbb, 0x19, - 0xc7, 0xc8, 0x51, 0x6d, 0x95, 0xfc, 0xc6, 0x10, 0x1d, 0x8a, - 0x63, 0x4f, 0xf8, 0xee, 0x2c, 0x9b, 0xef, 0x48, 0x99, 0x4a, - 0xa7, 0xdc, 0xb4, 0x49, 0xa1, 0xdc, 0xdb, 0x85, 0x7d, 0x2d, - 0xdf, 0xe1, 0x5e, 0x4f, 0xab, 0xf9, 0xbb, 0x54, 0x40, 0xef, - 0xe7, 0x9f, 0x64, 0x78, 0xdf, 0x16, 0x45, 0x26, 0x1c, 0xe6, - 0x45, 0x26, 0xe8, 0xd0, 0x11, 0x82, 0x2d, 0x8e, 0xf2, 0x82, - 0x2d, 0x2a, 0x39, 0xef, 0x22, 0x3c, 0x43, 0x29, 0xef, 0x1e, - 0x4b, 0xb6, 0x9c, 0x99, 0x77, 0x6f, 0x4f, 0x7b, 0x8b, 0x92, - 0x75, 0x81, 0xdc, 0x4d, 0x4a, 0x8f, 0xe7, 0x94, 0x54, 0x8f, - 0x84, 0xdf, 0xce, 0xe5, 0x8c, 0x91, 0x49, 0xfe, 0x4e, 0xfd, - 0x63, 0x63, 0x40, 0x05, 0xdd, 0x52, 0xbe, 0xf3, 0xe1, 0xf2, - 0x4f, 0xba, 0xfc, 0xa9, 0x96, 0x29, 0x4f, 0xeb, 0x1e, 0xae, - 0x9a, 0xfd, 0xad, 0xf0, 0x1a, 0xae, 0x56, 0x34, 0xd5, 0x3a, - 0x1d, 0x4f, 0x54, 0x31, 0xce, 0x35, 0xf3, 0x00, 0x71, 0xe7, - 0x4d, 0xc9, 0xb1, 0x29, 0x3b, 0xd3, 0x0d, 0x77, 0x11, 0x18, - 0x5c, 0x0e, 0x0c, 0x5a, 0xb4, 0x62, 0x46, 0x9a, 0x4b, 0x60, - 0xaf, 0x04, 0xfb, 0x60, 0x6e, 0xee, 0x49, 0xdd, 0x1d, 0x26, - 0x24, 0xad, 0xa0, 0x0c, 0x45, 0x7e, 0x68, 0xbb, 0xd8, 0x94, - 0x1d, 0xa8, 0xee, 0x3c, 0xd2, 0x5c, 0xd6, 0xff, 0x43, 0xb1, - 0xff, 0xb4, 0x27, 0x9d, 0xc0, 0xbf, 0x77, 0x1f, 0xb6, 0x61, - 0x3a, 0x17, 0x4b, 0x31, 0x0f, 0xdf, 0x51, 0xca, 0xd2, 0xb0, - 0x34, 0xb0, 0x7b, 0xbc, 0x3b, 0x62, 0x35, 0x71, 0x9e, 0xd7, - 0xc2, 0x76, 0x42, 0xdb, 0xc7, 0x72, 0xf5, 0x68, 0xfb, 0x3e, - 0xcf, 0x87, 0x44, 0x6e, 0x17, 0x03, 0x92, 0x47, 0xd0, 0x48, - 0x5e, 0xd6, 0x60, 0x64, 0xb4, 0xa9, 0xa8, 0xd4, 0xf1, 0x4e, - 0xd3, 0x84, 0x6a, 0x4c, 0xf2, 0xa6, 0x20, 0xe0, 0x9a, 0xa5, - 0x43, 0x12, 0x6c, 0x4b, 0x09, 0x55, 0xd0, 0x0b, 0x83, 0xbe, - 0xc8, 0xdc, 0x6b, 0xd7, 0x51, 0xbd, 0x85, 0x43, 0x96, 0x05, - 0x5b, 0x38, 0x47, 0xe2, 0xc2, 0xa9, 0xbb, 0x62, 0x0a, 0x23, - 0x9d, 0x9a, 0x04, 0x3a, 0x59, 0xf3, 0x65, 0xa7, 0x77, 0xa5, - 0x86, 0xb3, 0x81, 0xd8, 0x48, 0xb7, 0xb6, 0x4a, 0x64, 0x64, - 0x42, 0x53, 0xb8, 0xc6, 0x8e, 0xe1, 0xa1, 0xeb, 0x09, 0x34, - 0x20, 0xdc, 0x59, 0x4c, 0x39, 0x61, 0x59, 0x23, 0x41, 0x96, - 0x75, 0xdb, 0x80, 0x35, 0x1b, 0x2b, 0x25, 0xb7, 0x72, 0xe1, - 0xc1, 0x09, 0x4b, 0x9e, 0x28, 0x15, 0xdf, 0xc8, 0x65, 0x9f, - 0x28, 0xa1, 0xda, 0x8a, 0x6d, 0x64, 0xf8, 0x49, 0xd2, 0x7d, - 0xf1, 0x21, 0x0f, 0x87, 0x4b, 0x72, 0x90, 0x56, 0xbb, 0x33, - 0xce, 0x06, 0x81, 0x40, 0x03, 0x13, 0x81, 0x1a, 0x9b, 0x64, - 0x6e, 0xb3, 0x05, 0x06, 0xc4, 0x0d, 0x3f, 0x38, 0x48, 0x35, - 0x9c, 0x17, 0xa9, 0xce, 0xcc, 0x66, 0x03, 0x6e, 0x36, 0x2f, - 0xd3, 0xa9, 0xae, 0xcc, 0xbb, 0xa0, 0x42, 0x56, 0x1c, 0x4c, - 0x21, 0x81, 0xf8, 0x3f, 0x90, 0x88, 0xd4, 0x4b, 0x6c, 0x80, - 0x09, 0xce, 0xfb, 0x43, 0x6b, 0xbc, 0x50, 0x71, 0x81, 0x08, - 0x55, 0xa6, 0x13, 0x55, 0xa3, 0x68, 0x76, 0x3e, 0xa7, 0xee, - 0x86, 0x08, 0x3d, 0x73, 0xf5, 0xdd, 0x0f, 0x9e, 0x3d, 0xe0, - 0x3c, 0x54, 0x81, 0x77, 0x30, 0x47, 0x57, 0x29, 0x3c, 0x07, - 0xa4, 0x51, 0x18, 0xcc, 0x00, 0x5d, 0x89, 0x52, 0x3a, 0x49, - 0x02, 0x21, 0x56, 0x67, 0x04, 0x09, 0x41, 0x69, 0x04, 0x4f, - 0x65, 0xaa, 0x55, 0x47, 0x90, 0x50, 0x9c, 0x5a, 0x9d, 0x1b, - 0x36, 0x84, 0x67, 0x6a, 0x9f, 0x89, 0x0f, 0x83, 0x36, 0xc5, - 0xcb, 0xc5, 0xec, 0x56, 0xc9, 0xda, 0x35, 0x0c, 0x1c, 0xb0, - 0x46, 0xb7, 0x69, 0x97, 0xdb, 0x68, 0xa7, 0x4d, 0x68, 0x31, - 0x52, 0x12, 0xca, 0x5c, 0x70, 0x00, 0xb6, 0x88, 0x65, 0x90, - 0xe1, 0x39, 0x01, 0xf4, 0xf3, 0xd5, 0x8c, 0x97, 0xf3, 0xaf, - 0x49, 0xd4, 0xa0, 0xb4, 0x11, 0x3a, 0xdb, 0x15, 0xdc, 0x07, - 0x51, 0x8a, 0x9a, 0x2e, 0x88, 0x89, 0xa7, 0x91, 0x2e, 0xd5, - 0xe1, 0x8c, 0x49, 0x79, 0xe1, 0x7a, 0xc3, 0x77, 0x12, 0xc1, - 0x55, 0x81, 0xce, 0x52, 0xbc, 0xed, 0xe4, 0x69, 0xb8, 0x98, - 0x14, 0xc3, 0x64, 0x3f, 0x7d, 0x42, 0x07, 0xf3, 0x6d, 0xb5, - 0x06, 0xf2, 0xc5, 0x7c, 0x94, 0x47, 0xb4, 0xef, 0x43, 0xe9, - 0x53, 0x91, 0x2b, 0x11, 0x65, 0x1e, 0x98, 0x7a, 0x70, 0x9c, - 0x47, 0xbb, 0x5b, 0x25, 0x76, 0x16, 0x11, 0x95, 0xf2, 0x9c, - 0x1e, 0x9c, 0xe4, 0xd1, 0x65, 0x89, 0x4f, 0xab, 0x90, 0x9e, - 0x5d, 0x27, 0xe2, 0x91, 0x27, 0xb1, 0xc0, 0x04, 0x67, 0x8f, - 0x48, 0x72, 0x54, 0x9d, 0xb6, 0xa9, 0x75, 0x63, 0x4d, 0x67, - 0x70, 0x25, 0x71, 0xe1, 0x71, 0x70, 0xc6, 0x95, 0x43, 0x37, - 0x76, 0x11, 0x7e, 0xd8, 0x14, 0x6e, 0xfa, 0x61, 0x04, 0xe8, - 0x99, 0xa9, 0x46, 0xa8, 0x6e, 0x44, 0x13, 0xbd, 0x89, 0xd7, - 0x47, 0xf5, 0x0e, 0x0a, 0x8d, 0x0e, 0x4c, 0xd9, 0xc8, 0x08, - 0xf2, 0xec, 0xcc, 0x03, 0x3c, 0x41, 0xed, 0x6d, 0xb6, 0xf4, - 0xb2, 0x4c, 0xb0, 0x59, 0x1d, 0x1e, 0x1c, 0xa6, 0xf6, 0x5b, - 0x76, 0xa5, 0x46, 0x8b, 0x15, 0x68, 0x95, 0x95, 0x6a, 0x65, - 0x15, 0x1e, 0xe5, 0x55, 0x58, 0x41, 0x81, 0xf5, 0x52, 0x37, - 0x80, 0x39, 0x77, 0x7f, 0x74, 0x0a, 0x06, 0xcd, 0x74, 0x2b, - 0x74, 0xe7, 0xc7, 0x9a, 0x7f, 0x9c, 0x6a, 0x3e, 0xbe, 0x11, - 0xfc, 0xc7, 0xd6, 0xf6, 0x90, 0x65, 0x37, 0xdb, 0x0e, 0x0c, - 0xb8, 0x77, 0xf8, 0x04, 0x20, 0xf9, 0x58, 0xfb, 0x74, 0x1a, - 0x46, 0x08, 0x60, 0x59, 0x71, 0x8e, 0x4b, 0x5f, 0xbe, 0x39, - 0xc8, 0x1e, 0x90, 0x07, 0xb7, 0xef, 0xe8, 0xc1, 0xd4, 0xa1, - 0x56, 0x3d, 0x88, 0xe6, 0x6b, 0x5a, 0x4d, 0x9f, 0x3d, 0x67, - 0x7e, 0xfc, 0x55, 0xaf, 0x1a, 0x33, 0xed, 0x5b, 0x1b, 0x8a, - 0x08, 0x29, 0xe4, 0xba, 0x87, 0x6b, 0x3d, 0xf0, 0xb6, 0xe4, - 0x82, 0x13, 0x45, 0x5c, 0x0e, 0x5d, 0x7f, 0x1b, 0x83, 0xc6, - 0xd7, 0x89, 0x8a, 0x0d, 0x39, 0x07, 0xbc, 0xbf, 0x2c, 0x16, - 0x83, 0x84, 0x5d, 0xe4, 0x19, 0x78, 0x78, 0x84, 0x5c, 0x52, - 0xb0, 0x7a, 0xab, 0x87, 0xc0, 0x8e, 0xa0, 0x54, 0x76, 0x0c, - 0x16, 0xe3, 0x51, 0x70, 0x89, 0x7c, 0x53, 0x07, 0x46, 0x83, - 0x78, 0xe6, 0xe4, 0xf6, 0xe1, 0x50, 0xc1, 0xcb, 0x6a, 0xd4, - 0x07, 0x86, 0xb9, 0x55, 0xd0, 0x07, 0xb3, 0x46, 0x1f, 0xae, - 0x36, 0x51, 0xcf, 0x7d, 0xc9, 0xed, 0x42, 0x22, 0x6c, 0xae, - 0x26, 0x33, 0x03, 0x17, 0xd4, 0xed, 0x82, 0xeb, 0x08, 0x9c, - 0x7f, 0x93, 0xfc, 0x66, 0x07, 0x8b, 0xab, 0xde, 0x4d, 0x9e, - 0xdb, 0x5f, 0x59, 0x58, 0xd4, 0x8d, 0x39, 0xe8, 0x77, 0x97, - 0x5d, 0x93, 0xa1, 0x01, 0xee, 0xbf, 0xec, 0xef, 0xf3, 0xd0, - 0x28, 0x5c, 0x15, 0xba, 0x37, 0xd0, 0xdf, 0x39, 0x09, 0x41, - 0xa4, 0xd3, 0x0a, 0x04, 0x0f, 0x65, 0x82, 0x38, 0xc3, 0x72, - 0x35, 0x82, 0x93, 0xf1, 0x4c, 0xa0, 0x77, 0x2c, 0xd3, 0x9b, - 0x04, 0x91, 0x5b, 0x49, 0x67, 0x24, 0x34, 0x3b, 0xe3, 0x2b, - 0x81, 0xe6, 0xb9, 0x4c, 0xb3, 0x03, 0xa7, 0x06, 0x6e, 0xed, - 0x63, 0x84, 0xfe, 0x8e, 0x1c, 0x3d, 0x7c, 0xa7, 0x22, 0xf5, - 0x99, 0x48, 0xfd, 0x60, 0x5f, 0xa6, 0x4e, 0xd2, 0xf4, 0xd4, - 0x27, 0x7e, 0x6d, 0x76, 0x3a, 0x9c, 0xfa, 0xa1, 0x42, 0xfd, - 0x3a, 0x08, 0xdd, 0xd7, 0xc0, 0x8f, 0x09, 0x98, 0xea, 0x36, - 0xb4, 0x57, 0x3b, 0xc3, 0x82, 0xdb, 0xc3, 0xba, 0xfa, 0x44, - 0xde, 0x48, 0x15, 0x1d, 0x2b, 0x15, 0xdd, 0x20, 0x9f, 0xab, - 0x55, 0x0b, 0xd5, 0x5c, 0x77, 0x19, 0x8c, 0x10, 0xaa, 0xe6, - 0x3c, 0xbf, 0x3f, 0x5d, 0x97, 0x08, 0x61, 0x04, 0x6e, 0x38, - 0x09, 0xc1, 0xca, 0x8d, 0xaa, 0xcf, 0xfb, 0x8d, 0x58, 0x99, - 0x1c, 0x21, 0x27, 0xf6, 0xa9, 0x52, 0x55, 0x85, 0xd6, 0xba, - 0x5c, 0x9c, 0xbb, 0xab, 0xde, 0xbc, 0x09, 0x58, 0xd3, 0xa8, - 0x6b, 0x0e, 0x12, 0x45, 0x1d, 0x0d, 0x9c, 0xe0, 0x39, 0x08, - 0x55, 0x5f, 0xd3, 0xab, 0xa2, 0xa1, 0x77, 0xfb, 0xbd, 0x9e, - 0x85, 0x40, 0x0a, 0xfb, 0x59, 0x41, 0x92, 0x5d, 0xf7, 0x1e, - 0xfb, 0x6b, 0x43, 0xc5, 0xd7, 0xab, 0x92, 0xa5, 0xaf, 0x8b, - 0x0e, 0xa3, 0x9f, 0xc7, 0x1c, 0x58, 0x4f, 0x0c, 0xa0, 0xec, - 0x02, 0x1b, 0x3b, 0xed, 0x7c, 0x0f, 0xfc, 0x2a, 0x20, 0x95, - 0x43, 0x73, 0xb4, 0x30, 0x07, 0xcb, 0xfe, 0x68, 0xc2, 0x4e, - 0xcd, 0x90, 0x28, 0x3f, 0x02, 0xd9, 0xfe, 0x16, 0x2b, 0x06, - 0x9b, 0x0a, 0xe7, 0xe6, 0x59, 0x7f, 0xb8, 0x18, 0x98, 0xf3, - 0x3e, 0x83, 0x31, 0x17, 0x73, 0x91, 0xa6, 0xa0, 0xc0, 0x2b, - 0x4d, 0xfe, 0x36, 0x5e, 0x2d, 0x77, 0x18, 0xcd, 0x95, 0x1e, - 0x76, 0xe7, 0x1d, 0xe3, 0x16, 0xff, 0xae, 0x71, 0xe7, 0x84, - 0x88, 0xad, 0xe1, 0x42, 0x78, 0x14, 0xa9, 0x0d, 0xc9, 0x83, - 0xea, 0x56, 0x64, 0x44, 0xcd, 0xe1, 0xb6, 0x63, 0x44, 0xab, - 0x9b, 0xb6, 0x18, 0xeb, 0x52, 0x12, 0xbd, 0x34, 0x10, 0x29, - 0x7a, 0x61, 0x4e, 0x36, 0xba, 0xfa, 0x6e, 0x1a, 0xef, 0x37, - 0x20, 0xba, 0xa1, 0xe8, 0xf6, 0x5d, 0xf0, 0xc4, 0xc8, 0x1b, - 0xc0, 0xf3, 0xdc, 0x4d, 0x14, 0xb8, 0x4e, 0xa3, 0xd0, 0x74, - 0x28, 0x7f, 0x20, 0x9d, 0x98, 0x07, 0xa7, 0x93, 0x1b, 0x3d, - 0x34, 0xad, 0x33, 0xe1, 0x5d, 0x75, 0x86, 0x59, 0x05, 0x0f, - 0xfc, 0xaa, 0x33, 0xb5, 0xd1, 0x36, 0x4a, 0xb3, 0x12, 0x71, - 0xd2, 0xe9, 0x5d, 0xb6, 0x51, 0x92, 0x88, 0x47, 0x87, 0x9b, - 0x77, 0x4b, 0xb7, 0xa4, 0xea, 0xee, 0x82, 0x4f, 0x02, 0xf9, - 0x92, 0x4d, 0xa8, 0x3a, 0xf1, 0x47, 0x7b, 0xb5, 0xca, 0x68, - 0x7b, 0x7a, 0xdf, 0x6e, 0xc0, 0x2e, 0x4f, 0x42, 0x1d, 0x05, - 0x9a, 0x41, 0x6b, 0x17, 0xb9, 0xd6, 0xd6, 0x03, 0xa1, 0x89, - 0x52, 0xed, 0x45, 0xb9, 0x3a, 0x37, 0x4f, 0x8a, 0x8c, 0x0a, - 0x1b, 0xac, 0xb4, 0x96, 0xe2, 0x2d, 0x4a, 0x34, 0x9a, 0x88, - 0x1a, 0x6b, 0xae, 0x0d, 0xae, 0xf8, 0x9b, 0x65, 0x6b, 0xf2, - 0x3c, 0xd2, 0x81, 0x66, 0xc2, 0xa3, 0x49, 0x8e, 0x26, 0x8c, - 0xb9, 0xd5, 0x46, 0x23, 0x9a, 0xa4, 0x66, 0xba, 0xb5, 0x9f, - 0x49, 0x13, 0x8c, 0x8f, 0xf3, 0x70, 0x0b, 0x7e, 0x6b, 0xdc, - 0x92, 0xe5, 0xda, 0x7e, 0xf0, 0x41, 0x8c, 0xb8, 0xa6, 0x79, - 0x93, 0x86, 0x94, 0x56, 0xb5, 0x66, 0xe9, 0xb3, 0x7a, 0x17, - 0x78, 0x68, 0xfa, 0x72, 0xf8, 0xfd, 0x24, 0x8b, 0xdf, 0x0d, - 0xfa, 0xcd, 0xcf, 0xe2, 0x7a, 0xee, 0x2f, 0xd8, 0x6c, 0xaa, - 0xb8, 0xa7, 0x60, 0x33, 0x3a, 0xdc, 0x47, 0xb0, 0xe1, 0x4a, - 0xc2, 0x7e, 0xa8, 0x60, 0x23, 0xc7, 0x5e, 0x82, 0x2a, 0x6e, - 0xa9, 0xa5, 0x00, 0x2e, 0x38, 0x5f, 0x13, 0x4f, 0xaa, 0x95, - 0x33, 0xed, 0xa7, 0x79, 0x09, 0x9e, 0x7e, 0xe9, 0x49, 0xd7, - 0xdc, 0x77, 0x35, 0xa6, 0x5d, 0x93, 0x92, 0xc6, 0xc4, 0xd7, - 0xca, 0xe7, 0x64, 0x4a, 0x59, 0x8d, 0x73, 0xe6, 0xe8, 0x4c, - 0x8c, 0x97, 0xe7, 0xa5, 0x7f, 0xd5, 0xf9, 0xd1, 0xcf, 0xc3, - 0x5c, 0x36, 0x3f, 0xfa, 0x94, 0xca, 0xe6, 0x27, 0x97, 0x52, - 0x59, 0xc6, 0x51, 0x2a, 0x93, 0x7b, 0xd8, 0x14, 0x96, 0x37, - 0x41, 0xfc, 0x82, 0x93, 0x16, 0x37, 0x68, 0xf9, 0x5f, 0x75, - 0x8a, 0xae, 0x5a, 0x99, 0x9e, 0xab, 0x56, 0xa6, 0xe6, 0xaa, - 0x8e, 0xbd, 0x14, 0x2b, 0xe5, 0xa5, 0xc2, 0xed, 0x42, 0x8c, - 0x7d, 0xf3, 0x9d, 0xaa, 0xb2, 0xad, 0xdc, 0x7e, 0x7a, 0x83, - 0x2c, 0x1e, 0xb5, 0x50, 0xa5, 0x6e, 0xac, 0xc1, 0xf2, 0x6b, - 0xda, 0x5a, 0xf2, 0x15, 0x23, 0x23, 0x06, 0x3e, 0xb2, 0x31, - 0xbb, 0x91, 0x81, 0x5b, 0x90, 0x1f, 0x83, 0x86, 0x88, 0xdc, - 0xa6, 0xad, 0x23, 0xb7, 0x95, 0x89, 0x7c, 0x4b, 0x1b, 0x2f, - 0xbe, 0x15, 0x11, 0x69, 0x28, 0x1e, 0xda, 0x12, 0x0e, 0x6d, - 0x89, 0x86, 0x1a, 0x1c, 0xf8, 0x05, 0xa5, 0x7d, 0x2b, 0x63, - 0x40, 0x8e, 0x77, 0x81, 0x8b, 0xbf, 0xf3, 0xdf, 0x3b, 0xff, - 0xb5, 0xc5, 0x7f, 0x8c, 0x95, 0x0a, 0x95, 0xfa, 0x53, 0x7e, - 0x1f, 0xc3, 0x92, 0x52, 0xfe, 0xe2, 0x0a, 0xfd, 0x5f, 0x63, - 0x72, 0xba, 0x6e, 0x14, 0xdb, 0x18, 0xa1, 0x24, 0x67, 0x5e, - 0x0e, 0x85, 0x60, 0x69, 0x5a, 0xb2, 0x25, 0x89, 0xd0, 0xbd, - 0x69, 0x00, 0x0a, 0x8b, 0x6f, 0x39, 0x52, 0xb8, 0xb0, 0x64, - 0xe9, 0x55, 0xba, 0x29, 0x51, 0x5c, 0x05, 0x6f, 0x8a, 0x28, - 0x14, 0x1b, 0x4e, 0x57, 0x54, 0xd9, 0x95, 0xbd, 0x51, 0x09, - 0x37, 0xce, 0x44, 0xb4, 0xaa, 0x41, 0x52, 0x54, 0xcf, 0x21, - 0x35, 0xcb, 0xf1, 0x75, 0xbd, 0x5c, 0x51, 0x37, 0x65, 0xb9, - 0xba, 0x4b, 0xf8, 0x8a, 0x39, 0x30, 0x27, 0xde, 0xaf, 0x6b, - 0xd5, 0x71, 0xb9, 0x66, 0xbd, 0xd9, 0x17, 0xcd, 0x9c, 0x31, - 0xda, 0x32, 0x7a, 0x49, 0xa8, 0xf3, 0x39, 0x7c, 0x79, 0x94, - 0x09, 0x51, 0xdf, 0xe0, 0xbe, 0x5c, 0x0b, 0xea, 0xbe, 0x7a, - 0x5f, 0x26, 0xc8, 0x2f, 0xad, 0xa8, 0x23, 0xc7, 0x3c, 0x58, - 0x91, 0x95, 0x6c, 0xd0, 0x0b, 0x4e, 0x24, 0x4b, 0x46, 0x3c, - 0x4e, 0x6a, 0x65, 0x12, 0x25, 0xe1, 0x07, 0x39, 0xed, 0x3f, - 0x51, 0xa2, 0x14, 0x1a, 0x34, 0xbe, 0x6a, 0x9c, 0x83, 0x4e, - 0xbb, 0xc7, 0x34, 0x9c, 0x91, 0x34, 0xf6, 0x54, 0x6a, 0xac, - 0xc1, 0x5e, 0x36, 0x68, 0xf3, 0x58, 0x0a, 0x97, 0x6c, 0xde, - 0xe8, 0x19, 0x52, 0xff, 0x29, 0xd8, 0x7e, 0xce, 0x88, 0x9f, - 0x09, 0x48, 0x81, 0xbe, 0xc3, 0xf2, 0xcf, 0x56, 0xef, 0x03, - 0x0a, 0xb0, 0xde, 0x22, 0x87, 0x54, 0x89, 0x4e, 0x7b, 0x19, - 0xa0, 0xb1, 0x26, 0xd9, 0x05, 0x7e, 0x54, 0xa4, 0x77, 0x9e, - 0xcb, 0x7a, 0x67, 0x52, 0xbc, 0x41, 0x77, 0x14, 0x4a, 0x59, - 0x1d, 0xfa, 0xfe, 0xb0, 0xb7, 0x46, 0xff, 0xd6, 0x71, 0xe2, - 0x91, 0x52, 0x6c, 0xe4, 0xf4, 0xea, 0x22, 0x3b, 0x21, 0x47, - 0x13, 0x77, 0x1e, 0xad, 0xcc, 0x1e, 0x35, 0xf8, 0x0d, 0x6e, - 0x78, 0x7e, 0x41, 0x57, 0x38, 0x34, 0x1c, 0x2f, 0xd9, 0xa0, - 0x1b, 0x9c, 0x48, 0x43, 0x4c, 0xd9, 0x2f, 0x6e, 0xc9, 0x32, - 0xe1, 0xe8, 0x66, 0xa8, 0x68, 0xa5, 0x55, 0xe2, 0xb8, 0x21, - 0x90, 0x00, 0x69, 0xba, 0xfc, 0x41, 0xa3, 0x6b, 0xbb, 0xdc, - 0x84, 0x1a, 0xf5, 0x2e, 0xeb, 0xe0, 0x5e, 0x75, 0xb7, 0xf5, - 0x08, 0xc0, 0x1c, 0xdd, 0x0c, 0x85, 0x27, 0xed, 0x2d, 0xe4, - 0x29, 0x40, 0xbe, 0x01, 0x4f, 0xe0, 0x7a, 0xbb, 0xa6, 0x3a, - 0x5c, 0xce, 0x90, 0x0b, 0x51, 0x3d, 0xe4, 0x0b, 0x83, 0x7f, - 0x52, 0x0f, 0xd7, 0x59, 0x06, 0x75, 0x49, 0x91, 0x35, 0xda, - 0x01, 0x28, 0x86, 0x4a, 0x1a, 0x0a, 0x14, 0x26, 0x28, 0x54, - 0xa4, 0x2b, 0x47, 0xca, 0x71, 0x02, 0x07, 0x96, 0x7f, 0x44, - 0x25, 0x7e, 0x6b, 0xec, 0x10, 0xd9, 0x04, 0x2a, 0x87, 0x36, - 0xf5, 0xd2, 0xf5, 0xed, 0xc4, 0xa7, 0xf8, 0xec, 0x38, 0xb3, - 0xb1, 0xa4, 0x4c, 0xf3, 0xe6, 0x36, 0x00, 0x8f, 0xe5, 0x49, - 0x2f, 0x72, 0x38, 0xe6, 0x54, 0xca, 0x8f, 0x41, 0x13, 0xbe, - 0xe8, 0x1d, 0xf9, 0x72, 0x3d, 0x8e, 0x66, 0x0d, 0x1c, 0x8e, - 0xfa, 0x5d, 0x6b, 0xd6, 0x31, 0x47, 0x6a, 0x44, 0x9d, 0xeb, - 0x80, 0x68, 0x65, 0x17, 0x21, 0xc8, 0x75, 0xae, 0xc7, 0xb3, - 0xf1, 0x62, 0xd4, 0xb5, 0x52, 0x49, 0x27, 0x56, 0x8f, 0x01, - 0xd9, 0x61, 0x41, 0x41, 0xba, 0xcc, 0xe1, 0x62, 0x30, 0xef, - 0x5f, 0x5a, 0xe6, 0x50, 0x09, 0x32, 0x1a, 0x6e, 0xbd, 0xd8, - 0x45, 0xfa, 0xbe, 0x5e, 0x16, 0xb8, 0x90, 0x20, 0xeb, 0x26, - 0xa7, 0xae, 0x1e, 0x7f, 0x90, 0x9d, 0x42, 0xfb, 0xfa, 0x55, - 0xcf, 0x59, 0xde, 0xf5, 0x97, 0x92, 0xfb, 0xfd, 0x10, 0x4a, - 0x71, 0x14, 0xb3, 0x2f, 0xb9, 0xe1, 0x6f, 0x6b, 0xa1, 0x59, - 0x20, 0x38, 0x00, 0x99, 0x36, 0xc5, 0x03, 0x68, 0x81, 0xf6, - 0x9d, 0x1b, 0x47, 0x4b, 0xc8, 0x73, 0xcb, 0x4d, 0xe0, 0xfa, - 0x1c, 0x14, 0x06, 0x3e, 0xc5, 0x0e, 0xce, 0x78, 0x9d, 0x4c, - 0xc8, 0xab, 0x4c, 0x8e, 0x81, 0xdf, 0xeb, 0x49, 0xf6, 0x95, - 0xed, 0x81, 0xe5, 0xbd, 0xbd, 0x8a, 0x39, 0x30, 0xed, 0x6c, - 0x85, 0xf6, 0xba, 0x07, 0xa3, 0x47, 0x9f, 0x56, 0x4f, 0xf0, - 0xfe, 0x93, 0x8e, 0x79, 0xed, 0xa3, 0xc6, 0x4c, 0xb6, 0x5e, - 0x94, 0x7b, 0x02, 0x3a, 0x4b, 0xf4, 0x59, 0x5a, 0xac, 0x76, - 0xd6, 0x14, 0xfc, 0x3d, 0x09, 0x83, 0x82, 0xfd, 0x97, 0xf2, - 0x15, 0x1e, 0x9e, 0x9d, 0x4b, 0xb5, 0x18, 0x49, 0xb1, 0x46, - 0xf9, 0xaf, 0x33, 0x22, 0x20, 0x27, 0x0d, 0x22, 0x20, 0xc7, - 0xbd, 0x9e, 0x22, 0x79, 0xd4, 0xc6, 0xe2, 0x12, 0x7b, 0xb9, - 0xf9, 0x94, 0xd4, 0x0c, 0x48, 0xea, 0xd7, 0xa3, 0x1a, 0xa9, - 0x1c, 0x7a, 0x5b, 0xe0, 0xd1, 0xc0, 0x83, 0x9c, 0x09, 0x4c, - 0xb4, 0x5d, 0x54, 0xb4, 0x4e, 0xb2, 0x81, 0xbc, 0xfd, 0xbe, - 0x6a, 0x3e, 0x87, 0x2c, 0x4c, 0xfe, 0x7b, 0x28, 0xbb, 0xb1, - 0x3e, 0x94, 0x57, 0x49, 0x27, 0x29, 0x23, 0xc7, 0x57, 0xd4, - 0xa9, 0x2f, 0xd8, 0xac, 0x03, 0x87, 0xbb, 0x92, 0x25, 0xec, - 0x61, 0x0c, 0xc9, 0xe3, 0x9c, 0x70, 0x99, 0xf9, 0x76, 0xe3, - 0x81, 0x9a, 0x31, 0x33, 0x57, 0x9b, 0x68, 0x64, 0x3f, 0x71, - 0xfc, 0xb3, 0x43, 0x01, 0xe4, 0x72, 0x32, 0x33, 0xe0, 0x3b, - 0x97, 0x86, 0xf8, 0x77, 0xf9, 0xe2, 0x55, 0x23, 0x4f, 0xe2, - 0xe0, 0x59, 0xfc, 0x68, 0xe8, 0x7a, 0x50, 0x5a, 0x00, 0x94, - 0x61, 0x30, 0xf1, 0x71, 0xfc, 0x02, 0xc0, 0xf7, 0xbc, 0x5d, - 0x64, 0x5d, 0x1b, 0x72, 0xb9, 0x05, 0x6f, 0x45, 0xc5, 0xf9, - 0xb0, 0x0d, 0xaf, 0xc3, 0x25, 0xe0, 0x89, 0xfc, 0x24, 0xcf, - 0xc3, 0x56, 0x5c, 0x0e, 0x69, 0x1d, 0x11, 0xb0, 0x33, 0xeb, - 0x80, 0xcf, 0x0d, 0x2f, 0x9f, 0x11, 0xd7, 0x7f, 0x5d, 0x5f, - 0xb8, 0x74, 0x0d, 0xc0, 0x5b, 0x26, 0x33, 0x3c, 0xb2, 0xba, - 0xc6, 0x28, 0x08, 0xe3, 0x47, 0xe1, 0x72, 0xaa, 0xc9, 0xe9, - 0x09, 0x11, 0x07, 0x22, 0x71, 0xcb, 0x8e, 0xe2, 0x16, 0x69, - 0x3b, 0x22, 0xed, 0x6e, 0xf0, 0xec, 0xb7, 0x44, 0x3b, 0x7d, - 0x8a, 0x34, 0x3e, 0x1e, 0x75, 0x7f, 0x6b, 0x46, 0xf4, 0x41, - 0xa2, 0x4a, 0x2f, 0xa1, 0x29, 0xf1, 0xc3, 0xa6, 0xc4, 0x1f, - 0x81, 0x2d, 0x26, 0x11, 0xbc, 0x26, 0x3f, 0x0b, 0x08, 0x6b, - 0x1f, 0xa8, 0x05, 0x0e, 0x24, 0x8d, 0xd5, 0x65, 0x3f, 0xcd, - 0x96, 0xaf, 0x84, 0x0a, 0xa8, 0x13, 0xef, 0x9e, 0xc1, 0xda, - 0xaf, 0x59, 0x57, 0x3d, 0x6f, 0x38, 0x94, 0x1f, 0x2a, 0x48, - 0x82, 0x7e, 0xa8, 0x64, 0x3f, 0x10, 0xb3, 0x47, 0x05, 0x3c, - 0x26, 0xa8, 0x2a, 0x94, 0x51, 0x36, 0xaa, 0xb7, 0xae, 0x63, - 0xb3, 0xb4, 0x69, 0xd7, 0x70, 0x58, 0xe7, 0xcd, 0x6e, 0x6f, - 0xb8, 0xa4, 0x6b, 0x16, 0x32, 0x58, 0x87, 0xca, 0xa1, 0xb8, - 0x4a, 0xb2, 0x92, 0x17, 0xe5, 0x5b, 0xd6, 0x64, 0xe3, 0x93, - 0xf1, 0xb5, 0x89, 0x40, 0xdb, 0xe5, 0xd3, 0xbd, 0x6d, 0x42, - 0xf7, 0x35, 0x9f, 0xee, 0xb7, 0x26, 0x74, 0xb1, 0x2f, 0xaf, - 0x44, 0x79, 0x1a, 0xc4, 0x76, 0xf1, 0x48, 0x54, 0xf4, 0xd1, - 0xcd, 0xa3, 0x7e, 0xdb, 0x8c, 0xfa, 0x26, 0x2a, 0x68, 0xf9, - 0xb7, 0x36, 0x59, 0x4f, 0x3c, 0x8b, 0x11, 0xce, 0x3b, 0x2a, - 0x3a, 0x94, 0x69, 0xf1, 0x1f, 0x3e, 0xfa, 0xd1, 0x54, 0xb4, - 0x85, 0xee, 0xba, 0xfb, 0x52, 0x55, 0x05, 0xf9, 0x6a, 0x75, - 0xc7, 0x0d, 0xd7, 0xcc, 0x62, 0x2f, 0x2a, 0x54, 0x7d, 0x4d, - 0x3f, 0x69, 0x71, 0x49, 0x43, 0x75, 0x75, 0x66, 0x13, 0x63, - 0x31, 0x19, 0xd7, 0x63, 0x05, 0x50, 0xd2, 0xcf, 0x0d, 0x00, - 0x8f, 0x6c, 0x9f, 0x27, 0x07, 0xa2, 0x34, 0x92, 0x7b, 0xe7, - 0xfa, 0xa9, 0x06, 0x66, 0x66, 0x12, 0x89, 0x26, 0x50, 0x07, - 0x15, 0x70, 0x3c, 0xe6, 0x4b, 0x4e, 0x23, 0x91, 0xe6, 0x08, - 0xbd, 0xa3, 0x88, 0x4e, 0x05, 0x4b, 0xed, 0x63, 0xe0, 0xd8, - 0x70, 0x76, 0x40, 0x77, 0x97, 0x7b, 0xde, 0xe6, 0x08, 0xbb, - 0x49, 0x69, 0x03, 0x17, 0x6f, 0x07, 0x35, 0x9a, 0x0e, 0xe6, - 0x64, 0x72, 0x59, 0xe7, 0x72, 0x25, 0x84, 0x1a, 0xfc, 0xd8, - 0xcd, 0x3d, 0x6a, 0x72, 0xa4, 0x59, 0x5c, 0xd2, 0xc0, 0x45, - 0x7f, 0x81, 0x76, 0xf7, 0xe0, 0x20, 0x16, 0x35, 0x3b, 0x31, - 0x71, 0xa0, 0x82, 0xbf, 0x4c, 0xab, 0xd1, 0x6d, 0x41, 0xa1, - 0x41, 0x9f, 0x03, 0x5e, 0x0a, 0x45, 0x5b, 0x6d, 0xf8, 0x68, - 0xbe, 0xa8, 0xc3, 0x26, 0x8f, 0x5e, 0x10, 0x06, 0x9b, 0xc7, - 0x9d, 0x97, 0x3f, 0xe4, 0xfc, 0x0a, 0x4e, 0x2c, 0xdc, 0x6a, - 0xe3, 0xff, 0xf9, 0xbf, 0x0f, 0x7b, 0x83, 0x3a, 0xdc, 0xe2, - 0x6d, 0x83, 0x10, 0x44, 0x2b, 0xe0, 0xe6, 0x7a, 0x52, 0xf3, - 0x70, 0x14, 0xa9, 0xf0, 0x2f, 0xc0, 0x34, 0x93, 0xc7, 0xdd, - 0x2a, 0x58, 0xed, 0xa0, 0x50, 0xcd, 0x6f, 0x3c, 0x37, 0x40, - 0x89, 0x85, 0x7f, 0x95, 0xc6, 0x83, 0x70, 0x17, 0x3f, 0x86, - 0x05, 0xcd, 0x3f, 0x94, 0x9a, 0xcf, 0x8b, 0xff, 0x02, 0x1d, - 0x20, 0xf0, 0x0b, 0xd3, 0xf8, 0x7b, 0x6e, 0xe3, 0x55, 0x04, - 0x06, 0x63, 0x3a, 0xff, 0xdc, 0x9a, 0xcf, 0xd6, 0xb4, 0x29, - 0x0a, 0x83, 0x02, 0x9a, 0x70, 0xd0, 0x18, 0x34, 0xe1, 0xd2, - 0x9c, 0x15, 0xa0, 0x30, 0x10, 0x90, 0xf6, 0xc1, 0xf5, 0x2f, - 0x80, 0xc4, 0x70, 0x63, 0x0d, 0xf2, 0x91, 0x18, 0x12, 0xcb, - 0x40, 0xab, 0xa1, 0xf7, 0x78, 0xe6, 0x6b, 0xaa, 0x3a, 0xa3, - 0xcc, 0xa0, 0xfb, 0x51, 0x95, 0x68, 0xfb, 0xf1, 0xe5, 0x2c, - 0xed, 0xb6, 0x3b, 0xbe, 0xd3, 0x47, 0xe9, 0xea, 0x0d, 0xc6, - 0xe6, 0x3c, 0xed, 0xb4, 0xdb, 0xf3, 0x02, 0x5b, 0x3f, 0xec, - 0xbd, 0xd7, 0xff, 0x9a, 0x64, 0x73, 0x14, 0x42, 0xe8, 0xe1, - 0xca, 0x00, 0xb5, 0x1c, 0xfd, 0x14, 0x53, 0x69, 0xa1, 0x79, - 0x54, 0x3f, 0xaf, 0x40, 0xa3, 0x08, 0x70, 0x29, 0xc9, 0x41, - 0x2b, 0xc1, 0xd7, 0x3c, 0xd9, 0x41, 0xcd, 0x60, 0x41, 0x39, - 0x3b, 0x42, 0x7b, 0x6d, 0x92, 0xa3, 0xc2, 0x71, 0x2d, 0x6f, - 0x16, 0x1a, 0xee, 0xab, 0x06, 0x0b, 0x62, 0x7e, 0x6c, 0x42, - 0x12, 0xa4, 0x48, 0x22, 0xa3, 0x63, 0x13, 0x8a, 0x4e, 0x8a, - 0x22, 0x32, 0x35, 0x36, 0x32, 0xba, 0x72, 0x93, 0x6b, 0xe2, - 0x8b, 0x5d, 0xd4, 0x71, 0x5d, 0x93, 0x28, 0x37, 0xb6, 0x26, - 0x64, 0x0b, 0x3a, 0xaf, 0x4d, 0xd5, 0x49, 0x3b, 0x8e, 0xe7, - 0x0f, 0x80, 0xae, 0x89, 0xf5, 0xcd, 0x40, 0x01, 0x5c, 0x3b, - 0x5c, 0x3e, 0xee, 0x92, 0xfb, 0xc3, 0xbe, 0x39, 0x35, 0xae, - 0x77, 0x9b, 0x20, 0x7e, 0x04, 0x91, 0x4c, 0x50, 0x1b, 0x2f, - 0x03, 0x51, 0x0c, 0x49, 0xf6, 0x71, 0x4e, 0x93, 0xa6, 0x23, - 0x6f, 0xe8, 0x16, 0xc3, 0xb2, 0xc6, 0x27, 0xf7, 0x4b, 0x39, - 0x2a, 0xc7, 0xb1, 0x9a, 0x66, 0x3e, 0x75, 0xeb, 0x94, 0xa3, - 0x7f, 0xe4, 0x65, 0xf5, 0x95, 0x2f, 0xbb, 0x99, 0x79, 0xd5, - 0x91, 0xbc, 0xa8, 0x93, 0xa7, 0xcc, 0xb0, 0x97, 0x0d, 0xda, - 0x57, 0x9e, 0xab, 0x42, 0xdc, 0x3f, 0x61, 0xbb, 0x89, 0x53, - 0x80, 0xbc, 0x91, 0x5a, 0x5f, 0xe7, 0x23, 0xf3, 0xa6, 0x4a, - 0x4e, 0x87, 0xf4, 0x36, 0xb4, 0x18, 0x0c, 0x14, 0xd3, 0x41, - 0x0f, 0x25, 0x28, 0xa4, 0x8d, 0xdf, 0x2b, 0xf8, 0xd4, 0xbc, - 0x9e, 0xce, 0x54, 0x44, 0xdb, 0x98, 0x0a, 0x7b, 0x66, 0x8b, - 0x4e, 0x52, 0x8d, 0xb2, 0x0c, 0x2a, 0x63, 0xdf, 0xdb, 0x15, - 0x93, 0x85, 0x4a, 0xce, 0xd4, 0xea, 0x29, 0xfe, 0x26, 0x89, - 0x14, 0x49, 0x11, 0x0c, 0x64, 0x82, 0x95, 0x42, 0x0c, 0xa2, - 0xc0, 0x7b, 0x02, 0xce, 0xf8, 0x65, 0xf7, 0x00, 0xf2, 0xb5, - 0xee, 0x13, 0x21, 0xd2, 0x80, 0x7c, 0x60, 0xb0, 0x2f, 0x5a, - 0x3e, 0xb5, 0x0d, 0xeb, 0x84, 0xbf, 0xba, 0xe1, 0x0c, 0x39, - 0x87, 0x17, 0xc6, 0xbf, 0x5e, 0xf0, 0x18, 0x65, 0x37, 0x34, - 0xc4, 0xf2, 0xad, 0xf6, 0xe0, 0xdf, 0xeb, 0x9c, 0xf5, 0x1f, - 0xc3, 0x20, 0x8e, 0x59, 0xca, 0x9e, 0xc3, 0x8b, 0xc4, 0x22, - 0xc1, 0x5f, 0x34, 0x6e, 0xa3, 0xb8, 0xab, 0xd7, 0x69, 0xe3, - 0xe4, 0x3a, 0x77, 0x60, 0x13, 0x7d, 0x79, 0x73, 0xfd, 0x86, - 0xe9, 0xcd, 0x4a, 0xfd, 0x20, 0x9d, 0x20, 0x17, 0xfa, 0xee, - 0xe2, 0x82, 0x7b, 0x29, 0xc2, 0x62, 0xf0, 0x98, 0x10, 0x53, - 0x28, 0xa9, 0x76, 0x27, 0xff, 0xa6, 0x1e, 0xde, 0x63, 0xc7, - 0x46, 0x42, 0xea, 0x5b, 0x10, 0x50, 0xd8, 0xc7, 0x23, 0xae, - 0xd4, 0x93, 0x57, 0x06, 0x79, 0x57, 0xf1, 0x26, 0x89, 0x7e, - 0x5b, 0x3f, 0x0b, 0xc6, 0x2b, 0xae, 0x95, 0x21, 0x60, 0x47, - 0x08, 0x7f, 0x12, 0xe0, 0xa6, 0xa4, 0xc1, 0x2e, 0x75, 0x49, - 0xda, 0x92, 0xef, 0xae, 0x9a, 0x41, 0xd2, 0xec, 0x10, 0x08, - 0xac, 0x9a, 0xe7, 0xa2, 0x6f, 0xe3, 0xf1, 0x70, 0x39, 0xb5, - 0x66, 0x96, 0x8a, 0x54, 0x3e, 0x85, 0x3b, 0x78, 0x4c, 0x07, - 0x71, 0xaf, 0xe8, 0xe3, 0xbe, 0xea, 0xa5, 0x83, 0x7b, 0xdb, - 0xf7, 0x4b, 0x3e, 0x4b, 0x03, 0x90, 0xe3, 0xef, 0xc6, 0xdb, - 0xb8, 0xe4, 0xc3, 0xd9, 0x9c, 0x41, 0xc1, 0x1d, 0x71, 0xec, - 0xb4, 0x60, 0x83, 0x9b, 0x9a, 0x93, 0x71, 0xbd, 0xf4, 0x6e, - 0x32, 0x86, 0x52, 0x63, 0x0b, 0xb7, 0x85, 0x10, 0x8e, 0xee, - 0x56, 0x80, 0x93, 0x3f, 0xda, 0x17, 0x33, 0x65, 0x1a, 0xac, - 0x94, 0x21, 0x14, 0xab, 0xc8, 0x60, 0x09, 0x89, 0xfa, 0x2c, - 0x26, 0xdd, 0x57, 0x26, 0xa7, 0x29, 0x81, 0x3f, 0x48, 0xd3, - 0x5a, 0xf2, 0x25, 0x86, 0xfd, 0xce, 0xb8, 0xbb, 0x3d, 0xe2, - 0xc7, 0x57, 0x34, 0x30, 0xef, 0xf7, 0xb7, 0xe9, 0x51, 0xa3, - 0x7e, 0x78, 0xb3, 0x6d, 0x78, 0x6f, 0xaf, 0x40, 0x17, 0xdc, - 0x7b, 0xcc, 0xe7, 0x9e, 0x0c, 0xe0, 0x91, 0x38, 0x80, 0xb4, - 0xb0, 0x41, 0x4b, 0x1b, 0x62, 0xf1, 0x1f, 0x3a, 0x98, 0x36, - 0xc1, 0x09, 0x4a, 0x90, 0x49, 0xbc, 0x56, 0xbd, 0x00, 0x48, - 0x9e, 0x29, 0x22, 0xc2, 0xa2, 0x24, 0x99, 0x2c, 0x19, 0x8f, - 0x63, 0x25, 0x19, 0x15, 0x2d, 0x95, 0x40, 0xfe, 0xd7, 0xf1, - 0x67, 0x0c, 0x5a, 0x4d, 0x4f, 0x32, 0xb5, 0x26, 0xe9, 0x8c, - 0x0e, 0x65, 0xd9, 0x6a, 0xf3, 0xd3, 0x9f, 0xe9, 0x78, 0x40, - 0x13, 0xd9, 0x1f, 0xc9, 0xc2, 0xff, 0x6d, 0x1c, 0xef, 0xa4, - 0xb9, 0xc9, 0xd1, 0x0a, 0x8e, 0xf6, 0x4f, 0xb2, 0x67, 0x49, - 0xc2, 0xde, 0xfe, 0xf0, 0xb3, 0xbb, 0x72, 0xb9, 0x8d, 0xe3, - 0xc0, 0xb7, 0x9e, 0x30, 0xe6, 0x30, 0x69, 0x37, 0x37, 0x2e, - 0xe1, 0x77, 0x06, 0x7d, 0xa9, 0x77, 0x7b, 0x8d, 0x3f, 0x91, - 0x09, 0x34, 0x10, 0x54, 0x19, 0x2a, 0x51, 0x01, 0x95, 0xb2, - 0x04, 0x3f, 0x2b, 0x47, 0x72, 0x0c, 0x3e, 0xda, 0x4f, 0x34, - 0xe1, 0x41, 0xa7, 0x9b, 0xeb, 0x0c, 0xfc, 0x63, 0xf3, 0xfa, - 0xcc, 0x17, 0xd3, 0xd1, 0x32, 0xed, 0x0c, 0x3c, 0xdf, 0x86, - 0x08, 0x24, 0xef, 0xde, 0x70, 0xdc, 0x68, 0x83, 0x13, 0x1f, - 0xed, 0x15, 0x12, 0x50, 0x15, 0x0d, 0xf2, 0xbd, 0x5f, 0xfe, - 0xb9, 0x90, 0xf2, 0xef, 0x50, 0x4a, 0xf9, 0x57, 0xfe, 0xe9, - 0x97, 0x69, 0x7f, 0x6e, 0xed, 0x2b, 0xfa, 0xc6, 0x97, 0xd0, - 0x8d, 0x51, 0xb6, 0x68, 0x1f, 0x18, 0xff, 0xcf, 0x7e, 0xc9, - 0xb7, 0x07, 0x4a, 0x1e, 0x13, 0xf1, 0xdb, 0x83, 0xca, 0xf9, - 0xe5, 0xb3, 0x13, 0xcb, 0xd7, 0x38, 0x9a, 0x04, 0xcf, 0x20, - 0x54, 0x72, 0xe7, 0x1c, 0x71, 0x2b, 0x3e, 0x7e, 0x2d, 0x24, - 0xce, 0x69, 0x81, 0x7d, 0x9a, 0xf8, 0x91, 0x4f, 0xbe, 0x4c, - 0x97, 0xdd, 0xf1, 0x17, 0x35, 0x8c, 0x85, 0xb4, 0x12, 0x9b, - 0xc7, 0x74, 0xad, 0xe7, 0x8c, 0x52, 0x3a, 0xa9, 0x0e, 0x27, - 0x56, 0x2b, 0x2f, 0x4c, 0x42, 0x18, 0x27, 0xc4, 0x61, 0x16, - 0xfa, 0xc3, 0x0c, 0xea, 0x38, 0x2f, 0x4e, 0x85, 0xac, 0x21, - 0xb3, 0xce, 0xb5, 0xd5, 0x5d, 0xca, 0x43, 0xc0, 0x75, 0x87, - 0xd5, 0x23, 0x70, 0xb6, 0x1e, 0xf2, 0x90, 0xaa, 0x35, 0x16, - 0x8b, 0x89, 0xc2, 0x9e, 0x84, 0xce, 0x62, 0x53, 0x91, 0x4a, - 0x3a, 0xc5, 0x0e, 0x23, 0x54, 0x6b, 0x34, 0x79, 0x9f, 0x59, - 0x03, 0x4f, 0x73, 0x7a, 0x9c, 0xdf, 0xd2, 0x32, 0x14, 0xb8, - 0x65, 0x08, 0xd6, 0xb6, 0xeb, 0x4b, 0xc9, 0x62, 0xa7, 0xf8, - 0x11, 0x3e, 0x45, 0x34, 0xc8, 0xb4, 0x8e, 0x5a, 0x28, 0x61, - 0xeb, 0xb2, 0x36, 0x3b, 0x55, 0x51, 0x3c, 0x74, 0x56, 0x71, - 0x87, 0xe4, 0xa4, 0x53, 0x76, 0x81, 0x0b, 0x79, 0x1e, 0x68, - 0xa1, 0x1a, 0xc1, 0x21, 0xbe, 0xcd, 0xfb, 0xc1, 0xa8, 0xd4, - 0x4f, 0x3f, 0x81, 0x44, 0x04, 0x56, 0xd4, 0x4f, 0x8b, 0x44, - 0x45, 0xa7, 0xb3, 0x7c, 0xa3, 0xdd, 0x66, 0x7c, 0x7f, 0xaf, - 0xcd, 0x84, 0x05, 0x9b, 0xce, 0x58, 0x7f, 0x95, 0xcd, 0xc7, - 0x57, 0x57, 0x03, 0x4b, 0x11, 0x07, 0xf3, 0xe0, 0xe1, 0xc1, - 0x03, 0x15, 0x97, 0xc3, 0x38, 0x77, 0xf1, 0x57, 0x6d, 0x13, - 0xa5, 0xc7, 0x86, 0xe8, 0x38, 0x87, 0x60, 0x85, 0xb1, 0x22, - 0x14, 0x05, 0x3b, 0xc2, 0x89, 0x6c, 0x47, 0x60, 0x94, 0x2b, - 0x88, 0x00, 0xf3, 0xc6, 0x52, 0x97, 0xbe, 0xfd, 0x04, 0x92, - 0x3c, 0x10, 0xc4, 0xd0, 0x5c, 0x27, 0x81, 0xcf, 0x0f, 0x5b, - 0x9e, 0x58, 0xcd, 0x17, 0xd7, 0xa8, 0xe0, 0xcf, 0x7b, 0xc4, - 0xd3, 0x0b, 0xe0, 0x62, 0x86, 0xbc, 0x4e, 0xb3, 0x9d, 0x7b, - 0x2b, 0x84, 0x8e, 0xe5, 0xd5, 0x7a, 0x90, 0x2d, 0x17, 0xca, - 0xeb, 0xcb, 0x97, 0x0a, 0xf5, 0xa5, 0x41, 0x24, 0x5e, 0x80, - 0xd0, 0x26, 0x70, 0x21, 0x30, 0x6b, 0x31, 0xee, 0xac, 0x0a, - 0x2f, 0xa7, 0x96, 0xfc, 0xd8, 0x6f, 0xee, 0xc9, 0x38, 0x00, - 0xce, 0x65, 0x88, 0x2e, 0x76, 0x7d, 0xb4, 0x0f, 0xd2, 0xc9, - 0xe0, 0x59, 0x6c, 0xad, 0xae, 0x21, 0xbe, 0xd6, 0x52, 0xb7, - 0xda, 0x99, 0x83, 0xb7, 0x38, 0x94, 0x60, 0x8e, 0xce, 0xec, - 0xf1, 0x91, 0xcc, 0xf4, 0x3f, 0xae, 0xdf, 0xe5, 0xf6, 0x9a, - 0xcc, 0xf6, 0x1e, 0x4b, 0x49, 0x48, 0xff, 0x5a, 0xb3, 0x04, - 0xbb, 0x34, 0xf9, 0x32, 0x64, 0x3d, 0x3d, 0x11, 0x7b, 0x8a, - 0x9f, 0x57, 0x35, 0x9d, 0x53, 0x51, 0xd2, 0xcc, 0xfe, 0x44, - 0xec, 0x0d, 0x3c, 0xd9, 0x15, 0xf9, 0x95, 0x1d, 0xa6, 0xf7, - 0xcf, 0xff, 0xd5, 0x53, 0xc8, 0x9c, 0x6d, 0xbc, 0x5b, 0xae, - 0x76, 0x2b, 0x6e, 0xd8, 0xea, 0xc2, 0x27, 0x46, 0x87, 0x3c, - 0xa9, 0x44, 0xbb, 0x4c, 0xec, 0xf2, 0xf1, 0xe4, 0xe6, 0xc5, - 0xf7, 0xb1, 0xd4, 0x19, 0xcb, 0xcc, 0x0b, 0x7b, 0xe5, 0xa6, - 0x3c, 0xdb, 0x26, 0xc5, 0x13, 0x7e, 0xa5, 0xee, 0xd0, 0xb5, - 0x86, 0xbd, 0xa5, 0x74, 0x15, 0x1f, 0x89, 0xaf, 0xce, 0x6f, - 0xbf, 0x42, 0xc2, 0x8a, 0x76, 0xda, 0x92, 0x99, 0xb2, 0x22, - 0x4d, 0xba, 0xba, 0x4b, 0xce, 0x8b, 0xb0, 0x2d, 0x23, 0xed, - 0xd0, 0x6f, 0xea, 0x87, 0xb4, 0x53, 0x08, 0x82, 0x86, 0x5e, - 0x48, 0xaf, 0x0a, 0x3d, 0xa7, 0xa1, 0x0f, 0x52, 0xb3, 0x1c, - 0x02, 0x34, 0xce, 0x27, 0x40, 0x49, 0x31, 0x5e, 0x0c, 0xfb, - 0xc5, 0x8d, 0x5a, 0x89, 0x54, 0xaa, 0x95, 0x4d, 0x40, 0x6e, - 0xcd, 0xae, 0x85, 0xd6, 0x34, 0x49, 0x2b, 0x20, 0xb7, 0xe6, - 0xb5, 0x85, 0xd6, 0x6c, 0x13, 0x33, 0x6f, 0xe0, 0xec, 0x3e, - 0x61, 0xaf, 0x4a, 0xe3, 0xe5, 0xa5, 0xad, 0x30, 0xda, 0x0c, - 0xe2, 0xbb, 0x5d, 0x4b, 0xc4, 0x9f, 0x33, 0x88, 0xbf, 0xbe, - 0xb6, 0xd5, 0xf2, 0x97, 0x1c, 0x40, 0x67, 0xe3, 0xab, 0xf1, - 0x11, 0x7b, 0xd3, 0x35, 0x8c, 0xa9, 0x7d, 0xda, 0xe5, 0x55, - 0x70, 0x6b, 0x7c, 0x44, 0x7e, 0x75, 0x4d, 0xe9, 0xbf, 0xe6, - 0xd1, 0xff, 0x66, 0x7c, 0x44, 0x66, 0xb3, 0x86, 0xf4, 0x37, - 0xb5, 0x79, 0x58, 0x85, 0xff, 0x47, 0x06, 0xb3, 0x97, 0x5c, - 0x26, 0xd6, 0x6c, 0xce, 0x1f, 0xad, 0x36, 0x67, 0xd7, 0xb4, - 0x39, 0x61, 0xab, 0xcd, 0x79, 0x6d, 0xda, 0x1c, 0x87, 0x00, - 0x33, 0x4a, 0x38, 0x8f, 0xf5, 0x85, 0xbb, 0xed, 0x25, 0x7b, - 0xa4, 0xe9, 0xa9, 0x30, 0x10, 0x8d, 0x13, 0xe6, 0x70, 0x15, - 0x28, 0x04, 0xf6, 0xba, 0x04, 0xf7, 0xfa, 0x88, 0xe7, 0x0d, - 0x15, 0x75, 0x21, 0xf4, 0x65, 0x55, 0x08, 0xec, 0x97, 0x2c, - 0x60, 0xea, 0xd4, 0x52, 0x6f, 0x86, 0x20, 0x2c, 0x52, 0x56, - 0xd6, 0x78, 0x33, 0x48, 0x61, 0x91, 0xb0, 0xb2, 0xb8, 0x9b, - 0x63, 0x0c, 0xd3, 0xec, 0xb8, 0x80, 0xe1, 0xf5, 0x91, 0x81, - 0x3f, 0xe4, 0xb0, 0xbd, 0xf4, 0x75, 0x7d, 0x24, 0xcb, 0x04, - 0x5e, 0x30, 0x92, 0x41, 0xf5, 0xd4, 0xb6, 0x93, 0xdb, 0xa3, - 0x32, 0x4f, 0xb9, 0x70, 0x0b, 0xa4, 0x96, 0x72, 0xa8, 0x59, - 0xf8, 0xa6, 0x7e, 0x23, 0x39, 0x83, 0x3d, 0xe5, 0xbb, 0xcd, - 0x69, 0xb7, 0x92, 0x7b, 0xd8, 0x2e, 0xfc, 0x15, 0x08, 0x63, - 0x74, 0x38, 0xde, 0xb1, 0x16, 0x1f, 0x0b, 0xfe, 0xac, 0xcc, - 0x0f, 0x57, 0x2c, 0x56, 0xcc, 0xc0, 0x37, 0x76, 0xe8, 0x22, - 0x40, 0x5f, 0xe3, 0x93, 0xf1, 0x62, 0x14, 0x3b, 0x7b, 0x54, - 0xd4, 0x36, 0x05, 0xca, 0xbb, 0x56, 0x28, 0xbf, 0x66, 0x50, - 0x7e, 0x6d, 0x85, 0xb2, 0x10, 0xf9, 0x2e, 0xd0, 0x46, 0xf9, - 0xa9, 0x5a, 0x8c, 0x7a, 0x17, 0x28, 0xe3, 0xac, 0x53, 0xad, - 0x85, 0xbc, 0x0b, 0x84, 0x6f, 0xed, 0xe7, 0x86, 0x64, 0x33, - 0x88, 0x5e, 0xed, 0xc2, 0xe0, 0x77, 0x3c, 0x1a, 0xc8, 0xd5, - 0x1c, 0xb4, 0xb0, 0xfb, 0xe6, 0x54, 0x41, 0x92, 0x71, 0xb5, - 0x51, 0x47, 0x98, 0x5b, 0x07, 0x4a, 0x6c, 0xd5, 0x46, 0x0d, - 0xdb, 0x8c, 0x1a, 0xde, 0x54, 0x2b, 0xce, 0xae, 0xa7, 0x7d, - 0x05, 0x39, 0xbb, 0x9e, 0xe7, 0xe7, 0x96, 0xea, 0xb9, 0x73, - 0xed, 0x68, 0x99, 0xcb, 0xbc, 0xc6, 0x25, 0x7c, 0xdd, 0x10, - 0xd3, 0x00, 0x55, 0x50, 0x3e, 0xff, 0xc5, 0x35, 0xd5, 0xda, - 0xfa, 0xb8, 0xfc, 0xe5, 0x00, 0x5d, 0x47, 0x3c, 0x81, 0x99, - 0x16, 0x38, 0x97, 0x3a, 0x3c, 0x6f, 0x31, 0x26, 0xcd, 0x07, - 0xe2, 0x47, 0xa6, 0xbf, 0x5c, 0xed, 0xec, 0x67, 0x01, 0xbd, - 0x2d, 0x76, 0xfd, 0x6d, 0xb0, 0x8d, 0x9a, 0x4b, 0x3a, 0xef, - 0xce, 0x5b, 0x86, 0xe0, 0x7f, 0x96, 0x14, 0x7d, 0x8b, 0x07, - 0xf9, 0x4d, 0xc1, 0xff, 0x50, 0x04, 0xbd, 0x9e, 0xeb, 0x21, - 0x67, 0xd4, 0x2c, 0xa0, 0x38, 0x2d, 0x98, 0xa5, 0x4d, 0x94, - 0xae, 0x61, 0x70, 0x39, 0x68, 0xaf, 0x86, 0xd5, 0x36, 0x8a, - 0x83, 0xf5, 0x32, 0x6b, 0x33, 0xef, 0xe0, 0x57, 0x06, 0x7e, - 0x72, 0xe7, 0x81, 0x14, 0x7e, 0x4b, 0x05, 0xf2, 0x3b, 0x0d, - 0xf2, 0xb7, 0xf5, 0xc9, 0xbf, 0x6a, 0x90, 0xff, 0xd6, 0xd8, - 0x53, 0x97, 0xc6, 0x52, 0xb3, 0x91, 0x67, 0xab, 0xf3, 0x34, - 0x15, 0x40, 0xcd, 0x4b, 0x68, 0x69, 0x7d, 0x6f, 0x98, 0x29, - 0x18, 0x1e, 0x4c, 0x22, 0xee, 0x59, 0x37, 0xa5, 0xbf, 0x92, - 0x78, 0xdf, 0x69, 0xed, 0x1b, 0x40, 0xf3, 0x72, 0x7c, 0x63, - 0x2d, 0xe7, 0xd7, 0x53, 0x6b, 0x76, 0x3d, 0x1e, 0xa8, 0x99, - 0x35, 0x4c, 0x1c, 0x5b, 0x39, 0x7f, 0x0c, 0x41, 0xf4, 0x18, - 0x78, 0xfa, 0xae, 0x38, 0x52, 0x9e, 0x8e, 0x03, 0x25, 0x4f, - 0x07, 0x1e, 0x0b, 0x5d, 0x4a, 0xa4, 0x7d, 0x43, 0xf3, 0xab, - 0x90, 0x46, 0xfd, 0x50, 0x6e, 0x1e, 0x83, 0x8d, 0xc5, 0x05, - 0x6a, 0xd0, 0x4d, 0xb2, 0xc0, 0x1f, 0xe5, 0xd0, 0x45, 0x05, - 0x74, 0xe9, 0x0e, 0xc6, 0xb3, 0xf9, 0x12, 0x76, 0x7e, 0x79, - 0xd9, 0x9f, 0x2b, 0x4e, 0x03, 0x83, 0x00, 0xc1, 0xcc, 0xd1, - 0xd0, 0x7a, 0x28, 0x6a, 0xe3, 0x16, 0x2e, 0x4b, 0xef, 0x3c, - 0x0c, 0x96, 0x8b, 0xb2, 0xee, 0x6d, 0x68, 0x32, 0x0e, 0xc2, - 0xcc, 0x67, 0x92, 0x90, 0x41, 0x65, 0x0c, 0xb1, 0x50, 0xc5, - 0x6b, 0x96, 0x4b, 0x60, 0xaf, 0xa0, 0x88, 0x62, 0xb7, 0x2c, - 0x24, 0x8d, 0x49, 0x03, 0xcf, 0x7c, 0x09, 0xf6, 0x57, 0x82, - 0xfb, 0xad, 0x65, 0x57, 0x10, 0x3a, 0xc6, 0xb3, 0x10, 0xb2, - 0x27, 0x6d, 0x2c, 0x92, 0x4e, 0xc7, 0x9a, 0x24, 0xbe, 0x6a, - 0xfb, 0x72, 0x2d, 0x15, 0x3c, 0xd4, 0x32, 0x17, 0xdb, 0x01, - 0x5f, 0xd5, 0x48, 0xdc, 0x40, 0x05, 0xeb, 0x93, 0x51, 0x77, - 0xdd, 0xcd, 0xfa, 0xa3, 0xab, 0xc5, 0x20, 0xe5, 0xc2, 0x29, - 0x50, 0x9e, 0xb9, 0xd4, 0x4e, 0x44, 0xd0, 0x8f, 0xf5, 0x01, - 0x8c, 0x96, 0xfd, 0x51, 0x6f, 0xac, 0xac, 0x13, 0x81, 0x2e, - 0x82, 0x32, 0xb2, 0xfc, 0x60, 0xfb, 0xf0, 0x68, 0xf4, 0xfd, - 0xfb, 0x20, 0x5c, 0xdb, 0x95, 0xa0, 0x12, 0xcc, 0xf9, 0x72, - 0xb6, 0x98, 0xf6, 0xcc, 0x8e, 0xa5, 0x2c, 0x1a, 0xa1, 0x8a, - 0x1b, 0xc2, 0xab, 0x86, 0x19, 0x33, 0xef, 0xff, 0xe6, 0x0b, - 0xa8, 0xfb, 0xe4, 0xa5, 0xf6, 0x81, 0xc4, 0xb9, 0xb3, 0x7b, - 0x33, 0xa8, 0xbc, 0x07, 0xa8, 0xa0, 0x0c, 0x48, 0xf6, 0x3f, - 0x25, 0xda, 0x32, 0xe3, 0xc5, 0xf9, 0xed, 0xc4, 0xaa, 0x99, - 0x15, 0xed, 0xea, 0x26, 0x8d, 0xad, 0x40, 0x2d, 0xb5, 0xbc, - 0x9e, 0x5c, 0x47, 0xdb, 0x9b, 0x34, 0xaa, 0x02, 0xc9, 0x9a, - 0x91, 0xfa, 0xf6, 0xa7, 0xec, 0x46, 0xfd, 0xd1, 0x68, 0x7c, - 0xc3, 0x17, 0x48, 0x92, 0xfe, 0x8d, 0xef, 0x20, 0x7e, 0xf0, - 0x44, 0x84, 0x4f, 0xb2, 0x38, 0x30, 0x20, 0x9d, 0xfe, 0xc6, - 0x24, 0x57, 0x70, 0x9b, 0xda, 0xa2, 0x32, 0x2b, 0xb8, 0xad, - 0xb0, 0xc4, 0x67, 0xe9, 0xf6, 0x1f, 0xa6, 0x02, 0xdd, 0xea, - 0xb5, 0x5e, 0x26, 0x7e, 0x9b, 0xda, 0xb5, 0x32, 0x88, 0xdf, - 0xd6, 0xf1, 0xfc, 0xd2, 0x0d, 0x49, 0xd4, 0xce, 0x57, 0xf1, - 0xe6, 0xb9, 0x84, 0xe1, 0x46, 0xc8, 0xc1, 0x38, 0xf1, 0xa8, - 0xf0, 0xc4, 0x86, 0x68, 0x07, 0xa4, 0x1b, 0x18, 0x47, 0x5f, - 0x60, 0x85, 0xf3, 0xb0, 0xf0, 0x56, 0xe9, 0x8c, 0x5e, 0xb0, - 0x8e, 0x4b, 0xfa, 0x22, 0x45, 0xb8, 0x08, 0x80, 0xbd, 0xda, - 0x4d, 0x2f, 0x41, 0xba, 0xdd, 0xb4, 0x69, 0x7d, 0xc3, 0xf8, - 0xb6, 0x6d, 0x50, 0x7c, 0xb2, 0xc3, 0x65, 0x4e, 0x43, 0x8d, - 0x27, 0xaa, 0xb1, 0x37, 0xa5, 0x9f, 0xdd, 0xea, 0x56, 0xc8, - 0x3b, 0x49, 0xc2, 0x32, 0x35, 0xb3, 0x5d, 0x5b, 0x97, 0x10, - 0xa6, 0xe7, 0x3e, 0xf8, 0x6b, 0xa8, 0x24, 0x89, 0xae, 0x84, - 0x3c, 0xc5, 0x61, 0xf2, 0xba, 0x92, 0xdb, 0x45, 0x91, 0xf3, - 0x9f, 0x39, 0x6b, 0x00, 0xf4, 0x33, 0x5f, 0x42, 0x25, 0xfd, - 0x6a, 0x94, 0xd2, 0x6b, 0xd0, 0x5e, 0x8e, 0x9b, 0x0a, 0x0a, - 0x72, 0x62, 0x4a, 0x9f, 0xca, 0x3d, 0x2c, 0xfa, 0x0c, 0x23, - 0x21, 0x2e, 0x26, 0x93, 0x2c, 0xdf, 0x7f, 0x0c, 0x87, 0xb8, - 0xdd, 0x6c, 0x88, 0xdb, 0x7f, 0xf5, 0xf0, 0x54, 0xb4, 0x0d, - 0x6e, 0xf4, 0xae, 0x7f, 0x78, 0x7a, 0xc3, 0xac, 0x8f, 0xde, - 0xef, 0x79, 0xaa, 0x42, 0x24, 0xdc, 0x7b, 0x08, 0x1d, 0x89, - 0x0c, 0xed, 0x91, 0x80, 0x85, 0x40, 0x9e, 0x6b, 0xde, 0x99, - 0x08, 0xdf, 0x45, 0xcd, 0x93, 0x24, 0xd9, 0x81, 0x2d, 0x85, - 0x67, 0x22, 0x4d, 0xcc, 0x8e, 0x63, 0x7b, 0xf5, 0xbd, 0x21, - 0xf6, 0x74, 0x64, 0x4b, 0xe9, 0x61, 0x3c, 0x77, 0x63, 0xd8, - 0x0d, 0xe3, 0x3f, 0xb3, 0x91, 0x8d, 0x23, 0x37, 0x04, 0xce, - 0x35, 0xc3, 0xd0, 0xc6, 0x6a, 0x31, 0x0f, 0xde, 0xa7, 0xaf, - 0x8d, 0xe4, 0x7d, 0xab, 0x28, 0x0e, 0x75, 0xc1, 0x98, 0x71, - 0x9b, 0xbe, 0xb1, 0xc6, 0x1e, 0xa8, 0x8d, 0xfd, 0xd6, 0x32, - 0x26, 0x82, 0xe6, 0x65, 0xd1, 0x12, 0x95, 0x8e, 0x3e, 0x18, - 0x00, 0x0a, 0xc5, 0x4f, 0x0e, 0xb8, 0x87, 0x0b, 0x62, 0x41, - 0x9e, 0xb0, 0xe5, 0x41, 0x7f, 0x96, 0x89, 0x52, 0x72, 0x83, - 0x87, 0x44, 0x65, 0xed, 0xc1, 0x11, 0x6e, 0x18, 0x8f, 0xf7, - 0x0f, 0xd5, 0x01, 0xaa, 0x7d, 0xc9, 0x98, 0x35, 0x97, 0xda, - 0xa0, 0xf2, 0xe9, 0xf1, 0xc1, 0xed, 0x90, 0xc6, 0x88, 0xc0, - 0xac, 0x6b, 0x8e, 0x53, 0xed, 0xd1, 0x21, 0xf7, 0x6c, 0x64, - 0x70, 0x8e, 0xd4, 0xc1, 0x21, 0x2f, 0x7f, 0x1d, 0x3e, 0xa7, - 0x57, 0x77, 0xa4, 0xb5, 0xc7, 0x6a, 0x6b, 0xe9, 0xdb, 0x5f, - 0xa7, 0xb9, 0x2c, 0x55, 0xc3, 0x34, 0x51, 0x4d, 0x8e, 0xf7, - 0x4f, 0xd4, 0x56, 0x27, 0xf9, 0x1c, 0xa6, 0xfa, 0x0a, 0x8a, - 0x6e, 0xeb, 0x6b, 0x66, 0x2a, 0xa6, 0x83, 0x6d, 0xc7, 0xc9, - 0x58, 0x9f, 0xa6, 0xc6, 0xda, 0xd6, 0xce, 0x40, 0xba, 0x81, - 0x45, 0x97, 0x50, 0x7b, 0x4a, 0xbc, 0x7d, 0xe1, 0x6f, 0x0e, - 0x7a, 0x54, 0x0b, 0xc9, 0x0f, 0x2a, 0x68, 0x61, 0xdc, 0x10, - 0xca, 0x6f, 0x86, 0x68, 0x10, 0xa3, 0x8c, 0xf1, 0xe9, 0x53, - 0xbb, 0xa0, 0x7e, 0xb4, 0x7d, 0x0d, 0x1c, 0x66, 0x95, 0xd6, - 0x51, 0xb0, 0xbd, 0x96, 0x52, 0xaf, 0x90, 0xe6, 0xbd, 0xe6, - 0xd4, 0xf5, 0x2d, 0x3d, 0x39, 0x75, 0xf6, 0x00, 0x5a, 0x49, - 0xd9, 0x4e, 0x90, 0xaa, 0xbc, 0x8d, 0x8d, 0x21, 0x8d, 0x06, - 0xe8, 0x3b, 0x0d, 0xd9, 0xc5, 0xf2, 0x1d, 0x69, 0x3a, 0xd0, - 0x6c, 0xb4, 0x92, 0x59, 0x07, 0x37, 0xad, 0x01, 0xa7, 0xa8, - 0x0d, 0x6b, 0x91, 0x4f, 0x50, 0xd3, 0x5e, 0x33, 0xeb, 0x69, - 0x89, 0x47, 0x70, 0x05, 0x65, 0x1c, 0xa2, 0x54, 0xfc, 0x26, - 0xfc, 0x51, 0x9a, 0x2f, 0xf4, 0xe7, 0xed, 0xec, 0xd5, 0x3a, - 0xe2, 0xc1, 0xb9, 0x75, 0xb7, 0x11, 0xbf, 0x01, 0x71, 0x91, - 0xad, 0x11, 0x0e, 0xdc, 0x94, 0x3e, 0xaf, 0x3f, 0x59, 0xf8, - 0x5c, 0xc7, 0x91, 0x61, 0xf1, 0x0f, 0x76, 0x2a, 0xee, 0x0d, - 0x6a, 0x1a, 0x57, 0x67, 0x73, 0x73, 0x3a, 0x4f, 0xdb, 0x57, - 0x05, 0xa9, 0xa0, 0x6d, 0xab, 0xeb, 0xf6, 0xa7, 0x56, 0x27, - 0x03, 0xc4, 0x96, 0xa4, 0x94, 0xad, 0x62, 0x78, 0xff, 0x96, - 0x10, 0xe1, 0xee, 0x5d, 0x81, 0xc1, 0x3c, 0x28, 0xf7, 0x48, - 0x46, 0xeb, 0x15, 0x8d, 0x57, 0xd6, 0xa5, 0x7b, 0xd4, 0x9d, - 0x4f, 0xcd, 0xce, 0xe7, 0x84, 0x74, 0x62, 0xf4, 0x3e, 0xea, - 0x1a, 0xf3, 0x10, 0x1e, 0x92, 0xd0, 0x99, 0x42, 0x97, 0x58, - 0xa7, 0x33, 0x18, 0x77, 0x3e, 0x7f, 0x61, 0xc4, 0x0e, 0x84, - 0x14, 0x6b, 0x5b, 0x1f, 0xce, 0xf8, 0xa7, 0x0e, 0x3c, 0x58, - 0x7f, 0x7f, 0x76, 0x23, 0x60, 0x78, 0x98, 0x05, 0x2a, 0x5c, - 0xa7, 0xf5, 0xe7, 0xd6, 0x74, 0xd9, 0x59, 0x4c, 0xa7, 0x8c, - 0xfa, 0xe1, 0xbe, 0xc2, 0x4e, 0xf7, 0x61, 0xb0, 0x36, 0x56, - 0x34, 0xda, 0x75, 0x53, 0x15, 0xa4, 0x79, 0x6e, 0x7e, 0xb6, - 0x78, 0x18, 0xe4, 0xcb, 0x31, 0x0f, 0x83, 0xb6, 0xbf, 0x83, - 0xa0, 0x42, 0x34, 0xe4, 0xc0, 0x1c, 0x25, 0x70, 0xc3, 0x3c, - 0x15, 0xdb, 0xc0, 0xf6, 0x9d, 0x16, 0xae, 0x29, 0x88, 0x9e, - 0x23, 0x85, 0xae, 0x1f, 0x73, 0x00, 0x13, 0xa6, 0x06, 0x55, - 0x03, 0x31, 0x49, 0x0c, 0x1a, 0xbd, 0x00, 0x16, 0x36, 0x6c, - 0x28, 0xf6, 0x1f, 0x8c, 0xf8, 0x11, 0xa4, 0x42, 0x27, 0x44, - 0x61, 0x3d, 0xaa, 0x66, 0xd1, 0x50, 0x49, 0xef, 0x1a, 0x93, - 0x7e, 0xcd, 0x23, 0xfd, 0xda, 0x98, 0xf4, 0x77, 0x1e, 0x75, - 0x1e, 0xfe, 0x81, 0x67, 0x36, 0xd8, 0xc6, 0xe5, 0x23, 0xa2, - 0x99, 0xed, 0x34, 0x97, 0xf8, 0xae, 0x39, 0x71, 0x3f, 0x97, - 0xf8, 0x6b, 0x73, 0xe2, 0x6f, 0x22, 0x69, 0xbf, 0xa6, 0xa5, - 0x2c, 0x3e, 0x39, 0x20, 0x2b, 0xcd, 0x57, 0xc3, 0x8d, 0x8c, - 0x35, 0x40, 0xc9, 0x03, 0x1e, 0xee, 0xb7, 0xfa, 0x32, 0xed, - 0x36, 0x2d, 0x6d, 0x13, 0x9a, 0xb7, 0x35, 0x69, 0x66, 0x08, - 0xdf, 0x84, 0xe6, 0xb7, 0x9a, 0x34, 0x33, 0xa4, 0x6e, 0x42, - 0xf3, 0x73, 0x4d, 0x9a, 0xc3, 0xb4, 0xf0, 0x4d, 0x68, 0x0e, - 0x6b, 0xd2, 0x1c, 0xa5, 0x45, 0x6e, 0x42, 0x73, 0xa4, 0x47, - 0xb3, 0xb2, 0x88, 0xa3, 0xe6, 0x2c, 0xf1, 0x8c, 0x7a, 0x9e, - 0x63, 0xf2, 0x7a, 0x8b, 0x23, 0x6a, 0x5d, 0x7f, 0xbf, 0xe4, - 0x88, 0xcd, 0xcc, 0xce, 0xa4, 0xe9, 0x17, 0xe9, 0xe3, 0xb5, - 0x1a, 0x5b, 0x70, 0x53, 0xe8, 0x51, 0xa4, 0x7e, 0x8f, 0xe0, - 0x90, 0xec, 0x90, 0x26, 0xe8, 0x43, 0xf1, 0x2f, 0x2f, 0xcd, - 0x2c, 0xc4, 0x4f, 0x65, 0x15, 0xec, 0x76, 0xcd, 0x2a, 0x78, - 0x2e, 0xab, 0xe0, 0xf5, 0xb5, 0x59, 0x05, 0x1b, 0xb5, 0x02, - 0x16, 0x08, 0xd3, 0xda, 0x18, 0xfd, 0x51, 0x5a, 0x43, 0xd3, - 0x41, 0x0a, 0x4b, 0x6b, 0x68, 0x3a, 0x4a, 0x6f, 0xa3, 0x2d, - 0x2f, 0xa6, 0x57, 0x56, 0x81, 0x1c, 0xdf, 0xd6, 0x94, 0x3b, - 0xb3, 0x2f, 0x66, 0x91, 0x28, 0x7f, 0xaa, 0x49, 0xf6, 0xda, - 0x4a, 0x90, 0x52, 0x32, 0xc5, 0xf9, 0x73, 0x4d, 0xba, 0xd3, - 0xf1, 0x60, 0x50, 0x20, 0xd1, 0x37, 0x35, 0xc9, 0x4e, 0xfa, - 0xf3, 0xce, 0x75, 0x81, 0x54, 0xff, 0xa3, 0xee, 0x2e, 0x69, - 0x7e, 0x29, 0x90, 0xeb, 0x61, 0xdb, 0x72, 0x1d, 0xd9, 0xd7, - 0x18, 0xc2, 0x27, 0xbf, 0x14, 0x3d, 0xe6, 0x1d, 0xc2, 0x06, - 0xb8, 0x04, 0xd6, 0xb3, 0xc2, 0xbd, 0xe8, 0xbb, 0x25, 0xef, - 0xdd, 0x92, 0xf7, 0x17, 0xb3, 0xe4, 0xb5, 0xca, 0x2c, 0xef, - 0xa6, 0xbc, 0x5f, 0xc0, 0x94, 0xf7, 0x67, 0xb3, 0x80, 0x8d, - 0x12, 0x00, 0x50, 0x71, 0x4b, 0x1f, 0x21, 0x95, 0x0d, 0x0e, - 0xd7, 0xa6, 0x92, 0x09, 0x8c, 0x18, 0x6f, 0xfa, 0xa3, 0xab, - 0xf4, 0x66, 0x4e, 0xc6, 0xa1, 0x8a, 0x8d, 0xe9, 0x5f, 0xcb, - 0x10, 0xa6, 0xe5, 0x2a, 0x66, 0x62, 0xdb, 0x07, 0x6e, 0x64, - 0xbb, 0xe1, 0x9a, 0x9d, 0x30, 0x88, 0xa2, 0x16, 0x09, 0xbf, - 0xa6, 0xb2, 0xc5, 0xb7, 0x47, 0xfb, 0x29, 0x73, 0x38, 0x5a, - 0x0a, 0xb8, 0xcb, 0x1c, 0x91, 0x96, 0x68, 0xe7, 0x0d, 0x4a, - 0x3b, 0xe4, 0x57, 0x38, 0xf4, 0x6a, 0x09, 0xc2, 0x30, 0x08, - 0x95, 0x70, 0x2c, 0x8b, 0x3c, 0x6b, 0xe2, 0x03, 0x23, 0x84, - 0xb2, 0xf2, 0xe8, 0x66, 0x1c, 0xea, 0x12, 0xc3, 0x05, 0x19, - 0x86, 0x2e, 0x64, 0x65, 0xe3, 0xa3, 0x35, 0x37, 0x7f, 0xcb, - 0xcb, 0x1a, 0x58, 0xcb, 0xcf, 0xc8, 0x83, 0x23, 0x83, 0xaa, - 0xa2, 0xda, 0x22, 0x31, 0x76, 0x45, 0x4c, 0xa3, 0x14, 0x9c, - 0xd0, 0x68, 0xb9, 0x44, 0xad, 0x4c, 0x4a, 0x6a, 0x29, 0x96, - 0x7f, 0x45, 0x3b, 0x60, 0xf5, 0x96, 0x97, 0xa5, 0x62, 0x25, - 0x43, 0x3b, 0xb1, 0xe1, 0x78, 0x32, 0x8b, 0x34, 0xc7, 0xe9, - 0x63, 0x03, 0x4f, 0x5f, 0x17, 0x9f, 0xdc, 0x27, 0x61, 0x80, - 0x7c, 0xfe, 0xa0, 0x20, 0xb0, 0x93, 0x2f, 0xaa, 0xdf, 0x77, - 0xb9, 0xdc, 0x87, 0x3b, 0x06, 0x0f, 0xc8, 0x13, 0xf7, 0x09, - 0xd4, 0xa7, 0xe6, 0xf0, 0x23, 0x39, 0xe2, 0xe6, 0x66, 0xc4, - 0x04, 0x47, 0xb4, 0xd8, 0xfd, 0xf4, 0xc5, 0xf5, 0x9d, 0xed, - 0x46, 0x9b, 0x5a, 0x19, 0x84, 0x7b, 0x68, 0x7f, 0x4f, 0x0e, - 0x55, 0x3c, 0x0d, 0x1f, 0x7e, 0xfa, 0x43, 0xb1, 0xcb, 0x79, - 0xba, 0x91, 0x7d, 0x29, 0xdd, 0x08, 0x6a, 0x4a, 0x95, 0x3d, - 0x54, 0xb8, 0x83, 0x53, 0x2e, 0xe0, 0x4a, 0x28, 0x55, 0xb6, - 0xd6, 0x11, 0x53, 0x94, 0x74, 0x2a, 0x3d, 0xce, 0x33, 0x57, - 0xc5, 0xb9, 0xce, 0xe2, 0x2f, 0xea, 0x27, 0x9b, 0x20, 0x2a, - 0x34, 0x3b, 0x55, 0xdb, 0x8b, 0x15, 0xaa, 0xb9, 0xa6, 0xa6, - 0x6a, 0x1b, 0xb1, 0x42, 0x35, 0xd7, 0xbc, 0x54, 0x71, 0x0b, - 0x7e, 0x33, 0x33, 0xe5, 0xee, 0xad, 0xed, 0x94, 0x4f, 0xaf, - 0x6f, 0x6d, 0xa8, 0xb4, 0xf3, 0x46, 0x09, 0x85, 0x91, 0x79, - 0x74, 0x25, 0x96, 0x0c, 0x96, 0x6e, 0x55, 0x3b, 0xcd, 0xaa, - 0x0a, 0x46, 0x4d, 0xb7, 0xaa, 0x57, 0xcd, 0xaa, 0x0a, 0x86, - 0xaf, 0x75, 0x1b, 0x66, 0x95, 0xf4, 0xc4, 0x5f, 0x73, 0xb2, - 0x12, 0x13, 0x73, 0xd8, 0x4b, 0xe3, 0xab, 0xa8, 0xfd, 0x0c, - 0x0b, 0xe6, 0xae, 0xf1, 0x65, 0xd4, 0x7e, 0x86, 0xfd, 0xf2, - 0xb5, 0x26, 0xd5, 0x9b, 0xaf, 0x39, 0xf9, 0x89, 0xa9, 0xb9, - 0xb5, 0xee, 0x18, 0xdc, 0x08, 0x83, 0x90, 0x61, 0xbf, 0x7c, - 0xaa, 0x3b, 0x0a, 0x37, 0xc2, 0x30, 0x64, 0x58, 0x30, 0x9f, - 0xea, 0x8e, 0x83, 0x29, 0x8c, 0xc3, 0x71, 0x9a, 0xae, 0x5d, - 0x77, 0x1c, 0x04, 0x63, 0xf6, 0xfe, 0x79, 0x06, 0xdd, 0xba, - 0xe3, 0x60, 0xf2, 0x71, 0x38, 0xd8, 0xcf, 0xa0, 0xfb, 0xfa, - 0x46, 0x57, 0x74, 0x72, 0x46, 0xc1, 0xe3, 0x83, 0x94, 0x0f, - 0xe9, 0xcf, 0xcb, 0x2c, 0x98, 0x19, 0x15, 0x12, 0xc4, 0x01, - 0x6d, 0x2a, 0x07, 0x40, 0x45, 0x0f, 0x8d, 0xa1, 0xed, 0x83, - 0xed, 0x13, 0x8a, 0x60, 0x2e, 0xcd, 0xc9, 0x83, 0x22, 0xd8, - 0x82, 0x6d, 0x2c, 0x06, 0xb0, 0xe1, 0x9f, 0x15, 0x0e, 0x37, - 0x6f, 0x05, 0xa7, 0xda, 0x86, 0xa9, 0xb0, 0x1d, 0x30, 0xd5, - 0x36, 0x5a, 0x22, 0x84, 0xac, 0xb4, 0x62, 0x08, 0xfc, 0x41, - 0xbe, 0xff, 0x7f, 0x5d, 0x17, 0xbe, 0x10, 0x3b, 0xdd, 0x93, - 0x54, 0x14, 0xbf, 0x1f, 0x9e, 0x1f, 0x1d, 0x9c, 0x9f, 0x1c, - 0xed, 0x9f, 0x1d, 0x9c, 0x5d, 0x9c, 0x9c, 0x9f, 0xa6, 0x72, - 0xea, 0xc9, 0x30, 0x59, 0x75, 0xe6, 0x7f, 0x43, 0xbc, 0xe6, - 0x35, 0xeb, 0x53, 0xc0, 0xb3, 0xea, 0x54, 0x88, 0x21, 0x65, - 0x34, 0xab, 0x93, 0x80, 0x66, 0xea, 0x54, 0x46, 0x60, 0x4e, - 0x92, 0x43, 0x32, 0x41, 0x36, 0x89, 0x40, 0x1c, 0x43, 0x11, - 0x1d, 0x19, 0xf7, 0x41, 0x08, 0x5b, 0xc2, 0x64, 0xd2, 0x1b, - 0xa4, 0xfb, 0x9a, 0x04, 0x9b, 0xc5, 0x86, 0xc9, 0x42, 0x21, - 0xc1, 0x01, 0x7c, 0xfa, 0x2e, 0x0c, 0xdf, 0x85, 0xe1, 0xbb, - 0x30, 0x2c, 0x07, 0x75, 0x67, 0x06, 0x13, 0x06, 0xe9, 0x2e, - 0x47, 0x7c, 0xd7, 0xe3, 0x7d, 0x76, 0x45, 0x44, 0xd8, 0x7f, - 0x1f, 0xfd, 0x43, 0x19, 0x8d, 0x0b, 0xd6, 0x37, 0xbe, 0x2d, - 0xba, 0xaa, 0x79, 0x5d, 0x84, 0x1c, 0x73, 0x97, 0x93, 0xf1, - 0x2c, 0xcf, 0x67, 0xba, 0x99, 0x6f, 0xee, 0x17, 0xb3, 0x3f, - 0x5f, 0xaa, 0xd0, 0x20, 0x32, 0x76, 0x85, 0x1b, 0x1b, 0x76, - 0x6c, 0x44, 0xc5, 0x78, 0x20, 0x59, 0x36, 0x26, 0x94, 0x0c, - 0x78, 0xf9, 0xd9, 0xb2, 0x26, 0xe9, 0x4b, 0xa5, 0x19, 0xc5, - 0xca, 0xfe, 0x0e, 0xc0, 0x46, 0xcf, 0xde, 0xf4, 0xab, 0x09, - 0xfa, 0x39, 0x3c, 0x7a, 0x07, 0x72, 0xd2, 0xba, 0x63, 0x0e, - 0xbc, 0x2a, 0xbd, 0xad, 0x22, 0xf8, 0x7f, 0x72, 0xaf, 0xc8, - 0xa5, 0x21, 0xeb, 0xce, 0x91, 0x72, 0xa7, 0xfa, 0xbe, 0x81, - 0xbd, 0x6f, 0x60, 0x6f, 0xb5, 0x81, 0xbd, 0x8d, 0xdc, 0xff, - 0xcb, 0x6c, 0x8b, 0x04, 0xf4, 0x08, 0x73, 0xdc, 0xb1, 0xb2, - 0x2a, 0xe7, 0xf8, 0x15, 0xdb, 0x68, 0x06, 0xf3, 0xda, 0xd7, - 0x0b, 0x5d, 0xab, 0x67, 0x2e, 0x06, 0x6a, 0x52, 0xe1, 0x2e, - 0xb8, 0xb7, 0xb7, 0x5e, 0x41, 0x56, 0xe1, 0x4e, 0x7f, 0xda, - 0xe1, 0x88, 0x58, 0xc9, 0xee, 0xd4, 0x71, 0xc3, 0x15, 0xf2, - 0xb0, 0xcc, 0xff, 0x70, 0x0a, 0x37, 0x1c, 0xc1, 0x33, 0x80, - 0x63, 0x69, 0xa1, 0xac, 0xd3, 0x71, 0x88, 0x61, 0x04, 0xf2, - 0xbe, 0xb5, 0xfa, 0x57, 0xd7, 0x73, 0x05, 0x9d, 0xa7, 0x87, - 0xe0, 0x61, 0x80, 0x71, 0x9e, 0xff, 0xd5, 0xf5, 0xf8, 0xc6, - 0x9a, 0x2a, 0xf0, 0x57, 0xd7, 0x01, 0x96, 0x68, 0x3a, 0x98, - 0x4c, 0x3f, 0x42, 0x89, 0xf0, 0x80, 0xff, 0x10, 0x3f, 0x16, - 0x56, 0x32, 0xa0, 0x45, 0xea, 0x57, 0x72, 0x07, 0x6c, 0xec, - 0x19, 0x52, 0x7c, 0x2a, 0xdb, 0x17, 0xb0, 0xe9, 0x42, 0x29, - 0x11, 0x65, 0x1d, 0x41, 0xe5, 0xe0, 0xa8, 0x2c, 0x97, 0x0b, - 0x4e, 0x39, 0x5c, 0x4b, 0xba, 0x23, 0x43, 0xc0, 0x6d, 0x35, - 0x99, 0xf8, 0xa6, 0x6b, 0xa9, 0x77, 0x64, 0x0c, 0xd5, 0xac, - 0x0b, 0x36, 0xc0, 0x77, 0x70, 0xae, 0xe5, 0xfc, 0xec, 0xbc, - 0xdc, 0xb9, 0x84, 0x73, 0x32, 0xf3, 0x28, 0x29, 0xf8, 0x4e, - 0xfc, 0xf0, 0x50, 0x71, 0x49, 0x31, 0x34, 0x08, 0xf4, 0xbf, - 0xf4, 0x47, 0x5d, 0x1e, 0x83, 0x75, 0x24, 0xdc, 0xb4, 0x06, - 0xf8, 0x76, 0xf9, 0xd9, 0xf5, 0x9d, 0x3d, 0xaa, 0xe6, 0x69, - 0x71, 0xeb, 0x4f, 0xd6, 0x24, 0xfa, 0x8e, 0x07, 0xb8, 0xbe, - 0x40, 0xf4, 0x89, 0x63, 0x9e, 0x17, 0xde, 0x03, 0x19, 0xda, - 0xc4, 0x87, 0x1f, 0xb8, 0x33, 0xfc, 0x74, 0x45, 0xeb, 0x19, - 0xc3, 0xd0, 0xca, 0xf1, 0x66, 0x1c, 0xbe, 0x18, 0xbe, 0x27, - 0x38, 0xb5, 0x89, 0x83, 0x45, 0x15, 0x25, 0x92, 0x11, 0x95, - 0xd1, 0xb5, 0x28, 0xa5, 0x4e, 0xb0, 0x5e, 0xa3, 0x90, 0x39, - 0xd9, 0x8f, 0xa0, 0x0e, 0xa2, 0xd6, 0x5f, 0x72, 0x66, 0xa6, - 0xc1, 0x33, 0xf3, 0x77, 0xe1, 0x78, 0xb5, 0xe8, 0xe1, 0xbb, - 0xfa, 0xfb, 0xae, 0xfe, 0xbe, 0xdb, 0x6f, 0x7e, 0x45, 0xd5, - 0x62, 0x85, 0x5c, 0x07, 0x97, 0x14, 0x21, 0x8a, 0xae, 0x90, - 0xfd, 0xe3, 0xb3, 0x83, 0x8b, 0xb3, 0x93, 0x93, 0x03, 0xf8, - 0x5f, 0xbe, 0x3a, 0xe4, 0xa7, 0xa2, 0xe3, 0xa1, 0x29, 0xe3, - 0x4b, 0xd5, 0x69, 0xc6, 0xb3, 0xeb, 0x60, 0xcd, 0x4d, 0xea, - 0xe0, 0x17, 0xf2, 0xb0, 0x05, 0x85, 0x50, 0x22, 0xdb, 0x5c, - 0x07, 0x7c, 0x24, 0xf0, 0x90, 0x32, 0xd9, 0xeb, 0x20, 0x74, - 0x5f, 0xe1, 0x86, 0x60, 0xa3, 0x38, 0x91, 0x3c, 0xf4, 0xc8, - 0x75, 0xc2, 0x12, 0x47, 0xfb, 0x9a, 0x9e, 0x92, 0xf7, 0xf7, - 0x5c, 0x9e, 0x87, 0x4f, 0xc0, 0x20, 0xb9, 0xec, 0x72, 0x78, - 0x4f, 0x3b, 0xd5, 0x11, 0x08, 0x7d, 0x5b, 0xd0, 0x28, 0x85, - 0x2b, 0x5a, 0x93, 0xbf, 0x44, 0x5e, 0x60, 0xf0, 0x59, 0x9c, - 0x86, 0x51, 0x4e, 0x2e, 0x3d, 0x59, 0x77, 0x4e, 0xf6, 0x7f, - 0xa2, 0x9d, 0x6f, 0xf6, 0x8f, 0x85, 0x39, 0xb5, 0x50, 0x1c, - 0xbe, 0x10, 0x42, 0x25, 0x38, 0x4c, 0xcc, 0xfe, 0xd8, 0xda, - 0x21, 0xce, 0x39, 0xfd, 0x54, 0xa4, 0x88, 0xa2, 0xcf, 0x97, - 0x53, 0x7e, 0x3a, 0x92, 0xfd, 0x23, 0x7a, 0x6e, 0x18, 0xc5, - 0x84, 0x86, 0x31, 0x25, 0x19, 0x15, 0x7f, 0x7d, 0x55, 0xb2, - 0x17, 0x78, 0x5e, 0xf0, 0x2c, 0xa0, 0x13, 0x71, 0xe8, 0x6d, - 0xf2, 0x0a, 0x83, 0x13, 0xbd, 0x6f, 0xcf, 0xef, 0xdb, 0xf3, - 0xfb, 0xf6, 0x5c, 0x7a, 0xf9, 0x8b, 0xc2, 0x4b, 0x22, 0xf5, - 0x64, 0x80, 0xd6, 0x0f, 0xc1, 0x5e, 0x11, 0x03, 0xfd, 0x26, - 0xb4, 0xac, 0x74, 0x30, 0xf8, 0xe4, 0xe5, 0x2c, 0xe2, 0x5f, - 0xee, 0x26, 0x96, 0xf7, 0x89, 0x08, 0x8d, 0xf3, 0x74, 0xe7, - 0x3e, 0xe8, 0x00, 0x05, 0xd3, 0xbc, 0xab, 0x1f, 0xd7, 0xbf, - 0xb5, 0x07, 0x15, 0xdc, 0x0e, 0x4d, 0xee, 0x18, 0x18, 0x3c, - 0xfb, 0xf5, 0x68, 0x96, 0x0c, 0xe2, 0x6d, 0x70, 0x9b, 0x78, - 0xf6, 0x24, 0x91, 0xf6, 0xb7, 0xc1, 0xa7, 0xdb, 0x77, 0xd7, - 0x9e, 0x77, 0x71, 0xfb, 0x76, 0xe2, 0xd6, 0x5e, 0x6f, 0x3c, - 0x1a, 0x03, 0x49, 0xf5, 0x39, 0xfe, 0xa0, 0x41, 0xde, 0x39, - 0xc1, 0xf1, 0x65, 0xff, 0xf7, 0x33, 0x78, 0x2a, 0xb9, 0x38, - 0x3f, 0x48, 0x9d, 0x48, 0x48, 0x5a, 0x34, 0xb3, 0x32, 0xdc, - 0xec, 0x5f, 0x77, 0xcf, 0xf8, 0x95, 0x6e, 0x5a, 0xbb, 0x81, - 0xcf, 0xbc, 0x22, 0x39, 0xfc, 0xbc, 0x7c, 0xdb, 0x4a, 0x8a, - 0x64, 0x08, 0xa5, 0xe2, 0x6a, 0xe8, 0x95, 0xf4, 0x67, 0x7a, - 0x23, 0x4d, 0xeb, 0x38, 0x50, 0x6f, 0xac, 0x93, 0xf7, 0xa5, - 0x52, 0xef, 0x5d, 0x42, 0xfd, 0x85, 0x25, 0x94, 0x1c, 0x73, - 0xdc, 0xfc, 0xda, 0xe7, 0x5f, 0xee, 0xfa, 0xf3, 0x4f, 0x20, - 0x78, 0x2c, 0x0f, 0x3c, 0xd9, 0x71, 0xc0, 0xae, 0x2f, 0x38, - 0xa0, 0x3d, 0x7b, 0xf1, 0xb3, 0x75, 0xa0, 0x3f, 0x81, 0xc3, - 0xd1, 0xbb, 0x0a, 0xf7, 0x0e, 0xf0, 0xf1, 0x8e, 0x54, 0xa1, - 0x3a, 0x10, 0x48, 0x0a, 0x67, 0xf3, 0xcd, 0xe3, 0x5d, 0xd3, - 0x6c, 0xd3, 0xd0, 0x38, 0x0f, 0x6d, 0x94, 0x90, 0x2c, 0x08, - 0x19, 0xc6, 0x1c, 0x4f, 0xb7, 0x41, 0xcd, 0x8d, 0x62, 0x89, - 0xf7, 0xc3, 0xef, 0xbb, 0x6a, 0xf9, 0x6e, 0x6b, 0xac, 0x60, - 0x6b, 0xe4, 0x8b, 0x47, 0xb2, 0x38, 0xf2, 0xc7, 0x7f, 0x72, - 0xbb, 0x63, 0xaa, 0x7f, 0x44, 0x86, 0x1c, 0xe7, 0x75, 0xf4, - 0xdd, 0x06, 0x99, 0x16, 0x99, 0xa2, 0xb0, 0x4c, 0x68, 0x46, - 0xbf, 0xb5, 0x97, 0xcc, 0x8e, 0x70, 0x85, 0xe2, 0x9f, 0x74, - 0x7a, 0xa2, 0x30, 0xcd, 0x4f, 0x56, 0xef, 0x11, 0x29, 0x46, - 0x90, 0x35, 0xc5, 0x18, 0xe1, 0x87, 0x2a, 0xdf, 0xfe, 0x09, - 0xd6, 0x05, 0xf5, 0xc2, 0xeb, 0x25, 0x89, 0x4b, 0xe9, 0xa0, - 0x9f, 0xaa, 0x6e, 0x7a, 0x42, 0x89, 0x77, 0x1b, 0xcb, 0xfb, - 0x46, 0xf8, 0xbe, 0x11, 0xd6, 0xdd, 0x08, 0x37, 0x36, 0x42, - 0xbd, 0x72, 0x37, 0x76, 0x46, 0xe5, 0xea, 0x6a, 0x9c, 0xf0, - 0xb2, 0x02, 0xfa, 0xfb, 0x3a, 0xf1, 0xa0, 0x10, 0x08, 0xd5, - 0x6c, 0x0d, 0x39, 0x73, 0x8a, 0xc9, 0xdb, 0xc9, 0xf1, 0x72, - 0xee, 0xae, 0x73, 0xfc, 0x6e, 0xa2, 0x3f, 0xa3, 0x58, 0x93, - 0x06, 0x92, 0x48, 0xb8, 0xb3, 0x5c, 0x09, 0x27, 0x8e, 0x6c, - 0x4e, 0xe4, 0x3e, 0xcf, 0x10, 0xde, 0xef, 0x1a, 0x1f, 0xfb, - 0xc3, 0x8e, 0x61, 0x3b, 0x4e, 0x08, 0x1b, 0x91, 0xc6, 0xfd, - 0xd2, 0x19, 0xad, 0xe0, 0xfe, 0x7e, 0xf9, 0x92, 0x9e, 0xe1, - 0x80, 0xec, 0xb1, 0xf0, 0xe8, 0x8b, 0x21, 0xde, 0x3e, 0x51, - 0xef, 0xfb, 0xfa, 0x32, 0x03, 0xd5, 0xb3, 0x2b, 0xaa, 0x07, - 0x7b, 0x5d, 0xb5, 0x53, 0xcf, 0x6b, 0x51, 0x3d, 0x18, 0xb2, - 0x70, 0x8f, 0x21, 0x18, 0xb6, 0x77, 0x33, 0x8a, 0x80, 0x97, - 0x54, 0xfd, 0xe1, 0x5c, 0x42, 0x65, 0x4a, 0x6b, 0x0f, 0x0a, - 0x46, 0x43, 0x89, 0x1f, 0x2a, 0x78, 0x80, 0x1c, 0x09, 0x42, - 0xb5, 0x92, 0x0b, 0x9e, 0x14, 0x9a, 0x14, 0x28, 0xaf, 0x48, - 0x81, 0x47, 0xe3, 0x2c, 0x95, 0x68, 0x15, 0xfd, 0xae, 0x0e, - 0x37, 0x95, 0xb4, 0x98, 0x51, 0xcb, 0xc0, 0x22, 0x3e, 0xdb, - 0x4f, 0x55, 0x59, 0x07, 0x8f, 0xb8, 0x28, 0x4f, 0xeb, 0xb0, - 0x53, 0x3f, 0x51, 0xab, 0xf5, 0xd5, 0xea, 0x2c, 0xe6, 0x1c, - 0x46, 0x33, 0xd5, 0x58, 0xd7, 0x87, 0xf5, 0x04, 0x0f, 0x68, - 0xdd, 0xe9, 0xa7, 0xa7, 0x19, 0x8f, 0x2c, 0x25, 0x92, 0x20, - 0xa1, 0x87, 0x72, 0x85, 0x7a, 0xa0, 0x4a, 0x62, 0x7b, 0x6b, - 0x3a, 0x1d, 0xab, 0x49, 0xe7, 0x13, 0x72, 0x04, 0x83, 0x50, - 0x3f, 0x34, 0x73, 0x3c, 0x99, 0xb0, 0xd4, 0xb0, 0x47, 0x29, - 0x62, 0x50, 0x80, 0x6e, 0x36, 0xc0, 0xa9, 0x63, 0xd1, 0x15, - 0x40, 0x0b, 0x3b, 0xa4, 0x87, 0x38, 0xcd, 0xb7, 0x20, 0xe1, - 0xeb, 0x69, 0xc2, 0xae, 0x7f, 0x1f, 0xf0, 0x88, 0x08, 0xf4, - 0xb7, 0x86, 0x02, 0xac, 0x65, 0xec, 0x99, 0xed, 0xe0, 0x12, - 0x5a, 0x33, 0x2e, 0x3d, 0x50, 0x0c, 0x3d, 0xec, 0xad, 0xa0, - 0x87, 0xfe, 0x47, 0x31, 0x83, 0xd2, 0x0f, 0x28, 0x87, 0xe2, - 0x5f, 0xc6, 0x3c, 0x30, 0x08, 0xbd, 0x5a, 0x12, 0xfb, 0x3d, - 0x30, 0x4e, 0x0f, 0xaa, 0x75, 0x9c, 0x88, 0xfc, 0xaf, 0x35, - 0xba, 0xb2, 0x4b, 0x93, 0xb9, 0xad, 0x41, 0xe6, 0x95, 0xb3, - 0x7f, 0x10, 0x3a, 0xae, 0x0f, 0x3b, 0x84, 0xed, 0xc9, 0x75, - 0x48, 0xfd, 0x12, 0x29, 0x55, 0x51, 0xb0, 0x48, 0x34, 0x05, - 0x9e, 0xcd, 0x8c, 0xa1, 0x67, 0x42, 0x74, 0xd3, 0x7a, 0x0d, - 0xeb, 0x5a, 0x61, 0x6e, 0x8c, 0x0c, 0x52, 0xe8, 0xfd, 0x94, - 0xf6, 0x2f, 0xe7, 0x1e, 0xf2, 0x46, 0x02, 0x6a, 0x17, 0x2d, - 0x6d, 0x45, 0x90, 0x9a, 0xb5, 0x04, 0x28, 0xa2, 0x74, 0xa7, - 0x50, 0xba, 0xac, 0x45, 0x69, 0x1d, 0x3c, 0x81, 0x65, 0xfc, - 0x08, 0xb5, 0x80, 0xc7, 0xc0, 0xe3, 0x4a, 0x14, 0x7c, 0x6a, - 0x08, 0x4f, 0xdb, 0xd2, 0x30, 0x3b, 0x28, 0x30, 0xd5, 0x0c, - 0x81, 0xcd, 0x56, 0xde, 0x11, 0x5f, 0x79, 0x68, 0x9f, 0xc6, - 0xaf, 0xde, 0xd7, 0xdb, 0xbb, 0x55, 0xe4, 0x4f, 0x6b, 0x15, - 0xf1, 0x76, 0x0f, 0x98, 0x3d, 0x64, 0x5f, 0x64, 0xf2, 0x18, - 0x41, 0x76, 0x83, 0x17, 0x0e, 0xa0, 0x44, 0xcb, 0xb6, 0x78, - 0x27, 0x90, 0xc4, 0x85, 0x44, 0x6f, 0x84, 0x04, 0x25, 0xf5, - 0x83, 0x2c, 0xe1, 0x63, 0xa5, 0x43, 0x06, 0x7d, 0xfd, 0xbe, - 0x8c, 0xeb, 0xe5, 0xdd, 0x46, 0xa7, 0x0c, 0x3b, 0x8a, 0x3a, - 0xb6, 0xe7, 0xde, 0x49, 0x50, 0x2c, 0x67, 0x27, 0xe2, 0x41, - 0x04, 0x16, 0x31, 0x84, 0x32, 0xef, 0xbe, 0xcb, 0xef, 0xf2, - 0xf9, 0xcd, 0xe4, 0xb3, 0xe8, 0x65, 0x5c, 0x67, 0x7a, 0x15, - 0xc0, 0xbd, 0x3a, 0x9e, 0xc7, 0x6f, 0xe3, 0x3e, 0xfd, 0x7e, - 0x10, 0xfd, 0xf9, 0xe8, 0x20, 0xef, 0x20, 0x1a, 0xff, 0x52, - 0x20, 0x1a, 0xe2, 0xad, 0x42, 0xa2, 0xab, 0x90, 0xfd, 0xed, - 0x34, 0xf3, 0x9a, 0x26, 0x29, 0x54, 0xba, 0xaf, 0xdd, 0xb3, - 0xcf, 0x96, 0xe2, 0x35, 0x33, 0x27, 0x56, 0xff, 0x9e, 0x39, - 0x64, 0xd2, 0x7b, 0x79, 0x1f, 0x66, 0x92, 0x4e, 0xc4, 0xbb, - 0xd1, 0x23, 0x05, 0x5a, 0x48, 0x8d, 0x60, 0x99, 0xd3, 0xf9, - 0xf5, 0xb2, 0xd7, 0xff, 0xca, 0xec, 0x9a, 0xfb, 0xdc, 0xd7, - 0x01, 0x39, 0x50, 0xf4, 0xdc, 0x17, 0xb4, 0xa2, 0xf3, 0x38, - 0x67, 0x62, 0xca, 0x5f, 0x1f, 0x48, 0xb1, 0x62, 0x3a, 0x1f, - 0xe3, 0xc0, 0xdb, 0xae, 0xc2, 0xbb, 0x24, 0xf1, 0x1e, 0x8a, - 0xb6, 0x75, 0xb4, 0xd8, 0xed, 0xd7, 0xba, 0xb1, 0x2b, 0x67, - 0xfe, 0x7b, 0x7e, 0x55, 0xff, 0xa6, 0xdc, 0xef, 0xd9, 0xbe, - 0xf5, 0x02, 0x56, 0x5b, 0x51, 0xc1, 0x3b, 0xcb, 0xe8, 0x35, - 0x2c, 0x67, 0x08, 0x05, 0x4b, 0x17, 0xc1, 0x43, 0x18, 0x6c, - 0x37, 0xd2, 0x02, 0x98, 0xdb, 0xe1, 0x03, 0x88, 0x8d, 0x2b, - 0xf4, 0xa2, 0xc1, 0x1a, 0x78, 0xbb, 0xd5, 0x05, 0x4b, 0xfb, - 0x4b, 0x7e, 0x83, 0xa3, 0x74, 0x9e, 0xdf, 0xe3, 0x54, 0xa3, - 0xea, 0x80, 0x68, 0x15, 0xba, 0x1b, 0x71, 0x7b, 0xc7, 0xf4, - 0xba, 0xe2, 0xf3, 0x3a, 0x84, 0x3d, 0x60, 0x3b, 0x20, 0x5c, - 0x4a, 0xbb, 0x3c, 0x6f, 0xf3, 0x00, 0xbf, 0x35, 0x7a, 0x1e, - 0x0a, 0x45, 0x37, 0x4c, 0x37, 0x8c, 0x32, 0x14, 0x80, 0x8a, - 0x49, 0x20, 0x68, 0x8d, 0x77, 0xb6, 0xff, 0x7d, 0xe9, 0xb9, - 0xeb, 0x74, 0xa5, 0xa4, 0x80, 0x71, 0x4f, 0x2a, 0x45, 0xe5, - 0x0c, 0x58, 0xce, 0x8d, 0x9b, 0x55, 0xbb, 0x09, 0xa2, 0x65, - 0xe4, 0xae, 0x51, 0x3a, 0x28, 0xb1, 0x5a, 0x96, 0x7f, 0x0b, - 0x6a, 0x02, 0x11, 0xac, 0x7f, 0xf5, 0x58, 0x58, 0x57, 0xe5, - 0x9a, 0x9e, 0x43, 0x3f, 0xbf, 0xa6, 0x3a, 0x36, 0xa9, 0xc2, - 0xda, 0x94, 0xb3, 0x50, 0x46, 0x8d, 0xb0, 0xc0, 0xa7, 0xc6, - 0xc7, 0xa3, 0x55, 0xe0, 0xc3, 0x0d, 0xf5, 0x61, 0xb9, 0xe6, - 0xf9, 0x3c, 0x3a, 0xe4, 0x11, 0xde, 0x34, 0x5a, 0xe9, 0x16, - 0xab, 0x43, 0xe9, 0x92, 0x54, 0x4f, 0x4b, 0x9d, 0x59, 0xaf, - 0xa3, 0x74, 0x35, 0x92, 0xe9, 0xbc, 0x9d, 0x9a, 0xe2, 0x6d, - 0x78, 0x27, 0xb2, 0xde, 0x1c, 0xfe, 0xde, 0x7a, 0xb8, 0x2b, - 0x2d, 0xf0, 0xf7, 0x2f, 0xe1, 0x9a, 0x2d, 0x1c, 0x0c, 0xc9, - 0x26, 0x70, 0xae, 0x5c, 0xd8, 0x71, 0xd5, 0xa2, 0x3a, 0x5c, - 0xd6, 0x32, 0x0a, 0x57, 0x0a, 0x28, 0x96, 0x87, 0x72, 0xa0, - 0xcf, 0xf0, 0xf7, 0xb5, 0x0c, 0xc6, 0x8c, 0x32, 0xf0, 0xe3, - 0x2c, 0xca, 0x96, 0x1f, 0x0b, 0x59, 0xe8, 0x98, 0xce, 0xa3, - 0x35, 0xd7, 0x32, 0x3f, 0xf1, 0x6e, 0x2f, 0x36, 0x0e, 0xba, - 0x73, 0x52, 0xcc, 0x14, 0x15, 0x8e, 0x52, 0x24, 0x69, 0xe2, - 0x32, 0x33, 0xa7, 0x66, 0xe6, 0xf9, 0x45, 0x13, 0xab, 0x05, - 0x1f, 0x3f, 0x97, 0x88, 0x21, 0x42, 0xa8, 0x3d, 0x09, 0x38, - 0x2d, 0xc4, 0x82, 0xd0, 0x4f, 0x5e, 0x34, 0x4c, 0xd6, 0x95, - 0x62, 0x91, 0x8b, 0xf4, 0x20, 0x09, 0x17, 0xb2, 0xda, 0x37, - 0xbb, 0xc5, 0xb1, 0x56, 0x66, 0xdd, 0x60, 0x2b, 0x78, 0xe2, - 0xc1, 0x38, 0xc9, 0xe9, 0x60, 0xab, 0x45, 0x04, 0x8c, 0x41, - 0xb0, 0x52, 0x54, 0xe6, 0x7c, 0x2d, 0x74, 0x36, 0xb1, 0x12, - 0xdd, 0x57, 0xc0, 0x6f, 0x46, 0x64, 0xc8, 0xa9, 0x57, 0x83, - 0x46, 0x46, 0xfa, 0x4f, 0xf4, 0xfd, 0x37, 0x9d, 0x6f, 0xa7, - 0x66, 0xb7, 0xbf, 0x98, 0xa5, 0x93, 0x7c, 0x22, 0x02, 0x84, - 0x71, 0xb4, 0x7a, 0x81, 0x52, 0x93, 0x2d, 0x27, 0xe3, 0xfe, - 0x68, 0x9e, 0x4e, 0xf1, 0x89, 0x48, 0xc5, 0x8f, 0xae, 0x40, - 0xc8, 0xb0, 0x23, 0x83, 0x45, 0x29, 0xd1, 0xcd, 0x08, 0x89, - 0x22, 0x21, 0x23, 0x36, 0x28, 0x00, 0x20, 0xed, 0xf6, 0xa7, - 0x56, 0x67, 0x9e, 0x4e, 0xd5, 0x8d, 0xea, 0xe9, 0xd0, 0x00, - 0xb7, 0x84, 0x6e, 0xa3, 0x9a, 0x86, 0xe6, 0x88, 0xbb, 0x83, - 0xec, 0xbf, 0xf0, 0x1c, 0x35, 0x88, 0x93, 0x0c, 0xc1, 0x27, - 0x86, 0x39, 0x4d, 0x68, 0x1d, 0x17, 0xa8, 0xb6, 0x24, 0x9f, - 0x13, 0x68, 0x8a, 0x98, 0x59, 0xca, 0xae, 0x92, 0x36, 0xab, - 0x31, 0xac, 0xbf, 0xa4, 0xae, 0x94, 0x45, 0x2e, 0x93, 0xf4, - 0xb7, 0x02, 0x4b, 0x5d, 0x09, 0x49, 0x6c, 0xf9, 0x54, 0xcc, - 0x98, 0x19, 0xd6, 0x3e, 0x62, 0x3f, 0xdc, 0xcb, 0xb7, 0x58, - 0xaa, 0x06, 0xc8, 0x8a, 0x34, 0x74, 0xa2, 0x77, 0xf7, 0xaa, - 0xec, 0x4a, 0xa2, 0xaf, 0x93, 0x30, 0xb9, 0xea, 0xa6, 0x54, - 0xc5, 0xd7, 0xe9, 0x4f, 0xb8, 0x2b, 0x85, 0x7c, 0x16, 0x64, - 0xc6, 0x11, 0xa6, 0x47, 0x91, 0xc5, 0x75, 0x60, 0x27, 0x8b, - 0xbc, 0xc0, 0x7a, 0xd3, 0xda, 0x26, 0x04, 0x04, 0x85, 0xaf, - 0x9c, 0xfe, 0x11, 0xf8, 0x3d, 0x1a, 0x12, 0x7c, 0xd6, 0xc5, - 0xd0, 0x59, 0x61, 0xb9, 0x08, 0xbb, 0x1a, 0xcf, 0xc7, 0x8a, - 0x1d, 0xe0, 0x2a, 0x40, 0x54, 0xe2, 0xe0, 0xd9, 0x0e, 0x9d, - 0x08, 0xd2, 0x58, 0x01, 0xf7, 0x09, 0x2e, 0x48, 0x0d, 0x62, - 0x24, 0xc1, 0xb3, 0x62, 0xcf, 0x4a, 0x52, 0x3b, 0x1b, 0xf6, - 0x3d, 0xda, 0x97, 0x6d, 0x94, 0x0e, 0x16, 0xff, 0x24, 0x99, - 0x48, 0x35, 0xe8, 0xe6, 0x22, 0x21, 0x37, 0xa2, 0x6a, 0x0d, - 0xac, 0x1b, 0x73, 0xce, 0xfc, 0xd4, 0x4e, 0x84, 0x1b, 0x72, - 0x44, 0x07, 0xa5, 0xa8, 0xcb, 0xa1, 0x1d, 0x93, 0x63, 0xf7, - 0x6a, 0x07, 0x39, 0xd0, 0x29, 0x12, 0xa4, 0xf3, 0xfe, 0xd0, - 0x1a, 0x2f, 0xe8, 0x3c, 0x9d, 0x66, 0xb1, 0x2f, 0x71, 0xc1, - 0xc2, 0x3a, 0xb5, 0x63, 0x60, 0x1d, 0x48, 0xc7, 0xf0, 0x12, - 0x06, 0x2f, 0x48, 0x47, 0xde, 0x09, 0x09, 0x53, 0xd9, 0x03, - 0xc6, 0x5a, 0x93, 0xe9, 0xf8, 0x6b, 0xcd, 0x5d, 0xbe, 0x97, - 0x95, 0xf1, 0xbb, 0x67, 0x87, 0x24, 0x96, 0x1a, 0x0d, 0x00, - 0x3c, 0x80, 0xc7, 0x2e, 0x43, 0xb3, 0xcb, 0xeb, 0xfc, 0xd7, - 0xdb, 0xa5, 0x94, 0x3c, 0xfc, 0x50, 0x4a, 0x1e, 0x0e, 0x87, - 0x17, 0x51, 0x7a, 0xe4, 0x10, 0x7e, 0xc8, 0x56, 0x50, 0xb4, - 0xdb, 0xcb, 0xd4, 0x8e, 0xb3, 0xa8, 0x3d, 0xb1, 0xcc, 0xc9, - 0x32, 0xad, 0x1a, 0x46, 0x9c, 0x61, 0x00, 0x87, 0x2a, 0x09, - 0xa6, 0x3f, 0x3f, 0x48, 0x1f, 0xcc, 0x69, 0x09, 0x34, 0x89, - 0x5d, 0x3b, 0xce, 0xf1, 0x6d, 0xb0, 0x5f, 0x96, 0xab, 0xb5, - 0x23, 0x1e, 0xa4, 0x6c, 0xc8, 0x31, 0x8e, 0xf1, 0x55, 0x4e, - 0x87, 0xf8, 0x11, 0xc7, 0x4d, 0xfd, 0x56, 0x47, 0x57, 0xdd, - 0x65, 0x57, 0x70, 0xab, 0x54, 0x80, 0x62, 0xa8, 0x6a, 0xd1, - 0x7f, 0xcd, 0xa6, 0xff, 0x4d, 0xa1, 0x8f, 0xe2, 0xa9, 0x6a, - 0xd1, 0x7f, 0x59, 0x3a, 0x20, 0x52, 0x13, 0xc6, 0xb5, 0x39, - 0x3c, 0x19, 0xe4, 0x5b, 0x1c, 0x9c, 0x0c, 0xea, 0x6d, 0x0d, - 0xcd, 0x93, 0x1b, 0xc6, 0xd8, 0x90, 0x91, 0xd8, 0x15, 0xbe, - 0x1a, 0x37, 0xf0, 0xd9, 0x16, 0xf2, 0x37, 0x4e, 0xd9, 0xdd, - 0x60, 0x5c, 0x12, 0xda, 0x89, 0x08, 0xb9, 0x55, 0x69, 0xd7, - 0x1d, 0x94, 0x84, 0xb4, 0x70, 0x45, 0xaa, 0x90, 0xae, 0x3b, - 0x22, 0x28, 0xab, 0xcb, 0xf2, 0xde, 0xb9, 0xfb, 0x2e, 0x0e, - 0xc9, 0xcc, 0x73, 0x1d, 0xac, 0x62, 0x90, 0x94, 0x2f, 0x46, - 0x0f, 0x2a, 0x8f, 0x77, 0x28, 0x6f, 0x7a, 0xfd, 0xd1, 0xe1, - 0xf5, 0x08, 0xc3, 0x93, 0x5f, 0x4f, 0xdd, 0x91, 0xe2, 0xd5, - 0x08, 0x43, 0x95, 0x5f, 0x4d, 0xa3, 0x51, 0xdb, 0xfa, 0xdf, - 0x7d, 0x71, 0xd4, 0x16, 0x70, 0x67, 0x0c, 0x63, 0x64, 0xf2, - 0xd8, 0x61, 0x3d, 0x1e, 0xf8, 0x51, 0xd3, 0xb5, 0xc6, 0xeb, - 0x11, 0x46, 0x2d, 0xbf, 0x9e, 0x46, 0xa3, 0x86, 0xab, 0x79, - 0x15, 0xef, 0xc6, 0xf3, 0xaa, 0xa9, 0x3d, 0x6a, 0x91, 0x38, - 0x5c, 0xa2, 0xa5, 0xad, 0x0b, 0x9e, 0xdc, 0xc6, 0x63, 0x15, - 0x89, 0x83, 0x94, 0x43, 0xbd, 0xf6, 0x08, 0x45, 0xe2, 0xd0, - 0xe4, 0x10, 0xaf, 0x3b, 0x2e, 0x21, 0x80, 0x4a, 0x3e, 0xd1, - 0x62, 0x55, 0xad, 0xd9, 0xc3, 0x59, 0xd1, 0x67, 0xa2, 0xbe, - 0xcb, 0x1e, 0xb2, 0xb3, 0x84, 0xde, 0xdd, 0x4e, 0xa9, 0xd1, - 0x44, 0xaa, 0x89, 0xec, 0xd0, 0x87, 0x39, 0x55, 0x66, 0x8f, - 0x90, 0x70, 0x27, 0x41, 0x7d, 0x2c, 0xfb, 0xe8, 0x96, 0xd8, - 0x85, 0xc5, 0xc2, 0x9a, 0x77, 0x12, 0xa8, 0x2f, 0xc9, 0xf5, - 0x36, 0x1c, 0xa1, 0xb4, 0x43, 0x88, 0x16, 0xfa, 0x47, 0x18, - 0xa6, 0x0c, 0xd6, 0x58, 0x6a, 0xd6, 0xa0, 0xb5, 0x8a, 0x43, - 0x6f, 0xe9, 0xae, 0x37, 0x8a, 0xde, 0x69, 0xf4, 0xd7, 0x1b, - 0xc8, 0xb7, 0x35, 0x1b, 0x88, 0xe6, 0xdf, 0x71, 0x85, 0x4d, - 0x29, 0x19, 0xef, 0xe4, 0x52, 0x1f, 0x6e, 0xdf, 0xf5, 0x57, - 0x06, 0xa3, 0xbf, 0x2b, 0xa0, 0x7f, 0x5b, 0x7f, 0x6d, 0x30, - 0xf2, 0xaf, 0x05, 0xe4, 0xbf, 0xd5, 0x5f, 0x1d, 0xca, 0x76, - 0x2d, 0x4f, 0x61, 0x83, 0x51, 0x51, 0xb6, 0x6a, 0x95, 0x6e, - 0xdd, 0xd1, 0x50, 0xb6, 0x69, 0x95, 0x6c, 0x6d, 0x19, 0x71, - 0xbf, 0x2c, 0x1e, 0x88, 0xbe, 0x6f, 0x24, 0xe3, 0x8e, 0x6f, - 0xd5, 0x9b, 0x30, 0xcc, 0xfd, 0xb2, 0x78, 0x74, 0x32, 0x2a, - 0xab, 0xcd, 0x3d, 0xf7, 0xcb, 0xe2, 0x21, 0xcb, 0xa8, 0xab, - 0xe1, 0x20, 0x3e, 0x89, 0xda, 0x1f, 0xf0, 0x82, 0x15, 0x3c, - 0xe5, 0xbd, 0xdd, 0x28, 0x3e, 0x89, 0xfa, 0x60, 0x69, 0x6d, - 0x0d, 0x87, 0xf1, 0x49, 0xd4, 0x10, 0x4b, 0x2b, 0x7b, 0xdf, - 0xc8, 0xdb, 0xdd, 0xc8, 0xff, 0xe5, 0x8f, 0x17, 0x65, 0xc9, - 0xcd, 0xdd, 0xc8, 0x0b, 0x9c, 0x87, 0x44, 0xc1, 0x10, 0x9c, - 0xd7, 0xc8, 0x8b, 0x9f, 0xed, 0x97, 0x1b, 0x6e, 0x92, 0x0b, - 0xce, 0xe9, 0x64, 0x58, 0x63, 0x28, 0x05, 0xf7, 0xbc, 0x5c, - 0xb7, 0xbc, 0x6e, 0xbf, 0xbe, 0x89, 0xd2, 0x5c, 0x30, 0xd3, - 0xa2, 0x90, 0x08, 0x22, 0xa6, 0x86, 0x1a, 0xe2, 0x9f, 0xe7, - 0x80, 0x95, 0xeb, 0x14, 0x18, 0x7d, 0x7a, 0xe3, 0xe9, 0x17, - 0x73, 0xaa, 0xba, 0x39, 0x99, 0x31, 0xd4, 0xd8, 0x36, 0x90, - 0x52, 0x60, 0xa0, 0x20, 0x17, 0x64, 0xf0, 0x44, 0xb6, 0xca, - 0x7c, 0x32, 0x97, 0x66, 0xe7, 0x33, 0xa7, 0x73, 0x98, 0x47, - 0x07, 0x9d, 0xb3, 0x24, 0x42, 0x7f, 0x06, 0x67, 0x3b, 0xc6, - 0x9f, 0xc7, 0x29, 0x13, 0x55, 0x95, 0xfb, 0xc2, 0x37, 0xf3, - 0x00, 0x22, 0xa9, 0x00, 0x29, 0xdb, 0x4b, 0xb9, 0xff, 0x7a, - 0x9d, 0xda, 0x9c, 0x35, 0xb5, 0xfe, 0xb1, 0xb0, 0x66, 0x6a, - 0xee, 0xbf, 0x29, 0xf8, 0x63, 0x0b, 0xa2, 0x02, 0x57, 0xcf, - 0xa9, 0x35, 0x19, 0x4f, 0x55, 0xab, 0xf9, 0x14, 0x20, 0x6d, - 0x58, 0x6b, 0xca, 0x83, 0x44, 0x95, 0x1e, 0xf3, 0x5c, 0xaa, - 0x2d, 0xb8, 0x03, 0xe2, 0x6b, 0x44, 0xa5, 0x33, 0xf8, 0xf6, - 0xae, 0x52, 0x90, 0xb4, 0xd2, 0x2f, 0x14, 0xd5, 0xaf, 0xfd, - 0xfd, 0xd4, 0x32, 0xbb, 0xb7, 0x6a, 0x62, 0x43, 0x60, 0x3b, - 0x3b, 0xfd, 0x88, 0x6f, 0x39, 0x28, 0x3d, 0x91, 0x96, 0xd4, - 0xc1, 0x2d, 0x3f, 0x6b, 0x6e, 0x86, 0xf9, 0xb9, 0x3f, 0x58, - 0x4c, 0x2d, 0xc5, 0xdc, 0xdf, 0xb3, 0x5d, 0x6f, 0x1b, 0x82, - 0x3a, 0x71, 0xde, 0x6f, 0xe6, 0x37, 0xf7, 0x27, 0xf3, 0x6e, - 0x7b, 0x77, 0x75, 0xfd, 0x8b, 0xb8, 0xba, 0x96, 0x3a, 0x0d, - 0x52, 0x4f, 0xc5, 0x4b, 0xe4, 0x2d, 0x38, 0xc8, 0xf7, 0xa6, - 0xd2, 0x0e, 0xbb, 0x11, 0xdc, 0x22, 0x97, 0x6b, 0xd7, 0xcf, - 0xad, 0x70, 0xe8, 0xfa, 0xee, 0x7a, 0xbb, 0x36, 0x66, 0xad, - 0x39, 0x46, 0xd2, 0x3a, 0xed, 0x97, 0xfc, 0x3a, 0xed, 0x97, - 0x96, 0xeb, 0xb4, 0xbd, 0x58, 0xab, 0x97, 0x35, 0x60, 0x5a, - 0x0a, 0xab, 0xd4, 0xe8, 0x64, 0x1b, 0x55, 0xbe, 0xfb, 0x7e, - 0xbe, 0xfb, 0x7e, 0xbe, 0xfb, 0x7e, 0xbe, 0x5d, 0xae, 0x54, - 0x7b, 0xeb, 0xaf, 0x58, 0xee, 0xaf, 0x73, 0x9e, 0x22, 0x15, - 0x3f, 0x7e, 0x8f, 0xe5, 0x7c, 0x8f, 0xe5, 0x7c, 0x8f, 0xb5, - 0xff, 0xc5, 0x57, 0x70, 0x37, 0x44, 0x07, 0x3d, 0xb2, 0x7e, - 0x13, 0xde, 0x47, 0x0f, 0xdf, 0x57, 0xef, 0xfb, 0xea, 0x7d, - 0x5f, 0xbd, 0xbf, 0xf8, 0xea, 0x9d, 0xad, 0x1e, 0x81, 0x03, - 0xb5, 0x09, 0xe7, 0x2a, 0x88, 0x59, 0x36, 0xb8, 0xf3, 0x24, - 0xfc, 0x2e, 0x79, 0x6b, 0x90, 0xd7, 0xa5, 0xeb, 0x18, 0xfb, - 0xfe, 0xd9, 0x9e, 0x04, 0x05, 0x8a, 0x81, 0x9e, 0x83, 0x7b, - 0x83, 0xbe, 0x6b, 0x82, 0x07, 0xda, 0x6c, 0x49, 0x77, 0xb9, - 0x1f, 0x9e, 0xf1, 0xcb, 0x2c, 0x6f, 0xa9, 0x51, 0x6f, 0xb3, - 0xd4, 0xc5, 0x2a, 0xfe, 0xe4, 0xcb, 0x3e, 0x0e, 0xed, 0x27, - 0xe0, 0xf1, 0xdb, 0x8c, 0x39, 0xfe, 0xdd, 0x56, 0xaf, 0x18, - 0xf5, 0xb2, 0xce, 0x25, 0xb5, 0xbe, 0x0d, 0xe6, 0x16, 0x02, - 0x5b, 0xe3, 0xc2, 0xad, 0x4b, 0x7e, 0x1a, 0x97, 0xe0, 0xd1, - 0x7e, 0x72, 0x91, 0x6b, 0x43, 0x72, 0xdb, 0x70, 0x69, 0x5d, - 0xd7, 0xaa, 0x5c, 0xb5, 0x66, 0xce, 0x16, 0x43, 0x2b, 0x65, - 0x1d, 0x8e, 0x20, 0x05, 0x7d, 0x8b, 0xea, 0xe7, 0x7e, 0xca, - 0xa2, 0xfa, 0xdd, 0xdd, 0x54, 0xb2, 0x62, 0x2a, 0x46, 0x27, - 0x64, 0xc2, 0xd4, 0xb0, 0x5f, 0x96, 0x79, 0xbf, 0x04, 0xcf, - 0x11, 0x86, 0xd4, 0xb2, 0xf9, 0xdd, 0x54, 0x12, 0xbe, 0x82, - 0x5e, 0x1a, 0xfc, 0xed, 0x3b, 0x22, 0xf9, 0xbb, 0x46, 0xf1, - 0x17, 0xd0, 0x28, 0xee, 0x80, 0x1d, 0xe2, 0x2c, 0x86, 0x98, - 0x3d, 0x4e, 0x7f, 0x3f, 0x3c, 0x3f, 0x3a, 0x38, 0x3f, 0x39, - 0xda, 0x3f, 0x3b, 0x38, 0xbb, 0x38, 0x39, 0x4f, 0xe5, 0xc4, - 0xbc, 0x64, 0xc5, 0x9b, 0x30, 0xc1, 0x0a, 0x21, 0x3e, 0x2f, - 0x6d, 0x92, 0x58, 0x93, 0xae, 0x90, 0xfd, 0xe3, 0xb3, 0x83, - 0x8b, 0xb3, 0x93, 0x93, 0x03, 0xf8, 0x5f, 0xbe, 0x3a, 0xe4, - 0xa7, 0x54, 0xeb, 0x41, 0x5f, 0xab, 0x69, 0x39, 0xeb, 0x34, - 0xe3, 0xd9, 0x75, 0x50, 0x22, 0x71, 0xb9, 0x83, 0x5f, 0xc8, - 0xc3, 0x26, 0x56, 0x47, 0xff, 0x21, 0x4d, 0x76, 0x40, 0x9f, - 0x36, 0xb1, 0x55, 0xdd, 0xdf, 0x73, 0xc5, 0x0f, 0xa5, 0x6d, - 0x27, 0x00, 0xa5, 0x39, 0x0c, 0xa1, 0x47, 0x14, 0xce, 0x81, - 0xb9, 0x01, 0x61, 0x8c, 0x6e, 0x7f, 0xea, 0x0a, 0x08, 0x38, - 0x13, 0x5b, 0xcf, 0x0e, 0x0d, 0x4e, 0x28, 0xcf, 0x1e, 0xce, - 0x38, 0xf3, 0xf0, 0xf7, 0xfd, 0x8b, 0xe3, 0xa3, 0x8b, 0x13, - 0x4d, 0x34, 0x1d, 0xff, 0x81, 0xfb, 0x3c, 0x92, 0x1f, 0xd9, - 0x07, 0x3d, 0x4d, 0x9c, 0x70, 0x28, 0xc0, 0x3d, 0x7b, 0xc3, - 0xe1, 0x79, 0x92, 0x7b, 0x47, 0xf6, 0x22, 0x73, 0x3c, 0xff, - 0x3d, 0x69, 0xfd, 0xc1, 0xfe, 0x4f, 0x4c, 0xc9, 0x37, 0xfb, - 0xc7, 0xc2, 0x9c, 0x5a, 0xe4, 0xe2, 0x25, 0x23, 0x2d, 0xdf, - 0x1f, 0x5b, 0x3b, 0x04, 0xe4, 0xf2, 0x45, 0x7b, 0x37, 0xc5, - 0xb4, 0x96, 0xd3, 0xfe, 0xd5, 0xf5, 0x3c, 0x1d, 0x4f, 0xd2, - 0xc3, 0xb1, 0x4e, 0x84, 0xdf, 0xa6, 0x08, 0x26, 0xa1, 0xce, - 0x25, 0xe1, 0x8f, 0x3d, 0xb5, 0x64, 0x1c, 0x5b, 0x10, 0x0c, - 0x56, 0xb2, 0xa1, 0x27, 0x61, 0xc0, 0xe4, 0xf1, 0xbb, 0xe1, - 0xe1, 0x5d, 0x4d, 0x78, 0x57, 0x13, 0xca, 0xa1, 0x73, 0xd1, - 0xb6, 0x0f, 0xf6, 0xc5, 0x06, 0x5c, 0x06, 0x81, 0x07, 0x6c, - 0x9f, 0x3b, 0x7b, 0xb3, 0x22, 0x6d, 0x64, 0x7c, 0xa5, 0x15, - 0x1e, 0x94, 0x57, 0x78, 0xd0, 0x6a, 0x85, 0x87, 0xe5, 0x15, - 0x1e, 0xfe, 0x25, 0x72, 0xda, 0xf6, 0xd7, 0xf0, 0xd7, 0x1c, - 0x65, 0xdd, 0xe0, 0x49, 0xae, 0x2f, 0x92, 0xcd, 0x10, 0xbf, - 0x35, 0xf8, 0xeb, 0xca, 0x49, 0xb4, 0xe7, 0xf6, 0x77, 0x80, - 0x35, 0x16, 0x42, 0xf8, 0x80, 0xbb, 0x87, 0xe0, 0xe7, 0x55, - 0xa4, 0xee, 0xbb, 0x84, 0x7c, 0x97, 0x90, 0xbf, 0xbe, 0x84, - 0x8c, 0x09, 0x63, 0x2f, 0xf3, 0x51, 0x3f, 0x2f, 0xf6, 0xd5, - 0x53, 0x01, 0x46, 0xf8, 0x54, 0x8f, 0x32, 0x75, 0xbc, 0x48, - 0x7e, 0xfa, 0xbd, 0xac, 0xef, 0xb0, 0x95, 0x7e, 0xc8, 0x17, - 0x9e, 0xef, 0xf0, 0x65, 0xfe, 0xbe, 0xb2, 0xdf, 0x57, 0xf6, - 0x9f, 0x74, 0x65, 0xdb, 0x77, 0x81, 0x98, 0x88, 0xdb, 0x44, - 0x3f, 0xdb, 0x32, 0x22, 0xff, 0x0c, 0xf3, 0xcb, 0x83, 0xe7, - 0x3a, 0x60, 0x19, 0x79, 0xc1, 0x26, 0x31, 0xbf, 0x24, 0x15, - 0x5c, 0xa1, 0x77, 0xc6, 0x8c, 0xbc, 0xcb, 0x39, 0x08, 0x57, - 0xac, 0x03, 0x39, 0x60, 0x65, 0x90, 0x6f, 0xc5, 0xdf, 0xea, - 0x07, 0xca, 0x3d, 0xc3, 0xc8, 0x92, 0x7c, 0xe6, 0x36, 0x0e, - 0xfc, 0x60, 0x1d, 0x6c, 0xa3, 0x19, 0x73, 0xef, 0x27, 0x62, - 0x90, 0x9b, 0x47, 0x92, 0x12, 0x06, 0x2b, 0xf2, 0x2e, 0x0b, - 0x73, 0x5b, 0xf2, 0xd7, 0x10, 0x22, 0xf8, 0x77, 0xe6, 0xc8, - 0x22, 0x17, 0x2c, 0x21, 0xd3, 0x3c, 0xe4, 0xd0, 0x15, 0xac, - 0x71, 0x40, 0x1f, 0x33, 0xfb, 0x90, 0x35, 0xea, 0x8d, 0xa7, - 0x1d, 0x4b, 0xcf, 0x46, 0xf4, 0x37, 0x15, 0xcb, 0xca, 0x9a, - 0xcc, 0xaf, 0xd3, 0xb6, 0x21, 0xe6, 0xe6, 0x88, 0xd3, 0xe0, - 0x31, 0xcf, 0xd5, 0xbd, 0x6c, 0x12, 0xe6, 0x60, 0xde, 0x9f, - 0x2f, 0xba, 0x56, 0xda, 0x1e, 0xa4, 0xfa, 0x67, 0x96, 0x10, - 0x92, 0x40, 0x5a, 0x44, 0x64, 0x11, 0x7c, 0xcd, 0x5b, 0xd2, - 0x88, 0xa9, 0x65, 0x1e, 0x76, 0xd3, 0x30, 0x62, 0x34, 0x61, - 0x82, 0xed, 0xe1, 0xbc, 0x27, 0xc9, 0xd8, 0xed, 0xfd, 0x37, - 0x26, 0x52, 0x6a, 0x8c, 0x5a, 0x63, 0x58, 0x8c, 0x0d, 0x32, - 0xc6, 0xca, 0x03, 0x43, 0x1f, 0x66, 0xb1, 0xab, 0x9e, 0x30, - 0x82, 0x2b, 0x43, 0x94, 0x75, 0x6c, 0xa8, 0xec, 0x94, 0x9c, - 0xab, 0x4e, 0x1a, 0x19, 0x9e, 0x96, 0xd4, 0x7f, 0x2f, 0x3d, - 0x80, 0xf5, 0xaf, 0xc8, 0x6d, 0x38, 0x82, 0x4b, 0xc6, 0x94, - 0x1a, 0xd9, 0x37, 0xa4, 0x11, 0xaf, 0x0b, 0x26, 0x4c, 0x21, - 0x7a, 0x40, 0xa8, 0x82, 0xf6, 0x68, 0xc7, 0x87, 0xff, 0xf8, - 0xad, 0x40, 0x67, 0x2f, 0x20, 0x20, 0x5f, 0x62, 0xae, 0xef, - 0x8b, 0x63, 0x05, 0x00, 0x0c, 0xbf, 0x94, 0x95, 0xe2, 0xbf, - 0xa5, 0xce, 0x11, 0x28, 0x7e, 0x22, 0x91, 0x48, 0xf8, 0x70, - 0x9c, 0x4e, 0x1c, 0x27, 0x0f, 0xd0, 0xdf, 0xa4, 0xf1, 0xf9, - 0x5b, 0x06, 0xc7, 0x33, 0x80, 0x38, 0x49, 0x9b, 0xa8, 0xe0, - 0xde, 0x5d, 0x5c, 0xc3, 0xdb, 0x08, 0xd8, 0xd4, 0x24, 0xfc, - 0xed, 0x7d, 0xcb, 0xac, 0x72, 0x7c, 0xd0, 0x55, 0xac, 0xf2, - 0x56, 0xd4, 0x0f, 0x39, 0x38, 0xfc, 0xed, 0xa7, 0x9e, 0x64, - 0x0b, 0xf2, 0xf8, 0x0a, 0x08, 0x18, 0x27, 0xfb, 0xa9, 0xe4, - 0x07, 0x55, 0xf0, 0xfb, 0x82, 0xcd, 0x72, 0x1d, 0xf0, 0x14, - 0x1c, 0x49, 0x7c, 0x9b, 0x31, 0xc4, 0x4f, 0xd9, 0xa6, 0x7f, - 0x53, 0x3f, 0x6b, 0xe9, 0xcc, 0x9a, 0xde, 0xf4, 0x3b, 0xaa, - 0x57, 0xc6, 0x0c, 0x84, 0x4f, 0xee, 0xaa, 0xc2, 0x45, 0x90, - 0x39, 0xe8, 0x5f, 0x4e, 0x05, 0x10, 0x52, 0x9e, 0xb2, 0x41, - 0xc8, 0xaa, 0xd3, 0x24, 0x4d, 0xa9, 0x55, 0x29, 0x3b, 0xe9, - 0xd0, 0x1c, 0x59, 0x8b, 0x9b, 0x14, 0xe6, 0x9d, 0x62, 0x52, - 0xd0, 0x09, 0x9f, 0x9b, 0x5b, 0xd3, 0x91, 0x39, 0x50, 0xa2, - 0xde, 0xac, 0x97, 0x18, 0x84, 0x48, 0x8d, 0xa0, 0xdb, 0x8f, - 0x36, 0xbd, 0xcb, 0xf1, 0x78, 0xae, 0xe0, 0xda, 0x5d, 0x06, - 0x41, 0xad, 0x9b, 0x31, 0x9c, 0xae, 0x75, 0xb9, 0x42, 0x89, - 0x2d, 0xa4, 0x31, 0x8a, 0x70, 0x62, 0x64, 0xf2, 0xb8, 0x3a, - 0xfa, 0x22, 0xa1, 0x0a, 0x7c, 0x41, 0xd3, 0x4c, 0x88, 0x62, - 0x4c, 0x47, 0x17, 0x44, 0xf5, 0xc2, 0xdc, 0xd8, 0xda, 0x5b, - 0x8a, 0xa1, 0xa7, 0x09, 0x68, 0x29, 0x24, 0x4f, 0xc2, 0x50, - 0xeb, 0x64, 0xd4, 0x63, 0x94, 0x23, 0xd1, 0x1b, 0x50, 0x24, - 0xdd, 0x4e, 0x92, 0xf0, 0xa4, 0x1e, 0x21, 0x43, 0xad, 0x58, - 0x8b, 0x35, 0x37, 0x1b, 0xc7, 0xad, 0x60, 0x4c, 0x4d, 0x2f, - 0x08, 0x36, 0x70, 0x94, 0xef, 0xa8, 0xb2, 0x4e, 0xe4, 0x67, - 0x67, 0x80, 0x9e, 0x0e, 0xed, 0xe8, 0xbb, 0x0a, 0x1c, 0x33, - 0x20, 0xc5, 0x79, 0xcd, 0xa2, 0xcc, 0x4e, 0xdf, 0x0a, 0xd7, - 0xbc, 0x78, 0xbe, 0xa9, 0x7f, 0xf3, 0xcc, 0x56, 0xe3, 0x52, - 0x84, 0xaf, 0xdd, 0x4f, 0x27, 0x34, 0xee, 0x06, 0xd9, 0xe8, - 0x80, 0x19, 0x07, 0xde, 0x08, 0xa3, 0x0d, 0x04, 0x21, 0xdf, - 0x91, 0xa3, 0x98, 0x02, 0x0d, 0xe0, 0x7c, 0xdd, 0x4d, 0x33, - 0x0e, 0x24, 0x15, 0x48, 0x1e, 0xa6, 0x72, 0x2d, 0x15, 0xf9, - 0x49, 0x2f, 0x07, 0x3c, 0xc5, 0xf2, 0x63, 0xbb, 0xc7, 0x81, - 0xba, 0x7b, 0x24, 0xef, 0xb5, 0x83, 0xc8, 0xf3, 0x43, 0xbd, - 0x6f, 0x7e, 0x78, 0xa8, 0xf7, 0x6c, 0xd1, 0xe9, 0x58, 0xb3, - 0x59, 0x3a, 0xd6, 0xdb, 0xdb, 0xe1, 0x75, 0xba, 0x5d, 0xad, - 0x50, 0x76, 0xec, 0xfc, 0xe4, 0x3c, 0xa3, 0xe5, 0x64, 0x3a, - 0xbe, 0x9a, 0x26, 0x34, 0x0e, 0x53, 0x34, 0xfa, 0xbe, 0x31, - 0x61, 0x59, 0xb6, 0xf3, 0x01, 0x0c, 0xc4, 0x60, 0xe6, 0xa3, - 0x14, 0x0d, 0x16, 0xd5, 0xac, 0xc3, 0x8b, 0x21, 0xe9, 0xb3, - 0x10, 0x70, 0x4c, 0x47, 0x41, 0x33, 0x1f, 0x7a, 0x66, 0xc0, - 0x17, 0x9e, 0x61, 0x09, 0xdc, 0xb1, 0x95, 0x59, 0x43, 0xd1, - 0xe0, 0x4b, 0x79, 0x6f, 0xdc, 0x97, 0x23, 0xc2, 0x81, 0x51, - 0x79, 0x8f, 0x44, 0x41, 0xee, 0x0a, 0xd1, 0x83, 0xec, 0x1c, - 0xf6, 0xfa, 0x14, 0x11, 0x7e, 0x77, 0x4a, 0xa7, 0x38, 0x94, - 0x82, 0xf0, 0x8d, 0x3a, 0x9a, 0x05, 0x6e, 0x6b, 0x8a, 0xf0, - 0x91, 0xd4, 0x5c, 0x0d, 0xba, 0x3a, 0xbb, 0x84, 0x7a, 0x28, - 0xe6, 0xb7, 0x96, 0x8a, 0x2e, 0x52, 0x03, 0xbc, 0x78, 0x85, - 0x9a, 0x28, 0x49, 0x26, 0x31, 0x31, 0xe1, 0xaf, 0x99, 0x2a, - 0x9d, 0x02, 0xb3, 0x12, 0x60, 0x68, 0x49, 0x43, 0xe6, 0x16, - 0x22, 0x52, 0x84, 0x82, 0x47, 0x57, 0x04, 0xba, 0x2e, 0x5e, - 0x34, 0x43, 0x6b, 0xd6, 0x40, 0xd6, 0xcd, 0xac, 0xb4, 0xa4, - 0x43, 0x09, 0xbe, 0xe3, 0xc0, 0x80, 0x7b, 0xb3, 0xbd, 0xf5, - 0xe2, 0x02, 0x59, 0x63, 0x8d, 0xcc, 0xcb, 0x81, 0xa5, 0x2c, - 0x0c, 0xcb, 0xb7, 0xef, 0x90, 0x03, 0x51, 0x82, 0x56, 0x5b, - 0x04, 0x30, 0x3f, 0xe3, 0x04, 0x0e, 0x05, 0xb8, 0x1b, 0x6d, - 0x0a, 0xa4, 0x05, 0x4b, 0xeb, 0x6b, 0x67, 0xb0, 0x98, 0xf5, - 0x6f, 0x54, 0xb1, 0x97, 0x6a, 0x8b, 0xf1, 0x11, 0xbc, 0xac, - 0xbc, 0x6d, 0x84, 0x60, 0x9e, 0x3e, 0x19, 0x0e, 0xa9, 0x29, - 0x32, 0x6c, 0xcf, 0x33, 0x82, 0xf8, 0x11, 0x84, 0xd1, 0x6f, - 0x85, 0xd8, 0xfb, 0x73, 0x86, 0xe0, 0x7f, 0x2c, 0xe2, 0x6b, - 0x63, 0xe8, 0x7e, 0x6d, 0x4c, 0x0f, 0x90, 0xe8, 0x9a, 0xac, - 0x8d, 0x98, 0x25, 0x10, 0x28, 0x44, 0xd4, 0x06, 0x37, 0x12, - 0x7a, 0xbc, 0xcb, 0x12, 0x43, 0x1e, 0x29, 0xb5, 0x0a, 0x23, - 0x53, 0x85, 0x27, 0xd7, 0xb2, 0x72, 0x4e, 0x7b, 0x64, 0xac, - 0x09, 0x35, 0xe0, 0x18, 0x0d, 0xf4, 0xf4, 0xb5, 0x4f, 0x46, - 0xa2, 0x80, 0xb6, 0xfe, 0x58, 0xa5, 0x47, 0x3f, 0xbb, 0xe5, - 0xcf, 0x6e, 0xfc, 0x68, 0x00, 0x7a, 0x1e, 0x68, 0x70, 0xc6, - 0xc8, 0x6e, 0xbb, 0x4c, 0xbd, 0x41, 0xeb, 0x57, 0x05, 0xad, - 0x87, 0x6a, 0x21, 0x81, 0xa2, 0x6e, 0xde, 0x8d, 0x55, 0x41, - 0x37, 0xd2, 0xd5, 0x34, 0xe8, 0xcf, 0x5f, 0x51, 0xdb, 0x4d, - 0x2c, 0x19, 0xb6, 0xc7, 0x6c, 0xc2, 0x64, 0xed, 0x1d, 0xa7, - 0x6c, 0x1d, 0x70, 0x14, 0x59, 0x11, 0x6d, 0x9d, 0x77, 0x8d, - 0x8f, 0x49, 0xf2, 0x01, 0x6a, 0xbc, 0x21, 0x64, 0xc4, 0x23, - 0x54, 0x0f, 0x7f, 0xd5, 0xf7, 0x1d, 0x14, 0x4a, 0x1f, 0x20, - 0x40, 0x07, 0xf4, 0xae, 0xf8, 0x90, 0x93, 0x93, 0x0e, 0x42, - 0xb8, 0x1c, 0xc8, 0x36, 0x95, 0x76, 0xe5, 0x4b, 0x02, 0xd9, - 0xb0, 0x96, 0x47, 0x94, 0xdc, 0x0b, 0xd0, 0x4b, 0x00, 0x85, - 0xae, 0x26, 0xde, 0x45, 0x41, 0x7b, 0x73, 0x49, 0x6b, 0xe2, - 0x5a, 0x14, 0xb4, 0x3a, 0xdb, 0x6a, 0xac, 0x07, 0x44, 0x52, - 0xd0, 0xe2, 0x26, 0xc6, 0xe8, 0x02, 0xb2, 0x4f, 0x21, 0x81, - 0xce, 0xcd, 0x24, 0x7b, 0xc3, 0xe0, 0xeb, 0xa7, 0x02, 0x58, - 0xae, 0x36, 0xf9, 0x66, 0x96, 0x66, 0x7c, 0x6b, 0x02, 0x57, - 0x1f, 0x31, 0xef, 0x26, 0xd1, 0x84, 0xf9, 0x76, 0xde, 0xa2, - 0x84, 0x27, 0x75, 0xbd, 0xf4, 0x95, 0x36, 0x30, 0x9b, 0x73, - 0xe5, 0x46, 0xc0, 0x2d, 0x14, 0xee, 0xeb, 0x52, 0xfe, 0x5f, - 0x46, 0x7b, 0x2c, 0xbe, 0xca, 0x0d, 0x02, 0xd8, 0x2b, 0x0a, - 0xc6, 0x50, 0x1a, 0x5b, 0x14, 0x8c, 0x91, 0x37, 0x48, 0x34, - 0xd2, 0x42, 0xa6, 0x54, 0x1c, 0x7f, 0xa1, 0x95, 0xe2, 0xe5, - 0x0a, 0xc4, 0xb9, 0x02, 0x2f, 0x31, 0x04, 0xc2, 0x42, 0x46, - 0x89, 0xd0, 0xd3, 0xf3, 0x9f, 0x4c, 0x25, 0x32, 0x3f, 0xd9, - 0x3f, 0xcd, 0x32, 0xc7, 0xea, 0x69, 0x31, 0xad, 0x64, 0x6c, - 0x2e, 0xcd, 0xc0, 0x8e, 0x2d, 0x59, 0xd4, 0x90, 0x45, 0x9a, - 0x7c, 0x96, 0x63, 0xe6, 0xd2, 0x6a, 0x34, 0xc0, 0x2a, 0xad, - 0xac, 0xe0, 0xf2, 0xc3, 0x40, 0x67, 0x50, 0xfb, 0x2c, 0x20, - 0x29, 0xe3, 0xfb, 0x8a, 0x32, 0x5e, 0xeb, 0x0c, 0xa0, 0xa5, - 0x0e, 0x67, 0xed, 0x67, 0xc5, 0x06, 0xc1, 0xd4, 0x56, 0x56, - 0xdb, 0x28, 0x18, 0xad, 0x90, 0x27, 0x0e, 0x1c, 0x3a, 0x1e, - 0xac, 0x8d, 0x7c, 0x70, 0xf0, 0x2d, 0x72, 0xca, 0x91, 0x29, - 0xa9, 0xa9, 0xb6, 0x01, 0x6c, 0x08, 0x1c, 0x77, 0xbb, 0x66, - 0x5c, 0x70, 0xae, 0xda, 0xbf, 0xd8, 0x6b, 0x3d, 0x0d, 0x9c, - 0x16, 0xa6, 0xf2, 0x9c, 0xfe, 0x4a, 0x0c, 0x29, 0xc3, 0xda, - 0x6c, 0x70, 0x35, 0x1d, 0x2f, 0x46, 0x2a, 0x72, 0x1a, 0xc2, - 0xad, 0xf3, 0x1d, 0x6d, 0x5b, 0x84, 0xd9, 0x57, 0xad, 0x25, - 0xa6, 0xab, 0x6f, 0x23, 0xf9, 0x62, 0x26, 0x29, 0x7d, 0x0e, - 0x79, 0xa6, 0xa1, 0xb8, 0x82, 0x95, 0x05, 0x76, 0xc0, 0x9a, - 0x0a, 0x64, 0x12, 0x79, 0xbf, 0x40, 0xd9, 0x73, 0x9e, 0x2b, - 0xd2, 0xfa, 0x3c, 0x1a, 0x7f, 0x19, 0x29, 0xc7, 0xbe, 0x85, - 0xff, 0xdd, 0x0f, 0x9e, 0xfd, 0xe6, 0xc1, 0xb5, 0x1d, 0x94, - 0x96, 0x27, 0x12, 0xe4, 0xd9, 0x05, 0x67, 0xf9, 0xe4, 0x8d, - 0x16, 0x47, 0xe0, 0xea, 0x53, 0x1f, 0x1b, 0xf4, 0x71, 0xce, - 0xd6, 0xae, 0x89, 0x70, 0x94, 0x6f, 0x68, 0xed, 0x74, 0x6b, - 0x5a, 0xce, 0xbf, 0xa6, 0xad, 0xe5, 0x5f, 0x3f, 0x41, 0xb5, - 0x24, 0xd2, 0x9e, 0x99, 0xdb, 0xb4, 0x23, 0xce, 0x6d, 0x35, - 0x0a, 0x19, 0xf9, 0xfc, 0xbe, 0x55, 0xa3, 0xd0, 0x1f, 0x4e, - 0x4c, 0x9e, 0x22, 0x8f, 0xaf, 0xe9, 0xfe, 0x7a, 0x63, 0xaf, - 0xe2, 0xe6, 0xec, 0x81, 0x70, 0xd9, 0xc4, 0x03, 0xfc, 0xc1, - 0x7e, 0x1a, 0xb1, 0x8d, 0xc5, 0x23, 0x54, 0x3a, 0xc1, 0x4f, - 0x82, 0x68, 0xe6, 0xae, 0xad, 0x0c, 0xf0, 0xff, 0x21, 0x45, - 0x2c, 0x6b, 0xe2, 0x81, 0x48, 0xb1, 0xc2, 0x32, 0xa0, 0xc3, - 0x9a, 0x50, 0xe5, 0xa8, 0x5d, 0xdc, 0xfa, 0x02, 0x35, 0x99, - 0xb5, 0x21, 0xbe, 0x68, 0xc6, 0xe8, 0x64, 0x58, 0x86, 0x81, - 0x9f, 0x3b, 0x2c, 0x46, 0x92, 0xa8, 0x29, 0x49, 0x7c, 0x35, - 0xae, 0x6f, 0x80, 0x1b, 0x7f, 0x56, 0x24, 0xed, 0xf8, 0x7b, - 0xfe, 0x56, 0xfb, 0x65, 0x3a, 0x4a, 0x25, 0x60, 0x0b, 0x7d, - 0x9c, 0x3a, 0x8d, 0xe3, 0xbe, 0xe5, 0x66, 0x4a, 0xeb, 0x0f, - 0x15, 0x99, 0x8a, 0xb5, 0xb0, 0x8c, 0x4f, 0x8b, 0x27, 0x76, - 0x2d, 0x8e, 0x8e, 0x02, 0xd6, 0x96, 0x1a, 0x9a, 0xce, 0x78, - 0x38, 0xfc, 0x41, 0x83, 0x23, 0x39, 0xd5, 0x1d, 0xa4, 0x82, - 0x11, 0xb5, 0xfa, 0x86, 0xb9, 0x54, 0xea, 0x9e, 0xc0, 0xb7, - 0xbc, 0x4f, 0xa3, 0x9b, 0x5f, 0xb4, 0x4b, 0x25, 0xc2, 0x04, - 0x39, 0xdd, 0x6e, 0x5c, 0x2f, 0x88, 0x89, 0x8b, 0x05, 0x11, - 0x28, 0x07, 0xa2, 0x4b, 0x2e, 0x7e, 0x4b, 0x3d, 0x30, 0xb4, - 0xc4, 0x88, 0x4d, 0xfc, 0x78, 0x77, 0x8a, 0x5f, 0xef, 0x0e, - 0x1e, 0x2d, 0x9e, 0x80, 0xc7, 0x07, 0xcd, 0xac, 0xaf, 0x97, - 0x0e, 0xcd, 0xd1, 0x82, 0xb9, 0x29, 0x08, 0x07, 0x58, 0x7f, - 0x6b, 0xeb, 0x3b, 0x27, 0x98, 0xb3, 0x59, 0x7f, 0x36, 0x4f, - 0x41, 0xba, 0x9a, 0x51, 0xe4, 0x46, 0x62, 0xd5, 0xa5, 0x74, - 0x16, 0xa9, 0xdc, 0x85, 0xa8, 0xc7, 0xb5, 0x2e, 0x53, 0x04, - 0xe7, 0x17, 0x32, 0xe0, 0xcd, 0x4d, 0xbf, 0xc9, 0x9e, 0x20, - 0x6d, 0x19, 0x87, 0x2d, 0x6d, 0x19, 0xef, 0xc0, 0xda, 0xbf, - 0x20, 0xb0, 0x76, 0xf9, 0x66, 0xf6, 0xbe, 0xc7, 0xbf, 0xef, - 0xf1, 0xef, 0x7b, 0xfc, 0xbf, 0xca, 0x1e, 0x4f, 0x64, 0x20, - 0x73, 0xde, 0xa3, 0x3b, 0xc0, 0x91, 0x2c, 0x21, 0x13, 0xdf, - 0x3e, 0xfd, 0x5b, 0x87, 0xb7, 0x92, 0x97, 0x54, 0xfc, 0x2f, - 0xb3, 0xe4, 0x26, 0x73, 0x36, 0x21, 0x3e, 0x11, 0xc1, 0x3d, - 0xbd, 0x64, 0x8d, 0xaa, 0x39, 0x5b, 0xa4, 0x36, 0x7d, 0x3a, - 0x06, 0x98, 0x6a, 0x85, 0xad, 0x9f, 0xb7, 0x94, 0xc9, 0xe7, - 0xc3, 0x74, 0x43, 0x83, 0x4d, 0xbd, 0x76, 0x8e, 0x27, 0x13, - 0xd6, 0xce, 0xa3, 0x54, 0x3b, 0x83, 0xcd, 0xa6, 0x46, 0x3b, - 0xc5, 0x1d, 0xf2, 0x38, 0xd5, 0x52, 0x17, 0x45, 0xd7, 0x56, - 0x6e, 0x28, 0xa1, 0xb9, 0x9c, 0x59, 0x23, 0xd5, 0xd5, 0x53, - 0x22, 0x68, 0xcc, 0x50, 0xea, 0xec, 0x3a, 0x90, 0x28, 0x50, - 0xd4, 0x2c, 0x91, 0xf6, 0x83, 0x33, 0x51, 0x66, 0x0a, 0x20, - 0xa3, 0xcf, 0x5f, 0x27, 0xab, 0xb5, 0x5f, 0xd3, 0x06, 0x61, - 0x76, 0xc6, 0x8b, 0xd9, 0xbc, 0xdf, 0x49, 0x9b, 0x22, 0xcc, - 0x55, 0xb0, 0x8d, 0x62, 0x77, 0xa5, 0x3f, 0x87, 0xe6, 0xdc, - 0x1a, 0x0c, 0xfa, 0xf3, 0x8c, 0xe8, 0xa0, 0x19, 0x5c, 0x00, - 0x9e, 0xe7, 0xc6, 0xfa, 0x3e, 0xc7, 0x57, 0xb3, 0x61, 0xda, - 0x32, 0x81, 0x1e, 0x6a, 0x3b, 0x09, 0x8f, 0x2f, 0xfb, 0x03, - 0x2b, 0x6d, 0x96, 0x18, 0x06, 0x77, 0xae, 0x57, 0x2b, 0xa5, - 0x05, 0x5c, 0xf5, 0x6e, 0x90, 0x38, 0xa1, 0x4c, 0xe8, 0xaf, - 0x26, 0x9e, 0x38, 0xd1, 0x2e, 0x5a, 0x3a, 0x42, 0x0a, 0x43, - 0x01, 0x61, 0x91, 0x64, 0x48, 0xac, 0xa1, 0x11, 0x67, 0x9e, - 0x7a, 0xee, 0xb0, 0x52, 0x88, 0xd9, 0xf5, 0x64, 0x5f, 0x8a, - 0x57, 0xad, 0x71, 0x03, 0x81, 0x12, 0x63, 0xcc, 0x36, 0x60, - 0xe5, 0xde, 0x53, 0x86, 0x64, 0x94, 0x0f, 0xa4, 0xd4, 0x19, - 0x4a, 0x11, 0x6d, 0x39, 0xab, 0x24, 0xf8, 0xf8, 0x35, 0xd3, - 0x7a, 0x3c, 0x61, 0xf7, 0x80, 0x8d, 0xb0, 0x44, 0x47, 0xfc, - 0x41, 0x2d, 0x82, 0x76, 0xe8, 0x62, 0x47, 0x9c, 0x54, 0xb8, - 0x15, 0x6c, 0xef, 0x0d, 0x7d, 0x29, 0xf5, 0xe1, 0x86, 0x7f, - 0x51, 0x33, 0xe0, 0x2a, 0x42, 0xf2, 0x7f, 0xb9, 0x96, 0x86, - 0x1b, 0xef, 0x09, 0x48, 0xd7, 0xca, 0x8f, 0xa6, 0xa8, 0xe2, - 0x4d, 0x9d, 0xd9, 0x9d, 0x3c, 0x67, 0xb9, 0xfa, 0x3d, 0x89, - 0x43, 0xdb, 0x27, 0x0a, 0x6c, 0x66, 0x85, 0xf3, 0xe4, 0xb5, - 0x80, 0xbd, 0xc9, 0x3f, 0x68, 0x34, 0x7c, 0xf6, 0x8a, 0x52, - 0x11, 0xbd, 0x17, 0xcd, 0x55, 0x33, 0xd2, 0xc0, 0x77, 0x54, - 0xc2, 0x96, 0xef, 0x54, 0x25, 0xab, 0xb1, 0x8e, 0xf9, 0x54, - 0x90, 0x25, 0x7c, 0x28, 0xb1, 0x58, 0x05, 0x2c, 0x96, 0xc4, - 0x7d, 0x9e, 0xb3, 0x52, 0xe2, 0xf9, 0x5d, 0x7b, 0xf5, 0xa2, - 0x14, 0xef, 0x9a, 0x8e, 0x96, 0xaa, 0xb8, 0xa9, 0xee, 0x76, - 0xf9, 0x57, 0x98, 0x4e, 0x91, 0xd1, 0xc9, 0x84, 0x1e, 0x49, - 0x13, 0x2a, 0xbe, 0x2f, 0x9d, 0x52, 0x52, 0x00, 0xc9, 0x07, - 0x39, 0xe8, 0xb0, 0xb6, 0x28, 0x8e, 0x45, 0x5a, 0xe2, 0x66, - 0x97, 0x4c, 0x62, 0xfd, 0xb4, 0x50, 0xab, 0xc0, 0x77, 0x5c, - 0x69, 0x84, 0x79, 0x5f, 0x0d, 0xf1, 0x65, 0x1d, 0xe2, 0xca, - 0xdc, 0x09, 0x94, 0xed, 0x56, 0xa7, 0xd0, 0x5a, 0x93, 0x63, - 0xd8, 0x4e, 0x3e, 0xbc, 0x9c, 0xf0, 0xd0, 0x24, 0x56, 0x20, - 0xf3, 0xfc, 0x52, 0xcf, 0x79, 0xd6, 0xea, 0xcc, 0xeb, 0x5b, - 0x26, 0xc5, 0xab, 0xef, 0xfd, 0x9c, 0xab, 0xef, 0xe2, 0x6b, - 0xf6, 0x03, 0xed, 0x6b, 0x76, 0xe1, 0x80, 0x24, 0x3b, 0x8b, - 0x17, 0x7d, 0xc2, 0x4e, 0x2a, 0x92, 0x17, 0x78, 0xfe, 0x07, - 0xf0, 0xe0, 0x30, 0xbd, 0x55, 0x4e, 0x0c, 0xff, 0xd8, 0x82, - 0x70, 0x57, 0x50, 0x87, 0x35, 0x5f, 0x4e, 0x06, 0xe6, 0x48, - 0x3d, 0x0e, 0x80, 0x18, 0xa7, 0x24, 0xd3, 0x4b, 0x75, 0x85, - 0x0b, 0xa6, 0x37, 0x2e, 0x45, 0xa8, 0xe5, 0x6b, 0x57, 0xb2, - 0xb8, 0xd3, 0x72, 0x5b, 0x51, 0x99, 0x4d, 0x34, 0x98, 0x9e, - 0x9c, 0xe4, 0x72, 0x5c, 0x25, 0x7b, 0x69, 0x24, 0xe6, 0x25, - 0xa7, 0x1f, 0x72, 0xbe, 0xab, 0x6f, 0x32, 0x19, 0x8d, 0xe7, - 0xcb, 0xce, 0x78, 0xd4, 0xeb, 0x5f, 0x2d, 0xa6, 0xa9, 0x1c, - 0x67, 0xa3, 0x00, 0x1f, 0xef, 0xef, 0xdd, 0x87, 0x6d, 0x58, - 0x94, 0xa9, 0x8c, 0xb2, 0x61, 0x37, 0x9b, 0x0f, 0x9d, 0x32, - 0x7f, 0x0f, 0x35, 0xbd, 0x19, 0xe1, 0xfa, 0x82, 0xcf, 0xcc, - 0xe9, 0x30, 0x75, 0xc2, 0x35, 0xc3, 0x75, 0xe1, 0x27, 0x9d, - 0x79, 0xe2, 0xd1, 0x7d, 0xcc, 0x0f, 0x66, 0x28, 0x45, 0x6f, - 0x31, 0xd3, 0x4f, 0x92, 0xa4, 0x80, 0x27, 0x22, 0xe3, 0x6f, - 0x44, 0x4f, 0xf2, 0x0a, 0x59, 0xf6, 0x88, 0x12, 0xee, 0x64, - 0x44, 0xd6, 0xee, 0xe5, 0x9f, 0x62, 0x3d, 0x72, 0xff, 0xa1, - 0xc2, 0xa9, 0x2a, 0xc6, 0x34, 0x7a, 0x4b, 0x92, 0x87, 0xad, - 0xba, 0xa7, 0xb9, 0xf3, 0x75, 0x2f, 0x19, 0xeb, 0x9e, 0xca, - 0x9a, 0xfe, 0x65, 0x55, 0x4b, 0x7e, 0xf7, 0x72, 0xfe, 0x67, - 0x0b, 0x9c, 0x92, 0x02, 0x9e, 0x0e, 0x4b, 0x03, 0x9e, 0xca, - 0x03, 0xaf, 0x8e, 0xb4, 0x02, 0xaf, 0x6a, 0xdf, 0x2e, 0x74, - 0x2f, 0x9b, 0xdc, 0x2f, 0xa4, 0xc2, 0x35, 0x12, 0x51, 0xab, - 0x6b, 0x1b, 0xe8, 0x5a, 0x03, 0x75, 0xd1, 0x03, 0x0f, 0xc4, - 0xa0, 0x1a, 0x95, 0x2b, 0x4b, 0xdd, 0x8d, 0xae, 0xaa, 0x36, - 0x04, 0x92, 0x58, 0xf6, 0x47, 0xbd, 0xb1, 0x32, 0xea, 0x8c, - 0x8e, 0x81, 0xc3, 0x73, 0xb4, 0xc3, 0xb4, 0x07, 0x96, 0x39, - 0x55, 0x64, 0x45, 0xc7, 0x03, 0x76, 0x68, 0x74, 0xa1, 0x22, - 0x7d, 0x67, 0x47, 0xa0, 0x52, 0xbb, 0x50, 0xac, 0x87, 0xa5, - 0xc8, 0x10, 0xd4, 0x30, 0x46, 0x8c, 0x6c, 0x04, 0xc6, 0xc7, - 0x99, 0x8b, 0xd0, 0x72, 0x7f, 0xab, 0x44, 0xbb, 0x2b, 0x10, - 0x3f, 0x2d, 0x22, 0xde, 0x05, 0x31, 0x64, 0x5e, 0xe0, 0xfc, - 0x56, 0x23, 0x08, 0xfb, 0x4c, 0x0c, 0xc2, 0x36, 0xe0, 0xae, - 0xc0, 0xf7, 0xcb, 0x1a, 0xd6, 0x9f, 0xd6, 0x23, 0x01, 0xdb, - 0xb4, 0x73, 0xd8, 0xfc, 0x12, 0xca, 0x0c, 0x1f, 0xe0, 0x0a, - 0xe2, 0x41, 0x0f, 0x55, 0x8e, 0x40, 0x62, 0x64, 0x18, 0x14, - 0xd3, 0x70, 0x5a, 0x11, 0x25, 0x3b, 0xdc, 0x61, 0x46, 0x4c, - 0x32, 0x1c, 0x37, 0xbf, 0xa5, 0x25, 0x12, 0x5b, 0xd2, 0x38, - 0xce, 0x14, 0xb1, 0x4d, 0xf5, 0x8c, 0xfc, 0xa1, 0x93, 0xe2, - 0x40, 0xf0, 0x47, 0x59, 0xa1, 0xf1, 0xd5, 0xa6, 0x23, 0x72, - 0x5f, 0x81, 0x4a, 0x72, 0x06, 0x9f, 0xe1, 0xc4, 0x33, 0x9e, - 0x67, 0xa0, 0x42, 0x91, 0x8e, 0x37, 0x64, 0x7a, 0x47, 0x7c, - 0x44, 0x08, 0xe5, 0xe9, 0x08, 0x8c, 0x0e, 0x7e, 0x5e, 0x23, - 0x04, 0x23, 0xaf, 0x86, 0x88, 0xb3, 0x94, 0x52, 0x01, 0x85, - 0x8c, 0x31, 0x1d, 0x87, 0x48, 0xf1, 0x3a, 0xd1, 0xab, 0xb4, - 0x0e, 0x31, 0xaf, 0x6f, 0x76, 0x2d, 0xf5, 0x4f, 0x72, 0x6b, - 0x27, 0x11, 0x37, 0xc3, 0xee, 0x09, 0xa3, 0x11, 0xda, 0xcf, - 0xd8, 0x1c, 0xa0, 0x3b, 0x95, 0xd1, 0x92, 0x30, 0x73, 0x5a, - 0xa7, 0xee, 0x5e, 0x4a, 0xcc, 0x2c, 0x4c, 0xb6, 0x2b, 0x04, - 0x43, 0xb6, 0x70, 0x18, 0x57, 0x2a, 0x22, 0x6c, 0x7e, 0xae, - 0xb2, 0xb9, 0x58, 0xe6, 0xcd, 0xe5, 0x44, 0x36, 0x93, 0xcf, - 0xf0, 0x83, 0xfa, 0xec, 0x90, 0xc3, 0xd4, 0x4e, 0x0e, 0x57, - 0xbf, 0x33, 0x73, 0x01, 0x33, 0x6b, 0xf0, 0x95, 0x62, 0x1c, - 0xb8, 0x90, 0xe6, 0xb2, 0xfa, 0xbd, 0x66, 0xbe, 0x26, 0x3c, - 0xe9, 0xbc, 0x2b, 0xc2, 0x6f, 0xab, 0x08, 0x37, 0x18, 0xe1, - 0x5c, 0x37, 0x9b, 0x6a, 0x1a, 0x68, 0x8e, 0xaf, 0x4d, 0x35, - 0x22, 0x83, 0xb1, 0xa9, 0x9e, 0x86, 0x07, 0x81, 0xed, 0xd4, - 0x54, 0xa7, 0x8f, 0x74, 0xd5, 0xe9, 0x9f, 0xaf, 0xae, 0x39, - 0x28, 0x92, 0x19, 0x96, 0xab, 0x79, 0x4b, 0x52, 0x21, 0x15, - 0x88, 0x78, 0xb9, 0x98, 0xba, 0xd3, 0x2d, 0x86, 0x6d, 0xe2, - 0x97, 0xa0, 0xfb, 0xfb, 0x29, 0xe4, 0x26, 0x60, 0xdc, 0x48, - 0xc2, 0x41, 0xc3, 0xdf, 0xfb, 0x6a, 0x34, 0x9e, 0x5a, 0x4b, - 0x0c, 0xe3, 0x34, 0x13, 0x48, 0x27, 0x53, 0xdf, 0x7f, 0xf0, - 0x83, 0x10, 0x90, 0xd8, 0xd2, 0x82, 0x8b, 0xf5, 0x7f, 0xab, - 0xa0, 0xd4, 0xd2, 0xb9, 0xdb, 0x23, 0xab, 0xf0, 0xed, 0x54, - 0xdc, 0xb6, 0x74, 0x5b, 0xd9, 0xa4, 0x86, 0xa7, 0x99, 0xdd, - 0x1f, 0xbb, 0x2b, 0x2a, 0xb8, 0x4f, 0xf7, 0xb3, 0x04, 0x77, - 0x6b, 0xe6, 0xb5, 0x49, 0x03, 0xf3, 0xda, 0xe5, 0x60, 0xdc, - 0xf9, 0x9c, 0xb2, 0xab, 0x5d, 0x7a, 0xc1, 0xea, 0x7b, 0x25, - 0x37, 0x0c, 0xb3, 0x7b, 0x9b, 0x12, 0xe5, 0xb6, 0xb3, 0xd3, - 0x67, 0xb5, 0x51, 0x7f, 0xde, 0x87, 0x5c, 0xfc, 0x2d, 0xb1, - 0x66, 0x71, 0x26, 0x83, 0x5d, 0x71, 0x21, 0x0f, 0xbf, 0x22, - 0x8b, 0x96, 0x3e, 0xe0, 0x97, 0xd5, 0x59, 0xcc, 0x13, 0x62, - 0x47, 0x32, 0x3a, 0x4a, 0x01, 0xa5, 0xaa, 0x82, 0x01, 0xed, - 0x13, 0x4d, 0x54, 0x34, 0x01, 0x83, 0x8a, 0xd1, 0x13, 0xf0, - 0xa7, 0x94, 0x78, 0xaf, 0x48, 0x9f, 0xee, 0x26, 0xd9, 0xb9, - 0x64, 0xe2, 0x7c, 0x47, 0xcb, 0xf2, 0x2b, 0xfc, 0x77, 0xdd, - 0x2b, 0xdf, 0xac, 0xcb, 0xbf, 0x06, 0x43, 0x81, 0x28, 0xbe, - 0x05, 0x9e, 0x98, 0x06, 0xc4, 0x57, 0xad, 0x21, 0xc6, 0x91, - 0xf6, 0xc1, 0x36, 0x5e, 0x05, 0x8a, 0x42, 0x89, 0x87, 0x79, - 0xcc, 0x5e, 0xb0, 0x15, 0x3a, 0x98, 0x8c, 0x1b, 0x18, 0xc0, - 0x47, 0x56, 0xca, 0xec, 0xed, 0x57, 0xc8, 0xb4, 0x98, 0xa9, - 0x68, 0x31, 0xfd, 0xaa, 0x4a, 0xbe, 0xc5, 0xb4, 0xba, 0xc5, - 0xb4, 0xac, 0xc6, 0x91, 0x3f, 0xb2, 0xeb, 0x03, 0x11, 0x9a, - 0x07, 0x99, 0x3e, 0x10, 0x29, 0x79, 0xf9, 0x1f, 0xb9, 0xd7, - 0x61, 0xa2, 0xb6, 0x9f, 0xad, 0xd7, 0xe7, 0xd8, 0xb4, 0xa5, - 0xe0, 0xb2, 0x1b, 0x31, 0xa4, 0xac, 0xf4, 0xd3, 0x02, 0x15, - 0xfb, 0xa6, 0xbe, 0xb1, 0xf9, 0x72, 0x3c, 0x1e, 0x58, 0xec, - 0xde, 0x69, 0x5f, 0x30, 0x76, 0x91, 0xd4, 0x34, 0x79, 0x3a, - 0xee, 0x68, 0x31, 0xbc, 0x4c, 0x41, 0x39, 0x8d, 0xb6, 0xeb, - 0x3b, 0xa4, 0xc5, 0xe4, 0xfa, 0x68, 0x5a, 0x5f, 0x55, 0x63, - 0xe7, 0x5c, 0xec, 0x70, 0xda, 0xfd, 0x0a, 0x72, 0x97, 0x79, - 0xa5, 0x82, 0xd1, 0x0c, 0xa5, 0x0b, 0xaa, 0xb2, 0x4b, 0xd7, - 0x95, 0x20, 0xa9, 0x4c, 0xfc, 0xcb, 0x50, 0x47, 0xcf, 0xac, - 0x3d, 0x7a, 0xfd, 0xd1, 0x64, 0xa1, 0xea, 0xcf, 0x7d, 0x7f, - 0xb3, 0x2d, 0xe8, 0xd3, 0x78, 0x31, 0x9f, 0xa4, 0xfc, 0x54, - 0xe1, 0xb2, 0x2e, 0xfc, 0x08, 0x6e, 0xa5, 0xe6, 0x20, 0xa5, - 0x1c, 0xaf, 0x50, 0x06, 0xe3, 0xbd, 0x3a, 0x0b, 0xe2, 0x0a, - 0xf8, 0x40, 0x0a, 0xff, 0x3e, 0x95, 0x7d, 0x36, 0xc4, 0xf7, - 0xda, 0x8b, 0x62, 0xb5, 0xce, 0xbf, 0x1f, 0xee, 0x0c, 0xbb, - 0xf5, 0x23, 0x69, 0xad, 0x91, 0x25, 0x68, 0xa0, 0x5c, 0xb1, - 0xc7, 0x6d, 0x04, 0x15, 0x37, 0xee, 0x54, 0x88, 0x35, 0x01, - 0x35, 0xab, 0xb3, 0x69, 0xbf, 0xb1, 0x33, 0x6f, 0xce, 0xb9, - 0xb7, 0x06, 0x44, 0xea, 0x41, 0x3d, 0x88, 0x54, 0x49, 0xbe, - 0x1f, 0x6a, 0xca, 0xf7, 0x1f, 0x7d, 0xfc, 0xd9, 0xd8, 0xa1, - 0xbd, 0xe6, 0xba, 0x08, 0xfa, 0x05, 0x62, 0xc1, 0x0d, 0xac, - 0xdd, 0x54, 0x34, 0x50, 0xf3, 0x04, 0x61, 0xb1, 0x46, 0xce, - 0x91, 0x97, 0x71, 0xe1, 0x4a, 0xba, 0xf8, 0x43, 0x18, 0x6c, - 0x37, 0x4b, 0x71, 0x77, 0x41, 0x11, 0xe3, 0x9b, 0x06, 0xb6, - 0x23, 0xce, 0xa3, 0xc4, 0x51, 0xc8, 0x80, 0xff, 0x8b, 0x1f, - 0x81, 0xe1, 0x91, 0xc6, 0x45, 0xb2, 0xbe, 0xff, 0x66, 0x4c, - 0x5b, 0xe4, 0xf8, 0xa0, 0xea, 0x0f, 0x40, 0x33, 0x5e, 0xe9, - 0xb0, 0x46, 0xbc, 0x52, 0x4b, 0xa0, 0xde, 0x1f, 0x09, 0xd0, - 0xc9, 0x6f, 0xbf, 0x02, 0xac, 0x77, 0x3b, 0x6d, 0x79, 0x04, - 0x38, 0xff, 0x26, 0xa5, 0x7e, 0x8d, 0x7f, 0x65, 0x90, 0xae, - 0x1e, 0x88, 0x94, 0xa0, 0xfb, 0x93, 0x84, 0xb2, 0x06, 0x3c, - 0xd6, 0x37, 0x4b, 0x55, 0xbb, 0x53, 0x08, 0x02, 0x3b, 0x8a, - 0x1b, 0x65, 0x30, 0x52, 0xe8, 0x39, 0x08, 0x8f, 0xa0, 0x01, - 0xbd, 0xcd, 0xa3, 0x5b, 0x7b, 0x56, 0xa7, 0x01, 0x01, 0xb8, - 0x31, 0x50, 0x1e, 0x59, 0xe3, 0xc5, 0xc0, 0x31, 0xf4, 0x8d, - 0x72, 0x77, 0xc1, 0xb5, 0x8e, 0xfd, 0x1f, 0x0b, 0x12, 0x86, - 0x7d, 0x4a, 0x3f, 0xcf, 0x6a, 0xcd, 0xae, 0x85, 0xd6, 0x6c, - 0xa2, 0xb6, 0xc6, 0xe6, 0xb5, 0x85, 0xd6, 0x3c, 0xbd, 0xc8, - 0xb8, 0x1c, 0xc6, 0x0d, 0xf0, 0x82, 0x15, 0x82, 0xf3, 0xfb, - 0x6a, 0x7c, 0x1c, 0x21, 0x3e, 0xfd, 0xad, 0x38, 0x6f, 0x41, - 0x69, 0x05, 0xbb, 0xbc, 0x0a, 0x6e, 0x8d, 0x8f, 0x16, 0xe4, - 0xdb, 0xa6, 0xf4, 0x5f, 0xf3, 0xe8, 0x7f, 0x33, 0x3e, 0x76, - 0x21, 0x1f, 0x37, 0xa4, 0xbf, 0x69, 0x9c, 0xb6, 0x39, 0x69, - 0x90, 0xeb, 0x1b, 0x2f, 0xb9, 0xb3, 0xa5, 0xd9, 0x9c, 0x3f, - 0x5a, 0x6d, 0xce, 0xae, 0x69, 0x73, 0xc2, 0x56, 0x9b, 0xf3, - 0xda, 0xb4, 0x39, 0x11, 0x67, 0x67, 0x1a, 0xea, 0xd9, 0x36, - 0x3b, 0x47, 0x9c, 0x9f, 0xd5, 0x1a, 0xda, 0xe1, 0xe7, 0x88, - 0x33, 0xb4, 0x5a, 0x41, 0x2d, 0x86, 0xd6, 0x89, 0x41, 0x41, - 0x42, 0x05, 0x45, 0x28, 0x31, 0x54, 0xa9, 0xd3, 0x63, 0xf9, - 0x5a, 0x53, 0x78, 0xaf, 0xa5, 0xc2, 0xbd, 0x85, 0x8e, 0x9b, - 0x7f, 0xf4, 0x9f, 0xd7, 0x57, 0xd8, 0x26, 0x50, 0x97, 0x1a, - 0xa4, 0x4f, 0xfe, 0xe0, 0x1e, 0xd9, 0xdd, 0x25, 0xa7, 0xd3, - 0xac, 0x63, 0x6f, 0xf2, 0xe5, 0x81, 0x80, 0xfa, 0x85, 0x42, - 0x3e, 0x8a, 0xbf, 0x9c, 0x8c, 0x67, 0x73, 0xfe, 0x2d, 0x0f, - 0xfe, 0xbf, 0x87, 0x2a, 0x7b, 0x05, 0x4f, 0xd7, 0x30, 0x40, - 0xe9, 0xe0, 0x05, 0xf0, 0xd7, 0x89, 0xf0, 0x24, 0x39, 0xd8, - 0x4f, 0x27, 0x35, 0xe3, 0xd9, 0x2e, 0xcd, 0x99, 0x10, 0xcc, - 0xc6, 0xc7, 0xc6, 0x8e, 0xdc, 0x55, 0xb5, 0xfb, 0xa8, 0xd1, - 0x78, 0x34, 0xe8, 0x8f, 0x12, 0x97, 0x2a, 0x31, 0x34, 0x6e, - 0x14, 0xf8, 0x9e, 0xeb, 0x03, 0x3b, 0xac, 0x60, 0xc9, 0xee, - 0x21, 0x63, 0x76, 0x46, 0x68, 0x5c, 0xdf, 0xbf, 0x77, 0xfd, - 0x2a, 0x91, 0x71, 0x9d, 0xdb, 0xce, 0xa0, 0x9f, 0xd8, 0x14, - 0xc4, 0xf0, 0xb8, 0xce, 0x6e, 0xe5, 0x21, 0x28, 0x43, 0x7d, - 0x2c, 0x87, 0x01, 0xa7, 0x92, 0xf8, 0xdf, 0x98, 0x9e, 0x57, - 0xe7, 0x80, 0xc8, 0x90, 0xe4, 0x22, 0x15, 0x4a, 0xae, 0xe6, - 0x71, 0x2e, 0x5d, 0x01, 0x2c, 0x68, 0xfb, 0x2b, 0xce, 0x38, - 0x5d, 0xfe, 0xa0, 0x95, 0x0a, 0x14, 0x2f, 0x7f, 0x25, 0x3a, - 0xa3, 0x21, 0xf1, 0xfb, 0x2d, 0xf2, 0x72, 0xa5, 0x06, 0xd2, - 0x2d, 0xf7, 0x78, 0x6d, 0x3b, 0x49, 0x0d, 0x39, 0x50, 0x01, - 0x47, 0xf0, 0xad, 0x3a, 0xdd, 0xdf, 0x97, 0x8f, 0x5b, 0xc0, - 0xc9, 0x39, 0xd9, 0xfe, 0x47, 0x71, 0xaa, 0x65, 0xf9, 0x24, - 0x55, 0x0f, 0xa5, 0x52, 0x39, 0x02, 0x55, 0x26, 0x22, 0x65, - 0x68, 0xeb, 0x36, 0xcd, 0xcc, 0x86, 0x92, 0x8b, 0x71, 0x25, - 0xd5, 0xf3, 0x9a, 0x1d, 0xc4, 0x68, 0x86, 0x5f, 0x21, 0x85, - 0x6f, 0x33, 0x7a, 0x3b, 0xfb, 0x39, 0x41, 0xf5, 0xb2, 0x9f, - 0x9b, 0xd1, 0x0a, 0x57, 0x1b, 0xc9, 0x4f, 0x67, 0x0a, 0x56, - 0x60, 0x23, 0x00, 0xca, 0xfb, 0x41, 0x8c, 0x8d, 0x7f, 0x61, - 0x08, 0x56, 0xb1, 0x81, 0x03, 0x90, 0xa1, 0x30, 0x66, 0x6a, - 0xfb, 0xbd, 0x11, 0x3f, 0xba, 0x91, 0x41, 0x48, 0xae, 0xed, - 0x9d, 0x81, 0xae, 0xd7, 0x5d, 0xb8, 0xd9, 0x44, 0x3b, 0x7f, - 0xf5, 0x18, 0x06, 0xbe, 0xfb, 0x9a, 0x94, 0x5c, 0xa1, 0x6b, - 0xc2, 0xc8, 0xb8, 0x03, 0xf1, 0x33, 0x00, 0xbe, 0x11, 0x01, - 0x04, 0x38, 0x67, 0xa0, 0x9c, 0xbf, 0x90, 0xb4, 0xbb, 0x71, - 0x85, 0x8b, 0xdb, 0x3a, 0x6e, 0x6e, 0x82, 0x4b, 0x10, 0x89, - 0x91, 0x6d, 0xbc, 0x45, 0x47, 0xd2, 0x25, 0x13, 0x4b, 0xac, - 0x26, 0xed, 0xd5, 0xb3, 0xf9, 0xed, 0xc4, 0xaa, 0xbd, 0x5d, - 0x7f, 0xe9, 0x2f, 0x7b, 0x7d, 0x65, 0xb3, 0xfe, 0xe2, 0x7e, - 0xea, 0xb9, 0x05, 0xf6, 0xf6, 0xa9, 0xd9, 0xf9, 0x9c, 0xb2, - 0xd2, 0x63, 0xcc, 0x9a, 0x22, 0x33, 0xfd, 0x6c, 0x98, 0x32, - 0xf9, 0xa1, 0x27, 0x7b, 0x25, 0xc1, 0xdf, 0xcb, 0xe1, 0xb8, - 0x6b, 0x0d, 0xd5, 0xd0, 0x04, 0x1a, 0xff, 0x8d, 0xb1, 0x90, - 0xd6, 0xf9, 0x44, 0x24, 0x74, 0xc0, 0xc3, 0x13, 0x15, 0x1f, - 0x90, 0xca, 0x98, 0x5a, 0x38, 0x0e, 0x6b, 0xc8, 0x94, 0x33, - 0xe0, 0x47, 0x41, 0x48, 0x2e, 0xe7, 0x89, 0x34, 0x13, 0x2e, - 0x93, 0x51, 0x01, 0x83, 0x94, 0xa0, 0xf7, 0xf7, 0xa5, 0xe1, - 0x50, 0x9c, 0x7d, 0xb2, 0xe2, 0x19, 0xb4, 0xf8, 0x05, 0xd7, - 0xb7, 0x5c, 0x79, 0x36, 0xbf, 0x9e, 0xe8, 0x90, 0x1f, 0xf5, - 0xf0, 0xb9, 0x7f, 0x11, 0xd1, 0x2a, 0xa4, 0xa8, 0xac, 0x09, - 0x0d, 0xfd, 0x08, 0x6c, 0x07, 0x47, 0x98, 0x30, 0x53, 0x14, - 0xfd, 0x59, 0x11, 0xf2, 0x97, 0xc4, 0x7d, 0x4a, 0x89, 0xde, - 0xba, 0xf8, 0x51, 0xe9, 0x96, 0x99, 0x15, 0x2e, 0x92, 0x99, - 0xae, 0xc2, 0xde, 0x30, 0x6e, 0xe2, 0xf9, 0x29, 0xd0, 0xb3, - 0x4a, 0xec, 0xd3, 0xd0, 0xf9, 0x07, 0xd8, 0xf1, 0x36, 0x4c, - 0x07, 0x7c, 0xc3, 0x76, 0xf4, 0xc8, 0xab, 0x44, 0x5f, 0x48, - 0x4a, 0xb6, 0xe2, 0x9b, 0x2a, 0x56, 0x40, 0xc6, 0x40, 0x48, - 0xa1, 0xb6, 0x31, 0x92, 0x77, 0x3f, 0x7e, 0x2c, 0x24, 0x41, - 0x4c, 0xdb, 0xa1, 0xc0, 0x6c, 0x35, 0x12, 0xc4, 0x93, 0xb1, - 0x2a, 0x86, 0x49, 0xde, 0x4d, 0xb8, 0x6b, 0x61, 0x4c, 0x8d, - 0x2a, 0x77, 0x34, 0xbd, 0xfe, 0x60, 0x60, 0x75, 0x27, 0xe3, - 0x81, 0xea, 0xe2, 0xd2, 0x73, 0x3d, 0x0f, 0x6a, 0x58, 0x34, - 0x4d, 0xaa, 0xbe, 0x5a, 0x3f, 0x1e, 0xcd, 0xc7, 0x28, 0x9a, - 0x8d, 0x93, 0x3c, 0xe4, 0x77, 0x72, 0x5b, 0x3f, 0x0e, 0x50, - 0x34, 0x5b, 0x65, 0xb2, 0xe8, 0x08, 0xa3, 0x08, 0xf6, 0x81, - 0x5b, 0xc1, 0x51, 0x00, 0x6e, 0x44, 0xa3, 0xd9, 0x64, 0x8c, - 0xd0, 0x64, 0x95, 0xd0, 0x12, 0x1c, 0x05, 0xbb, 0x09, 0xd0, - 0xee, 0x5e, 0x0d, 0x8e, 0x66, 0x30, 0xee, 0xa4, 0x42, 0xd3, - 0x90, 0xdf, 0x22, 0xba, 0x15, 0xad, 0x94, 0xef, 0xe7, 0x7a, - 0x3c, 0xb4, 0xa6, 0x56, 0x4f, 0x09, 0x23, 0xb9, 0x0e, 0x24, - 0xe8, 0xe2, 0x3a, 0xbe, 0x83, 0x0f, 0x77, 0xcb, 0x10, 0x08, - 0x8e, 0x83, 0x0e, 0xf2, 0x14, 0x0b, 0x7c, 0x50, 0x2f, 0x95, - 0x04, 0x22, 0xf7, 0x10, 0x42, 0x5d, 0x88, 0x5b, 0xfc, 0xe0, - 0x8f, 0xc6, 0x24, 0xef, 0x04, 0x77, 0x84, 0x4b, 0xf8, 0x77, - 0x23, 0x82, 0xf7, 0x6c, 0xd1, 0xa7, 0x64, 0x11, 0x4d, 0x5b, - 0x2b, 0xad, 0xc9, 0xf6, 0x04, 0x91, 0x90, 0x14, 0xf7, 0x94, - 0x1f, 0x64, 0xf9, 0x8b, 0x52, 0x19, 0xf4, 0xe7, 0xdd, 0x3d, - 0xcb, 0x50, 0x91, 0x57, 0x5b, 0xeb, 0x09, 0xf0, 0xc1, 0xe1, - 0x20, 0xef, 0x9d, 0x85, 0x41, 0xdf, 0x94, 0x8e, 0x8e, 0x28, - 0x4f, 0xf1, 0x37, 0x8a, 0x5e, 0x6b, 0x35, 0x70, 0x3f, 0x19, - 0x8c, 0xaf, 0x96, 0xd6, 0x68, 0x3e, 0x55, 0xe5, 0xdf, 0x20, - 0x78, 0x30, 0x2e, 0x83, 0xe0, 0x3b, 0x4a, 0xf4, 0x14, 0xee, - 0x90, 0x87, 0x7e, 0x51, 0x84, 0x2b, 0xb2, 0x28, 0x2d, 0xcd, - 0x6e, 0x37, 0x15, 0x4e, 0x8b, 0xad, 0x6f, 0x3a, 0x1f, 0x4f, - 0xad, 0xe1, 0xf8, 0x26, 0x15, 0x58, 0x8b, 0x3f, 0x47, 0x0a, - 0xe2, 0x53, 0x29, 0x81, 0xce, 0xb5, 0x39, 0xba, 0x62, 0x04, - 0x64, 0x13, 0x22, 0x0d, 0x64, 0x28, 0x70, 0x73, 0x31, 0x27, - 0xcb, 0x9e, 0x65, 0xce, 0xa1, 0xe0, 0x16, 0x7b, 0x71, 0x22, - 0x6e, 0xa8, 0x74, 0x6d, 0x19, 0x76, 0x71, 0x67, 0x44, 0x52, - 0x52, 0x9f, 0x4e, 0xb3, 0x88, 0x85, 0x65, 0x5d, 0x13, 0xc9, - 0x49, 0x3d, 0x3c, 0xcb, 0x22, 0xb7, 0x2a, 0xeb, 0xe8, 0xdc, - 0x1a, 0x58, 0xe3, 0x89, 0x45, 0x12, 0xab, 0x2d, 0x25, 0x58, - 0xb1, 0x24, 0xa4, 0x65, 0xfe, 0x08, 0xd8, 0x71, 0x0f, 0x1e, - 0x16, 0xa1, 0xf2, 0x6f, 0xc4, 0xc0, 0x03, 0x01, 0x71, 0xb0, - 0xc0, 0xf0, 0x7d, 0xc0, 0x60, 0x06, 0x58, 0xcd, 0x8a, 0xac, - 0x51, 0x32, 0xa6, 0x17, 0x19, 0xd5, 0x44, 0x04, 0x19, 0x4c, - 0xa3, 0x1e, 0x31, 0x61, 0x77, 0x4d, 0x45, 0x26, 0x6f, 0xe1, - 0x0b, 0xb1, 0x77, 0x0e, 0x81, 0x99, 0xb0, 0x3d, 0x49, 0x61, - 0x2d, 0x0a, 0xcb, 0x2f, 0xc0, 0xca, 0x87, 0xfb, 0xf4, 0x77, - 0x6a, 0xda, 0x3e, 0x3d, 0x49, 0x25, 0x1a, 0xa6, 0x6f, 0xb5, - 0x0c, 0xdb, 0x1e, 0xf2, 0x37, 0x92, 0xc2, 0x5c, 0xd0, 0x83, - 0x06, 0xae, 0x09, 0x1e, 0xa9, 0x5c, 0xde, 0x2c, 0x4c, 0xdf, - 0x87, 0x7a, 0x0a, 0x47, 0x44, 0x22, 0x71, 0xea, 0xac, 0xa1, - 0xad, 0xec, 0x18, 0xf3, 0x10, 0xbc, 0x8c, 0xef, 0x22, 0x10, - 0x3e, 0x51, 0x97, 0x1d, 0xea, 0xc8, 0xe1, 0x00, 0x28, 0xd1, - 0x56, 0x24, 0xa5, 0x34, 0x19, 0x2f, 0x7e, 0x66, 0x9e, 0x5a, - 0x5f, 0x0d, 0xe9, 0x1b, 0x6d, 0xa3, 0x17, 0xb2, 0x97, 0x20, - 0x3b, 0xaf, 0x08, 0x49, 0x48, 0x7e, 0x6b, 0xb2, 0x06, 0x6c, - 0x14, 0xce, 0x3d, 0xc4, 0xc3, 0xad, 0xf8, 0x03, 0x5d, 0xee, - 0x8a, 0xe3, 0xd0, 0xbd, 0xdb, 0xc6, 0xdc, 0xec, 0x69, 0x0a, - 0x4f, 0x6a, 0x1d, 0x88, 0x32, 0x47, 0x35, 0x71, 0xfb, 0xca, - 0x1d, 0xd1, 0x43, 0x69, 0x44, 0x53, 0x99, 0x4a, 0xcb, 0x7d, - 0xcc, 0x4a, 0x70, 0x48, 0x1a, 0x38, 0xb0, 0x14, 0xe6, 0xed, - 0x30, 0x50, 0x7b, 0xeb, 0x25, 0xf0, 0x2b, 0xfe, 0x12, 0x5d, - 0x88, 0x2c, 0xaf, 0xc6, 0x29, 0xef, 0xbe, 0x49, 0x10, 0xc5, - 0xc6, 0x55, 0x20, 0x78, 0xf8, 0x65, 0xf8, 0xc2, 0x74, 0xcc, - 0xc1, 0x40, 0xf8, 0x58, 0x88, 0x33, 0x5a, 0xa1, 0x40, 0xd3, - 0xb2, 0xcf, 0x09, 0xc0, 0x21, 0xbf, 0x8e, 0x49, 0xc1, 0x1b, - 0xae, 0xb6, 0x61, 0x88, 0xf6, 0xfb, 0x4d, 0xe1, 0x9d, 0x0e, - 0x45, 0x33, 0xcc, 0x80, 0x2f, 0xa1, 0x30, 0x86, 0x99, 0x64, - 0x0a, 0x65, 0xe9, 0x03, 0x6c, 0xb9, 0x70, 0x89, 0x86, 0x3a, - 0x62, 0xd4, 0xb5, 0xb4, 0x60, 0x5a, 0x2f, 0x6b, 0x4f, 0x22, - 0xf6, 0x75, 0x38, 0x68, 0x23, 0x4c, 0x03, 0x8b, 0x92, 0x8d, - 0xe4, 0x4a, 0x79, 0xca, 0x61, 0x4f, 0x88, 0xd4, 0xd8, 0x54, - 0xf7, 0xa4, 0x7c, 0x2b, 0xc7, 0x42, 0xcc, 0x6c, 0xf3, 0xf1, - 0x67, 0x4b, 0xbd, 0xbb, 0xc3, 0xdc, 0x36, 0x0f, 0xbe, 0x03, - 0xff, 0x9d, 0x53, 0x7f, 0x10, 0xa7, 0x66, 0xee, 0x15, 0x64, - 0x06, 0xe4, 0x1d, 0x11, 0xf1, 0x18, 0x9d, 0x1a, 0xca, 0x56, - 0xe4, 0x47, 0x69, 0xd8, 0x92, 0x06, 0xef, 0x26, 0xdb, 0x00, - 0xe3, 0xdd, 0x53, 0x89, 0x77, 0x85, 0xd7, 0xd9, 0xbc, 0x5b, - 0xe6, 0x1b, 0x9f, 0x10, 0xd0, 0x55, 0x13, 0xf2, 0x76, 0x2f, - 0xc9, 0xa8, 0xc3, 0xa9, 0xc6, 0xf2, 0x65, 0x78, 0x13, 0xb3, - 0x0e, 0x72, 0x84, 0x57, 0x56, 0x05, 0xf5, 0x82, 0x37, 0xba, - 0xc1, 0x1a, 0x36, 0xb8, 0xe8, 0x3a, 0x7c, 0x9e, 0x0a, 0x2c, - 0x8a, 0xc1, 0x03, 0x4e, 0x57, 0x5e, 0xfc, 0x65, 0x6f, 0x30, - 0x36, 0xd5, 0x80, 0xc5, 0x9e, 0x17, 0xd8, 0x71, 0xe9, 0x97, - 0xb3, 0xf9, 0x34, 0x09, 0x41, 0x12, 0x92, 0xa8, 0xe2, 0x2b, - 0xf8, 0xb2, 0x6f, 0xad, 0xd1, 0x62, 0xa8, 0xf0, 0x3f, 0x1f, - 0x1f, 0xf5, 0xeb, 0xc2, 0xa9, 0x59, 0xbb, 0xbe, 0x92, 0xb8, - 0xaf, 0xe6, 0x1c, 0xaf, 0xed, 0x17, 0x25, 0xa7, 0x5e, 0x5b, - 0xe2, 0x99, 0xae, 0x16, 0xc2, 0xde, 0x67, 0x12, 0x7b, 0xd3, - 0x57, 0x7f, 0x5a, 0x55, 0x2e, 0x2d, 0x27, 0x84, 0x05, 0x9b, - 0xa7, 0xe7, 0x49, 0xca, 0xb3, 0xb6, 0x66, 0x47, 0x5c, 0x33, - 0xc8, 0x20, 0x9e, 0x4b, 0x83, 0x48, 0xde, 0x68, 0x8f, 0x61, - 0x08, 0xec, 0x55, 0xcc, 0xd3, 0x94, 0x4e, 0xc9, 0x4f, 0xc3, - 0xaf, 0x12, 0x44, 0x83, 0xc5, 0x64, 0xa4, 0x27, 0x27, 0x1b, - 0xf4, 0x5b, 0xb4, 0x9c, 0xf0, 0x38, 0x4b, 0xc5, 0x6a, 0x52, - 0xce, 0x34, 0xc1, 0x06, 0xf9, 0x86, 0xb3, 0x26, 0xe1, 0x1f, - 0xf5, 0x71, 0x2c, 0xa9, 0x52, 0xaa, 0x77, 0x91, 0x51, 0xeb, - 0xee, 0x1f, 0x59, 0x00, 0x51, 0x14, 0x1f, 0x70, 0xfa, 0x6b, - 0x7c, 0xde, 0xc4, 0xc7, 0xfd, 0xfd, 0x43, 0x31, 0xde, 0x95, - 0xbc, 0x37, 0x68, 0x01, 0x11, 0x24, 0xc0, 0x28, 0x3c, 0x42, - 0xde, 0x23, 0xe7, 0x7c, 0xbe, 0x59, 0xf6, 0xd0, 0x4f, 0x61, - 0xb7, 0x4c, 0x64, 0xf6, 0x5e, 0xa5, 0x11, 0x60, 0x40, 0x08, - 0x5a, 0x93, 0x8a, 0xdb, 0x3c, 0x7f, 0x99, 0x81, 0x18, 0x9d, - 0xf2, 0x23, 0xd6, 0xbd, 0x23, 0x9e, 0x70, 0x0a, 0x95, 0xc6, - 0x66, 0xe9, 0xb5, 0x1b, 0xe1, 0xcc, 0x5f, 0xbc, 0x6c, 0x85, - 0x9e, 0x6e, 0x22, 0xa9, 0x97, 0x91, 0x31, 0x41, 0xa1, 0x00, - 0x00, 0x81, 0x48, 0x6a, 0x76, 0xf7, 0x8f, 0xad, 0xed, 0xb9, - 0xf1, 0x8e, 0x03, 0x08, 0xd2, 0x9f, 0x5a, 0x1f, 0x87, 0x80, - 0x37, 0x00, 0xea, 0x36, 0x20, 0x96, 0x91, 0x2b, 0x4b, 0xbe, - 0x8e, 0x45, 0x74, 0x8f, 0xb9, 0x1d, 0x3e, 0x80, 0x38, 0x85, - 0xef, 0xc1, 0x3f, 0xd7, 0xf1, 0x27, 0xc1, 0x97, 0xb0, 0xdc, - 0x9b, 0xe4, 0xec, 0x64, 0x5f, 0xbd, 0x7f, 0xad, 0x10, 0x25, - 0xd1, 0x92, 0x13, 0x3f, 0x71, 0x6e, 0x6f, 0xe6, 0x42, 0xdc, - 0x8e, 0x0b, 0x7f, 0x1b, 0x2d, 0xc9, 0xf7, 0x69, 0x51, 0x54, - 0x21, 0x3d, 0xa7, 0x16, 0x9a, 0x45, 0x97, 0xea, 0x15, 0xc5, - 0x59, 0x73, 0xb5, 0x3d, 0xbf, 0x35, 0x6f, 0x74, 0x6b, 0xc9, - 0x2d, 0xc2, 0xa6, 0xd4, 0x98, 0xc8, 0x9d, 0x95, 0xe8, 0xe3, - 0x1c, 0x3e, 0xba, 0xe3, 0xfe, 0x54, 0x03, 0xf2, 0xa3, 0xf6, - 0xe5, 0x7b, 0xfb, 0xfc, 0xf8, 0xf3, 0x42, 0x4a, 0xda, 0x68, - 0x49, 0xe2, 0xc9, 0xfb, 0x2d, 0x9d, 0x02, 0xb4, 0x56, 0x98, - 0xc6, 0x12, 0x95, 0x86, 0x12, 0x0c, 0x40, 0x55, 0x95, 0xa4, - 0x37, 0xfd, 0xb6, 0x20, 0x4f, 0x58, 0x3d, 0xf4, 0x67, 0xd9, - 0x01, 0x80, 0xa4, 0x72, 0x44, 0x36, 0x1e, 0x3d, 0x4c, 0x60, - 0x21, 0x35, 0xcf, 0x36, 0x8c, 0x80, 0x31, 0x46, 0xf1, 0x07, - 0x34, 0x93, 0x67, 0xa3, 0x25, 0x1b, 0x71, 0xd2, 0x78, 0x85, - 0x95, 0x53, 0xae, 0xe7, 0xe7, 0x8c, 0x13, 0xcf, 0xef, 0x92, - 0xd0, 0x38, 0xb6, 0x46, 0x0e, 0xa4, 0xc4, 0xf4, 0xe2, 0x7b, - 0x6d, 0xd8, 0x9f, 0xf2, 0x38, 0x68, 0x3d, 0xd8, 0xfa, 0xf2, - 0xa0, 0xe8, 0xc6, 0xbd, 0x8e, 0x58, 0xb7, 0x0f, 0x73, 0xba, - 0x1d, 0xd5, 0xec, 0x37, 0x21, 0xd3, 0xc0, 0x0e, 0xce, 0x22, - 0x18, 0x65, 0x75, 0x36, 0x35, 0x29, 0x79, 0x01, 0x8e, 0x0d, - 0xad, 0xe1, 0x18, 0x98, 0x38, 0x6f, 0xac, 0x8e, 0x24, 0xf8, - 0xe2, 0x1f, 0x31, 0x60, 0x79, 0x71, 0xf3, 0x6e, 0xe4, 0xde, - 0xb9, 0xa2, 0x3e, 0x74, 0x23, 0x3c, 0xd1, 0x24, 0x82, 0xd3, - 0x14, 0x4b, 0x29, 0x8a, 0xf3, 0x3e, 0x2d, 0x19, 0x33, 0xa8, - 0x11, 0xe6, 0x8d, 0xd8, 0xb1, 0x10, 0xc6, 0xf8, 0x13, 0xc7, - 0xab, 0x4d, 0x9e, 0xd2, 0x1b, 0x12, 0xfb, 0x09, 0xe4, 0x8d, - 0x09, 0x77, 0xd1, 0xc8, 0x2c, 0xf4, 0x56, 0x83, 0x52, 0x76, - 0x37, 0x0e, 0x8f, 0xa2, 0xc8, 0x33, 0x30, 0xe2, 0x59, 0x83, - 0xcf, 0x85, 0x0b, 0x72, 0xfc, 0xd6, 0x48, 0x5e, 0xeb, 0x23, - 0xa1, 0xb1, 0x94, 0x53, 0x8c, 0x0d, 0xc8, 0x21, 0x22, 0xc9, - 0x44, 0xd5, 0x38, 0x09, 0x76, 0xc7, 0x0b, 0x22, 0xb5, 0xd9, - 0x3c, 0x13, 0x3a, 0x7a, 0x59, 0xa3, 0xd5, 0x11, 0xfa, 0xc2, - 0x51, 0x1b, 0x9d, 0xbe, 0xc8, 0xe4, 0x69, 0xc2, 0xf5, 0xd6, - 0x09, 0xa6, 0x33, 0xdb, 0xde, 0x09, 0x99, 0x52, 0x48, 0x8b, - 0xcf, 0xd5, 0xba, 0xe4, 0x42, 0x6f, 0xdd, 0xf0, 0x8c, 0x3c, - 0xe0, 0xb8, 0xe9, 0x91, 0x02, 0x32, 0x11, 0x19, 0x71, 0x60, - 0x44, 0xa4, 0x69, 0x77, 0xad, 0x6c, 0x4b, 0xb4, 0x89, 0x9f, - 0x01, 0xd8, 0x98, 0x1e, 0x86, 0xe0, 0x26, 0x03, 0x72, 0xa1, - 0xf6, 0x01, 0x95, 0xf8, 0x44, 0x8b, 0xfc, 0x22, 0xf3, 0x08, - 0xcf, 0x68, 0xdb, 0x28, 0x27, 0xf0, 0xfd, 0xfc, 0x60, 0x3f, - 0x35, 0xa5, 0xb4, 0xfc, 0x0f, 0x9f, 0xcc, 0x88, 0x56, 0xcc, - 0x31, 0xad, 0xb6, 0x91, 0xe8, 0x87, 0x6d, 0xce, 0x17, 0xf5, - 0x71, 0xad, 0x2c, 0xf8, 0xfd, 0xe5, 0xa0, 0x3f, 0xbb, 0x4e, - 0x81, 0xbe, 0x5b, 0xb0, 0xde, 0x3b, 0x28, 0x32, 0x1f, 0x8b, - 0x7c, 0x20, 0x3a, 0x83, 0xf1, 0x2c, 0xe5, 0xa7, 0x82, 0x97, - 0xad, 0x53, 0x07, 0xcc, 0x63, 0x1b, 0x3d, 0xe6, 0x88, 0x5d, - 0x9e, 0x91, 0x16, 0x15, 0x32, 0xa8, 0xc0, 0xfc, 0x05, 0x04, - 0xef, 0x24, 0xd8, 0xe4, 0x35, 0x59, 0xb8, 0x54, 0xda, 0xfc, - 0x42, 0x2d, 0xee, 0x07, 0x82, 0x2d, 0xf0, 0x9c, 0xa7, 0x01, - 0xec, 0xef, 0x8d, 0x33, 0xbc, 0xa8, 0xea, 0x22, 0x65, 0xf6, - 0xc7, 0x37, 0xcb, 0x46, 0x57, 0x18, 0x02, 0x1a, 0xcd, 0x81, - 0x84, 0x46, 0x63, 0x98, 0x4f, 0xb6, 0xeb, 0x15, 0x27, 0xc6, - 0xc0, 0x1f, 0x2f, 0x05, 0xd0, 0x90, 0x43, 0x99, 0x04, 0x81, - 0x0e, 0xd1, 0x89, 0xce, 0x03, 0xa4, 0xa4, 0x80, 0x38, 0x62, - 0x24, 0x90, 0x3d, 0xcd, 0xe5, 0xe7, 0xc2, 0x5e, 0xcf, 0x5f, - 0xb0, 0x4d, 0x8d, 0x4d, 0x07, 0x0f, 0x16, 0x10, 0x5e, 0x55, - 0x90, 0x39, 0x7f, 0x70, 0x81, 0xf3, 0xc7, 0x16, 0x1d, 0x53, - 0x15, 0x93, 0x24, 0x41, 0x4d, 0xdc, 0x6b, 0x2b, 0xf9, 0x5a, - 0x0e, 0xa5, 0x22, 0x18, 0xc7, 0xc5, 0xbc, 0x57, 0x3b, 0x33, - 0xdf, 0xe7, 0xac, 0xa4, 0x7c, 0x28, 0xa8, 0xc2, 0x03, 0xce, - 0x03, 0x20, 0x08, 0x88, 0x7b, 0xf9, 0x10, 0xf7, 0xe6, 0x6d, - 0x02, 0xe1, 0x27, 0xc4, 0x1b, 0x76, 0x81, 0x67, 0xef, 0x80, - 0x5e, 0x1a, 0xd4, 0x56, 0xcc, 0xb6, 0x70, 0x6a, 0xa7, 0xf2, - 0xac, 0x9f, 0x08, 0xb3, 0x3e, 0xad, 0x3e, 0xeb, 0x70, 0xde, - 0xa2, 0x70, 0xa5, 0xc4, 0xeb, 0x54, 0x9c, 0xb2, 0x1f, 0x34, - 0xf9, 0xd3, 0xba, 0x93, 0x3f, 0x99, 0x8e, 0x87, 0xfd, 0x59, - 0x67, 0x31, 0x5e, 0xcc, 0xd2, 0x4c, 0x30, 0x09, 0x83, 0xb5, - 0x1b, 0xad, 0xb6, 0xc1, 0x36, 0xfa, 0x93, 0x30, 0xc0, 0xfc, - 0x85, 0xed, 0xe4, 0x84, 0x03, 0x4e, 0xa5, 0x75, 0x5f, 0x43, - 0xd9, 0x68, 0xb2, 0xf0, 0xb3, 0x6c, 0x16, 0x7c, 0xb9, 0xd6, - 0xd7, 0x2e, 0xba, 0x69, 0x4c, 0x3e, 0xe9, 0x32, 0x82, 0xc0, - 0x8d, 0xc6, 0x45, 0x1a, 0x06, 0x02, 0xd4, 0x4b, 0xe9, 0x26, - 0x12, 0x91, 0x1e, 0x4e, 0x87, 0x50, 0xa0, 0xa3, 0x98, 0xa3, - 0x8e, 0x95, 0x4e, 0x4e, 0x23, 0x37, 0x04, 0x45, 0xcd, 0x16, - 0x52, 0xb9, 0x5c, 0xcc, 0x6e, 0x55, 0xe8, 0x36, 0x14, 0x05, - 0x86, 0xfc, 0x3a, 0xef, 0xb6, 0xd1, 0xae, 0x68, 0x2f, 0xba, - 0x41, 0x8e, 0xb0, 0x6a, 0xb0, 0x40, 0xdf, 0x87, 0xc5, 0x5c, - 0x07, 0xf9, 0xc0, 0x86, 0x85, 0x08, 0xce, 0xfd, 0x89, 0x72, - 0xbd, 0x5d, 0x15, 0x6f, 0xb9, 0xca, 0x16, 0xa6, 0x2f, 0xbf, - 0xa6, 0xc8, 0x3d, 0x96, 0x71, 0xef, 0x99, 0x24, 0xbf, 0xe8, - 0xab, 0x1f, 0xb7, 0x6b, 0xc9, 0xe1, 0x8f, 0x2d, 0xe0, 0x17, - 0x32, 0x43, 0xa5, 0xce, 0x68, 0xf4, 0x82, 0x70, 0xdd, 0x89, - 0x43, 0x0f, 0xab, 0x76, 0x74, 0x40, 0x0e, 0x13, 0x7e, 0xef, - 0x31, 0x28, 0xfb, 0x04, 0xce, 0xb6, 0x96, 0x0a, 0x48, 0x42, - 0xaf, 0xe5, 0x40, 0xec, 0xb6, 0x90, 0xae, 0xde, 0x1e, 0xe5, - 0xaa, 0x3e, 0xc4, 0xd5, 0x20, 0xf0, 0xaf, 0x6c, 0x37, 0x15, - 0x8c, 0xe0, 0x22, 0x87, 0x62, 0xf2, 0x42, 0x9a, 0x30, 0x1d, - 0x0b, 0xe5, 0xc0, 0x8e, 0x25, 0x92, 0x70, 0x74, 0xc2, 0xfa, - 0xd4, 0x2e, 0x03, 0xdf, 0x99, 0xc3, 0x89, 0xfb, 0xce, 0xfd, - 0x6c, 0xb6, 0xbe, 0x83, 0xd0, 0x93, 0x07, 0x70, 0x4f, 0x09, - 0x0d, 0xfc, 0xce, 0x57, 0x00, 0xf9, 0xf5, 0xdb, 0x0a, 0x6c, - 0x47, 0x6a, 0x2c, 0x01, 0x3a, 0xab, 0xd9, 0xd6, 0x2e, 0xba, - 0xb1, 0xbd, 0xf7, 0x44, 0x82, 0xf4, 0x91, 0x4b, 0xe0, 0xd4, - 0xf4, 0xe8, 0x6a, 0xac, 0x07, 0xcc, 0xf1, 0xd6, 0x93, 0xed, - 0xb1, 0xf5, 0x70, 0x90, 0x5e, 0x0f, 0xe8, 0xf5, 0x96, 0xfc, - 0xd9, 0xe5, 0xd0, 0xff, 0x69, 0xd9, 0xb5, 0x5c, 0x03, 0x9e, - 0x23, 0x71, 0x88, 0x5c, 0x98, 0x36, 0x01, 0xcd, 0x35, 0x48, - 0x25, 0x5b, 0xe5, 0x81, 0x40, 0xc0, 0x09, 0xcb, 0xb5, 0xeb, - 0x2f, 0xed, 0x3b, 0xee, 0x44, 0x7c, 0x17, 0x05, 0x1e, 0x72, - 0xc3, 0x5a, 0x13, 0xdf, 0x1f, 0x83, 0xa1, 0x2b, 0x34, 0xa1, - 0x9f, 0x6a, 0x7a, 0x75, 0xe2, 0xba, 0xa3, 0x4d, 0xc5, 0xcb, - 0x84, 0xda, 0x4a, 0xc9, 0xb0, 0x1f, 0xbe, 0x8b, 0xa1, 0x56, - 0xc4, 0x90, 0x17, 0xf8, 0xcb, 0x87, 0x96, 0xe5, 0x90, 0x67, - 0xc7, 0x32, 0xcd, 0x66, 0x82, 0xe8, 0x0e, 0x0a, 0xa2, 0x65, - 0x5c, 0x45, 0x12, 0x55, 0x69, 0x2b, 0x94, 0x3b, 0x72, 0x63, - 0x1b, 0x09, 0x22, 0x87, 0x48, 0x1d, 0x89, 0x62, 0x1d, 0x49, - 0x94, 0x89, 0x90, 0xeb, 0x2d, 0xa3, 0x67, 0x84, 0x34, 0x21, - 0x51, 0x47, 0x60, 0xb9, 0x1e, 0xf5, 0x3e, 0x36, 0x66, 0xf8, - 0x7d, 0xdd, 0x3a, 0x22, 0xfb, 0x1e, 0x2c, 0x1d, 0x97, 0x1f, - 0x95, 0x66, 0xf0, 0x41, 0xbc, 0x33, 0xba, 0x0d, 0xe4, 0x45, - 0xd2, 0xf7, 0x65, 0x80, 0x71, 0xfb, 0xb2, 0x07, 0x65, 0x4c, - 0xdf, 0xd5, 0x1d, 0x16, 0xd4, 0xf0, 0xb5, 0x1d, 0x3e, 0xe4, - 0x0d, 0x0b, 0xe9, 0xc7, 0x90, 0x96, 0xa8, 0x59, 0x8b, 0xe7, - 0xae, 0x97, 0xaa, 0xfb, 0xa3, 0x21, 0xad, 0x17, 0xb1, 0xd2, - 0x76, 0x77, 0x9b, 0xad, 0xe0, 0xba, 0x7e, 0x7e, 0x78, 0x54, - 0x73, 0xcf, 0xc9, 0x37, 0x6a, 0xf5, 0x7e, 0x78, 0xfa, 0x17, - 0x11, 0x22, 0xf4, 0xa0, 0x86, 0xe0, 0x7a, 0x2b, 0xe7, 0xfb, - 0xdc, 0x5c, 0x2b, 0x4d, 0xd3, 0xac, 0xd4, 0xc9, 0xa5, 0x70, - 0x58, 0x2f, 0x97, 0x42, 0xed, 0xdc, 0x07, 0xc5, 0xa8, 0xef, - 0xc7, 0xd5, 0x51, 0xdf, 0xf5, 0xd4, 0x9e, 0x09, 0x53, 0x7b, - 0xac, 0xb7, 0x50, 0x7b, 0xa8, 0xcb, 0x73, 0x23, 0x31, 0x96, - 0xab, 0xf6, 0xb4, 0x40, 0x1c, 0x01, 0x13, 0x2d, 0x11, 0x4f, - 0xa6, 0xa9, 0x23, 0x9c, 0x22, 0x63, 0x2a, 0x38, 0x1e, 0x57, - 0x20, 0x2b, 0x22, 0x00, 0x09, 0xd2, 0x41, 0x4e, 0xd2, 0xa5, - 0x4d, 0x4d, 0x51, 0xc2, 0xe4, 0x0b, 0xeb, 0x3c, 0x55, 0x4d, - 0x47, 0x43, 0x6b, 0x1a, 0x1f, 0x41, 0x0f, 0xfc, 0x13, 0x9c, - 0x1b, 0x1a, 0x8b, 0xc7, 0xb3, 0x33, 0xe5, 0x76, 0xd0, 0xe8, - 0x85, 0xf6, 0x03, 0x36, 0xa1, 0x66, 0x76, 0x6d, 0xcb, 0xef, - 0xb2, 0x24, 0xd3, 0xc9, 0xc2, 0x77, 0xa1, 0x0c, 0xd3, 0x77, - 0x7c, 0xbd, 0x87, 0xb5, 0x2c, 0x7d, 0x0a, 0xae, 0x9f, 0x38, - 0x95, 0xe2, 0x8a, 0x0d, 0x86, 0xb9, 0xaf, 0x45, 0x08, 0xd2, - 0x58, 0x22, 0x62, 0x3c, 0x09, 0x79, 0x10, 0xa3, 0x10, 0x4e, - 0x4c, 0x03, 0x01, 0x58, 0xdc, 0x53, 0xb2, 0x51, 0x0d, 0x97, - 0xdc, 0xa4, 0x49, 0xb5, 0x6d, 0x7c, 0x23, 0xb0, 0x89, 0xb7, - 0xd1, 0xa5, 0x17, 0xdc, 0xd1, 0x01, 0x3f, 0x4f, 0x6e, 0x89, - 0xc9, 0x2b, 0x03, 0xbf, 0xcb, 0x4b, 0xdd, 0x1e, 0xc3, 0xca, - 0xa5, 0x38, 0x91, 0x0e, 0x79, 0x26, 0x66, 0xf9, 0xd0, 0x48, - 0x3a, 0x8c, 0xbf, 0x51, 0x48, 0xd4, 0xea, 0x8e, 0x79, 0x87, - 0x61, 0xd2, 0x58, 0x5f, 0x2e, 0xb8, 0xfc, 0x20, 0xcf, 0x99, - 0x4c, 0x2b, 0x36, 0x1c, 0x45, 0x77, 0x9e, 0xe9, 0x3f, 0x78, - 0x80, 0x1d, 0x50, 0x38, 0x3c, 0xef, 0x62, 0x76, 0x39, 0x30, - 0xe8, 0xbb, 0xec, 0x85, 0x4a, 0x5d, 0x22, 0x25, 0x4f, 0xc8, - 0x3a, 0xe9, 0x4e, 0xee, 0x80, 0x1d, 0x0a, 0x90, 0x3c, 0x97, - 0xec, 0x67, 0x13, 0xe7, 0x37, 0xa8, 0xcf, 0x3c, 0x49, 0xd9, - 0x13, 0x2d, 0xfe, 0xa0, 0xb6, 0x63, 0x68, 0xe6, 0xf0, 0xb1, - 0x4d, 0x80, 0x0d, 0xe0, 0x81, 0x34, 0x80, 0xc9, 0xdb, 0xb7, - 0x1d, 0xc2, 0x44, 0xbf, 0xfb, 0xda, 0x0a, 0xf6, 0xf5, 0x6d, - 0x2b, 0x88, 0xd7, 0xdf, 0x2a, 0x50, 0xd1, 0x18, 0xe8, 0x9e, - 0xfb, 0xc2, 0xc6, 0xf8, 0x50, 0x1a, 0x63, 0xf4, 0xe2, 0x6d, - 0x87, 0xf7, 0x1d, 0xd7, 0xfd, 0x17, 0x73, 0x9b, 0x6d, 0xe8, - 0xfe, 0x5b, 0xe6, 0x42, 0x90, 0xec, 0xf3, 0x5f, 0xd7, 0xcc, - 0x60, 0xc6, 0xc7, 0x90, 0xbf, 0xc5, 0x71, 0xbe, 0xf9, 0x68, - 0x06, 0x32, 0x94, 0x41, 0x4d, 0xf7, 0x4d, 0x74, 0xdc, 0x74, - 0x05, 0x1f, 0x61, 0xf4, 0x8b, 0xa2, 0x96, 0x66, 0x6e, 0x85, - 0xd5, 0x7b, 0x7b, 0x05, 0xe2, 0xcc, 0x0e, 0x1f, 0x4b, 0x39, - 0x0e, 0x33, 0x3b, 0x5d, 0xea, 0xc7, 0x88, 0xe3, 0x5d, 0x3a, - 0x41, 0x10, 0x3a, 0xc9, 0x06, 0x73, 0x22, 0xa6, 0x44, 0x27, - 0xf1, 0x30, 0xb8, 0x00, 0xba, 0xdb, 0xcc, 0xdb, 0x6a, 0x56, - 0xf6, 0xba, 0xcf, 0xa3, 0xf2, 0x6d, 0xc4, 0x33, 0x39, 0x7e, - 0x3b, 0xe7, 0xb5, 0x05, 0xa6, 0x9a, 0xc1, 0x70, 0xf3, 0x52, - 0x53, 0x66, 0xea, 0x11, 0x2a, 0x9f, 0x94, 0x8c, 0xb1, 0x93, - 0xf2, 0x90, 0xbf, 0x8f, 0x5d, 0xfe, 0xd8, 0x7d, 0x09, 0x42, - 0xcf, 0x11, 0x87, 0x86, 0x0e, 0xe0, 0x99, 0x38, 0x80, 0xb8, - 0x50, 0xf9, 0x00, 0xc6, 0x08, 0xd1, 0x12, 0x2b, 0x24, 0x5c, - 0xc8, 0x25, 0x19, 0xac, 0x04, 0xd0, 0x4b, 0x41, 0x67, 0xd1, - 0x38, 0xbd, 0xb7, 0x85, 0xb6, 0xa8, 0xbd, 0x63, 0x68, 0x83, - 0x47, 0xbd, 0xeb, 0x1b, 0xa2, 0x5e, 0x6c, 0xbd, 0xc4, 0x08, - 0xc7, 0x87, 0xe9, 0xd9, 0x17, 0xe7, 0x19, 0xfa, 0xb1, 0x91, - 0x14, 0xaa, 0xac, 0x86, 0x54, 0x0c, 0x05, 0x52, 0x54, 0x65, - 0x82, 0x91, 0xd3, 0x8a, 0xc2, 0xec, 0xa5, 0x34, 0x66, 0x42, - 0xbc, 0x9e, 0xde, 0xfc, 0x67, 0xd2, 0xf1, 0x5b, 0x4e, 0xb1, - 0xe2, 0x79, 0x84, 0x2b, 0x7e, 0x5e, 0x62, 0x15, 0x0c, 0xeb, - 0xdc, 0x46, 0x23, 0x9a, 0xe4, 0x53, 0xb9, 0xb5, 0x9f, 0xdb, - 0x68, 0x82, 0xbd, 0x5a, 0x41, 0x6d, 0x67, 0xb5, 0x2b, 0x69, - 0xc7, 0xbe, 0x60, 0x3f, 0xa7, 0xe5, 0xdf, 0xe6, 0x94, 0xa7, - 0x8a, 0x83, 0x8b, 0xcc, 0xd3, 0xde, 0x0f, 0x13, 0x08, 0x7f, - 0x7a, 0x39, 0x9c, 0x36, 0x22, 0x25, 0x36, 0x99, 0x26, 0x54, - 0xb8, 0x05, 0xb1, 0x09, 0x95, 0x44, 0x6d, 0xea, 0xfe, 0xbc, - 0x8c, 0x4d, 0xef, 0xe2, 0xe4, 0x8d, 0xc4, 0x49, 0x05, 0xb1, - 0xd1, 0xc0, 0x62, 0x21, 0xcb, 0x8b, 0x8b, 0xfd, 0x7d, 0xd5, - 0x72, 0xf1, 0xe3, 0x74, 0x87, 0x77, 0x1b, 0xc6, 0x5f, 0xca, - 0x86, 0xf1, 0x93, 0x79, 0x9b, 0x22, 0xee, 0x13, 0xae, 0x96, - 0x6d, 0x9e, 0xc4, 0x0d, 0x53, 0x32, 0x55, 0xd4, 0x8c, 0xad, - 0x20, 0x94, 0x1a, 0x60, 0x40, 0xbe, 0x87, 0xce, 0xff, 0x65, - 0x42, 0xe7, 0x35, 0x78, 0xb2, 0x43, 0x6d, 0x65, 0x84, 0x29, - 0x65, 0x23, 0x71, 0x5d, 0x76, 0x7c, 0xb3, 0xfb, 0x7a, 0x6b, - 0xbe, 0xec, 0xf4, 0xae, 0xd4, 0x1b, 0x7b, 0x10, 0x1b, 0x83, - 0x54, 0x6b, 0x75, 0x6f, 0xbd, 0xaf, 0x44, 0x9a, 0x82, 0x73, - 0x42, 0x1c, 0xba, 0x00, 0xa1, 0x9c, 0xd6, 0x26, 0xdc, 0x59, - 0x4c, 0x39, 0x61, 0xd1, 0x5d, 0xcb, 0xdb, 0xa1, 0x08, 0x46, - 0xdb, 0x80, 0x35, 0x1b, 0x09, 0x78, 0xa6, 0x86, 0x17, 0xc4, - 0x1a, 0x2d, 0xec, 0xd4, 0x7d, 0xac, 0x20, 0x57, 0x84, 0xf5, - 0xdf, 0x56, 0x28, 0x7a, 0xd7, 0x8d, 0xa2, 0xc0, 0x7b, 0x02, - 0xce, 0x38, 0x7c, 0xb0, 0x7d, 0x77, 0x35, 0xb4, 0x63, 0x1c, - 0xa5, 0x9c, 0x19, 0x6f, 0x78, 0xc1, 0x83, 0xd3, 0x93, 0xef, - 0x0c, 0xfa, 0xa1, 0xc1, 0xbe, 0xd4, 0x82, 0x93, 0x29, 0xf7, - 0x69, 0x26, 0x2c, 0x33, 0x99, 0x5c, 0xd6, 0xca, 0xd6, 0x86, - 0x2e, 0x56, 0xd7, 0xc0, 0x8e, 0xb6, 0x21, 0x0d, 0xb7, 0x61, - 0xcc, 0xd9, 0xad, 0x8f, 0x9b, 0xdd, 0x19, 0x0f, 0xc6, 0xd3, - 0x24, 0x30, 0x83, 0x1b, 0x9f, 0xbd, 0x20, 0x2c, 0x0c, 0x0d, - 0x18, 0x2c, 0xe0, 0x67, 0xb3, 0x8e, 0x35, 0x52, 0x1d, 0x64, - 0x7a, 0xde, 0x16, 0x7e, 0x1a, 0xad, 0xc4, 0x78, 0x20, 0xfd, - 0x99, 0x1b, 0x6f, 0x62, 0x94, 0x33, 0xec, 0xd2, 0x5e, 0x7d, - 0x8f, 0x56, 0xc5, 0xb3, 0x76, 0xcc, 0x57, 0x2b, 0xfe, 0xc6, - 0x10, 0x3e, 0x42, 0xe0, 0x75, 0x9d, 0x00, 0xdc, 0xdf, 0xbb, - 0x2b, 0x37, 0x0b, 0x65, 0xab, 0xd9, 0xfc, 0x1d, 0xec, 0xd5, - 0xd9, 0x4a, 0xe7, 0xf6, 0xea, 0x31, 0x78, 0x08, 0xed, 0xcd, - 0x63, 0x6e, 0x97, 0x38, 0xe0, 0xa7, 0x50, 0x56, 0xab, 0xe9, - 0xc8, 0x95, 0x22, 0x8a, 0xed, 0xf5, 0x66, 0xe9, 0xd9, 0x51, - 0xbc, 0x44, 0xf8, 0xc2, 0x2e, 0xc7, 0x3e, 0x1e, 0xc0, 0x67, - 0xc6, 0x8c, 0x3c, 0xc3, 0xee, 0x15, 0xb8, 0x68, 0x93, 0xbc, - 0x47, 0xa8, 0xbe, 0xa5, 0x0f, 0x37, 0x67, 0xb5, 0x2a, 0x44, - 0xdd, 0xf8, 0x64, 0x8c, 0xe0, 0x2b, 0x56, 0x63, 0xf6, 0x20, - 0x56, 0xa8, 0x67, 0x1d, 0xc4, 0x41, 0x98, 0x5f, 0xdb, 0x10, - 0xbd, 0x6e, 0xbb, 0x4e, 0xd7, 0xf1, 0xc0, 0xf2, 0x81, 0x22, - 0xa8, 0x08, 0x95, 0xf5, 0xe1, 0x73, 0x58, 0x57, 0x11, 0xb6, - 0x4a, 0xd5, 0x5a, 0x6c, 0x37, 0xcc, 0xaa, 0xc2, 0x74, 0xc3, - 0x76, 0xe8, 0x3f, 0xdb, 0x02, 0x44, 0x83, 0x58, 0xc3, 0x17, - 0xf2, 0xa2, 0x8d, 0x3a, 0xb6, 0x08, 0x00, 0x3d, 0xb7, 0xa2, - 0x85, 0xf0, 0xb6, 0x9d, 0xda, 0x70, 0x32, 0xa7, 0xec, 0xaa, - 0xe8, 0xab, 0x56, 0x78, 0x2e, 0x83, 0x01, 0x18, 0xb7, 0xb5, - 0xc4, 0x01, 0xa4, 0x1e, 0x95, 0x05, 0x58, 0x25, 0x6d, 0xf0, - 0x00, 0xa9, 0x21, 0x3d, 0x37, 0xac, 0x8e, 0x76, 0xb8, 0x80, - 0xd4, 0x92, 0xc3, 0x06, 0xac, 0xaa, 0x16, 0xf9, 0x80, 0xd5, - 0x97, 0x66, 0x04, 0x5e, 0x59, 0x63, 0x4e, 0x08, 0x37, 0xeb, - 0xa5, 0x80, 0x4c, 0x3a, 0x05, 0xab, 0x20, 0x84, 0xe7, 0x77, - 0x63, 0x3a, 0x19, 0x46, 0xb0, 0x06, 0x05, 0xa9, 0x54, 0xb9, - 0xd0, 0x82, 0x1f, 0xeb, 0x57, 0xc2, 0x51, 0x4b, 0x53, 0x95, - 0xc8, 0x28, 0xa6, 0x35, 0x2b, 0xc1, 0xa0, 0x6e, 0x99, 0xd5, - 0x60, 0x84, 0xb7, 0x74, 0x3d, 0xcd, 0x8f, 0x8e, 0xe6, 0x66, - 0x2d, 0x86, 0x59, 0x5e, 0x70, 0x48, 0x14, 0x73, 0x32, 0x4c, - 0x41, 0x3a, 0x94, 0x04, 0xa9, 0x3d, 0xc1, 0x9d, 0x92, 0x43, - 0xf6, 0xcc, 0x92, 0xdf, 0x4c, 0x03, 0x82, 0x24, 0xeb, 0xe3, - 0x30, 0x0c, 0xad, 0xe9, 0x95, 0x35, 0xea, 0xdc, 0x2a, 0x4a, - 0x90, 0x05, 0xbf, 0x7b, 0x80, 0x47, 0xa6, 0x82, 0xf8, 0x42, - 0x73, 0x60, 0xa5, 0x3c, 0x84, 0x4d, 0x0f, 0x84, 0x05, 0x5e, - 0xc5, 0x9d, 0x69, 0x7f, 0xce, 0x13, 0xa6, 0x72, 0xe0, 0x06, - 0xd8, 0x1f, 0x9c, 0x2d, 0x35, 0x1f, 0x6c, 0x97, 0x47, 0xd4, - 0x1f, 0x49, 0x11, 0x85, 0xf9, 0x9f, 0x7c, 0x31, 0xa7, 0xa3, - 0x34, 0xb8, 0xef, 0x17, 0x3b, 0xf4, 0xf1, 0x8d, 0xcc, 0x5e, - 0x6e, 0xae, 0x59, 0xd8, 0x42, 0x4b, 0x89, 0x7c, 0x1c, 0x05, - 0xb1, 0xbb, 0x2a, 0x0c, 0xfb, 0xef, 0x8d, 0x95, 0x0c, 0x21, - 0x24, 0x07, 0x5e, 0x7e, 0x48, 0xf0, 0xe5, 0xe2, 0x4a, 0x49, - 0x02, 0xd2, 0x05, 0x77, 0xdb, 0x07, 0xad, 0x63, 0x05, 0x71, - 0xbd, 0xa3, 0xcb, 0x1e, 0xff, 0xdd, 0x02, 0xa2, 0x8a, 0xed, - 0xac, 0xa6, 0x04, 0x53, 0x30, 0x61, 0xda, 0xa4, 0x69, 0x33, - 0xb3, 0xdb, 0x31, 0xf8, 0x5b, 0x2d, 0xbe, 0x45, 0x79, 0x4c, - 0x7c, 0x04, 0x06, 0x88, 0xad, 0x01, 0xc7, 0xf4, 0xf4, 0x9f, - 0x70, 0x4a, 0x87, 0xbd, 0x4e, 0x96, 0xb6, 0xee, 0xbd, 0x7c, - 0xbe, 0xa6, 0x5a, 0x25, 0xc2, 0x4d, 0x0c, 0xd2, 0x20, 0x01, - 0x19, 0x6c, 0x39, 0x5d, 0x99, 0xfd, 0x51, 0xed, 0xf5, 0xf4, - 0xf5, 0x40, 0x59, 0x48, 0x2f, 0x07, 0xf9, 0x5c, 0xf0, 0x15, - 0xa1, 0xbd, 0x48, 0xeb, 0xe7, 0x05, 0x3d, 0x29, 0x28, 0xbe, - 0xaf, 0xac, 0x9c, 0x17, 0xfc, 0xa8, 0xf0, 0xa4, 0x91, 0xfc, - 0x19, 0xfd, 0xf7, 0xff, 0x0f, 0x95, 0xab, 0x53, 0x09, 0xf4, - 0xfc, 0x02, 0x00 + 0x74, 0x6d, 0x70, 0x35, 0x51, 0x76, 0x75, 0x43, 0x5a, 0x00, + 0xec, 0xbd, 0xd9, 0x72, 0xdc, 0x48, 0x92, 0x2e, 0x7c, 0x5d, + 0xfd, 0x14, 0x30, 0xfd, 0xd6, 0x76, 0x54, 0x66, 0xa3, 0xe2, + 0x2e, 0x52, 0x63, 0xd3, 0x73, 0x0c, 0xcc, 0x04, 0xc9, 0x3c, + 0xca, 0xad, 0x00, 0x24, 0x25, 0xea, 0x06, 0x06, 0x26, 0x82, + 0x49, 0x0c, 0x91, 0x40, 0x16, 0x80, 0x24, 0x99, 0x7c, 0xaa, + 0xb9, 0xe9, 0x17, 0xe8, 0x27, 0xfb, 0x63, 0x01, 0x10, 0x0b, + 0xb6, 0xc0, 0x42, 0x49, 0x55, 0xcd, 0x1a, 0xb3, 0x1e, 0x25, + 0x18, 0xe1, 0xb1, 0x79, 0x78, 0x78, 0x78, 0xb8, 0x7f, 0xfe, + 0x5f, 0xff, 0xf7, 0x79, 0xed, 0x29, 0x8f, 0x20, 0x8c, 0xdc, + 0xc0, 0xff, 0xc7, 0xbb, 0x83, 0xdf, 0xf6, 0xdf, 0x29, 0xc0, + 0x5f, 0x06, 0x8e, 0xeb, 0xaf, 0xfe, 0xf1, 0x6e, 0x61, 0x5e, + 0x7c, 0x38, 0x7b, 0xf7, 0x7f, 0xff, 0xfb, 0x6f, 0xff, 0xb5, + 0x06, 0x51, 0x64, 0xaf, 0x40, 0xa4, 0xc0, 0xe2, 0x7e, 0xf4, + 0x9f, 0xcf, 0x91, 0xfb, 0x8f, 0x77, 0xf7, 0x71, 0xbc, 0xf9, + 0xcf, 0xbd, 0xbd, 0xa7, 0xa7, 0xa7, 0xdf, 0x9e, 0x8e, 0x7e, + 0x0b, 0xc2, 0xd5, 0xde, 0xe1, 0xfe, 0xfe, 0xc1, 0xde, 0xd7, + 0xc9, 0xd8, 0x58, 0xde, 0x83, 0xb5, 0xfd, 0xc1, 0xf5, 0xa3, + 0xd8, 0xf6, 0x97, 0xe0, 0x9d, 0xe2, 0x05, 0xfe, 0xea, 0x83, + 0x6f, 0xaf, 0xc1, 0x3f, 0xde, 0x8d, 0xfc, 0x18, 0x84, 0xca, + 0x24, 0x70, 0xb6, 0x1e, 0x50, 0x06, 0xc1, 0x7a, 0xbd, 0xf5, + 0xdd, 0xa5, 0x1d, 0xc3, 0xe6, 0xdf, 0x29, 0x49, 0x89, 0xc9, + 0xe0, 0x1d, 0xed, 0xd2, 0xc9, 0x6f, 0xc7, 0xbf, 0x1d, 0xc1, + 0x5e, 0xc1, 0x26, 0xff, 0xd3, 0x0f, 0xa6, 0xb0, 0x44, 0xb4, + 0xb1, 0x97, 0x80, 0x34, 0x31, 0x0e, 0x48, 0x55, 0x5c, 0xe9, + 0xb7, 0xe7, 0xc8, 0x79, 0xf7, 0xdf, 0x7f, 0xfb, 0x9b, 0xa2, + 0xfc, 0x57, 0xbc, 0xdb, 0x80, 0xe8, 0xbf, 0xe1, 0xbf, 0x92, + 0x7f, 0x27, 0x94, 0x5d, 0x3f, 0x3e, 0xb3, 0xe2, 0x77, 0x4a, + 0xe4, 0xbe, 0xc0, 0x5f, 0x07, 0xef, 0x48, 0x09, 0x58, 0x66, + 0x0f, 0x15, 0xca, 0x97, 0xdf, 0x36, 0xad, 0x00, 0xcb, 0x1f, + 0x7c, 0xa4, 0x15, 0x0e, 0xa5, 0x5a, 0x68, 0x56, 0x03, 0x56, + 0x38, 0x3a, 0xa4, 0x15, 0x8e, 0xa5, 0x9a, 0x68, 0x56, 0x03, + 0x56, 0xf8, 0x78, 0x4c, 0x2b, 0x9c, 0xd5, 0x56, 0xb8, 0xdb, + 0x34, 0x6b, 0xe0, 0x6e, 0xd3, 0x8c, 0x7e, 0x68, 0x3f, 0x39, + 0x76, 0x6c, 0xd7, 0x96, 0xdb, 0x78, 0x36, 0xec, 0x3b, 0x78, + 0x8e, 0x6b, 0x4b, 0x26, 0xfc, 0x2c, 0x5b, 0xee, 0x83, 0xe7, + 0x46, 0x45, 0x44, 0xc9, 0xbf, 0x22, 0xc2, 0x74, 0x11, 0x08, + 0x5d, 0xdb, 0x73, 0x5f, 0x30, 0x47, 0xfe, 0xa9, 0x06, 0x21, + 0xf4, 0x1c, 0x7d, 0x83, 0xbb, 0x32, 0x4e, 0x77, 0x10, 0xfa, + 0xb7, 0x62, 0xdf, 0xde, 0x86, 0xe0, 0xf1, 0x1f, 0xef, 0xd4, + 0x74, 0x9b, 0xaa, 0xeb, 0x0d, 0x08, 0xe1, 0xde, 0xde, 0x2b, + 0x2a, 0x75, 0xeb, 0xc6, 0x69, 0xb9, 0x73, 0xf4, 0xcf, 0xe2, + 0x42, 0x9b, 0x88, 0x29, 0x14, 0x29, 0x90, 0x9e, 0x12, 0x81, + 0x65, 0xe0, 0x3b, 0x65, 0x15, 0x76, 0x31, 0xc8, 0x6a, 0xe0, + 0x7f, 0x17, 0x16, 0x5b, 0xa5, 0x65, 0x2e, 0x43, 0xfb, 0xd1, + 0x8d, 0x77, 0x8a, 0xbd, 0x5c, 0x02, 0x0f, 0x84, 0x89, 0x94, + 0x29, 0xac, 0xb3, 0x5c, 0xa7, 0x95, 0x06, 0xc0, 0x8f, 0xdd, + 0x35, 0x80, 0x52, 0xaa, 0xb4, 0xe8, 0x5e, 0x94, 0x2f, 0x5c, + 0xdf, 0x7b, 0x27, 0x6b, 0x62, 0x08, 0x96, 0x95, 0x2d, 0x38, + 0xe7, 0x6c, 0xc9, 0x5b, 0xe0, 0x95, 0x96, 0xdb, 0x5b, 0x0b, + 0x25, 0x71, 0x37, 0xaa, 0x69, 0x5f, 0xbd, 0x88, 0x75, 0xee, + 0x41, 0x18, 0xbf, 0x94, 0x96, 0xcf, 0x35, 0xb1, 0x76, 0x3d, + 0xcf, 0x7d, 0xb2, 0xe3, 0x38, 0xfa, 0xad, 0xa4, 0xd2, 0xbf, + 0xfe, 0x97, 0xd6, 0x59, 0x85, 0x00, 0x94, 0x16, 0x1b, 0xf0, + 0xe5, 0x94, 0x01, 0xf0, 0x22, 0x77, 0x1b, 0x95, 0x94, 0xbf, + 0xcc, 0x16, 0xd6, 0xde, 0x46, 0x65, 0x85, 0xee, 0xe7, 0x76, + 0x5a, 0xec, 0x0a, 0x2c, 0xe3, 0x60, 0x63, 0x47, 0x4b, 0xbb, + 0x6c, 0x06, 0xe9, 0x5c, 0x5c, 0x55, 0xcc, 0xc1, 0xc3, 0x6a, + 0x6f, 0x8d, 0xfe, 0x2f, 0x2d, 0xfb, 0xd9, 0xf5, 0x82, 0x55, + 0x68, 0xaf, 0xf1, 0x64, 0x2f, 0xb7, 0xb7, 0xee, 0x12, 0x4d, + 0x79, 0xe9, 0x66, 0x98, 0xb8, 0xd9, 0x7a, 0x4e, 0xc0, 0xad, + 0x7b, 0x5b, 0xce, 0xb9, 0x6b, 0x5a, 0xae, 0x7c, 0x05, 0x19, + 0xf6, 0x9b, 0xc8, 0x71, 0x1e, 0xac, 0x51, 0x58, 0xe7, 0x8f, + 0xad, 0x1d, 0x82, 0x9a, 0xaa, 0xb4, 0x1e, 0x5a, 0xf5, 0xca, + 0xb2, 0xff, 0xfa, 0x27, 0x53, 0x78, 0x19, 0x06, 0x95, 0x85, + 0xfd, 0xac, 0xec, 0xd4, 0xf6, 0xab, 0x8b, 0x1a, 0x74, 0xe6, + 0x0d, 0x17, 0xac, 0x81, 0x1f, 0xd5, 0x72, 0xf9, 0xc3, 0x4a, + 0x5c, 0xab, 0x92, 0x82, 0xd3, 0x8c, 0xf4, 0x14, 0x3c, 0xc5, + 0x81, 0x5f, 0x49, 0x75, 0x6a, 0x2e, 0x68, 0xe9, 0xcd, 0x3d, + 0xf0, 0x02, 0xb4, 0xec, 0x70, 0xf5, 0xcd, 0x6d, 0x78, 0xeb, + 0x3a, 0x48, 0xd4, 0x2c, 0xfc, 0x52, 0x71, 0x37, 0xe5, 0x5b, + 0x2a, 0x29, 0x45, 0xb9, 0x77, 0x5e, 0xc5, 0xb8, 0x7f, 0xcf, + 0x4a, 0x81, 0x70, 0x09, 0x85, 0x50, 0x19, 0xb5, 0xf9, 0x84, + 0x92, 0x0b, 0x13, 0x19, 0x8b, 0xf7, 0x6f, 0x79, 0x07, 0xe6, + 0xe7, 0xf9, 0x2a, 0xb7, 0xd5, 0x55, 0x8c, 0x6c, 0x5e, 0xe6, + 0x48, 0xca, 0xc2, 0x6e, 0x2b, 0x06, 0x3c, 0x50, 0xfc, 0x9a, + 0x19, 0x39, 0xa0, 0x0b, 0x3b, 0xf2, 0x91, 0xc6, 0x07, 0x94, + 0x2a, 0xc6, 0xdf, 0x3c, 0x67, 0xad, 0xb8, 0xcf, 0xa5, 0x42, + 0xf1, 0x5f, 0xff, 0x5c, 0xed, 0x8d, 0x39, 0x3e, 0xcc, 0xb6, + 0xaa, 0xe7, 0x96, 0x13, 0xff, 0xd7, 0x3f, 0x27, 0x5c, 0xa5, + 0x75, 0xe0, 0xd9, 0x65, 0x65, 0x43, 0xdb, 0x49, 0xcb, 0xea, + 0xb6, 0xe3, 0xda, 0x7e, 0x79, 0x39, 0xba, 0xef, 0x48, 0xc9, + 0xfa, 0xcd, 0x1a, 0x6e, 0xb2, 0x49, 0xd1, 0xc1, 0x63, 0xe0, + 0x6d, 0xd1, 0xa9, 0x95, 0x2e, 0x9c, 0xbf, 0x2d, 0x95, 0x1d, + 0xb0, 0x1e, 0xd3, 0x58, 0x61, 0xcd, 0xfa, 0xc6, 0x33, 0x02, + 0x46, 0x55, 0xa9, 0xeb, 0xb4, 0xd4, 0x75, 0xe0, 0x95, 0xad, + 0xad, 0xe6, 0x6f, 0xd7, 0xe8, 0xc8, 0x05, 0xd9, 0x54, 0xa5, + 0x5f, 0x60, 0xa7, 0x94, 0xe0, 0x4e, 0x41, 0x4a, 0xce, 0x0a, + 0xf6, 0xe7, 0xd1, 0xf6, 0xb6, 0xa0, 0x4c, 0x98, 0x8f, 0x91, + 0xca, 0x92, 0x9e, 0xb5, 0xf0, 0xb2, 0x60, 0xc3, 0xee, 0x6f, + 0x6c, 0x4c, 0x56, 0x41, 0xea, 0x0c, 0x22, 0x54, 0x49, 0x00, + 0x2a, 0x16, 0x77, 0x2e, 0xf0, 0x1c, 0x46, 0xd1, 0x50, 0x92, + 0x0f, 0x85, 0xe5, 0xcd, 0xed, 0xc6, 0x03, 0x6c, 0xab, 0xe3, + 0xa4, 0x95, 0x07, 0xb0, 0xdb, 0xc3, 0x2d, 0x29, 0x31, 0x2a, + 0x12, 0x31, 0x8a, 0x14, 0x22, 0x40, 0x14, 0xa9, 0x44, 0x6b, + 0x42, 0xff, 0x06, 0x74, 0xb4, 0xa9, 0x1e, 0xe5, 0x80, 0x3b, + 0xda, 0xaf, 0x20, 0xf0, 0x80, 0x9d, 0xdd, 0x79, 0x92, 0x9f, + 0xca, 0x35, 0x6a, 0xe1, 0x9d, 0xb2, 0x09, 0xc1, 0x9d, 0xfb, + 0x0c, 0x3f, 0xcf, 0x66, 0x63, 0xda, 0x10, 0x69, 0x3e, 0xa5, + 0x70, 0xa1, 0x8e, 0x0d, 0xed, 0x9d, 0xe2, 0x3a, 0xff, 0x78, + 0xb7, 0x9f, 0x92, 0xb9, 0xb0, 0xbd, 0x88, 0xf2, 0x47, 0xae, + 0x8a, 0xa9, 0x2f, 0x92, 0x1a, 0x07, 0x69, 0x0d, 0x33, 0xdc, + 0x32, 0x0c, 0xb5, 0x07, 0xbb, 0x88, 0xbb, 0x2f, 0xf4, 0x76, + 0x10, 0xf8, 0x71, 0x18, 0x78, 0x1e, 0x70, 0xe0, 0xc5, 0x0d, + 0xd0, 0x05, 0x49, 0xbf, 0x2a, 0xe4, 0x73, 0xda, 0xed, 0x81, + 0x39, 0x9e, 0x0c, 0xcb, 0xfa, 0xad, 0x6b, 0xe3, 0xd1, 0xf4, + 0xf7, 0xc5, 0xc8, 0xb8, 0xb2, 0xae, 0xd4, 0xe9, 0x70, 0x76, + 0x71, 0x61, 0xc1, 0xf2, 0xc2, 0x40, 0x74, 0x00, 0xa5, 0xc7, + 0x1f, 0x5b, 0x37, 0xba, 0x57, 0xf6, 0x94, 0x2b, 0xdb, 0x77, + 0x82, 0xbb, 0x3b, 0x25, 0x69, 0xaf, 0x7c, 0x7c, 0xba, 0xf6, + 0xfb, 0x42, 0x33, 0x4c, 0x4a, 0xef, 0x80, 0xd2, 0xfb, 0x03, + 0xf2, 0x48, 0x5c, 0x4f, 0x62, 0x76, 0xad, 0xe9, 0xfa, 0x68, + 0xa8, 0x51, 0x1a, 0x87, 0x29, 0x8d, 0x19, 0x94, 0x50, 0xa1, + 0xeb, 0x80, 0x1c, 0x91, 0xd2, 0x69, 0x33, 0x36, 0x00, 0x38, + 0x48, 0xfe, 0xd1, 0x6d, 0x85, 0xbe, 0x28, 0xc9, 0xa7, 0x74, + 0xba, 0x8c, 0xc5, 0x74, 0x64, 0x1a, 0x65, 0xf3, 0x35, 0xd1, + 0x4c, 0x4d, 0x37, 0xac, 0xb9, 0x21, 0x4c, 0x11, 0x96, 0x94, + 0x85, 0x4a, 0x73, 0x7e, 0x5e, 0xd0, 0x29, 0xc0, 0xcf, 0x07, + 0xfa, 0x52, 0x56, 0x7c, 0xae, 0xe9, 0x03, 0x6d, 0x6a, 0xaa, + 0x97, 0x9a, 0x30, 0x03, 0xc9, 0x59, 0x83, 0xee, 0x1c, 0xf5, + 0x63, 0xdf, 0x45, 0x31, 0x58, 0x9b, 0xf0, 0x8e, 0x91, 0x8d, + 0x1d, 0x7f, 0x51, 0xc8, 0xa7, 0x6c, 0xec, 0x37, 0x86, 0xa9, + 0x4d, 0xcc, 0x9b, 0xb9, 0x56, 0x36, 0xfe, 0xc1, 0x60, 0x21, + 0x8c, 0x1c, 0x7f, 0x29, 0xeb, 0xfc, 0xd5, 0x62, 0xa2, 0x4e, + 0x0d, 0x6d, 0x6a, 0xcc, 0x74, 0x61, 0xcc, 0x57, 0xdb, 0xb5, + 0xed, 0x7f, 0xd8, 0x04, 0x61, 0x6c, 0xdf, 0x7a, 0x40, 0x31, + 0xa0, 0x1e, 0x11, 0x84, 0xe5, 0x84, 0x16, 0x8b, 0x6b, 0x61, + 0xf8, 0xf8, 0x4b, 0x69, 0x71, 0x23, 0x29, 0x7e, 0x94, 0x15, + 0x37, 0xaa, 0x8a, 0xab, 0x49, 0xf1, 0xe3, 0xac, 0xb8, 0x5a, + 0x55, 0xfc, 0x32, 0x29, 0x7e, 0x92, 0x15, 0xbf, 0xac, 0x28, + 0x6e, 0x98, 0xaa, 0x39, 0x1a, 0xb0, 0xb3, 0xf0, 0x31, 0x5b, + 0x85, 0x18, 0x1d, 0xd0, 0x90, 0x65, 0xaa, 0x47, 0x3f, 0x99, + 0x9d, 0x8f, 0xc6, 0x1a, 0x4b, 0xe1, 0x34, 0x63, 0xbc, 0x00, + 0x6a, 0x03, 0xa0, 0x96, 0xc2, 0x17, 0x63, 0x4a, 0x2a, 0x9e, + 0xa5, 0x15, 0xbf, 0xb8, 0x21, 0xbc, 0x86, 0x45, 0x51, 0x32, + 0xf5, 0xca, 0x14, 0xc4, 0x4f, 0x41, 0xf8, 0x50, 0xcf, 0x4b, + 0xdf, 0xb8, 0x3d, 0xf4, 0x4d, 0xdc, 0x3f, 0xdf, 0xca, 0x58, + 0x67, 0x3a, 0x9b, 0x8a, 0x12, 0x72, 0x1a, 0xf8, 0x15, 0x02, + 0x72, 0xa8, 0xcd, 0xcd, 0x2b, 0x81, 0x6d, 0x86, 0x60, 0x13, + 0xdf, 0x97, 0x57, 0x51, 0xc7, 0xe6, 0xc8, 0x5c, 0x0c, 0xc5, + 0xad, 0xa2, 0x7a, 0xb1, 0x1b, 0x6f, 0x9d, 0x8a, 0xb6, 0xae, + 0xb4, 0xd1, 0xe5, 0x95, 0x29, 0xf0, 0xcc, 0x15, 0x70, 0x57, + 0xf7, 0x71, 0xfd, 0x8c, 0xe8, 0x86, 0x31, 0xe2, 0x26, 0x05, + 0x7d, 0x10, 0xe7, 0x05, 0x17, 0xaa, 0x12, 0x2d, 0xe8, 0x9e, + 0xc9, 0xcd, 0x8e, 0x78, 0xdd, 0xac, 0x15, 0x0d, 0x07, 0x6d, + 0x44, 0x03, 0xe4, 0x74, 0x56, 0x2e, 0xc0, 0x9f, 0x82, 0x50, + 0x40, 0x05, 0x2a, 0x24, 0xc2, 0xc5, 0xe8, 0xab, 0x36, 0xfc, + 0x32, 0x9a, 0x5e, 0x8a, 0xa7, 0x1f, 0xd4, 0x0a, 0x9d, 0x0f, + 0x5f, 0x5c, 0x7f, 0x55, 0x3e, 0x80, 0xc1, 0x6c, 0x0e, 0xc5, + 0xa9, 0xd0, 0xf9, 0x41, 0xb0, 0x61, 0x15, 0xc3, 0x5c, 0xa5, + 0x6b, 0x73, 0x26, 0x1e, 0x06, 0xd7, 0x71, 0xfe, 0x00, 0x40, + 0xff, 0xe0, 0x8f, 0x7d, 0xf4, 0xe9, 0x36, 0xd1, 0x40, 0x8a, + 0xb4, 0x80, 0xc1, 0x38, 0x08, 0x36, 0xd1, 0xc4, 0x8e, 0x1e, + 0x84, 0x33, 0x55, 0xc1, 0x7f, 0x50, 0xc8, 0x5f, 0xb2, 0x63, + 0x75, 0x2c, 0xc1, 0xe8, 0xcf, 0xfb, 0xc9, 0x7f, 0x72, 0x1c, + 0x3f, 0x57, 0x53, 0x86, 0xcf, 0x6a, 0xd2, 0x35, 0xb5, 0xe3, + 0xfb, 0xfa, 0x13, 0xd3, 0xd4, 0xc6, 0xda, 0x0c, 0xf2, 0x05, + 0x94, 0x38, 0xb3, 0xa9, 0x40, 0x2a, 0x9b, 0x2e, 0x13, 0x6e, + 0xfc, 0x60, 0x93, 0x6a, 0x7f, 0xb5, 0x34, 0xf9, 0x4d, 0x95, + 0x91, 0x3b, 0x16, 0x77, 0x57, 0x3d, 0x25, 0x66, 0x47, 0x67, + 0x64, 0xce, 0xb8, 0xad, 0x2d, 0xa1, 0x56, 0xcc, 0xc6, 0x63, + 0x9e, 0xc4, 0x01, 0x55, 0x54, 0xa0, 0xfe, 0x53, 0x4f, 0x61, + 0x3e, 0x32, 0x07, 0x42, 0x2f, 0x0e, 0xf7, 0xe9, 0x65, 0x26, + 0x5e, 0x4a, 0xf4, 0xe2, 0x46, 0xfd, 0xc2, 0x53, 0x38, 0xce, + 0x28, 0xdc, 0xd8, 0x4f, 0xf5, 0xf5, 0x8d, 0xb9, 0xa6, 0x0d, + 0x79, 0x0a, 0x67, 0xfb, 0xbc, 0x5e, 0x22, 0xd3, 0x07, 0x0b, + 0x2e, 0x34, 0xbf, 0x2e, 0x07, 0xfb, 0x5c, 0x47, 0x74, 0xa8, + 0x9c, 0xd7, 0x53, 0x82, 0x6a, 0x16, 0x3c, 0xa1, 0xd4, 0x71, + 0x9e, 0xdc, 0x21, 0x25, 0x77, 0x0d, 0x42, 0x72, 0x99, 0x94, + 0xa3, 0x69, 0xce, 0xf4, 0xdf, 0x17, 0x3c, 0xb1, 0x63, 0x4a, + 0xcc, 0x0c, 0x42, 0xa8, 0x03, 0xd6, 0x53, 0xb9, 0x98, 0x41, + 0x11, 0xc7, 0x11, 0x39, 0xa3, 0x44, 0x2e, 0x02, 0x28, 0xe6, + 0x64, 0x46, 0x37, 0x9e, 0x0d, 0x46, 0xe6, 0x0d, 0x4b, 0xe6, + 0x60, 0x9f, 0x1d, 0x98, 0x17, 0x2c, 0xd1, 0xe5, 0xb8, 0x7e, + 0x4c, 0x57, 0xfa, 0xcc, 0x34, 0xc7, 0x5c, 0x87, 0x0e, 0x19, + 0x4a, 0xe6, 0x7d, 0x18, 0xc4, 0xb1, 0x27, 0xd1, 0x27, 0xed, + 0x2b, 0x14, 0x7c, 0x53, 0x35, 0xe3, 0xe4, 0x63, 0x41, 0x4e, + 0x2c, 0xfc, 0x68, 0x03, 0xc5, 0x3f, 0x94, 0x55, 0x8e, 0xa2, + 0x3d, 0x43, 0x79, 0xe8, 0xdb, 0x12, 0x9c, 0x3d, 0x9d, 0x59, + 0xa9, 0xca, 0x9c, 0x12, 0x3e, 0xcb, 0x0b, 0xa0, 0x0f, 0x01, + 0xd1, 0x9d, 0xb1, 0xe2, 0xb5, 0xac, 0xdf, 0xfd, 0x59, 0x27, + 0x2f, 0x92, 0xff, 0xe8, 0xc6, 0x97, 0x50, 0xbb, 0x67, 0x9b, + 0xb1, 0xbb, 0x86, 0x27, 0x21, 0x2b, 0x57, 0x67, 0xa9, 0xf0, + 0x81, 0x83, 0x22, 0x7f, 0x15, 0x84, 0xeb, 0x6c, 0x5e, 0x2a, + 0x5d, 0x27, 0xea, 0x57, 0x8b, 0x97, 0x23, 0x99, 0x88, 0x9c, + 0xd8, 0xcf, 0xee, 0x7a, 0xbb, 0x56, 0x6a, 0x94, 0x84, 0xc9, + 0x68, 0x6a, 0x41, 0x99, 0x96, 0xd5, 0x3f, 0xa4, 0xa6, 0x06, + 0x1f, 0xd7, 0xaf, 0x57, 0x17, 0x50, 0x27, 0x58, 0x12, 0xc7, + 0x62, 0x17, 0x24, 0x48, 0xc0, 0x5e, 0xf0, 0x52, 0xe0, 0x4c, + 0xec, 0x07, 0x96, 0x03, 0xd5, 0x9d, 0xe0, 0x28, 0x50, 0x41, + 0x98, 0x76, 0x43, 0x82, 0xc2, 0x35, 0xbb, 0xe7, 0x0f, 0x73, + 0x14, 0xb8, 0x5d, 0x5f, 0xc1, 0x25, 0xba, 0xa6, 0x52, 0x5e, + 0xce, 0xad, 0xb3, 0xa2, 0x86, 0xc0, 0x2e, 0x3a, 0xa1, 0x99, + 0xf3, 0x18, 0xfd, 0x4e, 0x1f, 0x47, 0x56, 0x61, 0xb0, 0xdd, + 0xa4, 0x67, 0x34, 0xf7, 0x91, 0xf6, 0xdd, 0xf6, 0xc1, 0xf6, + 0x11, 0x29, 0x0a, 0x69, 0x87, 0x93, 0xdf, 0x59, 0x0f, 0xd3, + 0x7a, 0xf8, 0xf1, 0x25, 0xeb, 0xa8, 0xe7, 0xae, 0xfc, 0x35, + 0x6b, 0xa3, 0x2b, 0x2d, 0xb9, 0x8d, 0x03, 0x3f, 0x58, 0x07, + 0xdb, 0xc8, 0x00, 0x4b, 0xee, 0xb1, 0xa2, 0xac, 0x06, 0xb2, + 0x89, 0x44, 0xf0, 0xb2, 0x6c, 0xef, 0x64, 0x8a, 0x6e, 0xec, + 0x28, 0x1a, 0xd8, 0x9e, 0x7b, 0x2b, 0x3c, 0x85, 0x94, 0x57, + 0x81, 0xa3, 0xe3, 0xe6, 0xb1, 0xb4, 0xe4, 0x36, 0x8a, 0x83, + 0x35, 0x9d, 0xa0, 0x9a, 0xe2, 0x43, 0x37, 0xf2, 0x02, 0x67, + 0x05, 0xea, 0x0b, 0x86, 0xc1, 0xa6, 0xb6, 0xd0, 0xc8, 0xf1, + 0x80, 0x74, 0xd3, 0xa3, 0x35, 0xfc, 0x64, 0x86, 0xf6, 0xf2, + 0x41, 0xd0, 0x13, 0x0b, 0x4b, 0x6b, 0x1e, 0x78, 0xb4, 0xe3, + 0xa0, 0x9e, 0xec, 0x05, 0xd4, 0x03, 0x82, 0x27, 0xa4, 0x31, + 0xc9, 0x16, 0x0d, 0x5c, 0x09, 0x8e, 0x20, 0x65, 0x75, 0x70, + 0x07, 0x42, 0x80, 0x5f, 0xd2, 0xa5, 0xca, 0xc3, 0xe1, 0xfd, + 0x0f, 0x7a, 0xfa, 0x08, 0x77, 0x12, 0x15, 0xc2, 0x35, 0x66, + 0x86, 0xb9, 0x67, 0xfb, 0xda, 0x33, 0x58, 0x6e, 0xa5, 0x38, + 0xe3, 0x32, 0x88, 0x83, 0xda, 0x42, 0x63, 0x9b, 0x37, 0x4a, + 0x94, 0x14, 0xda, 0xfa, 0xcb, 0xfa, 0x49, 0x1b, 0x07, 0x6e, + 0x2c, 0xb1, 0xba, 0xe3, 0xe0, 0x69, 0x0c, 0x1e, 0x81, 0x57, + 0x70, 0x6e, 0x15, 0x96, 0x9f, 0xd8, 0x2b, 0x1f, 0xc4, 0x01, + 0x6f, 0xf4, 0x2f, 0x2b, 0x3c, 0x0f, 0x36, 0x8b, 0x7a, 0x6e, + 0xd4, 0x83, 0xa7, 0x48, 0xaa, 0x10, 0xde, 0x5d, 0xb6, 0xc4, + 0x26, 0x30, 0xec, 0xf5, 0xc6, 0x93, 0x28, 0xb6, 0xbc, 0x07, + 0xc8, 0xab, 0xc2, 0x91, 0x5a, 0x1c, 0x6c, 0x07, 0x08, 0xfc, + 0xcf, 0x00, 0x6c, 0x64, 0x36, 0x02, 0x5f, 0x1c, 0xe9, 0x07, + 0xbe, 0x03, 0xea, 0x57, 0xd7, 0xb4, 0x1f, 0x40, 0x70, 0x77, + 0x57, 0x5f, 0x8e, 0xbd, 0x1f, 0xd4, 0x96, 0xbe, 0x06, 0xf7, + 0xee, 0xd2, 0x03, 0x19, 0xef, 0xd6, 0x56, 0xb8, 0x09, 0x6e, + 0x02, 0xe6, 0x2c, 0xe0, 0xc4, 0x7b, 0xaa, 0x41, 0x14, 0xcb, + 0xfc, 0x84, 0x91, 0xb0, 0xed, 0xd9, 0x77, 0xc4, 0x5b, 0x5a, + 0xfa, 0xb9, 0x46, 0x88, 0x81, 0xc8, 0x0d, 0x81, 0xf3, 0xad, + 0x5e, 0xda, 0x91, 0x82, 0x57, 0xc0, 0x76, 0x64, 0xd6, 0x24, + 0x29, 0x8e, 0xae, 0x20, 0xb2, 0x65, 0xf1, 0x5d, 0x43, 0xb6, + 0x70, 0xee, 0x28, 0xaf, 0xa4, 0x2c, 0x23, 0xfa, 0x92, 0xb2, + 0xa9, 0xd2, 0xda, 0x6e, 0x49, 0x74, 0xb0, 0x0e, 0x62, 0x30, + 0x44, 0xbe, 0x14, 0x99, 0x75, 0x37, 0xfb, 0x52, 0xb3, 0xed, + 0x70, 0xc1, 0x6c, 0x31, 0x6b, 0x7a, 0x7b, 0xe5, 0xc2, 0x43, + 0x2d, 0x74, 0x97, 0xc2, 0xfe, 0xcb, 0x75, 0x36, 0xf7, 0x29, + 0x51, 0x2d, 0xee, 0x3c, 0x7b, 0x95, 0x6a, 0x14, 0xe8, 0xdf, + 0xf4, 0x21, 0x0b, 0x84, 0x6e, 0xe0, 0xb8, 0x4b, 0xc6, 0x78, + 0x92, 0xfc, 0xde, 0x2b, 0x2a, 0xee, 0x00, 0xa8, 0xa4, 0x2e, + 0xd9, 0xa7, 0x94, 0x21, 0xf3, 0x65, 0x8f, 0x74, 0x20, 0x69, + 0x0c, 0xfd, 0xfb, 0x1e, 0xf2, 0x0f, 0x08, 0x53, 0x4a, 0x48, + 0xd7, 0xa1, 0xef, 0x3b, 0x3b, 0x1f, 0xb6, 0x72, 0x87, 0x0c, + 0x25, 0xff, 0x78, 0x17, 0x63, 0xdb, 0x7f, 0x6a, 0x9c, 0x85, + 0x52, 0x38, 0x0c, 0xfc, 0xc4, 0x09, 0x44, 0x99, 0x6e, 0xd7, + 0xb7, 0x48, 0x24, 0xa2, 0x09, 0x61, 0xdd, 0x94, 0xb0, 0x0e, + 0x86, 0x35, 0x73, 0xed, 0x84, 0x75, 0xf4, 0xc1, 0xcd, 0x14, + 0x36, 0xb9, 0x5e, 0xb9, 0x0e, 0xb5, 0x59, 0xe3, 0x59, 0x52, + 0x46, 0x0e, 0xf2, 0x9b, 0xb8, 0x4b, 0x1c, 0xbf, 0xca, 0x1a, + 0x93, 0xa1, 0x8e, 0x5c, 0x88, 0x44, 0xea, 0xe4, 0x9b, 0xd8, + 0x73, 0xf4, 0x36, 0x93, 0xb8, 0x90, 0xc8, 0x10, 0x46, 0x6e, + 0x1d, 0x51, 0x0c, 0x57, 0x3e, 0xbb, 0x69, 0xc1, 0x0f, 0x4a, + 0xf2, 0x85, 0xd0, 0x4e, 0xdd, 0x98, 0x08, 0xe5, 0x48, 0xae, + 0xbf, 0x61, 0xb6, 0xea, 0x46, 0xb0, 0x45, 0x97, 0x49, 0xd5, + 0x71, 0x42, 0x80, 0xbc, 0x19, 0xda, 0x8c, 0x3e, 0x5c, 0x5a, + 0x58, 0xb1, 0xe4, 0x28, 0x6a, 0x70, 0x6e, 0xe3, 0x1d, 0x4b, + 0xf0, 0x4c, 0x92, 0x9e, 0x43, 0xdf, 0xbd, 0xe0, 0x56, 0x8d, + 0x5d, 0x3f, 0x51, 0xa5, 0x3b, 0x74, 0x11, 0x92, 0x64, 0xbb, + 0xc8, 0x92, 0x95, 0xee, 0xe7, 0x7f, 0xed, 0xa5, 0x2c, 0x8d, + 0xb7, 0x55, 0x00, 0xf7, 0x70, 0x31, 0x7b, 0x2f, 0xc3, 0xe5, + 0x41, 0x66, 0xe9, 0x1e, 0xdc, 0x83, 0xe5, 0x83, 0x62, 0xc0, + 0x1b, 0xc5, 0xfb, 0x81, 0x3e, 0xf8, 0x70, 0xf0, 0xf1, 0xc3, + 0xe8, 0x7c, 0xf2, 0xab, 0xcc, 0x20, 0xe0, 0x3f, 0x93, 0x36, + 0xd0, 0x0f, 0xb4, 0xcf, 0x56, 0x50, 0x0e, 0x64, 0x1e, 0x85, + 0xc9, 0x87, 0x5d, 0x76, 0x18, 0xb0, 0x9e, 0x1f, 0xc2, 0x1f, + 0xd5, 0x25, 0xd4, 0xe6, 0x91, 0xc1, 0x5d, 0x70, 0x75, 0xac, + 0x2b, 0x9e, 0xd8, 0xc6, 0xd9, 0x63, 0x20, 0x5f, 0x36, 0xde, + 0xd6, 0x50, 0x23, 0xf7, 0x89, 0x5d, 0x69, 0x01, 0xf6, 0x25, + 0x45, 0xfc, 0xdb, 0x10, 0xe9, 0x51, 0xc1, 0x86, 0xbb, 0xb8, + 0x88, 0x65, 0x2e, 0xb7, 0xf0, 0x4e, 0xcf, 0xea, 0xa5, 0x62, + 0x81, 0x54, 0x2d, 0xaf, 0x1a, 0xc7, 0xd4, 0x7e, 0x74, 0x57, + 0xd5, 0x03, 0x91, 0x98, 0x0d, 0xa4, 0xbf, 0xc2, 0xc5, 0x86, + 0xa2, 0xf5, 0xd1, 0x8d, 0xaa, 0x68, 0x91, 0xc7, 0x87, 0xa8, + 0xfc, 0xef, 0xf0, 0x12, 0xea, 0x55, 0x77, 0xc7, 0x80, 0xc7, + 0x02, 0x67, 0xe9, 0x16, 0xfe, 0x9e, 0xe8, 0x27, 0x52, 0xdd, + 0xb9, 0xae, 0xfe, 0x33, 0xb9, 0x58, 0x95, 0xfe, 0x39, 0x35, + 0xd4, 0x64, 0xc7, 0x00, 0xcb, 0xac, 0xf0, 0x03, 0x73, 0xc3, + 0x65, 0x5e, 0xe6, 0xd1, 0xb6, 0x43, 0x0a, 0x1d, 0x1c, 0x41, + 0x4a, 0x2f, 0x65, 0x63, 0xce, 0x2e, 0x4e, 0x4a, 0x2a, 0x49, + 0xd1, 0x08, 0x4b, 0x97, 0x7f, 0xbc, 0x7b, 0x24, 0xa3, 0x7b, + 0x57, 0x2c, 0x91, 0x48, 0x59, 0xfa, 0xd6, 0xc4, 0x98, 0xf5, + 0x35, 0xc3, 0x54, 0xc5, 0xdd, 0x9e, 0x08, 0x4f, 0xc6, 0x5b, + 0xa0, 0xe4, 0xba, 0x7f, 0x3e, 0x9b, 0x99, 0x82, 0xbd, 0xff, + 0x1c, 0x6e, 0xd2, 0x28, 0x0e, 0xed, 0xcd, 0xa6, 0xd2, 0xe4, + 0x3f, 0x9d, 0xe9, 0x13, 0x55, 0x7c, 0x10, 0x9e, 0x22, 0xdd, + 0xd1, 0x53, 0x66, 0x45, 0x3a, 0xa7, 0xf8, 0xce, 0xbe, 0x48, + 0xcd, 0x2e, 0x87, 0xf4, 0x9d, 0x7d, 0xeb, 0xc5, 0x15, 0xa6, + 0x36, 0x5d, 0x4f, 0x5f, 0xcd, 0xb2, 0x97, 0x1d, 0x2d, 0x0c, + 0xab, 0x5e, 0xcb, 0x2e, 0xd4, 0xd1, 0x78, 0xa1, 0x6b, 0xc2, + 0x9b, 0xe0, 0x85, 0xed, 0x7a, 0x5b, 0x56, 0xba, 0x54, 0x08, + 0x5a, 0xac, 0x00, 0x64, 0x15, 0xc9, 0x8f, 0x6c, 0xe6, 0x2f, + 0xc6, 0x65, 0x33, 0x9f, 0x39, 0x48, 0x54, 0xbd, 0xa7, 0x5a, + 0xa3, 0xa9, 0xa9, 0xe9, 0xd7, 0xda, 0x94, 0xb3, 0xf1, 0xf3, + 0x2f, 0xab, 0x0a, 0xf6, 0xec, 0x7e, 0x44, 0x07, 0x3b, 0x94, + 0xed, 0xe8, 0xc1, 0x1d, 0xa9, 0x7a, 0x52, 0x5d, 0x77, 0x40, + 0xb4, 0x0c, 0xdd, 0x0d, 0xeb, 0x04, 0x8e, 0xac, 0x15, 0x1e, + 0xf2, 0xf5, 0x8a, 0x6d, 0xc8, 0xec, 0x5c, 0x01, 0x32, 0x8c, + 0x22, 0x37, 0x59, 0x46, 0x80, 0x27, 0x4c, 0xcf, 0xd9, 0x78, + 0xb2, 0xf6, 0x7e, 0xdf, 0x82, 0x70, 0x57, 0xb9, 0x0d, 0xf0, + 0x64, 0xb2, 0x8a, 0x1a, 0xb7, 0xfc, 0xb8, 0xbe, 0xc2, 0xed, + 0x0e, 0x41, 0x35, 0x2c, 0x6e, 0x97, 0xd4, 0x18, 0xf9, 0x77, + 0x41, 0xf1, 0xc6, 0x3b, 0x12, 0x36, 0x1e, 0x2a, 0x99, 0x5d, + 0x71, 0xa4, 0xb6, 0x9f, 0xeb, 0x88, 0x24, 0x12, 0x4d, 0x8b, + 0x57, 0xaf, 0x64, 0xf5, 0x01, 0xcf, 0xc6, 0xaf, 0x81, 0x89, + 0x27, 0x0c, 0xf9, 0x21, 0x31, 0xfd, 0xf9, 0x73, 0x19, 0xae, + 0x66, 0xe0, 0x33, 0x6a, 0xc0, 0x20, 0xfd, 0x80, 0x7f, 0xb7, + 0x23, 0x6a, 0x2f, 0x63, 0x0b, 0x69, 0x69, 0xef, 0xe8, 0x79, + 0xe8, 0x3e, 0x12, 0xcd, 0xc2, 0x74, 0xd7, 0xa5, 0x1a, 0xa0, + 0x9c, 0x9e, 0xe6, 0x00, 0x91, 0xfc, 0x10, 0x7d, 0x69, 0xdd, + 0x80, 0x3c, 0x47, 0x96, 0xb3, 0xc7, 0x71, 0x21, 0xff, 0x15, + 0x32, 0xc9, 0x72, 0xb9, 0x7d, 0x0d, 0x06, 0x91, 0xe2, 0x6f, + 0xe2, 0x3d, 0x55, 0x34, 0x80, 0x13, 0xa1, 0x6d, 0x52, 0x52, + 0x8a, 0xb1, 0x83, 0x4c, 0x0f, 0x67, 0xcc, 0x04, 0xd4, 0x76, + 0xdf, 0xfa, 0x58, 0xd1, 0xb5, 0xf9, 0x4c, 0x37, 0x73, 0xde, + 0x47, 0xc8, 0x4b, 0xa4, 0x5c, 0x58, 0xff, 0xbe, 0xd0, 0xf4, + 0x1b, 0xe1, 0x40, 0xc1, 0x6b, 0x22, 0x25, 0xed, 0x3c, 0xc6, + 0xbb, 0x8c, 0xfc, 0x5b, 0xe4, 0xfe, 0xa4, 0xf7, 0xd4, 0x17, + 0xad, 0xf9, 0x52, 0x0c, 0x36, 0xdb, 0x05, 0x0e, 0x0e, 0x90, + 0x13, 0x6d, 0x99, 0x73, 0xc7, 0x60, 0xbe, 0x50, 0x92, 0x8a, + 0x52, 0xeb, 0xf2, 0x48, 0x1c, 0xd6, 0xd6, 0x36, 0x5c, 0x06, + 0xe6, 0x21, 0x10, 0x93, 0x40, 0xbe, 0x49, 0x99, 0x53, 0x40, + 0xe1, 0xfa, 0xfc, 0xbd, 0xc5, 0xc8, 0xcc, 0xd0, 0xf6, 0x23, + 0xb4, 0x3e, 0xe7, 0xae, 0x8f, 0xcc, 0x24, 0x51, 0x31, 0xaf, + 0x9d, 0x51, 0x0f, 0xb7, 0xa4, 0xbc, 0x42, 0x2b, 0x48, 0x0d, + 0x6d, 0x19, 0xf8, 0x11, 0x62, 0x1f, 0xc6, 0xe8, 0x83, 0x7f, + 0x77, 0x10, 0x59, 0xc9, 0x58, 0xac, 0xf2, 0x1b, 0xb1, 0xdc, + 0x35, 0xb8, 0x66, 0x8a, 0x74, 0x74, 0x73, 0x0d, 0x63, 0xe2, + 0x70, 0x55, 0x3c, 0x3d, 0x9f, 0x28, 0xaf, 0xe3, 0xb2, 0x4a, + 0x5a, 0xb8, 0x56, 0x82, 0xc4, 0x8c, 0xeb, 0x46, 0x5a, 0x99, + 0x77, 0xdf, 0xd0, 0x0d, 0xec, 0xbd, 0xd1, 0x76, 0x4b, 0x0e, + 0x17, 0x53, 0xd1, 0xbb, 0x64, 0xb8, 0xf5, 0xe9, 0xad, 0x1d, + 0x0d, 0x1f, 0xd7, 0x28, 0x7b, 0xe8, 0xc6, 0x2e, 0x65, 0xc2, + 0x91, 0x9d, 0x0c, 0xaf, 0x84, 0x86, 0xfc, 0xd4, 0xc2, 0x5b, + 0x11, 0xf3, 0x82, 0x92, 0x99, 0x99, 0x0b, 0xd5, 0xe8, 0x43, + 0x7a, 0x74, 0x3c, 0xba, 0xe8, 0xd9, 0x98, 0x56, 0xa4, 0x0f, + 0xab, 0x02, 0x2b, 0xfe, 0x47, 0xe9, 0xbc, 0x53, 0x09, 0x38, + 0xcb, 0x4b, 0xc0, 0xe1, 0x00, 0x69, 0xb8, 0x2d, 0x27, 0x1c, + 0xaa, 0xe5, 0x39, 0x11, 0x68, 0xa0, 0x75, 0x95, 0x9f, 0x72, + 0x13, 0x89, 0x60, 0x6e, 0xc9, 0xe0, 0x1d, 0x69, 0xd3, 0xa0, + 0xbe, 0x36, 0xb7, 0xa6, 0xda, 0x57, 0x33, 0xef, 0x70, 0x88, + 0x0e, 0x37, 0x78, 0x1b, 0x7e, 0x8e, 0xb9, 0xe9, 0x33, 0x62, + 0xd0, 0x90, 0xfa, 0x5c, 0xd7, 0xae, 0x47, 0xb3, 0x85, 0x21, + 0x68, 0x5a, 0x69, 0x0b, 0x73, 0x58, 0xd2, 0x85, 0x77, 0x6f, + 0xe9, 0x56, 0xda, 0xb2, 0x4c, 0xd5, 0xbd, 0xeb, 0xa8, 0x82, + 0x61, 0x8a, 0x2f, 0x61, 0xe5, 0xec, 0x12, 0x07, 0xb1, 0xed, + 0x59, 0x90, 0xe9, 0x69, 0x90, 0x95, 0x89, 0x3e, 0xe1, 0x41, + 0x45, 0x6d, 0x94, 0x41, 0x44, 0xcb, 0xf2, 0x13, 0x53, 0x5d, + 0x7a, 0x3b, 0x0d, 0x43, 0xa4, 0xc4, 0x21, 0x9a, 0x05, 0x56, + 0xbc, 0x26, 0x94, 0x19, 0x03, 0x51, 0x23, 0x55, 0xbf, 0xd1, + 0x3d, 0x68, 0x38, 0x30, 0x5a, 0x5e, 0x83, 0x52, 0xf6, 0xb1, + 0xa6, 0x33, 0xd3, 0x32, 0x16, 0x73, 0xa4, 0x35, 0x30, 0x0f, + 0xe9, 0xd4, 0x67, 0x2a, 0xe5, 0x23, 0x32, 0x25, 0x41, 0x8c, + 0x8c, 0x00, 0xe8, 0xf4, 0x61, 0xb6, 0x5f, 0x1d, 0xbf, 0xa2, + 0x8d, 0x50, 0xd2, 0xce, 0x21, 0x8d, 0x21, 0x79, 0x8e, 0xbb, + 0xb4, 0xf1, 0x45, 0x1d, 0x99, 0xa3, 0xe9, 0xa5, 0x35, 0x98, + 0x4d, 0x4d, 0x7d, 0x36, 0xce, 0xbb, 0x15, 0x7c, 0xb1, 0xdd, + 0x18, 0x1e, 0x96, 0x4a, 0x85, 0xec, 0x92, 0x6d, 0x8b, 0xb9, + 0x0e, 0xb3, 0x3e, 0x07, 0x2c, 0x49, 0x72, 0x3b, 0x96, 0x25, + 0x38, 0x98, 0x4d, 0xe6, 0x63, 0xcd, 0x2c, 0x72, 0x43, 0x60, + 0x89, 0xce, 0xc3, 0x60, 0x09, 0x1c, 0x78, 0x7f, 0x56, 0xc8, + 0x6d, 0xb2, 0x62, 0x7e, 0x9a, 0xea, 0xb8, 0xf4, 0xae, 0x51, + 0xb5, 0x9f, 0x8f, 0x05, 0x7d, 0x97, 0xb9, 0xa1, 0x34, 0xdd, + 0xce, 0x95, 0x76, 0x15, 0xd5, 0x68, 0x2d, 0xfb, 0x47, 0x53, + 0x75, 0x60, 0x8e, 0xae, 0x45, 0x37, 0xd9, 0xa4, 0xc3, 0x6e, + 0x04, 0xaf, 0x17, 0xf8, 0xda, 0x23, 0x7f, 0xfc, 0xb2, 0xf4, + 0x0e, 0xf2, 0xf4, 0xd4, 0xc6, 0xd4, 0xac, 0xd1, 0x5c, 0x74, + 0xae, 0xa5, 0xf3, 0xe8, 0xe2, 0x65, 0x5e, 0x61, 0xf3, 0x74, + 0x13, 0x9a, 0xc3, 0xcc, 0x63, 0xf2, 0xa8, 0x80, 0x6a, 0x2d, + 0xbf, 0x14, 0xd2, 0x44, 0x36, 0x1c, 0xe1, 0xa6, 0xc6, 0xd0, + 0x44, 0xb6, 0x9c, 0x06, 0x04, 0x87, 0x1a, 0x3b, 0xf4, 0x93, + 0xc2, 0x5b, 0xe8, 0xa8, 0xc5, 0xe0, 0x09, 0x5d, 0x3a, 0xfc, + 0x8f, 0x85, 0x94, 0x9b, 0x4f, 0x00, 0xa1, 0x4b, 0xa7, 0xe0, + 0xb4, 0x90, 0x6e, 0xf5, 0x24, 0x54, 0x89, 0x75, 0x40, 0xec, + 0x67, 0x9c, 0x31, 0xad, 0x57, 0x4b, 0x90, 0xdc, 0x96, 0x3e, + 0x29, 0xbc, 0x83, 0x37, 0xda, 0xd8, 0xd5, 0x3d, 0x4a, 0x6c, + 0xc7, 0x8c, 0xbf, 0x1a, 0x71, 0x57, 0x2b, 0xe9, 0xcf, 0xc7, + 0x77, 0x82, 0xcd, 0x39, 0xef, 0xe8, 0xd6, 0x4a, 0xc7, 0x54, + 0x97, 0x24, 0x4e, 0xcb, 0x57, 0xe2, 0x7b, 0xa0, 0x24, 0x15, + 0x95, 0x80, 0x21, 0xee, 0x25, 0xc4, 0x7b, 0xb9, 0x84, 0xe3, + 0xb8, 0x9d, 0xdc, 0x2d, 0x1c, 0xc7, 0xec, 0x54, 0x78, 0xb4, + 0x6a, 0xa6, 0xa8, 0x74, 0x82, 0xb8, 0x2a, 0x3a, 0x88, 0x5e, + 0xf5, 0x0f, 0x4b, 0xae, 0xfa, 0x95, 0x5a, 0x0a, 0x7a, 0x0e, + 0xb7, 0xd6, 0x2e, 0xd4, 0x4b, 0xe0, 0xff, 0xb0, 0x91, 0x38, + 0x89, 0xf3, 0x5c, 0x44, 0xde, 0xcb, 0xd3, 0xc7, 0x41, 0x82, + 0x89, 0x40, 0xe6, 0x00, 0x85, 0xe6, 0x49, 0x69, 0x42, 0xa4, + 0x0d, 0xfb, 0x39, 0xd7, 0x46, 0xe2, 0x1c, 0xd7, 0x43, 0x1b, + 0x08, 0x8c, 0xc3, 0xc2, 0x21, 0xf1, 0x62, 0x23, 0x63, 0xf8, + 0x17, 0xe4, 0x43, 0xe8, 0xa2, 0xf5, 0x5d, 0x27, 0x2d, 0xf2, + 0xc1, 0xf3, 0x25, 0x0d, 0x4b, 0x36, 0x6d, 0x7b, 0x31, 0x1a, + 0x9c, 0xb5, 0x8e, 0xbc, 0xb2, 0x01, 0x4e, 0x8c, 0xb1, 0x62, + 0x67, 0xae, 0x8c, 0x85, 0xcd, 0xc9, 0x19, 0xf0, 0xe0, 0x29, + 0x63, 0xdd, 0x85, 0x36, 0xe6, 0xe3, 0xaa, 0x19, 0x1d, 0xc2, + 0x82, 0xc4, 0xc1, 0x98, 0x38, 0x41, 0x5f, 0x24, 0x75, 0x84, + 0xc6, 0xa5, 0xcc, 0x9c, 0x70, 0x4f, 0xdc, 0x4a, 0x35, 0x3a, + 0x40, 0x25, 0x7b, 0x6a, 0xf5, 0xd6, 0xf6, 0x1f, 0x8a, 0xda, + 0x3a, 0x87, 0xdf, 0xc9, 0x2e, 0x2d, 0x9e, 0x47, 0x14, 0xc5, + 0x2a, 0x43, 0x7f, 0x53, 0x4a, 0x1c, 0x6d, 0xea, 0x9a, 0x16, + 0x24, 0x19, 0x63, 0x83, 0xfc, 0x52, 0xc8, 0xde, 0xe2, 0xf7, + 0x14, 0xfe, 0x83, 0x62, 0xfb, 0x2b, 0x0f, 0x74, 0x1c, 0x05, + 0x69, 0xc1, 0x7e, 0x16, 0x97, 0xa2, 0xb7, 0x16, 0xfe, 0xa8, + 0x5a, 0x70, 0xd2, 0x4a, 0x88, 0xcf, 0x86, 0x6e, 0x53, 0xb5, + 0x4a, 0x44, 0x10, 0xb2, 0xb8, 0xe5, 0x44, 0x90, 0x17, 0xd8, + 0x8e, 0x72, 0x67, 0x2f, 0x63, 0x7a, 0x3c, 0xf2, 0xed, 0xac, + 0x64, 0xdb, 0x28, 0x1f, 0x4a, 0x6f, 0x6d, 0x78, 0x76, 0x5c, + 0xd9, 0x0e, 0x9c, 0xac, 0x10, 0x1d, 0x34, 0xfd, 0xb4, 0x17, + 0x6e, 0xd6, 0x55, 0xc2, 0x5b, 0x9f, 0x4f, 0xa2, 0x92, 0xa5, + 0xd9, 0xac, 0xe5, 0x1b, 0x28, 0x1f, 0x4e, 0x3f, 0x0d, 0x20, + 0x0e, 0xaa, 0x69, 0xa5, 0x8a, 0xcb, 0x36, 0x25, 0x87, 0x44, + 0x8d, 0x52, 0x32, 0x89, 0x56, 0xe5, 0x56, 0x7d, 0xc6, 0x83, + 0x3b, 0xa9, 0xc6, 0xd8, 0xac, 0x45, 0x03, 0x68, 0xb4, 0x8a, + 0x84, 0xd2, 0xd9, 0xa4, 0x70, 0x30, 0x35, 0xe9, 0x7b, 0x36, + 0xdb, 0xad, 0xa2, 0x9e, 0x25, 0xaf, 0xf5, 0xc0, 0xc9, 0x29, + 0x6d, 0xec, 0x3b, 0x3e, 0x56, 0xa1, 0xa9, 0x6d, 0x2b, 0xad, + 0xd3, 0xe8, 0x65, 0x1b, 0xd6, 0x48, 0xed, 0xdc, 0xbf, 0x9d, + 0x9c, 0xee, 0x9f, 0x7e, 0xfa, 0x78, 0x74, 0xf8, 0xf1, 0xf4, + 0xd3, 0xf1, 0xd9, 0xa7, 0x8f, 0x1f, 0x93, 0xd5, 0xf8, 0x50, + 0xf4, 0x97, 0xf4, 0xf1, 0x2c, 0x89, 0x58, 0x7a, 0xff, 0xe5, + 0xd2, 0xf8, 0x70, 0x76, 0xfc, 0x6b, 0xb1, 0x13, 0x91, 0xac, + 0xac, 0xf1, 0x82, 0x54, 0x04, 0x1c, 0xfd, 0x76, 0x70, 0x7c, + 0x70, 0xf2, 0xe9, 0xf0, 0xe3, 0xc9, 0xd1, 0xc9, 0xd9, 0xa7, + 0xd3, 0x4f, 0x47, 0x69, 0x5f, 0x0a, 0xfe, 0xc0, 0x9f, 0xf2, + 0x7d, 0xf5, 0xe5, 0x3e, 0x89, 0x59, 0x64, 0x23, 0x18, 0x0b, + 0x48, 0x37, 0x3f, 0xc2, 0x33, 0x51, 0x3d, 0xbb, 0xbb, 0x8b, + 0x40, 0xac, 0xf8, 0x50, 0x53, 0xbb, 0x57, 0xde, 0xaf, 0x3b, + 0x11, 0xdd, 0x09, 0x44, 0x81, 0x1d, 0xc5, 0x5d, 0x69, 0xbe, + 0x08, 0x34, 0x9d, 0xe0, 0xc9, 0xef, 0x4a, 0x73, 0x73, 0xef, + 0xb6, 0x5e, 0x61, 0x3d, 0x88, 0x13, 0x98, 0x85, 0x47, 0x10, + 0x2a, 0xcf, 0x0a, 0x94, 0x0d, 0x51, 0xb7, 0xb3, 0x0d, 0x5e, + 0x02, 0x90, 0xbb, 0x65, 0x01, 0xfb, 0x7f, 0xda, 0x2f, 0x66, + 0xfe, 0x4f, 0xfb, 0xc5, 0xbd, 0xd9, 0xf5, 0xd0, 0x9b, 0x4d, + 0xd4, 0xd7, 0xdc, 0xbc, 0xf4, 0xd0, 0x9b, 0x2d, 0xf5, 0x47, + 0x71, 0x76, 0x1f, 0x70, 0x10, 0xaa, 0xf2, 0xfc, 0x0c, 0x85, + 0xa0, 0x0f, 0xec, 0x50, 0x49, 0x43, 0xbd, 0xba, 0xe9, 0xec, + 0x8f, 0x05, 0x6d, 0xec, 0x76, 0xfd, 0xb6, 0xf1, 0x54, 0xd0, + 0xc6, 0xcb, 0x4b, 0xbf, 0x6d, 0x6c, 0x5a, 0xaf, 0x9b, 0xea, + 0xaf, 0xa0, 0xd0, 0xa6, 0xfd, 0x40, 0x96, 0x9f, 0xe7, 0xae, + 0xba, 0xd4, 0x1f, 0xbd, 0x76, 0x67, 0xd7, 0xb5, 0x3b, 0x61, + 0xaf, 0xdd, 0x79, 0xe9, 0xda, 0x9d, 0xe8, 0xf1, 0x99, 0x5a, + 0x1c, 0x43, 0x60, 0xaf, 0x29, 0xf9, 0xaf, 0xca, 0xfb, 0x29, + 0x92, 0xc6, 0xbf, 0x76, 0xbc, 0xee, 0x3e, 0xee, 0xca, 0x5a, + 0xb8, 0x51, 0xde, 0x6b, 0x50, 0x34, 0x77, 0x6e, 0xe0, 0xa5, + 0xac, 0x81, 0x6f, 0xca, 0xfb, 0x21, 0x94, 0xd3, 0xcd, 0x1a, + 0xa8, 0xd1, 0x93, 0xc6, 0xc0, 0x7e, 0x60, 0xf5, 0x8e, 0x0a, + 0x6d, 0x24, 0xb3, 0x59, 0xa0, 0x3a, 0x0a, 0xf3, 0xe7, 0xe6, + 0x8f, 0x7f, 0x63, 0x63, 0x34, 0x69, 0x6d, 0x7b, 0x99, 0xa1, + 0xe0, 0x4a, 0xce, 0xee, 0x82, 0x3a, 0x14, 0x29, 0x33, 0x3e, + 0x6a, 0x43, 0xa8, 0x34, 0x15, 0x0c, 0x2f, 0x49, 0x1d, 0x5f, + 0xca, 0x90, 0x82, 0x5e, 0xba, 0x63, 0x17, 0x44, 0xdc, 0x0c, + 0x68, 0xd9, 0xc7, 0xee, 0x56, 0xbd, 0x85, 0x2a, 0xb9, 0x08, + 0x14, 0xda, 0xc3, 0x77, 0x40, 0xf8, 0x84, 0x2e, 0x1c, 0x4a, + 0xea, 0x82, 0x1b, 0xd5, 0x2e, 0x0a, 0xfb, 0x12, 0x2e, 0x02, + 0x18, 0xb4, 0xb7, 0xc8, 0x0f, 0x55, 0x53, 0x15, 0x61, 0x19, + 0xec, 0xd8, 0x56, 0xb0, 0x1f, 0xc3, 0xda, 0x8d, 0xa2, 0x4a, + 0x6f, 0xc5, 0x79, 0x06, 0x8b, 0x40, 0x9f, 0xa4, 0x2a, 0xbd, + 0x23, 0x51, 0x05, 0x4b, 0xd7, 0xe6, 0xe3, 0x1b, 0xf1, 0xed, + 0x15, 0xbd, 0xfe, 0xe8, 0x60, 0xe3, 0xed, 0xe4, 0xad, 0x63, + 0x9c, 0xcf, 0x45, 0xd2, 0xd7, 0x34, 0x22, 0xb4, 0xc4, 0x1f, + 0x7f, 0x23, 0xe9, 0x8f, 0xc5, 0x84, 0x7b, 0x90, 0xd0, 0x0f, + 0x42, 0x2f, 0x8f, 0xaa, 0x29, 0xfd, 0x2c, 0xbb, 0x83, 0xd4, + 0xe0, 0x32, 0xc3, 0x55, 0x9e, 0xdb, 0x18, 0x20, 0xae, 0x82, + 0x51, 0xe8, 0xcb, 0x6c, 0x52, 0x8b, 0x61, 0x0e, 0x05, 0x57, + 0xc7, 0x68, 0x3c, 0xcd, 0xac, 0xaa, 0x99, 0x9b, 0x70, 0x21, + 0xa9, 0x7f, 0x1f, 0xc3, 0x6a, 0x6c, 0x47, 0x87, 0xf6, 0x72, + 0x69, 0x6d, 0x56, 0x36, 0x35, 0x00, 0x99, 0xaa, 0xa1, 0xc4, + 0x81, 0xc2, 0x99, 0x24, 0x55, 0xc6, 0x14, 0xa9, 0x5c, 0xe2, + 0xc2, 0xad, 0xac, 0x65, 0x87, 0x1b, 0xbe, 0x2d, 0x6c, 0xcc, + 0x82, 0x8d, 0xe1, 0xff, 0x8f, 0x8d, 0x72, 0x72, 0xc4, 0x25, + 0xae, 0xa7, 0xc4, 0x53, 0x3c, 0xe7, 0x8a, 0x95, 0x79, 0x90, + 0x17, 0x7a, 0x63, 0x31, 0x8e, 0x54, 0x49, 0xc1, 0x46, 0x3e, + 0x59, 0xf6, 0xa3, 0xed, 0x7a, 0x28, 0xd4, 0x3e, 0x63, 0x3b, + 0xfa, 0x81, 0x32, 0x12, 0x7b, 0xda, 0x21, 0x84, 0x4a, 0x29, + 0x35, 0xb4, 0xc2, 0xdb, 0xab, 0x47, 0x17, 0xaf, 0x81, 0xbd, + 0xbc, 0x07, 0x05, 0xbe, 0x35, 0xd9, 0xac, 0x91, 0x49, 0xa2, + 0xf8, 0x2d, 0xa8, 0x7c, 0x27, 0x97, 0x9a, 0x34, 0xa0, 0xaf, + 0xe0, 0x74, 0x1d, 0x74, 0xd8, 0x7f, 0x86, 0x39, 0xd3, 0xb5, + 0x9c, 0x67, 0x0d, 0x1b, 0x2f, 0x92, 0xab, 0x32, 0x9e, 0xa9, + 0x43, 0xf1, 0x70, 0x0d, 0xec, 0x8a, 0x88, 0xfa, 0xc1, 0x58, + 0x53, 0x75, 0x61, 0xf3, 0x0d, 0x3c, 0x60, 0x87, 0x95, 0x20, + 0x38, 0x37, 0xc2, 0xe3, 0xe7, 0x20, 0xd8, 0xec, 0x14, 0xc3, + 0xb7, 0x37, 0xd1, 0x7d, 0x10, 0x57, 0xd7, 0xb4, 0xd2, 0xe7, + 0x77, 0xe1, 0xad, 0x33, 0xad, 0xad, 0x60, 0x5a, 0xe9, 0x0b, + 0xa2, 0xdc, 0xe1, 0x91, 0x35, 0x2c, 0x90, 0x72, 0x68, 0xb8, + 0x50, 0x27, 0x8f, 0x3b, 0xc1, 0xe6, 0x24, 0x98, 0x9c, 0xda, + 0x68, 0x7a, 0xc1, 0x6a, 0x05, 0x0f, 0xc8, 0x7a, 0x26, 0x3d, + 0xa4, 0xab, 0x88, 0x6b, 0xfc, 0x8c, 0x6c, 0x9a, 0xe2, 0xe6, + 0x15, 0x39, 0x82, 0xa5, 0xc8, 0x79, 0xd8, 0x21, 0x0c, 0x01, + 0x21, 0x26, 0xe3, 0x68, 0xe0, 0x7d, 0xa5, 0x52, 0x17, 0x96, + 0x03, 0x71, 0x36, 0x30, 0xd9, 0x06, 0xcf, 0xcc, 0xb4, 0xab, + 0xb3, 0x79, 0xee, 0xc4, 0x21, 0x3d, 0xa5, 0xa4, 0x1b, 0x79, + 0xa0, 0xcd, 0xe6, 0xf3, 0xb4, 0x97, 0x47, 0xf9, 0x5e, 0x06, + 0x9b, 0x4d, 0x8b, 0x5e, 0x0e, 0x16, 0xba, 0xae, 0x4d, 0x4d, + 0x6b, 0xaa, 0x4e, 0xc4, 0xdd, 0x92, 0x21, 0x12, 0x26, 0x2e, + 0x54, 0xb0, 0x29, 0x05, 0xa1, 0xdb, 0xcb, 0x3b, 0xc1, 0xe4, + 0x68, 0x9f, 0x88, 0x6e, 0x59, 0x75, 0x34, 0xab, 0x36, 0x0e, + 0x71, 0x72, 0xcd, 0xa6, 0x41, 0xc1, 0xde, 0xff, 0xca, 0x9e, + 0x42, 0xe2, 0x7c, 0xbb, 0xeb, 0xe8, 0x90, 0xe6, 0x79, 0x10, + 0x3c, 0x40, 0xb5, 0x1f, 0xb9, 0x4d, 0x97, 0x6e, 0x1f, 0x76, + 0x29, 0x14, 0x54, 0x41, 0x49, 0x6a, 0xc8, 0x3b, 0xc2, 0x95, + 0x6a, 0xe9, 0xe3, 0x73, 0xa4, 0xe7, 0xb4, 0x76, 0x9c, 0xb9, + 0x98, 0x09, 0x5b, 0x85, 0xf3, 0xc4, 0x2f, 0x85, 0xc5, 0x53, + 0xf5, 0x69, 0x5e, 0x47, 0xff, 0x62, 0x87, 0x7e, 0xa5, 0x9a, + 0xce, 0xf8, 0x50, 0x1d, 0x4a, 0x86, 0x14, 0x0d, 0xf4, 0x11, + 0x86, 0x58, 0x12, 0x25, 0x7d, 0xe8, 0x62, 0x78, 0x95, 0x2a, + 0xcc, 0xac, 0xf3, 0xc5, 0xa5, 0xc0, 0xae, 0x43, 0x70, 0xbb, + 0x5d, 0x49, 0xc9, 0xf2, 0x7b, 0x36, 0x68, 0xc2, 0xa4, 0x51, + 0xb4, 0xed, 0x63, 0x66, 0x11, 0x60, 0x10, 0x76, 0x8b, 0xa7, + 0x42, 0x10, 0xff, 0x6c, 0x73, 0x1e, 0xb0, 0x84, 0x4c, 0x59, + 0x2a, 0x72, 0xac, 0x5c, 0x7f, 0x16, 0x1c, 0xe7, 0x98, 0x39, + 0x77, 0x18, 0x40, 0x36, 0xfe, 0x8f, 0x1a, 0xaf, 0x74, 0x01, + 0x89, 0x20, 0xf9, 0x49, 0x99, 0x7a, 0xd0, 0x9a, 0xa7, 0x2f, + 0x35, 0x51, 0xfa, 0x5f, 0x02, 0x79, 0x27, 0x60, 0x46, 0x11, + 0x39, 0xe0, 0x15, 0x11, 0x59, 0x0a, 0xb0, 0x7d, 0x0b, 0x32, + 0xba, 0xc0, 0xe6, 0xb0, 0x0f, 0xc4, 0x3f, 0x30, 0x6a, 0x20, + 0x7f, 0xb3, 0xfb, 0xec, 0x11, 0x73, 0x21, 0x81, 0x57, 0xd9, + 0x16, 0x92, 0xb0, 0x7f, 0x86, 0x5e, 0x47, 0x70, 0x2b, 0xb1, + 0x90, 0x03, 0xa2, 0x38, 0x94, 0x78, 0x20, 0x6b, 0x13, 0x15, + 0x00, 0x99, 0x7c, 0x57, 0xcf, 0xa5, 0x27, 0xec, 0x8c, 0xd9, + 0x3b, 0xc1, 0xdd, 0xb3, 0x89, 0x61, 0x4a, 0xef, 0xa4, 0x3a, + 0x97, 0x39, 0xa5, 0x57, 0xa0, 0x9e, 0x16, 0x7b, 0xa1, 0x57, + 0x80, 0x1f, 0x2e, 0x8c, 0x1c, 0xc6, 0xad, 0xbd, 0xad, 0x82, + 0x50, 0xd6, 0x35, 0x63, 0x31, 0xd1, 0x72, 0xac, 0x85, 0x02, + 0x43, 0xe4, 0xa2, 0x34, 0x5d, 0x7a, 0x2d, 0xbb, 0x40, 0x30, + 0xaa, 0x66, 0xa0, 0x90, 0x79, 0xee, 0x43, 0x12, 0x0d, 0xbc, + 0x60, 0x29, 0x21, 0x87, 0x68, 0x88, 0x3c, 0x2a, 0x4f, 0x85, + 0x10, 0x1c, 0xb9, 0xf3, 0xe1, 0x76, 0xd7, 0x35, 0x18, 0xa1, + 0xd3, 0x8d, 0xe9, 0x66, 0x3a, 0xb0, 0xb4, 0xaf, 0xda, 0x40, + 0x74, 0x48, 0xc5, 0xd0, 0x44, 0x40, 0x41, 0x38, 0x15, 0xbf, + 0x35, 0x08, 0x05, 0x81, 0xd4, 0x38, 0x23, 0x48, 0x0e, 0x11, + 0xba, 0x05, 0x41, 0x4e, 0xa3, 0x3d, 0x64, 0x11, 0x34, 0x7e, + 0x6b, 0xac, 0xcf, 0x62, 0x82, 0x05, 0xce, 0xa8, 0x84, 0x9a, + 0x13, 0x34, 0x89, 0x7b, 0x81, 0xd2, 0xd3, 0xfc, 0x26, 0x5e, + 0xca, 0xa0, 0xf0, 0x44, 0x32, 0xeb, 0x05, 0x52, 0x52, 0x1a, + 0x92, 0x62, 0xfa, 0x75, 0xc2, 0xca, 0x3f, 0x4c, 0x0b, 0x12, + 0xde, 0x6e, 0xda, 0x88, 0xd3, 0x25, 0xe2, 0x39, 0x8e, 0x01, + 0xbb, 0x88, 0x52, 0x94, 0xb3, 0x03, 0x9b, 0x23, 0x0e, 0xb3, + 0x47, 0x92, 0xc3, 0x23, 0xb1, 0xb3, 0x69, 0x03, 0xad, 0x03, + 0x1b, 0x53, 0x24, 0x98, 0x81, 0x39, 0xac, 0xd8, 0x56, 0x99, + 0xcb, 0x6b, 0x5a, 0x5c, 0xc1, 0xe5, 0xc5, 0x5d, 0x55, 0x1a, + 0x6d, 0xe6, 0x6c, 0x91, 0x1b, 0x29, 0x7e, 0x63, 0xcb, 0x34, + 0x1d, 0xe6, 0x5b, 0xd1, 0x33, 0x05, 0x4e, 0x8d, 0xb1, 0x57, + 0xa2, 0xe9, 0xac, 0xf1, 0xd6, 0xc4, 0xf1, 0xe3, 0xa9, 0xc2, + 0xc3, 0x7c, 0x2a, 0x22, 0x87, 0x13, 0xb2, 0xec, 0x95, 0x04, + 0xc4, 0x62, 0x84, 0x43, 0x0e, 0x13, 0xb9, 0xf8, 0x75, 0xbb, + 0xc8, 0x75, 0xa3, 0x74, 0x46, 0x11, 0xf0, 0x13, 0x4a, 0xa2, + 0x51, 0x75, 0x07, 0x38, 0xcb, 0xcd, 0x2b, 0x53, 0x4b, 0x6e, + 0x76, 0xa9, 0x47, 0xa1, 0x08, 0xcf, 0x5c, 0x35, 0x86, 0xfc, + 0x03, 0x1d, 0x86, 0x5a, 0xa2, 0xc8, 0xaf, 0xad, 0x10, 0x51, + 0x36, 0x04, 0x83, 0x89, 0x01, 0x7f, 0x6d, 0x45, 0x66, 0x67, + 0x3f, 0x31, 0xb0, 0xab, 0xed, 0xe0, 0x63, 0x58, 0x9b, 0x3d, + 0x67, 0xa6, 0x17, 0xac, 0xf4, 0x4e, 0xc3, 0x55, 0x35, 0x02, + 0xdf, 0x0e, 0x89, 0x99, 0xbe, 0x74, 0x55, 0x3f, 0xe5, 0x56, + 0x15, 0xd7, 0x52, 0x48, 0xb5, 0xef, 0xba, 0xac, 0x4f, 0xae, + 0x43, 0x79, 0xfb, 0x0b, 0xf9, 0xd1, 0x88, 0x80, 0x07, 0xfc, + 0x15, 0xa5, 0x30, 0x4e, 0x7e, 0x35, 0x22, 0x71, 0x0b, 0x15, + 0x65, 0x7c, 0x03, 0x4c, 0x4c, 0xd2, 0xe9, 0x4f, 0x9e, 0x48, + 0x71, 0xdd, 0xcd, 0xb3, 0xc7, 0x65, 0x46, 0x89, 0x94, 0x39, + 0x08, 0xf1, 0xc3, 0xbd, 0xb8, 0x9e, 0x32, 0x5c, 0x91, 0xe6, + 0xff, 0xa3, 0xb1, 0x1b, 0xe9, 0xef, 0x2c, 0xe0, 0x64, 0xda, + 0xfe, 0x8e, 0x01, 0x8f, 0x14, 0xeb, 0xfc, 0xc6, 0xd4, 0xac, + 0xb9, 0xa6, 0x5b, 0xf3, 0xd1, 0x57, 0x4d, 0x4c, 0xfd, 0x30, + 0x83, 0x87, 0x0b, 0x4a, 0xee, 0x85, 0xc7, 0xc0, 0x27, 0x7a, + 0xc9, 0x2b, 0x70, 0xf9, 0xc7, 0xae, 0xe9, 0xa5, 0x82, 0xd0, + 0x06, 0x50, 0x4c, 0x04, 0x70, 0x14, 0x77, 0x2d, 0x00, 0xec, + 0xf1, 0xf5, 0xff, 0xdf, 0x5c, 0xbb, 0x14, 0x8e, 0x71, 0xf4, + 0xa9, 0x9c, 0x42, 0xe5, 0x6e, 0x42, 0xec, 0x6b, 0xb1, 0x0f, + 0x55, 0xcc, 0x36, 0xe8, 0xfa, 0x5a, 0x95, 0x6e, 0x12, 0xed, + 0x11, 0xa3, 0x28, 0x94, 0xed, 0x2a, 0x1a, 0x08, 0x95, 0xed, + 0xaa, 0xa4, 0x86, 0xdc, 0x86, 0x62, 0xaf, 0xc7, 0x49, 0xc5, + 0x5c, 0x70, 0xfa, 0x5e, 0xad, 0x99, 0x05, 0xd7, 0x14, 0x82, + 0x82, 0xb5, 0xeb, 0x4e, 0x41, 0xc1, 0x6d, 0xcd, 0x2d, 0x8c, + 0xdd, 0xe4, 0xa0, 0xd8, 0x6e, 0x22, 0xbf, 0x06, 0x29, 0x30, + 0xed, 0x3c, 0x0c, 0x88, 0x1a, 0x5f, 0xba, 0x0a, 0x07, 0x39, + 0x04, 0xeb, 0xac, 0x8e, 0xdc, 0x3a, 0x6c, 0xd2, 0x77, 0x40, + 0x26, 0x15, 0x53, 0xfa, 0x21, 0x9d, 0xd1, 0xb9, 0x3e, 0xbb, + 0x68, 0x3d, 0x9f, 0xa6, 0x36, 0xc1, 0x98, 0xed, 0x8b, 0xdc, + 0xfb, 0x04, 0xa7, 0x24, 0x94, 0x5e, 0xb5, 0xd4, 0xf1, 0x68, + 0x9a, 0x01, 0x5c, 0xd3, 0xeb, 0x56, 0x92, 0xf4, 0xa9, 0xea, + 0x01, 0x61, 0x3a, 0x5c, 0xa0, 0x08, 0xb1, 0xac, 0xf2, 0x61, + 0xb1, 0xb6, 0x53, 0xba, 0xe5, 0xaf, 0x04, 0x4d, 0x79, 0x73, + 0x55, 0x75, 0x5b, 0x1b, 0xce, 0xbe, 0xe6, 0x0c, 0xaf, 0x4e, + 0xf0, 0x5c, 0xd1, 0xc1, 0xab, 0xf1, 0x0c, 0xde, 0x5b, 0xaf, + 0x6e, 0x52, 0x10, 0x6a, 0x6a, 0x55, 0xbd, 0xf7, 0x82, 0x30, + 0xd8, 0xdc, 0xef, 0xbc, 0x2a, 0xbc, 0xee, 0x85, 0x7e, 0x3e, + 0x1a, 0x66, 0x83, 0xcb, 0x6e, 0x5a, 0x59, 0x86, 0x30, 0x29, + 0x51, 0x02, 0x97, 0x8f, 0x80, 0x0e, 0xd2, 0x24, 0x69, 0x38, + 0xb8, 0x16, 0xd9, 0xdf, 0xb3, 0x3f, 0x08, 0x2b, 0x5f, 0xbc, + 0x2d, 0xa3, 0xb4, 0x34, 0x6f, 0x6e, 0x48, 0xd8, 0x31, 0x45, + 0x36, 0x4c, 0x57, 0x8f, 0xa3, 0x5c, 0xe0, 0x8f, 0x5b, 0xec, + 0x14, 0xcb, 0x7b, 0xb8, 0xf6, 0xe0, 0xd8, 0x2a, 0xf8, 0xa9, + 0xd6, 0x51, 0xfc, 0xa5, 0x78, 0x0b, 0x17, 0xbf, 0xc8, 0x0a, + 0x23, 0x2f, 0xdd, 0xc2, 0xd4, 0x20, 0x40, 0x2a, 0x24, 0xf3, + 0x4e, 0x07, 0x21, 0xab, 0x1e, 0x6f, 0xcb, 0x74, 0xa9, 0xc2, + 0x97, 0xdb, 0x15, 0x7d, 0xb3, 0x4d, 0xc0, 0x61, 0x0b, 0x14, + 0x80, 0xfa, 0x77, 0xe7, 0x2b, 0xa8, 0x3e, 0xc4, 0x50, 0xa5, + 0xe0, 0x8e, 0x0a, 0x16, 0x45, 0xad, 0xf8, 0xdd, 0x99, 0xfa, + 0x48, 0x33, 0x04, 0x5a, 0x87, 0xb2, 0xa9, 0xbe, 0x1f, 0x6c, + 0x31, 0x3a, 0x5c, 0x71, 0x1f, 0x48, 0x93, 0x07, 0xd4, 0x87, + 0x2d, 0x2d, 0x2e, 0x1f, 0x15, 0xbb, 0x8b, 0x2c, 0xf6, 0xa1, + 0x22, 0x49, 0x31, 0x34, 0x6d, 0x0d, 0xd0, 0x81, 0x08, 0x92, + 0x93, 0x0c, 0x25, 0xf2, 0xf8, 0xe0, 0x80, 0xbb, 0xda, 0x4c, + 0x46, 0xd2, 0x02, 0xb8, 0xa2, 0xd9, 0xe0, 0xc9, 0xe7, 0x70, + 0x46, 0xc8, 0x23, 0x1f, 0xf9, 0xd8, 0x42, 0xaf, 0xef, 0xc9, + 0x55, 0x9d, 0xb8, 0x70, 0xff, 0x0c, 0x8e, 0xea, 0x7d, 0xf4, + 0xa4, 0xd0, 0x4d, 0x5d, 0x24, 0xdc, 0xdc, 0x4f, 0x3b, 0x42, + 0x08, 0x7f, 0x4b, 0xc0, 0x24, 0xce, 0x4b, 0x7f, 0x77, 0x37, + 0xe7, 0xa5, 0x3b, 0x22, 0xa1, 0x59, 0xbd, 0x8f, 0x0e, 0xc5, + 0x7d, 0xa4, 0x64, 0xd5, 0xe4, 0x90, 0xfb, 0xd2, 0xd2, 0xdc, + 0x38, 0x5a, 0x6e, 0x23, 0x52, 0xd9, 0x62, 0x95, 0xc2, 0x84, + 0xa0, 0x90, 0xfe, 0x4b, 0xbf, 0xb6, 0x2a, 0xf4, 0xc2, 0x3a, + 0x54, 0x06, 0x31, 0xa7, 0x05, 0x75, 0x09, 0x11, 0x80, 0x11, + 0x0b, 0x1d, 0x2d, 0x06, 0x4c, 0x45, 0xe6, 0x99, 0x9e, 0x4b, + 0xba, 0x29, 0x6f, 0x5d, 0x37, 0x8c, 0x51, 0xf5, 0x02, 0x31, + 0xe6, 0xe2, 0x25, 0x40, 0x41, 0x87, 0x86, 0xbb, 0xf2, 0x31, + 0x20, 0x47, 0x88, 0x2f, 0x8c, 0x2d, 0xe0, 0xde, 0x4a, 0xfc, + 0x71, 0x92, 0x2c, 0x82, 0x45, 0x4c, 0xdd, 0xc6, 0x1d, 0xe7, + 0xda, 0xf8, 0xa2, 0x57, 0x0f, 0xed, 0x98, 0x4d, 0x08, 0x89, + 0xaa, 0x1a, 0xb1, 0x8d, 0xb1, 0x96, 0x94, 0x2f, 0x36, 0x89, + 0xae, 0x74, 0x83, 0x66, 0x43, 0x2a, 0x1f, 0x48, 0x8b, 0xf7, + 0x39, 0xd7, 0x7f, 0xc0, 0xa8, 0xf0, 0xd5, 0x83, 0x38, 0xa1, + 0x29, 0x1f, 0xfd, 0x07, 0x25, 0xa9, 0xf0, 0xa3, 0xfa, 0x6c, + 0xac, 0xa3, 0x9a, 0xa3, 0x9b, 0x45, 0x85, 0x26, 0x03, 0xa0, + 0x39, 0xde, 0x26, 0x86, 0x64, 0xcf, 0x79, 0x38, 0x17, 0x1e, + 0xc1, 0xa5, 0xe1, 0xc3, 0xaa, 0xbb, 0x06, 0xc1, 0x36, 0x66, + 0x4d, 0xaf, 0xf8, 0x67, 0x8b, 0xe3, 0x0b, 0xbf, 0xf7, 0xfa, + 0x34, 0xb7, 0xd9, 0x20, 0xfb, 0xdd, 0x5d, 0xa4, 0xc2, 0x79, + 0x35, 0x9f, 0xab, 0xf9, 0xe0, 0x94, 0x99, 0xc6, 0xd4, 0xeb, + 0x36, 0x6e, 0xa2, 0x94, 0x80, 0x3f, 0xa8, 0xcc, 0xfb, 0x63, + 0x8b, 0xf2, 0x36, 0x14, 0x60, 0xe3, 0x48, 0x3b, 0x2c, 0x72, + 0x2e, 0x50, 0x39, 0x10, 0xe5, 0x57, 0x5d, 0xac, 0x66, 0x88, + 0x89, 0xbd, 0x7b, 0xe8, 0xc2, 0xb5, 0xd2, 0x6b, 0xd6, 0xea, + 0x8c, 0x5d, 0xab, 0x44, 0xae, 0xca, 0x9e, 0x77, 0xb8, 0x10, + 0x0f, 0x9d, 0xdd, 0x6e, 0x36, 0x5f, 0x65, 0xe4, 0xb9, 0x78, + 0xc6, 0xfc, 0xe0, 0x3f, 0xb1, 0x83, 0x6f, 0x04, 0xd2, 0xdb, + 0x2f, 0x87, 0x56, 0x61, 0xd3, 0x60, 0x51, 0xd4, 0xd2, 0x46, + 0xa1, 0x0e, 0x06, 0xda, 0x9c, 0xa2, 0xfc, 0x50, 0x27, 0xea, + 0x25, 0xbc, 0x5f, 0x55, 0x25, 0x19, 0xd2, 0xb5, 0xff, 0xa7, + 0x0d, 0xf2, 0x3e, 0x67, 0x3a, 0x40, 0x59, 0x51, 0xaa, 0x2a, + 0x62, 0x98, 0x5b, 0x7d, 0x31, 0xcf, 0xbf, 0xee, 0x61, 0x70, + 0xdb, 0x70, 0x5b, 0xdd, 0xae, 0x80, 0x4b, 0x74, 0xc4, 0x83, + 0xd9, 0x56, 0xb7, 0x3c, 0x1c, 0x8b, 0x1e, 0x62, 0x28, 0xad, + 0x4d, 0x55, 0x2e, 0x5f, 0x75, 0x6a, 0x4c, 0x46, 0xa6, 0x99, + 0x39, 0x13, 0x9d, 0x08, 0xde, 0xf7, 0x71, 0x5c, 0xe9, 0x51, + 0xa4, 0x6b, 0x03, 0x6d, 0x74, 0x9d, 0xd5, 0xfe, 0xc8, 0x6b, + 0x27, 0x1c, 0xd4, 0x76, 0x23, 0x58, 0x16, 0x45, 0xf0, 0xb1, + 0x14, 0x2d, 0x87, 0x75, 0xf0, 0x8e, 0xb0, 0x64, 0x46, 0xa1, + 0x82, 0xfb, 0x3f, 0xee, 0xb3, 0x6e, 0x3c, 0xb4, 0x51, 0x39, + 0x34, 0xd1, 0xd0, 0x5d, 0x51, 0xf7, 0xef, 0x59, 0xf2, 0xeb, + 0x67, 0xf1, 0x27, 0x1a, 0x85, 0xae, 0xe3, 0x6e, 0xd7, 0x93, + 0x68, 0x55, 0x23, 0xfe, 0x4e, 0xf7, 0x05, 0x95, 0xd2, 0x51, + 0x92, 0xba, 0xa5, 0xf3, 0x51, 0xf1, 0xa4, 0x5f, 0x30, 0x27, + 0x05, 0xb0, 0x94, 0xcd, 0xa6, 0xa7, 0x7f, 0xdf, 0x99, 0x02, + 0x8b, 0x93, 0xc2, 0xe4, 0x47, 0x2a, 0xbb, 0x21, 0x96, 0xd9, + 0xaf, 0x0a, 0xcc, 0x4d, 0x1d, 0xc8, 0xf5, 0x7f, 0x12, 0x50, + 0x5e, 0xa8, 0x51, 0x5b, 0x4e, 0x0f, 0xc4, 0xed, 0xdf, 0x81, + 0x17, 0x42, 0xf0, 0x07, 0x83, 0x51, 0x9a, 0xba, 0x4a, 0x34, + 0xc3, 0x28, 0xcd, 0x6f, 0x95, 0xd8, 0xe3, 0x72, 0x69, 0xc4, + 0x81, 0xe2, 0xe1, 0xe3, 0xba, 0x1b, 0x4e, 0x73, 0x95, 0x76, + 0xd4, 0x99, 0x7f, 0x5f, 0x6d, 0x41, 0xcd, 0x67, 0x74, 0x50, + 0x6e, 0xa3, 0xea, 0x35, 0xa5, 0xc7, 0x4f, 0xb2, 0x94, 0x7c, + 0x60, 0x55, 0x42, 0xe1, 0xc7, 0x2e, 0x6b, 0x94, 0xf4, 0x82, + 0x1e, 0xff, 0x08, 0x45, 0x93, 0xcb, 0x07, 0x6f, 0x7e, 0x45, + 0x09, 0xa9, 0x17, 0xed, 0x35, 0x81, 0xd9, 0x67, 0xf1, 0xa1, + 0x61, 0x0b, 0x95, 0x80, 0x28, 0xba, 0xdb, 0x7a, 0x9e, 0x12, + 0x4b, 0x05, 0xc6, 0x95, 0x3a, 0xd0, 0x2a, 0x4f, 0xf7, 0xc8, + 0xbc, 0x1b, 0x87, 0x3b, 0x74, 0x5f, 0x85, 0x4c, 0x19, 0xa7, + 0xfb, 0x27, 0x8b, 0x1d, 0xa8, 0xc0, 0x81, 0x5e, 0xe4, 0x0e, + 0xfb, 0x14, 0x04, 0xe3, 0xde, 0x8e, 0x94, 0x5b, 0x00, 0x7c, + 0x05, 0xce, 0xf2, 0x16, 0x4a, 0x66, 0x78, 0xb7, 0x97, 0xec, + 0x6a, 0x7a, 0xb4, 0x0b, 0xfa, 0x40, 0x4a, 0xd8, 0x8d, 0x94, + 0x25, 0x71, 0xf0, 0xf6, 0x76, 0xb0, 0x05, 0xdc, 0xeb, 0xf4, + 0xc4, 0xaf, 0x52, 0x31, 0xb4, 0xaf, 0xf3, 0x91, 0x9e, 0x76, + 0xf7, 0x44, 0xa0, 0xfa, 0x7f, 0x22, 0xc5, 0x34, 0xc7, 0xb8, + 0xd3, 0xe0, 0x79, 0x83, 0x90, 0xfb, 0x7f, 0xcb, 0xee, 0x3e, + 0x88, 0xd7, 0x96, 0x28, 0xcd, 0x87, 0xe7, 0xc1, 0xcf, 0x4c, + 0x03, 0xb9, 0x16, 0x26, 0xf3, 0xdc, 0xc3, 0xc7, 0x34, 0x50, + 0xd6, 0x41, 0x08, 0xd2, 0xc9, 0x8c, 0xd0, 0x0c, 0xdf, 0x02, + 0xb6, 0xc7, 0x0a, 0x9c, 0x98, 0x30, 0x39, 0xbf, 0x7e, 0x93, + 0x0b, 0x18, 0x63, 0x0e, 0xdd, 0x84, 0xe1, 0x8a, 0xcf, 0x5e, + 0x29, 0x8d, 0xe3, 0x12, 0xa5, 0x6c, 0x9a, 0x00, 0xa4, 0xfe, + 0x46, 0xf7, 0xee, 0xa6, 0x52, 0xf1, 0x2e, 0x36, 0x9b, 0xd3, + 0x3c, 0xba, 0x98, 0x96, 0x42, 0x89, 0x89, 0x6a, 0x79, 0xad, + 0x7b, 0x2f, 0xce, 0x1f, 0xc5, 0xd9, 0xb4, 0x09, 0xc9, 0xf6, + 0x26, 0x6d, 0xcf, 0xf5, 0x1f, 0x22, 0xd6, 0x5d, 0x38, 0xcb, + 0x42, 0x83, 0x3c, 0x04, 0x1e, 0x22, 0x45, 0x8d, 0x22, 0xf4, + 0x4a, 0x49, 0xef, 0x92, 0x55, 0xca, 0x7f, 0xdd, 0xc5, 0x05, + 0x5b, 0xc6, 0x71, 0x97, 0x2b, 0x25, 0xdb, 0xd9, 0x81, 0x60, + 0x4b, 0x27, 0x55, 0x0a, 0x07, 0x80, 0xff, 0x34, 0xed, 0x71, + 0x46, 0xd4, 0x25, 0x7b, 0x5c, 0x10, 0x6a, 0x08, 0xb2, 0x46, + 0x49, 0xff, 0xd0, 0x43, 0xe4, 0xe5, 0x10, 0xa1, 0x4a, 0xf0, + 0x41, 0xbc, 0x6e, 0x74, 0x2b, 0x64, 0x1d, 0x13, 0xde, 0x54, + 0x51, 0x8c, 0x65, 0x83, 0xa8, 0x4b, 0x74, 0x89, 0x2b, 0x0a, + 0x80, 0xa9, 0xb8, 0x9f, 0xdc, 0xaf, 0xc4, 0x9b, 0xc9, 0xbd, + 0xed, 0x57, 0x49, 0x38, 0x1d, 0x01, 0xf3, 0x0a, 0xcf, 0xa7, + 0xd5, 0xd8, 0xf8, 0x17, 0xe1, 0x52, 0x90, 0x30, 0x38, 0x67, + 0xb2, 0xd4, 0xbe, 0xc6, 0x4b, 0x31, 0x66, 0xe0, 0xf1, 0x09, + 0x73, 0x44, 0x78, 0xad, 0x93, 0x6c, 0x01, 0x3d, 0xb8, 0xeb, + 0x23, 0x73, 0x20, 0x5c, 0x3b, 0x7f, 0xb9, 0xab, 0xe6, 0xd1, + 0x43, 0xde, 0x20, 0x98, 0x54, 0xa9, 0x34, 0xc4, 0x72, 0x98, + 0x4c, 0x15, 0x66, 0xd8, 0x48, 0xfa, 0x35, 0x8a, 0x49, 0x18, + 0xc6, 0x6d, 0xde, 0x48, 0x49, 0xb2, 0x7d, 0x25, 0x1b, 0x68, + 0x34, 0xec, 0x01, 0x38, 0x3e, 0xcd, 0xeb, 0x58, 0x6b, 0xcc, + 0x3e, 0x3b, 0x62, 0x0d, 0xed, 0xa8, 0x8a, 0xd2, 0xbb, 0x55, + 0xbb, 0x91, 0x39, 0x35, 0x8f, 0xca, 0xe2, 0x63, 0x74, 0x4a, + 0xfa, 0x8c, 0x87, 0xc6, 0xb4, 0x20, 0x1f, 0x13, 0x4e, 0x86, + 0x1f, 0x94, 0xe4, 0x4b, 0x8b, 0x47, 0x3c, 0x49, 0x87, 0x1d, + 0xd1, 0x0b, 0x2e, 0x3f, 0x95, 0xc7, 0x39, 0x97, 0x1d, 0x1c, + 0xef, 0x6f, 0x00, 0x94, 0xc5, 0xe9, 0x5d, 0x49, 0x10, 0x73, + 0x04, 0x2c, 0xe6, 0x26, 0x74, 0x0e, 0x7f, 0x2b, 0xf9, 0x07, + 0x78, 0xde, 0xb5, 0x53, 0x32, 0x3c, 0x1a, 0x51, 0x0e, 0x7c, + 0x9e, 0x72, 0xfe, 0x25, 0xbe, 0x90, 0x74, 0x2d, 0x61, 0xf6, + 0x36, 0x88, 0x29, 0x17, 0x5c, 0x09, 0x9b, 0x6f, 0x13, 0xa2, + 0xa4, 0xf3, 0x0e, 0x0e, 0xf9, 0x24, 0x91, 0xac, 0xfa, 0x5e, + 0x0b, 0x35, 0x96, 0xf7, 0xac, 0xcf, 0x3c, 0xc2, 0xc8, 0x2a, + 0xd5, 0x88, 0x8e, 0x13, 0xd6, 0xf4, 0x93, 0x78, 0x92, 0xbd, + 0x2d, 0x6f, 0x97, 0xe5, 0xed, 0xf3, 0x0e, 0x26, 0x26, 0xf6, + 0xac, 0x5a, 0xc9, 0x8f, 0x25, 0xbb, 0x93, 0xf5, 0x06, 0x29, + 0x10, 0xdb, 0xf4, 0x9a, 0x45, 0x2c, 0x29, 0x48, 0x22, 0x26, + 0x82, 0xda, 0x69, 0xe7, 0x35, 0x0c, 0x35, 0xce, 0x90, 0xf1, + 0x0d, 0x9f, 0x67, 0xbf, 0xeb, 0x7c, 0xdb, 0xcb, 0x71, 0xd5, + 0xbe, 0x2a, 0x01, 0x06, 0x2c, 0x2b, 0xf1, 0xfa, 0x6d, 0x08, + 0xa8, 0x76, 0xd3, 0x07, 0xb5, 0x0c, 0xae, 0xe7, 0x5b, 0x35, + 0x35, 0x47, 0x8e, 0x1c, 0xf7, 0xc4, 0x51, 0x4d, 0xb1, 0x84, + 0x19, 0x4b, 0x3c, 0xaa, 0x38, 0x68, 0x96, 0x94, 0x8f, 0xf8, + 0xa0, 0xf2, 0x46, 0x1e, 0xd3, 0x88, 0x4e, 0x92, 0x42, 0xa8, + 0x8a, 0x1b, 0x4f, 0x8b, 0xb9, 0x91, 0xd4, 0x6c, 0x74, 0xe7, + 0xcf, 0x9b, 0x5d, 0xf6, 0x24, 0xd2, 0xbd, 0x90, 0xda, 0xfc, + 0x1b, 0xfe, 0x95, 0xde, 0xcc, 0xb3, 0xb3, 0x41, 0x3a, 0x25, + 0x5a, 0xa5, 0x20, 0x66, 0xa5, 0x2a, 0xea, 0xef, 0xb0, 0x2c, + 0xea, 0x4f, 0x86, 0x0e, 0x13, 0xc8, 0x78, 0x54, 0x16, 0xc8, + 0xd8, 0x28, 0xe4, 0x05, 0x41, 0x1e, 0x73, 0x89, 0x6a, 0x13, + 0xb0, 0x4e, 0xa3, 0x30, 0x51, 0xed, 0x9e, 0xf4, 0x21, 0xc7, + 0xeb, 0x18, 0xa5, 0xc7, 0x9c, 0x1c, 0x27, 0x0a, 0xb9, 0x91, + 0xab, 0xb8, 0xf0, 0x8c, 0x4f, 0xbc, 0x9c, 0xa5, 0xc1, 0x96, + 0xbf, 0xe6, 0x06, 0x89, 0x50, 0xb4, 0xf8, 0x57, 0x38, 0x2a, + 0x2b, 0xb9, 0xe7, 0xb8, 0x66, 0x09, 0x67, 0xa5, 0xde, 0x4b, + 0x9b, 0x59, 0x2e, 0x2b, 0x9f, 0x4b, 0x5b, 0x85, 0x34, 0xaf, + 0xf3, 0x11, 0xbc, 0x5d, 0x21, 0x29, 0x10, 0xa1, 0xe4, 0xc2, + 0x24, 0x21, 0x49, 0x3e, 0x15, 0x9b, 0x04, 0xd2, 0x1b, 0x57, + 0x42, 0x41, 0x7a, 0x41, 0xcb, 0xa3, 0xec, 0x07, 0xa3, 0xdf, + 0x5b, 0x7a, 0xf7, 0x30, 0x72, 0x81, 0x75, 0xed, 0x21, 0xc8, + 0xfb, 0x49, 0x47, 0xdb, 0x84, 0x04, 0xb3, 0xee, 0x3e, 0x82, + 0x7c, 0x48, 0x69, 0xa4, 0x34, 0x85, 0x45, 0x60, 0xbf, 0x16, + 0xc4, 0x65, 0x5b, 0xe8, 0x4e, 0x1a, 0xde, 0xd9, 0x94, 0xa1, + 0xf9, 0xc9, 0x1d, 0xd1, 0x3f, 0x97, 0xcc, 0x0e, 0x7b, 0x20, + 0x89, 0xd3, 0x93, 0x7b, 0x1d, 0x9d, 0x2d, 0x0c, 0x73, 0x34, + 0xc8, 0x4f, 0x50, 0x8a, 0x60, 0x96, 0x1f, 0xd6, 0xdf, 0x8a, + 0x7d, 0xb9, 0x4d, 0x6d, 0x3c, 0x1e, 0xa5, 0x78, 0x2e, 0xec, + 0xec, 0x18, 0x90, 0x81, 0x3c, 0xcf, 0x65, 0x52, 0x66, 0x57, + 0x93, 0xba, 0x34, 0x26, 0xf9, 0x4c, 0x32, 0xe8, 0xa3, 0x5c, + 0xf5, 0xc9, 0xec, 0x7c, 0x34, 0xd6, 0xf2, 0x99, 0x62, 0x26, + 0xc1, 0xad, 0xeb, 0xc9, 0xf6, 0x41, 0x57, 0x87, 0xa3, 0x59, + 0x3e, 0x31, 0x8c, 0x6e, 0x3b, 0x6e, 0x50, 0xbc, 0xd0, 0x85, + 0xc7, 0xbe, 0x28, 0xc2, 0x03, 0x87, 0x66, 0xc2, 0x9c, 0x90, + 0x1f, 0x12, 0x6b, 0x28, 0x73, 0xfc, 0x2d, 0xa6, 0x9f, 0xa7, + 0xb3, 0x2f, 0x34, 0xad, 0x6a, 0xd6, 0xe5, 0xad, 0xff, 0xe0, + 0x07, 0x4f, 0x3e, 0x7b, 0xea, 0x88, 0x47, 0x97, 0x38, 0x81, + 0x47, 0x43, 0x3d, 0xcf, 0x0f, 0xe8, 0xa3, 0x3c, 0x0d, 0x7d, + 0x78, 0xf1, 0x15, 0xfe, 0x37, 0x37, 0xe7, 0x05, 0xbb, 0x05, + 0xff, 0xed, 0x79, 0x1e, 0xcf, 0x8b, 0x08, 0x0a, 0x9b, 0x86, + 0xdd, 0x35, 0x75, 0x79, 0x10, 0x13, 0xdd, 0x78, 0x5c, 0x95, + 0x0e, 0xb1, 0x65, 0x26, 0xc4, 0x2c, 0x56, 0x70, 0x82, 0xa2, + 0xee, 0x2b, 0x44, 0xe2, 0x27, 0xe6, 0x45, 0x39, 0xa9, 0x92, + 0x7f, 0x3a, 0xeb, 0x20, 0x08, 0xcd, 0x49, 0x07, 0x1d, 0xc9, + 0xfc, 0x9a, 0x5f, 0x57, 0xf3, 0xb9, 0x6a, 0x59, 0x73, 0xeb, + 0xfa, 0xb5, 0x60, 0x3d, 0x9f, 0x4b, 0xd6, 0xb1, 0xbc, 0x1b, + 0xe9, 0x4b, 0x4e, 0x42, 0x8a, 0xc6, 0xda, 0xa6, 0x0f, 0x5a, + 0xff, 0xcd, 0xd4, 0x16, 0x78, 0x23, 0xc7, 0x18, 0xc5, 0x1a, + 0x76, 0x93, 0x67, 0x2a, 0xce, 0x1e, 0x54, 0xa3, 0xb9, 0xb7, + 0x7e, 0x80, 0xac, 0xa1, 0xbb, 0x0c, 0x1c, 0x46, 0xe0, 0x3b, + 0x7d, 0x2d, 0xf9, 0x60, 0x36, 0xd4, 0x2c, 0x28, 0x1c, 0xf2, + 0x82, 0x01, 0x35, 0xa2, 0x48, 0x48, 0x87, 0x42, 0x8a, 0x5c, + 0xc6, 0x53, 0x86, 0x9b, 0x30, 0xd1, 0xc4, 0xba, 0xcb, 0xe9, + 0xb9, 0x12, 0x6c, 0x81, 0x09, 0x8f, 0x26, 0x83, 0x3c, 0x87, + 0x61, 0xaa, 0xe8, 0x2f, 0x1c, 0x5b, 0xc8, 0x75, 0x54, 0xfd, + 0x92, 0x67, 0x33, 0x4c, 0x0f, 0xde, 0xfc, 0x8b, 0xe9, 0x29, + 0x5c, 0x1f, 0xab, 0xb9, 0xac, 0x87, 0x97, 0xe3, 0x3a, 0xc6, + 0x30, 0x0a, 0x5c, 0xcc, 0x7a, 0x21, 0x6c, 0x2f, 0xd1, 0xda, + 0x7b, 0xc0, 0x59, 0x31, 0xd9, 0x8f, 0x99, 0x4f, 0xb5, 0xfc, + 0x97, 0x53, 0xbd, 0xf2, 0x49, 0xe8, 0xd4, 0x02, 0xc6, 0x43, + 0xb9, 0xe6, 0xd8, 0xb6, 0xff, 0xfb, 0x6f, 0xf2, 0xb7, 0x2a, + 0x86, 0x5e, 0xc6, 0x73, 0x25, 0xb4, 0xb2, 0xe5, 0x94, 0x5d, + 0xcb, 0xa2, 0x37, 0xe8, 0x86, 0xbb, 0xb0, 0x94, 0xb7, 0xa7, + 0x19, 0x08, 0x02, 0x3b, 0x13, 0xc3, 0x00, 0x44, 0x8a, 0x8f, + 0xa6, 0x63, 0xc3, 0x22, 0xa4, 0x16, 0xbd, 0x04, 0xcd, 0x72, + 0xe9, 0x4c, 0x25, 0x5e, 0xaf, 0x0b, 0x13, 0xc4, 0xe7, 0xbc, + 0xd2, 0x1a, 0x3f, 0x60, 0xbf, 0xda, 0x13, 0xf6, 0xab, 0x3d, + 0x62, 0xbf, 0xd2, 0x33, 0x76, 0x65, 0x0b, 0x9d, 0x9f, 0xb1, + 0xab, 0xa8, 0x8f, 0xa6, 0xd7, 0x96, 0x3a, 0x4c, 0xf5, 0xb4, + 0x53, 0xea, 0x60, 0x08, 0x8b, 0xb9, 0x90, 0xa5, 0x1d, 0x07, + 0xe7, 0x73, 0xab, 0xa1, 0x60, 0x8c, 0xbe, 0x69, 0x42, 0xa2, + 0xe3, 0x94, 0x02, 0xbb, 0x42, 0x0a, 0x31, 0x3b, 0xec, 0x49, + 0x9e, 0x64, 0x2d, 0x4c, 0xad, 0x12, 0xc1, 0x68, 0xe3, 0x5b, + 0x4f, 0x27, 0xcf, 0x8c, 0x54, 0xfb, 0x4a, 0xef, 0x28, 0x0a, + 0x77, 0x43, 0x2a, 0x79, 0x60, 0x3f, 0xa4, 0xfb, 0x6e, 0x7c, + 0x3e, 0x56, 0x12, 0x62, 0x52, 0x6f, 0x49, 0x54, 0x8f, 0x38, + 0x07, 0xf6, 0x92, 0x91, 0xeb, 0xc9, 0x95, 0xac, 0x7d, 0xd2, + 0xd2, 0x90, 0xf4, 0x22, 0xbd, 0x5d, 0xf8, 0xab, 0x26, 0xe9, + 0xaa, 0xea, 0x9e, 0x28, 0x6f, 0x3d, 0xd2, 0x5d, 0x99, 0x29, + 0x23, 0x33, 0x74, 0xc8, 0xce, 0x50, 0x32, 0xd6, 0x41, 0xe0, + 0xdf, 0xb9, 0xab, 0x6d, 0x98, 0x4f, 0x0e, 0x5f, 0xad, 0xc3, + 0xde, 0x26, 0x6d, 0x73, 0x13, 0xd7, 0xc1, 0x03, 0xe1, 0x2d, + 0x1c, 0xad, 0x0b, 0x9e, 0x8a, 0x54, 0x22, 0x03, 0x64, 0x13, + 0xb1, 0x96, 0xf7, 0xb6, 0xef, 0xd3, 0x6b, 0x2a, 0xf1, 0x59, + 0x0e, 0x56, 0x84, 0xd3, 0xb3, 0x3f, 0xb6, 0x60, 0x75, 0x64, + 0x24, 0x11, 0xa9, 0x63, 0xcb, 0x49, 0x17, 0xaa, 0x31, 0x49, + 0xcc, 0x8e, 0x90, 0xd7, 0x2d, 0x78, 0x9f, 0xb6, 0x77, 0x42, + 0xc6, 0x76, 0xf4, 0x07, 0x25, 0xf9, 0x43, 0xe1, 0xf1, 0xbd, + 0x8e, 0xda, 0x6d, 0x2d, 0xb2, 0x2d, 0xe4, 0xb7, 0xd6, 0x11, + 0xbb, 0xb5, 0xda, 0xee, 0xa9, 0x4a, 0xc4, 0xac, 0x2e, 0x80, + 0x59, 0x9a, 0x69, 0x0d, 0x2e, 0x2e, 0x45, 0xa4, 0x34, 0x10, + 0x2b, 0xf9, 0xde, 0x36, 0xc1, 0xe1, 0xcb, 0x68, 0x32, 0xee, + 0xf3, 0x71, 0xe8, 0x82, 0x47, 0xd0, 0x81, 0xf0, 0x60, 0xa1, + 0x53, 0xc2, 0xbc, 0x0d, 0x0e, 0x1d, 0xa8, 0xb6, 0x02, 0x5b, + 0x56, 0x32, 0x84, 0x43, 0x09, 0x8f, 0x11, 0x22, 0xa9, 0x72, + 0xe1, 0xed, 0x8c, 0xfc, 0x64, 0x65, 0x58, 0x5f, 0x48, 0x7a, + 0x29, 0xbb, 0x14, 0xf8, 0xa9, 0x57, 0x73, 0xd2, 0x47, 0xd1, + 0x44, 0xd7, 0xd0, 0x6f, 0xbd, 0x18, 0xcd, 0x18, 0x4d, 0x5d, + 0x04, 0xfa, 0x30, 0x21, 0x1b, 0xee, 0xba, 0xf5, 0xd8, 0x4e, + 0xf3, 0xe9, 0xb5, 0x5a, 0x8e, 0xb2, 0x1e, 0x54, 0xa0, 0x27, + 0x24, 0x81, 0x5e, 0xe4, 0xb4, 0x5c, 0x3c, 0x2c, 0x8a, 0x60, + 0x63, 0x83, 0x6b, 0xd3, 0xdf, 0xad, 0x62, 0x0e, 0x9e, 0x39, + 0xaf, 0x7a, 0x56, 0xdd, 0x33, 0xdd, 0x35, 0xe8, 0x84, 0x4c, + 0x09, 0xaf, 0xd7, 0x6b, 0x2e, 0x6c, 0x17, 0xd9, 0x3a, 0xf9, + 0x50, 0xf7, 0xe6, 0x11, 0xf5, 0x8c, 0x0f, 0x53, 0x72, 0x09, + 0x8e, 0xb0, 0xbd, 0xaf, 0x6d, 0x70, 0x71, 0x3e, 0x7a, 0x49, + 0xfe, 0x3d, 0x13, 0xf5, 0xc7, 0xa1, 0x86, 0x47, 0xf6, 0xca, + 0x6f, 0x94, 0x74, 0xaa, 0x84, 0x52, 0x55, 0xa2, 0x79, 0x43, + 0x9d, 0xb4, 0x7c, 0xf4, 0x50, 0x07, 0x9f, 0x8b, 0x2c, 0xfa, + 0xd9, 0x3d, 0x79, 0x8d, 0x41, 0x79, 0xca, 0xa1, 0x7b, 0xc7, + 0xea, 0x4d, 0x51, 0xbe, 0xf8, 0x21, 0x3a, 0x47, 0xab, 0x63, + 0xa6, 0xd8, 0xf7, 0x11, 0x01, 0x35, 0x55, 0x46, 0x14, 0xd7, + 0xdd, 0x1d, 0x72, 0x8f, 0x90, 0xc5, 0x97, 0x85, 0x54, 0x66, + 0x30, 0xa7, 0xa4, 0xa4, 0x04, 0x3a, 0xc8, 0x3d, 0x80, 0x30, + 0x38, 0xe9, 0xcd, 0xcf, 0x64, 0xb5, 0xc3, 0xa1, 0xac, 0x9e, + 0xcf, 0x72, 0xe0, 0xa5, 0xea, 0x2d, 0x6f, 0x59, 0xab, 0xc9, + 0x27, 0x8e, 0x28, 0x64, 0xe9, 0xbf, 0x0f, 0x38, 0x22, 0xed, + 0x92, 0x9e, 0x63, 0x82, 0xe6, 0x68, 0xa2, 0xcd, 0x16, 0x62, + 0xae, 0x0e, 0x42, 0x35, 0x7d, 0xd6, 0x6c, 0x46, 0x11, 0xf2, + 0x6b, 0xce, 0x7e, 0x40, 0xe8, 0x31, 0x4c, 0xdb, 0x00, 0x39, + 0x5d, 0x9d, 0x5e, 0xe6, 0xa0, 0xd2, 0xd1, 0xe5, 0x4a, 0x49, + 0xbd, 0x5b, 0x1b, 0x51, 0xca, 0x27, 0x50, 0x27, 0xc4, 0xda, + 0xcc, 0x20, 0x21, 0xc8, 0xcd, 0xe0, 0x47, 0x9e, 0x6a, 0xd3, + 0x19, 0x24, 0x14, 0x75, 0x6d, 0x70, 0x9d, 0x4e, 0xe1, 0xa9, + 0x38, 0xe6, 0xc4, 0x9e, 0x20, 0x4b, 0xf1, 0x7c, 0x61, 0xdc, + 0x08, 0x66, 0x01, 0x22, 0xc0, 0xdd, 0x48, 0x39, 0xdf, 0x46, + 0x3b, 0x69, 0x42, 0x8b, 0xa9, 0xb1, 0x98, 0x23, 0x43, 0x71, + 0xda, 0xb3, 0x4f, 0x34, 0x55, 0x52, 0xb4, 0xdd, 0x20, 0x2b, + 0x31, 0x32, 0x79, 0x08, 0xfb, 0xab, 0x9e, 0xee, 0x74, 0x66, + 0x99, 0x5f, 0xd3, 0xc0, 0xcc, 0x7d, 0xee, 0x0c, 0x73, 0xb6, + 0x4b, 0xa8, 0xf0, 0x23, 0x13, 0xe3, 0x10, 0xc4, 0x24, 0x50, + 0x53, 0x96, 0xea, 0xc4, 0x48, 0x95, 0x55, 0xc6, 0x77, 0xda, + 0x77, 0x32, 0xbd, 0xa3, 0x01, 0x1d, 0x8b, 0xb5, 0x88, 0x51, + 0x14, 0xa0, 0x54, 0xd5, 0xc2, 0x64, 0x3f, 0x7c, 0x40, 0xef, + 0xe3, 0xdb, 0x66, 0x1d, 0xa4, 0x9b, 0xf9, 0xa8, 0x8c, 0xe8, + 0xc8, 0x87, 0xd2, 0xa7, 0x21, 0x57, 0x22, 0xca, 0x8c, 0x89, + 0xf1, 0xb8, 0x8c, 0xf6, 0xb0, 0x09, 0x94, 0x2c, 0x22, 0x8a, + 0x0c, 0x8e, 0x19, 0x3a, 0xd8, 0xc1, 0x49, 0x19, 0xdd, 0x0b, + 0xdb, 0xf5, 0x10, 0x54, 0x58, 0x13, 0xd2, 0xc6, 0x55, 0x26, + 0x1e, 0x69, 0x02, 0x7b, 0x4c, 0xd0, 0xb8, 0x47, 0x92, 0xa3, + 0xe9, 0xb2, 0xe9, 0xda, 0xb5, 0xa6, 0x1b, 0xe8, 0xc5, 0x20, + 0x13, 0x1e, 0x07, 0x8c, 0x61, 0xcd, 0x8d, 0x5d, 0x94, 0xd3, + 0x47, 0x87, 0x77, 0x97, 0x30, 0x02, 0x89, 0xf9, 0x48, 0x96, + 0xf6, 0xc5, 0x4c, 0x1f, 0x68, 0x43, 0x8b, 0x91, 0xe8, 0x07, + 0x67, 0x9c, 0x67, 0x3b, 0x54, 0x73, 0xab, 0x24, 0x7b, 0x8d, + 0x6e, 0x84, 0x15, 0x0e, 0xf6, 0x0d, 0xb4, 0x9d, 0x4e, 0xd4, + 0xc9, 0x18, 0x55, 0x8c, 0x4f, 0xce, 0x2f, 0xb7, 0x19, 0xe0, + 0x15, 0xef, 0x7e, 0xc5, 0x48, 0xcf, 0xe6, 0x32, 0x4f, 0x95, + 0xea, 0x23, 0xfe, 0x30, 0x77, 0xc4, 0xcb, 0x3b, 0xac, 0x34, + 0xea, 0x97, 0x7c, 0x97, 0x8e, 0xca, 0xba, 0xd4, 0xc0, 0x38, + 0xf0, 0x9d, 0x9e, 0xc2, 0xd3, 0x1e, 0xa2, 0x78, 0x06, 0xf9, + 0x01, 0x1e, 0xe7, 0x06, 0x88, 0xe3, 0x21, 0x7e, 0xdf, 0xda, + 0x1e, 0xf2, 0x3f, 0x2d, 0xf6, 0x56, 0x05, 0x0c, 0x74, 0x21, + 0x40, 0x62, 0xbd, 0xb5, 0xf5, 0x30, 0x8c, 0x50, 0xb6, 0x57, + 0x21, 0xcc, 0x39, 0x1f, 0x64, 0xe0, 0xa0, 0x5e, 0x97, 0x65, + 0x08, 0x77, 0xe4, 0xd2, 0x5b, 0xa1, 0x5e, 0xad, 0x58, 0x27, + 0xdb, 0xa4, 0x99, 0x51, 0xfa, 0x3d, 0x45, 0x85, 0xe9, 0x1c, + 0x68, 0x91, 0x4e, 0x65, 0x16, 0xb2, 0x23, 0xbb, 0x18, 0x27, + 0xb9, 0xc5, 0xe0, 0xee, 0x7f, 0xbc, 0x92, 0xd4, 0x4f, 0xf8, + 0x67, 0x87, 0xf0, 0xdb, 0x2e, 0x22, 0xad, 0x7f, 0xa7, 0xbb, + 0x7e, 0x85, 0x64, 0x85, 0xa3, 0x47, 0x17, 0xa0, 0xd3, 0xf2, + 0xab, 0x43, 0xf9, 0xd5, 0x8d, 0x39, 0xf6, 0x84, 0xe1, 0xed, + 0xc9, 0x9f, 0x98, 0x8c, 0x39, 0x8e, 0x3d, 0x27, 0x4b, 0x49, + 0x64, 0x3a, 0xd7, 0x51, 0x2e, 0xb9, 0x56, 0x79, 0x47, 0xbf, + 0xe4, 0x54, 0xfb, 0x27, 0xa9, 0xcb, 0xe5, 0x77, 0x39, 0x91, + 0x72, 0x01, 0xd9, 0xd5, 0x5b, 0xf1, 0x63, 0xf5, 0x56, 0x4c, + 0xdd, 0x61, 0xbe, 0xd3, 0x4e, 0x7c, 0x63, 0xc7, 0xef, 0xc8, + 0x8e, 0xd5, 0xfe, 0x06, 0x1d, 0x83, 0xdd, 0xd9, 0x0b, 0xc8, + 0x3e, 0xe3, 0xf4, 0xba, 0xad, 0x46, 0xae, 0xb1, 0xe6, 0xfa, + 0xec, 0x52, 0xd7, 0x0c, 0x43, 0x98, 0xfa, 0x11, 0x73, 0xd5, + 0xad, 0xc8, 0xf8, 0x39, 0x15, 0x8d, 0x02, 0x46, 0xa5, 0xa1, + 0x29, 0xbb, 0xba, 0x6a, 0xa3, 0xeb, 0xdc, 0xfd, 0x5f, 0xb8, + 0xbc, 0x56, 0x59, 0xab, 0x60, 0xed, 0xec, 0x31, 0x9f, 0x49, + 0x36, 0x85, 0xfc, 0xb2, 0xc2, 0xaa, 0xaa, 0xf4, 0xa2, 0xcb, + 0xe0, 0xde, 0xe1, 0x1b, 0x6e, 0xc5, 0x14, 0xcd, 0x17, 0xa6, + 0x70, 0xad, 0xd9, 0x67, 0xa6, 0x69, 0xb3, 0x4d, 0xf2, 0x0c, + 0xc9, 0xa1, 0x49, 0xef, 0x0b, 0x5e, 0x18, 0xd4, 0xff, 0x02, + 0xd9, 0xe2, 0x15, 0x3b, 0x15, 0x0a, 0x9c, 0x09, 0xb1, 0xfe, + 0x9e, 0xfd, 0x91, 0xbe, 0x7c, 0x66, 0x92, 0x0e, 0xf2, 0x11, + 0xba, 0xc0, 0xfb, 0x38, 0x21, 0xe2, 0x9d, 0xeb, 0x13, 0x67, + 0x03, 0xf8, 0x65, 0x4b, 0xef, 0xe2, 0x52, 0x7c, 0xeb, 0xfa, + 0x77, 0x41, 0x21, 0x7c, 0xf6, 0x77, 0xbf, 0x73, 0xd4, 0x7b, + 0x0d, 0xe8, 0x1b, 0x3e, 0x25, 0x2f, 0xf0, 0x23, 0x94, 0x02, + 0x8a, 0x30, 0xe9, 0x09, 0x83, 0x7c, 0xf3, 0x18, 0x78, 0x5b, + 0x12, 0x11, 0x8b, 0x10, 0xe3, 0x27, 0xae, 0xbf, 0x95, 0x06, + 0xc2, 0x2a, 0x8f, 0x34, 0x15, 0x7c, 0x01, 0xc3, 0x4d, 0x9b, + 0x67, 0xfc, 0x04, 0x0d, 0xb1, 0x70, 0x18, 0xc5, 0x8e, 0x0e, + 0x14, 0x0d, 0x37, 0xab, 0xdb, 0x7c, 0x20, 0x13, 0x60, 0x47, + 0xf0, 0x4a, 0xee, 0x28, 0x29, 0x1a, 0x63, 0x45, 0x20, 0xf2, + 0x75, 0x9b, 0x40, 0x03, 0xe2, 0xb8, 0xd3, 0x64, 0x58, 0x87, + 0x42, 0x6a, 0xc2, 0x4e, 0xc3, 0x4a, 0xd3, 0x1b, 0x56, 0x0c, + 0x4b, 0x6d, 0x31, 0xac, 0xcb, 0x4d, 0x74, 0xe1, 0x3e, 0x37, + 0x19, 0x55, 0x26, 0xf0, 0x2e, 0xe7, 0x86, 0x82, 0xeb, 0xca, + 0x8e, 0x2a, 0x81, 0x02, 0xcf, 0x18, 0x2f, 0xf9, 0x9d, 0x9e, + 0x20, 0x97, 0x17, 0xd7, 0xb2, 0x51, 0x01, 0xa2, 0x40, 0xb9, + 0x56, 0xc7, 0xa3, 0xa1, 0x35, 0x54, 0x19, 0x77, 0xfe, 0x7d, + 0x2a, 0xe5, 0x70, 0x53, 0x28, 0x66, 0x4c, 0xde, 0x00, 0x42, + 0x08, 0x22, 0xb3, 0x27, 0x43, 0xf0, 0x90, 0x27, 0x88, 0x9f, + 0x9d, 0x9a, 0x11, 0x9c, 0xcf, 0x0c, 0x86, 0xde, 0x31, 0x4f, + 0x6f, 0x1e, 0x44, 0x6e, 0x23, 0xb3, 0x22, 0xa1, 0x39, 0x98, + 0x5d, 0x32, 0x34, 0xcf, 0x78, 0x9a, 0x03, 0xb8, 0x34, 0x50, + 0x8d, 0x98, 0xc1, 0x83, 0x05, 0xa3, 0x4d, 0xf8, 0x4e, 0x43, + 0xea, 0x06, 0x4b, 0xfd, 0x60, 0x9f, 0xa7, 0x8e, 0xb3, 0xa7, + 0x74, 0x20, 0x7e, 0xa5, 0x0e, 0xa8, 0xf7, 0xec, 0xfe, 0xa1, + 0x40, 0xfd, 0x2a, 0x08, 0xdd, 0x97, 0xc0, 0x8f, 0x49, 0x0e, + 0xec, 0x6d, 0x68, 0x2f, 0x77, 0x8a, 0x06, 0x4f, 0x97, 0x75, + 0xf3, 0x85, 0xbc, 0xe6, 0x1a, 0x3a, 0x16, 0x1a, 0xca, 0xf2, + 0x15, 0x74, 0x6d, 0xe6, 0x6a, 0x38, 0xa3, 0xf1, 0x03, 0xfb, + 0x67, 0xe5, 0xe3, 0x19, 0xba, 0x44, 0x7a, 0x23, 0x68, 0xfb, + 0x79, 0x08, 0x96, 0x6e, 0xd4, 0x7c, 0xdd, 0xaf, 0xd9, 0xc6, + 0x78, 0x1c, 0x5c, 0x76, 0x4c, 0x8d, 0x9a, 0x6a, 0xa7, 0x6b, + 0x5f, 0x5e, 0x98, 0x5d, 0x32, 0xde, 0x4d, 0x87, 0xea, 0xb8, + 0xd0, 0xdd, 0x14, 0xe3, 0xe9, 0x2a, 0xaa, 0xd7, 0xc4, 0x88, + 0x3b, 0x1c, 0x5d, 0x5c, 0x68, 0x28, 0x45, 0xec, 0xa8, 0x08, + 0x20, 0x79, 0xe8, 0xde, 0x61, 0x94, 0xb3, 0xd8, 0xb5, 0x3d, + 0x79, 0x92, 0x9a, 0x3a, 0x44, 0x4a, 0xdf, 0xe7, 0x19, 0xcd, + 0x61, 0xca, 0xbf, 0x32, 0xda, 0x18, 0x08, 0xe2, 0x21, 0xf0, + 0x9b, 0xa4, 0x08, 0x9e, 0xa8, 0xd3, 0x85, 0x3a, 0xb6, 0xb0, + 0x82, 0x96, 0x7f, 0x82, 0x9c, 0xd8, 0xfe, 0x16, 0x1b, 0x61, + 0x36, 0x0d, 0x9e, 0x56, 0x8c, 0xd1, 0x64, 0x31, 0x56, 0xcd, + 0xd1, 0x6c, 0x9a, 0x0f, 0x48, 0x4a, 0x1c, 0x14, 0x5a, 0x2e, + 0xfe, 0x36, 0x5e, 0x5a, 0x3b, 0x9c, 0x5e, 0x3b, 0x79, 0x0f, + 0x31, 0x07, 0xca, 0x0d, 0xfe, 0xdd, 0x22, 0xb2, 0x10, 0x11, + 0x5b, 0xc3, 0x8d, 0x70, 0xcf, 0x52, 0x9b, 0x90, 0x0f, 0xcd, + 0x3d, 0xaa, 0x10, 0x35, 0x87, 0xfa, 0x51, 0x21, 0x5a, 0xc3, + 0xbc, 0xf7, 0x94, 0x2c, 0x25, 0xd6, 0xc9, 0x00, 0x91, 0x4a, + 0x42, 0xa8, 0xc9, 0x41, 0xd7, 0x3e, 0x9c, 0xff, 0xcd, 0x1b, + 0x50, 0x16, 0x9c, 0xde, 0xbe, 0x0d, 0x1e, 0x53, 0xf2, 0x0a, + 0x8a, 0xc3, 0xdb, 0x44, 0x81, 0xeb, 0x74, 0x02, 0xab, 0x4f, + 0xe3, 0xf9, 0x0a, 0xf3, 0x8a, 0xd0, 0xbf, 0x35, 0x67, 0x98, + 0x65, 0xb0, 0xa2, 0x21, 0x1a, 0xb9, 0x83, 0xb6, 0xb0, 0xcb, + 0xb2, 0x73, 0x13, 0x51, 0xd2, 0xf9, 0x53, 0xb6, 0x78, 0x32, + 0xf6, 0xe4, 0x58, 0xf1, 0xde, 0xa1, 0x1e, 0x00, 0xb5, 0x47, + 0x52, 0x73, 0xaf, 0x9f, 0x47, 0x86, 0x7c, 0xcd, 0x21, 0xd4, + 0x9c, 0xf8, 0xbd, 0xbd, 0x5c, 0x16, 0xf4, 0x3d, 0x7f, 0x6e, + 0x77, 0x60, 0x97, 0x47, 0xa6, 0x8d, 0x0a, 0xcd, 0xa0, 0x37, + 0xb7, 0x67, 0x6d, 0xeb, 0x81, 0x50, 0xf5, 0x57, 0x38, 0x09, + 0x8d, 0xbc, 0x1a, 0x9e, 0x09, 0x76, 0x5c, 0x5f, 0x49, 0x09, + 0x48, 0xe9, 0xe2, 0xac, 0x90, 0x1b, 0x02, 0x94, 0xa0, 0xa0, + 0xb3, 0x0f, 0xd5, 0xe6, 0xde, 0x6d, 0x2d, 0x55, 0x50, 0x52, + 0x41, 0x32, 0x80, 0x6e, 0xf2, 0x24, 0xbe, 0x07, 0x18, 0x2e, + 0x20, 0x2f, 0x66, 0x51, 0x94, 0x63, 0x91, 0x90, 0xa5, 0xd1, + 0x8f, 0x38, 0x25, 0x61, 0x1f, 0x9d, 0xd8, 0x44, 0xed, 0x27, + 0xe2, 0xc6, 0x7e, 0x22, 0x5d, 0x50, 0xde, 0x9b, 0xe1, 0x16, + 0xfc, 0xda, 0xb9, 0x27, 0xd6, 0xda, 0x5e, 0xf9, 0x00, 0x45, + 0x45, 0xf7, 0xd0, 0xa5, 0x49, 0x42, 0xab, 0x59, 0xb7, 0xe4, + 0xb9, 0x7f, 0x08, 0x3c, 0x21, 0x77, 0x62, 0xcd, 0x16, 0x38, + 0x29, 0xda, 0x02, 0x4a, 0x42, 0xe6, 0x47, 0x6d, 0x04, 0x8a, + 0x33, 0xd3, 0x6d, 0xf5, 0x28, 0xc2, 0x4c, 0x37, 0x3a, 0x14, + 0x5b, 0xa6, 0xe3, 0xe6, 0xc2, 0xa8, 0x46, 0x60, 0xc3, 0xe3, + 0x1a, 0x83, 0x26, 0x20, 0x47, 0xb5, 0x89, 0x5f, 0x56, 0x50, + 0x43, 0x0d, 0xaf, 0x81, 0x17, 0x2c, 0xb1, 0x61, 0x40, 0x9e, + 0x13, 0xe8, 0xab, 0x04, 0xa1, 0xa1, 0x50, 0x22, 0x3f, 0x31, + 0x1f, 0x48, 0x1e, 0xd8, 0x12, 0x9c, 0x20, 0x49, 0x49, 0x82, + 0x17, 0xf6, 0x5a, 0xad, 0xdc, 0x72, 0x09, 0xbc, 0x02, 0xcf, + 0xc5, 0xba, 0x65, 0x3b, 0x65, 0xd1, 0xed, 0x29, 0x81, 0x9f, + 0x75, 0xc9, 0xa0, 0x86, 0xd5, 0xd3, 0x92, 0xc9, 0x53, 0xaa, + 0x5b, 0xb2, 0x52, 0x4a, 0x35, 0x4b, 0x96, 0x0a, 0xf3, 0x0b, + 0x6c, 0x56, 0x6b, 0xb0, 0x66, 0xd4, 0xc5, 0x2e, 0xa1, 0xa0, + 0x24, 0x24, 0x7e, 0xd6, 0x55, 0xbb, 0xec, 0x65, 0xc5, 0x2e, + 0x7b, 0x59, 0xad, 0xcb, 0x36, 0x16, 0x5a, 0xac, 0xf3, 0xb7, + 0x91, 0x8a, 0x9f, 0x58, 0xb4, 0x57, 0xdf, 0x69, 0x2a, 0x14, + 0xeb, 0x2d, 0xb6, 0xd7, 0xc8, 0xc6, 0xd2, 0xca, 0xe1, 0xfb, + 0x5a, 0x1b, 0x5b, 0x05, 0xe0, 0x0e, 0x5f, 0x71, 0x12, 0xda, + 0xc0, 0x47, 0x86, 0x6e, 0x37, 0x52, 0x70, 0x0f, 0xca, 0x9f, + 0x91, 0x10, 0x91, 0x02, 0x74, 0x9b, 0x9b, 0xc6, 0x44, 0xbe, + 0xe5, 0xcd, 0x25, 0xdf, 0xaa, 0x88, 0x74, 0x14, 0x22, 0x7d, + 0x89, 0x90, 0xbe, 0x04, 0x48, 0x0b, 0xa6, 0xfc, 0x02, 0x99, + 0xb0, 0xcd, 0x49, 0x4d, 0x13, 0x58, 0x60, 0x0a, 0x6f, 0x2c, + 0xf9, 0xc6, 0x92, 0x7d, 0xb1, 0x64, 0xca, 0x4a, 0x4d, 0xaf, + 0x11, 0x1f, 0x99, 0xbc, 0xc5, 0x84, 0xc2, 0xcf, 0x7e, 0x85, + 0xf8, 0x6b, 0xac, 0xd7, 0xd0, 0x8d, 0x62, 0x5b, 0x48, 0x94, + 0x5a, 0xb7, 0x54, 0x87, 0x0c, 0xae, 0x78, 0x52, 0xb9, 0x27, + 0xb9, 0x31, 0xbc, 0xee, 0x90, 0xa5, 0x1b, 0x3f, 0xc8, 0xe4, + 0x12, 0x75, 0x93, 0x0d, 0xda, 0xe8, 0x51, 0x47, 0xf0, 0x62, + 0xb9, 0xae, 0xa2, 0x50, 0x6d, 0xe3, 0x4d, 0xbd, 0xb6, 0xf8, + 0x10, 0x51, 0xc2, 0xa0, 0x06, 0x9b, 0xba, 0x6a, 0x9c, 0x15, + 0x95, 0x8b, 0x12, 0x2d, 0x8a, 0x46, 0x5d, 0x5b, 0xcb, 0x24, + 0xba, 0x98, 0x6f, 0xee, 0x1c, 0xfe, 0x29, 0x8d, 0x3b, 0xce, + 0x42, 0x52, 0xd7, 0x62, 0x34, 0x71, 0xcb, 0x76, 0x8b, 0x9f, + 0xc9, 0x29, 0x63, 0xf4, 0x65, 0x9f, 0xe3, 0x52, 0x83, 0xcb, + 0xb3, 0xea, 0x51, 0x61, 0x6a, 0xf1, 0x0e, 0x0e, 0x00, 0x1c, + 0x9d, 0x62, 0xc8, 0xe2, 0x41, 0x8b, 0xe1, 0xcd, 0x91, 0x8f, + 0x54, 0xc3, 0xb1, 0x1d, 0x53, 0x3c, 0xde, 0xb4, 0x72, 0x87, + 0x81, 0x51, 0x22, 0x45, 0xc2, 0xe5, 0x7e, 0xde, 0x06, 0xec, + 0x38, 0x89, 0x59, 0x95, 0x1f, 0xd2, 0x89, 0x10, 0xed, 0xda, + 0x61, 0x3c, 0x4d, 0x71, 0x0d, 0x64, 0x86, 0x32, 0x4b, 0x40, + 0x7c, 0xcb, 0x5c, 0x83, 0xe8, 0x5b, 0x11, 0x2e, 0xae, 0xa4, + 0xe5, 0x3b, 0x0c, 0x63, 0xc6, 0xe1, 0x06, 0x77, 0x1f, 0x87, + 0x81, 0xee, 0x20, 0xf8, 0x2d, 0xa3, 0xc9, 0xba, 0x9c, 0x32, + 0x31, 0xb4, 0x7e, 0xe2, 0x71, 0xd0, 0x66, 0x58, 0x08, 0x92, + 0x7c, 0x8b, 0xa2, 0xb7, 0x38, 0x3a, 0x0d, 0xde, 0x51, 0x64, + 0x14, 0xe2, 0x21, 0x1c, 0x4c, 0x43, 0x7d, 0xf8, 0x8c, 0xd7, + 0x87, 0x33, 0x0a, 0x1d, 0x46, 0x28, 0x50, 0x2a, 0x1a, 0xe3, + 0xc3, 0x6a, 0x6f, 0x8d, 0xfe, 0xaf, 0x15, 0xe0, 0xaa, 0xef, + 0x6c, 0x97, 0xb1, 0xfb, 0xd8, 0x70, 0xa0, 0x0c, 0xf4, 0x2a, + 0x4b, 0xa0, 0x8b, 0x47, 0x14, 0x47, 0xa8, 0x68, 0x98, 0x46, + 0xab, 0x11, 0x1a, 0xf0, 0xd4, 0xf5, 0x9b, 0x8d, 0x8e, 0xe6, + 0xa4, 0xa3, 0x95, 0x3b, 0x8c, 0x8c, 0x12, 0x29, 0x1a, 0xd5, + 0xdc, 0x58, 0xb4, 0x61, 0x50, 0xb7, 0xf9, 0xee, 0xa3, 0xe9, + 0xd5, 0x50, 0xed, 0x46, 0x9b, 0xcf, 0x71, 0x43, 0xc0, 0x65, + 0x9c, 0x19, 0xd2, 0x0f, 0x9d, 0xde, 0x45, 0x49, 0x1f, 0x98, + 0x97, 0xd1, 0x6e, 0xaf, 0xa1, 0xf0, 0x38, 0xbd, 0xdd, 0x7a, + 0x2c, 0x4c, 0x81, 0xc9, 0x7c, 0xe9, 0x4f, 0x3e, 0xe8, 0x00, + 0x39, 0x5f, 0x3c, 0x82, 0xab, 0xed, 0x3a, 0xd1, 0x3c, 0xe5, + 0x57, 0x81, 0xf1, 0x0a, 0x27, 0x44, 0x14, 0x4a, 0xa5, 0x5d, + 0xc6, 0x6c, 0x3e, 0x65, 0x4b, 0x8e, 0xac, 0xd2, 0x4f, 0x3a, + 0x67, 0xa8, 0x6d, 0xa2, 0x98, 0x78, 0x92, 0xa5, 0xaa, 0xec, + 0xe4, 0x3a, 0x3d, 0x12, 0x6e, 0x4f, 0x18, 0xdb, 0xfd, 0x3d, + 0xaa, 0xf4, 0x6b, 0x67, 0x87, 0xd6, 0x2e, 0x19, 0x73, 0x92, + 0xde, 0x9f, 0xbb, 0xbe, 0x1d, 0xee, 0x2a, 0xfa, 0x7f, 0x5c, + 0xd8, 0x7f, 0x52, 0xad, 0xfb, 0x08, 0xda, 0xe7, 0x7b, 0x48, + 0x32, 0x10, 0x95, 0xf6, 0x5b, 0x4c, 0x55, 0xd4, 0x41, 0x5e, + 0x25, 0x14, 0x8a, 0x76, 0xcb, 0xb4, 0x95, 0xa6, 0x00, 0xe7, + 0x4e, 0x4c, 0x21, 0x53, 0xb7, 0x49, 0x68, 0x48, 0x2d, 0xaa, + 0xad, 0x90, 0xea, 0x72, 0x37, 0xf8, 0x52, 0xc7, 0x36, 0xa3, + 0x83, 0x5f, 0xdb, 0x68, 0xa8, 0x19, 0x03, 0x75, 0x2a, 0x42, + 0x14, 0xb9, 0x0e, 0x88, 0x96, 0x76, 0x55, 0xca, 0xbe, 0xc1, + 0xd5, 0xcc, 0x98, 0x2d, 0xa6, 0x43, 0x4d, 0x17, 0x6e, 0x83, + 0xda, 0xf2, 0x3e, 0x20, 0xea, 0x0b, 0xa8, 0xf0, 0xd6, 0x9f, + 0x2c, 0xc6, 0xe6, 0xe8, 0x5c, 0x53, 0x27, 0x42, 0x64, 0xc3, + 0x64, 0xeb, 0xc5, 0x2e, 0xba, 0xab, 0x49, 0x99, 0x8c, 0xee, + 0x42, 0x02, 0x32, 0x92, 0xdd, 0x98, 0x2f, 0xe8, 0x07, 0x01, + 0x87, 0x36, 0x99, 0x92, 0xab, 0x17, 0xb9, 0x28, 0x5b, 0xd7, + 0xb7, 0x38, 0x1f, 0xfa, 0x09, 0x3c, 0xe9, 0x50, 0x5a, 0x00, + 0xce, 0x97, 0x7e, 0xdb, 0x2a, 0x8d, 0x06, 0xca, 0x38, 0xc0, + 0xd3, 0x4e, 0x52, 0x0e, 0xf4, 0x40, 0xfb, 0xd6, 0x8d, 0x23, + 0x0b, 0xf2, 0x9c, 0xb5, 0x09, 0x5c, 0x9f, 0xe6, 0xa8, 0x81, + 0x5f, 0xb1, 0x03, 0x3e, 0xde, 0xf4, 0x73, 0xf2, 0xa7, 0x42, + 0x8e, 0x81, 0xf5, 0xe5, 0xce, 0xb7, 0xa5, 0xed, 0x01, 0xeb, + 0xce, 0x5e, 0xc6, 0x34, 0xc3, 0xb0, 0xb1, 0x44, 0xfa, 0xc0, + 0x4a, 0xb9, 0x48, 0xbe, 0x36, 0x76, 0x9b, 0xf9, 0x51, 0x57, + 0xf4, 0xfe, 0x93, 0xd8, 0xcc, 0xb7, 0x5e, 0xd4, 0xe4, 0xaa, + 0x7a, 0x9a, 0xdd, 0x1f, 0x92, 0x9a, 0x15, 0x69, 0x43, 0x25, + 0x5a, 0x26, 0x18, 0x0d, 0x70, 0x4a, 0xe0, 0xfc, 0xc4, 0x61, + 0xe0, 0x55, 0x88, 0xd7, 0x33, 0xae, 0x61, 0x25, 0xab, 0xa9, + 0x64, 0x55, 0xe5, 0x93, 0x14, 0x57, 0x21, 0xb6, 0xcc, 0x3b, + 0x20, 0xb6, 0xcc, 0x2e, 0x2e, 0x04, 0xf9, 0x24, 0x76, 0x16, + 0x97, 0x28, 0x13, 0x35, 0xa9, 0x9b, 0xe9, 0x41, 0x69, 0xed, + 0x69, 0x91, 0xb0, 0xa9, 0x3b, 0xb7, 0xb6, 0xc0, 0x4b, 0x22, + 0x8e, 0xe5, 0x97, 0x39, 0xbb, 0x5d, 0xa0, 0xda, 0x69, 0xc0, + 0x72, 0x1f, 0xba, 0x51, 0x45, 0xb8, 0xc5, 0xdf, 0x25, 0x7d, + 0x04, 0xe1, 0x4e, 0x72, 0x88, 0x3a, 0x59, 0xd6, 0xc8, 0x20, + 0x2b, 0xc3, 0xc7, 0x5a, 0xb7, 0x69, 0x2f, 0xd8, 0x20, 0x38, + 0xab, 0x28, 0xc7, 0x31, 0xca, 0x84, 0x7c, 0x2e, 0x09, 0xae, + 0x37, 0xb7, 0x1b, 0x0f, 0xb4, 0x8c, 0xb0, 0xbf, 0xdc, 0x44, + 0x53, 0xfb, 0xb1, 0xf4, 0xc0, 0xc6, 0x2b, 0xc4, 0x64, 0x0b, + 0x9d, 0x1b, 0x0a, 0x2c, 0xee, 0x26, 0x08, 0x8d, 0x43, 0x2a, + 0x08, 0xc4, 0xb8, 0xad, 0x38, 0x78, 0x62, 0x2b, 0x4d, 0x5c, + 0x0f, 0x4a, 0x1e, 0x00, 0x27, 0xd4, 0xc9, 0xdc, 0x72, 0xbf, + 0x00, 0xf0, 0x50, 0x76, 0x22, 0xad, 0x5b, 0xe7, 0xd6, 0xee, + 0xc1, 0xc1, 0xb6, 0x1a, 0x83, 0xad, 0x95, 0xa3, 0xac, 0x05, + 0x3c, 0xaf, 0xd0, 0x59, 0xb6, 0x17, 0x2f, 0xd9, 0xa4, 0x8d, + 0x08, 0xd8, 0x85, 0x6d, 0xc0, 0xef, 0x8a, 0x57, 0xce, 0x9b, + 0xeb, 0xbf, 0xae, 0xfb, 0x66, 0xbe, 0x05, 0xe0, 0x59, 0xd9, + 0x0a, 0x4f, 0xb5, 0xa1, 0x32, 0x0d, 0xc2, 0xf8, 0x9e, 0x79, + 0xca, 0xec, 0x72, 0x1f, 0x45, 0xc4, 0x01, 0x4b, 0x5c, 0xb3, + 0xa3, 0xb8, 0x47, 0xda, 0x0e, 0x4b, 0x7b, 0x18, 0x3c, 0xf9, + 0x3d, 0xd1, 0xce, 0xdf, 0xcb, 0x95, 0xf7, 0x47, 0xc3, 0x5f, + 0xbb, 0x11, 0x5d, 0x71, 0x54, 0x13, 0x2f, 0x86, 0x84, 0xf8, + 0x61, 0x57, 0xe2, 0xf7, 0xc0, 0x76, 0x70, 0x1e, 0x8c, 0x94, + 0xdb, 0xf1, 0xcf, 0x0a, 0xc2, 0xd2, 0x26, 0x0a, 0x86, 0x03, + 0x49, 0x67, 0x65, 0xd9, 0x4f, 0xb2, 0xe7, 0x4b, 0xa6, 0x81, + 0xc4, 0xef, 0x7c, 0x4f, 0x49, 0xfb, 0x2f, 0xd9, 0x56, 0x3b, + 0x6f, 0x4d, 0x03, 0x84, 0x8f, 0x41, 0x16, 0xa7, 0x56, 0x2e, + 0xec, 0x19, 0x40, 0x2a, 0x58, 0x81, 0x46, 0xb6, 0x35, 0x85, + 0xaf, 0x2e, 0x06, 0x07, 0x90, 0x75, 0xcf, 0xe7, 0x8e, 0xf6, + 0x16, 0x61, 0x17, 0xb4, 0xdb, 0xfd, 0xcd, 0x20, 0xf7, 0x02, + 0x57, 0x3a, 0x7f, 0x87, 0x82, 0x4d, 0x41, 0x48, 0xa8, 0x5d, + 0x39, 0x7b, 0xcf, 0x42, 0xdd, 0x74, 0x14, 0xca, 0x07, 0xe5, + 0x6b, 0x17, 0xb1, 0xb7, 0x2b, 0xa7, 0x7b, 0xd3, 0x85, 0xee, + 0x4b, 0x39, 0xdd, 0x6f, 0x5d, 0xe8, 0x62, 0x8f, 0x74, 0x8e, + 0xb2, 0x1e, 0xc4, 0x76, 0xf5, 0x4c, 0x34, 0xf4, 0x34, 0x2f, + 0xa3, 0x7e, 0xd3, 0x8d, 0xfa, 0x26, 0xaa, 0xe8, 0xf9, 0xb7, + 0x3e, 0xb9, 0x91, 0xbd, 0xfd, 0x95, 0x32, 0xe3, 0x51, 0xd5, + 0xcd, 0x50, 0x8a, 0x25, 0xf1, 0xfd, 0xf3, 0xc9, 0x75, 0xd0, + 0xb3, 0x58, 0xa5, 0x1f, 0xfa, 0x3e, 0xd7, 0xd4, 0x17, 0x52, + 0xa3, 0xcb, 0x54, 0xe2, 0x96, 0xd3, 0x38, 0xa3, 0x06, 0x4d, + 0x5f, 0x25, 0x55, 0x7a, 0xdc, 0xf8, 0x50, 0xcf, 0x35, 0xec, + 0xd2, 0x77, 0x05, 0x32, 0xd5, 0xc7, 0x42, 0x86, 0x4d, 0xbf, + 0x14, 0x6b, 0x2a, 0xb2, 0x7d, 0x0a, 0xac, 0x9b, 0x90, 0xcd, + 0x7c, 0x19, 0xda, 0xc3, 0x70, 0x18, 0x6a, 0x16, 0x88, 0xc9, + 0x50, 0x07, 0x0d, 0x90, 0x0e, 0x4d, 0x8b, 0xd2, 0x38, 0x60, + 0x53, 0xa8, 0x54, 0xd1, 0x69, 0x60, 0x47, 0xbf, 0x0f, 0x1c, + 0x1b, 0x2e, 0x18, 0x18, 0xee, 0x9a, 0xd8, 0x01, 0x68, 0x6e, + 0xe2, 0x8c, 0x80, 0x82, 0x29, 0xf4, 0x93, 0x9b, 0x3b, 0x7d, + 0x99, 0x99, 0x9f, 0xb7, 0x79, 0x51, 0x0b, 0xe1, 0x05, 0x61, + 0xe6, 0x36, 0xb9, 0xef, 0xd2, 0x04, 0xbd, 0xb8, 0xb2, 0x82, + 0x6b, 0xff, 0x04, 0x43, 0xb9, 0x80, 0xf3, 0xda, 0x70, 0x24, + 0x99, 0x81, 0x06, 0xd5, 0xfd, 0x69, 0x06, 0x82, 0x1e, 0x81, + 0x9a, 0xbe, 0xd3, 0xd0, 0x0c, 0xa1, 0x4c, 0xed, 0x5e, 0xc7, + 0x32, 0x35, 0xdb, 0xbc, 0xfc, 0x0d, 0xee, 0xbd, 0x20, 0x0c, + 0x36, 0xf7, 0x3b, 0xaf, 0xd1, 0xc2, 0xd0, 0x07, 0x5b, 0xb6, + 0x7e, 0xaf, 0xe3, 0xf9, 0xd7, 0x3f, 0x57, 0x7b, 0xe3, 0x36, + 0x6c, 0xe6, 0x6d, 0x83, 0x10, 0x44, 0x4b, 0xe0, 0x36, 0x09, + 0x37, 0xa0, 0xc1, 0x5e, 0x5c, 0xfd, 0x9f, 0x80, 0xdb, 0xe6, + 0xf7, 0xbb, 0x65, 0xb0, 0xdc, 0x41, 0x31, 0xde, 0x68, 0x3c, + 0xd4, 0xee, 0xc6, 0xd6, 0xff, 0x59, 0xc6, 0x03, 0xc2, 0x5d, + 0x7c, 0x1f, 0x36, 0x1b, 0xd1, 0x21, 0x37, 0x22, 0x4a, 0xe1, + 0x27, 0x18, 0x13, 0x01, 0x4a, 0xd1, 0xe3, 0x87, 0x26, 0xe3, + 0x11, 0xb1, 0x52, 0x14, 0xdd, 0xfc, 0xdc, 0x9b, 0xcb, 0xa2, + 0xde, 0x15, 0x2f, 0x45, 0x80, 0x37, 0x39, 0xe8, 0x0c, 0x6f, + 0x72, 0xae, 0x1a, 0x15, 0x78, 0x29, 0xe7, 0x36, 0xbc, 0xa8, + 0x8e, 0xc7, 0x57, 0x3f, 0x01, 0x66, 0xca, 0xb5, 0x36, 0x2e, + 0xc7, 0x4c, 0xc9, 0x0c, 0x22, 0xbd, 0x82, 0x64, 0xe0, 0x95, + 0x6f, 0xa9, 0x95, 0x15, 0x67, 0x63, 0x9b, 0x36, 0xc1, 0xc5, + 0x98, 0x9d, 0x1b, 0x79, 0xdf, 0xf6, 0xd9, 0xad, 0x3c, 0xe4, + 0xf2, 0xc5, 0x78, 0xa6, 0x9a, 0x79, 0xcf, 0xf6, 0x0b, 0x2f, + 0xb0, 0xe5, 0x01, 0x2a, 0x2e, 0x46, 0x5f, 0x19, 0x9c, 0xfe, + 0x23, 0x7a, 0xf4, 0x3f, 0x83, 0x56, 0x7e, 0xae, 0x82, 0x85, + 0xb8, 0xd2, 0x2a, 0x2c, 0x75, 0x5d, 0x80, 0x2c, 0x6a, 0x75, + 0xc3, 0x6a, 0x20, 0x5c, 0xde, 0x27, 0x60, 0x03, 0xe9, 0x54, + 0x07, 0xd4, 0x06, 0xd2, 0xa5, 0x5e, 0xa1, 0x1b, 0x70, 0x9f, + 0x78, 0xfc, 0x06, 0xdc, 0xca, 0xab, 0x81, 0x38, 0xf8, 0xa2, + 0x51, 0x86, 0x58, 0x5d, 0xbb, 0x90, 0x04, 0x39, 0x92, 0xc8, + 0xd6, 0xda, 0x85, 0xa2, 0x93, 0xa3, 0x88, 0x2c, 0xac, 0x9d, + 0x6c, 0xcd, 0xd4, 0xd2, 0x9c, 0x45, 0x27, 0x54, 0x0d, 0x5c, + 0xd6, 0x12, 0x4c, 0x6d, 0xcc, 0x19, 0xd9, 0x8a, 0xc1, 0x4b, + 0x53, 0x75, 0xf2, 0xa1, 0x14, 0xe5, 0x13, 0x20, 0x6b, 0x59, + 0x7e, 0x35, 0xf8, 0x0e, 0xd7, 0x0e, 0xad, 0xfb, 0x5d, 0xf6, + 0xb8, 0x3a, 0x52, 0x75, 0xe5, 0x6a, 0xb7, 0x09, 0xe2, 0x7b, + 0x10, 0xf1, 0x04, 0xa5, 0x91, 0x6d, 0x10, 0x45, 0x6c, 0x19, + 0x61, 0x69, 0xea, 0xe4, 0x43, 0x47, 0x67, 0x2a, 0xed, 0x39, + 0x06, 0xa1, 0x6f, 0x7b, 0x55, 0x2f, 0x6d, 0x25, 0x5a, 0x08, + 0x85, 0x8a, 0x48, 0x68, 0xe4, 0xde, 0xdf, 0x4a, 0x54, 0x92, + 0x42, 0x08, 0x50, 0x20, 0xba, 0x10, 0xa4, 0x86, 0x66, 0x87, + 0x8b, 0x2b, 0xc8, 0xbe, 0xa6, 0xc6, 0xcb, 0x62, 0xc4, 0x5a, + 0x89, 0x04, 0xc6, 0xcc, 0x91, 0x0a, 0xfb, 0x4d, 0x5c, 0x2d, + 0xf8, 0xb3, 0x55, 0xfb, 0x6a, 0x4e, 0xd5, 0xeb, 0x26, 0x59, + 0x87, 0xf3, 0x27, 0xd3, 0x62, 0x3c, 0x16, 0x0c, 0x1f, 0x17, + 0x28, 0x53, 0x69, 0xd2, 0xf9, 0xbd, 0x8a, 0xaa, 0xea, 0x95, + 0x2e, 0xc2, 0x8f, 0xaa, 0x71, 0x22, 0xff, 0x53, 0xab, 0xbc, + 0x0e, 0x30, 0xee, 0x14, 0x32, 0xe5, 0x12, 0xa4, 0xf3, 0x99, + 0x2f, 0x24, 0x50, 0xcd, 0x91, 0x85, 0x7a, 0x8f, 0xae, 0x5d, + 0x08, 0x5e, 0x3c, 0x99, 0x60, 0xc9, 0x11, 0x0c, 0x78, 0x82, + 0x8d, 0xe2, 0x70, 0xa2, 0xc0, 0x7b, 0x04, 0xce, 0xec, 0x79, + 0xb7, 0x02, 0x8d, 0xd4, 0xf5, 0x13, 0x26, 0x1c, 0x87, 0xd0, + 0x50, 0x52, 0x22, 0x3d, 0xdf, 0x13, 0x27, 0x6d, 0xa2, 0xd2, + 0xdd, 0xd0, 0x40, 0xe1, 0x12, 0x4d, 0xc3, 0xd2, 0x3f, 0x51, + 0x34, 0x01, 0x37, 0x54, 0x58, 0x12, 0xbd, 0x0e, 0xea, 0xef, + 0x6d, 0xcc, 0x12, 0xf7, 0x61, 0x10, 0xc7, 0x5e, 0xc5, 0xd3, + 0xc1, 0xa7, 0xcc, 0x9e, 0x42, 0xcb, 0x76, 0xee, 0x36, 0xab, + 0x21, 0xb4, 0xe9, 0xf6, 0xfc, 0xaa, 0xc9, 0xf4, 0x67, 0xea, + 0xf8, 0xe6, 0xaa, 0xaf, 0x29, 0x6f, 0xe3, 0xaf, 0xeb, 0x04, + 0x4d, 0x60, 0x31, 0x3f, 0x7d, 0xa2, 0xde, 0xb4, 0xb0, 0x26, + 0xbc, 0x98, 0xc4, 0x09, 0xcc, 0x5c, 0xbf, 0x5c, 0x73, 0xdd, + 0x0e, 0x57, 0x76, 0x60, 0x23, 0x19, 0xf8, 0x2d, 0x08, 0xd6, + 0x3c, 0xd4, 0x77, 0xbc, 0x65, 0xd0, 0xbd, 0x8f, 0x98, 0x64, + 0xeb, 0xb8, 0xbc, 0x42, 0x2a, 0x34, 0x7c, 0xb4, 0x4b, 0xea, + 0xb6, 0x4f, 0x32, 0xfb, 0x82, 0x5b, 0x4d, 0x61, 0xb7, 0x23, + 0x84, 0x74, 0x0b, 0x70, 0x57, 0xf2, 0x99, 0x08, 0x64, 0x49, + 0xda, 0x9c, 0x2f, 0xba, 0xba, 0x14, 0xb2, 0x5e, 0x0d, 0x08, + 0x66, 0x5e, 0xcb, 0xeb, 0xd9, 0xb7, 0xd9, 0x6c, 0x62, 0xe9, + 0x9a, 0xa1, 0x89, 0x98, 0xe1, 0x3a, 0x54, 0x24, 0xe2, 0x64, + 0x12, 0xf7, 0xaa, 0x2a, 0x8f, 0x44, 0x4f, 0x2a, 0x3c, 0xda, + 0x91, 0x5f, 0x53, 0x2d, 0x9f, 0xd4, 0x0a, 0xd7, 0x9b, 0x6d, + 0xe3, 0x9a, 0x8a, 0x86, 0x99, 0x62, 0x47, 0x1e, 0x51, 0xb0, + 0xc5, 0x60, 0x83, 0xbb, 0x8a, 0xdf, 0xc4, 0x1b, 0x7b, 0x6d, + 0x19, 0x20, 0x86, 0x02, 0x67, 0x0b, 0x8f, 0xa2, 0x90, 0xe1, + 0xaa, 0x0a, 0x56, 0x3b, 0x60, 0xb3, 0x76, 0xa6, 0x55, 0x15, + 0xa6, 0x58, 0x43, 0xae, 0xcb, 0x48, 0xb4, 0xe7, 0x3b, 0xee, + 0xbd, 0x38, 0xbb, 0xe9, 0x31, 0x4c, 0x43, 0xba, 0xd6, 0x93, + 0x77, 0x3c, 0x1c, 0x77, 0xe9, 0x73, 0x7a, 0x6e, 0xb6, 0x0e, + 0xd9, 0xd9, 0x7a, 0x7b, 0x54, 0xcf, 0x4f, 0x65, 0xe2, 0x55, + 0x69, 0x6c, 0xc3, 0x3b, 0x7b, 0x09, 0x86, 0xe0, 0xce, 0x4b, + 0xa3, 0x4d, 0x2a, 0x66, 0xf5, 0x88, 0x9d, 0xd5, 0x84, 0x82, + 0x92, 0x90, 0x50, 0x58, 0x1a, 0xdf, 0x75, 0x86, 0x6d, 0x02, + 0x42, 0x96, 0x01, 0x1a, 0x79, 0xbd, 0xba, 0x70, 0xe8, 0x60, + 0x0d, 0x8f, 0x26, 0x22, 0x01, 0xa3, 0xc2, 0x4c, 0x2c, 0xc2, + 0x24, 0xd1, 0x3c, 0x01, 0xb8, 0xa6, 0x92, 0x54, 0xcd, 0xb2, + 0xae, 0xb4, 0xf1, 0x63, 0x0d, 0x7a, 0xcd, 0x06, 0xac, 0x6b, + 0xf3, 0x7c, 0xbe, 0x06, 0x1d, 0x6c, 0x2a, 0x13, 0x36, 0xfc, + 0xbe, 0xd0, 0xf4, 0x1b, 0x41, 0xea, 0x26, 0xe9, 0x94, 0x24, + 0xfc, 0xe3, 0xc9, 0x79, 0x12, 0xf1, 0x07, 0xca, 0xeb, 0x78, + 0x57, 0x72, 0x0b, 0x56, 0xb2, 0x52, 0x85, 0x3a, 0xc9, 0xd1, + 0xfe, 0x49, 0xf1, 0xd2, 0x71, 0x39, 0x9a, 0xde, 0xfd, 0xe8, + 0xf1, 0x9d, 0x6f, 0xe3, 0x38, 0xf0, 0xb5, 0x47, 0x01, 0x5c, + 0x3d, 0xc7, 0x87, 0xd4, 0xc2, 0x86, 0x2b, 0x28, 0x49, 0x0d, + 0x39, 0x07, 0x04, 0x5c, 0x85, 0x27, 0xd0, 0x41, 0xf8, 0x15, + 0x68, 0x69, 0x15, 0x54, 0xea, 0x72, 0x73, 0x2f, 0x9d, 0x02, + 0x6f, 0xf2, 0xdc, 0xf0, 0x33, 0xbd, 0x7e, 0x3c, 0x18, 0x96, + 0xfa, 0x90, 0x7f, 0xdf, 0x2c, 0xdc, 0xe6, 0x42, 0x9f, 0x5a, + 0x79, 0x1f, 0x72, 0x73, 0x1b, 0x22, 0xa0, 0xcf, 0x3b, 0xc5, + 0x71, 0xa3, 0x0d, 0x4e, 0x64, 0xbe, 0x57, 0x49, 0x40, 0xd4, + 0x7d, 0x48, 0x7d, 0xbf, 0xbe, 0xfa, 0x60, 0xac, 0xa9, 0xba, + 0xa0, 0x00, 0x0d, 0x3c, 0x60, 0x87, 0xf5, 0x55, 0xbf, 0xe8, + 0x23, 0x53, 0xdb, 0x17, 0x54, 0xa0, 0x2f, 0xa1, 0x0b, 0x37, + 0xc9, 0x18, 0xbd, 0x43, 0xff, 0x7f, 0xfb, 0x35, 0x75, 0x0f, + 0x84, 0xec, 0x1d, 0x6c, 0xdd, 0x03, 0x29, 0x11, 0x42, 0xf6, + 0x4f, 0x8a, 0x11, 0xf0, 0x1c, 0xf7, 0x11, 0xb3, 0x36, 0x0f, + 0x9e, 0x40, 0x58, 0x92, 0x44, 0x56, 0xe0, 0x27, 0x1a, 0x9f, + 0x80, 0xea, 0x30, 0x49, 0x63, 0x7b, 0xe0, 0xa9, 0x2e, 0x31, + 0x09, 0xf3, 0x2f, 0xba, 0x35, 0x9c, 0x7d, 0x11, 0x03, 0xa7, + 0x48, 0x2f, 0xb1, 0x35, 0x51, 0xf6, 0xb1, 0x21, 0xa5, 0x94, + 0x4f, 0x28, 0x4b, 0x89, 0xb5, 0xca, 0x89, 0x9a, 0x11, 0xc6, + 0x79, 0x82, 0xd2, 0x07, 0x8d, 0xc3, 0x02, 0xea, 0x38, 0x69, + 0x50, 0x83, 0x8c, 0x99, 0xc6, 0xe0, 0x4a, 0x1b, 0x5a, 0xfc, + 0x14, 0x50, 0x25, 0x65, 0x79, 0x0f, 0x9c, 0xad, 0x87, 0x3c, + 0xe4, 0x5a, 0xcd, 0xc5, 0x62, 0x2e, 0xf0, 0x2c, 0xa1, 0xb3, + 0xd8, 0x34, 0xa4, 0x92, 0x4f, 0x2f, 0x9b, 0x12, 0x6a, 0x35, + 0x9b, 0x74, 0xcc, 0x69, 0x07, 0x3f, 0x96, 0x8c, 0xb8, 0xbc, + 0xa7, 0x75, 0xc0, 0x95, 0x56, 0x08, 0xd6, 0xb6, 0xeb, 0xb3, + 0xd8, 0x95, 0x50, 0x7f, 0x41, 0x9f, 0xf0, 0x6d, 0xa7, 0x3d, + 0xae, 0x77, 0x84, 0x7a, 0xc8, 0x81, 0x86, 0xa7, 0x7d, 0x76, + 0x9a, 0xc2, 0x00, 0xc9, 0x6c, 0xed, 0xc1, 0xbd, 0xed, 0xfb, + 0xc0, 0x93, 0x39, 0x2f, 0x3e, 0xf1, 0x8b, 0x93, 0xd4, 0x6c, + 0x11, 0x7d, 0xe4, 0xdb, 0x74, 0x70, 0x29, 0x95, 0xf6, 0x89, + 0x0d, 0x91, 0xdc, 0xc0, 0x77, 0x87, 0x8f, 0x55, 0xf2, 0x63, + 0x30, 0xb0, 0x5e, 0xe9, 0x5c, 0x9a, 0xdd, 0xdd, 0x49, 0x73, + 0x66, 0xc5, 0xf1, 0x34, 0x93, 0xdf, 0x7a, 0xe6, 0xec, 0xf2, + 0x72, 0x2c, 0xe6, 0xf7, 0x32, 0x83, 0xd5, 0xca, 0x03, 0x0d, + 0xf7, 0xc8, 0xac, 0x54, 0x22, 0x34, 0xed, 0x53, 0x42, 0x2f, + 0x9d, 0xa2, 0xe3, 0x12, 0x82, 0x0d, 0xe6, 0x8a, 0x50, 0x64, + 0x8c, 0x20, 0x27, 0xbc, 0x11, 0x24, 0xa5, 0xdc, 0x40, 0x2e, + 0xa8, 0xd7, 0x9a, 0x28, 0x0f, 0xec, 0x47, 0x90, 0x25, 0xc2, + 0x21, 0x96, 0x79, 0xf9, 0x6c, 0xb9, 0x86, 0xa9, 0xa6, 0x97, + 0x84, 0x53, 0xa6, 0x6f, 0xb1, 0xdd, 0x32, 0x8d, 0xed, 0x77, + 0xdb, 0xf9, 0xf8, 0x56, 0xc2, 0x6e, 0xff, 0x9c, 0xf7, 0xb8, + 0xb8, 0xf9, 0x0f, 0xf6, 0xb9, 0x1b, 0x8d, 0xc2, 0x8b, 0x80, + 0x62, 0x67, 0xf2, 0x06, 0x91, 0x90, 0x8d, 0xba, 0x72, 0x50, + 0x2c, 0x87, 0xea, 0x3b, 0x51, 0x2e, 0x85, 0xda, 0x4b, 0x9f, + 0x88, 0x7d, 0xa1, 0x4a, 0xba, 0x40, 0x85, 0x8e, 0xd1, 0x63, + 0x20, 0x65, 0x93, 0xbd, 0x93, 0x13, 0x31, 0x33, 0xbf, 0xbb, + 0xa3, 0xec, 0x18, 0x38, 0xe7, 0x21, 0x7a, 0x8c, 0xf7, 0x71, + 0x0e, 0xbc, 0x8a, 0x15, 0xca, 0x84, 0xd2, 0x58, 0x1b, 0x2a, + 0x6c, 0x1d, 0x29, 0x45, 0xb0, 0x9f, 0x85, 0x79, 0x8d, 0x8b, + 0x15, 0xe6, 0x7d, 0xf9, 0x69, 0x38, 0xe2, 0xf7, 0xcc, 0xf7, + 0x9b, 0x8c, 0x7a, 0xe3, 0x96, 0xfc, 0x20, 0x8e, 0x59, 0x8b, + 0xd6, 0x5f, 0x6c, 0x3d, 0xe1, 0x90, 0xe6, 0x5f, 0x26, 0x95, + 0xc3, 0x3f, 0x61, 0x87, 0x8f, 0x0b, 0x37, 0x7d, 0xbb, 0x48, + 0xc4, 0x53, 0x37, 0x0b, 0x1e, 0xb1, 0xc3, 0xd0, 0x54, 0xd0, + 0xe4, 0x57, 0x71, 0x94, 0xea, 0xbf, 0xfe, 0x29, 0xa7, 0x69, + 0x3a, 0xdb, 0x78, 0x67, 0x2d, 0x77, 0x4b, 0x6a, 0x1a, 0x1c, + 0xc2, 0x2f, 0xca, 0x80, 0x7c, 0x69, 0x44, 0xbb, 0x4e, 0xbe, + 0xd7, 0x4c, 0x32, 0x35, 0xe5, 0xbe, 0x4d, 0xb0, 0xcc, 0x04, + 0x17, 0x7a, 0x73, 0x08, 0x3e, 0x13, 0x74, 0xba, 0xa9, 0x6b, + 0x46, 0x99, 0x59, 0x8f, 0xa6, 0x81, 0xcc, 0xf9, 0x58, 0x48, + 0x2d, 0x46, 0x4f, 0xb9, 0x88, 0xde, 0x13, 0xf7, 0xae, 0x5f, + 0x7f, 0x86, 0x6c, 0x44, 0xfd, 0xf4, 0xa5, 0x30, 0x1f, 0x51, + 0x9e, 0x74, 0x73, 0x2f, 0xae, 0x67, 0x46, 0x2b, 0x40, 0xca, + 0xb0, 0xdf, 0xd5, 0x75, 0x6d, 0x27, 0x10, 0x04, 0x1d, 0x1d, + 0xd7, 0x5e, 0x04, 0x7a, 0x4e, 0x47, 0xb7, 0xb5, 0x6e, 0xd9, + 0x60, 0x92, 0x58, 0xb7, 0x00, 0x65, 0x3c, 0x7a, 0x56, 0xec, + 0x67, 0x37, 0xea, 0x25, 0x5a, 0xaf, 0x55, 0x5e, 0x18, 0xbe, + 0x37, 0xbb, 0x1e, 0x7a, 0xd3, 0x25, 0x41, 0x0c, 0xdf, 0x9b, + 0x97, 0x1e, 0x7a, 0xb3, 0xcd, 0x8c, 0xe2, 0x81, 0xb3, 0xfb, + 0x80, 0x1d, 0x71, 0x95, 0xe7, 0xe7, 0xbe, 0x02, 0xce, 0x0b, + 0x88, 0xef, 0x76, 0x3d, 0x11, 0x7f, 0x2a, 0x20, 0xfe, 0xf2, + 0xd2, 0x57, 0xcf, 0x9f, 0x4b, 0xb0, 0xf3, 0x95, 0xaf, 0xca, + 0x7b, 0xec, 0x80, 0xd9, 0x31, 0xfa, 0xfc, 0x71, 0x57, 0xd6, + 0xc0, 0x8d, 0xf2, 0x1e, 0xb9, 0x62, 0x76, 0xa5, 0xff, 0x52, + 0x46, 0xff, 0x9b, 0xf2, 0x1e, 0x99, 0x0e, 0x3b, 0xd2, 0xdf, + 0xb4, 0xe6, 0x61, 0x31, 0x45, 0x0b, 0x32, 0x1a, 0x3e, 0x97, + 0x32, 0xb1, 0x64, 0x77, 0xfe, 0xe8, 0xb5, 0x3b, 0xbb, 0xae, + 0xdd, 0x09, 0x7b, 0xed, 0xce, 0x4b, 0xd7, 0xee, 0x38, 0x04, + 0x91, 0x96, 0x03, 0xb8, 0x6d, 0x2f, 0xdc, 0x6d, 0x2f, 0x3b, + 0x23, 0x55, 0x4f, 0x04, 0x4c, 0xe9, 0x9c, 0x0d, 0x8d, 0x2a, + 0x46, 0x21, 0xb0, 0xd7, 0x45, 0x29, 0x06, 0x24, 0x34, 0xa4, + 0x83, 0x22, 0x0d, 0x09, 0xd1, 0x6b, 0x9a, 0x70, 0xe0, 0xb9, + 0x28, 0x0d, 0x40, 0x4e, 0x00, 0x74, 0x03, 0x67, 0x67, 0x29, + 0x0b, 0x3b, 0xbf, 0x1b, 0x5a, 0x3b, 0x4b, 0x58, 0xd8, 0xf2, + 0xdd, 0xe1, 0xdb, 0x47, 0x3e, 0x9c, 0x6f, 0xbc, 0x50, 0x22, + 0xa8, 0x28, 0xbb, 0x3e, 0x64, 0x39, 0x0e, 0x29, 0x28, 0x7a, + 0x52, 0xa9, 0x3d, 0x90, 0x6f, 0x06, 0x3a, 0x18, 0xf1, 0xe0, + 0x9f, 0xe2, 0x88, 0xc8, 0x13, 0x5c, 0x9d, 0x3f, 0x65, 0xb8, + 0x05, 0x12, 0xfd, 0xa7, 0x58, 0xde, 0xb0, 0x7c, 0xfb, 0xae, + 0x53, 0x66, 0x7c, 0x2c, 0xf7, 0xaf, 0x94, 0xee, 0x3b, 0xed, + 0xe6, 0xc2, 0x5f, 0x82, 0x30, 0x46, 0xd7, 0xf3, 0x5d, 0xf5, + 0x38, 0x8e, 0x19, 0x3f, 0xea, 0xd4, 0xff, 0x9b, 0xad, 0x5c, + 0xbd, 0x05, 0xae, 0xed, 0xd0, 0x45, 0xd0, 0xea, 0xca, 0x07, + 0xe5, 0x59, 0xa9, 0x76, 0xe3, 0x69, 0xa8, 0xc5, 0x32, 0x94, + 0x77, 0xbd, 0x50, 0x7e, 0x29, 0xa0, 0xfc, 0xd2, 0x0b, 0x65, + 0x06, 0x55, 0x82, 0xa1, 0x8d, 0x32, 0x18, 0xf6, 0x88, 0x28, + 0xc1, 0x50, 0xc6, 0x79, 0x09, 0x7b, 0x83, 0x93, 0x60, 0x08, + 0xdf, 0xd8, 0x4f, 0x1d, 0xc9, 0x16, 0x10, 0xbd, 0xdc, 0x85, + 0xc1, 0x6f, 0x78, 0x36, 0x50, 0xd4, 0x03, 0xe8, 0xe1, 0x54, + 0x2f, 0x69, 0x82, 0xa4, 0x6b, 0xec, 0xa3, 0x8d, 0xb0, 0xb4, + 0x0d, 0x94, 0xfa, 0xb0, 0x8f, 0x16, 0xb6, 0x05, 0x2d, 0xbc, + 0xaa, 0xb6, 0x5d, 0xdc, 0x4e, 0xff, 0x8a, 0x77, 0x71, 0x3b, + 0x4f, 0x4f, 0x3d, 0xb5, 0x73, 0xeb, 0xda, 0x91, 0x55, 0xca, + 0xbc, 0xca, 0x39, 0xfc, 0x73, 0x47, 0x70, 0x10, 0xd4, 0x40, + 0xfd, 0xfa, 0x57, 0xb7, 0xd4, 0xea, 0xf0, 0xa4, 0xf2, 0x57, + 0x8c, 0xe5, 0xc9, 0x0b, 0xed, 0x93, 0x02, 0xa1, 0x5d, 0x0e, + 0x9a, 0x27, 0x4e, 0xda, 0x6b, 0xcc, 0x54, 0xf7, 0xe9, 0xf9, + 0x9e, 0x99, 0x94, 0x97, 0x3b, 0xfb, 0x89, 0x01, 0x5a, 0x8c, + 0x5d, 0x7f, 0x1b, 0x6c, 0xa3, 0xee, 0xf2, 0xcf, 0xbb, 0xf5, + 0xac, 0x10, 0xfc, 0x8f, 0x95, 0xa0, 0xe2, 0xd1, 0x28, 0x54, + 0x1d, 0xfc, 0x4f, 0x82, 0x7f, 0x79, 0xe1, 0x7a, 0xc8, 0x23, + 0xb9, 0x08, 0xd3, 0x51, 0x0a, 0xfe, 0x6c, 0x13, 0xe5, 0x5b, + 0x18, 0x9f, 0x8f, 0xfb, 0x6b, 0x61, 0xb9, 0x8d, 0xe2, 0x60, + 0x6d, 0x15, 0x1d, 0xf1, 0x03, 0xfc, 0x27, 0x05, 0x7f, 0xb9, + 0xf5, 0x40, 0x0e, 0x31, 0xa9, 0x01, 0xf9, 0x9d, 0x04, 0xf9, + 0x9b, 0xf6, 0xe4, 0x5f, 0x24, 0xc8, 0x7f, 0xeb, 0xec, 0xae, + 0x9d, 0xc4, 0xff, 0xa7, 0x33, 0x5f, 0xbd, 0x67, 0x3f, 0xe6, + 0xe2, 0xfe, 0x69, 0x3d, 0x29, 0xbd, 0xf1, 0x15, 0x53, 0xd1, + 0xc3, 0x6b, 0x50, 0x44, 0x7d, 0x21, 0xf5, 0xe4, 0x57, 0x16, + 0xa6, 0xae, 0xb7, 0x7e, 0x04, 0x55, 0xcf, 0x67, 0xd7, 0x9a, + 0x65, 0x5e, 0xe9, 0x9a, 0x71, 0x35, 0x1b, 0x8b, 0xf9, 0x90, + 0x54, 0x1c, 0x12, 0x6c, 0xde, 0x87, 0x20, 0xba, 0x0f, 0x3c, + 0x79, 0x97, 0x28, 0x2e, 0xbb, 0xd2, 0x81, 0x90, 0x5d, 0x09, + 0xcf, 0x85, 0x2c, 0x25, 0xd2, 0xbf, 0x89, 0xfa, 0xd5, 0xba, + 0x1a, 0xa6, 0xe1, 0x0f, 0x87, 0x7c, 0xf7, 0x52, 0xc0, 0x68, + 0x5c, 0xa0, 0x05, 0x5d, 0x75, 0x30, 0x10, 0x5c, 0x34, 0x04, + 0xba, 0xa8, 0x80, 0x2c, 0xdd, 0xf1, 0xcc, 0x30, 0x2d, 0x38, + 0x78, 0xeb, 0x7c, 0x64, 0x0a, 0x7e, 0x1a, 0xe3, 0x00, 0x81, + 0x42, 0x26, 0x88, 0x10, 0x50, 0x00, 0xc7, 0x3d, 0xbc, 0x17, + 0xdf, 0x7a, 0x18, 0x26, 0x1b, 0xa5, 0x62, 0xdd, 0xe4, 0x12, + 0x73, 0xe5, 0x59, 0xfc, 0x94, 0x13, 0x48, 0xa8, 0xa6, 0xc2, + 0x56, 0x6d, 0xf8, 0x2c, 0x74, 0x0e, 0xec, 0x25, 0x14, 0x67, + 0xe9, 0xab, 0x10, 0x49, 0x49, 0xd5, 0x21, 0x94, 0x83, 0x83, + 0x01, 0xe7, 0xe0, 0xbf, 0x5b, 0x59, 0x3c, 0x98, 0x81, 0xd1, + 0x84, 0xb5, 0xe9, 0x97, 0x3e, 0xb6, 0xce, 0x60, 0xa0, 0xcd, + 0x33, 0x4f, 0xc2, 0x7d, 0xbe, 0x95, 0x06, 0xfe, 0x83, 0x85, + 0x5b, 0xf0, 0x80, 0xee, 0x75, 0x24, 0x84, 0xa0, 0x8a, 0xf6, + 0x41, 0x69, 0xbb, 0x1b, 0x8d, 0xd1, 0xf4, 0x72, 0x31, 0xce, + 0x79, 0xdd, 0x32, 0x94, 0x0d, 0x37, 0xb1, 0x60, 0x11, 0x34, + 0x74, 0x79, 0xe0, 0x30, 0x6b, 0x34, 0xbd, 0x98, 0x09, 0xbb, + 0x87, 0xa1, 0x8b, 0x20, 0xc4, 0x34, 0x3f, 0xd8, 0xae, 0xee, + 0x95, 0x91, 0x7f, 0x17, 0x84, 0x6b, 0xbb, 0x11, 0xee, 0x87, + 0x6a, 0x5a, 0xc6, 0x42, 0xbf, 0x50, 0x07, 0x9a, 0xb0, 0x95, + 0x98, 0x26, 0xae, 0x09, 0xaf, 0x2a, 0x6a, 0x9c, 0x06, 0x81, + 0x74, 0xdf, 0x56, 0xc3, 0x47, 0x4f, 0xf2, 0xcc, 0xc8, 0x1c, + 0x72, 0x87, 0xd7, 0xe3, 0xc6, 0xe7, 0x85, 0x88, 0x3b, 0x82, + 0xce, 0x89, 0xc7, 0x4c, 0x0b, 0x4f, 0x39, 0xd4, 0xbc, 0x99, + 0x6b, 0x2d, 0xb3, 0x63, 0x5e, 0x5e, 0xe7, 0xe1, 0x43, 0x12, + 0xcb, 0x32, 0x6d, 0xa7, 0xd4, 0x63, 0xfa, 0x3a, 0x0f, 0x1c, + 0x42, 0xb2, 0x14, 0xe5, 0xea, 0xfe, 0x90, 0x93, 0x6b, 0x34, + 0x9d, 0xce, 0xae, 0xe9, 0xb6, 0xc9, 0xd2, 0x80, 0xd2, 0xd3, + 0xc6, 0x0f, 0x1e, 0x89, 0x48, 0xca, 0xb6, 0x0c, 0x06, 0x91, + 0x94, 0x3f, 0xc4, 0xf8, 0x06, 0x6e, 0x72, 0xc7, 0x59, 0x61, + 0x03, 0x37, 0x0d, 0x36, 0xbe, 0x91, 0xef, 0xff, 0x61, 0x2e, + 0x88, 0xb2, 0x5d, 0xef, 0x79, 0xe2, 0x37, 0xb9, 0x13, 0xae, + 0x80, 0xf8, 0x4d, 0x1b, 0x97, 0x3a, 0xd9, 0x18, 0x58, 0xe9, + 0xdc, 0x3e, 0xaf, 0x9e, 0xb2, 0x1e, 0x1e, 0x9a, 0x14, 0x66, + 0xb7, 0x62, 0x73, 0xd3, 0xb4, 0xb7, 0xe8, 0xb4, 0x4c, 0x0e, + 0x3b, 0x0a, 0x3b, 0x92, 0x92, 0x28, 0x83, 0xb0, 0x5c, 0xe6, + 0x33, 0x39, 0xc2, 0x96, 0xcf, 0x93, 0x3f, 0xe4, 0x08, 0x57, + 0x25, 0x6f, 0x68, 0xf6, 0x5e, 0x4d, 0x90, 0xad, 0x37, 0x7d, + 0xda, 0xfa, 0x30, 0x9e, 0x75, 0x1f, 0x14, 0x1f, 0xed, 0xd0, + 0x2a, 0xe9, 0xa8, 0xf2, 0x98, 0xdc, 0x04, 0xba, 0xd2, 0x2f, + 0xee, 0x75, 0x2f, 0xe4, 0x9d, 0x2c, 0x51, 0xa5, 0x98, 0xd1, + 0xb4, 0xaf, 0xa7, 0x14, 0xd5, 0x73, 0x57, 0xfe, 0x1a, 0x2a, + 0x54, 0x95, 0x3e, 0x26, 0x84, 0x3f, 0x69, 0x94, 0x6b, 0x5a, + 0xa9, 0x91, 0x4b, 0x49, 0x95, 0x5f, 0xa5, 0x6a, 0x74, 0xc0, + 0xbd, 0x32, 0x2d, 0xa8, 0xfc, 0x5f, 0x4e, 0x73, 0x9a, 0x11, + 0xd2, 0x06, 0x70, 0x57, 0x41, 0x45, 0x1e, 0x65, 0xae, 0x2a, + 0x3f, 0xc2, 0xaa, 0x6a, 0x18, 0xc3, 0x74, 0x31, 0x9f, 0x17, + 0xc5, 0x76, 0x60, 0x20, 0xd3, 0xed, 0x66, 0x43, 0xc2, 0x3a, + 0xaa, 0x5b, 0x86, 0xaa, 0x92, 0x28, 0x2a, 0x51, 0xd3, 0x6c, + 0x7c, 0x75, 0x41, 0x6c, 0xd1, 0x6c, 0x7a, 0x69, 0x4d, 0xb4, + 0xe1, 0x68, 0x31, 0xc9, 0x45, 0x18, 0x05, 0xfe, 0x4a, 0x99, + 0x00, 0xc7, 0xdd, 0x56, 0x84, 0x93, 0x0f, 0x66, 0xaa, 0x6e, + 0x68, 0x64, 0xd6, 0x26, 0xda, 0x54, 0x74, 0xc6, 0x1e, 0x04, + 0x36, 0x32, 0xae, 0x64, 0xab, 0x5c, 0x4e, 0xe8, 0x62, 0x34, + 0xcd, 0x91, 0xf9, 0xc8, 0x61, 0x75, 0x4a, 0x10, 0x31, 0x6e, + 0x0c, 0x53, 0x43, 0xb1, 0xf1, 0xea, 0xf0, 0x46, 0x70, 0xbd, + 0x4e, 0x60, 0x4b, 0xe0, 0x29, 0xee, 0xec, 0x5a, 0xc4, 0x9b, + 0x23, 0xdd, 0x63, 0xd3, 0xe5, 0x8d, 0x90, 0xe6, 0x12, 0x2e, + 0x22, 0xf5, 0xf6, 0x18, 0xd8, 0x14, 0x6a, 0xe5, 0xce, 0x43, + 0x58, 0x6c, 0x55, 0x32, 0xe6, 0x88, 0x81, 0x55, 0x21, 0xa5, + 0x25, 0x9f, 0xd0, 0x98, 0x7a, 0x51, 0xf7, 0x8c, 0x7f, 0x76, + 0x60, 0x73, 0xc1, 0xd5, 0x48, 0x55, 0xb6, 0xe3, 0xd8, 0x5e, + 0x3e, 0x74, 0x84, 0xfd, 0x8f, 0x6c, 0x2e, 0xcb, 0x97, 0xe7, + 0x6e, 0x14, 0xbb, 0x63, 0xf4, 0x76, 0x31, 0x82, 0x7c, 0xe4, + 0x86, 0xc0, 0xb9, 0x4a, 0xd3, 0x17, 0xd0, 0x29, 0xbf, 0xdc, + 0xba, 0x0e, 0x39, 0x42, 0xb0, 0xe0, 0xa0, 0x68, 0x1e, 0x49, + 0x15, 0x25, 0xab, 0xd3, 0x2b, 0x22, 0x4c, 0x5b, 0x20, 0x7c, + 0xdc, 0xa7, 0x6f, 0x55, 0x03, 0x38, 0x10, 0x07, 0xf0, 0xad, + 0x67, 0x34, 0x15, 0xc9, 0xd7, 0x44, 0x0b, 0x95, 0x8e, 0xde, + 0x29, 0x00, 0x9e, 0x58, 0x1f, 0x1c, 0x70, 0x07, 0xb7, 0xd3, + 0x82, 0x7c, 0x49, 0x37, 0x57, 0xf2, 0xb3, 0xee, 0x9c, 0x23, + 0x0f, 0xbf, 0xe8, 0x1c, 0x6b, 0x3d, 0x61, 0xb9, 0xe7, 0x6a, + 0x71, 0xd2, 0x0e, 0xc5, 0x49, 0x6b, 0xfd, 0x5e, 0x5d, 0xb4, + 0xe6, 0xd2, 0xb9, 0x40, 0xf2, 0x73, 0x86, 0xfb, 0xc1, 0xcd, + 0x1b, 0xc9, 0x8e, 0x21, 0x39, 0x77, 0xad, 0x67, 0x8c, 0x3c, + 0xce, 0x96, 0x4f, 0xd8, 0x91, 0x38, 0x61, 0xa4, 0xc2, 0xcf, + 0xb3, 0x47, 0x92, 0x37, 0xe0, 0xf2, 0x11, 0x1c, 0x8b, 0x23, + 0x48, 0x6a, 0xfc, 0x3c, 0x43, 0x48, 0x33, 0xf1, 0xe8, 0x82, + 0x26, 0x2a, 0x8e, 0xe4, 0x44, 0x1c, 0x49, 0x96, 0xc2, 0x47, + 0x97, 0xd7, 0x46, 0x65, 0x47, 0xd4, 0xee, 0xac, 0x4b, 0x17, + 0xc5, 0x8e, 0x2b, 0xd7, 0xe4, 0x63, 0x6e, 0x4d, 0x6c, 0xe9, + 0xbc, 0xe2, 0x1b, 0x58, 0xd4, 0x82, 0xea, 0x73, 0xe6, 0xe0, + 0x0e, 0x7f, 0x53, 0xc4, 0xb7, 0x56, 0xc8, 0xa6, 0x38, 0xce, + 0xad, 0x23, 0xb4, 0xa9, 0x81, 0x68, 0x10, 0xbb, 0x9e, 0xf2, + 0xe1, 0x43, 0xbf, 0x20, 0xa7, 0x49, 0xff, 0x3a, 0x78, 0x83, + 0x0b, 0xbd, 0x4b, 0xc0, 0x47, 0x7b, 0xca, 0xc0, 0x45, 0xba, + 0xf7, 0x52, 0xd2, 0xd6, 0xb7, 0xfc, 0xe2, 0xb4, 0x39, 0x67, + 0x92, 0x46, 0xea, 0x4e, 0x9b, 0x5c, 0xe3, 0x7d, 0x1c, 0x3e, + 0x79, 0x74, 0x54, 0xdf, 0xe9, 0xc8, 0x2e, 0x9a, 0xef, 0x70, + 0xcb, 0x81, 0x56, 0xa3, 0x97, 0x04, 0x6b, 0xb8, 0x6b, 0x1d, + 0x38, 0x45, 0xec, 0x58, 0x8f, 0x7c, 0x82, 0xba, 0xf6, 0x52, + 0xd8, 0x4e, 0x4f, 0x3c, 0x82, 0x1b, 0xa8, 0xe3, 0x10, 0xa1, + 0xe1, 0x57, 0xe1, 0x8f, 0xda, 0x44, 0xdc, 0x3f, 0x4e, 0x53, + 0x68, 0x36, 0x10, 0x0f, 0xae, 0xad, 0xbb, 0x8d, 0xe8, 0xd3, + 0x9a, 0x8b, 0x0c, 0xd3, 0x70, 0xe2, 0xf4, 0xe4, 0x7b, 0xfb, + 0xc5, 0xc2, 0x37, 0x4f, 0x8a, 0x94, 0x8d, 0x7f, 0xa4, 0x66, + 0x91, 0x8b, 0x71, 0x4b, 0x4b, 0x3c, 0x13, 0xc7, 0xcc, 0x1a, + 0xe3, 0x19, 0xa9, 0x20, 0x6d, 0xd8, 0x1d, 0x8e, 0x74, 0x6d, + 0x50, 0x00, 0xea, 0x4d, 0x72, 0xb5, 0x37, 0x79, 0xbb, 0xf9, + 0x96, 0x11, 0xa1, 0x3e, 0x86, 0x81, 0x92, 0xba, 0x07, 0xef, + 0x61, 0x9f, 0x63, 0x78, 0x03, 0x25, 0xd8, 0x03, 0xb2, 0x74, + 0x8f, 0x86, 0xa6, 0xae, 0x0e, 0x3e, 0x67, 0xa4, 0xb3, 0x17, + 0x92, 0xa3, 0xa1, 0x62, 0x86, 0xf0, 0xc2, 0x86, 0xee, 0x32, + 0xb2, 0xc4, 0x06, 0x83, 0xf1, 0x6c, 0xf0, 0xf9, 0x4b, 0x4a, + 0xec, 0x80, 0x49, 0xbe, 0xb9, 0xf5, 0xe1, 0x8a, 0x7f, 0x18, + 0xc0, 0xab, 0xff, 0xc3, 0x93, 0x1b, 0x01, 0xc5, 0xc3, 0x2c, + 0xd0, 0xe0, 0x9d, 0x76, 0x64, 0x6a, 0xba, 0x35, 0x58, 0xe8, + 0x7a, 0x4a, 0xfd, 0x70, 0x5f, 0x60, 0xa7, 0xbb, 0x30, 0x58, + 0x2b, 0xcb, 0x24, 0x72, 0x7d, 0xd3, 0x14, 0xb4, 0xde, 0x54, + 0x3f, 0x6b, 0x34, 0xc4, 0xf8, 0xf9, 0x98, 0x42, 0x1a, 0xd8, + 0x0f, 0x20, 0x68, 0x10, 0x69, 0x3c, 0x56, 0xa7, 0x19, 0xfc, + 0x3a, 0xcd, 0xc8, 0x39, 0xb6, 0x7d, 0xa7, 0x87, 0x97, 0x2e, + 0xa2, 0xe7, 0x14, 0x60, 0x53, 0x88, 0xaa, 0xd1, 0xa9, 0xa8, + 0x1a, 0x35, 0x83, 0x33, 0x7a, 0xe6, 0x12, 0x97, 0x2b, 0xb6, + 0x87, 0xec, 0x62, 0xf1, 0x3d, 0xc8, 0xc5, 0x0a, 0xb1, 0x02, + 0x7c, 0xda, 0xcc, 0x0e, 0x23, 0x92, 0xde, 0x75, 0x26, 0xfd, + 0x52, 0x46, 0xfa, 0xa5, 0x33, 0xe9, 0x07, 0x8a, 0x2a, 0x11, + 0xfe, 0x81, 0x57, 0x3b, 0xd8, 0xc6, 0xf5, 0x33, 0x22, 0x99, + 0x54, 0xbb, 0x94, 0xf8, 0xae, 0x3b, 0x71, 0xbf, 0x94, 0xf8, + 0x4b, 0x77, 0xe2, 0xaf, 0x22, 0x7d, 0xbf, 0xe6, 0x25, 0x2f, + 0xbe, 0x61, 0x20, 0x2b, 0xd2, 0x57, 0xc5, 0x8d, 0x94, 0x35, + 0x40, 0x69, 0x58, 0x56, 0x77, 0x5b, 0x79, 0x39, 0x77, 0x93, + 0x97, 0xc0, 0x19, 0xcd, 0x9b, 0x96, 0x34, 0x0b, 0x04, 0x72, + 0x46, 0xf3, 0x5b, 0x4b, 0x9a, 0x05, 0x92, 0x38, 0xa3, 0xf9, + 0xb9, 0x25, 0xcd, 0x49, 0x5e, 0x20, 0x67, 0x34, 0x27, 0x2d, + 0x69, 0x4e, 0xf3, 0x62, 0x38, 0xa3, 0x39, 0x95, 0xa3, 0xd9, + 0x58, 0xec, 0x25, 0xa6, 0xb5, 0xba, 0xfb, 0xed, 0x59, 0x89, + 0x49, 0xee, 0x35, 0xae, 0xb7, 0x6d, 0x9d, 0x53, 0xb3, 0x2b, + 0x7b, 0xde, 0xac, 0x2e, 0x0e, 0xe7, 0x53, 0xfe, 0xba, 0x2e, + 0x86, 0xd7, 0x5c, 0x57, 0xba, 0xb9, 0x89, 0xf5, 0x11, 0x80, + 0x9a, 0x1d, 0x26, 0x39, 0x5e, 0x51, 0x60, 0xd8, 0x73, 0x37, + 0xfb, 0xf7, 0x63, 0x5d, 0x03, 0xbb, 0x5d, 0xb7, 0x06, 0x9e, + 0xea, 0x1a, 0x78, 0x79, 0xe9, 0xd6, 0xc0, 0x46, 0x6c, 0x20, + 0x8d, 0x10, 0xeb, 0x6d, 0x8e, 0xfe, 0xa8, 0x6d, 0xa1, 0xeb, + 0x24, 0x85, 0xb5, 0x2d, 0x74, 0x9d, 0xa5, 0xd7, 0xd1, 0xb4, + 0x17, 0xfa, 0xa5, 0x56, 0x21, 0xef, 0xb7, 0x2d, 0xe5, 0x93, + 0xf1, 0x45, 0xad, 0x12, 0xf9, 0x8f, 0x2d, 0xc9, 0x5e, 0x69, + 0x19, 0x62, 0x52, 0xa1, 0xd8, 0x7f, 0x6a, 0x49, 0x57, 0x9f, + 0x8d, 0xc7, 0x15, 0x92, 0x7f, 0xd3, 0x92, 0xec, 0x7c, 0x64, + 0x0e, 0xae, 0x2a, 0xa4, 0xff, 0x1f, 0x6d, 0x4f, 0x53, 0xf5, + 0x4b, 0x85, 0xfc, 0x0f, 0xfb, 0x96, 0xff, 0xc8, 0x36, 0x97, + 0x82, 0x0f, 0xc7, 0xd5, 0xd2, 0x9f, 0x0e, 0x12, 0x1b, 0xf4, + 0x32, 0xc0, 0xe1, 0x06, 0x0f, 0xed, 0x6f, 0x96, 0xc1, 0x37, + 0xcb, 0xe0, 0x5f, 0xcc, 0x32, 0xd8, 0x2b, 0xb3, 0xbc, 0x99, + 0x06, 0x7f, 0x02, 0xd3, 0xe0, 0x9f, 0xcd, 0xa2, 0x36, 0xcd, + 0x60, 0x84, 0xd9, 0x63, 0x7e, 0x8a, 0xd4, 0x38, 0x38, 0x5d, + 0x9b, 0x46, 0x26, 0x35, 0x62, 0x0c, 0xca, 0x5c, 0x7f, 0xd8, + 0x03, 0x9e, 0xcc, 0x43, 0x13, 0x9b, 0xd5, 0xbf, 0x97, 0x61, + 0x4d, 0xca, 0x23, 0x51, 0xc5, 0x76, 0x13, 0xdc, 0xc9, 0x7e, + 0x63, 0x90, 0x07, 0x61, 0x10, 0x45, 0x3d, 0x12, 0xa6, 0x51, + 0x49, 0xe9, 0x0b, 0x66, 0x7f, 0xb4, 0x1f, 0x0b, 0xa7, 0xa3, + 0xa7, 0x28, 0xd2, 0xc2, 0x19, 0xe9, 0x89, 0x76, 0xd9, 0xa4, + 0xf4, 0x43, 0x7e, 0x89, 0x23, 0x07, 0x2d, 0x10, 0x86, 0x41, + 0x28, 0x44, 0x13, 0x6a, 0xe4, 0x5b, 0x17, 0xff, 0x1e, 0x26, + 0x3e, 0x9b, 0x06, 0xf2, 0xe3, 0x98, 0xac, 0x18, 0x6e, 0xc8, + 0x30, 0x74, 0x21, 0x2b, 0x2b, 0xef, 0x35, 0x53, 0xfd, 0xb5, + 0x2c, 0x2b, 0x6b, 0x2b, 0xcf, 0x2a, 0x0f, 0xce, 0x0c, 0x6a, + 0x2a, 0xd1, 0x16, 0x89, 0xa1, 0x2c, 0xaa, 0xd2, 0x32, 0x19, + 0x4f, 0xc7, 0xa4, 0x6e, 0xa6, 0x6a, 0x66, 0xb5, 0xa5, 0x94, + 0xcd, 0xbf, 0xa2, 0x5d, 0xb1, 0x79, 0xcf, 0xeb, 0xb2, 0x6b, + 0x93, 0xa9, 0x9d, 0xdb, 0x70, 0x3e, 0xab, 0xac, 0xde, 0x14, + 0x66, 0x33, 0x5d, 0x8c, 0xa4, 0x4a, 0xf5, 0xad, 0x7f, 0x1e, + 0x06, 0xc8, 0xd9, 0x14, 0x0a, 0x0c, 0x3b, 0xab, 0xd1, 0xfc, + 0x9d, 0xcd, 0xa5, 0x81, 0x06, 0xb0, 0x7b, 0xc8, 0x31, 0xfc, + 0x11, 0xb4, 0xa7, 0xe6, 0xd0, 0xeb, 0x3c, 0xe2, 0xfa, 0x6e, + 0xc4, 0x18, 0x67, 0xbc, 0xd8, 0xfd, 0xf0, 0xc5, 0xf5, 0x9d, + 0xed, 0x46, 0x9a, 0x5a, 0x5d, 0x6a, 0x89, 0xd0, 0x7e, 0xa8, + 0xbc, 0x90, 0xd1, 0x14, 0xa9, 0xb8, 0xe4, 0x77, 0xcd, 0x9e, + 0x40, 0x73, 0x30, 0xed, 0x73, 0x39, 0x98, 0x50, 0x57, 0x9a, + 0x9c, 0xbf, 0xcc, 0x7b, 0xa0, 0xf0, 0x18, 0xd8, 0x94, 0x92, + 0xae, 0x5d, 0x6b, 0xba, 0x99, 0x0b, 0xed, 0x7a, 0x84, 0xb2, + 0x9a, 0x49, 0xcc, 0xd4, 0x97, 0xc5, 0x94, 0x18, 0xca, 0x6a, + 0xef, 0xcc, 0xc7, 0x65, 0x06, 0xb6, 0xb8, 0x34, 0x62, 0xe2, + 0x59, 0xac, 0xb2, 0x09, 0xa2, 0x4a, 0x43, 0x59, 0x33, 0x4d, + 0x41, 0xa0, 0x5a, 0x6a, 0x1c, 0x6b, 0xa6, 0x26, 0x08, 0x54, + 0x4b, 0x0d, 0x62, 0x0d, 0x15, 0x84, 0x57, 0x33, 0xac, 0xee, + 0x5e, 0xdb, 0xb2, 0xfa, 0xf8, 0xf2, 0xda, 0xa6, 0x55, 0xbb, + 0x6c, 0x96, 0x50, 0xdc, 0xa5, 0x97, 0xec, 0xf5, 0x9a, 0xc9, + 0x92, 0x6d, 0x6a, 0x27, 0xd9, 0x54, 0xc5, 0xac, 0xc9, 0x36, + 0xf5, 0x22, 0xd9, 0x54, 0xc5, 0xf4, 0xf5, 0x6e, 0x75, 0x6d, + 0x92, 0x9c, 0xfe, 0x6b, 0x49, 0x4e, 0x7a, 0x62, 0xc0, 0x7b, + 0xee, 0xfc, 0xc8, 0xb6, 0x5f, 0x60, 0x73, 0xdd, 0x75, 0x7e, + 0x66, 0xdb, 0x2f, 0xb0, 0xb8, 0xbe, 0xb4, 0xa4, 0x7a, 0xfd, + 0xb5, 0x24, 0x3b, 0x7d, 0x62, 0x20, 0x6e, 0x3b, 0x07, 0xd7, + 0xcc, 0x24, 0x14, 0x58, 0x5c, 0x1f, 0xdb, 0xce, 0xc2, 0x35, + 0x33, 0x0d, 0x05, 0x36, 0xd7, 0xc7, 0xb6, 0xf3, 0xa0, 0x32, + 0xf3, 0x70, 0x9c, 0xa7, 0x6b, 0xb7, 0x9d, 0x07, 0xc6, 0xfc, + 0xbe, 0x7f, 0x56, 0x40, 0xb7, 0xed, 0x3c, 0xa8, 0x74, 0x1e, + 0x0e, 0xf6, 0x0b, 0xe8, 0xbe, 0xbc, 0xd2, 0xe3, 0x63, 0x51, + 0x5a, 0x58, 0xf1, 0x1c, 0xcd, 0x79, 0xd6, 0xfe, 0xb8, 0xfc, + 0xb0, 0x85, 0xf1, 0x3c, 0x41, 0x1c, 0xb0, 0xdd, 0x9f, 0xd8, + 0x3e, 0xd8, 0x3e, 0x12, 0x73, 0x09, 0x19, 0x01, 0x85, 0x3d, + 0x46, 0x65, 0x95, 0xb4, 0x80, 0x44, 0x32, 0x33, 0x14, 0x07, + 0x1a, 0x6c, 0x63, 0x36, 0x0c, 0x14, 0xff, 0x6c, 0x70, 0x4b, + 0x7b, 0x2d, 0x10, 0xe5, 0x3e, 0x6c, 0x9e, 0xfd, 0x40, 0x28, + 0xf7, 0xd1, 0x13, 0x26, 0xda, 0xa8, 0x17, 0x8b, 0xe6, 0x77, + 0x0a, 0xbc, 0xf8, 0xeb, 0xfa, 0x36, 0x86, 0x38, 0x92, 0x81, + 0xe4, 0xdb, 0xf9, 0xed, 0xf0, 0xec, 0xe8, 0xe0, 0xec, 0xe4, + 0x68, 0xff, 0xf4, 0xe0, 0xf4, 0xd3, 0xc9, 0xd9, 0xc7, 0x5c, + 0x82, 0x53, 0x1e, 0xc4, 0xae, 0xcd, 0xfa, 0x6f, 0x48, 0xd8, + 0x81, 0x64, 0x7b, 0x02, 0xb4, 0x5d, 0x9b, 0x06, 0x31, 0xb4, + 0x93, 0x64, 0x73, 0x1c, 0xe0, 0x53, 0x9b, 0xc6, 0x08, 0xdc, + 0x50, 0x76, 0x8b, 0x27, 0x08, 0x43, 0x11, 0x88, 0x63, 0x28, + 0xa3, 0x22, 0xe5, 0x2e, 0x08, 0x61, 0x4f, 0x52, 0x99, 0xf4, + 0x0a, 0x79, 0x12, 0xe7, 0xc1, 0x66, 0xb1, 0xa9, 0x11, 0x91, + 0x4c, 0xb2, 0x15, 0x58, 0xf8, 0x4d, 0x46, 0xbe, 0xc9, 0xc8, + 0x37, 0x19, 0x59, 0x9f, 0xf7, 0x21, 0x35, 0xea, 0xa4, 0x59, + 0x1f, 0x78, 0xe0, 0x84, 0x76, 0xbc, 0x9f, 0x3e, 0x81, 0x11, + 0xf6, 0xdf, 0x47, 0xff, 0x25, 0x8c, 0x46, 0xe5, 0xed, 0x2b, + 0xbf, 0x86, 0x5d, 0xb6, 0x7c, 0x0e, 0x43, 0x8e, 0xcc, 0xd6, + 0x7c, 0x66, 0x94, 0xf9, 0x98, 0x77, 0xf3, 0x65, 0xfe, 0xa2, + 0x8e, 0x4c, 0x4b, 0x44, 0xe3, 0xe1, 0x81, 0x61, 0xdc, 0x58, + 0xb1, 0x63, 0x25, 0xaa, 0x86, 0xe0, 0x29, 0xb2, 0x83, 0xa1, + 0x2c, 0xee, 0xd6, 0x67, 0x4d, 0x9b, 0xe7, 0x1f, 0xcd, 0x8c, + 0x04, 0x38, 0xff, 0x01, 0x80, 0x4d, 0x85, 0x4d, 0xec, 0x27, + 0x96, 0xff, 0x26, 0xbc, 0xbc, 0x07, 0x45, 0xa9, 0x3d, 0x0b, + 0xce, 0x01, 0x9a, 0x67, 0x8e, 0xad, 0xd4, 0xe4, 0x3c, 0xf8, + 0xc1, 0x83, 0x25, 0x6f, 0xa5, 0x35, 0xa3, 0x3c, 0x12, 0x5e, + 0x98, 0xdf, 0x8e, 0xbb, 0xb7, 0xe3, 0xee, 0xb5, 0x8e, 0xbb, + 0xd7, 0x39, 0x25, 0xfe, 0x32, 0x87, 0x28, 0xc1, 0x1f, 0xc3, + 0x1c, 0x77, 0x2c, 0xec, 0x4a, 0x13, 0xff, 0x29, 0x3d, 0x96, + 0xc6, 0x66, 0xeb, 0x07, 0x93, 0xa1, 0x76, 0xa1, 0x2e, 0xc6, + 0x62, 0x9e, 0xf7, 0x21, 0xb8, 0xb3, 0xb7, 0x5e, 0x05, 0x06, + 0xc9, 0x60, 0xa4, 0x0f, 0x28, 0x64, 0x5d, 0x76, 0x96, 0x0d, + 0xdc, 0x70, 0x89, 0x7c, 0x50, 0xcb, 0x2b, 0xea, 0xf0, 0x78, + 0x62, 0xfc, 0x24, 0xe8, 0x8b, 0x08, 0x3c, 0x95, 0x94, 0x38, + 0xc4, 0x80, 0x11, 0x65, 0x75, 0xb5, 0xd1, 0xe5, 0x95, 0x29, + 0xa0, 0xbf, 0x5c, 0x20, 0x4c, 0x26, 0xa0, 0x9c, 0x95, 0xd7, + 0xba, 0x9a, 0x5d, 0x6b, 0xba, 0x00, 0xfb, 0x72, 0x15, 0x60, + 0x89, 0x26, 0x03, 0x8f, 0xf6, 0x3d, 0x54, 0x0e, 0x0f, 0xf8, + 0xab, 0xf8, 0xbe, 0xb2, 0x91, 0x71, 0x52, 0xa4, 0x7d, 0x23, + 0xb7, 0xc0, 0x26, 0x72, 0xbe, 0xf2, 0x6a, 0xb7, 0xcf, 0x80, + 0x47, 0x86, 0x5c, 0x1e, 0xdf, 0x36, 0x82, 0xca, 0xc1, 0x31, + 0x6f, 0x2e, 0x15, 0x9c, 0x7c, 0x30, 0x1c, 0xf7, 0xea, 0x87, + 0x90, 0x15, 0x5b, 0x32, 0xf1, 0xf5, 0x50, 0x13, 0x5f, 0xfd, + 0x52, 0xd8, 0xc1, 0x21, 0xd8, 0x00, 0xdf, 0xa9, 0xc4, 0xd3, + 0x61, 0x5d, 0x6d, 0x28, 0x27, 0xa7, 0xfe, 0x35, 0x15, 0xf5, + 0xd8, 0x8a, 0x87, 0x82, 0x83, 0x8e, 0x22, 0x41, 0x60, 0xf4, + 0x65, 0x34, 0x1d, 0xd2, 0x08, 0xb7, 0x23, 0xe6, 0x3d, 0x39, + 0xc0, 0xef, 0xea, 0x4f, 0xae, 0xef, 0xec, 0x25, 0x4a, 0xa1, + 0x14, 0xb7, 0xfe, 0x60, 0x05, 0x63, 0xe4, 0x78, 0x80, 0xea, + 0x0b, 0x95, 0x6a, 0x46, 0xb6, 0x15, 0x51, 0x9d, 0x02, 0x25, + 0xe3, 0xdd, 0x77, 0x3c, 0x30, 0x7e, 0xb8, 0x5a, 0xf6, 0x84, + 0xa1, 0xa6, 0x0b, 0x82, 0xfc, 0x0a, 0x26, 0xee, 0x84, 0x9e, + 0x04, 0x4f, 0x04, 0xa2, 0x3a, 0x73, 0x44, 0x69, 0xa2, 0x89, + 0xa6, 0x6d, 0xf1, 0x00, 0x78, 0x09, 0xa5, 0x41, 0xb0, 0x5e, + 0xa3, 0xf0, 0x45, 0xde, 0xb7, 0xa2, 0x0d, 0xe8, 0xdd, 0x5f, + 0x72, 0xc1, 0xf4, 0xe0, 0x29, 0xaa, 0x59, 0xa5, 0x8f, 0xd4, + 0xfe, 0xf7, 0x14, 0xbd, 0xe9, 0xd0, 0x6f, 0x3a, 0xf4, 0x9b, + 0xc9, 0xe8, 0x67, 0xd4, 0x4f, 0x96, 0xc8, 0x1b, 0xd3, 0x4a, + 0x00, 0xc5, 0x92, 0x1d, 0xb2, 0x7f, 0x7c, 0x7a, 0xf0, 0xe9, + 0xf4, 0xe4, 0xe4, 0x00, 0xfe, 0x2f, 0xdd, 0x1d, 0xfc, 0x57, + 0xd6, 0x97, 0x53, 0xe5, 0xe1, 0xc8, 0xda, 0x74, 0xe3, 0xc9, + 0x75, 0xb0, 0xfa, 0xc7, 0x0d, 0xf0, 0x0b, 0xf9, 0xd8, 0x83, + 0x56, 0xc9, 0x91, 0xed, 0xae, 0x48, 0xde, 0x13, 0xb8, 0x57, + 0x9e, 0xec, 0x55, 0x10, 0xba, 0x2f, 0xf0, 0x9c, 0xb0, 0x51, + 0xe8, 0x4d, 0x19, 0x1a, 0xec, 0x3a, 0x63, 0x89, 0xa3, 0x7d, + 0x49, 0xe7, 0xd3, 0xbb, 0x3b, 0x2a, 0xe6, 0xc3, 0x47, 0xa0, + 0x90, 0x5c, 0x9a, 0x25, 0xbc, 0x27, 0x9d, 0x6a, 0x0d, 0x84, + 0xbe, 0xcd, 0xa8, 0xa5, 0xcc, 0xbb, 0xb2, 0x4a, 0xff, 0x88, + 0x1c, 0xe6, 0xe0, 0xb7, 0x38, 0x0f, 0x96, 0x9e, 0xbd, 0xca, + 0xa6, 0xc3, 0x39, 0xd9, 0xff, 0x81, 0xa6, 0x45, 0xe3, 0xf7, + 0x85, 0xaa, 0x6b, 0x08, 0x2a, 0x81, 0x89, 0x54, 0x63, 0xbc, + 0x3c, 0x8c, 0x3f, 0xb6, 0x36, 0xbc, 0x22, 0xe1, 0xf9, 0xab, + 0xd0, 0x66, 0x51, 0x75, 0x4b, 0xa7, 0x57, 0x2c, 0xde, 0xa9, + 0xe3, 0xc2, 0x0d, 0xa3, 0x98, 0xd0, 0x50, 0x74, 0x92, 0xd1, + 0xf5, 0xe7, 0xd7, 0x47, 0x2f, 0x02, 0xcf, 0x0b, 0x9e, 0x44, + 0x50, 0xa9, 0x82, 0xe3, 0xfa, 0x94, 0xe2, 0x08, 0xa0, 0x1a, + 0x18, 0x56, 0xea, 0xed, 0xd4, 0x7e, 0x3b, 0xb5, 0xdf, 0x4e, + 0xed, 0xda, 0xd7, 0x69, 0x14, 0xc8, 0x13, 0x89, 0xf7, 0x08, + 0xb4, 0x7f, 0x08, 0x6a, 0x0e, 0x1b, 0x52, 0x39, 0x4f, 0xca, + 0x72, 0xd7, 0x88, 0x0f, 0x5e, 0xc9, 0xde, 0xfe, 0xe9, 0x9e, + 0x8a, 0xe9, 0x98, 0x2a, 0x65, 0xc9, 0x59, 0x7e, 0xcc, 0xef, + 0x64, 0x00, 0xc1, 0x93, 0x2c, 0xd1, 0xef, 0xd7, 0xbf, 0xf6, + 0x07, 0x09, 0xde, 0x0f, 0x4d, 0xea, 0xfb, 0x18, 0x3c, 0xf9, + 0xed, 0x68, 0xd6, 0xcc, 0xed, 0x4d, 0x70, 0x53, 0xe7, 0xa8, + 0x94, 0xa1, 0x22, 0xdc, 0x04, 0x1f, 0x6e, 0xde, 0x3c, 0x95, + 0xde, 0x84, 0xf3, 0xeb, 0x09, 0x67, 0x7b, 0xbd, 0xf1, 0x92, + 0xd8, 0xd4, 0x44, 0x29, 0xa4, 0x1f, 0x3a, 0x24, 0xb9, 0x64, + 0xfc, 0x78, 0xf6, 0x7f, 0x3b, 0x85, 0x57, 0x9b, 0x4f, 0x67, + 0x07, 0xb9, 0x6b, 0x0d, 0xc9, 0xc1, 0xa8, 0x36, 0x86, 0x38, + 0xfe, 0xeb, 0x9e, 0x30, 0x3f, 0xd3, 0x0b, 0xf1, 0x30, 0xf0, + 0x41, 0xb5, 0x9c, 0xa2, 0x49, 0x29, 0xf8, 0x57, 0x62, 0x52, + 0xb3, 0x40, 0x56, 0x55, 0xb7, 0x9e, 0xbc, 0xb0, 0x7f, 0x4e, + 0x1e, 0xd8, 0xab, 0x9b, 0x3e, 0x10, 0xdf, 0xe5, 0xb3, 0x6a, + 0xb5, 0x32, 0xf2, 0x4d, 0x9e, 0xfd, 0x85, 0xe5, 0x19, 0x1f, + 0x39, 0xde, 0xfd, 0xb9, 0xea, 0xdf, 0xee, 0xd9, 0xf6, 0x4f, + 0x20, 0xa6, 0x34, 0x0f, 0x3c, 0xda, 0x71, 0x50, 0xf3, 0xec, + 0x42, 0xf3, 0x33, 0xa4, 0xe5, 0x7f, 0xb4, 0x22, 0xf5, 0x27, + 0xf0, 0xb6, 0x7a, 0xd3, 0x03, 0xdf, 0xd0, 0x5b, 0xde, 0x60, + 0x48, 0x44, 0x7f, 0x08, 0x4e, 0x6b, 0xed, 0x7e, 0xa6, 0xbc, + 0xa9, 0xab, 0x7d, 0x9a, 0x3c, 0xcd, 0xd0, 0x46, 0xa9, 0x0e, + 0xe1, 0x29, 0x50, 0x73, 0x1e, 0x1c, 0x09, 0x86, 0x4f, 0xb6, + 0xe2, 0xdb, 0xc5, 0xfa, 0x4d, 0x11, 0x7d, 0xb3, 0x7a, 0x36, + 0xb0, 0x7a, 0xd2, 0xcd, 0xc3, 0xd9, 0x3e, 0xe9, 0xe7, 0x3f, + 0xb9, 0x05, 0x34, 0x37, 0xbe, 0x4a, 0xd1, 0x72, 0x5c, 0x36, + 0xfe, 0x37, 0x6b, 0x68, 0x5e, 0x92, 0xb2, 0x32, 0x34, 0xa3, + 0x19, 0xfd, 0xda, 0x5f, 0x52, 0x4d, 0xc2, 0x2c, 0x72, 0xce, + 0x59, 0x1f, 0x4f, 0x04, 0x16, 0xfb, 0xc1, 0x77, 0x04, 0x44, + 0x2a, 0x25, 0x98, 0x76, 0x45, 0x99, 0xe2, 0x8f, 0x22, 0x97, + 0xff, 0x09, 0x76, 0x51, 0xe2, 0x99, 0x78, 0x91, 0x65, 0x5b, + 0xae, 0x5e, 0x8b, 0x8f, 0xa2, 0x47, 0x23, 0x53, 0xf1, 0xcd, + 0xac, 0xf3, 0x76, 0x9a, 0xbe, 0x9d, 0xa6, 0x6d, 0x4f, 0xd3, + 0x8d, 0x8d, 0xe0, 0xd2, 0xdc, 0x8d, 0x5d, 0xd0, 0xb8, 0xb8, + 0x49, 0xe7, 0xb4, 0x2c, 0x93, 0x72, 0x60, 0x9d, 0xf9, 0x89, + 0x30, 0x84, 0x5a, 0xf6, 0x86, 0xdc, 0x67, 0x91, 0xf8, 0xe4, + 0xaf, 0xae, 0xa6, 0xbb, 0x2e, 0xf1, 0x2e, 0x8a, 0xfe, 0x8c, + 0xd2, 0x8e, 0x9b, 0xc8, 0x4a, 0xc1, 0x77, 0x5a, 0x2a, 0xf8, + 0xd8, 0x09, 0x2f, 0xc1, 0x55, 0x70, 0xb3, 0x8d, 0x31, 0x1a, + 0x2a, 0xef, 0x47, 0x93, 0x81, 0x62, 0x3b, 0x4e, 0x08, 0xfb, + 0x96, 0xc7, 0x91, 0x93, 0x99, 0xc4, 0xe0, 0xee, 0xce, 0x7a, + 0xce, 0x2f, 0x7c, 0x40, 0x0e, 0x6a, 0x78, 0xdb, 0xc6, 0x90, + 0x81, 0x1f, 0x92, 0xf8, 0x85, 0xf6, 0xa2, 0x04, 0xb5, 0xb3, + 0xab, 0x6a, 0x07, 0xbb, 0x9c, 0xf5, 0xd3, 0xce, 0x4b, 0x55, + 0x3b, 0x18, 0x02, 0x73, 0x2f, 0x45, 0xc4, 0xec, 0xef, 0xa1, + 0x17, 0x81, 0x71, 0x49, 0x2a, 0x21, 0x67, 0x1c, 0x80, 0x57, + 0x5e, 0x05, 0x11, 0x80, 0x35, 0x6a, 0x5c, 0x76, 0xc1, 0x0a, + 0xf2, 0x2f, 0x08, 0x25, 0xdb, 0xfe, 0x44, 0x81, 0xba, 0x48, + 0xbd, 0xfa, 0xf6, 0x05, 0x20, 0x3e, 0xca, 0x80, 0x99, 0xc6, + 0x32, 0x1a, 0xca, 0xf0, 0x5e, 0xcd, 0x40, 0x52, 0x6a, 0x65, + 0xe8, 0xd8, 0xf9, 0xc1, 0x9c, 0xee, 0xe7, 0x7a, 0xd2, 0x06, + 0x24, 0xbb, 0x2a, 0x1b, 0xf5, 0x64, 0xd0, 0x3e, 0x1d, 0xb5, + 0xf6, 0x55, 0x1b, 0x2c, 0x4c, 0x8a, 0xed, 0x9a, 0xeb, 0xac, + 0xeb, 0xc3, 0x76, 0x82, 0x15, 0xda, 0xbc, 0xf2, 0x39, 0x98, + 0x66, 0x53, 0x4d, 0x08, 0xe8, 0xc8, 0xe8, 0xa1, 0x94, 0xbd, + 0x1e, 0x60, 0x7b, 0x54, 0x47, 0x4d, 0xd3, 0xf5, 0x99, 0x2e, + 0x84, 0x79, 0x64, 0xe4, 0x08, 0x30, 0xa6, 0x7c, 0x3c, 0xed, + 0x6c, 0x3e, 0x4f, 0x13, 0x60, 0x1f, 0xe5, 0x88, 0x41, 0xe1, + 0xbc, 0xd9, 0x00, 0xa7, 0x8d, 0x25, 0x9a, 0x41, 0xd2, 0x1c, + 0x90, 0x11, 0xa2, 0x1d, 0xcd, 0x9e, 0x1e, 0xed, 0x94, 0x6f, + 0xd7, 0xbf, 0x0b, 0x68, 0x60, 0x0a, 0xfa, 0xb7, 0x84, 0xce, + 0x2d, 0x65, 0xa4, 0x22, 0xc9, 0xaa, 0x6b, 0x98, 0xf7, 0x40, + 0x30, 0x50, 0xa5, 0x95, 0x18, 0xd5, 0xf7, 0x3f, 0xaa, 0xf9, + 0x36, 0xa9, 0xc0, 0x25, 0xc8, 0x36, 0x03, 0x85, 0xd0, 0x6b, + 0x75, 0x1a, 0xbc, 0x85, 0x2d, 0xca, 0xc1, 0x0a, 0xcf, 0xb2, + 0xe3, 0xe4, 0x6b, 0x8b, 0xa1, 0xec, 0xf2, 0x64, 0x6e, 0x5a, + 0x90, 0x79, 0xa1, 0xbb, 0x22, 0x08, 0x1d, 0xd7, 0x87, 0x03, + 0xc2, 0xe6, 0xf1, 0x36, 0xa4, 0x7e, 0x8a, 0x94, 0xc5, 0x28, + 0x38, 0x27, 0xd2, 0x81, 0x67, 0xd7, 0xd8, 0x76, 0x4f, 0x99, + 0x90, 0xb4, 0xf5, 0x1a, 0x76, 0x61, 0x89, 0x99, 0x34, 0x52, + 0x48, 0xdd, 0xb7, 0xfb, 0xe2, 0xbf, 0x9d, 0x27, 0xcd, 0x2b, + 0xc9, 0xad, 0x5d, 0x64, 0xd9, 0x82, 0x7c, 0x55, 0x5b, 0xc9, + 0x55, 0x44, 0xe9, 0x56, 0xa0, 0x74, 0xde, 0x8a, 0xd2, 0x3a, + 0x78, 0x04, 0x56, 0x7c, 0x0f, 0x75, 0x86, 0xfb, 0xc0, 0xa3, + 0x9a, 0x18, 0xfc, 0xaa, 0x30, 0x5f, 0xfb, 0x52, 0x6a, 0x07, + 0x28, 0x9a, 0x58, 0x0d, 0x81, 0x5d, 0xb3, 0x21, 0x8f, 0xe8, + 0x86, 0x44, 0x87, 0x3d, 0xae, 0xf1, 0xb6, 0x0d, 0xdf, 0xcc, + 0x36, 0x7f, 0x5a, 0xb3, 0x8d, 0xb7, 0x5b, 0x61, 0xf6, 0xe0, + 0x7d, 0xbf, 0xc9, 0x67, 0x04, 0x46, 0x0f, 0x9e, 0x29, 0x74, + 0x56, 0x52, 0xb6, 0xc7, 0x97, 0x8f, 0x2c, 0x3c, 0x27, 0x7a, + 0x25, 0x68, 0x30, 0x6e, 0x1c, 0x95, 0x3b, 0xfb, 0x58, 0x18, + 0xa7, 0x92, 0xd4, 0x7a, 0xdb, 0xdd, 0xed, 0x12, 0xdc, 0xa3, + 0x1b, 0x8c, 0x1d, 0x45, 0x03, 0xdb, 0x73, 0x6f, 0x65, 0xb0, + 0x79, 0x4e, 0x4f, 0xd8, 0xbb, 0x0f, 0xac, 0xa9, 0x30, 0x55, + 0xdf, 0x7c, 0xc5, 0xdf, 0xa4, 0xf9, 0xab, 0x49, 0x73, 0xd6, + 0xab, 0xbb, 0xcd, 0xf2, 0x0a, 0x78, 0x8d, 0x6d, 0x3c, 0xbd, + 0x5f, 0xc7, 0x5d, 0xfd, 0xed, 0x92, 0xfb, 0xe3, 0x71, 0x61, + 0xde, 0xe0, 0x53, 0xfe, 0xad, 0xe0, 0x53, 0xd8, 0x47, 0x92, + 0x4c, 0xb3, 0xa9, 0x3c, 0xf6, 0x3e, 0x16, 0x3e, 0x46, 0x65, + 0x75, 0x6b, 0x8f, 0xbb, 0xbb, 0xb4, 0x9a, 0xc5, 0xbe, 0xb1, + 0x53, 0x62, 0xed, 0x1f, 0xd9, 0xc3, 0x54, 0xa8, 0x5b, 0x77, + 0x61, 0x21, 0xe9, 0x4c, 0xea, 0x2b, 0x17, 0xa4, 0x40, 0x0f, + 0xd9, 0x3f, 0x34, 0x55, 0x37, 0xaf, 0xac, 0x8b, 0xd1, 0xd7, + 0xd4, 0xc2, 0xba, 0x4f, 0xfd, 0x3f, 0x90, 0x53, 0xc9, 0x85, + 0xfb, 0x8c, 0x36, 0x7a, 0x19, 0x43, 0xcd, 0x55, 0xbe, 0xf6, + 0x01, 0x17, 0xc9, 0x27, 0x53, 0x19, 0x07, 0x51, 0x0f, 0x05, + 0x96, 0x26, 0x79, 0x29, 0x51, 0xe4, 0xb4, 0x23, 0xc5, 0x85, + 0x3f, 0xd7, 0xbb, 0x64, 0xfd, 0x9e, 0xb8, 0xa3, 0x0e, 0x09, + 0xaf, 0xba, 0x29, 0x3c, 0xdb, 0xd7, 0x9e, 0xc1, 0x72, 0x2b, + 0xa1, 0x0e, 0x9e, 0x16, 0x4c, 0x06, 0xac, 0xae, 0x30, 0xf5, + 0x6b, 0xf7, 0xc6, 0x2a, 0x0c, 0xb6, 0x1b, 0x6e, 0x5f, 0x98, + 0x76, 0xb8, 0x02, 0xb1, 0x72, 0x89, 0xfe, 0xd0, 0x61, 0x6b, + 0xbc, 0xde, 0xa6, 0x83, 0xa5, 0x7d, 0x8b, 0xbe, 0x3c, 0x09, + 0x83, 0xa7, 0xef, 0x4f, 0xcd, 0xa8, 0x3a, 0x20, 0x5a, 0x86, + 0xee, 0x86, 0x55, 0x06, 0x30, 0xbd, 0x21, 0xfb, 0xbd, 0x0d, + 0x61, 0x0f, 0xd8, 0x0e, 0x08, 0x2d, 0x4e, 0x27, 0xa0, 0x7d, + 0x1e, 0xe3, 0xbf, 0x2a, 0x17, 0x1e, 0x42, 0x1b, 0x50, 0x54, + 0x37, 0x8c, 0x0a, 0xd4, 0x85, 0x86, 0xc9, 0x49, 0x92, 0x16, + 0x6f, 0x6d, 0xff, 0xc1, 0xf2, 0xdc, 0x75, 0xbe, 0x51, 0x52, + 0x40, 0xb9, 0x23, 0x8d, 0xa2, 0x72, 0x0a, 0x2c, 0xe7, 0xc6, + 0xdd, 0x9a, 0xdd, 0x04, 0x91, 0x15, 0xb9, 0x6b, 0x94, 0x44, + 0x8d, 0x6d, 0x36, 0xcd, 0x5a, 0x07, 0xf5, 0x86, 0x08, 0xb6, + 0xbf, 0xbc, 0xaf, 0x6c, 0xab, 0x71, 0x4b, 0x4f, 0xa1, 0x5f, + 0xde, 0x52, 0x1b, 0x33, 0x58, 0x65, 0x6b, 0xc2, 0xcd, 0xa9, + 0xa0, 0x45, 0x58, 0xe0, 0x43, 0xe7, 0xcb, 0xd4, 0x32, 0xf0, + 0xe1, 0x56, 0x5f, 0x59, 0x6b, 0x9a, 0x67, 0x66, 0x40, 0x3e, + 0xe1, 0xb3, 0xa4, 0x97, 0x61, 0xa5, 0x6d, 0x08, 0x43, 0xe2, + 0xda, 0xe9, 0x69, 0x30, 0xeb, 0x75, 0x94, 0x6f, 0x86, 0xb3, + 0xd6, 0xf7, 0xd3, 0x52, 0xbc, 0x0d, 0x6f, 0x59, 0xd6, 0x33, + 0xe1, 0xef, 0xad, 0x87, 0x87, 0xd2, 0x03, 0x7f, 0xff, 0x14, + 0x3e, 0xef, 0xcc, 0x35, 0xb2, 0xf2, 0x6c, 0x38, 0x13, 0x5e, + 0x14, 0xa9, 0x22, 0xd2, 0x1c, 0x3f, 0xcd, 0x8a, 0xc2, 0xa5, + 0x80, 0x92, 0xe6, 0xc1, 0xa6, 0x14, 0x03, 0xd7, 0x6f, 0x65, + 0xba, 0x4e, 0x29, 0x03, 0x3f, 0x2e, 0xa2, 0xac, 0xf9, 0x31, + 0x93, 0xd2, 0x31, 0xd5, 0x90, 0xa4, 0x58, 0x80, 0x67, 0x33, + 0x3a, 0xec, 0xc5, 0xc6, 0x41, 0x8f, 0x62, 0x82, 0xad, 0xa3, + 0xc1, 0x7d, 0x8c, 0x64, 0x20, 0xb5, 0x0a, 0x13, 0xd4, 0x16, + 0x5e, 0x82, 0x24, 0x51, 0x7a, 0xf0, 0x1d, 0xd6, 0x42, 0x7c, + 0x12, 0x42, 0x5d, 0x8b, 0x41, 0xe8, 0x21, 0x66, 0x88, 0x51, + 0xf6, 0x87, 0x8e, 0x19, 0xed, 0x64, 0x39, 0xe7, 0x53, 0x7e, + 0xee, 0x98, 0x87, 0x64, 0xe9, 0x17, 0xe9, 0xea, 0x90, 0x37, + 0xb5, 0x6d, 0xcc, 0x1b, 0xbc, 0x4d, 0x61, 0xac, 0xee, 0x7c, + 0xcc, 0xdb, 0x22, 0x02, 0xca, 0x38, 0x58, 0x0a, 0x7a, 0x77, + 0xb9, 0x2a, 0x6b, 0xcc, 0xb5, 0x4c, 0x81, 0x66, 0x30, 0xc4, + 0x11, 0x19, 0x72, 0xa3, 0x96, 0xa0, 0x51, 0x90, 0x62, 0x17, + 0xd5, 0xff, 0x26, 0x53, 0x57, 0x57, 0x87, 0xa3, 0x85, 0x91, + 0x4f, 0xa4, 0x8b, 0x08, 0x10, 0x7e, 0x92, 0x1a, 0x05, 0x4a, + 0xe1, 0x67, 0xcd, 0x67, 0xa3, 0xa9, 0x99, 0x4f, 0xa3, 0x8b, + 0x48, 0xc5, 0xf7, 0x2e, 0x43, 0x48, 0xb1, 0x23, 0x25, 0x0d, + 0x16, 0x4b, 0x8e, 0x2e, 0x24, 0xb8, 0x98, 0x4c, 0xf4, 0xa0, + 0x02, 0xd6, 0x76, 0x38, 0xd2, 0xb5, 0x41, 0xd6, 0xce, 0x21, + 0xd7, 0xce, 0x20, 0x89, 0x33, 0xcc, 0xe8, 0x76, 0x6a, 0x69, + 0xa2, 0x4e, 0xa9, 0x77, 0xcb, 0xfe, 0x33, 0xcd, 0xb4, 0x84, + 0x38, 0x49, 0x61, 0x5c, 0x7c, 0x52, 0x1f, 0x10, 0xa9, 0x3b, + 0x47, 0xa2, 0x5b, 0xf1, 0x97, 0x8d, 0x24, 0xa9, 0x91, 0x91, + 0xb3, 0xd9, 0xe4, 0x4d, 0x76, 0x29, 0x26, 0x64, 0xd6, 0x56, + 0xce, 0xda, 0x57, 0x48, 0xfa, 0x5b, 0x85, 0x15, 0xb0, 0x86, + 0x24, 0xb6, 0xaa, 0x0a, 0x26, 0xd2, 0x02, 0x4b, 0x22, 0xb1, + 0x4d, 0xee, 0x95, 0x5b, 0x43, 0x45, 0xe3, 0x66, 0x43, 0x1a, + 0x32, 0xb1, 0xd5, 0x7b, 0x4d, 0xce, 0x30, 0x09, 0x8f, 0x2e, + 0x66, 0xcd, 0xc5, 0x23, 0xac, 0x89, 0x47, 0xd7, 0x9f, 0xf0, + 0x0c, 0x0b, 0xe9, 0xe2, 0xf0, 0xfc, 0xc4, 0xac, 0x9a, 0x20, + 0xa2, 0xdb, 0xa0, 0x96, 0x56, 0xf9, 0xba, 0x5d, 0xe8, 0xad, + 0xcd, 0x13, 0x28, 0x4b, 0x83, 0x60, 0x59, 0x40, 0x79, 0x19, + 0xd0, 0x94, 0xe0, 0x7b, 0x34, 0x86, 0x58, 0x0b, 0xeb, 0x25, + 0xdb, 0xe5, 0xcc, 0x9c, 0x09, 0x36, 0x86, 0xcb, 0x00, 0x51, + 0x89, 0x83, 0x27, 0x3b, 0x74, 0x22, 0x48, 0x63, 0x09, 0xdc, + 0x47, 0xb8, 0x4f, 0x25, 0x88, 0x91, 0xdc, 0xea, 0x82, 0x09, + 0x2d, 0xcb, 0xaa, 0xae, 0xd8, 0x77, 0xe8, 0x14, 0xb7, 0x51, + 0x26, 0x66, 0xfc, 0x93, 0x24, 0xfc, 0x95, 0xa0, 0x5b, 0x0a, + 0xbb, 0xdd, 0x89, 0xaa, 0x36, 0xd6, 0xae, 0x55, 0x33, 0xf5, + 0xc6, 0x3b, 0x61, 0x5e, 0xf6, 0x11, 0x1d, 0x94, 0x7f, 0xb1, + 0x84, 0x76, 0x4c, 0xee, 0xee, 0xcb, 0x1d, 0xe4, 0x40, 0xa7, + 0x4a, 0xbe, 0x9a, 0xa3, 0x89, 0x36, 0x5b, 0x24, 0xeb, 0xf4, + 0xb1, 0x88, 0x7d, 0x89, 0x47, 0x19, 0x56, 0xcc, 0x1d, 0x05, + 0x6b, 0x4c, 0x32, 0x46, 0x9d, 0x30, 0x78, 0x46, 0x8a, 0xf6, + 0x8e, 0xc9, 0x41, 0x9c, 0x7e, 0x48, 0x59, 0x6b, 0xae, 0xcf, + 0xbe, 0xb6, 0x3c, 0xfc, 0x2f, 0x52, 0x28, 0x76, 0xf6, 0xdc, + 0xbf, 0xb0, 0x43, 0x12, 0xe9, 0x8e, 0x26, 0x00, 0xde, 0xe2, + 0x63, 0x37, 0x45, 0x3d, 0x2c, 0x1b, 0xfc, 0xd7, 0x1b, 0x6b, + 0xaa, 0x31, 0xa4, 0x32, 0xfe, 0x9a, 0xa2, 0x5c, 0x97, 0x70, + 0x7a, 0x11, 0xa5, 0x7b, 0x0a, 0xf5, 0x88, 0x0c, 0x0e, 0x55, + 0x4a, 0x00, 0x4f, 0xed, 0xb8, 0x88, 0xda, 0x63, 0x9a, 0xb4, + 0xbc, 0x86, 0x16, 0xec, 0xda, 0x62, 0xaa, 0x6b, 0xea, 0xe0, + 0x4a, 0x3d, 0x1f, 0x6b, 0x05, 0xca, 0x81, 0x1f, 0x02, 0x7b, + 0x79, 0x6f, 0xdf, 0x7a, 0xa0, 0x4d, 0x47, 0x0b, 0x68, 0x33, + 0xda, 0x42, 0x9e, 0x76, 0x49, 0xb7, 0x5b, 0xd8, 0xb5, 0x26, + 0x01, 0x5c, 0xe1, 0x3a, 0xe0, 0x86, 0xb3, 0x83, 0xbc, 0xad, + 0x22, 0xa9, 0x88, 0x58, 0x72, 0x68, 0xc7, 0x25, 0xae, 0x24, + 0xf6, 0xb3, 0xb5, 0x5c, 0x3b, 0xec, 0xdd, 0xd2, 0x86, 0xfc, + 0xef, 0x28, 0x5f, 0xf9, 0xcc, 0xa5, 0xef, 0x71, 0xd4, 0xdd, + 0xaf, 0x6d, 0xf4, 0xf4, 0x5d, 0x71, 0x03, 0x37, 0x42, 0x03, + 0x28, 0x02, 0xaf, 0x15, 0xfd, 0x97, 0x62, 0xfa, 0xdf, 0x04, + 0xfa, 0x28, 0x1a, 0xaf, 0x15, 0xfd, 0x67, 0xcb, 0x01, 0x91, + 0x98, 0xc7, 0xb1, 0xcf, 0xe9, 0x29, 0x20, 0xdf, 0xe3, 0xe4, + 0x14, 0x50, 0xef, 0x6b, 0x6a, 0x1e, 0xdd, 0x30, 0xc6, 0xb6, + 0x9d, 0xcc, 0xd4, 0xf2, 0x55, 0xb9, 0x86, 0xdf, 0xb6, 0x90, + 0xed, 0x35, 0xe4, 0xf6, 0xdc, 0x61, 0x5e, 0x32, 0xda, 0x99, + 0x40, 0xbc, 0x11, 0x69, 0xb7, 0x9d, 0x94, 0x8c, 0x34, 0xf3, + 0xc6, 0x2c, 0x90, 0x6e, 0x3b, 0x23, 0x28, 0x7d, 0x92, 0x75, + 0xe7, 0xdc, 0x3e, 0xb0, 0x53, 0x62, 0x78, 0xae, 0x83, 0x15, + 0x26, 0x92, 0x5b, 0x49, 0xb9, 0x80, 0x1a, 0xf2, 0xad, 0xbd, + 0x7c, 0xe8, 0x30, 0x3b, 0xb4, 0x1d, 0x66, 0x7a, 0xca, 0xdb, + 0x69, 0x3b, 0x53, 0xb4, 0x19, 0x66, 0xaa, 0xca, 0x9b, 0xe9, + 0x34, 0x6b, 0x5b, 0xff, 0xc1, 0x67, 0x67, 0x6d, 0x01, 0xcf, + 0xf9, 0x30, 0x46, 0x56, 0xa0, 0x1d, 0xbe, 0xac, 0x00, 0x3f, + 0xea, 0xba, 0xd7, 0x68, 0x3b, 0xcc, 0xac, 0x95, 0xb7, 0xd3, + 0x69, 0xd6, 0x70, 0x33, 0x2f, 0xac, 0x73, 0x41, 0x59, 0x33, + 0xad, 0x67, 0x2d, 0x62, 0xa7, 0x8b, 0x35, 0x3e, 0x0e, 0xc1, + 0xa3, 0xdb, 0x79, 0xae, 0x22, 0x76, 0x92, 0x4a, 0xa8, 0xb7, + 0x9e, 0xa1, 0x88, 0x9d, 0x9a, 0x12, 0xe2, 0x6d, 0xe7, 0x25, + 0x04, 0xf0, 0xca, 0x42, 0x74, 0x72, 0xf1, 0x0e, 0x00, 0xef, + 0x84, 0x50, 0xed, 0x35, 0x58, 0xed, 0x3d, 0xfd, 0x98, 0xde, + 0x8c, 0xe4, 0x5e, 0xc1, 0x6a, 0x0d, 0x46, 0x5c, 0x4b, 0x95, + 0x07, 0xf7, 0x61, 0x49, 0x4f, 0x8a, 0x27, 0x8e, 0x79, 0xbd, + 0x49, 0x1c, 0x60, 0x47, 0xe8, 0xf5, 0xdd, 0x85, 0xc5, 0xc2, + 0x96, 0xaf, 0x37, 0x68, 0x88, 0x99, 0xdb, 0x00, 0x9c, 0xb8, + 0xbc, 0xa3, 0x8d, 0x14, 0x00, 0x4d, 0x18, 0xe6, 0x4c, 0xfb, + 0x58, 0x98, 0xb6, 0xa0, 0xb5, 0x8c, 0x43, 0xcf, 0x72, 0xd7, + 0x1b, 0x41, 0xb9, 0x56, 0x46, 0xeb, 0x0d, 0x64, 0xe7, 0x96, + 0x1d, 0x44, 0x6c, 0xe1, 0xb8, 0xcc, 0x59, 0x95, 0xcd, 0x77, + 0xe6, 0x2c, 0x01, 0x4f, 0xf5, 0xf6, 0x1b, 0x26, 0xa5, 0xbf, + 0xab, 0xa0, 0x7f, 0xd3, 0x7e, 0xcb, 0xa4, 0xe4, 0x5f, 0x2a, + 0xc8, 0x7f, 0x6b, 0xbf, 0x69, 0x84, 0x53, 0x9c, 0x5f, 0xc2, + 0x0e, 0xb3, 0x22, 0x9c, 0xe0, 0x22, 0xdd, 0xb6, 0xb3, 0x21, + 0x9c, 0xde, 0x22, 0xd9, 0xd6, 0xa2, 0xe3, 0xce, 0xaa, 0x9e, + 0x88, 0x91, 0xaf, 0x64, 0xf3, 0x8e, 0xdd, 0x12, 0xba, 0x30, + 0xcc, 0x9d, 0x55, 0x3d, 0x3b, 0x05, 0x8d, 0xb5, 0xe6, 0x9e, + 0x3b, 0xab, 0x7a, 0xca, 0x0a, 0xda, 0xea, 0x38, 0x89, 0x8f, + 0xac, 0x52, 0x08, 0xbc, 0x60, 0x09, 0xaf, 0xb2, 0xaf, 0x37, + 0x8b, 0x8f, 0xac, 0x9a, 0x58, 0xdb, 0x5a, 0xc7, 0x69, 0x7c, + 0x64, 0x15, 0xc7, 0xda, 0xc6, 0xde, 0xce, 0xf7, 0x7e, 0xcf, + 0xf7, 0x7f, 0xfb, 0x5b, 0x47, 0x8d, 0xf2, 0x01, 0x0f, 0x71, + 0x2f, 0x70, 0x56, 0x75, 0x7a, 0x07, 0xe3, 0x2b, 0x48, 0xca, + 0xff, 0x68, 0x37, 0xe8, 0x70, 0x93, 0xbd, 0x10, 0xeb, 0xf3, + 0x49, 0x8b, 0x19, 0x66, 0xbc, 0x21, 0x4b, 0xbd, 0x20, 0x87, + 0xa3, 0xf6, 0xe6, 0x59, 0x75, 0x91, 0x9a, 0x55, 0x99, 0x64, + 0x29, 0x71, 0x62, 0xed, 0x21, 0xee, 0x90, 0x0e, 0x58, 0xba, + 0x4e, 0x85, 0x1d, 0xe9, 0x62, 0xa6, 0x7f, 0x51, 0x75, 0xd1, + 0x7d, 0x4c, 0x8d, 0xa1, 0x22, 0xb7, 0x81, 0x94, 0x02, 0x05, + 0x05, 0x26, 0x21, 0x63, 0x2f, 0xb2, 0xd3, 0x96, 0x93, 0x39, + 0x57, 0x07, 0x9f, 0x29, 0x9d, 0xc3, 0x32, 0x3a, 0xe8, 0x56, + 0xc6, 0x11, 0xfa, 0x33, 0xf8, 0x36, 0xd6, 0xb0, 0xed, 0x71, + 0xce, 0xce, 0xd5, 0xe4, 0x65, 0xf5, 0xd5, 0x3c, 0xab, 0x48, + 0x2a, 0xce, 0x64, 0x37, 0x70, 0xb9, 0x37, 0x2f, 0x06, 0xad, + 0x19, 0x4e, 0xd7, 0x7e, 0x5f, 0x68, 0x86, 0x98, 0x7b, 0x53, + 0x07, 0x7f, 0x6c, 0x41, 0x54, 0xe1, 0x70, 0xab, 0x6b, 0xf3, + 0x99, 0x2e, 0x3e, 0x24, 0xe8, 0x00, 0xe9, 0xce, 0x52, 0x9c, + 0x10, 0x64, 0x8a, 0xf7, 0x8c, 0x66, 0x3e, 0xee, 0xc1, 0xfb, + 0x12, 0x3f, 0xb8, 0x0a, 0x83, 0xc1, 0xef, 0x9c, 0x8d, 0xa2, + 0xe3, 0x85, 0x71, 0x21, 0xf0, 0x07, 0xe9, 0xfa, 0xba, 0xa6, + 0x0e, 0x6f, 0xc4, 0xc4, 0xa2, 0xc0, 0x76, 0x76, 0xf2, 0xa1, + 0xfe, 0x3c, 0x1a, 0x41, 0x26, 0x44, 0x13, 0xc7, 0xc1, 0xf2, + 0x1c, 0xd7, 0x05, 0x16, 0xf9, 0xd1, 0x78, 0xa1, 0x6b, 0xc2, + 0x0b, 0xc8, 0x85, 0xed, 0x7a, 0xdb, 0x10, 0xb4, 0x09, 0xf0, + 0x7f, 0x35, 0x7f, 0xc4, 0x3f, 0x99, 0xd7, 0xe0, 0x9b, 0x67, + 0xf1, 0x5f, 0xc4, 0xb3, 0xb8, 0xd6, 0x19, 0x33, 0xf1, 0x00, + 0x3d, 0x47, 0x5e, 0x98, 0xe3, 0x72, 0x2f, 0x35, 0xe9, 0xe0, + 0x27, 0xc6, 0xdd, 0xd4, 0x5a, 0xbb, 0x7e, 0x69, 0x83, 0x13, + 0xd7, 0x77, 0xd7, 0xdb, 0xb5, 0x62, 0xf4, 0xe6, 0x70, 0x9a, + 0xb4, 0x69, 0x3f, 0x97, 0xb7, 0x69, 0x3f, 0xf7, 0xdc, 0xa6, + 0xed, 0xc5, 0x52, 0xa3, 0x6c, 0x01, 0xf2, 0x53, 0xd9, 0xa4, + 0xc4, 0x20, 0xfb, 0x68, 0xf2, 0xcd, 0xa7, 0xf6, 0xcd, 0xa7, + 0xf6, 0xcd, 0xa7, 0xf6, 0xf5, 0x92, 0x12, 0xdb, 0x5b, 0x7f, + 0x59, 0x93, 0x36, 0xef, 0x8c, 0xe6, 0x22, 0xc6, 0xa5, 0xdf, + 0x02, 0x6d, 0xdf, 0x02, 0x6d, 0xdf, 0x60, 0x13, 0x7e, 0xf2, + 0x8d, 0x3d, 0x0c, 0xd1, 0xfd, 0xaf, 0x72, 0x5b, 0x67, 0x5b, + 0x02, 0x95, 0x7d, 0xdb, 0xd4, 0x6f, 0x9b, 0xfa, 0x6d, 0x53, + 0xff, 0xe4, 0x9b, 0xda, 0x58, 0xde, 0x03, 0x07, 0xea, 0x1e, + 0xce, 0x65, 0x10, 0xd7, 0x24, 0x52, 0x3c, 0xcb, 0x62, 0x23, + 0xb3, 0x4a, 0x0a, 0xa9, 0x55, 0xbb, 0xbd, 0xb1, 0x4f, 0xa5, + 0xed, 0x71, 0x20, 0xb5, 0x18, 0xb0, 0x3c, 0xb8, 0x53, 0x92, + 0xbf, 0x75, 0x41, 0xaa, 0xed, 0xb6, 0xd3, 0x87, 0xd4, 0xbf, + 0x51, 0xf9, 0x69, 0x76, 0x3d, 0xd7, 0xa9, 0xd7, 0x91, 0x00, + 0x6c, 0x13, 0x7f, 0x72, 0x69, 0x10, 0x87, 0xf6, 0x23, 0xf0, + 0xe8, 0x03, 0x8a, 0x89, 0x7f, 0xf7, 0x35, 0xaa, 0x94, 0x7a, + 0xdd, 0xe0, 0xb2, 0x56, 0x5f, 0x07, 0x83, 0x0d, 0x81, 0xef, + 0x51, 0x99, 0x37, 0x24, 0x3f, 0x95, 0x73, 0x70, 0x6f, 0x3f, + 0xba, 0xc8, 0x9b, 0x22, 0x7b, 0xc9, 0x38, 0xd7, 0xae, 0x5a, + 0x35, 0x2e, 0x9a, 0x44, 0x8d, 0xc5, 0x44, 0xcb, 0x99, 0x98, + 0x23, 0x48, 0x41, 0xde, 0x2c, 0xfb, 0x79, 0x94, 0x33, 0xcb, + 0x3e, 0xb8, 0x9b, 0x46, 0xa6, 0x50, 0xc1, 0x72, 0x85, 0xec, + 0xa0, 0x12, 0x46, 0xd0, 0x3a, 0x3f, 0x9c, 0xe0, 0x29, 0xc2, + 0x58, 0x6a, 0x76, 0xed, 0x73, 0x58, 0xe6, 0x27, 0x8c, 0xea, + 0x28, 0xb4, 0xd2, 0x1b, 0x84, 0xfe, 0x9b, 0xfe, 0xf1, 0x17, + 0xd0, 0x3f, 0x6e, 0x81, 0x4d, 0xb8, 0x1d, 0xb3, 0xc7, 0xc7, + 0xdf, 0x0e, 0xcf, 0x8e, 0x0e, 0xce, 0x4e, 0x8e, 0xf6, 0x4f, + 0x0f, 0x4e, 0x3f, 0x9d, 0x9c, 0xe5, 0xb2, 0xcc, 0x9e, 0xa7, + 0xc5, 0xbb, 0x30, 0xc1, 0x12, 0x61, 0x91, 0x5b, 0x36, 0x49, + 0x55, 0x9b, 0xec, 0x90, 0xfd, 0xe3, 0xd3, 0x83, 0x4f, 0xa7, + 0x27, 0x27, 0x07, 0xf0, 0x7f, 0xe9, 0xee, 0xe0, 0xbf, 0x26, + 0x3a, 0x12, 0xaa, 0x2d, 0x26, 0xba, 0x6d, 0xd3, 0x8d, 0x27, + 0xd7, 0x89, 0xef, 0xc5, 0x01, 0x7e, 0x21, 0x1f, 0xbb, 0x58, + 0x34, 0xfd, 0x55, 0x9e, 0xec, 0x38, 0xf9, 0xda, 0xc5, 0x0e, + 0x76, 0x77, 0x47, 0xd5, 0xc4, 0xf0, 0x31, 0xcd, 0xf6, 0x52, + 0xc2, 0x10, 0x72, 0x44, 0xe1, 0x1a, 0xa8, 0x1b, 0x10, 0xc6, + 0xe8, 0x65, 0xa9, 0xad, 0x80, 0x80, 0x2b, 0xb1, 0xf5, 0xec, + 0x50, 0xa1, 0x84, 0xca, 0x6c, 0xed, 0x29, 0x67, 0x1e, 0xfe, + 0xb6, 0xff, 0xe9, 0xf8, 0xe8, 0xd3, 0x89, 0x24, 0x5e, 0x92, + 0xbf, 0xa2, 0x4e, 0x99, 0xe4, 0x47, 0xf1, 0xb5, 0x50, 0x12, + 0xc1, 0x1e, 0x0a, 0x70, 0xcf, 0xde, 0x50, 0x00, 0xa6, 0xec, + 0x4d, 0x33, 0xfd, 0x43, 0xe1, 0x7c, 0xfe, 0x3d, 0xeb, 0xfd, + 0xc1, 0xfe, 0x0f, 0xcc, 0x4f, 0x69, 0xfc, 0xbe, 0x50, 0x75, + 0x8d, 0x3c, 0xea, 0x14, 0xe4, 0xa8, 0xfc, 0x63, 0x6b, 0x87, + 0x80, 0x3c, 0xec, 0x48, 0x1f, 0xb2, 0x98, 0x96, 0xa5, 0x8f, + 0x2e, 0xaf, 0xcc, 0x7c, 0xf8, 0xce, 0x05, 0x0e, 0x2d, 0x23, + 0xfc, 0xa6, 0x23, 0x68, 0x8b, 0x36, 0x0f, 0x90, 0xdf, 0xf7, + 0x8e, 0x53, 0x70, 0xc9, 0x41, 0x40, 0x67, 0x75, 0xe7, 0x7c, + 0x16, 0xa3, 0x4d, 0x4a, 0xbf, 0x59, 0x2f, 0xde, 0xb4, 0x87, + 0x37, 0xed, 0xa1, 0x1e, 0x78, 0x19, 0x6d, 0x21, 0xb0, 0xcf, + 0x76, 0xe0, 0x3c, 0x08, 0x3c, 0x60, 0xfb, 0xd4, 0x1b, 0x3d, + 0x2d, 0xd2, 0x47, 0xb2, 0xe4, 0xa4, 0xc1, 0x83, 0xfa, 0x06, + 0x0f, 0x7a, 0x6d, 0xf0, 0xb0, 0xbe, 0xc1, 0xc3, 0xbf, 0x44, + 0x3a, 0xe8, 0xd1, 0x1a, 0xfe, 0x32, 0x51, 0x9a, 0x98, 0xda, + 0xb4, 0xf1, 0x9f, 0xb2, 0xa3, 0x13, 0x57, 0x52, 0x68, 0xad, + 0xc6, 0xd9, 0xea, 0x4d, 0xfb, 0x01, 0x60, 0xfd, 0xa6, 0xb2, + 0xbd, 0x03, 0xea, 0xbf, 0x82, 0x8b, 0x37, 0x91, 0xd1, 0x6f, + 0xf2, 0xf4, 0x4d, 0x9e, 0xfe, 0xfc, 0xf2, 0x34, 0x26, 0x8c, + 0x6d, 0x95, 0x83, 0xc3, 0x7e, 0xda, 0x17, 0xaf, 0x16, 0x18, + 0x08, 0x56, 0xbc, 0x0f, 0xb5, 0x71, 0x73, 0xf9, 0xe1, 0x0f, + 0xc7, 0xbe, 0x53, 0x23, 0x00, 0x0e, 0xe9, 0x7e, 0xf4, 0x1d, + 0xba, 0xfb, 0xdf, 0x36, 0xfc, 0xdb, 0x86, 0xff, 0x93, 0x6e, + 0x78, 0xfb, 0x36, 0x60, 0x33, 0xde, 0xab, 0xe8, 0x67, 0x5f, + 0x76, 0xeb, 0x1f, 0x61, 0xda, 0x59, 0x79, 0xae, 0x03, 0xac, + 0xc8, 0x0b, 0x36, 0x99, 0x69, 0x27, 0x6b, 0xe0, 0x12, 0xfd, + 0x4d, 0x31, 0xc8, 0xdf, 0x4a, 0x2e, 0xd9, 0x0d, 0xdb, 0x40, + 0x8e, 0x63, 0x05, 0xe4, 0x7b, 0xf1, 0x13, 0xfb, 0xc1, 0xe2, + 0x50, 0xdd, 0xc6, 0x81, 0x1f, 0xac, 0x83, 0x6d, 0x64, 0xa4, + 0xb1, 0x0a, 0x95, 0xb2, 0x91, 0xda, 0x63, 0xb2, 0x8a, 0x4a, + 0x5a, 0xf3, 0x4d, 0x40, 0x96, 0xf6, 0xe4, 0xaf, 0x23, 0x59, + 0x0a, 0x27, 0x16, 0xb9, 0x93, 0x65, 0xad, 0x69, 0x3e, 0xe4, + 0xda, 0x25, 0x6c, 0x70, 0x9c, 0x7c, 0x4e, 0xed, 0x51, 0xda, + 0xf4, 0x62, 0xa6, 0x0f, 0x34, 0x59, 0x9b, 0x54, 0x1e, 0xc4, + 0x4c, 0x9b, 0x9b, 0x57, 0x79, 0x73, 0x54, 0xea, 0xb5, 0x89, + 0x73, 0x42, 0xa6, 0x8e, 0xb8, 0x7b, 0xa5, 0x54, 0xd4, 0xb1, + 0x39, 0x32, 0x17, 0x43, 0x2d, 0x6f, 0x85, 0x12, 0x3d, 0x4e, + 0xeb, 0x69, 0x71, 0x60, 0x3c, 0x2c, 0x82, 0x0c, 0x7e, 0x76, + 0xae, 0xef, 0x8a, 0xae, 0xa9, 0x87, 0xc3, 0x3c, 0x56, 0x4c, + 0x92, 0xa5, 0xc3, 0xf6, 0x70, 0x0e, 0x9e, 0x6c, 0x1e, 0x25, + 0x3c, 0xa8, 0xd7, 0x18, 0x2e, 0x64, 0x83, 0x6c, 0xc0, 0xfc, + 0xe4, 0x24, 0x1f, 0x8b, 0x98, 0x56, 0x4e, 0x4e, 0xc1, 0xfd, + 0xc1, 0x8a, 0xc1, 0x74, 0xae, 0xec, 0x9c, 0x08, 0x6c, 0x4e, + 0x1a, 0x19, 0xb6, 0xac, 0xc4, 0x25, 0x31, 0x3f, 0x7d, 0xed, + 0x1f, 0xec, 0x6d, 0x38, 0x79, 0x56, 0xca, 0x9b, 0x12, 0x49, + 0x60, 0xb8, 0xc9, 0x6e, 0x0b, 0x47, 0x9d, 0x00, 0x31, 0x81, + 0x50, 0x84, 0x66, 0x6a, 0x1b, 0x20, 0xff, 0x53, 0x80, 0x97, + 0x26, 0x29, 0x8e, 0x2b, 0x8f, 0x86, 0x63, 0x01, 0xf5, 0x0d, + 0xd7, 0xa9, 0x51, 0x9f, 0x09, 0xec, 0x55, 0x26, 0xa7, 0xf0, + 0xf5, 0x3a, 0x9f, 0xfd, 0xb0, 0xd9, 0x84, 0xa1, 0x3d, 0x90, + 0xe2, 0x05, 0x72, 0xaa, 0x47, 0x8f, 0x3e, 0xec, 0xaf, 0x23, + 0x7a, 0xdf, 0x2c, 0xb6, 0x9d, 0x2f, 0x1c, 0x7f, 0xc6, 0x6b, + 0xc6, 0x8f, 0x56, 0x01, 0x3d, 0x77, 0xe5, 0xaf, 0x41, 0xed, + 0xfe, 0x3e, 0xa1, 0x08, 0xb7, 0x49, 0x85, 0x4a, 0xcb, 0xd8, + 0xdb, 0xfb, 0xc5, 0x5b, 0x42, 0xc8, 0x3f, 0xd1, 0xc6, 0x28, + 0x48, 0x05, 0x8e, 0x9d, 0xd6, 0x3e, 0x03, 0xb0, 0x81, 0xcd, + 0x69, 0xcf, 0x31, 0x4a, 0x34, 0x53, 0x67, 0x3a, 0xfa, 0xc8, + 0xa2, 0x72, 0x22, 0x97, 0xb7, 0xa4, 0xba, 0x42, 0xeb, 0xbf, + 0xd9, 0x90, 0xff, 0x9d, 0x4d, 0x4a, 0x32, 0x78, 0xbc, 0x6f, + 0x69, 0xb0, 0x3a, 0xea, 0x48, 0x9b, 0x60, 0xb3, 0xdd, 0x58, + 0x1b, 0xb8, 0x33, 0x03, 0x87, 0xde, 0xa9, 0x36, 0x8b, 0x8d, + 0x32, 0x4f, 0xbe, 0x75, 0x99, 0x1c, 0x42, 0x5d, 0x9c, 0x78, + 0x42, 0xbf, 0x9f, 0xe9, 0x7f, 0x1d, 0xa7, 0x8e, 0xcf, 0x9a, + 0x36, 0xb7, 0x0c, 0xf5, 0xa2, 0xc0, 0xa3, 0x03, 0x49, 0x29, + 0x25, 0xb2, 0xef, 0x80, 0x72, 0x4b, 0x1c, 0x3d, 0xb7, 0xe1, + 0xcf, 0xef, 0x81, 0x91, 0x93, 0xd8, 0xa9, 0x3c, 0x1e, 0x06, + 0x7e, 0x8d, 0x1b, 0x06, 0x75, 0xf3, 0xca, 0x00, 0xc9, 0x49, + 0x25, 0x16, 0xca, 0x41, 0x11, 0xb0, 0x1c, 0xea, 0x1a, 0x5f, + 0xf9, 0x00, 0x8e, 0x17, 0xa5, 0xb6, 0xaa, 0x69, 0xfc, 0x13, + 0x6d, 0x9c, 0xd6, 0x79, 0xf3, 0x04, 0x79, 0x3b, 0x75, 0xde, + 0x1e, 0x32, 0x7e, 0xc6, 0xc7, 0x06, 0xd6, 0x81, 0xf3, 0xa4, + 0x3f, 0x0f, 0x4e, 0x31, 0x79, 0xe2, 0x41, 0x05, 0x6c, 0xd0, + 0xa4, 0x7d, 0xf2, 0x44, 0x92, 0xc5, 0xd0, 0xba, 0x18, 0xe9, + 0x39, 0x24, 0x97, 0x2c, 0x87, 0xa1, 0x82, 0xfd, 0xef, 0x6a, + 0x53, 0x21, 0xb2, 0x44, 0x0e, 0x4a, 0x13, 0x22, 0x0a, 0xc4, + 0x7e, 0x9e, 0xf3, 0xa2, 0x48, 0x6a, 0x27, 0xa8, 0x12, 0x39, + 0xa0, 0xcc, 0x34, 0xbf, 0xa4, 0xb1, 0x85, 0x5a, 0xc4, 0xa3, + 0x1b, 0xe1, 0xd5, 0xc0, 0x90, 0xee, 0xfb, 0xb9, 0x1c, 0x94, + 0x4d, 0x72, 0x1a, 0x04, 0x1b, 0x6b, 0x1d, 0xd0, 0x4c, 0xa8, + 0x19, 0xc0, 0x8d, 0x32, 0xc1, 0x5f, 0xd3, 0xf5, 0xbe, 0x36, + 0xda, 0xa3, 0xdc, 0x68, 0xfa, 0xf5, 0x68, 0x20, 0x46, 0x54, + 0x18, 0x68, 0x14, 0xcb, 0x06, 0xde, 0x9a, 0xea, 0x78, 0x74, + 0xae, 0x33, 0xf9, 0x5a, 0xe8, 0x7a, 0x33, 0x39, 0x8f, 0xa5, + 0x51, 0x6b, 0x74, 0x3d, 0x85, 0xc4, 0xcf, 0x8c, 0xed, 0x04, + 0x9c, 0x53, 0x96, 0xc2, 0x44, 0x9d, 0x6a, 0x8b, 0xeb, 0x5c, + 0x1e, 0x00, 0xc1, 0xb8, 0x28, 0x83, 0x9f, 0x63, 0x6a, 0xfa, + 0x54, 0x1d, 0x0b, 0xb0, 0x37, 0xe8, 0x76, 0x16, 0x22, 0x7b, + 0x7b, 0x62, 0xac, 0x95, 0xa6, 0x77, 0x3e, 0x9b, 0x99, 0x02, + 0xd6, 0xff, 0x79, 0x10, 0xb4, 0x72, 0x5f, 0x05, 0x68, 0x42, + 0xac, 0x25, 0xda, 0x4e, 0xdc, 0x1c, 0x45, 0xca, 0x87, 0x0f, + 0xca, 0x80, 0x7c, 0x6e, 0x9e, 0x91, 0x82, 0x50, 0x05, 0x3e, + 0xf3, 0x3c, 0x93, 0x11, 0xc5, 0x79, 0x2e, 0x5c, 0x10, 0xb5, + 0x35, 0xb3, 0x92, 0xb9, 0xb7, 0x58, 0xec, 0xa9, 0x4c, 0x9d, + 0x82, 0xe4, 0x09, 0x0e, 0x55, 0x8b, 0xf4, 0x1c, 0x19, 0xe5, + 0x88, 0x8d, 0xe4, 0x63, 0x49, 0x93, 0xf4, 0x34, 0xa6, 0xbb, + 0x06, 0x5d, 0xde, 0x07, 0xb2, 0x76, 0x40, 0x6c, 0x17, 0xb5, + 0xa2, 0x99, 0x6a, 0x67, 0xe0, 0x0a, 0x9c, 0x67, 0xc4, 0x0b, + 0x82, 0x0d, 0x9c, 0xe5, 0xdb, 0x44, 0x41, 0x27, 0xe7, 0xe6, + 0x60, 0x8c, 0xbe, 0x4e, 0xec, 0xe8, 0x41, 0xc4, 0x99, 0x1d, + 0x93, 0xe2, 0xb4, 0x65, 0xf6, 0x70, 0xc9, 0x6b, 0xf9, 0x2d, + 0x2f, 0x12, 0xd7, 0xed, 0x6f, 0x12, 0xe9, 0x6e, 0xb4, 0xd8, + 0x4c, 0x3f, 0xec, 0x83, 0x1c, 0xa7, 0x53, 0x4b, 0x1c, 0x04, + 0x9e, 0x1d, 0x61, 0x70, 0xc2, 0x20, 0xa4, 0x0a, 0x65, 0x14, + 0x27, 0xb8, 0x84, 0x70, 0x25, 0xba, 0xa7, 0x72, 0xcc, 0x1a, + 0xe0, 0xa2, 0x43, 0xf9, 0x56, 0x1a, 0xf2, 0x53, 0xcd, 0x85, + 0x20, 0x39, 0x1e, 0x92, 0x8c, 0x00, 0x92, 0x87, 0xcb, 0x81, + 0x78, 0xb8, 0x64, 0xd5, 0xa5, 0x41, 0xe6, 0xca, 0xa1, 0xe0, + 0xae, 0xbf, 0x3b, 0x14, 0x9c, 0xb1, 0x18, 0x0c, 0x34, 0xc3, + 0xc8, 0x63, 0xc1, 0x79, 0x3b, 0xbc, 0x8d, 0xb7, 0xcb, 0x25, + 0x9c, 0xb5, 0x8a, 0x14, 0xca, 0x53, 0x6b, 0xae, 0xcf, 0x2e, + 0xf5, 0x8c, 0xc6, 0x61, 0x8e, 0xc6, 0xc8, 0x57, 0xe6, 0x61, + 0xb0, 0x0a, 0x2b, 0xe9, 0x70, 0x60, 0x67, 0x47, 0x39, 0x1a, + 0x29, 0xea, 0x99, 0x0c, 0xab, 0x86, 0x64, 0xcc, 0x0c, 0x20, + 0x59, 0x32, 0x0b, 0x0c, 0x12, 0x59, 0xc3, 0x64, 0x44, 0xc9, + 0x0a, 0x73, 0x19, 0x24, 0x7a, 0x59, 0x35, 0x84, 0x16, 0x67, + 0xf1, 0x47, 0xe7, 0x3e, 0x8f, 0x18, 0x07, 0x94, 0xc6, 0x47, + 0x28, 0x02, 0xc1, 0x13, 0x88, 0x72, 0x68, 0x78, 0x6d, 0x28, + 0xa2, 0x4c, 0x68, 0x39, 0x95, 0xe3, 0x90, 0x03, 0xe9, 0x53, + 0xda, 0x28, 0x1e, 0xb8, 0xaf, 0x39, 0xc2, 0x47, 0x5c, 0x77, + 0x25, 0xe8, 0xca, 0x1c, 0x22, 0xe2, 0x0b, 0x33, 0xbd, 0xce, + 0x0b, 0xaa, 0x4a, 0x8b, 0x7c, 0x4f, 0x4b, 0xd4, 0x45, 0x4e, + 0x70, 0x31, 0x9d, 0xe6, 0xc4, 0x56, 0xbb, 0x73, 0xca, 0xf5, + 0xef, 0x02, 0x9a, 0x9d, 0x1c, 0xfd, 0x5b, 0x42, 0xc6, 0xd6, + 0xd9, 0x43, 0x48, 0xf6, 0x17, 0x92, 0x4b, 0xab, 0x89, 0x7e, + 0x4d, 0xdd, 0x31, 0x08, 0x85, 0x24, 0x1d, 0x57, 0xc3, 0xd4, + 0x61, 0xd5, 0x7b, 0x6a, 0xa2, 0x19, 0x1d, 0x44, 0xa1, 0xa1, + 0xe5, 0x05, 0x61, 0x04, 0x30, 0xee, 0x29, 0x3c, 0xd9, 0xed, + 0xad, 0x17, 0x57, 0x88, 0x22, 0x6d, 0x4a, 0x73, 0xf8, 0x1c, + 0x50, 0x97, 0x19, 0x9c, 0xbb, 0x87, 0x66, 0xcc, 0xa9, 0xca, + 0xe4, 0x67, 0x50, 0x02, 0x87, 0x0c, 0x88, 0xae, 0x34, 0x05, + 0xd2, 0x03, 0x4b, 0xfb, 0x3a, 0x18, 0x2f, 0x8c, 0xd1, 0xb5, + 0x28, 0x15, 0x73, 0x7d, 0x51, 0xde, 0x83, 0xe7, 0xa5, 0xb7, + 0x8d, 0x10, 0xa6, 0xf4, 0x07, 0xc5, 0x21, 0x2d, 0x45, 0x8a, + 0xed, 0x79, 0x4a, 0x10, 0xdf, 0x83, 0x30, 0xfa, 0xb5, 0x32, + 0xc9, 0xa1, 0x99, 0xa6, 0x4a, 0x3c, 0x66, 0xdf, 0x46, 0x70, + 0x8e, 0x44, 0x69, 0x48, 0x50, 0x90, 0x69, 0xaa, 0x69, 0x1f, + 0x31, 0x4b, 0x20, 0x4c, 0xc9, 0xa8, 0x0f, 0x66, 0x25, 0xf4, + 0xe8, 0x90, 0x9b, 0xf0, 0xeb, 0x91, 0xd0, 0x29, 0x66, 0xe2, + 0x9a, 0xb0, 0xec, 0x9a, 0xd7, 0xfc, 0x93, 0x01, 0x2b, 0x6b, + 0x42, 0x0d, 0x38, 0x4a, 0x87, 0x4b, 0xc0, 0xda, 0x27, 0x13, + 0x55, 0x41, 0x5b, 0x7e, 0x2a, 0xf3, 0x8b, 0x53, 0xdc, 0xf3, + 0x27, 0x37, 0xbe, 0x57, 0x40, 0x72, 0xd9, 0xe8, 0x70, 0x81, + 0x29, 0xee, 0x3b, 0x4f, 0xbd, 0x43, 0xef, 0x97, 0x15, 0xbd, + 0x87, 0x3a, 0x27, 0x49, 0xa2, 0xd5, 0x7d, 0x18, 0xcb, 0x8a, + 0x61, 0xe4, 0x9b, 0xe9, 0x30, 0x9e, 0xbf, 0xa2, 0x2a, 0x9d, + 0x99, 0x49, 0x6c, 0x2f, 0x75, 0xcf, 0x92, 0xda, 0x9a, 0xc7, + 0x39, 0x3b, 0x0b, 0x9c, 0xe4, 0x94, 0x82, 0xb4, 0x42, 0xbd, + 0xc6, 0x57, 0x34, 0xfe, 0xf2, 0x36, 0xdb, 0x10, 0x32, 0xec, + 0xf5, 0xed, 0x02, 0xd7, 0x1a, 0xf9, 0x0e, 0xc2, 0xf1, 0x0b, + 0x90, 0x41, 0x1f, 0xfd, 0xad, 0xfa, 0x82, 0x55, 0x92, 0xb5, + 0x93, 0x71, 0xe3, 0x2b, 0x76, 0x61, 0x1a, 0xf2, 0xee, 0x7c, + 0xbc, 0xf5, 0xb1, 0x8c, 0x28, 0xf1, 0xe0, 0x4b, 0xdc, 0xf5, + 0x04, 0xba, 0x92, 0x60, 0x9b, 0x15, 0xfd, 0x2d, 0x25, 0x2d, + 0x09, 0xaa, 0x59, 0xd1, 0xeb, 0x62, 0x6f, 0x2e, 0x39, 0x14, + 0xd4, 0x8a, 0x1e, 0x77, 0x71, 0x12, 0xab, 0x20, 0xfb, 0x18, + 0x92, 0xe4, 0x3f, 0x85, 0x64, 0xaf, 0xd3, 0xbc, 0x7c, 0x3a, + 0x93, 0xee, 0x47, 0x9a, 0x7c, 0xb7, 0x47, 0x1a, 0xec, 0xdf, + 0x08, 0x37, 0x27, 0x79, 0x19, 0xc9, 0x50, 0x88, 0xca, 0xad, + 0xe3, 0x55, 0x79, 0x69, 0xdb, 0x86, 0xf1, 0x0b, 0x7d, 0x48, + 0x9f, 0x6b, 0x1a, 0x77, 0x02, 0x9e, 0xb0, 0x50, 0x2b, 0xe0, + 0x9e, 0x60, 0x53, 0xda, 0x33, 0xf6, 0x4f, 0xa5, 0x28, 0x01, + 0x7b, 0x55, 0xc6, 0x7e, 0xa1, 0xb3, 0x55, 0xb6, 0xfe, 0xb2, + 0x49, 0x4a, 0xa0, 0x18, 0x78, 0x4a, 0xd5, 0x00, 0x0d, 0x52, + 0x99, 0x78, 0x2f, 0x41, 0xdc, 0x56, 0x1e, 0x66, 0x36, 0x4a, + 0x48, 0x43, 0xa9, 0x91, 0x89, 0x72, 0xaf, 0x9e, 0xec, 0xe5, + 0x49, 0xae, 0x0f, 0x1f, 0x8b, 0x0c, 0xc9, 0x72, 0x2a, 0x52, + 0x2f, 0xbe, 0x0e, 0x75, 0x03, 0x22, 0x36, 0xb8, 0xc4, 0x04, + 0x27, 0x35, 0xa2, 0xd3, 0x12, 0xfb, 0x9d, 0xd4, 0x98, 0x00, + 0xd6, 0xb6, 0x79, 0xdd, 0x9b, 0xde, 0x53, 0x06, 0xe3, 0xd6, + 0xd7, 0x14, 0xee, 0x9e, 0xb0, 0x2f, 0xdc, 0x13, 0x5a, 0x5d, + 0x4f, 0x24, 0x1d, 0xd0, 0xf3, 0x87, 0x65, 0xb5, 0xa5, 0x33, + 0x77, 0x4e, 0xb6, 0xb6, 0x76, 0x46, 0x4b, 0x14, 0xab, 0x03, + 0xa7, 0x8e, 0x22, 0xc8, 0xa1, 0x28, 0x1d, 0xec, 0x4c, 0x9e, + 0x7b, 0xbe, 0xcd, 0x5a, 0x6a, 0x6d, 0xd9, 0x9b, 0x00, 0xc7, + 0xdd, 0xae, 0x25, 0x99, 0xe4, 0x4c, 0x34, 0xec, 0xa5, 0xb5, + 0xe5, 0x2e, 0x07, 0x49, 0xe1, 0xe4, 0x2c, 0x49, 0x7e, 0x65, + 0x16, 0xa2, 0x49, 0x6b, 0x2e, 0xb9, 0xd4, 0x67, 0x8b, 0xa9, + 0x08, 0x19, 0x8f, 0x00, 0xfb, 0x7d, 0x47, 0xda, 0xc8, 0xa2, + 0x8e, 0x44, 0x33, 0x90, 0xea, 0xca, 0x1b, 0x7f, 0xbe, 0xa8, + 0x59, 0x7a, 0xe7, 0x43, 0x9a, 0x75, 0x3a, 0x6e, 0x60, 0x3e, + 0x82, 0x03, 0xd0, 0x74, 0x86, 0xcc, 0x11, 0x4d, 0x8b, 0xeb, + 0x80, 0xf0, 0xa9, 0x21, 0xad, 0xcf, 0xd3, 0xd9, 0x97, 0xa9, + 0x70, 0x61, 0x5d, 0xf8, 0x0f, 0x7e, 0xf0, 0xe4, 0x77, 0x07, + 0x04, 0x1b, 0xa0, 0x14, 0xcd, 0x91, 0xbc, 0xb0, 0xfc, 0x44, + 0x37, 0x4c, 0x56, 0x51, 0x8a, 0x61, 0x70, 0xef, 0x72, 0x95, + 0x95, 0xe4, 0x73, 0x89, 0xd6, 0x21, 0xe9, 0xfb, 0x5e, 0x6e, + 0x60, 0x1e, 0x0c, 0x5b, 0x3e, 0x28, 0x7c, 0xcd, 0x3f, 0x22, + 0x7c, 0xfd, 0x00, 0x35, 0xa6, 0x48, 0x7a, 0xe1, 0x6e, 0xf2, + 0xe1, 0x3c, 0x37, 0xcd, 0x28, 0x7c, 0xcb, 0x47, 0xf1, 0x7c, + 0x6b, 0x46, 0x61, 0x34, 0x99, 0xab, 0x03, 0x33, 0x1f, 0xce, + 0x33, 0x5a, 0x6f, 0xec, 0x65, 0xdc, 0x9d, 0x7b, 0x10, 0x5e, + 0x7d, 0x03, 0xcb, 0x04, 0x0d, 0x89, 0xa4, 0x40, 0xf7, 0x29, + 0x78, 0x42, 0x23, 0xd3, 0xc4, 0x3c, 0x88, 0x0c, 0x77, 0xad, + 0x15, 0x64, 0x58, 0x9c, 0x24, 0x40, 0xef, 0x5d, 0xfc, 0x20, + 0x12, 0x88, 0xf5, 0x02, 0xc4, 0xf5, 0x2e, 0x54, 0x29, 0xd8, + 0x39, 0xb5, 0x3a, 0x41, 0x1d, 0x6c, 0xad, 0xb0, 0x7f, 0xe8, + 0xb6, 0x0f, 0xc8, 0xb4, 0x4c, 0x02, 0xbf, 0x74, 0x5a, 0x94, + 0x2c, 0x77, 0x76, 0x96, 0x42, 0x7d, 0xd6, 0xde, 0xf0, 0x38, + 0xfb, 0x2c, 0xc8, 0xe9, 0xd9, 0x43, 0xf9, 0x39, 0xfe, 0x45, + 0x17, 0x1f, 0xee, 0xbf, 0xd8, 0xa1, 0x8f, 0x56, 0x9e, 0x81, + 0xcb, 0x2f, 0xab, 0x3c, 0x1e, 0x4d, 0x04, 0x89, 0x8c, 0x15, + 0xc4, 0x82, 0xaa, 0xd5, 0x0b, 0xbb, 0x66, 0x67, 0x47, 0xc0, + 0xb8, 0xcf, 0x4d, 0xcd, 0x60, 0x36, 0x99, 0x7c, 0xa7, 0xc9, + 0xe1, 0xc2, 0xf6, 0x0e, 0x72, 0x6e, 0x74, 0x52, 0x63, 0xc3, + 0x5c, 0xca, 0x0d, 0x8f, 0xe1, 0x5b, 0x3a, 0xa6, 0xe9, 0xf5, + 0x4f, 0x3a, 0x24, 0x89, 0xb8, 0xe0, 0x8d, 0xeb, 0x05, 0x31, + 0x71, 0x4c, 0x91, 0x92, 0x37, 0x07, 0x6c, 0x6c, 0x30, 0xae, + 0x9c, 0xb8, 0xb5, 0x48, 0x49, 0x19, 0x9b, 0x04, 0x14, 0xef, + 0x84, 0x00, 0xe3, 0x1d, 0xbc, 0x33, 0x3d, 0x02, 0x8f, 0xce, + 0xa9, 0xda, 0x5e, 0x27, 0x9e, 0xa8, 0xd3, 0x45, 0xea, 0xfb, + 0xc1, 0xdc, 0xcc, 0xfd, 0xad, 0x2d, 0xef, 0xf1, 0xa1, 0x1a, + 0xc6, 0xc8, 0x30, 0x73, 0x89, 0x72, 0xd4, 0x28, 0x72, 0x23, + 0xb6, 0xe9, 0x5a, 0x3a, 0x59, 0x36, 0xb7, 0x43, 0x76, 0xc4, + 0xad, 0x9e, 0xa0, 0x18, 0x8f, 0x22, 0x32, 0xe1, 0xdd, 0x2d, + 0xe2, 0xd9, 0x91, 0xd1, 0xe4, 0xc0, 0x39, 0xec, 0xe9, 0xc0, + 0x79, 0xcb, 0x66, 0xf6, 0x13, 0x66, 0x33, 0xab, 0x3f, 0x0a, + 0xdf, 0x34, 0x84, 0x37, 0x0d, 0xe1, 0x4d, 0x43, 0xf8, 0x77, + 0xd1, 0x10, 0x88, 0x0c, 0x4c, 0x1d, 0x26, 0xe5, 0x0e, 0x88, + 0x23, 0x5e, 0x80, 0x66, 0xee, 0x96, 0xf2, 0x8f, 0x31, 0xaf, + 0x25, 0x4e, 0x93, 0xd3, 0xc1, 0x2a, 0x12, 0xab, 0xa9, 0x83, + 0x0f, 0xf1, 0x43, 0x09, 0xee, 0x92, 0x97, 0xeb, 0xa8, 0x99, + 0x83, 0x4b, 0x4e, 0x65, 0x48, 0xe6, 0x00, 0x53, 0x6d, 0xa0, + 0x38, 0xd0, 0x9e, 0xa6, 0xe2, 0xfb, 0x30, 0xdf, 0xd1, 0x60, + 0xd3, 0xae, 0x9f, 0xb3, 0xf9, 0x3c, 0xed, 0xe7, 0x51, 0xae, + 0x9f, 0xc1, 0x66, 0xd3, 0xa2, 0x9f, 0xec, 0x01, 0x7a, 0x9c, + 0xeb, 0xa9, 0x8b, 0x00, 0xc5, 0x1a, 0x77, 0x94, 0xd0, 0xb4, + 0x0c, 0x6d, 0x2a, 0x7a, 0xdf, 0x72, 0x04, 0x15, 0x03, 0x45, + 0x35, 0xb7, 0x09, 0x64, 0x82, 0x92, 0xc8, 0x42, 0xba, 0x53, + 0x78, 0x67, 0x2f, 0x41, 0xa1, 0x7c, 0x52, 0x46, 0xf4, 0xcf, + 0xd9, 0x66, 0x1e, 0xb5, 0xb4, 0x7f, 0xa8, 0x83, 0xd9, 0xc2, + 0x30, 0x47, 0x83, 0xbc, 0x19, 0x44, 0x5d, 0x06, 0xdb, 0x28, + 0x76, 0x97, 0xf2, 0x6b, 0xa8, 0x9a, 0xda, 0x78, 0x3c, 0x32, + 0x0b, 0xf0, 0x4d, 0x0c, 0xb8, 0x01, 0x3c, 0xcf, 0x8d, 0xe5, + 0xdd, 0xc0, 0x2f, 0x8d, 0x49, 0xde, 0x2a, 0x82, 0x3e, 0x4a, + 0xfb, 0x6d, 0xcf, 0xce, 0x47, 0x63, 0x2d, 0x6f, 0x12, 0x99, + 0x04, 0xb7, 0xae, 0x27, 0xdf, 0x0f, 0x5d, 0x1d, 0x8e, 0xd2, + 0xdc, 0xc7, 0xcf, 0xd4, 0xae, 0x81, 0xc2, 0x27, 0x5b, 0x69, + 0xcc, 0x42, 0x68, 0x60, 0x0f, 0x41, 0x81, 0xd1, 0x2e, 0xb2, + 0x9c, 0x28, 0x2e, 0xca, 0x7a, 0x61, 0xec, 0xe0, 0xc5, 0x60, + 0xdd, 0x87, 0x52, 0x8e, 0x75, 0xe8, 0x54, 0xf7, 0x94, 0x12, + 0xb8, 0x9c, 0xcf, 0x4d, 0xba, 0x2d, 0x70, 0xcb, 0xbf, 0x88, + 0x03, 0xc8, 0x65, 0x4d, 0x81, 0x55, 0xd6, 0x9b, 0x32, 0xc3, + 0x3c, 0x99, 0x95, 0x5f, 0x98, 0xde, 0xff, 0x92, 0x7f, 0xab, + 0x4c, 0x5e, 0xf6, 0xf8, 0x10, 0xb1, 0x62, 0xa5, 0xea, 0x5f, + 0xff, 0x0b, 0x09, 0x56, 0x92, 0xa3, 0x2f, 0x85, 0x42, 0xa4, + 0x57, 0x4b, 0x82, 0xf4, 0xbd, 0x3a, 0x45, 0x35, 0xe0, 0xfb, + 0x27, 0xf2, 0x81, 0xb3, 0x4e, 0x08, 0xe6, 0xe0, 0x84, 0x2c, + 0xce, 0x6a, 0xbc, 0xff, 0x7c, 0x01, 0xff, 0x13, 0x4c, 0xc7, + 0xcc, 0xeb, 0xf7, 0x1e, 0xea, 0x4a, 0x59, 0xa7, 0x38, 0xec, + 0x1e, 0xee, 0x91, 0x5f, 0xb2, 0x3b, 0x43, 0x6d, 0x2e, 0xd3, + 0x9d, 0x84, 0x74, 0x65, 0x5f, 0xee, 0x01, 0xdc, 0x5e, 0x7e, + 0xa6, 0x76, 0x5f, 0xa5, 0x3f, 0x73, 0x3e, 0xae, 0x55, 0xb3, + 0x5c, 0x1e, 0x79, 0x26, 0x8c, 0x67, 0x49, 0xa0, 0x57, 0xaa, + 0x68, 0xdd, 0x6d, 0x91, 0x1d, 0x20, 0xb9, 0x61, 0xe2, 0x7f, + 0x67, 0x94, 0x04, 0x74, 0xb7, 0xfc, 0xbc, 0x5c, 0x2c, 0xb4, + 0x31, 0x3f, 0x31, 0x1f, 0x0e, 0xc4, 0x49, 0x41, 0x34, 0x53, + 0x6b, 0x83, 0x8c, 0x53, 0xda, 0x33, 0x58, 0x5a, 0x11, 0xb9, + 0xd6, 0x72, 0x59, 0x98, 0xd1, 0x9e, 0x8f, 0x99, 0xe7, 0xfd, + 0x52, 0xf4, 0xb9, 0xbc, 0xaf, 0x9c, 0x66, 0x71, 0xf1, 0x3b, + 0xb4, 0x8f, 0x49, 0x00, 0x4f, 0x62, 0x50, 0xd9, 0xab, 0x24, + 0x41, 0x83, 0x52, 0x3e, 0x1c, 0xb2, 0x51, 0x29, 0x52, 0x95, + 0x73, 0xde, 0xb2, 0x1f, 0x8e, 0x8a, 0x9c, 0x4e, 0x65, 0x48, + 0x31, 0x61, 0x3f, 0x1f, 0x8e, 0xb9, 0xf0, 0x13, 0xbe, 0x7a, + 0x6d, 0xf2, 0xe7, 0xe5, 0x3d, 0x58, 0x3e, 0x44, 0xf4, 0x01, + 0x0c, 0x27, 0x6a, 0x1e, 0x64, 0x1f, 0xeb, 0x9d, 0xae, 0xeb, + 0x70, 0x81, 0x43, 0xdb, 0x8f, 0xd6, 0x6e, 0x84, 0x24, 0x67, + 0x66, 0x10, 0xa0, 0xf2, 0x75, 0x0a, 0xe2, 0xa7, 0x20, 0x7c, + 0xc8, 0x22, 0x78, 0x4f, 0x0e, 0x4e, 0x98, 0x64, 0x3c, 0x59, + 0x4d, 0x25, 0xad, 0x5a, 0xe6, 0x37, 0x5e, 0xe4, 0x33, 0xee, + 0x20, 0xd7, 0x46, 0x58, 0x32, 0x6c, 0xed, 0x3b, 0x6e, 0xad, + 0x19, 0x90, 0x68, 0x5e, 0x45, 0x99, 0xe0, 0xbf, 0x64, 0xda, + 0xc9, 0x44, 0x53, 0xa7, 0xad, 0x15, 0xe4, 0x2f, 0xa3, 0x8b, + 0x91, 0xa0, 0x17, 0x7f, 0x71, 0x2f, 0xdc, 0x72, 0x1e, 0xe0, + 0x75, 0x9a, 0xbc, 0x42, 0x53, 0xce, 0x3c, 0xbc, 0x06, 0x53, + 0xa0, 0xbe, 0x94, 0x56, 0xcd, 0xf4, 0x95, 0x23, 0x56, 0x59, + 0x29, 0xef, 0xe2, 0xf4, 0x46, 0xd0, 0x4b, 0x55, 0x7f, 0x57, + 0x51, 0x7c, 0x3c, 0x16, 0xb4, 0x4d, 0xd5, 0x93, 0x13, 0x15, + 0x0e, 0x55, 0x07, 0x9a, 0x69, 0x08, 0xbf, 0xd4, 0xd1, 0xb5, + 0x1d, 0xcf, 0xf5, 0x01, 0x25, 0x9a, 0xfe, 0xe6, 0xbc, 0x69, + 0xba, 0x25, 0xc0, 0x68, 0x15, 0xdc, 0x6a, 0xc7, 0x36, 0x17, + 0xe9, 0x38, 0x84, 0x1f, 0x84, 0x20, 0xc7, 0xe1, 0x64, 0x36, + 0xd4, 0x5a, 0xf3, 0xe3, 0x68, 0x3a, 0x1e, 0x4d, 0xb5, 0x89, + 0x71, 0x29, 0x30, 0xe5, 0xc8, 0x47, 0x13, 0x00, 0x59, 0x9f, + 0xb8, 0xd7, 0x97, 0x5f, 0x87, 0xb5, 0xaf, 0xb9, 0xbb, 0x30, + 0x8e, 0x2b, 0x2d, 0x35, 0x04, 0xaa, 0x5f, 0xc4, 0xeb, 0x96, + 0xfd, 0xa4, 0xa0, 0x71, 0x55, 0x70, 0xcc, 0x79, 0x76, 0xf5, + 0x39, 0xe2, 0xc0, 0x57, 0xab, 0x9a, 0x99, 0x5e, 0x6a, 0xe2, + 0x6d, 0x89, 0x2c, 0x47, 0xb9, 0x89, 0xf2, 0x5a, 0xd3, 0x0d, + 0xcd, 0x62, 0xaa, 0x9e, 0x50, 0x41, 0xf3, 0x08, 0xc2, 0x08, + 0x6a, 0x7e, 0x1c, 0x89, 0x4a, 0x6b, 0x72, 0xb4, 0xb2, 0x1c, + 0x9b, 0x89, 0x88, 0x4b, 0x84, 0x25, 0x19, 0x69, 0xf3, 0xe0, + 0x85, 0xf8, 0x39, 0xe6, 0xe8, 0xa1, 0x59, 0xe6, 0x88, 0x35, + 0x73, 0x3f, 0x0d, 0xed, 0x27, 0x8e, 0x1c, 0x5d, 0x04, 0x42, + 0x0d, 0xfe, 0x1d, 0xff, 0xb9, 0xdb, 0x29, 0x40, 0x5c, 0xd4, + 0xab, 0x0f, 0x81, 0x8f, 0x85, 0x87, 0x40, 0x52, 0xb3, 0x9f, + 0x33, 0xa0, 0xc4, 0xb7, 0x2c, 0x4a, 0x7a, 0xc7, 0xba, 0xd3, + 0xd3, 0x7d, 0x65, 0xa2, 0xd3, 0xb7, 0xc3, 0xbe, 0x12, 0x42, + 0xae, 0x98, 0x9d, 0x05, 0x9b, 0xa8, 0x8b, 0xb4, 0xa2, 0x57, + 0x72, 0x46, 0x75, 0xf1, 0x2b, 0xf8, 0x7d, 0xa8, 0x8d, 0x47, + 0x90, 0x7d, 0x53, 0xab, 0xc3, 0xc9, 0x01, 0x93, 0x7a, 0xce, + 0x85, 0xbc, 0x0b, 0x2a, 0xac, 0x90, 0x13, 0xf5, 0xe6, 0x5c, + 0xb3, 0x44, 0x0a, 0x87, 0x02, 0x85, 0x9d, 0xe2, 0x46, 0x70, + 0xf8, 0xc4, 0x85, 0xa3, 0x7a, 0xdf, 0x59, 0xba, 0x36, 0xd0, + 0x20, 0xb1, 0x84, 0xd4, 0xc7, 0x7d, 0x6e, 0x07, 0x2a, 0x21, + 0x58, 0x02, 0x48, 0xd1, 0xa9, 0x0a, 0x58, 0x9b, 0x2f, 0x4c, + 0x8b, 0x0b, 0x37, 0x3b, 0xa0, 0x97, 0xf9, 0x91, 0xbf, 0xd9, + 0x26, 0x4e, 0xd2, 0x55, 0x82, 0x69, 0x32, 0x9f, 0xe9, 0xaa, + 0x7e, 0x23, 0x92, 0x39, 0xa4, 0x3b, 0x68, 0x0d, 0xaf, 0x71, + 0x36, 0x1c, 0x58, 0x0d, 0xa9, 0xb9, 0xa6, 0xa3, 0x40, 0xad, + 0x69, 0xae, 0x47, 0x47, 0xcc, 0xd5, 0x17, 0x05, 0x30, 0xf9, + 0x71, 0xb3, 0x18, 0xb8, 0x5e, 0xcf, 0x0a, 0x31, 0xfa, 0x28, + 0x79, 0x3a, 0x2a, 0x08, 0xf9, 0x2f, 0x70, 0x8f, 0x2c, 0xba, + 0x25, 0xaf, 0x23, 0x29, 0x25, 0x8e, 0x26, 0x1a, 0x9d, 0x18, + 0xca, 0xab, 0x2b, 0x72, 0xed, 0xd5, 0x83, 0x76, 0x72, 0xb2, + 0x1a, 0x23, 0xa6, 0xd8, 0x27, 0xbf, 0xd2, 0xc0, 0x81, 0xb2, + 0xd6, 0xe3, 0x55, 0x60, 0x26, 0x0d, 0xff, 0x2e, 0xee, 0x5d, + 0x79, 0xe2, 0xa4, 0xc2, 0x15, 0x93, 0x11, 0xb8, 0x67, 0xa5, + 0x0b, 0xf6, 0xe3, 0x85, 0x2e, 0xec, 0x52, 0x27, 0xb1, 0xfb, + 0xfb, 0x42, 0x5b, 0x68, 0xa2, 0x23, 0xde, 0xef, 0x5b, 0xb0, + 0xad, 0x92, 0x36, 0x8d, 0x85, 0x6d, 0x0f, 0xe2, 0x89, 0xb9, + 0xd4, 0x31, 0x22, 0x89, 0xdc, 0xea, 0xe2, 0x70, 0x87, 0xdf, + 0x8f, 0x02, 0x25, 0x02, 0xbe, 0xa3, 0x40, 0x96, 0x91, 0x12, + 0x27, 0xd2, 0x02, 0xa0, 0xfa, 0x4c, 0x2f, 0x41, 0xf8, 0x88, + 0x03, 0xaf, 0xc9, 0x1b, 0x76, 0xe6, 0x72, 0x77, 0x6d, 0xce, + 0xc6, 0xc9, 0x3d, 0x1e, 0x37, 0x94, 0xe7, 0x06, 0xc0, 0x19, + 0xd7, 0x18, 0x7f, 0x4c, 0x58, 0xd3, 0xc2, 0x57, 0x60, 0x59, + 0x76, 0x28, 0xf0, 0x68, 0xbc, 0x80, 0xda, 0xad, 0xc8, 0x0f, + 0xc8, 0xa1, 0xf1, 0x0e, 0x6a, 0xb7, 0xac, 0x3b, 0x2c, 0x6b, + 0xf1, 0x14, 0x0e, 0x12, 0x78, 0xa4, 0x19, 0x23, 0x74, 0x91, + 0xb7, 0xcc, 0x99, 0x75, 0xf1, 0x45, 0xd4, 0x76, 0xd1, 0x06, + 0x22, 0xaf, 0x91, 0x70, 0xc1, 0x2e, 0xdc, 0x67, 0xe0, 0x7c, + 0xf8, 0x82, 0x76, 0x5b, 0x73, 0xda, 0x93, 0x81, 0xa0, 0x19, + 0xf3, 0xb4, 0x27, 0x5b, 0x2f, 0x76, 0x07, 0xc1, 0x86, 0x75, + 0xc4, 0xac, 0x22, 0x9e, 0x92, 0xa3, 0x30, 0x1f, 0xdb, 0x46, + 0xf5, 0xd3, 0xa1, 0x52, 0x40, 0xe2, 0xca, 0xc1, 0x35, 0xe1, + 0x26, 0x35, 0x5c, 0x37, 0x0b, 0x0f, 0x3c, 0xdc, 0xa7, 0x21, + 0x00, 0x6b, 0xea, 0x07, 0xd1, 0x90, 0xa3, 0x26, 0x33, 0x73, + 0xa6, 0x1b, 0x2d, 0xb9, 0x49, 0xd5, 0x27, 0x39, 0x4e, 0x82, + 0x9d, 0x61, 0x04, 0x4b, 0x81, 0xeb, 0x38, 0xad, 0x73, 0xc0, + 0xfa, 0x8e, 0x33, 0xd5, 0x2a, 0xa6, 0xad, 0x40, 0xb7, 0x1e, + 0xcc, 0x65, 0xce, 0xe4, 0x43, 0xca, 0x9d, 0x83, 0xf9, 0xdb, + 0x99, 0x2c, 0x11, 0xd9, 0xd9, 0xed, 0xb2, 0x56, 0x77, 0x23, + 0x1a, 0xcc, 0x25, 0xce, 0xe5, 0xc3, 0xc3, 0xd2, 0x45, 0xeb, + 0xf5, 0x5c, 0x96, 0xd0, 0x51, 0xaa, 0xef, 0x45, 0x70, 0x34, + 0x7f, 0xd2, 0x23, 0x7a, 0xbf, 0xd1, 0x11, 0x7d, 0x35, 0x33, + 0x84, 0x37, 0x09, 0xe6, 0x90, 0xbf, 0x0a, 0xe0, 0x2c, 0x2f, + 0xea, 0x6e, 0x43, 0x03, 0x15, 0x5e, 0x1a, 0x06, 0xb3, 0xe9, + 0x54, 0x4b, 0x1d, 0x9a, 0x99, 0xc3, 0x7e, 0x60, 0xfb, 0xff, + 0x07, 0xbf, 0xdd, 0xfb, 0x60, 0x19, 0x4b, 0x6a, 0x0a, 0x47, + 0x3f, 0x93, 0xa6, 0x50, 0x26, 0xdc, 0x6f, 0x85, 0x87, 0x35, + 0x6c, 0x67, 0xce, 0xcb, 0x74, 0x0a, 0x02, 0x97, 0xd4, 0x68, + 0x1c, 0x36, 0x85, 0x08, 0x1b, 0x1b, 0xb0, 0x84, 0x8c, 0xbe, + 0xcc, 0x05, 0x4f, 0x95, 0xb5, 0x7a, 0xc0, 0x99, 0xbf, 0x85, + 0xea, 0xd2, 0x0e, 0x14, 0xd8, 0xa0, 0x4e, 0xf7, 0x1d, 0xa6, + 0x45, 0x91, 0x4b, 0x9a, 0xc9, 0x33, 0x87, 0x8d, 0x25, 0x66, + 0xe8, 0x75, 0x8e, 0x31, 0x7e, 0xc4, 0xd1, 0xd2, 0x1b, 0xe6, + 0xed, 0x7d, 0x4a, 0x3f, 0xb4, 0x22, 0x68, 0x87, 0x2e, 0x86, + 0x2d, 0xc8, 0x25, 0x82, 0x80, 0xfd, 0xbd, 0x4e, 0xfe, 0xc8, + 0x8d, 0xe1, 0x9a, 0xd6, 0x68, 0x99, 0x0a, 0x22, 0x42, 0x8e, + 0x1d, 0xd6, 0x9a, 0x9b, 0x6e, 0xec, 0xec, 0x81, 0x38, 0xbf, + 0x1c, 0xd8, 0xae, 0x09, 0x72, 0x55, 0xe1, 0x70, 0xca, 0x90, + 0x47, 0xda, 0x8f, 0x24, 0xce, 0xd4, 0xb9, 0xc2, 0x06, 0xa9, + 0xb6, 0x97, 0xd7, 0xff, 0xba, 0x4e, 0x9f, 0xbd, 0x4c, 0xa8, + 0xb0, 0x50, 0x30, 0xea, 0xb2, 0x1b, 0x69, 0x28, 0x72, 0x44, + 0xc2, 0x1a, 0x94, 0x42, 0x0d, 0xc9, 0x4a, 0xec, 0x71, 0xba, + 0x14, 0xf5, 0xdb, 0xfb, 0x90, 0x63, 0xbf, 0x06, 0x68, 0xb0, + 0x19, 0x8c, 0x19, 0x65, 0xb3, 0x0c, 0x81, 0xab, 0xf5, 0xce, + 0xc6, 0xfa, 0x83, 0x1c, 0xa2, 0x8d, 0x28, 0x8a, 0x9a, 0x9b, + 0x88, 0xff, 0x0a, 0x4b, 0xcd, 0x6e, 0x82, 0xfa, 0xc5, 0x3e, + 0xe2, 0x16, 0x9b, 0xad, 0x5b, 0xbb, 0xdc, 0xa4, 0x00, 0x92, + 0x2b, 0x7c, 0xda, 0x94, 0xd6, 0x22, 0x3c, 0x66, 0x69, 0xb1, + 0xcf, 0x52, 0xd9, 0x02, 0x23, 0xe1, 0xdb, 0x12, 0x5d, 0x23, + 0xf0, 0x1d, 0x97, 0x9b, 0x7d, 0xe6, 0x6a, 0xc8, 0xfe, 0xb1, + 0x0d, 0x71, 0x61, 0x5d, 0x19, 0xca, 0x76, 0xaf, 0xcb, 0xab, + 0xad, 0x89, 0xdb, 0xe6, 0xae, 0xc0, 0xd9, 0xb1, 0x6c, 0x81, + 0xe9, 0x7b, 0x77, 0x5a, 0xb9, 0xd0, 0xd9, 0xb1, 0x1d, 0x7c, + 0x11, 0x54, 0xca, 0xda, 0x07, 0x41, 0xb0, 0x11, 0xbe, 0xfb, + 0x25, 0x11, 0xbe, 0xd5, 0xd1, 0xc4, 0x07, 0xd2, 0xd1, 0xc4, + 0x8c, 0x37, 0x25, 0x8f, 0xe6, 0x55, 0x55, 0x25, 0x75, 0x6b, + 0xe4, 0x60, 0xba, 0xca, 0x2b, 0x40, 0xb5, 0x5c, 0x17, 0x9f, + 0x71, 0xa1, 0x56, 0x1e, 0xee, 0xaa, 0x94, 0x72, 0xd3, 0x9a, + 0x8f, 0xd5, 0xa9, 0xe8, 0x3b, 0x08, 0x62, 0x05, 0xad, 0xa7, + 0xb4, 0x63, 0x42, 0xd1, 0x61, 0x28, 0x08, 0xc3, 0x72, 0x8d, + 0x8d, 0x17, 0x93, 0x52, 0xa1, 0xff, 0x22, 0x23, 0xe6, 0xec, + 0x10, 0x65, 0xdc, 0x78, 0x52, 0xca, 0x8d, 0x8d, 0xe2, 0x32, + 0xaa, 0x4c, 0x14, 0xda, 0xa0, 0xbd, 0x6b, 0xf6, 0x74, 0x86, + 0x2f, 0x1b, 0x17, 0xa3, 0xcb, 0x85, 0x9e, 0xbb, 0x61, 0x4d, + 0x03, 0x7c, 0xd7, 0xb8, 0x73, 0x57, 0xdb, 0xca, 0xc7, 0xa0, + 0x84, 0x45, 0x87, 0xc5, 0x3c, 0xea, 0xd4, 0x85, 0xbc, 0x0f, + 0x45, 0x7c, 0x5a, 0xbf, 0xa6, 0x1a, 0x63, 0x22, 0x39, 0x2a, + 0x36, 0xab, 0x14, 0xb8, 0x44, 0x98, 0x19, 0xde, 0x16, 0x75, + 0x39, 0x80, 0xb2, 0xea, 0x11, 0x54, 0x6f, 0x88, 0xf9, 0x68, + 0x7a, 0x29, 0x32, 0x2b, 0x72, 0xc7, 0x65, 0x71, 0xbe, 0x6a, + 0xbd, 0x68, 0x44, 0xa5, 0xdf, 0x29, 0x7b, 0x61, 0x29, 0x76, + 0x33, 0xf1, 0x88, 0x63, 0x54, 0x92, 0x6d, 0x73, 0xbf, 0xc4, + 0x69, 0x3f, 0x71, 0x9f, 0x2a, 0xc9, 0xbb, 0x29, 0xc5, 0xe5, + 0xa8, 0x77, 0xc3, 0x73, 0x19, 0xb6, 0xfe, 0xc8, 0xdf, 0x3a, + 0xce, 0x9b, 0x46, 0x13, 0x0d, 0xcf, 0xcd, 0x3f, 0x1b, 0x22, + 0x26, 0x67, 0x18, 0x38, 0xac, 0x45, 0xb2, 0xac, 0x7f, 0xde, + 0x3d, 0x92, 0x42, 0xd4, 0x6c, 0x1d, 0xe1, 0x34, 0x3c, 0xef, + 0x12, 0xe3, 0x94, 0x03, 0xda, 0xcb, 0x44, 0xb4, 0xac, 0xe7, + 0xf0, 0x50, 0x1b, 0x8b, 0x02, 0x01, 0x78, 0x20, 0x06, 0xcd, + 0xa8, 0x5c, 0x6a, 0xe2, 0x29, 0x76, 0xd9, 0xb4, 0x23, 0x90, + 0x84, 0x35, 0x9a, 0x5e, 0xcc, 0x44, 0xff, 0xa4, 0x84, 0x8e, + 0x82, 0x71, 0x17, 0xa5, 0xe1, 0xb9, 0xc7, 0x9a, 0xaa, 0x0b, + 0x72, 0x64, 0xe0, 0x01, 0x3b, 0xc4, 0x86, 0xbf, 0x5b, 0x3b, + 0x02, 0x8d, 0xfa, 0x95, 0xbc, 0x55, 0x70, 0xf2, 0x05, 0x75, + 0x2c, 0x25, 0x46, 0x0e, 0x09, 0xe5, 0xbd, 0xe1, 0xae, 0x37, + 0x1e, 0xf8, 0xb5, 0x11, 0xed, 0x21, 0x43, 0xfc, 0x63, 0x15, + 0xf1, 0x21, 0x88, 0x21, 0xf3, 0x02, 0xe7, 0xd7, 0x16, 0xe0, + 0xdb, 0xa7, 0x9c, 0x9b, 0x23, 0x3c, 0x31, 0xe8, 0x39, 0xdb, + 0xc2, 0x3b, 0xbc, 0x77, 0x88, 0xd7, 0x3e, 0x6d, 0x2e, 0x36, + 0x0d, 0x84, 0x53, 0xc3, 0xd5, 0x96, 0xe4, 0x6d, 0x6b, 0x7e, + 0xe5, 0x62, 0x2d, 0x69, 0x50, 0x84, 0xc3, 0x65, 0x45, 0x94, + 0x90, 0x4f, 0x41, 0x37, 0xbb, 0x5a, 0x89, 0x34, 0x97, 0xd6, + 0x54, 0x4e, 0x05, 0x91, 0xce, 0xbc, 0x97, 0x94, 0xf8, 0x86, + 0xb2, 0xf0, 0x7d, 0xb8, 0x52, 0x11, 0x5c, 0x7a, 0xb3, 0xa5, + 0x8a, 0xdc, 0x17, 0x20, 0x92, 0x34, 0xe0, 0x37, 0x14, 0x53, + 0x83, 0x60, 0x2f, 0x51, 0xa1, 0x48, 0x06, 0x48, 0x26, 0x7f, + 0x92, 0xde, 0x23, 0x6f, 0x89, 0x3c, 0x70, 0xde, 0x00, 0x7f, + 0x6f, 0x81, 0x9c, 0x57, 0xd6, 0x42, 0x44, 0xd9, 0x4d, 0x68, + 0x20, 0x49, 0xb2, 0xa9, 0x3a, 0x0e, 0x91, 0xf0, 0x6d, 0xdc, + 0x4e, 0x93, 0x36, 0x7c, 0xbb, 0x74, 0x18, 0x49, 0x2b, 0xed, + 0x6f, 0x8e, 0x6b, 0x27, 0x13, 0x45, 0x93, 0xe1, 0x89, 0x84, + 0x77, 0x57, 0xe1, 0x52, 0x46, 0x16, 0x61, 0xf4, 0xbc, 0x9e, + 0x3e, 0x3c, 0xe7, 0x18, 0x9d, 0x59, 0x6c, 0x97, 0x41, 0xc0, + 0xed, 0xc1, 0x30, 0x20, 0x34, 0x54, 0xbf, 0x05, 0xce, 0xc4, + 0x2d, 0xc0, 0xd6, 0x7f, 0x75, 0xf9, 0x52, 0xbc, 0x01, 0x0c, + 0xfc, 0xa1, 0x3d, 0xab, 0x94, 0x30, 0xbc, 0x53, 0xc2, 0xf1, + 0x6f, 0x8c, 0xde, 0xde, 0x8d, 0x11, 0xad, 0x57, 0x03, 0x43, + 0xc5, 0x27, 0xde, 0xa9, 0xbe, 0x71, 0x40, 0x66, 0xb9, 0x76, + 0x3d, 0x1f, 0xbc, 0x29, 0xd7, 0xaf, 0xab, 0x5c, 0x77, 0x98, + 0xe1, 0x52, 0xf8, 0x80, 0x66, 0x5a, 0x6d, 0x09, 0x86, 0x40, + 0x33, 0x22, 0xe3, 0x99, 0x2a, 0xde, 0xbe, 0xc7, 0x81, 0xed, + 0xb4, 0x54, 0xd1, 0x8f, 0x64, 0x55, 0xf4, 0x1f, 0xaf, 0x02, + 0xe6, 0xde, 0xba, 0x9b, 0x49, 0x8e, 0x06, 0x69, 0x02, 0xd9, + 0x48, 0xab, 0x5c, 0x30, 0x6a, 0x75, 0x0a, 0x20, 0x1a, 0xbd, + 0xb9, 0xbf, 0x9f, 0xcb, 0x02, 0x04, 0x94, 0x6b, 0x4e, 0x38, + 0x48, 0x80, 0x64, 0x5d, 0x4e, 0x67, 0x7a, 0x12, 0x1b, 0x64, + 0x30, 0xa4, 0xb3, 0xa5, 0x1f, 0xad, 0xfc, 0x20, 0x04, 0xe4, + 0x8d, 0xbb, 0x22, 0x22, 0xf8, 0x6f, 0x0d, 0x14, 0xe5, 0x64, + 0xed, 0xf6, 0xc8, 0x2e, 0x7c, 0x3d, 0xb5, 0xb9, 0x2f, 0x7d, + 0x59, 0xde, 0xbc, 0x87, 0x59, 0x20, 0x8d, 0x67, 0x45, 0x41, + 0x35, 0x58, 0xa8, 0x53, 0xbf, 0x65, 0x56, 0xa8, 0xf7, 0x66, + 0xea, 0x9b, 0x77, 0x30, 0xf5, 0x9d, 0xa3, 0x4c, 0x62, 0x39, + 0x1b, 0xdf, 0x39, 0x4a, 0x1e, 0xd6, 0x28, 0xb6, 0x5c, 0x1d, + 0xde, 0xe4, 0xc4, 0xbc, 0xed, 0xec, 0xe4, 0xd9, 0x70, 0x3a, + 0x32, 0x47, 0x90, 0xc3, 0xbf, 0x65, 0x96, 0x35, 0xca, 0x80, + 0x70, 0x28, 0x2e, 0xe4, 0xef, 0x17, 0xd6, 0x5f, 0xac, 0x3e, + 0xb1, 0x94, 0x36, 0x58, 0x98, 0x19, 0xb1, 0x23, 0x21, 0x24, + 0xb0, 0x9c, 0x52, 0x53, 0xa1, 0x81, 0xce, 0x90, 0x2e, 0xaa, + 0x1d, 0x93, 0xeb, 0x28, 0xa5, 0xc7, 0xe4, 0x39, 0x2a, 0x8c, + 0xf2, 0x95, 0xa2, 0x4b, 0x43, 0x03, 0x78, 0xe2, 0xf4, 0xb4, + 0x2b, 0xf2, 0x10, 0xff, 0xbb, 0xec, 0x73, 0x77, 0xd1, 0xe3, + 0x66, 0x87, 0xa9, 0x40, 0x14, 0x5f, 0x23, 0x6f, 0x95, 0x44, + 0x2a, 0xa9, 0x56, 0x53, 0x8c, 0x41, 0xd7, 0x83, 0x6d, 0xbc, + 0x0c, 0x04, 0x45, 0x14, 0x4f, 0xf3, 0x2c, 0xfd, 0x43, 0xba, + 0x43, 0xc7, 0xf3, 0x59, 0x07, 0x63, 0xfc, 0x54, 0xcb, 0x99, + 0xe0, 0x7d, 0x79, 0x01, 0x5f, 0xac, 0x84, 0xa5, 0xba, 0x97, + 0x2c, 0x95, 0x62, 0x55, 0x2c, 0xd5, 0xc0, 0x3a, 0x43, 0x29, + 0xf2, 0x6e, 0x1f, 0xb5, 0x5a, 0xf2, 0xc7, 0x83, 0x42, 0xdf, + 0x90, 0x9c, 0x2c, 0xfd, 0x8f, 0xd2, 0x27, 0x3d, 0xf6, 0x06, + 0x51, 0x7c, 0x57, 0x28, 0xb1, 0xbd, 0x73, 0x48, 0x9e, 0xd7, + 0x2c, 0x7e, 0x67, 0x6d, 0xd5, 0x0a, 0xd5, 0xfc, 0xba, 0xbd, + 0xe1, 0xfb, 0x7c, 0x36, 0x1b, 0x6b, 0xe9, 0xdb, 0xd9, 0x3e, + 0x63, 0x78, 0xf3, 0x80, 0x5d, 0xe1, 0x51, 0x36, 0x5d, 0x4c, + 0xce, 0x73, 0xf9, 0x82, 0xa6, 0xdb, 0xf5, 0x2d, 0x08, 0x65, + 0x82, 0xf4, 0x0e, 0xe5, 0x82, 0xf4, 0x26, 0x90, 0xf3, 0xd4, + 0x4b, 0x31, 0xa5, 0x89, 0x18, 0x0c, 0x58, 0xfd, 0xa8, 0xbc, + 0x64, 0xa4, 0x98, 0x8a, 0x7f, 0x29, 0xe2, 0xec, 0xa9, 0x1d, + 0xc2, 0xab, 0xe6, 0x0b, 0x33, 0x17, 0x58, 0xb5, 0xd9, 0x56, + 0x8c, 0x69, 0xb6, 0x30, 0xe7, 0x39, 0xdc, 0x1e, 0xb8, 0xe5, + 0x2b, 0x2b, 0xc1, 0x63, 0x36, 0x45, 0xba, 0x63, 0x94, 0xea, + 0xa5, 0xed, 0xb5, 0x40, 0xfa, 0x41, 0x3c, 0x7f, 0x09, 0x7c, + 0x10, 0xca, 0x9a, 0x30, 0x3e, 0xf2, 0xbe, 0x2c, 0x6c, 0x5d, + 0xe9, 0x0d, 0xb3, 0x5c, 0x97, 0xbf, 0x7f, 0x0f, 0x3a, 0xe4, + 0x43, 0xbd, 0xd4, 0xa6, 0x1a, 0xa3, 0xd5, 0xd2, 0xcb, 0x02, + 0xee, 0x23, 0x68, 0x78, 0xe0, 0xe7, 0x90, 0xb2, 0x49, 0x56, + 0xad, 0x36, 0x87, 0xfd, 0x2b, 0x23, 0x1b, 0x95, 0xdc, 0xa5, + 0x5b, 0xa4, 0xf0, 0x3c, 0x68, 0x97, 0xc2, 0x93, 0x3b, 0x17, + 0x0e, 0x25, 0xcf, 0x85, 0xef, 0x7d, 0xa5, 0xda, 0xd8, 0xa1, + 0xbd, 0xa6, 0x3a, 0x0c, 0xfa, 0x85, 0x92, 0x73, 0x47, 0xaf, + 0x92, 0xaf, 0x7c, 0x0c, 0x35, 0x56, 0x10, 0xb6, 0xd7, 0xf2, + 0x69, 0xd2, 0x6b, 0x4c, 0xa8, 0x91, 0x7e, 0xbf, 0x0a, 0x83, + 0xed, 0xc6, 0x62, 0x4f, 0x25, 0x84, 0xfa, 0xbd, 0xe9, 0x60, + 0xc7, 0xa2, 0xfc, 0x4b, 0x9c, 0xab, 0x14, 0x14, 0xfc, 0x71, + 0x0f, 0x14, 0x8f, 0x74, 0x2e, 0xe2, 0xef, 0x10, 0xaf, 0xc6, + 0xd0, 0x55, 0x4e, 0x1f, 0x39, 0x47, 0x6c, 0x49, 0xdc, 0xc7, + 0xc3, 0x16, 0xb8, 0x8f, 0x3d, 0xe5, 0x53, 0x7f, 0x4f, 0x12, + 0x65, 0xfc, 0xfa, 0x33, 0x64, 0x54, 0xef, 0xa7, 0x2f, 0xf7, + 0xc0, 0x5d, 0xdd, 0xc7, 0x14, 0x55, 0x06, 0xfd, 0x2a, 0x20, + 0xdd, 0x3c, 0x8e, 0xf4, 0x39, 0x93, 0x9f, 0x77, 0x77, 0x28, + 0x1d, 0x9b, 0x0f, 0x97, 0xaa, 0x13, 0xee, 0xe4, 0x4e, 0x20, + 0x08, 0xec, 0x28, 0xee, 0x94, 0xfd, 0x5d, 0xa0, 0xe7, 0x60, + 0x17, 0xfc, 0xf6, 0xf4, 0x36, 0xf7, 0x6e, 0xeb, 0x55, 0xd5, + 0x03, 0x92, 0x20, 0x45, 0x09, 0xd0, 0x0d, 0xe5, 0x59, 0xc1, + 0x40, 0xe7, 0xa5, 0xc9, 0x52, 0xa4, 0x9c, 0x84, 0xef, 0xf1, + 0xdd, 0xa7, 0x80, 0xe5, 0x3f, 0xed, 0x17, 0x33, 0xfc, 0xa7, + 0xfd, 0xe2, 0xde, 0xec, 0x7a, 0xe8, 0xcd, 0x26, 0xea, 0x6b, + 0x6e, 0x5e, 0x7a, 0xe8, 0xcd, 0xe3, 0x33, 0x9f, 0x5b, 0x41, + 0xb9, 0x06, 0x5e, 0xb0, 0x44, 0xd9, 0xe2, 0xbe, 0x2a, 0xef, + 0xa7, 0x88, 0x4f, 0x7f, 0x2d, 0xcf, 0x05, 0x24, 0xd5, 0xc0, + 0xae, 0xac, 0x81, 0x1b, 0xe5, 0xbd, 0x06, 0xf9, 0xb6, 0x2b, + 0xfd, 0x97, 0x32, 0xfa, 0xdf, 0x94, 0xf7, 0x43, 0xc8, 0xc7, + 0x1d, 0xe9, 0x6f, 0xda, 0x27, 0x14, 0xf2, 0x57, 0x5b, 0xcf, + 0x0e, 0x69, 0x87, 0x5c, 0x5f, 0x79, 0x2e, 0x5d, 0x2d, 0xc9, + 0xee, 0xfc, 0xd1, 0x6b, 0x77, 0x76, 0x5d, 0xbb, 0x13, 0xf6, + 0xda, 0x9d, 0x97, 0xae, 0xdd, 0x89, 0x28, 0x3b, 0x27, 0x90, + 0xb9, 0x7d, 0xb3, 0x73, 0x44, 0xf9, 0x59, 0x6c, 0xa1, 0x1f, + 0x7e, 0x8e, 0x28, 0x43, 0x8b, 0x0d, 0xb4, 0x62, 0x68, 0x99, + 0x78, 0x1f, 0x24, 0x54, 0x10, 0xf2, 0x51, 0x24, 0x73, 0x83, + 0x3a, 0xe6, 0x9f, 0x5f, 0x99, 0xba, 0x52, 0xea, 0xdd, 0x6b, + 0xe8, 0xc6, 0xe5, 0xe6, 0x04, 0xb3, 0xbd, 0x32, 0x37, 0x87, + 0x7a, 0xd6, 0x38, 0x6f, 0x4d, 0x00, 0x77, 0xe8, 0x0d, 0x80, + 0x73, 0xc6, 0x2d, 0xba, 0x4a, 0x67, 0x35, 0x0f, 0x98, 0x9c, + 0x50, 0x28, 0xbc, 0xa6, 0xba, 0xe6, 0x7c, 0x66, 0x98, 0xb4, + 0x2e, 0xc5, 0x5f, 0xbf, 0x83, 0xaa, 0x7e, 0x03, 0x0f, 0xe0, + 0x30, 0xd8, 0xa0, 0x6c, 0x6e, 0x34, 0xad, 0xe3, 0x9c, 0xf9, + 0x92, 0x19, 0x0b, 0xf4, 0x79, 0x4b, 0x50, 0xd0, 0x73, 0xd5, + 0x60, 0x10, 0x41, 0xe9, 0xdc, 0xd8, 0x91, 0xbb, 0x6c, 0xf6, + 0x36, 0x36, 0x9d, 0x61, 0xb0, 0xa4, 0xd4, 0x65, 0x8c, 0xc5, + 0x17, 0x9d, 0x06, 0x18, 0x2f, 0xc9, 0x0e, 0x1b, 0x58, 0xce, + 0x2f, 0x90, 0xf1, 0xbc, 0x00, 0x5f, 0x74, 0xe4, 0xdf, 0xb9, + 0x7e, 0x13, 0x78, 0xd1, 0xc1, 0xcd, 0x60, 0x3c, 0xca, 0xec, + 0x14, 0x2c, 0xc6, 0xe8, 0x60, 0xb7, 0xf4, 0x50, 0x9a, 0x3c, + 0x79, 0x38, 0xfd, 0x31, 0xa5, 0x72, 0xca, 0xc2, 0x73, 0xb5, + 0xb8, 0x58, 0xa6, 0x79, 0xc6, 0x22, 0x31, 0xd1, 0x58, 0xcb, + 0x6b, 0x60, 0xbe, 0x01, 0x58, 0xd0, 0xf6, 0x97, 0x94, 0x71, + 0x86, 0xf4, 0x43, 0x2f, 0x0d, 0x08, 0x91, 0x11, 0x42, 0xb4, + 0x4b, 0x47, 0xe2, 0x65, 0x30, 0x8c, 0x5d, 0xee, 0xc6, 0xe5, + 0x00, 0xd3, 0xc0, 0xc9, 0x5d, 0x90, 0x07, 0x83, 0x45, 0x8a, + 0xcf, 0xb3, 0xcf, 0xdf, 0xcc, 0x80, 0x53, 0x72, 0x09, 0x2e, + 0xb7, 0x33, 0xe1, 0x7b, 0x5a, 0x19, 0x42, 0x69, 0x93, 0x84, + 0x88, 0xa5, 0xa8, 0xa4, 0x92, 0x44, 0xca, 0xa1, 0x3f, 0x79, + 0x12, 0x72, 0x77, 0x83, 0x30, 0xf0, 0x3c, 0xaa, 0xcf, 0x7a, + 0x5e, 0xb7, 0x3b, 0xdb, 0xc6, 0xc5, 0x10, 0xfe, 0x89, 0x94, + 0x73, 0x39, 0x3c, 0xff, 0x36, 0xf4, 0x76, 0xf6, 0x53, 0x96, + 0xa5, 0x09, 0xfd, 0xb3, 0x0b, 0xad, 0x70, 0xb9, 0xe1, 0xdc, + 0x8b, 0x74, 0xb0, 0x04, 0x1b, 0x26, 0x31, 0xba, 0x1f, 0xc4, + 0xd8, 0x86, 0x18, 0x86, 0x60, 0x19, 0x2b, 0x18, 0xd4, 0x19, + 0xca, 0xe6, 0x54, 0xc3, 0xbf, 0x53, 0xe2, 0x7b, 0x37, 0x52, + 0x08, 0xc9, 0xb5, 0xbd, 0x53, 0xd0, 0xcb, 0xbf, 0x0b, 0xcf, + 0x9e, 0x68, 0xe7, 0x2f, 0xef, 0xc3, 0xc0, 0x77, 0x5f, 0xb2, + 0x92, 0x4b, 0xf4, 0x4a, 0x19, 0x29, 0xb7, 0x20, 0x7e, 0x02, + 0xc0, 0xc7, 0x91, 0xcb, 0xf0, 0xbc, 0xb0, 0xa1, 0x36, 0x0c, + 0x49, 0xbb, 0x1b, 0x97, 0x79, 0x53, 0x6e, 0xe3, 0xb9, 0xc7, + 0x78, 0x32, 0x11, 0x40, 0xc0, 0xce, 0x27, 0x76, 0xc4, 0xbd, + 0x71, 0x25, 0x9e, 0x4a, 0xfc, 0xd1, 0x6d, 0x98, 0x37, 0x73, + 0xad, 0x03, 0x28, 0xa4, 0x55, 0x80, 0x0a, 0xf9, 0xa1, 0x0a, + 0x16, 0xd2, 0xd4, 0xd5, 0xc1, 0xe7, 0xdc, 0x43, 0x00, 0x4e, + 0x13, 0x52, 0xf5, 0x12, 0x60, 0x4c, 0x72, 0x96, 0x43, 0xf4, + 0xa5, 0x0e, 0x7c, 0xd2, 0x42, 0x18, 0x83, 0x22, 0x26, 0x64, + 0x0a, 0x41, 0x89, 0xf1, 0x08, 0xd7, 0xe5, 0x44, 0xb8, 0x10, + 0xfa, 0xc3, 0x13, 0x31, 0x1d, 0x5c, 0x22, 0x63, 0x5a, 0x41, + 0xe7, 0xaf, 0x21, 0x53, 0x1a, 0xc0, 0x8f, 0x82, 0x90, 0xf8, + 0x0d, 0x14, 0x0a, 0x37, 0xe6, 0x69, 0x1b, 0x95, 0x57, 0x48, + 0x85, 0xc4, 0xd3, 0xa0, 0x36, 0x88, 0x8c, 0x72, 0x53, 0x51, + 0xa4, 0x87, 0x14, 0xfb, 0xe0, 0xf6, 0xac, 0xa5, 0x67, 0xd3, + 0x07, 0x91, 0x01, 0xf9, 0xd1, 0x2e, 0x71, 0xf4, 0x4f, 0x22, + 0x69, 0x6d, 0x2f, 0x2e, 0x03, 0x7d, 0x96, 0x4c, 0xee, 0x5a, + 0x0d, 0x8d, 0x2c, 0x9d, 0x6c, 0x96, 0x45, 0xee, 0x18, 0x40, + 0x96, 0x0c, 0xd6, 0x25, 0xc0, 0x88, 0xb9, 0x03, 0xb5, 0x28, + 0x90, 0xa6, 0x88, 0xd3, 0x26, 0xf6, 0xa6, 0x84, 0xb9, 0x0e, + 0xe9, 0x33, 0xf5, 0xa6, 0x21, 0x37, 0x75, 0xf4, 0x5a, 0x02, + 0x76, 0xbc, 0x0d, 0xf3, 0x91, 0xf8, 0xb0, 0x1f, 0x17, 0xe4, + 0x4f, 0x99, 0x72, 0x91, 0x95, 0xec, 0xc5, 0x19, 0x97, 0x6d, + 0xa0, 0x70, 0x4a, 0x8e, 0x98, 0x29, 0x51, 0xb2, 0xa2, 0xdf, + 0x7f, 0x6a, 0x38, 0xa9, 0x9d, 0xf4, 0x43, 0x48, 0x83, 0xd4, + 0x49, 0x6a, 0xcf, 0x67, 0xa2, 0xcc, 0x9e, 0x07, 0x90, 0x06, + 0x3a, 0xe2, 0x70, 0x52, 0x83, 0x26, 0xef, 0x42, 0x17, 0xa3, + 0xf1, 0x58, 0x1b, 0xce, 0x67, 0x63, 0xd1, 0x1d, 0xe7, 0xc2, + 0xf5, 0x3c, 0xa8, 0x8e, 0xcd, 0x03, 0x6f, 0xb7, 0x0a, 0xe4, + 0xaf, 0x2a, 0x83, 0xd9, 0xd4, 0x9c, 0xa1, 0x28, 0x40, 0x4a, + 0x92, 0xe2, 0x8e, 0x20, 0xaf, 0xfe, 0x00, 0x45, 0x01, 0x36, + 0x26, 0x8b, 0xae, 0x3f, 0xc2, 0x29, 0x30, 0x76, 0x1b, 0x38, + 0x35, 0x60, 0xbc, 0xab, 0xf9, 0x0c, 0x65, 0x1a, 0x15, 0xc2, + 0x6e, 0x70, 0xd4, 0xf1, 0x26, 0x40, 0xaa, 0x40, 0xb3, 0x7c, + 0x20, 0xe3, 0xd9, 0x20, 0x17, 0xd2, 0x87, 0xfc, 0x2f, 0xd1, + 0x2b, 0x6d, 0x55, 0xe4, 0x4a, 0x01, 0xdc, 0xcb, 0x44, 0xd3, + 0xb5, 0x0b, 0x21, 0xc4, 0xe6, 0x2a, 0xe0, 0xb2, 0xde, 0xb6, + 0xf1, 0x81, 0x5c, 0xdd, 0x5a, 0x21, 0x60, 0x1c, 0x20, 0x1d, + 0xe4, 0xf1, 0x16, 0xf8, 0x80, 0x0f, 0xad, 0x38, 0x93, 0x05, + 0x18, 0x86, 0xe4, 0x56, 0x21, 0x54, 0x9c, 0xa8, 0x25, 0x11, + 0xfe, 0xe8, 0x4c, 0xf2, 0x96, 0x71, 0x8f, 0x38, 0x87, 0xff, + 0xee, 0x44, 0xf0, 0x2e, 0xdd, 0xf4, 0x39, 0xd1, 0x84, 0x77, + 0x88, 0xb0, 0x27, 0xfb, 0x93, 0x4b, 0x09, 0xf5, 0x42, 0xa9, + 0x74, 0xcc, 0x48, 0xa5, 0xa4, 0x5c, 0xad, 0x48, 0xfa, 0xf3, + 0x1e, 0xb5, 0x75, 0x09, 0x74, 0x97, 0x5b, 0xed, 0x11, 0x94, + 0xce, 0x15, 0x4d, 0x2e, 0x3e, 0x58, 0x28, 0x49, 0xc1, 0xda, + 0xc9, 0x62, 0xa5, 0x2d, 0xae, 0x23, 0xa8, 0xc8, 0x5a, 0x07, + 0x67, 0x99, 0xf1, 0xec, 0xd2, 0xd2, 0xa6, 0xa6, 0x2e, 0x4a, + 0xc7, 0x71, 0xb0, 0x52, 0xce, 0x83, 0xe0, 0x41, 0xd1, 0xfc, + 0x38, 0xdc, 0xa1, 0x18, 0x85, 0xaa, 0xb8, 0x61, 0x64, 0xab, + 0xb2, 0xd4, 0xe1, 0x30, 0x17, 0xa4, 0x8c, 0xed, 0x7a, 0x32, + 0x95, 0x75, 0x6d, 0x32, 0xbb, 0xce, 0x85, 0x2b, 0xe3, 0xea, + 0x48, 0xb9, 0x7c, 0xac, 0x25, 0x30, 0xb8, 0x42, 0xf8, 0xb8, + 0x43, 0x41, 0xf8, 0x25, 0x40, 0xfc, 0x38, 0x94, 0xa3, 0x0a, + 0xa6, 0x77, 0x6e, 0x5d, 0x68, 0xaa, 0x09, 0xc5, 0x3a, 0x3b, + 0x8a, 0x13, 0xf6, 0xb8, 0x4d, 0x76, 0x9e, 0x62, 0x57, 0x0f, + 0x86, 0x25, 0xc5, 0x8d, 0xe9, 0x63, 0x11, 0xb1, 0xb0, 0x6e, + 0x68, 0x2c, 0x39, 0x6e, 0x84, 0xa7, 0x45, 0xe4, 0x96, 0x75, + 0x03, 0x35, 0xb5, 0xb1, 0x36, 0x9b, 0x6b, 0x24, 0x7b, 0x82, + 0xc5, 0x65, 0x7d, 0xca, 0x82, 0x7a, 0xcc, 0x7b, 0x90, 0xde, + 0x1c, 0xe1, 0xbd, 0x13, 0xde, 0x23, 0x94, 0x18, 0x78, 0x20, + 0x20, 0x2e, 0x1f, 0x38, 0xf9, 0x1a, 0x50, 0x52, 0xd3, 0xae, + 0x64, 0x43, 0xda, 0x34, 0x9b, 0xd3, 0x4f, 0x05, 0xcd, 0x44, + 0x24, 0x71, 0x93, 0x44, 0x3b, 0x99, 0xcc, 0x6a, 0xaf, 0xe6, + 0x94, 0xc9, 0x01, 0x26, 0x6a, 0xd1, 0x21, 0xa0, 0x1f, 0xb6, + 0x57, 0x88, 0x52, 0x27, 0xab, 0xd9, 0x26, 0x7e, 0xe7, 0xf0, + 0x14, 0x7f, 0xe0, 0x0c, 0xea, 0x6a, 0x96, 0x46, 0x14, 0xb3, + 0x05, 0xc5, 0xea, 0x4a, 0x31, 0x1a, 0x93, 0x1a, 0x52, 0x66, + 0x74, 0x0f, 0x79, 0x4c, 0x71, 0xc1, 0x3f, 0xe8, 0x43, 0x07, + 0x27, 0x09, 0x8f, 0x34, 0xce, 0x1f, 0x2f, 0xaa, 0xef, 0x43, + 0xcd, 0x86, 0x62, 0x5d, 0x11, 0x44, 0x80, 0xb4, 0xa3, 0xbd, + 0x9c, 0x31, 0x66, 0x08, 0x9e, 0x67, 0xb7, 0x11, 0x08, 0x1f, + 0x73, 0x3e, 0x5c, 0x74, 0xc2, 0x12, 0x37, 0x13, 0x07, 0x40, + 0xc9, 0xb7, 0xc4, 0x52, 0x2d, 0x99, 0x43, 0x7a, 0x4d, 0xd7, + 0xb5, 0xaf, 0x0a, 0x47, 0x47, 0xda, 0xce, 0x86, 0x4c, 0x34, + 0x6c, 0xaa, 0x02, 0x33, 0xfb, 0x2d, 0xc9, 0x42, 0xb0, 0x53, + 0x0e, 0x0a, 0xea, 0xa5, 0x81, 0x69, 0xf4, 0x83, 0x2c, 0x17, + 0xc6, 0x71, 0xe8, 0xde, 0x6e, 0x63, 0x6a, 0x78, 0x55, 0x99, + 0x2f, 0xad, 0x2e, 0x5d, 0x85, 0x33, 0x9d, 0x39, 0xac, 0x35, + 0x9a, 0xe5, 0x43, 0x6e, 0x96, 0x33, 0x1a, 0xf2, 0x1e, 0x73, + 0x35, 0xa8, 0x31, 0x1d, 0x5c, 0x6e, 0x38, 0xf8, 0x97, 0x7d, + 0x01, 0x5a, 0x43, 0x41, 0xfd, 0xad, 0x83, 0xd7, 0x10, 0x5d, + 0xc7, 0x7c, 0x89, 0x9a, 0xe8, 0x99, 0xc6, 0xba, 0x9c, 0xe5, + 0xfc, 0x18, 0xe7, 0x08, 0xc2, 0xf0, 0x32, 0x60, 0x7c, 0x19, + 0x0b, 0xbc, 0x77, 0x06, 0xea, 0x78, 0xcc, 0x54, 0x66, 0x22, + 0xb1, 0x96, 0x28, 0x84, 0xb7, 0xae, 0x3a, 0xc9, 0x5d, 0x47, + 0x1f, 0x89, 0x72, 0x99, 0xeb, 0x96, 0xdb, 0x30, 0x44, 0xba, + 0xc2, 0xa6, 0xf2, 0xa5, 0x29, 0x49, 0x54, 0x57, 0x00, 0x36, + 0x93, 0x64, 0xa8, 0x2b, 0x24, 0x53, 0x29, 0x87, 0x57, 0xb0, + 0xe7, 0xcc, 0xd3, 0x1e, 0x1a, 0x88, 0xd2, 0xd6, 0xc2, 0x83, + 0x69, 0x3d, 0xaf, 0x3d, 0x8e, 0xd8, 0xd7, 0xc9, 0xb8, 0x8f, + 0x40, 0x16, 0x2c, 0x72, 0x36, 0x05, 0x4e, 0xa3, 0xa2, 0x84, + 0x3e, 0xe1, 0xa5, 0xcb, 0xa6, 0xb9, 0xaf, 0xe8, 0x6b, 0xb9, + 0x4e, 0x62, 0x06, 0x34, 0x67, 0x9f, 0x35, 0xf1, 0x95, 0x11, + 0x73, 0xa0, 0x19, 0x3c, 0x00, 0xff, 0x8d, 0x7b, 0xbf, 0x13, + 0xf7, 0x16, 0x9e, 0x29, 0x64, 0x05, 0xf8, 0xd3, 0x14, 0xf1, + 0x5d, 0xb2, 0x34, 0x09, 0x5b, 0x91, 0x1f, 0x9d, 0xc1, 0x70, + 0x21, 0xdd, 0xec, 0xb8, 0xa8, 0xe2, 0xe7, 0x8f, 0x1c, 0x3f, + 0x33, 0x55, 0x8a, 0xf9, 0xb9, 0x2e, 0x5a, 0x20, 0x23, 0x20, + 0xab, 0x76, 0x94, 0x9d, 0x7c, 0x9c, 0x59, 0x89, 0x52, 0x8d, + 0xf9, 0xa7, 0xfc, 0x2e, 0x86, 0x25, 0x14, 0x1a, 0x20, 0xec, + 0x94, 0x24, 0x2e, 0x40, 0x19, 0x06, 0x6b, 0xd8, 0xe1, 0xaa, + 0xc7, 0x7c, 0x33, 0x17, 0x86, 0x05, 0x27, 0x18, 0xaa, 0xaf, + 0x75, 0x35, 0x2f, 0xc6, 0x33, 0x55, 0x0c, 0xfd, 0xbc, 0xf0, + 0x02, 0x3b, 0xae, 0xad, 0x69, 0x98, 0x7a, 0x16, 0xb0, 0xc5, + 0x24, 0x4a, 0xc4, 0x0e, 0x04, 0x75, 0x75, 0xb5, 0xe9, 0x62, + 0x22, 0xec, 0x09, 0x3a, 0x3f, 0x62, 0xed, 0xca, 0xa5, 0x59, + 0xbb, 0x19, 0xa7, 0x4e, 0x5c, 0xdf, 0x5d, 0x6f, 0xd7, 0x2d, + 0xd7, 0x78, 0x6d, 0x3f, 0xd3, 0x5b, 0xcb, 0xb3, 0x24, 0x21, + 0x29, 0xb6, 0x4f, 0x76, 0x50, 0x39, 0xcb, 0x9f, 0x72, 0x2c, + 0x9f, 0x14, 0xff, 0xd3, 0xaa, 0x86, 0x79, 0x79, 0xc2, 0x6c, + 0xe2, 0x32, 0xbd, 0x91, 0x53, 0xd0, 0xa5, 0x35, 0x45, 0xe2, + 0x6c, 0x52, 0x3e, 0xb1, 0x67, 0xdc, 0xc4, 0x92, 0xd2, 0xd2, + 0xf3, 0x1a, 0x02, 0x7b, 0x89, 0x13, 0x68, 0x67, 0x01, 0x92, + 0xe8, 0xa7, 0xe2, 0x37, 0x09, 0x3f, 0xc2, 0x22, 0x36, 0x92, + 0x93, 0xb1, 0x1d, 0xe6, 0x22, 0x67, 0xd4, 0x11, 0x26, 0x82, + 0x46, 0xb4, 0x0a, 0x56, 0x9d, 0x7a, 0xe6, 0x0a, 0x36, 0xc8, + 0x63, 0x3e, 0xed, 0x26, 0xfe, 0xd1, 0x1e, 0x11, 0x95, 0x26, + 0x33, 0x7b, 0x2d, 0xaf, 0x07, 0x64, 0xbf, 0x44, 0xf1, 0x92, + 0xc0, 0x19, 0xad, 0xf1, 0x7d, 0x98, 0xc9, 0x32, 0xc0, 0x78, + 0x88, 0x9d, 0x32, 0x70, 0xdc, 0x59, 0x0d, 0x25, 0xa9, 0xc2, + 0x82, 0x37, 0x28, 0x95, 0x17, 0xdc, 0x3b, 0x14, 0xe0, 0x40, + 0x8f, 0xe3, 0x0b, 0xf4, 0x93, 0x39, 0x8f, 0xb3, 0x13, 0x60, + 0xaf, 0xd1, 0x9c, 0xa4, 0xe0, 0x15, 0x52, 0x4b, 0x8f, 0xfb, + 0x6c, 0x3e, 0x1b, 0x20, 0x46, 0x76, 0x89, 0xa8, 0x7c, 0xc0, + 0x99, 0x74, 0xc7, 0x35, 0x04, 0xa0, 0xf9, 0xac, 0x76, 0x83, + 0xb1, 0x6f, 0x22, 0x6e, 0xdc, 0x91, 0x32, 0x47, 0x41, 0x14, + 0x00, 0xc1, 0x92, 0x4a, 0x4e, 0xc0, 0x1f, 0x5b, 0xdb, 0x73, + 0xe3, 0x1d, 0x85, 0x9d, 0x4c, 0x7e, 0x4a, 0x55, 0x0e, 0x01, + 0xed, 0x00, 0xd4, 0xa7, 0x40, 0xcc, 0x63, 0xa1, 0xd6, 0xd4, + 0x8e, 0x59, 0x8c, 0x16, 0xd3, 0x0e, 0x57, 0x20, 0xce, 0xa1, + 0xb4, 0xd0, 0xea, 0x32, 0xde, 0x36, 0xf8, 0x4d, 0xba, 0xd4, + 0xd7, 0xe6, 0xf4, 0x64, 0x5f, 0x7c, 0x8e, 0x6e, 0x10, 0x6e, + 0xd2, 0x53, 0x34, 0x04, 0x89, 0x12, 0xe8, 0xe6, 0x8b, 0xdd, + 0x4f, 0x2c, 0x44, 0x1f, 0x3d, 0xa9, 0x4e, 0xf6, 0x7b, 0xd6, + 0xd4, 0xe5, 0xa7, 0x3c, 0xd5, 0x6e, 0x4b, 0x9f, 0x6c, 0xe4, + 0x42, 0x2f, 0xf9, 0xc0, 0xdd, 0x4a, 0xd4, 0x11, 0xae, 0x65, + 0xb9, 0x2d, 0x0d, 0x99, 0xce, 0x92, 0x4b, 0x9c, 0x51, 0x0f, + 0xaf, 0xa4, 0x74, 0x09, 0x7b, 0xdd, 0x52, 0x9f, 0xb4, 0x31, + 0xf9, 0xd1, 0xda, 0x45, 0xa1, 0x7f, 0x36, 0xfd, 0x71, 0x21, + 0x3b, 0x7d, 0xf4, 0x24, 0xf3, 0x94, 0xfe, 0xc6, 0xbc, 0x27, + 0x76, 0x09, 0x83, 0xb1, 0x50, 0x69, 0x28, 0xe7, 0x00, 0x54, + 0x98, 0x3f, 0x38, 0xe0, 0x0e, 0x52, 0x5e, 0x90, 0x2f, 0x69, + 0x3b, 0xc9, 0xcf, 0xba, 0x6b, 0x88, 0x82, 0x75, 0x72, 0x64, + 0x91, 0x92, 0xc3, 0xa2, 0x5e, 0x31, 0x2f, 0xc9, 0x28, 0x29, + 0xe6, 0x0c, 0xc5, 0x77, 0x90, 0x80, 0x86, 0x6e, 0x3b, 0x39, + 0xa2, 0xa4, 0xf1, 0xc6, 0xab, 0xa7, 0xdc, 0xce, 0x8f, 0x5c, + 0xf3, 0x21, 0x87, 0xed, 0xb2, 0xb0, 0x44, 0x4e, 0x50, 0x07, + 0xe8, 0x41, 0x92, 0xec, 0x19, 0xc6, 0xcc, 0x26, 0x94, 0x97, + 0x86, 0x75, 0xaa, 0x8f, 0x57, 0x97, 0x4b, 0xbb, 0x50, 0x1f, + 0xbc, 0xde, 0x79, 0x16, 0xa2, 0xb2, 0x69, 0x38, 0x2c, 0x99, + 0x86, 0xa8, 0xe5, 0x3c, 0x10, 0x32, 0x1d, 0xac, 0xff, 0x69, + 0x74, 0x29, 0xaf, 0x4c, 0xe7, 0x16, 0xa9, 0x2c, 0xf8, 0xb4, + 0xe3, 0x1b, 0x00, 0x06, 0xc5, 0x96, 0x9d, 0xbb, 0x23, 0x0e, + 0x4a, 0xfb, 0x7b, 0x4c, 0x60, 0x19, 0xfe, 0x01, 0xd4, 0x01, + 0x6f, 0x5d, 0x56, 0xcb, 0xba, 0x66, 0xbe, 0x48, 0x12, 0x89, + 0x96, 0x01, 0xe3, 0x07, 0x49, 0x7e, 0xc8, 0x64, 0x97, 0xcc, + 0x67, 0x2a, 0x04, 0xb1, 0xec, 0x0c, 0x1e, 0x33, 0x61, 0xa6, + 0x3f, 0x70, 0xfe, 0xfa, 0xe4, 0x39, 0xb9, 0x29, 0xb2, 0x1f, + 0x81, 0xec, 0x1c, 0x51, 0xd7, 0x97, 0xc2, 0x4a, 0xaf, 0x35, + 0x49, 0x75, 0x4e, 0x06, 0xf0, 0xe2, 0x8c, 0xdc, 0x33, 0xa3, + 0x48, 0xb0, 0x5c, 0x8b, 0xa9, 0xaf, 0xce, 0x18, 0x87, 0x03, + 0x5c, 0x47, 0xc9, 0x2a, 0x15, 0x75, 0x1d, 0xc5, 0x40, 0xdf, + 0x7a, 0xe8, 0x28, 0xb0, 0xbd, 0x08, 0xbc, 0x93, 0x49, 0x11, + 0x96, 0xd0, 0x53, 0x84, 0x54, 0x61, 0x55, 0x98, 0xa3, 0x75, + 0x83, 0xf3, 0x82, 0x48, 0x6e, 0x6c, 0xa7, 0xd4, 0xe7, 0x33, + 0x88, 0x7a, 0x18, 0x5a, 0x84, 0x08, 0x38, 0xe2, 0xc8, 0x8a, + 0x13, 0x7e, 0x91, 0xa3, 0x52, 0x6e, 0x47, 0x92, 0x84, 0xcd, + 0xdb, 0x5b, 0x26, 0xe7, 0x50, 0xd5, 0xb0, 0xce, 0xc4, 0x1e, + 0xf0, 0x55, 0xbf, 0xf3, 0xe8, 0xf2, 0x56, 0x3c, 0x32, 0xbe, + 0x48, 0xc0, 0x2e, 0x89, 0x70, 0xae, 0x2c, 0xd2, 0xd3, 0xdb, + 0x5e, 0x4e, 0xd1, 0xa4, 0x8b, 0x9f, 0x01, 0xd8, 0xa8, 0x1e, + 0x46, 0xa0, 0xaf, 0x9a, 0xb5, 0x4f, 0xe2, 0xc8, 0x50, 0xbd, + 0x0f, 0x49, 0xc5, 0x9f, 0x93, 0x23, 0x2a, 0x33, 0xd7, 0x15, + 0x42, 0x2a, 0x9c, 0x1d, 0xec, 0xe7, 0x98, 0x23, 0xa1, 0xf2, + 0xa3, 0xd9, 0xa2, 0x26, 0xfb, 0xac, 0xa9, 0x9a, 0x8b, 0xf6, + 0xa0, 0x6c, 0x1a, 0xac, 0x7f, 0x3e, 0x1e, 0x19, 0x57, 0xb9, + 0xec, 0x09, 0x1a, 0x1e, 0xa2, 0x1b, 0xdd, 0x57, 0xb9, 0xbd, + 0x0c, 0xc6, 0x33, 0x23, 0xe7, 0x9a, 0x84, 0x85, 0x86, 0xd3, + 0x06, 0x6d, 0x66, 0x1b, 0xdd, 0x4b, 0x9e, 0x1f, 0x07, 0xf4, + 0x41, 0x0e, 0x56, 0x52, 0x12, 0xc9, 0xff, 0x13, 0x9c, 0x20, + 0xf3, 0x60, 0x23, 0x3b, 0x04, 0xe6, 0x5d, 0x70, 0xf3, 0x13, + 0x8d, 0x60, 0x14, 0xe4, 0xfd, 0xec, 0x98, 0x5e, 0x53, 0x5b, + 0xdc, 0xde, 0xac, 0xc0, 0xd1, 0xae, 0x2d, 0x64, 0xec, 0x68, + 0x76, 0x6d, 0x75, 0x7a, 0x81, 0x62, 0xe0, 0x95, 0x84, 0xb4, + 0xc6, 0xea, 0xa3, 0xed, 0x7a, 0xd5, 0xd9, 0x6a, 0x48, 0xea, + 0x45, 0x06, 0xe9, 0xe6, 0xb0, 0x2a, 0xed, 0x62, 0x65, 0xd6, + 0x29, 0x52, 0x92, 0xcd, 0x78, 0x98, 0x61, 0x50, 0x75, 0x97, + 0xdc, 0x0b, 0x7b, 0x6d, 0x3e, 0x63, 0x93, 0x25, 0x67, 0x31, + 0x4f, 0xa3, 0x5a, 0xb8, 0x8c, 0x1c, 0xe9, 0x82, 0xd1, 0xe0, + 0x15, 0xa6, 0xb2, 0xf4, 0x8a, 0x45, 0xe0, 0x0f, 0x2a, 0xc2, + 0xfe, 0xd8, 0x22, 0x0b, 0x80, 0x60, 0x25, 0x96, 0x06, 0xc9, + 0x8b, 0x76, 0x91, 0xe5, 0x44, 0x71, 0x51, 0xbe, 0x29, 0x12, + 0xf5, 0xd4, 0x3f, 0x16, 0xea, 0xc2, 0xbc, 0x68, 0x19, 0x82, + 0xab, 0x0e, 0x3e, 0xe7, 0x43, 0x66, 0xd5, 0x25, 0x0a, 0xff, + 0xf1, 0x80, 0xb3, 0xc2, 0xe0, 0x9f, 0x4d, 0x52, 0x51, 0xa8, + 0x37, 0x19, 0xf4, 0x25, 0x13, 0x37, 0x3b, 0x04, 0x9e, 0xbd, + 0x6b, 0x80, 0x7e, 0x79, 0x31, 0xd3, 0x07, 0x0c, 0x1d, 0x9a, + 0xe6, 0x38, 0x80, 0xab, 0xe9, 0xb4, 0x8a, 0x78, 0xad, 0x31, + 0xe4, 0xb7, 0xe2, 0x51, 0xbd, 0x29, 0x8f, 0x9e, 0x30, 0x3c, + 0xaa, 0x37, 0xe7, 0x51, 0xc8, 0x58, 0x51, 0xb8, 0x14, 0xa2, + 0xdd, 0xba, 0xf0, 0xd4, 0x8f, 0x60, 0x55, 0xbd, 0x2d, 0xab, + 0xce, 0xf5, 0xd9, 0x64, 0x64, 0x0c, 0x16, 0xb3, 0x85, 0x91, + 0x67, 0xd9, 0x79, 0x18, 0xac, 0xdd, 0x68, 0xb9, 0x0d, 0xb6, + 0xd1, 0xab, 0xb3, 0xeb, 0x77, 0xe7, 0x33, 0xf3, 0x39, 0xaf, + 0xea, 0x55, 0x33, 0xda, 0x47, 0x4e, 0x18, 0x56, 0xa9, 0x78, + 0xaf, 0x2d, 0x0d, 0x8b, 0x0c, 0x64, 0x54, 0x6c, 0xb5, 0xd7, + 0xe8, 0x86, 0x79, 0x10, 0x4f, 0xee, 0xbd, 0x8c, 0x60, 0x17, + 0xc7, 0x4d, 0x84, 0x8e, 0x3a, 0xca, 0x27, 0xd7, 0xe2, 0x68, + 0x5e, 0xe0, 0xf4, 0x2d, 0xf2, 0x91, 0x3e, 0xea, 0x74, 0xa0, + 0xe5, 0xf3, 0x6e, 0xf1, 0xdd, 0x44, 0x41, 0xf1, 0x4d, 0x88, + 0x9e, 0x2f, 0x8c, 0x1b, 0x11, 0xfc, 0x11, 0x05, 0x79, 0x22, + 0x5f, 0xeb, 0xdb, 0x6d, 0xd4, 0x04, 0x1f, 0xf8, 0x1a, 0xf9, + 0xaa, 0x8b, 0xd1, 0x3e, 0x23, 0x1f, 0x16, 0x73, 0x1d, 0xe4, + 0xa6, 0x1e, 0x36, 0x81, 0x33, 0x1d, 0xcd, 0x05, 0x67, 0x11, + 0x16, 0x07, 0x5e, 0x96, 0xc8, 0x62, 0x6a, 0x2c, 0xe6, 0xc8, + 0x23, 0x2b, 0xe7, 0xf4, 0xbe, 0xf0, 0xa3, 0xed, 0x26, 0x09, + 0x80, 0x0f, 0x32, 0x17, 0xb8, 0x26, 0x63, 0x35, 0x46, 0xdf, + 0x34, 0xc1, 0xf5, 0x3d, 0x1d, 0x6b, 0xcc, 0xae, 0x08, 0x7e, + 0x75, 0x94, 0x8e, 0x73, 0xca, 0x92, 0x5f, 0x9f, 0x89, 0x09, + 0xca, 0xef, 0x6d, 0x14, 0x48, 0x4d, 0xa2, 0xa8, 0x1b, 0x1d, + 0xa1, 0xa3, 0x6b, 0x4d, 0xcf, 0x79, 0xbb, 0xe7, 0xa8, 0xda, + 0xf4, 0x8c, 0x76, 0x94, 0xdb, 0x1d, 0xf6, 0x76, 0x67, 0x33, + 0xba, 0xb7, 0x90, 0x5d, 0xaf, 0xae, 0xd3, 0xe9, 0xcf, 0x3a, + 0x8a, 0x2f, 0x90, 0x17, 0x63, 0xa7, 0xdc, 0x79, 0x99, 0x54, + 0xfe, 0x41, 0x3a, 0x1d, 0x1f, 0xb9, 0xde, 0xf7, 0x6b, 0x81, + 0xc4, 0x33, 0x93, 0xcc, 0x39, 0xd1, 0x70, 0x7e, 0xcf, 0xb8, + 0x63, 0xe2, 0xc7, 0xce, 0xef, 0x6b, 0x28, 0x22, 0x82, 0xad, + 0x51, 0xb0, 0x31, 0xf2, 0x73, 0xde, 0xe6, 0xb5, 0x0a, 0xea, + 0xa3, 0xeb, 0x41, 0x1c, 0x7a, 0xf8, 0x3a, 0x5b, 0xfd, 0xcc, + 0x7b, 0xb8, 0xcf, 0x28, 0xb1, 0x24, 0xd5, 0x4d, 0x06, 0x5b, + 0xdf, 0xea, 0x36, 0x4c, 0x20, 0x4f, 0x78, 0x00, 0x94, 0xbe, + 0xd0, 0x27, 0x5f, 0x1f, 0x79, 0xb2, 0x3d, 0xec, 0xe4, 0x38, + 0xf0, 0x2f, 0x6d, 0x37, 0x17, 0xb9, 0xe7, 0xa2, 0x70, 0x1b, + 0xf2, 0x07, 0x6e, 0x75, 0x65, 0xd8, 0x64, 0x6c, 0xc7, 0x1c, + 0x49, 0x38, 0x3b, 0x61, 0x7b, 0x6a, 0xe7, 0x81, 0xef, 0x98, + 0x70, 0xe1, 0x1e, 0xa8, 0x87, 0xe8, 0xd6, 0x77, 0x50, 0x06, + 0x85, 0x31, 0xd4, 0x2a, 0x43, 0x05, 0xff, 0xcd, 0x17, 0x12, + 0xf6, 0xc8, 0xf7, 0x15, 0xd8, 0x0e, 0xd7, 0x59, 0x02, 0x3e, + 0xda, 0xb2, 0xaf, 0x43, 0xe4, 0x0b, 0x74, 0xe7, 0xb1, 0x04, + 0x93, 0x4f, 0x2e, 0x81, 0x38, 0x95, 0xa3, 0x2b, 0xb1, 0x4d, + 0x30, 0xc7, 0x6b, 0x8f, 0xb6, 0x57, 0xb3, 0x4d, 0x0e, 0xf2, + 0xdb, 0x04, 0xd5, 0xda, 0x92, 0x7f, 0x0e, 0xa9, 0x0e, 0x9d, + 0x3f, 0xbc, 0xac, 0x35, 0xa0, 0x69, 0x9e, 0x27, 0xc8, 0x27, + 0x77, 0x13, 0x24, 0xe9, 0x92, 0x93, 0xa3, 0xad, 0xf1, 0xfc, + 0x20, 0x1c, 0x23, 0x6b, 0xed, 0xfa, 0x96, 0x7d, 0x4b, 0x23, + 0x6a, 0x6e, 0xa3, 0xc0, 0x43, 0x7e, 0xc5, 0x6b, 0xe2, 0xcc, + 0xaa, 0xa4, 0x60, 0x47, 0x5d, 0xe8, 0xe7, 0xba, 0xde, 0x9c, + 0xb8, 0xec, 0x22, 0x24, 0x52, 0x67, 0x9e, 0x3c, 0x9b, 0x55, + 0xae, 0xc6, 0xe1, 0x9b, 0xd0, 0xea, 0x45, 0x68, 0x79, 0x81, + 0x6f, 0xad, 0x7a, 0x96, 0x5a, 0x9e, 0x1d, 0xf3, 0x34, 0xbb, + 0x89, 0xad, 0x5b, 0x28, 0xb6, 0xac, 0xb8, 0x89, 0xdc, 0x6a, + 0xd2, 0x57, 0x28, 0xa5, 0xf8, 0xce, 0x76, 0x12, 0x5b, 0x0e, + 0x91, 0x51, 0x1c, 0xc5, 0x36, 0x72, 0xab, 0x10, 0x1b, 0xdf, + 0xb3, 0xa2, 0x27, 0x04, 0x00, 0xc5, 0x51, 0x47, 0x30, 0xf9, + 0x5e, 0x72, 0xed, 0x50, 0x0c, 0xfc, 0xf7, 0xb6, 0x6d, 0x44, + 0xf6, 0x1d, 0xb0, 0x1c, 0x97, 0x6a, 0x3b, 0x06, 0xfc, 0x10, + 0xef, 0x94, 0x61, 0x07, 0x31, 0x92, 0x8d, 0xdd, 0x0a, 0x30, + 0xf2, 0x6e, 0xf1, 0xa4, 0xcc, 0x92, 0xbf, 0xb5, 0x9d, 0x16, + 0xd4, 0xf1, 0xb5, 0x1d, 0xae, 0xca, 0xa6, 0x85, 0x8c, 0x63, + 0x92, 0x94, 0x68, 0xd9, 0x8a, 0xe7, 0xae, 0x2d, 0xd1, 0xcd, + 0x5f, 0xe1, 0xf6, 0x0b, 0xdb, 0x68, 0xbf, 0x67, 0xd3, 0x36, + 0x17, 0xca, 0x55, 0x20, 0x13, 0x8f, 0x5a, 0x9e, 0x50, 0xe5, + 0x8f, 0x02, 0x17, 0xdf, 0x3d, 0x8f, 0x1c, 0x8b, 0xfd, 0x7d, + 0xd0, 0x42, 0x9e, 0xbd, 0x56, 0x3c, 0x5a, 0x69, 0xd2, 0xb6, + 0xae, 0xf9, 0xda, 0xda, 0x24, 0x5e, 0x3a, 0x6c, 0x97, 0x78, + 0xa9, 0x75, 0xa2, 0xa4, 0xea, 0x14, 0x31, 0xc7, 0xcd, 0x53, + 0xc4, 0xc8, 0x29, 0x49, 0xf3, 0x54, 0x49, 0xd2, 0x5e, 0x43, + 0x49, 0x4a, 0x22, 0x7e, 0x3a, 0x49, 0xb7, 0x52, 0x25, 0xa9, + 0x07, 0xe2, 0x08, 0x46, 0xd0, 0x42, 0x3c, 0x99, 0xa7, 0x8e, + 0x50, 0x05, 0x15, 0x9d, 0x89, 0xb1, 0x69, 0x40, 0x96, 0xc5, + 0xeb, 0x63, 0xa4, 0x03, 0x9f, 0x09, 0x54, 0x9a, 0x9a, 0xa0, + 0xb2, 0xf1, 0x9e, 0x4e, 0x65, 0x8a, 0x9d, 0x8c, 0xe2, 0xd6, + 0x35, 0x64, 0xd0, 0x08, 0xdc, 0x2f, 0xf6, 0x6e, 0x23, 0x82, + 0xbb, 0x14, 0x63, 0xfe, 0x9e, 0x51, 0x07, 0x7b, 0x63, 0x36, + 0x52, 0xb2, 0x8a, 0xa8, 0x9d, 0x5f, 0x9a, 0xe0, 0xbb, 0xb0, + 0xd7, 0xf6, 0x7f, 0xfd, 0x6f, 0x22, 0xb0, 0x7e, 0x69, 0x84, + 0xee, 0x22, 0x45, 0x82, 0x49, 0x75, 0x85, 0x16, 0x0e, 0x9e, + 0x9f, 0x8a, 0x1a, 0x86, 0x2e, 0xbe, 0xc4, 0x14, 0x3a, 0x35, + 0xfc, 0x52, 0x82, 0xb3, 0x2a, 0xc2, 0xac, 0x96, 0x25, 0x2e, + 0x8c, 0x24, 0xfd, 0x3f, 0x02, 0x57, 0x0c, 0xab, 0x2a, 0x9b, + 0xf1, 0x03, 0x76, 0xc6, 0x33, 0x48, 0xdd, 0x5f, 0x5a, 0x81, + 0x29, 0xd3, 0xde, 0x16, 0x0e, 0xf6, 0x29, 0x59, 0xcf, 0x1c, + 0x83, 0x72, 0x4c, 0x92, 0x40, 0x28, 0xd2, 0xb2, 0xad, 0xbd, + 0xf0, 0x02, 0xb7, 0x00, 0x85, 0xa0, 0x6c, 0x1e, 0x0e, 0xd9, + 0x79, 0x48, 0xeb, 0x15, 0x8d, 0xa2, 0xfc, 0x94, 0x86, 0x35, + 0xe5, 0x5f, 0xee, 0x7f, 0xa9, 0x3e, 0xa9, 0x0f, 0x8a, 0x4f, + 0xea, 0x5f, 0x1a, 0xe6, 0x94, 0x29, 0xab, 0xc5, 0xbc, 0xf0, + 0x1f, 0xf1, 0xb9, 0x6c, 0xd2, 0xa5, 0xa3, 0x3b, 0xfc, 0x97, + 0x86, 0x20, 0x0b, 0x70, 0x1a, 0xa4, 0xb3, 0x13, 0xfd, 0x52, + 0x78, 0x38, 0x16, 0x67, 0x14, 0x62, 0x61, 0xa9, 0x7f, 0xa9, + 0x38, 0xd6, 0x0f, 0xb9, 0x34, 0xac, 0xc9, 0xa1, 0x1a, 0x54, + 0xd4, 0xd4, 0x4c, 0x6b, 0xae, 0xea, 0xea, 0x44, 0xcc, 0x58, + 0x6b, 0xa0, 0xec, 0xa9, 0x8c, 0x2c, 0x2c, 0xa9, 0x7f, 0x29, + 0xd4, 0x3f, 0xe6, 0xb2, 0xaf, 0x4a, 0xd6, 0xcf, 0xc7, 0x97, + 0x67, 0xb9, 0x5b, 0xcb, 0xea, 0xe9, 0x9a, 0xb1, 0x98, 0x68, + 0xc2, 0x33, 0x88, 0x0e, 0x22, 0x38, 0xc1, 0xf9, 0x51, 0x57, + 0xac, 0x67, 0x94, 0x05, 0x8e, 0x65, 0xc3, 0x4e, 0x7e, 0x4b, + 0xc2, 0x81, 0x14, 0x09, 0x8b, 0x82, 0x2d, 0x4e, 0x06, 0x43, + 0x05, 0x48, 0x31, 0xec, 0xcd, 0x2f, 0x15, 0xe9, 0x46, 0xb5, + 0xe7, 0x38, 0xb4, 0xb9, 0x5c, 0xe0, 0x2d, 0x5d, 0x98, 0x03, + 0x57, 0x22, 0xe5, 0x10, 0x91, 0x0b, 0x47, 0xac, 0x5c, 0x20, + 0xb5, 0x1a, 0x67, 0x0b, 0x85, 0x55, 0x91, 0x7b, 0x9a, 0xbc, + 0x4f, 0x8f, 0xec, 0x9e, 0xc0, 0x97, 0x8e, 0xbd, 0xe2, 0x4a, + 0xa3, 0xe1, 0x58, 0xcc, 0x1d, 0x38, 0x72, 0x58, 0xdf, 0x9f, + 0xdc, 0x13, 0x98, 0x3a, 0x30, 0x47, 0xd7, 0x22, 0x46, 0xe0, + 0xc8, 0xb7, 0x31, 0x16, 0x8f, 0x1c, 0x1e, 0x7c, 0x9b, 0x63, + 0x22, 0x47, 0xe5, 0x69, 0xc3, 0x66, 0x1d, 0x4e, 0x4f, 0x82, + 0x12, 0x42, 0x15, 0xf1, 0x81, 0x29, 0x63, 0x5b, 0xcb, 0xfb, + 0x07, 0x91, 0xb9, 0x95, 0xc1, 0x3d, 0x58, 0x3e, 0x44, 0x34, + 0x40, 0x5c, 0xe8, 0x54, 0x1d, 0x60, 0x1d, 0xf9, 0x3d, 0x47, + 0x17, 0x8f, 0x2a, 0xa7, 0xd1, 0xd3, 0x53, 0xf1, 0x7d, 0xee, + 0x22, 0xb4, 0x57, 0x8c, 0xcf, 0x8c, 0xd0, 0xe5, 0x2d, 0x1d, + 0x37, 0xf7, 0x0a, 0xbc, 0xf0, 0x5d, 0x78, 0x0c, 0xc8, 0x87, + 0xa5, 0xde, 0xc1, 0x56, 0x2c, 0x3f, 0x49, 0x2d, 0x98, 0x05, + 0x78, 0xe2, 0x86, 0x95, 0x34, 0xe3, 0xa0, 0x14, 0x21, 0x48, + 0xc3, 0x42, 0xc4, 0x22, 0x1a, 0x3f, 0x1c, 0x23, 0xf8, 0x27, + 0x4c, 0x03, 0xc1, 0x65, 0xde, 0x25, 0x64, 0xa3, 0x16, 0x01, + 0xb3, 0x59, 0x97, 0x5a, 0x47, 0xce, 0x4e, 0xc1, 0x26, 0xde, + 0x46, 0xe7, 0x5e, 0x70, 0x5b, 0x18, 0xb1, 0x79, 0x76, 0x96, + 0x3d, 0x60, 0x91, 0x92, 0x0a, 0x2e, 0x5a, 0x12, 0x1b, 0x05, + 0x25, 0x88, 0x1f, 0x73, 0x10, 0x11, 0x03, 0xf2, 0x8d, 0x4d, + 0x87, 0x5a, 0x1b, 0x6d, 0x90, 0xd0, 0x11, 0x48, 0xb4, 0x1a, + 0x9d, 0x7a, 0x8b, 0xdf, 0xb3, 0x25, 0xc4, 0xd4, 0xd9, 0x27, + 0x7a, 0xaf, 0x22, 0x75, 0xd2, 0xcd, 0x5a, 0xfd, 0x24, 0x18, + 0xdd, 0x7a, 0xaa, 0xbf, 0xf2, 0x80, 0xbc, 0xe7, 0x08, 0xcd, + 0x58, 0xb4, 0x30, 0xce, 0xc7, 0x4a, 0x52, 0xbb, 0xf8, 0x8a, + 0x93, 0x04, 0x37, 0x72, 0xc1, 0x8b, 0x6d, 0x1e, 0xff, 0x6e, + 0x81, 0x1d, 0x32, 0x58, 0xc3, 0xe7, 0xe9, 0xcf, 0x2e, 0xf1, + 0x6a, 0xc0, 0x03, 0x8f, 0x9c, 0xea, 0xad, 0xd1, 0x0f, 0xad, + 0x43, 0x3c, 0x0b, 0x27, 0x38, 0xbd, 0x3e, 0xcb, 0x4f, 0xf1, + 0x01, 0x37, 0xc5, 0x59, 0xfd, 0xd7, 0x9d, 0xe4, 0xcc, 0xa4, + 0xf6, 0xb5, 0x97, 0x84, 0x61, 0x37, 0xbd, 0xa4, 0x09, 0xfb, + 0xd6, 0xe3, 0xf3, 0x37, 0x5c, 0x8a, 0x0b, 0xf7, 0x59, 0x7e, + 0x15, 0x0e, 0xb9, 0x55, 0x40, 0x55, 0x5f, 0x77, 0x01, 0xde, + 0xd2, 0xe5, 0xfd, 0x64, 0xd1, 0xb2, 0x1d, 0xa3, 0x7e, 0xeb, + 0x1c, 0xe4, 0xb3, 0x9b, 0xc1, 0xd7, 0x35, 0xf7, 0xe6, 0x99, + 0xa2, 0x34, 0xe6, 0xa5, 0x3c, 0x9d, 0x62, 0x5a, 0x99, 0x60, + 0x95, 0x49, 0x84, 0x61, 0x60, 0x20, 0x47, 0x1e, 0xc5, 0xb1, + 0x65, 0x0c, 0x27, 0x7a, 0x31, 0x70, 0x99, 0x40, 0x62, 0xf4, + 0x2b, 0xb1, 0x5b, 0x28, 0xfd, 0xb8, 0x34, 0xc2, 0xbb, 0x4f, + 0x9b, 0xe9, 0x29, 0xb9, 0x79, 0x55, 0x4c, 0x51, 0x6d, 0xa8, + 0x23, 0x06, 0xda, 0x18, 0x04, 0x41, 0xe8, 0x94, 0xc2, 0x72, + 0x9c, 0x7d, 0x3a, 0x61, 0x6f, 0x8c, 0x04, 0x9a, 0x03, 0x57, + 0x41, 0x1e, 0x2a, 0x65, 0x87, 0xe3, 0xd2, 0x5e, 0x8f, 0xe8, + 0x1d, 0xda, 0x46, 0x1c, 0x5a, 0xa1, 0xe1, 0xb6, 0x13, 0xe0, + 0xa2, 0xf5, 0x68, 0xf3, 0xdc, 0x52, 0x86, 0xcb, 0x11, 0xaa, + 0x5f, 0x54, 0xa9, 0xd9, 0xfc, 0xc8, 0xae, 0xe2, 0xdb, 0x6c, + 0x96, 0xcf, 0xe6, 0x97, 0x20, 0xf4, 0x1c, 0x76, 0x6a, 0x4a, + 0xa7, 0xf4, 0x94, 0x9d, 0x52, 0x5c, 0xad, 0x7e, 0x4a, 0x63, + 0x94, 0x8f, 0x04, 0xab, 0x59, 0x54, 0xec, 0xfe, 0xff, 0xed, + 0x5d, 0xdb, 0x6e, 0xe2, 0x30, 0x10, 0xfd, 0x95, 0xfc, 0xc0, + 0xaa, 0xa4, 0x4b, 0x5b, 0x78, 0x59, 0x29, 0x0d, 0x97, 0x45, + 0xe2, 0x26, 0x28, 0x6a, 0xfb, 0x84, 0xb2, 0x21, 0x85, 0x68, + 0x13, 0x82, 0x92, 0xb0, 0xa5, 0x7f, 0xbf, 0xbe, 0x24, 0xb6, + 0xb1, 0x1d, 0x70, 0x12, 0xb7, 0x55, 0x2b, 0xa4, 0x3e, 0xd0, + 0x84, 0x99, 0x31, 0xca, 0xb1, 0x33, 0xb6, 0xc7, 0xe7, 0x10, + 0x89, 0x73, 0x46, 0xb2, 0x84, 0xc9, 0xc4, 0x14, 0x76, 0x73, + 0x74, 0x89, 0x63, 0x28, 0xbf, 0xc3, 0x94, 0xe9, 0xbb, 0x2f, + 0x39, 0x12, 0x3b, 0x1f, 0xe8, 0x1e, 0x52, 0x48, 0x9d, 0xbc, + 0x52, 0x4f, 0x97, 0x5a, 0x92, 0x79, 0x81, 0x41, 0xdc, 0x94, + 0x4e, 0x9d, 0x4a, 0xb2, 0x96, 0x70, 0x53, 0x04, 0x4c, 0x52, + 0xac, 0x65, 0xa2, 0x10, 0x08, 0x33, 0x05, 0xec, 0xbc, 0xda, + 0x7c, 0xe1, 0x2b, 0xcd, 0x6d, 0x34, 0xab, 0xed, 0x06, 0x01, + 0x46, 0xc5, 0xe7, 0x69, 0xec, 0x22, 0xd9, 0x2e, 0x1d, 0x8d, + 0xa8, 0x23, 0xad, 0xfb, 0xec, 0xbc, 0xea, 0x68, 0x82, 0xe3, + 0xba, 0x20, 0xe7, 0x72, 0xdf, 0xce, 0xb4, 0xa3, 0xc1, 0x14, + 0x62, 0x64, 0xdf, 0x7f, 0x9f, 0xd9, 0x6d, 0xf9, 0x01, 0xa3, + 0x2d, 0x9d, 0xe5, 0x7e, 0xd8, 0x90, 0xf1, 0xe5, 0xc7, 0x72, + 0x71, 0xad, 0x8e, 0xac, 0x75, 0xd5, 0xf1, 0x42, 0x77, 0xa5, + 0xeb, 0x78, 0x21, 0xc9, 0x58, 0xe7, 0xf3, 0xe4, 0xbd, 0x2f, + 0x03, 0xce, 0x3b, 0x0d, 0x38, 0x25, 0x06, 0x96, 0x1a, 0x2b, + 0x35, 0x65, 0x47, 0x94, 0x76, 0xa3, 0xc1, 0xaf, 0xd8, 0x7c, + 0x5c, 0xfe, 0x71, 0x59, 0xbb, 0xf9, 0x56, 0x6b, 0x37, 0x9f, + 0x8c, 0xfe, 0x4c, 0x95, 0x51, 0x15, 0xf7, 0xc7, 0xeb, 0xc5, + 0xf8, 0xb4, 0xdf, 0xd1, 0xb2, 0x4c, 0x45, 0x0e, 0x05, 0xec, + 0xa9, 0x86, 0xd4, 0xc7, 0x85, 0x4b, 0xf0, 0xdb, 0x70, 0x09, + 0x2a, 0xa0, 0xd6, 0xce, 0xd6, 0x05, 0x55, 0x61, 0x7b, 0xbc, + 0xc0, 0x5e, 0x15, 0xb0, 0xef, 0x56, 0x69, 0xda, 0x7d, 0x58, + 0xda, 0xbd, 0x3e, 0x5f, 0x6b, 0xea, 0xa5, 0xc6, 0x50, 0x68, + 0xad, 0x6a, 0xbd, 0x66, 0x9f, 0xf5, 0xc9, 0x94, 0xf8, 0xa4, + 0xb1, 0xef, 0x41, 0xb9, 0x9b, 0xca, 0x8e, 0xed, 0xc5, 0x8c, + 0x3a, 0x66, 0xcf, 0x1f, 0x04, 0x6f, 0x90, 0x35, 0xc9, 0x31, + 0x40, 0x64, 0x83, 0x14, 0xee, 0x28, 0xec, 0xe4, 0x87, 0xb0, + 0xeb, 0x0b, 0x85, 0x5a, 0xcc, 0xd8, 0xc4, 0x8c, 0x10, 0xba, + 0xd8, 0xf9, 0x3a, 0x7e, 0x92, 0x44, 0xc1, 0x3f, 0x6f, 0x35, + 0x89, 0xd7, 0x0e, 0x00, 0xcb, 0xc8, 0x49, 0x39, 0x86, 0x47, + 0x2c, 0xff, 0x9a, 0x14, 0x70, 0x17, 0xb5, 0x29, 0x65, 0x1f, + 0x71, 0x65, 0x64, 0xbe, 0x8c, 0xdc, 0x99, 0x12, 0x57, 0xaf, + 0xea, 0x31, 0xcc, 0xe9, 0xf4, 0x5e, 0x2d, 0x87, 0xe4, 0x6a, + 0xc6, 0xe0, 0xc6, 0x79, 0xe8, 0x39, 0xc9, 0x3e, 0xc6, 0xfc, + 0x19, 0x04, 0xaf, 0x9d, 0xea, 0x3a, 0x6b, 0xf6, 0x64, 0x38, + 0x21, 0xc7, 0x82, 0x1b, 0x74, 0x75, 0x3e, 0x88, 0xe2, 0x53, + 0xcc, 0x45, 0xbd, 0xe1, 0x02, 0x98, 0xcd, 0x6d, 0x72, 0x4e, + 0x99, 0x9e, 0xaf, 0x0a, 0xf6, 0xc0, 0x34, 0x71, 0x51, 0x03, + 0x4b, 0x73, 0x18, 0x4d, 0x76, 0x29, 0x54, 0xaf, 0xbf, 0x77, + 0xdc, 0xbf, 0x89, 0x5b, 0xfa, 0x41, 0x36, 0x69, 0x9f, 0x46, + 0x6e, 0x0c, 0xc6, 0x0f, 0xd4, 0x26, 0xb0, 0x23, 0xef, 0xe5, + 0xc5, 0x77, 0x7d, 0x19, 0x11, 0x7a, 0xbd, 0x47, 0x6a, 0x5e, + 0x55, 0x79, 0x69, 0x3f, 0x38, 0xee, 0x26, 0x5a, 0xc7, 0xce, + 0x6e, 0x73, 0x76, 0xab, 0xa2, 0xe0, 0x17, 0x53, 0x09, 0x18, + 0xc6, 0x95, 0xd2, 0x2f, 0x83, 0x95, 0xc4, 0x49, 0xea, 0x84, + 0xbb, 0x65, 0xe0, 0x24, 0xe9, 0x12, 0x2a, 0x53, 0xf9, 0x54, + 0x49, 0x6b, 0x08, 0xae, 0x19, 0x73, 0x7c, 0x0d, 0x55, 0x17, + 0xa3, 0xaf, 0xd6, 0x11, 0xe9, 0x86, 0xf1, 0x96, 0x5b, 0x90, + 0x03, 0xf0, 0xa1, 0x50, 0x09, 0xec, 0x0f, 0x63, 0x0c, 0x6e, + 0xe5, 0x11, 0x4b, 0x9c, 0xa4, 0x95, 0xc7, 0x09, 0xa3, 0x34, + 0x8a, 0x8b, 0xa3, 0x8d, 0xe0, 0x6d, 0xdd, 0x31, 0xfd, 0x55, + 0xe0, 0x2d, 0xd7, 0x19, 0x73, 0x2d, 0x13, 0x0c, 0x96, 0x4f, + 0x81, 0x58, 0xa7, 0x38, 0x6d, 0xcb, 0x46, 0x71, 0xfc, 0x58, + 0x16, 0xc2, 0xf2, 0x63, 0x3d, 0xfe, 0x5f, 0x1d, 0x86, 0xda, + 0x92, 0x8d, 0xf0, 0x88, 0x6f, 0xe8, 0x88, 0xb1, 0x87, 0x12, + 0x7b, 0x85, 0x81, 0x16, 0xcc, 0x5d, 0x3d, 0xd1, 0x90, 0xf2, + 0xb8, 0x3c, 0x54, 0x76, 0x4b, 0x0b, 0xe6, 0x24, 0x00, 0xc8, + 0xd1, 0xa6, 0x09, 0x01, 0x38, 0x0e, 0x0f, 0x81, 0x3c, 0x88, + 0x0e, 0x0c, 0xe0, 0x08, 0xe2, 0xb3, 0xc9, 0x63, 0xe8, 0x41, + 0x01, 0x8e, 0x52, 0x00, 0x83, 0x3c, 0x94, 0x46, 0x1c, 0xe4, + 0xf1, 0x44, 0x20, 0xd0, 0x60, 0xb5, 0x91, 0x10, 0xef, 0xc2, + 0x25, 0xa3, 0x4b, 0x33, 0xf3, 0xdc, 0x28, 0x5e, 0x81, 0x7c, + 0x62, 0x36, 0x1d, 0x25, 0x20, 0x02, 0xa7, 0x53, 0xc3, 0xed, + 0xe8, 0x01, 0x63, 0xf5, 0x20, 0x54, 0xb3, 0x46, 0x08, 0x72, + 0xac, 0x61, 0x53, 0x31, 0x08, 0xe2, 0xd8, 0x97, 0x86, 0x41, + 0x84, 0xfb, 0x62, 0x9c, 0xfa, 0x73, 0x58, 0x6b, 0x17, 0x8a, + 0x84, 0x44, 0x85, 0x1b, 0xf7, 0x6d, 0xca, 0x21, 0x6b, 0x4d, + 0x47, 0x02, 0xdf, 0xe4, 0x19, 0x8a, 0x09, 0x78, 0xf6, 0x8e, + 0x32, 0x23, 0xcf, 0xc9, 0xff, 0x79, 0x4a, 0x05, 0x5c, 0x56, + 0x67, 0x85, 0x1c, 0x75, 0x67, 0xfd, 0xee, 0xd8, 0x7e, 0xe6, + 0xb2, 0xaa, 0x2e, 0xb0, 0x5b, 0x83, 0x89, 0xdb, 0x5b, 0x71, + 0x5e, 0x65, 0x0d, 0xbb, 0xc2, 0xf9, 0x39, 0x2b, 0xf0, 0xe2, + 0x13, 0x67, 0xee, 0xec, 0xd9, 0xe0, 0x61, 0x60, 0x0b, 0x6a, + 0x69, 0x36, 0xf8, 0x3d, 0x30, 0x07, 0x3a, 0xa1, 0xc4, 0x74, + 0xa6, 0x9a, 0x5f, 0x62, 0xf2, 0x68, 0xcd, 0xc6, 0xa2, 0xf2, + 0xd3, 0xa3, 0x13, 0x6f, 0x8f, 0x6a, 0x8a, 0x79, 0xb3, 0xf1, + 0x04, 0xb4, 0xb0, 0xcb, 0x55, 0xaa, 0x8f, 0xa3, 0x14, 0xbd, + 0x76, 0x8b, 0x49, 0x05, 0x7b, 0x13, 0xae, 0x4c, 0x7d, 0x80, + 0xaa, 0xba, 0xaf, 0x0a, 0x39, 0x6e, 0xee, 0x17, 0x7d, 0x8e, + 0x8a, 0xa7, 0xe3, 0xfd, 0xd9, 0xaf, 0x95, 0xa6, 0x2e, 0xb8, + 0x38, 0x33, 0x1b, 0x15, 0xd0, 0x67, 0x0d, 0x4c, 0xb1, 0xce, + 0xca, 0x9d, 0x61, 0x05, 0x88, 0x44, 0x9a, 0xc7, 0x62, 0x1c, + 0x93, 0xd6, 0xce, 0xad, 0x8e, 0x6d, 0x50, 0x03, 0x25, 0x28, + 0x43, 0x6d, 0xdd, 0x2d, 0x94, 0x6d, 0x40, 0xcb, 0x14, 0xcd, + 0x6c, 0x59, 0x82, 0x80, 0xc7, 0xce, 0x6f, 0x93, 0xc1, 0xa0, + 0xb5, 0xac, 0x4b, 0x2a, 0x53, 0x86, 0x57, 0x82, 0x3d, 0xec, + 0x8c, 0x0f, 0x36, 0xe7, 0x3d, 0xac, 0x6f, 0x0d, 0xc6, 0x95, + 0xbb, 0xd8, 0x93, 0xc9, 0xf5, 0xad, 0x83, 0x59, 0x0c, 0x8c, + 0x27, 0xc8, 0x4e, 0x7b, 0xd4, 0xa5, 0x0e, 0xf0, 0xca, 0x89, + 0xaf, 0x37, 0xb8, 0xce, 0x74, 0x40, 0x97, 0x4a, 0xcf, 0x66, + 0x3a, 0x61, 0xd2, 0xf1, 0x52, 0xcf, 0xe5, 0xeb, 0x38, 0xb9, + 0xe7, 0x4f, 0xf6, 0xc0, 0x3b, 0xa3, 0xb9, 0xc1, 0x18, 0x28, + 0x3e, 0xff, 0x06, 0xff, 0xb0, 0x0d, 0x93, 0x1f, 0x93, 0xaf, + 0x8a, 0x4c, 0xaf, 0x79, 0xd3, 0x6b, 0x65, 0xd3, 0x9f, 0xbc, + 0xe9, 0x4f, 0x65, 0xd3, 0x26, 0x6f, 0xda, 0x54, 0x36, 0xbd, + 0xe1, 0x4d, 0x6f, 0x94, 0x4d, 0x6f, 0x79, 0xd3, 0x5b, 0x65, + 0xd3, 0x3b, 0xde, 0xf4, 0x4e, 0xd9, 0xb4, 0xc5, 0x9b, 0xb6, + 0x94, 0x4d, 0xdb, 0xbc, 0x69, 0x5b, 0xd5, 0x94, 0xd2, 0x31, + 0x13, 0x48, 0x34, 0x94, 0x6d, 0x45, 0x38, 0x29, 0xe3, 0xc9, + 0x14, 0xf0, 0x64, 0x2a, 0x03, 0xca, 0x14, 0x00, 0x65, 0x2a, + 0x23, 0xca, 0x14, 0x10, 0x65, 0x2a, 0x43, 0xca, 0x14, 0x20, + 0x65, 0x2a, 0x63, 0xca, 0x14, 0x30, 0x65, 0xca, 0x41, 0xc5, + 0x0c, 0x14, 0x72, 0x49, 0x9f, 0xdf, 0x51, 0xe8, 0xc9, 0x4a, + 0xbe, 0x29, 0x77, 0x70, 0x9b, 0xe2, 0x01, 0x7e, 0x99, 0x16, + 0x78, 0x57, 0x91, 0x7b, 0xc5, 0x14, 0x29, 0x06, 0xf8, 0x63, + 0xe4, 0xcc, 0x8d, 0x0d, 0xf4, 0xbb, 0x23, 0x7e, 0xf5, 0x2c, + 0x87, 0x96, 0x24, 0x43, 0x21, 0xfc, 0x01, 0x95, 0xf8, 0x50, + 0x2e, 0x1b, 0x6a, 0xf2, 0xb6, 0x6c, 0x3c, 0x7f, 0xbd, 0x49, + 0xa9, 0x2a, 0x15, 0xfc, 0x4f, 0xe2, 0xba, 0xc2, 0x8e, 0x7d, + 0xa1, 0x14, 0x57, 0xa5, 0xfd, 0xb2, 0x20, 0xa5, 0x59, 0xef, + 0xa9, 0xe3, 0xd9, 0x72, 0x77, 0x7c, 0x2f, 0x93, 0x2d, 0xb9, + 0xc1, 0x83, 0x48, 0x23, 0x67, 0x0d, 0x45, 0x52, 0xb7, 0x09, + 0x4a, 0xf9, 0x0b, 0xde, 0xcb, 0xd7, 0x0d, 0xfa, 0xc6, 0xc0, + 0xc7, 0x97, 0x80, 0xd9, 0xd6, 0x83, 0xfb, 0x12, 0x3d, 0xd4, + 0x68, 0xc6, 0x45, 0xed, 0xb5, 0x44, 0xf4, 0x4c, 0xcf, 0x24, + 0x98, 0xe4, 0x73, 0xf2, 0xeb, 0x3f, 0xef, 0x71, 0xf4, 0xac, + 0x94, 0x7b, 0x03, 0x00 }; const unsigned char* diff --git a/src/DUNE/IMC/Blob.hpp b/src/DUNE/IMC/Blob.hpp index 265677756c..7c4d60085f 100644 --- a/src/DUNE/IMC/Blob.hpp +++ b/src/DUNE/IMC/Blob.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Bus.cpp b/src/DUNE/IMC/Bus.cpp index f5b83988af..16e256f7b7 100644 --- a/src/DUNE/IMC/Bus.cpp +++ b/src/DUNE/IMC/Bus.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -85,9 +85,9 @@ namespace DUNE bind->setTimeStamp(); bind->consumer = task->getName(); bind->message_id = id; - m_bind_msgs.push_back(bind); Concurrency::ScopedRWLock l(m_lock, true); + m_bind_msgs.push_back(bind); TransportList::iterator itr = std::find(m_recipients[id].begin(), m_recipients[id].end(), task); if (itr == m_recipients[id].end()) m_recipients[id].push_back(task); @@ -143,6 +143,7 @@ namespace DUNE const std::vector Bus::getBindings(void) { + Concurrency::ScopedRWLock l(m_lock); return m_bind_msgs; } } diff --git a/src/DUNE/IMC/Bus.hpp b/src/DUNE/IMC/Bus.hpp index 9f9755427e..402b14ff5d 100644 --- a/src/DUNE/IMC/Bus.hpp +++ b/src/DUNE/IMC/Bus.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Constants.hpp b/src/DUNE/IMC/Constants.hpp index 019cd83b1f..527587145f 100644 --- a/src/DUNE/IMC/Constants.hpp +++ b/src/DUNE/IMC/Constants.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,18 +28,18 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** #ifndef DUNE_IMC_CONSTANTS_HPP_INCLUDED_ #define DUNE_IMC_CONSTANTS_HPP_INCLUDED_ //! IMC version string. -#define DUNE_IMC_CONST_VERSION "5.4.11" +#define DUNE_IMC_CONST_VERSION "5.4.30" //! Git repository information. -#define DUNE_IMC_CONST_GIT_INFO "2017-05-17 ec59290 (HEAD -> master, origin/master, origin/HEAD)" +#define DUNE_IMC_CONST_GIT_INFO "2022-03-14 ada9492 (HEAD -> master, origin/master, origin/HEAD)" //! MD5 sum of XML specification file. -#define DUNE_IMC_CONST_MD5 "d292e724592557940354dddbfc5a9d32" +#define DUNE_IMC_CONST_MD5 "0f425402b735f36a64d579da7bb4baf3" //! Synchronization number. #define DUNE_IMC_CONST_SYNC 0xFE54 //! Reversed synchronization number. diff --git a/src/DUNE/IMC/Definitions.cpp b/src/DUNE/IMC/Definitions.cpp index 64df8201b0..c72b8ff879 100644 --- a/src/DUNE/IMC/Definitions.cpp +++ b/src/DUNE/IMC/Definitions.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** // ISO C++ 98 headers. @@ -519,6 +519,15 @@ namespace DUNE void RestartSystem::clear(void) { + type = 0; + } + + bool + RestartSystem::fieldsEqual(const Message& msg__) const + { + const IMC::RestartSystem& other__ = static_cast(msg__); + if (type != other__.type) return false; + return true; } int @@ -530,23 +539,31 @@ namespace DUNE uint8_t* RestartSystem::serializeFields(uint8_t* bfr__) const { - return bfr__; + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(type, ptr__); + return ptr__; } uint16_t RestartSystem::deserializeFields(const uint8_t* bfr__, uint16_t size__) { - (void)bfr__; - (void)size__; - return 0; + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(type, bfr__, size__); + return bfr__ - start__; } uint16_t RestartSystem::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { - (void)bfr__; - (void)size__; - return 0; + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(type, bfr__, size__); + return bfr__ - start__; + } + + void + RestartSystem::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "type", type, nindent__); } DevCalibrationControl::DevCalibrationControl(void) @@ -2261,6 +2278,179 @@ namespace DUNE IMC::toJSON(os__, "type", type, nindent__); } + ProfileSample::ProfileSample(void) + { + m_header.mgid = 112; + clear(); + } + + void + ProfileSample::clear(void) + { + depth = 0; + avg = 0; + } + + bool + ProfileSample::fieldsEqual(const Message& msg__) const + { + const IMC::ProfileSample& other__ = static_cast(msg__); + if (depth != other__.depth) return false; + if (avg != other__.avg) return false; + return true; + } + + int + ProfileSample::validate(void) const + { + return true; + } + + uint8_t* + ProfileSample::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(depth, ptr__); + ptr__ += IMC::serialize(avg, ptr__); + return ptr__; + } + + uint16_t + ProfileSample::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(depth, bfr__, size__); + bfr__ += IMC::deserialize(avg, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + ProfileSample::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(depth, bfr__, size__); + bfr__ += IMC::reverseDeserialize(avg, bfr__, size__); + return bfr__ - start__; + } + + void + ProfileSample::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "depth", depth, nindent__); + IMC::toJSON(os__, "avg", avg, nindent__); + } + + VerticalProfile::VerticalProfile(void) + { + m_header.mgid = 111; + clear(); + samples.setParent(this); + } + + void + VerticalProfile::clear(void) + { + parameter = 0; + numsamples = 0; + samples.clear(); + lat = 0; + lon = 0; + } + + bool + VerticalProfile::fieldsEqual(const Message& msg__) const + { + const IMC::VerticalProfile& other__ = static_cast(msg__); + if (parameter != other__.parameter) return false; + if (numsamples != other__.numsamples) return false; + if (samples != other__.samples) return false; + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + return true; + } + + int + VerticalProfile::validate(void) const + { + return true; + } + + uint8_t* + VerticalProfile::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(parameter, ptr__); + ptr__ += IMC::serialize(numsamples, ptr__); + ptr__ += samples.serialize(ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + return ptr__; + } + + uint16_t + VerticalProfile::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(parameter, bfr__, size__); + bfr__ += IMC::deserialize(numsamples, bfr__, size__); + bfr__ += samples.deserialize(bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + VerticalProfile::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(parameter, bfr__, size__); + bfr__ += IMC::deserialize(numsamples, bfr__, size__); + bfr__ += samples.reverseDeserialize(bfr__, size__); + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + return bfr__ - start__; + } + + void + VerticalProfile::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "parameter", parameter, nindent__); + IMC::toJSON(os__, "numsamples", numsamples, nindent__); + samples.toJSON(os__, "samples", nindent__); + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + } + + void + VerticalProfile::setTimeStampNested(double value__) + { + samples.setTimeStamp(value__); + } + + void + VerticalProfile::setSourceNested(uint16_t value__) + { + samples.setSource(value__); + } + + void + VerticalProfile::setSourceEntityNested(uint8_t value__) + { + samples.setSourceEntity(value__); + } + + void + VerticalProfile::setDestinationNested(uint16_t value__) + { + samples.setDestination(value__); + } + + void + VerticalProfile::setDestinationEntityNested(uint8_t value__) + { + samples.setDestinationEntity(value__); + } + Heartbeat::Heartbeat(void) { m_header.mgid = 150; @@ -4053,145 +4243,323 @@ namespace DUNE } } - LblRange::LblRange(void) + CommSystemsQuery::CommSystemsQuery(void) { - m_header.mgid = 200; + m_header.mgid = 189; clear(); } void - LblRange::clear(void) + CommSystemsQuery::clear(void) { - id = 0; - range = 0; + type = 0; + comm_interface = 0; + model = 0; + list.clear(); } bool - LblRange::fieldsEqual(const Message& msg__) const + CommSystemsQuery::fieldsEqual(const Message& msg__) const { - const IMC::LblRange& other__ = static_cast(msg__); - if (id != other__.id) return false; - if (range != other__.range) return false; + const IMC::CommSystemsQuery& other__ = static_cast(msg__); + if (type != other__.type) return false; + if (comm_interface != other__.comm_interface) return false; + if (model != other__.model) return false; + if (list != other__.list) return false; return true; } int - LblRange::validate(void) const + CommSystemsQuery::validate(void) const { return true; } uint8_t* - LblRange::serializeFields(uint8_t* bfr__) const + CommSystemsQuery::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(id, ptr__); - ptr__ += IMC::serialize(range, ptr__); + ptr__ += IMC::serialize(type, ptr__); + ptr__ += IMC::serialize(comm_interface, ptr__); + ptr__ += IMC::serialize(model, ptr__); + ptr__ += IMC::serialize(list, ptr__); return ptr__; } uint16_t - LblRange::deserializeFields(const uint8_t* bfr__, uint16_t size__) + CommSystemsQuery::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(id, bfr__, size__); - bfr__ += IMC::deserialize(range, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(comm_interface, bfr__, size__); + bfr__ += IMC::deserialize(model, bfr__, size__); + bfr__ += IMC::deserialize(list, bfr__, size__); return bfr__ - start__; } uint16_t - LblRange::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + CommSystemsQuery::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(id, bfr__, size__); - bfr__ += IMC::reverseDeserialize(range, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::reverseDeserialize(comm_interface, bfr__, size__); + bfr__ += IMC::reverseDeserialize(model, bfr__, size__); + bfr__ += IMC::reverseDeserialize(list, bfr__, size__); return bfr__ - start__; } - uint16_t - LblRange::getSubId(void) const - { - return id; - } - - void - LblRange::setSubId(uint16_t subid) - { - id = (uint8_t)subid; - } - void - LblRange::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + CommSystemsQuery::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "id", id, nindent__); - IMC::toJSON(os__, "range", range, nindent__); + IMC::toJSON(os__, "type", type, nindent__); + IMC::toJSON(os__, "comm_interface", comm_interface, nindent__); + IMC::toJSON(os__, "model", model, nindent__); + IMC::toJSON(os__, "list", list, nindent__); } - LblBeacon::LblBeacon(void) + TelemetryMsg::TelemetryMsg(void) { - m_header.mgid = 202; + m_header.mgid = 190; clear(); } void - LblBeacon::clear(void) + TelemetryMsg::clear(void) { - beacon.clear(); - lat = 0; - lon = 0; - depth = 0; - query_channel = 0; - reply_channel = 0; - transponder_delay = 0; + type = 0; + req_id = 0; + ttl = 0; + code = 0; + destination.clear(); + source.clear(); + acknowledge = 0; + status = 0; + data.clear(); } bool - LblBeacon::fieldsEqual(const Message& msg__) const + TelemetryMsg::fieldsEqual(const Message& msg__) const { - const IMC::LblBeacon& other__ = static_cast(msg__); - if (beacon != other__.beacon) return false; - if (lat != other__.lat) return false; - if (lon != other__.lon) return false; - if (depth != other__.depth) return false; - if (query_channel != other__.query_channel) return false; - if (reply_channel != other__.reply_channel) return false; - if (transponder_delay != other__.transponder_delay) return false; + const IMC::TelemetryMsg& other__ = static_cast(msg__); + if (type != other__.type) return false; + if (req_id != other__.req_id) return false; + if (ttl != other__.ttl) return false; + if (code != other__.code) return false; + if (destination != other__.destination) return false; + if (source != other__.source) return false; + if (acknowledge != other__.acknowledge) return false; + if (status != other__.status) return false; + if (data != other__.data) return false; return true; } int - LblBeacon::validate(void) const + TelemetryMsg::validate(void) const { - if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; - if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; return true; } uint8_t* - LblBeacon::serializeFields(uint8_t* bfr__) const + TelemetryMsg::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(beacon, ptr__); - ptr__ += IMC::serialize(lat, ptr__); - ptr__ += IMC::serialize(lon, ptr__); - ptr__ += IMC::serialize(depth, ptr__); - ptr__ += IMC::serialize(query_channel, ptr__); - ptr__ += IMC::serialize(reply_channel, ptr__); - ptr__ += IMC::serialize(transponder_delay, ptr__); + ptr__ += IMC::serialize(type, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(ttl, ptr__); + ptr__ += IMC::serialize(code, ptr__); + ptr__ += IMC::serialize(destination, ptr__); + ptr__ += IMC::serialize(source, ptr__); + ptr__ += IMC::serialize(acknowledge, ptr__); + ptr__ += IMC::serialize(status, ptr__); + ptr__ += IMC::serialize(data, ptr__); return ptr__; } uint16_t - LblBeacon::deserializeFields(const uint8_t* bfr__, uint16_t size__) + TelemetryMsg::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(beacon, bfr__, size__); - bfr__ += IMC::deserialize(lat, bfr__, size__); - bfr__ += IMC::deserialize(lon, bfr__, size__); - bfr__ += IMC::deserialize(depth, bfr__, size__); - bfr__ += IMC::deserialize(query_channel, bfr__, size__); - bfr__ += IMC::deserialize(reply_channel, bfr__, size__); - bfr__ += IMC::deserialize(transponder_delay, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(ttl, bfr__, size__); + bfr__ += IMC::deserialize(code, bfr__, size__); + bfr__ += IMC::deserialize(destination, bfr__, size__); + bfr__ += IMC::deserialize(source, bfr__, size__); + bfr__ += IMC::deserialize(acknowledge, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::deserialize(data, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + TelemetryMsg::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ttl, bfr__, size__); + bfr__ += IMC::deserialize(code, bfr__, size__); + bfr__ += IMC::reverseDeserialize(destination, bfr__, size__); + bfr__ += IMC::reverseDeserialize(source, bfr__, size__); + bfr__ += IMC::deserialize(acknowledge, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::reverseDeserialize(data, bfr__, size__); + return bfr__ - start__; + } + + void + TelemetryMsg::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "type", type, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "ttl", ttl, nindent__); + IMC::toJSON(os__, "code", code, nindent__); + IMC::toJSON(os__, "destination", destination, nindent__); + IMC::toJSON(os__, "source", source, nindent__); + IMC::toJSON(os__, "acknowledge", acknowledge, nindent__); + IMC::toJSON(os__, "status", status, nindent__); + IMC::toJSON(os__, "data", data, nindent__); + } + + LblRange::LblRange(void) + { + m_header.mgid = 200; + clear(); + } + + void + LblRange::clear(void) + { + id = 0; + range = 0; + } + + bool + LblRange::fieldsEqual(const Message& msg__) const + { + const IMC::LblRange& other__ = static_cast(msg__); + if (id != other__.id) return false; + if (range != other__.range) return false; + return true; + } + + int + LblRange::validate(void) const + { + return true; + } + + uint8_t* + LblRange::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(id, ptr__); + ptr__ += IMC::serialize(range, ptr__); + return ptr__; + } + + uint16_t + LblRange::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(id, bfr__, size__); + bfr__ += IMC::deserialize(range, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + LblRange::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(id, bfr__, size__); + bfr__ += IMC::reverseDeserialize(range, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + LblRange::getSubId(void) const + { + return id; + } + + void + LblRange::setSubId(uint16_t subid) + { + id = (uint8_t)subid; + } + + void + LblRange::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "id", id, nindent__); + IMC::toJSON(os__, "range", range, nindent__); + } + + LblBeacon::LblBeacon(void) + { + m_header.mgid = 202; + clear(); + } + + void + LblBeacon::clear(void) + { + beacon.clear(); + lat = 0; + lon = 0; + depth = 0; + query_channel = 0; + reply_channel = 0; + transponder_delay = 0; + } + + bool + LblBeacon::fieldsEqual(const Message& msg__) const + { + const IMC::LblBeacon& other__ = static_cast(msg__); + if (beacon != other__.beacon) return false; + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (depth != other__.depth) return false; + if (query_channel != other__.query_channel) return false; + if (reply_channel != other__.reply_channel) return false; + if (transponder_delay != other__.transponder_delay) return false; + return true; + } + + int + LblBeacon::validate(void) const + { + if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; + if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; + return true; + } + + uint8_t* + LblBeacon::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(beacon, ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(depth, ptr__); + ptr__ += IMC::serialize(query_channel, ptr__); + ptr__ += IMC::serialize(reply_channel, ptr__); + ptr__ += IMC::serialize(transponder_delay, ptr__); + return ptr__; + } + + uint16_t + LblBeacon::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(beacon, bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(depth, bfr__, size__); + bfr__ += IMC::deserialize(query_channel, bfr__, size__); + bfr__ += IMC::deserialize(reply_channel, bfr__, size__); + bfr__ += IMC::deserialize(transponder_delay, bfr__, size__); return bfr__ - start__; } @@ -4416,79 +4784,195 @@ namespace DUNE } } - AcousticOperation::AcousticOperation(void) + SimAcousticMessage::SimAcousticMessage(void) { - m_header.mgid = 211; + m_header.mgid = 207; clear(); - msg.setParent(this); } void - AcousticOperation::clear(void) + SimAcousticMessage::clear(void) { - op = 0; - system.clear(); - range = 0; - msg.clear(); + lat = 0; + lon = 0; + depth = 0; + sentence.clear(); + txtime = 0; + modem_type.clear(); + sys_src.clear(); + seq = 0; + sys_dst.clear(); + flags = 0; + data.clear(); } bool - AcousticOperation::fieldsEqual(const Message& msg__) const + SimAcousticMessage::fieldsEqual(const Message& msg__) const { - const IMC::AcousticOperation& other__ = static_cast(msg__); - if (op != other__.op) return false; - if (system != other__.system) return false; - if (range != other__.range) return false; - if (msg != other__.msg) return false; + const IMC::SimAcousticMessage& other__ = static_cast(msg__); + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (depth != other__.depth) return false; + if (sentence != other__.sentence) return false; + if (txtime != other__.txtime) return false; + if (modem_type != other__.modem_type) return false; + if (sys_src != other__.sys_src) return false; + if (seq != other__.seq) return false; + if (sys_dst != other__.sys_dst) return false; + if (flags != other__.flags) return false; + if (data != other__.data) return false; return true; } int - AcousticOperation::validate(void) const + SimAcousticMessage::validate(void) const { return true; } uint8_t* - AcousticOperation::serializeFields(uint8_t* bfr__) const + SimAcousticMessage::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(op, ptr__); - ptr__ += IMC::serialize(system, ptr__); - ptr__ += IMC::serialize(range, ptr__); - ptr__ += msg.serialize(ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(depth, ptr__); + ptr__ += IMC::serialize(sentence, ptr__); + ptr__ += IMC::serialize(txtime, ptr__); + ptr__ += IMC::serialize(modem_type, ptr__); + ptr__ += IMC::serialize(sys_src, ptr__); + ptr__ += IMC::serialize(seq, ptr__); + ptr__ += IMC::serialize(sys_dst, ptr__); + ptr__ += IMC::serialize(flags, ptr__); + ptr__ += IMC::serialize(data, ptr__); return ptr__; } uint16_t - AcousticOperation::deserializeFields(const uint8_t* bfr__, uint16_t size__) + SimAcousticMessage::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(op, bfr__, size__); - bfr__ += IMC::deserialize(system, bfr__, size__); - bfr__ += IMC::deserialize(range, bfr__, size__); - bfr__ += msg.deserialize(bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(depth, bfr__, size__); + bfr__ += IMC::deserialize(sentence, bfr__, size__); + bfr__ += IMC::deserialize(txtime, bfr__, size__); + bfr__ += IMC::deserialize(modem_type, bfr__, size__); + bfr__ += IMC::deserialize(sys_src, bfr__, size__); + bfr__ += IMC::deserialize(seq, bfr__, size__); + bfr__ += IMC::deserialize(sys_dst, bfr__, size__); + bfr__ += IMC::deserialize(flags, bfr__, size__); + bfr__ += IMC::deserialize(data, bfr__, size__); return bfr__ - start__; } uint16_t - AcousticOperation::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + SimAcousticMessage::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(op, bfr__, size__); - bfr__ += IMC::reverseDeserialize(system, bfr__, size__); - bfr__ += IMC::reverseDeserialize(range, bfr__, size__); - bfr__ += msg.reverseDeserialize(bfr__, size__); + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(depth, bfr__, size__); + bfr__ += IMC::reverseDeserialize(sentence, bfr__, size__); + bfr__ += IMC::reverseDeserialize(txtime, bfr__, size__); + bfr__ += IMC::reverseDeserialize(modem_type, bfr__, size__); + bfr__ += IMC::reverseDeserialize(sys_src, bfr__, size__); + bfr__ += IMC::reverseDeserialize(seq, bfr__, size__); + bfr__ += IMC::reverseDeserialize(sys_dst, bfr__, size__); + bfr__ += IMC::deserialize(flags, bfr__, size__); + bfr__ += IMC::reverseDeserialize(data, bfr__, size__); return bfr__ - start__; } void - AcousticOperation::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + SimAcousticMessage::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "op", op, nindent__); - IMC::toJSON(os__, "system", system, nindent__); - IMC::toJSON(os__, "range", range, nindent__); - msg.toJSON(os__, "msg", nindent__); + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + IMC::toJSON(os__, "depth", depth, nindent__); + IMC::toJSON(os__, "sentence", sentence, nindent__); + IMC::toJSON(os__, "txtime", txtime, nindent__); + IMC::toJSON(os__, "modem_type", modem_type, nindent__); + IMC::toJSON(os__, "sys_src", sys_src, nindent__); + IMC::toJSON(os__, "seq", seq, nindent__); + IMC::toJSON(os__, "sys_dst", sys_dst, nindent__); + IMC::toJSON(os__, "flags", flags, nindent__); + IMC::toJSON(os__, "data", data, nindent__); + } + + AcousticOperation::AcousticOperation(void) + { + m_header.mgid = 211; + clear(); + msg.setParent(this); + } + + void + AcousticOperation::clear(void) + { + op = 0; + system.clear(); + range = 0; + msg.clear(); + } + + bool + AcousticOperation::fieldsEqual(const Message& msg__) const + { + const IMC::AcousticOperation& other__ = static_cast(msg__); + if (op != other__.op) return false; + if (system != other__.system) return false; + if (range != other__.range) return false; + if (msg != other__.msg) return false; + return true; + } + + int + AcousticOperation::validate(void) const + { + return true; + } + + uint8_t* + AcousticOperation::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(op, ptr__); + ptr__ += IMC::serialize(system, ptr__); + ptr__ += IMC::serialize(range, ptr__); + ptr__ += msg.serialize(ptr__); + return ptr__; + } + + uint16_t + AcousticOperation::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::deserialize(system, bfr__, size__); + bfr__ += IMC::deserialize(range, bfr__, size__); + bfr__ += msg.deserialize(bfr__, size__); + return bfr__ - start__; + } + + uint16_t + AcousticOperation::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::reverseDeserialize(system, bfr__, size__); + bfr__ += IMC::reverseDeserialize(range, bfr__, size__); + bfr__ += msg.reverseDeserialize(bfr__, size__); + return bfr__ - start__; + } + + void + AcousticOperation::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "op", op, nindent__); + IMC::toJSON(os__, "system", system, nindent__); + IMC::toJSON(os__, "range", range, nindent__); + msg.toJSON(os__, "msg", nindent__); } void @@ -4699,170 +5183,246 @@ namespace DUNE IMC::toJSON(os__, "integrity", integrity, nindent__); } - Rpm::Rpm(void) + AcousticRequest::AcousticRequest(void) { - m_header.mgid = 250; + m_header.mgid = 215; clear(); + msg.setParent(this); } void - Rpm::clear(void) + AcousticRequest::clear(void) { - value = 0; + req_id = 0; + destination.clear(); + timeout = 0; + range = 0; + type = 0; + msg.clear(); } bool - Rpm::fieldsEqual(const Message& msg__) const + AcousticRequest::fieldsEqual(const Message& msg__) const { - const IMC::Rpm& other__ = static_cast(msg__); - if (value != other__.value) return false; + const IMC::AcousticRequest& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (destination != other__.destination) return false; + if (timeout != other__.timeout) return false; + if (range != other__.range) return false; + if (type != other__.type) return false; + if (msg != other__.msg) return false; return true; } int - Rpm::validate(void) const + AcousticRequest::validate(void) const { return true; } uint8_t* - Rpm::serializeFields(uint8_t* bfr__) const + AcousticRequest::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(value, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(destination, ptr__); + ptr__ += IMC::serialize(timeout, ptr__); + ptr__ += IMC::serialize(range, ptr__); + ptr__ += IMC::serialize(type, ptr__); + ptr__ += msg.serialize(ptr__); return ptr__; } uint16_t - Rpm::deserializeFields(const uint8_t* bfr__, uint16_t size__) + AcousticRequest::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(value, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(destination, bfr__, size__); + bfr__ += IMC::deserialize(timeout, bfr__, size__); + bfr__ += IMC::deserialize(range, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += msg.deserialize(bfr__, size__); return bfr__ - start__; } uint16_t - Rpm::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + AcousticRequest::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::reverseDeserialize(destination, bfr__, size__); + bfr__ += IMC::reverseDeserialize(timeout, bfr__, size__); + bfr__ += IMC::reverseDeserialize(range, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += msg.reverseDeserialize(bfr__, size__); return bfr__ - start__; } - fp64_t - Rpm::getValueFP(void) const + void + AcousticRequest::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - return static_cast(value); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "destination", destination, nindent__); + IMC::toJSON(os__, "timeout", timeout, nindent__); + IMC::toJSON(os__, "range", range, nindent__); + IMC::toJSON(os__, "type", type, nindent__); + msg.toJSON(os__, "msg", nindent__); } void - Rpm::setValueFP(fp64_t val) + AcousticRequest::setTimeStampNested(double value__) { - value = static_cast(val); + if (!msg.isNull()) + { + msg.get()->setTimeStamp(value__); + } } void - Rpm::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + AcousticRequest::setSourceNested(uint16_t value__) { - IMC::toJSON(os__, "value", value, nindent__); + if (!msg.isNull()) + { + msg.get()->setSource(value__); + } } - Voltage::Voltage(void) + void + AcousticRequest::setSourceEntityNested(uint8_t value__) { - m_header.mgid = 251; + if (!msg.isNull()) + { + msg.get()->setSourceEntity(value__); + } + } + + void + AcousticRequest::setDestinationNested(uint16_t value__) + { + if (!msg.isNull()) + { + msg.get()->setDestination(value__); + } + } + + void + AcousticRequest::setDestinationEntityNested(uint8_t value__) + { + if (!msg.isNull()) + { + msg.get()->setDestinationEntity(value__); + } + } + + AcousticStatus::AcousticStatus(void) + { + m_header.mgid = 216; clear(); } void - Voltage::clear(void) + AcousticStatus::clear(void) { - value = 0; + req_id = 0; + type = 0; + status = 0; + info.clear(); + range = 0; } bool - Voltage::fieldsEqual(const Message& msg__) const + AcousticStatus::fieldsEqual(const Message& msg__) const { - const IMC::Voltage& other__ = static_cast(msg__); - if (value != other__.value) return false; + const IMC::AcousticStatus& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (type != other__.type) return false; + if (status != other__.status) return false; + if (info != other__.info) return false; + if (range != other__.range) return false; return true; } int - Voltage::validate(void) const + AcousticStatus::validate(void) const { return true; } uint8_t* - Voltage::serializeFields(uint8_t* bfr__) const + AcousticStatus::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(value, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(type, ptr__); + ptr__ += IMC::serialize(status, ptr__); + ptr__ += IMC::serialize(info, ptr__); + ptr__ += IMC::serialize(range, ptr__); return ptr__; } uint16_t - Voltage::deserializeFields(const uint8_t* bfr__, uint16_t size__) + AcousticStatus::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(value, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::deserialize(info, bfr__, size__); + bfr__ += IMC::deserialize(range, bfr__, size__); return bfr__ - start__; } uint16_t - Voltage::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + AcousticStatus::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::reverseDeserialize(info, bfr__, size__); + bfr__ += IMC::reverseDeserialize(range, bfr__, size__); return bfr__ - start__; } - fp64_t - Voltage::getValueFP(void) const - { - return static_cast(value); - } - - void - Voltage::setValueFP(fp64_t val) - { - value = static_cast(val); - } - void - Voltage::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + AcousticStatus::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "value", value, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "type", type, nindent__); + IMC::toJSON(os__, "status", status, nindent__); + IMC::toJSON(os__, "info", info, nindent__); + IMC::toJSON(os__, "range", range, nindent__); } - Current::Current(void) + Rpm::Rpm(void) { - m_header.mgid = 252; + m_header.mgid = 250; clear(); } void - Current::clear(void) + Rpm::clear(void) { value = 0; } bool - Current::fieldsEqual(const Message& msg__) const + Rpm::fieldsEqual(const Message& msg__) const { - const IMC::Current& other__ = static_cast(msg__); + const IMC::Rpm& other__ = static_cast(msg__); if (value != other__.value) return false; return true; } int - Current::validate(void) const + Rpm::validate(void) const { return true; } uint8_t* - Current::serializeFields(uint8_t* bfr__) const + Rpm::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; ptr__ += IMC::serialize(value, ptr__); @@ -4870,7 +5430,7 @@ namespace DUNE } uint16_t - Current::deserializeFields(const uint8_t* bfr__, uint16_t size__) + Rpm::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; bfr__ += IMC::deserialize(value, bfr__, size__); @@ -4878,7 +5438,7 @@ namespace DUNE } uint16_t - Current::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + Rpm::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; bfr__ += IMC::reverseDeserialize(value, bfr__, size__); @@ -4886,31 +5446,167 @@ namespace DUNE } fp64_t - Current::getValueFP(void) const + Rpm::getValueFP(void) const { return static_cast(value); } void - Current::setValueFP(fp64_t val) + Rpm::setValueFP(fp64_t val) { - value = static_cast(val); + value = static_cast(val); } void - Current::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + Rpm::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { IMC::toJSON(os__, "value", value, nindent__); } - GpsFix::GpsFix(void) + Voltage::Voltage(void) { - m_header.mgid = 253; + m_header.mgid = 251; clear(); } void - GpsFix::clear(void) + Voltage::clear(void) + { + value = 0; + } + + bool + Voltage::fieldsEqual(const Message& msg__) const + { + const IMC::Voltage& other__ = static_cast(msg__); + if (value != other__.value) return false; + return true; + } + + int + Voltage::validate(void) const + { + return true; + } + + uint8_t* + Voltage::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(value, ptr__); + return ptr__; + } + + uint16_t + Voltage::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(value, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + Voltage::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + return bfr__ - start__; + } + + fp64_t + Voltage::getValueFP(void) const + { + return static_cast(value); + } + + void + Voltage::setValueFP(fp64_t val) + { + value = static_cast(val); + } + + void + Voltage::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "value", value, nindent__); + } + + Current::Current(void) + { + m_header.mgid = 252; + clear(); + } + + void + Current::clear(void) + { + value = 0; + } + + bool + Current::fieldsEqual(const Message& msg__) const + { + const IMC::Current& other__ = static_cast(msg__); + if (value != other__.value) return false; + return true; + } + + int + Current::validate(void) const + { + return true; + } + + uint8_t* + Current::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(value, ptr__); + return ptr__; + } + + uint16_t + Current::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(value, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + Current::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + return bfr__ - start__; + } + + fp64_t + Current::getValueFP(void) const + { + return static_cast(value); + } + + void + Current::setValueFP(fp64_t val) + { + value = static_cast(val); + } + + void + Current::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "value", value, nindent__); + } + + GpsFix::GpsFix(void) + { + m_header.mgid = 253; + clear(); + } + + void + GpsFix::clear(void) { validity = 0; type = 0; @@ -6730,6 +7426,74 @@ namespace DUNE IMC::toJSON(os__, "value", value, nindent__); } + Force::Force(void) + { + m_header.mgid = 275; + clear(); + } + + void + Force::clear(void) + { + value = 0; + } + + bool + Force::fieldsEqual(const Message& msg__) const + { + const IMC::Force& other__ = static_cast(msg__); + if (value != other__.value) return false; + return true; + } + + int + Force::validate(void) const + { + return true; + } + + uint8_t* + Force::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(value, ptr__); + return ptr__; + } + + uint16_t + Force::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(value, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + Force::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + return bfr__ - start__; + } + + fp64_t + Force::getValueFP(void) const + { + return static_cast(value); + } + + void + Force::setValueFP(fp64_t val) + { + value = static_cast(val); + } + + void + Force::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "value", value, nindent__); + } + SonarData::SonarData(void) { m_header.mgid = 276; @@ -17051,1149 +17815,2297 @@ namespace DUNE IMC::toJSON(os__, "custom", custom, nindent__); } - VehicleState::VehicleState(void) + Alignment::Alignment(void) { - m_header.mgid = 500; + m_header.mgid = 495; clear(); } void - VehicleState::clear(void) + Alignment::clear(void) { - op_mode = 0; - error_count = 0; - error_ents.clear(); - maneuver_type = 0; - maneuver_stime = 0; - maneuver_eta = 0; - control_loops = 0; - flags = 0; - last_error.clear(); - last_error_time = 0; + timeout = 0; + lat = 0; + lon = 0; + speed = 0; + speed_units = 0; + custom.clear(); } bool - VehicleState::fieldsEqual(const Message& msg__) const + Alignment::fieldsEqual(const Message& msg__) const { - const IMC::VehicleState& other__ = static_cast(msg__); - if (op_mode != other__.op_mode) return false; - if (error_count != other__.error_count) return false; - if (error_ents != other__.error_ents) return false; - if (maneuver_type != other__.maneuver_type) return false; - if (maneuver_stime != other__.maneuver_stime) return false; - if (maneuver_eta != other__.maneuver_eta) return false; - if (control_loops != other__.control_loops) return false; - if (flags != other__.flags) return false; - if (last_error != other__.last_error) return false; - if (last_error_time != other__.last_error_time) return false; + const IMC::Alignment& other__ = static_cast(msg__); + if (timeout != other__.timeout) return false; + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (speed != other__.speed) return false; + if (speed_units != other__.speed_units) return false; + if (custom != other__.custom) return false; return true; } int - VehicleState::validate(void) const + Alignment::validate(void) const { + if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; + if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; return true; } uint8_t* - VehicleState::serializeFields(uint8_t* bfr__) const + Alignment::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(op_mode, ptr__); - ptr__ += IMC::serialize(error_count, ptr__); - ptr__ += IMC::serialize(error_ents, ptr__); - ptr__ += IMC::serialize(maneuver_type, ptr__); - ptr__ += IMC::serialize(maneuver_stime, ptr__); - ptr__ += IMC::serialize(maneuver_eta, ptr__); - ptr__ += IMC::serialize(control_loops, ptr__); - ptr__ += IMC::serialize(flags, ptr__); - ptr__ += IMC::serialize(last_error, ptr__); - ptr__ += IMC::serialize(last_error_time, ptr__); + ptr__ += IMC::serialize(timeout, ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(speed, ptr__); + ptr__ += IMC::serialize(speed_units, ptr__); + ptr__ += IMC::serialize(custom, ptr__); return ptr__; } uint16_t - VehicleState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + Alignment::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(op_mode, bfr__, size__); - bfr__ += IMC::deserialize(error_count, bfr__, size__); - bfr__ += IMC::deserialize(error_ents, bfr__, size__); - bfr__ += IMC::deserialize(maneuver_type, bfr__, size__); - bfr__ += IMC::deserialize(maneuver_stime, bfr__, size__); - bfr__ += IMC::deserialize(maneuver_eta, bfr__, size__); - bfr__ += IMC::deserialize(control_loops, bfr__, size__); - bfr__ += IMC::deserialize(flags, bfr__, size__); - bfr__ += IMC::deserialize(last_error, bfr__, size__); - bfr__ += IMC::deserialize(last_error_time, bfr__, size__); + bfr__ += IMC::deserialize(timeout, bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(speed_units, bfr__, size__); + bfr__ += IMC::deserialize(custom, bfr__, size__); return bfr__ - start__; } uint16_t - VehicleState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + Alignment::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(op_mode, bfr__, size__); - bfr__ += IMC::deserialize(error_count, bfr__, size__); - bfr__ += IMC::reverseDeserialize(error_ents, bfr__, size__); - bfr__ += IMC::reverseDeserialize(maneuver_type, bfr__, size__); - bfr__ += IMC::reverseDeserialize(maneuver_stime, bfr__, size__); - bfr__ += IMC::reverseDeserialize(maneuver_eta, bfr__, size__); - bfr__ += IMC::reverseDeserialize(control_loops, bfr__, size__); - bfr__ += IMC::deserialize(flags, bfr__, size__); - bfr__ += IMC::reverseDeserialize(last_error, bfr__, size__); - bfr__ += IMC::reverseDeserialize(last_error_time, bfr__, size__); + bfr__ += IMC::reverseDeserialize(timeout, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(speed_units, bfr__, size__); + bfr__ += IMC::reverseDeserialize(custom, bfr__, size__); return bfr__ - start__; } void - VehicleState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + Alignment::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "op_mode", op_mode, nindent__); - IMC::toJSON(os__, "error_count", error_count, nindent__); - IMC::toJSON(os__, "error_ents", error_ents, nindent__); - IMC::toJSON(os__, "maneuver_type", maneuver_type, nindent__); - IMC::toJSON(os__, "maneuver_stime", maneuver_stime, nindent__); - IMC::toJSON(os__, "maneuver_eta", maneuver_eta, nindent__); - IMC::toJSON(os__, "control_loops", control_loops, nindent__); - IMC::toJSON(os__, "flags", flags, nindent__); - IMC::toJSON(os__, "last_error", last_error, nindent__); - IMC::toJSON(os__, "last_error_time", last_error_time, nindent__); + IMC::toJSON(os__, "timeout", timeout, nindent__); + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + IMC::toJSON(os__, "speed", speed, nindent__); + IMC::toJSON(os__, "speed_units", speed_units, nindent__); + IMC::toJSON(os__, "custom", custom, nindent__); } - VehicleCommand::VehicleCommand(void) + StationKeepingExtended::StationKeepingExtended(void) { - m_header.mgid = 501; + m_header.mgid = 496; clear(); - maneuver.setParent(this); } void - VehicleCommand::clear(void) + StationKeepingExtended::clear(void) { - type = 0; - request_id = 0; - command = 0; - maneuver.clear(); - calib_time = 0; - info.clear(); + lat = 0; + lon = 0; + z = 0; + z_units = 0; + radius = 0; + duration = 0; + speed = 0; + speed_units = 0; + popup_period = 0; + popup_duration = 0; + flags = 0; + custom.clear(); } bool - VehicleCommand::fieldsEqual(const Message& msg__) const + StationKeepingExtended::fieldsEqual(const Message& msg__) const { - const IMC::VehicleCommand& other__ = static_cast(msg__); - if (type != other__.type) return false; - if (request_id != other__.request_id) return false; - if (command != other__.command) return false; - if (maneuver != other__.maneuver) return false; - if (calib_time != other__.calib_time) return false; - if (info != other__.info) return false; + const IMC::StationKeepingExtended& other__ = static_cast(msg__); + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (z != other__.z) return false; + if (z_units != other__.z_units) return false; + if (radius != other__.radius) return false; + if (duration != other__.duration) return false; + if (speed != other__.speed) return false; + if (speed_units != other__.speed_units) return false; + if (popup_period != other__.popup_period) return false; + if (popup_duration != other__.popup_duration) return false; + if (flags != other__.flags) return false; + if (custom != other__.custom) return false; return true; } int - VehicleCommand::validate(void) const + StationKeepingExtended::validate(void) const { + if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; + if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; return true; } uint8_t* - VehicleCommand::serializeFields(uint8_t* bfr__) const + StationKeepingExtended::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(type, ptr__); - ptr__ += IMC::serialize(request_id, ptr__); - ptr__ += IMC::serialize(command, ptr__); - ptr__ += maneuver.serialize(ptr__); - ptr__ += IMC::serialize(calib_time, ptr__); - ptr__ += IMC::serialize(info, ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(z, ptr__); + ptr__ += IMC::serialize(z_units, ptr__); + ptr__ += IMC::serialize(radius, ptr__); + ptr__ += IMC::serialize(duration, ptr__); + ptr__ += IMC::serialize(speed, ptr__); + ptr__ += IMC::serialize(speed_units, ptr__); + ptr__ += IMC::serialize(popup_period, ptr__); + ptr__ += IMC::serialize(popup_duration, ptr__); + ptr__ += IMC::serialize(flags, ptr__); + ptr__ += IMC::serialize(custom, ptr__); return ptr__; } uint16_t - VehicleCommand::deserializeFields(const uint8_t* bfr__, uint16_t size__) + StationKeepingExtended::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(type, bfr__, size__); - bfr__ += IMC::deserialize(request_id, bfr__, size__); - bfr__ += IMC::deserialize(command, bfr__, size__); - bfr__ += maneuver.deserialize(bfr__, size__); - bfr__ += IMC::deserialize(calib_time, bfr__, size__); - bfr__ += IMC::deserialize(info, bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(z, bfr__, size__); + bfr__ += IMC::deserialize(z_units, bfr__, size__); + bfr__ += IMC::deserialize(radius, bfr__, size__); + bfr__ += IMC::deserialize(duration, bfr__, size__); + bfr__ += IMC::deserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(speed_units, bfr__, size__); + bfr__ += IMC::deserialize(popup_period, bfr__, size__); + bfr__ += IMC::deserialize(popup_duration, bfr__, size__); + bfr__ += IMC::deserialize(flags, bfr__, size__); + bfr__ += IMC::deserialize(custom, bfr__, size__); return bfr__ - start__; } uint16_t - VehicleCommand::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + StationKeepingExtended::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(type, bfr__, size__); - bfr__ += IMC::reverseDeserialize(request_id, bfr__, size__); - bfr__ += IMC::deserialize(command, bfr__, size__); - bfr__ += maneuver.reverseDeserialize(bfr__, size__); - bfr__ += IMC::reverseDeserialize(calib_time, bfr__, size__); - bfr__ += IMC::reverseDeserialize(info, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(z, bfr__, size__); + bfr__ += IMC::deserialize(z_units, bfr__, size__); + bfr__ += IMC::reverseDeserialize(radius, bfr__, size__); + bfr__ += IMC::reverseDeserialize(duration, bfr__, size__); + bfr__ += IMC::reverseDeserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(speed_units, bfr__, size__); + bfr__ += IMC::reverseDeserialize(popup_period, bfr__, size__); + bfr__ += IMC::reverseDeserialize(popup_duration, bfr__, size__); + bfr__ += IMC::deserialize(flags, bfr__, size__); + bfr__ += IMC::reverseDeserialize(custom, bfr__, size__); return bfr__ - start__; } void - VehicleCommand::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + StationKeepingExtended::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "type", type, nindent__); - IMC::toJSON(os__, "request_id", request_id, nindent__); - IMC::toJSON(os__, "command", command, nindent__); - maneuver.toJSON(os__, "maneuver", nindent__); - IMC::toJSON(os__, "calib_time", calib_time, nindent__); - IMC::toJSON(os__, "info", info, nindent__); + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + IMC::toJSON(os__, "z", z, nindent__); + IMC::toJSON(os__, "z_units", z_units, nindent__); + IMC::toJSON(os__, "radius", radius, nindent__); + IMC::toJSON(os__, "duration", duration, nindent__); + IMC::toJSON(os__, "speed", speed, nindent__); + IMC::toJSON(os__, "speed_units", speed_units, nindent__); + IMC::toJSON(os__, "popup_period", popup_period, nindent__); + IMC::toJSON(os__, "popup_duration", popup_duration, nindent__); + IMC::toJSON(os__, "flags", flags, nindent__); + IMC::toJSON(os__, "custom", custom, nindent__); } - void - VehicleCommand::setTimeStampNested(double value__) + ManeuverDone::ManeuverDone(void) { - if (!maneuver.isNull()) - { - maneuver.get()->setTimeStamp(value__); - } + m_header.mgid = 497; + clear(); } void - VehicleCommand::setSourceNested(uint16_t value__) + ManeuverDone::clear(void) { - if (!maneuver.isNull()) - { - maneuver.get()->setSource(value__); - } } - void - VehicleCommand::setSourceEntityNested(uint8_t value__) + int + ManeuverDone::validate(void) const { - if (!maneuver.isNull()) - { - maneuver.get()->setSourceEntity(value__); - } + return true; } - void - VehicleCommand::setDestinationNested(uint16_t value__) + uint8_t* + ManeuverDone::serializeFields(uint8_t* bfr__) const { - if (!maneuver.isNull()) - { - maneuver.get()->setDestination(value__); - } + return bfr__; } - void - VehicleCommand::setDestinationEntityNested(uint8_t value__) + uint16_t + ManeuverDone::deserializeFields(const uint8_t* bfr__, uint16_t size__) { - if (!maneuver.isNull()) - { - maneuver.get()->setDestinationEntity(value__); - } + (void)bfr__; + (void)size__; + return 0; } - MonitorEntityState::MonitorEntityState(void) + uint16_t + ManeuverDone::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { - m_header.mgid = 502; + (void)bfr__; + (void)size__; + return 0; + } + + Magnetometer::Magnetometer(void) + { + m_header.mgid = 499; clear(); } void - MonitorEntityState::clear(void) + Magnetometer::clear(void) { - command = 0; - entities.clear(); + timeout = 0; + lat = 0; + lon = 0; + z = 0; + z_units = 0; + speed = 0; + speed_units = 0; + bearing = 0; + width = 0; + direction = 0; + custom.clear(); } bool - MonitorEntityState::fieldsEqual(const Message& msg__) const + Magnetometer::fieldsEqual(const Message& msg__) const { - const IMC::MonitorEntityState& other__ = static_cast(msg__); - if (command != other__.command) return false; - if (entities != other__.entities) return false; + const IMC::Magnetometer& other__ = static_cast(msg__); + if (timeout != other__.timeout) return false; + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (z != other__.z) return false; + if (z_units != other__.z_units) return false; + if (speed != other__.speed) return false; + if (speed_units != other__.speed_units) return false; + if (bearing != other__.bearing) return false; + if (width != other__.width) return false; + if (direction != other__.direction) return false; + if (custom != other__.custom) return false; return true; } int - MonitorEntityState::validate(void) const + Magnetometer::validate(void) const { + if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; + if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; + if (bearing < 0 || bearing > 6.283185307179586) return false; + if (width < 50) return false; + if (direction > 1) return false; return true; } uint8_t* - MonitorEntityState::serializeFields(uint8_t* bfr__) const + Magnetometer::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(command, ptr__); - ptr__ += IMC::serialize(entities, ptr__); + ptr__ += IMC::serialize(timeout, ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(z, ptr__); + ptr__ += IMC::serialize(z_units, ptr__); + ptr__ += IMC::serialize(speed, ptr__); + ptr__ += IMC::serialize(speed_units, ptr__); + ptr__ += IMC::serialize(bearing, ptr__); + ptr__ += IMC::serialize(width, ptr__); + ptr__ += IMC::serialize(direction, ptr__); + ptr__ += IMC::serialize(custom, ptr__); return ptr__; } uint16_t - MonitorEntityState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + Magnetometer::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(command, bfr__, size__); - bfr__ += IMC::deserialize(entities, bfr__, size__); - return bfr__ - start__; - } - - uint16_t - MonitorEntityState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) - { + bfr__ += IMC::deserialize(timeout, bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(z, bfr__, size__); + bfr__ += IMC::deserialize(z_units, bfr__, size__); + bfr__ += IMC::deserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(speed_units, bfr__, size__); + bfr__ += IMC::deserialize(bearing, bfr__, size__); + bfr__ += IMC::deserialize(width, bfr__, size__); + bfr__ += IMC::deserialize(direction, bfr__, size__); + bfr__ += IMC::deserialize(custom, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + Magnetometer::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(command, bfr__, size__); - bfr__ += IMC::reverseDeserialize(entities, bfr__, size__); + bfr__ += IMC::reverseDeserialize(timeout, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(z, bfr__, size__); + bfr__ += IMC::deserialize(z_units, bfr__, size__); + bfr__ += IMC::reverseDeserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(speed_units, bfr__, size__); + bfr__ += IMC::reverseDeserialize(bearing, bfr__, size__); + bfr__ += IMC::reverseDeserialize(width, bfr__, size__); + bfr__ += IMC::deserialize(direction, bfr__, size__); + bfr__ += IMC::reverseDeserialize(custom, bfr__, size__); return bfr__ - start__; } void - MonitorEntityState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + Magnetometer::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "command", command, nindent__); - IMC::toJSON(os__, "entities", entities, nindent__); + IMC::toJSON(os__, "timeout", timeout, nindent__); + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + IMC::toJSON(os__, "z", z, nindent__); + IMC::toJSON(os__, "z_units", z_units, nindent__); + IMC::toJSON(os__, "speed", speed, nindent__); + IMC::toJSON(os__, "speed_units", speed_units, nindent__); + IMC::toJSON(os__, "bearing", bearing, nindent__); + IMC::toJSON(os__, "width", width, nindent__); + IMC::toJSON(os__, "direction", direction, nindent__); + IMC::toJSON(os__, "custom", custom, nindent__); } - EntityMonitoringState::EntityMonitoringState(void) + VehicleState::VehicleState(void) { - m_header.mgid = 503; + m_header.mgid = 500; clear(); } void - EntityMonitoringState::clear(void) + VehicleState::clear(void) { - mcount = 0; - mnames.clear(); - ecount = 0; - enames.clear(); - ccount = 0; - cnames.clear(); + op_mode = 0; + error_count = 0; + error_ents.clear(); + maneuver_type = 0; + maneuver_stime = 0; + maneuver_eta = 0; + control_loops = 0; + flags = 0; last_error.clear(); last_error_time = 0; } bool - EntityMonitoringState::fieldsEqual(const Message& msg__) const + VehicleState::fieldsEqual(const Message& msg__) const { - const IMC::EntityMonitoringState& other__ = static_cast(msg__); - if (mcount != other__.mcount) return false; - if (mnames != other__.mnames) return false; - if (ecount != other__.ecount) return false; - if (enames != other__.enames) return false; - if (ccount != other__.ccount) return false; - if (cnames != other__.cnames) return false; + const IMC::VehicleState& other__ = static_cast(msg__); + if (op_mode != other__.op_mode) return false; + if (error_count != other__.error_count) return false; + if (error_ents != other__.error_ents) return false; + if (maneuver_type != other__.maneuver_type) return false; + if (maneuver_stime != other__.maneuver_stime) return false; + if (maneuver_eta != other__.maneuver_eta) return false; + if (control_loops != other__.control_loops) return false; + if (flags != other__.flags) return false; if (last_error != other__.last_error) return false; if (last_error_time != other__.last_error_time) return false; return true; } int - EntityMonitoringState::validate(void) const + VehicleState::validate(void) const + { + return true; + } + + uint8_t* + VehicleState::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(op_mode, ptr__); + ptr__ += IMC::serialize(error_count, ptr__); + ptr__ += IMC::serialize(error_ents, ptr__); + ptr__ += IMC::serialize(maneuver_type, ptr__); + ptr__ += IMC::serialize(maneuver_stime, ptr__); + ptr__ += IMC::serialize(maneuver_eta, ptr__); + ptr__ += IMC::serialize(control_loops, ptr__); + ptr__ += IMC::serialize(flags, ptr__); + ptr__ += IMC::serialize(last_error, ptr__); + ptr__ += IMC::serialize(last_error_time, ptr__); + return ptr__; + } + + uint16_t + VehicleState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(op_mode, bfr__, size__); + bfr__ += IMC::deserialize(error_count, bfr__, size__); + bfr__ += IMC::deserialize(error_ents, bfr__, size__); + bfr__ += IMC::deserialize(maneuver_type, bfr__, size__); + bfr__ += IMC::deserialize(maneuver_stime, bfr__, size__); + bfr__ += IMC::deserialize(maneuver_eta, bfr__, size__); + bfr__ += IMC::deserialize(control_loops, bfr__, size__); + bfr__ += IMC::deserialize(flags, bfr__, size__); + bfr__ += IMC::deserialize(last_error, bfr__, size__); + bfr__ += IMC::deserialize(last_error_time, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + VehicleState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(op_mode, bfr__, size__); + bfr__ += IMC::deserialize(error_count, bfr__, size__); + bfr__ += IMC::reverseDeserialize(error_ents, bfr__, size__); + bfr__ += IMC::reverseDeserialize(maneuver_type, bfr__, size__); + bfr__ += IMC::reverseDeserialize(maneuver_stime, bfr__, size__); + bfr__ += IMC::reverseDeserialize(maneuver_eta, bfr__, size__); + bfr__ += IMC::reverseDeserialize(control_loops, bfr__, size__); + bfr__ += IMC::deserialize(flags, bfr__, size__); + bfr__ += IMC::reverseDeserialize(last_error, bfr__, size__); + bfr__ += IMC::reverseDeserialize(last_error_time, bfr__, size__); + return bfr__ - start__; + } + + void + VehicleState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "op_mode", op_mode, nindent__); + IMC::toJSON(os__, "error_count", error_count, nindent__); + IMC::toJSON(os__, "error_ents", error_ents, nindent__); + IMC::toJSON(os__, "maneuver_type", maneuver_type, nindent__); + IMC::toJSON(os__, "maneuver_stime", maneuver_stime, nindent__); + IMC::toJSON(os__, "maneuver_eta", maneuver_eta, nindent__); + IMC::toJSON(os__, "control_loops", control_loops, nindent__); + IMC::toJSON(os__, "flags", flags, nindent__); + IMC::toJSON(os__, "last_error", last_error, nindent__); + IMC::toJSON(os__, "last_error_time", last_error_time, nindent__); + } + + VehicleCommand::VehicleCommand(void) + { + m_header.mgid = 501; + clear(); + maneuver.setParent(this); + } + + void + VehicleCommand::clear(void) + { + type = 0; + request_id = 0; + command = 0; + maneuver.clear(); + calib_time = 0; + info.clear(); + } + + bool + VehicleCommand::fieldsEqual(const Message& msg__) const + { + const IMC::VehicleCommand& other__ = static_cast(msg__); + if (type != other__.type) return false; + if (request_id != other__.request_id) return false; + if (command != other__.command) return false; + if (maneuver != other__.maneuver) return false; + if (calib_time != other__.calib_time) return false; + if (info != other__.info) return false; + return true; + } + + int + VehicleCommand::validate(void) const + { + return true; + } + + uint8_t* + VehicleCommand::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(type, ptr__); + ptr__ += IMC::serialize(request_id, ptr__); + ptr__ += IMC::serialize(command, ptr__); + ptr__ += maneuver.serialize(ptr__); + ptr__ += IMC::serialize(calib_time, ptr__); + ptr__ += IMC::serialize(info, ptr__); + return ptr__; + } + + uint16_t + VehicleCommand::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(request_id, bfr__, size__); + bfr__ += IMC::deserialize(command, bfr__, size__); + bfr__ += maneuver.deserialize(bfr__, size__); + bfr__ += IMC::deserialize(calib_time, bfr__, size__); + bfr__ += IMC::deserialize(info, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + VehicleCommand::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::reverseDeserialize(request_id, bfr__, size__); + bfr__ += IMC::deserialize(command, bfr__, size__); + bfr__ += maneuver.reverseDeserialize(bfr__, size__); + bfr__ += IMC::reverseDeserialize(calib_time, bfr__, size__); + bfr__ += IMC::reverseDeserialize(info, bfr__, size__); + return bfr__ - start__; + } + + void + VehicleCommand::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "type", type, nindent__); + IMC::toJSON(os__, "request_id", request_id, nindent__); + IMC::toJSON(os__, "command", command, nindent__); + maneuver.toJSON(os__, "maneuver", nindent__); + IMC::toJSON(os__, "calib_time", calib_time, nindent__); + IMC::toJSON(os__, "info", info, nindent__); + } + + void + VehicleCommand::setTimeStampNested(double value__) + { + if (!maneuver.isNull()) + { + maneuver.get()->setTimeStamp(value__); + } + } + + void + VehicleCommand::setSourceNested(uint16_t value__) + { + if (!maneuver.isNull()) + { + maneuver.get()->setSource(value__); + } + } + + void + VehicleCommand::setSourceEntityNested(uint8_t value__) + { + if (!maneuver.isNull()) + { + maneuver.get()->setSourceEntity(value__); + } + } + + void + VehicleCommand::setDestinationNested(uint16_t value__) + { + if (!maneuver.isNull()) + { + maneuver.get()->setDestination(value__); + } + } + + void + VehicleCommand::setDestinationEntityNested(uint8_t value__) + { + if (!maneuver.isNull()) + { + maneuver.get()->setDestinationEntity(value__); + } + } + + MonitorEntityState::MonitorEntityState(void) + { + m_header.mgid = 502; + clear(); + } + + void + MonitorEntityState::clear(void) + { + command = 0; + entities.clear(); + } + + bool + MonitorEntityState::fieldsEqual(const Message& msg__) const + { + const IMC::MonitorEntityState& other__ = static_cast(msg__); + if (command != other__.command) return false; + if (entities != other__.entities) return false; + return true; + } + + int + MonitorEntityState::validate(void) const + { + return true; + } + + uint8_t* + MonitorEntityState::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(command, ptr__); + ptr__ += IMC::serialize(entities, ptr__); + return ptr__; + } + + uint16_t + MonitorEntityState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(command, bfr__, size__); + bfr__ += IMC::deserialize(entities, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + MonitorEntityState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(command, bfr__, size__); + bfr__ += IMC::reverseDeserialize(entities, bfr__, size__); + return bfr__ - start__; + } + + void + MonitorEntityState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "command", command, nindent__); + IMC::toJSON(os__, "entities", entities, nindent__); + } + + EntityMonitoringState::EntityMonitoringState(void) + { + m_header.mgid = 503; + clear(); + } + + void + EntityMonitoringState::clear(void) + { + mcount = 0; + mnames.clear(); + ecount = 0; + enames.clear(); + ccount = 0; + cnames.clear(); + last_error.clear(); + last_error_time = 0; + } + + bool + EntityMonitoringState::fieldsEqual(const Message& msg__) const + { + const IMC::EntityMonitoringState& other__ = static_cast(msg__); + if (mcount != other__.mcount) return false; + if (mnames != other__.mnames) return false; + if (ecount != other__.ecount) return false; + if (enames != other__.enames) return false; + if (ccount != other__.ccount) return false; + if (cnames != other__.cnames) return false; + if (last_error != other__.last_error) return false; + if (last_error_time != other__.last_error_time) return false; + return true; + } + + int + EntityMonitoringState::validate(void) const + { + return true; + } + + uint8_t* + EntityMonitoringState::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(mcount, ptr__); + ptr__ += IMC::serialize(mnames, ptr__); + ptr__ += IMC::serialize(ecount, ptr__); + ptr__ += IMC::serialize(enames, ptr__); + ptr__ += IMC::serialize(ccount, ptr__); + ptr__ += IMC::serialize(cnames, ptr__); + ptr__ += IMC::serialize(last_error, ptr__); + ptr__ += IMC::serialize(last_error_time, ptr__); + return ptr__; + } + + uint16_t + EntityMonitoringState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(mcount, bfr__, size__); + bfr__ += IMC::deserialize(mnames, bfr__, size__); + bfr__ += IMC::deserialize(ecount, bfr__, size__); + bfr__ += IMC::deserialize(enames, bfr__, size__); + bfr__ += IMC::deserialize(ccount, bfr__, size__); + bfr__ += IMC::deserialize(cnames, bfr__, size__); + bfr__ += IMC::deserialize(last_error, bfr__, size__); + bfr__ += IMC::deserialize(last_error_time, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + EntityMonitoringState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(mcount, bfr__, size__); + bfr__ += IMC::reverseDeserialize(mnames, bfr__, size__); + bfr__ += IMC::deserialize(ecount, bfr__, size__); + bfr__ += IMC::reverseDeserialize(enames, bfr__, size__); + bfr__ += IMC::deserialize(ccount, bfr__, size__); + bfr__ += IMC::reverseDeserialize(cnames, bfr__, size__); + bfr__ += IMC::reverseDeserialize(last_error, bfr__, size__); + bfr__ += IMC::reverseDeserialize(last_error_time, bfr__, size__); + return bfr__ - start__; + } + + void + EntityMonitoringState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "mcount", mcount, nindent__); + IMC::toJSON(os__, "mnames", mnames, nindent__); + IMC::toJSON(os__, "ecount", ecount, nindent__); + IMC::toJSON(os__, "enames", enames, nindent__); + IMC::toJSON(os__, "ccount", ccount, nindent__); + IMC::toJSON(os__, "cnames", cnames, nindent__); + IMC::toJSON(os__, "last_error", last_error, nindent__); + IMC::toJSON(os__, "last_error_time", last_error_time, nindent__); + } + + OperationalLimits::OperationalLimits(void) + { + m_header.mgid = 504; + clear(); + } + + void + OperationalLimits::clear(void) + { + mask = 0; + max_depth = 0; + min_altitude = 0; + max_altitude = 0; + min_speed = 0; + max_speed = 0; + max_vrate = 0; + lat = 0; + lon = 0; + orientation = 0; + width = 0; + length = 0; + } + + bool + OperationalLimits::fieldsEqual(const Message& msg__) const + { + const IMC::OperationalLimits& other__ = static_cast(msg__); + if (mask != other__.mask) return false; + if (max_depth != other__.max_depth) return false; + if (min_altitude != other__.min_altitude) return false; + if (max_altitude != other__.max_altitude) return false; + if (min_speed != other__.min_speed) return false; + if (max_speed != other__.max_speed) return false; + if (max_vrate != other__.max_vrate) return false; + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (orientation != other__.orientation) return false; + if (width != other__.width) return false; + if (length != other__.length) return false; + return true; + } + + int + OperationalLimits::validate(void) const + { + if (max_depth < 0) return false; + if (min_altitude < 0) return false; + if (max_altitude < 0) return false; + if (min_speed < 0) return false; + if (max_speed < 0) return false; + if (max_vrate < 0) return false; + if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; + if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; + return true; + } + + uint8_t* + OperationalLimits::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(mask, ptr__); + ptr__ += IMC::serialize(max_depth, ptr__); + ptr__ += IMC::serialize(min_altitude, ptr__); + ptr__ += IMC::serialize(max_altitude, ptr__); + ptr__ += IMC::serialize(min_speed, ptr__); + ptr__ += IMC::serialize(max_speed, ptr__); + ptr__ += IMC::serialize(max_vrate, ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(orientation, ptr__); + ptr__ += IMC::serialize(width, ptr__); + ptr__ += IMC::serialize(length, ptr__); + return ptr__; + } + + uint16_t + OperationalLimits::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(mask, bfr__, size__); + bfr__ += IMC::deserialize(max_depth, bfr__, size__); + bfr__ += IMC::deserialize(min_altitude, bfr__, size__); + bfr__ += IMC::deserialize(max_altitude, bfr__, size__); + bfr__ += IMC::deserialize(min_speed, bfr__, size__); + bfr__ += IMC::deserialize(max_speed, bfr__, size__); + bfr__ += IMC::deserialize(max_vrate, bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(orientation, bfr__, size__); + bfr__ += IMC::deserialize(width, bfr__, size__); + bfr__ += IMC::deserialize(length, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + OperationalLimits::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(mask, bfr__, size__); + bfr__ += IMC::reverseDeserialize(max_depth, bfr__, size__); + bfr__ += IMC::reverseDeserialize(min_altitude, bfr__, size__); + bfr__ += IMC::reverseDeserialize(max_altitude, bfr__, size__); + bfr__ += IMC::reverseDeserialize(min_speed, bfr__, size__); + bfr__ += IMC::reverseDeserialize(max_speed, bfr__, size__); + bfr__ += IMC::reverseDeserialize(max_vrate, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(orientation, bfr__, size__); + bfr__ += IMC::reverseDeserialize(width, bfr__, size__); + bfr__ += IMC::reverseDeserialize(length, bfr__, size__); + return bfr__ - start__; + } + + void + OperationalLimits::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "mask", mask, nindent__); + IMC::toJSON(os__, "max_depth", max_depth, nindent__); + IMC::toJSON(os__, "min_altitude", min_altitude, nindent__); + IMC::toJSON(os__, "max_altitude", max_altitude, nindent__); + IMC::toJSON(os__, "min_speed", min_speed, nindent__); + IMC::toJSON(os__, "max_speed", max_speed, nindent__); + IMC::toJSON(os__, "max_vrate", max_vrate, nindent__); + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + IMC::toJSON(os__, "orientation", orientation, nindent__); + IMC::toJSON(os__, "width", width, nindent__); + IMC::toJSON(os__, "length", length, nindent__); + } + + GetOperationalLimits::GetOperationalLimits(void) + { + m_header.mgid = 505; + clear(); + } + + void + GetOperationalLimits::clear(void) + { + } + + int + GetOperationalLimits::validate(void) const + { + return true; + } + + uint8_t* + GetOperationalLimits::serializeFields(uint8_t* bfr__) const + { + return bfr__; + } + + uint16_t + GetOperationalLimits::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + (void)bfr__; + (void)size__; + return 0; + } + + uint16_t + GetOperationalLimits::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + (void)bfr__; + (void)size__; + return 0; + } + + Calibration::Calibration(void) + { + m_header.mgid = 506; + clear(); + } + + void + Calibration::clear(void) + { + duration = 0; + } + + bool + Calibration::fieldsEqual(const Message& msg__) const + { + const IMC::Calibration& other__ = static_cast(msg__); + if (duration != other__.duration) return false; + return true; + } + + int + Calibration::validate(void) const + { + return true; + } + + uint8_t* + Calibration::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(duration, ptr__); + return ptr__; + } + + uint16_t + Calibration::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(duration, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + Calibration::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(duration, bfr__, size__); + return bfr__ - start__; + } + + void + Calibration::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "duration", duration, nindent__); + } + + ControlLoops::ControlLoops(void) + { + m_header.mgid = 507; + clear(); + } + + void + ControlLoops::clear(void) + { + enable = 0; + mask = 0; + scope_ref = 0; + } + + bool + ControlLoops::fieldsEqual(const Message& msg__) const + { + const IMC::ControlLoops& other__ = static_cast(msg__); + if (enable != other__.enable) return false; + if (mask != other__.mask) return false; + if (scope_ref != other__.scope_ref) return false; + return true; + } + + int + ControlLoops::validate(void) const + { + return true; + } + + uint8_t* + ControlLoops::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(enable, ptr__); + ptr__ += IMC::serialize(mask, ptr__); + ptr__ += IMC::serialize(scope_ref, ptr__); + return ptr__; + } + + uint16_t + ControlLoops::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(enable, bfr__, size__); + bfr__ += IMC::deserialize(mask, bfr__, size__); + bfr__ += IMC::deserialize(scope_ref, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + ControlLoops::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(enable, bfr__, size__); + bfr__ += IMC::reverseDeserialize(mask, bfr__, size__); + bfr__ += IMC::reverseDeserialize(scope_ref, bfr__, size__); + return bfr__ - start__; + } + + void + ControlLoops::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "enable", enable, nindent__); + IMC::toJSON(os__, "mask", mask, nindent__); + IMC::toJSON(os__, "scope_ref", scope_ref, nindent__); + } + + VehicleMedium::VehicleMedium(void) + { + m_header.mgid = 508; + clear(); + } + + void + VehicleMedium::clear(void) + { + medium = 0; + } + + bool + VehicleMedium::fieldsEqual(const Message& msg__) const + { + const IMC::VehicleMedium& other__ = static_cast(msg__); + if (medium != other__.medium) return false; + return true; + } + + int + VehicleMedium::validate(void) const + { + return true; + } + + uint8_t* + VehicleMedium::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(medium, ptr__); + return ptr__; + } + + uint16_t + VehicleMedium::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(medium, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + VehicleMedium::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(medium, bfr__, size__); + return bfr__ - start__; + } + + void + VehicleMedium::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "medium", medium, nindent__); + } + + Collision::Collision(void) + { + m_header.mgid = 509; + clear(); + } + + void + Collision::clear(void) + { + value = 0; + type = 0; + } + + bool + Collision::fieldsEqual(const Message& msg__) const + { + const IMC::Collision& other__ = static_cast(msg__); + if (value != other__.value) return false; + if (type != other__.type) return false; + return true; + } + + int + Collision::validate(void) const + { + return true; + } + + uint8_t* + Collision::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(value, ptr__); + ptr__ += IMC::serialize(type, ptr__); + return ptr__; + } + + uint16_t + Collision::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(value, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + Collision::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + return bfr__ - start__; + } + + fp64_t + Collision::getValueFP(void) const + { + return static_cast(value); + } + + void + Collision::setValueFP(fp64_t val) + { + value = static_cast(val); + } + + void + Collision::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "value", value, nindent__); + IMC::toJSON(os__, "type", type, nindent__); + } + + FormState::FormState(void) + { + m_header.mgid = 510; + clear(); + } + + void + FormState::clear(void) + { + possimerr = 0; + converg = 0; + turbulence = 0; + possimmon = 0; + commmon = 0; + convergmon = 0; + } + + bool + FormState::fieldsEqual(const Message& msg__) const + { + const IMC::FormState& other__ = static_cast(msg__); + if (possimerr != other__.possimerr) return false; + if (converg != other__.converg) return false; + if (turbulence != other__.turbulence) return false; + if (possimmon != other__.possimmon) return false; + if (commmon != other__.commmon) return false; + if (convergmon != other__.convergmon) return false; + return true; + } + + int + FormState::validate(void) const + { + return true; + } + + uint8_t* + FormState::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(possimerr, ptr__); + ptr__ += IMC::serialize(converg, ptr__); + ptr__ += IMC::serialize(turbulence, ptr__); + ptr__ += IMC::serialize(possimmon, ptr__); + ptr__ += IMC::serialize(commmon, ptr__); + ptr__ += IMC::serialize(convergmon, ptr__); + return ptr__; + } + + uint16_t + FormState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(possimerr, bfr__, size__); + bfr__ += IMC::deserialize(converg, bfr__, size__); + bfr__ += IMC::deserialize(turbulence, bfr__, size__); + bfr__ += IMC::deserialize(possimmon, bfr__, size__); + bfr__ += IMC::deserialize(commmon, bfr__, size__); + bfr__ += IMC::deserialize(convergmon, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + FormState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(possimerr, bfr__, size__); + bfr__ += IMC::reverseDeserialize(converg, bfr__, size__); + bfr__ += IMC::reverseDeserialize(turbulence, bfr__, size__); + bfr__ += IMC::deserialize(possimmon, bfr__, size__); + bfr__ += IMC::deserialize(commmon, bfr__, size__); + bfr__ += IMC::deserialize(convergmon, bfr__, size__); + return bfr__ - start__; + } + + void + FormState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "possimerr", possimerr, nindent__); + IMC::toJSON(os__, "converg", converg, nindent__); + IMC::toJSON(os__, "turbulence", turbulence, nindent__); + IMC::toJSON(os__, "possimmon", possimmon, nindent__); + IMC::toJSON(os__, "commmon", commmon, nindent__); + IMC::toJSON(os__, "convergmon", convergmon, nindent__); + } + + AutopilotMode::AutopilotMode(void) + { + m_header.mgid = 511; + clear(); + } + + void + AutopilotMode::clear(void) + { + autonomy = 0; + mode.clear(); + } + + bool + AutopilotMode::fieldsEqual(const Message& msg__) const + { + const IMC::AutopilotMode& other__ = static_cast(msg__); + if (autonomy != other__.autonomy) return false; + if (mode != other__.mode) return false; + return true; + } + + int + AutopilotMode::validate(void) const + { + return true; + } + + uint8_t* + AutopilotMode::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(autonomy, ptr__); + ptr__ += IMC::serialize(mode, ptr__); + return ptr__; + } + + uint16_t + AutopilotMode::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(autonomy, bfr__, size__); + bfr__ += IMC::deserialize(mode, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + AutopilotMode::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(autonomy, bfr__, size__); + bfr__ += IMC::reverseDeserialize(mode, bfr__, size__); + return bfr__ - start__; + } + + void + AutopilotMode::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "autonomy", autonomy, nindent__); + IMC::toJSON(os__, "mode", mode, nindent__); + } + + FormationState::FormationState(void) + { + m_header.mgid = 512; + clear(); + } + + void + FormationState::clear(void) + { + type = 0; + op = 0; + possimerr = 0; + converg = 0; + turbulence = 0; + possimmon = 0; + commmon = 0; + convergmon = 0; + } + + bool + FormationState::fieldsEqual(const Message& msg__) const + { + const IMC::FormationState& other__ = static_cast(msg__); + if (type != other__.type) return false; + if (op != other__.op) return false; + if (possimerr != other__.possimerr) return false; + if (converg != other__.converg) return false; + if (turbulence != other__.turbulence) return false; + if (possimmon != other__.possimmon) return false; + if (commmon != other__.commmon) return false; + if (convergmon != other__.convergmon) return false; + return true; + } + + int + FormationState::validate(void) const { return true; } uint8_t* - EntityMonitoringState::serializeFields(uint8_t* bfr__) const + FormationState::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(mcount, ptr__); - ptr__ += IMC::serialize(mnames, ptr__); - ptr__ += IMC::serialize(ecount, ptr__); - ptr__ += IMC::serialize(enames, ptr__); - ptr__ += IMC::serialize(ccount, ptr__); - ptr__ += IMC::serialize(cnames, ptr__); - ptr__ += IMC::serialize(last_error, ptr__); - ptr__ += IMC::serialize(last_error_time, ptr__); + ptr__ += IMC::serialize(type, ptr__); + ptr__ += IMC::serialize(op, ptr__); + ptr__ += IMC::serialize(possimerr, ptr__); + ptr__ += IMC::serialize(converg, ptr__); + ptr__ += IMC::serialize(turbulence, ptr__); + ptr__ += IMC::serialize(possimmon, ptr__); + ptr__ += IMC::serialize(commmon, ptr__); + ptr__ += IMC::serialize(convergmon, ptr__); return ptr__; } uint16_t - EntityMonitoringState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + FormationState::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(mcount, bfr__, size__); - bfr__ += IMC::deserialize(mnames, bfr__, size__); - bfr__ += IMC::deserialize(ecount, bfr__, size__); - bfr__ += IMC::deserialize(enames, bfr__, size__); - bfr__ += IMC::deserialize(ccount, bfr__, size__); - bfr__ += IMC::deserialize(cnames, bfr__, size__); - bfr__ += IMC::deserialize(last_error, bfr__, size__); - bfr__ += IMC::deserialize(last_error_time, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::deserialize(possimerr, bfr__, size__); + bfr__ += IMC::deserialize(converg, bfr__, size__); + bfr__ += IMC::deserialize(turbulence, bfr__, size__); + bfr__ += IMC::deserialize(possimmon, bfr__, size__); + bfr__ += IMC::deserialize(commmon, bfr__, size__); + bfr__ += IMC::deserialize(convergmon, bfr__, size__); return bfr__ - start__; } uint16_t - EntityMonitoringState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + FormationState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(mcount, bfr__, size__); - bfr__ += IMC::reverseDeserialize(mnames, bfr__, size__); - bfr__ += IMC::deserialize(ecount, bfr__, size__); - bfr__ += IMC::reverseDeserialize(enames, bfr__, size__); - bfr__ += IMC::deserialize(ccount, bfr__, size__); - bfr__ += IMC::reverseDeserialize(cnames, bfr__, size__); - bfr__ += IMC::reverseDeserialize(last_error, bfr__, size__); - bfr__ += IMC::reverseDeserialize(last_error_time, bfr__, size__); + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::reverseDeserialize(possimerr, bfr__, size__); + bfr__ += IMC::reverseDeserialize(converg, bfr__, size__); + bfr__ += IMC::reverseDeserialize(turbulence, bfr__, size__); + bfr__ += IMC::deserialize(possimmon, bfr__, size__); + bfr__ += IMC::deserialize(commmon, bfr__, size__); + bfr__ += IMC::deserialize(convergmon, bfr__, size__); return bfr__ - start__; } void - EntityMonitoringState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + FormationState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "mcount", mcount, nindent__); - IMC::toJSON(os__, "mnames", mnames, nindent__); - IMC::toJSON(os__, "ecount", ecount, nindent__); - IMC::toJSON(os__, "enames", enames, nindent__); - IMC::toJSON(os__, "ccount", ccount, nindent__); - IMC::toJSON(os__, "cnames", cnames, nindent__); - IMC::toJSON(os__, "last_error", last_error, nindent__); - IMC::toJSON(os__, "last_error_time", last_error_time, nindent__); + IMC::toJSON(os__, "type", type, nindent__); + IMC::toJSON(os__, "op", op, nindent__); + IMC::toJSON(os__, "possimerr", possimerr, nindent__); + IMC::toJSON(os__, "converg", converg, nindent__); + IMC::toJSON(os__, "turbulence", turbulence, nindent__); + IMC::toJSON(os__, "possimmon", possimmon, nindent__); + IMC::toJSON(os__, "commmon", commmon, nindent__); + IMC::toJSON(os__, "convergmon", convergmon, nindent__); } - OperationalLimits::OperationalLimits(void) + ReportControl::ReportControl(void) { - m_header.mgid = 504; + m_header.mgid = 513; clear(); } void - OperationalLimits::clear(void) + ReportControl::clear(void) { - mask = 0; - max_depth = 0; - min_altitude = 0; - max_altitude = 0; - min_speed = 0; - max_speed = 0; - max_vrate = 0; - lat = 0; - lon = 0; - orientation = 0; - width = 0; - length = 0; + op = 0; + comm_interface = 0; + period = 0; + sys_dst.clear(); } bool - OperationalLimits::fieldsEqual(const Message& msg__) const + ReportControl::fieldsEqual(const Message& msg__) const { - const IMC::OperationalLimits& other__ = static_cast(msg__); - if (mask != other__.mask) return false; - if (max_depth != other__.max_depth) return false; - if (min_altitude != other__.min_altitude) return false; - if (max_altitude != other__.max_altitude) return false; - if (min_speed != other__.min_speed) return false; - if (max_speed != other__.max_speed) return false; - if (max_vrate != other__.max_vrate) return false; - if (lat != other__.lat) return false; - if (lon != other__.lon) return false; - if (orientation != other__.orientation) return false; - if (width != other__.width) return false; - if (length != other__.length) return false; + const IMC::ReportControl& other__ = static_cast(msg__); + if (op != other__.op) return false; + if (comm_interface != other__.comm_interface) return false; + if (period != other__.period) return false; + if (sys_dst != other__.sys_dst) return false; return true; } int - OperationalLimits::validate(void) const + ReportControl::validate(void) const { - if (max_depth < 0) return false; - if (min_altitude < 0) return false; - if (max_altitude < 0) return false; - if (min_speed < 0) return false; - if (max_speed < 0) return false; - if (max_vrate < 0) return false; - if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; - if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; return true; } uint8_t* - OperationalLimits::serializeFields(uint8_t* bfr__) const + ReportControl::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(mask, ptr__); - ptr__ += IMC::serialize(max_depth, ptr__); - ptr__ += IMC::serialize(min_altitude, ptr__); - ptr__ += IMC::serialize(max_altitude, ptr__); - ptr__ += IMC::serialize(min_speed, ptr__); - ptr__ += IMC::serialize(max_speed, ptr__); - ptr__ += IMC::serialize(max_vrate, ptr__); - ptr__ += IMC::serialize(lat, ptr__); - ptr__ += IMC::serialize(lon, ptr__); - ptr__ += IMC::serialize(orientation, ptr__); - ptr__ += IMC::serialize(width, ptr__); - ptr__ += IMC::serialize(length, ptr__); + ptr__ += IMC::serialize(op, ptr__); + ptr__ += IMC::serialize(comm_interface, ptr__); + ptr__ += IMC::serialize(period, ptr__); + ptr__ += IMC::serialize(sys_dst, ptr__); return ptr__; } uint16_t - OperationalLimits::deserializeFields(const uint8_t* bfr__, uint16_t size__) + ReportControl::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(mask, bfr__, size__); - bfr__ += IMC::deserialize(max_depth, bfr__, size__); - bfr__ += IMC::deserialize(min_altitude, bfr__, size__); - bfr__ += IMC::deserialize(max_altitude, bfr__, size__); - bfr__ += IMC::deserialize(min_speed, bfr__, size__); - bfr__ += IMC::deserialize(max_speed, bfr__, size__); - bfr__ += IMC::deserialize(max_vrate, bfr__, size__); - bfr__ += IMC::deserialize(lat, bfr__, size__); - bfr__ += IMC::deserialize(lon, bfr__, size__); - bfr__ += IMC::deserialize(orientation, bfr__, size__); - bfr__ += IMC::deserialize(width, bfr__, size__); - bfr__ += IMC::deserialize(length, bfr__, size__); + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::deserialize(comm_interface, bfr__, size__); + bfr__ += IMC::deserialize(period, bfr__, size__); + bfr__ += IMC::deserialize(sys_dst, bfr__, size__); return bfr__ - start__; } uint16_t - OperationalLimits::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + ReportControl::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(mask, bfr__, size__); - bfr__ += IMC::reverseDeserialize(max_depth, bfr__, size__); - bfr__ += IMC::reverseDeserialize(min_altitude, bfr__, size__); - bfr__ += IMC::reverseDeserialize(max_altitude, bfr__, size__); - bfr__ += IMC::reverseDeserialize(min_speed, bfr__, size__); - bfr__ += IMC::reverseDeserialize(max_speed, bfr__, size__); - bfr__ += IMC::reverseDeserialize(max_vrate, bfr__, size__); - bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); - bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); - bfr__ += IMC::reverseDeserialize(orientation, bfr__, size__); - bfr__ += IMC::reverseDeserialize(width, bfr__, size__); - bfr__ += IMC::reverseDeserialize(length, bfr__, size__); + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::deserialize(comm_interface, bfr__, size__); + bfr__ += IMC::reverseDeserialize(period, bfr__, size__); + bfr__ += IMC::reverseDeserialize(sys_dst, bfr__, size__); return bfr__ - start__; } void - OperationalLimits::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + ReportControl::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "mask", mask, nindent__); - IMC::toJSON(os__, "max_depth", max_depth, nindent__); - IMC::toJSON(os__, "min_altitude", min_altitude, nindent__); - IMC::toJSON(os__, "max_altitude", max_altitude, nindent__); - IMC::toJSON(os__, "min_speed", min_speed, nindent__); - IMC::toJSON(os__, "max_speed", max_speed, nindent__); - IMC::toJSON(os__, "max_vrate", max_vrate, nindent__); - IMC::toJSON(os__, "lat", lat, nindent__); - IMC::toJSON(os__, "lon", lon, nindent__); - IMC::toJSON(os__, "orientation", orientation, nindent__); - IMC::toJSON(os__, "width", width, nindent__); - IMC::toJSON(os__, "length", length, nindent__); + IMC::toJSON(os__, "op", op, nindent__); + IMC::toJSON(os__, "comm_interface", comm_interface, nindent__); + IMC::toJSON(os__, "period", period, nindent__); + IMC::toJSON(os__, "sys_dst", sys_dst, nindent__); } - GetOperationalLimits::GetOperationalLimits(void) + StateReport::StateReport(void) { - m_header.mgid = 505; + m_header.mgid = 514; clear(); } void - GetOperationalLimits::clear(void) + StateReport::clear(void) + { + stime = 0; + latitude = 0; + longitude = 0; + altitude = 0; + depth = 0; + heading = 0; + speed = 0; + fuel = 0; + exec_state = 0; + plan_checksum = 0; + } + + bool + StateReport::fieldsEqual(const Message& msg__) const { + const IMC::StateReport& other__ = static_cast(msg__); + if (stime != other__.stime) return false; + if (latitude != other__.latitude) return false; + if (longitude != other__.longitude) return false; + if (altitude != other__.altitude) return false; + if (depth != other__.depth) return false; + if (heading != other__.heading) return false; + if (speed != other__.speed) return false; + if (fuel != other__.fuel) return false; + if (exec_state != other__.exec_state) return false; + if (plan_checksum != other__.plan_checksum) return false; + return true; } int - GetOperationalLimits::validate(void) const + StateReport::validate(void) const { return true; } uint8_t* - GetOperationalLimits::serializeFields(uint8_t* bfr__) const + StateReport::serializeFields(uint8_t* bfr__) const { - return bfr__; + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(stime, ptr__); + ptr__ += IMC::serialize(latitude, ptr__); + ptr__ += IMC::serialize(longitude, ptr__); + ptr__ += IMC::serialize(altitude, ptr__); + ptr__ += IMC::serialize(depth, ptr__); + ptr__ += IMC::serialize(heading, ptr__); + ptr__ += IMC::serialize(speed, ptr__); + ptr__ += IMC::serialize(fuel, ptr__); + ptr__ += IMC::serialize(exec_state, ptr__); + ptr__ += IMC::serialize(plan_checksum, ptr__); + return ptr__; } uint16_t - GetOperationalLimits::deserializeFields(const uint8_t* bfr__, uint16_t size__) + StateReport::deserializeFields(const uint8_t* bfr__, uint16_t size__) { - (void)bfr__; - (void)size__; - return 0; + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(stime, bfr__, size__); + bfr__ += IMC::deserialize(latitude, bfr__, size__); + bfr__ += IMC::deserialize(longitude, bfr__, size__); + bfr__ += IMC::deserialize(altitude, bfr__, size__); + bfr__ += IMC::deserialize(depth, bfr__, size__); + bfr__ += IMC::deserialize(heading, bfr__, size__); + bfr__ += IMC::deserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(fuel, bfr__, size__); + bfr__ += IMC::deserialize(exec_state, bfr__, size__); + bfr__ += IMC::deserialize(plan_checksum, bfr__, size__); + return bfr__ - start__; } uint16_t - GetOperationalLimits::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + StateReport::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { - (void)bfr__; - (void)size__; - return 0; + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(stime, bfr__, size__); + bfr__ += IMC::reverseDeserialize(latitude, bfr__, size__); + bfr__ += IMC::reverseDeserialize(longitude, bfr__, size__); + bfr__ += IMC::reverseDeserialize(altitude, bfr__, size__); + bfr__ += IMC::reverseDeserialize(depth, bfr__, size__); + bfr__ += IMC::reverseDeserialize(heading, bfr__, size__); + bfr__ += IMC::reverseDeserialize(speed, bfr__, size__); + bfr__ += IMC::deserialize(fuel, bfr__, size__); + bfr__ += IMC::deserialize(exec_state, bfr__, size__); + bfr__ += IMC::reverseDeserialize(plan_checksum, bfr__, size__); + return bfr__ - start__; + } + + void + StateReport::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "stime", stime, nindent__); + IMC::toJSON(os__, "latitude", latitude, nindent__); + IMC::toJSON(os__, "longitude", longitude, nindent__); + IMC::toJSON(os__, "altitude", altitude, nindent__); + IMC::toJSON(os__, "depth", depth, nindent__); + IMC::toJSON(os__, "heading", heading, nindent__); + IMC::toJSON(os__, "speed", speed, nindent__); + IMC::toJSON(os__, "fuel", fuel, nindent__); + IMC::toJSON(os__, "exec_state", exec_state, nindent__); + IMC::toJSON(os__, "plan_checksum", plan_checksum, nindent__); } - Calibration::Calibration(void) + TransmissionRequest::TransmissionRequest(void) { - m_header.mgid = 506; + m_header.mgid = 515; clear(); + msg_data.setParent(this); } void - Calibration::clear(void) + TransmissionRequest::clear(void) { - duration = 0; + req_id = 0; + comm_mean = 0; + destination.clear(); + deadline = 0; + range = 0; + data_mode = 0; + msg_data.clear(); + txt_data.clear(); + raw_data.clear(); } bool - Calibration::fieldsEqual(const Message& msg__) const + TransmissionRequest::fieldsEqual(const Message& msg__) const { - const IMC::Calibration& other__ = static_cast(msg__); - if (duration != other__.duration) return false; + const IMC::TransmissionRequest& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (comm_mean != other__.comm_mean) return false; + if (destination != other__.destination) return false; + if (deadline != other__.deadline) return false; + if (range != other__.range) return false; + if (data_mode != other__.data_mode) return false; + if (msg_data != other__.msg_data) return false; + if (txt_data != other__.txt_data) return false; + if (raw_data != other__.raw_data) return false; return true; } int - Calibration::validate(void) const + TransmissionRequest::validate(void) const { return true; } uint8_t* - Calibration::serializeFields(uint8_t* bfr__) const + TransmissionRequest::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(duration, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(comm_mean, ptr__); + ptr__ += IMC::serialize(destination, ptr__); + ptr__ += IMC::serialize(deadline, ptr__); + ptr__ += IMC::serialize(range, ptr__); + ptr__ += IMC::serialize(data_mode, ptr__); + ptr__ += msg_data.serialize(ptr__); + ptr__ += IMC::serialize(txt_data, ptr__); + ptr__ += IMC::serialize(raw_data, ptr__); return ptr__; } uint16_t - Calibration::deserializeFields(const uint8_t* bfr__, uint16_t size__) + TransmissionRequest::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(duration, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(comm_mean, bfr__, size__); + bfr__ += IMC::deserialize(destination, bfr__, size__); + bfr__ += IMC::deserialize(deadline, bfr__, size__); + bfr__ += IMC::deserialize(range, bfr__, size__); + bfr__ += IMC::deserialize(data_mode, bfr__, size__); + bfr__ += msg_data.deserialize(bfr__, size__); + bfr__ += IMC::deserialize(txt_data, bfr__, size__); + bfr__ += IMC::deserialize(raw_data, bfr__, size__); return bfr__ - start__; } uint16_t - Calibration::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + TransmissionRequest::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::reverseDeserialize(duration, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(comm_mean, bfr__, size__); + bfr__ += IMC::reverseDeserialize(destination, bfr__, size__); + bfr__ += IMC::reverseDeserialize(deadline, bfr__, size__); + bfr__ += IMC::reverseDeserialize(range, bfr__, size__); + bfr__ += IMC::deserialize(data_mode, bfr__, size__); + bfr__ += msg_data.reverseDeserialize(bfr__, size__); + bfr__ += IMC::reverseDeserialize(txt_data, bfr__, size__); + bfr__ += IMC::reverseDeserialize(raw_data, bfr__, size__); return bfr__ - start__; } void - Calibration::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + TransmissionRequest::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "duration", duration, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "comm_mean", comm_mean, nindent__); + IMC::toJSON(os__, "destination", destination, nindent__); + IMC::toJSON(os__, "deadline", deadline, nindent__); + IMC::toJSON(os__, "range", range, nindent__); + IMC::toJSON(os__, "data_mode", data_mode, nindent__); + msg_data.toJSON(os__, "msg_data", nindent__); + IMC::toJSON(os__, "txt_data", txt_data, nindent__); + IMC::toJSON(os__, "raw_data", raw_data, nindent__); } - ControlLoops::ControlLoops(void) + void + TransmissionRequest::setTimeStampNested(double value__) { - m_header.mgid = 507; + if (!msg_data.isNull()) + { + msg_data.get()->setTimeStamp(value__); + } + } + + void + TransmissionRequest::setSourceNested(uint16_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setSource(value__); + } + } + + void + TransmissionRequest::setSourceEntityNested(uint8_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setSourceEntity(value__); + } + } + + void + TransmissionRequest::setDestinationNested(uint16_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setDestination(value__); + } + } + + void + TransmissionRequest::setDestinationEntityNested(uint8_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setDestinationEntity(value__); + } + } + + TransmissionStatus::TransmissionStatus(void) + { + m_header.mgid = 516; clear(); } void - ControlLoops::clear(void) + TransmissionStatus::clear(void) { - enable = 0; - mask = 0; - scope_ref = 0; + req_id = 0; + status = 0; + range = 0; + info.clear(); } bool - ControlLoops::fieldsEqual(const Message& msg__) const + TransmissionStatus::fieldsEqual(const Message& msg__) const { - const IMC::ControlLoops& other__ = static_cast(msg__); - if (enable != other__.enable) return false; - if (mask != other__.mask) return false; - if (scope_ref != other__.scope_ref) return false; + const IMC::TransmissionStatus& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (status != other__.status) return false; + if (range != other__.range) return false; + if (info != other__.info) return false; return true; } int - ControlLoops::validate(void) const + TransmissionStatus::validate(void) const { return true; } uint8_t* - ControlLoops::serializeFields(uint8_t* bfr__) const + TransmissionStatus::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(enable, ptr__); - ptr__ += IMC::serialize(mask, ptr__); - ptr__ += IMC::serialize(scope_ref, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(status, ptr__); + ptr__ += IMC::serialize(range, ptr__); + ptr__ += IMC::serialize(info, ptr__); return ptr__; } uint16_t - ControlLoops::deserializeFields(const uint8_t* bfr__, uint16_t size__) + TransmissionStatus::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(enable, bfr__, size__); - bfr__ += IMC::deserialize(mask, bfr__, size__); - bfr__ += IMC::deserialize(scope_ref, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::deserialize(range, bfr__, size__); + bfr__ += IMC::deserialize(info, bfr__, size__); return bfr__ - start__; } uint16_t - ControlLoops::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + TransmissionStatus::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(enable, bfr__, size__); - bfr__ += IMC::reverseDeserialize(mask, bfr__, size__); - bfr__ += IMC::reverseDeserialize(scope_ref, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::reverseDeserialize(range, bfr__, size__); + bfr__ += IMC::reverseDeserialize(info, bfr__, size__); return bfr__ - start__; } void - ControlLoops::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + TransmissionStatus::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "enable", enable, nindent__); - IMC::toJSON(os__, "mask", mask, nindent__); - IMC::toJSON(os__, "scope_ref", scope_ref, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "status", status, nindent__); + IMC::toJSON(os__, "range", range, nindent__); + IMC::toJSON(os__, "info", info, nindent__); } - VehicleMedium::VehicleMedium(void) + SmsRequest::SmsRequest(void) { - m_header.mgid = 508; + m_header.mgid = 517; clear(); } void - VehicleMedium::clear(void) + SmsRequest::clear(void) { - medium = 0; + req_id = 0; + destination.clear(); + timeout = 0; + sms_text.clear(); } bool - VehicleMedium::fieldsEqual(const Message& msg__) const + SmsRequest::fieldsEqual(const Message& msg__) const { - const IMC::VehicleMedium& other__ = static_cast(msg__); - if (medium != other__.medium) return false; + const IMC::SmsRequest& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (destination != other__.destination) return false; + if (timeout != other__.timeout) return false; + if (sms_text != other__.sms_text) return false; return true; } int - VehicleMedium::validate(void) const + SmsRequest::validate(void) const { return true; } uint8_t* - VehicleMedium::serializeFields(uint8_t* bfr__) const + SmsRequest::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(medium, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(destination, ptr__); + ptr__ += IMC::serialize(timeout, ptr__); + ptr__ += IMC::serialize(sms_text, ptr__); return ptr__; } uint16_t - VehicleMedium::deserializeFields(const uint8_t* bfr__, uint16_t size__) + SmsRequest::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(medium, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(destination, bfr__, size__); + bfr__ += IMC::deserialize(timeout, bfr__, size__); + bfr__ += IMC::deserialize(sms_text, bfr__, size__); return bfr__ - start__; } uint16_t - VehicleMedium::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + SmsRequest::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(medium, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::reverseDeserialize(destination, bfr__, size__); + bfr__ += IMC::reverseDeserialize(timeout, bfr__, size__); + bfr__ += IMC::reverseDeserialize(sms_text, bfr__, size__); return bfr__ - start__; } void - VehicleMedium::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + SmsRequest::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "medium", medium, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "destination", destination, nindent__); + IMC::toJSON(os__, "timeout", timeout, nindent__); + IMC::toJSON(os__, "sms_text", sms_text, nindent__); } - Collision::Collision(void) + SmsStatus::SmsStatus(void) { - m_header.mgid = 509; + m_header.mgid = 518; clear(); } void - Collision::clear(void) + SmsStatus::clear(void) { - value = 0; - type = 0; + req_id = 0; + status = 0; + info.clear(); } bool - Collision::fieldsEqual(const Message& msg__) const + SmsStatus::fieldsEqual(const Message& msg__) const { - const IMC::Collision& other__ = static_cast(msg__); - if (value != other__.value) return false; - if (type != other__.type) return false; + const IMC::SmsStatus& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (status != other__.status) return false; + if (info != other__.info) return false; return true; } int - Collision::validate(void) const + SmsStatus::validate(void) const { return true; } uint8_t* - Collision::serializeFields(uint8_t* bfr__) const + SmsStatus::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(value, ptr__); - ptr__ += IMC::serialize(type, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(status, ptr__); + ptr__ += IMC::serialize(info, ptr__); return ptr__; } uint16_t - Collision::deserializeFields(const uint8_t* bfr__, uint16_t size__) + SmsStatus::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(value, bfr__, size__); - bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::deserialize(info, bfr__, size__); return bfr__ - start__; } uint16_t - Collision::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + SmsStatus::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::reverseDeserialize(value, bfr__, size__); - bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::reverseDeserialize(info, bfr__, size__); return bfr__ - start__; } - fp64_t - Collision::getValueFP(void) const - { - return static_cast(value); - } - - void - Collision::setValueFP(fp64_t val) - { - value = static_cast(val); - } - void - Collision::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + SmsStatus::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "value", value, nindent__); - IMC::toJSON(os__, "type", type, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "status", status, nindent__); + IMC::toJSON(os__, "info", info, nindent__); } - FormState::FormState(void) + VtolState::VtolState(void) { - m_header.mgid = 510; + m_header.mgid = 519; clear(); } void - FormState::clear(void) + VtolState::clear(void) { - possimerr = 0; - converg = 0; - turbulence = 0; - possimmon = 0; - commmon = 0; - convergmon = 0; + state = 0; } bool - FormState::fieldsEqual(const Message& msg__) const + VtolState::fieldsEqual(const Message& msg__) const { - const IMC::FormState& other__ = static_cast(msg__); - if (possimerr != other__.possimerr) return false; - if (converg != other__.converg) return false; - if (turbulence != other__.turbulence) return false; - if (possimmon != other__.possimmon) return false; - if (commmon != other__.commmon) return false; - if (convergmon != other__.convergmon) return false; + const IMC::VtolState& other__ = static_cast(msg__); + if (state != other__.state) return false; return true; } int - FormState::validate(void) const + VtolState::validate(void) const { return true; } uint8_t* - FormState::serializeFields(uint8_t* bfr__) const + VtolState::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(possimerr, ptr__); - ptr__ += IMC::serialize(converg, ptr__); - ptr__ += IMC::serialize(turbulence, ptr__); - ptr__ += IMC::serialize(possimmon, ptr__); - ptr__ += IMC::serialize(commmon, ptr__); - ptr__ += IMC::serialize(convergmon, ptr__); + ptr__ += IMC::serialize(state, ptr__); return ptr__; } uint16_t - FormState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + VtolState::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(possimerr, bfr__, size__); - bfr__ += IMC::deserialize(converg, bfr__, size__); - bfr__ += IMC::deserialize(turbulence, bfr__, size__); - bfr__ += IMC::deserialize(possimmon, bfr__, size__); - bfr__ += IMC::deserialize(commmon, bfr__, size__); - bfr__ += IMC::deserialize(convergmon, bfr__, size__); + bfr__ += IMC::deserialize(state, bfr__, size__); return bfr__ - start__; } uint16_t - FormState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + VtolState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::reverseDeserialize(possimerr, bfr__, size__); - bfr__ += IMC::reverseDeserialize(converg, bfr__, size__); - bfr__ += IMC::reverseDeserialize(turbulence, bfr__, size__); - bfr__ += IMC::deserialize(possimmon, bfr__, size__); - bfr__ += IMC::deserialize(commmon, bfr__, size__); - bfr__ += IMC::deserialize(convergmon, bfr__, size__); + bfr__ += IMC::deserialize(state, bfr__, size__); return bfr__ - start__; } void - FormState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + VtolState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "possimerr", possimerr, nindent__); - IMC::toJSON(os__, "converg", converg, nindent__); - IMC::toJSON(os__, "turbulence", turbulence, nindent__); - IMC::toJSON(os__, "possimmon", possimmon, nindent__); - IMC::toJSON(os__, "commmon", commmon, nindent__); - IMC::toJSON(os__, "convergmon", convergmon, nindent__); + IMC::toJSON(os__, "state", state, nindent__); } - AutopilotMode::AutopilotMode(void) + ArmingState::ArmingState(void) { - m_header.mgid = 511; + m_header.mgid = 520; clear(); } void - AutopilotMode::clear(void) + ArmingState::clear(void) { - autonomy = 0; - mode.clear(); + state = 0; } bool - AutopilotMode::fieldsEqual(const Message& msg__) const + ArmingState::fieldsEqual(const Message& msg__) const { - const IMC::AutopilotMode& other__ = static_cast(msg__); - if (autonomy != other__.autonomy) return false; - if (mode != other__.mode) return false; + const IMC::ArmingState& other__ = static_cast(msg__); + if (state != other__.state) return false; return true; } int - AutopilotMode::validate(void) const + ArmingState::validate(void) const { return true; } uint8_t* - AutopilotMode::serializeFields(uint8_t* bfr__) const + ArmingState::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(autonomy, ptr__); - ptr__ += IMC::serialize(mode, ptr__); + ptr__ += IMC::serialize(state, ptr__); return ptr__; } uint16_t - AutopilotMode::deserializeFields(const uint8_t* bfr__, uint16_t size__) + ArmingState::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(autonomy, bfr__, size__); - bfr__ += IMC::deserialize(mode, bfr__, size__); + bfr__ += IMC::deserialize(state, bfr__, size__); return bfr__ - start__; } uint16_t - AutopilotMode::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + ArmingState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(autonomy, bfr__, size__); - bfr__ += IMC::reverseDeserialize(mode, bfr__, size__); + bfr__ += IMC::deserialize(state, bfr__, size__); return bfr__ - start__; } void - AutopilotMode::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + ArmingState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "autonomy", autonomy, nindent__); - IMC::toJSON(os__, "mode", mode, nindent__); + IMC::toJSON(os__, "state", state, nindent__); } - FormationState::FormationState(void) + TCPRequest::TCPRequest(void) { - m_header.mgid = 512; + m_header.mgid = 521; clear(); + msg_data.setParent(this); } void - FormationState::clear(void) + TCPRequest::clear(void) { - type = 0; - op = 0; - possimerr = 0; - converg = 0; - turbulence = 0; - possimmon = 0; - commmon = 0; - convergmon = 0; + req_id = 0; + destination.clear(); + timeout = 0; + msg_data.clear(); } bool - FormationState::fieldsEqual(const Message& msg__) const + TCPRequest::fieldsEqual(const Message& msg__) const { - const IMC::FormationState& other__ = static_cast(msg__); - if (type != other__.type) return false; - if (op != other__.op) return false; - if (possimerr != other__.possimerr) return false; - if (converg != other__.converg) return false; - if (turbulence != other__.turbulence) return false; - if (possimmon != other__.possimmon) return false; - if (commmon != other__.commmon) return false; - if (convergmon != other__.convergmon) return false; + const IMC::TCPRequest& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (destination != other__.destination) return false; + if (timeout != other__.timeout) return false; + if (msg_data != other__.msg_data) return false; return true; } int - FormationState::validate(void) const + TCPRequest::validate(void) const { return true; } uint8_t* - FormationState::serializeFields(uint8_t* bfr__) const + TCPRequest::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(type, ptr__); - ptr__ += IMC::serialize(op, ptr__); - ptr__ += IMC::serialize(possimerr, ptr__); - ptr__ += IMC::serialize(converg, ptr__); - ptr__ += IMC::serialize(turbulence, ptr__); - ptr__ += IMC::serialize(possimmon, ptr__); - ptr__ += IMC::serialize(commmon, ptr__); - ptr__ += IMC::serialize(convergmon, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(destination, ptr__); + ptr__ += IMC::serialize(timeout, ptr__); + ptr__ += msg_data.serialize(ptr__); return ptr__; } uint16_t - FormationState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + TCPRequest::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(type, bfr__, size__); - bfr__ += IMC::deserialize(op, bfr__, size__); - bfr__ += IMC::deserialize(possimerr, bfr__, size__); - bfr__ += IMC::deserialize(converg, bfr__, size__); - bfr__ += IMC::deserialize(turbulence, bfr__, size__); - bfr__ += IMC::deserialize(possimmon, bfr__, size__); - bfr__ += IMC::deserialize(commmon, bfr__, size__); - bfr__ += IMC::deserialize(convergmon, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(destination, bfr__, size__); + bfr__ += IMC::deserialize(timeout, bfr__, size__); + bfr__ += msg_data.deserialize(bfr__, size__); return bfr__ - start__; } uint16_t - FormationState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + TCPRequest::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(type, bfr__, size__); - bfr__ += IMC::deserialize(op, bfr__, size__); - bfr__ += IMC::reverseDeserialize(possimerr, bfr__, size__); - bfr__ += IMC::reverseDeserialize(converg, bfr__, size__); - bfr__ += IMC::reverseDeserialize(turbulence, bfr__, size__); - bfr__ += IMC::deserialize(possimmon, bfr__, size__); - bfr__ += IMC::deserialize(commmon, bfr__, size__); - bfr__ += IMC::deserialize(convergmon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::reverseDeserialize(destination, bfr__, size__); + bfr__ += IMC::reverseDeserialize(timeout, bfr__, size__); + bfr__ += msg_data.reverseDeserialize(bfr__, size__); return bfr__ - start__; } void - FormationState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + TCPRequest::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "type", type, nindent__); - IMC::toJSON(os__, "op", op, nindent__); - IMC::toJSON(os__, "possimerr", possimerr, nindent__); - IMC::toJSON(os__, "converg", converg, nindent__); - IMC::toJSON(os__, "turbulence", turbulence, nindent__); - IMC::toJSON(os__, "possimmon", possimmon, nindent__); - IMC::toJSON(os__, "commmon", commmon, nindent__); - IMC::toJSON(os__, "convergmon", convergmon, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "destination", destination, nindent__); + IMC::toJSON(os__, "timeout", timeout, nindent__); + msg_data.toJSON(os__, "msg_data", nindent__); } - ReportControl::ReportControl(void) + void + TCPRequest::setTimeStampNested(double value__) { - m_header.mgid = 513; + if (!msg_data.isNull()) + { + msg_data.get()->setTimeStamp(value__); + } + } + + void + TCPRequest::setSourceNested(uint16_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setSource(value__); + } + } + + void + TCPRequest::setSourceEntityNested(uint8_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setSourceEntity(value__); + } + } + + void + TCPRequest::setDestinationNested(uint16_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setDestination(value__); + } + } + + void + TCPRequest::setDestinationEntityNested(uint8_t value__) + { + if (!msg_data.isNull()) + { + msg_data.get()->setDestinationEntity(value__); + } + } + + TCPStatus::TCPStatus(void) + { + m_header.mgid = 522; clear(); } void - ReportControl::clear(void) + TCPStatus::clear(void) { - op = 0; - comm_interface = 0; - period = 0; - sys_dst.clear(); + req_id = 0; + status = 0; + info.clear(); } bool - ReportControl::fieldsEqual(const Message& msg__) const + TCPStatus::fieldsEqual(const Message& msg__) const { - const IMC::ReportControl& other__ = static_cast(msg__); - if (op != other__.op) return false; - if (comm_interface != other__.comm_interface) return false; - if (period != other__.period) return false; - if (sys_dst != other__.sys_dst) return false; + const IMC::TCPStatus& other__ = static_cast(msg__); + if (req_id != other__.req_id) return false; + if (status != other__.status) return false; + if (info != other__.info) return false; return true; } int - ReportControl::validate(void) const + TCPStatus::validate(void) const { return true; } uint8_t* - ReportControl::serializeFields(uint8_t* bfr__) const + TCPStatus::serializeFields(uint8_t* bfr__) const { uint8_t* ptr__ = bfr__; - ptr__ += IMC::serialize(op, ptr__); - ptr__ += IMC::serialize(comm_interface, ptr__); - ptr__ += IMC::serialize(period, ptr__); - ptr__ += IMC::serialize(sys_dst, ptr__); + ptr__ += IMC::serialize(req_id, ptr__); + ptr__ += IMC::serialize(status, ptr__); + ptr__ += IMC::serialize(info, ptr__); return ptr__; } uint16_t - ReportControl::deserializeFields(const uint8_t* bfr__, uint16_t size__) + TCPStatus::deserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(op, bfr__, size__); - bfr__ += IMC::deserialize(comm_interface, bfr__, size__); - bfr__ += IMC::deserialize(period, bfr__, size__); - bfr__ += IMC::deserialize(sys_dst, bfr__, size__); + bfr__ += IMC::deserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::deserialize(info, bfr__, size__); return bfr__ - start__; } uint16_t - ReportControl::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + TCPStatus::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; - bfr__ += IMC::deserialize(op, bfr__, size__); - bfr__ += IMC::deserialize(comm_interface, bfr__, size__); - bfr__ += IMC::reverseDeserialize(period, bfr__, size__); - bfr__ += IMC::reverseDeserialize(sys_dst, bfr__, size__); + bfr__ += IMC::reverseDeserialize(req_id, bfr__, size__); + bfr__ += IMC::deserialize(status, bfr__, size__); + bfr__ += IMC::reverseDeserialize(info, bfr__, size__); return bfr__ - start__; } void - ReportControl::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + TCPStatus::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { - IMC::toJSON(os__, "op", op, nindent__); - IMC::toJSON(os__, "comm_interface", comm_interface, nindent__); - IMC::toJSON(os__, "period", period, nindent__); - IMC::toJSON(os__, "sys_dst", sys_dst, nindent__); + IMC::toJSON(os__, "req_id", req_id, nindent__); + IMC::toJSON(os__, "status", status, nindent__); + IMC::toJSON(os__, "info", info, nindent__); } Abort::Abort(void) @@ -22521,33 +24433,101 @@ namespace DUNE } uint16_t - UamRxRange::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + UamRxRange::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(seq, bfr__, size__); + bfr__ += IMC::reverseDeserialize(sys, bfr__, size__); + bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + return bfr__ - start__; + } + + fp64_t + UamRxRange::getValueFP(void) const + { + return static_cast(value); + } + + void + UamRxRange::setValueFP(fp64_t val) + { + value = static_cast(val); + } + + void + UamRxRange::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "seq", seq, nindent__); + IMC::toJSON(os__, "sys", sys, nindent__); + IMC::toJSON(os__, "value", value, nindent__); + } + + UamTxRange::UamTxRange(void) + { + m_header.mgid = 818; + clear(); + } + + void + UamTxRange::clear(void) + { + seq = 0; + sys_dst.clear(); + timeout = 0; + } + + bool + UamTxRange::fieldsEqual(const Message& msg__) const + { + const IMC::UamTxRange& other__ = static_cast(msg__); + if (seq != other__.seq) return false; + if (sys_dst != other__.sys_dst) return false; + if (timeout != other__.timeout) return false; + return true; + } + + int + UamTxRange::validate(void) const + { + return true; + } + + uint8_t* + UamTxRange::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(seq, ptr__); + ptr__ += IMC::serialize(sys_dst, ptr__); + ptr__ += IMC::serialize(timeout, ptr__); + return ptr__; + } + + uint16_t + UamTxRange::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(seq, bfr__, size__); + bfr__ += IMC::deserialize(sys_dst, bfr__, size__); + bfr__ += IMC::deserialize(timeout, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + UamTxRange::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) { const uint8_t* start__ = bfr__; bfr__ += IMC::reverseDeserialize(seq, bfr__, size__); - bfr__ += IMC::reverseDeserialize(sys, bfr__, size__); - bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + bfr__ += IMC::reverseDeserialize(sys_dst, bfr__, size__); + bfr__ += IMC::reverseDeserialize(timeout, bfr__, size__); return bfr__ - start__; } - fp64_t - UamRxRange::getValueFP(void) const - { - return static_cast(value); - } - - void - UamRxRange::setValueFP(fp64_t val) - { - value = static_cast(val); - } - void - UamRxRange::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + UamTxRange::fieldsToJSON(std::ostream& os__, unsigned nindent__) const { IMC::toJSON(os__, "seq", seq, nindent__); - IMC::toJSON(os__, "sys", sys, nindent__); - IMC::toJSON(os__, "value", value, nindent__); + IMC::toJSON(os__, "sys_dst", sys_dst, nindent__); + IMC::toJSON(os__, "timeout", timeout, nindent__); } FormCtrlParam::FormCtrlParam(void) @@ -22920,50 +24900,417 @@ namespace DUNE } void - FormationEvaluation::setTimeStampNested(double value__) + FormationEvaluation::setTimeStampNested(double value__) + { + if (!controlparams.isNull()) + { + controlparams.get()->setTimeStamp(value__); + } + } + + void + FormationEvaluation::setSourceNested(uint16_t value__) + { + if (!controlparams.isNull()) + { + controlparams.get()->setSource(value__); + } + } + + void + FormationEvaluation::setSourceEntityNested(uint8_t value__) + { + if (!controlparams.isNull()) + { + controlparams.get()->setSourceEntity(value__); + } + } + + void + FormationEvaluation::setDestinationNested(uint16_t value__) + { + if (!controlparams.isNull()) + { + controlparams.get()->setDestination(value__); + } + } + + void + FormationEvaluation::setDestinationEntityNested(uint8_t value__) + { + if (!controlparams.isNull()) + { + controlparams.get()->setDestinationEntity(value__); + } + } + + SoiWaypoint::SoiWaypoint(void) + { + m_header.mgid = 850; + clear(); + } + + void + SoiWaypoint::clear(void) + { + lat = 0; + lon = 0; + eta = 0; + duration = 0; + } + + bool + SoiWaypoint::fieldsEqual(const Message& msg__) const + { + const IMC::SoiWaypoint& other__ = static_cast(msg__); + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (eta != other__.eta) return false; + if (duration != other__.duration) return false; + return true; + } + + int + SoiWaypoint::validate(void) const + { + return true; + } + + uint8_t* + SoiWaypoint::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(eta, ptr__); + ptr__ += IMC::serialize(duration, ptr__); + return ptr__; + } + + uint16_t + SoiWaypoint::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(eta, bfr__, size__); + bfr__ += IMC::deserialize(duration, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + SoiWaypoint::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(eta, bfr__, size__); + bfr__ += IMC::reverseDeserialize(duration, bfr__, size__); + return bfr__ - start__; + } + + void + SoiWaypoint::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + IMC::toJSON(os__, "eta", eta, nindent__); + IMC::toJSON(os__, "duration", duration, nindent__); + } + + SoiPlan::SoiPlan(void) + { + m_header.mgid = 851; + clear(); + waypoints.setParent(this); + } + + void + SoiPlan::clear(void) + { + plan_id = 0; + waypoints.clear(); + } + + bool + SoiPlan::fieldsEqual(const Message& msg__) const + { + const IMC::SoiPlan& other__ = static_cast(msg__); + if (plan_id != other__.plan_id) return false; + if (waypoints != other__.waypoints) return false; + return true; + } + + int + SoiPlan::validate(void) const + { + return true; + } + + uint8_t* + SoiPlan::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(plan_id, ptr__); + ptr__ += waypoints.serialize(ptr__); + return ptr__; + } + + uint16_t + SoiPlan::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(plan_id, bfr__, size__); + bfr__ += waypoints.deserialize(bfr__, size__); + return bfr__ - start__; + } + + uint16_t + SoiPlan::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(plan_id, bfr__, size__); + bfr__ += waypoints.reverseDeserialize(bfr__, size__); + return bfr__ - start__; + } + + void + SoiPlan::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "plan_id", plan_id, nindent__); + waypoints.toJSON(os__, "waypoints", nindent__); + } + + void + SoiPlan::setTimeStampNested(double value__) + { + waypoints.setTimeStamp(value__); + } + + void + SoiPlan::setSourceNested(uint16_t value__) + { + waypoints.setSource(value__); + } + + void + SoiPlan::setSourceEntityNested(uint8_t value__) + { + waypoints.setSourceEntity(value__); + } + + void + SoiPlan::setDestinationNested(uint16_t value__) + { + waypoints.setDestination(value__); + } + + void + SoiPlan::setDestinationEntityNested(uint8_t value__) + { + waypoints.setDestinationEntity(value__); + } + + SoiCommand::SoiCommand(void) + { + m_header.mgid = 852; + clear(); + plan.setParent(this); + } + + void + SoiCommand::clear(void) + { + type = 0; + command = 0; + settings.clear(); + plan.clear(); + info.clear(); + } + + bool + SoiCommand::fieldsEqual(const Message& msg__) const + { + const IMC::SoiCommand& other__ = static_cast(msg__); + if (type != other__.type) return false; + if (command != other__.command) return false; + if (settings != other__.settings) return false; + if (plan != other__.plan) return false; + if (info != other__.info) return false; + return true; + } + + int + SoiCommand::validate(void) const + { + return true; + } + + uint8_t* + SoiCommand::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(type, ptr__); + ptr__ += IMC::serialize(command, ptr__); + ptr__ += IMC::serialize(settings, ptr__); + ptr__ += plan.serialize(ptr__); + ptr__ += IMC::serialize(info, ptr__); + return ptr__; + } + + uint16_t + SoiCommand::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(command, bfr__, size__); + bfr__ += IMC::deserialize(settings, bfr__, size__); + bfr__ += plan.deserialize(bfr__, size__); + bfr__ += IMC::deserialize(info, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + SoiCommand::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(type, bfr__, size__); + bfr__ += IMC::deserialize(command, bfr__, size__); + bfr__ += IMC::reverseDeserialize(settings, bfr__, size__); + bfr__ += plan.reverseDeserialize(bfr__, size__); + bfr__ += IMC::reverseDeserialize(info, bfr__, size__); + return bfr__ - start__; + } + + void + SoiCommand::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "type", type, nindent__); + IMC::toJSON(os__, "command", command, nindent__); + IMC::toJSON(os__, "settings", settings, nindent__); + plan.toJSON(os__, "plan", nindent__); + IMC::toJSON(os__, "info", info, nindent__); + } + + void + SoiCommand::setTimeStampNested(double value__) { - if (!controlparams.isNull()) + if (!plan.isNull()) { - controlparams.get()->setTimeStamp(value__); + plan.get()->setTimeStamp(value__); } } void - FormationEvaluation::setSourceNested(uint16_t value__) + SoiCommand::setSourceNested(uint16_t value__) { - if (!controlparams.isNull()) + if (!plan.isNull()) { - controlparams.get()->setSource(value__); + plan.get()->setSource(value__); } } void - FormationEvaluation::setSourceEntityNested(uint8_t value__) + SoiCommand::setSourceEntityNested(uint8_t value__) { - if (!controlparams.isNull()) + if (!plan.isNull()) { - controlparams.get()->setSourceEntity(value__); + plan.get()->setSourceEntity(value__); } } void - FormationEvaluation::setDestinationNested(uint16_t value__) + SoiCommand::setDestinationNested(uint16_t value__) { - if (!controlparams.isNull()) + if (!plan.isNull()) { - controlparams.get()->setDestination(value__); + plan.get()->setDestination(value__); } } void - FormationEvaluation::setDestinationEntityNested(uint8_t value__) + SoiCommand::setDestinationEntityNested(uint8_t value__) { - if (!controlparams.isNull()) + if (!plan.isNull()) { - controlparams.get()->setDestinationEntity(value__); + plan.get()->setDestinationEntity(value__); } } + SoiState::SoiState(void) + { + m_header.mgid = 853; + clear(); + } + + void + SoiState::clear(void) + { + state = 0; + plan_id = 0; + wpt_id = 0; + settings_chk = 0; + } + + bool + SoiState::fieldsEqual(const Message& msg__) const + { + const IMC::SoiState& other__ = static_cast(msg__); + if (state != other__.state) return false; + if (plan_id != other__.plan_id) return false; + if (wpt_id != other__.wpt_id) return false; + if (settings_chk != other__.settings_chk) return false; + return true; + } + + int + SoiState::validate(void) const + { + return true; + } + + uint8_t* + SoiState::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(state, ptr__); + ptr__ += IMC::serialize(plan_id, ptr__); + ptr__ += IMC::serialize(wpt_id, ptr__); + ptr__ += IMC::serialize(settings_chk, ptr__); + return ptr__; + } + + uint16_t + SoiState::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(state, bfr__, size__); + bfr__ += IMC::deserialize(plan_id, bfr__, size__); + bfr__ += IMC::deserialize(wpt_id, bfr__, size__); + bfr__ += IMC::deserialize(settings_chk, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + SoiState::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(state, bfr__, size__); + bfr__ += IMC::reverseDeserialize(plan_id, bfr__, size__); + bfr__ += IMC::deserialize(wpt_id, bfr__, size__); + bfr__ += IMC::reverseDeserialize(settings_chk, bfr__, size__); + return bfr__ - start__; + } + + void + SoiState::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "state", state, nindent__); + IMC::toJSON(os__, "plan_id", plan_id, nindent__); + IMC::toJSON(os__, "wpt_id", wpt_id, nindent__); + IMC::toJSON(os__, "settings_chk", settings_chk, nindent__); + } + MessagePart::MessagePart(void) { m_header.mgid = 877; @@ -24608,5 +26955,307 @@ namespace DUNE IMC::toJSON(os__, "value", value, nindent__); IMC::toJSON(os__, "gain", gain, nindent__); } + + DmsDetection::DmsDetection(void) + { + m_header.mgid = 908; + clear(); + } + + void + DmsDetection::clear(void) + { + ch01 = 0; + ch02 = 0; + ch03 = 0; + ch04 = 0; + ch05 = 0; + ch06 = 0; + ch07 = 0; + ch08 = 0; + ch09 = 0; + ch10 = 0; + ch11 = 0; + ch12 = 0; + ch13 = 0; + ch14 = 0; + ch15 = 0; + ch16 = 0; + } + + bool + DmsDetection::fieldsEqual(const Message& msg__) const + { + const IMC::DmsDetection& other__ = static_cast(msg__); + if (ch01 != other__.ch01) return false; + if (ch02 != other__.ch02) return false; + if (ch03 != other__.ch03) return false; + if (ch04 != other__.ch04) return false; + if (ch05 != other__.ch05) return false; + if (ch06 != other__.ch06) return false; + if (ch07 != other__.ch07) return false; + if (ch08 != other__.ch08) return false; + if (ch09 != other__.ch09) return false; + if (ch10 != other__.ch10) return false; + if (ch11 != other__.ch11) return false; + if (ch12 != other__.ch12) return false; + if (ch13 != other__.ch13) return false; + if (ch14 != other__.ch14) return false; + if (ch15 != other__.ch15) return false; + if (ch16 != other__.ch16) return false; + return true; + } + + int + DmsDetection::validate(void) const + { + return true; + } + + uint8_t* + DmsDetection::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(ch01, ptr__); + ptr__ += IMC::serialize(ch02, ptr__); + ptr__ += IMC::serialize(ch03, ptr__); + ptr__ += IMC::serialize(ch04, ptr__); + ptr__ += IMC::serialize(ch05, ptr__); + ptr__ += IMC::serialize(ch06, ptr__); + ptr__ += IMC::serialize(ch07, ptr__); + ptr__ += IMC::serialize(ch08, ptr__); + ptr__ += IMC::serialize(ch09, ptr__); + ptr__ += IMC::serialize(ch10, ptr__); + ptr__ += IMC::serialize(ch11, ptr__); + ptr__ += IMC::serialize(ch12, ptr__); + ptr__ += IMC::serialize(ch13, ptr__); + ptr__ += IMC::serialize(ch14, ptr__); + ptr__ += IMC::serialize(ch15, ptr__); + ptr__ += IMC::serialize(ch16, ptr__); + return ptr__; + } + + uint16_t + DmsDetection::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(ch01, bfr__, size__); + bfr__ += IMC::deserialize(ch02, bfr__, size__); + bfr__ += IMC::deserialize(ch03, bfr__, size__); + bfr__ += IMC::deserialize(ch04, bfr__, size__); + bfr__ += IMC::deserialize(ch05, bfr__, size__); + bfr__ += IMC::deserialize(ch06, bfr__, size__); + bfr__ += IMC::deserialize(ch07, bfr__, size__); + bfr__ += IMC::deserialize(ch08, bfr__, size__); + bfr__ += IMC::deserialize(ch09, bfr__, size__); + bfr__ += IMC::deserialize(ch10, bfr__, size__); + bfr__ += IMC::deserialize(ch11, bfr__, size__); + bfr__ += IMC::deserialize(ch12, bfr__, size__); + bfr__ += IMC::deserialize(ch13, bfr__, size__); + bfr__ += IMC::deserialize(ch14, bfr__, size__); + bfr__ += IMC::deserialize(ch15, bfr__, size__); + bfr__ += IMC::deserialize(ch16, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + DmsDetection::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(ch01, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch02, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch03, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch04, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch05, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch06, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch07, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch08, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch09, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch10, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch11, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch12, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch13, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch14, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch15, bfr__, size__); + bfr__ += IMC::reverseDeserialize(ch16, bfr__, size__); + return bfr__ - start__; + } + + void + DmsDetection::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "ch01", ch01, nindent__); + IMC::toJSON(os__, "ch02", ch02, nindent__); + IMC::toJSON(os__, "ch03", ch03, nindent__); + IMC::toJSON(os__, "ch04", ch04, nindent__); + IMC::toJSON(os__, "ch05", ch05, nindent__); + IMC::toJSON(os__, "ch06", ch06, nindent__); + IMC::toJSON(os__, "ch07", ch07, nindent__); + IMC::toJSON(os__, "ch08", ch08, nindent__); + IMC::toJSON(os__, "ch09", ch09, nindent__); + IMC::toJSON(os__, "ch10", ch10, nindent__); + IMC::toJSON(os__, "ch11", ch11, nindent__); + IMC::toJSON(os__, "ch12", ch12, nindent__); + IMC::toJSON(os__, "ch13", ch13, nindent__); + IMC::toJSON(os__, "ch14", ch14, nindent__); + IMC::toJSON(os__, "ch15", ch15, nindent__); + IMC::toJSON(os__, "ch16", ch16, nindent__); + } + + HomePosition::HomePosition(void) + { + m_header.mgid = 909; + clear(); + } + + void + HomePosition::clear(void) + { + op = 0; + lat = 0; + lon = 0; + height = 0; + depth = 0; + alt = 0; + } + + bool + HomePosition::fieldsEqual(const Message& msg__) const + { + const IMC::HomePosition& other__ = static_cast(msg__); + if (op != other__.op) return false; + if (lat != other__.lat) return false; + if (lon != other__.lon) return false; + if (height != other__.height) return false; + if (depth != other__.depth) return false; + if (alt != other__.alt) return false; + return true; + } + + int + HomePosition::validate(void) const + { + if (lat < -1.5707963267948966 || lat > 1.5707963267948966) return false; + if (lon < -3.141592653589793 || lon > 3.141592653589793) return false; + return true; + } + + uint8_t* + HomePosition::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(op, ptr__); + ptr__ += IMC::serialize(lat, ptr__); + ptr__ += IMC::serialize(lon, ptr__); + ptr__ += IMC::serialize(height, ptr__); + ptr__ += IMC::serialize(depth, ptr__); + ptr__ += IMC::serialize(alt, ptr__); + return ptr__; + } + + uint16_t + HomePosition::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::deserialize(lat, bfr__, size__); + bfr__ += IMC::deserialize(lon, bfr__, size__); + bfr__ += IMC::deserialize(height, bfr__, size__); + bfr__ += IMC::deserialize(depth, bfr__, size__); + bfr__ += IMC::deserialize(alt, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + HomePosition::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(op, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lat, bfr__, size__); + bfr__ += IMC::reverseDeserialize(lon, bfr__, size__); + bfr__ += IMC::reverseDeserialize(height, bfr__, size__); + bfr__ += IMC::reverseDeserialize(depth, bfr__, size__); + bfr__ += IMC::reverseDeserialize(alt, bfr__, size__); + return bfr__ - start__; + } + + void + HomePosition::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "op", op, nindent__); + IMC::toJSON(os__, "lat", lat, nindent__); + IMC::toJSON(os__, "lon", lon, nindent__); + IMC::toJSON(os__, "height", height, nindent__); + IMC::toJSON(os__, "depth", depth, nindent__); + IMC::toJSON(os__, "alt", alt, nindent__); + } + + TotalMagIntensity::TotalMagIntensity(void) + { + m_header.mgid = 2006; + clear(); + } + + void + TotalMagIntensity::clear(void) + { + value = 0; + } + + bool + TotalMagIntensity::fieldsEqual(const Message& msg__) const + { + const IMC::TotalMagIntensity& other__ = static_cast(msg__); + if (value != other__.value) return false; + return true; + } + + int + TotalMagIntensity::validate(void) const + { + return true; + } + + uint8_t* + TotalMagIntensity::serializeFields(uint8_t* bfr__) const + { + uint8_t* ptr__ = bfr__; + ptr__ += IMC::serialize(value, ptr__); + return ptr__; + } + + uint16_t + TotalMagIntensity::deserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::deserialize(value, bfr__, size__); + return bfr__ - start__; + } + + uint16_t + TotalMagIntensity::reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__) + { + const uint8_t* start__ = bfr__; + bfr__ += IMC::reverseDeserialize(value, bfr__, size__); + return bfr__ - start__; + } + + fp64_t + TotalMagIntensity::getValueFP(void) const + { + return static_cast(value); + } + + void + TotalMagIntensity::setValueFP(fp64_t val) + { + value = static_cast(val); + } + + void + TotalMagIntensity::fieldsToJSON(std::ostream& os__, unsigned nindent__) const + { + IMC::toJSON(os__, "value", value, nindent__); + } } } diff --git a/src/DUNE/IMC/Definitions.hpp b/src/DUNE/IMC/Definitions.hpp index d66ce6bb7f..e919a12ffc 100644 --- a/src/DUNE/IMC/Definitions.hpp +++ b/src/DUNE/IMC/Definitions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** #ifndef DUNE_IMC_DEFINITIONS_HPP_INCLUDED_ @@ -94,7 +94,7 @@ namespace DUNE EntityState(void); - Message* + EntityState* clone(void) const { return new EntityState(*this); @@ -159,7 +159,7 @@ namespace DUNE QueryEntityState(void); - Message* + QueryEntityState* clone(void) const { return new QueryEntityState(*this); @@ -222,7 +222,7 @@ namespace DUNE EntityInfo(void); - Message* + EntityInfo* clone(void) const { return new EntityInfo(*this); @@ -295,7 +295,7 @@ namespace DUNE QueryEntityInfo(void); - Message* + QueryEntityInfo* clone(void) const { return new QueryEntityInfo(*this); @@ -373,7 +373,7 @@ namespace DUNE EntityList(void); - Message* + EntityList* clone(void) const { return new EntityList(*this); @@ -440,7 +440,7 @@ namespace DUNE CpuUsage(void); - Message* + CpuUsage* clone(void) const { return new CpuUsage(*this); @@ -509,7 +509,7 @@ namespace DUNE TransportBindings(void); - Message* + TransportBindings* clone(void) const { return new TransportBindings(*this); @@ -565,6 +565,17 @@ namespace DUNE class RestartSystem: public Message { public: + //! Restart Type. + enum RestartTypeEnum + { + //! Dune. + RSTYPE_DUNE = 1, + //! System. + RSTYPE_SYSTEM = 2 + }; + + //! Restart Type. + uint8_t type; static uint16_t getIdStatic(void) @@ -574,7 +585,7 @@ namespace DUNE RestartSystem(void); - Message* + RestartSystem* clone(void) const { return new RestartSystem(*this); @@ -583,6 +594,9 @@ namespace DUNE void clear(void); + bool + fieldsEqual(const Message& msg__) const; + int validate(void) const; @@ -610,8 +624,11 @@ namespace DUNE unsigned getFixedSerializationSize(void) const { - return 0; + return 1; } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; //! Device Calibration Control. @@ -642,7 +659,7 @@ namespace DUNE DevCalibrationControl(void); - Message* + DevCalibrationControl* clone(void) const { return new DevCalibrationControl(*this); @@ -724,7 +741,7 @@ namespace DUNE DevCalibrationState(void); - Message* + DevCalibrationState* clone(void) const { return new DevCalibrationState(*this); @@ -814,7 +831,7 @@ namespace DUNE EntityActivationState(void); - Message* + EntityActivationState* clone(void) const { return new EntityActivationState(*this); @@ -879,7 +896,7 @@ namespace DUNE QueryEntityActivationState(void); - Message* + QueryEntityActivationState* clone(void) const { return new QueryEntityActivationState(*this); @@ -979,7 +996,7 @@ namespace DUNE VehicleOperationalLimits(void); - Message* + VehicleOperationalLimits* clone(void) const { return new VehicleOperationalLimits(*this); @@ -1040,7 +1057,7 @@ namespace DUNE MsgList(void); - Message* + MsgList* clone(void) const { return new MsgList(*this); @@ -1157,7 +1174,7 @@ namespace DUNE SimulatedState(void); - Message* + SimulatedState* clone(void) const { return new SimulatedState(*this); @@ -1229,7 +1246,7 @@ namespace DUNE LeakSimulation(void); - Message* + LeakSimulation* clone(void) const { return new LeakSimulation(*this); @@ -1311,7 +1328,7 @@ namespace DUNE UASimulation(void); - Message* + UASimulation* clone(void) const { return new UASimulation(*this); @@ -1393,7 +1410,7 @@ namespace DUNE DynamicsSimParam(void); - Message* + DynamicsSimParam* clone(void) const { return new DynamicsSimParam(*this); @@ -1456,7 +1473,7 @@ namespace DUNE StorageUsage(void); - Message* + StorageUsage* clone(void) const { return new StorageUsage(*this); @@ -1542,7 +1559,7 @@ namespace DUNE CacheControl(void); - Message* + CacheControl* clone(void) const { return new CacheControl(*this); @@ -1644,7 +1661,7 @@ namespace DUNE LoggingControl(void); - Message* + LoggingControl* clone(void) const { return new LoggingControl(*this); @@ -1732,7 +1749,7 @@ namespace DUNE LogBookEntry(void); - Message* + LogBookEntry* clone(void) const { return new LogBookEntry(*this); @@ -1816,7 +1833,7 @@ namespace DUNE LogBookControl(void); - Message* + LogBookControl* clone(void) const { return new LogBookControl(*this); @@ -1914,7 +1931,7 @@ namespace DUNE ReplayControl(void); - Message* + ReplayControl* clone(void) const { return new ReplayControl(*this); @@ -2002,7 +2019,7 @@ namespace DUNE ClockControl(void); - Message* + ClockControl* clone(void) const { return new ClockControl(*this); @@ -2067,7 +2084,7 @@ namespace DUNE HistoricCTD(void); - Message* + HistoricCTD* clone(void) const { return new HistoricCTD(*this); @@ -2136,7 +2153,7 @@ namespace DUNE HistoricTelemetry(void); - Message* + HistoricTelemetry* clone(void) const { return new HistoricTelemetry(*this); @@ -2220,7 +2237,7 @@ namespace DUNE HistoricSonarData(void); - Message* + HistoricSonarData* clone(void) const { return new HistoricSonarData(*this); @@ -2298,7 +2315,7 @@ namespace DUNE HistoricEvent(void); - Message* + HistoricEvent* clone(void) const { return new HistoricEvent(*this); @@ -2350,6 +2367,179 @@ namespace DUNE fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; + //! Profile Sample. + class ProfileSample: public Message + { + public: + //! Depth. + uint16_t depth; + //! Average. + fp32_t avg; + + static uint16_t + getIdStatic(void) + { + return 112; + } + + ProfileSample(void); + + ProfileSample* + clone(void) const + { + return new ProfileSample(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return ProfileSample::getIdStatic(); + } + + const char* + getName(void) const + { + return "ProfileSample"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 6; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Vertical Profile. + class VerticalProfile: public Message + { + public: + //! Parameter. + enum ParameterEnum + { + //! Temperature. + PROF_TEMPERATURE = 0, + //! Salinity. + PROF_SALINITY = 1, + //! Conductivity. + PROF_CONDUCTIVITY = 2, + //! pH. + PROF_PH = 3, + //! Redox. + PROF_REDOX = 4, + //! Chlorophyll. + PROF_CHLOROPHYLL = 5, + //! Turbidity. + PROF_TURBIDITY = 6 + }; + + //! Parameter. + uint8_t parameter; + //! Number of Samples. + uint8_t numsamples; + //! Samples. + MessageList samples; + //! Latitude. + fp64_t lat; + //! Longitude. + fp64_t lon; + + static uint16_t + getIdStatic(void) + { + return 111; + } + + VerticalProfile(void); + + VerticalProfile* + clone(void) const + { + return new VerticalProfile(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return VerticalProfile::getIdStatic(); + } + + const char* + getName(void) const + { + return "VerticalProfile"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 18; + } + + unsigned + getVariableSerializationSize(void) const + { + return samples.getSerializationSize(); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + + protected: + void + setTimeStampNested(double value__); + + void + setSourceNested(uint16_t value__); + + void + setSourceEntityNested(uint8_t value__); + + void + setDestinationNested(uint16_t value__); + + void + setDestinationEntityNested(uint8_t value__); + }; + //! Heartbeat. class Heartbeat: public Message { @@ -2363,7 +2553,7 @@ namespace DUNE Heartbeat(void); - Message* + Heartbeat* clone(void) const { return new Heartbeat(*this); @@ -2430,7 +2620,7 @@ namespace DUNE Announce(void); - Message* + Announce* clone(void) const { return new Announce(*this); @@ -2508,7 +2698,7 @@ namespace DUNE AnnounceService(void); - Message* + AnnounceService* clone(void) const { return new AnnounceService(*this); @@ -2575,7 +2765,7 @@ namespace DUNE RSSI(void); - Message* + RSSI* clone(void) const { return new RSSI(*this); @@ -2642,7 +2832,7 @@ namespace DUNE VSWR(void); - Message* + VSWR* clone(void) const { return new VSWR(*this); @@ -2709,7 +2899,7 @@ namespace DUNE LinkLevel(void); - Message* + LinkLevel* clone(void) const { return new LinkLevel(*this); @@ -2780,7 +2970,7 @@ namespace DUNE Sms(void); - Message* + Sms* clone(void) const { return new Sms(*this); @@ -2853,7 +3043,7 @@ namespace DUNE SmsTx(void); - Message* + SmsTx* clone(void) const { return new SmsTx(*this); @@ -2922,7 +3112,7 @@ namespace DUNE SmsRx(void); - Message* + SmsRx* clone(void) const { return new SmsRx(*this); @@ -3012,7 +3202,7 @@ namespace DUNE SmsState(void); - Message* + SmsState* clone(void) const { return new SmsState(*this); @@ -3081,7 +3271,7 @@ namespace DUNE TextMessage(void); - Message* + TextMessage* clone(void) const { return new TextMessage(*this); @@ -3156,7 +3346,7 @@ namespace DUNE IridiumMsgRx(void); - Message* + IridiumMsgRx* clone(void) const { return new IridiumMsgRx(*this); @@ -3229,7 +3419,7 @@ namespace DUNE IridiumMsgTx(void); - Message* + IridiumMsgTx* clone(void) const { return new IridiumMsgTx(*this); @@ -3297,7 +3487,9 @@ namespace DUNE //! Message is currently being transmitted. TXSTATUS_TRANSMIT = 4, //! Message's TTL has expired. Transmition cancelled.. - TXSTATUS_EXPIRED = 5 + TXSTATUS_EXPIRED = 5, + //! No more messages to be transmitted or received.. + TXSTATUS_EMPTY = 6 }; //! Request Identifier. @@ -3315,7 +3507,7 @@ namespace DUNE IridiumTxStatus(void); - Message* + IridiumTxStatus* clone(void) const { return new IridiumTxStatus(*this); @@ -3384,7 +3576,7 @@ namespace DUNE GroupMembershipState(void); - Message* + GroupMembershipState* clone(void) const { return new GroupMembershipState(*this); @@ -3472,7 +3664,7 @@ namespace DUNE SystemGroup(void); - Message* + SystemGroup* clone(void) const { return new SystemGroup(*this); @@ -3541,7 +3733,7 @@ namespace DUNE LinkLatency(void); - Message* + LinkLatency* clone(void) const { return new LinkLatency(*this); @@ -3610,7 +3802,7 @@ namespace DUNE ExtendedRSSI(void); - Message* + ExtendedRSSI* clone(void) const { return new ExtendedRSSI(*this); @@ -3683,7 +3875,7 @@ namespace DUNE HistoricData(void); - Message* + HistoricData* clone(void) const { return new HistoricData(*this); @@ -3772,7 +3964,7 @@ namespace DUNE CompressedHistory(void); - Message* + CompressedHistory* clone(void) const { return new CompressedHistory(*this); @@ -3851,7 +4043,7 @@ namespace DUNE HistoricSample(void); - Message* + HistoricSample* clone(void) const { return new HistoricSample(*this); @@ -3951,7 +4143,7 @@ namespace DUNE HistoricDataQuery(void); - Message* + HistoricDataQuery* clone(void) const { return new HistoricDataQuery(*this); @@ -4040,7 +4232,7 @@ namespace DUNE RemoteCommand(void); - Message* + RemoteCommand* clone(void) const { return new RemoteCommand(*this); @@ -4108,27 +4300,66 @@ namespace DUNE setDestinationEntityNested(uint8_t value__); }; - //! LBL Range. - class LblRange: public Message + //! Communication Systems Query. + class CommSystemsQuery: public Message { public: - //! Beacon Identification Number. - uint8_t id; - //! Range. - fp32_t range; + //! Model. + enum ModelEnum + { + //! unknown. + CIQ_UNKNOWN = 0x00, + //! 3DR. + CIQ_M3DR = 0x01, + //! RDFXXXxPtP. + CIQ_RDFXXXXPTP = 0x02 + }; + + //! Type. + enum TypeBits + { + //! Query Systems. + CIQ_QUERY = 0x01, + //! Reply. + CIQ_REPLY = 0x02 + }; + + //! Communication Interface. + enum CommunicationInterfaceBits + { + //! Acoustic. + CIQ_ACOUSTIC = 0x01, + //! Satellite. + CIQ_SATELLITE = 0x02, + //! GSM. + CIQ_GSM = 0x04, + //! Mobile. + CIQ_MOBILE = 0x08, + //! Radio. + CIQ_RADIO = 0x10 + }; + + //! Type. + uint8_t type; + //! Communication Interface. + uint16_t comm_interface; + //! Model. + uint16_t model; + //! System List. + std::string list; static uint16_t getIdStatic(void) { - return 200; + return 189; } - LblRange(void); + CommSystemsQuery(void); - Message* + CommSystemsQuery* clone(void) const { - return new LblRange(*this); + return new CommSystemsQuery(*this); } void @@ -4152,13 +4383,13 @@ namespace DUNE uint16_t getId(void) const { - return LblRange::getIdStatic(); + return CommSystemsQuery::getIdStatic(); } const char* getName(void) const { - return "LblRange"; + return "CommSystemsQuery"; } unsigned @@ -4167,47 +4398,107 @@ namespace DUNE return 5; } - uint16_t - getSubId(void) const; - - void - setSubId(uint16_t subid); + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(list); + } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! LBL Beacon Configuration. - class LblBeacon: public Message + //! Telemetry Message. + class TelemetryMsg: public Message { public: - //! Beacon Name. - std::string beacon; - //! Latitude WGS-84. - fp64_t lat; - //! Longitude WGS-84. - fp64_t lon; - //! Depth. - fp32_t depth; - //! Interrogation channel. - uint8_t query_channel; - //! Reply channel. - uint8_t reply_channel; - //! Transponder delay. - uint8_t transponder_delay; + //! Type. + enum TypeEnum + { + //! Tx. + TM_TX = 0x01, + //! Rx. + TM_RX = 0x02, + //! TxStatus. + TM_TXSTATUS = 0x03 + }; + + //! Code. + enum CodeEnum + { + //! Code unknown. + TM_CODE_UNK = 0x00, + //! Code Report. + TM_CODE_REPORT = 0x01, + //! Code IMC. + TM_CODE_IMC = 0x02, + //! Code raw. + TM_CODE_RAW = 0x03 + }; + + //! Status. + enum StatusEnum + { + //! Does not apply. + TM_NONE = 0x00, + //! Successfull transmission. + TM_DONE = 1, + //! Error while trying to transmit message. + TM_FAILED = 2, + //! Message has been queued for transmission. + TM_QUEUED = 3, + //! Message is currently being transmitted. + TM_TRANSMIT = 4, + //! Message's TTL has expired. Transmition cancelled. + TM_EXPIRED = 5, + //! No more messages to be transmitted or received. + TM_EMPTY = 6, + //! Invalid address. + TM_INV_ADDR = 7, + //! Invalid transmission size. + TM_INV_SIZE = 8 + }; + + //! Acknowledge. + enum AcknowledgeBits + { + //! Not acknowledge. + TM_NAK = 0x00, + //! acknowledge. + TM_AK = 0x01 + }; + + //! Type. + uint8_t type; + //! Request Identifier. + uint32_t req_id; + //! Time to live. + uint16_t ttl; + //! Code. + uint8_t code; + //! Destination Identifier. + std::string destination; + //! Source Identifier. + std::string source; + //! Acknowledge. + uint8_t acknowledge; + //! Status. + uint8_t status; + //! Data. + std::vector data; static uint16_t getIdStatic(void) { - return 202; + return 190; } - LblBeacon(void); + TelemetryMsg(void); - Message* + TelemetryMsg* clone(void) const { - return new LblBeacon(*this); + return new TelemetryMsg(*this); } void @@ -4231,39 +4522,187 @@ namespace DUNE uint16_t getId(void) const { - return LblBeacon::getIdStatic(); + return TelemetryMsg::getIdStatic(); } const char* getName(void) const { - return "LblBeacon"; + return "TelemetryMsg"; } unsigned getFixedSerializationSize(void) const { - return 23; + return 10; } unsigned getVariableSerializationSize(void) const { - return IMC::getSerializationSize(beacon); + return IMC::getSerializationSize(destination) + IMC::getSerializationSize(source) + IMC::getSerializationSize(data); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! LBL Configuration. - class LblConfig: public Message + //! LBL Range. + class LblRange: public Message { public: - //! Operation. - enum OperationEnum + //! Beacon Identification Number. + uint8_t id; + //! Range. + fp32_t range; + + static uint16_t + getIdStatic(void) { - //! Set LBL Configuration. + return 200; + } + + LblRange(void); + + LblRange* + clone(void) const + { + return new LblRange(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return LblRange::getIdStatic(); + } + + const char* + getName(void) const + { + return "LblRange"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 5; + } + + uint16_t + getSubId(void) const; + + void + setSubId(uint16_t subid); + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! LBL Beacon Configuration. + class LblBeacon: public Message + { + public: + //! Beacon Name. + std::string beacon; + //! Latitude WGS-84. + fp64_t lat; + //! Longitude WGS-84. + fp64_t lon; + //! Depth. + fp32_t depth; + //! Interrogation channel. + uint8_t query_channel; + //! Reply channel. + uint8_t reply_channel; + //! Transponder delay. + uint8_t transponder_delay; + + static uint16_t + getIdStatic(void) + { + return 202; + } + + LblBeacon(void); + + LblBeacon* + clone(void) const + { + return new LblBeacon(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return LblBeacon::getIdStatic(); + } + + const char* + getName(void) const + { + return "LblBeacon"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 23; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(beacon); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! LBL Configuration. + class LblConfig: public Message + { + public: + //! Operation. + enum OperationEnum + { + //! Set LBL Configuration. OP_SET_CFG = 0, //! Retrieve LBL Configuration. OP_GET_CFG = 1, @@ -4284,7 +4723,7 @@ namespace DUNE LblConfig(void); - Message* + LblConfig* clone(void) const { return new LblConfig(*this); @@ -4367,7 +4806,7 @@ namespace DUNE AcousticMessage(void); - Message* + AcousticMessage* clone(void) const { return new AcousticMessage(*this); @@ -4435,6 +4874,104 @@ namespace DUNE setDestinationEntityNested(uint8_t value__); }; + //! Simulated Acoustic Message. + class SimAcousticMessage: public Message + { + public: + //! Flags. + enum FlagsBits + { + //! Acknowledgement. + SAM_ACK = 0x01, + //! Delayed. + SAM_DELAYED = 0x02, + //! Reply. + SAM_REPLY = 0x03 + }; + + //! Latitude. + fp64_t lat; + //! Longitude. + fp64_t lon; + //! Depth. + fp32_t depth; + //! Sentence. + std::string sentence; + //! Transmission Time. + fp64_t txtime; + //! Modem Type. + std::string modem_type; + //! Source system. + std::string sys_src; + //! Sequence Id. + uint16_t seq; + //! Destination System. + std::string sys_dst; + //! Flags. + uint8_t flags; + //! Data. + std::vector data; + + static uint16_t + getIdStatic(void) + { + return 207; + } + + SimAcousticMessage(void); + + SimAcousticMessage* + clone(void) const + { + return new SimAcousticMessage(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return SimAcousticMessage::getIdStatic(); + } + + const char* + getName(void) const + { + return "SimAcousticMessage"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 31; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(sentence) + IMC::getSerializationSize(modem_type) + IMC::getSerializationSize(sys_src) + IMC::getSerializationSize(sys_dst) + IMC::getSerializationSize(data); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + //! Acoustic Operation. class AcousticOperation: public Message { @@ -4477,7 +5014,9 @@ namespace DUNE //! Send Short Message. AOP_MSG_SHORT = 16, //! Initiate Reverse Range. - AOP_REVERSE_RANGE = 17 + AOP_REVERSE_RANGE = 17, + //! Forced Abort. + AOP_FORCED_ABORT = 18 }; //! Operation. @@ -4497,7 +5036,7 @@ namespace DUNE AcousticOperation(void); - Message* + AcousticOperation* clone(void) const { return new AcousticOperation(*this); @@ -4578,7 +5117,7 @@ namespace DUNE AcousticSystemsQuery(void); - Message* + AcousticSystemsQuery* clone(void) const { return new AcousticSystemsQuery(*this); @@ -4633,7 +5172,7 @@ namespace DUNE AcousticSystems(void); - Message* + AcousticSystems* clone(void) const { return new AcousticSystems(*this); @@ -4704,7 +5243,7 @@ namespace DUNE AcousticLink(void); - Message* + AcousticLink* clone(void) const { return new AcousticLink(*this); @@ -4756,25 +5295,50 @@ namespace DUNE fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Revolutions Per Minute. - class Rpm: public Message + //! Acoustic Transmission Request. + class AcousticRequest: public Message { public: - //! Value. - int16_t value; + //! Type. + enum TypeEnum + { + //! Abort. + TYPE_ABORT = 0, + //! Range. + TYPE_RANGE = 1, + //! Reverse Range. + TYPE_REVERSE_RANGE = 2, + //! Message. + TYPE_MSG = 3, + //! Raw. + TYPE_RAW = 4 + }; + + //! Request Identifier. + uint16_t req_id; + //! Destination System. + std::string destination; + //! Timeout. + fp64_t timeout; + //! Range. + fp32_t range; + //! Type. + uint8_t type; + //! Message To Send. + InlineMessage msg; static uint16_t getIdStatic(void) { - return 250; + return 215; } - Rpm(void); + AcousticRequest(void); - Message* + AcousticRequest* clone(void) const { - return new Rpm(*this); + return new AcousticRequest(*this); } void @@ -4798,26 +5362,222 @@ namespace DUNE uint16_t getId(void) const { - return Rpm::getIdStatic(); + return AcousticRequest::getIdStatic(); } const char* getName(void) const { - return "Rpm"; + return "AcousticRequest"; } unsigned getFixedSerializationSize(void) const { - return 2; + return 15; } - fp64_t - getValueFP(void) const; - - void - setValueFP(fp64_t val); + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(destination) + msg.getSerializationSize(); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + + protected: + void + setTimeStampNested(double value__); + + void + setSourceNested(uint16_t value__); + + void + setSourceEntityNested(uint8_t value__); + + void + setDestinationNested(uint16_t value__); + + void + setDestinationEntityNested(uint8_t value__); + }; + + //! Acoustic Transmission Status. + class AcousticStatus: public Message + { + public: + //! Type. + enum TypeEnum + { + //! Abort. + TYPE_ABORT = 0, + //! Range. + TYPE_RANGE = 1, + //! Reverse Range. + TYPE_REVERSE_RANGE = 2, + //! Message. + TYPE_MSG = 3, + //! Raw. + TYPE_RAW = 4 + }; + + //! Status. + enum StatusEnum + { + //! Queued. + STATUS_QUEUED = 0, + //! In Progress. + STATUS_IN_PROGRESS = 1, + //! Sent. + STATUS_SENT = 2, + //! Range Received. + STATUS_RANGE_RECEIVED = 3, + //! Delivered. + STATUS_DELIVERED = 4, + //! Busy. + STATUS_BUSY = 100, + //! Input Error. + STATUS_INPUT_FAILURE = 101, + //! Error trying to send acoustic text. + STATUS_ERROR = 102, + //! Message Type is not defined or is unsupported. + STATUS_UNSUPPORTED = 666 + }; + + //! Request Identifier. + uint16_t req_id; + //! Type. + uint8_t type; + //! Status. + uint8_t status; + //! Information. + std::string info; + //! Range. + fp32_t range; + + static uint16_t + getIdStatic(void) + { + return 216; + } + + AcousticStatus(void); + + AcousticStatus* + clone(void) const + { + return new AcousticStatus(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return AcousticStatus::getIdStatic(); + } + + const char* + getName(void) const + { + return "AcousticStatus"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 8; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(info); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Revolutions Per Minute. + class Rpm: public Message + { + public: + //! Value. + int16_t value; + + static uint16_t + getIdStatic(void) + { + return 250; + } + + Rpm(void); + + Rpm* + clone(void) const + { + return new Rpm(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return Rpm::getIdStatic(); + } + + const char* + getName(void) const + { + return "Rpm"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 2; + } + + fp64_t + getValueFP(void) const; + + void + setValueFP(fp64_t val); void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; @@ -4838,7 +5598,7 @@ namespace DUNE Voltage(void); - Message* + Voltage* clone(void) const { return new Voltage(*this); @@ -4905,7 +5665,7 @@ namespace DUNE Current(void); - Message* + Current* clone(void) const { return new Current(*this); @@ -5040,7 +5800,7 @@ namespace DUNE GpsFix(void); - Message* + GpsFix* clone(void) const { return new GpsFix(*this); @@ -5109,7 +5869,7 @@ namespace DUNE EulerAngles(void); - Message* + EulerAngles* clone(void) const { return new EulerAngles(*this); @@ -5178,7 +5938,7 @@ namespace DUNE EulerAnglesDelta(void); - Message* + EulerAnglesDelta* clone(void) const { return new EulerAnglesDelta(*this); @@ -5245,7 +6005,7 @@ namespace DUNE AngularVelocity(void); - Message* + AngularVelocity* clone(void) const { return new AngularVelocity(*this); @@ -5312,7 +6072,7 @@ namespace DUNE Acceleration(void); - Message* + Acceleration* clone(void) const { return new Acceleration(*this); @@ -5379,7 +6139,7 @@ namespace DUNE MagneticField(void); - Message* + MagneticField* clone(void) const { return new MagneticField(*this); @@ -5457,7 +6217,7 @@ namespace DUNE GroundVelocity(void); - Message* + GroundVelocity* clone(void) const { return new GroundVelocity(*this); @@ -5535,7 +6295,7 @@ namespace DUNE WaterVelocity(void); - Message* + WaterVelocity* clone(void) const { return new WaterVelocity(*this); @@ -5602,7 +6362,7 @@ namespace DUNE VelocityDelta(void); - Message* + VelocityDelta* clone(void) const { return new VelocityDelta(*this); @@ -5673,7 +6433,7 @@ namespace DUNE DeviceState(void); - Message* + DeviceState* clone(void) const { return new DeviceState(*this); @@ -5736,7 +6496,7 @@ namespace DUNE BeamConfig(void); - Message* + BeamConfig* clone(void) const { return new BeamConfig(*this); @@ -5812,7 +6572,7 @@ namespace DUNE Distance(void); - Message* + Distance* clone(void) const { return new Distance(*this); @@ -5901,7 +6661,7 @@ namespace DUNE Temperature(void); - Message* + Temperature* clone(void) const { return new Temperature(*this); @@ -5968,7 +6728,7 @@ namespace DUNE Pressure(void); - Message* + Pressure* clone(void) const { return new Pressure(*this); @@ -6035,7 +6795,7 @@ namespace DUNE Depth(void); - Message* + Depth* clone(void) const { return new Depth(*this); @@ -6102,7 +6862,7 @@ namespace DUNE DepthOffset(void); - Message* + DepthOffset* clone(void) const { return new DepthOffset(*this); @@ -6169,7 +6929,7 @@ namespace DUNE SoundSpeed(void); - Message* + SoundSpeed* clone(void) const { return new SoundSpeed(*this); @@ -6236,7 +6996,7 @@ namespace DUNE WaterDensity(void); - Message* + WaterDensity* clone(void) const { return new WaterDensity(*this); @@ -6303,7 +7063,7 @@ namespace DUNE Conductivity(void); - Message* + Conductivity* clone(void) const { return new Conductivity(*this); @@ -6370,7 +7130,7 @@ namespace DUNE Salinity(void); - Message* + Salinity* clone(void) const { return new Salinity(*this); @@ -6441,7 +7201,7 @@ namespace DUNE WindSpeed(void); - Message* + WindSpeed* clone(void) const { return new WindSpeed(*this); @@ -6502,7 +7262,7 @@ namespace DUNE RelativeHumidity(void); - Message* + RelativeHumidity* clone(void) const { return new RelativeHumidity(*this); @@ -6569,7 +7329,7 @@ namespace DUNE DevDataText(void); - Message* + DevDataText* clone(void) const { return new DevDataText(*this); @@ -6636,7 +7396,7 @@ namespace DUNE DevDataBinary(void); - Message* + DevDataBinary* clone(void) const { return new DevDataBinary(*this); @@ -6688,6 +7448,73 @@ namespace DUNE fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; + //! Force. + class Force: public Message + { + public: + //! Measured Force. + fp32_t value; + + static uint16_t + getIdStatic(void) + { + return 275; + } + + Force(void); + + Force* + clone(void) const + { + return new Force(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return Force::getIdStatic(); + } + + const char* + getName(void) const + { + return "Force"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 4; + } + + fp64_t + getValueFP(void) const; + + void + setValueFP(fp64_t val); + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + //! Sonar Data. class SonarData: public Message { @@ -6728,7 +7555,7 @@ namespace DUNE SonarData(void); - Message* + SonarData* clone(void) const { return new SonarData(*this); @@ -6809,7 +7636,7 @@ namespace DUNE Pulse(void); - Message* + Pulse* clone(void) const { return new Pulse(*this); @@ -6873,7 +7700,7 @@ namespace DUNE PulseDetectionControl(void); - Message* + PulseDetectionControl* clone(void) const { return new PulseDetectionControl(*this); @@ -6938,7 +7765,7 @@ namespace DUNE FuelLevel(void); - Message* + FuelLevel* clone(void) const { return new FuelLevel(*this); @@ -7039,7 +7866,7 @@ namespace DUNE GpsNavData(void); - Message* + GpsNavData* clone(void) const { return new GpsNavData(*this); @@ -7102,7 +7929,7 @@ namespace DUNE ServoPosition(void); - Message* + ServoPosition* clone(void) const { return new ServoPosition(*this); @@ -7184,7 +8011,7 @@ namespace DUNE DataSanity(void); - Message* + DataSanity* clone(void) const { return new DataSanity(*this); @@ -7245,7 +8072,7 @@ namespace DUNE RhodamineDye(void); - Message* + RhodamineDye* clone(void) const { return new RhodamineDye(*this); @@ -7312,7 +8139,7 @@ namespace DUNE CrudeOil(void); - Message* + CrudeOil* clone(void) const { return new CrudeOil(*this); @@ -7379,7 +8206,7 @@ namespace DUNE FineOil(void); - Message* + FineOil* clone(void) const { return new FineOil(*this); @@ -7446,7 +8273,7 @@ namespace DUNE Turbidity(void); - Message* + Turbidity* clone(void) const { return new Turbidity(*this); @@ -7513,7 +8340,7 @@ namespace DUNE Chlorophyll(void); - Message* + Chlorophyll* clone(void) const { return new Chlorophyll(*this); @@ -7580,7 +8407,7 @@ namespace DUNE Fluorescein(void); - Message* + Fluorescein* clone(void) const { return new Fluorescein(*this); @@ -7647,7 +8474,7 @@ namespace DUNE Phycocyanin(void); - Message* + Phycocyanin* clone(void) const { return new Phycocyanin(*this); @@ -7714,7 +8541,7 @@ namespace DUNE Phycoerythrin(void); - Message* + Phycoerythrin* clone(void) const { return new Phycoerythrin(*this); @@ -7835,7 +8662,7 @@ namespace DUNE GpsFixRtk(void); - Message* + GpsFixRtk* clone(void) const { return new GpsFixRtk(*this); @@ -7934,7 +8761,7 @@ namespace DUNE EstimatedState(void); - Message* + EstimatedState* clone(void) const { return new EstimatedState(*this); @@ -8008,7 +8835,7 @@ namespace DUNE ExternalNavData(void); - Message* + ExternalNavData* clone(void) const { return new ExternalNavData(*this); @@ -8091,7 +8918,7 @@ namespace DUNE DissolvedOxygen(void); - Message* + DissolvedOxygen* clone(void) const { return new DissolvedOxygen(*this); @@ -8158,7 +8985,7 @@ namespace DUNE AirSaturation(void); - Message* + AirSaturation* clone(void) const { return new AirSaturation(*this); @@ -8225,7 +9052,7 @@ namespace DUNE Throttle(void); - Message* + Throttle* clone(void) const { return new Throttle(*this); @@ -8292,7 +9119,7 @@ namespace DUNE PH(void); - Message* + PH* clone(void) const { return new PH(*this); @@ -8359,7 +9186,7 @@ namespace DUNE Redox(void); - Message* + Redox* clone(void) const { return new Redox(*this); @@ -8443,7 +9270,7 @@ namespace DUNE CameraZoom(void); - Message* + CameraZoom* clone(void) const { return new CameraZoom(*this); @@ -8512,7 +9339,7 @@ namespace DUNE SetThrusterActuation(void); - Message* + SetThrusterActuation* clone(void) const { return new SetThrusterActuation(*this); @@ -8587,7 +9414,7 @@ namespace DUNE SetServoPosition(void); - Message* + SetServoPosition* clone(void) const { return new SetServoPosition(*this); @@ -8662,7 +9489,7 @@ namespace DUNE SetControlSurfaceDeflection(void); - Message* + SetControlSurfaceDeflection* clone(void) const { return new SetControlSurfaceDeflection(*this); @@ -8740,7 +9567,7 @@ namespace DUNE RemoteActionsRequest(void); - Message* + RemoteActionsRequest* clone(void) const { return new RemoteActionsRequest(*this); @@ -8807,7 +9634,7 @@ namespace DUNE RemoteActions(void); - Message* + RemoteActions* clone(void) const { return new RemoteActions(*this); @@ -8876,7 +9703,7 @@ namespace DUNE ButtonEvent(void); - Message* + ButtonEvent* clone(void) const { return new ButtonEvent(*this); @@ -8960,7 +9787,7 @@ namespace DUNE LcdControl(void); - Message* + LcdControl* clone(void) const { return new LcdControl(*this); @@ -9050,7 +9877,7 @@ namespace DUNE PowerOperation(void); - Message* + PowerOperation* clone(void) const { return new PowerOperation(*this); @@ -9116,7 +9943,9 @@ namespace DUNE //! Reset Schedules. PCC_OP_SCHED_RESET = 5, //! Save Current State. - PCC_OP_SAVE = 6 + PCC_OP_SAVE = 6, + //! Restart. + PCC_OP_RESTART = 7 }; //! Channel Name. @@ -9134,7 +9963,7 @@ namespace DUNE PowerChannelControl(void); - Message* + PowerChannelControl* clone(void) const { return new PowerChannelControl(*this); @@ -9199,7 +10028,7 @@ namespace DUNE QueryPowerChannelState(void); - Message* + QueryPowerChannelState* clone(void) const { return new QueryPowerChannelState(*this); @@ -9265,7 +10094,7 @@ namespace DUNE PowerChannelState(void); - Message* + PowerChannelState* clone(void) const { return new PowerChannelState(*this); @@ -9334,7 +10163,7 @@ namespace DUNE LedBrightness(void); - Message* + LedBrightness* clone(void) const { return new LedBrightness(*this); @@ -9407,7 +10236,7 @@ namespace DUNE QueryLedBrightness(void); - Message* + QueryLedBrightness* clone(void) const { return new QueryLedBrightness(*this); @@ -9476,7 +10305,7 @@ namespace DUNE SetLedBrightness(void); - Message* + SetLedBrightness* clone(void) const { return new SetLedBrightness(*this); @@ -9553,7 +10382,7 @@ namespace DUNE SetPWM(void); - Message* + SetPWM* clone(void) const { return new SetPWM(*this); @@ -9624,7 +10453,7 @@ namespace DUNE PWM(void); - Message* + PWM* clone(void) const { return new PWM(*this); @@ -9695,7 +10524,7 @@ namespace DUNE EstimatedStreamVelocity(void); - Message* + EstimatedStreamVelocity* clone(void) const { return new EstimatedStreamVelocity(*this); @@ -9756,7 +10585,7 @@ namespace DUNE IndicatedSpeed(void); - Message* + IndicatedSpeed* clone(void) const { return new IndicatedSpeed(*this); @@ -9823,7 +10652,7 @@ namespace DUNE TrueSpeed(void); - Message* + TrueSpeed* clone(void) const { return new TrueSpeed(*this); @@ -9916,7 +10745,7 @@ namespace DUNE NavigationUncertainty(void); - Message* + NavigationUncertainty* clone(void) const { return new NavigationUncertainty(*this); @@ -9993,7 +10822,7 @@ namespace DUNE NavigationData(void); - Message* + NavigationData* clone(void) const { return new NavigationData(*this); @@ -10071,7 +10900,7 @@ namespace DUNE GpsFixRejection(void); - Message* + GpsFixRejection* clone(void) const { return new GpsFixRejection(*this); @@ -10151,7 +10980,7 @@ namespace DUNE LblRangeAcceptance(void); - Message* + LblRangeAcceptance* clone(void) const { return new LblRangeAcceptance(*this); @@ -10246,7 +11075,7 @@ namespace DUNE DvlRejection(void); - Message* + DvlRejection* clone(void) const { return new DvlRejection(*this); @@ -10323,7 +11152,7 @@ namespace DUNE LblEstimate(void); - Message* + LblEstimate* clone(void) const { return new LblEstimate(*this); @@ -10403,7 +11232,17 @@ namespace DUNE //! Aligned. AS_ALIGNED = 1, //! Not Supported. - AS_NOT_SUPPORTED = 2 + AS_NOT_SUPPORTED = 2, + //! Aligning. + AS_ALIGNING = 3, + //! Wrong Medium. + AS_WRONG_MEDIUM = 4, + //! Coarse Alignment. + AS_COARSE_ALIGNMENT = 5, + //! Fine Alignment. + AS_FINE_ALIGNMENT = 6, + //! System Ready. + AS_SYSTEM_READY = 7 }; //! State. @@ -10417,7 +11256,7 @@ namespace DUNE AlignmentState(void); - Message* + AlignmentState* clone(void) const { return new AlignmentState(*this); @@ -10482,7 +11321,7 @@ namespace DUNE GroupStreamVelocity(void); - Message* + GroupStreamVelocity* clone(void) const { return new GroupStreamVelocity(*this); @@ -10547,7 +11386,7 @@ namespace DUNE Airflow(void); - Message* + Airflow* clone(void) const { return new Airflow(*this); @@ -10608,7 +11447,7 @@ namespace DUNE DesiredHeading(void); - Message* + DesiredHeading* clone(void) const { return new DesiredHeading(*this); @@ -10677,7 +11516,7 @@ namespace DUNE DesiredZ(void); - Message* + DesiredZ* clone(void) const { return new DesiredZ(*this); @@ -10746,7 +11585,7 @@ namespace DUNE DesiredSpeed(void); - Message* + DesiredSpeed* clone(void) const { return new DesiredSpeed(*this); @@ -10813,7 +11652,7 @@ namespace DUNE DesiredRoll(void); - Message* + DesiredRoll* clone(void) const { return new DesiredRoll(*this); @@ -10880,7 +11719,7 @@ namespace DUNE DesiredPitch(void); - Message* + DesiredPitch* clone(void) const { return new DesiredPitch(*this); @@ -10947,7 +11786,7 @@ namespace DUNE DesiredVerticalRate(void); - Message* + DesiredVerticalRate* clone(void) const { return new DesiredVerticalRate(*this); @@ -11059,7 +11898,7 @@ namespace DUNE DesiredPath(void); - Message* + DesiredPath* clone(void) const { return new DesiredPath(*this); @@ -11149,7 +11988,7 @@ namespace DUNE DesiredControl(void); - Message* + DesiredControl* clone(void) const { return new DesiredControl(*this); @@ -11210,7 +12049,7 @@ namespace DUNE DesiredHeadingRate(void); - Message* + DesiredHeadingRate* clone(void) const { return new DesiredHeadingRate(*this); @@ -11306,7 +12145,7 @@ namespace DUNE DesiredVelocity(void); - Message* + DesiredVelocity* clone(void) const { return new DesiredVelocity(*this); @@ -11418,7 +12257,7 @@ namespace DUNE PathControlState(void); - Message* + PathControlState* clone(void) const { return new PathControlState(*this); @@ -11483,7 +12322,7 @@ namespace DUNE AllocatedControlTorques(void); - Message* + AllocatedControlTorques* clone(void) const { return new AllocatedControlTorques(*this); @@ -11550,7 +12389,7 @@ namespace DUNE ControlParcel(void); - Message* + ControlParcel* clone(void) const { return new ControlParcel(*this); @@ -11606,7 +12445,9 @@ namespace DUNE //! Stop Braking. OP_STOP = 0, //! Start Braking. - OP_START = 1 + OP_START = 1, + //! Revert Actuation. + OP_REVERT = 2 }; //! Operation. @@ -11620,7 +12461,7 @@ namespace DUNE Brake(void); - Message* + Brake* clone(void) const { return new Brake(*this); @@ -11722,7 +12563,7 @@ namespace DUNE DesiredLinearState(void); - Message* + DesiredLinearState* clone(void) const { return new DesiredLinearState(*this); @@ -11783,7 +12624,7 @@ namespace DUNE DesiredThrottle(void); - Message* + DesiredThrottle* clone(void) const { return new DesiredThrottle(*this); @@ -11870,7 +12711,7 @@ namespace DUNE Goto(void); - Message* + Goto* clone(void) const { return new Goto(*this); @@ -11968,7 +12809,7 @@ namespace DUNE PopUp(void); - Message* + PopUp* clone(void) const { return new PopUp(*this); @@ -12035,7 +12876,7 @@ namespace DUNE Teleoperation(void); - Message* + Teleoperation* clone(void) const { return new Teleoperation(*this); @@ -12156,7 +12997,7 @@ namespace DUNE Loiter(void); - Message* + Loiter* clone(void) const { return new Loiter(*this); @@ -12225,7 +13066,7 @@ namespace DUNE IdleManeuver(void); - Message* + IdleManeuver* clone(void) const { return new IdleManeuver(*this); @@ -12296,7 +13137,7 @@ namespace DUNE LowLevelControl(void); - Message* + LowLevelControl* clone(void) const { return new LowLevelControl(*this); @@ -12418,7 +13259,7 @@ namespace DUNE Rows(void); - Message* + Rows* clone(void) const { return new Rows(*this); @@ -12489,7 +13330,7 @@ namespace DUNE PathPoint(void); - Message* + PathPoint* clone(void) const { return new PathPoint(*this); @@ -12566,7 +13407,7 @@ namespace DUNE FollowPath(void); - Message* + FollowPath* clone(void) const { return new FollowPath(*this); @@ -12667,7 +13508,7 @@ namespace DUNE YoYo(void); - Message* + YoYo* clone(void) const { return new YoYo(*this); @@ -12732,7 +13573,7 @@ namespace DUNE TeleoperationDone(void); - Message* + TeleoperationDone* clone(void) const { return new TeleoperationDone(*this); @@ -12803,7 +13644,7 @@ namespace DUNE StationKeeping(void); - Message* + StationKeeping* clone(void) const { return new StationKeeping(*this); @@ -12899,7 +13740,7 @@ namespace DUNE Elevator(void); - Message* + Elevator* clone(void) const { return new Elevator(*this); @@ -12972,7 +13813,7 @@ namespace DUNE TrajectoryPoint(void); - Message* + TrajectoryPoint* clone(void) const { return new TrajectoryPoint(*this); @@ -13049,7 +13890,7 @@ namespace DUNE FollowTrajectory(void); - Message* + FollowTrajectory* clone(void) const { return new FollowTrajectory(*this); @@ -13136,7 +13977,7 @@ namespace DUNE CustomManeuver(void); - Message* + CustomManeuver* clone(void) const { return new CustomManeuver(*this); @@ -13209,7 +14050,7 @@ namespace DUNE VehicleFormationParticipant(void); - Message* + VehicleFormationParticipant* clone(void) const { return new VehicleFormationParticipant(*this); @@ -13288,7 +14129,7 @@ namespace DUNE VehicleFormation(void); - Message* + VehicleFormation* clone(void) const { return new VehicleFormation(*this); @@ -13369,7 +14210,7 @@ namespace DUNE StopManeuver(void); - Message* + StopManeuver* clone(void) const { return new StopManeuver(*this); @@ -13424,7 +14265,7 @@ namespace DUNE RegisterManeuver(void); - Message* + RegisterManeuver* clone(void) const { return new RegisterManeuver(*this); @@ -13502,7 +14343,7 @@ namespace DUNE ManeuverControlState(void); - Message* + ManeuverControlState* clone(void) const { return new ManeuverControlState(*this); @@ -13583,7 +14424,7 @@ namespace DUNE FollowSystem(void); - Message* + FollowSystem* clone(void) const { return new FollowSystem(*this); @@ -13658,7 +14499,7 @@ namespace DUNE CommsRelay(void); - Message* + CommsRelay* clone(void) const { return new CommsRelay(*this); @@ -13721,7 +14562,7 @@ namespace DUNE PolygonVertex(void); - Message* + PolygonVertex* clone(void) const { return new PolygonVertex(*this); @@ -13796,7 +14637,7 @@ namespace DUNE CoverArea(void); - Message* + CoverArea* clone(void) const { return new CoverArea(*this); @@ -13916,7 +14757,7 @@ namespace DUNE CompassCalibration(void); - Message* + CompassCalibration* clone(void) const { return new CompassCalibration(*this); @@ -14000,7 +14841,7 @@ namespace DUNE FormationParameters(void); - Message* + FormationParameters* clone(void) const { return new FormationParameters(*this); @@ -14109,7 +14950,7 @@ namespace DUNE FormationPlanExecution(void); - Message* + FormationPlanExecution* clone(void) const { return new FormationPlanExecution(*this); @@ -14184,7 +15025,7 @@ namespace DUNE FollowReference(void); - Message* + FollowReference* clone(void) const { return new FollowReference(*this); @@ -14274,7 +15115,7 @@ namespace DUNE Reference(void); - Message* + Reference* clone(void) const { return new Reference(*this); @@ -14371,7 +15212,11 @@ namespace DUNE //! Near in the horizontal plane. PROX_XY_NEAR = 0x02, //! Near in the vertical plane. - PROX_Z_NEAR = 0x04 + PROX_Z_NEAR = 0x04, + //! Unreachable in the horizontal plane. + PROX_XY_UNREACHABLE = 0x08, + //! Unreachable in the vertical plane. + PROX_Z_UNREACHABLE = 0x10 }; //! Controlling Source. @@ -14393,7 +15238,7 @@ namespace DUNE FollowRefState(void); - Message* + FollowRefState* clone(void) const { return new FollowRefState(*this); @@ -14518,7 +15363,7 @@ namespace DUNE RelativeState(void); - Message* + RelativeState* clone(void) const { return new RelativeState(*this); @@ -14621,7 +15466,7 @@ namespace DUNE FormationMonitor(void); - Message* + FormationMonitor* clone(void) const { return new FormationMonitor(*this); @@ -14721,7 +15566,7 @@ namespace DUNE Dislodge(void); - Message* + Dislodge* clone(void) const { return new Dislodge(*this); @@ -14863,7 +15708,7 @@ namespace DUNE Formation(void); - Message* + Formation* clone(void) const { return new Formation(*this); @@ -14960,7 +15805,7 @@ namespace DUNE Launch(void); - Message* + Launch* clone(void) const { return new Launch(*this); @@ -15041,7 +15886,7 @@ namespace DUNE Drop(void); - Message* + Drop* clone(void) const { return new Drop(*this); @@ -15133,7 +15978,7 @@ namespace DUNE ScheduledGoto(void); - Message* + ScheduledGoto* clone(void) const { return new ScheduledGoto(*this); @@ -15233,7 +16078,7 @@ namespace DUNE RowsCoverage(void); - Message* + RowsCoverage* clone(void) const { return new RowsCoverage(*this); @@ -15320,7 +16165,7 @@ namespace DUNE Sample(void); - Message* + Sample* clone(void) const { return new Sample(*this); @@ -15385,7 +16230,7 @@ namespace DUNE ImageTracking(void); - Message* + ImageTracking* clone(void) const { return new ImageTracking(*this); @@ -15454,7 +16299,7 @@ namespace DUNE Takeoff(void); - Message* + Takeoff* clone(void) const { return new Takeoff(*this); @@ -15541,7 +16386,7 @@ namespace DUNE Land(void); - Message* + Land* clone(void) const { return new Land(*this); @@ -15641,7 +16486,7 @@ namespace DUNE AutonomousSection(void); - Message* + AutonomousSection* clone(void) const { return new AutonomousSection(*this); @@ -15738,7 +16583,7 @@ namespace DUNE FollowPoint(void); - Message* + FollowPoint* clone(void) const { return new FollowPoint(*this); @@ -15790,67 +16635,35 @@ namespace DUNE fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Vehicle State. - class VehicleState: public Message + //! Alignment Maneuver. + class Alignment: public Maneuver { public: - //! Operation Mode. - enum OperationModeEnum - { - //! Service. - VS_SERVICE = 0, - //! Calibration. - VS_CALIBRATION = 1, - //! Error. - VS_ERROR = 2, - //! Maneuver. - VS_MANEUVER = 3, - //! External Control. - VS_EXTERNAL = 4, - //! Boot. - VS_BOOT = 5 - }; - - //! Flags. - enum FlagsBits - { - //! Maneuver Done. - VFLG_MANEUVER_DONE = 0x01 - }; - - //! Operation Mode. - uint8_t op_mode; - //! Errors -- Count. - uint8_t error_count; - //! Errors -- Entities. - std::string error_ents; - //! Maneuver -- Type. - uint16_t maneuver_type; - //! Maneuver -- Start Time. - fp64_t maneuver_stime; - //! Maneuver -- ETA. - uint16_t maneuver_eta; - //! Control Loops. - uint32_t control_loops; - //! Flags. - uint8_t flags; - //! Last Error -- Description. - std::string last_error; - //! Last Error -- Time. - fp64_t last_error_time; + //! Timeout. + uint16_t timeout; + //! Latitude WGS-84. + fp64_t lat; + //! Longitude WGS-84. + fp64_t lon; + //! Speed. + fp32_t speed; + //! Speed Units. + uint8_t speed_units; + //! Custom settings for maneuver. + std::string custom; static uint16_t getIdStatic(void) { - return 500; + return 495; } - VehicleState(void); + Alignment(void); - Message* + Alignment* clone(void) const { - return new VehicleState(*this); + return new Alignment(*this); } void @@ -15874,86 +16687,79 @@ namespace DUNE uint16_t getId(void) const { - return VehicleState::getIdStatic(); + return Alignment::getIdStatic(); } const char* getName(void) const { - return "VehicleState"; + return "Alignment"; } unsigned getFixedSerializationSize(void) const { - return 27; + return 23; } unsigned getVariableSerializationSize(void) const { - return IMC::getSerializationSize(error_ents) + IMC::getSerializationSize(last_error); + return IMC::getSerializationSize(custom); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Vehicle Command. - class VehicleCommand: public Message + //! Station Keeping Extended. + class StationKeepingExtended: public Maneuver { public: - //! Type. - enum TypeEnum - { - //! Request. - VC_REQUEST = 0, - //! Reply -- Success. - VC_SUCCESS = 1, - //! Reply -- In Progress. - VC_IN_PROGRESS = 2, - //! Reply -- Failure. - VC_FAILURE = 3 - }; - - //! Command. - enum CommandEnum + //! Flags. + enum FlagsBits { - //! Execute Maneuver. - VC_EXEC_MANEUVER = 0, - //! Stop Maneuver. - VC_STOP_MANEUVER = 1, - //! Start Calibration. - VC_START_CALIBRATION = 2, - //! Stop Calibration. - VC_STOP_CALIBRATION = 3 + //! Keep safe behaviour. + FLG_KEEP_SAFE = 0x01 }; - //! Type. - uint8_t type; - //! Request ID. - uint16_t request_id; - //! Command. - uint8_t command; - //! Maneuver. - InlineMessage maneuver; - //! Calibration Time. - uint16_t calib_time; - //! Info. - std::string info; + //! Latitude WGS-84. + fp64_t lat; + //! Longitude WGS-84. + fp64_t lon; + //! Z Reference. + fp32_t z; + //! Z Units. + uint8_t z_units; + //! Radius. + fp32_t radius; + //! Duration. + uint16_t duration; + //! Speed. + fp32_t speed; + //! Speed Units. + uint8_t speed_units; + //! PopUp Period. + uint16_t popup_period; + //! PopUp Duration. + uint16_t popup_duration; + //! Flags. + uint8_t flags; + //! Custom settings for maneuver. + std::string custom; static uint16_t getIdStatic(void) { - return 501; + return 496; } - VehicleCommand(void); + StationKeepingExtended(void); - Message* + StationKeepingExtended* clone(void) const { - return new VehicleCommand(*this); + return new StationKeepingExtended(*this); } void @@ -15977,91 +16783,53 @@ namespace DUNE uint16_t getId(void) const { - return VehicleCommand::getIdStatic(); + return StationKeepingExtended::getIdStatic(); } const char* getName(void) const { - return "VehicleCommand"; + return "StationKeepingExtended"; } unsigned getFixedSerializationSize(void) const { - return 6; + return 37; } unsigned getVariableSerializationSize(void) const { - return maneuver.getSerializationSize() + IMC::getSerializationSize(info); + return IMC::getSerializationSize(custom); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; - - protected: - void - setTimeStampNested(double value__); - - void - setSourceNested(uint16_t value__); - - void - setSourceEntityNested(uint8_t value__); - - void - setDestinationNested(uint16_t value__); - - void - setDestinationEntityNested(uint8_t value__); }; - //! Monitor Entity State. - class MonitorEntityState: public Message + //! Maneuver Done. + class ManeuverDone: public Message { public: - //! Command. - enum CommandEnum - { - //! Reset to defaults. - MES_RESET = 0, - //! Enable Monitoring. - MES_ENABLE = 1, - //! Disable Monitoring. - MES_DISABLE = 2, - //! Enable Monitoring (exclusive - disables all others). - MES_ENABLE_EXCLUSIVE = 3, - //! Status Report. - MES_STATUS = 4 - }; - - //! Command. - uint8_t command; - //! Entity Names. - std::string entities; static uint16_t getIdStatic(void) { - return 502; + return 497; } - MonitorEntityState(void); + ManeuverDone(void); - Message* + ManeuverDone* clone(void) const { - return new MonitorEntityState(*this); + return new ManeuverDone(*this); } void clear(void); - bool - fieldsEqual(const Message& msg__) const; - int validate(void) const; @@ -16077,64 +16845,70 @@ namespace DUNE uint16_t getId(void) const { - return MonitorEntityState::getIdStatic(); + return ManeuverDone::getIdStatic(); } const char* getName(void) const { - return "MonitorEntityState"; + return "ManeuverDone"; } unsigned getFixedSerializationSize(void) const { - return 1; - } - - unsigned - getVariableSerializationSize(void) const - { - return IMC::getSerializationSize(entities); + return 0; } - - void - fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Entity Monitoring State. - class EntityMonitoringState: public Message + //! Magnetometer Maneuver. + class Magnetometer: public Maneuver { public: - //! Entities monitored - Count. - uint8_t mcount; - //! Entities monitored - Names. - std::string mnames; - //! Entities with errors - Count. - uint8_t ecount; - //! Entities with errors - Names. - std::string enames; - //! Entities with critical errors - Count. - uint8_t ccount; - //! Entities with critical errors - Names. - std::string cnames; - //! Last Error -- Description. - std::string last_error; - //! Last Error -- Time. - fp64_t last_error_time; + //! Direction. + enum DirectionEnum + { + //! Clockwise First. + MD_CLOCKW_FIRST = 0, + //! Counter Clockwise First. + MD_CCLOCKW_FIRST = 1 + }; + + //! Timeout. + uint16_t timeout; + //! Latitude WGS-84. + fp64_t lat; + //! Longitude WGS-84. + fp64_t lon; + //! Z Reference. + fp32_t z; + //! Z Units. + uint8_t z_units; + //! Speed. + fp32_t speed; + //! Speed Units. + uint8_t speed_units; + //! Bearing. + fp64_t bearing; + //! Width. + fp32_t width; + //! Direction. + uint8_t direction; + //! Custom settings for maneuver. + std::string custom; static uint16_t getIdStatic(void) { - return 503; + return 499; } - EntityMonitoringState(void); + Magnetometer(void); - Message* + Magnetometer* clone(void) const { - return new EntityMonitoringState(*this); + return new Magnetometer(*this); } void @@ -16158,72 +16932,1212 @@ namespace DUNE uint16_t getId(void) const { - return EntityMonitoringState::getIdStatic(); + return Magnetometer::getIdStatic(); } const char* getName(void) const { - return "EntityMonitoringState"; + return "Magnetometer"; } unsigned getFixedSerializationSize(void) const { - return 11; + return 41; } unsigned getVariableSerializationSize(void) const { - return IMC::getSerializationSize(mnames) + IMC::getSerializationSize(enames) + IMC::getSerializationSize(cnames) + IMC::getSerializationSize(last_error); + return IMC::getSerializationSize(custom); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Operational Limits. - class OperationalLimits: public Message + //! Vehicle State. + class VehicleState: public Message { public: - //! Field Indicator Mask. - uint8_t mask; - //! Maximum Depth. - fp32_t max_depth; - //! Minimum Altitude. - fp32_t min_altitude; - //! Maximum Altitude. - fp32_t max_altitude; - //! Minimum Speed. - fp32_t min_speed; - //! Maximum Speed. - fp32_t max_speed; - //! Maximum Vertical Rate. - fp32_t max_vrate; - //! Area -- WGS-84 Latitude. - fp64_t lat; - //! Area -- WGS-84 Longitude. - fp64_t lon; - //! Area -- Orientation. - fp32_t orientation; - //! Area -- Width. - fp32_t width; - //! Area -- Length. - fp32_t length; - - static uint16_t - getIdStatic(void) - { - return 504; - } - - OperationalLimits(void); - - Message* - clone(void) const + //! Operation Mode. + enum OperationModeEnum { - return new OperationalLimits(*this); + //! Service. + VS_SERVICE = 0, + //! Calibration. + VS_CALIBRATION = 1, + //! Error. + VS_ERROR = 2, + //! Maneuver. + VS_MANEUVER = 3, + //! External Control. + VS_EXTERNAL = 4, + //! Boot. + VS_BOOT = 5 + }; + + //! Flags. + enum FlagsBits + { + //! Maneuver Done. + VFLG_MANEUVER_DONE = 0x01 + }; + + //! Operation Mode. + uint8_t op_mode; + //! Errors -- Count. + uint8_t error_count; + //! Errors -- Entities. + std::string error_ents; + //! Maneuver -- Type. + uint16_t maneuver_type; + //! Maneuver -- Start Time. + fp64_t maneuver_stime; + //! Maneuver -- ETA. + uint16_t maneuver_eta; + //! Control Loops. + uint32_t control_loops; + //! Flags. + uint8_t flags; + //! Last Error -- Description. + std::string last_error; + //! Last Error -- Time. + fp64_t last_error_time; + + static uint16_t + getIdStatic(void) + { + return 500; + } + + VehicleState(void); + + VehicleState* + clone(void) const + { + return new VehicleState(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return VehicleState::getIdStatic(); + } + + const char* + getName(void) const + { + return "VehicleState"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 27; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(error_ents) + IMC::getSerializationSize(last_error); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Vehicle Command. + class VehicleCommand: public Message + { + public: + //! Type. + enum TypeEnum + { + //! Request. + VC_REQUEST = 0, + //! Reply -- Success. + VC_SUCCESS = 1, + //! Reply -- In Progress. + VC_IN_PROGRESS = 2, + //! Reply -- Failure. + VC_FAILURE = 3 + }; + + //! Command. + enum CommandEnum + { + //! Execute Maneuver. + VC_EXEC_MANEUVER = 0, + //! Stop Maneuver. + VC_STOP_MANEUVER = 1, + //! Start Calibration. + VC_START_CALIBRATION = 2, + //! Stop Calibration. + VC_STOP_CALIBRATION = 3 + }; + + //! Type. + uint8_t type; + //! Request ID. + uint16_t request_id; + //! Command. + uint8_t command; + //! Maneuver. + InlineMessage maneuver; + //! Calibration Time. + uint16_t calib_time; + //! Info. + std::string info; + + static uint16_t + getIdStatic(void) + { + return 501; + } + + VehicleCommand(void); + + VehicleCommand* + clone(void) const + { + return new VehicleCommand(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return VehicleCommand::getIdStatic(); + } + + const char* + getName(void) const + { + return "VehicleCommand"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 6; + } + + unsigned + getVariableSerializationSize(void) const + { + return maneuver.getSerializationSize() + IMC::getSerializationSize(info); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + + protected: + void + setTimeStampNested(double value__); + + void + setSourceNested(uint16_t value__); + + void + setSourceEntityNested(uint8_t value__); + + void + setDestinationNested(uint16_t value__); + + void + setDestinationEntityNested(uint8_t value__); + }; + + //! Monitor Entity State. + class MonitorEntityState: public Message + { + public: + //! Command. + enum CommandEnum + { + //! Reset to defaults. + MES_RESET = 0, + //! Enable Monitoring. + MES_ENABLE = 1, + //! Disable Monitoring. + MES_DISABLE = 2, + //! Enable Monitoring (exclusive - disables all others). + MES_ENABLE_EXCLUSIVE = 3, + //! Status Report. + MES_STATUS = 4 + }; + + //! Command. + uint8_t command; + //! Entity Names. + std::string entities; + + static uint16_t + getIdStatic(void) + { + return 502; + } + + MonitorEntityState(void); + + MonitorEntityState* + clone(void) const + { + return new MonitorEntityState(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return MonitorEntityState::getIdStatic(); + } + + const char* + getName(void) const + { + return "MonitorEntityState"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 1; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(entities); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Entity Monitoring State. + class EntityMonitoringState: public Message + { + public: + //! Entities monitored - Count. + uint8_t mcount; + //! Entities monitored - Names. + std::string mnames; + //! Entities with errors - Count. + uint8_t ecount; + //! Entities with errors - Names. + std::string enames; + //! Entities with critical errors - Count. + uint8_t ccount; + //! Entities with critical errors - Names. + std::string cnames; + //! Last Error -- Description. + std::string last_error; + //! Last Error -- Time. + fp64_t last_error_time; + + static uint16_t + getIdStatic(void) + { + return 503; + } + + EntityMonitoringState(void); + + EntityMonitoringState* + clone(void) const + { + return new EntityMonitoringState(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return EntityMonitoringState::getIdStatic(); + } + + const char* + getName(void) const + { + return "EntityMonitoringState"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 11; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(mnames) + IMC::getSerializationSize(enames) + IMC::getSerializationSize(cnames) + IMC::getSerializationSize(last_error); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Operational Limits. + class OperationalLimits: public Message + { + public: + //! Field Indicator Mask. + uint8_t mask; + //! Maximum Depth. + fp32_t max_depth; + //! Minimum Altitude. + fp32_t min_altitude; + //! Maximum Altitude. + fp32_t max_altitude; + //! Minimum Speed. + fp32_t min_speed; + //! Maximum Speed. + fp32_t max_speed; + //! Maximum Vertical Rate. + fp32_t max_vrate; + //! Area -- WGS-84 Latitude. + fp64_t lat; + //! Area -- WGS-84 Longitude. + fp64_t lon; + //! Area -- Orientation. + fp32_t orientation; + //! Area -- Width. + fp32_t width; + //! Area -- Length. + fp32_t length; + + static uint16_t + getIdStatic(void) + { + return 504; + } + + OperationalLimits(void); + + OperationalLimits* + clone(void) const + { + return new OperationalLimits(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return OperationalLimits::getIdStatic(); + } + + const char* + getName(void) const + { + return "OperationalLimits"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 53; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Get Operational Limits. + class GetOperationalLimits: public Message + { + public: + + static uint16_t + getIdStatic(void) + { + return 505; + } + + GetOperationalLimits(void); + + GetOperationalLimits* + clone(void) const + { + return new GetOperationalLimits(*this); + } + + void + clear(void); + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return GetOperationalLimits::getIdStatic(); + } + + const char* + getName(void) const + { + return "GetOperationalLimits"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 0; + } + }; + + //! Calibration. + class Calibration: public Message + { + public: + //! Duration. + uint16_t duration; + + static uint16_t + getIdStatic(void) + { + return 506; + } + + Calibration(void); + + Calibration* + clone(void) const + { + return new Calibration(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return Calibration::getIdStatic(); + } + + const char* + getName(void) const + { + return "Calibration"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 2; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Control Loops. + class ControlLoops: public Message + { + public: + //! Enable. + enum EnableEnum + { + //! Disable. + CL_DISABLE = 0, + //! Enable. + CL_ENABLE = 1 + }; + + //! Enable. + uint8_t enable; + //! Control Loop Mask. + uint32_t mask; + //! Scope Time Reference. + uint32_t scope_ref; + + static uint16_t + getIdStatic(void) + { + return 507; + } + + ControlLoops(void); + + ControlLoops* + clone(void) const + { + return new ControlLoops(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return ControlLoops::getIdStatic(); + } + + const char* + getName(void) const + { + return "ControlLoops"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 9; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Vehicle Medium. + class VehicleMedium: public Message + { + public: + //! Medium. + enum MediumEnum + { + //! Ground. + VM_GROUND = 0, + //! Air. + VM_AIR = 1, + //! Water. + VM_WATER = 2, + //! Underwater. + VM_UNDERWATER = 3, + //! Unknown. + VM_UNKNOWN = 4 + }; + + //! Medium. + uint8_t medium; + + static uint16_t + getIdStatic(void) + { + return 508; + } + + VehicleMedium(void); + + VehicleMedium* + clone(void) const + { + return new VehicleMedium(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return VehicleMedium::getIdStatic(); + } + + const char* + getName(void) const + { + return "VehicleMedium"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 1; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Collision. + class Collision: public Message + { + public: + //! Type. + enum TypeBits + { + //! X-axis. + CD_X = 0x01, + //! Y-axis. + CD_Y = 0x02, + //! Z-axis. + CD_Z = 0x04, + //! Impact. + CD_IMPACT = 0x08 + }; + + //! Collision value. + fp32_t value; + //! Type. + uint8_t type; + + static uint16_t + getIdStatic(void) + { + return 509; + } + + Collision(void); + + Collision* + clone(void) const + { + return new Collision(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return Collision::getIdStatic(); + } + + const char* + getName(void) const + { + return "Collision"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 5; + } + + fp64_t + getValueFP(void) const; + + void + setValueFP(fp64_t val); + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Formation Tracking State. + class FormState: public Message + { + public: + //! Position Mismatch Monitor. + enum PositionMismatchMonitorEnum + { + //! Ok. + POS_OK = 0, + //! Warning threshold. + POS_WRN = 1, + //! Limit threshold. + POS_LIM = 2 + }; + + //! Communications Monitor. + enum CommunicationsMonitorEnum + { + //! Ok. + COMMS_OK = 0, + //! Timeout. + COMMS_TIMEOUT = 1 + }; + + //! Convergence. + enum ConvergenceEnum + { + //! Ok. + CONV_OK = 0, + //! Timeout. + CONV_TIMEOUT = 1 + }; + + //! Position Mismatch. + fp32_t possimerr; + //! Convergence. + fp32_t converg; + //! Stream Turbulence. + fp32_t turbulence; + //! Position Mismatch Monitor. + uint8_t possimmon; + //! Communications Monitor. + uint8_t commmon; + //! Convergence. + uint8_t convergmon; + + static uint16_t + getIdStatic(void) + { + return 510; + } + + FormState(void); + + FormState* + clone(void) const + { + return new FormState(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return FormState::getIdStatic(); + } + + const char* + getName(void) const + { + return "FormState"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 15; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Autopilot Mode. + class AutopilotMode: public Message + { + public: + //! Autonomy Level. + enum AutonomyLevelEnum + { + //! Manual. + AL_MANUAL = 0, + //! Assisted. + AL_ASSISTED = 1, + //! Auto. + AL_AUTO = 2 + }; + + //! Autonomy Level. + uint8_t autonomy; + //! Mode. + std::string mode; + + static uint16_t + getIdStatic(void) + { + return 511; + } + + AutopilotMode(void); + + AutopilotMode* + clone(void) const + { + return new AutopilotMode(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return AutopilotMode::getIdStatic(); + } + + const char* + getName(void) const + { + return "AutopilotMode"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 1; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(mode); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Formation Tracking State. + class FormationState: public Message + { + public: + //! Type. + enum TypeEnum + { + //! Request. + FC_REQUEST = 0, + //! Report. + FC_REPORT = 1 + }; + + //! Operation. + enum OperationEnum + { + //! Start. + OP_START = 0, + //! Stop. + OP_STOP = 1 + }; + + //! Position Mismatch Monitor. + enum PositionMismatchMonitorEnum + { + //! Ok. + POS_OK = 0, + //! Warning threshold. + POS_WRN = 1, + //! Limit threshold. + POS_LIM = 2 + }; + + //! Communications Monitor. + enum CommunicationsMonitorEnum + { + //! Ok. + COMMS_OK = 0, + //! Timeout. + COMMS_TIMEOUT = 1 + }; + + //! Convergence. + enum ConvergenceEnum + { + //! Ok. + CONV_OK = 0, + //! Timeout. + CONV_TIMEOUT = 1 + }; + + //! Type. + uint8_t type; + //! Operation. + uint8_t op; + //! Position Mismatch. + fp32_t possimerr; + //! Convergence. + fp32_t converg; + //! Stream Turbulence. + fp32_t turbulence; + //! Position Mismatch Monitor. + uint8_t possimmon; + //! Communications Monitor. + uint8_t commmon; + //! Convergence. + uint8_t convergmon; + + static uint16_t + getIdStatic(void) + { + return 512; + } + + FormationState(void); + + FormationState* + clone(void) const + { + return new FormationState(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return FormationState::getIdStatic(); + } + + const char* + getName(void) const + { + return "FormationState"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 17; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Report Control. + class ReportControl: public Message + { + public: + //! Operation. + enum OperationEnum + { + //! Request Start of Reports. + OP_REQUEST_START = 0, + //! Report Started. + OP_STARTED = 1, + //! Request Stop of Reports. + OP_REQUEST_STOP = 2, + //! Report Stopped. + OP_STOPPED = 3, + //! Request Single Reports. + OP_REQUEST_REPORT = 4, + //! Single Report Sent. + OP_REPORT_SENT = 5 + }; + + //! Communication Interface. + enum CommunicationInterfaceBits + { + //! Acoustic. + CI_ACOUSTIC = 0x01, + //! Satellite. + CI_SATELLITE = 0x02, + //! GSM. + CI_GSM = 0x04, + //! Mobile. + CI_MOBILE = 0x08, + //! Radio. + CI_RADIO = 0x10 + }; + + //! Operation. + uint8_t op; + //! Communication Interface. + uint8_t comm_interface; + //! Period. + uint16_t period; + //! Destination System. + std::string sys_dst; + + static uint16_t + getIdStatic(void) + { + return 513; + } + + ReportControl(void); + + ReportControl* + clone(void) const + { + return new ReportControl(*this); } void @@ -16247,47 +18161,76 @@ namespace DUNE uint16_t getId(void) const { - return OperationalLimits::getIdStatic(); + return ReportControl::getIdStatic(); } const char* getName(void) const { - return "OperationalLimits"; + return "ReportControl"; } unsigned getFixedSerializationSize(void) const { - return 53; + return 4; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(sys_dst); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Get Operational Limits. - class GetOperationalLimits: public Message + //! State Report. + class StateReport: public Message { public: + //! Time Stamp. + uint32_t stime; + //! Latitude. + fp32_t latitude; + //! Longitude. + fp32_t longitude; + //! Altitude. + uint16_t altitude; + //! Depth. + uint16_t depth; + //! Heading. + uint16_t heading; + //! Speed. + int16_t speed; + //! Fuel. + int8_t fuel; + //! Execution State. + int8_t exec_state; + //! Plan Checksum. + uint16_t plan_checksum; static uint16_t getIdStatic(void) { - return 505; + return 514; } - GetOperationalLimits(void); + StateReport(void); - Message* + StateReport* clone(void) const { - return new GetOperationalLimits(*this); + return new StateReport(*this); } void clear(void); + bool + fieldsEqual(const Message& msg__) const; + int validate(void) const; @@ -16303,41 +18246,94 @@ namespace DUNE uint16_t getId(void) const { - return GetOperationalLimits::getIdStatic(); + return StateReport::getIdStatic(); } const char* getName(void) const { - return "GetOperationalLimits"; + return "StateReport"; } unsigned getFixedSerializationSize(void) const { - return 0; + return 24; } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Calibration. - class Calibration: public Message + //! Transmission Request. + class TransmissionRequest: public Message { public: - //! Duration. - uint16_t duration; + //! Communication Mean. + enum CommunicationMeanEnum + { + //! WiFi. + CMEAN_WIFI = 0, + //! Acoustic. + CMEAN_ACOUSTIC = 1, + //! Satellite. + CMEAN_SATELLITE = 2, + //! GSM. + CMEAN_GSM = 3, + //! Any. + CMEAN_ANY = 4, + //! All. + CMEAN_ALL = 5 + }; + + //! Data Mode. + enum DataModeEnum + { + //! Inline Message. + DMODE_INLINEMSG = 0, + //! Text. + DMODE_TEXT = 1, + //! Raw Data. + DMODE_RAW = 2, + //! Abort. + DMODE_ABORT = 3, + //! Range. + DMODE_RANGE = 4, + //! Reverse Range. + DMODE_REVERSE_RANGE = 5 + }; + + //! Request Identifier. + uint16_t req_id; + //! Communication Mean. + uint8_t comm_mean; + //! Destination System. + std::string destination; + //! Deadline. + fp64_t deadline; + //! Range. + fp32_t range; + //! Data Mode. + uint8_t data_mode; + //! Message Data. + InlineMessage msg_data; + //! Text Data. + std::string txt_data; + //! Raw Data. + std::vector raw_data; static uint16_t getIdStatic(void) { - return 506; + return 515; } - Calibration(void); + TransmissionRequest(void); - Message* + TransmissionRequest* clone(void) const { - return new Calibration(*this); + return new TransmissionRequest(*this); } void @@ -16361,57 +18357,93 @@ namespace DUNE uint16_t getId(void) const { - return Calibration::getIdStatic(); + return TransmissionRequest::getIdStatic(); } const char* getName(void) const { - return "Calibration"; + return "TransmissionRequest"; } unsigned getFixedSerializationSize(void) const { - return 2; + return 16; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(destination) + msg_data.getSerializationSize() + IMC::getSerializationSize(txt_data) + IMC::getSerializationSize(raw_data); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + + protected: + void + setTimeStampNested(double value__); + + void + setSourceNested(uint16_t value__); + + void + setSourceEntityNested(uint8_t value__); + + void + setDestinationNested(uint16_t value__); + + void + setDestinationEntityNested(uint8_t value__); }; - //! Control Loops. - class ControlLoops: public Message + //! Transmission Status. + class TransmissionStatus: public Message { public: - //! Enable. - enum EnableEnum + //! Status. + enum StatusEnum { - //! Disable. - CL_DISABLE = 0, - //! Enable. - CL_ENABLE = 1 + //! In progress. + TSTAT_IN_PROGRESS = 0, + //! Sent. + TSTAT_SENT = 1, + //! Delivered. + TSTAT_DELIVERED = 51, + //! Delivery is unknown. + TSTAT_MAYBE_DELIVERED = 52, + //! Range received. + TSTAT_RANGE_RECEIVED = 60, + //! Input Error. + TSTAT_INPUT_FAILURE = 101, + //! Temporary Error. + TSTAT_TEMPORARY_FAILURE = 102, + //! Permanent Failure. + TSTAT_PERMANENT_FAILURE = 103 }; - //! Enable. - uint8_t enable; - //! Control Loop Mask. - uint32_t mask; - //! Scope Time Reference. - uint32_t scope_ref; + //! Request Identifier. + uint16_t req_id; + //! Status. + uint8_t status; + //! Range. + fp32_t range; + //! Information. + std::string info; static uint16_t getIdStatic(void) { - return 507; + return 516; } - ControlLoops(void); + TransmissionStatus(void); - Message* + TransmissionStatus* clone(void) const { - return new ControlLoops(*this); + return new TransmissionStatus(*this); } void @@ -16435,59 +18467,56 @@ namespace DUNE uint16_t getId(void) const { - return ControlLoops::getIdStatic(); + return TransmissionStatus::getIdStatic(); } const char* getName(void) const { - return "ControlLoops"; + return "TransmissionStatus"; } unsigned getFixedSerializationSize(void) const { - return 9; + return 7; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(info); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Vehicle Medium. - class VehicleMedium: public Message + //! SMS Transmission Request. + class SmsRequest: public Message { public: - //! Medium. - enum MediumEnum - { - //! Ground. - VM_GROUND = 0, - //! Air. - VM_AIR = 1, - //! Water. - VM_WATER = 2, - //! Underwater. - VM_UNDERWATER = 3, - //! Unknown. - VM_UNKNOWN = 4 - }; - - //! Medium. - uint8_t medium; + //! Request Identifier. + uint16_t req_id; + //! Destination. + std::string destination; + //! Timeout. + fp64_t timeout; + //! SMS Text. + std::string sms_text; static uint16_t getIdStatic(void) { - return 508; + return 517; } - VehicleMedium(void); + SmsRequest(void); - Message* + SmsRequest* clone(void) const { - return new VehicleMedium(*this); + return new SmsRequest(*this); } void @@ -16511,59 +18540,67 @@ namespace DUNE uint16_t getId(void) const { - return VehicleMedium::getIdStatic(); + return SmsRequest::getIdStatic(); } const char* getName(void) const { - return "VehicleMedium"; + return "SmsRequest"; } unsigned getFixedSerializationSize(void) const { - return 1; + return 10; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(destination) + IMC::getSerializationSize(sms_text); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Collision. - class Collision: public Message + //! SMS Transmission Status. + class SmsStatus: public Message { public: - //! Type. - enum TypeBits + //! Status. + enum StatusEnum { - //! X-axis. - CD_X = 0x01, - //! Y-axis. - CD_Y = 0x02, - //! Z-axis. - CD_Z = 0x04, - //! Impact. - CD_IMPACT = 0x08 + //! Queued. + SMSSTAT_QUEUED = 0, + //! Sent. + SMSSTAT_SENT = 1, + //! Input Error. + SMSSTAT_INPUT_FAILURE = 101, + //! Error trying to send sms. + SMSSTAT_ERROR = 102 }; - //! Collision value. - fp32_t value; - //! Type. - uint8_t type; + //! Request Identifier. + uint16_t req_id; + //! Status. + uint8_t status; + //! Information. + std::string info; static uint16_t getIdStatic(void) { - return 509; + return 518; } - Collision(void); + SmsStatus(void); - Message* + SmsStatus* clone(void) const { - return new Collision(*this); + return new SmsStatus(*this); } void @@ -16587,89 +18624,65 @@ namespace DUNE uint16_t getId(void) const { - return Collision::getIdStatic(); + return SmsStatus::getIdStatic(); } const char* getName(void) const { - return "Collision"; + return "SmsStatus"; } unsigned getFixedSerializationSize(void) const { - return 5; + return 3; } - fp64_t - getValueFP(void) const; - - void - setValueFP(fp64_t val); + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(info); + } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Formation Tracking State. - class FormState: public Message + //! VTOL State. + class VtolState: public Message { public: - //! Position Mismatch Monitor. - enum PositionMismatchMonitorEnum - { - //! Ok. - POS_OK = 0, - //! Warning threshold. - POS_WRN = 1, - //! Limit threshold. - POS_LIM = 2 - }; - - //! Communications Monitor. - enum CommunicationsMonitorEnum - { - //! Ok. - COMMS_OK = 0, - //! Timeout. - COMMS_TIMEOUT = 1 - }; - - //! Convergence. - enum ConvergenceEnum + //! State. + enum StateEnum { - //! Ok. - CONV_OK = 0, - //! Timeout. - CONV_TIMEOUT = 1 + //! Undefined. + VTOL_STATE_UNDEFINED = 0, + //! Transition to Fixed-Wing. + VTOL_STATE_TRANSITION_TO_FW = 1, + //! Transition to MultiCopter. + VTOL_STATE_TRANSITION_TO_MC = 2, + //! MutiCopter. + VTOL_STATE_MC = 3, + //! Fixed-Wing. + VTOL_STATE_FW = 4 }; - //! Position Mismatch. - fp32_t possimerr; - //! Convergence. - fp32_t converg; - //! Stream Turbulence. - fp32_t turbulence; - //! Position Mismatch Monitor. - uint8_t possimmon; - //! Communications Monitor. - uint8_t commmon; - //! Convergence. - uint8_t convergmon; + //! State. + uint8_t state; static uint16_t getIdStatic(void) { - return 510; + return 519; } - FormState(void); + VtolState(void); - Message* + VtolState* clone(void) const { - return new FormState(*this); + return new VtolState(*this); } void @@ -16693,57 +18706,53 @@ namespace DUNE uint16_t getId(void) const { - return FormState::getIdStatic(); + return VtolState::getIdStatic(); } const char* getName(void) const { - return "FormState"; + return "VtolState"; } unsigned getFixedSerializationSize(void) const { - return 15; + return 1; } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Autopilot Mode. - class AutopilotMode: public Message + //! Arming State. + class ArmingState: public Message { - public: - //! Autonomy Level. - enum AutonomyLevelEnum + public: + //! State. + enum StateEnum { - //! Manual. - AL_MANUAL = 0, - //! Assisted. - AL_ASSISTED = 1, - //! Auto. - AL_AUTO = 2 + //! Armed. + MOTORS_ARMED = 0, + //! Disarmed. + MOTORS_DISARMED = 1 }; - //! Autonomy Level. - uint8_t autonomy; - //! Mode. - std::string mode; + //! State. + uint8_t state; static uint16_t getIdStatic(void) { - return 511; + return 520; } - AutopilotMode(void); + ArmingState(void); - Message* + ArmingState* clone(void) const { - return new AutopilotMode(*this); + return new ArmingState(*this); } void @@ -16767,13 +18776,13 @@ namespace DUNE uint16_t getId(void) const { - return AutopilotMode::getIdStatic(); + return ArmingState::getIdStatic(); } const char* getName(void) const { - return "AutopilotMode"; + return "ArmingState"; } unsigned @@ -16782,96 +18791,35 @@ namespace DUNE return 1; } - unsigned - getVariableSerializationSize(void) const - { - return IMC::getSerializationSize(mode); - } - void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! Formation Tracking State. - class FormationState: public Message + //! TCP Transmission Request. + class TCPRequest: public Message { public: - //! Type. - enum TypeEnum - { - //! Request. - FC_REQUEST = 0, - //! Report. - FC_REPORT = 1 - }; - - //! Operation. - enum OperationEnum - { - //! Start. - OP_START = 0, - //! Stop. - OP_STOP = 1 - }; - - //! Position Mismatch Monitor. - enum PositionMismatchMonitorEnum - { - //! Ok. - POS_OK = 0, - //! Warning threshold. - POS_WRN = 1, - //! Limit threshold. - POS_LIM = 2 - }; - - //! Communications Monitor. - enum CommunicationsMonitorEnum - { - //! Ok. - COMMS_OK = 0, - //! Timeout. - COMMS_TIMEOUT = 1 - }; - - //! Convergence. - enum ConvergenceEnum - { - //! Ok. - CONV_OK = 0, - //! Timeout. - CONV_TIMEOUT = 1 - }; - - //! Type. - uint8_t type; - //! Operation. - uint8_t op; - //! Position Mismatch. - fp32_t possimerr; - //! Convergence. - fp32_t converg; - //! Stream Turbulence. - fp32_t turbulence; - //! Position Mismatch Monitor. - uint8_t possimmon; - //! Communications Monitor. - uint8_t commmon; - //! Convergence. - uint8_t convergmon; + //! Request Identifier. + uint16_t req_id; + //! Destination. + std::string destination; + //! Timeout. + fp64_t timeout; + //! Message Data. + InlineMessage msg_data; static uint16_t getIdStatic(void) { - return 512; + return 521; } - FormationState(void); + TCPRequest(void); - Message* + TCPRequest* clone(void) const { - return new FormationState(*this); + return new TCPRequest(*this); } void @@ -16895,80 +18843,87 @@ namespace DUNE uint16_t getId(void) const { - return FormationState::getIdStatic(); + return TCPRequest::getIdStatic(); } const char* getName(void) const { - return "FormationState"; + return "TCPRequest"; } unsigned getFixedSerializationSize(void) const { - return 17; + return 10; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(destination) + msg_data.getSerializationSize(); } void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + + protected: + void + setTimeStampNested(double value__); + + void + setSourceNested(uint16_t value__); + + void + setSourceEntityNested(uint8_t value__); + + void + setDestinationNested(uint16_t value__); + + void + setDestinationEntityNested(uint8_t value__); }; - //! Report Control. - class ReportControl: public Message + //! TCP Transmission Status. + class TCPStatus: public Message { public: - //! Operation. - enum OperationEnum - { - //! Request Start of Reports. - OP_REQUEST_START = 0, - //! Report Started. - OP_STARTED = 1, - //! Request Stop of Reports. - OP_REQUEST_STOP = 2, - //! Report Stopped. - OP_STOPPED = 3, - //! Request Single Reports. - OP_REQUEST_REPORT = 4, - //! Single Report Sent. - OP_REPORT_SENT = 5 - }; - - //! Communication Interface. - enum CommunicationInterfaceBits + //! Status. + enum StatusEnum { - //! Acoustic. - CI_ACOUSTIC = 0x01, - //! Satellite. - CI_SATELLITE = 0x02, - //! GSM. - CI_GSM = 0x04, - //! Mobile. - CI_MOBILE = 0x08 + //! Queued. + TCPSTAT_QUEUED = 0, + //! Sent. + TCPSTAT_SENT = 1, + //! Input Error. + TCPSTAT_INPUT_FAILURE = 100, + //! Host Unknown. + TCPSTAT_HOST_UNKNOWN = 101, + //! Can't Connect. + TCPSTAT_CANT_CONNECT = 102, + //! Error trying to send sms. + TCPSTAT_ERROR = 103 }; - //! Operation. - uint8_t op; - //! Communication Interface. - uint8_t comm_interface; - //! Period. - uint16_t period; - //! Destination System. - std::string sys_dst; + //! Request Identifier. + uint16_t req_id; + //! Status. + uint8_t status; + //! Information. + std::string info; static uint16_t getIdStatic(void) { - return 513; + return 522; } - ReportControl(void); + TCPStatus(void); - Message* + TCPStatus* clone(void) const { - return new ReportControl(*this); + return new TCPStatus(*this); } void @@ -16992,25 +18947,25 @@ namespace DUNE uint16_t getId(void) const { - return ReportControl::getIdStatic(); + return TCPStatus::getIdStatic(); } const char* getName(void) const { - return "ReportControl"; + return "TCPStatus"; } unsigned getFixedSerializationSize(void) const { - return 4; + return 3; } unsigned getVariableSerializationSize(void) const { - return IMC::getSerializationSize(sys_dst); + return IMC::getSerializationSize(info); } void @@ -17030,7 +18985,7 @@ namespace DUNE Abort(void); - Message* + Abort* clone(void) const { return new Abort(*this); @@ -17115,7 +19070,7 @@ namespace DUNE PlanVariable(void); - Message* + PlanVariable* clone(void) const { return new PlanVariable(*this); @@ -17188,7 +19143,7 @@ namespace DUNE PlanManeuver(void); - Message* + PlanManeuver* clone(void) const { return new PlanManeuver(*this); @@ -17277,7 +19232,7 @@ namespace DUNE PlanTransition(void); - Message* + PlanTransition* clone(void) const { return new PlanTransition(*this); @@ -17376,7 +19331,7 @@ namespace DUNE PlanSpecification(void); - Message* + PlanSpecification* clone(void) const { return new PlanSpecification(*this); @@ -17478,7 +19433,7 @@ namespace DUNE EmergencyControl(void); - Message* + EmergencyControl* clone(void) const { return new EmergencyControl(*this); @@ -17582,7 +19537,7 @@ namespace DUNE EmergencyControlState(void); - Message* + EmergencyControlState* clone(void) const { return new EmergencyControlState(*this); @@ -17693,7 +19648,7 @@ namespace DUNE PlanDB(void); - Message* + PlanDB* clone(void) const { return new PlanDB(*this); @@ -17786,7 +19741,7 @@ namespace DUNE PlanDBInformation(void); - Message* + PlanDBInformation* clone(void) const { return new PlanDBInformation(*this); @@ -17865,7 +19820,7 @@ namespace DUNE PlanDBState(void); - Message* + PlanDBState* clone(void) const { return new PlanDBState(*this); @@ -17995,7 +19950,7 @@ namespace DUNE PlanControl(void); - Message* + PlanControl* clone(void) const { return new PlanControl(*this); @@ -18116,7 +20071,7 @@ namespace DUNE PlanControlState(void); - Message* + PlanControlState* clone(void) const { return new PlanControlState(*this); @@ -18209,7 +20164,7 @@ namespace DUNE PlanGeneration(void); - Message* + PlanGeneration* clone(void) const { return new PlanGeneration(*this); @@ -18325,7 +20280,7 @@ namespace DUNE LeaderState(void); - Message* + LeaderState* clone(void) const { return new LeaderState(*this); @@ -18430,7 +20385,7 @@ namespace DUNE PlanStatistics(void); - Message* + PlanStatistics* clone(void) const { return new PlanStatistics(*this); @@ -18528,7 +20483,7 @@ namespace DUNE ReportedState(void); - Message* + ReportedState* clone(void) const { return new ReportedState(*this); @@ -18607,7 +20562,7 @@ namespace DUNE RemoteSensorInfo(void); - Message* + RemoteSensorInfo* clone(void) const { return new RemoteSensorInfo(*this); @@ -18678,7 +20633,7 @@ namespace DUNE MapPoint(void); - Message* + MapPoint* clone(void) const { return new MapPoint(*this); @@ -18768,7 +20723,7 @@ namespace DUNE MapFeature(void); - Message* + MapFeature* clone(void) const { return new MapFeature(*this); @@ -18853,7 +20808,7 @@ namespace DUNE Map(void); - Message* + Map* clone(void) const { return new Map(*this); @@ -18963,7 +20918,7 @@ namespace DUNE CcuEvent(void); - Message* + CcuEvent* clone(void) const { return new CcuEvent(*this); @@ -19048,7 +21003,7 @@ namespace DUNE VehicleLinks(void); - Message* + VehicleLinks* clone(void) const { return new VehicleLinks(*this); @@ -19135,7 +21090,7 @@ namespace DUNE TrexObservation(void); - Message* + TrexObservation* clone(void) const { return new TrexObservation(*this); @@ -19223,7 +21178,7 @@ namespace DUNE TrexCommand(void); - Message* + TrexCommand* clone(void) const { return new TrexCommand(*this); @@ -19311,7 +21266,7 @@ namespace DUNE TrexAttribute(void); - Message* + TrexAttribute* clone(void) const { return new TrexAttribute(*this); @@ -19382,7 +21337,7 @@ namespace DUNE TrexToken(void); - Message* + TrexToken* clone(void) const { return new TrexToken(*this); @@ -19484,7 +21439,7 @@ namespace DUNE TrexOperation(void); - Message* + TrexOperation* clone(void) const { return new TrexOperation(*this); @@ -19569,7 +21524,7 @@ namespace DUNE TrexPlan(void); - Message* + TrexPlan* clone(void) const { return new TrexPlan(*this); @@ -19654,7 +21609,7 @@ namespace DUNE Event(void); - Message* + Event* clone(void) const { return new Event(*this); @@ -19723,7 +21678,7 @@ namespace DUNE CompressedImage(void); - Message* + CompressedImage* clone(void) const { return new CompressedImage(*this); @@ -19796,7 +21751,7 @@ namespace DUNE ImageTxSettings(void); - Message* + ImageTxSettings* clone(void) const { return new ImageTxSettings(*this); @@ -19865,7 +21820,7 @@ namespace DUNE RemoteState(void); - Message* + RemoteState* clone(void) const { return new RemoteState(*this); @@ -19938,7 +21893,7 @@ namespace DUNE Target(void); - Message* + Target* clone(void) const { return new Target(*this); @@ -20007,7 +21962,7 @@ namespace DUNE EntityParameter(void); - Message* + EntityParameter* clone(void) const { return new EntityParameter(*this); @@ -20076,7 +22031,7 @@ namespace DUNE EntityParameters(void); - Message* + EntityParameters* clone(void) const { return new EntityParameters(*this); @@ -20163,7 +22118,7 @@ namespace DUNE QueryEntityParameters(void); - Message* + QueryEntityParameters* clone(void) const { return new QueryEntityParameters(*this); @@ -20232,7 +22187,7 @@ namespace DUNE SetEntityParameters(void); - Message* + SetEntityParameters* clone(void) const { return new SetEntityParameters(*this); @@ -20315,7 +22270,7 @@ namespace DUNE SaveEntityParameters(void); - Message* + SaveEntityParameters* clone(void) const { return new SaveEntityParameters(*this); @@ -20382,7 +22337,7 @@ namespace DUNE CreateSession(void); - Message* + CreateSession* clone(void) const { return new CreateSession(*this); @@ -20443,7 +22398,7 @@ namespace DUNE CloseSession(void); - Message* + CloseSession* clone(void) const { return new CloseSession(*this); @@ -20506,7 +22461,7 @@ namespace DUNE SessionSubscription(void); - Message* + SessionSubscription* clone(void) const { return new SessionSubscription(*this); @@ -20573,7 +22528,7 @@ namespace DUNE SessionKeepAlive(void); - Message* + SessionKeepAlive* clone(void) const { return new SessionKeepAlive(*this); @@ -20645,7 +22600,7 @@ namespace DUNE SessionStatus(void); - Message* + SessionStatus* clone(void) const { return new SessionStatus(*this); @@ -20706,7 +22661,7 @@ namespace DUNE PushEntityParameters(void); - Message* + PushEntityParameters* clone(void) const { return new PushEntityParameters(*this); @@ -20773,7 +22728,7 @@ namespace DUNE PopEntityParameters(void); - Message* + PopEntityParameters* clone(void) const { return new PopEntityParameters(*this); @@ -20851,7 +22806,7 @@ namespace DUNE IoEvent(void); - Message* + IoEvent* clone(void) const { return new IoEvent(*this); @@ -20913,7 +22868,9 @@ namespace DUNE //! Acknowledgement. UTF_ACK = 0x01, //! Delayed. - UTF_DELAYED = 0x02 + UTF_DELAYED = 0x02, + //! Forced. + UTF_FORCED = 0x04 }; //! Sequence Id. @@ -20933,7 +22890,7 @@ namespace DUNE UamTxFrame(void); - Message* + UamTxFrame* clone(void) const { return new UamTxFrame(*this); @@ -21015,7 +22972,7 @@ namespace DUNE UamRxFrame(void); - Message* + UamRxFrame* clone(void) const { return new UamRxFrame(*this); @@ -21085,7 +23042,15 @@ namespace DUNE //! Invalid address. UTS_INV_ADDR = 4, //! In Progress. - UTS_IP = 5 + UTS_IP = 5, + //! Unsupported operation. + UTS_UNSUPPORTED = 6, + //! Invalid transmission size. + UTS_INV_SIZE = 7, + //! Message has been sent. + UTS_SENT = 8, + //! Message has been acknowledged by the destination. + UTS_DELIVERED = 9 }; //! Sequence Id. @@ -21098,15 +23063,92 @@ namespace DUNE static uint16_t getIdStatic(void) { - return 816; + return 816; + } + + UamTxStatus(void); + + UamTxStatus* + clone(void) const + { + return new UamTxStatus(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return UamTxStatus::getIdStatic(); + } + + const char* + getName(void) const + { + return "UamTxStatus"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 3; + } + + unsigned + getVariableSerializationSize(void) const + { + return IMC::getSerializationSize(error); + } + + fp64_t + getValueFP(void) const; + + void + setValueFP(fp64_t val); + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! UamRxRange. + class UamRxRange: public Message + { + public: + //! Sequence Id. + uint16_t seq; + //! System. + std::string sys; + //! Value. + fp32_t value; + + static uint16_t + getIdStatic(void) + { + return 817; } - UamTxStatus(void); + UamRxRange(void); - Message* + UamRxRange* clone(void) const { - return new UamTxStatus(*this); + return new UamRxRange(*this); } void @@ -21130,25 +23172,25 @@ namespace DUNE uint16_t getId(void) const { - return UamTxStatus::getIdStatic(); + return UamRxRange::getIdStatic(); } const char* getName(void) const { - return "UamTxStatus"; + return "UamRxRange"; } unsigned getFixedSerializationSize(void) const { - return 3; + return 6; } unsigned getVariableSerializationSize(void) const { - return IMC::getSerializationSize(error); + return IMC::getSerializationSize(sys); } fp64_t @@ -21161,29 +23203,29 @@ namespace DUNE fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; - //! UamRxRange. - class UamRxRange: public Message + //! UamTxRange. + class UamTxRange: public Message { public: //! Sequence Id. uint16_t seq; - //! System. - std::string sys; - //! Value. - fp32_t value; + //! Destination System. + std::string sys_dst; + //! Timeout. + fp32_t timeout; static uint16_t getIdStatic(void) { - return 817; + return 818; } - UamRxRange(void); + UamTxRange(void); - Message* + UamTxRange* clone(void) const { - return new UamRxRange(*this); + return new UamTxRange(*this); } void @@ -21207,13 +23249,13 @@ namespace DUNE uint16_t getId(void) const { - return UamRxRange::getIdStatic(); + return UamTxRange::getIdStatic(); } const char* getName(void) const { - return "UamRxRange"; + return "UamTxRange"; } unsigned @@ -21225,15 +23267,9 @@ namespace DUNE unsigned getVariableSerializationSize(void) const { - return IMC::getSerializationSize(sys); + return IMC::getSerializationSize(sys_dst); } - fp64_t - getValueFP(void) const; - - void - setValueFP(fp64_t val); - void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; @@ -21274,7 +23310,7 @@ namespace DUNE FormCtrlParam(void); - Message* + FormCtrlParam* clone(void) const { return new FormCtrlParam(*this); @@ -21339,7 +23375,7 @@ namespace DUNE FormationEval(void); - Message* + FormationEval* clone(void) const { return new FormationEval(*this); @@ -21431,7 +23467,7 @@ namespace DUNE FormationControlParams(void); - Message* + FormationControlParams* clone(void) const { return new FormationControlParams(*this); @@ -21525,15 +23561,286 @@ namespace DUNE static uint16_t getIdStatic(void) { - return 823; + return 823; + } + + FormationEvaluation(void); + + FormationEvaluation* + clone(void) const + { + return new FormationEvaluation(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return FormationEvaluation::getIdStatic(); + } + + const char* + getName(void) const + { + return "FormationEvaluation"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 22; + } + + unsigned + getVariableSerializationSize(void) const + { + return controlparams.getSerializationSize(); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + + protected: + void + setTimeStampNested(double value__); + + void + setSourceNested(uint16_t value__); + + void + setSourceEntityNested(uint8_t value__); + + void + setDestinationNested(uint16_t value__); + + void + setDestinationEntityNested(uint8_t value__); + }; + + //! SOI Waypoint. + class SoiWaypoint: public Message + { + public: + //! Latitude. + fp32_t lat; + //! Longitude. + fp32_t lon; + //! Time Of Arrival. + uint32_t eta; + //! Duration. + uint16_t duration; + + static uint16_t + getIdStatic(void) + { + return 850; + } + + SoiWaypoint(void); + + SoiWaypoint* + clone(void) const + { + return new SoiWaypoint(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return SoiWaypoint::getIdStatic(); + } + + const char* + getName(void) const + { + return "SoiWaypoint"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 14; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! SOI Plan. + class SoiPlan: public Message + { + public: + //! Plan Identifier. + uint16_t plan_id; + //! Waypoints. + MessageList waypoints; + + static uint16_t + getIdStatic(void) + { + return 851; + } + + SoiPlan(void); + + SoiPlan* + clone(void) const + { + return new SoiPlan(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return SoiPlan::getIdStatic(); + } + + const char* + getName(void) const + { + return "SoiPlan"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 2; + } + + unsigned + getVariableSerializationSize(void) const + { + return waypoints.getSerializationSize(); + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + + protected: + void + setTimeStampNested(double value__); + + void + setSourceNested(uint16_t value__); + + void + setSourceEntityNested(uint8_t value__); + + void + setDestinationNested(uint16_t value__); + + void + setDestinationEntityNested(uint8_t value__); + }; + + //! SOI Command. + class SoiCommand: public Message + { + public: + //! Type. + enum TypeEnum + { + //! Request. + SOITYPE_REQUEST = 1, + //! Success. + SOITYPE_SUCCESS = 2, + //! Error. + SOITYPE_ERROR = 3 + }; + + //! Command. + enum CommandEnum + { + //! Execute Plan. + SOICMD_EXEC = 1, + //! Stop Execution. + SOICMD_STOP = 2, + //! Set Parameters. + SOICMD_SET_PARAMS = 3, + //! Get Parameters. + SOICMD_GET_PARAMS = 4, + //! Get Plan. + SOICMD_GET_PLAN = 5, + //! Resume Execution. + SOICMD_RESUME = 6 + }; + + //! Type. + uint8_t type; + //! Command. + uint8_t command; + //! Settings. + std::string settings; + //! Plan. + InlineMessage plan; + //! Extra Information. + std::string info; + + static uint16_t + getIdStatic(void) + { + return 852; } - FormationEvaluation(void); + SoiCommand(void); - Message* + SoiCommand* clone(void) const { - return new FormationEvaluation(*this); + return new SoiCommand(*this); } void @@ -21557,25 +23864,25 @@ namespace DUNE uint16_t getId(void) const { - return FormationEvaluation::getIdStatic(); + return SoiCommand::getIdStatic(); } const char* getName(void) const { - return "FormationEvaluation"; + return "SoiCommand"; } unsigned getFixedSerializationSize(void) const { - return 22; + return 2; } unsigned getVariableSerializationSize(void) const { - return controlparams.getSerializationSize(); + return IMC::getSerializationSize(settings) + plan.getSerializationSize() + IMC::getSerializationSize(info); } void @@ -21598,6 +23905,84 @@ namespace DUNE setDestinationEntityNested(uint8_t value__); }; + //! SOI State. + class SoiState: public Message + { + public: + //! State. + enum StateEnum + { + //! Executing. + SOISTATE_EXEC = 1, + //! Idle. + SOISTATE_IDLE = 2, + //! Inactive. + SOISTATE_INACTIVE = 3 + }; + + //! State. + uint8_t state; + //! Plan Identifier. + uint16_t plan_id; + //! Waypoint Identifier. + uint8_t wpt_id; + //! Settings Checksum. + uint16_t settings_chk; + + static uint16_t + getIdStatic(void) + { + return 853; + } + + SoiState(void); + + SoiState* + clone(void) const + { + return new SoiState(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return SoiState::getIdStatic(); + } + + const char* + getName(void) const + { + return "SoiState"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 6; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + //! Message Fragment. class MessagePart: public Message { @@ -21619,7 +24004,7 @@ namespace DUNE MessagePart(void); - Message* + MessagePart* clone(void) const { return new MessagePart(*this); @@ -21688,7 +24073,7 @@ namespace DUNE NeptusBlob(void); - Message* + NeptusBlob* clone(void) const { return new NeptusBlob(*this); @@ -21753,7 +24138,7 @@ namespace DUNE Aborted(void); - Message* + Aborted* clone(void) const { return new Aborted(*this); @@ -21812,7 +24197,7 @@ namespace DUNE UsblAngles(void); - Message* + UsblAngles* clone(void) const { return new UsblAngles(*this); @@ -21879,7 +24264,7 @@ namespace DUNE UsblPosition(void); - Message* + UsblPosition* clone(void) const { return new UsblPosition(*this); @@ -21948,7 +24333,7 @@ namespace DUNE UsblFix(void); - Message* + UsblFix* clone(void) const { return new UsblFix(*this); @@ -22011,7 +24396,7 @@ namespace DUNE ParametersXml(void); - Message* + ParametersXml* clone(void) const { return new ParametersXml(*this); @@ -22076,7 +24461,7 @@ namespace DUNE GetParametersXml(void); - Message* + GetParametersXml* clone(void) const { return new GetParametersXml(*this); @@ -22135,7 +24520,7 @@ namespace DUNE SetImageCoords(void); - Message* + SetImageCoords* clone(void) const { return new SetImageCoords(*this); @@ -22200,7 +24585,7 @@ namespace DUNE GetImageCoords(void); - Message* + GetImageCoords* clone(void) const { return new GetImageCoords(*this); @@ -22271,7 +24656,7 @@ namespace DUNE GetWorldCoordinates(void); - Message* + GetWorldCoordinates* clone(void) const { return new GetWorldCoordinates(*this); @@ -22348,7 +24733,7 @@ namespace DUNE UsblAnglesExtended(void); - Message* + UsblAnglesExtended* clone(void) const { return new UsblAnglesExtended(*this); @@ -22435,7 +24820,7 @@ namespace DUNE UsblPositionExtended(void); - Message* + UsblPositionExtended* clone(void) const { return new UsblPositionExtended(*this); @@ -22512,7 +24897,7 @@ namespace DUNE UsblFixExtended(void); - Message* + UsblFixExtended* clone(void) const { return new UsblFixExtended(*this); @@ -22587,7 +24972,7 @@ namespace DUNE UsblModem(void); - Message* + UsblModem* clone(void) const { return new UsblModem(*this); @@ -22667,7 +25052,7 @@ namespace DUNE UsblConfig(void); - Message* + UsblConfig* clone(void) const { return new UsblConfig(*this); @@ -22761,7 +25146,7 @@ namespace DUNE DissolvedOrganicMatter(void); - Message* + DissolvedOrganicMatter* clone(void) const { return new DissolvedOrganicMatter(*this); @@ -22828,7 +25213,7 @@ namespace DUNE OpticalBackscatter(void); - Message* + OpticalBackscatter* clone(void) const { return new OpticalBackscatter(*this); @@ -22925,7 +25310,7 @@ namespace DUNE Tachograph(void); - Message* + Tachograph* clone(void) const { return new Tachograph(*this); @@ -23009,7 +25394,7 @@ namespace DUNE ApmStatus(void); - Message* + ApmStatus* clone(void) const { return new ApmStatus(*this); @@ -23091,7 +25476,7 @@ namespace DUNE SadcReadings(void); - Message* + SadcReadings* clone(void) const { return new SadcReadings(*this); @@ -23142,6 +25527,244 @@ namespace DUNE void fieldsToJSON(std::ostream& os__, unsigned nindent__) const; }; + + //! DMS Detection. + class DmsDetection: public Message + { + public: + //! Channel 1. + fp32_t ch01; + //! Channel 2. + fp32_t ch02; + //! Channel 3. + fp32_t ch03; + //! Channel 4. + fp32_t ch04; + //! Channel 5. + fp32_t ch05; + //! Channel 6. + fp32_t ch06; + //! Channel 7. + fp32_t ch07; + //! Channel 8. + fp32_t ch08; + //! Channel 9. + fp32_t ch09; + //! Channel 10. + fp32_t ch10; + //! Channel 11. + fp32_t ch11; + //! Channel 12. + fp32_t ch12; + //! Channel 13. + fp32_t ch13; + //! Channel 14. + fp32_t ch14; + //! Channel 15. + fp32_t ch15; + //! Channel 16. + fp32_t ch16; + + static uint16_t + getIdStatic(void) + { + return 908; + } + + DmsDetection(void); + + DmsDetection* + clone(void) const + { + return new DmsDetection(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return DmsDetection::getIdStatic(); + } + + const char* + getName(void) const + { + return "DmsDetection"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 64; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Home Position. + class HomePosition: public Message + { + public: + //! Action on the vehicle home position. + enum ActiononthevehiclehomepositionEnum + { + //! Set. + OP_SET = 1, + //! Report. + OP_REPORT = 2 + }; + + //! Action on the vehicle home position. + uint8_t op; + //! Latitude (WGS-84). + fp64_t lat; + //! Longitude (WGS-84). + fp64_t lon; + //! Height (WGS-84). + fp32_t height; + //! Depth. + fp32_t depth; + //! Altitude. + fp32_t alt; + + static uint16_t + getIdStatic(void) + { + return 909; + } + + HomePosition(void); + + HomePosition* + clone(void) const + { + return new HomePosition(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return HomePosition::getIdStatic(); + } + + const char* + getName(void) const + { + return "HomePosition"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 29; + } + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; + + //! Total Magnetic Field Intensity. + class TotalMagIntensity: public Message + { + public: + //! Value. + fp64_t value; + + static uint16_t + getIdStatic(void) + { + return 2006; + } + + TotalMagIntensity(void); + + TotalMagIntensity* + clone(void) const + { + return new TotalMagIntensity(*this); + } + + void + clear(void); + + bool + fieldsEqual(const Message& msg__) const; + + int + validate(void) const; + + uint8_t* + serializeFields(uint8_t* bfr__) const; + + uint16_t + deserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + reverseDeserializeFields(const uint8_t* bfr__, uint16_t size__); + + uint16_t + getId(void) const + { + return TotalMagIntensity::getIdStatic(); + } + + const char* + getName(void) const + { + return "TotalMagIntensity"; + } + + unsigned + getFixedSerializationSize(void) const + { + return 8; + } + + fp64_t + getValueFP(void) const; + + void + setValueFP(fp64_t val); + + void + fieldsToJSON(std::ostream& os__, unsigned nindent__) const; + }; } } diff --git a/src/DUNE/IMC/Enumerations.hpp b/src/DUNE/IMC/Enumerations.hpp index 038b392a26..a95f8af88a 100644 --- a/src/DUNE/IMC/Enumerations.hpp +++ b/src/DUNE/IMC/Enumerations.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** #ifndef DUNE_IMC_ENUMERATIONS_HPP_INCLUDED_ diff --git a/src/DUNE/IMC/Exceptions.hpp b/src/DUNE/IMC/Exceptions.hpp index e3712a50ec..62f7d66cbf 100644 --- a/src/DUNE/IMC/Exceptions.hpp +++ b/src/DUNE/IMC/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Factory.cpp b/src/DUNE/IMC/Factory.cpp index b59a13067c..0039cc0dd0 100644 --- a/src/DUNE/IMC/Factory.cpp +++ b/src/DUNE/IMC/Factory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Factory.def b/src/DUNE/IMC/Factory.def index 9c784cfe46..0b3250cb03 100644 --- a/src/DUNE/IMC/Factory.def +++ b/src/DUNE/IMC/Factory.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** MESSAGE(1, EntityState) @@ -60,6 +60,8 @@ MESSAGE(107, HistoricCTD) MESSAGE(108, HistoricTelemetry) MESSAGE(109, HistoricSonarData) MESSAGE(110, HistoricEvent) +MESSAGE(111, VerticalProfile) +MESSAGE(112, ProfileSample) MESSAGE(150, Heartbeat) MESSAGE(151, Announce) MESSAGE(152, AnnounceService) @@ -83,14 +85,19 @@ MESSAGE(185, CompressedHistory) MESSAGE(186, HistoricSample) MESSAGE(187, HistoricDataQuery) MESSAGE(188, RemoteCommand) +MESSAGE(189, CommSystemsQuery) +MESSAGE(190, TelemetryMsg) MESSAGE(200, LblRange) MESSAGE(202, LblBeacon) MESSAGE(203, LblConfig) MESSAGE(206, AcousticMessage) +MESSAGE(207, SimAcousticMessage) MESSAGE(211, AcousticOperation) MESSAGE(212, AcousticSystemsQuery) MESSAGE(213, AcousticSystems) MESSAGE(214, AcousticLink) +MESSAGE(215, AcousticRequest) +MESSAGE(216, AcousticStatus) MESSAGE(250, Rpm) MESSAGE(251, Voltage) MESSAGE(252, Current) @@ -116,6 +123,7 @@ MESSAGE(271, WindSpeed) MESSAGE(272, RelativeHumidity) MESSAGE(273, DevDataText) MESSAGE(274, DevDataBinary) +MESSAGE(275, Force) MESSAGE(276, SonarData) MESSAGE(277, Pulse) MESSAGE(278, PulseDetectionControl) @@ -231,6 +239,10 @@ MESSAGE(491, Takeoff) MESSAGE(492, Land) MESSAGE(493, AutonomousSection) MESSAGE(494, FollowPoint) +MESSAGE(495, Alignment) +MESSAGE(496, StationKeepingExtended) +MESSAGE(497, ManeuverDone) +MESSAGE(499, Magnetometer) MESSAGE(500, VehicleState) MESSAGE(501, VehicleCommand) MESSAGE(502, MonitorEntityState) @@ -245,6 +257,15 @@ MESSAGE(510, FormState) MESSAGE(511, AutopilotMode) MESSAGE(512, FormationState) MESSAGE(513, ReportControl) +MESSAGE(514, StateReport) +MESSAGE(515, TransmissionRequest) +MESSAGE(516, TransmissionStatus) +MESSAGE(517, SmsRequest) +MESSAGE(518, SmsStatus) +MESSAGE(519, VtolState) +MESSAGE(520, ArmingState) +MESSAGE(521, TCPRequest) +MESSAGE(522, TCPStatus) MESSAGE(550, Abort) MESSAGE(551, PlanSpecification) MESSAGE(552, PlanManeuver) @@ -295,10 +316,15 @@ MESSAGE(814, UamTxFrame) MESSAGE(815, UamRxFrame) MESSAGE(816, UamTxStatus) MESSAGE(817, UamRxRange) +MESSAGE(818, UamTxRange) MESSAGE(820, FormCtrlParam) MESSAGE(821, FormationEval) MESSAGE(822, FormationControlParams) MESSAGE(823, FormationEvaluation) +MESSAGE(850, SoiWaypoint) +MESSAGE(851, SoiPlan) +MESSAGE(852, SoiCommand) +MESSAGE(853, SoiState) MESSAGE(877, MessagePart) MESSAGE(888, NeptusBlob) MESSAGE(889, Aborted) @@ -320,4 +346,7 @@ MESSAGE(904, OpticalBackscatter) MESSAGE(905, Tachograph) MESSAGE(906, ApmStatus) MESSAGE(907, SadcReadings) +MESSAGE(908, DmsDetection) +MESSAGE(909, HomePosition) +MESSAGE(2006, TotalMagIntensity) #undef MESSAGE diff --git a/src/DUNE/IMC/Factory.hpp b/src/DUNE/IMC/Factory.hpp index fd508342b9..c071d8da2b 100644 --- a/src/DUNE/IMC/Factory.hpp +++ b/src/DUNE/IMC/Factory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Header.hpp b/src/DUNE/IMC/Header.hpp index 05922b393f..dadb805648 100644 --- a/src/DUNE/IMC/Header.hpp +++ b/src/DUNE/IMC/Header.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** #ifndef DUNE_IMC_HEADER_HPP_INCLUDED_ diff --git a/src/DUNE/IMC/InlineMessage.hpp b/src/DUNE/IMC/InlineMessage.hpp index 0eb0b4efeb..f338610ad6 100644 --- a/src/DUNE/IMC/InlineMessage.hpp +++ b/src/DUNE/IMC/InlineMessage.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/IridiumMessageDefinitions.cpp b/src/DUNE/IMC/IridiumMessageDefinitions.cpp index 543891d7c7..b71e3a5f75 100644 --- a/src/DUNE/IMC/IridiumMessageDefinitions.cpp +++ b/src/DUNE/IMC/IridiumMessageDefinitions.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/IridiumMessageDefinitions.hpp b/src/DUNE/IMC/IridiumMessageDefinitions.hpp index b4c5f33689..9b52fe2d87 100644 --- a/src/DUNE/IMC/IridiumMessageDefinitions.hpp +++ b/src/DUNE/IMC/IridiumMessageDefinitions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/JSON.cpp b/src/DUNE/IMC/JSON.cpp index e09ed7366b..26fe8d5ef4 100644 --- a/src/DUNE/IMC/JSON.cpp +++ b/src/DUNE/IMC/JSON.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/JSON.hpp b/src/DUNE/IMC/JSON.hpp index abf08afec8..0ef047abd0 100644 --- a/src/DUNE/IMC/JSON.hpp +++ b/src/DUNE/IMC/JSON.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Macros.hpp b/src/DUNE/IMC/Macros.hpp index ef384849d9..0741192cdd 100644 --- a/src/DUNE/IMC/Macros.hpp +++ b/src/DUNE/IMC/Macros.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** #ifndef DUNE_IMC_MACROS_HPP_INCLUDED_ @@ -92,6 +92,10 @@ #define DUNE_IMC_HISTORICSONARDATA 109 //! HistoricEvent identification number. #define DUNE_IMC_HISTORICEVENT 110 +//! VerticalProfile identification number. +#define DUNE_IMC_VERTICALPROFILE 111 +//! ProfileSample identification number. +#define DUNE_IMC_PROFILESAMPLE 112 //! Heartbeat identification number. #define DUNE_IMC_HEARTBEAT 150 //! Announce identification number. @@ -138,6 +142,10 @@ #define DUNE_IMC_HISTORICDATAQUERY 187 //! RemoteCommand identification number. #define DUNE_IMC_REMOTECOMMAND 188 +//! CommSystemsQuery identification number. +#define DUNE_IMC_COMMSYSTEMSQUERY 189 +//! TelemetryMsg identification number. +#define DUNE_IMC_TELEMETRYMSG 190 //! LblRange identification number. #define DUNE_IMC_LBLRANGE 200 //! LblBeacon identification number. @@ -146,6 +154,8 @@ #define DUNE_IMC_LBLCONFIG 203 //! AcousticMessage identification number. #define DUNE_IMC_ACOUSTICMESSAGE 206 +//! SimAcousticMessage identification number. +#define DUNE_IMC_SIMACOUSTICMESSAGE 207 //! AcousticOperation identification number. #define DUNE_IMC_ACOUSTICOPERATION 211 //! AcousticSystemsQuery identification number. @@ -154,6 +164,10 @@ #define DUNE_IMC_ACOUSTICSYSTEMS 213 //! AcousticLink identification number. #define DUNE_IMC_ACOUSTICLINK 214 +//! AcousticRequest identification number. +#define DUNE_IMC_ACOUSTICREQUEST 215 +//! AcousticStatus identification number. +#define DUNE_IMC_ACOUSTICSTATUS 216 //! Rpm identification number. #define DUNE_IMC_RPM 250 //! Voltage identification number. @@ -204,6 +218,8 @@ #define DUNE_IMC_DEVDATATEXT 273 //! DevDataBinary identification number. #define DUNE_IMC_DEVDATABINARY 274 +//! Force identification number. +#define DUNE_IMC_FORCE 275 //! SonarData identification number. #define DUNE_IMC_SONARDATA 276 //! Pulse identification number. @@ -434,6 +450,14 @@ #define DUNE_IMC_AUTONOMOUSSECTION 493 //! FollowPoint identification number. #define DUNE_IMC_FOLLOWPOINT 494 +//! Alignment identification number. +#define DUNE_IMC_ALIGNMENT 495 +//! StationKeepingExtended identification number. +#define DUNE_IMC_STATIONKEEPINGEXTENDED 496 +//! ManeuverDone identification number. +#define DUNE_IMC_MANEUVERDONE 497 +//! Magnetometer identification number. +#define DUNE_IMC_MAGNETOMETER 499 //! VehicleState identification number. #define DUNE_IMC_VEHICLESTATE 500 //! VehicleCommand identification number. @@ -462,6 +486,24 @@ #define DUNE_IMC_FORMATIONSTATE 512 //! ReportControl identification number. #define DUNE_IMC_REPORTCONTROL 513 +//! StateReport identification number. +#define DUNE_IMC_STATEREPORT 514 +//! TransmissionRequest identification number. +#define DUNE_IMC_TRANSMISSIONREQUEST 515 +//! TransmissionStatus identification number. +#define DUNE_IMC_TRANSMISSIONSTATUS 516 +//! SmsRequest identification number. +#define DUNE_IMC_SMSREQUEST 517 +//! SmsStatus identification number. +#define DUNE_IMC_SMSSTATUS 518 +//! VtolState identification number. +#define DUNE_IMC_VTOLSTATE 519 +//! ArmingState identification number. +#define DUNE_IMC_ARMINGSTATE 520 +//! TCPRequest identification number. +#define DUNE_IMC_TCPREQUEST 521 +//! TCPStatus identification number. +#define DUNE_IMC_TCPSTATUS 522 //! Abort identification number. #define DUNE_IMC_ABORT 550 //! PlanSpecification identification number. @@ -562,6 +604,8 @@ #define DUNE_IMC_UAMTXSTATUS 816 //! UamRxRange identification number. #define DUNE_IMC_UAMRXRANGE 817 +//! UamTxRange identification number. +#define DUNE_IMC_UAMTXRANGE 818 //! FormCtrlParam identification number. #define DUNE_IMC_FORMCTRLPARAM 820 //! FormationEval identification number. @@ -570,6 +614,14 @@ #define DUNE_IMC_FORMATIONCONTROLPARAMS 822 //! FormationEvaluation identification number. #define DUNE_IMC_FORMATIONEVALUATION 823 +//! SoiWaypoint identification number. +#define DUNE_IMC_SOIWAYPOINT 850 +//! SoiPlan identification number. +#define DUNE_IMC_SOIPLAN 851 +//! SoiCommand identification number. +#define DUNE_IMC_SOICOMMAND 852 +//! SoiState identification number. +#define DUNE_IMC_SOISTATE 853 //! MessagePart identification number. #define DUNE_IMC_MESSAGEPART 877 //! NeptusBlob identification number. @@ -612,5 +664,11 @@ #define DUNE_IMC_APMSTATUS 906 //! SadcReadings identification number. #define DUNE_IMC_SADCREADINGS 907 +//! DmsDetection identification number. +#define DUNE_IMC_DMSDETECTION 908 +//! HomePosition identification number. +#define DUNE_IMC_HOMEPOSITION 909 +//! TotalMagIntensity identification number. +#define DUNE_IMC_TOTALMAGINTENSITY 2006 #endif diff --git a/src/DUNE/IMC/Message.cpp b/src/DUNE/IMC/Message.cpp index 059299609c..451a39fcd7 100644 --- a/src/DUNE/IMC/Message.cpp +++ b/src/DUNE/IMC/Message.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Message.hpp b/src/DUNE/IMC/Message.hpp index e6137c4681..5e471d876b 100644 --- a/src/DUNE/IMC/Message.hpp +++ b/src/DUNE/IMC/Message.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/MessageList.hpp b/src/DUNE/IMC/MessageList.hpp index 7b5722cc45..ce4631699c 100644 --- a/src/DUNE/IMC/MessageList.hpp +++ b/src/DUNE/IMC/MessageList.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -126,6 +126,14 @@ namespace DUNE return m_list.end(); } + //! Check if the list is empty. + //! @return true if the list is empty. + bool + empty(void) const + { + return m_list.empty(); + } + //! Add a new element at the end of the list, after its current //! last element. The content of this new element is initialized //! to a copy of 'msg'. diff --git a/src/DUNE/IMC/Packet.cpp b/src/DUNE/IMC/Packet.cpp index 00da59ef9d..91ea30a2ab 100644 --- a/src/DUNE/IMC/Packet.cpp +++ b/src/DUNE/IMC/Packet.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Packet.hpp b/src/DUNE/IMC/Packet.hpp index 0565c846a4..f010ea4084 100644 --- a/src/DUNE/IMC/Packet.hpp +++ b/src/DUNE/IMC/Packet.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Parser.cpp b/src/DUNE/IMC/Parser.cpp index 0c1ecfcf22..5eded1fb48 100644 --- a/src/DUNE/IMC/Parser.cpp +++ b/src/DUNE/IMC/Parser.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Parser.hpp b/src/DUNE/IMC/Parser.hpp index f1db48952b..a7bca6288c 100644 --- a/src/DUNE/IMC/Parser.hpp +++ b/src/DUNE/IMC/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Serialization.cpp b/src/DUNE/IMC/Serialization.cpp index ed160871e6..2c77515484 100644 --- a/src/DUNE/IMC/Serialization.cpp +++ b/src/DUNE/IMC/Serialization.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/Serialization.hpp b/src/DUNE/IMC/Serialization.hpp index 994ea59f3f..b75cd6bf3a 100644 --- a/src/DUNE/IMC/Serialization.hpp +++ b/src/DUNE/IMC/Serialization.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IMC/SuperTypes.hpp b/src/DUNE/IMC/SuperTypes.hpp index 040aa280df..8c7f067e5a 100644 --- a/src/DUNE/IMC/SuperTypes.hpp +++ b/src/DUNE/IMC/SuperTypes.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,7 @@ //*************************************************************************** // Automatically generated. * //*************************************************************************** -// IMC XML MD5: d292e724592557940354dddbfc5a9d32 * +// IMC XML MD5: 0f425402b735f36a64d579da7bb4baf3 * //*************************************************************************** #ifndef DUNE_IMC_SUPERTYPES_HPP_INCLUDED_ diff --git a/src/DUNE/IO.hpp b/src/DUNE/IO.hpp index 09af276e56..8f6baf6020 100644 --- a/src/DUNE/IO.hpp +++ b/src/DUNE/IO.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IO/Handle.hpp b/src/DUNE/IO/Handle.hpp index 057971b664..0904f60a1f 100644 --- a/src/DUNE/IO/Handle.hpp +++ b/src/DUNE/IO/Handle.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IO/Poll.cpp b/src/DUNE/IO/Poll.cpp index cb310e8a48..5bb9e27a57 100644 --- a/src/DUNE/IO/Poll.cpp +++ b/src/DUNE/IO/Poll.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/IO/Poll.hpp b/src/DUNE/IO/Poll.hpp index 50a97f0877..3c6e42fbd6 100644 --- a/src/DUNE/IO/Poll.hpp +++ b/src/DUNE/IO/Poll.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers.hpp b/src/DUNE/Maneuvers.hpp index 0c2a4c6c5b..51057ea356 100644 --- a/src/DUNE/Maneuvers.hpp +++ b/src/DUNE/Maneuvers.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/AbstractLoiter.hpp b/src/DUNE/Maneuvers/AbstractLoiter.hpp index 5c7a32f1f6..38b80d706c 100644 --- a/src/DUNE/Maneuvers/AbstractLoiter.hpp +++ b/src/DUNE/Maneuvers/AbstractLoiter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/Circular.cpp b/src/DUNE/Maneuvers/Circular.cpp index f700df994e..6f9665ee19 100644 --- a/src/DUNE/Maneuvers/Circular.cpp +++ b/src/DUNE/Maneuvers/Circular.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/Circular.hpp b/src/DUNE/Maneuvers/Circular.hpp index 106db85af3..ae9db47140 100644 --- a/src/DUNE/Maneuvers/Circular.hpp +++ b/src/DUNE/Maneuvers/Circular.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/Elevate.cpp b/src/DUNE/Maneuvers/Elevate.cpp index aa34f10cda..6940c1a2bf 100644 --- a/src/DUNE/Maneuvers/Elevate.cpp +++ b/src/DUNE/Maneuvers/Elevate.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/Elevate.hpp b/src/DUNE/Maneuvers/Elevate.hpp index 2747896bf3..cf2fe26fb5 100644 --- a/src/DUNE/Maneuvers/Elevate.hpp +++ b/src/DUNE/Maneuvers/Elevate.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/FigureEight.cpp b/src/DUNE/Maneuvers/FigureEight.cpp index 7f94205d98..0b1c09872d 100644 --- a/src/DUNE/Maneuvers/FigureEight.cpp +++ b/src/DUNE/Maneuvers/FigureEight.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/FigureEight.hpp b/src/DUNE/Maneuvers/FigureEight.hpp index a8938eb779..080c3e43e5 100644 --- a/src/DUNE/Maneuvers/FigureEight.hpp +++ b/src/DUNE/Maneuvers/FigureEight.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/FollowTrajectory.cpp b/src/DUNE/Maneuvers/FollowTrajectory.cpp index a32c529dff..f51ef64101 100644 --- a/src/DUNE/Maneuvers/FollowTrajectory.cpp +++ b/src/DUNE/Maneuvers/FollowTrajectory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/FollowTrajectory.hpp b/src/DUNE/Maneuvers/FollowTrajectory.hpp index 659377eb4d..8889b76f67 100644 --- a/src/DUNE/Maneuvers/FollowTrajectory.hpp +++ b/src/DUNE/Maneuvers/FollowTrajectory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/Maneuver.cpp b/src/DUNE/Maneuvers/Maneuver.cpp index 73fab12466..66188125aa 100644 --- a/src/DUNE/Maneuvers/Maneuver.cpp +++ b/src/DUNE/Maneuvers/Maneuver.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/Maneuver.hpp b/src/DUNE/Maneuvers/Maneuver.hpp index 42740018f4..a9ae83b47f 100644 --- a/src/DUNE/Maneuvers/Maneuver.hpp +++ b/src/DUNE/Maneuvers/Maneuver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -252,7 +252,7 @@ namespace DUNE void signalNoAltitude(void); - //! Signal an error. + //! Signal maneuver completion. //! This method should be used by subclasses to signal maneuver completion. //! @param msg completion message void diff --git a/src/DUNE/Maneuvers/RowsStages.cpp b/src/DUNE/Maneuvers/RowsStages.cpp index e9d7f0e332..6b5f953cab 100644 --- a/src/DUNE/Maneuvers/RowsStages.cpp +++ b/src/DUNE/Maneuvers/RowsStages.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -266,7 +266,12 @@ namespace DUNE if (std::fabs(ady) > c_y_margin) { - if (std::abs(m_sabs.y) > m_width) + double tmp_x = m_sabs.x; + double tmp_y = m_sabs.y; + if (m_cross_angle != 0.0) + Angles::rotate(-m_cross_angle, curveLeft(), tmp_x, tmp_y); + + if (std::abs(tmp_y) > m_width) return true; } diff --git a/src/DUNE/Maneuvers/RowsStages.hpp b/src/DUNE/Maneuvers/RowsStages.hpp index 3d53005a52..31c31236d4 100644 --- a/src/DUNE/Maneuvers/RowsStages.hpp +++ b/src/DUNE/Maneuvers/RowsStages.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/StationKeep.cpp b/src/DUNE/Maneuvers/StationKeep.cpp index 156485cfee..16fb02aa9e 100644 --- a/src/DUNE/Maneuvers/StationKeep.cpp +++ b/src/DUNE/Maneuvers/StationKeep.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -41,6 +41,8 @@ namespace DUNE { //! Factor for the radius to consider traveling at the surface static const float c_surface_factor = 2.5f; + //! Limits the rate at which DesiredPath messages are dispatched. + static const double c_dpath_dispatch_period = 1.0; //! Default constructor. StationKeep::StationKeep(const IMC::StationKeeping* maneuver, Maneuvers::Maneuver* task, @@ -72,6 +74,7 @@ namespace DUNE m_path.end_z_units = z_units; m_path.speed = speed; m_path.speed_units = speed_units; + m_path.flags |= IMC::DesiredPath::FL_DIRECT; } double @@ -86,13 +89,7 @@ namespace DUNE double y; WGS84::displacement(lat, lon, 0, m_lat, m_lon, 0, &x, &y); - // dummy variable - double bearing; - double range; - - toPolar(x, y, &bearing, &range); - - return range; + return Math::norm(x, y); } void @@ -112,6 +109,8 @@ namespace DUNE { m_task->dispatch(m_path); } + + m_last_dpath_dispatch = DUNE::Time::Clock::get(); } void @@ -168,10 +167,27 @@ namespace DUNE switch (m_sks) { case ST_OFF_STATION: - if (pcs->flags & IMC::PathControlState::FL_NEAR && range < m_radius) + if (pcs->flags & IMC::PathControlState::FL_NEAR) { - stopMoving(range); - m_sks = ST_ON_STATION; + if (range < m_radius) + { + stopMoving(range); + m_sks = ST_ON_STATION; + } + else + { + const double now = DUNE::Time::Clock::get(); + + if (now >= m_last_dpath_dispatch + c_dpath_dispatch_period) + { + m_task->debug("FL_NEAR is set but range is %.2f >= %.2f", + range, + m_radius); + + m_task->dispatch(m_path); + m_last_dpath_dispatch = now; + } + } } break; default: diff --git a/src/DUNE/Maneuvers/StationKeep.hpp b/src/DUNE/Maneuvers/StationKeep.hpp index 7f380413a5..9494183407 100644 --- a/src/DUNE/Maneuvers/StationKeep.hpp +++ b/src/DUNE/Maneuvers/StationKeep.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -126,6 +126,8 @@ namespace DUNE double m_radius; //! Current state of the state machine StationState m_sks; + //! Time of last DesiredPath dispatch. + double m_last_dpath_dispatch; }; } } diff --git a/src/DUNE/Maneuvers/VehicleFormation.cpp b/src/DUNE/Maneuvers/VehicleFormation.cpp index 5fd69588a2..ea032095ca 100644 --- a/src/DUNE/Maneuvers/VehicleFormation.cpp +++ b/src/DUNE/Maneuvers/VehicleFormation.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Maneuvers/VehicleFormation.hpp b/src/DUNE/Maneuvers/VehicleFormation.hpp index 3e0f439d8c..7da3b99f12 100644 --- a/src/DUNE/Maneuvers/VehicleFormation.hpp +++ b/src/DUNE/Maneuvers/VehicleFormation.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math.hpp b/src/DUNE/Math.hpp index 5213ad612c..7fa109661e 100644 --- a/src/DUNE/Math.hpp +++ b/src/DUNE/Math.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -39,13 +39,17 @@ namespace DUNE #include #include +#include #include #include #include #include #include #include +#include #include #include +#include +#include #endif diff --git a/src/DUNE/Math/Angles.hpp b/src/DUNE/Math/Angles.hpp index 496ee08859..cb6f1c6241 100644 --- a/src/DUNE/Math/Angles.hpp +++ b/src/DUNE/Math/Angles.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -84,7 +84,8 @@ namespace DUNE inline static fp64_t convertDMSToDecimal(int degrees, int minutes, int seconds) { - return degrees + (minutes / 60.0) + (seconds / 3600.0); + fp64_t result = std::abs(degrees) + (std::abs(minutes) / 60.0) + (std::abs(seconds) / 3600.0); + return (degrees < 0) ? -result : result; } //! Convert Degrees, Minutes to Decimal Format. @@ -94,7 +95,8 @@ namespace DUNE inline static fp64_t convertDMSToDecimal(int degrees, double minutes) { - return degrees + (minutes / 60.0); + fp64_t result = std::abs(degrees) + (std::fabs(minutes) / 60.0); + return (degrees < 0) ? -result : result; } //! Convert decimal degrees to Degrees, Minutes, Seconds. @@ -123,11 +125,11 @@ namespace DUNE } //! XY Coordinate conversion considering a rotation angle. - //! (Eduardo Marques) - //! @param angle angle - //! @param clockwise clockwise rotation or not - //! @param x original x value on entry, rotated x value on exit. - //! @param y original y value on entry, rotated y value on exit. + //! @param[in] angle angle in radian. + //! @param[in] clockwise true for a clockwise rotation, false for counterclockwise. + //! @param[in,out] x original x value on entry, rotated x value on exit. + //! @param[in,out] y original y value on entry, rotated y value on exit. + //! @author Eduardo Marques inline static void rotate(double angle, bool clockwise, double& x, double& y) { diff --git a/src/DUNE/Math/Constants.hpp b/src/DUNE/Math/Constants.hpp index d94eec5c93..dfbfdc2073 100644 --- a/src/DUNE/Math/Constants.hpp +++ b/src/DUNE/Math/Constants.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Derivative.hpp b/src/DUNE/Math/Derivative.hpp index fcbdc061f2..9420253de2 100644 --- a/src/DUNE/Math/Derivative.hpp +++ b/src/DUNE/Math/Derivative.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/EulerAnglesZyx.cpp b/src/DUNE/Math/EulerAnglesZyx.cpp new file mode 100644 index 0000000000..4bbcfd5eae --- /dev/null +++ b/src/DUNE/Math/EulerAnglesZyx.cpp @@ -0,0 +1,33 @@ +#include "EulerAnglesZyx.hpp" + +#include + +namespace DUNE +{ + namespace Math + { + EulerAnglesZyx::EulerAnglesZyx() + : roll(0), pitch(0), yaw(0) {} + + EulerAnglesZyx::EulerAnglesZyx(double _roll, double _pitch, double _yaw) + : roll(_roll), pitch(_pitch), yaw(_yaw) {} + + EulerAnglesZyx::EulerAnglesZyx(const Quaternion& q) + { + const double& w = q.w(); + const double& x = q.x(); + const double& y = q.y(); + const double& z = q.z(); + + roll = std::atan2(2*(w*x + y*z), 1 - 2*(x*x + y*y)); + pitch = std::asin( 2*(w*y - x*z)); + yaw = std::atan2(2*(w*z + x*y), 1 - 2*(y*y + z*z)); + } + + std::ostream& operator<<(std::ostream& os, const EulerAnglesZyx& eul) + { + os << eul.roll << std::endl << eul.pitch << std::endl << eul.yaw << std::endl; + return os; + } + } +} diff --git a/src/DUNE/Math/EulerAnglesZyx.hpp b/src/DUNE/Math/EulerAnglesZyx.hpp new file mode 100644 index 0000000000..05a8374801 --- /dev/null +++ b/src/DUNE/Math/EulerAnglesZyx.hpp @@ -0,0 +1,30 @@ +#ifndef DUNE_MATH_EULER_ANGLES_ZYX_HPP_INCLUDED_ +#define DUNE_MATH_EULER_ANGLES_ZYX_HPP_INCLUDED_ + +#include +#include + +#include + +namespace DUNE +{ + namespace Math + { + class Quaternion; + + // Euler angles in radians following the ZYX convention. + // Roll and yaw are valid from -pi to pi, pitch from -pi/2 to pi/2. + struct EulerAnglesZyx + { + EulerAnglesZyx(); + EulerAnglesZyx(double roll, double pitch, double yaw); + EulerAnglesZyx(const Quaternion& quat); + friend std::ostream& operator<<(std::ostream& os, const EulerAnglesZyx& eul); + double roll; + double pitch; + double yaw; + }; + } +} + +#endif diff --git a/src/DUNE/Math/FIRFilter.hpp b/src/DUNE/Math/FIRFilter.hpp new file mode 100644 index 0000000000..376f954355 --- /dev/null +++ b/src/DUNE/Math/FIRFilter.hpp @@ -0,0 +1,98 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#ifndef DUNE_MATH_FIR_FILTER_HPP_INCLUDED_ +#define DUNE_MATH_FIR_FILTER_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include "DUNE/Utils/CircularBuffer.hpp" + +namespace DUNE +{ + namespace Math + { + template class FIRFilter + { + public: + //! Create a zero-initialized filter. + FIRFilter(std::vector weights) + : m_weights(std::move(weights)), m_buffer(m_weights.size()), m_val(T{ 0 }) + { + for (size_t i = 0; i < m_weights.size(); ++i) + m_buffer.add(T{ 0 }); + } + + //! Clear samples and reset state. + void + clear(void) + { + m_val = T{ 0 }; + + for (size_t i = 0; i < m_weights.size(); ++i) + m_buffer(i) = T{ 0 }; + } + + //! Add a new sample to the buffer. + //! @return new filter output + T + update(T value) + { + m_buffer.add(value); + + m_val = T{ 0 }; + + for (size_t i = 0; i < m_weights.size(); ++i) + m_val += m_weights[i] * m_buffer(i); + + return m_val; + } + + //! Get filter output. + //! @return filter output. + T + get(void) const + { + return m_val; + } + + private: + //! Impulse response. + std::vector m_weights; + //! Input samples. + DUNE::Utils::CircularBuffer m_buffer; + //! Caches the last filter output. + T m_val; + }; + } // namespace Math +} // namespace DUNE + +#endif diff --git a/src/DUNE/Math/General.hpp b/src/DUNE/Math/General.hpp index c1486e1538..031ba5bbd9 100644 --- a/src/DUNE/Math/General.hpp +++ b/src/DUNE/Math/General.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -78,12 +78,12 @@ namespace DUNE Type average(Type* a, uint32_t size) { - Type t = 0; + double t = 0; for (uint32_t i = 0; i < size; ++i) t += a[i]; - return (t / (Type)size); + return (Type) (t / size); } //! Computes the norm between two points. @@ -414,6 +414,81 @@ namespace DUNE #endif } + + //! @param val value + //! @return the factorial of val, i.e. val! = val*(val-1)*(val-2)*(val-3)*.... + //! implementation based on matlab + inline double + factorial(int val) + { + double ret; + static const double dv0[170] = { 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, + 40320.0, 362880.0, 3.6288E+6, 3.99168E+7, 4.790016E+8, 6.2270208E+9, + 8.71782912E+10, 1.307674368E+12, 2.0922789888E+13, 3.55687428096E+14, + 6.402373705728E+15, 1.21645100408832E+17, 2.43290200817664E+18, + 5.109094217170944E+19, 1.1240007277776077E+21, 2.5852016738884978E+22, + 6.2044840173323941E+23, 1.5511210043330986E+25, 4.0329146112660565E+26, + 1.0888869450418352E+28, 3.0488834461171384E+29, 8.8417619937397008E+30, + 2.6525285981219103E+32, 8.2228386541779224E+33, 2.6313083693369352E+35, + 8.6833176188118859E+36, 2.9523279903960412E+38, 1.0333147966386144E+40, + 3.7199332678990118E+41, 1.3763753091226343E+43, 5.23022617466601E+44, + 2.0397882081197442E+46, 8.1591528324789768E+47, 3.3452526613163803E+49, + 1.4050061177528798E+51, 6.0415263063373834E+52, 2.6582715747884485E+54, + 1.1962222086548019E+56, 5.5026221598120885E+57, 2.5862324151116818E+59, + 1.2413915592536073E+61, 6.0828186403426752E+62, 3.0414093201713376E+64, + 1.5511187532873822E+66, 8.0658175170943877E+67, 4.2748832840600255E+69, + 2.3084369733924138E+71, 1.2696403353658276E+73, 7.1099858780486348E+74, + 4.0526919504877221E+76, 2.3505613312828789E+78, 1.3868311854568986E+80, + 8.3209871127413916E+81, 5.0758021387722484E+83, 3.1469973260387939E+85, + 1.98260831540444E+87, 1.2688693218588417E+89, 8.2476505920824715E+90, + 5.4434493907744307E+92, 3.6471110918188683E+94, 2.4800355424368305E+96, + 1.711224524281413E+98, 1.197857166996989E+100, 8.5047858856786218E+101, + 6.1234458376886077E+103, 4.4701154615126834E+105, 3.3078854415193856E+107, + 2.4809140811395391E+109, 1.8854947016660498E+111, 1.4518309202828584E+113, + 1.1324281178206295E+115, 8.9461821307829729E+116, 7.1569457046263779E+118, + 5.7971260207473655E+120, 4.75364333701284E+122, 3.9455239697206569E+124, + 3.314240134565352E+126, 2.8171041143805494E+128, 2.4227095383672724E+130, + 2.1077572983795269E+132, 1.8548264225739836E+134, 1.6507955160908452E+136, + 1.4857159644817607E+138, 1.3520015276784023E+140, 1.24384140546413E+142, + 1.1567725070816409E+144, 1.0873661566567424E+146, 1.0329978488239052E+148, + 9.916779348709491E+149, 9.6192759682482062E+151, 9.426890448883242E+153, + 9.33262154439441E+155, 9.33262154439441E+157, 9.4259477598383536E+159, + 9.6144667150351211E+161, 9.9029007164861754E+163, 1.0299016745145622E+166, + 1.0813967582402903E+168, 1.1462805637347078E+170, 1.2265202031961373E+172, + 1.3246418194518284E+174, 1.4438595832024928E+176, 1.5882455415227421E+178, + 1.7629525510902437E+180, 1.9745068572210728E+182, 2.2311927486598123E+184, + 2.5435597334721862E+186, 2.9250936934930141E+188, 3.3931086844518965E+190, + 3.969937160808719E+192, 4.6845258497542883E+194, 5.5745857612076033E+196, + 6.6895029134491239E+198, 8.09429852527344E+200, 9.8750442008335976E+202, + 1.2146304367025325E+205, 1.5061417415111404E+207, 1.8826771768889254E+209, + 2.3721732428800459E+211, 3.0126600184576582E+213, 3.8562048236258025E+215, + 4.9745042224772855E+217, 6.4668554892204716E+219, 8.4715806908788174E+221, + 1.1182486511960039E+224, 1.4872707060906852E+226, 1.9929427461615181E+228, + 2.6904727073180495E+230, 3.6590428819525472E+232, 5.01288874827499E+234, + 6.9177864726194859E+236, 9.6157231969410859E+238, 1.346201247571752E+241, + 1.89814375907617E+243, 2.6953641378881614E+245, 3.8543707171800706E+247, + 5.5502938327393013E+249, 8.0479260574719866E+251, 1.17499720439091E+254, + 1.7272458904546376E+256, 2.5563239178728637E+258, 3.8089226376305671E+260, + 5.7133839564458505E+262, 8.6272097742332346E+264, 1.3113358856834518E+267, + 2.0063439050956811E+269, 3.0897696138473489E+271, 4.7891429014633912E+273, + 7.47106292628289E+275, 1.1729568794264138E+278, 1.8532718694937338E+280, + 2.9467022724950369E+282, 4.714723635992059E+284, 7.5907050539472148E+286, + 1.2296942187394488E+289, 2.0044015765453015E+291, 3.2872185855342945E+293, + 5.423910666131586E+295, 9.0036917057784329E+297, 1.5036165148649983E+300, + 2.5260757449731969E+302, 4.2690680090047027E+304, 7.257415615307994E+306 }; + + if ( (val > 170) || (val < 0)) + { + ret = 0.0; + throw std::out_of_range(DTR("Value out of range for finding factorial")); + } else if (val < 1.0) { + ret = 1.0; + } else { + ret = dv0[(int)val - 1]; + } + + return ret; + } } } diff --git a/src/DUNE/Math/Grid.hpp b/src/DUNE/Math/Grid.hpp new file mode 100644 index 0000000000..d73e0ce7eb --- /dev/null +++ b/src/DUNE/Math/Grid.hpp @@ -0,0 +1,268 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#ifndef DUNE_MATH_GRID_HPP_INCLUDED_ +#define DUNE_MATH_GRID_HPP_INCLUDED_ + +#include +#include +#include +#include +#include + +namespace DUNE +{ + namespace Math + { + //! Converts between grid indices, coordinate points and row-major + //! ordering. + //! @tparam dim number of dimensions. + template + class Grid + { + public: + //! Constructor. + //! @param[in] min the lower limits of the grid in each dimension. + //! @param[in] max the upper limits of the grid in each dimension. + //! @param[in] dimensions the number of points in each dimension. + Grid(std::vector const& min, + std::vector const& max, + std::vector const& dimensions); + + //! Convert an array of grid indices to a row-major ordered offset. + //! @param[in] indices the indices of the grid point. + //! @return the row-major offset of the grid point. + size_t + getOffset(std::array const& indices) const; + + //! Convert a row-major ordered offset to an array of grid indices. + //! @param[in] offset the row-major offset of the gridpoint. + //! @return indices of the gridpoint. + std::array + getIndices(size_t offset) const; + + //! Get the indices of the "lower corner" of the grid cell where a + //! point lies. + //! @param[in] coordinates coordinates of a point in dim-dimensional + //! space. + //! @return grid indices of the "lower" vertex of the grid cell where + //! the point lies. + std::array + getCorner(std::array const& coordinates) const; + + //! Get the coordinates of a gridpoint given by an array of indices. + //! @param[in] indices indices of a gridpoint. + //! @return the coordinates of the corresponding point in + //! dim-dimensional space. + std::array + getCoordinates(std::array const& indices) const; + + //! Get the coordinates of a gridpoint given by a row-major offset. + //! @param[in] offset the row-major offset of the gridpoint. + //! @return the coordinates of the corresponding point in + //! dim-dimensional space. + std::array + getCoordinates(size_t offset) const; + + //! Get the number of points in the grid along a dimension. + //! @param[in] dimension index of the dimension to query. + //! @return number of points along the given dimension. + size_t + getDimensions(size_t dimension) const + { + if (dimension >= dim) + throw std::runtime_error("Grid::getDimensions(): invalid index"); + + return m_npts[dimension]; + } + + //! @return the total number of gridpoints. + size_t + size() const + { + return m_size; + } + + //! Get the upper limit of the grid along a dimension. + //! @param[in] dimension index of the dimension to query. + //! @return upper limit along the given dimension. + double + getUpper(size_t dimension) const + { + if (dimension >= dim) + throw std::runtime_error("Grid::getUpper(): invalid index"); + + return m_max[dimension]; + } + + //! Get the loer limit of the grid along a dimension. + //! @param[in] dimension index of the dimension to query. + //! @return lower limit along the given dimension. + double + getLower(size_t dimension) const + { + if (dimension >= dim) + throw std::runtime_error("Grid::getLower(): invalid index"); + + return m_min[dimension]; + } + + //! Get the grid spacing along a dimension. + //! @param[in] dimension index of the dimension to query. + //! @return spacing along the given dimension. + double + getSpacing(size_t dimension) const + { + if (dimension >= dim) + throw std::runtime_error("Grid::getSpacing(): invalid index"); + + return m_h[dimension]; + } + + private: + //! The upper limits of the grid in each dimension. + std::array m_max; + //! The lower limits of the grid in each dimension. + std::array m_min; + //! The grid spacing in each dimension. + std::array m_h; + //! The number of gridpoints in each dimension. + std::array m_npts; + //! The total number of gridpoints. + size_t m_size; + }; + + template + Grid::Grid(std::vector const& min, + std::vector const& max, + std::vector const& dimensions) + + { + if (min.size() < dim || max.size() < dim || dimensions.size() < dim) + throw std::runtime_error( + "Grid::Grid(): insufficient number of elements to create the " + "grid."); + + std::copy_n(std::begin(min), dim, std::begin(m_min)); + std::copy_n(std::begin(max), dim, std::begin(m_max)); + std::copy_n(std::begin(dimensions), dim, std::begin(m_npts)); + + for (size_t i = 0; i < dim; ++i) + { + if (m_npts[i] < 2) + throw std::runtime_error("Grid::Grid(): invalid grid dimensions."); + + if (m_max[i] <= m_min[i]) + throw std::runtime_error("Grid::Grid(): invalid grid limits."); + + m_h[i] = (m_max[i] - m_min[i]) / (m_npts[i] - 1); + } + + m_size = std::accumulate( + std::begin(m_npts), std::end(m_npts), 1.0, std::multiplies()); + } + + template + size_t + Grid::getOffset(std::array const& indices) const + { + if (indices[0] >= m_npts[0]) + throw std::runtime_error("Grid::getOffset(): out of bounds."); + + size_t offset = indices[0]; + + for (size_t i = 1; i < dim; ++i) + { + if (indices[i] >= m_npts[i]) + throw std::runtime_error("Grid::getOffset(): out of bounds."); + + offset = m_npts[i] * offset + indices[i]; + } + + return offset; + } + + template + std::array + Grid::getIndices(size_t offset) const + { + if (offset >= m_size) + throw std::runtime_error("Grid::getIndices(): out of bounds."); + + std::array point; + + for (size_t i = dim; i > 0; --i) + { + point[i - 1] = offset % m_npts[i - 1]; + offset /= m_npts[i - 1]; + } + + return point; + } + + template + std::array + Grid::getCorner(std::array const& coordinates) const + { + std::array corner; + + for (size_t i = 0; i < dim; ++i) + { + if (coordinates[i] < m_min[i] || coordinates[i] > m_max[i]) + corner[i] = m_npts[i]; + else + corner[i] = std::floor((coordinates[i] - m_min[i]) / m_h[i]); + } + + return corner; + } + + template + std::array + Grid::getCoordinates(std::array const& indices) const + { + std::array coordinates; + + for (size_t i = 0; i < dim; ++i) + coordinates[i] = m_min[i] + m_h[i] * indices[i]; + + return coordinates; + } + + template + std::array + Grid::getCoordinates(size_t offset) const + { + return getCoordinates(getIndices(offset)); + } + + } // namespace Math +} // namespace DUNE + +#endif diff --git a/src/DUNE/Math/Matrix.cpp b/src/DUNE/Math/Matrix.cpp index b620749af7..2b1bf7575e 100644 --- a/src/DUNE/Math/Matrix.cpp +++ b/src/DUNE/Math/Matrix.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -46,6 +46,7 @@ // DUNE headers. #include +#include #include #include #include @@ -117,7 +118,7 @@ namespace DUNE } } - Matrix::Matrix(double* data, size_t r, size_t c) + Matrix::Matrix(const double* data, size_t r, size_t c) { if (!r || !c) throw Error("Invalid dimension!"); @@ -150,7 +151,7 @@ namespace DUNE identity(); } - Matrix::Matrix(double* diag, size_t n) + Matrix::Matrix(const double* diag, size_t n) { m_nrows = n; m_ncols = n; @@ -205,6 +206,42 @@ namespace DUNE *m_counter = 1; } + double* + Matrix::begin(void) + { + return m_data; + } + + double* + Matrix::end(void) + { + return m_data + m_size; + } + + const double* + Matrix::begin(void) const + { + return m_data; + } + + const double* + Matrix::end(void) const + { + return m_data + m_size; + } + + const double* + Matrix::cbegin(void) const + { + return m_data; + } + + const double* + Matrix::cend(void) const + { + return m_data + m_size; + } + int Matrix::rows(void) const { @@ -517,7 +554,7 @@ namespace DUNE void Matrix::swapRows(size_t i, size_t j) { - if (i >= m_ncols || j >= m_ncols) + if (i >= m_nrows || j >= m_nrows) throw Error("Invalid index!"); if (i == j) @@ -846,7 +883,7 @@ namespace DUNE } Matrix - Matrix::operator-(void) + Matrix::operator-(void) const { if (isEmpty()) throw Error("Trying to access an empty matrix!"); @@ -1203,7 +1240,11 @@ namespace DUNE double cy = std::cos(ea[2] / 2); double sy = std::sin(ea[2] / 2); - double q[4] = {cr* cp * cy + sr * sp * sy, sr * cp * cy - cr * sp * sy, cr * sp * cy + sr * cp * sy, cr * cp * sy - sr * sp * cy}; + double q[4] = {cr * cp * cy + sr * sp * sy, + sr * cp * cy - cr * sp * sy, + cr * sp * cy + sr * cp * sy, + cr * cp * sy - sr * sp * cy}; + return Matrix(q, 4, 1); } @@ -1247,17 +1288,26 @@ namespace DUNE return Matrix(ea, 3, 1); } - // quaternion to Euler angles + // Quaternion to Euler angles if (m_nrows == 4 && m_ncols == 1) { - double q[4] = {element(0, 0), element(1, 0), element(2, 0), element(3, 0)}; + double norm = norm_p(2); + double q[4] = {element(0, 0) / norm, + element(1, 0) / norm, + element(2, 0) / norm, + element(3, 0) / norm}; - double ea[3] = - { - std::atan2(2 * (q[2] * q[3] - q[0] * q[1]), 1 - 2 * (q[1] * q[1] + q[2] * q[2])), - std::asin(2 * (q[1] * q[3] - q[0] * q[2])), - std::atan2(2 * (q[1] * q[2] - q[0] * q[3]), 1 - 2 * (q[2] * q[2] + q[3] * q[3])) - }; + double roll = std::atan2(2 * (q[0] * q[1] + q[2] * q[3]), 1 - 2 * (q[1] * q[1] + q[2] * q[2])); + + double pitch = 2 * (q[0] * q[2] - q[3] * q[1]); + if (std::fabs(pitch) >= 1) + pitch = c_half_pi * pitch / std::fabs(pitch); + else + pitch = std::asin(pitch); + + double yaw = std::atan2(2 * (q[0] * q[3] + q[1] * q[2]), 1 - 2 * (q[2] * q[2] + q[3] * q[3])); + + double ea[3] = { roll, pitch, yaw }; return Matrix(ea, 3, 1); } @@ -1924,7 +1974,7 @@ namespace DUNE } Matrix - skew(double data[3]) + skew(const double data[3]) { Matrix m(3, 3, 0.0); m(0, 1) = -data[2]; diff --git a/src/DUNE/Math/Matrix.hpp b/src/DUNE/Math/Matrix.hpp index b2eab7c275..7bf4592ebb 100644 --- a/src/DUNE/Math/Matrix.hpp +++ b/src/DUNE/Math/Matrix.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -81,7 +81,7 @@ namespace DUNE //! @param[in] data pointer to data to be copied to new matrix //! @param[in] r number of rows of new matrix //! @param[in] c number of columns of new matrix - Matrix(double* data, size_t r, size_t c); + Matrix(const double* data, size_t r, size_t c); //! Constructor. //! Construct a matrix of size rows*columns. @@ -99,19 +99,43 @@ namespace DUNE //! Constructor. //! Construct a square identity matrix of size n //! param[in] n size of new matrix (n * n) - Matrix(size_t n); + explicit Matrix(size_t n); //! Constructor. //! Construct a diagonal matrix using the values in data //! param[in] diag pointer to data to be copied to diagonal matrix //! param[in] n size of new matrix (n * n) - Matrix(double* diag, size_t n); + Matrix(const double* diag, size_t n); //! Destructor. //! Decrement the number of copies of a Matrix and frees the //! allocated memory if this number reaches zero. ~Matrix(void); + //! Pointer to first element. + double* + begin(void); + + //! Pointer to element after last element. + double* + end(void); + + //! Const pointer to first element. + const double* + begin(void) const; + + //! Const pointer to element after last element. + const double* + end(void) const; + + //! Const pointer to first element. + const double* + cbegin(void) const; + + //! Const pointer to element after last element. + const double* + cend(void) const; + //! Retrieve the number of rows of the matrix. //! @return number of rows of the matrix. int @@ -426,7 +450,7 @@ namespace DUNE //! This method implements the unary minus operator. //! @return resultant matrix Matrix - operator-(void); + operator-(void) const; //! This method multiplies a Matrix by a real number. //! @param[in] x real number @@ -720,13 +744,6 @@ namespace DUNE friend DUNE_DLL_SYM Matrix inverse(const Matrix& a, const Matrix& b); - //! This function returns a 3x3 skew symmetrical - //! matrix using an array with 3 elements. - //! @param[in] data array with 3 elements - //! @return skewed matrix - friend Matrix - skew(double data[3]); - //! This function returns a 3x3 skew symmetrical //! matrix using a matrix (3x1 or 1x3) //! @param[in] a row or column vector with 3 elements @@ -851,6 +868,13 @@ namespace DUNE void split(void); }; + + //! This function returns a 3x3 skew symmetrical + //! matrix using an array with 3 elements. + //! @param[in] data array with 3 elements + //! @return skewed matrix + Matrix + skew(const double data[3]); } } diff --git a/src/DUNE/Math/MovingAverage.hpp b/src/DUNE/Math/MovingAverage.hpp index 24cb6cbbab..813375cb47 100644 --- a/src/DUNE/Math/MovingAverage.hpp +++ b/src/DUNE/Math/MovingAverage.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/MultiMovingAverage.hpp b/src/DUNE/Math/MultiMovingAverage.hpp index e1ac9496d1..fd007cd97f 100644 --- a/src/DUNE/Math/MultiMovingAverage.hpp +++ b/src/DUNE/Math/MultiMovingAverage.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Optimization.cpp b/src/DUNE/Math/Optimization.cpp index 5d032c8113..c5f7672600 100644 --- a/src/DUNE/Math/Optimization.cpp +++ b/src/DUNE/Math/Optimization.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Optimization.hpp b/src/DUNE/Math/Optimization.hpp index 05dc48faee..a384205fa0 100644 --- a/src/DUNE/Math/Optimization.hpp +++ b/src/DUNE/Math/Optimization.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/QPSolver.cpp b/src/DUNE/Math/QPSolver.cpp index 99226d73d6..42065bb664 100644 --- a/src/DUNE/Math/QPSolver.cpp +++ b/src/DUNE/Math/QPSolver.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/QPSolver.hpp b/src/DUNE/Math/QPSolver.hpp index 090ac5dd01..07ff1f01ff 100644 --- a/src/DUNE/Math/QPSolver.hpp +++ b/src/DUNE/Math/QPSolver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Quaternion.cpp b/src/DUNE/Math/Quaternion.cpp new file mode 100644 index 0000000000..2b95ddbc29 --- /dev/null +++ b/src/DUNE/Math/Quaternion.cpp @@ -0,0 +1,247 @@ +#include "Quaternion.hpp" + +#include +#include + +namespace DUNE +{ + namespace Math + { + Quaternion::Quaternion() + : m_matrix(4, 1) + { + this->identity(); + } + + Quaternion::Quaternion(double qw, double qx, double qy, double qz) + : m_matrix(4, 1) + { + m_matrix(INDEX_W) = qw; + m_matrix(INDEX_X) = qx; + m_matrix(INDEX_Y) = qy; + m_matrix(INDEX_Z) = qz; + } + + Quaternion::Quaternion(const std::vector& q) + : m_matrix(4, 1) + { + if (q.size() != 4) + throw std::invalid_argument("vector must have length 4"); + + m_matrix(INDEX_W) = q[0]; + m_matrix(INDEX_X) = q[1]; + m_matrix(INDEX_Y) = q[2]; + m_matrix(INDEX_Z) = q[3]; + } + + Quaternion::Quaternion(const double qw, const std::vector& v) + : m_matrix(4, 1) + { + if (v.size() != 3) + throw std::invalid_argument("vector must have length 3"); + + m_matrix(INDEX_W) = qw; + m_matrix(INDEX_X) = v[0]; + m_matrix(INDEX_Y) = v[1]; + m_matrix(INDEX_Z) = v[2]; + } + + Quaternion::Quaternion(const Matrix& q) + : m_matrix(4, 1) + { + if (!q.isColumnVector() || q.size() != 4) + throw std::invalid_argument("matrix must have size 4x1"); + + m_matrix = q; + } + + Quaternion::Quaternion(double qw, const Matrix& v) + : m_matrix(4, 1) + { + if (!v.isColumnVector() || v.size() != 3) + throw std::invalid_argument("matrix must have size 3x1"); + + m_matrix(INDEX_W) = qw; + m_matrix(INDEX_X) = v(0); + m_matrix(INDEX_Y) = v(1); + m_matrix(INDEX_Z) = v(2); + } + + Quaternion::Quaternion(const EulerAnglesZyx& euler) + : m_matrix(4, 1) + { + const double cr = std::cos(euler.roll / 2); + const double sr = std::sin(euler.roll / 2); + const double cp = std::cos(euler.pitch / 2); + const double sp = std::sin(euler.pitch / 2); + const double cy = std::cos(euler.yaw / 2); + const double sy = std::sin(euler.yaw / 2); + + m_matrix(INDEX_W) = cr*cp*cy + sr*sp*sy; + m_matrix(INDEX_X) = sr*cp*cy - cr*sp*sy; + m_matrix(INDEX_Y) = cr*sp*cy + sr*cp*sy; + m_matrix(INDEX_Z) = cr*cp*sy - sr*sp*cy; + } + + double Quaternion::w() const { return m_matrix(INDEX_W); } + double Quaternion::x() const { return m_matrix(INDEX_X); } + double Quaternion::y() const { return m_matrix(INDEX_Y); } + double Quaternion::z() const { return m_matrix(INDEX_Z); } + Matrix Quaternion::vec() const { return m_matrix.get(INDEX_X, INDEX_Z, 0, 0); } + + Matrix Quaternion::matrix() const + { + return m_matrix; + } + + double Quaternion::norm() const + { + return m_matrix.norm_2(); + } + + Quaternion Quaternion::normalized() const + { + Quaternion q = *this; + q.normalize(); + return q; + } + + Matrix Quaternion::rotationMatrix() const + { + return (m_matrix / this->norm()).toDCM(); + } + + Matrix Quaternion::angVelTransform() const + { + double data[12] = { + -x(), -y(), -z(), + w(), -z(), y(), + z(), w(), -x(), + -y(), x(), w(), + }; + + return 0.5 * Matrix(data, 4, 3); + } + + void Quaternion::identity() + { + m_matrix.fill(0.0); + m_matrix(INDEX_W) = 1.0; + } + + void Quaternion::normalize() + { + m_matrix /= this->norm(); + } + + Quaternion Quaternion::operator-() const + { + return Quaternion(-this->matrix()); + } + + Quaternion& Quaternion::operator+=(const Quaternion& rhs) + { + m_matrix += rhs.matrix(); + return *this; + } + + Quaternion& Quaternion::operator-=(const Quaternion& rhs) + { + m_matrix -= rhs.matrix(); + return *this; + } + + Quaternion& Quaternion::operator*=(const Quaternion& rhs) + { + // Based on http://mathworld.wolfram.com/Quaternion.html. + const double _w = rhs.w()*w() - rhs.x()*x() - rhs.y()*y() - rhs.z()*z(); + const double _x = rhs.w()*x() + rhs.x()*w() - rhs.y()*z() + rhs.z()*y(); + const double _y = rhs.w()*y() + rhs.x()*z() + rhs.y()*w() - rhs.z()*x(); + const double _z = rhs.w()*z() - rhs.x()*y() + rhs.y()*x() + rhs.z()*w(); + + m_matrix(INDEX_W) = _w; + m_matrix(INDEX_X) = _x; + m_matrix(INDEX_Y) = _y; + m_matrix(INDEX_Z) = _z; + + return *this; + } + + Quaternion conjugate(const Quaternion& quat) + { + return Quaternion(quat.w(), -quat.x(), -quat.y(), -quat.z()); + } + + Quaternion inverse(const Quaternion& quat) + { + return conjugate(quat); + } + + Matrix transpose(const Quaternion& quat) + { + return transpose(quat.matrix()); + } + + bool operator==(const Quaternion& lhs, const Quaternion& rhs) + { + return lhs.matrix() == rhs.matrix(); + } + + bool operator!=(const Quaternion& lhs, const Quaternion& rhs) + { + return !(lhs == rhs); + } + + Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs) + { + Quaternion temp(lhs); + temp += rhs; + return temp; + } + + Quaternion operator+(const Quaternion& lhs, const Matrix& rhs) + { + if (!rhs.isColumnVector() || rhs.size() != 4) + throw std::invalid_argument("matrix must have size 4x1"); + + return Quaternion(lhs.matrix() + rhs); + } + + Quaternion operator+(const Matrix& lhs, const Quaternion& rhs) + { + if (lhs.isColumnVector() || lhs.size() != 4) + throw std::invalid_argument("matrix must have size 4x1"); + + return Quaternion(lhs + rhs.matrix()); + } + + Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs) + { + Quaternion temp(lhs); + temp *= rhs; + return temp; + } + + Matrix operator*(const Quaternion& lhs, const Matrix& rhs) + { + if (rhs.rows() != 1) + throw std::invalid_argument("matrix must have 1 row"); + + return lhs.matrix() * rhs; + } + + Matrix operator*(const Matrix& lhs, const Quaternion& rhs) + { + if (lhs.columns() != 4) + throw std::invalid_argument("matrix must have 4 columns"); + + return lhs * rhs.matrix(); + } + + std::ostream& operator<<(std::ostream& os, const Quaternion& quat) + { + os << quat.matrix(); + return os; + } + } +} diff --git a/src/DUNE/Math/Quaternion.hpp b/src/DUNE/Math/Quaternion.hpp new file mode 100644 index 0000000000..d57ba7238b --- /dev/null +++ b/src/DUNE/Math/Quaternion.hpp @@ -0,0 +1,82 @@ +#ifndef DUNE_MATH_QUATERNION_HPP_INCLUDED_ +#define DUNE_MATH_QUATERNION_HPP_INCLUDED_ + +#include +#include + +#include +#include + +namespace DUNE +{ + namespace Math + { + struct EulerAnglesZyx; + + // Quaternions on the form (w + ix + jy + kz) + // where w is the scalar part and v = (x, y, z) is the vector part. + class Quaternion + { + public: + // Initialize to the identity quaternion [1 0 0 0]. + Quaternion(); + + // Initialize from individual elements. + Quaternion(double qw, double qx, double qy, double qz); + + // Initialize from size 4 vector q = [w x y z]. + explicit Quaternion(const std::vector& q); + + // Initialize from real element w and size 3 vector v = [x y z]. + Quaternion(double qw, const std::vector& v); + + // Initialize from 4x1 Matrix q = [w x y z]. + explicit Quaternion(const Matrix& q); + + // Initialize from scalar element w and 3x1 Matrix v = [x y z]. + Quaternion(double qw, const Matrix& v); + + // Convert from ZYX-convention Euler angles. + explicit Quaternion(const EulerAnglesZyx& euler); + + double w() const; + double x() const; + double y() const; + double z() const; + Matrix vec() const; + + Matrix matrix() const; + double norm() const; + Quaternion normalized() const; + Matrix rotationMatrix() const; + Matrix angVelTransform() const; + + void identity(); + void normalize(); + + Quaternion operator-() const; + Quaternion& operator+=(const Quaternion& rhs); + Quaternion& operator-=(const Quaternion& rhs); + Quaternion& operator*=(const Quaternion& rhs); + private: + Matrix m_matrix; + enum Index {INDEX_W, INDEX_X, INDEX_Y, INDEX_Z}; + }; + + Quaternion conjugate(const Quaternion& quat); + Quaternion inverse(const Quaternion& quat); + Matrix transpose(const Quaternion& quat); + + bool operator==(const Quaternion& lhs, const Quaternion& rhs); + bool operator!=(const Quaternion& lhs, const Quaternion& rhs); + Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs); + Quaternion operator+(const Quaternion& lhs, const Matrix& rhs); + Quaternion operator+(const Matrix& lhs, const Quaternion& rhs); + Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs); + Matrix operator*(const Quaternion& lhs, const Matrix& rhs); + Matrix operator*(const Matrix& lhs, const Quaternion& rhs); + std::ostream& operator<<(std::ostream& os, const Quaternion& quat); + } +} + +#endif diff --git a/src/DUNE/Math/Random.hpp b/src/DUNE/Math/Random.hpp index a2534269af..ec564d9e37 100644 --- a/src/DUNE/Math/Random.hpp +++ b/src/DUNE/Math/Random.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/DRand48.cpp b/src/DUNE/Math/Random/DRand48.cpp index 5548484b52..5e091761ba 100644 --- a/src/DUNE/Math/Random/DRand48.cpp +++ b/src/DUNE/Math/Random/DRand48.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/DRand48.hpp b/src/DUNE/Math/Random/DRand48.hpp index f4a73ad59e..8485b9608c 100644 --- a/src/DUNE/Math/Random/DRand48.hpp +++ b/src/DUNE/Math/Random/DRand48.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/FSR256.cpp b/src/DUNE/Math/Random/FSR256.cpp index a4d6365dff..18bd3e29c3 100644 --- a/src/DUNE/Math/Random/FSR256.cpp +++ b/src/DUNE/Math/Random/FSR256.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/FSR256.hpp b/src/DUNE/Math/Random/FSR256.hpp index e4a68084e3..87bea7510d 100644 --- a/src/DUNE/Math/Random/FSR256.hpp +++ b/src/DUNE/Math/Random/FSR256.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/Factory.cpp b/src/DUNE/Math/Random/Factory.cpp index 12264d7c6a..403ef7a99d 100644 --- a/src/DUNE/Math/Random/Factory.cpp +++ b/src/DUNE/Math/Random/Factory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/Factory.hpp b/src/DUNE/Math/Random/Factory.hpp index 7f3cca66b9..df3a6542ae 100644 --- a/src/DUNE/Math/Random/Factory.hpp +++ b/src/DUNE/Math/Random/Factory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/Generator.cpp b/src/DUNE/Math/Random/Generator.cpp index cd40255363..b7c1f0df6e 100644 --- a/src/DUNE/Math/Random/Generator.cpp +++ b/src/DUNE/Math/Random/Generator.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/Generator.hpp b/src/DUNE/Math/Random/Generator.hpp index 25e4a60414..f89e76f23d 100644 --- a/src/DUNE/Math/Random/Generator.hpp +++ b/src/DUNE/Math/Random/Generator.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/KernelDevice.cpp b/src/DUNE/Math/Random/KernelDevice.cpp index 20f492da6a..df38834102 100644 --- a/src/DUNE/Math/Random/KernelDevice.cpp +++ b/src/DUNE/Math/Random/KernelDevice.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/KernelDevice.hpp b/src/DUNE/Math/Random/KernelDevice.hpp index 5061046a19..872ba20621 100644 --- a/src/DUNE/Math/Random/KernelDevice.hpp +++ b/src/DUNE/Math/Random/KernelDevice.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/MT19937.cpp b/src/DUNE/Math/Random/MT19937.cpp index f4e57e8700..a1fa809fe5 100644 --- a/src/DUNE/Math/Random/MT19937.cpp +++ b/src/DUNE/Math/Random/MT19937.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/MT19937.hpp b/src/DUNE/Math/Random/MT19937.hpp index 6b1668f77e..002334dbd4 100644 --- a/src/DUNE/Math/Random/MT19937.hpp +++ b/src/DUNE/Math/Random/MT19937.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Math/Random/TSGenerator.hpp b/src/DUNE/Math/Random/TSGenerator.hpp index 7d2405c592..6533d24ba1 100644 --- a/src/DUNE/Math/Random/TSGenerator.hpp +++ b/src/DUNE/Math/Random/TSGenerator.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media.hpp b/src/DUNE/Media.hpp index 0775242ca3..37483b014c 100644 --- a/src/DUNE/Media.hpp +++ b/src/DUNE/Media.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/BayerDecoder.cpp b/src/DUNE/Media/BayerDecoder.cpp index 7b39081e2e..2df9d8ea15 100644 --- a/src/DUNE/Media/BayerDecoder.cpp +++ b/src/DUNE/Media/BayerDecoder.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/BayerDecoder.hpp b/src/DUNE/Media/BayerDecoder.hpp index 965b5fb391..f35fca7a0e 100644 --- a/src/DUNE/Media/BayerDecoder.hpp +++ b/src/DUNE/Media/BayerDecoder.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/JPEGCompressor.cpp b/src/DUNE/Media/JPEGCompressor.cpp index 8e71e86c5d..fca677b5a1 100644 --- a/src/DUNE/Media/JPEGCompressor.cpp +++ b/src/DUNE/Media/JPEGCompressor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/JPEGCompressor.hpp b/src/DUNE/Media/JPEGCompressor.hpp index 9a2c5b4356..6af0a0dd2b 100644 --- a/src/DUNE/Media/JPEGCompressor.hpp +++ b/src/DUNE/Media/JPEGCompressor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/MJPG/AVIH.hpp b/src/DUNE/Media/MJPG/AVIH.hpp index 4edf51bcac..d10c015eca 100644 --- a/src/DUNE/Media/MJPG/AVIH.hpp +++ b/src/DUNE/Media/MJPG/AVIH.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/Chunk.hpp b/src/DUNE/Media/MJPG/Chunk.hpp index 36afc131d1..14c593b767 100644 --- a/src/DUNE/Media/MJPG/Chunk.hpp +++ b/src/DUNE/Media/MJPG/Chunk.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/Encoder.hpp b/src/DUNE/Media/MJPG/Encoder.hpp index 5532d27700..6e1272d165 100644 --- a/src/DUNE/Media/MJPG/Encoder.hpp +++ b/src/DUNE/Media/MJPG/Encoder.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/IDX1.hpp b/src/DUNE/Media/MJPG/IDX1.hpp index 2a5648ac77..af24510a3d 100644 --- a/src/DUNE/Media/MJPG/IDX1.hpp +++ b/src/DUNE/Media/MJPG/IDX1.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/ISFT.hpp b/src/DUNE/Media/MJPG/ISFT.hpp index b6fb3245b7..766f55f395 100644 --- a/src/DUNE/Media/MJPG/ISFT.hpp +++ b/src/DUNE/Media/MJPG/ISFT.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/List.hpp b/src/DUNE/Media/MJPG/List.hpp index e076244a1a..84f65e7938 100644 --- a/src/DUNE/Media/MJPG/List.hpp +++ b/src/DUNE/Media/MJPG/List.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/MJPG.hpp b/src/DUNE/Media/MJPG/MJPG.hpp index 10ccbb7986..106be80770 100644 --- a/src/DUNE/Media/MJPG/MJPG.hpp +++ b/src/DUNE/Media/MJPG/MJPG.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/Properties.hpp b/src/DUNE/Media/MJPG/Properties.hpp index a7273f70fa..57d8955f9a 100644 --- a/src/DUNE/Media/MJPG/Properties.hpp +++ b/src/DUNE/Media/MJPG/Properties.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/STRF.hpp b/src/DUNE/Media/MJPG/STRF.hpp index 6b709ec59c..5d32cc32b0 100644 --- a/src/DUNE/Media/MJPG/STRF.hpp +++ b/src/DUNE/Media/MJPG/STRF.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/STRH.hpp b/src/DUNE/Media/MJPG/STRH.hpp index 9a7ec92553..79eb27e749 100644 --- a/src/DUNE/Media/MJPG/STRH.hpp +++ b/src/DUNE/Media/MJPG/STRH.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/MJPG/TSTP.hpp b/src/DUNE/Media/MJPG/TSTP.hpp index 552f0b92fc..54b97230d0 100644 --- a/src/DUNE/Media/MJPG/TSTP.hpp +++ b/src/DUNE/Media/MJPG/TSTP.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * diff --git a/src/DUNE/Media/VideoCapture.cpp b/src/DUNE/Media/VideoCapture.cpp index 897dad08d8..200c6c33db 100644 --- a/src/DUNE/Media/VideoCapture.cpp +++ b/src/DUNE/Media/VideoCapture.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/VideoCapture.hpp b/src/DUNE/Media/VideoCapture.hpp index d49286b03e..7b42d13115 100644 --- a/src/DUNE/Media/VideoCapture.hpp +++ b/src/DUNE/Media/VideoCapture.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/VideoIIDC1394.cpp b/src/DUNE/Media/VideoIIDC1394.cpp index 8ad371e723..2e14503063 100644 --- a/src/DUNE/Media/VideoIIDC1394.cpp +++ b/src/DUNE/Media/VideoIIDC1394.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Media/VideoIIDC1394.hpp b/src/DUNE/Media/VideoIIDC1394.hpp index 3d3f566531..9d703fa91e 100644 --- a/src/DUNE/Media/VideoIIDC1394.hpp +++ b/src/DUNE/Media/VideoIIDC1394.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Memory.hpp b/src/DUNE/Memory.hpp index 8e915637cc..a554ac730d 100644 --- a/src/DUNE/Memory.hpp +++ b/src/DUNE/Memory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Monitors.hpp b/src/DUNE/Monitors.hpp index c61c2cf46a..6fafc14bf1 100644 --- a/src/DUNE/Monitors.hpp +++ b/src/DUNE/Monitors.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Monitors/DelayedTrigger.hpp b/src/DUNE/Monitors/DelayedTrigger.hpp index 471df20482..2469423e22 100644 --- a/src/DUNE/Monitors/DelayedTrigger.hpp +++ b/src/DUNE/Monitors/DelayedTrigger.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Monitors/MediumHandler.hpp b/src/DUNE/Monitors/MediumHandler.hpp index a8cc10beec..b42f5f9440 100644 --- a/src/DUNE/Monitors/MediumHandler.hpp +++ b/src/DUNE/Monitors/MediumHandler.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Monitors/MotorCurrentMonitor.hpp b/src/DUNE/Monitors/MotorCurrentMonitor.hpp index b070f309e4..f4717e8f62 100644 --- a/src/DUNE/Monitors/MotorCurrentMonitor.hpp +++ b/src/DUNE/Monitors/MotorCurrentMonitor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Monitors/ServoCurrentMonitor.hpp b/src/DUNE/Monitors/ServoCurrentMonitor.hpp index b318f0e212..bcf4cf770e 100644 --- a/src/DUNE/Monitors/ServoCurrentMonitor.hpp +++ b/src/DUNE/Monitors/ServoCurrentMonitor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Monitors/ServoPositionMonitor.hpp b/src/DUNE/Monitors/ServoPositionMonitor.hpp index f7eb25c44c..29084b39d3 100644 --- a/src/DUNE/Monitors/ServoPositionMonitor.hpp +++ b/src/DUNE/Monitors/ServoPositionMonitor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Monitors/VerticalMonitor.hpp b/src/DUNE/Monitors/VerticalMonitor.hpp index ffd5478c33..7f52df7ac1 100644 --- a/src/DUNE/Monitors/VerticalMonitor.hpp +++ b/src/DUNE/Monitors/VerticalMonitor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Navigation.hpp b/src/DUNE/Navigation.hpp index 0b1e90faa3..aeab6b034b 100644 --- a/src/DUNE/Navigation.hpp +++ b/src/DUNE/Navigation.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Navigation/BasicNavigation.cpp b/src/DUNE/Navigation/BasicNavigation.cpp index 8ca267ac12..045285dd28 100644 --- a/src/DUNE/Navigation/BasicNavigation.cpp +++ b/src/DUNE/Navigation/BasicNavigation.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -48,9 +48,10 @@ namespace DUNE BasicNavigation::BasicNavigation(const std::string& name, Tasks::Context& ctx): Tasks::Periodic(name, ctx), m_active(false), - m_origin(NULL), - m_avg_heave(NULL), - m_avg_gps(NULL) + m_origin(nullptr), + m_avg_heave(nullptr), + m_avg_gps(nullptr), + m_usbl_filter(nullptr) { // Declare configuration parameters. param("Maximum Distance to Reference", m_max_dis2ref) @@ -75,10 +76,14 @@ namespace DUNE .size(2) .description("Constants used in current LBL rejection scheme"); + param("Disable GPS for debug", m_gps_disable) + .defaultValue("false") + .description("Disable GPS for debug"); + param("GPS timeout", m_without_gps_timeout) .units(Units::Second) .defaultValue("3.0") - .minimumValue("2.0") + .minimumValue("1.5") .description("No GPS readings timeout"); param("DVL timeout", m_without_dvl_timeout) @@ -213,6 +218,17 @@ namespace DUNE .defaultValue("1.0") .description("Exponential moving average filter gain used in altitude"); + param("USBL Filter -- Moving Average Samples", m_usbl_avg_samples) + .defaultValue("5") + .minimumValue("5") + .maximumValue("20") + .description("Number of moving average samples for USBL filter"); + + param("USBL Filter -- Maximum Deviation Factor", m_usbl_k_std) + .minimumValue("1") + .defaultValue("2") + .description("Maximum deviation possible to issue error"); + // Do not use the declination offset when simulating. m_use_declination = !m_ctx.profiles.isSelected("Simulation"); m_declination_defined = false; @@ -275,6 +291,7 @@ namespace DUNE void BasicNavigation::onResourceInitialization(void) { + m_usbl_filter = new UsblTools::Filter(m_usbl_avg_samples, m_usbl_k_std); m_avg_heave = new Math::MovingAverage(m_avg_heave_samples); m_avg_gps = new Math::MovingAverage(m_avg_gps_samples); reset(); @@ -330,6 +347,7 @@ namespace DUNE Memory::clear(m_origin); Memory::clear(m_avg_heave); Memory::clear(m_avg_gps); + Memory::clear(m_usbl_filter); } void @@ -342,7 +360,7 @@ namespace DUNE std::fabs(msg->y) > c_max_accel || std::fabs(msg->z) > c_max_accel) { - war(DTR("received acceleration beyond range: %f, %f, %f"), + err(DTR("received acceleration beyond range: %f, %f, %f"), msg->x, msg->y, msg->z); return; @@ -498,6 +516,9 @@ namespace DUNE void BasicNavigation::consume(const IMC::GpsFix* msg) { + + if (m_gps_disable== true) + return; if (msg->type == IMC::GpsFix::GFT_MANUAL_INPUT) return; @@ -755,6 +776,9 @@ namespace DUNE { if (msg->target != getSystemName()) return; + + if (!m_usbl_filter->consume(msg)) + return; double x = 0.0; double y = 0.0; @@ -874,7 +898,7 @@ namespace DUNE { reset(); - if (m_origin == NULL) + if (m_origin == nullptr) return false; m_estate.lat = m_origin->lat; @@ -1005,6 +1029,8 @@ namespace DUNE m_uncertainty.x = m_kal.getCovariance(STATE_X, STATE_X); m_uncertainty.y = m_kal.getCovariance(STATE_Y, STATE_Y); m_navdata.cyaw = m_heading; + + m_usbl_filter->consume(&m_estate); } bool diff --git a/src/DUNE/Navigation/BasicNavigation.hpp b/src/DUNE/Navigation/BasicNavigation.hpp index ca68e5b21e..f93202c71e 100644 --- a/src/DUNE/Navigation/BasicNavigation.hpp +++ b/src/DUNE/Navigation/BasicNavigation.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -130,19 +131,19 @@ namespace DUNE //! Update internal parameters. virtual void - onUpdateParameters(void); + onUpdateParameters(void) override; //! Resolve entities. virtual void - onEntityResolution(void); + onEntityResolution(void) override; //! Initialize resources. virtual void - onResourceInitialization(void); + onResourceInitialization(void) override; //! Release allocated resources. virtual void - onResourceRelease(void); + onResourceRelease(void) override; void consume(const IMC::Acceleration* msg); @@ -657,6 +658,8 @@ namespace DUNE float m_altitude; //! DVL entity label. std::string m_elabel_dvl; + //! GPS disable for debug + bool m_gps_disable; //! Altitude entity label hardware. std::string m_elabel_alt_hard; //! Altitude entity label simulation. @@ -720,6 +723,12 @@ namespace DUNE uint8_t m_gvel_val_bits; //! DVL water velocity validation bits. uint8_t m_wvel_val_bits; + //! USBL position filter. + UsblTools::Filter* m_usbl_filter; + //! Number of moving average samples for USBL filter. + unsigned m_usbl_avg_samples; + //! Maximum deviation possible to issue error. + double m_usbl_k_std; }; } } diff --git a/src/DUNE/Navigation/BeamFilter.hpp b/src/DUNE/Navigation/BeamFilter.hpp index d8b41e919a..342fee88b5 100644 --- a/src/DUNE/Navigation/BeamFilter.hpp +++ b/src/DUNE/Navigation/BeamFilter.hpp @@ -1,7 +1,9 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** +// Copyright 2018 OceanScan - Marine Systems & Technology, Lda. * +//*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * // Commercial Licence Usage * @@ -35,6 +37,8 @@ #include // DUNE headers. +#include +#include #include #include @@ -64,7 +68,8 @@ namespace DUNE //! Filter spacing. enum Spacing { - STANDARD, + CLOCKWISE, + ANTICLOCKWISE, CROSSED }; @@ -271,7 +276,9 @@ namespace DUNE m_list[0].location.push_back(ds); // Beam 2. - if (m_type == STANDARD) + if (m_type == CLOCKWISE) + ds.psi += Math::Angles::radians(90.0); + else if (m_type == ANTICLOCKWISE) ds.psi -= Math::Angles::radians(90.0); else ds.psi += Math::Angles::radians(180.0); @@ -280,13 +287,18 @@ namespace DUNE m_list[1].location.push_back(ds); // Beam 3. - ds.psi -= Math::Angles::radians(90.0); + if (m_type == CLOCKWISE) + ds.psi += Math::Angles::radians(90.0); + else + ds.psi -= Math::Angles::radians(90.0); ds.x = m_position[0] + std::cos(ds.psi) * m_offset; ds.y = m_position[1] + std::sin(ds.psi) * m_offset; m_list[2].location.push_back(ds); // Beam 4. - if (m_type == STANDARD) + if (m_type == CLOCKWISE) + ds.psi += Math::Angles::radians(90.0); + else if (m_type == ANTICLOCKWISE) ds.psi -= Math::Angles::radians(90.0); else ds.psi -= Math::Angles::radians(180.0); diff --git a/src/DUNE/Navigation/CompassCalibration.hpp b/src/DUNE/Navigation/CompassCalibration.hpp index 9f146e3a4b..7daf198917 100644 --- a/src/DUNE/Navigation/CompassCalibration.hpp +++ b/src/DUNE/Navigation/CompassCalibration.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Navigation/KalmanFilter.cpp b/src/DUNE/Navigation/KalmanFilter.cpp index 48a4e85f73..3370d2872a 100644 --- a/src/DUNE/Navigation/KalmanFilter.cpp +++ b/src/DUNE/Navigation/KalmanFilter.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Navigation/KalmanFilter.hpp b/src/DUNE/Navigation/KalmanFilter.hpp index a782706be2..09bf6623e5 100644 --- a/src/DUNE/Navigation/KalmanFilter.hpp +++ b/src/DUNE/Navigation/KalmanFilter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Navigation/Ranging.hpp b/src/DUNE/Navigation/Ranging.hpp index 50ef3c20c2..6eeb5c8e9a 100644 --- a/src/DUNE/Navigation/Ranging.hpp +++ b/src/DUNE/Navigation/Ranging.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Navigation/StreamEstimator.hpp b/src/DUNE/Navigation/StreamEstimator.hpp index c0ced34c6a..16e7a2200e 100644 --- a/src/DUNE/Navigation/StreamEstimator.hpp +++ b/src/DUNE/Navigation/StreamEstimator.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Navigation/UsblTools.hpp b/src/DUNE/Navigation/UsblTools.hpp index 9501b276e8..7646876af1 100644 --- a/src/DUNE/Navigation/UsblTools.hpp +++ b/src/DUNE/Navigation/UsblTools.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 OceanScan - Marine Systems & Technology, Lda. * +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * // * @@ -25,6 +25,7 @@ //*************************************************************************** // Author: José Braga * // Author: Raúl Sáez * +// Author: Luis Venancio * //*************************************************************************** #ifndef DUNE_NAVIGATION_USBL_TOOLS_HPP_INCLUDED_ @@ -35,6 +36,8 @@ #include // DUNE headers. +#include +#include #include #include @@ -49,19 +52,23 @@ namespace DUNE { public: //! Request frame: start/stop mask. - static const uint8_t c_mask_start = 0x10; + static constexpr uint8_t c_mask_start = 0x10; //! Request frame: absolute fix mask. - static const uint8_t c_mask_fix = 0x01; + static constexpr uint8_t c_mask_fix = 0x01; + //! Request frame: inverted mode. + static constexpr uint8_t c_mask_inverted = 0x02; //! Request frame: size of frame.Size of frame: request. - static const uint8_t c_fsize_req = 5; + static constexpr uint8_t c_fsize_req = 5; //! Node or modem destination identifier mask. - static const uint8_t c_target_mask = 0x80; + static constexpr uint8_t c_target_mask = 0x80; //! Code placement in received frame messages. - static const uint8_t c_code = 2; + static constexpr uint8_t c_code = 2; //! Minimum time interval between consecutive requests from node. - static const uint16_t c_requests_interval = 30; + static constexpr uint16_t c_requests_interval = 30; //! Number of communication timeouts before considering that a system has failed. - static const uint8_t c_max_comm_timeout = 5; + static constexpr uint8_t c_max_comm_timeout = 5; + //! Origin validity timeout. + static constexpr uint8_t c_origin_timeout = 5; enum Codes { @@ -69,7 +76,9 @@ namespace DUNE CODE_RPL = c_target_mask, CODE_FIX = c_target_mask | 0x01, CODE_POS = c_target_mask | 0x02, - CODE_ANG = c_target_mask | 0x03 + CODE_ANG = c_target_mask | 0x03, + CODE_INV = c_target_mask | 0x04, + CODE_ORG = 0x05 }; enum RequestIndexes @@ -86,6 +95,107 @@ namespace DUNE fp32_t z; uint8_t z_units; fp32_t accuracy; + + //! Decode an incoming data frame into a fix message. + //! @param[out] frame fix structure. + //! @param[in] data incoming frame. + static void + decode(Fix& frame, const std::vector& data) + { + uint8_t* ptr = (uint8_t*)&data[c_code + 1]; + + uint16_t length = (uint16_t)Fix::size(); + ptr += IMC::deserialize(frame.lat, ptr, length); + ptr += IMC::deserialize(frame.lon, ptr, length); + ptr += IMC::deserialize(frame.z, ptr, length); + ptr += IMC::deserialize(frame.z_units, ptr, length); + ptr += IMC::deserialize(frame.accuracy, ptr, length); + } + + //! Encode a fix message into a data frame. + //! @param[in] frame fix structure. + //! @param[out] data data frame. + static void + encode(Fix& frame, std::vector& data) + { + data.resize(Fix::size() + 2); + data[c_code - 1] = CODE_FIX; + + uint8_t* ptr = (uint8_t*)&data[c_code]; + + ptr += IMC::serialize(frame.lat, ptr); + ptr += IMC::serialize(frame.lon, ptr); + ptr += IMC::serialize(frame.z, ptr); + ptr += IMC::serialize(frame.z_units, ptr); + ptr += IMC::serialize(frame.accuracy, ptr); + } + + //! Get size of frame. + //! @return size of fix structure. + static size_t + size(void) + { + return 2 * (sizeof(fp64_t) + sizeof(fp32_t)) + sizeof(uint8_t); + } + }; + + struct Gps + { + fp64_t lat; + fp64_t lon; + fp32_t z; + + //! Decode an incoming data frame into a gps message. + //! @param[out] frame gps structure. + //! @param[in] data incoming frame. + static void + decode(Gps& frame, const std::vector& data) + { + uint8_t* ptr = (uint8_t*)&data[c_code + 1]; + + uint16_t length = (uint16_t)Gps::size(); + ptr += IMC::deserialize(frame.lat, ptr, length); + ptr += IMC::deserialize(frame.lon, ptr, length); + ptr += IMC::deserialize(frame.z, ptr, length); + } + + //! Encode a fix message into a data frame. + //! @param[in] frame fix structure. + //! @param[out] data data frame. + static void + encode(Gps& frame, std::vector& data) + { + data.resize(Gps::size() + 2); + data[c_code - 1] = CODE_ORG; + + uint8_t* ptr = (uint8_t*)&data[c_code]; + + ptr += IMC::serialize(frame.lat, ptr); + ptr += IMC::serialize(frame.lon, ptr); + ptr += IMC::serialize(frame.z, ptr); + } + + //! Decode an incoming data frame into a gps message. + //! @param[out] frame gps structure. + //! @param[in] data incoming frame. + static void + decode(IMC::GpsFix& msg, const std::vector& data) + { + uint8_t* ptr = (uint8_t*)&data[c_code + 1]; + + uint16_t length = (uint16_t)Gps::size(); + ptr += IMC::deserialize(msg.lat, ptr, length); + ptr += IMC::deserialize(msg.lon, ptr, length); + ptr += IMC::deserialize(msg.height, ptr, length); + } + + //! Get size of frame. + //! @return size of fix structure. + static size_t + size(void) + { + return 2 * sizeof(fp64_t) + sizeof(fp32_t); + } }; //! Position data structure. @@ -97,7 +207,53 @@ namespace DUNE fp32_t n; fp32_t e; fp32_t d; - fp32_t accuracy; + uint8_t accuracy; + + //! Decode an incoming data frame into a position message. + //! @param[out] frame position structure. + //! @param[in] data incoming frame. + static void + decode(Position& frame, const std::vector& data) + { + uint8_t* ptr = (uint8_t*)&data[c_code + 1]; + + uint16_t length = (uint16_t)Position::size(); + ptr += IMC::deserialize(frame.x, ptr, length); + ptr += IMC::deserialize(frame.y, ptr, length); + ptr += IMC::deserialize(frame.z, ptr, length); + ptr += IMC::deserialize(frame.n, ptr, length); + ptr += IMC::deserialize(frame.e, ptr, length); + ptr += IMC::deserialize(frame.d, ptr, length); + ptr += IMC::deserialize(frame.accuracy, ptr, length); + } + + //! Encode a position message into a data frame. + //! @param[in] frame position structure. + //! @param[out] data data frame. + static void + encode(Position& frame, std::vector& data) + { + data.resize(Position::size() + 2); + data[c_code - 1] = CODE_POS; + + uint8_t* ptr = (uint8_t*)&data[c_code]; + + ptr += IMC::serialize(frame.x, ptr); + ptr += IMC::serialize(frame.y, ptr); + ptr += IMC::serialize(frame.z, ptr); + ptr += IMC::serialize(frame.n, ptr); + ptr += IMC::serialize(frame.e, ptr); + ptr += IMC::serialize(frame.d, ptr); + ptr += IMC::serialize(frame.accuracy, ptr); + } + + //! Get size of frame. + //! @return size of position structure. + static size_t + size(void) + { + return (6 * sizeof(fp32_t) + sizeof(uint8_t)); + } }; //! Angles data structure. @@ -108,6 +264,48 @@ namespace DUNE fp32_t bearing; fp32_t elevation; fp32_t accuracy; + + //! Decode an incoming data frame into an angles message. + //! @param[out] frame angles structure. + //! @param[in] data incoming frame. + static void + decode(Angles& frame, const std::vector& data) + { + uint8_t* ptr = (uint8_t*)&data[c_code + 1]; + + uint16_t length = (uint16_t)Angles::size(); + ptr += IMC::deserialize(frame.lbearing, ptr, length); + ptr += IMC::deserialize(frame.lelevation, ptr, length); + ptr += IMC::deserialize(frame.bearing, ptr, length); + ptr += IMC::deserialize(frame.elevation, ptr, length); + ptr += IMC::deserialize(frame.accuracy, ptr, length); + } + + //! Encode an angles message into a data frame. + //! @param[in] frame angles structure. + //! @param[out] data data frame. + static void + encode(Angles& frame, std::vector& data) + { + data.resize(Angles::size() + 2); + data[c_code - 1] = CODE_ANG; + + uint8_t* ptr = (uint8_t*)&data[c_code]; + + ptr += IMC::serialize(frame.lbearing, ptr); + ptr += IMC::serialize(frame.lelevation, ptr); + ptr += IMC::serialize(frame.bearing, ptr); + ptr += IMC::serialize(frame.elevation, ptr); + ptr += IMC::serialize(frame.accuracy, ptr); + } + + //! Get size of frame. + //! @return size of angles structure. + static size_t + size(void) + { + return 5 * sizeof(fp32_t); + } }; //! This method checks if code is intended for nodes or USBL modem. @@ -123,23 +321,26 @@ namespace DUNE } static IMC::UsblFixExtended - toFix(const IMC::UsblPositionExtended& usbl, const IMC::GpsFix& gps) + toFix(const IMC::UsblPositionExtended& usbl, const IMC::GpsFix& gps, bool inverted = false) { - return toFix(usbl, gps.lat, gps.lon, gps.height, IMC::Z_HEIGHT); + return toFix(usbl, gps.lat, gps.lon, gps.height, IMC::Z_HEIGHT, inverted); } static IMC::UsblFixExtended - toFix(const IMC::UsblPositionExtended& usbl, const IMC::EstimatedState& state) + toFix(const IMC::UsblPositionExtended& usbl, const IMC::EstimatedState& state, bool inverted = false) { double lat, lon; Coordinates::toWGS84(state, lat, lon); - return toFix(usbl, lat, lon, state.depth, IMC::Z_DEPTH); + return toFix(usbl, lat, lon, state.depth, IMC::Z_DEPTH, inverted); } static IMC::UsblFixExtended - toFix(const IMC::UsblPositionExtended& usbl, double lat, double lon, float z, IMC::ZUnits z_units) + toFix(const IMC::UsblPositionExtended& usbl, double lat, double lon, float z, IMC::ZUnits z_units, bool inverted = false) { - Coordinates::WGS84::displace(usbl.n, usbl.e, &lat, &lon); + if (!inverted) + Coordinates::WGS84::displace(usbl.n, usbl.e, &lat, &lon); + else + Coordinates::WGS84::displace(-usbl.n, -usbl.e, &lat, &lon); IMC::UsblFixExtended fix; fix.target = usbl.target; @@ -160,7 +361,7 @@ namespace DUNE class Node { public: - //! Target arguments. + //! Node arguments. struct Arguments { //! True to enable target request. @@ -171,18 +372,20 @@ namespace DUNE bool fix; //! Quick mode, without range. bool no_range; + //! Inverted mode. + bool inverted; }; //! Constructor. - Node(Tasks::Task* task, const Arguments* args): + Node(Tasks::Task* const task, const Arguments* args): + m_args(args), m_usbl_alive(false), m_wait_reply(false), - m_args(args), + m_fix(m_args->fix), + m_inverted(m_args->inverted), + m_period(m_args->period), m_task(task) { - m_period = m_args->period; - m_fix = m_args->fix; - // in quick mode, we actively ping the modem if (m_args->no_range) { @@ -235,9 +438,12 @@ namespace DUNE } //! Parse incoming frame. + //! @param[in] imc_src IMC id of message source. //! @param[in] msg received acoustic frame. - void - parse(uint16_t imc_src, const IMC::UamRxFrame* msg) + //! @param[out] data frame to be send. + //! @return true if there's data to be sent, false otherwise. + bool + parse(uint16_t imc_src, const IMC::UamRxFrame* msg, std::vector& data) { switch ((uint8_t)msg->data[c_code]) { @@ -250,6 +456,7 @@ namespace DUNE { std::memcpy(&m_period, &msg->data[REQ_PERIOD], sizeof(uint16_t)); m_fix = msg->data[REQ_START] & c_mask_fix; + m_inverted = msg->data[REQ_START] & c_mask_inverted; m_usbl_alive = true; m_comm_timeout_timer.setTop(c_max_comm_timeout * m_period); } @@ -257,15 +464,13 @@ namespace DUNE { m_usbl_alive = false; } - - m_usbl_name = msg->sys_src; } break; case CODE_FIX: { UsblTools::Fix fs; - std::memcpy(&fs, &msg->data[c_code + 1], sizeof(UsblTools::Fix)); + Fix::decode(fs, msg->data); IMC::UsblFixExtended fix; fix.setSource(imc_src); @@ -286,7 +491,7 @@ namespace DUNE case CODE_POS: { UsblTools::Position ps; - std::memcpy(&ps, &msg->data[c_code + 1], sizeof(UsblTools::Position)); + Position::decode(ps, msg->data); IMC::UsblPositionExtended pos; pos.setSource(imc_src); @@ -297,7 +502,7 @@ namespace DUNE pos.n = ps.n; pos.e = ps.e; pos.d = ps.d; - pos.accuracy = ps.accuracy; + pos.accuracy = (fp32_t) ps.accuracy; if (!getFix(msg->sys_src, pos)) m_task->dispatch(pos); @@ -311,7 +516,7 @@ namespace DUNE case CODE_ANG: { UsblTools::Angles as; - std::memcpy(&as, &msg->data[c_code + 1], sizeof(UsblTools::Angles)); + Angles::decode(as, msg->data); IMC::UsblAnglesExtended ang; ang.setSource(imc_src); @@ -325,11 +530,25 @@ namespace DUNE m_task->dispatch(ang); break; } + + case CODE_INV: + { + UsblTools::Gps gps; + gps.lat = m_origin.lat; + gps.lon = m_origin.lon; + gps.z = m_origin.height; + + Gps::encode(gps, data); + + return true; + } } + + return false; } //! Consume a USBL configuration message. - //! param[in] msg The UsblConfig message with a list of UsblModem messages. + //! @param[in] msg The UsblConfig message with a list of UsblModem messages. void consume(const IMC::UsblConfig* msg) { @@ -347,6 +566,17 @@ namespace DUNE } } + //! Consume a GpsFix message and save system position. + //! @param[in] msg GpsFix message. + void + consume(const IMC::GpsFix* msg) + { + if (msg->type == IMC::GpsFix::GFT_MANUAL_INPUT) + return; + + m_origin = *msg; + } + private: //! Encode a request to be transmitted by node. //! @param[out] data frame to be send. @@ -367,6 +597,9 @@ namespace DUNE if (m_args->fix) data[REQ_START - 1] |= c_mask_fix; + if (m_args->inverted) + data[REQ_START - 1] |= c_mask_inverted; + if (m_args->enabled) data[REQ_START - 1] |= c_mask_start; @@ -380,18 +613,17 @@ namespace DUNE //! @param[in] pos the position stored into a UsblPositionExtended. //! @return true if the fix has been dispatched, false otherwise. bool - getFix(std::string modem, const IMC::UsblPositionExtended& pos) + getFix(const std::string& modem, const IMC::UsblPositionExtended& pos) { - IMC::MessageList::const_iterator itr = m_config.modems.begin(); - for (; itr < m_config.modems.end(); ++itr) + for (const auto& itr : m_config.modems) { - if ((*itr) == NULL) + if (itr == nullptr) continue; - if ((*itr)->name == modem) + if (itr->name == modem) { - IMC::UsblFixExtended fix = toFix(pos, (*itr)->lat, (*itr)->lon, (*itr)->z, - (IMC::ZUnits)(*itr)->z_units); + IMC::UsblFixExtended fix = toFix(pos, itr->lat, itr->lon, itr->z, + static_cast(itr->z_units)); m_task->dispatch(fix); return true; } @@ -400,14 +632,16 @@ namespace DUNE return false; } + //! Class arguments. + const Arguments* m_args; //! True if USBL is on. bool m_usbl_alive; //! True if waiting reply. bool m_wait_reply; - //! USBL system. - std::string m_usbl_name; //! Absolute fix or request relative position. bool m_fix; + //! Inverted mode flag. + bool m_inverted; //! Periodicity. uint16_t m_period; //! USBL configuration. @@ -416,10 +650,10 @@ namespace DUNE Time::Counter m_node_timer; //! Communication timeout timer. Time::Counter m_comm_timeout_timer; - //! Class arguments. - const Arguments* m_args; //! Pointer to task. - Tasks::Task* m_task; + Tasks::Task* const m_task; + //! Local position + IMC::GpsFix m_origin; }; //! USBL tools handler ticket. @@ -430,19 +664,20 @@ namespace DUNE //! @param[in] name target's name. //! @param[in] fix absolute fix or relative positioning //! @param[in] period target's desired periodicity. - Target(std::string name, bool fix, uint16_t period): + Target(std::string name, bool fix, bool inverted, uint16_t period): + m_name(std::move(name)), + m_fix(fix), + m_inverted(inverted), + m_period(period), m_comm_errors(0) { - m_name = name; - m_fix = fix; - m_period = period; m_target_timer.setTop(m_period); } //! Time to track target. //! @return true, if timer has overflown. bool - trigger(void) + trigger() { if (m_target_timer.overflow()) { @@ -457,21 +692,20 @@ namespace DUNE //! @param[in] name name of target. //! @return true if target's name is matched. bool - compare(std::string name) + compare(const std::string& name) const { - if (m_name == name) - return true; - - return false; + return m_name == name; } //! Reset variables of target. - //! @param[in] return absolute fixes or relative position. + //! @param[in] fix return absolute fixes or relative position. + //! @param[in] inverted inverted mode flag. //! @param[in] period desired periodicity. void - reset(bool fix, uint16_t period) + reset(bool fix, bool inverted, uint16_t period) { m_fix = fix; + m_inverted = inverted; m_period = period; m_target_timer.setTop(m_period); resetErrors(); @@ -480,7 +714,7 @@ namespace DUNE //! Get target's name. //! @return target's name. std::string - getName(void) + getName() const { return m_name; } @@ -489,40 +723,100 @@ namespace DUNE //! @return true if target's wants absolute fix, //! false otherwise. bool - wantsFix(void) + wantsFix() const { return m_fix; } + //! Check if target is for inverted mode. + //! @return true if target is set as inverted, + //! false otherwise. + bool + isInverted() const + { + return m_inverted; + } + //! Check if the target node has failed. //! @return true if target has reached threshold, false otherwise. bool - hasFailed(void) + hasFailed() { - if (++m_comm_errors >= c_max_comm_timeout) - return true; - - return false; + return ++m_comm_errors >= c_max_comm_timeout; } //! Reset count of errors. void - resetErrors(void) + resetErrors() { m_comm_errors = 0; } + + //! Set target's absolute position. + //! @param[in] msg GpsFix message of target's position. + void + setOrigin(const IMC::GpsFix* msg) + { + m_origin = *msg; + m_origin_timer.setTop(c_origin_timeout); + } + + //! Get target's absolute position. + //! @param[out] msg GpsFix message of target's position. + //! @return true if message is valid and has been filled, false otherwise. + bool + getOrigin(IMC::GpsFix& msg) + { + if (m_origin_timer.overflow()) + return false; + + msg = m_origin; + return true; + } + + //! Set target's relative position. + //! @param[in] msg UsblPositionExtended message of target's position. + void + setRelativePosition(const IMC::UsblPositionExtended* msg) + { + m_rpos = *msg; + m_rpos_timer.setTop(c_origin_timeout); + } + + //! Get target's relative position. + //! @param[out] msg UsblPositionExtended message of target's position. + //! @return true if message is valid and has been filled, false otherwise. + bool + getRelativePosition(IMC::UsblPositionExtended& msg) + { + if (m_rpos_timer.overflow()) + return false; + + msg = m_rpos; + return true; + } private: //! Target name. std::string m_name; //! Absolute or relative fix. bool m_fix; + //! Inverted mode. + bool m_inverted; //! Periodicity. uint16_t m_period; //! Number of communication errors uint8_t m_comm_errors; //! Target's desired period timer. Time::Counter m_target_timer; + //! Target's absolute position timer. + Time::Counter m_origin_timer; + //! Target's absolute position. + IMC::GpsFix m_origin; + //! Target's relative position timer. + Time::Counter m_rpos_timer; + //! Target's relative position. + IMC::UsblPositionExtended m_rpos; }; //! USBL tools handler. @@ -530,22 +824,17 @@ namespace DUNE { public: //! Constructor. - Modem(void) + Modem(Tasks::Task* const task): + m_task(task) { } //! This function verifies if we are waiting for the target's reply. //! @param[in] name name of the target. //! @return true if we are waiting, false otherwise. bool - waitingForSystem(std::string name) + waitingForSystem(const std::string& name) const { - if (m_system.empty()) - return false; - - if (name == m_system) - return true; - - return false; + return !m_system.empty() && name == m_system; } //! Trigger through all targets. @@ -568,14 +857,13 @@ namespace DUNE } // Iterate and call triggers. - std::vector::iterator itr = m_list.begin(); - for (; itr != m_list.end(); ++itr) + for (auto& target : m_list) { - if (itr->trigger()) + if (target.trigger()) { // we'll track this system - m_system = itr->getName(); - name = itr->getName(); + m_system = target.getName(); + name = target.getName(); // reset timer. m_modem_wdog.setTop(time); @@ -590,15 +878,13 @@ namespace DUNE //! @return true if target wants an absolute fix, //! false if it wants a relative position. bool - wantsFix(std::string name) + wantsFix(const std::string& name) const { - // Iterate through list and add if necessary. - std::vector::iterator itr = m_list.begin(); - for (; itr != m_list.end(); ++itr) + for (const auto& target : m_list) { // Same target - if (itr->compare(name)) - return itr->wantsFix(); + if (target.compare(name)) + return target.wantsFix(); } // default is relative positioning to be @@ -606,12 +892,34 @@ namespace DUNE return false; } + //! Get if target's is set for inverted mode. + //! @return true if target wants an absolute fix, + //! false if it wants a relative position. + bool + isInverted(const std::string& name, std::vector& data) const + { + // Iterate through list. + for (const auto& target : m_list) + { + // Same target + if (target.compare(name) && target.isInverted()) + { + data.push_back(CODE_INV); + return true; + } + } + + // default is non inverted. + return false; + } + //! Parse incoming frame. + //! @param[in] imc_src IMC id of message source. //! @param[in] msg received acoustic frame. //! @param[out] data frame to be send. //! @return true if there's data to be sent, false otherwise. bool - parse(const IMC::UamRxFrame* msg, std::vector& data) + parse(uint16_t imc_src, const IMC::UamRxFrame* msg, std::vector& data) { if ((uint8_t)msg->data[c_code] == CODE_REQ) { @@ -632,7 +940,8 @@ namespace DUNE } bool fix = msg->data[REQ_START] & c_mask_fix; - add(msg->sys_src, fix, period); + bool inverted = msg->data[REQ_START] & c_mask_inverted; + add(msg->sys_src, fix, inverted, period); } else { @@ -646,6 +955,97 @@ namespace DUNE data[c_code - 1] = CODE_RPL; return true; } + else if ((uint8_t)msg->data[c_code] == CODE_ORG) + { + // Check if we are targeting this system + if (msg->sys_src != m_system) + return false; + + // Get absolute origin of message + IMC::GpsFix origin; + origin.setSource(imc_src); + Gps::decode(origin, msg->data); + + if (!Modem::consume(&origin)) + return false; + + IMC::UsblFixExtended fix; + if (invertedFix(m_system, fix)) + m_task->dispatch(fix); + + // Target replyed to ping + targetReplied(m_system); + m_system.clear(); + } + + return false; + } + + //! Set target's relative position. + //! @param[in] msg UsblPositionExtended message of target's position. + //! @return true if position set, false otherwise. + bool + consume(const IMC::UsblPositionExtended* msg) + { + // Iterate through list and set relative position if required. + for (auto& target : m_list) + { + // Same target + if (target.compare(msg->target)) + { + target.setRelativePosition(msg); + return true; + } + } + + return false; + } + + //! Set target's absolute position. + //! @param[in] msg GpsFix message of target's position. + //! @return true if position set, false otherwise. + bool + consume(const IMC::GpsFix* msg) + { + // Iterate through list and set origin if required. + for (auto& target : m_list) + { + // Same target + if (target.compare(m_system)) + { + target.setOrigin(msg); + return true; + } + } + + return false; + } + + //! Compute absolute fix of system from absolute and relative positions of target + //! @param[in] name Target's name. + //! @param[out] fix self fix message. + //! @return true if able to compute fix and fill message, false otherwise. + bool + invertedFix(const std::string& name, IMC::UsblFixExtended& fix) + { + // Iterate through list and compute absolute fix + for (auto& target : m_list) + { + // Same target + if (target.compare(name)) + { + IMC::GpsFix gps; + IMC::UsblPositionExtended rpos; + + //! Check timeout + if (!target.getOrigin(gps) || !target.getRelativePosition(rpos)) + return false; + + fix = UsblTools::toFix(rpos, gps, true); + fix.target = m_task->getSystemName(); + return true; + } + } return false; } @@ -663,8 +1063,6 @@ namespace DUNE if (m_system != msg->target) return false; - data.resize(sizeof(UsblTools::Fix) + 2); - UsblTools::Fix fix; fix.lat = msg->lat; fix.lon = msg->lon; @@ -672,8 +1070,7 @@ namespace DUNE fix.z_units = msg->z_units; fix.accuracy = msg->accuracy; - data[c_code - 1] = CODE_FIX; - std::memcpy(&data[c_code], &fix, sizeof(UsblTools::Fix)); + Fix::encode(fix, data); targetReplied(m_system); m_system.clear(); @@ -693,8 +1090,6 @@ namespace DUNE if (m_system != msg->target) return false; - data.resize(sizeof(UsblTools::Position) + 2); - UsblTools::Position pos; pos.x = msg->x; pos.y = msg->y; @@ -702,10 +1097,12 @@ namespace DUNE pos.n = msg->n; pos.e = msg->e; pos.d = msg->d; - pos.accuracy = msg->accuracy; + if (msg->accuracy > 255) + pos.accuracy = 255; + else + pos.accuracy = (uint8_t) msg->accuracy; - data[c_code - 1] = CODE_POS; - std::memcpy(&data[c_code], &pos, sizeof(UsblTools::Position)); + Position::encode(pos, data); targetReplied(m_system); m_system.clear(); @@ -726,8 +1123,6 @@ namespace DUNE if (m_system != msg->target) return false; - data.resize(sizeof(UsblTools::Angles) + 2); - UsblTools::Angles ang; ang.lbearing = msg->lbearing; ang.lelevation = msg->lelevation; @@ -735,8 +1130,7 @@ namespace DUNE ang.elevation = msg->elevation; ang.accuracy = msg->accuracy; - data[c_code - 1] = CODE_ANG; - std::memcpy(&data[c_code], &ang, sizeof(UsblTools::Angles)); + Angles::encode(ang, data); m_system.clear(); return true; @@ -748,30 +1142,29 @@ namespace DUNE //! @param[in] fix absolute fix or relative positioning //! @param[in] period target's desired periodicity. void - add(std::string name, bool fix, uint16_t period) + add(const std::string& name, bool fix, bool inverted, uint16_t period) { // Iterate through list and add if necessary. - std::vector::iterator itr = m_list.begin(); - for (; itr != m_list.end(); ++itr) + for (auto& target : m_list) { // Same target - if (itr->compare(name)) + if (target.compare(name)) { - itr->reset(fix, period); + target.reset(fix, inverted, period); return; } } - m_list.push_back(Target(name, fix, period)); + m_list.emplace_back(name, fix, inverted, period); } //! Remove target. //! @param[in] target target's name. void - remove(std::string name) + remove(const std::string& name) { // Iterate through list and remove target. - std::vector::iterator itr = m_list.begin(); + auto itr = m_list.begin(); for (; itr != m_list.end(); ++itr) { // Erase target from list. @@ -785,7 +1178,7 @@ namespace DUNE //! Clear current list of targets. void - clear(void) + clear() { m_list.clear(); } @@ -793,16 +1186,15 @@ namespace DUNE //! Target is alive and replying. //! @param[in] name target's name. void - targetReplied(std::string name) + targetReplied(const std::string& name) { - // Iterate through list and remove if necessary. - std::vector::iterator itr = m_list.begin(); - for (; itr != m_list.end(); ++itr) + // Iterate through list and reset any errors. + for (auto& target : m_list) { // Same target - if (itr->compare(name)) + if (target.compare(name)) { - itr->resetErrors(); + target.resetErrors(); return; } } @@ -811,10 +1203,10 @@ namespace DUNE //! Target failed to reply. //! @param[in] name target's name. void - targetFailed(std::string name) + targetFailed(const std::string& name) { // Iterate through list and remove if necessary. - std::vector::iterator itr = m_list.begin(); + auto itr = m_list.begin(); for (; itr != m_list.end(); ++itr) { // Same target @@ -836,6 +1228,54 @@ namespace DUNE std::string m_system; //! Maximum amount of time waiting for system's reply. Time::Counter m_modem_wdog; + //! Pointer to task. + Tasks::Task* const m_task; + }; + + //! USBL position filter. + class Filter + { + public: + //! Constructor. + Filter(unsigned avg_samples, double k_std): + m_avg_range(avg_samples), + m_k_std(k_std) + { } + + //! Set last received state + void + consume(const IMC::EstimatedState* msg) + { + m_last_state = *msg; + } + + //! Set last received USBL fix + //! @return true if position passes filter, false otherwise. + bool + consume(const IMC::UsblFixExtended* msg) + { + double lat, lon; + double range, bearing; + Coordinates::toWGS84(m_last_state, lat, lon); + Coordinates::WGS84::getNEBearingAndRange(lat, lon, + msg->lat, msg->lon, + &range, &bearing); + + double mean_range = m_avg_range.update(range); + double std_range = m_avg_range.stdev(); + + double diff_to_mean = std::abs(range - mean_range); + + return diff_to_mean <= m_k_std * std_range; + } + + private: + //! Moving average of distance between estimated state and USBL Fix + Math::MovingAverage m_avg_range; + //! Standard deviation multiplication factor to issue error. + double m_k_std; + //! Last received estimated state + IMC::EstimatedState m_last_state; }; }; } diff --git a/src/DUNE/Network.hpp b/src/DUNE/Network.hpp index 0059804dee..36e6841b5d 100644 --- a/src/DUNE/Network.hpp +++ b/src/DUNE/Network.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -45,5 +45,6 @@ namespace DUNE #include #include #include +#include #endif diff --git a/src/DUNE/Network/Address.cpp b/src/DUNE/Network/Address.cpp index 6fd03b4062..7774061df8 100644 --- a/src/DUNE/Network/Address.cpp +++ b/src/DUNE/Network/Address.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Address.hpp b/src/DUNE/Network/Address.hpp index b553410405..dba4c8768a 100644 --- a/src/DUNE/Network/Address.hpp +++ b/src/DUNE/Network/Address.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Exceptions.hpp b/src/DUNE/Network/Exceptions.hpp index 8cf50301da..7063abb79f 100644 --- a/src/DUNE/Network/Exceptions.hpp +++ b/src/DUNE/Network/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/FragmentedMessage.cpp b/src/DUNE/Network/FragmentedMessage.cpp index a6ee17636c..ed28e1853f 100644 --- a/src/DUNE/Network/FragmentedMessage.cpp +++ b/src/DUNE/Network/FragmentedMessage.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/FragmentedMessage.hpp b/src/DUNE/Network/FragmentedMessage.hpp index 9ed175c886..24d59f2f18 100644 --- a/src/DUNE/Network/FragmentedMessage.hpp +++ b/src/DUNE/Network/FragmentedMessage.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Fragments.cpp b/src/DUNE/Network/Fragments.cpp index 775f7380d8..20eb36838b 100644 --- a/src/DUNE/Network/Fragments.cpp +++ b/src/DUNE/Network/Fragments.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Fragments.hpp b/src/DUNE/Network/Fragments.hpp index c688c88085..b0e751208f 100644 --- a/src/DUNE/Network/Fragments.hpp +++ b/src/DUNE/Network/Fragments.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Initializer.cpp b/src/DUNE/Network/Initializer.cpp index eaa9a55104..9a6f459413 100644 --- a/src/DUNE/Network/Initializer.cpp +++ b/src/DUNE/Network/Initializer.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Initializer.hpp b/src/DUNE/Network/Initializer.hpp index 7fe725bf2c..e76d820999 100644 --- a/src/DUNE/Network/Initializer.hpp +++ b/src/DUNE/Network/Initializer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Interface.cpp b/src/DUNE/Network/Interface.cpp index 3d555e7cd1..badb544555 100644 --- a/src/DUNE/Network/Interface.cpp +++ b/src/DUNE/Network/Interface.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/Interface.hpp b/src/DUNE/Network/Interface.hpp index f71d3640c0..f891f7a9f9 100644 --- a/src/DUNE/Network/Interface.hpp +++ b/src/DUNE/Network/Interface.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/TCPSocket.cpp b/src/DUNE/Network/TCPSocket.cpp index a9d46ce745..01e1e045bb 100644 --- a/src/DUNE/Network/TCPSocket.cpp +++ b/src/DUNE/Network/TCPSocket.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/TCPSocket.hpp b/src/DUNE/Network/TCPSocket.hpp index 0be5b8b5e3..17351720bf 100644 --- a/src/DUNE/Network/TCPSocket.hpp +++ b/src/DUNE/Network/TCPSocket.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/TDMA.hpp b/src/DUNE/Network/TDMA.hpp index d6544219d5..a669a1cdfe 100644 --- a/src/DUNE/Network/TDMA.hpp +++ b/src/DUNE/Network/TDMA.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/UDPSocket.cpp b/src/DUNE/Network/UDPSocket.cpp index 194ca54ac8..6d0c532df4 100644 --- a/src/DUNE/Network/UDPSocket.cpp +++ b/src/DUNE/Network/UDPSocket.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/UDPSocket.hpp b/src/DUNE/Network/UDPSocket.hpp index ec2d6302e9..bcf3ca5685 100644 --- a/src/DUNE/Network/UDPSocket.hpp +++ b/src/DUNE/Network/UDPSocket.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/URL.cpp b/src/DUNE/Network/URL.cpp index 72938a1b21..8522f22b08 100644 --- a/src/DUNE/Network/URL.cpp +++ b/src/DUNE/Network/URL.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/URL.hpp b/src/DUNE/Network/URL.hpp index 8e225c2ec1..8161df6d23 100644 --- a/src/DUNE/Network/URL.hpp +++ b/src/DUNE/Network/URL.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Network/UpstreamTCPServer.hpp b/src/DUNE/Network/UpstreamTCPServer.hpp new file mode 100644 index 0000000000..30b184a902 --- /dev/null +++ b/src/DUNE/Network/UpstreamTCPServer.hpp @@ -0,0 +1,113 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Ricardo Martins * +//*************************************************************************** + +#ifndef DUNE_NETWORK_UPSTREAM_TCP_SERVER_HPP_INCLUDED_ +#define DUNE_NETWORK_UPSTREAM_TCP_SERVER_HPP_INCLUDED_ + +// DUNE headers. +#include +#include +#include +#include +#include + +namespace DUNE +{ + namespace Network + { + class UpstreamTCPServer: public Concurrency::Thread + { + public: + UpstreamTCPServer(Tasks::Task* parent, int port): + m_parent(parent), + m_port(port), + m_sock(nullptr), + m_client(nullptr) + { + m_sock = new Network::TCPSocket(); + m_sock->bind(m_port); + m_sock->listen(4); + m_sock->setKeepAlive(true); + m_sock->setNoDelay(true); + m_sock->setSendTimeout(1.0); + } + + ~UpstreamTCPServer() override + { + Memory::clear(m_client); + Memory::clear(m_sock); + } + + void + sendToClient(const uint8_t* bfr, size_t bfr_size) + { + if (m_client == nullptr) + return; + + try + { + m_client->write(bfr, bfr_size); + } + catch (...) + { + Memory::clear(m_client); + } + } + + void + run() override + { + while (!isStopping()) + { + if (!IO::Poll::poll(*m_sock, 1.0)) + continue; + + try + { + Network::TCPSocket* client = m_sock->accept(); + Memory::clear(m_client); + m_client = client; + } + catch (...) + { } + } + } + + private: + //! Parent task. + Tasks::Task* m_parent; + //! Listening port. + int m_port; + //! Socket handle. + Network::TCPSocket* m_sock; + //! Client. + Network::TCPSocket* m_client; + }; + } +} + +#endif diff --git a/src/DUNE/Parsers.hpp b/src/DUNE/Parsers.hpp index cfe4f523b4..0f2077ebb6 100644 --- a/src/DUNE/Parsers.hpp +++ b/src/DUNE/Parsers.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -40,11 +40,13 @@ namespace DUNE #include #include #include +#include #include #include #include #include #include #include +#include #endif diff --git a/src/DUNE/Parsers/AbstractStringReader.hpp b/src/DUNE/Parsers/AbstractStringReader.hpp index 04ba9bd08c..5318a763b7 100644 --- a/src/DUNE/Parsers/AbstractStringReader.hpp +++ b/src/DUNE/Parsers/AbstractStringReader.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/AbstractStringWriter.hpp b/src/DUNE/Parsers/AbstractStringWriter.hpp index af0dd3fcb3..1612eb57b4 100644 --- a/src/DUNE/Parsers/AbstractStringWriter.hpp +++ b/src/DUNE/Parsers/AbstractStringWriter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/BasicStringReader.hpp b/src/DUNE/Parsers/BasicStringReader.hpp index eab5446ed7..34ce4dc7c0 100644 --- a/src/DUNE/Parsers/BasicStringReader.hpp +++ b/src/DUNE/Parsers/BasicStringReader.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/BasicStringWriter.hpp b/src/DUNE/Parsers/BasicStringWriter.hpp index be466a681e..f4add39d70 100644 --- a/src/DUNE/Parsers/BasicStringWriter.hpp +++ b/src/DUNE/Parsers/BasicStringWriter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/Config.cpp b/src/DUNE/Parsers/Config.cpp index e86ed73022..729094480a 100644 --- a/src/DUNE/Parsers/Config.cpp +++ b/src/DUNE/Parsers/Config.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -83,6 +83,8 @@ namespace DUNE void Config::parseFile(const char* fname) { + Concurrency::ScopedRWLock(m_data_lock, false); + char line[c_max_bfr_size] = {0}; char section[c_max_bfr_size] = {0}; char option[c_max_bfr_size] = {0}; @@ -108,7 +110,7 @@ namespace DUNE // Section name. if (std::sscanf(line, "[%[^]]] ", section) == 1) { - String::rtrim(section); + String::rightTrimInPlace(section); if (std::strncmp(section, "Include ", 8) == 0) { @@ -136,10 +138,25 @@ namespace DUNE if (section_count == 0) throw SyntaxError(fname, line_count); - String::rtrim(option); - String::rtrim(arg); + String::rightTrimInPlace(option); + String::rightTrimInPlace(arg); + + bool append = false; + if (String::endsWith(String::str(option), "+")) + { + String::resize(option, -1); + // append if a previous value already exists + append = m_data[section].find(option) != m_data[section].end(); + } + std::strncpy(tmp, option, c_max_bfr_size); - m_data[section][option] = arg; + if (append) + { + m_data[section][option] += ", "; + m_data[section][option] += arg; + } + else + m_data[section][option] = arg; if (std::strlen(arg) < 4) continue; @@ -163,7 +180,10 @@ namespace DUNE if (section_count == 0) throw SyntaxError(fname, line_count); - String::rtrim(arg); + if (String::endsWith(String::str(option), "+")) + String::resize(option, -1); + + String::rightTrimInPlace(arg); m_data[section][tmp] += " "; m_data[section][tmp] += arg; } @@ -189,6 +209,8 @@ namespace DUNE std::vector Config::sections(void) { + Concurrency::ScopedRWLock(m_data_lock, false); + std::vector vec; for (Sections::iterator itr = m_data.begin(); itr != m_data.end(); ++itr) vec.push_back(itr->first); @@ -198,6 +220,8 @@ namespace DUNE std::vector Config::options(const std::string& section) { + Concurrency::ScopedRWLock(m_data_lock, false); + Sections::const_iterator sitr = m_data.find(section); if (sitr == m_data.end()) @@ -215,6 +239,8 @@ namespace DUNE std::ostream& operator<<(std::ostream& os, const Config& cfg) { + Concurrency::ScopedRWLock(cfg.m_data_lock, false); + Config::Sections::const_iterator sections; Config::Section::const_iterator labels; std::string banner = String::str("Generated by DUNE v%s", getFullVersion()); @@ -223,7 +249,6 @@ namespace DUNE << std::setw(74) << ";" << std::endl << String::str("; %-71s;", banner.c_str()) << std::endl << std::setw(74) << ";" << std::endl; - for (sections = cfg.m_data.begin(); sections != cfg.m_data.end(); ++sections) { os << "[" << (*sections).first << "]" << std::endl; diff --git a/src/DUNE/Parsers/Config.hpp b/src/DUNE/Parsers/Config.hpp index dac5c5dbbe..3fcd72c1db 100644 --- a/src/DUNE/Parsers/Config.hpp +++ b/src/DUNE/Parsers/Config.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -82,6 +82,7 @@ namespace DUNE void set(const std::string& section, const std::string& option, const std::string& value) { + Concurrency::ScopedRWLock(m_data_lock, true); m_data[section][option] = value; } @@ -92,6 +93,7 @@ namespace DUNE std::string get(const std::string& section, const std::string& option) { + Concurrency::ScopedRWLock(m_data_lock, false); return m_data[section][option]; } @@ -101,6 +103,7 @@ namespace DUNE void setSection(const std::string& section, const std::map& map) { + Concurrency::ScopedRWLock(m_data_lock, true); m_data[section] = map; } @@ -110,6 +113,7 @@ namespace DUNE std::map getSection(const std::string& section) { + Concurrency::ScopedRWLock(m_data_lock, false); return m_data[section]; } @@ -122,6 +126,7 @@ namespace DUNE void get(const std::string& sec, const std::string& opt, const std::string& def, Type& var) { + Concurrency::ScopedRWLock(m_data_lock, false); if (m_data[sec].find(opt) != m_data[sec].end()) { if (castLexical(m_data[sec][opt], var)) @@ -201,6 +206,9 @@ namespace DUNE //! List of parsed files. std::vector m_files; + //! Configuration map lock + mutable Concurrency::RWLock m_data_lock; + // Non - copyable. Config(const Config&); diff --git a/src/DUNE/Parsers/Exceptions.hpp b/src/DUNE/Parsers/Exceptions.hpp index 6aa5df9c65..316d9f58ec 100644 --- a/src/DUNE/Parsers/Exceptions.hpp +++ b/src/DUNE/Parsers/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/HDF5Reader.cpp b/src/DUNE/Parsers/HDF5Reader.cpp new file mode 100644 index 0000000000..63a0846a3f --- /dev/null +++ b/src/DUNE/Parsers/HDF5Reader.cpp @@ -0,0 +1,220 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#include +#include + +#include "DUNE/I18N.hpp" + +// This component depends on the h5cpp library +// (https://github.com/ess-dmsc/h5cpp.com). +// To enable support for h5cpp, set the H5CPP flag to 1 when calling CMake. +// If support for h5cpp is not enabled, the compilation will not fail, but +// the constructor of HDF5Reader will throw. +#if DUNE_H5CPP_ENABLED +# include "h5cpp/hdf5.hpp" +#else +// Define hdf5::file::File to avoid compilation errors due to incomplete type +namespace hdf5 +{ + namespace file + { + class File + {}; + } // namespace file +} // namespace hdf5 +#endif + +#include "HDF5Reader.hpp" + +namespace DUNE +{ + namespace Parsers + { + HDF5Reader::HDF5Reader(std::string const& filename) + : m_file(std::make_unique()) + { +#ifndef DUNE_H5CPP_ENABLED + (void)filename; + throw std::runtime_error( + DTR("HDF5Reader::HDF5Reader(): support for HDF5 i/o is not " + "enabled.")); +#else + try + { + *m_file = hdf5::file::open(filename, hdf5::file::AccessFlags::READONLY); + + if (m_file == nullptr) + throw; + } + catch (...) + { + throw std::runtime_error( + DTR("HDF5Reader::HDF5Reader(): unable to open file.")); + } +#endif + } + + HDF5Reader::~HDF5Reader() = default; + +#ifdef DUNE_H5CPP_ENABLED + inline bool + dsetExists(File const* f, std::string const& path) + { + return f->root().has_dataset(path); + return false; + } +#endif + + bool + HDF5Reader::datasetExists(std::string const& path) const + { +#ifdef DUNE_H5CPP_ENABLED + return dsetExists(m_file.get(), path); +#else + (void)path; + return false; +#endif + } + + template + HDF5Reader::HDF5Dataset + HDF5Reader::getDataset(std::string const& path) const + { +#ifdef DUNE_H5CPP_ENABLED + if (!dsetExists(m_file.get(), path)) + throw std::runtime_error( + DTR("HDF5Reader::getDataset(): The requested dataset does not " + "exist.")); + + auto dset = m_file->root().get_dataset(path); + auto dimensions = + hdf5::dataspace::Simple(dset.dataspace()).current_dimensions(); + + // Total number of gridpoints is the product of the sizes of all + // dimensions. + size_t size = std::accumulate( + std::begin(dimensions), std::end(dimensions), 1, std::multiplies()); + + std::vector data(size); + dset.read(data); + + // Convert elements of dimensions to size_t + std::vector dimensions_(dimensions.size()); + + std::copy(std::begin(dimensions), + std::end(dimensions), + std::begin(dimensions_)); + + return {dimensions_, data}; +#else + (void)path; + return {}; +#endif + } + + template + std::vector + HDF5Reader::getAttribute(std::string const& path, + std::string const& attribute) const + { +#ifdef DUNE_H5CPP_ENABLED + auto node = hdf5::node::get_node(m_file->root(), path); + auto attributes = node.attributes; + + if (!attributes.exists(attribute)) + throw std::runtime_error( + DTR("HDF5Reader::getAttribute(): requested attribute does not " + "exist.")); + + auto attr_handle = attributes[attribute]; + + std::vector data(attr_handle.dataspace().size()); + + attr_handle.read(data); + + return data; +#else + (void)path; + (void)attribute; + return {}; +#endif + } + + // Template specialization declarations for getDataset + template HDF5Reader::HDF5Dataset + HDF5Reader::getDataset(std::string const&) const; + + template HDF5Reader::HDF5Dataset + HDF5Reader::getDataset(std::string const&) const; + + template HDF5Reader::HDF5Dataset + HDF5Reader::getDataset(std::string const&) const; + + // Template specialization declarations for getAttribute + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + + template std::vector + HDF5Reader::getAttribute(std::string const&, + std::string const&) const; + } // namespace Parsers +} // namespace DUNE diff --git a/src/DUNE/Parsers/HDF5Reader.hpp b/src/DUNE/Parsers/HDF5Reader.hpp new file mode 100644 index 0000000000..a6ee7c6e43 --- /dev/null +++ b/src/DUNE/Parsers/HDF5Reader.hpp @@ -0,0 +1,102 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#ifndef DUNE_PARSERS_HDF5_READER_HPP_INCLUDED_ +#define DUNE_PARSERS_HDF5_READER_HPP_INCLUDED_ + +#include +#include +#include +#include + +namespace hdf5 +{ + namespace file + { + class File; + } +} // namespace hdf5 + +namespace DUNE +{ + namespace Parsers + { + using hdf5::file::File; + + //! Simplifies reading data and attributes from HDF5 format files. + class HDF5Reader + { + public: + //! Constructor. + //! @param[in] filename path to an hdf5 file. + HDF5Reader(std::string const& filename); + + //! Destructor. + ~HDF5Reader(); + + //! Structure holding an arbitrary multidimensional HDF5 dataset. + template + struct HDF5Dataset + { + //! Number of points in each dimension. + std::vector dimensions; + //! The data values in row-major (C-style) order. + std::vector data; + }; + + //! Check if a dataset exists in the given file. + //! @param[in] path path to the dataset in the file. + //! @return whether the dataset exists in the file. + bool + datasetExists(std::string const& path) const; + + //! Get a dataset and its dimensions. + //! @param[in] path path to the dataset in the file. + //! @return structure containing the data and the dataset dimensions. + template + HDF5Dataset + getDataset(std::string const& path) const; + + //! Get an attribute. + //! @param[in] path path to the node in the file where the attribute is + //! stored. + //! @param[in] attribute name of the attribute to get. + //! @return the attribute's data. + template + std::vector + getAttribute(std::string const& path, std::string const& attribute) const; + + private: + //! Handle to an HDF5 file. + std::unique_ptr m_file; + }; + } // namespace Parsers +} // namespace DUNE + +#endif diff --git a/src/DUNE/Parsers/NMEAReader.cpp b/src/DUNE/Parsers/NMEAReader.cpp index b3c0b3664f..0791f6b721 100644 --- a/src/DUNE/Parsers/NMEAReader.cpp +++ b/src/DUNE/Parsers/NMEAReader.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/NMEAReader.hpp b/src/DUNE/Parsers/NMEAReader.hpp index 01b9e015ab..12c8d70106 100644 --- a/src/DUNE/Parsers/NMEAReader.hpp +++ b/src/DUNE/Parsers/NMEAReader.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/NMEASentence.hpp b/src/DUNE/Parsers/NMEASentence.hpp new file mode 100644 index 0000000000..70c141266a --- /dev/null +++ b/src/DUNE/Parsers/NMEASentence.hpp @@ -0,0 +1,186 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Ricardo Martins * +//*************************************************************************** + +#ifndef DUNE_PARSERS_NMEA_SENTENCE_HPP_INCLUDED_ +#define DUNE_PARSERS_NMEA_SENTENCE_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include +#include + +// DUNE headers. +#include +#include +#include +#include + +namespace DUNE +{ + namespace Parsers + { + // Export DLL Symbol. + class DUNE_DLL_SYM NMEASentence; + + //! NMEA Sentence reader is a simple NMEA parser capable of + //! validating and converting sentence fields. + class NMEASentence + { + public: + explicit + NMEASentence(char start_sym = '$') + { + m_start_sym.push_back(start_sym); + clear(); + } + + const std::string& + getCode() const + { + return m_fields[0]; + } + + void + setCode(const std::string& code) + { + m_fields[0] = code; + } + + const std::string& + getField(size_t index) const + { + return m_fields[index + 1]; + } + + void + setField(size_t index, const std::string& value) + { + if (index + 1 >= m_fields.size()) + m_fields.resize(index + 2); + + m_fields[index + 1] = value; + } + + void + setField(size_t index, const char* fmt, ...) + { + std::va_list ap; + va_start(ap, fmt); + std::string result = Utils::String::strVl(fmt, ap); + va_end(ap); + setField(index, result); + } + + //! Retrieve the number of fields currently present in the sentence. + //! + //! @return number of fields. + size_t + getFieldCount() const + { + return m_fields.size() - 1; + } + + std::string + str() const + { + std::string data = Utils::String::join(m_fields.begin(), m_fields.end(), ","); + return m_start_sym + + data + + Utils::String::str("*%02X\r\n", computeChecksum(data, 0, data.size())); + } + + //! Clear sentence. + void + clear() + { + m_fields.clear(); + m_fields.emplace_back(""); + } + + //! Parse NMEA sentence. + //! @param[in] text string with NMEA sentence. + void + parse(const std::string& text) + { + std::string str_trim(Utils::String::trim(text)); + if (str_trim[0] != m_start_sym[0]) + throw std::runtime_error(DTR("invalid start symbol")); + + uint8_t ccsum = computeChecksum(str_trim, 1, str_trim.size() - 4); + uint8_t rcsum = readChecksum(str_trim); + if (ccsum != rcsum) + throw InvalidChecksum(); + + m_fields.clear(); + Utils::String::split(str_trim.substr(1, str_trim.size() - 4), ",", m_fields); + } + + private: + //! Start of sentence symbol. + std::string m_start_sym; + //! List of fields. + std::vector m_fields; + + uint8_t + computeChecksum(const std::string& text, size_t pos, size_t len) const + { + return Algorithms::XORChecksum::compute((const uint8_t*)&text[pos], len); + } + + uint8_t + readChecksum(const std::string& text) const + { + size_t idx = text.find_last_of('*'); + if ((idx == std::string::npos) || (text.size() - idx) != 3) + return 0; + + uint8_t result = 0; + unsigned shift = 4; + + for (size_t i = idx + 1; i < text.size(); ++i) + { + uint8_t byte = text[i]; + + if (byte >= '0' && byte <= '9') + result |= (byte - '0') << shift; + else if (byte >= 'a' && byte <= 'f') + result |= (byte - 'a' + 10) << shift; + else if (byte >= 'A' && byte <= 'F') + result |= (byte - 'A' + 10) << shift; + else + throw InvalidChecksum(); + + shift = 0; + } + + return result; + } + }; + } +} + +#endif diff --git a/src/DUNE/Parsers/NMEAWriter.cpp b/src/DUNE/Parsers/NMEAWriter.cpp index bc33671b67..6a9dd6c9f8 100644 --- a/src/DUNE/Parsers/NMEAWriter.cpp +++ b/src/DUNE/Parsers/NMEAWriter.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -100,6 +100,7 @@ namespace DUNE << std::hex << (unsigned)csum << "\r\n"; + m_stream.seekp(5, m_stream.end); return m_stream.str(); } } diff --git a/src/DUNE/Parsers/NMEAWriter.hpp b/src/DUNE/Parsers/NMEAWriter.hpp index 370a199822..14b2cd58a2 100644 --- a/src/DUNE/Parsers/NMEAWriter.hpp +++ b/src/DUNE/Parsers/NMEAWriter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/PD4.cpp b/src/DUNE/Parsers/PD4.cpp index 5ee3f30664..77cf738231 100644 --- a/src/DUNE/Parsers/PD4.cpp +++ b/src/DUNE/Parsers/PD4.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/PD4.hpp b/src/DUNE/Parsers/PD4.hpp index 0508ddf8ed..46b6cf26eb 100644 --- a/src/DUNE/Parsers/PD4.hpp +++ b/src/DUNE/Parsers/PD4.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/PlanConfigParser.cpp b/src/DUNE/Parsers/PlanConfigParser.cpp index b90906c812..90c4e7bd29 100644 --- a/src/DUNE/Parsers/PlanConfigParser.cpp +++ b/src/DUNE/Parsers/PlanConfigParser.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Parsers/PlanConfigParser.hpp b/src/DUNE/Parsers/PlanConfigParser.hpp index f6f886ba85..0dc66c383f 100644 --- a/src/DUNE/Parsers/PlanConfigParser.hpp +++ b/src/DUNE/Parsers/PlanConfigParser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Plans.hpp b/src/DUNE/Plans.hpp index a2852c1359..2df187b289 100644 --- a/src/DUNE/Plans.hpp +++ b/src/DUNE/Plans.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Plans/Progress.cpp b/src/DUNE/Plans/Progress.cpp index af4d5a08f9..1031258037 100644 --- a/src/DUNE/Plans/Progress.cpp +++ b/src/DUNE/Plans/Progress.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Plans/Progress.hpp b/src/DUNE/Plans/Progress.hpp index 9ef5f95e7f..6f321e0db6 100644 --- a/src/DUNE/Plans/Progress.hpp +++ b/src/DUNE/Plans/Progress.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Plans/SpeedModel.cpp b/src/DUNE/Plans/SpeedModel.cpp index 1a8cabae87..9617ce2161 100644 --- a/src/DUNE/Plans/SpeedModel.cpp +++ b/src/DUNE/Plans/SpeedModel.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Plans/SpeedModel.hpp b/src/DUNE/Plans/SpeedModel.hpp index 3ddd238e5c..5e6e06d106 100644 --- a/src/DUNE/Plans/SpeedModel.hpp +++ b/src/DUNE/Plans/SpeedModel.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Plans/TimeProfile.cpp b/src/DUNE/Plans/TimeProfile.cpp index fafa9d9fcc..298f80e50e 100644 --- a/src/DUNE/Plans/TimeProfile.cpp +++ b/src/DUNE/Plans/TimeProfile.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Plans/TimeProfile.hpp b/src/DUNE/Plans/TimeProfile.hpp index 62dc591677..b9a5a1ffa9 100644 --- a/src/DUNE/Plans/TimeProfile.hpp +++ b/src/DUNE/Plans/TimeProfile.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Power.hpp b/src/DUNE/Power.hpp index d095845fff..6762b19537 100644 --- a/src/DUNE/Power.hpp +++ b/src/DUNE/Power.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Power/Model.cpp b/src/DUNE/Power/Model.cpp index 33f694aebd..81f90e9b16 100644 --- a/src/DUNE/Power/Model.cpp +++ b/src/DUNE/Power/Model.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Power/Model.hpp b/src/DUNE/Power/Model.hpp index 8445779115..a4ea8ab380 100644 --- a/src/DUNE/Power/Model.hpp +++ b/src/DUNE/Power/Model.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Simulation/UAV.cpp b/src/DUNE/Simulation/UAV.cpp index 299065a9fd..6aa4eaef86 100644 --- a/src/DUNE/Simulation/UAV.cpp +++ b/src/DUNE/Simulation/UAV.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Simulation/UAV.hpp b/src/DUNE/Simulation/UAV.hpp index e9d865e8e6..470c2d30c6 100644 --- a/src/DUNE/Simulation/UAV.hpp +++ b/src/DUNE/Simulation/UAV.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Status.hpp b/src/DUNE/Status.hpp index 591cc6d788..706d41ec6d 100644 --- a/src/DUNE/Status.hpp +++ b/src/DUNE/Status.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Status/Codes.def b/src/DUNE/Status/Codes.def index 322f0fe9aa..4606fff143 100644 --- a/src/DUNE/Status/Codes.def +++ b/src/DUNE/Status/Codes.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Status/Codes.hpp b/src/DUNE/Status/Codes.hpp index e6381eae35..9c35ddb31c 100644 --- a/src/DUNE/Status/Codes.hpp +++ b/src/DUNE/Status/Codes.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Status/Messages.cpp b/src/DUNE/Status/Messages.cpp index 352b8e86ea..e6d761396a 100644 --- a/src/DUNE/Status/Messages.cpp +++ b/src/DUNE/Status/Messages.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Status/Messages.hpp b/src/DUNE/Status/Messages.hpp index 7e56a4c263..f1ad04d626 100644 --- a/src/DUNE/Status/Messages.hpp +++ b/src/DUNE/Status/Messages.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Streams.hpp b/src/DUNE/Streams.hpp index f14bc3a6a5..5b8cc52f5f 100644 --- a/src/DUNE/Streams.hpp +++ b/src/DUNE/Streams.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Streams/OutputMultiplexer.hpp b/src/DUNE/Streams/OutputMultiplexer.hpp index a4aa33e918..7433e2c678 100644 --- a/src/DUNE/Streams/OutputMultiplexer.hpp +++ b/src/DUNE/Streams/OutputMultiplexer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Streams/OutputMultiplexerBuffer.cpp b/src/DUNE/Streams/OutputMultiplexerBuffer.cpp index 5b713af378..ea6f36d6db 100644 --- a/src/DUNE/Streams/OutputMultiplexerBuffer.cpp +++ b/src/DUNE/Streams/OutputMultiplexerBuffer.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Streams/OutputMultiplexerBuffer.hpp b/src/DUNE/Streams/OutputMultiplexerBuffer.hpp index 3e96df073e..109f8fdd44 100644 --- a/src/DUNE/Streams/OutputMultiplexerBuffer.hpp +++ b/src/DUNE/Streams/OutputMultiplexerBuffer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Streams/Terminal.cpp b/src/DUNE/Streams/Terminal.cpp index e688132915..8580ca3cb6 100644 --- a/src/DUNE/Streams/Terminal.cpp +++ b/src/DUNE/Streams/Terminal.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Streams/Terminal.hpp b/src/DUNE/Streams/Terminal.hpp index 95238a1f88..e42d19e0ba 100644 --- a/src/DUNE/Streams/Terminal.hpp +++ b/src/DUNE/Streams/Terminal.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System.hpp b/src/DUNE/System.hpp index 0679f49cd6..83fb19e9c9 100644 --- a/src/DUNE/System.hpp +++ b/src/DUNE/System.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System/DynamicLoader.cpp b/src/DUNE/System/DynamicLoader.cpp index 729c0047c8..4e109b462e 100644 --- a/src/DUNE/System/DynamicLoader.cpp +++ b/src/DUNE/System/DynamicLoader.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System/DynamicLoader.hpp b/src/DUNE/System/DynamicLoader.hpp index 2f73f4b823..15babfba9d 100644 --- a/src/DUNE/System/DynamicLoader.hpp +++ b/src/DUNE/System/DynamicLoader.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System/Environment.cpp b/src/DUNE/System/Environment.cpp index 7a55384af4..6a2cda51c7 100644 --- a/src/DUNE/System/Environment.cpp +++ b/src/DUNE/System/Environment.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System/Environment.hpp b/src/DUNE/System/Environment.hpp index 8331711514..5e2a7b9389 100644 --- a/src/DUNE/System/Environment.hpp +++ b/src/DUNE/System/Environment.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System/Error.hpp b/src/DUNE/System/Error.hpp index 35283029ec..5440bfe734 100644 --- a/src/DUNE/System/Error.hpp +++ b/src/DUNE/System/Error.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System/Resources.cpp b/src/DUNE/System/Resources.cpp index bb8ce2263f..1b317691d9 100644 --- a/src/DUNE/System/Resources.cpp +++ b/src/DUNE/System/Resources.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/System/Resources.hpp b/src/DUNE/System/Resources.hpp index 71125e40c3..fc80a52ef8 100644 --- a/src/DUNE/System/Resources.hpp +++ b/src/DUNE/System/Resources.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks.hpp b/src/DUNE/Tasks.hpp index 20e6fffb17..09c8430308 100644 --- a/src/DUNE/Tasks.hpp +++ b/src/DUNE/Tasks.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/AbstractConsumer.hpp b/src/DUNE/Tasks/AbstractConsumer.hpp index b83fbd2000..405e464453 100644 --- a/src/DUNE/Tasks/AbstractConsumer.hpp +++ b/src/DUNE/Tasks/AbstractConsumer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/AbstractCreator.hpp b/src/DUNE/Tasks/AbstractCreator.hpp index 143e187b2b..baaede4019 100644 --- a/src/DUNE/Tasks/AbstractCreator.hpp +++ b/src/DUNE/Tasks/AbstractCreator.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/AbstractParameterParser.hpp b/src/DUNE/Tasks/AbstractParameterParser.hpp index cbde1d9809..83fdb13e5a 100644 --- a/src/DUNE/Tasks/AbstractParameterParser.hpp +++ b/src/DUNE/Tasks/AbstractParameterParser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/AbstractTask.hpp b/src/DUNE/Tasks/AbstractTask.hpp index 30b441f900..083b17951b 100644 --- a/src/DUNE/Tasks/AbstractTask.hpp +++ b/src/DUNE/Tasks/AbstractTask.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/BasicParameterParser.hpp b/src/DUNE/Tasks/BasicParameterParser.hpp index 6873d218e1..c6ddea60a4 100644 --- a/src/DUNE/Tasks/BasicParameterParser.hpp +++ b/src/DUNE/Tasks/BasicParameterParser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -97,15 +97,19 @@ namespace DUNE void minimumValue(const std::string& value) { - castLexical(value, m_min); - m_min_set = false; + if(!castLexical(value, m_min)) + throw std::runtime_error(DTR("minimum value is not of the correct type")); + + m_min_set = true; } void maximumValue(const std::string& value) { - castLexical(value, m_max); - m_max_set = false; + if(!castLexical(value, m_max)) + throw std::runtime_error(DTR("maximum value is not of the correct type")); + + m_max_set = true; } void diff --git a/src/DUNE/Tasks/Consumer.hpp b/src/DUNE/Tasks/Consumer.hpp index 3c82680ef5..3a8e0215a7 100644 --- a/src/DUNE/Tasks/Consumer.hpp +++ b/src/DUNE/Tasks/Consumer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Context.cpp b/src/DUNE/Tasks/Context.cpp index e3e2223c3c..e72c15b667 100644 --- a/src/DUNE/Tasks/Context.cpp +++ b/src/DUNE/Tasks/Context.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Context.hpp b/src/DUNE/Tasks/Context.hpp index 4554cf2901..7558ee0dcf 100644 --- a/src/DUNE/Tasks/Context.hpp +++ b/src/DUNE/Tasks/Context.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -56,8 +56,10 @@ namespace DUNE { Context(void); - //! Configuration directives. + //! Current configuration. Parsers::Config config; + //! Configuration loaded from disk. + Parsers::Config original_cfg; //! Message bus. IMC::Bus mbus; //! IMC address resolver. diff --git a/src/DUNE/Tasks/Creator.hpp b/src/DUNE/Tasks/Creator.hpp index d53ce8b99f..305c0ffa71 100644 --- a/src/DUNE/Tasks/Creator.hpp +++ b/src/DUNE/Tasks/Creator.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Exceptions.hpp b/src/DUNE/Tasks/Exceptions.hpp index d60836a67d..351670044f 100644 --- a/src/DUNE/Tasks/Exceptions.hpp +++ b/src/DUNE/Tasks/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Factory.cpp b/src/DUNE/Tasks/Factory.cpp index d4c9efc8d4..26cecf4677 100644 --- a/src/DUNE/Tasks/Factory.cpp +++ b/src/DUNE/Tasks/Factory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Factory.hpp b/src/DUNE/Tasks/Factory.hpp index 791fb8ac16..8760a27a93 100644 --- a/src/DUNE/Tasks/Factory.hpp +++ b/src/DUNE/Tasks/Factory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Manager.cpp b/src/DUNE/Tasks/Manager.cpp index 6d8561a4c0..5ab0e4e3d6 100644 --- a/src/DUNE/Tasks/Manager.cpp +++ b/src/DUNE/Tasks/Manager.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -72,7 +72,17 @@ namespace DUNE { // If this section is not a task continue. if (!Factory::exists(getTaskName(vec[i]))) + { + // We use '.' here to ignore configuration sections (such as General + // or Addresses) + if (getTaskName(vec[i]).find('.') != std::string::npos) + { + std::string invalid = "Invalid task name: " + getTaskName(vec[i]); + DUNE_WRN("Manager", DTR(invalid.c_str())); + } + continue; + } // Check if the task is enabled acording to the currently // selected profiles. diff --git a/src/DUNE/Tasks/Manager.hpp b/src/DUNE/Tasks/Manager.hpp index 8e0e1d5403..1089baaaed 100644 --- a/src/DUNE/Tasks/Manager.hpp +++ b/src/DUNE/Tasks/Manager.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/MessageFilter.cpp b/src/DUNE/Tasks/MessageFilter.cpp index 430cd6468b..cce761ac8e 100644 --- a/src/DUNE/Tasks/MessageFilter.cpp +++ b/src/DUNE/Tasks/MessageFilter.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/MessageFilter.hpp b/src/DUNE/Tasks/MessageFilter.hpp index 9ddbcd6ade..da5afb4bb8 100644 --- a/src/DUNE/Tasks/MessageFilter.hpp +++ b/src/DUNE/Tasks/MessageFilter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Parameter.cpp b/src/DUNE/Tasks/Parameter.cpp index 31433a787b..89d1eaeefd 100644 --- a/src/DUNE/Tasks/Parameter.cpp +++ b/src/DUNE/Tasks/Parameter.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -106,7 +106,8 @@ namespace DUNE m_reader(NULL), m_changed(true), m_visibility(VISIBILITY_DEVELOPER), - m_scope(SCOPE_GLOBAL) + m_scope(SCOPE_GLOBAL), + m_editable(true) { } Parameter::~Parameter(void) @@ -174,6 +175,8 @@ namespace DUNE os << "\n"; XML::writeTag("name-i18n", DTR(m_name.c_str()), os); diff --git a/src/DUNE/Tasks/Parameter.hpp b/src/DUNE/Tasks/Parameter.hpp index df0e77ac65..7ebc334a85 100644 --- a/src/DUNE/Tasks/Parameter.hpp +++ b/src/DUNE/Tasks/Parameter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -38,6 +38,7 @@ #include // DUNE headers. +#include #include #include #include @@ -248,6 +249,13 @@ namespace DUNE Parameter& scope(const std::string a_scope); + Parameter& + editable(std::string a_editable) + { + castLexical(a_editable, m_editable); + return *this; + } + void writeXML(std::ostream& os) const; @@ -310,6 +318,8 @@ namespace DUNE Visibility m_visibility; //! Parameter scope. Scope m_scope; + //! True if parameter can be editable by the operator on runtime. + bool m_editable; }; } } diff --git a/src/DUNE/Tasks/ParameterTable.cpp b/src/DUNE/Tasks/ParameterTable.cpp index cf615b4100..21c41f0fb5 100644 --- a/src/DUNE/Tasks/ParameterTable.cpp +++ b/src/DUNE/Tasks/ParameterTable.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/ParameterTable.hpp b/src/DUNE/Tasks/ParameterTable.hpp index 788c6f1c3d..69de4f96d4 100644 --- a/src/DUNE/Tasks/ParameterTable.hpp +++ b/src/DUNE/Tasks/ParameterTable.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/ParameterTypeName.hpp b/src/DUNE/Tasks/ParameterTypeName.hpp index 58e341efaa..47d5ee99d9 100644 --- a/src/DUNE/Tasks/ParameterTypeName.hpp +++ b/src/DUNE/Tasks/ParameterTypeName.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Periodic.cpp b/src/DUNE/Tasks/Periodic.cpp index 0feb5c6610..ef80dcb2c2 100644 --- a/src/DUNE/Tasks/Periodic.cpp +++ b/src/DUNE/Tasks/Periodic.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Periodic.hpp b/src/DUNE/Tasks/Periodic.hpp index 2810ce0022..aaa51a416b 100644 --- a/src/DUNE/Tasks/Periodic.hpp +++ b/src/DUNE/Tasks/Periodic.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Profiles.cpp b/src/DUNE/Tasks/Profiles.cpp index f9053d1f1b..0af8daff9b 100644 --- a/src/DUNE/Tasks/Profiles.cpp +++ b/src/DUNE/Tasks/Profiles.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Profiles.hpp b/src/DUNE/Tasks/Profiles.hpp index 6c00cecd33..425c25d91a 100644 --- a/src/DUNE/Tasks/Profiles.hpp +++ b/src/DUNE/Tasks/Profiles.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Recipient.cpp b/src/DUNE/Tasks/Recipient.cpp index 9f19e6b1af..233708ec97 100644 --- a/src/DUNE/Tasks/Recipient.cpp +++ b/src/DUNE/Tasks/Recipient.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Recipient.hpp b/src/DUNE/Tasks/Recipient.hpp index ff021a21b0..df8eb6ca4f 100644 --- a/src/DUNE/Tasks/Recipient.hpp +++ b/src/DUNE/Tasks/Recipient.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/SimpleTransport.cpp b/src/DUNE/Tasks/SimpleTransport.cpp index bb148735da..7f6555b791 100644 --- a/src/DUNE/Tasks/SimpleTransport.cpp +++ b/src/DUNE/Tasks/SimpleTransport.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -75,7 +75,15 @@ namespace DUNE uint8_t* p = m_buf.getBuffer(); - IMC::Packet::serialize(msg, p, n); + try + { + IMC::Packet::serialize(msg, p, n); + } + catch(const std::exception& e) + { + err(DTR("failed to serialize message %s: %s"), msg->getName(), e.what()); + return; + } if (m_gargs.trace_out) inf(DTR("outgoing: %s"), msg->getName()); diff --git a/src/DUNE/Tasks/SimpleTransport.hpp b/src/DUNE/Tasks/SimpleTransport.hpp index 4067f2e026..ae2f388579 100644 --- a/src/DUNE/Tasks/SimpleTransport.hpp +++ b/src/DUNE/Tasks/SimpleTransport.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/SourceFilter.cpp b/src/DUNE/Tasks/SourceFilter.cpp index 3ff152bdb1..69fd75cf31 100644 --- a/src/DUNE/Tasks/SourceFilter.cpp +++ b/src/DUNE/Tasks/SourceFilter.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/SourceFilter.hpp b/src/DUNE/Tasks/SourceFilter.hpp index a67b27b1b7..d1384ca489 100644 --- a/src/DUNE/Tasks/SourceFilter.hpp +++ b/src/DUNE/Tasks/SourceFilter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Tasks/Task.cpp b/src/DUNE/Tasks/Task.cpp index 1a22bebb3d..92208f15d4 100644 --- a/src/DUNE/Tasks/Task.cpp +++ b/src/DUNE/Tasks/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -43,6 +43,8 @@ #include #include #include +#include +#include #if defined(DUNE_OS_LINUX) # include @@ -109,6 +111,16 @@ namespace DUNE return e->getId(); } + Entities::BasicEntity* + Task::getLocalEntity(const std::string& label) + { + std::vector::iterator it = std::find(m_entities.begin(), m_entities.end(), label); + if (it == m_entities.end()) + return NULL; + else + return (*it); + } + void Task::reserveEntities(void) { @@ -243,6 +255,7 @@ namespace DUNE { if (paramChanged(m_args.active)) { + war("due to params active change, requesting %s", m_args.active ? "activation" : "deactivation"); if (m_args.active) requestActivation(); else @@ -262,9 +275,8 @@ namespace DUNE Task::requestActivation(void) { spew("request activation"); - m_entity->requestActivation(); - if (m_entity->isActivating()) + if (m_entity->requestActivation()) { spew("calling on request activation"); onRequestActivation(); @@ -287,14 +299,20 @@ namespace DUNE m_entity->succeedActivation(); if (m_entity->hasPendingDeactivation()) + { + spew("has pending deactivation"); requestDeactivation(); + } } void Task::activationFailed(const std::string& reason) { spew("activation failed: %s", reason.c_str()); - m_args.active = false; + + if (m_honours_active) + m_params.set("Active", "false"); + m_entity->failActivation(reason); } @@ -302,9 +320,8 @@ namespace DUNE Task::requestDeactivation(void) { spew("request deactivation"); - m_entity->requestDeactivation(); - if (m_entity->isDeactivating()) + if (m_entity->requestDeactivation()) { spew("calling on request deactivation"); onRequestDeactivation(); @@ -327,7 +344,10 @@ namespace DUNE m_entity->succeedDeactivation(); if (m_entity->hasPendingActivation()) + { + spew("has pending activation"); requestActivation(); + } } void @@ -471,6 +491,7 @@ namespace DUNE try { m_params.set((*itr)->name, (*itr)->value); + m_ctx.config.set(getName(), (*itr)->name, (*itr)->value); } catch (std::runtime_error& e) { @@ -693,11 +714,24 @@ namespace DUNE if (pitr->first == "Enabled") continue; + // Ignore Supervisors.Delegator sections + std::string section = getName(); + std::string::size_type p = section.find('/'); + if(!std::strcmp(section.substr(0,p).c_str(),"Supervisors.Delegator")) + continue; + if (m_params.find(pitr->first) == m_params.end()) err(DTR("invalid parameter '%s'"), pitr->first.c_str()); } - updateParameters(false); + try + { + updateParameters(false); + } + catch (RestartNeeded& e) + { + err(DTR("unable to load parameters: %s"), e.getError()); + } } } } diff --git a/src/DUNE/Tasks/Task.hpp b/src/DUNE/Tasks/Task.hpp index 6d2ac81f13..8a6e8818e3 100644 --- a/src/DUNE/Tasks/Task.hpp +++ b/src/DUNE/Tasks/Task.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -447,6 +447,13 @@ namespace DUNE return entity; } + //! Retrieve pointer to a previously stored entity object + //! object. + //! @param[in] label entity name/label. + //! @return pointer to entity object. + Entities::BasicEntity* + getLocalEntity(const std::string& label); + //! Test if task is stopping. //! @return true if task is stopping, false otherwise. bool @@ -601,6 +608,17 @@ namespace DUNE new Consumer(*task_obj, func)); } + //! Register a consumer for a given message identifier. + //! @param[in] message_id message identifier. + //! @param[in] consumer consumer object. + void + bind(unsigned int message_id, AbstractConsumer* consumer) + { + spew("registering consumer for '%s'", + IMC::Factory::getAbbrevFromId(message_id).c_str()); + m_recipient->bind(message_id, consumer); + } + //! Request task to start/resume normal execution. void requestActivation(void); @@ -802,17 +820,6 @@ namespace DUNE void run(void); - //! Register a consumer for a given message identifier. - //! @param[in] message_id message identifier. - //! @param[in] consumer consumer object. - void - bind(unsigned int message_id, AbstractConsumer* consumer) - { - spew("registering consumer for '%s'", - IMC::Factory::getAbbrevFromId(message_id).c_str()); - m_recipient->bind(message_id, consumer); - } - //! Consume QueryEntityState messages and reply accordingly. //! @param[in] msg QueryEntityState message. void diff --git a/src/DUNE/Time.hpp b/src/DUNE/Time.hpp index 74eab4399d..7866fd0858 100644 --- a/src/DUNE/Time.hpp +++ b/src/DUNE/Time.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Time/BrokenDown.hpp b/src/DUNE/Time/BrokenDown.hpp index 6fcfa86e9e..8fbd772c2e 100644 --- a/src/DUNE/Time/BrokenDown.hpp +++ b/src/DUNE/Time/BrokenDown.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Time/Clock.cpp b/src/DUNE/Time/Clock.cpp index c54f3d3c72..7d6d7f60a1 100644 --- a/src/DUNE/Time/Clock.cpp +++ b/src/DUNE/Time/Clock.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -55,8 +55,23 @@ namespace DUNE { namespace Time { + uint64_t Clock::s_starttime_epoch = getSinceEpochNsecRT(); + uint64_t Clock::s_starttime_mono = getNsecRT(); + double Clock::s_time_multiplier = 1.0; + uint64_t Clock::getNsec(void) + { + uint64_t time = getNsecRT(); + if (Clock::s_time_multiplier != 1.0) { + double ellapsed_time = (time - s_starttime_mono); + time = ellapsed_time * Clock::s_time_multiplier + s_starttime_mono; + } + return time; + } + + uint64_t + Clock::getNsecRT(void) { // POSIX RT. #if defined(DUNE_SYS_HAS_CLOCK_GETTIME) @@ -81,6 +96,52 @@ namespace DUNE uint64_t Clock::getSinceEpochNsec(void) + { + uint64_t time = getSinceEpochNsecRT(); + if (Clock::s_time_multiplier != 1.0) { + double ellapsed_time = (time - s_starttime_epoch); + time = ellapsed_time * Clock::s_time_multiplier + s_starttime_epoch; + } + return time; + } + + void + Clock::set(double value) + { + if (Clock::s_time_multiplier != 1.0) { + s_starttime_epoch = value * c_nsec_per_sec; + setTimeMultiplier(Clock::s_time_multiplier); + return; + } + +#if defined(DUNE_SYS_HAS_SETTIMEOFDAY) + timeval tv; + tv.tv_sec = static_cast(value); + tv.tv_usec = 0; + if (settimeofday(&tv, 0) != 0) + throw System::Error(errno, DTR("failed to set time")); +#else + (void)value; +#endif + } + + void + Clock::setTimeMultiplier(double mul) + { + Clock::s_time_multiplier = 1.0; + s_starttime_epoch = getSinceEpochNsecRT(); + s_starttime_mono = getNsecRT(); + Clock::s_time_multiplier = mul; + } + + double + Clock::getTimeMultiplier(void) + { + return Clock::s_time_multiplier; + } + + uint64_t + Clock::getSinceEpochNsecRT(void) { // POSIX RT. #if defined(DUNE_SYS_HAS_CLOCK_GETTIME) @@ -114,18 +175,14 @@ namespace DUNE #endif } - void - Clock::set(double value) + double + Clock::toSimTime(double timestamp) { -#if defined(DUNE_SYS_HAS_SETTIMEOFDAY) - timeval tv; - tv.tv_sec = static_cast(value); - tv.tv_usec = 0; - if (settimeofday(&tv, 0) != 0) - throw System::Error(errno, DTR("failed to set time")); -#else - (void)value; -#endif + double starttime = s_starttime_epoch / c_nsec_per_sec_fp; + if (timestamp < starttime) + return timestamp; + + return ((timestamp - starttime) * Time::Clock::s_time_multiplier) + starttime; } } } diff --git a/src/DUNE/Time/Clock.hpp b/src/DUNE/Time/Clock.hpp index 1c738c844f..77deaf212b 100644 --- a/src/DUNE/Time/Clock.hpp +++ b/src/DUNE/Time/Clock.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -41,18 +41,19 @@ namespace DUNE // Export DLL Symbol. class DUNE_DLL_SYM Clock; + //! %System clock routines. class Clock { public: - //! Get the amount of time (in nanoseconds) since an unspecified + //! Get the amount of non-realtime (in nanoseconds) since an unspecified //! point in the past. If the system permits, this point does //! not change after system start-up time. //! @return time in nanoseconds. static uint64_t getNsec(void); - //! Get the amount of time (in microseconds) since an unspecified + //! Get the amount of non-realtime (in microseconds) since an unspecified //! point in the past. If the system permits, this point does //! not change after system start-up time. //! @return time in microseconds. @@ -62,7 +63,7 @@ namespace DUNE return getNsec() / c_nsec_per_usec; } - //! Get the amount of time (in milliseconds) since an unspecified + //! Get the amount of non-realtime (in milliseconds) since an unspecified //! point in the past. If the system permits, this point does //! not change after system start-up time. //! @return time in milliseconds. @@ -72,7 +73,7 @@ namespace DUNE return getNsec() / c_nsec_per_msec; } - //! Get the amount of time (in seconds) since an unspecified + //! Get the amount of non-realtime (in seconds) since an unspecified //! point in the past. If the system permits, this point does //! not change after system start-up time. //! @return time in seconds. @@ -82,13 +83,13 @@ namespace DUNE return getNsec() / c_nsec_per_sec_fp; } - //! Get the amount of time (in nanoseconds) elapsed since the + //! Get the amount of non-realtime (in nanoseconds) elapsed since the //! UNIX Epoch (Midnight UTC of January 1, 1970). //! @return time in nanoseconds. static uint64_t getSinceEpochNsec(void); - //! Get the amount of time (in microseconds) elapsed since the + //! Get the amount of non-realtime (in microseconds) elapsed since the //! UNIX Epoch (Midnight UTC of January 1, 1970). //! @return time in microseconds. static uint64_t @@ -97,7 +98,7 @@ namespace DUNE return getSinceEpochNsec() / c_nsec_per_usec; } - //! Get the amount of time (in milliseconds) elapsed since the + //! Get the amount of non-realtime (in milliseconds) elapsed since the //! UNIX Epoch (Midnight UTC of January 1, 1970). //! @return time in milliseconds. static uint64_t @@ -106,7 +107,7 @@ namespace DUNE return getSinceEpochNsec() / c_nsec_per_msec; } - //! Get the amount of time (in seconds) elapsed since the + //! Get the amount of non-realtime (in seconds) elapsed since the //! UNIX Epoch (Midnight UTC of January 1, 1970). //! @return time in seconds. static double @@ -120,8 +121,74 @@ namespace DUNE //! @param value time in seconds. static void set(double value); + + //! Time multiplier for non-realtime simulations + //! @param mul multiplier (e.g. 4.0 for 4x speed) + static void + setTimeMultiplier(double mul); + + //! Return configured time multipler + //! @return simulation time multiplier (1.0 for real-time) + static double + getTimeMultiplier(); + + //! Return reference time used for epoch clock acceleration + //! @return s_starttime_epoch epoch time reference + static double + getStartTimeEpoch() + { + return s_starttime_epoch; + } + + //! Return reference time used for monotonic clock acceleration + //! @return s_starttime_epoch epoch time reference + static double + getStartTimeMono() + { + return s_starttime_mono; + } + + //! Get the amount of realtime (in nanoseconds) elapsed since the + //! UNIX Epoch (Midnight UTC of January 1, 1970). + //! @return time in nanoseconds. + static uint64_t + getSinceEpochNsecRT(void); + + //! Get the amount of realtime (in nanoseconds) since an unspecified + //! point in the past. If the system permits, this point does + //! not change after system start-up time. + //! @return time in nanoseconds. + static uint64_t + getNsecRT(void); + + //! Get the amount of realtime (in seconds) elapsed since the + //! UNIX Epoch (Midnight UTC of January 1, 1970). + //! @return time in seconds. + static double + getSinceEpochRT(void) + { + return getSinceEpochNsecRT() / c_nsec_per_sec_fp; + } + + //! Get the amount of realtime (in seconds) since an unspecified + //! point in the past. If the system permits, this point does + //! not change after system start-up time. + //! @return time in seconds. + static double + getRT(void) + { + return getNsecRT() / c_nsec_per_sec_fp; + } + + static double + toSimTime(double timestamp); + + private: + static uint64_t s_starttime_epoch; + static uint64_t s_starttime_mono; + static double s_time_multiplier; }; } } -#endif +#endif \ No newline at end of file diff --git a/src/DUNE/Time/Constants.hpp b/src/DUNE/Time/Constants.hpp index e8ea420fbb..fc345c52cc 100644 --- a/src/DUNE/Time/Constants.hpp +++ b/src/DUNE/Time/Constants.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -57,6 +57,7 @@ namespace DUNE static const unsigned c_nsec_per_msec = 1000000u; //! Number of nanoseconds in a second (floating point). static const double c_nsec_per_sec_fp = 1000000000.0; + //! Time multiplier to use in simulation } } diff --git a/src/DUNE/Time/Counter.hpp b/src/DUNE/Time/Counter.hpp index 31814ce9a5..50805e4d55 100644 --- a/src/DUNE/Time/Counter.hpp +++ b/src/DUNE/Time/Counter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Time/Delay.cpp b/src/DUNE/Time/Delay.cpp index 39e09abb90..5acb88f1e9 100644 --- a/src/DUNE/Time/Delay.cpp +++ b/src/DUNE/Time/Delay.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -31,6 +31,7 @@ #include #include #include +#include // Platform headers. #if defined(DUNE_SYS_HAS_TIME_H) @@ -48,6 +49,7 @@ namespace DUNE void Delay::waitNsec(uint64_t nsec) { + // Microsoft Windows. #if defined(DUNE_SYS_HAS_CREATE_WAITABLE_TIMER) HANDLE t = CreateWaitableTimer(0, TRUE, 0); diff --git a/src/DUNE/Time/Delay.hpp b/src/DUNE/Time/Delay.hpp index e4a4dbf57f..04cbfee0ac 100644 --- a/src/DUNE/Time/Delay.hpp +++ b/src/DUNE/Time/Delay.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -33,7 +33,7 @@ // DUNE headers. #include #include - +#include namespace DUNE { namespace Time @@ -78,6 +78,7 @@ namespace DUNE uint64_t secs = (uint64_t)s; uint64_t nsecs = secs * c_nsec_per_sec + (uint64_t)((s - secs) * c_nsec_per_sec_fp); + nsecs /= Time::Clock::getTimeMultiplier(); waitNsec(nsecs); } }; diff --git a/src/DUNE/Time/Delta.hpp b/src/DUNE/Time/Delta.hpp index 6d846200cc..2c7755e0e1 100644 --- a/src/DUNE/Time/Delta.hpp +++ b/src/DUNE/Time/Delta.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Time/Format.cpp b/src/DUNE/Time/Format.cpp index 100296c307..2ffe4b15be 100644 --- a/src/DUNE/Time/Format.cpp +++ b/src/DUNE/Time/Format.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Time/Format.hpp b/src/DUNE/Time/Format.hpp index 1738a79b26..e83d4d1aa5 100644 --- a/src/DUNE/Time/Format.hpp +++ b/src/DUNE/Time/Format.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Time/PeriodicDelay.hpp b/src/DUNE/Time/PeriodicDelay.hpp index d33410f8dd..4d8b45aba1 100644 --- a/src/DUNE/Time/PeriodicDelay.hpp +++ b/src/DUNE/Time/PeriodicDelay.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -40,6 +40,7 @@ // DUNE headers. #include +#include namespace DUNE { @@ -58,6 +59,9 @@ namespace DUNE void set(uint32_t delay_usec) { + + delay_usec = (uint32_t) (delay_usec / Clock::getTimeMultiplier()); + // Microsoft Windows. #if defined(DUNE_SYS_HAS_GET_SYSTEM_TIME_AS_FILE_TIME) m_delay = delay_usec * 10; diff --git a/src/DUNE/Time/Utils.hpp b/src/DUNE/Time/Utils.hpp index b31855b5c4..53ac99cfae 100644 --- a/src/DUNE/Time/Utils.hpp +++ b/src/DUNE/Time/Utils.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -43,8 +43,13 @@ #endif #if defined(DUNE_SYS_HAS_STRUCT_TIMEVAL) +#ifdef DUNE_OS_WINDOWS # define DUNE_TIMEVAL_INIT_SEC_FP(sec) \ {(long)sec, (long)((sec - (long)sec) * DUNE::Time::c_usec_per_sec)} +#else +# define DUNE_TIMEVAL_INIT_SEC_FP(sec) \ + {(time_t) sec, (suseconds_t)((sec - (long)sec) * DUNE::Time::c_usec_per_sec)} +#endif #endif #if defined(DUNE_SYS_HAS_STRUCT_TIMESPEC) diff --git a/src/DUNE/Units.cpp b/src/DUNE/Units.cpp index 2bb3defe3c..19b5a9ac35 100644 --- a/src/DUNE/Units.cpp +++ b/src/DUNE/Units.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Units.def b/src/DUNE/Units.def index ec6fe859dd..fc91b70d07 100644 --- a/src/DUNE/Units.def +++ b/src/DUNE/Units.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Units.hpp b/src/DUNE/Units.hpp index d6c8147f6b..09c49107ae 100644 --- a/src/DUNE/Units.hpp +++ b/src/DUNE/Units.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils.hpp b/src/DUNE/Utils.hpp index 29ddf045c8..b992942a77 100644 --- a/src/DUNE/Utils.hpp +++ b/src/DUNE/Utils.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/BitBuffer.hpp b/src/DUNE/Utils/BitBuffer.hpp index fdea1c178a..2d3e5d6ef3 100644 --- a/src/DUNE/Utils/BitBuffer.hpp +++ b/src/DUNE/Utils/BitBuffer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/ByteBuffer.hpp b/src/DUNE/Utils/ByteBuffer.hpp index 609285d45a..30f7f469b8 100644 --- a/src/DUNE/Utils/ByteBuffer.hpp +++ b/src/DUNE/Utils/ByteBuffer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/ByteCopy.hpp b/src/DUNE/Utils/ByteCopy.hpp index 15deefa3d3..deaf5f100c 100644 --- a/src/DUNE/Utils/ByteCopy.hpp +++ b/src/DUNE/Utils/ByteCopy.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -359,6 +359,18 @@ namespace DUNE return copy4b(reinterpret_cast(&dest), src); } + static inline uint16_t + copy(int64_t& dest, const uint8_t* src) + { + return copy8b(reinterpret_cast(&dest), src); + } + + static inline uint16_t + copy(uint64_t& dest, const uint8_t* src) + { + return copy8b(reinterpret_cast(&dest), src); + } + static inline uint16_t copy(fp32_t& dest, const uint8_t* src) { @@ -407,6 +419,18 @@ namespace DUNE return rcopy4b(reinterpret_cast(&dest), src); } + static inline uint16_t + rcopy(int64_t& dest, const uint8_t* src) + { + return rcopy8b(reinterpret_cast(&dest), src); + } + + static inline uint16_t + rcopy(uint64_t& dest, const uint8_t* src) + { + return rcopy8b(reinterpret_cast(&dest), src); + } + static inline uint16_t rcopy(fp32_t& dest, const uint8_t* src) { @@ -467,6 +491,26 @@ namespace DUNE return toLE(static_cast(value), dst); } + static inline unsigned + toLE(const float value, uint8_t* dst) + { +#if defined(DUNE_CPU_BIG_ENDIAN) + return rcopy4b(dst, (uint8_t*)&value); +#else + return copy4b(dst, (uint8_t*)&value); +#endif + } + + static inline unsigned + toLE(const double value, uint8_t* dst) + { +#if defined(DUNE_CPU_BIG_ENDIAN) + return rcopy8b(dst, (uint8_t*)&value); +#else + return copy8b(dst, (uint8_t*)&value); +#endif + } + static inline unsigned toBE(const uint8_t value, uint8_t* dst) { diff --git a/src/DUNE/Utils/CircularBuffer.hpp b/src/DUNE/Utils/CircularBuffer.hpp index ba428abff8..3b8d1239f4 100644 --- a/src/DUNE/Utils/CircularBuffer.hpp +++ b/src/DUNE/Utils/CircularBuffer.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/Codecs.hpp b/src/DUNE/Utils/Codecs.hpp index 8f5f9a5463..ced437a799 100644 --- a/src/DUNE/Utils/Codecs.hpp +++ b/src/DUNE/Utils/Codecs.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/Codecs/CodedEstimatedState.hpp b/src/DUNE/Utils/Codecs/CodedEstimatedState.hpp index a433732de8..8ce20f3089 100644 --- a/src/DUNE/Utils/Codecs/CodedEstimatedState.hpp +++ b/src/DUNE/Utils/Codecs/CodedEstimatedState.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/Codecs/CodedReference.hpp b/src/DUNE/Utils/Codecs/CodedReference.hpp index a625d39e86..62ed529d6d 100644 --- a/src/DUNE/Utils/Codecs/CodedReference.hpp +++ b/src/DUNE/Utils/Codecs/CodedReference.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/Exceptions.hpp b/src/DUNE/Utils/Exceptions.hpp index dbfd71c877..9056d42fef 100644 --- a/src/DUNE/Utils/Exceptions.hpp +++ b/src/DUNE/Utils/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/OptionParser.cpp b/src/DUNE/Utils/OptionParser.cpp index 057ce2bf13..6edb815f6d 100644 --- a/src/DUNE/Utils/OptionParser.cpp +++ b/src/DUNE/Utils/OptionParser.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/OptionParser.hpp b/src/DUNE/Utils/OptionParser.hpp index 182133c84a..70f9cfbd71 100644 --- a/src/DUNE/Utils/OptionParser.hpp +++ b/src/DUNE/Utils/OptionParser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/RawFifo.cpp b/src/DUNE/Utils/RawFifo.cpp index 821efb82b0..d8b2f8e208 100644 --- a/src/DUNE/Utils/RawFifo.cpp +++ b/src/DUNE/Utils/RawFifo.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/RawFifo.hpp b/src/DUNE/Utils/RawFifo.hpp index a3dc613b3d..847651a66c 100644 --- a/src/DUNE/Utils/RawFifo.hpp +++ b/src/DUNE/Utils/RawFifo.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/StateMachine.hpp b/src/DUNE/Utils/StateMachine.hpp index 2460e8c5e0..87b00f2a87 100644 --- a/src/DUNE/Utils/StateMachine.hpp +++ b/src/DUNE/Utils/StateMachine.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/String.cpp b/src/DUNE/Utils/String.cpp index e0fca8b34b..49d7c73efc 100644 --- a/src/DUNE/Utils/String.cpp +++ b/src/DUNE/Utils/String.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -80,7 +80,7 @@ namespace DUNE } void - String::rtrim(char* str) + String::rightTrimInPlace(char* str) { char* r = str + std::strlen(str) - 1; // Rightmost character @@ -88,6 +88,20 @@ namespace DUNE *r = 0; } + void + String::resize(char* str, int size) + { + int i; + + if (size < 0) + size = std::strlen(str) + size; + if (size < 0 || (int)std::strlen(str) <= size) + return; + + for (i = std::strlen(str) - 1; i >= size; i--) + *(str + i) = 0; + } + std::string String::rtrim(const std::string& s) { @@ -165,6 +179,20 @@ namespace DUNE return rv; } + std::string + String::replaceAll(const std::string& inStr, const std::string& searchStr, const std::string& replaceStr) + { + std::string result = inStr; + size_t pos = result.find(searchStr); + while (pos != std::string::npos) + { + result.replace(pos, searchStr.size(), replaceStr); + pos = result.find(searchStr, pos + searchStr.size()); + } + + return result; + } + void String::toLowerCase(std::string& str) { @@ -220,6 +248,21 @@ namespace DUNE return ss.str(); } + std::vector + String::hexToBytes(const std::string& hex) + { + std::vector bytes; + + for (unsigned int i = 0; i < hex.length(); i += 2) + { + std::string byteString = hex.substr(i, 2); + uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16); + bytes.push_back(byte); + } + + return bytes; + } + std::string String::fromHex(const std::string& str) { diff --git a/src/DUNE/Utils/String.hpp b/src/DUNE/Utils/String.hpp index 2e28701e21..78ef3ed06e 100644 --- a/src/DUNE/Utils/String.hpp +++ b/src/DUNE/Utils/String.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -31,12 +31,12 @@ #define DUNE_UTILS_STRING_HPP_INCLUDED_ // ISO C++ 98 headers. +#include +#include +#include +#include #include #include -#include -#include -#include -#include // DUNE headers. #include @@ -84,17 +84,24 @@ namespace DUNE static std::string ltrim(const std::string& str); + //! Strip whitespace from the end of a string in place. + //! @param[in,out] str string. + static void + rightTrimInPlace(char* str); + //! Strip whitespace from the end of a string. //! @param str object string. //! @return string without trailing whitespaces. static std::string rtrim(const std::string& str); - //! Strip whitespace from the end of a string, modifying the - //! original string. - //! @param str object string. + //! Resize string by replacing any extra characters with '\0'. + //! If size is greater than current size, the string is untouched. + //! If size is lower than 0, the resulting size is [strlen(str) + size]. + //! @param str object string + //! @param size new size static void - rtrim(char* str); + resize(char* str, int size); //! Strip whitespace from the beginning and end of a string. //! @param str object string. @@ -175,6 +182,9 @@ namespace DUNE static std::string toHex(int nr); + static std::vector + hexToBytes(const std::string& hex); + static std::string fromHex(const std::string& str); @@ -194,39 +204,43 @@ namespace DUNE } static std::string - str(const char* format, ...) + str(const char* fmt, ...) { - char bfr[1024] = {0}; std::va_list ap; - va_start(ap, format); - -#if defined(DUNE_SYS_HAS_VSNPRINTF) - vsnprintf(bfr, sizeof(bfr), format, ap); -#elif defined(DUNE_SYS_HAS_VSNPRINTF_S) - vsnprintf_s(bfr, sizeof(bfr), sizeof(bfr) - 1, format, ap); -#else - std::vsprintf(bfr, format, ap); -#endif + va_start(ap, fmt); + std::string result = strVl(fmt, ap); va_end(ap); + return result; + } + static std::string + strVl(const char* fmt, std::va_list ap) + { + char bfr[1024] = {0}; + formatVl(bfr, sizeof(bfr), fmt, ap); return bfr; } static int - format(char* str, size_t size, const char* format, ...) + format(char* str, size_t size, const char* fmt, ...) { std::va_list ap; - va_start(ap, format); + va_start(ap, fmt); + int rv = formatVl(str, size, fmt, ap); + va_end(ap); + return rv; + } + static int + formatVl(char* str, size_t size, const char* fmt, std::va_list ap) + { #if defined(DUNE_SYS_HAS_VSNPRINTF) - int rv = vsnprintf(str, size, format, ap); + int rv = vsnprintf(str, size, fmt, ap); #elif defined(DUNE_SYS_HAS_VSNPRINTF_S) - int rv = vsnprintf_s(str, size, size - 1, format, ap); + int rv = vsnprintf_s(str, size, size - 1, fmt, ap); #else - int rv = std::vsprintf(str, format, ap); + int rv = std::vsprintf(str, fmt, ap); #endif - - va_end(ap); return rv; } @@ -236,6 +250,14 @@ namespace DUNE static std::string replace(const std::string& str, char rep, const std::string& pat); + //! Replace all occurrences of a substring in a string + //! @param[in] inStr string. + //! @param[in] searchStr substring to search for. + //! @param[in] replaceStr substring replacement. + //! @return resulting string with all substring occurrences replaced. + static std::string + replaceAll(const std::string& inStr, const std::string& searchStr, const std::string& replaceStr); + static std::string escape(const std::string& input); diff --git a/src/DUNE/Utils/TupleList.cpp b/src/DUNE/Utils/TupleList.cpp index 96d7b5a400..39d915b0b2 100644 --- a/src/DUNE/Utils/TupleList.cpp +++ b/src/DUNE/Utils/TupleList.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/TupleList.hpp b/src/DUNE/Utils/TupleList.hpp index ebe19b6b55..5aeb25c92e 100644 --- a/src/DUNE/Utils/TupleList.hpp +++ b/src/DUNE/Utils/TupleList.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/Utils.hpp b/src/DUNE/Utils/Utils.hpp index 961ae98b08..14eb962598 100644 --- a/src/DUNE/Utils/Utils.hpp +++ b/src/DUNE/Utils/Utils.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/XML.cpp b/src/DUNE/Utils/XML.cpp index aa6baa565b..312ce4eea1 100644 --- a/src/DUNE/Utils/XML.cpp +++ b/src/DUNE/Utils/XML.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Utils/XML.hpp b/src/DUNE/Utils/XML.hpp index c2f81bb707..0f0984b7d2 100644 --- a/src/DUNE/Utils/XML.hpp +++ b/src/DUNE/Utils/XML.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Version.cpp.in b/src/DUNE/Version.cpp.in index 7e229d3ebd..c5d83a8daf 100644 --- a/src/DUNE/Version.cpp.in +++ b/src/DUNE/Version.cpp.in @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Version.hpp b/src/DUNE/Version.hpp index 70edae03bd..4d5a089947 100644 --- a/src/DUNE/Version.hpp +++ b/src/DUNE/Version.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/DUNE/Version.rc.in b/src/DUNE/Version.rc.in index 3884b270fb..27074e7cf8 100644 --- a/src/DUNE/Version.rc.in +++ b/src/DUNE/Version.rc.in @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Main/Daemon.cpp b/src/Main/Daemon.cpp index 73ff8d9c89..fd26b14019 100644 --- a/src/Main/Daemon.cpp +++ b/src/Main/Daemon.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -63,6 +63,10 @@ # include #endif +#if defined(DUNE_SYS_HAS_SYS_REBOOT_H) +# include +#endif + void registerStaticTasks(void); @@ -141,12 +145,25 @@ setDaemonSignalHandlers(void) #endif } +int +callReboot() +{ +#if defined(DUNE_OS_POSIX) + sync(); + return reboot(RB_AUTOBOOT); +#else + DUNE_WRN("Daemon", "Reboot not supported"); + return -1; +#endif +} + int runDaemon(DUNE::Daemon& daemon) { setDaemonSignalHandlers(); bool call_abort = false; + bool call_reboot = false; try { @@ -164,6 +181,7 @@ runDaemon(DUNE::Daemon& daemon) } DUNE_WRN("Daemon", DTR("stopping tasks")); + call_reboot = daemon.callReboot(); daemon.stopAndJoin(); } catch (std::exception& e) @@ -177,6 +195,15 @@ runDaemon(DUNE::Daemon& daemon) return 1; } + if(call_reboot) + { + DUNE_WRN("Daemon", "Rebooting"); + + int rt = callReboot(); + if (rt != -1) + return rt; + } + if (call_abort) std::abort(); @@ -260,6 +287,7 @@ main(int argc, char** argv) try { context.config.parseFile(cfg_file.c_str()); + context.original_cfg.parseFile(cfg_file.c_str()); } catch (std::runtime_error& e) { @@ -267,6 +295,7 @@ main(int argc, char** argv) { cfg_file = context.dir_usr_cfg / options.value("--config-file") + ".ini"; context.config.parseFile(cfg_file.c_str()); + context.original_cfg.parseFile(cfg_file.c_str()); context.dir_cfg = context.dir_usr_cfg; } catch (std::runtime_error& e2) diff --git a/src/Main/Launcher.cpp b/src/Main/Launcher.cpp index bef9728ab6..fe601a7f10 100644 --- a/src/Main/Launcher.cpp +++ b/src/Main/Launcher.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Main/Memory.hpp b/src/Main/Memory.hpp index 1eba792285..ecbc54f0e2 100644 --- a/src/Main/Memory.hpp +++ b/src/Main/Memory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Main/StaticTasks.cpp.cmake b/src/Main/StaticTasks.cpp.cmake index 38cdabeff8..92e5e4958a 100644 --- a/src/Main/StaticTasks.cpp.cmake +++ b/src/Main/StaticTasks.cpp.cmake @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/CommsRelay/Task.cpp b/src/Maneuver/CommsRelay/Task.cpp index 389d758b4f..0612d76f7c 100644 --- a/src/Maneuver/CommsRelay/Task.cpp +++ b/src/Maneuver/CommsRelay/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -45,8 +45,8 @@ namespace Maneuver struct Arguments { float loitering_radius; - float depth; - float altitude; + float z; + std::string z_mode; }; struct Task: public DUNE::Maneuvers::Maneuver @@ -86,15 +86,14 @@ namespace Maneuver .units(Units::Meter) .description("Radius of loitering circle after arriving at destination"); - param("Depth", m_args.depth) - .defaultValue("-1") + param("Z Value", m_args.z) + .defaultValue("") .units(Units::Meter) - .description("Default depth. If value is below 0, altitude will be used instead."); + .description("Z value to maintain while executing this maneuver."); - param("Altitude", m_args.altitude) - .defaultValue("100") - .units(Units::Meter) - .description("Altitude to use if depth less than 0."); + param("Z Mode", m_args.z_mode) + .defaultValue("") + .description("Z Mode to use. One of Depth, Altitude or Height."); // initialize everything... m_mode = STOP; @@ -115,11 +114,12 @@ namespace Maneuver void onUpdateParameters(void) { - // depending on z reference, activate altitude or depth control - if (m_args.depth >= 0) + if (m_args.z_mode == "Depth") m_control = IMC::CL_DEPTH | IMC::CL_SPEED | IMC::CL_PATH; - else + else if (m_args.z_mode == "Altitude") m_control = IMC::CL_ALTITUDE | IMC::CL_SPEED | IMC::CL_PATH; + else + m_control = IMC::CL_SPEED | IMC::CL_PATH; } void @@ -280,17 +280,14 @@ namespace Maneuver m_path.speed_units = m_maneuver.speed_units; m_path.end_lat = m_lat_center; m_path.end_lon = m_lon_center; - - if (m_args.depth >= 0) - { - m_path.end_z = m_args.depth; + m_path.end_z = m_args.z; + + if (m_args.z_mode == "Depth") m_path.end_z_units = IMC::Z_DEPTH; - } - else - { - m_path.end_z = m_args.altitude; + else if (m_args.z_mode == "Altitude") m_path.end_z_units = IMC::Z_ALTITUDE; - } + else if (m_args.z_mode == "Height") + m_path.end_z_units = IMC::Z_HEIGHT; } }; } diff --git a/src/Maneuver/CompassCalibration/Task.cpp b/src/Maneuver/CompassCalibration/Task.cpp index b7a5d1bce4..3d2ddf0ec8 100644 --- a/src/Maneuver/CompassCalibration/Task.cpp +++ b/src/Maneuver/CompassCalibration/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/CoverArea/Task.cpp b/src/Maneuver/CoverArea/Task.cpp index 2249d4e458..86552cebb9 100644 --- a/src/Maneuver/CoverArea/Task.cpp +++ b/src/Maneuver/CoverArea/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/FlyByCamera/Task.cpp b/src/Maneuver/FlyByCamera/Task.cpp index 41574e2992..8ad9dca3d5 100644 --- a/src/Maneuver/FlyByCamera/Task.cpp +++ b/src/Maneuver/FlyByCamera/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/FollowReference/AUV/Task.cpp b/src/Maneuver/FollowReference/AUV/Task.cpp index c901628eb8..b18f76ac70 100644 --- a/src/Maneuver/FollowReference/AUV/Task.cpp +++ b/src/Maneuver/FollowReference/AUV/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -65,10 +65,17 @@ namespace Maneuver IMC::FollowRefState m_fref_state; //! Did we get a reference already? bool m_got_reference; + //! Did we get a reference start loc already? + bool m_got_reference_start; + double m_start_lat; + double m_start_lon; + double m_start_z; //! Are we moving or idle (floating) bool m_moving; //! Store last timestamp when reference was received double m_last_ref_time; + //! sent path ref + int m_path_ref; //! Task arguments. Arguments m_args; @@ -120,9 +127,13 @@ namespace Maneuver .description("Units to use for default z reference (one of 'DEPTH', 'ALTITUDE' or 'HEIGHT')"); m_got_reference = false; + m_got_reference_start = false; + m_start_lat = 0; + m_start_lon = 0; m_moving = false; m_last_ref_time = 0; m_path_sent = false; + m_path_ref = 0; bindToManeuver(); bind(this); @@ -134,6 +145,9 @@ namespace Maneuver { m_moving = false; m_got_reference = false; + m_got_reference_start = false; + m_start_lat = 0; + m_start_lon = 0; m_spec = *msg; m_last_ref_time = Clock::get(); @@ -240,9 +254,11 @@ namespace Maneuver m_last_ref_time = Clock::get(); m_last_ref = m_cur_ref; - m_cur_ref = *msg; + if (msg->flags & IMC::Reference::FLAG_LOCATION) { + m_cur_ref = *msg; + } - if (m_cur_ref.flags & IMC::Reference::FLAG_MANDONE) + if (msg->flags & IMC::Reference::FLAG_MANDONE) { m_fref_state.proximity = IMC::FollowRefState::PROX_FAR; m_fref_state.state = IMC::FollowRefState::FR_WAIT; @@ -251,7 +267,8 @@ namespace Maneuver return; } - guide(&m_pcs, &m_cur_ref, &m_estate); + IMC::Reference ref = *msg; + guide(&m_pcs, &ref, &m_estate); } void @@ -312,18 +329,15 @@ namespace Maneuver IMC::DesiredPath desired_path; double curlat = state->lat; double curlon = state->lon; - bool near_ref = - (pcs == NULL) ? false : + bool near_ref = (pcs == NULL) || pcs->path_ref != m_last_desired_path.path_ref ? false : (pcs->flags & IMC::PathControlState::FL_NEAR) != 0; WGS84::displace(state->x, state->y, &curlat, &curlon); // command start corresponds to current position - desired_path.start_lat = curlat; - desired_path.start_lon = curlon; - desired_path.flags = IMC::DesiredPath::FL_DIRECT; // set attributes in desired path according to flags + updateStartLoc(ref, desired_path, curlat, curlon); updateEndLoc(ref, desired_path, curlat, curlon); updateSpeed(ref, desired_path); @@ -338,10 +352,34 @@ namespace Maneuver bool target_at_surface = desired_path.end_z == 0 && desired_path.end_z_units == Z_DEPTH; - bool still_same_reference = sameReference(ref, &m_last_ref); + bool still_same_reference = (ref->flags & IMC::Reference::FLAG_START_POINT) || + sameReference(ref, &m_last_ref); updateRadius(ref, desired_path); int prev_mode = m_fref_state.state; + std::string mode; + + switch (prev_mode) + { + case IMC::FollowRefState::FR_GOTO: + mode = "GOTO"; + break; + case IMC::FollowRefState::FR_HOVER: + mode = "Hover"; + break; + case IMC::FollowRefState::FR_LOITER: + mode = "Loiter"; + break; + case IMC::FollowRefState::FR_ELEVATOR: + mode = "Elevator"; + break; + default: + mode = "Elevator"; + break; + } + + debug("Mode: %s, Z_DIST: %f/%d, XY_DIST: %f/%d, TARGET_AT_SURF: %d, SAME_REF: %d", + mode.c_str(), z_dist, at_z_target, xy_dist, at_xy_target, target_at_surface, still_same_reference); if (still_same_reference && prev_mode != IMC::FollowRefState::FR_WAIT) { @@ -412,7 +450,10 @@ namespace Maneuver return; } - dispatchDesiredPath(desired_path); + if (!ref->speed.isNull() && ref->speed.get()->value == 0) + enableMovement(false); + else + updateDesiredPath(desired_path); } //! Function for enabling and disabling the control loops @@ -430,7 +471,7 @@ namespace Maneuver if (!was_moving) { m_path_sent = false; - dispatchDesiredPath(m_last_desired_path); + updateDesiredPath(m_last_desired_path); } } else @@ -442,6 +483,54 @@ namespace Maneuver } private: + void + updateStartLoc(const IMC::Reference* ref, IMC::DesiredPath &desired_path, + double curlat, double curlon) + { + // set end location according to received reference + if (ref->flags & IMC::Reference::FLAG_DIRECT) + { + spew("Using direct path following"); + m_got_reference_start = false; + m_start_lat = 0; + m_start_lon = 0; + m_start_z = 0; + // just stay where we are + desired_path.start_lat = curlat; + desired_path.start_lon = curlon; + desired_path.start_z = 0; + desired_path.start_z_units = ZUnits::Z_NONE; + desired_path.flags = IMC::DesiredPath::FL_DIRECT; + } + else if (ref->flags & IMC::Reference::FLAG_START_POINT) + { + spew("Using sent start point path following"); + m_got_reference_start = true; + m_start_lat = ref->lat; + m_start_lon = ref->lon; + desired_path.start_lat = m_start_lat; + desired_path.start_lon = m_start_lon; + desired_path.start_z = m_start_z; + desired_path.start_z_units = m_start_z >= 0 ? ZUnits::Z_DEPTH : ZUnits::Z_NONE; + desired_path.flags = IMC::DesiredPath::FL_START; + } + else if (m_got_reference_start && m_start_lat != 0 && m_start_lon != 0) + { + spew("Keeping last sent start point path following"); + // use previously received reference + desired_path.start_lat = m_start_lat; + desired_path.start_lon = m_start_lon; + desired_path.start_z = m_start_z; + desired_path.start_z_units = m_start_z >= 0 ? ZUnits::Z_DEPTH : ZUnits::Z_NONE; + desired_path.flags = IMC::DesiredPath::FL_START; + } + else + { + spew("Failing back to using direct path following"); + desired_path.flags = IMC::DesiredPath::FL_DIRECT; + } + } + void updateEndLoc(const IMC::Reference* ref, IMC::DesiredPath &desired_path, double curlat, double curlon) @@ -453,7 +542,7 @@ namespace Maneuver desired_path.end_lat = ref->lat; desired_path.end_lon = ref->lon; } - else if (m_got_reference) + else if (m_got_reference && (m_cur_ref.flags & IMC::Reference::FLAG_LOCATION)) { // use previously received reference desired_path.end_lat = m_cur_ref.lat; @@ -559,10 +648,18 @@ namespace Maneuver void dispatchDesiredPath(IMC::DesiredPath desired_path) + { + desired_path.path_ref = ++m_path_ref; + dispatch(desired_path); + m_last_desired_path = desired_path; + } + + void + updateDesiredPath(IMC::DesiredPath desired_path) { int diff = pathDifferences(&m_last_desired_path, &desired_path); - desired_path.flags &= 0xFF ^ DesiredPath::FL_NO_Z; + desired_path.flags &= ~DesiredPath::FL_NO_Z; m_last_desired_path = desired_path; @@ -571,9 +668,6 @@ namespace Maneuver bool changedSpeed = (diff & SPEED_CHANGED) != 0; bool changedRadius = (diff & RADIUS_CHANGED) != 0; - //std::cerr << "difference: " << changedZ << " " << changedSpeed << " " - // << changedLoc << " " << changedRadius << "\n"; - if (changedZ || !m_path_sent) { IMC::DesiredZ desZ; @@ -597,7 +691,7 @@ namespace Maneuver inf(DTR("Loiter radius reference changed to %f"), desired_path.lradius); } - bool send_desired_path = changedRadius || changedLoc || !m_path_sent; + bool send_desired_path = changedSpeed || changedRadius || changedLoc || !m_path_sent; // dispatch new desired path switch (m_fref_state.state) @@ -607,7 +701,7 @@ namespace Maneuver enableMovement(true); if (send_desired_path) { - dispatch(desired_path); + dispatchDesiredPath(desired_path); inf(DTR("loitering around (%f, %f, %f, %f)."), Angles::degrees(desired_path.end_lat), Angles::degrees(desired_path.end_lon), desired_path.end_z, desired_path.lradius); @@ -618,7 +712,7 @@ namespace Maneuver enableMovement(true); if (send_desired_path) { - dispatch(desired_path); + dispatchDesiredPath(desired_path); inf(DTR("loitering (elevator) towards (%f, %f, %f, %f)."), Angles::degrees(desired_path.end_lat), Angles::degrees(desired_path.end_lon), desired_path.end_z, desired_path.lradius); @@ -629,14 +723,19 @@ namespace Maneuver enableMovement(true); if (send_desired_path) { - dispatch(desired_path); + dispatchDesiredPath(desired_path); inf(DTR("going towards (%f, %f, %f)."), Angles::degrees(desired_path.end_lat), Angles::degrees(desired_path.end_lon), desired_path.end_z); } break; default: - inf(DTR("hovering next to (%f, %f)."), Angles::degrees(desired_path.end_lat), - Angles::degrees(desired_path.end_lon)); + if (send_desired_path) + { + dispatchDesiredPath(desired_path); + enableMovement(true); + inf(DTR("hovering next to (%f, %f)."), Angles::degrees(desired_path.end_lat), + Angles::degrees(desired_path.end_lon)); + } enableMovement(false); break; } diff --git a/src/Maneuver/FollowReference/UAV/Task.cpp b/src/Maneuver/FollowReference/UAV/Task.cpp index 698592571e..93102ca3ec 100644 --- a/src/Maneuver/FollowReference/UAV/Task.cpp +++ b/src/Maneuver/FollowReference/UAV/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -362,7 +362,8 @@ namespace Maneuver // command start corresponds to reference position m_desired_path.start_lat = m_cur_ref.lat; m_desired_path.start_lon = m_cur_ref.lon; - m_desired_path.start_lon = m_cur_ref.lon; + m_desired_path.start_z = m_cur_ref.z->value; + m_desired_path.start_z_units = m_cur_ref.z->z_units; m_desired_path.flags &= ~IMC::DesiredPath::FL_DIRECT; } else if (m_cur_ref.flags & IMC::Reference::FLAG_DIRECT) diff --git a/src/Maneuver/FollowSystem/Task.cpp b/src/Maneuver/FollowSystem/Task.cpp index e361222f91..49074bcbc5 100644 --- a/src/Maneuver/FollowSystem/Task.cpp +++ b/src/Maneuver/FollowSystem/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/FollowTarget/Task.cpp b/src/Maneuver/FollowTarget/Task.cpp index 1057592828..990e409caa 100644 --- a/src/Maneuver/FollowTarget/Task.cpp +++ b/src/Maneuver/FollowTarget/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/FollowTrajectory/Task.cpp b/src/Maneuver/FollowTrajectory/Task.cpp index 7ab6eb15c2..c0f9d93a19 100644 --- a/src/Maneuver/FollowTrajectory/Task.cpp +++ b/src/Maneuver/FollowTrajectory/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/AbstractMux.hpp b/src/Maneuver/Multiplexer/AbstractMux.hpp index 8c10c386e3..d4a8c3d808 100644 --- a/src/Maneuver/Multiplexer/AbstractMux.hpp +++ b/src/Maneuver/Multiplexer/AbstractMux.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -90,6 +90,13 @@ namespace Maneuver (void)msg; } + //! On Rpm message + virtual void + onThrottle(const IMC::Throttle* msg) + { + (void)msg; + } + //! On GpsFix message virtual void onGpsFix(const IMC::GpsFix* msg) @@ -97,6 +104,13 @@ namespace Maneuver (void)msg; } + //! On ManeuverDone message + virtual void + onManeuverDone(const IMC::ManeuverDone* msg) + { + (void)msg; + } + protected: //! Pointer to task Maneuvers::Maneuver* m_task; diff --git a/src/Maneuver/Multiplexer/Constants.hpp b/src/Maneuver/Multiplexer/Constants.hpp index 90ab213515..530befa2a7 100644 --- a/src/Maneuver/Multiplexer/Constants.hpp +++ b/src/Maneuver/Multiplexer/Constants.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Dislodge.hpp b/src/Maneuver/Multiplexer/Dislodge.hpp index 538afd0198..5f059051ab 100644 --- a/src/Maneuver/Multiplexer/Dislodge.hpp +++ b/src/Maneuver/Multiplexer/Dislodge.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Drop.hpp b/src/Maneuver/Multiplexer/Drop.hpp new file mode 100644 index 0000000000..b5dc87c9b5 --- /dev/null +++ b/src/Maneuver/Multiplexer/Drop.hpp @@ -0,0 +1,107 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Manuel Ribeiro * +//*************************************************************************** + +#ifndef MANEUVER_MULTIPLEXER_DROP_HPP_INCLUDED_ +#define MANEUVER_MULTIPLEXER_DROP_HPP_INCLUDED_ + +#include + +// Local headers +#include "MuxedManeuver.hpp" + +namespace Maneuver +{ + namespace Multiplexer + { + using DUNE_NAMESPACES; + //!Variables + struct DropArgs + { + // Servo Id + int servoId; + // Servo Id + float servoValue; + }; + + //! Drop maneuver + class Drop: public MuxedManeuver + { + public: + //! Default constructor. + //! @param[in] task pointer to Maneuver task + //! @param[in] args drop arguments + Drop(Maneuvers::Maneuver* task, DropArgs* args): + MuxedManeuver(task, args) + { } + + ~Drop(void) + { } + + //! Start maneuver function + //! @param[in] maneuver drop maneuver message + void + onStart(const IMC::Drop* maneuver) + { + m_task->setControl(IMC::CL_PATH); + + IMC::DesiredPath path; + path.end_lat = maneuver->lat; + path.end_lon = maneuver->lon; + path.end_z = maneuver->z; + path.end_z_units = maneuver->z_units; + path.speed = maneuver->speed; + path.speed_units = maneuver->speed_units; + + m_task->dispatch(path); + } + + //! On PathControlState message + //! @param[in] pcs pointer to PathControlState message + void + onPathControlState(const IMC::PathControlState* pcs) + { + if (pcs->flags & IMC::PathControlState::FL_NEAR) + { + IMC::SetServoPosition setServo; + setServo.id = m_args->servoId; + setServo.value = m_args->servoValue; + m_task->dispatch(setServo); + + m_task->signalCompletion(); + } + else + { + m_task->signalProgress(pcs->eta); + } + } + }; + } +} + +#endif diff --git a/src/Maneuver/Multiplexer/Elevator.hpp b/src/Maneuver/Multiplexer/Elevator.hpp index e8628d043a..5921e2b4be 100644 --- a/src/Maneuver/Multiplexer/Elevator.hpp +++ b/src/Maneuver/Multiplexer/Elevator.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/FollowPath.hpp b/src/Maneuver/Multiplexer/FollowPath.hpp index bb673f9fa8..e6f869e409 100644 --- a/src/Maneuver/Multiplexer/FollowPath.hpp +++ b/src/Maneuver/Multiplexer/FollowPath.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Goto.hpp b/src/Maneuver/Multiplexer/Goto.hpp index b51877cae8..9bb6ede0bf 100644 --- a/src/Maneuver/Multiplexer/Goto.hpp +++ b/src/Maneuver/Multiplexer/Goto.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Idle.hpp b/src/Maneuver/Multiplexer/Idle.hpp index bdca989834..414187d27f 100644 --- a/src/Maneuver/Multiplexer/Idle.hpp +++ b/src/Maneuver/Multiplexer/Idle.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Land.hpp b/src/Maneuver/Multiplexer/Land.hpp new file mode 100644 index 0000000000..e63d186486 --- /dev/null +++ b/src/Maneuver/Multiplexer/Land.hpp @@ -0,0 +1,156 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Maria Costa * +//*************************************************************************** + +#ifndef MANEUVER_MULTIPLEXER_LAND_HPP_INCLUDED_ +#define MANEUVER_MULTIPLEXER_LAND_HPP_INCLUDED_ + +#include + +// Local headers +#include "MuxedManeuver.hpp" + +namespace Maneuver +{ + namespace Multiplexer + { + using DUNE_NAMESPACES; + + //! Land maneuver + class Land: public MuxedManeuver + { + public: + //! Default constructor. + //! @param[in] task pointer to Maneuver task + Land(Maneuvers::Maneuver* task): + MuxedManeuver(task), + m_ground(false), + m_status(false) + { } + + //! Start maneuver function + //! @param[in] maneuver goto maneuver message + void + onStart(const IMC::Land* maneuver) + { + // Local variables + float dist; + double m_lat, m_lon; + + // Save touchdown desired coordinates + m_land = *maneuver; + + // Enable Path Control + m_task->setControl(IMC::CL_PATH); + + // Calculation of Glide Slope WP + m_lat = maneuver->lat; + m_lon = maneuver->lon; + dist = maneuver->glide_slope * maneuver->glide_slope_alt; + Coordinates::WGS84::displace(-std::cos(maneuver->bearing)*dist, -std::sin(maneuver->bearing)*dist, &m_lat, &m_lon); + + // Dispatch DesiredPath of Glide Slope WP + m_path.end_lat = m_lat; + m_path.end_lon = m_lon; + m_path.end_z = maneuver->glide_slope_alt; + m_path.end_z_units = maneuver->z_units; + m_path.speed = maneuver->speed; + m_path.speed_units = maneuver->speed_units; + m_path.lradius = 0; + m_path.flags = DesiredPath::FL_3DTRACK; + m_task->dispatch(m_path); + + m_task->debug("Sent DesiredPath of GlideSlope WP."); + } + + //! On PathControlState message + //! @param[in] pcs pointer to PathControlState message + void + onPathControlState(const IMC::PathControlState* pcs) + { + // Maneuver doesn't complete until vehicle reports vehicle medium as ground + if (pcs->flags & IMC::PathControlState::FL_NEAR) + { + if (!m_status) + { + sendTouchdown(m_land.lat, m_land.lon, m_land.z); + m_status = true; + } + } + else + m_task->signalProgress(pcs->eta); + } + + //! On message VehicleMedium + //! @param[in] msg pointer to VehicleMedium message + void + onVehicleMedium(const IMC::VehicleMedium* msg) + { + m_ground = (msg->medium == IMC::VehicleMedium::VM_GROUND); + + // Maneuver is complete only vehicle medium is GROUND + if(m_ground && m_status) + { + m_task->signalCompletion(); + m_status = false; + } + } + + //! Send touchdown DesiredPath + //! @param[in] lat latitude + //! @param[in] lon longitude + void + sendTouchdown(double lat, double lon, double z) + { + // Dispatch new desired path + m_path.end_lat = lat; + m_path.end_lon = lon; + m_path.end_z = z; + m_path.flags = IMC::DesiredPath::FL_LAND; + m_task->dispatch(m_path); + m_task->debug("Sent Touchdown DesiredPath."); + + // Dispatch Land IMC message with order to perform landing approach + m_task->dispatch(m_land); + } + + ~Land(void) + { } + + private: + //! Desired Path message + IMC::DesiredPath m_path; + //! Land message + IMC::Land m_land; + //! Vehicle is on ground + bool m_ground; + //! Status flag + bool m_status; + }; + } +} + +#endif diff --git a/src/Maneuver/Multiplexer/Launch.hpp b/src/Maneuver/Multiplexer/Launch.hpp index f220e4fa57..30e69433db 100644 --- a/src/Maneuver/Multiplexer/Launch.hpp +++ b/src/Maneuver/Multiplexer/Launch.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Loiter.hpp b/src/Maneuver/Multiplexer/Loiter.hpp index af7efd3366..d739fd1335 100644 --- a/src/Maneuver/Multiplexer/Loiter.hpp +++ b/src/Maneuver/Multiplexer/Loiter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/MuxedManeuver.hpp b/src/Maneuver/Multiplexer/MuxedManeuver.hpp index f11091b893..a8eaa7254b 100644 --- a/src/Maneuver/Multiplexer/MuxedManeuver.hpp +++ b/src/Maneuver/Multiplexer/MuxedManeuver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/PopUp.hpp b/src/Maneuver/Multiplexer/PopUp.hpp index 369745714e..d4573c49c8 100644 --- a/src/Maneuver/Multiplexer/PopUp.hpp +++ b/src/Maneuver/Multiplexer/PopUp.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Rows.hpp b/src/Maneuver/Multiplexer/Rows.hpp index 265473e255..4bcaf97ab8 100644 --- a/src/Maneuver/Multiplexer/Rows.hpp +++ b/src/Maneuver/Multiplexer/Rows.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/Sample.hpp b/src/Maneuver/Multiplexer/Sample.hpp new file mode 100644 index 0000000000..bb65e43190 --- /dev/null +++ b/src/Maneuver/Multiplexer/Sample.hpp @@ -0,0 +1,141 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Manuel Ribeiro * +//*************************************************************************** + +#ifndef MANEUVER_MULTIPLEXER_SAMPLE_HPP_INCLUDED_ +#define MANEUVER_MULTIPLEXER_SAMPLE_HPP_INCLUDED_ + +#include + +// Local headers +#include "MuxedManeuver.hpp" + +namespace Maneuver +{ + namespace Multiplexer + { + using DUNE_NAMESPACES; + //!Variables + struct SampleArgs + { + // Syringe 0 Id + int syringe0Id; + // Syringe 1 Id + int syringe1Id; + // Syringe 2 Id + int syringe2Id; + // Servo Open Value + float openValue; + // Servo Close Value + float closeValue; + // Time tolerance to execute maneuver + double max_time; + }; + + //! Sample maneuver + class Sample: public MuxedManeuver + { + public: + //! Default constructor. + //! @param[in] task pointer to Maneuver task + //! @param[in] args Sample arguments + Sample(Maneuvers::Maneuver* task, SampleArgs* args): + MuxedManeuver(task, args), + m_done(false) + { } + + ~Sample(void) + { } + + //! Start maneuver function + //! @param[in] maneuver Sample maneuver message + void + onStart(const IMC::Sample* maneuver) + { + m_maneuver = *maneuver; + timer.setTop(m_args->max_time); + m_done = false; + } + + void + onThrottle(const IMC::Throttle* throttle) + { + m_task->debug("Trottle: %f\tDone?: %d\n", throttle->value, m_done); + + if (throttle->value < 1 && (m_medium.medium == IMC::VehicleMedium::VM_GROUND) && !m_done) + { + if (m_maneuver.syringe0 == IMC::BOOL_TRUE) + setSyringeState(m_args->syringe0Id, m_args->openValue); + + if (m_maneuver.syringe1 == IMC::BOOL_TRUE) + setSyringeState(m_args->syringe1Id, m_args->openValue); + + if (m_maneuver.syringe2 == IMC::BOOL_TRUE) + setSyringeState(m_args->syringe2Id, m_args->openValue); + + m_done = true; + } + + if (timer.overflow()) + { + if (m_done) + m_task->signalCompletion(); + else + m_task->signalError(DTR("sample failed")); + } + else + m_task->debug("Sampling for %f/%f seconds...", timer.getElapsed(), timer.getTop()); + } + + void + setSyringeState(int syringe, float value) + { + IMC::SetServoPosition updateSyringe; + updateSyringe.id = syringe; + updateSyringe.value = value; + m_task->dispatch(updateSyringe); + } + + void + onVehicleMedium(const IMC::VehicleMedium* medium) + { + m_medium = *medium; + } + + private: + IMC::Sample m_maneuver; + IMC::VehicleMedium m_medium; + //! Timer counter for duration + Time::Counter timer; + bool m_done; + + }; + } +} + +#endif diff --git a/src/Maneuver/Multiplexer/ScheduledGoto.hpp b/src/Maneuver/Multiplexer/ScheduledGoto.hpp index f7c477ae3e..7901515178 100644 --- a/src/Maneuver/Multiplexer/ScheduledGoto.hpp +++ b/src/Maneuver/Multiplexer/ScheduledGoto.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Multiplexer/StationKeeping.hpp b/src/Maneuver/Multiplexer/StationKeeping.hpp index 26f3707516..e444bd1c2e 100644 --- a/src/Maneuver/Multiplexer/StationKeeping.hpp +++ b/src/Maneuver/Multiplexer/StationKeeping.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -135,6 +135,15 @@ namespace Maneuver } } + //! On ManeuverDone message + //! @param[in] pcs pointer to ManeuverDone message + void + onManeuverDone(const IMC::ManeuverDone* msg) + { + (void)msg; + m_task->signalCompletion(); + } + private: //! Station Keeping behavior Maneuvers::StationKeep* m_skeep; diff --git a/src/Maneuver/Multiplexer/StationKeepingExtended.hpp b/src/Maneuver/Multiplexer/StationKeepingExtended.hpp new file mode 100644 index 0000000000..4c8cb75bd0 --- /dev/null +++ b/src/Maneuver/Multiplexer/StationKeepingExtended.hpp @@ -0,0 +1,277 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Calado * +// Author: Eduardo Marques (original maneuver implementation) * +// Author: Maria Costa ("Keep Safe" behaviour) * +//*************************************************************************** + +#ifndef MANEUVER_MULTIPLEXER_STATION_KEEPING_EXTENDED_HPP_INCLUDED_ +#define MANEUVER_MULTIPLEXER_STATION_KEEPING_EXTENDED_HPP_INCLUDED_ + +#include + +// Local headers +#include "MuxedManeuver.hpp" +#include "Constants.hpp" +#include + +namespace Maneuver +{ + namespace Multiplexer + { + using DUNE_NAMESPACES; + + struct StationKeepingExtendedArgs + { + //! Minimum radius to prevent incompatibility with path controller + double min_radius; + }; + + //! StationKeepingExtended maneuver + class StationKeepingExtended: public MuxedManeuver + { + public: + //! Default constructor. + //! @param[in] task pointer to Maneuver task + //! @param[in] args stationkeepingextended arguments + StationKeepingExtended(Maneuvers::Maneuver* task, StationKeepingExtendedArgs* args): + MuxedManeuver(task, args), + m_skeep(NULL), + m_elevate(NULL), + m_end_time(-1.0), + m_ks(KS_UNKNOWN) + { } + + ~StationKeepingExtended(void) + { + Memory::clear(m_skeep); + Memory::clear(m_elevate); + } + + //! Start maneuver function + //! @param[in] maneuver stationkeepingextended maneuver message + void + onStart(const IMC::StationKeepingExtended* maneuver) + { + m_maneuver = *maneuver; + m_duration = maneuver->duration; + + Memory::replace(m_skeep, new Maneuvers::StationKeep(m_task, maneuver->lat, maneuver->lon, + m_args->min_radius, maneuver->z, maneuver->z_units, maneuver->speed, maneuver->speed_units)); + + if (m_duration > 0) + m_end_time = -1.0; + + if(keepSafe()) + { + m_ks = KS_STATION; + m_end_time = -1.0; + } + else + m_ks = KS_UNKNOWN; + + m_timer.reset(); + } + + //! On EstimatedState message + //! @param[in] msg EstimatedState message + void + onEstimatedState(const IMC::EstimatedState* msg) + { + if (m_skeep == NULL) + return; + + if (m_skeep->isInside() && (m_end_time < 0)) + { + m_end_time = Clock::get() + m_duration; + m_pos = *msg; + if (keepSafe() && m_ks != KS_LOITER) + startLoiter(); + } + + switch(m_ks) + { + case KS_STATION: + m_skeep->update(msg); + break; + case KS_POPUP: + m_elevate->update(msg); + break; + case KS_LOITER: + m_skeep->update(&m_pos); + break; + case KS_UNKNOWN: + m_skeep->update(msg); + break; + } + } + + //! On PathControlState message + //! @param[in] pcs PathControlState message + void + onPathControlState(const IMC::PathControlState* pcs) + { + m_pcs = *pcs; + + if (m_skeep == NULL) + return; + + if (m_ks != KS_POPUP) + m_skeep->updatePathControl(pcs); + else + { + m_elevate->updatePathControl(pcs); + if (m_elevate->isDone()) + { + m_ks = KS_STATION; + m_timer.setTop(m_maneuver.popup_duration); + m_task->setControl(IMC::CL_NONE); + } + } + } + + //! On state report function + void + onStateReport(void) + { + if (m_skeep == NULL) + return; + + if (m_duration > 0 && m_end_time > 0) + { + double time_left = m_end_time - Clock::get(); + + if (time_left <= 0) + m_task->signalCompletion(); + else + m_task->signalProgress((uint16_t)Math::round(time_left)); + } + else if (m_duration > 0 && m_end_time < 0) + m_task->signalProgress(m_pcs.eta + m_duration); + + // Check if KEEP_SAFE option enabled + if(keepSafe() && m_skeep->isInside() && m_timer.overflow()) + { + if (m_ks != KS_LOITER) + startLoiter(); + else if (m_ks != KS_POPUP) + doPopUp(); + } + } + + //! Must adopt safe behavior (loiter underwater and popup periodically to report position) + //! @return true if KEEP_SAFE option is enabled + bool + keepSafe(void) + { + return (m_maneuver.flags & IMC::StationKeepingExtended::FLG_KEEP_SAFE) != 0; + } + + //! Starts Loiter on current position + void + startLoiter(void) + { + m_task->debug("\n\tStart LOITER!"); + m_task->setControl(IMC::CL_PATH); + + m_timer.reset(); + m_timer.setTop(m_maneuver.popup_period); + + IMC::DesiredPath dpath; + dpath.lradius = m_maneuver.radius; + dpath.speed = m_maneuver.speed; + dpath.speed_units = m_maneuver.speed_units; + dpath.end_z = m_maneuver.z; + dpath.end_z_units = m_maneuver.z_units; + dpath.end_lat = m_maneuver.lat; + dpath.end_lon = m_maneuver.lon; + m_task->dispatch(dpath); + + m_ks = KS_LOITER; + } + + //! Surfaces to report position + void + doPopUp(void) + { + m_task->debug("\n\tStart ELEVATOR!"); + m_task->setControl(IMC::CL_PATH); + + m_timer.reset(); + m_timer.setTop(m_maneuver.popup_duration); + + IMC::Elevator elev; + elev.flags = IMC::Elevator::FLG_CURR_POS; + + elev.end_z = 0; + elev.end_z_units = IMC::Z_DEPTH; + elev.speed = m_maneuver.speed; + elev.speed_units = m_maneuver.speed_units; + + elev.radius = m_maneuver.radius; + elev.lat = m_maneuver.lat; + elev.lon = m_maneuver.lon; + + Memory::replace(m_elevate, new Maneuvers::Elevate(&elev, m_task, c_min_elev_radius)); + m_ks = KS_POPUP; + } + + private: + enum KeepSafeState + { + //! Unknown state + KS_UNKNOWN, + //! Station Keeping + KS_STATION, + //! Loitering + KS_LOITER, + //! Poping up to surface + KS_POPUP + }; + + //! Station Keeping behavior + Maneuvers::StationKeep* m_skeep; + //! PathControlState message + IMC::PathControlState m_pcs; + //! EstimatedState message of position inside SK radius + IMC::EstimatedState m_pos; + //! StationKeeping maneuver message + IMC::StationKeepingExtended m_maneuver; + //! Elevate maneuver message (for KEEP_SAFE behavior) + Maneuvers::Elevate* m_elevate; + //! Maneuver's duration + float m_duration; + //! End time for the maneuver + double m_end_time; + KeepSafeState m_ks; + //! Timer (for KEEP_SAFE behavior) + Time::Counter m_timer; + }; + } +} + +#endif diff --git a/src/Maneuver/Multiplexer/Takeoff.hpp b/src/Maneuver/Multiplexer/Takeoff.hpp new file mode 100644 index 0000000000..02bb3b8e8e --- /dev/null +++ b/src/Maneuver/Multiplexer/Takeoff.hpp @@ -0,0 +1,127 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Maria Costa * +//*************************************************************************** + +#ifndef MANEUVER_MULTIPLEXER_TAKEOFF_HPP_INCLUDED_ +#define MANEUVER_MULTIPLEXER_TAKEOFF_HPP_INCLUDED_ + +#include + +// Local headers +#include "MuxedManeuver.hpp" + +namespace Maneuver +{ + namespace Multiplexer + { + using DUNE_NAMESPACES; + + //! Takeoff maneuver + class Takeoff: public MuxedManeuver + { + public: + //! Default constructor. + //! @param[in] task pointer to Maneuver task + Takeoff(Maneuvers::Maneuver* task): + MuxedManeuver(task), + m_status(false), + m_height(0) + { } + + //! Start maneuver function + //! @param[in] maneuver goto maneuver message + void + onStart(const IMC::Takeoff* maneuver) + { + // Enable Path Control + m_task->setControl(IMC::CL_PATH); + + // Update DesiredPath + m_path.end_lat = maneuver->lat; + m_path.end_lon = maneuver->lon; + m_path.end_z = maneuver->z; + m_path.end_z_units = maneuver->z_units; + m_path.speed = maneuver->speed; + m_path.speed_units = maneuver->speed_units; + m_path.lradius = 0; + m_path.flags = DesiredPath::FL_3DTRACK; + } + + //! On PathControlState message + //! @param[in] pcs pointer to PathControlState message + void + onPathControlState(const IMC::PathControlState* pcs) + { + if (pcs->flags & IMC::PathControlState::FL_NEAR) + { + m_task->signalCompletion(); + m_status = false; + } + else + m_task->signalProgress(pcs->eta); + } + + //! On message EstimatedState + //! @param[in] msg pointer to EstimatedState message + void + onEstimatedState(const IMC::EstimatedState* msg) + { + m_height = msg->height; + } + + //! On message VehicleMedium + //! @param[in] msg pointer to VehicleMedium message + void + onVehicleMedium(const IMC::VehicleMedium* msg) + { + // Dispatch DesiredPath after launch + if(msg->medium == IMC::VehicleMedium::VM_AIR && !m_status) + { + if (m_height >= m_path.end_z) + { + m_task->dispatch(m_path); + m_task->debug("Takeoff: Launch Successful - DesiredPath sent."); + + m_status = true; + } + } + } + + ~Takeoff(void) + { } + + private: + //! Desired Path message + IMC::DesiredPath m_path; + //! Status flag + bool m_status; + //! Current vehicle height + float m_height; + }; + } +} + +#endif diff --git a/src/Maneuver/Multiplexer/Task.cpp b/src/Maneuver/Multiplexer/Task.cpp index e61c241c2c..6899cc8980 100644 --- a/src/Maneuver/Multiplexer/Task.cpp +++ b/src/Maneuver/Multiplexer/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -50,6 +50,11 @@ #include "Dislodge.hpp" #include "MuxedManeuver.hpp" #include "ScheduledGoto.hpp" +#include "Takeoff.hpp" +#include "Land.hpp" +#include "Drop.hpp" +#include "Sample.hpp" +#include "StationKeepingExtended.hpp" namespace Maneuver { @@ -60,7 +65,8 @@ namespace Maneuver static const std::string c_names[] = {"IdleManeuver", "Goto", "Launch", "Loiter", "StationKeeping", "YoYo", "Rows", "FollowPath", "Elevator", "PopUp", - "Dislodge","ScheduledGoto"}; + "Dislodge","ScheduledGoto", "Takeoff", "Land", + "Drop", "Sample", "StationKeepingExtended"}; enum ManeuverType { @@ -88,6 +94,16 @@ namespace Maneuver TYPE_DISLODGE, //! Type ScheduledGoto TYPE_SCHEDULEDGOTO, + //! Type Takeoff + TYPE_TAKEOFF, + //! Type Land + TYPE_LAND, + //! Type Drop + TYPE_DROP, + //! Type Sample + TYPE_SAMPLE, + //! Type StationKeepingExtended + TYPE_SKEEPEXT, //! Total number of maneuvers TYPE_TOTAL }; @@ -110,9 +126,14 @@ namespace Maneuver PopUpArgs popup; //! Dislodge Arguments DislodgeArgs dislodge; - //! + //! Scheduled Arguments ScheduledArgs scheduled; - + //! Drop Arguments + DropArgs drop; + //! Sample Arguments + SampleArgs sample; + //! StationKeepingExtended Arguments + StationKeepingExtendedArgs skext; }; struct Task: public DUNE::Maneuvers::Maneuver @@ -264,6 +285,42 @@ namespace Maneuver .units(Units::MeterPerSecond) .description("Maximum commanded speed"); + param("Drop -- Servo Id", m_args.drop.servoId) + .defaultValue("2") + .description("Servo Id."); + + param("Drop -- Servo Value", m_args.drop.servoValue) + .defaultValue("3.14159") + .description("Servo Value in radians."); + + param("Sample -- Syringe 0 Id", m_args.sample.syringe0Id) + .defaultValue("0") + .description("Port to use for syringe 0 servo"); + + param("Sample -- Syringe 1 Id", m_args.sample.syringe1Id) + .defaultValue("1") + .description("Port to use for syringe 1 servo"); + + param("Sample -- Syringe 2 Id", m_args.sample.syringe2Id) + .defaultValue("2") + .description("Port to use for syringe 2 servo"); + + param("Sample -- Servo Open Value", m_args.sample.openValue) + .defaultValue("3.14159") + .description("Value to open servo"); + + param("Sample -- Servo Close Value", m_args.sample.closeValue) + .defaultValue("1.57079") + .description("Value to close servo"); + + param("Sample -- Execution Tolerance", m_args.sample.max_time) + .defaultValue("30") + .description("Default time tolerance to execute maneuver"); + + param("StationKeepingExtended -- Minimum Radius", m_args.skext.min_radius) + .defaultValue("10.0") + .description("Minimum radius for StationKeepingExtended to prevent incompatibility with path controller"); + m_ctx.config.get("General", "Underwater Depth Threshold", "0.3", m_args.dislodge.depth_threshold); m_ctx.config.get("General", "Absolute Maximum Depth", "50.0", m_args.yoyo.max_depth); @@ -275,6 +332,8 @@ namespace Maneuver bind(this); bind(this); bind(this); + bind(this); + bind(this); } void @@ -346,6 +405,11 @@ namespace Maneuver m_maneuvers[TYPE_POPUP] = create(&m_args.popup); m_maneuvers[TYPE_DISLODGE] = create(&m_args.dislodge); m_maneuvers[TYPE_SCHEDULEDGOTO] = create(&m_args.scheduled); + m_maneuvers[TYPE_TAKEOFF] = create(); + m_maneuvers[TYPE_LAND] = create(); + m_maneuvers[TYPE_DROP] = create(&m_args.drop); + m_maneuvers[TYPE_SAMPLE] = create(&m_args.sample); + m_maneuvers[TYPE_SKEEPEXT] = create(&m_args.skext); } void @@ -425,6 +489,18 @@ namespace Maneuver m_maneuvers[m_type]->onVehicleMedium(msg); } + void + consume(const IMC::Throttle* msg) + { + m_maneuvers[m_type]->onThrottle(msg); + } + + void + consume(const IMC::ManeuverDone* msg) + { + m_maneuvers[m_type]->onManeuverDone(msg); + } + void onPathControlState(const IMC::PathControlState* pcs) { diff --git a/src/Maneuver/Multiplexer/YoYo.hpp b/src/Maneuver/Multiplexer/YoYo.hpp index 4eeb25b833..2300fe23fc 100644 --- a/src/Maneuver/Multiplexer/YoYo.hpp +++ b/src/Maneuver/Multiplexer/YoYo.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/RowsCoverage/Task.cpp b/src/Maneuver/RowsCoverage/Task.cpp index a1b34ccefc..b219233b21 100644 --- a/src/Maneuver/RowsCoverage/Task.cpp +++ b/src/Maneuver/RowsCoverage/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/Teleoperation/Task.cpp b/src/Maneuver/Teleoperation/Task.cpp index 09cf8bb6c9..8f1c3fcad6 100644 --- a/src/Maneuver/Teleoperation/Task.cpp +++ b/src/Maneuver/Teleoperation/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/VehicleFormation/Coordinator/Task.cpp b/src/Maneuver/VehicleFormation/Coordinator/Task.cpp index 6eb4f6df98..9a36fb2bf8 100644 --- a/src/Maneuver/VehicleFormation/Coordinator/Task.cpp +++ b/src/Maneuver/VehicleFormation/Coordinator/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/VehicleFormation/FormCollAvoid/Task.cpp b/src/Maneuver/VehicleFormation/FormCollAvoid/Task.cpp index e36c099ae7..a016197598 100644 --- a/src/Maneuver/VehicleFormation/FormCollAvoid/Task.cpp +++ b/src/Maneuver/VehicleFormation/FormCollAvoid/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/VehicleFormation/SMC/Task.cpp b/src/Maneuver/VehicleFormation/SMC/Task.cpp index 3a4657c6f2..86d2b61ab7 100644 --- a/src/Maneuver/VehicleFormation/SMC/Task.cpp +++ b/src/Maneuver/VehicleFormation/SMC/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Maneuver/VehicleFormation/Test/Task.cpp b/src/Maneuver/VehicleFormation/Test/Task.cpp index ea0d52ec67..3ccb60c0e7 100644 --- a/src/Maneuver/VehicleFormation/Test/Task.cpp +++ b/src/Maneuver/VehicleFormation/Test/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Monitors/Clock/Task.cpp b/src/Monitors/Clock/Task.cpp index d9fa80914a..0c89b999eb 100644 --- a/src/Monitors/Clock/Task.cpp +++ b/src/Monitors/Clock/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Monitors/Collisions/Task.cpp b/src/Monitors/Collisions/Task.cpp index f7cf7d9413..653a73f701 100644 --- a/src/Monitors/Collisions/Task.cpp +++ b/src/Monitors/Collisions/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -100,6 +100,8 @@ namespace Monitors bool m_braking; //! Motor's rpms int m_rpms; + //! Collision report + std::string m_report; //! Task arguments. Arguments m_args; @@ -120,9 +122,9 @@ namespace Monitors .description("Number of moving average samples to smooth accelerations"); param("Absolute Moving Average Samples", m_args.avg_samples_abs) - .defaultValue("3") + .defaultValue("5") .minimumValue("2") - .maximumValue("5") + .maximumValue("100") .description("Number of moving average samples to smooth accelerations"); param("Maximum Deviation Factor", m_args.k_std) @@ -259,6 +261,7 @@ namespace Monitors m_collision.value = msg->x; m_collision.type = (IMC::Collision::CD_IMPACT | IMC::Collision::CD_X); + m_report = "X-Axis | Impact"; collided(); } @@ -269,6 +272,7 @@ namespace Monitors m_collision.value = msg->z; m_collision.type = (IMC::Collision::CD_IMPACT | IMC::Collision::CD_Z); + m_report = "Z-Axis | Impact"; collided(); } @@ -278,6 +282,7 @@ namespace Monitors { m_collision.value = mean_x_abs; m_collision.type = IMC::Collision::CD_X; + m_report = "X-Axis"; collided(); } @@ -288,6 +293,7 @@ namespace Monitors { m_collision.value = mean_z_abs; m_collision.type = IMC::Collision::CD_Z; + m_report = "Z-Axis"; collided(); } @@ -365,7 +371,7 @@ namespace Monitors } // Change state and send state to the bus. - setEntityState(IMC::EntityState::ESTA_ERROR, DTR("collision detected")); + setEntityState(IMC::EntityState::ESTA_ERROR, Utils::String::str(DTR("Collision detected: %s"), m_report.c_str())); } void diff --git a/src/Monitors/Emergency/Task.cpp b/src/Monitors/Emergency/Task.cpp index b48f377914..0ebd65e28d 100644 --- a/src/Monitors/Emergency/Task.cpp +++ b/src/Monitors/Emergency/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -64,12 +64,16 @@ namespace Monitors float m_fuel; //! Confidence in fuel level. float m_fuel_conf; + //! Batteries voltage + float m_bat_voltage; //! True if executing plan. bool m_in_mission; //! Executing plan's progress. float m_progress; //! Iridium request identifier. unsigned m_req; + //! Vehicle State + uint8_t m_vstate; //! Lost communications timer. Counter m_lost_coms_timer; //! Medium handler. @@ -125,6 +129,15 @@ namespace Monitors bind(this); bind(this); bind(this); + bind(this); + bind(this); + } + + void + onUpdateParameters(void) + { + if (paramChanged(m_args.heartbeat_tout)) + m_lost_coms_timer.setTop(m_args.heartbeat_tout); } void @@ -152,7 +165,9 @@ namespace Monitors m_lost_coms_timer.setTop(m_args.heartbeat_tout); m_fuel = -1.0; m_fuel_conf = -1.0; + m_bat_voltage = -1.0; m_progress = -1.0; + m_vstate = '?'; } void @@ -182,11 +197,11 @@ namespace Monitors Time::BrokenDown bdt; - m_emsg = String::str("(%s) %02u:%02u:%02u / %d %f, %d %f / f:%d c:%d", + m_emsg = String::str("(%s) %02u:%02u:%02u / %d %f, %d %f / f:%d v:%d c:%d / s: %c", getSystemName(), bdt.hour, bdt.minutes, bdt.seconds, lat_deg, lat_min, lon_deg, lon_min, - (int)m_fuel, (int)m_fuel_conf); + (int)m_fuel, (int) m_bat_voltage, (int)m_fuel_conf, vehicleStateChar(m_vstate)); m_emsg += m_in_mission ? String::str(" / p:%d", (int)m_progress) : ""; } @@ -254,6 +269,20 @@ namespace Monitors m_fuel_conf = msg->confidence; } + void + consume(const IMC::Voltage* msg) + { + try + { + if(msg->getSourceEntity() != resolveEntity("Batteries")) + return; + m_bat_voltage = msg->value * 10; + } + catch (std::runtime_error& e) { + spew("Batteries entity is not present."); + } + } + void consume(const IMC::PlanControlState* msg) { @@ -270,6 +299,34 @@ namespace Monitors m_lost_coms_timer.reset(); } + void + consume(const IMC::VehicleState* msg) + { + m_vstate = msg->op_mode; + } + + char + vehicleStateChar(const uint8_t vstate) + { + switch((IMC::VehicleState::OperationModeEnum) vstate) + { + case IMC::VehicleState::VS_BOOT: + return 'B'; + case IMC::VehicleState::VS_CALIBRATION: + return 'C'; + case IMC::VehicleState::VS_ERROR: + return 'E'; + case IMC::VehicleState::VS_EXTERNAL: + return 'X'; + case IMC::VehicleState::VS_MANEUVER: + return 'M'; + case IMC::VehicleState::VS_SERVICE: + return 'S'; + default: + return '?'; + } + } + //! Send SMS request. //! @param[in] prefix message prefix. //! @param[in] timeout time to live. @@ -277,49 +334,62 @@ namespace Monitors void sendSMS(const char* prefix, unsigned timeout, std::string recipient = "") { - IMC::Sms sms; + IMC::TransmissionRequest msg; + msg.data_mode= IMC::TransmissionRequest::DMODE_TEXT; + if (recipient.size() == 0) - sms.number = m_args.recipient; + msg.destination = m_args.recipient; else - sms.number = recipient; + msg.destination = recipient; - sms.timeout = timeout; + msg.deadline = Time::Clock::getSinceEpoch() + timeout; if (!m_emsg.empty()) { - sms.contents = String::str("(%s) %s", prefix, m_emsg.c_str()); + msg.txt_data = String::str("(%s) %s", prefix, m_emsg.c_str()); } else { - std::string msg; + std::string s; Time::BrokenDown bdt; - msg = String::str("(%s) %02u:%02u:%02u / Unknown Location / f:%d c:%d", + s = String::str("(%s) %02u:%02u:%02u / Unknown Location / f:%d v:%d c:%d", getSystemName(), bdt.hour, bdt.minutes, bdt.seconds, - (int)m_fuel, (int)m_fuel_conf); + (int)m_fuel, (int)m_bat_voltage, (int)m_fuel_conf); - msg += m_in_mission ? String::str(" / p:%d", (int)m_progress) : ""; + s += m_in_mission ? String::str(" / p:%d", (int)m_progress) : ""; + s += String::str("/ s: %c", vehicleStateChar(m_vstate)); - sms.contents = String::str("(%s) %s", prefix, msg.c_str()); + msg.txt_data = String::str("(%s) %s", prefix, s.c_str()); } - inf(DTR("sending SMS (t:%u) to %s: %s"), - timeout, sms.number.c_str(), sms.contents.c_str()); + msg.setDestination(getSystemId()); + msg.setDestinationEntity(getEntityId()); bool ird = m_args.interface == "Iridium" || m_args.interface == "Both"; bool gsm = m_args.interface == "GSM" || m_args.interface == "Both"; if (ird) { - DUNE::IMC::IridiumMsgTx m; - m.req_id = m_req++; - m.ttl = 60; - m.data.assign(sms.contents.begin(), sms.contents.end()); - dispatch(m); + msg.comm_mean=IMC::TransmissionRequest::CMEAN_SATELLITE; + msg.deadline+=30; + msg.req_id=m_req++; + dispatch(msg); + + inf(DTR("sending IridiumMsg (t:%u) to %s: %s"), + timeout, msg.destination.c_str(), msg.txt_data.c_str()); + } + + if (gsm){ + msg.comm_mean=IMC::TransmissionRequest::CMEAN_GSM; + msg.req_id=m_req++; + dispatch(msg); + + inf(DTR("sending SMS (t:%u) to %s: %s"), + timeout, msg.destination.c_str(), msg.txt_data.c_str()); } - if (gsm) - dispatch(sms); + } //! Send all scheduled reports. diff --git a/src/Monitors/Entities/Task.cpp b/src/Monitors/Entities/Task.cpp index 221cef3303..19d88aeea3 100644 --- a/src/Monitors/Entities/Task.cpp +++ b/src/Monitors/Entities/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Monitors/FuelLevel/BatteryData.hpp b/src/Monitors/FuelLevel/BatteryData.hpp index 3574d207ad..441629ed42 100644 --- a/src/Monitors/FuelLevel/BatteryData.hpp +++ b/src/Monitors/FuelLevel/BatteryData.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Monitors/FuelLevel/EntityPower.hpp b/src/Monitors/FuelLevel/EntityPower.hpp index 3bda9d4b1b..7f9fd77c4d 100644 --- a/src/Monitors/FuelLevel/EntityPower.hpp +++ b/src/Monitors/FuelLevel/EntityPower.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Monitors/FuelLevel/FuelFilter.hpp b/src/Monitors/FuelLevel/FuelFilter.hpp index 24b6be1e1d..951a380213 100644 --- a/src/Monitors/FuelLevel/FuelFilter.hpp +++ b/src/Monitors/FuelLevel/FuelFilter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -529,10 +529,7 @@ namespace Monitors m_args->models[MDL_OPT].temp, temperature)); } - else - { - // fall through - } + /* Fall through */ default: return -1.0; } diff --git a/src/Monitors/FuelLevel/Task.cpp b/src/Monitors/FuelLevel/Task.cpp index a3d890c2cf..1720e1b794 100644 --- a/src/Monitors/FuelLevel/Task.cpp +++ b/src/Monitors/FuelLevel/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -58,6 +58,10 @@ namespace Monitors float war_lvl; //! Level of battery below which an error will be thrown. float err_lvl; + //! Level of battery, in volts, below which an error will be thrown. + float err_lvl_volt; + //! Threshold Level of battery, to switch of error to active. + float thr_err_lvl_volt; //! Value below which fuel estimation is unreliable. float low_confidence; //! List of entity labels that must be estimated. @@ -76,6 +80,10 @@ namespace Monitors IMC::FuelLevel m_fuel; //! Array of entities unsigned m_eids[BatteryData::BM_TOTAL]; + //! Flag to control state of voltage error level + bool m_volt_error_level; + //! Volatage level of batteries + float m_volt_bat; //! True if filter is ready and computing estimates bool m_filter_ready; //! Set to gather estimated power consumption of certain entities @@ -92,6 +100,8 @@ namespace Monitors Task(const std::string& name, Tasks::Context& ctx): Periodic(name, ctx), m_fuel_filter(NULL), + m_volt_error_level(false), + m_volt_bat(0), m_filter_ready(false) { m_power_model = new Power::Model(&ctx.config); @@ -160,6 +170,18 @@ namespace Monitors .units(Units::Percentage) .description("Level of battery below which an error will be thrown"); + param("Voltage Error Level", m_args.err_lvl_volt) + .defaultValue("25.5") + .units(Units::Volt) + .description("Level of battery, in voltage, below which an error will be thrown"); + + param("Voltage Threshold Error Level", m_args.thr_err_lvl_volt) + .defaultValue("0.2") + .minimumValue("0.1") + .maximumValue("8.0") + .units(Units::Volt) + .description("Threshold Level of battery, to switch of error to active."); + param("Low Confidence Level", m_args.low_confidence) .defaultValue("40.0") .minimumValue("0.0") @@ -273,6 +295,19 @@ namespace Monitors void consume(const IMC::Voltage* msg) { + if(msg->getSource() == getSystemId()) + { + if(resolveEntity(msg->getSourceEntity()).compare(m_args.elb[0]) == 0) + { + if(m_args.err_lvl_volt >= 0) + { + if(msg->value < m_args.err_lvl_volt) + m_volt_error_level = true; + + m_volt_bat = msg->value; + } + } + } m_fuel_filter->onVoltage(msg); } @@ -320,14 +355,20 @@ namespace Monitors // Fill fuel level message m_fuel_filter->fillMessage(m_fuel, m_op_labels, m_op_values); - if (m_fuel.value < m_args.err_lvl) + if (m_fuel.value < m_args.err_lvl && !m_volt_error_level) setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_FUEL_RESERVE); - else if (m_fuel.value < m_args.war_lvl) + else if (m_fuel.value < m_args.war_lvl && !m_volt_error_level) setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_FUEL_LOW); - else if (m_fuel.confidence < m_args.low_confidence) + else if (m_fuel.confidence < m_args.low_confidence && !m_volt_error_level) setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_FUEL_EST_UNRELIABLE); + else if (m_volt_error_level) + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_FUEL_RESERVE); else - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + if(!m_volt_error_level) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + + if(m_volt_error_level && m_volt_bat > (m_args.err_lvl_volt + m_args.thr_err_lvl_volt)) + m_volt_error_level = false; dispatch(m_fuel); diff --git a/src/Monitors/MantaFuelLevel/Task.cmake b/src/Monitors/MantaFuelLevel/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Monitors/MantaFuelLevel/Task.cpp b/src/Monitors/MantaFuelLevel/Task.cpp new file mode 100644 index 0000000000..fc7566ef95 --- /dev/null +++ b/src/Monitors/MantaFuelLevel/Task.cpp @@ -0,0 +1,403 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: PGonçalves * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include +#include +#include +#include + +// DUNE headers. +#include + +namespace Monitors +{ + namespace MantaFuelLevel + { + using DUNE_NAMESPACES; + + static const unsigned int c_max_fuel_level = 5; + static const unsigned int c_timeout_warning_level = 10; + static const unsigned int c_max_len_row_line_lcd = 16; + + struct Arguments + { + //! Entity label of temperature sensor. + std::string elabel_fuel; + //! Values for fuel level + float fuel_level[c_max_fuel_level]; + //! Entity label to get voltage value of main power + std::string elabel_voltage_main; + //! Entity label to get current value of charger + std::string elabel_current_charger; + //! Current value of charger to reject + float chager_current; + //! Warning fuel level + float warning_level; + //! Shutdown fuel level + float shutdow_level; + //| Use Volatge to monitor fuel + bool is_to_use_voltage; + //! Warning fuel level voltage + float warning_level_voltage; + //! Shutdown fuel level voltage + float shutdow_level_voltage; + }; + + struct Task: public DUNE::Tasks::Periodic + { + //! IMC msg for fuel level. + IMC::FuelLevel m_fuel; + //! LCD Control Message. + IMC::LcdControl m_lcd; + //! Task arguments. + Arguments m_args; + //! Flag to control state of task + bool m_is_task_in_error; + //! Voltage of battery pack. + float m_battery_volts; + //! Current of charge. + float m_current_charge; + //! Buffer forEntityState + char m_bufer_entity[64]; + //! WatchDog for warning fuel level + Counter m_wdog; + + Task(const std::string& name, Tasks::Context& ctx): + Periodic(name, ctx) + { + param("Entity Label - FuelLevel", m_args.elabel_fuel) + .defaultValue("FuelLevel") + .description("Entity label of fuel level."); + + for(unsigned int i = 0; i < c_max_fuel_level; ++i) + { + std::string option = String::str("Fuel Level %u", i + 1); + param(option, m_args.fuel_level[i]) + .defaultValue("0") + .description("Fuel Level value."); + } + + param("Entity Label for Main Voltage", m_args.elabel_voltage_main) + .defaultValue("Main Board") + .description("Entity label to get main voltage level."); + + param("Entity Label for Charger Current", m_args.elabel_current_charger) + .defaultValue("Charger") + .description("Entity label to get charger current level."); + + param("Current Value Charger Reject", m_args.chager_current) + .defaultValue("0.2") + .description("Minimun value to ignore charge."); + + param("Fuel Percentage Warning", m_args.warning_level) + .defaultValue("40") + .description("Fuel Percentage Warning."); + + param("Fuel Percentage Auto Shutdown", m_args.shutdow_level) + .defaultValue("20") + .description("Fuel Percentage Auto Shutdown."); + + param("Use Voltage Value", m_args.is_to_use_voltage) + .defaultValue("true") + .description("Monitor the fuel level using battery voltage."); + + param("Fuel Voltage Warning", m_args.warning_level_voltage) + .defaultValue("21.5") + .description("Fuel Voltage Warning."); + + param("Fuel Voltage Auto Shutdown", m_args.shutdow_level_voltage) + .defaultValue("20.5") + .description("Fuel Voltage Auto Shutdown."); + + bind(this); + bind(this); + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + m_fuel.setSourceEntity(reserveEntity(m_args.elabel_fuel)); + } + + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + if(m_args.fuel_level[0] > m_args.fuel_level[1] && m_args.fuel_level[1] > m_args.fuel_level[2] && + m_args.fuel_level[2] > m_args.fuel_level[3] && m_args.fuel_level[3] > m_args.fuel_level[4] && + m_args.fuel_level[4] > 0) + { + m_is_task_in_error = false; + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + else + { + m_is_task_in_error = true; + err(DTR("Wrong values in config file, please check values.")); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + } + m_wdog.setTop(c_timeout_warning_level); + m_wdog.reset(); + } + + //! Consume message IMC::Voltage + void + consume(const IMC::Voltage* msg) + { + if (msg->getSource() != getSystemId()) + return; + + if(m_args.elabel_voltage_main != resolveEntity(msg->getSourceEntity()) && m_args.elabel_current_charger != resolveEntity(msg->getSourceEntity())) + return; + + if(m_current_charge > 0) + { + if(m_args.elabel_current_charger != resolveEntity(msg->getSourceEntity())) + return; + + m_battery_volts = msg->value; + debug("Consume level (%s): %.2f", m_args.elabel_current_charger.c_str(), m_battery_volts); + } + else + { + if(m_args.elabel_voltage_main != resolveEntity(msg->getSourceEntity())) + return; + + m_battery_volts = msg->value; + debug("Consume level (%s): %.2f", m_args.elabel_current_charger.c_str(), m_battery_volts); + } + } + + //! Consume message IMC::Current + void + consume(const IMC::Current* msg) + { + if (msg->getSource() != getSystemId()) + return; + + if(m_args.elabel_current_charger != resolveEntity(msg->getSourceEntity())) + return; + + if(msg->value <= m_args.chager_current) + m_current_charge = 0; + else + m_current_charge = msg->value; + } + + float + getFuelLevelPercentage(void) + { + float fuel_level_perc = 0; + float interval_fuel_level, diff_voltage; + + if(m_battery_volts > m_args.fuel_level[0]) + { + fuel_level_perc = 99; + } + else if(m_battery_volts > m_args.fuel_level[1] && m_battery_volts <= m_args.fuel_level[0]) + { + interval_fuel_level = m_args.fuel_level[0] - m_args.fuel_level[1]; + diff_voltage = m_battery_volts - m_args.fuel_level[1]; + fuel_level_perc = 80 + ((diff_voltage * 20) / interval_fuel_level); + } + else if(m_battery_volts > m_args.fuel_level[2] && m_battery_volts <= m_args.fuel_level[1]) + { + interval_fuel_level = m_args.fuel_level[1] - m_args.fuel_level[2]; + diff_voltage = m_battery_volts - m_args.fuel_level[2]; + fuel_level_perc = 60 + ((diff_voltage * 20) / interval_fuel_level); + } + else if(m_battery_volts > m_args.fuel_level[3] && m_battery_volts <= m_args.fuel_level[2]) + { + interval_fuel_level = m_args.fuel_level[2] - m_args.fuel_level[3]; + diff_voltage = m_battery_volts - m_args.fuel_level[3]; + fuel_level_perc = 40 + ((diff_voltage * 20) / interval_fuel_level); + } + else if(m_battery_volts > m_args.fuel_level[4] && m_battery_volts <= m_args.fuel_level[3]) + { + interval_fuel_level = m_args.fuel_level[3] - m_args.fuel_level[4]; + diff_voltage = m_battery_volts - m_args.fuel_level[4]; + fuel_level_perc = 20 + ((diff_voltage * 20) / interval_fuel_level); + } + else if(m_battery_volts > 0 && m_battery_volts <= m_args.fuel_level[4]) + { + interval_fuel_level = m_args.fuel_level[4]; + diff_voltage = m_battery_volts - m_args.fuel_level[3]; + fuel_level_perc = abs((diff_voltage * 20) / interval_fuel_level); + } + else + { + fuel_level_perc = 0; + } + + if(fuel_level_perc > 100) + fuel_level_perc = 99; + + if(fuel_level_perc < 0) + fuel_level_perc = 1; + + return fuel_level_perc; + } + + std::string + fill(const std::string& var) + { + std::string str; + str.assign(var); + str.resize(c_max_len_row_line_lcd, ' '); + return str; + } + + void + parsePercentageValue(void) + { + debug("Battery percentage read: %.2f vs configured warning: %.2f, shutdown: %.2f", m_fuel.value, m_args.warning_level, m_args.shutdow_level); + + if (m_fuel.value > m_args.warning_level) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + else + { + if (m_fuel.value > m_args.shutdow_level) + { + if (m_wdog.overflow()) + { + m_wdog.reset(); + war("Fuel low (%d%%)", (int)m_fuel.value); + m_lcd.op = IMC::LcdControl::OP_WRITE0; + m_lcd.text = fill(String::str("Low fuel(%d%%)", (int)m_fuel.value)); + dispatch(m_lcd); + } + setEntityState(IMC::EntityState::ESTA_FAULT, Status::CODE_FUEL_LOW); + } + else + { + err("Shutting down system (%d%%)", (int)m_fuel.value); + sendToLCDPowerOff(); + } + } + } + + void + parseVoltageValue(void) + { + debug("Voltage: read %.2f, warning voltage: %.2f, shut down voltage: %.2f", m_battery_volts, + m_args.warning_level_voltage, m_args.shutdow_level_voltage); + + if (m_battery_volts > m_args.warning_level_voltage) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + else + { + if (m_battery_volts > m_args.shutdow_level_voltage) + { + if (m_wdog.overflow()) + { + m_wdog.reset(); + war("Fuel low (%.2f)", m_battery_volts); + m_lcd.op = IMC::LcdControl::OP_WRITE0; + m_lcd.text = fill(String::str("Low fuel(%.1fV)", m_battery_volts)); + dispatch(m_lcd); + } + setEntityState(IMC::EntityState::ESTA_FAULT, Status::CODE_FUEL_LOW); + } + else + { + err("Shutting down system (%.2fV)", m_battery_volts); + sendToLCDPowerOff(); + } + } + } + + void + sendToLCDPowerOff(void) + { + setEntityState(IMC::EntityState::ESTA_FAULT, Status::CODE_POWER_DOWN); + m_lcd.op = IMC::LcdControl::OP_WRITE0; + m_lcd.text = fill(String::str("Very low bat!!!")); + dispatch(m_lcd); + m_lcd.op = IMC::LcdControl::OP_WRITE1; + m_lcd.text = fill(String::str("Turning off!!!")); + dispatch(m_lcd); + IMC::PowerOperation pop; + pop.setDestination(getSystemId()); + pop.op = IMC::PowerOperation::POP_PWR_DOWN_IP; + dispatch(pop); + } + + void + task(void) + { + if(!m_is_task_in_error) + { + debug("task is not in error"); + try + { + m_fuel.value = getFuelLevelPercentage(); + m_fuel.confidence = 50; + } + catch (...) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + } + + debug("Fuel level: %.2f", m_fuel.value); + + if (m_fuel.value >= 0 || m_battery_volts > 0) + { + m_fuel.setDestination(getSystemId()); + dispatch(m_fuel); + if(m_current_charge == 0) + { + std::sprintf(m_bufer_entity, "active | %.2f V", m_battery_volts); + if(m_args.is_to_use_voltage) + parseVoltageValue(); + else + parsePercentageValue(); + } + else + { + std::sprintf(m_bufer_entity, "active | %.2f V | Charging: %.2f A", m_battery_volts, m_current_charge); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + } + } + else + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + war("Task in error, not dispatching messages"); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Monitors/Medium/Task.cpp b/src/Monitors/Medium/Task.cpp index 173a7e6388..c8a6946dcd 100644 --- a/src/Monitors/Medium/Task.cpp +++ b/src/Monitors/Medium/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -45,14 +45,23 @@ namespace Monitors static const float c_depth_hyst = 0.1; //! Timeout to check presence of wet measurement sensors. static const float c_water_presence = 30.0; + //! String to medium map + static const std::map c_str_to_medium = { + {"Air", IMC::VehicleMedium::VM_AIR}, + {"Ground", IMC::VehicleMedium::VM_GROUND}, + {"Water", IMC::VehicleMedium::VM_WATER}, + {"Underwater", IMC::VehicleMedium::VM_UNDERWATER} + }; //! %Task arguments. struct Arguments { //! Wet measurements timeout. float water_timeout; - //! Wet measurements threshold. - float water_lm; + //! Salinity threshold. + float salinity_lm; + //! Sound speed threshold. + float sspeed_lm; //! Initialization time. float init_time; //! GPS timeout. @@ -71,6 +80,8 @@ namespace Monitors std::string stype; //! Medium Sensor Entity Label. std::string label_medium; + //! Vehicle Medium (force). + std::string vmedium; }; //! %Medium task. @@ -106,6 +117,7 @@ namespace Monitors m_depth(0), m_airspeed(0), m_gndspeed(0), + m_medium_eid(UINT_MAX), m_altitude(0) { paramActive(Tasks::Parameter::SCOPE_IDLE, @@ -124,11 +136,17 @@ namespace Monitors .minimumValue("1.5") .description("No valid wet sensor data timeout"); - param("Wet Data Threshold", m_args.water_lm) + param("Salinity Threshold", m_args.salinity_lm) .defaultValue("1.0") .minimumValue("0.0") .maximumValue("5.0") - .description("No valid wet sensor data threshold value"); + .description("No valid salinity threshold value"); + + param("Sound Speed Threshold", m_args.sspeed_lm) + .defaultValue("1000.0") + .minimumValue("0.0") + .maximumValue("2000.0") + .description("No valid sound speed threshold value"); param("GPS Timeout", m_args.gps_timeout) .units(Units::Second) @@ -169,6 +187,11 @@ namespace Monitors .defaultValue("Medium Sensor") .description("Entity label of 'EntityState' Medium Sensor messages"); + param("Vehicle Medium", m_args.vmedium) + .defaultValue("Auto") + .values("Auto, Air, Ground, Water, Underwater") + .description("Set vehicle medium."); + // GPS validity. m_gps_val_bits = (IMC::GpsFix::GFV_VALID_DATE | IMC::GpsFix::GFV_VALID_TIME | IMC::GpsFix::GFV_VALID_HACC | IMC::GpsFix::GFV_VALID_VACC | @@ -218,8 +241,10 @@ namespace Monitors m_wet_devs.reset(); - if (msg->description == DTR("water")) + if (msg->description == DTR("water")) { m_in_water.reset(); + debug(DTR("Water detected using medium sensor.")); + } } void @@ -259,8 +284,10 @@ namespace Monitors m_wet_devs.reset(); - if (msg->value >= m_args.water_lm) + if (msg->value >= m_args.salinity_lm) { m_in_water.reset(); + debug(DTR("Water detected using salinity threshold.")); + } } void @@ -271,8 +298,10 @@ namespace Monitors m_wet_devs.reset(); - if (msg->value >= m_args.water_lm) + if (msg->value >= m_args.sspeed_lm) { m_in_water.reset(); + debug(DTR("Water detected using sound speed sensor.")); + } } //! Routine to check if we have recent wet sensor measurements. @@ -295,14 +324,18 @@ namespace Monitors void checkWater(void) { + spew("Water check."); + if (m_wet_devs.overflow()) { m_vm.medium = IMC::VehicleMedium::VM_UNKNOWN; return; } - if (inWater()) + if (inWater()) { m_vm.medium = IMC::VehicleMedium::VM_WATER; + spew("Vehicle is in water."); + } else m_vm.medium = IMC::VehicleMedium::VM_GROUND; } @@ -380,12 +413,16 @@ namespace Monitors // No way to detect medium properly. if (isActive() && m_wet_devs.overflow()) { + + debug("No medium data has been received for %f seconds.", m_wet_devs.getElapsed()); m_vm.medium = IMC::VehicleMedium::VM_UNKNOWN; dispatch(m_vm); setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_MISSING_DATA); return false; } + spew("Either not active or there was an overflow."); + return true; } @@ -421,6 +458,9 @@ namespace Monitors if (isActive()) { + if (m_args.vmedium != "Auto") + m_vm.medium = c_str_to_medium.at(m_args.vmedium); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); dispatch(m_vm); } diff --git a/src/Monitors/OperationalLimits/Task.cpp b/src/Monitors/OperationalLimits/Task.cpp index 582e4df321..0b1d7cf626 100644 --- a/src/Monitors/OperationalLimits/Task.cpp +++ b/src/Monitors/OperationalLimits/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Monitors/Servos/Task.cpp b/src/Monitors/Servos/Task.cpp index 7d0a009cbf..9e3b60c84b 100644 --- a/src/Monitors/Servos/Task.cpp +++ b/src/Monitors/Servos/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Navigation/AUV/Navigation/Task.cpp b/src/Navigation/AUV/Navigation/Task.cpp index 9d0f4ad9b8..b92bb26d3d 100644 --- a/src/Navigation/AUV/Navigation/Task.cpp +++ b/src/Navigation/AUV/Navigation/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -156,8 +156,21 @@ namespace Navigation float rpm_max; //! Heading bias uncertainty alignment threshold. double alignment_index; + //! Heading alignment sensor diff threshold + double alignment_diff; + //! Diff threshold - buffer of values for threshold validation + double heading_buffer_value; //! Abort if navigation exceeds maximum uncertainty. bool abort; + //! Activate RPM to m/s estimation + bool rpm_estimation; + //! Activate RPM to m/s % limit on estimation + bool speed_relation_Limit; + //! Value RPM to m/s limit on estimation + double speed_relation_limit_value; + //! Distance of Depth sensor to the veicle pitch rotation axis + float distance_depth_sensor; + }; struct Task: public DUNE::Navigation::BasicNavigation @@ -170,10 +183,16 @@ namespace Navigation MovingAverage* m_avg_speed; //! Task arguments. Arguments m_args; + //! Heading alignment buffer + int m_heading_buffer; + //! Pointer to speed model for speed conversions + const Plans::SpeedModel* m_speed_model; Task(const std::string& name, Tasks::Context& ctx): DUNE::Navigation::BasicNavigation(name, ctx), - m_avg_speed(NULL) + m_avg_speed(nullptr), + m_heading_buffer(0), + m_speed_model(nullptr) { // Declare configuration parameters. param("Position Noise Covariance with IMU", m_args.pos_noise) @@ -239,9 +258,40 @@ namespace Navigation .maximumValue("1e-4") .description("Heading bias uncertainty alignment threshold"); + param("Heading alignment sensor diff", m_args.alignment_diff) + .defaultValue("15") + .minimumValue("1") + .maximumValue("180") + .description("Heading alignment sensor diff threshold"); + + param("Heading buffer value", m_args.heading_buffer_value) + .defaultValue("200") + .minimumValue("1") + .description("Heading buffer value - how many repetitions to aligned"); + param("Entity Label - IMU", m_args.elabel_imu) .description("Entity label of the IMU"); + param("Depth sensor localization in x axis", m_args.distance_depth_sensor) + .defaultValue("0.0") + .minimumValue("0.0") + .maximumValue("2.0") + .description("Depth sensor localization in x axis in meters- used for depth correction due to pitch"); + + param("Rpm to speed estimation", m_args.rpm_estimation) + .defaultValue("true") + .description(""); + + param("Activate speed to rpm estimation limit", m_args.speed_relation_Limit) + .defaultValue("false") + .description(""); + + param("speed to rpm estimation percentage limit", m_args.speed_relation_limit_value) + .defaultValue("15") + .minimumValue("1") + .maximumValue("100") + .description("speed to rpm maximum diference between estimation and speed model"); + // Extended Kalman Filter initialization. m_kal.reset(NUM_STATE, NUM_OUT); resetKalman(); @@ -251,7 +301,7 @@ namespace Navigation } void - onUpdateParameters(void) + onUpdateParameters(void) override { BasicNavigation::onUpdateParameters(); @@ -289,21 +339,23 @@ namespace Navigation } void - onResourceInitialization(void) + onResourceInitialization(void) override { BasicNavigation::onResourceInitialization(); m_avg_speed = new MovingAverage(m_args.navg_speed); + startSpeedModel(&m_ctx.config); } void - onResourceRelease(void) + onResourceRelease(void) override { BasicNavigation::onResourceRelease(); Memory::clear(m_avg_speed); + Memory::clear(m_speed_model); } void - onEntityResolution(void) + onEntityResolution(void) override { BasicNavigation::onEntityResolution(); try @@ -321,10 +373,7 @@ namespace Navigation { IMC::AlignmentState as; - if (m_aligned) - as.state = IMC::AlignmentState::AS_ALIGNED; - else - as.state = IMC::AlignmentState::AS_NOT_ALIGNED; + as.state = m_aligned ? IMC::AlignmentState::AS_ALIGNED : IMC::AlignmentState::AS_NOT_ALIGNED; // No IMU unit available. if (m_imu_eid == std::numeric_limits::max()) @@ -423,7 +472,7 @@ namespace Navigation } double - getBiasedHeading(void) + getBiasedHeading(void) const { return m_kal.getState(STATE_PSI) + m_kal.getState(STATE_PSI_BIAS); } @@ -436,7 +485,7 @@ namespace Navigation } void - updateKalmanParametersGps(double hacc) + updateKalmanGpsParameters(double hacc) { if (hacc > GPS_BAD) { @@ -576,7 +625,22 @@ namespace Navigation } else if (m_time_without_gps.overflow() && m_time_without_dvl.overflow()) { - double u = m_rpm * m_kal.getState(STATE_K) * std::cos(getEuler(AXIS_Y)); + double u = 0.0; + double speed_m = getRpmToMs(m_rpm); + if(m_args.rpm_estimation) + { + u = m_rpm * m_kal.getState(STATE_K) * std::cos(getEuler(AXIS_Y)); + if(m_args.speed_relation_Limit) + { + double speedR = (std::abs(u) - std::abs(speed_m))/ std::abs(speed_m) * 100; + if (speedR > m_args.speed_relation_limit_value) + u = speed_m; + } + } + else + { + u = speed_m; + } m_kal.setInnovation(OUT_U, u - m_kal.getState(STATE_U)); m_kal.setInnovation(OUT_V, 0 - m_kal.getState(STATE_V)); } @@ -619,12 +683,32 @@ namespace Navigation m_kal.setState(STATE_K, k_lim); // Check alignment threshold index. + double diff_psi = std::abs(Angles::normalizeRadian(Angles::normalizeRadian(m_kal.getState(STATE_PSI)) + - Angles::normalizeRadian(getEuler(AXIS_Z)) ) ); + + if (m_dead_reckoning) { - if (m_kal.getCovariance(STATE_PSI_BIAS) < m_args.alignment_index) + if (m_kal.getCovariance(STATE_PSI_BIAS) < m_args.alignment_index && + diff_psi < Angles::normalizeRadian(Angles::radians(m_args.alignment_diff)) ) + { m_aligned = true; + m_heading_buffer = 0; + } else - m_aligned = false; + { + if (m_aligned) + { + m_heading_buffer++; + if (m_heading_buffer > m_args.heading_buffer_value) + { + sendDeActiveIMU(); + war(DTR("navigation not aligned - Automatic IMU poweroff")); + m_aligned = false; + m_heading_buffer=0; + } + } + } } checkUncertainty(m_args.abort); @@ -641,6 +725,42 @@ namespace Navigation resetKalman(); } + void + sendDeActiveIMU(void) + { + IMC::EntityParameter p; + p.name = "Active"; + p.value = "false"; + IMC::SetEntityParameters msg; + msg.name = m_args.elabel_imu ; + msg.params.push_back(p); + dispatch(msg); + } + + void + startSpeedModel(Parsers::Config* config) + { + try + { + m_speed_model = new Plans::SpeedModel(config); + m_speed_model->validate(); + } + catch (...) + { + Memory::clear(m_speed_model); + inf(DTR("Nav: speed model invalid")); + } + } + + double + getRpmToMs(double rpm) const + { + if (m_speed_model != nullptr) + return m_speed_model->toMPS(rpm, IMC::SUNITS_RPM); + + return m_args.rpm_ini * rpm; + } + // Reinitialize Extended Kalman Filter transition matrix function. void setTransition(Matrix& A) @@ -694,6 +814,8 @@ namespace Navigation m_estate.u = m_avg_speed->update(m_kal.getState(STATE_U)); m_estate.v = m_kal.getState(STATE_V); + m_estate.depth = getDepth() - m_estate.theta * m_args.distance_depth_sensor; + m_estate.z = m_last_z + m_estate.depth; // Log Navigation Uncertainty. m_uncertainty.psi = m_kal.getCovariance(STATE_PSI); diff --git a/src/Navigation/AUV/Ranger/Task.cpp b/src/Navigation/AUV/Ranger/Task.cpp index c7843ddd39..e586656936 100644 --- a/src/Navigation/AUV/Ranger/Task.cpp +++ b/src/Navigation/AUV/Ranger/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Navigation/General/GPSNavigation/Task.cpp b/src/Navigation/General/GPSNavigation/Task.cpp index 2d8d5bb77f..0b9e5762fc 100644 --- a/src/Navigation/General/GPSNavigation/Task.cpp +++ b/src/Navigation/General/GPSNavigation/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Navigation/General/LBL/Task.cpp b/src/Navigation/General/LBL/Task.cpp index b3d7d00192..0706d1bc01 100644 --- a/src/Navigation/General/LBL/Task.cpp +++ b/src/Navigation/General/LBL/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Navigation/General/ROV/Task.cpp b/src/Navigation/General/ROV/Task.cpp index 743940742c..72985b74ec 100644 --- a/src/Navigation/General/ROV/Task.cpp +++ b/src/Navigation/General/ROV/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/DB/Task.cpp b/src/Plan/DB/Task.cpp index 5ad3c39fdf..e5e36de2d3 100644 --- a/src/Plan/DB/Task.cpp +++ b/src/Plan/DB/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -291,6 +291,7 @@ namespace Plan clearDatabase(*req); break; case IMC::PlanDB::DBOP_GET_STATE: + case IMC::PlanDB::DBOP_GET_DSTATE: m_reply.plan_id.clear(); getDatabaseState(*req); break; diff --git a/src/Plan/Engine/ActionSchedule.cpp b/src/Plan/Engine/ActionSchedule.cpp index 08a3d675df..1dc44b7f6e 100644 --- a/src/Plan/Engine/ActionSchedule.cpp +++ b/src/Plan/Engine/ActionSchedule.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/ActionSchedule.hpp b/src/Plan/Engine/ActionSchedule.hpp index 81abf85362..d660d1fa1c 100644 --- a/src/Plan/Engine/ActionSchedule.hpp +++ b/src/Plan/Engine/ActionSchedule.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/Calibration.hpp b/src/Plan/Engine/Calibration.hpp index 71002fc6ed..b0607e5a5a 100644 --- a/src/Plan/Engine/Calibration.hpp +++ b/src/Plan/Engine/Calibration.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/ComponentActiveTime.hpp b/src/Plan/Engine/ComponentActiveTime.hpp index 39c02f5653..0bd6751f07 100644 --- a/src/Plan/Engine/ComponentActiveTime.hpp +++ b/src/Plan/Engine/ComponentActiveTime.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/FuelPrediction.hpp b/src/Plan/Engine/FuelPrediction.hpp index 19ae0d96ae..219111b312 100644 --- a/src/Plan/Engine/FuelPrediction.hpp +++ b/src/Plan/Engine/FuelPrediction.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/GroupSpeed.hpp b/src/Plan/Engine/GroupSpeed.hpp index 3d7a783b99..917ac29659 100644 --- a/src/Plan/Engine/GroupSpeed.hpp +++ b/src/Plan/Engine/GroupSpeed.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/Plan.cpp b/src/Plan/Engine/Plan.cpp index 3f8b86d32d..f93d0e8f75 100644 --- a/src/Plan/Engine/Plan.cpp +++ b/src/Plan/Engine/Plan.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -704,6 +704,9 @@ namespace Plan if (m->end_z > m_max_depth + c_depth_margin) return false; } + + // no means to evaluate other perils. + return true; } case DUNE_IMC_SCHEDULEDGOTO: { diff --git a/src/Plan/Engine/Plan.hpp b/src/Plan/Engine/Plan.hpp index a2759f1b03..d02a39c753 100644 --- a/src/Plan/Engine/Plan.hpp +++ b/src/Plan/Engine/Plan.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/Statistics.hpp b/src/Plan/Engine/Statistics.hpp index 7c70c6b75d..df822c2948 100644 --- a/src/Plan/Engine/Statistics.hpp +++ b/src/Plan/Engine/Statistics.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Engine/Task.cpp b/src/Plan/Engine/Task.cpp index c012343289..ab3a287fba 100644 --- a/src/Plan/Engine/Task.cpp +++ b/src/Plan/Engine/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -578,6 +578,10 @@ namespace Plan void processRequest(const IMC::PlanControl* pc) { + if (pc->getDestination() != getSystemId() + && pc->getDestination() != m_ctx.resolver.resolve("broadcast")) + return; + m_reply.setDestination(pc->getSource()); m_reply.setDestinationEntity(pc->getSourceEntity()); m_reply.request_id = pc->request_id; diff --git a/src/Plan/Engine/Timeline.hpp b/src/Plan/Engine/Timeline.hpp index f4da437f34..ff17a09027 100644 --- a/src/Plan/Engine/Timeline.hpp +++ b/src/Plan/Engine/Timeline.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Plan/Generator/Task.cpp b/src/Plan/Generator/Task.cpp index b28111c429..a95f40aefc 100644 --- a/src/Plan/Generator/Task.cpp +++ b/src/Plan/Generator/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -130,7 +130,7 @@ namespace Plan void consume(const IMC::Announce* msg) { - m_last_announces[msg->getSource()] = *msg; + m_last_announces.insert(std::pair(msg->getSource(),*msg)); } //! Stores the last received EstimatedState message. @@ -249,6 +249,7 @@ namespace Plan pcontrol.request_id = 0; pcontrol.type = IMC::PlanControl::PC_REQUEST; pcontrol.op = IMC::PlanControl::PC_START; + pcontrol.setDestination(m_ctx.resolver.id()); dispatch(pcontrol); } diff --git a/src/Power/APD/Task.cpp b/src/Power/APD/Task.cpp index cc37f589d5..b051edae67 100644 --- a/src/Power/APD/Task.cpp +++ b/src/Power/APD/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Power/BATMANv2/Driver.hpp b/src/Power/BATMANv2/Driver.hpp new file mode 100644 index 0000000000..f53eade367 --- /dev/null +++ b/src/Power/BATMANv2/Driver.hpp @@ -0,0 +1,314 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Gonçalves * +//*************************************************************************** + +#ifndef POWER_BATMAN_DRIVER_HPP_INCLUDED_ +#define POWER_BATMAN_DRIVER_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include +#include + +// DUNE headers. +#include + + +namespace Power +{ + namespace BATMANv2 + { + using DUNE_NAMESPACES; + + class DriverBatMan + { + public: + + struct BatManData + { + //! Firmware version + std::string firmVersion; + //! Voltage + float voltage; + //! Current + float current; + //! Temperature + float temperature; + //! Remaining capacity + float r_cap; + //! Full Charge Capacity + float f_cap; + //! Design Capacity + float d_cap; + //! Health + int health; + //! Cell Voltage + float cell_volt[16]; + //! State of new data received + bool state_new_data[9]; + //! Time, in min to full empty battery + float time_empty; + //! Time, in min, to full charge of battery + float time_full; + }; + + //! Serial port + SerialPort* m_uart; + //! Interrupt/Poll for serial port + Poll m_poll; + //! number of cell to read + int m_numberCell; + + + DriverBatMan(DUNE::Tasks::Task* task, SerialPort* uart, Poll poll, int numberCell): + m_task(task) + { + m_uart = uart; + m_poll = poll; + m_timeout_uart = 1.0f; + m_numberCell = numberCell; + resetStateNewData(); + } + + ~DriverBatMan(void){} + + void + resetStateNewData(void) + { + for(uint8_t t = 0; t < 8; t++) + m_batManData.state_new_data[t] = false; + } + + bool + getVersionFirmware(void) + { + if(sendCommand("@VERS,*", "$VERS,")) + return true; + + return false; + } + + bool + initBatMan(int cellNumber, float scale) + { + // Smaller by 2 otherwise compiler complains of + // format overflow inside 'sendCommand'. + char textCmd[30]; + std::sprintf(textCmd, "@CELL,%d,*", cellNumber); + if(sendCommand(textCmd, "$RSP,ACK,,*")) + { + std::memset(&textCmd, '\0', sizeof(textCmd)); + std::sprintf(textCmd, "@SCALE,%.2f,*", scale); + if(sendCommand(textCmd, "$RSP,ACK,,*")) + return true; + } + + return false; + } + + bool + startAcquisition(void) + { + if(sendCommand("@START,*", "$RSP,ACK,,*")) + return true; + + return false; + } + + bool + stopAcquisition(void) + { + if (sendCommand("@STOP,*", "")) + return true; + + return false; + } + + bool + sendCommand(const char* cmd, const char* reply) + { + char cmdText[32]; + char cmdReplyText[32]; + std::sprintf(cmdText, "%s%c\n", cmd, (Algorithms::XORChecksum::compute((uint8_t*)cmd, strlen(cmd) - 1) | 0x80)); + std::sprintf(cmdReplyText, "%s%c\n", reply, (Algorithms::XORChecksum::compute((uint8_t*)reply, strlen(reply) - 1) | 0x80)); + char bfrUart[128]; + m_task->spew("Command: %s", cmdText); + m_uart->writeString(cmdText); + + if (Poll::poll(*m_uart, m_timeout_uart)) + { + m_uart->readString(bfrUart, sizeof(bfrUart)); + m_task->spew("Reply: %s", bfrUart); + if (std::strcmp(bfrUart, cmdReplyText) == 0) + { + return true; + } + else if(std::strcmp(reply, "$VERS,") == 0) + { + char* vrs = std::strtok(bfrUart, ","); + vrs = std::strtok(NULL, ","); + m_batManData.firmVersion = vrs; + return true; + } + } + + return false; + } + + void + sendCommandNoRsp(const char* cmd) + { + char cmdText[32]; + std::sprintf(cmdText, "%s%c\n", cmd, (Algorithms::XORChecksum::compute((uint8_t*)cmd, strlen(cmd) - 1) | 0x80)); + m_task->spew("Command (no rsp): %s", cmdText); + m_uart->writeString(cmdText); + } + + bool + haveNewData(void) + { + std::size_t rv = m_uart->readString(bfr, sizeof(bfr)); + + if (rv == 0) + { + m_task->err(DTR("I/O error")); + return false; + } + + bfr[strlen(bfr) - 3] = '\0'; + + char* parameter = std::strtok(bfr, ","); + if(std::strcmp(parameter, "$VOLT") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.voltage); + m_task->debug("Volt: %.3f V", m_batManData.voltage); + m_batManData.state_new_data[0] = true; + } + else if(std::strcmp(parameter, "$AMPE") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.current); + m_task->debug("Ampe: %.3f A", m_batManData.current); + m_batManData.state_new_data[1] = true; + } + else if(std::strcmp(parameter, "$TEMP") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.temperature); + m_task->debug("Temp: %.3f C", m_batManData.temperature); + m_batManData.state_new_data[2] = true; + } + else if(std::strcmp(parameter, "$RCAP") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.r_cap); + m_task->debug("RCap: %.3f Ah", m_batManData.r_cap); + m_batManData.state_new_data[3] = true; + } + else if(std::strcmp(parameter, "$FCAP") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.f_cap); + m_task->debug("FCap: %.3f Ah", m_batManData.f_cap); + m_batManData.state_new_data[4] = true; + } + else if(std::strcmp(parameter, "$DCAP") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.d_cap); + m_task->debug("DCap: %.3f Ah", m_batManData.d_cap); + m_batManData.state_new_data[5] = true; + } + else if (std::strcmp(parameter, "$HEAL") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%d", &m_batManData.health); + m_task->debug("Health: %d %%", m_batManData.health); + m_batManData.state_new_data[6] = true; + } + else if (std::strcmp(parameter, "$CELL") == 0) + { + parameter = std::strtok(NULL, ","); + for(int i = 0; i < m_numberCell; i++) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.cell_volt[i]); + m_task->debug("Cell %d: %.3f V", i+1, m_batManData.cell_volt[i]); + } + m_batManData.state_new_data[7] = true; + m_task->debug(" "); + } + else if (std::strcmp(parameter, "$BATS") == 0) + { + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.time_empty); + if (m_batManData.time_empty == 65535) + m_batManData.time_empty = -1; + + m_task->debug("Average Time to Empty: %.0f min", m_batManData.time_empty); + parameter = std::strtok(NULL, ","); + std::sscanf(parameter, "%f", &m_batManData.time_full); + if (m_batManData.time_full == 65535) + m_batManData.time_full = -1; + + m_task->debug("Average Time to Full: %.0f min", m_batManData.time_full); + m_batManData.state_new_data[8] = true; + } + + bool result = true; + for(uint8_t t = 0; t < 8; t++) + { + if(m_batManData.state_new_data[t] == false) + result = false; + } + + return result; + } + + std::string + getFirmwareVersion(void) + { + return m_batManData.firmVersion; + } + + BatManData m_batManData; + + private: + + //! Parent task. + DUNE::Tasks::Task* m_task; + //! Timeout for new data in uart + float m_timeout_uart; + //! Buffer of uart + char bfr[64]; + }; + } +} + +#endif /* POWER_BATMAN_DRIVER_HPP_INCLUDED_ */ diff --git a/src/Power/BATMANv2/Task.cmake b/src/Power/BATMANv2/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Power/BATMANv2/Task.cpp b/src/Power/BATMANv2/Task.cpp new file mode 100644 index 0000000000..bc4c36a3b8 --- /dev/null +++ b/src/Power/BATMANv2/Task.cpp @@ -0,0 +1,511 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: PGonçalves * +//*************************************************************************** + +// DUNE headers. +#include + +// Local Headers. +#include "Driver.hpp" + +namespace Power +{ + namespace BATMANv2 + { + using DUNE_NAMESPACES; + + static const float c_delay_startup = 4.0f; + static const uint8_t c_max_values_voltage = 16; + static const uint8_t c_max_values_current = 3; + + struct Arguments + { + //! Serial port device. + std::string uart_dev; + //! Serial port baud rate. + unsigned uart_baud; + //! Input timeout. + double input_timeout; + //! Input number cell + unsigned int number_cell; + //! Scale conversion for A/Ah + float scale_factor; + //! Cell entity labels + std::string cell_elabels[c_max_values_voltage - 1]; + //! Remaining Capacity entity label + std::string rcap_elabel; + //! Full Capacity entity label + std::string fcap_elabel; + //! State to dispatch Feul level + bool dispatch_fuel_level; + //! Level of battery below which a warning will be thrown. + float war_lvl; + //! Level of battery below which an error will be thrown. + float err_lvl; + //! Level of battery (VOltage) below which an error will be thrown. + float err_volt_lvl; + //! Number of attempts before error + int number_attempts; + }; + + struct Task: public DUNE::Tasks::Task + { + //! Serial port handle. + SerialPort* m_uart; + //! I/O Multiplexer. + Poll m_poll; + //! Task arguments + Arguments m_args; + //! Driver of BatMan + DriverBatMan *m_driver; + //! Watchdog. + Counter m_wdog; + //! Temperature message + IMC::Temperature m_tmp; + //! Voltage message + IMC::Voltage m_volt[c_max_values_voltage]; + //! Voltage of batteries message + IMC::Voltage m_bat_volt; + //! Current message + IMC::Current m_amp[c_max_values_current]; + //! Fuel Level message + IMC::FuelLevel m_fuel; + //! Buffer forEntityState + char m_bufer_entity[128]; + //! Read timestamp. + double m_tstamp; + //! Count for attempts + int m_count_attempts; + //! Flag to control reset of board + bool m_is_first_reset; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL), + m_driver(0), + m_tstamp(0) + { + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the sensor"); + + param("Serial Port - Baud Rate", m_args.uart_baud) + .defaultValue("38400") + .description("Serial port baud rate"); + + param("Input Timeout", m_args.input_timeout) + .defaultValue("3.0") + .minimumValue("2.0") + .maximumValue("4.0") + .units(Units::Second) + .description("Amount of seconds to wait for data before reporting an error"); + + param("Number of cells", m_args.number_cell) + .defaultValue("7") + .minimumValue("1") + .maximumValue("15") + .description("Number of cells to read."); + + param("Scale Factor A/Ah", m_args.scale_factor) + .defaultValue("1") + .description("Scale Factor A/Ah."); + + param("Number of attempts before error", m_args.number_attempts) + .defaultValue("5") + .minimumValue("1") + .maximumValue("10") + .description("Number of attempts before error."); + + // Extract cell entity label + for (uint8_t i = 1; i < c_max_values_voltage; ++i) + { + std::string option = String::str("Cell %u - Entity Label", i); + param(option, m_args.cell_elabels[i - 1]) + .defaultValue("") + .description("Cell Entity Label"); + } + + param("Remaining Capacity - Entity Label", m_args.rcap_elabel) + .defaultValue("1") + .description("Remaining Capacity A/Ah."); + + param("Full Capacity - Entity Label", m_args.fcap_elabel) + .defaultValue("1") + .description("Full Capacity A/Ah."); + + param("Dispatch Fuel Level", m_args.dispatch_fuel_level) + .defaultValue("true") + .description("Dispatch Fuel Level."); + + param("Warning Level", m_args.war_lvl) + .defaultValue("35.0") + .minimumValue("20.0") + .maximumValue("100.0") + .units(Units::Percentage) + .description("Level of battery below which a warning will be thrown"); + + param("Error Level", m_args.err_lvl) + .defaultValue("20.0") + .minimumValue("1.0") + .maximumValue("20.0") + .units(Units::Percentage) + .description("Level of battery below which an error will be thrown"); + + param("Error Voltage Value", m_args.err_volt_lvl) + .defaultValue("22.0") + .minimumValue("18.0") + .maximumValue("30.0") + .units(Units::Volt) + .description("Level of battery, in voltage, below which an error will be thrown"); + + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + for (uint8_t i = 0; i < m_args.number_cell; ++i) + { + + if (m_args.cell_elabels[i].empty()) + continue; + + m_volt[i + 1].setSourceEntity(getEid(m_args.cell_elabels[i])); + } + + m_bat_volt.setSourceEntity(getEid("Batteries")); + m_amp[1].setSourceEntity(getEid(m_args.rcap_elabel)); + m_amp[2].setSourceEntity(getEid(m_args.fcap_elabel)); + } + + unsigned + getEid(std::string label) + { + unsigned eid = 0; + try + { + eid = resolveEntity(label); + } + catch (Entities::EntityDataBase::NonexistentLabel& e) + { + (void)e; + eid = reserveEntity(label); + } + + return eid; + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); + try + { + m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); + m_uart->setCanonicalInput(true); + m_uart->flush(); + m_poll.add(*m_uart); + m_driver = new DriverBatMan(this, m_uart, m_poll, m_args.number_cell); + m_count_attempts = 0; + } + catch (std::runtime_error& e) + { + throw RestartNeeded(e.what(), 10); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + m_driver->stopAcquisition(); + m_uart->flush(); + Delay::wait(c_delay_startup); + initBoard(false); + m_is_first_reset = true; + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_uart != NULL) + { + m_poll.remove(*m_uart); + Memory::clear(m_driver); + Memory::clear(m_uart); + } + } + + void + initBoard(bool noRestart) + { + if (!m_driver->getVersionFirmware()) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR("trying connecting to board"))); + war(DTR("failed to get firmware version")); + } + else + { + inf("Firmware Version: %s", m_driver->getFirmwareVersion().c_str()); + } + + if (!m_driver->initBatMan(m_args.number_cell, m_args.scale_factor)) + { + if (!noRestart) + { + m_driver->sendCommandNoRsp("@RESET,*"); + Delay::wait(1.0); + throw RestartNeeded(DTR("failed to init BatMan"), 10, true); + } + else + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR("trying connecting to board"))); + war(DTR("failed to init BatMan")); + return; + } + } + + if (!m_driver->startAcquisition()) + { + if (!noRestart) + { + m_driver->sendCommandNoRsp("@RESET,*"); + Delay::wait(1.0); + throw RestartNeeded(DTR("failed to start acquisition"), 10, true); + } + else + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR("trying connecting to board"))); + war(DTR("failed to start acquisition")); + return; + } + } + + debug("Init and Start OK"); + m_wdog.setTop(m_args.input_timeout); + m_wdog.reset(); + } + + std::string + minutesToTime(int minutes) + { + char time_battery[32]; + int hour = minutes / 60; + int day = hour / 24; + hour = hour - (24 * day); + int min = minutes % 60; + if (day > 0) + std::sprintf(time_battery, "%dd %dh %dm", day, hour, min); + else if (hour > 0) + std::sprintf(time_battery, "%dh %dm", hour, min); + else + std::sprintf(time_battery, "%dm", min); + + return time_battery; + } + + void + dispatchData(void) + { + m_driver->resetStateNewData(); + + m_volt[0].setTimeStamp(m_tstamp); + m_volt[0].value = m_driver->m_batManData.voltage; + dispatch(m_volt[0], DF_KEEP_TIME); + + m_bat_volt.setTimeStamp(m_tstamp); + m_bat_volt.value = m_driver->m_batManData.voltage; + dispatch(m_bat_volt, DF_KEEP_TIME); + + m_amp[0].setTimeStamp(m_tstamp); + m_amp[0].value = m_driver->m_batManData.current; + dispatch(m_amp[0], DF_KEEP_TIME); + + for (uint8_t id = 1; id <= m_args.number_cell; ++id) + { + m_volt[id].setTimeStamp(m_tstamp); + m_volt[id].value = m_driver->m_batManData.cell_volt[id - 1]; + dispatch(m_volt[id], DF_KEEP_TIME); + } + + m_tmp.setTimeStamp(m_tstamp); + m_tmp.value = m_driver->m_batManData.temperature; + dispatch(m_tmp, DF_KEEP_TIME); + + m_amp[1].setTimeStamp(m_tstamp); + m_amp[1].value = m_driver->m_batManData.r_cap; + dispatch(m_amp[1], DF_KEEP_TIME); + + m_amp[2].setTimeStamp(m_tstamp); + m_amp[2].value = m_driver->m_batManData.f_cap; + dispatch(m_amp[2], DF_KEEP_TIME); + + if(m_args.dispatch_fuel_level) + { + m_fuel.setTimeStamp(m_tstamp); + m_fuel.value = (m_driver->m_batManData.r_cap * 100) / m_driver->m_batManData.f_cap; + m_fuel.confidence = 100; + dispatch(m_fuel, DF_KEEP_TIME); + } + + if (m_fuel.value < m_args.err_lvl && m_driver->m_batManData.voltage < m_args.err_volt_lvl) + { + std::memset(&m_bufer_entity, '\0', sizeof(m_bufer_entity)); + if (m_driver->m_batManData.time_full > 0) + { + std::sprintf(m_bufer_entity, "fuel reserve - ETF: %s", minutesToTime(m_driver->m_batManData.time_full).c_str()); + setEntityState(IMC::EntityState::ESTA_ERROR, Utils::String::str(DTR(m_bufer_entity))); + } + else if((m_driver->m_batManData.time_empty > 0)) + { + std::sprintf(m_bufer_entity, "fuel reserve - ETD: %s", minutesToTime(m_driver->m_batManData.time_empty).c_str()); + setEntityState(IMC::EntityState::ESTA_ERROR, Utils::String::str(DTR(m_bufer_entity))); + } + else + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_FUEL_RESERVE); + } + } + else if (m_fuel.value < m_args.err_lvl) + { + std::memset(&m_bufer_entity, '\0', sizeof(m_bufer_entity)); + if (m_driver->m_batManData.time_full > 0) + { + std::sprintf(m_bufer_entity, "fuel warning - ETF: %s", minutesToTime(m_driver->m_batManData.time_full).c_str()); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + else if((m_driver->m_batManData.time_empty > 0)) + { + std::sprintf(m_bufer_entity, "fuel warning - ETD: %s", minutesToTime(m_driver->m_batManData.time_empty).c_str()); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + else + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_FUEL_RESERVE); + } + } + else if (m_fuel.value < m_args.war_lvl) + { + std::memset(&m_bufer_entity, '\0', sizeof(m_bufer_entity)); + if (m_driver->m_batManData.time_full > 0) + { + std::sprintf(m_bufer_entity, "fuel running low - ETF: %s", minutesToTime(m_driver->m_batManData.time_full).c_str()); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + else if ((m_driver->m_batManData.time_empty > 0)) + { + std::sprintf(m_bufer_entity, "fuel running low - ETD: %s", minutesToTime(m_driver->m_batManData.time_empty).c_str()); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + else + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_FUEL_LOW); + } + } + else + { + std::memset(&m_bufer_entity, '\0', sizeof(m_bufer_entity)); + + if (m_driver->m_batManData.time_full > 0) + std::sprintf(m_bufer_entity, + "H: %d %%, Volt: %.3f V, RCap: %.3f Ah, ETF: %s", + m_driver->m_batManData.health, + m_driver->m_batManData.voltage, + m_driver->m_batManData.r_cap, + minutesToTime(m_driver->m_batManData.time_full).c_str()); + else if (m_driver->m_batManData.time_empty > 0) + std::sprintf(m_bufer_entity, + "H: %d %%, Volt: %.3f V, RCap: %.3f Ah, ETD: %s", + m_driver->m_batManData.health, + m_driver->m_batManData.voltage, + m_driver->m_batManData.r_cap, + minutesToTime(m_driver->m_batManData.time_empty).c_str()); + else + std::sprintf(m_bufer_entity, + "H: %d %%, Volt: %.3f V, RCap: %.3f Ah", + m_driver->m_batManData.health, + m_driver->m_batManData.voltage, + m_driver->m_batManData.r_cap); + + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(0.01); + + if (m_wdog.overflow()) + { + if (m_count_attempts >= m_args.number_attempts) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 10); + } + + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR("trying connecting to board"))); + war(DTR("trying connecting to board")); + m_count_attempts++; + if (m_is_first_reset) + { + m_driver->sendCommandNoRsp("@RESET,*"); + m_is_first_reset = false; + } + m_uart->flush(); + initBoard(true); + } + + if (!Poll::poll(*m_uart, m_args.input_timeout)) + continue; + + if(m_driver->haveNewData()) + { + m_tstamp = Clock::getSinceEpoch(); + dispatchData(); + m_count_attempts = 0; + m_is_first_reset = true; + m_wdog.reset(); + } + } + debug("Sending stop to BatMan"); + m_driver->stopAcquisition(); + } + }; + } +} + +DUNE_TASK diff --git a/src/Power/CPMB/Task.cmake b/src/Power/CPMB/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Power/CPMB/Task.cpp b/src/Power/CPMB/Task.cpp new file mode 100644 index 0000000000..25a5d2848c --- /dev/null +++ b/src/Power/CPMB/Task.cpp @@ -0,0 +1,380 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Maria Costa * +//*************************************************************************** + +// DUNE headers. +#include +#include + +namespace Power +{ + namespace CPMB + { + //! Device driver for CPMB (Copter Power Management Board). + //! + //! This board is able to monitor voltages and currents measurements. + //! It's also capable of controlling the following I/O's: + //! 2x (5V Outputs) + //! 1x (12V Outputs) + //! 2x (Batteries Outputs) + //! + //! @author Maria Costa + + using DUNE_NAMESPACES; + using ::Power::PCTLv2::PowerChannel; + using ::Power::PCTLv2::PowerChannels; + + //! Serial port baud rate. + static const unsigned c_baud_rate = 115200; + //! Amount of seconds to wait before restarting task. + static const unsigned c_restart_delay = 1; + //! Number of Power channels. + static const unsigned c_pwrs_count = 5; + //! Number of ADC channels. + static const unsigned c_adcs_count = 4; + + //! Packet identifiers. + enum PacketIds + { + //! State. + PKT_ID_STATE = 1, + PKT_ID_SET_POWER = 2 + }; + + //! Task arguments. + struct Arguments + { + //! Serial port device. + std::string uart_dev; + //! ADC Messages. + std::string adc_messages[c_adcs_count]; + //! ADC entity labels. + std::string adc_elabels[c_adcs_count]; + //! ADC conversion factors. + std::vector adc_factors[c_adcs_count]; + //! Power channels names. + std::string pwr_names[c_pwrs_count]; + //! Power channels states. + unsigned pwr_states[c_pwrs_count]; + //! ADC nominal fixed offset (atxmega32a4u). + float adc_vdelta; + }; + + struct Task: public DUNE::Tasks::Task + { + //! ADC messages. + IMC::Message* m_adcs[c_adcs_count]; + //! Power channels. + PowerChannels m_channels; + //! UART. + SerialPort* m_uart; + //! Control Interface. + UCTK::Interface* m_ctl; + //! Current. + IMC::Current m_current[c_adcs_count/2-1]; + //! Voltage. + IMC::Voltage m_voltage[c_adcs_count/2]; + //! Task arguments. + Arguments m_args; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL), + m_ctl(NULL) + { + // Define configuration parameters. + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the board."); + + for (unsigned i = 0; i < c_adcs_count; ++i) + { + std::string option = String::str("ADC Channel %u - Message", i); + param(option, m_args.adc_messages[i]); + + option = String::str("ADC Channel %u - Entity Label", i); + param(option, m_args.adc_elabels[i]); + + option = String::str("ADC Channel %u - Conversion", i); + param(option, m_args.adc_factors[i]) + .size(2) + .defaultValue("1.0, 0.0"); + } + + for (unsigned i = 0; i < c_pwrs_count; ++i) + { + std::string option = String::str("Power Channel %u - Name", i); + param(option, m_args.pwr_names[i]); + + option = String::str("Power Channel %u - State", i); + param(option, m_args.pwr_states[i]) + .defaultValue("0"); + } + + param("ADC VDelta Offset", m_args.adc_vdelta) + .defaultValue("0.05") + .description("ADC nominal fixed offset (atxmega32a4u)."); + + + // Setup handlers for IMC messages. + bind(this); + bind(this); + + // ADC messages initialization. + std::memset(m_adcs, 0, sizeof(m_adcs)); + } + + ~Task(void) + { + onResourceRelease(); + clearADCs(); + } + + void + clearADCs() + { + for (unsigned i = 0; i < c_adcs_count; ++i) + { + if (m_adcs[i] != NULL) + Memory::clear(m_adcs[i]); + } + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + // Produces ADC messages. + for (unsigned i = 0; i < c_adcs_count; ++i) + { + if (m_adcs[i] != NULL) + delete m_adcs[i]; + + m_adcs[i] = IMC::Factory::produce(m_args.adc_messages[i]); + + try + { + unsigned eid = resolveEntity(m_args.adc_elabels[i]); + m_adcs[i]->setSourceEntity(eid); + } + catch (...) + { } + } + // Updates power channels state. + m_channels.clear(); + for (unsigned i = 0; i < c_pwrs_count; ++i) + { + PowerChannel* channel = new PowerChannel; + channel->id = i; + channel->state.name = m_args.pwr_names[i]; + if (m_args.pwr_states[i] == 1) + channel->state.state = IMC::PowerChannelState::PCS_ON; + else + channel->state.state = IMC::PowerChannelState::PCS_OFF; + m_channels.add(i, channel); + } + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + for (unsigned i = 0; i < c_adcs_count; ++i) + { + unsigned eid = 0; + + try + { + eid = resolveEntity(m_args.adc_elabels[i]); + } + catch (Entities::EntityDataBase::NonexistentLabel& e) + { + (void)e; + eid = reserveEntity(m_args.adc_elabels[i]); + } + + m_adcs[i]->setSourceEntity(eid); + } + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + try + { + m_uart = new SerialPort(m_args.uart_dev, c_baud_rate); + m_ctl = new UCTK::Interface(m_uart); + UCTK::FirmwareInfo info = m_ctl->getFirmwareInfo(); + + if (info.isDevelopment()) + war(DTR("Device is using unstable firmware!")); + else + inf(DTR("Firmware version %u.%u.%u"), info.major, + info.minor, info.patch); + } + catch (std::runtime_error& e) + { + throw RestartNeeded(e.what(), c_restart_delay); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + std::map::const_iterator itr = m_channels.begin(); + for ( ; itr != m_channels.end(); ++itr) + setPowerChannel(itr->second->id, itr->second->state.state); + + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_ctl != NULL) + { + delete m_ctl; + m_ctl = NULL; + } + + Memory::clear(m_uart); + } + + void + consume(const IMC::PowerChannelControl* msg) + { + // If PCC message received doesn't match any of the power channel names defined in m_channels, return. + std::map::const_iterator itr = m_channels.find_by_name(msg->name); + if (itr == m_channels.end_by_name()) + return; + + // Sets power channel as specified in received PCC message. + uint8_t channel = itr->second->id; + uint8_t value = 0; + + if (msg->op == IMC::PowerChannelControl::PCC_OP_TURN_ON) + value = 1; + else if (msg->op == IMC::PowerChannelControl::PCC_OP_TURN_OFF) + value = 0; + + debug("Setting power channel %s to %u.", msg->name.c_str(), value); + setPowerChannel(channel, value); + } + + void + consume(const IMC::QueryPowerChannelState* msg) + { + (void)msg; + dispatchPowerChannelStates(); + } + + //! Sends command to board through serial port. + bool + setPowerChannel(uint8_t channel, uint8_t value) + { + UCTK::Frame frame; + frame.setId(PKT_ID_SET_POWER); + frame.setPayloadSize(2); + frame.set(channel, 0); + frame.set(value, 1); + + return m_ctl->sendFrame(frame); + } + + //! Dispatches power channel states to IMC bus. + void + dispatchPowerChannelStates(void) + { + std::map::const_iterator itr = m_channels.begin(); + + for (; itr != m_channels.end(); ++itr) + { + dispatch(itr->second->state); + } + } + + bool + getMonitors(void) + { + UCTK::Frame frame; + frame.setId(PKT_ID_STATE); + + if (!m_ctl->sendFrame(frame)) + throw std::runtime_error(DTR("Failed to send frame to APD. Check connection!")); + + if (frame.getPayloadSize() != (c_adcs_count*2+2)) + return false; + + // Converts measurements read (12-bit ADC) and dispatches them to IMC bus. + for (unsigned i = 0; i < c_adcs_count; ++i) + { + uint16_t value = 0; + frame.get(value, i*2); + + if (m_adcs[i] != NULL) + { + float tmp = m_args.adc_factors[i][0] * ((value / 4096.0) - m_args.adc_vdelta) + m_args.adc_factors[i][1]; + m_adcs[i]->setValueFP(tmp); + dispatch(m_adcs[i]); + } + } + + // Reads power channel states. + uint8_t power_state = 0; + frame.get(power_state, c_adcs_count*2); + std::map::const_iterator itr = m_channels.begin(); + for ( ; itr != m_channels.end(); ++itr) + { + unsigned id = itr->second->id; + itr->second->state.state = (power_state & (1 << id)) ? IMC::PowerChannelState::PCS_ON : IMC::PowerChannelState::PCS_OFF; + } + + return true; + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + getMonitors(); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Power/CPMBH/Task.cmake b/src/Power/CPMBH/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Power/CPMBH/Task.cpp b/src/Power/CPMBH/Task.cpp new file mode 100644 index 0000000000..0f0fb0413d --- /dev/null +++ b/src/Power/CPMBH/Task.cpp @@ -0,0 +1,379 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Maria Costa * +//*************************************************************************** + +// DUNE headers. +#include +#include + +namespace Power +{ + namespace CPMBH + { + //! Device driver for CPMB-H (Copter Power Management Board) for Hercules platform. + //! + //! This board is able to monitor voltages and currents measurements. + //! It's also capable of controlling the following I/O's: + //! 2x (5V Outputs) + //! 4x (24V Outputs) + //! + //! @author Maria Costa + + using DUNE_NAMESPACES; + using ::Power::PCTLv2::PowerChannel; + using ::Power::PCTLv2::PowerChannels; + + //! Serial port baud rate. + static const unsigned c_baud_rate = 115200; + //! Amount of seconds to wait before restarting task. + static const unsigned c_restart_delay = 1; + //! Number of Power channels. + static const unsigned c_pwrs_count = 6; + //! Number of ADC channels. + static const unsigned c_adcs_count = 4; + + //! Packet identifiers. + enum PacketIds + { + //! State. + PKT_ID_STATE = 1, + PKT_ID_SET_POWER = 2 + }; + + //! Task arguments. + struct Arguments + { + //! Serial port device. + std::string uart_dev; + //! ADC Messages. + std::string adc_messages[c_adcs_count]; + //! ADC entity labels. + std::string adc_elabels[c_adcs_count]; + //! ADC conversion factors. + std::vector adc_factors[c_adcs_count]; + //! Power channels names. + std::string pwr_names[c_pwrs_count]; + //! Power channels states. + unsigned pwr_states[c_pwrs_count]; + //! ADC nominal fixed offset (atxmega32a4u). + float adc_vdelta; + }; + + struct Task: public DUNE::Tasks::Task + { + //! ADC messages. + IMC::Message* m_adcs[c_adcs_count]; + //! Power channels. + PowerChannels m_channels; + //! UART. + SerialPort* m_uart; + //! Control Interface. + UCTK::Interface* m_ctl; + //! Current. + IMC::Current m_current[c_adcs_count/2-1]; + //! Voltage. + IMC::Voltage m_voltage[c_adcs_count/2]; + //! Task arguments. + Arguments m_args; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL), + m_ctl(NULL) + { + // Define configuration parameters. + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the board."); + + for (unsigned i = 0; i < c_adcs_count; ++i) + { + std::string option = String::str("ADC Channel %u - Message", i); + param(option, m_args.adc_messages[i]); + + option = String::str("ADC Channel %u - Entity Label", i); + param(option, m_args.adc_elabels[i]); + + option = String::str("ADC Channel %u - Conversion", i); + param(option, m_args.adc_factors[i]) + .size(2) + .defaultValue("1.0, 0.0"); + } + + for (unsigned i = 0; i < c_pwrs_count; ++i) + { + std::string option = String::str("Power Channel %u - Name", i); + param(option, m_args.pwr_names[i]); + + option = String::str("Power Channel %u - State", i); + param(option, m_args.pwr_states[i]) + .defaultValue("0"); + } + + param("ADC VDelta Offset", m_args.adc_vdelta) + .defaultValue("0.05") + .description("ADC nominal fixed offset (atxmega32a4u)."); + + + // Setup handlers for IMC messages. + bind(this); + bind(this); + + // ADC messages initialization. + std::memset(m_adcs, 0, sizeof(m_adcs)); + } + + ~Task(void) + { + onResourceRelease(); + clearADCs(); + } + + void + clearADCs() + { + for (unsigned i = 0; i < c_adcs_count; ++i) + { + if (m_adcs[i] != NULL) + Memory::clear(m_adcs[i]); + } + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + // Produces ADC messages. + for (unsigned i = 0; i < c_adcs_count; ++i) + { + if (m_adcs[i] != NULL) + delete m_adcs[i]; + + m_adcs[i] = IMC::Factory::produce(m_args.adc_messages[i]); + + try + { + unsigned eid = resolveEntity(m_args.adc_elabels[i]); + m_adcs[i]->setSourceEntity(eid); + } + catch (...) + { } + } + // Updates power channels state. + m_channels.clear(); + for (unsigned i = 0; i < c_pwrs_count; ++i) + { + PowerChannel* channel = new PowerChannel; + channel->id = i; + channel->state.name = m_args.pwr_names[i]; + if (m_args.pwr_states[i] == 1) + channel->state.state = IMC::PowerChannelState::PCS_ON; + else + channel->state.state = IMC::PowerChannelState::PCS_OFF; + m_channels.add(i, channel); + } + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + for (unsigned i = 0; i < c_adcs_count; ++i) + { + unsigned eid = 0; + + try + { + eid = resolveEntity(m_args.adc_elabels[i]); + } + catch (Entities::EntityDataBase::NonexistentLabel& e) + { + (void)e; + eid = reserveEntity(m_args.adc_elabels[i]); + } + + m_adcs[i]->setSourceEntity(eid); + } + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + try + { + m_uart = new SerialPort(m_args.uart_dev, c_baud_rate); + m_ctl = new UCTK::Interface(m_uart); + UCTK::FirmwareInfo info = m_ctl->getFirmwareInfo(); + + if (info.isDevelopment()) + war(DTR("Device is using unstable firmware!")); + else + inf(DTR("Firmware version %u.%u.%u"), info.major, + info.minor, info.patch); + } + catch (std::runtime_error& e) + { + throw RestartNeeded(e.what(), c_restart_delay); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + std::map::const_iterator itr = m_channels.begin(); + for ( ; itr != m_channels.end(); ++itr) + setPowerChannel(itr->second->id, itr->second->state.state); + + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_ctl != NULL) + { + delete m_ctl; + m_ctl = NULL; + } + + Memory::clear(m_uart); + } + + void + consume(const IMC::PowerChannelControl* msg) + { + // If PCC message received doesn't match any of the power channel names defined in m_channels, return. + std::map::const_iterator itr = m_channels.find_by_name(msg->name); + if (itr == m_channels.end_by_name()) + return; + + // Sets power channel as specified in received PCC message. + uint8_t channel = itr->second->id; + uint8_t value = 0; + + if (msg->op == IMC::PowerChannelControl::PCC_OP_TURN_ON) + value = 1; + else if (msg->op == IMC::PowerChannelControl::PCC_OP_TURN_OFF) + value = 0; + + debug("Setting power channel %s to %u.", msg->name.c_str(), value); + setPowerChannel(channel, value); + } + + void + consume(const IMC::QueryPowerChannelState* msg) + { + (void)msg; + dispatchPowerChannelStates(); + } + + //! Sends command to board through serial port. + bool + setPowerChannel(uint8_t channel, uint8_t value) + { + UCTK::Frame frame; + frame.setId(PKT_ID_SET_POWER); + frame.setPayloadSize(2); + frame.set(channel, 0); + frame.set(value, 1); + + return m_ctl->sendFrame(frame); + } + + //! Dispatches power channel states to IMC bus. + void + dispatchPowerChannelStates(void) + { + std::map::const_iterator itr = m_channels.begin(); + + for (; itr != m_channels.end(); ++itr) + { + dispatch(itr->second->state); + } + } + + bool + getMonitors(void) + { + UCTK::Frame frame; + frame.setId(PKT_ID_STATE); + + if (!m_ctl->sendFrame(frame)) + throw std::runtime_error(DTR("Failed to send frame to CPMB-H. Check connection!")); + + if (frame.getPayloadSize() != (c_adcs_count*2+2)) + return false; + + // Converts measurements read (12-bit ADC) and dispatches them to IMC bus. + for (unsigned i = 0; i < c_adcs_count; ++i) + { + uint16_t value = 0; + frame.get(value, i*2); + + if (m_adcs[i] != NULL) + { + float tmp = m_args.adc_factors[i][0] * ((value / 4096.0) - m_args.adc_vdelta) + m_args.adc_factors[i][1]; + m_adcs[i]->setValueFP(tmp); + dispatch(m_adcs[i]); + } + } + + // Reads power channel states. + uint8_t power_state = 0; + frame.get(power_state, c_adcs_count*2); + std::map::const_iterator itr = m_channels.begin(); + for ( ; itr != m_channels.end(); ++itr) + { + unsigned id = itr->second->id; + itr->second->state.state = (power_state & (1 << id)) ? IMC::PowerChannelState::PCS_ON : IMC::PowerChannelState::PCS_OFF; + } + + return true; + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + getMonitors(); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Power/CPMBv2/Task.cmake b/src/Power/CPMBv2/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Power/CPMBv2/Task.cpp b/src/Power/CPMBv2/Task.cpp new file mode 100644 index 0000000000..c09d235f50 --- /dev/null +++ b/src/Power/CPMBv2/Task.cpp @@ -0,0 +1,381 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Maria Costa * +//*************************************************************************** + +// DUNE headers. +#include +#include + +namespace Power +{ + namespace CPMBv2 + { + //! Device driver for CPMBv2 (Copter Power Management Board v2.1.0). + //! + //! This board is able to monitor voltages and currents measurements. + //! It's also capable of controlling the following I/O's: + //! 2x (5V Outputs) + //! 3x (12V Outputs) + //! 2x (24V output) + //! 2x (Batteries Outputs) + //! + //! @author Maria Costa + + using DUNE_NAMESPACES; + using ::Power::PCTLv2::PowerChannel; + using ::Power::PCTLv2::PowerChannels; + + //! Serial port baud rate. + static const unsigned c_baud_rate = 115200; + //! Amount of seconds to wait before restarting task. + static const unsigned c_restart_delay = 1; + //! Number of Power channels. + static const unsigned c_pwrs_count = 9; + //! Number of ADC channels. + static const unsigned c_adcs_count = 5; + + //! Packet identifiers. + enum PacketIds + { + //! State. + PKT_ID_STATE = 1, + PKT_ID_SET_POWER = 2 + }; + + //! Task arguments. + struct Arguments + { + //! Serial port device. + std::string uart_dev; + //! ADC Messages. + std::string adc_messages[c_adcs_count]; + //! ADC entity labels. + std::string adc_elabels[c_adcs_count]; + //! ADC conversion factors. + std::vector adc_factors[c_adcs_count]; + //! Power channels names. + std::string pwr_names[c_pwrs_count]; + //! Power channels states. + unsigned pwr_states[c_pwrs_count]; + //! ADC nominal fixed offset (atxmega32a4u). + float adc_vdelta; + }; + + struct Task: public DUNE::Tasks::Task + { + //! ADC messages. + IMC::Message* m_adcs[c_adcs_count]; + //! Power channels. + PowerChannels m_channels; + //! UART. + SerialPort* m_uart; + //! Control Interface. + UCTK::Interface* m_ctl; + //! Current. + IMC::Current m_current[c_adcs_count/2-1]; + //! Voltage. + IMC::Voltage m_voltage[c_adcs_count/2]; + //! Task arguments. + Arguments m_args; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL), + m_ctl(NULL) + { + // Define configuration parameters. + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the board."); + + for (unsigned i = 0; i < c_adcs_count; ++i) + { + std::string option = String::str("ADC Channel %u - Message", i); + param(option, m_args.adc_messages[i]); + + option = String::str("ADC Channel %u - Entity Label", i); + param(option, m_args.adc_elabels[i]); + + option = String::str("ADC Channel %u - Conversion", i); + param(option, m_args.adc_factors[i]) + .size(2) + .defaultValue("1.0, 0.0"); + } + + for (unsigned i = 0; i < c_pwrs_count; ++i) + { + std::string option = String::str("Power Channel %u - Name", i); + param(option, m_args.pwr_names[i]); + + option = String::str("Power Channel %u - State", i); + param(option, m_args.pwr_states[i]) + .defaultValue("0"); + } + + param("ADC VDelta Offset", m_args.adc_vdelta) + .defaultValue("0.05") + .description("ADC nominal fixed offset (atxmega32a4u)."); + + + // Setup handlers for IMC messages. + bind(this); + bind(this); + + // ADC messages initialization. + std::memset(m_adcs, 0, sizeof(m_adcs)); + } + + ~Task(void) + { + onResourceRelease(); + clearADCs(); + } + + void + clearADCs() + { + for (unsigned i = 0; i < c_adcs_count; ++i) + { + if (m_adcs[i] != NULL) + Memory::clear(m_adcs[i]); + } + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + // Produces ADC messages. + for (unsigned i = 0; i < c_adcs_count; ++i) + { + if (m_adcs[i] != NULL) + delete m_adcs[i]; + + m_adcs[i] = IMC::Factory::produce(m_args.adc_messages[i]); + + try + { + unsigned eid = resolveEntity(m_args.adc_elabels[i]); + m_adcs[i]->setSourceEntity(eid); + } + catch (...) + { } + } + // Updates power channels state. + m_channels.clear(); + for (unsigned i = 0; i < c_pwrs_count; ++i) + { + PowerChannel* channel = new PowerChannel; + channel->id = i; + channel->state.name = m_args.pwr_names[i]; + if (m_args.pwr_states[i] == 1) + channel->state.state = IMC::PowerChannelState::PCS_ON; + else + channel->state.state = IMC::PowerChannelState::PCS_OFF; + m_channels.add(i, channel); + } + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + for (unsigned i = 0; i < c_adcs_count; ++i) + { + unsigned eid = 0; + + try + { + eid = resolveEntity(m_args.adc_elabels[i]); + } + catch (Entities::EntityDataBase::NonexistentLabel& e) + { + (void)e; + eid = reserveEntity(m_args.adc_elabels[i]); + } + + m_adcs[i]->setSourceEntity(eid); + } + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + try + { + m_uart = new SerialPort(m_args.uart_dev, c_baud_rate); + m_ctl = new UCTK::Interface(m_uart); + UCTK::FirmwareInfo info = m_ctl->getFirmwareInfo(); + + if (info.isDevelopment()) + war(DTR("Device is using unstable firmware!")); + else + inf(DTR("Firmware version %u.%u.%u"), info.major, + info.minor, info.patch); + } + catch (std::runtime_error& e) + { + throw RestartNeeded(e.what(), c_restart_delay); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + std::map::const_iterator itr = m_channels.begin(); + for ( ; itr != m_channels.end(); ++itr) + setPowerChannel(itr->second->id, itr->second->state.state); + + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_ctl != NULL) + { + delete m_ctl; + m_ctl = NULL; + } + + Memory::clear(m_uart); + } + + void + consume(const IMC::PowerChannelControl* msg) + { + // If PCC message received doesn't match any of the power channel names defined in m_channels, return. + std::map::const_iterator itr = m_channels.find_by_name(msg->name); + if (itr == m_channels.end_by_name()) + return; + + // Sets power channel as specified in received PCC message. + uint8_t channel = itr->second->id; + uint8_t value = 0; + + if (msg->op == IMC::PowerChannelControl::PCC_OP_TURN_ON) + value = 1; + else if (msg->op == IMC::PowerChannelControl::PCC_OP_TURN_OFF) + value = 0; + + debug("Setting power channel %s to %u.", msg->name.c_str(), value); + setPowerChannel(channel, value); + } + + void + consume(const IMC::QueryPowerChannelState* msg) + { + (void)msg; + dispatchPowerChannelStates(); + } + + //! Sends command to board through serial port. + bool + setPowerChannel(uint8_t channel, uint8_t value) + { + UCTK::Frame frame; + frame.setId(PKT_ID_SET_POWER); + frame.setPayloadSize(2); + frame.set(channel, 0); + frame.set(value, 1); + + return m_ctl->sendFrame(frame); + } + + //! Dispatches power channel states to IMC bus. + void + dispatchPowerChannelStates(void) + { + std::map::const_iterator itr = m_channels.begin(); + + for (; itr != m_channels.end(); ++itr) + { + dispatch(itr->second->state); + } + } + + bool + getMonitors(void) + { + UCTK::Frame frame; + frame.setId(PKT_ID_STATE); + + if (!m_ctl->sendFrame(frame)) + throw std::runtime_error(DTR("Failed to send frame to CPMB_v2. Check connection!")); + + if (frame.getPayloadSize() != (c_adcs_count*2+2)) + return false; + + // Converts measurements read (12-bit ADC) and dispatches them to IMC bus. + for (unsigned i = 0; i < c_adcs_count; ++i) + { + uint16_t value = 0; + frame.get(value, i*2); + + if (m_adcs[i] != NULL) + { + float tmp = m_args.adc_factors[i][0] * ((value / 4096.0) - m_args.adc_vdelta) + m_args.adc_factors[i][1]; + m_adcs[i]->setValueFP(tmp); + dispatch(m_adcs[i]); + } + } + + // Reads power channel states. + uint16_t power_state = 0; + frame.get(power_state, c_adcs_count*2); + std::map::const_iterator itr = m_channels.begin(); + for ( ; itr != m_channels.end(); ++itr) + { + unsigned id = itr->second->id; + itr->second->state.state = (power_state & (1 << id)) ? IMC::PowerChannelState::PCS_ON : IMC::PowerChannelState::PCS_OFF; + } + + return true; + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + getMonitors(); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Power/DOAMv1/Task.cpp b/src/Power/DOAMv1/Task.cpp index 2e64d863c0..155a6481c9 100644 --- a/src/Power/DOAMv1/Task.cpp +++ b/src/Power/DOAMv1/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Power/DOAMv2/Task.cpp b/src/Power/DOAMv2/Task.cpp index 9dbbc02358..85ba65e155 100644 --- a/src/Power/DOAMv2/Task.cpp +++ b/src/Power/DOAMv2/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Power/LUEMB/Task.cpp b/src/Power/LUEMB/Task.cpp index fac80ede3a..3d8a56c61b 100644 --- a/src/Power/LUEMB/Task.cpp +++ b/src/Power/LUEMB/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Power/MCBv2/MCP23017.hpp b/src/Power/MCBv2/MCP23017.hpp index 720155e0cc..805e707d12 100644 --- a/src/Power/MCBv2/MCP23017.hpp +++ b/src/Power/MCBv2/MCP23017.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Power/MCBv2/Task.cpp b/src/Power/MCBv2/Task.cpp index d1d20c54ae..fe2c123b9d 100644 --- a/src/Power/MCBv2/Task.cpp +++ b/src/Power/MCBv2/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Power/OPCON/Task.cpp b/src/Power/OPCON/Task.cpp index f50f5820a2..c4b0bdc086 100644 --- a/src/Power/OPCON/Task.cpp +++ b/src/Power/OPCON/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2016 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -28,7 +28,6 @@ // ISO C++ 98 headers. #include #include -#include // DUNE headers. #include diff --git a/src/Power/PCTLv2/PowerChannels.hpp b/src/Power/PCTLv2/PowerChannels.hpp index 85b92c9da6..1e8c3840ce 100644 --- a/src/Power/PCTLv2/PowerChannels.hpp +++ b/src/Power/PCTLv2/PowerChannels.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Power/PCTLv2/Task.cpp b/src/Power/PCTLv2/Task.cpp index af6567f168..0a2a4b02b2 100644 --- a/src/Power/PCTLv2/Task.cpp +++ b/src/Power/PCTLv2/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -695,6 +695,16 @@ namespace Power m_proto.sendCommand(CMD_PWR_CTL, data, sizeof(data)); waitForCommand(CMD_PWR_CTL); } + else if (msg->op == IMC::PowerChannelControl::PCC_OP_RESTART) + { + uint8_t data[] = {id, 0}; + m_proto.sendCommand(CMD_PWR_CTL, data, sizeof(data)); + waitForCommand(CMD_PWR_CTL); + + data[1] = 1; + m_proto.sendCommand(CMD_PWR_CTL, data, sizeof(data)); + waitForCommand(CMD_PWR_CTL); + } } void diff --git a/src/Power/PSIMAR/Task.cpp b/src/Power/PSIMAR/Task.cpp index 0a03d1573a..62f3ce7854 100644 --- a/src/Power/PSIMAR/Task.cpp +++ b/src/Power/PSIMAR/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/AIM104MultiIO/Driver.cpp b/src/Sensors/AIM104MultiIO/Driver.cpp index ebd8516fe1..7088a8f8d4 100644 --- a/src/Sensors/AIM104MultiIO/Driver.cpp +++ b/src/Sensors/AIM104MultiIO/Driver.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/AIM104MultiIO/Driver.hpp b/src/Sensors/AIM104MultiIO/Driver.hpp index 56e6e2b1b5..0f67cda90c 100644 --- a/src/Sensors/AIM104MultiIO/Driver.hpp +++ b/src/Sensors/AIM104MultiIO/Driver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/AIM104MultiIO/Task.cpp b/src/Sensors/AIM104MultiIO/Task.cpp index 73ea21856a..50273c4756 100644 --- a/src/Sensors/AIM104MultiIO/Task.cpp +++ b/src/Sensors/AIM104MultiIO/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/AIS/ShipTypeCode.cpp b/src/Sensors/AIS/ShipTypeCode.cpp index 33649517a2..50010cf658 100644 --- a/src/Sensors/AIS/ShipTypeCode.cpp +++ b/src/Sensors/AIS/ShipTypeCode.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/AIS/ShipTypeCode.def b/src/Sensors/AIS/ShipTypeCode.def index 16c3b479d1..477d94df77 100644 --- a/src/Sensors/AIS/ShipTypeCode.def +++ b/src/Sensors/AIS/ShipTypeCode.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/AIS/ShipTypeCode.hpp b/src/Sensors/AIS/ShipTypeCode.hpp index d1f2886ecc..c1b92e7f34 100644 --- a/src/Sensors/AIS/ShipTypeCode.hpp +++ b/src/Sensors/AIS/ShipTypeCode.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/AIS/Task.cpp b/src/Sensors/AIS/Task.cpp index 4855b8daf9..29d1ba24fa 100644 --- a/src/Sensors/AIS/Task.cpp +++ b/src/Sensors/AIS/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -63,13 +63,11 @@ namespace Sensors //! %Task arguments. struct Arguments { - //! Serial port device. - std::string uart_dev; - //! Serial port baud rate. - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; }; - struct Task: public DUNE::Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Serial port handle. IO::Handle* m_handle; @@ -83,59 +81,53 @@ namespace Sensors bool m_nmea5_wait_fg; //! Vehicle Type. std::map m_systems; + //! Buffer + std::vector m_bfr; Task(const std::string& name, Tasks::Context& ctx): - DUNE::Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_handle(NULL) { // Define configuration parameters. - param("Serial Port - Device", m_args.uart_dev) - .defaultValue("") - .description("Serial port device used to communicate with the sensor"); + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("38400") - .description("Serial port baud rate"); + param("IO Port - Device", m_args.io_dev) + .defaultValue("") + .description("IO device URI in the form \"tcp://ADDRESS:PORT\" " + "or \"uart://DEVICE:BAUD\""); + m_bfr.resize(c_read_buffer_size); m_nmea5_wait_fg = false; } - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { try { - if (!openSocket()) // Check if instead of serial is a tcp port - { - m_handle = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_handle->flush(); - } + m_handle = openDeviceHandle(m_args.io_dev); + return true; } catch (...) { throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } - } - - //! Check if we have a TCP socket as device input argument. - //! @return true if it is a TCP socket, false otherwise. - bool - openSocket(void) - { - char addr[128] = {0}; - unsigned port = 0; - - if (std::sscanf(m_args.uart_dev.c_str(), "tcp://%[^:]:%u", addr, &port) != 2) - return false; - TCPSocket* sock = new TCPSocket; - sock->connect(addr, port); - m_handle = sock; - return true; + return false; } + //! No initialization process. + void + onInitializeDevice() override + { } + + //! Disconnect from device. void - onResourceRelease(void) + onDisconnect() override { Memory::clear(m_handle); } @@ -196,7 +188,10 @@ namespace Sensors // We are able to send a message with ship information. IMC::RemoteSensorInfo rsi; - rsi.id = static_cast(&(std::ostringstream() << msg.mmsi))->str(); + std::ostringstream oss; + oss << msg.mmsi; + + rsi.id = static_cast(&oss)->str(); // Find ship type. std::map::iterator itr = m_systems.find(msg.mmsi); @@ -212,41 +207,37 @@ namespace Sensors } } - void - onMain(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { - std::vector bfr; - bfr.resize(c_read_buffer_size); + if (!Poll::poll(*m_handle, 1.0)) + return false; - while (!stopping()) + size_t rv = m_handle->read(&m_bfr[0], m_bfr.size()); + if (rv == 0) { - consumeMessages(); - - if (!Poll::poll(*m_handle, 1.0)) - continue; + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR("I/O error"), 5); + } - size_t rv = m_handle->read(&bfr[0], bfr.size()); - if (rv == 0) + for (size_t i = 0; i < rv; ++i) + { + // Detected line termination. + if (m_bfr[i] == c_line_term) { - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - throw RestartNeeded(DTR("I/O error"), 5); + process(m_line); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + m_line.clear(); } - - for (size_t i = 0; i < rv; ++i) + else { - // Detected line termination. - if (bfr[i] == c_line_term) - { - process(m_line); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); - m_line.clear(); - } - else - { - m_line.push_back(bfr[i]); - } + m_line.push_back(m_bfr[i]); } } + + return true; } }; } diff --git a/src/Sensors/CyclopsC7/Task.cpp b/src/Sensors/CyclopsC7/Task.cpp index 49e7b522ef..902509b16d 100644 --- a/src/Sensors/CyclopsC7/Task.cpp +++ b/src/Sensors/CyclopsC7/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/DMS/DriverDMS.hpp b/src/Sensors/DMS/DriverDMS.hpp new file mode 100644 index 0000000000..70478393c9 --- /dev/null +++ b/src/Sensors/DMS/DriverDMS.hpp @@ -0,0 +1,221 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Gonçalves * +//*************************************************************************** + +#ifndef SENSORS_DRIVER_DMS_HPP_INCLUDED_ +#define SENSORS_DRIVER_DMS_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include + +// Import namespaces. +using DUNE_NAMESPACES; + +#define ERRO1 "Wrong CSUM" +#define ERRO2 "Wrong Mode (E or D)" +#define ERRO3 "Wrong Sample Rate" +#define ERRO4 "Unrecognized Command" +#define ERRO5 "Error Setting Sample Rate(Stop Readings of ADC first)" + +namespace Sensors +{ + namespace DMS + { + //! Message Parser for DMS. + //! + //! @author Pedro Gonçalves + class DriverDMS + { + public: + struct DMSState + { + //! Value read from adc + long int value; + //! ADC Channel + int channel; + }; + + //! State machine. + enum DMSParserStates + { + //! Read preamble + PS_PREAMBLE, + //! Data received + PS_DATA, + //! Read checksum + PS_CS + }; + + DriverDMS(void): + m_dms_state(DriverDMS::PS_PREAMBLE) + { } + + ~DriverDMS(void) + { } + + //! Parse message received + bool + parse(uint8_t byte) + { + switch (m_dms_state) + { + case PS_PREAMBLE: + if (byte == c_preamble) + { + m_csum = byte; + m_dms_state = PS_DATA; + m_cnt = 0; + std::memset(&m_bfr, '0', sizeof(m_bfr)); + } + break; + + case PS_DATA: + if (byte != c_terminator) + { + m_bfr[m_cnt++] = byte; + m_csum ^= byte; + } + else + m_dms_state = PS_CS; + break; + + case PS_CS: + m_dms_state = PS_PREAMBLE; + + if (m_csum == byte) + return true; + break; + + default: + m_dms_state = PS_PREAMBLE; + break; + } + + return false; + } + + //! Filter data received of DMS board + bool + translate(void) + { + if (m_bfr[1] == ',' || m_bfr[2] == ',') + { + std::sscanf(m_bfr, "%d,%ld,*", &m_dms.channel, &m_dms.value); + std::memset(&m_bfr, '\0', sizeof(m_bfr)); + return true; + } + return false; + } + + std::string + translate_feadback(void) + { + //! Feadback message + char feadback_msg[16]; + if (m_bfr[1] != ',') + { + std::sscanf(m_bfr, "%s ,*", feadback_msg); + std::memset(&m_bfr, '\0', sizeof(m_bfr)); + + if(std::strcmp(feadback_msg, "ERRO,1") == 0) + return ERRO1; + else if(std::strcmp(feadback_msg, "ERRO,2") == 0) + return ERRO2; + else if(std::strcmp(feadback_msg, "ERRO,3") == 0) + return ERRO3; + else if(std::strcmp(feadback_msg, "ERRO,4") == 0) + return ERRO4; + else if(std::strcmp(feadback_msg, "ERRO,5") == 0) + return ERRO5; + else if(std::strcmp(feadback_msg, "OK") == 0) + return feadback_msg; + } + + return ""; + } + + //! Enable Output data of DMS + char* + enable_output(void) + { + std::memset(&m_send_bfr, '\0', sizeof(m_send_bfr)); + std::sprintf(m_send_bfr, "#0,E,*"); + std::sprintf(m_send_bfr, "#0,E,*%c\r\n", Algorithms::XORChecksum::compute((uint8_t*)m_send_bfr, strlen(m_send_bfr) - 1)); + + return m_send_bfr; + } + + //! Disable Output data of DMS + char* + disable_output(void) + { + std::memset(&m_send_bfr, '\0', sizeof(m_send_bfr)); + std::sprintf(m_send_bfr, "#0,D,*"); + std::sprintf(m_send_bfr, "#0,D,*%c\r\n", Algorithms::XORChecksum::compute((uint8_t*)m_send_bfr, strlen(m_send_bfr) - 1)); + + return m_send_bfr; + } + + //! Set number of channels/second + char* + set_sample_ps(int value) + { + std::memset(&m_send_bfr, '\0', sizeof(m_send_bfr)); + std::sprintf(m_send_bfr, "#1,F,%d,*", value); + std::sprintf(m_send_bfr, "#1,F,%d,*%c\r\n", value, Algorithms::XORChecksum::compute((uint8_t*)m_send_bfr, strlen(m_send_bfr) - 1)); + + return m_send_bfr; + } + + //! DMS state. + DMSState m_dms; + + private: + //! State machine. + DMSParserStates m_dms_state; + //! Checksum. + uint8_t m_csum; + //! Position in buffer. + uint8_t m_cnt; + //! Received buffer. + char m_bfr[16]; + //! Received buffer. + char m_send_bfr[32]; + //! Frame preamble. + static const uint8_t c_preamble = '$'; + //! Frame terminator. + static const uint8_t c_terminator = '*'; + }; + } +} + +#endif diff --git a/src/Sensors/DMS/Task.cmake b/src/Sensors/DMS/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Sensors/DMS/Task.cpp b/src/Sensors/DMS/Task.cpp new file mode 100644 index 0000000000..f52a1a4a22 --- /dev/null +++ b/src/Sensors/DMS/Task.cpp @@ -0,0 +1,443 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Gonçalves * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include + +// Local Headers. +#include + +namespace Sensors +{ + namespace DMS + { + using DUNE_NAMESPACES; + + static const unsigned int c_max_adc = 16; + static const unsigned int c_max_buffer = 32; + static const float c_adc_resolution = 32768.0f; + static const float c_adc_scalor_factor = 6.144f; + static const float c_timeout_connection_sadc = 5.0f; + + struct Arguments + { + //! Serial port device. + std::string uart_dev; + //! Serial port baud rate. + unsigned uart_baud; + //! Serial Port timeOut for reading + float timeout_uart; + //! ADC entity label + std::string adc_label; + //! Number of channels of adc + int number_adc; + //! Baseline of channels + float channel_baseline[c_max_adc]; + //! Scale factor for positive detection + float baseline_scale; + //! Number of channels to read/s + int sample_rate; + }; + + struct Task: public DUNE::Tasks::Task + { + //! Voltage message + IMC::Voltage m_volt[c_max_adc]; + //! DMS Detection message + IMC::DmsDetection m_dms_detection[c_max_adc]; + //! Task arguments. + Arguments m_args; + //! Serial port device. + SerialPort* m_uart; + //! I/O Multiplexer. + Poll m_poll; + //! Read timestamp. + double m_tstamp; + //! Parser for message + DriverDMS* m_driver; + //! Scratch buffer. + uint8_t m_buffer[c_max_buffer]; + //! Flag to check correct configuration of DMS + bool m_is_correct_conf; + //! Buffer for DMS readings + float m_dms_readings[c_max_adc]; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL), + m_tstamp(0), + m_driver(NULL), + m_is_correct_conf(0) + { + param("Serial Port - Device", m_args.uart_dev) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("") + .description("Serial port device used to communicate with the sensor"); + + param("Serial Port - Baud Rate", m_args.uart_baud) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("57600") + .description("Serial port baud rate"); + + param("Serial Port - TimeOut", m_args.timeout_uart) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("2.0") + .minimumValue("1.0") + .maximumValue("5.0") + .description("Serial Port timeOut for reading."); + + param("ADC Reads - Entity Label", m_args.adc_label) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .description("Label for ADC labels."); + + param("ADC Channels", m_args.number_adc) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("16") + .minimumValue("1") + .maximumValue("16") + .description("Number of Channels of ADC."); + + for(uint8_t i = 1; i <= c_max_adc; i++) + { + std::string option = String::str("DMS CH%u Baseline", i); + param(option, m_args.channel_baseline[i-1]) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .minimumValue("0") + .maximumValue("4.99") + .description("Baseline of channel."); + } + + param("Scale Factor Positive", m_args.baseline_scale) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("3") + .minimumValue("1") + .maximumValue("10") + .description("Scale Factor for Positive Detection."); + + param("Number Samples per s", m_args.sample_rate) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("4") + .minimumValue("1") + .maximumValue("16") + .description("Number of channels to read/s."); + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + unsigned eid = 0; + + for (unsigned i = 1; i <= c_max_adc; ++i) + { + if (m_args.adc_label.empty()) + continue; + + try + { + eid = resolveEntity(m_args.adc_label + " CH"+ NumberToString(i)); + } + catch (Entities::EntityDataBase::NonexistentLabel& e) + { + (void)e; + eid = reserveEntity(m_args.adc_label + " CH"+ NumberToString(i)); + } + + m_volt[i-1].setSourceEntity(eid); + } + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + try + { + m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); + } + catch (std::runtime_error& e) + { + throw RestartNeeded(e.what(), 15); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVATING); + + for(uint8_t i = 0; i < c_max_adc; i++) + m_dms_readings[i] = -1.0; + + m_is_correct_conf = true; + m_driver = new DriverDMS(); + m_poll.add(*m_uart); + if(checkConnectionDMS(c_timeout_connection_sadc)) + { + configDMS(); + Delay::waitMsec(1000); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + else + { + throw RestartNeeded("Cannot connect to board", 10); + } + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_uart != NULL) + { + m_uart->write(m_driver->disable_output(), strlen(m_driver->disable_output())); + + m_poll.remove(*m_uart); + delete m_uart; + m_uart = NULL; + + Memory::clear(m_driver); + } + } + + //! Config board DMS + void + configDMS(void) + { + m_uart->write(m_driver->disable_output(), strlen(m_driver->disable_output())); + processFeedback(); + m_uart->write(m_driver->set_sample_ps(m_args.sample_rate), strlen(m_driver->set_sample_ps(m_args.sample_rate))); + processFeedback(); + + if(m_is_correct_conf) + { + inf(DTR("Requesting DMS readings")); + m_uart->write(m_driver->enable_output(), strlen(m_driver->enable_output())); + processFeedback(); + } + else + { + err(DTR("Board DMS not operational")); + } + } + + //! Check connection to dms board + bool + checkConnectionDMS(float c_timeout) + { + bool is_connect = false; + for(int i = 0; i < (int)(c_timeout/0.2); i++) + { + m_uart->write(m_driver->disable_output(), strlen(m_driver->disable_output())); + is_connect = processInput(0.2, false); + if(is_connect) + break; + } + return is_connect; + } + + //! Check feadback of commands + void + processFeedback(void) + { + if(!processInput(m_args.timeout_uart, false)) + m_is_correct_conf = false; + } + + //! Read data send by DMS board. + bool + checkSerialPort(void) + { + if (m_poll.wasTriggered(*m_uart)) + { + std::memset(&m_buffer, '0', sizeof(m_buffer)); + int rv = 0; + + try + { + rv = m_uart->read(m_buffer, sizeof(m_buffer)); + m_tstamp = Clock::getSinceEpoch(); + } + catch (std::exception& e) + { + err(DTR("read error: %s"), e.what()); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + return false; + } + + if (rv <= 0) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR("unknown read error"), 15); + } + else + { + for (uint8_t i = 0; i < rv; ++i) + { + if (!m_driver->parse(m_buffer[i])) + continue; + + return true; + } + } + } + + return false; + } + + bool + processInput(double timeout, bool isData) + { + bool result = false; + double deadline = Clock::get() + timeout; + + while (Clock::get() <= deadline) + { + if (m_poll.poll(0.01)) + { + if (checkSerialPort()) + { + if(isData) + { + if(m_driver->translate()) + { + debug("Channel %d -> %ld", m_driver->m_dms.channel, m_driver->m_dms.value); + m_volt[m_driver->m_dms.channel - 1].setTimeStamp(m_tstamp); + m_volt[m_driver->m_dms.channel - 1].setDestination(getSystemId()); + m_volt[m_driver->m_dms.channel - 1].value = (m_driver->m_dms.value * c_adc_scalor_factor) / c_adc_resolution; + dispatch(m_volt[m_driver->m_dms.channel - 1], DF_KEEP_TIME); + processValueOfDMSChannel(m_driver->m_dms.channel, (m_driver->m_dms.value * c_adc_scalor_factor) / c_adc_resolution); + result = true; + break; + } + } + else + { + std::string feedback_text = m_driver->translate_feadback(); + if(feedback_text.compare("OK") == 0) + { + debug("%s",feedback_text.c_str()); + result = true; + break; + } + else + { + err("%s",feedback_text.c_str()); + result = false; + break; + } + } + } + } + } + + return result; + } + + void + processValueOfDMSChannel(int channel, float value) + { + float real_value = value - m_args.channel_baseline[channel-1]; + float valueAdc = real_value - (m_args.baseline_scale * m_args.channel_baseline[channel-1]); + m_dms_readings[channel-1] = valueAdc; + debug("DMS Sample - CH%d | R: %0.3f | V: %0.3f | S: %0.3f", channel, real_value, valueAdc, m_args.baseline_scale); + + if(channel == 16) + { + m_dms_detection->setTimeStamp(m_tstamp); + m_dms_detection->setDestination(getSystemId()); + m_dms_detection->ch01 = m_dms_readings[0]; + m_dms_detection->ch02 = m_dms_readings[1]; + m_dms_detection->ch03 = m_dms_readings[2]; + m_dms_detection->ch04 = m_dms_readings[3]; + m_dms_detection->ch05 = m_dms_readings[4]; + m_dms_detection->ch06 = m_dms_readings[5]; + m_dms_detection->ch07 = m_dms_readings[6]; + m_dms_detection->ch08 = m_dms_readings[7]; + m_dms_detection->ch09 = m_dms_readings[8]; + m_dms_detection->ch10 = m_dms_readings[9]; + m_dms_detection->ch11 = m_dms_readings[10]; + m_dms_detection->ch12 = m_dms_readings[11]; + m_dms_detection->ch13 = m_dms_readings[12]; + m_dms_detection->ch14 = m_dms_readings[13]; + m_dms_detection->ch15 = m_dms_readings[14]; + m_dms_detection->ch16 = m_dms_readings[15]; + dispatch(m_dms_detection, DF_KEEP_TIME); + } + } + + bool + checkDataDMS(void) + { + bool checkEnd = processInput(m_args.timeout_uart, true); + m_uart->flush(); + return checkEnd; + } + + template + std::string NumberToString ( T Number ) + { + std::stringstream ss; + ss << Number; + return ss.str(); + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + if(m_is_correct_conf) + { + consumeMessages(); + + if(checkDataDMS()) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + else + { + waitForMessages(1.0); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + } + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Sensors/DataStore/Task.cmake b/src/Sensors/DataStore/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Sensors/DataStore/Task.cpp b/src/Sensors/DataStore/Task.cpp new file mode 100644 index 0000000000..4d03c15b04 --- /dev/null +++ b/src/Sensors/DataStore/Task.cpp @@ -0,0 +1,289 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: José Pinto * +//*************************************************************************** + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include + +namespace Sensors +{ + namespace DataStore + { + using DUNE_NAMESPACES; + + struct Arguments + { + fp32_t ctd_period; + fp32_t telemetry_period; + fp32_t sss_period; + bool log_events; + std::string ctd_label; + }; + + struct Task: public DUNE::Tasks::Task + { + Arguments m_args; + + IMC::EstimatedState m_state; + IMC::HistoricCTD m_ctd; + IMC::HistoricSonarData m_sonar; + Time::Counter m_ctd_counter; + Time::Counter m_sss_counter; + Time::Counter m_tel_counter; + int m_ctd_entity; + bool m_got_ctd; + + Task(const std::string& name, Tasks::Context& ctx) : + DUNE::Tasks::Task(name, ctx), + m_ctd_entity(-1), + m_got_ctd(false) + { + param("CTD Sample Period", m_args.ctd_period) + .defaultValue("-1") + .description("Time, in seconds, between CTD samples. Values lower than 0 will disable these samples.") + .scope(Parameter::SCOPE_GLOBAL); + + param("CTD Entity Name", m_args.ctd_label) + .defaultValue("CTD") + .description("Entity to use for getting temperature and conductivity."); + + param("Telemetry Sample Period", m_args.telemetry_period) + .defaultValue("-1") + .description("Time, in seconds, between telemetry samples. Values lower than 0 will disable these samples.") + .scope(Parameter::SCOPE_GLOBAL); + + param("Sonar Sample Period", m_args.sss_period) + .defaultValue("-1") + .description("Time, in seconds, between sidescan sonar samples. Values lower than 0 will disable these samples.") + .scope(Parameter::SCOPE_GLOBAL); + + param("Log Events", m_args.log_events) + .defaultValue("false") + .description("Whether to log historic events") + .scope(Parameter::SCOPE_GLOBAL); + + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + } + + void + onUpdateParameters(void) + { + m_ctd_counter.setTop(m_args.ctd_period); + m_tel_counter.setTop(m_args.telemetry_period); + m_sss_counter.setTop(m_args.sss_period); + + bool active = false; + if (m_args.ctd_period > 0) + active = true; + if (m_args.telemetry_period > 0) + active = true; + if (m_args.sss_period > 0) + active = true; + if (m_args.log_events) + active = true; + + if (active) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + else + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + + void + onEntityResolution(void) + { + try + { + m_ctd_entity = m_ctx.entities.resolve(m_args.ctd_label); + } + catch (std::exception& what) + { + war("Error resolving CTD entity"); + m_ctd_entity = -1; + } + } + + //! On resource initialization + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + + void + consume(const IMC::EstimatedState* msg) + { + m_state = *msg; + } + + void + consume(const IMC::Temperature* msg) + { + if (msg->getSourceEntity() != m_ctd_entity) + return; + + m_ctd.temperature = msg->value; + m_got_ctd = true; + } + + void + consume(const IMC::Conductivity* msg) + { + if (msg->getSourceEntity() != m_ctd_entity) + return; + + m_ctd.conductivity = msg->value; + m_got_ctd = true; + } + + void + consume(const IMC::LogBookEntry* msg) + { + if (!m_args.log_events) + return; + + if (msg->type == IMC::LogBookEntry::LBET_ERROR + || msg->type == IMC::LogBookEntry::LBET_CRITICAL) + { + IMC::HistoricEvent event; + event.text = msg->text; + event.type = IMC::HistoricEvent::EVTYPE_ERROR; + dispatch(event); + } + } + + void + consume(const IMC::PlanControl* msg) + { + if (!m_args.log_events) + return; + + IMC::HistoricEvent event; + event.type = IMC::HistoricEvent::EVTYPE_INFO; + std::string srcname = m_ctx.resolver.resolve(msg->getSource()); + + if (msg->type == IMC::PlanControl::PC_REQUEST + && msg->op == IMC::PlanControl::PC_START) + { + event.text = Utils::String::str("Request to start plan '%s' issued by '%s'.", + msg->plan_id.c_str(), srcname.c_str()); + } + else if (msg->type == IMC::PlanControl::PC_REQUEST + && msg->op == IMC::PlanControl::PC_STOP) + { + event.text = Utils::String::str("Request to stop plan '%s' issued by '%s'.", + msg->plan_id.c_str(), srcname.c_str()); + } + else if (msg->type == IMC::PlanControl::PC_SUCCESS + && msg->op == IMC::PlanControl::PC_START) + { + event.text = Utils::String::str("Successfully finished executing plan '%s'.", + msg->plan_id.c_str()); + } + else if (msg->type == IMC::PlanControl::PC_FAILURE + && msg->op == IMC::PlanControl::PC_START) + { + event.text = Utils::String::str("Execution of plan '%s' was interrupted.", + msg->plan_id.c_str()); + } + + dispatch(event); + } + + void + consume(const IMC::SonarData* msg) + { + if (m_args.sss_period < 0) + return; + + // TODO + (void)msg; + } + + void + sendHistoricMessages() + { + if (m_args.ctd_period > 0 && m_got_ctd && m_ctd_counter.overflow()) + { + m_ctd.depth = m_state.depth; + debug("Generated new HistoricCTD."); + dispatch(m_ctd); + m_ctd_counter.reset(); + m_got_ctd = false; + } + + if (m_args.telemetry_period > 0 && m_tel_counter.overflow()) + { + IMC::HistoricTelemetry msg; + msg.altitude = m_state.alt; + msg.speed = Math::norm(m_state.u, m_state.v) * 10; + double attitude[3]; + attitude[0] = Angles::normalizeRadian(m_state.phi); + attitude[1] = Angles::normalizeRadian(m_state.theta); + attitude[2] = Angles::normalizeRadian(m_state.psi); + for (int i = 0; i < 3; i++) + { + if (attitude[i] < 0) + attitude[i] += (Math::c_pi * 2); + attitude[i] *= (0xFFFF / (Math::c_pi * 2)); + } + msg.roll = attitude[0]; + msg.pitch = attitude[1]; + msg.yaw = attitude[2]; + debug("Generated new HistoricTelemetry."); + dispatch(msg); + + m_tel_counter.reset(); + } + + if (m_args.sss_period > 0 && m_sss_counter.overflow()) + { + // TODO + m_sss_counter.reset(); + } + } + + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + sendHistoricMessages(); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Sensors/Edgetech2205/CommandLink.hpp b/src/Sensors/Edgetech2205/CommandLink.hpp index 3b1d162e69..dc5176eaee 100644 --- a/src/Sensors/Edgetech2205/CommandLink.hpp +++ b/src/Sensors/Edgetech2205/CommandLink.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/Constants.hpp b/src/Sensors/Edgetech2205/Constants.hpp index b0eeac2b44..f9bc741c6a 100644 --- a/src/Sensors/Edgetech2205/Constants.hpp +++ b/src/Sensors/Edgetech2205/Constants.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/EstimatedStateEntry.hpp b/src/Sensors/Edgetech2205/EstimatedStateEntry.hpp index 98003cee6f..cf67b18d67 100644 --- a/src/Sensors/Edgetech2205/EstimatedStateEntry.hpp +++ b/src/Sensors/Edgetech2205/EstimatedStateEntry.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/EstimatedStateList.hpp b/src/Sensors/Edgetech2205/EstimatedStateList.hpp index 5f8cbc06c7..e550b559e6 100644 --- a/src/Sensors/Edgetech2205/EstimatedStateList.hpp +++ b/src/Sensors/Edgetech2205/EstimatedStateList.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/Log.hpp b/src/Sensors/Edgetech2205/Log.hpp index 4dbd830e97..cb0b342ee3 100644 --- a/src/Sensors/Edgetech2205/Log.hpp +++ b/src/Sensors/Edgetech2205/Log.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/Packet.hpp b/src/Sensors/Edgetech2205/Packet.hpp index 1fe2641e36..c3a282bcea 100644 --- a/src/Sensors/Edgetech2205/Packet.hpp +++ b/src/Sensors/Edgetech2205/Packet.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/Parser.hpp b/src/Sensors/Edgetech2205/Parser.hpp index 14c85e0c58..9680a49678 100644 --- a/src/Sensors/Edgetech2205/Parser.hpp +++ b/src/Sensors/Edgetech2205/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/SubsystemData.hpp b/src/Sensors/Edgetech2205/SubsystemData.hpp index fbfdbc6335..02b68a9f27 100644 --- a/src/Sensors/Edgetech2205/SubsystemData.hpp +++ b/src/Sensors/Edgetech2205/SubsystemData.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Edgetech2205/Task.cpp b/src/Sensors/Edgetech2205/Task.cpp index 9d399254fd..76283216ca 100644 --- a/src/Sensors/Edgetech2205/Task.cpp +++ b/src/Sensors/Edgetech2205/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -46,41 +46,6 @@ namespace Sensors { using DUNE_NAMESPACES; - //! Finite state machine states. - enum StateMachineStates - { - //! Waiting for activation. - SM_IDLE, - //! Start activation sequence. - SM_ACT_BEGIN, - //! Turn power on. - SM_ACT_POWER_ON, - //! Wait for power to be turned on. - SM_ACT_POWER_WAIT, - //! Wait for device to become available. - SM_ACT_SS_WAIT, - //! Synchronize time. - SM_ACT_SS_SYNC, - //! Request log file. - SM_ACT_LOG_REQUEST, - //! Wait for log file. - SM_ACT_LOG_WAIT, - //! Activation sequence is complete. - SM_ACT_DONE, - //! Sampling. - SM_ACT_SAMPLE, - //! Start deactivation sequence. - SM_DEACT_BEGIN, - //! Disconnect from sidescan. - SM_DEACT_DISCONNECT, - //! Switch power off. - SM_DEACT_POWER_OFF, - //! Wait for power to be turned off. - SM_DEACT_POWER_WAIT, - //! Deactivation sequence is complete. - SM_DEACT_DONE - }; - //! Task arguments. struct Arguments { @@ -116,7 +81,7 @@ namespace Sensors unsigned time_delta_init_samples; }; - struct Task: public Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Buffer size. static const unsigned c_buffer_size = 256 * 1024; @@ -130,30 +95,22 @@ namespace Sensors CommandLink* m_cmd; //! Log file. Log* m_log; - //! Watchdog timer. - Counter m_wdog; + //! Start timer. + Counter m_start_timer; //! Timer for time delta estimation. Counter m_time_delta_timer; //! Subsystem specific data. SubsystemData m_subsys_data[c_subsys_count]; - //! Current state machine state. - StateMachineStates m_sm_state; - //! State machine state queue. - std::queue m_sm_state_queue; - //! True if device is powered on. - bool m_powered; //! Current packet being parsed. Packet* m_packet; //! Configuration parameters. Arguments m_args; Task(const std::string& name, Tasks::Context& ctx): - Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_sock_dat(NULL), m_cmd(NULL), m_log(NULL), - m_sm_state(SM_IDLE), - m_powered(false), m_packet(NULL) { // Define configuration parameters. @@ -262,8 +219,11 @@ namespace Sensors void onUpdateParameters(void) { - if (m_args.power_channel.empty()) - m_powered = true; + if (paramChanged(m_args.power_channel)) + { + clearPowerChannelNames(); + addPowerChannelName(m_args.power_channel); + } if (!isActive()) return; @@ -305,61 +265,16 @@ namespace Sensors } void - onResourceRelease(void) - { - closeLog(); - } - - void - onResourceInitialization(void) - { - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - } - - //! Push a new state to the state queue. - //! @param[in] state state machine state. - void - queueState(StateMachineStates state) - { - m_sm_state_queue.push(state); - } - - //! Test if state queue has pending state transitions. - //! @return true if state queue has pending states, false otherwise. - bool - hasQueuedStates(void) const - { - return !m_sm_state_queue.empty(); - } - - StateMachineStates - getCurrentState(void) const - { - return m_sm_state; - } - - StateMachineStates - dequeueState(void) - { - if (hasQueuedStates()) - { - m_sm_state = m_sm_state_queue.front(); - m_sm_state_queue.pop(); - } - - return m_sm_state; - } - - void - onRequestActivation(void) + onIdle(void) override { - queueState(SM_ACT_BEGIN); + m_start_timer.setTop(getActivationTime()); } + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. bool - connect(void) + onConnect() override { - Counter timer(1.0); try { m_cmd = new CommandLink(this, m_args.addr, m_args.port_cmd); @@ -368,30 +283,15 @@ namespace Sensors } catch (...) { - double delay = timer.getRemaining(); - if (delay > 0.0) - Delay::wait(delay); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } return false; } + //! Disconnect from device. void - failActivation(const std::string& message) - { - activationFailed(message); - controlPower(IMC::PowerChannelControl::PCC_OP_TURN_OFF); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - } - - void - onRequestDeactivation(void) - { - queueState(SM_DEACT_BEGIN); - } - - void - disconnect(void) + onDisconnect() override { debug("disconnecting"); setDataActive(SUBSYS_SSL, "None"); @@ -404,17 +304,20 @@ namespace Sensors debug("disconnected"); } - void - onDeactivation(void) + //! Synchronize with device. + bool + onSynchronize() override { - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - debug("deactivation complete"); + estimateTimeDelta(m_start_timer); + + return true; } + //! Device may be initialized. void - onActivation(void) + onInitializeDevice() override { - debug("activation took %0.2f s", m_wdog.getElapsed()); + m_time_delta_timer.setTop(5.0); for (size_t i = 0; i < c_subsys_count; ++i) m_subsys_data[i].clear(); @@ -430,66 +333,58 @@ namespace Sensors m_cmd->setPingTrigger(SUBSYS_SSL, TRIG_MODE_INTERNAL); initConfig(); - - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); } - void - requestLogName(void) + //! Enable log control. + bool + enableLogControl(void) override { - debug("requesting current log path"); - IMC::LoggingControl lc; - lc.op = IMC::LoggingControl::COP_REQUEST_CURRENT_NAME; - dispatch(lc); + return true; } void - consume(const IMC::PowerChannelState* msg) + onOpenLog(const Path& path) override { - if (msg->name != m_args.power_channel) - return; + BasicDeviceDriver::onOpenLog(path); - bool old_state = m_powered; - m_powered = (msg->state == IMC::PowerChannelState::PCS_ON); - if (!old_state && m_powered) - debug("device is powered"); - else if (old_state && !m_powered) - debug("device is no longer powered"); + m_log = new Log(this, m_ctx.dir_log / path / "Data.jsf"); + m_log->start(); + m_packet = m_log->get(); + debug("opened: %s", path.c_str()); } void - consume(const IMC::EstimatedState* msg) + logPacket(void) { - if (msg->getSource() != getSystemId()) - return; - - if (!isActive()) - return; - - for (size_t i = 0; i < c_subsys_count; ++i) + if (m_log != NULL) { - if (m_subsys_data[i].active) - m_subsys_data[i].estates.push_back(*msg); + m_log->put(m_packet); + m_packet = m_log->get(); } } void - consume(const IMC::LoggingControl* msg) + onCloseLog(void) override { - if (msg->getSource() != getSystemId()) + BasicDeviceDriver::onCloseLog(); + + if (m_log == NULL) return; - switch (msg->op) + m_log->stopAndJoin(); + debug("closed: %s", m_log->getPath().c_str()); + + Memory::clear(m_packet); + Memory::clear(m_log); + } + + void + onEstimatedState(const IMC::EstimatedState& msg) override + { + for (size_t i = 0; i < c_subsys_count; ++i) { - case IMC::LoggingControl::COP_STARTED: - case IMC::LoggingControl::COP_CURRENT_NAME: - if (getCurrentState() == SM_ACT_LOG_WAIT || getCurrentState() == SM_ACT_SAMPLE) - openLog(m_ctx.dir_log / msg->name / "Data.jsf"); - break; - - case IMC::LoggingControl::COP_STOPPED: - closeLog(); - break; + if (m_subsys_data[i].active) + m_subsys_data[i].estates.push_back(msg); } } @@ -774,9 +669,16 @@ namespace Sensors handleSonarData(); } + // Read samples and continuously estimate time difference. bool - readData(void) + onReadData(void) override { + if (m_time_delta_timer.overflow()) + { + m_time_delta_timer.reset(); + m_cmd->estimateTimeDelta(m_args.time_delta_max_latency); + } + if (!Poll::poll(*m_sock_dat, 1.0)) return false; @@ -824,229 +726,6 @@ namespace Sensors debug("time is not synchronized"); } - - void - openLog(const Path& path) - { - if (!isActive() && !isActivating()) - return; - - if (m_log != NULL) - { - if (m_log->getPath() == path) - return; - } - - closeLog(); - - m_log = new Log(this, path); - m_log->start(); - m_packet = m_log->get(); - debug("opened: %s", path.c_str()); - } - - void - logPacket(void) - { - if (m_log != NULL) - { - m_log->put(m_packet); - m_packet = m_log->get(); - } - } - - void - closeLog(void) - { - if (m_log == NULL) - return; - - m_log->stopAndJoin(); - debug("closed: %s", m_log->getPath().c_str()); - - Memory::clear(m_packet); - Memory::clear(m_log); - } - - void - controlPower(IMC::PowerChannelControl::OperationEnum op) - { - if (m_args.power_channel.empty()) - return; - - IMC::PowerChannelControl pcc; - pcc.op = op; - pcc.name = m_args.power_channel; - dispatch(pcc); - } - - void - turnPowerOn(void) - { - trace("turning power on"); - controlPower(IMC::PowerChannelControl::PCC_OP_TURN_ON); - } - - void - turnPowerOff(void) - { - trace("turning power off"); - controlPower(IMC::PowerChannelControl::PCC_OP_TURN_OFF); - } - - //! Test if power channel is on. - //! @return true if power channel is on, false otherwise. - bool - isPowered(void) - { - return m_powered; - } - - void - updateStateMachine(void) - { - switch (dequeueState()) - { - // Wait for activation. - case SM_IDLE: - break; - - // Begin activation sequence. - case SM_ACT_BEGIN: - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVATING); - m_wdog.setTop(getActivationTime()); - queueState(SM_ACT_POWER_ON); - break; - - // Turn power on. - case SM_ACT_POWER_ON: - turnPowerOn(); - queueState(SM_ACT_POWER_WAIT); - break; - - // Wait for power to be on. - case SM_ACT_POWER_WAIT: - if (isPowered()) - { - queueState(SM_ACT_SS_WAIT); - } - - if (m_wdog.overflow()) - { - failActivation(DTR("failed to turn power on")); - queueState(SM_IDLE); - } - break; - - // Connect to sidescan. - case SM_ACT_SS_WAIT: - if (m_wdog.overflow()) - { - failActivation(DTR("failed to connect to device")); - queueState(SM_IDLE); - } - else if (connect()) - { - queueState(SM_ACT_SS_SYNC); - } - break; - - // Synchronize time. - case SM_ACT_SS_SYNC: - estimateTimeDelta(m_wdog); - queueState(SM_ACT_LOG_REQUEST); - break; - - // Request log name. - case SM_ACT_LOG_REQUEST: - closeLog(); - requestLogName(); - queueState(SM_ACT_LOG_WAIT); - break; - - // Wait for log name. - case SM_ACT_LOG_WAIT: - if (m_log != NULL) - queueState(SM_ACT_DONE); - break; - - // Activation procedure is complete. - case SM_ACT_DONE: - m_time_delta_timer.setTop(5.0); - queueState(SM_ACT_SAMPLE); - activate(); - break; - - // Read samples and continuously estimate time difference. - case SM_ACT_SAMPLE: - if (m_time_delta_timer.overflow()) - { - m_time_delta_timer.reset(); - m_cmd->estimateTimeDelta(m_args.time_delta_max_latency); - } - - readData(); - break; - - // Start deactivation procedure. - case SM_DEACT_BEGIN: - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_DEACTIVATING); - m_wdog.setTop(getDeactivationTime()); - queueState(SM_DEACT_DISCONNECT); - break; - - // Disconnect and shutdown sidescan. - case SM_DEACT_DISCONNECT: - disconnect(); - closeLog(); - queueState(SM_DEACT_POWER_OFF); - break; - - // Turn power off. - case SM_DEACT_POWER_OFF: - if (m_wdog.overflow()) - { - turnPowerOff(); - queueState(SM_DEACT_POWER_WAIT); - } - break; - - // Wait for power to be turned off. - case SM_DEACT_POWER_WAIT: - if (!isPowered()) - queueState(SM_DEACT_DONE); - break; - - // Deactivation is complete. - case SM_DEACT_DONE: - deactivate(); - queueState(SM_IDLE); - break; - } - } - - void - onMain(void) - { - while (!stopping()) - { - if (isActive()) - consumeMessages(); - else if (hasQueuedStates()) - updateStateMachine(); - else - waitForMessages(1.0); - - try - { - updateStateMachine(); - } - catch (std::runtime_error& e) - { - throw RestartNeeded(e.what(), 5); - } - } - } }; } } diff --git a/src/Sensors/EmulatedGPS/Task.cpp b/src/Sensors/EmulatedGPS/Task.cpp index 024de5c58d..6391e49e0b 100644 --- a/src/Sensors/EmulatedGPS/Task.cpp +++ b/src/Sensors/EmulatedGPS/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/GPS/Reader.hpp b/src/Sensors/GPS/Reader.hpp index 719b0f3b30..27512abb7f 100644 --- a/src/Sensors/GPS/Reader.hpp +++ b/src/Sensors/GPS/Reader.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/GPS/Task.cpp b/src/Sensors/GPS/Task.cpp index 927a76e433..a03a8d3041 100644 --- a/src/Sensors/GPS/Task.cpp +++ b/src/Sensors/GPS/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -25,12 +25,13 @@ // http://ec.europa.eu/idabc/eupl.html. * //*************************************************************************** // Author: Ricardo Martins * +// Author: Luis Venancio (BasicDeviceDriver compatibility) * //*************************************************************************** // ISO C++ 98 headers. -#include #include #include +#include // DUNE headers. #include @@ -70,10 +71,8 @@ namespace Sensors struct Arguments { - //! Serial port device. - std::string uart_dev; - //! Serial port baud rate. - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; //! Order of sentences. std::vector stn_order; //! Input timeout in seconds. @@ -84,9 +83,13 @@ namespace Sensors std::string init_rpls[c_max_init_cmds]; //! Power channels. std::vector pwr_channels; + //! Power on delay + double post_pwr_on_delay; + //! Enable novatel sbas mode. + bool novatelSbas; }; - struct Task: public Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Serial port handle. IO::Handle* m_handle; @@ -108,22 +111,24 @@ namespace Sensors std::string m_init_line; //! Reader thread. Reader* m_reader; + //! Buffer forEntityState + char m_bufer_entity[64]; Task(const std::string& name, Tasks::Context& ctx): - Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_handle(NULL), m_has_agvel(false), m_has_euler(false), m_reader(NULL) { // Define configuration parameters. - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); - - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("4800") - .description("Serial port baud rate"); + .description("IO device URI in the form \"uart://DEVICE:BAUD\""); param("Input Timeout", m_args.inp_tout) .units(Units::Second) @@ -135,6 +140,10 @@ namespace Sensors .defaultValue("") .description("Device's power channels"); + param("Post Power On Delay", m_args.post_pwr_on_delay) + .defaultValue("0.0") + .description("Delay on power on before attempts to connect"); + param("Sentence Order", m_args.stn_order) .defaultValue("") .description("Sentence order"); @@ -150,6 +159,13 @@ namespace Sensors .defaultValue(""); } + param("Novatel SBAS", m_args.novatelSbas) + .defaultValue("false") + .description("Enable novatel sbas mode"); + + // Use wait for messages + setWaitForMessages(1.0); + // Initialize messages. clearMessages(); @@ -158,68 +174,66 @@ namespace Sensors } void - onResourceAcquisition(void) + onUpdateParameters(void) { - if (m_args.pwr_channels.size() > 0) + if (paramChanged(m_args.pwr_channels)) { - IMC::PowerChannelControl pcc; - pcc.op = IMC::PowerChannelControl::PCC_OP_TURN_ON; - for (size_t i = 0; i < m_args.pwr_channels.size(); ++i) - { - pcc.name = m_args.pwr_channels[i]; - dispatch(pcc); - } + clearPowerChannelNames(); + for (std::string pc : m_args.pwr_channels) + addPowerChannelName(pc); } - Counter timer(c_pwr_on_delay); - while (!stopping() && !timer.overflow()) - waitForMessages(timer.getRemaining()); + if (paramChanged(m_args.post_pwr_on_delay)) + { + setPostPowerOnDelay(m_args.post_pwr_on_delay); + } + } + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override + { try { - if (!openSocket()) - m_handle = new SerialPort(m_args.uart_dev, m_args.uart_baud); - + m_handle = openDeviceHandle(m_args.io_dev); m_reader = new Reader(this, m_handle); m_reader->start(); + return true; } catch (...) { throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } - } - bool - openSocket(void) - { - char addr[128] = {0}; - unsigned port = 0; - - if (std::sscanf(m_args.uart_dev.c_str(), "tcp://%[^:]:%u", addr, &port) != 2) - return false; - - TCPSocket* sock = new TCPSocket; - sock->connect(addr, port); - m_handle = sock; - return true; + return false; } + //! Disconnect from device. void - onResourceRelease(void) + onDisconnect() override { if (m_reader != NULL) { m_reader->stopAndJoin(); - delete m_reader; - m_reader = NULL; + Memory::clear(m_reader); } Memory::clear(m_handle); } + //! Initialize device. void - onResourceInitialization(void) + onInitializeDevice() override { + if (m_args.novatelSbas) + { + trace(DTR("enabling NOVATEL SBAS mode.")); + + std::string cmd = String::unescape("SBASCONTROL ENABLE AUTO\r\n"); + m_handle->writeString(cmd.c_str()); + } + for (unsigned i = 0; i < c_max_init_cmds; ++i) { if (m_args.init_cmds[i].empty()) @@ -239,7 +253,6 @@ namespace Sensors } } - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); m_wdog.setTop(m_args.inp_tout); } @@ -426,7 +439,17 @@ namespace Sensors // Validate checksum. unsigned rcsum = 0; if (std::sscanf(&line[0] + eidx + 1, "%02X", &rcsum) != 1) + { + trace("No checksum found, will not parse sentence."); return; + } + + if (ccsum != rcsum) + { + trace("Checksum field does not match computed checksum, will not " + "parse sentence."); + return; + } // Split sentence std::vector parts; @@ -501,10 +524,17 @@ namespace Sensors m_has_agvel = false; } + std::memset(&m_bufer_entity, '\0', sizeof(m_bufer_entity)); if (m_fix.validity & IMC::GpsFix::GFV_VALID_POS) - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + { + std::sprintf(m_bufer_entity, "active - hdop: %.2f , Sat: %d", m_fix.hdop, m_fix.satellites); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } else - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_WAIT_GPS_FIX); + { + std::sprintf(m_bufer_entity, "wait gps fix - hdop: %.2f , Sat: %d", m_fix.hdop, m_fix.satellites); + setEntityState(IMC::EntityState::ESTA_NORMAL, Utils::String::str(DTR(m_bufer_entity))); + } } } @@ -562,6 +592,31 @@ namespace Sensors m_fix.validity |= IMC::GpsFix::GFV_VALID_POS; } + if (m_args.novatelSbas) + { + static bool sbas_alert = false; + + if (quality == 9) + { + m_fix.type = IMC::GpsFix::GFT_STANDALONE; + m_fix.validity |= IMC::GpsFix::GFV_VALID_POS; + + if (!sbas_alert) + { + sbas_alert = true; + inf(DTR("SBAS corrections are now being applied.")); + } + } + else + { + if (sbas_alert) + { + sbas_alert = false; + war(DTR("SBAS corrections are no longer being applied.")); + } + } + } + if (readLatitude(parts[2], parts[3], m_fix.lat) && readLongitude(parts[4], parts[5], m_fix.lon) && readNumber(parts[9], m_fix.height) @@ -737,19 +792,19 @@ namespace Sensors } } - void - onMain(void) + //! Check for input timeout. + //! Data is read in the DevDataText consume. + //! @return true. + bool + onReadData() override { - while (!stopping()) + if (m_wdog.overflow()) { - waitForMessages(1.0); - - if (m_wdog.overflow()) - { - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); - } + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } + + return true; } }; } diff --git a/src/Sensors/Genesys/Task.cpp b/src/Sensors/Genesys/Task.cpp index 6e0f19c81f..41f18bb2da 100644 --- a/src/Sensors/Genesys/Task.cpp +++ b/src/Sensors/Genesys/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/GillWindObserverII/Task.cpp b/src/Sensors/GillWindObserverII/Task.cpp index 2847454bf5..36b5ad5fac 100644 --- a/src/Sensors/GillWindObserverII/Task.cpp +++ b/src/Sensors/GillWindObserverII/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/IFOG/Task.cpp b/src/Sensors/IFOG/Task.cpp index 04af907b52..cc1e5e0bea 100644 --- a/src/Sensors/IFOG/Task.cpp +++ b/src/Sensors/IFOG/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex837B/ExternalControl.hpp b/src/Sensors/Imagenex837B/ExternalControl.hpp index 6e0c578947..1c015d071f 100644 --- a/src/Sensors/Imagenex837B/ExternalControl.hpp +++ b/src/Sensors/Imagenex837B/ExternalControl.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex837B/Frame.hpp b/src/Sensors/Imagenex837B/Frame.hpp index c250d6fe78..09f415a6aa 100644 --- a/src/Sensors/Imagenex837B/Frame.hpp +++ b/src/Sensors/Imagenex837B/Frame.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex837B/Frame837.hpp b/src/Sensors/Imagenex837B/Frame837.hpp index a32c7e378c..f196b3a27c 100644 --- a/src/Sensors/Imagenex837B/Frame837.hpp +++ b/src/Sensors/Imagenex837B/Frame837.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex837B/Frame83P.hpp b/src/Sensors/Imagenex837B/Frame83P.hpp index 42c184723f..980a84c324 100644 --- a/src/Sensors/Imagenex837B/Frame83P.hpp +++ b/src/Sensors/Imagenex837B/Frame83P.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex837B/Task.cpp b/src/Sensors/Imagenex837B/Task.cpp index 5cd370eb7d..3f34a415b6 100644 --- a/src/Sensors/Imagenex837B/Task.cpp +++ b/src/Sensors/Imagenex837B/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -120,10 +120,8 @@ namespace Sensors //! %Task arguments. struct Arguments { - //! IPv4 address. - Address addr; - //! TCP port. - unsigned port; + //! Device address. + std::string io_dev; //! Start gain. unsigned start_gain; //! Absorption. @@ -188,7 +186,7 @@ namespace Sensors static const float c_min_alt = 0.3; //! %Task. - struct Task: public Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! TCP socket. TCPSocket* m_tcp; @@ -214,10 +212,6 @@ namespace Sensors std::ofstream m_log_file; //! Log filename Path m_log_path; - //! Power channel control. - IMC::PowerChannelControl m_power_channel_control; - //! Activation/deactivation timer. - Counter m_countdown; //! Range adaptive modifier counter. Counter m_range_counter; //! Watchdog. @@ -227,7 +221,7 @@ namespace Sensors //! Constructor. Task(const std::string& name, Tasks::Context& ctx): - Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_tcp(NULL), m_udp(NULL), m_frame837(NULL), @@ -239,15 +233,9 @@ namespace Sensors paramActive(Tasks::Parameter::SCOPE_MANEUVER, Tasks::Parameter::VISIBILITY_USER); - param("IPv4 Address", m_args.addr) - .defaultValue("192.168.0.2") - .description("IP address of the sonar"); - - param("TCP Port", m_args.port) - .defaultValue("4040") - .minimumValue("0") - .maximumValue("65535") - .description("TCP port"); + param("IO Port - Device", m_args.io_dev) + .defaultValue("") + .description("IO device URI in the form \"tcp://ADDRESS:PORT\"."); param("Start Gain", m_args.start_gain) .defaultValue("3") @@ -333,7 +321,7 @@ namespace Sensors .description("837/83P file name"); param("Power Channel", m_args.power_channel) - .defaultValue("Multibeam") + .defaultValue("") .description("Power channel that controls the power of the device"); param("Adaptive Range Modifier", m_args.mod) @@ -376,11 +364,6 @@ namespace Sensors m_sdata[20] = 0x08; m_sdata[26] = 0xfd; m_sdata[SD_FREQUENCY] = (uint8_t)86; - - // Register consumers. - bind(this); - bind(this); - bind(this); } //! Update task parameters. @@ -389,11 +372,8 @@ namespace Sensors { if (isActive()) { - if (paramChanged(m_args.addr)) - throw RestartNeeded(DTR("restarting to change IPv4 address"), 1); - - if (paramChanged(m_args.port)) - throw RestartNeeded(DTR("restarting to change TCP port"), 1); + if (paramChanged(m_args.io_dev)) + throw RestartNeeded(DTR("restarting to change TCP address"), 1); } if (paramChanged(m_args.data_points)) @@ -483,9 +463,11 @@ namespace Sensors setAutoMode(false); } - m_power_channel_control.name = m_args.power_channel; - - m_countdown.setTop(getActivationTime()); + if (paramChanged(m_args.power_channel)) + { + clearPowerChannelNames(); + addPowerChannelName(m_args.power_channel); + } if (paramChanged(m_args.mod_timer)) m_range_counter.setTop(m_args.mod_timer); @@ -516,111 +498,106 @@ namespace Sensors m_data->data.resize(data_size); } - void - onResourceInitialization(void) + + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - requestDeactivation(); - closeLog(); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + onUpdateParameters(); + + try + { + if (m_ec == NULL) + { + m_tcp = static_cast(openSocketTCP(m_args.io_dev)); + } + else + { + char addr[128] = {0}; + unsigned port = 0; + + if (std::sscanf(m_args.io_dev.c_str(), "tcp://%[^:]:%u", addr, &port) != 2) + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + + m_udp = new UDPSocket; + m_udp->bind(port, Address::Any, false); + } + + return m_tcp || m_udp; + } + catch (std::runtime_error& e) + { + spew("%s", e.what()); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + } + + return false; } + //! Disconnect from device. void - onResourceRelease(void) + onDisconnect() override { Memory::clear(m_frame837); Memory::clear(m_frame83P); Memory::clear(m_data); Memory::clear(m_ec); - requestDeactivation(); - } - - void - onRequestActivation(void) - { - m_power_channel_control.op = IMC::PowerChannelControl::PCC_OP_TURN_ON; - dispatch(m_power_channel_control); - m_countdown.reset(); + Memory::clear(m_tcp); + Memory::clear(m_udp); } + //! Initialize device. void - onActivation(void) + onInitializeDevice() override { - inf("%s", DTR(Status::getString(Status::CODE_ACTIVE))); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); - - IMC::LoggingControl lc; - lc.op = IMC::LoggingControl::COP_REQUEST_CURRENT_NAME; - dispatch(lc); - m_wdog.reset(); } - void - onDeactivation(void) + //! Enable log control. + bool + enableLogControl(void) { - closeLog(); - - Memory::clear(m_tcp); - Memory::clear(m_udp); - - inf("%s", DTR(Status::getString(Status::CODE_IDLE))); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - - m_power_channel_control.op = IMC::PowerChannelControl::PCC_OP_TURN_OFF; - dispatch(m_power_channel_control); + return true; } - void - checkActivationProgress(void) + //! Test if the logging control message should be discarded. + //! @param[in] msg logging control message. + //! @return true to discard message, false otherwise. + bool + discardLoggingControl(const IMC::LoggingControl* msg) override { - if (m_countdown.overflow()) - { - activationFailed(DTR("failed to contact device")); - return; - } - - try - { - if (m_ec == NULL) - { - m_tcp = new TCPSocket; - m_tcp->setNoDelay(true); - m_tcp->connect(m_args.addr, m_args.port); - } - else - { - m_udp = new UDPSocket; - m_udp->bind(m_args.port, Address::Any, false); - } - - activate(); - debug("activation took %0.2f s", getActivationTime() - - m_countdown.getRemaining()); - } - catch (...) - { } + return msg->getSource() != getSystemId(); } //! Open a log file to hold 837 or 83P files. - //! @param[in] path desired log path. + //! @param[in] path path to log file. void - openLog(const Path& path) + onOpenLog(const DUNE::FileSystem::Path& path) override { - if (path == m_log_path) + BasicDeviceDriver::onOpenLog(path); + + if (m_frame837 == NULL && m_frame83P == NULL) return; - closeLog(); + if (m_frame83P != NULL) + m_log_path = m_ctx.dir_log / path / String::str("%s.83P", m_args.file_name.c_str()); + + if (m_frame837 != NULL) + m_log_path = m_ctx.dir_log / path / String::str("%s.837", m_args.file_name.c_str()); - m_log_path = path; m_log_file.open(m_log_path.c_str(), std::ofstream::app | std::ios::binary); debug("opening %s", m_log_path.c_str()); } - //! Close current log file. + + //! Close log file. void - closeLog(void) + onCloseLog() override { + BasicDeviceDriver::onCloseLog(); + if (m_log_file.is_open()) { m_log_file.close(); @@ -635,55 +612,22 @@ namespace Sensors } void - consume(const IMC::EstimatedState* msg) - { - if (msg->getSource() != getSystemId()) - return; - - m_estate = *msg; - } - - void - consume(const IMC::LoggingControl* msg) + onEstimatedState(const IMC::EstimatedState& msg) { - if (msg->getSource() != getSystemId()) - return; - - if (m_frame837 == NULL && m_frame83P == NULL) - return; - - switch (msg->op) - { - case IMC::LoggingControl::COP_STARTED: - case IMC::LoggingControl::COP_CURRENT_NAME: - if (m_frame83P != NULL) - openLog(m_ctx.dir_log / msg->name / String::str("%s.83P", m_args.file_name.c_str())); - - if (m_frame837 != NULL) - openLog(m_ctx.dir_log / msg->name / String::str("%s.837", m_args.file_name.c_str())); - break; - - case IMC::LoggingControl::COP_STOPPED: - closeLog(); - break; - } + m_estate = msg; } void - consume(const IMC::SoundSpeed* msg) + onSoundSpeed(double value) override { - // Do not use invalid readings. - if (msg->value < 0) - return; - if (m_frame837 != NULL) - m_frame837->setSoundVelocity(msg->value); + m_frame837->setSoundVelocity(value); if (m_frame83P != NULL) - m_frame83P->setSoundVelocity(msg->value); + m_frame83P->setSoundVelocity(value); if (m_ec != NULL) - m_ec->setSoundVelocity(msg->value); + m_ec->setSoundVelocity(value); } //! Get index from table according with given value. @@ -1049,33 +993,27 @@ namespace Sensors } } - void - onMain(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { - while (!stopping()) + if (m_tcp != NULL || m_udp != NULL) { - consumeMessages(); + if (request()) + process(); + checkRange(); - if (isActive() && (m_tcp != NULL || m_udp != NULL)) + if (m_wdog.overflow()) { - if (request()) - process(); - checkRange(); - - if (m_wdog.overflow()) - { - err("%s", DTR(Status::getString(CODE_COM_ERROR))); - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); - } - } - else - { - waitForMessages(1.0); - if (isActivating()) - checkActivationProgress(); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } + + return true; } + + return false; } }; } diff --git a/src/Sensors/Imagenex852/Parser.hpp b/src/Sensors/Imagenex852/Parser.hpp index 66d3c71b91..5f044dda08 100644 --- a/src/Sensors/Imagenex852/Parser.hpp +++ b/src/Sensors/Imagenex852/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex852/PatternFilter.hpp b/src/Sensors/Imagenex852/PatternFilter.hpp index 04639489e0..0dcbd06eff 100644 --- a/src/Sensors/Imagenex852/PatternFilter.hpp +++ b/src/Sensors/Imagenex852/PatternFilter.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex852/SwitchData.hpp b/src/Sensors/Imagenex852/SwitchData.hpp index a251695841..b56d222c55 100644 --- a/src/Sensors/Imagenex852/SwitchData.hpp +++ b/src/Sensors/Imagenex852/SwitchData.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex852/Task.cpp b/src/Sensors/Imagenex852/Task.cpp index f7609c8113..76f1000acd 100644 --- a/src/Sensors/Imagenex852/Task.cpp +++ b/src/Sensors/Imagenex852/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -75,7 +75,7 @@ namespace Sensors struct Arguments { //! Serial port device. - std::string uart_dev; + std::string io_dev; //! Default Range. unsigned range; //! Pulse length. @@ -130,7 +130,7 @@ namespace Sensors static const unsigned c_pattern_occurs = 50; //! %Task. - struct Task: public Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Serial port handle. SerialPort* m_uart; @@ -144,6 +144,8 @@ namespace Sensors Arguments m_args; //! Watchdog. Counter m_wdog; + //! Device buffer. + uint8_t m_bfr[1024]; //! Last valid sound speed value. double m_sound_speed; //! Switch data. @@ -159,7 +161,7 @@ namespace Sensors //! %Task constructor. Task(const std::string& name, Tasks::Context& ctx): - Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_uart(NULL), m_sound_speed(c_sound_speed), m_parser(m_profile.data), @@ -169,9 +171,11 @@ namespace Sensors paramActive(Tasks::Parameter::SCOPE_IDLE, Tasks::Parameter::VISIBILITY_USER); - param("Serial Port - Device", m_args.uart_dev) + // Define configuration parameters. + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); + .description("IO device URI in the form \"uart://DEVICE\"." + "This device has only one baud rate."); param("Sampling Frequency", m_args.sample_frequency) .defaultValue("5") @@ -272,7 +276,6 @@ namespace Sensors m_profile.bits_per_point = 8; m_profile.scale_factor = 1.0f; - bind(this); bind(this); bind(this); } @@ -288,7 +291,7 @@ namespace Sensors m_switch.setDataPoints(m_args.data_points); m_trigger.setSampleFrequency(m_args.sample_frequency); - if (paramChanged(m_args.uart_dev) && (m_uart != NULL)) + if (paramChanged(m_args.io_dev) && (m_uart != NULL)) throw RestartNeeded(DTR("restarting to change UART device"), 1); m_sound_speed = m_args.sspeed; @@ -319,34 +322,43 @@ namespace Sensors m_profile.beam_config.push_back(bc); } - //! Acquire resources. - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { + char uart[128] = {0}; + + if (std::sscanf(m_args.io_dev.c_str(), "uart://%s", uart) != 1) + return false; + try { - m_uart = new SerialPort(m_args.uart_dev, + m_uart = new SerialPort(uart, c_uart_baud, SerialPort::SP_PARITY_NONE, SerialPort::SP_STOPBITS_1, SerialPort::SP_DATABITS_8, true); + + m_wdog.setTop(2.0); + + if (m_args.pattern_filter) + m_pfilt = new PatternFilter(c_pattern_size, m_args.pattern_diff, + c_pattern_samples, c_pattern_occurs); + return true; } catch (std::runtime_error& e) { throw RestartNeeded(e.what(), 30); } - m_wdog.setTop(2.0); - - if (m_args.pattern_filter) - m_pfilt = new PatternFilter(c_pattern_size, m_args.pattern_diff, - c_pattern_samples, c_pattern_occurs); + return false; } - //! Release resources. + //! Disconnect from device. void - onResourceRelease(void) + onDisconnect() override { if (m_trigger.isRunning() || m_trigger.isStopping()) { @@ -355,38 +367,34 @@ namespace Sensors Memory::clear(m_uart); Memory::clear(m_pfilt); + + if (m_hand.isKnown()) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + else + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_NO_MEDIUM_IDLE); + + m_trigger.setActive(false); } - //! Initialize resources. - void - onResourceInitialization(void) + bool + onSynchronize(void) override { m_trigger.setActive(isActive()); m_trigger.setUART(m_uart); m_trigger.setSwitchData(m_switch.data(), m_switch.size()); m_trigger.start(); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + return true; } + //! Initialize device. void - onActivation(void) + onInitializeDevice() override { m_wdog.reset(); m_trigger.setActive(true); } - void - onDeactivation(void) - { - if (m_hand.isKnown()) - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - else - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_NO_MEDIUM_IDLE); - - m_trigger.setActive(false); - } - void consume(const IMC::UamTxStatus* msg) { @@ -394,12 +402,9 @@ namespace Sensors } void - consume(const IMC::SoundSpeed* msg) + onSoundSpeed(double value) override { - if (msg->value < 0.0) - return; - - m_sound_speed = msg->value; + m_sound_speed = value; } void @@ -423,8 +428,6 @@ namespace Sensors { if (isActive()) requestDeactivation(); - - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); } // Medium is unknown. @@ -439,78 +442,72 @@ namespace Sensors } } - void - onMain(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { - uint8_t bfr[1024]; - - while (!stopping()) + if (m_wdog.overflow()) { - if (!isActive()) - { - waitForMessages(1.0); - continue; - } + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + err("%s", DTR(Status::getString(Status::CODE_COM_ERROR))); + } - consumeMessages(); + if (!Poll::poll(*m_uart, 1.0)) + return false; - if (m_wdog.overflow()) - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + size_t rv = m_uart->read(m_bfr, sizeof(m_bfr)); + if (rv == 0) + return false; - if (!Poll::poll(*m_uart, 1.0)) - continue; - - size_t rv = m_uart->read(bfr, sizeof(bfr)); - if (rv == 0) + for (size_t i = 0; i < rv; ++i) + { + if (!m_parser.parse(m_bfr[i])) continue; - for (size_t i = 0; i < rv; ++i) - { - if (!m_parser.parse(bfr[i])) - continue; - - m_dist.validity = IMC::Distance::DV_VALID; + m_dist.validity = IMC::Distance::DV_VALID; - m_dist.value = m_parser.getProfileRange(); + m_dist.value = m_parser.getProfileRange(); - // If range is zero, there are no echoes. - if (m_dist.value < c_min_range) - m_dist.value = m_parser.getRange(); + // If range is zero, there are no echoes. + if (m_dist.value < c_min_range) + m_dist.value = m_parser.getRange(); - // Filter using data points - if (m_args.filter_enabled) - filterRange(m_dist, m_profile); + // Filter using data points + if (m_args.filter_enabled) + filterRange(m_dist, m_profile); - if (m_args.pattern_filter) - { - if (!m_pfilt->filterPattern(m_profile.data)) - m_dist.validity = IMC::Distance::DV_INVALID; - } + if (m_args.pattern_filter) + { + if (!m_pfilt->filterPattern(m_profile.data)) + m_dist.validity = IMC::Distance::DV_INVALID; + } - // Correct for dynamic sound speed. - if (m_args.sspeed_dyn) - m_dist.value = (m_dist.value * m_sound_speed) / c_sound_speed; + // Correct for dynamic sound speed. + if (m_args.sspeed_dyn) + m_dist.value = (m_dist.value * m_sound_speed) / c_sound_speed; - // UAM is transmitting, data are probably garbled. - if (!m_uam_tx_ip) - dispatch(m_dist); + // UAM is transmitting, data are probably garbled. + if (!m_uam_tx_ip) + dispatch(m_dist); - if (m_parser.getDataPointsCount() > 0) - { - m_profile.setTimeStamp(m_dist.getTimeStamp()); - m_profile.min_range = static_cast(m_switch.getProfileMinRange()); - m_profile.max_range = m_parser.getRange(); - dispatch(m_profile); - } + if (m_parser.getDataPointsCount() > 0) + { + m_profile.setTimeStamp(m_dist.getTimeStamp()); + m_profile.min_range = static_cast(m_switch.getProfileMinRange()); + m_profile.max_range = m_parser.getRange(); + dispatch(m_profile); + } - if (m_hand.isKnown()) - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); - else - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_NO_MEDIUM_ACTIVE); + if (m_hand.isKnown()) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + else + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_NO_MEDIUM_ACTIVE); - m_wdog.reset(); - } + m_wdog.reset(); } + + return true; } //! Filter profile range using information in data points diff --git a/src/Sensors/Imagenex852/Trigger.hpp b/src/Sensors/Imagenex852/Trigger.hpp index 00d444d038..e937fb64ed 100644 --- a/src/Sensors/Imagenex852/Trigger.hpp +++ b/src/Sensors/Imagenex852/Trigger.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex872/Task.cpp b/src/Sensors/Imagenex872/Task.cpp index 888c2e5e86..68afcd8f30 100644 --- a/src/Sensors/Imagenex872/Task.cpp +++ b/src/Sensors/Imagenex872/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -62,10 +62,10 @@ namespace Sensors struct Arguments { - // IPv4 address. - Address addr; - // TCP port. - unsigned port; + //! IO device. + std::string io_dev; + //! Read frequency. + double read_frequency; // Data gain. unsigned dat_gain; // Balance gain. @@ -99,7 +99,7 @@ namespace Sensors // Return data footer size. static const int c_rdata_ftr_size = 1; - struct Task: public Tasks::Periodic + struct Task: public Hardware::BasicDeviceDriver { // TCP socket. TCPSocket* m_sock; @@ -115,22 +115,22 @@ namespace Sensors Arguments m_args; Task(const std::string& name, Tasks::Context& ctx): - Tasks::Periodic(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_sock(NULL) { // Define configuration parameters. paramActive(Tasks::Parameter::SCOPE_MANEUVER, Tasks::Parameter::VISIBILITY_USER); - param("IPv4 Address", m_args.addr) - .defaultValue("192.168.0.5") - .description("IP address of the sonar"); - - param("TCP Port", m_args.port) - .defaultValue("4040") - .minimumValue("0") - .maximumValue("65535") - .description("TCP port"); + // Define configuration parameters. + param("IO Port - Device", m_args.io_dev) + .defaultValue("tcp://192.168.0.5:4040") + .description("IO device URI in the form \"tcp://HOST:PORT\""); + + param(DTR_RT("Execution Frequency"), m_args.read_frequency) + .units(Units::Hertz) + .defaultValue("1.0") + .description(DTR("Frequency at which task reads data")); param("Data Gain", m_args.dat_gain) .defaultValue("40") @@ -184,52 +184,58 @@ namespace Sensors setDataGain(m_args.dat_gain); setBalanceGain(m_args.bal_gain); - if (paramChanged(m_args.addr) && m_sock != NULL) - throw RestartNeeded(DTR("restarting to change IPv4 address"), 1); + if (paramChanged(m_args.io_dev) && m_sock != NULL) + throw RestartNeeded(DTR("restarting to change URI"), 1); - if (paramChanged(m_args.port) && m_sock != NULL) - throw RestartNeeded(DTR("restarting to change TCP port"), 1); + if (paramChanged(m_args.read_frequency)) + setReadFrequency(m_args.read_frequency); } - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - m_sock = new TCPSocket(); - m_sock->setNoDelay(true); + try + { + m_sock = static_cast(openSocketTCP(m_args.io_dev)); + return true; + } + catch (...) + { + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + } + + return false; } + //! Disconnect from device. void - onResourceRelease(void) + onDisconnect() override { Memory::clear(m_sock); } - void - onResourceInitialization(void) + //! Synchronize with device. + bool + onSynchronize() override { try { - m_sock->connect(m_args.addr, m_args.port); pingBoth(); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); } catch (std::runtime_error& e) { throw RestartNeeded(e.what(), 10.0, false); } - } - void - onActivation(void) - { - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + return true; } + //! Device may be initialized. void - onDeactivation(void) - { - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - } + onInitializeDevice() override + { } unsigned getIndex(unsigned value, const unsigned* table, unsigned table_size) @@ -264,7 +270,7 @@ namespace Sensors m_sdata[SD_RANGE] = (uint8_t)c_ranges[idx]; m_ping.min_range = 0; m_ping.max_range = c_ranges[idx]; - Periodic::setFrequency(1.0 / (c_range_rates[idx] / 1000.0)); + setReadFrequency(1.0 / (c_range_rates[idx] / 1000.0)); } void @@ -315,15 +321,13 @@ namespace Sensors { ping(SIDE_PORT); ping(SIDE_STARBOARD); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); } - void - task(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { - if (!isActive()) - return; - try { pingBoth(); @@ -335,6 +339,8 @@ namespace Sensors setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } + + return true; } }; } diff --git a/src/Sensors/Imagenex881A/Parser.hpp b/src/Sensors/Imagenex881A/Parser.hpp index ac655971fa..e28a88a545 100644 --- a/src/Sensors/Imagenex881A/Parser.hpp +++ b/src/Sensors/Imagenex881A/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Imagenex881A/Task.cpp b/src/Sensors/Imagenex881A/Task.cpp index fa0fd85602..0ebd4b0431 100644 --- a/src/Sensors/Imagenex881A/Task.cpp +++ b/src/Sensors/Imagenex881A/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/Keller/Task.cpp b/src/Sensors/Keller/Task.cpp index 7765598822..c8083633ec 100644 --- a/src/Sensors/Keller/Task.cpp +++ b/src/Sensors/Keller/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -76,10 +76,10 @@ namespace Sensors struct Arguments { - // UART device. - std::string uart_dev; - // UART baud rate. - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; + //! Read frequency. + double read_frequency; // True if UART has local echo enabled. bool uart_echo; // Depth conversion factor. @@ -98,7 +98,7 @@ namespace Sensors // Number of seconds to wait before setting an entity error. static const float c_expire_wdog = 2.0f; - struct Task: public Tasks::Periodic + struct Task: public Hardware::BasicDeviceDriver { static const unsigned c_parser_data_size = 6; // Maximum number of consecutive CRC errors before bailing out. @@ -153,8 +153,8 @@ namespace Sensors Arguments m_args; Task(const std::string& name, Tasks::Context& ctx): - Tasks::Periodic(name, ctx), - m_handle(NULL), + Hardware::BasicDeviceDriver(name, ctx), + m_handle(nullptr), m_crc_err_count(0), m_state_timer(1), m_sample_count(0), @@ -162,13 +162,19 @@ namespace Sensors m_timeout_count(0) { // Define configuration parameters. - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); - - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("9600") - .description("Serial port baud rate"); + .description("IO device URI in the form \"tcp://ADDRESS:PORT\" " + "or \"uart://DEVICE:BAUD\""); + + param(DTR_RT("Execution Frequency"), m_args.read_frequency) + .units(Units::Hertz) + .defaultValue("1.0") + .description(DTR("Frequency at which task reads data")); param("Serial Port - Local Echo", m_args.uart_echo) .defaultValue("false") @@ -208,6 +214,9 @@ namespace Sensors void onUpdateParameters(void) { + if (paramChanged(m_args.read_frequency)) + setReadFrequency(m_args.read_frequency); + // Depth conversion (bar to meters of fluid). if (paramChanged(m_args.depth_conv)) m_args.depth_conv = Math::c_pascal_per_bar / (Math::c_gravity * m_args.depth_conv); @@ -229,38 +238,58 @@ namespace Sensors m_wdog.setTop(m_args.timeout_error); } - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - onResourceRelease(); - try { - if (openSocket()) - return; - - m_handle = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_handle->flush(); + m_handle = openDeviceHandle(m_args.io_dev); + return true; } catch (...) { throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } + + return false; } - bool - openSocket(void) + //! Disconnect from device. + void + onDisconnect() override { - char addr[128] = {0}; - unsigned port = 0; + Memory::clear(m_handle); + } - if (std::sscanf(m_args.uart_dev.c_str(), "tcp://%[^:]:%u", addr, &port) != 2) - return false; + //! Device may be initialized. + void + onInitializeDevice() override + { + m_crc_err_count = 0; + m_handle->flush(); - TCPSocket* sock = new TCPSocket; - sock->connect(addr, port); - m_handle = sock; - return true; + uint16_t crc = 0; + uint8_t bfr[10] = + { + (uint8_t)m_args.address, + (uint8_t)CMD_CONFIRMATION_FOR_INITIALIZATION + }; + + crc = Algorithms::CRC16::compute(bfr, 2, 0xFFFF); + ByteCopy::toBE(crc, &bfr[2]); + write(bfr, 4); + if (!read()) + throw RestartNeeded(DTR("unable to initialize the device"), 5.0, false); + + bfr[0] = m_args.address; + bfr[1] = CMD_READ_SERIAL_NUMBER; + crc = Algorithms::CRC16::compute(bfr, 2, 0xFFFF); + ByteCopy::toBE(crc, &bfr[2]); + write(bfr, 4); + if (!read()) + throw RestartNeeded(DTR("unable to retrieve the serial number"), 5.0, false); } void @@ -276,22 +305,12 @@ namespace Sensors } } - void - onResourceRelease(void) - { - Memory::clear(m_handle); - } - - void - onResourceInitialization(void) - { - m_crc_err_count = 0; - initialize(); - } - void consume(const IMC::GpsFix* msg) { + if (!isActive()) + return; + if (msg->getSourceEntity() != m_gps_eid) return; @@ -302,6 +321,9 @@ namespace Sensors void consume(const IMC::VehicleMedium* msg) { + if (!isActive()) + return; + if (msg->medium != IMC::VehicleMedium::VM_UNDERWATER) calibrate(); } @@ -320,6 +342,9 @@ namespace Sensors bool write(uint8_t* bfr, int len) { + if (m_handle == nullptr) + return false; + uint8_t rxbfr[10]; int i = len; bool aborted = true; @@ -423,12 +448,14 @@ namespace Sensors m_parser_state = STA_CMD; } break; + case STA_CMD: m_parser_cmd = *bfr; m_parser_data_crc = Algorithms::CRC16::compute(bfr, 1, m_parser_data_crc); m_parser_state = STA_DATA; m_parser_data_len = 0; break; + case STA_DATA: m_parser_data[m_parser_data_len++] = *bfr; if ((m_parser_data_len >= c_parser_data_size) || @@ -440,12 +467,14 @@ namespace Sensors ((m_parser_cmd == CMD_ZERO_CHANNEL) && (m_parser_data_len >= CMD_ZERO_CHANNEL_SIZE))) m_parser_state = STA_CRC_MSB; break; + case STA_CRC_MSB: m_parser_data_crc = Algorithms::CRC16::compute(m_parser_data, m_parser_data_len, m_parser_data_crc); m_parser_packet_crc = (*bfr << 8); m_parser_state = STA_CRC_LSB; break; + case STA_CRC_LSB: m_parser_packet_crc |= *bfr; // Handle crc errors properly: @@ -455,6 +484,8 @@ namespace Sensors result = RES_EXCEPTION; else result = RES_DONE; + // Falls through. + default: m_parser_state = STA_ADDR; break; @@ -478,7 +509,7 @@ namespace Sensors { err(DTR("device not initialized, initializing")); setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); - initialize(); + onInitializeDevice(); } else { @@ -512,33 +543,6 @@ namespace Sensors return true; } - void - initialize(void) - { - m_handle->flush(); - - uint16_t crc = 0; - uint8_t bfr[10] = - { - (uint8_t)m_args.address, - (uint8_t)CMD_CONFIRMATION_FOR_INITIALIZATION - }; - - crc = Algorithms::CRC16::compute(bfr, 2, 0xFFFF); - ByteCopy::toBE(crc, &bfr[2]); - write(bfr, 4); - if (!read()) - throw RestartNeeded(DTR("unable to initialize the device"), 5.0, false); - - bfr[0] = m_args.address; - bfr[1] = CMD_READ_SERIAL_NUMBER; - crc = Algorithms::CRC16::compute(bfr, 2, 0xFFFF); - ByteCopy::toBE(crc, &bfr[2]); - write(bfr, 4); - if (!read()) - throw RestartNeeded(DTR("unable to retrieve the serial number"), 5.0, false); - } - void zero(void) { @@ -589,9 +593,12 @@ namespace Sensors m_sample_count = 0; } - void - task(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { + bool reading = false; // Query pressure. if (write(m_msg_read_pressure, sizeof(m_msg_read_pressure))) { @@ -602,6 +609,7 @@ namespace Sensors dispatch(m_pressure); m_depth.value = m_channel_readout * m_args.depth_conv; dispatch(m_depth); + reading = true; } } @@ -612,10 +620,12 @@ namespace Sensors { m_temperature.value = m_channel_readout; dispatch(m_temperature); + reading = true; } } reportEntityState(); + return reading; } }; } diff --git a/src/Sensors/LIMU/ErrorHandling.hpp b/src/Sensors/LIMU/ErrorHandling.hpp index 858604ba6b..c0796f318f 100644 --- a/src/Sensors/LIMU/ErrorHandling.hpp +++ b/src/Sensors/LIMU/ErrorHandling.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/LIMU/Task.cpp b/src/Sensors/LIMU/Task.cpp index b41c04ee39..3a5257adc1 100644 --- a/src/Sensors/LIMU/Task.cpp +++ b/src/Sensors/LIMU/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -47,6 +47,8 @@ namespace Sensors static const double c_power_up_delay = 2.0; //! Hard Iron calibration parameter name. static const std::string c_hard_iron_param = "Hard-Iron Calibration"; + //! Hard Iron calibration date. + static const std::string c_calib_time_param = "Last Calibration Time"; //! Packet identifiers. enum PacketIds @@ -66,8 +68,8 @@ namespace Sensors //! %Task arguments. struct Arguments { - //! Serial port device. - std::string uart_dev; + //! IO device (URI). + std::string io_dev; //! Output frequency. unsigned output_frq; //! Raw data output. @@ -83,9 +85,11 @@ namespace Sensors //! Number of seconds without data before //! reporting a failure and restarting. double timeout_failure; + //! Calibration time stamp + std::string calib_time; }; - struct Task: public Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Angular velocity. IMC::AngularVelocity m_ang_vel; @@ -133,7 +137,7 @@ namespace Sensors Arguments m_args; Task(const std::string& name, Tasks::Context& ctx): - Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_uart(NULL), m_ctl(NULL), m_state_timer(1.0), @@ -142,9 +146,14 @@ namespace Sensors m_timeout_count(0) { // Define configuration parameters. - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); + .description("IO device URI in the form \"uart://DEVICE\"." + "This device has only one baud rate."); param("Power Channel - Name", m_args.pwr_name) .defaultValue("") @@ -183,12 +192,20 @@ namespace Sensors .units(Units::Second) .description("Number of seconds without data before restarting task"); + param(c_calib_time_param, m_args.calib_time) + .description("Date of last successful calibration") + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("N/A"); + bind(this); } void onUpdateParameters(void) { + if (paramChanged(m_args.io_dev)) + m_args.io_dev += String::str(":%u", c_baud_rate); + m_rotation.fill(c_axes_count, c_axes_count, &m_args.rotation_mx[0]); // Rotate calibration parameters. @@ -207,51 +224,69 @@ namespace Sensors if (paramChanged(m_args.output_frq) || paramChanged(m_args.raw_data)) setOutputFrequency(m_args.output_frq); + + if (paramChanged(m_args.pwr_name)) + { + clearPowerChannelNames(); + addPowerChannelName(m_args.pwr_name); + } + setPostPowerOnDelay(c_power_up_delay); } - //! Acquire resources. - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - if (!m_args.pwr_name.empty()) + try + { + m_uart = static_cast(openUART(m_args.io_dev)); + m_ctl = new UCTK::Interface(m_uart); + return true; + } + catch (std::runtime_error& e) { - IMC::PowerChannelControl pcc; - pcc.name = m_args.pwr_name; - pcc.op = IMC::PowerChannelControl::PCC_OP_TURN_ON; - dispatch(pcc); - Delay::wait(c_power_up_delay); + throw RestartNeeded(DTR(e.what()), 5.0); } + return false; + } + + //! Disconnect from device. + void + onDisconnect() override + { + Memory::clear(m_ctl); + Memory::clear(m_uart); + } + + //! Synchronize with device. + bool + onSynchronize() override + { try { - m_uart = new SerialPort(m_args.uart_dev, c_baud_rate); - m_ctl = new UCTK::Interface(m_uart); UCTK::FirmwareInfo info = m_ctl->getFirmwareInfo(); if (info.isDevelopment()) war(DTR("device is using unstable firmware")); else inf(DTR("firmware version %u.%u.%u"), info.major, info.minor, info.patch); + + return true; } catch (std::runtime_error& e) { - throw RestartNeeded(DTR(e.what()), 5.0, false); + throw RestartNeeded(DTR(e.what()), 5.0); } + + return false; } - //! Release resources. - void - onResourceRelease(void) - { - Memory::clear(m_ctl); - Memory::clear(m_uart); - } - - //! Initialize resources. + //! Initialize device. void - onResourceInitialization(void) + onInitializeDevice() override { - setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); setHardIronFactors(); setOutputFrequency(m_args.output_frq); } @@ -269,9 +304,16 @@ namespace Sensors hip.name = c_hard_iron_param; hip.value = String::str("%.4f, %.4f, 0.0", hi_x, hi_y); + IMC::EntityParameter calt; + Time::BrokenDown bdt(Time::Clock::getSinceEpochMsec() / 1000); + calt.name = c_calib_time_param; + calt.value = String::str("%04u-%02u-%02u %02u:%02u", bdt.year, bdt.month, + bdt.day, bdt.hour, bdt.minutes); + IMC::SetEntityParameters np; np.name = getEntityLabel(); np.params.push_back(hip); + np.params.push_back(calt); dispatch(np, DF_LOOP_BACK); IMC::SaveEntityParameters sp; @@ -557,20 +599,22 @@ namespace Sensors m_sample_count = 0; } - void - onMain(void) + //! Read data. + //! @return true. + bool + onReadData() override { - while (!stopping()) + bool got_data = false; + if (Poll::poll(*m_uart, 1.0)) { - consumeMessages(); - - if (Poll::poll(*m_uart, 1.0)) - readInput(); - else - m_timeout_count++; - - reportEntityState(); + readInput(); + got_data = true; } + else + m_timeout_count++; + + reportEntityState(); + return got_data; } }; } diff --git a/src/Sensors/MLBL/Task.cpp b/src/Sensors/MLBL/Task.cpp index e76068af0b..8112858ae8 100644 --- a/src/Sensors/MLBL/Task.cpp +++ b/src/Sensors/MLBL/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -936,6 +936,7 @@ namespace Sensors pc.op = IMC::PlanControl::PC_START; pc.plan_id.assign(plan_name); pc.flags = IMC::PlanControl::FLG_IGNORE_ERRORS; + pc.setDestination(m_ctx.resolver.id()); dispatch(pc); war(DTR("start plan detected")); diff --git a/src/Sensors/MLBLTracker/Task.cpp b/src/Sensors/MLBLTracker/Task.cpp index 737d2ed630..0c806e698b 100644 --- a/src/Sensors/MLBLTracker/Task.cpp +++ b/src/Sensors/MLBLTracker/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -251,6 +251,7 @@ namespace Sensors // Register message handlers. bind(this); bind(this); + bind(this); } ~Task(void) @@ -368,6 +369,21 @@ namespace Sensors dispatch(announce); } + void + consume(const IMC::AcousticSystemsQuery* msg) + { + if (m_args.addr_section.empty()) + { + war("Modem address section was not properly set."); + return; + } + AcousticSystems reply; + std::vector options = m_ctx.config.options(m_args.addr_section); + options.erase(std::remove(options.begin(), options.end(), m_ctx.resolver.name()), options.end()); + reply.list = String::join(options.begin(), options.end(), ","); + dispatchReply(*msg, reply); + } + void resetOp(void) { diff --git a/src/Sensors/MTi/Task.cpp b/src/Sensors/MTi/Task.cpp index 19d806386e..d5324d3686 100644 --- a/src/Sensors/MTi/Task.cpp +++ b/src/Sensors/MTi/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/MetrecX/Probes.cpp b/src/Sensors/MetrecX/Probes.cpp index d43f9056e8..34f2d5e72f 100644 --- a/src/Sensors/MetrecX/Probes.cpp +++ b/src/Sensors/MetrecX/Probes.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/MetrecX/Probes.def b/src/Sensors/MetrecX/Probes.def index 698d9c961c..972c1ca1cd 100644 --- a/src/Sensors/MetrecX/Probes.def +++ b/src/Sensors/MetrecX/Probes.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/MetrecX/Probes.hpp b/src/Sensors/MetrecX/Probes.hpp index 19abe2e50a..eaf2d9f943 100644 --- a/src/Sensors/MetrecX/Probes.hpp +++ b/src/Sensors/MetrecX/Probes.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/MetrecX/Task.cpp b/src/Sensors/MetrecX/Task.cpp index bc7c03b68c..9d0742a33f 100644 --- a/src/Sensors/MetrecX/Task.cpp +++ b/src/Sensors/MetrecX/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -113,10 +113,8 @@ namespace Sensors //! %Task arguments. struct Arguments { - //! Serial port device. - std::string uart_dev; - //! Serial port baud rate. - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; //! Input timeout. double input_timeout; //! Geopotential Anomaly. @@ -137,7 +135,7 @@ namespace Sensors std::string elabel_temp; }; - struct Task: public DUNE::Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Serial port handle. SerialPort* m_uart; @@ -165,21 +163,26 @@ namespace Sensors float m_temp; //! Probes. Probes m_probes; + //! Input buffer + char m_bfr[255]; + //! Sensor values + double m_values[c_total]; + //! Constructor. //! @param[in] name task name. //! @param[in] ctx context. Task(const std::string& name, Tasks::Context& ctx): - DUNE::Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_uart(NULL) { - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); - - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("38400") - .description("Serial port baud rate"); + .description("IO device URI in the form \"uart://DEVICE:BAUD\""); param("Input Timeout", m_args.input_timeout) .defaultValue("4.0") @@ -263,49 +266,6 @@ namespace Sensors bind(this); } - ~Task(void) - { - // To clear uart if an exception is thrown. - onResourceRelease(); - - for (unsigned i = 0; i < c_total; ++i) - Memory::clear(m_msgs[i]); - } - - void - onEntityResolution(void) - { - try - { - m_temp_eid = resolveEntity(m_args.elabel_temp); - } - catch (...) - { - m_temp_eid = UINT_MAX; - } - } - - void - consume(const IMC::EstimatedState* msg) - { - if (msg->getSource() != getSystemId()) - return; - - m_lat = msg->lat; - } - - void - consume(const IMC::Temperature* msg) - { - if (msg->getSourceEntity() != m_temp_eid) - return; - - if (!m_temp_wdog.overflow()) - return; - - m_temp = msg->value; - } - //! Update internal state with new parameter values. void onUpdateParameters(void) @@ -361,6 +321,87 @@ namespace Sensors } } + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override + { + try + { + m_uart = static_cast(openUART(m_args.io_dev)); + m_uart->setCanonicalInput(true); + return true; + } + catch (...) + { + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + } + + return true; + } + + //! Disconnect from device. + void + onDisconnect() override + { + stopMonitoring(); + disableInChannels(); + + Memory::clear(m_uart); + for (unsigned i = 0; i < c_total; ++i) + Memory::clear(m_msgs[i]); + } + + //! Device may be initialized. + void + onInitializeDevice() override + { + onUpdateParameters(); + + m_uart->writeString("\r"); + Delay::wait(1.0); + m_uart->flush(); + + if (!sendCommand("")) + throw RestartNeeded(DTR("failed to enter command mode"), 5, false); + + setup(); + } + + void + onEntityResolution(void) + { + try + { + m_temp_eid = resolveEntity(m_args.elabel_temp); + } + catch (...) + { + m_temp_eid = UINT_MAX; + } + } + + void + consume(const IMC::EstimatedState* msg) + { + if (msg->getSource() != getSystemId()) + return; + + m_lat = msg->lat; + } + + void + consume(const IMC::Temperature* msg) + { + if (msg->getSourceEntity() != m_temp_eid) + return; + + if (!m_temp_wdog.overflow()) + return; + + m_temp = msg->value; + } + //! Reserve entities. void onEntityReservation(void) @@ -390,45 +431,6 @@ namespace Sensors reserveEntity(m_args.labels[i]); } } - - onUpdateParameters(); - } - - //! Acquire resources. - void - onResourceAcquisition(void) - { - setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); - try - { - m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_uart->setCanonicalInput(true); - m_uart->flush(); - } - catch (std::runtime_error& e) - { - throw RestartNeeded(e.what(), 30); - } - } - - //! Release resources. - void - onResourceRelease(void) - { - Memory::clear(m_uart); - } - - void - onResourceInitialization(void) - { - m_uart->writeString("\r"); - Delay::wait(1.0); - m_uart->flush(); - - if (!sendCommand("")) - throw RestartNeeded(DTR("failed to enter command mode"), 5, false); - - setup(); } //! Setup device. @@ -724,86 +726,78 @@ namespace Sensors return active; } - //! Main loop. - void - onMain(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { - char bfr[255]; - double values[c_total]; - - while (!stopping()) + if (m_need_setup) { - consumeMessages(); - - if (m_need_setup) - { - stopMonitoring(); - setup(); - } + stopMonitoring(); + setup(); + } - if (m_wdog.overflow()) - { - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); - } + if (m_wdog.overflow()) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + } - if (!Poll::poll(*m_uart, 1.0)) - continue; + if (!Poll::poll(*m_uart, 1.0)) + return false; - size_t rv = m_uart->readString(bfr, sizeof(bfr)); - double tstamp = Clock::getSinceEpoch(); + size_t rv = m_uart->readString(m_bfr, sizeof(m_bfr)); + double tstamp = Clock::getSinceEpoch(); - if (rv == 0) - throw RestartNeeded(DTR("I/O error"), 5); + if (rv == 0) + throw RestartNeeded(DTR("I/O error"), 5); - char* ptr = bfr; - unsigned ix_read = 0; - int pos = 0; + char* ptr = m_bfr; + unsigned ix_read = 0; + int pos = 0; - double value; - unsigned chn_active = getChannels(); - while (std::sscanf(ptr, "%lf%n", &value, &pos) == 1) - { - ptr += pos; + double value; + unsigned chn_active = getChannels(); + while (std::sscanf(ptr, "%lf%n", &value, &pos) == 1) + { + ptr += pos; - // Save to temporary buffer. - if (ix_read < chn_active) - values[ix_read] = value; - ix_read++; - } + // Save to temporary buffer. + if (ix_read < chn_active) + m_values[ix_read] = value; + ix_read++; + } - // Check if there is some mismatch between the configuration file - // and sensor output. If true, doesn't dispatch any message. - if (ix_read != chn_active) - throw RestartNeeded(DTR("mismatch between output and configuration"), 30, true); + // Check if there is some mismatch between the configuration file + // and sensor output. If true, doesn't dispatch any message. + if (ix_read != chn_active) + throw RestartNeeded(DTR("mismatch between output and configuration"), 30, true); - // Dispatch data. - unsigned index = 0; - for (unsigned i = 0; i < c_total; i++) + // Dispatch data. + unsigned index = 0; + for (unsigned i = 0; i < c_total; i++) + { + if (m_slots[i]) { - if (m_slots[i]) + if (i < c_channels) { - if (i < c_channels) - { - // dispatch raw voltage (analog). - if (i >= c_di_count) - dispatchValue(m_msgs[i], values[index++], m_args.factors[i], tstamp, true, i - c_di_count); - else - dispatchValue(m_msgs[i], values[index++], m_args.factors[i], tstamp, false, i); - } + // dispatch raw voltage (analog). + if (i >= c_di_count) + dispatchValue(m_msgs[i], m_values[index++], m_args.factors[i], tstamp, true, i - c_di_count); else - { - dispatchValue(m_msgs[i], values[index++], tstamp); - } + dispatchValue(m_msgs[i], m_values[index++], m_args.factors[i], tstamp, false, i); + } + else + { + dispatchValue(m_msgs[i], m_values[index++], tstamp); } } - - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); - m_wdog.reset(); } - stopMonitoring(); - disableInChannels(); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + m_wdog.reset(); + + return true; } }; diff --git a/src/Sensors/Microstrain3DMGX1/Task.cmake b/src/Sensors/Microstrain3DMGX1/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Sensors/Microstrain3DMGX1/Task.cpp b/src/Sensors/Microstrain3DMGX1/Task.cpp new file mode 100644 index 0000000000..ab1fafb4f0 --- /dev/null +++ b/src/Sensors/Microstrain3DMGX1/Task.cpp @@ -0,0 +1,801 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Ricardo Martins * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include + +namespace Sensors +{ + //! Device driver for the Microstrain 3DM-GX1 AHRS. + namespace Microstrain3DMGX1 + { + using DUNE_NAMESPACES; + + // Duration of each clock cycle (seconds). + static const fp64_t c_tick_duration = 0.0065536; + // Tick rollover (seconds). + static const uint16_t c_tick_rollover = 65535; + // Euler angles conversion factor. + static const fp64_t c_euler_factor = (360.0 / 65536.0); + //! Number of axis. + static const uint8_t c_number_axis = 3; + //! Hard Iron calibration parameter name. + static const std::string c_hard_iron_param = "Hard-Iron Calibration"; + //! Hard Iron calibration date. + static const std::string c_calib_time_param = "Last Calibration Time"; + //! Time to wait for soft-reset. + static const float c_reset_tout = 5.0; + + //todo adicionar matriz de rotação + enum CommandByte + { + // Null command. + MSG_NULL = 0x00, + // Continuous mode. + MSG_CONTMODE = 0x10, + // EEPROM Value. + MSG_EEPROM = 0x28, + // Gyro-Stabilized Magnetic Field, Acceleration and Angular + // Rate Vectors. + MSG_IVECS = 0x02, + // Instantaneous Magnetic Field, Acceleration and Angular + // Rate Vectors. + MSG_RAW_IVECS = 0x03, + // Gyro-Stabilized Euler Angles. + MSG_GS_EULER = 0x0E, + //Write EEPROM Value + MSG_W_EEPROM= 0x29 + }; + + // States of the internal FSM. + enum FSMStates + { + FSM_STATE_NONE, + FSM_STATE_MESSAGE + }; + + struct Arguments + { + // UART device. + std::string uart_dev; + // UART baud rate. + unsigned uart_baud; + // Data timeout. + double data_tout; + // True to sample raw inertial vectors, false for compensated. + bool raw_ivecs; + // Rotation matrix values. + std::vector rotation_mx; + //! Hard iron calibration. + std::vector hard_iron; + //! Calibration threshold. + double calib_threshold; + //! Calibration time stamp + std::string calib_time; + }; + + struct Task: public DUNE::Tasks::Task + { + // Serial port. + SerialPort* m_uart; + // Euler Angles message. + IMC::EulerAngles m_euler; + // Angular velocity. + IMC::AngularVelocity m_agvel; + // Acceleration + IMC::Acceleration m_accel; + //! Magnetometer Vector message. + IMC::MagneticField m_magfield; + // Current FSM state. + FSMStates m_state; + //! Rotation Matrix to correct mounting position. + Math::Matrix m_rotation; + //! Rotated calibration parameters. + float m_hard_iron[3]; + // Count of bytes left to form a complete message. + int m_togo; + // Count of parsed bytes from current message. + int m_done; + // Command data. + uint8_t m_data[32]; + // Acceleration vector scale constant. + fp64_t m_accel_scale; + // Angular rate scale constant. + fp64_t m_gyro_scale; + // MAg gain scale + fp64_t m_mag_scale; + // Value of the last read EEPROM address. + int16_t m_eeprom; + // Device's timer. + fp64_t m_timer; + // Value of the last timer tick. + uint16_t m_last_tick; + // Task arguments. + Arguments m_args; + // Watchdog. + Counter m_wdog; + + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL), + m_timer(0), + m_last_tick(0) + { + // Define configuration parameters. + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the sensor"); + + param("Serial Port - Baud Rate", m_args.uart_baud) + .defaultValue("115200") + .description("Serial port baud rate"); + + param("Data Timeout", m_args.data_tout) + .units(Units::Second) + .defaultValue("2.0") + .minimumValue("1.0"); + + param("Raw Inertial Vectors", m_args.raw_ivecs) + .defaultValue("false") + .description("Set to true to enable sampling of raw data"); + + param("IMU Rotation Matrix", m_args.rotation_mx) + .defaultValue("") + .size(9) + .description("IMU rotation matrix which is dependent of the mounting position"); + + param(c_hard_iron_param, m_args.hard_iron) + .units(Units::Gauss) + .size(c_number_axis) + .description("Hard-Iron calibration parameters"); + + param("Calibration Threshold", m_args.calib_threshold) + .defaultValue("0.1") + .units(Units::Gauss) + .minimumValue("0.0") + .description("Minimum magnetic field calibration values to reset hard iron parameters"); + + param(c_calib_time_param, m_args.calib_time) + .description("Date of last successful calibration") + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("N/A"); + + bind(this); + } + + //! Update parameters. + void + onUpdateParameters(void) + { + m_rotation.fill(3, 3, &m_args.rotation_mx[0]); + + // Rotate calibration parameters. + Math::Matrix data(3, 1); + + for (unsigned i = 0; i < 3; i++) + data(i) = m_args.hard_iron[i]; + data = transpose(m_rotation) * data; + for (unsigned i = 0; i < 3; i++) + m_hard_iron[i] = data(i); + + if (m_uart != NULL) + { + if (paramChanged(m_args.hard_iron)) + runCalibration(); + } + } + void + onResourceAcquisition(void) + { + m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); + } + + void + onResourceInitialization(void) + { + m_wdog.setTop(m_args.data_tout); + } + + void + consume(const IMC::MagneticField* msg) + { + if (msg->getDestinationEntity() != getEntityId()) + return; + + // Reject if it is small adjustment. + if ((std::abs(msg->x) < m_args.calib_threshold) && + (std::abs(msg->y) < m_args.calib_threshold)) + return; + + double hi_x = m_args.hard_iron[0] + msg->x; + double hi_y = m_args.hard_iron[1] + msg->y; + + IMC::EntityParameter hip; + hip.name = c_hard_iron_param; + hip.value = String::str("%f, %f, 0.0", hi_x, hi_y); + + IMC::EntityParameter calt; + Time::BrokenDown bdt(Time::Clock::getSinceEpochMsec() / 1000); + calt.name = c_calib_time_param; + calt.value = String::str("%04u-%02u-%02u %02u:%02u", bdt.year, bdt.month, + bdt.day, bdt.hour, bdt.minutes); + + IMC::SetEntityParameters np; + np.name = getEntityLabel(); + np.params.push_back(hip); + np.params.push_back(calt); + dispatch(np, DF_LOOP_BACK); + + IMC::SaveEntityParameters sp; + sp.name = getEntityLabel(); + dispatch(sp); + } + + void + onResourceRelease(void) + { + Memory::clear(m_uart); + } + + int8_t + getCommandDataSize(uint8_t id) + { + switch (id) + { + case MSG_IVECS: + return 23; + case MSG_RAW_IVECS: + return 23; + case MSG_CONTMODE: + return 7; + case MSG_EEPROM: + return 7; + case MSG_GS_EULER: + return 11; + case MSG_W_EEPROM : + return 7; + } + + return -1; + } + + bool + setup(void) + { + clear(); + + setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); + // Stop continuous mode. + setContinuousMode(); + Delay::wait(1.0); + m_uart->flushInput(); + + // Stop continuous mode and read answer. + setContinuousMode(); + if (!getMessage(MSG_CONTMODE)) + { + setEntityState(IMC::EntityState::ESTA_FAILURE, + DTR("failed to stop device")); + return false; + } + + // Read GyroGainScale. + queryEEPROM(130); + if (!getMessage(MSG_EEPROM)) + { + setEntityState(IMC::EntityState::ESTA_FAILURE, + DTR("failed to read EEPROM#130")); + return false; + } + m_gyro_scale = (32768000.0 / m_eeprom); + + // Read AccelGainScale. + queryEEPROM(230); + if (!getMessage(MSG_EEPROM)) + { + setEntityState(IMC::EntityState::ESTA_FAILURE, + DTR("failed to read EEPROM#230")); + return false; + } + m_accel_scale = (32768000.0 / m_eeprom); + + // Read MagGainScale. + queryEEPROM(232); + if (!getMessage(MSG_EEPROM)) + { + setEntityState(IMC::EntityState::ESTA_FAILURE, + DTR("failed to read EEPROM#230")); + return false; + } + m_mag_scale = (32768000.0 / m_eeprom); + + runCalibration(); + // Set continuous mode for gyro-stabilized euler angles. + setContinuousMode(MSG_GS_EULER); + + // Device is configured. + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + + return true; + } + + bool + getMessage(CommandByte type, fp64_t maxwait = 1.0) + { + char bfr[64]; + bool got = false; + + while (Poll::poll(*m_uart, maxwait) && !got) + { + int rv = m_uart->read(bfr, 64); + + for (int i = 0; i < rv; ++i) + if (parse(bfr[i]) == type) + { + got = true; + break; + } + } + + return got; + } + + void + clear(void) + { + m_state = FSM_STATE_NONE; + m_togo = 0; + m_done = 0; + } + + fp64_t + updateTimerCount(uint8_t* data) + { + uint16_t ticks = 0; + ByteCopy::fromBE(ticks, data); + + // Check for overflows. + if (ticks < m_last_tick) + m_timer += (c_tick_rollover - m_last_tick + ticks) * c_tick_duration; + else + m_timer += (ticks - m_last_tick) * c_tick_duration; + + m_last_tick = ticks; + + return m_timer; + } + + //! Correct data according with mounting position. + void + rotateAcceleration(void) + { + Math::Matrix data(3, 1); + + // Acceleration. + data(0) = m_accel.x; + data(1) = m_accel.y; + data(2) = m_accel.z; + data = m_rotation * data; + m_accel.x = data(0); + m_accel.y = data(1); + m_accel.z = data(2); + } + + void + rotateAngularVelocity(void) + { + Math::Matrix data(3, 1); + + // Angular Velocity. + data(0) = m_agvel.x; + data(1) = m_agvel.y; + data(2) = m_agvel.z; + data = m_rotation * data; + m_agvel.x = data(0); + m_agvel.y = data(1); + m_agvel.z = data(2); + } + + void + rotateMagneticField(void) + { + Math::Matrix data(3, 1); + // Magnetic Field. + data(0) = m_magfield.x; + data(1) = m_magfield.y; + data(2) = m_magfield.z; + data = m_rotation * data; + m_magfield.x = data(0); + m_magfield.y = data(1); + m_magfield.z = data(2); + } + + void + rotateEuler(void) + { + Math::Matrix data(3, 1); + + // Acceleration. + data(0) = m_euler.phi; + data(1) = m_euler.theta; + data(2) = m_euler.psi; + data = m_rotation * data; + m_euler.phi = data(0); + m_euler.theta = data(1); + m_euler.psi = data(2); + } + + CommandByte + parse(uint8_t byte) + { + int8_t msg_size = 0; + + switch (m_state) + { + // Test for synchronization + case FSM_STATE_NONE: + m_togo = m_done = 0; + msg_size = getCommandDataSize(byte); + if (msg_size > 0) + { + m_togo = msg_size - 1; + m_done = 1; + m_data[0] = byte; // Store ID. + m_state = FSM_STATE_MESSAGE; + } + break; + + // Parse message body. + case FSM_STATE_MESSAGE: + m_data[m_done] = byte; + ++m_done; + --m_togo; + break; + + // Should never get here. + default: + debug("%s: 0x%02x", DTR("unexpected byte"), byte); + break; + } + + // Exit if we don't have a complete message. + if (m_togo != 0 || m_state != FSM_STATE_MESSAGE) + return MSG_NULL; + + m_state = FSM_STATE_NONE; + + if (!validateCheckSum(m_data, m_done)) + { + err("%s", DTR(Status::getString(Status::CODE_INVALID_CHECKSUM))); + return MSG_NULL; + } + + double tstamp = Clock::getSinceEpoch(); + + // Interpret parsed data. + int16_t angle = 0; + switch (m_data[0]) + { + case MSG_CONTMODE: + return MSG_CONTMODE; + + case MSG_EEPROM: + ByteCopy::fromBE(m_eeprom, m_data + 1); + return MSG_EEPROM; + + case MSG_GS_EULER: + m_euler.time = updateTimerCount(m_data + 7); + ByteCopy::fromBE(angle, m_data + 1); + m_euler.phi = Angles::radians((fp64_t)angle * c_euler_factor); + ByteCopy::fromBE(angle, m_data + 3); + m_euler.theta = Angles::radians((fp64_t)angle * c_euler_factor); + ByteCopy::fromBE(angle, m_data + 5); + m_euler.psi = Angles::radians((fp64_t)angle * c_euler_factor); + rotateEuler(); + m_euler.psi_magnetic = m_euler.psi; + m_euler.setTimeStamp(tstamp); + dispatch(m_euler, DF_KEEP_TIME); + requestMessage(m_args.raw_ivecs ? MSG_RAW_IVECS : MSG_IVECS); + return MSG_GS_EULER; + + case MSG_IVECS: + // Acceleration. + m_accel.time = updateTimerCount(m_data + 19); + ByteCopy::fromBE(angle, m_data + 7); + m_accel.x = (fp64_t)angle / m_accel_scale; + ByteCopy::fromBE(angle, m_data + 9); + m_accel.y = (fp64_t)angle / m_accel_scale; + ByteCopy::fromBE(angle, m_data + 11); + m_accel.z = (fp64_t)angle / m_accel_scale; + m_accel.setTimeStamp(tstamp); + rotateAcceleration(); + + // Angular velocity. + m_agvel.time = updateTimerCount(m_data + 19); + ByteCopy::fromBE(angle, m_data + 13); + m_agvel.x = (fp64_t)angle / m_gyro_scale; + ByteCopy::fromBE(angle, m_data + 15); + m_agvel.y = (fp64_t)angle / m_gyro_scale; + ByteCopy::fromBE(angle, m_data + 17); + m_agvel.z = (fp64_t)angle / m_gyro_scale; + m_agvel.setTimeStamp(tstamp); + rotateAngularVelocity(); + + // Extract magnetic field. + m_magfield.time = updateTimerCount(m_data + 19); + ByteCopy::fromBE(angle, m_data + 1); + m_magfield.x = (fp64_t)angle / m_mag_scale; + ByteCopy::fromBE(angle, m_data + 3); + m_magfield.y = (fp64_t)angle / m_mag_scale; + ByteCopy::fromBE(angle, m_data + 5); + m_magfield.z = (fp64_t)angle / m_mag_scale; + m_magfield.setTimeStamp(tstamp); + rotateMagneticField(); + + dispatch(m_magfield, DF_KEEP_TIME); + dispatch(m_accel, DF_KEEP_TIME); + dispatch(m_agvel, DF_KEEP_TIME); + + return MSG_IVECS; + + case MSG_RAW_IVECS: + // Acceleration. + m_accel.time = updateTimerCount(m_data + 19); + ByteCopy::fromBE(angle, m_data + 7); + m_accel.x = (fp64_t)angle / m_accel_scale; + ByteCopy::fromBE(angle, m_data + 9); + m_accel.y = (fp64_t)angle / m_accel_scale; + ByteCopy::fromBE(angle, m_data + 11); + m_accel.z = (fp64_t)angle / m_accel_scale; + m_accel.setTimeStamp(tstamp); + rotateAcceleration(); + // Angular velocity. + ByteCopy::fromBE(angle, m_data + 13); + m_agvel.x = (fp64_t)angle / m_gyro_scale; + ByteCopy::fromBE(angle, m_data + 15); + m_agvel.y = (fp64_t)angle / m_gyro_scale; + ByteCopy::fromBE(angle, m_data + 17); + m_agvel.z = (fp64_t)angle / m_gyro_scale; + m_agvel.setTimeStamp(tstamp); + rotateAngularVelocity(); + dispatch(m_accel, DF_KEEP_TIME); + dispatch(m_agvel, DF_KEEP_TIME); + return MSG_RAW_IVECS; + + case MSG_W_EEPROM: + ByteCopy::fromBE(m_eeprom, m_data + 1); + return MSG_W_EEPROM; + } + + return MSG_NULL; + } + + void + setContinuousMode(CommandByte msg = MSG_NULL) + { + uint8_t cmd[3] = + { + (uint8_t)MSG_CONTMODE, + (uint8_t)0x00, + (uint8_t)msg + }; + + m_uart->write(cmd, 3); + } + + void + queryEEPROM(uint16_t address) + { + uint8_t cmd[3] = + { + MSG_EEPROM, + (uint8_t)(address >> 8), + (uint8_t)address + }; + + m_uart->write(cmd, 3); + } + + void + writeEEPROM(uint16_t address , uint16_t w_data) + { + uint8_t cmd[7] = + { + (uint8_t)MSG_W_EEPROM, + (uint8_t)0x71, + (uint8_t)(address >> 8), + (uint8_t)address, + (uint8_t)(w_data >> 8), + (uint8_t)w_data, + (uint8_t)0xAA + }; + + m_uart->write(cmd, 7); + } + + //! Routine to run calibration proceedings. + void + runCalibration(void) + { + if (m_uart == NULL) + return; + + // See if vehicle has same hard iron calibration parameters. + if (!isCalibrated()) + { + + // Set hard iron calibration parameters and reset device. + if (!setHardIron()) + { + throw RestartNeeded(DTR("failed to set hard-iron correction factors"), 5); + } + else + { + // Set continuous mode for gyro-stabilized euler angles. + setContinuousMode(MSG_GS_EULER); + } + } + } + + //! Check if sensor has the same hard iron calibration parameters. + //! @return true if the parameters are the same, false otherwise. + bool + isCalibrated(void) + { + // Sensor magnetic calibration. + int16_t senCal[c_number_axis] = {0}; + // Magnetic calibration in configuration. + int16_t cfgCal[c_number_axis] = {0}; + // Stop continuous mode and read answer. + setContinuousMode(); + if (!getMessage(MSG_CONTMODE)) + { + setEntityState(IMC::EntityState::ESTA_FAILURE, + DTR("failed to stop device")); + return false; + } + for (unsigned i=0; iwrite(&cmd, 1); + } + + bool + validateCheckSum(const uint8_t* bfr, unsigned int size) + { + int16_t rsum = 0; + int16_t sum = bfr[0]; + + ByteCopy::fromBE(rsum, bfr + size - 2); + + for (unsigned int i = 1; i < size - 2; i += 2) + { + int16_t val = 0; + ByteCopy::fromBE(val, bfr + i); + sum += val; + } + + return (rsum == sum); + } + + void + onMain(void) + { + while (!setup()) + { + Delay::wait(1.0); + } + + uint8_t bfr[256]; + + while (!stopping()) + { + if (Poll::poll(*m_uart, 0.5)) + { + size_t rv = m_uart->read(bfr, 256); + for (size_t i = 0; i < rv; ++i) + { + CommandByte cb = parse(bfr[i]); + if (cb == MSG_GS_EULER) + m_wdog.reset(); + } + + setEntityState(IMC::EntityState::ESTA_NORMAL, + Status::CODE_ACTIVE); + } + + if (m_wdog.overflow()) + setEntityState(IMC::EntityState::ESTA_ERROR, + Status::CODE_COM_ERROR); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Sensors/Microstrain3DMGX3/Task.cpp b/src/Sensors/Microstrain3DMGX3/Task.cpp index 4dfc61514a..5d707d53b7 100644 --- a/src/Sensors/Microstrain3DMGX3/Task.cpp +++ b/src/Sensors/Microstrain3DMGX3/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -49,6 +49,8 @@ namespace Sensors //! Hard Iron calibration parameter name. static const std::string c_hard_iron_param = "Hard-Iron Calibration"; + //! Hard Iron calibration date. + static const std::string c_calib_time_param = "Last Calibration Time"; //! Time to wait for soft-reset. static const float c_reset_tout = 5.0; //! Number of axis. @@ -88,10 +90,10 @@ namespace Sensors //! %Task arguments. struct Arguments { - //! UART device. - std::string uart_dev; - //! UART baud rate. - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; + //! Read frequency. + double read_frequency; //! Calibration threshold. double calib_threshold; //! Hard iron calibration. @@ -103,10 +105,12 @@ namespace Sensors //! Number of seconds without data before //! reporting a failure and restarting. double timeout_failure; + //! Calibration time stamp + std::string calib_time; }; //! %Microstrain3DMGX3 software driver. - struct Task: public DUNE::Tasks::Periodic + struct Task: public Hardware::BasicDeviceDriver { //! Internal read buffer. static const unsigned c_bfr_size = 128; @@ -150,7 +154,7 @@ namespace Sensors Arguments m_args; Task(const std::string& name, Tasks::Context& ctx): - DUNE::Tasks::Periodic(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_uart(NULL), m_tstamp(0), m_state_timer(1.0), @@ -158,13 +162,18 @@ namespace Sensors m_faults_count(0), m_timeout_count(0) { - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); - - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("115200") - .description("Serial port baud rate"); + .description("IO device URI in the form \"uart://DEVICE:BAUD\""); + + param(DTR_RT("Execution Frequency"), m_args.read_frequency) + .units(Units::Hertz) + .defaultValue("1.0") + .description(DTR("Frequency at which task reads data")); param("Calibration Threshold", m_args.calib_threshold) .defaultValue("0.1") @@ -194,6 +203,11 @@ namespace Sensors .units(Units::Second) .description("Number of seconds without data before restarting task"); + param(c_calib_time_param, m_args.calib_time) + .description("Date of last successful calibration") + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("N/A"); + m_timer.setTop(c_reset_tout); // Magnetic calibration addresses. @@ -207,6 +221,9 @@ namespace Sensors void onUpdateParameters(void) { + if (paramChanged(m_args.read_frequency)) + setReadFrequency(m_args.read_frequency); + m_rotation.fill(3, 3, &m_args.rotation_mx[0]); // Rotate calibration parameters. @@ -228,45 +245,48 @@ namespace Sensors } } - //! Release resources. - void - onResourceRelease(void) - { - Memory::clear(m_uart); - } - - //! Acquire resources. - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); - try { - m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_uart->flush(); + m_uart = static_cast(openUART(m_args.io_dev)); + return true; } - catch (std::runtime_error& e) + catch (...) { - throw RestartNeeded(e.what(), 30); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 30); } + + return false; } - //! Initialize resources. + //! Disconnect from device. void - onResourceInitialization(void) + onDisconnect() override { - while (!stopping()) - { - // Read firmware version in order to assess if we can communicate - // with the device. - m_uart->setMinimumRead(CMD_FWARE_VERSION_SIZE); - if (poll(CMD_FWARE_VERSION, CMD_FWARE_VERSION_SIZE, 0, 0)) - break; + Memory::clear(m_uart); + } - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - } + //! Synchronize with device. + bool + onSynchronize() override + { + // Read firmware version in order to assess if we can communicate + // with the device. + m_uart->setMinimumRead(CMD_FWARE_VERSION_SIZE); + if (poll(CMD_FWARE_VERSION, CMD_FWARE_VERSION_SIZE, 0, 0)) + return true; + + return false; + } + //! Device may be initialized. + void + onInitializeDevice() override + { // Calibrate sensor. runCalibration(); @@ -292,9 +312,16 @@ namespace Sensors hip.name = c_hard_iron_param; hip.value = String::str("%f, %f, 0.0", hi_x, hi_y); + IMC::EntityParameter calt; + Time::BrokenDown bdt(Time::Clock::getSinceEpochMsec() / 1000); + calt.name = c_calib_time_param; + calt.value = String::str("%04u-%02u-%02u %02u:%02u", bdt.year, bdt.month, + bdt.day, bdt.hour, bdt.minutes); + IMC::SetEntityParameters np; np.name = getEntityLabel(); np.params.push_back(hip); + np.params.push_back(calt); dispatch(np, DF_LOOP_BACK); IMC::SaveEntityParameters sp; @@ -617,13 +644,11 @@ namespace Sensors m_sample_count = 0; } - //! Main task. - void - task(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { - // Check for incoming messages. - consumeMessages(); - if (poll(CMD_DATA, CMD_DATA_SIZE, 0, 0)) { // Set timestamps so we have realistic times. @@ -701,6 +726,7 @@ namespace Sensors } reportEntityState(); + return true; } }; } diff --git a/src/Sensors/MiniSVS/Task.cpp b/src/Sensors/MiniSVS/Task.cpp index 9241eb92d4..6ceb7f636d 100644 --- a/src/Sensors/MiniSVS/Task.cpp +++ b/src/Sensors/MiniSVS/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/OEMX/Driver.hpp b/src/Sensors/OEMX/Driver.hpp new file mode 100644 index 0000000000..6c1b3bd203 --- /dev/null +++ b/src/Sensors/OEMX/Driver.hpp @@ -0,0 +1,281 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Gonçalves * +//*************************************************************************** + +#ifndef SENSORS_OEMX_DRIVER_HPP_INCLUDED_ +#define SENSORS_OEMX_DRIVER_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include + + +namespace Sensors +{ + namespace OEMX + { + using DUNE_NAMESPACES; + + class DriverOEMX + { + public: + + struct CTDData + { + //! Data get from CTD + float dataReceived[8]; + //! CTD Info + std::string ctdInfo; + //! Primary Mount Info + std::string primaryInfo; + //! Secondary Mount Info + std::string secondaryInfo; + }; + + //! Serial port + SerialPort* m_uart; + //! Interrupt/Poll for serial port + Poll m_poll; + + DriverOEMX(DUNE::Tasks::Task* task, SerialPort* uart, Poll poll): + m_task(task) + { + m_uart = uart; + m_poll = poll; + m_timeout_uart = 1.0f;; + } + + ~DriverOEMX(void) + {} + + bool + initCTD(int numberSamples) + { + if(numberSamples > 5 || numberSamples <= 0) + { + m_task->war("Incorrect Number of Samples, setting 1 sample/s"); + numberSamples = 1; + } + char cmdSample[32]; + char replySample[32]; + + std::sprintf(cmdSample, "SET S %d /s\r", numberSamples); + std::sprintf(replySample, ">SET S %d /s\r\n", numberSamples); + + m_uart->writeString("\r"); + Delay::wait(1.0); + m_uart->flush(); + + if (!sendCommand("\r", "\r\n")) + { + m_task->err(DTR("failed to enter command mode")); + return false; + } + + if (!sendCommand(cmdSample, replySample)) + { + m_task->err(DTR("failed to set sampling rate")); + return false; + } + + if (!sendCommand("MONITOR\r", ">MONITOR\r\n")) + { + m_task->err(DTR("failed to enter monitor mode")); + return false; + } + + return true; + } + + bool + getInfoOfCTD() + { + char usart_rec[2]; + bool result = false; + sendCommand("\r", "\r\n"); + Delay::wait(2.0); + m_uart->flush(); + Delay::wait(2.0); + + while(!m_task->isStopping()) + { + if (sendCommand("\r", "\r\n")) + { + result = true; + break; + } + else + { + Delay::wait(2.0); + m_uart->flush(); + break; + } + } + + if(result) + { + m_uart->writeString("display options\r\r"); + std::string txtRec; + bool isFristTerminator = true; + + while(!m_task->isStopping()) + { + if (m_poll.poll(m_timeout_uart)) + if (m_poll.wasTriggered(*m_uart)) + { + m_uart->read(usart_rec, 1); + txtRec += usart_rec[0]; + + if (usart_rec[0] == '>') + { + if (isFristTerminator) + isFristTerminator = false; + else + break; + } + } + } + + std::string delimiter = "\r\n\r\n"; + size_t pos = 0; + size_t cnt = 0; + std::string token[4]; + while ((pos = txtRec.find(delimiter)) != std::string::npos) + { + token[cnt] = txtRec.substr(0, pos); + txtRec.erase(0, pos + delimiter.length()); + cnt++; + } + token[cnt] = txtRec; + + getFirmwareVersion(token[0]); + m_ctdData.primaryInfo = getInfoMount(token[1]); + m_ctdData.secondaryInfo = getInfoMount(token[2]); + } + + return result; + } + + void + getFirmwareVersion(std::string text) + { + m_task->spew("%s", text.c_str()); + std::string identifier = "Firmware=V"; + std::size_t found = text.find(identifier); + std::string version = text.substr(found, identifier.size() + 5); + std::replace(version.begin(), version.end(), '\r', ' '); + std::replace(version.begin(), version.end(), '\n', '\0'); + + identifier = "SN="; + found = text.find(identifier); + std::string serialCTD = text.substr(found, identifier.size() + 6); + std::replace(serialCTD.begin(), serialCTD.end(), '\r', ' '); + std::replace(serialCTD.begin(), serialCTD.end(), '\n', '\0'); + + identifier = "Type="; + found = text.find(identifier); + std::string typeCTD = text.substr(found, identifier.size() + 4); + std::replace(typeCTD.begin(), typeCTD.end(), '\r', ' '); + std::replace(typeCTD.begin(), typeCTD.end(), '\n', '\0'); + + m_ctdData.ctdInfo = typeCTD + version + serialCTD; + } + + std::string + getInfoMount(std::string text) + { + m_task->spew("%s", text.c_str()); + std::string identifier = "SensorName="; + std::size_t found = text.find(identifier); + identifier = "\r\n"; + std::size_t found2 = text.find(identifier, found); + std::string serialN = text.substr(found2 + 2, text.size() - found2 - 4); + + return text.substr(found, found2 - found) + " " + serialN; + } + + bool + sendCommand(const char* cmd, const char* reply) + { + char bfrUart[128]; + m_task->debug("Command: %s", cmd); + m_uart->writeString(cmd); + + if (Poll::poll(*m_uart, m_timeout_uart)) + { + m_uart->readString(bfrUart, sizeof(bfrUart)); + m_task->debug("Reply: %s", bfr); + if (std::strcmp(bfrUart, reply) == 0) + return true; + } + + return false; + } + + bool + haveNewData(int numberSensors) + { + std::size_t rv = m_uart->readString(bfr, sizeof(bfr)); + + if (rv == 0) + { + m_task->err(DTR("I/O error")); + return false; + } + + m_task->spew("%s", bfr); + + int total_sensors_read = std::sscanf(bfr, " %f %f %f %f %f %f\r\n", &m_ctdData.dataReceived[0], &m_ctdData.dataReceived[1], + &m_ctdData.dataReceived[2], &m_ctdData.dataReceived[3], + &m_ctdData.dataReceived[4], &m_ctdData.dataReceived[5]); + + if(numberSensors == total_sensors_read) + return true; + else + return false; + } + + CTDData m_ctdData; + + private: + + //! Parent task. + DUNE::Tasks::Task* m_task; + //! Timeout for new data in uart + float m_timeout_uart; + //! Buffer of uart + char bfr[32]; + + }; + } +} + +#endif /* SENSORS_OEMX_DRIVER_HPP_INCLUDED_ */ diff --git a/src/Sensors/OEMX/Task.cmake b/src/Sensors/OEMX/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Sensors/OEMX/Task.cpp b/src/Sensors/OEMX/Task.cpp new file mode 100644 index 0000000000..2a27cb3f87 --- /dev/null +++ b/src/Sensors/OEMX/Task.cpp @@ -0,0 +1,441 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: PGonçalves * +//*************************************************************************** + +// DUNE headers. +#include + +// Local Headers. +#include "Driver.hpp" + +namespace Sensors +{ + namespace OEMX + { + using DUNE_NAMESPACES; + + static const float c_delay_startup = 10.0f; + static const float c_timeout_uart = 1.0f; + static const float c_mS_per_cm_to_S_per_m = 0.1f; + static const float c_bar_to_Pa = 100000.0f; + static const float c_dbar_to_bar = 0.1f; + //! Sensor options. + static const std::string c_s_options[] = { "Conductivity", "SoundSpeed", + "Temperature", "Pressure", + "Turbidity" }; + + struct Arguments + { + //! Serial port device. + std::string uart_dev; + //! Serial port baud rate. + unsigned uart_baud; + //! Input timeout. + double input_timeout; + //! Input number samples/s + unsigned int input_samples_number; + //! List of sensors in primary mount. + std::vector primary_mount; + //! List of sensors in secondary mount. + std::vector secondary_mount; + }; + + struct SensorStateData + { + //! Conductivity + bool haveConductivity; + //! SoundSpeed + bool haveSoundSpeed; + //! Temperature + bool haveTemperature; + //! Pressure + bool havePressure; + //! Turbidity + bool haveTurbidity; + //! Salinity + bool haveSalinity; + }; + + struct Task: public DUNE::Tasks::Task + { + //! Serial port handle. + SerialPort* m_uart; + //! I/O Multiplexer. + Poll m_poll; + //! Task arguments + Arguments m_args; + //! Sensor data state + SensorStateData m_sdstate; + //! Driver of CTD + DriverOEMX *m_driver; + //! Watchdog. + Counter m_wdog; + //! Conductivity. + IMC::Conductivity m_cond; + //! Salinity. + IMC::Salinity m_sali; + //! Sound speed. + IMC::SoundSpeed m_sspe; + //! Temperature. + IMC::Temperature m_temp; + //! Pressure. + IMC::Pressure m_pres; + //! Turbidity + IMC::Turbidity m_turb; + //! Depth + IMC::Depth m_depth; + //! Temperature + float m_temperature; + //! Salinity + float m_salinity; + //! Pressure + float m_pressure; + //! Conductivity + float m_conductivity; + //! SoundSpeed + float m_soundSpeed; + //! Turbidity + float m_turbidity; + //! Number of sensors plug in CTD + std::size_t m_numberSensors; + //! Timestamp. + double m_tstamp; + //! Flag to control calibration of CTD + bool m_first_value; + //! Offset of pressure from CTD + float m_offset_pressure; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL), + m_driver(0), + m_temperature(0), + m_salinity(0), + m_pressure(0), + m_conductivity(0), + m_soundSpeed(0), + m_turbidity(0), + m_numberSensors(0), + m_tstamp(0) + { + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the sensor"); + + param("Serial Port - Baud Rate", m_args.uart_baud) + .defaultValue("38400") + .description("Serial port baud rate"); + + param("Input Timeout", m_args.input_timeout) + .defaultValue("4.0") + .minimumValue("1.0") + .units(Units::Second) + .description("Amount of seconds to wait for data before reporting an error"); + + param("Number of Samples/s", m_args.input_samples_number) + .defaultValue("1") + .minimumValue("1") + .maximumValue("5") + .description("Amount of samples/s."); + + param("Primary Mount", m_args.primary_mount) + .defaultValue("") + .description("List of sensors in primary mount"); + + param("Secondary Mount", m_args.secondary_mount) + .defaultValue("") + .description("List of sensors in secondary mount"); + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); + resetStateDataSensor(); + + for (unsigned i = 0; i < m_args.primary_mount.size(); i++) + { + if (m_args.primary_mount[i].compare(c_s_options[0]) == 0) + m_sdstate.haveConductivity = true; + else if (m_args.primary_mount[i].compare(c_s_options[1]) == 0) + m_sdstate.haveSoundSpeed = true; + else if (m_args.primary_mount[i].compare(c_s_options[2]) == 0) + m_sdstate.haveTemperature = true; + } + + for (unsigned i = 0; i < m_args.secondary_mount.size(); i++) + { + if (m_args.secondary_mount[i].compare(c_s_options[3]) == 0) + m_sdstate.havePressure = true; + else if (m_args.secondary_mount[i].compare(c_s_options[4]) == 0) + m_sdstate.haveTurbidity = true; + else if (m_args.secondary_mount[i].compare(c_s_options[2]) == 0) + m_sdstate.haveTemperature = true; + } + + if (m_sdstate.haveConductivity && m_sdstate.havePressure + && m_sdstate.haveTemperature) + m_sdstate.haveSalinity = true; + + try + { + m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); + m_uart->setCanonicalInput(true); + m_uart->flush(); + m_poll.add(*m_uart); + m_driver = new DriverOEMX(this, m_uart, m_poll); + m_numberSensors = m_args.primary_mount.size() + m_args.secondary_mount.size(); + m_first_value = true; + } + catch (std::runtime_error& e) + { + throw RestartNeeded(e.what(), 10); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + resetStateDataSensor(); + Delay::wait(c_delay_startup); + getInfoOfCTD(); + + if(!m_driver->initCTD(m_args.input_samples_number)) + throw RestartNeeded(DTR("failed to init CTD"), 10, true); + + m_wdog.setTop(m_args.input_timeout); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_uart != NULL) + { + m_poll.remove(*m_uart); + Memory::clear(m_driver); + Memory::clear(m_uart); + } + } + + void + resetStateDataSensor(void) + { + m_sdstate.haveConductivity = false; + m_sdstate.havePressure = false; + m_sdstate.haveSalinity = false; + m_sdstate.haveSoundSpeed = false; + m_sdstate.haveTemperature = false; + m_sdstate.haveTurbidity = false; + } + + void + getInfoOfCTD() + { + if(m_driver->getInfoOfCTD()) + { + inf("CTD Info: %s", m_driver->m_ctdData.ctdInfo.c_str()); + inf("Primary Mount Info: %s", m_driver->m_ctdData.primaryInfo.c_str()); + inf("Secondary Mount Info: %s", m_driver->m_ctdData.secondaryInfo.c_str()); + } + else + { + throw RestartNeeded(DTR("com error - get info"), 10, true); + } + } + + void + formateDataCTD(void) + { + std::size_t cntIndex = 0; + for (std::size_t i = 0; i < m_args.primary_mount.size(); i++) + { + if (m_args.primary_mount[i].compare(c_s_options[0]) == 0) + { + m_conductivity = m_driver->m_ctdData.dataReceived[i] * c_mS_per_cm_to_S_per_m; + m_sdstate.haveConductivity = true; + cntIndex++; + } + else if (m_args.primary_mount[i].compare(c_s_options[1]) == 0) + { + m_soundSpeed = m_driver->m_ctdData.dataReceived[i]; + m_sdstate.haveSoundSpeed = true; + cntIndex++; + } + else if (m_args.primary_mount[i].compare(c_s_options[2]) == 0) + { + m_temperature = m_driver->m_ctdData.dataReceived[i]; + m_sdstate.haveTemperature = true; + cntIndex++; + } + } + + for (std::size_t i = 0; i < m_args.secondary_mount.size(); i++) + { + if (m_args.secondary_mount[i].compare(c_s_options[3]) == 0) + { + m_pressure = m_driver->m_ctdData.dataReceived[cntIndex + i] * c_dbar_to_bar; + m_sdstate.havePressure = true; + } + else if (m_args.secondary_mount[i].compare(c_s_options[4]) == 0) + { + m_turbidity = m_driver->m_ctdData.dataReceived[cntIndex + i]; + m_sdstate.haveTurbidity = true; + } + else if (m_args.secondary_mount[i].compare(c_s_options[2]) == 0) + { + m_temperature = m_driver->m_ctdData.dataReceived[cntIndex + i]; + m_sdstate.haveTemperature = true; + } + } + + if(m_sdstate.haveConductivity && m_sdstate.havePressure && m_sdstate.haveTemperature) + { + m_salinity = UNESCO1983::computeSalinity(m_conductivity, (m_pressure - m_offset_pressure), m_temperature); + if(m_salinity < 0) + m_salinity = 0; + m_sdstate.haveSalinity = true; + } + + if(m_sdstate.haveSalinity && m_sdstate.havePressure && m_sdstate.haveTemperature && !m_sdstate.haveSoundSpeed) + { + if (m_salinity > 0) + m_soundSpeed = UNESCO1983::computeSoundSpeed(m_salinity, (m_pressure - m_offset_pressure), m_temperature); + else + m_soundSpeed = 0; + + m_sdstate.haveSoundSpeed = true; + } + } + + void + dispatchData(void) + { + if (!m_first_value) + { + if (m_sdstate.haveConductivity) + { + spew("Conductivity: %f S/m", m_conductivity); + m_cond.setTimeStamp(m_tstamp); + m_cond.value = m_conductivity; + dispatch(m_cond, DF_KEEP_TIME); + } + if (m_sdstate.havePressure) + { + spew("Pressure: %f Bar", (m_pressure - m_offset_pressure)); + m_pres.setTimeStamp(m_tstamp); + m_pres.value = (m_pressure - m_offset_pressure) * c_bar_to_Pa; + dispatch(m_pres, DF_KEEP_TIME); + + m_depth.setTimeStamp(m_tstamp); + m_depth.value = (m_pres.value / (Math::c_gravity * c_seawater_density)); + spew("Depth: %f m", m_depth.value); + dispatch(m_depth, DF_KEEP_TIME); + } + if (m_sdstate.haveSoundSpeed) + { + spew("SoundSpeed: %f m/s", m_soundSpeed); + m_sspe.setTimeStamp(m_tstamp); + m_sspe.value = m_soundSpeed; + dispatch(m_sspe, DF_KEEP_TIME); + } + if (m_sdstate.haveTemperature) + { + spew("Temperature: %f C", m_temperature); + m_temp.setTimeStamp(m_tstamp); + m_temp.value = m_temperature; + dispatch(m_temp, DF_KEEP_TIME); + } + if (m_sdstate.haveSalinity) + { + spew("Salinity: %f", m_salinity); + m_sali.setTimeStamp(m_tstamp); + m_sali.value = m_salinity; + dispatch(m_sali, DF_KEEP_TIME); + } + if (m_sdstate.haveTurbidity) + { + spew("Turbidity: %f", m_turbidity); + m_turb.setTimeStamp(m_tstamp); + m_turb.value = m_turbidity; + dispatch(m_turb, DF_KEEP_TIME); + } + } + else + { + m_first_value = false; + if (m_sdstate.havePressure) + { + m_offset_pressure = m_pressure; + inf(DTR("CTD - Pressure calibrated (%f)"), m_offset_pressure); + } + } + + spew(" "); + resetStateDataSensor(); + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(0.1); + + if (m_wdog.overflow()) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 10); + } + + if (!Poll::poll(*m_uart, c_timeout_uart)) + continue; + + m_tstamp = Clock::getSinceEpoch(); + if(m_driver->haveNewData(m_numberSensors)) + { + formateDataCTD(); + dispatchData(); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + m_wdog.reset(); + } + } + m_driver->sendCommand("\r", ">"); + } + }; + } +} + +DUNE_TASK diff --git a/src/Sensors/OS4000/Task.cpp b/src/Sensors/OS4000/Task.cpp index cca09d0972..5bb89b068b 100644 --- a/src/Sensors/OS4000/Task.cpp +++ b/src/Sensors/OS4000/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -77,8 +77,8 @@ namespace Sensors //! %Task arguments. struct Arguments { - std::string uart_dev; - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; double data_tout; int data_rate; }; @@ -89,7 +89,7 @@ namespace Sensors //! characters to validate process. static const int c_min_chars = 10; - struct Task: public DUNE::Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Internal read buffer. static const unsigned c_bfr_size = 128; @@ -119,18 +119,18 @@ namespace Sensors Counter m_wdog; Task(const std::string& name, Tasks::Context& ctx): - DUNE::Tasks::Task(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_uart(NULL), m_tstamp(0) { // Retrieve config values. - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); - - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("19200") - .description("Serial port baud rate"); + .description("IO device URI in the form \"uart://DEVICE:BAUD\""); param("Data Timeout", m_args.data_tout) .defaultValue("0.5") @@ -181,51 +181,61 @@ namespace Sensors bind(this); } - //! Release allocated resources. + //! Update %Task parameters. void - onResourceRelease(void) + onUpdateParameters(void) { - Memory::clear(m_uart); + if (paramChanged(m_args.data_tout)) + m_wdog.setTop(m_args.data_tout); } - //! Acquire resources. - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_uart->setCanonicalInput(true); - m_uart->flush(); + try + { + m_uart = static_cast(openUART(m_args.io_dev)); + m_uart->setCanonicalInput(true); + return true; + } + catch (...) + { + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + } + + return false; } - //! Initialize resources. + //! Disconnect from device. void - onResourceInitialization(void) + onDisconnect() override + { + Memory::clear(m_uart); + } + + //! Synchronize with device. + bool + onSynchronize() override { m_accumulator = 0; m_state = STA_BOOT; - while (!stopping()) - { - if (setParameter("R", "Output rate", m_args.data_rate)) - break; - } + if (!setParameter("R", "Output rate", m_args.data_rate)) + return false; - while (!stopping()) - { - if (setParameter("X", "Display", c_display_fields)) - break; - } + if (!setParameter("X", "Display", c_display_fields)) + return false; - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - m_wdog.reset(); + return true; } - //! Update %Task parameters. + //! Device may be initialized. void - onUpdateParameters(void) + onInitializeDevice() override { - if (paramChanged(m_args.data_tout)) - m_wdog.setTop(m_args.data_tout); + m_wdog.reset(); } //! Read a string from the serial port, @@ -394,75 +404,74 @@ namespace Sensors setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); } - void - onMain(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { - while (!stopping()) - { - if (m_wdog.overflow()) - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - - consumeMessages(); - - if (m_state == STA_WAIT_LEVEL) - { - std::string desc = String::str(DTR("Level the device and hit NEXT (Roll: %0.2f | Pitch: %0.2f)"), - m_euler.phi, m_euler.theta); - m_states[STA_WAIT_LEVEL].step = desc; - dispatch(m_states[m_state]); - } + if (m_wdog.overflow()) + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - if (m_state == STA_ROTATE) - { - - calibrating(); - continue; - } + if (m_state == STA_WAIT_LEVEL) + { + std::string desc = String::str(DTR("Level the device and hit NEXT (Roll: %0.2f | Pitch: %0.2f)"), + m_euler.phi, m_euler.theta); + m_states[STA_WAIT_LEVEL].step = desc; + dispatch(m_states[m_state]); + } - int rv = readString(); - if (rv <= 0) - continue; + if (m_state == STA_ROTATE) + { - unsigned rcsum = 0; - unsigned ccsum = XORChecksum::compute((uint8_t*)m_bfr + 1, rv - 1 - 5); + calibrating(); + return false; + } - std::sscanf(m_bfr, "$C%lfP%lfR%lfT%fMx%lfMy%lfMz%lfAx%lfAy%lfAz%lf*%02X\r\n", - &m_euler.psi_magnetic, &m_euler.theta, &m_euler.phi, - &m_temp.value, - &m_mag.x, &m_mag.y, &m_mag.z, - &m_accel.x, &m_accel.y, &m_accel.z, - &rcsum); + int rv = readString(); + if (rv <= 0) + return false; + + unsigned rcsum = 0; + unsigned ccsum = XORChecksum::compute((uint8_t*)m_bfr + 1, rv - 1 - 5); + + std::sscanf(m_bfr, "$C%lfP%lfR%lfT%fMx%lfMy%lfMz%lfAx%lfAy%lfAz%lf*%02X\r\n", + &m_euler.psi_magnetic, &m_euler.theta, &m_euler.phi, + &m_temp.value, + &m_mag.x, &m_mag.y, &m_mag.z, + &m_accel.x, &m_accel.y, &m_accel.z, + &rcsum); + + if (rcsum != ccsum) + return false; + + // Convert degree to radian. + m_euler.setTimeStamp(); + m_euler.psi_magnetic = Angles::radians(m_euler.psi_magnetic); + m_euler.psi = m_euler.psi_magnetic; + m_euler.phi = Angles::radians(m_euler.phi); + m_euler.theta = Angles::radians(m_euler.theta); + dispatch(m_euler, DF_KEEP_TIME); + + // Convert G to m/s/s. + m_accel.setTimeStamp(m_euler.getTimeStamp()); + m_accel.x = Math::c_gravity * m_accel.x; + m_accel.y = Math::c_gravity * m_accel.y * -1.0; + m_accel.z = Math::c_gravity * m_accel.z * -1.0; + dispatch(m_accel, DF_KEEP_TIME); + + m_temp.setTimeStamp(m_euler.getTimeStamp()); + dispatch(m_temp, DF_KEEP_TIME); + + m_mag.setTimeStamp(m_euler.getTimeStamp()); + m_mag.x /= 1000.0; + m_mag.y /= 1000.0; + m_mag.z /= 1000.0; + dispatch(m_mag, DF_KEEP_TIME); - if (rcsum != ccsum) - continue; + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + m_wdog.reset(); - // Convert degree to radian. - m_euler.setTimeStamp(); - m_euler.psi_magnetic = Angles::radians(m_euler.psi_magnetic); - m_euler.psi = m_euler.psi_magnetic; - m_euler.phi = Angles::radians(m_euler.phi); - m_euler.theta = Angles::radians(m_euler.theta); - dispatch(m_euler, DF_KEEP_TIME); - - // Convert G to m/s/s. - m_accel.setTimeStamp(m_euler.getTimeStamp()); - m_accel.x = Math::c_gravity * m_accel.x; - m_accel.y = Math::c_gravity * m_accel.y * -1.0; - m_accel.z = Math::c_gravity * m_accel.z * -1.0; - dispatch(m_accel, DF_KEEP_TIME); - - m_temp.setTimeStamp(m_euler.getTimeStamp()); - dispatch(m_temp, DF_KEEP_TIME); - - m_mag.setTimeStamp(m_euler.getTimeStamp()); - m_mag.x /= 1000.0; - m_mag.y /= 1000.0; - m_mag.z /= 1000.0; - dispatch(m_mag, DF_KEEP_TIME); - - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); - m_wdog.reset(); - } + return true; } }; } diff --git a/src/Sensors/SADC/DriverSADC.hpp b/src/Sensors/SADC/DriverSADC.hpp index 87cbaf0d94..dcc431fa8d 100644 --- a/src/Sensors/SADC/DriverSADC.hpp +++ b/src/Sensors/SADC/DriverSADC.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/SADC/Task.cpp b/src/Sensors/SADC/Task.cpp index dcce37b414..2903c58e53 100644 --- a/src/Sensors/SADC/Task.cpp +++ b/src/Sensors/SADC/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/SCH311X/Task.cpp b/src/Sensors/SCH311X/Task.cpp index 6e77b488fd..ab8b97cf72 100644 --- a/src/Sensors/SCH311X/Task.cpp +++ b/src/Sensors/SCH311X/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/SW100/Driver.cpp b/src/Sensors/SW100/Driver.cpp index 77e42b2f3f..278e06fcfa 100644 --- a/src/Sensors/SW100/Driver.cpp +++ b/src/Sensors/SW100/Driver.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/SW100/Driver.hpp b/src/Sensors/SW100/Driver.hpp index fd31ac5866..6909f0a3c1 100644 --- a/src/Sensors/SW100/Driver.hpp +++ b/src/Sensors/SW100/Driver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/SW100/Task.cpp b/src/Sensors/SW100/Task.cpp index 3934b42436..c8405e2689 100644 --- a/src/Sensors/SW100/Task.cpp +++ b/src/Sensors/SW100/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -42,10 +42,10 @@ namespace Sensors struct Arguments { - //! UART device. - std::string uart_dev; - //! UART baud rate. - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; + //! Read frequency. + double read_frequency; //! Depth calibration parameters. std::vector depth_cal; //! Input timeout. @@ -60,7 +60,7 @@ namespace Sensors CS_ABLE }; - struct Task: public DUNE::Tasks::Periodic + struct Task: public Hardware::BasicDeviceDriver { //! Device driver. Driver* m_driver; @@ -90,7 +90,7 @@ namespace Sensors Counter m_wdog; Task(const std::string& name, Tasks::Context& ctx): - DUNE::Tasks::Periodic(name, ctx), + Hardware::BasicDeviceDriver(name, ctx), m_driver(NULL), m_uart(NULL), m_depth_avg(10), @@ -99,13 +99,18 @@ namespace Sensors m_cs(CS_UNABLE) { // Define configuration parameters. - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); - - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("9600") - .description("Serial port baud rate"); + .description("IO device URI in the form \"uart://DEVICE:BAUD\""); + + param(DTR_RT("Execution Frequency"), m_args.read_frequency) + .units(Units::Hertz) + .defaultValue("1.0") + .description(DTR("Frequency at which task reads data")); param("Depth Calibration", m_args.depth_cal) .defaultValue("1.0, 0.0") @@ -124,25 +129,46 @@ namespace Sensors } void - onResourceAcquisition(void) + onUpdateParameters(void) { - m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_driver = new Driver(this, *m_uart); + if (paramChanged(m_args.read_frequency)) + setReadFrequency(m_args.read_frequency); } - void - onResourceInitialization(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - m_wdog.setTop(m_args.data_timeout); + try + { + m_uart = static_cast(openUART(m_args.io_dev)); + m_driver = new Driver(this, *m_uart); + return true; + } + catch (...) + { + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + } + + return false; } + //! Disconnect from device. void - onResourceRelease(void) + onDisconnect() override { Memory::clear(m_uart); Memory::clear(m_driver); } + //! Device may be initialized. + void + onInitializeDevice() override + { + m_wdog.setTop(m_args.data_timeout); + } + void consume(const IMC::VehicleMedium* msg) { @@ -161,8 +187,10 @@ namespace Sensors return (m_at_surface && !m_maneuvering); } - void - task(void) + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override { if (m_wdog.overflow()) { @@ -175,7 +203,7 @@ namespace Sensors else { setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - return; + return false; } } @@ -222,6 +250,8 @@ namespace Sensors if (m_cs == CS_ABLE) m_depth_offset.value = m_depth_avg.update(m_depth.value); } + + return true; } }; } diff --git a/src/Sensors/SonTekArgonaut/Task.cpp b/src/Sensors/SonTekArgonaut/Task.cpp index d888bf4797..0c3869c604 100644 --- a/src/Sensors/SonTekArgonaut/Task.cpp +++ b/src/Sensors/SonTekArgonaut/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/ThermalZone/Task.cpp b/src/Sensors/ThermalZone/Task.cpp index 3f71616eed..75a5d079a1 100644 --- a/src/Sensors/ThermalZone/Task.cpp +++ b/src/Sensors/ThermalZone/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -93,10 +93,13 @@ namespace Sensors { m_temp.value = readValue(m_args.path.c_str()); dispatch(m_temp); + + if (getEntityState() == IMC::EntityState::ESTA_ERROR) + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); } catch (...) { - // Ignored. + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); } } }; diff --git a/src/Sensors/V104setup/Task.cmake b/src/Sensors/V104setup/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Sensors/V104setup/Task.cpp b/src/Sensors/V104setup/Task.cpp new file mode 100644 index 0000000000..e5a98957d6 --- /dev/null +++ b/src/Sensors/V104setup/Task.cpp @@ -0,0 +1,124 @@ +//*************************************************************************** +// Copyright 2007-2019 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Nikolai Lauvås * +//*************************************************************************** + +// DUNE headers. +#include + +namespace Sensors +{ + //! Insert short task description here. + //! + //! Insert explanation on task behaviour here. + //! @author Nikolai Lauvås + namespace V104setup + { + using DUNE_NAMESPACES; + struct Arguments + { + std::string uart_dev; + int uart_baud; + }; + struct Task: public DUNE::Tasks::Task + { + //! UART. + Hardware::SerialPort* m_uart; + //! Task arguments. + Arguments m_args; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_uart(NULL) + { + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the sensor"); + + param("Serial Port - Baud Rate", m_args.uart_baud) + .defaultValue("4800") + .description("Serial port baud rate"); + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + } + + //! Resolve entity names. + void + onEntityResolution(void) + { + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + m_uart = new Hardware::SerialPort(m_args.uart_dev, m_args.uart_baud); + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + } + + //! Release resources. + void + onResourceRelease(void) + { + //Memory::clear(m_uart); + } + + //! Main loop. + void + onMain(void) + { + std::string cmdText = "$JBAUD,19200\r\n"; + m_uart->writeString(cmdText.c_str()); + Memory::clear(m_uart); + while (!stopping()) + { + waitForMessages(1.0); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Sensors/VantagePro2/Parser.hpp b/src/Sensors/VantagePro2/Parser.hpp new file mode 100644 index 0000000000..bcca96a701 --- /dev/null +++ b/src/Sensors/VantagePro2/Parser.hpp @@ -0,0 +1,520 @@ +//*************************************************************************** +// Copyright 2007-2021 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Joao Costa * +//********************************************************************SENSORS +#ifndef SENSORS_VANTAGEPRO2_PARSER_HPP_INCLUDED_ +#define SENSORS_VANTAGEPRO2_PARSER_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include + +/* CCITT table of CRC values */ +static uint16_t crc_table[] = { + 0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, + 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, + 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, + 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, + 0x2c22, 0x3c03, 0xc60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, + 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, + 0xe37f, 0xf35e, 0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, + 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, + 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, + 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0, +}; + +// Import namespaces. +using DUNE_NAMESPACES; + +namespace Sensors +{ + namespace VantagePro2 + { + //! Message Parser for WeatherStation. + //! + //! @author João Costa + class Parser + { + public: + //! State machine states. + enum ParserStates + { + PS_ACK, + //! Read preamble 1 + PS_PREAMBLE_1, + //! Read preamble 2 + PS_PREAMBLE_2, + //! Read preamble 3 + PS_PREAMBLE_3, + //! Data received 1 + PS_DATA_1, + //! Data received 2 + PS_DATA_2, + //! Read middle preamble 4 + PS_PREAMBLE_4, + //! Read middle preamble 2 + PS_PREAMBLE_5, + //! Read terminator 2 + PS_TERMINATOR_1, + //! Read preamble 2 + PS_TERMINATOR_2, + //! Csum + PS_CSUM + }; + + //! Received buffer. + char m_bfr[256]; + //! Message byte counter. + uint8_t m_rx_byte_size; + //! Console's ersion + float m_console_version; + + //! Definition of Davis LOOP data packet + struct __attribute__((__packed__)) LOOPData + { + uint8_t Ack; // Acknowledge char + char L; // "L" + char O1; // "O" + char O2; // "O" + char P; // Barometer trend + uint8_t PacketType; // Always zero for current firmware release + uint16_t NextRec; // Loc in archive memory for next data packet + uint16_t Barometer; // Current barometer (Hg / 1000) + int16_t InsideTemp; // Inside Temperature (DegF / 10) + uint8_t InsideHum; // Inside Humidity (%) + int16_t OutsideTemp; // Outside Temperature (DegF / 10) + uint8_t WindSpeed; // Wind Speed + uint8_t AvgWindSpeed; // 10-Minute Avg Wind Speed + uint16_t WindDir; // Wind Direction in degress + int8_t XtraTemps[7]; // Extra Temperatures + int8_t SoilTemps[4]; // Soil Temperatures + int8_t LeafTemps[4]; // Leaf Temperatures + uint8_t OutsideHum; // Outside Humidity + uint8_t XtraHums[7]; // Extra Humidities + uint16_t RainRate; // Rain Rate + uint8_t UVLevel; // UV Level + uint16_t SolarRad; // Solar Radiation + uint16_t StormRain; // Total Storm Rain + uint16_t StormStart; // Start date of current storm + uint16_t RainDay; // Rain Today + uint16_t RainMonth; // Rain this Month + uint16_t RainYear; // Rain this Year + uint16_t ETDay; // Day ET + uint16_t ETMonth; // Month ET + uint16_t ETYear; // Year ET + uint32_t SoilMoist; // Soil Moistures + uint32_t LeafWet; // Leaf Wetness + uint8_t AlarmInside; // Inside Alarm bits + uint8_t AlarmRain; // Rain Alarm bits + uint16_t AlarmOut; // Outside Temperature Alarm bits + uint8_t AlarmXtra[8]; // Extra Temp/Hum Alarms + uint32_t AlarmSL; // Soil and Leaf Alarms + uint8_t XmitBatt; // Transmitter battery status + uint16_t BattLevel; // Console Battery Level: Voltage = ((wBattLevel * 300)/512)/100.0 + uint8_t ForeIcon; // Forecast Icon + uint8_t Rule; // Forecast rule number + uint16_t Sunrise; // Sunrise time (BCD encoded, 24hr) + uint16_t Sunset; // Sunset time (BCD encoded, 24hr) + uint8_t LF; // '\n' 0x0a + uint8_t CR; // '\r' 0x0d + uint16_t WCRC; // CRC check bytes (CCITT-16 standard) 2bytes + }; + + //! DAVIS' LOOP data packet data. + LOOPData m_LOOPData; + + Parser(DUNE::Tasks::Task *task) : m_task(task), + m_parser_state_OK(Parser::PS_PREAMBLE_1), + m_parser_state_LOOP(Parser::PS_ACK) + { + } + + ~Parser(void) + { + } + + //! Parse message received + bool + parseLOOP(uint8_t byte) + { + switch (m_parser_state_LOOP) + { + case PS_ACK: + if (byte == 0x06) + { + m_parser_state_LOOP = PS_PREAMBLE_1; + m_cnt = 0; + m_rx_byte_size = 0; + std::memset(&m_bfr, '\0', sizeof(m_bfr)); + m_bfr[m_cnt++] = byte; + } + break; + case PS_PREAMBLE_1: + if (byte == 'L') + { + m_parser_state_LOOP = PS_PREAMBLE_2; + m_bfr[m_cnt++] = byte; + } + else + { + m_parser_state_LOOP = PS_ACK; + } + break; + case PS_PREAMBLE_2: + if (byte == 'O') + { + m_parser_state_LOOP = PS_PREAMBLE_3; + m_bfr[m_cnt++] = byte; + } + else + { + m_parser_state_LOOP = PS_ACK; + } + break; + case PS_PREAMBLE_3: + if (byte == 'O') + { + m_parser_state_LOOP = PS_DATA_1; + m_bfr[m_cnt++] = byte; + } + else + { + m_parser_state_LOOP = PS_ACK; + } + break; + case PS_DATA_1: + if (byte != '\n') + { + m_bfr[m_cnt++] = byte; + } + else + { + m_parser_state_LOOP = PS_TERMINATOR_1; + m_bfr[m_cnt++] = byte; + } + break; + case PS_TERMINATOR_1: + if (byte == '\r') + { + m_parser_state_LOOP = PS_CSUM; + m_bfr[m_cnt++] = byte; + m_rx_byte_size = m_cnt; + } + else + { + m_parser_state_LOOP = PS_ACK; + } + break; + case PS_CSUM: + m_bfr[m_cnt++] = byte; + m_rx_byte_size = m_cnt; + + if (m_cnt == 100) + { + m_parser_state_LOOP = PS_ACK; + int csum_calc = CheckCRC(99, m_bfr + 1); + if (csum_calc == 0) + { + return true; + } + else + { + m_task->war("Checksum failed."); + return false; + } + } + else if (m_cnt >= 103) + { + m_task->war("Overflow loop message."); + m_parser_state_LOOP = PS_ACK; + return false; + } + break; + default: + m_parser_state_LOOP = PS_ACK; + break; + } + return false; + } + + //! Parse message received + bool + parseOK(uint8_t byte) + { + switch (m_parser_state_OK) + { + case PS_PREAMBLE_1: + if (byte == '\n') + { + m_parser_state_OK = PS_PREAMBLE_2; + m_cnt = 0; + m_rx_byte_size = 0; + std::memset(&m_bfr, '\0', sizeof(m_bfr)); + } + break; + case PS_PREAMBLE_2: + if (byte == '\r') + { + m_parser_state_OK = PS_DATA_1; + } + else + { + m_parser_state_OK = PS_PREAMBLE_1; + } + break; + case PS_DATA_1: + if (byte != '\n') + { + m_bfr[m_cnt++] = byte; + } + else + { + m_parser_state_OK = PS_PREAMBLE_4; + m_bfr[m_cnt++] = ' '; + } + break; + case PS_PREAMBLE_4: + if (byte == '\r') + { + m_parser_state_OK = PS_DATA_2; + } + else + { + m_parser_state_OK = PS_PREAMBLE_1; + } + break; + case PS_DATA_2: + if (byte != '\n') + { + m_bfr[m_cnt++] = byte; + } + else + { + m_parser_state_OK = PS_TERMINATOR_1; + } + break; + case PS_TERMINATOR_1: + if (byte == '\r') + { + m_parser_state_OK = PS_PREAMBLE_1; + return true; + } + else + { + m_parser_state_OK = PS_PREAMBLE_1; + } + break; + default: + m_parser_state_OK = PS_PREAMBLE_1; + break; + } + return false; + } + + //! Filter data received from doris sampler board. + bool + translate(bool waiting_LOOP) // TODO: (Maybe) receive last cmd and do a switch case. + { + std::string mbuf; + if (waiting_LOOP) // TODO: Check if "waiting_LOOP" is actually needed. + { + if (m_bfr[1] == 'L' && m_bfr[2] == 'O' && m_bfr[3] == 'O') + { + std::memcpy((char *)&m_LOOPData, &m_bfr, sizeof(LOOPData)); + printData(); + return true; + } + } + else + { + if (m_bfr[0] == 'O' && m_bfr[1] == 'K') + { + float tempValue = 0; + std::sscanf(m_bfr, "OK %f", &tempValue); + m_console_version = tempValue; + m_task->war("console version = %.02f", m_console_version); + + return true; + } + } + return false; + } + + void + printData(void) + { + /*int16_t i; + i = m_LOOPData.P; + m_task->trace("BaroTrend = "); + switch (i) + { + case -60: + m_task->trace("Falling Rapidly"); + break; + case -20: + m_task->trace("Falling Slowly"); + break; + case 0: + m_task->trace("Steady"); + break; + case 20: + m_task->trace("Rising Slowly"); + break; + case 60: + m_task->trace("Rising Rapidly"); + break; + default: + m_task->trace("n/a-P"); + } + m_task->trace("Baro Trend Img = "); + switch (i) + { + case -60: + m_task->trace("baro_fr"); + break; + case -20: + m_task->trace("baro_fs"); + break; + case 0: + m_task->trace("baro_s"); + break; + case 20: + m_task->trace("baro_rs"); + break; + case 60: + m_task->trace("baro_rr"); + break; + default: + m_task->trace("baro_none"); + }*/ + m_task->trace("BaroCurr = %2.2f", m_LOOPData.Barometer / 1000.0); + m_task->trace("Inside Temp = %.1f", ((int16_t)m_LOOPData.InsideTemp) / 10.0); + m_task->trace("Inside Hum = %d", m_LOOPData.InsideHum); + m_task->trace("Outside Temp = %.1f", ((int16_t)m_LOOPData.OutsideTemp) / 10.0); + m_task->trace("Wind Speed = %d", m_LOOPData.WindSpeed); + m_task->trace("Wind Avg Speed = %d", m_LOOPData.AvgWindSpeed); + m_task->trace("Wind Dir = %d", m_LOOPData.WindDir); + m_task->trace("Wind Dir Rose = "); + if (m_LOOPData.WindDir >= 347 && m_LOOPData.WindDir < 12) + m_task->trace("N"); + else if (m_LOOPData.WindDir >= 12 && m_LOOPData.WindDir < 34) + m_task->trace("NNE"); + else if (m_LOOPData.WindDir >= 34 && m_LOOPData.WindDir < 57) + m_task->trace("NE"); + else if (m_LOOPData.WindDir >= 57 && m_LOOPData.WindDir < 79) + m_task->trace("ENE"); + else if (m_LOOPData.WindDir >= 79 && m_LOOPData.WindDir < 102) + m_task->trace("E"); + else if (m_LOOPData.WindDir >= 102 && m_LOOPData.WindDir < 124) + m_task->trace("ESE"); + else if (m_LOOPData.WindDir >= 124 && m_LOOPData.WindDir < 147) + m_task->trace("SE"); + else if (m_LOOPData.WindDir >= 147 && m_LOOPData.WindDir < 170) + m_task->trace("SSE"); + else if (m_LOOPData.WindDir >= 170 && m_LOOPData.WindDir < 192) + m_task->trace("S"); + else if (m_LOOPData.WindDir >= 192 && m_LOOPData.WindDir < 214) + m_task->trace("SSW"); + else if (m_LOOPData.WindDir >= 214 && m_LOOPData.WindDir < 237) + m_task->trace("SW"); + else if (m_LOOPData.WindDir >= 237 && m_LOOPData.WindDir < 259) + m_task->trace("WSW"); + else if (m_LOOPData.WindDir >= 259 && m_LOOPData.WindDir < 280) + m_task->trace("W"); + else if (m_LOOPData.WindDir >= 280 && m_LOOPData.WindDir < 303) + m_task->trace("WNW"); + else if (m_LOOPData.WindDir >= 303 && m_LOOPData.WindDir < 347) + m_task->trace("NW"); + else /* >326 <347 */ + m_task->trace("NNW"); + + m_task->trace("Outside Hum = %d", m_LOOPData.OutsideHum); + //m_task->trace("Rain Rate = %.2f", m_LOOPData.RainRate / 100.0); + //m_task->trace("Is Raining = %s", m_LOOPData.RainRate ? "yes" : "no"); + /*m_task->trace("UV Levev = "); + if (m_LOOPData.UVLevel == 0xff) + m_task->trace("n/a"); + else + m_task->trace("%.1f", m_LOOPData.UVLevel / 10.0); + m_task->trace("%s = ", SOLAR_RAD); + if (m_LOOPData.SolarRad == 32767) + m_task->trace("n/a"); + else + m_task->trace("%d", m_LOOPData.SolarRad);*/ + //m_task->trace("Rain Storm = %.2f", m_LOOPData.StormRain / 100.0); + //m_task->trace("Storm Start Date = 202020"); + //PrintDate(m_LOOPData.wStormStart); + //m_task->trace("Day Rain= %.2f", m_LOOPData.RainDay / 100.0); + //m_task->trace("Month Rain = %.2f", m_LOOPData.RainMonth / 100.0); + //m_task->trace("Year Rain = %.2f", m_LOOPData.RainYear / 100.0); + //m_task->trace("Day ET = %d", m_LOOPData.ETDay); + //m_task->trace("Month ET = %d", m_LOOPData.ETMonth); + //m_task->trace("XmitBat = %d", m_LOOPData.XmitBatt); + m_task->trace("Battery Voltage = %.1f", ((m_LOOPData.BattLevel * 300) / 512) / 100.0); + //m_task->trace("Forecast Icon = %d", m_LOOPData.ForeIcon); + //m_task->trace("Foreast Rule = %d", m_LOOPData.Rule); + //m_task->trace("Forecast String = 909090"); //, ForecastString(m_LOOPData.yRule)); + //m_task->trace("Sunrise = ", TimeConvert(m_LOOPData.wSunrise)); + //m_task->trace("Sunset = , TimeConvert(m_LOOPData.wSunset)); + } + + private: + DUNE::Tasks::Task *m_task; + //! State machine state. + ParserStates m_parser_state_OK; + //! State machine state. + ParserStates m_parser_state_LOOP; + //! Checksum. + uint8_t m_csum; + //! Position in buffer. + uint8_t m_cnt; + + //! Frame preamble 1. + static const char c_LF = '\n'; + //! Frame preamble 2. + static const char c_CR = '\r'; + + int CheckCRC(int nCnt, char *pData) + { + int i; + uint16_t wCRC = 0; /* zero checksum to start */ + uint8_t y; + for (i = 0; i < nCnt; i++) + { + y = *(pData)++; + wCRC = crc_table[(wCRC >> 8) ^ y] ^ (wCRC << 8); /* CCITT std */ + } + return wCRC; /* if zero, it passed */ + } + }; + } // namespace VantagePro2 +} // namespace Hardware +#endif \ No newline at end of file diff --git a/src/Sensors/VantagePro2/Task.cmake b/src/Sensors/VantagePro2/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Sensors/VantagePro2/Task.cpp b/src/Sensors/VantagePro2/Task.cpp new file mode 100644 index 0000000000..076a4ce043 --- /dev/null +++ b/src/Sensors/VantagePro2/Task.cpp @@ -0,0 +1,316 @@ +//*************************************************************************** +// Copyright 2007-2021 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Joao Costa * +// Based on: vproweather 1.0 by Joe Jaworski * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include +#include + +// DUNE headers. +#include + +// Local Headers. +#include "Parser.hpp" + +namespace Sensors +{ + //! This task reads data from the Davis Instruments Vantage Pro2 Weather Station. + //! + //! Periodicaly is sent a LOOP command to the serial data logger. It returns the + //! temperature, humidity, wind and rain values measured by the weather station. + //! @author Joao Costa + namespace VantagePro2 + { + using DUNE_NAMESPACES; + + static const unsigned int c_max_csum = 2; + static const unsigned int c_max_buffer = 128; + + enum StateMachineStates + { + //! Stopped State. + SM_STOP, + ///! Ask FW's version + SM_ASK_VERSION, + //! Get for FW's version state + SM_GET_VERSION, + //! Init done state + SM_DONE, + //! No response error state + SM_ERROR + }; + + //! Task arguments. + struct Arguments + { + //! Serial port device. + std::string uart_dev; + //! Serial port baud rate. + unsigned uart_baud; + }; + + struct Task : public DUNE::Tasks::Task + { + //! Serial port handle. + SerialPort *m_uart; + //! Command to be sent via usart. + char m_cmd[c_max_buffer]; + //! Serial input buffer. + char m_buffer[c_max_buffer]; + //! I/O Multiplexer. + Poll m_poll; + //! Parser + Parser *m_parse; + //! Serial buffer in + uint8_t m_bfr[c_max_buffer]; + //! Current state machine's state + StateMachineStates m_sm_state; + //! Timer used for resend the command to firmware + Time::Counter m_timer; + //! LOOP cmd sent flag + bool m_LOOP_sent; + //! + int m_num_bytes; + //! Initiate station flag + bool m_init_station; + //! Ask for loop packages + bool m_init_loop; + //! Task arguments. + Arguments m_args; + + //! Constructor. + //! @param [in] name task name. + //! @param [in] ctx context. + Task(const std::string &name, Tasks::Context &ctx) : DUNE::Tasks::Task(name, ctx), + m_LOOP_sent(false), + m_init_station(true), + m_init_loop(false) + { + param("Serial Port - Device", m_args.uart_dev) + .defaultValue("/dev/ttyUSB0") + .description("Serial port used to communicate with the meteo station"); + + param("Serial Port - Baud Rate", m_args.uart_baud) + .defaultValue("19200") + .description("Serial port baudrate"); + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + } + + //! Resolve entity names. + void + onEntityResolution(void) + { + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + try + { + m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); + m_uart->setCanonicalInput(false); + m_uart->flush(); + + m_poll.add(*m_uart); + } + catch (std::runtime_error &e) + { + throw RestartNeeded(e.what(), 10); + } + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + m_uart->flushInput(); + m_uart->flush(); + + m_parse = new Parser(this); + + m_timer.setTop(2); + + // Wake up console + //m_uart->writeString("\n\r"); + } + + //! Release resources. + void + onResourceRelease(void) + { + if (m_uart != NULL) + { + m_poll.remove(*m_uart); + Memory::clear(m_uart); + } + } + + //! Read data sent by Doris Sampler. + bool + hasNewData(void) + { + if (m_poll.wasTriggered(*m_uart)) + { + std::memset(&m_bfr, '\0', sizeof(m_bfr)); + m_num_bytes = 0; + try + { + m_num_bytes = m_uart->read(m_bfr, sizeof(m_bfr)); + } + catch (std::exception &e) + { + err(DTR("read error: %s"), e.what()); + return false; + } + if (m_num_bytes <= 0) + { + err(DTR("unknown read error")); + return false; + } + else + { + for (uint8_t i = 0; i < m_num_bytes; ++i) + { + if (m_LOOP_sent) + { + if (!m_parse->parseLOOP(m_bfr[i])) + continue; + } + else + { + if (!m_parse->parseOK(m_bfr[i])) + continue; + } + return true; + } + } + } + return false; + } + + //! Creates a Log Book Entry with the VP2's firmware version + //! @return Returns 1 if got version successfully + /*void + getVersion(void) + { + // clear channel and delay + strcpy(m_cmd, "NVER\n"); // make Davis cmd string + m_uart->writeString(m_cmd); + war("NVER\n"); + }*/ + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + // clear channel and delay + if (m_timer.overflow()) + { + if (m_init_station) + { + m_LOOP_sent = false; + strcpy(m_cmd, "NVER\n"); // make Davis cmd string + } + else + { + m_LOOP_sent = true; + strcpy(m_cmd, "LOOP 1\n"); // make Davis cmd string + } + + m_uart->writeString(m_cmd); + m_timer.reset(); + //war("NVER"); + } + + if (m_poll.poll(0.01)) + { + if (hasNewData()) + { + if (m_parse->translate(m_LOOP_sent)) + { + if (m_LOOP_sent) + { + IMC::Temperature m_temp; + m_temp.value = ((float)m_parse->m_LOOPData.OutsideTemp / 10 - 32) * 5/9; + debug("temperature = %.2f", m_temp.value); + + IMC::WindSpeed m_windSpd; + m_windSpd.speed = m_parse->m_LOOPData.WindSpeed; + m_windSpd.direction = Angles::radians(m_parse->m_LOOPData.WindDir); + debug("wind speed = %.2f", m_windSpd.speed); + debug("wind direction = %.2f", m_windSpd.direction); + + IMC::RelativeHumidity m_humidity; + m_humidity.value = m_parse->m_LOOPData.OutsideHum; + debug("outside humidity = %.2f", m_humidity.value); + + Delay::wait(0.2); + + dispatch(m_temp); + dispatch(m_windSpd); + dispatch(m_humidity); + } + else + { + m_init_station = false; + + // Logs the version of the Vantage Pro2 firmware + IMC::LogBookEntry m_version; + m_version.type = IMC::LogBookEntry::LBET_INFO; + m_version.htime = Time::Clock::getSinceEpoch(); + m_version.context = "Vantage Pro2 Firmware Version"; + m_version.text = m_parse->m_console_version; + Delay::wait(0.2); + dispatch(m_version, DF_LOOP_BACK); + } + } + } + } + } + waitForMessages(1.0); + } + }; + } +} +DUNE_TASK \ No newline at end of file diff --git a/src/Sensors/WifiRSSI/Task.cpp b/src/Sensors/WifiRSSI/Task.cpp index ee690fe5b2..3e40d18ddb 100644 --- a/src/Sensors/WifiRSSI/Task.cpp +++ b/src/Sensors/WifiRSSI/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/XR620CTD/Parser.hpp b/src/Sensors/XR620CTD/Parser.hpp index 028da9c6ca..94faf61935 100644 --- a/src/Sensors/XR620CTD/Parser.hpp +++ b/src/Sensors/XR620CTD/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/XR620CTD/Task.cpp b/src/Sensors/XR620CTD/Task.cpp index f894a625f0..7dbd07c2fa 100644 --- a/src/Sensors/XR620CTD/Task.cpp +++ b/src/Sensors/XR620CTD/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Sensors/XchangeSV/Task.cpp b/src/Sensors/XchangeSV/Task.cpp index ae2bf0cec9..c751f76f64 100644 --- a/src/Sensors/XchangeSV/Task.cpp +++ b/src/Sensors/XchangeSV/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -39,10 +39,10 @@ namespace Sensors { struct Arguments { - //! Serial port device. - std::string uart_dev; - //! Serial port baud rate. - unsigned uart_baud; + //! IO device (URI). + std::string io_dev; + //! Power on Delay + double pwr_on_delay; //! Input timeout. double input_timeout; }; @@ -52,28 +52,37 @@ namespace Sensors //! Maximum sound speed value. static const double c_max_speed = 1625.0; - struct Task: public DUNE::Tasks::Task + struct Task: public Hardware::BasicDeviceDriver { //! Sound speed message. IMC::SoundSpeed m_sspeed; //! Serial port handle. - SerialPort* m_uart; - //! Task arguments + IO::Handle* m_handle; + //! Task arguments. Arguments m_args; //! Watchdog. Counter m_wdog; + //! True if IO handle is a SerialPort. + bool m_uart; + //! Read buffer + char m_bfr[32]; Task(const std::string& name, Tasks::Context& ctx): - DUNE::Tasks::Task(name, ctx), - m_uart(NULL) + Hardware::BasicDeviceDriver(name, ctx), + m_handle(nullptr), + m_uart(false) { - param("Serial Port - Device", m_args.uart_dev) + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_DEVELOPER, + true); + + param("IO Port - Device", m_args.io_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); + .description("IO device URI in the form \"tcp://ADDRESS:PORT\" " + "or \"uart://DEVICE:BAUD\""); - param("Serial Port - Baud Rate", m_args.uart_baud) - .defaultValue("19200") - .description("Serial port baud rate"); + param(DTR_RT("Power On Delay"), m_args.pwr_on_delay) + .defaultValue("0.0"); param("Input Timeout", m_args.input_timeout) .defaultValue("4.0") @@ -82,55 +91,55 @@ namespace Sensors .description("Amount of seconds to wait for data before reporting an error"); } - void - onResourceAcquisition(void) + //! Try to connect to the device. + //! @return true if connection was established, false otherwise. + bool + onConnect() override { - setEntityState(IMC::EntityState::ESTA_BOOT, Status::CODE_INIT); + Delay::wait(m_args.pwr_on_delay); try - { - m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_uart->setCanonicalInput(true); - m_uart->flush(); - } - catch (std::runtime_error& e) - { - throw RestartNeeded(e.what(), 30); - } - } - - void - onResourceRelease(void) - { - Memory::clear(m_uart); - } + { + m_handle = openSocketTCP(m_args.io_dev); - bool - sendCommand(const char* cmd, const char* reply) - { - char bfr[128]; + if (m_handle == nullptr) + { + m_handle = openUART(m_args.io_dev); + static_cast(m_handle)->setCanonicalInput(true); + m_uart = true; + } - m_uart->writeString(cmd); + if (m_handle != nullptr) + m_handle->flush(); - if (Poll::poll(*m_uart, 1.0)) + return m_handle != nullptr; + } + catch (...) { - m_uart->readString(bfr, sizeof(bfr)); - if (std::strcmp(bfr, reply) == 0) - return true; + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); } return false; } + //! Disconnect from device. void - onResourceInitialization(void) + onDisconnect() override { - m_uart->writeString("\r"); + Memory::clear(m_handle); + } + + //! Device may be initialized. + void + onInitializeDevice() override + { + m_handle->writeString("\r"); Delay::wait(1.0); - m_uart->flush(); + m_handle->flush(); - if (!sendCommand("\r", "\r\n")) - throw RestartNeeded(DTR("failed to enter command mode"), 5, false); + if (m_uart) + if (!sendCommand("\r", "\r\n")) + throw RestartNeeded(DTR("failed to enter command mode"), 5, false); if (!sendCommand("SET SAMPLE 1 s\r", ">SET SAMPLE 1 s\r\n")) throw RestartNeeded(DTR("failed to set sampling rate"), 5, false); @@ -141,39 +150,53 @@ namespace Sensors m_wdog.setTop(m_args.input_timeout); } - void - onMain(void) + bool + sendCommand(const char* cmd, const char* reply) { - char bfr[32]; + char bfr[128]; - while (!stopping()) + m_handle->writeString(cmd); + + if (Poll::poll(*m_handle, 1.0)) { - consumeMessages(); + m_handle->readString(bfr, sizeof(bfr)); + if (std::strcmp(bfr, reply) == 0) + return true; + } - if (m_wdog.overflow()) - { - setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); - throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); - } + return false; + } + + //! Get data from device. + //! @return true if data was received, false otherwise. + bool + onReadData() override + { + if (m_wdog.overflow()) + { + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + throw RestartNeeded(DTR(Status::getString(CODE_COM_ERROR)), 5); + } - if (!Poll::poll(*m_uart, 1.0)) - continue; + if (!Poll::poll(*m_handle, 1.0)) + return false; - size_t rv = m_uart->readString(bfr, sizeof(bfr)); + size_t rv = m_handle->readString(m_bfr, sizeof(m_bfr)); - if (rv == 0) - throw RestartNeeded(DTR("I/O error"), 5); + if (rv == 0) + throw RestartNeeded(DTR("I/O error"), 5); - if (std::sscanf(bfr, "%f", &m_sspeed.value) != 1) - continue; + if (std::sscanf(m_bfr, "%f", &m_sspeed.value) != 1) + return false; - if ((m_sspeed.value < c_min_speed) || (m_sspeed.value > c_max_speed)) - m_sspeed.value = -1; + if ((m_sspeed.value < c_min_speed) || (m_sspeed.value > c_max_speed)) + m_sspeed.value = -1; - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); - m_wdog.reset(); - dispatch(m_sspeed); - } + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + m_wdog.reset(); + dispatch(m_sspeed); + + return true; } }; } diff --git a/src/Simulators/AcousticModem/Driver.hpp b/src/Simulators/AcousticModem/Driver.hpp new file mode 100644 index 0000000000..ddf3ddbf58 --- /dev/null +++ b/src/Simulators/AcousticModem/Driver.hpp @@ -0,0 +1,458 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Luis Venancio * +//*************************************************************************** + +#ifndef SIMULATORS_ACOUSTICMODEM_DRIVER_HPP_INCLUDED_ +#define SIMULATORS_ACOUSTICMODEM_DRIVER_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include + +namespace Simulators +{ + namespace AcousticModem + { + using DUNE_NAMESPACES; + + //! Sound speed (m/s). + static const double c_sound_speed = 1500; + //! Absolute maximum transmission range. + static const double c_max_range = 3000; + + //! Structure holding transmission/reception operation + //! parameters. + struct Operation + { + Operation(const Operation &op): + is_tx(op.is_tx), + start_time(op.start_time), + msg(op.msg) + {} + + Operation(bool a_is_tx, + double a_start_time, + SimAcousticMessage a_msg): + is_tx(std::move(a_is_tx)), + start_time(std::move(a_start_time)), + msg(std::move(a_msg)) + {} + + //! Transmission flag. + bool is_tx; + //! Absolute time to start receiving. + double start_time; + //! Message to handle. + IMC::SimAcousticMessage msg; + }; + + struct DriverArguments + { + //! Multicast Address. + Address udp_maddr; + //! UDP port. + uint16_t udp_port; + //! Modem type. + std::string modem_type; + //! Trasmission speed. + double tx_speed; + //! Standard deviation for distance probability. + float dst_peak_width; + //! Standard deviation for data size probability. + float dsize_peak_width; + //! PRNG type. + std::string prng_type; + //! PRNG seed. + int prng_seed; + }; + + class Driver: public Concurrency::Thread + { + public: + //! Constructor. + Driver(DriverArguments* a_args, IMC::SimulatedState* a_sstate, Tasks::Task* a_task): + m_task(a_task), + m_args(a_args), + m_sstate(a_sstate), + m_current_op(nullptr) + { + //Initialize UDP socket in multicast + m_sock = new DUNE::Network::UDPSocket(); + m_sock->setMulticastTTL(1); + m_sock->setMulticastLoop(true); + m_sock->joinMulticastGroup(m_args->udp_maddr); + m_sock->bind(m_args->udp_port); + + //Initialize random number generator + m_prng = Random::Factory::create(m_args->prng_type, m_args->prng_seed); + } + + //! Destructor. + ~Driver(void) + { + if (m_sock) + Memory::clear(m_sock); + + Memory::clear(m_prng); + + for (auto op : m_queue) + delete op; + + Memory::clear(m_current_op); + } + + //! Set current operation to transmission operation. + //! @param[in] msg message to transmit. + void + transmit(const IMC::SimAcousticMessage a_msg) + { + setCurrentOperation(Operation(true, a_msg.getTimeStamp(), a_msg)); + } + + //! Overload of transmission for UamTxFrame. + //! @param[in] msg message to transmit. + void + transmit(const IMC::UamTxFrame a_msg) + { + IMC::SimAcousticMessage sim_acoustic_msg; + // Construct simulated acoustic message metadata + Coordinates::toWGS84(*m_sstate, sim_acoustic_msg.lat, sim_acoustic_msg.lon); + sim_acoustic_msg.depth = m_sstate->z; + sim_acoustic_msg.modem_type = m_args->modem_type; + sim_acoustic_msg.txtime = (double)a_msg.data.size() * 8 / m_args->tx_speed; + sim_acoustic_msg.sys_src = m_task->getSystemName(); + + // Copy UamTxFrame data + sim_acoustic_msg.seq = a_msg.seq; + sim_acoustic_msg.sys_dst = a_msg.sys_dst; + sim_acoustic_msg.flags = a_msg.flags; + sim_acoustic_msg.data = a_msg.data; + + // Set header + sim_acoustic_msg.setSource(a_msg.getSource()); + sim_acoustic_msg.setDestination(a_msg.getDestination()); + sim_acoustic_msg.setTimeStamp(); + + transmit(sim_acoustic_msg); + } + + //! Modem is busy if there is a valid current operation. + //! @return true if modem is busy. + bool + isBusy() const + { + return m_current_op; + } + + //! Distance to source vehicle. + //! @param[in] msg current vehicle state. + double + distance(const IMC::SimAcousticMessage* src_state) + { + double lat, lon; + Coordinates::toWGS84(*m_sstate, lat, lon); + + return WGS84::distance(lat, lon, m_sstate->z, + src_state->lat, src_state->lon, src_state->depth); + } + + private: + //! Simulator task + Tasks::Task* m_task; + //! Driver arguments + DriverArguments* m_args; + //! Vehicle simulated state + IMC::SimulatedState* m_sstate; + //! UDP socket. + UDPSocket* m_sock; + //! UDP message buffer. + uint8_t m_buf[1024]; + //! PRNG handle. + Random::Generator* m_prng; + //! Operation queue. + typedef std::vector OpQueue; + OpQueue m_queue; + //! Current operation being handled. + Operation* m_current_op; + //! Timeout counter. + Time::Counter m_operation_timer; + + //! Transmit message over UDP. + //! @param[in] message to transmit. + void + share(const IMC::Message* msg) + { + int n = msg->getSerializationSize(); + IMC::Packet::serialize(msg, m_buf, n); + m_sock->write(m_buf, n, m_args->udp_maddr, m_args->udp_port); + + std::stringstream ss; + msg->toText(ss); + m_task->debug(DTR("Message sent: \n%s"), ss.str().c_str()); + } + + //! Check UDP socket for incoming message. + void + checkIncomingData() + { + Address dummy; + + try + { + if (Poll::poll(*m_sock, 0.01)) + { + size_t n = m_sock->read(m_buf, sizeof(m_buf), &dummy); + IMC::Message* msg = IMC::Packet::deserialize(m_buf, n); + + if (msg->getId() == DUNE_IMC_SIMACOUSTICMESSAGE) + { + IMC::SimAcousticMessage* amsg = static_cast(msg); + parse(amsg); + + std::stringstream ss; + amsg->toText(ss); + m_task->debug("Message received: \n%s", ss.str().c_str()); + } + else + { + m_task->err(DTR("Unexpected simulation message: %s"), msg->getName()); + } + delete msg; + } + } + catch(std::runtime_error& e) + { + m_task->err(DTR("Read error: %s"), e.what()); + } + } + + //! Compute delivery time and add operation to queue. + //! @param[in] a_msg message to add to queue. + void + receive(IMC::SimAcousticMessage a_msg) + { + double start_time = a_msg.getTimeStamp() + + distance(&a_msg)/c_sound_speed; + + addToQueue(new Operation(false, start_time, a_msg)); + } + + //! Add an operation to queue. + //! @param[in] a_op operation to add to queue. + void + addToQueue(Operation* a_op) + { + m_queue.push_back(a_op); + } + + //! Check if received message should be added to queue. + //! @param[in] amsg message to add to queue. + //! @return true if message is parsed. + bool + parse(const IMC::SimAcousticMessage* a_msg) + { + // Check destination and modem compatibility + bool check; + // Specific destination + check = a_msg->sys_dst == m_task->getSystemName(); + // or Broadcast + check |= ((a_msg->sys_dst == "broadcast") & (a_msg->sys_src != m_task->getSystemName())); + // and modem type + check &= a_msg->modem_type == m_args->modem_type; + if (!check) + return false; + + // Simulate data loss + double dist = distance(a_msg); + if (deliverySucceeds(dist, a_msg->data.size())) + { + receive(*a_msg); + return true; + } + + return false; + } + + //! Simulate random successful delivery + //! based on gaussian model of distance and data size. + //! @param[in] distance distance to source vehicle. + //! @param[in] data_size size of message data. + //! @return true if delivery is successful + bool + deliverySucceeds(double distance, uint16_t data_size) + { + // Out of range + if (distance > c_max_range) + return false; + + // Gaussian profiles for distance and msg size + float dist_prob = exp(-1 * (distance*distance)/(2 * m_args->dst_peak_width * m_args->dst_peak_width)); + float size_prob = exp(-1 * (float)(data_size*data_size)/ + (2 * m_args->dsize_peak_width * m_args->dsize_peak_width)); + + return m_prng->uniform() <= dist_prob*size_prob; + } + + //! Attempt to set an operation as the current operation. + //! @param[in] a_op candidate to current operation. + //! @return true if current operation is set. + bool + setCurrentOperation(Operation a_op) + { + if (!collisionLogic(a_op)) + return false; + + Memory::replace(m_current_op, new Operation(a_op)); + m_operation_timer.setTop(a_op.msg.txtime); + return true; + } + + // TODO: Explain collision logic + // TODO: Expand to allow 3+ way collisions + //! Message collision logic goes here. + //! Collision logic: + //! if Tx or Rx operation is ongoing + //! and Rx arrives -> both are dropped + //! @param[in] a_op new operation candidate + //! @return true if no collision is detected + bool + collisionLogic(Operation a_op) + { + if (!isBusy()) + return true; + + if (!a_op.is_tx) + Memory::clear(m_current_op); + + return false; + } + + //! Check message queue for a valid delivery time. + void + checkQueue() + { + if (m_queue.empty()) + return; + + auto it = m_queue.begin(); + while (it != m_queue.end()) + { + Operation* op = (*it); + if (op->start_time <= Clock::getSinceEpoch()) + { + setCurrentOperation(*op); + + //Remove from queue + delete op; + m_queue.erase(it); + } + else + { + ++it; + } + } + } + + //! Main. + //! Check for valid curret operation and execute. + void + run() + { + while (!isStopping()) + { + checkIncomingData(); + checkQueue(); + + // Ready to execute operation + if (!(m_current_op && m_operation_timer.overflow())) + continue; + + if (m_current_op->is_tx) // Transmission Op + { + std::string str; + try + { + share(&m_current_op->msg); + str = "IP"; + } + catch (std::runtime_error& e) + { + str = "FAILED"; + str += e.what(); + } + dispatch(str); + + Memory::clear(m_current_op); + } + else // Reception Op + { + m_current_op->msg.setDestination(m_task->getSystemId()); + m_current_op->msg.setDestinationEntity(m_task->getEntityId()); + + m_task->dispatch(&m_current_op->msg, DF_LOOP_BACK); + + IMC::SimAcousticMessage request = m_current_op->msg; + Memory::clear(m_current_op); + + if (request.flags == IMC::SimAcousticMessage::SAM_ACK) + sendRangeReply(&request); + } + } + } + + //! Build range request reply and send. + //! @param[in] range_request range request message. + void + sendRangeReply(const IMC::SimAcousticMessage* range_request) + { + IMC::UamTxFrame msg; + msg.seq = range_request->seq; + msg.sys_dst = range_request->sys_src; + msg.flags = IMC::SimAcousticMessage::SAM_REPLY; + + transmit(msg); + } + + //! Dispatch DevDataText to acoustic modem task. + //! @param[in] str string to send. + void + dispatch(const std::string& str) + { + IMC::DevDataText msg; + msg.setDestination(m_task->getSystemId()); + msg.setDestinationEntity(m_task->getEntityId()); + msg.value.assign(str); + m_task->dispatch(msg, DF_LOOP_BACK); + } + }; + } +} + +#endif diff --git a/src/Simulators/AcousticModem/Task.cpp b/src/Simulators/AcousticModem/Task.cpp index 7017cff86c..4cf13f8fe2 100644 --- a/src/Simulators/AcousticModem/Task.cpp +++ b/src/Simulators/AcousticModem/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -24,182 +24,347 @@ // https://github.com/LSTS/dune/blob/master/LICENCE.md and * // http://ec.europa.eu/idabc/eupl.html. * //*************************************************************************** -// Author: José Braga * +// Author: Luis Venancio * //*************************************************************************** +// TODO: Add support for USBL simulation +// (requires modification of the USBL simulator). + // DUNE headers. #include +#include "Driver.hpp" + namespace Simulators { - //! This task simulates a (simplified) acoustic modem. It implements - //! acoustic transmission via a secondary UDP client/server (alternative - //! to Transports::UDP). - //! - //! Transmission requests coming in the form of DUNE::IMC::UamTxFrame are - //! translated into DUNE::IMC::AcousticMessage structures and are then sent - //! via UDP to a (parametrized) remote UDP address. The same UDP socked is - //! used to receive DUNE::IMC::AcousticMessage from the remote peer which - //! are translated to DUNE::IMC::UamRxFrame + //! Simulates an Acoustic Modem. //! - //! @author José Braga + //! Receives UamTxFrame messages, encapsulates in SimAcousticMessages and sends over + //! UDP multicast. + //! Receives SimAcousticMessages, simulates message travel time and data loss (based + //! on a Gaussian distribution of distance and message size) and sends + //! corresponding UamRxFrame. + //! @author Luis Venancio namespace AcousticModem { using DUNE_NAMESPACES; + //! Timeout time. + static const double c_timeout = 5.0; + + //! Transmission ticket structure. + struct Ticket + { + //! IMC source address. + uint16_t imc_sid; + //! IMC source entity. + uint8_t imc_eid; + //! Sequence number. + uint16_t seq; + //! Wait for ack. + bool ack; + }; + struct Arguments { - //! Local UDP port to listen to datagrams containing IMC::DUNE::AcousticMessage - uint16_t local_port; - //! IPv4 Address of the remote DUNE system also running this task - Address addr; - //! Remote port of the remote DUNE system also running this task - uint16_t port; + //! Modem operation arguments. + DriverArguments driver_args; }; - struct Task: public DUNE::Tasks::Task + struct Task: public Tasks::Task { - //! Buffer capacity. - static const unsigned c_bfr_size = 255; - // Task arguments. + //! Task arguments. Arguments m_args; - // UDP Socket. - UDPSocket* m_sock; - //! Read buffer. - std::vector m_bfr; + //! Current transmission ticket. + Ticket* m_ticket; + //! Timeout counter. + Time::Counter m_timeout; + //! Modem driver handler. + Driver* m_driver; + //! Simulated state. + IMC::SimulatedState* m_sstate; //! Constructor. //! @param[in] name task name. //! @param[in] ctx context. Task(const std::string& name, Tasks::Context& ctx): - DUNE::Tasks::Task(name, ctx), - m_sock(NULL) + Tasks::Task(name, ctx), + m_ticket(nullptr), + m_driver(nullptr), + m_sstate(nullptr) { - param("Local Port", m_args.local_port) - .defaultValue("6021") - .minimumValue("0") - .maximumValue("65535") - .description("Local UDP port"); + param("UDP Communications -- Multicast Address", m_args.driver_args.udp_maddr) + .defaultValue("225.0.2.1") + .description("UDP multicast address for communications"); + + param("UDP Communications -- Port", m_args.driver_args.udp_port) + .defaultValue("8021") + .description("UDP port for communications"); + + param("Modem Type", m_args.driver_args.modem_type) + .description("Vehicle modem type (Ex. Evologics, Seatrac)"); + + param("Transmission Speed", m_args.driver_args.tx_speed) + .description("Modem transmission speed (bps)"); + + param("Distance Standard Deviation", m_args.driver_args.dst_peak_width) + .defaultValue("750"); - param("Destination UDP Address", m_args.addr) - .defaultValue("172.0.0.1") - .description("IP address of remote system"); + param("Size Standard Deviation", m_args.driver_args.dsize_peak_width) + .defaultValue("800"); - param("Destination UDP Port", m_args.port) - .defaultValue("6022") - .minimumValue("0") - .maximumValue("65535") - .description("UDP port of remote system"); + param("PRNG Type", m_args.driver_args.prng_type) + .defaultValue(Random::Factory::c_default); - m_bfr.resize(c_bfr_size); + param("PRNG Seed", m_args.driver_args.prng_seed) + .defaultValue("-1"); + // Register consumers. + bind(this); + bind(this); bind(this); + bind(this); + bind(this); } - //! Update internal state with new parameter values. + //! Initialize resources. void - onUpdateParameters(void) + onResourceAcquisition(void) + { + m_sstate = new IMC::SimulatedState; + m_driver = new Driver(&m_args.driver_args, m_sstate, this); + m_driver->start(); + + //Deactivate until SimulatedState message is received + requestDeactivation(); + } + + //! Release resources. + void + onResourceRelease(void) { - if (isActive()) + if (m_driver) { - if (paramChanged(m_args.addr)) - throw RestartNeeded(DTR("restarting to change IPv4 address"), 1); + m_driver->stopAndJoin(); + Memory::clear(m_driver); + } + + Memory::clear(m_sstate); + clearTicket(IMC::UamTxStatus::UTS_CANCELED); + } - if (paramChanged(m_args.port)) - throw RestartNeeded(DTR("restarting to change UDP port"), 1); + //! Clear ticket and send status. + //! @param[in] reason status to send. + //! @param[in] error error message, if available. + void + clearTicket(IMC::UamTxStatus::ValueEnum reason, const std::string& error = "") + { + if (m_ticket != nullptr) + { + sendTxStatus(*m_ticket, reason, error); + Memory::clear(m_ticket); } } - //! Acquire resources by binding to the local UDP port. + //! Replace current ticket. + //! @param[in] ticket ticket to replae current. + //! @param[in] reason status to send. void - onResourceAcquisition(void) + replaceTicket(const Ticket* ticket) { - m_sock = new UDPSocket; - m_sock->bind(m_args.local_port, Address::Any, false); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + clearTicket(IMC::UamTxStatus::UTS_CANCELED); + m_ticket = new Ticket(*ticket); + m_timeout.setTop(c_timeout); } - //! Release resources. Clears UDP socket. + //! Send status. + //! @param[in] ticket ticket to return status. + //! @param[in] value status to send. + //! @param[in] error error message, if available. void - onResourceRelease(void) + sendTxStatus(const Ticket& ticket, IMC::UamTxStatus::ValueEnum value, + const std::string& error = "") { - Memory::clear(m_sock); + IMC::UamTxStatus status; + status.setDestination(ticket.imc_sid); + status.setDestinationEntity(ticket.imc_eid); + status.seq = ticket.seq; + status.value = value; + status.error = error; + dispatch(status); } - //! Translates transmission request to a DUNE::IMC::AcousticMessage and - //! forwards the message to the remote peer. void consume(const IMC::UamTxFrame* msg) { - // Only use local UamTxFrame. if (msg->getSource() != getSystemId()) return; - // Serialize AcousticMessage. - IMC::AcousticMessage amsg; - amsg.setSource(getSystemId()); - amsg.setSourceEntity(getEntityId()); - amsg.setTimeStamp(); - amsg.message.set(*msg); + if (msg->getDestinationEntity() != 255 && msg->getDestinationEntity() != getEntityId()) + return; - size_t rv = IMC::Packet::serialize(&amsg, (uint8_t*)&m_bfr[0], (uint16_t)m_bfr.size()); + // Create and fill new ticket. + Ticket ticket; + ticket.imc_sid = msg->getSource(); + ticket.imc_eid = msg->getSourceEntity(); + ticket.seq = msg->seq; + ticket.ack = (msg->flags == IMC::UamTxFrame::UTF_ACK); - debug("acoustic message to %s", msg->sys_dst.c_str()); + if (msg->sys_dst == getSystemName()) + { + sendTxStatus(ticket, IMC::UamTxStatus::UTS_INV_ADDR); + return; + } - try + if (m_driver->isBusy()) { - m_sock->write((const uint8_t*)&m_bfr[0], rv, m_args.addr, m_args.port); + sendTxStatus(ticket, IMC::UamTxStatus::UTS_BUSY); + return; } - catch (...) - { } + + m_driver->transmit(*msg); + + replaceTicket(&ticket); + sendTxStatus(ticket, IMC::UamTxStatus::UTS_IP); + } + + void + consume(const IMC::SimAcousticMessage* amsg) + { + if (amsg->getDestination() != getSystemId()) + return; + + if (amsg->getDestinationEntity() != getEntityId()) + return; + + if (amsg->flags == IMC::SimAcousticMessage::SAM_REPLY) + rcvRxRange(amsg); + else + rcvRxFrame(amsg); } - //! Read incoming datagrams. If incoming data is a DUNE::IMC::AcousticMessage, - //! and contains a DUNE::IMC::UamTxFrame (inline) it gets translated to a - //! @publish DUNE::IMC::UamRxFrame and gets posted to the local bus. void - readData(void) + consume(const IMC::DevDataText* msg) { - if (!Poll::poll(*m_sock, 1.0)) + if (msg->getDestination() != getSystemId()) return; - size_t rv = m_sock->read(&m_bfr[0], m_bfr.size()); - IMC::Message* msg = IMC::Packet::deserialize((uint8_t*)&m_bfr[0], rv); + if (msg->getDestinationEntity() != getEntityId()) + return; + + if (String::startsWith(msg->value, "DONE")) + { + if (!m_ticket) + return; - if (msg->getId() == DUNE_IMC_ACOUSTICMESSAGE) + if (!m_ticket->ack) + return; + + clearTicket(IMC::UamTxStatus::UTS_DONE); + debug("Ticket cleared"); + } + else if (String::startsWith(msg->value, "IP")) + { + if (!m_ticket) + return; + + debug("Message is being sent"); + } + else if (String::startsWith(msg->value, "FAILED")) + { + int offset = 0; + std::sscanf(msg->value.c_str(), "FAILED%n", &offset); + + if ((unsigned)offset == msg->value.size()) + clearTicket(IMC::UamTxStatus::UTS_FAILED); + else + clearTicket(IMC::UamTxStatus::UTS_FAILED, msg->value.substr(offset+1)); + } + else { - const IMC::AcousticMessage* am = static_cast(msg); - const IMC::Message* m = am->message.get(); - - if (m->getId() == DUNE_IMC_UAMTXFRAME) - { - const IMC::UamTxFrame* frame = static_cast(m); - - // Check if we are the right destination - if (resolveSystemName(frame->sys_dst) != getSystemId()) - return; - - // Process data. - IMC::UamRxFrame rx; - rx.sys_src = resolveSystemId(msg->getSource()); - rx.sys_dst = getSystemName(); - rx.data = frame->data; - debug("received acoustic message from %s", rx.sys_src.c_str()); - dispatch(rx); - } + err(DTR("Unknown transmission status: %s"), msg->value.c_str()); } } - //! Main loop. + void + consume(const IMC::GpsFix* msg) + { + if (msg->type != IMC::GpsFix::GFT_MANUAL_INPUT) + return; + + if(!isActive()) + requestActivation(); + + // Define vehicle origin. + m_sstate->lat = msg->lat; + m_sstate->lon = msg->lon; + m_sstate->height = msg->height; + } + + void + consume(const IMC::SimulatedState* msg) + { + if(!isActive()) + requestActivation(); + + *m_sstate = *msg; + } + + //! Parse SimAcousticMessage into UamRxFrame and send. + //! @param[in] amsg SimAcousticMessage encapsulating UamRxFrame data. + void + rcvRxFrame(const IMC::SimAcousticMessage* amsg) + { + IMC::UamRxFrame rx; + rx.sys_src = amsg->sys_src; + rx.sys_dst = amsg->sys_dst; + rx.data = amsg->data; + + if (getSystemName() != amsg->sys_dst) + rx.flags = IMC::UamRxFrame::URF_PROMISCUOUS; + + rx.setTimeStamp(); + + dispatch(rx); + } + + //! Parse SimAcousticMessage into UamRxRange and send. + //! @param[in] amsg SimAcousticMessage encapsulating UamRxRange data. + void + rcvRxRange(const IMC::SimAcousticMessage* amsg) + { + IMC::UamRxRange range; + range.sys = amsg->sys_src; + range.seq = amsg->seq; + range.value = m_driver->distance(amsg); + range.setTimeStamp(); + + dispatch(range); + clearTicket(IMC::UamTxStatus::UTS_DONE); + } + + //! Check timeout counter for overflow if there is + //! an open transmission ticket. + void + checkTimeout() + { + if (!m_ticket) + return; + + if (m_ticket->ack && m_timeout.overflow()) + clearTicket(IMC::UamTxStatus::UTS_FAILED); + } + void onMain(void) { while (!stopping()) { - consumeMessages(); + //Reference: Sensors/GPS Reader.hpp + checkTimeout(); + // m_driver->run(); - if (m_sock != NULL) - readData(); + waitForMessages(0.1); } } }; diff --git a/src/Simulators/CDC3/Task.cmake b/src/Simulators/CDC3/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Simulators/CDC3/Task.cpp b/src/Simulators/CDC3/Task.cpp new file mode 100644 index 0000000000..97a2c5e55c --- /dev/null +++ b/src/Simulators/CDC3/Task.cpp @@ -0,0 +1,569 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: tsm * +//*************************************************************************** + +// DUNE headers. +#include + +namespace Simulators +{ + //! Insert short task description here. + //! + //! Insert explanation on task behaviour here. + //! @author tsm + namespace CDC3 + { + using DUNE_NAMESPACES; + + // Synchronization byte. + static const uint8_t c_sync = 0xCD; + static const uint8_t c_poly = 0x07; + + enum AcommsCodes + { + //! Acoustic report + CODE_ENABLE_MESSAGE = 0x01, + //! Acoustic report + CODE_REPORT = 0x03, + //! Target of Interest + CODE_TOI = 0x04, + //! Retask mission + CODE_RETASK_MISSION = 0x05, + //! Retask to Waypoint + CODE_RETASK_WP = 0x06, + //! Extended format + CODE_EXT = 0x07 + }; + + struct EnableMessage + { + //! Message ordinal + uint8_t m_msg_ordinal; + //! Mission ID + uint8_t m_enable_disable; + }; + + struct Report + { + float lat; + float lon; + uint8_t depth; + int16_t yaw; + int16_t alt; + int8_t progress; + uint8_t fuel_level; + uint8_t fuel_conf; + }; + + struct TargetOfInterest + { + uint32_t hashCode; + uint32_t timestamp; + float lat; + float lon; + uint32_t sourceId; + int8_t confidence; + }; + + struct RetaskMission + { + //! Time of request in seconds + uint32_t m_timestamp_s; + //! Mission ID + uint32_t m_mission_id; + }; + + struct RetaskWaypoint + { + //! Time of request in seconds + uint32_t m_timestamp_s; + //! Latitude in radians + fp32_t m_lat_rads; + //! Longitude in radians + fp32_t m_lon_rads; + //! Speed in meters per second + fp32_t m_speed_mps; + }; + + + struct Arguments + { + //! EnableMessage periodicty + int period_enable; + //! Report periodicty + int period_report; + //! TargetOfInterest periodicty + int period_toi; + //! RetaskMission periodicty + int period_rtm; + //! RetaskWaypoint periodicty + int period_rtw; + //! IMC Source + std::string src; + //! IMC destination + std::string dest; + //! Override EstimatedState Lat and Lon + bool override_location; + //! Origin latitude in degrees + double origin_lat_degs; + //! Origin longitude in degrees + double origin_lon_degs; + //! toi latitude in degrees + double toi_lat_degs; + //! toi longitude in degrees + double toi_lon_degs; + //! Retask mission id + int retask_mission_id; + //! Enable msg ordinal + int enbl_ordinal; + //! Enable value (0=Disable, 1=Enable, 2->255=minutes from reception to be enable) + int enbl_value; + }; + + struct Task: public DUNE::Tasks::Task + { + Time::Counter m_wdog_enable; + Time::Counter m_wdog_report; + Time::Counter m_wdog_toi; + Time::Counter m_wdog_rtm; + Time::Counter m_wdog_rtw; + IMC::EstimatedState* m_eestate; + std::vector m_bfr; + Arguments m_args; + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx) + { + param("Period -- Enable", m_args.period_enable) + .defaultValue("-1") + .units(Units::Second) + .description(""); + + param("Period -- Report", m_args.period_report) + .defaultValue("1") + .units(Units::Second) + .description(""); + + param("Period -- TargetOfInterest", m_args.period_toi) + .defaultValue("-1") + .units(Units::Second) + .description(""); + + param("Period -- RetaskMission", m_args.period_rtm) + .defaultValue("-1") + .units(Units::Second) + .description(""); + + param("Period -- RetaskWaypoint", m_args.period_rtw) + .defaultValue("-1") + .units(Units::Second) + .description(""); + + param("Source", m_args.src) + .defaultValue("lauv-nemo-1") + .description(""); + + param("Destination", m_args.dest) + .defaultValue("iver-3055") + .description(""); + + param("Override Location", m_args.override_location) + .defaultValue("false") + .description(""); + + param("Origin Latitude", m_args.origin_lat_degs) + .defaultValue("33.28413") + .units(Units::Degree) + .description(""); + + param("Origin Longitude", m_args.origin_lon_degs) + .defaultValue("-117.46737") + .units(Units::Degree) + .description(""); + + param("TargetOfInterest Latitude", m_args.toi_lat_degs) + .defaultValue("21.43422") + .units(Units::Degree) + .description(""); + + param("TargetOfInterest Longitude", m_args.toi_lon_degs) + .defaultValue("-157.78612") + .units(Units::Degree) + .description(""); + + param("Retask Mission ID", m_args.retask_mission_id) + .defaultValue("10") + .description(""); + + param("Enable Message Ordinal", m_args.enbl_ordinal) + .defaultValue("3") + .description(""); + + param("Enable Value", m_args.enbl_value) + .defaultValue("2") + .description(""); + + m_bfr.resize(255); + bind(this); + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + m_wdog_enable.setTop(m_args.period_enable); + m_wdog_report.setTop(m_args.period_report); + m_wdog_toi.setTop(m_args.period_toi); + m_wdog_rtm.setTop(m_args.period_rtm); + m_wdog_rtw.setTop(m_args.period_rtw); + } + + void + consume(const IMC::EstimatedState* estate) + { + m_eestate = estate->clone(); + } + + void + sendAcomms(const std::vector& data) + { + inf("Send Acomms"); + Algorithms::CRC8 crc(c_poly); + + std::vector frame; + frame.reserve(data.size()); + + frame.push_back(c_sync); + crc.putByte(c_sync); + for (size_t i = 0; i < data.size(); ++i) + { + frame.push_back(data[i]); + crc.putByte(data[i]); + } + frame.push_back(crc.get()); + + IMC::UamRxFrame rx; + rx.sys_src = m_args.src; + rx.sys_dst = m_args.dest; + rx.data = frame; + + debug("%s", Utils::String::toHex(frame).c_str()); + + dispatch(rx); + } + + void + sendEnable(void) + { + if (m_wdog_enable.getTop() == -1 || !m_wdog_enable.overflow()) + return; + + EnableMessage enbl; + enbl.m_msg_ordinal = m_args.enbl_ordinal; + enbl.m_enable_disable = m_args.enbl_value; + + std::vector data; + data.resize(sizeof(enbl.m_msg_ordinal) + sizeof(enbl.m_enable_disable) + 1); + data[0] = CODE_ENABLE_MESSAGE; + + unsigned idx = 1; + std::memcpy(&data[idx], &enbl.m_msg_ordinal, sizeof(enbl.m_msg_ordinal)); + idx += sizeof(enbl.m_msg_ordinal); + + std::memcpy(&data[idx], &enbl.m_enable_disable, sizeof(enbl.m_enable_disable)); + idx += sizeof(enbl.m_enable_disable); + + war("%s", Utils::String::toHex(data).c_str()); + debug("%d, %d", + enbl.m_msg_ordinal, + enbl.m_enable_disable); + sendAcomms(data); + m_wdog_enable.reset(); + } + + void + sendRetaskWaypoint(void) + { + if (m_eestate == NULL || m_wdog_rtw.getTop() == -1 || !m_wdog_rtw.overflow()) + return; + + double lat = 0; + double lon = 0; + Coordinates::toWGS84(*m_eestate, lat, lon); + + RetaskWaypoint rtw; + rtw.m_timestamp_s = Time::Clock::getSinceEpoch(); + + if (!m_args.override_location) + { + rtw.m_lat_rads = lat; + rtw.m_lon_rads = lon; + } + else + { + rtw.m_lat_rads = Angles::radians(m_args.origin_lat_degs); + rtw.m_lon_rads = Angles::radians(m_args.origin_lon_degs); + } + + rtw.m_speed_mps = m_eestate->u; + + std::vector data; + data.resize(sizeof(rtw.m_lat_rads) + sizeof(rtw.m_lon_rads) + sizeof(rtw.m_speed_mps) + sizeof(rtw.m_timestamp_s) + 1); + data[0] = CODE_RETASK_WP; + + int idx = 1; + std::memcpy(&data[idx], &rtw.m_timestamp_s, sizeof(rtw.m_timestamp_s)); + idx += sizeof(rtw.m_timestamp_s); + + std::memcpy(&data[idx], &rtw.m_lat_rads, sizeof(rtw.m_lat_rads)); + idx += sizeof(rtw.m_lat_rads); + + std::memcpy(&data[idx], &rtw.m_lon_rads, sizeof(rtw.m_lon_rads)); + idx += sizeof(rtw.m_lon_rads); + + std::memcpy(&data[idx], &rtw.m_speed_mps, sizeof(rtw.m_speed_mps)); + idx += sizeof(rtw.m_speed_mps); + + war("%s", Utils::String::toHex(data).c_str()); + war("%d, %lf %lf %lf", + rtw.m_timestamp_s, + rtw.m_lat_rads, + rtw.m_lon_rads, + rtw.m_speed_mps); + sendAcomms(data); + m_wdog_rtw.reset(); + } + + void + sendRetaskMission(void) + { + if (m_wdog_rtm.getTop() == -1 || !m_wdog_rtm.overflow()) + return; + + RetaskMission rtm; + rtm.m_timestamp_s = Time::Clock::getSinceEpoch(); + rtm.m_mission_id = m_args.retask_mission_id; + + std::vector data; + data.resize(sizeof(rtm.m_mission_id) + sizeof(rtm.m_timestamp_s) + 1); + data[0] = CODE_RETASK_MISSION; + + unsigned idx = 1; + std::memcpy(&data[idx], &rtm.m_timestamp_s, sizeof(rtm.m_timestamp_s)); + idx += sizeof(rtm.m_timestamp_s); + + std::memcpy(&data[idx], &rtm.m_mission_id, sizeof(rtm.m_mission_id)); + idx += sizeof(rtm.m_mission_id); + + war("%s", Utils::String::toHex(data).c_str()); + debug("%d, %d", + rtm.m_timestamp_s, + rtm.m_mission_id); + sendAcomms(data); + m_wdog_rtm.reset(); + } + + void + sendReport(void) + { + if (m_eestate == NULL || m_wdog_report.getTop() == -1 || !m_wdog_report.overflow()) + return; + + double lat = 0; + double lon = 0; + Coordinates::toWGS84(*m_eestate, lat, lon); + + Report dat; + + if (!m_args.override_location) + { + dat.lat = lat; + dat.lon = lon; + } + else + { + dat.lat = Angles::radians(m_args.origin_lat_degs); + dat.lon = Angles::radians(m_args.origin_lon_degs); + } + + dat.depth = (uint8_t)m_eestate->depth; + dat.yaw = (int16_t)(m_eestate->psi * 100.0); + dat.alt = (int16_t)(m_eestate->alt * 10.0); + dat.fuel_level = 50.0; + dat.fuel_conf = 99.0; + dat.progress = 0; + + std::vector data; + data.resize(sizeof(dat.lat) + + sizeof(dat.lon) + + sizeof(dat.depth) + + sizeof(dat.yaw) + + sizeof(dat.alt) + + sizeof(dat.progress) + + sizeof(dat.fuel_level) + + sizeof(dat.fuel_conf) + 1); + data[0] = CODE_REPORT; + + int idx = 1; + std::memcpy(&data[idx], &dat.lat, sizeof(dat.lat)); + idx += sizeof(dat.lat); + + std::memcpy(&data[idx], &dat.lon, sizeof(dat.lon)); + idx += sizeof(dat.lon); + + std::memcpy(&data[idx], &dat.depth, sizeof(dat.depth)); + idx += sizeof(dat.depth); + + std::memcpy(&data[idx], &dat.yaw, sizeof(dat.yaw)); + idx += sizeof(dat.yaw); + + std::memcpy(&data[idx], &dat.alt, sizeof(dat.alt)); + idx += sizeof(dat.alt); + + std::memcpy(&data[idx], &dat.progress, sizeof(dat.progress)); + idx += sizeof(dat.progress); + + std::memcpy(&data[idx], &dat.fuel_level, sizeof(dat.fuel_level)); + idx += sizeof(dat.fuel_level); + + std::memcpy(&data[idx], &dat.fuel_conf, sizeof(dat.fuel_conf)); + idx += sizeof(dat.fuel_conf); + + war("%s", Utils::String::toHex(data).c_str()); + debug("%f, %f, %d, %d, %d, %d, %d, %d", + dat.lat, + dat.lon, + dat.depth, + dat.yaw, + dat.alt, + dat.progress, + dat.fuel_level, + dat.fuel_conf); + sendAcomms(data); + m_wdog_report.reset(); + } + + inline static int64_t positionToInteger(const double& pos) + { + return (int64_t) std::round((double) pos * 1e6); + } + + inline uint32_t calculateHash(const uint32_t& seconds, const double& latDeg, const double& lonDeg, const uint32_t& sourceId) const + { + // http://stackoverflow.com/a/1646913/126995 + uint32_t rtn = 17; + rtn = rtn * 31 + (uint32_t) std::hash()(((int64_t)seconds * 1000)); + rtn = rtn * 31 + (uint32_t) std::hash()(positionToInteger(latDeg)); + rtn = rtn * 31 + (uint32_t) std::hash()(positionToInteger(lonDeg)); + rtn = rtn * 31 + (uint32_t) std::hash()(sourceId); + return rtn; + } + + void + sendTargetOfInterest(void) + { + if (m_eestate == NULL || m_wdog_toi.getTop() == -1 || !m_wdog_toi.overflow()) + return; + + static const uint32_t initialTime = Time::Clock::getSinceEpoch(); + + double lat = Angles::radians(m_args.toi_lat_degs); + double lon = Angles::radians(m_args.toi_lon_degs); + + TargetOfInterest toi; + + toi.timestamp = initialTime; + toi.lat = lat; + toi.lon = lon; + toi.sourceId = 0x00470101; + toi.confidence = 43; + + toi.hashCode = calculateHash(initialTime, toi.lat, toi.lon, toi.sourceId ); + + std::vector data; + data.resize(sizeof (toi.hashCode) + + sizeof (toi.timestamp) + + sizeof (toi.lat) + + sizeof (toi.lon) + + sizeof (toi.sourceId) + + sizeof (toi.confidence) + 1); + + data[0] = CODE_TOI; + + int idx = 1; + std::memcpy(&data[idx], &toi.hashCode, sizeof (toi.hashCode)); + idx += sizeof (toi.hashCode); + + std::memcpy(&data[idx], &toi.timestamp, sizeof (toi.timestamp)); + idx += sizeof (toi.timestamp); + + std::memcpy(&data[idx], &toi.lat, sizeof (toi.lat)); + idx += sizeof (toi.lat); + + std::memcpy(&data[idx], &toi.lon, sizeof (toi.lon)); + idx += sizeof (toi.lon); + + std::memcpy(&data[idx], &toi.sourceId, sizeof (toi.sourceId)); + idx += sizeof (toi.sourceId); + + std::memcpy(&data[idx], &toi.confidence, sizeof (toi.confidence)); + idx += sizeof (toi.confidence); + + war("%s", Utils::String::toHex(data).c_str()); + debug("%d, %d, %f, %f, %d, %d", + toi.hashCode, + toi.sourceId, + toi.lat, + toi.lon, + toi.timestamp, + (int) toi.confidence); + sendAcomms(data); + m_wdog_toi.reset(); + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + sendEnable(); + sendReport(); + sendTargetOfInterest(); + sendRetaskMission(); + sendRetaskWaypoint(); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Simulators/CTD/Task.cpp b/src/Simulators/CTD/Task.cpp index f79f27ebaf..26c26fafba 100644 --- a/src/Simulators/CTD/Task.cpp +++ b/src/Simulators/CTD/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/DVL/Task.cpp b/src/Simulators/DVL/Task.cpp index 136bd0530e..ced105e536 100644 --- a/src/Simulators/DVL/Task.cpp +++ b/src/Simulators/DVL/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/DepthSensor/Task.cpp b/src/Simulators/DepthSensor/Task.cpp index 977d1720b3..e708b4366b 100644 --- a/src/Simulators/DepthSensor/Task.cpp +++ b/src/Simulators/DepthSensor/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Docking/Task.cpp b/src/Simulators/Docking/Task.cpp index 41722746c6..c95fc36aad 100644 --- a/src/Simulators/Docking/Task.cpp +++ b/src/Simulators/Docking/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Environment/Bounds.hpp b/src/Simulators/Environment/Bounds.hpp index 2428299a80..9e8e25ba91 100644 --- a/src/Simulators/Environment/Bounds.hpp +++ b/src/Simulators/Environment/Bounds.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Environment/Point.hpp b/src/Simulators/Environment/Point.hpp index 7484699191..dfa7f1a682 100644 --- a/src/Simulators/Environment/Point.hpp +++ b/src/Simulators/Environment/Point.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Environment/QuadTree.cpp b/src/Simulators/Environment/QuadTree.cpp index 8783745224..d52393e363 100644 --- a/src/Simulators/Environment/QuadTree.cpp +++ b/src/Simulators/Environment/QuadTree.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Environment/QuadTree.hpp b/src/Simulators/Environment/QuadTree.hpp index 000248c9b7..42a781d4ed 100644 --- a/src/Simulators/Environment/QuadTree.hpp +++ b/src/Simulators/Environment/QuadTree.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Environment/Task.cpp b/src/Simulators/Environment/Task.cpp index 7a6d6128fb..c1402b4447 100644 --- a/src/Simulators/Environment/Task.cpp +++ b/src/Simulators/Environment/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/GPS/Task.cpp b/src/Simulators/GPS/Task.cpp index e4dcecf36c..8ac903af60 100644 --- a/src/Simulators/GPS/Task.cpp +++ b/src/Simulators/GPS/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Gaussian/Task.cpp b/src/Simulators/Gaussian/Task.cpp index 33b8e68df1..bf537ca954 100644 --- a/src/Simulators/Gaussian/Task.cpp +++ b/src/Simulators/Gaussian/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/IMU/Task.cpp b/src/Simulators/IMU/Task.cpp index ac25640c89..d83937ffc9 100644 --- a/src/Simulators/IMU/Task.cpp +++ b/src/Simulators/IMU/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -63,6 +63,8 @@ namespace Simulators double gyro_bias; //! Measures Euler Angles messages. bool euler; + //! Outputs velocity and euler angles deltas + bool deltas; //! Activation Control bool activation_control; //! PRNG type. @@ -80,6 +82,10 @@ namespace Simulators IMC::AngularVelocity m_agvel; //! Acceleration. IMC::Acceleration m_accel; + //! Velocity Delta + IMC::VelocityDelta m_vdel; + //! Euler Angles Delta + IMC::EulerAnglesDelta m_agdel; //! Stored Velocity. double m_vel[3]; //! Pseudo-random generator. @@ -123,6 +129,10 @@ namespace Simulators .defaultValue("true") .description("Some IMUs do not output Euler Angles measurements"); + param("Output Deltas", m_args.deltas) + .defaultValue("false") + .description("Activates output of Velocity and Euler Angles Delta"); + param("Activation Control", m_args.activation_control) .defaultValue("false") .description("True if it is possible to actively control the device"); @@ -229,6 +239,25 @@ namespace Simulators dispatch(m_agvel, DF_KEEP_TIME); dispatch(m_accel, DF_KEEP_TIME); + // Compute deltas + if (m_args.deltas) + { + m_vdel.x = m_accel.x * tstep; + m_vdel.y = m_accel.y * tstep; + m_vdel.z = m_accel.z * tstep; + + m_agdel.x = m_agvel.x * tstep; + m_agdel.y = m_agvel.y * tstep; + m_agdel.z = m_agvel.z * tstep; + + m_agdel.timestep = tstep; + + m_agdel.setTimeStamp(msg->getTimeStamp()); + m_vdel.setTimeStamp(msg->getTimeStamp()); + dispatch(m_agdel, DF_KEEP_TIME); + dispatch(m_vdel, DF_KEEP_TIME); + } + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); } diff --git a/src/Simulators/Iridium/Task.cmake b/src/Simulators/Iridium/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Simulators/Iridium/Task.cpp b/src/Simulators/Iridium/Task.cpp new file mode 100644 index 0000000000..f99130356b --- /dev/null +++ b/src/Simulators/Iridium/Task.cpp @@ -0,0 +1,165 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: José Pinto * +//*************************************************************************** + +// DUNE headers. +#include +#include + +using DUNE_NAMESPACES; + +namespace Simulators +{ + //! This task simulates Iridium communications + //! by posting messages directly to Ripples + namespace Iridium + { + //! %Task arguments. + struct Arguments + { + //! Server hostname + std::string server_address; + //! Server port + int server_port; + //! Server path + std::string server_path; + }; + + bool m_send_empty = false; + + //! + struct Task: public Tasks::Periodic + { + //! Task arguments. + Arguments m_args; + + Task(const std::string& name, Tasks::Context& ctx): + Tasks::Periodic(name, ctx) + { + // Retrieve configuration values. + param("Server Address", m_args.server_address) + .defaultValue("127.0.0.1"); + + param("Server Port", m_args.server_port) + .defaultValue("8888"); + + param("Server Path", m_args.server_path) + .defaultValue("/api/v1/irsim"); + + setFrequency(0.2); + + // Register consumers. + bind(this); + } + + + //! Acquire resources. + void + onResourceAcquisition(void) + { + setEntityState(EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + + std::string asHex(int byte) { + char b[3]; + sprintf(b, "%02X", byte & 0xFF); + return std::string(b); + } + + //! + void + consume(const IMC::IridiumMsgTx* msg) + { + + IMC::IridiumTxStatus status; + status.req_id = msg->req_id; + status.setDestination(msg->getSource()); + status.setDestinationEntity(msg->getSourceEntity()); + + m_send_empty = false; + + std::stringstream ss; + ss << "POST " << m_args.server_path << " HTTP/1.1\r\n"; + ss << "Host: " << m_args.server_address << "\r\n"; + ss << "Content-Type: application/hub\r\n"; + ss << "Content-Length: "<< msg->data.size()*2 << "\r\n\r\n"; + + std::vector::const_iterator it = msg->data.begin(); + for(; it != msg->data.end(); it++) + { + ss << asHex(*it); + } + debug("POSTING: %s", ss.str().c_str()); + inf("Sent message with %d bytes to %s:%d%s", (int) msg->data.size(), + m_args.server_address.c_str(), m_args.server_port, m_args.server_path.c_str()); + try { + TCPSocket* sock = new TCPSocket(); + char incoming[65535] = {0}; + + Network::Address addr(m_args.server_address.c_str()); + sock->connect(addr, m_args.server_port); + std::string data = ss.str(); + sock->write(data.c_str(), data.length()); + sock->flushOutput(); + int read = sock->read(incoming, 65535); + if (read > 0) + incoming[read] = 0; + + debug("RESPONSE: %s", incoming); + + Memory::clear(sock); + + status.status = IMC::IridiumTxStatus::TXSTATUS_OK; + status.text = "Transmitted to Ripples (Simulation)"; + dispatch(status); + } + catch (Exception &e) { + err("Error while posting: %s", e.what()); + status.status = IMC::IridiumTxStatus::TXSTATUS_ERROR; + status.text = e.what(); + dispatch(status); + } + m_send_empty = true; + } + + //! @publish DUNE::IMC::IridiumMsgRx + void + task(void) + { + if (m_send_empty) + { + IMC::IridiumTxStatus status; + status.status = IridiumTxStatus::TXSTATUS_EMPTY; + dispatch(status); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Simulators/LBL/Task.cpp b/src/Simulators/LBL/Task.cpp index fb131b705c..0c9b3af3bf 100644 --- a/src/Simulators/LBL/Task.cpp +++ b/src/Simulators/LBL/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Leaks/Task.cpp b/src/Simulators/Leaks/Task.cpp index 1403e39a28..5abca29058 100644 --- a/src/Simulators/Leaks/Task.cpp +++ b/src/Simulators/Leaks/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Motor/Task.cpp b/src/Simulators/Motor/Task.cpp index 4d8ca6c814..d7875103be 100644 --- a/src/Simulators/Motor/Task.cpp +++ b/src/Simulators/Motor/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/Reporter/Task.cpp b/src/Simulators/Reporter/Task.cpp new file mode 100644 index 0000000000..fb2ae019de --- /dev/null +++ b/src/Simulators/Reporter/Task.cpp @@ -0,0 +1,245 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: tsm * +//*************************************************************************** + +// DUNE headers. +#include + +namespace Simulators +{ + //! Insert short task description here. + //! + //! Insert explanation on task behaviour here. + //! @author tsm + namespace Reporter + { + using DUNE_NAMESPACES; + + // Synchronization byte. + static const uint8_t c_sync = 0xCD; + static const uint8_t c_poly = 0x07; + + enum Codes + { + CODE_ABORT = 0x00, + CODE_RANGE = 0x01, + CODE_PLAN = 0x02, + CODE_REPORT = 0x03, + CODE_RESTART = 0x04, + CODE_RAW = 0x05, + CODE_USBL = 0x06 + }; + + struct Report + { + float lat; + float lon; + uint8_t depth; + int16_t yaw; + int16_t alt; + int8_t progress; + uint8_t fuel_level; + uint8_t fuel_conf; + }; + + struct Arguments + { + int period; + std::string dest; + bool as_struct; + }; + + struct Task: public DUNE::Tasks::Task + { + Time::Counter m_timer; + IMC::EstimatedState* m_eestate; + std::vector m_bfr; + Arguments m_args; + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_eestate(NULL) + { + param("Period", m_args.period) + .defaultValue("10") + .units(Units::Second) + .description(""); + + param("Destination", m_args.dest) + .defaultValue("lauv-noptilus-1") + .description(""); + + param("As Struct", m_args.as_struct) + .defaultValue("true") + .description(""); + + m_bfr.resize(255); + bind(this); + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + m_timer.setTop(m_args.period); + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + } + + //! Release resources. + void + onResourceRelease(void) + { + Memory::clear(m_eestate); + } + + void + consume(const IMC::EstimatedState* msg) + { + m_eestate = msg->clone(); + } + + void + sendReport(const std::vector& data) + { + inf("Send Report"); + Algorithms::CRC8 crc(c_poly); + + std::vector frame; + frame.reserve(data.size()); + + frame.push_back(c_sync); + crc.putByte(c_sync); + for (size_t i = 0; i < data.size(); ++i) + { + frame.push_back(data[i]); + crc.putByte(data[i]); + } + frame.push_back(crc.get()); + + IMC::UamRxFrame rx; + rx.sys_src = resolveSystemId(getSystemId()); + rx.sys_dst = m_args.dest; + rx.data = frame; + + debug("%s", Utils::String::toHex(frame).c_str()); + + dispatch(rx); + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + + if (m_eestate == NULL || !m_timer.overflow()) + continue; + + double lat = 0; + double lon = 0; + Coordinates::toWGS84(*m_eestate, lat, lon); + + Report dat; + dat.lat = lat; + dat.lon = lon; + dat.depth = (uint8_t)m_eestate->depth; + dat.yaw = (int16_t)(m_eestate->psi * 100.0); + dat.alt = (int16_t)(m_eestate->alt * 10.0); + dat.fuel_level = 50.0; + dat.fuel_conf = 99.0; + dat.progress = 0; + + std::vector data; + data.resize(sizeof(dat) + 1); + data[0] = CODE_REPORT; + + if (m_args.as_struct) + std::memcpy(&data[1], &dat, sizeof(dat)); + else + { + int idx = 1; + std::memcpy(&data[idx], &dat.lat, sizeof(dat.lat)); + idx += sizeof(dat.lat); + + std::memcpy(&data[idx], &dat.lon, sizeof(dat.lon)); + idx += sizeof(dat.lon); + + std::memcpy(&data[idx], &dat.depth, sizeof(dat.depth)); + idx += sizeof(dat.depth); + + std::memcpy(&data[idx], &dat.yaw, sizeof(dat.yaw)); + idx += sizeof(dat.yaw); + + std::memcpy(&data[idx], &dat.alt, sizeof(dat.alt)); + idx += sizeof(dat.alt); + + std::memcpy(&data[idx], &dat.progress, sizeof(dat.progress)); + idx += sizeof(dat.progress); + + std::memcpy(&data[idx], &dat.fuel_level, sizeof(dat.fuel_level)); + idx += sizeof(dat.fuel_level); + + std::memcpy(&data[idx], &dat.fuel_conf, sizeof(dat.fuel_conf)); + idx += sizeof(dat.fuel_conf); + } + + war("%s", Utils::String::toHex(data).c_str()); + debug("%f, %f, %d, %d, %d, %d, %d, %d", + dat.lat, + dat.lon, + dat.depth, + dat.yaw, + dat.alt, + dat.progress, + dat.fuel_level, + dat.fuel_conf); + sendReport(data); + m_timer.reset(); + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Simulators/Servos/Task.cpp b/src/Simulators/Servos/Task.cpp index 96482ec36a..68384db177 100644 --- a/src/Simulators/Servos/Task.cpp +++ b/src/Simulators/Servos/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp b/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp new file mode 100644 index 0000000000..cdddd960e4 --- /dev/null +++ b/src/Simulators/StreamVelocity/ModelDataStreamGenerator.cpp @@ -0,0 +1,141 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#include "DUNE/Coordinates.hpp" +#include "DUNE/I18N.hpp" + +#include "ModelDataStreamGenerator.hpp" + +namespace Simulators +{ + namespace StreamVelocity + { + namespace StreamGenerator + { + Gridded2DModelDataStreamGenerator::Gridded2DModelDataStreamGenerator( + GriddedModelDataConfig const& config, + double wx, + double wy, + double wz) + : StreamGenerator(wx, wy, wz), + m_file(config.filename), + m_u(0), + m_v(0), + m_grid(m_file.getAttribute(config.grid_path, "min"), + m_file.getAttribute(config.grid_path, "max"), + m_file.getAttribute(config.grid_path, "npts")) + { + auto data_u = m_file.getDataset(config.u_data_path); + auto data_v = m_file.getDataset(config.v_data_path); + + if (data_u.dimensions != data_v.dimensions) + throw std::runtime_error( + DTR("Gridded2DModelDataStreamGenerator::" + "Gridded2DModelDataStreamGenerator(): dimensions of velocity " + "components do not match.")); + + if (data_u.dimensions.size() != 3) + throw std::runtime_error( + DTR("Gridded2DModelDataStreamGenerator::" + "Gridded2DModelDataStreamGenerator(): data must be " + "three-dimensional (2D space + time).")); + + if (m_grid.getDimensions(0) != data_u.dimensions[0] || + m_grid.getDimensions(1) != data_u.dimensions[1] || + m_grid.getDimensions(2) != data_u.dimensions[2]) + throw std::runtime_error( + DTR("Gridded2DModelDataStreamGenerator::" + "Gridded2DModelDataStreamGenerator(): data dimensions do not " + "match grid dimensions.")); + + m_u = std::move(data_u.data); + m_v = std::move(data_v.data); + } + + inline double + interpolateLinear2d(double* values, double* delta) + { + return (1 - delta[0]) * (1 - delta[1]) * values[0] + + delta[0] * (1 - delta[1]) * values[1] + + delta[0] * delta[1] * values[2] + + (1 - delta[0]) * delta[1] * values[3]; + } + + std::array + Gridded2DModelDataStreamGenerator::getVelocity(double lat, + double lon, + double, + double time) const + { + // Find closest grid cell + auto corner_indices = + m_grid.getCorner({lat, lon, time + m_grid.getLower(2)}); + + // If vehicles is outside the grid, fall back to default stream velocity + for (auto i = 0; i < 3; ++i) + if (corner_indices[i] >= m_grid.getDimensions(i)) + return getDefaultVelocity(); + + auto corner_point = m_grid.getCoordinates(corner_indices); + + double delta[2] = {(lat - corner_point[0]) / m_grid.getSpacing(0), + (lon - corner_point[1]) / m_grid.getSpacing(1)}; + + double u_values[4]; + double v_values[4]; + + // Interpolate data to the current vehicle position and current time. + // This scheme uses nearest-neighbor interpolation in time and linear + // interpolation for the position. + // TODO Allow configurable interpolation schemes. + + auto gridpoint = corner_indices; + u_values[0] = m_u[m_grid.getOffset(gridpoint)]; + v_values[0] = m_v[m_grid.getOffset(gridpoint)]; + + gridpoint[0] += 1; + u_values[1] = m_u[m_grid.getOffset(gridpoint)]; + v_values[1] = m_v[m_grid.getOffset(gridpoint)]; + + gridpoint[1] += 1; + u_values[2] = m_u[m_grid.getOffset(gridpoint)]; + v_values[2] = m_v[m_grid.getOffset(gridpoint)]; + + gridpoint[0] -= 1; + u_values[3] = m_u[m_grid.getOffset(gridpoint)]; + v_values[3] = m_v[m_grid.getOffset(gridpoint)]; + + auto u_val = interpolateLinear2d(u_values, delta); + auto v_val = interpolateLinear2d(v_values, delta); + + return {v_val, u_val, 0.0}; + } + } // namespace StreamGenerator + } // namespace StreamVelocity +} // namespace Simulators diff --git a/src/Simulators/StreamVelocity/ModelDataStreamGenerator.hpp b/src/Simulators/StreamVelocity/ModelDataStreamGenerator.hpp new file mode 100644 index 0000000000..893b257cb3 --- /dev/null +++ b/src/Simulators/StreamVelocity/ModelDataStreamGenerator.hpp @@ -0,0 +1,107 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#ifndef SIMULATORS_STREAM_VELOCITY_MODEL_DATA_STREAM_GENERATOR_HPP_INCLUDED_ +#define SIMULATORS_STREAM_VELOCITY_MODEL_DATA_STREAM_GENERATOR_HPP_INCLUDED_ + +#include +#include + +#include "DUNE/Parsers/HDF5Reader.hpp" +#include "DUNE/Math/Grid.hpp" + +#include "StreamGenerator.hpp" + +namespace Simulators +{ + namespace StreamVelocity + { + namespace StreamGenerator + { + // Configuration parameters for stream generators which use model data + // stored on disk to generate the stream velocity values. + struct ModelDataConfig + { + //! Path to the file containing the data. + std::string filename; + //! Path to the node in the file containing the velocity values in the + //! East direction. + std::string u_data_path; + //! Path to the node in the file containing the velocity values in the + //! North direction. + std::string v_data_path; + // TODO std::string units; + }; + + // Extra configuration parameters if the model is gridded. + struct GriddedModelDataConfig : public ModelDataConfig + { + //! Path to the node in the file containing the grid parameters. + std::string grid_path; + }; + + //! Get stream velocity values from 2D (horizontal velocities) model data + //! on a cartesian grid. + //! Uses the HDF5 format to load the stream values. + class Gridded2DModelDataStreamGenerator : public StreamGenerator + { + public: + //! Constructor. + //! @param[in] config structure containing the configuration parameters + //! for reading the data from the file. + //! @param[in] wx default stream speed in the North direction (m/s). + //! @param[in] wy default stream speed in the East direction (m/s). + //! @param[in] wz default stream speed in the Down direction (m/s). + Gridded2DModelDataStreamGenerator(GriddedModelDataConfig const& config, + double wx = 0.0, + double wy = 0.0, + double wz = 0.0); + + ~Gridded2DModelDataStreamGenerator() = default; + + virtual std::array + getVelocity(double lat, + double lon, + double depth, + double time = 0.0) const override; + + private: + DUNE::Parsers::HDF5Reader m_file; + //! Velocity in the East direction. + std::vector m_u; + //! Velocity in the North direction. + std::vector m_v; + //! Converts between grid indices and datapoint indices. + DUNE::Math::Grid<3> m_grid; + }; + } // namespace StreamGenerator + } // namespace StreamVelocity +} // namespace Simulators + +#endif diff --git a/src/Simulators/StreamVelocity/StreamGenerator.cpp b/src/Simulators/StreamVelocity/StreamGenerator.cpp new file mode 100644 index 0000000000..8051f73777 --- /dev/null +++ b/src/Simulators/StreamVelocity/StreamGenerator.cpp @@ -0,0 +1,63 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#include "StreamGenerator.hpp" + +namespace Simulators +{ + namespace StreamVelocity + { + namespace StreamGenerator + { + StreamGenerator::StreamGenerator(double wx, double wy, double wz) + : m_wx(wx), m_wy(wy), m_wz(wz) + {} + + std::array + StreamGenerator::getVelocity(double, double, double, double) const + { + return getDefaultVelocity(); + } + + std::array + StreamGenerator::getDefaultVelocity() const + { + return {m_wx, m_wy, m_wz}; + } + + void + StreamGenerator::setVelocity(double wx, double wy, double wz) + { + m_wx = wx; + m_wy = wy; + m_wz = wz; + } + } // namespace StreamGenerator + } // namespace StreamVelocity +} // namespace Simulators diff --git a/src/Simulators/StreamVelocity/StreamGenerator.hpp b/src/Simulators/StreamVelocity/StreamGenerator.hpp new file mode 100644 index 0000000000..bd33f21132 --- /dev/null +++ b/src/Simulators/StreamVelocity/StreamGenerator.hpp @@ -0,0 +1,92 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#ifndef SIMULATORS_STREAM_VELOCITY_STREAM_GENERATOR_HPP_INCLUDED_ +#define SIMULATORS_STREAM_VELOCITY_STREAM_GENERATOR_HPP_INCLUDED_ + +#include + +namespace Simulators +{ + namespace StreamVelocity + { + namespace StreamGenerator + { + // A simple interface for any sort of source of velocity values. + // This base class just provides a constant value. + class StreamGenerator + { + public: + //! Constructor. + //! @param[in] wx default stream speed in the North direction (m/s). + //! @param[in] wy default stream speed in the East direction (m/s). + //! @param[in] wz default stream speed in the Down direction (m/s). + StreamGenerator(double wx, double wy, double wz = 0.0); + + ~StreamGenerator() = default; + + //! Get a stream velocity value. + //! @param[in] lat WGS84 latitude in degrees. + //! @param[in] lon WGS84 longitude in degrees. + //! @param[in] depth depth in meters. + //! @param[in] time time elapsed since the simulation started. + //! @return 3-dimensional array containing the stream velocity in the + //! North, East and Down directions in meters per second. + virtual std::array + getVelocity(double lat, + double lon, + double depth, + double time = 0.0) const; + + //! Get the default stream velocity. + //! @return 3-dimensional array containing the default stream velocity + //! value in the North, East and Down directions in meters per second. + std::array + getDefaultVelocity() const; + + //! Set the default stream velocity. + //! @param[in] wx default stream speed in the North direction (m/s). + //! @param[in] wy default stream speed in the East direction (m/s). + //! @param[in] wz default stream speed in the Down direction (m/s). + void + setVelocity(double wx, double wy, double wz = 0.0); + + private: + //! Default speed North. + double m_wx; + //! Default speed East. + double m_wy; + //! Default speed Down. + double m_wz; + }; + } // namespace StreamGenerator + } // namespace StreamVelocity +} // namespace Simulators + +#endif diff --git a/src/Simulators/StreamVelocity/StreamGeneratorFactory.hpp b/src/Simulators/StreamVelocity/StreamGeneratorFactory.hpp new file mode 100644 index 0000000000..2410795dd2 --- /dev/null +++ b/src/Simulators/StreamVelocity/StreamGeneratorFactory.hpp @@ -0,0 +1,83 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +#ifndef SIMULATORS_STREAM_VELOCITY_STREAM_GENERATOR_FACTORY_HPP_INCLUDED_ +#define SIMULATORS_STREAM_VELOCITY_STREAM_GENERATOR_FACTORY_HPP_INCLUDED_ + +#include + +#include "DUNE/I18N.hpp" + +#include "ModelDataStreamGenerator.hpp" +#include "StreamGenerator.hpp" + +namespace Simulators +{ + namespace StreamVelocity + { + namespace StreamGenerator + { + //! Factory method for the stream velocity source. + //! @param[in] config structure with configuration fields + //! @return handle to the stream velocity source. + template + std::unique_ptr + factory(Configuration const& config) + { + if (config.type == "Constant") + return std::make_unique( + config.default_wx, config.default_wy, config.default_wz); + if (config.type == "Gridded 2D Model Data") + { + GriddedModelDataConfig mdcfg; + mdcfg.filename = config.filename; + // Path to the dataset in the file containing the velocity values in + // the East direction, given in m/s as u = u(Lat, Lon, Time). + mdcfg.u_data_path = "u"; + // Path to the dataset in the file containing the velocity values in + // the North direction, given in m/s as v = v(Lat, Lon, Time). + mdcfg.v_data_path = "v"; + //! Path to the node in the file containing the grid data. + //! This node should include the following child nodes: + //! min - array with the lower grid limits. + //! max - array with the upper grid limits. + //! npts - array with the number of points in each dimension. + mdcfg.grid_path = "grid"; + + return std::make_unique( + mdcfg, config.default_wx, config.default_wy, config.default_wz); + } + else + throw std::runtime_error(DTR("Unknown stream velocity source type.")); + } + } // namespace StreamGenerator + } // namespace StreamVelocity +} // namespace Simulators + +#endif diff --git a/src/Simulators/StreamVelocity/Task.cmake b/src/Simulators/StreamVelocity/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Simulators/StreamVelocity/Task.cpp b/src/Simulators/StreamVelocity/Task.cpp new file mode 100644 index 0000000000..342e9e6e7e --- /dev/null +++ b/src/Simulators/StreamVelocity/Task.cpp @@ -0,0 +1,232 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Miguel Aguiar * +//*************************************************************************** + +// Standard library headers. +#include +#include +#include + +// DUNE headers. +#include + +// Local headers. +#include "StreamGeneratorFactory.hpp" + +namespace Simulators +{ + //! Produces stream velocity values. + //! + //! Fetches current or wind velocity values from a specified source (e.g., a + //! file with model data) and packs them into an IMC EstimatedStreamVelocity + //! message. + //! Currently supports only a single vehicle. + //! @author Miguel Aguiar + namespace StreamVelocity + { + using DUNE_NAMESPACES; + + struct Arguments + { + //! Determines how the stream values are generated. + std::string type; + + //! Default stream speed in the North direction (m/s) + double default_wx; + //! Default stream speed in the East direction (m/s) + double default_wy; + //! Default stream speed in the Down direction (m/s) + double default_wz; + + //! Configurations for loading stream velocity data from a file. + //! Path to file containing the data. + std::string filename; + + //! Advance the simulation by some time, if using forecasted data. + struct + { + unsigned days_fwd; + unsigned hours_fwd; + unsigned minutes_fwd; + unsigned seconds_fwd; + } date; + }; + + struct Task : public DUNE::Tasks::Periodic + { + //! Task arguments. + Arguments m_args; + //! Source for stream velocity values. + std::unique_ptr m_ssg; + //! Dispatched EstimatedStreamVelocity message + IMC::EstimatedStreamVelocity m_esv; + //! Latest consumed SimulatedState + IMC::SimulatedState m_state; + //! Time offset in seconds. + double m_time0; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx) + : DUNE::Tasks::Periodic(name, ctx), m_ssg(nullptr) + { + bind(this); + + param("Stream Velocity Source", m_args.type) + .defaultValue("Constant") + .description("Source of the stream speed values."); + + param("Default Speed North", m_args.default_wx) + .units(Units::MeterPerSecond) + .defaultValue("0.0") + .description("Default stream speed in the North direction (m/s)"); + + param("Default Speed East", m_args.default_wy) + .units(Units::MeterPerSecond) + .defaultValue("0.0") + .description("Default stream speed in the East direction (m/s)"); + + param("Default Speed Down", m_args.default_wz) + .units(Units::MeterPerSecond) + .defaultValue("0.0") + .description("Default stream speed in the Down direction (m/s)"); + + param("File", m_args.filename) + .defaultValue("") + .description("Path to the file containg the stream velocity data."); + + param("Days Forward", m_args.date.days_fwd) + .defaultValue("0") + .description( + "Number of days to advance the simulation by, relative to the " + "time of the first datapoint."); + + param("Hours Forward", m_args.date.hours_fwd) + .defaultValue("0") + .description( + "Number of hours to advance the simulation by, relative to the " + "time of the first datapoint."); + + param("Minutes Forward", m_args.date.minutes_fwd) + .defaultValue("0") + .description( + "Number of minutes to advance the simulation by, relative to " + "the time of the first datapoint."); + + param("Seconds Forward", m_args.date.seconds_fwd) + .defaultValue("0") + .description( + "Number of seconds to advance the simulation by, relative to " + "the time of the first datapoint."); + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + debug(DTR("Setting default stream velocity: %f m/s N : %f m/s E : " + "%f m/s D"), + m_args.default_wx, + m_args.default_wy, + m_args.default_wz); + + m_esv.x = m_args.default_wx; + m_esv.y = m_args.default_wy; + m_esv.z = m_args.default_wz; + + try + { + m_ssg = StreamGenerator::factory(m_args); + } + catch (std::exception const& e) + { + err(DTR("An error ocurred while accessing the stream velocity source:" + "\n" + "\t%s\n" + "\tFalling back to constant stream velocity."), + e.what()); + + m_args.type = "Constant"; + m_ssg = StreamGenerator::factory(m_args); + } + + m_time0 = m_args.date.seconds_fwd + 60 * m_args.date.minutes_fwd + + 3600 * m_args.date.hours_fwd + 86400 * m_args.date.days_fwd; + + debug(DTR("Setting initial time delta to %f seconds"), m_time0); + + m_time0 -= DUNE::Time::Clock::get(); + } + + //! Update the EstimatedStreamVelocity message, using the most recent + //! SimulatedState data. + void + updateMessage(void) + { + double lat = m_state.lat; + double lon = m_state.lon; + double height = m_state.height; + + Coordinates::WGS84::displace( + m_state.x, m_state.y, m_state.z, &lat, &lon, &height); + + auto p = m_ssg->getVelocity(Angles::degrees(lat), + Angles::degrees(lon), + -height, + DUNE::Time::Clock::get() + m_time0); + + //! Fill EstimatedStreamVelocity. + m_esv.x = std::isnan(p[0]) ? m_args.default_wx : p[0]; + m_esv.y = std::isnan(p[1]) ? m_args.default_wy : p[1]; + m_esv.z = std::isnan(p[2]) ? m_args.default_wz : p[2]; + + debug(DTR("Stream velocity is %f m/s N : %f m/s E : %f m/s D"), + m_esv.x, + m_esv.y, + m_esv.z); + } + + void + consume(IMC::SimulatedState const* msg) + { + if (msg->getSource() == getSystemId()) + m_state = *msg; + } + + void + task(void) + { + updateMessage(); + dispatch(m_esv); + } + }; + } // namespace StreamVelocity +} // namespace Simulators + +DUNE_TASK diff --git a/src/Simulators/Target/Task.cpp b/src/Simulators/Target/Task.cpp index 1e6c85f66a..73007d7577 100644 --- a/src/Simulators/Target/Task.cpp +++ b/src/Simulators/Target/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/UAV/Task.cpp b/src/Simulators/UAV/Task.cpp index 08c18c2a31..fe89df22ad 100644 --- a/src/Simulators/UAV/Task.cpp +++ b/src/Simulators/UAV/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/UAVAutopilot/Task.cpp b/src/Simulators/UAVAutopilot/Task.cpp index 5bc4804f78..01a4fbd337 100644 --- a/src/Simulators/UAVAutopilot/Task.cpp +++ b/src/Simulators/UAVAutopilot/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/USBL/Task.cpp b/src/Simulators/USBL/Task.cpp index 4ce790205c..7c0105da1b 100644 --- a/src/Simulators/USBL/Task.cpp +++ b/src/Simulators/USBL/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/UnderwaterAcoustics/Task.cpp b/src/Simulators/UnderwaterAcoustics/Task.cpp deleted file mode 100644 index 05cce24a78..0000000000 --- a/src/Simulators/UnderwaterAcoustics/Task.cpp +++ /dev/null @@ -1,397 +0,0 @@ -//*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * -// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * -//*************************************************************************** -// This file is part of DUNE: Unified Navigation Environment. * -// * -// Commercial Licence Usage * -// Licencees holding valid commercial DUNE licences may use this file in * -// accordance with the commercial licence agreement provided with the * -// Software or, alternatively, in accordance with the terms contained in a * -// written agreement between you and Faculdade de Engenharia da * -// Universidade do Porto. For licensing terms, conditions, and further * -// information contact lsts@fe.up.pt. * -// * -// Modified European Union Public Licence - EUPL v.1.1 Usage * -// Alternatively, this file may be used under the terms of the Modified * -// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * -// included in the packaging of this file. You may not use this work * -// except in compliance with the Licence. Unless required by applicable * -// law or agreed to in writing, software distributed under the Licence is * -// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * -// ANY KIND, either express or implied. See the Licence for the specific * -// language governing permissions and limitations at * -// https://github.com/LSTS/dune/blob/master/LICENCE.md and * -// http://ec.europa.eu/idabc/eupl.html. * -//*************************************************************************** -// Author: Eduardo Marques * -//*************************************************************************** - -// ISO C++ 98 headers. -#include -#include -#include -#include - -// DUNE headers. -#include - -namespace Simulators -{ - namespace UnderwaterAcoustics - { - using DUNE_NAMESPACES; - - struct Arguments - { - Address udp_maddr; - uint16_t udp_port; - std::vector location; - bool trace; - //! Gps simulator entity id. - std::string label_gps; - }; - - static const double c_sound_speed = 1500; - static const double c_max_range = 3000; - - struct Task: public Tasks::Task - { - // Task arguments. - Arguments m_args; - - // Flags. - bool m_setup, m_fixed_location; - // Position awareness (of self and others). - uint16_t m_local_imc_addr; - IMC::GpsFix m_origin; - IMC::RemoteState m_lstate; - typedef std::map RStateMap; - RStateMap m_positions; - - // Handling of simulated traffic. - IMC::UASimulation* m_pending; // Pending delivery to self - double m_busy_till; // Time until underwater medium is busy (for collision detection) - double m_send_time; - - // UDP socket and related auxilliary data. - UDPSocket* m_sock; - uint8_t m_buf[1024]; - - Task(const std::string& name, Tasks::Context& ctx): - Tasks::Task(name, ctx), - m_setup(false), - m_fixed_location(false), - m_pending(0), - m_sock(0) - { - param("UDP Communications -- Multicast Address", m_args.udp_maddr) - .defaultValue("225.0.2.1") - .description("UDP multicast address for communications"); - - param("UDP Communications -- Port", m_args.udp_port) - .defaultValue("8021") - .description("UDP port for communications"); - - param("Fixed Location", m_args.location) - .defaultValue("") - .description("WGS84 latitude and longitude for node with fixed position"); - - param("Trace", m_args.trace) - .defaultValue("false") - .description("Enable verbose output"); - - param("Entity Label - GPS", m_args.label_gps) - .description("Entity label of simulated 'GpsFix' messages"); - - // Misc. initialization - m_local_imc_addr = getSystemId(); - m_lstate.setSource(m_local_imc_addr); - m_lstate.setTimeStamp(0); - - // Register consumers. - bind(this); - bind(this); - bind(this); - } - - ~Task(void) - { - onResourceRelease(); - } - - void - onUpdateParameters(void) - { - if (m_args.location.size() == 2) - { - m_fixed_location = true; - m_lstate.clear(); - m_lstate.lat = Angles::radians(m_args.location[0]); - m_lstate.lon = Angles::radians(m_args.location[1]); - m_lstate.depth = 0; - m_setup = true; - } - else - { - m_setup = false; - } - } - - void - onResourceAcquisition(void) - { - m_sock = new DUNE::Network::UDPSocket(); - m_sock->setMulticastTTL(1); - m_sock->setMulticastLoop(true); - m_sock->joinMulticastGroup(m_args.udp_maddr); - m_sock->bind(m_args.udp_port); - } - - void - onResourceRelease(void) - { - if (m_pending) - { - delete m_pending; - m_pending = 0; - } - - if (m_sock) - { - delete m_sock; - m_sock = 0; - } - } - - void - share(const IMC::Message* msg) - { - // Share message over the UDP multicast socket. - int n = msg->getSerializationSize(); - IMC::Packet::serialize(msg, m_buf, n); - m_sock->write(m_buf, n, m_args.udp_maddr, m_args.udp_port); - } - - void - updatePosition(const IMC::RemoteState* rstate) - { - if (m_positions.find(rstate->getSource()) == m_positions.end()) - { - debug("%s | part of network", - resolveSystemId(rstate->getSource())); - } - - m_positions[rstate->getSource()] = *rstate; - - if (m_args.trace) - { - debug("%s (%u) -- position: %0.4f %0.4f %u %0.4f", - resolveSystemId(rstate->getSource()), - rstate->getSource(), Angles::degrees(rstate->lat), - Angles::degrees(rstate->lon), rstate->depth, - distance(m_local_imc_addr, rstate->getSource())); - } - } - - double - distance(int src, int dst) - { - RStateMap::iterator sitr = m_positions.find(src); - RStateMap::iterator ditr = m_positions.find(dst); - - if (sitr == m_positions.end() || ditr == m_positions.end()) - return -1; - - return WGS84::distance(sitr->second.lat, sitr->second.lon, 0, - ditr->second.lat, ditr->second.lon, 0); - } - - void - updateKnowledge(const IMC::UASimulation* m) - { - if (!m_setup) - { - debug("not setup yet"); - return; - } - - uint16_t src = m->getSource(); - - double d = src == m_local_imc_addr ? 0 : distance(src, m_local_imc_addr); - - if (d < 0) - { - debug("can't handle this -- some nodes are not part of simulation (yet?)"); - return; - } - - int bits; - - if (m->type == IMC::UASimulation::UAS_DATA) - bits = 8 * m->data.size(); - else - bits = 1; // well ... :) - - double stime = Clock::get(); - double trip_time = d / c_sound_speed; - double transm_time = ((double)bits) / (double)m->speed; - double etime = stime + trip_time + transm_time; - - double btime = etime; - - if (d < c_max_range) - btime += (c_max_range - d) / c_sound_speed; - - if (src != m_local_imc_addr) - { - debug("%s | distance %0.3f m | trip time %0.3f s | %d bits at %d bps | data transm. %0.3f | total time %0.3f s", - resolveSystemId(src), d, trip_time, - bits, m->speed, transm_time, etime - stime); - } - - if (stime < m_busy_till) - { - err(DTR("collision detected")); - - if (m_pending) - { - delete m_pending; - m_pending = 0; - } - } - else if (src != m_local_imc_addr) - { - m_pending = new IMC::UASimulation(*m); - m_send_time = etime; - } - - if (btime > m_busy_till) - { - debug("collision-prone for %0.2f s", (btime - stime)); - m_busy_till = btime; - } - } - - void - consume(const IMC::GpsFix* msg) - { - if (m_fixed_location) - return; - - if (msg->type != IMC::GpsFix::GFT_MANUAL_INPUT) - return; - - m_setup = true; - m_origin = *msg; - m_busy_till = -1; - } - - void - consume(const IMC::SimulatedState* msg) - { - if (!m_setup || m_fixed_location) - return; - - double tstamp = msg->getTimeStamp(); - - if (tstamp - m_lstate.getTimeStamp() >= 1) - { - double rlat, rlon; - m_lstate.setTimeStamp(tstamp); - rlat = m_origin.lat; - rlon = m_origin.lon; - WGS84::displace(msg->x, msg->y, &rlat, &rlon); - m_lstate.lat = (fp32_t)rlat; - m_lstate.lon = (fp32_t)rlon; - m_lstate.depth = (uint8_t)msg->z; - m_lstate.psi = msg->psi; - m_lstate.speed = msg->u; - share(&m_lstate); - } - } - - void - consume(const IMC::UASimulation* msg) - { - debug("transmitting"); - - if (m_args.trace) - msg->toText(std::cerr); - - share(msg); - } - - void - onMain(void) - { - double last_pos_update = 0; - - while (!stopping()) - { - double now = Clock::get(); - - if (m_fixed_location && now - last_pos_update >= 1) - { - m_lstate.setTimeStamp(); - share(&m_lstate); - last_pos_update = now; - } - - if (m_pending && now >= m_send_time) - { - debug("delivering | time delivery error: %0.4f", - (now - m_send_time)); - - if (m_args.trace) - m_pending->toText(std::cerr); - - dispatch(m_pending, DF_KEEP_TIME); - delete m_pending; - m_pending = 0; - } - - checkIncomingData(); - - waitForMessages(0.1); - } - } - - void - checkIncomingData(void) - { - Address dummy; - - try - { - if (Poll::poll(*m_sock, 0.01)) - { - size_t n = m_sock->read(m_buf, sizeof(m_buf), &dummy); - - IMC::Message* m = IMC::Packet::deserialize(m_buf, n); - - if (m->getId() == DUNE_IMC_REMOTESTATE) - { - updatePosition(static_cast(m)); - } - else if (m->getId() == DUNE_IMC_UASIMULATION) - { - updateKnowledge(static_cast(m)); - } - else - { - err(DTR("unexpected simulation message: %s"), m->getName()); - } - delete m; - } - } - catch (std::runtime_error& e) - { - err(DTR("read error: %s"), e.what()); - } - } - }; - } -} - -DUNE_TASK diff --git a/src/Simulators/VSIM/Factory.cpp b/src/Simulators/VSIM/Factory.cpp index 13c8d4eaac..b9a9702eee 100644 --- a/src/Simulators/VSIM/Factory.cpp +++ b/src/Simulators/VSIM/Factory.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/Factory.hpp b/src/Simulators/VSIM/Factory.hpp index 93960137e3..87a104f6cf 100644 --- a/src/Simulators/VSIM/Factory.hpp +++ b/src/Simulators/VSIM/Factory.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/Task.cpp b/src/Simulators/VSIM/Task.cpp index cf57a391da..7f0ecdcf4f 100644 --- a/src/Simulators/VSIM/Task.cpp +++ b/src/Simulators/VSIM/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -32,6 +32,7 @@ // ISO C++ 98 headers. #include #include +#include #include #include #include @@ -60,10 +61,10 @@ namespace Simulators //! %Task arguments. struct Arguments { - //! Stream speed North parameter (m/s). - double wx; - //! Stream speed East parameter (m/s). - double wy; + //! Entity label of the stream velocity source. + std::string svlabel; + //! Simulation time multiplier + double time_multiplier; }; //! Simulator task. @@ -75,32 +76,39 @@ namespace Simulators Simulators::VSIM::World* m_world; //! Simulated position (X,Y,Z). IMC::SimulatedState m_sstate; - //! Start time. - double m_start_time; //! Task arguments. Arguments m_args; + //! Stream velocity. + double m_svel[3]; Task(const std::string& name, Tasks::Context& ctx): Periodic(name, ctx), m_vehicle(NULL), - m_world(NULL), - m_start_time(Clock::get()) + m_world(NULL) { - // Retrieve configuration values. - param("Stream Speed North", m_args.wx) - .units(Units::MeterPerSecond) - .defaultValue("0.0") - .description("Water current speed along the North in the NED frame"); + param("Time Multiplier", m_args.time_multiplier) + .defaultValue("1.0") + .description("Simulation time multiplier"); - param("Stream Speed East", m_args.wy) - .units(Units::MeterPerSecond) - .defaultValue("0.0") - .description("Water current speed along the East in the NED frame"); + param("Entity Label - Stream Velocity Source", m_args.svlabel) + .defaultValue("Stream Velocity Simulator") + .description("Entity label of the stream velocity source."); // Register handler routines. bind(this); bind(this); bind(this); + bind(this); + } + + void + onUpdateParameters(void) + { + if (m_args.time_multiplier != 1.0) + { + Time::Clock::setTimeMultiplier(m_args.time_multiplier); + war("Using time multiplier: x%.2f", Time::Clock::getTimeMultiplier()); + } } //! Release allocated resources. @@ -127,6 +135,10 @@ namespace Simulators m_world->addVehicle(m_vehicle); m_world->setTimeStep(1.0 / getFrequency()); + m_svel[0] = 0.0; + m_svel[1] = 0.0; + m_svel[2] = 0.0; + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); } @@ -145,8 +157,6 @@ namespace Simulators m_sstate.lon = msg->lon; m_sstate.height = msg->height; - m_start_time = Clock::get(); - requestActivation(); // Save message to cache. @@ -159,7 +169,6 @@ namespace Simulators void consume(const IMC::ServoPosition* msg) { - using Simulators::VSIM::UUV; UUV* v = static_cast(m_vehicle); v->updateFin(msg->id, msg->value); } @@ -170,6 +179,24 @@ namespace Simulators m_vehicle->updateEngine(msg->id, msg->value); } + void + consume(const IMC::EstimatedStreamVelocity* msg) + { + // Filter valid messages. + if (msg->getSource() != getSystemId() || + resolveEntity(msg->getSourceEntity()) != m_args.svlabel) + return; + + m_svel[0] = msg->x; + m_svel[1] = msg->y; + m_svel[2] = msg->z; + + debug(DTR("Setting stream velocity: %f m/s N : %f m/s E : %f m/s D"), + m_svel[0], + m_svel[1], + m_svel[2]); + } + void task(void) { @@ -180,9 +207,17 @@ namespace Simulators // Fill position. double* position = m_vehicle->getPosition(); - double sim_time = Clock::get() - m_start_time; - m_sstate.x = position[0] + sim_time * m_args.wx; - m_sstate.y = position[1] + sim_time * m_args.wy; + + // TODO + // This is a temporary fix and this operation should probably be done + // inside the Vehicle class. + // Add stream velocity. + position[0] += m_world->getTimeStep() * m_svel[0]; + position[1] += m_world->getTimeStep() * m_svel[1]; + position[2] += m_world->getTimeStep() * m_svel[2]; + + m_sstate.x = position[0]; + m_sstate.y = position[1]; m_sstate.z = std::max(position[2], 0.0); // Fill attitude. @@ -204,9 +239,9 @@ namespace Simulators m_sstate.w = lv[2]; // Fill stream velocity. - m_sstate.svx = m_args.wx; - m_sstate.svy = m_args.wy; - m_sstate.svz = 0; + m_sstate.svx = m_svel[0]; + m_sstate.svy = m_svel[1]; + m_sstate.svz = m_svel[2]; dispatch(m_sstate); } diff --git a/src/Simulators/VSIM/VSIM/ASV.cpp b/src/Simulators/VSIM/VSIM/ASV.cpp index 89cfd82d30..1de2277883 100644 --- a/src/Simulators/VSIM/VSIM/ASV.cpp +++ b/src/Simulators/VSIM/VSIM/ASV.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/ASV.hpp b/src/Simulators/VSIM/VSIM/ASV.hpp index 0f099adec3..c0e2eac53d 100644 --- a/src/Simulators/VSIM/VSIM/ASV.hpp +++ b/src/Simulators/VSIM/VSIM/ASV.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Engine.cpp b/src/Simulators/VSIM/VSIM/Engine.cpp index 838c66c598..b5fac32c6f 100644 --- a/src/Simulators/VSIM/VSIM/Engine.cpp +++ b/src/Simulators/VSIM/VSIM/Engine.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Engine.hpp b/src/Simulators/VSIM/VSIM/Engine.hpp index 690f423712..872829beb9 100644 --- a/src/Simulators/VSIM/VSIM/Engine.hpp +++ b/src/Simulators/VSIM/VSIM/Engine.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Fin.cpp b/src/Simulators/VSIM/VSIM/Fin.cpp index 57c76b7eb3..e3fcd5adb3 100644 --- a/src/Simulators/VSIM/VSIM/Fin.cpp +++ b/src/Simulators/VSIM/VSIM/Fin.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Fin.hpp b/src/Simulators/VSIM/VSIM/Fin.hpp index 5dcd24026d..b9423541b7 100644 --- a/src/Simulators/VSIM/VSIM/Fin.hpp +++ b/src/Simulators/VSIM/VSIM/Fin.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Force.cpp b/src/Simulators/VSIM/VSIM/Force.cpp index 50b621b080..fd38956743 100644 --- a/src/Simulators/VSIM/VSIM/Force.cpp +++ b/src/Simulators/VSIM/VSIM/Force.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Force.hpp b/src/Simulators/VSIM/VSIM/Force.hpp index 864536bae4..f4a292ce6e 100644 --- a/src/Simulators/VSIM/VSIM/Force.hpp +++ b/src/Simulators/VSIM/VSIM/Force.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Object.cpp b/src/Simulators/VSIM/VSIM/Object.cpp index b19acfd616..95b99460bf 100644 --- a/src/Simulators/VSIM/VSIM/Object.cpp +++ b/src/Simulators/VSIM/VSIM/Object.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Object.hpp b/src/Simulators/VSIM/VSIM/Object.hpp index a64f0c6cfd..6496548fe8 100644 --- a/src/Simulators/VSIM/VSIM/Object.hpp +++ b/src/Simulators/VSIM/VSIM/Object.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/UUV.cpp b/src/Simulators/VSIM/VSIM/UUV.cpp index d2389ee790..c28c61ae84 100644 --- a/src/Simulators/VSIM/VSIM/UUV.cpp +++ b/src/Simulators/VSIM/VSIM/UUV.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/UUV.hpp b/src/Simulators/VSIM/VSIM/UUV.hpp index a9479f0678..3980f20b1e 100644 --- a/src/Simulators/VSIM/VSIM/UUV.hpp +++ b/src/Simulators/VSIM/VSIM/UUV.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/VSIM.hpp b/src/Simulators/VSIM/VSIM/VSIM.hpp index 77e98ebd83..7adf99168e 100644 --- a/src/Simulators/VSIM/VSIM/VSIM.hpp +++ b/src/Simulators/VSIM/VSIM/VSIM.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Vehicle.cpp b/src/Simulators/VSIM/VSIM/Vehicle.cpp index e9289d804d..bf815f9a87 100644 --- a/src/Simulators/VSIM/VSIM/Vehicle.cpp +++ b/src/Simulators/VSIM/VSIM/Vehicle.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Vehicle.hpp b/src/Simulators/VSIM/VSIM/Vehicle.hpp index 188eaf2f34..6cf2f999a7 100644 --- a/src/Simulators/VSIM/VSIM/Vehicle.hpp +++ b/src/Simulators/VSIM/VSIM/Vehicle.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Volume.cpp b/src/Simulators/VSIM/VSIM/Volume.cpp index e86b122405..b1fe714396 100644 --- a/src/Simulators/VSIM/VSIM/Volume.cpp +++ b/src/Simulators/VSIM/VSIM/Volume.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/Volume.hpp b/src/Simulators/VSIM/VSIM/Volume.hpp index 7a0cc8779e..363da022dc 100644 --- a/src/Simulators/VSIM/VSIM/Volume.hpp +++ b/src/Simulators/VSIM/VSIM/Volume.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/World.cpp b/src/Simulators/VSIM/VSIM/World.cpp index 735b90e096..abde2a655e 100644 --- a/src/Simulators/VSIM/VSIM/World.cpp +++ b/src/Simulators/VSIM/VSIM/World.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Simulators/VSIM/VSIM/World.hpp b/src/Simulators/VSIM/VSIM/World.hpp index 4501c5a245..25c5be255a 100644 --- a/src/Simulators/VSIM/VSIM/World.hpp +++ b/src/Simulators/VSIM/VSIM/World.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/AUV/Assist/Task.cpp b/src/Supervisors/AUV/Assist/Task.cpp index 745e4f7420..01814dcd70 100644 --- a/src/Supervisors/AUV/Assist/Task.cpp +++ b/src/Supervisors/AUV/Assist/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -85,8 +85,6 @@ namespace Supervisors float m_depth; //! Current Medium uint8_t m_medium; - //! Current vehicle state - uint8_t m_vstate; //! Rate of ascent VerticalMonitor* m_vmon; //! Task's state @@ -103,6 +101,8 @@ namespace Supervisors bool m_first_fix; //! RPM value for dislodging the vehicle float m_dislodge_rpm; + //! Current motor status. + bool m_motor; //! Task arguments. Arguments m_args; @@ -137,11 +137,11 @@ namespace Supervisors bind(this); bind(this); - bind(this); bind(this); bind(this); bind(this); bind(this); + bind(this); } void @@ -199,12 +199,6 @@ namespace Supervisors m_ltimer.reset(); } - void - consume(const IMC::VehicleState* msg) - { - m_vstate = msg->op_mode; - } - void consume(const IMC::VehicleMedium* msg) { @@ -219,7 +213,10 @@ namespace Supervisors // reset finish depth if the vehicle comes to the surface if (m_depth < m_args.depth_threshold) + { + m_dislodge_rpm = c_rpm_start; m_finish_depth = -1.0; + } } void @@ -262,6 +259,13 @@ namespace Supervisors } } + void + consume(const IMC::Rpm* msg) + { + //! Motor State + m_motor = (msg->value == 0) ? false : true; + } + //! Check if the received PlanControl message reports to //! a successful Dislodge plan request //! @param[in] msg pointer to PlanControl message @@ -324,8 +328,7 @@ namespace Supervisors bool mainConditions(void) { - if ((m_vstate != IMC::VehicleState::VS_SERVICE) && - (m_vstate != IMC::VehicleState::VS_ERROR)) + if (m_motor) return false; if (!m_first_fix) @@ -365,7 +368,6 @@ namespace Supervisors switch (state) { case ST_IDLE: - m_dislodge_rpm = c_rpm_start; setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); break; case ST_CHECK_STUCK: diff --git a/src/Supervisors/AUV/LostComms/Task.cpp b/src/Supervisors/AUV/LostComms/Task.cpp index 2357463776..717dcf0d3e 100644 --- a/src/Supervisors/AUV/LostComms/Task.cpp +++ b/src/Supervisors/AUV/LostComms/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -322,6 +322,7 @@ namespace Supervisors pc.request_id = 0; pc.plan_id = m_args.plan_name; pc.flags = IMC::PlanControl::FLG_IGNORE_ERRORS; + pc.setDestination(m_ctx.resolver.id()); pc.arg.set(m_plan); dispatch(pc); diff --git a/src/Supervisors/Delegator/Task.cpp b/src/Supervisors/Delegator/Task.cpp index e288b03992..294446ffb9 100644 --- a/src/Supervisors/Delegator/Task.cpp +++ b/src/Supervisors/Delegator/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -59,6 +59,10 @@ namespace Supervisors std::string entity_name; //! Surrogate task name. std::string task_name; + //! Surrogate config section. + std::string config_section; + //! Surrogate system power channel. + std::string power_channel; }; struct Task: public Tasks::Task @@ -68,6 +72,22 @@ namespace Supervisors //! Surrogate entity id. unsigned m_eid; Counter m_query_info_timer; + //! Activation timer. + Counter m_act_countdown; + //! Deactivation timer. + Counter m_deact_countdown; + //! Power channel control. + IMC::PowerChannelControl m_pcc; + //! Power channel state. + IMC::PowerChannelState m_pcs; + //! True if task is activating. + bool m_activating; + //! True if task is deactivating. + bool m_deactivating; + //! PushEntityParameters message. + IMC::PushEntityParameters m_push; + //! Entity Parameter message. + IMC::EntityState m_estate; //! Task arguments. Arguments m_args; @@ -75,7 +95,9 @@ namespace Supervisors Tasks::Task(name, ctx), m_sid(IMC::AddressResolver::invalid()), m_eid(DUNE_IMC_CONST_UNK_EID), - m_query_info_timer(5.0) + m_query_info_timer(5.0), + m_activating(false), + m_deactivating(false) { // Define configuration parameters. paramActive(Tasks::Parameter::SCOPE_MANEUVER, @@ -90,11 +112,19 @@ namespace Supervisors param("Surrogate Task", m_args.task_name) .description("Name of the slave task"); + param("Surrogate Section", m_args.config_section) + .description("Name of the surrogate configuration section"); + + param("Surrogate Power Channel", m_args.power_channel) + .defaultValue("None") + .description("Name of the power channel of the surrogate system. Only use if PCC is for the payload's CPU."); + // Register handler routines. bind(this); bind(this); bind(this); bind(this); + bind(this); } bool @@ -103,10 +133,13 @@ namespace Supervisors if (m_args.task_name.empty()) return false; - Tasks::Task* task = Tasks::Factory::produce(m_args.task_name, "Surrogate", m_ctx); - if (task == NULL) + Tasks::Task* task = Tasks::Factory::produce(m_args.task_name, m_args.config_section, m_ctx); + if (task == nullptr) throw std::invalid_argument(Utils::String::str(DTR("invalid task name '%s'"), m_args.task_name.c_str())); + Path cfg_path = (m_ctx.dir_cfg / m_args.system_name + ".ini"); + m_ctx.config.parseFile(cfg_path.c_str()); + try { task->setEntityLabel(getEntityLabel()); @@ -133,6 +166,14 @@ namespace Supervisors onResourceInitialization(void) { setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + + m_pcc.name = m_args.power_channel; + m_pcs.name = m_args.power_channel; + m_act_countdown.setTop(getActivationTime()); + m_deact_countdown.setTop(getDeactivationTime()); + + if(m_args.power_channel != "None") + queryEntityInfo(); } void @@ -163,6 +204,14 @@ namespace Supervisors return; relayTo(msg); + + if(m_args.power_channel == "None") + return; + + IMC::MessageList::const_iterator itr = msg->params.begin(); + for (; itr != msg->params.end(); ++itr) + if((*itr)->name == "Active" && (*itr)->value == "true") + onRequestActivation(); } void @@ -181,6 +230,7 @@ namespace Supervisors return; relayTo(msg); + m_push = *msg; } void @@ -199,13 +249,42 @@ namespace Supervisors void onRequestActivation(void) { - sendActiveParameter("true"); + if(m_args.power_channel != "None") + { + // Powerdown aborted + if (m_deactivating && !m_deact_countdown.overflow()) + { + IMC::PowerOperation pop; + pop.op = IMC::PowerOperation::POP_PWR_DOWN_ABORTED; + relayTo(&pop); + m_deactivating = false; + debug("Sent PowerOperation aborted to surrogate."); + } + + m_pcc.op = IMC::PowerChannelControl::PCC_OP_TURN_ON; + dispatch(m_pcc); + m_act_countdown.reset(); + m_activating = true; + debug("Power on surrogate PCC."); + } + else + sendActiveParameter("true"); } void onRequestDeactivation(void) { - sendActiveParameter("false"); + if(m_args.power_channel != "None") + { + IMC::PowerOperation pop; + pop.op = IMC::PowerOperation::POP_PWR_DOWN_IP; + relayTo(&pop); + debug ("Sent PowerOperation shutdown in progress to surrogate."); + m_deact_countdown.reset(); + m_deactivating = true; + } + else + sendActiveParameter("false"); } bool @@ -214,6 +293,18 @@ namespace Supervisors return (msg->getSource() == m_sid) && (msg->getSourceEntity() == m_eid); } + void + consume(const IMC::PowerChannelState* msg) + { + if(msg->name != m_args.power_channel) + return; + + if(msg->state == IMC::PowerChannelState::PCS_OFF) + m_eid = DUNE_IMC_CONST_UNK_EID; + + m_pcs = *msg; + } + void consume(const IMC::EntityInfo* msg) { @@ -234,6 +325,7 @@ namespace Supervisors return; setEntityState((DUNE::IMC::EntityState::StateEnum)msg->state, msg->description); + m_estate = *msg; } void @@ -249,6 +341,16 @@ namespace Supervisors activate(); else if (isDeactivating() && (msg->state == IMC::EntityActivationState::EAS_INACTIVE)) deactivate(); + + if(m_args.power_channel != "None" && msg->state == IMC::EntityActivationState::EAS_DEACT_IP) + onRequestDeactivation(); + + if(m_args.power_channel != "None" && msg->state == IMC::EntityActivationState::EAS_ACT_IP && + m_estate.state == IMC::EntityState::ESTA_FAILURE) + { + activationFailed(DTR("failed activation, device reporting failure state.")); + onRequestDeactivation(); + } } void @@ -291,6 +393,37 @@ namespace Supervisors m_query_info_timer.reset(); queryEntityInfo(); } + + if (m_activating) + { + if (m_pcs.state == IMC::PowerChannelControl::PCC_OP_TURN_ON && m_eid != DUNE_IMC_CONST_UNK_EID) + { + debug("PCC activation took %0.2f s", getActivationTime()-m_act_countdown.getRemaining()); + dispatch(m_push); + sendActiveParameter("true"); + m_activating = false; + } + else if (m_act_countdown.overflow()) + { + activationFailed(DTR("failed to contact device")); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_COM_ERROR); + m_activating = false; + onRequestDeactivation(); + } + } + + if (m_deactivating) + { + if (m_deact_countdown.overflow()) + { + m_pcc.op = IMC::PowerChannelControl::PCC_OP_TURN_OFF; + dispatch (m_pcc); + m_deactivating = false; + sendActiveParameter("false"); + + debug ("Power off surrogate PCC."); + } + } } } }; diff --git a/src/Supervisors/Entities/Task.cpp b/src/Supervisors/Entities/Task.cpp index 080b3684cc..00d30dc9b0 100644 --- a/src/Supervisors/Entities/Task.cpp +++ b/src/Supervisors/Entities/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/Power/Command.hpp b/src/Supervisors/Power/Command.hpp index b5adaecaa5..e9ea7a3b0b 100644 --- a/src/Supervisors/Power/Command.hpp +++ b/src/Supervisors/Power/Command.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/Power/Task.cpp b/src/Supervisors/Power/Task.cpp index 898a231293..32c434c87e 100644 --- a/src/Supervisors/Power/Task.cpp +++ b/src/Supervisors/Power/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/PowerManager/Task.cmake b/src/Supervisors/PowerManager/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Supervisors/PowerManager/Task.cpp b/src/Supervisors/PowerManager/Task.cpp new file mode 100644 index 0000000000..faf4c5f3bd --- /dev/null +++ b/src/Supervisors/PowerManager/Task.cpp @@ -0,0 +1,199 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Ana Santos * +//*************************************************************************** + +// DUNE headers. +#include + +namespace Supervisors +{ + namespace PowerManager + { + using DUNE_NAMESPACES; + + struct Task: public DUNE::Tasks::Task + { + const static int c_rpm_counter_size = 6; + + //! Vehicle is underwater + bool m_vehicle_underwater; + //! Last state has changed + bool m_has_changes; + //! Motor's rpms + int m_rpms; + + int m_zero_rpm_counter; + + bool m_wifi_on; + + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_vehicle_underwater(false), + m_has_changes(false), + m_rpms(0), + m_zero_rpm_counter(0), + m_wifi_on(false) + { + + // Register consumer + bind(this); + bind(this); + bind(this); + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + } + + //! Resolve entity names. + void + onEntityResolution(void) + { + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + + //! Release resources. + void + onResourceRelease(void) + { + } + + void + consume(const IMC::VehicleMedium * msg) + { + bool last_state = m_vehicle_underwater; + + m_vehicle_underwater = (msg->medium == IMC::VehicleMedium::VM_UNDERWATER); + + if(last_state != m_vehicle_underwater) + { + if(m_vehicle_underwater) + debug("IN UNDERWATER...'"); + else + debug("NOT IN UNDERWATER...'"); + + m_has_changes = true; + } + } + + void + consume(const IMC::Rpm* msg) + { + int last_rpms = m_rpms; + + m_rpms = msg->value; + + if(m_rpms == 0) + m_zero_rpm_counter++; + else + m_zero_rpm_counter = 0; + + //! If last rpms of vehicle are different from current ones a + //! and the current or previous rpms are equal to 0 + if((m_rpms == 0 || last_rpms == 0) && last_rpms != m_rpms) + { + m_has_changes = true; + } + } + + void + consume(const IMC::PowerChannelState * msg) + { + if(msg->name != "Radio") + return; + + if(msg->state == IMC::PowerChannelState::PCS_ON) + m_wifi_on = true; + else + m_wifi_on = false; + } + + //! Main loop. + void + onMain(void) + { + IMC::PowerChannelControl power_control_channel; + power_control_channel.name = "Radio"; + + while (!stopping()) + { + waitForMessages(1.0); + consumeMessages(); + + if(!m_has_changes) + continue; + + m_has_changes = false; + + //! If vehicle is in moving and underwater then turn off wifi + if(m_zero_rpm_counter == c_rpm_counter_size || !m_vehicle_underwater){ + if(m_wifi_on) + continue; + debug("WIFI IS ON...'"); + power_control_channel.op = IMC::PowerChannelControl::PCC_OP_TURN_ON; + m_zero_rpm_counter = 0; + } + else { + if(!m_wifi_on) + continue; + debug("WIFI IS OFF...'"); + power_control_channel.op = IMC::PowerChannelControl::PCC_OP_TURN_OFF; + } + + dispatch(power_control_channel); + } + } + }; + } +} + +DUNE_TASK \ No newline at end of file diff --git a/src/Supervisors/Reporter/Client.hpp b/src/Supervisors/Reporter/Client.hpp index b38a1b83d7..f4a120a05b 100644 --- a/src/Supervisors/Reporter/Client.hpp +++ b/src/Supervisors/Reporter/Client.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/Reporter/Dispatcher.hpp b/src/Supervisors/Reporter/Dispatcher.hpp index da4bb86502..1311e153db 100644 --- a/src/Supervisors/Reporter/Dispatcher.hpp +++ b/src/Supervisors/Reporter/Dispatcher.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/Reporter/Task.cpp b/src/Supervisors/Reporter/Task.cpp index eb38d446f7..0b16ef9c49 100644 --- a/src/Supervisors/Reporter/Task.cpp +++ b/src/Supervisors/Reporter/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -46,6 +46,10 @@ namespace Supervisors bool acoustic; //! Acoustic reports periodicity. double acoustic_period; + //! Enable radio reports. + bool radio; + //! Radio reports periodicity. + double radio_period; }; struct Task: public DUNE::Tasks::Task @@ -76,6 +80,20 @@ namespace Supervisors .maximumValue("600") .description("Reports periodicity"); + param(DTR_RT("Radio Reports"), m_args.radio) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("false") + .description("Enable Radio system state reporting"); + + param(DTR_RT("Radio Reports Periodicity"), m_args.radio_period) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .units(Units::Second) + .defaultValue("3") + .minimumValue("1") + .maximumValue("600") + .description("Reports periodicity"); + + bind(this); } @@ -105,6 +123,29 @@ namespace Supervisors } } + if (paramChanged(m_args.radio) || paramChanged(m_args.radio_period)) + { + if (m_args.radio) + { + IMC::ReportControl rc; + rc.op = IMC::ReportControl::OP_REQUEST_START; + rc.comm_interface = IMC::ReportControl::CI_RADIO; + rc.period = m_args.radio_period; + rc.sys_dst = "broadcast"; + dispatch(rc, DF_LOOP_BACK); + } + else + { + IMC::ReportControl rc; + rc.op = IMC::ReportControl::OP_REQUEST_STOP; + rc.comm_interface = IMC::ReportControl::CI_RADIO; + rc.period = m_args.radio_period; + rc.sys_dst = "broadcast"; + dispatch(rc, DF_LOOP_BACK); + } + } + + if (m_dispatcher.isEmpty()) setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); else diff --git a/src/Supervisors/Reporter/Ticket.hpp b/src/Supervisors/Reporter/Ticket.hpp index 55c19c92d7..29ed44d308 100644 --- a/src/Supervisors/Reporter/Ticket.hpp +++ b/src/Supervisors/Reporter/Ticket.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -53,7 +53,9 @@ namespace Supervisors //! GSM. IS_GSM = 0x04, //! Mobile. - IS_MOBILE = 0x08 + IS_MOBILE = 0x08, + //! Radio + IS_RADIO = 0x10 }; //! Request structure. diff --git a/src/Supervisors/SlaveCPU/Task.cpp b/src/Supervisors/SlaveCPU/Task.cpp index 5daf816142..863745f424 100644 --- a/src/Supervisors/SlaveCPU/Task.cpp +++ b/src/Supervisors/SlaveCPU/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/StratoPIWatchdog/Task.cmake b/src/Supervisors/StratoPIWatchdog/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Supervisors/StratoPIWatchdog/Task.cpp b/src/Supervisors/StratoPIWatchdog/Task.cpp new file mode 100644 index 0000000000..633cb4b77e --- /dev/null +++ b/src/Supervisors/StratoPIWatchdog/Task.cpp @@ -0,0 +1,147 @@ +//*************************************************************************** +// Copyright 2007-2021 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Nikolai Lauvås * +//*************************************************************************** + +// DUNE headers. +#include +#include + +namespace Supervisors +{ + //! This task is used with the watchdog feature of the StratoPi CAN expansion board for the Raspberry Pi. + //! + //! The task activates the watchdog when it's activated. + //! The task is periodic, and toggles the heartbeat pin once for every time it executes. + //! @author Nikolai Lauvås + namespace StratoPIWatchdog + { + using DUNE_NAMESPACES; + + struct Arguments + { + //! Toggle + float toggled_time; + }; + + struct Task: public DUNE::Tasks::Periodic + { + Hardware::GPIO* m_gpio_activation_pin; + Hardware::GPIO* m_gpio_heartbeat_pin; + Hardware::GPIO* m_gpio_watchdog_timeout_pin; + Hardware::GPIO* m_gpio_watchdog_timeout_answer_pin; + Arguments m_args; + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Periodic(name, ctx), + m_gpio_activation_pin(NULL), + m_gpio_heartbeat_pin(NULL), + m_gpio_watchdog_timeout_pin(NULL), + m_gpio_watchdog_timeout_answer_pin(NULL) + { + + param("TimeToggled", m_args.toggled_time) + .units(Units::Second) + .description("How long GPIO5 stays toggled") + .defaultValue("1.00"); + + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + } + + //! Resolve entity names. + void + onEntityResolution(void) + { + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + m_gpio_heartbeat_pin = new Hardware::GPIO(5); + m_gpio_activation_pin = new Hardware::GPIO(6); + m_gpio_watchdog_timeout_pin = new Hardware::GPIO(12); + m_gpio_watchdog_timeout_answer_pin = new Hardware::GPIO(16); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } + + //! Initialize resources. + void + onResourceInitialization(void) + { + m_gpio_heartbeat_pin->setDirection(Hardware::GPIO::GPIO_DIR_OUTPUT); + m_gpio_activation_pin->setDirection(Hardware::GPIO::GPIO_DIR_OUTPUT); + m_gpio_watchdog_timeout_pin->setDirection(Hardware::GPIO::GPIO_DIR_INPUT); + m_gpio_watchdog_timeout_answer_pin->setDirection(Hardware::GPIO::GPIO_DIR_OUTPUT); + + m_gpio_heartbeat_pin->setValue(0); + m_gpio_activation_pin->setValue(1); + m_gpio_watchdog_timeout_answer_pin->setValue(0); + } + + //! Release resources. + void + onResourceRelease(void) + { + Memory::clear(m_gpio_heartbeat_pin); + Memory::clear(m_gpio_activation_pin); + Memory::clear(m_gpio_watchdog_timeout_pin); + Memory::clear(m_gpio_watchdog_timeout_answer_pin); + } + + //! Main loop. + void + task(void) + { + if(m_gpio_watchdog_timeout_pin->getValue()) { + err(DTR("StratoPIWatchdog timeout")); + setEntityState(IMC::EntityState::ESTA_FAILURE, "StratoPIWatchdog timeout"); + } + + debug(DTR("Toggled heartbeat gpio")); + m_gpio_heartbeat_pin->setValue(1); + Delay::wait(m_args.toggled_time); + m_gpio_heartbeat_pin->setValue(0); + } + }; + } +} + +DUNE_TASK diff --git a/src/Supervisors/UAV/LostComms/Task.cpp b/src/Supervisors/UAV/LostComms/Task.cpp index f2eed36b81..17907209e7 100644 --- a/src/Supervisors/UAV/LostComms/Task.cpp +++ b/src/Supervisors/UAV/LostComms/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -198,6 +198,7 @@ namespace Supervisors p_control.op = IMC::PlanControl::PC_START; p_control.type = IMC::PlanControl::PC_REQUEST; p_control.flags = IMC::PlanControl::FLG_IGNORE_ERRORS; + p_control.setDestination(m_ctx.resolver.id()); p_control.arg.set(m_plan); dispatch(p_control); diff --git a/src/Supervisors/Vehicle/ManeuverSupervisor.hpp b/src/Supervisors/Vehicle/ManeuverSupervisor.hpp index e5b18d8dfa..c546752e77 100644 --- a/src/Supervisors/Vehicle/ManeuverSupervisor.hpp +++ b/src/Supervisors/Vehicle/ManeuverSupervisor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/Vehicle/Request.hpp b/src/Supervisors/Vehicle/Request.hpp index e91c37c74c..97528be0bb 100644 --- a/src/Supervisors/Vehicle/Request.hpp +++ b/src/Supervisors/Vehicle/Request.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Supervisors/Vehicle/Task.cpp b/src/Supervisors/Vehicle/Task.cpp index d7d5db93fc..ede27b0dac 100644 --- a/src/Supervisors/Vehicle/Task.cpp +++ b/src/Supervisors/Vehicle/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -243,7 +243,24 @@ namespace Supervisors if (msg->getDestination() != getSystemId()) return; - m_vs.last_error = DTR("got abort request"); + if (msg->getSource() == getSystemId()) + { + try + { + m_vs.last_error = DTR("got abort request from entity ") + resolveEntity(msg->getSourceEntity()) + + String::str(" @ 0x%02X", msg->getSourceEntity()); + } + catch (Entities::EntityDataBase::InvalidId& e ) + { + m_vs.last_error = DTR("got abort request from entity ") + + String::str("unknown @ 0x%02X", msg->getSourceEntity()); + } + } + else + { + m_vs.last_error = DTR("got abort request from system ") + String::str("%s - 0x%04X @ 0x%02X", + resolveSystemId(msg->getSource()), msg->getSource(), msg->getSourceEntity()); + } m_vs.last_error_time = Clock::getSinceEpoch(); err("%s", m_vs.last_error.c_str()); diff --git a/src/Transports/Announce/Task.cpp b/src/Transports/Announce/Task.cpp index fa82582206..8cc7170f65 100644 --- a/src/Transports/Announce/Task.cpp +++ b/src/Transports/Announce/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/Cache/Task.cpp b/src/Transports/Cache/Task.cpp index df177be342..0749e280f9 100644 --- a/src/Transports/Cache/Task.cpp +++ b/src/Transports/Cache/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/CommManager/Router.hpp b/src/Transports/CommManager/Router.hpp new file mode 100644 index 0000000000..a2246934b1 --- /dev/null +++ b/src/Transports/CommManager/Router.hpp @@ -0,0 +1,921 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Seruca * +//*************************************************************************** + +#ifndef SRC_TRANSPORTS_COMMMANAGER_ROUTER_HPP_ +#define SRC_TRANSPORTS_COMMMANAGER_ROUTER_HPP_ + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include + +namespace Transports +{ + namespace CommManager + { + + using DUNE_NAMESPACES; + + struct TCPAnnounce + { + char address[50]; + double timestamp; + }; + + class Router + { + + public: + Router(Task* task) + { + m_parent = task; + m_medium = 4; + m_gsm_entity_id = -1; + m_iridium_entity_id = -1; + m_reqid = 0; + c_wifi_timeout = 15; + } + + void + process(IMC::VehicleMedium* msg) + { + m_medium = msg->medium; + } + + void + process(IMC::RSSI* msg) + { + m_rssi_msg_map[msg->getSourceEntity()] = msg->value; + } + + void + process(IMC::Announce* msg) + { + std::vector list; + String::split(msg->services, ";", list); + + char addr[50]; + char number[20]; + + for (uint16_t i = 0; i < list.size(); i++) + { + int result_tcp = std::sscanf(list[i].c_str(), "imc+tcp://%[^/]", addr); + if (result_tcp == 1) + { + TCPAnnounce ann; + ann.timestamp = msg->getTimeStamp(); + strcpy(ann.address, addr); + m_wifi_map[msg->sys_name] = ann; + } + int result_gsm = std::sscanf(list[i].c_str(), "imc+gsm://%[^/]", + number); + if (result_gsm == 1) + { + m_gsm_announce_map[msg->sys_name] = std::string(number); + } + } + } + + void + answer(const IMC::AcousticOperation* req, int status, std::string system, fp32_t range = 0.0) + { + IMC::AcousticOperation msg; + msg.op = status; + msg.system = system; + msg.range = range; + msg.setDestination(req->getSource()); + msg.setDestinationEntity(req->getSourceEntity()); + m_parent->dispatch(msg); + } + + void + answerTCPStatus(const IMC::TransmissionRequest* req, std::string info, int status) + { + IMC::TCPStatus msg; + msg.info = info; + msg.req_id = req->req_id; + msg.status = status; + msg.setDestination(req->getSource()); + msg.setDestinationEntity(req->getSourceEntity()); + m_parent->dispatch(msg, DF_LOOP_BACK); + } + + void + answer(const IMC::TransmissionRequest* req, std::string info, int status, fp32_t range = 0.0) + { + IMC::TransmissionStatus msg; + msg.info = info; + msg.req_id = req->req_id; + msg.status = status; + msg.range = range; + msg.setDestination(req->getSource()); + msg.setDestinationEntity(req->getSourceEntity()); + m_parent->dispatch(msg); + + m_parent->inf("Status of transmission message (%d) changed to: %s", + req->req_id, info.c_str()); + } + + void + answerCommNotAvailable(const IMC::TransmissionRequest* msg) + { + answer(msg, "No communication mode available for this message type", + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + } + + void + answerDestinationNotVisible(const IMC::TransmissionRequest* msg) + { + answer(msg, "No communication mode available for this destination", + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + } + + uint16_t + createInternalId() + { + if (m_reqid == 0xFFFF) + { + m_reqid = 0; + } + else + { + m_reqid++; + } + return m_reqid; + } + + void + clearTimeouts() + { + std::map::iterator it; + double time = Time::Clock::getSinceEpoch(); + it = m_transmission_requests.begin(); + + while (it != m_transmission_requests.end()) + { + if (it->second->deadline <= time) + { + m_parent->inf("Transmission Request %d is expired by %f seconds", it->second->req_id, it->second->deadline - time); + answer(it->second, "Transmission timed out.", + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + Memory::clear(it->second); + m_transmission_requests.erase(it++); + } + else + ++it; + } + } + + void + sendViaAcoustic(const IMC::TransmissionRequest* msg) + { + m_parent->inf("Request to send data over Acoustic to %s (%d)", + msg->destination.c_str(), msg->req_id); + + AcousticRequest tx; + + if (msg->destination == "") + tx.destination = "broadcast"; + else + tx.destination = msg->destination.c_str(); + + tx.setDestination(m_parent->getSystemId()); + tx.setDestinationEntity(m_parent->getEntityId()); + + tx.range = msg->range; + + switch (msg->data_mode) + { + case IMC::TransmissionRequest::DMODE_INLINEMSG: + { + tx.type = IMC::AcousticRequest::TYPE_MSG; + tx.msg.set(msg->msg_data.get()->clone()); + + break; + } + + case IMC::TransmissionRequest::DMODE_ABORT: + { + tx.type = IMC::AcousticRequest::TYPE_ABORT; + + break; + } + case IMC::TransmissionRequest::DMODE_RANGE: + { + tx.type = IMC::AcousticRequest::TYPE_RANGE; + + break; + } + case IMC::TransmissionRequest::DMODE_REVERSE_RANGE: + { + tx.type = IMC::AcousticRequest::TYPE_REVERSE_RANGE; + + break; + } + case IMC::TransmissionRequest::DMODE_RAW: + { + tx.type = IMC::AcousticRequest::TYPE_RAW; + IMC::DevDataBinary ddb; + ddb.value = msg->raw_data; + tx.msg.set(ddb); + break; + } + default: + { + answer( + msg, + "Communication mode not implemented for communication mean Acoustic", + IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE); + return; + + break; + } + } + + uint16_t newId = createInternalId(); + tx.req_id = newId; + m_transmission_requests[newId] = msg->clone(); + + tx.timeout = msg->deadline - Time::Clock::getSinceEpoch(); + if (tx.timeout < 0) + tx.timeout = 0; + + m_parent->dispatch(tx); + } + + void + sendViaSatellite(const IMC::TransmissionRequest* msg, bool plain_text) + { + m_parent->inf("Request to send data over satellite (%d)", msg->req_id); + + IridiumMsgTx tx; + + tx.destination = msg->destination; + tx.ttl = msg->deadline - Time::Clock::getSinceEpoch(); + tx.setDestination(msg->getDestination()); + tx.setDestinationEntity(msg->getDestinationEntity()); + + switch (msg->data_mode) + { + case IMC::TransmissionRequest::DMODE_RAW: + { + tx.data.assign(msg->raw_data.begin(), msg->raw_data.end()); + + break; + } + case IMC::TransmissionRequest::DMODE_INLINEMSG: + { + IMC::ImcIridiumMessage m; + const IMC::Message * inlinemsg = msg->msg_data.get(); + m.destination = 0xFFFF; + m.source = m_parent->getSystemId(); + m.msg = inlinemsg->clone(); + uint8_t buffer[65535]; + int len = m.serialize(buffer); + tx.data.assign(buffer, buffer + len); + Memory::clear(m.msg); + + break; + } + case IMC::TransmissionRequest::DMODE_TEXT: + { + if(plain_text) + { + const char* txt = msg->txt_data.c_str(); + tx.data.assign(txt, txt + msg->txt_data.length()); + } + else + { + IMC::IridiumCommand m; + m.destination = 0xFFFF; + m.source = m_parent->getSystemId(); + m.command = msg->txt_data; + uint8_t buffer[65535]; + int len = m.serialize(buffer); + tx.data.assign(buffer, buffer + len); + } + + break; + } + default: + answer( + msg, + "Communication mode not implemented for communication mean Satellite", + IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE); + return; + + break; + } + + uint16_t newId = createInternalId(); + tx.req_id = newId; + m_transmission_requests[newId] = msg->clone(); + m_parent->dispatch(tx); + } + + void + sendViaAny(const IMC::TransmissionRequest* msg, bool plain_text) + { + //restriction by medium + if (m_medium == IMC::VehicleMedium::VM_UNDERWATER) + { + if (msg->data_mode != IMC::TransmissionRequest::DMODE_TEXT) + { + if (visibleOverAcoustic(msg->destination)) + { + sendViaAcoustic(msg); + return; + } + else + { + answerDestinationNotVisible(msg); + return; + } + } + else + { + answerCommNotAvailable(msg); + return; + } + } + //end + + //restriction by transmission mode + std::string dest; + switch (msg->data_mode) + { + //unique for uan modems + case IMC::TransmissionRequest::DMODE_ABORT: + case IMC::TransmissionRequest::DMODE_RANGE: + case IMC::TransmissionRequest::DMODE_REVERSE_RANGE: + if (m_medium == IMC::VehicleMedium::VM_WATER) + { + if (visibleOverAcoustic(msg->destination)) + { + sendViaAcoustic(msg); + return; + } + answerDestinationNotVisible(msg); + return; + } + answerCommNotAvailable(msg); + return; + + break; + + //unique for satellite modem + case IMC::TransmissionRequest::DMODE_RAW: + if (checkRSSISignal(IRIDIUM)) + { + sendViaSatellite(msg, plain_text); + return; + } + answerCommNotAvailable(msg); + return; + + break; + + //only for satellite modem or gsm + case IMC::TransmissionRequest::DMODE_TEXT: + + if (visibleOverGSM(msg->destination, dest) + && checkGSMMessageSize(msg)) + { + sendViaGSM(msg); + return; + } + + if (checkRSSISignal(IRIDIUM)) + { + sendViaSatellite(msg, plain_text); + return; + } + answerCommNotAvailable(msg); + return; + + break; + + case IMC::TransmissionRequest::DMODE_INLINEMSG: + if (visibleOverWifi(msg->destination)) + { + sendViaWifi(msg); + return; + } + if (visibleOverGSM(msg->destination, dest) + && checkGSMMessageSize(msg)) + { + sendViaGSM(msg); + return; + } + if (m_medium != IMC::VehicleMedium::VM_WATER) + { + if (checkRSSISignal(IRIDIUM)) + { + sendViaSatellite(msg, plain_text); + return; + } + answerCommNotAvailable(msg); + return; + } + else + { + if (visibleOverAcoustic(msg->destination)) + { + sendViaAcoustic(msg); + return; + } + if (checkRSSISignal(IRIDIUM)) + { + sendViaSatellite(msg, plain_text); + return; + } + answerCommNotAvailable(msg); + return; + } + + break; + + default: + answerCommNotAvailable(msg); + return; + break; + } + //end + + return; + + } + + void + sendViaGSM(const IMC::TransmissionRequest* msg) + { + m_parent->inf("Request to send data over SMS to %s (%d)", + msg->destination.c_str(), msg->req_id); + + SmsRequest sms; + + /* + if (msg->destination == "broadcast" || msg->destination == "") + m_parent->m_ctx.config.get(c_sms_section, c_sms_field, "", sms.destination); + else*/ + if (msg->destination.empty()) + { + answer(msg, "Destination of message can not be empty.", + IMC::TransmissionStatus::TSTAT_INPUT_FAILURE); + return; + } + else + { + std::string dest; + if (visibleOverGSM(msg->destination, dest)) + { + sms.destination = dest; + } + else + { + sms.destination = msg->destination; + } + } + sms.timeout = + (msg->deadline < Time::Clock::getSinceEpoch()) ? 0 : + msg->deadline - Time::Clock::getSinceEpoch(); + + switch (msg->data_mode) + { + case IMC::TransmissionRequest::DMODE_TEXT: + { + if (msg->txt_data == "") + { + answer(msg, "GSM message cannot be empty", + IMC::TransmissionStatus::TSTAT_INPUT_FAILURE); + return; + } + sms.sms_text = msg->txt_data; + + break; + } + case IMC::TransmissionRequest::DMODE_INLINEMSG: + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(msg->msg_data.get(), bfr); + std::string encoded = Algorithms::Base64::encode(bfr.getBuffer(), + bfr.getSize()); + sms.sms_text.assign(encoded); + + break; + } + default: + { + answer( + msg, + "Communication mode not implemented for communication mean GSM", + IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE); + return; + + break; + } + } + + if (sms.sms_text.length() > 160) + { //160 characters -> 120 bytes for the inline message + answer(msg, "Can only send 160 characters over SMS.", + IMC::TransmissionStatus::TSTAT_INPUT_FAILURE); + return; + } + uint16_t newId = createInternalId(); + sms.req_id = newId; + m_transmission_requests[newId] = msg->clone(); + m_parent->dispatch(sms); + } + + void + sendViaWifi(const IMC::TransmissionRequest* msg) + { + m_parent->inf("Request to send data over TCP to %s (%d)", + msg->destination.c_str(), msg->req_id); + + TCPRequest send; + + if (msg->destination.empty()) + { + answer(msg, "Destination of message can not be empty.", + IMC::TransmissionStatus::TSTAT_INPUT_FAILURE); + return; + } + else + { + if (visibleOverWifi(msg->destination)) + { + send.destination = std::string( + m_wifi_map[msg->destination].address); + } + else + { + uint16_t newId = createInternalId(); + m_transmission_requests[newId] = msg->clone(); + IMC::TransmissionRequest* msg2 = msg->clone(); + msg2->req_id = newId; + answerTCPStatus(msg2, "Didn't find TCP server on destination host", + IMC::TCPStatus::TCPSTAT_HOST_UNKNOWN); + return; + } + } + + send.timeout = (msg->deadline < 0) ? 0 : msg->deadline; + + switch (msg->data_mode) + { + case IMC::TransmissionRequest::DMODE_INLINEMSG: + { + send.msg_data.set(msg->msg_data.get()->clone()); + break; + } + default: + { + answer( + msg, + "Communication mode not implemented for communication mean GSM", + IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE); + return; + + break; + } + } + + uint16_t newId = createInternalId(); + send.req_id = newId; + m_transmission_requests[newId] = msg->clone(); + m_parent->dispatch(send); + + } + + void + sendViaAll(const IMC::TransmissionRequest* msg, bool plain_text) + { + + //restriction by medium + if (m_medium == IMC::VehicleMedium::VM_UNDERWATER) + { + if (msg->data_mode != IMC::TransmissionRequest::DMODE_TEXT) + { + if (visibleOverAcoustic(msg->destination)) + { + sendViaAcoustic(msg); + return; + } + } + answerCommNotAvailable(msg); + return; + } + //end + + //restriction by transmission mode + std::string dest; + bool flag = false; + switch (msg->data_mode) + { + //unique for uan modems + case IMC::TransmissionRequest::DMODE_ABORT: + case IMC::TransmissionRequest::DMODE_RANGE: + case IMC::TransmissionRequest::DMODE_REVERSE_RANGE: + if (m_medium == IMC::VehicleMedium::VM_WATER) + { + if (visibleOverAcoustic(msg->destination)) + { + sendViaAcoustic(msg); + return; + } + } + answerCommNotAvailable(msg); + return; + break; + + //unique for satellite modem + case IMC::TransmissionRequest::DMODE_RAW: + if (checkRSSISignal(IRIDIUM)) + { + sendViaSatellite(msg, plain_text); + return; + } + answerCommNotAvailable(msg); + return; + break; + + //only for satellite modem or gsm + case IMC::TransmissionRequest::DMODE_TEXT: + if (visibleOverGSM(msg->destination, dest) + && checkGSMMessageSize(msg)) + { + sendViaGSM(msg); + flag = true; + } + if (checkRSSISignal(IRIDIUM)) + { + sendViaSatellite(msg, plain_text); + flag = true; + } + if (!flag) + answerCommNotAvailable(msg); + + return; + break; + + case IMC::TransmissionRequest::DMODE_INLINEMSG: + if (visibleOverWifi(msg->destination)) + { + sendViaWifi(msg); + flag = true; + } + if (visibleOverGSM(msg->destination, dest) + && checkGSMMessageSize(msg)) + { + sendViaGSM(msg); + flag = true; + } + if (visibleOverAcoustic(msg->destination)) + { + sendViaAcoustic(msg); + flag = true; + } + if (checkRSSISignal(IRIDIUM)) + { + sendViaSatellite(msg, plain_text); + flag = true; + } + if (!flag) + answerCommNotAvailable(msg); + + return; + break; + + default: + answerCommNotAvailable(msg); + return; + break; + } + //end + + return; + } + + void + setGSMMap(std::map map) + { + m_gsm_config_map = map; + } + + void + setAcousticMap(std::vector map) + { + m_acoustic_map = map; + } + + void + setGsmLabel(int id) + { + m_gsm_entity_id = id; + } + + void + setIridiumLabel(int id) + { + m_iridium_entity_id = id; + } + + std::map* + getList() + { + return &m_transmission_requests; + } + + ~Router() + { + } + + private: + Task* m_parent; + uint8_t m_medium; + + int m_gsm_entity_id; + int m_iridium_entity_id; + std::map m_rssi_msg_map; + uint16_t m_reqid; + + typedef std::map MessagesQueued; + MessagesQueued m_transmission_requests; + + typedef std::map WifiMap; + WifiMap m_wifi_map; + + typedef std::map GsmAnnounceMap; + GsmAnnounceMap m_gsm_announce_map; + + typedef std::map GsmConfigMap; + GsmConfigMap m_gsm_config_map; + + typedef std::vector AcousticMap; + AcousticMap m_acoustic_map; + + uint16_t c_wifi_timeout; + + enum RSSIType + { + GSM, IRIDIUM + }; + + bool + visibleOverAcoustic(std::string system) + { + if (system.empty()) + return false; + + for (unsigned i = 0; i < m_acoustic_map.size(); i++) + { + if (m_acoustic_map[i] == system) + return true; + } + + return false; + } + + bool + visibleOverWifi(std::string system) + { + if (system.empty()) + return false; + + std::map::iterator it; + + it = m_wifi_map.find(system); + if (it == m_wifi_map.end()) + return false; + + double curTime = Clock::getSinceEpoch(); + if (curTime - it->second.timestamp > c_wifi_timeout) + return false; + + return true; + } + + bool + visibleOverGSM(std::string system, std::string& std) + { + if (system.empty()) + return false; + + std::map::iterator it; + it = m_gsm_announce_map.find(system); + if (it != m_gsm_announce_map.end()) + { + std = it->second; + return checkRSSISignal(GSM); + } + + it = m_gsm_config_map.find(system); + if (it != m_gsm_config_map.end()) + { + std = it->second; + return checkRSSISignal(GSM); + } + + return false; + } + + bool + checkRSSISignal(RSSIType type) + { + switch (type) + { + case GSM: + { + if (m_gsm_entity_id == -1) + return false; + std::map::iterator it; + it = m_rssi_msg_map.find(m_gsm_entity_id); + if (it == m_rssi_msg_map.end()) + return false; + if (it->second > 0) + return true; + return false; + + break; + } + case IRIDIUM: + { + if (m_iridium_entity_id == -1) + return false; + std::map::iterator it; + it = m_rssi_msg_map.find(m_iridium_entity_id); + if (it == m_rssi_msg_map.end()) + return false; + if (it->second >= 20) + return true; + return false; + + break; + } + default: + { + return false; + break; + } + } + } + + bool + checkGSMMessageSize(const IMC::TransmissionRequest* msg) + { + switch (msg->data_mode) + { + case IMC::TransmissionRequest::DMODE_TEXT: + { + return msg->txt_data.length() <= 160; + break; + } + case IMC::TransmissionRequest::DMODE_INLINEMSG: + { + Utils::ByteBuffer bfr; + IMC::Packet::serialize(msg->msg_data.get(), bfr); + std::string encoded = Algorithms::Base64::encode(bfr.getBuffer(), + bfr.getSize()); + return encoded.length() <= 160; + break; + } + default: + { + return false; + break; + } + } + } + + }; + } +} + +#endif /* SRC_TRANSPORTS_COMMMANAGER_ROUTER_HPP_ */ diff --git a/src/Transports/CommManager/Task.cmake b/src/Transports/CommManager/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Transports/CommManager/Task.cpp b/src/Transports/CommManager/Task.cpp new file mode 100644 index 0000000000..c1c3df7960 --- /dev/null +++ b/src/Transports/CommManager/Task.cpp @@ -0,0 +1,923 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Jose Pinto * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include +#include + +// DUNE headers. +#include + +// Local headers. +#include "Router.hpp" + +namespace Transports +{ + namespace CommManager + { + using DUNE_NAMESPACES; + + struct Arguments + { + //! Period, in seconds, between state report transmissions over iridium + int iridium_period; + //! Enable CommManager to process and convert legacy message -> AcousticOperation + bool enable_acoustic; + //! Addresses Number - modem + std::string gsm_addr_section; + //! Entity label of Iridium modem + std::string iridium_label; + //! Entity label of GSM modem + std::string gsm_label; + //! Name of the configuration section with acoustic modem addresses + std::string acoustic_addr_section; + //! Send Iridium text messages as plain text + bool iridium_plain_texts; + }; + + //! Config section from where to fetch emergency sms number + const std::string c_sms_section = "Monitors.Emergency"; + //! Config field from where to fetch emergency sms number + const std::string c_sms_field = "SMS Recipient Number"; + + struct Task: public DUNE::Tasks::Task + { + // Task arguments. + Arguments m_args; + + IMC::PlanControlState* m_pstate; + IMC::FuelLevel* m_fuel; + IMC::EstimatedState* m_estate; + IMC::VehicleState* m_vstate; + IMC::VehicleMedium* m_vmedium; + Time::Counter m_iridium_timer; + Time::Counter m_clean_timer; + Time::Counter m_retransmission_timer; + std::list m_retransmission_list; + int m_plan_chksum; + Router m_router; + + std::map m_acoustic_requests; + + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_pstate(NULL), + m_fuel(NULL), + m_estate(NULL), + m_vstate(NULL), + m_vmedium(NULL), + m_plan_chksum(0), + m_router(this) + { + param("Iridium - Entity Label", m_args.iridium_label) + .defaultValue("GSM") + .description("Entity label of Iridium modem"); + + param("GSM - Entity Label", m_args.gsm_label) + .defaultValue("Iridium Modem") + .description("Entity label of GSM modem"); + + param("GSM Address Section", m_args.gsm_addr_section) + .defaultValue("GSM Addresses") + .description("Name of the configuration section with gsm modem addresses"); + + param("Acoustic Address Section", m_args.acoustic_addr_section) + .defaultValue("Evologics Addresses") + .description("Name of the configuration section with acoustic modem addresses"); + + param("Iridium Reports Period", m_args.iridium_period) + .description("Period, in seconds, between transmission of states via Iridium. Value of 0 disables transmission.") + .defaultValue("300"); + + param("Process AcousticOperation Messages", m_args.enable_acoustic) + .description("Enable CommManager to process and convert legacy message -> AcousticOperation") + .defaultValue("true"); + + param("Send Iridium plain texts", m_args.iridium_plain_texts) + .description("Send Iridium text messages as plain text (and not IMC)") + .defaultValue("1"); + + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + + m_clean_timer.setTop(3); + m_retransmission_timer.setTop(1); + } + + void + onResourceRelease(void) + { + Memory::clear(m_fuel); + Memory::clear(m_pstate); + Memory::clear(m_vstate); + Memory::clear(m_estate); + } + + //! Initialize resources and configure modem + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + + // verify modem local address value -> GSM + std::map mapName; + std::vector addrs = m_ctx.config.options(m_args.gsm_addr_section); + for (unsigned i = 0; i < addrs.size(); ++i) + { + std::string addr; + m_ctx.config.get(m_args.gsm_addr_section, addrs[i], "0", addr); + if (addr != "0") + { + mapName[addrs[i]] = addr; + } + } + m_router.setGSMMap(mapName); + + // verify modem local address value -> Acoustic + std::vector acousticMap; + addrs = m_ctx.config.options(m_args.acoustic_addr_section); + for (unsigned i = 0; i < addrs.size(); ++i) + { + std::string addr; + m_ctx.config.get(m_args.acoustic_addr_section, addrs[i], "-1", addr); + if (addr != "-1") + { + acousticMap.push_back(addrs[i]); + } + } + m_router.setAcousticMap(acousticMap); + } + + void + onEntityResolution(void) + { + try + { + uint8_t gsm_id = resolveEntity(m_args.gsm_label); + m_router.setGsmLabel(gsm_id); + } + catch (std::runtime_error& e) + { + war(DTR("ERROR Initializing CommManager. Couldn't resolve GSM label.")); + //throw RestartNeeded(e.what(), 5, false); + } + try + { + uint8_t iridium_id = resolveEntity(m_args.iridium_label); + m_router.setIridiumLabel(iridium_id); + } + catch (std::runtime_error& e) + { + war(DTR("ERROR Initializing CommManager. Couldn't resolve Iridium label.")); + //throw RestartNeeded(e.what(), 5, false); + } + } + + void + onUpdateParameters(void) + { + m_iridium_timer.setTop(m_args.iridium_period); + } + + void + consume(const IMC::PlanControlState* msg) + { + if (msg->getSource() != getSystemId()) + return; + + Memory::replace(m_pstate, new IMC::PlanControlState(*msg)); + } + + void + consume(const IMC::FuelLevel* msg) + { + if (msg->getSource() != getSystemId()) + return; + + Memory::replace(m_fuel, new IMC::FuelLevel(*msg)); + } + + void + consume(const IMC::EstimatedState* msg) + { + if (msg->getSource() != getSystemId()) + return; + + Memory::replace(m_estate, new IMC::EstimatedState(*msg)); + } + + void + consume(const IMC::VehicleState* msg) + { + if (msg->getSource() != getSystemId()) + return; + + Memory::replace(m_vstate, new IMC::VehicleState(*msg)); + } + + void + consume(const IMC::VehicleMedium* msg) + { + if (msg->getSource() != getSystemId()) + return; + + Memory::replace(m_vmedium, new IMC::VehicleMedium(*msg)); + m_router.process(msg->clone()); + } + + void + consume(const IMC::PlanSpecification* msg) + { + if (msg->getSource() != getSystemId()) + return; + const char * name = msg->plan_id.c_str(); + m_plan_chksum = CRC16::compute((uint8_t *)name, strlen(name)); + } + + void + consume(const IMC::RSSI* msg) + { + if (msg->getSource() != getSystemId()) + return; + m_router.process(msg->clone()); + } + + void + consume(const IMC::Announce* msg) + { + m_router.process(msg->clone()); + } + + void + consume(const IMC::IridiumTxStatus* msg) + { + if (msg->getSource() != getSystemId()) + return; + + if (msg->getDestinationEntity() != getEntityId()) + return; + + std::map* tr_list = + m_router.getList(); + + if (tr_list->find(msg->req_id) != tr_list->end()) + { + IMC::TransmissionRequest* req = tr_list->operator [](msg->req_id); + + if (req->comm_mean != IMC::TransmissionRequest::CMEAN_SATELLITE) + return; + + switch (msg->status) + { + case (IMC::IridiumTxStatus::TXSTATUS_QUEUED): + m_router.answer( + req, "Message has been queued for Satellite transmission.", + IMC::TransmissionStatus::TSTAT_IN_PROGRESS); + break; + case (IMC::IridiumTxStatus::TXSTATUS_TRANSMIT): + m_router.answer(req, "Message is being transmitted.", + IMC::TransmissionStatus::TSTAT_IN_PROGRESS); + break; + case (IMC::IridiumTxStatus::TXSTATUS_OK): + m_router.answer(req, "Message has been sent via Iridium.", + IMC::TransmissionStatus::TSTAT_SENT); + Memory::clear(req); + tr_list->erase(msg->req_id); + break; + case (IMC::IridiumTxStatus::TXSTATUS_ERROR): + m_router.answer(req, "Error while trying to transmit message.", + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + tr_list->erase(msg->req_id); + m_retransmission_list.push_back(req->clone()); + Memory::clear(req); + + break; + case (IMC::IridiumTxStatus::TXSTATUS_EXPIRED): + m_router.answer(req, "Timeout while trying to transmit message.", + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + Memory::clear(req); + tr_list->erase(msg->req_id); + break; + default: + break; + } + } + } + + void + consume(const IMC::SmsStatus* msg) + { + if (msg->getSource() != getSystemId()) + return; + std::map* tr_list = m_router.getList(); + + if (tr_list->find(msg->req_id) != tr_list->end()) + { + IMC::TransmissionRequest* req = tr_list->operator [](msg->req_id); + switch (msg->status) + { + case (IMC::SmsStatus::SMSSTAT_QUEUED): + m_router.answer(req, + "Message has been queued for GSM transmission.", + IMC::TransmissionStatus::TSTAT_IN_PROGRESS); + break; + + case (IMC::SmsStatus::SMSSTAT_SENT): + m_router.answer(req, "Message has been sent via GSM.", + IMC::TransmissionStatus::TSTAT_SENT); + Memory::clear(req); + tr_list->erase(msg->req_id); + break; + + case (IMC::SmsStatus::SMSSTAT_INPUT_FAILURE): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_INPUT_FAILURE); + tr_list->erase(msg->req_id); + Memory::clear(req); + break; + + case (IMC::SmsStatus::SMSSTAT_ERROR): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + tr_list->erase(msg->req_id); + m_retransmission_list.push_back(req->clone()); + Memory::clear(req); + break; + + default: + inf("ERROR: SmsStatus->status not implemented"); + break; + } + } + } + + void + consume(const IMC::AcousticStatus* msg) + { + if (msg->getSource() != getSystemId()) + { + return; + } + std::map* tr_list = + m_router.getList(); + + if (tr_list->find(msg->req_id) != tr_list->end()) + { + + IMC::TransmissionRequest* req = tr_list->operator [](msg->req_id); + + if (req->comm_mean != IMC::TransmissionRequest::CMEAN_ACOUSTIC) + return; + + switch (msg->status) + { + case (IMC::AcousticStatus::STATUS_QUEUED): + break; + + case (IMC::AcousticStatus::STATUS_IN_PROGRESS): + m_router.answer( + req, "Message has been queued for Acoustic transmission.", + IMC::TransmissionStatus::TSTAT_IN_PROGRESS); + break; + + case (IMC::AcousticStatus::STATUS_SENT): + m_router.answer(req, "Message has been sent via Acoustic.", + IMC::TransmissionStatus::TSTAT_SENT); + Memory::clear(req); + tr_list->erase(msg->req_id); + break; + + case (IMC::AcousticStatus::STATUS_RANGE_RECEIVED): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_RANGE_RECEIVED, + msg->range); + Memory::clear(req); + tr_list->erase(msg->req_id); + break; + + case (IMC::AcousticStatus::STATUS_ERROR): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + tr_list->erase(msg->req_id); + m_retransmission_list.push_back(req->clone()); + Memory::clear(req); + break; + + case (IMC::AcousticStatus::STATUS_BUSY): + m_router.answer(req, "Acoustic modem is busy.", + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + tr_list->erase(msg->req_id); + m_retransmission_list.push_back(req->clone()); + Memory::clear(req); + break; + + case (IMC::AcousticStatus::STATUS_INPUT_FAILURE): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_INPUT_FAILURE); + tr_list->erase(msg->req_id); + Memory::clear(req); + break; + + default: + inf("ERROR: AcousticStatus->status not implemented"); + break; + } + return; + } + + if (!m_args.enable_acoustic) + { + return; + } + //old API + if (m_acoustic_requests.find(msg->req_id) != m_acoustic_requests.end()) + { + IMC::AcousticOperation* req = m_acoustic_requests[msg->req_id]; + + switch (msg->status) + { + case (IMC::AcousticStatus::STATUS_QUEUED): + switch (req->op) + { + case IMC::AcousticOperation::AOP_MSG: + m_router.answer(req, IMC::AcousticOperation::AOP_MSG_QUEUED, req->system); + break; + + default: + break; + } + break; + + case (IMC::AcousticStatus::STATUS_IN_PROGRESS): + switch (req->op) + { + case IMC::AcousticOperation::AOP_MSG: + m_router.answer(req, IMC::AcousticOperation::AOP_MSG_IP, req->system); + break; + + case IMC::AcousticOperation::AOP_RANGE: + case IMC::AcousticOperation::AOP_REVERSE_RANGE: + m_router.answer(req, IMC::AcousticOperation::AOP_RANGE_IP, req->system); + break; + + case IMC::AcousticOperation::AOP_ABORT: + m_router.answer(req, IMC::AcousticOperation::AOP_ABORT_IP, req->system); + break; + + default: + break; + } + break; + + case (IMC::AcousticStatus::STATUS_SENT): + switch (req->op) + { + case IMC::AcousticOperation::AOP_MSG: + m_router.answer(req, IMC::AcousticOperation::AOP_MSG_DONE, req->system); + Memory::clear(req); + m_acoustic_requests.erase(msg->req_id); + break; + + case IMC::AcousticOperation::AOP_ABORT: + m_router.answer(req, IMC::AcousticOperation::AOP_ABORT_ACKED, req->system); + Memory::clear(req); + m_acoustic_requests.erase(msg->req_id); + break; + + default: + break; + } + break; + + case (IMC::AcousticStatus::STATUS_RANGE_RECEIVED): + switch (req->op) + { + case IMC::AcousticOperation::AOP_RANGE: + m_router.answer(req, IMC::AcousticOperation::AOP_RANGE_RECVED, + req->system, + msg->range); + Memory::clear(req); + m_acoustic_requests.erase(msg->req_id); + break; + + default: + break; + } + break; + + case (IMC::AcousticStatus::STATUS_ERROR): + switch (req->op) + { + case IMC::AcousticOperation::AOP_MSG: + m_router.answer(req, IMC::AcousticOperation::AOP_MSG_FAILURE, req->system); + Memory::clear(req); + m_acoustic_requests.erase(msg->req_id); + break; + + case IMC::AcousticOperation::AOP_RANGE: + case IMC::AcousticOperation::AOP_REVERSE_RANGE: + m_router.answer(req, IMC::AcousticOperation::AOP_RANGE_TIMEOUT, req->system); + Memory::clear(req); + m_acoustic_requests.erase(msg->req_id); + break; + + case IMC::AcousticOperation::AOP_ABORT: + m_router.answer(req, IMC::AcousticOperation::AOP_ABORT_TIMEOUT, req->system); + Memory::clear(req); + m_acoustic_requests.erase(msg->req_id); + break; + + default: + break; + } + + break; + + case (IMC::AcousticStatus::STATUS_BUSY): + switch (req->op) + { + case IMC::AcousticOperation::AOP_MSG: + case IMC::AcousticOperation::AOP_RANGE: + case IMC::AcousticOperation::AOP_REVERSE_RANGE: + case IMC::AcousticOperation::AOP_ABORT: + m_router.answer(req, IMC::AcousticOperation::AOP_BUSY, req->system); + break; + + default: + break; + } + break; + + case (IMC::AcousticStatus::STATUS_INPUT_FAILURE): + switch (req->op) + { + case IMC::AcousticOperation::AOP_MSG: + case IMC::AcousticOperation::AOP_RANGE: + case IMC::AcousticOperation::AOP_REVERSE_RANGE: + case IMC::AcousticOperation::AOP_ABORT: + m_router.answer(req, IMC::AcousticOperation::AOP_UNSUPPORTED, req->system); + Memory::clear(req); + m_acoustic_requests.erase(msg->req_id); + break; + + default: + break; + } + break; + + default: + break; + } + } + } + + void + consume(const IMC::TCPStatus* msg) + { + if (msg->getSource() != getSystemId()) + return; + + std::map* tr_list = m_router.getList(); + if (tr_list->find(msg->req_id) != tr_list->end()) + { + IMC::TransmissionRequest* req = tr_list->operator [](msg->req_id); + switch (msg->status) + { + case (IMC::TCPStatus::TCPSTAT_QUEUED): + m_router.answer(req, "Message has been queued for TCP transmission.", + IMC::TransmissionStatus::TSTAT_IN_PROGRESS); + break; + + case (IMC::TCPStatus::TCPSTAT_SENT): + m_router.answer(req, "Message has been sent via TCP.", + IMC::TransmissionStatus::TSTAT_SENT); + Memory::clear(req); + tr_list->erase(msg->req_id); + break; + + case (IMC::TCPStatus::TCPSTAT_HOST_UNKNOWN): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + tr_list->erase(msg->req_id); + m_retransmission_list.push_back(req->clone()); + Memory::clear(req); + break; + + case (IMC::TCPStatus::TCPSTAT_CANT_CONNECT): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE); + tr_list->erase(msg->req_id); + m_retransmission_list.push_back(req->clone()); + Memory::clear(req); + break; + + case (IMC::TCPStatus::TCPSTAT_INPUT_FAILURE): + m_router.answer(req, msg->info, + IMC::TransmissionStatus::TSTAT_INPUT_FAILURE); + tr_list->erase(msg->req_id); + Memory::clear(req); + break; + + default: + inf("ERROR: TCPStatus -> status not implemented"); + break; + } + } + } + + void + consume(const IMC::TransmissionRequest* msg) + { + if (msg->getDestination() != getSystemId()) + return; + + switch (msg->comm_mean) + { + case (IMC::TransmissionRequest::CMEAN_SATELLITE): + m_router.sendViaSatellite(msg, m_args.iridium_plain_texts); + break; + case (IMC::TransmissionRequest::CMEAN_GSM): + if (msg->destination.empty() || msg->destination == "broadcast") { + IMC::TransmissionRequest req = *msg->clone(); + req.destination = m_ctx.config.get(c_sms_section, c_sms_field); + m_router.sendViaGSM(&req); + } + else + m_router.sendViaGSM(msg); + break; + case (IMC::TransmissionRequest::CMEAN_ACOUSTIC): + m_router.sendViaAcoustic(msg); + break; + case (IMC::TransmissionRequest::CMEAN_WIFI): + m_router.sendViaWifi(msg); + break; + case (IMC::TransmissionRequest::CMEAN_ANY): + m_router.sendViaAny(msg, m_args.iridium_plain_texts); + break; + case (IMC::TransmissionRequest::CMEAN_ALL): + m_router.sendViaAll(msg, m_args.iridium_plain_texts); + break; + default: + m_router.answer(msg, "Communication mean not implemented.", + IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE); + break; + } + } + + //Conversion from Sms to SmsRequest Message + void + consume(const IMC::Sms* msg) + { + if (msg->getSource() != getSystemId() && msg->getDestination() != getSystemId()) + return; + + uint16_t newId = m_router.createInternalId(); + + SmsRequest sms_req; + + sms_req.req_id = newId; + sms_req.destination = msg->number; + sms_req.sms_text = msg->contents; + sms_req.timeout = msg->timeout; + sms_req.setSource(msg->getSource()); + sms_req.setSourceEntity(msg->getSourceEntity()); + + dispatch(sms_req); + } + + //Conversion from AcousticOperation to AcousticRequest Message + void + consume(const IMC::AcousticOperation* msg) + { + if (!m_args.enable_acoustic) + { + return; + } + + if (msg->getSource() != getSystemId() && msg->getDestination() != getSystemId()) + return; + + uint16_t newId = m_router.createInternalId(); + + AcousticRequest tx; + //set message id + tx.req_id = newId; + + //set destination + if (msg->system == "") + tx.destination = "broadcast"; + else + tx.destination = msg->system.c_str(); + + tx.setDestination(msg->getDestination()); + tx.setDestinationEntity(msg->getDestinationEntity()); + tx.setSource(getSystemId()); + tx.setSourceEntity(getEntityId()); + + tx.timeout = 10; + + tx.range = msg->range; + + //set message type + switch (msg->op) + { + case IMC::AcousticOperation::AOP_MSG: + { + tx.type = IMC::AcousticRequest::TYPE_MSG; + //set message content + const IMC::Message * inlinemsg = msg->msg.get(); + tx.msg.set(inlinemsg->clone()); + break; + } + + case IMC::AcousticOperation::AOP_ABORT: + { + tx.type = IMC::AcousticRequest::TYPE_ABORT; + break; + } + case IMC::AcousticOperation::AOP_RANGE: + { + tx.type = IMC::AcousticRequest::TYPE_RANGE; + break; + } + case IMC::AcousticOperation::AOP_REVERSE_RANGE: + { + tx.type = IMC::AcousticRequest::TYPE_REVERSE_RANGE; + break; + } + default: + { + //answer(msg, "Communication mode not implemented for communication mean Acoustic", IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE); + return; + break; + } + } + + //add to transmission_queue + m_acoustic_requests[newId] = msg->clone(); + dispatch(tx); + } + + IMC::StateReport* + produceReport() + { + if (m_vstate == NULL || m_estate == NULL) + return NULL; + + IMC::EstimatedState* estate = new IMC::EstimatedState(*m_estate); + IMC::VehicleState* vstate = new IMC::VehicleState(*m_vstate); + + IMC::StateReport* report = new IMC::StateReport(); + report->stime = (int)Clock::getSinceEpoch(); + + // get current position + double lat = estate->lat, lon = estate->lon; + WGS84::displace(estate->x, estate->y, &lat, &lon); + lat = Angles::degrees(lat); + lon = Angles::degrees(lon); + + report->latitude = (fp32_t)lat; + report->longitude = (fp32_t)lon; + + if (estate->depth != -1) + report->depth = Math::roundToInteger(estate->depth * 10.0f); + else + report->depth = 0xFFFF; + + if (estate->alt != -1) + report->altitude = Math::roundToInteger(estate->alt * 10.0f); + else + report->altitude = 0xFFFF; + + report->speed = Math::roundToInteger(estate->u * 100.0f); + + double ang = Angles::normalizeRadian(estate->psi); + if (ang < 0) + ang += Math::c_two_pi; + report->heading = Math::roundToInteger((ang / c_two_pi) * 65535); + + if (m_fuel != NULL) + report->fuel = Math::roundToInteger(m_fuel->value); + + switch (vstate->op_mode) + { + case VehicleState::VS_SERVICE: + report->exec_state = -1; + break; + case VehicleState::VS_BOOT: + report->exec_state = -2; + break; + case VehicleState::VS_CALIBRATION: + report->exec_state = -3; + report->plan_checksum = m_plan_chksum; + break; + default: + if (m_pstate != NULL) + { + report->exec_state = Math::roundToInteger(m_pstate->plan_progress); + report->plan_checksum = m_plan_chksum; + } + else + report->exec_state = -2; + break; + } + + Memory::clear(vstate); + Memory::clear(estate); + return report; + } + + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + + if (m_retransmission_timer.overflow()) + { + while (!m_retransmission_list.empty()) + { + consume(m_retransmission_list.front()); + m_retransmission_list.pop_front(); + } + m_retransmission_timer.reset(); + } + + if (m_clean_timer.overflow()) + { + m_router.clearTimeouts(); + m_clean_timer.reset(); + } + + if (m_args.iridium_period > 0 && m_iridium_timer.overflow()) + { + if (m_vmedium != NULL && m_vmedium->medium == IMC::VehicleMedium::VM_WATER) + { + IMC::StateReport* msg = produceReport(); + if (msg != NULL) + { + dispatch(msg); + inf("Requesting report transmission over Iridium."); + IMC::TransmissionRequest request; + request.setDestination (getSystemId()); + request.comm_mean = IMC::TransmissionRequest::CMEAN_SATELLITE; + request.data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + request.deadline = Time::Clock::getSinceEpoch() + m_args.iridium_period; + request.destination = "broadcast"; + request.msg_data.set(msg); + request.req_id = m_router.createInternalId(); + dispatch(request, DF_LOOP_BACK); + + Memory::clear(msg); + } + m_iridium_timer.reset(); + } + } + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Transports/DataStore/DataStore.hpp b/src/Transports/DataStore/DataStore.hpp new file mode 100644 index 0000000000..2cbf17535d --- /dev/null +++ b/src/Transports/DataStore/DataStore.hpp @@ -0,0 +1,315 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Jose Pinto * +//*************************************************************************** + +#ifndef SRC_TRANSPORTS_DATASTORE_DATASTORE_HPP_ +#define SRC_TRANSPORTS_DATASTORE_DATASTORE_HPP_ + +#define BASE_HISTORY_SIZE 36 +#define MINIMUM_SAMPLE_SIZE 15 + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include + +namespace Transports +{ + namespace DataStore + { + using DUNE_NAMESPACES; + + //! Class used to store a single sample. + //! All samples have a location, timestamp, priority and a message (IMC). + class DataSample + { + public: + //! Sample global coordinates + double latDegs, lonDegs, zMeters, timestamp; + + //! Priority of the sample (higher priority samples are transmitted first) + int priority; + + //! The system that generated this sample + int source; + + //! Actual data gathered at these coords + IMC::Message* sample; + + DataSample(void) + { + latDegs = lonDegs = zMeters = timestamp = 0; + priority = source = -1; + sample = NULL; + } + + ~DataSample(void) + { + if (sample != NULL) + delete sample; + } + + int + serializationSize(void) + { + return sample->getPayloadSerializationSize() + MINIMUM_SAMPLE_SIZE; + } + }; + + class CompareSamples + { + public: + bool operator()(const DataSample* p1, const DataSample* p2) const + { + return p1->priority <= p2->priority && p1->timestamp < p2->timestamp; + } + }; + + //! Translate a (global coordinates) Data Sample into an IMC HistoricSample message + HistoricSample* + parse(DataSample* sample, double base_lat, double base_lon, long base_time) + { + HistoricSample* s = new HistoricSample(); + + double lat1 = Angles::radians(base_lat); + double lat2 = Angles::radians(sample->latDegs); + double lon1 = Angles::radians(base_lon); + double lon2 = Angles::radians(sample->lonDegs); + double x, y, z; + + // compute displacement to used relative to base coordinates + WGS84::displacement(lat1, lon1, 0, lat2, lon2, 0, &x, &y, &z); + s->x = (int16_t) x; + s->y = (int16_t) y; + s->z = (int16_t) (sample->zMeters * 10); + s->t = (int16_t) (sample->timestamp - base_time); + + // other fields are copied from original + s->sys_id = sample->source; + s->sample.set(sample->sample); + s->priority = sample->priority; + return s; + } + + //! Given an HistoricData message, extract all samples + void + parse(const IMC::HistoricData* data, std::vector& samples, std::vector& commands) + { + IMC::MessageList::const_iterator it; + + for (it = data->data.begin(); it != data->data.end(); it++) + { + if ((*it)->getId() == RemoteCommand::getIdStatic()) + { + commands.push_back(static_cast((*it)->clone())); + } + else + { + const HistoricSample* sample = static_cast(*it); + DataSample* s = new DataSample(); + + double lat = Angles::radians(data->base_lat); + double lon = Angles::radians(data->base_lon); + WGS84::displace((sample)->x, (sample)->y, &lat, &lon); + s->latDegs = Angles::degrees(lat); + s->lonDegs = Angles::degrees(lon); + s->source = (sample)->sys_id; + s->timestamp = data->base_time + (sample)->t; + s->zMeters = (sample)->z / 10.0; + s->sample = (sample)->sample.get()->clone(); + samples.push_back(s); + } + } + } + + //! This class is used to store samples locally until they are forwarded to other node + class DataStore + { + public: + DataStore(Task* task): + m_task(task) + { } + + ~DataStore(void) + { + Concurrency::ScopedRWLock(m_lock, true); + while (!m_samples.empty()) + { + delete m_samples.top(); + m_samples.pop(); + } + } + + //! Add sample to this store + void + addSample(DataSample* sample) + { + Concurrency::ScopedRWLock(m_lock, true); + m_task->debug("Adding sample %d/%f", sample->sample->getId(), sample->timestamp); + m_samples.push(sample); + } + + //! Add a series of historic samples packed as an HistoricData message + void + addData(const IMC::HistoricData * data) + { + std::vector new_samples; + std::vector commands; + parse(data, new_samples, commands); + std::vector::iterator it; + std::vector::iterator cmd; + for (it = new_samples.begin(); it != new_samples.end(); it++) + addSample(*it); + for (cmd = commands.begin(); cmd != commands.end(); cmd++) + { + uint16_t dst = (*cmd)->destination; + double timeout = (*cmd)->timeout; + + // if command has timed-out, drop it + if (Clock::getSinceEpoch() > timeout) + { + m_task->debug("Dropping expired remote command."); + continue; + } + + // if message's destination is this system, dispatch it locally + if (dst == m_task->getSystemId()) + { + Message * msg = (*cmd)->cmd.get(); + msg->setDestination(dst); + msg->setSource((*cmd)->original_source); + m_task->debug("Dispatching remote command of type %s sent by %s.", + msg->getName(), + m_task->resolveSystemId((*cmd)->original_source)); + + m_task->dispatch(msg, DF_KEEP_SRC_EID); + } + else + { + m_task->debug("Adding (multi-hop) remote command."); + m_commands.push_back(*cmd); + } + } + } + + //! Retrieve a series of commands that take up to 'size' + IMC::HistoricData* + pollCommands(int destination, int size) + { + size -= BASE_HISTORY_SIZE; // base fields from HistoricData + IMC::HistoricData* ret = new IMC::HistoricData(); + + // add commands for that destination + std::vector::iterator cmd_it; + + cmd_it = m_commands.begin(); + while(cmd_it != m_commands.end()) { + if ((*cmd_it)->destination == destination) { + int ser_size = (*cmd_it)->getSerializationSize(); + if (ser_size < size) + { + size -= ser_size; + ret->data.push_back(*cmd_it); + cmd_it = m_commands.erase(cmd_it); + continue; + } + } + cmd_it++; + } + + if (ret->data.size() == 0) + return NULL; + else + return ret; + } + + //! Retrieve a series of sample that take up to 'size' + IMC::HistoricData* + pollSamples(int size) + { + + size -= BASE_HISTORY_SIZE; // base fields from HistoricData + IMC::HistoricData* ret = new IMC::HistoricData(); + + std::vector added, rejected; + + Concurrency::ScopedRWLock(m_lock, true); + while (!m_samples.empty() && size > MINIMUM_SAMPLE_SIZE) + { + // pop next sample + DataSample* sample = m_samples.top(); + m_samples.pop(); + + // check if there is space left for this sample + int sample_size = sample->serializationSize(); + if (sample_size > size) + { + rejected.push_back(sample); + } + else + { + size -= sample_size; + added.push_back(sample); + } + } + + // add back samples that didn't fit on the message + std::vector::iterator it; + for (it = rejected.begin(); it != rejected.end(); it++) + { + m_samples.push(*it); + } + + // no data can be added + if (added.empty()) + return NULL; + + ret->base_lat = added.at(0)->latDegs; + ret->base_lon = added.at(0)->lonDegs; + ret->base_time = added.at(0)->timestamp; + + for (it = added.begin(); it != added.end(); it++) + { + DataSample * sample = *it; + ret->data.push_back( + parse(sample, ret->base_lat, ret->base_lon, ret->base_time)); + delete sample; + } + + return ret; + } + + private: + std::priority_queue , CompareSamples> m_samples; + std::vector m_commands; + Concurrency::RWLock m_lock; + Task* m_task; + }; + } +} + +#endif diff --git a/src/Transports/DataStore/Router.hpp b/src/Transports/DataStore/Router.hpp new file mode 100644 index 0000000000..ac930e3ae5 --- /dev/null +++ b/src/Transports/DataStore/Router.hpp @@ -0,0 +1,263 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Jose Pinto * +//*************************************************************************** + +#ifndef SRC_TRANSPORTS_DATASTORE_ROUTER_HPP_ +#define SRC_TRANSPORTS_DATASTORE_ROUTER_HPP_ + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include + +namespace Transports +{ + namespace DataStore + { + const int c_max_size_wifi = 32 * 1024; + const int c_max_size_acoustic = 1000; + const int c_max_size_iridium = 220; + + const int c_wifi_timeout = 15; + const int c_acoustic_timeout = 300; + + using DUNE_NAMESPACES; + + class Router + { + public: + uint16_t m_reqid; + + Router(Task* parent) + { + m_reqid=0, + m_parent = parent; + } + + void + process(const IMC::EstimatedState* msg) + { + Concurrency::ScopedRWLock l(m_lock, true); + std::string name = String::str(m_parent->resolveSystemId(msg->getSource())); + m_states[name] = *msg; + Memory::clear(msg); + } + + void + process(const IMC::UamRxFrame* msg) + { + Concurrency::ScopedRWLock l(m_lock, true); + m_acousticVisibility[msg->sys_src] = msg->getTimeStamp(); + Memory::clear(msg); + } + + void + process(const IMC::Announce* msg) + { + Concurrency::ScopedRWLock l(m_lock, true); + m_wifiVisibility[msg->sys_name] = *msg; + Memory::clear(msg); + } + + + bool + visibleOverWiFi(std::string system) + { + std::map::iterator it; + double curTime = Clock::getSinceEpoch(); + Concurrency::ScopedRWLock l(m_lock, false); + + it = m_wifiVisibility.find(system); + return (it != m_wifiVisibility.end() && curTime - it->second.getTimeStamp() < c_wifi_timeout); + } + + bool + visibleOverAcoustic(std::string system) + { + std::map::iterator it; + double curTime = Clock::getSinceEpoch(); + Concurrency::ScopedRWLock l(m_lock, false); + + it = m_acousticVisibility.find(system); + return (it != m_acousticVisibility.end() && curTime - it->second < c_acoustic_timeout); + } + + bool + routeOverAcoustic(std::string destination, HistoricData* data) + { + if (!visibleOverAcoustic(destination)) + return false; + + TransmissionRequest tr = makeAcousticRequest(destination,data); + tr.setDestination(m_parent->getSystemId()); + m_parent->dispatch(tr); + return true; + } + + bool + routeOverWifi(std::string destination, HistoricData* data) + { + if (!visibleOverWiFi(destination)) + return false; + + data->setDestination(m_parent->resolveSystemName(destination)); + m_parent->dispatch(data); + + return true; + } + + void + forwardCommandsWifi(DataStore* store) + { + std::map::iterator it; + Concurrency::ScopedRWLock l(m_lock, false); + double curTime = Clock::getSinceEpoch(); + + for (it = m_wifiVisibility.begin(); it != m_wifiVisibility.end(); it++) + { + if (curTime - it->second.getTimeStamp() < c_wifi_timeout) + { + IMC::HistoricData* cmds = store->pollCommands(it->second.getSource(), c_max_size_wifi); + if (cmds != NULL) + { + m_parent->inf("Forwarding commands over Wifi to %s.", it->first.c_str()); + cmds->setDestination(it->second.getSource()); + m_parent->dispatch(cmds); + } + } + } + } + + void + forwardCommandsAnyMean(DataStore* store) + { + std::map::iterator it; + Concurrency::ScopedRWLock l(m_lock, false); + double curTime = Clock::getSinceEpoch(); + + for (it = m_acousticVisibility.begin(); it != m_acousticVisibility.end(); it++) + { + if (curTime - it->second < c_acoustic_timeout) + { + int id = m_parent->resolveSystemName(it->first); + + IMC::HistoricData* cmds = store->pollCommands(id, c_max_size_acoustic); + if (cmds != NULL) + { + cmds->setDestination(id); + + TransmissionRequest tr = makeAcousticRequest(it->first,cmds); + + m_parent->inf("Forwarding commands over Acoustic Modem to %s.", it->first.c_str()); + m_parent->dispatch(tr); + } + } + } + } + + void + forwardCommandsAcoustic(DataStore* store) + { + std::map::iterator it; + Concurrency::ScopedRWLock l(m_lock, false); + double curTime = Clock::getSinceEpoch(); + + for (it = m_acousticVisibility.begin(); it != m_acousticVisibility.end(); it++) + { + if (curTime - it->second < c_acoustic_timeout) + { + int id = m_parent->resolveSystemName(it->first); + + IMC::HistoricData* cmds = store->pollCommands(id, c_max_size_acoustic); + if (cmds != NULL) + { + cmds->setDestination(id); + + TransmissionRequest tr = makeAcousticRequest(it->first,cmds); + + m_parent->inf("Forwarding commands over Acoustic Modem to %s.", it->first.c_str()); + m_parent->dispatch(tr); + } + } + } + } + + TransmissionRequest + makeAcousticRequest(std::string destination,IMC::HistoricData* hist){ + + IMC::TransmissionRequest msg; + msg.comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + msg.data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + msg.destination = destination; + msg.req_id = createInternalId(); + msg.msg_data.set(hist); + + return msg; + + } + + uint16_t + createInternalId(){ + if(m_reqid==0xFFFF){ + m_reqid=0; + } + else{ + m_reqid++; + } + return m_reqid; + } + + void iridiumUpload(DataStore* store) + { + IMC::HistoricData* data = store->pollSamples(c_max_size_iridium); + if (data == NULL) + return; + + IMC::TransmissionRequest tr; + tr.comm_mean = IMC::TransmissionRequest::CMEAN_SATELLITE; + tr.data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + tr.msg_data.set(data->clone()); + tr.deadline = Time::Clock::getSinceEpoch() + 120; + tr.req_id = createInternalId(); + m_parent->inf("Requesting upload of %u samples via Iridium.", (uint32_t) data->data.size()); + m_parent->dispatch(tr); + Memory::clear(data); + } + + ~Router() + { } + private: + Task* m_parent; + std::map m_acousticVisibility; + std::map m_wifiVisibility; + std::map m_states; + Concurrency::RWLock m_lock; + }; + } +} + +#endif /* SRC_TRANSPORTS_DATASTORE_ROUTER_HPP_ */ diff --git a/src/Transports/DataStore/Task.cmake b/src/Transports/DataStore/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Transports/DataStore/Task.cpp b/src/Transports/DataStore/Task.cpp new file mode 100644 index 0000000000..2b86db3694 --- /dev/null +++ b/src/Transports/DataStore/Task.cpp @@ -0,0 +1,545 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Jose Pinto * +//*************************************************************************** + +// ISO C++ 98 headers. +#include + +// DUNE headers. +#include +#include "DataStore.hpp" +#include "Router.hpp" + +namespace Transports +{ + namespace DataStore + { + using DUNE_NAMESPACES; + + struct Arguments + { + //! List of messages to store. + std::vector messages; + + //! If set, messages will be forwarded to gateway using wifi + std::string wifi_gateway; + + //! If set, messages will be forwarded to gateway using acoustic modem + std::string acoustic_gateway; + + //! If set, messages will be forwarded to gateway using any comm available + std::string any_gateway; + + //! Period, in seconds, between wifi forwarding + int wifi_forward_period; + + //! Period, in seconds, between acoustic forwarding + int acoustic_forward_period; + + //! Maximum size for acoustic messages + int acoustic_mtu; + + //! Period, in seconds, between forwarding + int any_forward_period; + + //! Period, in seconds, between iridium uploads (0 == deactivated) + int iridium_upload_period; + + //! Variable priorities will result in older + //! data being sent through low bandwidth connections + bool variable_priorities; + }; + + struct Task: public DUNE::Tasks::Task + { + //! object used to store samples locally + DataStore m_store; + + //! task arguments + Arguments m_args; + + //! last position from local platform + IMC::EstimatedState m_state; + + //! priority for each message type + std::map m_priorities; + + //! messages currently on the way to their destination + std::map, IMC::HistoricData*> m_sending; + + //! Timer used for forwarding data over acoustic modem + Time::Counter m_acoustic_forward_timer; + + //! Timer used for forwarding data over wifi + Time::Counter m_wifi_forward_timer; + + //! Timer used for forwarding data over any mean + Time::Counter m_any_forward_timer; + + //! Timer used for uploading data over iridium + Time::Counter m_iridium_upload_timer; + + //! Number of stored local samples + int sample_count; + + //! Router is used to forward data to other systems + Router m_router; + + typedef std::map MessagesQueued; + MessagesQueued m_transmission_requests; + + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_store(this), + sample_count(0), + m_router(this) + { + param("Messages", m_args.messages) + .description("List of :"); + + param("WiFi Gateway", m_args.wifi_gateway) + .description("If set, messages will be forwarded to gateway using wifi") + .defaultValue(""); + + param("Acoustic Gateway", m_args.acoustic_gateway) + .description("If set, messages will be forwarded to gateway using acoustic modem") + .defaultValue(""); + + param("Any Mean Gateway", m_args.any_gateway) + .description("If set, messages will be forwarded to gateway using any comm available") + .defaultValue(""); + + param("WiFi Forward Period", m_args.wifi_forward_period) + .description("WiFi forwarding period, in seconds") + .defaultValue("30"); + + param("Acoustic Forward Period", m_args.acoustic_forward_period) + .description("Acoustic forwarding period, in seconds") + .defaultValue("300"); + + param("Acoustic MTU", m_args.acoustic_mtu) + .description("Maximum Size To Transmit Over Acoustic") + .defaultValue("250"); + + param("Any Mean Forward Period", m_args.any_forward_period) + .description("Any mean upload period, in seconds.") + .defaultValue("30"); + + param("Iridium Upload Period", m_args.iridium_upload_period) + .description("Iridium upload period, in seconds. 0 Deactivates uploading via Iridium.") + .defaultValue("0"); + + param("Variable priorities", m_args.variable_priorities) + .description("Apply variable priorities to local samples") + .defaultValue("true"); + + m_wifi_forward_timer.setTop(m_args.wifi_forward_period); + m_acoustic_forward_timer.setTop(m_args.acoustic_forward_period); + m_any_forward_timer.setTop(m_args.any_forward_period); + m_iridium_upload_timer.setTop(m_args.iridium_upload_period); + } + + void + onUpdateParameters(void) + { + m_priorities.clear(); + std::vector consumed; + int priority = 0; + std::vector parts; + + // initialize list of messages to be consumed + for (unsigned int i = 0; i < m_args.messages.size(); ++i) + { + parts.clear(); + Utils::String::split(m_args.messages[i], ":", parts); + if (parts.size() == 2) + { + if (std::sscanf(parts[1].c_str(), "%d", &priority) && priority > 0) + { + m_priorities[parts[0]] = priority; + consumed.push_back(parts[0]); + debug("Will store message %s with priority %d.", parts[0].c_str(), priority); + continue; + } + } + throw std::runtime_error(Utils::String::str(DTR("invalid format: %s"), m_args.messages[i].c_str())); + } + + // consume these messages on top of transported messages + consumed.push_back("HistoricData"); + consumed.push_back("EstimatedState"); + consumed.push_back("HistoricDataQuery"); + consumed.push_back("Announce"); + consumed.push_back("UamRxFrame"); + consumed.push_back("TransmissionStatus"); + + std::stringstream ss; + for (std::vector::const_iterator it = consumed.begin(); it != consumed.end(); it++) + ss << *it << " "; + + bind(this, consumed); + + m_wifi_forward_timer.setTop(m_args.wifi_forward_period); + m_acoustic_forward_timer.setTop(m_args.acoustic_forward_period); + m_any_forward_timer.setTop(m_args.any_forward_period); + m_iridium_upload_timer.setTop(m_args.iridium_upload_period); + } + + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + + void + consume(const IMC::Message* msg) + { + if (msg->getId() == EstimatedState::getIdStatic()) + { + m_router.process(static_cast(msg->clone())); + process(static_cast(msg->clone())); + } + else if (msg->getId() == HistoricData::getIdStatic()) + process(static_cast(msg->clone())); + else if (msg->getId() == HistoricDataQuery::getIdStatic()) + process(static_cast(msg->clone())); + else if (msg->getId() == UamRxFrame::getIdStatic()) + m_router.process(static_cast(msg->clone())); + else if (msg->getId() == Announce::getIdStatic()) + m_router.process(static_cast(msg->clone())); + else if (msg->getId() == TransmissionStatus::getIdStatic()) + process(static_cast(msg->clone())); + + // only store messages with some defined priority (transported) + if (m_priorities.find(msg->getName()) == m_priorities.end()) + return; + + war("Storing message of type %s.", msg->getName()); + + // only start storing messages after there is a known system position + if (m_state.lat == 0) + return; + + if (m_ctx.resolver.isLocal(msg->getSource())) + { + DataSample* sample = new DataSample(); + + int num = sample_count++; + int add_priority = 0; + if (m_args.variable_priorities) + { + while (num % 2) + { + add_priority++; + num /= 2; + } + } + + // use last EstimatedState for this sample's position + double lat = m_state.lat, lon = m_state.lon; + WGS84::displace(m_state.x, m_state.y, &lat, &lon); + sample->latDegs = Angles::degrees(lat); + sample->lonDegs = Angles::degrees(lon); + sample->zMeters = m_state.depth != -1? -m_state.depth : m_state.alt; + sample->source = msg->getSource(); + sample->timestamp = msg->getTimeStamp(); + sample->sample = msg->clone(); + // retrieve priority set in the configuration + sample->priority = m_priorities[msg->getName()] + add_priority; + inf("Added message of type %s with size %d and priority %d to data store.", + msg->getName(), sample->serializationSize(), sample->priority); + m_store.addSample(sample); + } + } + + //! Updates position of this platform + void + process(const IMC::EstimatedState* msg) + { + if (m_ctx.resolver.isLocal(msg->getSource())) + m_state = *msg; + } + + //! Updates position of this platform + void + process(const IMC::TransmissionStatus* msg) + { + if (msg->getDestination() != getSystemId() + || msg->getDestinationEntity() != getEntityId()) + return; + + if (m_transmission_requests.find(msg->req_id) + != m_transmission_requests.end()) + { + IMC::TransmissionRequest* req = m_transmission_requests[msg->req_id]; + switch (msg->status) + { + case IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE: + war("not possible to forward data through %s by any mean at this time.", + m_args.any_gateway.c_str()); + m_store.addData((IMC::HistoricData*)req->msg_data.get()); + m_transmission_requests.erase(msg->req_id); + Memory::clear(req); + break; + + case IMC::TransmissionStatus::TSTAT_SENT: + inf("Routed samples to %s using any mean available", + m_args.any_gateway.c_str()); + m_transmission_requests.erase(msg->req_id); + Memory::clear(req); + break; + + case IMC::TransmissionStatus::TSTAT_INPUT_FAILURE: + war("not possible to forward data through %s by any mean at this time.", + m_args.any_gateway.c_str()); + m_store.addData((IMC::HistoricData*)req->msg_data.get()); + m_transmission_requests.erase(msg->req_id); + Memory::clear(req); + break; + + case IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE: + war("not possible to forward data through %s by any mean at this time.", + m_args.any_gateway.c_str()); + m_store.addData((IMC::HistoricData*)req->msg_data.get()); + m_transmission_requests.erase(msg->req_id); + Memory::clear(req); + break; + + default: + return; + } + + } + + } + + //! Process incoming HistoricData (multi-hop forwarding) + void + process(const IMC::HistoricData* msg) + { + // avoid loop back + if (m_ctx.resolver.isLocal(msg->getSource()) && getEntityId() == msg->getSourceEntity()) + return; + + if (!m_ctx.resolver.isLocal(msg->getSource())) + debug("Received %u items from %s.", (uint32_t) msg->data.size(), resolveSystemId(msg->getSource())); + else + debug("Adding %u items from %s (%d) to data store.", (uint32_t) msg->data.size(), + m_ctx.resolver.resolve(msg->getSource()), msg->getSource()); + + // add all data to local store + m_store.addData(msg); + } + + //! Handle incoming HistoricDataQuery messages + void + process(const IMC::HistoricDataQuery* msg) + { + std::pair source = std::pair(msg->getSource(), msg->getSourceEntity()); + + if (msg->type == IMC::HistoricDataQuery::HRTYPE_QUERY) + { + if (m_sending.find(source) != m_sending.end()) + { + debug("Adding back data previously queried from same peer as it wasn't cleared with HRTYPE_CLEAR."); + m_store.addData(m_sending[source]); + delete m_sending[source]; + m_sending.erase(source); + } + + IMC::HistoricDataQuery reply; + IMC::HistoricData* data = m_store.pollSamples(msg->max_size); + if (data != NULL) + { + m_sending[source] = static_cast(data->clone()); + reply.data.set(data); + Memory::clear(data); + } + + if (m_ctx.resolver.isLocal(msg->getSource())) + debug("Sending historic data to entity %s.", m_ctx.entities.resolve(msg->getSourceEntity()).c_str()); + else + debug("Sending historic data to system %s.", m_ctx.resolver.resolve(msg->getSource())); + + reply.max_size = msg->max_size; + reply.req_id = msg->req_id; + reply.type = IMC::HistoricDataQuery::HRTYPE_REPLY; + reply.setDestination(msg->getSource()); + reply.setDestinationEntity(msg->getSourceEntity()); + dispatch(reply); + } + else if (msg->type == IMC::HistoricDataQuery::HRTYPE_CLEAR) + { + IMC::HistoricDataQuery reply; + reply.req_id = msg->req_id; + reply.type = IMC::HistoricDataQuery::HRTYPE_CLEAR; + reply.setDestination(msg->getSource()); + reply.setDestinationEntity(msg->getSourceEntity()); + dispatch(reply); + if (m_sending.find(source) != m_sending.end()) + { + debug("Clearing previously queried data from store"); + m_sending.erase(source); + } + else + { + debug("No previously queried data to clear."); + } + } + Memory::clear(msg); + } + + void + anyMeanRouting() + { + inf("forwarding to gateway over any mean"); + + IMC::HistoricData* data = m_store.pollSamples(1000); + + uint16_t newId = m_router.createInternalId(); + + TransmissionRequest tr; + tr.setSource(getSystemId()); + tr.setSourceEntity(getEntityId()); + tr.setDestination(getSystemId()); + + tr.comm_mean = IMC::TransmissionRequest::CMEAN_ANY; + tr.data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + tr.destination = m_args.any_gateway; + tr.req_id = newId; + tr.msg_data.set(data); + tr.deadline = Clock::getSinceEpoch() + m_args.any_forward_period; + + dispatch(tr); + m_transmission_requests[newId] = tr.clone(); + + Memory::clear(data); + } + + void + acousticRouting() + { + IMC::HistoricData* data = m_store.pollSamples(m_args.acoustic_mtu); + int size = 0; + if (data != NULL) + size = (int)data->data.size(); + else + war("Nothing to forward via acoustic modem."); + + if (size > 0 && !m_router.routeOverAcoustic(m_args.acoustic_gateway, data)) + { + war("not possible to forward data through %s acoustically at this time.", + m_args.acoustic_gateway.c_str()); + m_store.addData(data); + } + else { + inf("Routed %d samples to %s using Acoustic Modem", size, m_args.acoustic_gateway.c_str()); + } + + Memory::clear(data); + } + + void + wifiRouting() + { + + debug("forwarding to gateway over wifi"); + + IMC::HistoricData* data = m_store.pollSamples(32 * 1024); + if (data == NULL) + return; + if (!m_router.routeOverWifi(m_args.wifi_gateway, data)) + { + war("not possible to forward data over WiFi through %s at this time.", m_args.wifi_gateway.c_str()); + m_store.addData(data); + } + else + inf("Routed %u samples to %s using UDP", (uint32_t) data->data.size(), m_args.wifi_gateway.c_str()); + + Memory::clear(data); + } + + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + + std::stringstream ss; + + if (m_args.any_forward_period > 0 && m_any_forward_timer.overflow()) + { + m_any_forward_timer.reset(); + //m_router.forwardCommandsAnyMean(&m_store); + + if (!m_args.any_gateway.empty()) + anyMeanRouting(); + } + else if (m_args.any_forward_period > 0) + ss << " Any mean: " << m_any_forward_timer.getRemaining(); + else + ss << " Any mean: N/A"; + + + if (m_args.acoustic_forward_period > 0 && m_acoustic_forward_timer.overflow()) + { + m_acoustic_forward_timer.reset(); + m_router.forwardCommandsAcoustic(&m_store); + + if (!m_args.acoustic_gateway.empty()) + acousticRouting(); + } + else if (m_args.acoustic_forward_period > 0) + ss << " Acoustic: " << m_acoustic_forward_timer.getRemaining(); + else + ss << " Acoustic: N/A"; + + if (m_args.wifi_forward_period > 0 && m_wifi_forward_timer.overflow()) + { + m_wifi_forward_timer.reset(); + m_router.forwardCommandsWifi(&m_store); + + if (!m_args.wifi_gateway.empty()) + wifiRouting(); + } + else if (m_args.wifi_forward_period > 0) + ss << " Wi-Fi: " << m_wifi_forward_timer.getRemaining(); + else + ss << " Wi-Fi: N/A"; + + if (m_args.iridium_upload_period > 0 && m_iridium_upload_timer.overflow()) + { + m_iridium_upload_timer.reset(); + m_router.iridiumUpload(&m_store); + } + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Transports/Discovery/Task.cpp b/src/Transports/Discovery/Task.cpp index bcc7a7ffca..ce6575c7fa 100644 --- a/src/Transports/Discovery/Task.cpp +++ b/src/Transports/Discovery/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/Evologics/Driver.hpp b/src/Transports/Evologics/Driver.hpp index 9a87bd4c96..f1b275e92e 100644 --- a/src/Transports/Evologics/Driver.hpp +++ b/src/Transports/Evologics/Driver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -77,9 +77,11 @@ namespace Transports "SENDEND", "SENDPBM", "RECVPBM", - "CANCELEDPBM" + "RECVSRV", + "STATUS" }; + class Driver: public HayesModem { public: @@ -184,6 +186,14 @@ namespace Transports expectOK(); } + //! Set modem driver timeout + //! @param[in] timeout time to wait (seconds). + void + setDriverTimeout(double timeout) + { + setTimeout(timeout); + } + //! Retrieve the firmware version string. //! @return firmware version. std::string @@ -267,8 +277,10 @@ namespace Transports sendAT("?T"); std::string str = readLine(); unsigned value = 0; - if (!castLexical(str, value)) + if (!castLexical(str, value)) { + getTask()->debug("invalid format: getPropagationTime"); throw Hardware::InvalidFormat(str); + } return value; } @@ -281,8 +293,10 @@ namespace Transports sendAT("?CA"); std::string str = readLine(); unsigned value = 0; - if (!castLexical(str, value)) + if (!castLexical(str, value)) { + getTask()->debug("invalid format: getSoundSpeed"); throw Hardware::InvalidFormat(str); + } return value; } @@ -318,8 +332,11 @@ namespace Transports sendAT("?CLOCK"); std::string str = readLine(); unsigned value = 0; - if (!castLexical(str, value)) + if (!castLexical(str, value)) { + getTask()->debug("invalid format: getClock"); + throw Hardware::InvalidFormat(str); + } return value; } @@ -340,8 +357,10 @@ namespace Transports for (unsigned i = 0; i < 16; ++i) { ss >> mp[i]; - if (ss.fail()) + if (ss.fail()) { + getTask()->debug("invalid format: getMultipathStructure"); throw Hardware::InvalidFormat(str); + } } return mp; @@ -499,6 +518,8 @@ namespace Transports private: //! Firmware version. std::string m_version; + //! Mode + std::string m_mode = "unknown"; //! Physical layer protocol version. std::string m_phy_ptl_version; //! Data-link layer protocol version. @@ -509,6 +530,15 @@ namespace Transports void sendInitialization(void) { + // Get mode + sendAT("?MODE"); + m_mode = readLine(); + getTask()->debug("Mode: %s", m_mode.c_str()); + + if(m_mode.compare("NET") != 0) { + throw std::runtime_error("invalid mode for Evologics"); + } + // Get firmware version. sendAT("I0"); m_version = readLine(); diff --git a/src/Transports/Evologics/Replies.hpp b/src/Transports/Evologics/Replies.hpp index a3ed8af046..b94c6e8849 100644 --- a/src/Transports/Evologics/Replies.hpp +++ b/src/Transports/Evologics/Replies.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/Evologics/Task.cpp b/src/Transports/Evologics/Task.cpp index 400b64fdcb..7fec665656 100644 --- a/src/Transports/Evologics/Task.cpp +++ b/src/Transports/Evologics/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -43,6 +43,11 @@ namespace Transports { using DUNE_NAMESPACES; + //! Simulator command timeout. + static const double c_sim_timeout = 6.0; + //! Default port. + static const int c_default_port = 9200; + struct Arguments { //! IP address. @@ -53,6 +58,8 @@ namespace Transports bool low_gain; //! Source level. unsigned source_level; + //! Carrier waveform ID. + unsigned waveform_id; //! Connection retry count. unsigned con_retry_count; //! Connection retry timeout. @@ -67,6 +74,8 @@ namespace Transports double sound_speed_def; //! Entity label of sound speed provider. std::string sound_speed_elabel; + //! Entity label of modem simulator. + std::string simulator_elabel; //! Keep-alive timeout. double kalive_tout; //! Highest address. @@ -112,6 +121,8 @@ namespace Transports Counter m_kalive_counter; //! Medium. IMC::VehicleMedium m_medium; + //! Simulator flag + bool m_simulating; //! Task arguments. Arguments m_args; @@ -130,7 +141,7 @@ namespace Transports .description("IPv4 address"); param("TCP Port", m_args.port) - .defaultValue("9200") + .defaultValue(std::to_string(c_default_port)) .description("TCP port"); param("Low Gain", m_args.low_gain) @@ -143,6 +154,12 @@ namespace Transports .maximumValue("3") .description("Signal transmission source level during data exchange"); + param("Waveform ID", m_args.waveform_id) + .defaultValue("2") + .minimumValue("0") + .maximumValue("2") + .description("Carrier waveform ID for Evologics modems"); + param("Connection Retry Count", m_args.con_retry_count) .defaultValue("3") .minimumValue("0") @@ -186,6 +203,12 @@ namespace Transports param("Sound Speed - Entity Label", m_args.sound_speed_elabel) .description("Entity label of sound speed provider"); + param("Simulator - Entity Label", m_args.simulator_elabel) + .defaultValue("Evologics Interface") + .description("Entity label of Evologics simulator. If task is found the " + "address is set to local (172.0.0.1) and port is set based on " + "\"Address Section\" parameter (default + address)."); + param("Keep Alive - Timeout", m_args.kalive_tout) .defaultValue("5.0") .units(Units::Second) @@ -228,14 +251,42 @@ namespace Transports void onEntityResolution(void) { + processEntityForSoundSpeed(); + + // Check for Evologics simulator try { - m_sound_speed_eid = resolveEntity(m_args.sound_speed_elabel); + resolveEntity(m_args.simulator_elabel); + m_simulating = m_ctx.profiles.isSelected("Simulation"); } - catch (...) + catch(const std::exception& e) { - debug("dynamic sound speed corrections are disabled"); + m_simulating = false; + } + + debug("Simulator %sfound", m_simulating ? "" : "not "); + } + + void + processEntityForSoundSpeed(void) + { + try + { + if (m_args.sound_speed_elabel.length() == 0) + { + inf("dynamic sound speed corrections are disabled, using default %d", (int)m_args.sound_speed_def); + m_sound_speed = m_args.sound_speed_def; + m_sound_speed_eid = DUNE_IMC_CONST_UNK_EID; + } + else + m_sound_speed_eid = resolveEntity(m_args.sound_speed_elabel); + } + catch (std::exception& e) + { + err("problem resolving entity for dynamic sound speed corrections: %s", e.what()); + war("dynamic sound speed corrections are disabled, using default %f", m_args.sound_speed_def); m_sound_speed = m_args.sound_speed_def; + m_sound_speed_eid = DUNE_IMC_CONST_UNK_EID; } } @@ -243,11 +294,33 @@ namespace Transports onUpdateParameters(void) { m_sound_speed = m_args.sound_speed_def; + processEntityForSoundSpeed(); } void onResourceAcquisition(void) { + // Process modem addresses. + std::string system = getSystemName(); + std::vector addrs = m_ctx.config.options(m_args.addr_section); + for (unsigned i = 0; i < addrs.size(); ++i) + { + unsigned addr = 0; + m_ctx.config.get(m_args.addr_section, addrs[i], "0", addr); + m_modem_names[addrs[i]] = addr; + m_modem_addrs[addr] = addrs[i]; + + if (addrs[i] == system) + m_address = addr; + } + + // Change port for simulation purposes + if (m_simulating) + { + m_args.port = c_default_port + m_address; + m_args.address = Address(Address::Loopback); + } + try { { @@ -268,7 +341,6 @@ namespace Transports m_driver = new Driver(this, m_sock); m_driver->setLineTermIn("\r\n"); m_driver->setLineTermOut("\n"); - m_driver->initialize(); } void @@ -288,34 +360,41 @@ namespace Transports void onResourceInitialization(void) { - // Process modem addresses. - std::string system = getSystemName(); - std::vector addrs = m_ctx.config.options(m_args.addr_section); - for (unsigned i = 0; i < addrs.size(); ++i) + try { - unsigned addr = 0; - m_ctx.config.get(m_args.addr_section, addrs[i], "0", addr); - m_modem_names[addrs[i]] = addr; - m_modem_addrs[addr] = addrs[i]; - - if (addrs[i] == system) - m_address = addr; + m_driver->initialize(); + } + catch (std::runtime_error &e) + { + war(DTR("Evologics Task desactivation: %s"), e.what()); + requestDeactivation(); + setEntityState(IMC::EntityState::ESTA_ERROR, e.what()); } - m_driver->setControl(); - m_driver->setAddress(m_address); - m_driver->setSourceLevel(m_args.source_level); - m_driver->setLowGain(m_args.low_gain); - m_driver->setRetryCount(m_args.con_retry_count); - m_driver->setRetryTimeout(m_args.con_retry_tout); - m_driver->setRetryCountIM(m_args.im_retry_count); - m_driver->setIdleTimeout(m_args.con_idle_tout); - m_driver->setHighestAddress(m_args.highest_addr); - m_driver->setPositionDataOutput(true); - m_driver->setPromiscuous(true); - m_driver->setExtendedNotifications(true); - m_kalive_counter.setTop(m_args.kalive_tout); - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + if (m_simulating) + m_driver->setDriverTimeout(c_sim_timeout); + + if (!isActive()) + requestActivation(); + + if(isActive()) + { + m_driver->setControl(); + m_driver->setAddress(m_address); + m_driver->setSourceLevel(m_args.source_level); + m_driver->setLowGain(m_args.low_gain); + m_driver->setRetryCount(m_args.con_retry_count); + m_driver->setRetryTimeout(m_args.con_retry_tout); + m_driver->setRetryCountIM(m_args.im_retry_count); + m_driver->setIdleTimeout(m_args.con_idle_tout); + m_driver->setHighestAddress(m_args.highest_addr); + m_driver->setPositionDataOutput(true); + m_driver->setPromiscuous(true); + m_driver->setCarrierWaveformID(m_args.waveform_id); + m_driver->setExtendedNotifications(true); + m_kalive_counter.setTop(m_args.kalive_tout); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + } } unsigned @@ -436,7 +515,7 @@ namespace Transports else if (String::startsWith(msg->value, "FAILEDIM")) handleMessageFailed(msg->value); else if (String::startsWith(msg->value, "BUSY")) - handleMessageFailed(msg->value); + handleMessageBusy(msg->value); else if (String::startsWith(msg->value, "SENDEND")) handleSendEnd(msg->value); else if (String::startsWith(msg->value, "RECVSTART")) @@ -445,6 +524,8 @@ namespace Transports return; else if (String::startsWith(msg->value, "RECVFAILED")) return; + else if (String::startsWith(msg->value, "RECVSRV")) + return; else if (String::startsWith(msg->value, "RECV")) handleBurstMessage(msg->value); @@ -498,6 +579,9 @@ namespace Transports if (msg->getDestination() != getSystemId()) return; + if (msg->getDestinationEntity() != 255 && msg->getDestinationEntity() != getEntityId()) + return; + // Create and fill new ticket. Ticket ticket; ticket.imc_sid = msg->getSource(); @@ -544,6 +628,7 @@ namespace Transports sendTxStatus(ticket, IMC::UamTxStatus::UTS_IP); m_kalive_counter.reset(); + } void @@ -574,6 +659,14 @@ namespace Transports clearTicket(IMC::UamTxStatus::UTS_FAILED); } + void + handleMessageBusy(const std::string& str) + { + (void)str; + m_driver->setBusy(false); + clearTicket(IMC::UamTxStatus::UTS_BUSY, "Modem replied busy"); + } + void handleMessageDelivered(const std::string& str) { @@ -728,6 +821,9 @@ namespace Transports { while (!stopping()) { + if(!isActive()) + return; + waitForMessages(1.0); keepAlive(); } diff --git a/src/Transports/Evologics/Ticket.hpp b/src/Transports/Evologics/Ticket.hpp index c43764f5c4..eab1326c02 100644 --- a/src/Transports/Evologics/Ticket.hpp +++ b/src/Transports/Evologics/Ticket.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/FTP/CommandParser.hpp b/src/Transports/FTP/CommandParser.hpp index 88f2d2d72a..c75996f46e 100644 --- a/src/Transports/FTP/CommandParser.hpp +++ b/src/Transports/FTP/CommandParser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/FTP/Replies.def b/src/Transports/FTP/Replies.def index 2c7f73be27..59d8c92362 100644 --- a/src/Transports/FTP/Replies.def +++ b/src/Transports/FTP/Replies.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/FTP/Session.cpp b/src/Transports/FTP/Session.cpp index 45eb507db2..80f25944f4 100644 --- a/src/Transports/FTP/Session.cpp +++ b/src/Transports/FTP/Session.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/FTP/Session.hpp b/src/Transports/FTP/Session.hpp index e1970a557b..d239f59995 100644 --- a/src/Transports/FTP/Session.hpp +++ b/src/Transports/FTP/Session.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/FTP/Task.cpp b/src/Transports/FTP/Task.cpp index f8cd632fc7..bb08b40959 100644 --- a/src/Transports/FTP/Task.cpp +++ b/src/Transports/FTP/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/Fragments/Task.cpp b/src/Transports/Fragments/Task.cpp index e219b847cb..6a00785241 100644 --- a/src/Transports/Fragments/Task.cpp +++ b/src/Transports/Fragments/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/GSM/Driver.hpp b/src/Transports/GSM/Driver.hpp index bc21e99754..8fc054b2ea 100644 --- a/src/Transports/GSM/Driver.hpp +++ b/src/Transports/GSM/Driver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -74,16 +74,17 @@ namespace Transports IMC::TextMessage sms; std::string location; unsigned read_count = 0; - + bool text_mode = true; sendAT("+CMGL=\"ALL\""); //! Read all messages. - while (readSMS(location, sms.origin, sms.text)) + while (readSMS(location, sms.origin, sms.text,text_mode)) { if ((location == "\"REC UNREAD\"") || (location == "\"REC READ\"")) { ++read_count; - getTask()->dispatch(sms); + if(text_mode) + getTask()->dispatch(sms); } } @@ -95,6 +96,53 @@ namespace Transports } } + std::string + getOwnNumber(void) + { + try + { + sendAT("+CPBS=ON"); + expectOK(); + sendAT("+CPBS?"); + std::string line = readLine(); + int n_registered_numbers = 0; + int n_total_capacity = 0; + if (std::sscanf(line.c_str(), "+CPBS: \"ON\",%d,%d", + &n_registered_numbers, &n_total_capacity) == 2) + { + expectOK(); + if (n_registered_numbers > 0) + { + sendAT("+CPBR=1"); + line = readLine(); + int n_index; + char n_number[20]; + int n_type; + char n_name[20]; + if (std::sscanf(line.c_str(), "+CPBR: %d,\"%[^\"]\",%d,\"%[^\"]", &n_index, + n_number,&n_type,n_name) == 4) + { + expectOK(); + if (n_index == 1) + { + + getTask()->inf(DTR("SIM card number: %s"), n_number); + return std::string(n_number); + } + } + + } + } + } + catch (...) + { + getTask()->inf("SIM card number: not found"); + return ""; + } + return ""; + + } + void sendSMS(const std::string& number, const std::string& msg, double timeout) { @@ -145,6 +193,42 @@ namespace Transports expectOK(); } + bool + getBalance(unsigned ussd_code, std::string &balance) + { + char code[50]; + sprintf(code,"+CUSD=1,\"*#%d#\"",ussd_code); + sendAT(code); + + try{ + expectOK(); + } + catch(...) { + getTask()->war("Can't read balance. Please check the USSD code or connection"); + return false; + } + std::string msg = readLine(); + Utils::String::toLowerCase(msg); + + size_t startPos = msg.find("saldo:"); + + if(startPos == std::string::npos) { + getTask()->war("Can't read balance"); + return false; + } + + std::string firstPart = msg.substr(startPos); + balance = firstPart.substr(6, firstPart.find("eur")-6); + + getTask()->debug("Saldo: %s", balance.c_str()); + + std::stringstream ss; + ss << " | " << String::str(balance) << "Eur "; + balance = ss.str(); + + return true; + } + private: //! PIN number if needed. std::string m_pin; @@ -217,7 +301,12 @@ namespace Transports return true; if (String::startsWith(str, "^RSSI")) return true; - + if(String::startsWith(str, "+CRING")) //incoming call + return true; + if(String::startsWith(str, "^CEND:")) //end of call + return true; + if(String::startsWith(str, "NO CARRIER")) //missed call + return true; return false; } @@ -250,7 +339,7 @@ namespace Transports } bool - readSMS(std::string& location, std::string& origin, std::string& text) + readSMS(std::string& location, std::string& origin, std::string& text, bool& text_mode) { std::string header = readLine(); if (header == "OK") @@ -277,7 +366,35 @@ namespace Transports location = parts[1]; origin = std::string(parts[2], 1, parts[2].size() - 2); - text = readLine(); + std::string incoming_data = readLine(); + + if(Algorithms::Base64::validBase64(incoming_data)) + { + text_mode = false; + Utils::ByteBuffer bfr; + bfr.setSize(incoming_data.length()); + std::string decoded = Algorithms::Base64::decode(incoming_data); + std::copy(decoded.begin(),decoded.end(),bfr.getBuffer()); + uint16_t length = decoded.size(); + try + { + IMC::Message* msg_d = IMC::Packet::deserialize(bfr.getBuffer(), length); + getTask()->inf(DTR("received IMC message of type %s via SMS"),msg_d->getName()); + getTask()->dispatch(msg_d); + } + catch(...) //InvalidSync || InvalidMessageId || InvalidCrc + { + getTask()->war(DTR("Parsing unrecognized Base64 message as text")); + text.assign(incoming_data); + text_mode = true; + return true; + } + } + else + { + text.assign(incoming_data); + text_mode = true; + } return true; } }; diff --git a/src/Transports/GSM/Task.cpp b/src/Transports/GSM/Task.cpp index 623f707d23..6d71e7e613 100644 --- a/src/Transports/GSM/Task.cpp +++ b/src/Transports/GSM/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -47,6 +47,9 @@ namespace Transports { using DUNE_NAMESPACES; + //! Default timer - security (m) + static const int m_balance_per_default = 5; + //! SMS struct. struct SMS { @@ -56,10 +59,25 @@ namespace Transports std::string message; // Delivery deadline. double deadline; + }; + struct SmsRequest + { + // Request id. + uint16_t req_id; + // Source address. + uint16_t src_adr; + // Source entity id. + uint8_t src_eid; + // Recipient. + std::string destination; + // Message to send. + std::string sms_text; + // Deadline to deliver the + double deadline; // Higher deadlines have less priority. bool - operator<(const SMS& other) const + operator<(const SmsRequest& other) const { return deadline > other.deadline; } @@ -82,8 +100,16 @@ namespace Transports double sms_tout; //! Device response timeout. float reply_tout; + //! Code to request balance. + unsigned ussd_code; + //! Request balance. + bool request_balance; + //! Balance periodicity (m). + unsigned balance_per; }; + static const std::string c_balance_request_param = "Request Balance"; + struct Task: public DUNE::Tasks::Task { //! Serial port handle. @@ -91,18 +117,33 @@ namespace Transports //! GSM driver. Driver* m_driver; //! SMS queue. - std::priority_queue m_queue; + std::priority_queue m_queue; //! RSSI query timer. Counter m_rssi_timer; //! SMS reception query timer. Counter m_rsms_timer; + //! SMS Request id for SMS Messages + unsigned m_req_id; //! Task arguments. Arguments m_args; + //! Balance of card + std::string m_balance; + //! Balance timer count. + Time::Counter m_balance_timer; + //! Balance periodicity (s). + int m_balance_per; + + bool m_success_balance; + int m_rssi; + Task(const std::string& name, Tasks::Context& ctx): Tasks::Task(name, ctx), m_uart(NULL), - m_driver(NULL) + m_driver(NULL), + m_req_id(1560), + m_success_balance(false), + m_rssi(0) { param("Serial Port - Device", m_args.uart_dev) .defaultValue("") @@ -136,7 +177,21 @@ namespace Transports .units(Units::Second) .description("Maximum amount of time to wait for SMS send completion"); - bind(this); + param("USSD code", m_args.ussd_code) + .defaultValue("123") + .description("USSD code"); + + param("Request Balance", m_args.request_balance) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .scope(Tasks::Parameter::SCOPE_GLOBAL) + .defaultValue("true") + .description("Enable Balance Request"); + + param("Balance Periodicity", m_args.balance_per) + .defaultValue("60") + .description("Balance Periodicity"); + + bind(this); bind(this); } @@ -148,8 +203,16 @@ namespace Transports if (paramChanged(m_args.rssi_per)) m_rssi_timer.setTop(m_args.rssi_per); + + if (paramChanged(m_args.balance_per)) { + if(m_args.balance_per > m_balance_per_default) + m_balance_timer.setTop(m_args.balance_per * 60); + else + m_balance_timer.setTop(m_balance_per_default * 60); + } } + void onResourceAcquisition(void) { @@ -161,17 +224,18 @@ namespace Transports debug("manufacturer: %s", m_driver->getManufacturer().c_str()); debug("model: %s", m_driver->getModel().c_str()); debug("IMEI: %s", m_driver->getIMEI().c_str()); + annouceNumber(); } catch (std::runtime_error& e) { - throw RestartNeeded(e.what(), 5, false); + throw RestartNeeded(DTR(e.what()), 5); } } void onResourceInitialization(void) { - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + setEntityState(IMC::EntityState::ESTA_NORMAL, getMessage(Status::CODE_IDLE).c_str()); } void @@ -201,19 +265,62 @@ namespace Transports } void - consume(const IMC::Sms* msg) + sendSmsStatus(const SmsRequest* sms_req,IMC::SmsStatus::StatusEnum status,const std::string& info = "") { - if (msg->timeout == 0) + IMC::SmsStatus sms_status; + sms_status.setDestination(sms_req->src_adr); + sms_status.setDestinationEntity(sms_req->src_eid); + sms_status.req_id = sms_req->req_id; + sms_status.info = info; + sms_status.status = status; + + dispatch(sms_status); + } + + void + consume(const IMC::SmsRequest* msg) + { + SmsRequest sms_req; + sms_req.req_id = msg->req_id; + sms_req.destination = msg->destination; + sms_req.sms_text = msg->sms_text; + sms_req.src_adr = msg->getSource(); + sms_req.src_eid = msg->getSourceEntity(); + + if (msg->timeout <= 0) { - err("%s", DTR("SMS timeout cannot be zero")); + sendSmsStatus(&sms_req,IMC::SmsStatus::SMSSTAT_INPUT_FAILURE,"SMS timeout cannot be zero"); + inf("%s", DTR("SMS timeout cannot be zero")); return; } + if(sms_req.sms_text.length() > 160) //160 characters encoded in 8-bit alphabet per SMS message + { + sendSmsStatus(&sms_req,IMC::SmsStatus::SMSSTAT_INPUT_FAILURE,"Can only send 160 characters over SMS."); + inf("%s", DTR("Can only send 160 characters over SMS")); + return; + } + sms_req.deadline = Clock::getSinceEpoch() + msg->timeout; + m_queue.push(sms_req); + sendSmsStatus(&sms_req,IMC::SmsStatus::SMSSTAT_QUEUED,DTR("SMS sent to queue")); + } + + void + annouceNumber(void) + { + std::string number = m_driver->getOwnNumber(); + if (number != "") + { - SMS sms; - sms.recipient = msg->number; - sms.message = msg->contents; - sms.deadline = Clock::get() + msg->timeout; - m_queue.push(sms); + std::stringstream os; + os << "imc+gsm://" << number << "/"; + + IMC::AnnounceService announce; + announce.service = os.str(); + announce.service_type = IMC::AnnounceService::SRV_TYPE_EXTERNAL; + + dispatch(announce); + + } } void @@ -221,30 +328,36 @@ namespace Transports { if (m_queue.empty()) { - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + setEntityState(IMC::EntityState::ESTA_NORMAL, getMessage(Status::CODE_IDLE).c_str()); return; } - setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + setEntityState(IMC::EntityState::ESTA_NORMAL, getMessage(Status::CODE_ACTIVE).c_str()); - SMS sms = m_queue.top(); + SmsRequest sms_req = m_queue.top(); m_queue.pop(); // Message is too old, discard it. - if (Clock::get() >= sms.deadline) + if (Time::Clock::getSinceEpoch() >= sms_req.deadline) { - war(DTR("discarded expired SMS to recipient '%s'"), sms.recipient.c_str()); + sendSmsStatus(&sms_req,IMC::SmsStatus::SMSSTAT_INPUT_FAILURE,DTR("SMS timeout")); + war(DTR("discarded expired SMS to recipient %s"), sms_req.destination.c_str()); return; } try { m_driver->getRSSI(); - m_driver->sendSMS(sms.recipient, sms.message, m_args.sms_tout); + m_driver->sendSMS(sms_req.destination, sms_req.sms_text, m_args.sms_tout); + //SMS successfully sent, otherwise driver throws error + sendSmsStatus(&sms_req,IMC::SmsStatus::SMSSTAT_SENT); } catch (...) { - m_queue.push(sms); + m_queue.push(sms_req); + sendSmsStatus(&sms_req,IMC::SmsStatus::SMSSTAT_ERROR, + DTR("Error sending message over GSM modem")); + inf(DTR("Error sending SMS to recipient %s"),sms_req.destination.c_str()); } } @@ -256,7 +369,7 @@ namespace Transports if (m_rssi_timer.overflow()) { m_rssi_timer.reset(); - m_driver->getRSSI(); + m_rssi = m_driver->getRSSI(); } if (m_rsms_timer.overflow()) @@ -272,6 +385,25 @@ namespace Transports } } + void checkBalance(void) + { + if(m_args.request_balance) + { + if(m_driver->getBalance(m_args.ussd_code, m_balance)) + setEntityState(IMC::EntityState::ESTA_NORMAL, getMessage(Status::CODE_ACTIVE).c_str()); + + m_args.request_balance = false; + + IMC::SetEntityParameters msg; + IMC::EntityParameter balance_param; + balance_param.name = c_balance_request_param; + balance_param.value = "false"; + msg.params.push_back(balance_param); + msg.name = getEntityLabel(); + dispatch(msg, DF_LOOP_BACK); + } + } + void onMain(void) { @@ -280,8 +412,20 @@ namespace Transports waitForMessages(1.0); pollStatus(); processQueue(); + + checkBalance(); + } } + + std::string + getMessage(Status::Code code) + { + std::stringstream ss; + ss << getString(code) << m_balance; + + return ss.str(); + } }; } } diff --git a/src/Transports/HTTP/MessageMonitor.cpp b/src/Transports/HTTP/MessageMonitor.cpp index 4596e52649..9abb74a309 100644 --- a/src/Transports/HTTP/MessageMonitor.cpp +++ b/src/Transports/HTTP/MessageMonitor.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/HTTP/MessageMonitor.hpp b/src/Transports/HTTP/MessageMonitor.hpp index 4ab6865caa..169deda0f5 100644 --- a/src/Transports/HTTP/MessageMonitor.hpp +++ b/src/Transports/HTTP/MessageMonitor.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/HTTP/RequestHandler.cpp b/src/Transports/HTTP/RequestHandler.cpp index 9cbc753265..afdb6b9528 100644 --- a/src/Transports/HTTP/RequestHandler.cpp +++ b/src/Transports/HTTP/RequestHandler.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/HTTP/RequestHandler.hpp b/src/Transports/HTTP/RequestHandler.hpp index fa3c03acb2..8dbf8dcd63 100644 --- a/src/Transports/HTTP/RequestHandler.hpp +++ b/src/Transports/HTTP/RequestHandler.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/HTTP/Server.cpp b/src/Transports/HTTP/Server.cpp index 31eb13dc8c..2ca829ce4a 100644 --- a/src/Transports/HTTP/Server.cpp +++ b/src/Transports/HTTP/Server.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/HTTP/Server.hpp b/src/Transports/HTTP/Server.hpp index 12c6f505f9..dc796f8768 100644 --- a/src/Transports/HTTP/Server.hpp +++ b/src/Transports/HTTP/Server.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/HTTP/Task.cpp b/src/Transports/HTTP/Task.cpp index 62537bfc1f..5f792476f1 100644 --- a/src/Transports/HTTP/Task.cpp +++ b/src/Transports/HTTP/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -109,6 +109,8 @@ namespace Transports void onResourceAcquisition(void) { + bind(this, m_args.messages); + uint16_t last_port = m_args.port + c_max_port_tries; for (uint16_t port = m_args.port; port < last_port; ++port) @@ -158,12 +160,6 @@ namespace Transports m_msg_mon.setEntities(m_ctx.entities.entries()); } - void - onUpdateParameters(void) - { - bind(this, m_args.messages); - } - void consume(const IMC::Message* msg) { diff --git a/src/Transports/Iridium/Task.cpp b/src/Transports/Iridium/Task.cpp index f7e22b2b32..f84d2dfe47 100644 --- a/src/Transports/Iridium/Task.cpp +++ b/src/Transports/Iridium/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -48,6 +48,8 @@ namespace Transports int max_age_secs; //! Destination to send all iridium messages std::string iridium_destination; + //! Text messages received over Iridium are tagged with this origin + std::string text_origin; }; struct Task: public DUNE::Tasks::Task @@ -59,6 +61,7 @@ namespace Transports bool m_announce_pool_empty; int m_dev_update_req_id; int m_announce_req_id; + uint16_t req_id; IMC::FuelLevel m_fuel_state; IMC::PlanControlState m_plan_state; @@ -74,6 +77,7 @@ namespace Transports m_announce_pool_empty(true), m_dev_update_req_id(10), m_announce_req_id(75), + req_id(0), m_rnd(NULL) { paramActive(Tasks::Parameter::SCOPE_GLOBAL, @@ -93,6 +97,10 @@ namespace Transports .defaultValue("1200") .description("Age, in seconds, after which received IMC messages are discarded."); + param("Iridium Text Origin", m_args.text_origin) + .description("Text messages received via Iridium will be tagged with this origin") + .defaultValue("iridium"); + bind(this); bind(this); bind(this); @@ -139,7 +147,7 @@ namespace Transports IMC::TextMessage tm; inf("received command: '%s'", irCmd->command.c_str()); tm.text = irCmd->command; - tm.origin = "Iridium"; + tm.origin = m_args.text_origin; tm.setSource(irCmd->source); std::stringstream ss; tm.toText(ss); @@ -166,6 +174,8 @@ namespace Transports sensorInfo.lon = p.lon; sensorInfo.heading = 0; + war(" System %X is at (%.5f, %.5f).", p.id, Angles::degrees(p.lat), Angles::degrees(p.lon)); + std::string name = resolveSystemId(p.id); switch (selector) @@ -221,7 +231,7 @@ namespace Transports std::string text(msg->data.begin(), msg->data.end()); IMC::TextMessage tm; tm.text = text; - tm.origin = "Iridium (text)"; + tm.origin = "iridium"; std::stringstream ss; tm.toText(ss); spew("sending this message to bus: %s", ss.str().c_str()); @@ -254,8 +264,10 @@ namespace Transports double age = Clock::getSinceEpoch() - irMsg->msg->getTimeStamp(); if (age < m_args.max_age_secs) { - inf("received IMC message of type %s via Iridium.", irMsg->msg->getName()); - dispatch(irMsg->msg); + inf("received IMC message of type %s via Iridium from %d.", irMsg->msg->getName(), irMsg->source); + IMC::Message* m2 = irMsg->msg; + m2->setSource(irMsg->source); + dispatch(m2); } else { @@ -332,7 +344,7 @@ namespace Transports if (m_last_announces.find(getSystemName()) != m_last_announces.end()) { - Announce ann = m_last_announces[getSystemName()]; + IMC::Announce* ann = &m_last_announces[getSystemName()]; std::stringstream ss; if (m_plan_state.state == IMC::PlanControlState::PCS_EXECUTING) @@ -343,20 +355,10 @@ namespace Transports if (m_vehicle_state.error_count > 0) ss << "E:" << m_vehicle_state.last_error; - ann.services = ss.str(); - DUNE::IMC::ImcIridiumMessage irMsg(&ann); - irMsg.source = getSystemId(); - irMsg.destination = 65535; - uint8_t buffer[65535]; - int len = irMsg.serialize(buffer); - - DUNE::IMC::IridiumMsgTx m; - m.data.assign(buffer, buffer + len); - m.req_id = m_rnd->random() % 65535; - m_announce_req_id = m.req_id; - m.ttl = 60; - m.setTimeStamp(); - dispatch(m); + ann->services = ss.str(); + + sendIridiumMsg(ann); + m_announce_pool_empty = false; return true; } @@ -374,8 +376,7 @@ namespace Transports } debug("queuing device updates"); - DUNE::IMC::DeviceUpdate msg; - uint8_t buffer[65535]; + IMC::DeviceUpdate msg; std::map::iterator it; for (it = m_last_announces.begin(); it != m_last_announces.end(); it++) @@ -394,23 +395,54 @@ namespace Transports msg.source = getSystemId(); msg.destination = 0xFFFF; - IMC::IridiumMsgTx m; - int len = msg.serialize(buffer); - m.data.assign(buffer, buffer + len); - m.req_id = m_rnd->random() % 65535; - m.ttl = 60; - m.setTimeStamp(); - m_dev_update_req_id = m.req_id; - dispatch(m); - std::stringstream ss; - m.toText(ss); - spew("sent the following message: %s", ss.str().c_str()); + sendIridiumMsg(&msg); + m_update_pool_empty = false; return true; } + void + sendIridiumMsg(IMC::DeviceUpdate* msg) + { + + IMC::TransmissionRequest tr; + tr.data_mode = IMC::TransmissionRequest::DMODE_RAW; + tr.comm_mean = IMC::TransmissionRequest::CMEAN_SATELLITE; + tr.req_id = req_id++; + tr.deadline = Time::Clock::getSinceEpoch() + 60; + uint8_t buffer[65535]; + int len = msg->serialize(buffer); + tr.raw_data.assign(buffer, buffer + len); + + m_dev_update_req_id = tr.req_id; + + dispatch(tr); + std::stringstream ss; + tr.toText(ss); + spew("sent the following message: %s", ss.str().c_str()); + } + + void + sendIridiumMsg(const IMC::Message* msg) + { + + IMC::TransmissionRequest tr; + tr.data_mode = IMC::TransmissionRequest::DMODE_INLINEMSG; + tr.comm_mean = IMC::TransmissionRequest::CMEAN_SATELLITE; + tr.req_id = req_id++; + tr.msg_data.set(msg->clone()); + tr.deadline = Time::Clock::getSinceEpoch() + 60; + + m_announce_req_id= tr.req_id; + + dispatch(tr); + std::stringstream ss; + tr.toText(ss); + spew("sent the following message: %s", ss.str().c_str()); + } + void onMain(void) { diff --git a/src/Transports/IridiumSBD/Driver.hpp b/src/Transports/IridiumSBD/Driver.hpp index 2feca4cad3..95a1e897c3 100644 --- a/src/Transports/IridiumSBD/Driver.hpp +++ b/src/Transports/IridiumSBD/Driver.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -58,12 +58,14 @@ namespace Transports //! Constructor. //! @param[in] task parent task. //! @param[in] uart serial port connected to the ISU. - Driver(Tasks::Task* task, SerialPort* uart): + Driver(Tasks::Task* task, SerialPort* uart, bool use_9523N, double wait_boot): HayesModem(task, uart), m_session_result_read(true), m_sbd_ring(false), m_queued_mt(0) { + m_use_9523 = use_9523N; + m_wait_boot = wait_boot; setLineTrim(true); } @@ -74,6 +76,12 @@ namespace Transports void sendReset(void) { + if(m_use_9523) + { + sendAT("R"); + Delay::wait(m_wait_boot); + } + sendAT("Z0"); } @@ -122,11 +130,15 @@ namespace Transports if (length > 0) { readRaw(timer, data, length); + data[length] = '\0'; + getTask()->debug("data: %s", data); computeChecksum(data, length, ccsum); + getTask()->debug("ccsum: %02x %02x", ccsum[0], ccsum[1]); } // Read and validate. readRaw(timer, bfr, 2); + getTask()->debug("bfr 0 | 1: %02x %02x", bfr[0], bfr[1]); if ((bfr[0] != ccsum[0]) || (bfr[1] != ccsum[1])) throw Hardware::InvalidChecksum(bfr, ccsum); @@ -246,6 +258,12 @@ namespace Transports return m_queued_mt; } + std::string + getFirmVersionLIDB(void) + { + return readValue("V"); + } + private: //! Message buffer types. enum BufferType @@ -266,6 +284,12 @@ namespace Transports bool m_sbd_ring; //! Number of MT messages waiting at the GSS. unsigned m_queued_mt; + //! Flag to control use of iridium module 9523N + bool m_use_9523; + //! Length of message received by 9523N + uint16_t m_length_msg_9523; + //! Delay of boot up of lidb board. + double m_wait_boot; //! Perform ISU initialization, this function must be called //! before any other. @@ -352,7 +376,11 @@ namespace Transports m_session_result_read = false; m_session_result.parse(str); if (m_session_result.isSuccessMT()) + { m_queued_mt = m_session_result.getQueuedMT(); + if(m_use_9523) + m_length_msg_9523 = m_session_result.getLengthMT(); + } } setSkipLine("OK"); @@ -365,8 +393,12 @@ namespace Transports void setRadioActivity(bool value) { - sendAT(value ? "*R1" : "*R0"); - expectOK(); + if(!m_use_9523) + { + getTask()->debug("setRadioActivity: %s", value ? "*R1" : "*R0"); + sendAT(value ? "*R1" : "*R0"); + expectOK(); + } } //! Enable or disable the ISU to listen for SBD Ring Alerts. @@ -374,6 +406,7 @@ namespace Transports void setRingAlert(bool value) { + getTask()->debug("setRingAlert: %s", value ? "+SBDMTA=1" : "+SBDMTA=0"); sendAT(value ? "+SBDMTA=1" : "+SBDMTA=0"); expectOK(); } @@ -383,6 +416,7 @@ namespace Transports void setAutomaticRegistration(bool value) { + getTask()->debug("setAutomaticRegistration %d", value); if (value) sendAT("+SBDAREG=1"); else @@ -394,6 +428,7 @@ namespace Transports void setIndicatorEventReporting(bool value) { + getTask()->debug("setIndicatorEventReporting %s", value ? "+CIER=1,1,0" : "+CIER=0"); sendAT(value ? "+CIER=1,1,0" : "+CIER=0"); expectOK(); } @@ -497,10 +532,31 @@ namespace Transports { return getBufferSizeMT(timer); } + else if(bfr[0] == 0) + { + if(m_use_9523) + return getBufferSizeMT(timer); + } - // Read second byte and handle SBD length. - readRaw(timer, bfr + 1, 1); - return (bfr[0] << 8) | bfr[1]; + if(m_use_9523) + { + if(m_length_msg_9523 <= 255) + { + getTask()->debug("size <255: %d ! %d", m_length_msg_9523, bfr[0]); + } + else + { + readRaw(timer, bfr + 1, 1); + getTask()->debug("size >255: %d ! %d", m_length_msg_9523, (bfr[0] << 8) | bfr[1]); + } + return m_length_msg_9523; + } + else + { + // Read second byte and handle SBD length. + readRaw(timer, bfr + 1, 1); + return (bfr[0] << 8) | bfr[1]; + } } }; } diff --git a/src/Transports/IridiumSBD/Exceptions.hpp b/src/Transports/IridiumSBD/Exceptions.hpp index 3a0cfe87d3..9603f65954 100644 --- a/src/Transports/IridiumSBD/Exceptions.hpp +++ b/src/Transports/IridiumSBD/Exceptions.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/IridiumSBD/SessionResult.hpp b/src/Transports/IridiumSBD/SessionResult.hpp index 9512f0d7db..9b07f24476 100644 --- a/src/Transports/IridiumSBD/SessionResult.hpp +++ b/src/Transports/IridiumSBD/SessionResult.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/IridiumSBD/SessionResultCode.cpp b/src/Transports/IridiumSBD/SessionResultCode.cpp index 4e1b92e2d1..d04d7662d7 100644 --- a/src/Transports/IridiumSBD/SessionResultCode.cpp +++ b/src/Transports/IridiumSBD/SessionResultCode.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/IridiumSBD/SessionResultCode.def b/src/Transports/IridiumSBD/SessionResultCode.def index 38172e6336..8bbbfd3f67 100644 --- a/src/Transports/IridiumSBD/SessionResultCode.def +++ b/src/Transports/IridiumSBD/SessionResultCode.def @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/IridiumSBD/SessionResultCode.hpp b/src/Transports/IridiumSBD/SessionResultCode.hpp index ff410402ac..37da96182b 100644 --- a/src/Transports/IridiumSBD/SessionResultCode.hpp +++ b/src/Transports/IridiumSBD/SessionResultCode.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/IridiumSBD/Task.cpp b/src/Transports/IridiumSBD/Task.cpp index c414d9fff6..bb24d7030d 100644 --- a/src/Transports/IridiumSBD/Task.cpp +++ b/src/Transports/IridiumSBD/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -58,6 +58,12 @@ namespace Transports double mbox_check_per; //! Maximum transmission rate. unsigned max_tx_rate; + //! Flush Iridium Queue on start + bool flush_queue; + //! Flag to control use of 9523N Module + bool use_9523; + //! Serial port baud rate fot 9523N Module. + unsigned uart_baud_9523; }; struct Task: public DUNE::Tasks::Task @@ -103,15 +109,26 @@ namespace Transports .units(Units::Second) .defaultValue("300") .description("Amount of time without alert rings or " - "MT SBDs before doing a mailbox check"); + "MT SBDs before doing a mailbox check"); param("Maximum Transmission Rate", m_args.max_tx_rate) .units(Units::Second) .defaultValue("0") .description(""); + param("Flush Iridium Queue", m_args.flush_queue) + .defaultValue("false"); + + param("Use 9523N Module", m_args.use_9523) + .defaultValue("false"); + + param("Serial Port 9523 - Baud Rate", m_args.uart_baud_9523) + .defaultValue("115200") + .description("Serial port baud rate for 9523N Module"); + bind(this); bind(this); + m_queued_mt = 0; } //! Destructor. @@ -124,7 +141,7 @@ namespace Transports TxRequest* req = m_tx_requests.front(); m_tx_requests.pop_front(); sendTxRequestStatus(req, IMC::IridiumTxStatus::TXSTATUS_ERROR, - DTR("task is shutting down")); + DTR("task is shutting down")); delete req; } } @@ -146,10 +163,18 @@ namespace Transports { try { - m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); - m_driver = new Driver(this, m_uart); + if(m_args.use_9523) + m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud_9523); + else + m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); + m_driver = new Driver(this, m_uart, m_args.use_9523, c_pwr_on_delay); m_driver->initialize(); m_driver->setTxRateMax(m_args.max_tx_rate); + if(m_args.use_9523) + { + inf("LIDB FW: %s", m_driver->getFirmVersionLIDB().c_str()); + inf("Model: %s | IMEI: %s", m_driver->getModel().c_str(), m_driver->getIMEI().c_str()); + } debug("manufacturer: %s", m_driver->getManufacturer().c_str()); debug("model: %s", m_driver->getModel().c_str()); debug("IMEI: %s", m_driver->getIMEI().c_str()); @@ -172,6 +197,19 @@ namespace Transports { m_mbox_check_timer.reset(); setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + + if (m_args.flush_queue) + { + IridiumMsgTx req; + std::string data = "FLUSH_MT"; + req.data.assign(data.begin(), data.end()); + req.destination = "broadcast"; + req.ttl = 60; + req.setSource(m_ctx.resolver.id()); + req.setDestination(m_ctx.resolver.id()); + consume(&req); + war("Flushing MT Queue"); + } } void @@ -210,9 +248,10 @@ namespace Transports void consume(const IMC::IridiumMsgTx* msg) { - // FIXME: check if req_id already exists. - // FIXME: check MTU. - debug("queueing message"); + if (msg->getSource() != getSystemId() + && msg->getDestination() != getSystemId()) + return; + unsigned src_adr = msg->getSource(); unsigned src_eid = msg->getSourceEntity(); TxRequest* request = new TxRequest(src_adr, src_eid, msg->req_id, @@ -224,8 +263,8 @@ namespace Transports void sendTxRequestStatus(const TxRequest* request, - IMC::IridiumTxStatus::StatusCodeEnum code, - const std::string& text = "") + IMC::IridiumTxStatus::StatusCodeEnum code, + const std::string& text = "") { IMC::IridiumTxStatus status; status.setDestination(request->getSource()); @@ -264,6 +303,7 @@ namespace Transports debug("dequeing message"); m_driver->clearBufferMO(); sendTxRequestStatus(m_tx_request, IMC::IridiumTxStatus::TXSTATUS_OK); + inf(DTR("Message sent successfully.")); Memory::clear(m_tx_request); } @@ -280,7 +320,7 @@ namespace Transports m_tx_request->invalidateMSN(); sendTxRequestStatus(m_tx_request, IMC::IridiumTxStatus::TXSTATUS_ERROR, - String::str(DTR("failed with error %u"), err_code)); + String::str(DTR("failed with error %u"), err_code)); enqueueTxRequest(m_tx_request); m_tx_request = NULL; @@ -376,6 +416,15 @@ namespace Transports m_driver->checkMailBoxAlert(); else if (m_driver->getQueuedMT() > 0 || m_mbox_check_timer.overflow()) m_driver->checkMailBox(); + else if(m_driver->getQueuedMT() == 0) //No messages to be received or sent + { + unsigned src_adr = getSystemId(); + unsigned src_eid = getEntityId(); + const std::vector data(1); + TxRequest* empty_req = new TxRequest(src_adr, src_eid, 0xFFFF, 0, data); + sendTxRequestStatus(empty_req, IMC::IridiumTxStatus::TXSTATUS_EMPTY,"No message to be received or sent."); + debug(DTR("No message to be received or sent.")); + } } else { diff --git a/src/Transports/IridiumSBD/TxRequest.hpp b/src/Transports/IridiumSBD/TxRequest.hpp index 5ef6b541e2..68b71b18b3 100644 --- a/src/Transports/IridiumSBD/TxRequest.hpp +++ b/src/Transports/IridiumSBD/TxRequest.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/LogBook/Task.cpp b/src/Transports/LogBook/Task.cpp index e75a5f654d..11145156d1 100644 --- a/src/Transports/LogBook/Task.cpp +++ b/src/Transports/LogBook/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/Logging/Task.cpp b/src/Transports/Logging/Task.cpp index 92dfd0cdea..6143e7855c 100644 --- a/src/Transports/Logging/Task.cpp +++ b/src/Transports/Logging/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -127,6 +127,16 @@ namespace Transports void onResourceInitialization(void) { + if (m_args.messages.empty()) + { + std::vector all_abbrevs; + IMC::Factory::getAbbrevs(all_abbrevs); + bind(this, all_abbrevs); + inf("Logging all messages"); + } + else + bind(this, m_args.messages); + // Initialize entity state. setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); } @@ -143,8 +153,6 @@ namespace Transports m_compression = Compression::Factory::method(m_args.lsf_compression); if (m_args.lsf_volumes.empty()) m_args.lsf_volumes.push_back(""); - - bind(this, m_args.messages); } void diff --git a/src/Transports/LoggingDigest/Task.cpp b/src/Transports/LoggingDigest/Task.cpp index 0f6ce37e84..e376cf5e97 100644 --- a/src/Transports/LoggingDigest/Task.cpp +++ b/src/Transports/LoggingDigest/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/MobileInternet/Task.cpp b/src/Transports/MobileInternet/Task.cpp index a5303489d0..fb374e9c51 100644 --- a/src/Transports/MobileInternet/Task.cpp +++ b/src/Transports/MobileInternet/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -98,6 +98,14 @@ namespace Transports bool ip_fwd; //! Enable USB Mode switch (USB pen). bool code_presentation_mode; + //! Enable dynamic DNS + bool dyn_dns; + //! Dynamic DNS update periodicity + double dyn_dns_period; + //! Dynamic DNS update url + std::string dyn_dns_url; + //! Connection timeout (seconds) + int conn_timeout; }; struct Task: public Tasks::Task @@ -112,6 +120,8 @@ namespace Transports std::string m_command_nat_start; //! Stop NAT command. std::string m_command_nat_stop; + //! Update dynamic DNS command + std::string m_command_dyndns_update; //! True if modem is powered on. bool m_powered; //! Current state machine state. @@ -119,6 +129,11 @@ namespace Transports //! Interface IPv4 address. Address m_address; Time::Counter m_conn_watchdog; + Time::Counter m_dyndns_watchdog; + //! Are we reactivating the task? + bool m_reactivating; + //! Connection timeout time in seconds + int m_conn_timeout; Task(const std::string& name, Tasks::Context& ctx): Tasks::Task(name, ctx), @@ -186,15 +201,35 @@ namespace Transports .defaultValue("true") .description("Enable or disable IP forward"); + param("Enable Dynamic DNS", m_args.dyn_dns) + .defaultValue("false") + .scope(Tasks::Parameter::SCOPE_GLOBAL) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .description("Enable or disable Dynamic DNS"); + + param("DynDNS Update Periodicity", m_args.dyn_dns_period) + .defaultValue("60") + .units(Units::Second) + .description("Number of seconds between dynamic DNS updates"); + + param("DynDNS URL", m_args.dyn_dns_url) + .defaultValue("") + .description("URL used to update dynamic DNS"); + Path script = m_ctx.dir_scripts / "dune-mobile-inet.sh"; - m_command_connect = String::str("/bin/sh %s start > /dev/null 2>&1", script.c_str()); - m_command_disconnect = String::str("/bin/sh %s stop > /dev/null 2>&1", script.c_str()); - m_command_nat_start = String::str("/bin/sh %s nat_start > /dev/null 2>&1", script.c_str()); - m_command_nat_stop = String::str("/bin/sh %s nat_stop > /dev/null 2>&1", script.c_str()); + m_command_connect = String::str("/bin/sh %s start >> /dev/null 2>&1", script.c_str()); + m_command_disconnect = String::str("/bin/sh %s stop >> /dev/null 2>&1", script.c_str()); + m_command_nat_start = String::str("/bin/sh %s nat_start >> /dev/null 2>&1", script.c_str()); + m_command_nat_stop = String::str("/bin/sh %s nat_stop >> /dev/null 2>&1", script.c_str()); + m_command_dyndns_update = String::str("/bin/sh %s dyndns_update >> /dev/null 2>&1", script.c_str()); bind(this); - m_conn_watchdog.setTop(60); + m_conn_timeout = 30; + + m_conn_watchdog.setTop(m_conn_timeout); + + m_reactivating = false; } ~Task(void) @@ -207,12 +242,16 @@ namespace Transports { if (m_args.power_channel.empty()) m_powered = true; + + if (paramChanged(m_args.dyn_dns_period)) + m_dyndns_watchdog.setTop(m_args.dyn_dns_period); } void consume(const IMC::PowerChannelState* msg) { - if (msg->name != m_args.power_channel) + + if (msg->name != m_args.power_channel) return; m_powered = (msg->state == IMC::PowerChannelState::PCS_ON); @@ -234,8 +273,28 @@ namespace Transports void onRequestDeactivation(void) { - m_sm_state = SM_DEACT_BEGIN; - updateStateMachine(); + m_sm_state = SM_DEACT_BEGIN; + updateStateMachine(); + } + + void + onDeactivation(void) + { + if (m_reactivating) + { + m_reactivating = false; + requestActivation(); + } + } + + void + requestReactivation(void) + { + m_reactivating = true; + m_conn_timeout = std::min(m_conn_timeout + 10, 240); + debug("Retrying connection using %d seconds timeout.", m_conn_timeout); + m_conn_watchdog.setTop(m_conn_timeout); + requestDeactivation(); } void @@ -295,11 +354,16 @@ namespace Transports else Environment::set("PRESENTATION_MODE", "AT"); - if (std::system(m_command_connect.c_str()) == -1) + int ret = std::system(m_command_connect.c_str()); + if (ret == -1) { err(DTR("failed to execute connect command")); return false; } + else { + debug("PPP start returned %d.", ret); + } + return true; } @@ -352,10 +416,26 @@ namespace Transports err(DTR("failed to stop NAT")); } + void + updateDynDNS() + { + + inf("Updating dynamic dns."); + + if (!m_args.dyn_dns) + return; + + Environment::set("DYNDNS_URL", m_args.dyn_dns_url); + if (std::system(m_command_dyndns_update.c_str()) == -1) + err(DTR("failed to update dynamic DNS")); + + m_dyndns_watchdog.reset(); + } + void updateStateMachine(void) { - switch (m_sm_state) + switch (m_sm_state) { case SM_IDLE: break; @@ -364,15 +444,15 @@ namespace Transports debug("starting activation sequence"); setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVATING); if (!m_args.power_channel.empty()) - m_sm_state = SM_ACT_POWER_ON; + m_sm_state = SM_ACT_POWER_ON; else m_sm_state = SM_ACT_MODEM_WAIT; - /* no break */ + /* Falls through */ case SM_ACT_POWER_ON: turnPowerOn(); m_sm_state = SM_ACT_POWER_WAIT; - /* no break */ + /* Falls through */ case SM_ACT_POWER_WAIT: if (isPowered()) @@ -383,9 +463,10 @@ namespace Transports } else { + spew("waiting for power to be on"); break; } - /* no break */ + /* Falls through */ case SM_ACT_MODEM_WAIT: if (Path(m_args.uart_dev).isDevice() || Path(m_args.uart_dev).isLink()) @@ -398,30 +479,32 @@ namespace Transports debug("No modem detected in %s, retrying...", m_args.uart_dev.c_str()); break; } + /* Falls through */ case SM_ACT_CONNECT: connect(); debug("connection succeeded"); m_sm_state = SM_ACT_DONE; m_conn_watchdog.reset(); - /* no break */ + /* Falls through */ case SM_ACT_DONE: + if (!isActive()) + activate(); debug("activation complete"); - activate(); + m_sm_state = SM_ACT_CONNECTING; - /* no break */ + /* Falls through */ case SM_ACT_CONNECTING: if (m_conn_watchdog.overflow()) { - err("Connection timed out"); - requestDeactivation(); - requestActivation(); + war("Connection timed out. Retrying..."); + requestReactivation(); } if (isConnected(&m_address)) { - debug("connected: %s", m_address.c_str()); + inf("connected: %s", m_address.c_str()); startNAT(); setEntityState(IMC::EntityState::ESTA_NORMAL, String::str(DTR("connected to the Internet with public address '%s'"), m_address.c_str())); @@ -443,7 +526,7 @@ namespace Transports case SM_DEACT_BEGIN: setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_DEACTIVATING); m_sm_state = SM_DEACT_DISCONNECT; - /* no break */ + /* Falls through */ case SM_DEACT_DISCONNECT: disconnect(); @@ -456,7 +539,7 @@ namespace Transports case SM_DEACT_POWER_OFF: turnPowerOff(); m_sm_state = SM_DEACT_POWER_WAIT; - /* no break */ + /* Falls through */ case SM_DEACT_POWER_WAIT: if (!isPowered()) @@ -468,13 +551,13 @@ namespace Transports { break; } - /* no break */ + /* Falls through */ case SM_DEACT_DONE: debug("deactivation complete"); setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); - deactivate(); m_sm_state = SM_IDLE; + deactivate(); break; } } @@ -486,6 +569,11 @@ namespace Transports { waitForMessages(1.0); updateStateMachine(); + + if(m_args.dyn_dns && m_dyndns_watchdog.overflow() && isConnected()) + { + updateDynDNS(); + } } } }; diff --git a/src/Transports/Radio/3DR.hpp b/src/Transports/Radio/3DR.hpp new file mode 100644 index 0000000000..d10e66d30c --- /dev/null +++ b/src/Transports/Radio/3DR.hpp @@ -0,0 +1,529 @@ +//*************************************************************************** +// Copyright 2007-2021 OceanScan - Marine Systems & Technology, Lda. * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: João Teixeira * +//*************************************************************************** + +#ifndef DUNE_TRANSPORTS_RADIO_3DR_HPP_INCLUDED_ +#define DUNE_TRANSPORTS_RADIO_3DR_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include +#include + +namespace Transports +{ + namespace Radio + { + using DUNE_NAMESPACES; + + static const char * AT_3DR[] = { + "+++", + "AT", + "ATI", + "ATI2", + "ATI3", + "ATI4", + "ATI5", + "ATI6", + "ATI7", + "ATO", + "ATS", + "ATZ", + "AT&W", + "AT&T=RSSI", + "AT&T=TDM", + "AT&T", + "" + }; + + //! @author João Teixeira. + class Radio3dr: public RadioDriver + { + public: + //! Entity states. + enum At_cmd + { + ENABLE_CMD, + AT, + RADIO_VERSION, + BOARD_TYPE, + BOARD_FREQUENCY, + BOARD_VERSION, + SETTABLE_EEPROM_PARAMETERS, + TDM_TIMING, + RSSI, + EXIT_AT_COMMAND_MODE, + DISPLAY_OR_SET_PARAMETER_N, + REBOOT, + WRITE_PARAMETERS_EEPROM, + ENABLE_RSSI_REPORTING, + ENABLE_TDM_REPORTING, + DISABLE_DEBUG_REPORTING, + NO_CMD + }; + + + enum Mavlink + { + NO_MAVLINK_FRAMING = 0, + FRAME_MAVLINK = 1, + LOW_LATENCY_MAVLINK = 2 + }; + + struct DeviceParam + { + std::string s0_format; + std::string s1_serial_speed; + std::string s2_air_speed; + std::string s3_net_id; + std::string s4_power_level; + std::string s5_error_correction; + std::string s6_mavlink; + std::string s7_oppresend; + std::string s8_min_frequency; + std::string s9_max_frequency; + std::string s10_mum_channels; + std::string s11_duty_cycle; + std::string s12_lbt_rssi; + std::string s13_manchester; + std::string s14_rtscts; + // hardware specs + std::string radio_version; + std::string board_type; + std::string board_frequency; + std::string board_version; + + }; + + //! Radio 3DR driver. + Radio3dr(RadioConfParam args , Tasks::Task* taskp = NULL): + RadioDriver( args ,taskp ), + cmd_mode(false) + { + } + + //! Default destructor. + ~Radio3dr(void) + { + Memory::clear(m_handle); + } + + int + configDevice(void) + { + int status; + status =DeviceVerifyConf(); + if(status==0) + return 0; + + if(status==2) + status = DeviceVerifyConf(); + task->trace("configure device final status: %d", status); + return status; + } + + int + DeviceVerifyConf() + { + std::string data; + task->spew("wait two seconds to enter in AT mode"); + Delay::wait(2); + sendCommandAndWait(commandCreate(ENABLE_CMD,data),1); + sendCommandAndWait(commandCreate(REBOOT,data),3); + Delay::wait(3); + sendCommandAndWait(commandCreate(ENABLE_CMD,data),1); + sendCommandAndWait(commandCreate(AT,data),1); + m_line.clear(); + sendCommandAndWait(commandCreate(AT,data),1); + if(!(String::startsWith(m_last_line,"OK" ))) + { + task->err("Not in AT mode"); + return 0; + } + cmd_mode = true; + sendCommandAndWait(commandCreate(RADIO_VERSION,data),1); + if(device_param.radio_version.size()==0) + { + task->err("Incorrect radio_version"); + return 0; + } + sendCommandAndWait(commandCreate(BOARD_TYPE,data),1); + if(device_param.board_type.size()==0) + { + task->err("Incorrect board_type"); + return 0; + } + sendCommandAndWait(commandCreate(BOARD_FREQUENCY,data),1); + if(device_param.board_frequency.size()==0) + { + task->err("Incorrect board_frequency"); + return 0; + } + sendCommandAndWait(commandCreate(BOARD_VERSION,data),1); + if(device_param.board_version.size()==0) + { + task->err("Incorrect board_version"); + return 0; + } + + sendCommandAndWait(commandCreate(RSSI,data),1); + if(device_reports.rssi.size()==0) + { + task->err("No RSSI reporting"); + return 0; + } + + sendCommandAndWait(commandCreate(TDM_TIMING,data),1); + if(device_reports.tdm_timing_max_data_packet.size()==0) + { + task->err("No tdm_timing reporting"); + return 0; + } + + sendCommandAndWait(commandCreate(SETTABLE_EEPROM_PARAMETERS,data),1); + + //todo verify if necessary + // S6: MAVLINK=1 + // S7: OPPRESEND=1 + // S12: LBT_RSSI=0 + // S13: MANCHESTER=0 + // S14: RTSCTS=0 + bool changed =false; + + if(radioParams.air_speed.compare(device_param.s2_air_speed) !=0) + { + data = "2="+ radioParams.air_speed; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change air_speed from %s to %s",device_param.s2_air_speed.c_str(),radioParams.air_speed.c_str()); + changed=true; + } + if(radioParams.net_id.compare(device_param.s3_net_id) !=0) + { + data = "3="+ radioParams.net_id; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change net_id from %s to %s",device_param.s3_net_id.c_str(),radioParams.net_id.c_str()); + changed=true; + } + if(radioParams.power_level.compare(device_param.s4_power_level) !=0) + { + data ="4="+ radioParams.power_level; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change power_level from %s to %s",device_param.s4_power_level.c_str(),radioParams.power_level.c_str()); + changed=true; + } + if(radioParams.error_correction && device_param.s5_error_correction.compare("1") !=0 ) + { + data ="5=1"; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change error_correction from %s to %s",device_param.s5_error_correction.c_str(),"1"); + changed=true; + + } + if( !radioParams.error_correction && device_param.s5_error_correction.compare("0") != 0 ) + { + data ="5=0"; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change error_correction from %s to %s",device_param.s5_error_correction.c_str(),"0"); + changed=true; + + } + if(radioParams.min_frequency.compare(device_param.s8_min_frequency) !=0) + { + data= "8=" + String::str("%s", radioParams.min_frequency.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change min_frequency from %s to %s",device_param.s8_min_frequency.c_str(),radioParams.min_frequency.c_str()); + changed=true; + } + + if(radioParams.max_frequency.compare(device_param.s9_max_frequency) !=0) + { + data= "9=" + String::str("%s", radioParams.max_frequency.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change max_frequency from %s to %s",device_param.s9_max_frequency.c_str(),radioParams.max_frequency.c_str()); + changed=true; + } + + if(radioParams.mum_channels.compare(device_param.s10_mum_channels) !=0) + { + data= "10=" + String::str("%s", radioParams.mum_channels.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change mum_channels from %s to %s",device_param.s10_mum_channels.c_str(),radioParams.mum_channels.c_str()); + changed=true; + } + + if(radioParams.duty_cycle.compare(device_param.s11_duty_cycle) !=0) + { + data= "11=" + String::str("%s", radioParams.duty_cycle.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change duty_cycle from %s to %s",device_param.s11_duty_cycle.c_str(),radioParams.duty_cycle.c_str()); + changed=true; + } + + if (changed) + { + data.clear(); + sendCommandAndWait(commandCreate(WRITE_PARAMETERS_EEPROM,data),3); + sendCommandAndWait(commandCreate(REBOOT,data),3); + return 2; + } + data.clear(); + //enable radio report + if(radioParams.rssi_report) + sendCommandAndWait(commandCreate(ENABLE_RSSI_REPORTING,data),1); + if(radioParams.tdm_report) + sendCommandAndWait(commandCreate(ENABLE_TDM_REPORTING,data),1); + //disable CMD line + data.clear(); + sendCommandAndWait(commandCreate(EXIT_AT_COMMAND_MODE,data),3); + cmd_mode = false; + return 1; + } + + std::string + commandCreate(At_cmd cmd_type, std::string& data) + { + std::string command; + + if(ENABLE_CMD == cmd_type) + { + command = AT_3DR[cmd_type]; + } + else + { + if(data.size()>0) + { + command = (AT_3DR[cmd_type]+data + "\r\n"); + } + else + { + std::string cmd = AT_3DR[cmd_type]; + command = (cmd + "\r\n"); + } + } + last_command = command; + return command ; + } + + + void + sendCommandAndWait(const std::string& cmd, double delay_aft) + { + sendCommand(cmd); + processInputInit(delay_aft); + } + + void + sendCommand(const std::string& cmd) + { + m_handle->writeString(cmd.c_str()); + m_dev_data.value.assign("TX: " + sanitize(cmd)); + task->dispatch(m_dev_data); + task->spew("%s",m_dev_data.value.c_str()); + } + + void + sendString(std::string& msg) + { + std::string data = "$"+ msg; + sendCommand(commandCreate(NO_CMD,data)); + } + + bool + saveIfExpectedCmdIs(const std::string& msg, std::string& expectedCmd, std::string& output) + { + if(String::startsWith(msg, expectedCmd.c_str())) + { + output = msg.substr(expectedCmd.size()); + output = sanitize(output.erase(output.size()-1)); + task->trace("For %s output is: %s",expectedCmd.c_str(),output.c_str()); + return true; + } + return false; + } + + //! Process sentence. + //! @param[in] msg sentence. + void + process(const std::string msg) + { + + m_dev_data.value.assign("RX: " + sanitize(msg)); + task->spew("%s",m_dev_data.value.c_str()); + task->dispatch(m_dev_data); + + try + { + + //AT comadns + if(cmd_mode) + { + if(String::startsWith(last_command,AT_3DR[RADIO_VERSION])) + { + if(String::startsWith(msg,"SiK")) + { + device_param.radio_version = msg; + task->trace("%s",device_param.radio_version.c_str()); + } + } + + if(String::startsWith(last_command,AT_3DR[BOARD_TYPE])) + { + if(String::startsWith(msg,"78")) + { + device_param.board_type = msg; + task->trace("%s",device_param.board_type.c_str()); + } + } + + if(String::startsWith(last_command,AT_3DR[BOARD_FREQUENCY])) + { + if(String::startsWith(msg,"67")) + { + device_param.board_frequency = msg; + task->trace("%s",device_param.board_frequency.c_str()); + } + } + + if(String::startsWith(last_command,AT_3DR[BOARD_VERSION])) + { + if(String::startsWith(msg,"1")) + { + device_param.board_version = msg; + task->trace("%s",device_param.board_version.c_str()); + } + } + + if(String::startsWith(last_command,AT_3DR[SETTABLE_EEPROM_PARAMETERS])) + { + + std::string output; + + std::string expectedCMD = "S0: FORMAT="; + saveIfExpectedCmdIs(msg, expectedCMD, device_param.s0_format); + expectedCMD = "S1: SERIAL_SPEED="; + saveIfExpectedCmdIs(msg, expectedCMD, device_param.s1_serial_speed); + expectedCMD ="S2: AIR_SPEED="; + saveIfExpectedCmdIs(msg, expectedCMD, device_param.s2_air_speed); + expectedCMD ="S3: NETID="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s3_net_id); + expectedCMD ="S4: TXPOWER="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s4_power_level); + expectedCMD ="S5: ECC="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s5_error_correction); + expectedCMD ="S6: MAVLINK="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s6_mavlink); + expectedCMD ="S7: OPPRESEND="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s7_oppresend); + expectedCMD ="S8: MIN_FREQ="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s8_min_frequency); + expectedCMD ="S9: MAX_FREQ="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s9_max_frequency); + expectedCMD ="S10: NUM_CHANNELS="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s10_mum_channels); + expectedCMD ="S11: DUTY_CYCLE="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s11_duty_cycle); + expectedCMD ="S12: LBT_RSSI="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s12_lbt_rssi); + expectedCMD ="S13: MANCHESTER="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s13_manchester); + expectedCMD ="S14: RTSCTS="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s14_rtscts); + + } + + if(String::startsWith(last_command,AT_3DR[TDM_TIMING])) + { + if(String::startsWith(msg,"tx_window_width:")) + { + device_reports.tdm_timing_tx_window = msg; + task->trace("%s",device_reports.tdm_timing_tx_window.c_str()); + + } + if(String::startsWith(msg,"silence_period:")) + { + device_reports.tdm_timing_silence_period = msg; + task->trace("%s",device_reports.tdm_timing_silence_period.c_str()); + + } + if(String::startsWith(msg,"max_data_packet_length:")) + { + std::string expectedCMD= "max_data_packet_length:"; + saveIfExpectedCmdIs(msg, expectedCMD,device_reports.tdm_timing_max_data_packet); + task->trace("max_data_packet_length: %s",device_reports.tdm_timing_max_data_packet.c_str()); + } + + } + + + } + //End AT commands + if(String::startsWith(msg,"$")) + { + std::string tmp = msg; + tmp.erase( (msg.size()- 1), 1); + tmp.erase(0,1); + device_reports.data_report = tmp; + device_reports.report_status[DATA_REPORT] = true; + //task->spew("data_report:%s",device_reports.data_report.c_str()); + } + //Radio Report + if(String::startsWith(msg,"L/R RSSI:")) + { + device_reports.rssi = msg; + device_reports.report_status[RSSI_REPORT] = true; + task->spew("%s",device_reports.rssi.c_str()); + } + + if(String::startsWith(msg,"TDM:")) + { + device_reports.tdm_report = msg; + device_reports.report_status[TDM_REPORT] = true; + task->spew("%s",device_reports.tdm_report.c_str()); + } + } + catch (std::exception& e) + { + task->err("%s", e.what()); + } + + } + + protected: + + DeviceParam device_param; + bool cmd_mode; + std::string last_command; + }; + } +} + + +#endif + diff --git a/src/Transports/Radio/RadioDriver.hpp b/src/Transports/Radio/RadioDriver.hpp new file mode 100644 index 0000000000..e5a5cf1e04 --- /dev/null +++ b/src/Transports/Radio/RadioDriver.hpp @@ -0,0 +1,324 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: João Teixeira * +//*************************************************************************** + +#ifndef DUNE_TRANSPORTS_RADIO_RADIODRIVER_HPP_INCLUDED_ +#define DUNE_TRANSPORTS_RADIO_RADIODRIVER_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include +#include + +namespace Transports +{ + namespace Radio + { + using DUNE_NAMESPACES; + static const int c_bfr_size = 256; + //! % RadioDriver provide an API for different radio telemetry devices + //! + //! @author João Teixeira. + enum ReportType + { + NONE_REPORT, + RSSI_REPORT, + TDM_TIMING_MAX_DATA_PACKET_REPORT, + TDM_TIMING_SILENCE_PERIOD_REPORT, + TDM_TIMING_TX_WINDOW_REPORT, + TDM_REPORT, + DATA_REPORT, + SIZE_REPORT + }; + + struct RadioConfParam + { + //! Radio Model + std::string radio_model; + //! Serial port baud rate. + unsigned uart_baud; + //! Serial port device. + std::string uart_dev; + //! radio power level + std::string power_level; + //! radio air spead + std::string air_speed; + //! radio duty cycle + std::string duty_cycle; + //! radio number of channels + std::string mum_channels; + //! Network ID + std::string net_id; + //! mavlink framing + bool mavlink_framing; + //! Vehicle to bind if i am a server + std::string vehicle_name; + //! Radio max frequency + std::string max_frequency; + //! Radio min frequency + std::string min_frequency; + //! radio hardware error correction + bool error_correction; + //! RSSI report + bool rssi_report; + //! TDM report + bool tdm_report; + }; + + struct DeviceReports + { + // reports + std::string rssi; + std::string tdm_timing_max_data_packet; + std::string tdm_timing_silence_period; + std::string tdm_timing_tx_window; + std::string tdm_report; + std::string data_report; + bool report_status[SIZE_REPORT]; + }; + + class RadioDriver + { + public: + DeviceReports device_reports; + + RadioDriver( RadioConfParam args , Tasks::Task* taskp = NULL): + task(taskp), + m_handle(NULL), + radioParams(args) + { + } + + //! Default destructor. + virtual + ~RadioDriver(void) + { + Memory::clear(m_handle); + } + + virtual int configDevice (void) = 0; + virtual void process(const std::string msg) = 0; + + bool + processNewReport() + { + std::string rxData; + if (device_reports.data_report.size() > 6 && device_reports.report_status[DATA_REPORT] == true) + { + if (processCrc()) + { + rxData = String::fromHex(device_reports.data_report); + device_reports.report_status[DATA_REPORT] = false; + device_reports.data_report.clear(); + driverRxRata.push(rxData); + //task->trace( "New Telemetry Report size %d rxData: %s", (int) rxData.size(),rxData.c_str()); + return true; + } + device_reports.report_status[DATA_REPORT] = false; + } + return false; + + } + + bool + newRxData(std::string& rx_data) + { + if(!driverRxRata.empty()) + { + rx_data = driverRxRata.front(); + driverRxRata.pop(); + return true; + } + return false; + } + + void + clearNewRxData() + { + while (!driverRxRata.empty()) + { + driverRxRata.pop(); + } + } + + virtual void sendString(std::string& data) = 0; + + bool + processCrc(void) + { + bool msg_validity = false; + uint16_t crc, crc2; + + std::string msg = String::fromHex(device_reports.data_report.substr((device_reports.data_report.size() - 4), 4)); + std::memcpy(&crc2, msg.data(), 2); + std::string m_datahex = String::fromHex(device_reports.data_report.erase((device_reports.data_report.size() - 4), 4)); + crc = CRC16::compute((uint8_t*) m_datahex.data(), m_datahex.size(),0); + if (crc == crc2) + { + msg_validity = true; + } + else + { task->trace("crc %d %d %s",crc,crc2, device_reports.data_report.c_str()); + task->war("%s", DTR(Status::getString(Status::CODE_INVALID_CHECKSUM))); + } + return msg_validity; + } + + bool + sendData(std::string txData) + { + //add crc + uint16_t temp_crc = CRC16::compute((uint8_t*) txData.data(), txData.size(),0); + uint16_t crc = ((0x00ff & temp_crc) << 8) + ((0xff00 & temp_crc) >> 8); + std::string message_build = String::toHex(txData)+ String::str("%04X",(uint16_t) crc); + sendString(message_build); + task->trace( "RadioDriver: size %d txData: %s CRC %d ", (int) message_build.size(), message_build.c_str(), crc); + return 1; + } + int + maxDataPacket() + { + //todo update + int max_data_packet = atoi(device_reports.tdm_timing_max_data_packet.c_str()); + return max_data_packet; + } + + //! Read sentence. + bool + readSentence(void) + { + bool active = false; + if (Poll::poll(*m_handle, 0.05)) + { + char bfr[c_bfr_size]; + size_t rv = m_handle->readString(bfr, sizeof(bfr)); + for (size_t i = 0; i < rv; ++i) + { + // Detected line termination. + if (bfr[i] == '\n') + { + process(m_line); + processNewReport(); + m_last_line= m_line; + m_line.clear(); + } + else + { + if( bfr[i] != '+') + m_line.push_back(bfr[i]); + } + active = true; + } + } + return active; + } + + bool + openSocket(void) + { + char socket_addr[128] = { 0 }; + unsigned port = 0; + + if (std::sscanf(radioParams.uart_dev.c_str(), "tcp://%[^:]:%u", socket_addr, &port) != 2) + return false; + + TCPSocket* sock = new TCPSocket; + sock->connect(socket_addr, port); + m_handle = sock; + return true; + } + + int + connectToDevice() + { + try + { + if (openSocket()) + return 1; + + SerialPort* port = new SerialPort(radioParams.uart_dev, radioParams.uart_baud); + port->setCanonicalInput(true); + port->flush(); + m_handle = port; + } + catch (std::runtime_error& e) + { + throw RestartNeeded(e.what(), 30); + } + return 1; + } + + void + processInputInit(double timeout = 0.05) + { + double deadline = Clock::get() + timeout; + do + { + readSentence(); + } + while (Clock::get() <= deadline); + } + + bool + processInput(double timeout = 0.05) + { + bool active = false; + double deadline = Clock::get() + timeout; + do + { + active=readSentence(); + } + while (Clock::get() <= deadline); + return active; + } + + protected: + + Tasks::Task* task; + // Save modem commands. + IMC::DevDataText m_dev_data; + //! Serial port handle. + IO::Handle* m_handle; + //! Current line. + std::string m_line; + //! last line. + std::string m_last_line; + //! radio Params + RadioConfParam radioParams; + + std::queue driverRxRata; + + }; + } +} + +#endif + diff --git a/src/Transports/Radio/RadioRFDXXXxPtP.hpp b/src/Transports/Radio/RadioRFDXXXxPtP.hpp new file mode 100644 index 0000000000..6bdc3d9790 --- /dev/null +++ b/src/Transports/Radio/RadioRFDXXXxPtP.hpp @@ -0,0 +1,552 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: João Teixeira * +//*************************************************************************** + +#ifndef DUNE_TRANSPORTS_RADIO_RADIORFDXXXXPTP_HPP_INCLUDED_ +#define DUNE_TRANSPORTS_RADIO_RADIORFDXXXXPTP_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include + +// DUNE headers. +#include +#include + +namespace Transports +{ + namespace Radio + { + using DUNE_NAMESPACES; + + static const char * AT_RFDPTP[] = { + "+++", + "AT", + "ATI", + "ATI2", + "ATI3", + "ATI4", + "ATI5", + "ATI6", + "ATI7", + "ATO", + "ATS", + "ATZ", + "AT&W", + "AT&T=RSSI", + "AT&T=TDM", + "AT&T", + "" + }; + + //! @author João Teixeira. + class RadioRFDXXXxPtP: public RadioDriver + { + public: + //! Entity states. + enum At_cmd + { + ENABLE_CMD, + AT, + RADIO_VERSION, + BOARD_TYPE, + BOARD_FREQUENCY, + BOARD_VERSION, + SETTABLE_EEPROM_PARAMETERS, + TDM_TIMING, + RSSI, + EXIT_AT_COMMAND_MODE, + DISPLAY_OR_SET_PARAMETER_N, + REBOOT, + WRITE_PARAMETERS_EEPROM, + ENABLE_RSSI_REPORTING, + ENABLE_TDM_REPORTING, + DISABLE_DEBUG_REPORTING, + NO_CMD + }; + + + enum Mavlink + { + NO_MAVLINK_FRAMING = 0, + FRAME_MAVLINK = 1, + LOW_LATENCY_MAVLINK = 2 + }; + + struct DeviceParam + { + std::string s0_format; + std::string s1_serial_speed; + std::string s2_air_speed; + std::string s3_net_id; + std::string s4_power_level; + std::string s5_error_correction; + std::string s6_mavlink; + std::string s7_oppresend; + std::string s8_min_frequency; + std::string s9_max_frequency; + std::string s10_mum_channels; + std::string s11_duty_cycle; + std::string s12_lbt_rssi; + std::string s13_manchester; + std::string s14_rtscts; + // hardware specs + std::string radio_version; + std::string board_type; + std::string board_frequency; + std::string board_version; + + }; + + //! Radio RadioRFDXXXxPtP driver. + RadioRFDXXXxPtP(RadioConfParam args , Tasks::Task* taskp = NULL): + RadioDriver( args ,taskp ), + cmd_mode(false) + { + } + + //! Default destructor. + ~RadioRFDXXXxPtP(void) + { + Memory::clear(m_handle); + } + + int + configDevice(void) + { + int status; + status =DeviceVerifyConf(); + if(status==0) + return 0; + + if(status==2) + status = DeviceVerifyConf(); + task->trace("configure device final status: %d", status); + return status; + } + + int + DeviceVerifyConf() + { + std::string data; + task->spew("wait two seconds to enter in AT mode"); + Delay::wait(2); + sendCommandAndWait(commandCreate(ENABLE_CMD,data),1); + sendCommandAndWait(commandCreate(REBOOT,data),6); + Delay::wait(3); + sendCommandAndWait(commandCreate(ENABLE_CMD,data),1); + sendCommandAndWait(commandCreate(AT,data),1); + m_line.clear(); + sendCommandAndWait(commandCreate(AT,data),1); + + if(!(String::startsWith(m_last_line,"OK" ))) + { + task->err("Not in AT mode"); + return 0; + } + cmd_mode = true; + + sendCommandAndWait(commandCreate(RADIO_VERSION,data),1); + if(device_param.radio_version.size()==0) + { + task->err("Incorrect radio_version"); + return 0; + } + sendCommandAndWait(commandCreate(BOARD_TYPE,data),1); + if(device_param.board_type.size()==0) + { + task->err("Incorrect board_type"); + return 0; + } + sendCommandAndWait(commandCreate(BOARD_FREQUENCY,data),1); + if(device_param.board_frequency.size()==0) + { + task->err("Incorrect board_frequency"); + return 0; + } + sendCommandAndWait(commandCreate(BOARD_VERSION,data),1); + if(device_param.board_version.size()==0) + { + task->err("Incorrect board_version"); + return 0; + } + + sendCommandAndWait(commandCreate(RSSI,data),1); + if(device_reports.rssi.size()==0) + { + task->err("No RSSI reporting"); + return 0; + } + + sendCommandAndWait(commandCreate(TDM_TIMING,data),1); + if(device_reports.tdm_timing_max_data_packet.size()==0) + { + task->err("No tdm_timing reporting"); + return 0; + } + + sendCommandAndWait(commandCreate(SETTABLE_EEPROM_PARAMETERS,data),1); + + //todo verify if necessary + // S6: MAVLINK=1 + // S7: OPPRESEND=1 + // S12: LBT_RSSI=0 + // S13: MANCHESTER=0 + // S14: RTSCTS=0 + bool changed =false; + + if(radioParams.air_speed.compare(device_param.s2_air_speed) !=0) + { + data = "2="+ radioParams.air_speed; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change air_speed from %s to %s",device_param.s2_air_speed.c_str(),radioParams.air_speed.c_str()); + changed=true; + } + if(radioParams.net_id.compare(device_param.s3_net_id) !=0) + { + data = "3="+ radioParams.net_id; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change net_id from %s to %s",device_param.s3_net_id.c_str(),radioParams.net_id.c_str()); + changed=true; + } + if(radioParams.power_level.compare(device_param.s4_power_level) !=0) + { + data ="4="+ radioParams.power_level; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change power_level from %s to %s",device_param.s4_power_level.c_str(),radioParams.power_level.c_str()); + changed=true; + } + if(radioParams.error_correction && device_param.s5_error_correction.compare("1") !=0 ) + { + data ="5=1"; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change error_correction from %s to %s",device_param.s5_error_correction.c_str(),"1"); + changed=true; + + } + if( !radioParams.error_correction && device_param.s5_error_correction.compare("0") != 0 ) + { + data ="5=0"; + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change error_correction from %s to %s",device_param.s5_error_correction.c_str(),"0"); + changed=true; + + } + if(radioParams.min_frequency.compare(device_param.s8_min_frequency) !=0) + { + data= "8=" + String::str("%s", radioParams.min_frequency.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change min_frequency from %s to %s",device_param.s8_min_frequency.c_str(),radioParams.min_frequency.c_str()); + changed=true; + } + + if(radioParams.max_frequency.compare(device_param.s9_max_frequency) !=0) + { + data= "9=" + String::str("%s", radioParams.max_frequency.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change max_frequency from %s to %s",device_param.s9_max_frequency.c_str(),radioParams.max_frequency.c_str()); + changed=true; + } + + if(radioParams.mum_channels.compare(device_param.s10_mum_channels) !=0) + { + data= "10=" + String::str("%s", radioParams.mum_channels.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change mum_channels from %s to %s",device_param.s10_mum_channels.c_str(),radioParams.mum_channels.c_str()); + changed=true; + } + + if(radioParams.duty_cycle.compare(device_param.s11_duty_cycle) !=0) + { + data= "11=" + String::str("%s", radioParams.duty_cycle.c_str()); + sendCommandAndWait(commandCreate(DISPLAY_OR_SET_PARAMETER_N, data),1); + task->trace("change duty_cycle from %s to %s",device_param.s11_duty_cycle.c_str(),radioParams.duty_cycle.c_str()); + changed=true; + } + + if (changed) + { + data.clear(); + sendCommandAndWait(commandCreate(WRITE_PARAMETERS_EEPROM,data),3); + sendCommandAndWait(commandCreate(REBOOT,data),6); + return 2; + } + data.clear(); + //enable radio rssi report + if(radioParams.rssi_report) + sendCommandAndWait(commandCreate(ENABLE_RSSI_REPORTING,data),1); + if(radioParams.tdm_report) + sendCommandAndWait(commandCreate(ENABLE_TDM_REPORTING,data),1); + //disable CMD line + data.clear(); + sendCommandAndWait(commandCreate(EXIT_AT_COMMAND_MODE,data),3); + cmd_mode = false; + + return 1; + } + + std::string + commandCreate(At_cmd cmd_type, std::string& data) + { + std::string command; + + if(ENABLE_CMD == cmd_type) + { + command = AT_RFDPTP[cmd_type]; + } + else + { + if(data.size()>0) + { + command = (AT_RFDPTP[cmd_type]+data + "\r\n"); + } + else + { + std::string cmd = AT_RFDPTP[cmd_type]; + command = (cmd + "\r\n"); + } + } + last_command = command; + return command ; + } + + + void + sendCommandAndWait(const std::string& cmd, double delay_aft) + { + sendCommand(cmd); + processInputInit(delay_aft); + } + + void + sendCommand(const std::string& cmd) + { + m_handle->writeString(cmd.c_str()); + m_dev_data.value.assign("TX: " + sanitize(cmd)); + task->dispatch(m_dev_data); + task->spew("%s",m_dev_data.value.c_str()); + } + + void + sendString(std::string& msg) + { + std::string data = "$"+ msg; + sendCommand(commandCreate(NO_CMD,data)); + } + + bool + saveIfExpectedCmdIs(const std::string& msg, std::string& expectedCmd, std::string& output) + { + if(String::startsWith(msg, expectedCmd.c_str())) + { + output = msg.substr(expectedCmd.size()); + output = sanitize(output.erase(output.size()-1)); + task->trace("For %s output is: %s",expectedCmd.c_str(),output.c_str()); + return true; + } + return false; + } + + //! Process sentence. + //! @param[in] msg sentence. + void + process(const std::string msg) + { + + m_dev_data.value.assign("RX: " + sanitize(msg)); + task->spew("%s",m_dev_data.value.c_str()); + task->dispatch(m_dev_data); + + try + { + + //AT comadns + if(cmd_mode) + { + if(String::startsWith(last_command,AT_RFDPTP[RADIO_VERSION])) + { + if(String::startsWith(msg,"RFD SiK 2.60")) + { + device_param.radio_version = msg; + task->trace("%s",device_param.radio_version.c_str()); + } + } + + if(String::startsWith(last_command,AT_RFDPTP[BOARD_TYPE])) + { + if(String::startsWith(msg,"131")) + { + device_param.board_type = msg; + task->trace("%s",device_param.board_type.c_str()); + } + } + + if(String::startsWith(last_command,AT_RFDPTP[BOARD_FREQUENCY])) + { + if(String::startsWith(msg,"0X0086")) + { + device_param.board_frequency = msg; + task->trace("%s",device_param.board_frequency.c_str()); + } + } + + if(String::startsWith(last_command,AT_RFDPTP[BOARD_VERSION])) + { + if(String::startsWith(msg,"255")) + { + device_param.board_version = msg; + task->trace("%s",device_param.board_version.c_str()); + } + } + + if(String::startsWith(last_command,AT_RFDPTP[SETTABLE_EEPROM_PARAMETERS])) + { + + std::string expectedCMD = "S0:FORMAT="; + saveIfExpectedCmdIs(msg, expectedCMD, device_param.s0_format); + expectedCMD = "S1:SERIAL_SPEED="; + saveIfExpectedCmdIs(msg, expectedCMD, device_param.s1_serial_speed); + expectedCMD ="S2:AIR_SPEED="; + saveIfExpectedCmdIs(msg, expectedCMD, device_param.s2_air_speed); + expectedCMD ="S3:NETID="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s3_net_id); + expectedCMD ="S4:TXPOWER="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s4_power_level); + expectedCMD ="S5:ECC="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s5_error_correction); + expectedCMD ="S6:MAVLINK="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s6_mavlink); + expectedCMD ="S7:OPPRESEND="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s7_oppresend); + expectedCMD ="S8:MIN_FREQ="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s8_min_frequency); + expectedCMD ="S9:MAX_FREQ="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s9_max_frequency); + expectedCMD ="S10:NUM_CHANNELS="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s10_mum_channels); + expectedCMD ="S11:DUTY_CYCLE="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s11_duty_cycle); + expectedCMD ="S12:LBT_RSSI="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s12_lbt_rssi); + expectedCMD ="S13:MANCHESTER="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s13_manchester); + expectedCMD ="S14:RTSCTS="; + saveIfExpectedCmdIs(msg, expectedCMD,device_param.s14_rtscts); + + } + + if(String::startsWith(last_command,AT_RFDPTP[TDM_TIMING])) + { + if(String::startsWith(msg,"tx_window_width:")) + { + device_reports.tdm_timing_tx_window = msg; + task->trace("%s",device_reports.tdm_timing_tx_window.c_str()); + } + if(String::startsWith(msg,"silence_period:")) + { + device_reports.tdm_timing_silence_period = msg; + task->trace("%s",device_reports.tdm_timing_silence_period.c_str()); + } + if(String::startsWith(msg,"max_data_packet_length:")) + { + std::string expectedCMD= "max_data_packet_length:"; + saveIfExpectedCmdIs(msg, expectedCMD,device_reports.tdm_timing_max_data_packet); + task->trace("max_data_packet_length: %s",device_reports.tdm_timing_max_data_packet.c_str()); + } + + } + + + } + //End AT commands + if(String::startsWith(msg,"$")) + { + std::string tmp = msg; + tmp.erase( (msg.size()- 1), 1); + tmp.erase(0,1); + device_reports.data_report = tmp; + device_reports.report_status[DATA_REPORT] = true; + //task->spew("data_report:%s",device_reports.data_report.c_str()); + } + //Radio Report + if(String::startsWith(msg,"L/R RSSI:")) + { + device_reports.rssi = msg; + device_reports.report_status[RSSI_REPORT] = true; + task->spew("%s",device_reports.rssi.c_str()); + } + + if(String::startsWith(msg,"TDM:")) + { + device_reports.tdm_report = msg; + device_reports.report_status[TDM_REPORT] = true; + task->spew("%s",device_reports.tdm_report.c_str()); + } + } + catch (std::exception& e) + { + task->err("%s", e.what()); + } + + } + + protected: + + DeviceParam device_param; + bool cmd_mode; + std::string last_command; + }; + } +} + + +#endif + +// default config +// S0:FORMAT=34\r +// S1:SERIAL_SPEED=57\r +// S2:AIR_SPEED=64\r +// S3:NETID=25\r +// S4:TXPOWER=20\r +// S5:ECC=0\r +// S6:MAVLINK=1\r +// S7:OPPRESEND=0\r +// S8:MIN_FREQ=868000\r +// S9:MAX_FREQ=870000\r +// S10:NUM_CHANNELS=10\r +// S11:DUTY_CYCLE=60\r +// S12:LBT_RSSI=0\r +// S13:RTSCTS=0\r +// S14:MAX_WINDOW=20\r +// S15:ENCRYPTION_LEVEL=0\r +// S16:GPI1_1R/CIN=0\r +// S17:GPO1_1R/COUT=0\r +// S18:ANT_MODE=0\r +// S19:PKT_DROP_RSSI=0\r +// R0:TARGET_RSSI=255\r +// R1:HYSTERESIS_RSSI=50\r diff --git a/src/Transports/Radio/Task.cmake b/src/Transports/Radio/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Transports/Radio/Task.cpp b/src/Transports/Radio/Task.cpp new file mode 100644 index 0000000000..b44c6c077e --- /dev/null +++ b/src/Transports/Radio/Task.cpp @@ -0,0 +1,766 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: João Teixeira * +//*************************************************************************** + +// DUNE headers. +#include +#include + +// Local headers +#include "RadioDriver.hpp" +#include "Telemetry.hpp" +#include "3DR.hpp" +#include "RadioRFDXXXxPtP.hpp" + +namespace Transports +{ + namespace Radio + { + using DUNE_NAMESPACES; + + //! Task arguments. + + //! States of the internal SM. + + //! Finite state machine states. + enum StateMachineStates + { + //! Waiting for activation. + SM_IDLE, + //! Start activation sequence. + SM_ACT_BEGIN, + //! Turn modem power on. + SM_ACT_POWER_ON, + //! Wait for power to be turned on. + SM_ACT_POWER_WAIT, + //! Wait for serial port device to become available. + SM_ACT_MODEM_WAIT, + //! Connect to device + SM_ACT_CONNECT, + //! Start modem configuration session. + SM_ACT_CONFIG, + //! Activation sequence is complete. + SM_ACT_DONE, + //! Start deactivation sequence. + SM_DEACT_BEGIN, + //! Close connection port + SM_DEACT_DISCONNECT, + //! Switch power off. + SM_DEACT_POWER_OFF, + //! Wait for power to be turned off. + SM_DEACT_POWER_WAIT, + //! Deactivation sequence is complete. + SM_DEACT_DONE + }; + + + struct Arguments + { + //! Radio driver data + RadioConfParam radioParams; + //! Power channel name. + std::string power_channel; + //! Name of the section with vehicle addresses. + std::string addr_section; + //! Name of the Communication mode + std::string coms_mode; + //! Enable Telemetry report + bool report_enable; + //! Enable Telemetry report + bool high_speed_report; + //! IMU entity label. + std::string elabel_voltage; + //! Radio reports periodicity. + double radio_period; + + }; + + struct Task: public DUNE::Tasks::Task + { + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + //! Task arguments. + Arguments m_args; + //! Current state machine state. + StateMachineStates m_sm_state; + + RadioDriver* m_radio; + //! Map of radio modems by name. + MapName m_radio_names; + //! Map of radio modems by address. + MapAddr m_radio_addrs; + //! True if modem is powered on. + bool m_powered; + //! Reporter API. + Supervisors::Reporter::Client* m_reporter; + //! Telemetry communication manager + Telemetry* m_telemetry; + //! timrer to config modem + Time::Counter m_conn_watchdog; + //! Data collected by radio + std::string m_rxData; + //! IMU entity id. + unsigned m_voltage_eid; + //! Driver configuration + IMC::CommSystemsQuery* m_comm_systems_query; + //! System ID + uint16_t m_systemID; + //! Higth speed radio report + Time::Counter m_fast_treport_counter; + + Task(const std::string& name, Tasks::Context& ctx): + DUNE::Tasks::Task(name, ctx), + m_sm_state(SM_IDLE), + m_radio(NULL), + m_powered(false), + m_reporter(NULL), + m_telemetry(NULL) + { + + // Define configuration parameters. + paramActive(Tasks::Parameter::SCOPE_GLOBAL, + Tasks::Parameter::VISIBILITY_USER); + + param("Serial Port - Device", m_args.radioParams.uart_dev) + .defaultValue("") + .description("Serial port device used to communicate with the sensor"); + + param("Serial Port - Baud Rate", m_args.radioParams.uart_baud) + .defaultValue("57600") + .description("Serial port baud rate"); + + param("Power Channel", m_args.power_channel) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .scope(Tasks::Parameter::SCOPE_GLOBAL) + .defaultValue("") + .description("Power channel name"); + + param("Address Section", m_args.addr_section) + .defaultValue("Radio Addresses") + .description("Name of the configuration section with vehicle addresses"); + + param("Radio Model", m_args.radioParams.radio_model) + .defaultValue("3DR") + .values("3DR, RDFXXXxPtP") + .visibility(Tasks::Parameter::VISIBILITY_USER) + .description("Radio Model"); + + param("Mode of communication", m_args.coms_mode) + .defaultValue("Client") + .visibility(Tasks::Parameter::VISIBILITY_USER) + .values("Server, Client") + .description("Coms mode"); + + param("Vehicle to bind", m_args.radioParams.vehicle_name) + .defaultValue("") + .visibility(Tasks::Parameter::VISIBILITY_USER) + .description("Vehicle to bind"); + + param("Radio power level", m_args.radioParams.power_level) + .defaultValue("8") + .values("1, 2, 4, 8, 11, 14, 17, 20, 30") + .description("Radio power level (dBm)"); + + param("Number of channels", m_args.radioParams.mum_channels) + .defaultValue("10") + .description("number of frequency hopping channels"); + + param("Duty cycle", m_args.radioParams.duty_cycle) + .defaultValue("10") + .description("Duty cycle - the percentage of time to allow transmit"); + + param("Air speed", m_args.radioParams.air_speed) + .defaultValue("64") + .values("2, 4, 8, 16, 19, 24, 32, 48, 64, 96, 128, 192, 250") + .description("Air speed (Air data rate)"); + + param("Radio Error correction", m_args.radioParams.error_correction) + .defaultValue("true") + .description("Radio Error correction - this reduces bandwidth"); + + param("Mavlink framing", m_args.radioParams.mavlink_framing) + .defaultValue("true") + .description("Mavlink framing"); + + + param("Radio rssi report", m_args.radioParams.rssi_report) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("true") + .description("Radio rssi report"); + + param("Radio TDM report", m_args.radioParams.tdm_report) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("true") + .description("Radio TDM sync time report"); + + param("Enable telemetry report", m_args.report_enable) + .defaultValue("false") + .description("Enable system state telemetry reporting. When enabled, systems" + " shall acknowledge reception of requests to broadcast Reports" + " messages containing the overall state of the system." + " When disabled, those requests shall be ignored"); + + param("Enable UAV high speed report", m_args.high_speed_report) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("false") + .description("Enable system state telemetry reporting."); + + param(DTR_RT("UAV high speed Reports Periodicity"), m_args.radio_period) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .units(Units::Second) + .defaultValue("0.3") + .minimumValue("0.3") + .maximumValue("600") + .description("Reports periodicity"); + + param("Entity Label - Voltage", m_args.elabel_voltage) + .defaultValue("Autopilot") + .description("Entity label for battery Voltage"); + + + m_conn_watchdog.setTop(30); + + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + bind(this); + } + + void + consume(const IMC::Voltage* msg) + { + if ( (m_telemetry != NULL) && (msg->getSourceEntity() == m_voltage_eid)) + { + m_telemetry->consume(msg); + } + } + + + void + consume(const IMC::TelemetryMsg* msg) + { + if ( (m_telemetry != NULL)) + { + m_telemetry->consume(msg); + } + } + + void + consume(const IMC::PowerChannelState* msg) + { + if (msg->name != m_args.power_channel) + return; + + m_powered = (msg->state == IMC::PowerChannelState::PCS_ON); + } + + void + consume(const IMC::ReportControl* msg) + { + if (m_reporter != NULL) + m_reporter->consume(msg); + } + + void + consume(const IMC::EstimatedState* msg) + { + if (m_telemetry != NULL) + m_telemetry->consume(msg); + } + + void + consume(const IMC::PlanControlState* msg) + { + if (m_telemetry != NULL) + m_telemetry->consume(msg); + } + + void + consume(const IMC::FuelLevel* msg) + { + if (m_telemetry != NULL) + m_telemetry->consume(msg); + } + + void + consume(const IMC::VehicleState* msg) + { + if (m_telemetry != NULL) + m_telemetry->consume(msg); + } + + void + consume(const IMC::VtolState* msg) + { + if (m_telemetry != NULL) + m_telemetry->consume(msg); + } + + //! Consume air Speed messages. + //! @param[in] msg IndicatedSpeed message. + void + consume(const IMC::IndicatedSpeed* msg) + { + if (m_telemetry != NULL) + m_telemetry->consume(msg); + } + void + consume(const IMC::CommSystemsQuery *msg) + { + if (msg->getDestination() != getSystemId()) + return; + if(msg->type != IMC::CommSystemsQuery::CIQ_QUERY) + return; + if(msg->comm_interface != IMC::CommSystemsQuery::CIQ_RADIO) + return; + + std::string list; + for (unsigned i = 0; i < m_radio_names.size(); ++i) + { + list += m_radio_addrs[i]; + list += ";" ; + } + if( m_sm_state != SM_ACT_DONE) + m_comm_systems_query->model = IMC::CommSystemsQuery::CIQ_UNKNOWN; + + m_comm_systems_query->setDestination(msg->getSource()); + m_comm_systems_query->setDestinationEntity(msg->getSourceEntity()); + m_comm_systems_query->list = list; + dispatch(m_comm_systems_query); + } + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + if (m_args.power_channel.empty()) + m_powered = true; + + } + + //! Reserve entity identifiers. + void + onEntityReservation(void) + { + } + + //! Resolve entity names. + void + onEntityResolution(void) + { + try + { + m_voltage_eid = resolveEntity(m_args.elabel_voltage); + } + catch (...) + { + m_voltage_eid = std::numeric_limits::max(); + } + } + //! Open TCP socket. + //! @return true if socket was opened, false otherwise. + + void + onRequestActivation(void) + { + + int m_addr = 0; + m_systemID =0; + if(m_args.coms_mode.compare("Client")==0) + { + // Process modem addresses. + std::string agent = getSystemName(); + + m_ctx.config.get(m_args.addr_section, agent, "1024", m_addr); + if (m_addr < 1 || m_addr > 256) + { + throw RestartNeeded(String::str(DTR("modem address for agent '%s' is invalid"), agent.c_str()), 5.0, true); + } + m_ctx.config.get(m_args.addr_section, agent, "1024", m_args.radioParams.net_id); + debug("MY_NET_ID IS: %s", m_args.radioParams.net_id.c_str()); + castLexical(m_args.radioParams.net_id, m_systemID); + } + else if(m_args.coms_mode.compare("Server")==0) + { + if(m_args.radioParams.vehicle_name.empty()) + { + throw RestartNeeded(String::str(DTR("Vehicle to bind is not define")), 5.0, true); + } + + m_ctx.config.get(m_args.addr_section, m_args.radioParams.vehicle_name, "1024", m_addr); + if (m_addr < 1 || m_addr > 256) + { + throw RestartNeeded(String::str(DTR("modem address for agent '%s' is invalid"), m_args.radioParams.vehicle_name.c_str()), 5.0, true); + } + m_ctx.config.get(m_args.addr_section, m_args.radioParams.vehicle_name, "1024", m_args.radioParams.net_id); + debug("MY_NET_ID for vehicle %s is : %s", m_args.radioParams.vehicle_name.c_str(), m_args.radioParams.net_id.c_str() ); + } + else + { + throw RestartNeeded(String::str(DTR("Invalid communication mode")), 5.0, true); + } + + if (m_args.radioParams.radio_model.compare("3DR") == 0) + { + m_args.radioParams.max_frequency= "415000"; + m_args.radioParams.min_frequency= "414000"; + m_radio = new Radio3dr(m_args.radioParams, this); + m_comm_systems_query->model = IMC::CommSystemsQuery::CIQ_M3DR; + } + else if (m_args.radioParams.radio_model.compare("RDFXXXxPtP") == 0) + { + m_args.radioParams.max_frequency= "870000"; + m_args.radioParams.min_frequency= "868000"; + m_radio = new RadioRFDXXXxPtP(m_args.radioParams, this); + m_comm_systems_query->model = IMC::CommSystemsQuery::CIQ_RDFXXXXPTP; + } + else + { + throw RestartNeeded(String::str(DTR("Invalid radio model")), 5.0, true); + } + + m_sm_state = SM_ACT_BEGIN; + hardwareUpdateStateMachine(); + } + + void + onRequestDeactivation(void) + { + m_sm_state = SM_DEACT_BEGIN; + hardwareUpdateStateMachine(); + } + + //! Acquire resources. + void + onResourceAcquisition(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + m_reporter = new Supervisors::Reporter::Client(this, Supervisors::Reporter::IS_RADIO, + 0.1, false); + m_comm_systems_query = new IMC::CommSystemsQuery(); + m_comm_systems_query->type= IMC::CommSystemsQuery::CIQ_REPLY; + m_comm_systems_query->comm_interface = IMC::CommSystemsQuery::CIQ_RADIO; + m_comm_systems_query->model = IMC::CommSystemsQuery::CIQ_UNKNOWN; + } + + void + controlPower(IMC::PowerChannelControl::OperationEnum op) + { + if (m_args.power_channel.empty()) + return; + + IMC::PowerChannelControl pcc; + pcc.op = op; + pcc.name = m_args.power_channel; + dispatch(pcc); + } + + //! Turn power channel on. + void + turnPowerOn(void) + { + debug("switching power on"); + controlPower(IMC::PowerChannelControl::PCC_OP_TURN_ON); + } + + //! Turn power channel off. + void + turnPowerOff(void) + { + debug("switching power off"); + controlPower(IMC::PowerChannelControl::PCC_OP_TURN_OFF); + } + + //! Test if power channel is on. + //! @return true if power channel is on, false otherwise. + bool + isPowered(void) + { + return m_powered; + } + + void + failActivation(const std::string& message) + { + + Memory::clear(m_radio); + Memory::clear(m_telemetry); + activationFailed(message); + if (!m_args.power_channel.empty()) + { + turnPowerOff(); + } + m_sm_state = SM_IDLE; + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + + void + hardwareUpdateStateMachine(void) + { + switch (m_sm_state) + { + case SM_IDLE: + break; + + case SM_ACT_BEGIN: + debug("starting activation sequence"); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVATING); + if (!m_args.power_channel.empty()) + { + m_sm_state = SM_ACT_POWER_ON; + } + else + { + m_sm_state = SM_ACT_MODEM_WAIT; + m_conn_watchdog.reset(); + } + /* Falls through */ + + case SM_ACT_POWER_ON: + turnPowerOn(); + m_sm_state = SM_ACT_POWER_WAIT; + /* Falls through */ + + case SM_ACT_POWER_WAIT: + if (isPowered()) + { + debug("power is on"); + debug("waiting for modem"); + m_sm_state = SM_ACT_MODEM_WAIT; + m_conn_watchdog.reset(); + } + else + { + break; + } + /* Falls through */ + + case SM_ACT_MODEM_WAIT: + + if (Path(m_args.radioParams.uart_dev).isDevice() || Path(m_args.radioParams.uart_dev).isLink()) + { + debug("Device detected: %s", m_args.radioParams.uart_dev.c_str()); + m_sm_state = SM_ACT_CONNECT; + } + else + { + debug("No radio detected in %s, retrying...", m_args.radioParams.uart_dev.c_str()); + if(m_conn_watchdog.overflow()) + { + std::string error = "No Radio device on port: " + m_args.radioParams.uart_dev; + err(DTR("No Radio device on port: %s"), m_args.radioParams.uart_dev.c_str()); + failActivation(error); + } + break; + } + + case SM_ACT_CONNECT: + m_radio->connectToDevice(); + spew("done: connectToDevice"); + activate(); + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_ACTIVE); + m_sm_state = SM_ACT_CONFIG; + break; + + case SM_ACT_CONFIG: + + if(!m_radio->configDevice()) + { + err(DTR("Radio configuration failed. Wrong parameter or device on port %s is not a radio ") + ,m_args.radioParams.uart_dev.c_str()); + requestDeactivation(); + break; + } + debug("configuration completed"); + m_radio->clearNewRxData(); + m_telemetry = new Telemetry(this, (uint8_t) m_systemID, m_radio_names, m_radio_addrs, m_radio->maxDataPacket()); + m_fast_treport_counter.setTop(m_args.radio_period); + m_sm_state = SM_ACT_DONE; + /* Falls through */ + + case SM_ACT_DONE: + break; + + case SM_DEACT_BEGIN: + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_DEACTIVATING); + m_sm_state = SM_DEACT_DISCONNECT; + /* Falls through */ + + case SM_DEACT_DISCONNECT: + if (m_args.power_channel.empty()) + m_sm_state = SM_DEACT_DONE; + else + m_sm_state = SM_DEACT_POWER_OFF; + Memory::clear(m_radio); + Memory::clear(m_telemetry); + break; + + case SM_DEACT_POWER_OFF: + turnPowerOff(); + m_sm_state = SM_DEACT_POWER_WAIT; + /* Falls through */ + + case SM_DEACT_POWER_WAIT: + if (!isPowered()) + { + debug("device is no longer powered"); + m_sm_state = SM_DEACT_DONE; + } + else + { + break; + } + /* Falls through */ + + case SM_DEACT_DONE: + + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + deactivate(); + m_sm_state = SM_IDLE; + debug("deactivation complete"); + break; + } + } + //! Initialize resources. + void + onResourceInitialization(void) + { + std::vector addrs = m_ctx.config.options(m_args.addr_section); + for (unsigned i = 0; i < addrs.size(); ++i) + { + unsigned addr = 0; + m_ctx.config.get(m_args.addr_section, addrs[i], "0", addr); + m_radio_names[addrs[i]] = addr; + m_radio_addrs[addr] = addrs[i]; + } + if(m_args.coms_mode.compare("Server")==0) + { + IMC::AnnounceService announce; + announce.service = std::string("imc+any://radio/telemetry/") + + URL::encode(getEntityLabel()); + dispatch(announce); + } + + } + + //! Release resources. + void + onResourceRelease(void) + { + Memory::clear(m_reporter); + Memory::clear(m_telemetry); + } + + void + radioReport(void) + { + //report creation + if (m_args.report_enable) + { + if (m_reporter != NULL && m_reporter->trigger() && m_telemetry!=NULL) + { + if(m_telemetry->isIdle()) + { + m_telemetry->createReport(); + } + } + } + } + void + highSpeedReport(void) + { + + //report creation + if (m_args.high_speed_report) + { + if (m_reporter != NULL && m_telemetry!=NULL && m_fast_treport_counter.overflow()) + { + m_fast_treport_counter.setTop(m_args.radio_period); + if(m_telemetry->isIdle()) + { + m_telemetry->createReport(); + } + } + } + + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + if(!isActive()) + { + waitForMessages(1.0); + } + + if( isActive() && m_sm_state == SM_ACT_DONE) + { + consumeMessages(); + //uart/ip + m_radio->processInput(); + //RXdata + if(m_radio->newRxData(m_rxData)) + { + m_telemetry->recivedDataToDecode(m_rxData); + } + m_telemetry->recivedDataTimeOut(); + // RxData + m_telemetry->anyDataToProcess(); + //report + radioReport(); + highSpeedReport(); + //Txdata + std::string txData; + if(m_telemetry->anyDatatosend(txData)) + { + m_radio->sendData(txData); + m_telemetry->updateTxState(); + } + } + hardwareUpdateStateMachine(); + } + Memory::clear(m_radio); + Memory::clear(m_telemetry); + } + }; + } +} + +DUNE_TASK diff --git a/src/Transports/Radio/Telemetry.hpp b/src/Transports/Radio/Telemetry.hpp new file mode 100644 index 0000000000..e1062d5d77 --- /dev/null +++ b/src/Transports/Radio/Telemetry.hpp @@ -0,0 +1,757 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: João Teixeira * +//*************************************************************************** + +#ifndef DUNE_TRANSPORTS_RADIO_TELEMETRY_HPP_INCLUDED_ +#define DUNE_TRANSPORTS_RADIO_TELEMETRY_HPP_INCLUDED_ + +// ISO C++ 98 headers. +#include +#include +#include + +// DUNE headers. +#include +#include + +// Local headers +#include "TelemetryTypes.hpp" + +namespace Transports +{ + namespace Radio + { + using DUNE_NAMESPACES; + + //! This class is a communication manager for telemetry + //! + //! @author João Teixeira + + class Telemetry + { + public: + //! Constructor. + Telemetry(Tasks::Task* task, uint8_t system, MapName radio_names, MapAddr radio_addrs, int max_packet_size): + m_task(task), + m_tx_telemetry_State(IDLE), + m_rx_telemetry_State(IDLE), + local_tx_sync(0), + local_rx_sync(0), + systemID(system) + { + m_tx_mesg.state = MSG_TRANSMIT; + m_radio_names= radio_names; + m_radio_addrs = radio_addrs; + m_max_packet_size = (int) max_packet_size * MAX_MESSAGE_PERIOD; + m_task->debug("Telemetry max_packet_size %d", m_max_packet_size); + } + + //! Consume Estimated State messages. + //! @param[in] msg EstimatedState message. + void + consume(const IMC::EstimatedState* msg) + { + if (msg->getSource() != m_task->getSystemId()) + return; + + m_repotdata.estate = *msg; + } + + //! Consume VehicleState messages. + //! @param[in] msg VehicleState message. + void + consume(const IMC::VehicleState* msg) + { + if (msg->getSource() != m_task->getSystemId()) + return; + m_repotdata.vehicle_state = *msg; + } + + //! Consume Plan Control State messages. + //! @param[in] msg PlanControlState message. + void + consume(const IMC::PlanControlState* msg) + { + if (msg->getSource() != m_task->getSystemId()) + return; + m_repotdata.plan_progress = *msg; + } + + //! Consume Fuel Level messages. + //! @param[in] msg FuelLevel message. + void + consume(const IMC::FuelLevel* msg) + { + if (msg->getSource() != m_task->getSystemId()) + return; + m_repotdata.fuel_level= *msg; + } + + void + consume(const IMC::Voltage* msg) + { + if (msg->getSource() != m_task->getSystemId()) + return; + m_repotdata.batt_voltage= *msg; + } + + //! Consume air Speed messages. + //! @param[in] msg IndicatedSpeed message. + void + consume(const IMC::IndicatedSpeed* msg) + { + if (msg->getSource() != m_task->getSystemId()) + return; + m_repotdata.air_speed= *msg; + } + + void + consume(const IMC::VtolState* msg) + { + if (msg->getSource() != m_task->getSystemId()) + return; + m_repotdata.vtolstate= *msg; + } + + + //! Consume TelemetryMsg messages. + //! @param[in] msg TelemetryMsg message. + void + consume(const IMC::TelemetryMsg* msg) + { + m_task->debug("consume Telemetry tx"); + imc_TelemetryMsg_queue.push( * msg); + imc_time.push(Time::Clock::get()); + } + bool + imc_TelemetryMsg_tx() + { + if(!imc_TelemetryMsg_queue.empty()) + { + IMC::TelemetryMsg msg; + msg = imc_TelemetryMsg_queue.front(); + imc_TelemetryMsg_queue.pop(); + double valid = imc_time.front()+ msg.ttl; + + imc_time.pop(); + if( (Time::Clock::get()) > valid ) + { + m_task->inf("IMC Radio msg %d discarded due to ttl timeout", msg.req_id); + return false; + } + + + if (msg.getDestination() != m_task->getSystemId()) + return false; + if(msg.type != IMC::TelemetryMsg::TM_TX) + return false; + unsigned dst, src; + if( !lookupSystemAddress(msg.destination, dst)) + { + m_task->err("Invalid Tx destination %s",msg.destination.c_str()); + return false; + } + if( !lookupSystemAddress(m_task->getSystemName(),src)) + { + m_task->err("This src system is not in the Radio system list"); + return false; + } + uint16_t msgtype = (msg.data[1] << 8) + msg.data[0]; + + m_task->debug("IMC type to tx %d , size %d ",msgtype, (int) msg.data.size()); + XxMesg TxFrame; + if(TxFrame.imc_to_tx_msg(&msg,src, dst)) + { + updateTxSync(); + TxFrame.encodeHeader(local_tx_sync, m_max_packet_size, msg.ttl ); + m_tx_msg_queue.push(TxFrame); + } + else + { + m_task->err("Invalid Tx code type"); + return false; + } + m_task->dispatch(TxFrame.telemetry_imc_status); + return true; + } + return false; + } + + //! update the Tx synchronization number + void + updateTxSync(void) + { + if(local_tx_sync == 255) + local_tx_sync = 0; + else + local_tx_sync++; + } + + //! update the local Rx synchronization number to detect data loss + void + updateRxSync(int value = -1) + { + if(value < 0) + { + + if(local_rx_sync == 255) + local_rx_sync = 0; + else + local_rx_sync++; + } + else + { + local_rx_sync= (uint8_t) value; + } + } + + //! verifies if TX channel is busy + bool + isIdle(void) + { + if(m_tx_telemetry_State == IDLE) + return true; + return false; + } + + void + createReport(void) + { + m_task->trace("create Report"); + XxMesg ReportFrame; + double lat = 0; + double lon = 0; + Coordinates::toWGS84(m_repotdata.estate, lat, lon); + + Report dat; + dat.lat = lat; + dat.lon = lon; + dat.depth = abs(Math::round(m_repotdata.estate.depth)); + dat.roll = Math::round((m_repotdata.estate.phi * 100.0)); + dat.pitch = Math::round((m_repotdata.estate.theta * 100.0)); + dat.yaw = Math::round((m_repotdata.estate.psi * 100.0)); + dat.alt = Math::round((m_repotdata.estate.alt * 10.0)); + dat.height = Math::round((m_repotdata.estate.height * 10.0)); + dat.fuel_level = Math::round(m_repotdata.fuel_level.value); + dat.fuel_conf = Math::round(m_repotdata.fuel_level.confidence); + dat.progress = m_repotdata.plan_progress.plan_progress; + dat.air_speed = Math::round((m_repotdata.air_speed.value*100)); + dat.vehicle_state = m_repotdata.vehicle_state.op_mode; + dat.vehicle_state_ent = m_repotdata.vehicle_state.getSourceEntity(); + dat.vtolstate = m_repotdata.vtolstate.state; + dat.voltage= m_repotdata.batt_voltage.value*10; + + std::vector data(29,0); + std::memcpy(&data[0], &dat.lat, 4); + std::memcpy(&data[4], &dat.lon, 4); + std::memcpy(&data[8], &dat.depth, 1); + std::memcpy(&data[9], &dat.roll, 2 ); + std::memcpy(&data[11], &dat.pitch, 2 ); + std::memcpy(&data[13], &dat.yaw, 2 ); + std::memcpy(&data[15], &dat.alt, 2 ); + std::memcpy(&data[17], &dat.height, 2 ); + std::memcpy(&data[19], &dat.fuel_level, 1 ); + std::memcpy(&data[20], &dat.fuel_conf, 1 ); + std::memcpy(&data[21], &dat.progress, 1); + std::memcpy(&data[22], &dat.air_speed, 2); + std::memcpy(&data[24], &dat.vehicle_state, 1); + std::memcpy(&data[25], &dat.vehicle_state_ent, 1); + std::memcpy(&data[26], &dat.voltage, 2); + std::memcpy(&data[28], &dat.vtolstate, 1); + std::string str(data.begin(),data.end()); + + ReportFrame.setMsgData(str); + updateTxSync(); + ReportFrame.encodeHeader(CODE_REPORT,systemID, 0 , + local_tx_sync, false, m_max_packet_size, MAX_MESSAGE_PERIOD*4); + ReportFrame.state = MSG_QUEUE; + ReportFrame.telemetry_imc_status.type = IMC::TelemetryMsg::TM_TXSTATUS; + ReportFrame.telemetry_imc_status.code = CODE_REPORT ; + ReportFrame.telemetry_imc_status.req_id= local_tx_sync; + + m_tx_msg_queue.push(ReportFrame); + m_task->debug("Report to queue"); + + } + + bool + reportDecode(XxMesg & rxmsg) + { + + const char* data= rxmsg.msg.data(); + int size = rxmsg.msg.size(); + m_task->debug("RX: reportDecode : size %d", size); + if(size == 29) + { + RepotImcData report_imc; + Report dat; + std::memcpy(&dat.lat, data + 0, 4); + std::memcpy(&dat.lon, data + 4, 4); + std::memcpy(&dat.depth, data + 8, 1); + std::memcpy(&dat.roll, data + 9, 2 ); + std::memcpy(&dat.pitch, data + 11, 2 ); + std::memcpy(&dat.yaw, data + 13, 2 ); + std::memcpy(&dat.alt, data + 15, 2 ); + std::memcpy(&dat.height, data + 17, 2 ); + std::memcpy(&dat.fuel_level, data + 19, 1 ); + std::memcpy(&dat.fuel_conf, data + 20, 1 ); + std::memcpy(&dat.progress, data + 21, 1); + std::memcpy(&dat.air_speed, data + 22, 2); + std::memcpy(&dat.vehicle_state, data + 24, 1); + std::memcpy(&dat.vehicle_state_ent, data + 25, 1); + std::memcpy(&dat.voltage, data + 26, 2); + std::memcpy(&dat.vtolstate, data + 28, 2); + report_imc.estate.lat = (double) (dat.lat); + report_imc.estate.lon = (double) (dat.lon); + report_imc.estate.depth = dat.depth; + report_imc.estate.phi = ((double)dat.roll) /100.0; + report_imc.estate.theta = ((double)dat.pitch ) /100.0; + report_imc.estate.psi = ((double)dat.yaw) /100.0; + report_imc.estate.alt = ((double)dat.alt) /10; + report_imc.estate.height = ((double)dat.height) /10.0; + report_imc.fuel_level.value = (double)dat.fuel_level; + report_imc.fuel_level.confidence = (double)dat.fuel_conf; + report_imc.plan_progress.plan_progress = (double) (dat.progress); + report_imc.air_speed.value = ((double)(dat.air_speed)) /100.0; + report_imc.vehicle_state.op_mode = dat.vehicle_state; + report_imc.vehicle_state.setSourceEntity(dat.vehicle_state_ent); + report_imc.batt_voltage.value = ((double)dat.voltage)/10; + report_imc.vtolstate.state = dat.vtolstate; + + std::string src_system = safeLookup(rxmsg.src_id); + uint16_t imc_src = m_task->resolveSystemName(src_system); + + report_imc.estate.setSource(imc_src); + report_imc.plan_progress.setSource(imc_src); + report_imc.fuel_level.setSource(imc_src); + report_imc.air_speed.setSource(imc_src); + report_imc.vehicle_state.setSource(imc_src); + report_imc.batt_voltage.setSource(imc_src); + report_imc.vtolstate.setSource(imc_src); + m_task->dispatch(report_imc.estate); + m_task->dispatch(report_imc.plan_progress); + m_task->dispatch(report_imc.fuel_level); + m_task->dispatch(report_imc.air_speed); + m_task->dispatch(report_imc.vehicle_state); + m_task->dispatch(report_imc.batt_voltage); + m_task->dispatch(report_imc.vtolstate); + rxmsg.state = MSG_PROCESSED; + return true; + } + rxmsg.state = MSG_ERROR; + return false; + } + void + recivedDataTimeOut() + { + if (acquisition_Rx_Frame.state == MSG_IN_PARTS && acquisition_Rx_Frame.msg_timer.overflow()) + { + m_task->war("Time for message reception timeout"); + acquisition_Rx_Frame.clear(); + } + } + void + recivedDataToDecode(std::string& rxData) + { + updateRxSync(); + + XxMesg rx_test; + if (!rx_test.testDecodeHeader(rxData)) + { + m_task->err("RxData decoe error %s ", rx_test.error_msg.c_str()); + return; + } + m_task->trace("RX header ak:%d code:%d src:%d des:%d npart: %d sync:%d n_parts: %d, first_part: %d ", + (int)rx_test.acknowledge, (int) rx_test.code, rx_test.src_id, rx_test.des_id, + (int) rx_test.npart , rx_test.sync, (int) rx_test.n_parts, rx_test.start_part); + + if(!rx_test.npart) + { + // new msg clean garbage + acquisition_Rx_Frame.clear(); + } + + if(local_rx_sync != rx_test.sync && rx_test.code != CODE_AK) + { + m_task->trace("local_rx_sync % d rx_test.sync %d",local_rx_sync,rx_test.sync); + updateRxSync(rx_test.sync); + m_task->inf("previous message(s) lost or first sync"); + } + + if(rx_test.npart && rx_test.start_part) + { + // begin of a multiple part msg + acquisition_Rx_Frame.clear(); + m_task->debug("RX start multiple clear buffer"); + } + + if (rx_test.npart && !rx_test.start_part && !acquisition_Rx_Frame.start_part ) + { + m_task->inf("Rx Part of message ignored because start was not detected"); + return ; + } + + acquisition_Rx_Frame.decodeHeader(rxData); + + if(!acquisition_Rx_Frame.npart) + { + m_rx_msg_queue.push(acquisition_Rx_Frame); + acquisition_Rx_Frame.clear(); + } + else if (acquisition_Rx_Frame.start_part) + { + m_task->debug("RX multiple msg, state: %d end_sync; %d error_mmessage: %s", (int)acquisition_Rx_Frame.state, + (int) acquisition_Rx_Frame.n_parts_end_sync, acquisition_Rx_Frame.error_msg.c_str() ); + + if(acquisition_Rx_Frame.state == MSG_IN_PARTS_ERR) + { + //parts was lost + if (acquisition_Rx_Frame.sync == acquisition_Rx_Frame.n_parts_end_sync) + { + acquisition_Rx_Frame.clear(); + m_task->debug("RX multiple parts was lost clear buffer"); + return; + } + } + if(acquisition_Rx_Frame.state == MSG_IN_PARTS && + acquisition_Rx_Frame.sync == acquisition_Rx_Frame.n_parts_end_sync) + { + //last part and msg state is ok + std::string tmphex = String::toHex( acquisition_Rx_Frame.msg); + m_task->debug("new RX message queue: %s",tmphex.c_str()); + + m_rx_msg_queue.push(acquisition_Rx_Frame); + acquisition_Rx_Frame.clear(); + } + } + } + + bool + anyDataToProcess(void) + { + //verify queue to read + if(m_rx_msg_queue.empty()) + return false; + + m_task->trace("Rx queue size %d:", (int) m_rx_msg_queue.size() ); + m_rx_msg = m_rx_msg_queue.front(); + m_rx_msg_queue.pop(); + switch (m_rx_msg.code) + { + case CODE_REPORT: + if ( !reportDecode(m_rx_msg)) + m_task->err("rxData is invalid wrong size"); + break; + case CODE_IMC: + recvImcMessage(m_rx_msg); + break; + case CODE_AK: + // data transmition reciver side + m_task->debug("AK to message trasmition"); + if(m_rx_msg.sync== m_tx_mesg.sync) + { + m_tx_telemetry_State = IDLE; + m_tx_mesg.state = MSG_AK; + m_tx_mesg.telemetry_imc_status.status= IMC::TelemetryMsg::TM_DONE; + m_tx_mesg.telemetry_imc_status.acknowledge = IMC::TelemetryMsg::TM_AK; + m_task->dispatch(m_tx_mesg.telemetry_imc_status); + m_task->debug("AK dispatch"); + } + + break; + + default: return false; + } + //data reciver side + if(m_rx_msg.state == MSG_PROCESSED && m_rx_msg.acknowledge) + { + sendAKtoRXMsg(); + } + + return true; + } + + + bool + buzyStateMachine(std::string& txData) + { + bool new_part= false; + m_task->trace("m_tx_mesg state %d ", (int) m_tx_mesg.state); + if( (m_tx_mesg.state == WAITING_ACKN && m_tx_mesg.acknowledge ) || m_tx_mesg.state == MSG_IN_PARTS) + { + + if (m_tx_mesg.msg_timer.overflow()) + { + m_tx_mesg.state = MSG_NAK; + m_tx_telemetry_State = IDLE; + m_tx_mesg.telemetry_imc_status.status= IMC::TelemetryMsg::TM_EXPIRED; + m_task->dispatch(m_tx_mesg.telemetry_imc_status); + m_task->war("TX msg not AK"); + return false; + } + + } + + if(m_tx_mesg.state == MSG_IN_PARTS) + { + + if(m_tx_mesg.msg_multi_timer.overflow()) + { + + m_tx_mesg.msg_multi_timer.setTop(MAX_MESSAGE_PERIOD*4); + //send next part + updateTxSync(); + m_tx_mesg.encodeHeader(local_tx_sync, m_max_packet_size); + txData = m_tx_mesg.str_header + m_tx_mesg.msg; + new_part = true; + m_task->trace("TX Next msg part m_tx_mesg.n_parts_status %d m_tx_mesg.n_parts %d local_tx_sync %d", + (int) m_tx_mesg.n_parts_status, (int) m_tx_mesg.n_parts, (int) local_tx_sync); + } + + if(m_tx_mesg.n_parts_status == m_tx_mesg.n_parts) + { + if (m_tx_mesg.acknowledge) + { + m_tx_mesg.state = WAITING_ACKN; + } + else + { + m_tx_telemetry_State = IDLE; + m_tx_mesg.state = MSG_TRANSMIT; + } + } + if (new_part) + { + return true; + } + } + else if(m_tx_mesg.state == MSG_TRANSMIT) + { + m_tx_telemetry_State = IDLE; + } + return false; + } + void + sendAKtoRXMsg(void) + { + XxMesg tx_ak_mesg; + updateTxSync(); + tx_ak_mesg.encodeHeader(CODE_AK,systemID, m_rx_msg.src_id, m_rx_msg.sync, false, m_max_packet_size,-1); + tx_ak_mesg.state = MSG_QUEUE; + m_tx_msg_queue.push(tx_ak_mesg); + //for debug only + std::string tmp0 =String::toHex(tx_ak_mesg.str_header); + m_task->trace("AK header : %s", tmp0.c_str()); + } + + int + anyDatatosend(std::string& txData) + { + // check Tx current msg + if(m_tx_telemetry_State == BUZY) + { + m_task->trace("TX BUZY"); + if(buzyStateMachine(txData)) + { + return true; + } + else + { + return false; + } + + } + + if( m_tx_telemetry_State == IDLE) + { + //if last trasmition is done + if(m_tx_mesg.state == MSG_TRANSMIT || m_tx_mesg.state == MSG_NAK || + m_tx_mesg.state == MSG_AK || m_tx_mesg.state == MSG_ERROR) + { + //verify queue to send + if(m_tx_msg_queue.empty()) + { + imc_TelemetryMsg_tx(); + return false; + } + //something in the queue + m_task->trace("tx queue sixe %d:", (int) m_tx_msg_queue.size() ); + m_tx_mesg = m_tx_msg_queue.front(); + m_tx_msg_queue.pop(); + if (m_tx_mesg.error) + { + m_task->err("%s",m_tx_mesg.error_msg.c_str()); + return false; + } + + //for debug only + m_task->trace("TX header ak:%d code:%d src:%d des:%d npart: %d sync:%d n_parts: %d first_part: %d " , + (int)m_tx_mesg.acknowledge, (int) m_tx_mesg.code, + m_tx_mesg.src_id, m_tx_mesg.des_id, (int) m_tx_mesg.npart + , m_tx_mesg.sync, m_tx_mesg.n_parts, (int) m_tx_mesg.start_part); + std::string tmp = String::toHex(m_tx_mesg.str_header); + std::string tmp2 = String::toHex(m_tx_mesg.msg_compl); + std::string tmp3 = String::toHex(m_tx_mesg.msg); + m_task->trace("header : %s \n\r msg_compl: %s , msg: %s", + tmp.c_str(), tmp2.c_str(), tmp3.c_str()); + //end debug + + //telemetry msg to send + txData = m_tx_mesg.str_header + m_tx_mesg.msg; + m_tx_telemetry_State = BUZY; + //request to send + return true; + } + } + return false; + } + + + void + updateTxState() + { + if (m_tx_mesg.state == WAITING_ACKN) + return; + + if(m_tx_mesg.acknowledge && !m_tx_mesg.npart) + { + //if single msg and nead to waite for AK + m_tx_mesg.state = WAITING_ACKN; + } + else if (m_tx_mesg.state == MSG_QUEUE && !m_tx_mesg.npart) + { //if is single msg and sent for radio Driver + m_tx_mesg.state = MSG_TRANSMIT; + m_tx_mesg.telemetry_imc_status.status= IMC::TelemetryMsg::TM_DONE ; + m_task->dispatch(m_tx_mesg.telemetry_imc_status); + } + if(m_tx_mesg.npart) + { + m_tx_mesg.state = MSG_IN_PARTS; + m_tx_mesg.telemetry_imc_status.status= IMC::TelemetryMsg::TM_TRANSMIT ; + m_task->dispatch(m_tx_mesg.telemetry_imc_status); + } + } + + void + recvImcMessage(XxMesg& rxmsg) + { + m_task->debug("Parsing message received via Telemetry message."); + m_task->debug(" RX IMC SIZE %d", (int) m_rx_msg.msg.size()); + try + { + + uint16_t msg_type; + const char* data = rxmsg.msg.data(); + std::memcpy(&msg_type, data, sizeof(uint16_t)); + m_task->debug(" RX IMC TYPE %d", (int) msg_type); + Message *m = IMC::Factory::produce(msg_type); + if (m == NULL) + { + m_task->err("Invalid message type received: %d", msg_type); + rxmsg.state = MSG_ERROR; + m_tx_mesg.telemetry_imc_status.status= IMC::TelemetryMsg::TM_INV_SIZE; + return; + } + + std::string src_system = safeLookup(rxmsg.src_id); + uint16_t imc_src = m_task->resolveSystemName(src_system); + src_system = safeLookup(rxmsg.des_id); + uint16_t imc_dst = m_task->resolveSystemName(src_system); + m->setSource(imc_src); + m->setDestination(imc_dst); + m->setTimeStamp(rxmsg.timestamp); + m->deserializeFields((const unsigned char *) &data[2], rxmsg.msg.size()-2); + m_task->dispatch(m, DF_KEEP_TIME | DF_LOOP_BACK); + m_task->debug("Telemetry IMC message successfully parsed as '%s'.", m->getName()); + rxmsg.state = MSG_PROCESSED; + } + catch (std::exception& ex) { + m_task->err("Error parsing raw Rx message from Telemetry : %s.", ex.what()); + } + } + + unsigned + lookupSystemAddress(const std::string& name ,unsigned& adrr) + { + MapName::iterator itr = m_radio_names.find(name); + if (itr == m_radio_names.end()) + return false; + + adrr =itr->second; + return true; + } + + std::string + lookupSystemName(unsigned addr) + { + MapAddr::iterator itr = m_radio_addrs.find(addr); + if (itr == m_radio_addrs.end()) + throw std::runtime_error("unknown system address"); + return itr->second; + } + + std::string + safeLookup(unsigned addr) + { + try + { + return lookupSystemName(addr); + } + catch (...) + { } + + return "unknown"; + } + private: + + //! Pointer to task. + Tasks::Task* m_task; + RepotImcData m_repotdata; + XxMesg acquisition_Rx_Frame; + XxMesg m_tx_mesg; + XxMesg m_rx_msg; + std::queue m_tx_msg_queue; + std::queue m_rx_msg_queue; + std::queue imc_TelemetryMsg_queue; + std::queue imc_time; + TelemetryState m_tx_telemetry_State; + TelemetryState m_rx_telemetry_State; + uint8_t local_tx_sync; + uint8_t local_rx_sync; + uint8_t systemID; + int m_max_packet_size; + //! Map of radio modems by name. + MapName m_radio_names; + //! Map of radio modems by address. + MapAddr m_radio_addrs; + + }; + } +} + +#endif diff --git a/src/Transports/Radio/TelemetryTypes.hpp b/src/Transports/Radio/TelemetryTypes.hpp new file mode 100644 index 0000000000..7242b4089d --- /dev/null +++ b/src/Transports/Radio/TelemetryTypes.hpp @@ -0,0 +1,477 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: João Teixeira * +//*************************************************************************** + +#ifndef DUNE_TRANSPORTS_RADIO_TELEMETRYTYPES_HPP_INCLUDED_ +#define DUNE_TRANSPORTS_RADIO_TELEMETRYTYPES_HPP_INCLUDED_ + +#define MAX_MESSAGE_PERIOD 0.1 +#define HEADER_SIZE 5 +// ISO C++ 98 headers. +#include +#include +#include + +// DUNE headers. +#include +#include + +namespace Transports +{ + namespace Radio + { + using DUNE_NAMESPACES; + + //! This file defines all data structures for telemetry + //! + //! @author João Teixeira + enum TelemetryState + { + IDLE, + BUZY + }; + + enum MsgState + { + MSG_NONE, + MSG_QUEUE, + MSG_TO_DRIVER, + MSG_IN_PARTS, + MSG_IN_PARTS_ERR, + WAITING_ACKN, + MSG_TRANSMIT, + MSG_RECIVING, + MSG_RECIVED, + MSG_PROCESSED, + MSG_NAK, + MSG_ERROR, + MSG_AK + }; + + enum Codes + { + CODE_UNK = 0x00, + CODE_REPORT = 0x01, + CODE_IMC = 0x02, + CODE_AK = 0x03, + CODE_RAW = 0x04 + }; + + struct RepotImcData + { + + //! Estimated state. + IMC::EstimatedState estate; + //! Plan Progress + IMC::PlanControlState plan_progress; + //! Fuel level + IMC::FuelLevel fuel_level; + //! Air speed + IMC::IndicatedSpeed air_speed; + //! VehicleState op_mode + IMC::VehicleState vehicle_state; + //!t voltage (max 50v uma casa decimal ) + IMC::Voltage batt_voltage; + + IMC::VtolState vtolstate; + + }; + + struct Report + { + float lat; + float lon; + uint8_t depth; + int16_t roll; + int16_t pitch; + int16_t yaw; + int16_t alt; + int16_t height; + int8_t progress; + uint8_t fuel_level; + uint8_t fuel_conf; + int16_t air_speed; + uint8_t vehicle_state; + uint8_t vehicle_state_ent; + uint16_t voltage; + uint8_t vtolstate; + }; + + struct XxMesg + { + //Telemetry header + Codes code; + bool acknowledge; + bool npart; + bool start_part; + uint8_t sync; + uint8_t src_id; + uint8_t des_id; + uint8_t n_parts; + //Telemetry header vector + std::vector header; + std::string str_header; + //Telemetry payload + std::string msg; + std::string msg_compl; + //Radio state machine status + MsgState state; + bool first_call; + uint8_t past_sync; + uint8_t n_parts_status; + uint16_t n_parts_end_sync; + bool error; + double timestamp; + uint16_t max_data_payload; + std::string error_msg; + Time::Counter msg_timer; + Time::Counter msg_multi_timer; + //imc dispatch + IMC::TelemetryMsg telemetry_imc; + IMC::TelemetryMsg telemetry_imc_status; + //channel max data packaging + + XxMesg(void) + { + clear(); + } + + void + clear(void) + { + first_call = true; + state = MSG_NONE; + acknowledge = 0; + npart = false; + start_part = false; + n_parts = 1; + sync=0; + past_sync = 0; + error = false; + n_parts_status = 0; + n_parts_end_sync =0; + src_id = 0; + des_id = 0; + error_msg.clear(); + msg.clear(); + msg_compl.clear(); + str_header.clear(); + telemetry_imc.clear(); + max_data_payload=0; + telemetry_imc_status.clear(); + header.clear(); + } + + void + setMsgData(std::string msgData) + { + msg_compl = msgData; + } + + void + encodeHeader(Codes code_t, uint8_t src, uint8_t dst, uint8_t sync_n, bool ak, int max_data_packaging, double ttl) + { + code = code_t; + src_id = src; + des_id = dst; + acknowledge = ak; + encodeHeader(sync_n, max_data_packaging, ttl); + } + + void + encodeHeader(uint8_t sync_n, int max_data_packaging, double ttl = -1.0) + { + uint8_t tmp = 0; + sync = sync_n; + n_parts_status++; + // bit 8 7 6 code; bit 5 ak ; bit 4 multiple parts; bit 3 first part 2 1 bis not defined + tmp = (code << 5); + tmp += (((uint8_t)acknowledge)<< 4); + if(first_call==true) + { + header = std::vector(HEADER_SIZE,0); + max_data_payload = (max_data_packaging - (HEADER_SIZE*2+4)); + if ( msg_compl.size()*2 > max_data_payload) + { + tmp+= ((uint8_t) 1 << 3); // multiple parts + npart= true; + tmp+= ((uint8_t) 1 << 2); //1º part start_part + start_part = true; + + int temp = (msg_compl.size()*2) / max_data_payload; + int n_sub_rest = (msg_compl.size()*2) % max_data_payload; + msg_multi_timer.setTop(MAX_MESSAGE_PERIOD*4); + if(temp <= 254) + { + n_parts = temp; // Header limit + } + else + { + error =1; + error_msg = "txData is to big to encode"; + } + if (n_sub_rest != 0) + { + n_parts++; + } + } + else + { + n_parts=1; + } + } + else + { + tmp+= ((uint8_t) 1 << 3); + tmp = 0; + tmp = (code << 5); + tmp+= ((uint8_t) 1 << 3); + if (n_parts_status == n_parts) + { + tmp += (((uint8_t)acknowledge)<< 4); + } + } + first_call = false; + + if(ttl > 0.0) + msg_timer.setTop(ttl); + + std::memcpy(&header[0], &tmp, 1); + // sync number 1byte + std::memcpy(&header[1], &sync, 1); + // src 8 bit + std::memcpy(&header[2], &src_id, 1); + // des 8 bit + std::memcpy(&header[3], &des_id, 1); + // n_parts 8 bit + std::memcpy(&header[4], &n_parts, 1); + + if(!npart) + { + msg = msg_compl; + std::string header_str(header.begin(),header.end()); + str_header = header_str; + } + else + { + std::string header_str(header.begin(),header.end()); + str_header = header_str; + + if (n_parts_status == n_parts) + { + msg = msg_compl; + } + else + { + msg.clear(); + msg = msg_compl.substr( 0 ,(max_data_payload / 2 )); + msg_compl.erase( 0 , (max_data_payload / 2 )); + } + } + + } + + bool + testDecodeHeader(std::string rxData) + { + size_t size = rxData.size(); + if (size < HEADER_SIZE) + { + error_msg= "RxData invalid size to read header"; + return false; + } + const char* data =rxData.data(); + uint8_t tmp = data[0]; + //code + uint8_t code_t = ((tmp & 0xE0) >> 5); + code = (Codes) code_t; + //multiple parts + npart = (bool) ((tmp & 0xF) >> 3); + //ak + acknowledge = (bool)((tmp & 0x1F) >> 4); + // start_part + start_part = (bool) ((tmp & 0x7) >> 2); + // sync number 1byte + sync = data[1]; + // src 8 bit + src_id = data[2]; + // des 8 bit + des_id = data[3]; + // n_parts 8 bit + n_parts = data[4]; + return true; + } + + bool + decodeHeader(std::string rxData) + { + size_t size = rxData.size(); + if (size < HEADER_SIZE) + { + error_msg= "RxData invalid size to read header"; + return false; + } + const char* data =rxData.data(); + uint8_t tmp = data[0]; + //code + uint8_t code_t = ((tmp & 0xE0) >> 5); + code = (Codes) code_t; + //multiple parts + npart = (bool) ((tmp & 0xF) >> 3); + //ak + if (!start_part) + { + acknowledge = (bool)((tmp & 0x1F) >> 4); + // start_part + start_part = (bool) ((tmp & 0x7) >> 2); + msg_timer.setTop((MAX_MESSAGE_PERIOD*4) * data[4] + 1); + } + // sync number 1byte + sync = data[1]; + // src 8 bit + src_id = data[2]; + // des 8 bit + des_id = data[3]; + // n_parts 8 bit + n_parts = data[4]; + + if (npart) + { + n_parts_status++; + if(n_parts_status == 1) + { + // start of message reception im parts + n_parts_end_sync = sync + n_parts-1; + if (n_parts_end_sync > 255) + n_parts_end_sync= n_parts_end_sync - 255; + past_sync = sync; + state = MSG_IN_PARTS; + msg.clear(); + if (!start_part) + { + state = MSG_IN_PARTS_ERR; + error_msg= "start was not detected"; + return false; + } + } + else + { + past_sync = updateSync(past_sync); + if (sync != past_sync || state == MSG_IN_PARTS_ERR ) + { + state = MSG_IN_PARTS_ERR; + error_msg = "MSG_IN_PARTS_ERR"; + //error igonre next msg until the end + return true; + } + } + } + if(!npart) + { + n_parts_status = 1; + msg.clear(); + msg = rxData; + msg.erase(0,5); + } + else + { + //next part + rxData.erase(0,5); + msg += rxData; + } + + return true; + } + + uint8_t + updateSync( uint8_t syncn) + { + if(syncn == 255) + syncn = 0; + else + syncn++; + return syncn; + } + + void + rx_to_imc_msg(void) + { + //todo + } + + bool + imc_to_tx_msg(const IMC::TelemetryMsg* tmsg, uint8_t src , uint8_t dst) + { + telemetry_imc= *tmsg; + telemetry_imc_status.type = IMC::TelemetryMsg::TM_TXSTATUS; + telemetry_imc_status.req_id = telemetry_imc.req_id; + telemetry_imc_status.setSource(telemetry_imc.getDestination()); + telemetry_imc_status.setDestination(telemetry_imc.getSource()); + telemetry_imc_status.ttl = telemetry_imc.ttl; + telemetry_imc_status.code =telemetry_imc.code; + + switch(telemetry_imc.code) + { + case IMC::TelemetryMsg::TM_CODE_IMC: code = CODE_IMC; + break; + case IMC::TelemetryMsg::TM_CODE_RAW : code = CODE_RAW; + break; + default: code = CODE_UNK; + break; + } + + if(code == CODE_UNK) + { + telemetry_imc_status.status = IMC::TelemetryMsg::TM_FAILED; + return false; + } + + if(telemetry_imc.acknowledge) + acknowledge = true; + else + acknowledge = false; + des_id = dst; + src_id = src; + + std::string data_str(telemetry_imc.data.begin(),telemetry_imc.data.end()); + msg_compl = data_str; + + telemetry_imc_status.status = IMC::TelemetryMsg::TM_QUEUED; + return true; + } + + }; + + + typedef std::map MapName; + typedef std::map MapAddr; + + } +} + +#endif diff --git a/src/Transports/Replay/Task.cpp b/src/Transports/Replay/Task.cpp index a8d11e0f08..5c2793880d 100644 --- a/src/Transports/Replay/Task.cpp +++ b/src/Transports/Replay/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -47,6 +47,8 @@ namespace Transports std::string startup_file; std::vector msgs; std::vector ents; + double time_multiplier; + double initial_log_skip_seconds; }; static const int c_stats_period = 10; @@ -110,6 +112,15 @@ namespace Transports .defaultValue("") .description("Entities for which state should be reported"); + param("Time Multiplier", m_args.time_multiplier) + .defaultValue("1.0") + .description("Time multiplier for fast replay."); + + param("Seconds to skip", m_args.initial_log_skip_seconds) + .minimumValue("0") + .defaultValue("0") + .description("Number of seconds to skip in the beginning of the log"); + bind(this); } @@ -123,6 +134,12 @@ namespace Transports bind(this); reset(); + + if (m_args.time_multiplier != 1.0) + { + Time::Clock::setTimeMultiplier(m_args.time_multiplier); + war("Using time multiplier: x%.2f", Time::Clock::getTimeMultiplier()); + } } ~Task(void) @@ -195,6 +212,20 @@ namespace Transports return itr->second; } + void + updateEntityMap(IMC::Message* m) + { + IMC::EntityInfo* ei = static_cast(m); + Name2Eid::iterator itr = m_name2eid.find(ei->label); + + if (itr != m_name2eid.end()) + { + m_eid2eid[ei->id] = itr->second; + + trace("entity %s %d --> %d", ei->label.c_str(), (int)ei->id, (int)itr->second); + } + } + void startReplay(const std::string& file) { @@ -261,8 +292,21 @@ namespace Transports lc->op = IMC::LoggingControl::COP_REQUEST_START; dispatch(lc); // change log (if Logging task happens to be active) - m_ts_delta = lc->getTimeStamp() - m_ts_delta; - m_start_time = lc->getTimeStamp(); + // skip messages + if (m_args.initial_log_skip_seconds > 0) + { + m = getFirstMessageAfterSkip(m_args.initial_log_skip_seconds); + if (!m) + { + err("No messages for specified time range"); + return; + } + else + inf("Skipped messages up to %s", Time::Format::getTimeDate(m->getTimeStamp()).c_str()); + } + + m_ts_delta = lc->getTimeStamp() - m_ts_delta - m_args.initial_log_skip_seconds; + m_start_time = m->getTimeStamp(); m_next_stats = m_start_time + c_stats_period; delete m; @@ -271,6 +315,30 @@ namespace Transports war("%s '%s'", DTR("started replay of"), file.c_str()); } + IMC::Message* + getFirstMessageAfterSkip(double time_to_skip) + { + IMC::Message* m = 0; + double time_origin = m_ts_delta; + m = IMC::Packet::deserialize(*m_is); + while (m) + { + if (m->getTimeStamp() - time_origin >= time_to_skip) + return m; + // Do not miss information from EntityInfo + if (m->getId() == DUNE_IMC_ENTITYINFO) + { + updateEntityMap(m); + } + + delete m; + m = IMC::Packet::deserialize(*m_is); + if(getDebugLevel() >= DEBUG_LEVEL_SPEW) + m->toText(std::cout); + } + return NULL; + } + void stopReplay(void) { @@ -322,15 +390,63 @@ namespace Transports m_is = 0; } m_eid2eid.clear(); - m_name2eid.clear(); - m_eid2name.clear(); m_tstats.clear(); m_tgstats = Stats(); } + void + dispatchWithNewTime(IMC::Message* m) + { + double original_ts; + + if (m->getId() == DUNE_IMC_LBLCONFIG) + original_ts = m_start_time - m_ts_delta; + else + original_ts = m->getTimeStamp(); + + double new_ts = original_ts + m_ts_delta; + m->setTimeStamp(new_ts); + + // Wait till the time is right + double now = Clock::getSinceEpoch(); + double delta = new_ts - now; + + double delay; + + if (delta >= 1e-03) + { + // Delay::wait does not behave satisfactorily otherwise + // in some systems + Delay::wait(delta); + delay = Clock::getSinceEpoch() - new_ts; + } + else + { + delay = 0; + delta = 0; + } + + // Counter for delay before bus delivery + updateStats(m_tstats[m->getName()], delay); + updateStats(m_tgstats, delay); + + // Dispatch message + dispatch(m, DF_KEEP_TIME); + + if (now >= m_next_stats) + { + displayStats(); + m_next_stats += c_stats_period; + } + + spew("%s %0.4f %s", m->getName(), (new_ts - m_start_time), + m_eid2name[m->getSourceEntity()].c_str()); + } + void onMain(void) { + if (!m_args.startup_file.empty()) startReplay(m_args.startup_file); @@ -360,15 +476,7 @@ namespace Transports else if (m->getId() == DUNE_IMC_ENTITYINFO) { // Update entity id map - IMC::EntityInfo* ei = static_cast(m); - Name2Eid::iterator itr = m_name2eid.find(ei->label); - - if (itr != m_name2eid.end()) - { - m_eid2eid[ei->id] = itr->second; - - trace("entity %s %d --> %d", ei->label.c_str(), (int)ei->id, (int)itr->second); - } + updateEntityMap(m); } m->setSourceEntity(mapEntity(m->getSourceEntity())); @@ -376,50 +484,7 @@ namespace Transports if ((m->getId() == DUNE_IMC_ENTITYSTATE && m->getSourceEntity() != DUNE_IMC_CONST_UNK_EID) || m_replay.find(m->getName()) != m_replay.end()) { - double original_ts; - - if (m->getId() == DUNE_IMC_LBLCONFIG) - original_ts = m_start_time - m_ts_delta; - else - original_ts = m->getTimeStamp(); - - double new_ts = original_ts + m_ts_delta; - m->setTimeStamp(new_ts); - - // Wait till the time is right - double now = Clock::getSinceEpoch(); - double delta = new_ts - now; - - double delay; - - if (delta >= 1e-03) - { - // Delay::wait does not behave satisfactorily otherwise - // in some systems - Delay::wait(delta); - delay = Clock::getSinceEpoch() - new_ts; - } - else - { - delay = 0; - delta = 0; - } - - // Counter for delay before bus delivery - updateStats(m_tstats[m->getName()], delay); - updateStats(m_tgstats, delay); - - // Dispatch message - dispatch(m, DF_KEEP_TIME); - - if (now >= m_next_stats) - { - displayStats(); - m_next_stats += c_stats_period; - } - - spew("%s %0.4f %s", m->getName(), (new_ts - m_start_time), - m_eid2name[m->getSourceEntity()].c_str()); + dispatchWithNewTime(m); } } diff --git a/src/Transports/Seatrac/DataTypes.hpp b/src/Transports/Seatrac/DataTypes.hpp index 07f49b4d5a..d3881a7326 100644 --- a/src/Transports/Seatrac/DataTypes.hpp +++ b/src/Transports/Seatrac/DataTypes.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -35,6 +35,7 @@ #define MAX_MESSAGE_ERRORS 5 #define MAX_PACKET_LEN 31 #define MAX_MESSAGE_PERIOD 30 +#define MIN_SOUND_SPEED 1400 //! Defines the minimum message length without preamble nor postamble #define MIN_MESSAGE_LENGTH 6 diff --git a/src/Transports/Seatrac/DebugMsg.hpp b/src/Transports/Seatrac/DebugMsg.hpp index 09979fdcce..36d3977dbd 100644 --- a/src/Transports/Seatrac/DebugMsg.hpp +++ b/src/Transports/Seatrac/DebugMsg.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -124,7 +124,6 @@ namespace Transports printDebugFunction(unsigned message_type, DataSeatrac& data_Beacon, Tasks::Task* task = NULL) { - switch(message_type) { case CID_STATUS: @@ -139,25 +138,25 @@ namespace Transports { task->spew("data_Beacon.cid_status_msg.environment_supply %d", data_Beacon.cid_status_msg.environment_supply); - task->spew("data_Beacon.cid_status_msg.environment_temperature/10 %d", - data_Beacon.cid_status_msg.environment_temperature/10); - task->spew("data_Beacon.cid_status_msg.environment_pressure) %d", + task->spew("data_Beacon.cid_status_msg.environment_temperature/10 %f \u00B0C", + data_Beacon.cid_status_msg.environment_temperature / 10.0); + task->spew("data_Beacon.cid_status_msg.environment_pressure %d mbar", data_Beacon.cid_status_msg.environment_pressure); - task->spew("data_Beacon.cid_status_msg.EnvironmentDepth %d", - data_Beacon.cid_status_msg.EnvironmentDepth); - task->spew("data_Beacon.cid_status_msg.EnvironmentVos/10 %d", - data_Beacon.cid_status_msg.EnvironmentVos/10); + task->spew("data_Beacon.cid_status_msg.environment_depth/10 %f m", + data_Beacon.cid_status_msg.environment_depth / 10.0); + task->spew("data_Beacon.cid_status_msg.environmentVos/10 %f m/s", + data_Beacon.cid_status_msg.environment_vos / 10.0); } // Attitude. if (data_Beacon.cid_status_msg.outputflags_list[1]) { task->spew("data_Beacon.cid_status_msg.attitude_yaw/10 %d", - data_Beacon.cid_status_msg.attitude_yaw/10); + data_Beacon.cid_status_msg.attitude_yaw / 10); task->spew("data_Beacon.cid_status_msg.attitude_pitch/10 %d", - data_Beacon.cid_status_msg.attitude_pitch/10); + data_Beacon.cid_status_msg.attitude_pitch / 10); task->spew("data_Beacon.cid_status_msg.attitude_roll/10 %d", - data_Beacon.cid_status_msg.attitude_roll/10); + data_Beacon.cid_status_msg.attitude_roll / 10); } // Mag cal. @@ -251,8 +250,8 @@ namespace Transports case CID_PING_ERROR: //Message sent when a PING response error/timeout task->debug("MESSAGE CID_PING_ERROR"); - task->debug("data_Beacon.cid_ping_error_msg.status %d", - (int) data_Beacon.cid_ping_error_msg.status); + task->debug("data_Beacon.cid_ping_error_msg.status 0x%02X", + (unsigned) data_Beacon.cid_ping_error_msg.status); switch(data_Beacon.cid_ping_error_msg.status) { case CST_XCVR_RESP_TIMEOUT: @@ -273,16 +272,16 @@ namespace Transports case CID_PING_SEND: task->debug("MESSAGE CID_PING_SEND ACK"); - task->debug("data_Beacon.cid_ping_send_msg.status %d", - (int)data_Beacon.cid_ping_send_msg.status); + task->debug("data_Beacon.cid_ping_send_msg.status 0x%02X", + (unsigned)data_Beacon.cid_ping_send_msg.status); task->debug("data_Beacon.cid_ping_send_msg.beacon_id %d", (int)data_Beacon.cid_ping_send_msg.beacon_id); break; case CID_DAT_SEND: // Report of CID_DAT_SEND operation task->debug("MESSAGE CID_DAT_SEND ACK "); - task->debug("data_Beacon.cid_dat_send_msg.status %d", - (int)data_Beacon.cid_dat_send_msg.status); + task->debug("data_Beacon.cid_dat_send_msg.status 0x%02X", + (unsigned)data_Beacon.cid_dat_send_msg.status); task->debug("data_Beacon.cid_dat_send_msg.beacon_id %d", (int)data_Beacon.cid_dat_send_msg.beacon_id); break; @@ -296,14 +295,14 @@ namespace Transports task->debug("data_Beacon.cid_dat_receive_msg.packet_len %d", (int)data_Beacon.cid_dat_receive_msg.packet_len); for (int i = 0; i < (int)data_Beacon.cid_dat_receive_msg.packet_len; i++) - task->debug("data_Beacon.cid_dat_receive_msg.packet_data[%d] %d ", i, - (unsigned)data_Beacon.cid_dat_receive_msg.packet_data[i]); + task->debug("data_Beacon.cid_dat_receive_msg.packet_data[%02d] 0x%02X ", i, + (unsigned)(data_Beacon.cid_dat_receive_msg.packet_data[i] & 0xFF)); break; case CID_DAT_ERROR: task->debug("MESSAGE CID_DAT_ERROR "); - task->debug("data_Beacon.cid_dat_send_msg.status %d", - data_Beacon.cid_dat_send_msg.status); + task->debug("data_Beacon.cid_dat_send_msg.status 0x%02X", + (unsigned)data_Beacon.cid_dat_send_msg.status); task->debug("data_Beacon.cid_dat_send_msg.beacon_id %d", data_Beacon.cid_dat_send_msg.beacon_id); break; @@ -414,26 +413,26 @@ namespace Transports case CID_SYS_REBOOT: task->debug("MESSAGE CID_SYS_REBOOT"); - task->debug("data_Beacon.cid_sys_reboot_msg.status %d", - data_Beacon.cid_sys_reboot_msg.status); + task->debug("data_Beacon.cid_sys_reboot_msg.status 0x%02X", + (unsigned)data_Beacon.cid_sys_reboot_msg.status); break; case CID_SETTINGS_SET: task->debug("MESSAGE CID_SETTINGS_SET"); - task->debug("data_Beacon.cid_sys_settings_set_msg.status %d", - data_Beacon.cid_sys_settings_set_msg.status); + task->debug("data_Beacon.cid_sys_settings_set_msg.status 0x%02X", + (unsigned)data_Beacon.cid_sys_settings_set_msg.status); break; case CID_SETTINGS_SAVE: task->debug("MESSAGE CID_SETTINGS_SAVE"); - task->debug("data_Beacon.cid_settings_save_msg.status %d", - data_Beacon.cid_settings_save_msg.status); + task->debug("data_Beacon.cid_settings_save_msg.status 0x%02X", + (unsigned)data_Beacon.cid_settings_save_msg.status); break; case CID_NAV_QUERY_SEND: task->debug("MESSAGE CID_NAV_QUERY_SEND"); - task->debug("data_Beacon.cid_settings_save_msg.status %d", - data_Beacon.cid_nav_query_send_msg.status); + task->debug("data_Beacon.cid_settings_save_msg.status 0x%02X", + (unsigned)data_Beacon.cid_nav_query_send_msg.status); break; case CID_NAV_QUERY_RESP: @@ -481,14 +480,14 @@ namespace Transports case CID_NAV_BEACON_POS_SEND: task->debug("CID_NAV_BEACON_POS_SEND"); - task->debug("data_Beacon.cid_nav_beacon_pos_send_msg.status %d", - data_Beacon.cid_nav_beacon_pos_send_msg.status); + task->debug("data_Beacon.cid_nav_beacon_pos_send_msg.status 0x%02X", + (unsigned)data_Beacon.cid_nav_beacon_pos_send_msg.status); break; case CID_NAV_REF_POS_SEND: task->debug("CID_NAV_REF_POS_SEND"); - task->debug("data_Beacon.cid_nav_ref_pos_send_msg.status %d", - data_Beacon.cid_nav_ref_pos_send_msg.status); + task->debug("data_Beacon.cid_nav_ref_pos_send_msg.status 0x%02X", + (unsigned)data_Beacon.cid_nav_ref_pos_send_msg.status); break; case CID_NAV_REF_POS_UPDATE: diff --git a/src/Transports/Seatrac/MsgTypes.hpp b/src/Transports/Seatrac/MsgTypes.hpp index 9bb5994dc3..38cbf378c0 100644 --- a/src/Transports/Seatrac/MsgTypes.hpp +++ b/src/Transports/Seatrac/MsgTypes.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -57,8 +57,8 @@ namespace Transports uint16_t environment_supply; int16_t environment_temperature; int32_t environment_pressure; - int32_t EnvironmentDepth; - uint16_t EnvironmentVos; + int32_t environment_depth; + uint16_t environment_vos; // Attitude. int16_t attitude_yaw; int16_t attitude_pitch; @@ -212,6 +212,9 @@ namespace Transports { std::memcpy(&index, packet_data + 0, 1); std::memcpy(&n_sub_messages, packet_data + 1, 1); + if (packet_len == 0) + return -2; + if (data_rec_flag == 0 && index != n_sub_messages && index != 1) { return -1; diff --git a/src/Transports/Seatrac/Parser.hpp b/src/Transports/Seatrac/Parser.hpp index 3d0e22f877..27ad8e1604 100644 --- a/src/Transports/Seatrac/Parser.hpp +++ b/src/Transports/Seatrac/Parser.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -88,6 +88,11 @@ namespace Transports DataSeatrac(void) { cid_dat_send_msg.lock_flag = 0; + cid_dat_send_msg.status = CST_E::CST_OK; + + cid_ping_error_msg.status = CST_E::CST_OK; + cid_ping_send_msg.status = CST_E::CST_OK; + cid_dat_receive_msg.data_rec_flag = 0; for (int i = 0; i < MESSAGE_NUMBER; i++) new_message[i] = 0; @@ -203,8 +208,8 @@ namespace Transports msg_raw + ind + 2, 2); std::memcpy(&data_Beacon.cid_status_msg.environment_pressure, msg_raw + ind + 4, 4); - std::memcpy(&data_Beacon.cid_status_msg.EnvironmentDepth, msg_raw + ind + 8, 4); - std::memcpy(&data_Beacon.cid_status_msg.EnvironmentVos, msg_raw + ind + 12, 2); + std::memcpy(&data_Beacon.cid_status_msg.environment_depth, msg_raw + ind + 8, 4); + std::memcpy(&data_Beacon.cid_status_msg.environment_vos, msg_raw + ind + 12, 2); ind += 14; } diff --git a/src/Transports/Seatrac/Task.cpp b/src/Transports/Seatrac/Task.cpp index 0ca4063ed3..650a744563 100644 --- a/src/Transports/Seatrac/Task.cpp +++ b/src/Transports/Seatrac/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2015 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -25,6 +25,7 @@ //*************************************************************************** // Author: João Teixeira * // Author: Raúl Sáez * +// Author: Paulo Dias * //*************************************************************************** // ISO C++ 98 headers. @@ -46,12 +47,18 @@ namespace Transports { //! Blueprint Subsea's Seatrac acoustic modem driver. + //! Tested for AppFW v1.5.2041, v1.9.2132, v2.2.2191 //! //! @author João Teixeira. namespace Seatrac { using DUNE_NAMESPACES; + //! Hard Iron calibration parameter name. + static const std::string c_hard_iron_param = "Hard-Iron Calibration"; + //! Number of axis. + static const uint8_t c_number_axis = 3; + //! Entity states. enum EntityStates { @@ -74,10 +81,28 @@ namespace Transports bool only_underwater; //! Addresses Number - modem std::string addr_section; + //! Enable ARHS mode + bool arhs_mode; + //! Enable pressure sensor + bool pressure_sensor_mode; + //! Enable pressure sensor use for checking if underwater + bool use_pressure_sensor_for_medium; //! Enable usbl mode bool usbl_mode; + //! Hard iron calibration. + std::vector hard_iron; //! Enhanced usbl information will be requested. bool enhanced_usbl; + // Rotation matrix values. + std::vector rotation_mx; + //! Calibration threshold. + double calib_threshold; + //! max range + uint16_t max_range; + //! Timeout time multiplier for ack wait + uint8_t ack_timeout_time_multiplier; + //! dummy connection + bool dummy_connection; }; //! Map of system's names. @@ -91,6 +116,10 @@ namespace Transports IO::Handle* m_handle; //! Task arguments. Arguments m_args; + //! Config Status. + bool m_config_status; + //! c_preamble detected + bool m_pre_detected; //! Current state. EntityStates m_state_entity; //! Entity states. @@ -109,8 +138,12 @@ namespace Transports DataSeatrac m_data_beacon; //! Time of last serial port input. double m_last_input; - //! Timer to manage the fragmentation of OWAY messages. + //! Read timestamp. + double m_tstamp; + //! Timer to manage the fragmentation of OWAY messages. Time::Counter m_oway_timer; + //! hard iron calibration parameters. + float m_hard_iron[3]; //! Map of seatrac modems by name. MapName m_modem_names; //! Map of seatrac modems by address. @@ -119,6 +152,24 @@ namespace Transports Ticket* m_ticket; // Save modem commands. IMC::DevDataText m_dev_data; + //! Euler angles message. + IMC::EulerAngles m_euler; + //! Acceleration message. + IMC::Acceleration m_accel; + //! Angular velocity message. + IMC::AngularVelocity m_agvel; + //! Magnetometer Vector message. + IMC::MagneticField m_magfield; + //! Current sound speed. + IMC::SoundSpeed m_sspeed; + // Depth. + IMC::Depth m_depth; + // Pressure. + IMC::Pressure m_pressure; + // Measured temperature. + IMC::Temperature m_temperature; + //! Rotation Matrix to correct mounting position. + Math::Matrix m_rotation; //! Constructor. //! @param[in] name task name. @@ -126,8 +177,12 @@ namespace Transports Task(const std::string& name, Tasks::Context& ctx) : DUNE::Tasks::Task(name, ctx), m_handle(NULL), + m_config_status(false), + m_pre_detected(false), m_stop_comms(false), - m_usbl_receiver(false) + m_usbl_receiver(false), + m_tstamp(0), + m_ticket(NULL) { // Define configuration parameters. paramActive(Tasks::Parameter::SCOPE_MANEUVER, @@ -135,7 +190,8 @@ namespace Transports param("Serial Port - Device", m_args.uart_dev) .defaultValue("") - .description("Serial port device used to communicate with the sensor"); + .description("Serial port device used to communicate with the sensor. " + "For TCP connection use in the form of 'tcp://xxx.xxx.xxx.xxx:xxxx'."); param("Serial Port - Baud Rate", m_args.uart_baud) .defaultValue("19200") @@ -149,6 +205,18 @@ namespace Transports .defaultValue("Seatrac Addresses") .description("Name of the configuration section with modem addresses"); + param("AHRS Mode", m_args.arhs_mode) + .defaultValue("false") + .description("Enable the AHRS information to used in navigation"); + + param("Pressure Sensor Mode", m_args.pressure_sensor_mode) + .defaultValue("false") + .description("Enable the pressure sensor, depth, sound velocity and temperature information "); + + param("Use Internal Pressure Sensor for Medium", m_args.use_pressure_sensor_for_medium) + .defaultValue("false") + .description("Enable pressure sensor use for checking if underwater"); + param("USBL Mode", m_args.usbl_mode) .defaultValue("false") .description("Enable the USBL mode. USBL receivers can obtain position information."); @@ -159,6 +227,36 @@ namespace Transports "information in transmissions. This parameter is useful only when " "the beacon has an USBL receiver."); + param("AHRS Rotation Matrix", m_args.rotation_mx) + .defaultValue("") + .size(9) + .description("AHRS rotation matrix which is dependent of the mounting position"); + + param(c_hard_iron_param, m_args.hard_iron) + .units(Units::Gauss) + .size(c_number_axis) + .description("Hard-Iron calibration parameters"); + + param("Calibration Threshold", m_args.calib_threshold) + .defaultValue("0.1") + .units(Units::Gauss) + .minimumValue("0.0") + .description("Minimum magnetic field calibration values to reset hard iron parameters"); + + param("Max Range", m_args.max_range) + .defaultValue("1000") + .minimumValue("250") + .description("Maximum value of distance at which Ranges are considered"); + + param("Acknowledged timeout time multiplier", m_args.ack_timeout_time_multiplier) + .defaultValue("6") + .minimumValue("3") + .description("A time multiplier to wait before timeout for acknowledge (it ack requested)"); + + param("Dummy Connection", m_args.dummy_connection) + .defaultValue("false") + .description("To assume a dummy connection and not a modem (no replies"); + // Initialize state messages. m_states[STA_BOOT].state = IMC::EntityState::ESTA_BOOT; m_states[STA_BOOT].description = DTR("initializing"); @@ -210,16 +308,35 @@ namespace Transports void processNewData(void) { - if (m_data_beacon.newDataAvailable(CID_DAT_RECEIVE)) - handleBinaryMessage(); + if(m_config_status==true) + { + if (m_data_beacon.newDataAvailable(CID_DAT_RECEIVE)) + handleBinaryMessage(); + + if (m_data_beacon.newDataAvailable(CID_DAT_SEND)) + handleDatSendResponse(); - if (m_data_beacon.newDataAvailable(CID_DAT_SEND)) - handleDatSendResponse(); + if (m_data_beacon.newDataAvailable(CID_DAT_ERROR)) + handleCommunicationError(); + + if(m_data_beacon.newDataAvailable(CID_STATUS)) + { + if(m_args.arhs_mode == true) + { + handleAhrsData(); + } + if(m_args.pressure_sensor_mode == true) + { + handlePressureSensor(); + } - if (m_data_beacon.newDataAvailable(CID_DAT_ERROR)) - handleCommunicationError(); + //todo send environment_supply + //m_data_beacon.cid_status_msg.environment_supply; //uint16_t + } + } } + //! Release //! Read sentence. void readSentence(void) @@ -233,6 +350,7 @@ namespace Transports if (Poll::poll(*m_handle, 0.001)) { rv = m_handle->readString(bfr, c_bfr_size); + m_tstamp = Clock::getSinceEpoch(); m_last_input = Clock::get(); for (size_t i = 0; i < rv; ++i) { @@ -241,23 +359,32 @@ namespace Transports { m_dev_data.value.assign(sanitize(m_data)); dispatch(m_dev_data); - if (processSentence()) + if(m_pre_detected==true) { - msg_raw = m_datahex.data(); - std::memcpy(&typemes, msg_raw, 1); - dataParser(typemes, msg_raw + 1, m_data_beacon); - processNewData(); - printDebugFunction(typemes, m_data_beacon, this); - typemes = 0; + if (processSentence()) + { + msg_raw = m_datahex.data(); + std::memcpy(&typemes, msg_raw, 1); + dataParser(typemes, msg_raw + 1, m_data_beacon); + processNewData(); + printDebugFunction(typemes, m_data_beacon, this); + typemes = 0; + } } + m_pre_detected = false; m_data.clear(); } else { if (bfr[i] == c_preamble) + { m_data.clear(); + m_pre_detected = true; + } else if (bfr[i] != '\r') + { m_data.push_back(bfr[i]); + } } } } @@ -287,6 +414,9 @@ namespace Transports setAndSendState(STA_BOOT); try { + if (m_args.only_underwater == true) + m_stop_comms = true; + if (openSocket()) return; @@ -309,11 +439,11 @@ namespace Transports std::string agent = getSystemName(); std::vector addrs = m_ctx.config.options(m_args.addr_section); - // verify modem local addres value. + // verify modem local address value. for (unsigned i = 0; i < addrs.size(); ++i) { unsigned addr = 0; - m_ctx.config.get("Seatrac Addresses", addrs[i], "0", addr); + m_ctx.config.get(m_args.addr_section, addrs[i], "0", addr); m_modem_names[addrs[i]] = addr; m_modem_addrs[addr] = addrs[i]; } @@ -334,11 +464,11 @@ namespace Transports sendCommand(commandCreateSeatrac(CID_SETTINGS_GET, m_data_beacon)); processInput(); } - while (m_data_beacon.newDataAvailable(CID_SETTINGS_GET) == 0); + while (m_data_beacon.newDataAvailable(CID_SETTINGS_GET) == 0 && !m_args.dummy_connection); sendCommandAndWait(commandCreateSeatrac(CID_SYS_INFO, m_data_beacon), 1); - if( m_data_beacon.cid_sys_info.hardware.part_number == BT_X150) + if (m_data_beacon.cid_sys_info.hardware.part_number == BT_X150) m_usbl_receiver = true; uint8_t output_flags = (ENVIRONMENT_FLAG | ATTITUDE_FLAG @@ -350,17 +480,37 @@ namespace Transports if (m_usbl_receiver) xcvr_flags |= USBL_USE_AHRS_FLAG | XCVR_USBL_MSGS_FLAG; + StatusMode_E status_mode= STATUS_MODE_1HZ; + bool chage_IMU = true; + if (m_args.arhs_mode == true) + { + status_mode = STATUS_MODE_10HZ; + chage_IMU = isCalibrated(); + } if (!((m_data_beacon.cid_settings_msg.xcvr_beacon_id == m_addr) - && (m_data_beacon.cid_settings_msg.status_flags == STATUS_MODE_1HZ) + && (m_data_beacon.cid_settings_msg.status_flags == status_mode) && (m_data_beacon.cid_settings_msg.status_output == output_flags) - && (m_data_beacon.cid_settings_msg.xcvr_flags == xcvr_flags))) + && (m_data_beacon.cid_settings_msg.xcvr_flags == xcvr_flags) + && (m_data_beacon.cid_settings_msg.xcvr_range_tmo == m_args.max_range) + && chage_IMU == true)) { - m_data_beacon.cid_settings_msg.status_flags = STATUS_MODE_1HZ; + m_data_beacon.cid_settings_msg.status_flags = status_mode; m_data_beacon.cid_settings_msg.status_output = output_flags; m_data_beacon.cid_settings_msg.xcvr_flags = xcvr_flags; m_data_beacon.cid_settings_msg.xcvr_beacon_id = m_addr; + m_data_beacon.cid_settings_msg.xcvr_range_tmo = m_args.max_range; + + if(chage_IMU == false) + { + m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_x = m_args.hard_iron[0]; + m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_y = m_args.hard_iron[1]; + m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_z = m_args.hard_iron[2]; + } + + inf("asking to save settings to modem"); sendCommandAndWait(commandCreateSeatrac(CID_SETTINGS_SET, m_data_beacon), 2); sendCommandAndWait(commandCreateSeatrac(CID_SETTINGS_SAVE, m_data_beacon), 2); + inf("rebooting modem"); sendCommandAndWait(commandCreateSeatrac(CID_SYS_REBOOT, m_data_beacon), 6); sendCommandAndWait(commandCreateSeatrac(CID_SETTINGS_GET, m_data_beacon), 2); @@ -370,14 +520,31 @@ namespace Transports war(DTR("failed to configure device")); } - debug("ready"); + inf("ready"); setAndSendState(STA_IDLE); + m_config_status = true; } else { - debug("ready"); + inf("ready (settings already set)"); setAndSendState(STA_IDLE); + m_config_status = true; } + + inf(DTR("Beacon id=%d | HW P#%d (rev#%d) serial#%d | FW P#%d v%d.%d.%d | App P#%d v%d.%d.%d | %s USBL beacon"), + m_data_beacon.cid_settings_msg.xcvr_beacon_id, + m_data_beacon.cid_sys_info.hardware.part_number, + m_data_beacon.cid_sys_info.hardware.part_rev, + m_data_beacon.cid_sys_info.hardware.serial_number, + m_data_beacon.cid_sys_info.boot_firmware.part_number, + m_data_beacon.cid_sys_info.boot_firmware.version_maj, + m_data_beacon.cid_sys_info.boot_firmware.version_min, + m_data_beacon.cid_sys_info.boot_firmware.version_build, + m_data_beacon.cid_sys_info.main_firmware.part_number, + m_data_beacon.cid_sys_info.main_firmware.version_maj, + m_data_beacon.cid_sys_info.main_firmware.version_min, + m_data_beacon.cid_sys_info.main_firmware.version_build, + m_usbl_receiver ? "Is" : "Not"); } else { @@ -387,6 +554,118 @@ namespace Transports } } + //! Update parameters. + void + onUpdateParameters(void) + { + m_rotation.fill(3, 3, &m_args.rotation_mx[0]); + + // Rotate calibration parameters. + Math::Matrix data(3, 1); + + for (unsigned i = 0; i < 3; i++) + data(i) = m_args.hard_iron[i]; + data = transpose(m_rotation) * data; + for (unsigned i = 0; i < 3; i++) + m_hard_iron[i] = data(i); + + if (m_handle != NULL) + { + + if (paramChanged(m_args.hard_iron)) + runCalibration(); + } + } + //! Routine to run calibration proceedings. + void + runCalibration(void) + { + if (m_handle == NULL) + return; + + // See if vehicle has same hard iron calibration parameters. + if (!isCalibrated()) + { + // Set hard iron calibration parameters and reset device. + if (!setHardIron()) + { + throw RestartNeeded(DTR("failed to set hard-iron correction factors"), 5); + } + } + } + + void + consume(const IMC::MagneticField* msg) + { + if (msg->getDestinationEntity() != getEntityId()) + return; + + // Reject if it is small adjustment. + if ((std::abs(msg->x) < m_args.calib_threshold) && + (std::abs(msg->y) < m_args.calib_threshold)) + return; + + double hi_x = m_args.hard_iron[0] + msg->x; + double hi_y = m_args.hard_iron[1] + msg->y; + + IMC::EntityParameter hip; + hip.name = c_hard_iron_param; + hip.value = String::str("%f, %f, 0.0", hi_x, hi_y); + + IMC::SetEntityParameters np; + np.name = getEntityLabel(); + np.params.push_back(hip); + dispatch(np, DF_LOOP_BACK); + + IMC::SaveEntityParameters sp; + sp.name = getEntityLabel(); + dispatch(sp); + } + + //! Check if sensor has the same hard iron calibration parameters. + //! @return true if the parameters are the same, false otherwise. + bool + isCalibrated(void) + { + if( ((int32_t) (m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_x*100)) != ( (int32_t) (m_args.hard_iron[0]*100))) + { + war(DTR("different calibration parameters")); + return false; + } + if( ((int32_t) (m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_y*100)) != ( (int32_t) (m_args.hard_iron[1]*100))) + { + war(DTR("different calibration parameters")); + return false; + } + if( ((int32_t) (m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_z*100)) != ( (int32_t) (m_args.hard_iron[2]*100))) + { + war(DTR("different calibration parameters")); + return false; + } + debug("Is calibrated"); + return true; + } + + //! Set new hard iron calibration parameters. + //! @return true if successful, false otherwise. + bool + setHardIron(void) + { + m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_x = m_args.hard_iron[0]; + m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_y = m_args.hard_iron[1]; + m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_z = m_args.hard_iron[2]; + sendCommandAndWait(commandCreateSeatrac(CID_SETTINGS_SET, m_data_beacon), 2); + sendCommandAndWait(commandCreateSeatrac(CID_SETTINGS_SAVE, m_data_beacon), 2); + sendCommandAndWait(commandCreateSeatrac(CID_SETTINGS_GET, m_data_beacon), 2); + if(m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_x != m_args.hard_iron[0]) + return false; + if(m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_y != m_args.hard_iron[1]) + return false; + if(m_data_beacon.cid_settings_msg.ahrs_cal.mag_hard_z != m_args.hard_iron[2]) + return false; + + return true; + } //! Release resources. void onResourceRelease(void) @@ -406,12 +685,23 @@ namespace Transports processInput(delay_aft); } + //! Check if medium and configuration for protected msg send. + bool + isCommsBlockedByMedium(void) + { + if (m_args.only_underwater && m_args.pressure_sensor_mode + && m_args.use_pressure_sensor_for_medium) + return m_pressure.value <= 0; + + return m_stop_comms; + } + //! Send command if the modem has conditions to operate. //! @param[in] cmd command string. void sendProtectedCommand(const std::string& cmd) { - if (m_stop_comms) + if (isCommsBlockedByMedium()) { war(DTR("Sending stopped: Communication out of water forbidden.")); clearTicket(IMC::UamTxStatus::UTS_FAILED); @@ -426,7 +716,9 @@ namespace Transports void sendCommand(const std::string& cmd) { + debug(DTR("Send command to the acoustic modem %s"), cmd.c_str()); m_handle->writeString(cmd.c_str()); + debug(DTR("Sent done")); m_dev_data.value.assign(sanitize(cmd)); dispatch(m_dev_data); } @@ -436,7 +728,11 @@ namespace Transports bool hasConnection(void) { - return m_data_beacon.new_message[CID_STATUS]; + if (Clock::get() >= (m_last_input + c_input_tout)) + { + return false; + } + return true; } //! Processing incoming data. @@ -446,8 +742,24 @@ namespace Transports if (m_data_beacon.cid_dat_receive_msg.ack_flag != 0) { // if msg has more than 1 packet, send next part - if (m_data_beacon.cid_dat_send_msg.packetDataNextPart(1) != -1) + if (m_ticket != NULL) { + debug(DTR("Success transmission complete (part %d of %d) for ticket %d (in %f s)"), + m_data_beacon.cid_dat_send_msg.message_index, + m_data_beacon.cid_dat_send_msg.n_sub_messages, + m_ticket->seq, + m_oway_timer.getElapsed()); + } + + if (m_ticket != NULL && m_data_beacon.cid_dat_send_msg.packetDataNextPart(1) != -1) + { + resetOneWayTimer(); + debug(DTR("Sending (handleBinaryMessage) part %d of %d for ticket %d will take up to %f s for %d bytes"), + m_data_beacon.cid_dat_send_msg.message_index, + m_data_beacon.cid_dat_send_msg.n_sub_messages, + m_ticket == NULL ? -1 : m_ticket->seq, + m_oway_timer.getTop(), + m_data_beacon.cid_dat_send_msg.packet_len); sendProtectedCommand(commandCreateSeatrac(CID_DAT_SEND, m_data_beacon)); } else @@ -457,7 +769,13 @@ namespace Transports handleAcousticInformation(m_data_beacon.cid_dat_receive_msg.aco_fix); // Data communication done - clearTicket(IMC::UamTxStatus::UTS_DONE); + if (m_ticket != NULL) + { + debug(DTR("Msg transmission complete for ticket %d (in %f s)"), + m_ticket->seq, + m_oway_timer.getElapsed()); + clearTicket(IMC::UamTxStatus::UTS_DONE); + } } return; } @@ -477,6 +795,8 @@ namespace Transports if (data_rec_flag == 0) debug("colecting data"); + if(data_rec_flag == -2) + debug("no data size"); } } @@ -589,18 +909,131 @@ namespace Transports void handleCommunicationError(void) { - if (m_data_beacon.cid_dat_send_msg.packetDataNextPart(0) < MAX_MESSAGE_ERRORS) + if( !(m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAY || + m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAYU)) { - m_oway_timer.reset(); - sendProtectedCommand(commandCreateSeatrac(CID_DAT_SEND, m_data_beacon)); + int next_part_code = m_ticket == NULL ? -1 : m_data_beacon.cid_dat_send_msg.packetDataNextPart(0); + if (next_part_code < MAX_MESSAGE_ERRORS && next_part_code > 0) + { + resetOneWayTimer(); + debug(DTR("Error sending (handleCommunicationError) part %d of %d for ticket %d, resending"), + m_data_beacon.cid_dat_send_msg.message_index, + m_data_beacon.cid_dat_send_msg.n_sub_messages, + m_ticket == NULL ? -1 : m_ticket->seq); + sendProtectedCommand(commandCreateSeatrac(CID_DAT_SEND, m_data_beacon)); + } + else + { + war(DTR("Communication failed for ticket %d %d"), + m_ticket == NULL ? -1 : m_ticket->seq, + next_part_code); + clearTicket(IMC::UamTxStatus::UTS_FAILED); + } } else { - war(DTR("Communication failed")); - clearTicket(IMC::UamTxStatus::UTS_FAILED); + war(DTR("Next msg or part send to son for ticket %d with ERROR"), m_ticket == NULL ? -1 : m_ticket->seq); + } + } + + //! Correct data according with mounting position. + void + rotateData(void) + { + Math::Matrix data(3, 1); + + // Acceleration. + data(0) = m_accel.x; + data(1) = m_accel.y; + data(2) = m_accel.z; + data = m_rotation * data; + m_accel.x = data(0); + m_accel.y = data(1); + m_accel.z = data(2); + + // Angular Velocity. + data(0) = m_agvel.x; + data(1) = m_agvel.y; + data(2) = m_agvel.z; + data = m_rotation * data; + m_agvel.x = data(0); + m_agvel.y = data(1); + m_agvel.z = data(2); + + // Magnetic Field. + data(0) = m_magfield.x; + data(1) = m_magfield.y; + data(2) = m_magfield.z; + data = m_rotation * data; + m_magfield.x = data(0); + m_magfield.y = data(1); + m_magfield.z = data(2); + } + + //! Handle AHRS data send by local beacon. + //! The method tries to dispatch all the necessary information for navigation + void + handleAhrsData(void) + { + if(m_data_beacon.cid_status_msg.outputflags_list[5]) + { + //Time Stamp + m_euler.setTimeStamp(m_tstamp); + m_accel.setTimeStamp(m_tstamp); + m_agvel.setTimeStamp(m_tstamp); + m_magfield.setTimeStamp(m_tstamp); + + // Acceleration. + m_accel.x = ( (fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_acc_x / (fp32_t) m_data_beacon.cid_settings_msg.ahrs_cal.acc_max_x) * Math::c_gravity; + m_accel.y = ( (fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_acc_y / (fp32_t) m_data_beacon.cid_settings_msg.ahrs_cal.acc_max_y) * Math::c_gravity; + m_accel.z = ( (fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_acc_z / (fp32_t) m_data_beacon.cid_settings_msg.ahrs_cal.acc_max_z) * Math::c_gravity; + // Magnetic Field. + m_magfield.x = (fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_mag_x; + m_magfield.y = (fp32_t)m_data_beacon.cid_status_msg.ahrs_comp_mag_y; + m_magfield.z = (fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_mag_z; + + m_euler.theta= Angles::radians( ((fp32_t) m_data_beacon.cid_status_msg.attitude_roll)/10); + m_euler.psi = Angles::radians(((fp32_t) m_data_beacon.cid_status_msg.attitude_pitch)/10); + m_euler.psi_magnetic = m_euler.psi; + m_euler.phi= Angles::radians(((fp32_t) m_data_beacon.cid_status_msg.attitude_yaw)/10); + // Angular Velocity. + m_agvel.x = Angles::radians((fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_gyro_x); + m_agvel.y = Angles::radians((fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_gyro_y); + m_agvel.z = Angles::radians((fp32_t) m_data_beacon.cid_status_msg.ahrs_comp_gyro_z); + //Euler angles. + m_euler.time = ((fp32_t) m_data_beacon.cid_status_msg.timestamp)/1000; + m_accel.time = m_euler.time; + m_agvel.time = m_euler.time; + m_magfield.time = m_euler.time; + rotateData(); + // Dispatch messages. + dispatch(m_euler, DF_KEEP_TIME); + dispatch(m_accel, DF_KEEP_TIME); + dispatch(m_agvel, DF_KEEP_TIME); + dispatch(m_magfield, DF_KEEP_TIME); } } + //! Handle Pressure, Depth, Temperature and Sound Speed data and dispatch. + //! The method tries to dispatch data prom sensors: Pressure, Depth, Temperature, and Sound Speed data + void + handlePressureSensor (void) + { + m_depth.value = ((fp32_t) (m_data_beacon.cid_status_msg.environment_depth)) / 10.0; //int32_t // m_channel_readout * m_args.depth_conv; + m_pressure.value = (((fp32_t) (m_data_beacon.cid_status_msg.environment_pressure)) / 1000.0) * Math::c_pascal_per_bar; + m_temperature.value = ((fp32_t) (m_data_beacon.cid_status_msg.environment_temperature)) / 10.0; //int16_t//m_channel_readout; + m_sspeed.value = ((fp32_t) (m_data_beacon.cid_status_msg.environment_vos)) / 10.0; //uint16_t + dispatch(m_depth); + dispatch(m_pressure); + dispatch(m_temperature); + dispatch(m_sspeed); + trace("Received from modem: Depth %f m | Presure %f P | Temperature %f \u00B0C | SoundSpeed %f m/s", + m_depth.value, + m_pressure.value, + m_temperature.value, + m_sspeed.value); + } + //! Handle the response to a CID_Data_Send command. //! If the acknowledged message is an OWAY and it is compound //! by more than one packet, the method sends the following packet. @@ -609,20 +1042,7 @@ namespace Transports void handleDatSendResponse(void) { - if (m_data_beacon.cid_dat_send_msg.status == CST_OK) - { - if (m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAY || - m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAYU) - { - // if msg has more than 1 packet, send next part - if (m_data_beacon.cid_dat_send_msg.packetDataNextPart(1) != -1) - { - m_oway_timer.setTop(m_data_beacon.cid_dat_send_msg.packet_len * 8 * 1/c_acoustic_bitrate); - sendProtectedCommand(commandCreateSeatrac(CID_DAT_SEND, m_data_beacon)); - } - } - } - else + if (m_data_beacon.cid_dat_send_msg.status != CST_OK) { if (m_data_beacon.cid_dat_send_msg.status != CST_XCVR_BUSY) handleCommunicationError(); @@ -632,6 +1052,8 @@ namespace Transports void consume(const IMC::UamTxFrame* msg) { + debug(DTR("Received UamTxFrame with dst=0x%04X. Msg for system '%s'"), msg->getDestination(), msg->sys_dst.c_str()); + std::string hex = String::toHex(msg->data); std::vector data_t; std::copy(hex.begin(), hex.end(), std::back_inserter(data_t)); @@ -639,6 +1061,10 @@ namespace Transports if (msg->getDestination() != getSystemId()) return; + if (msg->getDestinationEntity() != 255 && msg->getDestinationEntity() != getEntityId()) + return; + + // Create and fill new ticket. Ticket ticket; ticket.imc_sid = msg->getSource(); @@ -646,9 +1072,12 @@ namespace Transports ticket.seq = msg->seq; ticket.ack = (msg->flags & IMC::UamTxFrame::UTF_ACK) != 0; + debug(DTR("Creating ticket %d"), ticket.seq); + if (msg->sys_dst == getSystemName()) { sendTxStatus(ticket, IMC::UamTxStatus::UTS_INV_ADDR); + debug(DTR("Sending UamTxStatus::UTS_INV_ADDR. Ticket %d died"), ticket.seq); return; } @@ -667,12 +1096,14 @@ namespace Transports if (m_data_beacon.cid_dat_send_msg.packetDataSendStatus()) { sendTxStatus(ticket, IMC::UamTxStatus::UTS_BUSY); + debug(DTR("Sending UamTxStatus::UTS_BUSY. Ticket %d died"), ticket.seq); return; } // Replace ticket and transmit. replaceTicket(ticket); sendTxStatus(ticket, IMC::UamTxStatus::UTS_IP); + debug(DTR("Sending UamTxStatus::UTS_IP. Ticket %d being processed"), ticket.seq); // Fill the message type. if ((ticket.addr != 0) && (ticket.ack == true)) @@ -688,6 +1119,7 @@ namespace Transports { m_data_beacon.cid_dat_send_msg.msg_type = MSG_REQ; } + debug(DTR("Configuration as %s %s"), m_args.usbl_mode ? "USBL" : "MSG_ONLY", m_args.usbl_mode && m_args.enhanced_usbl ? "enhanced" : ""); } else { @@ -695,6 +1127,7 @@ namespace Transports m_data_beacon.cid_dat_send_msg.msg_type = MSG_OWAYU; else m_data_beacon.cid_dat_send_msg.msg_type = MSG_OWAY; + debug(DTR("Configuration as ONEWAY %s"), m_args.usbl_mode ? "USBL" : "MSG_ONLY"); } int code; @@ -712,7 +1145,14 @@ namespace Transports err(DTR("size mismatch")); break; default: - m_oway_timer.setTop(m_data_beacon.cid_dat_send_msg.packet_len * 8 * 1/c_acoustic_bitrate); + resetOneWayTimer(); + debug(DTR("Sending package %f s"), m_oway_timer.getTop()); + debug(DTR("Sending (consume UamTxFrame) part %d of %d for ticket %d will take up to %f s for %d bytes"), + m_data_beacon.cid_dat_send_msg.message_index, + m_data_beacon.cid_dat_send_msg.n_sub_messages, + ticket.seq, + m_oway_timer.getTop(), + m_data_beacon.cid_dat_send_msg.packet_len); sendProtectedCommand(commandCreateSeatrac(CID_DAT_SEND, m_data_beacon)); break; } @@ -822,30 +1262,76 @@ namespace Transports m_stop_comms = false; } - + + void + resetOneWayTimer() + { + int multiplier = 2; + if(!(m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAY || + m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAYU)) + multiplier = m_args.ack_timeout_time_multiplier; + m_oway_timer.setTop((m_data_beacon.cid_dat_send_msg.packet_len * 8 + * 1.0/c_acoustic_bitrate + (m_args.max_range * 1.0 / MIN_SOUND_SPEED)) + * multiplier ); + trace(DTR("Calc new timer (bytes %d | bit-rate %f | max-range %d m | multiplier %d) calculated to %f s"), + m_data_beacon.cid_dat_send_msg.packet_len, + c_acoustic_bitrate, + m_args.max_range, + multiplier, + m_oway_timer.getTop()); + } + //! Checks if an OWAY message is waiting to be sent. void - checkTxOWAY(void) { - - if (m_data_beacon.cid_dat_send_msg.packetDataSendStatus()) + checkTxOWAY(void) + { + if (m_data_beacon.cid_dat_send_msg.packetDataSendStatus()) { if (m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAY || m_data_beacon.cid_dat_send_msg.msg_type == MSG_OWAYU) { if (m_oway_timer.overflow()) { - if (m_data_beacon.cid_dat_send_msg.packetDataNextPart(0) < MAX_MESSAGE_ERRORS) + debug(DTR("NOACK Success transmission complete (part %d of %d) for ticket %d (in %f s)"), + m_data_beacon.cid_dat_send_msg.message_index, + m_data_beacon.cid_dat_send_msg.n_sub_messages, + m_ticket == NULL ? -1 : m_ticket->seq, + m_oway_timer.getElapsed()); + + if (m_data_beacon.cid_dat_send_msg.packetDataNextPart(1) != -1) { - m_oway_timer.setTop(m_oway_timer.getTop() / 2); + resetOneWayTimer(); + debug(DTR("Sending (checkTxOWAY) part %d of %d for ticket %d will take up to %f s for %d bytes"), + m_data_beacon.cid_dat_send_msg.message_index, + m_data_beacon.cid_dat_send_msg.n_sub_messages, + m_ticket == NULL ? -1 : m_ticket->seq, + m_oway_timer.getTop(), + m_data_beacon.cid_dat_send_msg.packet_len); sendProtectedCommand(commandCreateSeatrac(CID_DAT_SEND, m_data_beacon)); } - else + else { - war(DTR("OWAY transmission failed.")); - clearTicket(IMC::UamTxStatus::UTS_FAILED); + debug(DTR("Msg transmission complete for ticket %d (in %f s)"), + m_ticket == NULL ? -1 : m_ticket->seq, + m_oway_timer.getElapsed()); + clearTicket(IMC::UamTxStatus::UTS_DONE); } } } + else + { + // is with ack + if (m_ticket != NULL && m_oway_timer.overflow()) + { + //Took too long, lets bail with error + war(DTR("ACK TIMEOUT: Msg transmission with ack for ticket %d timeout ACK. Lets bail with error!! (%f s > %f s)"), + m_ticket->seq, + m_oway_timer.getElapsed(), + m_oway_timer.getTop()); + m_data_beacon.cid_dat_send_msg.lock_flag = 0; + clearTicket(IMC::UamTxStatus::UTS_FAILED); + } + } } } diff --git a/src/Transports/Serial/Task.cpp b/src/Transports/Serial/Task.cpp index e03ebf64d4..9e346ee50f 100644 --- a/src/Transports/Serial/Task.cpp +++ b/src/Transports/Serial/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/SerialOverTCP/Task.cpp b/src/Transports/SerialOverTCP/Task.cpp index 7a4fcf83ca..be9724b6ec 100644 --- a/src/Transports/SerialOverTCP/Task.cpp +++ b/src/Transports/SerialOverTCP/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -47,6 +47,8 @@ namespace Transports std::string uart_dev; // Serial port baud rate. unsigned uart_baud; + // Serial set canonical input + bool uart_canonical_input; // TCP listening port. unsigned tcp_port; }; @@ -78,6 +80,10 @@ namespace Transports .defaultValue("9600") .description("Serial port baud rate"); + param("Serial Port - Canonical Input", m_args.uart_canonical_input) + .defaultValue("false") + .description("Serial canonical input set"); + param("TCP - Port", m_args.tcp_port) .defaultValue("9999") .description("TCP port to listen on"); @@ -95,6 +101,11 @@ namespace Transports { m_sock = new TCPSocket; m_uart = new SerialPort(m_args.uart_dev, m_args.uart_baud); + if (m_args.uart_canonical_input) + { + m_uart->setCanonicalInput(true); + m_uart->flush(); + } } catch (std::runtime_error& e) { diff --git a/src/Transports/TCP/Client/Task.cpp b/src/Transports/TCP/Client/Task.cpp index 9125517e4b..fe18329ce3 100644 --- a/src/Transports/TCP/Client/Task.cpp +++ b/src/Transports/TCP/Client/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/TCP/Server/Task.cpp b/src/Transports/TCP/Server/Task.cpp index b3376fdd62..d3ba29aedc 100644 --- a/src/Transports/TCP/Server/Task.cpp +++ b/src/Transports/TCP/Server/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/TCPOnDemand/Task.cmake b/src/Transports/TCPOnDemand/Task.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Transports/TCPOnDemand/Task.cpp b/src/Transports/TCPOnDemand/Task.cpp new file mode 100644 index 0000000000..290a0559aa --- /dev/null +++ b/src/Transports/TCPOnDemand/Task.cpp @@ -0,0 +1,290 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Faculdade de Engenharia da * +// Universidade do Porto. For licensing terms, conditions, and further * +// information contact lsts@fe.up.pt. * +// * +// Modified European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the Modified * +// EUPL, Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// https://github.com/LSTS/dune/blob/master/LICENCE.md and * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Seruca * +//*************************************************************************** + +// DUNE headers. +#include + +namespace Transports +{ + namespace TCPOnDemand + { + using DUNE_NAMESPACES; + + const int c_max_size_wifi = 32 * 1024; + const int c_wifi_timeout = 15; + + struct Arguments + { + //! Maximum number of tries for one requested message + uint8_t max_number_tries; + //! Time between tries for one requested message + double time_between_tries; + }; + + struct TCPRequest{ + + IMC::TCPRequest* msg; + + bool + operator<(const TCPRequest& other) const + { + return msg->timeout > other.msg->timeout; + } + + TCPRequest(IMC::TCPRequest* other){ + msg = other; + } + + }; + + struct Task : public DUNE::Tasks::Task + { + + // Task arguments. + Arguments m_args; + + //! Queue of messages to send. + std::priority_queue m_queue; + //! Last RSSI value. + fp32_t m_value_RSSI; + //! Flag for dispatch messages. + bool m_can_send; + //! Sequence number of sending request. + uint16_t m_reqid; + //! Number of tries to establish a connection + uint8_t m_number_tries; + //! Timer for sending preceding message + Counter m_msg_send_timer; + + double m_connection_timeout; + + //! Constructor. + //! @param[in] name task name. + //! @param[in] ctx context. + Task(const std::string& name, Tasks::Context& ctx) : + DUNE::Tasks::Task(name, ctx), + m_value_RSSI(0), + m_can_send(true), + m_reqid(0), + m_number_tries(m_args.max_number_tries), + m_connection_timeout(2) + { + param("Maximum Number of Tries", m_args.max_number_tries) + .description("Maximum number of tries for one requested message before throwing error.") + .defaultValue("3"); + + param("Time Between Tries", m_args.time_between_tries) + .description("Time between tries for one requested message.") + .defaultValue("5"); + + bind(this); + + m_msg_send_timer.setTop(1); + + } + + + //! Update internal state with new parameter values. + void + onUpdateParameters(void) + { + } + + void + onResourceInitialization(void) + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + + void + consume(const IMC::TCPRequest* msg) + { + if(msg->getSource() != getSystemId()){ + return; + } + + if(msg->timeout == 0) + { + answer(msg,"TCPRequest timeout cannot be zero", IMC::TCPStatus::TCPSTAT_INPUT_FAILURE); + inf("%s", DTR("TCPRequest timeout cannot be zero")); + return; + } + if(msg->timeout < Time::Clock::getSinceEpoch()) + { + answer(msg, "TCPRequest timeout cannot be less than current time", IMC::TCPStatus::TCPSTAT_INPUT_FAILURE); + inf("%s", DTR("TCPRequest timeout cannot be less than current time")); + return; + + } + + //! Add message to the end of queue + m_queue.push(TCPRequest(msg->clone())); + answer(msg, "TCPRequest sent to queue", IMC::TCPStatus::TCPSTAT_QUEUED); + } + + void + updateEntityState(unsigned client_count) + { + if (client_count > 0) + { + setEntityState( + IMC::EntityState::ESTA_NORMAL, + String::str(DTR("connected to %u clients"), client_count)); + } + else + { + setEntityState(IMC::EntityState::ESTA_NORMAL, Status::CODE_IDLE); + } + } + + void + createTCPSocket(std::string system, TCPSocket& socket){ + + std::vector list; + String::split(system, ":", list); + Address addr=list[0].c_str(); + uint16_t port = atoi(list[1].c_str()); + + socket.setKeepAlive(true); + socket.setSendTimeout(m_connection_timeout); + socket.setReceiveTimeout(m_connection_timeout); + socket.connect(addr, port); + } + + void + answer(const IMC::TCPRequest* req, std::string info, int status) + { + IMC::TCPStatus msg; + msg.info = info; + msg.req_id = req->req_id; + msg.status = status; + msg.setDestination(req->getSource()); + msg.setDestinationEntity(req->getSourceEntity()); + dispatch(msg); + } + + void + clearTimeouts() + { + double time = Time::Clock::getSinceEpoch(); + while (!m_queue.empty() && m_queue.top().msg->timeout < time) + { + answer(m_queue.top().msg, "Transmission timed out.", IMC::TCPStatus::TCPSTAT_INPUT_FAILURE); + removeFromQueue(); + } + } + + uint16_t + createInternalId(){ + if(m_reqid==0xFFFF){ + m_reqid=0; + } + else{ + m_reqid++; + } + return m_reqid; + } + + //! Remove message from the queue. Resets timer. And unlocks the queue + void + removeFromQueue(){ + if(!m_queue.empty()) + { + m_queue.pop(); + } + m_number_tries = m_args.max_number_tries; + m_can_send=true; + } + + void + processQueue() + { + const IMC::TCPRequest * req = m_queue.top().msg; + + try{ + TCPSocket socket; + createTCPSocket(req->destination, socket); + + Utils::ByteBuffer data; + IMC::Packet::serialize(req->msg_data.get(), data); + socket.write(data.getBuffer(), data.getSize()); + + answer(req,"Message sent over TCP",IMC::TCPStatus::TCPSTAT_SENT); + removeFromQueue(); + + } + catch (std::exception& e) + { + m_number_tries--; + if (m_number_tries <= 0) + { + removeFromQueue(); + answer(req, "Couldn't connect with destination host", + IMC::TCPStatus::TCPSTAT_CANT_CONNECT); + m_msg_send_timer.setTop(1); + } + else + { + m_can_send = true; + m_msg_send_timer.setTop(m_args.time_between_tries); + } + } + + } + + //! Main loop. + void + onMain(void) + { + while (!stopping()) + { + waitForMessages(1.0); + if (m_msg_send_timer.overflow()) + { + clearTimeouts(); + if (m_can_send && !m_queue.empty()) + { + m_can_send = false; + processQueue(); + } + else + { + m_msg_send_timer.reset(); + } + + } + + + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Transports/UAN/Task.cpp b/src/Transports/UAN/Task.cpp index e91572498e..5f61961325 100644 --- a/src/Transports/UAN/Task.cpp +++ b/src/Transports/UAN/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -72,6 +72,8 @@ namespace Transports float usbl_max_wait; //! USBL Modem Announce service. bool usbl_announce; + //! Section where to read modem addresses + std::string addr_section; }; struct Task: public DUNE::Tasks::Task @@ -85,15 +87,13 @@ namespace Transports //! Last fuel level confidence. float m_fuel_conf; //! Sequence number. - uint16_t m_seq; - //! Last acoustic operation. - IMC::AcousticOperation* m_last_acop; - //! Vector of pending message requests - std::vector m_msg_requests; + uint16_t m_reqid; + //! Map of messages to send + std::map m_transmission_requests; //! Timer for sending preceding message Counter m_msg_send_timer; - //! When set should wait and send next message - bool m_send_next; + //! When "false" processQueue must wait + bool m_can_send; //! Reporter API. Supervisors::Reporter::Client* m_reporter; //! USBL Node arguments. @@ -113,67 +113,71 @@ namespace Transports m_progress(0), m_fuel_level(0), m_fuel_conf(0), - m_seq(0), - m_last_acop(NULL), - m_send_next(false), + m_reqid(0), + m_can_send(true), m_reporter(NULL), m_usbl_node(NULL), m_usbl_modem(NULL) { param("Enable Reports", m_args.report_enable) - .defaultValue("false") - .description("Enable system state acoustic reporting. When enabled, systems" - " shall acknowledge reception of requests to broadcast acoustic" - " messages containing the overall state of the system." - " When disabled, those requests shall be ignored"); + .defaultValue("false") + .description("Enable system state acoustic reporting. When enabled, systems" + " shall acknowledge reception of requests to broadcast acoustic" + " messages containing the overall state of the system." + " When disabled, those requests shall be ignored"); param("USBL Node -- Enabled", m_node_args.enabled) .defaultValue("false") .description("Enable system's USBL mode. When active, this system will" - " start using USBL by actively broadcasting an acoustic" - " message containing a request to get USBL feedback. The" - " request contains the period for transmissions, if quick" - " (two-way travel) or ranging (three-way travel) mode is" - " desired, and, if in ranging mode (not \"quick\"), to use" - " absolute or relative positioning. If a USBL modem is in" - " reach, they will start exchanging acoustic transmissions" - " to provide USBL positioning to the system." - " Any system can be configured to request USBL information" - " including modems with built-in USBL capabilities"); + " start using USBL by actively broadcasting an acoustic" + " message containing a request to get USBL feedback. The" + " request contains the period for transmissions, if quick" + " (two-way travel) or ranging (three-way travel) mode is" + " desired, and, if in ranging mode (not \"quick\"), to use" + " absolute or relative positioning. If a USBL modem is in" + " reach, they will start exchanging acoustic transmissions" + " to provide USBL positioning to the system." + " Any system can be configured to request USBL information" + " including modems with built-in USBL capabilities"); param("USBL Node -- Period", m_node_args.period) .defaultValue("60.0") .minimumValue("2.0") .units(Units::Second) .description("USBL's period. This value determines the period of USBL" - " positioning data. If \"Quick\" mode is selected, modem" - " shall ping the USBL modem with this period to get bearing" - " and elevation (two-way travel transmission). If \"Quick\"" - " mode is disabled, ranging information is included for a" - " proper fix. In this case, the USBL modem pings the node," - " hears the reply, computes the position and transmits back" - " to the node (three-way travel transmission)"); + " positioning data. If \"Quick\" mode is selected, modem" + " shall ping the USBL modem with this period to get bearing" + " and elevation (two-way travel transmission). If \"Quick\"" + " mode is disabled, ranging information is included for a" + " proper fix. In this case, the USBL modem pings the node," + " hears the reply, computes the position and transmits back" + " to the node (three-way travel transmission)"); param("USBL Node -- Absolute Fix", m_node_args.fix) .defaultValue("false") .description("If this argument is enabled, USBL sends an absolute fix using" - " WGS-84 lat/lon coordinates. If disabled, then the positioning" - " is relative to the origin of a system where the center of the" - " reference frame is the USBL modem"); + " WGS-84 lat/lon coordinates. If disabled, then the positioning" + " is relative to the origin of a system where the center of the" + " reference frame is the USBL modem"); + + param("USBL Node -- Inverted", m_node_args.inverted) + .defaultValue("false") + .description("If this argument is enabled, USBL node anounces itself" + " for inverted positioning by USBL modems."); param("USBL Node -- Quick, No Range", m_node_args.no_range) .defaultValue("false") .description("In this mode, the USBL node does not request ranging information." - " Thus, with this mode enabled, there's only a two-way travel" - " transmission between the node and the USBL modem. The node will" - " actively ping the modem to get bearing/elevation information" - " With this mode enabled \"Absolute Fix\" argument is ignored"); + " Thus, with this mode enabled, there's only a two-way travel" + " transmission between the node and the USBL modem. The node will" + " actively ping the modem to get bearing/elevation information" + " With this mode enabled \"Absolute Fix\" argument is ignored"); param("USBL Modem -- Announce Service", m_args.usbl_announce) .defaultValue("false") .description("This argument only concerns systems with USBL modems installed." - " This parameter statically adds a USBL announce, even if service" - " has not been detected yet (eg. modem not connected)"); + " This parameter statically adds a USBL announce, even if service" + " has not been detected yet (eg. modem not connected)"); param("USBL Modem -- Max Waiting Time", m_args.usbl_max_wait) .defaultValue("10.0") @@ -181,12 +185,17 @@ namespace Transports .maximumValue("20.0") .units(Units::Second) .description("This argument only concerns systems with USBL modems installed." - " This value establishes the maximum amount of time that the modem" - " waits for the target system's reply"); + " This value establishes the maximum amount of time that the modem" + " waits for the target system's reply"); - bind(this); + param("Address Section", m_args.addr_section) + .defaultValue("") + .description("Name of the configuration section with modem addresses"); + + bind(this); bind(this); bind(this); + bind(this); bind(this); bind(this); bind(this); @@ -195,6 +204,9 @@ namespace Transports bind(this); bind(this); bind(this); + bind(this); + + m_msg_send_timer.setTop(2); } ~Task(void) @@ -206,7 +218,7 @@ namespace Transports onResourceAcquisition(void) { m_reporter = new Supervisors::Reporter::Client(this, Supervisors::Reporter::IS_ACOUSTIC, - 2.0, false); + 2.0, false); m_usbl_node = new UsblTools::Node(this, &m_node_args); } @@ -230,12 +242,26 @@ namespace Transports void onResourceRelease(void) { - clearLastOp(); Memory::clear(m_reporter); Memory::clear(m_usbl_node); Memory::clear(m_usbl_modem); } + void + consume(const IMC::AcousticSystemsQuery* msg) + { + if (m_args.addr_section.empty()) + { + war("Modem address section was not properly set."); + return; + } + AcousticSystems reply; + std::vector options = m_ctx.config.options(m_args.addr_section); + options.erase(std::remove(options.begin(), options.end(), m_ctx.resolver.name()), options.end()); + reply.list = String::join(options.begin(), options.end(), ","); + dispatchReply(*msg, reply); + } + void consume(const IMC::EstimatedState* msg) { @@ -245,6 +271,15 @@ namespace Transports m_estate = *msg; } + void + consume(const IMC::GpsFix* msg) + { + if (msg->getSource() != getSystemId()) + return; + + m_usbl_node->consume(msg); + } + void consume(const IMC::PlanControlState* msg) { @@ -259,41 +294,25 @@ namespace Transports } void - consume(const IMC::AcousticOperation* msg) + consume(const IMC::AcousticRequest* msg) { - if (msg->getDestination() != getSystemId()) + if (msg->getSource() != getSystemId() + || msg->getDestination() != getSystemId()) return; - switch (msg->op) - { - case IMC::AcousticOperation::AOP_ABORT: - sendAbort(msg->system); - break; - - case IMC::AcousticOperation::AOP_RANGE: - sendRange(msg->system); - break; - - case IMC::AcousticOperation::AOP_MSG: - m_msg_requests.push_back((const IMC::AcousticOperation*)msg->clone()); - // are there more messages being sent? - if (m_msg_requests.size() > 1) - { - IMC::AcousticOperation aop(*msg); - aop.op = IMC::AcousticOperation::AOP_MSG_QUEUED; - dispatch(aop); - return; - } - else - { - sendMessage(msg->system, msg->msg); - } - break; + switch(msg->type){ + case (IMC::AcousticRequest::TYPE_MSG): + case (IMC::AcousticRequest::TYPE_ABORT): + case (IMC::AcousticRequest::TYPE_RANGE): + case (IMC::AcousticRequest::TYPE_RAW): + addToQueue((const IMC::AcousticRequest*)msg->clone()); + processQueue(); + break; default: - return; + inf("Status of transmission %d changed: AcousticRequest->Type not implemented.", msg->req_id); + break; } - replaceLastOp(msg); } void @@ -364,20 +383,23 @@ namespace Transports break; case CODE_USBL: + std::vector data; + data.push_back(CODE_USBL); if (UsblTools::toNode(msg->data[2])) { if (m_usbl_node != NULL) - m_usbl_node->parse(imc_addr_src, msg); + { + if (m_usbl_node->parse(imc_addr_src, msg, data)) + sendFrame(msg->sys_src, createInternalId(), data, false); + } } else { // handle request to USBL modem. if (m_usbl_modem != NULL) { - std::vector data; - data.push_back(CODE_USBL); - if (m_usbl_modem->parse(msg, data)) - sendFrame(msg->sys_src, data, false); + if (m_usbl_modem->parse(imc_addr_src, msg, data)) + sendFrame(msg->sys_src, createInternalId(), data, false); } } break; @@ -393,111 +415,89 @@ namespace Transports if (msg->getDestinationEntity() != getEntityId()) return; - if (m_last_acop == NULL) + if (m_transmission_requests.find(msg->seq) + == m_transmission_requests.end()) { return; + } + uint16_t idOfMsg = msg->seq; - IMC::AcousticOperation aop(*m_last_acop); + if (m_transmission_requests.find(idOfMsg) == m_transmission_requests.end()) return; - switch(msg->value) - { + const IMC::AcousticRequest* request = m_transmission_requests[idOfMsg]; + + switch (msg->value) { case IMC::UamTxStatus::UTS_BUSY: - aop.op = IMC::AcousticOperation::AOP_BUSY; + sendAcousticStatus(request,IMC::AcousticStatus::STATUS_BUSY,msg->error); + m_msg_send_timer.setTop(2); + m_can_send = true; break; case IMC::UamTxStatus::UTS_INV_ADDR: - aop.op = IMC::AcousticOperation::AOP_UNSUPPORTED; - if (m_last_acop->op == IMC::AcousticOperation::AOP_MSG) - { - delete m_msg_requests.front(); - m_msg_requests.erase(m_msg_requests.begin()); - } + sendAcousticStatus(request,IMC::AcousticStatus::STATUS_UNSUPPORTED,msg->error); + removeFromQueue(idOfMsg); + break; case IMC::UamTxStatus::UTS_DONE: - switch(m_last_acop->op) - { - case IMC::AcousticOperation::AOP_ABORT: - aop.op = IMC::AcousticOperation::AOP_ABORT_ACKED; - break; - case IMC::AcousticOperation::AOP_RANGE: - // do nothing. - return; - break; - case IMC::AcousticOperation::AOP_MSG: - delete m_msg_requests.front(); - m_msg_requests.erase(m_msg_requests.begin()); - aop.op = IMC::AcousticOperation::AOP_MSG_DONE; - break; - } + sendAcousticStatus(request,IMC::AcousticStatus::STATUS_SENT,msg->error); + if(request->type != IMC::AcousticRequest::TYPE_RANGE) + removeFromQueue(idOfMsg); break; case IMC::UamTxStatus::UTS_IP: - switch(m_last_acop->op) - { - case IMC::AcousticOperation::AOP_ABORT: - aop.op = IMC::AcousticOperation::AOP_ABORT_IP; - break; - case IMC::AcousticOperation::AOP_RANGE: - aop.op = IMC::AcousticOperation::AOP_RANGE_IP; - break; - case IMC::AcousticOperation::AOP_MSG: - aop.op = IMC::AcousticOperation::AOP_MSG_IP; - break; - } + sendAcousticStatus(request,IMC::AcousticStatus::STATUS_IN_PROGRESS,msg->error); + break; case IMC::UamTxStatus::UTS_FAILED: - switch(m_last_acop->op) - { - case IMC::AcousticOperation::AOP_ABORT: - aop.op = IMC::AcousticOperation::AOP_ABORT_TIMEOUT; - break; - case IMC::AcousticOperation::AOP_RANGE: - aop.op = IMC::AcousticOperation::AOP_RANGE_TIMEOUT; - break; - case IMC::AcousticOperation::AOP_MSG: - delete m_msg_requests.front(); - m_msg_requests.erase(m_msg_requests.begin()); - aop.op = IMC::AcousticOperation::AOP_MSG_FAILURE; - break; - } + sendAcousticStatus(request,IMC::AcousticStatus::STATUS_ERROR,msg->error); + removeFromQueue(idOfMsg); + break; - } - dispatch(aop); + default: + break; - // If idle send pending messages. - if (msg->value != IMC::UamTxStatus::UTS_IP && !m_msg_requests.empty()) - { - // wait (for clearing buffers) and send next message - m_msg_send_timer.setTop(2); - m_msg_send_timer.reset(); - m_send_next = true; } } void consume(const IMC::UamRxRange* msg) { - if (m_last_acop == NULL) + if (m_transmission_requests.find(msg->seq) + == m_transmission_requests.end()) { return; + } + uint16_t idOfMsg = msg->seq; - if (m_last_acop->op == IMC::AcousticOperation::AOP_RANGE) - { - IMC::AcousticOperation aop(*m_last_acop); - aop.op = IMC::AcousticOperation::AOP_RANGE_RECVED; - aop.range = msg->value; - dispatch(aop); + const IMC::AcousticRequest* request = m_transmission_requests[idOfMsg]; + + if(request->type != IMC::AcousticRequest::TYPE_RANGE){ + return; + } + + if(request->destination != msg->sys){ + return; } + + sendAcousticStatus(request,IMC::AcousticStatus::STATUS_RANGE_RECEIVED,"",msg->value); + removeFromQueue(idOfMsg); } void consume(const IMC::UsblPositionExtended* msg) { + debug("Received USBL position for %s.", msg->target.c_str()); + + // always dispatch UsblFixExtended. + IMC::UsblFixExtended fix = UsblTools::toFix(*msg, m_estate); + dispatch(fix); + debug("Generated USBL fix to %s.", fix.target.c_str()); + if (m_usbl_modem == NULL) { announceUSBL(); - m_usbl_modem = new UsblTools::Modem(); + m_usbl_modem = new UsblTools::Modem(this); return; } @@ -508,28 +508,39 @@ namespace Transports std::vector data; data.push_back(CODE_USBL); + // Inverted mode + if(m_usbl_modem->isInverted(msg->target, data)) + { + m_usbl_modem->consume(msg); + + if (m_usbl_modem->invertedFix(msg->target, fix)) + dispatch(fix); + + return; + } + // The target wants an absolute fix? if (m_usbl_modem->wantsFix(msg->target)) { - // transform data. - IMC::UsblFixExtended fix = UsblTools::toFix(*msg, m_estate); if (m_usbl_modem->encode(&fix, data)) - sendFrame(msg->target, data, false); + sendFrame(msg->target, createInternalId(), data, false); } else { if (m_usbl_modem->encode(msg, data)) - sendFrame(msg->target, data, false); + sendFrame(msg->target, createInternalId(), data, false); } } void consume(const IMC::UsblAnglesExtended* msg) { + debug("Received USBL angles to %s.", msg->target.c_str()); + if (m_usbl_modem == NULL) { announceUSBL(); - m_usbl_modem = new UsblTools::Modem(); + m_usbl_modem = new UsblTools::Modem(this); return; } @@ -539,8 +550,12 @@ namespace Transports std::vector data; data.push_back(CODE_USBL); + + if(m_usbl_modem->isInverted(msg->target, data)) + return; + if (m_usbl_modem->encode(msg, data)) - sendFrame(msg->target, data, false); + sendFrame(msg->target, createInternalId(), data, false); } void @@ -557,40 +572,95 @@ namespace Transports m_reporter->consume(msg); } + void + sendAcousticStatus(const AcousticRequest* acReq, IMC::AcousticStatus::StatusEnum status, + const std::string& info = "", const fp32_t range = 0.0) { + IMC::AcousticStatus acStat; + + acStat.req_id = acReq->req_id; + acStat.type = acReq->type; + acStat.status = status; + acStat.range = range; + acStat.info = info; + acStat.setDestination(acReq->getSource()); + acStat.setDestinationEntity(acReq->getSourceEntity()); + + dispatch(acStat); + } + + uint16_t + createInternalId(){ + if(m_reqid==0xFFFF){ + m_reqid=0; + } + else{ + m_reqid++; + } + return m_reqid; + } + + //! Add message to the end of queue + void + addToQueue(const IMC::AcousticRequest* msg) + { + m_transmission_requests[createInternalId()] = msg->clone(); + } + + //! Remove message from the queue. Resets timer. And unlocks the queue + void + removeFromQueue(uint16_t index) + { + delete m_transmission_requests.find(index)->second; + m_transmission_requests.erase(index); + m_msg_send_timer.setTop(2); + m_can_send = true; + } + //! Announce USBL service. void announceUSBL(void) { IMC::AnnounceService announce; announce.service = std::string("imc+any://acoustic/usbl/") - + URL::encode(getEntityLabel()); + + URL::encode(getEntityLabel()); dispatch(announce); } - //! Clear last operation. void - clearLastOp(void) + sendReport(void) { - Memory::clear(m_last_acop); - } + double lat = 0; + double lon = 0; + Coordinates::toWGS84(m_estate, lat, lon); + + Report dat; + dat.lat = lat; + dat.lon = lon; + dat.depth = (uint8_t)m_estate.depth; + dat.yaw = (int16_t)(m_estate.psi * 100.0); + dat.alt = (int16_t)(m_estate.alt * 10.0); + dat.fuel_level = (uint8_t)m_fuel_level; + dat.fuel_conf = (uint8_t)m_fuel_conf; + dat.progress = (int8_t)m_progress; - void - sendFrame(const std::string& sys, Codes code, bool ack) - { std::vector data; - data.push_back(code); - sendFrame(sys, data, ack); + data.resize(sizeof(dat) + 1); + data[0] = CODE_REPORT; + std::memcpy(&data[1], &dat, sizeof(dat)); + sendFrame("broadcast", createInternalId(), data, false); } void - sendFrame(const std::string& sys, const std::vector& data, bool ack) + sendFrame(const std::string& sys, const uint16_t id, const std::vector& data, bool ack) { Algorithms::CRC8 crc(c_poly); IMC::UamTxFrame frame; + frame.setSource(getSystemId()); + frame.setSourceEntity(getEntityId()); frame.setDestination(getSystemId()); frame.sys_dst = sys; - frame.seq = m_seq++; + frame.seq = id; frame.flags = ack ? IMC::UamTxFrame::UTF_ACK : 0; frame.data.push_back(c_sync); @@ -606,59 +676,43 @@ namespace Transports } void - replaceLastOp(const IMC::AcousticOperation* msg) - { - clearLastOp(); - m_last_acop = static_cast(msg->clone()); - m_last_acop->setDestination(m_last_acop->getSource()); - m_last_acop->setDestinationEntity(m_last_acop->getSourceEntity()); - m_last_acop->setSource(getSystemId()); - m_last_acop->setSourceEntity(getEntityId()); - } - - void - sendAbort(const std::string& sys) - { - sendFrame(sys, CODE_ABORT, true); - } - - void - recvAbort(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) + sendFrameRaw(const std::string& sys, const uint16_t id, const std::vector& data, bool ack) { - (void)msg; + IMC::UamTxFrame frame; + frame.setSource(getSystemId()); + frame.setSourceEntity(getEntityId()); + frame.setDestination(getSystemId()); + frame.sys_dst = sys; + frame.seq = id; + frame.flags = ack ? IMC::UamTxFrame::UTF_ACK : 0; - // ignore aborts addressed to other systems - if (imc_dst != getSystemId()) + for (size_t i = 0; i < data.size(); ++i) { - inf(DTR("ignoring abort message addressed to other system")); - return; + frame.data.push_back(data[i]); } - war(DTR("got abort request")); - - IMC::Abort abort; - abort.setSource(imc_src); - abort.setDestination(imc_dst); - dispatch(abort); + dispatch(frame); } void - sendRange(const std::string& sys) + sendAbort(const std::string& sys, const uint16_t id) { - spew("sending range to %s", sys.c_str()); - sendFrame(sys, CODE_RANGE, true); + std::vector data; + data.push_back(CODE_ABORT); + sendFrame(sys, id, data, true); } void - recvRange(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) + sendRange(const std::string& sys, const uint16_t id) { - (void)imc_src; - (void)imc_dst; - (void)msg; + spew("sending range to %s", sys.c_str()); + std::vector data; + data.push_back(CODE_RANGE); + sendFrame(sys, id, data, true); } void - sendMessage(const std::string& sys, const InlineMessage& imsg) + sendMessage(const std::string& sys, const uint16_t id, const InlineMessage& imsg) { const IMC::Message* msg = NULL; @@ -677,66 +731,78 @@ namespace Transports const IMC::PlanControl * pc = static_cast(msg); if (pc->arg.isNull()) { - sendPlanControl(sys, static_cast(msg)); + sendPlanControl(sys, id, static_cast(msg)); return; } } // For all other cases, send the raw message across - sendRawMessage(sys, msg); - } - - void - recvMessage(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) - { - debug("Parsing message received via acoustic message."); - - try - { - uint16_t msg_type; - std::memcpy(&msg_type, &msg->data[2], sizeof(uint16_t)); - Message *m = IMC::Factory::produce(msg_type); - if (m == NULL) - { - err("Invalid message type received: %d", msg_type); - return; - } - - m->setSource(imc_src); - m->setDestination(imc_dst); - m->setTimeStamp(msg->getTimeStamp()); - m->deserializeFields((const unsigned char *)&msg->data[4], msg->data.size()-4); - dispatch(m, DF_KEEP_TIME | DF_LOOP_BACK); - debug("Acoustic message successfully parsed as '%s'.", m->getName()); - } - catch (std::exception& ex) { - err("Error parsing raw message from UAM frame: %s.", ex.what()); - } + sendRawMessage(sys, id, msg); } void - sendRawMessage(const std::string& sys, const IMC::Message * msg) + sendRawMessage(const std::string& sys, const uint16_t id, const IMC::Message * msg) { std::vector data; data.push_back(CODE_RAW); + inf("Send message of type %s, with serialization size %d.", msg->getName(), msg->getSerializationSize()); + // leave 1 byte for CODE_RAW and another for CRC8 - uint8_t buf[1022]; + uint8_t buf[2500]; // start with message id - uint16_t id = msg->getId(); - std::memcpy(&buf[0], &id, sizeof(uint16_t)); + uint16_t id2 = msg->getId(); + std::memcpy(&buf[0], &id2, sizeof(uint16_t)); // followed by all message fields - uint8_t* end = msg->serializeFields(&buf[2]); + msg->serializeFields(&buf[2]); - int length = end - buf; + int length = msg->getSerializationSize() + 2; data.insert(data.end(), buf, buf + length); - sendFrame(sys, data, true); + sendFrame(sys, id, data, true); + } + + void + sendRaw(const IMC::AcousticRequest& req, const std::string& sys, const uint16_t id, const InlineMessage& imsg) + { + const IMC::Message* msg = NULL; + + try + { + msg = imsg.get(); + } + catch (...) + { + sendAcousticStatus(&req, IMC::AcousticStatus::STATUS_INPUT_FAILURE, "Null pointer."); + removeFromQueue(req.req_id); + return; + } + + // Check if is DevDataBinary... + if (msg->getId() == IMC::DevDataBinary::getIdStatic()) + { + const IMC::DevDataBinary * ddb = static_cast(msg); + if (ddb->value.size() > 0) + { + std::vector data; + // no coding, send as is + for (size_t i = 0; i < ddb->value.size(); ++i) + { + data.push_back(ddb->value[i]); + } + + sendFrameRaw(sys, id, data, true); + return; + } + } + + sendAcousticStatus(&req, IMC::AcousticStatus::STATUS_UNSUPPORTED, "Unsupported type for raw send."); + removeFromQueue(req.req_id); } void - sendPlanControl(const std::string& sys, const IMC::PlanControl* msg) + sendPlanControl(const std::string& sys, const uint16_t id, const IMC::PlanControl* msg) { if (msg->type != IMC::PlanControl::PC_REQUEST) return; @@ -748,70 +814,98 @@ namespace Transports data.push_back(CODE_PLAN); for (size_t i = 0; i < msg->plan_id.size(); ++i) data.push_back((uint8_t)msg->plan_id[i]); - sendFrame(sys, data, true); + sendFrame(sys, id, data, true); } void - recvPlanControl(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) + recvAbort(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) { - IMC::OperationalLimits ol; - ol.setDestination(imc_dst); - ol.setSource(imc_src); - ol.mask = 0; - dispatch(ol); + (void)msg; - Delay::wait(1.0); + // ignore aborts addressed to other systems + if (imc_dst != getSystemId()) + { + inf(DTR("ignoring abort message addressed to other system")); + return; + } - IMC::PlanControl pc; - pc.setSource(imc_src); - pc.type = IMC::PlanControl::PC_REQUEST; - pc.op = IMC::PlanControl::PC_START; - pc.plan_id.assign(&msg->data[2], msg->data.size() - 3); - pc.flags = IMC::PlanControl::FLG_IGNORE_ERRORS; - dispatch(pc); + war(DTR("got abort request")); - war(DTR("start plan detected")); + IMC::Abort abort; + abort.setSource(imc_src); + abort.setDestination(imc_dst); + dispatch(abort); } void - sendRestartSystem(const std::string& sys, const IMC::RestartSystem* msg) + recvRange(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) { + (void)imc_src; + (void)imc_dst; (void)msg; - sendFrame(sys, CODE_RESTART, true); } void - recvRestartSystem(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) + recvMessage(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) { - (void)msg; - IMC::RestartSystem restart; - restart.setSource(imc_src); - restart.setDestination(imc_dst); - dispatch(restart); + debug("Parsing message received via acoustic message."); + + try + { + uint16_t msg_type; + std::memcpy(&msg_type, &msg->data[2], sizeof(uint16_t)); + Message *m = IMC::Factory::produce(msg_type); + if (m == NULL) + { + err("Invalid message type received: %d", msg_type); + return; + } + + m->setSource(imc_src); + m->setDestination(imc_dst); + m->setTimeStamp(msg->getTimeStamp()); + m->deserializeFields((const unsigned char *)&msg->data[4], msg->data.size()-4); + + // mark the message's origin as acoustic if it is an acoustic command + if (m->getId() == IMC::TextMessage::getIdStatic()) + { + IMC::TextMessage* txtmsg = static_cast(m); + std::stringstream ss; + ss << "acoustic/" << msg->sys_src; + txtmsg->origin = ss.str(); + } + + dispatch(m, DF_KEEP_TIME | DF_LOOP_BACK); + debug("Acoustic message successfully parsed as '%s'.", m->getName()); + } + catch (std::exception& ex) { + err("Error parsing raw message from UAM frame: %s.", ex.what()); + } } void - sendReport(void) + recvPlanControl(uint16_t imc_src, uint16_t imc_dst, const IMC::UamRxFrame* msg) { - double lat = 0; - double lon = 0; - Coordinates::toWGS84(m_estate, lat, lon); + IMC::OperationalLimits ol; + ol.setSource(imc_src); + ol.setDestination(imc_dst); + ol.mask = 0; + dispatch(ol); - Report dat; - dat.lat = lat; - dat.lon = lon; - dat.depth = (uint8_t)m_estate.depth; - dat.yaw = (int16_t)(m_estate.psi * 100.0); - dat.alt = (int16_t)(m_estate.alt * 10.0); - dat.fuel_level = (uint8_t)m_fuel_level; - dat.fuel_conf = (uint8_t)m_fuel_conf; - dat.progress = (int8_t)m_progress; + Delay::wait(1.0); - std::vector data; - data.resize(sizeof(dat) + 1); - data[0] = CODE_REPORT; - std::memcpy(&data[1], &dat, sizeof(dat)); - sendFrame("broadcast", data, false); + IMC::PlanControl pc; + pc.setSource(imc_src); + pc.setDestination(imc_dst); + pc.type = IMC::PlanControl::PC_REQUEST; + pc.op = IMC::PlanControl::PC_START; + pc.plan_id.assign(&msg->data[2], msg->data.size() - 3); + pc.flags = IMC::PlanControl::FLG_IGNORE_ERRORS; + dispatch(pc); + + war(DTR("start plan detected with id: %s for 0x%02X"), + pc.plan_id.c_str(), + pc.getDestination() & 0xFFFF); } void @@ -847,12 +941,16 @@ namespace Transports void onUsblModem(void) { - if (m_usbl_modem != NULL) + // Trigger target. + std::string sys; + if (m_usbl_modem->run(sys, m_args.usbl_max_wait)) { - // Trigger target. - std::string sys; - if (m_usbl_modem->run(sys, m_args.usbl_max_wait)) - sendRange(sys); + std::vector data; + data.push_back(CODE_USBL); + if (m_usbl_modem->isInverted(sys, data)) + sendFrame(sys, createInternalId(), data, true); + else + sendRange(sys,createInternalId()); } } @@ -860,12 +958,62 @@ namespace Transports void onUsblNode(void) { - if (m_usbl_node != NULL) + std::vector data; + data.push_back(CODE_USBL); + if (m_usbl_node->run(data)) + sendFrame("broadcast", createInternalId(), data, false); + } + + void + clearTimeouts() + { + std::map::iterator it; + it = m_transmission_requests.begin(); + + while (it != m_transmission_requests.end()) { - std::vector data; - data.push_back(CODE_USBL); - if (m_usbl_node->run(data)) - sendFrame("broadcast", data, false); + if (it->second->getTimeStamp() + it->second->timeout <= Clock::getSinceEpoch()) + { + sendAcousticStatus(it->second,IMC::AcousticStatus::STATUS_INPUT_FAILURE,"Transmission timed out."); + Memory::clear(it->second); + m_transmission_requests.erase(it++); + m_can_send = true; + } + else + ++it; + } + } + + void + processQueue(void) + { + if (m_can_send && !m_transmission_requests.empty()) + { + m_can_send = false; + const IMC::AcousticRequest* req = m_transmission_requests.begin()->second; + uint16_t id = m_transmission_requests.begin()->first; + + switch (req->type) + { + case (IMC::AcousticRequest::TYPE_ABORT): + sendAbort(req->destination,id); + break; + + case (IMC::AcousticRequest::TYPE_RANGE): + sendRange(req->destination,id); + break; + + case (IMC::AcousticRequest::TYPE_MSG): + sendMessage(req->destination, id, req->msg); + break; + + case (IMC::AcousticRequest::TYPE_RAW): + sendRaw(*req, req->destination, id, req->msg); + break; + + default: + break; + } } } @@ -877,21 +1025,15 @@ namespace Transports { waitForMessages(1.0); - onUsblModem(); - onUsblNode(); - - if (m_args.report_enable) - { + if (m_usbl_modem != NULL) onUsblModem(); + if (m_usbl_node != NULL) onUsblNode(); + if (m_args.report_enable) { if (m_reporter != NULL && m_reporter->trigger()) sendReport(); } - - if (m_send_next && m_msg_send_timer.overflow()) - { - m_send_next = false; - const IMC::AcousticOperation * req = m_msg_requests.at(0); - replaceLastOp(req); - sendMessage(req->system, req->msg); + if(m_msg_send_timer.overflow()){ + clearTimeouts(); + processQueue(); } } } diff --git a/src/Transports/UDP/Contact.hpp b/src/Transports/UDP/Contact.hpp index de3c4eb4e6..5d4ad5af5b 100644 --- a/src/Transports/UDP/Contact.hpp +++ b/src/Transports/UDP/Contact.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/UDP/ContactTable.hpp b/src/Transports/UDP/ContactTable.hpp index 6d719d708f..eda159dc29 100644 --- a/src/Transports/UDP/ContactTable.hpp +++ b/src/Transports/UDP/ContactTable.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/UDP/LimitedComms.hpp b/src/Transports/UDP/LimitedComms.hpp index eb2219a5fc..01709f67d0 100644 --- a/src/Transports/UDP/LimitedComms.hpp +++ b/src/Transports/UDP/LimitedComms.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/UDP/Listener.hpp b/src/Transports/UDP/Listener.hpp index aaec6f9ba6..7fc18cbb10 100644 --- a/src/Transports/UDP/Listener.hpp +++ b/src/Transports/UDP/Listener.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/UDP/Node.hpp b/src/Transports/UDP/Node.hpp index 08261c5b5b..d8493fca51 100644 --- a/src/Transports/UDP/Node.hpp +++ b/src/Transports/UDP/Node.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -100,7 +100,7 @@ namespace Transports std::map::iterator itr; itr = m_addrs.find(addr); - return (itr != m_addrs.end() && itr->second != port); + return (itr != m_addrs.end() && itr->second == port); } //! Point active address to existing node service. diff --git a/src/Transports/UDP/NodeAddress.hpp b/src/Transports/UDP/NodeAddress.hpp index e186b2e0c6..3059ba0fd7 100644 --- a/src/Transports/UDP/NodeAddress.hpp +++ b/src/Transports/UDP/NodeAddress.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/UDP/NodeTable.hpp b/src/Transports/UDP/NodeTable.hpp index df3ea27bb9..84a342b1cd 100644 --- a/src/Transports/UDP/NodeTable.hpp +++ b/src/Transports/UDP/NodeTable.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Transports/UDP/Task.cpp b/src/Transports/UDP/Task.cpp index 496107e09d..86b0fd331a 100644 --- a/src/Transports/UDP/Task.cpp +++ b/src/Transports/UDP/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -82,6 +82,8 @@ namespace Transports bool dynamic_nodes; // Only transmit messages from local system bool only_local; + // Optional custom service type + std::string custom_service; }; // Internal buffer size. @@ -178,6 +180,10 @@ namespace Transports .defaultValue("false") .description("Only transmit messsages from local system."); + param("Custom Service Type", m_args.custom_service) + .defaultValue("") + .description("Optional custom service type (imc+udp+), empty entry gives default service (imc+udp)"); + // Allocate space for internal buffer. m_bfr = new uint8_t[c_bfr_size]; @@ -223,14 +229,14 @@ namespace Transports debug("limited communications simulation is not active"); m_comm_limitations = false; } - - // Register normal messages. - bind(this, m_args.messages); } void onResourceAcquisition(void) { + // Register normal messages. + bind(this, m_args.messages); + // Find a free port. unsigned port_limit = m_args.port + c_port_retries; while (m_args.port != port_limit) @@ -261,7 +267,17 @@ namespace Transports for (unsigned i = 0; i < itfs.size(); ++i) { std::stringstream os; - os << "imc+udp://" << itfs[i].address().str() << ":" << m_args.port + std::string service = "imc+udp"; + + // if custom service type is enabled + if (m_args.custom_service != "") + { + std::stringstream cs; + cs << service << "+" << m_args.custom_service; + service = cs.str(); + } + + os << service << "://" << itfs[i].address().str() << ":" << m_args.port << "/"; IMC::AnnounceService announce; @@ -323,7 +339,16 @@ namespace Transports if (m_args.trace_out) msg->toText(std::cerr); - uint16_t rv = IMC::Packet::serialize(msg, m_bfr, c_bfr_size); + uint16_t rv; + try + { + rv = IMC::Packet::serialize(msg, m_bfr, c_bfr_size); + } + catch(const std::exception& e) + { + war(DTR("failed to serialize message %s to send to %u: %s"), msg->getName(), m_args.port, e.what()); + return; + } // Send to static nodes. std::set::iterator itr = m_static_dsts.begin(); diff --git a/src/UserInterfaces/Buttons/Task.cpp b/src/UserInterfaces/Buttons/Task.cpp index 98803fb030..a8e0728371 100644 --- a/src/UserInterfaces/Buttons/Task.cpp +++ b/src/UserInterfaces/Buttons/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/LCD/Task.cpp b/src/UserInterfaces/LCD/Task.cpp index 3c2f1e58a4..1e92683400 100644 --- a/src/UserInterfaces/LCD/Task.cpp +++ b/src/UserInterfaces/LCD/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/LEDs/AbstractOutput.hpp b/src/UserInterfaces/LEDs/AbstractOutput.hpp index 93f77f5948..1743bfb6ef 100644 --- a/src/UserInterfaces/LEDs/AbstractOutput.hpp +++ b/src/UserInterfaces/LEDs/AbstractOutput.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/LEDs/Emulator.hpp b/src/UserInterfaces/LEDs/Emulator.hpp index 9caae0be60..dd6b578dc1 100644 --- a/src/UserInterfaces/LEDs/Emulator.hpp +++ b/src/UserInterfaces/LEDs/Emulator.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/LEDs/GPIO.hpp b/src/UserInterfaces/LEDs/GPIO.hpp index 9ac12e640e..ee7bda34b5 100644 --- a/src/UserInterfaces/LEDs/GPIO.hpp +++ b/src/UserInterfaces/LEDs/GPIO.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/LEDs/Message.hpp b/src/UserInterfaces/LEDs/Message.hpp index 6f2d57c73f..83beedf7ef 100644 --- a/src/UserInterfaces/LEDs/Message.hpp +++ b/src/UserInterfaces/LEDs/Message.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/LEDs/ParallelPort.hpp b/src/UserInterfaces/LEDs/ParallelPort.hpp index acdca952f5..f38681f6c5 100644 --- a/src/UserInterfaces/LEDs/ParallelPort.hpp +++ b/src/UserInterfaces/LEDs/ParallelPort.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/LEDs/Task.cpp b/src/UserInterfaces/LEDs/Task.cpp index 58b130e3a6..930ade5532 100644 --- a/src/UserInterfaces/LEDs/Task.cpp +++ b/src/UserInterfaces/LEDs/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/MantaPanel/Command.hpp b/src/UserInterfaces/MantaPanel/Command.hpp index b7e0c463b7..96f5e4a2bb 100644 --- a/src/UserInterfaces/MantaPanel/Command.hpp +++ b/src/UserInterfaces/MantaPanel/Command.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/UserInterfaces/MantaPanel/Task.cpp b/src/UserInterfaces/MantaPanel/Task.cpp index 55942dcbd2..ece01aa1c2 100644 --- a/src/UserInterfaces/MantaPanel/Task.cpp +++ b/src/UserInterfaces/MantaPanel/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -83,6 +83,8 @@ namespace UserInterfaces std::vector sys_addr_sections; //! Set of excluded systems. std::vector sys_exclude; + //! Reply to AcousticSystemsQuery requests + bool reply_asq; }; struct Task: public Tasks::Task @@ -107,8 +109,12 @@ namespace UserInterfaces Command* m_cmd; //! Time of last acoustic operation dispatch. double m_last_acop; + //! Sequence number. + uint16_t m_reqid; //! Progress bar. unsigned m_prog_bar; + //! Supported umodem system names. + std::set m_addrs_umodem; Task(const std::string& name, Tasks::Context& ctx): Tasks::Task(name, ctx), @@ -117,6 +123,7 @@ namespace UserInterfaces m_power_down_now(false), m_cmd(0), m_last_acop(-1.0), + m_reqid(0), m_prog_bar(0) { // Define configuration parameters. @@ -164,11 +171,15 @@ namespace UserInterfaces .defaultValue("broadcast") .description("List of excluded systems"); + param("Reply to System Queries", m_args.reply_asq) + .defaultValue("false"); + // Register listeners. bind(this); bind(this); bind(this); bind(this); + bind(this); bind(this); } @@ -183,11 +194,21 @@ namespace UserInterfaces { std::vector addrs = m_ctx.config.options(m_args.sys_addr_sections[i]); m_sys.insert(addrs.begin(), addrs.end()); + + if(!strcmp(m_args.sys_addr_sections[i].c_str(), "Micromodem Addresses") || + !strcmp(m_args.sys_addr_sections[i].c_str(), "Micromodem Addresses - DMSMW")) + m_addrs_umodem.insert(addrs.begin(), addrs.end()); } + } else { m_sys.insert(m_args.systems.begin(), m_args.systems.end()); + + std::vector addrs = m_ctx.config.options("Micromodem Addresses"); + m_addrs_umodem.insert(addrs.begin(), addrs.end()); + std::vector addrs_dmsmw = m_ctx.config.options("Micromodem Addresses - DMSMW"); + m_addrs_umodem.insert(addrs_dmsmw.begin(), addrs_dmsmw.end()); } // Remove our name from the list. @@ -250,33 +271,79 @@ namespace UserInterfaces void requestAbort(const std::string& sys) { - IMC::AcousticOperation acop; - acop.setDestination(getSystemId()); - acop.system = sys; - acop.op = IMC::AcousticOperation::AOP_ABORT; - dispatch(&acop, DF_LOOP_BACK); + if(m_addrs_umodem.find(sys) != m_addrs_umodem.end()) + { + IMC::AcousticOperation acop; + acop.setDestination(getSystemId()); + acop.system = sys; + acop.op = IMC::AcousticOperation::AOP_ABORT; + dispatch(&acop, DF_LOOP_BACK); + } + else + { + sendMessage(sys, IMC::TransmissionRequest::DMODE_ABORT); + abortSystem(sys); + } } void requestPing(const std::string& sys) { - IMC::AcousticOperation acop; - acop.setDestination(getSystemId()); - acop.system = sys; - acop.op = IMC::AcousticOperation::AOP_RANGE; - dispatch(&acop, DF_LOOP_BACK); + if(m_addrs_umodem.find(sys) != m_addrs_umodem.end()) + { + IMC::AcousticOperation acop; + acop.setDestination(getSystemId()); + acop.system = sys; + acop.op = IMC::AcousticOperation::AOP_RANGE; + dispatch(&acop, DF_LOOP_BACK); + } + else + { + sendMessage(sys, IMC::TransmissionRequest::DMODE_RANGE); + pingSystem(sys); + } + } + + void + sendMessage(const std::string& sys, int code){ + IMC::TransmissionRequest tr; + tr.setDestination(getSystemId()); + tr.destination = sys; + tr.deadline = Time::Clock::getSinceEpoch() + 10; + tr.req_id = createInternalId(); + tr.comm_mean = IMC::TransmissionRequest::CMEAN_ACOUSTIC; + tr.data_mode = code; + + dispatch(&tr, DF_LOOP_BACK); + + } + + uint16_t + createInternalId(){ + if(m_reqid==0xFFFF){ + m_reqid=0; + } + else{ + m_reqid++; + } + return m_reqid; } + void consume(const IMC::Abort* msg) { + if (msg->getDestination() == getSystemId()) + return; + requestAbort(resolveSystemId(msg->getDestination())); } void consume(const IMC::AcousticSystemsQuery* msg) { - dispatchReply(*msg, m_acoustic_systems); + if (m_args.reply_asq) + dispatchReply(*msg, m_acoustic_systems); } void @@ -320,6 +387,60 @@ namespace UserInterfaces } } + void + consume(const IMC::TransmissionStatus* msg) + { + + if(msg->getDestination() != getSystemId()) return; + if(msg->getDestinationEntity() != getEntityId()) return; + + m_lcd.op = IMC::LcdControl::OP_WRITE1; + + switch (msg->status) + { + case IMC::TransmissionStatus::TSTAT_TEMPORARY_FAILURE: + + if (m_mode == MODE_SYS_PING || m_mode == MODE_SYS_ABORT) + return; + + m_lcd.text = fill("Temp. Failure"); + reset(); + break; + + case IMC::TransmissionStatus::TSTAT_RANGE_RECEIVED: + m_lcd.text = fill(String::str("Range %0.1fm", msg->range)); + reset(); + break; + + case IMC::TransmissionStatus::TSTAT_SENT: + if (m_mode == MODE_SYS_ABORT) + { + m_lcd.text = fill("Aborted!"); + reset(); + } + else if (m_mode == MODE_SYS_PING) + { + m_lcd.text = fill("Pinged..."); + } + break; + + case IMC::TransmissionStatus::TSTAT_INPUT_FAILURE: + m_lcd.text = fill("Timeout/Failure"); + reset(); + break; + + case IMC::TransmissionStatus::TSTAT_PERMANENT_FAILURE: + m_lcd.text = fill("Permanent Failure"); + reset(); + break; + + default: + return; + } + + dispatch(m_lcd); + } + void consume(const IMC::AcousticOperation* msg) { diff --git a/src/Vision/DFK51BG02H/AutoExposure.hpp b/src/Vision/DFK51BG02H/AutoExposure.hpp index 8fdd58c862..97e38c6922 100644 --- a/src/Vision/DFK51BG02H/AutoExposure.hpp +++ b/src/Vision/DFK51BG02H/AutoExposure.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/DFK51BG02H/Frame.hpp b/src/Vision/DFK51BG02H/Frame.hpp index 6aa1c790b0..73009a486b 100644 --- a/src/Vision/DFK51BG02H/Frame.hpp +++ b/src/Vision/DFK51BG02H/Frame.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/DFK51BG02H/GVCP.hpp b/src/Vision/DFK51BG02H/GVCP.hpp index c3bd09572b..bf23db6ccd 100644 --- a/src/Vision/DFK51BG02H/GVCP.hpp +++ b/src/Vision/DFK51BG02H/GVCP.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/DFK51BG02H/GVSP.hpp b/src/Vision/DFK51BG02H/GVSP.hpp index ea321222c2..f23728baa2 100644 --- a/src/Vision/DFK51BG02H/GVSP.hpp +++ b/src/Vision/DFK51BG02H/GVSP.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/DFK51BG02H/Task.cpp b/src/Vision/DFK51BG02H/Task.cpp index 322c654e8d..d8935f8d76 100644 --- a/src/Vision/DFK51BG02H/Task.cpp +++ b/src/Vision/DFK51BG02H/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/DFK51BG02H/WhiteBalance.hpp b/src/Vision/DFK51BG02H/WhiteBalance.hpp index 9be88b21f4..00727cb55f 100644 --- a/src/Vision/DFK51BG02H/WhiteBalance.hpp +++ b/src/Vision/DFK51BG02H/WhiteBalance.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/FrameGrabber/Task.cpp b/src/Vision/FrameGrabber/Task.cpp index a7e06151e2..d015449de1 100644 --- a/src/Vision/FrameGrabber/Task.cpp +++ b/src/Vision/FrameGrabber/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/Lumenera/EntityActivation.hpp b/src/Vision/Lumenera/EntityActivation.hpp index 0a3d23a8e3..f524204f5b 100644 --- a/src/Vision/Lumenera/EntityActivation.hpp +++ b/src/Vision/Lumenera/EntityActivation.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/Lumenera/EntityActivationMaster.hpp b/src/Vision/Lumenera/EntityActivationMaster.hpp index da6cf81738..9b900d696e 100644 --- a/src/Vision/Lumenera/EntityActivationMaster.hpp +++ b/src/Vision/Lumenera/EntityActivationMaster.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -170,7 +170,7 @@ namespace Vision continue; } - itr->entityActivationUpdate((const IMC::EntityActivationState::StateEnum)(msg->state)); + itr->entityActivationUpdate(static_cast(msg->state)); break; } } diff --git a/src/Vision/Lumenera/HTTPClient.hpp b/src/Vision/Lumenera/HTTPClient.hpp index 65678cd0c9..050ff28eb2 100644 --- a/src/Vision/Lumenera/HTTPClient.hpp +++ b/src/Vision/Lumenera/HTTPClient.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/Lumenera/Log.hpp b/src/Vision/Lumenera/Log.hpp index abfe6654e9..18ec96f551 100644 --- a/src/Vision/Lumenera/Log.hpp +++ b/src/Vision/Lumenera/Log.hpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/Lumenera/Task.cpp b/src/Vision/Lumenera/Task.cpp index 0d5366243e..98ed2b2e5d 100644 --- a/src/Vision/Lumenera/Task.cpp +++ b/src/Vision/Lumenera/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/src/Vision/PhotoTrigger/Task.cpp b/src/Vision/PhotoTrigger/Task.cpp index 571fb99895..d148f2ca89 100644 --- a/src/Vision/PhotoTrigger/Task.cpp +++ b/src/Vision/PhotoTrigger/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * @@ -65,6 +65,10 @@ namespace Vision double m_lat; double m_lon; float m_hei; + //! Current attitude + float m_roll; + float m_pitch; + float m_yaw; //! Last picture position double m_prev_lat; double m_prev_lon; @@ -80,6 +84,9 @@ namespace Vision m_lat(0), m_lon(0), m_hei(0), + m_roll(0), + m_pitch(0), + m_yaw(0), m_prev_lat(0), m_prev_lon(0), m_prev_hei(0), @@ -134,6 +141,10 @@ namespace Vision if (e_state->getSource() != getSystemId()) return; + m_roll = e_state->phi; + m_pitch = e_state->theta; + m_yaw = e_state->psi; + Coordinates::toWGS84(*e_state, m_lat, m_lon, m_hei); if(!m_args.dist_trigger) @@ -163,7 +174,7 @@ namespace Vision log_entry.type = IMC::LogBookEntry::LBET_INFO; log_entry.context = "Photo Trigger"; std::ostringstream ss; - ss << m_lat << ", " << m_lon << ", " << m_hei; + ss << m_lat << ", " << m_lon << ", " << m_hei << ", " << m_roll << ", " << m_pitch << ", " << m_yaw; log_entry.text = ss.str(); Delay::wait(0.2); pcc.op = IMC::PowerChannelControl::PCC_OP_TURN_OFF; diff --git a/src/Vision/PointGrey/SaveImage.hpp b/src/Vision/PointGrey/SaveImage.hpp new file mode 100644 index 0000000000..670be9ffa1 --- /dev/null +++ b/src/Vision/PointGrey/SaveImage.hpp @@ -0,0 +1,358 @@ +/* + * SavImage.hpp + * + * Created on: May 8, 2017 + * Author: Pedro Gonçalves + */ + +#ifndef VISION_POINTGREY_SAVEIMAGE_HPP_INCLUDED_ +#define VISION_POINTGREY_SAVEIMAGE_HPP_INCLUDED_ + +// DUNE headers. +#include + +// Import namespaces. +using DUNE_NAMESPACES; + +//FlyCapture headers +#include + +//Exiv headers +#include + +//OpenCV headers +#include + +namespace Vision +{ + namespace PointGrey + { + //! Mutex lock/unlock + static Concurrency::Mutex m_mutex; + + class SaveImage : public Concurrency::Thread + { + struct exifData + { + //! + int lat_deg; + //! + int lat_min; + //! + double lat_sec; + //! + int lon_deg; + //! + int lon_min; + //! + double lon_sec; + //! + std::string date_time_original; + //! + std::string date_time_digitized; + //! + std::string make; + //! + std::string model; + //! + std::string lens_make; + //! + std::string lens_model; + //! + std::string copyright; + //! + std::string artist; + //! + std::string notes; + }; + + public: + //! Name of camera + std::string m_name_thread; + //! Constructor. + //! @param[in] task parent task. + //! @param[in] url of ipcam. + //! @param[in] name od ipcam. + SaveImage(DUNE::Tasks::Task* task, std::string name) : + m_task(task) + { + m_name_thread = name; + m_new_image = false; + m_jpeg_params.push_back(CV_IMWRITE_JPEG_QUALITY); + m_jpeg_params.push_back(65); + m_row_bytes = 0; + cv::setNumThreads(1); + m_is_free = true; + } + + //! Destructor. + ~SaveImage(void) + { + } + + //! check state of connection to ipcam + //! @return true if connected to ipcam. + bool + saveNewImage(FlyCapture2::Image rgbImage, std::string fileName) + { + if(rgbImage.GetData() == NULL) + return false; + + if(!m_is_free) + return false; + + m_is_free = false; + + m_path_file_name = fileName; + m_image = rgbImage; + rgbImage.ReleaseBuffer(); + m_new_image = true; + + return true; + } + + bool + writeExifData(std::string image) + { + if(image.empty()) + return false; + + try + { + m_imageTag = Exiv2::ImageFactory::open(image); + } + catch(...) + { + m_task->war("error writing exif data to %s", image.c_str()); + m_imageTag.release(); + return false; + } + + m_imageTag->readMetadata(); + m_exifData = m_imageTag->exifData(); + + m_exifData["Exif.Photo.UserComment"] = m_exif_data.notes.c_str(); + + std::memset(&m_text_exif, '\0', sizeof(m_text_exif)); + std::sprintf(m_text_exif, "%d/1 %d/1 %d/1000000", std::abs(m_exif_data.lat_deg), m_exif_data.lat_min, (int)(m_exif_data.lat_sec * 1E6)); + m_exifData["Exif.GPSInfo.GPSLatitude"] = m_text_exif; + if(m_exif_data.lat_deg >= 0) + m_exifData["Exif.GPSInfo.GPSLatitudeRef"] = "N"; + else + m_exifData["Exif.GPSInfo.GPSLatitudeRef"] = "S"; + + std::memset(&m_text_exif, '\0', sizeof(m_text_exif)); + std::sprintf(m_text_exif, "%d/1 %d/1 %d/1000000", std::abs(m_exif_data.lon_deg), m_exif_data.lon_min, (int)(m_exif_data.lon_sec * 1E6)); + m_exifData["Exif.GPSInfo.GPSLongitude"] = m_text_exif; + if(m_exif_data.lon_deg >= 0) + m_exifData["Exif.GPSInfo.GPSLongitudeRef"] = "E"; + else + m_exifData["Exif.GPSInfo.GPSLongitudeRef"] = "W"; + + m_exifData["Exif.Photo.DateTimeOriginal"] = m_exif_data.date_time_original.c_str(); + m_exifData["Exif.Photo.DateTimeDigitized"] = m_exif_data.date_time_digitized.c_str(); + m_exifData["Exif.Image.Make"] = m_exif_data.make.c_str(); + m_exifData["Exif.Image.Model"] = m_exif_data.model.c_str(); + m_exifData["Exif.Photo.LensMake"] = m_exif_data.lens_make.c_str(); + m_exifData["Exif.Photo.LensModel"] = m_exif_data.lens_model.c_str(); + m_exifData["Exif.Image.Copyright"] = m_exif_data.copyright.c_str(); + m_exifData["Exif.Image.Artist"] = m_exif_data.artist.c_str(); + + m_imageTag->setExifData(m_exifData); + m_imageTag->writeMetadata(); + m_imageTag.release(); + m_exifData.clear(); + + return true; + } + + std::string + getNameError(FlyCapture2::Error error) + { + if(error == FlyCapture2::PGRERROR_UNDEFINED) + return "PGRERROR_UNDEFINED"; + else if(error == FlyCapture2::PGRERROR_OK) + return "PGRERROR_OK"; + else if(error == FlyCapture2::PGRERROR_FAILED) + return "PGRERROR_FAILED"; + else if(error == FlyCapture2::PGRERROR_NOT_IMPLEMENTED) + return "PGRERROR_NOT_IMPLEMENTED"; + else if(error == FlyCapture2::PGRERROR_FAILED_BUS_MASTER_CONNECTION) + return "PGRERROR_FAILED_BUS_MASTER_CONNECTION"; + else if(error == FlyCapture2::PGRERROR_NOT_CONNECTED) + return "PGRERROR_NOT_CONNECTED"; + else if(error == FlyCapture2::PGRERROR_INIT_FAILED) + return "PGRERROR_INIT_FAILED"; + else if(error == FlyCapture2::PGRERROR_NOT_INTITIALIZED) + return "PGRERROR_NOT_INTITIALIZED"; + else if(error == FlyCapture2::PGRERROR_INVALID_PARAMETER) + return "PGRERROR_INVALID_PARAMETER"; + else if(error == FlyCapture2::PGRERROR_INVALID_SETTINGS) + return "PGRERROR_INVALID_SETTINGS"; + else if(error == FlyCapture2::PGRERROR_INVALID_BUS_MANAGER) + return "PGRERROR_INVALID_BUS_MANAGER"; + else if(error == FlyCapture2::PGRERROR_MEMORY_ALLOCATION_FAILED) + return "PGRERROR_MEMORY_ALLOCATION_FAILED"; + else if(error == FlyCapture2::PGRERROR_LOW_LEVEL_FAILURE) + return "PGRERROR_LOW_LEVEL_FAILURE"; + else if(error == FlyCapture2::PGRERROR_NOT_FOUND) + return "PGRERROR_NOT_FOUND"; + else if(error == FlyCapture2::PGRERROR_FAILED_GUID) + return "PGRERROR_FAILED_GUID"; + else if(error == FlyCapture2::PGRERROR_INVALID_PACKET_SIZE) + return "PGRERROR_INVALID_PACKET_SIZE"; + else if(error == FlyCapture2::PGRERROR_INVALID_MODE) + return "PGRERROR_INVALID_MODE"; + else if(error == FlyCapture2::PGRERROR_NOT_IN_FORMAT7) + return "PGRERROR_NOT_IN_FORMAT7"; + else if(error == FlyCapture2::PGRERROR_NOT_SUPPORTED) + return "PGRERROR_NOT_SUPPORTED"; + else if(error == FlyCapture2::PGRERROR_TIMEOUT) + return "PGRERROR_TIMEOUT"; + else if(error == FlyCapture2::PGRERROR_BUS_MASTER_FAILED) + return "PGRERROR_BUS_MASTER_FAILED"; + else if(error == FlyCapture2::PGRERROR_INVALID_GENERATION) + return "PGRERROR_INVALID_GENERATION"; + else if(error == FlyCapture2::PGRERROR_LUT_FAILED) + return "PGRERROR_LUT_FAILED"; + else if(error == FlyCapture2::PGRERROR_IIDC_FAILED) + return "PGRERROR_IIDC_FAILED"; + else if(error == FlyCapture2::PGRERROR_STROBE_FAILED) + return "PGRERROR_STROBE_FAILED"; + else if(error == FlyCapture2::PGRERROR_TRIGGER_FAILED) + return "PGRERROR_TRIGGER_FAILED"; + else if(error == FlyCapture2::PGRERROR_PROPERTY_FAILED) + return "PGRERROR_PROPERTY_FAILED"; + else if(error == FlyCapture2::PGRERROR_PROPERTY_NOT_PRESENT) + return "PGRERROR_PROPERTY_NOT_PRESENT"; + else if(error == FlyCapture2::PGRERROR_REGISTER_FAILED) + return "PGRERROR_REGISTER_FAILED"; + else if(error == FlyCapture2::PGRERROR_READ_REGISTER_FAILED) + return "PGRERROR_READ_REGISTER_FAILED"; + else if(error == FlyCapture2::PGRERROR_WRITE_REGISTER_FAILED) + return "PGRERROR_WRITE_REGISTER_FAILED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_FAILED) + return "PGRERROR_ISOCH_FAILED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_ALREADY_STARTED) + return "PGRERROR_ISOCH_ALREADY_STARTED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_NOT_STARTED) + return "PGRERROR_ISOCH_NOT_STARTED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_START_FAILED) + return "PGRERROR_ISOCH_START_FAILED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_RETRIEVE_BUFFER_FAILED) + return "PGRERROR_ISOCH_RETRIEVE_BUFFER_FAILED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_STOP_FAILED) + return "PGRERROR_ISOCH_STOP_FAILED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_SYNC_FAILED) + return "PGRERROR_ISOCH_SYNC_FAILED"; + else if(error == FlyCapture2::PGRERROR_ISOCH_BANDWIDTH_EXCEEDED) + return "PGRERROR_ISOCH_BANDWIDTH_EXCEEDED"; + else if(error == FlyCapture2::PGRERROR_IMAGE_CONVERSION_FAILED) + return "PGRERROR_IMAGE_CONVERSION_FAILED"; + else if(error == FlyCapture2::PGRERROR_IMAGE_LIBRARY_FAILURE) + return "PGRERROR_IMAGE_LIBRARY_FAILURE"; + else if(error == FlyCapture2::PGRERROR_BUFFER_TOO_SMALL) + return "PGRERROR_BUFFER_TOO_SMALL"; + else if(error == FlyCapture2::PGRERROR_IMAGE_CONSISTENCY_ERROR) + return "PGRERROR_IMAGE_CONSISTENCY_ERROR"; + else if(error == FlyCapture2::PGRERROR_INCOMPATIBLE_DRIVER) + return "PGRERROR_INCOMPATIBLE_DRIVER"; + else if(error == FlyCapture2::PGRERROR_FORCE_32BITS) + return "PGRERROR_FORCE_32BITS"; + + return "OTHER"; + } + + void + run(void) + { + while(!isStopping()) + { + if(m_new_image) + { + m_new_image = false; + m_task->debug("Save thread: %s", m_name_thread.c_str()); + try + { + m_row_bytes = (double)m_image.GetReceivedDataSize()/(double)m_image.GetRows(); + m_mat_image = cv::Mat(m_image.GetRows(), m_image.GetCols(), CV_8UC3, m_image.GetData(),m_row_bytes); + if(save_image()) + { + try + { + writeExifData(m_path_file_name); + } + catch(...) + { + m_task->war("error write exif data - thr: %s", m_name_thread.c_str()); + } + } + m_image.ReleaseBuffer(); + m_mat_image.~Mat(); + } + catch(...) + { + m_task->war("save error - thr: %s", m_name_thread.c_str()); + } + + m_is_free = true; + } + else + { + Delay::waitMsec(10); + } + } + } + + exifData m_exif_data; + + private: + //! Parent task. + DUNE::Tasks::Task* m_task; + //! The Image class is used to retrieve images from a camera + FlyCapture2::Image m_image; + //! The Error object of error that is returned + FlyCapture2::Error m_error; + //! Received new image to save + bool m_new_image; + //! Path to save the image + std::string m_path_file_name; + //! Options for saving JPEG image + std::vector m_jpeg_params; + //! Save metadata to image + Exiv2::Image::AutoPtr m_imageTag; + //! Buffer for metadata + char m_text_exif[32]; + //! A container for Exif data + Exiv2::ExifData m_exifData; + //! Number of row bytes of image + unsigned int m_row_bytes; + //! Buffer to opencv mat image + cv::Mat m_mat_image; + //! Flag to control state of thread + bool m_is_free; + + bool + save_image(void) + { + try + { + m_mutex.lock(); + imwrite( m_path_file_name.c_str(), m_mat_image, m_jpeg_params ); + m_mutex.unlock(); + return true; + } + catch (std::runtime_error& ex) + { + m_mutex.unlock(); + m_task->war("Exception saving image: %s\n", ex.what()); + return false; + } + } + }; + } +} + +#endif + + diff --git a/src/Vision/PointGrey/Task.cmake b/src/Vision/PointGrey/Task.cmake new file mode 100644 index 0000000000..58577e0650 --- /dev/null +++ b/src/Vision/PointGrey/Task.cmake @@ -0,0 +1,17 @@ +if(DUNE_SYS_HAS___ARM_ARCH_7A__) + +if(NOT DUNE_SYS_HAS_OPENCV) + set(TASK_ENABLED FALSE) +endif(NOT DUNE_SYS_HAS_OPENCV) + +if(NOT DUNE_SYS_HAS_EXIV2) + set(TASK_ENABLED FALSE) +endif(NOT DUNE_SYS_HAS_EXIV2) + +if(NOT DUNE_SYS_HAS_FLYCAPTURE) + set(TASK_ENABLED FALSE) +endif(NOT DUNE_SYS_HAS_FLYCAPTURE) + +endif(DUNE_SYS_HAS___ARM_ARCH_7A__) + +set(TASK_LICENSE "Proprietary") diff --git a/src/Vision/PointGrey/Task.cpp b/src/Vision/PointGrey/Task.cpp new file mode 100644 index 0000000000..0c0a3fe6cf --- /dev/null +++ b/src/Vision/PointGrey/Task.cpp @@ -0,0 +1,1230 @@ +//*************************************************************************** +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * +// Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * +//*************************************************************************** +// This file is part of DUNE: Unified Navigation Environment. * +// * +// Commercial Licence Usage * +// Licencees holding valid commercial DUNE licences may use this file in * +// accordance with the commercial licence agreement provided with the * +// Software or, alternatively, in accordance with the terms contained in a * +// written agreement between you and Universidade do Porto. For licensing * +// terms, conditions, and further information contact lsts@fe.up.pt. * +// * +// European Union Public Licence - EUPL v.1.1 Usage * +// Alternatively, this file may be used under the terms of the EUPL, * +// Version 1.1 only (the "Licence"), appearing in the file LICENCE.md * +// included in the packaging of this file. You may not use this work * +// except in compliance with the Licence. Unless required by applicable * +// law or agreed to in writing, software distributed under the Licence is * +// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF * +// ANY KIND, either express or implied. See the Licence for the specific * +// language governing permissions and limitations at * +// http://ec.europa.eu/idabc/eupl.html. * +//*************************************************************************** +// Author: Pedro Gonçalves * +//*************************************************************************** + +// ISO C++ 98 headers. +#include +#include +#include +#include +#include +#include +#include + +// DUNE headers. +#include + +#if defined(DUNE_CPU_ARMV7) +//FlyCapture headers +#include +//Exiv2 headers +#include +//Local header +#include "SaveImage.hpp" +#endif + +namespace Vision +{ + namespace PointGrey + { + //! Command types. + enum CommandType + { + //! Set GPIO LOW (on). + GPIO_HIGH = 1, + //! Set GPIO HIGH (off). + GPIO_LOW = 0 + }; + + using DUNE_NAMESPACES; + + static const int c_number_max_thread = 25; + static const int c_number_max_fps = 5; + static const int c_max_number_attempts_bus = 5; + static const float c_time_to_release_cached_ram = 300.0; + static const float c_time_to_release_camera = 3.0; + static const float c_time_to_update_cnt_info = 10.0; + static const std::string c_log_path = "/opt/lsts/dune/log/"; + static const std::string c_camera_log_folder = "CameraLog/"; + static const float c_timeout_reading = 15.0; + + //! %Task arguments. + struct Arguments + { + //! Master Name. + std::string system_name; + //! Power channel of strobe + std::string channel_strobe; + //! LED scheme. + std::string led_type; + //! Copyright Image + std::string copyright; + //! Lens Model + std::string lens_model; + //! Lens Maker + std::string lens_maker; + //! Saved Image Dir + std::string save_image_dir; + //! Number of frames/s + int number_fs; + //! Split photos by folder + bool split_photos; + //! Number of photos to folder + unsigned int number_photos; + //! Gpio Number for driver power + int gpio_drive_power; + //! Gpio Number for strobe + int gpio_strobe; + //! Delay before capture image + int delay_capture; + //! shutter value for image + float shutter_value; + //! flag o control statistics of disk use + bool disk_statistics; + }; + + //! Device driver task. + struct Task: public DUNE::Tasks::Task + { + //! Configuration parameters + Arguments m_args; + #if defined(DUNE_CPU_ARMV7) + //! Camera object + FlyCapture2::Camera m_camera; + //! Structure of Camera object + FlyCapture2::CameraInfo m_camInfo; + //! The Error object of error that is returned + FlyCapture2::Error m_error; + //! Buffer raw image from a camera + FlyCapture2::Image m_rawImage; + //! Buffer for rgb image; + FlyCapture2::Image m_rgbImage; + //! Identifier of camera + FlyCapture2::PGRGuid m_guid; + #endif + //! Latitude deg + int m_lat_deg; + //! Latitude min + int m_lat_min; + //! Latitude sec + double m_lat_sec; + //! Longitude deg + int m_lon_deg; + //! Longitude min + int m_lon_min; + //! Longitude sec + double m_lon_sec; + //! Buffer for exif timestamp + char m_text_exif_timestamp[16]; + //! Buffer to backup path log + std::string m_back_path_log; + //! Buffer to backup path to main system log + std::string m_back_path_main_log; + //! Buffer to backup epoch + std::string m_back_epoch; + //! Buffer to backup time + std::string m_back_time; + //! Buffer for path to save image + std::string m_path_image; + //! Buffer for backup of path to save image + std::string m_back_path_image; + //! Path to save image + Path m_log_dir; + //! Timer to control fps + Time::Counter m_cnt_fps; + //! Timer to control the cached ram + Time::Counter m_clean_cached_ram; + //! Timer to control the refresh of captured frames + Time::Counter m_update_cnt_frames; + //! Id thread + int m_thread_cnt; + //! Number of frames captured + long unsigned int m_frame_cnt; + //! Number of frames lost + long unsigned int m_frame_lost_cnt; + #if defined(DUNE_CPU_ARMV7) + //! Clase/thread to save image/exif data + SaveImage *m_save[c_number_max_thread]; + #endif + //! Buffer for the note comment of user + std::string m_note_comment; + //! Number of photos in folder + unsigned int m_cnt_photos_by_folder; + //! Number of folder + unsigned m_folder_number; + //! Bufer for name log + std::string m_log_name; + //! Flag to control capture of image + bool m_is_to_capture; + //! flag to control led - strobe + bool m_is_strobe; + //! flag to control led - on + bool m_is_on; + //! Strobe delay + float m_strobe_delay; + //! Flag to control init state + bool m_isStartTask; + //! Control state of capture + bool m_isCapturing; + //! buffer for path to get storage usage of logs + char m_buffer[64]; + //! Storage usage value + std::string m_storage; + //! Timer to control reading of storage + Time::Counter m_timeout_reading; + //! string for result output + std::string m_result; + //! Flag to control reading of used storage + bool m_read_storage; + //! Flag to control read of path from LoggingControl + bool m_read_path; + + Task(const std::string& name, Tasks::Context& ctx): + Tasks::Task(name, ctx), + m_log_dir(ctx.dir_log) + { + paramActive(Tasks::Parameter::SCOPE_MANEUVER, + Tasks::Parameter::VISIBILITY_USER); + + param("Power Channel - Strobe", m_args.channel_strobe) + .description("Power Channel of Strobe."); + + param("System Name", m_args.system_name) + .description("Main system name."); + + param("Led Mode", m_args.led_type) + .values("Strobe, On, Off") + .description("Led type mode."); + + param("Copyright", m_args.copyright) + .description("Copyright of Image."); + + param("Lens Model", m_args.lens_model) + .description("Lens Model of camera."); + + param("Lens Make", m_args.lens_maker) + .description("Lens builder/maker."); + + param("Saved Images Dir", m_args.save_image_dir) + .defaultValue("Photos") + .description("Saved Images Dir."); + + param("Number Frames/s", m_args.number_fs) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .defaultValue("4") + .minimumValue("1") + .maximumValue("5") + .description("Number Frames/s."); + + param("Split Photos", m_args.split_photos) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("true") + .description("Split photos by folder."); + + param("Number of photos to divide", m_args.number_photos) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("1000") + .minimumValue("500") + .maximumValue("3000") + .description("Split photos by folder."); + + param("GPIO Driver Power", m_args.gpio_drive_power) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("17") + .description("GPIO of RPI2 for driver power."); + + param("GPIO Strobe", m_args.gpio_strobe) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("27") + .description("GPIO of RPI2 for strobe."); + + param("Strobe Delay (us)", m_args.delay_capture) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .scope(Tasks::Parameter::SCOPE_MANEUVER) + .defaultValue("1000") + .description("Strobe Delay in us."); + + param("Shutter Value (ms)", m_args.shutter_value) + .visibility(Tasks::Parameter::VISIBILITY_USER) + .scope(Tasks::Parameter::SCOPE_MANEUVER) + .defaultValue("8") + .minimumValue("1") + .maximumValue("300") + .description("Shutter Value time in ms."); + + param("No Disk Statistics", m_args.disk_statistics) + .visibility(Tasks::Parameter::VISIBILITY_DEVELOPER) + .defaultValue("false") + .description("Set dispatch of Disk Statistics use."); + + bind(this); + bind(this); + } + + void + onUpdateParameters(void) + { + if (paramChanged(m_args.shutter_value) && m_isStartTask) + inf("shutter: %f", m_args.shutter_value); + + if (paramChanged(m_args.delay_capture) && m_isStartTask) + inf("strobe delay: %d", m_args.delay_capture); + + if (paramChanged(m_args.number_fs) && !m_isCapturing) + { + inf("Fps: %d", m_args.number_fs); + m_cnt_fps.setTop((1.0/m_args.number_fs)); + } + else if (paramChanged(m_args.number_fs) && m_isCapturing) + { + inf("Cannot change frames in capturing mode"); + } + } + + void + onResourceInitialization(void) + { + m_read_path = true; + m_read_storage = true; + m_isStartTask = false; + m_isCapturing = false; + set_cpu_governor(); + init_gpio_driver(); + init_gpio_strobe(); + + if(m_args.number_fs > 0 && m_args.number_fs <= c_number_max_fps) + { + m_cnt_fps.setTop((1.0/m_args.number_fs)); + } + else + { + war("Number of frames are wrong (1 <> 5)"); + war("Setting number of frames to default (4)"); + m_cnt_fps.setTop(0.25); + } + + if(m_args.number_photos < 500 && m_args.split_photos) + { + war("Number of photos by folder is to small (mim: 500)"); + war("Setting Number of photos by folder to default (1000)"); + m_args.number_photos = 1000; + } + else if(m_args.number_photos > 3000 && m_args.split_photos) + { + war("Number of photos by folder is to high (max: 3000)"); + war("Setting Number of photos by folder to default (1000)"); + m_args.number_photos = 1000; + } + + m_thread_cnt = 0; + m_frame_cnt = 0; + m_frame_lost_cnt = 0; + m_cnt_photos_by_folder = 0; + m_folder_number = 0; + m_is_to_capture = false; + m_strobe_delay = m_args.delay_capture; + + char text[8]; + for(int i = 0; i < c_number_max_thread; i++) + { + sprintf(text, "thr%d", i); + #if defined(DUNE_CPU_ARMV7) + m_save[i] = new SaveImage(this, text); + m_save[i]->start(); + #endif + } + + m_clean_cached_ram.setTop(c_time_to_release_cached_ram); + m_update_cnt_frames.setTop(c_time_to_update_cnt_info); + + if(m_args.disk_statistics) + setEntityState(IMC::EntityState::ESTA_BOOT, "idle | " + getStorageUsageLogs()); + else + setEntityState(IMC::EntityState::ESTA_BOOT, "idle"); + + m_isStartTask = true; + } + + #if defined(DUNE_CPU_ARMV7) + void + onResourceRelease(void) + { + m_is_to_capture = false; + if(m_isStartTask) + { + Delay::wait(c_time_to_release_camera); + setGpio(GPIO_LOW, m_args.gpio_strobe); + setGpio(GPIO_LOW, m_args.gpio_drive_power); + + for(int i = 0; i < c_number_max_thread; i++) + { + if (m_save[i] != NULL) + { + m_save[i]->stopAndJoin(); + delete m_save[i]; + m_save[i] = NULL; + } + } + + if(m_camera.IsConnected()) + { + m_error = m_camera.StopCapture(); + if ( m_error != FlyCapture2::PGRERROR_OK ) + inf("Error stopping camera capture: %s , already stop?", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + + m_error = m_camera.Disconnect(); + if ( m_error != FlyCapture2::PGRERROR_OK ) + inf("Error disconnecting camera: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + } + } + } + #endif + + void + consume(const IMC::LoggingControl* msg) + { + std::string sysNameMsg = resolveSystemId(msg->getSource()); + std::string sysLocalName = getSystemName(); + + if(sysNameMsg != m_args.system_name && sysNameMsg != sysLocalName) + return; + + if(sysNameMsg != sysLocalName) + { + debug("Camera FLAG: %u", msg->op); + if (msg->op == IMC::LoggingControl::COP_STARTED || msg->op == IMC::LoggingControl::COP_CURRENT_NAME) + { + if (m_read_path && msg->op == IMC::LoggingControl::COP_CURRENT_NAME) + { + return; // Already know log folder + } + + if (msg->op == IMC::LoggingControl::COP_STARTED && m_read_path) + { + m_isCapturing = false; + } + + m_read_path = true; + m_frame_cnt = 0; + m_frame_lost_cnt = 0; + m_cnt_photos_by_folder = 0; + m_folder_number = 0; + debug("LoggingControl: reset count m_frame_cnt: %d", msg->op); + std::string m_path = c_log_path + m_args.system_name; + m_back_path_main_log = m_path + "/" + msg->name; + + if(m_args.split_photos) + m_log_dir = m_path / msg->name / m_args.save_image_dir / String::str("%06u", m_folder_number); + else + m_log_dir = m_path / msg->name / m_args.save_image_dir; + + inf("Camera photos stored: %s", m_back_path_main_log.c_str()); + m_back_path_image = m_log_dir.c_str(); + m_log_dir.create(); + m_log_name = msg->name; + m_thread_cnt = 0; + m_cnt_fps.reset(); + m_isCapturing = true; + } + } + + std::string m_base_path = m_ctx.dir_log.c_str(); + m_back_path_log = m_base_path + "/" + msg->name; + } + + void + consume(const IMC::EstimatedState* msg) + { + std::string sysName = resolveSystemId(msg->getSource()); + if(sysName != m_args.system_name) + return; + + Angles::convertDecimalToDMS(Angles::degrees(msg->lat), m_lat_deg, m_lat_min, m_lat_sec); + Angles::convertDecimalToDMS(Angles::degrees(msg->lon), m_lon_deg, m_lon_min, m_lon_sec); + m_note_comment = "Depth: "+to_string(msg->depth)+" m # Altitude: "+to_string(msg->alt)+" m"; + + IMC::GpsFix pos; + pos.lat = msg->lat; + pos.lon = msg->lon; + dispatch(pos); + } + + void + onRequestActivation(void) + { + inf("received activation request"); + activate(); + } + + void + onRequestDeactivation(void) + { + inf("received deactivation request"); + deactivate(); + } + + void + onActivation(void) + { + inf("on Activation"); + m_read_path = false; + releaseRamCached(); + updateStrobe(); + + IMC::LoggingControl logcontrol; + logcontrol.op = IMC::LoggingControl::COP_REQUEST_CURRENT_NAME; + dispatch(logcontrol); + Delay::wait(0.2); + + try + { + if(!setUpCamera()) + throw RestartNeeded("Cannot detect camera", 10); + + setEntityState(IMC::EntityState::ESTA_NORMAL, "Led Mode: "+m_args.led_type+" # Fps: "+to_string(m_args.number_fs)); + set_shutter_value(m_args.shutter_value); + } + catch(...) + { + throw RestartNeeded("Error Flycapture API", 10); + } + m_is_to_capture = true; + inf("Starting Capture."); + } + + void + onDeactivation(void) + { + m_read_path = true; + inf("on Deactivation"); + m_is_to_capture = false; + m_isCapturing = false; + #if defined(DUNE_CPU_ARMV7) + m_error = m_camera.StopCapture(); + if ( m_error != FlyCapture2::PGRERROR_OK ) + war("Error stopping camera capture: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + + setGpio(GPIO_LOW, m_args.gpio_strobe); + #endif + + moveLogFiles(); + if(m_args.disk_statistics) + setEntityState(IMC::EntityState::ESTA_NORMAL, "idle | " + getStorageUsageLogs()); + else + setEntityState(IMC::EntityState::ESTA_NORMAL, "idle"); + } + + int + moveLogFiles(void) + { + std::string path_log_dune_cam = m_back_path_main_log + "/" + c_camera_log_folder; + std::string system_command = "mkdir " + path_log_dune_cam; + inf("Camera dune log stored: %s", m_back_path_main_log.c_str()); + int result = std::system(system_command.c_str()); + debug("Path of dune log running in camara: %s", m_back_path_log.c_str()); + + std::string file_name_old = m_back_path_log + "/Output.txt "; + std::string file_name_new = path_log_dune_cam + "/camera_Output.txt"; + system_command = "mv " + file_name_old + file_name_new; + result = std::system(system_command.c_str()); + + file_name_old = m_back_path_log + "/Config.ini "; + file_name_new = path_log_dune_cam + "/camera_Config.ini"; + system_command = "mv " + file_name_old + file_name_new; + result = std::system(system_command.c_str()); + + file_name_old = m_back_path_log + "/Data.lsf.gz "; + file_name_new = path_log_dune_cam + "/camera_Data.lsf.gz"; + system_command = "mv " + file_name_old + file_name_new; + result = std::system(system_command.c_str()); + + file_name_old = m_back_path_log + "/IMC.xml.gz "; + file_name_new = path_log_dune_cam + "/camera_IMC.xml.gz"; + system_command = "mv " + file_name_old + file_name_new; + result = std::system(system_command.c_str()); + + return result; + } + + std::string + getStorageUsageLogs(void) + { + m_timeout_reading.setTop(c_timeout_reading); + std::memset(&m_buffer, '\0', sizeof(m_buffer)); + std::sprintf(m_buffer, "du -hs /opt/lsts/dune/log"); + FILE* pipe = std::fopen(m_buffer, "r"); + if (!pipe) + { + war("timeout - error reading storage usage"); + m_read_storage = true; + m_storage = "0"; + } + else + { + std::memset(&m_buffer, '\0', sizeof(m_buffer)); + m_timeout_reading.reset(); + try + { + while (!std::feof(pipe) && !m_timeout_reading.overflow()) + { + #if defined(DUNE_CPU_ARMV7) + (void)std::fgets(m_buffer, sizeof(m_buffer), pipe); + #endif + } + + if(m_timeout_reading.overflow()) + { + std::fclose(pipe); + war("timeout - error reading storage usage"); + m_read_storage = true; + return "0"; + } + } + catch (...) + { + std::fclose(pipe); + m_read_storage = true; + return "0"; + } + std::fclose(pipe); + try + { + std::vector parts; + Utils::String::split(m_buffer, "/", parts); + if(parts.size() > 1) + m_storage = parts[0] + " used space"; + else + m_storage = "Fail get size info"; + } + catch (...) + { + m_read_storage = true; + return "0"; + } + } + return m_storage; + } + + int + set_cpu_governor(void) + { + char buffer[16]; + char governor[16]; + std::string result = ""; + FILE* pipe; + if ((pipe = popen("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r")) == NULL) + { + war("popen() failed - set_cpu_governor!"); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + } + else + { + std::memset(&buffer, '\0', sizeof(buffer)); + try + { + while (!std::feof(pipe)) + { + if (std::fgets(buffer, sizeof(buffer), pipe) != NULL) + result += buffer; + } + } + catch (...) + { + std::fclose(pipe); + throw; + } + std::fclose(pipe); + std::sscanf(buffer, "%s", governor); + if( std::strcmp(governor, "ondemand") == 0) + { + inf("CPU governor is already ondemand"); + } + else + { + war("CPU governor is not in ondemand, setting to ondemand"); + return std::system("echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"); + } + } + + return -1; + } + + bool + init_gpio_strobe(void) + { + FILE* pipe; + if ((pipe = fopen("/sys/class/gpio/export", "ab")) == NULL) + { + err("Unable to export GPIO pin (%d)", m_args.gpio_strobe); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + return false; + } + else + { + std::fwrite(to_string(m_args.gpio_strobe).c_str(), sizeof(char), 2, pipe); + std::fclose(pipe); + setGpioDirection(m_args.gpio_strobe, true); + return setGpio(GPIO_LOW, m_args.gpio_strobe); + } + return false; + } + + bool + init_gpio_driver(void) + { + FILE* pipe; + if ((pipe = fopen("/sys/class/gpio/export", "ab")) == NULL) + { + err("Unable to export GPIO pin (%d)", m_args.gpio_drive_power); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + return false; + } + else + { + std::fwrite(to_string(m_args.gpio_drive_power).c_str(), sizeof(char), 2, pipe); + std::fclose(pipe); + setGpioDirection(m_args.gpio_drive_power, true); + return setGpio(GPIO_HIGH, m_args.gpio_drive_power); + } + return false; + } + + bool + setGpioDirection(int gpio, bool isOut) + { + char buffer[64]; + FILE* pipe; + std::sprintf(buffer, "/sys/class/gpio/gpio%d/direction", gpio); + if ((pipe = fopen(buffer, "rb+")) == NULL) + { + err("Unable to open direction handle (%d)", gpio); + setEntityState(IMC::EntityState::ESTA_ERROR, Status::CODE_INTERNAL_ERROR); + return false; + } + else + { + if(isOut) + std::fwrite("out", sizeof(char), 3, pipe); + else + std::fwrite("in", sizeof(char), 3, pipe); + std::fclose(pipe); + Delay::wait(1); + return true; + } + } + + bool + setGpio(CommandType mode, int gpio) + { + char buffer[64]; + std::sprintf(buffer, "/sys/class/gpio/gpio%d/value", gpio); + FILE* pipe; + if ((pipe = std::fopen(buffer, "rb+")) == NULL) + { + err("Unable to open value handle (%d)", gpio); + return false; + } + else + { + switch (mode) + { + case GPIO_LOW: + std::fwrite("0", sizeof(char), 1, pipe); + std::fclose(pipe); + break; + + case GPIO_HIGH: + std::fwrite("1", sizeof(char), 1, pipe); + std::fclose(pipe); + break; + + default: + std::fclose(pipe); + break; + } + } + + return true; + } + + void + updateStrobe(void) + { + m_is_strobe = false; + m_is_on = false; + init_gpio_strobe(); + if (m_args.led_type == "Strobe" || m_args.led_type == "STROBE") + { + war("enabling strobe output"); + m_is_strobe = true; + } + else if (m_args.led_type == "On" || m_args.led_type == "ON") + { + setGpio(GPIO_HIGH, m_args.gpio_strobe); + m_is_on = true; + war("leds always on"); + } + else + { + war("leds always off"); + } + } + + void + getInfoCamera(void) + { + #if defined(DUNE_CPU_ARMV7) + debug("Vendor Name: %s", m_camInfo.vendorName); + debug("Model Name: %s", m_camInfo.modelName); + debug("Serial Number: %d", m_camInfo.serialNumber); + debug("Sensor Info: %s", m_camInfo.sensorInfo); + debug("Sensor Resolution: %s", m_camInfo.sensorResolution); + debug("Firmware Version: %s", m_camInfo.firmwareVersion); + debug("copyright: %s", m_args.copyright.c_str()); + debug("Lens Model: %s", m_args.lens_model.c_str()); + debug("Lens Maker: %s", m_args.lens_maker.c_str()); + #endif + } + + bool + setUpCamera(void) + { + #if defined(DUNE_CPU_ARMV7) + unsigned int nb_cameras; + int bus_attempts = 1; + while (bus_attempts <= c_max_number_attempts_bus) + { + FlyCapture2::BusManager m_busMgr; + m_error = m_busMgr.GetNumOfCameras(&nb_cameras); + if (m_error != FlyCapture2::PGRERROR_OK) + { + err("Failed to create bus manager (attempt: %d): %s",bus_attempts, m_save[m_thread_cnt]->getNameError(m_error).c_str()); + } + else + { + if (nb_cameras < 1 && nb_cameras > 2) + { + err("No cameras found at bus manager attempt %d (%d)", bus_attempts, nb_cameras); + } + else + { + inf("Number of cameras found in bus manager attempt %d is %d", bus_attempts, nb_cameras); + inf("Initialization of Camera"); + // Get Flea2 camera + m_error = m_busMgr.GetCameraFromIndex( 0, &m_guid ); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed to get camera index at bus manager attempt %d: %s", bus_attempts, m_save[m_thread_cnt]->getNameError(m_error).c_str()); + } + else + { + break; + } + } + } + bus_attempts++; + Delay::wait(2); + } + + if (bus_attempts > c_max_number_attempts_bus) + { + err("No cameras found in attempt %d", bus_attempts); + return false; + } + + // Connect the camera + m_error = m_camera.Connect( &m_guid ); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed to connect to camera: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + return false; + } + // Get the camera info and print it out + m_error = m_camera.GetCameraInfo( &m_camInfo ); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed to get camera info from camera: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + return false; + } + // Get the camera info and print it out + m_error = m_camera.RestoreFromMemoryChannel( 1 ); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed to restore config %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + return false; + } + + set_shutter_value(m_args.shutter_value); + + m_error = m_camera.StartCapture(); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed to start image capture: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + return false; + } + + getInfoCamera(); + inf("Camera ready."); + #endif + return true; + } + + // Start polling for trigger ready + bool + pollForTriggerReady(void) + { + #if defined(DUNE_CPU_ARMV7) + unsigned int k_softwareTrigger = 0x62C; + unsigned int regVal = 0; + + do + { + m_error = m_camera.ReadRegister( k_softwareTrigger, ®Val ); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed of PollForTriggerReady: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + return false; + } + } while ( (regVal >> 31) != 0 && !stopping()); + #endif + return true; + } + + bool + set_shutter_value(float value) + { + #if defined(DUNE_CPU_ARMV7) + //Declare a Property struct. + FlyCapture2::Property prop; + //Define the property to adjust. + prop.type = FlyCapture2::SHUTTER; + //Ensure the property is on. + prop.onOff = true; + //Ensure auto-adjust mode is off. + prop.autoManualMode = false; + //Ensure the property is set up to use absolute value control. + prop.absControl = true; + //Set the absolute value of shutter to x ms. + prop.absValue = value; + //Set the property. + m_error = m_camera.SetProperty( &prop ); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed to set shutter value: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + m_error.PrintErrorTrace(); + return false; + } + #else + (void)value; + #endif + return true; + } + + // Launch the software trigger event + bool + fireSoftwareTrigger(void) + { + #if defined(DUNE_CPU_ARMV7) + const unsigned int k_softwareTrigger = 0x62C; + const unsigned int k_fireVal = 0x80000000; + m_error = m_camera.WriteRegister( k_softwareTrigger, k_fireVal ); + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + err("Failed to FireSoftwareTrigger: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + return false; + } + #endif + return true; + } + + bool + getImage(void) + { + #if defined(DUNE_CPU_ARMV7) + bool result = false; + saveInfoExif(); + if(m_is_strobe) + { + setGpio(GPIO_HIGH, m_args.gpio_strobe); + Delay::waitUsec(m_args.delay_capture); + } + else if(m_is_on) + { + setGpio(GPIO_HIGH, m_args.gpio_strobe); + } + + // Check that the trigger is ready + pollForTriggerReady(); + // Fire software trigger + fireSoftwareTrigger(); + + try + { + m_error = m_camera.RetrieveBuffer( &m_rawImage ); + } + catch (...) + { + war("error RetrieveBuffer"); + return false; + } + + if ( m_error != FlyCapture2::PGRERROR_OK) + { + if(m_is_to_capture) + war("capture error: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + + return false; + } + + if(m_is_strobe) + setGpio(GPIO_LOW, m_args.gpio_strobe); + else if(m_is_on) + setGpio(GPIO_HIGH, m_args.gpio_strobe); + + // convert to rgb + try + { + m_error = m_rawImage.Convert( FlyCapture2::PIXEL_FORMAT_BGR, &m_rgbImage ); + } + catch(...) + { + war("error Convert"); + return false; + } + + if ( m_error != FlyCapture2::PGRERROR_OK ) + { + war("convert error: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + return false; + } + + m_path_image = m_back_path_image.c_str(); + m_path_image.append("/"); + m_path_image.append(m_back_epoch); + m_path_image.append(".jpg"); + + debug("Size Image Capture: %u x %u", m_rgbImage.GetCols(), m_rgbImage.GetRows()); + debug("Path: %s", m_path_image.c_str()); + + m_thread_cnt = sendImageThread(m_thread_cnt); + result = true; + + if(m_thread_cnt >= c_number_max_thread) + m_thread_cnt = 0; + + m_rgbImage.ReleaseBuffer(); + m_rawImage.ReleaseBuffer(); + + return result; + #else + return false; + #endif + } + + int + sendImageThread(int cnt_thread) + { + #if defined(DUNE_CPU_ARMV7) + int pointer_cnt_thread = cnt_thread; + bool jump_over = false; + bool result_thread; + while(!jump_over && !stopping()) + { + try + { + result_thread = m_save[pointer_cnt_thread]->saveNewImage(m_rgbImage, m_path_image); + } + catch(...) + { + war("error thread"); + } + + if(result_thread) + { + pointer_cnt_thread++; + jump_over = true; + m_frame_cnt++; + return pointer_cnt_thread; + } + else + { + debug("thread %d is working, jump to other", pointer_cnt_thread); + pointer_cnt_thread++; + if(pointer_cnt_thread >= c_number_max_thread) + pointer_cnt_thread = 0; + + if(cnt_thread == pointer_cnt_thread) + { + pointer_cnt_thread++; + inf("Error saving image, all thread working"); + m_frame_lost_cnt++; + jump_over = true; + return pointer_cnt_thread; + } + } + } + + return pointer_cnt_thread; + #else + (void)cnt_thread; + return -1; + #endif + } + + void + releaseRamCached(void) + { + debug("Releasing cache ram."); + #if defined(DUNE_CPU_ARMV7) + (void)std::system("sync"); + (void)std::system("echo 1 > /proc/sys/vm/drop_caches"); + (void)std::system("sync"); + #endif + } + + void + saveInfoExif(void) + { + #if defined(DUNE_CPU_ARMV7) + std::memset(&m_text_exif_timestamp, '\0', sizeof(m_text_exif_timestamp)); + std::sprintf(m_text_exif_timestamp, "%0.4f", Clock::getSinceEpoch()); + m_back_epoch = m_text_exif_timestamp; + + m_save[m_thread_cnt]->m_exif_data.lat_deg = m_lat_deg; + m_save[m_thread_cnt]->m_exif_data.lat_min = m_lat_min; + m_save[m_thread_cnt]->m_exif_data.lat_sec = m_lat_sec; + m_save[m_thread_cnt]->m_exif_data.lon_deg = m_lon_deg; + m_save[m_thread_cnt]->m_exif_data.lon_min = m_lon_min; + m_save[m_thread_cnt]->m_exif_data.lon_sec = m_lon_sec; + m_save[m_thread_cnt]->m_exif_data.date_time_original = Time::Format::getTimeDate().c_str(); + m_save[m_thread_cnt]->m_exif_data.date_time_digitized = m_back_epoch.c_str(); + m_save[m_thread_cnt]->m_exif_data.make = m_camInfo.vendorName; + m_save[m_thread_cnt]->m_exif_data.model = m_camInfo.modelName; + m_save[m_thread_cnt]->m_exif_data.lens_make = m_args.lens_maker.c_str(); + m_save[m_thread_cnt]->m_exif_data.lens_model = m_args.lens_model.c_str(); + m_save[m_thread_cnt]->m_exif_data.copyright = m_args.copyright.c_str(); + m_save[m_thread_cnt]->m_exif_data.artist = getSystemName(); + m_save[m_thread_cnt]->m_exif_data.notes = m_note_comment.c_str(); + #endif + } + + template + inline std::string to_string (const T& t) + { + std::stringstream ss; + ss << t; + return ss.str(); + } + + void + triggerFrame(void) + { + #if defined(DUNE_CPU_ARMV7) + if(!getImage() && m_is_to_capture) + { + war("Restarting camera..."); + if(m_camera.IsConnected()) + { + m_error = m_camera.StopCapture(); + if ( m_error != FlyCapture2::PGRERROR_OK ) + war("Error stopping camera capture: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + + m_error = m_camera.Disconnect(); + if ( m_error != FlyCapture2::PGRERROR_OK ) + war("Error disconnecting camera: %s", m_save[m_thread_cnt]->getNameError(m_error).c_str()); + } + if (isActive()) + setUpCamera(); + } + else + { + if(m_args.split_photos) + { + m_cnt_photos_by_folder++; + if(m_cnt_photos_by_folder >= m_args.number_photos) + { + std::string m_path = c_log_path + m_args.system_name; + m_cnt_photos_by_folder = 0; + m_folder_number++; + m_log_dir = m_path / m_log_name / m_args.save_image_dir / String::str("%06u", m_folder_number); + m_back_path_image = m_log_dir.c_str(); + m_log_dir.create(); + } + } + } + + debug("Capture: thr %d", m_thread_cnt); + #endif + } + + void + onMain(void) + { + while (!stopping()) + { + if (isActive()) + { + consumeMessages(); + if(m_isCapturing) + { + if(m_cnt_fps.overflow()) + { + m_cnt_fps.reset(); + triggerFrame(); + } + else if(m_clean_cached_ram.overflow()) + { + m_clean_cached_ram.reset(); + releaseRamCached(); + } + else if(m_update_cnt_frames.overflow()) + { + debug("Count Frames: %ld", m_frame_cnt); + m_update_cnt_frames.reset(); + setEntityState(IMC::EntityState::ESTA_NORMAL, "Led Mode: "+m_args.led_type+" # Fps: "+to_string(m_args.number_fs)+" # "+to_string(m_frame_cnt)+" - "+to_string(m_frame_lost_cnt)); + } + } + } + else + { + waitForMessages(1.0); + setGpio(GPIO_LOW, m_args.gpio_strobe); + if(m_args.disk_statistics) + { + if(m_read_storage) + { + m_read_storage = false; + setEntityState(IMC::EntityState::ESTA_NORMAL, "idle | " + getStorageUsageLogs()); + } + } + } + } + } + }; + } +} + +DUNE_TASK diff --git a/src/Vision/UAVCamera/Task.cpp b/src/Vision/UAVCamera/Task.cpp index ec1eec21de..25e8f548a0 100644 --- a/src/Vision/UAVCamera/Task.cpp +++ b/src/Vision/UAVCamera/Task.cpp @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/vendor/libraries/bzip2/Library.cmake b/vendor/libraries/bzip2/Library.cmake index 099e43bcdf..7f2f608177 100644 --- a/vendor/libraries/bzip2/Library.cmake +++ b/vendor/libraries/bzip2/Library.cmake @@ -1,7 +1,12 @@ file(GLOB DUNE_BZIP2_FILES vendor/libraries/bzip2/*.c) +check_cxx_compiler_flag(-Wimplicit-fallthrough=0 _has_wimplicit_fallthrough_0) +if(_has_wimplicit_fallthrough_0) + set(_bzip2_extra_cflags -Wimplicit-fallthrough=0) +endif() + set_source_files_properties(${DUNE_BZIP2_FILES} - PROPERTIES COMPILE_FLAGS "${DUNE_C_FLAGS} ${DUNE_C_FLAGS_STRICT}") + PROPERTIES COMPILE_FLAGS "${DUNE_C_FLAGS} ${DUNE_C_FLAGS_STRICT} ${_bzip2_extra_cflags}") list(APPEND DUNE_VENDOR_FILES ${DUNE_BZIP2_FILES}) diff --git a/vendor/libraries/mavlink/ardupilotmega/ardupilotmega.h b/vendor/libraries/mavlink/ardupilotmega/ardupilotmega.h index f7cd665a43..3627a83699 100644 --- a/vendor/libraries/mavlink/ardupilotmega/ardupilotmega.h +++ b/vendor/libraries/mavlink/ardupilotmega/ardupilotmega.h @@ -1,7 +1,8 @@ /** @file - * @brief MAVLink comm protocol generated from ardupilotmega.xml - * @see http://mavlink.org + * @brief MAVLink comm protocol generated from ardupilotmega.xml + * @see http://mavlink.org */ +#pragma once #ifndef MAVLINK_ARDUPILOTMEGA_H #define MAVLINK_ARDUPILOTMEGA_H @@ -9,6 +10,9 @@ #error Wrong include order: MAVLINK_ARDUPILOTMEGA.H MUST NOT BE DIRECTLY USED. Include mavlink.h from the same directory instead or set ALL AND EVERY defines from MAVLINK.H manually accordingly, including the #define MAVLINK_H call. #endif +#undef MAVLINK_THIS_XML_IDX +#define MAVLINK_THIS_XML_IDX 0 + #ifdef __cplusplus extern "C" { #endif @@ -16,15 +20,11 @@ extern "C" { // MESSAGE LENGTHS AND CRCS #ifndef MAVLINK_MESSAGE_LENGTHS -#define MAVLINK_MESSAGE_LENGTHS {9, 31, 12, 0, 14, 28, 3, 32, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 25, 23, 30, 101, 22, 26, 16, 14, 28, 32, 28, 28, 22, 22, 21, 6, 6, 37, 4, 4, 2, 2, 4, 2, 2, 3, 13, 12, 37, 0, 0, 0, 27, 25, 0, 0, 0, 0, 0, 68, 26, 185, 181, 42, 6, 4, 0, 11, 18, 0, 0, 37, 20, 35, 33, 3, 0, 0, 0, 22, 39, 37, 53, 51, 53, 51, 0, 28, 56, 42, 33, 0, 0, 0, 0, 0, 0, 0, 26, 32, 32, 20, 32, 62, 44, 64, 84, 9, 254, 16, 0, 36, 44, 64, 22, 6, 14, 12, 97, 2, 2, 113, 35, 6, 79, 35, 35, 0, 13, 255, 14, 18, 43, 8, 22, 14, 36, 43, 41, 0, 0, 0, 0, 0, 0, 36, 60, 0, 42, 8, 4, 12, 15, 13, 6, 15, 14, 0, 12, 3, 8, 28, 44, 3, 9, 22, 12, 18, 34, 66, 98, 8, 48, 19, 3, 20, 24, 29, 45, 4, 40, 2, 42, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 36, 30, 18, 18, 51, 9, 0} +#define MAVLINK_MESSAGE_LENGTHS {9, 31, 12, 0, 14, 28, 3, 32, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 25, 23, 30, 101, 22, 26, 16, 14, 28, 32, 28, 28, 22, 22, 21, 6, 6, 37, 4, 4, 2, 2, 4, 2, 2, 3, 13, 12, 37, 4, 0, 0, 27, 25, 0, 0, 0, 0, 0, 72, 26, 181, 225, 42, 6, 4, 0, 11, 18, 0, 0, 37, 20, 35, 33, 3, 0, 0, 0, 22, 39, 37, 53, 51, 53, 51, 0, 28, 56, 42, 33, 81, 0, 0, 0, 0, 0, 0, 26, 32, 32, 20, 32, 62, 44, 64, 84, 9, 254, 16, 12, 36, 44, 64, 22, 6, 14, 12, 97, 2, 2, 113, 35, 6, 79, 35, 35, 22, 13, 255, 14, 18, 43, 8, 22, 14, 36, 43, 41, 32, 243, 14, 93, 0, 100, 36, 60, 30, 42, 8, 4, 12, 15, 13, 6, 15, 14, 0, 12, 3, 8, 28, 44, 3, 9, 22, 12, 18, 34, 66, 98, 8, 48, 19, 3, 20, 24, 29, 45, 4, 40, 2, 206, 7, 29, 0, 0, 0, 0, 27, 44, 22, 25, 0, 0, 0, 0, 0, 42, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 3, 3, 6, 7, 2, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 42, 40, 63, 182, 40, 0, 0, 0, 0, 0, 0, 32, 52, 53, 6, 2, 38, 19, 254, 36, 30, 18, 18, 51, 9, 0} #endif #ifndef MAVLINK_MESSAGE_CRCS -#define MAVLINK_MESSAGE_CRCS {50, 124, 137, 0, 237, 217, 104, 119, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 214, 159, 220, 168, 24, 23, 170, 144, 67, 115, 39, 246, 185, 104, 237, 244, 222, 212, 9, 254, 230, 28, 28, 132, 221, 232, 11, 153, 41, 39, 78, 0, 0, 0, 15, 3, 0, 0, 0, 0, 0, 153, 183, 51, 82, 118, 148, 21, 0, 243, 124, 0, 0, 38, 20, 158, 152, 143, 0, 0, 0, 106, 49, 22, 143, 140, 5, 150, 0, 231, 183, 63, 54, 0, 0, 0, 0, 0, 0, 0, 175, 102, 158, 208, 56, 93, 138, 108, 32, 185, 84, 34, 0, 124, 237, 4, 76, 128, 56, 116, 134, 237, 203, 250, 87, 203, 220, 25, 226, 0, 29, 223, 85, 6, 229, 203, 1, 195, 109, 168, 181, 0, 0, 0, 0, 0, 0, 154, 178, 0, 134, 219, 208, 188, 84, 22, 19, 21, 134, 0, 78, 68, 189, 127, 154, 21, 21, 144, 1, 234, 73, 181, 22, 83, 167, 138, 234, 240, 47, 189, 52, 174, 229, 85, 97, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 204, 49, 170, 44, 83, 46, 0} -#endif - -#ifndef MAVLINK_MESSAGE_INFO -#define MAVLINK_MESSAGE_INFO {MAVLINK_MESSAGE_INFO_HEARTBEAT, MAVLINK_MESSAGE_INFO_SYS_STATUS, MAVLINK_MESSAGE_INFO_SYSTEM_TIME, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PING, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK, MAVLINK_MESSAGE_INFO_AUTH_KEY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SET_MODE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST, MAVLINK_MESSAGE_INFO_PARAM_VALUE, MAVLINK_MESSAGE_INFO_PARAM_SET, MAVLINK_MESSAGE_INFO_GPS_RAW_INT, MAVLINK_MESSAGE_INFO_GPS_STATUS, MAVLINK_MESSAGE_INFO_SCALED_IMU, MAVLINK_MESSAGE_INFO_RAW_IMU, MAVLINK_MESSAGE_INFO_RAW_PRESSURE, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE, MAVLINK_MESSAGE_INFO_ATTITUDE, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT, MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED, MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW, MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_ITEM, MAVLINK_MESSAGE_INFO_MISSION_REQUEST, MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST, MAVLINK_MESSAGE_INFO_MISSION_COUNT, MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL, MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED, MAVLINK_MESSAGE_INFO_MISSION_ACK, MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_PARAM_MAP_RC, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION_COV, MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT_COV, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_COV, MAVLINK_MESSAGE_INFO_RC_CHANNELS, MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM, MAVLINK_MESSAGE_INFO_DATA_STREAM, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_CONTROL, MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MISSION_ITEM_INT, MAVLINK_MESSAGE_INFO_VFR_HUD, MAVLINK_MESSAGE_INFO_COMMAND_INT, MAVLINK_MESSAGE_INFO_COMMAND_LONG, MAVLINK_MESSAGE_INFO_COMMAND_ACK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT, MAVLINK_MESSAGE_INFO_SET_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_GLOBAL_INT, MAVLINK_MESSAGE_INFO_POSITION_TARGET_GLOBAL_INT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, MAVLINK_MESSAGE_INFO_HIL_STATE, MAVLINK_MESSAGE_INFO_HIL_CONTROLS, MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE, MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_HIGHRES_IMU, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW_RAD, MAVLINK_MESSAGE_INFO_HIL_SENSOR, MAVLINK_MESSAGE_INFO_SIM_STATE, MAVLINK_MESSAGE_INFO_RADIO_STATUS, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_PROTOCOL, MAVLINK_MESSAGE_INFO_TIMESYNC, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_HIL_GPS, MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION, MAVLINK_MESSAGE_INFO_SCALED_IMU2, MAVLINK_MESSAGE_INFO_LOG_REQUEST_LIST, MAVLINK_MESSAGE_INFO_LOG_ENTRY, MAVLINK_MESSAGE_INFO_LOG_REQUEST_DATA, MAVLINK_MESSAGE_INFO_LOG_DATA, MAVLINK_MESSAGE_INFO_LOG_ERASE, MAVLINK_MESSAGE_INFO_LOG_REQUEST_END, MAVLINK_MESSAGE_INFO_GPS_INJECT_DATA, MAVLINK_MESSAGE_INFO_GPS2_RAW, MAVLINK_MESSAGE_INFO_POWER_STATUS, MAVLINK_MESSAGE_INFO_SERIAL_CONTROL, MAVLINK_MESSAGE_INFO_GPS_RTK, MAVLINK_MESSAGE_INFO_GPS2_RTK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_DATA_TRANSMISSION_HANDSHAKE, MAVLINK_MESSAGE_INFO_ENCAPSULATED_DATA, MAVLINK_MESSAGE_INFO_DISTANCE_SENSOR, MAVLINK_MESSAGE_INFO_TERRAIN_REQUEST, MAVLINK_MESSAGE_INFO_TERRAIN_DATA, MAVLINK_MESSAGE_INFO_TERRAIN_CHECK, MAVLINK_MESSAGE_INFO_TERRAIN_REPORT, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE2, MAVLINK_MESSAGE_INFO_ATT_POS_MOCAP, MAVLINK_MESSAGE_INFO_SET_ACTUATOR_CONTROL_TARGET, MAVLINK_MESSAGE_INFO_ACTUATOR_CONTROL_TARGET, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_BATTERY_STATUS, MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SENSOR_OFFSETS, MAVLINK_MESSAGE_INFO_SET_MAG_OFFSETS, MAVLINK_MESSAGE_INFO_MEMINFO, MAVLINK_MESSAGE_INFO_AP_ADC, MAVLINK_MESSAGE_INFO_DIGICAM_CONFIGURE, MAVLINK_MESSAGE_INFO_DIGICAM_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_CONFIGURE, MAVLINK_MESSAGE_INFO_MOUNT_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_STATUS, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_FENCE_POINT, MAVLINK_MESSAGE_INFO_FENCE_FETCH_POINT, MAVLINK_MESSAGE_INFO_FENCE_STATUS, MAVLINK_MESSAGE_INFO_AHRS, MAVLINK_MESSAGE_INFO_SIMSTATE, MAVLINK_MESSAGE_INFO_HWSTATUS, MAVLINK_MESSAGE_INFO_RADIO, MAVLINK_MESSAGE_INFO_LIMITS_STATUS, MAVLINK_MESSAGE_INFO_WIND, MAVLINK_MESSAGE_INFO_DATA16, MAVLINK_MESSAGE_INFO_DATA32, MAVLINK_MESSAGE_INFO_DATA64, MAVLINK_MESSAGE_INFO_DATA96, MAVLINK_MESSAGE_INFO_RANGEFINDER, MAVLINK_MESSAGE_INFO_AIRSPEED_AUTOCAL, MAVLINK_MESSAGE_INFO_RALLY_POINT, MAVLINK_MESSAGE_INFO_RALLY_FETCH_POINT, MAVLINK_MESSAGE_INFO_COMPASSMOT_STATUS, MAVLINK_MESSAGE_INFO_AHRS2, MAVLINK_MESSAGE_INFO_CAMERA_STATUS, MAVLINK_MESSAGE_INFO_CAMERA_FEEDBACK, MAVLINK_MESSAGE_INFO_BATTERY2, MAVLINK_MESSAGE_INFO_AHRS3, MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION_REQUEST, MAVLINK_MESSAGE_INFO_GIMBAL_REPORT, MAVLINK_MESSAGE_INFO_GIMBAL_CONTROL, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_V2_EXTENSION, MAVLINK_MESSAGE_INFO_MEMORY_VECT, MAVLINK_MESSAGE_INFO_DEBUG_VECT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT, MAVLINK_MESSAGE_INFO_STATUSTEXT, MAVLINK_MESSAGE_INFO_DEBUG, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}} +#define MAVLINK_MESSAGE_CRCS {50, 124, 137, 0, 237, 217, 104, 119, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 214, 159, 220, 168, 24, 23, 170, 144, 67, 115, 39, 246, 185, 104, 237, 244, 222, 212, 9, 254, 230, 28, 28, 132, 221, 232, 11, 153, 41, 39, 78, 196, 0, 0, 15, 3, 0, 0, 0, 0, 0, 167, 183, 119, 191, 118, 148, 21, 0, 243, 124, 0, 0, 38, 20, 158, 152, 143, 0, 0, 0, 106, 49, 22, 143, 140, 5, 150, 0, 231, 183, 63, 54, 47, 0, 0, 0, 0, 0, 0, 175, 102, 158, 208, 56, 93, 138, 108, 32, 185, 84, 34, 174, 124, 237, 4, 76, 128, 56, 116, 134, 237, 203, 250, 87, 203, 220, 25, 226, 46, 29, 223, 85, 6, 229, 203, 1, 195, 109, 168, 181, 47, 72, 131, 127, 0, 103, 154, 178, 200, 134, 219, 208, 188, 84, 22, 19, 21, 134, 0, 78, 68, 189, 127, 154, 21, 21, 144, 1, 234, 73, 181, 22, 83, 167, 138, 234, 240, 47, 189, 52, 174, 229, 85, 159, 186, 72, 0, 0, 0, 0, 92, 36, 71, 98, 0, 0, 0, 0, 0, 134, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 101, 50, 202, 17, 162, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 163, 105, 151, 35, 150, 0, 0, 0, 0, 0, 0, 90, 104, 85, 95, 130, 184, 81, 8, 204, 49, 170, 44, 83, 46, 0} #endif #include "../protocol.h" @@ -35,74 +35,167 @@ extern "C" { /** @brief */ +#ifndef HAVE_ENUM_ACCELCAL_VEHICLE_POS +#define HAVE_ENUM_ACCELCAL_VEHICLE_POS +typedef enum ACCELCAL_VEHICLE_POS +{ + ACCELCAL_VEHICLE_POS_LEVEL=1, /* | */ + ACCELCAL_VEHICLE_POS_LEFT=2, /* | */ + ACCELCAL_VEHICLE_POS_RIGHT=3, /* | */ + ACCELCAL_VEHICLE_POS_NOSEDOWN=4, /* | */ + ACCELCAL_VEHICLE_POS_NOSEUP=5, /* | */ + ACCELCAL_VEHICLE_POS_BACK=6, /* | */ + ACCELCAL_VEHICLE_POS_ENUM_END=7 /* | */ +} ACCELCAL_VEHICLE_POS; +#endif + +/** @brief Commands to be executed by the MAV. They can be executed on user request, or as part of a mission script. If the action is used in a mission, the parameter mapping to the waypoint/mission message is as follows: Param 1, Param 2, Param 3, Param 4, X: Param 5, Y:Param 6, Z:Param 7. This command list is similar what ARINC 424 is for commercial aircraft: A data format how to interpret waypoint/mission data. */ #ifndef HAVE_ENUM_MAV_CMD #define HAVE_ENUM_MAV_CMD typedef enum MAV_CMD { - MAV_CMD_NAV_WAYPOINT=16, /* Navigate to MISSION. |Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing)| Acceptance radius in meters (if the sphere with this radius is hit, the MISSION counts as reached)| 0 to pass through the WP, if > 0 radius in meters to pass by WP. Positive value for clockwise orbit, negative value for counter-clockwise orbit. Allows trajectory control.| Desired yaw angle at MISSION (rotary wing)| Latitude| Longitude| Altitude| */ - MAV_CMD_NAV_LOITER_UNLIM=17, /* Loiter around this MISSION an unlimited amount of time |Empty| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Desired yaw angle.| Latitude| Longitude| Altitude| */ - MAV_CMD_NAV_LOITER_TURNS=18, /* Loiter around this MISSION for X turns |Turns| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Desired yaw angle.| Latitude| Longitude| Altitude| */ - MAV_CMD_NAV_LOITER_TIME=19, /* Loiter around this MISSION for X seconds |Seconds (decimal)| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Desired yaw angle.| Latitude| Longitude| Altitude| */ - MAV_CMD_NAV_RETURN_TO_LAUNCH=20, /* Return to launch location |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_NAV_LAND=21, /* Land at location |Empty| Empty| Empty| Desired yaw angle.| Latitude| Longitude| Altitude| */ - MAV_CMD_NAV_TAKEOFF=22, /* Takeoff from ground / hand |Minimum pitch (if airspeed sensor present), desired pitch without sensor| Empty| Empty| Yaw angle (if magnetometer present), ignored without magnetometer| Latitude| Longitude| Altitude| */ - MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT=30, /* Continue on the current course and climb/descend to specified altitude. When the altitude is reached continue to the next command (i.e., don't proceed to the next command until the desired altitude is reached. |Empty| Empty| Empty| Empty| Empty| Empty| Desired altitude in meters| */ - MAV_CMD_NAV_ROI=80, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ - MAV_CMD_NAV_PATHPLANNING=81, /* Control autonomous path planning on the MAV. |0: Disable local obstacle avoidance / local path planning (without resetting map), 1: Enable local path planning, 2: Enable and reset local path planning| 0: Disable full path planning (without resetting map), 1: Enable, 2: Enable and reset map/occupancy grid, 3: Enable and reset planned route, but not occupancy grid| Empty| Yaw angle at goal, in compass degrees, [0..360]| Latitude/X of goal| Longitude/Y of goal| Altitude/Z of goal| */ - MAV_CMD_NAV_SPLINE_WAYPOINT=82, /* Navigate to MISSION using a spline path. |Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing)| Empty| Empty| Empty| Latitude/X of goal| Longitude/Y of goal| Altitude/Z of goal| */ - MAV_CMD_NAV_GUIDED_ENABLE=92, /* hand control over to an external controller |On / Off (> 0.5f on)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_NAV_LAST=95, /* NOP - This command is only used to mark the upper limit of the NAV/ACTION commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_CONDITION_DELAY=112, /* Delay mission state machine. |Delay in seconds (decimal)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_CONDITION_CHANGE_ALT=113, /* Ascend/descend at rate. Delay mission state machine until desired altitude reached. |Descent / Ascend rate (m/s)| Empty| Empty| Empty| Empty| Empty| Finish Altitude| */ - MAV_CMD_CONDITION_DISTANCE=114, /* Delay mission state machine until within desired distance of next NAV point. |Distance (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_CONDITION_YAW=115, /* Reach a certain target angle. |target angle: [0-360], 0 is north| speed during yaw change:[deg per second]| direction: negative: counter clockwise, positive: clockwise [-1,1]| relative offset or absolute angle: [ 1,0]| Empty| Empty| Empty| */ - MAV_CMD_CONDITION_LAST=159, /* NOP - This command is only used to mark the upper limit of the CONDITION commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_SET_MODE=176, /* Set system mode. |Mode, as defined by ENUM MAV_MODE| Custom mode - this is system specific, please refer to the individual autopilot specifications for details.| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_JUMP=177, /* Jump to the desired command in the mission list. Repeat this action only the specified number of times |Sequence number| Repeat count| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_CHANGE_SPEED=178, /* Change speed and/or throttle set points. |Speed type (0=Airspeed, 1=Ground Speed)| Speed (m/s, -1 indicates no change)| Throttle ( Percent, -1 indicates no change)| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_SET_HOME=179, /* Changes the home location either to the current location or a specified location. |Use current (1=use current location, 0=use specified location)| Empty| Empty| Empty| Latitude| Longitude| Altitude| */ - MAV_CMD_DO_SET_PARAMETER=180, /* Set a system parameter. Caution! Use of this command requires knowledge of the numeric enumeration value of the parameter. |Parameter number| Parameter value| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_SET_RELAY=181, /* Set a relay to a condition. |Relay number| Setting (1=on, 0=off, others possible depending on system hardware)| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_REPEAT_RELAY=182, /* Cycle a relay on and off for a desired number of cyles with a desired period. |Relay number| Cycle count| Cycle time (seconds, decimal)| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_SET_SERVO=183, /* Set a servo to a desired PWM value. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_REPEAT_SERVO=184, /* Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Cycle count| Cycle time (seconds)| Empty| Empty| Empty| */ - MAV_CMD_DO_FLIGHTTERMINATION=185, /* Terminate flight immediately |Flight termination activated if > 0.5| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_LAND_START=189, /* Mission command to perform a landing. This is used as a marker in a mission to tell the autopilot where a sequence of mission items that represents a landing starts. It may also be sent via a COMMAND_LONG to trigger a landing, in which case the nearest (geographically) landing sequence in the mission will be used. The Latitude/Longitude is optional, and may be set to 0/0 if not needed. If specified then it will be used to help find the closest landing sequence. |Empty| Empty| Empty| Empty| Latitude| Longitude| Empty| */ - MAV_CMD_DO_RALLY_LAND=190, /* Mission command to perform a landing from a rally point. |Break altitude (meters)| Landing speed (m/s)| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_GO_AROUND=191, /* Mission command to safely abort an autonmous landing. |Altitude (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_CONTROL_VIDEO=200, /* Control onboard camera system. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ - MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ - MAV_CMD_DO_DIGICAM_CONFIGURE=202, /* Mission command to configure an on-board camera controller system. |Modes: P, TV, AV, M, Etc| Shutter speed: Divisor number for one second| Aperture: F stop number| ISO number e.g. 80, 100, 200, Etc| Exposure type enumerator| Command Identity| Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off)| */ - MAV_CMD_DO_DIGICAM_CONTROL=203, /* Mission command to control an on-board camera controller system. |Session control e.g. show/hide lens| Zoom's absolute position| Zooming step value to offset zoom from the current position| Focus Locking, Unlocking or Re-locking| Shooting Command| Command Identity| Empty| */ - MAV_CMD_DO_MOUNT_CONFIGURE=204, /* Mission command to configure a camera or antenna mount |Mount operation mode (see MAV_MOUNT_MODE enum)| stabilize roll? (1 = yes, 0 = no)| stabilize pitch? (1 = yes, 0 = no)| stabilize yaw? (1 = yes, 0 = no)| Empty| Empty| Empty| */ - MAV_CMD_DO_MOUNT_CONTROL=205, /* Mission command to control a camera or antenna mount |pitch or lat in degrees, depending on mount mode.| roll or lon in degrees depending on mount mode| yaw or alt (in meters) depending on mount mode| reserved| reserved| reserved| MAV_MOUNT_MODE enum value| */ - MAV_CMD_DO_SET_CAM_TRIGG_DIST=206, /* Mission command to set CAM_TRIGG_DIST for this flight |Camera trigger distance (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_FENCE_ENABLE=207, /* Mission command to enable the geofence |enable? (0=disable, 1=enable)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_PARACHUTE=208, /* Mission command to trigger a parachute |action (0=disable, 1=enable, 2=release, for some systems see PARACHUTE_ACTION enum, not in general message set.)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_MOTOR_TEST=209, /* Mission command to perform motor test |motor sequence number (a number from 1 to max number of motors on the vehicle)| throttle type (0=throttle percentage, 1=PWM, 2=pilot throttle channel pass-through. See MOTOR_TEST_THROTTLE_TYPE enum)| throttle| timeout (in seconds)| Empty| Empty| Empty| */ - MAV_CMD_DO_INVERTED_FLIGHT=210, /* Change to/from inverted flight |inverted (0=normal, 1=inverted)| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_GRIPPER=211, /* Mission command to operate EPM gripper |gripper number (a number from 1 to max number of grippers on the vehicle)| gripper action (0=release, 1=grab. See GRIPPER_ACTIONS enum)| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_MOUNT_CONTROL_QUAT=220, /* Mission command to control a camera or antenna mount, using a quaternion as reference. |q1 - quaternion param #1, w (1 in null-rotation)| q2 - quaternion param #2, x (0 in null-rotation)| q3 - quaternion param #3, y (0 in null-rotation)| q4 - quaternion param #4, z (0 in null-rotation)| Empty| Empty| Empty| */ - MAV_CMD_DO_GUIDED_MASTER=221, /* set id of master controller |System ID| Component ID| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_DO_GUIDED_LIMITS=222, /* set limits for external control |timeout - maximum time (in seconds) that external controller will be allowed to control vehicle. 0 means no timeout| absolute altitude min (in meters, AMSL) - if vehicle moves below this alt, the command will be aborted and the mission will continue. 0 means no lower altitude limit| absolute altitude max (in meters)- if vehicle moves above this alt, the command will be aborted and the mission will continue. 0 means no upper altitude limit| horizontal move limit (in meters, AMSL) - if vehicle moves more than this distance from it's location at the moment the command was executed, the command will be aborted and the mission will continue. 0 means no horizontal altitude limit| Empty| Empty| Empty| */ - MAV_CMD_DO_LAST=240, /* NOP - This command is only used to mark the upper limit of the DO commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ - MAV_CMD_PREFLIGHT_CALIBRATION=241, /* Trigger calibration. This command will be only accepted if in pre-flight mode. |Gyro calibration: 0: no, 1: yes| Magnetometer calibration: 0: no, 1: yes| Ground pressure: 0: no, 1: yes| Radio calibration: 0: no, 1: yes| Accelerometer calibration: 0: no, 1: yes| Compass/Motor interference calibration: 0: no, 1: yes| Empty| */ - MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS=242, /* Set sensor offsets. This command will be only accepted if in pre-flight mode. |Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow, 5: second magnetometer| X axis offset (or generic dimension 1), in the sensor's raw units| Y axis offset (or generic dimension 2), in the sensor's raw units| Z axis offset (or generic dimension 3), in the sensor's raw units| Generic dimension 4, in the sensor's raw units| Generic dimension 5, in the sensor's raw units| Generic dimension 6, in the sensor's raw units| */ - MAV_CMD_PREFLIGHT_STORAGE=245, /* Request storage of different parameter values and logs. This command will be only accepted if in pre-flight mode. |Parameter storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM| Mission storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM| Reserved| Reserved| Empty| Empty| Empty| */ - MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN=246, /* Request the reboot or shutdown of system components. |0: Do nothing for autopilot, 1: Reboot autopilot, 2: Shutdown autopilot.| 0: Do nothing for onboard computer, 1: Reboot onboard computer, 2: Shutdown onboard computer.| Reserved| Reserved| Empty| Empty| Empty| */ - MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ - MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ - MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ - MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ - MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES=520, /* Request autopilot capabilities |1: Request autopilot version| Reserved (all remaining params)| */ - MAV_CMD_IMAGE_START_CAPTURE=2000, /* Start image capture sequence |Duration between two consecutive pictures (in seconds)| Number of images to capture total - 0 for unlimited capture| Resolution in megapixels (0.3 for 640x480, 1.3 for 1280x720, etc)| */ - MAV_CMD_IMAGE_STOP_CAPTURE=2001, /* Stop image capture sequence |Reserved| Reserved| */ - MAV_CMD_VIDEO_START_CAPTURE=2500, /* Starts video capture |Camera ID (0 for all cameras), 1 for first, 2 for second, etc.| Frames per second| Resolution in megapixels (0.3 for 640x480, 1.3 for 1280x720, etc)| */ - MAV_CMD_VIDEO_STOP_CAPTURE=2501, /* Stop the current video capture |Reserved| Reserved| */ - MAV_CMD_PANORAMA_CREATE=2800, /* Create a panorama at the current position |Viewing angle horizontal of the panorama (in degrees, +- 0.5 the total angle)| Viewing angle vertical of panorama (in degrees)| Speed of the horizontal rotation (in degrees per second)| Speed of the vertical rotation (in degrees per second)| */ - MAV_CMD_PAYLOAD_PREPARE_DEPLOY=30001, /* Deploy payload on a Lat / Lon / Alt position. This includes the navigation to reach the required release position and velocity. |Operation mode. 0: prepare single payload deploy (overwriting previous requests), but do not execute it. 1: execute payload deploy immediately (rejecting further deploy commands during execution, but allowing abort). 2: add payload deploy to existing deployment list.| Desired approach vector in degrees compass heading (0..360). A negative value indicates the system can define the approach vector at will.| Desired ground speed at release time. This can be overriden by the airframe in case it needs to meet minimum airspeed. A negative value indicates the system can define the ground speed at will.| Minimum altitude clearance to the release position in meters. A negative value indicates the system can define the clearance at will.| Latitude unscaled for MISSION_ITEM or in 1e7 degrees for MISSION_ITEM_INT| Longitude unscaled for MISSION_ITEM or in 1e7 degrees for MISSION_ITEM_INT| Altitude, in meters AMSL| */ - MAV_CMD_PAYLOAD_CONTROL_DEPLOY=30002, /* Control the payload deployment. |Operation mode. 0: Abort deployment, continue normal mission. 1: switch to payload deploment mode. 100: delete first payload deployment request. 101: delete all payload deployment requests.| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ - MAV_CMD_ENUM_END=30003 /* | */ + MAV_CMD_NAV_WAYPOINT=16, /* Navigate to MISSION. |Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing)| Acceptance radius in meters (if the sphere with this radius is hit, the MISSION counts as reached)| 0 to pass through the WP, if > 0 radius in meters to pass by WP. Positive value for clockwise orbit, negative value for counter-clockwise orbit. Allows trajectory control.| Desired yaw angle at MISSION (rotary wing). NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LOITER_UNLIM=17, /* Loiter around this MISSION an unlimited amount of time |Empty| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Desired yaw angle.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LOITER_TURNS=18, /* Loiter around this MISSION for X turns |Turns| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Forward moving aircraft this sets exit xtrack location: 0 for center of loiter wp, 1 for exit location. Else, this is desired yaw angle| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LOITER_TIME=19, /* Loiter around this MISSION for X seconds |Seconds (decimal)| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Forward moving aircraft this sets exit xtrack location: 0 for center of loiter wp, 1 for exit location. Else, this is desired yaw angle| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_RETURN_TO_LAUNCH=20, /* Return to launch location |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_NAV_LAND=21, /* Land at location |Abort Alt| Empty| Empty| Desired yaw angle. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_TAKEOFF=22, /* Takeoff from ground / hand |Minimum pitch (if airspeed sensor present), desired pitch without sensor| Empty| Empty| Yaw angle (if magnetometer present), ignored without magnetometer. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LAND_LOCAL=23, /* Land at local position (local frame only) |Landing target number (if available)| Maximum accepted offset from desired landing position [m] - computed magnitude from spherical coordinates: d = sqrt(x^2 + y^2 + z^2), which gives the maximum accepted distance between the desired landing position and the position where the vehicle is about to land| Landing descend rate [ms^-1]| Desired yaw angle [rad]| Y-axis position [m]| X-axis position [m]| Z-axis / ground level position [m]| */ + MAV_CMD_NAV_TAKEOFF_LOCAL=24, /* Takeoff from local position (local frame only) |Minimum pitch (if airspeed sensor present), desired pitch without sensor [rad]| Empty| Takeoff ascend rate [ms^-1]| Yaw angle [rad] (if magnetometer or another yaw estimation source present), ignored without one of these| Y-axis position [m]| X-axis position [m]| Z-axis position [m]| */ + MAV_CMD_NAV_FOLLOW=25, /* Vehicle following, i.e. this waypoint represents the position of a moving vehicle |Following logic to use (e.g. loitering or sinusoidal following) - depends on specific autopilot implementation| Ground speed of vehicle to be followed| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Desired yaw angle.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT=30, /* Continue on the current course and climb/descend to specified altitude. When the altitude is reached continue to the next command (i.e., don't proceed to the next command until the desired altitude is reached. |Climb or Descend (0 = Neutral, command completes when within 5m of this command's altitude, 1 = Climbing, command completes when at or above this command's altitude, 2 = Descending, command completes when at or below this command's altitude. | Empty| Empty| Empty| Empty| Empty| Desired altitude in meters| */ + MAV_CMD_NAV_LOITER_TO_ALT=31, /* Begin loiter at the specified Latitude and Longitude. If Lat=Lon=0, then loiter at the current position. Don't consider the navigation command complete (don't leave loiter) until the altitude has been reached. Additionally, if the Heading Required parameter is non-zero the aircraft will not leave the loiter until heading toward the next waypoint. |Heading Required (0 = False)| Radius in meters. If positive loiter clockwise, negative counter-clockwise, 0 means no change to standard loiter.| Empty| Forward moving aircraft this sets exit xtrack location: 0 for center of loiter wp, 1 for exit location| Latitude| Longitude| Altitude| */ + MAV_CMD_DO_FOLLOW=32, /* Being following a target |System ID (the system ID of the FOLLOW_TARGET beacon). Send 0 to disable follow-me and return to the default position hold mode| RESERVED| RESERVED| altitude flag: 0: Keep current altitude, 1: keep altitude difference to target, 2: go to a fixed altitude above home| altitude| RESERVED| TTL in seconds in which the MAV should go to the default position hold mode after a message rx timeout| */ + MAV_CMD_DO_FOLLOW_REPOSITION=33, /* Reposition the MAV after a follow target command has been sent |Camera q1 (where 0 is on the ray from the camera to the tracking device)| Camera q2| Camera q3| Camera q4| altitude offset from target (m)| X offset from target (m)| Y offset from target (m)| */ + MAV_CMD_NAV_ROI=80, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ + MAV_CMD_NAV_PATHPLANNING=81, /* Control autonomous path planning on the MAV. |0: Disable local obstacle avoidance / local path planning (without resetting map), 1: Enable local path planning, 2: Enable and reset local path planning| 0: Disable full path planning (without resetting map), 1: Enable, 2: Enable and reset map/occupancy grid, 3: Enable and reset planned route, but not occupancy grid| Empty| Yaw angle at goal, in compass degrees, [0..360]| Latitude/X of goal| Longitude/Y of goal| Altitude/Z of goal| */ + MAV_CMD_NAV_SPLINE_WAYPOINT=82, /* Navigate to MISSION using a spline path. |Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing)| Empty| Empty| Empty| Latitude/X of goal| Longitude/Y of goal| Altitude/Z of goal| */ + MAV_CMD_NAV_ALTITUDE_WAIT=83, /* Mission command to wait for an altitude or downwards vertical speed. This is meant for high altitude balloon launches, allowing the aircraft to be idle until either an altitude is reached or a negative vertical speed is reached (indicating early balloon burst). The wiggle time is how often to wiggle the control surfaces to prevent them seizing up. |altitude (m)| descent speed (m/s)| Wiggle Time (s)| Empty| Empty| Empty| Empty| */ + MAV_CMD_NAV_VTOL_TAKEOFF=84, /* Takeoff from ground using VTOL mode |Empty| Empty| Empty| Yaw angle in degrees. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_VTOL_LAND=85, /* Land using VTOL mode |Empty| Empty| Empty| Yaw angle in degrees. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_GUIDED_ENABLE=92, /* hand control over to an external controller |On / Off (> 0.5f on)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_NAV_DELAY=93, /* Delay the next navigation command a number of seconds or until a specified time |Delay in seconds (decimal, -1 to enable time-of-day fields)| hour (24h format, UTC, -1 to ignore)| minute (24h format, UTC, -1 to ignore)| second (24h format, UTC)| Empty| Empty| Empty| */ + MAV_CMD_NAV_PAYLOAD_PLACE=94, /* Descend and place payload. Vehicle descends until it detects a hanging payload has reached the ground, the gripper is opened to release the payload |Maximum distance to descend (meters)| Empty| Empty| Empty| Latitude (deg * 1E7)| Longitude (deg * 1E7)| Altitude (meters)| */ + MAV_CMD_NAV_LAST=95, /* NOP - This command is only used to mark the upper limit of the NAV/ACTION commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_DELAY=112, /* Delay mission state machine. |Delay in seconds (decimal)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_CHANGE_ALT=113, /* Ascend/descend at rate. Delay mission state machine until desired altitude reached. |Descent / Ascend rate (m/s)| Empty| Empty| Empty| Empty| Empty| Finish Altitude| */ + MAV_CMD_CONDITION_DISTANCE=114, /* Delay mission state machine until within desired distance of next NAV point. |Distance (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_YAW=115, /* Reach a certain target angle. |target angle: [0-360], 0 is north| speed during yaw change:[deg per second]| direction: negative: counter clockwise, positive: clockwise [-1,1]| relative offset or absolute angle: [ 1,0]| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_LAST=159, /* NOP - This command is only used to mark the upper limit of the CONDITION commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_MODE=176, /* Set system mode. |Mode, as defined by ENUM MAV_MODE| Custom mode - this is system specific, please refer to the individual autopilot specifications for details.| Custom sub mode - this is system specific, please refer to the individual autopilot specifications for details.| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_JUMP=177, /* Jump to the desired command in the mission list. Repeat this action only the specified number of times |Sequence number| Repeat count| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_CHANGE_SPEED=178, /* Change speed and/or throttle set points. |Speed type (0=Airspeed, 1=Ground Speed)| Speed (m/s, -1 indicates no change)| Throttle ( Percent, -1 indicates no change)| absolute or relative [0,1]| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_HOME=179, /* Changes the home location either to the current location or a specified location. |Use current (1=use current location, 0=use specified location)| Empty| Empty| Empty| Latitude| Longitude| Altitude| */ + MAV_CMD_DO_SET_PARAMETER=180, /* Set a system parameter. Caution! Use of this command requires knowledge of the numeric enumeration value of the parameter. |Parameter number| Parameter value| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_RELAY=181, /* Set a relay to a condition. |Relay number| Setting (1=on, 0=off, others possible depending on system hardware)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_REPEAT_RELAY=182, /* Cycle a relay on and off for a desired number of cyles with a desired period. |Relay number| Cycle count| Cycle time (seconds, decimal)| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_SERVO=183, /* Set a servo to a desired PWM value. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_REPEAT_SERVO=184, /* Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Cycle count| Cycle time (seconds)| Empty| Empty| Empty| */ + MAV_CMD_DO_FLIGHTTERMINATION=185, /* Terminate flight immediately |Flight termination activated if > 0.5| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_CHANGE_ALTITUDE=186, /* Change altitude set point. |Altitude in meters| Mav frame of new altitude (see MAV_FRAME)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_LAND_START=189, /* Mission command to perform a landing. This is used as a marker in a mission to tell the autopilot where a sequence of mission items that represents a landing starts. It may also be sent via a COMMAND_LONG to trigger a landing, in which case the nearest (geographically) landing sequence in the mission will be used. The Latitude/Longitude is optional, and may be set to 0/0 if not needed. If specified then it will be used to help find the closest landing sequence. |Empty| Empty| Empty| Empty| Latitude| Longitude| Empty| */ + MAV_CMD_DO_RALLY_LAND=190, /* Mission command to perform a landing from a rally point. |Break altitude (meters)| Landing speed (m/s)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_GO_AROUND=191, /* Mission command to safely abort an autonmous landing. |Altitude (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_REPOSITION=192, /* Reposition the vehicle to a specific WGS84 global position. |Ground speed, less than 0 (-1) for default| Bitmask of option flags, see the MAV_DO_REPOSITION_FLAGS enum.| Reserved| Yaw heading, NaN for unchanged. For planes indicates loiter direction (0: clockwise, 1: counter clockwise)| Latitude (deg * 1E7)| Longitude (deg * 1E7)| Altitude (meters)| */ + MAV_CMD_DO_PAUSE_CONTINUE=193, /* If in a GPS controlled position mode, hold the current position or continue. |0: Pause current mission or reposition command, hold current position. 1: Continue mission. A VTOL capable vehicle should enter hover mode (multicopter and VTOL planes). A plane should loiter with the default loiter radius.| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_DO_SET_REVERSE=194, /* Set moving direction to forward or reverse. |Direction (0=Forward, 1=Reverse)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_CONTROL_VIDEO=200, /* Control onboard camera system. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ + MAV_CMD_DO_DIGICAM_CONFIGURE=202, /* Mission command to configure an on-board camera controller system. |Modes: P, TV, AV, M, Etc| Shutter speed: Divisor number for one second| Aperture: F stop number| ISO number e.g. 80, 100, 200, Etc| Exposure type enumerator| Command Identity| Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off)| */ + MAV_CMD_DO_DIGICAM_CONTROL=203, /* Mission command to control an on-board camera controller system. |Session control e.g. show/hide lens| Zoom's absolute position| Zooming step value to offset zoom from the current position| Focus Locking, Unlocking or Re-locking| Shooting Command| Command Identity| Empty| */ + MAV_CMD_DO_MOUNT_CONFIGURE=204, /* Mission command to configure a camera or antenna mount |Mount operation mode (see MAV_MOUNT_MODE enum)| stabilize roll? (1 = yes, 0 = no)| stabilize pitch? (1 = yes, 0 = no)| stabilize yaw? (1 = yes, 0 = no)| Empty| Empty| Empty| */ + MAV_CMD_DO_MOUNT_CONTROL=205, /* Mission command to control a camera or antenna mount |pitch (WIP: DEPRECATED: or lat in degrees) depending on mount mode.| roll (WIP: DEPRECATED: or lon in degrees) depending on mount mode.| yaw (WIP: DEPRECATED: or alt in meters) depending on mount mode.| WIP: alt in meters depending on mount mode.| WIP: latitude in degrees * 1E7, set if appropriate mount mode.| WIP: longitude in degrees * 1E7, set if appropriate mount mode.| MAV_MOUNT_MODE enum value| */ + MAV_CMD_DO_SET_CAM_TRIGG_DIST=206, /* Mission command to set CAM_TRIGG_DIST for this flight |Camera trigger distance (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_FENCE_ENABLE=207, /* Mission command to enable the geofence |enable? (0=disable, 1=enable, 2=disable_floor_only)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_PARACHUTE=208, /* Mission command to trigger a parachute |action (0=disable, 1=enable, 2=release, for some systems see PARACHUTE_ACTION enum, not in general message set.)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_MOTOR_TEST=209, /* Mission command to perform motor test |motor sequence number (a number from 1 to max number of motors on the vehicle)| throttle type (0=throttle percentage, 1=PWM, 2=pilot throttle channel pass-through. See MOTOR_TEST_THROTTLE_TYPE enum)| throttle| timeout (in seconds)| Empty| Empty| Empty| */ + MAV_CMD_DO_INVERTED_FLIGHT=210, /* Change to/from inverted flight |inverted (0=normal, 1=inverted)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_GRIPPER=211, /* Mission command to operate EPM gripper |gripper number (a number from 1 to max number of grippers on the vehicle)| gripper action (0=release, 1=grab. See GRIPPER_ACTIONS enum)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_AUTOTUNE_ENABLE=212, /* Enable/disable autotune |enable (1: enable, 0:disable)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_NAV_SET_YAW_SPEED=213, /* Sets a desired vehicle turn angle and speed change |yaw angle to adjust steering by in centidegress| speed - normalized to 0 .. 1| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_MOUNT_CONTROL_QUAT=220, /* Mission command to control a camera or antenna mount, using a quaternion as reference. |q1 - quaternion param #1, w (1 in null-rotation)| q2 - quaternion param #2, x (0 in null-rotation)| q3 - quaternion param #3, y (0 in null-rotation)| q4 - quaternion param #4, z (0 in null-rotation)| Empty| Empty| Empty| */ + MAV_CMD_DO_GUIDED_MASTER=221, /* set id of master controller |System ID| Component ID| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_GUIDED_LIMITS=222, /* set limits for external control |timeout - maximum time (in seconds) that external controller will be allowed to control vehicle. 0 means no timeout| absolute altitude min (in meters, AMSL) - if vehicle moves below this alt, the command will be aborted and the mission will continue. 0 means no lower altitude limit| absolute altitude max (in meters)- if vehicle moves above this alt, the command will be aborted and the mission will continue. 0 means no upper altitude limit| horizontal move limit (in meters, AMSL) - if vehicle moves more than this distance from it's location at the moment the command was executed, the command will be aborted and the mission will continue. 0 means no horizontal altitude limit| Empty| Empty| Empty| */ + MAV_CMD_DO_ENGINE_CONTROL=223, /* Control vehicle engine. This is interpreted by the vehicles engine controller to change the target engine state. It is intended for vehicles with internal combustion engines |0: Stop engine, 1:Start Engine| 0: Warm start, 1:Cold start. Controls use of choke where applicable| Height delay (meters). This is for commanding engine start only after the vehicle has gained the specified height. Used in VTOL vehicles during takeoff to start engine after the aircraft is off the ground. Zero for no delay.| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_LAST=240, /* NOP - This command is only used to mark the upper limit of the DO commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_PREFLIGHT_CALIBRATION=241, /* Trigger calibration. This command will be only accepted if in pre-flight mode. Except for Temperature Calibration, only one sensor should be set in a single message and all others should be zero. |1: gyro calibration, 3: gyro temperature calibration| 1: magnetometer calibration| 1: ground pressure calibration| 1: radio RC calibration, 2: RC trim calibration| 1: accelerometer calibration, 2: board level calibration, 3: accelerometer temperature calibration| 1: APM: compass/motor interference calibration (PX4: airspeed calibration, deprecated), 2: airspeed calibration| 1: ESC calibration, 3: barometer temperature calibration| */ + MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS=242, /* Set sensor offsets. This command will be only accepted if in pre-flight mode. |Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow, 5: second magnetometer, 6: third magnetometer| X axis offset (or generic dimension 1), in the sensor's raw units| Y axis offset (or generic dimension 2), in the sensor's raw units| Z axis offset (or generic dimension 3), in the sensor's raw units| Generic dimension 4, in the sensor's raw units| Generic dimension 5, in the sensor's raw units| Generic dimension 6, in the sensor's raw units| */ + MAV_CMD_PREFLIGHT_UAVCAN=243, /* Trigger UAVCAN config. This command will be only accepted if in pre-flight mode. |1: Trigger actuator ID assignment and direction mapping.| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_PREFLIGHT_STORAGE=245, /* Request storage of different parameter values and logs. This command will be only accepted if in pre-flight mode. |Parameter storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM, 2: Reset to defaults| Mission storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM, 2: Reset to defaults| Onboard logging: 0: Ignore, 1: Start default rate logging, -1: Stop logging, > 1: start logging with rate of param 3 in Hz (e.g. set to 1000 for 1000 Hz logging)| Reserved| Empty| Empty| Empty| */ + MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN=246, /* Request the reboot or shutdown of system components. |0: Do nothing for autopilot, 1: Reboot autopilot, 2: Shutdown autopilot, 3: Reboot autopilot and keep it in the bootloader until upgraded.| 0: Do nothing for onboard computer, 1: Reboot onboard computer, 2: Shutdown onboard computer, 3: Reboot onboard computer and keep it in the bootloader until upgraded.| WIP: 0: Do nothing for camera, 1: Reboot onboard camera, 2: Shutdown onboard camera, 3: Reboot onboard camera and keep it in the bootloader until upgraded| WIP: 0: Do nothing for mount (e.g. gimbal), 1: Reboot mount, 2: Shutdown mount, 3: Reboot mount and keep it in the bootloader until upgraded| Reserved, send 0| Reserved, send 0| WIP: ID (e.g. camera ID -1 for all IDs)| */ + MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ + MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ + MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ + MAV_CMD_GET_HOME_POSITION=410, /* Request the home position from the vehicle. |Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ + MAV_CMD_GET_MESSAGE_INTERVAL=510, /* Request the interval between messages for a particular MAVLink message ID |The MAVLink message ID| */ + MAV_CMD_SET_MESSAGE_INTERVAL=511, /* Request the interval between messages for a particular MAVLink message ID. This interface replaces REQUEST_DATA_STREAM |The MAVLink message ID| The interval between two messages, in microseconds. Set to -1 to disable and 0 to request default rate.| */ + MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES=520, /* Request autopilot capabilities |1: Request autopilot version| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_CAMERA_INFORMATION=521, /* WIP: Request camera information (CAMERA_INFORMATION) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No action 1: Request camera capabilities| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_CAMERA_SETTINGS=522, /* WIP: Request camera settings (CAMERA_SETTINGS) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No Action 1: Request camera settings| Reserved (all remaining params)| */ + MAV_CMD_SET_CAMERA_SETTINGS_1=523, /* WIP: Set the camera settings part 1 (CAMERA_SETTINGS). Use NAN for values you don't want to change. |Camera ID (1 for first, 2 for second, etc.)| Aperture (1/value)| Shutter speed in seconds| ISO sensitivity| AE mode (Auto Exposure) (0: full auto 1: full manual 2: aperture priority 3: shutter priority)| EV value (when in auto exposure)| White balance (color temperature in K) (0: Auto WB)| */ + MAV_CMD_SET_CAMERA_SETTINGS_2=524, /* WIP: Set the camera settings part 2 (CAMERA_SETTINGS). Use NAN for values you don't want to change. |Camera ID (1 for first, 2 for second, etc.)| Camera mode (0: photo, 1: video)| Audio recording enabled (0: off 1: on)| Reserved for metering mode ID (Average, Center, Spot, etc.)| Reserved for image format ID (Jpeg/Raw/Jpeg+Raw)| Reserved for image quality ID (Compression)| Reserved for color mode ID (Neutral, Vivid, etc.)| */ + MAV_CMD_REQUEST_STORAGE_INFORMATION=525, /* WIP: Request storage information (STORAGE_INFORMATION) |Storage ID (0 for all, 1 for first, 2 for second, etc.)| 0: No Action 1: Request storage information| Reserved (all remaining params)| */ + MAV_CMD_STORAGE_FORMAT=526, /* WIP: Format a storage medium |Storage ID (1 for first, 2 for second, etc.)| 0: No action 1: Format storage| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS=527, /* WIP: Request camera capture status (CAMERA_CAPTURE_STATUS) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No Action 1: Request camera capture status| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_FLIGHT_INFORMATION=528, /* WIP: Request flight information (FLIGHT_INFORMATION) |1: Request flight information| Reserved (all remaining params)| */ + MAV_CMD_RESET_CAMERA_SETTINGS=529, /* WIP: Reset all camera settings to Factory Default (CAMERA_SETTINGS) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No Action 1: Reset all settings| Reserved (all remaining params)| */ + MAV_CMD_IMAGE_START_CAPTURE=2000, /* WIP: Start image capture sequence. Sends CAMERA_IMAGE_CAPTURED after each capture. |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Duration between two consecutive pictures (in seconds)| Number of images to capture total - 0 for unlimited capture| Resolution horizontal in pixels (set to -1 for highest resolution possible)| Resolution vertical in pixels (set to -1 for highest resolution possible)| */ + MAV_CMD_IMAGE_STOP_CAPTURE=2001, /* WIP: Stop image capture sequence |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Reserved| */ + MAV_CMD_REQUEST_CAMERA_IMAGE_CAPTURE=2002, /* WIP: Re-request a CAMERA_IMAGE_CAPTURE packet |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Sequence number for missing CAMERA_IMAGE_CAPTURE packet| Reserved (all remaining params)| */ + MAV_CMD_DO_TRIGGER_CONTROL=2003, /* Enable or disable on-board camera triggering system. |Trigger enable/disable (0 for disable, 1 for start), -1 to ignore| Shutter integration time (in ms), -1 to ignore| 1 to reset the trigger sequence, -1/0 to ignore| */ + MAV_CMD_VIDEO_START_CAPTURE=2500, /* WIP: Starts video capture (recording) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Frames per second, set to -1 for highest framerate possible.| Resolution horizontal in pixels (set to -1 for highest resolution possible)| Resolution vertical in pixels (set to -1 for highest resolution possible)| Frequency CAMERA_CAPTURE_STATUS messages should be sent while recording (0 for no messages, otherwise time in Hz)| */ + MAV_CMD_VIDEO_STOP_CAPTURE=2501, /* WIP: Stop the current video capture (recording) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Reserved| */ + MAV_CMD_LOGGING_START=2510, /* Request to start streaming logging data over MAVLink (see also LOGGING_DATA message) |Format: 0: ULog| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| */ + MAV_CMD_LOGGING_STOP=2511, /* Request to stop streaming log data over MAVLink |Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| */ + MAV_CMD_AIRFRAME_CONFIGURATION=2520, /* |Landing gear ID (default: 0, -1 for all)| Landing gear position (Down: 0, Up: 1, NAN for no change)| Reserved, set to NAN| Reserved, set to NAN| Reserved, set to NAN| Reserved, set to NAN| Reserved, set to NAN| */ + MAV_CMD_PANORAMA_CREATE=2800, /* Create a panorama at the current position |Viewing angle horizontal of the panorama (in degrees, +- 0.5 the total angle)| Viewing angle vertical of panorama (in degrees)| Speed of the horizontal rotation (in degrees per second)| Speed of the vertical rotation (in degrees per second)| */ + MAV_CMD_DO_VTOL_TRANSITION=3000, /* Request VTOL transition |The target VTOL state, as defined by ENUM MAV_VTOL_STATE. Only MAV_VTOL_STATE_MC and MAV_VTOL_STATE_FW can be used.| */ + MAV_CMD_SET_GUIDED_SUBMODE_STANDARD=4000, /* This command sets the submode to standard guided when vehicle is in guided mode. The vehicle holds position and altitude and the user can input the desired velocites along all three axes. + | */ + MAV_CMD_SET_GUIDED_SUBMODE_CIRCLE=4001, /* This command sets submode circle when vehicle is in guided mode. Vehicle flies along a circle facing the center of the circle. The user can input the velocity along the circle and change the radius. If no input is given the vehicle will hold position. + |Radius of desired circle in CIRCLE_MODE| User defined| User defined| User defined| Unscaled target latitude of center of circle in CIRCLE_MODE| Unscaled target longitude of center of circle in CIRCLE_MODE| */ + MAV_CMD_NAV_FENCE_RETURN_POINT=5000, /* Fence return point. There can only be one fence return point. + |Reserved| Reserved| Reserved| Reserved| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION=5001, /* Fence vertex for an inclusion polygon. The vehicle must stay within this area. Minimum of 3 vertices required. + |Polygon vertex count| Reserved| Reserved| Reserved| Latitude| Longitude| Reserved| */ + MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION=5002, /* Fence vertex for an exclusion polygon. The vehicle must stay outside this area. Minimum of 3 vertices required. + |Polygon vertex count| Reserved| Reserved| Reserved| Latitude| Longitude| Reserved| */ + MAV_CMD_NAV_RALLY_POINT=5100, /* Rally point. You can have multiple rally points defined. + |Reserved| Reserved| Reserved| Reserved| Latitude| Longitude| Altitude| */ + MAV_CMD_PAYLOAD_PREPARE_DEPLOY=30001, /* Deploy payload on a Lat / Lon / Alt position. This includes the navigation to reach the required release position and velocity. |Operation mode. 0: prepare single payload deploy (overwriting previous requests), but do not execute it. 1: execute payload deploy immediately (rejecting further deploy commands during execution, but allowing abort). 2: add payload deploy to existing deployment list.| Desired approach vector in degrees compass heading (0..360). A negative value indicates the system can define the approach vector at will.| Desired ground speed at release time. This can be overriden by the airframe in case it needs to meet minimum airspeed. A negative value indicates the system can define the ground speed at will.| Minimum altitude clearance to the release position in meters. A negative value indicates the system can define the clearance at will.| Latitude unscaled for MISSION_ITEM or in 1e7 degrees for MISSION_ITEM_INT| Longitude unscaled for MISSION_ITEM or in 1e7 degrees for MISSION_ITEM_INT| Altitude, in meters AMSL| */ + MAV_CMD_PAYLOAD_CONTROL_DEPLOY=30002, /* Control the payload deployment. |Operation mode. 0: Abort deployment, continue normal mission. 1: switch to payload deploment mode. 100: delete first payload deployment request. 101: delete all payload deployment requests.| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_WAYPOINT_USER_1=31000, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_2=31001, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_3=31002, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_4=31003, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_5=31004, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_1=31005, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_2=31006, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_3=31007, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_4=31008, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_5=31009, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_USER_1=31010, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_2=31011, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_3=31012, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_4=31013, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_5=31014, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_POWER_OFF_INITIATED=42000, /* A system wide power-off event has been initiated. |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_SOLO_BTN_FLY_CLICK=42001, /* FLY button has been clicked. |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_SOLO_BTN_FLY_HOLD=42002, /* FLY button has been held for 1.5 seconds. |Takeoff altitude| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_SOLO_BTN_PAUSE_CLICK=42003, /* PAUSE button has been clicked. |1 if Solo is in a shot mode, 0 otherwise| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_START_MAG_CAL=42424, /* Initiate a magnetometer calibration |uint8_t bitmask of magnetometers (0 means all)| Automatically retry on failure (0=no retry, 1=retry).| Save without user input (0=require input, 1=autosave).| Delay (seconds)| Autoreboot (0=user reboot, 1=autoreboot)| Empty| Empty| */ + MAV_CMD_DO_ACCEPT_MAG_CAL=42425, /* Initiate a magnetometer calibration |uint8_t bitmask of magnetometers (0 means all)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_CANCEL_MAG_CAL=42426, /* Cancel a running magnetometer calibration |uint8_t bitmask of magnetometers (0 means all)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_SET_FACTORY_TEST_MODE=42427, /* Command autopilot to get into factory test/diagnostic mode |0 means get out of test mode, 1 means get into test mode| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_SEND_BANNER=42428, /* Reply with the version banner |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_ACCELCAL_VEHICLE_POS=42429, /* Used when doing accelerometer calibration. When sent to the GCS tells it what position to put the vehicle in. When sent to the vehicle says what position the vehicle is in. |Position, one of the ACCELCAL_VEHICLE_POS enum values| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_GIMBAL_RESET=42501, /* Causes the gimbal to reset and boot as if it was just powered on |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_GIMBAL_AXIS_CALIBRATION_STATUS=42502, /* Reports progress and success or failure of gimbal axis calibration procedure |Gimbal axis we're reporting calibration progress for| Current calibration progress for this axis, 0x64=100%| Status of the calibration| Empty| Empty| Empty| Empty| */ + MAV_CMD_GIMBAL_REQUEST_AXIS_CALIBRATION=42503, /* Starts commutation calibration on the gimbal |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_GIMBAL_FULL_RESET=42505, /* Erases gimbal application and parameters |Magic number| Magic number| Magic number| Magic number| Magic number| Magic number| Magic number| */ + MAV_CMD_ENUM_END=42506 /* | */ } MAV_CMD; #endif @@ -111,13 +204,13 @@ typedef enum MAV_CMD #define HAVE_ENUM_LIMITS_STATE typedef enum LIMITS_STATE { - LIMITS_INIT=0, /* pre-initialization | */ - LIMITS_DISABLED=1, /* disabled | */ - LIMITS_ENABLED=2, /* checking limits | */ - LIMITS_TRIGGERED=3, /* a limit has been breached | */ - LIMITS_RECOVERING=4, /* taking action eg. RTL | */ - LIMITS_RECOVERED=5, /* we're no longer in breach of a limit | */ - LIMITS_STATE_ENUM_END=6 /* | */ + LIMITS_INIT=0, /* pre-initialization | */ + LIMITS_DISABLED=1, /* disabled | */ + LIMITS_ENABLED=2, /* checking limits | */ + LIMITS_TRIGGERED=3, /* a limit has been breached | */ + LIMITS_RECOVERING=4, /* taking action eg. RTL | */ + LIMITS_RECOVERED=5, /* we're no longer in breach of a limit | */ + LIMITS_STATE_ENUM_END=6 /* | */ } LIMITS_STATE; #endif @@ -126,10 +219,10 @@ typedef enum LIMITS_STATE #define HAVE_ENUM_LIMIT_MODULE typedef enum LIMIT_MODULE { - LIMIT_GPSLOCK=1, /* pre-initialization | */ - LIMIT_GEOFENCE=2, /* disabled | */ - LIMIT_ALTITUDE=4, /* checking limits | */ - LIMIT_MODULE_ENUM_END=5 /* | */ + LIMIT_GPSLOCK=1, /* pre-initialization | */ + LIMIT_GEOFENCE=2, /* disabled | */ + LIMIT_ALTITUDE=4, /* checking limits | */ + LIMIT_MODULE_ENUM_END=5 /* | */ } LIMIT_MODULE; #endif @@ -138,9 +231,9 @@ typedef enum LIMIT_MODULE #define HAVE_ENUM_RALLY_FLAGS typedef enum RALLY_FLAGS { - FAVORABLE_WIND=1, /* Flag set when requiring favorable winds for landing. | */ - LAND_IMMEDIATELY=2, /* Flag set when plane is to immediately descend to break altitude and land without GCS intervention. Flag not set when plane is to loiter at Rally point until commanded to land. | */ - RALLY_FLAGS_ENUM_END=3 /* | */ + FAVORABLE_WIND=1, /* Flag set when requiring favorable winds for landing. | */ + LAND_IMMEDIATELY=2, /* Flag set when plane is to immediately descend to break altitude and land without GCS intervention. Flag not set when plane is to loiter at Rally point until commanded to land. | */ + RALLY_FLAGS_ENUM_END=3 /* | */ } RALLY_FLAGS; #endif @@ -149,33 +242,21 @@ typedef enum RALLY_FLAGS #define HAVE_ENUM_PARACHUTE_ACTION typedef enum PARACHUTE_ACTION { - PARACHUTE_DISABLE=0, /* Disable parachute release | */ - PARACHUTE_ENABLE=1, /* Enable parachute release | */ - PARACHUTE_RELEASE=2, /* Release parachute | */ - PARACHUTE_ACTION_ENUM_END=3 /* | */ + PARACHUTE_DISABLE=0, /* Disable parachute release | */ + PARACHUTE_ENABLE=1, /* Enable parachute release | */ + PARACHUTE_RELEASE=2, /* Release parachute | */ + PARACHUTE_ACTION_ENUM_END=3 /* | */ } PARACHUTE_ACTION; #endif -/** @brief */ -#ifndef HAVE_ENUM_MOTOR_TEST_THROTTLE_TYPE -#define HAVE_ENUM_MOTOR_TEST_THROTTLE_TYPE -typedef enum MOTOR_TEST_THROTTLE_TYPE -{ - MOTOR_TEST_THROTTLE_PERCENT=0, /* throttle as a percentage from 0 ~ 100 | */ - MOTOR_TEST_THROTTLE_PWM=1, /* throttle as an absolute PWM value (normally in range of 1000~2000) | */ - MOTOR_TEST_THROTTLE_PILOT=2, /* throttle pass-through from pilot's transmitter | */ - MOTOR_TEST_THROTTLE_TYPE_ENUM_END=3 /* | */ -} MOTOR_TEST_THROTTLE_TYPE; -#endif - /** @brief Gripper actions. */ #ifndef HAVE_ENUM_GRIPPER_ACTIONS #define HAVE_ENUM_GRIPPER_ACTIONS typedef enum GRIPPER_ACTIONS { - GRIPPER_ACTION_RELEASE=0, /* gripper release of cargo | */ - GRIPPER_ACTION_GRAB=1, /* gripper grabs onto cargo | */ - GRIPPER_ACTIONS_ENUM_END=2 /* | */ + GRIPPER_ACTION_RELEASE=0, /* gripper release of cargo | */ + GRIPPER_ACTION_GRAB=1, /* gripper grabs onto cargo | */ + GRIPPER_ACTIONS_ENUM_END=2 /* | */ } GRIPPER_ACTIONS; #endif @@ -184,14 +265,14 @@ typedef enum GRIPPER_ACTIONS #define HAVE_ENUM_CAMERA_STATUS_TYPES typedef enum CAMERA_STATUS_TYPES { - CAMERA_STATUS_TYPE_HEARTBEAT=0, /* Camera heartbeat, announce camera component ID at 1hz | */ - CAMERA_STATUS_TYPE_TRIGGER=1, /* Camera image triggered | */ - CAMERA_STATUS_TYPE_DISCONNECT=2, /* Camera connection lost | */ - CAMERA_STATUS_TYPE_ERROR=3, /* Camera unknown error | */ - CAMERA_STATUS_TYPE_LOWBATT=4, /* Camera battery low. Parameter p1 shows reported voltage | */ - CAMERA_STATUS_TYPE_LOWSTORE=5, /* Camera storage low. Parameter p1 shows reported shots remaining | */ - CAMERA_STATUS_TYPE_LOWSTOREV=6, /* Camera storage low. Parameter p1 shows reported video minutes remaining | */ - CAMERA_STATUS_TYPES_ENUM_END=7 /* | */ + CAMERA_STATUS_TYPE_HEARTBEAT=0, /* Camera heartbeat, announce camera component ID at 1hz | */ + CAMERA_STATUS_TYPE_TRIGGER=1, /* Camera image triggered | */ + CAMERA_STATUS_TYPE_DISCONNECT=2, /* Camera connection lost | */ + CAMERA_STATUS_TYPE_ERROR=3, /* Camera unknown error | */ + CAMERA_STATUS_TYPE_LOWBATT=4, /* Camera battery low. Parameter p1 shows reported voltage | */ + CAMERA_STATUS_TYPE_LOWSTORE=5, /* Camera storage low. Parameter p1 shows reported shots remaining | */ + CAMERA_STATUS_TYPE_LOWSTOREV=6, /* Camera storage low. Parameter p1 shows reported video minutes remaining | */ + CAMERA_STATUS_TYPES_ENUM_END=7 /* | */ } CAMERA_STATUS_TYPES; #endif @@ -200,15 +281,443 @@ typedef enum CAMERA_STATUS_TYPES #define HAVE_ENUM_CAMERA_FEEDBACK_FLAGS typedef enum CAMERA_FEEDBACK_FLAGS { - VIDEO=1, /* Shooting video, not stills | */ - BADEXPOSURE=2, /* Unable to achieve requested exposure (e.g. shutter speed too low) | */ - CLOSEDLOOP=3, /* Closed loop feedback from camera, we know for sure it has successfully taken a picture | */ - OPENLOOP=4, /* Open loop camera, an image trigger has been requested but we can't know for sure it has successfully taken a picture | */ - CAMERA_FEEDBACK_FLAGS_ENUM_END=5 /* | */ + CAMERA_FEEDBACK_PHOTO=0, /* Shooting photos, not video | */ + CAMERA_FEEDBACK_VIDEO=1, /* Shooting video, not stills | */ + CAMERA_FEEDBACK_BADEXPOSURE=2, /* Unable to achieve requested exposure (e.g. shutter speed too low) | */ + CAMERA_FEEDBACK_CLOSEDLOOP=3, /* Closed loop feedback from camera, we know for sure it has successfully taken a picture | */ + CAMERA_FEEDBACK_OPENLOOP=4, /* Open loop camera, an image trigger has been requested but we can't know for sure it has successfully taken a picture | */ + CAMERA_FEEDBACK_FLAGS_ENUM_END=5 /* | */ } CAMERA_FEEDBACK_FLAGS; #endif -#include "../common/common.h" +/** @brief */ +#ifndef HAVE_ENUM_MAV_MODE_GIMBAL +#define HAVE_ENUM_MAV_MODE_GIMBAL +typedef enum MAV_MODE_GIMBAL +{ + MAV_MODE_GIMBAL_UNINITIALIZED=0, /* Gimbal is powered on but has not started initializing yet | */ + MAV_MODE_GIMBAL_CALIBRATING_PITCH=1, /* Gimbal is currently running calibration on the pitch axis | */ + MAV_MODE_GIMBAL_CALIBRATING_ROLL=2, /* Gimbal is currently running calibration on the roll axis | */ + MAV_MODE_GIMBAL_CALIBRATING_YAW=3, /* Gimbal is currently running calibration on the yaw axis | */ + MAV_MODE_GIMBAL_INITIALIZED=4, /* Gimbal has finished calibrating and initializing, but is relaxed pending reception of first rate command from copter | */ + MAV_MODE_GIMBAL_ACTIVE=5, /* Gimbal is actively stabilizing | */ + MAV_MODE_GIMBAL_RATE_CMD_TIMEOUT=6, /* Gimbal is relaxed because it missed more than 10 expected rate command messages in a row. Gimbal will move back to active mode when it receives a new rate command | */ + MAV_MODE_GIMBAL_ENUM_END=7 /* | */ +} MAV_MODE_GIMBAL; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GIMBAL_AXIS +#define HAVE_ENUM_GIMBAL_AXIS +typedef enum GIMBAL_AXIS +{ + GIMBAL_AXIS_YAW=0, /* Gimbal yaw axis | */ + GIMBAL_AXIS_PITCH=1, /* Gimbal pitch axis | */ + GIMBAL_AXIS_ROLL=2, /* Gimbal roll axis | */ + GIMBAL_AXIS_ENUM_END=3 /* | */ +} GIMBAL_AXIS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GIMBAL_AXIS_CALIBRATION_STATUS +#define HAVE_ENUM_GIMBAL_AXIS_CALIBRATION_STATUS +typedef enum GIMBAL_AXIS_CALIBRATION_STATUS +{ + GIMBAL_AXIS_CALIBRATION_STATUS_IN_PROGRESS=0, /* Axis calibration is in progress | */ + GIMBAL_AXIS_CALIBRATION_STATUS_SUCCEEDED=1, /* Axis calibration succeeded | */ + GIMBAL_AXIS_CALIBRATION_STATUS_FAILED=2, /* Axis calibration failed | */ + GIMBAL_AXIS_CALIBRATION_STATUS_ENUM_END=3 /* | */ +} GIMBAL_AXIS_CALIBRATION_STATUS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GIMBAL_AXIS_CALIBRATION_REQUIRED +#define HAVE_ENUM_GIMBAL_AXIS_CALIBRATION_REQUIRED +typedef enum GIMBAL_AXIS_CALIBRATION_REQUIRED +{ + GIMBAL_AXIS_CALIBRATION_REQUIRED_UNKNOWN=0, /* Whether or not this axis requires calibration is unknown at this time | */ + GIMBAL_AXIS_CALIBRATION_REQUIRED_TRUE=1, /* This axis requires calibration | */ + GIMBAL_AXIS_CALIBRATION_REQUIRED_FALSE=2, /* This axis does not require calibration | */ + GIMBAL_AXIS_CALIBRATION_REQUIRED_ENUM_END=3 /* | */ +} GIMBAL_AXIS_CALIBRATION_REQUIRED; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_HEARTBEAT_STATUS +#define HAVE_ENUM_GOPRO_HEARTBEAT_STATUS +typedef enum GOPRO_HEARTBEAT_STATUS +{ + GOPRO_HEARTBEAT_STATUS_DISCONNECTED=0, /* No GoPro connected | */ + GOPRO_HEARTBEAT_STATUS_INCOMPATIBLE=1, /* The detected GoPro is not HeroBus compatible | */ + GOPRO_HEARTBEAT_STATUS_CONNECTED=2, /* A HeroBus compatible GoPro is connected | */ + GOPRO_HEARTBEAT_STATUS_ERROR=3, /* An unrecoverable error was encountered with the connected GoPro, it may require a power cycle | */ + GOPRO_HEARTBEAT_STATUS_ENUM_END=4 /* | */ +} GOPRO_HEARTBEAT_STATUS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_HEARTBEAT_FLAGS +#define HAVE_ENUM_GOPRO_HEARTBEAT_FLAGS +typedef enum GOPRO_HEARTBEAT_FLAGS +{ + GOPRO_FLAG_RECORDING=1, /* GoPro is currently recording | */ + GOPRO_HEARTBEAT_FLAGS_ENUM_END=2 /* | */ +} GOPRO_HEARTBEAT_FLAGS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_REQUEST_STATUS +#define HAVE_ENUM_GOPRO_REQUEST_STATUS +typedef enum GOPRO_REQUEST_STATUS +{ + GOPRO_REQUEST_SUCCESS=0, /* The write message with ID indicated succeeded | */ + GOPRO_REQUEST_FAILED=1, /* The write message with ID indicated failed | */ + GOPRO_REQUEST_STATUS_ENUM_END=2 /* | */ +} GOPRO_REQUEST_STATUS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_COMMAND +#define HAVE_ENUM_GOPRO_COMMAND +typedef enum GOPRO_COMMAND +{ + GOPRO_COMMAND_POWER=0, /* (Get/Set) | */ + GOPRO_COMMAND_CAPTURE_MODE=1, /* (Get/Set) | */ + GOPRO_COMMAND_SHUTTER=2, /* (___/Set) | */ + GOPRO_COMMAND_BATTERY=3, /* (Get/___) | */ + GOPRO_COMMAND_MODEL=4, /* (Get/___) | */ + GOPRO_COMMAND_VIDEO_SETTINGS=5, /* (Get/Set) | */ + GOPRO_COMMAND_LOW_LIGHT=6, /* (Get/Set) | */ + GOPRO_COMMAND_PHOTO_RESOLUTION=7, /* (Get/Set) | */ + GOPRO_COMMAND_PHOTO_BURST_RATE=8, /* (Get/Set) | */ + GOPRO_COMMAND_PROTUNE=9, /* (Get/Set) | */ + GOPRO_COMMAND_PROTUNE_WHITE_BALANCE=10, /* (Get/Set) Hero 3+ Only | */ + GOPRO_COMMAND_PROTUNE_COLOUR=11, /* (Get/Set) Hero 3+ Only | */ + GOPRO_COMMAND_PROTUNE_GAIN=12, /* (Get/Set) Hero 3+ Only | */ + GOPRO_COMMAND_PROTUNE_SHARPNESS=13, /* (Get/Set) Hero 3+ Only | */ + GOPRO_COMMAND_PROTUNE_EXPOSURE=14, /* (Get/Set) Hero 3+ Only | */ + GOPRO_COMMAND_TIME=15, /* (Get/Set) | */ + GOPRO_COMMAND_CHARGING=16, /* (Get/Set) | */ + GOPRO_COMMAND_ENUM_END=17 /* | */ +} GOPRO_COMMAND; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_CAPTURE_MODE +#define HAVE_ENUM_GOPRO_CAPTURE_MODE +typedef enum GOPRO_CAPTURE_MODE +{ + GOPRO_CAPTURE_MODE_VIDEO=0, /* Video mode | */ + GOPRO_CAPTURE_MODE_PHOTO=1, /* Photo mode | */ + GOPRO_CAPTURE_MODE_BURST=2, /* Burst mode, hero 3+ only | */ + GOPRO_CAPTURE_MODE_TIME_LAPSE=3, /* Time lapse mode, hero 3+ only | */ + GOPRO_CAPTURE_MODE_MULTI_SHOT=4, /* Multi shot mode, hero 4 only | */ + GOPRO_CAPTURE_MODE_PLAYBACK=5, /* Playback mode, hero 4 only, silver only except when LCD or HDMI is connected to black | */ + GOPRO_CAPTURE_MODE_SETUP=6, /* Playback mode, hero 4 only | */ + GOPRO_CAPTURE_MODE_UNKNOWN=255, /* Mode not yet known | */ + GOPRO_CAPTURE_MODE_ENUM_END=256 /* | */ +} GOPRO_CAPTURE_MODE; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_RESOLUTION +#define HAVE_ENUM_GOPRO_RESOLUTION +typedef enum GOPRO_RESOLUTION +{ + GOPRO_RESOLUTION_480p=0, /* 848 x 480 (480p) | */ + GOPRO_RESOLUTION_720p=1, /* 1280 x 720 (720p) | */ + GOPRO_RESOLUTION_960p=2, /* 1280 x 960 (960p) | */ + GOPRO_RESOLUTION_1080p=3, /* 1920 x 1080 (1080p) | */ + GOPRO_RESOLUTION_1440p=4, /* 1920 x 1440 (1440p) | */ + GOPRO_RESOLUTION_2_7k_17_9=5, /* 2704 x 1440 (2.7k-17:9) | */ + GOPRO_RESOLUTION_2_7k_16_9=6, /* 2704 x 1524 (2.7k-16:9) | */ + GOPRO_RESOLUTION_2_7k_4_3=7, /* 2704 x 2028 (2.7k-4:3) | */ + GOPRO_RESOLUTION_4k_16_9=8, /* 3840 x 2160 (4k-16:9) | */ + GOPRO_RESOLUTION_4k_17_9=9, /* 4096 x 2160 (4k-17:9) | */ + GOPRO_RESOLUTION_720p_SUPERVIEW=10, /* 1280 x 720 (720p-SuperView) | */ + GOPRO_RESOLUTION_1080p_SUPERVIEW=11, /* 1920 x 1080 (1080p-SuperView) | */ + GOPRO_RESOLUTION_2_7k_SUPERVIEW=12, /* 2704 x 1520 (2.7k-SuperView) | */ + GOPRO_RESOLUTION_4k_SUPERVIEW=13, /* 3840 x 2160 (4k-SuperView) | */ + GOPRO_RESOLUTION_ENUM_END=14 /* | */ +} GOPRO_RESOLUTION; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_FRAME_RATE +#define HAVE_ENUM_GOPRO_FRAME_RATE +typedef enum GOPRO_FRAME_RATE +{ + GOPRO_FRAME_RATE_12=0, /* 12 FPS | */ + GOPRO_FRAME_RATE_15=1, /* 15 FPS | */ + GOPRO_FRAME_RATE_24=2, /* 24 FPS | */ + GOPRO_FRAME_RATE_25=3, /* 25 FPS | */ + GOPRO_FRAME_RATE_30=4, /* 30 FPS | */ + GOPRO_FRAME_RATE_48=5, /* 48 FPS | */ + GOPRO_FRAME_RATE_50=6, /* 50 FPS | */ + GOPRO_FRAME_RATE_60=7, /* 60 FPS | */ + GOPRO_FRAME_RATE_80=8, /* 80 FPS | */ + GOPRO_FRAME_RATE_90=9, /* 90 FPS | */ + GOPRO_FRAME_RATE_100=10, /* 100 FPS | */ + GOPRO_FRAME_RATE_120=11, /* 120 FPS | */ + GOPRO_FRAME_RATE_240=12, /* 240 FPS | */ + GOPRO_FRAME_RATE_12_5=13, /* 12.5 FPS | */ + GOPRO_FRAME_RATE_ENUM_END=14 /* | */ +} GOPRO_FRAME_RATE; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_FIELD_OF_VIEW +#define HAVE_ENUM_GOPRO_FIELD_OF_VIEW +typedef enum GOPRO_FIELD_OF_VIEW +{ + GOPRO_FIELD_OF_VIEW_WIDE=0, /* 0x00: Wide | */ + GOPRO_FIELD_OF_VIEW_MEDIUM=1, /* 0x01: Medium | */ + GOPRO_FIELD_OF_VIEW_NARROW=2, /* 0x02: Narrow | */ + GOPRO_FIELD_OF_VIEW_ENUM_END=3 /* | */ +} GOPRO_FIELD_OF_VIEW; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_VIDEO_SETTINGS_FLAGS +#define HAVE_ENUM_GOPRO_VIDEO_SETTINGS_FLAGS +typedef enum GOPRO_VIDEO_SETTINGS_FLAGS +{ + GOPRO_VIDEO_SETTINGS_TV_MODE=1, /* 0=NTSC, 1=PAL | */ + GOPRO_VIDEO_SETTINGS_FLAGS_ENUM_END=2 /* | */ +} GOPRO_VIDEO_SETTINGS_FLAGS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_PHOTO_RESOLUTION +#define HAVE_ENUM_GOPRO_PHOTO_RESOLUTION +typedef enum GOPRO_PHOTO_RESOLUTION +{ + GOPRO_PHOTO_RESOLUTION_5MP_MEDIUM=0, /* 5MP Medium | */ + GOPRO_PHOTO_RESOLUTION_7MP_MEDIUM=1, /* 7MP Medium | */ + GOPRO_PHOTO_RESOLUTION_7MP_WIDE=2, /* 7MP Wide | */ + GOPRO_PHOTO_RESOLUTION_10MP_WIDE=3, /* 10MP Wide | */ + GOPRO_PHOTO_RESOLUTION_12MP_WIDE=4, /* 12MP Wide | */ + GOPRO_PHOTO_RESOLUTION_ENUM_END=5 /* | */ +} GOPRO_PHOTO_RESOLUTION; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_PROTUNE_WHITE_BALANCE +#define HAVE_ENUM_GOPRO_PROTUNE_WHITE_BALANCE +typedef enum GOPRO_PROTUNE_WHITE_BALANCE +{ + GOPRO_PROTUNE_WHITE_BALANCE_AUTO=0, /* Auto | */ + GOPRO_PROTUNE_WHITE_BALANCE_3000K=1, /* 3000K | */ + GOPRO_PROTUNE_WHITE_BALANCE_5500K=2, /* 5500K | */ + GOPRO_PROTUNE_WHITE_BALANCE_6500K=3, /* 6500K | */ + GOPRO_PROTUNE_WHITE_BALANCE_RAW=4, /* Camera Raw | */ + GOPRO_PROTUNE_WHITE_BALANCE_ENUM_END=5 /* | */ +} GOPRO_PROTUNE_WHITE_BALANCE; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_PROTUNE_COLOUR +#define HAVE_ENUM_GOPRO_PROTUNE_COLOUR +typedef enum GOPRO_PROTUNE_COLOUR +{ + GOPRO_PROTUNE_COLOUR_STANDARD=0, /* Auto | */ + GOPRO_PROTUNE_COLOUR_NEUTRAL=1, /* Neutral | */ + GOPRO_PROTUNE_COLOUR_ENUM_END=2 /* | */ +} GOPRO_PROTUNE_COLOUR; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_PROTUNE_GAIN +#define HAVE_ENUM_GOPRO_PROTUNE_GAIN +typedef enum GOPRO_PROTUNE_GAIN +{ + GOPRO_PROTUNE_GAIN_400=0, /* ISO 400 | */ + GOPRO_PROTUNE_GAIN_800=1, /* ISO 800 (Only Hero 4) | */ + GOPRO_PROTUNE_GAIN_1600=2, /* ISO 1600 | */ + GOPRO_PROTUNE_GAIN_3200=3, /* ISO 3200 (Only Hero 4) | */ + GOPRO_PROTUNE_GAIN_6400=4, /* ISO 6400 | */ + GOPRO_PROTUNE_GAIN_ENUM_END=5 /* | */ +} GOPRO_PROTUNE_GAIN; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_PROTUNE_SHARPNESS +#define HAVE_ENUM_GOPRO_PROTUNE_SHARPNESS +typedef enum GOPRO_PROTUNE_SHARPNESS +{ + GOPRO_PROTUNE_SHARPNESS_LOW=0, /* Low Sharpness | */ + GOPRO_PROTUNE_SHARPNESS_MEDIUM=1, /* Medium Sharpness | */ + GOPRO_PROTUNE_SHARPNESS_HIGH=2, /* High Sharpness | */ + GOPRO_PROTUNE_SHARPNESS_ENUM_END=3 /* | */ +} GOPRO_PROTUNE_SHARPNESS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_PROTUNE_EXPOSURE +#define HAVE_ENUM_GOPRO_PROTUNE_EXPOSURE +typedef enum GOPRO_PROTUNE_EXPOSURE +{ + GOPRO_PROTUNE_EXPOSURE_NEG_5_0=0, /* -5.0 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_NEG_4_5=1, /* -4.5 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_NEG_4_0=2, /* -4.0 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_NEG_3_5=3, /* -3.5 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_NEG_3_0=4, /* -3.0 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_NEG_2_5=5, /* -2.5 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_NEG_2_0=6, /* -2.0 EV | */ + GOPRO_PROTUNE_EXPOSURE_NEG_1_5=7, /* -1.5 EV | */ + GOPRO_PROTUNE_EXPOSURE_NEG_1_0=8, /* -1.0 EV | */ + GOPRO_PROTUNE_EXPOSURE_NEG_0_5=9, /* -0.5 EV | */ + GOPRO_PROTUNE_EXPOSURE_ZERO=10, /* 0.0 EV | */ + GOPRO_PROTUNE_EXPOSURE_POS_0_5=11, /* +0.5 EV | */ + GOPRO_PROTUNE_EXPOSURE_POS_1_0=12, /* +1.0 EV | */ + GOPRO_PROTUNE_EXPOSURE_POS_1_5=13, /* +1.5 EV | */ + GOPRO_PROTUNE_EXPOSURE_POS_2_0=14, /* +2.0 EV | */ + GOPRO_PROTUNE_EXPOSURE_POS_2_5=15, /* +2.5 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_POS_3_0=16, /* +3.0 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_POS_3_5=17, /* +3.5 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_POS_4_0=18, /* +4.0 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_POS_4_5=19, /* +4.5 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_POS_5_0=20, /* +5.0 EV (Hero 3+ Only) | */ + GOPRO_PROTUNE_EXPOSURE_ENUM_END=21 /* | */ +} GOPRO_PROTUNE_EXPOSURE; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_CHARGING +#define HAVE_ENUM_GOPRO_CHARGING +typedef enum GOPRO_CHARGING +{ + GOPRO_CHARGING_DISABLED=0, /* Charging disabled | */ + GOPRO_CHARGING_ENABLED=1, /* Charging enabled | */ + GOPRO_CHARGING_ENUM_END=2 /* | */ +} GOPRO_CHARGING; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_MODEL +#define HAVE_ENUM_GOPRO_MODEL +typedef enum GOPRO_MODEL +{ + GOPRO_MODEL_UNKNOWN=0, /* Unknown gopro model | */ + GOPRO_MODEL_HERO_3_PLUS_SILVER=1, /* Hero 3+ Silver (HeroBus not supported by GoPro) | */ + GOPRO_MODEL_HERO_3_PLUS_BLACK=2, /* Hero 3+ Black | */ + GOPRO_MODEL_HERO_4_SILVER=3, /* Hero 4 Silver | */ + GOPRO_MODEL_HERO_4_BLACK=4, /* Hero 4 Black | */ + GOPRO_MODEL_ENUM_END=5 /* | */ +} GOPRO_MODEL; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GOPRO_BURST_RATE +#define HAVE_ENUM_GOPRO_BURST_RATE +typedef enum GOPRO_BURST_RATE +{ + GOPRO_BURST_RATE_3_IN_1_SECOND=0, /* 3 Shots / 1 Second | */ + GOPRO_BURST_RATE_5_IN_1_SECOND=1, /* 5 Shots / 1 Second | */ + GOPRO_BURST_RATE_10_IN_1_SECOND=2, /* 10 Shots / 1 Second | */ + GOPRO_BURST_RATE_10_IN_2_SECOND=3, /* 10 Shots / 2 Second | */ + GOPRO_BURST_RATE_10_IN_3_SECOND=4, /* 10 Shots / 3 Second (Hero 4 Only) | */ + GOPRO_BURST_RATE_30_IN_1_SECOND=5, /* 30 Shots / 1 Second | */ + GOPRO_BURST_RATE_30_IN_2_SECOND=6, /* 30 Shots / 2 Second | */ + GOPRO_BURST_RATE_30_IN_3_SECOND=7, /* 30 Shots / 3 Second | */ + GOPRO_BURST_RATE_30_IN_6_SECOND=8, /* 30 Shots / 6 Second | */ + GOPRO_BURST_RATE_ENUM_END=9 /* | */ +} GOPRO_BURST_RATE; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_LED_CONTROL_PATTERN +#define HAVE_ENUM_LED_CONTROL_PATTERN +typedef enum LED_CONTROL_PATTERN +{ + LED_CONTROL_PATTERN_OFF=0, /* LED patterns off (return control to regular vehicle control) | */ + LED_CONTROL_PATTERN_FIRMWAREUPDATE=1, /* LEDs show pattern during firmware update | */ + LED_CONTROL_PATTERN_CUSTOM=255, /* Custom Pattern using custom bytes fields | */ + LED_CONTROL_PATTERN_ENUM_END=256 /* | */ +} LED_CONTROL_PATTERN; +#endif + +/** @brief Flags in EKF_STATUS message */ +#ifndef HAVE_ENUM_EKF_STATUS_FLAGS +#define HAVE_ENUM_EKF_STATUS_FLAGS +typedef enum EKF_STATUS_FLAGS +{ + EKF_ATTITUDE=1, /* set if EKF's attitude estimate is good | */ + EKF_VELOCITY_HORIZ=2, /* set if EKF's horizontal velocity estimate is good | */ + EKF_VELOCITY_VERT=4, /* set if EKF's vertical velocity estimate is good | */ + EKF_POS_HORIZ_REL=8, /* set if EKF's horizontal position (relative) estimate is good | */ + EKF_POS_HORIZ_ABS=16, /* set if EKF's horizontal position (absolute) estimate is good | */ + EKF_POS_VERT_ABS=32, /* set if EKF's vertical position (absolute) estimate is good | */ + EKF_POS_VERT_AGL=64, /* set if EKF's vertical position (above ground) estimate is good | */ + EKF_CONST_POS_MODE=128, /* EKF is in constant position mode and does not know it's absolute or relative position | */ + EKF_PRED_POS_HORIZ_REL=256, /* set if EKF's predicted horizontal position (relative) estimate is good | */ + EKF_PRED_POS_HORIZ_ABS=512, /* set if EKF's predicted horizontal position (absolute) estimate is good | */ + EKF_STATUS_FLAGS_ENUM_END=513 /* | */ +} EKF_STATUS_FLAGS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_PID_TUNING_AXIS +#define HAVE_ENUM_PID_TUNING_AXIS +typedef enum PID_TUNING_AXIS +{ + PID_TUNING_ROLL=1, /* | */ + PID_TUNING_PITCH=2, /* | */ + PID_TUNING_YAW=3, /* | */ + PID_TUNING_ACCZ=4, /* | */ + PID_TUNING_STEER=5, /* | */ + PID_TUNING_LANDING=6, /* | */ + PID_TUNING_AXIS_ENUM_END=7 /* | */ +} PID_TUNING_AXIS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_MAG_CAL_STATUS +#define HAVE_ENUM_MAG_CAL_STATUS +typedef enum MAG_CAL_STATUS +{ + MAG_CAL_NOT_STARTED=0, /* | */ + MAG_CAL_WAITING_TO_START=1, /* | */ + MAG_CAL_RUNNING_STEP_ONE=2, /* | */ + MAG_CAL_RUNNING_STEP_TWO=3, /* | */ + MAG_CAL_SUCCESS=4, /* | */ + MAG_CAL_FAILED=5, /* | */ + MAG_CAL_STATUS_ENUM_END=6 /* | */ +} MAG_CAL_STATUS; +#endif + +/** @brief Special ACK block numbers control activation of dataflash log streaming */ +#ifndef HAVE_ENUM_MAV_REMOTE_LOG_DATA_BLOCK_COMMANDS +#define HAVE_ENUM_MAV_REMOTE_LOG_DATA_BLOCK_COMMANDS +typedef enum MAV_REMOTE_LOG_DATA_BLOCK_COMMANDS +{ + MAV_REMOTE_LOG_DATA_BLOCK_STOP=2147483645, /* UAV to stop sending DataFlash blocks | */ + MAV_REMOTE_LOG_DATA_BLOCK_START=2147483646, /* UAV to start sending DataFlash blocks | */ + MAV_REMOTE_LOG_DATA_BLOCK_COMMANDS_ENUM_END=2147483647 /* | */ +} MAV_REMOTE_LOG_DATA_BLOCK_COMMANDS; +#endif + +/** @brief Possible remote log data block statuses */ +#ifndef HAVE_ENUM_MAV_REMOTE_LOG_DATA_BLOCK_STATUSES +#define HAVE_ENUM_MAV_REMOTE_LOG_DATA_BLOCK_STATUSES +typedef enum MAV_REMOTE_LOG_DATA_BLOCK_STATUSES +{ + MAV_REMOTE_LOG_DATA_BLOCK_NACK=0, /* This block has NOT been received | */ + MAV_REMOTE_LOG_DATA_BLOCK_ACK=1, /* This block has been received | */ + MAV_REMOTE_LOG_DATA_BLOCK_STATUSES_ENUM_END=2 /* | */ +} MAV_REMOTE_LOG_DATA_BLOCK_STATUSES; +#endif + +/** @brief Bus types for device operations */ +#ifndef HAVE_ENUM_DEVICE_OP_BUSTYPE +#define HAVE_ENUM_DEVICE_OP_BUSTYPE +typedef enum DEVICE_OP_BUSTYPE +{ + DEVICE_OP_BUSTYPE_I2C=0, /* I2C Device operation | */ + DEVICE_OP_BUSTYPE_SPI=1, /* SPI Device operation | */ + DEVICE_OP_BUSTYPE_ENUM_END=2 /* | */ +} DEVICE_OP_BUSTYPE; +#endif // MAVLINK VERSION @@ -255,8 +764,36 @@ typedef enum CAMERA_FEEDBACK_FLAGS #include "./mavlink_msg_battery2.h" #include "./mavlink_msg_ahrs3.h" #include "./mavlink_msg_autopilot_version_request.h" +#include "./mavlink_msg_remote_log_data_block.h" +#include "./mavlink_msg_remote_log_block_status.h" +#include "./mavlink_msg_led_control.h" +#include "./mavlink_msg_mag_cal_progress.h" +#include "./mavlink_msg_mag_cal_report.h" +#include "./mavlink_msg_ekf_status_report.h" +#include "./mavlink_msg_pid_tuning.h" #include "./mavlink_msg_gimbal_report.h" #include "./mavlink_msg_gimbal_control.h" +#include "./mavlink_msg_gimbal_torque_cmd_report.h" +#include "./mavlink_msg_gopro_heartbeat.h" +#include "./mavlink_msg_gopro_get_request.h" +#include "./mavlink_msg_gopro_get_response.h" +#include "./mavlink_msg_gopro_set_request.h" +#include "./mavlink_msg_gopro_set_response.h" +#include "./mavlink_msg_rpm.h" + +// base include +#include "../common/common.h" +#include "../uAvionix/uAvionix.h" + +#undef MAVLINK_THIS_XML_IDX +#define MAVLINK_THIS_XML_IDX 0 + +#if MAVLINK_THIS_XML_IDX == MAVLINK_PRIMARY_XML_IDX +# define MAVLINK_MESSAGE_INFO {MAVLINK_MESSAGE_INFO_HEARTBEAT, MAVLINK_MESSAGE_INFO_SYS_STATUS, MAVLINK_MESSAGE_INFO_SYSTEM_TIME, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PING, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK, MAVLINK_MESSAGE_INFO_AUTH_KEY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SET_MODE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST, MAVLINK_MESSAGE_INFO_PARAM_VALUE, MAVLINK_MESSAGE_INFO_PARAM_SET, MAVLINK_MESSAGE_INFO_GPS_RAW_INT, MAVLINK_MESSAGE_INFO_GPS_STATUS, MAVLINK_MESSAGE_INFO_SCALED_IMU, MAVLINK_MESSAGE_INFO_RAW_IMU, MAVLINK_MESSAGE_INFO_RAW_PRESSURE, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE, MAVLINK_MESSAGE_INFO_ATTITUDE, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT, MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED, MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW, MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_ITEM, MAVLINK_MESSAGE_INFO_MISSION_REQUEST, MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST, MAVLINK_MESSAGE_INFO_MISSION_COUNT, MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL, MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED, MAVLINK_MESSAGE_INFO_MISSION_ACK, MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_PARAM_MAP_RC, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_INT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION_COV, MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT_COV, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_COV, MAVLINK_MESSAGE_INFO_RC_CHANNELS, MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM, MAVLINK_MESSAGE_INFO_DATA_STREAM, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_CONTROL, MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MISSION_ITEM_INT, MAVLINK_MESSAGE_INFO_VFR_HUD, MAVLINK_MESSAGE_INFO_COMMAND_INT, MAVLINK_MESSAGE_INFO_COMMAND_LONG, MAVLINK_MESSAGE_INFO_COMMAND_ACK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT, MAVLINK_MESSAGE_INFO_SET_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_GLOBAL_INT, MAVLINK_MESSAGE_INFO_POSITION_TARGET_GLOBAL_INT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, MAVLINK_MESSAGE_INFO_HIL_STATE, MAVLINK_MESSAGE_INFO_HIL_CONTROLS, MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW, MAVLINK_MESSAGE_INFO_HIL_ACTUATOR_CONTROLS, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE, MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_HIGHRES_IMU, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW_RAD, MAVLINK_MESSAGE_INFO_HIL_SENSOR, MAVLINK_MESSAGE_INFO_SIM_STATE, MAVLINK_MESSAGE_INFO_RADIO_STATUS, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_PROTOCOL, MAVLINK_MESSAGE_INFO_TIMESYNC, MAVLINK_MESSAGE_INFO_CAMERA_TRIGGER, MAVLINK_MESSAGE_INFO_HIL_GPS, MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION, MAVLINK_MESSAGE_INFO_SCALED_IMU2, MAVLINK_MESSAGE_INFO_LOG_REQUEST_LIST, MAVLINK_MESSAGE_INFO_LOG_ENTRY, MAVLINK_MESSAGE_INFO_LOG_REQUEST_DATA, MAVLINK_MESSAGE_INFO_LOG_DATA, MAVLINK_MESSAGE_INFO_LOG_ERASE, MAVLINK_MESSAGE_INFO_LOG_REQUEST_END, MAVLINK_MESSAGE_INFO_GPS_INJECT_DATA, MAVLINK_MESSAGE_INFO_GPS2_RAW, MAVLINK_MESSAGE_INFO_POWER_STATUS, MAVLINK_MESSAGE_INFO_SERIAL_CONTROL, MAVLINK_MESSAGE_INFO_GPS_RTK, MAVLINK_MESSAGE_INFO_GPS2_RTK, MAVLINK_MESSAGE_INFO_SCALED_IMU3, MAVLINK_MESSAGE_INFO_DATA_TRANSMISSION_HANDSHAKE, MAVLINK_MESSAGE_INFO_ENCAPSULATED_DATA, MAVLINK_MESSAGE_INFO_DISTANCE_SENSOR, MAVLINK_MESSAGE_INFO_TERRAIN_REQUEST, MAVLINK_MESSAGE_INFO_TERRAIN_DATA, MAVLINK_MESSAGE_INFO_TERRAIN_CHECK, MAVLINK_MESSAGE_INFO_TERRAIN_REPORT, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE2, MAVLINK_MESSAGE_INFO_ATT_POS_MOCAP, MAVLINK_MESSAGE_INFO_SET_ACTUATOR_CONTROL_TARGET, MAVLINK_MESSAGE_INFO_ACTUATOR_CONTROL_TARGET, MAVLINK_MESSAGE_INFO_ALTITUDE, MAVLINK_MESSAGE_INFO_RESOURCE_REQUEST, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE3, MAVLINK_MESSAGE_INFO_FOLLOW_TARGET, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_CONTROL_SYSTEM_STATE, MAVLINK_MESSAGE_INFO_BATTERY_STATUS, MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION, MAVLINK_MESSAGE_INFO_LANDING_TARGET, MAVLINK_MESSAGE_INFO_SENSOR_OFFSETS, MAVLINK_MESSAGE_INFO_SET_MAG_OFFSETS, MAVLINK_MESSAGE_INFO_MEMINFO, MAVLINK_MESSAGE_INFO_AP_ADC, MAVLINK_MESSAGE_INFO_DIGICAM_CONFIGURE, MAVLINK_MESSAGE_INFO_DIGICAM_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_CONFIGURE, MAVLINK_MESSAGE_INFO_MOUNT_CONTROL, MAVLINK_MESSAGE_INFO_MOUNT_STATUS, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_FENCE_POINT, MAVLINK_MESSAGE_INFO_FENCE_FETCH_POINT, MAVLINK_MESSAGE_INFO_FENCE_STATUS, MAVLINK_MESSAGE_INFO_AHRS, MAVLINK_MESSAGE_INFO_SIMSTATE, MAVLINK_MESSAGE_INFO_HWSTATUS, MAVLINK_MESSAGE_INFO_RADIO, MAVLINK_MESSAGE_INFO_LIMITS_STATUS, MAVLINK_MESSAGE_INFO_WIND, MAVLINK_MESSAGE_INFO_DATA16, MAVLINK_MESSAGE_INFO_DATA32, MAVLINK_MESSAGE_INFO_DATA64, MAVLINK_MESSAGE_INFO_DATA96, MAVLINK_MESSAGE_INFO_RANGEFINDER, MAVLINK_MESSAGE_INFO_AIRSPEED_AUTOCAL, MAVLINK_MESSAGE_INFO_RALLY_POINT, MAVLINK_MESSAGE_INFO_RALLY_FETCH_POINT, MAVLINK_MESSAGE_INFO_COMPASSMOT_STATUS, MAVLINK_MESSAGE_INFO_AHRS2, MAVLINK_MESSAGE_INFO_CAMERA_STATUS, MAVLINK_MESSAGE_INFO_CAMERA_FEEDBACK, MAVLINK_MESSAGE_INFO_BATTERY2, MAVLINK_MESSAGE_INFO_AHRS3, MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION_REQUEST, MAVLINK_MESSAGE_INFO_REMOTE_LOG_DATA_BLOCK, MAVLINK_MESSAGE_INFO_REMOTE_LOG_BLOCK_STATUS, MAVLINK_MESSAGE_INFO_LED_CONTROL, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MAG_CAL_PROGRESS, MAVLINK_MESSAGE_INFO_MAG_CAL_REPORT, MAVLINK_MESSAGE_INFO_EKF_STATUS_REPORT, MAVLINK_MESSAGE_INFO_PID_TUNING, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_GIMBAL_REPORT, MAVLINK_MESSAGE_INFO_GIMBAL_CONTROL, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_GIMBAL_TORQUE_CMD_REPORT, MAVLINK_MESSAGE_INFO_GOPRO_HEARTBEAT, MAVLINK_MESSAGE_INFO_GOPRO_GET_REQUEST, MAVLINK_MESSAGE_INFO_GOPRO_GET_RESPONSE, MAVLINK_MESSAGE_INFO_GOPRO_SET_REQUEST, MAVLINK_MESSAGE_INFO_GOPRO_SET_RESPONSE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_RPM, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ESTIMATOR_STATUS, MAVLINK_MESSAGE_INFO_WIND_COV, MAVLINK_MESSAGE_INFO_GPS_INPUT, MAVLINK_MESSAGE_INFO_GPS_RTCM_DATA, MAVLINK_MESSAGE_INFO_HIGH_LATENCY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_VIBRATION, MAVLINK_MESSAGE_INFO_HOME_POSITION, MAVLINK_MESSAGE_INFO_SET_HOME_POSITION, MAVLINK_MESSAGE_INFO_MESSAGE_INTERVAL, MAVLINK_MESSAGE_INFO_EXTENDED_SYS_STATE, MAVLINK_MESSAGE_INFO_ADSB_VEHICLE, MAVLINK_MESSAGE_INFO_COLLISION, MAVLINK_MESSAGE_INFO_V2_EXTENSION, MAVLINK_MESSAGE_INFO_MEMORY_VECT, MAVLINK_MESSAGE_INFO_DEBUG_VECT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT, MAVLINK_MESSAGE_INFO_STATUSTEXT, MAVLINK_MESSAGE_INFO_DEBUG, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}} +# if MAVLINK_COMMAND_24BIT +# include "../mavlink_get_info.h" +# endif +#endif #ifdef __cplusplus } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink.h b/vendor/libraries/mavlink/ardupilotmega/mavlink.h index edf27d638e..eda063f84a 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink.h @@ -1,10 +1,13 @@ /** @file - * @brief MAVLink comm protocol built from ardupilotmega.xml - * @see http://mavlink.org + * @brief MAVLink comm protocol built from ardupilotmega.xml + * @see http://mavlink.org */ +#pragma once #ifndef MAVLINK_H #define MAVLINK_H +#define MAVLINK_PRIMARY_XML_IDX 0 + #ifndef MAVLINK_STX #define MAVLINK_STX 254 #endif @@ -21,6 +24,10 @@ #define MAVLINK_CRC_EXTRA 1 #endif +#ifndef MAVLINK_COMMAND_24BIT +#define MAVLINK_COMMAND_24BIT 0 +#endif + #include "version.h" #include "ardupilotmega.h" diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs.h index 50ddc79e5a..075c1f3281 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE AHRS PACKING #define MAVLINK_MSG_ID_AHRS 163 -typedef struct __mavlink_ahrs_t -{ - float omegaIx; ///< X gyro drift estimate rad/s - float omegaIy; ///< Y gyro drift estimate rad/s - float omegaIz; ///< Z gyro drift estimate rad/s - float accel_weight; ///< average accel_weight - float renorm_val; ///< average renormalisation value - float error_rp; ///< average error_roll_pitch value - float error_yaw; ///< average error_yaw value -} mavlink_ahrs_t; +MAVPACKED( +typedef struct __mavlink_ahrs_t { + float omegaIx; /*< X gyro drift estimate rad/s*/ + float omegaIy; /*< Y gyro drift estimate rad/s*/ + float omegaIz; /*< Z gyro drift estimate rad/s*/ + float accel_weight; /*< average accel_weight*/ + float renorm_val; /*< average renormalisation value*/ + float error_rp; /*< average error_roll_pitch value*/ + float error_yaw; /*< average error_yaw value*/ +}) mavlink_ahrs_t; #define MAVLINK_MSG_ID_AHRS_LEN 28 +#define MAVLINK_MSG_ID_AHRS_MIN_LEN 28 #define MAVLINK_MSG_ID_163_LEN 28 +#define MAVLINK_MSG_ID_163_MIN_LEN 28 #define MAVLINK_MSG_ID_AHRS_CRC 127 #define MAVLINK_MSG_ID_163_CRC 127 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AHRS { \ - "AHRS", \ - 7, \ - { { "omegaIx", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs_t, omegaIx) }, \ + 163, \ + "AHRS", \ + 7, \ + { { "omegaIx", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs_t, omegaIx) }, \ { "omegaIy", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ahrs_t, omegaIy) }, \ { "omegaIz", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ahrs_t, omegaIz) }, \ { "accel_weight", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ahrs_t, accel_weight) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_ahrs_t { "error_yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_ahrs_t, error_yaw) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AHRS { \ + "AHRS", \ + 7, \ + { { "omegaIx", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs_t, omegaIx) }, \ + { "omegaIy", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ahrs_t, omegaIy) }, \ + { "omegaIz", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ahrs_t, omegaIz) }, \ + { "accel_weight", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ahrs_t, accel_weight) }, \ + { "renorm_val", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_ahrs_t, renorm_val) }, \ + { "error_rp", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_ahrs_t, error_rp) }, \ + { "error_yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_ahrs_t, error_yaw) }, \ + } \ +} +#endif /** * @brief Pack a ahrs message @@ -51,38 +69,34 @@ typedef struct __mavlink_ahrs_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ahrs_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float omegaIx, float omegaIy, float omegaIz, float accel_weight, float renorm_val, float error_rp, float error_yaw) + float omegaIx, float omegaIy, float omegaIz, float accel_weight, float renorm_val, float error_rp, float error_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS_LEN]; - _mav_put_float(buf, 0, omegaIx); - _mav_put_float(buf, 4, omegaIy); - _mav_put_float(buf, 8, omegaIz); - _mav_put_float(buf, 12, accel_weight); - _mav_put_float(buf, 16, renorm_val); - _mav_put_float(buf, 20, error_rp); - _mav_put_float(buf, 24, error_yaw); + char buf[MAVLINK_MSG_ID_AHRS_LEN]; + _mav_put_float(buf, 0, omegaIx); + _mav_put_float(buf, 4, omegaIy); + _mav_put_float(buf, 8, omegaIz); + _mav_put_float(buf, 12, accel_weight); + _mav_put_float(buf, 16, renorm_val); + _mav_put_float(buf, 20, error_rp); + _mav_put_float(buf, 24, error_yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AHRS_LEN); #else - mavlink_ahrs_t packet; - packet.omegaIx = omegaIx; - packet.omegaIy = omegaIy; - packet.omegaIz = omegaIz; - packet.accel_weight = accel_weight; - packet.renorm_val = renorm_val; - packet.error_rp = error_rp; - packet.error_yaw = error_yaw; + mavlink_ahrs_t packet; + packet.omegaIx = omegaIx; + packet.omegaIy = omegaIy; + packet.omegaIz = omegaIz; + packet.accel_weight = accel_weight; + packet.renorm_val = renorm_val; + packet.error_rp = error_rp; + packet.error_yaw = error_yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AHRS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AHRS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AHRS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS_MIN_LEN, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_ahrs_pack(uint8_t system_id, uint8_t componen * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ahrs_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float omegaIx,float omegaIy,float omegaIz,float accel_weight,float renorm_val,float error_rp,float error_yaw) + mavlink_message_t* msg, + float omegaIx,float omegaIy,float omegaIz,float accel_weight,float renorm_val,float error_rp,float error_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS_LEN]; - _mav_put_float(buf, 0, omegaIx); - _mav_put_float(buf, 4, omegaIy); - _mav_put_float(buf, 8, omegaIz); - _mav_put_float(buf, 12, accel_weight); - _mav_put_float(buf, 16, renorm_val); - _mav_put_float(buf, 20, error_rp); - _mav_put_float(buf, 24, error_yaw); + char buf[MAVLINK_MSG_ID_AHRS_LEN]; + _mav_put_float(buf, 0, omegaIx); + _mav_put_float(buf, 4, omegaIy); + _mav_put_float(buf, 8, omegaIz); + _mav_put_float(buf, 12, accel_weight); + _mav_put_float(buf, 16, renorm_val); + _mav_put_float(buf, 20, error_rp); + _mav_put_float(buf, 24, error_yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AHRS_LEN); #else - mavlink_ahrs_t packet; - packet.omegaIx = omegaIx; - packet.omegaIy = omegaIy; - packet.omegaIz = omegaIz; - packet.accel_weight = accel_weight; - packet.renorm_val = renorm_val; - packet.error_rp = error_rp; - packet.error_yaw = error_yaw; + mavlink_ahrs_t packet; + packet.omegaIx = omegaIx; + packet.omegaIy = omegaIy; + packet.omegaIz = omegaIz; + packet.accel_weight = accel_weight; + packet.renorm_val = renorm_val; + packet.error_rp = error_rp; + packet.error_yaw = error_yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AHRS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AHRS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AHRS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS_MIN_LEN, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_ahrs_pack_chan(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_ahrs_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_ahrs_t* ahrs) { - return mavlink_msg_ahrs_pack(system_id, component_id, msg, ahrs->omegaIx, ahrs->omegaIy, ahrs->omegaIz, ahrs->accel_weight, ahrs->renorm_val, ahrs->error_rp, ahrs->error_yaw); + return mavlink_msg_ahrs_pack(system_id, component_id, msg, ahrs->omegaIx, ahrs->omegaIy, ahrs->omegaIz, ahrs->accel_weight, ahrs->renorm_val, ahrs->error_rp, ahrs->error_yaw); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_ahrs_encode(uint8_t system_id, uint8_t compon */ static inline uint16_t mavlink_msg_ahrs_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ahrs_t* ahrs) { - return mavlink_msg_ahrs_pack_chan(system_id, component_id, chan, msg, ahrs->omegaIx, ahrs->omegaIy, ahrs->omegaIz, ahrs->accel_weight, ahrs->renorm_val, ahrs->error_rp, ahrs->error_yaw); + return mavlink_msg_ahrs_pack_chan(system_id, component_id, chan, msg, ahrs->omegaIx, ahrs->omegaIy, ahrs->omegaIz, ahrs->accel_weight, ahrs->renorm_val, ahrs->error_rp, ahrs->error_yaw); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_ahrs_encode_chan(uint8_t system_id, uint8_t c static inline void mavlink_msg_ahrs_send(mavlink_channel_t chan, float omegaIx, float omegaIy, float omegaIz, float accel_weight, float renorm_val, float error_rp, float error_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS_LEN]; - _mav_put_float(buf, 0, omegaIx); - _mav_put_float(buf, 4, omegaIy); - _mav_put_float(buf, 8, omegaIz); - _mav_put_float(buf, 12, accel_weight); - _mav_put_float(buf, 16, renorm_val); - _mav_put_float(buf, 20, error_rp); - _mav_put_float(buf, 24, error_yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, buf, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); + char buf[MAVLINK_MSG_ID_AHRS_LEN]; + _mav_put_float(buf, 0, omegaIx); + _mav_put_float(buf, 4, omegaIy); + _mav_put_float(buf, 8, omegaIz); + _mav_put_float(buf, 12, accel_weight); + _mav_put_float(buf, 16, renorm_val); + _mav_put_float(buf, 20, error_rp); + _mav_put_float(buf, 24, error_yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, buf, MAVLINK_MSG_ID_AHRS_MIN_LEN, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, buf, MAVLINK_MSG_ID_AHRS_LEN); + mavlink_ahrs_t packet; + packet.omegaIx = omegaIx; + packet.omegaIy = omegaIy; + packet.omegaIz = omegaIz; + packet.accel_weight = accel_weight; + packet.renorm_val = renorm_val; + packet.error_rp = error_rp; + packet.error_yaw = error_yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, (const char *)&packet, MAVLINK_MSG_ID_AHRS_MIN_LEN, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); #endif +} + +/** + * @brief Send a ahrs message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_ahrs_send_struct(mavlink_channel_t chan, const mavlink_ahrs_t* ahrs) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_ahrs_send(chan, ahrs->omegaIx, ahrs->omegaIy, ahrs->omegaIz, ahrs->accel_weight, ahrs->renorm_val, ahrs->error_rp, ahrs->error_yaw); #else - mavlink_ahrs_t packet; - packet.omegaIx = omegaIx; - packet.omegaIy = omegaIy; - packet.omegaIz = omegaIz; - packet.accel_weight = accel_weight; - packet.renorm_val = renorm_val; - packet.error_rp = error_rp; - packet.error_yaw = error_yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, (const char *)&packet, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, (const char *)&packet, MAVLINK_MSG_ID_AHRS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, (const char *)ahrs, MAVLINK_MSG_ID_AHRS_MIN_LEN, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_ahrs_send(mavlink_channel_t chan, float omegaIx, static inline void mavlink_msg_ahrs_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float omegaIx, float omegaIy, float omegaIz, float accel_weight, float renorm_val, float error_rp, float error_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, omegaIx); - _mav_put_float(buf, 4, omegaIy); - _mav_put_float(buf, 8, omegaIz); - _mav_put_float(buf, 12, accel_weight); - _mav_put_float(buf, 16, renorm_val); - _mav_put_float(buf, 20, error_rp); - _mav_put_float(buf, 24, error_yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, buf, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, buf, MAVLINK_MSG_ID_AHRS_LEN); -#endif -#else - mavlink_ahrs_t *packet = (mavlink_ahrs_t *)msgbuf; - packet->omegaIx = omegaIx; - packet->omegaIy = omegaIy; - packet->omegaIz = omegaIz; - packet->accel_weight = accel_weight; - packet->renorm_val = renorm_val; - packet->error_rp = error_rp; - packet->error_yaw = error_yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, (const char *)packet, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, omegaIx); + _mav_put_float(buf, 4, omegaIy); + _mav_put_float(buf, 8, omegaIz); + _mav_put_float(buf, 12, accel_weight); + _mav_put_float(buf, 16, renorm_val); + _mav_put_float(buf, 20, error_rp); + _mav_put_float(buf, 24, error_yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, buf, MAVLINK_MSG_ID_AHRS_MIN_LEN, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, (const char *)packet, MAVLINK_MSG_ID_AHRS_LEN); -#endif + mavlink_ahrs_t *packet = (mavlink_ahrs_t *)msgbuf; + packet->omegaIx = omegaIx; + packet->omegaIy = omegaIy; + packet->omegaIz = omegaIz; + packet->accel_weight = accel_weight; + packet->renorm_val = renorm_val; + packet->error_rp = error_rp; + packet->error_yaw = error_yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS, (const char *)packet, MAVLINK_MSG_ID_AHRS_MIN_LEN, MAVLINK_MSG_ID_AHRS_LEN, MAVLINK_MSG_ID_AHRS_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_ahrs_send_buf(mavlink_message_t *msgbuf, mavlink_ */ static inline float mavlink_msg_ahrs_get_omegaIx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -278,7 +286,7 @@ static inline float mavlink_msg_ahrs_get_omegaIx(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs_get_omegaIy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_ahrs_get_omegaIy(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs_get_omegaIz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_ahrs_get_omegaIz(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs_get_accel_weight(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_ahrs_get_accel_weight(const mavlink_message_t* m */ static inline float mavlink_msg_ahrs_get_renorm_val(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_ahrs_get_renorm_val(const mavlink_message_t* msg */ static inline float mavlink_msg_ahrs_get_error_rp(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_ahrs_get_error_rp(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs_get_error_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_ahrs_get_error_yaw(const mavlink_message_t* msg) */ static inline void mavlink_msg_ahrs_decode(const mavlink_message_t* msg, mavlink_ahrs_t* ahrs) { -#if MAVLINK_NEED_BYTE_SWAP - ahrs->omegaIx = mavlink_msg_ahrs_get_omegaIx(msg); - ahrs->omegaIy = mavlink_msg_ahrs_get_omegaIy(msg); - ahrs->omegaIz = mavlink_msg_ahrs_get_omegaIz(msg); - ahrs->accel_weight = mavlink_msg_ahrs_get_accel_weight(msg); - ahrs->renorm_val = mavlink_msg_ahrs_get_renorm_val(msg); - ahrs->error_rp = mavlink_msg_ahrs_get_error_rp(msg); - ahrs->error_yaw = mavlink_msg_ahrs_get_error_yaw(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + ahrs->omegaIx = mavlink_msg_ahrs_get_omegaIx(msg); + ahrs->omegaIy = mavlink_msg_ahrs_get_omegaIy(msg); + ahrs->omegaIz = mavlink_msg_ahrs_get_omegaIz(msg); + ahrs->accel_weight = mavlink_msg_ahrs_get_accel_weight(msg); + ahrs->renorm_val = mavlink_msg_ahrs_get_renorm_val(msg); + ahrs->error_rp = mavlink_msg_ahrs_get_error_rp(msg); + ahrs->error_yaw = mavlink_msg_ahrs_get_error_yaw(msg); #else - memcpy(ahrs, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AHRS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AHRS_LEN? msg->len : MAVLINK_MSG_ID_AHRS_LEN; + memset(ahrs, 0, MAVLINK_MSG_ID_AHRS_LEN); + memcpy(ahrs, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs2.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs2.h index 33e0066882..c43a0a5aaa 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs2.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs2.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE AHRS2 PACKING #define MAVLINK_MSG_ID_AHRS2 178 -typedef struct __mavlink_ahrs2_t -{ - float roll; ///< Roll angle (rad) - float pitch; ///< Pitch angle (rad) - float yaw; ///< Yaw angle (rad) - float altitude; ///< Altitude (MSL) - int32_t lat; ///< Latitude in degrees * 1E7 - int32_t lng; ///< Longitude in degrees * 1E7 -} mavlink_ahrs2_t; +MAVPACKED( +typedef struct __mavlink_ahrs2_t { + float roll; /*< Roll angle (rad)*/ + float pitch; /*< Pitch angle (rad)*/ + float yaw; /*< Yaw angle (rad)*/ + float altitude; /*< Altitude (MSL)*/ + int32_t lat; /*< Latitude in degrees * 1E7*/ + int32_t lng; /*< Longitude in degrees * 1E7*/ +}) mavlink_ahrs2_t; #define MAVLINK_MSG_ID_AHRS2_LEN 24 +#define MAVLINK_MSG_ID_AHRS2_MIN_LEN 24 #define MAVLINK_MSG_ID_178_LEN 24 +#define MAVLINK_MSG_ID_178_MIN_LEN 24 #define MAVLINK_MSG_ID_AHRS2_CRC 47 #define MAVLINK_MSG_ID_178_CRC 47 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AHRS2 { \ - "AHRS2", \ - 6, \ - { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs2_t, roll) }, \ + 178, \ + "AHRS2", \ + 6, \ + { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs2_t, roll) }, \ { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ahrs2_t, pitch) }, \ { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ahrs2_t, yaw) }, \ { "altitude", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ahrs2_t, altitude) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_ahrs2_t { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_ahrs2_t, lng) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AHRS2 { \ + "AHRS2", \ + 6, \ + { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs2_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ahrs2_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ahrs2_t, yaw) }, \ + { "altitude", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ahrs2_t, altitude) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_ahrs2_t, lat) }, \ + { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_ahrs2_t, lng) }, \ + } \ +} +#endif /** * @brief Pack a ahrs2 message @@ -48,36 +65,32 @@ typedef struct __mavlink_ahrs2_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ahrs2_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng) + float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS2_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); + char buf[MAVLINK_MSG_ID_AHRS2_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AHRS2_LEN); #else - mavlink_ahrs2_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.altitude = altitude; - packet.lat = lat; - packet.lng = lng; + mavlink_ahrs2_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.altitude = altitude; + packet.lat = lat; + packet.lng = lng; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AHRS2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AHRS2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AHRS2; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS2_MIN_LEN, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); } /** @@ -95,37 +108,33 @@ static inline uint16_t mavlink_msg_ahrs2_pack(uint8_t system_id, uint8_t compone * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ahrs2_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float roll,float pitch,float yaw,float altitude,int32_t lat,int32_t lng) + mavlink_message_t* msg, + float roll,float pitch,float yaw,float altitude,int32_t lat,int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS2_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); + char buf[MAVLINK_MSG_ID_AHRS2_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AHRS2_LEN); #else - mavlink_ahrs2_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.altitude = altitude; - packet.lat = lat; - packet.lng = lng; + mavlink_ahrs2_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.altitude = altitude; + packet.lat = lat; + packet.lng = lng; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AHRS2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AHRS2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AHRS2; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS2_MIN_LEN, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_ahrs2_pack_chan(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_ahrs2_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_ahrs2_t* ahrs2) { - return mavlink_msg_ahrs2_pack(system_id, component_id, msg, ahrs2->roll, ahrs2->pitch, ahrs2->yaw, ahrs2->altitude, ahrs2->lat, ahrs2->lng); + return mavlink_msg_ahrs2_pack(system_id, component_id, msg, ahrs2->roll, ahrs2->pitch, ahrs2->yaw, ahrs2->altitude, ahrs2->lat, ahrs2->lng); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_ahrs2_encode(uint8_t system_id, uint8_t compo */ static inline uint16_t mavlink_msg_ahrs2_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ahrs2_t* ahrs2) { - return mavlink_msg_ahrs2_pack_chan(system_id, component_id, chan, msg, ahrs2->roll, ahrs2->pitch, ahrs2->yaw, ahrs2->altitude, ahrs2->lat, ahrs2->lng); + return mavlink_msg_ahrs2_pack_chan(system_id, component_id, chan, msg, ahrs2->roll, ahrs2->pitch, ahrs2->yaw, ahrs2->altitude, ahrs2->lat, ahrs2->lng); } /** @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_ahrs2_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_ahrs2_send(mavlink_channel_t chan, float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS2_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, buf, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); + char buf[MAVLINK_MSG_ID_AHRS2_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, buf, MAVLINK_MSG_ID_AHRS2_MIN_LEN, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, buf, MAVLINK_MSG_ID_AHRS2_LEN); + mavlink_ahrs2_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.altitude = altitude; + packet.lat = lat; + packet.lng = lng; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, (const char *)&packet, MAVLINK_MSG_ID_AHRS2_MIN_LEN, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); #endif +} + +/** + * @brief Send a ahrs2 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_ahrs2_send_struct(mavlink_channel_t chan, const mavlink_ahrs2_t* ahrs2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_ahrs2_send(chan, ahrs2->roll, ahrs2->pitch, ahrs2->yaw, ahrs2->altitude, ahrs2->lat, ahrs2->lng); #else - mavlink_ahrs2_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.altitude = altitude; - packet.lat = lat; - packet.lng = lng; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, (const char *)&packet, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, (const char *)&packet, MAVLINK_MSG_ID_AHRS2_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, (const char *)ahrs2, MAVLINK_MSG_ID_AHRS2_MIN_LEN, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_ahrs2_send(mavlink_channel_t chan, float roll, fl static inline void mavlink_msg_ahrs2_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, buf, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, buf, MAVLINK_MSG_ID_AHRS2_MIN_LEN, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, buf, MAVLINK_MSG_ID_AHRS2_LEN); -#endif -#else - mavlink_ahrs2_t *packet = (mavlink_ahrs2_t *)msgbuf; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->altitude = altitude; - packet->lat = lat; - packet->lng = lng; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, (const char *)packet, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, (const char *)packet, MAVLINK_MSG_ID_AHRS2_LEN); -#endif + mavlink_ahrs2_t *packet = (mavlink_ahrs2_t *)msgbuf; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->altitude = altitude; + packet->lat = lat; + packet->lng = lng; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS2, (const char *)packet, MAVLINK_MSG_ID_AHRS2_MIN_LEN, MAVLINK_MSG_ID_AHRS2_LEN, MAVLINK_MSG_ID_AHRS2_CRC); #endif } #endif @@ -255,7 +262,7 @@ static inline void mavlink_msg_ahrs2_send_buf(mavlink_message_t *msgbuf, mavlink */ static inline float mavlink_msg_ahrs2_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -265,7 +272,7 @@ static inline float mavlink_msg_ahrs2_get_roll(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs2_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -275,7 +282,7 @@ static inline float mavlink_msg_ahrs2_get_pitch(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs2_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -285,7 +292,7 @@ static inline float mavlink_msg_ahrs2_get_yaw(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs2_get_altitude(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -295,7 +302,7 @@ static inline float mavlink_msg_ahrs2_get_altitude(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_ahrs2_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -305,7 +312,7 @@ static inline int32_t mavlink_msg_ahrs2_get_lat(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_ahrs2_get_lng(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 20); + return _MAV_RETURN_int32_t(msg, 20); } /** @@ -316,14 +323,16 @@ static inline int32_t mavlink_msg_ahrs2_get_lng(const mavlink_message_t* msg) */ static inline void mavlink_msg_ahrs2_decode(const mavlink_message_t* msg, mavlink_ahrs2_t* ahrs2) { -#if MAVLINK_NEED_BYTE_SWAP - ahrs2->roll = mavlink_msg_ahrs2_get_roll(msg); - ahrs2->pitch = mavlink_msg_ahrs2_get_pitch(msg); - ahrs2->yaw = mavlink_msg_ahrs2_get_yaw(msg); - ahrs2->altitude = mavlink_msg_ahrs2_get_altitude(msg); - ahrs2->lat = mavlink_msg_ahrs2_get_lat(msg); - ahrs2->lng = mavlink_msg_ahrs2_get_lng(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + ahrs2->roll = mavlink_msg_ahrs2_get_roll(msg); + ahrs2->pitch = mavlink_msg_ahrs2_get_pitch(msg); + ahrs2->yaw = mavlink_msg_ahrs2_get_yaw(msg); + ahrs2->altitude = mavlink_msg_ahrs2_get_altitude(msg); + ahrs2->lat = mavlink_msg_ahrs2_get_lat(msg); + ahrs2->lng = mavlink_msg_ahrs2_get_lng(msg); #else - memcpy(ahrs2, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AHRS2_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AHRS2_LEN? msg->len : MAVLINK_MSG_ID_AHRS2_LEN; + memset(ahrs2, 0, MAVLINK_MSG_ID_AHRS2_LEN); + memcpy(ahrs2, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs3.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs3.h index 32fb8f4a82..ad64e3d6b4 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs3.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ahrs3.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE AHRS3 PACKING #define MAVLINK_MSG_ID_AHRS3 182 -typedef struct __mavlink_ahrs3_t -{ - float roll; ///< Roll angle (rad) - float pitch; ///< Pitch angle (rad) - float yaw; ///< Yaw angle (rad) - float altitude; ///< Altitude (MSL) - int32_t lat; ///< Latitude in degrees * 1E7 - int32_t lng; ///< Longitude in degrees * 1E7 - float v1; ///< test variable1 - float v2; ///< test variable2 - float v3; ///< test variable3 - float v4; ///< test variable4 -} mavlink_ahrs3_t; +MAVPACKED( +typedef struct __mavlink_ahrs3_t { + float roll; /*< Roll angle (rad)*/ + float pitch; /*< Pitch angle (rad)*/ + float yaw; /*< Yaw angle (rad)*/ + float altitude; /*< Altitude (MSL)*/ + int32_t lat; /*< Latitude in degrees * 1E7*/ + int32_t lng; /*< Longitude in degrees * 1E7*/ + float v1; /*< test variable1*/ + float v2; /*< test variable2*/ + float v3; /*< test variable3*/ + float v4; /*< test variable4*/ +}) mavlink_ahrs3_t; #define MAVLINK_MSG_ID_AHRS3_LEN 40 +#define MAVLINK_MSG_ID_AHRS3_MIN_LEN 40 #define MAVLINK_MSG_ID_182_LEN 40 +#define MAVLINK_MSG_ID_182_MIN_LEN 40 #define MAVLINK_MSG_ID_AHRS3_CRC 229 #define MAVLINK_MSG_ID_182_CRC 229 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AHRS3 { \ - "AHRS3", \ - 10, \ - { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs3_t, roll) }, \ + 182, \ + "AHRS3", \ + 10, \ + { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs3_t, roll) }, \ { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ahrs3_t, pitch) }, \ { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ahrs3_t, yaw) }, \ { "altitude", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ahrs3_t, altitude) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_ahrs3_t { "v4", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_ahrs3_t, v4) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AHRS3 { \ + "AHRS3", \ + 10, \ + { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ahrs3_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ahrs3_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ahrs3_t, yaw) }, \ + { "altitude", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ahrs3_t, altitude) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_ahrs3_t, lat) }, \ + { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_ahrs3_t, lng) }, \ + { "v1", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_ahrs3_t, v1) }, \ + { "v2", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_ahrs3_t, v2) }, \ + { "v3", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_ahrs3_t, v3) }, \ + { "v4", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_ahrs3_t, v4) }, \ + } \ +} +#endif /** * @brief Pack a ahrs3 message @@ -60,44 +81,40 @@ typedef struct __mavlink_ahrs3_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ahrs3_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng, float v1, float v2, float v3, float v4) + float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng, float v1, float v2, float v3, float v4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS3_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); - _mav_put_float(buf, 24, v1); - _mav_put_float(buf, 28, v2); - _mav_put_float(buf, 32, v3); - _mav_put_float(buf, 36, v4); + char buf[MAVLINK_MSG_ID_AHRS3_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); + _mav_put_float(buf, 24, v1); + _mav_put_float(buf, 28, v2); + _mav_put_float(buf, 32, v3); + _mav_put_float(buf, 36, v4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AHRS3_LEN); #else - mavlink_ahrs3_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.altitude = altitude; - packet.lat = lat; - packet.lng = lng; - packet.v1 = v1; - packet.v2 = v2; - packet.v3 = v3; - packet.v4 = v4; + mavlink_ahrs3_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.altitude = altitude; + packet.lat = lat; + packet.lng = lng; + packet.v1 = v1; + packet.v2 = v2; + packet.v3 = v3; + packet.v4 = v4; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AHRS3_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AHRS3; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS3_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AHRS3; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AHRS3_MIN_LEN, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_ahrs3_pack(uint8_t system_id, uint8_t compone * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ahrs3_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float roll,float pitch,float yaw,float altitude,int32_t lat,int32_t lng,float v1,float v2,float v3,float v4) + mavlink_message_t* msg, + float roll,float pitch,float yaw,float altitude,int32_t lat,int32_t lng,float v1,float v2,float v3,float v4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS3_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); - _mav_put_float(buf, 24, v1); - _mav_put_float(buf, 28, v2); - _mav_put_float(buf, 32, v3); - _mav_put_float(buf, 36, v4); + char buf[MAVLINK_MSG_ID_AHRS3_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); + _mav_put_float(buf, 24, v1); + _mav_put_float(buf, 28, v2); + _mav_put_float(buf, 32, v3); + _mav_put_float(buf, 36, v4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AHRS3_LEN); #else - mavlink_ahrs3_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.altitude = altitude; - packet.lat = lat; - packet.lng = lng; - packet.v1 = v1; - packet.v2 = v2; - packet.v3 = v3; - packet.v4 = v4; + mavlink_ahrs3_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.altitude = altitude; + packet.lat = lat; + packet.lng = lng; + packet.v1 = v1; + packet.v2 = v2; + packet.v3 = v3; + packet.v4 = v4; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AHRS3_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AHRS3; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS3_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AHRS3; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AHRS3_MIN_LEN, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_ahrs3_pack_chan(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_ahrs3_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_ahrs3_t* ahrs3) { - return mavlink_msg_ahrs3_pack(system_id, component_id, msg, ahrs3->roll, ahrs3->pitch, ahrs3->yaw, ahrs3->altitude, ahrs3->lat, ahrs3->lng, ahrs3->v1, ahrs3->v2, ahrs3->v3, ahrs3->v4); + return mavlink_msg_ahrs3_pack(system_id, component_id, msg, ahrs3->roll, ahrs3->pitch, ahrs3->yaw, ahrs3->altitude, ahrs3->lat, ahrs3->lng, ahrs3->v1, ahrs3->v2, ahrs3->v3, ahrs3->v4); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_ahrs3_encode(uint8_t system_id, uint8_t compo */ static inline uint16_t mavlink_msg_ahrs3_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ahrs3_t* ahrs3) { - return mavlink_msg_ahrs3_pack_chan(system_id, component_id, chan, msg, ahrs3->roll, ahrs3->pitch, ahrs3->yaw, ahrs3->altitude, ahrs3->lat, ahrs3->lng, ahrs3->v1, ahrs3->v2, ahrs3->v3, ahrs3->v4); + return mavlink_msg_ahrs3_pack_chan(system_id, component_id, chan, msg, ahrs3->roll, ahrs3->pitch, ahrs3->yaw, ahrs3->altitude, ahrs3->lat, ahrs3->lng, ahrs3->v1, ahrs3->v2, ahrs3->v3, ahrs3->v4); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_ahrs3_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_ahrs3_send(mavlink_channel_t chan, float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng, float v1, float v2, float v3, float v4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AHRS3_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); - _mav_put_float(buf, 24, v1); - _mav_put_float(buf, 28, v2); - _mav_put_float(buf, 32, v3); - _mav_put_float(buf, 36, v4); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, buf, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); + char buf[MAVLINK_MSG_ID_AHRS3_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); + _mav_put_float(buf, 24, v1); + _mav_put_float(buf, 28, v2); + _mav_put_float(buf, 32, v3); + _mav_put_float(buf, 36, v4); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, buf, MAVLINK_MSG_ID_AHRS3_MIN_LEN, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, buf, MAVLINK_MSG_ID_AHRS3_LEN); + mavlink_ahrs3_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.altitude = altitude; + packet.lat = lat; + packet.lng = lng; + packet.v1 = v1; + packet.v2 = v2; + packet.v3 = v3; + packet.v4 = v4; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, (const char *)&packet, MAVLINK_MSG_ID_AHRS3_MIN_LEN, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); #endif +} + +/** + * @brief Send a ahrs3 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_ahrs3_send_struct(mavlink_channel_t chan, const mavlink_ahrs3_t* ahrs3) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_ahrs3_send(chan, ahrs3->roll, ahrs3->pitch, ahrs3->yaw, ahrs3->altitude, ahrs3->lat, ahrs3->lng, ahrs3->v1, ahrs3->v2, ahrs3->v3, ahrs3->v4); #else - mavlink_ahrs3_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.altitude = altitude; - packet.lat = lat; - packet.lng = lng; - packet.v1 = v1; - packet.v2 = v2; - packet.v3 = v3; - packet.v4 = v4; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, (const char *)&packet, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, (const char *)&packet, MAVLINK_MSG_ID_AHRS3_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, (const char *)ahrs3, MAVLINK_MSG_ID_AHRS3_MIN_LEN, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_ahrs3_send(mavlink_channel_t chan, float roll, fl static inline void mavlink_msg_ahrs3_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float roll, float pitch, float yaw, float altitude, int32_t lat, int32_t lng, float v1, float v2, float v3, float v4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, altitude); - _mav_put_int32_t(buf, 16, lat); - _mav_put_int32_t(buf, 20, lng); - _mav_put_float(buf, 24, v1); - _mav_put_float(buf, 28, v2); - _mav_put_float(buf, 32, v3); - _mav_put_float(buf, 36, v4); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, buf, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, buf, MAVLINK_MSG_ID_AHRS3_LEN); -#endif -#else - mavlink_ahrs3_t *packet = (mavlink_ahrs3_t *)msgbuf; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->altitude = altitude; - packet->lat = lat; - packet->lng = lng; - packet->v1 = v1; - packet->v2 = v2; - packet->v3 = v3; - packet->v4 = v4; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, (const char *)packet, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, altitude); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lng); + _mav_put_float(buf, 24, v1); + _mav_put_float(buf, 28, v2); + _mav_put_float(buf, 32, v3); + _mav_put_float(buf, 36, v4); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, buf, MAVLINK_MSG_ID_AHRS3_MIN_LEN, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, (const char *)packet, MAVLINK_MSG_ID_AHRS3_LEN); -#endif + mavlink_ahrs3_t *packet = (mavlink_ahrs3_t *)msgbuf; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->altitude = altitude; + packet->lat = lat; + packet->lng = lng; + packet->v1 = v1; + packet->v2 = v2; + packet->v3 = v3; + packet->v4 = v4; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AHRS3, (const char *)packet, MAVLINK_MSG_ID_AHRS3_MIN_LEN, MAVLINK_MSG_ID_AHRS3_LEN, MAVLINK_MSG_ID_AHRS3_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_ahrs3_send_buf(mavlink_message_t *msgbuf, mavlink */ static inline float mavlink_msg_ahrs3_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -317,7 +328,7 @@ static inline float mavlink_msg_ahrs3_get_roll(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs3_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -327,7 +338,7 @@ static inline float mavlink_msg_ahrs3_get_pitch(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs3_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -337,7 +348,7 @@ static inline float mavlink_msg_ahrs3_get_yaw(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs3_get_altitude(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -347,7 +358,7 @@ static inline float mavlink_msg_ahrs3_get_altitude(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_ahrs3_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -357,7 +368,7 @@ static inline int32_t mavlink_msg_ahrs3_get_lat(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_ahrs3_get_lng(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 20); + return _MAV_RETURN_int32_t(msg, 20); } /** @@ -367,7 +378,7 @@ static inline int32_t mavlink_msg_ahrs3_get_lng(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs3_get_v1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -377,7 +388,7 @@ static inline float mavlink_msg_ahrs3_get_v1(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs3_get_v2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -387,7 +398,7 @@ static inline float mavlink_msg_ahrs3_get_v2(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs3_get_v3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -397,7 +408,7 @@ static inline float mavlink_msg_ahrs3_get_v3(const mavlink_message_t* msg) */ static inline float mavlink_msg_ahrs3_get_v4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -408,18 +419,20 @@ static inline float mavlink_msg_ahrs3_get_v4(const mavlink_message_t* msg) */ static inline void mavlink_msg_ahrs3_decode(const mavlink_message_t* msg, mavlink_ahrs3_t* ahrs3) { -#if MAVLINK_NEED_BYTE_SWAP - ahrs3->roll = mavlink_msg_ahrs3_get_roll(msg); - ahrs3->pitch = mavlink_msg_ahrs3_get_pitch(msg); - ahrs3->yaw = mavlink_msg_ahrs3_get_yaw(msg); - ahrs3->altitude = mavlink_msg_ahrs3_get_altitude(msg); - ahrs3->lat = mavlink_msg_ahrs3_get_lat(msg); - ahrs3->lng = mavlink_msg_ahrs3_get_lng(msg); - ahrs3->v1 = mavlink_msg_ahrs3_get_v1(msg); - ahrs3->v2 = mavlink_msg_ahrs3_get_v2(msg); - ahrs3->v3 = mavlink_msg_ahrs3_get_v3(msg); - ahrs3->v4 = mavlink_msg_ahrs3_get_v4(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + ahrs3->roll = mavlink_msg_ahrs3_get_roll(msg); + ahrs3->pitch = mavlink_msg_ahrs3_get_pitch(msg); + ahrs3->yaw = mavlink_msg_ahrs3_get_yaw(msg); + ahrs3->altitude = mavlink_msg_ahrs3_get_altitude(msg); + ahrs3->lat = mavlink_msg_ahrs3_get_lat(msg); + ahrs3->lng = mavlink_msg_ahrs3_get_lng(msg); + ahrs3->v1 = mavlink_msg_ahrs3_get_v1(msg); + ahrs3->v2 = mavlink_msg_ahrs3_get_v2(msg); + ahrs3->v3 = mavlink_msg_ahrs3_get_v3(msg); + ahrs3->v4 = mavlink_msg_ahrs3_get_v4(msg); #else - memcpy(ahrs3, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AHRS3_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AHRS3_LEN? msg->len : MAVLINK_MSG_ID_AHRS3_LEN; + memset(ahrs3, 0, MAVLINK_MSG_ID_AHRS3_LEN); + memcpy(ahrs3, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_airspeed_autocal.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_airspeed_autocal.h index 521831c8ff..7fd55d7678 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_airspeed_autocal.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_airspeed_autocal.h @@ -1,35 +1,40 @@ +#pragma once // MESSAGE AIRSPEED_AUTOCAL PACKING #define MAVLINK_MSG_ID_AIRSPEED_AUTOCAL 174 -typedef struct __mavlink_airspeed_autocal_t -{ - float vx; ///< GPS velocity north m/s - float vy; ///< GPS velocity east m/s - float vz; ///< GPS velocity down m/s - float diff_pressure; ///< Differential pressure pascals - float EAS2TAS; ///< Estimated to true airspeed ratio - float ratio; ///< Airspeed ratio - float state_x; ///< EKF state x - float state_y; ///< EKF state y - float state_z; ///< EKF state z - float Pax; ///< EKF Pax - float Pby; ///< EKF Pby - float Pcz; ///< EKF Pcz -} mavlink_airspeed_autocal_t; +MAVPACKED( +typedef struct __mavlink_airspeed_autocal_t { + float vx; /*< GPS velocity north m/s*/ + float vy; /*< GPS velocity east m/s*/ + float vz; /*< GPS velocity down m/s*/ + float diff_pressure; /*< Differential pressure pascals*/ + float EAS2TAS; /*< Estimated to true airspeed ratio*/ + float ratio; /*< Airspeed ratio*/ + float state_x; /*< EKF state x*/ + float state_y; /*< EKF state y*/ + float state_z; /*< EKF state z*/ + float Pax; /*< EKF Pax*/ + float Pby; /*< EKF Pby*/ + float Pcz; /*< EKF Pcz*/ +}) mavlink_airspeed_autocal_t; #define MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN 48 +#define MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN 48 #define MAVLINK_MSG_ID_174_LEN 48 +#define MAVLINK_MSG_ID_174_MIN_LEN 48 #define MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC 167 #define MAVLINK_MSG_ID_174_CRC 167 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AIRSPEED_AUTOCAL { \ - "AIRSPEED_AUTOCAL", \ - 12, \ - { { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_airspeed_autocal_t, vx) }, \ + 174, \ + "AIRSPEED_AUTOCAL", \ + 12, \ + { { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_airspeed_autocal_t, vx) }, \ { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_airspeed_autocal_t, vy) }, \ { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_airspeed_autocal_t, vz) }, \ { "diff_pressure", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_airspeed_autocal_t, diff_pressure) }, \ @@ -43,7 +48,25 @@ typedef struct __mavlink_airspeed_autocal_t { "Pcz", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_airspeed_autocal_t, Pcz) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AIRSPEED_AUTOCAL { \ + "AIRSPEED_AUTOCAL", \ + 12, \ + { { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_airspeed_autocal_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_airspeed_autocal_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_airspeed_autocal_t, vz) }, \ + { "diff_pressure", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_airspeed_autocal_t, diff_pressure) }, \ + { "EAS2TAS", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_airspeed_autocal_t, EAS2TAS) }, \ + { "ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_airspeed_autocal_t, ratio) }, \ + { "state_x", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_airspeed_autocal_t, state_x) }, \ + { "state_y", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_airspeed_autocal_t, state_y) }, \ + { "state_z", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_airspeed_autocal_t, state_z) }, \ + { "Pax", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_airspeed_autocal_t, Pax) }, \ + { "Pby", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_airspeed_autocal_t, Pby) }, \ + { "Pcz", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_airspeed_autocal_t, Pcz) }, \ + } \ +} +#endif /** * @brief Pack a airspeed_autocal message @@ -66,48 +89,44 @@ typedef struct __mavlink_airspeed_autocal_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_airspeed_autocal_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float vx, float vy, float vz, float diff_pressure, float EAS2TAS, float ratio, float state_x, float state_y, float state_z, float Pax, float Pby, float Pcz) + float vx, float vy, float vz, float diff_pressure, float EAS2TAS, float ratio, float state_x, float state_y, float state_z, float Pax, float Pby, float Pcz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; - _mav_put_float(buf, 0, vx); - _mav_put_float(buf, 4, vy); - _mav_put_float(buf, 8, vz); - _mav_put_float(buf, 12, diff_pressure); - _mav_put_float(buf, 16, EAS2TAS); - _mav_put_float(buf, 20, ratio); - _mav_put_float(buf, 24, state_x); - _mav_put_float(buf, 28, state_y); - _mav_put_float(buf, 32, state_z); - _mav_put_float(buf, 36, Pax); - _mav_put_float(buf, 40, Pby); - _mav_put_float(buf, 44, Pcz); + char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; + _mav_put_float(buf, 0, vx); + _mav_put_float(buf, 4, vy); + _mav_put_float(buf, 8, vz); + _mav_put_float(buf, 12, diff_pressure); + _mav_put_float(buf, 16, EAS2TAS); + _mav_put_float(buf, 20, ratio); + _mav_put_float(buf, 24, state_x); + _mav_put_float(buf, 28, state_y); + _mav_put_float(buf, 32, state_z); + _mav_put_float(buf, 36, Pax); + _mav_put_float(buf, 40, Pby); + _mav_put_float(buf, 44, Pcz); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); #else - mavlink_airspeed_autocal_t packet; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.diff_pressure = diff_pressure; - packet.EAS2TAS = EAS2TAS; - packet.ratio = ratio; - packet.state_x = state_x; - packet.state_y = state_y; - packet.state_z = state_z; - packet.Pax = Pax; - packet.Pby = Pby; - packet.Pcz = Pcz; + mavlink_airspeed_autocal_t packet; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.diff_pressure = diff_pressure; + packet.EAS2TAS = EAS2TAS; + packet.ratio = ratio; + packet.state_x = state_x; + packet.state_y = state_y; + packet.state_z = state_z; + packet.Pax = Pax; + packet.Pby = Pby; + packet.Pcz = Pcz; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AIRSPEED_AUTOCAL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AIRSPEED_AUTOCAL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); } /** @@ -131,49 +150,45 @@ static inline uint16_t mavlink_msg_airspeed_autocal_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_airspeed_autocal_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float vx,float vy,float vz,float diff_pressure,float EAS2TAS,float ratio,float state_x,float state_y,float state_z,float Pax,float Pby,float Pcz) + mavlink_message_t* msg, + float vx,float vy,float vz,float diff_pressure,float EAS2TAS,float ratio,float state_x,float state_y,float state_z,float Pax,float Pby,float Pcz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; - _mav_put_float(buf, 0, vx); - _mav_put_float(buf, 4, vy); - _mav_put_float(buf, 8, vz); - _mav_put_float(buf, 12, diff_pressure); - _mav_put_float(buf, 16, EAS2TAS); - _mav_put_float(buf, 20, ratio); - _mav_put_float(buf, 24, state_x); - _mav_put_float(buf, 28, state_y); - _mav_put_float(buf, 32, state_z); - _mav_put_float(buf, 36, Pax); - _mav_put_float(buf, 40, Pby); - _mav_put_float(buf, 44, Pcz); + char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; + _mav_put_float(buf, 0, vx); + _mav_put_float(buf, 4, vy); + _mav_put_float(buf, 8, vz); + _mav_put_float(buf, 12, diff_pressure); + _mav_put_float(buf, 16, EAS2TAS); + _mav_put_float(buf, 20, ratio); + _mav_put_float(buf, 24, state_x); + _mav_put_float(buf, 28, state_y); + _mav_put_float(buf, 32, state_z); + _mav_put_float(buf, 36, Pax); + _mav_put_float(buf, 40, Pby); + _mav_put_float(buf, 44, Pcz); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); #else - mavlink_airspeed_autocal_t packet; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.diff_pressure = diff_pressure; - packet.EAS2TAS = EAS2TAS; - packet.ratio = ratio; - packet.state_x = state_x; - packet.state_y = state_y; - packet.state_z = state_z; - packet.Pax = Pax; - packet.Pby = Pby; - packet.Pcz = Pcz; + mavlink_airspeed_autocal_t packet; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.diff_pressure = diff_pressure; + packet.EAS2TAS = EAS2TAS; + packet.ratio = ratio; + packet.state_x = state_x; + packet.state_y = state_y; + packet.state_z = state_z; + packet.Pax = Pax; + packet.Pby = Pby; + packet.Pcz = Pcz; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AIRSPEED_AUTOCAL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AIRSPEED_AUTOCAL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); } /** @@ -186,7 +201,7 @@ static inline uint16_t mavlink_msg_airspeed_autocal_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_airspeed_autocal_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_airspeed_autocal_t* airspeed_autocal) { - return mavlink_msg_airspeed_autocal_pack(system_id, component_id, msg, airspeed_autocal->vx, airspeed_autocal->vy, airspeed_autocal->vz, airspeed_autocal->diff_pressure, airspeed_autocal->EAS2TAS, airspeed_autocal->ratio, airspeed_autocal->state_x, airspeed_autocal->state_y, airspeed_autocal->state_z, airspeed_autocal->Pax, airspeed_autocal->Pby, airspeed_autocal->Pcz); + return mavlink_msg_airspeed_autocal_pack(system_id, component_id, msg, airspeed_autocal->vx, airspeed_autocal->vy, airspeed_autocal->vz, airspeed_autocal->diff_pressure, airspeed_autocal->EAS2TAS, airspeed_autocal->ratio, airspeed_autocal->state_x, airspeed_autocal->state_y, airspeed_autocal->state_z, airspeed_autocal->Pax, airspeed_autocal->Pby, airspeed_autocal->Pcz); } /** @@ -200,7 +215,7 @@ static inline uint16_t mavlink_msg_airspeed_autocal_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_airspeed_autocal_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_airspeed_autocal_t* airspeed_autocal) { - return mavlink_msg_airspeed_autocal_pack_chan(system_id, component_id, chan, msg, airspeed_autocal->vx, airspeed_autocal->vy, airspeed_autocal->vz, airspeed_autocal->diff_pressure, airspeed_autocal->EAS2TAS, airspeed_autocal->ratio, airspeed_autocal->state_x, airspeed_autocal->state_y, airspeed_autocal->state_z, airspeed_autocal->Pax, airspeed_autocal->Pby, airspeed_autocal->Pcz); + return mavlink_msg_airspeed_autocal_pack_chan(system_id, component_id, chan, msg, airspeed_autocal->vx, airspeed_autocal->vy, airspeed_autocal->vz, airspeed_autocal->diff_pressure, airspeed_autocal->EAS2TAS, airspeed_autocal->ratio, airspeed_autocal->state_x, airspeed_autocal->state_y, airspeed_autocal->state_z, airspeed_autocal->Pax, airspeed_autocal->Pby, airspeed_autocal->Pcz); } /** @@ -225,45 +240,51 @@ static inline uint16_t mavlink_msg_airspeed_autocal_encode_chan(uint8_t system_i static inline void mavlink_msg_airspeed_autocal_send(mavlink_channel_t chan, float vx, float vy, float vz, float diff_pressure, float EAS2TAS, float ratio, float state_x, float state_y, float state_z, float Pax, float Pby, float Pcz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; - _mav_put_float(buf, 0, vx); - _mav_put_float(buf, 4, vy); - _mav_put_float(buf, 8, vz); - _mav_put_float(buf, 12, diff_pressure); - _mav_put_float(buf, 16, EAS2TAS); - _mav_put_float(buf, 20, ratio); - _mav_put_float(buf, 24, state_x); - _mav_put_float(buf, 28, state_y); - _mav_put_float(buf, 32, state_z); - _mav_put_float(buf, 36, Pax); - _mav_put_float(buf, 40, Pby); - _mav_put_float(buf, 44, Pcz); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); + char buf[MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN]; + _mav_put_float(buf, 0, vx); + _mav_put_float(buf, 4, vy); + _mav_put_float(buf, 8, vz); + _mav_put_float(buf, 12, diff_pressure); + _mav_put_float(buf, 16, EAS2TAS); + _mav_put_float(buf, 20, ratio); + _mav_put_float(buf, 24, state_x); + _mav_put_float(buf, 28, state_y); + _mav_put_float(buf, 32, state_z); + _mav_put_float(buf, 36, Pax); + _mav_put_float(buf, 40, Pby); + _mav_put_float(buf, 44, Pcz); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); + mavlink_airspeed_autocal_t packet; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.diff_pressure = diff_pressure; + packet.EAS2TAS = EAS2TAS; + packet.ratio = ratio; + packet.state_x = state_x; + packet.state_y = state_y; + packet.state_z = state_z; + packet.Pax = Pax; + packet.Pby = Pby; + packet.Pcz = Pcz; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)&packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); #endif +} + +/** + * @brief Send a airspeed_autocal message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_airspeed_autocal_send_struct(mavlink_channel_t chan, const mavlink_airspeed_autocal_t* airspeed_autocal) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_airspeed_autocal_send(chan, airspeed_autocal->vx, airspeed_autocal->vy, airspeed_autocal->vz, airspeed_autocal->diff_pressure, airspeed_autocal->EAS2TAS, airspeed_autocal->ratio, airspeed_autocal->state_x, airspeed_autocal->state_y, airspeed_autocal->state_z, airspeed_autocal->Pax, airspeed_autocal->Pby, airspeed_autocal->Pcz); #else - mavlink_airspeed_autocal_t packet; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.diff_pressure = diff_pressure; - packet.EAS2TAS = EAS2TAS; - packet.ratio = ratio; - packet.state_x = state_x; - packet.state_y = state_y; - packet.state_z = state_z; - packet.Pax = Pax; - packet.Pby = Pby; - packet.Pcz = Pcz; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)&packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)&packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)airspeed_autocal, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); #endif } @@ -278,45 +299,37 @@ static inline void mavlink_msg_airspeed_autocal_send(mavlink_channel_t chan, flo static inline void mavlink_msg_airspeed_autocal_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float vx, float vy, float vz, float diff_pressure, float EAS2TAS, float ratio, float state_x, float state_y, float state_z, float Pax, float Pby, float Pcz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, vx); - _mav_put_float(buf, 4, vy); - _mav_put_float(buf, 8, vz); - _mav_put_float(buf, 12, diff_pressure); - _mav_put_float(buf, 16, EAS2TAS); - _mav_put_float(buf, 20, ratio); - _mav_put_float(buf, 24, state_x); - _mav_put_float(buf, 28, state_y); - _mav_put_float(buf, 32, state_z); - _mav_put_float(buf, 36, Pax); - _mav_put_float(buf, 40, Pby); - _mav_put_float(buf, 44, Pcz); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, vx); + _mav_put_float(buf, 4, vy); + _mav_put_float(buf, 8, vz); + _mav_put_float(buf, 12, diff_pressure); + _mav_put_float(buf, 16, EAS2TAS); + _mav_put_float(buf, 20, ratio); + _mav_put_float(buf, 24, state_x); + _mav_put_float(buf, 28, state_y); + _mav_put_float(buf, 32, state_z); + _mav_put_float(buf, 36, Pax); + _mav_put_float(buf, 40, Pby); + _mav_put_float(buf, 44, Pcz); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, buf, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); -#endif -#else - mavlink_airspeed_autocal_t *packet = (mavlink_airspeed_autocal_t *)msgbuf; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->diff_pressure = diff_pressure; - packet->EAS2TAS = EAS2TAS; - packet->ratio = ratio; - packet->state_x = state_x; - packet->state_y = state_y; - packet->state_z = state_z; - packet->Pax = Pax; - packet->Pby = Pby; - packet->Pcz = Pcz; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); -#endif + mavlink_airspeed_autocal_t *packet = (mavlink_airspeed_autocal_t *)msgbuf; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->diff_pressure = diff_pressure; + packet->EAS2TAS = EAS2TAS; + packet->ratio = ratio; + packet->state_x = state_x; + packet->state_y = state_y; + packet->state_z = state_z; + packet->Pax = Pax; + packet->Pby = Pby; + packet->Pcz = Pcz; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL, (const char *)packet, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_CRC); #endif } #endif @@ -333,7 +346,7 @@ static inline void mavlink_msg_airspeed_autocal_send_buf(mavlink_message_t *msgb */ static inline float mavlink_msg_airspeed_autocal_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -343,7 +356,7 @@ static inline float mavlink_msg_airspeed_autocal_get_vx(const mavlink_message_t* */ static inline float mavlink_msg_airspeed_autocal_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -353,7 +366,7 @@ static inline float mavlink_msg_airspeed_autocal_get_vy(const mavlink_message_t* */ static inline float mavlink_msg_airspeed_autocal_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -363,7 +376,7 @@ static inline float mavlink_msg_airspeed_autocal_get_vz(const mavlink_message_t* */ static inline float mavlink_msg_airspeed_autocal_get_diff_pressure(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -373,7 +386,7 @@ static inline float mavlink_msg_airspeed_autocal_get_diff_pressure(const mavlink */ static inline float mavlink_msg_airspeed_autocal_get_EAS2TAS(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -383,7 +396,7 @@ static inline float mavlink_msg_airspeed_autocal_get_EAS2TAS(const mavlink_messa */ static inline float mavlink_msg_airspeed_autocal_get_ratio(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -393,7 +406,7 @@ static inline float mavlink_msg_airspeed_autocal_get_ratio(const mavlink_message */ static inline float mavlink_msg_airspeed_autocal_get_state_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -403,7 +416,7 @@ static inline float mavlink_msg_airspeed_autocal_get_state_x(const mavlink_messa */ static inline float mavlink_msg_airspeed_autocal_get_state_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -413,7 +426,7 @@ static inline float mavlink_msg_airspeed_autocal_get_state_y(const mavlink_messa */ static inline float mavlink_msg_airspeed_autocal_get_state_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -423,7 +436,7 @@ static inline float mavlink_msg_airspeed_autocal_get_state_z(const mavlink_messa */ static inline float mavlink_msg_airspeed_autocal_get_Pax(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -433,7 +446,7 @@ static inline float mavlink_msg_airspeed_autocal_get_Pax(const mavlink_message_t */ static inline float mavlink_msg_airspeed_autocal_get_Pby(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -443,7 +456,7 @@ static inline float mavlink_msg_airspeed_autocal_get_Pby(const mavlink_message_t */ static inline float mavlink_msg_airspeed_autocal_get_Pcz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -454,20 +467,22 @@ static inline float mavlink_msg_airspeed_autocal_get_Pcz(const mavlink_message_t */ static inline void mavlink_msg_airspeed_autocal_decode(const mavlink_message_t* msg, mavlink_airspeed_autocal_t* airspeed_autocal) { -#if MAVLINK_NEED_BYTE_SWAP - airspeed_autocal->vx = mavlink_msg_airspeed_autocal_get_vx(msg); - airspeed_autocal->vy = mavlink_msg_airspeed_autocal_get_vy(msg); - airspeed_autocal->vz = mavlink_msg_airspeed_autocal_get_vz(msg); - airspeed_autocal->diff_pressure = mavlink_msg_airspeed_autocal_get_diff_pressure(msg); - airspeed_autocal->EAS2TAS = mavlink_msg_airspeed_autocal_get_EAS2TAS(msg); - airspeed_autocal->ratio = mavlink_msg_airspeed_autocal_get_ratio(msg); - airspeed_autocal->state_x = mavlink_msg_airspeed_autocal_get_state_x(msg); - airspeed_autocal->state_y = mavlink_msg_airspeed_autocal_get_state_y(msg); - airspeed_autocal->state_z = mavlink_msg_airspeed_autocal_get_state_z(msg); - airspeed_autocal->Pax = mavlink_msg_airspeed_autocal_get_Pax(msg); - airspeed_autocal->Pby = mavlink_msg_airspeed_autocal_get_Pby(msg); - airspeed_autocal->Pcz = mavlink_msg_airspeed_autocal_get_Pcz(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + airspeed_autocal->vx = mavlink_msg_airspeed_autocal_get_vx(msg); + airspeed_autocal->vy = mavlink_msg_airspeed_autocal_get_vy(msg); + airspeed_autocal->vz = mavlink_msg_airspeed_autocal_get_vz(msg); + airspeed_autocal->diff_pressure = mavlink_msg_airspeed_autocal_get_diff_pressure(msg); + airspeed_autocal->EAS2TAS = mavlink_msg_airspeed_autocal_get_EAS2TAS(msg); + airspeed_autocal->ratio = mavlink_msg_airspeed_autocal_get_ratio(msg); + airspeed_autocal->state_x = mavlink_msg_airspeed_autocal_get_state_x(msg); + airspeed_autocal->state_y = mavlink_msg_airspeed_autocal_get_state_y(msg); + airspeed_autocal->state_z = mavlink_msg_airspeed_autocal_get_state_z(msg); + airspeed_autocal->Pax = mavlink_msg_airspeed_autocal_get_Pax(msg); + airspeed_autocal->Pby = mavlink_msg_airspeed_autocal_get_Pby(msg); + airspeed_autocal->Pcz = mavlink_msg_airspeed_autocal_get_Pcz(msg); #else - memcpy(airspeed_autocal, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN? msg->len : MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN; + memset(airspeed_autocal, 0, MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_LEN); + memcpy(airspeed_autocal, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ap_adc.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ap_adc.h index 3c18e644ef..d597e21c22 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ap_adc.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ap_adc.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE AP_ADC PACKING #define MAVLINK_MSG_ID_AP_ADC 153 -typedef struct __mavlink_ap_adc_t -{ - uint16_t adc1; ///< ADC output 1 - uint16_t adc2; ///< ADC output 2 - uint16_t adc3; ///< ADC output 3 - uint16_t adc4; ///< ADC output 4 - uint16_t adc5; ///< ADC output 5 - uint16_t adc6; ///< ADC output 6 -} mavlink_ap_adc_t; +MAVPACKED( +typedef struct __mavlink_ap_adc_t { + uint16_t adc1; /*< ADC output 1*/ + uint16_t adc2; /*< ADC output 2*/ + uint16_t adc3; /*< ADC output 3*/ + uint16_t adc4; /*< ADC output 4*/ + uint16_t adc5; /*< ADC output 5*/ + uint16_t adc6; /*< ADC output 6*/ +}) mavlink_ap_adc_t; #define MAVLINK_MSG_ID_AP_ADC_LEN 12 +#define MAVLINK_MSG_ID_AP_ADC_MIN_LEN 12 #define MAVLINK_MSG_ID_153_LEN 12 +#define MAVLINK_MSG_ID_153_MIN_LEN 12 #define MAVLINK_MSG_ID_AP_ADC_CRC 188 #define MAVLINK_MSG_ID_153_CRC 188 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AP_ADC { \ - "AP_ADC", \ - 6, \ - { { "adc1", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_ap_adc_t, adc1) }, \ + 153, \ + "AP_ADC", \ + 6, \ + { { "adc1", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_ap_adc_t, adc1) }, \ { "adc2", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_ap_adc_t, adc2) }, \ { "adc3", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_ap_adc_t, adc3) }, \ { "adc4", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_ap_adc_t, adc4) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_ap_adc_t { "adc6", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_ap_adc_t, adc6) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AP_ADC { \ + "AP_ADC", \ + 6, \ + { { "adc1", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_ap_adc_t, adc1) }, \ + { "adc2", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_ap_adc_t, adc2) }, \ + { "adc3", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_ap_adc_t, adc3) }, \ + { "adc4", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_ap_adc_t, adc4) }, \ + { "adc5", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_ap_adc_t, adc5) }, \ + { "adc6", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_ap_adc_t, adc6) }, \ + } \ +} +#endif /** * @brief Pack a ap_adc message @@ -48,36 +65,32 @@ typedef struct __mavlink_ap_adc_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ap_adc_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t adc1, uint16_t adc2, uint16_t adc3, uint16_t adc4, uint16_t adc5, uint16_t adc6) + uint16_t adc1, uint16_t adc2, uint16_t adc3, uint16_t adc4, uint16_t adc5, uint16_t adc6) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AP_ADC_LEN]; - _mav_put_uint16_t(buf, 0, adc1); - _mav_put_uint16_t(buf, 2, adc2); - _mav_put_uint16_t(buf, 4, adc3); - _mav_put_uint16_t(buf, 6, adc4); - _mav_put_uint16_t(buf, 8, adc5); - _mav_put_uint16_t(buf, 10, adc6); + char buf[MAVLINK_MSG_ID_AP_ADC_LEN]; + _mav_put_uint16_t(buf, 0, adc1); + _mav_put_uint16_t(buf, 2, adc2); + _mav_put_uint16_t(buf, 4, adc3); + _mav_put_uint16_t(buf, 6, adc4); + _mav_put_uint16_t(buf, 8, adc5); + _mav_put_uint16_t(buf, 10, adc6); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AP_ADC_LEN); #else - mavlink_ap_adc_t packet; - packet.adc1 = adc1; - packet.adc2 = adc2; - packet.adc3 = adc3; - packet.adc4 = adc4; - packet.adc5 = adc5; - packet.adc6 = adc6; + mavlink_ap_adc_t packet; + packet.adc1 = adc1; + packet.adc2 = adc2; + packet.adc3 = adc3; + packet.adc4 = adc4; + packet.adc5 = adc5; + packet.adc6 = adc6; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AP_ADC_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AP_ADC; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AP_ADC_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AP_ADC; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AP_ADC_MIN_LEN, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); } /** @@ -95,37 +108,33 @@ static inline uint16_t mavlink_msg_ap_adc_pack(uint8_t system_id, uint8_t compon * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ap_adc_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t adc1,uint16_t adc2,uint16_t adc3,uint16_t adc4,uint16_t adc5,uint16_t adc6) + mavlink_message_t* msg, + uint16_t adc1,uint16_t adc2,uint16_t adc3,uint16_t adc4,uint16_t adc5,uint16_t adc6) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AP_ADC_LEN]; - _mav_put_uint16_t(buf, 0, adc1); - _mav_put_uint16_t(buf, 2, adc2); - _mav_put_uint16_t(buf, 4, adc3); - _mav_put_uint16_t(buf, 6, adc4); - _mav_put_uint16_t(buf, 8, adc5); - _mav_put_uint16_t(buf, 10, adc6); + char buf[MAVLINK_MSG_ID_AP_ADC_LEN]; + _mav_put_uint16_t(buf, 0, adc1); + _mav_put_uint16_t(buf, 2, adc2); + _mav_put_uint16_t(buf, 4, adc3); + _mav_put_uint16_t(buf, 6, adc4); + _mav_put_uint16_t(buf, 8, adc5); + _mav_put_uint16_t(buf, 10, adc6); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AP_ADC_LEN); #else - mavlink_ap_adc_t packet; - packet.adc1 = adc1; - packet.adc2 = adc2; - packet.adc3 = adc3; - packet.adc4 = adc4; - packet.adc5 = adc5; - packet.adc6 = adc6; + mavlink_ap_adc_t packet; + packet.adc1 = adc1; + packet.adc2 = adc2; + packet.adc3 = adc3; + packet.adc4 = adc4; + packet.adc5 = adc5; + packet.adc6 = adc6; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AP_ADC_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AP_ADC; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AP_ADC_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AP_ADC; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AP_ADC_MIN_LEN, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_ap_adc_pack_chan(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_ap_adc_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_ap_adc_t* ap_adc) { - return mavlink_msg_ap_adc_pack(system_id, component_id, msg, ap_adc->adc1, ap_adc->adc2, ap_adc->adc3, ap_adc->adc4, ap_adc->adc5, ap_adc->adc6); + return mavlink_msg_ap_adc_pack(system_id, component_id, msg, ap_adc->adc1, ap_adc->adc2, ap_adc->adc3, ap_adc->adc4, ap_adc->adc5, ap_adc->adc6); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_ap_adc_encode(uint8_t system_id, uint8_t comp */ static inline uint16_t mavlink_msg_ap_adc_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ap_adc_t* ap_adc) { - return mavlink_msg_ap_adc_pack_chan(system_id, component_id, chan, msg, ap_adc->adc1, ap_adc->adc2, ap_adc->adc3, ap_adc->adc4, ap_adc->adc5, ap_adc->adc6); + return mavlink_msg_ap_adc_pack_chan(system_id, component_id, chan, msg, ap_adc->adc1, ap_adc->adc2, ap_adc->adc3, ap_adc->adc4, ap_adc->adc5, ap_adc->adc6); } /** @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_ap_adc_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_ap_adc_send(mavlink_channel_t chan, uint16_t adc1, uint16_t adc2, uint16_t adc3, uint16_t adc4, uint16_t adc5, uint16_t adc6) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AP_ADC_LEN]; - _mav_put_uint16_t(buf, 0, adc1); - _mav_put_uint16_t(buf, 2, adc2); - _mav_put_uint16_t(buf, 4, adc3); - _mav_put_uint16_t(buf, 6, adc4); - _mav_put_uint16_t(buf, 8, adc5); - _mav_put_uint16_t(buf, 10, adc6); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, buf, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); + char buf[MAVLINK_MSG_ID_AP_ADC_LEN]; + _mav_put_uint16_t(buf, 0, adc1); + _mav_put_uint16_t(buf, 2, adc2); + _mav_put_uint16_t(buf, 4, adc3); + _mav_put_uint16_t(buf, 6, adc4); + _mav_put_uint16_t(buf, 8, adc5); + _mav_put_uint16_t(buf, 10, adc6); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, buf, MAVLINK_MSG_ID_AP_ADC_MIN_LEN, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, buf, MAVLINK_MSG_ID_AP_ADC_LEN); + mavlink_ap_adc_t packet; + packet.adc1 = adc1; + packet.adc2 = adc2; + packet.adc3 = adc3; + packet.adc4 = adc4; + packet.adc5 = adc5; + packet.adc6 = adc6; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, (const char *)&packet, MAVLINK_MSG_ID_AP_ADC_MIN_LEN, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); #endif +} + +/** + * @brief Send a ap_adc message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_ap_adc_send_struct(mavlink_channel_t chan, const mavlink_ap_adc_t* ap_adc) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_ap_adc_send(chan, ap_adc->adc1, ap_adc->adc2, ap_adc->adc3, ap_adc->adc4, ap_adc->adc5, ap_adc->adc6); #else - mavlink_ap_adc_t packet; - packet.adc1 = adc1; - packet.adc2 = adc2; - packet.adc3 = adc3; - packet.adc4 = adc4; - packet.adc5 = adc5; - packet.adc6 = adc6; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, (const char *)&packet, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, (const char *)&packet, MAVLINK_MSG_ID_AP_ADC_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, (const char *)ap_adc, MAVLINK_MSG_ID_AP_ADC_MIN_LEN, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_ap_adc_send(mavlink_channel_t chan, uint16_t adc1 static inline void mavlink_msg_ap_adc_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t adc1, uint16_t adc2, uint16_t adc3, uint16_t adc4, uint16_t adc5, uint16_t adc6) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, adc1); - _mav_put_uint16_t(buf, 2, adc2); - _mav_put_uint16_t(buf, 4, adc3); - _mav_put_uint16_t(buf, 6, adc4); - _mav_put_uint16_t(buf, 8, adc5); - _mav_put_uint16_t(buf, 10, adc6); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, buf, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, adc1); + _mav_put_uint16_t(buf, 2, adc2); + _mav_put_uint16_t(buf, 4, adc3); + _mav_put_uint16_t(buf, 6, adc4); + _mav_put_uint16_t(buf, 8, adc5); + _mav_put_uint16_t(buf, 10, adc6); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, buf, MAVLINK_MSG_ID_AP_ADC_MIN_LEN, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, buf, MAVLINK_MSG_ID_AP_ADC_LEN); -#endif -#else - mavlink_ap_adc_t *packet = (mavlink_ap_adc_t *)msgbuf; - packet->adc1 = adc1; - packet->adc2 = adc2; - packet->adc3 = adc3; - packet->adc4 = adc4; - packet->adc5 = adc5; - packet->adc6 = adc6; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, (const char *)packet, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, (const char *)packet, MAVLINK_MSG_ID_AP_ADC_LEN); -#endif + mavlink_ap_adc_t *packet = (mavlink_ap_adc_t *)msgbuf; + packet->adc1 = adc1; + packet->adc2 = adc2; + packet->adc3 = adc3; + packet->adc4 = adc4; + packet->adc5 = adc5; + packet->adc6 = adc6; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AP_ADC, (const char *)packet, MAVLINK_MSG_ID_AP_ADC_MIN_LEN, MAVLINK_MSG_ID_AP_ADC_LEN, MAVLINK_MSG_ID_AP_ADC_CRC); #endif } #endif @@ -255,7 +262,7 @@ static inline void mavlink_msg_ap_adc_send_buf(mavlink_message_t *msgbuf, mavlin */ static inline uint16_t mavlink_msg_ap_adc_get_adc1(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -265,7 +272,7 @@ static inline uint16_t mavlink_msg_ap_adc_get_adc1(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_ap_adc_get_adc2(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 2); + return _MAV_RETURN_uint16_t(msg, 2); } /** @@ -275,7 +282,7 @@ static inline uint16_t mavlink_msg_ap_adc_get_adc2(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_ap_adc_get_adc3(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -285,7 +292,7 @@ static inline uint16_t mavlink_msg_ap_adc_get_adc3(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_ap_adc_get_adc4(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -295,7 +302,7 @@ static inline uint16_t mavlink_msg_ap_adc_get_adc4(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_ap_adc_get_adc5(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -305,7 +312,7 @@ static inline uint16_t mavlink_msg_ap_adc_get_adc5(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_ap_adc_get_adc6(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 10); + return _MAV_RETURN_uint16_t(msg, 10); } /** @@ -316,14 +323,16 @@ static inline uint16_t mavlink_msg_ap_adc_get_adc6(const mavlink_message_t* msg) */ static inline void mavlink_msg_ap_adc_decode(const mavlink_message_t* msg, mavlink_ap_adc_t* ap_adc) { -#if MAVLINK_NEED_BYTE_SWAP - ap_adc->adc1 = mavlink_msg_ap_adc_get_adc1(msg); - ap_adc->adc2 = mavlink_msg_ap_adc_get_adc2(msg); - ap_adc->adc3 = mavlink_msg_ap_adc_get_adc3(msg); - ap_adc->adc4 = mavlink_msg_ap_adc_get_adc4(msg); - ap_adc->adc5 = mavlink_msg_ap_adc_get_adc5(msg); - ap_adc->adc6 = mavlink_msg_ap_adc_get_adc6(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + ap_adc->adc1 = mavlink_msg_ap_adc_get_adc1(msg); + ap_adc->adc2 = mavlink_msg_ap_adc_get_adc2(msg); + ap_adc->adc3 = mavlink_msg_ap_adc_get_adc3(msg); + ap_adc->adc4 = mavlink_msg_ap_adc_get_adc4(msg); + ap_adc->adc5 = mavlink_msg_ap_adc_get_adc5(msg); + ap_adc->adc6 = mavlink_msg_ap_adc_get_adc6(msg); #else - memcpy(ap_adc, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AP_ADC_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AP_ADC_LEN? msg->len : MAVLINK_MSG_ID_AP_ADC_LEN; + memset(ap_adc, 0, MAVLINK_MSG_ID_AP_ADC_LEN); + memcpy(ap_adc, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_autopilot_version_request.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_autopilot_version_request.h index 0420d5d8a1..aae3bb9f87 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_autopilot_version_request.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_autopilot_version_request.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE AUTOPILOT_VERSION_REQUEST PACKING #define MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST 183 -typedef struct __mavlink_autopilot_version_request_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_autopilot_version_request_t; +MAVPACKED( +typedef struct __mavlink_autopilot_version_request_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_autopilot_version_request_t; #define MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN 2 +#define MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN 2 #define MAVLINK_MSG_ID_183_LEN 2 +#define MAVLINK_MSG_ID_183_MIN_LEN 2 #define MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC 85 #define MAVLINK_MSG_ID_183_CRC 85 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION_REQUEST { \ - "AUTOPILOT_VERSION_REQUEST", \ - 2, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_autopilot_version_request_t, target_system) }, \ + 183, \ + "AUTOPILOT_VERSION_REQUEST", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_autopilot_version_request_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_autopilot_version_request_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION_REQUEST { \ + "AUTOPILOT_VERSION_REQUEST", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_autopilot_version_request_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_autopilot_version_request_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a autopilot_version_request message @@ -36,28 +49,24 @@ typedef struct __mavlink_autopilot_version_request_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_autopilot_version_request_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component) + uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); #else - mavlink_autopilot_version_request_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_autopilot_version_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_autopilot_version_request_pack(uint8_t system * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_autopilot_version_request_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); #else - mavlink_autopilot_version_request_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_autopilot_version_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_autopilot_version_request_pack_chan(uint8_t s */ static inline uint16_t mavlink_msg_autopilot_version_request_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_autopilot_version_request_t* autopilot_version_request) { - return mavlink_msg_autopilot_version_request_pack(system_id, component_id, msg, autopilot_version_request->target_system, autopilot_version_request->target_component); + return mavlink_msg_autopilot_version_request_pack(system_id, component_id, msg, autopilot_version_request->target_system, autopilot_version_request->target_component); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_autopilot_version_request_encode(uint8_t syst */ static inline uint16_t mavlink_msg_autopilot_version_request_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_autopilot_version_request_t* autopilot_version_request) { - return mavlink_msg_autopilot_version_request_pack_chan(system_id, component_id, chan, msg, autopilot_version_request->target_system, autopilot_version_request->target_component); + return mavlink_msg_autopilot_version_request_pack_chan(system_id, component_id, chan, msg, autopilot_version_request->target_system, autopilot_version_request->target_component); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_autopilot_version_request_encode_chan(uint8_t static inline void mavlink_msg_autopilot_version_request_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); + mavlink_autopilot_version_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); #endif -#else - mavlink_autopilot_version_request_t packet; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); +/** + * @brief Send a autopilot_version_request message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_autopilot_version_request_send_struct(mavlink_channel_t chan, const mavlink_autopilot_version_request_t* autopilot_version_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_autopilot_version_request_send(chan, autopilot_version_request->target_system, autopilot_version_request->target_component); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, (const char *)autopilot_version_request, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_autopilot_version_request_send(mavlink_channel_t static inline void mavlink_msg_autopilot_version_request_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); #else - mavlink_autopilot_version_request_t *packet = (mavlink_autopilot_version_request_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_autopilot_version_request_t *packet = (mavlink_autopilot_version_request_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, (const char *)packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, (const char *)packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST, (const char *)packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_autopilot_version_request_send_buf(mavlink_messag */ static inline uint8_t mavlink_msg_autopilot_version_request_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint8_t mavlink_msg_autopilot_version_request_get_target_system(co */ static inline uint8_t mavlink_msg_autopilot_version_request_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_autopilot_version_request_get_target_component */ static inline void mavlink_msg_autopilot_version_request_decode(const mavlink_message_t* msg, mavlink_autopilot_version_request_t* autopilot_version_request) { -#if MAVLINK_NEED_BYTE_SWAP - autopilot_version_request->target_system = mavlink_msg_autopilot_version_request_get_target_system(msg); - autopilot_version_request->target_component = mavlink_msg_autopilot_version_request_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + autopilot_version_request->target_system = mavlink_msg_autopilot_version_request_get_target_system(msg); + autopilot_version_request->target_component = mavlink_msg_autopilot_version_request_get_target_component(msg); #else - memcpy(autopilot_version_request, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN? msg->len : MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN; + memset(autopilot_version_request, 0, MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_LEN); + memcpy(autopilot_version_request, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_battery2.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_battery2.h index c8c2bbf035..3a6de3858c 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_battery2.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_battery2.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE BATTERY2 PACKING #define MAVLINK_MSG_ID_BATTERY2 181 -typedef struct __mavlink_battery2_t -{ - uint16_t voltage; ///< voltage in millivolts - int16_t current_battery; ///< Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current -} mavlink_battery2_t; +MAVPACKED( +typedef struct __mavlink_battery2_t { + uint16_t voltage; /*< voltage in millivolts*/ + int16_t current_battery; /*< Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current*/ +}) mavlink_battery2_t; #define MAVLINK_MSG_ID_BATTERY2_LEN 4 +#define MAVLINK_MSG_ID_BATTERY2_MIN_LEN 4 #define MAVLINK_MSG_ID_181_LEN 4 +#define MAVLINK_MSG_ID_181_MIN_LEN 4 #define MAVLINK_MSG_ID_BATTERY2_CRC 174 #define MAVLINK_MSG_ID_181_CRC 174 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_BATTERY2 { \ - "BATTERY2", \ - 2, \ - { { "voltage", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_battery2_t, voltage) }, \ + 181, \ + "BATTERY2", \ + 2, \ + { { "voltage", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_battery2_t, voltage) }, \ { "current_battery", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_battery2_t, current_battery) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_BATTERY2 { \ + "BATTERY2", \ + 2, \ + { { "voltage", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_battery2_t, voltage) }, \ + { "current_battery", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_battery2_t, current_battery) }, \ + } \ +} +#endif /** * @brief Pack a battery2 message @@ -36,28 +49,24 @@ typedef struct __mavlink_battery2_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_battery2_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t voltage, int16_t current_battery) + uint16_t voltage, int16_t current_battery) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_BATTERY2_LEN]; - _mav_put_uint16_t(buf, 0, voltage); - _mav_put_int16_t(buf, 2, current_battery); + char buf[MAVLINK_MSG_ID_BATTERY2_LEN]; + _mav_put_uint16_t(buf, 0, voltage); + _mav_put_int16_t(buf, 2, current_battery); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_BATTERY2_LEN); #else - mavlink_battery2_t packet; - packet.voltage = voltage; - packet.current_battery = current_battery; + mavlink_battery2_t packet; + packet.voltage = voltage; + packet.current_battery = current_battery; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_BATTERY2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_BATTERY2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_BATTERY2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_BATTERY2; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_BATTERY2_MIN_LEN, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_battery2_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_battery2_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t voltage,int16_t current_battery) + mavlink_message_t* msg, + uint16_t voltage,int16_t current_battery) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_BATTERY2_LEN]; - _mav_put_uint16_t(buf, 0, voltage); - _mav_put_int16_t(buf, 2, current_battery); + char buf[MAVLINK_MSG_ID_BATTERY2_LEN]; + _mav_put_uint16_t(buf, 0, voltage); + _mav_put_int16_t(buf, 2, current_battery); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_BATTERY2_LEN); #else - mavlink_battery2_t packet; - packet.voltage = voltage; - packet.current_battery = current_battery; + mavlink_battery2_t packet; + packet.voltage = voltage; + packet.current_battery = current_battery; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_BATTERY2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_BATTERY2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_BATTERY2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_BATTERY2; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_BATTERY2_MIN_LEN, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_battery2_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_battery2_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_battery2_t* battery2) { - return mavlink_msg_battery2_pack(system_id, component_id, msg, battery2->voltage, battery2->current_battery); + return mavlink_msg_battery2_pack(system_id, component_id, msg, battery2->voltage, battery2->current_battery); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_battery2_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_battery2_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_battery2_t* battery2) { - return mavlink_msg_battery2_pack_chan(system_id, component_id, chan, msg, battery2->voltage, battery2->current_battery); + return mavlink_msg_battery2_pack_chan(system_id, component_id, chan, msg, battery2->voltage, battery2->current_battery); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_battery2_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_battery2_send(mavlink_channel_t chan, uint16_t voltage, int16_t current_battery) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_BATTERY2_LEN]; - _mav_put_uint16_t(buf, 0, voltage); - _mav_put_int16_t(buf, 2, current_battery); + char buf[MAVLINK_MSG_ID_BATTERY2_LEN]; + _mav_put_uint16_t(buf, 0, voltage); + _mav_put_int16_t(buf, 2, current_battery); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, buf, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, buf, MAVLINK_MSG_ID_BATTERY2_MIN_LEN, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, buf, MAVLINK_MSG_ID_BATTERY2_LEN); + mavlink_battery2_t packet; + packet.voltage = voltage; + packet.current_battery = current_battery; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, (const char *)&packet, MAVLINK_MSG_ID_BATTERY2_MIN_LEN, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); #endif -#else - mavlink_battery2_t packet; - packet.voltage = voltage; - packet.current_battery = current_battery; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, (const char *)&packet, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); +/** + * @brief Send a battery2 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_battery2_send_struct(mavlink_channel_t chan, const mavlink_battery2_t* battery2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_battery2_send(chan, battery2->voltage, battery2->current_battery); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, (const char *)&packet, MAVLINK_MSG_ID_BATTERY2_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, (const char *)battery2, MAVLINK_MSG_ID_BATTERY2_MIN_LEN, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_battery2_send(mavlink_channel_t chan, uint16_t vo static inline void mavlink_msg_battery2_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t voltage, int16_t current_battery) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, voltage); - _mav_put_int16_t(buf, 2, current_battery); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, voltage); + _mav_put_int16_t(buf, 2, current_battery); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, buf, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, buf, MAVLINK_MSG_ID_BATTERY2_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, buf, MAVLINK_MSG_ID_BATTERY2_MIN_LEN, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); #else - mavlink_battery2_t *packet = (mavlink_battery2_t *)msgbuf; - packet->voltage = voltage; - packet->current_battery = current_battery; + mavlink_battery2_t *packet = (mavlink_battery2_t *)msgbuf; + packet->voltage = voltage; + packet->current_battery = current_battery; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, (const char *)packet, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, (const char *)packet, MAVLINK_MSG_ID_BATTERY2_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY2, (const char *)packet, MAVLINK_MSG_ID_BATTERY2_MIN_LEN, MAVLINK_MSG_ID_BATTERY2_LEN, MAVLINK_MSG_ID_BATTERY2_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_battery2_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint16_t mavlink_msg_battery2_get_voltage(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint16_t mavlink_msg_battery2_get_voltage(const mavlink_message_t* */ static inline int16_t mavlink_msg_battery2_get_current_battery(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 2); + return _MAV_RETURN_int16_t(msg, 2); } /** @@ -224,10 +227,12 @@ static inline int16_t mavlink_msg_battery2_get_current_battery(const mavlink_mes */ static inline void mavlink_msg_battery2_decode(const mavlink_message_t* msg, mavlink_battery2_t* battery2) { -#if MAVLINK_NEED_BYTE_SWAP - battery2->voltage = mavlink_msg_battery2_get_voltage(msg); - battery2->current_battery = mavlink_msg_battery2_get_current_battery(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + battery2->voltage = mavlink_msg_battery2_get_voltage(msg); + battery2->current_battery = mavlink_msg_battery2_get_current_battery(msg); #else - memcpy(battery2, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_BATTERY2_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_BATTERY2_LEN? msg->len : MAVLINK_MSG_ID_BATTERY2_LEN; + memset(battery2, 0, MAVLINK_MSG_ID_BATTERY2_LEN); + memcpy(battery2, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_feedback.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_feedback.h index 6a9748d592..0b70ff727c 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_feedback.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_feedback.h @@ -1,36 +1,41 @@ +#pragma once // MESSAGE CAMERA_FEEDBACK PACKING #define MAVLINK_MSG_ID_CAMERA_FEEDBACK 180 -typedef struct __mavlink_camera_feedback_t -{ - uint64_t time_usec; ///< Image timestamp (microseconds since UNIX epoch), as passed in by CAMERA_STATUS message (or autopilot if no CCB) - int32_t lat; ///< Latitude in (deg * 1E7) - int32_t lng; ///< Longitude in (deg * 1E7) - float alt_msl; ///< Altitude Absolute (meters AMSL) - float alt_rel; ///< Altitude Relative (meters above HOME location) - float roll; ///< Camera Roll angle (earth frame, degrees, +-180) - float pitch; ///< Camera Pitch angle (earth frame, degrees, +-180) - float yaw; ///< Camera Yaw (earth frame, degrees, 0-360, true) - float foc_len; ///< Focal Length (mm) - uint16_t img_idx; ///< Image index - uint8_t target_system; ///< System ID - uint8_t cam_idx; ///< Camera ID - uint8_t flags; ///< See CAMERA_FEEDBACK_FLAGS enum for definition of the bitmask -} mavlink_camera_feedback_t; +MAVPACKED( +typedef struct __mavlink_camera_feedback_t { + uint64_t time_usec; /*< Image timestamp (microseconds since UNIX epoch), as passed in by CAMERA_STATUS message (or autopilot if no CCB)*/ + int32_t lat; /*< Latitude in (deg * 1E7)*/ + int32_t lng; /*< Longitude in (deg * 1E7)*/ + float alt_msl; /*< Altitude Absolute (meters AMSL)*/ + float alt_rel; /*< Altitude Relative (meters above HOME location)*/ + float roll; /*< Camera Roll angle (earth frame, degrees, +-180)*/ + float pitch; /*< Camera Pitch angle (earth frame, degrees, +-180)*/ + float yaw; /*< Camera Yaw (earth frame, degrees, 0-360, true)*/ + float foc_len; /*< Focal Length (mm)*/ + uint16_t img_idx; /*< Image index*/ + uint8_t target_system; /*< System ID*/ + uint8_t cam_idx; /*< Camera ID*/ + uint8_t flags; /*< See CAMERA_FEEDBACK_FLAGS enum for definition of the bitmask*/ +}) mavlink_camera_feedback_t; #define MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN 45 +#define MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN 45 #define MAVLINK_MSG_ID_180_LEN 45 +#define MAVLINK_MSG_ID_180_MIN_LEN 45 #define MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC 52 #define MAVLINK_MSG_ID_180_CRC 52 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_CAMERA_FEEDBACK { \ - "CAMERA_FEEDBACK", \ - 13, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_feedback_t, time_usec) }, \ + 180, \ + "CAMERA_FEEDBACK", \ + 13, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_feedback_t, time_usec) }, \ { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_camera_feedback_t, lat) }, \ { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_camera_feedback_t, lng) }, \ { "alt_msl", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_camera_feedback_t, alt_msl) }, \ @@ -45,7 +50,26 @@ typedef struct __mavlink_camera_feedback_t { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 44, offsetof(mavlink_camera_feedback_t, flags) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_CAMERA_FEEDBACK { \ + "CAMERA_FEEDBACK", \ + 13, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_feedback_t, time_usec) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_camera_feedback_t, lat) }, \ + { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_camera_feedback_t, lng) }, \ + { "alt_msl", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_camera_feedback_t, alt_msl) }, \ + { "alt_rel", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_camera_feedback_t, alt_rel) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_camera_feedback_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_camera_feedback_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_camera_feedback_t, yaw) }, \ + { "foc_len", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_camera_feedback_t, foc_len) }, \ + { "img_idx", NULL, MAVLINK_TYPE_UINT16_T, 0, 40, offsetof(mavlink_camera_feedback_t, img_idx) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_camera_feedback_t, target_system) }, \ + { "cam_idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 43, offsetof(mavlink_camera_feedback_t, cam_idx) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 44, offsetof(mavlink_camera_feedback_t, flags) }, \ + } \ +} +#endif /** * @brief Pack a camera_feedback message @@ -69,50 +93,46 @@ typedef struct __mavlink_camera_feedback_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_camera_feedback_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, int32_t lat, int32_t lng, float alt_msl, float alt_rel, float roll, float pitch, float yaw, float foc_len, uint8_t flags) + uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, int32_t lat, int32_t lng, float alt_msl, float alt_rel, float roll, float pitch, float yaw, float foc_len, uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lng); - _mav_put_float(buf, 16, alt_msl); - _mav_put_float(buf, 20, alt_rel); - _mav_put_float(buf, 24, roll); - _mav_put_float(buf, 28, pitch); - _mav_put_float(buf, 32, yaw); - _mav_put_float(buf, 36, foc_len); - _mav_put_uint16_t(buf, 40, img_idx); - _mav_put_uint8_t(buf, 42, target_system); - _mav_put_uint8_t(buf, 43, cam_idx); - _mav_put_uint8_t(buf, 44, flags); + char buf[MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lng); + _mav_put_float(buf, 16, alt_msl); + _mav_put_float(buf, 20, alt_rel); + _mav_put_float(buf, 24, roll); + _mav_put_float(buf, 28, pitch); + _mav_put_float(buf, 32, yaw); + _mav_put_float(buf, 36, foc_len); + _mav_put_uint16_t(buf, 40, img_idx); + _mav_put_uint8_t(buf, 42, target_system); + _mav_put_uint8_t(buf, 43, cam_idx); + _mav_put_uint8_t(buf, 44, flags); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); #else - mavlink_camera_feedback_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lng = lng; - packet.alt_msl = alt_msl; - packet.alt_rel = alt_rel; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.foc_len = foc_len; - packet.img_idx = img_idx; - packet.target_system = target_system; - packet.cam_idx = cam_idx; - packet.flags = flags; + mavlink_camera_feedback_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lng = lng; + packet.alt_msl = alt_msl; + packet.alt_rel = alt_rel; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.foc_len = foc_len; + packet.img_idx = img_idx; + packet.target_system = target_system; + packet.cam_idx = cam_idx; + packet.flags = flags; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CAMERA_FEEDBACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CAMERA_FEEDBACK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); } /** @@ -137,51 +157,47 @@ static inline uint16_t mavlink_msg_camera_feedback_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_camera_feedback_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t target_system,uint8_t cam_idx,uint16_t img_idx,int32_t lat,int32_t lng,float alt_msl,float alt_rel,float roll,float pitch,float yaw,float foc_len,uint8_t flags) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t target_system,uint8_t cam_idx,uint16_t img_idx,int32_t lat,int32_t lng,float alt_msl,float alt_rel,float roll,float pitch,float yaw,float foc_len,uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lng); - _mav_put_float(buf, 16, alt_msl); - _mav_put_float(buf, 20, alt_rel); - _mav_put_float(buf, 24, roll); - _mav_put_float(buf, 28, pitch); - _mav_put_float(buf, 32, yaw); - _mav_put_float(buf, 36, foc_len); - _mav_put_uint16_t(buf, 40, img_idx); - _mav_put_uint8_t(buf, 42, target_system); - _mav_put_uint8_t(buf, 43, cam_idx); - _mav_put_uint8_t(buf, 44, flags); + char buf[MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lng); + _mav_put_float(buf, 16, alt_msl); + _mav_put_float(buf, 20, alt_rel); + _mav_put_float(buf, 24, roll); + _mav_put_float(buf, 28, pitch); + _mav_put_float(buf, 32, yaw); + _mav_put_float(buf, 36, foc_len); + _mav_put_uint16_t(buf, 40, img_idx); + _mav_put_uint8_t(buf, 42, target_system); + _mav_put_uint8_t(buf, 43, cam_idx); + _mav_put_uint8_t(buf, 44, flags); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); #else - mavlink_camera_feedback_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lng = lng; - packet.alt_msl = alt_msl; - packet.alt_rel = alt_rel; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.foc_len = foc_len; - packet.img_idx = img_idx; - packet.target_system = target_system; - packet.cam_idx = cam_idx; - packet.flags = flags; + mavlink_camera_feedback_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lng = lng; + packet.alt_msl = alt_msl; + packet.alt_rel = alt_rel; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.foc_len = foc_len; + packet.img_idx = img_idx; + packet.target_system = target_system; + packet.cam_idx = cam_idx; + packet.flags = flags; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CAMERA_FEEDBACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CAMERA_FEEDBACK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); } /** @@ -194,7 +210,7 @@ static inline uint16_t mavlink_msg_camera_feedback_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_camera_feedback_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_camera_feedback_t* camera_feedback) { - return mavlink_msg_camera_feedback_pack(system_id, component_id, msg, camera_feedback->time_usec, camera_feedback->target_system, camera_feedback->cam_idx, camera_feedback->img_idx, camera_feedback->lat, camera_feedback->lng, camera_feedback->alt_msl, camera_feedback->alt_rel, camera_feedback->roll, camera_feedback->pitch, camera_feedback->yaw, camera_feedback->foc_len, camera_feedback->flags); + return mavlink_msg_camera_feedback_pack(system_id, component_id, msg, camera_feedback->time_usec, camera_feedback->target_system, camera_feedback->cam_idx, camera_feedback->img_idx, camera_feedback->lat, camera_feedback->lng, camera_feedback->alt_msl, camera_feedback->alt_rel, camera_feedback->roll, camera_feedback->pitch, camera_feedback->yaw, camera_feedback->foc_len, camera_feedback->flags); } /** @@ -208,7 +224,7 @@ static inline uint16_t mavlink_msg_camera_feedback_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_camera_feedback_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_camera_feedback_t* camera_feedback) { - return mavlink_msg_camera_feedback_pack_chan(system_id, component_id, chan, msg, camera_feedback->time_usec, camera_feedback->target_system, camera_feedback->cam_idx, camera_feedback->img_idx, camera_feedback->lat, camera_feedback->lng, camera_feedback->alt_msl, camera_feedback->alt_rel, camera_feedback->roll, camera_feedback->pitch, camera_feedback->yaw, camera_feedback->foc_len, camera_feedback->flags); + return mavlink_msg_camera_feedback_pack_chan(system_id, component_id, chan, msg, camera_feedback->time_usec, camera_feedback->target_system, camera_feedback->cam_idx, camera_feedback->img_idx, camera_feedback->lat, camera_feedback->lng, camera_feedback->alt_msl, camera_feedback->alt_rel, camera_feedback->roll, camera_feedback->pitch, camera_feedback->yaw, camera_feedback->foc_len, camera_feedback->flags); } /** @@ -234,47 +250,53 @@ static inline uint16_t mavlink_msg_camera_feedback_encode_chan(uint8_t system_id static inline void mavlink_msg_camera_feedback_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, int32_t lat, int32_t lng, float alt_msl, float alt_rel, float roll, float pitch, float yaw, float foc_len, uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lng); - _mav_put_float(buf, 16, alt_msl); - _mav_put_float(buf, 20, alt_rel); - _mav_put_float(buf, 24, roll); - _mav_put_float(buf, 28, pitch); - _mav_put_float(buf, 32, yaw); - _mav_put_float(buf, 36, foc_len); - _mav_put_uint16_t(buf, 40, img_idx); - _mav_put_uint8_t(buf, 42, target_system); - _mav_put_uint8_t(buf, 43, cam_idx); - _mav_put_uint8_t(buf, 44, flags); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); + char buf[MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lng); + _mav_put_float(buf, 16, alt_msl); + _mav_put_float(buf, 20, alt_rel); + _mav_put_float(buf, 24, roll); + _mav_put_float(buf, 28, pitch); + _mav_put_float(buf, 32, yaw); + _mav_put_float(buf, 36, foc_len); + _mav_put_uint16_t(buf, 40, img_idx); + _mav_put_uint8_t(buf, 42, target_system); + _mav_put_uint8_t(buf, 43, cam_idx); + _mav_put_uint8_t(buf, 44, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); + mavlink_camera_feedback_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lng = lng; + packet.alt_msl = alt_msl; + packet.alt_rel = alt_rel; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.foc_len = foc_len; + packet.img_idx = img_idx; + packet.target_system = target_system; + packet.cam_idx = cam_idx; + packet.flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, (const char *)&packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); #endif +} + +/** + * @brief Send a camera_feedback message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_camera_feedback_send_struct(mavlink_channel_t chan, const mavlink_camera_feedback_t* camera_feedback) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_camera_feedback_send(chan, camera_feedback->time_usec, camera_feedback->target_system, camera_feedback->cam_idx, camera_feedback->img_idx, camera_feedback->lat, camera_feedback->lng, camera_feedback->alt_msl, camera_feedback->alt_rel, camera_feedback->roll, camera_feedback->pitch, camera_feedback->yaw, camera_feedback->foc_len, camera_feedback->flags); #else - mavlink_camera_feedback_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lng = lng; - packet.alt_msl = alt_msl; - packet.alt_rel = alt_rel; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.foc_len = foc_len; - packet.img_idx = img_idx; - packet.target_system = target_system; - packet.cam_idx = cam_idx; - packet.flags = flags; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, (const char *)&packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, (const char *)&packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, (const char *)camera_feedback, MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); #endif } @@ -289,47 +311,39 @@ static inline void mavlink_msg_camera_feedback_send(mavlink_channel_t chan, uint static inline void mavlink_msg_camera_feedback_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, int32_t lat, int32_t lng, float alt_msl, float alt_rel, float roll, float pitch, float yaw, float foc_len, uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lng); - _mav_put_float(buf, 16, alt_msl); - _mav_put_float(buf, 20, alt_rel); - _mav_put_float(buf, 24, roll); - _mav_put_float(buf, 28, pitch); - _mav_put_float(buf, 32, yaw); - _mav_put_float(buf, 36, foc_len); - _mav_put_uint16_t(buf, 40, img_idx); - _mav_put_uint8_t(buf, 42, target_system); - _mav_put_uint8_t(buf, 43, cam_idx); - _mav_put_uint8_t(buf, 44, flags); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lng); + _mav_put_float(buf, 16, alt_msl); + _mav_put_float(buf, 20, alt_rel); + _mav_put_float(buf, 24, roll); + _mav_put_float(buf, 28, pitch); + _mav_put_float(buf, 32, yaw); + _mav_put_float(buf, 36, foc_len); + _mav_put_uint16_t(buf, 40, img_idx); + _mav_put_uint8_t(buf, 42, target_system); + _mav_put_uint8_t(buf, 43, cam_idx); + _mav_put_uint8_t(buf, 44, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, buf, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); -#endif -#else - mavlink_camera_feedback_t *packet = (mavlink_camera_feedback_t *)msgbuf; - packet->time_usec = time_usec; - packet->lat = lat; - packet->lng = lng; - packet->alt_msl = alt_msl; - packet->alt_rel = alt_rel; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->foc_len = foc_len; - packet->img_idx = img_idx; - packet->target_system = target_system; - packet->cam_idx = cam_idx; - packet->flags = flags; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, (const char *)packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, (const char *)packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); -#endif + mavlink_camera_feedback_t *packet = (mavlink_camera_feedback_t *)msgbuf; + packet->time_usec = time_usec; + packet->lat = lat; + packet->lng = lng; + packet->alt_msl = alt_msl; + packet->alt_rel = alt_rel; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->foc_len = foc_len; + packet->img_idx = img_idx; + packet->target_system = target_system; + packet->cam_idx = cam_idx; + packet->flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_FEEDBACK, (const char *)packet, MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN, MAVLINK_MSG_ID_CAMERA_FEEDBACK_CRC); #endif } #endif @@ -346,7 +360,7 @@ static inline void mavlink_msg_camera_feedback_send_buf(mavlink_message_t *msgbu */ static inline uint64_t mavlink_msg_camera_feedback_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -356,7 +370,7 @@ static inline uint64_t mavlink_msg_camera_feedback_get_time_usec(const mavlink_m */ static inline uint8_t mavlink_msg_camera_feedback_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 42); + return _MAV_RETURN_uint8_t(msg, 42); } /** @@ -366,7 +380,7 @@ static inline uint8_t mavlink_msg_camera_feedback_get_target_system(const mavlin */ static inline uint8_t mavlink_msg_camera_feedback_get_cam_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 43); + return _MAV_RETURN_uint8_t(msg, 43); } /** @@ -376,7 +390,7 @@ static inline uint8_t mavlink_msg_camera_feedback_get_cam_idx(const mavlink_mess */ static inline uint16_t mavlink_msg_camera_feedback_get_img_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 40); + return _MAV_RETURN_uint16_t(msg, 40); } /** @@ -386,7 +400,7 @@ static inline uint16_t mavlink_msg_camera_feedback_get_img_idx(const mavlink_mes */ static inline int32_t mavlink_msg_camera_feedback_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -396,7 +410,7 @@ static inline int32_t mavlink_msg_camera_feedback_get_lat(const mavlink_message_ */ static inline int32_t mavlink_msg_camera_feedback_get_lng(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -406,7 +420,7 @@ static inline int32_t mavlink_msg_camera_feedback_get_lng(const mavlink_message_ */ static inline float mavlink_msg_camera_feedback_get_alt_msl(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -416,7 +430,7 @@ static inline float mavlink_msg_camera_feedback_get_alt_msl(const mavlink_messag */ static inline float mavlink_msg_camera_feedback_get_alt_rel(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -426,7 +440,7 @@ static inline float mavlink_msg_camera_feedback_get_alt_rel(const mavlink_messag */ static inline float mavlink_msg_camera_feedback_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -436,7 +450,7 @@ static inline float mavlink_msg_camera_feedback_get_roll(const mavlink_message_t */ static inline float mavlink_msg_camera_feedback_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -446,7 +460,7 @@ static inline float mavlink_msg_camera_feedback_get_pitch(const mavlink_message_ */ static inline float mavlink_msg_camera_feedback_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -456,7 +470,7 @@ static inline float mavlink_msg_camera_feedback_get_yaw(const mavlink_message_t* */ static inline float mavlink_msg_camera_feedback_get_foc_len(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -466,7 +480,7 @@ static inline float mavlink_msg_camera_feedback_get_foc_len(const mavlink_messag */ static inline uint8_t mavlink_msg_camera_feedback_get_flags(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 44); + return _MAV_RETURN_uint8_t(msg, 44); } /** @@ -477,21 +491,23 @@ static inline uint8_t mavlink_msg_camera_feedback_get_flags(const mavlink_messag */ static inline void mavlink_msg_camera_feedback_decode(const mavlink_message_t* msg, mavlink_camera_feedback_t* camera_feedback) { -#if MAVLINK_NEED_BYTE_SWAP - camera_feedback->time_usec = mavlink_msg_camera_feedback_get_time_usec(msg); - camera_feedback->lat = mavlink_msg_camera_feedback_get_lat(msg); - camera_feedback->lng = mavlink_msg_camera_feedback_get_lng(msg); - camera_feedback->alt_msl = mavlink_msg_camera_feedback_get_alt_msl(msg); - camera_feedback->alt_rel = mavlink_msg_camera_feedback_get_alt_rel(msg); - camera_feedback->roll = mavlink_msg_camera_feedback_get_roll(msg); - camera_feedback->pitch = mavlink_msg_camera_feedback_get_pitch(msg); - camera_feedback->yaw = mavlink_msg_camera_feedback_get_yaw(msg); - camera_feedback->foc_len = mavlink_msg_camera_feedback_get_foc_len(msg); - camera_feedback->img_idx = mavlink_msg_camera_feedback_get_img_idx(msg); - camera_feedback->target_system = mavlink_msg_camera_feedback_get_target_system(msg); - camera_feedback->cam_idx = mavlink_msg_camera_feedback_get_cam_idx(msg); - camera_feedback->flags = mavlink_msg_camera_feedback_get_flags(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + camera_feedback->time_usec = mavlink_msg_camera_feedback_get_time_usec(msg); + camera_feedback->lat = mavlink_msg_camera_feedback_get_lat(msg); + camera_feedback->lng = mavlink_msg_camera_feedback_get_lng(msg); + camera_feedback->alt_msl = mavlink_msg_camera_feedback_get_alt_msl(msg); + camera_feedback->alt_rel = mavlink_msg_camera_feedback_get_alt_rel(msg); + camera_feedback->roll = mavlink_msg_camera_feedback_get_roll(msg); + camera_feedback->pitch = mavlink_msg_camera_feedback_get_pitch(msg); + camera_feedback->yaw = mavlink_msg_camera_feedback_get_yaw(msg); + camera_feedback->foc_len = mavlink_msg_camera_feedback_get_foc_len(msg); + camera_feedback->img_idx = mavlink_msg_camera_feedback_get_img_idx(msg); + camera_feedback->target_system = mavlink_msg_camera_feedback_get_target_system(msg); + camera_feedback->cam_idx = mavlink_msg_camera_feedback_get_cam_idx(msg); + camera_feedback->flags = mavlink_msg_camera_feedback_get_flags(msg); #else - memcpy(camera_feedback, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN? msg->len : MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN; + memset(camera_feedback, 0, MAVLINK_MSG_ID_CAMERA_FEEDBACK_LEN); + memcpy(camera_feedback, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_status.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_status.h index 9d1e54e360..140fbadf35 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_status.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_camera_status.h @@ -1,32 +1,37 @@ +#pragma once // MESSAGE CAMERA_STATUS PACKING #define MAVLINK_MSG_ID_CAMERA_STATUS 179 -typedef struct __mavlink_camera_status_t -{ - uint64_t time_usec; ///< Image timestamp (microseconds since UNIX epoch, according to camera clock) - float p1; ///< Parameter 1 (meaning depends on event, see CAMERA_STATUS_TYPES enum) - float p2; ///< Parameter 2 (meaning depends on event, see CAMERA_STATUS_TYPES enum) - float p3; ///< Parameter 3 (meaning depends on event, see CAMERA_STATUS_TYPES enum) - float p4; ///< Parameter 4 (meaning depends on event, see CAMERA_STATUS_TYPES enum) - uint16_t img_idx; ///< Image index - uint8_t target_system; ///< System ID - uint8_t cam_idx; ///< Camera ID - uint8_t event_id; ///< See CAMERA_STATUS_TYPES enum for definition of the bitmask -} mavlink_camera_status_t; +MAVPACKED( +typedef struct __mavlink_camera_status_t { + uint64_t time_usec; /*< Image timestamp (microseconds since UNIX epoch, according to camera clock)*/ + float p1; /*< Parameter 1 (meaning depends on event, see CAMERA_STATUS_TYPES enum)*/ + float p2; /*< Parameter 2 (meaning depends on event, see CAMERA_STATUS_TYPES enum)*/ + float p3; /*< Parameter 3 (meaning depends on event, see CAMERA_STATUS_TYPES enum)*/ + float p4; /*< Parameter 4 (meaning depends on event, see CAMERA_STATUS_TYPES enum)*/ + uint16_t img_idx; /*< Image index*/ + uint8_t target_system; /*< System ID*/ + uint8_t cam_idx; /*< Camera ID*/ + uint8_t event_id; /*< See CAMERA_STATUS_TYPES enum for definition of the bitmask*/ +}) mavlink_camera_status_t; #define MAVLINK_MSG_ID_CAMERA_STATUS_LEN 29 +#define MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN 29 #define MAVLINK_MSG_ID_179_LEN 29 +#define MAVLINK_MSG_ID_179_MIN_LEN 29 #define MAVLINK_MSG_ID_CAMERA_STATUS_CRC 189 #define MAVLINK_MSG_ID_179_CRC 189 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_CAMERA_STATUS { \ - "CAMERA_STATUS", \ - 9, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_status_t, time_usec) }, \ + 179, \ + "CAMERA_STATUS", \ + 9, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_status_t, time_usec) }, \ { "p1", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_camera_status_t, p1) }, \ { "p2", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_camera_status_t, p2) }, \ { "p3", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_camera_status_t, p3) }, \ @@ -37,7 +42,22 @@ typedef struct __mavlink_camera_status_t { "event_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 28, offsetof(mavlink_camera_status_t, event_id) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_CAMERA_STATUS { \ + "CAMERA_STATUS", \ + 9, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_status_t, time_usec) }, \ + { "p1", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_camera_status_t, p1) }, \ + { "p2", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_camera_status_t, p2) }, \ + { "p3", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_camera_status_t, p3) }, \ + { "p4", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_camera_status_t, p4) }, \ + { "img_idx", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_camera_status_t, img_idx) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 26, offsetof(mavlink_camera_status_t, target_system) }, \ + { "cam_idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 27, offsetof(mavlink_camera_status_t, cam_idx) }, \ + { "event_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 28, offsetof(mavlink_camera_status_t, event_id) }, \ + } \ +} +#endif /** * @brief Pack a camera_status message @@ -57,42 +77,38 @@ typedef struct __mavlink_camera_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_camera_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, uint8_t event_id, float p1, float p2, float p3, float p4) + uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, uint8_t event_id, float p1, float p2, float p3, float p4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CAMERA_STATUS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, p1); - _mav_put_float(buf, 12, p2); - _mav_put_float(buf, 16, p3); - _mav_put_float(buf, 20, p4); - _mav_put_uint16_t(buf, 24, img_idx); - _mav_put_uint8_t(buf, 26, target_system); - _mav_put_uint8_t(buf, 27, cam_idx); - _mav_put_uint8_t(buf, 28, event_id); + char buf[MAVLINK_MSG_ID_CAMERA_STATUS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, p1); + _mav_put_float(buf, 12, p2); + _mav_put_float(buf, 16, p3); + _mav_put_float(buf, 20, p4); + _mav_put_uint16_t(buf, 24, img_idx); + _mav_put_uint8_t(buf, 26, target_system); + _mav_put_uint8_t(buf, 27, cam_idx); + _mav_put_uint8_t(buf, 28, event_id); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); #else - mavlink_camera_status_t packet; - packet.time_usec = time_usec; - packet.p1 = p1; - packet.p2 = p2; - packet.p3 = p3; - packet.p4 = p4; - packet.img_idx = img_idx; - packet.target_system = target_system; - packet.cam_idx = cam_idx; - packet.event_id = event_id; + mavlink_camera_status_t packet; + packet.time_usec = time_usec; + packet.p1 = p1; + packet.p2 = p2; + packet.p3 = p3; + packet.p4 = p4; + packet.img_idx = img_idx; + packet.target_system = target_system; + packet.cam_idx = cam_idx; + packet.event_id = event_id; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CAMERA_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CAMERA_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); } /** @@ -113,43 +129,39 @@ static inline uint16_t mavlink_msg_camera_status_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_camera_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t target_system,uint8_t cam_idx,uint16_t img_idx,uint8_t event_id,float p1,float p2,float p3,float p4) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t target_system,uint8_t cam_idx,uint16_t img_idx,uint8_t event_id,float p1,float p2,float p3,float p4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CAMERA_STATUS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, p1); - _mav_put_float(buf, 12, p2); - _mav_put_float(buf, 16, p3); - _mav_put_float(buf, 20, p4); - _mav_put_uint16_t(buf, 24, img_idx); - _mav_put_uint8_t(buf, 26, target_system); - _mav_put_uint8_t(buf, 27, cam_idx); - _mav_put_uint8_t(buf, 28, event_id); + char buf[MAVLINK_MSG_ID_CAMERA_STATUS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, p1); + _mav_put_float(buf, 12, p2); + _mav_put_float(buf, 16, p3); + _mav_put_float(buf, 20, p4); + _mav_put_uint16_t(buf, 24, img_idx); + _mav_put_uint8_t(buf, 26, target_system); + _mav_put_uint8_t(buf, 27, cam_idx); + _mav_put_uint8_t(buf, 28, event_id); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); #else - mavlink_camera_status_t packet; - packet.time_usec = time_usec; - packet.p1 = p1; - packet.p2 = p2; - packet.p3 = p3; - packet.p4 = p4; - packet.img_idx = img_idx; - packet.target_system = target_system; - packet.cam_idx = cam_idx; - packet.event_id = event_id; + mavlink_camera_status_t packet; + packet.time_usec = time_usec; + packet.p1 = p1; + packet.p2 = p2; + packet.p3 = p3; + packet.p4 = p4; + packet.img_idx = img_idx; + packet.target_system = target_system; + packet.cam_idx = cam_idx; + packet.event_id = event_id; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CAMERA_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CAMERA_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); } /** @@ -162,7 +174,7 @@ static inline uint16_t mavlink_msg_camera_status_pack_chan(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_camera_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_camera_status_t* camera_status) { - return mavlink_msg_camera_status_pack(system_id, component_id, msg, camera_status->time_usec, camera_status->target_system, camera_status->cam_idx, camera_status->img_idx, camera_status->event_id, camera_status->p1, camera_status->p2, camera_status->p3, camera_status->p4); + return mavlink_msg_camera_status_pack(system_id, component_id, msg, camera_status->time_usec, camera_status->target_system, camera_status->cam_idx, camera_status->img_idx, camera_status->event_id, camera_status->p1, camera_status->p2, camera_status->p3, camera_status->p4); } /** @@ -176,7 +188,7 @@ static inline uint16_t mavlink_msg_camera_status_encode(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_camera_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_camera_status_t* camera_status) { - return mavlink_msg_camera_status_pack_chan(system_id, component_id, chan, msg, camera_status->time_usec, camera_status->target_system, camera_status->cam_idx, camera_status->img_idx, camera_status->event_id, camera_status->p1, camera_status->p2, camera_status->p3, camera_status->p4); + return mavlink_msg_camera_status_pack_chan(system_id, component_id, chan, msg, camera_status->time_usec, camera_status->target_system, camera_status->cam_idx, camera_status->img_idx, camera_status->event_id, camera_status->p1, camera_status->p2, camera_status->p3, camera_status->p4); } /** @@ -198,39 +210,45 @@ static inline uint16_t mavlink_msg_camera_status_encode_chan(uint8_t system_id, static inline void mavlink_msg_camera_status_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, uint8_t event_id, float p1, float p2, float p3, float p4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CAMERA_STATUS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, p1); - _mav_put_float(buf, 12, p2); - _mav_put_float(buf, 16, p3); - _mav_put_float(buf, 20, p4); - _mav_put_uint16_t(buf, 24, img_idx); - _mav_put_uint8_t(buf, 26, target_system); - _mav_put_uint8_t(buf, 27, cam_idx); - _mav_put_uint8_t(buf, 28, event_id); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, buf, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); + char buf[MAVLINK_MSG_ID_CAMERA_STATUS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, p1); + _mav_put_float(buf, 12, p2); + _mav_put_float(buf, 16, p3); + _mav_put_float(buf, 20, p4); + _mav_put_uint16_t(buf, 24, img_idx); + _mav_put_uint8_t(buf, 26, target_system); + _mav_put_uint8_t(buf, 27, cam_idx); + _mav_put_uint8_t(buf, 28, event_id); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, buf, MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, buf, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); + mavlink_camera_status_t packet; + packet.time_usec = time_usec; + packet.p1 = p1; + packet.p2 = p2; + packet.p3 = p3; + packet.p4 = p4; + packet.img_idx = img_idx; + packet.target_system = target_system; + packet.cam_idx = cam_idx; + packet.event_id = event_id; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, (const char *)&packet, MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); #endif +} + +/** + * @brief Send a camera_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_camera_status_send_struct(mavlink_channel_t chan, const mavlink_camera_status_t* camera_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_camera_status_send(chan, camera_status->time_usec, camera_status->target_system, camera_status->cam_idx, camera_status->img_idx, camera_status->event_id, camera_status->p1, camera_status->p2, camera_status->p3, camera_status->p4); #else - mavlink_camera_status_t packet; - packet.time_usec = time_usec; - packet.p1 = p1; - packet.p2 = p2; - packet.p3 = p3; - packet.p4 = p4; - packet.img_idx = img_idx; - packet.target_system = target_system; - packet.cam_idx = cam_idx; - packet.event_id = event_id; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, (const char *)&packet, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, (const char *)&packet, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, (const char *)camera_status, MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); #endif } @@ -245,39 +263,31 @@ static inline void mavlink_msg_camera_status_send(mavlink_channel_t chan, uint64 static inline void mavlink_msg_camera_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t target_system, uint8_t cam_idx, uint16_t img_idx, uint8_t event_id, float p1, float p2, float p3, float p4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, p1); - _mav_put_float(buf, 12, p2); - _mav_put_float(buf, 16, p3); - _mav_put_float(buf, 20, p4); - _mav_put_uint16_t(buf, 24, img_idx); - _mav_put_uint8_t(buf, 26, target_system); - _mav_put_uint8_t(buf, 27, cam_idx); - _mav_put_uint8_t(buf, 28, event_id); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, buf, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, buf, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); -#endif -#else - mavlink_camera_status_t *packet = (mavlink_camera_status_t *)msgbuf; - packet->time_usec = time_usec; - packet->p1 = p1; - packet->p2 = p2; - packet->p3 = p3; - packet->p4 = p4; - packet->img_idx = img_idx; - packet->target_system = target_system; - packet->cam_idx = cam_idx; - packet->event_id = event_id; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, (const char *)packet, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, p1); + _mav_put_float(buf, 12, p2); + _mav_put_float(buf, 16, p3); + _mav_put_float(buf, 20, p4); + _mav_put_uint16_t(buf, 24, img_idx); + _mav_put_uint8_t(buf, 26, target_system); + _mav_put_uint8_t(buf, 27, cam_idx); + _mav_put_uint8_t(buf, 28, event_id); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, buf, MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, (const char *)packet, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); -#endif + mavlink_camera_status_t *packet = (mavlink_camera_status_t *)msgbuf; + packet->time_usec = time_usec; + packet->p1 = p1; + packet->p2 = p2; + packet->p3 = p3; + packet->p4 = p4; + packet->img_idx = img_idx; + packet->target_system = target_system; + packet->cam_idx = cam_idx; + packet->event_id = event_id; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_STATUS, (const char *)packet, MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_LEN, MAVLINK_MSG_ID_CAMERA_STATUS_CRC); #endif } #endif @@ -294,7 +304,7 @@ static inline void mavlink_msg_camera_status_send_buf(mavlink_message_t *msgbuf, */ static inline uint64_t mavlink_msg_camera_status_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -304,7 +314,7 @@ static inline uint64_t mavlink_msg_camera_status_get_time_usec(const mavlink_mes */ static inline uint8_t mavlink_msg_camera_status_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 26); + return _MAV_RETURN_uint8_t(msg, 26); } /** @@ -314,7 +324,7 @@ static inline uint8_t mavlink_msg_camera_status_get_target_system(const mavlink_ */ static inline uint8_t mavlink_msg_camera_status_get_cam_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 27); + return _MAV_RETURN_uint8_t(msg, 27); } /** @@ -324,7 +334,7 @@ static inline uint8_t mavlink_msg_camera_status_get_cam_idx(const mavlink_messag */ static inline uint16_t mavlink_msg_camera_status_get_img_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -334,7 +344,7 @@ static inline uint16_t mavlink_msg_camera_status_get_img_idx(const mavlink_messa */ static inline uint8_t mavlink_msg_camera_status_get_event_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 28); + return _MAV_RETURN_uint8_t(msg, 28); } /** @@ -344,7 +354,7 @@ static inline uint8_t mavlink_msg_camera_status_get_event_id(const mavlink_messa */ static inline float mavlink_msg_camera_status_get_p1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -354,7 +364,7 @@ static inline float mavlink_msg_camera_status_get_p1(const mavlink_message_t* ms */ static inline float mavlink_msg_camera_status_get_p2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -364,7 +374,7 @@ static inline float mavlink_msg_camera_status_get_p2(const mavlink_message_t* ms */ static inline float mavlink_msg_camera_status_get_p3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -374,7 +384,7 @@ static inline float mavlink_msg_camera_status_get_p3(const mavlink_message_t* ms */ static inline float mavlink_msg_camera_status_get_p4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -385,17 +395,19 @@ static inline float mavlink_msg_camera_status_get_p4(const mavlink_message_t* ms */ static inline void mavlink_msg_camera_status_decode(const mavlink_message_t* msg, mavlink_camera_status_t* camera_status) { -#if MAVLINK_NEED_BYTE_SWAP - camera_status->time_usec = mavlink_msg_camera_status_get_time_usec(msg); - camera_status->p1 = mavlink_msg_camera_status_get_p1(msg); - camera_status->p2 = mavlink_msg_camera_status_get_p2(msg); - camera_status->p3 = mavlink_msg_camera_status_get_p3(msg); - camera_status->p4 = mavlink_msg_camera_status_get_p4(msg); - camera_status->img_idx = mavlink_msg_camera_status_get_img_idx(msg); - camera_status->target_system = mavlink_msg_camera_status_get_target_system(msg); - camera_status->cam_idx = mavlink_msg_camera_status_get_cam_idx(msg); - camera_status->event_id = mavlink_msg_camera_status_get_event_id(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + camera_status->time_usec = mavlink_msg_camera_status_get_time_usec(msg); + camera_status->p1 = mavlink_msg_camera_status_get_p1(msg); + camera_status->p2 = mavlink_msg_camera_status_get_p2(msg); + camera_status->p3 = mavlink_msg_camera_status_get_p3(msg); + camera_status->p4 = mavlink_msg_camera_status_get_p4(msg); + camera_status->img_idx = mavlink_msg_camera_status_get_img_idx(msg); + camera_status->target_system = mavlink_msg_camera_status_get_target_system(msg); + camera_status->cam_idx = mavlink_msg_camera_status_get_cam_idx(msg); + camera_status->event_id = mavlink_msg_camera_status_get_event_id(msg); #else - memcpy(camera_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_CAMERA_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_CAMERA_STATUS_LEN? msg->len : MAVLINK_MSG_ID_CAMERA_STATUS_LEN; + memset(camera_status, 0, MAVLINK_MSG_ID_CAMERA_STATUS_LEN); + memcpy(camera_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_compassmot_status.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_compassmot_status.h index 9655459889..507625087a 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_compassmot_status.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_compassmot_status.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE COMPASSMOT_STATUS PACKING #define MAVLINK_MSG_ID_COMPASSMOT_STATUS 177 -typedef struct __mavlink_compassmot_status_t -{ - float current; ///< current (amps) - float CompensationX; ///< Motor Compensation X - float CompensationY; ///< Motor Compensation Y - float CompensationZ; ///< Motor Compensation Z - uint16_t throttle; ///< throttle (percent*10) - uint16_t interference; ///< interference (percent) -} mavlink_compassmot_status_t; +MAVPACKED( +typedef struct __mavlink_compassmot_status_t { + float current; /*< current (Ampere)*/ + float CompensationX; /*< Motor Compensation X*/ + float CompensationY; /*< Motor Compensation Y*/ + float CompensationZ; /*< Motor Compensation Z*/ + uint16_t throttle; /*< throttle (percent*10)*/ + uint16_t interference; /*< interference (percent)*/ +}) mavlink_compassmot_status_t; #define MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN 20 +#define MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN 20 #define MAVLINK_MSG_ID_177_LEN 20 +#define MAVLINK_MSG_ID_177_MIN_LEN 20 #define MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC 240 #define MAVLINK_MSG_ID_177_CRC 240 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_COMPASSMOT_STATUS { \ - "COMPASSMOT_STATUS", \ - 6, \ - { { "current", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_compassmot_status_t, current) }, \ + 177, \ + "COMPASSMOT_STATUS", \ + 6, \ + { { "current", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_compassmot_status_t, current) }, \ { "CompensationX", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_compassmot_status_t, CompensationX) }, \ { "CompensationY", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_compassmot_status_t, CompensationY) }, \ { "CompensationZ", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_compassmot_status_t, CompensationZ) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_compassmot_status_t { "interference", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_compassmot_status_t, interference) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_COMPASSMOT_STATUS { \ + "COMPASSMOT_STATUS", \ + 6, \ + { { "current", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_compassmot_status_t, current) }, \ + { "CompensationX", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_compassmot_status_t, CompensationX) }, \ + { "CompensationY", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_compassmot_status_t, CompensationY) }, \ + { "CompensationZ", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_compassmot_status_t, CompensationZ) }, \ + { "throttle", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_compassmot_status_t, throttle) }, \ + { "interference", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_compassmot_status_t, interference) }, \ + } \ +} +#endif /** * @brief Pack a compassmot_status message @@ -40,7 +57,7 @@ typedef struct __mavlink_compassmot_status_t * @param msg The MAVLink message to compress the data into * * @param throttle throttle (percent*10) - * @param current current (amps) + * @param current current (Ampere) * @param interference interference (percent) * @param CompensationX Motor Compensation X * @param CompensationY Motor Compensation Y @@ -48,36 +65,32 @@ typedef struct __mavlink_compassmot_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_compassmot_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t throttle, float current, uint16_t interference, float CompensationX, float CompensationY, float CompensationZ) + uint16_t throttle, float current, uint16_t interference, float CompensationX, float CompensationY, float CompensationZ) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN]; - _mav_put_float(buf, 0, current); - _mav_put_float(buf, 4, CompensationX); - _mav_put_float(buf, 8, CompensationY); - _mav_put_float(buf, 12, CompensationZ); - _mav_put_uint16_t(buf, 16, throttle); - _mav_put_uint16_t(buf, 18, interference); + char buf[MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN]; + _mav_put_float(buf, 0, current); + _mav_put_float(buf, 4, CompensationX); + _mav_put_float(buf, 8, CompensationY); + _mav_put_float(buf, 12, CompensationZ); + _mav_put_uint16_t(buf, 16, throttle); + _mav_put_uint16_t(buf, 18, interference); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); #else - mavlink_compassmot_status_t packet; - packet.current = current; - packet.CompensationX = CompensationX; - packet.CompensationY = CompensationY; - packet.CompensationZ = CompensationZ; - packet.throttle = throttle; - packet.interference = interference; + mavlink_compassmot_status_t packet; + packet.current = current; + packet.CompensationX = CompensationX; + packet.CompensationY = CompensationY; + packet.CompensationZ = CompensationZ; + packet.throttle = throttle; + packet.interference = interference; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMPASSMOT_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMPASSMOT_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); } /** @@ -87,7 +100,7 @@ static inline uint16_t mavlink_msg_compassmot_status_pack(uint8_t system_id, uin * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param throttle throttle (percent*10) - * @param current current (amps) + * @param current current (Ampere) * @param interference interference (percent) * @param CompensationX Motor Compensation X * @param CompensationY Motor Compensation Y @@ -95,37 +108,33 @@ static inline uint16_t mavlink_msg_compassmot_status_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_compassmot_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t throttle,float current,uint16_t interference,float CompensationX,float CompensationY,float CompensationZ) + mavlink_message_t* msg, + uint16_t throttle,float current,uint16_t interference,float CompensationX,float CompensationY,float CompensationZ) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN]; - _mav_put_float(buf, 0, current); - _mav_put_float(buf, 4, CompensationX); - _mav_put_float(buf, 8, CompensationY); - _mav_put_float(buf, 12, CompensationZ); - _mav_put_uint16_t(buf, 16, throttle); - _mav_put_uint16_t(buf, 18, interference); + char buf[MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN]; + _mav_put_float(buf, 0, current); + _mav_put_float(buf, 4, CompensationX); + _mav_put_float(buf, 8, CompensationY); + _mav_put_float(buf, 12, CompensationZ); + _mav_put_uint16_t(buf, 16, throttle); + _mav_put_uint16_t(buf, 18, interference); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); #else - mavlink_compassmot_status_t packet; - packet.current = current; - packet.CompensationX = CompensationX; - packet.CompensationY = CompensationY; - packet.CompensationZ = CompensationZ; - packet.throttle = throttle; - packet.interference = interference; + mavlink_compassmot_status_t packet; + packet.current = current; + packet.CompensationX = CompensationX; + packet.CompensationY = CompensationY; + packet.CompensationZ = CompensationZ; + packet.throttle = throttle; + packet.interference = interference; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMPASSMOT_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMPASSMOT_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_compassmot_status_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_compassmot_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_compassmot_status_t* compassmot_status) { - return mavlink_msg_compassmot_status_pack(system_id, component_id, msg, compassmot_status->throttle, compassmot_status->current, compassmot_status->interference, compassmot_status->CompensationX, compassmot_status->CompensationY, compassmot_status->CompensationZ); + return mavlink_msg_compassmot_status_pack(system_id, component_id, msg, compassmot_status->throttle, compassmot_status->current, compassmot_status->interference, compassmot_status->CompensationX, compassmot_status->CompensationY, compassmot_status->CompensationZ); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_compassmot_status_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_compassmot_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_compassmot_status_t* compassmot_status) { - return mavlink_msg_compassmot_status_pack_chan(system_id, component_id, chan, msg, compassmot_status->throttle, compassmot_status->current, compassmot_status->interference, compassmot_status->CompensationX, compassmot_status->CompensationY, compassmot_status->CompensationZ); + return mavlink_msg_compassmot_status_pack_chan(system_id, component_id, chan, msg, compassmot_status->throttle, compassmot_status->current, compassmot_status->interference, compassmot_status->CompensationX, compassmot_status->CompensationY, compassmot_status->CompensationZ); } /** @@ -160,7 +169,7 @@ static inline uint16_t mavlink_msg_compassmot_status_encode_chan(uint8_t system_ * @param chan MAVLink channel to send the message * * @param throttle throttle (percent*10) - * @param current current (amps) + * @param current current (Ampere) * @param interference interference (percent) * @param CompensationX Motor Compensation X * @param CompensationY Motor Compensation Y @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_compassmot_status_encode_chan(uint8_t system_ static inline void mavlink_msg_compassmot_status_send(mavlink_channel_t chan, uint16_t throttle, float current, uint16_t interference, float CompensationX, float CompensationY, float CompensationZ) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN]; - _mav_put_float(buf, 0, current); - _mav_put_float(buf, 4, CompensationX); - _mav_put_float(buf, 8, CompensationY); - _mav_put_float(buf, 12, CompensationZ); - _mav_put_uint16_t(buf, 16, throttle); - _mav_put_uint16_t(buf, 18, interference); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); + char buf[MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN]; + _mav_put_float(buf, 0, current); + _mav_put_float(buf, 4, CompensationX); + _mav_put_float(buf, 8, CompensationY); + _mav_put_float(buf, 12, CompensationZ); + _mav_put_uint16_t(buf, 16, throttle); + _mav_put_uint16_t(buf, 18, interference); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); + mavlink_compassmot_status_t packet; + packet.current = current; + packet.CompensationX = CompensationX; + packet.CompensationY = CompensationY; + packet.CompensationZ = CompensationZ; + packet.throttle = throttle; + packet.interference = interference; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, (const char *)&packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); #endif +} + +/** + * @brief Send a compassmot_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_compassmot_status_send_struct(mavlink_channel_t chan, const mavlink_compassmot_status_t* compassmot_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_compassmot_status_send(chan, compassmot_status->throttle, compassmot_status->current, compassmot_status->interference, compassmot_status->CompensationX, compassmot_status->CompensationY, compassmot_status->CompensationZ); #else - mavlink_compassmot_status_t packet; - packet.current = current; - packet.CompensationX = CompensationX; - packet.CompensationY = CompensationY; - packet.CompensationZ = CompensationZ; - packet.throttle = throttle; - packet.interference = interference; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, (const char *)&packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, (const char *)&packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, (const char *)compassmot_status, MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_compassmot_status_send(mavlink_channel_t chan, ui static inline void mavlink_msg_compassmot_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t throttle, float current, uint16_t interference, float CompensationX, float CompensationY, float CompensationZ) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, current); - _mav_put_float(buf, 4, CompensationX); - _mav_put_float(buf, 8, CompensationY); - _mav_put_float(buf, 12, CompensationZ); - _mav_put_uint16_t(buf, 16, throttle); - _mav_put_uint16_t(buf, 18, interference); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, current); + _mav_put_float(buf, 4, CompensationX); + _mav_put_float(buf, 8, CompensationY); + _mav_put_float(buf, 12, CompensationZ); + _mav_put_uint16_t(buf, 16, throttle); + _mav_put_uint16_t(buf, 18, interference); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, buf, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); -#endif -#else - mavlink_compassmot_status_t *packet = (mavlink_compassmot_status_t *)msgbuf; - packet->current = current; - packet->CompensationX = CompensationX; - packet->CompensationY = CompensationY; - packet->CompensationZ = CompensationZ; - packet->throttle = throttle; - packet->interference = interference; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, (const char *)packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, (const char *)packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); -#endif + mavlink_compassmot_status_t *packet = (mavlink_compassmot_status_t *)msgbuf; + packet->current = current; + packet->CompensationX = CompensationX; + packet->CompensationY = CompensationY; + packet->CompensationZ = CompensationZ; + packet->throttle = throttle; + packet->interference = interference; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMPASSMOT_STATUS, (const char *)packet, MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN, MAVLINK_MSG_ID_COMPASSMOT_STATUS_CRC); #endif } #endif @@ -255,17 +262,17 @@ static inline void mavlink_msg_compassmot_status_send_buf(mavlink_message_t *msg */ static inline uint16_t mavlink_msg_compassmot_status_get_throttle(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** * @brief Get field current from compassmot_status message * - * @return current (amps) + * @return current (Ampere) */ static inline float mavlink_msg_compassmot_status_get_current(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -275,7 +282,7 @@ static inline float mavlink_msg_compassmot_status_get_current(const mavlink_mess */ static inline uint16_t mavlink_msg_compassmot_status_get_interference(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -285,7 +292,7 @@ static inline uint16_t mavlink_msg_compassmot_status_get_interference(const mavl */ static inline float mavlink_msg_compassmot_status_get_CompensationX(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -295,7 +302,7 @@ static inline float mavlink_msg_compassmot_status_get_CompensationX(const mavlin */ static inline float mavlink_msg_compassmot_status_get_CompensationY(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -305,7 +312,7 @@ static inline float mavlink_msg_compassmot_status_get_CompensationY(const mavlin */ static inline float mavlink_msg_compassmot_status_get_CompensationZ(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -316,14 +323,16 @@ static inline float mavlink_msg_compassmot_status_get_CompensationZ(const mavlin */ static inline void mavlink_msg_compassmot_status_decode(const mavlink_message_t* msg, mavlink_compassmot_status_t* compassmot_status) { -#if MAVLINK_NEED_BYTE_SWAP - compassmot_status->current = mavlink_msg_compassmot_status_get_current(msg); - compassmot_status->CompensationX = mavlink_msg_compassmot_status_get_CompensationX(msg); - compassmot_status->CompensationY = mavlink_msg_compassmot_status_get_CompensationY(msg); - compassmot_status->CompensationZ = mavlink_msg_compassmot_status_get_CompensationZ(msg); - compassmot_status->throttle = mavlink_msg_compassmot_status_get_throttle(msg); - compassmot_status->interference = mavlink_msg_compassmot_status_get_interference(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + compassmot_status->current = mavlink_msg_compassmot_status_get_current(msg); + compassmot_status->CompensationX = mavlink_msg_compassmot_status_get_CompensationX(msg); + compassmot_status->CompensationY = mavlink_msg_compassmot_status_get_CompensationY(msg); + compassmot_status->CompensationZ = mavlink_msg_compassmot_status_get_CompensationZ(msg); + compassmot_status->throttle = mavlink_msg_compassmot_status_get_throttle(msg); + compassmot_status->interference = mavlink_msg_compassmot_status_get_interference(msg); #else - memcpy(compassmot_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN? msg->len : MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN; + memset(compassmot_status, 0, MAVLINK_MSG_ID_COMPASSMOT_STATUS_LEN); + memcpy(compassmot_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data16.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data16.h index 7bad1b23de..bbd34dbd8d 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data16.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data16.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE DATA16 PACKING #define MAVLINK_MSG_ID_DATA16 169 -typedef struct __mavlink_data16_t -{ - uint8_t type; ///< data type - uint8_t len; ///< data length - uint8_t data[16]; ///< raw data -} mavlink_data16_t; +MAVPACKED( +typedef struct __mavlink_data16_t { + uint8_t type; /*< data type*/ + uint8_t len; /*< data length*/ + uint8_t data[16]; /*< raw data*/ +}) mavlink_data16_t; #define MAVLINK_MSG_ID_DATA16_LEN 18 +#define MAVLINK_MSG_ID_DATA16_MIN_LEN 18 #define MAVLINK_MSG_ID_169_LEN 18 +#define MAVLINK_MSG_ID_169_MIN_LEN 18 #define MAVLINK_MSG_ID_DATA16_CRC 234 #define MAVLINK_MSG_ID_169_CRC 234 #define MAVLINK_MSG_DATA16_FIELD_DATA_LEN 16 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DATA16 { \ - "DATA16", \ - 3, \ - { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data16_t, type) }, \ + 169, \ + "DATA16", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data16_t, type) }, \ { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data16_t, len) }, \ { "data", NULL, MAVLINK_TYPE_UINT8_T, 16, 2, offsetof(mavlink_data16_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DATA16 { \ + "DATA16", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data16_t, type) }, \ + { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data16_t, len) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 16, 2, offsetof(mavlink_data16_t, data) }, \ + } \ +} +#endif /** * @brief Pack a data16 message @@ -39,28 +53,24 @@ typedef struct __mavlink_data16_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data16_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t type, uint8_t len, const uint8_t *data) + uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA16_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 16); + char buf[MAVLINK_MSG_ID_DATA16_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA16_LEN); #else - mavlink_data16_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*16); + mavlink_data16_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA16_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA16; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA16_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA16; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA16_MIN_LEN, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); } /** @@ -75,29 +85,25 @@ static inline uint16_t mavlink_msg_data16_pack(uint8_t system_id, uint8_t compon * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data16_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t type,uint8_t len,const uint8_t *data) + mavlink_message_t* msg, + uint8_t type,uint8_t len,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA16_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 16); + char buf[MAVLINK_MSG_ID_DATA16_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA16_LEN); #else - mavlink_data16_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*16); + mavlink_data16_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA16_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA16; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA16_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA16; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA16_MIN_LEN, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); } /** @@ -110,7 +116,7 @@ static inline uint16_t mavlink_msg_data16_pack_chan(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_data16_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_data16_t* data16) { - return mavlink_msg_data16_pack(system_id, component_id, msg, data16->type, data16->len, data16->data); + return mavlink_msg_data16_pack(system_id, component_id, msg, data16->type, data16->len, data16->data); } /** @@ -124,7 +130,7 @@ static inline uint16_t mavlink_msg_data16_encode(uint8_t system_id, uint8_t comp */ static inline uint16_t mavlink_msg_data16_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data16_t* data16) { - return mavlink_msg_data16_pack_chan(system_id, component_id, chan, msg, data16->type, data16->len, data16->data); + return mavlink_msg_data16_pack_chan(system_id, component_id, chan, msg, data16->type, data16->len, data16->data); } /** @@ -140,25 +146,31 @@ static inline uint16_t mavlink_msg_data16_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_data16_send(mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA16_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, buf, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); + char buf[MAVLINK_MSG_ID_DATA16_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, buf, MAVLINK_MSG_ID_DATA16_MIN_LEN, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, buf, MAVLINK_MSG_ID_DATA16_LEN); + mavlink_data16_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, (const char *)&packet, MAVLINK_MSG_ID_DATA16_MIN_LEN, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); #endif +} + +/** + * @brief Send a data16 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_data16_send_struct(mavlink_channel_t chan, const mavlink_data16_t* data16) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_data16_send(chan, data16->type, data16->len, data16->data); #else - mavlink_data16_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, (const char *)&packet, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, (const char *)&packet, MAVLINK_MSG_ID_DATA16_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, (const char *)data16, MAVLINK_MSG_ID_DATA16_MIN_LEN, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); #endif } @@ -173,25 +185,17 @@ static inline void mavlink_msg_data16_send(mavlink_channel_t chan, uint8_t type, static inline void mavlink_msg_data16_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, buf, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, buf, MAVLINK_MSG_ID_DATA16_MIN_LEN, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, buf, MAVLINK_MSG_ID_DATA16_LEN); -#endif -#else - mavlink_data16_t *packet = (mavlink_data16_t *)msgbuf; - packet->type = type; - packet->len = len; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, (const char *)packet, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, (const char *)packet, MAVLINK_MSG_ID_DATA16_LEN); -#endif + mavlink_data16_t *packet = (mavlink_data16_t *)msgbuf; + packet->type = type; + packet->len = len; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA16, (const char *)packet, MAVLINK_MSG_ID_DATA16_MIN_LEN, MAVLINK_MSG_ID_DATA16_LEN, MAVLINK_MSG_ID_DATA16_CRC); #endif } #endif @@ -208,7 +212,7 @@ static inline void mavlink_msg_data16_send_buf(mavlink_message_t *msgbuf, mavlin */ static inline uint8_t mavlink_msg_data16_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -218,7 +222,7 @@ static inline uint8_t mavlink_msg_data16_get_type(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_data16_get_len(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -228,7 +232,7 @@ static inline uint8_t mavlink_msg_data16_get_len(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_data16_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 16, 2); + return _MAV_RETURN_uint8_t_array(msg, data, 16, 2); } /** @@ -239,11 +243,13 @@ static inline uint16_t mavlink_msg_data16_get_data(const mavlink_message_t* msg, */ static inline void mavlink_msg_data16_decode(const mavlink_message_t* msg, mavlink_data16_t* data16) { -#if MAVLINK_NEED_BYTE_SWAP - data16->type = mavlink_msg_data16_get_type(msg); - data16->len = mavlink_msg_data16_get_len(msg); - mavlink_msg_data16_get_data(msg, data16->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + data16->type = mavlink_msg_data16_get_type(msg); + data16->len = mavlink_msg_data16_get_len(msg); + mavlink_msg_data16_get_data(msg, data16->data); #else - memcpy(data16, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DATA16_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DATA16_LEN? msg->len : MAVLINK_MSG_ID_DATA16_LEN; + memset(data16, 0, MAVLINK_MSG_ID_DATA16_LEN); + memcpy(data16, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data32.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data32.h index df7a2ec801..65df0050ee 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data32.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data32.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE DATA32 PACKING #define MAVLINK_MSG_ID_DATA32 170 -typedef struct __mavlink_data32_t -{ - uint8_t type; ///< data type - uint8_t len; ///< data length - uint8_t data[32]; ///< raw data -} mavlink_data32_t; +MAVPACKED( +typedef struct __mavlink_data32_t { + uint8_t type; /*< data type*/ + uint8_t len; /*< data length*/ + uint8_t data[32]; /*< raw data*/ +}) mavlink_data32_t; #define MAVLINK_MSG_ID_DATA32_LEN 34 +#define MAVLINK_MSG_ID_DATA32_MIN_LEN 34 #define MAVLINK_MSG_ID_170_LEN 34 +#define MAVLINK_MSG_ID_170_MIN_LEN 34 #define MAVLINK_MSG_ID_DATA32_CRC 73 #define MAVLINK_MSG_ID_170_CRC 73 #define MAVLINK_MSG_DATA32_FIELD_DATA_LEN 32 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DATA32 { \ - "DATA32", \ - 3, \ - { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data32_t, type) }, \ + 170, \ + "DATA32", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data32_t, type) }, \ { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data32_t, len) }, \ { "data", NULL, MAVLINK_TYPE_UINT8_T, 32, 2, offsetof(mavlink_data32_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DATA32 { \ + "DATA32", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data32_t, type) }, \ + { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data32_t, len) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 32, 2, offsetof(mavlink_data32_t, data) }, \ + } \ +} +#endif /** * @brief Pack a data32 message @@ -39,28 +53,24 @@ typedef struct __mavlink_data32_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data32_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t type, uint8_t len, const uint8_t *data) + uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA32_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 32); + char buf[MAVLINK_MSG_ID_DATA32_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA32_LEN); #else - mavlink_data32_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*32); + mavlink_data32_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA32_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA32; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA32_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA32; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA32_MIN_LEN, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); } /** @@ -75,29 +85,25 @@ static inline uint16_t mavlink_msg_data32_pack(uint8_t system_id, uint8_t compon * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data32_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t type,uint8_t len,const uint8_t *data) + mavlink_message_t* msg, + uint8_t type,uint8_t len,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA32_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 32); + char buf[MAVLINK_MSG_ID_DATA32_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA32_LEN); #else - mavlink_data32_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*32); + mavlink_data32_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA32_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA32; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA32_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA32; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA32_MIN_LEN, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); } /** @@ -110,7 +116,7 @@ static inline uint16_t mavlink_msg_data32_pack_chan(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_data32_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_data32_t* data32) { - return mavlink_msg_data32_pack(system_id, component_id, msg, data32->type, data32->len, data32->data); + return mavlink_msg_data32_pack(system_id, component_id, msg, data32->type, data32->len, data32->data); } /** @@ -124,7 +130,7 @@ static inline uint16_t mavlink_msg_data32_encode(uint8_t system_id, uint8_t comp */ static inline uint16_t mavlink_msg_data32_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data32_t* data32) { - return mavlink_msg_data32_pack_chan(system_id, component_id, chan, msg, data32->type, data32->len, data32->data); + return mavlink_msg_data32_pack_chan(system_id, component_id, chan, msg, data32->type, data32->len, data32->data); } /** @@ -140,25 +146,31 @@ static inline uint16_t mavlink_msg_data32_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_data32_send(mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA32_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, buf, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); + char buf[MAVLINK_MSG_ID_DATA32_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, buf, MAVLINK_MSG_ID_DATA32_MIN_LEN, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, buf, MAVLINK_MSG_ID_DATA32_LEN); + mavlink_data32_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, (const char *)&packet, MAVLINK_MSG_ID_DATA32_MIN_LEN, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); #endif +} + +/** + * @brief Send a data32 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_data32_send_struct(mavlink_channel_t chan, const mavlink_data32_t* data32) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_data32_send(chan, data32->type, data32->len, data32->data); #else - mavlink_data32_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, (const char *)&packet, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, (const char *)&packet, MAVLINK_MSG_ID_DATA32_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, (const char *)data32, MAVLINK_MSG_ID_DATA32_MIN_LEN, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); #endif } @@ -173,25 +185,17 @@ static inline void mavlink_msg_data32_send(mavlink_channel_t chan, uint8_t type, static inline void mavlink_msg_data32_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, buf, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, buf, MAVLINK_MSG_ID_DATA32_MIN_LEN, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, buf, MAVLINK_MSG_ID_DATA32_LEN); -#endif -#else - mavlink_data32_t *packet = (mavlink_data32_t *)msgbuf; - packet->type = type; - packet->len = len; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, (const char *)packet, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, (const char *)packet, MAVLINK_MSG_ID_DATA32_LEN); -#endif + mavlink_data32_t *packet = (mavlink_data32_t *)msgbuf; + packet->type = type; + packet->len = len; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA32, (const char *)packet, MAVLINK_MSG_ID_DATA32_MIN_LEN, MAVLINK_MSG_ID_DATA32_LEN, MAVLINK_MSG_ID_DATA32_CRC); #endif } #endif @@ -208,7 +212,7 @@ static inline void mavlink_msg_data32_send_buf(mavlink_message_t *msgbuf, mavlin */ static inline uint8_t mavlink_msg_data32_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -218,7 +222,7 @@ static inline uint8_t mavlink_msg_data32_get_type(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_data32_get_len(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -228,7 +232,7 @@ static inline uint8_t mavlink_msg_data32_get_len(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_data32_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 32, 2); + return _MAV_RETURN_uint8_t_array(msg, data, 32, 2); } /** @@ -239,11 +243,13 @@ static inline uint16_t mavlink_msg_data32_get_data(const mavlink_message_t* msg, */ static inline void mavlink_msg_data32_decode(const mavlink_message_t* msg, mavlink_data32_t* data32) { -#if MAVLINK_NEED_BYTE_SWAP - data32->type = mavlink_msg_data32_get_type(msg); - data32->len = mavlink_msg_data32_get_len(msg); - mavlink_msg_data32_get_data(msg, data32->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + data32->type = mavlink_msg_data32_get_type(msg); + data32->len = mavlink_msg_data32_get_len(msg); + mavlink_msg_data32_get_data(msg, data32->data); #else - memcpy(data32, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DATA32_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DATA32_LEN? msg->len : MAVLINK_MSG_ID_DATA32_LEN; + memset(data32, 0, MAVLINK_MSG_ID_DATA32_LEN); + memcpy(data32, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data64.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data64.h index c354f8908a..fe456b30c0 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data64.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data64.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE DATA64 PACKING #define MAVLINK_MSG_ID_DATA64 171 -typedef struct __mavlink_data64_t -{ - uint8_t type; ///< data type - uint8_t len; ///< data length - uint8_t data[64]; ///< raw data -} mavlink_data64_t; +MAVPACKED( +typedef struct __mavlink_data64_t { + uint8_t type; /*< data type*/ + uint8_t len; /*< data length*/ + uint8_t data[64]; /*< raw data*/ +}) mavlink_data64_t; #define MAVLINK_MSG_ID_DATA64_LEN 66 +#define MAVLINK_MSG_ID_DATA64_MIN_LEN 66 #define MAVLINK_MSG_ID_171_LEN 66 +#define MAVLINK_MSG_ID_171_MIN_LEN 66 #define MAVLINK_MSG_ID_DATA64_CRC 181 #define MAVLINK_MSG_ID_171_CRC 181 #define MAVLINK_MSG_DATA64_FIELD_DATA_LEN 64 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DATA64 { \ - "DATA64", \ - 3, \ - { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data64_t, type) }, \ + 171, \ + "DATA64", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data64_t, type) }, \ { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data64_t, len) }, \ { "data", NULL, MAVLINK_TYPE_UINT8_T, 64, 2, offsetof(mavlink_data64_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DATA64 { \ + "DATA64", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data64_t, type) }, \ + { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data64_t, len) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 64, 2, offsetof(mavlink_data64_t, data) }, \ + } \ +} +#endif /** * @brief Pack a data64 message @@ -39,28 +53,24 @@ typedef struct __mavlink_data64_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data64_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t type, uint8_t len, const uint8_t *data) + uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA64_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 64); + char buf[MAVLINK_MSG_ID_DATA64_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 64); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA64_LEN); #else - mavlink_data64_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*64); + mavlink_data64_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*64); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA64_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA64; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA64_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA64; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA64_MIN_LEN, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); } /** @@ -75,29 +85,25 @@ static inline uint16_t mavlink_msg_data64_pack(uint8_t system_id, uint8_t compon * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data64_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t type,uint8_t len,const uint8_t *data) + mavlink_message_t* msg, + uint8_t type,uint8_t len,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA64_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 64); + char buf[MAVLINK_MSG_ID_DATA64_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 64); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA64_LEN); #else - mavlink_data64_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*64); + mavlink_data64_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*64); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA64_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA64; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA64_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA64; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA64_MIN_LEN, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); } /** @@ -110,7 +116,7 @@ static inline uint16_t mavlink_msg_data64_pack_chan(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_data64_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_data64_t* data64) { - return mavlink_msg_data64_pack(system_id, component_id, msg, data64->type, data64->len, data64->data); + return mavlink_msg_data64_pack(system_id, component_id, msg, data64->type, data64->len, data64->data); } /** @@ -124,7 +130,7 @@ static inline uint16_t mavlink_msg_data64_encode(uint8_t system_id, uint8_t comp */ static inline uint16_t mavlink_msg_data64_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data64_t* data64) { - return mavlink_msg_data64_pack_chan(system_id, component_id, chan, msg, data64->type, data64->len, data64->data); + return mavlink_msg_data64_pack_chan(system_id, component_id, chan, msg, data64->type, data64->len, data64->data); } /** @@ -140,25 +146,31 @@ static inline uint16_t mavlink_msg_data64_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_data64_send(mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA64_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 64); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, buf, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); + char buf[MAVLINK_MSG_ID_DATA64_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 64); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, buf, MAVLINK_MSG_ID_DATA64_MIN_LEN, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, buf, MAVLINK_MSG_ID_DATA64_LEN); + mavlink_data64_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*64); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, (const char *)&packet, MAVLINK_MSG_ID_DATA64_MIN_LEN, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); #endif +} + +/** + * @brief Send a data64 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_data64_send_struct(mavlink_channel_t chan, const mavlink_data64_t* data64) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_data64_send(chan, data64->type, data64->len, data64->data); #else - mavlink_data64_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*64); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, (const char *)&packet, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, (const char *)&packet, MAVLINK_MSG_ID_DATA64_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, (const char *)data64, MAVLINK_MSG_ID_DATA64_MIN_LEN, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); #endif } @@ -173,25 +185,17 @@ static inline void mavlink_msg_data64_send(mavlink_channel_t chan, uint8_t type, static inline void mavlink_msg_data64_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 64); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, buf, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 64); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, buf, MAVLINK_MSG_ID_DATA64_MIN_LEN, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, buf, MAVLINK_MSG_ID_DATA64_LEN); -#endif -#else - mavlink_data64_t *packet = (mavlink_data64_t *)msgbuf; - packet->type = type; - packet->len = len; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*64); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, (const char *)packet, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, (const char *)packet, MAVLINK_MSG_ID_DATA64_LEN); -#endif + mavlink_data64_t *packet = (mavlink_data64_t *)msgbuf; + packet->type = type; + packet->len = len; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*64); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA64, (const char *)packet, MAVLINK_MSG_ID_DATA64_MIN_LEN, MAVLINK_MSG_ID_DATA64_LEN, MAVLINK_MSG_ID_DATA64_CRC); #endif } #endif @@ -208,7 +212,7 @@ static inline void mavlink_msg_data64_send_buf(mavlink_message_t *msgbuf, mavlin */ static inline uint8_t mavlink_msg_data64_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -218,7 +222,7 @@ static inline uint8_t mavlink_msg_data64_get_type(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_data64_get_len(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -228,7 +232,7 @@ static inline uint8_t mavlink_msg_data64_get_len(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_data64_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 64, 2); + return _MAV_RETURN_uint8_t_array(msg, data, 64, 2); } /** @@ -239,11 +243,13 @@ static inline uint16_t mavlink_msg_data64_get_data(const mavlink_message_t* msg, */ static inline void mavlink_msg_data64_decode(const mavlink_message_t* msg, mavlink_data64_t* data64) { -#if MAVLINK_NEED_BYTE_SWAP - data64->type = mavlink_msg_data64_get_type(msg); - data64->len = mavlink_msg_data64_get_len(msg); - mavlink_msg_data64_get_data(msg, data64->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + data64->type = mavlink_msg_data64_get_type(msg); + data64->len = mavlink_msg_data64_get_len(msg); + mavlink_msg_data64_get_data(msg, data64->data); #else - memcpy(data64, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DATA64_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DATA64_LEN? msg->len : MAVLINK_MSG_ID_DATA64_LEN; + memset(data64, 0, MAVLINK_MSG_ID_DATA64_LEN); + memcpy(data64, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data96.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data96.h index 634e3f81d5..4d4555875d 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data96.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_data96.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE DATA96 PACKING #define MAVLINK_MSG_ID_DATA96 172 -typedef struct __mavlink_data96_t -{ - uint8_t type; ///< data type - uint8_t len; ///< data length - uint8_t data[96]; ///< raw data -} mavlink_data96_t; +MAVPACKED( +typedef struct __mavlink_data96_t { + uint8_t type; /*< data type*/ + uint8_t len; /*< data length*/ + uint8_t data[96]; /*< raw data*/ +}) mavlink_data96_t; #define MAVLINK_MSG_ID_DATA96_LEN 98 +#define MAVLINK_MSG_ID_DATA96_MIN_LEN 98 #define MAVLINK_MSG_ID_172_LEN 98 +#define MAVLINK_MSG_ID_172_MIN_LEN 98 #define MAVLINK_MSG_ID_DATA96_CRC 22 #define MAVLINK_MSG_ID_172_CRC 22 #define MAVLINK_MSG_DATA96_FIELD_DATA_LEN 96 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DATA96 { \ - "DATA96", \ - 3, \ - { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data96_t, type) }, \ + 172, \ + "DATA96", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data96_t, type) }, \ { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data96_t, len) }, \ { "data", NULL, MAVLINK_TYPE_UINT8_T, 96, 2, offsetof(mavlink_data96_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DATA96 { \ + "DATA96", \ + 3, \ + { { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_data96_t, type) }, \ + { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_data96_t, len) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 96, 2, offsetof(mavlink_data96_t, data) }, \ + } \ +} +#endif /** * @brief Pack a data96 message @@ -39,28 +53,24 @@ typedef struct __mavlink_data96_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data96_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t type, uint8_t len, const uint8_t *data) + uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA96_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 96); + char buf[MAVLINK_MSG_ID_DATA96_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 96); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA96_LEN); #else - mavlink_data96_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*96); + mavlink_data96_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*96); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA96_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA96; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA96_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA96; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA96_MIN_LEN, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); } /** @@ -75,29 +85,25 @@ static inline uint16_t mavlink_msg_data96_pack(uint8_t system_id, uint8_t compon * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data96_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t type,uint8_t len,const uint8_t *data) + mavlink_message_t* msg, + uint8_t type,uint8_t len,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA96_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 96); + char buf[MAVLINK_MSG_ID_DATA96_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 96); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA96_LEN); #else - mavlink_data96_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*96); + mavlink_data96_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*96); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA96_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA96; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA96_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA96; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA96_MIN_LEN, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); } /** @@ -110,7 +116,7 @@ static inline uint16_t mavlink_msg_data96_pack_chan(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_data96_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_data96_t* data96) { - return mavlink_msg_data96_pack(system_id, component_id, msg, data96->type, data96->len, data96->data); + return mavlink_msg_data96_pack(system_id, component_id, msg, data96->type, data96->len, data96->data); } /** @@ -124,7 +130,7 @@ static inline uint16_t mavlink_msg_data96_encode(uint8_t system_id, uint8_t comp */ static inline uint16_t mavlink_msg_data96_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data96_t* data96) { - return mavlink_msg_data96_pack_chan(system_id, component_id, chan, msg, data96->type, data96->len, data96->data); + return mavlink_msg_data96_pack_chan(system_id, component_id, chan, msg, data96->type, data96->len, data96->data); } /** @@ -140,25 +146,31 @@ static inline uint16_t mavlink_msg_data96_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_data96_send(mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA96_LEN]; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 96); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, buf, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); + char buf[MAVLINK_MSG_ID_DATA96_LEN]; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 96); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, buf, MAVLINK_MSG_ID_DATA96_MIN_LEN, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, buf, MAVLINK_MSG_ID_DATA96_LEN); + mavlink_data96_t packet; + packet.type = type; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*96); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, (const char *)&packet, MAVLINK_MSG_ID_DATA96_MIN_LEN, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); #endif +} + +/** + * @brief Send a data96 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_data96_send_struct(mavlink_channel_t chan, const mavlink_data96_t* data96) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_data96_send(chan, data96->type, data96->len, data96->data); #else - mavlink_data96_t packet; - packet.type = type; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*96); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, (const char *)&packet, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, (const char *)&packet, MAVLINK_MSG_ID_DATA96_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, (const char *)data96, MAVLINK_MSG_ID_DATA96_MIN_LEN, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); #endif } @@ -173,25 +185,17 @@ static inline void mavlink_msg_data96_send(mavlink_channel_t chan, uint8_t type, static inline void mavlink_msg_data96_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t type, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, type); - _mav_put_uint8_t(buf, 1, len); - _mav_put_uint8_t_array(buf, 2, data, 96); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, buf, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, type); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 96); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, buf, MAVLINK_MSG_ID_DATA96_MIN_LEN, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, buf, MAVLINK_MSG_ID_DATA96_LEN); -#endif -#else - mavlink_data96_t *packet = (mavlink_data96_t *)msgbuf; - packet->type = type; - packet->len = len; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*96); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, (const char *)packet, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, (const char *)packet, MAVLINK_MSG_ID_DATA96_LEN); -#endif + mavlink_data96_t *packet = (mavlink_data96_t *)msgbuf; + packet->type = type; + packet->len = len; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*96); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA96, (const char *)packet, MAVLINK_MSG_ID_DATA96_MIN_LEN, MAVLINK_MSG_ID_DATA96_LEN, MAVLINK_MSG_ID_DATA96_CRC); #endif } #endif @@ -208,7 +212,7 @@ static inline void mavlink_msg_data96_send_buf(mavlink_message_t *msgbuf, mavlin */ static inline uint8_t mavlink_msg_data96_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -218,7 +222,7 @@ static inline uint8_t mavlink_msg_data96_get_type(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_data96_get_len(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -228,7 +232,7 @@ static inline uint8_t mavlink_msg_data96_get_len(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_data96_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 96, 2); + return _MAV_RETURN_uint8_t_array(msg, data, 96, 2); } /** @@ -239,11 +243,13 @@ static inline uint16_t mavlink_msg_data96_get_data(const mavlink_message_t* msg, */ static inline void mavlink_msg_data96_decode(const mavlink_message_t* msg, mavlink_data96_t* data96) { -#if MAVLINK_NEED_BYTE_SWAP - data96->type = mavlink_msg_data96_get_type(msg); - data96->len = mavlink_msg_data96_get_len(msg); - mavlink_msg_data96_get_data(msg, data96->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + data96->type = mavlink_msg_data96_get_type(msg); + data96->len = mavlink_msg_data96_get_len(msg); + mavlink_msg_data96_get_data(msg, data96->data); #else - memcpy(data96, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DATA96_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DATA96_LEN? msg->len : MAVLINK_MSG_ID_DATA96_LEN; + memset(data96, 0, MAVLINK_MSG_ID_DATA96_LEN); + memcpy(data96, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_configure.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_configure.h index d5f9e7132c..ee16db455f 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_configure.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_configure.h @@ -1,34 +1,39 @@ +#pragma once // MESSAGE DIGICAM_CONFIGURE PACKING #define MAVLINK_MSG_ID_DIGICAM_CONFIGURE 154 -typedef struct __mavlink_digicam_configure_t -{ - float extra_value; ///< Correspondent value to given extra_param - uint16_t shutter_speed; ///< Divisor number //e.g. 1000 means 1/1000 (0 means ignore) - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t mode; ///< Mode enumeration from 1 to N //P, TV, AV, M, Etc (0 means ignore) - uint8_t aperture; ///< F stop number x 10 //e.g. 28 means 2.8 (0 means ignore) - uint8_t iso; ///< ISO enumeration from 1 to N //e.g. 80, 100, 200, Etc (0 means ignore) - uint8_t exposure_type; ///< Exposure type enumeration from 1 to N (0 means ignore) - uint8_t command_id; ///< Command Identity (incremental loop: 0 to 255)//A command sent multiple times will be executed or pooled just once - uint8_t engine_cut_off; ///< Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off) - uint8_t extra_param; ///< Extra parameters enumeration (0 means ignore) -} mavlink_digicam_configure_t; +MAVPACKED( +typedef struct __mavlink_digicam_configure_t { + float extra_value; /*< Correspondent value to given extra_param*/ + uint16_t shutter_speed; /*< Divisor number //e.g. 1000 means 1/1000 (0 means ignore)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t mode; /*< Mode enumeration from 1 to N //P, TV, AV, M, Etc (0 means ignore)*/ + uint8_t aperture; /*< F stop number x 10 //e.g. 28 means 2.8 (0 means ignore)*/ + uint8_t iso; /*< ISO enumeration from 1 to N //e.g. 80, 100, 200, Etc (0 means ignore)*/ + uint8_t exposure_type; /*< Exposure type enumeration from 1 to N (0 means ignore)*/ + uint8_t command_id; /*< Command Identity (incremental loop: 0 to 255)//A command sent multiple times will be executed or pooled just once*/ + uint8_t engine_cut_off; /*< Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off)*/ + uint8_t extra_param; /*< Extra parameters enumeration (0 means ignore)*/ +}) mavlink_digicam_configure_t; #define MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN 15 +#define MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN 15 #define MAVLINK_MSG_ID_154_LEN 15 +#define MAVLINK_MSG_ID_154_MIN_LEN 15 #define MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC 84 #define MAVLINK_MSG_ID_154_CRC 84 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DIGICAM_CONFIGURE { \ - "DIGICAM_CONFIGURE", \ - 11, \ - { { "extra_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_digicam_configure_t, extra_value) }, \ + 154, \ + "DIGICAM_CONFIGURE", \ + 11, \ + { { "extra_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_digicam_configure_t, extra_value) }, \ { "shutter_speed", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_digicam_configure_t, shutter_speed) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_digicam_configure_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_digicam_configure_t, target_component) }, \ @@ -41,7 +46,24 @@ typedef struct __mavlink_digicam_configure_t { "extra_param", NULL, MAVLINK_TYPE_UINT8_T, 0, 14, offsetof(mavlink_digicam_configure_t, extra_param) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DIGICAM_CONFIGURE { \ + "DIGICAM_CONFIGURE", \ + 11, \ + { { "extra_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_digicam_configure_t, extra_value) }, \ + { "shutter_speed", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_digicam_configure_t, shutter_speed) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_digicam_configure_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_digicam_configure_t, target_component) }, \ + { "mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_digicam_configure_t, mode) }, \ + { "aperture", NULL, MAVLINK_TYPE_UINT8_T, 0, 9, offsetof(mavlink_digicam_configure_t, aperture) }, \ + { "iso", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_digicam_configure_t, iso) }, \ + { "exposure_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_digicam_configure_t, exposure_type) }, \ + { "command_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_digicam_configure_t, command_id) }, \ + { "engine_cut_off", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_digicam_configure_t, engine_cut_off) }, \ + { "extra_param", NULL, MAVLINK_TYPE_UINT8_T, 0, 14, offsetof(mavlink_digicam_configure_t, extra_param) }, \ + } \ +} +#endif /** * @brief Pack a digicam_configure message @@ -63,46 +85,42 @@ typedef struct __mavlink_digicam_configure_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_digicam_configure_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t mode, uint16_t shutter_speed, uint8_t aperture, uint8_t iso, uint8_t exposure_type, uint8_t command_id, uint8_t engine_cut_off, uint8_t extra_param, float extra_value) + uint8_t target_system, uint8_t target_component, uint8_t mode, uint16_t shutter_speed, uint8_t aperture, uint8_t iso, uint8_t exposure_type, uint8_t command_id, uint8_t engine_cut_off, uint8_t extra_param, float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN]; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint16_t(buf, 4, shutter_speed); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); - _mav_put_uint8_t(buf, 8, mode); - _mav_put_uint8_t(buf, 9, aperture); - _mav_put_uint8_t(buf, 10, iso); - _mav_put_uint8_t(buf, 11, exposure_type); - _mav_put_uint8_t(buf, 12, command_id); - _mav_put_uint8_t(buf, 13, engine_cut_off); - _mav_put_uint8_t(buf, 14, extra_param); + char buf[MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN]; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint16_t(buf, 4, shutter_speed); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + _mav_put_uint8_t(buf, 8, mode); + _mav_put_uint8_t(buf, 9, aperture); + _mav_put_uint8_t(buf, 10, iso); + _mav_put_uint8_t(buf, 11, exposure_type); + _mav_put_uint8_t(buf, 12, command_id); + _mav_put_uint8_t(buf, 13, engine_cut_off); + _mav_put_uint8_t(buf, 14, extra_param); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); #else - mavlink_digicam_configure_t packet; - packet.extra_value = extra_value; - packet.shutter_speed = shutter_speed; - packet.target_system = target_system; - packet.target_component = target_component; - packet.mode = mode; - packet.aperture = aperture; - packet.iso = iso; - packet.exposure_type = exposure_type; - packet.command_id = command_id; - packet.engine_cut_off = engine_cut_off; - packet.extra_param = extra_param; + mavlink_digicam_configure_t packet; + packet.extra_value = extra_value; + packet.shutter_speed = shutter_speed; + packet.target_system = target_system; + packet.target_component = target_component; + packet.mode = mode; + packet.aperture = aperture; + packet.iso = iso; + packet.exposure_type = exposure_type; + packet.command_id = command_id; + packet.engine_cut_off = engine_cut_off; + packet.extra_param = extra_param; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONFIGURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONFIGURE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); } /** @@ -125,47 +143,43 @@ static inline uint16_t mavlink_msg_digicam_configure_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_digicam_configure_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t mode,uint16_t shutter_speed,uint8_t aperture,uint8_t iso,uint8_t exposure_type,uint8_t command_id,uint8_t engine_cut_off,uint8_t extra_param,float extra_value) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t mode,uint16_t shutter_speed,uint8_t aperture,uint8_t iso,uint8_t exposure_type,uint8_t command_id,uint8_t engine_cut_off,uint8_t extra_param,float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN]; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint16_t(buf, 4, shutter_speed); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); - _mav_put_uint8_t(buf, 8, mode); - _mav_put_uint8_t(buf, 9, aperture); - _mav_put_uint8_t(buf, 10, iso); - _mav_put_uint8_t(buf, 11, exposure_type); - _mav_put_uint8_t(buf, 12, command_id); - _mav_put_uint8_t(buf, 13, engine_cut_off); - _mav_put_uint8_t(buf, 14, extra_param); + char buf[MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN]; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint16_t(buf, 4, shutter_speed); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + _mav_put_uint8_t(buf, 8, mode); + _mav_put_uint8_t(buf, 9, aperture); + _mav_put_uint8_t(buf, 10, iso); + _mav_put_uint8_t(buf, 11, exposure_type); + _mav_put_uint8_t(buf, 12, command_id); + _mav_put_uint8_t(buf, 13, engine_cut_off); + _mav_put_uint8_t(buf, 14, extra_param); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); #else - mavlink_digicam_configure_t packet; - packet.extra_value = extra_value; - packet.shutter_speed = shutter_speed; - packet.target_system = target_system; - packet.target_component = target_component; - packet.mode = mode; - packet.aperture = aperture; - packet.iso = iso; - packet.exposure_type = exposure_type; - packet.command_id = command_id; - packet.engine_cut_off = engine_cut_off; - packet.extra_param = extra_param; + mavlink_digicam_configure_t packet; + packet.extra_value = extra_value; + packet.shutter_speed = shutter_speed; + packet.target_system = target_system; + packet.target_component = target_component; + packet.mode = mode; + packet.aperture = aperture; + packet.iso = iso; + packet.exposure_type = exposure_type; + packet.command_id = command_id; + packet.engine_cut_off = engine_cut_off; + packet.extra_param = extra_param; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONFIGURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONFIGURE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); } /** @@ -178,7 +192,7 @@ static inline uint16_t mavlink_msg_digicam_configure_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_digicam_configure_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_digicam_configure_t* digicam_configure) { - return mavlink_msg_digicam_configure_pack(system_id, component_id, msg, digicam_configure->target_system, digicam_configure->target_component, digicam_configure->mode, digicam_configure->shutter_speed, digicam_configure->aperture, digicam_configure->iso, digicam_configure->exposure_type, digicam_configure->command_id, digicam_configure->engine_cut_off, digicam_configure->extra_param, digicam_configure->extra_value); + return mavlink_msg_digicam_configure_pack(system_id, component_id, msg, digicam_configure->target_system, digicam_configure->target_component, digicam_configure->mode, digicam_configure->shutter_speed, digicam_configure->aperture, digicam_configure->iso, digicam_configure->exposure_type, digicam_configure->command_id, digicam_configure->engine_cut_off, digicam_configure->extra_param, digicam_configure->extra_value); } /** @@ -192,7 +206,7 @@ static inline uint16_t mavlink_msg_digicam_configure_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_digicam_configure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_digicam_configure_t* digicam_configure) { - return mavlink_msg_digicam_configure_pack_chan(system_id, component_id, chan, msg, digicam_configure->target_system, digicam_configure->target_component, digicam_configure->mode, digicam_configure->shutter_speed, digicam_configure->aperture, digicam_configure->iso, digicam_configure->exposure_type, digicam_configure->command_id, digicam_configure->engine_cut_off, digicam_configure->extra_param, digicam_configure->extra_value); + return mavlink_msg_digicam_configure_pack_chan(system_id, component_id, chan, msg, digicam_configure->target_system, digicam_configure->target_component, digicam_configure->mode, digicam_configure->shutter_speed, digicam_configure->aperture, digicam_configure->iso, digicam_configure->exposure_type, digicam_configure->command_id, digicam_configure->engine_cut_off, digicam_configure->extra_param, digicam_configure->extra_value); } /** @@ -216,43 +230,49 @@ static inline uint16_t mavlink_msg_digicam_configure_encode_chan(uint8_t system_ static inline void mavlink_msg_digicam_configure_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t mode, uint16_t shutter_speed, uint8_t aperture, uint8_t iso, uint8_t exposure_type, uint8_t command_id, uint8_t engine_cut_off, uint8_t extra_param, float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN]; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint16_t(buf, 4, shutter_speed); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); - _mav_put_uint8_t(buf, 8, mode); - _mav_put_uint8_t(buf, 9, aperture); - _mav_put_uint8_t(buf, 10, iso); - _mav_put_uint8_t(buf, 11, exposure_type); - _mav_put_uint8_t(buf, 12, command_id); - _mav_put_uint8_t(buf, 13, engine_cut_off); - _mav_put_uint8_t(buf, 14, extra_param); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); + char buf[MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN]; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint16_t(buf, 4, shutter_speed); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + _mav_put_uint8_t(buf, 8, mode); + _mav_put_uint8_t(buf, 9, aperture); + _mav_put_uint8_t(buf, 10, iso); + _mav_put_uint8_t(buf, 11, exposure_type); + _mav_put_uint8_t(buf, 12, command_id); + _mav_put_uint8_t(buf, 13, engine_cut_off); + _mav_put_uint8_t(buf, 14, extra_param); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); + mavlink_digicam_configure_t packet; + packet.extra_value = extra_value; + packet.shutter_speed = shutter_speed; + packet.target_system = target_system; + packet.target_component = target_component; + packet.mode = mode; + packet.aperture = aperture; + packet.iso = iso; + packet.exposure_type = exposure_type; + packet.command_id = command_id; + packet.engine_cut_off = engine_cut_off; + packet.extra_param = extra_param; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, (const char *)&packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); #endif +} + +/** + * @brief Send a digicam_configure message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_digicam_configure_send_struct(mavlink_channel_t chan, const mavlink_digicam_configure_t* digicam_configure) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_digicam_configure_send(chan, digicam_configure->target_system, digicam_configure->target_component, digicam_configure->mode, digicam_configure->shutter_speed, digicam_configure->aperture, digicam_configure->iso, digicam_configure->exposure_type, digicam_configure->command_id, digicam_configure->engine_cut_off, digicam_configure->extra_param, digicam_configure->extra_value); #else - mavlink_digicam_configure_t packet; - packet.extra_value = extra_value; - packet.shutter_speed = shutter_speed; - packet.target_system = target_system; - packet.target_component = target_component; - packet.mode = mode; - packet.aperture = aperture; - packet.iso = iso; - packet.exposure_type = exposure_type; - packet.command_id = command_id; - packet.engine_cut_off = engine_cut_off; - packet.extra_param = extra_param; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, (const char *)&packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, (const char *)&packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, (const char *)digicam_configure, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); #endif } @@ -267,43 +287,35 @@ static inline void mavlink_msg_digicam_configure_send(mavlink_channel_t chan, ui static inline void mavlink_msg_digicam_configure_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t mode, uint16_t shutter_speed, uint8_t aperture, uint8_t iso, uint8_t exposure_type, uint8_t command_id, uint8_t engine_cut_off, uint8_t extra_param, float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint16_t(buf, 4, shutter_speed); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); - _mav_put_uint8_t(buf, 8, mode); - _mav_put_uint8_t(buf, 9, aperture); - _mav_put_uint8_t(buf, 10, iso); - _mav_put_uint8_t(buf, 11, exposure_type); - _mav_put_uint8_t(buf, 12, command_id); - _mav_put_uint8_t(buf, 13, engine_cut_off); - _mav_put_uint8_t(buf, 14, extra_param); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint16_t(buf, 4, shutter_speed); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + _mav_put_uint8_t(buf, 8, mode); + _mav_put_uint8_t(buf, 9, aperture); + _mav_put_uint8_t(buf, 10, iso); + _mav_put_uint8_t(buf, 11, exposure_type); + _mav_put_uint8_t(buf, 12, command_id); + _mav_put_uint8_t(buf, 13, engine_cut_off); + _mav_put_uint8_t(buf, 14, extra_param); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, buf, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); -#endif -#else - mavlink_digicam_configure_t *packet = (mavlink_digicam_configure_t *)msgbuf; - packet->extra_value = extra_value; - packet->shutter_speed = shutter_speed; - packet->target_system = target_system; - packet->target_component = target_component; - packet->mode = mode; - packet->aperture = aperture; - packet->iso = iso; - packet->exposure_type = exposure_type; - packet->command_id = command_id; - packet->engine_cut_off = engine_cut_off; - packet->extra_param = extra_param; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, (const char *)packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, (const char *)packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); -#endif + mavlink_digicam_configure_t *packet = (mavlink_digicam_configure_t *)msgbuf; + packet->extra_value = extra_value; + packet->shutter_speed = shutter_speed; + packet->target_system = target_system; + packet->target_component = target_component; + packet->mode = mode; + packet->aperture = aperture; + packet->iso = iso; + packet->exposure_type = exposure_type; + packet->command_id = command_id; + packet->engine_cut_off = engine_cut_off; + packet->extra_param = extra_param; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONFIGURE, (const char *)packet, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_CRC); #endif } #endif @@ -320,7 +332,7 @@ static inline void mavlink_msg_digicam_configure_send_buf(mavlink_message_t *msg */ static inline uint8_t mavlink_msg_digicam_configure_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -330,7 +342,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_target_system(const mavl */ static inline uint8_t mavlink_msg_digicam_configure_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -340,7 +352,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_target_component(const m */ static inline uint8_t mavlink_msg_digicam_configure_get_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 8); + return _MAV_RETURN_uint8_t(msg, 8); } /** @@ -350,7 +362,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_mode(const mavlink_messa */ static inline uint16_t mavlink_msg_digicam_configure_get_shutter_speed(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -360,7 +372,7 @@ static inline uint16_t mavlink_msg_digicam_configure_get_shutter_speed(const mav */ static inline uint8_t mavlink_msg_digicam_configure_get_aperture(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 9); + return _MAV_RETURN_uint8_t(msg, 9); } /** @@ -370,7 +382,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_aperture(const mavlink_m */ static inline uint8_t mavlink_msg_digicam_configure_get_iso(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 10); + return _MAV_RETURN_uint8_t(msg, 10); } /** @@ -380,7 +392,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_iso(const mavlink_messag */ static inline uint8_t mavlink_msg_digicam_configure_get_exposure_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 11); + return _MAV_RETURN_uint8_t(msg, 11); } /** @@ -390,7 +402,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_exposure_type(const mavl */ static inline uint8_t mavlink_msg_digicam_configure_get_command_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -400,7 +412,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_command_id(const mavlink */ static inline uint8_t mavlink_msg_digicam_configure_get_engine_cut_off(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 13); + return _MAV_RETURN_uint8_t(msg, 13); } /** @@ -410,7 +422,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_engine_cut_off(const mav */ static inline uint8_t mavlink_msg_digicam_configure_get_extra_param(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 14); + return _MAV_RETURN_uint8_t(msg, 14); } /** @@ -420,7 +432,7 @@ static inline uint8_t mavlink_msg_digicam_configure_get_extra_param(const mavlin */ static inline float mavlink_msg_digicam_configure_get_extra_value(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -431,19 +443,21 @@ static inline float mavlink_msg_digicam_configure_get_extra_value(const mavlink_ */ static inline void mavlink_msg_digicam_configure_decode(const mavlink_message_t* msg, mavlink_digicam_configure_t* digicam_configure) { -#if MAVLINK_NEED_BYTE_SWAP - digicam_configure->extra_value = mavlink_msg_digicam_configure_get_extra_value(msg); - digicam_configure->shutter_speed = mavlink_msg_digicam_configure_get_shutter_speed(msg); - digicam_configure->target_system = mavlink_msg_digicam_configure_get_target_system(msg); - digicam_configure->target_component = mavlink_msg_digicam_configure_get_target_component(msg); - digicam_configure->mode = mavlink_msg_digicam_configure_get_mode(msg); - digicam_configure->aperture = mavlink_msg_digicam_configure_get_aperture(msg); - digicam_configure->iso = mavlink_msg_digicam_configure_get_iso(msg); - digicam_configure->exposure_type = mavlink_msg_digicam_configure_get_exposure_type(msg); - digicam_configure->command_id = mavlink_msg_digicam_configure_get_command_id(msg); - digicam_configure->engine_cut_off = mavlink_msg_digicam_configure_get_engine_cut_off(msg); - digicam_configure->extra_param = mavlink_msg_digicam_configure_get_extra_param(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + digicam_configure->extra_value = mavlink_msg_digicam_configure_get_extra_value(msg); + digicam_configure->shutter_speed = mavlink_msg_digicam_configure_get_shutter_speed(msg); + digicam_configure->target_system = mavlink_msg_digicam_configure_get_target_system(msg); + digicam_configure->target_component = mavlink_msg_digicam_configure_get_target_component(msg); + digicam_configure->mode = mavlink_msg_digicam_configure_get_mode(msg); + digicam_configure->aperture = mavlink_msg_digicam_configure_get_aperture(msg); + digicam_configure->iso = mavlink_msg_digicam_configure_get_iso(msg); + digicam_configure->exposure_type = mavlink_msg_digicam_configure_get_exposure_type(msg); + digicam_configure->command_id = mavlink_msg_digicam_configure_get_command_id(msg); + digicam_configure->engine_cut_off = mavlink_msg_digicam_configure_get_engine_cut_off(msg); + digicam_configure->extra_param = mavlink_msg_digicam_configure_get_extra_param(msg); #else - memcpy(digicam_configure, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN? msg->len : MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN; + memset(digicam_configure, 0, MAVLINK_MSG_ID_DIGICAM_CONFIGURE_LEN); + memcpy(digicam_configure, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_control.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_control.h index 68484f7b84..a83c3f27e8 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_control.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_digicam_control.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE DIGICAM_CONTROL PACKING #define MAVLINK_MSG_ID_DIGICAM_CONTROL 155 -typedef struct __mavlink_digicam_control_t -{ - float extra_value; ///< Correspondent value to given extra_param - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t session; ///< 0: stop, 1: start or keep it up //Session control e.g. show/hide lens - uint8_t zoom_pos; ///< 1 to N //Zoom's absolute position (0 means ignore) - int8_t zoom_step; ///< -100 to 100 //Zooming step value to offset zoom from the current position - uint8_t focus_lock; ///< 0: unlock focus or keep unlocked, 1: lock focus or keep locked, 3: re-lock focus - uint8_t shot; ///< 0: ignore, 1: shot or start filming - uint8_t command_id; ///< Command Identity (incremental loop: 0 to 255)//A command sent multiple times will be executed or pooled just once - uint8_t extra_param; ///< Extra parameters enumeration (0 means ignore) -} mavlink_digicam_control_t; +MAVPACKED( +typedef struct __mavlink_digicam_control_t { + float extra_value; /*< Correspondent value to given extra_param*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t session; /*< 0: stop, 1: start or keep it up //Session control e.g. show/hide lens*/ + uint8_t zoom_pos; /*< 1 to N //Zoom's absolute position (0 means ignore)*/ + int8_t zoom_step; /*< -100 to 100 //Zooming step value to offset zoom from the current position*/ + uint8_t focus_lock; /*< 0: unlock focus or keep unlocked, 1: lock focus or keep locked, 3: re-lock focus*/ + uint8_t shot; /*< 0: ignore, 1: shot or start filming*/ + uint8_t command_id; /*< Command Identity (incremental loop: 0 to 255)//A command sent multiple times will be executed or pooled just once*/ + uint8_t extra_param; /*< Extra parameters enumeration (0 means ignore)*/ +}) mavlink_digicam_control_t; #define MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN 13 +#define MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN 13 #define MAVLINK_MSG_ID_155_LEN 13 +#define MAVLINK_MSG_ID_155_MIN_LEN 13 #define MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC 22 #define MAVLINK_MSG_ID_155_CRC 22 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DIGICAM_CONTROL { \ - "DIGICAM_CONTROL", \ - 10, \ - { { "extra_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_digicam_control_t, extra_value) }, \ + 155, \ + "DIGICAM_CONTROL", \ + 10, \ + { { "extra_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_digicam_control_t, extra_value) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_digicam_control_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_digicam_control_t, target_component) }, \ { "session", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_digicam_control_t, session) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_digicam_control_t { "extra_param", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_digicam_control_t, extra_param) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DIGICAM_CONTROL { \ + "DIGICAM_CONTROL", \ + 10, \ + { { "extra_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_digicam_control_t, extra_value) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_digicam_control_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_digicam_control_t, target_component) }, \ + { "session", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_digicam_control_t, session) }, \ + { "zoom_pos", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_digicam_control_t, zoom_pos) }, \ + { "zoom_step", NULL, MAVLINK_TYPE_INT8_T, 0, 8, offsetof(mavlink_digicam_control_t, zoom_step) }, \ + { "focus_lock", NULL, MAVLINK_TYPE_UINT8_T, 0, 9, offsetof(mavlink_digicam_control_t, focus_lock) }, \ + { "shot", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_digicam_control_t, shot) }, \ + { "command_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_digicam_control_t, command_id) }, \ + { "extra_param", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_digicam_control_t, extra_param) }, \ + } \ +} +#endif /** * @brief Pack a digicam_control message @@ -60,44 +81,40 @@ typedef struct __mavlink_digicam_control_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_digicam_control_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t session, uint8_t zoom_pos, int8_t zoom_step, uint8_t focus_lock, uint8_t shot, uint8_t command_id, uint8_t extra_param, float extra_value) + uint8_t target_system, uint8_t target_component, uint8_t session, uint8_t zoom_pos, int8_t zoom_step, uint8_t focus_lock, uint8_t shot, uint8_t command_id, uint8_t extra_param, float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN]; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 6, session); - _mav_put_uint8_t(buf, 7, zoom_pos); - _mav_put_int8_t(buf, 8, zoom_step); - _mav_put_uint8_t(buf, 9, focus_lock); - _mav_put_uint8_t(buf, 10, shot); - _mav_put_uint8_t(buf, 11, command_id); - _mav_put_uint8_t(buf, 12, extra_param); + char buf[MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN]; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, session); + _mav_put_uint8_t(buf, 7, zoom_pos); + _mav_put_int8_t(buf, 8, zoom_step); + _mav_put_uint8_t(buf, 9, focus_lock); + _mav_put_uint8_t(buf, 10, shot); + _mav_put_uint8_t(buf, 11, command_id); + _mav_put_uint8_t(buf, 12, extra_param); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); #else - mavlink_digicam_control_t packet; - packet.extra_value = extra_value; - packet.target_system = target_system; - packet.target_component = target_component; - packet.session = session; - packet.zoom_pos = zoom_pos; - packet.zoom_step = zoom_step; - packet.focus_lock = focus_lock; - packet.shot = shot; - packet.command_id = command_id; - packet.extra_param = extra_param; + mavlink_digicam_control_t packet; + packet.extra_value = extra_value; + packet.target_system = target_system; + packet.target_component = target_component; + packet.session = session; + packet.zoom_pos = zoom_pos; + packet.zoom_step = zoom_step; + packet.focus_lock = focus_lock; + packet.shot = shot; + packet.command_id = command_id; + packet.extra_param = extra_param; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONTROL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_digicam_control_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_digicam_control_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t session,uint8_t zoom_pos,int8_t zoom_step,uint8_t focus_lock,uint8_t shot,uint8_t command_id,uint8_t extra_param,float extra_value) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t session,uint8_t zoom_pos,int8_t zoom_step,uint8_t focus_lock,uint8_t shot,uint8_t command_id,uint8_t extra_param,float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN]; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 6, session); - _mav_put_uint8_t(buf, 7, zoom_pos); - _mav_put_int8_t(buf, 8, zoom_step); - _mav_put_uint8_t(buf, 9, focus_lock); - _mav_put_uint8_t(buf, 10, shot); - _mav_put_uint8_t(buf, 11, command_id); - _mav_put_uint8_t(buf, 12, extra_param); + char buf[MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN]; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, session); + _mav_put_uint8_t(buf, 7, zoom_pos); + _mav_put_int8_t(buf, 8, zoom_step); + _mav_put_uint8_t(buf, 9, focus_lock); + _mav_put_uint8_t(buf, 10, shot); + _mav_put_uint8_t(buf, 11, command_id); + _mav_put_uint8_t(buf, 12, extra_param); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); #else - mavlink_digicam_control_t packet; - packet.extra_value = extra_value; - packet.target_system = target_system; - packet.target_component = target_component; - packet.session = session; - packet.zoom_pos = zoom_pos; - packet.zoom_step = zoom_step; - packet.focus_lock = focus_lock; - packet.shot = shot; - packet.command_id = command_id; - packet.extra_param = extra_param; + mavlink_digicam_control_t packet; + packet.extra_value = extra_value; + packet.target_system = target_system; + packet.target_component = target_component; + packet.session = session; + packet.zoom_pos = zoom_pos; + packet.zoom_step = zoom_step; + packet.focus_lock = focus_lock; + packet.shot = shot; + packet.command_id = command_id; + packet.extra_param = extra_param; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DIGICAM_CONTROL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_digicam_control_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_digicam_control_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_digicam_control_t* digicam_control) { - return mavlink_msg_digicam_control_pack(system_id, component_id, msg, digicam_control->target_system, digicam_control->target_component, digicam_control->session, digicam_control->zoom_pos, digicam_control->zoom_step, digicam_control->focus_lock, digicam_control->shot, digicam_control->command_id, digicam_control->extra_param, digicam_control->extra_value); + return mavlink_msg_digicam_control_pack(system_id, component_id, msg, digicam_control->target_system, digicam_control->target_component, digicam_control->session, digicam_control->zoom_pos, digicam_control->zoom_step, digicam_control->focus_lock, digicam_control->shot, digicam_control->command_id, digicam_control->extra_param, digicam_control->extra_value); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_digicam_control_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_digicam_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_digicam_control_t* digicam_control) { - return mavlink_msg_digicam_control_pack_chan(system_id, component_id, chan, msg, digicam_control->target_system, digicam_control->target_component, digicam_control->session, digicam_control->zoom_pos, digicam_control->zoom_step, digicam_control->focus_lock, digicam_control->shot, digicam_control->command_id, digicam_control->extra_param, digicam_control->extra_value); + return mavlink_msg_digicam_control_pack_chan(system_id, component_id, chan, msg, digicam_control->target_system, digicam_control->target_component, digicam_control->session, digicam_control->zoom_pos, digicam_control->zoom_step, digicam_control->focus_lock, digicam_control->shot, digicam_control->command_id, digicam_control->extra_param, digicam_control->extra_value); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_digicam_control_encode_chan(uint8_t system_id static inline void mavlink_msg_digicam_control_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t session, uint8_t zoom_pos, int8_t zoom_step, uint8_t focus_lock, uint8_t shot, uint8_t command_id, uint8_t extra_param, float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN]; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 6, session); - _mav_put_uint8_t(buf, 7, zoom_pos); - _mav_put_int8_t(buf, 8, zoom_step); - _mav_put_uint8_t(buf, 9, focus_lock); - _mav_put_uint8_t(buf, 10, shot); - _mav_put_uint8_t(buf, 11, command_id); - _mav_put_uint8_t(buf, 12, extra_param); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); + char buf[MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN]; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, session); + _mav_put_uint8_t(buf, 7, zoom_pos); + _mav_put_int8_t(buf, 8, zoom_step); + _mav_put_uint8_t(buf, 9, focus_lock); + _mav_put_uint8_t(buf, 10, shot); + _mav_put_uint8_t(buf, 11, command_id); + _mav_put_uint8_t(buf, 12, extra_param); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); + mavlink_digicam_control_t packet; + packet.extra_value = extra_value; + packet.target_system = target_system; + packet.target_component = target_component; + packet.session = session; + packet.zoom_pos = zoom_pos; + packet.zoom_step = zoom_step; + packet.focus_lock = focus_lock; + packet.shot = shot; + packet.command_id = command_id; + packet.extra_param = extra_param; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); #endif +} + +/** + * @brief Send a digicam_control message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_digicam_control_send_struct(mavlink_channel_t chan, const mavlink_digicam_control_t* digicam_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_digicam_control_send(chan, digicam_control->target_system, digicam_control->target_component, digicam_control->session, digicam_control->zoom_pos, digicam_control->zoom_step, digicam_control->focus_lock, digicam_control->shot, digicam_control->command_id, digicam_control->extra_param, digicam_control->extra_value); #else - mavlink_digicam_control_t packet; - packet.extra_value = extra_value; - packet.target_system = target_system; - packet.target_component = target_component; - packet.session = session; - packet.zoom_pos = zoom_pos; - packet.zoom_step = zoom_step; - packet.focus_lock = focus_lock; - packet.shot = shot; - packet.command_id = command_id; - packet.extra_param = extra_param; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, (const char *)digicam_control, MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_digicam_control_send(mavlink_channel_t chan, uint static inline void mavlink_msg_digicam_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t session, uint8_t zoom_pos, int8_t zoom_step, uint8_t focus_lock, uint8_t shot, uint8_t command_id, uint8_t extra_param, float extra_value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, extra_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 6, session); - _mav_put_uint8_t(buf, 7, zoom_pos); - _mav_put_int8_t(buf, 8, zoom_step); - _mav_put_uint8_t(buf, 9, focus_lock); - _mav_put_uint8_t(buf, 10, shot); - _mav_put_uint8_t(buf, 11, command_id); - _mav_put_uint8_t(buf, 12, extra_param); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); -#endif -#else - mavlink_digicam_control_t *packet = (mavlink_digicam_control_t *)msgbuf; - packet->extra_value = extra_value; - packet->target_system = target_system; - packet->target_component = target_component; - packet->session = session; - packet->zoom_pos = zoom_pos; - packet->zoom_step = zoom_step; - packet->focus_lock = focus_lock; - packet->shot = shot; - packet->command_id = command_id; - packet->extra_param = extra_param; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, (const char *)packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, extra_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, session); + _mav_put_uint8_t(buf, 7, zoom_pos); + _mav_put_int8_t(buf, 8, zoom_step); + _mav_put_uint8_t(buf, 9, focus_lock); + _mav_put_uint8_t(buf, 10, shot); + _mav_put_uint8_t(buf, 11, command_id); + _mav_put_uint8_t(buf, 12, extra_param); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, buf, MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, (const char *)packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); -#endif + mavlink_digicam_control_t *packet = (mavlink_digicam_control_t *)msgbuf; + packet->extra_value = extra_value; + packet->target_system = target_system; + packet->target_component = target_component; + packet->session = session; + packet->zoom_pos = zoom_pos; + packet->zoom_step = zoom_step; + packet->focus_lock = focus_lock; + packet->shot = shot; + packet->command_id = command_id; + packet->extra_param = extra_param; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DIGICAM_CONTROL, (const char *)packet, MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN, MAVLINK_MSG_ID_DIGICAM_CONTROL_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_digicam_control_send_buf(mavlink_message_t *msgbu */ static inline uint8_t mavlink_msg_digicam_control_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -317,7 +328,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_target_system(const mavlin */ static inline uint8_t mavlink_msg_digicam_control_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -327,7 +338,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_target_component(const mav */ static inline uint8_t mavlink_msg_digicam_control_get_session(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -337,7 +348,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_session(const mavlink_mess */ static inline uint8_t mavlink_msg_digicam_control_get_zoom_pos(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -347,7 +358,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_zoom_pos(const mavlink_mes */ static inline int8_t mavlink_msg_digicam_control_get_zoom_step(const mavlink_message_t* msg) { - return _MAV_RETURN_int8_t(msg, 8); + return _MAV_RETURN_int8_t(msg, 8); } /** @@ -357,7 +368,7 @@ static inline int8_t mavlink_msg_digicam_control_get_zoom_step(const mavlink_mes */ static inline uint8_t mavlink_msg_digicam_control_get_focus_lock(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 9); + return _MAV_RETURN_uint8_t(msg, 9); } /** @@ -367,7 +378,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_focus_lock(const mavlink_m */ static inline uint8_t mavlink_msg_digicam_control_get_shot(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 10); + return _MAV_RETURN_uint8_t(msg, 10); } /** @@ -377,7 +388,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_shot(const mavlink_message */ static inline uint8_t mavlink_msg_digicam_control_get_command_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 11); + return _MAV_RETURN_uint8_t(msg, 11); } /** @@ -387,7 +398,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_command_id(const mavlink_m */ static inline uint8_t mavlink_msg_digicam_control_get_extra_param(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -397,7 +408,7 @@ static inline uint8_t mavlink_msg_digicam_control_get_extra_param(const mavlink_ */ static inline float mavlink_msg_digicam_control_get_extra_value(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -408,18 +419,20 @@ static inline float mavlink_msg_digicam_control_get_extra_value(const mavlink_me */ static inline void mavlink_msg_digicam_control_decode(const mavlink_message_t* msg, mavlink_digicam_control_t* digicam_control) { -#if MAVLINK_NEED_BYTE_SWAP - digicam_control->extra_value = mavlink_msg_digicam_control_get_extra_value(msg); - digicam_control->target_system = mavlink_msg_digicam_control_get_target_system(msg); - digicam_control->target_component = mavlink_msg_digicam_control_get_target_component(msg); - digicam_control->session = mavlink_msg_digicam_control_get_session(msg); - digicam_control->zoom_pos = mavlink_msg_digicam_control_get_zoom_pos(msg); - digicam_control->zoom_step = mavlink_msg_digicam_control_get_zoom_step(msg); - digicam_control->focus_lock = mavlink_msg_digicam_control_get_focus_lock(msg); - digicam_control->shot = mavlink_msg_digicam_control_get_shot(msg); - digicam_control->command_id = mavlink_msg_digicam_control_get_command_id(msg); - digicam_control->extra_param = mavlink_msg_digicam_control_get_extra_param(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + digicam_control->extra_value = mavlink_msg_digicam_control_get_extra_value(msg); + digicam_control->target_system = mavlink_msg_digicam_control_get_target_system(msg); + digicam_control->target_component = mavlink_msg_digicam_control_get_target_component(msg); + digicam_control->session = mavlink_msg_digicam_control_get_session(msg); + digicam_control->zoom_pos = mavlink_msg_digicam_control_get_zoom_pos(msg); + digicam_control->zoom_step = mavlink_msg_digicam_control_get_zoom_step(msg); + digicam_control->focus_lock = mavlink_msg_digicam_control_get_focus_lock(msg); + digicam_control->shot = mavlink_msg_digicam_control_get_shot(msg); + digicam_control->command_id = mavlink_msg_digicam_control_get_command_id(msg); + digicam_control->extra_param = mavlink_msg_digicam_control_get_extra_param(msg); #else - memcpy(digicam_control, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN? msg->len : MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN; + memset(digicam_control, 0, MAVLINK_MSG_ID_DIGICAM_CONTROL_LEN); + memcpy(digicam_control, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ekf_status_report.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ekf_status_report.h new file mode 100644 index 0000000000..cc7cfd5136 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_ekf_status_report.h @@ -0,0 +1,338 @@ +#pragma once +// MESSAGE EKF_STATUS_REPORT PACKING + +#define MAVLINK_MSG_ID_EKF_STATUS_REPORT 193 + +MAVPACKED( +typedef struct __mavlink_ekf_status_report_t { + float velocity_variance; /*< Velocity variance*/ + float pos_horiz_variance; /*< Horizontal Position variance*/ + float pos_vert_variance; /*< Vertical Position variance*/ + float compass_variance; /*< Compass variance*/ + float terrain_alt_variance; /*< Terrain Altitude variance*/ + uint16_t flags; /*< Flags*/ +}) mavlink_ekf_status_report_t; + +#define MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN 22 +#define MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN 22 +#define MAVLINK_MSG_ID_193_LEN 22 +#define MAVLINK_MSG_ID_193_MIN_LEN 22 + +#define MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC 71 +#define MAVLINK_MSG_ID_193_CRC 71 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_EKF_STATUS_REPORT { \ + 193, \ + "EKF_STATUS_REPORT", \ + 6, \ + { { "velocity_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ekf_status_report_t, velocity_variance) }, \ + { "pos_horiz_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ekf_status_report_t, pos_horiz_variance) }, \ + { "pos_vert_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ekf_status_report_t, pos_vert_variance) }, \ + { "compass_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ekf_status_report_t, compass_variance) }, \ + { "terrain_alt_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_ekf_status_report_t, terrain_alt_variance) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_ekf_status_report_t, flags) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_EKF_STATUS_REPORT { \ + "EKF_STATUS_REPORT", \ + 6, \ + { { "velocity_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_ekf_status_report_t, velocity_variance) }, \ + { "pos_horiz_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_ekf_status_report_t, pos_horiz_variance) }, \ + { "pos_vert_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_ekf_status_report_t, pos_vert_variance) }, \ + { "compass_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_ekf_status_report_t, compass_variance) }, \ + { "terrain_alt_variance", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_ekf_status_report_t, terrain_alt_variance) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_ekf_status_report_t, flags) }, \ + } \ +} +#endif + +/** + * @brief Pack a ekf_status_report message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param flags Flags + * @param velocity_variance Velocity variance + * @param pos_horiz_variance Horizontal Position variance + * @param pos_vert_variance Vertical Position variance + * @param compass_variance Compass variance + * @param terrain_alt_variance Terrain Altitude variance + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_ekf_status_report_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint16_t flags, float velocity_variance, float pos_horiz_variance, float pos_vert_variance, float compass_variance, float terrain_alt_variance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN]; + _mav_put_float(buf, 0, velocity_variance); + _mav_put_float(buf, 4, pos_horiz_variance); + _mav_put_float(buf, 8, pos_vert_variance); + _mav_put_float(buf, 12, compass_variance); + _mav_put_float(buf, 16, terrain_alt_variance); + _mav_put_uint16_t(buf, 20, flags); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN); +#else + mavlink_ekf_status_report_t packet; + packet.velocity_variance = velocity_variance; + packet.pos_horiz_variance = pos_horiz_variance; + packet.pos_vert_variance = pos_vert_variance; + packet.compass_variance = compass_variance; + packet.terrain_alt_variance = terrain_alt_variance; + packet.flags = flags; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_EKF_STATUS_REPORT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC); +} + +/** + * @brief Pack a ekf_status_report message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flags Flags + * @param velocity_variance Velocity variance + * @param pos_horiz_variance Horizontal Position variance + * @param pos_vert_variance Vertical Position variance + * @param compass_variance Compass variance + * @param terrain_alt_variance Terrain Altitude variance + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_ekf_status_report_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint16_t flags,float velocity_variance,float pos_horiz_variance,float pos_vert_variance,float compass_variance,float terrain_alt_variance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN]; + _mav_put_float(buf, 0, velocity_variance); + _mav_put_float(buf, 4, pos_horiz_variance); + _mav_put_float(buf, 8, pos_vert_variance); + _mav_put_float(buf, 12, compass_variance); + _mav_put_float(buf, 16, terrain_alt_variance); + _mav_put_uint16_t(buf, 20, flags); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN); +#else + mavlink_ekf_status_report_t packet; + packet.velocity_variance = velocity_variance; + packet.pos_horiz_variance = pos_horiz_variance; + packet.pos_vert_variance = pos_vert_variance; + packet.compass_variance = compass_variance; + packet.terrain_alt_variance = terrain_alt_variance; + packet.flags = flags; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_EKF_STATUS_REPORT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC); +} + +/** + * @brief Encode a ekf_status_report struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param ekf_status_report C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_ekf_status_report_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_ekf_status_report_t* ekf_status_report) +{ + return mavlink_msg_ekf_status_report_pack(system_id, component_id, msg, ekf_status_report->flags, ekf_status_report->velocity_variance, ekf_status_report->pos_horiz_variance, ekf_status_report->pos_vert_variance, ekf_status_report->compass_variance, ekf_status_report->terrain_alt_variance); +} + +/** + * @brief Encode a ekf_status_report struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param ekf_status_report C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_ekf_status_report_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ekf_status_report_t* ekf_status_report) +{ + return mavlink_msg_ekf_status_report_pack_chan(system_id, component_id, chan, msg, ekf_status_report->flags, ekf_status_report->velocity_variance, ekf_status_report->pos_horiz_variance, ekf_status_report->pos_vert_variance, ekf_status_report->compass_variance, ekf_status_report->terrain_alt_variance); +} + +/** + * @brief Send a ekf_status_report message + * @param chan MAVLink channel to send the message + * + * @param flags Flags + * @param velocity_variance Velocity variance + * @param pos_horiz_variance Horizontal Position variance + * @param pos_vert_variance Vertical Position variance + * @param compass_variance Compass variance + * @param terrain_alt_variance Terrain Altitude variance + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_ekf_status_report_send(mavlink_channel_t chan, uint16_t flags, float velocity_variance, float pos_horiz_variance, float pos_vert_variance, float compass_variance, float terrain_alt_variance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN]; + _mav_put_float(buf, 0, velocity_variance); + _mav_put_float(buf, 4, pos_horiz_variance); + _mav_put_float(buf, 8, pos_vert_variance); + _mav_put_float(buf, 12, compass_variance); + _mav_put_float(buf, 16, terrain_alt_variance); + _mav_put_uint16_t(buf, 20, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EKF_STATUS_REPORT, buf, MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC); +#else + mavlink_ekf_status_report_t packet; + packet.velocity_variance = velocity_variance; + packet.pos_horiz_variance = pos_horiz_variance; + packet.pos_vert_variance = pos_vert_variance; + packet.compass_variance = compass_variance; + packet.terrain_alt_variance = terrain_alt_variance; + packet.flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EKF_STATUS_REPORT, (const char *)&packet, MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC); +#endif +} + +/** + * @brief Send a ekf_status_report message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_ekf_status_report_send_struct(mavlink_channel_t chan, const mavlink_ekf_status_report_t* ekf_status_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_ekf_status_report_send(chan, ekf_status_report->flags, ekf_status_report->velocity_variance, ekf_status_report->pos_horiz_variance, ekf_status_report->pos_vert_variance, ekf_status_report->compass_variance, ekf_status_report->terrain_alt_variance); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EKF_STATUS_REPORT, (const char *)ekf_status_report, MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC); +#endif +} + +#if MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_ekf_status_report_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t flags, float velocity_variance, float pos_horiz_variance, float pos_vert_variance, float compass_variance, float terrain_alt_variance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, velocity_variance); + _mav_put_float(buf, 4, pos_horiz_variance); + _mav_put_float(buf, 8, pos_vert_variance); + _mav_put_float(buf, 12, compass_variance); + _mav_put_float(buf, 16, terrain_alt_variance); + _mav_put_uint16_t(buf, 20, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EKF_STATUS_REPORT, buf, MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC); +#else + mavlink_ekf_status_report_t *packet = (mavlink_ekf_status_report_t *)msgbuf; + packet->velocity_variance = velocity_variance; + packet->pos_horiz_variance = pos_horiz_variance; + packet->pos_vert_variance = pos_vert_variance; + packet->compass_variance = compass_variance; + packet->terrain_alt_variance = terrain_alt_variance; + packet->flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EKF_STATUS_REPORT, (const char *)packet, MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN, MAVLINK_MSG_ID_EKF_STATUS_REPORT_CRC); +#endif +} +#endif + +#endif + +// MESSAGE EKF_STATUS_REPORT UNPACKING + + +/** + * @brief Get field flags from ekf_status_report message + * + * @return Flags + */ +static inline uint16_t mavlink_msg_ekf_status_report_get_flags(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 20); +} + +/** + * @brief Get field velocity_variance from ekf_status_report message + * + * @return Velocity variance + */ +static inline float mavlink_msg_ekf_status_report_get_velocity_variance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 0); +} + +/** + * @brief Get field pos_horiz_variance from ekf_status_report message + * + * @return Horizontal Position variance + */ +static inline float mavlink_msg_ekf_status_report_get_pos_horiz_variance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Get field pos_vert_variance from ekf_status_report message + * + * @return Vertical Position variance + */ +static inline float mavlink_msg_ekf_status_report_get_pos_vert_variance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field compass_variance from ekf_status_report message + * + * @return Compass variance + */ +static inline float mavlink_msg_ekf_status_report_get_compass_variance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field terrain_alt_variance from ekf_status_report message + * + * @return Terrain Altitude variance + */ +static inline float mavlink_msg_ekf_status_report_get_terrain_alt_variance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Decode a ekf_status_report message into a struct + * + * @param msg The message to decode + * @param ekf_status_report C-struct to decode the message contents into + */ +static inline void mavlink_msg_ekf_status_report_decode(const mavlink_message_t* msg, mavlink_ekf_status_report_t* ekf_status_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + ekf_status_report->velocity_variance = mavlink_msg_ekf_status_report_get_velocity_variance(msg); + ekf_status_report->pos_horiz_variance = mavlink_msg_ekf_status_report_get_pos_horiz_variance(msg); + ekf_status_report->pos_vert_variance = mavlink_msg_ekf_status_report_get_pos_vert_variance(msg); + ekf_status_report->compass_variance = mavlink_msg_ekf_status_report_get_compass_variance(msg); + ekf_status_report->terrain_alt_variance = mavlink_msg_ekf_status_report_get_terrain_alt_variance(msg); + ekf_status_report->flags = mavlink_msg_ekf_status_report_get_flags(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN? msg->len : MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN; + memset(ekf_status_report, 0, MAVLINK_MSG_ID_EKF_STATUS_REPORT_LEN); + memcpy(ekf_status_report, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_fetch_point.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_fetch_point.h index 4021c7a096..c38d34c56f 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_fetch_point.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_fetch_point.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE FENCE_FETCH_POINT PACKING #define MAVLINK_MSG_ID_FENCE_FETCH_POINT 161 -typedef struct __mavlink_fence_fetch_point_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t idx; ///< point index (first point is 1, 0 is for return point) -} mavlink_fence_fetch_point_t; +MAVPACKED( +typedef struct __mavlink_fence_fetch_point_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t idx; /*< point index (first point is 1, 0 is for return point)*/ +}) mavlink_fence_fetch_point_t; #define MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN 3 +#define MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN 3 #define MAVLINK_MSG_ID_161_LEN 3 +#define MAVLINK_MSG_ID_161_MIN_LEN 3 #define MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC 68 #define MAVLINK_MSG_ID_161_CRC 68 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_FENCE_FETCH_POINT { \ - "FENCE_FETCH_POINT", \ - 3, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_fence_fetch_point_t, target_system) }, \ + 161, \ + "FENCE_FETCH_POINT", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_fence_fetch_point_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_fence_fetch_point_t, target_component) }, \ { "idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_fence_fetch_point_t, idx) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_FENCE_FETCH_POINT { \ + "FENCE_FETCH_POINT", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_fence_fetch_point_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_fence_fetch_point_t, target_component) }, \ + { "idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_fence_fetch_point_t, idx) }, \ + } \ +} +#endif /** * @brief Pack a fence_fetch_point message @@ -39,30 +53,26 @@ typedef struct __mavlink_fence_fetch_point_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_fence_fetch_point_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t idx) + uint8_t target_system, uint8_t target_component, uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char buf[MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); #else - mavlink_fence_fetch_point_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; + mavlink_fence_fetch_point_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FENCE_FETCH_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FENCE_FETCH_POINT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_fence_fetch_point_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_fence_fetch_point_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t idx) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char buf[MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); #else - mavlink_fence_fetch_point_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; + mavlink_fence_fetch_point_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FENCE_FETCH_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FENCE_FETCH_POINT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_fence_fetch_point_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_fence_fetch_point_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_fence_fetch_point_t* fence_fetch_point) { - return mavlink_msg_fence_fetch_point_pack(system_id, component_id, msg, fence_fetch_point->target_system, fence_fetch_point->target_component, fence_fetch_point->idx); + return mavlink_msg_fence_fetch_point_pack(system_id, component_id, msg, fence_fetch_point->target_system, fence_fetch_point->target_component, fence_fetch_point->idx); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_fence_fetch_point_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_fence_fetch_point_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_fence_fetch_point_t* fence_fetch_point) { - return mavlink_msg_fence_fetch_point_pack_chan(system_id, component_id, chan, msg, fence_fetch_point->target_system, fence_fetch_point->target_component, fence_fetch_point->idx); + return mavlink_msg_fence_fetch_point_pack_chan(system_id, component_id, chan, msg, fence_fetch_point->target_system, fence_fetch_point->target_component, fence_fetch_point->idx); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_fence_fetch_point_encode_chan(uint8_t system_ static inline void mavlink_msg_fence_fetch_point_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char buf[MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); + mavlink_fence_fetch_point_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, (const char *)&packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); #endif -#else - mavlink_fence_fetch_point_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, (const char *)&packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); +/** + * @brief Send a fence_fetch_point message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_fence_fetch_point_send_struct(mavlink_channel_t chan, const mavlink_fence_fetch_point_t* fence_fetch_point) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_fence_fetch_point_send(chan, fence_fetch_point->target_system, fence_fetch_point->target_component, fence_fetch_point->idx); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, (const char *)&packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, (const char *)fence_fetch_point, MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_fence_fetch_point_send(mavlink_channel_t chan, ui static inline void mavlink_msg_fence_fetch_point_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, buf, MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); #else - mavlink_fence_fetch_point_t *packet = (mavlink_fence_fetch_point_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; - packet->idx = idx; + mavlink_fence_fetch_point_t *packet = (mavlink_fence_fetch_point_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->idx = idx; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, (const char *)packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, (const char *)packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_FETCH_POINT, (const char *)packet, MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN, MAVLINK_MSG_ID_FENCE_FETCH_POINT_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_fence_fetch_point_send_buf(mavlink_message_t *msg */ static inline uint8_t mavlink_msg_fence_fetch_point_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_fence_fetch_point_get_target_system(const mavl */ static inline uint8_t mavlink_msg_fence_fetch_point_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_fence_fetch_point_get_target_component(const m */ static inline uint8_t mavlink_msg_fence_fetch_point_get_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -247,11 +251,13 @@ static inline uint8_t mavlink_msg_fence_fetch_point_get_idx(const mavlink_messag */ static inline void mavlink_msg_fence_fetch_point_decode(const mavlink_message_t* msg, mavlink_fence_fetch_point_t* fence_fetch_point) { -#if MAVLINK_NEED_BYTE_SWAP - fence_fetch_point->target_system = mavlink_msg_fence_fetch_point_get_target_system(msg); - fence_fetch_point->target_component = mavlink_msg_fence_fetch_point_get_target_component(msg); - fence_fetch_point->idx = mavlink_msg_fence_fetch_point_get_idx(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + fence_fetch_point->target_system = mavlink_msg_fence_fetch_point_get_target_system(msg); + fence_fetch_point->target_component = mavlink_msg_fence_fetch_point_get_target_component(msg); + fence_fetch_point->idx = mavlink_msg_fence_fetch_point_get_idx(msg); #else - memcpy(fence_fetch_point, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN? msg->len : MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN; + memset(fence_fetch_point, 0, MAVLINK_MSG_ID_FENCE_FETCH_POINT_LEN); + memcpy(fence_fetch_point, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_point.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_point.h index 6fc2c83fc4..4187f93077 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_point.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_point.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE FENCE_POINT PACKING #define MAVLINK_MSG_ID_FENCE_POINT 160 -typedef struct __mavlink_fence_point_t -{ - float lat; ///< Latitude of point - float lng; ///< Longitude of point - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t idx; ///< point index (first point is 1, 0 is for return point) - uint8_t count; ///< total number of points (for sanity checking) -} mavlink_fence_point_t; +MAVPACKED( +typedef struct __mavlink_fence_point_t { + float lat; /*< Latitude of point*/ + float lng; /*< Longitude of point*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t idx; /*< point index (first point is 1, 0 is for return point)*/ + uint8_t count; /*< total number of points (for sanity checking)*/ +}) mavlink_fence_point_t; #define MAVLINK_MSG_ID_FENCE_POINT_LEN 12 +#define MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN 12 #define MAVLINK_MSG_ID_160_LEN 12 +#define MAVLINK_MSG_ID_160_MIN_LEN 12 #define MAVLINK_MSG_ID_FENCE_POINT_CRC 78 #define MAVLINK_MSG_ID_160_CRC 78 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_FENCE_POINT { \ - "FENCE_POINT", \ - 6, \ - { { "lat", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_fence_point_t, lat) }, \ + 160, \ + "FENCE_POINT", \ + 6, \ + { { "lat", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_fence_point_t, lat) }, \ { "lng", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_fence_point_t, lng) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_fence_point_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 9, offsetof(mavlink_fence_point_t, target_component) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_fence_point_t { "count", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_fence_point_t, count) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_FENCE_POINT { \ + "FENCE_POINT", \ + 6, \ + { { "lat", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_fence_point_t, lat) }, \ + { "lng", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_fence_point_t, lng) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_fence_point_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 9, offsetof(mavlink_fence_point_t, target_component) }, \ + { "idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_fence_point_t, idx) }, \ + { "count", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_fence_point_t, count) }, \ + } \ +} +#endif /** * @brief Pack a fence_point message @@ -48,36 +65,32 @@ typedef struct __mavlink_fence_point_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_fence_point_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, float lat, float lng) + uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, float lat, float lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_POINT_LEN]; - _mav_put_float(buf, 0, lat); - _mav_put_float(buf, 4, lng); - _mav_put_uint8_t(buf, 8, target_system); - _mav_put_uint8_t(buf, 9, target_component); - _mav_put_uint8_t(buf, 10, idx); - _mav_put_uint8_t(buf, 11, count); + char buf[MAVLINK_MSG_ID_FENCE_POINT_LEN]; + _mav_put_float(buf, 0, lat); + _mav_put_float(buf, 4, lng); + _mav_put_uint8_t(buf, 8, target_system); + _mav_put_uint8_t(buf, 9, target_component); + _mav_put_uint8_t(buf, 10, idx); + _mav_put_uint8_t(buf, 11, count); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FENCE_POINT_LEN); #else - mavlink_fence_point_t packet; - packet.lat = lat; - packet.lng = lng; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; - packet.count = count; + mavlink_fence_point_t packet; + packet.lat = lat; + packet.lng = lng; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + packet.count = count; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FENCE_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FENCE_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FENCE_POINT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); } /** @@ -95,37 +108,33 @@ static inline uint16_t mavlink_msg_fence_point_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_fence_point_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t idx,uint8_t count,float lat,float lng) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t idx,uint8_t count,float lat,float lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_POINT_LEN]; - _mav_put_float(buf, 0, lat); - _mav_put_float(buf, 4, lng); - _mav_put_uint8_t(buf, 8, target_system); - _mav_put_uint8_t(buf, 9, target_component); - _mav_put_uint8_t(buf, 10, idx); - _mav_put_uint8_t(buf, 11, count); + char buf[MAVLINK_MSG_ID_FENCE_POINT_LEN]; + _mav_put_float(buf, 0, lat); + _mav_put_float(buf, 4, lng); + _mav_put_uint8_t(buf, 8, target_system); + _mav_put_uint8_t(buf, 9, target_component); + _mav_put_uint8_t(buf, 10, idx); + _mav_put_uint8_t(buf, 11, count); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FENCE_POINT_LEN); #else - mavlink_fence_point_t packet; - packet.lat = lat; - packet.lng = lng; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; - packet.count = count; + mavlink_fence_point_t packet; + packet.lat = lat; + packet.lng = lng; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + packet.count = count; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FENCE_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FENCE_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FENCE_POINT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_fence_point_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_fence_point_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_fence_point_t* fence_point) { - return mavlink_msg_fence_point_pack(system_id, component_id, msg, fence_point->target_system, fence_point->target_component, fence_point->idx, fence_point->count, fence_point->lat, fence_point->lng); + return mavlink_msg_fence_point_pack(system_id, component_id, msg, fence_point->target_system, fence_point->target_component, fence_point->idx, fence_point->count, fence_point->lat, fence_point->lng); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_fence_point_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_fence_point_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_fence_point_t* fence_point) { - return mavlink_msg_fence_point_pack_chan(system_id, component_id, chan, msg, fence_point->target_system, fence_point->target_component, fence_point->idx, fence_point->count, fence_point->lat, fence_point->lng); + return mavlink_msg_fence_point_pack_chan(system_id, component_id, chan, msg, fence_point->target_system, fence_point->target_component, fence_point->idx, fence_point->count, fence_point->lat, fence_point->lng); } /** @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_fence_point_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_fence_point_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, float lat, float lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_POINT_LEN]; - _mav_put_float(buf, 0, lat); - _mav_put_float(buf, 4, lng); - _mav_put_uint8_t(buf, 8, target_system); - _mav_put_uint8_t(buf, 9, target_component); - _mav_put_uint8_t(buf, 10, idx); - _mav_put_uint8_t(buf, 11, count); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, buf, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); + char buf[MAVLINK_MSG_ID_FENCE_POINT_LEN]; + _mav_put_float(buf, 0, lat); + _mav_put_float(buf, 4, lng); + _mav_put_uint8_t(buf, 8, target_system); + _mav_put_uint8_t(buf, 9, target_component); + _mav_put_uint8_t(buf, 10, idx); + _mav_put_uint8_t(buf, 11, count); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, buf, MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, buf, MAVLINK_MSG_ID_FENCE_POINT_LEN); + mavlink_fence_point_t packet; + packet.lat = lat; + packet.lng = lng; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + packet.count = count; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, (const char *)&packet, MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); #endif +} + +/** + * @brief Send a fence_point message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_fence_point_send_struct(mavlink_channel_t chan, const mavlink_fence_point_t* fence_point) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_fence_point_send(chan, fence_point->target_system, fence_point->target_component, fence_point->idx, fence_point->count, fence_point->lat, fence_point->lng); #else - mavlink_fence_point_t packet; - packet.lat = lat; - packet.lng = lng; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; - packet.count = count; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, (const char *)&packet, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, (const char *)&packet, MAVLINK_MSG_ID_FENCE_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, (const char *)fence_point, MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_fence_point_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_fence_point_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, float lat, float lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, lat); - _mav_put_float(buf, 4, lng); - _mav_put_uint8_t(buf, 8, target_system); - _mav_put_uint8_t(buf, 9, target_component); - _mav_put_uint8_t(buf, 10, idx); - _mav_put_uint8_t(buf, 11, count); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, buf, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, lat); + _mav_put_float(buf, 4, lng); + _mav_put_uint8_t(buf, 8, target_system); + _mav_put_uint8_t(buf, 9, target_component); + _mav_put_uint8_t(buf, 10, idx); + _mav_put_uint8_t(buf, 11, count); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, buf, MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, buf, MAVLINK_MSG_ID_FENCE_POINT_LEN); -#endif -#else - mavlink_fence_point_t *packet = (mavlink_fence_point_t *)msgbuf; - packet->lat = lat; - packet->lng = lng; - packet->target_system = target_system; - packet->target_component = target_component; - packet->idx = idx; - packet->count = count; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, (const char *)packet, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, (const char *)packet, MAVLINK_MSG_ID_FENCE_POINT_LEN); -#endif + mavlink_fence_point_t *packet = (mavlink_fence_point_t *)msgbuf; + packet->lat = lat; + packet->lng = lng; + packet->target_system = target_system; + packet->target_component = target_component; + packet->idx = idx; + packet->count = count; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_POINT, (const char *)packet, MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN, MAVLINK_MSG_ID_FENCE_POINT_LEN, MAVLINK_MSG_ID_FENCE_POINT_CRC); #endif } #endif @@ -255,7 +262,7 @@ static inline void mavlink_msg_fence_point_send_buf(mavlink_message_t *msgbuf, m */ static inline uint8_t mavlink_msg_fence_point_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 8); + return _MAV_RETURN_uint8_t(msg, 8); } /** @@ -265,7 +272,7 @@ static inline uint8_t mavlink_msg_fence_point_get_target_system(const mavlink_me */ static inline uint8_t mavlink_msg_fence_point_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 9); + return _MAV_RETURN_uint8_t(msg, 9); } /** @@ -275,7 +282,7 @@ static inline uint8_t mavlink_msg_fence_point_get_target_component(const mavlink */ static inline uint8_t mavlink_msg_fence_point_get_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 10); + return _MAV_RETURN_uint8_t(msg, 10); } /** @@ -285,7 +292,7 @@ static inline uint8_t mavlink_msg_fence_point_get_idx(const mavlink_message_t* m */ static inline uint8_t mavlink_msg_fence_point_get_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 11); + return _MAV_RETURN_uint8_t(msg, 11); } /** @@ -295,7 +302,7 @@ static inline uint8_t mavlink_msg_fence_point_get_count(const mavlink_message_t* */ static inline float mavlink_msg_fence_point_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -305,7 +312,7 @@ static inline float mavlink_msg_fence_point_get_lat(const mavlink_message_t* msg */ static inline float mavlink_msg_fence_point_get_lng(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -316,14 +323,16 @@ static inline float mavlink_msg_fence_point_get_lng(const mavlink_message_t* msg */ static inline void mavlink_msg_fence_point_decode(const mavlink_message_t* msg, mavlink_fence_point_t* fence_point) { -#if MAVLINK_NEED_BYTE_SWAP - fence_point->lat = mavlink_msg_fence_point_get_lat(msg); - fence_point->lng = mavlink_msg_fence_point_get_lng(msg); - fence_point->target_system = mavlink_msg_fence_point_get_target_system(msg); - fence_point->target_component = mavlink_msg_fence_point_get_target_component(msg); - fence_point->idx = mavlink_msg_fence_point_get_idx(msg); - fence_point->count = mavlink_msg_fence_point_get_count(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + fence_point->lat = mavlink_msg_fence_point_get_lat(msg); + fence_point->lng = mavlink_msg_fence_point_get_lng(msg); + fence_point->target_system = mavlink_msg_fence_point_get_target_system(msg); + fence_point->target_component = mavlink_msg_fence_point_get_target_component(msg); + fence_point->idx = mavlink_msg_fence_point_get_idx(msg); + fence_point->count = mavlink_msg_fence_point_get_count(msg); #else - memcpy(fence_point, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_FENCE_POINT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_FENCE_POINT_LEN? msg->len : MAVLINK_MSG_ID_FENCE_POINT_LEN; + memset(fence_point, 0, MAVLINK_MSG_ID_FENCE_POINT_LEN); + memcpy(fence_point, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_status.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_status.h index c50d37724e..e4bb67f4fb 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_status.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_fence_status.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE FENCE_STATUS PACKING #define MAVLINK_MSG_ID_FENCE_STATUS 162 -typedef struct __mavlink_fence_status_t -{ - uint32_t breach_time; ///< time of last breach in milliseconds since boot - uint16_t breach_count; ///< number of fence breaches - uint8_t breach_status; ///< 0 if currently inside fence, 1 if outside - uint8_t breach_type; ///< last breach type (see FENCE_BREACH_* enum) -} mavlink_fence_status_t; +MAVPACKED( +typedef struct __mavlink_fence_status_t { + uint32_t breach_time; /*< time of last breach in milliseconds since boot*/ + uint16_t breach_count; /*< number of fence breaches*/ + uint8_t breach_status; /*< 0 if currently inside fence, 1 if outside*/ + uint8_t breach_type; /*< last breach type (see FENCE_BREACH_* enum)*/ +}) mavlink_fence_status_t; #define MAVLINK_MSG_ID_FENCE_STATUS_LEN 8 +#define MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN 8 #define MAVLINK_MSG_ID_162_LEN 8 +#define MAVLINK_MSG_ID_162_MIN_LEN 8 #define MAVLINK_MSG_ID_FENCE_STATUS_CRC 189 #define MAVLINK_MSG_ID_162_CRC 189 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_FENCE_STATUS { \ - "FENCE_STATUS", \ - 4, \ - { { "breach_time", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_fence_status_t, breach_time) }, \ + 162, \ + "FENCE_STATUS", \ + 4, \ + { { "breach_time", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_fence_status_t, breach_time) }, \ { "breach_count", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_fence_status_t, breach_count) }, \ { "breach_status", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_fence_status_t, breach_status) }, \ { "breach_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_fence_status_t, breach_type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_FENCE_STATUS { \ + "FENCE_STATUS", \ + 4, \ + { { "breach_time", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_fence_status_t, breach_time) }, \ + { "breach_count", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_fence_status_t, breach_count) }, \ + { "breach_status", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_fence_status_t, breach_status) }, \ + { "breach_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_fence_status_t, breach_type) }, \ + } \ +} +#endif /** * @brief Pack a fence_status message @@ -42,32 +57,28 @@ typedef struct __mavlink_fence_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_fence_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t breach_status, uint16_t breach_count, uint8_t breach_type, uint32_t breach_time) + uint8_t breach_status, uint16_t breach_count, uint8_t breach_type, uint32_t breach_time) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, breach_time); - _mav_put_uint16_t(buf, 4, breach_count); - _mav_put_uint8_t(buf, 6, breach_status); - _mav_put_uint8_t(buf, 7, breach_type); + char buf[MAVLINK_MSG_ID_FENCE_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, breach_time); + _mav_put_uint16_t(buf, 4, breach_count); + _mav_put_uint8_t(buf, 6, breach_status); + _mav_put_uint8_t(buf, 7, breach_type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FENCE_STATUS_LEN); #else - mavlink_fence_status_t packet; - packet.breach_time = breach_time; - packet.breach_count = breach_count; - packet.breach_status = breach_status; - packet.breach_type = breach_type; + mavlink_fence_status_t packet; + packet.breach_time = breach_time; + packet.breach_count = breach_count; + packet.breach_status = breach_status; + packet.breach_type = breach_type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FENCE_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FENCE_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FENCE_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_fence_status_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_fence_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t breach_status,uint16_t breach_count,uint8_t breach_type,uint32_t breach_time) + mavlink_message_t* msg, + uint8_t breach_status,uint16_t breach_count,uint8_t breach_type,uint32_t breach_time) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, breach_time); - _mav_put_uint16_t(buf, 4, breach_count); - _mav_put_uint8_t(buf, 6, breach_status); - _mav_put_uint8_t(buf, 7, breach_type); + char buf[MAVLINK_MSG_ID_FENCE_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, breach_time); + _mav_put_uint16_t(buf, 4, breach_count); + _mav_put_uint8_t(buf, 6, breach_status); + _mav_put_uint8_t(buf, 7, breach_type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FENCE_STATUS_LEN); #else - mavlink_fence_status_t packet; - packet.breach_time = breach_time; - packet.breach_count = breach_count; - packet.breach_status = breach_status; - packet.breach_type = breach_type; + mavlink_fence_status_t packet; + packet.breach_time = breach_time; + packet.breach_count = breach_count; + packet.breach_status = breach_status; + packet.breach_type = breach_type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FENCE_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FENCE_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FENCE_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_fence_status_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_fence_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_fence_status_t* fence_status) { - return mavlink_msg_fence_status_pack(system_id, component_id, msg, fence_status->breach_status, fence_status->breach_count, fence_status->breach_type, fence_status->breach_time); + return mavlink_msg_fence_status_pack(system_id, component_id, msg, fence_status->breach_status, fence_status->breach_count, fence_status->breach_type, fence_status->breach_time); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_fence_status_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_fence_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_fence_status_t* fence_status) { - return mavlink_msg_fence_status_pack_chan(system_id, component_id, chan, msg, fence_status->breach_status, fence_status->breach_count, fence_status->breach_type, fence_status->breach_time); + return mavlink_msg_fence_status_pack_chan(system_id, component_id, chan, msg, fence_status->breach_status, fence_status->breach_count, fence_status->breach_type, fence_status->breach_time); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_fence_status_encode_chan(uint8_t system_id, u static inline void mavlink_msg_fence_status_send(mavlink_channel_t chan, uint8_t breach_status, uint16_t breach_count, uint8_t breach_type, uint32_t breach_time) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FENCE_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, breach_time); - _mav_put_uint16_t(buf, 4, breach_count); - _mav_put_uint8_t(buf, 6, breach_status); - _mav_put_uint8_t(buf, 7, breach_type); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, buf, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); + char buf[MAVLINK_MSG_ID_FENCE_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, breach_time); + _mav_put_uint16_t(buf, 4, breach_count); + _mav_put_uint8_t(buf, 6, breach_status); + _mav_put_uint8_t(buf, 7, breach_type); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, buf, MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, buf, MAVLINK_MSG_ID_FENCE_STATUS_LEN); + mavlink_fence_status_t packet; + packet.breach_time = breach_time; + packet.breach_count = breach_count; + packet.breach_status = breach_status; + packet.breach_type = breach_type; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, (const char *)&packet, MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); #endif +} + +/** + * @brief Send a fence_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_fence_status_send_struct(mavlink_channel_t chan, const mavlink_fence_status_t* fence_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_fence_status_send(chan, fence_status->breach_status, fence_status->breach_count, fence_status->breach_type, fence_status->breach_time); #else - mavlink_fence_status_t packet; - packet.breach_time = breach_time; - packet.breach_count = breach_count; - packet.breach_status = breach_status; - packet.breach_type = breach_type; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, (const char *)&packet, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, (const char *)&packet, MAVLINK_MSG_ID_FENCE_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, (const char *)fence_status, MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_fence_status_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_fence_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t breach_status, uint16_t breach_count, uint8_t breach_type, uint32_t breach_time) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, breach_time); - _mav_put_uint16_t(buf, 4, breach_count); - _mav_put_uint8_t(buf, 6, breach_status); - _mav_put_uint8_t(buf, 7, breach_type); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, buf, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, buf, MAVLINK_MSG_ID_FENCE_STATUS_LEN); -#endif -#else - mavlink_fence_status_t *packet = (mavlink_fence_status_t *)msgbuf; - packet->breach_time = breach_time; - packet->breach_count = breach_count; - packet->breach_status = breach_status; - packet->breach_type = breach_type; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, (const char *)packet, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, breach_time); + _mav_put_uint16_t(buf, 4, breach_count); + _mav_put_uint8_t(buf, 6, breach_status); + _mav_put_uint8_t(buf, 7, breach_type); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, buf, MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, (const char *)packet, MAVLINK_MSG_ID_FENCE_STATUS_LEN); -#endif + mavlink_fence_status_t *packet = (mavlink_fence_status_t *)msgbuf; + packet->breach_time = breach_time; + packet->breach_count = breach_count; + packet->breach_status = breach_status; + packet->breach_type = breach_type; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FENCE_STATUS, (const char *)packet, MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN, MAVLINK_MSG_ID_FENCE_STATUS_LEN, MAVLINK_MSG_ID_FENCE_STATUS_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_fence_status_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_fence_status_get_breach_status(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -239,7 +244,7 @@ static inline uint8_t mavlink_msg_fence_status_get_breach_status(const mavlink_m */ static inline uint16_t mavlink_msg_fence_status_get_breach_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -249,7 +254,7 @@ static inline uint16_t mavlink_msg_fence_status_get_breach_count(const mavlink_m */ static inline uint8_t mavlink_msg_fence_status_get_breach_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -259,7 +264,7 @@ static inline uint8_t mavlink_msg_fence_status_get_breach_type(const mavlink_mes */ static inline uint32_t mavlink_msg_fence_status_get_breach_time(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -270,12 +275,14 @@ static inline uint32_t mavlink_msg_fence_status_get_breach_time(const mavlink_me */ static inline void mavlink_msg_fence_status_decode(const mavlink_message_t* msg, mavlink_fence_status_t* fence_status) { -#if MAVLINK_NEED_BYTE_SWAP - fence_status->breach_time = mavlink_msg_fence_status_get_breach_time(msg); - fence_status->breach_count = mavlink_msg_fence_status_get_breach_count(msg); - fence_status->breach_status = mavlink_msg_fence_status_get_breach_status(msg); - fence_status->breach_type = mavlink_msg_fence_status_get_breach_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + fence_status->breach_time = mavlink_msg_fence_status_get_breach_time(msg); + fence_status->breach_count = mavlink_msg_fence_status_get_breach_count(msg); + fence_status->breach_status = mavlink_msg_fence_status_get_breach_status(msg); + fence_status->breach_type = mavlink_msg_fence_status_get_breach_type(msg); #else - memcpy(fence_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_FENCE_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_FENCE_STATUS_LEN? msg->len : MAVLINK_MSG_ID_FENCE_STATUS_LEN; + memset(fence_status, 0, MAVLINK_MSG_ID_FENCE_STATUS_LEN); + memcpy(fence_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_control.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_control.h index 106a8fc469..4f39e41f24 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_control.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_control.h @@ -1,41 +1,51 @@ +#pragma once // MESSAGE GIMBAL_CONTROL PACKING -#define MAVLINK_MSG_ID_GIMBAL_CONTROL 185 +#define MAVLINK_MSG_ID_GIMBAL_CONTROL 201 -typedef struct __mavlink_gimbal_control_t -{ - float demanded_rate_x; ///< Demanded angular rate X, radians/s - float demanded_rate_y; ///< Demanded angular rate Y, radians/s - float demanded_rate_z; ///< Demanded angular rate Z, radians/s - float gyro_bias_x; ///< Gyro bias X, radians/s - float gyro_bias_y; ///< Gyro bias Y, radians/s - float gyro_bias_z; ///< Gyro bias Z, radians/s - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_gimbal_control_t; +MAVPACKED( +typedef struct __mavlink_gimbal_control_t { + float demanded_rate_x; /*< Demanded angular rate X (rad/s)*/ + float demanded_rate_y; /*< Demanded angular rate Y (rad/s)*/ + float demanded_rate_z; /*< Demanded angular rate Z (rad/s)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_gimbal_control_t; -#define MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN 26 -#define MAVLINK_MSG_ID_185_LEN 26 +#define MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN 14 +#define MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN 14 +#define MAVLINK_MSG_ID_201_LEN 14 +#define MAVLINK_MSG_ID_201_MIN_LEN 14 -#define MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC 239 -#define MAVLINK_MSG_ID_185_CRC 239 +#define MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC 205 +#define MAVLINK_MSG_ID_201_CRC 205 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GIMBAL_CONTROL { \ - "GIMBAL_CONTROL", \ - 8, \ - { { "demanded_rate_x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_gimbal_control_t, demanded_rate_x) }, \ + 201, \ + "GIMBAL_CONTROL", \ + 5, \ + { { "demanded_rate_x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_gimbal_control_t, demanded_rate_x) }, \ { "demanded_rate_y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_gimbal_control_t, demanded_rate_y) }, \ { "demanded_rate_z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_gimbal_control_t, demanded_rate_z) }, \ - { "gyro_bias_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_gimbal_control_t, gyro_bias_x) }, \ - { "gyro_bias_y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_gimbal_control_t, gyro_bias_y) }, \ - { "gyro_bias_z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_gimbal_control_t, gyro_bias_z) }, \ - { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_gimbal_control_t, target_system) }, \ - { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 25, offsetof(mavlink_gimbal_control_t, target_component) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_gimbal_control_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_gimbal_control_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GIMBAL_CONTROL { \ + "GIMBAL_CONTROL", \ + 5, \ + { { "demanded_rate_x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_gimbal_control_t, demanded_rate_x) }, \ + { "demanded_rate_y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_gimbal_control_t, demanded_rate_y) }, \ + { "demanded_rate_z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_gimbal_control_t, demanded_rate_z) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_gimbal_control_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_gimbal_control_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a gimbal_control message @@ -45,49 +55,36 @@ typedef struct __mavlink_gimbal_control_t * * @param target_system System ID * @param target_component Component ID - * @param demanded_rate_x Demanded angular rate X, radians/s - * @param demanded_rate_y Demanded angular rate Y, radians/s - * @param demanded_rate_z Demanded angular rate Z, radians/s - * @param gyro_bias_x Gyro bias X, radians/s - * @param gyro_bias_y Gyro bias Y, radians/s - * @param gyro_bias_z Gyro bias Z, radians/s + * @param demanded_rate_x Demanded angular rate X (rad/s) + * @param demanded_rate_y Demanded angular rate Y (rad/s) + * @param demanded_rate_z Demanded angular rate Z (rad/s) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gimbal_control_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, float demanded_rate_x, float demanded_rate_y, float demanded_rate_z, float gyro_bias_x, float gyro_bias_y, float gyro_bias_z) + uint8_t target_system, uint8_t target_component, float demanded_rate_x, float demanded_rate_y, float demanded_rate_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN]; - _mav_put_float(buf, 0, demanded_rate_x); - _mav_put_float(buf, 4, demanded_rate_y); - _mav_put_float(buf, 8, demanded_rate_z); - _mav_put_float(buf, 12, gyro_bias_x); - _mav_put_float(buf, 16, gyro_bias_y); - _mav_put_float(buf, 20, gyro_bias_z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); + char buf[MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN]; + _mav_put_float(buf, 0, demanded_rate_x); + _mav_put_float(buf, 4, demanded_rate_y); + _mav_put_float(buf, 8, demanded_rate_z); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); #else - mavlink_gimbal_control_t packet; - packet.demanded_rate_x = demanded_rate_x; - packet.demanded_rate_y = demanded_rate_y; - packet.demanded_rate_z = demanded_rate_z; - packet.gyro_bias_x = gyro_bias_x; - packet.gyro_bias_y = gyro_bias_y; - packet.gyro_bias_z = gyro_bias_z; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_gimbal_control_t packet; + packet.demanded_rate_x = demanded_rate_x; + packet.demanded_rate_y = demanded_rate_y; + packet.demanded_rate_z = demanded_rate_z; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GIMBAL_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GIMBAL_CONTROL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); } /** @@ -98,50 +95,37 @@ static inline uint16_t mavlink_msg_gimbal_control_pack(uint8_t system_id, uint8_ * @param msg The MAVLink message to compress the data into * @param target_system System ID * @param target_component Component ID - * @param demanded_rate_x Demanded angular rate X, radians/s - * @param demanded_rate_y Demanded angular rate Y, radians/s - * @param demanded_rate_z Demanded angular rate Z, radians/s - * @param gyro_bias_x Gyro bias X, radians/s - * @param gyro_bias_y Gyro bias Y, radians/s - * @param gyro_bias_z Gyro bias Z, radians/s + * @param demanded_rate_x Demanded angular rate X (rad/s) + * @param demanded_rate_y Demanded angular rate Y (rad/s) + * @param demanded_rate_z Demanded angular rate Z (rad/s) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gimbal_control_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,float demanded_rate_x,float demanded_rate_y,float demanded_rate_z,float gyro_bias_x,float gyro_bias_y,float gyro_bias_z) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,float demanded_rate_x,float demanded_rate_y,float demanded_rate_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN]; - _mav_put_float(buf, 0, demanded_rate_x); - _mav_put_float(buf, 4, demanded_rate_y); - _mav_put_float(buf, 8, demanded_rate_z); - _mav_put_float(buf, 12, gyro_bias_x); - _mav_put_float(buf, 16, gyro_bias_y); - _mav_put_float(buf, 20, gyro_bias_z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); + char buf[MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN]; + _mav_put_float(buf, 0, demanded_rate_x); + _mav_put_float(buf, 4, demanded_rate_y); + _mav_put_float(buf, 8, demanded_rate_z); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); #else - mavlink_gimbal_control_t packet; - packet.demanded_rate_x = demanded_rate_x; - packet.demanded_rate_y = demanded_rate_y; - packet.demanded_rate_z = demanded_rate_z; - packet.gyro_bias_x = gyro_bias_x; - packet.gyro_bias_y = gyro_bias_y; - packet.gyro_bias_z = gyro_bias_z; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_gimbal_control_t packet; + packet.demanded_rate_x = demanded_rate_x; + packet.demanded_rate_y = demanded_rate_y; + packet.demanded_rate_z = demanded_rate_z; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GIMBAL_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GIMBAL_CONTROL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); } /** @@ -154,7 +138,7 @@ static inline uint16_t mavlink_msg_gimbal_control_pack_chan(uint8_t system_id, u */ static inline uint16_t mavlink_msg_gimbal_control_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gimbal_control_t* gimbal_control) { - return mavlink_msg_gimbal_control_pack(system_id, component_id, msg, gimbal_control->target_system, gimbal_control->target_component, gimbal_control->demanded_rate_x, gimbal_control->demanded_rate_y, gimbal_control->demanded_rate_z, gimbal_control->gyro_bias_x, gimbal_control->gyro_bias_y, gimbal_control->gyro_bias_z); + return mavlink_msg_gimbal_control_pack(system_id, component_id, msg, gimbal_control->target_system, gimbal_control->target_component, gimbal_control->demanded_rate_x, gimbal_control->demanded_rate_y, gimbal_control->demanded_rate_z); } /** @@ -168,7 +152,7 @@ static inline uint16_t mavlink_msg_gimbal_control_encode(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_gimbal_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gimbal_control_t* gimbal_control) { - return mavlink_msg_gimbal_control_pack_chan(system_id, component_id, chan, msg, gimbal_control->target_system, gimbal_control->target_component, gimbal_control->demanded_rate_x, gimbal_control->demanded_rate_y, gimbal_control->demanded_rate_z, gimbal_control->gyro_bias_x, gimbal_control->gyro_bias_y, gimbal_control->gyro_bias_z); + return mavlink_msg_gimbal_control_pack_chan(system_id, component_id, chan, msg, gimbal_control->target_system, gimbal_control->target_component, gimbal_control->demanded_rate_x, gimbal_control->demanded_rate_y, gimbal_control->demanded_rate_z); } /** @@ -177,49 +161,46 @@ static inline uint16_t mavlink_msg_gimbal_control_encode_chan(uint8_t system_id, * * @param target_system System ID * @param target_component Component ID - * @param demanded_rate_x Demanded angular rate X, radians/s - * @param demanded_rate_y Demanded angular rate Y, radians/s - * @param demanded_rate_z Demanded angular rate Z, radians/s - * @param gyro_bias_x Gyro bias X, radians/s - * @param gyro_bias_y Gyro bias Y, radians/s - * @param gyro_bias_z Gyro bias Z, radians/s + * @param demanded_rate_x Demanded angular rate X (rad/s) + * @param demanded_rate_y Demanded angular rate Y (rad/s) + * @param demanded_rate_z Demanded angular rate Z (rad/s) */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS -static inline void mavlink_msg_gimbal_control_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float demanded_rate_x, float demanded_rate_y, float demanded_rate_z, float gyro_bias_x, float gyro_bias_y, float gyro_bias_z) +static inline void mavlink_msg_gimbal_control_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float demanded_rate_x, float demanded_rate_y, float demanded_rate_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN]; - _mav_put_float(buf, 0, demanded_rate_x); - _mav_put_float(buf, 4, demanded_rate_y); - _mav_put_float(buf, 8, demanded_rate_z); - _mav_put_float(buf, 12, gyro_bias_x); - _mav_put_float(buf, 16, gyro_bias_y); - _mav_put_float(buf, 20, gyro_bias_z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); + char buf[MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN]; + _mav_put_float(buf, 0, demanded_rate_x); + _mav_put_float(buf, 4, demanded_rate_y); + _mav_put_float(buf, 8, demanded_rate_z); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); + mavlink_gimbal_control_t packet; + packet.demanded_rate_x = demanded_rate_x; + packet.demanded_rate_y = demanded_rate_y; + packet.demanded_rate_z = demanded_rate_z; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); #endif +} + +/** + * @brief Send a gimbal_control message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gimbal_control_send_struct(mavlink_channel_t chan, const mavlink_gimbal_control_t* gimbal_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gimbal_control_send(chan, gimbal_control->target_system, gimbal_control->target_component, gimbal_control->demanded_rate_x, gimbal_control->demanded_rate_y, gimbal_control->demanded_rate_z); #else - mavlink_gimbal_control_t packet; - packet.demanded_rate_x = demanded_rate_x; - packet.demanded_rate_y = demanded_rate_y; - packet.demanded_rate_z = demanded_rate_z; - packet.gyro_bias_x = gyro_bias_x; - packet.gyro_bias_y = gyro_bias_y; - packet.gyro_bias_z = gyro_bias_z; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, (const char *)gimbal_control, MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); #endif } @@ -231,40 +212,26 @@ static inline void mavlink_msg_gimbal_control_send(mavlink_channel_t chan, uint8 is usually the receive buffer for the channel, and allows a reply to an incoming message with minimum stack space usage. */ -static inline void mavlink_msg_gimbal_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float demanded_rate_x, float demanded_rate_y, float demanded_rate_z, float gyro_bias_x, float gyro_bias_y, float gyro_bias_z) +static inline void mavlink_msg_gimbal_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float demanded_rate_x, float demanded_rate_y, float demanded_rate_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, demanded_rate_x); - _mav_put_float(buf, 4, demanded_rate_y); - _mav_put_float(buf, 8, demanded_rate_z); - _mav_put_float(buf, 12, gyro_bias_x); - _mav_put_float(buf, 16, gyro_bias_y); - _mav_put_float(buf, 20, gyro_bias_z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, demanded_rate_x); + _mav_put_float(buf, 4, demanded_rate_y); + _mav_put_float(buf, 8, demanded_rate_z); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, buf, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); -#endif -#else - mavlink_gimbal_control_t *packet = (mavlink_gimbal_control_t *)msgbuf; - packet->demanded_rate_x = demanded_rate_x; - packet->demanded_rate_y = demanded_rate_y; - packet->demanded_rate_z = demanded_rate_z; - packet->gyro_bias_x = gyro_bias_x; - packet->gyro_bias_y = gyro_bias_y; - packet->gyro_bias_z = gyro_bias_z; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); -#endif + mavlink_gimbal_control_t *packet = (mavlink_gimbal_control_t *)msgbuf; + packet->demanded_rate_x = demanded_rate_x; + packet->demanded_rate_y = demanded_rate_y; + packet->demanded_rate_z = demanded_rate_z; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN, MAVLINK_MSG_ID_GIMBAL_CONTROL_CRC); #endif } #endif @@ -281,7 +248,7 @@ static inline void mavlink_msg_gimbal_control_send_buf(mavlink_message_t *msgbuf */ static inline uint8_t mavlink_msg_gimbal_control_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 24); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -291,67 +258,37 @@ static inline uint8_t mavlink_msg_gimbal_control_get_target_system(const mavlink */ static inline uint8_t mavlink_msg_gimbal_control_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 25); + return _MAV_RETURN_uint8_t(msg, 13); } /** * @brief Get field demanded_rate_x from gimbal_control message * - * @return Demanded angular rate X, radians/s + * @return Demanded angular rate X (rad/s) */ static inline float mavlink_msg_gimbal_control_get_demanded_rate_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** * @brief Get field demanded_rate_y from gimbal_control message * - * @return Demanded angular rate Y, radians/s + * @return Demanded angular rate Y (rad/s) */ static inline float mavlink_msg_gimbal_control_get_demanded_rate_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** * @brief Get field demanded_rate_z from gimbal_control message * - * @return Demanded angular rate Z, radians/s + * @return Demanded angular rate Z (rad/s) */ static inline float mavlink_msg_gimbal_control_get_demanded_rate_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); -} - -/** - * @brief Get field gyro_bias_x from gimbal_control message - * - * @return Gyro bias X, radians/s - */ -static inline float mavlink_msg_gimbal_control_get_gyro_bias_x(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 12); -} - -/** - * @brief Get field gyro_bias_y from gimbal_control message - * - * @return Gyro bias Y, radians/s - */ -static inline float mavlink_msg_gimbal_control_get_gyro_bias_y(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 16); -} - -/** - * @brief Get field gyro_bias_z from gimbal_control message - * - * @return Gyro bias Z, radians/s - */ -static inline float mavlink_msg_gimbal_control_get_gyro_bias_z(const mavlink_message_t* msg) -{ - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 8); } /** @@ -362,16 +299,15 @@ static inline float mavlink_msg_gimbal_control_get_gyro_bias_z(const mavlink_mes */ static inline void mavlink_msg_gimbal_control_decode(const mavlink_message_t* msg, mavlink_gimbal_control_t* gimbal_control) { -#if MAVLINK_NEED_BYTE_SWAP - gimbal_control->demanded_rate_x = mavlink_msg_gimbal_control_get_demanded_rate_x(msg); - gimbal_control->demanded_rate_y = mavlink_msg_gimbal_control_get_demanded_rate_y(msg); - gimbal_control->demanded_rate_z = mavlink_msg_gimbal_control_get_demanded_rate_z(msg); - gimbal_control->gyro_bias_x = mavlink_msg_gimbal_control_get_gyro_bias_x(msg); - gimbal_control->gyro_bias_y = mavlink_msg_gimbal_control_get_gyro_bias_y(msg); - gimbal_control->gyro_bias_z = mavlink_msg_gimbal_control_get_gyro_bias_z(msg); - gimbal_control->target_system = mavlink_msg_gimbal_control_get_target_system(msg); - gimbal_control->target_component = mavlink_msg_gimbal_control_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gimbal_control->demanded_rate_x = mavlink_msg_gimbal_control_get_demanded_rate_x(msg); + gimbal_control->demanded_rate_y = mavlink_msg_gimbal_control_get_demanded_rate_y(msg); + gimbal_control->demanded_rate_z = mavlink_msg_gimbal_control_get_demanded_rate_z(msg); + gimbal_control->target_system = mavlink_msg_gimbal_control_get_target_system(msg); + gimbal_control->target_component = mavlink_msg_gimbal_control_get_target_component(msg); #else - memcpy(gimbal_control, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN? msg->len : MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN; + memset(gimbal_control, 0, MAVLINK_MSG_ID_GIMBAL_CONTROL_LEN); + memcpy(gimbal_control, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_report.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_report.h index a92f0fa2d1..920cb8b32e 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_report.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_report.h @@ -1,35 +1,40 @@ +#pragma once // MESSAGE GIMBAL_REPORT PACKING -#define MAVLINK_MSG_ID_GIMBAL_REPORT 184 - -typedef struct __mavlink_gimbal_report_t -{ - float delta_time; ///< Time since last update (seconds) - float delta_angle_x; ///< Delta angle X, radians - float delta_angle_y; ///< Delta angle Y, radians - float delta_angle_z; ///< Delta angle Z, radians - float delta_velocity_x; ///< Delta velocity X, m/s - float delta_velocity_y; ///< Delta velocity Y, m/s - float delta_velocity_z; ///< Delta velocity Z, m/s - float joint_roll; ///< Joint roll, radians - float joint_pitch; ///< Joint pitch, radians - float joint_yaw; ///< Joint yaw, radians - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_gimbal_report_t; +#define MAVLINK_MSG_ID_GIMBAL_REPORT 200 + +MAVPACKED( +typedef struct __mavlink_gimbal_report_t { + float delta_time; /*< Time since last update (seconds)*/ + float delta_angle_x; /*< Delta angle X (radians)*/ + float delta_angle_y; /*< Delta angle Y (radians)*/ + float delta_angle_z; /*< Delta angle X (radians)*/ + float delta_velocity_x; /*< Delta velocity X (m/s)*/ + float delta_velocity_y; /*< Delta velocity Y (m/s)*/ + float delta_velocity_z; /*< Delta velocity Z (m/s)*/ + float joint_roll; /*< Joint ROLL (radians)*/ + float joint_el; /*< Joint EL (radians)*/ + float joint_az; /*< Joint AZ (radians)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_gimbal_report_t; #define MAVLINK_MSG_ID_GIMBAL_REPORT_LEN 42 -#define MAVLINK_MSG_ID_184_LEN 42 +#define MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN 42 +#define MAVLINK_MSG_ID_200_LEN 42 +#define MAVLINK_MSG_ID_200_MIN_LEN 42 -#define MAVLINK_MSG_ID_GIMBAL_REPORT_CRC 97 -#define MAVLINK_MSG_ID_184_CRC 97 +#define MAVLINK_MSG_ID_GIMBAL_REPORT_CRC 134 +#define MAVLINK_MSG_ID_200_CRC 134 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GIMBAL_REPORT { \ - "GIMBAL_REPORT", \ - 12, \ - { { "delta_time", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_gimbal_report_t, delta_time) }, \ + 200, \ + "GIMBAL_REPORT", \ + 12, \ + { { "delta_time", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_gimbal_report_t, delta_time) }, \ { "delta_angle_x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_gimbal_report_t, delta_angle_x) }, \ { "delta_angle_y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_gimbal_report_t, delta_angle_y) }, \ { "delta_angle_z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_gimbal_report_t, delta_angle_z) }, \ @@ -37,13 +42,31 @@ typedef struct __mavlink_gimbal_report_t { "delta_velocity_y", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_gimbal_report_t, delta_velocity_y) }, \ { "delta_velocity_z", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_gimbal_report_t, delta_velocity_z) }, \ { "joint_roll", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_gimbal_report_t, joint_roll) }, \ - { "joint_pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_gimbal_report_t, joint_pitch) }, \ - { "joint_yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_gimbal_report_t, joint_yaw) }, \ + { "joint_el", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_gimbal_report_t, joint_el) }, \ + { "joint_az", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_gimbal_report_t, joint_az) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_gimbal_report_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_gimbal_report_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GIMBAL_REPORT { \ + "GIMBAL_REPORT", \ + 12, \ + { { "delta_time", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_gimbal_report_t, delta_time) }, \ + { "delta_angle_x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_gimbal_report_t, delta_angle_x) }, \ + { "delta_angle_y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_gimbal_report_t, delta_angle_y) }, \ + { "delta_angle_z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_gimbal_report_t, delta_angle_z) }, \ + { "delta_velocity_x", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_gimbal_report_t, delta_velocity_x) }, \ + { "delta_velocity_y", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_gimbal_report_t, delta_velocity_y) }, \ + { "delta_velocity_z", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_gimbal_report_t, delta_velocity_z) }, \ + { "joint_roll", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_gimbal_report_t, joint_roll) }, \ + { "joint_el", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_gimbal_report_t, joint_el) }, \ + { "joint_az", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_gimbal_report_t, joint_az) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_gimbal_report_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_gimbal_report_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a gimbal_report message @@ -54,60 +77,56 @@ typedef struct __mavlink_gimbal_report_t * @param target_system System ID * @param target_component Component ID * @param delta_time Time since last update (seconds) - * @param delta_angle_x Delta angle X, radians - * @param delta_angle_y Delta angle Y, radians - * @param delta_angle_z Delta angle Z, radians - * @param delta_velocity_x Delta velocity X, m/s - * @param delta_velocity_y Delta velocity Y, m/s - * @param delta_velocity_z Delta velocity Z, m/s - * @param joint_roll Joint roll, radians - * @param joint_pitch Joint pitch, radians - * @param joint_yaw Joint yaw, radians + * @param delta_angle_x Delta angle X (radians) + * @param delta_angle_y Delta angle Y (radians) + * @param delta_angle_z Delta angle X (radians) + * @param delta_velocity_x Delta velocity X (m/s) + * @param delta_velocity_y Delta velocity Y (m/s) + * @param delta_velocity_z Delta velocity Z (m/s) + * @param joint_roll Joint ROLL (radians) + * @param joint_el Joint EL (radians) + * @param joint_az Joint AZ (radians) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gimbal_report_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, float delta_time, float delta_angle_x, float delta_angle_y, float delta_angle_z, float delta_velocity_x, float delta_velocity_y, float delta_velocity_z, float joint_roll, float joint_pitch, float joint_yaw) + uint8_t target_system, uint8_t target_component, float delta_time, float delta_angle_x, float delta_angle_y, float delta_angle_z, float delta_velocity_x, float delta_velocity_y, float delta_velocity_z, float joint_roll, float joint_el, float joint_az) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GIMBAL_REPORT_LEN]; - _mav_put_float(buf, 0, delta_time); - _mav_put_float(buf, 4, delta_angle_x); - _mav_put_float(buf, 8, delta_angle_y); - _mav_put_float(buf, 12, delta_angle_z); - _mav_put_float(buf, 16, delta_velocity_x); - _mav_put_float(buf, 20, delta_velocity_y); - _mav_put_float(buf, 24, delta_velocity_z); - _mav_put_float(buf, 28, joint_roll); - _mav_put_float(buf, 32, joint_pitch); - _mav_put_float(buf, 36, joint_yaw); - _mav_put_uint8_t(buf, 40, target_system); - _mav_put_uint8_t(buf, 41, target_component); + char buf[MAVLINK_MSG_ID_GIMBAL_REPORT_LEN]; + _mav_put_float(buf, 0, delta_time); + _mav_put_float(buf, 4, delta_angle_x); + _mav_put_float(buf, 8, delta_angle_y); + _mav_put_float(buf, 12, delta_angle_z); + _mav_put_float(buf, 16, delta_velocity_x); + _mav_put_float(buf, 20, delta_velocity_y); + _mav_put_float(buf, 24, delta_velocity_z); + _mav_put_float(buf, 28, joint_roll); + _mav_put_float(buf, 32, joint_el); + _mav_put_float(buf, 36, joint_az); + _mav_put_uint8_t(buf, 40, target_system); + _mav_put_uint8_t(buf, 41, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); #else - mavlink_gimbal_report_t packet; - packet.delta_time = delta_time; - packet.delta_angle_x = delta_angle_x; - packet.delta_angle_y = delta_angle_y; - packet.delta_angle_z = delta_angle_z; - packet.delta_velocity_x = delta_velocity_x; - packet.delta_velocity_y = delta_velocity_y; - packet.delta_velocity_z = delta_velocity_z; - packet.joint_roll = joint_roll; - packet.joint_pitch = joint_pitch; - packet.joint_yaw = joint_yaw; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_gimbal_report_t packet; + packet.delta_time = delta_time; + packet.delta_angle_x = delta_angle_x; + packet.delta_angle_y = delta_angle_y; + packet.delta_angle_z = delta_angle_z; + packet.delta_velocity_x = delta_velocity_x; + packet.delta_velocity_y = delta_velocity_y; + packet.delta_velocity_z = delta_velocity_z; + packet.joint_roll = joint_roll; + packet.joint_el = joint_el; + packet.joint_az = joint_az; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GIMBAL_REPORT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GIMBAL_REPORT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); } /** @@ -119,61 +138,57 @@ static inline uint16_t mavlink_msg_gimbal_report_pack(uint8_t system_id, uint8_t * @param target_system System ID * @param target_component Component ID * @param delta_time Time since last update (seconds) - * @param delta_angle_x Delta angle X, radians - * @param delta_angle_y Delta angle Y, radians - * @param delta_angle_z Delta angle Z, radians - * @param delta_velocity_x Delta velocity X, m/s - * @param delta_velocity_y Delta velocity Y, m/s - * @param delta_velocity_z Delta velocity Z, m/s - * @param joint_roll Joint roll, radians - * @param joint_pitch Joint pitch, radians - * @param joint_yaw Joint yaw, radians + * @param delta_angle_x Delta angle X (radians) + * @param delta_angle_y Delta angle Y (radians) + * @param delta_angle_z Delta angle X (radians) + * @param delta_velocity_x Delta velocity X (m/s) + * @param delta_velocity_y Delta velocity Y (m/s) + * @param delta_velocity_z Delta velocity Z (m/s) + * @param joint_roll Joint ROLL (radians) + * @param joint_el Joint EL (radians) + * @param joint_az Joint AZ (radians) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gimbal_report_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,float delta_time,float delta_angle_x,float delta_angle_y,float delta_angle_z,float delta_velocity_x,float delta_velocity_y,float delta_velocity_z,float joint_roll,float joint_pitch,float joint_yaw) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,float delta_time,float delta_angle_x,float delta_angle_y,float delta_angle_z,float delta_velocity_x,float delta_velocity_y,float delta_velocity_z,float joint_roll,float joint_el,float joint_az) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GIMBAL_REPORT_LEN]; - _mav_put_float(buf, 0, delta_time); - _mav_put_float(buf, 4, delta_angle_x); - _mav_put_float(buf, 8, delta_angle_y); - _mav_put_float(buf, 12, delta_angle_z); - _mav_put_float(buf, 16, delta_velocity_x); - _mav_put_float(buf, 20, delta_velocity_y); - _mav_put_float(buf, 24, delta_velocity_z); - _mav_put_float(buf, 28, joint_roll); - _mav_put_float(buf, 32, joint_pitch); - _mav_put_float(buf, 36, joint_yaw); - _mav_put_uint8_t(buf, 40, target_system); - _mav_put_uint8_t(buf, 41, target_component); + char buf[MAVLINK_MSG_ID_GIMBAL_REPORT_LEN]; + _mav_put_float(buf, 0, delta_time); + _mav_put_float(buf, 4, delta_angle_x); + _mav_put_float(buf, 8, delta_angle_y); + _mav_put_float(buf, 12, delta_angle_z); + _mav_put_float(buf, 16, delta_velocity_x); + _mav_put_float(buf, 20, delta_velocity_y); + _mav_put_float(buf, 24, delta_velocity_z); + _mav_put_float(buf, 28, joint_roll); + _mav_put_float(buf, 32, joint_el); + _mav_put_float(buf, 36, joint_az); + _mav_put_uint8_t(buf, 40, target_system); + _mav_put_uint8_t(buf, 41, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); #else - mavlink_gimbal_report_t packet; - packet.delta_time = delta_time; - packet.delta_angle_x = delta_angle_x; - packet.delta_angle_y = delta_angle_y; - packet.delta_angle_z = delta_angle_z; - packet.delta_velocity_x = delta_velocity_x; - packet.delta_velocity_y = delta_velocity_y; - packet.delta_velocity_z = delta_velocity_z; - packet.joint_roll = joint_roll; - packet.joint_pitch = joint_pitch; - packet.joint_yaw = joint_yaw; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_gimbal_report_t packet; + packet.delta_time = delta_time; + packet.delta_angle_x = delta_angle_x; + packet.delta_angle_y = delta_angle_y; + packet.delta_angle_z = delta_angle_z; + packet.delta_velocity_x = delta_velocity_x; + packet.delta_velocity_y = delta_velocity_y; + packet.delta_velocity_z = delta_velocity_z; + packet.joint_roll = joint_roll; + packet.joint_el = joint_el; + packet.joint_az = joint_az; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GIMBAL_REPORT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GIMBAL_REPORT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); } /** @@ -186,7 +201,7 @@ static inline uint16_t mavlink_msg_gimbal_report_pack_chan(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_gimbal_report_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gimbal_report_t* gimbal_report) { - return mavlink_msg_gimbal_report_pack(system_id, component_id, msg, gimbal_report->target_system, gimbal_report->target_component, gimbal_report->delta_time, gimbal_report->delta_angle_x, gimbal_report->delta_angle_y, gimbal_report->delta_angle_z, gimbal_report->delta_velocity_x, gimbal_report->delta_velocity_y, gimbal_report->delta_velocity_z, gimbal_report->joint_roll, gimbal_report->joint_pitch, gimbal_report->joint_yaw); + return mavlink_msg_gimbal_report_pack(system_id, component_id, msg, gimbal_report->target_system, gimbal_report->target_component, gimbal_report->delta_time, gimbal_report->delta_angle_x, gimbal_report->delta_angle_y, gimbal_report->delta_angle_z, gimbal_report->delta_velocity_x, gimbal_report->delta_velocity_y, gimbal_report->delta_velocity_z, gimbal_report->joint_roll, gimbal_report->joint_el, gimbal_report->joint_az); } /** @@ -200,7 +215,7 @@ static inline uint16_t mavlink_msg_gimbal_report_encode(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_gimbal_report_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gimbal_report_t* gimbal_report) { - return mavlink_msg_gimbal_report_pack_chan(system_id, component_id, chan, msg, gimbal_report->target_system, gimbal_report->target_component, gimbal_report->delta_time, gimbal_report->delta_angle_x, gimbal_report->delta_angle_y, gimbal_report->delta_angle_z, gimbal_report->delta_velocity_x, gimbal_report->delta_velocity_y, gimbal_report->delta_velocity_z, gimbal_report->joint_roll, gimbal_report->joint_pitch, gimbal_report->joint_yaw); + return mavlink_msg_gimbal_report_pack_chan(system_id, component_id, chan, msg, gimbal_report->target_system, gimbal_report->target_component, gimbal_report->delta_time, gimbal_report->delta_angle_x, gimbal_report->delta_angle_y, gimbal_report->delta_angle_z, gimbal_report->delta_velocity_x, gimbal_report->delta_velocity_y, gimbal_report->delta_velocity_z, gimbal_report->joint_roll, gimbal_report->joint_el, gimbal_report->joint_az); } /** @@ -210,60 +225,66 @@ static inline uint16_t mavlink_msg_gimbal_report_encode_chan(uint8_t system_id, * @param target_system System ID * @param target_component Component ID * @param delta_time Time since last update (seconds) - * @param delta_angle_x Delta angle X, radians - * @param delta_angle_y Delta angle Y, radians - * @param delta_angle_z Delta angle Z, radians - * @param delta_velocity_x Delta velocity X, m/s - * @param delta_velocity_y Delta velocity Y, m/s - * @param delta_velocity_z Delta velocity Z, m/s - * @param joint_roll Joint roll, radians - * @param joint_pitch Joint pitch, radians - * @param joint_yaw Joint yaw, radians + * @param delta_angle_x Delta angle X (radians) + * @param delta_angle_y Delta angle Y (radians) + * @param delta_angle_z Delta angle X (radians) + * @param delta_velocity_x Delta velocity X (m/s) + * @param delta_velocity_y Delta velocity Y (m/s) + * @param delta_velocity_z Delta velocity Z (m/s) + * @param joint_roll Joint ROLL (radians) + * @param joint_el Joint EL (radians) + * @param joint_az Joint AZ (radians) */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS -static inline void mavlink_msg_gimbal_report_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float delta_time, float delta_angle_x, float delta_angle_y, float delta_angle_z, float delta_velocity_x, float delta_velocity_y, float delta_velocity_z, float joint_roll, float joint_pitch, float joint_yaw) +static inline void mavlink_msg_gimbal_report_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float delta_time, float delta_angle_x, float delta_angle_y, float delta_angle_z, float delta_velocity_x, float delta_velocity_y, float delta_velocity_z, float joint_roll, float joint_el, float joint_az) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GIMBAL_REPORT_LEN]; - _mav_put_float(buf, 0, delta_time); - _mav_put_float(buf, 4, delta_angle_x); - _mav_put_float(buf, 8, delta_angle_y); - _mav_put_float(buf, 12, delta_angle_z); - _mav_put_float(buf, 16, delta_velocity_x); - _mav_put_float(buf, 20, delta_velocity_y); - _mav_put_float(buf, 24, delta_velocity_z); - _mav_put_float(buf, 28, joint_roll); - _mav_put_float(buf, 32, joint_pitch); - _mav_put_float(buf, 36, joint_yaw); - _mav_put_uint8_t(buf, 40, target_system); - _mav_put_uint8_t(buf, 41, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); + char buf[MAVLINK_MSG_ID_GIMBAL_REPORT_LEN]; + _mav_put_float(buf, 0, delta_time); + _mav_put_float(buf, 4, delta_angle_x); + _mav_put_float(buf, 8, delta_angle_y); + _mav_put_float(buf, 12, delta_angle_z); + _mav_put_float(buf, 16, delta_velocity_x); + _mav_put_float(buf, 20, delta_velocity_y); + _mav_put_float(buf, 24, delta_velocity_z); + _mav_put_float(buf, 28, joint_roll); + _mav_put_float(buf, 32, joint_el); + _mav_put_float(buf, 36, joint_az); + _mav_put_uint8_t(buf, 40, target_system); + _mav_put_uint8_t(buf, 41, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); + mavlink_gimbal_report_t packet; + packet.delta_time = delta_time; + packet.delta_angle_x = delta_angle_x; + packet.delta_angle_y = delta_angle_y; + packet.delta_angle_z = delta_angle_z; + packet.delta_velocity_x = delta_velocity_x; + packet.delta_velocity_y = delta_velocity_y; + packet.delta_velocity_z = delta_velocity_z; + packet.joint_roll = joint_roll; + packet.joint_el = joint_el; + packet.joint_az = joint_az; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, (const char *)&packet, MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); #endif +} + +/** + * @brief Send a gimbal_report message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gimbal_report_send_struct(mavlink_channel_t chan, const mavlink_gimbal_report_t* gimbal_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gimbal_report_send(chan, gimbal_report->target_system, gimbal_report->target_component, gimbal_report->delta_time, gimbal_report->delta_angle_x, gimbal_report->delta_angle_y, gimbal_report->delta_angle_z, gimbal_report->delta_velocity_x, gimbal_report->delta_velocity_y, gimbal_report->delta_velocity_z, gimbal_report->joint_roll, gimbal_report->joint_el, gimbal_report->joint_az); #else - mavlink_gimbal_report_t packet; - packet.delta_time = delta_time; - packet.delta_angle_x = delta_angle_x; - packet.delta_angle_y = delta_angle_y; - packet.delta_angle_z = delta_angle_z; - packet.delta_velocity_x = delta_velocity_x; - packet.delta_velocity_y = delta_velocity_y; - packet.delta_velocity_z = delta_velocity_z; - packet.joint_roll = joint_roll; - packet.joint_pitch = joint_pitch; - packet.joint_yaw = joint_yaw; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, (const char *)&packet, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, (const char *)&packet, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, (const char *)gimbal_report, MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); #endif } @@ -275,48 +296,40 @@ static inline void mavlink_msg_gimbal_report_send(mavlink_channel_t chan, uint8_ is usually the receive buffer for the channel, and allows a reply to an incoming message with minimum stack space usage. */ -static inline void mavlink_msg_gimbal_report_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float delta_time, float delta_angle_x, float delta_angle_y, float delta_angle_z, float delta_velocity_x, float delta_velocity_y, float delta_velocity_z, float joint_roll, float joint_pitch, float joint_yaw) +static inline void mavlink_msg_gimbal_report_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, float delta_time, float delta_angle_x, float delta_angle_y, float delta_angle_z, float delta_velocity_x, float delta_velocity_y, float delta_velocity_z, float joint_roll, float joint_el, float joint_az) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, delta_time); - _mav_put_float(buf, 4, delta_angle_x); - _mav_put_float(buf, 8, delta_angle_y); - _mav_put_float(buf, 12, delta_angle_z); - _mav_put_float(buf, 16, delta_velocity_x); - _mav_put_float(buf, 20, delta_velocity_y); - _mav_put_float(buf, 24, delta_velocity_z); - _mav_put_float(buf, 28, joint_roll); - _mav_put_float(buf, 32, joint_pitch); - _mav_put_float(buf, 36, joint_yaw); - _mav_put_uint8_t(buf, 40, target_system); - _mav_put_uint8_t(buf, 41, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, delta_time); + _mav_put_float(buf, 4, delta_angle_x); + _mav_put_float(buf, 8, delta_angle_y); + _mav_put_float(buf, 12, delta_angle_z); + _mav_put_float(buf, 16, delta_velocity_x); + _mav_put_float(buf, 20, delta_velocity_y); + _mav_put_float(buf, 24, delta_velocity_z); + _mav_put_float(buf, 28, joint_roll); + _mav_put_float(buf, 32, joint_el); + _mav_put_float(buf, 36, joint_az); + _mav_put_uint8_t(buf, 40, target_system); + _mav_put_uint8_t(buf, 41, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); -#endif -#else - mavlink_gimbal_report_t *packet = (mavlink_gimbal_report_t *)msgbuf; - packet->delta_time = delta_time; - packet->delta_angle_x = delta_angle_x; - packet->delta_angle_y = delta_angle_y; - packet->delta_angle_z = delta_angle_z; - packet->delta_velocity_x = delta_velocity_x; - packet->delta_velocity_y = delta_velocity_y; - packet->delta_velocity_z = delta_velocity_z; - packet->joint_roll = joint_roll; - packet->joint_pitch = joint_pitch; - packet->joint_yaw = joint_yaw; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, (const char *)packet, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, (const char *)packet, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); -#endif + mavlink_gimbal_report_t *packet = (mavlink_gimbal_report_t *)msgbuf; + packet->delta_time = delta_time; + packet->delta_angle_x = delta_angle_x; + packet->delta_angle_y = delta_angle_y; + packet->delta_angle_z = delta_angle_z; + packet->delta_velocity_x = delta_velocity_x; + packet->delta_velocity_y = delta_velocity_y; + packet->delta_velocity_z = delta_velocity_z; + packet->joint_roll = joint_roll; + packet->joint_el = joint_el; + packet->joint_az = joint_az; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_REPORT, (const char *)packet, MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_REPORT_CRC); #endif } #endif @@ -333,7 +346,7 @@ static inline void mavlink_msg_gimbal_report_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_gimbal_report_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 40); + return _MAV_RETURN_uint8_t(msg, 40); } /** @@ -343,7 +356,7 @@ static inline uint8_t mavlink_msg_gimbal_report_get_target_system(const mavlink_ */ static inline uint8_t mavlink_msg_gimbal_report_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 41); + return _MAV_RETURN_uint8_t(msg, 41); } /** @@ -353,97 +366,97 @@ static inline uint8_t mavlink_msg_gimbal_report_get_target_component(const mavli */ static inline float mavlink_msg_gimbal_report_get_delta_time(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** * @brief Get field delta_angle_x from gimbal_report message * - * @return Delta angle X, radians + * @return Delta angle X (radians) */ static inline float mavlink_msg_gimbal_report_get_delta_angle_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** * @brief Get field delta_angle_y from gimbal_report message * - * @return Delta angle Y, radians + * @return Delta angle Y (radians) */ static inline float mavlink_msg_gimbal_report_get_delta_angle_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** * @brief Get field delta_angle_z from gimbal_report message * - * @return Delta angle Z, radians + * @return Delta angle X (radians) */ static inline float mavlink_msg_gimbal_report_get_delta_angle_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** * @brief Get field delta_velocity_x from gimbal_report message * - * @return Delta velocity X, m/s + * @return Delta velocity X (m/s) */ static inline float mavlink_msg_gimbal_report_get_delta_velocity_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** * @brief Get field delta_velocity_y from gimbal_report message * - * @return Delta velocity Y, m/s + * @return Delta velocity Y (m/s) */ static inline float mavlink_msg_gimbal_report_get_delta_velocity_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** * @brief Get field delta_velocity_z from gimbal_report message * - * @return Delta velocity Z, m/s + * @return Delta velocity Z (m/s) */ static inline float mavlink_msg_gimbal_report_get_delta_velocity_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** * @brief Get field joint_roll from gimbal_report message * - * @return Joint roll, radians + * @return Joint ROLL (radians) */ static inline float mavlink_msg_gimbal_report_get_joint_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** - * @brief Get field joint_pitch from gimbal_report message + * @brief Get field joint_el from gimbal_report message * - * @return Joint pitch, radians + * @return Joint EL (radians) */ -static inline float mavlink_msg_gimbal_report_get_joint_pitch(const mavlink_message_t* msg) +static inline float mavlink_msg_gimbal_report_get_joint_el(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** - * @brief Get field joint_yaw from gimbal_report message + * @brief Get field joint_az from gimbal_report message * - * @return Joint yaw, radians + * @return Joint AZ (radians) */ -static inline float mavlink_msg_gimbal_report_get_joint_yaw(const mavlink_message_t* msg) +static inline float mavlink_msg_gimbal_report_get_joint_az(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -454,20 +467,22 @@ static inline float mavlink_msg_gimbal_report_get_joint_yaw(const mavlink_messag */ static inline void mavlink_msg_gimbal_report_decode(const mavlink_message_t* msg, mavlink_gimbal_report_t* gimbal_report) { -#if MAVLINK_NEED_BYTE_SWAP - gimbal_report->delta_time = mavlink_msg_gimbal_report_get_delta_time(msg); - gimbal_report->delta_angle_x = mavlink_msg_gimbal_report_get_delta_angle_x(msg); - gimbal_report->delta_angle_y = mavlink_msg_gimbal_report_get_delta_angle_y(msg); - gimbal_report->delta_angle_z = mavlink_msg_gimbal_report_get_delta_angle_z(msg); - gimbal_report->delta_velocity_x = mavlink_msg_gimbal_report_get_delta_velocity_x(msg); - gimbal_report->delta_velocity_y = mavlink_msg_gimbal_report_get_delta_velocity_y(msg); - gimbal_report->delta_velocity_z = mavlink_msg_gimbal_report_get_delta_velocity_z(msg); - gimbal_report->joint_roll = mavlink_msg_gimbal_report_get_joint_roll(msg); - gimbal_report->joint_pitch = mavlink_msg_gimbal_report_get_joint_pitch(msg); - gimbal_report->joint_yaw = mavlink_msg_gimbal_report_get_joint_yaw(msg); - gimbal_report->target_system = mavlink_msg_gimbal_report_get_target_system(msg); - gimbal_report->target_component = mavlink_msg_gimbal_report_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gimbal_report->delta_time = mavlink_msg_gimbal_report_get_delta_time(msg); + gimbal_report->delta_angle_x = mavlink_msg_gimbal_report_get_delta_angle_x(msg); + gimbal_report->delta_angle_y = mavlink_msg_gimbal_report_get_delta_angle_y(msg); + gimbal_report->delta_angle_z = mavlink_msg_gimbal_report_get_delta_angle_z(msg); + gimbal_report->delta_velocity_x = mavlink_msg_gimbal_report_get_delta_velocity_x(msg); + gimbal_report->delta_velocity_y = mavlink_msg_gimbal_report_get_delta_velocity_y(msg); + gimbal_report->delta_velocity_z = mavlink_msg_gimbal_report_get_delta_velocity_z(msg); + gimbal_report->joint_roll = mavlink_msg_gimbal_report_get_joint_roll(msg); + gimbal_report->joint_el = mavlink_msg_gimbal_report_get_joint_el(msg); + gimbal_report->joint_az = mavlink_msg_gimbal_report_get_joint_az(msg); + gimbal_report->target_system = mavlink_msg_gimbal_report_get_target_system(msg); + gimbal_report->target_component = mavlink_msg_gimbal_report_get_target_component(msg); #else - memcpy(gimbal_report, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GIMBAL_REPORT_LEN? msg->len : MAVLINK_MSG_ID_GIMBAL_REPORT_LEN; + memset(gimbal_report, 0, MAVLINK_MSG_ID_GIMBAL_REPORT_LEN); + memcpy(gimbal_report, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_torque_cmd_report.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_torque_cmd_report.h new file mode 100644 index 0000000000..d3e90db5b1 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gimbal_torque_cmd_report.h @@ -0,0 +1,313 @@ +#pragma once +// MESSAGE GIMBAL_TORQUE_CMD_REPORT PACKING + +#define MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT 214 + +MAVPACKED( +typedef struct __mavlink_gimbal_torque_cmd_report_t { + int16_t rl_torque_cmd; /*< Roll Torque Command*/ + int16_t el_torque_cmd; /*< Elevation Torque Command*/ + int16_t az_torque_cmd; /*< Azimuth Torque Command*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_gimbal_torque_cmd_report_t; + +#define MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN 8 +#define MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN 8 +#define MAVLINK_MSG_ID_214_LEN 8 +#define MAVLINK_MSG_ID_214_MIN_LEN 8 + +#define MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC 69 +#define MAVLINK_MSG_ID_214_CRC 69 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GIMBAL_TORQUE_CMD_REPORT { \ + 214, \ + "GIMBAL_TORQUE_CMD_REPORT", \ + 5, \ + { { "rl_torque_cmd", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_gimbal_torque_cmd_report_t, rl_torque_cmd) }, \ + { "el_torque_cmd", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_gimbal_torque_cmd_report_t, el_torque_cmd) }, \ + { "az_torque_cmd", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_gimbal_torque_cmd_report_t, az_torque_cmd) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_gimbal_torque_cmd_report_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_gimbal_torque_cmd_report_t, target_component) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GIMBAL_TORQUE_CMD_REPORT { \ + "GIMBAL_TORQUE_CMD_REPORT", \ + 5, \ + { { "rl_torque_cmd", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_gimbal_torque_cmd_report_t, rl_torque_cmd) }, \ + { "el_torque_cmd", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_gimbal_torque_cmd_report_t, el_torque_cmd) }, \ + { "az_torque_cmd", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_gimbal_torque_cmd_report_t, az_torque_cmd) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_gimbal_torque_cmd_report_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_gimbal_torque_cmd_report_t, target_component) }, \ + } \ +} +#endif + +/** + * @brief Pack a gimbal_torque_cmd_report message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID + * @param target_component Component ID + * @param rl_torque_cmd Roll Torque Command + * @param el_torque_cmd Elevation Torque Command + * @param az_torque_cmd Azimuth Torque Command + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gimbal_torque_cmd_report_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, uint8_t target_component, int16_t rl_torque_cmd, int16_t el_torque_cmd, int16_t az_torque_cmd) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN]; + _mav_put_int16_t(buf, 0, rl_torque_cmd); + _mav_put_int16_t(buf, 2, el_torque_cmd); + _mav_put_int16_t(buf, 4, az_torque_cmd); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN); +#else + mavlink_gimbal_torque_cmd_report_t packet; + packet.rl_torque_cmd = rl_torque_cmd; + packet.el_torque_cmd = el_torque_cmd; + packet.az_torque_cmd = az_torque_cmd; + packet.target_system = target_system; + packet.target_component = target_component; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC); +} + +/** + * @brief Pack a gimbal_torque_cmd_report message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID + * @param target_component Component ID + * @param rl_torque_cmd Roll Torque Command + * @param el_torque_cmd Elevation Torque Command + * @param az_torque_cmd Azimuth Torque Command + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gimbal_torque_cmd_report_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,int16_t rl_torque_cmd,int16_t el_torque_cmd,int16_t az_torque_cmd) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN]; + _mav_put_int16_t(buf, 0, rl_torque_cmd); + _mav_put_int16_t(buf, 2, el_torque_cmd); + _mav_put_int16_t(buf, 4, az_torque_cmd); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN); +#else + mavlink_gimbal_torque_cmd_report_t packet; + packet.rl_torque_cmd = rl_torque_cmd; + packet.el_torque_cmd = el_torque_cmd; + packet.az_torque_cmd = az_torque_cmd; + packet.target_system = target_system; + packet.target_component = target_component; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC); +} + +/** + * @brief Encode a gimbal_torque_cmd_report struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gimbal_torque_cmd_report C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gimbal_torque_cmd_report_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gimbal_torque_cmd_report_t* gimbal_torque_cmd_report) +{ + return mavlink_msg_gimbal_torque_cmd_report_pack(system_id, component_id, msg, gimbal_torque_cmd_report->target_system, gimbal_torque_cmd_report->target_component, gimbal_torque_cmd_report->rl_torque_cmd, gimbal_torque_cmd_report->el_torque_cmd, gimbal_torque_cmd_report->az_torque_cmd); +} + +/** + * @brief Encode a gimbal_torque_cmd_report struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gimbal_torque_cmd_report C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gimbal_torque_cmd_report_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gimbal_torque_cmd_report_t* gimbal_torque_cmd_report) +{ + return mavlink_msg_gimbal_torque_cmd_report_pack_chan(system_id, component_id, chan, msg, gimbal_torque_cmd_report->target_system, gimbal_torque_cmd_report->target_component, gimbal_torque_cmd_report->rl_torque_cmd, gimbal_torque_cmd_report->el_torque_cmd, gimbal_torque_cmd_report->az_torque_cmd); +} + +/** + * @brief Send a gimbal_torque_cmd_report message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID + * @param target_component Component ID + * @param rl_torque_cmd Roll Torque Command + * @param el_torque_cmd Elevation Torque Command + * @param az_torque_cmd Azimuth Torque Command + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gimbal_torque_cmd_report_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t rl_torque_cmd, int16_t el_torque_cmd, int16_t az_torque_cmd) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN]; + _mav_put_int16_t(buf, 0, rl_torque_cmd); + _mav_put_int16_t(buf, 2, el_torque_cmd); + _mav_put_int16_t(buf, 4, az_torque_cmd); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC); +#else + mavlink_gimbal_torque_cmd_report_t packet; + packet.rl_torque_cmd = rl_torque_cmd; + packet.el_torque_cmd = el_torque_cmd; + packet.az_torque_cmd = az_torque_cmd; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT, (const char *)&packet, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC); +#endif +} + +/** + * @brief Send a gimbal_torque_cmd_report message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gimbal_torque_cmd_report_send_struct(mavlink_channel_t chan, const mavlink_gimbal_torque_cmd_report_t* gimbal_torque_cmd_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gimbal_torque_cmd_report_send(chan, gimbal_torque_cmd_report->target_system, gimbal_torque_cmd_report->target_component, gimbal_torque_cmd_report->rl_torque_cmd, gimbal_torque_cmd_report->el_torque_cmd, gimbal_torque_cmd_report->az_torque_cmd); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT, (const char *)gimbal_torque_cmd_report, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gimbal_torque_cmd_report_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t rl_torque_cmd, int16_t el_torque_cmd, int16_t az_torque_cmd) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_int16_t(buf, 0, rl_torque_cmd); + _mav_put_int16_t(buf, 2, el_torque_cmd); + _mav_put_int16_t(buf, 4, az_torque_cmd); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT, buf, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC); +#else + mavlink_gimbal_torque_cmd_report_t *packet = (mavlink_gimbal_torque_cmd_report_t *)msgbuf; + packet->rl_torque_cmd = rl_torque_cmd; + packet->el_torque_cmd = el_torque_cmd; + packet->az_torque_cmd = az_torque_cmd; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT, (const char *)packet, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GIMBAL_TORQUE_CMD_REPORT UNPACKING + + +/** + * @brief Get field target_system from gimbal_torque_cmd_report message + * + * @return System ID + */ +static inline uint8_t mavlink_msg_gimbal_torque_cmd_report_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 6); +} + +/** + * @brief Get field target_component from gimbal_torque_cmd_report message + * + * @return Component ID + */ +static inline uint8_t mavlink_msg_gimbal_torque_cmd_report_get_target_component(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 7); +} + +/** + * @brief Get field rl_torque_cmd from gimbal_torque_cmd_report message + * + * @return Roll Torque Command + */ +static inline int16_t mavlink_msg_gimbal_torque_cmd_report_get_rl_torque_cmd(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 0); +} + +/** + * @brief Get field el_torque_cmd from gimbal_torque_cmd_report message + * + * @return Elevation Torque Command + */ +static inline int16_t mavlink_msg_gimbal_torque_cmd_report_get_el_torque_cmd(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 2); +} + +/** + * @brief Get field az_torque_cmd from gimbal_torque_cmd_report message + * + * @return Azimuth Torque Command + */ +static inline int16_t mavlink_msg_gimbal_torque_cmd_report_get_az_torque_cmd(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 4); +} + +/** + * @brief Decode a gimbal_torque_cmd_report message into a struct + * + * @param msg The message to decode + * @param gimbal_torque_cmd_report C-struct to decode the message contents into + */ +static inline void mavlink_msg_gimbal_torque_cmd_report_decode(const mavlink_message_t* msg, mavlink_gimbal_torque_cmd_report_t* gimbal_torque_cmd_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gimbal_torque_cmd_report->rl_torque_cmd = mavlink_msg_gimbal_torque_cmd_report_get_rl_torque_cmd(msg); + gimbal_torque_cmd_report->el_torque_cmd = mavlink_msg_gimbal_torque_cmd_report_get_el_torque_cmd(msg); + gimbal_torque_cmd_report->az_torque_cmd = mavlink_msg_gimbal_torque_cmd_report_get_az_torque_cmd(msg); + gimbal_torque_cmd_report->target_system = mavlink_msg_gimbal_torque_cmd_report_get_target_system(msg); + gimbal_torque_cmd_report->target_component = mavlink_msg_gimbal_torque_cmd_report_get_target_component(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN? msg->len : MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN; + memset(gimbal_torque_cmd_report, 0, MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_LEN); + memcpy(gimbal_torque_cmd_report, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_get_request.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_get_request.h new file mode 100644 index 0000000000..eb60d15081 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_get_request.h @@ -0,0 +1,263 @@ +#pragma once +// MESSAGE GOPRO_GET_REQUEST PACKING + +#define MAVLINK_MSG_ID_GOPRO_GET_REQUEST 216 + +MAVPACKED( +typedef struct __mavlink_gopro_get_request_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t cmd_id; /*< Command ID*/ +}) mavlink_gopro_get_request_t; + +#define MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN 3 +#define MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN 3 +#define MAVLINK_MSG_ID_216_LEN 3 +#define MAVLINK_MSG_ID_216_MIN_LEN 3 + +#define MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC 50 +#define MAVLINK_MSG_ID_216_CRC 50 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GOPRO_GET_REQUEST { \ + 216, \ + "GOPRO_GET_REQUEST", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_get_request_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_get_request_t, target_component) }, \ + { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gopro_get_request_t, cmd_id) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GOPRO_GET_REQUEST { \ + "GOPRO_GET_REQUEST", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_get_request_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_get_request_t, target_component) }, \ + { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gopro_get_request_t, cmd_id) }, \ + } \ +} +#endif + +/** + * @brief Pack a gopro_get_request message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID + * @param target_component Component ID + * @param cmd_id Command ID + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_get_request_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, uint8_t target_component, uint8_t cmd_id) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN); +#else + mavlink_gopro_get_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.cmd_id = cmd_id; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_GET_REQUEST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC); +} + +/** + * @brief Pack a gopro_get_request message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID + * @param target_component Component ID + * @param cmd_id Command ID + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_get_request_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t cmd_id) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN); +#else + mavlink_gopro_get_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.cmd_id = cmd_id; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_GET_REQUEST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC); +} + +/** + * @brief Encode a gopro_get_request struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gopro_get_request C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_get_request_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gopro_get_request_t* gopro_get_request) +{ + return mavlink_msg_gopro_get_request_pack(system_id, component_id, msg, gopro_get_request->target_system, gopro_get_request->target_component, gopro_get_request->cmd_id); +} + +/** + * @brief Encode a gopro_get_request struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gopro_get_request C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_get_request_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gopro_get_request_t* gopro_get_request) +{ + return mavlink_msg_gopro_get_request_pack_chan(system_id, component_id, chan, msg, gopro_get_request->target_system, gopro_get_request->target_component, gopro_get_request->cmd_id); +} + +/** + * @brief Send a gopro_get_request message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID + * @param target_component Component ID + * @param cmd_id Command ID + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gopro_get_request_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t cmd_id) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_REQUEST, buf, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC); +#else + mavlink_gopro_get_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.cmd_id = cmd_id; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC); +#endif +} + +/** + * @brief Send a gopro_get_request message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gopro_get_request_send_struct(mavlink_channel_t chan, const mavlink_gopro_get_request_t* gopro_get_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gopro_get_request_send(chan, gopro_get_request->target_system, gopro_get_request->target_component, gopro_get_request->cmd_id); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_REQUEST, (const char *)gopro_get_request, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gopro_get_request_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t cmd_id) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_REQUEST, buf, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC); +#else + mavlink_gopro_get_request_t *packet = (mavlink_gopro_get_request_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->cmd_id = cmd_id; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_REQUEST, (const char *)packet, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GOPRO_GET_REQUEST UNPACKING + + +/** + * @brief Get field target_system from gopro_get_request message + * + * @return System ID + */ +static inline uint8_t mavlink_msg_gopro_get_request_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field target_component from gopro_get_request message + * + * @return Component ID + */ +static inline uint8_t mavlink_msg_gopro_get_request_get_target_component(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Get field cmd_id from gopro_get_request message + * + * @return Command ID + */ +static inline uint8_t mavlink_msg_gopro_get_request_get_cmd_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 2); +} + +/** + * @brief Decode a gopro_get_request message into a struct + * + * @param msg The message to decode + * @param gopro_get_request C-struct to decode the message contents into + */ +static inline void mavlink_msg_gopro_get_request_decode(const mavlink_message_t* msg, mavlink_gopro_get_request_t* gopro_get_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gopro_get_request->target_system = mavlink_msg_gopro_get_request_get_target_system(msg); + gopro_get_request->target_component = mavlink_msg_gopro_get_request_get_target_component(msg); + gopro_get_request->cmd_id = mavlink_msg_gopro_get_request_get_cmd_id(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN? msg->len : MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN; + memset(gopro_get_request, 0, MAVLINK_MSG_ID_GOPRO_GET_REQUEST_LEN); + memcpy(gopro_get_request, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_get_response.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_get_response.h new file mode 100644 index 0000000000..e97306c2b1 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_get_response.h @@ -0,0 +1,255 @@ +#pragma once +// MESSAGE GOPRO_GET_RESPONSE PACKING + +#define MAVLINK_MSG_ID_GOPRO_GET_RESPONSE 217 + +MAVPACKED( +typedef struct __mavlink_gopro_get_response_t { + uint8_t cmd_id; /*< Command ID*/ + uint8_t status; /*< Status*/ + uint8_t value[4]; /*< Value*/ +}) mavlink_gopro_get_response_t; + +#define MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN 6 +#define MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN 6 +#define MAVLINK_MSG_ID_217_LEN 6 +#define MAVLINK_MSG_ID_217_MIN_LEN 6 + +#define MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC 202 +#define MAVLINK_MSG_ID_217_CRC 202 + +#define MAVLINK_MSG_GOPRO_GET_RESPONSE_FIELD_VALUE_LEN 4 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GOPRO_GET_RESPONSE { \ + 217, \ + "GOPRO_GET_RESPONSE", \ + 3, \ + { { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_get_response_t, cmd_id) }, \ + { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_get_response_t, status) }, \ + { "value", NULL, MAVLINK_TYPE_UINT8_T, 4, 2, offsetof(mavlink_gopro_get_response_t, value) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GOPRO_GET_RESPONSE { \ + "GOPRO_GET_RESPONSE", \ + 3, \ + { { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_get_response_t, cmd_id) }, \ + { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_get_response_t, status) }, \ + { "value", NULL, MAVLINK_TYPE_UINT8_T, 4, 2, offsetof(mavlink_gopro_get_response_t, value) }, \ + } \ +} +#endif + +/** + * @brief Pack a gopro_get_response message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param cmd_id Command ID + * @param status Status + * @param value Value + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_get_response_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t cmd_id, uint8_t status, const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN]; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + _mav_put_uint8_t_array(buf, 2, value, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN); +#else + mavlink_gopro_get_response_t packet; + packet.cmd_id = cmd_id; + packet.status = status; + mav_array_memcpy(packet.value, value, sizeof(uint8_t)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_GET_RESPONSE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC); +} + +/** + * @brief Pack a gopro_get_response message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param cmd_id Command ID + * @param status Status + * @param value Value + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_get_response_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t cmd_id,uint8_t status,const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN]; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + _mav_put_uint8_t_array(buf, 2, value, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN); +#else + mavlink_gopro_get_response_t packet; + packet.cmd_id = cmd_id; + packet.status = status; + mav_array_memcpy(packet.value, value, sizeof(uint8_t)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_GET_RESPONSE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC); +} + +/** + * @brief Encode a gopro_get_response struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gopro_get_response C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_get_response_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gopro_get_response_t* gopro_get_response) +{ + return mavlink_msg_gopro_get_response_pack(system_id, component_id, msg, gopro_get_response->cmd_id, gopro_get_response->status, gopro_get_response->value); +} + +/** + * @brief Encode a gopro_get_response struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gopro_get_response C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_get_response_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gopro_get_response_t* gopro_get_response) +{ + return mavlink_msg_gopro_get_response_pack_chan(system_id, component_id, chan, msg, gopro_get_response->cmd_id, gopro_get_response->status, gopro_get_response->value); +} + +/** + * @brief Send a gopro_get_response message + * @param chan MAVLink channel to send the message + * + * @param cmd_id Command ID + * @param status Status + * @param value Value + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gopro_get_response_send(mavlink_channel_t chan, uint8_t cmd_id, uint8_t status, const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN]; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + _mav_put_uint8_t_array(buf, 2, value, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE, buf, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC); +#else + mavlink_gopro_get_response_t packet; + packet.cmd_id = cmd_id; + packet.status = status; + mav_array_memcpy(packet.value, value, sizeof(uint8_t)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE, (const char *)&packet, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC); +#endif +} + +/** + * @brief Send a gopro_get_response message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gopro_get_response_send_struct(mavlink_channel_t chan, const mavlink_gopro_get_response_t* gopro_get_response) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gopro_get_response_send(chan, gopro_get_response->cmd_id, gopro_get_response->status, gopro_get_response->value); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE, (const char *)gopro_get_response, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gopro_get_response_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t cmd_id, uint8_t status, const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + _mav_put_uint8_t_array(buf, 2, value, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE, buf, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC); +#else + mavlink_gopro_get_response_t *packet = (mavlink_gopro_get_response_t *)msgbuf; + packet->cmd_id = cmd_id; + packet->status = status; + mav_array_memcpy(packet->value, value, sizeof(uint8_t)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE, (const char *)packet, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GOPRO_GET_RESPONSE UNPACKING + + +/** + * @brief Get field cmd_id from gopro_get_response message + * + * @return Command ID + */ +static inline uint8_t mavlink_msg_gopro_get_response_get_cmd_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field status from gopro_get_response message + * + * @return Status + */ +static inline uint8_t mavlink_msg_gopro_get_response_get_status(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Get field value from gopro_get_response message + * + * @return Value + */ +static inline uint16_t mavlink_msg_gopro_get_response_get_value(const mavlink_message_t* msg, uint8_t *value) +{ + return _MAV_RETURN_uint8_t_array(msg, value, 4, 2); +} + +/** + * @brief Decode a gopro_get_response message into a struct + * + * @param msg The message to decode + * @param gopro_get_response C-struct to decode the message contents into + */ +static inline void mavlink_msg_gopro_get_response_decode(const mavlink_message_t* msg, mavlink_gopro_get_response_t* gopro_get_response) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gopro_get_response->cmd_id = mavlink_msg_gopro_get_response_get_cmd_id(msg); + gopro_get_response->status = mavlink_msg_gopro_get_response_get_status(msg); + mavlink_msg_gopro_get_response_get_value(msg, gopro_get_response->value); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN? msg->len : MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN; + memset(gopro_get_response, 0, MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_LEN); + memcpy(gopro_get_response, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_heartbeat.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_heartbeat.h new file mode 100644 index 0000000000..5275e6a66c --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_heartbeat.h @@ -0,0 +1,263 @@ +#pragma once +// MESSAGE GOPRO_HEARTBEAT PACKING + +#define MAVLINK_MSG_ID_GOPRO_HEARTBEAT 215 + +MAVPACKED( +typedef struct __mavlink_gopro_heartbeat_t { + uint8_t status; /*< Status*/ + uint8_t capture_mode; /*< Current capture mode*/ + uint8_t flags; /*< additional status bits*/ +}) mavlink_gopro_heartbeat_t; + +#define MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN 3 +#define MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN 3 +#define MAVLINK_MSG_ID_215_LEN 3 +#define MAVLINK_MSG_ID_215_MIN_LEN 3 + +#define MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC 101 +#define MAVLINK_MSG_ID_215_CRC 101 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GOPRO_HEARTBEAT { \ + 215, \ + "GOPRO_HEARTBEAT", \ + 3, \ + { { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_heartbeat_t, status) }, \ + { "capture_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_heartbeat_t, capture_mode) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gopro_heartbeat_t, flags) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GOPRO_HEARTBEAT { \ + "GOPRO_HEARTBEAT", \ + 3, \ + { { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_heartbeat_t, status) }, \ + { "capture_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_heartbeat_t, capture_mode) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gopro_heartbeat_t, flags) }, \ + } \ +} +#endif + +/** + * @brief Pack a gopro_heartbeat message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param status Status + * @param capture_mode Current capture mode + * @param flags additional status bits + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_heartbeat_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t status, uint8_t capture_mode, uint8_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN]; + _mav_put_uint8_t(buf, 0, status); + _mav_put_uint8_t(buf, 1, capture_mode); + _mav_put_uint8_t(buf, 2, flags); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN); +#else + mavlink_gopro_heartbeat_t packet; + packet.status = status; + packet.capture_mode = capture_mode; + packet.flags = flags; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_HEARTBEAT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC); +} + +/** + * @brief Pack a gopro_heartbeat message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param status Status + * @param capture_mode Current capture mode + * @param flags additional status bits + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_heartbeat_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t status,uint8_t capture_mode,uint8_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN]; + _mav_put_uint8_t(buf, 0, status); + _mav_put_uint8_t(buf, 1, capture_mode); + _mav_put_uint8_t(buf, 2, flags); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN); +#else + mavlink_gopro_heartbeat_t packet; + packet.status = status; + packet.capture_mode = capture_mode; + packet.flags = flags; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_HEARTBEAT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC); +} + +/** + * @brief Encode a gopro_heartbeat struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gopro_heartbeat C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_heartbeat_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gopro_heartbeat_t* gopro_heartbeat) +{ + return mavlink_msg_gopro_heartbeat_pack(system_id, component_id, msg, gopro_heartbeat->status, gopro_heartbeat->capture_mode, gopro_heartbeat->flags); +} + +/** + * @brief Encode a gopro_heartbeat struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gopro_heartbeat C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_heartbeat_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gopro_heartbeat_t* gopro_heartbeat) +{ + return mavlink_msg_gopro_heartbeat_pack_chan(system_id, component_id, chan, msg, gopro_heartbeat->status, gopro_heartbeat->capture_mode, gopro_heartbeat->flags); +} + +/** + * @brief Send a gopro_heartbeat message + * @param chan MAVLink channel to send the message + * + * @param status Status + * @param capture_mode Current capture mode + * @param flags additional status bits + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gopro_heartbeat_send(mavlink_channel_t chan, uint8_t status, uint8_t capture_mode, uint8_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN]; + _mav_put_uint8_t(buf, 0, status); + _mav_put_uint8_t(buf, 1, capture_mode); + _mav_put_uint8_t(buf, 2, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_HEARTBEAT, buf, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC); +#else + mavlink_gopro_heartbeat_t packet; + packet.status = status; + packet.capture_mode = capture_mode; + packet.flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_HEARTBEAT, (const char *)&packet, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC); +#endif +} + +/** + * @brief Send a gopro_heartbeat message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gopro_heartbeat_send_struct(mavlink_channel_t chan, const mavlink_gopro_heartbeat_t* gopro_heartbeat) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gopro_heartbeat_send(chan, gopro_heartbeat->status, gopro_heartbeat->capture_mode, gopro_heartbeat->flags); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_HEARTBEAT, (const char *)gopro_heartbeat, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gopro_heartbeat_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t status, uint8_t capture_mode, uint8_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, status); + _mav_put_uint8_t(buf, 1, capture_mode); + _mav_put_uint8_t(buf, 2, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_HEARTBEAT, buf, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC); +#else + mavlink_gopro_heartbeat_t *packet = (mavlink_gopro_heartbeat_t *)msgbuf; + packet->status = status; + packet->capture_mode = capture_mode; + packet->flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_HEARTBEAT, (const char *)packet, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GOPRO_HEARTBEAT UNPACKING + + +/** + * @brief Get field status from gopro_heartbeat message + * + * @return Status + */ +static inline uint8_t mavlink_msg_gopro_heartbeat_get_status(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field capture_mode from gopro_heartbeat message + * + * @return Current capture mode + */ +static inline uint8_t mavlink_msg_gopro_heartbeat_get_capture_mode(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Get field flags from gopro_heartbeat message + * + * @return additional status bits + */ +static inline uint8_t mavlink_msg_gopro_heartbeat_get_flags(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 2); +} + +/** + * @brief Decode a gopro_heartbeat message into a struct + * + * @param msg The message to decode + * @param gopro_heartbeat C-struct to decode the message contents into + */ +static inline void mavlink_msg_gopro_heartbeat_decode(const mavlink_message_t* msg, mavlink_gopro_heartbeat_t* gopro_heartbeat) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gopro_heartbeat->status = mavlink_msg_gopro_heartbeat_get_status(msg); + gopro_heartbeat->capture_mode = mavlink_msg_gopro_heartbeat_get_capture_mode(msg); + gopro_heartbeat->flags = mavlink_msg_gopro_heartbeat_get_flags(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN? msg->len : MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN; + memset(gopro_heartbeat, 0, MAVLINK_MSG_ID_GOPRO_HEARTBEAT_LEN); + memcpy(gopro_heartbeat, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_set_request.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_set_request.h new file mode 100644 index 0000000000..09d84548c3 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_set_request.h @@ -0,0 +1,280 @@ +#pragma once +// MESSAGE GOPRO_SET_REQUEST PACKING + +#define MAVLINK_MSG_ID_GOPRO_SET_REQUEST 218 + +MAVPACKED( +typedef struct __mavlink_gopro_set_request_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t cmd_id; /*< Command ID*/ + uint8_t value[4]; /*< Value*/ +}) mavlink_gopro_set_request_t; + +#define MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN 7 +#define MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN 7 +#define MAVLINK_MSG_ID_218_LEN 7 +#define MAVLINK_MSG_ID_218_MIN_LEN 7 + +#define MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC 17 +#define MAVLINK_MSG_ID_218_CRC 17 + +#define MAVLINK_MSG_GOPRO_SET_REQUEST_FIELD_VALUE_LEN 4 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GOPRO_SET_REQUEST { \ + 218, \ + "GOPRO_SET_REQUEST", \ + 4, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_set_request_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_set_request_t, target_component) }, \ + { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gopro_set_request_t, cmd_id) }, \ + { "value", NULL, MAVLINK_TYPE_UINT8_T, 4, 3, offsetof(mavlink_gopro_set_request_t, value) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GOPRO_SET_REQUEST { \ + "GOPRO_SET_REQUEST", \ + 4, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_set_request_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_set_request_t, target_component) }, \ + { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gopro_set_request_t, cmd_id) }, \ + { "value", NULL, MAVLINK_TYPE_UINT8_T, 4, 3, offsetof(mavlink_gopro_set_request_t, value) }, \ + } \ +} +#endif + +/** + * @brief Pack a gopro_set_request message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID + * @param target_component Component ID + * @param cmd_id Command ID + * @param value Value + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_set_request_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, uint8_t target_component, uint8_t cmd_id, const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + _mav_put_uint8_t_array(buf, 3, value, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN); +#else + mavlink_gopro_set_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.cmd_id = cmd_id; + mav_array_memcpy(packet.value, value, sizeof(uint8_t)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_SET_REQUEST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC); +} + +/** + * @brief Pack a gopro_set_request message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID + * @param target_component Component ID + * @param cmd_id Command ID + * @param value Value + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_set_request_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t cmd_id,const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + _mav_put_uint8_t_array(buf, 3, value, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN); +#else + mavlink_gopro_set_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.cmd_id = cmd_id; + mav_array_memcpy(packet.value, value, sizeof(uint8_t)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_SET_REQUEST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC); +} + +/** + * @brief Encode a gopro_set_request struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gopro_set_request C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_set_request_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gopro_set_request_t* gopro_set_request) +{ + return mavlink_msg_gopro_set_request_pack(system_id, component_id, msg, gopro_set_request->target_system, gopro_set_request->target_component, gopro_set_request->cmd_id, gopro_set_request->value); +} + +/** + * @brief Encode a gopro_set_request struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gopro_set_request C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_set_request_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gopro_set_request_t* gopro_set_request) +{ + return mavlink_msg_gopro_set_request_pack_chan(system_id, component_id, chan, msg, gopro_set_request->target_system, gopro_set_request->target_component, gopro_set_request->cmd_id, gopro_set_request->value); +} + +/** + * @brief Send a gopro_set_request message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID + * @param target_component Component ID + * @param cmd_id Command ID + * @param value Value + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gopro_set_request_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t cmd_id, const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + _mav_put_uint8_t_array(buf, 3, value, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_REQUEST, buf, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC); +#else + mavlink_gopro_set_request_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.cmd_id = cmd_id; + mav_array_memcpy(packet.value, value, sizeof(uint8_t)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC); +#endif +} + +/** + * @brief Send a gopro_set_request message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gopro_set_request_send_struct(mavlink_channel_t chan, const mavlink_gopro_set_request_t* gopro_set_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gopro_set_request_send(chan, gopro_set_request->target_system, gopro_set_request->target_component, gopro_set_request->cmd_id, gopro_set_request->value); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_REQUEST, (const char *)gopro_set_request, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gopro_set_request_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t cmd_id, const uint8_t *value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, cmd_id); + _mav_put_uint8_t_array(buf, 3, value, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_REQUEST, buf, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC); +#else + mavlink_gopro_set_request_t *packet = (mavlink_gopro_set_request_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->cmd_id = cmd_id; + mav_array_memcpy(packet->value, value, sizeof(uint8_t)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_REQUEST, (const char *)packet, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GOPRO_SET_REQUEST UNPACKING + + +/** + * @brief Get field target_system from gopro_set_request message + * + * @return System ID + */ +static inline uint8_t mavlink_msg_gopro_set_request_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field target_component from gopro_set_request message + * + * @return Component ID + */ +static inline uint8_t mavlink_msg_gopro_set_request_get_target_component(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Get field cmd_id from gopro_set_request message + * + * @return Command ID + */ +static inline uint8_t mavlink_msg_gopro_set_request_get_cmd_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 2); +} + +/** + * @brief Get field value from gopro_set_request message + * + * @return Value + */ +static inline uint16_t mavlink_msg_gopro_set_request_get_value(const mavlink_message_t* msg, uint8_t *value) +{ + return _MAV_RETURN_uint8_t_array(msg, value, 4, 3); +} + +/** + * @brief Decode a gopro_set_request message into a struct + * + * @param msg The message to decode + * @param gopro_set_request C-struct to decode the message contents into + */ +static inline void mavlink_msg_gopro_set_request_decode(const mavlink_message_t* msg, mavlink_gopro_set_request_t* gopro_set_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gopro_set_request->target_system = mavlink_msg_gopro_set_request_get_target_system(msg); + gopro_set_request->target_component = mavlink_msg_gopro_set_request_get_target_component(msg); + gopro_set_request->cmd_id = mavlink_msg_gopro_set_request_get_cmd_id(msg); + mavlink_msg_gopro_set_request_get_value(msg, gopro_set_request->value); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN? msg->len : MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN; + memset(gopro_set_request, 0, MAVLINK_MSG_ID_GOPRO_SET_REQUEST_LEN); + memcpy(gopro_set_request, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_set_response.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_set_response.h new file mode 100644 index 0000000000..7dbb3f4dad --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_gopro_set_response.h @@ -0,0 +1,238 @@ +#pragma once +// MESSAGE GOPRO_SET_RESPONSE PACKING + +#define MAVLINK_MSG_ID_GOPRO_SET_RESPONSE 219 + +MAVPACKED( +typedef struct __mavlink_gopro_set_response_t { + uint8_t cmd_id; /*< Command ID*/ + uint8_t status; /*< Status*/ +}) mavlink_gopro_set_response_t; + +#define MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN 2 +#define MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN 2 +#define MAVLINK_MSG_ID_219_LEN 2 +#define MAVLINK_MSG_ID_219_MIN_LEN 2 + +#define MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC 162 +#define MAVLINK_MSG_ID_219_CRC 162 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GOPRO_SET_RESPONSE { \ + 219, \ + "GOPRO_SET_RESPONSE", \ + 2, \ + { { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_set_response_t, cmd_id) }, \ + { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_set_response_t, status) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GOPRO_SET_RESPONSE { \ + "GOPRO_SET_RESPONSE", \ + 2, \ + { { "cmd_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gopro_set_response_t, cmd_id) }, \ + { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gopro_set_response_t, status) }, \ + } \ +} +#endif + +/** + * @brief Pack a gopro_set_response message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param cmd_id Command ID + * @param status Status + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_set_response_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t cmd_id, uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN]; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN); +#else + mavlink_gopro_set_response_t packet; + packet.cmd_id = cmd_id; + packet.status = status; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_SET_RESPONSE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC); +} + +/** + * @brief Pack a gopro_set_response message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param cmd_id Command ID + * @param status Status + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gopro_set_response_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t cmd_id,uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN]; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN); +#else + mavlink_gopro_set_response_t packet; + packet.cmd_id = cmd_id; + packet.status = status; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GOPRO_SET_RESPONSE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC); +} + +/** + * @brief Encode a gopro_set_response struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gopro_set_response C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_set_response_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gopro_set_response_t* gopro_set_response) +{ + return mavlink_msg_gopro_set_response_pack(system_id, component_id, msg, gopro_set_response->cmd_id, gopro_set_response->status); +} + +/** + * @brief Encode a gopro_set_response struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gopro_set_response C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gopro_set_response_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gopro_set_response_t* gopro_set_response) +{ + return mavlink_msg_gopro_set_response_pack_chan(system_id, component_id, chan, msg, gopro_set_response->cmd_id, gopro_set_response->status); +} + +/** + * @brief Send a gopro_set_response message + * @param chan MAVLink channel to send the message + * + * @param cmd_id Command ID + * @param status Status + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gopro_set_response_send(mavlink_channel_t chan, uint8_t cmd_id, uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN]; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE, buf, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC); +#else + mavlink_gopro_set_response_t packet; + packet.cmd_id = cmd_id; + packet.status = status; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE, (const char *)&packet, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC); +#endif +} + +/** + * @brief Send a gopro_set_response message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gopro_set_response_send_struct(mavlink_channel_t chan, const mavlink_gopro_set_response_t* gopro_set_response) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gopro_set_response_send(chan, gopro_set_response->cmd_id, gopro_set_response->status); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE, (const char *)gopro_set_response, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gopro_set_response_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t cmd_id, uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, cmd_id); + _mav_put_uint8_t(buf, 1, status); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE, buf, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC); +#else + mavlink_gopro_set_response_t *packet = (mavlink_gopro_set_response_t *)msgbuf; + packet->cmd_id = cmd_id; + packet->status = status; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE, (const char *)packet, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GOPRO_SET_RESPONSE UNPACKING + + +/** + * @brief Get field cmd_id from gopro_set_response message + * + * @return Command ID + */ +static inline uint8_t mavlink_msg_gopro_set_response_get_cmd_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field status from gopro_set_response message + * + * @return Status + */ +static inline uint8_t mavlink_msg_gopro_set_response_get_status(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Decode a gopro_set_response message into a struct + * + * @param msg The message to decode + * @param gopro_set_response C-struct to decode the message contents into + */ +static inline void mavlink_msg_gopro_set_response_decode(const mavlink_message_t* msg, mavlink_gopro_set_response_t* gopro_set_response) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gopro_set_response->cmd_id = mavlink_msg_gopro_set_response_get_cmd_id(msg); + gopro_set_response->status = mavlink_msg_gopro_set_response_get_status(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN? msg->len : MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN; + memset(gopro_set_response, 0, MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_LEN); + memcpy(gopro_set_response, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_hwstatus.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_hwstatus.h index acf031f62d..40799bb163 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_hwstatus.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_hwstatus.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE HWSTATUS PACKING #define MAVLINK_MSG_ID_HWSTATUS 165 -typedef struct __mavlink_hwstatus_t -{ - uint16_t Vcc; ///< board voltage (mV) - uint8_t I2Cerr; ///< I2C error count -} mavlink_hwstatus_t; +MAVPACKED( +typedef struct __mavlink_hwstatus_t { + uint16_t Vcc; /*< board voltage (mV)*/ + uint8_t I2Cerr; /*< I2C error count*/ +}) mavlink_hwstatus_t; #define MAVLINK_MSG_ID_HWSTATUS_LEN 3 +#define MAVLINK_MSG_ID_HWSTATUS_MIN_LEN 3 #define MAVLINK_MSG_ID_165_LEN 3 +#define MAVLINK_MSG_ID_165_MIN_LEN 3 #define MAVLINK_MSG_ID_HWSTATUS_CRC 21 #define MAVLINK_MSG_ID_165_CRC 21 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HWSTATUS { \ - "HWSTATUS", \ - 2, \ - { { "Vcc", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_hwstatus_t, Vcc) }, \ + 165, \ + "HWSTATUS", \ + 2, \ + { { "Vcc", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_hwstatus_t, Vcc) }, \ { "I2Cerr", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_hwstatus_t, I2Cerr) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HWSTATUS { \ + "HWSTATUS", \ + 2, \ + { { "Vcc", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_hwstatus_t, Vcc) }, \ + { "I2Cerr", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_hwstatus_t, I2Cerr) }, \ + } \ +} +#endif /** * @brief Pack a hwstatus message @@ -36,28 +49,24 @@ typedef struct __mavlink_hwstatus_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hwstatus_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t Vcc, uint8_t I2Cerr) + uint16_t Vcc, uint8_t I2Cerr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HWSTATUS_LEN]; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint8_t(buf, 2, I2Cerr); + char buf[MAVLINK_MSG_ID_HWSTATUS_LEN]; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint8_t(buf, 2, I2Cerr); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HWSTATUS_LEN); #else - mavlink_hwstatus_t packet; - packet.Vcc = Vcc; - packet.I2Cerr = I2Cerr; + mavlink_hwstatus_t packet; + packet.Vcc = Vcc; + packet.I2Cerr = I2Cerr; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HWSTATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HWSTATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HWSTATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HWSTATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HWSTATUS_MIN_LEN, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_hwstatus_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hwstatus_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t Vcc,uint8_t I2Cerr) + mavlink_message_t* msg, + uint16_t Vcc,uint8_t I2Cerr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HWSTATUS_LEN]; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint8_t(buf, 2, I2Cerr); + char buf[MAVLINK_MSG_ID_HWSTATUS_LEN]; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint8_t(buf, 2, I2Cerr); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HWSTATUS_LEN); #else - mavlink_hwstatus_t packet; - packet.Vcc = Vcc; - packet.I2Cerr = I2Cerr; + mavlink_hwstatus_t packet; + packet.Vcc = Vcc; + packet.I2Cerr = I2Cerr; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HWSTATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HWSTATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HWSTATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HWSTATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HWSTATUS_MIN_LEN, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_hwstatus_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_hwstatus_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hwstatus_t* hwstatus) { - return mavlink_msg_hwstatus_pack(system_id, component_id, msg, hwstatus->Vcc, hwstatus->I2Cerr); + return mavlink_msg_hwstatus_pack(system_id, component_id, msg, hwstatus->Vcc, hwstatus->I2Cerr); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_hwstatus_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_hwstatus_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hwstatus_t* hwstatus) { - return mavlink_msg_hwstatus_pack_chan(system_id, component_id, chan, msg, hwstatus->Vcc, hwstatus->I2Cerr); + return mavlink_msg_hwstatus_pack_chan(system_id, component_id, chan, msg, hwstatus->Vcc, hwstatus->I2Cerr); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_hwstatus_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_hwstatus_send(mavlink_channel_t chan, uint16_t Vcc, uint8_t I2Cerr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HWSTATUS_LEN]; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint8_t(buf, 2, I2Cerr); + char buf[MAVLINK_MSG_ID_HWSTATUS_LEN]; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint8_t(buf, 2, I2Cerr); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, buf, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, buf, MAVLINK_MSG_ID_HWSTATUS_MIN_LEN, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, buf, MAVLINK_MSG_ID_HWSTATUS_LEN); + mavlink_hwstatus_t packet; + packet.Vcc = Vcc; + packet.I2Cerr = I2Cerr; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, (const char *)&packet, MAVLINK_MSG_ID_HWSTATUS_MIN_LEN, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); #endif -#else - mavlink_hwstatus_t packet; - packet.Vcc = Vcc; - packet.I2Cerr = I2Cerr; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, (const char *)&packet, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); +/** + * @brief Send a hwstatus message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hwstatus_send_struct(mavlink_channel_t chan, const mavlink_hwstatus_t* hwstatus) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hwstatus_send(chan, hwstatus->Vcc, hwstatus->I2Cerr); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, (const char *)&packet, MAVLINK_MSG_ID_HWSTATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, (const char *)hwstatus, MAVLINK_MSG_ID_HWSTATUS_MIN_LEN, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_hwstatus_send(mavlink_channel_t chan, uint16_t Vc static inline void mavlink_msg_hwstatus_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t Vcc, uint8_t I2Cerr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint8_t(buf, 2, I2Cerr); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint8_t(buf, 2, I2Cerr); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, buf, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, buf, MAVLINK_MSG_ID_HWSTATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, buf, MAVLINK_MSG_ID_HWSTATUS_MIN_LEN, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); #else - mavlink_hwstatus_t *packet = (mavlink_hwstatus_t *)msgbuf; - packet->Vcc = Vcc; - packet->I2Cerr = I2Cerr; + mavlink_hwstatus_t *packet = (mavlink_hwstatus_t *)msgbuf; + packet->Vcc = Vcc; + packet->I2Cerr = I2Cerr; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, (const char *)packet, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, (const char *)packet, MAVLINK_MSG_ID_HWSTATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HWSTATUS, (const char *)packet, MAVLINK_MSG_ID_HWSTATUS_MIN_LEN, MAVLINK_MSG_ID_HWSTATUS_LEN, MAVLINK_MSG_ID_HWSTATUS_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_hwstatus_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint16_t mavlink_msg_hwstatus_get_Vcc(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint16_t mavlink_msg_hwstatus_get_Vcc(const mavlink_message_t* msg */ static inline uint8_t mavlink_msg_hwstatus_get_I2Cerr(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_hwstatus_get_I2Cerr(const mavlink_message_t* m */ static inline void mavlink_msg_hwstatus_decode(const mavlink_message_t* msg, mavlink_hwstatus_t* hwstatus) { -#if MAVLINK_NEED_BYTE_SWAP - hwstatus->Vcc = mavlink_msg_hwstatus_get_Vcc(msg); - hwstatus->I2Cerr = mavlink_msg_hwstatus_get_I2Cerr(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hwstatus->Vcc = mavlink_msg_hwstatus_get_Vcc(msg); + hwstatus->I2Cerr = mavlink_msg_hwstatus_get_I2Cerr(msg); #else - memcpy(hwstatus, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HWSTATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HWSTATUS_LEN? msg->len : MAVLINK_MSG_ID_HWSTATUS_LEN; + memset(hwstatus, 0, MAVLINK_MSG_ID_HWSTATUS_LEN); + memcpy(hwstatus, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_led_control.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_led_control.h new file mode 100644 index 0000000000..49685e7768 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_led_control.h @@ -0,0 +1,330 @@ +#pragma once +// MESSAGE LED_CONTROL PACKING + +#define MAVLINK_MSG_ID_LED_CONTROL 186 + +MAVPACKED( +typedef struct __mavlink_led_control_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t instance; /*< Instance (LED instance to control or 255 for all LEDs)*/ + uint8_t pattern; /*< Pattern (see LED_PATTERN_ENUM)*/ + uint8_t custom_len; /*< Custom Byte Length*/ + uint8_t custom_bytes[24]; /*< Custom Bytes*/ +}) mavlink_led_control_t; + +#define MAVLINK_MSG_ID_LED_CONTROL_LEN 29 +#define MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN 29 +#define MAVLINK_MSG_ID_186_LEN 29 +#define MAVLINK_MSG_ID_186_MIN_LEN 29 + +#define MAVLINK_MSG_ID_LED_CONTROL_CRC 72 +#define MAVLINK_MSG_ID_186_CRC 72 + +#define MAVLINK_MSG_LED_CONTROL_FIELD_CUSTOM_BYTES_LEN 24 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_LED_CONTROL { \ + 186, \ + "LED_CONTROL", \ + 6, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_led_control_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_led_control_t, target_component) }, \ + { "instance", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_led_control_t, instance) }, \ + { "pattern", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_led_control_t, pattern) }, \ + { "custom_len", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_led_control_t, custom_len) }, \ + { "custom_bytes", NULL, MAVLINK_TYPE_UINT8_T, 24, 5, offsetof(mavlink_led_control_t, custom_bytes) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_LED_CONTROL { \ + "LED_CONTROL", \ + 6, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_led_control_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_led_control_t, target_component) }, \ + { "instance", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_led_control_t, instance) }, \ + { "pattern", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_led_control_t, pattern) }, \ + { "custom_len", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_led_control_t, custom_len) }, \ + { "custom_bytes", NULL, MAVLINK_TYPE_UINT8_T, 24, 5, offsetof(mavlink_led_control_t, custom_bytes) }, \ + } \ +} +#endif + +/** + * @brief Pack a led_control message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID + * @param target_component Component ID + * @param instance Instance (LED instance to control or 255 for all LEDs) + * @param pattern Pattern (see LED_PATTERN_ENUM) + * @param custom_len Custom Byte Length + * @param custom_bytes Custom Bytes + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_led_control_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, uint8_t target_component, uint8_t instance, uint8_t pattern, uint8_t custom_len, const uint8_t *custom_bytes) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_LED_CONTROL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, instance); + _mav_put_uint8_t(buf, 3, pattern); + _mav_put_uint8_t(buf, 4, custom_len); + _mav_put_uint8_t_array(buf, 5, custom_bytes, 24); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LED_CONTROL_LEN); +#else + mavlink_led_control_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.instance = instance; + packet.pattern = pattern; + packet.custom_len = custom_len; + mav_array_memcpy(packet.custom_bytes, custom_bytes, sizeof(uint8_t)*24); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LED_CONTROL_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_LED_CONTROL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN, MAVLINK_MSG_ID_LED_CONTROL_LEN, MAVLINK_MSG_ID_LED_CONTROL_CRC); +} + +/** + * @brief Pack a led_control message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID + * @param target_component Component ID + * @param instance Instance (LED instance to control or 255 for all LEDs) + * @param pattern Pattern (see LED_PATTERN_ENUM) + * @param custom_len Custom Byte Length + * @param custom_bytes Custom Bytes + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_led_control_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t instance,uint8_t pattern,uint8_t custom_len,const uint8_t *custom_bytes) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_LED_CONTROL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, instance); + _mav_put_uint8_t(buf, 3, pattern); + _mav_put_uint8_t(buf, 4, custom_len); + _mav_put_uint8_t_array(buf, 5, custom_bytes, 24); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LED_CONTROL_LEN); +#else + mavlink_led_control_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.instance = instance; + packet.pattern = pattern; + packet.custom_len = custom_len; + mav_array_memcpy(packet.custom_bytes, custom_bytes, sizeof(uint8_t)*24); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LED_CONTROL_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_LED_CONTROL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN, MAVLINK_MSG_ID_LED_CONTROL_LEN, MAVLINK_MSG_ID_LED_CONTROL_CRC); +} + +/** + * @brief Encode a led_control struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param led_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_led_control_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_led_control_t* led_control) +{ + return mavlink_msg_led_control_pack(system_id, component_id, msg, led_control->target_system, led_control->target_component, led_control->instance, led_control->pattern, led_control->custom_len, led_control->custom_bytes); +} + +/** + * @brief Encode a led_control struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param led_control C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_led_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_led_control_t* led_control) +{ + return mavlink_msg_led_control_pack_chan(system_id, component_id, chan, msg, led_control->target_system, led_control->target_component, led_control->instance, led_control->pattern, led_control->custom_len, led_control->custom_bytes); +} + +/** + * @brief Send a led_control message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID + * @param target_component Component ID + * @param instance Instance (LED instance to control or 255 for all LEDs) + * @param pattern Pattern (see LED_PATTERN_ENUM) + * @param custom_len Custom Byte Length + * @param custom_bytes Custom Bytes + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_led_control_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t instance, uint8_t pattern, uint8_t custom_len, const uint8_t *custom_bytes) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_LED_CONTROL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, instance); + _mav_put_uint8_t(buf, 3, pattern); + _mav_put_uint8_t(buf, 4, custom_len); + _mav_put_uint8_t_array(buf, 5, custom_bytes, 24); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LED_CONTROL, buf, MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN, MAVLINK_MSG_ID_LED_CONTROL_LEN, MAVLINK_MSG_ID_LED_CONTROL_CRC); +#else + mavlink_led_control_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.instance = instance; + packet.pattern = pattern; + packet.custom_len = custom_len; + mav_array_memcpy(packet.custom_bytes, custom_bytes, sizeof(uint8_t)*24); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LED_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN, MAVLINK_MSG_ID_LED_CONTROL_LEN, MAVLINK_MSG_ID_LED_CONTROL_CRC); +#endif +} + +/** + * @brief Send a led_control message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_led_control_send_struct(mavlink_channel_t chan, const mavlink_led_control_t* led_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_led_control_send(chan, led_control->target_system, led_control->target_component, led_control->instance, led_control->pattern, led_control->custom_len, led_control->custom_bytes); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LED_CONTROL, (const char *)led_control, MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN, MAVLINK_MSG_ID_LED_CONTROL_LEN, MAVLINK_MSG_ID_LED_CONTROL_CRC); +#endif +} + +#if MAVLINK_MSG_ID_LED_CONTROL_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_led_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t instance, uint8_t pattern, uint8_t custom_len, const uint8_t *custom_bytes) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, instance); + _mav_put_uint8_t(buf, 3, pattern); + _mav_put_uint8_t(buf, 4, custom_len); + _mav_put_uint8_t_array(buf, 5, custom_bytes, 24); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LED_CONTROL, buf, MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN, MAVLINK_MSG_ID_LED_CONTROL_LEN, MAVLINK_MSG_ID_LED_CONTROL_CRC); +#else + mavlink_led_control_t *packet = (mavlink_led_control_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->instance = instance; + packet->pattern = pattern; + packet->custom_len = custom_len; + mav_array_memcpy(packet->custom_bytes, custom_bytes, sizeof(uint8_t)*24); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LED_CONTROL, (const char *)packet, MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN, MAVLINK_MSG_ID_LED_CONTROL_LEN, MAVLINK_MSG_ID_LED_CONTROL_CRC); +#endif +} +#endif + +#endif + +// MESSAGE LED_CONTROL UNPACKING + + +/** + * @brief Get field target_system from led_control message + * + * @return System ID + */ +static inline uint8_t mavlink_msg_led_control_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field target_component from led_control message + * + * @return Component ID + */ +static inline uint8_t mavlink_msg_led_control_get_target_component(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Get field instance from led_control message + * + * @return Instance (LED instance to control or 255 for all LEDs) + */ +static inline uint8_t mavlink_msg_led_control_get_instance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 2); +} + +/** + * @brief Get field pattern from led_control message + * + * @return Pattern (see LED_PATTERN_ENUM) + */ +static inline uint8_t mavlink_msg_led_control_get_pattern(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 3); +} + +/** + * @brief Get field custom_len from led_control message + * + * @return Custom Byte Length + */ +static inline uint8_t mavlink_msg_led_control_get_custom_len(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 4); +} + +/** + * @brief Get field custom_bytes from led_control message + * + * @return Custom Bytes + */ +static inline uint16_t mavlink_msg_led_control_get_custom_bytes(const mavlink_message_t* msg, uint8_t *custom_bytes) +{ + return _MAV_RETURN_uint8_t_array(msg, custom_bytes, 24, 5); +} + +/** + * @brief Decode a led_control message into a struct + * + * @param msg The message to decode + * @param led_control C-struct to decode the message contents into + */ +static inline void mavlink_msg_led_control_decode(const mavlink_message_t* msg, mavlink_led_control_t* led_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + led_control->target_system = mavlink_msg_led_control_get_target_system(msg); + led_control->target_component = mavlink_msg_led_control_get_target_component(msg); + led_control->instance = mavlink_msg_led_control_get_instance(msg); + led_control->pattern = mavlink_msg_led_control_get_pattern(msg); + led_control->custom_len = mavlink_msg_led_control_get_custom_len(msg); + mavlink_msg_led_control_get_custom_bytes(msg, led_control->custom_bytes); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_LED_CONTROL_LEN? msg->len : MAVLINK_MSG_ID_LED_CONTROL_LEN; + memset(led_control, 0, MAVLINK_MSG_ID_LED_CONTROL_LEN); + memcpy(led_control, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_limits_status.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_limits_status.h index 5fef937181..9d3c6da65b 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_limits_status.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_limits_status.h @@ -1,32 +1,37 @@ +#pragma once // MESSAGE LIMITS_STATUS PACKING #define MAVLINK_MSG_ID_LIMITS_STATUS 167 -typedef struct __mavlink_limits_status_t -{ - uint32_t last_trigger; ///< time of last breach in milliseconds since boot - uint32_t last_action; ///< time of last recovery action in milliseconds since boot - uint32_t last_recovery; ///< time of last successful recovery in milliseconds since boot - uint32_t last_clear; ///< time of last all-clear in milliseconds since boot - uint16_t breach_count; ///< number of fence breaches - uint8_t limits_state; ///< state of AP_Limits, (see enum LimitState, LIMITS_STATE) - uint8_t mods_enabled; ///< AP_Limit_Module bitfield of enabled modules, (see enum moduleid or LIMIT_MODULE) - uint8_t mods_required; ///< AP_Limit_Module bitfield of required modules, (see enum moduleid or LIMIT_MODULE) - uint8_t mods_triggered; ///< AP_Limit_Module bitfield of triggered modules, (see enum moduleid or LIMIT_MODULE) -} mavlink_limits_status_t; +MAVPACKED( +typedef struct __mavlink_limits_status_t { + uint32_t last_trigger; /*< time of last breach in milliseconds since boot*/ + uint32_t last_action; /*< time of last recovery action in milliseconds since boot*/ + uint32_t last_recovery; /*< time of last successful recovery in milliseconds since boot*/ + uint32_t last_clear; /*< time of last all-clear in milliseconds since boot*/ + uint16_t breach_count; /*< number of fence breaches*/ + uint8_t limits_state; /*< state of AP_Limits, (see enum LimitState, LIMITS_STATE)*/ + uint8_t mods_enabled; /*< AP_Limit_Module bitfield of enabled modules, (see enum moduleid or LIMIT_MODULE)*/ + uint8_t mods_required; /*< AP_Limit_Module bitfield of required modules, (see enum moduleid or LIMIT_MODULE)*/ + uint8_t mods_triggered; /*< AP_Limit_Module bitfield of triggered modules, (see enum moduleid or LIMIT_MODULE)*/ +}) mavlink_limits_status_t; #define MAVLINK_MSG_ID_LIMITS_STATUS_LEN 22 +#define MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN 22 #define MAVLINK_MSG_ID_167_LEN 22 +#define MAVLINK_MSG_ID_167_MIN_LEN 22 #define MAVLINK_MSG_ID_LIMITS_STATUS_CRC 144 #define MAVLINK_MSG_ID_167_CRC 144 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LIMITS_STATUS { \ - "LIMITS_STATUS", \ - 9, \ - { { "last_trigger", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_limits_status_t, last_trigger) }, \ + 167, \ + "LIMITS_STATUS", \ + 9, \ + { { "last_trigger", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_limits_status_t, last_trigger) }, \ { "last_action", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_limits_status_t, last_action) }, \ { "last_recovery", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_limits_status_t, last_recovery) }, \ { "last_clear", NULL, MAVLINK_TYPE_UINT32_T, 0, 12, offsetof(mavlink_limits_status_t, last_clear) }, \ @@ -37,7 +42,22 @@ typedef struct __mavlink_limits_status_t { "mods_triggered", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_limits_status_t, mods_triggered) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LIMITS_STATUS { \ + "LIMITS_STATUS", \ + 9, \ + { { "last_trigger", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_limits_status_t, last_trigger) }, \ + { "last_action", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_limits_status_t, last_action) }, \ + { "last_recovery", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_limits_status_t, last_recovery) }, \ + { "last_clear", NULL, MAVLINK_TYPE_UINT32_T, 0, 12, offsetof(mavlink_limits_status_t, last_clear) }, \ + { "breach_count", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_limits_status_t, breach_count) }, \ + { "limits_state", NULL, MAVLINK_TYPE_UINT8_T, 0, 18, offsetof(mavlink_limits_status_t, limits_state) }, \ + { "mods_enabled", NULL, MAVLINK_TYPE_UINT8_T, 0, 19, offsetof(mavlink_limits_status_t, mods_enabled) }, \ + { "mods_required", NULL, MAVLINK_TYPE_UINT8_T, 0, 20, offsetof(mavlink_limits_status_t, mods_required) }, \ + { "mods_triggered", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_limits_status_t, mods_triggered) }, \ + } \ +} +#endif /** * @brief Pack a limits_status message @@ -57,42 +77,38 @@ typedef struct __mavlink_limits_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_limits_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t limits_state, uint32_t last_trigger, uint32_t last_action, uint32_t last_recovery, uint32_t last_clear, uint16_t breach_count, uint8_t mods_enabled, uint8_t mods_required, uint8_t mods_triggered) + uint8_t limits_state, uint32_t last_trigger, uint32_t last_action, uint32_t last_recovery, uint32_t last_clear, uint16_t breach_count, uint8_t mods_enabled, uint8_t mods_required, uint8_t mods_triggered) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LIMITS_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, last_trigger); - _mav_put_uint32_t(buf, 4, last_action); - _mav_put_uint32_t(buf, 8, last_recovery); - _mav_put_uint32_t(buf, 12, last_clear); - _mav_put_uint16_t(buf, 16, breach_count); - _mav_put_uint8_t(buf, 18, limits_state); - _mav_put_uint8_t(buf, 19, mods_enabled); - _mav_put_uint8_t(buf, 20, mods_required); - _mav_put_uint8_t(buf, 21, mods_triggered); + char buf[MAVLINK_MSG_ID_LIMITS_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, last_trigger); + _mav_put_uint32_t(buf, 4, last_action); + _mav_put_uint32_t(buf, 8, last_recovery); + _mav_put_uint32_t(buf, 12, last_clear); + _mav_put_uint16_t(buf, 16, breach_count); + _mav_put_uint8_t(buf, 18, limits_state); + _mav_put_uint8_t(buf, 19, mods_enabled); + _mav_put_uint8_t(buf, 20, mods_required); + _mav_put_uint8_t(buf, 21, mods_triggered); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); #else - mavlink_limits_status_t packet; - packet.last_trigger = last_trigger; - packet.last_action = last_action; - packet.last_recovery = last_recovery; - packet.last_clear = last_clear; - packet.breach_count = breach_count; - packet.limits_state = limits_state; - packet.mods_enabled = mods_enabled; - packet.mods_required = mods_required; - packet.mods_triggered = mods_triggered; + mavlink_limits_status_t packet; + packet.last_trigger = last_trigger; + packet.last_action = last_action; + packet.last_recovery = last_recovery; + packet.last_clear = last_clear; + packet.breach_count = breach_count; + packet.limits_state = limits_state; + packet.mods_enabled = mods_enabled; + packet.mods_required = mods_required; + packet.mods_triggered = mods_triggered; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LIMITS_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LIMITS_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); } /** @@ -113,43 +129,39 @@ static inline uint16_t mavlink_msg_limits_status_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_limits_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t limits_state,uint32_t last_trigger,uint32_t last_action,uint32_t last_recovery,uint32_t last_clear,uint16_t breach_count,uint8_t mods_enabled,uint8_t mods_required,uint8_t mods_triggered) + mavlink_message_t* msg, + uint8_t limits_state,uint32_t last_trigger,uint32_t last_action,uint32_t last_recovery,uint32_t last_clear,uint16_t breach_count,uint8_t mods_enabled,uint8_t mods_required,uint8_t mods_triggered) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LIMITS_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, last_trigger); - _mav_put_uint32_t(buf, 4, last_action); - _mav_put_uint32_t(buf, 8, last_recovery); - _mav_put_uint32_t(buf, 12, last_clear); - _mav_put_uint16_t(buf, 16, breach_count); - _mav_put_uint8_t(buf, 18, limits_state); - _mav_put_uint8_t(buf, 19, mods_enabled); - _mav_put_uint8_t(buf, 20, mods_required); - _mav_put_uint8_t(buf, 21, mods_triggered); + char buf[MAVLINK_MSG_ID_LIMITS_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, last_trigger); + _mav_put_uint32_t(buf, 4, last_action); + _mav_put_uint32_t(buf, 8, last_recovery); + _mav_put_uint32_t(buf, 12, last_clear); + _mav_put_uint16_t(buf, 16, breach_count); + _mav_put_uint8_t(buf, 18, limits_state); + _mav_put_uint8_t(buf, 19, mods_enabled); + _mav_put_uint8_t(buf, 20, mods_required); + _mav_put_uint8_t(buf, 21, mods_triggered); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); #else - mavlink_limits_status_t packet; - packet.last_trigger = last_trigger; - packet.last_action = last_action; - packet.last_recovery = last_recovery; - packet.last_clear = last_clear; - packet.breach_count = breach_count; - packet.limits_state = limits_state; - packet.mods_enabled = mods_enabled; - packet.mods_required = mods_required; - packet.mods_triggered = mods_triggered; + mavlink_limits_status_t packet; + packet.last_trigger = last_trigger; + packet.last_action = last_action; + packet.last_recovery = last_recovery; + packet.last_clear = last_clear; + packet.breach_count = breach_count; + packet.limits_state = limits_state; + packet.mods_enabled = mods_enabled; + packet.mods_required = mods_required; + packet.mods_triggered = mods_triggered; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LIMITS_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LIMITS_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); } /** @@ -162,7 +174,7 @@ static inline uint16_t mavlink_msg_limits_status_pack_chan(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_limits_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_limits_status_t* limits_status) { - return mavlink_msg_limits_status_pack(system_id, component_id, msg, limits_status->limits_state, limits_status->last_trigger, limits_status->last_action, limits_status->last_recovery, limits_status->last_clear, limits_status->breach_count, limits_status->mods_enabled, limits_status->mods_required, limits_status->mods_triggered); + return mavlink_msg_limits_status_pack(system_id, component_id, msg, limits_status->limits_state, limits_status->last_trigger, limits_status->last_action, limits_status->last_recovery, limits_status->last_clear, limits_status->breach_count, limits_status->mods_enabled, limits_status->mods_required, limits_status->mods_triggered); } /** @@ -176,7 +188,7 @@ static inline uint16_t mavlink_msg_limits_status_encode(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_limits_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_limits_status_t* limits_status) { - return mavlink_msg_limits_status_pack_chan(system_id, component_id, chan, msg, limits_status->limits_state, limits_status->last_trigger, limits_status->last_action, limits_status->last_recovery, limits_status->last_clear, limits_status->breach_count, limits_status->mods_enabled, limits_status->mods_required, limits_status->mods_triggered); + return mavlink_msg_limits_status_pack_chan(system_id, component_id, chan, msg, limits_status->limits_state, limits_status->last_trigger, limits_status->last_action, limits_status->last_recovery, limits_status->last_clear, limits_status->breach_count, limits_status->mods_enabled, limits_status->mods_required, limits_status->mods_triggered); } /** @@ -198,39 +210,45 @@ static inline uint16_t mavlink_msg_limits_status_encode_chan(uint8_t system_id, static inline void mavlink_msg_limits_status_send(mavlink_channel_t chan, uint8_t limits_state, uint32_t last_trigger, uint32_t last_action, uint32_t last_recovery, uint32_t last_clear, uint16_t breach_count, uint8_t mods_enabled, uint8_t mods_required, uint8_t mods_triggered) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LIMITS_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, last_trigger); - _mav_put_uint32_t(buf, 4, last_action); - _mav_put_uint32_t(buf, 8, last_recovery); - _mav_put_uint32_t(buf, 12, last_clear); - _mav_put_uint16_t(buf, 16, breach_count); - _mav_put_uint8_t(buf, 18, limits_state); - _mav_put_uint8_t(buf, 19, mods_enabled); - _mav_put_uint8_t(buf, 20, mods_required); - _mav_put_uint8_t(buf, 21, mods_triggered); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, buf, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); + char buf[MAVLINK_MSG_ID_LIMITS_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, last_trigger); + _mav_put_uint32_t(buf, 4, last_action); + _mav_put_uint32_t(buf, 8, last_recovery); + _mav_put_uint32_t(buf, 12, last_clear); + _mav_put_uint16_t(buf, 16, breach_count); + _mav_put_uint8_t(buf, 18, limits_state); + _mav_put_uint8_t(buf, 19, mods_enabled); + _mav_put_uint8_t(buf, 20, mods_required); + _mav_put_uint8_t(buf, 21, mods_triggered); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, buf, MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, buf, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); + mavlink_limits_status_t packet; + packet.last_trigger = last_trigger; + packet.last_action = last_action; + packet.last_recovery = last_recovery; + packet.last_clear = last_clear; + packet.breach_count = breach_count; + packet.limits_state = limits_state; + packet.mods_enabled = mods_enabled; + packet.mods_required = mods_required; + packet.mods_triggered = mods_triggered; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); #endif +} + +/** + * @brief Send a limits_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_limits_status_send_struct(mavlink_channel_t chan, const mavlink_limits_status_t* limits_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_limits_status_send(chan, limits_status->limits_state, limits_status->last_trigger, limits_status->last_action, limits_status->last_recovery, limits_status->last_clear, limits_status->breach_count, limits_status->mods_enabled, limits_status->mods_required, limits_status->mods_triggered); #else - mavlink_limits_status_t packet; - packet.last_trigger = last_trigger; - packet.last_action = last_action; - packet.last_recovery = last_recovery; - packet.last_clear = last_clear; - packet.breach_count = breach_count; - packet.limits_state = limits_state; - packet.mods_enabled = mods_enabled; - packet.mods_required = mods_required; - packet.mods_triggered = mods_triggered; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, (const char *)limits_status, MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); #endif } @@ -245,39 +263,31 @@ static inline void mavlink_msg_limits_status_send(mavlink_channel_t chan, uint8_ static inline void mavlink_msg_limits_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t limits_state, uint32_t last_trigger, uint32_t last_action, uint32_t last_recovery, uint32_t last_clear, uint16_t breach_count, uint8_t mods_enabled, uint8_t mods_required, uint8_t mods_triggered) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, last_trigger); - _mav_put_uint32_t(buf, 4, last_action); - _mav_put_uint32_t(buf, 8, last_recovery); - _mav_put_uint32_t(buf, 12, last_clear); - _mav_put_uint16_t(buf, 16, breach_count); - _mav_put_uint8_t(buf, 18, limits_state); - _mav_put_uint8_t(buf, 19, mods_enabled); - _mav_put_uint8_t(buf, 20, mods_required); - _mav_put_uint8_t(buf, 21, mods_triggered); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, buf, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, buf, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); -#endif -#else - mavlink_limits_status_t *packet = (mavlink_limits_status_t *)msgbuf; - packet->last_trigger = last_trigger; - packet->last_action = last_action; - packet->last_recovery = last_recovery; - packet->last_clear = last_clear; - packet->breach_count = breach_count; - packet->limits_state = limits_state; - packet->mods_enabled = mods_enabled; - packet->mods_required = mods_required; - packet->mods_triggered = mods_triggered; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, (const char *)packet, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, last_trigger); + _mav_put_uint32_t(buf, 4, last_action); + _mav_put_uint32_t(buf, 8, last_recovery); + _mav_put_uint32_t(buf, 12, last_clear); + _mav_put_uint16_t(buf, 16, breach_count); + _mav_put_uint8_t(buf, 18, limits_state); + _mav_put_uint8_t(buf, 19, mods_enabled); + _mav_put_uint8_t(buf, 20, mods_required); + _mav_put_uint8_t(buf, 21, mods_triggered); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, buf, MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, (const char *)packet, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); -#endif + mavlink_limits_status_t *packet = (mavlink_limits_status_t *)msgbuf; + packet->last_trigger = last_trigger; + packet->last_action = last_action; + packet->last_recovery = last_recovery; + packet->last_clear = last_clear; + packet->breach_count = breach_count; + packet->limits_state = limits_state; + packet->mods_enabled = mods_enabled; + packet->mods_required = mods_required; + packet->mods_triggered = mods_triggered; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LIMITS_STATUS, (const char *)packet, MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_LEN, MAVLINK_MSG_ID_LIMITS_STATUS_CRC); #endif } #endif @@ -294,7 +304,7 @@ static inline void mavlink_msg_limits_status_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_limits_status_get_limits_state(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 18); + return _MAV_RETURN_uint8_t(msg, 18); } /** @@ -304,7 +314,7 @@ static inline uint8_t mavlink_msg_limits_status_get_limits_state(const mavlink_m */ static inline uint32_t mavlink_msg_limits_status_get_last_trigger(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -314,7 +324,7 @@ static inline uint32_t mavlink_msg_limits_status_get_last_trigger(const mavlink_ */ static inline uint32_t mavlink_msg_limits_status_get_last_action(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 4); + return _MAV_RETURN_uint32_t(msg, 4); } /** @@ -324,7 +334,7 @@ static inline uint32_t mavlink_msg_limits_status_get_last_action(const mavlink_m */ static inline uint32_t mavlink_msg_limits_status_get_last_recovery(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 8); + return _MAV_RETURN_uint32_t(msg, 8); } /** @@ -334,7 +344,7 @@ static inline uint32_t mavlink_msg_limits_status_get_last_recovery(const mavlink */ static inline uint32_t mavlink_msg_limits_status_get_last_clear(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 12); + return _MAV_RETURN_uint32_t(msg, 12); } /** @@ -344,7 +354,7 @@ static inline uint32_t mavlink_msg_limits_status_get_last_clear(const mavlink_me */ static inline uint16_t mavlink_msg_limits_status_get_breach_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** @@ -354,7 +364,7 @@ static inline uint16_t mavlink_msg_limits_status_get_breach_count(const mavlink_ */ static inline uint8_t mavlink_msg_limits_status_get_mods_enabled(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 19); + return _MAV_RETURN_uint8_t(msg, 19); } /** @@ -364,7 +374,7 @@ static inline uint8_t mavlink_msg_limits_status_get_mods_enabled(const mavlink_m */ static inline uint8_t mavlink_msg_limits_status_get_mods_required(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 20); + return _MAV_RETURN_uint8_t(msg, 20); } /** @@ -374,7 +384,7 @@ static inline uint8_t mavlink_msg_limits_status_get_mods_required(const mavlink_ */ static inline uint8_t mavlink_msg_limits_status_get_mods_triggered(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 21); + return _MAV_RETURN_uint8_t(msg, 21); } /** @@ -385,17 +395,19 @@ static inline uint8_t mavlink_msg_limits_status_get_mods_triggered(const mavlink */ static inline void mavlink_msg_limits_status_decode(const mavlink_message_t* msg, mavlink_limits_status_t* limits_status) { -#if MAVLINK_NEED_BYTE_SWAP - limits_status->last_trigger = mavlink_msg_limits_status_get_last_trigger(msg); - limits_status->last_action = mavlink_msg_limits_status_get_last_action(msg); - limits_status->last_recovery = mavlink_msg_limits_status_get_last_recovery(msg); - limits_status->last_clear = mavlink_msg_limits_status_get_last_clear(msg); - limits_status->breach_count = mavlink_msg_limits_status_get_breach_count(msg); - limits_status->limits_state = mavlink_msg_limits_status_get_limits_state(msg); - limits_status->mods_enabled = mavlink_msg_limits_status_get_mods_enabled(msg); - limits_status->mods_required = mavlink_msg_limits_status_get_mods_required(msg); - limits_status->mods_triggered = mavlink_msg_limits_status_get_mods_triggered(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + limits_status->last_trigger = mavlink_msg_limits_status_get_last_trigger(msg); + limits_status->last_action = mavlink_msg_limits_status_get_last_action(msg); + limits_status->last_recovery = mavlink_msg_limits_status_get_last_recovery(msg); + limits_status->last_clear = mavlink_msg_limits_status_get_last_clear(msg); + limits_status->breach_count = mavlink_msg_limits_status_get_breach_count(msg); + limits_status->limits_state = mavlink_msg_limits_status_get_limits_state(msg); + limits_status->mods_enabled = mavlink_msg_limits_status_get_mods_enabled(msg); + limits_status->mods_required = mavlink_msg_limits_status_get_mods_required(msg); + limits_status->mods_triggered = mavlink_msg_limits_status_get_mods_triggered(msg); #else - memcpy(limits_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LIMITS_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LIMITS_STATUS_LEN? msg->len : MAVLINK_MSG_ID_LIMITS_STATUS_LEN; + memset(limits_status, 0, MAVLINK_MSG_ID_LIMITS_STATUS_LEN); + memcpy(limits_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mag_cal_progress.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mag_cal_progress.h new file mode 100644 index 0000000000..383037a5fc --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mag_cal_progress.h @@ -0,0 +1,405 @@ +#pragma once +// MESSAGE MAG_CAL_PROGRESS PACKING + +#define MAVLINK_MSG_ID_MAG_CAL_PROGRESS 191 + +MAVPACKED( +typedef struct __mavlink_mag_cal_progress_t { + float direction_x; /*< Body frame direction vector for display*/ + float direction_y; /*< Body frame direction vector for display*/ + float direction_z; /*< Body frame direction vector for display*/ + uint8_t compass_id; /*< Compass being calibrated*/ + uint8_t cal_mask; /*< Bitmask of compasses being calibrated*/ + uint8_t cal_status; /*< Status (see MAG_CAL_STATUS enum)*/ + uint8_t attempt; /*< Attempt number*/ + uint8_t completion_pct; /*< Completion percentage*/ + uint8_t completion_mask[10]; /*< Bitmask of sphere sections (see http://en.wikipedia.org/wiki/Geodesic_grid)*/ +}) mavlink_mag_cal_progress_t; + +#define MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN 27 +#define MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN 27 +#define MAVLINK_MSG_ID_191_LEN 27 +#define MAVLINK_MSG_ID_191_MIN_LEN 27 + +#define MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC 92 +#define MAVLINK_MSG_ID_191_CRC 92 + +#define MAVLINK_MSG_MAG_CAL_PROGRESS_FIELD_COMPLETION_MASK_LEN 10 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_MAG_CAL_PROGRESS { \ + 191, \ + "MAG_CAL_PROGRESS", \ + 9, \ + { { "direction_x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mag_cal_progress_t, direction_x) }, \ + { "direction_y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mag_cal_progress_t, direction_y) }, \ + { "direction_z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mag_cal_progress_t, direction_z) }, \ + { "compass_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_mag_cal_progress_t, compass_id) }, \ + { "cal_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_mag_cal_progress_t, cal_mask) }, \ + { "cal_status", NULL, MAVLINK_TYPE_UINT8_T, 0, 14, offsetof(mavlink_mag_cal_progress_t, cal_status) }, \ + { "attempt", NULL, MAVLINK_TYPE_UINT8_T, 0, 15, offsetof(mavlink_mag_cal_progress_t, attempt) }, \ + { "completion_pct", NULL, MAVLINK_TYPE_UINT8_T, 0, 16, offsetof(mavlink_mag_cal_progress_t, completion_pct) }, \ + { "completion_mask", NULL, MAVLINK_TYPE_UINT8_T, 10, 17, offsetof(mavlink_mag_cal_progress_t, completion_mask) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_MAG_CAL_PROGRESS { \ + "MAG_CAL_PROGRESS", \ + 9, \ + { { "direction_x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mag_cal_progress_t, direction_x) }, \ + { "direction_y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mag_cal_progress_t, direction_y) }, \ + { "direction_z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mag_cal_progress_t, direction_z) }, \ + { "compass_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_mag_cal_progress_t, compass_id) }, \ + { "cal_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_mag_cal_progress_t, cal_mask) }, \ + { "cal_status", NULL, MAVLINK_TYPE_UINT8_T, 0, 14, offsetof(mavlink_mag_cal_progress_t, cal_status) }, \ + { "attempt", NULL, MAVLINK_TYPE_UINT8_T, 0, 15, offsetof(mavlink_mag_cal_progress_t, attempt) }, \ + { "completion_pct", NULL, MAVLINK_TYPE_UINT8_T, 0, 16, offsetof(mavlink_mag_cal_progress_t, completion_pct) }, \ + { "completion_mask", NULL, MAVLINK_TYPE_UINT8_T, 10, 17, offsetof(mavlink_mag_cal_progress_t, completion_mask) }, \ + } \ +} +#endif + +/** + * @brief Pack a mag_cal_progress message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param compass_id Compass being calibrated + * @param cal_mask Bitmask of compasses being calibrated + * @param cal_status Status (see MAG_CAL_STATUS enum) + * @param attempt Attempt number + * @param completion_pct Completion percentage + * @param completion_mask Bitmask of sphere sections (see http://en.wikipedia.org/wiki/Geodesic_grid) + * @param direction_x Body frame direction vector for display + * @param direction_y Body frame direction vector for display + * @param direction_z Body frame direction vector for display + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_mag_cal_progress_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t compass_id, uint8_t cal_mask, uint8_t cal_status, uint8_t attempt, uint8_t completion_pct, const uint8_t *completion_mask, float direction_x, float direction_y, float direction_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN]; + _mav_put_float(buf, 0, direction_x); + _mav_put_float(buf, 4, direction_y); + _mav_put_float(buf, 8, direction_z); + _mav_put_uint8_t(buf, 12, compass_id); + _mav_put_uint8_t(buf, 13, cal_mask); + _mav_put_uint8_t(buf, 14, cal_status); + _mav_put_uint8_t(buf, 15, attempt); + _mav_put_uint8_t(buf, 16, completion_pct); + _mav_put_uint8_t_array(buf, 17, completion_mask, 10); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN); +#else + mavlink_mag_cal_progress_t packet; + packet.direction_x = direction_x; + packet.direction_y = direction_y; + packet.direction_z = direction_z; + packet.compass_id = compass_id; + packet.cal_mask = cal_mask; + packet.cal_status = cal_status; + packet.attempt = attempt; + packet.completion_pct = completion_pct; + mav_array_memcpy(packet.completion_mask, completion_mask, sizeof(uint8_t)*10); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MAG_CAL_PROGRESS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC); +} + +/** + * @brief Pack a mag_cal_progress message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param compass_id Compass being calibrated + * @param cal_mask Bitmask of compasses being calibrated + * @param cal_status Status (see MAG_CAL_STATUS enum) + * @param attempt Attempt number + * @param completion_pct Completion percentage + * @param completion_mask Bitmask of sphere sections (see http://en.wikipedia.org/wiki/Geodesic_grid) + * @param direction_x Body frame direction vector for display + * @param direction_y Body frame direction vector for display + * @param direction_z Body frame direction vector for display + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_mag_cal_progress_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t compass_id,uint8_t cal_mask,uint8_t cal_status,uint8_t attempt,uint8_t completion_pct,const uint8_t *completion_mask,float direction_x,float direction_y,float direction_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN]; + _mav_put_float(buf, 0, direction_x); + _mav_put_float(buf, 4, direction_y); + _mav_put_float(buf, 8, direction_z); + _mav_put_uint8_t(buf, 12, compass_id); + _mav_put_uint8_t(buf, 13, cal_mask); + _mav_put_uint8_t(buf, 14, cal_status); + _mav_put_uint8_t(buf, 15, attempt); + _mav_put_uint8_t(buf, 16, completion_pct); + _mav_put_uint8_t_array(buf, 17, completion_mask, 10); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN); +#else + mavlink_mag_cal_progress_t packet; + packet.direction_x = direction_x; + packet.direction_y = direction_y; + packet.direction_z = direction_z; + packet.compass_id = compass_id; + packet.cal_mask = cal_mask; + packet.cal_status = cal_status; + packet.attempt = attempt; + packet.completion_pct = completion_pct; + mav_array_memcpy(packet.completion_mask, completion_mask, sizeof(uint8_t)*10); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MAG_CAL_PROGRESS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC); +} + +/** + * @brief Encode a mag_cal_progress struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param mag_cal_progress C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mag_cal_progress_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mag_cal_progress_t* mag_cal_progress) +{ + return mavlink_msg_mag_cal_progress_pack(system_id, component_id, msg, mag_cal_progress->compass_id, mag_cal_progress->cal_mask, mag_cal_progress->cal_status, mag_cal_progress->attempt, mag_cal_progress->completion_pct, mag_cal_progress->completion_mask, mag_cal_progress->direction_x, mag_cal_progress->direction_y, mag_cal_progress->direction_z); +} + +/** + * @brief Encode a mag_cal_progress struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mag_cal_progress C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mag_cal_progress_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mag_cal_progress_t* mag_cal_progress) +{ + return mavlink_msg_mag_cal_progress_pack_chan(system_id, component_id, chan, msg, mag_cal_progress->compass_id, mag_cal_progress->cal_mask, mag_cal_progress->cal_status, mag_cal_progress->attempt, mag_cal_progress->completion_pct, mag_cal_progress->completion_mask, mag_cal_progress->direction_x, mag_cal_progress->direction_y, mag_cal_progress->direction_z); +} + +/** + * @brief Send a mag_cal_progress message + * @param chan MAVLink channel to send the message + * + * @param compass_id Compass being calibrated + * @param cal_mask Bitmask of compasses being calibrated + * @param cal_status Status (see MAG_CAL_STATUS enum) + * @param attempt Attempt number + * @param completion_pct Completion percentage + * @param completion_mask Bitmask of sphere sections (see http://en.wikipedia.org/wiki/Geodesic_grid) + * @param direction_x Body frame direction vector for display + * @param direction_y Body frame direction vector for display + * @param direction_z Body frame direction vector for display + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_mag_cal_progress_send(mavlink_channel_t chan, uint8_t compass_id, uint8_t cal_mask, uint8_t cal_status, uint8_t attempt, uint8_t completion_pct, const uint8_t *completion_mask, float direction_x, float direction_y, float direction_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN]; + _mav_put_float(buf, 0, direction_x); + _mav_put_float(buf, 4, direction_y); + _mav_put_float(buf, 8, direction_z); + _mav_put_uint8_t(buf, 12, compass_id); + _mav_put_uint8_t(buf, 13, cal_mask); + _mav_put_uint8_t(buf, 14, cal_status); + _mav_put_uint8_t(buf, 15, attempt); + _mav_put_uint8_t(buf, 16, completion_pct); + _mav_put_uint8_t_array(buf, 17, completion_mask, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_PROGRESS, buf, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC); +#else + mavlink_mag_cal_progress_t packet; + packet.direction_x = direction_x; + packet.direction_y = direction_y; + packet.direction_z = direction_z; + packet.compass_id = compass_id; + packet.cal_mask = cal_mask; + packet.cal_status = cal_status; + packet.attempt = attempt; + packet.completion_pct = completion_pct; + mav_array_memcpy(packet.completion_mask, completion_mask, sizeof(uint8_t)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_PROGRESS, (const char *)&packet, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC); +#endif +} + +/** + * @brief Send a mag_cal_progress message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mag_cal_progress_send_struct(mavlink_channel_t chan, const mavlink_mag_cal_progress_t* mag_cal_progress) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mag_cal_progress_send(chan, mag_cal_progress->compass_id, mag_cal_progress->cal_mask, mag_cal_progress->cal_status, mag_cal_progress->attempt, mag_cal_progress->completion_pct, mag_cal_progress->completion_mask, mag_cal_progress->direction_x, mag_cal_progress->direction_y, mag_cal_progress->direction_z); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_PROGRESS, (const char *)mag_cal_progress, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC); +#endif +} + +#if MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_mag_cal_progress_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t compass_id, uint8_t cal_mask, uint8_t cal_status, uint8_t attempt, uint8_t completion_pct, const uint8_t *completion_mask, float direction_x, float direction_y, float direction_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, direction_x); + _mav_put_float(buf, 4, direction_y); + _mav_put_float(buf, 8, direction_z); + _mav_put_uint8_t(buf, 12, compass_id); + _mav_put_uint8_t(buf, 13, cal_mask); + _mav_put_uint8_t(buf, 14, cal_status); + _mav_put_uint8_t(buf, 15, attempt); + _mav_put_uint8_t(buf, 16, completion_pct); + _mav_put_uint8_t_array(buf, 17, completion_mask, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_PROGRESS, buf, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC); +#else + mavlink_mag_cal_progress_t *packet = (mavlink_mag_cal_progress_t *)msgbuf; + packet->direction_x = direction_x; + packet->direction_y = direction_y; + packet->direction_z = direction_z; + packet->compass_id = compass_id; + packet->cal_mask = cal_mask; + packet->cal_status = cal_status; + packet->attempt = attempt; + packet->completion_pct = completion_pct; + mav_array_memcpy(packet->completion_mask, completion_mask, sizeof(uint8_t)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_PROGRESS, (const char *)packet, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_CRC); +#endif +} +#endif + +#endif + +// MESSAGE MAG_CAL_PROGRESS UNPACKING + + +/** + * @brief Get field compass_id from mag_cal_progress message + * + * @return Compass being calibrated + */ +static inline uint8_t mavlink_msg_mag_cal_progress_get_compass_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 12); +} + +/** + * @brief Get field cal_mask from mag_cal_progress message + * + * @return Bitmask of compasses being calibrated + */ +static inline uint8_t mavlink_msg_mag_cal_progress_get_cal_mask(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 13); +} + +/** + * @brief Get field cal_status from mag_cal_progress message + * + * @return Status (see MAG_CAL_STATUS enum) + */ +static inline uint8_t mavlink_msg_mag_cal_progress_get_cal_status(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 14); +} + +/** + * @brief Get field attempt from mag_cal_progress message + * + * @return Attempt number + */ +static inline uint8_t mavlink_msg_mag_cal_progress_get_attempt(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 15); +} + +/** + * @brief Get field completion_pct from mag_cal_progress message + * + * @return Completion percentage + */ +static inline uint8_t mavlink_msg_mag_cal_progress_get_completion_pct(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 16); +} + +/** + * @brief Get field completion_mask from mag_cal_progress message + * + * @return Bitmask of sphere sections (see http://en.wikipedia.org/wiki/Geodesic_grid) + */ +static inline uint16_t mavlink_msg_mag_cal_progress_get_completion_mask(const mavlink_message_t* msg, uint8_t *completion_mask) +{ + return _MAV_RETURN_uint8_t_array(msg, completion_mask, 10, 17); +} + +/** + * @brief Get field direction_x from mag_cal_progress message + * + * @return Body frame direction vector for display + */ +static inline float mavlink_msg_mag_cal_progress_get_direction_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 0); +} + +/** + * @brief Get field direction_y from mag_cal_progress message + * + * @return Body frame direction vector for display + */ +static inline float mavlink_msg_mag_cal_progress_get_direction_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Get field direction_z from mag_cal_progress message + * + * @return Body frame direction vector for display + */ +static inline float mavlink_msg_mag_cal_progress_get_direction_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Decode a mag_cal_progress message into a struct + * + * @param msg The message to decode + * @param mag_cal_progress C-struct to decode the message contents into + */ +static inline void mavlink_msg_mag_cal_progress_decode(const mavlink_message_t* msg, mavlink_mag_cal_progress_t* mag_cal_progress) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mag_cal_progress->direction_x = mavlink_msg_mag_cal_progress_get_direction_x(msg); + mag_cal_progress->direction_y = mavlink_msg_mag_cal_progress_get_direction_y(msg); + mag_cal_progress->direction_z = mavlink_msg_mag_cal_progress_get_direction_z(msg); + mag_cal_progress->compass_id = mavlink_msg_mag_cal_progress_get_compass_id(msg); + mag_cal_progress->cal_mask = mavlink_msg_mag_cal_progress_get_cal_mask(msg); + mag_cal_progress->cal_status = mavlink_msg_mag_cal_progress_get_cal_status(msg); + mag_cal_progress->attempt = mavlink_msg_mag_cal_progress_get_attempt(msg); + mag_cal_progress->completion_pct = mavlink_msg_mag_cal_progress_get_completion_pct(msg); + mavlink_msg_mag_cal_progress_get_completion_mask(msg, mag_cal_progress->completion_mask); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN? msg->len : MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN; + memset(mag_cal_progress, 0, MAVLINK_MSG_ID_MAG_CAL_PROGRESS_LEN); + memcpy(mag_cal_progress, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mag_cal_report.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mag_cal_report.h new file mode 100644 index 0000000000..8e2f4391f2 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mag_cal_report.h @@ -0,0 +1,538 @@ +#pragma once +// MESSAGE MAG_CAL_REPORT PACKING + +#define MAVLINK_MSG_ID_MAG_CAL_REPORT 192 + +MAVPACKED( +typedef struct __mavlink_mag_cal_report_t { + float fitness; /*< RMS milligauss residuals*/ + float ofs_x; /*< X offset*/ + float ofs_y; /*< Y offset*/ + float ofs_z; /*< Z offset*/ + float diag_x; /*< X diagonal (matrix 11)*/ + float diag_y; /*< Y diagonal (matrix 22)*/ + float diag_z; /*< Z diagonal (matrix 33)*/ + float offdiag_x; /*< X off-diagonal (matrix 12 and 21)*/ + float offdiag_y; /*< Y off-diagonal (matrix 13 and 31)*/ + float offdiag_z; /*< Z off-diagonal (matrix 32 and 23)*/ + uint8_t compass_id; /*< Compass being calibrated*/ + uint8_t cal_mask; /*< Bitmask of compasses being calibrated*/ + uint8_t cal_status; /*< Status (see MAG_CAL_STATUS enum)*/ + uint8_t autosaved; /*< 0=requires a MAV_CMD_DO_ACCEPT_MAG_CAL, 1=saved to parameters*/ +}) mavlink_mag_cal_report_t; + +#define MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN 44 +#define MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN 44 +#define MAVLINK_MSG_ID_192_LEN 44 +#define MAVLINK_MSG_ID_192_MIN_LEN 44 + +#define MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC 36 +#define MAVLINK_MSG_ID_192_CRC 36 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_MAG_CAL_REPORT { \ + 192, \ + "MAG_CAL_REPORT", \ + 14, \ + { { "fitness", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mag_cal_report_t, fitness) }, \ + { "ofs_x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mag_cal_report_t, ofs_x) }, \ + { "ofs_y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mag_cal_report_t, ofs_y) }, \ + { "ofs_z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_mag_cal_report_t, ofs_z) }, \ + { "diag_x", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_mag_cal_report_t, diag_x) }, \ + { "diag_y", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_mag_cal_report_t, diag_y) }, \ + { "diag_z", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_mag_cal_report_t, diag_z) }, \ + { "offdiag_x", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_mag_cal_report_t, offdiag_x) }, \ + { "offdiag_y", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_mag_cal_report_t, offdiag_y) }, \ + { "offdiag_z", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_mag_cal_report_t, offdiag_z) }, \ + { "compass_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_mag_cal_report_t, compass_id) }, \ + { "cal_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_mag_cal_report_t, cal_mask) }, \ + { "cal_status", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_mag_cal_report_t, cal_status) }, \ + { "autosaved", NULL, MAVLINK_TYPE_UINT8_T, 0, 43, offsetof(mavlink_mag_cal_report_t, autosaved) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_MAG_CAL_REPORT { \ + "MAG_CAL_REPORT", \ + 14, \ + { { "fitness", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mag_cal_report_t, fitness) }, \ + { "ofs_x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mag_cal_report_t, ofs_x) }, \ + { "ofs_y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mag_cal_report_t, ofs_y) }, \ + { "ofs_z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_mag_cal_report_t, ofs_z) }, \ + { "diag_x", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_mag_cal_report_t, diag_x) }, \ + { "diag_y", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_mag_cal_report_t, diag_y) }, \ + { "diag_z", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_mag_cal_report_t, diag_z) }, \ + { "offdiag_x", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_mag_cal_report_t, offdiag_x) }, \ + { "offdiag_y", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_mag_cal_report_t, offdiag_y) }, \ + { "offdiag_z", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_mag_cal_report_t, offdiag_z) }, \ + { "compass_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_mag_cal_report_t, compass_id) }, \ + { "cal_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_mag_cal_report_t, cal_mask) }, \ + { "cal_status", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_mag_cal_report_t, cal_status) }, \ + { "autosaved", NULL, MAVLINK_TYPE_UINT8_T, 0, 43, offsetof(mavlink_mag_cal_report_t, autosaved) }, \ + } \ +} +#endif + +/** + * @brief Pack a mag_cal_report message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param compass_id Compass being calibrated + * @param cal_mask Bitmask of compasses being calibrated + * @param cal_status Status (see MAG_CAL_STATUS enum) + * @param autosaved 0=requires a MAV_CMD_DO_ACCEPT_MAG_CAL, 1=saved to parameters + * @param fitness RMS milligauss residuals + * @param ofs_x X offset + * @param ofs_y Y offset + * @param ofs_z Z offset + * @param diag_x X diagonal (matrix 11) + * @param diag_y Y diagonal (matrix 22) + * @param diag_z Z diagonal (matrix 33) + * @param offdiag_x X off-diagonal (matrix 12 and 21) + * @param offdiag_y Y off-diagonal (matrix 13 and 31) + * @param offdiag_z Z off-diagonal (matrix 32 and 23) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_mag_cal_report_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t compass_id, uint8_t cal_mask, uint8_t cal_status, uint8_t autosaved, float fitness, float ofs_x, float ofs_y, float ofs_z, float diag_x, float diag_y, float diag_z, float offdiag_x, float offdiag_y, float offdiag_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN]; + _mav_put_float(buf, 0, fitness); + _mav_put_float(buf, 4, ofs_x); + _mav_put_float(buf, 8, ofs_y); + _mav_put_float(buf, 12, ofs_z); + _mav_put_float(buf, 16, diag_x); + _mav_put_float(buf, 20, diag_y); + _mav_put_float(buf, 24, diag_z); + _mav_put_float(buf, 28, offdiag_x); + _mav_put_float(buf, 32, offdiag_y); + _mav_put_float(buf, 36, offdiag_z); + _mav_put_uint8_t(buf, 40, compass_id); + _mav_put_uint8_t(buf, 41, cal_mask); + _mav_put_uint8_t(buf, 42, cal_status); + _mav_put_uint8_t(buf, 43, autosaved); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN); +#else + mavlink_mag_cal_report_t packet; + packet.fitness = fitness; + packet.ofs_x = ofs_x; + packet.ofs_y = ofs_y; + packet.ofs_z = ofs_z; + packet.diag_x = diag_x; + packet.diag_y = diag_y; + packet.diag_z = diag_z; + packet.offdiag_x = offdiag_x; + packet.offdiag_y = offdiag_y; + packet.offdiag_z = offdiag_z; + packet.compass_id = compass_id; + packet.cal_mask = cal_mask; + packet.cal_status = cal_status; + packet.autosaved = autosaved; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MAG_CAL_REPORT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC); +} + +/** + * @brief Pack a mag_cal_report message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param compass_id Compass being calibrated + * @param cal_mask Bitmask of compasses being calibrated + * @param cal_status Status (see MAG_CAL_STATUS enum) + * @param autosaved 0=requires a MAV_CMD_DO_ACCEPT_MAG_CAL, 1=saved to parameters + * @param fitness RMS milligauss residuals + * @param ofs_x X offset + * @param ofs_y Y offset + * @param ofs_z Z offset + * @param diag_x X diagonal (matrix 11) + * @param diag_y Y diagonal (matrix 22) + * @param diag_z Z diagonal (matrix 33) + * @param offdiag_x X off-diagonal (matrix 12 and 21) + * @param offdiag_y Y off-diagonal (matrix 13 and 31) + * @param offdiag_z Z off-diagonal (matrix 32 and 23) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_mag_cal_report_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t compass_id,uint8_t cal_mask,uint8_t cal_status,uint8_t autosaved,float fitness,float ofs_x,float ofs_y,float ofs_z,float diag_x,float diag_y,float diag_z,float offdiag_x,float offdiag_y,float offdiag_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN]; + _mav_put_float(buf, 0, fitness); + _mav_put_float(buf, 4, ofs_x); + _mav_put_float(buf, 8, ofs_y); + _mav_put_float(buf, 12, ofs_z); + _mav_put_float(buf, 16, diag_x); + _mav_put_float(buf, 20, diag_y); + _mav_put_float(buf, 24, diag_z); + _mav_put_float(buf, 28, offdiag_x); + _mav_put_float(buf, 32, offdiag_y); + _mav_put_float(buf, 36, offdiag_z); + _mav_put_uint8_t(buf, 40, compass_id); + _mav_put_uint8_t(buf, 41, cal_mask); + _mav_put_uint8_t(buf, 42, cal_status); + _mav_put_uint8_t(buf, 43, autosaved); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN); +#else + mavlink_mag_cal_report_t packet; + packet.fitness = fitness; + packet.ofs_x = ofs_x; + packet.ofs_y = ofs_y; + packet.ofs_z = ofs_z; + packet.diag_x = diag_x; + packet.diag_y = diag_y; + packet.diag_z = diag_z; + packet.offdiag_x = offdiag_x; + packet.offdiag_y = offdiag_y; + packet.offdiag_z = offdiag_z; + packet.compass_id = compass_id; + packet.cal_mask = cal_mask; + packet.cal_status = cal_status; + packet.autosaved = autosaved; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MAG_CAL_REPORT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC); +} + +/** + * @brief Encode a mag_cal_report struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param mag_cal_report C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mag_cal_report_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mag_cal_report_t* mag_cal_report) +{ + return mavlink_msg_mag_cal_report_pack(system_id, component_id, msg, mag_cal_report->compass_id, mag_cal_report->cal_mask, mag_cal_report->cal_status, mag_cal_report->autosaved, mag_cal_report->fitness, mag_cal_report->ofs_x, mag_cal_report->ofs_y, mag_cal_report->ofs_z, mag_cal_report->diag_x, mag_cal_report->diag_y, mag_cal_report->diag_z, mag_cal_report->offdiag_x, mag_cal_report->offdiag_y, mag_cal_report->offdiag_z); +} + +/** + * @brief Encode a mag_cal_report struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mag_cal_report C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mag_cal_report_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mag_cal_report_t* mag_cal_report) +{ + return mavlink_msg_mag_cal_report_pack_chan(system_id, component_id, chan, msg, mag_cal_report->compass_id, mag_cal_report->cal_mask, mag_cal_report->cal_status, mag_cal_report->autosaved, mag_cal_report->fitness, mag_cal_report->ofs_x, mag_cal_report->ofs_y, mag_cal_report->ofs_z, mag_cal_report->diag_x, mag_cal_report->diag_y, mag_cal_report->diag_z, mag_cal_report->offdiag_x, mag_cal_report->offdiag_y, mag_cal_report->offdiag_z); +} + +/** + * @brief Send a mag_cal_report message + * @param chan MAVLink channel to send the message + * + * @param compass_id Compass being calibrated + * @param cal_mask Bitmask of compasses being calibrated + * @param cal_status Status (see MAG_CAL_STATUS enum) + * @param autosaved 0=requires a MAV_CMD_DO_ACCEPT_MAG_CAL, 1=saved to parameters + * @param fitness RMS milligauss residuals + * @param ofs_x X offset + * @param ofs_y Y offset + * @param ofs_z Z offset + * @param diag_x X diagonal (matrix 11) + * @param diag_y Y diagonal (matrix 22) + * @param diag_z Z diagonal (matrix 33) + * @param offdiag_x X off-diagonal (matrix 12 and 21) + * @param offdiag_y Y off-diagonal (matrix 13 and 31) + * @param offdiag_z Z off-diagonal (matrix 32 and 23) + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_mag_cal_report_send(mavlink_channel_t chan, uint8_t compass_id, uint8_t cal_mask, uint8_t cal_status, uint8_t autosaved, float fitness, float ofs_x, float ofs_y, float ofs_z, float diag_x, float diag_y, float diag_z, float offdiag_x, float offdiag_y, float offdiag_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN]; + _mav_put_float(buf, 0, fitness); + _mav_put_float(buf, 4, ofs_x); + _mav_put_float(buf, 8, ofs_y); + _mav_put_float(buf, 12, ofs_z); + _mav_put_float(buf, 16, diag_x); + _mav_put_float(buf, 20, diag_y); + _mav_put_float(buf, 24, diag_z); + _mav_put_float(buf, 28, offdiag_x); + _mav_put_float(buf, 32, offdiag_y); + _mav_put_float(buf, 36, offdiag_z); + _mav_put_uint8_t(buf, 40, compass_id); + _mav_put_uint8_t(buf, 41, cal_mask); + _mav_put_uint8_t(buf, 42, cal_status); + _mav_put_uint8_t(buf, 43, autosaved); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_REPORT, buf, MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC); +#else + mavlink_mag_cal_report_t packet; + packet.fitness = fitness; + packet.ofs_x = ofs_x; + packet.ofs_y = ofs_y; + packet.ofs_z = ofs_z; + packet.diag_x = diag_x; + packet.diag_y = diag_y; + packet.diag_z = diag_z; + packet.offdiag_x = offdiag_x; + packet.offdiag_y = offdiag_y; + packet.offdiag_z = offdiag_z; + packet.compass_id = compass_id; + packet.cal_mask = cal_mask; + packet.cal_status = cal_status; + packet.autosaved = autosaved; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_REPORT, (const char *)&packet, MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC); +#endif +} + +/** + * @brief Send a mag_cal_report message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mag_cal_report_send_struct(mavlink_channel_t chan, const mavlink_mag_cal_report_t* mag_cal_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mag_cal_report_send(chan, mag_cal_report->compass_id, mag_cal_report->cal_mask, mag_cal_report->cal_status, mag_cal_report->autosaved, mag_cal_report->fitness, mag_cal_report->ofs_x, mag_cal_report->ofs_y, mag_cal_report->ofs_z, mag_cal_report->diag_x, mag_cal_report->diag_y, mag_cal_report->diag_z, mag_cal_report->offdiag_x, mag_cal_report->offdiag_y, mag_cal_report->offdiag_z); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_REPORT, (const char *)mag_cal_report, MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC); +#endif +} + +#if MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_mag_cal_report_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t compass_id, uint8_t cal_mask, uint8_t cal_status, uint8_t autosaved, float fitness, float ofs_x, float ofs_y, float ofs_z, float diag_x, float diag_y, float diag_z, float offdiag_x, float offdiag_y, float offdiag_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, fitness); + _mav_put_float(buf, 4, ofs_x); + _mav_put_float(buf, 8, ofs_y); + _mav_put_float(buf, 12, ofs_z); + _mav_put_float(buf, 16, diag_x); + _mav_put_float(buf, 20, diag_y); + _mav_put_float(buf, 24, diag_z); + _mav_put_float(buf, 28, offdiag_x); + _mav_put_float(buf, 32, offdiag_y); + _mav_put_float(buf, 36, offdiag_z); + _mav_put_uint8_t(buf, 40, compass_id); + _mav_put_uint8_t(buf, 41, cal_mask); + _mav_put_uint8_t(buf, 42, cal_status); + _mav_put_uint8_t(buf, 43, autosaved); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_REPORT, buf, MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC); +#else + mavlink_mag_cal_report_t *packet = (mavlink_mag_cal_report_t *)msgbuf; + packet->fitness = fitness; + packet->ofs_x = ofs_x; + packet->ofs_y = ofs_y; + packet->ofs_z = ofs_z; + packet->diag_x = diag_x; + packet->diag_y = diag_y; + packet->diag_z = diag_z; + packet->offdiag_x = offdiag_x; + packet->offdiag_y = offdiag_y; + packet->offdiag_z = offdiag_z; + packet->compass_id = compass_id; + packet->cal_mask = cal_mask; + packet->cal_status = cal_status; + packet->autosaved = autosaved; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MAG_CAL_REPORT, (const char *)packet, MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN, MAVLINK_MSG_ID_MAG_CAL_REPORT_CRC); +#endif +} +#endif + +#endif + +// MESSAGE MAG_CAL_REPORT UNPACKING + + +/** + * @brief Get field compass_id from mag_cal_report message + * + * @return Compass being calibrated + */ +static inline uint8_t mavlink_msg_mag_cal_report_get_compass_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 40); +} + +/** + * @brief Get field cal_mask from mag_cal_report message + * + * @return Bitmask of compasses being calibrated + */ +static inline uint8_t mavlink_msg_mag_cal_report_get_cal_mask(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 41); +} + +/** + * @brief Get field cal_status from mag_cal_report message + * + * @return Status (see MAG_CAL_STATUS enum) + */ +static inline uint8_t mavlink_msg_mag_cal_report_get_cal_status(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 42); +} + +/** + * @brief Get field autosaved from mag_cal_report message + * + * @return 0=requires a MAV_CMD_DO_ACCEPT_MAG_CAL, 1=saved to parameters + */ +static inline uint8_t mavlink_msg_mag_cal_report_get_autosaved(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 43); +} + +/** + * @brief Get field fitness from mag_cal_report message + * + * @return RMS milligauss residuals + */ +static inline float mavlink_msg_mag_cal_report_get_fitness(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 0); +} + +/** + * @brief Get field ofs_x from mag_cal_report message + * + * @return X offset + */ +static inline float mavlink_msg_mag_cal_report_get_ofs_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Get field ofs_y from mag_cal_report message + * + * @return Y offset + */ +static inline float mavlink_msg_mag_cal_report_get_ofs_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field ofs_z from mag_cal_report message + * + * @return Z offset + */ +static inline float mavlink_msg_mag_cal_report_get_ofs_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field diag_x from mag_cal_report message + * + * @return X diagonal (matrix 11) + */ +static inline float mavlink_msg_mag_cal_report_get_diag_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field diag_y from mag_cal_report message + * + * @return Y diagonal (matrix 22) + */ +static inline float mavlink_msg_mag_cal_report_get_diag_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field diag_z from mag_cal_report message + * + * @return Z diagonal (matrix 33) + */ +static inline float mavlink_msg_mag_cal_report_get_diag_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field offdiag_x from mag_cal_report message + * + * @return X off-diagonal (matrix 12 and 21) + */ +static inline float mavlink_msg_mag_cal_report_get_offdiag_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Get field offdiag_y from mag_cal_report message + * + * @return Y off-diagonal (matrix 13 and 31) + */ +static inline float mavlink_msg_mag_cal_report_get_offdiag_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 32); +} + +/** + * @brief Get field offdiag_z from mag_cal_report message + * + * @return Z off-diagonal (matrix 32 and 23) + */ +static inline float mavlink_msg_mag_cal_report_get_offdiag_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 36); +} + +/** + * @brief Decode a mag_cal_report message into a struct + * + * @param msg The message to decode + * @param mag_cal_report C-struct to decode the message contents into + */ +static inline void mavlink_msg_mag_cal_report_decode(const mavlink_message_t* msg, mavlink_mag_cal_report_t* mag_cal_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mag_cal_report->fitness = mavlink_msg_mag_cal_report_get_fitness(msg); + mag_cal_report->ofs_x = mavlink_msg_mag_cal_report_get_ofs_x(msg); + mag_cal_report->ofs_y = mavlink_msg_mag_cal_report_get_ofs_y(msg); + mag_cal_report->ofs_z = mavlink_msg_mag_cal_report_get_ofs_z(msg); + mag_cal_report->diag_x = mavlink_msg_mag_cal_report_get_diag_x(msg); + mag_cal_report->diag_y = mavlink_msg_mag_cal_report_get_diag_y(msg); + mag_cal_report->diag_z = mavlink_msg_mag_cal_report_get_diag_z(msg); + mag_cal_report->offdiag_x = mavlink_msg_mag_cal_report_get_offdiag_x(msg); + mag_cal_report->offdiag_y = mavlink_msg_mag_cal_report_get_offdiag_y(msg); + mag_cal_report->offdiag_z = mavlink_msg_mag_cal_report_get_offdiag_z(msg); + mag_cal_report->compass_id = mavlink_msg_mag_cal_report_get_compass_id(msg); + mag_cal_report->cal_mask = mavlink_msg_mag_cal_report_get_cal_mask(msg); + mag_cal_report->cal_status = mavlink_msg_mag_cal_report_get_cal_status(msg); + mag_cal_report->autosaved = mavlink_msg_mag_cal_report_get_autosaved(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN? msg->len : MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN; + memset(mag_cal_report, 0, MAVLINK_MSG_ID_MAG_CAL_REPORT_LEN); + memcpy(mag_cal_report, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_meminfo.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_meminfo.h index c64b2e9377..0649973338 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_meminfo.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_meminfo.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE MEMINFO PACKING #define MAVLINK_MSG_ID_MEMINFO 152 -typedef struct __mavlink_meminfo_t -{ - uint16_t brkval; ///< heap top - uint16_t freemem; ///< free memory -} mavlink_meminfo_t; +MAVPACKED( +typedef struct __mavlink_meminfo_t { + uint16_t brkval; /*< heap top*/ + uint16_t freemem; /*< free memory*/ +}) mavlink_meminfo_t; #define MAVLINK_MSG_ID_MEMINFO_LEN 4 +#define MAVLINK_MSG_ID_MEMINFO_MIN_LEN 4 #define MAVLINK_MSG_ID_152_LEN 4 +#define MAVLINK_MSG_ID_152_MIN_LEN 4 #define MAVLINK_MSG_ID_MEMINFO_CRC 208 #define MAVLINK_MSG_ID_152_CRC 208 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MEMINFO { \ - "MEMINFO", \ - 2, \ - { { "brkval", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_meminfo_t, brkval) }, \ + 152, \ + "MEMINFO", \ + 2, \ + { { "brkval", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_meminfo_t, brkval) }, \ { "freemem", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_meminfo_t, freemem) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MEMINFO { \ + "MEMINFO", \ + 2, \ + { { "brkval", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_meminfo_t, brkval) }, \ + { "freemem", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_meminfo_t, freemem) }, \ + } \ +} +#endif /** * @brief Pack a meminfo message @@ -36,28 +49,24 @@ typedef struct __mavlink_meminfo_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_meminfo_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t brkval, uint16_t freemem) + uint16_t brkval, uint16_t freemem) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MEMINFO_LEN]; - _mav_put_uint16_t(buf, 0, brkval); - _mav_put_uint16_t(buf, 2, freemem); + char buf[MAVLINK_MSG_ID_MEMINFO_LEN]; + _mav_put_uint16_t(buf, 0, brkval); + _mav_put_uint16_t(buf, 2, freemem); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MEMINFO_LEN); #else - mavlink_meminfo_t packet; - packet.brkval = brkval; - packet.freemem = freemem; + mavlink_meminfo_t packet; + packet.brkval = brkval; + packet.freemem = freemem; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MEMINFO_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MEMINFO; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MEMINFO_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MEMINFO; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MEMINFO_MIN_LEN, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_meminfo_pack(uint8_t system_id, uint8_t compo * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_meminfo_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t brkval,uint16_t freemem) + mavlink_message_t* msg, + uint16_t brkval,uint16_t freemem) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MEMINFO_LEN]; - _mav_put_uint16_t(buf, 0, brkval); - _mav_put_uint16_t(buf, 2, freemem); + char buf[MAVLINK_MSG_ID_MEMINFO_LEN]; + _mav_put_uint16_t(buf, 0, brkval); + _mav_put_uint16_t(buf, 2, freemem); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MEMINFO_LEN); #else - mavlink_meminfo_t packet; - packet.brkval = brkval; - packet.freemem = freemem; + mavlink_meminfo_t packet; + packet.brkval = brkval; + packet.freemem = freemem; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MEMINFO_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MEMINFO; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MEMINFO_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MEMINFO; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MEMINFO_MIN_LEN, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_meminfo_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_meminfo_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_meminfo_t* meminfo) { - return mavlink_msg_meminfo_pack(system_id, component_id, msg, meminfo->brkval, meminfo->freemem); + return mavlink_msg_meminfo_pack(system_id, component_id, msg, meminfo->brkval, meminfo->freemem); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_meminfo_encode(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_meminfo_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_meminfo_t* meminfo) { - return mavlink_msg_meminfo_pack_chan(system_id, component_id, chan, msg, meminfo->brkval, meminfo->freemem); + return mavlink_msg_meminfo_pack_chan(system_id, component_id, chan, msg, meminfo->brkval, meminfo->freemem); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_meminfo_encode_chan(uint8_t system_id, uint8_ static inline void mavlink_msg_meminfo_send(mavlink_channel_t chan, uint16_t brkval, uint16_t freemem) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MEMINFO_LEN]; - _mav_put_uint16_t(buf, 0, brkval); - _mav_put_uint16_t(buf, 2, freemem); + char buf[MAVLINK_MSG_ID_MEMINFO_LEN]; + _mav_put_uint16_t(buf, 0, brkval); + _mav_put_uint16_t(buf, 2, freemem); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, buf, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, buf, MAVLINK_MSG_ID_MEMINFO_MIN_LEN, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, buf, MAVLINK_MSG_ID_MEMINFO_LEN); + mavlink_meminfo_t packet; + packet.brkval = brkval; + packet.freemem = freemem; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, (const char *)&packet, MAVLINK_MSG_ID_MEMINFO_MIN_LEN, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); #endif -#else - mavlink_meminfo_t packet; - packet.brkval = brkval; - packet.freemem = freemem; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, (const char *)&packet, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); +/** + * @brief Send a meminfo message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_meminfo_send_struct(mavlink_channel_t chan, const mavlink_meminfo_t* meminfo) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_meminfo_send(chan, meminfo->brkval, meminfo->freemem); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, (const char *)&packet, MAVLINK_MSG_ID_MEMINFO_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, (const char *)meminfo, MAVLINK_MSG_ID_MEMINFO_MIN_LEN, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_meminfo_send(mavlink_channel_t chan, uint16_t brk static inline void mavlink_msg_meminfo_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t brkval, uint16_t freemem) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, brkval); - _mav_put_uint16_t(buf, 2, freemem); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, brkval); + _mav_put_uint16_t(buf, 2, freemem); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, buf, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, buf, MAVLINK_MSG_ID_MEMINFO_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, buf, MAVLINK_MSG_ID_MEMINFO_MIN_LEN, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); #else - mavlink_meminfo_t *packet = (mavlink_meminfo_t *)msgbuf; - packet->brkval = brkval; - packet->freemem = freemem; + mavlink_meminfo_t *packet = (mavlink_meminfo_t *)msgbuf; + packet->brkval = brkval; + packet->freemem = freemem; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, (const char *)packet, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, (const char *)packet, MAVLINK_MSG_ID_MEMINFO_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMINFO, (const char *)packet, MAVLINK_MSG_ID_MEMINFO_MIN_LEN, MAVLINK_MSG_ID_MEMINFO_LEN, MAVLINK_MSG_ID_MEMINFO_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_meminfo_send_buf(mavlink_message_t *msgbuf, mavli */ static inline uint16_t mavlink_msg_meminfo_get_brkval(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint16_t mavlink_msg_meminfo_get_brkval(const mavlink_message_t* m */ static inline uint16_t mavlink_msg_meminfo_get_freemem(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 2); + return _MAV_RETURN_uint16_t(msg, 2); } /** @@ -224,10 +227,12 @@ static inline uint16_t mavlink_msg_meminfo_get_freemem(const mavlink_message_t* */ static inline void mavlink_msg_meminfo_decode(const mavlink_message_t* msg, mavlink_meminfo_t* meminfo) { -#if MAVLINK_NEED_BYTE_SWAP - meminfo->brkval = mavlink_msg_meminfo_get_brkval(msg); - meminfo->freemem = mavlink_msg_meminfo_get_freemem(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + meminfo->brkval = mavlink_msg_meminfo_get_brkval(msg); + meminfo->freemem = mavlink_msg_meminfo_get_freemem(msg); #else - memcpy(meminfo, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MEMINFO_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MEMINFO_LEN? msg->len : MAVLINK_MSG_ID_MEMINFO_LEN; + memset(meminfo, 0, MAVLINK_MSG_ID_MEMINFO_LEN); + memcpy(meminfo, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_configure.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_configure.h index 350bb0b785..afd5fcc210 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_configure.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_configure.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE MOUNT_CONFIGURE PACKING #define MAVLINK_MSG_ID_MOUNT_CONFIGURE 156 -typedef struct __mavlink_mount_configure_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t mount_mode; ///< mount operating mode (see MAV_MOUNT_MODE enum) - uint8_t stab_roll; ///< (1 = yes, 0 = no) - uint8_t stab_pitch; ///< (1 = yes, 0 = no) - uint8_t stab_yaw; ///< (1 = yes, 0 = no) -} mavlink_mount_configure_t; +MAVPACKED( +typedef struct __mavlink_mount_configure_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t mount_mode; /*< mount operating mode (see MAV_MOUNT_MODE enum)*/ + uint8_t stab_roll; /*< (1 = yes, 0 = no)*/ + uint8_t stab_pitch; /*< (1 = yes, 0 = no)*/ + uint8_t stab_yaw; /*< (1 = yes, 0 = no)*/ +}) mavlink_mount_configure_t; #define MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN 6 +#define MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN 6 #define MAVLINK_MSG_ID_156_LEN 6 +#define MAVLINK_MSG_ID_156_MIN_LEN 6 #define MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC 19 #define MAVLINK_MSG_ID_156_CRC 19 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MOUNT_CONFIGURE { \ - "MOUNT_CONFIGURE", \ - 6, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mount_configure_t, target_system) }, \ + 156, \ + "MOUNT_CONFIGURE", \ + 6, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mount_configure_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mount_configure_t, target_component) }, \ { "mount_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mount_configure_t, mount_mode) }, \ { "stab_roll", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mount_configure_t, stab_roll) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_mount_configure_t { "stab_yaw", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_mount_configure_t, stab_yaw) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MOUNT_CONFIGURE { \ + "MOUNT_CONFIGURE", \ + 6, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mount_configure_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mount_configure_t, target_component) }, \ + { "mount_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mount_configure_t, mount_mode) }, \ + { "stab_roll", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mount_configure_t, stab_roll) }, \ + { "stab_pitch", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_mount_configure_t, stab_pitch) }, \ + { "stab_yaw", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_mount_configure_t, stab_yaw) }, \ + } \ +} +#endif /** * @brief Pack a mount_configure message @@ -48,36 +65,32 @@ typedef struct __mavlink_mount_configure_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mount_configure_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t mount_mode, uint8_t stab_roll, uint8_t stab_pitch, uint8_t stab_yaw) + uint8_t target_system, uint8_t target_component, uint8_t mount_mode, uint8_t stab_roll, uint8_t stab_pitch, uint8_t stab_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, mount_mode); - _mav_put_uint8_t(buf, 3, stab_roll); - _mav_put_uint8_t(buf, 4, stab_pitch); - _mav_put_uint8_t(buf, 5, stab_yaw); + char buf[MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, mount_mode); + _mav_put_uint8_t(buf, 3, stab_roll); + _mav_put_uint8_t(buf, 4, stab_pitch); + _mav_put_uint8_t(buf, 5, stab_yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); #else - mavlink_mount_configure_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.mount_mode = mount_mode; - packet.stab_roll = stab_roll; - packet.stab_pitch = stab_pitch; - packet.stab_yaw = stab_yaw; + mavlink_mount_configure_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.mount_mode = mount_mode; + packet.stab_roll = stab_roll; + packet.stab_pitch = stab_pitch; + packet.stab_yaw = stab_yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MOUNT_CONFIGURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MOUNT_CONFIGURE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); } /** @@ -95,37 +108,33 @@ static inline uint16_t mavlink_msg_mount_configure_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mount_configure_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t mount_mode,uint8_t stab_roll,uint8_t stab_pitch,uint8_t stab_yaw) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t mount_mode,uint8_t stab_roll,uint8_t stab_pitch,uint8_t stab_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, mount_mode); - _mav_put_uint8_t(buf, 3, stab_roll); - _mav_put_uint8_t(buf, 4, stab_pitch); - _mav_put_uint8_t(buf, 5, stab_yaw); + char buf[MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, mount_mode); + _mav_put_uint8_t(buf, 3, stab_roll); + _mav_put_uint8_t(buf, 4, stab_pitch); + _mav_put_uint8_t(buf, 5, stab_yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); #else - mavlink_mount_configure_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.mount_mode = mount_mode; - packet.stab_roll = stab_roll; - packet.stab_pitch = stab_pitch; - packet.stab_yaw = stab_yaw; + mavlink_mount_configure_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.mount_mode = mount_mode; + packet.stab_roll = stab_roll; + packet.stab_pitch = stab_pitch; + packet.stab_yaw = stab_yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MOUNT_CONFIGURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MOUNT_CONFIGURE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_mount_configure_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_mount_configure_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mount_configure_t* mount_configure) { - return mavlink_msg_mount_configure_pack(system_id, component_id, msg, mount_configure->target_system, mount_configure->target_component, mount_configure->mount_mode, mount_configure->stab_roll, mount_configure->stab_pitch, mount_configure->stab_yaw); + return mavlink_msg_mount_configure_pack(system_id, component_id, msg, mount_configure->target_system, mount_configure->target_component, mount_configure->mount_mode, mount_configure->stab_roll, mount_configure->stab_pitch, mount_configure->stab_yaw); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_mount_configure_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_mount_configure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mount_configure_t* mount_configure) { - return mavlink_msg_mount_configure_pack_chan(system_id, component_id, chan, msg, mount_configure->target_system, mount_configure->target_component, mount_configure->mount_mode, mount_configure->stab_roll, mount_configure->stab_pitch, mount_configure->stab_yaw); + return mavlink_msg_mount_configure_pack_chan(system_id, component_id, chan, msg, mount_configure->target_system, mount_configure->target_component, mount_configure->mount_mode, mount_configure->stab_roll, mount_configure->stab_pitch, mount_configure->stab_yaw); } /** @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_mount_configure_encode_chan(uint8_t system_id static inline void mavlink_msg_mount_configure_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t mount_mode, uint8_t stab_roll, uint8_t stab_pitch, uint8_t stab_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, mount_mode); - _mav_put_uint8_t(buf, 3, stab_roll); - _mav_put_uint8_t(buf, 4, stab_pitch); - _mav_put_uint8_t(buf, 5, stab_yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); + char buf[MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, mount_mode); + _mav_put_uint8_t(buf, 3, stab_roll); + _mav_put_uint8_t(buf, 4, stab_pitch); + _mav_put_uint8_t(buf, 5, stab_yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); + mavlink_mount_configure_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.mount_mode = mount_mode; + packet.stab_roll = stab_roll; + packet.stab_pitch = stab_pitch; + packet.stab_yaw = stab_yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); #endif +} + +/** + * @brief Send a mount_configure message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mount_configure_send_struct(mavlink_channel_t chan, const mavlink_mount_configure_t* mount_configure) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mount_configure_send(chan, mount_configure->target_system, mount_configure->target_component, mount_configure->mount_mode, mount_configure->stab_roll, mount_configure->stab_pitch, mount_configure->stab_yaw); #else - mavlink_mount_configure_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.mount_mode = mount_mode; - packet.stab_roll = stab_roll; - packet.stab_pitch = stab_pitch; - packet.stab_yaw = stab_yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, (const char *)mount_configure, MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_mount_configure_send(mavlink_channel_t chan, uint static inline void mavlink_msg_mount_configure_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t mount_mode, uint8_t stab_roll, uint8_t stab_pitch, uint8_t stab_yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, mount_mode); - _mav_put_uint8_t(buf, 3, stab_roll); - _mav_put_uint8_t(buf, 4, stab_pitch); - _mav_put_uint8_t(buf, 5, stab_yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, mount_mode); + _mav_put_uint8_t(buf, 3, stab_roll); + _mav_put_uint8_t(buf, 4, stab_pitch); + _mav_put_uint8_t(buf, 5, stab_yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, buf, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); -#endif -#else - mavlink_mount_configure_t *packet = (mavlink_mount_configure_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; - packet->mount_mode = mount_mode; - packet->stab_roll = stab_roll; - packet->stab_pitch = stab_pitch; - packet->stab_yaw = stab_yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, (const char *)packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, (const char *)packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); -#endif + mavlink_mount_configure_t *packet = (mavlink_mount_configure_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->mount_mode = mount_mode; + packet->stab_roll = stab_roll; + packet->stab_pitch = stab_pitch; + packet->stab_yaw = stab_yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONFIGURE, (const char *)packet, MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN, MAVLINK_MSG_ID_MOUNT_CONFIGURE_CRC); #endif } #endif @@ -255,7 +262,7 @@ static inline void mavlink_msg_mount_configure_send_buf(mavlink_message_t *msgbu */ static inline uint8_t mavlink_msg_mount_configure_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -265,7 +272,7 @@ static inline uint8_t mavlink_msg_mount_configure_get_target_system(const mavlin */ static inline uint8_t mavlink_msg_mount_configure_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -275,7 +282,7 @@ static inline uint8_t mavlink_msg_mount_configure_get_target_component(const mav */ static inline uint8_t mavlink_msg_mount_configure_get_mount_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -285,7 +292,7 @@ static inline uint8_t mavlink_msg_mount_configure_get_mount_mode(const mavlink_m */ static inline uint8_t mavlink_msg_mount_configure_get_stab_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -295,7 +302,7 @@ static inline uint8_t mavlink_msg_mount_configure_get_stab_roll(const mavlink_me */ static inline uint8_t mavlink_msg_mount_configure_get_stab_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -305,7 +312,7 @@ static inline uint8_t mavlink_msg_mount_configure_get_stab_pitch(const mavlink_m */ static inline uint8_t mavlink_msg_mount_configure_get_stab_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -316,14 +323,16 @@ static inline uint8_t mavlink_msg_mount_configure_get_stab_yaw(const mavlink_mes */ static inline void mavlink_msg_mount_configure_decode(const mavlink_message_t* msg, mavlink_mount_configure_t* mount_configure) { -#if MAVLINK_NEED_BYTE_SWAP - mount_configure->target_system = mavlink_msg_mount_configure_get_target_system(msg); - mount_configure->target_component = mavlink_msg_mount_configure_get_target_component(msg); - mount_configure->mount_mode = mavlink_msg_mount_configure_get_mount_mode(msg); - mount_configure->stab_roll = mavlink_msg_mount_configure_get_stab_roll(msg); - mount_configure->stab_pitch = mavlink_msg_mount_configure_get_stab_pitch(msg); - mount_configure->stab_yaw = mavlink_msg_mount_configure_get_stab_yaw(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mount_configure->target_system = mavlink_msg_mount_configure_get_target_system(msg); + mount_configure->target_component = mavlink_msg_mount_configure_get_target_component(msg); + mount_configure->mount_mode = mavlink_msg_mount_configure_get_mount_mode(msg); + mount_configure->stab_roll = mavlink_msg_mount_configure_get_stab_roll(msg); + mount_configure->stab_pitch = mavlink_msg_mount_configure_get_stab_pitch(msg); + mount_configure->stab_yaw = mavlink_msg_mount_configure_get_stab_yaw(msg); #else - memcpy(mount_configure, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN? msg->len : MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN; + memset(mount_configure, 0, MAVLINK_MSG_ID_MOUNT_CONFIGURE_LEN); + memcpy(mount_configure, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_control.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_control.h index 72d6e24197..e2592334ba 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_control.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_control.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE MOUNT_CONTROL PACKING #define MAVLINK_MSG_ID_MOUNT_CONTROL 157 -typedef struct __mavlink_mount_control_t -{ - int32_t input_a; ///< pitch(deg*100) or lat, depending on mount mode - int32_t input_b; ///< roll(deg*100) or lon depending on mount mode - int32_t input_c; ///< yaw(deg*100) or alt (in cm) depending on mount mode - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t save_position; ///< if "1" it will save current trimmed position on EEPROM (just valid for NEUTRAL and LANDING) -} mavlink_mount_control_t; +MAVPACKED( +typedef struct __mavlink_mount_control_t { + int32_t input_a; /*< pitch(deg*100) or lat, depending on mount mode*/ + int32_t input_b; /*< roll(deg*100) or lon depending on mount mode*/ + int32_t input_c; /*< yaw(deg*100) or alt (in cm) depending on mount mode*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t save_position; /*< if "1" it will save current trimmed position on EEPROM (just valid for NEUTRAL and LANDING)*/ +}) mavlink_mount_control_t; #define MAVLINK_MSG_ID_MOUNT_CONTROL_LEN 15 +#define MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN 15 #define MAVLINK_MSG_ID_157_LEN 15 +#define MAVLINK_MSG_ID_157_MIN_LEN 15 #define MAVLINK_MSG_ID_MOUNT_CONTROL_CRC 21 #define MAVLINK_MSG_ID_157_CRC 21 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MOUNT_CONTROL { \ - "MOUNT_CONTROL", \ - 6, \ - { { "input_a", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_mount_control_t, input_a) }, \ + 157, \ + "MOUNT_CONTROL", \ + 6, \ + { { "input_a", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_mount_control_t, input_a) }, \ { "input_b", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_mount_control_t, input_b) }, \ { "input_c", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_mount_control_t, input_c) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_mount_control_t, target_system) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_mount_control_t { "save_position", NULL, MAVLINK_TYPE_UINT8_T, 0, 14, offsetof(mavlink_mount_control_t, save_position) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MOUNT_CONTROL { \ + "MOUNT_CONTROL", \ + 6, \ + { { "input_a", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_mount_control_t, input_a) }, \ + { "input_b", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_mount_control_t, input_b) }, \ + { "input_c", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_mount_control_t, input_c) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_mount_control_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_mount_control_t, target_component) }, \ + { "save_position", NULL, MAVLINK_TYPE_UINT8_T, 0, 14, offsetof(mavlink_mount_control_t, save_position) }, \ + } \ +} +#endif /** * @brief Pack a mount_control message @@ -48,36 +65,32 @@ typedef struct __mavlink_mount_control_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mount_control_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, int32_t input_a, int32_t input_b, int32_t input_c, uint8_t save_position) + uint8_t target_system, uint8_t target_component, int32_t input_a, int32_t input_b, int32_t input_c, uint8_t save_position) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_CONTROL_LEN]; - _mav_put_int32_t(buf, 0, input_a); - _mav_put_int32_t(buf, 4, input_b); - _mav_put_int32_t(buf, 8, input_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - _mav_put_uint8_t(buf, 14, save_position); + char buf[MAVLINK_MSG_ID_MOUNT_CONTROL_LEN]; + _mav_put_int32_t(buf, 0, input_a); + _mav_put_int32_t(buf, 4, input_b); + _mav_put_int32_t(buf, 8, input_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + _mav_put_uint8_t(buf, 14, save_position); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); #else - mavlink_mount_control_t packet; - packet.input_a = input_a; - packet.input_b = input_b; - packet.input_c = input_c; - packet.target_system = target_system; - packet.target_component = target_component; - packet.save_position = save_position; + mavlink_mount_control_t packet; + packet.input_a = input_a; + packet.input_b = input_b; + packet.input_c = input_c; + packet.target_system = target_system; + packet.target_component = target_component; + packet.save_position = save_position; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MOUNT_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MOUNT_CONTROL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); } /** @@ -95,37 +108,33 @@ static inline uint16_t mavlink_msg_mount_control_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mount_control_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,int32_t input_a,int32_t input_b,int32_t input_c,uint8_t save_position) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,int32_t input_a,int32_t input_b,int32_t input_c,uint8_t save_position) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_CONTROL_LEN]; - _mav_put_int32_t(buf, 0, input_a); - _mav_put_int32_t(buf, 4, input_b); - _mav_put_int32_t(buf, 8, input_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - _mav_put_uint8_t(buf, 14, save_position); + char buf[MAVLINK_MSG_ID_MOUNT_CONTROL_LEN]; + _mav_put_int32_t(buf, 0, input_a); + _mav_put_int32_t(buf, 4, input_b); + _mav_put_int32_t(buf, 8, input_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + _mav_put_uint8_t(buf, 14, save_position); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); #else - mavlink_mount_control_t packet; - packet.input_a = input_a; - packet.input_b = input_b; - packet.input_c = input_c; - packet.target_system = target_system; - packet.target_component = target_component; - packet.save_position = save_position; + mavlink_mount_control_t packet; + packet.input_a = input_a; + packet.input_b = input_b; + packet.input_c = input_c; + packet.target_system = target_system; + packet.target_component = target_component; + packet.save_position = save_position; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MOUNT_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MOUNT_CONTROL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_mount_control_pack_chan(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_mount_control_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mount_control_t* mount_control) { - return mavlink_msg_mount_control_pack(system_id, component_id, msg, mount_control->target_system, mount_control->target_component, mount_control->input_a, mount_control->input_b, mount_control->input_c, mount_control->save_position); + return mavlink_msg_mount_control_pack(system_id, component_id, msg, mount_control->target_system, mount_control->target_component, mount_control->input_a, mount_control->input_b, mount_control->input_c, mount_control->save_position); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_mount_control_encode(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_mount_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mount_control_t* mount_control) { - return mavlink_msg_mount_control_pack_chan(system_id, component_id, chan, msg, mount_control->target_system, mount_control->target_component, mount_control->input_a, mount_control->input_b, mount_control->input_c, mount_control->save_position); + return mavlink_msg_mount_control_pack_chan(system_id, component_id, chan, msg, mount_control->target_system, mount_control->target_component, mount_control->input_a, mount_control->input_b, mount_control->input_c, mount_control->save_position); } /** @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_mount_control_encode_chan(uint8_t system_id, static inline void mavlink_msg_mount_control_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int32_t input_a, int32_t input_b, int32_t input_c, uint8_t save_position) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_CONTROL_LEN]; - _mav_put_int32_t(buf, 0, input_a); - _mav_put_int32_t(buf, 4, input_b); - _mav_put_int32_t(buf, 8, input_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - _mav_put_uint8_t(buf, 14, save_position); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, buf, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); + char buf[MAVLINK_MSG_ID_MOUNT_CONTROL_LEN]; + _mav_put_int32_t(buf, 0, input_a); + _mav_put_int32_t(buf, 4, input_b); + _mav_put_int32_t(buf, 8, input_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + _mav_put_uint8_t(buf, 14, save_position); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, buf, MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, buf, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); + mavlink_mount_control_t packet; + packet.input_a = input_a; + packet.input_b = input_b; + packet.input_c = input_c; + packet.target_system = target_system; + packet.target_component = target_component; + packet.save_position = save_position; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); #endif +} + +/** + * @brief Send a mount_control message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mount_control_send_struct(mavlink_channel_t chan, const mavlink_mount_control_t* mount_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mount_control_send(chan, mount_control->target_system, mount_control->target_component, mount_control->input_a, mount_control->input_b, mount_control->input_c, mount_control->save_position); #else - mavlink_mount_control_t packet; - packet.input_a = input_a; - packet.input_b = input_b; - packet.input_c = input_c; - packet.target_system = target_system; - packet.target_component = target_component; - packet.save_position = save_position; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, (const char *)mount_control, MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_mount_control_send(mavlink_channel_t chan, uint8_ static inline void mavlink_msg_mount_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int32_t input_a, int32_t input_b, int32_t input_c, uint8_t save_position) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, input_a); - _mav_put_int32_t(buf, 4, input_b); - _mav_put_int32_t(buf, 8, input_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - _mav_put_uint8_t(buf, 14, save_position); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, buf, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, input_a); + _mav_put_int32_t(buf, 4, input_b); + _mav_put_int32_t(buf, 8, input_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + _mav_put_uint8_t(buf, 14, save_position); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, buf, MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, buf, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); -#endif -#else - mavlink_mount_control_t *packet = (mavlink_mount_control_t *)msgbuf; - packet->input_a = input_a; - packet->input_b = input_b; - packet->input_c = input_c; - packet->target_system = target_system; - packet->target_component = target_component; - packet->save_position = save_position; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, (const char *)packet, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, (const char *)packet, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); -#endif + mavlink_mount_control_t *packet = (mavlink_mount_control_t *)msgbuf; + packet->input_a = input_a; + packet->input_b = input_b; + packet->input_c = input_c; + packet->target_system = target_system; + packet->target_component = target_component; + packet->save_position = save_position; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_CONTROL, (const char *)packet, MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN, MAVLINK_MSG_ID_MOUNT_CONTROL_CRC); #endif } #endif @@ -255,7 +262,7 @@ static inline void mavlink_msg_mount_control_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_mount_control_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -265,7 +272,7 @@ static inline uint8_t mavlink_msg_mount_control_get_target_system(const mavlink_ */ static inline uint8_t mavlink_msg_mount_control_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 13); + return _MAV_RETURN_uint8_t(msg, 13); } /** @@ -275,7 +282,7 @@ static inline uint8_t mavlink_msg_mount_control_get_target_component(const mavli */ static inline int32_t mavlink_msg_mount_control_get_input_a(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -285,7 +292,7 @@ static inline int32_t mavlink_msg_mount_control_get_input_a(const mavlink_messag */ static inline int32_t mavlink_msg_mount_control_get_input_b(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -295,7 +302,7 @@ static inline int32_t mavlink_msg_mount_control_get_input_b(const mavlink_messag */ static inline int32_t mavlink_msg_mount_control_get_input_c(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -305,7 +312,7 @@ static inline int32_t mavlink_msg_mount_control_get_input_c(const mavlink_messag */ static inline uint8_t mavlink_msg_mount_control_get_save_position(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 14); + return _MAV_RETURN_uint8_t(msg, 14); } /** @@ -316,14 +323,16 @@ static inline uint8_t mavlink_msg_mount_control_get_save_position(const mavlink_ */ static inline void mavlink_msg_mount_control_decode(const mavlink_message_t* msg, mavlink_mount_control_t* mount_control) { -#if MAVLINK_NEED_BYTE_SWAP - mount_control->input_a = mavlink_msg_mount_control_get_input_a(msg); - mount_control->input_b = mavlink_msg_mount_control_get_input_b(msg); - mount_control->input_c = mavlink_msg_mount_control_get_input_c(msg); - mount_control->target_system = mavlink_msg_mount_control_get_target_system(msg); - mount_control->target_component = mavlink_msg_mount_control_get_target_component(msg); - mount_control->save_position = mavlink_msg_mount_control_get_save_position(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mount_control->input_a = mavlink_msg_mount_control_get_input_a(msg); + mount_control->input_b = mavlink_msg_mount_control_get_input_b(msg); + mount_control->input_c = mavlink_msg_mount_control_get_input_c(msg); + mount_control->target_system = mavlink_msg_mount_control_get_target_system(msg); + mount_control->target_component = mavlink_msg_mount_control_get_target_component(msg); + mount_control->save_position = mavlink_msg_mount_control_get_save_position(msg); #else - memcpy(mount_control, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MOUNT_CONTROL_LEN? msg->len : MAVLINK_MSG_ID_MOUNT_CONTROL_LEN; + memset(mount_control, 0, MAVLINK_MSG_ID_MOUNT_CONTROL_LEN); + memcpy(mount_control, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_status.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_status.h index 5c4fa0c503..6cfa45f341 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_status.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_mount_status.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE MOUNT_STATUS PACKING #define MAVLINK_MSG_ID_MOUNT_STATUS 158 -typedef struct __mavlink_mount_status_t -{ - int32_t pointing_a; ///< pitch(deg*100) - int32_t pointing_b; ///< roll(deg*100) - int32_t pointing_c; ///< yaw(deg*100) - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mount_status_t; +MAVPACKED( +typedef struct __mavlink_mount_status_t { + int32_t pointing_a; /*< pitch(deg*100)*/ + int32_t pointing_b; /*< roll(deg*100)*/ + int32_t pointing_c; /*< yaw(deg*100)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mount_status_t; #define MAVLINK_MSG_ID_MOUNT_STATUS_LEN 14 +#define MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN 14 #define MAVLINK_MSG_ID_158_LEN 14 +#define MAVLINK_MSG_ID_158_MIN_LEN 14 #define MAVLINK_MSG_ID_MOUNT_STATUS_CRC 134 #define MAVLINK_MSG_ID_158_CRC 134 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MOUNT_STATUS { \ - "MOUNT_STATUS", \ - 5, \ - { { "pointing_a", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_mount_status_t, pointing_a) }, \ + 158, \ + "MOUNT_STATUS", \ + 5, \ + { { "pointing_a", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_mount_status_t, pointing_a) }, \ { "pointing_b", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_mount_status_t, pointing_b) }, \ { "pointing_c", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_mount_status_t, pointing_c) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_mount_status_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_mount_status_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MOUNT_STATUS { \ + "MOUNT_STATUS", \ + 5, \ + { { "pointing_a", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_mount_status_t, pointing_a) }, \ + { "pointing_b", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_mount_status_t, pointing_b) }, \ + { "pointing_c", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_mount_status_t, pointing_c) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_mount_status_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_mount_status_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mount_status message @@ -45,34 +61,30 @@ typedef struct __mavlink_mount_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mount_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, int32_t pointing_a, int32_t pointing_b, int32_t pointing_c) + uint8_t target_system, uint8_t target_component, int32_t pointing_a, int32_t pointing_b, int32_t pointing_c) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_STATUS_LEN]; - _mav_put_int32_t(buf, 0, pointing_a); - _mav_put_int32_t(buf, 4, pointing_b); - _mav_put_int32_t(buf, 8, pointing_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); + char buf[MAVLINK_MSG_ID_MOUNT_STATUS_LEN]; + _mav_put_int32_t(buf, 0, pointing_a); + _mav_put_int32_t(buf, 4, pointing_b); + _mav_put_int32_t(buf, 8, pointing_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); #else - mavlink_mount_status_t packet; - packet.pointing_a = pointing_a; - packet.pointing_b = pointing_b; - packet.pointing_c = pointing_c; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mount_status_t packet; + packet.pointing_a = pointing_a; + packet.pointing_b = pointing_b; + packet.pointing_c = pointing_c; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MOUNT_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MOUNT_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); } /** @@ -89,35 +101,31 @@ static inline uint16_t mavlink_msg_mount_status_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mount_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,int32_t pointing_a,int32_t pointing_b,int32_t pointing_c) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,int32_t pointing_a,int32_t pointing_b,int32_t pointing_c) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_STATUS_LEN]; - _mav_put_int32_t(buf, 0, pointing_a); - _mav_put_int32_t(buf, 4, pointing_b); - _mav_put_int32_t(buf, 8, pointing_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); + char buf[MAVLINK_MSG_ID_MOUNT_STATUS_LEN]; + _mav_put_int32_t(buf, 0, pointing_a); + _mav_put_int32_t(buf, 4, pointing_b); + _mav_put_int32_t(buf, 8, pointing_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); #else - mavlink_mount_status_t packet; - packet.pointing_a = pointing_a; - packet.pointing_b = pointing_b; - packet.pointing_c = pointing_c; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mount_status_t packet; + packet.pointing_a = pointing_a; + packet.pointing_b = pointing_b; + packet.pointing_c = pointing_c; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MOUNT_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MOUNT_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); } /** @@ -130,7 +138,7 @@ static inline uint16_t mavlink_msg_mount_status_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_mount_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mount_status_t* mount_status) { - return mavlink_msg_mount_status_pack(system_id, component_id, msg, mount_status->target_system, mount_status->target_component, mount_status->pointing_a, mount_status->pointing_b, mount_status->pointing_c); + return mavlink_msg_mount_status_pack(system_id, component_id, msg, mount_status->target_system, mount_status->target_component, mount_status->pointing_a, mount_status->pointing_b, mount_status->pointing_c); } /** @@ -144,7 +152,7 @@ static inline uint16_t mavlink_msg_mount_status_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_mount_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mount_status_t* mount_status) { - return mavlink_msg_mount_status_pack_chan(system_id, component_id, chan, msg, mount_status->target_system, mount_status->target_component, mount_status->pointing_a, mount_status->pointing_b, mount_status->pointing_c); + return mavlink_msg_mount_status_pack_chan(system_id, component_id, chan, msg, mount_status->target_system, mount_status->target_component, mount_status->pointing_a, mount_status->pointing_b, mount_status->pointing_c); } /** @@ -162,31 +170,37 @@ static inline uint16_t mavlink_msg_mount_status_encode_chan(uint8_t system_id, u static inline void mavlink_msg_mount_status_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int32_t pointing_a, int32_t pointing_b, int32_t pointing_c) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MOUNT_STATUS_LEN]; - _mav_put_int32_t(buf, 0, pointing_a); - _mav_put_int32_t(buf, 4, pointing_b); - _mav_put_int32_t(buf, 8, pointing_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, buf, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); + char buf[MAVLINK_MSG_ID_MOUNT_STATUS_LEN]; + _mav_put_int32_t(buf, 0, pointing_a); + _mav_put_int32_t(buf, 4, pointing_b); + _mav_put_int32_t(buf, 8, pointing_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, buf, MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, buf, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); + mavlink_mount_status_t packet; + packet.pointing_a = pointing_a; + packet.pointing_b = pointing_b; + packet.pointing_c = pointing_c; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); #endif +} + +/** + * @brief Send a mount_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mount_status_send_struct(mavlink_channel_t chan, const mavlink_mount_status_t* mount_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mount_status_send(chan, mount_status->target_system, mount_status->target_component, mount_status->pointing_a, mount_status->pointing_b, mount_status->pointing_c); #else - mavlink_mount_status_t packet; - packet.pointing_a = pointing_a; - packet.pointing_b = pointing_b; - packet.pointing_c = pointing_c; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, (const char *)&packet, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, (const char *)mount_status, MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); #endif } @@ -201,31 +215,23 @@ static inline void mavlink_msg_mount_status_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_mount_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int32_t pointing_a, int32_t pointing_b, int32_t pointing_c) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, pointing_a); - _mav_put_int32_t(buf, 4, pointing_b); - _mav_put_int32_t(buf, 8, pointing_c); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, buf, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, pointing_a); + _mav_put_int32_t(buf, 4, pointing_b); + _mav_put_int32_t(buf, 8, pointing_c); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, buf, MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, buf, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); -#endif -#else - mavlink_mount_status_t *packet = (mavlink_mount_status_t *)msgbuf; - packet->pointing_a = pointing_a; - packet->pointing_b = pointing_b; - packet->pointing_c = pointing_c; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, (const char *)packet, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, (const char *)packet, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); -#endif + mavlink_mount_status_t *packet = (mavlink_mount_status_t *)msgbuf; + packet->pointing_a = pointing_a; + packet->pointing_b = pointing_b; + packet->pointing_c = pointing_c; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MOUNT_STATUS, (const char *)packet, MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_LEN, MAVLINK_MSG_ID_MOUNT_STATUS_CRC); #endif } #endif @@ -242,7 +248,7 @@ static inline void mavlink_msg_mount_status_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_mount_status_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -252,7 +258,7 @@ static inline uint8_t mavlink_msg_mount_status_get_target_system(const mavlink_m */ static inline uint8_t mavlink_msg_mount_status_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 13); + return _MAV_RETURN_uint8_t(msg, 13); } /** @@ -262,7 +268,7 @@ static inline uint8_t mavlink_msg_mount_status_get_target_component(const mavlin */ static inline int32_t mavlink_msg_mount_status_get_pointing_a(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -272,7 +278,7 @@ static inline int32_t mavlink_msg_mount_status_get_pointing_a(const mavlink_mess */ static inline int32_t mavlink_msg_mount_status_get_pointing_b(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -282,7 +288,7 @@ static inline int32_t mavlink_msg_mount_status_get_pointing_b(const mavlink_mess */ static inline int32_t mavlink_msg_mount_status_get_pointing_c(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -293,13 +299,15 @@ static inline int32_t mavlink_msg_mount_status_get_pointing_c(const mavlink_mess */ static inline void mavlink_msg_mount_status_decode(const mavlink_message_t* msg, mavlink_mount_status_t* mount_status) { -#if MAVLINK_NEED_BYTE_SWAP - mount_status->pointing_a = mavlink_msg_mount_status_get_pointing_a(msg); - mount_status->pointing_b = mavlink_msg_mount_status_get_pointing_b(msg); - mount_status->pointing_c = mavlink_msg_mount_status_get_pointing_c(msg); - mount_status->target_system = mavlink_msg_mount_status_get_target_system(msg); - mount_status->target_component = mavlink_msg_mount_status_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mount_status->pointing_a = mavlink_msg_mount_status_get_pointing_a(msg); + mount_status->pointing_b = mavlink_msg_mount_status_get_pointing_b(msg); + mount_status->pointing_c = mavlink_msg_mount_status_get_pointing_c(msg); + mount_status->target_system = mavlink_msg_mount_status_get_target_system(msg); + mount_status->target_component = mavlink_msg_mount_status_get_target_component(msg); #else - memcpy(mount_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MOUNT_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MOUNT_STATUS_LEN? msg->len : MAVLINK_MSG_ID_MOUNT_STATUS_LEN; + memset(mount_status, 0, MAVLINK_MSG_ID_MOUNT_STATUS_LEN); + memcpy(mount_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_pid_tuning.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_pid_tuning.h new file mode 100644 index 0000000000..550ee1a4bd --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_pid_tuning.h @@ -0,0 +1,363 @@ +#pragma once +// MESSAGE PID_TUNING PACKING + +#define MAVLINK_MSG_ID_PID_TUNING 194 + +MAVPACKED( +typedef struct __mavlink_pid_tuning_t { + float desired; /*< desired rate (degrees/s)*/ + float achieved; /*< achieved rate (degrees/s)*/ + float FF; /*< FF component*/ + float P; /*< P component*/ + float I; /*< I component*/ + float D; /*< D component*/ + uint8_t axis; /*< axis*/ +}) mavlink_pid_tuning_t; + +#define MAVLINK_MSG_ID_PID_TUNING_LEN 25 +#define MAVLINK_MSG_ID_PID_TUNING_MIN_LEN 25 +#define MAVLINK_MSG_ID_194_LEN 25 +#define MAVLINK_MSG_ID_194_MIN_LEN 25 + +#define MAVLINK_MSG_ID_PID_TUNING_CRC 98 +#define MAVLINK_MSG_ID_194_CRC 98 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_PID_TUNING { \ + 194, \ + "PID_TUNING", \ + 7, \ + { { "desired", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_pid_tuning_t, desired) }, \ + { "achieved", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_pid_tuning_t, achieved) }, \ + { "FF", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_pid_tuning_t, FF) }, \ + { "P", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_pid_tuning_t, P) }, \ + { "I", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_pid_tuning_t, I) }, \ + { "D", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_pid_tuning_t, D) }, \ + { "axis", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_pid_tuning_t, axis) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_PID_TUNING { \ + "PID_TUNING", \ + 7, \ + { { "desired", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_pid_tuning_t, desired) }, \ + { "achieved", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_pid_tuning_t, achieved) }, \ + { "FF", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_pid_tuning_t, FF) }, \ + { "P", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_pid_tuning_t, P) }, \ + { "I", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_pid_tuning_t, I) }, \ + { "D", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_pid_tuning_t, D) }, \ + { "axis", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_pid_tuning_t, axis) }, \ + } \ +} +#endif + +/** + * @brief Pack a pid_tuning message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param axis axis + * @param desired desired rate (degrees/s) + * @param achieved achieved rate (degrees/s) + * @param FF FF component + * @param P P component + * @param I I component + * @param D D component + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_pid_tuning_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t axis, float desired, float achieved, float FF, float P, float I, float D) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_PID_TUNING_LEN]; + _mav_put_float(buf, 0, desired); + _mav_put_float(buf, 4, achieved); + _mav_put_float(buf, 8, FF); + _mav_put_float(buf, 12, P); + _mav_put_float(buf, 16, I); + _mav_put_float(buf, 20, D); + _mav_put_uint8_t(buf, 24, axis); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PID_TUNING_LEN); +#else + mavlink_pid_tuning_t packet; + packet.desired = desired; + packet.achieved = achieved; + packet.FF = FF; + packet.P = P; + packet.I = I; + packet.D = D; + packet.axis = axis; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PID_TUNING_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_PID_TUNING; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PID_TUNING_MIN_LEN, MAVLINK_MSG_ID_PID_TUNING_LEN, MAVLINK_MSG_ID_PID_TUNING_CRC); +} + +/** + * @brief Pack a pid_tuning message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param axis axis + * @param desired desired rate (degrees/s) + * @param achieved achieved rate (degrees/s) + * @param FF FF component + * @param P P component + * @param I I component + * @param D D component + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_pid_tuning_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t axis,float desired,float achieved,float FF,float P,float I,float D) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_PID_TUNING_LEN]; + _mav_put_float(buf, 0, desired); + _mav_put_float(buf, 4, achieved); + _mav_put_float(buf, 8, FF); + _mav_put_float(buf, 12, P); + _mav_put_float(buf, 16, I); + _mav_put_float(buf, 20, D); + _mav_put_uint8_t(buf, 24, axis); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PID_TUNING_LEN); +#else + mavlink_pid_tuning_t packet; + packet.desired = desired; + packet.achieved = achieved; + packet.FF = FF; + packet.P = P; + packet.I = I; + packet.D = D; + packet.axis = axis; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PID_TUNING_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_PID_TUNING; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PID_TUNING_MIN_LEN, MAVLINK_MSG_ID_PID_TUNING_LEN, MAVLINK_MSG_ID_PID_TUNING_CRC); +} + +/** + * @brief Encode a pid_tuning struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param pid_tuning C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_pid_tuning_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_pid_tuning_t* pid_tuning) +{ + return mavlink_msg_pid_tuning_pack(system_id, component_id, msg, pid_tuning->axis, pid_tuning->desired, pid_tuning->achieved, pid_tuning->FF, pid_tuning->P, pid_tuning->I, pid_tuning->D); +} + +/** + * @brief Encode a pid_tuning struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param pid_tuning C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_pid_tuning_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_pid_tuning_t* pid_tuning) +{ + return mavlink_msg_pid_tuning_pack_chan(system_id, component_id, chan, msg, pid_tuning->axis, pid_tuning->desired, pid_tuning->achieved, pid_tuning->FF, pid_tuning->P, pid_tuning->I, pid_tuning->D); +} + +/** + * @brief Send a pid_tuning message + * @param chan MAVLink channel to send the message + * + * @param axis axis + * @param desired desired rate (degrees/s) + * @param achieved achieved rate (degrees/s) + * @param FF FF component + * @param P P component + * @param I I component + * @param D D component + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_pid_tuning_send(mavlink_channel_t chan, uint8_t axis, float desired, float achieved, float FF, float P, float I, float D) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_PID_TUNING_LEN]; + _mav_put_float(buf, 0, desired); + _mav_put_float(buf, 4, achieved); + _mav_put_float(buf, 8, FF); + _mav_put_float(buf, 12, P); + _mav_put_float(buf, 16, I); + _mav_put_float(buf, 20, D); + _mav_put_uint8_t(buf, 24, axis); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PID_TUNING, buf, MAVLINK_MSG_ID_PID_TUNING_MIN_LEN, MAVLINK_MSG_ID_PID_TUNING_LEN, MAVLINK_MSG_ID_PID_TUNING_CRC); +#else + mavlink_pid_tuning_t packet; + packet.desired = desired; + packet.achieved = achieved; + packet.FF = FF; + packet.P = P; + packet.I = I; + packet.D = D; + packet.axis = axis; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PID_TUNING, (const char *)&packet, MAVLINK_MSG_ID_PID_TUNING_MIN_LEN, MAVLINK_MSG_ID_PID_TUNING_LEN, MAVLINK_MSG_ID_PID_TUNING_CRC); +#endif +} + +/** + * @brief Send a pid_tuning message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_pid_tuning_send_struct(mavlink_channel_t chan, const mavlink_pid_tuning_t* pid_tuning) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_pid_tuning_send(chan, pid_tuning->axis, pid_tuning->desired, pid_tuning->achieved, pid_tuning->FF, pid_tuning->P, pid_tuning->I, pid_tuning->D); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PID_TUNING, (const char *)pid_tuning, MAVLINK_MSG_ID_PID_TUNING_MIN_LEN, MAVLINK_MSG_ID_PID_TUNING_LEN, MAVLINK_MSG_ID_PID_TUNING_CRC); +#endif +} + +#if MAVLINK_MSG_ID_PID_TUNING_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_pid_tuning_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t axis, float desired, float achieved, float FF, float P, float I, float D) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, desired); + _mav_put_float(buf, 4, achieved); + _mav_put_float(buf, 8, FF); + _mav_put_float(buf, 12, P); + _mav_put_float(buf, 16, I); + _mav_put_float(buf, 20, D); + _mav_put_uint8_t(buf, 24, axis); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PID_TUNING, buf, MAVLINK_MSG_ID_PID_TUNING_MIN_LEN, MAVLINK_MSG_ID_PID_TUNING_LEN, MAVLINK_MSG_ID_PID_TUNING_CRC); +#else + mavlink_pid_tuning_t *packet = (mavlink_pid_tuning_t *)msgbuf; + packet->desired = desired; + packet->achieved = achieved; + packet->FF = FF; + packet->P = P; + packet->I = I; + packet->D = D; + packet->axis = axis; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PID_TUNING, (const char *)packet, MAVLINK_MSG_ID_PID_TUNING_MIN_LEN, MAVLINK_MSG_ID_PID_TUNING_LEN, MAVLINK_MSG_ID_PID_TUNING_CRC); +#endif +} +#endif + +#endif + +// MESSAGE PID_TUNING UNPACKING + + +/** + * @brief Get field axis from pid_tuning message + * + * @return axis + */ +static inline uint8_t mavlink_msg_pid_tuning_get_axis(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 24); +} + +/** + * @brief Get field desired from pid_tuning message + * + * @return desired rate (degrees/s) + */ +static inline float mavlink_msg_pid_tuning_get_desired(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 0); +} + +/** + * @brief Get field achieved from pid_tuning message + * + * @return achieved rate (degrees/s) + */ +static inline float mavlink_msg_pid_tuning_get_achieved(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Get field FF from pid_tuning message + * + * @return FF component + */ +static inline float mavlink_msg_pid_tuning_get_FF(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field P from pid_tuning message + * + * @return P component + */ +static inline float mavlink_msg_pid_tuning_get_P(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field I from pid_tuning message + * + * @return I component + */ +static inline float mavlink_msg_pid_tuning_get_I(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field D from pid_tuning message + * + * @return D component + */ +static inline float mavlink_msg_pid_tuning_get_D(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Decode a pid_tuning message into a struct + * + * @param msg The message to decode + * @param pid_tuning C-struct to decode the message contents into + */ +static inline void mavlink_msg_pid_tuning_decode(const mavlink_message_t* msg, mavlink_pid_tuning_t* pid_tuning) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + pid_tuning->desired = mavlink_msg_pid_tuning_get_desired(msg); + pid_tuning->achieved = mavlink_msg_pid_tuning_get_achieved(msg); + pid_tuning->FF = mavlink_msg_pid_tuning_get_FF(msg); + pid_tuning->P = mavlink_msg_pid_tuning_get_P(msg); + pid_tuning->I = mavlink_msg_pid_tuning_get_I(msg); + pid_tuning->D = mavlink_msg_pid_tuning_get_D(msg); + pid_tuning->axis = mavlink_msg_pid_tuning_get_axis(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_PID_TUNING_LEN? msg->len : MAVLINK_MSG_ID_PID_TUNING_LEN; + memset(pid_tuning, 0, MAVLINK_MSG_ID_PID_TUNING_LEN); + memcpy(pid_tuning, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_radio.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_radio.h index 830eb4639a..76ed07ce24 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_radio.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_radio.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE RADIO PACKING #define MAVLINK_MSG_ID_RADIO 166 -typedef struct __mavlink_radio_t -{ - uint16_t rxerrors; ///< receive errors - uint16_t fixed; ///< count of error corrected packets - uint8_t rssi; ///< local signal strength - uint8_t remrssi; ///< remote signal strength - uint8_t txbuf; ///< how full the tx buffer is as a percentage - uint8_t noise; ///< background noise level - uint8_t remnoise; ///< remote background noise level -} mavlink_radio_t; +MAVPACKED( +typedef struct __mavlink_radio_t { + uint16_t rxerrors; /*< receive errors*/ + uint16_t fixed; /*< count of error corrected packets*/ + uint8_t rssi; /*< local signal strength*/ + uint8_t remrssi; /*< remote signal strength*/ + uint8_t txbuf; /*< how full the tx buffer is as a percentage*/ + uint8_t noise; /*< background noise level*/ + uint8_t remnoise; /*< remote background noise level*/ +}) mavlink_radio_t; #define MAVLINK_MSG_ID_RADIO_LEN 9 +#define MAVLINK_MSG_ID_RADIO_MIN_LEN 9 #define MAVLINK_MSG_ID_166_LEN 9 +#define MAVLINK_MSG_ID_166_MIN_LEN 9 #define MAVLINK_MSG_ID_RADIO_CRC 21 #define MAVLINK_MSG_ID_166_CRC 21 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RADIO { \ - "RADIO", \ - 7, \ - { { "rxerrors", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_radio_t, rxerrors) }, \ + 166, \ + "RADIO", \ + 7, \ + { { "rxerrors", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_radio_t, rxerrors) }, \ { "fixed", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_radio_t, fixed) }, \ { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_radio_t, rssi) }, \ { "remrssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_radio_t, remrssi) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_radio_t { "remnoise", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_radio_t, remnoise) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RADIO { \ + "RADIO", \ + 7, \ + { { "rxerrors", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_radio_t, rxerrors) }, \ + { "fixed", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_radio_t, fixed) }, \ + { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_radio_t, rssi) }, \ + { "remrssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_radio_t, remrssi) }, \ + { "txbuf", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_radio_t, txbuf) }, \ + { "noise", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_radio_t, noise) }, \ + { "remnoise", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_radio_t, remnoise) }, \ + } \ +} +#endif /** * @brief Pack a radio message @@ -51,38 +69,34 @@ typedef struct __mavlink_radio_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_radio_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) + uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RADIO_LEN]; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); + char buf[MAVLINK_MSG_ID_RADIO_LEN]; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RADIO_LEN); #else - mavlink_radio_t packet; - packet.rxerrors = rxerrors; - packet.fixed = fixed; - packet.rssi = rssi; - packet.remrssi = remrssi; - packet.txbuf = txbuf; - packet.noise = noise; - packet.remnoise = remnoise; + mavlink_radio_t packet; + packet.rxerrors = rxerrors; + packet.fixed = fixed; + packet.rssi = rssi; + packet.remrssi = remrssi; + packet.txbuf = txbuf; + packet.noise = noise; + packet.remnoise = remnoise; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RADIO_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RADIO; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RADIO_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RADIO; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RADIO_MIN_LEN, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_radio_pack(uint8_t system_id, uint8_t compone * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_radio_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t rssi,uint8_t remrssi,uint8_t txbuf,uint8_t noise,uint8_t remnoise,uint16_t rxerrors,uint16_t fixed) + mavlink_message_t* msg, + uint8_t rssi,uint8_t remrssi,uint8_t txbuf,uint8_t noise,uint8_t remnoise,uint16_t rxerrors,uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RADIO_LEN]; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); + char buf[MAVLINK_MSG_ID_RADIO_LEN]; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RADIO_LEN); #else - mavlink_radio_t packet; - packet.rxerrors = rxerrors; - packet.fixed = fixed; - packet.rssi = rssi; - packet.remrssi = remrssi; - packet.txbuf = txbuf; - packet.noise = noise; - packet.remnoise = remnoise; + mavlink_radio_t packet; + packet.rxerrors = rxerrors; + packet.fixed = fixed; + packet.rssi = rssi; + packet.remrssi = remrssi; + packet.txbuf = txbuf; + packet.noise = noise; + packet.remnoise = remnoise; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RADIO_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RADIO; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RADIO_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RADIO; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RADIO_MIN_LEN, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_radio_pack_chan(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_radio_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_radio_t* radio) { - return mavlink_msg_radio_pack(system_id, component_id, msg, radio->rssi, radio->remrssi, radio->txbuf, radio->noise, radio->remnoise, radio->rxerrors, radio->fixed); + return mavlink_msg_radio_pack(system_id, component_id, msg, radio->rssi, radio->remrssi, radio->txbuf, radio->noise, radio->remnoise, radio->rxerrors, radio->fixed); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_radio_encode(uint8_t system_id, uint8_t compo */ static inline uint16_t mavlink_msg_radio_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_radio_t* radio) { - return mavlink_msg_radio_pack_chan(system_id, component_id, chan, msg, radio->rssi, radio->remrssi, radio->txbuf, radio->noise, radio->remnoise, radio->rxerrors, radio->fixed); + return mavlink_msg_radio_pack_chan(system_id, component_id, chan, msg, radio->rssi, radio->remrssi, radio->txbuf, radio->noise, radio->remnoise, radio->rxerrors, radio->fixed); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_radio_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_radio_send(mavlink_channel_t chan, uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RADIO_LEN]; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, buf, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); + char buf[MAVLINK_MSG_ID_RADIO_LEN]; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, buf, MAVLINK_MSG_ID_RADIO_MIN_LEN, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, buf, MAVLINK_MSG_ID_RADIO_LEN); + mavlink_radio_t packet; + packet.rxerrors = rxerrors; + packet.fixed = fixed; + packet.rssi = rssi; + packet.remrssi = remrssi; + packet.txbuf = txbuf; + packet.noise = noise; + packet.remnoise = remnoise; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, (const char *)&packet, MAVLINK_MSG_ID_RADIO_MIN_LEN, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); #endif +} + +/** + * @brief Send a radio message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_radio_send_struct(mavlink_channel_t chan, const mavlink_radio_t* radio) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_radio_send(chan, radio->rssi, radio->remrssi, radio->txbuf, radio->noise, radio->remnoise, radio->rxerrors, radio->fixed); #else - mavlink_radio_t packet; - packet.rxerrors = rxerrors; - packet.fixed = fixed; - packet.rssi = rssi; - packet.remrssi = remrssi; - packet.txbuf = txbuf; - packet.noise = noise; - packet.remnoise = remnoise; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, (const char *)&packet, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, (const char *)&packet, MAVLINK_MSG_ID_RADIO_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, (const char *)radio, MAVLINK_MSG_ID_RADIO_MIN_LEN, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_radio_send(mavlink_channel_t chan, uint8_t rssi, static inline void mavlink_msg_radio_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, buf, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, buf, MAVLINK_MSG_ID_RADIO_LEN); -#endif -#else - mavlink_radio_t *packet = (mavlink_radio_t *)msgbuf; - packet->rxerrors = rxerrors; - packet->fixed = fixed; - packet->rssi = rssi; - packet->remrssi = remrssi; - packet->txbuf = txbuf; - packet->noise = noise; - packet->remnoise = remnoise; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, (const char *)packet, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, buf, MAVLINK_MSG_ID_RADIO_MIN_LEN, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, (const char *)packet, MAVLINK_MSG_ID_RADIO_LEN); -#endif + mavlink_radio_t *packet = (mavlink_radio_t *)msgbuf; + packet->rxerrors = rxerrors; + packet->fixed = fixed; + packet->rssi = rssi; + packet->remrssi = remrssi; + packet->txbuf = txbuf; + packet->noise = noise; + packet->remnoise = remnoise; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO, (const char *)packet, MAVLINK_MSG_ID_RADIO_MIN_LEN, MAVLINK_MSG_ID_RADIO_LEN, MAVLINK_MSG_ID_RADIO_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_radio_send_buf(mavlink_message_t *msgbuf, mavlink */ static inline uint8_t mavlink_msg_radio_get_rssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -278,7 +286,7 @@ static inline uint8_t mavlink_msg_radio_get_rssi(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_radio_get_remrssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -288,7 +296,7 @@ static inline uint8_t mavlink_msg_radio_get_remrssi(const mavlink_message_t* msg */ static inline uint8_t mavlink_msg_radio_get_txbuf(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -298,7 +306,7 @@ static inline uint8_t mavlink_msg_radio_get_txbuf(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_radio_get_noise(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -308,7 +316,7 @@ static inline uint8_t mavlink_msg_radio_get_noise(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_radio_get_remnoise(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 8); + return _MAV_RETURN_uint8_t(msg, 8); } /** @@ -318,7 +326,7 @@ static inline uint8_t mavlink_msg_radio_get_remnoise(const mavlink_message_t* ms */ static inline uint16_t mavlink_msg_radio_get_rxerrors(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -328,7 +336,7 @@ static inline uint16_t mavlink_msg_radio_get_rxerrors(const mavlink_message_t* m */ static inline uint16_t mavlink_msg_radio_get_fixed(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 2); + return _MAV_RETURN_uint16_t(msg, 2); } /** @@ -339,15 +347,17 @@ static inline uint16_t mavlink_msg_radio_get_fixed(const mavlink_message_t* msg) */ static inline void mavlink_msg_radio_decode(const mavlink_message_t* msg, mavlink_radio_t* radio) { -#if MAVLINK_NEED_BYTE_SWAP - radio->rxerrors = mavlink_msg_radio_get_rxerrors(msg); - radio->fixed = mavlink_msg_radio_get_fixed(msg); - radio->rssi = mavlink_msg_radio_get_rssi(msg); - radio->remrssi = mavlink_msg_radio_get_remrssi(msg); - radio->txbuf = mavlink_msg_radio_get_txbuf(msg); - radio->noise = mavlink_msg_radio_get_noise(msg); - radio->remnoise = mavlink_msg_radio_get_remnoise(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + radio->rxerrors = mavlink_msg_radio_get_rxerrors(msg); + radio->fixed = mavlink_msg_radio_get_fixed(msg); + radio->rssi = mavlink_msg_radio_get_rssi(msg); + radio->remrssi = mavlink_msg_radio_get_remrssi(msg); + radio->txbuf = mavlink_msg_radio_get_txbuf(msg); + radio->noise = mavlink_msg_radio_get_noise(msg); + radio->remnoise = mavlink_msg_radio_get_remnoise(msg); #else - memcpy(radio, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RADIO_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RADIO_LEN? msg->len : MAVLINK_MSG_ID_RADIO_LEN; + memset(radio, 0, MAVLINK_MSG_ID_RADIO_LEN); + memcpy(radio, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_fetch_point.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_fetch_point.h index 4598251fe1..42b195b27f 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_fetch_point.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_fetch_point.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE RALLY_FETCH_POINT PACKING #define MAVLINK_MSG_ID_RALLY_FETCH_POINT 176 -typedef struct __mavlink_rally_fetch_point_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t idx; ///< point index (first point is 0) -} mavlink_rally_fetch_point_t; +MAVPACKED( +typedef struct __mavlink_rally_fetch_point_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t idx; /*< point index (first point is 0)*/ +}) mavlink_rally_fetch_point_t; #define MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN 3 +#define MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN 3 #define MAVLINK_MSG_ID_176_LEN 3 +#define MAVLINK_MSG_ID_176_MIN_LEN 3 #define MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC 234 #define MAVLINK_MSG_ID_176_CRC 234 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RALLY_FETCH_POINT { \ - "RALLY_FETCH_POINT", \ - 3, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_rally_fetch_point_t, target_system) }, \ + 176, \ + "RALLY_FETCH_POINT", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_rally_fetch_point_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_rally_fetch_point_t, target_component) }, \ { "idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_rally_fetch_point_t, idx) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RALLY_FETCH_POINT { \ + "RALLY_FETCH_POINT", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_rally_fetch_point_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_rally_fetch_point_t, target_component) }, \ + { "idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_rally_fetch_point_t, idx) }, \ + } \ +} +#endif /** * @brief Pack a rally_fetch_point message @@ -39,30 +53,26 @@ typedef struct __mavlink_rally_fetch_point_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rally_fetch_point_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t idx) + uint8_t target_system, uint8_t target_component, uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char buf[MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); #else - mavlink_rally_fetch_point_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; + mavlink_rally_fetch_point_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RALLY_FETCH_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RALLY_FETCH_POINT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_rally_fetch_point_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rally_fetch_point_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t idx) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char buf[MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); #else - mavlink_rally_fetch_point_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; + mavlink_rally_fetch_point_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RALLY_FETCH_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RALLY_FETCH_POINT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_rally_fetch_point_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_rally_fetch_point_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rally_fetch_point_t* rally_fetch_point) { - return mavlink_msg_rally_fetch_point_pack(system_id, component_id, msg, rally_fetch_point->target_system, rally_fetch_point->target_component, rally_fetch_point->idx); + return mavlink_msg_rally_fetch_point_pack(system_id, component_id, msg, rally_fetch_point->target_system, rally_fetch_point->target_component, rally_fetch_point->idx); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_rally_fetch_point_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_rally_fetch_point_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rally_fetch_point_t* rally_fetch_point) { - return mavlink_msg_rally_fetch_point_pack_chan(system_id, component_id, chan, msg, rally_fetch_point->target_system, rally_fetch_point->target_component, rally_fetch_point->idx); + return mavlink_msg_rally_fetch_point_pack_chan(system_id, component_id, chan, msg, rally_fetch_point->target_system, rally_fetch_point->target_component, rally_fetch_point->idx); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_rally_fetch_point_encode_chan(uint8_t system_ static inline void mavlink_msg_rally_fetch_point_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char buf[MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); + mavlink_rally_fetch_point_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, (const char *)&packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); #endif -#else - mavlink_rally_fetch_point_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, (const char *)&packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); +/** + * @brief Send a rally_fetch_point message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rally_fetch_point_send_struct(mavlink_channel_t chan, const mavlink_rally_fetch_point_t* rally_fetch_point) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rally_fetch_point_send(chan, rally_fetch_point->target_system, rally_fetch_point->target_component, rally_fetch_point->idx); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, (const char *)&packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, (const char *)rally_fetch_point, MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_rally_fetch_point_send(mavlink_channel_t chan, ui static inline void mavlink_msg_rally_fetch_point_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, idx); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, idx); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, buf, MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); #else - mavlink_rally_fetch_point_t *packet = (mavlink_rally_fetch_point_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; - packet->idx = idx; + mavlink_rally_fetch_point_t *packet = (mavlink_rally_fetch_point_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->idx = idx; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, (const char *)packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, (const char *)packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_FETCH_POINT, (const char *)packet, MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN, MAVLINK_MSG_ID_RALLY_FETCH_POINT_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_rally_fetch_point_send_buf(mavlink_message_t *msg */ static inline uint8_t mavlink_msg_rally_fetch_point_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_rally_fetch_point_get_target_system(const mavl */ static inline uint8_t mavlink_msg_rally_fetch_point_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_rally_fetch_point_get_target_component(const m */ static inline uint8_t mavlink_msg_rally_fetch_point_get_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -247,11 +251,13 @@ static inline uint8_t mavlink_msg_rally_fetch_point_get_idx(const mavlink_messag */ static inline void mavlink_msg_rally_fetch_point_decode(const mavlink_message_t* msg, mavlink_rally_fetch_point_t* rally_fetch_point) { -#if MAVLINK_NEED_BYTE_SWAP - rally_fetch_point->target_system = mavlink_msg_rally_fetch_point_get_target_system(msg); - rally_fetch_point->target_component = mavlink_msg_rally_fetch_point_get_target_component(msg); - rally_fetch_point->idx = mavlink_msg_rally_fetch_point_get_idx(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rally_fetch_point->target_system = mavlink_msg_rally_fetch_point_get_target_system(msg); + rally_fetch_point->target_component = mavlink_msg_rally_fetch_point_get_target_component(msg); + rally_fetch_point->idx = mavlink_msg_rally_fetch_point_get_idx(msg); #else - memcpy(rally_fetch_point, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN? msg->len : MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN; + memset(rally_fetch_point, 0, MAVLINK_MSG_ID_RALLY_FETCH_POINT_LEN); + memcpy(rally_fetch_point, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_point.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_point.h index b44e764a94..e6b19fe269 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_point.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rally_point.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE RALLY_POINT PACKING #define MAVLINK_MSG_ID_RALLY_POINT 175 -typedef struct __mavlink_rally_point_t -{ - int32_t lat; ///< Latitude of point in degrees * 1E7 - int32_t lng; ///< Longitude of point in degrees * 1E7 - int16_t alt; ///< Transit / loiter altitude in meters relative to home - int16_t break_alt; ///< Break altitude in meters relative to home - uint16_t land_dir; ///< Heading to aim for when landing. In centi-degrees. - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t idx; ///< point index (first point is 0) - uint8_t count; ///< total number of points (for sanity checking) - uint8_t flags; ///< See RALLY_FLAGS enum for definition of the bitmask. -} mavlink_rally_point_t; +MAVPACKED( +typedef struct __mavlink_rally_point_t { + int32_t lat; /*< Latitude of point in degrees * 1E7*/ + int32_t lng; /*< Longitude of point in degrees * 1E7*/ + int16_t alt; /*< Transit / loiter altitude in meters relative to home*/ + int16_t break_alt; /*< Break altitude in meters relative to home*/ + uint16_t land_dir; /*< Heading to aim for when landing. In centi-degrees.*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t idx; /*< point index (first point is 0)*/ + uint8_t count; /*< total number of points (for sanity checking)*/ + uint8_t flags; /*< See RALLY_FLAGS enum for definition of the bitmask.*/ +}) mavlink_rally_point_t; #define MAVLINK_MSG_ID_RALLY_POINT_LEN 19 +#define MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN 19 #define MAVLINK_MSG_ID_175_LEN 19 +#define MAVLINK_MSG_ID_175_MIN_LEN 19 #define MAVLINK_MSG_ID_RALLY_POINT_CRC 138 #define MAVLINK_MSG_ID_175_CRC 138 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RALLY_POINT { \ - "RALLY_POINT", \ - 10, \ - { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_rally_point_t, lat) }, \ + 175, \ + "RALLY_POINT", \ + 10, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_rally_point_t, lat) }, \ { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_rally_point_t, lng) }, \ { "alt", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_rally_point_t, alt) }, \ { "break_alt", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_rally_point_t, break_alt) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_rally_point_t { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 18, offsetof(mavlink_rally_point_t, flags) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RALLY_POINT { \ + "RALLY_POINT", \ + 10, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_rally_point_t, lat) }, \ + { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_rally_point_t, lng) }, \ + { "alt", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_rally_point_t, alt) }, \ + { "break_alt", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_rally_point_t, break_alt) }, \ + { "land_dir", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_rally_point_t, land_dir) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 14, offsetof(mavlink_rally_point_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 15, offsetof(mavlink_rally_point_t, target_component) }, \ + { "idx", NULL, MAVLINK_TYPE_UINT8_T, 0, 16, offsetof(mavlink_rally_point_t, idx) }, \ + { "count", NULL, MAVLINK_TYPE_UINT8_T, 0, 17, offsetof(mavlink_rally_point_t, count) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 18, offsetof(mavlink_rally_point_t, flags) }, \ + } \ +} +#endif /** * @brief Pack a rally_point message @@ -60,44 +81,40 @@ typedef struct __mavlink_rally_point_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rally_point_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, int32_t lat, int32_t lng, int16_t alt, int16_t break_alt, uint16_t land_dir, uint8_t flags) + uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, int32_t lat, int32_t lng, int16_t alt, int16_t break_alt, uint16_t land_dir, uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RALLY_POINT_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lng); - _mav_put_int16_t(buf, 8, alt); - _mav_put_int16_t(buf, 10, break_alt); - _mav_put_uint16_t(buf, 12, land_dir); - _mav_put_uint8_t(buf, 14, target_system); - _mav_put_uint8_t(buf, 15, target_component); - _mav_put_uint8_t(buf, 16, idx); - _mav_put_uint8_t(buf, 17, count); - _mav_put_uint8_t(buf, 18, flags); + char buf[MAVLINK_MSG_ID_RALLY_POINT_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lng); + _mav_put_int16_t(buf, 8, alt); + _mav_put_int16_t(buf, 10, break_alt); + _mav_put_uint16_t(buf, 12, land_dir); + _mav_put_uint8_t(buf, 14, target_system); + _mav_put_uint8_t(buf, 15, target_component); + _mav_put_uint8_t(buf, 16, idx); + _mav_put_uint8_t(buf, 17, count); + _mav_put_uint8_t(buf, 18, flags); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RALLY_POINT_LEN); #else - mavlink_rally_point_t packet; - packet.lat = lat; - packet.lng = lng; - packet.alt = alt; - packet.break_alt = break_alt; - packet.land_dir = land_dir; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; - packet.count = count; - packet.flags = flags; + mavlink_rally_point_t packet; + packet.lat = lat; + packet.lng = lng; + packet.alt = alt; + packet.break_alt = break_alt; + packet.land_dir = land_dir; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + packet.count = count; + packet.flags = flags; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RALLY_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RALLY_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RALLY_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RALLY_POINT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_rally_point_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rally_point_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t idx,uint8_t count,int32_t lat,int32_t lng,int16_t alt,int16_t break_alt,uint16_t land_dir,uint8_t flags) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t idx,uint8_t count,int32_t lat,int32_t lng,int16_t alt,int16_t break_alt,uint16_t land_dir,uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RALLY_POINT_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lng); - _mav_put_int16_t(buf, 8, alt); - _mav_put_int16_t(buf, 10, break_alt); - _mav_put_uint16_t(buf, 12, land_dir); - _mav_put_uint8_t(buf, 14, target_system); - _mav_put_uint8_t(buf, 15, target_component); - _mav_put_uint8_t(buf, 16, idx); - _mav_put_uint8_t(buf, 17, count); - _mav_put_uint8_t(buf, 18, flags); + char buf[MAVLINK_MSG_ID_RALLY_POINT_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lng); + _mav_put_int16_t(buf, 8, alt); + _mav_put_int16_t(buf, 10, break_alt); + _mav_put_uint16_t(buf, 12, land_dir); + _mav_put_uint8_t(buf, 14, target_system); + _mav_put_uint8_t(buf, 15, target_component); + _mav_put_uint8_t(buf, 16, idx); + _mav_put_uint8_t(buf, 17, count); + _mav_put_uint8_t(buf, 18, flags); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RALLY_POINT_LEN); #else - mavlink_rally_point_t packet; - packet.lat = lat; - packet.lng = lng; - packet.alt = alt; - packet.break_alt = break_alt; - packet.land_dir = land_dir; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; - packet.count = count; - packet.flags = flags; + mavlink_rally_point_t packet; + packet.lat = lat; + packet.lng = lng; + packet.alt = alt; + packet.break_alt = break_alt; + packet.land_dir = land_dir; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + packet.count = count; + packet.flags = flags; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RALLY_POINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RALLY_POINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RALLY_POINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RALLY_POINT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_rally_point_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_rally_point_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rally_point_t* rally_point) { - return mavlink_msg_rally_point_pack(system_id, component_id, msg, rally_point->target_system, rally_point->target_component, rally_point->idx, rally_point->count, rally_point->lat, rally_point->lng, rally_point->alt, rally_point->break_alt, rally_point->land_dir, rally_point->flags); + return mavlink_msg_rally_point_pack(system_id, component_id, msg, rally_point->target_system, rally_point->target_component, rally_point->idx, rally_point->count, rally_point->lat, rally_point->lng, rally_point->alt, rally_point->break_alt, rally_point->land_dir, rally_point->flags); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_rally_point_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_rally_point_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rally_point_t* rally_point) { - return mavlink_msg_rally_point_pack_chan(system_id, component_id, chan, msg, rally_point->target_system, rally_point->target_component, rally_point->idx, rally_point->count, rally_point->lat, rally_point->lng, rally_point->alt, rally_point->break_alt, rally_point->land_dir, rally_point->flags); + return mavlink_msg_rally_point_pack_chan(system_id, component_id, chan, msg, rally_point->target_system, rally_point->target_component, rally_point->idx, rally_point->count, rally_point->lat, rally_point->lng, rally_point->alt, rally_point->break_alt, rally_point->land_dir, rally_point->flags); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_rally_point_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_rally_point_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, int32_t lat, int32_t lng, int16_t alt, int16_t break_alt, uint16_t land_dir, uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RALLY_POINT_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lng); - _mav_put_int16_t(buf, 8, alt); - _mav_put_int16_t(buf, 10, break_alt); - _mav_put_uint16_t(buf, 12, land_dir); - _mav_put_uint8_t(buf, 14, target_system); - _mav_put_uint8_t(buf, 15, target_component); - _mav_put_uint8_t(buf, 16, idx); - _mav_put_uint8_t(buf, 17, count); - _mav_put_uint8_t(buf, 18, flags); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, buf, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); + char buf[MAVLINK_MSG_ID_RALLY_POINT_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lng); + _mav_put_int16_t(buf, 8, alt); + _mav_put_int16_t(buf, 10, break_alt); + _mav_put_uint16_t(buf, 12, land_dir); + _mav_put_uint8_t(buf, 14, target_system); + _mav_put_uint8_t(buf, 15, target_component); + _mav_put_uint8_t(buf, 16, idx); + _mav_put_uint8_t(buf, 17, count); + _mav_put_uint8_t(buf, 18, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, buf, MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, buf, MAVLINK_MSG_ID_RALLY_POINT_LEN); + mavlink_rally_point_t packet; + packet.lat = lat; + packet.lng = lng; + packet.alt = alt; + packet.break_alt = break_alt; + packet.land_dir = land_dir; + packet.target_system = target_system; + packet.target_component = target_component; + packet.idx = idx; + packet.count = count; + packet.flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, (const char *)&packet, MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); #endif +} + +/** + * @brief Send a rally_point message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rally_point_send_struct(mavlink_channel_t chan, const mavlink_rally_point_t* rally_point) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rally_point_send(chan, rally_point->target_system, rally_point->target_component, rally_point->idx, rally_point->count, rally_point->lat, rally_point->lng, rally_point->alt, rally_point->break_alt, rally_point->land_dir, rally_point->flags); #else - mavlink_rally_point_t packet; - packet.lat = lat; - packet.lng = lng; - packet.alt = alt; - packet.break_alt = break_alt; - packet.land_dir = land_dir; - packet.target_system = target_system; - packet.target_component = target_component; - packet.idx = idx; - packet.count = count; - packet.flags = flags; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, (const char *)&packet, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, (const char *)&packet, MAVLINK_MSG_ID_RALLY_POINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, (const char *)rally_point, MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_rally_point_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_rally_point_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t idx, uint8_t count, int32_t lat, int32_t lng, int16_t alt, int16_t break_alt, uint16_t land_dir, uint8_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lng); - _mav_put_int16_t(buf, 8, alt); - _mav_put_int16_t(buf, 10, break_alt); - _mav_put_uint16_t(buf, 12, land_dir); - _mav_put_uint8_t(buf, 14, target_system); - _mav_put_uint8_t(buf, 15, target_component); - _mav_put_uint8_t(buf, 16, idx); - _mav_put_uint8_t(buf, 17, count); - _mav_put_uint8_t(buf, 18, flags); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, buf, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, buf, MAVLINK_MSG_ID_RALLY_POINT_LEN); -#endif -#else - mavlink_rally_point_t *packet = (mavlink_rally_point_t *)msgbuf; - packet->lat = lat; - packet->lng = lng; - packet->alt = alt; - packet->break_alt = break_alt; - packet->land_dir = land_dir; - packet->target_system = target_system; - packet->target_component = target_component; - packet->idx = idx; - packet->count = count; - packet->flags = flags; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, (const char *)packet, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lng); + _mav_put_int16_t(buf, 8, alt); + _mav_put_int16_t(buf, 10, break_alt); + _mav_put_uint16_t(buf, 12, land_dir); + _mav_put_uint8_t(buf, 14, target_system); + _mav_put_uint8_t(buf, 15, target_component); + _mav_put_uint8_t(buf, 16, idx); + _mav_put_uint8_t(buf, 17, count); + _mav_put_uint8_t(buf, 18, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, buf, MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, (const char *)packet, MAVLINK_MSG_ID_RALLY_POINT_LEN); -#endif + mavlink_rally_point_t *packet = (mavlink_rally_point_t *)msgbuf; + packet->lat = lat; + packet->lng = lng; + packet->alt = alt; + packet->break_alt = break_alt; + packet->land_dir = land_dir; + packet->target_system = target_system; + packet->target_component = target_component; + packet->idx = idx; + packet->count = count; + packet->flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RALLY_POINT, (const char *)packet, MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN, MAVLINK_MSG_ID_RALLY_POINT_LEN, MAVLINK_MSG_ID_RALLY_POINT_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_rally_point_send_buf(mavlink_message_t *msgbuf, m */ static inline uint8_t mavlink_msg_rally_point_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 14); + return _MAV_RETURN_uint8_t(msg, 14); } /** @@ -317,7 +328,7 @@ static inline uint8_t mavlink_msg_rally_point_get_target_system(const mavlink_me */ static inline uint8_t mavlink_msg_rally_point_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 15); + return _MAV_RETURN_uint8_t(msg, 15); } /** @@ -327,7 +338,7 @@ static inline uint8_t mavlink_msg_rally_point_get_target_component(const mavlink */ static inline uint8_t mavlink_msg_rally_point_get_idx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 16); + return _MAV_RETURN_uint8_t(msg, 16); } /** @@ -337,7 +348,7 @@ static inline uint8_t mavlink_msg_rally_point_get_idx(const mavlink_message_t* m */ static inline uint8_t mavlink_msg_rally_point_get_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 17); + return _MAV_RETURN_uint8_t(msg, 17); } /** @@ -347,7 +358,7 @@ static inline uint8_t mavlink_msg_rally_point_get_count(const mavlink_message_t* */ static inline int32_t mavlink_msg_rally_point_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -357,7 +368,7 @@ static inline int32_t mavlink_msg_rally_point_get_lat(const mavlink_message_t* m */ static inline int32_t mavlink_msg_rally_point_get_lng(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -367,7 +378,7 @@ static inline int32_t mavlink_msg_rally_point_get_lng(const mavlink_message_t* m */ static inline int16_t mavlink_msg_rally_point_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 8); + return _MAV_RETURN_int16_t(msg, 8); } /** @@ -377,7 +388,7 @@ static inline int16_t mavlink_msg_rally_point_get_alt(const mavlink_message_t* m */ static inline int16_t mavlink_msg_rally_point_get_break_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 10); + return _MAV_RETURN_int16_t(msg, 10); } /** @@ -387,7 +398,7 @@ static inline int16_t mavlink_msg_rally_point_get_break_alt(const mavlink_messag */ static inline uint16_t mavlink_msg_rally_point_get_land_dir(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -397,7 +408,7 @@ static inline uint16_t mavlink_msg_rally_point_get_land_dir(const mavlink_messag */ static inline uint8_t mavlink_msg_rally_point_get_flags(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 18); + return _MAV_RETURN_uint8_t(msg, 18); } /** @@ -408,18 +419,20 @@ static inline uint8_t mavlink_msg_rally_point_get_flags(const mavlink_message_t* */ static inline void mavlink_msg_rally_point_decode(const mavlink_message_t* msg, mavlink_rally_point_t* rally_point) { -#if MAVLINK_NEED_BYTE_SWAP - rally_point->lat = mavlink_msg_rally_point_get_lat(msg); - rally_point->lng = mavlink_msg_rally_point_get_lng(msg); - rally_point->alt = mavlink_msg_rally_point_get_alt(msg); - rally_point->break_alt = mavlink_msg_rally_point_get_break_alt(msg); - rally_point->land_dir = mavlink_msg_rally_point_get_land_dir(msg); - rally_point->target_system = mavlink_msg_rally_point_get_target_system(msg); - rally_point->target_component = mavlink_msg_rally_point_get_target_component(msg); - rally_point->idx = mavlink_msg_rally_point_get_idx(msg); - rally_point->count = mavlink_msg_rally_point_get_count(msg); - rally_point->flags = mavlink_msg_rally_point_get_flags(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rally_point->lat = mavlink_msg_rally_point_get_lat(msg); + rally_point->lng = mavlink_msg_rally_point_get_lng(msg); + rally_point->alt = mavlink_msg_rally_point_get_alt(msg); + rally_point->break_alt = mavlink_msg_rally_point_get_break_alt(msg); + rally_point->land_dir = mavlink_msg_rally_point_get_land_dir(msg); + rally_point->target_system = mavlink_msg_rally_point_get_target_system(msg); + rally_point->target_component = mavlink_msg_rally_point_get_target_component(msg); + rally_point->idx = mavlink_msg_rally_point_get_idx(msg); + rally_point->count = mavlink_msg_rally_point_get_count(msg); + rally_point->flags = mavlink_msg_rally_point_get_flags(msg); #else - memcpy(rally_point, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RALLY_POINT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RALLY_POINT_LEN? msg->len : MAVLINK_MSG_ID_RALLY_POINT_LEN; + memset(rally_point, 0, MAVLINK_MSG_ID_RALLY_POINT_LEN); + memcpy(rally_point, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rangefinder.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rangefinder.h index 464ce8a47f..0bbec2a926 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rangefinder.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rangefinder.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE RANGEFINDER PACKING #define MAVLINK_MSG_ID_RANGEFINDER 173 -typedef struct __mavlink_rangefinder_t -{ - float distance; ///< distance in meters - float voltage; ///< raw voltage if available, zero otherwise -} mavlink_rangefinder_t; +MAVPACKED( +typedef struct __mavlink_rangefinder_t { + float distance; /*< distance in meters*/ + float voltage; /*< raw voltage if available, zero otherwise*/ +}) mavlink_rangefinder_t; #define MAVLINK_MSG_ID_RANGEFINDER_LEN 8 +#define MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN 8 #define MAVLINK_MSG_ID_173_LEN 8 +#define MAVLINK_MSG_ID_173_MIN_LEN 8 #define MAVLINK_MSG_ID_RANGEFINDER_CRC 83 #define MAVLINK_MSG_ID_173_CRC 83 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RANGEFINDER { \ - "RANGEFINDER", \ - 2, \ - { { "distance", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_rangefinder_t, distance) }, \ + 173, \ + "RANGEFINDER", \ + 2, \ + { { "distance", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_rangefinder_t, distance) }, \ { "voltage", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_rangefinder_t, voltage) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RANGEFINDER { \ + "RANGEFINDER", \ + 2, \ + { { "distance", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_rangefinder_t, distance) }, \ + { "voltage", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_rangefinder_t, voltage) }, \ + } \ +} +#endif /** * @brief Pack a rangefinder message @@ -36,28 +49,24 @@ typedef struct __mavlink_rangefinder_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rangefinder_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float distance, float voltage) + float distance, float voltage) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RANGEFINDER_LEN]; - _mav_put_float(buf, 0, distance); - _mav_put_float(buf, 4, voltage); + char buf[MAVLINK_MSG_ID_RANGEFINDER_LEN]; + _mav_put_float(buf, 0, distance); + _mav_put_float(buf, 4, voltage); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RANGEFINDER_LEN); #else - mavlink_rangefinder_t packet; - packet.distance = distance; - packet.voltage = voltage; + mavlink_rangefinder_t packet; + packet.distance = distance; + packet.voltage = voltage; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RANGEFINDER_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RANGEFINDER; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RANGEFINDER_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RANGEFINDER; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_rangefinder_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rangefinder_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float distance,float voltage) + mavlink_message_t* msg, + float distance,float voltage) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RANGEFINDER_LEN]; - _mav_put_float(buf, 0, distance); - _mav_put_float(buf, 4, voltage); + char buf[MAVLINK_MSG_ID_RANGEFINDER_LEN]; + _mav_put_float(buf, 0, distance); + _mav_put_float(buf, 4, voltage); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RANGEFINDER_LEN); #else - mavlink_rangefinder_t packet; - packet.distance = distance; - packet.voltage = voltage; + mavlink_rangefinder_t packet; + packet.distance = distance; + packet.voltage = voltage; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RANGEFINDER_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RANGEFINDER; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RANGEFINDER_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RANGEFINDER; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_rangefinder_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_rangefinder_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rangefinder_t* rangefinder) { - return mavlink_msg_rangefinder_pack(system_id, component_id, msg, rangefinder->distance, rangefinder->voltage); + return mavlink_msg_rangefinder_pack(system_id, component_id, msg, rangefinder->distance, rangefinder->voltage); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_rangefinder_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_rangefinder_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rangefinder_t* rangefinder) { - return mavlink_msg_rangefinder_pack_chan(system_id, component_id, chan, msg, rangefinder->distance, rangefinder->voltage); + return mavlink_msg_rangefinder_pack_chan(system_id, component_id, chan, msg, rangefinder->distance, rangefinder->voltage); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_rangefinder_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_rangefinder_send(mavlink_channel_t chan, float distance, float voltage) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RANGEFINDER_LEN]; - _mav_put_float(buf, 0, distance); - _mav_put_float(buf, 4, voltage); + char buf[MAVLINK_MSG_ID_RANGEFINDER_LEN]; + _mav_put_float(buf, 0, distance); + _mav_put_float(buf, 4, voltage); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, buf, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, buf, MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, buf, MAVLINK_MSG_ID_RANGEFINDER_LEN); + mavlink_rangefinder_t packet; + packet.distance = distance; + packet.voltage = voltage; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, (const char *)&packet, MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); #endif -#else - mavlink_rangefinder_t packet; - packet.distance = distance; - packet.voltage = voltage; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, (const char *)&packet, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); +/** + * @brief Send a rangefinder message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rangefinder_send_struct(mavlink_channel_t chan, const mavlink_rangefinder_t* rangefinder) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rangefinder_send(chan, rangefinder->distance, rangefinder->voltage); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, (const char *)&packet, MAVLINK_MSG_ID_RANGEFINDER_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, (const char *)rangefinder, MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_rangefinder_send(mavlink_channel_t chan, float di static inline void mavlink_msg_rangefinder_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float distance, float voltage) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, distance); - _mav_put_float(buf, 4, voltage); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, distance); + _mav_put_float(buf, 4, voltage); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, buf, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, buf, MAVLINK_MSG_ID_RANGEFINDER_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, buf, MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); #else - mavlink_rangefinder_t *packet = (mavlink_rangefinder_t *)msgbuf; - packet->distance = distance; - packet->voltage = voltage; + mavlink_rangefinder_t *packet = (mavlink_rangefinder_t *)msgbuf; + packet->distance = distance; + packet->voltage = voltage; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, (const char *)packet, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, (const char *)packet, MAVLINK_MSG_ID_RANGEFINDER_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RANGEFINDER, (const char *)packet, MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN, MAVLINK_MSG_ID_RANGEFINDER_LEN, MAVLINK_MSG_ID_RANGEFINDER_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_rangefinder_send_buf(mavlink_message_t *msgbuf, m */ static inline float mavlink_msg_rangefinder_get_distance(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -213,7 +216,7 @@ static inline float mavlink_msg_rangefinder_get_distance(const mavlink_message_t */ static inline float mavlink_msg_rangefinder_get_voltage(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -224,10 +227,12 @@ static inline float mavlink_msg_rangefinder_get_voltage(const mavlink_message_t* */ static inline void mavlink_msg_rangefinder_decode(const mavlink_message_t* msg, mavlink_rangefinder_t* rangefinder) { -#if MAVLINK_NEED_BYTE_SWAP - rangefinder->distance = mavlink_msg_rangefinder_get_distance(msg); - rangefinder->voltage = mavlink_msg_rangefinder_get_voltage(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rangefinder->distance = mavlink_msg_rangefinder_get_distance(msg); + rangefinder->voltage = mavlink_msg_rangefinder_get_voltage(msg); #else - memcpy(rangefinder, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RANGEFINDER_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RANGEFINDER_LEN? msg->len : MAVLINK_MSG_ID_RANGEFINDER_LEN; + memset(rangefinder, 0, MAVLINK_MSG_ID_RANGEFINDER_LEN); + memcpy(rangefinder, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_remote_log_block_status.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_remote_log_block_status.h new file mode 100644 index 0000000000..c0d4916d36 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_remote_log_block_status.h @@ -0,0 +1,288 @@ +#pragma once +// MESSAGE REMOTE_LOG_BLOCK_STATUS PACKING + +#define MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS 185 + +MAVPACKED( +typedef struct __mavlink_remote_log_block_status_t { + uint32_t seqno; /*< log data block sequence number*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t status; /*< log data block status*/ +}) mavlink_remote_log_block_status_t; + +#define MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN 7 +#define MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN 7 +#define MAVLINK_MSG_ID_185_LEN 7 +#define MAVLINK_MSG_ID_185_MIN_LEN 7 + +#define MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC 186 +#define MAVLINK_MSG_ID_185_CRC 186 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_REMOTE_LOG_BLOCK_STATUS { \ + 185, \ + "REMOTE_LOG_BLOCK_STATUS", \ + 4, \ + { { "seqno", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_remote_log_block_status_t, seqno) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_remote_log_block_status_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_remote_log_block_status_t, target_component) }, \ + { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_remote_log_block_status_t, status) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_REMOTE_LOG_BLOCK_STATUS { \ + "REMOTE_LOG_BLOCK_STATUS", \ + 4, \ + { { "seqno", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_remote_log_block_status_t, seqno) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_remote_log_block_status_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_remote_log_block_status_t, target_component) }, \ + { "status", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_remote_log_block_status_t, status) }, \ + } \ +} +#endif + +/** + * @brief Pack a remote_log_block_status message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID + * @param target_component Component ID + * @param seqno log data block sequence number + * @param status log data block status + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_remote_log_block_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, uint8_t target_component, uint32_t seqno, uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, status); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN); +#else + mavlink_remote_log_block_status_t packet; + packet.seqno = seqno; + packet.target_system = target_system; + packet.target_component = target_component; + packet.status = status; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC); +} + +/** + * @brief Pack a remote_log_block_status message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID + * @param target_component Component ID + * @param seqno log data block sequence number + * @param status log data block status + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_remote_log_block_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint32_t seqno,uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, status); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN); +#else + mavlink_remote_log_block_status_t packet; + packet.seqno = seqno; + packet.target_system = target_system; + packet.target_component = target_component; + packet.status = status; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC); +} + +/** + * @brief Encode a remote_log_block_status struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param remote_log_block_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_remote_log_block_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_remote_log_block_status_t* remote_log_block_status) +{ + return mavlink_msg_remote_log_block_status_pack(system_id, component_id, msg, remote_log_block_status->target_system, remote_log_block_status->target_component, remote_log_block_status->seqno, remote_log_block_status->status); +} + +/** + * @brief Encode a remote_log_block_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param remote_log_block_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_remote_log_block_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_remote_log_block_status_t* remote_log_block_status) +{ + return mavlink_msg_remote_log_block_status_pack_chan(system_id, component_id, chan, msg, remote_log_block_status->target_system, remote_log_block_status->target_component, remote_log_block_status->seqno, remote_log_block_status->status); +} + +/** + * @brief Send a remote_log_block_status message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID + * @param target_component Component ID + * @param seqno log data block sequence number + * @param status log data block status + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_remote_log_block_status_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint32_t seqno, uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, status); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS, buf, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC); +#else + mavlink_remote_log_block_status_t packet; + packet.seqno = seqno; + packet.target_system = target_system; + packet.target_component = target_component; + packet.status = status; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS, (const char *)&packet, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC); +#endif +} + +/** + * @brief Send a remote_log_block_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_remote_log_block_status_send_struct(mavlink_channel_t chan, const mavlink_remote_log_block_status_t* remote_log_block_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_remote_log_block_status_send(chan, remote_log_block_status->target_system, remote_log_block_status->target_component, remote_log_block_status->seqno, remote_log_block_status->status); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS, (const char *)remote_log_block_status, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC); +#endif +} + +#if MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_remote_log_block_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint32_t seqno, uint8_t status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 6, status); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS, buf, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC); +#else + mavlink_remote_log_block_status_t *packet = (mavlink_remote_log_block_status_t *)msgbuf; + packet->seqno = seqno; + packet->target_system = target_system; + packet->target_component = target_component; + packet->status = status; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS, (const char *)packet, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_CRC); +#endif +} +#endif + +#endif + +// MESSAGE REMOTE_LOG_BLOCK_STATUS UNPACKING + + +/** + * @brief Get field target_system from remote_log_block_status message + * + * @return System ID + */ +static inline uint8_t mavlink_msg_remote_log_block_status_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 4); +} + +/** + * @brief Get field target_component from remote_log_block_status message + * + * @return Component ID + */ +static inline uint8_t mavlink_msg_remote_log_block_status_get_target_component(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 5); +} + +/** + * @brief Get field seqno from remote_log_block_status message + * + * @return log data block sequence number + */ +static inline uint32_t mavlink_msg_remote_log_block_status_get_seqno(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 0); +} + +/** + * @brief Get field status from remote_log_block_status message + * + * @return log data block status + */ +static inline uint8_t mavlink_msg_remote_log_block_status_get_status(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 6); +} + +/** + * @brief Decode a remote_log_block_status message into a struct + * + * @param msg The message to decode + * @param remote_log_block_status C-struct to decode the message contents into + */ +static inline void mavlink_msg_remote_log_block_status_decode(const mavlink_message_t* msg, mavlink_remote_log_block_status_t* remote_log_block_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + remote_log_block_status->seqno = mavlink_msg_remote_log_block_status_get_seqno(msg); + remote_log_block_status->target_system = mavlink_msg_remote_log_block_status_get_target_system(msg); + remote_log_block_status->target_component = mavlink_msg_remote_log_block_status_get_target_component(msg); + remote_log_block_status->status = mavlink_msg_remote_log_block_status_get_status(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN? msg->len : MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN; + memset(remote_log_block_status, 0, MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_LEN); + memcpy(remote_log_block_status, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_remote_log_data_block.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_remote_log_data_block.h new file mode 100644 index 0000000000..4ba8cb2b34 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_remote_log_data_block.h @@ -0,0 +1,280 @@ +#pragma once +// MESSAGE REMOTE_LOG_DATA_BLOCK PACKING + +#define MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK 184 + +MAVPACKED( +typedef struct __mavlink_remote_log_data_block_t { + uint32_t seqno; /*< log data block sequence number*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t data[200]; /*< log data block*/ +}) mavlink_remote_log_data_block_t; + +#define MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN 206 +#define MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN 206 +#define MAVLINK_MSG_ID_184_LEN 206 +#define MAVLINK_MSG_ID_184_MIN_LEN 206 + +#define MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC 159 +#define MAVLINK_MSG_ID_184_CRC 159 + +#define MAVLINK_MSG_REMOTE_LOG_DATA_BLOCK_FIELD_DATA_LEN 200 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_REMOTE_LOG_DATA_BLOCK { \ + 184, \ + "REMOTE_LOG_DATA_BLOCK", \ + 4, \ + { { "seqno", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_remote_log_data_block_t, seqno) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_remote_log_data_block_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_remote_log_data_block_t, target_component) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 200, 6, offsetof(mavlink_remote_log_data_block_t, data) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_REMOTE_LOG_DATA_BLOCK { \ + "REMOTE_LOG_DATA_BLOCK", \ + 4, \ + { { "seqno", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_remote_log_data_block_t, seqno) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_remote_log_data_block_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_remote_log_data_block_t, target_component) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 200, 6, offsetof(mavlink_remote_log_data_block_t, data) }, \ + } \ +} +#endif + +/** + * @brief Pack a remote_log_data_block message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID + * @param target_component Component ID + * @param seqno log data block sequence number + * @param data log data block + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_remote_log_data_block_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, uint8_t target_component, uint32_t seqno, const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN]; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t_array(buf, 6, data, 200); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN); +#else + mavlink_remote_log_data_block_t packet; + packet.seqno = seqno; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*200); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC); +} + +/** + * @brief Pack a remote_log_data_block message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID + * @param target_component Component ID + * @param seqno log data block sequence number + * @param data log data block + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_remote_log_data_block_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint32_t seqno,const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN]; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t_array(buf, 6, data, 200); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN); +#else + mavlink_remote_log_data_block_t packet; + packet.seqno = seqno; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*200); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC); +} + +/** + * @brief Encode a remote_log_data_block struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param remote_log_data_block C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_remote_log_data_block_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_remote_log_data_block_t* remote_log_data_block) +{ + return mavlink_msg_remote_log_data_block_pack(system_id, component_id, msg, remote_log_data_block->target_system, remote_log_data_block->target_component, remote_log_data_block->seqno, remote_log_data_block->data); +} + +/** + * @brief Encode a remote_log_data_block struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param remote_log_data_block C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_remote_log_data_block_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_remote_log_data_block_t* remote_log_data_block) +{ + return mavlink_msg_remote_log_data_block_pack_chan(system_id, component_id, chan, msg, remote_log_data_block->target_system, remote_log_data_block->target_component, remote_log_data_block->seqno, remote_log_data_block->data); +} + +/** + * @brief Send a remote_log_data_block message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID + * @param target_component Component ID + * @param seqno log data block sequence number + * @param data log data block + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_remote_log_data_block_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint32_t seqno, const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN]; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t_array(buf, 6, data, 200); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK, buf, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC); +#else + mavlink_remote_log_data_block_t packet; + packet.seqno = seqno; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*200); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK, (const char *)&packet, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC); +#endif +} + +/** + * @brief Send a remote_log_data_block message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_remote_log_data_block_send_struct(mavlink_channel_t chan, const mavlink_remote_log_data_block_t* remote_log_data_block) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_remote_log_data_block_send(chan, remote_log_data_block->target_system, remote_log_data_block->target_component, remote_log_data_block->seqno, remote_log_data_block->data); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK, (const char *)remote_log_data_block, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC); +#endif +} + +#if MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_remote_log_data_block_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint32_t seqno, const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, seqno); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t_array(buf, 6, data, 200); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK, buf, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC); +#else + mavlink_remote_log_data_block_t *packet = (mavlink_remote_log_data_block_t *)msgbuf; + packet->seqno = seqno; + packet->target_system = target_system; + packet->target_component = target_component; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*200); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK, (const char *)packet, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_CRC); +#endif +} +#endif + +#endif + +// MESSAGE REMOTE_LOG_DATA_BLOCK UNPACKING + + +/** + * @brief Get field target_system from remote_log_data_block message + * + * @return System ID + */ +static inline uint8_t mavlink_msg_remote_log_data_block_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 4); +} + +/** + * @brief Get field target_component from remote_log_data_block message + * + * @return Component ID + */ +static inline uint8_t mavlink_msg_remote_log_data_block_get_target_component(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 5); +} + +/** + * @brief Get field seqno from remote_log_data_block message + * + * @return log data block sequence number + */ +static inline uint32_t mavlink_msg_remote_log_data_block_get_seqno(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 0); +} + +/** + * @brief Get field data from remote_log_data_block message + * + * @return log data block + */ +static inline uint16_t mavlink_msg_remote_log_data_block_get_data(const mavlink_message_t* msg, uint8_t *data) +{ + return _MAV_RETURN_uint8_t_array(msg, data, 200, 6); +} + +/** + * @brief Decode a remote_log_data_block message into a struct + * + * @param msg The message to decode + * @param remote_log_data_block C-struct to decode the message contents into + */ +static inline void mavlink_msg_remote_log_data_block_decode(const mavlink_message_t* msg, mavlink_remote_log_data_block_t* remote_log_data_block) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + remote_log_data_block->seqno = mavlink_msg_remote_log_data_block_get_seqno(msg); + remote_log_data_block->target_system = mavlink_msg_remote_log_data_block_get_target_system(msg); + remote_log_data_block->target_component = mavlink_msg_remote_log_data_block_get_target_component(msg); + mavlink_msg_remote_log_data_block_get_data(msg, remote_log_data_block->data); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN? msg->len : MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN; + memset(remote_log_data_block, 0, MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_LEN); + memcpy(remote_log_data_block, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rpm.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rpm.h new file mode 100644 index 0000000000..497bf53fc0 --- /dev/null +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_rpm.h @@ -0,0 +1,238 @@ +#pragma once +// MESSAGE RPM PACKING + +#define MAVLINK_MSG_ID_RPM 226 + +MAVPACKED( +typedef struct __mavlink_rpm_t { + float rpm1; /*< RPM Sensor1*/ + float rpm2; /*< RPM Sensor2*/ +}) mavlink_rpm_t; + +#define MAVLINK_MSG_ID_RPM_LEN 8 +#define MAVLINK_MSG_ID_RPM_MIN_LEN 8 +#define MAVLINK_MSG_ID_226_LEN 8 +#define MAVLINK_MSG_ID_226_MIN_LEN 8 + +#define MAVLINK_MSG_ID_RPM_CRC 207 +#define MAVLINK_MSG_ID_226_CRC 207 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_RPM { \ + 226, \ + "RPM", \ + 2, \ + { { "rpm1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_rpm_t, rpm1) }, \ + { "rpm2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_rpm_t, rpm2) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_RPM { \ + "RPM", \ + 2, \ + { { "rpm1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_rpm_t, rpm1) }, \ + { "rpm2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_rpm_t, rpm2) }, \ + } \ +} +#endif + +/** + * @brief Pack a rpm message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param rpm1 RPM Sensor1 + * @param rpm2 RPM Sensor2 + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_rpm_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + float rpm1, float rpm2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_RPM_LEN]; + _mav_put_float(buf, 0, rpm1); + _mav_put_float(buf, 4, rpm2); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RPM_LEN); +#else + mavlink_rpm_t packet; + packet.rpm1 = rpm1; + packet.rpm2 = rpm2; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RPM_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_RPM; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RPM_MIN_LEN, MAVLINK_MSG_ID_RPM_LEN, MAVLINK_MSG_ID_RPM_CRC); +} + +/** + * @brief Pack a rpm message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param rpm1 RPM Sensor1 + * @param rpm2 RPM Sensor2 + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_rpm_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + float rpm1,float rpm2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_RPM_LEN]; + _mav_put_float(buf, 0, rpm1); + _mav_put_float(buf, 4, rpm2); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RPM_LEN); +#else + mavlink_rpm_t packet; + packet.rpm1 = rpm1; + packet.rpm2 = rpm2; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RPM_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_RPM; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RPM_MIN_LEN, MAVLINK_MSG_ID_RPM_LEN, MAVLINK_MSG_ID_RPM_CRC); +} + +/** + * @brief Encode a rpm struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param rpm C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_rpm_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rpm_t* rpm) +{ + return mavlink_msg_rpm_pack(system_id, component_id, msg, rpm->rpm1, rpm->rpm2); +} + +/** + * @brief Encode a rpm struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param rpm C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_rpm_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rpm_t* rpm) +{ + return mavlink_msg_rpm_pack_chan(system_id, component_id, chan, msg, rpm->rpm1, rpm->rpm2); +} + +/** + * @brief Send a rpm message + * @param chan MAVLink channel to send the message + * + * @param rpm1 RPM Sensor1 + * @param rpm2 RPM Sensor2 + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_rpm_send(mavlink_channel_t chan, float rpm1, float rpm2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_RPM_LEN]; + _mav_put_float(buf, 0, rpm1); + _mav_put_float(buf, 4, rpm2); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RPM, buf, MAVLINK_MSG_ID_RPM_MIN_LEN, MAVLINK_MSG_ID_RPM_LEN, MAVLINK_MSG_ID_RPM_CRC); +#else + mavlink_rpm_t packet; + packet.rpm1 = rpm1; + packet.rpm2 = rpm2; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RPM, (const char *)&packet, MAVLINK_MSG_ID_RPM_MIN_LEN, MAVLINK_MSG_ID_RPM_LEN, MAVLINK_MSG_ID_RPM_CRC); +#endif +} + +/** + * @brief Send a rpm message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rpm_send_struct(mavlink_channel_t chan, const mavlink_rpm_t* rpm) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rpm_send(chan, rpm->rpm1, rpm->rpm2); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RPM, (const char *)rpm, MAVLINK_MSG_ID_RPM_MIN_LEN, MAVLINK_MSG_ID_RPM_LEN, MAVLINK_MSG_ID_RPM_CRC); +#endif +} + +#if MAVLINK_MSG_ID_RPM_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_rpm_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float rpm1, float rpm2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, rpm1); + _mav_put_float(buf, 4, rpm2); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RPM, buf, MAVLINK_MSG_ID_RPM_MIN_LEN, MAVLINK_MSG_ID_RPM_LEN, MAVLINK_MSG_ID_RPM_CRC); +#else + mavlink_rpm_t *packet = (mavlink_rpm_t *)msgbuf; + packet->rpm1 = rpm1; + packet->rpm2 = rpm2; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RPM, (const char *)packet, MAVLINK_MSG_ID_RPM_MIN_LEN, MAVLINK_MSG_ID_RPM_LEN, MAVLINK_MSG_ID_RPM_CRC); +#endif +} +#endif + +#endif + +// MESSAGE RPM UNPACKING + + +/** + * @brief Get field rpm1 from rpm message + * + * @return RPM Sensor1 + */ +static inline float mavlink_msg_rpm_get_rpm1(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 0); +} + +/** + * @brief Get field rpm2 from rpm message + * + * @return RPM Sensor2 + */ +static inline float mavlink_msg_rpm_get_rpm2(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Decode a rpm message into a struct + * + * @param msg The message to decode + * @param rpm C-struct to decode the message contents into + */ +static inline void mavlink_msg_rpm_decode(const mavlink_message_t* msg, mavlink_rpm_t* rpm) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rpm->rpm1 = mavlink_msg_rpm_get_rpm1(msg); + rpm->rpm2 = mavlink_msg_rpm_get_rpm2(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_RPM_LEN? msg->len : MAVLINK_MSG_ID_RPM_LEN; + memset(rpm, 0, MAVLINK_MSG_ID_RPM_LEN); + memcpy(rpm, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_sensor_offsets.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_sensor_offsets.h index d18f31c954..7b036f8472 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_sensor_offsets.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_sensor_offsets.h @@ -1,35 +1,40 @@ +#pragma once // MESSAGE SENSOR_OFFSETS PACKING #define MAVLINK_MSG_ID_SENSOR_OFFSETS 150 -typedef struct __mavlink_sensor_offsets_t -{ - float mag_declination; ///< magnetic declination (radians) - int32_t raw_press; ///< raw pressure from barometer - int32_t raw_temp; ///< raw temperature from barometer - float gyro_cal_x; ///< gyro X calibration - float gyro_cal_y; ///< gyro Y calibration - float gyro_cal_z; ///< gyro Z calibration - float accel_cal_x; ///< accel X calibration - float accel_cal_y; ///< accel Y calibration - float accel_cal_z; ///< accel Z calibration - int16_t mag_ofs_x; ///< magnetometer X offset - int16_t mag_ofs_y; ///< magnetometer Y offset - int16_t mag_ofs_z; ///< magnetometer Z offset -} mavlink_sensor_offsets_t; +MAVPACKED( +typedef struct __mavlink_sensor_offsets_t { + float mag_declination; /*< magnetic declination (radians)*/ + int32_t raw_press; /*< raw pressure from barometer*/ + int32_t raw_temp; /*< raw temperature from barometer*/ + float gyro_cal_x; /*< gyro X calibration*/ + float gyro_cal_y; /*< gyro Y calibration*/ + float gyro_cal_z; /*< gyro Z calibration*/ + float accel_cal_x; /*< accel X calibration*/ + float accel_cal_y; /*< accel Y calibration*/ + float accel_cal_z; /*< accel Z calibration*/ + int16_t mag_ofs_x; /*< magnetometer X offset*/ + int16_t mag_ofs_y; /*< magnetometer Y offset*/ + int16_t mag_ofs_z; /*< magnetometer Z offset*/ +}) mavlink_sensor_offsets_t; #define MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN 42 +#define MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN 42 #define MAVLINK_MSG_ID_150_LEN 42 +#define MAVLINK_MSG_ID_150_MIN_LEN 42 #define MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC 134 #define MAVLINK_MSG_ID_150_CRC 134 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SENSOR_OFFSETS { \ - "SENSOR_OFFSETS", \ - 12, \ - { { "mag_declination", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_sensor_offsets_t, mag_declination) }, \ + 150, \ + "SENSOR_OFFSETS", \ + 12, \ + { { "mag_declination", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_sensor_offsets_t, mag_declination) }, \ { "raw_press", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_sensor_offsets_t, raw_press) }, \ { "raw_temp", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_sensor_offsets_t, raw_temp) }, \ { "gyro_cal_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_sensor_offsets_t, gyro_cal_x) }, \ @@ -43,7 +48,25 @@ typedef struct __mavlink_sensor_offsets_t { "mag_ofs_z", NULL, MAVLINK_TYPE_INT16_T, 0, 40, offsetof(mavlink_sensor_offsets_t, mag_ofs_z) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SENSOR_OFFSETS { \ + "SENSOR_OFFSETS", \ + 12, \ + { { "mag_declination", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_sensor_offsets_t, mag_declination) }, \ + { "raw_press", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_sensor_offsets_t, raw_press) }, \ + { "raw_temp", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_sensor_offsets_t, raw_temp) }, \ + { "gyro_cal_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_sensor_offsets_t, gyro_cal_x) }, \ + { "gyro_cal_y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_sensor_offsets_t, gyro_cal_y) }, \ + { "gyro_cal_z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_sensor_offsets_t, gyro_cal_z) }, \ + { "accel_cal_x", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_sensor_offsets_t, accel_cal_x) }, \ + { "accel_cal_y", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_sensor_offsets_t, accel_cal_y) }, \ + { "accel_cal_z", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_sensor_offsets_t, accel_cal_z) }, \ + { "mag_ofs_x", NULL, MAVLINK_TYPE_INT16_T, 0, 36, offsetof(mavlink_sensor_offsets_t, mag_ofs_x) }, \ + { "mag_ofs_y", NULL, MAVLINK_TYPE_INT16_T, 0, 38, offsetof(mavlink_sensor_offsets_t, mag_ofs_y) }, \ + { "mag_ofs_z", NULL, MAVLINK_TYPE_INT16_T, 0, 40, offsetof(mavlink_sensor_offsets_t, mag_ofs_z) }, \ + } \ +} +#endif /** * @brief Pack a sensor_offsets message @@ -66,48 +89,44 @@ typedef struct __mavlink_sensor_offsets_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_sensor_offsets_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z, float mag_declination, int32_t raw_press, int32_t raw_temp, float gyro_cal_x, float gyro_cal_y, float gyro_cal_z, float accel_cal_x, float accel_cal_y, float accel_cal_z) + int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z, float mag_declination, int32_t raw_press, int32_t raw_temp, float gyro_cal_x, float gyro_cal_y, float gyro_cal_z, float accel_cal_x, float accel_cal_y, float accel_cal_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN]; - _mav_put_float(buf, 0, mag_declination); - _mav_put_int32_t(buf, 4, raw_press); - _mav_put_int32_t(buf, 8, raw_temp); - _mav_put_float(buf, 12, gyro_cal_x); - _mav_put_float(buf, 16, gyro_cal_y); - _mav_put_float(buf, 20, gyro_cal_z); - _mav_put_float(buf, 24, accel_cal_x); - _mav_put_float(buf, 28, accel_cal_y); - _mav_put_float(buf, 32, accel_cal_z); - _mav_put_int16_t(buf, 36, mag_ofs_x); - _mav_put_int16_t(buf, 38, mag_ofs_y); - _mav_put_int16_t(buf, 40, mag_ofs_z); + char buf[MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN]; + _mav_put_float(buf, 0, mag_declination); + _mav_put_int32_t(buf, 4, raw_press); + _mav_put_int32_t(buf, 8, raw_temp); + _mav_put_float(buf, 12, gyro_cal_x); + _mav_put_float(buf, 16, gyro_cal_y); + _mav_put_float(buf, 20, gyro_cal_z); + _mav_put_float(buf, 24, accel_cal_x); + _mav_put_float(buf, 28, accel_cal_y); + _mav_put_float(buf, 32, accel_cal_z); + _mav_put_int16_t(buf, 36, mag_ofs_x); + _mav_put_int16_t(buf, 38, mag_ofs_y); + _mav_put_int16_t(buf, 40, mag_ofs_z); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); #else - mavlink_sensor_offsets_t packet; - packet.mag_declination = mag_declination; - packet.raw_press = raw_press; - packet.raw_temp = raw_temp; - packet.gyro_cal_x = gyro_cal_x; - packet.gyro_cal_y = gyro_cal_y; - packet.gyro_cal_z = gyro_cal_z; - packet.accel_cal_x = accel_cal_x; - packet.accel_cal_y = accel_cal_y; - packet.accel_cal_z = accel_cal_z; - packet.mag_ofs_x = mag_ofs_x; - packet.mag_ofs_y = mag_ofs_y; - packet.mag_ofs_z = mag_ofs_z; + mavlink_sensor_offsets_t packet; + packet.mag_declination = mag_declination; + packet.raw_press = raw_press; + packet.raw_temp = raw_temp; + packet.gyro_cal_x = gyro_cal_x; + packet.gyro_cal_y = gyro_cal_y; + packet.gyro_cal_z = gyro_cal_z; + packet.accel_cal_x = accel_cal_x; + packet.accel_cal_y = accel_cal_y; + packet.accel_cal_z = accel_cal_z; + packet.mag_ofs_x = mag_ofs_x; + packet.mag_ofs_y = mag_ofs_y; + packet.mag_ofs_z = mag_ofs_z; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SENSOR_OFFSETS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SENSOR_OFFSETS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); } /** @@ -131,49 +150,45 @@ static inline uint16_t mavlink_msg_sensor_offsets_pack(uint8_t system_id, uint8_ * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_sensor_offsets_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - int16_t mag_ofs_x,int16_t mag_ofs_y,int16_t mag_ofs_z,float mag_declination,int32_t raw_press,int32_t raw_temp,float gyro_cal_x,float gyro_cal_y,float gyro_cal_z,float accel_cal_x,float accel_cal_y,float accel_cal_z) + mavlink_message_t* msg, + int16_t mag_ofs_x,int16_t mag_ofs_y,int16_t mag_ofs_z,float mag_declination,int32_t raw_press,int32_t raw_temp,float gyro_cal_x,float gyro_cal_y,float gyro_cal_z,float accel_cal_x,float accel_cal_y,float accel_cal_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN]; - _mav_put_float(buf, 0, mag_declination); - _mav_put_int32_t(buf, 4, raw_press); - _mav_put_int32_t(buf, 8, raw_temp); - _mav_put_float(buf, 12, gyro_cal_x); - _mav_put_float(buf, 16, gyro_cal_y); - _mav_put_float(buf, 20, gyro_cal_z); - _mav_put_float(buf, 24, accel_cal_x); - _mav_put_float(buf, 28, accel_cal_y); - _mav_put_float(buf, 32, accel_cal_z); - _mav_put_int16_t(buf, 36, mag_ofs_x); - _mav_put_int16_t(buf, 38, mag_ofs_y); - _mav_put_int16_t(buf, 40, mag_ofs_z); + char buf[MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN]; + _mav_put_float(buf, 0, mag_declination); + _mav_put_int32_t(buf, 4, raw_press); + _mav_put_int32_t(buf, 8, raw_temp); + _mav_put_float(buf, 12, gyro_cal_x); + _mav_put_float(buf, 16, gyro_cal_y); + _mav_put_float(buf, 20, gyro_cal_z); + _mav_put_float(buf, 24, accel_cal_x); + _mav_put_float(buf, 28, accel_cal_y); + _mav_put_float(buf, 32, accel_cal_z); + _mav_put_int16_t(buf, 36, mag_ofs_x); + _mav_put_int16_t(buf, 38, mag_ofs_y); + _mav_put_int16_t(buf, 40, mag_ofs_z); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); #else - mavlink_sensor_offsets_t packet; - packet.mag_declination = mag_declination; - packet.raw_press = raw_press; - packet.raw_temp = raw_temp; - packet.gyro_cal_x = gyro_cal_x; - packet.gyro_cal_y = gyro_cal_y; - packet.gyro_cal_z = gyro_cal_z; - packet.accel_cal_x = accel_cal_x; - packet.accel_cal_y = accel_cal_y; - packet.accel_cal_z = accel_cal_z; - packet.mag_ofs_x = mag_ofs_x; - packet.mag_ofs_y = mag_ofs_y; - packet.mag_ofs_z = mag_ofs_z; + mavlink_sensor_offsets_t packet; + packet.mag_declination = mag_declination; + packet.raw_press = raw_press; + packet.raw_temp = raw_temp; + packet.gyro_cal_x = gyro_cal_x; + packet.gyro_cal_y = gyro_cal_y; + packet.gyro_cal_z = gyro_cal_z; + packet.accel_cal_x = accel_cal_x; + packet.accel_cal_y = accel_cal_y; + packet.accel_cal_z = accel_cal_z; + packet.mag_ofs_x = mag_ofs_x; + packet.mag_ofs_y = mag_ofs_y; + packet.mag_ofs_z = mag_ofs_z; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SENSOR_OFFSETS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SENSOR_OFFSETS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); } /** @@ -186,7 +201,7 @@ static inline uint16_t mavlink_msg_sensor_offsets_pack_chan(uint8_t system_id, u */ static inline uint16_t mavlink_msg_sensor_offsets_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_sensor_offsets_t* sensor_offsets) { - return mavlink_msg_sensor_offsets_pack(system_id, component_id, msg, sensor_offsets->mag_ofs_x, sensor_offsets->mag_ofs_y, sensor_offsets->mag_ofs_z, sensor_offsets->mag_declination, sensor_offsets->raw_press, sensor_offsets->raw_temp, sensor_offsets->gyro_cal_x, sensor_offsets->gyro_cal_y, sensor_offsets->gyro_cal_z, sensor_offsets->accel_cal_x, sensor_offsets->accel_cal_y, sensor_offsets->accel_cal_z); + return mavlink_msg_sensor_offsets_pack(system_id, component_id, msg, sensor_offsets->mag_ofs_x, sensor_offsets->mag_ofs_y, sensor_offsets->mag_ofs_z, sensor_offsets->mag_declination, sensor_offsets->raw_press, sensor_offsets->raw_temp, sensor_offsets->gyro_cal_x, sensor_offsets->gyro_cal_y, sensor_offsets->gyro_cal_z, sensor_offsets->accel_cal_x, sensor_offsets->accel_cal_y, sensor_offsets->accel_cal_z); } /** @@ -200,7 +215,7 @@ static inline uint16_t mavlink_msg_sensor_offsets_encode(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_sensor_offsets_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_sensor_offsets_t* sensor_offsets) { - return mavlink_msg_sensor_offsets_pack_chan(system_id, component_id, chan, msg, sensor_offsets->mag_ofs_x, sensor_offsets->mag_ofs_y, sensor_offsets->mag_ofs_z, sensor_offsets->mag_declination, sensor_offsets->raw_press, sensor_offsets->raw_temp, sensor_offsets->gyro_cal_x, sensor_offsets->gyro_cal_y, sensor_offsets->gyro_cal_z, sensor_offsets->accel_cal_x, sensor_offsets->accel_cal_y, sensor_offsets->accel_cal_z); + return mavlink_msg_sensor_offsets_pack_chan(system_id, component_id, chan, msg, sensor_offsets->mag_ofs_x, sensor_offsets->mag_ofs_y, sensor_offsets->mag_ofs_z, sensor_offsets->mag_declination, sensor_offsets->raw_press, sensor_offsets->raw_temp, sensor_offsets->gyro_cal_x, sensor_offsets->gyro_cal_y, sensor_offsets->gyro_cal_z, sensor_offsets->accel_cal_x, sensor_offsets->accel_cal_y, sensor_offsets->accel_cal_z); } /** @@ -225,45 +240,51 @@ static inline uint16_t mavlink_msg_sensor_offsets_encode_chan(uint8_t system_id, static inline void mavlink_msg_sensor_offsets_send(mavlink_channel_t chan, int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z, float mag_declination, int32_t raw_press, int32_t raw_temp, float gyro_cal_x, float gyro_cal_y, float gyro_cal_z, float accel_cal_x, float accel_cal_y, float accel_cal_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN]; - _mav_put_float(buf, 0, mag_declination); - _mav_put_int32_t(buf, 4, raw_press); - _mav_put_int32_t(buf, 8, raw_temp); - _mav_put_float(buf, 12, gyro_cal_x); - _mav_put_float(buf, 16, gyro_cal_y); - _mav_put_float(buf, 20, gyro_cal_z); - _mav_put_float(buf, 24, accel_cal_x); - _mav_put_float(buf, 28, accel_cal_y); - _mav_put_float(buf, 32, accel_cal_z); - _mav_put_int16_t(buf, 36, mag_ofs_x); - _mav_put_int16_t(buf, 38, mag_ofs_y); - _mav_put_int16_t(buf, 40, mag_ofs_z); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); + char buf[MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN]; + _mav_put_float(buf, 0, mag_declination); + _mav_put_int32_t(buf, 4, raw_press); + _mav_put_int32_t(buf, 8, raw_temp); + _mav_put_float(buf, 12, gyro_cal_x); + _mav_put_float(buf, 16, gyro_cal_y); + _mav_put_float(buf, 20, gyro_cal_z); + _mav_put_float(buf, 24, accel_cal_x); + _mav_put_float(buf, 28, accel_cal_y); + _mav_put_float(buf, 32, accel_cal_z); + _mav_put_int16_t(buf, 36, mag_ofs_x); + _mav_put_int16_t(buf, 38, mag_ofs_y); + _mav_put_int16_t(buf, 40, mag_ofs_z); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); + mavlink_sensor_offsets_t packet; + packet.mag_declination = mag_declination; + packet.raw_press = raw_press; + packet.raw_temp = raw_temp; + packet.gyro_cal_x = gyro_cal_x; + packet.gyro_cal_y = gyro_cal_y; + packet.gyro_cal_z = gyro_cal_z; + packet.accel_cal_x = accel_cal_x; + packet.accel_cal_y = accel_cal_y; + packet.accel_cal_z = accel_cal_z; + packet.mag_ofs_x = mag_ofs_x; + packet.mag_ofs_y = mag_ofs_y; + packet.mag_ofs_z = mag_ofs_z; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, (const char *)&packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); #endif +} + +/** + * @brief Send a sensor_offsets message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_sensor_offsets_send_struct(mavlink_channel_t chan, const mavlink_sensor_offsets_t* sensor_offsets) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_sensor_offsets_send(chan, sensor_offsets->mag_ofs_x, sensor_offsets->mag_ofs_y, sensor_offsets->mag_ofs_z, sensor_offsets->mag_declination, sensor_offsets->raw_press, sensor_offsets->raw_temp, sensor_offsets->gyro_cal_x, sensor_offsets->gyro_cal_y, sensor_offsets->gyro_cal_z, sensor_offsets->accel_cal_x, sensor_offsets->accel_cal_y, sensor_offsets->accel_cal_z); #else - mavlink_sensor_offsets_t packet; - packet.mag_declination = mag_declination; - packet.raw_press = raw_press; - packet.raw_temp = raw_temp; - packet.gyro_cal_x = gyro_cal_x; - packet.gyro_cal_y = gyro_cal_y; - packet.gyro_cal_z = gyro_cal_z; - packet.accel_cal_x = accel_cal_x; - packet.accel_cal_y = accel_cal_y; - packet.accel_cal_z = accel_cal_z; - packet.mag_ofs_x = mag_ofs_x; - packet.mag_ofs_y = mag_ofs_y; - packet.mag_ofs_z = mag_ofs_z; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, (const char *)&packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, (const char *)&packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, (const char *)sensor_offsets, MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); #endif } @@ -278,45 +299,37 @@ static inline void mavlink_msg_sensor_offsets_send(mavlink_channel_t chan, int16 static inline void mavlink_msg_sensor_offsets_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z, float mag_declination, int32_t raw_press, int32_t raw_temp, float gyro_cal_x, float gyro_cal_y, float gyro_cal_z, float accel_cal_x, float accel_cal_y, float accel_cal_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, mag_declination); - _mav_put_int32_t(buf, 4, raw_press); - _mav_put_int32_t(buf, 8, raw_temp); - _mav_put_float(buf, 12, gyro_cal_x); - _mav_put_float(buf, 16, gyro_cal_y); - _mav_put_float(buf, 20, gyro_cal_z); - _mav_put_float(buf, 24, accel_cal_x); - _mav_put_float(buf, 28, accel_cal_y); - _mav_put_float(buf, 32, accel_cal_z); - _mav_put_int16_t(buf, 36, mag_ofs_x); - _mav_put_int16_t(buf, 38, mag_ofs_y); - _mav_put_int16_t(buf, 40, mag_ofs_z); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, mag_declination); + _mav_put_int32_t(buf, 4, raw_press); + _mav_put_int32_t(buf, 8, raw_temp); + _mav_put_float(buf, 12, gyro_cal_x); + _mav_put_float(buf, 16, gyro_cal_y); + _mav_put_float(buf, 20, gyro_cal_z); + _mav_put_float(buf, 24, accel_cal_x); + _mav_put_float(buf, 28, accel_cal_y); + _mav_put_float(buf, 32, accel_cal_z); + _mav_put_int16_t(buf, 36, mag_ofs_x); + _mav_put_int16_t(buf, 38, mag_ofs_y); + _mav_put_int16_t(buf, 40, mag_ofs_z); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, buf, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); -#endif -#else - mavlink_sensor_offsets_t *packet = (mavlink_sensor_offsets_t *)msgbuf; - packet->mag_declination = mag_declination; - packet->raw_press = raw_press; - packet->raw_temp = raw_temp; - packet->gyro_cal_x = gyro_cal_x; - packet->gyro_cal_y = gyro_cal_y; - packet->gyro_cal_z = gyro_cal_z; - packet->accel_cal_x = accel_cal_x; - packet->accel_cal_y = accel_cal_y; - packet->accel_cal_z = accel_cal_z; - packet->mag_ofs_x = mag_ofs_x; - packet->mag_ofs_y = mag_ofs_y; - packet->mag_ofs_z = mag_ofs_z; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, (const char *)packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, (const char *)packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); -#endif + mavlink_sensor_offsets_t *packet = (mavlink_sensor_offsets_t *)msgbuf; + packet->mag_declination = mag_declination; + packet->raw_press = raw_press; + packet->raw_temp = raw_temp; + packet->gyro_cal_x = gyro_cal_x; + packet->gyro_cal_y = gyro_cal_y; + packet->gyro_cal_z = gyro_cal_z; + packet->accel_cal_x = accel_cal_x; + packet->accel_cal_y = accel_cal_y; + packet->accel_cal_z = accel_cal_z; + packet->mag_ofs_x = mag_ofs_x; + packet->mag_ofs_y = mag_ofs_y; + packet->mag_ofs_z = mag_ofs_z; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SENSOR_OFFSETS, (const char *)packet, MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN, MAVLINK_MSG_ID_SENSOR_OFFSETS_CRC); #endif } #endif @@ -333,7 +346,7 @@ static inline void mavlink_msg_sensor_offsets_send_buf(mavlink_message_t *msgbuf */ static inline int16_t mavlink_msg_sensor_offsets_get_mag_ofs_x(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 36); + return _MAV_RETURN_int16_t(msg, 36); } /** @@ -343,7 +356,7 @@ static inline int16_t mavlink_msg_sensor_offsets_get_mag_ofs_x(const mavlink_mes */ static inline int16_t mavlink_msg_sensor_offsets_get_mag_ofs_y(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 38); + return _MAV_RETURN_int16_t(msg, 38); } /** @@ -353,7 +366,7 @@ static inline int16_t mavlink_msg_sensor_offsets_get_mag_ofs_y(const mavlink_mes */ static inline int16_t mavlink_msg_sensor_offsets_get_mag_ofs_z(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 40); + return _MAV_RETURN_int16_t(msg, 40); } /** @@ -363,7 +376,7 @@ static inline int16_t mavlink_msg_sensor_offsets_get_mag_ofs_z(const mavlink_mes */ static inline float mavlink_msg_sensor_offsets_get_mag_declination(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -373,7 +386,7 @@ static inline float mavlink_msg_sensor_offsets_get_mag_declination(const mavlink */ static inline int32_t mavlink_msg_sensor_offsets_get_raw_press(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -383,7 +396,7 @@ static inline int32_t mavlink_msg_sensor_offsets_get_raw_press(const mavlink_mes */ static inline int32_t mavlink_msg_sensor_offsets_get_raw_temp(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -393,7 +406,7 @@ static inline int32_t mavlink_msg_sensor_offsets_get_raw_temp(const mavlink_mess */ static inline float mavlink_msg_sensor_offsets_get_gyro_cal_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -403,7 +416,7 @@ static inline float mavlink_msg_sensor_offsets_get_gyro_cal_x(const mavlink_mess */ static inline float mavlink_msg_sensor_offsets_get_gyro_cal_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -413,7 +426,7 @@ static inline float mavlink_msg_sensor_offsets_get_gyro_cal_y(const mavlink_mess */ static inline float mavlink_msg_sensor_offsets_get_gyro_cal_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -423,7 +436,7 @@ static inline float mavlink_msg_sensor_offsets_get_gyro_cal_z(const mavlink_mess */ static inline float mavlink_msg_sensor_offsets_get_accel_cal_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -433,7 +446,7 @@ static inline float mavlink_msg_sensor_offsets_get_accel_cal_x(const mavlink_mes */ static inline float mavlink_msg_sensor_offsets_get_accel_cal_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -443,7 +456,7 @@ static inline float mavlink_msg_sensor_offsets_get_accel_cal_y(const mavlink_mes */ static inline float mavlink_msg_sensor_offsets_get_accel_cal_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -454,20 +467,22 @@ static inline float mavlink_msg_sensor_offsets_get_accel_cal_z(const mavlink_mes */ static inline void mavlink_msg_sensor_offsets_decode(const mavlink_message_t* msg, mavlink_sensor_offsets_t* sensor_offsets) { -#if MAVLINK_NEED_BYTE_SWAP - sensor_offsets->mag_declination = mavlink_msg_sensor_offsets_get_mag_declination(msg); - sensor_offsets->raw_press = mavlink_msg_sensor_offsets_get_raw_press(msg); - sensor_offsets->raw_temp = mavlink_msg_sensor_offsets_get_raw_temp(msg); - sensor_offsets->gyro_cal_x = mavlink_msg_sensor_offsets_get_gyro_cal_x(msg); - sensor_offsets->gyro_cal_y = mavlink_msg_sensor_offsets_get_gyro_cal_y(msg); - sensor_offsets->gyro_cal_z = mavlink_msg_sensor_offsets_get_gyro_cal_z(msg); - sensor_offsets->accel_cal_x = mavlink_msg_sensor_offsets_get_accel_cal_x(msg); - sensor_offsets->accel_cal_y = mavlink_msg_sensor_offsets_get_accel_cal_y(msg); - sensor_offsets->accel_cal_z = mavlink_msg_sensor_offsets_get_accel_cal_z(msg); - sensor_offsets->mag_ofs_x = mavlink_msg_sensor_offsets_get_mag_ofs_x(msg); - sensor_offsets->mag_ofs_y = mavlink_msg_sensor_offsets_get_mag_ofs_y(msg); - sensor_offsets->mag_ofs_z = mavlink_msg_sensor_offsets_get_mag_ofs_z(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + sensor_offsets->mag_declination = mavlink_msg_sensor_offsets_get_mag_declination(msg); + sensor_offsets->raw_press = mavlink_msg_sensor_offsets_get_raw_press(msg); + sensor_offsets->raw_temp = mavlink_msg_sensor_offsets_get_raw_temp(msg); + sensor_offsets->gyro_cal_x = mavlink_msg_sensor_offsets_get_gyro_cal_x(msg); + sensor_offsets->gyro_cal_y = mavlink_msg_sensor_offsets_get_gyro_cal_y(msg); + sensor_offsets->gyro_cal_z = mavlink_msg_sensor_offsets_get_gyro_cal_z(msg); + sensor_offsets->accel_cal_x = mavlink_msg_sensor_offsets_get_accel_cal_x(msg); + sensor_offsets->accel_cal_y = mavlink_msg_sensor_offsets_get_accel_cal_y(msg); + sensor_offsets->accel_cal_z = mavlink_msg_sensor_offsets_get_accel_cal_z(msg); + sensor_offsets->mag_ofs_x = mavlink_msg_sensor_offsets_get_mag_ofs_x(msg); + sensor_offsets->mag_ofs_y = mavlink_msg_sensor_offsets_get_mag_ofs_y(msg); + sensor_offsets->mag_ofs_z = mavlink_msg_sensor_offsets_get_mag_ofs_z(msg); #else - memcpy(sensor_offsets, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN? msg->len : MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN; + memset(sensor_offsets, 0, MAVLINK_MSG_ID_SENSOR_OFFSETS_LEN); + memcpy(sensor_offsets, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_set_mag_offsets.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_set_mag_offsets.h index fc6aa71e06..a8b4c180d2 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_set_mag_offsets.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_set_mag_offsets.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE SET_MAG_OFFSETS PACKING #define MAVLINK_MSG_ID_SET_MAG_OFFSETS 151 -typedef struct __mavlink_set_mag_offsets_t -{ - int16_t mag_ofs_x; ///< magnetometer X offset - int16_t mag_ofs_y; ///< magnetometer Y offset - int16_t mag_ofs_z; ///< magnetometer Z offset - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_set_mag_offsets_t; +MAVPACKED( +typedef struct __mavlink_set_mag_offsets_t { + int16_t mag_ofs_x; /*< magnetometer X offset*/ + int16_t mag_ofs_y; /*< magnetometer Y offset*/ + int16_t mag_ofs_z; /*< magnetometer Z offset*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_set_mag_offsets_t; #define MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN 8 +#define MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN 8 #define MAVLINK_MSG_ID_151_LEN 8 +#define MAVLINK_MSG_ID_151_MIN_LEN 8 #define MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC 219 #define MAVLINK_MSG_ID_151_CRC 219 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SET_MAG_OFFSETS { \ - "SET_MAG_OFFSETS", \ - 5, \ - { { "mag_ofs_x", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_set_mag_offsets_t, mag_ofs_x) }, \ + 151, \ + "SET_MAG_OFFSETS", \ + 5, \ + { { "mag_ofs_x", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_set_mag_offsets_t, mag_ofs_x) }, \ { "mag_ofs_y", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_set_mag_offsets_t, mag_ofs_y) }, \ { "mag_ofs_z", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_set_mag_offsets_t, mag_ofs_z) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_set_mag_offsets_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_set_mag_offsets_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SET_MAG_OFFSETS { \ + "SET_MAG_OFFSETS", \ + 5, \ + { { "mag_ofs_x", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_set_mag_offsets_t, mag_ofs_x) }, \ + { "mag_ofs_y", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_set_mag_offsets_t, mag_ofs_y) }, \ + { "mag_ofs_z", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_set_mag_offsets_t, mag_ofs_z) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_set_mag_offsets_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_set_mag_offsets_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a set_mag_offsets message @@ -45,34 +61,30 @@ typedef struct __mavlink_set_mag_offsets_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_mag_offsets_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z) + uint8_t target_system, uint8_t target_component, int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN]; - _mav_put_int16_t(buf, 0, mag_ofs_x); - _mav_put_int16_t(buf, 2, mag_ofs_y); - _mav_put_int16_t(buf, 4, mag_ofs_z); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); + char buf[MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN]; + _mav_put_int16_t(buf, 0, mag_ofs_x); + _mav_put_int16_t(buf, 2, mag_ofs_y); + _mav_put_int16_t(buf, 4, mag_ofs_z); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); #else - mavlink_set_mag_offsets_t packet; - packet.mag_ofs_x = mag_ofs_x; - packet.mag_ofs_y = mag_ofs_y; - packet.mag_ofs_z = mag_ofs_z; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_set_mag_offsets_t packet; + packet.mag_ofs_x = mag_ofs_x; + packet.mag_ofs_y = mag_ofs_y; + packet.mag_ofs_z = mag_ofs_z; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_MAG_OFFSETS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_MAG_OFFSETS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); } /** @@ -89,35 +101,31 @@ static inline uint16_t mavlink_msg_set_mag_offsets_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_mag_offsets_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,int16_t mag_ofs_x,int16_t mag_ofs_y,int16_t mag_ofs_z) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,int16_t mag_ofs_x,int16_t mag_ofs_y,int16_t mag_ofs_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN]; - _mav_put_int16_t(buf, 0, mag_ofs_x); - _mav_put_int16_t(buf, 2, mag_ofs_y); - _mav_put_int16_t(buf, 4, mag_ofs_z); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); + char buf[MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN]; + _mav_put_int16_t(buf, 0, mag_ofs_x); + _mav_put_int16_t(buf, 2, mag_ofs_y); + _mav_put_int16_t(buf, 4, mag_ofs_z); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); #else - mavlink_set_mag_offsets_t packet; - packet.mag_ofs_x = mag_ofs_x; - packet.mag_ofs_y = mag_ofs_y; - packet.mag_ofs_z = mag_ofs_z; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_set_mag_offsets_t packet; + packet.mag_ofs_x = mag_ofs_x; + packet.mag_ofs_y = mag_ofs_y; + packet.mag_ofs_z = mag_ofs_z; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_MAG_OFFSETS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_MAG_OFFSETS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); } /** @@ -130,7 +138,7 @@ static inline uint16_t mavlink_msg_set_mag_offsets_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_set_mag_offsets_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_mag_offsets_t* set_mag_offsets) { - return mavlink_msg_set_mag_offsets_pack(system_id, component_id, msg, set_mag_offsets->target_system, set_mag_offsets->target_component, set_mag_offsets->mag_ofs_x, set_mag_offsets->mag_ofs_y, set_mag_offsets->mag_ofs_z); + return mavlink_msg_set_mag_offsets_pack(system_id, component_id, msg, set_mag_offsets->target_system, set_mag_offsets->target_component, set_mag_offsets->mag_ofs_x, set_mag_offsets->mag_ofs_y, set_mag_offsets->mag_ofs_z); } /** @@ -144,7 +152,7 @@ static inline uint16_t mavlink_msg_set_mag_offsets_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_set_mag_offsets_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_mag_offsets_t* set_mag_offsets) { - return mavlink_msg_set_mag_offsets_pack_chan(system_id, component_id, chan, msg, set_mag_offsets->target_system, set_mag_offsets->target_component, set_mag_offsets->mag_ofs_x, set_mag_offsets->mag_ofs_y, set_mag_offsets->mag_ofs_z); + return mavlink_msg_set_mag_offsets_pack_chan(system_id, component_id, chan, msg, set_mag_offsets->target_system, set_mag_offsets->target_component, set_mag_offsets->mag_ofs_x, set_mag_offsets->mag_ofs_y, set_mag_offsets->mag_ofs_z); } /** @@ -162,31 +170,37 @@ static inline uint16_t mavlink_msg_set_mag_offsets_encode_chan(uint8_t system_id static inline void mavlink_msg_set_mag_offsets_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN]; - _mav_put_int16_t(buf, 0, mag_ofs_x); - _mav_put_int16_t(buf, 2, mag_ofs_y); - _mav_put_int16_t(buf, 4, mag_ofs_z); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); + char buf[MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN]; + _mav_put_int16_t(buf, 0, mag_ofs_x); + _mav_put_int16_t(buf, 2, mag_ofs_y); + _mav_put_int16_t(buf, 4, mag_ofs_z); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); + mavlink_set_mag_offsets_t packet; + packet.mag_ofs_x = mag_ofs_x; + packet.mag_ofs_y = mag_ofs_y; + packet.mag_ofs_z = mag_ofs_z; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, (const char *)&packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); #endif +} + +/** + * @brief Send a set_mag_offsets message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_mag_offsets_send_struct(mavlink_channel_t chan, const mavlink_set_mag_offsets_t* set_mag_offsets) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_mag_offsets_send(chan, set_mag_offsets->target_system, set_mag_offsets->target_component, set_mag_offsets->mag_ofs_x, set_mag_offsets->mag_ofs_y, set_mag_offsets->mag_ofs_z); #else - mavlink_set_mag_offsets_t packet; - packet.mag_ofs_x = mag_ofs_x; - packet.mag_ofs_y = mag_ofs_y; - packet.mag_ofs_z = mag_ofs_z; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, (const char *)&packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, (const char *)&packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, (const char *)set_mag_offsets, MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); #endif } @@ -201,31 +215,23 @@ static inline void mavlink_msg_set_mag_offsets_send(mavlink_channel_t chan, uint static inline void mavlink_msg_set_mag_offsets_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t mag_ofs_x, int16_t mag_ofs_y, int16_t mag_ofs_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int16_t(buf, 0, mag_ofs_x); - _mav_put_int16_t(buf, 2, mag_ofs_y); - _mav_put_int16_t(buf, 4, mag_ofs_z); - _mav_put_uint8_t(buf, 6, target_system); - _mav_put_uint8_t(buf, 7, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); + char *buf = (char *)msgbuf; + _mav_put_int16_t(buf, 0, mag_ofs_x); + _mav_put_int16_t(buf, 2, mag_ofs_y); + _mav_put_int16_t(buf, 4, mag_ofs_z); + _mav_put_uint8_t(buf, 6, target_system); + _mav_put_uint8_t(buf, 7, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, buf, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); -#endif -#else - mavlink_set_mag_offsets_t *packet = (mavlink_set_mag_offsets_t *)msgbuf; - packet->mag_ofs_x = mag_ofs_x; - packet->mag_ofs_y = mag_ofs_y; - packet->mag_ofs_z = mag_ofs_z; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, (const char *)packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, (const char *)packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); -#endif + mavlink_set_mag_offsets_t *packet = (mavlink_set_mag_offsets_t *)msgbuf; + packet->mag_ofs_x = mag_ofs_x; + packet->mag_ofs_y = mag_ofs_y; + packet->mag_ofs_z = mag_ofs_z; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MAG_OFFSETS, (const char *)packet, MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN, MAVLINK_MSG_ID_SET_MAG_OFFSETS_CRC); #endif } #endif @@ -242,7 +248,7 @@ static inline void mavlink_msg_set_mag_offsets_send_buf(mavlink_message_t *msgbu */ static inline uint8_t mavlink_msg_set_mag_offsets_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -252,7 +258,7 @@ static inline uint8_t mavlink_msg_set_mag_offsets_get_target_system(const mavlin */ static inline uint8_t mavlink_msg_set_mag_offsets_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -262,7 +268,7 @@ static inline uint8_t mavlink_msg_set_mag_offsets_get_target_component(const mav */ static inline int16_t mavlink_msg_set_mag_offsets_get_mag_ofs_x(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 0); + return _MAV_RETURN_int16_t(msg, 0); } /** @@ -272,7 +278,7 @@ static inline int16_t mavlink_msg_set_mag_offsets_get_mag_ofs_x(const mavlink_me */ static inline int16_t mavlink_msg_set_mag_offsets_get_mag_ofs_y(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 2); + return _MAV_RETURN_int16_t(msg, 2); } /** @@ -282,7 +288,7 @@ static inline int16_t mavlink_msg_set_mag_offsets_get_mag_ofs_y(const mavlink_me */ static inline int16_t mavlink_msg_set_mag_offsets_get_mag_ofs_z(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 4); + return _MAV_RETURN_int16_t(msg, 4); } /** @@ -293,13 +299,15 @@ static inline int16_t mavlink_msg_set_mag_offsets_get_mag_ofs_z(const mavlink_me */ static inline void mavlink_msg_set_mag_offsets_decode(const mavlink_message_t* msg, mavlink_set_mag_offsets_t* set_mag_offsets) { -#if MAVLINK_NEED_BYTE_SWAP - set_mag_offsets->mag_ofs_x = mavlink_msg_set_mag_offsets_get_mag_ofs_x(msg); - set_mag_offsets->mag_ofs_y = mavlink_msg_set_mag_offsets_get_mag_ofs_y(msg); - set_mag_offsets->mag_ofs_z = mavlink_msg_set_mag_offsets_get_mag_ofs_z(msg); - set_mag_offsets->target_system = mavlink_msg_set_mag_offsets_get_target_system(msg); - set_mag_offsets->target_component = mavlink_msg_set_mag_offsets_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_mag_offsets->mag_ofs_x = mavlink_msg_set_mag_offsets_get_mag_ofs_x(msg); + set_mag_offsets->mag_ofs_y = mavlink_msg_set_mag_offsets_get_mag_ofs_y(msg); + set_mag_offsets->mag_ofs_z = mavlink_msg_set_mag_offsets_get_mag_ofs_z(msg); + set_mag_offsets->target_system = mavlink_msg_set_mag_offsets_get_target_system(msg); + set_mag_offsets->target_component = mavlink_msg_set_mag_offsets_get_target_component(msg); #else - memcpy(set_mag_offsets, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN? msg->len : MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN; + memset(set_mag_offsets, 0, MAVLINK_MSG_ID_SET_MAG_OFFSETS_LEN); + memcpy(set_mag_offsets, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_simstate.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_simstate.h index 48cfb6ffd5..6f7968d6d7 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_simstate.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_simstate.h @@ -1,34 +1,39 @@ +#pragma once // MESSAGE SIMSTATE PACKING #define MAVLINK_MSG_ID_SIMSTATE 164 -typedef struct __mavlink_simstate_t -{ - float roll; ///< Roll angle (rad) - float pitch; ///< Pitch angle (rad) - float yaw; ///< Yaw angle (rad) - float xacc; ///< X acceleration m/s/s - float yacc; ///< Y acceleration m/s/s - float zacc; ///< Z acceleration m/s/s - float xgyro; ///< Angular speed around X axis rad/s - float ygyro; ///< Angular speed around Y axis rad/s - float zgyro; ///< Angular speed around Z axis rad/s - int32_t lat; ///< Latitude in degrees * 1E7 - int32_t lng; ///< Longitude in degrees * 1E7 -} mavlink_simstate_t; +MAVPACKED( +typedef struct __mavlink_simstate_t { + float roll; /*< Roll angle (rad)*/ + float pitch; /*< Pitch angle (rad)*/ + float yaw; /*< Yaw angle (rad)*/ + float xacc; /*< X acceleration m/s/s*/ + float yacc; /*< Y acceleration m/s/s*/ + float zacc; /*< Z acceleration m/s/s*/ + float xgyro; /*< Angular speed around X axis rad/s*/ + float ygyro; /*< Angular speed around Y axis rad/s*/ + float zgyro; /*< Angular speed around Z axis rad/s*/ + int32_t lat; /*< Latitude in degrees * 1E7*/ + int32_t lng; /*< Longitude in degrees * 1E7*/ +}) mavlink_simstate_t; #define MAVLINK_MSG_ID_SIMSTATE_LEN 44 +#define MAVLINK_MSG_ID_SIMSTATE_MIN_LEN 44 #define MAVLINK_MSG_ID_164_LEN 44 +#define MAVLINK_MSG_ID_164_MIN_LEN 44 #define MAVLINK_MSG_ID_SIMSTATE_CRC 154 #define MAVLINK_MSG_ID_164_CRC 154 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SIMSTATE { \ - "SIMSTATE", \ - 11, \ - { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_simstate_t, roll) }, \ + 164, \ + "SIMSTATE", \ + 11, \ + { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_simstate_t, roll) }, \ { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_simstate_t, pitch) }, \ { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_simstate_t, yaw) }, \ { "xacc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_simstate_t, xacc) }, \ @@ -41,7 +46,24 @@ typedef struct __mavlink_simstate_t { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 40, offsetof(mavlink_simstate_t, lng) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SIMSTATE { \ + "SIMSTATE", \ + 11, \ + { { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_simstate_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_simstate_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_simstate_t, yaw) }, \ + { "xacc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_simstate_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_simstate_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_simstate_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_simstate_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_simstate_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_simstate_t, zgyro) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 36, offsetof(mavlink_simstate_t, lat) }, \ + { "lng", NULL, MAVLINK_TYPE_INT32_T, 0, 40, offsetof(mavlink_simstate_t, lng) }, \ + } \ +} +#endif /** * @brief Pack a simstate message @@ -63,46 +85,42 @@ typedef struct __mavlink_simstate_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_simstate_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, int32_t lat, int32_t lng) + float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, xacc); - _mav_put_float(buf, 16, yacc); - _mav_put_float(buf, 20, zacc); - _mav_put_float(buf, 24, xgyro); - _mav_put_float(buf, 28, ygyro); - _mav_put_float(buf, 32, zgyro); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lng); + char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, xacc); + _mav_put_float(buf, 16, yacc); + _mav_put_float(buf, 20, zacc); + _mav_put_float(buf, 24, xgyro); + _mav_put_float(buf, 28, ygyro); + _mav_put_float(buf, 32, zgyro); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lng); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SIMSTATE_LEN); #else - mavlink_simstate_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.lat = lat; - packet.lng = lng; + mavlink_simstate_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.lat = lat; + packet.lng = lng; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SIMSTATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SIMSTATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SIMSTATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SIMSTATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SIMSTATE_MIN_LEN, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); } /** @@ -125,47 +143,43 @@ static inline uint16_t mavlink_msg_simstate_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_simstate_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float roll,float pitch,float yaw,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,int32_t lat,int32_t lng) + mavlink_message_t* msg, + float roll,float pitch,float yaw,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,int32_t lat,int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, xacc); - _mav_put_float(buf, 16, yacc); - _mav_put_float(buf, 20, zacc); - _mav_put_float(buf, 24, xgyro); - _mav_put_float(buf, 28, ygyro); - _mav_put_float(buf, 32, zgyro); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lng); + char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, xacc); + _mav_put_float(buf, 16, yacc); + _mav_put_float(buf, 20, zacc); + _mav_put_float(buf, 24, xgyro); + _mav_put_float(buf, 28, ygyro); + _mav_put_float(buf, 32, zgyro); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lng); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SIMSTATE_LEN); #else - mavlink_simstate_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.lat = lat; - packet.lng = lng; + mavlink_simstate_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.lat = lat; + packet.lng = lng; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SIMSTATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SIMSTATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SIMSTATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SIMSTATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SIMSTATE_MIN_LEN, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); } /** @@ -178,7 +192,7 @@ static inline uint16_t mavlink_msg_simstate_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_simstate_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_simstate_t* simstate) { - return mavlink_msg_simstate_pack(system_id, component_id, msg, simstate->roll, simstate->pitch, simstate->yaw, simstate->xacc, simstate->yacc, simstate->zacc, simstate->xgyro, simstate->ygyro, simstate->zgyro, simstate->lat, simstate->lng); + return mavlink_msg_simstate_pack(system_id, component_id, msg, simstate->roll, simstate->pitch, simstate->yaw, simstate->xacc, simstate->yacc, simstate->zacc, simstate->xgyro, simstate->ygyro, simstate->zgyro, simstate->lat, simstate->lng); } /** @@ -192,7 +206,7 @@ static inline uint16_t mavlink_msg_simstate_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_simstate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_simstate_t* simstate) { - return mavlink_msg_simstate_pack_chan(system_id, component_id, chan, msg, simstate->roll, simstate->pitch, simstate->yaw, simstate->xacc, simstate->yacc, simstate->zacc, simstate->xgyro, simstate->ygyro, simstate->zgyro, simstate->lat, simstate->lng); + return mavlink_msg_simstate_pack_chan(system_id, component_id, chan, msg, simstate->roll, simstate->pitch, simstate->yaw, simstate->xacc, simstate->yacc, simstate->zacc, simstate->xgyro, simstate->ygyro, simstate->zgyro, simstate->lat, simstate->lng); } /** @@ -216,43 +230,49 @@ static inline uint16_t mavlink_msg_simstate_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_simstate_send(mavlink_channel_t chan, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, xacc); - _mav_put_float(buf, 16, yacc); - _mav_put_float(buf, 20, zacc); - _mav_put_float(buf, 24, xgyro); - _mav_put_float(buf, 28, ygyro); - _mav_put_float(buf, 32, zgyro); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lng); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, buf, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); + char buf[MAVLINK_MSG_ID_SIMSTATE_LEN]; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, xacc); + _mav_put_float(buf, 16, yacc); + _mav_put_float(buf, 20, zacc); + _mav_put_float(buf, 24, xgyro); + _mav_put_float(buf, 28, ygyro); + _mav_put_float(buf, 32, zgyro); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lng); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, buf, MAVLINK_MSG_ID_SIMSTATE_MIN_LEN, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, buf, MAVLINK_MSG_ID_SIMSTATE_LEN); + mavlink_simstate_t packet; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.lat = lat; + packet.lng = lng; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, (const char *)&packet, MAVLINK_MSG_ID_SIMSTATE_MIN_LEN, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); #endif +} + +/** + * @brief Send a simstate message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_simstate_send_struct(mavlink_channel_t chan, const mavlink_simstate_t* simstate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_simstate_send(chan, simstate->roll, simstate->pitch, simstate->yaw, simstate->xacc, simstate->yacc, simstate->zacc, simstate->xgyro, simstate->ygyro, simstate->zgyro, simstate->lat, simstate->lng); #else - mavlink_simstate_t packet; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.lat = lat; - packet.lng = lng; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, (const char *)&packet, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, (const char *)&packet, MAVLINK_MSG_ID_SIMSTATE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, (const char *)simstate, MAVLINK_MSG_ID_SIMSTATE_MIN_LEN, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); #endif } @@ -267,43 +287,35 @@ static inline void mavlink_msg_simstate_send(mavlink_channel_t chan, float roll, static inline void mavlink_msg_simstate_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, int32_t lat, int32_t lng) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, roll); - _mav_put_float(buf, 4, pitch); - _mav_put_float(buf, 8, yaw); - _mav_put_float(buf, 12, xacc); - _mav_put_float(buf, 16, yacc); - _mav_put_float(buf, 20, zacc); - _mav_put_float(buf, 24, xgyro); - _mav_put_float(buf, 28, ygyro); - _mav_put_float(buf, 32, zgyro); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lng); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, buf, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, roll); + _mav_put_float(buf, 4, pitch); + _mav_put_float(buf, 8, yaw); + _mav_put_float(buf, 12, xacc); + _mav_put_float(buf, 16, yacc); + _mav_put_float(buf, 20, zacc); + _mav_put_float(buf, 24, xgyro); + _mav_put_float(buf, 28, ygyro); + _mav_put_float(buf, 32, zgyro); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lng); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, buf, MAVLINK_MSG_ID_SIMSTATE_MIN_LEN, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, buf, MAVLINK_MSG_ID_SIMSTATE_LEN); -#endif -#else - mavlink_simstate_t *packet = (mavlink_simstate_t *)msgbuf; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - packet->xgyro = xgyro; - packet->ygyro = ygyro; - packet->zgyro = zgyro; - packet->lat = lat; - packet->lng = lng; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, (const char *)packet, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, (const char *)packet, MAVLINK_MSG_ID_SIMSTATE_LEN); -#endif + mavlink_simstate_t *packet = (mavlink_simstate_t *)msgbuf; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->lat = lat; + packet->lng = lng; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIMSTATE, (const char *)packet, MAVLINK_MSG_ID_SIMSTATE_MIN_LEN, MAVLINK_MSG_ID_SIMSTATE_LEN, MAVLINK_MSG_ID_SIMSTATE_CRC); #endif } #endif @@ -320,7 +332,7 @@ static inline void mavlink_msg_simstate_send_buf(mavlink_message_t *msgbuf, mavl */ static inline float mavlink_msg_simstate_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -330,7 +342,7 @@ static inline float mavlink_msg_simstate_get_roll(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -340,7 +352,7 @@ static inline float mavlink_msg_simstate_get_pitch(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -350,7 +362,7 @@ static inline float mavlink_msg_simstate_get_yaw(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -360,7 +372,7 @@ static inline float mavlink_msg_simstate_get_xacc(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -370,7 +382,7 @@ static inline float mavlink_msg_simstate_get_yacc(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -380,7 +392,7 @@ static inline float mavlink_msg_simstate_get_zacc(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -390,7 +402,7 @@ static inline float mavlink_msg_simstate_get_xgyro(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -400,7 +412,7 @@ static inline float mavlink_msg_simstate_get_ygyro(const mavlink_message_t* msg) */ static inline float mavlink_msg_simstate_get_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -410,7 +422,7 @@ static inline float mavlink_msg_simstate_get_zgyro(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_simstate_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 36); + return _MAV_RETURN_int32_t(msg, 36); } /** @@ -420,7 +432,7 @@ static inline int32_t mavlink_msg_simstate_get_lat(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_simstate_get_lng(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 40); + return _MAV_RETURN_int32_t(msg, 40); } /** @@ -431,19 +443,21 @@ static inline int32_t mavlink_msg_simstate_get_lng(const mavlink_message_t* msg) */ static inline void mavlink_msg_simstate_decode(const mavlink_message_t* msg, mavlink_simstate_t* simstate) { -#if MAVLINK_NEED_BYTE_SWAP - simstate->roll = mavlink_msg_simstate_get_roll(msg); - simstate->pitch = mavlink_msg_simstate_get_pitch(msg); - simstate->yaw = mavlink_msg_simstate_get_yaw(msg); - simstate->xacc = mavlink_msg_simstate_get_xacc(msg); - simstate->yacc = mavlink_msg_simstate_get_yacc(msg); - simstate->zacc = mavlink_msg_simstate_get_zacc(msg); - simstate->xgyro = mavlink_msg_simstate_get_xgyro(msg); - simstate->ygyro = mavlink_msg_simstate_get_ygyro(msg); - simstate->zgyro = mavlink_msg_simstate_get_zgyro(msg); - simstate->lat = mavlink_msg_simstate_get_lat(msg); - simstate->lng = mavlink_msg_simstate_get_lng(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + simstate->roll = mavlink_msg_simstate_get_roll(msg); + simstate->pitch = mavlink_msg_simstate_get_pitch(msg); + simstate->yaw = mavlink_msg_simstate_get_yaw(msg); + simstate->xacc = mavlink_msg_simstate_get_xacc(msg); + simstate->yacc = mavlink_msg_simstate_get_yacc(msg); + simstate->zacc = mavlink_msg_simstate_get_zacc(msg); + simstate->xgyro = mavlink_msg_simstate_get_xgyro(msg); + simstate->ygyro = mavlink_msg_simstate_get_ygyro(msg); + simstate->zgyro = mavlink_msg_simstate_get_zgyro(msg); + simstate->lat = mavlink_msg_simstate_get_lat(msg); + simstate->lng = mavlink_msg_simstate_get_lng(msg); #else - memcpy(simstate, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SIMSTATE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SIMSTATE_LEN? msg->len : MAVLINK_MSG_ID_SIMSTATE_LEN; + memset(simstate, 0, MAVLINK_MSG_ID_SIMSTATE_LEN); + memcpy(simstate, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_wind.h b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_wind.h index 5d5edc4cc3..83b19f126a 100644 --- a/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_wind.h +++ b/vendor/libraries/mavlink/ardupilotmega/mavlink_msg_wind.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE WIND PACKING #define MAVLINK_MSG_ID_WIND 168 -typedef struct __mavlink_wind_t -{ - float direction; ///< wind direction that wind is coming from (degrees) - float speed; ///< wind speed in ground plane (m/s) - float speed_z; ///< vertical wind speed (m/s) -} mavlink_wind_t; +MAVPACKED( +typedef struct __mavlink_wind_t { + float direction; /*< wind direction that wind is coming from (degrees)*/ + float speed; /*< wind speed in ground plane (m/s)*/ + float speed_z; /*< vertical wind speed (m/s)*/ +}) mavlink_wind_t; #define MAVLINK_MSG_ID_WIND_LEN 12 +#define MAVLINK_MSG_ID_WIND_MIN_LEN 12 #define MAVLINK_MSG_ID_168_LEN 12 +#define MAVLINK_MSG_ID_168_MIN_LEN 12 #define MAVLINK_MSG_ID_WIND_CRC 1 #define MAVLINK_MSG_ID_168_CRC 1 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_WIND { \ - "WIND", \ - 3, \ - { { "direction", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_wind_t, direction) }, \ + 168, \ + "WIND", \ + 3, \ + { { "direction", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_wind_t, direction) }, \ { "speed", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_wind_t, speed) }, \ { "speed_z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_wind_t, speed_z) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_WIND { \ + "WIND", \ + 3, \ + { { "direction", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_wind_t, direction) }, \ + { "speed", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_wind_t, speed) }, \ + { "speed_z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_wind_t, speed_z) }, \ + } \ +} +#endif /** * @brief Pack a wind message @@ -39,30 +53,26 @@ typedef struct __mavlink_wind_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_wind_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float direction, float speed, float speed_z) + float direction, float speed, float speed_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_WIND_LEN]; - _mav_put_float(buf, 0, direction); - _mav_put_float(buf, 4, speed); - _mav_put_float(buf, 8, speed_z); + char buf[MAVLINK_MSG_ID_WIND_LEN]; + _mav_put_float(buf, 0, direction); + _mav_put_float(buf, 4, speed); + _mav_put_float(buf, 8, speed_z); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_WIND_LEN); #else - mavlink_wind_t packet; - packet.direction = direction; - packet.speed = speed; - packet.speed_z = speed_z; + mavlink_wind_t packet; + packet.direction = direction; + packet.speed = speed; + packet.speed_z = speed_z; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_WIND_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_WIND; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_WIND_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_WIND; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_WIND_MIN_LEN, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_wind_pack(uint8_t system_id, uint8_t componen * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_wind_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float direction,float speed,float speed_z) + mavlink_message_t* msg, + float direction,float speed,float speed_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_WIND_LEN]; - _mav_put_float(buf, 0, direction); - _mav_put_float(buf, 4, speed); - _mav_put_float(buf, 8, speed_z); + char buf[MAVLINK_MSG_ID_WIND_LEN]; + _mav_put_float(buf, 0, direction); + _mav_put_float(buf, 4, speed); + _mav_put_float(buf, 8, speed_z); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_WIND_LEN); #else - mavlink_wind_t packet; - packet.direction = direction; - packet.speed = speed; - packet.speed_z = speed_z; + mavlink_wind_t packet; + packet.direction = direction; + packet.speed = speed; + packet.speed_z = speed_z; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_WIND_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_WIND; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_WIND_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_WIND; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_WIND_MIN_LEN, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_wind_pack_chan(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_wind_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_wind_t* wind) { - return mavlink_msg_wind_pack(system_id, component_id, msg, wind->direction, wind->speed, wind->speed_z); + return mavlink_msg_wind_pack(system_id, component_id, msg, wind->direction, wind->speed, wind->speed_z); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_wind_encode(uint8_t system_id, uint8_t compon */ static inline uint16_t mavlink_msg_wind_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_wind_t* wind) { - return mavlink_msg_wind_pack_chan(system_id, component_id, chan, msg, wind->direction, wind->speed, wind->speed_z); + return mavlink_msg_wind_pack_chan(system_id, component_id, chan, msg, wind->direction, wind->speed, wind->speed_z); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_wind_encode_chan(uint8_t system_id, uint8_t c static inline void mavlink_msg_wind_send(mavlink_channel_t chan, float direction, float speed, float speed_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_WIND_LEN]; - _mav_put_float(buf, 0, direction); - _mav_put_float(buf, 4, speed); - _mav_put_float(buf, 8, speed_z); + char buf[MAVLINK_MSG_ID_WIND_LEN]; + _mav_put_float(buf, 0, direction); + _mav_put_float(buf, 4, speed); + _mav_put_float(buf, 8, speed_z); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, buf, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, buf, MAVLINK_MSG_ID_WIND_MIN_LEN, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, buf, MAVLINK_MSG_ID_WIND_LEN); + mavlink_wind_t packet; + packet.direction = direction; + packet.speed = speed; + packet.speed_z = speed_z; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, (const char *)&packet, MAVLINK_MSG_ID_WIND_MIN_LEN, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); #endif -#else - mavlink_wind_t packet; - packet.direction = direction; - packet.speed = speed; - packet.speed_z = speed_z; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, (const char *)&packet, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); +/** + * @brief Send a wind message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_wind_send_struct(mavlink_channel_t chan, const mavlink_wind_t* wind) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_wind_send(chan, wind->direction, wind->speed, wind->speed_z); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, (const char *)&packet, MAVLINK_MSG_ID_WIND_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, (const char *)wind, MAVLINK_MSG_ID_WIND_MIN_LEN, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_wind_send(mavlink_channel_t chan, float direction static inline void mavlink_msg_wind_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float direction, float speed, float speed_z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, direction); - _mav_put_float(buf, 4, speed); - _mav_put_float(buf, 8, speed_z); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, direction); + _mav_put_float(buf, 4, speed); + _mav_put_float(buf, 8, speed_z); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, buf, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, buf, MAVLINK_MSG_ID_WIND_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, buf, MAVLINK_MSG_ID_WIND_MIN_LEN, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); #else - mavlink_wind_t *packet = (mavlink_wind_t *)msgbuf; - packet->direction = direction; - packet->speed = speed; - packet->speed_z = speed_z; + mavlink_wind_t *packet = (mavlink_wind_t *)msgbuf; + packet->direction = direction; + packet->speed = speed; + packet->speed_z = speed_z; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, (const char *)packet, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, (const char *)packet, MAVLINK_MSG_ID_WIND_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND, (const char *)packet, MAVLINK_MSG_ID_WIND_MIN_LEN, MAVLINK_MSG_ID_WIND_LEN, MAVLINK_MSG_ID_WIND_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_wind_send_buf(mavlink_message_t *msgbuf, mavlink_ */ static inline float mavlink_msg_wind_get_direction(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -226,7 +230,7 @@ static inline float mavlink_msg_wind_get_direction(const mavlink_message_t* msg) */ static inline float mavlink_msg_wind_get_speed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -236,7 +240,7 @@ static inline float mavlink_msg_wind_get_speed(const mavlink_message_t* msg) */ static inline float mavlink_msg_wind_get_speed_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -247,11 +251,13 @@ static inline float mavlink_msg_wind_get_speed_z(const mavlink_message_t* msg) */ static inline void mavlink_msg_wind_decode(const mavlink_message_t* msg, mavlink_wind_t* wind) { -#if MAVLINK_NEED_BYTE_SWAP - wind->direction = mavlink_msg_wind_get_direction(msg); - wind->speed = mavlink_msg_wind_get_speed(msg); - wind->speed_z = mavlink_msg_wind_get_speed_z(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + wind->direction = mavlink_msg_wind_get_direction(msg); + wind->speed = mavlink_msg_wind_get_speed(msg); + wind->speed_z = mavlink_msg_wind_get_speed_z(msg); #else - memcpy(wind, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_WIND_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_WIND_LEN? msg->len : MAVLINK_MSG_ID_WIND_LEN; + memset(wind, 0, MAVLINK_MSG_ID_WIND_LEN); + memcpy(wind, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/ardupilotmega/testsuite.h b/vendor/libraries/mavlink/ardupilotmega/testsuite.h index 198818aeba..f997f7d2d9 100644 --- a/vendor/libraries/mavlink/ardupilotmega/testsuite.h +++ b/vendor/libraries/mavlink/ardupilotmega/testsuite.h @@ -1,7 +1,8 @@ /** @file - * @brief MAVLink comm protocol testsuite generated from ardupilotmega.xml - * @see http://qgroundcontrol.org/mavlink/ + * @brief MAVLink comm protocol testsuite generated from ardupilotmega.xml + * @see http://qgroundcontrol.org/mavlink/ */ +#pragma once #ifndef ARDUPILOTMEGA_TESTSUITE_H #define ARDUPILOTMEGA_TESTSUITE_H @@ -12,1747 +13,2960 @@ extern "C" { #ifndef MAVLINK_TEST_ALL #define MAVLINK_TEST_ALL static void mavlink_test_common(uint8_t, uint8_t, mavlink_message_t *last_msg); +static void mavlink_test_uAvionix(uint8_t, uint8_t, mavlink_message_t *last_msg); static void mavlink_test_ardupilotmega(uint8_t, uint8_t, mavlink_message_t *last_msg); static void mavlink_test_all(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg) { - mavlink_test_common(system_id, component_id, last_msg); - mavlink_test_ardupilotmega(system_id, component_id, last_msg); + mavlink_test_common(system_id, component_id, last_msg); + mavlink_test_uAvionix(system_id, component_id, last_msg); + mavlink_test_ardupilotmega(system_id, component_id, last_msg); } #endif #include "../common/testsuite.h" +#include "../uAvionix/testsuite.h" static void mavlink_test_sensor_offsets(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg) { - mavlink_message_t msg; +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + mavlink_status_t *status = mavlink_get_channel_status(MAVLINK_COMM_0); + if ((status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SENSOR_OFFSETS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_sensor_offsets_t packet_in = { - 17.0,963497672,963497880,101.0,129.0,157.0,185.0,213.0,241.0,19107,19211,19315 + mavlink_sensor_offsets_t packet_in = { + 17.0,963497672,963497880,101.0,129.0,157.0,185.0,213.0,241.0,19107,19211,19315 }; - mavlink_sensor_offsets_t packet1, packet2; + mavlink_sensor_offsets_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.mag_declination = packet_in.mag_declination; - packet1.raw_press = packet_in.raw_press; - packet1.raw_temp = packet_in.raw_temp; - packet1.gyro_cal_x = packet_in.gyro_cal_x; - packet1.gyro_cal_y = packet_in.gyro_cal_y; - packet1.gyro_cal_z = packet_in.gyro_cal_z; - packet1.accel_cal_x = packet_in.accel_cal_x; - packet1.accel_cal_y = packet_in.accel_cal_y; - packet1.accel_cal_z = packet_in.accel_cal_z; - packet1.mag_ofs_x = packet_in.mag_ofs_x; - packet1.mag_ofs_y = packet_in.mag_ofs_y; - packet1.mag_ofs_z = packet_in.mag_ofs_z; - - - + packet1.mag_declination = packet_in.mag_declination; + packet1.raw_press = packet_in.raw_press; + packet1.raw_temp = packet_in.raw_temp; + packet1.gyro_cal_x = packet_in.gyro_cal_x; + packet1.gyro_cal_y = packet_in.gyro_cal_y; + packet1.gyro_cal_z = packet_in.gyro_cal_z; + packet1.accel_cal_x = packet_in.accel_cal_x; + packet1.accel_cal_y = packet_in.accel_cal_y; + packet1.accel_cal_z = packet_in.accel_cal_z; + packet1.mag_ofs_x = packet_in.mag_ofs_x; + packet1.mag_ofs_y = packet_in.mag_ofs_y; + packet1.mag_ofs_z = packet_in.mag_ofs_z; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SENSOR_OFFSETS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sensor_offsets_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_sensor_offsets_decode(&msg, &packet2); + mavlink_msg_sensor_offsets_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_sensor_offsets_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sensor_offsets_pack(system_id, component_id, &msg , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z , packet1.mag_declination , packet1.raw_press , packet1.raw_temp , packet1.gyro_cal_x , packet1.gyro_cal_y , packet1.gyro_cal_z , packet1.accel_cal_x , packet1.accel_cal_y , packet1.accel_cal_z ); - mavlink_msg_sensor_offsets_decode(&msg, &packet2); + mavlink_msg_sensor_offsets_pack(system_id, component_id, &msg , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z , packet1.mag_declination , packet1.raw_press , packet1.raw_temp , packet1.gyro_cal_x , packet1.gyro_cal_y , packet1.gyro_cal_z , packet1.accel_cal_x , packet1.accel_cal_y , packet1.accel_cal_z ); + mavlink_msg_sensor_offsets_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sensor_offsets_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z , packet1.mag_declination , packet1.raw_press , packet1.raw_temp , packet1.gyro_cal_x , packet1.gyro_cal_y , packet1.gyro_cal_z , packet1.accel_cal_x , packet1.accel_cal_y , packet1.accel_cal_z ); - mavlink_msg_sensor_offsets_decode(&msg, &packet2); + mavlink_msg_sensor_offsets_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z , packet1.mag_declination , packet1.raw_press , packet1.raw_temp , packet1.gyro_cal_x , packet1.gyro_cal_y , packet1.gyro_cal_z , packet1.accel_cal_x , packet1.accel_cal_y , packet1.accel_cal_z ); + mavlink_msg_sensor_offsets_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_MAG_OFFSETS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_set_mag_offsets_t packet_in = { - 17235,17339,17443,151,218 + mavlink_set_mag_offsets_t packet_in = { + 17235,17339,17443,151,218 }; - mavlink_set_mag_offsets_t packet1, packet2; + mavlink_set_mag_offsets_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.mag_ofs_x = packet_in.mag_ofs_x; - packet1.mag_ofs_y = packet_in.mag_ofs_y; - packet1.mag_ofs_z = packet_in.mag_ofs_z; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.mag_ofs_x = packet_in.mag_ofs_x; + packet1.mag_ofs_y = packet_in.mag_ofs_y; + packet1.mag_ofs_z = packet_in.mag_ofs_z; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_MAG_OFFSETS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_mag_offsets_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_set_mag_offsets_decode(&msg, &packet2); + mavlink_msg_set_mag_offsets_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_mag_offsets_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_mag_offsets_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z ); - mavlink_msg_set_mag_offsets_decode(&msg, &packet2); + mavlink_msg_set_mag_offsets_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z ); + mavlink_msg_set_mag_offsets_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_mag_offsets_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z ); - mavlink_msg_set_mag_offsets_decode(&msg, &packet2); + mavlink_msg_set_mag_offsets_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.mag_ofs_x , packet1.mag_ofs_y , packet1.mag_ofs_z ); + mavlink_msg_set_mag_offsets_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MEMINFO >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_meminfo_t packet_in = { - 17235,17339 + mavlink_meminfo_t packet_in = { + 17235,17339 }; - mavlink_meminfo_t packet1, packet2; + mavlink_meminfo_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.brkval = packet_in.brkval; - packet1.freemem = packet_in.freemem; + packet1.brkval = packet_in.brkval; + packet1.freemem = packet_in.freemem; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MEMINFO_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MEMINFO_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_meminfo_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_meminfo_decode(&msg, &packet2); + mavlink_msg_meminfo_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_meminfo_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_meminfo_pack(system_id, component_id, &msg , packet1.brkval , packet1.freemem ); - mavlink_msg_meminfo_decode(&msg, &packet2); + mavlink_msg_meminfo_pack(system_id, component_id, &msg , packet1.brkval , packet1.freemem ); + mavlink_msg_meminfo_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_meminfo_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.brkval , packet1.freemem ); - mavlink_msg_meminfo_decode(&msg, &packet2); + mavlink_msg_meminfo_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.brkval , packet1.freemem ); + mavlink_msg_meminfo_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AP_ADC >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_ap_adc_t packet_in = { - 17235,17339,17443,17547,17651,17755 + mavlink_ap_adc_t packet_in = { + 17235,17339,17443,17547,17651,17755 }; - mavlink_ap_adc_t packet1, packet2; + mavlink_ap_adc_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.adc1 = packet_in.adc1; - packet1.adc2 = packet_in.adc2; - packet1.adc3 = packet_in.adc3; - packet1.adc4 = packet_in.adc4; - packet1.adc5 = packet_in.adc5; - packet1.adc6 = packet_in.adc6; - - - + packet1.adc1 = packet_in.adc1; + packet1.adc2 = packet_in.adc2; + packet1.adc3 = packet_in.adc3; + packet1.adc4 = packet_in.adc4; + packet1.adc5 = packet_in.adc5; + packet1.adc6 = packet_in.adc6; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AP_ADC_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AP_ADC_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ap_adc_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_ap_adc_decode(&msg, &packet2); + mavlink_msg_ap_adc_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_ap_adc_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ap_adc_pack(system_id, component_id, &msg , packet1.adc1 , packet1.adc2 , packet1.adc3 , packet1.adc4 , packet1.adc5 , packet1.adc6 ); - mavlink_msg_ap_adc_decode(&msg, &packet2); + mavlink_msg_ap_adc_pack(system_id, component_id, &msg , packet1.adc1 , packet1.adc2 , packet1.adc3 , packet1.adc4 , packet1.adc5 , packet1.adc6 ); + mavlink_msg_ap_adc_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ap_adc_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.adc1 , packet1.adc2 , packet1.adc3 , packet1.adc4 , packet1.adc5 , packet1.adc6 ); - mavlink_msg_ap_adc_decode(&msg, &packet2); + mavlink_msg_ap_adc_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.adc1 , packet1.adc2 , packet1.adc3 , packet1.adc4 , packet1.adc5 , packet1.adc6 ); + mavlink_msg_ap_adc_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DIGICAM_CONFIGURE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_digicam_configure_t packet_in = { - 17.0,17443,151,218,29,96,163,230,41,108,175 + mavlink_digicam_configure_t packet_in = { + 17.0,17443,151,218,29,96,163,230,41,108,175 }; - mavlink_digicam_configure_t packet1, packet2; + mavlink_digicam_configure_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.extra_value = packet_in.extra_value; - packet1.shutter_speed = packet_in.shutter_speed; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.mode = packet_in.mode; - packet1.aperture = packet_in.aperture; - packet1.iso = packet_in.iso; - packet1.exposure_type = packet_in.exposure_type; - packet1.command_id = packet_in.command_id; - packet1.engine_cut_off = packet_in.engine_cut_off; - packet1.extra_param = packet_in.extra_param; - - - + packet1.extra_value = packet_in.extra_value; + packet1.shutter_speed = packet_in.shutter_speed; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.mode = packet_in.mode; + packet1.aperture = packet_in.aperture; + packet1.iso = packet_in.iso; + packet1.exposure_type = packet_in.exposure_type; + packet1.command_id = packet_in.command_id; + packet1.engine_cut_off = packet_in.engine_cut_off; + packet1.extra_param = packet_in.extra_param; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DIGICAM_CONFIGURE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_digicam_configure_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_digicam_configure_decode(&msg, &packet2); + mavlink_msg_digicam_configure_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_digicam_configure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_digicam_configure_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.mode , packet1.shutter_speed , packet1.aperture , packet1.iso , packet1.exposure_type , packet1.command_id , packet1.engine_cut_off , packet1.extra_param , packet1.extra_value ); - mavlink_msg_digicam_configure_decode(&msg, &packet2); + mavlink_msg_digicam_configure_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.mode , packet1.shutter_speed , packet1.aperture , packet1.iso , packet1.exposure_type , packet1.command_id , packet1.engine_cut_off , packet1.extra_param , packet1.extra_value ); + mavlink_msg_digicam_configure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_digicam_configure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.mode , packet1.shutter_speed , packet1.aperture , packet1.iso , packet1.exposure_type , packet1.command_id , packet1.engine_cut_off , packet1.extra_param , packet1.extra_value ); - mavlink_msg_digicam_configure_decode(&msg, &packet2); + mavlink_msg_digicam_configure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.mode , packet1.shutter_speed , packet1.aperture , packet1.iso , packet1.exposure_type , packet1.command_id , packet1.engine_cut_off , packet1.extra_param , packet1.extra_value ); + mavlink_msg_digicam_configure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DIGICAM_CONTROL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_digicam_control_t packet_in = { - 17.0,17,84,151,218,29,96,163,230,41 + mavlink_digicam_control_t packet_in = { + 17.0,17,84,151,218,29,96,163,230,41 }; - mavlink_digicam_control_t packet1, packet2; + mavlink_digicam_control_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.extra_value = packet_in.extra_value; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.session = packet_in.session; - packet1.zoom_pos = packet_in.zoom_pos; - packet1.zoom_step = packet_in.zoom_step; - packet1.focus_lock = packet_in.focus_lock; - packet1.shot = packet_in.shot; - packet1.command_id = packet_in.command_id; - packet1.extra_param = packet_in.extra_param; - - - + packet1.extra_value = packet_in.extra_value; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.session = packet_in.session; + packet1.zoom_pos = packet_in.zoom_pos; + packet1.zoom_step = packet_in.zoom_step; + packet1.focus_lock = packet_in.focus_lock; + packet1.shot = packet_in.shot; + packet1.command_id = packet_in.command_id; + packet1.extra_param = packet_in.extra_param; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DIGICAM_CONTROL_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_digicam_control_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_digicam_control_decode(&msg, &packet2); + mavlink_msg_digicam_control_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_digicam_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_digicam_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.session , packet1.zoom_pos , packet1.zoom_step , packet1.focus_lock , packet1.shot , packet1.command_id , packet1.extra_param , packet1.extra_value ); - mavlink_msg_digicam_control_decode(&msg, &packet2); + mavlink_msg_digicam_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.session , packet1.zoom_pos , packet1.zoom_step , packet1.focus_lock , packet1.shot , packet1.command_id , packet1.extra_param , packet1.extra_value ); + mavlink_msg_digicam_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_digicam_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.session , packet1.zoom_pos , packet1.zoom_step , packet1.focus_lock , packet1.shot , packet1.command_id , packet1.extra_param , packet1.extra_value ); - mavlink_msg_digicam_control_decode(&msg, &packet2); + mavlink_msg_digicam_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.session , packet1.zoom_pos , packet1.zoom_step , packet1.focus_lock , packet1.shot , packet1.command_id , packet1.extra_param , packet1.extra_value ); + mavlink_msg_digicam_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MOUNT_CONFIGURE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mount_configure_t packet_in = { - 5,72,139,206,17,84 + mavlink_mount_configure_t packet_in = { + 5,72,139,206,17,84 }; - mavlink_mount_configure_t packet1, packet2; + mavlink_mount_configure_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.mount_mode = packet_in.mount_mode; - packet1.stab_roll = packet_in.stab_roll; - packet1.stab_pitch = packet_in.stab_pitch; - packet1.stab_yaw = packet_in.stab_yaw; - - - + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.mount_mode = packet_in.mount_mode; + packet1.stab_roll = packet_in.stab_roll; + packet1.stab_pitch = packet_in.stab_pitch; + packet1.stab_yaw = packet_in.stab_yaw; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MOUNT_CONFIGURE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_configure_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mount_configure_decode(&msg, &packet2); + mavlink_msg_mount_configure_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mount_configure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_configure_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.mount_mode , packet1.stab_roll , packet1.stab_pitch , packet1.stab_yaw ); - mavlink_msg_mount_configure_decode(&msg, &packet2); + mavlink_msg_mount_configure_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.mount_mode , packet1.stab_roll , packet1.stab_pitch , packet1.stab_yaw ); + mavlink_msg_mount_configure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_configure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.mount_mode , packet1.stab_roll , packet1.stab_pitch , packet1.stab_yaw ); - mavlink_msg_mount_configure_decode(&msg, &packet2); + mavlink_msg_mount_configure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.mount_mode , packet1.stab_roll , packet1.stab_pitch , packet1.stab_yaw ); + mavlink_msg_mount_configure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MOUNT_CONTROL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mount_control_t packet_in = { - 963497464,963497672,963497880,41,108,175 + mavlink_mount_control_t packet_in = { + 963497464,963497672,963497880,41,108,175 }; - mavlink_mount_control_t packet1, packet2; + mavlink_mount_control_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.input_a = packet_in.input_a; - packet1.input_b = packet_in.input_b; - packet1.input_c = packet_in.input_c; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.save_position = packet_in.save_position; - - - + packet1.input_a = packet_in.input_a; + packet1.input_b = packet_in.input_b; + packet1.input_c = packet_in.input_c; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.save_position = packet_in.save_position; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MOUNT_CONTROL_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_control_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mount_control_decode(&msg, &packet2); + mavlink_msg_mount_control_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mount_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.input_a , packet1.input_b , packet1.input_c , packet1.save_position ); - mavlink_msg_mount_control_decode(&msg, &packet2); + mavlink_msg_mount_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.input_a , packet1.input_b , packet1.input_c , packet1.save_position ); + mavlink_msg_mount_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.input_a , packet1.input_b , packet1.input_c , packet1.save_position ); - mavlink_msg_mount_control_decode(&msg, &packet2); + mavlink_msg_mount_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.input_a , packet1.input_b , packet1.input_c , packet1.save_position ); + mavlink_msg_mount_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MOUNT_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mount_status_t packet_in = { - 963497464,963497672,963497880,41,108 + mavlink_mount_status_t packet_in = { + 963497464,963497672,963497880,41,108 }; - mavlink_mount_status_t packet1, packet2; + mavlink_mount_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.pointing_a = packet_in.pointing_a; - packet1.pointing_b = packet_in.pointing_b; - packet1.pointing_c = packet_in.pointing_c; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.pointing_a = packet_in.pointing_a; + packet1.pointing_b = packet_in.pointing_b; + packet1.pointing_c = packet_in.pointing_c; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MOUNT_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mount_status_decode(&msg, &packet2); + mavlink_msg_mount_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mount_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_status_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.pointing_a , packet1.pointing_b , packet1.pointing_c ); - mavlink_msg_mount_status_decode(&msg, &packet2); + mavlink_msg_mount_status_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.pointing_a , packet1.pointing_b , packet1.pointing_c ); + mavlink_msg_mount_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mount_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.pointing_a , packet1.pointing_b , packet1.pointing_c ); - mavlink_msg_mount_status_decode(&msg, &packet2); + mavlink_msg_mount_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.pointing_a , packet1.pointing_b , packet1.pointing_c ); + mavlink_msg_mount_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_FENCE_POINT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_fence_point_t packet_in = { - 17.0,45.0,29,96,163,230 + mavlink_fence_point_t packet_in = { + 17.0,45.0,29,96,163,230 }; - mavlink_fence_point_t packet1, packet2; + mavlink_fence_point_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.lat = packet_in.lat; - packet1.lng = packet_in.lng; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.idx = packet_in.idx; - packet1.count = packet_in.count; - - - + packet1.lat = packet_in.lat; + packet1.lng = packet_in.lng; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.idx = packet_in.idx; + packet1.count = packet_in.count; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_FENCE_POINT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_point_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_fence_point_decode(&msg, &packet2); + mavlink_msg_fence_point_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_fence_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng ); - mavlink_msg_fence_point_decode(&msg, &packet2); + mavlink_msg_fence_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng ); + mavlink_msg_fence_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng ); - mavlink_msg_fence_point_decode(&msg, &packet2); + mavlink_msg_fence_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng ); + mavlink_msg_fence_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_FENCE_FETCH_POINT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_fence_fetch_point_t packet_in = { - 5,72,139 + mavlink_fence_fetch_point_t packet_in = { + 5,72,139 }; - mavlink_fence_fetch_point_t packet1, packet2; + mavlink_fence_fetch_point_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.idx = packet_in.idx; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.idx = packet_in.idx; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_FENCE_FETCH_POINT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_fetch_point_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_fence_fetch_point_decode(&msg, &packet2); + mavlink_msg_fence_fetch_point_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_fence_fetch_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_fetch_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx ); - mavlink_msg_fence_fetch_point_decode(&msg, &packet2); + mavlink_msg_fence_fetch_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx ); + mavlink_msg_fence_fetch_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_fetch_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx ); - mavlink_msg_fence_fetch_point_decode(&msg, &packet2); + mavlink_msg_fence_fetch_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx ); + mavlink_msg_fence_fetch_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_FENCE_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_fence_status_t packet_in = { - 963497464,17443,151,218 + mavlink_fence_status_t packet_in = { + 963497464,17443,151,218 }; - mavlink_fence_status_t packet1, packet2; + mavlink_fence_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.breach_time = packet_in.breach_time; - packet1.breach_count = packet_in.breach_count; - packet1.breach_status = packet_in.breach_status; - packet1.breach_type = packet_in.breach_type; + packet1.breach_time = packet_in.breach_time; + packet1.breach_count = packet_in.breach_count; + packet1.breach_status = packet_in.breach_status; + packet1.breach_type = packet_in.breach_type; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_FENCE_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_fence_status_decode(&msg, &packet2); + mavlink_msg_fence_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_fence_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_status_pack(system_id, component_id, &msg , packet1.breach_status , packet1.breach_count , packet1.breach_type , packet1.breach_time ); - mavlink_msg_fence_status_decode(&msg, &packet2); + mavlink_msg_fence_status_pack(system_id, component_id, &msg , packet1.breach_status , packet1.breach_count , packet1.breach_type , packet1.breach_time ); + mavlink_msg_fence_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_fence_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.breach_status , packet1.breach_count , packet1.breach_type , packet1.breach_time ); - mavlink_msg_fence_status_decode(&msg, &packet2); + mavlink_msg_fence_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.breach_status , packet1.breach_count , packet1.breach_type , packet1.breach_time ); + mavlink_msg_fence_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AHRS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_ahrs_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,185.0 + mavlink_ahrs_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0 }; - mavlink_ahrs_t packet1, packet2; + mavlink_ahrs_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.omegaIx = packet_in.omegaIx; - packet1.omegaIy = packet_in.omegaIy; - packet1.omegaIz = packet_in.omegaIz; - packet1.accel_weight = packet_in.accel_weight; - packet1.renorm_val = packet_in.renorm_val; - packet1.error_rp = packet_in.error_rp; - packet1.error_yaw = packet_in.error_yaw; - - - + packet1.omegaIx = packet_in.omegaIx; + packet1.omegaIy = packet_in.omegaIy; + packet1.omegaIz = packet_in.omegaIz; + packet1.accel_weight = packet_in.accel_weight; + packet1.renorm_val = packet_in.renorm_val; + packet1.error_rp = packet_in.error_rp; + packet1.error_yaw = packet_in.error_yaw; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AHRS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AHRS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_ahrs_decode(&msg, &packet2); + mavlink_msg_ahrs_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_ahrs_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs_pack(system_id, component_id, &msg , packet1.omegaIx , packet1.omegaIy , packet1.omegaIz , packet1.accel_weight , packet1.renorm_val , packet1.error_rp , packet1.error_yaw ); - mavlink_msg_ahrs_decode(&msg, &packet2); + mavlink_msg_ahrs_pack(system_id, component_id, &msg , packet1.omegaIx , packet1.omegaIy , packet1.omegaIz , packet1.accel_weight , packet1.renorm_val , packet1.error_rp , packet1.error_yaw ); + mavlink_msg_ahrs_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.omegaIx , packet1.omegaIy , packet1.omegaIz , packet1.accel_weight , packet1.renorm_val , packet1.error_rp , packet1.error_yaw ); - mavlink_msg_ahrs_decode(&msg, &packet2); + mavlink_msg_ahrs_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.omegaIx , packet1.omegaIy , packet1.omegaIz , packet1.accel_weight , packet1.renorm_val , packet1.error_rp , packet1.error_yaw ); + mavlink_msg_ahrs_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SIMSTATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_simstate_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,963499336,963499544 + mavlink_simstate_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,963499336,963499544 }; - mavlink_simstate_t packet1, packet2; + mavlink_simstate_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - packet1.xgyro = packet_in.xgyro; - packet1.ygyro = packet_in.ygyro; - packet1.zgyro = packet_in.zgyro; - packet1.lat = packet_in.lat; - packet1.lng = packet_in.lng; - - - + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.lat = packet_in.lat; + packet1.lng = packet_in.lng; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SIMSTATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SIMSTATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_simstate_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_simstate_decode(&msg, &packet2); + mavlink_msg_simstate_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_simstate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_simstate_pack(system_id, component_id, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lng ); - mavlink_msg_simstate_decode(&msg, &packet2); + mavlink_msg_simstate_pack(system_id, component_id, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lng ); + mavlink_msg_simstate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_simstate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lng ); - mavlink_msg_simstate_decode(&msg, &packet2); + mavlink_msg_simstate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lng ); + mavlink_msg_simstate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HWSTATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hwstatus_t packet_in = { - 17235,139 + mavlink_hwstatus_t packet_in = { + 17235,139 }; - mavlink_hwstatus_t packet1, packet2; + mavlink_hwstatus_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.Vcc = packet_in.Vcc; - packet1.I2Cerr = packet_in.I2Cerr; + packet1.Vcc = packet_in.Vcc; + packet1.I2Cerr = packet_in.I2Cerr; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HWSTATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HWSTATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hwstatus_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hwstatus_decode(&msg, &packet2); + mavlink_msg_hwstatus_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hwstatus_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hwstatus_pack(system_id, component_id, &msg , packet1.Vcc , packet1.I2Cerr ); - mavlink_msg_hwstatus_decode(&msg, &packet2); + mavlink_msg_hwstatus_pack(system_id, component_id, &msg , packet1.Vcc , packet1.I2Cerr ); + mavlink_msg_hwstatus_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hwstatus_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.Vcc , packet1.I2Cerr ); - mavlink_msg_hwstatus_decode(&msg, &packet2); + mavlink_msg_hwstatus_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.Vcc , packet1.I2Cerr ); + mavlink_msg_hwstatus_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RADIO >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_radio_t packet_in = { - 17235,17339,17,84,151,218,29 + mavlink_radio_t packet_in = { + 17235,17339,17,84,151,218,29 }; - mavlink_radio_t packet1, packet2; + mavlink_radio_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.rxerrors = packet_in.rxerrors; - packet1.fixed = packet_in.fixed; - packet1.rssi = packet_in.rssi; - packet1.remrssi = packet_in.remrssi; - packet1.txbuf = packet_in.txbuf; - packet1.noise = packet_in.noise; - packet1.remnoise = packet_in.remnoise; - - - + packet1.rxerrors = packet_in.rxerrors; + packet1.fixed = packet_in.fixed; + packet1.rssi = packet_in.rssi; + packet1.remrssi = packet_in.remrssi; + packet1.txbuf = packet_in.txbuf; + packet1.noise = packet_in.noise; + packet1.remnoise = packet_in.remnoise; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RADIO_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RADIO_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_radio_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_radio_decode(&msg, &packet2); + mavlink_msg_radio_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_radio_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_radio_pack(system_id, component_id, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); - mavlink_msg_radio_decode(&msg, &packet2); + mavlink_msg_radio_pack(system_id, component_id, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); + mavlink_msg_radio_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_radio_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); - mavlink_msg_radio_decode(&msg, &packet2); + mavlink_msg_radio_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); + mavlink_msg_radio_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LIMITS_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_limits_status_t packet_in = { - 963497464,963497672,963497880,963498088,18067,187,254,65,132 + mavlink_limits_status_t packet_in = { + 963497464,963497672,963497880,963498088,18067,187,254,65,132 }; - mavlink_limits_status_t packet1, packet2; + mavlink_limits_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.last_trigger = packet_in.last_trigger; - packet1.last_action = packet_in.last_action; - packet1.last_recovery = packet_in.last_recovery; - packet1.last_clear = packet_in.last_clear; - packet1.breach_count = packet_in.breach_count; - packet1.limits_state = packet_in.limits_state; - packet1.mods_enabled = packet_in.mods_enabled; - packet1.mods_required = packet_in.mods_required; - packet1.mods_triggered = packet_in.mods_triggered; - - - + packet1.last_trigger = packet_in.last_trigger; + packet1.last_action = packet_in.last_action; + packet1.last_recovery = packet_in.last_recovery; + packet1.last_clear = packet_in.last_clear; + packet1.breach_count = packet_in.breach_count; + packet1.limits_state = packet_in.limits_state; + packet1.mods_enabled = packet_in.mods_enabled; + packet1.mods_required = packet_in.mods_required; + packet1.mods_triggered = packet_in.mods_triggered; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LIMITS_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_limits_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_limits_status_decode(&msg, &packet2); + mavlink_msg_limits_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_limits_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_limits_status_pack(system_id, component_id, &msg , packet1.limits_state , packet1.last_trigger , packet1.last_action , packet1.last_recovery , packet1.last_clear , packet1.breach_count , packet1.mods_enabled , packet1.mods_required , packet1.mods_triggered ); - mavlink_msg_limits_status_decode(&msg, &packet2); + mavlink_msg_limits_status_pack(system_id, component_id, &msg , packet1.limits_state , packet1.last_trigger , packet1.last_action , packet1.last_recovery , packet1.last_clear , packet1.breach_count , packet1.mods_enabled , packet1.mods_required , packet1.mods_triggered ); + mavlink_msg_limits_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_limits_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.limits_state , packet1.last_trigger , packet1.last_action , packet1.last_recovery , packet1.last_clear , packet1.breach_count , packet1.mods_enabled , packet1.mods_required , packet1.mods_triggered ); - mavlink_msg_limits_status_decode(&msg, &packet2); + mavlink_msg_limits_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.limits_state , packet1.last_trigger , packet1.last_action , packet1.last_recovery , packet1.last_clear , packet1.breach_count , packet1.mods_enabled , packet1.mods_required , packet1.mods_triggered ); + mavlink_msg_limits_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_WIND >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_wind_t packet_in = { - 17.0,45.0,73.0 + mavlink_wind_t packet_in = { + 17.0,45.0,73.0 }; - mavlink_wind_t packet1, packet2; + mavlink_wind_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.direction = packet_in.direction; - packet1.speed = packet_in.speed; - packet1.speed_z = packet_in.speed_z; + packet1.direction = packet_in.direction; + packet1.speed = packet_in.speed; + packet1.speed_z = packet_in.speed_z; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_WIND_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_WIND_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_wind_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_wind_decode(&msg, &packet2); + mavlink_msg_wind_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_wind_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_wind_pack(system_id, component_id, &msg , packet1.direction , packet1.speed , packet1.speed_z ); - mavlink_msg_wind_decode(&msg, &packet2); + mavlink_msg_wind_pack(system_id, component_id, &msg , packet1.direction , packet1.speed , packet1.speed_z ); + mavlink_msg_wind_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_wind_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.direction , packet1.speed , packet1.speed_z ); - mavlink_msg_wind_decode(&msg, &packet2); + mavlink_msg_wind_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.direction , packet1.speed , packet1.speed_z ); + mavlink_msg_wind_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DATA16 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_data16_t packet_in = { - 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154 } + mavlink_data16_t packet_in = { + 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154 } }; - mavlink_data16_t packet1, packet2; + mavlink_data16_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.type = packet_in.type; - packet1.len = packet_in.len; + packet1.type = packet_in.type; + packet1.len = packet_in.len; - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*16); + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*16); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DATA16_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DATA16_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data16_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_data16_decode(&msg, &packet2); + mavlink_msg_data16_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_data16_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data16_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data16_decode(&msg, &packet2); + mavlink_msg_data16_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data16_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data16_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data16_decode(&msg, &packet2); + mavlink_msg_data16_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data16_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DATA32 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_data32_t packet_in = { - 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170 } + mavlink_data32_t packet_in = { + 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170 } }; - mavlink_data32_t packet1, packet2; + mavlink_data32_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.type = packet_in.type; - packet1.len = packet_in.len; + packet1.type = packet_in.type; + packet1.len = packet_in.len; - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*32); + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*32); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DATA32_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DATA32_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data32_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_data32_decode(&msg, &packet2); + mavlink_msg_data32_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_data32_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data32_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data32_decode(&msg, &packet2); + mavlink_msg_data32_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data32_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data32_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data32_decode(&msg, &packet2); + mavlink_msg_data32_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data32_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DATA64 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_data64_t packet_in = { - 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202 } + mavlink_data64_t packet_in = { + 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202 } }; - mavlink_data64_t packet1, packet2; + mavlink_data64_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.type = packet_in.type; - packet1.len = packet_in.len; + packet1.type = packet_in.type; + packet1.len = packet_in.len; - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*64); + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*64); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DATA64_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DATA64_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data64_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_data64_decode(&msg, &packet2); + mavlink_msg_data64_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_data64_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data64_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data64_decode(&msg, &packet2); + mavlink_msg_data64_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data64_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data64_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data64_decode(&msg, &packet2); + mavlink_msg_data64_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data64_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DATA96 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_data96_t packet_in = { - 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234 } + mavlink_data96_t packet_in = { + 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234 } }; - mavlink_data96_t packet1, packet2; + mavlink_data96_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.type = packet_in.type; - packet1.len = packet_in.len; + packet1.type = packet_in.type; + packet1.len = packet_in.len; - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*96); + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*96); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DATA96_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DATA96_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data96_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_data96_decode(&msg, &packet2); + mavlink_msg_data96_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_data96_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data96_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data96_decode(&msg, &packet2); + mavlink_msg_data96_pack(system_id, component_id, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data96_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data96_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); - mavlink_msg_data96_decode(&msg, &packet2); + mavlink_msg_data96_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.len , packet1.data ); + mavlink_msg_data96_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RANGEFINDER >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_rangefinder_t packet_in = { - 17.0,45.0 + mavlink_rangefinder_t packet_in = { + 17.0,45.0 }; - mavlink_rangefinder_t packet1, packet2; + mavlink_rangefinder_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.distance = packet_in.distance; - packet1.voltage = packet_in.voltage; + packet1.distance = packet_in.distance; + packet1.voltage = packet_in.voltage; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RANGEFINDER_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rangefinder_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_rangefinder_decode(&msg, &packet2); + mavlink_msg_rangefinder_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rangefinder_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rangefinder_pack(system_id, component_id, &msg , packet1.distance , packet1.voltage ); - mavlink_msg_rangefinder_decode(&msg, &packet2); + mavlink_msg_rangefinder_pack(system_id, component_id, &msg , packet1.distance , packet1.voltage ); + mavlink_msg_rangefinder_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rangefinder_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.distance , packet1.voltage ); - mavlink_msg_rangefinder_decode(&msg, &packet2); + mavlink_msg_rangefinder_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.distance , packet1.voltage ); + mavlink_msg_rangefinder_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AIRSPEED_AUTOCAL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_airspeed_autocal_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0 + mavlink_airspeed_autocal_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0 }; - mavlink_airspeed_autocal_t packet1, packet2; + mavlink_airspeed_autocal_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.diff_pressure = packet_in.diff_pressure; - packet1.EAS2TAS = packet_in.EAS2TAS; - packet1.ratio = packet_in.ratio; - packet1.state_x = packet_in.state_x; - packet1.state_y = packet_in.state_y; - packet1.state_z = packet_in.state_z; - packet1.Pax = packet_in.Pax; - packet1.Pby = packet_in.Pby; - packet1.Pcz = packet_in.Pcz; - - - + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.diff_pressure = packet_in.diff_pressure; + packet1.EAS2TAS = packet_in.EAS2TAS; + packet1.ratio = packet_in.ratio; + packet1.state_x = packet_in.state_x; + packet1.state_y = packet_in.state_y; + packet1.state_z = packet_in.state_z; + packet1.Pax = packet_in.Pax; + packet1.Pby = packet_in.Pby; + packet1.Pcz = packet_in.Pcz; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AIRSPEED_AUTOCAL_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_airspeed_autocal_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_airspeed_autocal_decode(&msg, &packet2); + mavlink_msg_airspeed_autocal_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_airspeed_autocal_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_airspeed_autocal_pack(system_id, component_id, &msg , packet1.vx , packet1.vy , packet1.vz , packet1.diff_pressure , packet1.EAS2TAS , packet1.ratio , packet1.state_x , packet1.state_y , packet1.state_z , packet1.Pax , packet1.Pby , packet1.Pcz ); - mavlink_msg_airspeed_autocal_decode(&msg, &packet2); + mavlink_msg_airspeed_autocal_pack(system_id, component_id, &msg , packet1.vx , packet1.vy , packet1.vz , packet1.diff_pressure , packet1.EAS2TAS , packet1.ratio , packet1.state_x , packet1.state_y , packet1.state_z , packet1.Pax , packet1.Pby , packet1.Pcz ); + mavlink_msg_airspeed_autocal_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_airspeed_autocal_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.vx , packet1.vy , packet1.vz , packet1.diff_pressure , packet1.EAS2TAS , packet1.ratio , packet1.state_x , packet1.state_y , packet1.state_z , packet1.Pax , packet1.Pby , packet1.Pcz ); - mavlink_msg_airspeed_autocal_decode(&msg, &packet2); + mavlink_msg_airspeed_autocal_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.vx , packet1.vy , packet1.vz , packet1.diff_pressure , packet1.EAS2TAS , packet1.ratio , packet1.state_x , packet1.state_y , packet1.state_z , packet1.Pax , packet1.Pby , packet1.Pcz ); + mavlink_msg_airspeed_autocal_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RALLY_POINT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_rally_point_t packet_in = { - 963497464,963497672,17651,17755,17859,175,242,53,120,187 + mavlink_rally_point_t packet_in = { + 963497464,963497672,17651,17755,17859,175,242,53,120,187 }; - mavlink_rally_point_t packet1, packet2; + mavlink_rally_point_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.lat = packet_in.lat; - packet1.lng = packet_in.lng; - packet1.alt = packet_in.alt; - packet1.break_alt = packet_in.break_alt; - packet1.land_dir = packet_in.land_dir; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.idx = packet_in.idx; - packet1.count = packet_in.count; - packet1.flags = packet_in.flags; - - - + packet1.lat = packet_in.lat; + packet1.lng = packet_in.lng; + packet1.alt = packet_in.alt; + packet1.break_alt = packet_in.break_alt; + packet1.land_dir = packet_in.land_dir; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.idx = packet_in.idx; + packet1.count = packet_in.count; + packet1.flags = packet_in.flags; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RALLY_POINT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rally_point_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_rally_point_decode(&msg, &packet2); + mavlink_msg_rally_point_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rally_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rally_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng , packet1.alt , packet1.break_alt , packet1.land_dir , packet1.flags ); - mavlink_msg_rally_point_decode(&msg, &packet2); + mavlink_msg_rally_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng , packet1.alt , packet1.break_alt , packet1.land_dir , packet1.flags ); + mavlink_msg_rally_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rally_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng , packet1.alt , packet1.break_alt , packet1.land_dir , packet1.flags ); - mavlink_msg_rally_point_decode(&msg, &packet2); + mavlink_msg_rally_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx , packet1.count , packet1.lat , packet1.lng , packet1.alt , packet1.break_alt , packet1.land_dir , packet1.flags ); + mavlink_msg_rally_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RALLY_FETCH_POINT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_rally_fetch_point_t packet_in = { - 5,72,139 + mavlink_rally_fetch_point_t packet_in = { + 5,72,139 }; - mavlink_rally_fetch_point_t packet1, packet2; + mavlink_rally_fetch_point_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.idx = packet_in.idx; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.idx = packet_in.idx; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RALLY_FETCH_POINT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rally_fetch_point_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_rally_fetch_point_decode(&msg, &packet2); + mavlink_msg_rally_fetch_point_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rally_fetch_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rally_fetch_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx ); - mavlink_msg_rally_fetch_point_decode(&msg, &packet2); + mavlink_msg_rally_fetch_point_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.idx ); + mavlink_msg_rally_fetch_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rally_fetch_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx ); - mavlink_msg_rally_fetch_point_decode(&msg, &packet2); + mavlink_msg_rally_fetch_point_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.idx ); + mavlink_msg_rally_fetch_point_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_COMPASSMOT_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_compassmot_status_t packet_in = { - 17.0,45.0,73.0,101.0,18067,18171 + mavlink_compassmot_status_t packet_in = { + 17.0,45.0,73.0,101.0,18067,18171 }; - mavlink_compassmot_status_t packet1, packet2; + mavlink_compassmot_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.current = packet_in.current; - packet1.CompensationX = packet_in.CompensationX; - packet1.CompensationY = packet_in.CompensationY; - packet1.CompensationZ = packet_in.CompensationZ; - packet1.throttle = packet_in.throttle; - packet1.interference = packet_in.interference; - - - + packet1.current = packet_in.current; + packet1.CompensationX = packet_in.CompensationX; + packet1.CompensationY = packet_in.CompensationY; + packet1.CompensationZ = packet_in.CompensationZ; + packet1.throttle = packet_in.throttle; + packet1.interference = packet_in.interference; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_COMPASSMOT_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_compassmot_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_compassmot_status_decode(&msg, &packet2); + mavlink_msg_compassmot_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_compassmot_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_compassmot_status_pack(system_id, component_id, &msg , packet1.throttle , packet1.current , packet1.interference , packet1.CompensationX , packet1.CompensationY , packet1.CompensationZ ); - mavlink_msg_compassmot_status_decode(&msg, &packet2); + mavlink_msg_compassmot_status_pack(system_id, component_id, &msg , packet1.throttle , packet1.current , packet1.interference , packet1.CompensationX , packet1.CompensationY , packet1.CompensationZ ); + mavlink_msg_compassmot_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_compassmot_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.throttle , packet1.current , packet1.interference , packet1.CompensationX , packet1.CompensationY , packet1.CompensationZ ); - mavlink_msg_compassmot_status_decode(&msg, &packet2); + mavlink_msg_compassmot_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.throttle , packet1.current , packet1.interference , packet1.CompensationX , packet1.CompensationY , packet1.CompensationZ ); + mavlink_msg_compassmot_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AHRS2 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_ahrs2_t packet_in = { - 17.0,45.0,73.0,101.0,963498296,963498504 + mavlink_ahrs2_t packet_in = { + 17.0,45.0,73.0,101.0,963498296,963498504 }; - mavlink_ahrs2_t packet1, packet2; + mavlink_ahrs2_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.altitude = packet_in.altitude; - packet1.lat = packet_in.lat; - packet1.lng = packet_in.lng; - - - + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.altitude = packet_in.altitude; + packet1.lat = packet_in.lat; + packet1.lng = packet_in.lng; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AHRS2_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AHRS2_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs2_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_ahrs2_decode(&msg, &packet2); + mavlink_msg_ahrs2_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_ahrs2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs2_pack(system_id, component_id, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng ); - mavlink_msg_ahrs2_decode(&msg, &packet2); + mavlink_msg_ahrs2_pack(system_id, component_id, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng ); + mavlink_msg_ahrs2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng ); - mavlink_msg_ahrs2_decode(&msg, &packet2); + mavlink_msg_ahrs2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng ); + mavlink_msg_ahrs2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_CAMERA_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_camera_status_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,18483,211,22,89 + mavlink_camera_status_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,18483,211,22,89 }; - mavlink_camera_status_t packet1, packet2; + mavlink_camera_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.p1 = packet_in.p1; - packet1.p2 = packet_in.p2; - packet1.p3 = packet_in.p3; - packet1.p4 = packet_in.p4; - packet1.img_idx = packet_in.img_idx; - packet1.target_system = packet_in.target_system; - packet1.cam_idx = packet_in.cam_idx; - packet1.event_id = packet_in.event_id; - - - + packet1.time_usec = packet_in.time_usec; + packet1.p1 = packet_in.p1; + packet1.p2 = packet_in.p2; + packet1.p3 = packet_in.p3; + packet1.p4 = packet_in.p4; + packet1.img_idx = packet_in.img_idx; + packet1.target_system = packet_in.target_system; + packet1.cam_idx = packet_in.cam_idx; + packet1.event_id = packet_in.event_id; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_CAMERA_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_camera_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_camera_status_decode(&msg, &packet2); + mavlink_msg_camera_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_camera_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_camera_status_pack(system_id, component_id, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.event_id , packet1.p1 , packet1.p2 , packet1.p3 , packet1.p4 ); - mavlink_msg_camera_status_decode(&msg, &packet2); + mavlink_msg_camera_status_pack(system_id, component_id, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.event_id , packet1.p1 , packet1.p2 , packet1.p3 , packet1.p4 ); + mavlink_msg_camera_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_camera_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.event_id , packet1.p1 , packet1.p2 , packet1.p3 , packet1.p4 ); - mavlink_msg_camera_status_decode(&msg, &packet2); + mavlink_msg_camera_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.event_id , packet1.p1 , packet1.p2 , packet1.p3 , packet1.p4 ); + mavlink_msg_camera_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_CAMERA_FEEDBACK >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_camera_feedback_t packet_in = { - 93372036854775807ULL,963497880,963498088,129.0,157.0,185.0,213.0,241.0,269.0,19315,3,70,137 + mavlink_camera_feedback_t packet_in = { + 93372036854775807ULL,963497880,963498088,129.0,157.0,185.0,213.0,241.0,269.0,19315,3,70,137 }; - mavlink_camera_feedback_t packet1, packet2; + mavlink_camera_feedback_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.lat = packet_in.lat; - packet1.lng = packet_in.lng; - packet1.alt_msl = packet_in.alt_msl; - packet1.alt_rel = packet_in.alt_rel; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.foc_len = packet_in.foc_len; - packet1.img_idx = packet_in.img_idx; - packet1.target_system = packet_in.target_system; - packet1.cam_idx = packet_in.cam_idx; - packet1.flags = packet_in.flags; - - - + packet1.time_usec = packet_in.time_usec; + packet1.lat = packet_in.lat; + packet1.lng = packet_in.lng; + packet1.alt_msl = packet_in.alt_msl; + packet1.alt_rel = packet_in.alt_rel; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.foc_len = packet_in.foc_len; + packet1.img_idx = packet_in.img_idx; + packet1.target_system = packet_in.target_system; + packet1.cam_idx = packet_in.cam_idx; + packet1.flags = packet_in.flags; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_CAMERA_FEEDBACK_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_camera_feedback_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_camera_feedback_decode(&msg, &packet2); + mavlink_msg_camera_feedback_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_camera_feedback_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_camera_feedback_pack(system_id, component_id, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.lat , packet1.lng , packet1.alt_msl , packet1.alt_rel , packet1.roll , packet1.pitch , packet1.yaw , packet1.foc_len , packet1.flags ); - mavlink_msg_camera_feedback_decode(&msg, &packet2); + mavlink_msg_camera_feedback_pack(system_id, component_id, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.lat , packet1.lng , packet1.alt_msl , packet1.alt_rel , packet1.roll , packet1.pitch , packet1.yaw , packet1.foc_len , packet1.flags ); + mavlink_msg_camera_feedback_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_camera_feedback_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.lat , packet1.lng , packet1.alt_msl , packet1.alt_rel , packet1.roll , packet1.pitch , packet1.yaw , packet1.foc_len , packet1.flags ); - mavlink_msg_camera_feedback_decode(&msg, &packet2); + mavlink_msg_camera_feedback_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.target_system , packet1.cam_idx , packet1.img_idx , packet1.lat , packet1.lng , packet1.alt_msl , packet1.alt_rel , packet1.roll , packet1.pitch , packet1.yaw , packet1.foc_len , packet1.flags ); + mavlink_msg_camera_feedback_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_BATTERY2 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_battery2_t packet_in = { - 17235,17339 + mavlink_battery2_t packet_in = { + 17235,17339 }; - mavlink_battery2_t packet1, packet2; + mavlink_battery2_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.voltage = packet_in.voltage; - packet1.current_battery = packet_in.current_battery; + packet1.voltage = packet_in.voltage; + packet1.current_battery = packet_in.current_battery; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_BATTERY2_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_BATTERY2_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_battery2_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_battery2_decode(&msg, &packet2); + mavlink_msg_battery2_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_battery2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_battery2_pack(system_id, component_id, &msg , packet1.voltage , packet1.current_battery ); - mavlink_msg_battery2_decode(&msg, &packet2); + mavlink_msg_battery2_pack(system_id, component_id, &msg , packet1.voltage , packet1.current_battery ); + mavlink_msg_battery2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_battery2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.voltage , packet1.current_battery ); - mavlink_msg_battery2_decode(&msg, &packet2); + mavlink_msg_battery2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.voltage , packet1.current_battery ); + mavlink_msg_battery2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AHRS3 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_ahrs3_t packet_in = { - 17.0,45.0,73.0,101.0,963498296,963498504,185.0,213.0,241.0,269.0 + mavlink_ahrs3_t packet_in = { + 17.0,45.0,73.0,101.0,963498296,963498504,185.0,213.0,241.0,269.0 }; - mavlink_ahrs3_t packet1, packet2; + mavlink_ahrs3_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.altitude = packet_in.altitude; - packet1.lat = packet_in.lat; - packet1.lng = packet_in.lng; - packet1.v1 = packet_in.v1; - packet1.v2 = packet_in.v2; - packet1.v3 = packet_in.v3; - packet1.v4 = packet_in.v4; - - - + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.altitude = packet_in.altitude; + packet1.lat = packet_in.lat; + packet1.lng = packet_in.lng; + packet1.v1 = packet_in.v1; + packet1.v2 = packet_in.v2; + packet1.v3 = packet_in.v3; + packet1.v4 = packet_in.v4; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AHRS3_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AHRS3_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs3_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_ahrs3_decode(&msg, &packet2); + mavlink_msg_ahrs3_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_ahrs3_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs3_pack(system_id, component_id, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng , packet1.v1 , packet1.v2 , packet1.v3 , packet1.v4 ); - mavlink_msg_ahrs3_decode(&msg, &packet2); + mavlink_msg_ahrs3_pack(system_id, component_id, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng , packet1.v1 , packet1.v2 , packet1.v3 , packet1.v4 ); + mavlink_msg_ahrs3_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ahrs3_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng , packet1.v1 , packet1.v2 , packet1.v3 , packet1.v4 ); - mavlink_msg_ahrs3_decode(&msg, &packet2); + mavlink_msg_ahrs3_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.roll , packet1.pitch , packet1.yaw , packet1.altitude , packet1.lat , packet1.lng , packet1.v1 , packet1.v2 , packet1.v3 , packet1.v4 ); + mavlink_msg_ahrs3_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_autopilot_version_request_t packet_in = { - 5,72 + mavlink_autopilot_version_request_t packet_in = { + 5,72 }; - mavlink_autopilot_version_request_t packet1, packet2; + mavlink_autopilot_version_request_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AUTOPILOT_VERSION_REQUEST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_autopilot_version_request_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_autopilot_version_request_decode(&msg, &packet2); + mavlink_msg_autopilot_version_request_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_autopilot_version_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_autopilot_version_request_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_autopilot_version_request_decode(&msg, &packet2); + mavlink_msg_autopilot_version_request_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_autopilot_version_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_autopilot_version_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_autopilot_version_request_decode(&msg, &packet2); + mavlink_msg_autopilot_version_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_autopilot_version_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gimbal_report_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,125,192 + mavlink_remote_log_data_block_t packet_in = { + 963497464,17,84,{ 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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, 86, 87, 88, 89, 90, 91, 92, 93, 94 } }; - mavlink_gimbal_report_t packet1, packet2; + mavlink_remote_log_data_block_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.delta_time = packet_in.delta_time; - packet1.delta_angle_x = packet_in.delta_angle_x; - packet1.delta_angle_y = packet_in.delta_angle_y; - packet1.delta_angle_z = packet_in.delta_angle_z; - packet1.delta_velocity_x = packet_in.delta_velocity_x; - packet1.delta_velocity_y = packet_in.delta_velocity_y; - packet1.delta_velocity_z = packet_in.delta_velocity_z; - packet1.joint_roll = packet_in.joint_roll; - packet1.joint_pitch = packet_in.joint_pitch; - packet1.joint_yaw = packet_in.joint_yaw; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.seqno = packet_in.seqno; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*200); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_REMOTE_LOG_DATA_BLOCK_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gimbal_report_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gimbal_report_decode(&msg, &packet2); + mavlink_msg_remote_log_data_block_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_remote_log_data_block_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gimbal_report_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.delta_time , packet1.delta_angle_x , packet1.delta_angle_y , packet1.delta_angle_z , packet1.delta_velocity_x , packet1.delta_velocity_y , packet1.delta_velocity_z , packet1.joint_roll , packet1.joint_pitch , packet1.joint_yaw ); - mavlink_msg_gimbal_report_decode(&msg, &packet2); + mavlink_msg_remote_log_data_block_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seqno , packet1.data ); + mavlink_msg_remote_log_data_block_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gimbal_report_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.delta_time , packet1.delta_angle_x , packet1.delta_angle_y , packet1.delta_angle_z , packet1.delta_velocity_x , packet1.delta_velocity_y , packet1.delta_velocity_z , packet1.joint_roll , packet1.joint_pitch , packet1.joint_yaw ); - mavlink_msg_gimbal_report_decode(&msg, &packet2); + mavlink_msg_remote_log_data_block_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seqno , packet1.data ); + mavlink_msg_remote_log_data_block_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gimbal_control_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,77,144 + mavlink_remote_log_block_status_t packet_in = { + 963497464,17,84,151 }; - mavlink_gimbal_control_t packet1, packet2; + mavlink_remote_log_block_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.demanded_rate_x = packet_in.demanded_rate_x; - packet1.demanded_rate_y = packet_in.demanded_rate_y; - packet1.demanded_rate_z = packet_in.demanded_rate_z; - packet1.gyro_bias_x = packet_in.gyro_bias_x; - packet1.gyro_bias_y = packet_in.gyro_bias_y; - packet1.gyro_bias_z = packet_in.gyro_bias_z; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.seqno = packet_in.seqno; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.status = packet_in.status; +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_REMOTE_LOG_BLOCK_STATUS_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_remote_log_block_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_remote_log_block_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_remote_log_block_status_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seqno , packet1.status ); + mavlink_msg_remote_log_block_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_remote_log_block_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seqno , packet1.status ); + mavlink_msg_remote_log_block_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LED_CONTROL >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_led_control_t packet_in = { + 5,72,139,206,17,{ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107 } + }; + mavlink_led_control_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.instance = packet_in.instance; + packet1.pattern = packet_in.pattern; + packet1.custom_len = packet_in.custom_len; + + mav_array_memcpy(packet1.custom_bytes, packet_in.custom_bytes, sizeof(uint8_t)*24); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LED_CONTROL_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_led_control_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_led_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_led_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.instance , packet1.pattern , packet1.custom_len , packet1.custom_bytes ); + mavlink_msg_led_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_led_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.instance , packet1.pattern , packet1.custom_len , packet1.custom_bytes ); + mavlink_msg_led_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gimbal_control_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gimbal_control_decode(&msg, &packet2); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MAG_CAL_PROGRESS >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_mag_cal_progress_t packet_in = { + 17.0,45.0,73.0,41,108,175,242,53,{ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129 } + }; + mavlink_mag_cal_progress_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.direction_x = packet_in.direction_x; + packet1.direction_y = packet_in.direction_y; + packet1.direction_z = packet_in.direction_z; + packet1.compass_id = packet_in.compass_id; + packet1.cal_mask = packet_in.cal_mask; + packet1.cal_status = packet_in.cal_status; + packet1.attempt = packet_in.attempt; + packet1.completion_pct = packet_in.completion_pct; + + mav_array_memcpy(packet1.completion_mask, packet_in.completion_mask, sizeof(uint8_t)*10); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MAG_CAL_PROGRESS_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_mag_cal_progress_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mag_cal_progress_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_mag_cal_progress_pack(system_id, component_id, &msg , packet1.compass_id , packet1.cal_mask , packet1.cal_status , packet1.attempt , packet1.completion_pct , packet1.completion_mask , packet1.direction_x , packet1.direction_y , packet1.direction_z ); + mavlink_msg_mag_cal_progress_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_mag_cal_progress_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.compass_id , packet1.cal_mask , packet1.cal_status , packet1.attempt , packet1.completion_pct , packet1.completion_mask , packet1.direction_x , packet1.direction_y , packet1.direction_z ); + mavlink_msg_mag_cal_progress_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MAG_CAL_REPORT >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_mag_cal_report_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,125,192,3,70 + }; + mavlink_mag_cal_report_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.fitness = packet_in.fitness; + packet1.ofs_x = packet_in.ofs_x; + packet1.ofs_y = packet_in.ofs_y; + packet1.ofs_z = packet_in.ofs_z; + packet1.diag_x = packet_in.diag_x; + packet1.diag_y = packet_in.diag_y; + packet1.diag_z = packet_in.diag_z; + packet1.offdiag_x = packet_in.offdiag_x; + packet1.offdiag_y = packet_in.offdiag_y; + packet1.offdiag_z = packet_in.offdiag_z; + packet1.compass_id = packet_in.compass_id; + packet1.cal_mask = packet_in.cal_mask; + packet1.cal_status = packet_in.cal_status; + packet1.autosaved = packet_in.autosaved; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MAG_CAL_REPORT_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_mag_cal_report_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mag_cal_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_mag_cal_report_pack(system_id, component_id, &msg , packet1.compass_id , packet1.cal_mask , packet1.cal_status , packet1.autosaved , packet1.fitness , packet1.ofs_x , packet1.ofs_y , packet1.ofs_z , packet1.diag_x , packet1.diag_y , packet1.diag_z , packet1.offdiag_x , packet1.offdiag_y , packet1.offdiag_z ); + mavlink_msg_mag_cal_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_mag_cal_report_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.compass_id , packet1.cal_mask , packet1.cal_status , packet1.autosaved , packet1.fitness , packet1.ofs_x , packet1.ofs_y , packet1.ofs_z , packet1.diag_x , packet1.diag_y , packet1.diag_z , packet1.offdiag_x , packet1.offdiag_y , packet1.offdiag_z ); + mavlink_msg_mag_cal_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_EKF_STATUS_REPORT >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_ekf_status_report_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,18275 + }; + mavlink_ekf_status_report_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.velocity_variance = packet_in.velocity_variance; + packet1.pos_horiz_variance = packet_in.pos_horiz_variance; + packet1.pos_vert_variance = packet_in.pos_vert_variance; + packet1.compass_variance = packet_in.compass_variance; + packet1.terrain_alt_variance = packet_in.terrain_alt_variance; + packet1.flags = packet_in.flags; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_EKF_STATUS_REPORT_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_ekf_status_report_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_ekf_status_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_ekf_status_report_pack(system_id, component_id, &msg , packet1.flags , packet1.velocity_variance , packet1.pos_horiz_variance , packet1.pos_vert_variance , packet1.compass_variance , packet1.terrain_alt_variance ); + mavlink_msg_ekf_status_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_ekf_status_report_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.flags , packet1.velocity_variance , packet1.pos_horiz_variance , packet1.pos_vert_variance , packet1.compass_variance , packet1.terrain_alt_variance ); + mavlink_msg_ekf_status_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_PID_TUNING >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_pid_tuning_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,77 + }; + mavlink_pid_tuning_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.desired = packet_in.desired; + packet1.achieved = packet_in.achieved; + packet1.FF = packet_in.FF; + packet1.P = packet_in.P; + packet1.I = packet_in.I; + packet1.D = packet_in.D; + packet1.axis = packet_in.axis; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_PID_TUNING_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_PID_TUNING_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_pid_tuning_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_pid_tuning_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_pid_tuning_pack(system_id, component_id, &msg , packet1.axis , packet1.desired , packet1.achieved , packet1.FF , packet1.P , packet1.I , packet1.D ); + mavlink_msg_pid_tuning_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_pid_tuning_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.axis , packet1.desired , packet1.achieved , packet1.FF , packet1.P , packet1.I , packet1.D ); + mavlink_msg_pid_tuning_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GIMBAL_REPORT >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gimbal_report_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,125,192 + }; + mavlink_gimbal_report_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.delta_time = packet_in.delta_time; + packet1.delta_angle_x = packet_in.delta_angle_x; + packet1.delta_angle_y = packet_in.delta_angle_y; + packet1.delta_angle_z = packet_in.delta_angle_z; + packet1.delta_velocity_x = packet_in.delta_velocity_x; + packet1.delta_velocity_y = packet_in.delta_velocity_y; + packet1.delta_velocity_z = packet_in.delta_velocity_z; + packet1.joint_roll = packet_in.joint_roll; + packet1.joint_el = packet_in.joint_el; + packet1.joint_az = packet_in.joint_az; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GIMBAL_REPORT_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_report_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gimbal_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_report_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.delta_time , packet1.delta_angle_x , packet1.delta_angle_y , packet1.delta_angle_z , packet1.delta_velocity_x , packet1.delta_velocity_y , packet1.delta_velocity_z , packet1.joint_roll , packet1.joint_el , packet1.joint_az ); + mavlink_msg_gimbal_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_report_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.delta_time , packet1.delta_angle_x , packet1.delta_angle_y , packet1.delta_angle_z , packet1.delta_velocity_x , packet1.delta_velocity_y , packet1.delta_velocity_z , packet1.joint_roll , packet1.joint_el , packet1.joint_az ); + mavlink_msg_gimbal_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GIMBAL_CONTROL >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gimbal_control_t packet_in = { + 17.0,45.0,73.0,41,108 + }; + mavlink_gimbal_control_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.demanded_rate_x = packet_in.demanded_rate_x; + packet1.demanded_rate_y = packet_in.demanded_rate_y; + packet1.demanded_rate_z = packet_in.demanded_rate_z; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GIMBAL_CONTROL_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_control_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gimbal_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.demanded_rate_x , packet1.demanded_rate_y , packet1.demanded_rate_z ); + mavlink_msg_gimbal_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.demanded_rate_x , packet1.demanded_rate_y , packet1.demanded_rate_z ); + mavlink_msg_gimbal_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gimbal_torque_cmd_report_t packet_in = { + 17235,17339,17443,151,218 + }; + mavlink_gimbal_torque_cmd_report_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.rl_torque_cmd = packet_in.rl_torque_cmd; + packet1.el_torque_cmd = packet_in.el_torque_cmd; + packet1.az_torque_cmd = packet_in.az_torque_cmd; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GIMBAL_TORQUE_CMD_REPORT_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_torque_cmd_report_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gimbal_torque_cmd_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_torque_cmd_report_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.rl_torque_cmd , packet1.el_torque_cmd , packet1.az_torque_cmd ); + mavlink_msg_gimbal_torque_cmd_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gimbal_torque_cmd_report_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.rl_torque_cmd , packet1.el_torque_cmd , packet1.az_torque_cmd ); + mavlink_msg_gimbal_torque_cmd_report_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GOPRO_HEARTBEAT >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gopro_heartbeat_t packet_in = { + 5,72,139 + }; + mavlink_gopro_heartbeat_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.status = packet_in.status; + packet1.capture_mode = packet_in.capture_mode; + packet1.flags = packet_in.flags; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GOPRO_HEARTBEAT_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_heartbeat_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gopro_heartbeat_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_heartbeat_pack(system_id, component_id, &msg , packet1.status , packet1.capture_mode , packet1.flags ); + mavlink_msg_gopro_heartbeat_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_heartbeat_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.status , packet1.capture_mode , packet1.flags ); + mavlink_msg_gopro_heartbeat_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GOPRO_GET_REQUEST >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gopro_get_request_t packet_in = { + 5,72,139 + }; + mavlink_gopro_get_request_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.cmd_id = packet_in.cmd_id; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GOPRO_GET_REQUEST_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_get_request_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gopro_get_request_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_get_request_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.cmd_id ); + mavlink_msg_gopro_get_request_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_get_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.cmd_id ); + mavlink_msg_gopro_get_request_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GOPRO_GET_RESPONSE >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gopro_get_response_t packet_in = { + 5,72,{ 139, 140, 141, 142 } + }; + mavlink_gopro_get_response_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.cmd_id = packet_in.cmd_id; + packet1.status = packet_in.status; + + mav_array_memcpy(packet1.value, packet_in.value, sizeof(uint8_t)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GOPRO_GET_RESPONSE_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_get_response_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gopro_get_response_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_get_response_pack(system_id, component_id, &msg , packet1.cmd_id , packet1.status , packet1.value ); + mavlink_msg_gopro_get_response_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_get_response_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.cmd_id , packet1.status , packet1.value ); + mavlink_msg_gopro_get_response_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GOPRO_SET_REQUEST >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gopro_set_request_t packet_in = { + 5,72,139,{ 206, 207, 208, 209 } + }; + mavlink_gopro_set_request_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.cmd_id = packet_in.cmd_id; + + mav_array_memcpy(packet1.value, packet_in.value, sizeof(uint8_t)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GOPRO_SET_REQUEST_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_set_request_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gopro_set_request_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_set_request_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.cmd_id , packet1.value ); + mavlink_msg_gopro_set_request_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_set_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.cmd_id , packet1.value ); + mavlink_msg_gopro_set_request_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GOPRO_SET_RESPONSE >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gopro_set_response_t packet_in = { + 5,72 + }; + mavlink_gopro_set_response_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.cmd_id = packet_in.cmd_id; + packet1.status = packet_in.status; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GOPRO_SET_RESPONSE_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_set_response_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gopro_set_response_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_set_response_pack(system_id, component_id, &msg , packet1.cmd_id , packet1.status ); + mavlink_msg_gopro_set_response_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gopro_set_response_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.cmd_id , packet1.status ); + mavlink_msg_gopro_set_response_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RPM >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_rpm_t packet_in = { + 17.0,45.0 + }; + mavlink_rpm_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.rpm1 = packet_in.rpm1; + packet1.rpm2 = packet_in.rpm2; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RPM_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RPM_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_rpm_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rpm_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gimbal_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.demanded_rate_x , packet1.demanded_rate_y , packet1.demanded_rate_z , packet1.gyro_bias_x , packet1.gyro_bias_y , packet1.gyro_bias_z ); - mavlink_msg_gimbal_control_decode(&msg, &packet2); + mavlink_msg_rpm_pack(system_id, component_id, &msg , packet1.rpm1 , packet1.rpm2 ); + mavlink_msg_rpm_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gimbal_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.demanded_rate_x , packet1.demanded_rate_y , packet1.demanded_rate_z , packet1.gyro_bias_x , packet1.gyro_bias_y , packet1.gyro_bias_z ); - mavlink_msg_gimbal_control_decode(&msg, &packet2); + mavlink_msg_rpm_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.rpm1 , packet1.rpm2 ); + mavlink_msg_rpm_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; i /** * diff --git a/vendor/libraries/mavlink/common/common.h b/vendor/libraries/mavlink/common/common.h index 10c230acd7..e9541d5690 100644 --- a/vendor/libraries/mavlink/common/common.h +++ b/vendor/libraries/mavlink/common/common.h @@ -1,7 +1,8 @@ /** @file - * @brief MAVLink comm protocol generated from common.xml - * @see http://mavlink.org + * @brief MAVLink comm protocol generated from common.xml + * @see http://mavlink.org */ +#pragma once #ifndef MAVLINK_COMMON_H #define MAVLINK_COMMON_H @@ -9,6 +10,9 @@ #error Wrong include order: MAVLINK_COMMON.H MUST NOT BE DIRECTLY USED. Include mavlink.h from the same directory instead or set ALL AND EVERY defines from MAVLINK.H manually accordingly, including the #define MAVLINK_H call. #endif +#undef MAVLINK_THIS_XML_IDX +#define MAVLINK_THIS_XML_IDX 1 + #ifdef __cplusplus extern "C" { #endif @@ -16,15 +20,11 @@ extern "C" { // MESSAGE LENGTHS AND CRCS #ifndef MAVLINK_MESSAGE_LENGTHS -#define MAVLINK_MESSAGE_LENGTHS {9, 31, 12, 0, 14, 28, 3, 32, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 25, 23, 30, 101, 22, 26, 16, 14, 28, 32, 28, 28, 22, 22, 21, 6, 6, 37, 4, 4, 2, 2, 4, 2, 2, 3, 13, 12, 37, 0, 0, 0, 27, 25, 0, 0, 0, 0, 0, 68, 26, 185, 181, 42, 6, 4, 0, 11, 18, 0, 0, 37, 20, 35, 33, 3, 0, 0, 0, 22, 39, 37, 53, 51, 53, 51, 0, 28, 56, 42, 33, 0, 0, 0, 0, 0, 0, 0, 26, 32, 32, 20, 32, 62, 44, 64, 84, 9, 254, 16, 0, 36, 44, 64, 22, 6, 14, 12, 97, 2, 2, 113, 35, 6, 79, 35, 35, 0, 13, 255, 14, 18, 43, 8, 22, 14, 36, 43, 41, 0, 0, 0, 0, 0, 0, 36, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 36, 30, 18, 18, 51, 9, 0} +#define MAVLINK_MESSAGE_LENGTHS {9, 31, 12, 0, 14, 28, 3, 32, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 25, 23, 30, 101, 22, 26, 16, 14, 28, 32, 28, 28, 22, 22, 21, 6, 6, 37, 4, 4, 2, 2, 4, 2, 2, 3, 13, 12, 37, 4, 0, 0, 27, 25, 0, 0, 0, 0, 0, 72, 26, 181, 225, 42, 6, 4, 0, 11, 18, 0, 0, 37, 20, 35, 33, 3, 0, 0, 0, 22, 39, 37, 53, 51, 53, 51, 0, 28, 56, 42, 33, 81, 0, 0, 0, 0, 0, 0, 26, 32, 32, 20, 32, 62, 44, 64, 84, 9, 254, 16, 12, 36, 44, 64, 22, 6, 14, 12, 97, 2, 2, 113, 35, 6, 79, 35, 35, 22, 13, 255, 14, 18, 43, 8, 22, 14, 36, 43, 41, 32, 243, 14, 93, 0, 100, 36, 60, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 40, 63, 182, 40, 0, 0, 0, 0, 0, 0, 32, 52, 53, 6, 2, 38, 19, 254, 36, 30, 18, 18, 51, 9, 0} #endif #ifndef MAVLINK_MESSAGE_CRCS -#define MAVLINK_MESSAGE_CRCS {50, 124, 137, 0, 237, 217, 104, 119, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 214, 159, 220, 168, 24, 23, 170, 144, 67, 115, 39, 246, 185, 104, 237, 244, 222, 212, 9, 254, 230, 28, 28, 132, 221, 232, 11, 153, 41, 39, 78, 0, 0, 0, 15, 3, 0, 0, 0, 0, 0, 153, 183, 51, 82, 118, 148, 21, 0, 243, 124, 0, 0, 38, 20, 158, 152, 143, 0, 0, 0, 106, 49, 22, 143, 140, 5, 150, 0, 231, 183, 63, 54, 0, 0, 0, 0, 0, 0, 0, 175, 102, 158, 208, 56, 93, 138, 108, 32, 185, 84, 34, 0, 124, 237, 4, 76, 128, 56, 116, 134, 237, 203, 250, 87, 203, 220, 25, 226, 0, 29, 223, 85, 6, 229, 203, 1, 195, 109, 168, 181, 0, 0, 0, 0, 0, 0, 154, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 204, 49, 170, 44, 83, 46, 0} -#endif - -#ifndef MAVLINK_MESSAGE_INFO -#define MAVLINK_MESSAGE_INFO {MAVLINK_MESSAGE_INFO_HEARTBEAT, MAVLINK_MESSAGE_INFO_SYS_STATUS, MAVLINK_MESSAGE_INFO_SYSTEM_TIME, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PING, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK, MAVLINK_MESSAGE_INFO_AUTH_KEY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SET_MODE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST, MAVLINK_MESSAGE_INFO_PARAM_VALUE, MAVLINK_MESSAGE_INFO_PARAM_SET, MAVLINK_MESSAGE_INFO_GPS_RAW_INT, MAVLINK_MESSAGE_INFO_GPS_STATUS, MAVLINK_MESSAGE_INFO_SCALED_IMU, MAVLINK_MESSAGE_INFO_RAW_IMU, MAVLINK_MESSAGE_INFO_RAW_PRESSURE, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE, MAVLINK_MESSAGE_INFO_ATTITUDE, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT, MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED, MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW, MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_ITEM, MAVLINK_MESSAGE_INFO_MISSION_REQUEST, MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST, MAVLINK_MESSAGE_INFO_MISSION_COUNT, MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL, MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED, MAVLINK_MESSAGE_INFO_MISSION_ACK, MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_PARAM_MAP_RC, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION_COV, MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT_COV, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_COV, MAVLINK_MESSAGE_INFO_RC_CHANNELS, MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM, MAVLINK_MESSAGE_INFO_DATA_STREAM, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_CONTROL, MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MISSION_ITEM_INT, MAVLINK_MESSAGE_INFO_VFR_HUD, MAVLINK_MESSAGE_INFO_COMMAND_INT, MAVLINK_MESSAGE_INFO_COMMAND_LONG, MAVLINK_MESSAGE_INFO_COMMAND_ACK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT, MAVLINK_MESSAGE_INFO_SET_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_GLOBAL_INT, MAVLINK_MESSAGE_INFO_POSITION_TARGET_GLOBAL_INT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, MAVLINK_MESSAGE_INFO_HIL_STATE, MAVLINK_MESSAGE_INFO_HIL_CONTROLS, MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE, MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_HIGHRES_IMU, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW_RAD, MAVLINK_MESSAGE_INFO_HIL_SENSOR, MAVLINK_MESSAGE_INFO_SIM_STATE, MAVLINK_MESSAGE_INFO_RADIO_STATUS, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_PROTOCOL, MAVLINK_MESSAGE_INFO_TIMESYNC, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_HIL_GPS, MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION, MAVLINK_MESSAGE_INFO_SCALED_IMU2, MAVLINK_MESSAGE_INFO_LOG_REQUEST_LIST, MAVLINK_MESSAGE_INFO_LOG_ENTRY, MAVLINK_MESSAGE_INFO_LOG_REQUEST_DATA, MAVLINK_MESSAGE_INFO_LOG_DATA, MAVLINK_MESSAGE_INFO_LOG_ERASE, MAVLINK_MESSAGE_INFO_LOG_REQUEST_END, MAVLINK_MESSAGE_INFO_GPS_INJECT_DATA, MAVLINK_MESSAGE_INFO_GPS2_RAW, MAVLINK_MESSAGE_INFO_POWER_STATUS, MAVLINK_MESSAGE_INFO_SERIAL_CONTROL, MAVLINK_MESSAGE_INFO_GPS_RTK, MAVLINK_MESSAGE_INFO_GPS2_RTK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_DATA_TRANSMISSION_HANDSHAKE, MAVLINK_MESSAGE_INFO_ENCAPSULATED_DATA, MAVLINK_MESSAGE_INFO_DISTANCE_SENSOR, MAVLINK_MESSAGE_INFO_TERRAIN_REQUEST, MAVLINK_MESSAGE_INFO_TERRAIN_DATA, MAVLINK_MESSAGE_INFO_TERRAIN_CHECK, MAVLINK_MESSAGE_INFO_TERRAIN_REPORT, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE2, MAVLINK_MESSAGE_INFO_ATT_POS_MOCAP, MAVLINK_MESSAGE_INFO_SET_ACTUATOR_CONTROL_TARGET, MAVLINK_MESSAGE_INFO_ACTUATOR_CONTROL_TARGET, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_BATTERY_STATUS, MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_V2_EXTENSION, MAVLINK_MESSAGE_INFO_MEMORY_VECT, MAVLINK_MESSAGE_INFO_DEBUG_VECT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT, MAVLINK_MESSAGE_INFO_STATUSTEXT, MAVLINK_MESSAGE_INFO_DEBUG, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}} +#define MAVLINK_MESSAGE_CRCS {50, 124, 137, 0, 237, 217, 104, 119, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 214, 159, 220, 168, 24, 23, 170, 144, 67, 115, 39, 246, 185, 104, 237, 244, 222, 212, 9, 254, 230, 28, 28, 132, 221, 232, 11, 153, 41, 39, 78, 196, 0, 0, 15, 3, 0, 0, 0, 0, 0, 167, 183, 119, 191, 118, 148, 21, 0, 243, 124, 0, 0, 38, 20, 158, 152, 143, 0, 0, 0, 106, 49, 22, 143, 140, 5, 150, 0, 231, 183, 63, 54, 47, 0, 0, 0, 0, 0, 0, 175, 102, 158, 208, 56, 93, 138, 108, 32, 185, 84, 34, 174, 124, 237, 4, 76, 128, 56, 116, 134, 237, 203, 250, 87, 203, 220, 25, 226, 46, 29, 223, 85, 6, 229, 203, 1, 195, 109, 168, 181, 47, 72, 131, 127, 0, 103, 154, 178, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 105, 151, 35, 150, 0, 0, 0, 0, 0, 0, 90, 104, 85, 95, 130, 184, 81, 8, 204, 49, 170, 44, 83, 46, 0} #endif #include "../protocol.h" @@ -39,25 +39,26 @@ extern "C" { #define HAVE_ENUM_MAV_AUTOPILOT typedef enum MAV_AUTOPILOT { - MAV_AUTOPILOT_GENERIC=0, /* Generic autopilot, full support for everything | */ - MAV_AUTOPILOT_PIXHAWK=1, /* PIXHAWK autopilot, http://pixhawk.ethz.ch | */ - MAV_AUTOPILOT_SLUGS=2, /* SLUGS autopilot, http://slugsuav.soe.ucsc.edu | */ - MAV_AUTOPILOT_ARDUPILOTMEGA=3, /* ArduPilotMega / ArduCopter, http://diydrones.com | */ - MAV_AUTOPILOT_OPENPILOT=4, /* OpenPilot, http://openpilot.org | */ - MAV_AUTOPILOT_GENERIC_WAYPOINTS_ONLY=5, /* Generic autopilot only supporting simple waypoints | */ - MAV_AUTOPILOT_GENERIC_WAYPOINTS_AND_SIMPLE_NAVIGATION_ONLY=6, /* Generic autopilot supporting waypoints and other simple navigation commands | */ - MAV_AUTOPILOT_GENERIC_MISSION_FULL=7, /* Generic autopilot supporting the full mission command set | */ - MAV_AUTOPILOT_INVALID=8, /* No valid autopilot, e.g. a GCS or other MAVLink component | */ - MAV_AUTOPILOT_PPZ=9, /* PPZ UAV - http://nongnu.org/paparazzi | */ - MAV_AUTOPILOT_UDB=10, /* UAV Dev Board | */ - MAV_AUTOPILOT_FP=11, /* FlexiPilot | */ - MAV_AUTOPILOT_PX4=12, /* PX4 Autopilot - http://pixhawk.ethz.ch/px4/ | */ - MAV_AUTOPILOT_SMACCMPILOT=13, /* SMACCMPilot - http://smaccmpilot.org | */ - MAV_AUTOPILOT_AUTOQUAD=14, /* AutoQuad -- http://autoquad.org | */ - MAV_AUTOPILOT_ARMAZILA=15, /* Armazila -- http://armazila.com | */ - MAV_AUTOPILOT_AEROB=16, /* Aerob -- http://aerob.ru | */ - MAV_AUTOPILOT_ASLUAV=17, /* ASLUAV autopilot -- http://www.asl.ethz.ch | */ - MAV_AUTOPILOT_ENUM_END=18 /* | */ + MAV_AUTOPILOT_GENERIC=0, /* Generic autopilot, full support for everything | */ + MAV_AUTOPILOT_RESERVED=1, /* Reserved for future use. | */ + MAV_AUTOPILOT_SLUGS=2, /* SLUGS autopilot, http://slugsuav.soe.ucsc.edu | */ + MAV_AUTOPILOT_ARDUPILOTMEGA=3, /* ArduPilotMega / ArduCopter, http://diydrones.com | */ + MAV_AUTOPILOT_OPENPILOT=4, /* OpenPilot, http://openpilot.org | */ + MAV_AUTOPILOT_GENERIC_WAYPOINTS_ONLY=5, /* Generic autopilot only supporting simple waypoints | */ + MAV_AUTOPILOT_GENERIC_WAYPOINTS_AND_SIMPLE_NAVIGATION_ONLY=6, /* Generic autopilot supporting waypoints and other simple navigation commands | */ + MAV_AUTOPILOT_GENERIC_MISSION_FULL=7, /* Generic autopilot supporting the full mission command set | */ + MAV_AUTOPILOT_INVALID=8, /* No valid autopilot, e.g. a GCS or other MAVLink component | */ + MAV_AUTOPILOT_PPZ=9, /* PPZ UAV - http://nongnu.org/paparazzi | */ + MAV_AUTOPILOT_UDB=10, /* UAV Dev Board | */ + MAV_AUTOPILOT_FP=11, /* FlexiPilot | */ + MAV_AUTOPILOT_PX4=12, /* PX4 Autopilot - http://pixhawk.ethz.ch/px4/ | */ + MAV_AUTOPILOT_SMACCMPILOT=13, /* SMACCMPilot - http://smaccmpilot.org | */ + MAV_AUTOPILOT_AUTOQUAD=14, /* AutoQuad -- http://autoquad.org | */ + MAV_AUTOPILOT_ARMAZILA=15, /* Armazila -- http://armazila.com | */ + MAV_AUTOPILOT_AEROB=16, /* Aerob -- http://aerob.ru | */ + MAV_AUTOPILOT_ASLUAV=17, /* ASLUAV autopilot -- http://www.asl.ethz.ch | */ + MAV_AUTOPILOT_SMARTAP=18, /* SmartAP Autopilot - http://sky-drones.com | */ + MAV_AUTOPILOT_ENUM_END=19 /* | */ } MAV_AUTOPILOT; #endif @@ -66,46 +67,66 @@ typedef enum MAV_AUTOPILOT #define HAVE_ENUM_MAV_TYPE typedef enum MAV_TYPE { - MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */ - MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */ - MAV_TYPE_QUADROTOR=2, /* Quadrotor | */ - MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */ - MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */ - MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */ - MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */ - MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */ - MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */ - MAV_TYPE_ROCKET=9, /* Rocket | */ - MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */ - MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */ - MAV_TYPE_SUBMARINE=12, /* Submarine | */ - MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */ - MAV_TYPE_OCTOROTOR=14, /* Octorotor | */ - MAV_TYPE_TRICOPTER=15, /* Octorotor | */ - MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */ - MAV_TYPE_KITE=17, /* Flapping wing | */ - MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */ - MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */ - MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */ - MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */ - MAV_TYPE_ENUM_END=27 /* | */ + MAV_TYPE_GENERIC=0, /* Generic micro air vehicle. | */ + MAV_TYPE_FIXED_WING=1, /* Fixed wing aircraft. | */ + MAV_TYPE_QUADROTOR=2, /* Quadrotor | */ + MAV_TYPE_COAXIAL=3, /* Coaxial helicopter | */ + MAV_TYPE_HELICOPTER=4, /* Normal helicopter with tail rotor. | */ + MAV_TYPE_ANTENNA_TRACKER=5, /* Ground installation | */ + MAV_TYPE_GCS=6, /* Operator control unit / ground control station | */ + MAV_TYPE_AIRSHIP=7, /* Airship, controlled | */ + MAV_TYPE_FREE_BALLOON=8, /* Free balloon, uncontrolled | */ + MAV_TYPE_ROCKET=9, /* Rocket | */ + MAV_TYPE_GROUND_ROVER=10, /* Ground rover | */ + MAV_TYPE_SURFACE_BOAT=11, /* Surface vessel, boat, ship | */ + MAV_TYPE_SUBMARINE=12, /* Submarine | */ + MAV_TYPE_HEXAROTOR=13, /* Hexarotor | */ + MAV_TYPE_OCTOROTOR=14, /* Octorotor | */ + MAV_TYPE_TRICOPTER=15, /* Tricopter | */ + MAV_TYPE_FLAPPING_WING=16, /* Flapping wing | */ + MAV_TYPE_KITE=17, /* Kite | */ + MAV_TYPE_ONBOARD_CONTROLLER=18, /* Onboard companion controller | */ + MAV_TYPE_VTOL_DUOROTOR=19, /* Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter. | */ + MAV_TYPE_VTOL_QUADROTOR=20, /* Quad-rotor VTOL using a V-shaped quad config in vertical operation. Tailsitter. | */ + MAV_TYPE_VTOL_TILTROTOR=21, /* Tiltrotor VTOL | */ + MAV_TYPE_VTOL_RESERVED2=22, /* VTOL reserved 2 | */ + MAV_TYPE_VTOL_RESERVED3=23, /* VTOL reserved 3 | */ + MAV_TYPE_VTOL_RESERVED4=24, /* VTOL reserved 4 | */ + MAV_TYPE_VTOL_RESERVED5=25, /* VTOL reserved 5 | */ + MAV_TYPE_GIMBAL=26, /* Onboard gimbal | */ + MAV_TYPE_ADSB=27, /* Onboard ADSB peripheral | */ + MAV_TYPE_ENUM_END=28 /* | */ } MAV_TYPE; #endif +/** @brief These values define the type of firmware release. These values indicate the first version or release of this type. For example the first alpha release would be 64, the second would be 65. */ +#ifndef HAVE_ENUM_FIRMWARE_VERSION_TYPE +#define HAVE_ENUM_FIRMWARE_VERSION_TYPE +typedef enum FIRMWARE_VERSION_TYPE +{ + FIRMWARE_VERSION_TYPE_DEV=0, /* development release | */ + FIRMWARE_VERSION_TYPE_ALPHA=64, /* alpha release | */ + FIRMWARE_VERSION_TYPE_BETA=128, /* beta release | */ + FIRMWARE_VERSION_TYPE_RC=192, /* release candidate | */ + FIRMWARE_VERSION_TYPE_OFFICIAL=255, /* official stable release | */ + FIRMWARE_VERSION_TYPE_ENUM_END=256 /* | */ +} FIRMWARE_VERSION_TYPE; +#endif + /** @brief These flags encode the MAV mode. */ #ifndef HAVE_ENUM_MAV_MODE_FLAG #define HAVE_ENUM_MAV_MODE_FLAG typedef enum MAV_MODE_FLAG { - MAV_MODE_FLAG_CUSTOM_MODE_ENABLED=1, /* 0b00000001 Reserved for future use. | */ - MAV_MODE_FLAG_TEST_ENABLED=2, /* 0b00000010 system has a test mode enabled. This flag is intended for temporary system tests and should not be used for stable implementations. | */ - MAV_MODE_FLAG_AUTO_ENABLED=4, /* 0b00000100 autonomous mode enabled, system finds its own goal positions. Guided flag can be set or not, depends on the actual implementation. | */ - MAV_MODE_FLAG_GUIDED_ENABLED=8, /* 0b00001000 guided mode enabled, system flies MISSIONs / mission items. | */ - MAV_MODE_FLAG_STABILIZE_ENABLED=16, /* 0b00010000 system stabilizes electronically its attitude (and optionally position). It needs however further control inputs to move around. | */ - MAV_MODE_FLAG_HIL_ENABLED=32, /* 0b00100000 hardware in the loop simulation. All motors / actuators are blocked, but internal software is full operational. | */ - MAV_MODE_FLAG_MANUAL_INPUT_ENABLED=64, /* 0b01000000 remote control input is enabled. | */ - MAV_MODE_FLAG_SAFETY_ARMED=128, /* 0b10000000 MAV safety set to armed. Motors are enabled / running / can start. Ready to fly. | */ - MAV_MODE_FLAG_ENUM_END=129 /* | */ + MAV_MODE_FLAG_CUSTOM_MODE_ENABLED=1, /* 0b00000001 Reserved for future use. | */ + MAV_MODE_FLAG_TEST_ENABLED=2, /* 0b00000010 system has a test mode enabled. This flag is intended for temporary system tests and should not be used for stable implementations. | */ + MAV_MODE_FLAG_AUTO_ENABLED=4, /* 0b00000100 autonomous mode enabled, system finds its own goal positions. Guided flag can be set or not, depends on the actual implementation. | */ + MAV_MODE_FLAG_GUIDED_ENABLED=8, /* 0b00001000 guided mode enabled, system flies MISSIONs / mission items. | */ + MAV_MODE_FLAG_STABILIZE_ENABLED=16, /* 0b00010000 system stabilizes electronically its attitude (and optionally position). It needs however further control inputs to move around. | */ + MAV_MODE_FLAG_HIL_ENABLED=32, /* 0b00100000 hardware in the loop simulation. All motors / actuators are blocked, but internal software is full operational. | */ + MAV_MODE_FLAG_MANUAL_INPUT_ENABLED=64, /* 0b01000000 remote control input is enabled. | */ + MAV_MODE_FLAG_SAFETY_ARMED=128, /* 0b10000000 MAV safety set to armed. Motors are enabled / running / can start. Ready to fly. Additional note: this flag is to be ignore when sent in the command MAV_CMD_DO_SET_MODE and MAV_CMD_COMPONENT_ARM_DISARM shall be used instead. The flag can still be used to report the armed state. | */ + MAV_MODE_FLAG_ENUM_END=129 /* | */ } MAV_MODE_FLAG; #endif @@ -114,15 +135,15 @@ typedef enum MAV_MODE_FLAG #define HAVE_ENUM_MAV_MODE_FLAG_DECODE_POSITION typedef enum MAV_MODE_FLAG_DECODE_POSITION { - MAV_MODE_FLAG_DECODE_POSITION_CUSTOM_MODE=1, /* Eighth bit: 00000001 | */ - MAV_MODE_FLAG_DECODE_POSITION_TEST=2, /* Seventh bit: 00000010 | */ - MAV_MODE_FLAG_DECODE_POSITION_AUTO=4, /* Sixt bit: 00000100 | */ - MAV_MODE_FLAG_DECODE_POSITION_GUIDED=8, /* Fifth bit: 00001000 | */ - MAV_MODE_FLAG_DECODE_POSITION_STABILIZE=16, /* Fourth bit: 00010000 | */ - MAV_MODE_FLAG_DECODE_POSITION_HIL=32, /* Third bit: 00100000 | */ - MAV_MODE_FLAG_DECODE_POSITION_MANUAL=64, /* Second bit: 01000000 | */ - MAV_MODE_FLAG_DECODE_POSITION_SAFETY=128, /* First bit: 10000000 | */ - MAV_MODE_FLAG_DECODE_POSITION_ENUM_END=129 /* | */ + MAV_MODE_FLAG_DECODE_POSITION_CUSTOM_MODE=1, /* Eighth bit: 00000001 | */ + MAV_MODE_FLAG_DECODE_POSITION_TEST=2, /* Seventh bit: 00000010 | */ + MAV_MODE_FLAG_DECODE_POSITION_AUTO=4, /* Sixt bit: 00000100 | */ + MAV_MODE_FLAG_DECODE_POSITION_GUIDED=8, /* Fifth bit: 00001000 | */ + MAV_MODE_FLAG_DECODE_POSITION_STABILIZE=16, /* Fourth bit: 00010000 | */ + MAV_MODE_FLAG_DECODE_POSITION_HIL=32, /* Third bit: 00100000 | */ + MAV_MODE_FLAG_DECODE_POSITION_MANUAL=64, /* Second bit: 01000000 | */ + MAV_MODE_FLAG_DECODE_POSITION_SAFETY=128, /* First bit: 10000000 | */ + MAV_MODE_FLAG_DECODE_POSITION_ENUM_END=129 /* | */ } MAV_MODE_FLAG_DECODE_POSITION; #endif @@ -131,11 +152,11 @@ typedef enum MAV_MODE_FLAG_DECODE_POSITION #define HAVE_ENUM_MAV_GOTO typedef enum MAV_GOTO { - MAV_GOTO_DO_HOLD=0, /* Hold at the current position. | */ - MAV_GOTO_DO_CONTINUE=1, /* Continue with the next item in mission execution. | */ - MAV_GOTO_HOLD_AT_CURRENT_POSITION=2, /* Hold at the current position of the system | */ - MAV_GOTO_HOLD_AT_SPECIFIED_POSITION=3, /* Hold at the position specified in the parameters of the DO_HOLD action | */ - MAV_GOTO_ENUM_END=4 /* | */ + MAV_GOTO_DO_HOLD=0, /* Hold at the current position. | */ + MAV_GOTO_DO_CONTINUE=1, /* Continue with the next item in mission execution. | */ + MAV_GOTO_HOLD_AT_CURRENT_POSITION=2, /* Hold at the current position of the system | */ + MAV_GOTO_HOLD_AT_SPECIFIED_POSITION=3, /* Hold at the position specified in the parameters of the DO_HOLD action | */ + MAV_GOTO_ENUM_END=4 /* | */ } MAV_GOTO; #endif @@ -145,18 +166,18 @@ typedef enum MAV_GOTO #define HAVE_ENUM_MAV_MODE typedef enum MAV_MODE { - MAV_MODE_PREFLIGHT=0, /* System is not ready to fly, booting, calibrating, etc. No flag is set. | */ - MAV_MODE_MANUAL_DISARMED=64, /* System is allowed to be active, under manual (RC) control, no stabilization | */ - MAV_MODE_TEST_DISARMED=66, /* UNDEFINED mode. This solely depends on the autopilot - use with caution, intended for developers only. | */ - MAV_MODE_STABILIZE_DISARMED=80, /* System is allowed to be active, under assisted RC control. | */ - MAV_MODE_GUIDED_DISARMED=88, /* System is allowed to be active, under autonomous control, manual setpoint | */ - MAV_MODE_AUTO_DISARMED=92, /* System is allowed to be active, under autonomous control and navigation (the trajectory is decided onboard and not pre-programmed by MISSIONs) | */ - MAV_MODE_MANUAL_ARMED=192, /* System is allowed to be active, under manual (RC) control, no stabilization | */ - MAV_MODE_TEST_ARMED=194, /* UNDEFINED mode. This solely depends on the autopilot - use with caution, intended for developers only. | */ - MAV_MODE_STABILIZE_ARMED=208, /* System is allowed to be active, under assisted RC control. | */ - MAV_MODE_GUIDED_ARMED=216, /* System is allowed to be active, under autonomous control, manual setpoint | */ - MAV_MODE_AUTO_ARMED=220, /* System is allowed to be active, under autonomous control and navigation (the trajectory is decided onboard and not pre-programmed by MISSIONs) | */ - MAV_MODE_ENUM_END=221 /* | */ + MAV_MODE_PREFLIGHT=0, /* System is not ready to fly, booting, calibrating, etc. No flag is set. | */ + MAV_MODE_MANUAL_DISARMED=64, /* System is allowed to be active, under manual (RC) control, no stabilization | */ + MAV_MODE_TEST_DISARMED=66, /* UNDEFINED mode. This solely depends on the autopilot - use with caution, intended for developers only. | */ + MAV_MODE_STABILIZE_DISARMED=80, /* System is allowed to be active, under assisted RC control. | */ + MAV_MODE_GUIDED_DISARMED=88, /* System is allowed to be active, under autonomous control, manual setpoint | */ + MAV_MODE_AUTO_DISARMED=92, /* System is allowed to be active, under autonomous control and navigation (the trajectory is decided onboard and not pre-programmed by MISSIONs) | */ + MAV_MODE_MANUAL_ARMED=192, /* System is allowed to be active, under manual (RC) control, no stabilization | */ + MAV_MODE_TEST_ARMED=194, /* UNDEFINED mode. This solely depends on the autopilot - use with caution, intended for developers only. | */ + MAV_MODE_STABILIZE_ARMED=208, /* System is allowed to be active, under assisted RC control. | */ + MAV_MODE_GUIDED_ARMED=216, /* System is allowed to be active, under autonomous control, manual setpoint | */ + MAV_MODE_AUTO_ARMED=220, /* System is allowed to be active, under autonomous control and navigation (the trajectory is decided onboard and not pre-programmed by MISSIONs) | */ + MAV_MODE_ENUM_END=221 /* | */ } MAV_MODE; #endif @@ -165,15 +186,15 @@ typedef enum MAV_MODE #define HAVE_ENUM_MAV_STATE typedef enum MAV_STATE { - MAV_STATE_UNINIT=0, /* Uninitialized system, state is unknown. | */ - MAV_STATE_BOOT=1, /* System is booting up. | */ - MAV_STATE_CALIBRATING=2, /* System is calibrating and not flight-ready. | */ - MAV_STATE_STANDBY=3, /* System is grounded and on standby. It can be launched any time. | */ - MAV_STATE_ACTIVE=4, /* System is active and might be already airborne. Motors are engaged. | */ - MAV_STATE_CRITICAL=5, /* System is in a non-normal flight mode. It can however still navigate. | */ - MAV_STATE_EMERGENCY=6, /* System is in a non-normal flight mode. It lost control over parts or over the whole airframe. It is in mayday and going down. | */ - MAV_STATE_POWEROFF=7, /* System just initialized its power-down sequence, will shut down now. | */ - MAV_STATE_ENUM_END=8 /* | */ + MAV_STATE_UNINIT=0, /* Uninitialized system, state is unknown. | */ + MAV_STATE_BOOT=1, /* System is booting up. | */ + MAV_STATE_CALIBRATING=2, /* System is calibrating and not flight-ready. | */ + MAV_STATE_STANDBY=3, /* System is grounded and on standby. It can be launched any time. | */ + MAV_STATE_ACTIVE=4, /* System is active and might be already airborne. Motors are engaged. | */ + MAV_STATE_CRITICAL=5, /* System is in a non-normal flight mode. It can however still navigate. | */ + MAV_STATE_EMERGENCY=6, /* System is in a non-normal flight mode. It lost control over parts or over the whole airframe. It is in mayday and going down. | */ + MAV_STATE_POWEROFF=7, /* System just initialized its power-down sequence, will shut down now. | */ + MAV_STATE_ENUM_END=8 /* | */ } MAV_STATE; #endif @@ -182,34 +203,41 @@ typedef enum MAV_STATE #define HAVE_ENUM_MAV_COMPONENT typedef enum MAV_COMPONENT { - MAV_COMP_ID_ALL=0, /* | */ - MAV_COMP_ID_CAMERA=100, /* | */ - MAV_COMP_ID_SERVO1=140, /* | */ - MAV_COMP_ID_SERVO2=141, /* | */ - MAV_COMP_ID_SERVO3=142, /* | */ - MAV_COMP_ID_SERVO4=143, /* | */ - MAV_COMP_ID_SERVO5=144, /* | */ - MAV_COMP_ID_SERVO6=145, /* | */ - MAV_COMP_ID_SERVO7=146, /* | */ - MAV_COMP_ID_SERVO8=147, /* | */ - MAV_COMP_ID_SERVO9=148, /* | */ - MAV_COMP_ID_SERVO10=149, /* | */ - MAV_COMP_ID_SERVO11=150, /* | */ - MAV_COMP_ID_SERVO12=151, /* | */ - MAV_COMP_ID_SERVO13=152, /* | */ - MAV_COMP_ID_SERVO14=153, /* | */ - MAV_COMP_ID_GIMBAL=154, /* | */ - MAV_COMP_ID_MAPPER=180, /* | */ - MAV_COMP_ID_MISSIONPLANNER=190, /* | */ - MAV_COMP_ID_PATHPLANNER=195, /* | */ - MAV_COMP_ID_IMU=200, /* | */ - MAV_COMP_ID_IMU_2=201, /* | */ - MAV_COMP_ID_IMU_3=202, /* | */ - MAV_COMP_ID_GPS=220, /* | */ - MAV_COMP_ID_UDP_BRIDGE=240, /* | */ - MAV_COMP_ID_UART_BRIDGE=241, /* | */ - MAV_COMP_ID_SYSTEM_CONTROL=250, /* | */ - MAV_COMPONENT_ENUM_END=251 /* | */ + MAV_COMP_ID_ALL=0, /* | */ + MAV_COMP_ID_AUTOPILOT1=1, /* | */ + MAV_COMP_ID_CAMERA=100, /* | */ + MAV_COMP_ID_SERVO1=140, /* | */ + MAV_COMP_ID_SERVO2=141, /* | */ + MAV_COMP_ID_SERVO3=142, /* | */ + MAV_COMP_ID_SERVO4=143, /* | */ + MAV_COMP_ID_SERVO5=144, /* | */ + MAV_COMP_ID_SERVO6=145, /* | */ + MAV_COMP_ID_SERVO7=146, /* | */ + MAV_COMP_ID_SERVO8=147, /* | */ + MAV_COMP_ID_SERVO9=148, /* | */ + MAV_COMP_ID_SERVO10=149, /* | */ + MAV_COMP_ID_SERVO11=150, /* | */ + MAV_COMP_ID_SERVO12=151, /* | */ + MAV_COMP_ID_SERVO13=152, /* | */ + MAV_COMP_ID_SERVO14=153, /* | */ + MAV_COMP_ID_GIMBAL=154, /* | */ + MAV_COMP_ID_LOG=155, /* | */ + MAV_COMP_ID_ADSB=156, /* | */ + MAV_COMP_ID_OSD=157, /* On Screen Display (OSD) devices for video links | */ + MAV_COMP_ID_PERIPHERAL=158, /* Generic autopilot peripheral component ID. Meant for devices that do not implement the parameter sub-protocol | */ + MAV_COMP_ID_QX1_GIMBAL=159, /* | */ + MAV_COMP_ID_MAPPER=180, /* | */ + MAV_COMP_ID_MISSIONPLANNER=190, /* | */ + MAV_COMP_ID_PATHPLANNER=195, /* | */ + MAV_COMP_ID_IMU=200, /* | */ + MAV_COMP_ID_IMU_2=201, /* | */ + MAV_COMP_ID_IMU_3=202, /* | */ + MAV_COMP_ID_GPS=220, /* | */ + MAV_COMP_ID_GPS2=221, /* | */ + MAV_COMP_ID_UDP_BRIDGE=240, /* | */ + MAV_COMP_ID_UART_BRIDGE=241, /* | */ + MAV_COMP_ID_SYSTEM_CONTROL=250, /* | */ + MAV_COMPONENT_ENUM_END=251 /* | */ } MAV_COMPONENT; #endif @@ -218,30 +246,33 @@ typedef enum MAV_COMPONENT #define HAVE_ENUM_MAV_SYS_STATUS_SENSOR typedef enum MAV_SYS_STATUS_SENSOR { - MAV_SYS_STATUS_SENSOR_3D_GYRO=1, /* 0x01 3D gyro | */ - MAV_SYS_STATUS_SENSOR_3D_ACCEL=2, /* 0x02 3D accelerometer | */ - MAV_SYS_STATUS_SENSOR_3D_MAG=4, /* 0x04 3D magnetometer | */ - MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE=8, /* 0x08 absolute pressure | */ - MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE=16, /* 0x10 differential pressure | */ - MAV_SYS_STATUS_SENSOR_GPS=32, /* 0x20 GPS | */ - MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW=64, /* 0x40 optical flow | */ - MAV_SYS_STATUS_SENSOR_VISION_POSITION=128, /* 0x80 computer vision position | */ - MAV_SYS_STATUS_SENSOR_LASER_POSITION=256, /* 0x100 laser based position | */ - MAV_SYS_STATUS_SENSOR_EXTERNAL_GROUND_TRUTH=512, /* 0x200 external ground truth (Vicon or Leica) | */ - MAV_SYS_STATUS_SENSOR_ANGULAR_RATE_CONTROL=1024, /* 0x400 3D angular rate control | */ - MAV_SYS_STATUS_SENSOR_ATTITUDE_STABILIZATION=2048, /* 0x800 attitude stabilization | */ - MAV_SYS_STATUS_SENSOR_YAW_POSITION=4096, /* 0x1000 yaw position | */ - MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL=8192, /* 0x2000 z/altitude control | */ - MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL=16384, /* 0x4000 x/y position control | */ - MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS=32768, /* 0x8000 motor outputs / control | */ - MAV_SYS_STATUS_SENSOR_RC_RECEIVER=65536, /* 0x10000 rc receiver | */ - MAV_SYS_STATUS_SENSOR_3D_GYRO2=131072, /* 0x20000 2nd 3D gyro | */ - MAV_SYS_STATUS_SENSOR_3D_ACCEL2=262144, /* 0x40000 2nd 3D accelerometer | */ - MAV_SYS_STATUS_SENSOR_3D_MAG2=524288, /* 0x80000 2nd 3D magnetometer | */ - MAV_SYS_STATUS_GEOFENCE=1048576, /* 0x100000 geofence | */ - MAV_SYS_STATUS_AHRS=2097152, /* 0x200000 AHRS subsystem health | */ - MAV_SYS_STATUS_TERRAIN=4194304, /* 0x400000 Terrain subsystem health | */ - MAV_SYS_STATUS_SENSOR_ENUM_END=4194305 /* | */ + MAV_SYS_STATUS_SENSOR_3D_GYRO=1, /* 0x01 3D gyro | */ + MAV_SYS_STATUS_SENSOR_3D_ACCEL=2, /* 0x02 3D accelerometer | */ + MAV_SYS_STATUS_SENSOR_3D_MAG=4, /* 0x04 3D magnetometer | */ + MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE=8, /* 0x08 absolute pressure | */ + MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE=16, /* 0x10 differential pressure | */ + MAV_SYS_STATUS_SENSOR_GPS=32, /* 0x20 GPS | */ + MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW=64, /* 0x40 optical flow | */ + MAV_SYS_STATUS_SENSOR_VISION_POSITION=128, /* 0x80 computer vision position | */ + MAV_SYS_STATUS_SENSOR_LASER_POSITION=256, /* 0x100 laser based position | */ + MAV_SYS_STATUS_SENSOR_EXTERNAL_GROUND_TRUTH=512, /* 0x200 external ground truth (Vicon or Leica) | */ + MAV_SYS_STATUS_SENSOR_ANGULAR_RATE_CONTROL=1024, /* 0x400 3D angular rate control | */ + MAV_SYS_STATUS_SENSOR_ATTITUDE_STABILIZATION=2048, /* 0x800 attitude stabilization | */ + MAV_SYS_STATUS_SENSOR_YAW_POSITION=4096, /* 0x1000 yaw position | */ + MAV_SYS_STATUS_SENSOR_Z_ALTITUDE_CONTROL=8192, /* 0x2000 z/altitude control | */ + MAV_SYS_STATUS_SENSOR_XY_POSITION_CONTROL=16384, /* 0x4000 x/y position control | */ + MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS=32768, /* 0x8000 motor outputs / control | */ + MAV_SYS_STATUS_SENSOR_RC_RECEIVER=65536, /* 0x10000 rc receiver | */ + MAV_SYS_STATUS_SENSOR_3D_GYRO2=131072, /* 0x20000 2nd 3D gyro | */ + MAV_SYS_STATUS_SENSOR_3D_ACCEL2=262144, /* 0x40000 2nd 3D accelerometer | */ + MAV_SYS_STATUS_SENSOR_3D_MAG2=524288, /* 0x80000 2nd 3D magnetometer | */ + MAV_SYS_STATUS_GEOFENCE=1048576, /* 0x100000 geofence | */ + MAV_SYS_STATUS_AHRS=2097152, /* 0x200000 AHRS subsystem health | */ + MAV_SYS_STATUS_TERRAIN=4194304, /* 0x400000 Terrain subsystem health | */ + MAV_SYS_STATUS_REVERSE_MOTOR=8388608, /* 0x800000 Motors are reversed | */ + MAV_SYS_STATUS_LOGGING=16777216, /* 0x1000000 Logging | */ + MAV_SYS_STATUS_SENSOR_BATTERY=33554432, /* 0x2000000 Battery | */ + MAV_SYS_STATUS_SENSOR_ENUM_END=33554433 /* | */ } MAV_SYS_STATUS_SENSOR; #endif @@ -250,19 +281,19 @@ typedef enum MAV_SYS_STATUS_SENSOR #define HAVE_ENUM_MAV_FRAME typedef enum MAV_FRAME { - MAV_FRAME_GLOBAL=0, /* Global coordinate frame, WGS84 coordinate system. First value / x: latitude, second value / y: longitude, third value / z: positive altitude over mean sea level (MSL) | */ - MAV_FRAME_LOCAL_NED=1, /* Local coordinate frame, Z-up (x: north, y: east, z: down). | */ - MAV_FRAME_MISSION=2, /* NOT a coordinate frame, indicates a mission command. | */ - MAV_FRAME_GLOBAL_RELATIVE_ALT=3, /* Global coordinate frame, WGS84 coordinate system, relative altitude over ground with respect to the home position. First value / x: latitude, second value / y: longitude, third value / z: positive altitude with 0 being at the altitude of the home location. | */ - MAV_FRAME_LOCAL_ENU=4, /* Local coordinate frame, Z-down (x: east, y: north, z: up) | */ - MAV_FRAME_GLOBAL_INT=5, /* Global coordinate frame, WGS84 coordinate system. First value / x: latitude in degrees*1.0e-7, second value / y: longitude in degrees*1.0e-7, third value / z: positive altitude over mean sea level (MSL) | */ - MAV_FRAME_GLOBAL_RELATIVE_ALT_INT=6, /* Global coordinate frame, WGS84 coordinate system, relative altitude over ground with respect to the home position. First value / x: latitude in degrees*10e-7, second value / y: longitude in degrees*10e-7, third value / z: positive altitude with 0 being at the altitude of the home location. | */ - MAV_FRAME_LOCAL_OFFSET_NED=7, /* Offset to the current local frame. Anything expressed in this frame should be added to the current local frame position. | */ - MAV_FRAME_BODY_NED=8, /* Setpoint in body NED frame. This makes sense if all position control is externalized - e.g. useful to command 2 m/s^2 acceleration to the right. | */ - MAV_FRAME_BODY_OFFSET_NED=9, /* Offset in body NED frame. This makes sense if adding setpoints to the current flight path, to avoid an obstacle - e.g. useful to command 2 m/s^2 acceleration to the east. | */ - MAV_FRAME_GLOBAL_TERRAIN_ALT=10, /* Global coordinate frame with above terrain level altitude. WGS84 coordinate system, relative altitude over terrain with respect to the waypoint coordinate. First value / x: latitude in degrees, second value / y: longitude in degrees, third value / z: positive altitude in meters with 0 being at ground level in terrain model. | */ - MAV_FRAME_GLOBAL_TERRAIN_ALT_INT=11, /* Global coordinate frame with above terrain level altitude. WGS84 coordinate system, relative altitude over terrain with respect to the waypoint coordinate. First value / x: latitude in degrees*10e-7, second value / y: longitude in degrees*10e-7, third value / z: positive altitude in meters with 0 being at ground level in terrain model. | */ - MAV_FRAME_ENUM_END=12 /* | */ + MAV_FRAME_GLOBAL=0, /* Global coordinate frame, WGS84 coordinate system. First value / x: latitude, second value / y: longitude, third value / z: positive altitude over mean sea level (MSL) | */ + MAV_FRAME_LOCAL_NED=1, /* Local coordinate frame, Z-up (x: north, y: east, z: down). | */ + MAV_FRAME_MISSION=2, /* NOT a coordinate frame, indicates a mission command. | */ + MAV_FRAME_GLOBAL_RELATIVE_ALT=3, /* Global coordinate frame, WGS84 coordinate system, relative altitude over ground with respect to the home position. First value / x: latitude, second value / y: longitude, third value / z: positive altitude with 0 being at the altitude of the home location. | */ + MAV_FRAME_LOCAL_ENU=4, /* Local coordinate frame, Z-down (x: east, y: north, z: up) | */ + MAV_FRAME_GLOBAL_INT=5, /* Global coordinate frame, WGS84 coordinate system. First value / x: latitude in degrees*1.0e-7, second value / y: longitude in degrees*1.0e-7, third value / z: positive altitude over mean sea level (MSL) | */ + MAV_FRAME_GLOBAL_RELATIVE_ALT_INT=6, /* Global coordinate frame, WGS84 coordinate system, relative altitude over ground with respect to the home position. First value / x: latitude in degrees*10e-7, second value / y: longitude in degrees*10e-7, third value / z: positive altitude with 0 being at the altitude of the home location. | */ + MAV_FRAME_LOCAL_OFFSET_NED=7, /* Offset to the current local frame. Anything expressed in this frame should be added to the current local frame position. | */ + MAV_FRAME_BODY_NED=8, /* Setpoint in body NED frame. This makes sense if all position control is externalized - e.g. useful to command 2 m/s^2 acceleration to the right. | */ + MAV_FRAME_BODY_OFFSET_NED=9, /* Offset in body NED frame. This makes sense if adding setpoints to the current flight path, to avoid an obstacle - e.g. useful to command 2 m/s^2 acceleration to the east. | */ + MAV_FRAME_GLOBAL_TERRAIN_ALT=10, /* Global coordinate frame with above terrain level altitude. WGS84 coordinate system, relative altitude over terrain with respect to the waypoint coordinate. First value / x: latitude in degrees, second value / y: longitude in degrees, third value / z: positive altitude in meters with 0 being at ground level in terrain model. | */ + MAV_FRAME_GLOBAL_TERRAIN_ALT_INT=11, /* Global coordinate frame with above terrain level altitude. WGS84 coordinate system, relative altitude over terrain with respect to the waypoint coordinate. First value / x: latitude in degrees*10e-7, second value / y: longitude in degrees*10e-7, third value / z: positive altitude in meters with 0 being at ground level in terrain model. | */ + MAV_FRAME_ENUM_END=12 /* | */ } MAV_FRAME; #endif @@ -271,13 +302,13 @@ typedef enum MAV_FRAME #define HAVE_ENUM_MAVLINK_DATA_STREAM_TYPE typedef enum MAVLINK_DATA_STREAM_TYPE { - MAVLINK_DATA_STREAM_IMG_JPEG=1, /* | */ - MAVLINK_DATA_STREAM_IMG_BMP=2, /* | */ - MAVLINK_DATA_STREAM_IMG_RAW8U=3, /* | */ - MAVLINK_DATA_STREAM_IMG_RAW32U=4, /* | */ - MAVLINK_DATA_STREAM_IMG_PGM=5, /* | */ - MAVLINK_DATA_STREAM_IMG_PNG=6, /* | */ - MAVLINK_DATA_STREAM_TYPE_ENUM_END=7 /* | */ + MAVLINK_DATA_STREAM_IMG_JPEG=1, /* | */ + MAVLINK_DATA_STREAM_IMG_BMP=2, /* | */ + MAVLINK_DATA_STREAM_IMG_RAW8U=3, /* | */ + MAVLINK_DATA_STREAM_IMG_RAW32U=4, /* | */ + MAVLINK_DATA_STREAM_IMG_PGM=5, /* | */ + MAVLINK_DATA_STREAM_IMG_PNG=6, /* | */ + MAVLINK_DATA_STREAM_TYPE_ENUM_END=7 /* | */ } MAVLINK_DATA_STREAM_TYPE; #endif @@ -286,11 +317,12 @@ typedef enum MAVLINK_DATA_STREAM_TYPE #define HAVE_ENUM_FENCE_ACTION typedef enum FENCE_ACTION { - FENCE_ACTION_NONE=0, /* Disable fenced mode | */ - FENCE_ACTION_GUIDED=1, /* Switched to guided mode to return point (fence point 0) | */ - FENCE_ACTION_REPORT=2, /* Report fence breach, but don't take action | */ - FENCE_ACTION_GUIDED_THR_PASS=3, /* Switched to guided mode to return point (fence point 0) with manual throttle control | */ - FENCE_ACTION_ENUM_END=4 /* | */ + FENCE_ACTION_NONE=0, /* Disable fenced mode | */ + FENCE_ACTION_GUIDED=1, /* Switched to guided mode to return point (fence point 0) | */ + FENCE_ACTION_REPORT=2, /* Report fence breach, but don't take action | */ + FENCE_ACTION_GUIDED_THR_PASS=3, /* Switched to guided mode to return point (fence point 0) with manual throttle control | */ + FENCE_ACTION_RTL=4, /* Switch to RTL (return to launch) mode and head for the return point. | */ + FENCE_ACTION_ENUM_END=5 /* | */ } FENCE_ACTION; #endif @@ -299,11 +331,11 @@ typedef enum FENCE_ACTION #define HAVE_ENUM_FENCE_BREACH typedef enum FENCE_BREACH { - FENCE_BREACH_NONE=0, /* No last fence breach | */ - FENCE_BREACH_MINALT=1, /* Breached minimum altitude | */ - FENCE_BREACH_MAXALT=2, /* Breached maximum altitude | */ - FENCE_BREACH_BOUNDARY=3, /* Breached fence boundary | */ - FENCE_BREACH_ENUM_END=4 /* | */ + FENCE_BREACH_NONE=0, /* No last fence breach | */ + FENCE_BREACH_MINALT=1, /* Breached minimum altitude | */ + FENCE_BREACH_MAXALT=2, /* Breached maximum altitude | */ + FENCE_BREACH_BOUNDARY=3, /* Breached fence boundary | */ + FENCE_BREACH_ENUM_END=4 /* | */ } FENCE_BREACH; #endif @@ -312,32 +344,165 @@ typedef enum FENCE_BREACH #define HAVE_ENUM_MAV_MOUNT_MODE typedef enum MAV_MOUNT_MODE { - MAV_MOUNT_MODE_RETRACT=0, /* Load and keep safe position (Roll,Pitch,Yaw) from permant memory and stop stabilization | */ - MAV_MOUNT_MODE_NEUTRAL=1, /* Load and keep neutral position (Roll,Pitch,Yaw) from permanent memory. | */ - MAV_MOUNT_MODE_MAVLINK_TARGETING=2, /* Load neutral position and start MAVLink Roll,Pitch,Yaw control with stabilization | */ - MAV_MOUNT_MODE_RC_TARGETING=3, /* Load neutral position and start RC Roll,Pitch,Yaw control with stabilization | */ - MAV_MOUNT_MODE_GPS_POINT=4, /* Load neutral position and start to point to Lat,Lon,Alt | */ - MAV_MOUNT_MODE_ENUM_END=5 /* | */ + MAV_MOUNT_MODE_RETRACT=0, /* Load and keep safe position (Roll,Pitch,Yaw) from permant memory and stop stabilization | */ + MAV_MOUNT_MODE_NEUTRAL=1, /* Load and keep neutral position (Roll,Pitch,Yaw) from permanent memory. | */ + MAV_MOUNT_MODE_MAVLINK_TARGETING=2, /* Load neutral position and start MAVLink Roll,Pitch,Yaw control with stabilization | */ + MAV_MOUNT_MODE_RC_TARGETING=3, /* Load neutral position and start RC Roll,Pitch,Yaw control with stabilization | */ + MAV_MOUNT_MODE_GPS_POINT=4, /* Load neutral position and start to point to Lat,Lon,Alt | */ + MAV_MOUNT_MODE_ENUM_END=5 /* | */ } MAV_MOUNT_MODE; #endif -/** @brief Data stream IDs. A data stream is not a fixed set of messages, but rather a +/** @brief Commands to be executed by the MAV. They can be executed on user request, or as part of a mission script. If the action is used in a mission, the parameter mapping to the waypoint/mission message is as follows: Param 1, Param 2, Param 3, Param 4, X: Param 5, Y:Param 6, Z:Param 7. This command list is similar what ARINC 424 is for commercial aircraft: A data format how to interpret waypoint/mission data. */ +#ifndef HAVE_ENUM_MAV_CMD +#define HAVE_ENUM_MAV_CMD +typedef enum MAV_CMD +{ + MAV_CMD_NAV_WAYPOINT=16, /* Navigate to MISSION. |Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing)| Acceptance radius in meters (if the sphere with this radius is hit, the MISSION counts as reached)| 0 to pass through the WP, if > 0 radius in meters to pass by WP. Positive value for clockwise orbit, negative value for counter-clockwise orbit. Allows trajectory control.| Desired yaw angle at MISSION (rotary wing). NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LOITER_UNLIM=17, /* Loiter around this MISSION an unlimited amount of time |Empty| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Desired yaw angle.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LOITER_TURNS=18, /* Loiter around this MISSION for X turns |Turns| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Forward moving aircraft this sets exit xtrack location: 0 for center of loiter wp, 1 for exit location. Else, this is desired yaw angle| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LOITER_TIME=19, /* Loiter around this MISSION for X seconds |Seconds (decimal)| Empty| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Forward moving aircraft this sets exit xtrack location: 0 for center of loiter wp, 1 for exit location. Else, this is desired yaw angle| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_RETURN_TO_LAUNCH=20, /* Return to launch location |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_NAV_LAND=21, /* Land at location |Abort Alt| Empty| Empty| Desired yaw angle. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_TAKEOFF=22, /* Takeoff from ground / hand |Minimum pitch (if airspeed sensor present), desired pitch without sensor| Empty| Empty| Yaw angle (if magnetometer present), ignored without magnetometer. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_LAND_LOCAL=23, /* Land at local position (local frame only) |Landing target number (if available)| Maximum accepted offset from desired landing position [m] - computed magnitude from spherical coordinates: d = sqrt(x^2 + y^2 + z^2), which gives the maximum accepted distance between the desired landing position and the position where the vehicle is about to land| Landing descend rate [ms^-1]| Desired yaw angle [rad]| Y-axis position [m]| X-axis position [m]| Z-axis / ground level position [m]| */ + MAV_CMD_NAV_TAKEOFF_LOCAL=24, /* Takeoff from local position (local frame only) |Minimum pitch (if airspeed sensor present), desired pitch without sensor [rad]| Empty| Takeoff ascend rate [ms^-1]| Yaw angle [rad] (if magnetometer or another yaw estimation source present), ignored without one of these| Y-axis position [m]| X-axis position [m]| Z-axis position [m]| */ + MAV_CMD_NAV_FOLLOW=25, /* Vehicle following, i.e. this waypoint represents the position of a moving vehicle |Following logic to use (e.g. loitering or sinusoidal following) - depends on specific autopilot implementation| Ground speed of vehicle to be followed| Radius around MISSION, in meters. If positive loiter clockwise, else counter-clockwise| Desired yaw angle.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT=30, /* Continue on the current course and climb/descend to specified altitude. When the altitude is reached continue to the next command (i.e., don't proceed to the next command until the desired altitude is reached. |Climb or Descend (0 = Neutral, command completes when within 5m of this command's altitude, 1 = Climbing, command completes when at or above this command's altitude, 2 = Descending, command completes when at or below this command's altitude. | Empty| Empty| Empty| Empty| Empty| Desired altitude in meters| */ + MAV_CMD_NAV_LOITER_TO_ALT=31, /* Begin loiter at the specified Latitude and Longitude. If Lat=Lon=0, then loiter at the current position. Don't consider the navigation command complete (don't leave loiter) until the altitude has been reached. Additionally, if the Heading Required parameter is non-zero the aircraft will not leave the loiter until heading toward the next waypoint. |Heading Required (0 = False)| Radius in meters. If positive loiter clockwise, negative counter-clockwise, 0 means no change to standard loiter.| Empty| Forward moving aircraft this sets exit xtrack location: 0 for center of loiter wp, 1 for exit location| Latitude| Longitude| Altitude| */ + MAV_CMD_DO_FOLLOW=32, /* Being following a target |System ID (the system ID of the FOLLOW_TARGET beacon). Send 0 to disable follow-me and return to the default position hold mode| RESERVED| RESERVED| altitude flag: 0: Keep current altitude, 1: keep altitude difference to target, 2: go to a fixed altitude above home| altitude| RESERVED| TTL in seconds in which the MAV should go to the default position hold mode after a message rx timeout| */ + MAV_CMD_DO_FOLLOW_REPOSITION=33, /* Reposition the MAV after a follow target command has been sent |Camera q1 (where 0 is on the ray from the camera to the tracking device)| Camera q2| Camera q3| Camera q4| altitude offset from target (m)| X offset from target (m)| Y offset from target (m)| */ + MAV_CMD_NAV_ROI=80, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ + MAV_CMD_NAV_PATHPLANNING=81, /* Control autonomous path planning on the MAV. |0: Disable local obstacle avoidance / local path planning (without resetting map), 1: Enable local path planning, 2: Enable and reset local path planning| 0: Disable full path planning (without resetting map), 1: Enable, 2: Enable and reset map/occupancy grid, 3: Enable and reset planned route, but not occupancy grid| Empty| Yaw angle at goal, in compass degrees, [0..360]| Latitude/X of goal| Longitude/Y of goal| Altitude/Z of goal| */ + MAV_CMD_NAV_SPLINE_WAYPOINT=82, /* Navigate to MISSION using a spline path. |Hold time in decimal seconds. (ignored by fixed wing, time to stay at MISSION for rotary wing)| Empty| Empty| Empty| Latitude/X of goal| Longitude/Y of goal| Altitude/Z of goal| */ + MAV_CMD_NAV_VTOL_TAKEOFF=84, /* Takeoff from ground using VTOL mode |Empty| Empty| Empty| Yaw angle in degrees. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_VTOL_LAND=85, /* Land using VTOL mode |Empty| Empty| Empty| Yaw angle in degrees. NaN for unchanged.| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_GUIDED_ENABLE=92, /* hand control over to an external controller |On / Off (> 0.5f on)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_NAV_DELAY=93, /* Delay the next navigation command a number of seconds or until a specified time |Delay in seconds (decimal, -1 to enable time-of-day fields)| hour (24h format, UTC, -1 to ignore)| minute (24h format, UTC, -1 to ignore)| second (24h format, UTC)| Empty| Empty| Empty| */ + MAV_CMD_NAV_PAYLOAD_PLACE=94, /* Descend and place payload. Vehicle descends until it detects a hanging payload has reached the ground, the gripper is opened to release the payload |Maximum distance to descend (meters)| Empty| Empty| Empty| Latitude (deg * 1E7)| Longitude (deg * 1E7)| Altitude (meters)| */ + MAV_CMD_NAV_LAST=95, /* NOP - This command is only used to mark the upper limit of the NAV/ACTION commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_DELAY=112, /* Delay mission state machine. |Delay in seconds (decimal)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_CHANGE_ALT=113, /* Ascend/descend at rate. Delay mission state machine until desired altitude reached. |Descent / Ascend rate (m/s)| Empty| Empty| Empty| Empty| Empty| Finish Altitude| */ + MAV_CMD_CONDITION_DISTANCE=114, /* Delay mission state machine until within desired distance of next NAV point. |Distance (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_YAW=115, /* Reach a certain target angle. |target angle: [0-360], 0 is north| speed during yaw change:[deg per second]| direction: negative: counter clockwise, positive: clockwise [-1,1]| relative offset or absolute angle: [ 1,0]| Empty| Empty| Empty| */ + MAV_CMD_CONDITION_LAST=159, /* NOP - This command is only used to mark the upper limit of the CONDITION commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_MODE=176, /* Set system mode. |Mode, as defined by ENUM MAV_MODE| Custom mode - this is system specific, please refer to the individual autopilot specifications for details.| Custom sub mode - this is system specific, please refer to the individual autopilot specifications for details.| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_JUMP=177, /* Jump to the desired command in the mission list. Repeat this action only the specified number of times |Sequence number| Repeat count| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_CHANGE_SPEED=178, /* Change speed and/or throttle set points. |Speed type (0=Airspeed, 1=Ground Speed)| Speed (m/s, -1 indicates no change)| Throttle ( Percent, -1 indicates no change)| absolute or relative [0,1]| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_HOME=179, /* Changes the home location either to the current location or a specified location. |Use current (1=use current location, 0=use specified location)| Empty| Empty| Empty| Latitude| Longitude| Altitude| */ + MAV_CMD_DO_SET_PARAMETER=180, /* Set a system parameter. Caution! Use of this command requires knowledge of the numeric enumeration value of the parameter. |Parameter number| Parameter value| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_RELAY=181, /* Set a relay to a condition. |Relay number| Setting (1=on, 0=off, others possible depending on system hardware)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_REPEAT_RELAY=182, /* Cycle a relay on and off for a desired number of cyles with a desired period. |Relay number| Cycle count| Cycle time (seconds, decimal)| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_SERVO=183, /* Set a servo to a desired PWM value. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_REPEAT_SERVO=184, /* Cycle a between its nominal setting and a desired PWM for a desired number of cycles with a desired period. |Servo number| PWM (microseconds, 1000 to 2000 typical)| Cycle count| Cycle time (seconds)| Empty| Empty| Empty| */ + MAV_CMD_DO_FLIGHTTERMINATION=185, /* Terminate flight immediately |Flight termination activated if > 0.5| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_CHANGE_ALTITUDE=186, /* Change altitude set point. |Altitude in meters| Mav frame of new altitude (see MAV_FRAME)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_LAND_START=189, /* Mission command to perform a landing. This is used as a marker in a mission to tell the autopilot where a sequence of mission items that represents a landing starts. It may also be sent via a COMMAND_LONG to trigger a landing, in which case the nearest (geographically) landing sequence in the mission will be used. The Latitude/Longitude is optional, and may be set to 0/0 if not needed. If specified then it will be used to help find the closest landing sequence. |Empty| Empty| Empty| Empty| Latitude| Longitude| Empty| */ + MAV_CMD_DO_RALLY_LAND=190, /* Mission command to perform a landing from a rally point. |Break altitude (meters)| Landing speed (m/s)| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_GO_AROUND=191, /* Mission command to safely abort an autonmous landing. |Altitude (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_REPOSITION=192, /* Reposition the vehicle to a specific WGS84 global position. |Ground speed, less than 0 (-1) for default| Bitmask of option flags, see the MAV_DO_REPOSITION_FLAGS enum.| Reserved| Yaw heading, NaN for unchanged. For planes indicates loiter direction (0: clockwise, 1: counter clockwise)| Latitude (deg * 1E7)| Longitude (deg * 1E7)| Altitude (meters)| */ + MAV_CMD_DO_PAUSE_CONTINUE=193, /* If in a GPS controlled position mode, hold the current position or continue. |0: Pause current mission or reposition command, hold current position. 1: Continue mission. A VTOL capable vehicle should enter hover mode (multicopter and VTOL planes). A plane should loiter with the default loiter radius.| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_DO_SET_REVERSE=194, /* Set moving direction to forward or reverse. |Direction (0=Forward, 1=Reverse)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_CONTROL_VIDEO=200, /* Control onboard camera system. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty| */ + MAV_CMD_DO_SET_ROI=201, /* Sets the region of interest (ROI) for a sensor set or the vehicle itself. This can then be used by the vehicles control system to control the vehicle attitude and the attitude of various sensors such as cameras. |Region of intereset mode. (see MAV_ROI enum)| MISSION index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple ROI's)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z| */ + MAV_CMD_DO_DIGICAM_CONFIGURE=202, /* Mission command to configure an on-board camera controller system. |Modes: P, TV, AV, M, Etc| Shutter speed: Divisor number for one second| Aperture: F stop number| ISO number e.g. 80, 100, 200, Etc| Exposure type enumerator| Command Identity| Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off)| */ + MAV_CMD_DO_DIGICAM_CONTROL=203, /* Mission command to control an on-board camera controller system. |Session control e.g. show/hide lens| Zoom's absolute position| Zooming step value to offset zoom from the current position| Focus Locking, Unlocking or Re-locking| Shooting Command| Command Identity| Empty| */ + MAV_CMD_DO_MOUNT_CONFIGURE=204, /* Mission command to configure a camera or antenna mount |Mount operation mode (see MAV_MOUNT_MODE enum)| stabilize roll? (1 = yes, 0 = no)| stabilize pitch? (1 = yes, 0 = no)| stabilize yaw? (1 = yes, 0 = no)| Empty| Empty| Empty| */ + MAV_CMD_DO_MOUNT_CONTROL=205, /* Mission command to control a camera or antenna mount |pitch (WIP: DEPRECATED: or lat in degrees) depending on mount mode.| roll (WIP: DEPRECATED: or lon in degrees) depending on mount mode.| yaw (WIP: DEPRECATED: or alt in meters) depending on mount mode.| WIP: alt in meters depending on mount mode.| WIP: latitude in degrees * 1E7, set if appropriate mount mode.| WIP: longitude in degrees * 1E7, set if appropriate mount mode.| MAV_MOUNT_MODE enum value| */ + MAV_CMD_DO_SET_CAM_TRIGG_DIST=206, /* Mission command to set CAM_TRIGG_DIST for this flight |Camera trigger distance (meters)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_FENCE_ENABLE=207, /* Mission command to enable the geofence |enable? (0=disable, 1=enable, 2=disable_floor_only)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_PARACHUTE=208, /* Mission command to trigger a parachute |action (0=disable, 1=enable, 2=release, for some systems see PARACHUTE_ACTION enum, not in general message set.)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_MOTOR_TEST=209, /* Mission command to perform motor test |motor sequence number (a number from 1 to max number of motors on the vehicle)| throttle type (0=throttle percentage, 1=PWM, 2=pilot throttle channel pass-through. See MOTOR_TEST_THROTTLE_TYPE enum)| throttle| timeout (in seconds)| Empty| Empty| Empty| */ + MAV_CMD_DO_INVERTED_FLIGHT=210, /* Change to/from inverted flight |inverted (0=normal, 1=inverted)| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_NAV_SET_YAW_SPEED=213, /* Sets a desired vehicle turn angle and speed change |yaw angle to adjust steering by in centidegress| speed - normalized to 0 .. 1| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_MOUNT_CONTROL_QUAT=220, /* Mission command to control a camera or antenna mount, using a quaternion as reference. |q1 - quaternion param #1, w (1 in null-rotation)| q2 - quaternion param #2, x (0 in null-rotation)| q3 - quaternion param #3, y (0 in null-rotation)| q4 - quaternion param #4, z (0 in null-rotation)| Empty| Empty| Empty| */ + MAV_CMD_DO_GUIDED_MASTER=221, /* set id of master controller |System ID| Component ID| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_GUIDED_LIMITS=222, /* set limits for external control |timeout - maximum time (in seconds) that external controller will be allowed to control vehicle. 0 means no timeout| absolute altitude min (in meters, AMSL) - if vehicle moves below this alt, the command will be aborted and the mission will continue. 0 means no lower altitude limit| absolute altitude max (in meters)- if vehicle moves above this alt, the command will be aborted and the mission will continue. 0 means no upper altitude limit| horizontal move limit (in meters, AMSL) - if vehicle moves more than this distance from it's location at the moment the command was executed, the command will be aborted and the mission will continue. 0 means no horizontal altitude limit| Empty| Empty| Empty| */ + MAV_CMD_DO_ENGINE_CONTROL=223, /* Control vehicle engine. This is interpreted by the vehicles engine controller to change the target engine state. It is intended for vehicles with internal combustion engines |0: Stop engine, 1:Start Engine| 0: Warm start, 1:Cold start. Controls use of choke where applicable| Height delay (meters). This is for commanding engine start only after the vehicle has gained the specified height. Used in VTOL vehicles during takeoff to start engine after the aircraft is off the ground. Zero for no delay.| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_DO_LAST=240, /* NOP - This command is only used to mark the upper limit of the DO commands in the enumeration |Empty| Empty| Empty| Empty| Empty| Empty| Empty| */ + MAV_CMD_PREFLIGHT_CALIBRATION=241, /* Trigger calibration. This command will be only accepted if in pre-flight mode. Except for Temperature Calibration, only one sensor should be set in a single message and all others should be zero. |1: gyro calibration, 3: gyro temperature calibration| 1: magnetometer calibration| 1: ground pressure calibration| 1: radio RC calibration, 2: RC trim calibration| 1: accelerometer calibration, 2: board level calibration, 3: accelerometer temperature calibration| 1: APM: compass/motor interference calibration (PX4: airspeed calibration, deprecated), 2: airspeed calibration| 1: ESC calibration, 3: barometer temperature calibration| */ + MAV_CMD_PREFLIGHT_SET_SENSOR_OFFSETS=242, /* Set sensor offsets. This command will be only accepted if in pre-flight mode. |Sensor to adjust the offsets for: 0: gyros, 1: accelerometer, 2: magnetometer, 3: barometer, 4: optical flow, 5: second magnetometer, 6: third magnetometer| X axis offset (or generic dimension 1), in the sensor's raw units| Y axis offset (or generic dimension 2), in the sensor's raw units| Z axis offset (or generic dimension 3), in the sensor's raw units| Generic dimension 4, in the sensor's raw units| Generic dimension 5, in the sensor's raw units| Generic dimension 6, in the sensor's raw units| */ + MAV_CMD_PREFLIGHT_UAVCAN=243, /* Trigger UAVCAN config. This command will be only accepted if in pre-flight mode. |1: Trigger actuator ID assignment and direction mapping.| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_PREFLIGHT_STORAGE=245, /* Request storage of different parameter values and logs. This command will be only accepted if in pre-flight mode. |Parameter storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM, 2: Reset to defaults| Mission storage: 0: READ FROM FLASH/EEPROM, 1: WRITE CURRENT TO FLASH/EEPROM, 2: Reset to defaults| Onboard logging: 0: Ignore, 1: Start default rate logging, -1: Stop logging, > 1: start logging with rate of param 3 in Hz (e.g. set to 1000 for 1000 Hz logging)| Reserved| Empty| Empty| Empty| */ + MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN=246, /* Request the reboot or shutdown of system components. |0: Do nothing for autopilot, 1: Reboot autopilot, 2: Shutdown autopilot, 3: Reboot autopilot and keep it in the bootloader until upgraded.| 0: Do nothing for onboard computer, 1: Reboot onboard computer, 2: Shutdown onboard computer, 3: Reboot onboard computer and keep it in the bootloader until upgraded.| WIP: 0: Do nothing for camera, 1: Reboot onboard camera, 2: Shutdown onboard camera, 3: Reboot onboard camera and keep it in the bootloader until upgraded| WIP: 0: Do nothing for mount (e.g. gimbal), 1: Reboot mount, 2: Shutdown mount, 3: Reboot mount and keep it in the bootloader until upgraded| Reserved, send 0| Reserved, send 0| WIP: ID (e.g. camera ID -1 for all IDs)| */ + MAV_CMD_OVERRIDE_GOTO=252, /* Hold / continue the current action |MAV_GOTO_DO_HOLD: hold MAV_GOTO_DO_CONTINUE: continue with next item in mission plan| MAV_GOTO_HOLD_AT_CURRENT_POSITION: Hold at current position MAV_GOTO_HOLD_AT_SPECIFIED_POSITION: hold at specified position| MAV_FRAME coordinate frame of hold point| Desired yaw angle in degrees| Latitude / X position| Longitude / Y position| Altitude / Z position| */ + MAV_CMD_MISSION_START=300, /* start running a mission |first_item: the first mission item to run| last_item: the last mission item to run (after this item is run, the mission ends)| */ + MAV_CMD_COMPONENT_ARM_DISARM=400, /* Arms / Disarms a component |1 to arm, 0 to disarm| */ + MAV_CMD_GET_HOME_POSITION=410, /* Request the home position from the vehicle. |Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_START_RX_PAIR=500, /* Starts receiver pairing |0:Spektrum| 0:Spektrum DSM2, 1:Spektrum DSMX| */ + MAV_CMD_GET_MESSAGE_INTERVAL=510, /* Request the interval between messages for a particular MAVLink message ID |The MAVLink message ID| */ + MAV_CMD_SET_MESSAGE_INTERVAL=511, /* Request the interval between messages for a particular MAVLink message ID. This interface replaces REQUEST_DATA_STREAM |The MAVLink message ID| The interval between two messages, in microseconds. Set to -1 to disable and 0 to request default rate.| */ + MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES=520, /* Request autopilot capabilities |1: Request autopilot version| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_CAMERA_INFORMATION=521, /* WIP: Request camera information (CAMERA_INFORMATION) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No action 1: Request camera capabilities| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_CAMERA_SETTINGS=522, /* WIP: Request camera settings (CAMERA_SETTINGS) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No Action 1: Request camera settings| Reserved (all remaining params)| */ + MAV_CMD_SET_CAMERA_SETTINGS_1=523, /* WIP: Set the camera settings part 1 (CAMERA_SETTINGS). Use NAN for values you don't want to change. |Camera ID (1 for first, 2 for second, etc.)| Aperture (1/value)| Shutter speed in seconds| ISO sensitivity| AE mode (Auto Exposure) (0: full auto 1: full manual 2: aperture priority 3: shutter priority)| EV value (when in auto exposure)| White balance (color temperature in K) (0: Auto WB)| */ + MAV_CMD_SET_CAMERA_SETTINGS_2=524, /* WIP: Set the camera settings part 2 (CAMERA_SETTINGS). Use NAN for values you don't want to change. |Camera ID (1 for first, 2 for second, etc.)| Camera mode (0: photo, 1: video)| Audio recording enabled (0: off 1: on)| Reserved for metering mode ID (Average, Center, Spot, etc.)| Reserved for image format ID (Jpeg/Raw/Jpeg+Raw)| Reserved for image quality ID (Compression)| Reserved for color mode ID (Neutral, Vivid, etc.)| */ + MAV_CMD_REQUEST_STORAGE_INFORMATION=525, /* WIP: Request storage information (STORAGE_INFORMATION) |Storage ID (0 for all, 1 for first, 2 for second, etc.)| 0: No Action 1: Request storage information| Reserved (all remaining params)| */ + MAV_CMD_STORAGE_FORMAT=526, /* WIP: Format a storage medium |Storage ID (1 for first, 2 for second, etc.)| 0: No action 1: Format storage| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_CAMERA_CAPTURE_STATUS=527, /* WIP: Request camera capture status (CAMERA_CAPTURE_STATUS) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No Action 1: Request camera capture status| Reserved (all remaining params)| */ + MAV_CMD_REQUEST_FLIGHT_INFORMATION=528, /* WIP: Request flight information (FLIGHT_INFORMATION) |1: Request flight information| Reserved (all remaining params)| */ + MAV_CMD_RESET_CAMERA_SETTINGS=529, /* WIP: Reset all camera settings to Factory Default (CAMERA_SETTINGS) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| 0: No Action 1: Reset all settings| Reserved (all remaining params)| */ + MAV_CMD_IMAGE_START_CAPTURE=2000, /* WIP: Start image capture sequence. Sends CAMERA_IMAGE_CAPTURED after each capture. |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Duration between two consecutive pictures (in seconds)| Number of images to capture total - 0 for unlimited capture| Resolution horizontal in pixels (set to -1 for highest resolution possible)| Resolution vertical in pixels (set to -1 for highest resolution possible)| */ + MAV_CMD_IMAGE_STOP_CAPTURE=2001, /* WIP: Stop image capture sequence |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Reserved| */ + MAV_CMD_REQUEST_CAMERA_IMAGE_CAPTURE=2002, /* WIP: Re-request a CAMERA_IMAGE_CAPTURE packet |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Sequence number for missing CAMERA_IMAGE_CAPTURE packet| Reserved (all remaining params)| */ + MAV_CMD_DO_TRIGGER_CONTROL=2003, /* Enable or disable on-board camera triggering system. |Trigger enable/disable (0 for disable, 1 for start), -1 to ignore| Shutter integration time (in ms), -1 to ignore| 1 to reset the trigger sequence, -1/0 to ignore| */ + MAV_CMD_VIDEO_START_CAPTURE=2500, /* WIP: Starts video capture (recording) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Frames per second, set to -1 for highest framerate possible.| Resolution horizontal in pixels (set to -1 for highest resolution possible)| Resolution vertical in pixels (set to -1 for highest resolution possible)| Frequency CAMERA_CAPTURE_STATUS messages should be sent while recording (0 for no messages, otherwise time in Hz)| */ + MAV_CMD_VIDEO_STOP_CAPTURE=2501, /* WIP: Stop the current video capture (recording) |Camera ID (0 for all cameras, 1 for first, 2 for second, etc.)| Reserved| */ + MAV_CMD_LOGGING_START=2510, /* Request to start streaming logging data over MAVLink (see also LOGGING_DATA message) |Format: 0: ULog| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| */ + MAV_CMD_LOGGING_STOP=2511, /* Request to stop streaming log data over MAVLink |Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| Reserved (set to 0)| */ + MAV_CMD_AIRFRAME_CONFIGURATION=2520, /* |Landing gear ID (default: 0, -1 for all)| Landing gear position (Down: 0, Up: 1, NAN for no change)| Reserved, set to NAN| Reserved, set to NAN| Reserved, set to NAN| Reserved, set to NAN| Reserved, set to NAN| */ + MAV_CMD_PANORAMA_CREATE=2800, /* Create a panorama at the current position |Viewing angle horizontal of the panorama (in degrees, +- 0.5 the total angle)| Viewing angle vertical of panorama (in degrees)| Speed of the horizontal rotation (in degrees per second)| Speed of the vertical rotation (in degrees per second)| */ + MAV_CMD_DO_VTOL_TRANSITION=3000, /* Request VTOL transition |The target VTOL state, as defined by ENUM MAV_VTOL_STATE. Only MAV_VTOL_STATE_MC and MAV_VTOL_STATE_FW can be used.| */ + MAV_CMD_SET_GUIDED_SUBMODE_STANDARD=4000, /* This command sets the submode to standard guided when vehicle is in guided mode. The vehicle holds position and altitude and the user can input the desired velocites along all three axes. + | */ + MAV_CMD_SET_GUIDED_SUBMODE_CIRCLE=4001, /* This command sets submode circle when vehicle is in guided mode. Vehicle flies along a circle facing the center of the circle. The user can input the velocity along the circle and change the radius. If no input is given the vehicle will hold position. + |Radius of desired circle in CIRCLE_MODE| User defined| User defined| User defined| Unscaled target latitude of center of circle in CIRCLE_MODE| Unscaled target longitude of center of circle in CIRCLE_MODE| */ + MAV_CMD_NAV_FENCE_RETURN_POINT=5000, /* Fence return point. There can only be one fence return point. + |Reserved| Reserved| Reserved| Reserved| Latitude| Longitude| Altitude| */ + MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION=5001, /* Fence vertex for an inclusion polygon. The vehicle must stay within this area. Minimum of 3 vertices required. + |Polygon vertex count| Reserved| Reserved| Reserved| Latitude| Longitude| Reserved| */ + MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION=5002, /* Fence vertex for an exclusion polygon. The vehicle must stay outside this area. Minimum of 3 vertices required. + |Polygon vertex count| Reserved| Reserved| Reserved| Latitude| Longitude| Reserved| */ + MAV_CMD_NAV_RALLY_POINT=5100, /* Rally point. You can have multiple rally points defined. + |Reserved| Reserved| Reserved| Reserved| Latitude| Longitude| Altitude| */ + MAV_CMD_PAYLOAD_PREPARE_DEPLOY=30001, /* Deploy payload on a Lat / Lon / Alt position. This includes the navigation to reach the required release position and velocity. |Operation mode. 0: prepare single payload deploy (overwriting previous requests), but do not execute it. 1: execute payload deploy immediately (rejecting further deploy commands during execution, but allowing abort). 2: add payload deploy to existing deployment list.| Desired approach vector in degrees compass heading (0..360). A negative value indicates the system can define the approach vector at will.| Desired ground speed at release time. This can be overriden by the airframe in case it needs to meet minimum airspeed. A negative value indicates the system can define the ground speed at will.| Minimum altitude clearance to the release position in meters. A negative value indicates the system can define the clearance at will.| Latitude unscaled for MISSION_ITEM or in 1e7 degrees for MISSION_ITEM_INT| Longitude unscaled for MISSION_ITEM or in 1e7 degrees for MISSION_ITEM_INT| Altitude, in meters AMSL| */ + MAV_CMD_PAYLOAD_CONTROL_DEPLOY=30002, /* Control the payload deployment. |Operation mode. 0: Abort deployment, continue normal mission. 1: switch to payload deploment mode. 100: delete first payload deployment request. 101: delete all payload deployment requests.| Reserved| Reserved| Reserved| Reserved| Reserved| Reserved| */ + MAV_CMD_WAYPOINT_USER_1=31000, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_2=31001, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_3=31002, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_4=31003, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_WAYPOINT_USER_5=31004, /* User defined waypoint item. Ground Station will show the Vehicle as flying through this item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_1=31005, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_2=31006, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_3=31007, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_4=31008, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_SPATIAL_USER_5=31009, /* User defined spatial item. Ground Station will not show the Vehicle as flying through this item. Example: ROI item. |User defined| User defined| User defined| User defined| Latitude unscaled| Longitude unscaled| Altitude, in meters AMSL| */ + MAV_CMD_USER_1=31010, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_2=31011, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_3=31012, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_4=31013, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_USER_5=31014, /* User defined command. Ground Station will not show the Vehicle as flying through this item. Example: MAV_CMD_DO_SET_PARAMETER item. |User defined| User defined| User defined| User defined| User defined| User defined| User defined| */ + MAV_CMD_ENUM_END=31015 /* | */ +} MAV_CMD; +#endif + +/** @brief THIS INTERFACE IS DEPRECATED AS OF JULY 2015. Please use MESSAGE_INTERVAL instead. A data stream is not a fixed set of messages, but rather a recommendation to the autopilot software. Individual autopilots may or may not obey the recommended messages. */ #ifndef HAVE_ENUM_MAV_DATA_STREAM #define HAVE_ENUM_MAV_DATA_STREAM typedef enum MAV_DATA_STREAM { - MAV_DATA_STREAM_ALL=0, /* Enable all data streams | */ - MAV_DATA_STREAM_RAW_SENSORS=1, /* Enable IMU_RAW, GPS_RAW, GPS_STATUS packets. | */ - MAV_DATA_STREAM_EXTENDED_STATUS=2, /* Enable GPS_STATUS, CONTROL_STATUS, AUX_STATUS | */ - MAV_DATA_STREAM_RC_CHANNELS=3, /* Enable RC_CHANNELS_SCALED, RC_CHANNELS_RAW, SERVO_OUTPUT_RAW | */ - MAV_DATA_STREAM_RAW_CONTROLLER=4, /* Enable ATTITUDE_CONTROLLER_OUTPUT, POSITION_CONTROLLER_OUTPUT, NAV_CONTROLLER_OUTPUT. | */ - MAV_DATA_STREAM_POSITION=6, /* Enable LOCAL_POSITION, GLOBAL_POSITION/GLOBAL_POSITION_INT messages. | */ - MAV_DATA_STREAM_EXTRA1=10, /* Dependent on the autopilot | */ - MAV_DATA_STREAM_EXTRA2=11, /* Dependent on the autopilot | */ - MAV_DATA_STREAM_EXTRA3=12, /* Dependent on the autopilot | */ - MAV_DATA_STREAM_ENUM_END=13 /* | */ + MAV_DATA_STREAM_ALL=0, /* Enable all data streams | */ + MAV_DATA_STREAM_RAW_SENSORS=1, /* Enable IMU_RAW, GPS_RAW, GPS_STATUS packets. | */ + MAV_DATA_STREAM_EXTENDED_STATUS=2, /* Enable GPS_STATUS, CONTROL_STATUS, AUX_STATUS | */ + MAV_DATA_STREAM_RC_CHANNELS=3, /* Enable RC_CHANNELS_SCALED, RC_CHANNELS_RAW, SERVO_OUTPUT_RAW | */ + MAV_DATA_STREAM_RAW_CONTROLLER=4, /* Enable ATTITUDE_CONTROLLER_OUTPUT, POSITION_CONTROLLER_OUTPUT, NAV_CONTROLLER_OUTPUT. | */ + MAV_DATA_STREAM_POSITION=6, /* Enable LOCAL_POSITION, GLOBAL_POSITION/GLOBAL_POSITION_INT messages. | */ + MAV_DATA_STREAM_EXTRA1=10, /* Dependent on the autopilot | */ + MAV_DATA_STREAM_EXTRA2=11, /* Dependent on the autopilot | */ + MAV_DATA_STREAM_EXTRA3=12, /* Dependent on the autopilot | */ + MAV_DATA_STREAM_ENUM_END=13 /* | */ } MAV_DATA_STREAM; #endif @@ -348,12 +513,12 @@ typedef enum MAV_DATA_STREAM #define HAVE_ENUM_MAV_ROI typedef enum MAV_ROI { - MAV_ROI_NONE=0, /* No region of interest. | */ - MAV_ROI_WPNEXT=1, /* Point toward next MISSION. | */ - MAV_ROI_WPINDEX=2, /* Point toward given MISSION. | */ - MAV_ROI_LOCATION=3, /* Point toward fixed location. | */ - MAV_ROI_TARGET=4, /* Point toward of given id. | */ - MAV_ROI_ENUM_END=5 /* | */ + MAV_ROI_NONE=0, /* No region of interest. | */ + MAV_ROI_WPNEXT=1, /* Point toward next MISSION. | */ + MAV_ROI_WPINDEX=2, /* Point toward given MISSION. | */ + MAV_ROI_LOCATION=3, /* Point toward fixed location. | */ + MAV_ROI_TARGET=4, /* Point toward of given id. | */ + MAV_ROI_ENUM_END=5 /* | */ } MAV_ROI; #endif @@ -362,16 +527,16 @@ typedef enum MAV_ROI #define HAVE_ENUM_MAV_CMD_ACK typedef enum MAV_CMD_ACK { - MAV_CMD_ACK_OK=1, /* Command / mission item is ok. | */ - MAV_CMD_ACK_ERR_FAIL=2, /* Generic error message if none of the other reasons fails or if no detailed error reporting is implemented. | */ - MAV_CMD_ACK_ERR_ACCESS_DENIED=3, /* The system is refusing to accept this command from this source / communication partner. | */ - MAV_CMD_ACK_ERR_NOT_SUPPORTED=4, /* Command or mission item is not supported, other commands would be accepted. | */ - MAV_CMD_ACK_ERR_COORDINATE_FRAME_NOT_SUPPORTED=5, /* The coordinate frame of this command / mission item is not supported. | */ - MAV_CMD_ACK_ERR_COORDINATES_OUT_OF_RANGE=6, /* The coordinate frame of this command is ok, but he coordinate values exceed the safety limits of this system. This is a generic error, please use the more specific error messages below if possible. | */ - MAV_CMD_ACK_ERR_X_LAT_OUT_OF_RANGE=7, /* The X or latitude value is out of range. | */ - MAV_CMD_ACK_ERR_Y_LON_OUT_OF_RANGE=8, /* The Y or longitude value is out of range. | */ - MAV_CMD_ACK_ERR_Z_ALT_OUT_OF_RANGE=9, /* The Z or altitude value is out of range. | */ - MAV_CMD_ACK_ENUM_END=10 /* | */ + MAV_CMD_ACK_OK=1, /* Command / mission item is ok. | */ + MAV_CMD_ACK_ERR_FAIL=2, /* Generic error message if none of the other reasons fails or if no detailed error reporting is implemented. | */ + MAV_CMD_ACK_ERR_ACCESS_DENIED=3, /* The system is refusing to accept this command from this source / communication partner. | */ + MAV_CMD_ACK_ERR_NOT_SUPPORTED=4, /* Command or mission item is not supported, other commands would be accepted. | */ + MAV_CMD_ACK_ERR_COORDINATE_FRAME_NOT_SUPPORTED=5, /* The coordinate frame of this command / mission item is not supported. | */ + MAV_CMD_ACK_ERR_COORDINATES_OUT_OF_RANGE=6, /* The coordinate frame of this command is ok, but he coordinate values exceed the safety limits of this system. This is a generic error, please use the more specific error messages below if possible. | */ + MAV_CMD_ACK_ERR_X_LAT_OUT_OF_RANGE=7, /* The X or latitude value is out of range. | */ + MAV_CMD_ACK_ERR_Y_LON_OUT_OF_RANGE=8, /* The Y or longitude value is out of range. | */ + MAV_CMD_ACK_ERR_Z_ALT_OUT_OF_RANGE=9, /* The Z or altitude value is out of range. | */ + MAV_CMD_ACK_ENUM_END=10 /* | */ } MAV_CMD_ACK; #endif @@ -380,17 +545,17 @@ typedef enum MAV_CMD_ACK #define HAVE_ENUM_MAV_PARAM_TYPE typedef enum MAV_PARAM_TYPE { - MAV_PARAM_TYPE_UINT8=1, /* 8-bit unsigned integer | */ - MAV_PARAM_TYPE_INT8=2, /* 8-bit signed integer | */ - MAV_PARAM_TYPE_UINT16=3, /* 16-bit unsigned integer | */ - MAV_PARAM_TYPE_INT16=4, /* 16-bit signed integer | */ - MAV_PARAM_TYPE_UINT32=5, /* 32-bit unsigned integer | */ - MAV_PARAM_TYPE_INT32=6, /* 32-bit signed integer | */ - MAV_PARAM_TYPE_UINT64=7, /* 64-bit unsigned integer | */ - MAV_PARAM_TYPE_INT64=8, /* 64-bit signed integer | */ - MAV_PARAM_TYPE_REAL32=9, /* 32-bit floating-point | */ - MAV_PARAM_TYPE_REAL64=10, /* 64-bit floating-point | */ - MAV_PARAM_TYPE_ENUM_END=11 /* | */ + MAV_PARAM_TYPE_UINT8=1, /* 8-bit unsigned integer | */ + MAV_PARAM_TYPE_INT8=2, /* 8-bit signed integer | */ + MAV_PARAM_TYPE_UINT16=3, /* 16-bit unsigned integer | */ + MAV_PARAM_TYPE_INT16=4, /* 16-bit signed integer | */ + MAV_PARAM_TYPE_UINT32=5, /* 32-bit unsigned integer | */ + MAV_PARAM_TYPE_INT32=6, /* 32-bit signed integer | */ + MAV_PARAM_TYPE_UINT64=7, /* 64-bit unsigned integer | */ + MAV_PARAM_TYPE_INT64=8, /* 64-bit signed integer | */ + MAV_PARAM_TYPE_REAL32=9, /* 32-bit floating-point | */ + MAV_PARAM_TYPE_REAL64=10, /* 64-bit floating-point | */ + MAV_PARAM_TYPE_ENUM_END=11 /* | */ } MAV_PARAM_TYPE; #endif @@ -399,12 +564,13 @@ typedef enum MAV_PARAM_TYPE #define HAVE_ENUM_MAV_RESULT typedef enum MAV_RESULT { - MAV_RESULT_ACCEPTED=0, /* Command ACCEPTED and EXECUTED | */ - MAV_RESULT_TEMPORARILY_REJECTED=1, /* Command TEMPORARY REJECTED/DENIED | */ - MAV_RESULT_DENIED=2, /* Command PERMANENTLY DENIED | */ - MAV_RESULT_UNSUPPORTED=3, /* Command UNKNOWN/UNSUPPORTED | */ - MAV_RESULT_FAILED=4, /* Command executed, but failed | */ - MAV_RESULT_ENUM_END=5 /* | */ + MAV_RESULT_ACCEPTED=0, /* Command ACCEPTED and EXECUTED | */ + MAV_RESULT_TEMPORARILY_REJECTED=1, /* Command TEMPORARY REJECTED/DENIED | */ + MAV_RESULT_DENIED=2, /* Command PERMANENTLY DENIED | */ + MAV_RESULT_UNSUPPORTED=3, /* Command UNKNOWN/UNSUPPORTED | */ + MAV_RESULT_FAILED=4, /* Command executed, but failed | */ + MAV_RESULT_IN_PROGRESS=5, /* WIP: Command being executed | */ + MAV_RESULT_ENUM_END=6 /* | */ } MAV_RESULT; #endif @@ -413,22 +579,22 @@ typedef enum MAV_RESULT #define HAVE_ENUM_MAV_MISSION_RESULT typedef enum MAV_MISSION_RESULT { - MAV_MISSION_ACCEPTED=0, /* mission accepted OK | */ - MAV_MISSION_ERROR=1, /* generic error / not accepting mission commands at all right now | */ - MAV_MISSION_UNSUPPORTED_FRAME=2, /* coordinate frame is not supported | */ - MAV_MISSION_UNSUPPORTED=3, /* command is not supported | */ - MAV_MISSION_NO_SPACE=4, /* mission item exceeds storage space | */ - MAV_MISSION_INVALID=5, /* one of the parameters has an invalid value | */ - MAV_MISSION_INVALID_PARAM1=6, /* param1 has an invalid value | */ - MAV_MISSION_INVALID_PARAM2=7, /* param2 has an invalid value | */ - MAV_MISSION_INVALID_PARAM3=8, /* param3 has an invalid value | */ - MAV_MISSION_INVALID_PARAM4=9, /* param4 has an invalid value | */ - MAV_MISSION_INVALID_PARAM5_X=10, /* x/param5 has an invalid value | */ - MAV_MISSION_INVALID_PARAM6_Y=11, /* y/param6 has an invalid value | */ - MAV_MISSION_INVALID_PARAM7=12, /* param7 has an invalid value | */ - MAV_MISSION_INVALID_SEQUENCE=13, /* received waypoint out of sequence | */ - MAV_MISSION_DENIED=14, /* not accepting any mission commands from this communication partner | */ - MAV_MISSION_RESULT_ENUM_END=15 /* | */ + MAV_MISSION_ACCEPTED=0, /* mission accepted OK | */ + MAV_MISSION_ERROR=1, /* generic error / not accepting mission commands at all right now | */ + MAV_MISSION_UNSUPPORTED_FRAME=2, /* coordinate frame is not supported | */ + MAV_MISSION_UNSUPPORTED=3, /* command is not supported | */ + MAV_MISSION_NO_SPACE=4, /* mission item exceeds storage space | */ + MAV_MISSION_INVALID=5, /* one of the parameters has an invalid value | */ + MAV_MISSION_INVALID_PARAM1=6, /* param1 has an invalid value | */ + MAV_MISSION_INVALID_PARAM2=7, /* param2 has an invalid value | */ + MAV_MISSION_INVALID_PARAM3=8, /* param3 has an invalid value | */ + MAV_MISSION_INVALID_PARAM4=9, /* param4 has an invalid value | */ + MAV_MISSION_INVALID_PARAM5_X=10, /* x/param5 has an invalid value | */ + MAV_MISSION_INVALID_PARAM6_Y=11, /* y/param6 has an invalid value | */ + MAV_MISSION_INVALID_PARAM7=12, /* param7 has an invalid value | */ + MAV_MISSION_INVALID_SEQUENCE=13, /* received waypoint out of sequence | */ + MAV_MISSION_DENIED=14, /* not accepting any mission commands from this communication partner | */ + MAV_MISSION_RESULT_ENUM_END=15 /* | */ } MAV_MISSION_RESULT; #endif @@ -437,15 +603,15 @@ typedef enum MAV_MISSION_RESULT #define HAVE_ENUM_MAV_SEVERITY typedef enum MAV_SEVERITY { - MAV_SEVERITY_EMERGENCY=0, /* System is unusable. This is a "panic" condition. | */ - MAV_SEVERITY_ALERT=1, /* Action should be taken immediately. Indicates error in non-critical systems. | */ - MAV_SEVERITY_CRITICAL=2, /* Action must be taken immediately. Indicates failure in a primary system. | */ - MAV_SEVERITY_ERROR=3, /* Indicates an error in secondary/redundant systems. | */ - MAV_SEVERITY_WARNING=4, /* Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. | */ - MAV_SEVERITY_NOTICE=5, /* An unusual event has occured, though not an error condition. This should be investigated for the root cause. | */ - MAV_SEVERITY_INFO=6, /* Normal operational messages. Useful for logging. No action is required for these messages. | */ - MAV_SEVERITY_DEBUG=7, /* Useful non-operational messages that can assist in debugging. These should not occur during normal operation. | */ - MAV_SEVERITY_ENUM_END=8 /* | */ + MAV_SEVERITY_EMERGENCY=0, /* System is unusable. This is a "panic" condition. | */ + MAV_SEVERITY_ALERT=1, /* Action should be taken immediately. Indicates error in non-critical systems. | */ + MAV_SEVERITY_CRITICAL=2, /* Action must be taken immediately. Indicates failure in a primary system. | */ + MAV_SEVERITY_ERROR=3, /* Indicates an error in secondary/redundant systems. | */ + MAV_SEVERITY_WARNING=4, /* Indicates about a possible future error if this is not resolved within a given timeframe. Example would be a low battery warning. | */ + MAV_SEVERITY_NOTICE=5, /* An unusual event has occured, though not an error condition. This should be investigated for the root cause. | */ + MAV_SEVERITY_INFO=6, /* Normal operational messages. Useful for logging. No action is required for these messages. | */ + MAV_SEVERITY_DEBUG=7, /* Useful non-operational messages that can assist in debugging. These should not occur during normal operation. | */ + MAV_SEVERITY_ENUM_END=8 /* | */ } MAV_SEVERITY; #endif @@ -454,13 +620,13 @@ typedef enum MAV_SEVERITY #define HAVE_ENUM_MAV_POWER_STATUS typedef enum MAV_POWER_STATUS { - MAV_POWER_STATUS_BRICK_VALID=1, /* main brick power supply valid | */ - MAV_POWER_STATUS_SERVO_VALID=2, /* main servo power supply valid for FMU | */ - MAV_POWER_STATUS_USB_CONNECTED=4, /* USB power is connected | */ - MAV_POWER_STATUS_PERIPH_OVERCURRENT=8, /* peripheral supply is in over-current state | */ - MAV_POWER_STATUS_PERIPH_HIPOWER_OVERCURRENT=16, /* hi-power peripheral supply is in over-current state | */ - MAV_POWER_STATUS_CHANGED=32, /* Power status has changed since boot | */ - MAV_POWER_STATUS_ENUM_END=33 /* | */ + MAV_POWER_STATUS_BRICK_VALID=1, /* main brick power supply valid | */ + MAV_POWER_STATUS_SERVO_VALID=2, /* main servo power supply valid for FMU | */ + MAV_POWER_STATUS_USB_CONNECTED=4, /* USB power is connected | */ + MAV_POWER_STATUS_PERIPH_OVERCURRENT=8, /* peripheral supply is in over-current state | */ + MAV_POWER_STATUS_PERIPH_HIPOWER_OVERCURRENT=16, /* hi-power peripheral supply is in over-current state | */ + MAV_POWER_STATUS_CHANGED=32, /* Power status has changed since boot | */ + MAV_POWER_STATUS_ENUM_END=33 /* | */ } MAV_POWER_STATUS; #endif @@ -469,11 +635,12 @@ typedef enum MAV_POWER_STATUS #define HAVE_ENUM_SERIAL_CONTROL_DEV typedef enum SERIAL_CONTROL_DEV { - SERIAL_CONTROL_DEV_TELEM1=0, /* First telemetry port | */ - SERIAL_CONTROL_DEV_TELEM2=1, /* Second telemetry port | */ - SERIAL_CONTROL_DEV_GPS1=2, /* First GPS port | */ - SERIAL_CONTROL_DEV_GPS2=3, /* Second GPS port | */ - SERIAL_CONTROL_DEV_ENUM_END=4 /* | */ + SERIAL_CONTROL_DEV_TELEM1=0, /* First telemetry port | */ + SERIAL_CONTROL_DEV_TELEM2=1, /* Second telemetry port | */ + SERIAL_CONTROL_DEV_GPS1=2, /* First GPS port | */ + SERIAL_CONTROL_DEV_GPS2=3, /* Second GPS port | */ + SERIAL_CONTROL_DEV_SHELL=10, /* system shell | */ + SERIAL_CONTROL_DEV_ENUM_END=11 /* | */ } SERIAL_CONTROL_DEV; #endif @@ -482,12 +649,12 @@ typedef enum SERIAL_CONTROL_DEV #define HAVE_ENUM_SERIAL_CONTROL_FLAG typedef enum SERIAL_CONTROL_FLAG { - SERIAL_CONTROL_FLAG_REPLY=1, /* Set if this is a reply | */ - SERIAL_CONTROL_FLAG_RESPOND=2, /* Set if the sender wants the receiver to send a response as another SERIAL_CONTROL message | */ - SERIAL_CONTROL_FLAG_EXCLUSIVE=4, /* Set if access to the serial port should be removed from whatever driver is currently using it, giving exclusive access to the SERIAL_CONTROL protocol. The port can be handed back by sending a request without this flag set | */ - SERIAL_CONTROL_FLAG_BLOCKING=8, /* Block on writes to the serial port | */ - SERIAL_CONTROL_FLAG_MULTI=16, /* Send multiple replies until port is drained | */ - SERIAL_CONTROL_FLAG_ENUM_END=17 /* | */ + SERIAL_CONTROL_FLAG_REPLY=1, /* Set if this is a reply | */ + SERIAL_CONTROL_FLAG_RESPOND=2, /* Set if the sender wants the receiver to send a response as another SERIAL_CONTROL message | */ + SERIAL_CONTROL_FLAG_EXCLUSIVE=4, /* Set if access to the serial port should be removed from whatever driver is currently using it, giving exclusive access to the SERIAL_CONTROL protocol. The port can be handed back by sending a request without this flag set | */ + SERIAL_CONTROL_FLAG_BLOCKING=8, /* Block on writes to the serial port | */ + SERIAL_CONTROL_FLAG_MULTI=16, /* Send multiple replies until port is drained | */ + SERIAL_CONTROL_FLAG_ENUM_END=17 /* | */ } SERIAL_CONTROL_FLAG; #endif @@ -496,43 +663,110 @@ typedef enum SERIAL_CONTROL_FLAG #define HAVE_ENUM_MAV_DISTANCE_SENSOR typedef enum MAV_DISTANCE_SENSOR { - MAV_DISTANCE_SENSOR_LASER=0, /* Laser altimeter, e.g. LightWare SF02/F or PulsedLight units | */ - MAV_DISTANCE_SENSOR_ULTRASOUND=1, /* Ultrasound altimeter, e.g. MaxBotix units | */ - MAV_DISTANCE_SENSOR_ENUM_END=2 /* | */ + MAV_DISTANCE_SENSOR_LASER=0, /* Laser rangefinder, e.g. LightWare SF02/F or PulsedLight units | */ + MAV_DISTANCE_SENSOR_ULTRASOUND=1, /* Ultrasound rangefinder, e.g. MaxBotix units | */ + MAV_DISTANCE_SENSOR_INFRARED=2, /* Infrared rangefinder, e.g. Sharp units | */ + MAV_DISTANCE_SENSOR_ENUM_END=3 /* | */ } MAV_DISTANCE_SENSOR; #endif +/** @brief Enumeration of sensor orientation, according to its rotations */ +#ifndef HAVE_ENUM_MAV_SENSOR_ORIENTATION +#define HAVE_ENUM_MAV_SENSOR_ORIENTATION +typedef enum MAV_SENSOR_ORIENTATION +{ + MAV_SENSOR_ROTATION_NONE=0, /* Roll: 0, Pitch: 0, Yaw: 0 | */ + MAV_SENSOR_ROTATION_YAW_45=1, /* Roll: 0, Pitch: 0, Yaw: 45 | */ + MAV_SENSOR_ROTATION_YAW_90=2, /* Roll: 0, Pitch: 0, Yaw: 90 | */ + MAV_SENSOR_ROTATION_YAW_135=3, /* Roll: 0, Pitch: 0, Yaw: 135 | */ + MAV_SENSOR_ROTATION_YAW_180=4, /* Roll: 0, Pitch: 0, Yaw: 180 | */ + MAV_SENSOR_ROTATION_YAW_225=5, /* Roll: 0, Pitch: 0, Yaw: 225 | */ + MAV_SENSOR_ROTATION_YAW_270=6, /* Roll: 0, Pitch: 0, Yaw: 270 | */ + MAV_SENSOR_ROTATION_YAW_315=7, /* Roll: 0, Pitch: 0, Yaw: 315 | */ + MAV_SENSOR_ROTATION_ROLL_180=8, /* Roll: 180, Pitch: 0, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_180_YAW_45=9, /* Roll: 180, Pitch: 0, Yaw: 45 | */ + MAV_SENSOR_ROTATION_ROLL_180_YAW_90=10, /* Roll: 180, Pitch: 0, Yaw: 90 | */ + MAV_SENSOR_ROTATION_ROLL_180_YAW_135=11, /* Roll: 180, Pitch: 0, Yaw: 135 | */ + MAV_SENSOR_ROTATION_PITCH_180=12, /* Roll: 0, Pitch: 180, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_180_YAW_225=13, /* Roll: 180, Pitch: 0, Yaw: 225 | */ + MAV_SENSOR_ROTATION_ROLL_180_YAW_270=14, /* Roll: 180, Pitch: 0, Yaw: 270 | */ + MAV_SENSOR_ROTATION_ROLL_180_YAW_315=15, /* Roll: 180, Pitch: 0, Yaw: 315 | */ + MAV_SENSOR_ROTATION_ROLL_90=16, /* Roll: 90, Pitch: 0, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_90_YAW_45=17, /* Roll: 90, Pitch: 0, Yaw: 45 | */ + MAV_SENSOR_ROTATION_ROLL_90_YAW_90=18, /* Roll: 90, Pitch: 0, Yaw: 90 | */ + MAV_SENSOR_ROTATION_ROLL_90_YAW_135=19, /* Roll: 90, Pitch: 0, Yaw: 135 | */ + MAV_SENSOR_ROTATION_ROLL_270=20, /* Roll: 270, Pitch: 0, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_270_YAW_45=21, /* Roll: 270, Pitch: 0, Yaw: 45 | */ + MAV_SENSOR_ROTATION_ROLL_270_YAW_90=22, /* Roll: 270, Pitch: 0, Yaw: 90 | */ + MAV_SENSOR_ROTATION_ROLL_270_YAW_135=23, /* Roll: 270, Pitch: 0, Yaw: 135 | */ + MAV_SENSOR_ROTATION_PITCH_90=24, /* Roll: 0, Pitch: 90, Yaw: 0 | */ + MAV_SENSOR_ROTATION_PITCH_270=25, /* Roll: 0, Pitch: 270, Yaw: 0 | */ + MAV_SENSOR_ROTATION_PITCH_180_YAW_90=26, /* Roll: 0, Pitch: 180, Yaw: 90 | */ + MAV_SENSOR_ROTATION_PITCH_180_YAW_270=27, /* Roll: 0, Pitch: 180, Yaw: 270 | */ + MAV_SENSOR_ROTATION_ROLL_90_PITCH_90=28, /* Roll: 90, Pitch: 90, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_180_PITCH_90=29, /* Roll: 180, Pitch: 90, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_270_PITCH_90=30, /* Roll: 270, Pitch: 90, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_90_PITCH_180=31, /* Roll: 90, Pitch: 180, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_270_PITCH_180=32, /* Roll: 270, Pitch: 180, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_90_PITCH_270=33, /* Roll: 90, Pitch: 270, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_180_PITCH_270=34, /* Roll: 180, Pitch: 270, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_270_PITCH_270=35, /* Roll: 270, Pitch: 270, Yaw: 0 | */ + MAV_SENSOR_ROTATION_ROLL_90_PITCH_180_YAW_90=36, /* Roll: 90, Pitch: 180, Yaw: 90 | */ + MAV_SENSOR_ROTATION_ROLL_90_YAW_270=37, /* Roll: 90, Pitch: 0, Yaw: 270 | */ + MAV_SENSOR_ROTATION_ROLL_315_PITCH_315_YAW_315=38, /* Roll: 315, Pitch: 315, Yaw: 315 | */ + MAV_SENSOR_ORIENTATION_ENUM_END=39 /* | */ +} MAV_SENSOR_ORIENTATION; +#endif + /** @brief Bitmask of (optional) autopilot capabilities (64 bit). If a bit is set, the autopilot supports this capability. */ #ifndef HAVE_ENUM_MAV_PROTOCOL_CAPABILITY #define HAVE_ENUM_MAV_PROTOCOL_CAPABILITY typedef enum MAV_PROTOCOL_CAPABILITY { - MAV_PROTOCOL_CAPABILITY_MISSION_FLOAT=1, /* Autopilot supports MISSION float message type. | */ - MAV_PROTOCOL_CAPABILITY_PARAM_FLOAT=2, /* Autopilot supports the new param float message type. | */ - MAV_PROTOCOL_CAPABILITY_MISSION_INT=4, /* Autopilot supports MISSION_INT scaled integer message type. | */ - MAV_PROTOCOL_CAPABILITY_COMMAND_INT=8, /* Autopilot supports COMMAND_INT scaled integer message type. | */ - MAV_PROTOCOL_CAPABILITY_PARAM_UNION=16, /* Autopilot supports the new param union message type. | */ - MAV_PROTOCOL_CAPABILITY_FTP=32, /* Autopilot supports the new param union message type. | */ - MAV_PROTOCOL_CAPABILITY_SET_ATTITUDE_TARGET=64, /* Autopilot supports commanding attitude offboard. | */ - MAV_PROTOCOL_CAPABILITY_SET_POSITION_TARGET_LOCAL_NED=128, /* Autopilot supports commanding position and velocity targets in local NED frame. | */ - MAV_PROTOCOL_CAPABILITY_SET_POSITION_TARGET_GLOBAL_INT=256, /* Autopilot supports commanding position and velocity targets in global scaled integers. | */ - MAV_PROTOCOL_CAPABILITY_TERRAIN=512, /* Autopilot supports terrain protocol / data handling. | */ - MAV_PROTOCOL_CAPABILITY_SET_ACTUATOR_TARGET=1024, /* Autopilot supports direct actuator control. | */ - MAV_PROTOCOL_CAPABILITY_ENUM_END=1025 /* | */ + MAV_PROTOCOL_CAPABILITY_MISSION_FLOAT=1, /* Autopilot supports MISSION float message type. | */ + MAV_PROTOCOL_CAPABILITY_PARAM_FLOAT=2, /* Autopilot supports the new param float message type. | */ + MAV_PROTOCOL_CAPABILITY_MISSION_INT=4, /* Autopilot supports MISSION_INT scaled integer message type. | */ + MAV_PROTOCOL_CAPABILITY_COMMAND_INT=8, /* Autopilot supports COMMAND_INT scaled integer message type. | */ + MAV_PROTOCOL_CAPABILITY_PARAM_UNION=16, /* Autopilot supports the new param union message type. | */ + MAV_PROTOCOL_CAPABILITY_FTP=32, /* Autopilot supports the new FILE_TRANSFER_PROTOCOL message type. | */ + MAV_PROTOCOL_CAPABILITY_SET_ATTITUDE_TARGET=64, /* Autopilot supports commanding attitude offboard. | */ + MAV_PROTOCOL_CAPABILITY_SET_POSITION_TARGET_LOCAL_NED=128, /* Autopilot supports commanding position and velocity targets in local NED frame. | */ + MAV_PROTOCOL_CAPABILITY_SET_POSITION_TARGET_GLOBAL_INT=256, /* Autopilot supports commanding position and velocity targets in global scaled integers. | */ + MAV_PROTOCOL_CAPABILITY_TERRAIN=512, /* Autopilot supports terrain protocol / data handling. | */ + MAV_PROTOCOL_CAPABILITY_SET_ACTUATOR_TARGET=1024, /* Autopilot supports direct actuator control. | */ + MAV_PROTOCOL_CAPABILITY_FLIGHT_TERMINATION=2048, /* Autopilot supports the flight termination command. | */ + MAV_PROTOCOL_CAPABILITY_COMPASS_CALIBRATION=4096, /* Autopilot supports onboard compass calibration. | */ + MAV_PROTOCOL_CAPABILITY_MAVLINK2=8192, /* Autopilot supports mavlink version 2. | */ + MAV_PROTOCOL_CAPABILITY_MISSION_FENCE=16384, /* Autopilot supports mission fence protocol. | */ + MAV_PROTOCOL_CAPABILITY_MISSION_RALLY=32768, /* Autopilot supports mission rally point protocol. | */ + MAV_PROTOCOL_CAPABILITY_ENUM_END=32769 /* | */ } MAV_PROTOCOL_CAPABILITY; #endif +/** @brief Type of mission items being requested/sent in mission protocol. */ +#ifndef HAVE_ENUM_MAV_MISSION_TYPE +#define HAVE_ENUM_MAV_MISSION_TYPE +typedef enum MAV_MISSION_TYPE +{ + MAV_MISSION_TYPE_MISSION=0, /* Items are mission commands for main mission. | */ + MAV_MISSION_TYPE_FENCE=1, /* Specifies GeoFence area(s). Items are MAV_CMD_FENCE_ GeoFence items. | */ + MAV_MISSION_TYPE_RALLY=2, /* Specifies the rally points for the vehicle. Rally points are alternative RTL points. Items are MAV_CMD_RALLY_POINT rally point items. | */ + MAV_MISSION_TYPE_ALL=255, /* Only used in MISSION_CLEAR_ALL to clear all mission types. | */ + MAV_MISSION_TYPE_ENUM_END=256 /* | */ +} MAV_MISSION_TYPE; +#endif + /** @brief Enumeration of estimator types */ #ifndef HAVE_ENUM_MAV_ESTIMATOR_TYPE #define HAVE_ENUM_MAV_ESTIMATOR_TYPE typedef enum MAV_ESTIMATOR_TYPE { - MAV_ESTIMATOR_TYPE_NAIVE=1, /* This is a naive estimator without any real covariance feedback. | */ - MAV_ESTIMATOR_TYPE_VISION=2, /* Computer vision based estimate. Might be up to scale. | */ - MAV_ESTIMATOR_TYPE_VIO=3, /* Visual-inertial estimate. | */ - MAV_ESTIMATOR_TYPE_GPS=4, /* Plain GPS estimate. | */ - MAV_ESTIMATOR_TYPE_GPS_INS=5, /* Estimator integrating GPS and inertial sensing. | */ - MAV_ESTIMATOR_TYPE_ENUM_END=6 /* | */ + MAV_ESTIMATOR_TYPE_NAIVE=1, /* This is a naive estimator without any real covariance feedback. | */ + MAV_ESTIMATOR_TYPE_VISION=2, /* Computer vision based estimate. Might be up to scale. | */ + MAV_ESTIMATOR_TYPE_VIO=3, /* Visual-inertial estimate. | */ + MAV_ESTIMATOR_TYPE_GPS=4, /* Plain GPS estimate. | */ + MAV_ESTIMATOR_TYPE_GPS_INS=5, /* Estimator integrating GPS and inertial sensing. | */ + MAV_ESTIMATOR_TYPE_ENUM_END=6 /* | */ } MAV_ESTIMATOR_TYPE; #endif @@ -541,12 +775,12 @@ typedef enum MAV_ESTIMATOR_TYPE #define HAVE_ENUM_MAV_BATTERY_TYPE typedef enum MAV_BATTERY_TYPE { - MAV_BATTERY_TYPE_UNKNOWN=0, /* Not specified. | */ - MAV_BATTERY_TYPE_LIPO=1, /* Lithium polymere battery | */ - MAV_BATTERY_TYPE_LIFE=2, /* Lithium ferrite battery | */ - MAV_BATTERY_TYPE_LION=3, /* Lithium-ION battery | */ - MAV_BATTERY_TYPE_NIMH=4, /* Nickel metal hydride battery | */ - MAV_BATTERY_TYPE_ENUM_END=5 /* | */ + MAV_BATTERY_TYPE_UNKNOWN=0, /* Not specified. | */ + MAV_BATTERY_TYPE_LIPO=1, /* Lithium polymer battery | */ + MAV_BATTERY_TYPE_LIFE=2, /* Lithium-iron-phosphate battery | */ + MAV_BATTERY_TYPE_LION=3, /* Lithium-ION battery | */ + MAV_BATTERY_TYPE_NIMH=4, /* Nickel metal hydride battery | */ + MAV_BATTERY_TYPE_ENUM_END=5 /* | */ } MAV_BATTERY_TYPE; #endif @@ -555,16 +789,213 @@ typedef enum MAV_BATTERY_TYPE #define HAVE_ENUM_MAV_BATTERY_FUNCTION typedef enum MAV_BATTERY_FUNCTION { - MAV_BATTERY_FUNCTION_UNKNOWN=0, /* Lithium polymere battery | */ - MAV_BATTERY_FUNCTION_ALL=1, /* Battery supports all flight systems | */ - MAV_BATTERY_FUNCTION_PROPULSION=2, /* Battery for the propulsion system | */ - MAV_BATTERY_FUNCTION_AVIONICS=3, /* Avionics battery | */ - MAV_BATTERY_TYPE_PAYLOAD=4, /* Payload battery | */ - MAV_BATTERY_FUNCTION_ENUM_END=5 /* | */ + MAV_BATTERY_FUNCTION_UNKNOWN=0, /* Battery function is unknown | */ + MAV_BATTERY_FUNCTION_ALL=1, /* Battery supports all flight systems | */ + MAV_BATTERY_FUNCTION_PROPULSION=2, /* Battery for the propulsion system | */ + MAV_BATTERY_FUNCTION_AVIONICS=3, /* Avionics battery | */ + MAV_BATTERY_TYPE_PAYLOAD=4, /* Payload battery | */ + MAV_BATTERY_FUNCTION_ENUM_END=5 /* | */ } MAV_BATTERY_FUNCTION; #endif +/** @brief Enumeration of VTOL states */ +#ifndef HAVE_ENUM_MAV_VTOL_STATE +#define HAVE_ENUM_MAV_VTOL_STATE +typedef enum MAV_VTOL_STATE +{ + MAV_VTOL_STATE_UNDEFINED=0, /* MAV is not configured as VTOL | */ + MAV_VTOL_STATE_TRANSITION_TO_FW=1, /* VTOL is in transition from multicopter to fixed-wing | */ + MAV_VTOL_STATE_TRANSITION_TO_MC=2, /* VTOL is in transition from fixed-wing to multicopter | */ + MAV_VTOL_STATE_MC=3, /* VTOL is in multicopter state | */ + MAV_VTOL_STATE_FW=4, /* VTOL is in fixed-wing state | */ + MAV_VTOL_STATE_ENUM_END=5 /* | */ +} MAV_VTOL_STATE; +#endif + +/** @brief Enumeration of landed detector states */ +#ifndef HAVE_ENUM_MAV_LANDED_STATE +#define HAVE_ENUM_MAV_LANDED_STATE +typedef enum MAV_LANDED_STATE +{ + MAV_LANDED_STATE_UNDEFINED=0, /* MAV landed state is unknown | */ + MAV_LANDED_STATE_ON_GROUND=1, /* MAV is landed (on ground) | */ + MAV_LANDED_STATE_IN_AIR=2, /* MAV is in air | */ + MAV_LANDED_STATE_TAKEOFF=3, /* MAV currently taking off | */ + MAV_LANDED_STATE_LANDING=4, /* MAV currently landing | */ + MAV_LANDED_STATE_ENUM_END=5 /* | */ +} MAV_LANDED_STATE; +#endif +/** @brief Enumeration of the ADSB altimeter types */ +#ifndef HAVE_ENUM_ADSB_ALTITUDE_TYPE +#define HAVE_ENUM_ADSB_ALTITUDE_TYPE +typedef enum ADSB_ALTITUDE_TYPE +{ + ADSB_ALTITUDE_TYPE_PRESSURE_QNH=0, /* Altitude reported from a Baro source using QNH reference | */ + ADSB_ALTITUDE_TYPE_GEOMETRIC=1, /* Altitude reported from a GNSS source | */ + ADSB_ALTITUDE_TYPE_ENUM_END=2 /* | */ +} ADSB_ALTITUDE_TYPE; +#endif + +/** @brief ADSB classification for the type of vehicle emitting the transponder signal */ +#ifndef HAVE_ENUM_ADSB_EMITTER_TYPE +#define HAVE_ENUM_ADSB_EMITTER_TYPE +typedef enum ADSB_EMITTER_TYPE +{ + ADSB_EMITTER_TYPE_NO_INFO=0, /* | */ + ADSB_EMITTER_TYPE_LIGHT=1, /* | */ + ADSB_EMITTER_TYPE_SMALL=2, /* | */ + ADSB_EMITTER_TYPE_LARGE=3, /* | */ + ADSB_EMITTER_TYPE_HIGH_VORTEX_LARGE=4, /* | */ + ADSB_EMITTER_TYPE_HEAVY=5, /* | */ + ADSB_EMITTER_TYPE_HIGHLY_MANUV=6, /* | */ + ADSB_EMITTER_TYPE_ROTOCRAFT=7, /* | */ + ADSB_EMITTER_TYPE_UNASSIGNED=8, /* | */ + ADSB_EMITTER_TYPE_GLIDER=9, /* | */ + ADSB_EMITTER_TYPE_LIGHTER_AIR=10, /* | */ + ADSB_EMITTER_TYPE_PARACHUTE=11, /* | */ + ADSB_EMITTER_TYPE_ULTRA_LIGHT=12, /* | */ + ADSB_EMITTER_TYPE_UNASSIGNED2=13, /* | */ + ADSB_EMITTER_TYPE_UAV=14, /* | */ + ADSB_EMITTER_TYPE_SPACE=15, /* | */ + ADSB_EMITTER_TYPE_UNASSGINED3=16, /* | */ + ADSB_EMITTER_TYPE_EMERGENCY_SURFACE=17, /* | */ + ADSB_EMITTER_TYPE_SERVICE_SURFACE=18, /* | */ + ADSB_EMITTER_TYPE_POINT_OBSTACLE=19, /* | */ + ADSB_EMITTER_TYPE_ENUM_END=20 /* | */ +} ADSB_EMITTER_TYPE; +#endif + +/** @brief These flags indicate status such as data validity of each data source. Set = data valid */ +#ifndef HAVE_ENUM_ADSB_FLAGS +#define HAVE_ENUM_ADSB_FLAGS +typedef enum ADSB_FLAGS +{ + ADSB_FLAGS_VALID_COORDS=1, /* | */ + ADSB_FLAGS_VALID_ALTITUDE=2, /* | */ + ADSB_FLAGS_VALID_HEADING=4, /* | */ + ADSB_FLAGS_VALID_VELOCITY=8, /* | */ + ADSB_FLAGS_VALID_CALLSIGN=16, /* | */ + ADSB_FLAGS_VALID_SQUAWK=32, /* | */ + ADSB_FLAGS_SIMULATED=64, /* | */ + ADSB_FLAGS_ENUM_END=65 /* | */ +} ADSB_FLAGS; +#endif + +/** @brief Bitmask of options for the MAV_CMD_DO_REPOSITION */ +#ifndef HAVE_ENUM_MAV_DO_REPOSITION_FLAGS +#define HAVE_ENUM_MAV_DO_REPOSITION_FLAGS +typedef enum MAV_DO_REPOSITION_FLAGS +{ + MAV_DO_REPOSITION_FLAGS_CHANGE_MODE=1, /* The aircraft should immediately transition into guided. This should not be set for follow me applications | */ + MAV_DO_REPOSITION_FLAGS_ENUM_END=2 /* | */ +} MAV_DO_REPOSITION_FLAGS; +#endif + +/** @brief Flags in EKF_STATUS message */ +#ifndef HAVE_ENUM_ESTIMATOR_STATUS_FLAGS +#define HAVE_ENUM_ESTIMATOR_STATUS_FLAGS +typedef enum ESTIMATOR_STATUS_FLAGS +{ + ESTIMATOR_ATTITUDE=1, /* True if the attitude estimate is good | */ + ESTIMATOR_VELOCITY_HORIZ=2, /* True if the horizontal velocity estimate is good | */ + ESTIMATOR_VELOCITY_VERT=4, /* True if the vertical velocity estimate is good | */ + ESTIMATOR_POS_HORIZ_REL=8, /* True if the horizontal position (relative) estimate is good | */ + ESTIMATOR_POS_HORIZ_ABS=16, /* True if the horizontal position (absolute) estimate is good | */ + ESTIMATOR_POS_VERT_ABS=32, /* True if the vertical position (absolute) estimate is good | */ + ESTIMATOR_POS_VERT_AGL=64, /* True if the vertical position (above ground) estimate is good | */ + ESTIMATOR_CONST_POS_MODE=128, /* True if the EKF is in a constant position mode and is not using external measurements (eg GPS or optical flow) | */ + ESTIMATOR_PRED_POS_HORIZ_REL=256, /* True if the EKF has sufficient data to enter a mode that will provide a (relative) position estimate | */ + ESTIMATOR_PRED_POS_HORIZ_ABS=512, /* True if the EKF has sufficient data to enter a mode that will provide a (absolute) position estimate | */ + ESTIMATOR_GPS_GLITCH=1024, /* True if the EKF has detected a GPS glitch | */ + ESTIMATOR_STATUS_FLAGS_ENUM_END=1025 /* | */ +} ESTIMATOR_STATUS_FLAGS; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_MOTOR_TEST_THROTTLE_TYPE +#define HAVE_ENUM_MOTOR_TEST_THROTTLE_TYPE +typedef enum MOTOR_TEST_THROTTLE_TYPE +{ + MOTOR_TEST_THROTTLE_PERCENT=0, /* throttle as a percentage from 0 ~ 100 | */ + MOTOR_TEST_THROTTLE_PWM=1, /* throttle as an absolute PWM value (normally in range of 1000~2000) | */ + MOTOR_TEST_THROTTLE_PILOT=2, /* throttle pass-through from pilot's transmitter | */ + MOTOR_TEST_THROTTLE_TYPE_ENUM_END=3 /* | */ +} MOTOR_TEST_THROTTLE_TYPE; +#endif + +/** @brief */ +#ifndef HAVE_ENUM_GPS_INPUT_IGNORE_FLAGS +#define HAVE_ENUM_GPS_INPUT_IGNORE_FLAGS +typedef enum GPS_INPUT_IGNORE_FLAGS +{ + GPS_INPUT_IGNORE_FLAG_ALT=1, /* ignore altitude field | */ + GPS_INPUT_IGNORE_FLAG_HDOP=2, /* ignore hdop field | */ + GPS_INPUT_IGNORE_FLAG_VDOP=4, /* ignore vdop field | */ + GPS_INPUT_IGNORE_FLAG_VEL_HORIZ=8, /* ignore horizontal velocity field (vn and ve) | */ + GPS_INPUT_IGNORE_FLAG_VEL_VERT=16, /* ignore vertical velocity field (vd) | */ + GPS_INPUT_IGNORE_FLAG_SPEED_ACCURACY=32, /* ignore speed accuracy field | */ + GPS_INPUT_IGNORE_FLAG_HORIZONTAL_ACCURACY=64, /* ignore horizontal accuracy field | */ + GPS_INPUT_IGNORE_FLAG_VERTICAL_ACCURACY=128, /* ignore vertical accuracy field | */ + GPS_INPUT_IGNORE_FLAGS_ENUM_END=129 /* | */ +} GPS_INPUT_IGNORE_FLAGS; +#endif + +/** @brief Possible actions an aircraft can take to avoid a collision. */ +#ifndef HAVE_ENUM_MAV_COLLISION_ACTION +#define HAVE_ENUM_MAV_COLLISION_ACTION +typedef enum MAV_COLLISION_ACTION +{ + MAV_COLLISION_ACTION_NONE=0, /* Ignore any potential collisions | */ + MAV_COLLISION_ACTION_REPORT=1, /* Report potential collision | */ + MAV_COLLISION_ACTION_ASCEND_OR_DESCEND=2, /* Ascend or Descend to avoid threat | */ + MAV_COLLISION_ACTION_MOVE_HORIZONTALLY=3, /* Move horizontally to avoid threat | */ + MAV_COLLISION_ACTION_MOVE_PERPENDICULAR=4, /* Aircraft to move perpendicular to the collision's velocity vector | */ + MAV_COLLISION_ACTION_RTL=5, /* Aircraft to fly directly back to its launch point | */ + MAV_COLLISION_ACTION_HOVER=6, /* Aircraft to stop in place | */ + MAV_COLLISION_ACTION_ENUM_END=7 /* | */ +} MAV_COLLISION_ACTION; +#endif + +/** @brief Aircraft-rated danger from this threat. */ +#ifndef HAVE_ENUM_MAV_COLLISION_THREAT_LEVEL +#define HAVE_ENUM_MAV_COLLISION_THREAT_LEVEL +typedef enum MAV_COLLISION_THREAT_LEVEL +{ + MAV_COLLISION_THREAT_LEVEL_NONE=0, /* Not a threat | */ + MAV_COLLISION_THREAT_LEVEL_LOW=1, /* Craft is mildly concerned about this threat | */ + MAV_COLLISION_THREAT_LEVEL_HIGH=2, /* Craft is panicing, and may take actions to avoid threat | */ + MAV_COLLISION_THREAT_LEVEL_ENUM_END=3 /* | */ +} MAV_COLLISION_THREAT_LEVEL; +#endif + +/** @brief Source of information about this collision. */ +#ifndef HAVE_ENUM_MAV_COLLISION_SRC +#define HAVE_ENUM_MAV_COLLISION_SRC +typedef enum MAV_COLLISION_SRC +{ + MAV_COLLISION_SRC_ADSB=0, /* ID field references ADSB_VEHICLE packets | */ + MAV_COLLISION_SRC_MAVLINK_GPS_GLOBAL_INT=1, /* ID field references MAVLink SRC ID | */ + MAV_COLLISION_SRC_ENUM_END=2 /* | */ +} MAV_COLLISION_SRC; +#endif + +/** @brief Type of GPS fix */ +#ifndef HAVE_ENUM_GPS_FIX_TYPE +#define HAVE_ENUM_GPS_FIX_TYPE +typedef enum GPS_FIX_TYPE +{ + GPS_FIX_TYPE_NO_GPS=0, /* No GPS connected | */ + GPS_FIX_TYPE_NO_FIX=1, /* No position information, GPS is connected | */ + GPS_FIX_TYPE_2D_FIX=2, /* 2D position | */ + GPS_FIX_TYPE_3D_FIX=3, /* 3D position | */ + GPS_FIX_TYPE_DGPS=4, /* DGPS/SBAS aided 3D position | */ + GPS_FIX_TYPE_RTK_FLOAT=5, /* RTK float, 3D position | */ + GPS_FIX_TYPE_RTK_FIXED=6, /* RTK Fixed, 3D position | */ + GPS_FIX_TYPE_STATIC=7, /* Static fixed, typically used for base stations | */ + GPS_FIX_TYPE_ENUM_END=8 /* | */ +} GPS_FIX_TYPE; +#endif // MAVLINK VERSION @@ -617,6 +1048,7 @@ typedef enum MAV_BATTERY_FUNCTION #include "./mavlink_msg_set_gps_global_origin.h" #include "./mavlink_msg_gps_global_origin.h" #include "./mavlink_msg_param_map_rc.h" +#include "./mavlink_msg_mission_request_int.h" #include "./mavlink_msg_safety_set_allowed_area.h" #include "./mavlink_msg_safety_allowed_area.h" #include "./mavlink_msg_attitude_quaternion_cov.h" @@ -644,6 +1076,7 @@ typedef enum MAV_BATTERY_FUNCTION #include "./mavlink_msg_hil_state.h" #include "./mavlink_msg_hil_controls.h" #include "./mavlink_msg_hil_rc_inputs_raw.h" +#include "./mavlink_msg_hil_actuator_controls.h" #include "./mavlink_msg_optical_flow.h" #include "./mavlink_msg_global_vision_position_estimate.h" #include "./mavlink_msg_vision_position_estimate.h" @@ -656,6 +1089,7 @@ typedef enum MAV_BATTERY_FUNCTION #include "./mavlink_msg_radio_status.h" #include "./mavlink_msg_file_transfer_protocol.h" #include "./mavlink_msg_timesync.h" +#include "./mavlink_msg_camera_trigger.h" #include "./mavlink_msg_hil_gps.h" #include "./mavlink_msg_hil_optical_flow.h" #include "./mavlink_msg_hil_state_quaternion.h" @@ -672,6 +1106,7 @@ typedef enum MAV_BATTERY_FUNCTION #include "./mavlink_msg_serial_control.h" #include "./mavlink_msg_gps_rtk.h" #include "./mavlink_msg_gps2_rtk.h" +#include "./mavlink_msg_scaled_imu3.h" #include "./mavlink_msg_data_transmission_handshake.h" #include "./mavlink_msg_encapsulated_data.h" #include "./mavlink_msg_distance_sensor.h" @@ -683,8 +1118,26 @@ typedef enum MAV_BATTERY_FUNCTION #include "./mavlink_msg_att_pos_mocap.h" #include "./mavlink_msg_set_actuator_control_target.h" #include "./mavlink_msg_actuator_control_target.h" +#include "./mavlink_msg_altitude.h" +#include "./mavlink_msg_resource_request.h" +#include "./mavlink_msg_scaled_pressure3.h" +#include "./mavlink_msg_follow_target.h" +#include "./mavlink_msg_control_system_state.h" #include "./mavlink_msg_battery_status.h" #include "./mavlink_msg_autopilot_version.h" +#include "./mavlink_msg_landing_target.h" +#include "./mavlink_msg_estimator_status.h" +#include "./mavlink_msg_wind_cov.h" +#include "./mavlink_msg_gps_input.h" +#include "./mavlink_msg_gps_rtcm_data.h" +#include "./mavlink_msg_high_latency.h" +#include "./mavlink_msg_vibration.h" +#include "./mavlink_msg_home_position.h" +#include "./mavlink_msg_set_home_position.h" +#include "./mavlink_msg_message_interval.h" +#include "./mavlink_msg_extended_sys_state.h" +#include "./mavlink_msg_adsb_vehicle.h" +#include "./mavlink_msg_collision.h" #include "./mavlink_msg_v2_extension.h" #include "./mavlink_msg_memory_vect.h" #include "./mavlink_msg_debug_vect.h" @@ -693,6 +1146,19 @@ typedef enum MAV_BATTERY_FUNCTION #include "./mavlink_msg_statustext.h" #include "./mavlink_msg_debug.h" +// base include + + +#undef MAVLINK_THIS_XML_IDX +#define MAVLINK_THIS_XML_IDX 1 + +#if MAVLINK_THIS_XML_IDX == MAVLINK_PRIMARY_XML_IDX +# define MAVLINK_MESSAGE_INFO {MAVLINK_MESSAGE_INFO_HEARTBEAT, MAVLINK_MESSAGE_INFO_SYS_STATUS, MAVLINK_MESSAGE_INFO_SYSTEM_TIME, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PING, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL, MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK, MAVLINK_MESSAGE_INFO_AUTH_KEY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SET_MODE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ, MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST, MAVLINK_MESSAGE_INFO_PARAM_VALUE, MAVLINK_MESSAGE_INFO_PARAM_SET, MAVLINK_MESSAGE_INFO_GPS_RAW_INT, MAVLINK_MESSAGE_INFO_GPS_STATUS, MAVLINK_MESSAGE_INFO_SCALED_IMU, MAVLINK_MESSAGE_INFO_RAW_IMU, MAVLINK_MESSAGE_INFO_RAW_PRESSURE, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE, MAVLINK_MESSAGE_INFO_ATTITUDE, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT, MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED, MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW, MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST, MAVLINK_MESSAGE_INFO_MISSION_ITEM, MAVLINK_MESSAGE_INFO_MISSION_REQUEST, MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_CURRENT, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST, MAVLINK_MESSAGE_INFO_MISSION_COUNT, MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL, MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED, MAVLINK_MESSAGE_INFO_MISSION_ACK, MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN, MAVLINK_MESSAGE_INFO_PARAM_MAP_RC, MAVLINK_MESSAGE_INFO_MISSION_REQUEST_INT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA, MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION_COV, MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT, MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT_COV, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_COV, MAVLINK_MESSAGE_INFO_RC_CHANNELS, MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM, MAVLINK_MESSAGE_INFO_DATA_STREAM, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_CONTROL, MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MISSION_ITEM_INT, MAVLINK_MESSAGE_INFO_VFR_HUD, MAVLINK_MESSAGE_INFO_COMMAND_INT, MAVLINK_MESSAGE_INFO_COMMAND_LONG, MAVLINK_MESSAGE_INFO_COMMAND_ACK, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT, MAVLINK_MESSAGE_INFO_SET_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_ATTITUDE_TARGET, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_POSITION_TARGET_LOCAL_NED, MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_GLOBAL_INT, MAVLINK_MESSAGE_INFO_POSITION_TARGET_GLOBAL_INT, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, MAVLINK_MESSAGE_INFO_HIL_STATE, MAVLINK_MESSAGE_INFO_HIL_CONTROLS, MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW, MAVLINK_MESSAGE_INFO_HIL_ACTUATOR_CONTROLS, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE, MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE, MAVLINK_MESSAGE_INFO_HIGHRES_IMU, MAVLINK_MESSAGE_INFO_OPTICAL_FLOW_RAD, MAVLINK_MESSAGE_INFO_HIL_SENSOR, MAVLINK_MESSAGE_INFO_SIM_STATE, MAVLINK_MESSAGE_INFO_RADIO_STATUS, MAVLINK_MESSAGE_INFO_FILE_TRANSFER_PROTOCOL, MAVLINK_MESSAGE_INFO_TIMESYNC, MAVLINK_MESSAGE_INFO_CAMERA_TRIGGER, MAVLINK_MESSAGE_INFO_HIL_GPS, MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW, MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION, MAVLINK_MESSAGE_INFO_SCALED_IMU2, MAVLINK_MESSAGE_INFO_LOG_REQUEST_LIST, MAVLINK_MESSAGE_INFO_LOG_ENTRY, MAVLINK_MESSAGE_INFO_LOG_REQUEST_DATA, MAVLINK_MESSAGE_INFO_LOG_DATA, MAVLINK_MESSAGE_INFO_LOG_ERASE, MAVLINK_MESSAGE_INFO_LOG_REQUEST_END, MAVLINK_MESSAGE_INFO_GPS_INJECT_DATA, MAVLINK_MESSAGE_INFO_GPS2_RAW, MAVLINK_MESSAGE_INFO_POWER_STATUS, MAVLINK_MESSAGE_INFO_SERIAL_CONTROL, MAVLINK_MESSAGE_INFO_GPS_RTK, MAVLINK_MESSAGE_INFO_GPS2_RTK, MAVLINK_MESSAGE_INFO_SCALED_IMU3, MAVLINK_MESSAGE_INFO_DATA_TRANSMISSION_HANDSHAKE, MAVLINK_MESSAGE_INFO_ENCAPSULATED_DATA, MAVLINK_MESSAGE_INFO_DISTANCE_SENSOR, MAVLINK_MESSAGE_INFO_TERRAIN_REQUEST, MAVLINK_MESSAGE_INFO_TERRAIN_DATA, MAVLINK_MESSAGE_INFO_TERRAIN_CHECK, MAVLINK_MESSAGE_INFO_TERRAIN_REPORT, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE2, MAVLINK_MESSAGE_INFO_ATT_POS_MOCAP, MAVLINK_MESSAGE_INFO_SET_ACTUATOR_CONTROL_TARGET, MAVLINK_MESSAGE_INFO_ACTUATOR_CONTROL_TARGET, MAVLINK_MESSAGE_INFO_ALTITUDE, MAVLINK_MESSAGE_INFO_RESOURCE_REQUEST, MAVLINK_MESSAGE_INFO_SCALED_PRESSURE3, MAVLINK_MESSAGE_INFO_FOLLOW_TARGET, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_CONTROL_SYSTEM_STATE, MAVLINK_MESSAGE_INFO_BATTERY_STATUS, MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION, MAVLINK_MESSAGE_INFO_LANDING_TARGET, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_ESTIMATOR_STATUS, MAVLINK_MESSAGE_INFO_WIND_COV, MAVLINK_MESSAGE_INFO_GPS_INPUT, MAVLINK_MESSAGE_INFO_GPS_RTCM_DATA, MAVLINK_MESSAGE_INFO_HIGH_LATENCY, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, MAVLINK_MESSAGE_INFO_VIBRATION, MAVLINK_MESSAGE_INFO_HOME_POSITION, MAVLINK_MESSAGE_INFO_SET_HOME_POSITION, MAVLINK_MESSAGE_INFO_MESSAGE_INTERVAL, MAVLINK_MESSAGE_INFO_EXTENDED_SYS_STATE, MAVLINK_MESSAGE_INFO_ADSB_VEHICLE, MAVLINK_MESSAGE_INFO_COLLISION, MAVLINK_MESSAGE_INFO_V2_EXTENSION, MAVLINK_MESSAGE_INFO_MEMORY_VECT, MAVLINK_MESSAGE_INFO_DEBUG_VECT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT, MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT, MAVLINK_MESSAGE_INFO_STATUSTEXT, MAVLINK_MESSAGE_INFO_DEBUG, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}} +# if MAVLINK_COMMAND_24BIT +# include "../mavlink_get_info.h" +# endif +#endif + #ifdef __cplusplus } #endif // __cplusplus diff --git a/vendor/libraries/mavlink/common/mavlink.h b/vendor/libraries/mavlink/common/mavlink.h index f92b2b2db7..6644aa5c2f 100644 --- a/vendor/libraries/mavlink/common/mavlink.h +++ b/vendor/libraries/mavlink/common/mavlink.h @@ -1,10 +1,13 @@ /** @file - * @brief MAVLink comm protocol built from common.xml - * @see http://mavlink.org + * @brief MAVLink comm protocol built from common.xml + * @see http://mavlink.org */ +#pragma once #ifndef MAVLINK_H #define MAVLINK_H +#define MAVLINK_PRIMARY_XML_IDX 1 + #ifndef MAVLINK_STX #define MAVLINK_STX 254 #endif @@ -21,6 +24,10 @@ #define MAVLINK_CRC_EXTRA 1 #endif +#ifndef MAVLINK_COMMAND_24BIT +#define MAVLINK_COMMAND_24BIT 0 +#endif + #include "version.h" #include "common.h" diff --git a/vendor/libraries/mavlink/common/mavlink_msg_actuator_control_target.h b/vendor/libraries/mavlink/common/mavlink_msg_actuator_control_target.h index 9c33833b38..2d1ebc05a2 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_actuator_control_target.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_actuator_control_target.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE ACTUATOR_CONTROL_TARGET PACKING #define MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET 140 -typedef struct __mavlink_actuator_control_target_t -{ - uint64_t time_usec; ///< Timestamp (micros since boot or Unix epoch) - float controls[8]; ///< Actuator controls. Normed to -1..+1 where 0 is neutral position. Throttle for single rotation direction motors is 0..1, negative range for reverse direction. Standard mapping for attitude controls (group 0): (index 0-7): roll, pitch, yaw, throttle, flaps, spoilers, airbrakes, landing gear. Load a pass-through mixer to repurpose them as generic outputs. - uint8_t group_mlx; ///< Actuator group. The "_mlx" indicates this is a multi-instance message and a MAVLink parser should use this field to difference between instances. -} mavlink_actuator_control_target_t; +MAVPACKED( +typedef struct __mavlink_actuator_control_target_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float controls[8]; /*< Actuator controls. Normed to -1..+1 where 0 is neutral position. Throttle for single rotation direction motors is 0..1, negative range for reverse direction. Standard mapping for attitude controls (group 0): (index 0-7): roll, pitch, yaw, throttle, flaps, spoilers, airbrakes, landing gear. Load a pass-through mixer to repurpose them as generic outputs.*/ + uint8_t group_mlx; /*< Actuator group. The "_mlx" indicates this is a multi-instance message and a MAVLink parser should use this field to difference between instances.*/ +}) mavlink_actuator_control_target_t; #define MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN 41 +#define MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN 41 #define MAVLINK_MSG_ID_140_LEN 41 +#define MAVLINK_MSG_ID_140_MIN_LEN 41 #define MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC 181 #define MAVLINK_MSG_ID_140_CRC 181 #define MAVLINK_MSG_ACTUATOR_CONTROL_TARGET_FIELD_CONTROLS_LEN 8 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_ACTUATOR_CONTROL_TARGET { \ - "ACTUATOR_CONTROL_TARGET", \ - 3, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_actuator_control_target_t, time_usec) }, \ + 140, \ + "ACTUATOR_CONTROL_TARGET", \ + 3, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_actuator_control_target_t, time_usec) }, \ { "controls", NULL, MAVLINK_TYPE_FLOAT, 8, 8, offsetof(mavlink_actuator_control_target_t, controls) }, \ { "group_mlx", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_actuator_control_target_t, group_mlx) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_ACTUATOR_CONTROL_TARGET { \ + "ACTUATOR_CONTROL_TARGET", \ + 3, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_actuator_control_target_t, time_usec) }, \ + { "controls", NULL, MAVLINK_TYPE_FLOAT, 8, 8, offsetof(mavlink_actuator_control_target_t, controls) }, \ + { "group_mlx", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_actuator_control_target_t, group_mlx) }, \ + } \ +} +#endif /** * @brief Pack a actuator_control_target message @@ -39,28 +53,24 @@ typedef struct __mavlink_actuator_control_target_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_actuator_control_target_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t group_mlx, const float *controls) + uint64_t time_usec, uint8_t group_mlx, const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_float_array(buf, 8, controls, 8); + char buf[MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_float_array(buf, 8, controls, 8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); #else - mavlink_actuator_control_target_t packet; - packet.time_usec = time_usec; - packet.group_mlx = group_mlx; - mav_array_memcpy(packet.controls, controls, sizeof(float)*8); + mavlink_actuator_control_target_t packet; + packet.time_usec = time_usec; + packet.group_mlx = group_mlx; + mav_array_memcpy(packet.controls, controls, sizeof(float)*8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); } /** @@ -75,29 +85,25 @@ static inline uint16_t mavlink_msg_actuator_control_target_pack(uint8_t system_i * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_actuator_control_target_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t group_mlx,const float *controls) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t group_mlx,const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_float_array(buf, 8, controls, 8); + char buf[MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_float_array(buf, 8, controls, 8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); #else - mavlink_actuator_control_target_t packet; - packet.time_usec = time_usec; - packet.group_mlx = group_mlx; - mav_array_memcpy(packet.controls, controls, sizeof(float)*8); + mavlink_actuator_control_target_t packet; + packet.time_usec = time_usec; + packet.group_mlx = group_mlx; + mav_array_memcpy(packet.controls, controls, sizeof(float)*8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); } /** @@ -110,7 +116,7 @@ static inline uint16_t mavlink_msg_actuator_control_target_pack_chan(uint8_t sys */ static inline uint16_t mavlink_msg_actuator_control_target_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_actuator_control_target_t* actuator_control_target) { - return mavlink_msg_actuator_control_target_pack(system_id, component_id, msg, actuator_control_target->time_usec, actuator_control_target->group_mlx, actuator_control_target->controls); + return mavlink_msg_actuator_control_target_pack(system_id, component_id, msg, actuator_control_target->time_usec, actuator_control_target->group_mlx, actuator_control_target->controls); } /** @@ -124,7 +130,7 @@ static inline uint16_t mavlink_msg_actuator_control_target_encode(uint8_t system */ static inline uint16_t mavlink_msg_actuator_control_target_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_actuator_control_target_t* actuator_control_target) { - return mavlink_msg_actuator_control_target_pack_chan(system_id, component_id, chan, msg, actuator_control_target->time_usec, actuator_control_target->group_mlx, actuator_control_target->controls); + return mavlink_msg_actuator_control_target_pack_chan(system_id, component_id, chan, msg, actuator_control_target->time_usec, actuator_control_target->group_mlx, actuator_control_target->controls); } /** @@ -140,25 +146,31 @@ static inline uint16_t mavlink_msg_actuator_control_target_encode_chan(uint8_t s static inline void mavlink_msg_actuator_control_target_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t group_mlx, const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_float_array(buf, 8, controls, 8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); + char buf[MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_float_array(buf, 8, controls, 8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); + mavlink_actuator_control_target_t packet; + packet.time_usec = time_usec; + packet.group_mlx = group_mlx; + mav_array_memcpy(packet.controls, controls, sizeof(float)*8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, (const char *)&packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); #endif +} + +/** + * @brief Send a actuator_control_target message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_actuator_control_target_send_struct(mavlink_channel_t chan, const mavlink_actuator_control_target_t* actuator_control_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_actuator_control_target_send(chan, actuator_control_target->time_usec, actuator_control_target->group_mlx, actuator_control_target->controls); #else - mavlink_actuator_control_target_t packet; - packet.time_usec = time_usec; - packet.group_mlx = group_mlx; - mav_array_memcpy(packet.controls, controls, sizeof(float)*8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, (const char *)&packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, (const char *)&packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, (const char *)actuator_control_target, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); #endif } @@ -173,25 +185,17 @@ static inline void mavlink_msg_actuator_control_target_send(mavlink_channel_t ch static inline void mavlink_msg_actuator_control_target_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t group_mlx, const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_float_array(buf, 8, controls, 8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_float_array(buf, 8, controls, 8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); -#endif -#else - mavlink_actuator_control_target_t *packet = (mavlink_actuator_control_target_t *)msgbuf; - packet->time_usec = time_usec; - packet->group_mlx = group_mlx; - mav_array_memcpy(packet->controls, controls, sizeof(float)*8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, (const char *)packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, (const char *)packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); -#endif + mavlink_actuator_control_target_t *packet = (mavlink_actuator_control_target_t *)msgbuf; + packet->time_usec = time_usec; + packet->group_mlx = group_mlx; + mav_array_memcpy(packet->controls, controls, sizeof(float)*8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET, (const char *)packet, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_CRC); #endif } #endif @@ -208,7 +212,7 @@ static inline void mavlink_msg_actuator_control_target_send_buf(mavlink_message_ */ static inline uint64_t mavlink_msg_actuator_control_target_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -218,7 +222,7 @@ static inline uint64_t mavlink_msg_actuator_control_target_get_time_usec(const m */ static inline uint8_t mavlink_msg_actuator_control_target_get_group_mlx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 40); + return _MAV_RETURN_uint8_t(msg, 40); } /** @@ -228,7 +232,7 @@ static inline uint8_t mavlink_msg_actuator_control_target_get_group_mlx(const ma */ static inline uint16_t mavlink_msg_actuator_control_target_get_controls(const mavlink_message_t* msg, float *controls) { - return _MAV_RETURN_float_array(msg, controls, 8, 8); + return _MAV_RETURN_float_array(msg, controls, 8, 8); } /** @@ -239,11 +243,13 @@ static inline uint16_t mavlink_msg_actuator_control_target_get_controls(const ma */ static inline void mavlink_msg_actuator_control_target_decode(const mavlink_message_t* msg, mavlink_actuator_control_target_t* actuator_control_target) { -#if MAVLINK_NEED_BYTE_SWAP - actuator_control_target->time_usec = mavlink_msg_actuator_control_target_get_time_usec(msg); - mavlink_msg_actuator_control_target_get_controls(msg, actuator_control_target->controls); - actuator_control_target->group_mlx = mavlink_msg_actuator_control_target_get_group_mlx(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + actuator_control_target->time_usec = mavlink_msg_actuator_control_target_get_time_usec(msg); + mavlink_msg_actuator_control_target_get_controls(msg, actuator_control_target->controls); + actuator_control_target->group_mlx = mavlink_msg_actuator_control_target_get_group_mlx(msg); #else - memcpy(actuator_control_target, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN? msg->len : MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN; + memset(actuator_control_target, 0, MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_LEN); + memcpy(actuator_control_target, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_adsb_vehicle.h b/vendor/libraries/mavlink/common/mavlink_msg_adsb_vehicle.h new file mode 100644 index 0000000000..d395be5e9d --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_adsb_vehicle.h @@ -0,0 +1,505 @@ +#pragma once +// MESSAGE ADSB_VEHICLE PACKING + +#define MAVLINK_MSG_ID_ADSB_VEHICLE 246 + +MAVPACKED( +typedef struct __mavlink_adsb_vehicle_t { + uint32_t ICAO_address; /*< ICAO address*/ + int32_t lat; /*< Latitude, expressed as degrees * 1E7*/ + int32_t lon; /*< Longitude, expressed as degrees * 1E7*/ + int32_t altitude; /*< Altitude(ASL) in millimeters*/ + uint16_t heading; /*< Course over ground in centidegrees*/ + uint16_t hor_velocity; /*< The horizontal velocity in centimeters/second*/ + int16_t ver_velocity; /*< The vertical velocity in centimeters/second, positive is up*/ + uint16_t flags; /*< Flags to indicate various statuses including valid data fields*/ + uint16_t squawk; /*< Squawk code*/ + uint8_t altitude_type; /*< Type from ADSB_ALTITUDE_TYPE enum*/ + char callsign[9]; /*< The callsign, 8+null*/ + uint8_t emitter_type; /*< Type from ADSB_EMITTER_TYPE enum*/ + uint8_t tslc; /*< Time since last communication in seconds*/ +}) mavlink_adsb_vehicle_t; + +#define MAVLINK_MSG_ID_ADSB_VEHICLE_LEN 38 +#define MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN 38 +#define MAVLINK_MSG_ID_246_LEN 38 +#define MAVLINK_MSG_ID_246_MIN_LEN 38 + +#define MAVLINK_MSG_ID_ADSB_VEHICLE_CRC 184 +#define MAVLINK_MSG_ID_246_CRC 184 + +#define MAVLINK_MSG_ADSB_VEHICLE_FIELD_CALLSIGN_LEN 9 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_ADSB_VEHICLE { \ + 246, \ + "ADSB_VEHICLE", \ + 13, \ + { { "ICAO_address", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_adsb_vehicle_t, ICAO_address) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_adsb_vehicle_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_adsb_vehicle_t, lon) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_adsb_vehicle_t, altitude) }, \ + { "heading", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_adsb_vehicle_t, heading) }, \ + { "hor_velocity", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_adsb_vehicle_t, hor_velocity) }, \ + { "ver_velocity", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_adsb_vehicle_t, ver_velocity) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 22, offsetof(mavlink_adsb_vehicle_t, flags) }, \ + { "squawk", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_adsb_vehicle_t, squawk) }, \ + { "altitude_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 26, offsetof(mavlink_adsb_vehicle_t, altitude_type) }, \ + { "callsign", NULL, MAVLINK_TYPE_CHAR, 9, 27, offsetof(mavlink_adsb_vehicle_t, callsign) }, \ + { "emitter_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_adsb_vehicle_t, emitter_type) }, \ + { "tslc", NULL, MAVLINK_TYPE_UINT8_T, 0, 37, offsetof(mavlink_adsb_vehicle_t, tslc) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_ADSB_VEHICLE { \ + "ADSB_VEHICLE", \ + 13, \ + { { "ICAO_address", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_adsb_vehicle_t, ICAO_address) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_adsb_vehicle_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_adsb_vehicle_t, lon) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_adsb_vehicle_t, altitude) }, \ + { "heading", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_adsb_vehicle_t, heading) }, \ + { "hor_velocity", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_adsb_vehicle_t, hor_velocity) }, \ + { "ver_velocity", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_adsb_vehicle_t, ver_velocity) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 22, offsetof(mavlink_adsb_vehicle_t, flags) }, \ + { "squawk", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_adsb_vehicle_t, squawk) }, \ + { "altitude_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 26, offsetof(mavlink_adsb_vehicle_t, altitude_type) }, \ + { "callsign", NULL, MAVLINK_TYPE_CHAR, 9, 27, offsetof(mavlink_adsb_vehicle_t, callsign) }, \ + { "emitter_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_adsb_vehicle_t, emitter_type) }, \ + { "tslc", NULL, MAVLINK_TYPE_UINT8_T, 0, 37, offsetof(mavlink_adsb_vehicle_t, tslc) }, \ + } \ +} +#endif + +/** + * @brief Pack a adsb_vehicle message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param ICAO_address ICAO address + * @param lat Latitude, expressed as degrees * 1E7 + * @param lon Longitude, expressed as degrees * 1E7 + * @param altitude_type Type from ADSB_ALTITUDE_TYPE enum + * @param altitude Altitude(ASL) in millimeters + * @param heading Course over ground in centidegrees + * @param hor_velocity The horizontal velocity in centimeters/second + * @param ver_velocity The vertical velocity in centimeters/second, positive is up + * @param callsign The callsign, 8+null + * @param emitter_type Type from ADSB_EMITTER_TYPE enum + * @param tslc Time since last communication in seconds + * @param flags Flags to indicate various statuses including valid data fields + * @param squawk Squawk code + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_adsb_vehicle_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint32_t ICAO_address, int32_t lat, int32_t lon, uint8_t altitude_type, int32_t altitude, uint16_t heading, uint16_t hor_velocity, int16_t ver_velocity, const char *callsign, uint8_t emitter_type, uint8_t tslc, uint16_t flags, uint16_t squawk) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ADSB_VEHICLE_LEN]; + _mav_put_uint32_t(buf, 0, ICAO_address); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, altitude); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, hor_velocity); + _mav_put_int16_t(buf, 20, ver_velocity); + _mav_put_uint16_t(buf, 22, flags); + _mav_put_uint16_t(buf, 24, squawk); + _mav_put_uint8_t(buf, 26, altitude_type); + _mav_put_uint8_t(buf, 36, emitter_type); + _mav_put_uint8_t(buf, 37, tslc); + _mav_put_char_array(buf, 27, callsign, 9); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN); +#else + mavlink_adsb_vehicle_t packet; + packet.ICAO_address = ICAO_address; + packet.lat = lat; + packet.lon = lon; + packet.altitude = altitude; + packet.heading = heading; + packet.hor_velocity = hor_velocity; + packet.ver_velocity = ver_velocity; + packet.flags = flags; + packet.squawk = squawk; + packet.altitude_type = altitude_type; + packet.emitter_type = emitter_type; + packet.tslc = tslc; + mav_array_memcpy(packet.callsign, callsign, sizeof(char)*9); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_ADSB_VEHICLE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_CRC); +} + +/** + * @brief Pack a adsb_vehicle message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param ICAO_address ICAO address + * @param lat Latitude, expressed as degrees * 1E7 + * @param lon Longitude, expressed as degrees * 1E7 + * @param altitude_type Type from ADSB_ALTITUDE_TYPE enum + * @param altitude Altitude(ASL) in millimeters + * @param heading Course over ground in centidegrees + * @param hor_velocity The horizontal velocity in centimeters/second + * @param ver_velocity The vertical velocity in centimeters/second, positive is up + * @param callsign The callsign, 8+null + * @param emitter_type Type from ADSB_EMITTER_TYPE enum + * @param tslc Time since last communication in seconds + * @param flags Flags to indicate various statuses including valid data fields + * @param squawk Squawk code + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_adsb_vehicle_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint32_t ICAO_address,int32_t lat,int32_t lon,uint8_t altitude_type,int32_t altitude,uint16_t heading,uint16_t hor_velocity,int16_t ver_velocity,const char *callsign,uint8_t emitter_type,uint8_t tslc,uint16_t flags,uint16_t squawk) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ADSB_VEHICLE_LEN]; + _mav_put_uint32_t(buf, 0, ICAO_address); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, altitude); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, hor_velocity); + _mav_put_int16_t(buf, 20, ver_velocity); + _mav_put_uint16_t(buf, 22, flags); + _mav_put_uint16_t(buf, 24, squawk); + _mav_put_uint8_t(buf, 26, altitude_type); + _mav_put_uint8_t(buf, 36, emitter_type); + _mav_put_uint8_t(buf, 37, tslc); + _mav_put_char_array(buf, 27, callsign, 9); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN); +#else + mavlink_adsb_vehicle_t packet; + packet.ICAO_address = ICAO_address; + packet.lat = lat; + packet.lon = lon; + packet.altitude = altitude; + packet.heading = heading; + packet.hor_velocity = hor_velocity; + packet.ver_velocity = ver_velocity; + packet.flags = flags; + packet.squawk = squawk; + packet.altitude_type = altitude_type; + packet.emitter_type = emitter_type; + packet.tslc = tslc; + mav_array_memcpy(packet.callsign, callsign, sizeof(char)*9); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_ADSB_VEHICLE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_CRC); +} + +/** + * @brief Encode a adsb_vehicle struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param adsb_vehicle C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_adsb_vehicle_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_adsb_vehicle_t* adsb_vehicle) +{ + return mavlink_msg_adsb_vehicle_pack(system_id, component_id, msg, adsb_vehicle->ICAO_address, adsb_vehicle->lat, adsb_vehicle->lon, adsb_vehicle->altitude_type, adsb_vehicle->altitude, adsb_vehicle->heading, adsb_vehicle->hor_velocity, adsb_vehicle->ver_velocity, adsb_vehicle->callsign, adsb_vehicle->emitter_type, adsb_vehicle->tslc, adsb_vehicle->flags, adsb_vehicle->squawk); +} + +/** + * @brief Encode a adsb_vehicle struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param adsb_vehicle C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_adsb_vehicle_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_adsb_vehicle_t* adsb_vehicle) +{ + return mavlink_msg_adsb_vehicle_pack_chan(system_id, component_id, chan, msg, adsb_vehicle->ICAO_address, adsb_vehicle->lat, adsb_vehicle->lon, adsb_vehicle->altitude_type, adsb_vehicle->altitude, adsb_vehicle->heading, adsb_vehicle->hor_velocity, adsb_vehicle->ver_velocity, adsb_vehicle->callsign, adsb_vehicle->emitter_type, adsb_vehicle->tslc, adsb_vehicle->flags, adsb_vehicle->squawk); +} + +/** + * @brief Send a adsb_vehicle message + * @param chan MAVLink channel to send the message + * + * @param ICAO_address ICAO address + * @param lat Latitude, expressed as degrees * 1E7 + * @param lon Longitude, expressed as degrees * 1E7 + * @param altitude_type Type from ADSB_ALTITUDE_TYPE enum + * @param altitude Altitude(ASL) in millimeters + * @param heading Course over ground in centidegrees + * @param hor_velocity The horizontal velocity in centimeters/second + * @param ver_velocity The vertical velocity in centimeters/second, positive is up + * @param callsign The callsign, 8+null + * @param emitter_type Type from ADSB_EMITTER_TYPE enum + * @param tslc Time since last communication in seconds + * @param flags Flags to indicate various statuses including valid data fields + * @param squawk Squawk code + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_adsb_vehicle_send(mavlink_channel_t chan, uint32_t ICAO_address, int32_t lat, int32_t lon, uint8_t altitude_type, int32_t altitude, uint16_t heading, uint16_t hor_velocity, int16_t ver_velocity, const char *callsign, uint8_t emitter_type, uint8_t tslc, uint16_t flags, uint16_t squawk) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ADSB_VEHICLE_LEN]; + _mav_put_uint32_t(buf, 0, ICAO_address); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, altitude); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, hor_velocity); + _mav_put_int16_t(buf, 20, ver_velocity); + _mav_put_uint16_t(buf, 22, flags); + _mav_put_uint16_t(buf, 24, squawk); + _mav_put_uint8_t(buf, 26, altitude_type); + _mav_put_uint8_t(buf, 36, emitter_type); + _mav_put_uint8_t(buf, 37, tslc); + _mav_put_char_array(buf, 27, callsign, 9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ADSB_VEHICLE, buf, MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_CRC); +#else + mavlink_adsb_vehicle_t packet; + packet.ICAO_address = ICAO_address; + packet.lat = lat; + packet.lon = lon; + packet.altitude = altitude; + packet.heading = heading; + packet.hor_velocity = hor_velocity; + packet.ver_velocity = ver_velocity; + packet.flags = flags; + packet.squawk = squawk; + packet.altitude_type = altitude_type; + packet.emitter_type = emitter_type; + packet.tslc = tslc; + mav_array_memcpy(packet.callsign, callsign, sizeof(char)*9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ADSB_VEHICLE, (const char *)&packet, MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_CRC); +#endif +} + +/** + * @brief Send a adsb_vehicle message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_adsb_vehicle_send_struct(mavlink_channel_t chan, const mavlink_adsb_vehicle_t* adsb_vehicle) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_adsb_vehicle_send(chan, adsb_vehicle->ICAO_address, adsb_vehicle->lat, adsb_vehicle->lon, adsb_vehicle->altitude_type, adsb_vehicle->altitude, adsb_vehicle->heading, adsb_vehicle->hor_velocity, adsb_vehicle->ver_velocity, adsb_vehicle->callsign, adsb_vehicle->emitter_type, adsb_vehicle->tslc, adsb_vehicle->flags, adsb_vehicle->squawk); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ADSB_VEHICLE, (const char *)adsb_vehicle, MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_CRC); +#endif +} + +#if MAVLINK_MSG_ID_ADSB_VEHICLE_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_adsb_vehicle_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t ICAO_address, int32_t lat, int32_t lon, uint8_t altitude_type, int32_t altitude, uint16_t heading, uint16_t hor_velocity, int16_t ver_velocity, const char *callsign, uint8_t emitter_type, uint8_t tslc, uint16_t flags, uint16_t squawk) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, ICAO_address); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, altitude); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, hor_velocity); + _mav_put_int16_t(buf, 20, ver_velocity); + _mav_put_uint16_t(buf, 22, flags); + _mav_put_uint16_t(buf, 24, squawk); + _mav_put_uint8_t(buf, 26, altitude_type); + _mav_put_uint8_t(buf, 36, emitter_type); + _mav_put_uint8_t(buf, 37, tslc); + _mav_put_char_array(buf, 27, callsign, 9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ADSB_VEHICLE, buf, MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_CRC); +#else + mavlink_adsb_vehicle_t *packet = (mavlink_adsb_vehicle_t *)msgbuf; + packet->ICAO_address = ICAO_address; + packet->lat = lat; + packet->lon = lon; + packet->altitude = altitude; + packet->heading = heading; + packet->hor_velocity = hor_velocity; + packet->ver_velocity = ver_velocity; + packet->flags = flags; + packet->squawk = squawk; + packet->altitude_type = altitude_type; + packet->emitter_type = emitter_type; + packet->tslc = tslc; + mav_array_memcpy(packet->callsign, callsign, sizeof(char)*9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ADSB_VEHICLE, (const char *)packet, MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN, MAVLINK_MSG_ID_ADSB_VEHICLE_CRC); +#endif +} +#endif + +#endif + +// MESSAGE ADSB_VEHICLE UNPACKING + + +/** + * @brief Get field ICAO_address from adsb_vehicle message + * + * @return ICAO address + */ +static inline uint32_t mavlink_msg_adsb_vehicle_get_ICAO_address(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 0); +} + +/** + * @brief Get field lat from adsb_vehicle message + * + * @return Latitude, expressed as degrees * 1E7 + */ +static inline int32_t mavlink_msg_adsb_vehicle_get_lat(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 4); +} + +/** + * @brief Get field lon from adsb_vehicle message + * + * @return Longitude, expressed as degrees * 1E7 + */ +static inline int32_t mavlink_msg_adsb_vehicle_get_lon(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 8); +} + +/** + * @brief Get field altitude_type from adsb_vehicle message + * + * @return Type from ADSB_ALTITUDE_TYPE enum + */ +static inline uint8_t mavlink_msg_adsb_vehicle_get_altitude_type(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 26); +} + +/** + * @brief Get field altitude from adsb_vehicle message + * + * @return Altitude(ASL) in millimeters + */ +static inline int32_t mavlink_msg_adsb_vehicle_get_altitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 12); +} + +/** + * @brief Get field heading from adsb_vehicle message + * + * @return Course over ground in centidegrees + */ +static inline uint16_t mavlink_msg_adsb_vehicle_get_heading(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 16); +} + +/** + * @brief Get field hor_velocity from adsb_vehicle message + * + * @return The horizontal velocity in centimeters/second + */ +static inline uint16_t mavlink_msg_adsb_vehicle_get_hor_velocity(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 18); +} + +/** + * @brief Get field ver_velocity from adsb_vehicle message + * + * @return The vertical velocity in centimeters/second, positive is up + */ +static inline int16_t mavlink_msg_adsb_vehicle_get_ver_velocity(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 20); +} + +/** + * @brief Get field callsign from adsb_vehicle message + * + * @return The callsign, 8+null + */ +static inline uint16_t mavlink_msg_adsb_vehicle_get_callsign(const mavlink_message_t* msg, char *callsign) +{ + return _MAV_RETURN_char_array(msg, callsign, 9, 27); +} + +/** + * @brief Get field emitter_type from adsb_vehicle message + * + * @return Type from ADSB_EMITTER_TYPE enum + */ +static inline uint8_t mavlink_msg_adsb_vehicle_get_emitter_type(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 36); +} + +/** + * @brief Get field tslc from adsb_vehicle message + * + * @return Time since last communication in seconds + */ +static inline uint8_t mavlink_msg_adsb_vehicle_get_tslc(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 37); +} + +/** + * @brief Get field flags from adsb_vehicle message + * + * @return Flags to indicate various statuses including valid data fields + */ +static inline uint16_t mavlink_msg_adsb_vehicle_get_flags(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 22); +} + +/** + * @brief Get field squawk from adsb_vehicle message + * + * @return Squawk code + */ +static inline uint16_t mavlink_msg_adsb_vehicle_get_squawk(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 24); +} + +/** + * @brief Decode a adsb_vehicle message into a struct + * + * @param msg The message to decode + * @param adsb_vehicle C-struct to decode the message contents into + */ +static inline void mavlink_msg_adsb_vehicle_decode(const mavlink_message_t* msg, mavlink_adsb_vehicle_t* adsb_vehicle) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + adsb_vehicle->ICAO_address = mavlink_msg_adsb_vehicle_get_ICAO_address(msg); + adsb_vehicle->lat = mavlink_msg_adsb_vehicle_get_lat(msg); + adsb_vehicle->lon = mavlink_msg_adsb_vehicle_get_lon(msg); + adsb_vehicle->altitude = mavlink_msg_adsb_vehicle_get_altitude(msg); + adsb_vehicle->heading = mavlink_msg_adsb_vehicle_get_heading(msg); + adsb_vehicle->hor_velocity = mavlink_msg_adsb_vehicle_get_hor_velocity(msg); + adsb_vehicle->ver_velocity = mavlink_msg_adsb_vehicle_get_ver_velocity(msg); + adsb_vehicle->flags = mavlink_msg_adsb_vehicle_get_flags(msg); + adsb_vehicle->squawk = mavlink_msg_adsb_vehicle_get_squawk(msg); + adsb_vehicle->altitude_type = mavlink_msg_adsb_vehicle_get_altitude_type(msg); + mavlink_msg_adsb_vehicle_get_callsign(msg, adsb_vehicle->callsign); + adsb_vehicle->emitter_type = mavlink_msg_adsb_vehicle_get_emitter_type(msg); + adsb_vehicle->tslc = mavlink_msg_adsb_vehicle_get_tslc(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_ADSB_VEHICLE_LEN? msg->len : MAVLINK_MSG_ID_ADSB_VEHICLE_LEN; + memset(adsb_vehicle, 0, MAVLINK_MSG_ID_ADSB_VEHICLE_LEN); + memcpy(adsb_vehicle, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_altitude.h b/vendor/libraries/mavlink/common/mavlink_msg_altitude.h new file mode 100644 index 0000000000..d51a9e80c0 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_altitude.h @@ -0,0 +1,363 @@ +#pragma once +// MESSAGE ALTITUDE PACKING + +#define MAVLINK_MSG_ID_ALTITUDE 141 + +MAVPACKED( +typedef struct __mavlink_altitude_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float altitude_monotonic; /*< This altitude measure is initialized on system boot and monotonic (it is never reset, but represents the local altitude change). The only guarantee on this field is that it will never be reset and is consistent within a flight. The recommended value for this field is the uncorrected barometric altitude at boot time. This altitude will also drift and vary between flights.*/ + float altitude_amsl; /*< This altitude measure is strictly above mean sea level and might be non-monotonic (it might reset on events like GPS lock or when a new QNH value is set). It should be the altitude to which global altitude waypoints are compared to. Note that it is *not* the GPS altitude, however, most GPS modules already output AMSL by default and not the WGS84 altitude.*/ + float altitude_local; /*< This is the local altitude in the local coordinate frame. It is not the altitude above home, but in reference to the coordinate origin (0, 0, 0). It is up-positive.*/ + float altitude_relative; /*< This is the altitude above the home position. It resets on each change of the current home position.*/ + float altitude_terrain; /*< This is the altitude above terrain. It might be fed by a terrain database or an altimeter. Values smaller than -1000 should be interpreted as unknown.*/ + float bottom_clearance; /*< This is not the altitude, but the clear space below the system according to the fused clearance estimate. It generally should max out at the maximum range of e.g. the laser altimeter. It is generally a moving target. A negative value indicates no measurement available.*/ +}) mavlink_altitude_t; + +#define MAVLINK_MSG_ID_ALTITUDE_LEN 32 +#define MAVLINK_MSG_ID_ALTITUDE_MIN_LEN 32 +#define MAVLINK_MSG_ID_141_LEN 32 +#define MAVLINK_MSG_ID_141_MIN_LEN 32 + +#define MAVLINK_MSG_ID_ALTITUDE_CRC 47 +#define MAVLINK_MSG_ID_141_CRC 47 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_ALTITUDE { \ + 141, \ + "ALTITUDE", \ + 7, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_altitude_t, time_usec) }, \ + { "altitude_monotonic", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_altitude_t, altitude_monotonic) }, \ + { "altitude_amsl", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_altitude_t, altitude_amsl) }, \ + { "altitude_local", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_altitude_t, altitude_local) }, \ + { "altitude_relative", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_altitude_t, altitude_relative) }, \ + { "altitude_terrain", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_altitude_t, altitude_terrain) }, \ + { "bottom_clearance", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_altitude_t, bottom_clearance) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_ALTITUDE { \ + "ALTITUDE", \ + 7, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_altitude_t, time_usec) }, \ + { "altitude_monotonic", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_altitude_t, altitude_monotonic) }, \ + { "altitude_amsl", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_altitude_t, altitude_amsl) }, \ + { "altitude_local", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_altitude_t, altitude_local) }, \ + { "altitude_relative", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_altitude_t, altitude_relative) }, \ + { "altitude_terrain", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_altitude_t, altitude_terrain) }, \ + { "bottom_clearance", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_altitude_t, bottom_clearance) }, \ + } \ +} +#endif + +/** + * @brief Pack a altitude message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param altitude_monotonic This altitude measure is initialized on system boot and monotonic (it is never reset, but represents the local altitude change). The only guarantee on this field is that it will never be reset and is consistent within a flight. The recommended value for this field is the uncorrected barometric altitude at boot time. This altitude will also drift and vary between flights. + * @param altitude_amsl This altitude measure is strictly above mean sea level and might be non-monotonic (it might reset on events like GPS lock or when a new QNH value is set). It should be the altitude to which global altitude waypoints are compared to. Note that it is *not* the GPS altitude, however, most GPS modules already output AMSL by default and not the WGS84 altitude. + * @param altitude_local This is the local altitude in the local coordinate frame. It is not the altitude above home, but in reference to the coordinate origin (0, 0, 0). It is up-positive. + * @param altitude_relative This is the altitude above the home position. It resets on each change of the current home position. + * @param altitude_terrain This is the altitude above terrain. It might be fed by a terrain database or an altimeter. Values smaller than -1000 should be interpreted as unknown. + * @param bottom_clearance This is not the altitude, but the clear space below the system according to the fused clearance estimate. It generally should max out at the maximum range of e.g. the laser altimeter. It is generally a moving target. A negative value indicates no measurement available. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_altitude_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, float altitude_monotonic, float altitude_amsl, float altitude_local, float altitude_relative, float altitude_terrain, float bottom_clearance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ALTITUDE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, altitude_monotonic); + _mav_put_float(buf, 12, altitude_amsl); + _mav_put_float(buf, 16, altitude_local); + _mav_put_float(buf, 20, altitude_relative); + _mav_put_float(buf, 24, altitude_terrain); + _mav_put_float(buf, 28, bottom_clearance); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ALTITUDE_LEN); +#else + mavlink_altitude_t packet; + packet.time_usec = time_usec; + packet.altitude_monotonic = altitude_monotonic; + packet.altitude_amsl = altitude_amsl; + packet.altitude_local = altitude_local; + packet.altitude_relative = altitude_relative; + packet.altitude_terrain = altitude_terrain; + packet.bottom_clearance = bottom_clearance; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ALTITUDE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_ALTITUDE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ALTITUDE_MIN_LEN, MAVLINK_MSG_ID_ALTITUDE_LEN, MAVLINK_MSG_ID_ALTITUDE_CRC); +} + +/** + * @brief Pack a altitude message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param altitude_monotonic This altitude measure is initialized on system boot and monotonic (it is never reset, but represents the local altitude change). The only guarantee on this field is that it will never be reset and is consistent within a flight. The recommended value for this field is the uncorrected barometric altitude at boot time. This altitude will also drift and vary between flights. + * @param altitude_amsl This altitude measure is strictly above mean sea level and might be non-monotonic (it might reset on events like GPS lock or when a new QNH value is set). It should be the altitude to which global altitude waypoints are compared to. Note that it is *not* the GPS altitude, however, most GPS modules already output AMSL by default and not the WGS84 altitude. + * @param altitude_local This is the local altitude in the local coordinate frame. It is not the altitude above home, but in reference to the coordinate origin (0, 0, 0). It is up-positive. + * @param altitude_relative This is the altitude above the home position. It resets on each change of the current home position. + * @param altitude_terrain This is the altitude above terrain. It might be fed by a terrain database or an altimeter. Values smaller than -1000 should be interpreted as unknown. + * @param bottom_clearance This is not the altitude, but the clear space below the system according to the fused clearance estimate. It generally should max out at the maximum range of e.g. the laser altimeter. It is generally a moving target. A negative value indicates no measurement available. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_altitude_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,float altitude_monotonic,float altitude_amsl,float altitude_local,float altitude_relative,float altitude_terrain,float bottom_clearance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ALTITUDE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, altitude_monotonic); + _mav_put_float(buf, 12, altitude_amsl); + _mav_put_float(buf, 16, altitude_local); + _mav_put_float(buf, 20, altitude_relative); + _mav_put_float(buf, 24, altitude_terrain); + _mav_put_float(buf, 28, bottom_clearance); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ALTITUDE_LEN); +#else + mavlink_altitude_t packet; + packet.time_usec = time_usec; + packet.altitude_monotonic = altitude_monotonic; + packet.altitude_amsl = altitude_amsl; + packet.altitude_local = altitude_local; + packet.altitude_relative = altitude_relative; + packet.altitude_terrain = altitude_terrain; + packet.bottom_clearance = bottom_clearance; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ALTITUDE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_ALTITUDE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ALTITUDE_MIN_LEN, MAVLINK_MSG_ID_ALTITUDE_LEN, MAVLINK_MSG_ID_ALTITUDE_CRC); +} + +/** + * @brief Encode a altitude struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param altitude C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_altitude_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_altitude_t* altitude) +{ + return mavlink_msg_altitude_pack(system_id, component_id, msg, altitude->time_usec, altitude->altitude_monotonic, altitude->altitude_amsl, altitude->altitude_local, altitude->altitude_relative, altitude->altitude_terrain, altitude->bottom_clearance); +} + +/** + * @brief Encode a altitude struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param altitude C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_altitude_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_altitude_t* altitude) +{ + return mavlink_msg_altitude_pack_chan(system_id, component_id, chan, msg, altitude->time_usec, altitude->altitude_monotonic, altitude->altitude_amsl, altitude->altitude_local, altitude->altitude_relative, altitude->altitude_terrain, altitude->bottom_clearance); +} + +/** + * @brief Send a altitude message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param altitude_monotonic This altitude measure is initialized on system boot and monotonic (it is never reset, but represents the local altitude change). The only guarantee on this field is that it will never be reset and is consistent within a flight. The recommended value for this field is the uncorrected barometric altitude at boot time. This altitude will also drift and vary between flights. + * @param altitude_amsl This altitude measure is strictly above mean sea level and might be non-monotonic (it might reset on events like GPS lock or when a new QNH value is set). It should be the altitude to which global altitude waypoints are compared to. Note that it is *not* the GPS altitude, however, most GPS modules already output AMSL by default and not the WGS84 altitude. + * @param altitude_local This is the local altitude in the local coordinate frame. It is not the altitude above home, but in reference to the coordinate origin (0, 0, 0). It is up-positive. + * @param altitude_relative This is the altitude above the home position. It resets on each change of the current home position. + * @param altitude_terrain This is the altitude above terrain. It might be fed by a terrain database or an altimeter. Values smaller than -1000 should be interpreted as unknown. + * @param bottom_clearance This is not the altitude, but the clear space below the system according to the fused clearance estimate. It generally should max out at the maximum range of e.g. the laser altimeter. It is generally a moving target. A negative value indicates no measurement available. + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_altitude_send(mavlink_channel_t chan, uint64_t time_usec, float altitude_monotonic, float altitude_amsl, float altitude_local, float altitude_relative, float altitude_terrain, float bottom_clearance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ALTITUDE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, altitude_monotonic); + _mav_put_float(buf, 12, altitude_amsl); + _mav_put_float(buf, 16, altitude_local); + _mav_put_float(buf, 20, altitude_relative); + _mav_put_float(buf, 24, altitude_terrain); + _mav_put_float(buf, 28, bottom_clearance); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ALTITUDE, buf, MAVLINK_MSG_ID_ALTITUDE_MIN_LEN, MAVLINK_MSG_ID_ALTITUDE_LEN, MAVLINK_MSG_ID_ALTITUDE_CRC); +#else + mavlink_altitude_t packet; + packet.time_usec = time_usec; + packet.altitude_monotonic = altitude_monotonic; + packet.altitude_amsl = altitude_amsl; + packet.altitude_local = altitude_local; + packet.altitude_relative = altitude_relative; + packet.altitude_terrain = altitude_terrain; + packet.bottom_clearance = bottom_clearance; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ALTITUDE, (const char *)&packet, MAVLINK_MSG_ID_ALTITUDE_MIN_LEN, MAVLINK_MSG_ID_ALTITUDE_LEN, MAVLINK_MSG_ID_ALTITUDE_CRC); +#endif +} + +/** + * @brief Send a altitude message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_altitude_send_struct(mavlink_channel_t chan, const mavlink_altitude_t* altitude) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_altitude_send(chan, altitude->time_usec, altitude->altitude_monotonic, altitude->altitude_amsl, altitude->altitude_local, altitude->altitude_relative, altitude->altitude_terrain, altitude->bottom_clearance); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ALTITUDE, (const char *)altitude, MAVLINK_MSG_ID_ALTITUDE_MIN_LEN, MAVLINK_MSG_ID_ALTITUDE_LEN, MAVLINK_MSG_ID_ALTITUDE_CRC); +#endif +} + +#if MAVLINK_MSG_ID_ALTITUDE_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_altitude_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float altitude_monotonic, float altitude_amsl, float altitude_local, float altitude_relative, float altitude_terrain, float bottom_clearance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, altitude_monotonic); + _mav_put_float(buf, 12, altitude_amsl); + _mav_put_float(buf, 16, altitude_local); + _mav_put_float(buf, 20, altitude_relative); + _mav_put_float(buf, 24, altitude_terrain); + _mav_put_float(buf, 28, bottom_clearance); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ALTITUDE, buf, MAVLINK_MSG_ID_ALTITUDE_MIN_LEN, MAVLINK_MSG_ID_ALTITUDE_LEN, MAVLINK_MSG_ID_ALTITUDE_CRC); +#else + mavlink_altitude_t *packet = (mavlink_altitude_t *)msgbuf; + packet->time_usec = time_usec; + packet->altitude_monotonic = altitude_monotonic; + packet->altitude_amsl = altitude_amsl; + packet->altitude_local = altitude_local; + packet->altitude_relative = altitude_relative; + packet->altitude_terrain = altitude_terrain; + packet->bottom_clearance = bottom_clearance; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ALTITUDE, (const char *)packet, MAVLINK_MSG_ID_ALTITUDE_MIN_LEN, MAVLINK_MSG_ID_ALTITUDE_LEN, MAVLINK_MSG_ID_ALTITUDE_CRC); +#endif +} +#endif + +#endif + +// MESSAGE ALTITUDE UNPACKING + + +/** + * @brief Get field time_usec from altitude message + * + * @return Timestamp (micros since boot or Unix epoch) + */ +static inline uint64_t mavlink_msg_altitude_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field altitude_monotonic from altitude message + * + * @return This altitude measure is initialized on system boot and monotonic (it is never reset, but represents the local altitude change). The only guarantee on this field is that it will never be reset and is consistent within a flight. The recommended value for this field is the uncorrected barometric altitude at boot time. This altitude will also drift and vary between flights. + */ +static inline float mavlink_msg_altitude_get_altitude_monotonic(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field altitude_amsl from altitude message + * + * @return This altitude measure is strictly above mean sea level and might be non-monotonic (it might reset on events like GPS lock or when a new QNH value is set). It should be the altitude to which global altitude waypoints are compared to. Note that it is *not* the GPS altitude, however, most GPS modules already output AMSL by default and not the WGS84 altitude. + */ +static inline float mavlink_msg_altitude_get_altitude_amsl(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field altitude_local from altitude message + * + * @return This is the local altitude in the local coordinate frame. It is not the altitude above home, but in reference to the coordinate origin (0, 0, 0). It is up-positive. + */ +static inline float mavlink_msg_altitude_get_altitude_local(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field altitude_relative from altitude message + * + * @return This is the altitude above the home position. It resets on each change of the current home position. + */ +static inline float mavlink_msg_altitude_get_altitude_relative(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field altitude_terrain from altitude message + * + * @return This is the altitude above terrain. It might be fed by a terrain database or an altimeter. Values smaller than -1000 should be interpreted as unknown. + */ +static inline float mavlink_msg_altitude_get_altitude_terrain(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field bottom_clearance from altitude message + * + * @return This is not the altitude, but the clear space below the system according to the fused clearance estimate. It generally should max out at the maximum range of e.g. the laser altimeter. It is generally a moving target. A negative value indicates no measurement available. + */ +static inline float mavlink_msg_altitude_get_bottom_clearance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Decode a altitude message into a struct + * + * @param msg The message to decode + * @param altitude C-struct to decode the message contents into + */ +static inline void mavlink_msg_altitude_decode(const mavlink_message_t* msg, mavlink_altitude_t* altitude) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + altitude->time_usec = mavlink_msg_altitude_get_time_usec(msg); + altitude->altitude_monotonic = mavlink_msg_altitude_get_altitude_monotonic(msg); + altitude->altitude_amsl = mavlink_msg_altitude_get_altitude_amsl(msg); + altitude->altitude_local = mavlink_msg_altitude_get_altitude_local(msg); + altitude->altitude_relative = mavlink_msg_altitude_get_altitude_relative(msg); + altitude->altitude_terrain = mavlink_msg_altitude_get_altitude_terrain(msg); + altitude->bottom_clearance = mavlink_msg_altitude_get_bottom_clearance(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_ALTITUDE_LEN? msg->len : MAVLINK_MSG_ID_ALTITUDE_LEN; + memset(altitude, 0, MAVLINK_MSG_ID_ALTITUDE_LEN); + memcpy(altitude, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_att_pos_mocap.h b/vendor/libraries/mavlink/common/mavlink_msg_att_pos_mocap.h index f7768831f4..3c1a251a6e 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_att_pos_mocap.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_att_pos_mocap.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE ATT_POS_MOCAP PACKING #define MAVLINK_MSG_ID_ATT_POS_MOCAP 138 -typedef struct __mavlink_att_pos_mocap_t -{ - uint64_t time_usec; ///< Timestamp (micros since boot or Unix epoch) - float q[4]; ///< Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0) - float x; ///< X position in meters (NED) - float y; ///< Y position in meters (NED) - float z; ///< Z position in meters (NED) -} mavlink_att_pos_mocap_t; +MAVPACKED( +typedef struct __mavlink_att_pos_mocap_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float q[4]; /*< Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0)*/ + float x; /*< X position in meters (NED)*/ + float y; /*< Y position in meters (NED)*/ + float z; /*< Z position in meters (NED)*/ +}) mavlink_att_pos_mocap_t; #define MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN 36 +#define MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN 36 #define MAVLINK_MSG_ID_138_LEN 36 +#define MAVLINK_MSG_ID_138_MIN_LEN 36 #define MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC 109 #define MAVLINK_MSG_ID_138_CRC 109 #define MAVLINK_MSG_ATT_POS_MOCAP_FIELD_Q_LEN 4 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_ATT_POS_MOCAP { \ - "ATT_POS_MOCAP", \ - 5, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_att_pos_mocap_t, time_usec) }, \ + 138, \ + "ATT_POS_MOCAP", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_att_pos_mocap_t, time_usec) }, \ { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 8, offsetof(mavlink_att_pos_mocap_t, q) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_att_pos_mocap_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_att_pos_mocap_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_att_pos_mocap_t, z) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_ATT_POS_MOCAP { \ + "ATT_POS_MOCAP", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_att_pos_mocap_t, time_usec) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 8, offsetof(mavlink_att_pos_mocap_t, q) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_att_pos_mocap_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_att_pos_mocap_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_att_pos_mocap_t, z) }, \ + } \ +} +#endif /** * @brief Pack a att_pos_mocap message @@ -45,32 +61,28 @@ typedef struct __mavlink_att_pos_mocap_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_att_pos_mocap_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, const float *q, float x, float y, float z) + uint64_t time_usec, const float *q, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, x); - _mav_put_float(buf, 28, y); - _mav_put_float(buf, 32, z); - _mav_put_float_array(buf, 8, q, 4); + char buf[MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, x); + _mav_put_float(buf, 28, y); + _mav_put_float(buf, 32, z); + _mav_put_float_array(buf, 8, q, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); #else - mavlink_att_pos_mocap_t packet; - packet.time_usec = time_usec; - packet.x = x; - packet.y = y; - packet.z = z; - mav_array_memcpy(packet.q, q, sizeof(float)*4); + mavlink_att_pos_mocap_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + mav_array_memcpy(packet.q, q, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATT_POS_MOCAP; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATT_POS_MOCAP; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); } /** @@ -87,33 +99,29 @@ static inline uint16_t mavlink_msg_att_pos_mocap_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_att_pos_mocap_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,const float *q,float x,float y,float z) + mavlink_message_t* msg, + uint64_t time_usec,const float *q,float x,float y,float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, x); - _mav_put_float(buf, 28, y); - _mav_put_float(buf, 32, z); - _mav_put_float_array(buf, 8, q, 4); + char buf[MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, x); + _mav_put_float(buf, 28, y); + _mav_put_float(buf, 32, z); + _mav_put_float_array(buf, 8, q, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); #else - mavlink_att_pos_mocap_t packet; - packet.time_usec = time_usec; - packet.x = x; - packet.y = y; - packet.z = z; - mav_array_memcpy(packet.q, q, sizeof(float)*4); + mavlink_att_pos_mocap_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + mav_array_memcpy(packet.q, q, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATT_POS_MOCAP; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATT_POS_MOCAP; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); } /** @@ -126,7 +134,7 @@ static inline uint16_t mavlink_msg_att_pos_mocap_pack_chan(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_att_pos_mocap_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_att_pos_mocap_t* att_pos_mocap) { - return mavlink_msg_att_pos_mocap_pack(system_id, component_id, msg, att_pos_mocap->time_usec, att_pos_mocap->q, att_pos_mocap->x, att_pos_mocap->y, att_pos_mocap->z); + return mavlink_msg_att_pos_mocap_pack(system_id, component_id, msg, att_pos_mocap->time_usec, att_pos_mocap->q, att_pos_mocap->x, att_pos_mocap->y, att_pos_mocap->z); } /** @@ -140,7 +148,7 @@ static inline uint16_t mavlink_msg_att_pos_mocap_encode(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_att_pos_mocap_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_att_pos_mocap_t* att_pos_mocap) { - return mavlink_msg_att_pos_mocap_pack_chan(system_id, component_id, chan, msg, att_pos_mocap->time_usec, att_pos_mocap->q, att_pos_mocap->x, att_pos_mocap->y, att_pos_mocap->z); + return mavlink_msg_att_pos_mocap_pack_chan(system_id, component_id, chan, msg, att_pos_mocap->time_usec, att_pos_mocap->q, att_pos_mocap->x, att_pos_mocap->y, att_pos_mocap->z); } /** @@ -158,29 +166,35 @@ static inline uint16_t mavlink_msg_att_pos_mocap_encode_chan(uint8_t system_id, static inline void mavlink_msg_att_pos_mocap_send(mavlink_channel_t chan, uint64_t time_usec, const float *q, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, x); - _mav_put_float(buf, 28, y); - _mav_put_float(buf, 32, z); - _mav_put_float_array(buf, 8, q, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); + char buf[MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, x); + _mav_put_float(buf, 28, y); + _mav_put_float(buf, 32, z); + _mav_put_float_array(buf, 8, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); + mavlink_att_pos_mocap_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, (const char *)&packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); #endif +} + +/** + * @brief Send a att_pos_mocap message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_att_pos_mocap_send_struct(mavlink_channel_t chan, const mavlink_att_pos_mocap_t* att_pos_mocap) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_att_pos_mocap_send(chan, att_pos_mocap->time_usec, att_pos_mocap->q, att_pos_mocap->x, att_pos_mocap->y, att_pos_mocap->z); #else - mavlink_att_pos_mocap_t packet; - packet.time_usec = time_usec; - packet.x = x; - packet.y = y; - packet.z = z; - mav_array_memcpy(packet.q, q, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, (const char *)&packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, (const char *)&packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, (const char *)att_pos_mocap, MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); #endif } @@ -195,29 +209,21 @@ static inline void mavlink_msg_att_pos_mocap_send(mavlink_channel_t chan, uint64 static inline void mavlink_msg_att_pos_mocap_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, const float *q, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, x); - _mav_put_float(buf, 28, y); - _mav_put_float(buf, 32, z); - _mav_put_float_array(buf, 8, q, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, x); + _mav_put_float(buf, 28, y); + _mav_put_float(buf, 32, z); + _mav_put_float_array(buf, 8, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, buf, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); -#endif -#else - mavlink_att_pos_mocap_t *packet = (mavlink_att_pos_mocap_t *)msgbuf; - packet->time_usec = time_usec; - packet->x = x; - packet->y = y; - packet->z = z; - mav_array_memcpy(packet->q, q, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, (const char *)packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, (const char *)packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); -#endif + mavlink_att_pos_mocap_t *packet = (mavlink_att_pos_mocap_t *)msgbuf; + packet->time_usec = time_usec; + packet->x = x; + packet->y = y; + packet->z = z; + mav_array_memcpy(packet->q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATT_POS_MOCAP, (const char *)packet, MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN, MAVLINK_MSG_ID_ATT_POS_MOCAP_CRC); #endif } #endif @@ -234,7 +240,7 @@ static inline void mavlink_msg_att_pos_mocap_send_buf(mavlink_message_t *msgbuf, */ static inline uint64_t mavlink_msg_att_pos_mocap_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -244,7 +250,7 @@ static inline uint64_t mavlink_msg_att_pos_mocap_get_time_usec(const mavlink_mes */ static inline uint16_t mavlink_msg_att_pos_mocap_get_q(const mavlink_message_t* msg, float *q) { - return _MAV_RETURN_float_array(msg, q, 4, 8); + return _MAV_RETURN_float_array(msg, q, 4, 8); } /** @@ -254,7 +260,7 @@ static inline uint16_t mavlink_msg_att_pos_mocap_get_q(const mavlink_message_t* */ static inline float mavlink_msg_att_pos_mocap_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -264,7 +270,7 @@ static inline float mavlink_msg_att_pos_mocap_get_x(const mavlink_message_t* msg */ static inline float mavlink_msg_att_pos_mocap_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -274,7 +280,7 @@ static inline float mavlink_msg_att_pos_mocap_get_y(const mavlink_message_t* msg */ static inline float mavlink_msg_att_pos_mocap_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -285,13 +291,15 @@ static inline float mavlink_msg_att_pos_mocap_get_z(const mavlink_message_t* msg */ static inline void mavlink_msg_att_pos_mocap_decode(const mavlink_message_t* msg, mavlink_att_pos_mocap_t* att_pos_mocap) { -#if MAVLINK_NEED_BYTE_SWAP - att_pos_mocap->time_usec = mavlink_msg_att_pos_mocap_get_time_usec(msg); - mavlink_msg_att_pos_mocap_get_q(msg, att_pos_mocap->q); - att_pos_mocap->x = mavlink_msg_att_pos_mocap_get_x(msg); - att_pos_mocap->y = mavlink_msg_att_pos_mocap_get_y(msg); - att_pos_mocap->z = mavlink_msg_att_pos_mocap_get_z(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + att_pos_mocap->time_usec = mavlink_msg_att_pos_mocap_get_time_usec(msg); + mavlink_msg_att_pos_mocap_get_q(msg, att_pos_mocap->q); + att_pos_mocap->x = mavlink_msg_att_pos_mocap_get_x(msg); + att_pos_mocap->y = mavlink_msg_att_pos_mocap_get_y(msg); + att_pos_mocap->z = mavlink_msg_att_pos_mocap_get_z(msg); #else - memcpy(att_pos_mocap, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN? msg->len : MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN; + memset(att_pos_mocap, 0, MAVLINK_MSG_ID_ATT_POS_MOCAP_LEN); + memcpy(att_pos_mocap, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_attitude.h b/vendor/libraries/mavlink/common/mavlink_msg_attitude.h index ff2f104d40..21472fb2b0 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_attitude.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_attitude.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE ATTITUDE PACKING #define MAVLINK_MSG_ID_ATTITUDE 30 -typedef struct __mavlink_attitude_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float roll; ///< Roll angle (rad, -pi..+pi) - float pitch; ///< Pitch angle (rad, -pi..+pi) - float yaw; ///< Yaw angle (rad, -pi..+pi) - float rollspeed; ///< Roll angular speed (rad/s) - float pitchspeed; ///< Pitch angular speed (rad/s) - float yawspeed; ///< Yaw angular speed (rad/s) -} mavlink_attitude_t; +MAVPACKED( +typedef struct __mavlink_attitude_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float roll; /*< Roll angle (rad, -pi..+pi)*/ + float pitch; /*< Pitch angle (rad, -pi..+pi)*/ + float yaw; /*< Yaw angle (rad, -pi..+pi)*/ + float rollspeed; /*< Roll angular speed (rad/s)*/ + float pitchspeed; /*< Pitch angular speed (rad/s)*/ + float yawspeed; /*< Yaw angular speed (rad/s)*/ +}) mavlink_attitude_t; #define MAVLINK_MSG_ID_ATTITUDE_LEN 28 +#define MAVLINK_MSG_ID_ATTITUDE_MIN_LEN 28 #define MAVLINK_MSG_ID_30_LEN 28 +#define MAVLINK_MSG_ID_30_MIN_LEN 28 #define MAVLINK_MSG_ID_ATTITUDE_CRC 39 #define MAVLINK_MSG_ID_30_CRC 39 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_ATTITUDE { \ - "ATTITUDE", \ - 7, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_t, time_boot_ms) }, \ + 30, \ + "ATTITUDE", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_t, time_boot_ms) }, \ { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_attitude_t, roll) }, \ { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_attitude_t, pitch) }, \ { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_attitude_t, yaw) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_attitude_t { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_t, yawspeed) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_ATTITUDE { \ + "ATTITUDE", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_t, time_boot_ms) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_attitude_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_attitude_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_attitude_t, yaw) }, \ + { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_attitude_t, rollspeed) }, \ + { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_attitude_t, pitchspeed) }, \ + { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_t, yawspeed) }, \ + } \ +} +#endif /** * @brief Pack a attitude message @@ -51,38 +69,34 @@ typedef struct __mavlink_attitude_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed) + uint32_t time_boot_ms, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, rollspeed); - _mav_put_float(buf, 20, pitchspeed); - _mav_put_float(buf, 24, yawspeed); + char buf[MAVLINK_MSG_ID_ATTITUDE_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, rollspeed); + _mav_put_float(buf, 20, pitchspeed); + _mav_put_float(buf, 24, yawspeed); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_LEN); #else - mavlink_attitude_t packet; - packet.time_boot_ms = time_boot_ms; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; + mavlink_attitude_t packet; + packet.time_boot_ms = time_boot_ms; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_attitude_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,float roll,float pitch,float yaw,float rollspeed,float pitchspeed,float yawspeed) + mavlink_message_t* msg, + uint32_t time_boot_ms,float roll,float pitch,float yaw,float rollspeed,float pitchspeed,float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, rollspeed); - _mav_put_float(buf, 20, pitchspeed); - _mav_put_float(buf, 24, yawspeed); + char buf[MAVLINK_MSG_ID_ATTITUDE_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, rollspeed); + _mav_put_float(buf, 20, pitchspeed); + _mav_put_float(buf, 24, yawspeed); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_LEN); #else - mavlink_attitude_t packet; - packet.time_boot_ms = time_boot_ms; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; + mavlink_attitude_t packet; + packet.time_boot_ms = time_boot_ms; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_attitude_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_attitude_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_attitude_t* attitude) { - return mavlink_msg_attitude_pack(system_id, component_id, msg, attitude->time_boot_ms, attitude->roll, attitude->pitch, attitude->yaw, attitude->rollspeed, attitude->pitchspeed, attitude->yawspeed); + return mavlink_msg_attitude_pack(system_id, component_id, msg, attitude->time_boot_ms, attitude->roll, attitude->pitch, attitude->yaw, attitude->rollspeed, attitude->pitchspeed, attitude->yawspeed); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_attitude_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_attitude_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_attitude_t* attitude) { - return mavlink_msg_attitude_pack_chan(system_id, component_id, chan, msg, attitude->time_boot_ms, attitude->roll, attitude->pitch, attitude->yaw, attitude->rollspeed, attitude->pitchspeed, attitude->yawspeed); + return mavlink_msg_attitude_pack_chan(system_id, component_id, chan, msg, attitude->time_boot_ms, attitude->roll, attitude->pitch, attitude->yaw, attitude->rollspeed, attitude->pitchspeed, attitude->yawspeed); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_attitude_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_attitude_send(mavlink_channel_t chan, uint32_t time_boot_ms, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, rollspeed); - _mav_put_float(buf, 20, pitchspeed); - _mav_put_float(buf, 24, yawspeed); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, buf, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); + char buf[MAVLINK_MSG_ID_ATTITUDE_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, rollspeed); + _mav_put_float(buf, 20, pitchspeed); + _mav_put_float(buf, 24, yawspeed); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, buf, MAVLINK_MSG_ID_ATTITUDE_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, buf, MAVLINK_MSG_ID_ATTITUDE_LEN); + mavlink_attitude_t packet; + packet.time_boot_ms = time_boot_ms; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); #endif +} + +/** + * @brief Send a attitude message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_attitude_send_struct(mavlink_channel_t chan, const mavlink_attitude_t* attitude) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_attitude_send(chan, attitude->time_boot_ms, attitude->roll, attitude->pitch, attitude->yaw, attitude->rollspeed, attitude->pitchspeed, attitude->yawspeed); #else - mavlink_attitude_t packet; - packet.time_boot_ms = time_boot_ms; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, (const char *)attitude, MAVLINK_MSG_ID_ATTITUDE_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_attitude_send(mavlink_channel_t chan, uint32_t ti static inline void mavlink_msg_attitude_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, rollspeed); - _mav_put_float(buf, 20, pitchspeed); - _mav_put_float(buf, 24, yawspeed); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, buf, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, buf, MAVLINK_MSG_ID_ATTITUDE_LEN); -#endif -#else - mavlink_attitude_t *packet = (mavlink_attitude_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->rollspeed = rollspeed; - packet->pitchspeed = pitchspeed; - packet->yawspeed = yawspeed; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, rollspeed); + _mav_put_float(buf, 20, pitchspeed); + _mav_put_float(buf, 24, yawspeed); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, buf, MAVLINK_MSG_ID_ATTITUDE_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_LEN); -#endif + mavlink_attitude_t *packet = (mavlink_attitude_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->rollspeed = rollspeed; + packet->pitchspeed = pitchspeed; + packet->yawspeed = yawspeed; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_LEN, MAVLINK_MSG_ID_ATTITUDE_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_attitude_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint32_t mavlink_msg_attitude_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline uint32_t mavlink_msg_attitude_get_time_boot_ms(const mavlink_messa */ static inline float mavlink_msg_attitude_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_attitude_get_roll(const mavlink_message_t* msg) */ static inline float mavlink_msg_attitude_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_attitude_get_pitch(const mavlink_message_t* msg) */ static inline float mavlink_msg_attitude_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_attitude_get_yaw(const mavlink_message_t* msg) */ static inline float mavlink_msg_attitude_get_rollspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_attitude_get_rollspeed(const mavlink_message_t* */ static inline float mavlink_msg_attitude_get_pitchspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_attitude_get_pitchspeed(const mavlink_message_t* */ static inline float mavlink_msg_attitude_get_yawspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_attitude_get_yawspeed(const mavlink_message_t* m */ static inline void mavlink_msg_attitude_decode(const mavlink_message_t* msg, mavlink_attitude_t* attitude) { -#if MAVLINK_NEED_BYTE_SWAP - attitude->time_boot_ms = mavlink_msg_attitude_get_time_boot_ms(msg); - attitude->roll = mavlink_msg_attitude_get_roll(msg); - attitude->pitch = mavlink_msg_attitude_get_pitch(msg); - attitude->yaw = mavlink_msg_attitude_get_yaw(msg); - attitude->rollspeed = mavlink_msg_attitude_get_rollspeed(msg); - attitude->pitchspeed = mavlink_msg_attitude_get_pitchspeed(msg); - attitude->yawspeed = mavlink_msg_attitude_get_yawspeed(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + attitude->time_boot_ms = mavlink_msg_attitude_get_time_boot_ms(msg); + attitude->roll = mavlink_msg_attitude_get_roll(msg); + attitude->pitch = mavlink_msg_attitude_get_pitch(msg); + attitude->yaw = mavlink_msg_attitude_get_yaw(msg); + attitude->rollspeed = mavlink_msg_attitude_get_rollspeed(msg); + attitude->pitchspeed = mavlink_msg_attitude_get_pitchspeed(msg); + attitude->yawspeed = mavlink_msg_attitude_get_yawspeed(msg); #else - memcpy(attitude, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_ATTITUDE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_ATTITUDE_LEN? msg->len : MAVLINK_MSG_ID_ATTITUDE_LEN; + memset(attitude, 0, MAVLINK_MSG_ID_ATTITUDE_LEN); + memcpy(attitude, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion.h b/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion.h index 35170a71ab..df8e1e97a9 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion.h @@ -1,31 +1,36 @@ +#pragma once // MESSAGE ATTITUDE_QUATERNION PACKING #define MAVLINK_MSG_ID_ATTITUDE_QUATERNION 31 -typedef struct __mavlink_attitude_quaternion_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float q1; ///< Quaternion component 1, w (1 in null-rotation) - float q2; ///< Quaternion component 2, x (0 in null-rotation) - float q3; ///< Quaternion component 3, y (0 in null-rotation) - float q4; ///< Quaternion component 4, z (0 in null-rotation) - float rollspeed; ///< Roll angular speed (rad/s) - float pitchspeed; ///< Pitch angular speed (rad/s) - float yawspeed; ///< Yaw angular speed (rad/s) -} mavlink_attitude_quaternion_t; +MAVPACKED( +typedef struct __mavlink_attitude_quaternion_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float q1; /*< Quaternion component 1, w (1 in null-rotation)*/ + float q2; /*< Quaternion component 2, x (0 in null-rotation)*/ + float q3; /*< Quaternion component 3, y (0 in null-rotation)*/ + float q4; /*< Quaternion component 4, z (0 in null-rotation)*/ + float rollspeed; /*< Roll angular speed (rad/s)*/ + float pitchspeed; /*< Pitch angular speed (rad/s)*/ + float yawspeed; /*< Yaw angular speed (rad/s)*/ +}) mavlink_attitude_quaternion_t; #define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN 32 +#define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN 32 #define MAVLINK_MSG_ID_31_LEN 32 +#define MAVLINK_MSG_ID_31_MIN_LEN 32 #define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC 246 #define MAVLINK_MSG_ID_31_CRC 246 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION { \ - "ATTITUDE_QUATERNION", \ - 8, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_quaternion_t, time_boot_ms) }, \ + 31, \ + "ATTITUDE_QUATERNION", \ + 8, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_quaternion_t, time_boot_ms) }, \ { "q1", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_attitude_quaternion_t, q1) }, \ { "q2", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_attitude_quaternion_t, q2) }, \ { "q3", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_attitude_quaternion_t, q3) }, \ @@ -35,7 +40,21 @@ typedef struct __mavlink_attitude_quaternion_t { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_attitude_quaternion_t, yawspeed) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION { \ + "ATTITUDE_QUATERNION", \ + 8, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_quaternion_t, time_boot_ms) }, \ + { "q1", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_attitude_quaternion_t, q1) }, \ + { "q2", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_attitude_quaternion_t, q2) }, \ + { "q3", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_attitude_quaternion_t, q3) }, \ + { "q4", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_attitude_quaternion_t, q4) }, \ + { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_attitude_quaternion_t, rollspeed) }, \ + { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_quaternion_t, pitchspeed) }, \ + { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_attitude_quaternion_t, yawspeed) }, \ + } \ +} +#endif /** * @brief Pack a attitude_quaternion message @@ -54,40 +73,36 @@ typedef struct __mavlink_attitude_quaternion_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_quaternion_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, float q1, float q2, float q3, float q4, float rollspeed, float pitchspeed, float yawspeed) + uint32_t time_boot_ms, float q1, float q2, float q3, float q4, float rollspeed, float pitchspeed, float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, q1); - _mav_put_float(buf, 8, q2); - _mav_put_float(buf, 12, q3); - _mav_put_float(buf, 16, q4); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); + char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, q1); + _mav_put_float(buf, 8, q2); + _mav_put_float(buf, 12, q3); + _mav_put_float(buf, 16, q4); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); #else - mavlink_attitude_quaternion_t packet; - packet.time_boot_ms = time_boot_ms; - packet.q1 = q1; - packet.q2 = q2; - packet.q3 = q3; - packet.q4 = q4; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; + mavlink_attitude_quaternion_t packet; + packet.time_boot_ms = time_boot_ms; + packet.q1 = q1; + packet.q2 = q2; + packet.q3 = q3; + packet.q4 = q4; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); } /** @@ -107,41 +122,37 @@ static inline uint16_t mavlink_msg_attitude_quaternion_pack(uint8_t system_id, u * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_quaternion_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,float q1,float q2,float q3,float q4,float rollspeed,float pitchspeed,float yawspeed) + mavlink_message_t* msg, + uint32_t time_boot_ms,float q1,float q2,float q3,float q4,float rollspeed,float pitchspeed,float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, q1); - _mav_put_float(buf, 8, q2); - _mav_put_float(buf, 12, q3); - _mav_put_float(buf, 16, q4); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); + char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, q1); + _mav_put_float(buf, 8, q2); + _mav_put_float(buf, 12, q3); + _mav_put_float(buf, 16, q4); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); #else - mavlink_attitude_quaternion_t packet; - packet.time_boot_ms = time_boot_ms; - packet.q1 = q1; - packet.q2 = q2; - packet.q3 = q3; - packet.q4 = q4; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; + mavlink_attitude_quaternion_t packet; + packet.time_boot_ms = time_boot_ms; + packet.q1 = q1; + packet.q2 = q2; + packet.q3 = q3; + packet.q4 = q4; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); } /** @@ -154,7 +165,7 @@ static inline uint16_t mavlink_msg_attitude_quaternion_pack_chan(uint8_t system_ */ static inline uint16_t mavlink_msg_attitude_quaternion_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_attitude_quaternion_t* attitude_quaternion) { - return mavlink_msg_attitude_quaternion_pack(system_id, component_id, msg, attitude_quaternion->time_boot_ms, attitude_quaternion->q1, attitude_quaternion->q2, attitude_quaternion->q3, attitude_quaternion->q4, attitude_quaternion->rollspeed, attitude_quaternion->pitchspeed, attitude_quaternion->yawspeed); + return mavlink_msg_attitude_quaternion_pack(system_id, component_id, msg, attitude_quaternion->time_boot_ms, attitude_quaternion->q1, attitude_quaternion->q2, attitude_quaternion->q3, attitude_quaternion->q4, attitude_quaternion->rollspeed, attitude_quaternion->pitchspeed, attitude_quaternion->yawspeed); } /** @@ -168,7 +179,7 @@ static inline uint16_t mavlink_msg_attitude_quaternion_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_attitude_quaternion_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_attitude_quaternion_t* attitude_quaternion) { - return mavlink_msg_attitude_quaternion_pack_chan(system_id, component_id, chan, msg, attitude_quaternion->time_boot_ms, attitude_quaternion->q1, attitude_quaternion->q2, attitude_quaternion->q3, attitude_quaternion->q4, attitude_quaternion->rollspeed, attitude_quaternion->pitchspeed, attitude_quaternion->yawspeed); + return mavlink_msg_attitude_quaternion_pack_chan(system_id, component_id, chan, msg, attitude_quaternion->time_boot_ms, attitude_quaternion->q1, attitude_quaternion->q2, attitude_quaternion->q3, attitude_quaternion->q4, attitude_quaternion->rollspeed, attitude_quaternion->pitchspeed, attitude_quaternion->yawspeed); } /** @@ -189,37 +200,43 @@ static inline uint16_t mavlink_msg_attitude_quaternion_encode_chan(uint8_t syste static inline void mavlink_msg_attitude_quaternion_send(mavlink_channel_t chan, uint32_t time_boot_ms, float q1, float q2, float q3, float q4, float rollspeed, float pitchspeed, float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, q1); - _mav_put_float(buf, 8, q2); - _mav_put_float(buf, 12, q3); - _mav_put_float(buf, 16, q4); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); + char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, q1); + _mav_put_float(buf, 8, q2); + _mav_put_float(buf, 12, q3); + _mav_put_float(buf, 16, q4); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); + mavlink_attitude_quaternion_t packet; + packet.time_boot_ms = time_boot_ms; + packet.q1 = q1; + packet.q2 = q2; + packet.q3 = q3; + packet.q4 = q4; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); #endif +} + +/** + * @brief Send a attitude_quaternion message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_attitude_quaternion_send_struct(mavlink_channel_t chan, const mavlink_attitude_quaternion_t* attitude_quaternion) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_attitude_quaternion_send(chan, attitude_quaternion->time_boot_ms, attitude_quaternion->q1, attitude_quaternion->q2, attitude_quaternion->q3, attitude_quaternion->q4, attitude_quaternion->rollspeed, attitude_quaternion->pitchspeed, attitude_quaternion->yawspeed); #else - mavlink_attitude_quaternion_t packet; - packet.time_boot_ms = time_boot_ms; - packet.q1 = q1; - packet.q2 = q2; - packet.q3 = q3; - packet.q4 = q4; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, (const char *)attitude_quaternion, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); #endif } @@ -234,37 +251,29 @@ static inline void mavlink_msg_attitude_quaternion_send(mavlink_channel_t chan, static inline void mavlink_msg_attitude_quaternion_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float q1, float q2, float q3, float q4, float rollspeed, float pitchspeed, float yawspeed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, q1); - _mav_put_float(buf, 8, q2); - _mav_put_float(buf, 12, q3); - _mav_put_float(buf, 16, q4); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); -#endif -#else - mavlink_attitude_quaternion_t *packet = (mavlink_attitude_quaternion_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->q1 = q1; - packet->q2 = q2; - packet->q3 = q3; - packet->q4 = q4; - packet->rollspeed = rollspeed; - packet->pitchspeed = pitchspeed; - packet->yawspeed = yawspeed; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, q1); + _mav_put_float(buf, 8, q2); + _mav_put_float(buf, 12, q3); + _mav_put_float(buf, 16, q4); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); -#endif + mavlink_attitude_quaternion_t *packet = (mavlink_attitude_quaternion_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->q1 = q1; + packet->q2 = q2; + packet->q3 = q3; + packet->q4 = q4; + packet->rollspeed = rollspeed; + packet->pitchspeed = pitchspeed; + packet->yawspeed = yawspeed; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_CRC); #endif } #endif @@ -281,7 +290,7 @@ static inline void mavlink_msg_attitude_quaternion_send_buf(mavlink_message_t *m */ static inline uint32_t mavlink_msg_attitude_quaternion_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -291,7 +300,7 @@ static inline uint32_t mavlink_msg_attitude_quaternion_get_time_boot_ms(const ma */ static inline float mavlink_msg_attitude_quaternion_get_q1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -301,7 +310,7 @@ static inline float mavlink_msg_attitude_quaternion_get_q1(const mavlink_message */ static inline float mavlink_msg_attitude_quaternion_get_q2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -311,7 +320,7 @@ static inline float mavlink_msg_attitude_quaternion_get_q2(const mavlink_message */ static inline float mavlink_msg_attitude_quaternion_get_q3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -321,7 +330,7 @@ static inline float mavlink_msg_attitude_quaternion_get_q3(const mavlink_message */ static inline float mavlink_msg_attitude_quaternion_get_q4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -331,7 +340,7 @@ static inline float mavlink_msg_attitude_quaternion_get_q4(const mavlink_message */ static inline float mavlink_msg_attitude_quaternion_get_rollspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -341,7 +350,7 @@ static inline float mavlink_msg_attitude_quaternion_get_rollspeed(const mavlink_ */ static inline float mavlink_msg_attitude_quaternion_get_pitchspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -351,7 +360,7 @@ static inline float mavlink_msg_attitude_quaternion_get_pitchspeed(const mavlink */ static inline float mavlink_msg_attitude_quaternion_get_yawspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -362,16 +371,18 @@ static inline float mavlink_msg_attitude_quaternion_get_yawspeed(const mavlink_m */ static inline void mavlink_msg_attitude_quaternion_decode(const mavlink_message_t* msg, mavlink_attitude_quaternion_t* attitude_quaternion) { -#if MAVLINK_NEED_BYTE_SWAP - attitude_quaternion->time_boot_ms = mavlink_msg_attitude_quaternion_get_time_boot_ms(msg); - attitude_quaternion->q1 = mavlink_msg_attitude_quaternion_get_q1(msg); - attitude_quaternion->q2 = mavlink_msg_attitude_quaternion_get_q2(msg); - attitude_quaternion->q3 = mavlink_msg_attitude_quaternion_get_q3(msg); - attitude_quaternion->q4 = mavlink_msg_attitude_quaternion_get_q4(msg); - attitude_quaternion->rollspeed = mavlink_msg_attitude_quaternion_get_rollspeed(msg); - attitude_quaternion->pitchspeed = mavlink_msg_attitude_quaternion_get_pitchspeed(msg); - attitude_quaternion->yawspeed = mavlink_msg_attitude_quaternion_get_yawspeed(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + attitude_quaternion->time_boot_ms = mavlink_msg_attitude_quaternion_get_time_boot_ms(msg); + attitude_quaternion->q1 = mavlink_msg_attitude_quaternion_get_q1(msg); + attitude_quaternion->q2 = mavlink_msg_attitude_quaternion_get_q2(msg); + attitude_quaternion->q3 = mavlink_msg_attitude_quaternion_get_q3(msg); + attitude_quaternion->q4 = mavlink_msg_attitude_quaternion_get_q4(msg); + attitude_quaternion->rollspeed = mavlink_msg_attitude_quaternion_get_rollspeed(msg); + attitude_quaternion->pitchspeed = mavlink_msg_attitude_quaternion_get_pitchspeed(msg); + attitude_quaternion->yawspeed = mavlink_msg_attitude_quaternion_get_yawspeed(msg); #else - memcpy(attitude_quaternion, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN? msg->len : MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN; + memset(attitude_quaternion, 0, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_LEN); + memcpy(attitude_quaternion, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion_cov.h b/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion_cov.h index 38b8f24d59..adfcfa7905 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion_cov.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_attitude_quaternion_cov.h @@ -1,38 +1,55 @@ +#pragma once // MESSAGE ATTITUDE_QUATERNION_COV PACKING #define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV 61 -typedef struct __mavlink_attitude_quaternion_cov_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float q[4]; ///< Quaternion components, w, x, y, z (1 0 0 0 is the null-rotation) - float rollspeed; ///< Roll angular speed (rad/s) - float pitchspeed; ///< Pitch angular speed (rad/s) - float yawspeed; ///< Yaw angular speed (rad/s) - float covariance[9]; ///< Attitude covariance -} mavlink_attitude_quaternion_cov_t; +MAVPACKED( +typedef struct __mavlink_attitude_quaternion_cov_t { + uint64_t time_usec; /*< Timestamp (microseconds since system boot or since UNIX epoch)*/ + float q[4]; /*< Quaternion components, w, x, y, z (1 0 0 0 is the null-rotation)*/ + float rollspeed; /*< Roll angular speed (rad/s)*/ + float pitchspeed; /*< Pitch angular speed (rad/s)*/ + float yawspeed; /*< Yaw angular speed (rad/s)*/ + float covariance[9]; /*< Attitude covariance*/ +}) mavlink_attitude_quaternion_cov_t; -#define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN 68 -#define MAVLINK_MSG_ID_61_LEN 68 +#define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN 72 +#define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN 72 +#define MAVLINK_MSG_ID_61_LEN 72 +#define MAVLINK_MSG_ID_61_MIN_LEN 72 -#define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC 153 -#define MAVLINK_MSG_ID_61_CRC 153 +#define MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC 167 +#define MAVLINK_MSG_ID_61_CRC 167 #define MAVLINK_MSG_ATTITUDE_QUATERNION_COV_FIELD_Q_LEN 4 #define MAVLINK_MSG_ATTITUDE_QUATERNION_COV_FIELD_COVARIANCE_LEN 9 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION_COV { \ - "ATTITUDE_QUATERNION_COV", \ - 6, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_quaternion_cov_t, time_boot_ms) }, \ - { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 4, offsetof(mavlink_attitude_quaternion_cov_t, q) }, \ - { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_attitude_quaternion_cov_t, rollspeed) }, \ - { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_quaternion_cov_t, pitchspeed) }, \ - { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_attitude_quaternion_cov_t, yawspeed) }, \ - { "covariance", NULL, MAVLINK_TYPE_FLOAT, 9, 32, offsetof(mavlink_attitude_quaternion_cov_t, covariance) }, \ + 61, \ + "ATTITUDE_QUATERNION_COV", \ + 6, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_attitude_quaternion_cov_t, time_usec) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 8, offsetof(mavlink_attitude_quaternion_cov_t, q) }, \ + { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_quaternion_cov_t, rollspeed) }, \ + { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_attitude_quaternion_cov_t, pitchspeed) }, \ + { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_attitude_quaternion_cov_t, yawspeed) }, \ + { "covariance", NULL, MAVLINK_TYPE_FLOAT, 9, 36, offsetof(mavlink_attitude_quaternion_cov_t, covariance) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_ATTITUDE_QUATERNION_COV { \ + "ATTITUDE_QUATERNION_COV", \ + 6, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_attitude_quaternion_cov_t, time_usec) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 8, offsetof(mavlink_attitude_quaternion_cov_t, q) }, \ + { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_quaternion_cov_t, rollspeed) }, \ + { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_attitude_quaternion_cov_t, pitchspeed) }, \ + { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_attitude_quaternion_cov_t, yawspeed) }, \ + { "covariance", NULL, MAVLINK_TYPE_FLOAT, 9, 36, offsetof(mavlink_attitude_quaternion_cov_t, covariance) }, \ + } \ +} +#endif /** * @brief Pack a attitude_quaternion_cov message @@ -40,7 +57,7 @@ typedef struct __mavlink_attitude_quaternion_cov_t * @param component_id ID of this component (e.g. 200 for IMU) * @param msg The MAVLink message to compress the data into * - * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param q Quaternion components, w, x, y, z (1 0 0 0 is the null-rotation) * @param rollspeed Roll angular speed (rad/s) * @param pitchspeed Pitch angular speed (rad/s) @@ -49,34 +66,30 @@ typedef struct __mavlink_attitude_quaternion_cov_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_quaternion_cov_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, const float *q, float rollspeed, float pitchspeed, float yawspeed, const float *covariance) + uint64_t time_usec, const float *q, float rollspeed, float pitchspeed, float yawspeed, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_float_array(buf, 4, q, 4); - _mav_put_float_array(buf, 32, covariance, 9); + char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_float_array(buf, 8, q, 4); + _mav_put_float_array(buf, 36, covariance, 9); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); #else - mavlink_attitude_quaternion_cov_t packet; - packet.time_boot_ms = time_boot_ms; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - mav_array_memcpy(packet.q, q, sizeof(float)*4); - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*9); + mavlink_attitude_quaternion_cov_t packet; + packet.time_usec = time_usec; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*9); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); } /** @@ -85,7 +98,7 @@ static inline uint16_t mavlink_msg_attitude_quaternion_cov_pack(uint8_t system_i * @param component_id ID of this component (e.g. 200 for IMU) * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into - * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param q Quaternion components, w, x, y, z (1 0 0 0 is the null-rotation) * @param rollspeed Roll angular speed (rad/s) * @param pitchspeed Pitch angular speed (rad/s) @@ -94,35 +107,31 @@ static inline uint16_t mavlink_msg_attitude_quaternion_cov_pack(uint8_t system_i * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_quaternion_cov_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,const float *q,float rollspeed,float pitchspeed,float yawspeed,const float *covariance) + mavlink_message_t* msg, + uint64_t time_usec,const float *q,float rollspeed,float pitchspeed,float yawspeed,const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_float_array(buf, 4, q, 4); - _mav_put_float_array(buf, 32, covariance, 9); + char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_float_array(buf, 8, q, 4); + _mav_put_float_array(buf, 36, covariance, 9); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); #else - mavlink_attitude_quaternion_cov_t packet; - packet.time_boot_ms = time_boot_ms; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - mav_array_memcpy(packet.q, q, sizeof(float)*4); - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*9); + mavlink_attitude_quaternion_cov_t packet; + packet.time_usec = time_usec; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*9); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); } /** @@ -135,7 +144,7 @@ static inline uint16_t mavlink_msg_attitude_quaternion_cov_pack_chan(uint8_t sys */ static inline uint16_t mavlink_msg_attitude_quaternion_cov_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_attitude_quaternion_cov_t* attitude_quaternion_cov) { - return mavlink_msg_attitude_quaternion_cov_pack(system_id, component_id, msg, attitude_quaternion_cov->time_boot_ms, attitude_quaternion_cov->q, attitude_quaternion_cov->rollspeed, attitude_quaternion_cov->pitchspeed, attitude_quaternion_cov->yawspeed, attitude_quaternion_cov->covariance); + return mavlink_msg_attitude_quaternion_cov_pack(system_id, component_id, msg, attitude_quaternion_cov->time_usec, attitude_quaternion_cov->q, attitude_quaternion_cov->rollspeed, attitude_quaternion_cov->pitchspeed, attitude_quaternion_cov->yawspeed, attitude_quaternion_cov->covariance); } /** @@ -149,14 +158,14 @@ static inline uint16_t mavlink_msg_attitude_quaternion_cov_encode(uint8_t system */ static inline uint16_t mavlink_msg_attitude_quaternion_cov_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_attitude_quaternion_cov_t* attitude_quaternion_cov) { - return mavlink_msg_attitude_quaternion_cov_pack_chan(system_id, component_id, chan, msg, attitude_quaternion_cov->time_boot_ms, attitude_quaternion_cov->q, attitude_quaternion_cov->rollspeed, attitude_quaternion_cov->pitchspeed, attitude_quaternion_cov->yawspeed, attitude_quaternion_cov->covariance); + return mavlink_msg_attitude_quaternion_cov_pack_chan(system_id, component_id, chan, msg, attitude_quaternion_cov->time_usec, attitude_quaternion_cov->q, attitude_quaternion_cov->rollspeed, attitude_quaternion_cov->pitchspeed, attitude_quaternion_cov->yawspeed, attitude_quaternion_cov->covariance); } /** * @brief Send a attitude_quaternion_cov message * @param chan MAVLink channel to send the message * - * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param q Quaternion components, w, x, y, z (1 0 0 0 is the null-rotation) * @param rollspeed Roll angular speed (rad/s) * @param pitchspeed Pitch angular speed (rad/s) @@ -165,34 +174,40 @@ static inline uint16_t mavlink_msg_attitude_quaternion_cov_encode_chan(uint8_t s */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS -static inline void mavlink_msg_attitude_quaternion_cov_send(mavlink_channel_t chan, uint32_t time_boot_ms, const float *q, float rollspeed, float pitchspeed, float yawspeed, const float *covariance) +static inline void mavlink_msg_attitude_quaternion_cov_send(mavlink_channel_t chan, uint64_t time_usec, const float *q, float rollspeed, float pitchspeed, float yawspeed, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_float_array(buf, 4, q, 4); - _mav_put_float_array(buf, 32, covariance, 9); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); + char buf[MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_float_array(buf, 8, q, 4); + _mav_put_float_array(buf, 36, covariance, 9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); + mavlink_attitude_quaternion_cov_t packet; + packet.time_usec = time_usec; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); #endif +} + +/** + * @brief Send a attitude_quaternion_cov message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_attitude_quaternion_cov_send_struct(mavlink_channel_t chan, const mavlink_attitude_quaternion_cov_t* attitude_quaternion_cov) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_attitude_quaternion_cov_send(chan, attitude_quaternion_cov->time_usec, attitude_quaternion_cov->q, attitude_quaternion_cov->rollspeed, attitude_quaternion_cov->pitchspeed, attitude_quaternion_cov->yawspeed, attitude_quaternion_cov->covariance); #else - mavlink_attitude_quaternion_cov_t packet; - packet.time_boot_ms = time_boot_ms; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - mav_array_memcpy(packet.q, q, sizeof(float)*4); - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*9); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, (const char *)attitude_quaternion_cov, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); #endif } @@ -204,34 +219,26 @@ static inline void mavlink_msg_attitude_quaternion_cov_send(mavlink_channel_t ch is usually the receive buffer for the channel, and allows a reply to an incoming message with minimum stack space usage. */ -static inline void mavlink_msg_attitude_quaternion_cov_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, const float *q, float rollspeed, float pitchspeed, float yawspeed, const float *covariance) +static inline void mavlink_msg_attitude_quaternion_cov_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, const float *q, float rollspeed, float pitchspeed, float yawspeed, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_float_array(buf, 4, q, 4); - _mav_put_float_array(buf, 32, covariance, 9); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); -#endif + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_float_array(buf, 8, q, 4); + _mav_put_float_array(buf, 36, covariance, 9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, buf, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); #else - mavlink_attitude_quaternion_cov_t *packet = (mavlink_attitude_quaternion_cov_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->rollspeed = rollspeed; - packet->pitchspeed = pitchspeed; - packet->yawspeed = yawspeed; - mav_array_memcpy(packet->q, q, sizeof(float)*4); - mav_array_memcpy(packet->covariance, covariance, sizeof(float)*9); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); -#endif + mavlink_attitude_quaternion_cov_t *packet = (mavlink_attitude_quaternion_cov_t *)msgbuf; + packet->time_usec = time_usec; + packet->rollspeed = rollspeed; + packet->pitchspeed = pitchspeed; + packet->yawspeed = yawspeed; + mav_array_memcpy(packet->q, q, sizeof(float)*4); + mav_array_memcpy(packet->covariance, covariance, sizeof(float)*9); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_CRC); #endif } #endif @@ -242,13 +249,13 @@ static inline void mavlink_msg_attitude_quaternion_cov_send_buf(mavlink_message_ /** - * @brief Get field time_boot_ms from attitude_quaternion_cov message + * @brief Get field time_usec from attitude_quaternion_cov message * - * @return Timestamp (milliseconds since system boot) + * @return Timestamp (microseconds since system boot or since UNIX epoch) */ -static inline uint32_t mavlink_msg_attitude_quaternion_cov_get_time_boot_ms(const mavlink_message_t* msg) +static inline uint64_t mavlink_msg_attitude_quaternion_cov_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -258,7 +265,7 @@ static inline uint32_t mavlink_msg_attitude_quaternion_cov_get_time_boot_ms(cons */ static inline uint16_t mavlink_msg_attitude_quaternion_cov_get_q(const mavlink_message_t* msg, float *q) { - return _MAV_RETURN_float_array(msg, q, 4, 4); + return _MAV_RETURN_float_array(msg, q, 4, 8); } /** @@ -268,7 +275,7 @@ static inline uint16_t mavlink_msg_attitude_quaternion_cov_get_q(const mavlink_m */ static inline float mavlink_msg_attitude_quaternion_cov_get_rollspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 24); } /** @@ -278,7 +285,7 @@ static inline float mavlink_msg_attitude_quaternion_cov_get_rollspeed(const mavl */ static inline float mavlink_msg_attitude_quaternion_cov_get_pitchspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 28); } /** @@ -288,7 +295,7 @@ static inline float mavlink_msg_attitude_quaternion_cov_get_pitchspeed(const mav */ static inline float mavlink_msg_attitude_quaternion_cov_get_yawspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 32); } /** @@ -298,7 +305,7 @@ static inline float mavlink_msg_attitude_quaternion_cov_get_yawspeed(const mavli */ static inline uint16_t mavlink_msg_attitude_quaternion_cov_get_covariance(const mavlink_message_t* msg, float *covariance) { - return _MAV_RETURN_float_array(msg, covariance, 9, 32); + return _MAV_RETURN_float_array(msg, covariance, 9, 36); } /** @@ -309,14 +316,16 @@ static inline uint16_t mavlink_msg_attitude_quaternion_cov_get_covariance(const */ static inline void mavlink_msg_attitude_quaternion_cov_decode(const mavlink_message_t* msg, mavlink_attitude_quaternion_cov_t* attitude_quaternion_cov) { -#if MAVLINK_NEED_BYTE_SWAP - attitude_quaternion_cov->time_boot_ms = mavlink_msg_attitude_quaternion_cov_get_time_boot_ms(msg); - mavlink_msg_attitude_quaternion_cov_get_q(msg, attitude_quaternion_cov->q); - attitude_quaternion_cov->rollspeed = mavlink_msg_attitude_quaternion_cov_get_rollspeed(msg); - attitude_quaternion_cov->pitchspeed = mavlink_msg_attitude_quaternion_cov_get_pitchspeed(msg); - attitude_quaternion_cov->yawspeed = mavlink_msg_attitude_quaternion_cov_get_yawspeed(msg); - mavlink_msg_attitude_quaternion_cov_get_covariance(msg, attitude_quaternion_cov->covariance); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + attitude_quaternion_cov->time_usec = mavlink_msg_attitude_quaternion_cov_get_time_usec(msg); + mavlink_msg_attitude_quaternion_cov_get_q(msg, attitude_quaternion_cov->q); + attitude_quaternion_cov->rollspeed = mavlink_msg_attitude_quaternion_cov_get_rollspeed(msg); + attitude_quaternion_cov->pitchspeed = mavlink_msg_attitude_quaternion_cov_get_pitchspeed(msg); + attitude_quaternion_cov->yawspeed = mavlink_msg_attitude_quaternion_cov_get_yawspeed(msg); + mavlink_msg_attitude_quaternion_cov_get_covariance(msg, attitude_quaternion_cov->covariance); #else - memcpy(attitude_quaternion_cov, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN? msg->len : MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN; + memset(attitude_quaternion_cov, 0, MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_LEN); + memcpy(attitude_quaternion_cov, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_attitude_target.h b/vendor/libraries/mavlink/common/mavlink_msg_attitude_target.h index 7c4b1c79a8..a310920b33 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_attitude_target.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_attitude_target.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE ATTITUDE_TARGET PACKING #define MAVLINK_MSG_ID_ATTITUDE_TARGET 83 -typedef struct __mavlink_attitude_target_t -{ - uint32_t time_boot_ms; ///< Timestamp in milliseconds since system boot - float q[4]; ///< Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0) - float body_roll_rate; ///< Body roll rate in radians per second - float body_pitch_rate; ///< Body roll rate in radians per second - float body_yaw_rate; ///< Body roll rate in radians per second - float thrust; ///< Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust) - uint8_t type_mask; ///< Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 7: reserved, bit 8: attitude -} mavlink_attitude_target_t; +MAVPACKED( +typedef struct __mavlink_attitude_target_t { + uint32_t time_boot_ms; /*< Timestamp in milliseconds since system boot*/ + float q[4]; /*< Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0)*/ + float body_roll_rate; /*< Body roll rate in radians per second*/ + float body_pitch_rate; /*< Body pitch rate in radians per second*/ + float body_yaw_rate; /*< Body yaw rate in radians per second*/ + float thrust; /*< Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust)*/ + uint8_t type_mask; /*< Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 7: reserved, bit 8: attitude*/ +}) mavlink_attitude_target_t; #define MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN 37 +#define MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN 37 #define MAVLINK_MSG_ID_83_LEN 37 +#define MAVLINK_MSG_ID_83_MIN_LEN 37 #define MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC 22 #define MAVLINK_MSG_ID_83_CRC 22 #define MAVLINK_MSG_ATTITUDE_TARGET_FIELD_Q_LEN 4 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_ATTITUDE_TARGET { \ - "ATTITUDE_TARGET", \ - 7, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_target_t, time_boot_ms) }, \ + 83, \ + "ATTITUDE_TARGET", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_target_t, time_boot_ms) }, \ { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 4, offsetof(mavlink_attitude_target_t, q) }, \ { "body_roll_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_attitude_target_t, body_roll_rate) }, \ { "body_pitch_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_target_t, body_pitch_rate) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_attitude_target_t { "type_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_attitude_target_t, type_mask) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_ATTITUDE_TARGET { \ + "ATTITUDE_TARGET", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_attitude_target_t, time_boot_ms) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 4, offsetof(mavlink_attitude_target_t, q) }, \ + { "body_roll_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_attitude_target_t, body_roll_rate) }, \ + { "body_pitch_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_attitude_target_t, body_pitch_rate) }, \ + { "body_yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_attitude_target_t, body_yaw_rate) }, \ + { "thrust", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_attitude_target_t, thrust) }, \ + { "type_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_attitude_target_t, type_mask) }, \ + } \ +} +#endif /** * @brief Pack a attitude_target message @@ -45,42 +63,38 @@ typedef struct __mavlink_attitude_target_t * @param type_mask Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 7: reserved, bit 8: attitude * @param q Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0) * @param body_roll_rate Body roll rate in radians per second - * @param body_pitch_rate Body roll rate in radians per second - * @param body_yaw_rate Body roll rate in radians per second + * @param body_pitch_rate Body pitch rate in radians per second + * @param body_yaw_rate Body yaw rate in radians per second * @param thrust Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_target_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) + uint32_t time_boot_ms, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, type_mask); - _mav_put_float_array(buf, 4, q, 4); + char buf[MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, type_mask); + _mav_put_float_array(buf, 4, q, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); #else - mavlink_attitude_target_t packet; - packet.time_boot_ms = time_boot_ms; - packet.body_roll_rate = body_roll_rate; - packet.body_pitch_rate = body_pitch_rate; - packet.body_yaw_rate = body_yaw_rate; - packet.thrust = thrust; - packet.type_mask = type_mask; - mav_array_memcpy(packet.q, q, sizeof(float)*4); + mavlink_attitude_target_t packet; + packet.time_boot_ms = time_boot_ms; + packet.body_roll_rate = body_roll_rate; + packet.body_pitch_rate = body_pitch_rate; + packet.body_yaw_rate = body_yaw_rate; + packet.thrust = thrust; + packet.type_mask = type_mask; + mav_array_memcpy(packet.q, q, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE_TARGET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); } /** @@ -93,43 +107,39 @@ static inline uint16_t mavlink_msg_attitude_target_pack(uint8_t system_id, uint8 * @param type_mask Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 7: reserved, bit 8: attitude * @param q Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0) * @param body_roll_rate Body roll rate in radians per second - * @param body_pitch_rate Body roll rate in radians per second - * @param body_yaw_rate Body roll rate in radians per second + * @param body_pitch_rate Body pitch rate in radians per second + * @param body_yaw_rate Body yaw rate in radians per second * @param thrust Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_attitude_target_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t type_mask,const float *q,float body_roll_rate,float body_pitch_rate,float body_yaw_rate,float thrust) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t type_mask,const float *q,float body_roll_rate,float body_pitch_rate,float body_yaw_rate,float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, type_mask); - _mav_put_float_array(buf, 4, q, 4); + char buf[MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, type_mask); + _mav_put_float_array(buf, 4, q, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); #else - mavlink_attitude_target_t packet; - packet.time_boot_ms = time_boot_ms; - packet.body_roll_rate = body_roll_rate; - packet.body_pitch_rate = body_pitch_rate; - packet.body_yaw_rate = body_yaw_rate; - packet.thrust = thrust; - packet.type_mask = type_mask; - mav_array_memcpy(packet.q, q, sizeof(float)*4); + mavlink_attitude_target_t packet; + packet.time_boot_ms = time_boot_ms; + packet.body_roll_rate = body_roll_rate; + packet.body_pitch_rate = body_pitch_rate; + packet.body_yaw_rate = body_yaw_rate; + packet.thrust = thrust; + packet.type_mask = type_mask; + mav_array_memcpy(packet.q, q, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ATTITUDE_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ATTITUDE_TARGET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); } /** @@ -142,7 +152,7 @@ static inline uint16_t mavlink_msg_attitude_target_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_attitude_target_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_attitude_target_t* attitude_target) { - return mavlink_msg_attitude_target_pack(system_id, component_id, msg, attitude_target->time_boot_ms, attitude_target->type_mask, attitude_target->q, attitude_target->body_roll_rate, attitude_target->body_pitch_rate, attitude_target->body_yaw_rate, attitude_target->thrust); + return mavlink_msg_attitude_target_pack(system_id, component_id, msg, attitude_target->time_boot_ms, attitude_target->type_mask, attitude_target->q, attitude_target->body_roll_rate, attitude_target->body_pitch_rate, attitude_target->body_yaw_rate, attitude_target->thrust); } /** @@ -156,7 +166,7 @@ static inline uint16_t mavlink_msg_attitude_target_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_attitude_target_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_attitude_target_t* attitude_target) { - return mavlink_msg_attitude_target_pack_chan(system_id, component_id, chan, msg, attitude_target->time_boot_ms, attitude_target->type_mask, attitude_target->q, attitude_target->body_roll_rate, attitude_target->body_pitch_rate, attitude_target->body_yaw_rate, attitude_target->thrust); + return mavlink_msg_attitude_target_pack_chan(system_id, component_id, chan, msg, attitude_target->time_boot_ms, attitude_target->type_mask, attitude_target->q, attitude_target->body_roll_rate, attitude_target->body_pitch_rate, attitude_target->body_yaw_rate, attitude_target->thrust); } /** @@ -167,8 +177,8 @@ static inline uint16_t mavlink_msg_attitude_target_encode_chan(uint8_t system_id * @param type_mask Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 7: reserved, bit 8: attitude * @param q Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0) * @param body_roll_rate Body roll rate in radians per second - * @param body_pitch_rate Body roll rate in radians per second - * @param body_yaw_rate Body roll rate in radians per second + * @param body_pitch_rate Body pitch rate in radians per second + * @param body_yaw_rate Body yaw rate in radians per second * @param thrust Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust) */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -176,33 +186,39 @@ static inline uint16_t mavlink_msg_attitude_target_encode_chan(uint8_t system_id static inline void mavlink_msg_attitude_target_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, type_mask); - _mav_put_float_array(buf, 4, q, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); + char buf[MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, type_mask); + _mav_put_float_array(buf, 4, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); + mavlink_attitude_target_t packet; + packet.time_boot_ms = time_boot_ms; + packet.body_roll_rate = body_roll_rate; + packet.body_pitch_rate = body_pitch_rate; + packet.body_yaw_rate = body_yaw_rate; + packet.thrust = thrust; + packet.type_mask = type_mask; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); #endif +} + +/** + * @brief Send a attitude_target message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_attitude_target_send_struct(mavlink_channel_t chan, const mavlink_attitude_target_t* attitude_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_attitude_target_send(chan, attitude_target->time_boot_ms, attitude_target->type_mask, attitude_target->q, attitude_target->body_roll_rate, attitude_target->body_pitch_rate, attitude_target->body_yaw_rate, attitude_target->thrust); #else - mavlink_attitude_target_t packet; - packet.time_boot_ms = time_boot_ms; - packet.body_roll_rate = body_roll_rate; - packet.body_pitch_rate = body_pitch_rate; - packet.body_yaw_rate = body_yaw_rate; - packet.thrust = thrust; - packet.type_mask = type_mask; - mav_array_memcpy(packet.q, q, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, (const char *)&packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, (const char *)attitude_target, MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); #endif } @@ -217,33 +233,25 @@ static inline void mavlink_msg_attitude_target_send(mavlink_channel_t chan, uint static inline void mavlink_msg_attitude_target_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, type_mask); - _mav_put_float_array(buf, 4, q, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); -#endif -#else - mavlink_attitude_target_t *packet = (mavlink_attitude_target_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->body_roll_rate = body_roll_rate; - packet->body_pitch_rate = body_pitch_rate; - packet->body_yaw_rate = body_yaw_rate; - packet->thrust = thrust; - packet->type_mask = type_mask; - mav_array_memcpy(packet->q, q, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, type_mask); + _mav_put_float_array(buf, 4, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); -#endif + mavlink_attitude_target_t *packet = (mavlink_attitude_target_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->body_roll_rate = body_roll_rate; + packet->body_pitch_rate = body_pitch_rate; + packet->body_yaw_rate = body_yaw_rate; + packet->thrust = thrust; + packet->type_mask = type_mask; + mav_array_memcpy(packet->q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ATTITUDE_TARGET, (const char *)packet, MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_ATTITUDE_TARGET_CRC); #endif } #endif @@ -260,7 +268,7 @@ static inline void mavlink_msg_attitude_target_send_buf(mavlink_message_t *msgbu */ static inline uint32_t mavlink_msg_attitude_target_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -270,7 +278,7 @@ static inline uint32_t mavlink_msg_attitude_target_get_time_boot_ms(const mavlin */ static inline uint8_t mavlink_msg_attitude_target_get_type_mask(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 36); + return _MAV_RETURN_uint8_t(msg, 36); } /** @@ -280,7 +288,7 @@ static inline uint8_t mavlink_msg_attitude_target_get_type_mask(const mavlink_me */ static inline uint16_t mavlink_msg_attitude_target_get_q(const mavlink_message_t* msg, float *q) { - return _MAV_RETURN_float_array(msg, q, 4, 4); + return _MAV_RETURN_float_array(msg, q, 4, 4); } /** @@ -290,27 +298,27 @@ static inline uint16_t mavlink_msg_attitude_target_get_q(const mavlink_message_t */ static inline float mavlink_msg_attitude_target_get_body_roll_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** * @brief Get field body_pitch_rate from attitude_target message * - * @return Body roll rate in radians per second + * @return Body pitch rate in radians per second */ static inline float mavlink_msg_attitude_target_get_body_pitch_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** * @brief Get field body_yaw_rate from attitude_target message * - * @return Body roll rate in radians per second + * @return Body yaw rate in radians per second */ static inline float mavlink_msg_attitude_target_get_body_yaw_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -320,7 +328,7 @@ static inline float mavlink_msg_attitude_target_get_body_yaw_rate(const mavlink_ */ static inline float mavlink_msg_attitude_target_get_thrust(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -331,15 +339,17 @@ static inline float mavlink_msg_attitude_target_get_thrust(const mavlink_message */ static inline void mavlink_msg_attitude_target_decode(const mavlink_message_t* msg, mavlink_attitude_target_t* attitude_target) { -#if MAVLINK_NEED_BYTE_SWAP - attitude_target->time_boot_ms = mavlink_msg_attitude_target_get_time_boot_ms(msg); - mavlink_msg_attitude_target_get_q(msg, attitude_target->q); - attitude_target->body_roll_rate = mavlink_msg_attitude_target_get_body_roll_rate(msg); - attitude_target->body_pitch_rate = mavlink_msg_attitude_target_get_body_pitch_rate(msg); - attitude_target->body_yaw_rate = mavlink_msg_attitude_target_get_body_yaw_rate(msg); - attitude_target->thrust = mavlink_msg_attitude_target_get_thrust(msg); - attitude_target->type_mask = mavlink_msg_attitude_target_get_type_mask(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + attitude_target->time_boot_ms = mavlink_msg_attitude_target_get_time_boot_ms(msg); + mavlink_msg_attitude_target_get_q(msg, attitude_target->q); + attitude_target->body_roll_rate = mavlink_msg_attitude_target_get_body_roll_rate(msg); + attitude_target->body_pitch_rate = mavlink_msg_attitude_target_get_body_pitch_rate(msg); + attitude_target->body_yaw_rate = mavlink_msg_attitude_target_get_body_yaw_rate(msg); + attitude_target->thrust = mavlink_msg_attitude_target_get_thrust(msg); + attitude_target->type_mask = mavlink_msg_attitude_target_get_type_mask(msg); #else - memcpy(attitude_target, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN? msg->len : MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN; + memset(attitude_target, 0, MAVLINK_MSG_ID_ATTITUDE_TARGET_LEN); + memcpy(attitude_target, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_auth_key.h b/vendor/libraries/mavlink/common/mavlink_msg_auth_key.h index f31b6bbf48..2754a2ad6b 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_auth_key.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_auth_key.h @@ -1,27 +1,39 @@ +#pragma once // MESSAGE AUTH_KEY PACKING #define MAVLINK_MSG_ID_AUTH_KEY 7 -typedef struct __mavlink_auth_key_t -{ - char key[32]; ///< key -} mavlink_auth_key_t; +MAVPACKED( +typedef struct __mavlink_auth_key_t { + char key[32]; /*< key*/ +}) mavlink_auth_key_t; #define MAVLINK_MSG_ID_AUTH_KEY_LEN 32 +#define MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN 32 #define MAVLINK_MSG_ID_7_LEN 32 +#define MAVLINK_MSG_ID_7_MIN_LEN 32 #define MAVLINK_MSG_ID_AUTH_KEY_CRC 119 #define MAVLINK_MSG_ID_7_CRC 119 #define MAVLINK_MSG_AUTH_KEY_FIELD_KEY_LEN 32 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AUTH_KEY { \ - "AUTH_KEY", \ - 1, \ - { { "key", NULL, MAVLINK_TYPE_CHAR, 32, 0, offsetof(mavlink_auth_key_t, key) }, \ + 7, \ + "AUTH_KEY", \ + 1, \ + { { "key", NULL, MAVLINK_TYPE_CHAR, 32, 0, offsetof(mavlink_auth_key_t, key) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AUTH_KEY { \ + "AUTH_KEY", \ + 1, \ + { { "key", NULL, MAVLINK_TYPE_CHAR, 32, 0, offsetof(mavlink_auth_key_t, key) }, \ + } \ +} +#endif /** * @brief Pack a auth_key message @@ -33,26 +45,22 @@ typedef struct __mavlink_auth_key_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_auth_key_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - const char *key) + const char *key) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTH_KEY_LEN]; + char buf[MAVLINK_MSG_ID_AUTH_KEY_LEN]; - _mav_put_char_array(buf, 0, key, 32); + _mav_put_char_array(buf, 0, key, 32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AUTH_KEY_LEN); #else - mavlink_auth_key_t packet; + mavlink_auth_key_t packet; - mav_array_memcpy(packet.key, key, sizeof(char)*32); + mav_array_memcpy(packet.key, key, sizeof(char)*32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AUTH_KEY_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AUTH_KEY; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTH_KEY_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AUTH_KEY; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); } /** @@ -65,27 +73,23 @@ static inline uint16_t mavlink_msg_auth_key_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_auth_key_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - const char *key) + mavlink_message_t* msg, + const char *key) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTH_KEY_LEN]; + char buf[MAVLINK_MSG_ID_AUTH_KEY_LEN]; - _mav_put_char_array(buf, 0, key, 32); + _mav_put_char_array(buf, 0, key, 32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AUTH_KEY_LEN); #else - mavlink_auth_key_t packet; + mavlink_auth_key_t packet; - mav_array_memcpy(packet.key, key, sizeof(char)*32); + mav_array_memcpy(packet.key, key, sizeof(char)*32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AUTH_KEY_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AUTH_KEY; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTH_KEY_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AUTH_KEY; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); } /** @@ -98,7 +102,7 @@ static inline uint16_t mavlink_msg_auth_key_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_auth_key_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_auth_key_t* auth_key) { - return mavlink_msg_auth_key_pack(system_id, component_id, msg, auth_key->key); + return mavlink_msg_auth_key_pack(system_id, component_id, msg, auth_key->key); } /** @@ -112,7 +116,7 @@ static inline uint16_t mavlink_msg_auth_key_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_auth_key_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_auth_key_t* auth_key) { - return mavlink_msg_auth_key_pack_chan(system_id, component_id, chan, msg, auth_key->key); + return mavlink_msg_auth_key_pack_chan(system_id, component_id, chan, msg, auth_key->key); } /** @@ -126,23 +130,29 @@ static inline uint16_t mavlink_msg_auth_key_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_auth_key_send(mavlink_channel_t chan, const char *key) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTH_KEY_LEN]; + char buf[MAVLINK_MSG_ID_AUTH_KEY_LEN]; - _mav_put_char_array(buf, 0, key, 32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, buf, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); + _mav_put_char_array(buf, 0, key, 32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, buf, MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, buf, MAVLINK_MSG_ID_AUTH_KEY_LEN); + mavlink_auth_key_t packet; + + mav_array_memcpy(packet.key, key, sizeof(char)*32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, (const char *)&packet, MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); #endif -#else - mavlink_auth_key_t packet; +} - mav_array_memcpy(packet.key, key, sizeof(char)*32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, (const char *)&packet, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); +/** + * @brief Send a auth_key message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_auth_key_send_struct(mavlink_channel_t chan, const mavlink_auth_key_t* auth_key) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_auth_key_send(chan, auth_key->key); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, (const char *)&packet, MAVLINK_MSG_ID_AUTH_KEY_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, (const char *)auth_key, MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); #endif } @@ -157,23 +167,15 @@ static inline void mavlink_msg_auth_key_send(mavlink_channel_t chan, const char static inline void mavlink_msg_auth_key_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, const char *key) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; + char *buf = (char *)msgbuf; - _mav_put_char_array(buf, 0, key, 32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, buf, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, buf, MAVLINK_MSG_ID_AUTH_KEY_LEN); -#endif + _mav_put_char_array(buf, 0, key, 32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, buf, MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); #else - mavlink_auth_key_t *packet = (mavlink_auth_key_t *)msgbuf; + mavlink_auth_key_t *packet = (mavlink_auth_key_t *)msgbuf; - mav_array_memcpy(packet->key, key, sizeof(char)*32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, (const char *)packet, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, (const char *)packet, MAVLINK_MSG_ID_AUTH_KEY_LEN); -#endif + mav_array_memcpy(packet->key, key, sizeof(char)*32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTH_KEY, (const char *)packet, MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN, MAVLINK_MSG_ID_AUTH_KEY_LEN, MAVLINK_MSG_ID_AUTH_KEY_CRC); #endif } #endif @@ -190,7 +192,7 @@ static inline void mavlink_msg_auth_key_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint16_t mavlink_msg_auth_key_get_key(const mavlink_message_t* msg, char *key) { - return _MAV_RETURN_char_array(msg, key, 32, 0); + return _MAV_RETURN_char_array(msg, key, 32, 0); } /** @@ -201,9 +203,11 @@ static inline uint16_t mavlink_msg_auth_key_get_key(const mavlink_message_t* msg */ static inline void mavlink_msg_auth_key_decode(const mavlink_message_t* msg, mavlink_auth_key_t* auth_key) { -#if MAVLINK_NEED_BYTE_SWAP - mavlink_msg_auth_key_get_key(msg, auth_key->key); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_auth_key_get_key(msg, auth_key->key); #else - memcpy(auth_key, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AUTH_KEY_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AUTH_KEY_LEN? msg->len : MAVLINK_MSG_ID_AUTH_KEY_LEN; + memset(auth_key, 0, MAVLINK_MSG_ID_AUTH_KEY_LEN); + memcpy(auth_key, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_autopilot_version.h b/vendor/libraries/mavlink/common/mavlink_msg_autopilot_version.h index 5012503b0d..68f7d83b69 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_autopilot_version.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_autopilot_version.h @@ -1,24 +1,27 @@ +#pragma once // MESSAGE AUTOPILOT_VERSION PACKING #define MAVLINK_MSG_ID_AUTOPILOT_VERSION 148 -typedef struct __mavlink_autopilot_version_t -{ - uint64_t capabilities; ///< bitmask of capabilities (see MAV_PROTOCOL_CAPABILITY enum) - uint64_t uid; ///< UID if provided by hardware - uint32_t flight_sw_version; ///< Firmware version number - uint32_t middleware_sw_version; ///< Middleware version number - uint32_t os_sw_version; ///< Operating system version number - uint32_t board_version; ///< HW / board version (last 8 bytes should be silicon ID, if any) - uint16_t vendor_id; ///< ID of the board vendor - uint16_t product_id; ///< ID of the product - uint8_t flight_custom_version[8]; ///< Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases. - uint8_t middleware_custom_version[8]; ///< Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases. - uint8_t os_custom_version[8]; ///< Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases. -} mavlink_autopilot_version_t; +MAVPACKED( +typedef struct __mavlink_autopilot_version_t { + uint64_t capabilities; /*< bitmask of capabilities (see MAV_PROTOCOL_CAPABILITY enum)*/ + uint64_t uid; /*< UID if provided by hardware*/ + uint32_t flight_sw_version; /*< Firmware version number*/ + uint32_t middleware_sw_version; /*< Middleware version number*/ + uint32_t os_sw_version; /*< Operating system version number*/ + uint32_t board_version; /*< HW / board version (last 8 bytes should be silicon ID, if any)*/ + uint16_t vendor_id; /*< ID of the board vendor*/ + uint16_t product_id; /*< ID of the product*/ + uint8_t flight_custom_version[8]; /*< Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases.*/ + uint8_t middleware_custom_version[8]; /*< Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases.*/ + uint8_t os_custom_version[8]; /*< Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases.*/ +}) mavlink_autopilot_version_t; #define MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN 60 +#define MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN 60 #define MAVLINK_MSG_ID_148_LEN 60 +#define MAVLINK_MSG_ID_148_MIN_LEN 60 #define MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC 178 #define MAVLINK_MSG_ID_148_CRC 178 @@ -27,10 +30,12 @@ typedef struct __mavlink_autopilot_version_t #define MAVLINK_MSG_AUTOPILOT_VERSION_FIELD_MIDDLEWARE_CUSTOM_VERSION_LEN 8 #define MAVLINK_MSG_AUTOPILOT_VERSION_FIELD_OS_CUSTOM_VERSION_LEN 8 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION { \ - "AUTOPILOT_VERSION", \ - 11, \ - { { "capabilities", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_autopilot_version_t, capabilities) }, \ + 148, \ + "AUTOPILOT_VERSION", \ + 11, \ + { { "capabilities", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_autopilot_version_t, capabilities) }, \ { "uid", NULL, MAVLINK_TYPE_UINT64_T, 0, 8, offsetof(mavlink_autopilot_version_t, uid) }, \ { "flight_sw_version", NULL, MAVLINK_TYPE_UINT32_T, 0, 16, offsetof(mavlink_autopilot_version_t, flight_sw_version) }, \ { "middleware_sw_version", NULL, MAVLINK_TYPE_UINT32_T, 0, 20, offsetof(mavlink_autopilot_version_t, middleware_sw_version) }, \ @@ -43,7 +48,24 @@ typedef struct __mavlink_autopilot_version_t { "os_custom_version", NULL, MAVLINK_TYPE_UINT8_T, 8, 52, offsetof(mavlink_autopilot_version_t, os_custom_version) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_AUTOPILOT_VERSION { \ + "AUTOPILOT_VERSION", \ + 11, \ + { { "capabilities", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_autopilot_version_t, capabilities) }, \ + { "uid", NULL, MAVLINK_TYPE_UINT64_T, 0, 8, offsetof(mavlink_autopilot_version_t, uid) }, \ + { "flight_sw_version", NULL, MAVLINK_TYPE_UINT32_T, 0, 16, offsetof(mavlink_autopilot_version_t, flight_sw_version) }, \ + { "middleware_sw_version", NULL, MAVLINK_TYPE_UINT32_T, 0, 20, offsetof(mavlink_autopilot_version_t, middleware_sw_version) }, \ + { "os_sw_version", NULL, MAVLINK_TYPE_UINT32_T, 0, 24, offsetof(mavlink_autopilot_version_t, os_sw_version) }, \ + { "board_version", NULL, MAVLINK_TYPE_UINT32_T, 0, 28, offsetof(mavlink_autopilot_version_t, board_version) }, \ + { "vendor_id", NULL, MAVLINK_TYPE_UINT16_T, 0, 32, offsetof(mavlink_autopilot_version_t, vendor_id) }, \ + { "product_id", NULL, MAVLINK_TYPE_UINT16_T, 0, 34, offsetof(mavlink_autopilot_version_t, product_id) }, \ + { "flight_custom_version", NULL, MAVLINK_TYPE_UINT8_T, 8, 36, offsetof(mavlink_autopilot_version_t, flight_custom_version) }, \ + { "middleware_custom_version", NULL, MAVLINK_TYPE_UINT8_T, 8, 44, offsetof(mavlink_autopilot_version_t, middleware_custom_version) }, \ + { "os_custom_version", NULL, MAVLINK_TYPE_UINT8_T, 8, 52, offsetof(mavlink_autopilot_version_t, os_custom_version) }, \ + } \ +} +#endif /** * @brief Pack a autopilot_version message @@ -65,44 +87,40 @@ typedef struct __mavlink_autopilot_version_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_autopilot_version_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t capabilities, uint32_t flight_sw_version, uint32_t middleware_sw_version, uint32_t os_sw_version, uint32_t board_version, const uint8_t *flight_custom_version, const uint8_t *middleware_custom_version, const uint8_t *os_custom_version, uint16_t vendor_id, uint16_t product_id, uint64_t uid) + uint64_t capabilities, uint32_t flight_sw_version, uint32_t middleware_sw_version, uint32_t os_sw_version, uint32_t board_version, const uint8_t *flight_custom_version, const uint8_t *middleware_custom_version, const uint8_t *os_custom_version, uint16_t vendor_id, uint16_t product_id, uint64_t uid) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN]; - _mav_put_uint64_t(buf, 0, capabilities); - _mav_put_uint64_t(buf, 8, uid); - _mav_put_uint32_t(buf, 16, flight_sw_version); - _mav_put_uint32_t(buf, 20, middleware_sw_version); - _mav_put_uint32_t(buf, 24, os_sw_version); - _mav_put_uint32_t(buf, 28, board_version); - _mav_put_uint16_t(buf, 32, vendor_id); - _mav_put_uint16_t(buf, 34, product_id); - _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); - _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); - _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); + char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN]; + _mav_put_uint64_t(buf, 0, capabilities); + _mav_put_uint64_t(buf, 8, uid); + _mav_put_uint32_t(buf, 16, flight_sw_version); + _mav_put_uint32_t(buf, 20, middleware_sw_version); + _mav_put_uint32_t(buf, 24, os_sw_version); + _mav_put_uint32_t(buf, 28, board_version); + _mav_put_uint16_t(buf, 32, vendor_id); + _mav_put_uint16_t(buf, 34, product_id); + _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); + _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); + _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); #else - mavlink_autopilot_version_t packet; - packet.capabilities = capabilities; - packet.uid = uid; - packet.flight_sw_version = flight_sw_version; - packet.middleware_sw_version = middleware_sw_version; - packet.os_sw_version = os_sw_version; - packet.board_version = board_version; - packet.vendor_id = vendor_id; - packet.product_id = product_id; - mav_array_memcpy(packet.flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet.middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet.os_custom_version, os_custom_version, sizeof(uint8_t)*8); + mavlink_autopilot_version_t packet; + packet.capabilities = capabilities; + packet.uid = uid; + packet.flight_sw_version = flight_sw_version; + packet.middleware_sw_version = middleware_sw_version; + packet.os_sw_version = os_sw_version; + packet.board_version = board_version; + packet.vendor_id = vendor_id; + packet.product_id = product_id; + mav_array_memcpy(packet.flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet.middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet.os_custom_version, os_custom_version, sizeof(uint8_t)*8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); } /** @@ -125,45 +143,41 @@ static inline uint16_t mavlink_msg_autopilot_version_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_autopilot_version_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t capabilities,uint32_t flight_sw_version,uint32_t middleware_sw_version,uint32_t os_sw_version,uint32_t board_version,const uint8_t *flight_custom_version,const uint8_t *middleware_custom_version,const uint8_t *os_custom_version,uint16_t vendor_id,uint16_t product_id,uint64_t uid) + mavlink_message_t* msg, + uint64_t capabilities,uint32_t flight_sw_version,uint32_t middleware_sw_version,uint32_t os_sw_version,uint32_t board_version,const uint8_t *flight_custom_version,const uint8_t *middleware_custom_version,const uint8_t *os_custom_version,uint16_t vendor_id,uint16_t product_id,uint64_t uid) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN]; - _mav_put_uint64_t(buf, 0, capabilities); - _mav_put_uint64_t(buf, 8, uid); - _mav_put_uint32_t(buf, 16, flight_sw_version); - _mav_put_uint32_t(buf, 20, middleware_sw_version); - _mav_put_uint32_t(buf, 24, os_sw_version); - _mav_put_uint32_t(buf, 28, board_version); - _mav_put_uint16_t(buf, 32, vendor_id); - _mav_put_uint16_t(buf, 34, product_id); - _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); - _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); - _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); + char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN]; + _mav_put_uint64_t(buf, 0, capabilities); + _mav_put_uint64_t(buf, 8, uid); + _mav_put_uint32_t(buf, 16, flight_sw_version); + _mav_put_uint32_t(buf, 20, middleware_sw_version); + _mav_put_uint32_t(buf, 24, os_sw_version); + _mav_put_uint32_t(buf, 28, board_version); + _mav_put_uint16_t(buf, 32, vendor_id); + _mav_put_uint16_t(buf, 34, product_id); + _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); + _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); + _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); #else - mavlink_autopilot_version_t packet; - packet.capabilities = capabilities; - packet.uid = uid; - packet.flight_sw_version = flight_sw_version; - packet.middleware_sw_version = middleware_sw_version; - packet.os_sw_version = os_sw_version; - packet.board_version = board_version; - packet.vendor_id = vendor_id; - packet.product_id = product_id; - mav_array_memcpy(packet.flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet.middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet.os_custom_version, os_custom_version, sizeof(uint8_t)*8); + mavlink_autopilot_version_t packet; + packet.capabilities = capabilities; + packet.uid = uid; + packet.flight_sw_version = flight_sw_version; + packet.middleware_sw_version = middleware_sw_version; + packet.os_sw_version = os_sw_version; + packet.board_version = board_version; + packet.vendor_id = vendor_id; + packet.product_id = product_id; + mav_array_memcpy(packet.flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet.middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet.os_custom_version, os_custom_version, sizeof(uint8_t)*8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_AUTOPILOT_VERSION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); } /** @@ -176,7 +190,7 @@ static inline uint16_t mavlink_msg_autopilot_version_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_autopilot_version_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_autopilot_version_t* autopilot_version) { - return mavlink_msg_autopilot_version_pack(system_id, component_id, msg, autopilot_version->capabilities, autopilot_version->flight_sw_version, autopilot_version->middleware_sw_version, autopilot_version->os_sw_version, autopilot_version->board_version, autopilot_version->flight_custom_version, autopilot_version->middleware_custom_version, autopilot_version->os_custom_version, autopilot_version->vendor_id, autopilot_version->product_id, autopilot_version->uid); + return mavlink_msg_autopilot_version_pack(system_id, component_id, msg, autopilot_version->capabilities, autopilot_version->flight_sw_version, autopilot_version->middleware_sw_version, autopilot_version->os_sw_version, autopilot_version->board_version, autopilot_version->flight_custom_version, autopilot_version->middleware_custom_version, autopilot_version->os_custom_version, autopilot_version->vendor_id, autopilot_version->product_id, autopilot_version->uid); } /** @@ -190,7 +204,7 @@ static inline uint16_t mavlink_msg_autopilot_version_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_autopilot_version_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_autopilot_version_t* autopilot_version) { - return mavlink_msg_autopilot_version_pack_chan(system_id, component_id, chan, msg, autopilot_version->capabilities, autopilot_version->flight_sw_version, autopilot_version->middleware_sw_version, autopilot_version->os_sw_version, autopilot_version->board_version, autopilot_version->flight_custom_version, autopilot_version->middleware_custom_version, autopilot_version->os_custom_version, autopilot_version->vendor_id, autopilot_version->product_id, autopilot_version->uid); + return mavlink_msg_autopilot_version_pack_chan(system_id, component_id, chan, msg, autopilot_version->capabilities, autopilot_version->flight_sw_version, autopilot_version->middleware_sw_version, autopilot_version->os_sw_version, autopilot_version->board_version, autopilot_version->flight_custom_version, autopilot_version->middleware_custom_version, autopilot_version->os_custom_version, autopilot_version->vendor_id, autopilot_version->product_id, autopilot_version->uid); } /** @@ -214,41 +228,47 @@ static inline uint16_t mavlink_msg_autopilot_version_encode_chan(uint8_t system_ static inline void mavlink_msg_autopilot_version_send(mavlink_channel_t chan, uint64_t capabilities, uint32_t flight_sw_version, uint32_t middleware_sw_version, uint32_t os_sw_version, uint32_t board_version, const uint8_t *flight_custom_version, const uint8_t *middleware_custom_version, const uint8_t *os_custom_version, uint16_t vendor_id, uint16_t product_id, uint64_t uid) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN]; - _mav_put_uint64_t(buf, 0, capabilities); - _mav_put_uint64_t(buf, 8, uid); - _mav_put_uint32_t(buf, 16, flight_sw_version); - _mav_put_uint32_t(buf, 20, middleware_sw_version); - _mav_put_uint32_t(buf, 24, os_sw_version); - _mav_put_uint32_t(buf, 28, board_version); - _mav_put_uint16_t(buf, 32, vendor_id); - _mav_put_uint16_t(buf, 34, product_id); - _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); - _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); - _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); + char buf[MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN]; + _mav_put_uint64_t(buf, 0, capabilities); + _mav_put_uint64_t(buf, 8, uid); + _mav_put_uint32_t(buf, 16, flight_sw_version); + _mav_put_uint32_t(buf, 20, middleware_sw_version); + _mav_put_uint32_t(buf, 24, os_sw_version); + _mav_put_uint32_t(buf, 28, board_version); + _mav_put_uint16_t(buf, 32, vendor_id); + _mav_put_uint16_t(buf, 34, product_id); + _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); + _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); + _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); + mavlink_autopilot_version_t packet; + packet.capabilities = capabilities; + packet.uid = uid; + packet.flight_sw_version = flight_sw_version; + packet.middleware_sw_version = middleware_sw_version; + packet.os_sw_version = os_sw_version; + packet.board_version = board_version; + packet.vendor_id = vendor_id; + packet.product_id = product_id; + mav_array_memcpy(packet.flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet.middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet.os_custom_version, os_custom_version, sizeof(uint8_t)*8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, (const char *)&packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); #endif +} + +/** + * @brief Send a autopilot_version message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_autopilot_version_send_struct(mavlink_channel_t chan, const mavlink_autopilot_version_t* autopilot_version) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_autopilot_version_send(chan, autopilot_version->capabilities, autopilot_version->flight_sw_version, autopilot_version->middleware_sw_version, autopilot_version->os_sw_version, autopilot_version->board_version, autopilot_version->flight_custom_version, autopilot_version->middleware_custom_version, autopilot_version->os_custom_version, autopilot_version->vendor_id, autopilot_version->product_id, autopilot_version->uid); #else - mavlink_autopilot_version_t packet; - packet.capabilities = capabilities; - packet.uid = uid; - packet.flight_sw_version = flight_sw_version; - packet.middleware_sw_version = middleware_sw_version; - packet.os_sw_version = os_sw_version; - packet.board_version = board_version; - packet.vendor_id = vendor_id; - packet.product_id = product_id; - mav_array_memcpy(packet.flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet.middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet.os_custom_version, os_custom_version, sizeof(uint8_t)*8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, (const char *)&packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, (const char *)&packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, (const char *)autopilot_version, MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); #endif } @@ -263,41 +283,33 @@ static inline void mavlink_msg_autopilot_version_send(mavlink_channel_t chan, ui static inline void mavlink_msg_autopilot_version_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t capabilities, uint32_t flight_sw_version, uint32_t middleware_sw_version, uint32_t os_sw_version, uint32_t board_version, const uint8_t *flight_custom_version, const uint8_t *middleware_custom_version, const uint8_t *os_custom_version, uint16_t vendor_id, uint16_t product_id, uint64_t uid) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, capabilities); - _mav_put_uint64_t(buf, 8, uid); - _mav_put_uint32_t(buf, 16, flight_sw_version); - _mav_put_uint32_t(buf, 20, middleware_sw_version); - _mav_put_uint32_t(buf, 24, os_sw_version); - _mav_put_uint32_t(buf, 28, board_version); - _mav_put_uint16_t(buf, 32, vendor_id); - _mav_put_uint16_t(buf, 34, product_id); - _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); - _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); - _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, capabilities); + _mav_put_uint64_t(buf, 8, uid); + _mav_put_uint32_t(buf, 16, flight_sw_version); + _mav_put_uint32_t(buf, 20, middleware_sw_version); + _mav_put_uint32_t(buf, 24, os_sw_version); + _mav_put_uint32_t(buf, 28, board_version); + _mav_put_uint16_t(buf, 32, vendor_id); + _mav_put_uint16_t(buf, 34, product_id); + _mav_put_uint8_t_array(buf, 36, flight_custom_version, 8); + _mav_put_uint8_t_array(buf, 44, middleware_custom_version, 8); + _mav_put_uint8_t_array(buf, 52, os_custom_version, 8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, buf, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); -#endif -#else - mavlink_autopilot_version_t *packet = (mavlink_autopilot_version_t *)msgbuf; - packet->capabilities = capabilities; - packet->uid = uid; - packet->flight_sw_version = flight_sw_version; - packet->middleware_sw_version = middleware_sw_version; - packet->os_sw_version = os_sw_version; - packet->board_version = board_version; - packet->vendor_id = vendor_id; - packet->product_id = product_id; - mav_array_memcpy(packet->flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet->middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet->os_custom_version, os_custom_version, sizeof(uint8_t)*8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, (const char *)packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, (const char *)packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); -#endif + mavlink_autopilot_version_t *packet = (mavlink_autopilot_version_t *)msgbuf; + packet->capabilities = capabilities; + packet->uid = uid; + packet->flight_sw_version = flight_sw_version; + packet->middleware_sw_version = middleware_sw_version; + packet->os_sw_version = os_sw_version; + packet->board_version = board_version; + packet->vendor_id = vendor_id; + packet->product_id = product_id; + mav_array_memcpy(packet->flight_custom_version, flight_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet->middleware_custom_version, middleware_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet->os_custom_version, os_custom_version, sizeof(uint8_t)*8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_AUTOPILOT_VERSION, (const char *)packet, MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN, MAVLINK_MSG_ID_AUTOPILOT_VERSION_CRC); #endif } #endif @@ -314,7 +326,7 @@ static inline void mavlink_msg_autopilot_version_send_buf(mavlink_message_t *msg */ static inline uint64_t mavlink_msg_autopilot_version_get_capabilities(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -324,7 +336,7 @@ static inline uint64_t mavlink_msg_autopilot_version_get_capabilities(const mavl */ static inline uint32_t mavlink_msg_autopilot_version_get_flight_sw_version(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 16); + return _MAV_RETURN_uint32_t(msg, 16); } /** @@ -334,7 +346,7 @@ static inline uint32_t mavlink_msg_autopilot_version_get_flight_sw_version(const */ static inline uint32_t mavlink_msg_autopilot_version_get_middleware_sw_version(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 20); + return _MAV_RETURN_uint32_t(msg, 20); } /** @@ -344,7 +356,7 @@ static inline uint32_t mavlink_msg_autopilot_version_get_middleware_sw_version(c */ static inline uint32_t mavlink_msg_autopilot_version_get_os_sw_version(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 24); + return _MAV_RETURN_uint32_t(msg, 24); } /** @@ -354,7 +366,7 @@ static inline uint32_t mavlink_msg_autopilot_version_get_os_sw_version(const mav */ static inline uint32_t mavlink_msg_autopilot_version_get_board_version(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 28); + return _MAV_RETURN_uint32_t(msg, 28); } /** @@ -364,7 +376,7 @@ static inline uint32_t mavlink_msg_autopilot_version_get_board_version(const mav */ static inline uint16_t mavlink_msg_autopilot_version_get_flight_custom_version(const mavlink_message_t* msg, uint8_t *flight_custom_version) { - return _MAV_RETURN_uint8_t_array(msg, flight_custom_version, 8, 36); + return _MAV_RETURN_uint8_t_array(msg, flight_custom_version, 8, 36); } /** @@ -374,7 +386,7 @@ static inline uint16_t mavlink_msg_autopilot_version_get_flight_custom_version(c */ static inline uint16_t mavlink_msg_autopilot_version_get_middleware_custom_version(const mavlink_message_t* msg, uint8_t *middleware_custom_version) { - return _MAV_RETURN_uint8_t_array(msg, middleware_custom_version, 8, 44); + return _MAV_RETURN_uint8_t_array(msg, middleware_custom_version, 8, 44); } /** @@ -384,7 +396,7 @@ static inline uint16_t mavlink_msg_autopilot_version_get_middleware_custom_versi */ static inline uint16_t mavlink_msg_autopilot_version_get_os_custom_version(const mavlink_message_t* msg, uint8_t *os_custom_version) { - return _MAV_RETURN_uint8_t_array(msg, os_custom_version, 8, 52); + return _MAV_RETURN_uint8_t_array(msg, os_custom_version, 8, 52); } /** @@ -394,7 +406,7 @@ static inline uint16_t mavlink_msg_autopilot_version_get_os_custom_version(const */ static inline uint16_t mavlink_msg_autopilot_version_get_vendor_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 32); + return _MAV_RETURN_uint16_t(msg, 32); } /** @@ -404,7 +416,7 @@ static inline uint16_t mavlink_msg_autopilot_version_get_vendor_id(const mavlink */ static inline uint16_t mavlink_msg_autopilot_version_get_product_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 34); + return _MAV_RETURN_uint16_t(msg, 34); } /** @@ -414,7 +426,7 @@ static inline uint16_t mavlink_msg_autopilot_version_get_product_id(const mavlin */ static inline uint64_t mavlink_msg_autopilot_version_get_uid(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 8); + return _MAV_RETURN_uint64_t(msg, 8); } /** @@ -425,19 +437,21 @@ static inline uint64_t mavlink_msg_autopilot_version_get_uid(const mavlink_messa */ static inline void mavlink_msg_autopilot_version_decode(const mavlink_message_t* msg, mavlink_autopilot_version_t* autopilot_version) { -#if MAVLINK_NEED_BYTE_SWAP - autopilot_version->capabilities = mavlink_msg_autopilot_version_get_capabilities(msg); - autopilot_version->uid = mavlink_msg_autopilot_version_get_uid(msg); - autopilot_version->flight_sw_version = mavlink_msg_autopilot_version_get_flight_sw_version(msg); - autopilot_version->middleware_sw_version = mavlink_msg_autopilot_version_get_middleware_sw_version(msg); - autopilot_version->os_sw_version = mavlink_msg_autopilot_version_get_os_sw_version(msg); - autopilot_version->board_version = mavlink_msg_autopilot_version_get_board_version(msg); - autopilot_version->vendor_id = mavlink_msg_autopilot_version_get_vendor_id(msg); - autopilot_version->product_id = mavlink_msg_autopilot_version_get_product_id(msg); - mavlink_msg_autopilot_version_get_flight_custom_version(msg, autopilot_version->flight_custom_version); - mavlink_msg_autopilot_version_get_middleware_custom_version(msg, autopilot_version->middleware_custom_version); - mavlink_msg_autopilot_version_get_os_custom_version(msg, autopilot_version->os_custom_version); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + autopilot_version->capabilities = mavlink_msg_autopilot_version_get_capabilities(msg); + autopilot_version->uid = mavlink_msg_autopilot_version_get_uid(msg); + autopilot_version->flight_sw_version = mavlink_msg_autopilot_version_get_flight_sw_version(msg); + autopilot_version->middleware_sw_version = mavlink_msg_autopilot_version_get_middleware_sw_version(msg); + autopilot_version->os_sw_version = mavlink_msg_autopilot_version_get_os_sw_version(msg); + autopilot_version->board_version = mavlink_msg_autopilot_version_get_board_version(msg); + autopilot_version->vendor_id = mavlink_msg_autopilot_version_get_vendor_id(msg); + autopilot_version->product_id = mavlink_msg_autopilot_version_get_product_id(msg); + mavlink_msg_autopilot_version_get_flight_custom_version(msg, autopilot_version->flight_custom_version); + mavlink_msg_autopilot_version_get_middleware_custom_version(msg, autopilot_version->middleware_custom_version); + mavlink_msg_autopilot_version_get_os_custom_version(msg, autopilot_version->os_custom_version); #else - memcpy(autopilot_version, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN? msg->len : MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN; + memset(autopilot_version, 0, MAVLINK_MSG_ID_AUTOPILOT_VERSION_LEN); + memcpy(autopilot_version, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_battery_status.h b/vendor/libraries/mavlink/common/mavlink_msg_battery_status.h index 12371e69fa..d69a246c4d 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_battery_status.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_battery_status.h @@ -1,32 +1,37 @@ +#pragma once // MESSAGE BATTERY_STATUS PACKING #define MAVLINK_MSG_ID_BATTERY_STATUS 147 -typedef struct __mavlink_battery_status_t -{ - int32_t current_consumed; ///< Consumed charge, in milliampere hours (1 = 1 mAh), -1: autopilot does not provide mAh consumption estimate - int32_t energy_consumed; ///< Consumed energy, in 100*Joules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate - int16_t temperature; ///< Temperature of the battery in centi-degrees celsius. INT16_MAX for unknown temperature. - uint16_t voltages[10]; ///< Battery voltage of cells, in millivolts (1 = 1 millivolt) - int16_t current_battery; ///< Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current - uint8_t id; ///< Battery ID - uint8_t battery_function; ///< Function of the battery - uint8_t type; ///< Type (chemistry) of the battery - int8_t battery_remaining; ///< Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot does not estimate the remaining battery -} mavlink_battery_status_t; +MAVPACKED( +typedef struct __mavlink_battery_status_t { + int32_t current_consumed; /*< Consumed charge, in milliampere hours (1 = 1 mAh), -1: autopilot does not provide mAh consumption estimate*/ + int32_t energy_consumed; /*< Consumed energy, in HectoJoules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate*/ + int16_t temperature; /*< Temperature of the battery in centi-degrees celsius. INT16_MAX for unknown temperature.*/ + uint16_t voltages[10]; /*< Battery voltage of cells, in millivolts (1 = 1 millivolt). Cells above the valid cell count for this battery should have the UINT16_MAX value.*/ + int16_t current_battery; /*< Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current*/ + uint8_t id; /*< Battery ID*/ + uint8_t battery_function; /*< Function of the battery*/ + uint8_t type; /*< Type (chemistry) of the battery*/ + int8_t battery_remaining; /*< Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot does not estimate the remaining battery*/ +}) mavlink_battery_status_t; #define MAVLINK_MSG_ID_BATTERY_STATUS_LEN 36 +#define MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN 36 #define MAVLINK_MSG_ID_147_LEN 36 +#define MAVLINK_MSG_ID_147_MIN_LEN 36 #define MAVLINK_MSG_ID_BATTERY_STATUS_CRC 154 #define MAVLINK_MSG_ID_147_CRC 154 #define MAVLINK_MSG_BATTERY_STATUS_FIELD_VOLTAGES_LEN 10 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_BATTERY_STATUS { \ - "BATTERY_STATUS", \ - 9, \ - { { "current_consumed", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_battery_status_t, current_consumed) }, \ + 147, \ + "BATTERY_STATUS", \ + 9, \ + { { "current_consumed", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_battery_status_t, current_consumed) }, \ { "energy_consumed", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_battery_status_t, energy_consumed) }, \ { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_battery_status_t, temperature) }, \ { "voltages", NULL, MAVLINK_TYPE_UINT16_T, 10, 10, offsetof(mavlink_battery_status_t, voltages) }, \ @@ -37,7 +42,22 @@ typedef struct __mavlink_battery_status_t { "battery_remaining", NULL, MAVLINK_TYPE_INT8_T, 0, 35, offsetof(mavlink_battery_status_t, battery_remaining) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_BATTERY_STATUS { \ + "BATTERY_STATUS", \ + 9, \ + { { "current_consumed", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_battery_status_t, current_consumed) }, \ + { "energy_consumed", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_battery_status_t, energy_consumed) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_battery_status_t, temperature) }, \ + { "voltages", NULL, MAVLINK_TYPE_UINT16_T, 10, 10, offsetof(mavlink_battery_status_t, voltages) }, \ + { "current_battery", NULL, MAVLINK_TYPE_INT16_T, 0, 30, offsetof(mavlink_battery_status_t, current_battery) }, \ + { "id", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_battery_status_t, id) }, \ + { "battery_function", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_battery_status_t, battery_function) }, \ + { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_battery_status_t, type) }, \ + { "battery_remaining", NULL, MAVLINK_TYPE_INT8_T, 0, 35, offsetof(mavlink_battery_status_t, battery_remaining) }, \ + } \ +} +#endif /** * @brief Pack a battery_status message @@ -49,48 +69,44 @@ typedef struct __mavlink_battery_status_t * @param battery_function Function of the battery * @param type Type (chemistry) of the battery * @param temperature Temperature of the battery in centi-degrees celsius. INT16_MAX for unknown temperature. - * @param voltages Battery voltage of cells, in millivolts (1 = 1 millivolt) + * @param voltages Battery voltage of cells, in millivolts (1 = 1 millivolt). Cells above the valid cell count for this battery should have the UINT16_MAX value. * @param current_battery Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current * @param current_consumed Consumed charge, in milliampere hours (1 = 1 mAh), -1: autopilot does not provide mAh consumption estimate - * @param energy_consumed Consumed energy, in 100*Joules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate + * @param energy_consumed Consumed energy, in HectoJoules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate * @param battery_remaining Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot does not estimate the remaining battery * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_battery_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t id, uint8_t battery_function, uint8_t type, int16_t temperature, const uint16_t *voltages, int16_t current_battery, int32_t current_consumed, int32_t energy_consumed, int8_t battery_remaining) + uint8_t id, uint8_t battery_function, uint8_t type, int16_t temperature, const uint16_t *voltages, int16_t current_battery, int32_t current_consumed, int32_t energy_consumed, int8_t battery_remaining) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_BATTERY_STATUS_LEN]; - _mav_put_int32_t(buf, 0, current_consumed); - _mav_put_int32_t(buf, 4, energy_consumed); - _mav_put_int16_t(buf, 8, temperature); - _mav_put_int16_t(buf, 30, current_battery); - _mav_put_uint8_t(buf, 32, id); - _mav_put_uint8_t(buf, 33, battery_function); - _mav_put_uint8_t(buf, 34, type); - _mav_put_int8_t(buf, 35, battery_remaining); - _mav_put_uint16_t_array(buf, 10, voltages, 10); + char buf[MAVLINK_MSG_ID_BATTERY_STATUS_LEN]; + _mav_put_int32_t(buf, 0, current_consumed); + _mav_put_int32_t(buf, 4, energy_consumed); + _mav_put_int16_t(buf, 8, temperature); + _mav_put_int16_t(buf, 30, current_battery); + _mav_put_uint8_t(buf, 32, id); + _mav_put_uint8_t(buf, 33, battery_function); + _mav_put_uint8_t(buf, 34, type); + _mav_put_int8_t(buf, 35, battery_remaining); + _mav_put_uint16_t_array(buf, 10, voltages, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); #else - mavlink_battery_status_t packet; - packet.current_consumed = current_consumed; - packet.energy_consumed = energy_consumed; - packet.temperature = temperature; - packet.current_battery = current_battery; - packet.id = id; - packet.battery_function = battery_function; - packet.type = type; - packet.battery_remaining = battery_remaining; - mav_array_memcpy(packet.voltages, voltages, sizeof(uint16_t)*10); + mavlink_battery_status_t packet; + packet.current_consumed = current_consumed; + packet.energy_consumed = energy_consumed; + packet.temperature = temperature; + packet.current_battery = current_battery; + packet.id = id; + packet.battery_function = battery_function; + packet.type = type; + packet.battery_remaining = battery_remaining; + mav_array_memcpy(packet.voltages, voltages, sizeof(uint16_t)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_BATTERY_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_BATTERY_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); } /** @@ -103,49 +119,45 @@ static inline uint16_t mavlink_msg_battery_status_pack(uint8_t system_id, uint8_ * @param battery_function Function of the battery * @param type Type (chemistry) of the battery * @param temperature Temperature of the battery in centi-degrees celsius. INT16_MAX for unknown temperature. - * @param voltages Battery voltage of cells, in millivolts (1 = 1 millivolt) + * @param voltages Battery voltage of cells, in millivolts (1 = 1 millivolt). Cells above the valid cell count for this battery should have the UINT16_MAX value. * @param current_battery Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current * @param current_consumed Consumed charge, in milliampere hours (1 = 1 mAh), -1: autopilot does not provide mAh consumption estimate - * @param energy_consumed Consumed energy, in 100*Joules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate + * @param energy_consumed Consumed energy, in HectoJoules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate * @param battery_remaining Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot does not estimate the remaining battery * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_battery_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t id,uint8_t battery_function,uint8_t type,int16_t temperature,const uint16_t *voltages,int16_t current_battery,int32_t current_consumed,int32_t energy_consumed,int8_t battery_remaining) + mavlink_message_t* msg, + uint8_t id,uint8_t battery_function,uint8_t type,int16_t temperature,const uint16_t *voltages,int16_t current_battery,int32_t current_consumed,int32_t energy_consumed,int8_t battery_remaining) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_BATTERY_STATUS_LEN]; - _mav_put_int32_t(buf, 0, current_consumed); - _mav_put_int32_t(buf, 4, energy_consumed); - _mav_put_int16_t(buf, 8, temperature); - _mav_put_int16_t(buf, 30, current_battery); - _mav_put_uint8_t(buf, 32, id); - _mav_put_uint8_t(buf, 33, battery_function); - _mav_put_uint8_t(buf, 34, type); - _mav_put_int8_t(buf, 35, battery_remaining); - _mav_put_uint16_t_array(buf, 10, voltages, 10); + char buf[MAVLINK_MSG_ID_BATTERY_STATUS_LEN]; + _mav_put_int32_t(buf, 0, current_consumed); + _mav_put_int32_t(buf, 4, energy_consumed); + _mav_put_int16_t(buf, 8, temperature); + _mav_put_int16_t(buf, 30, current_battery); + _mav_put_uint8_t(buf, 32, id); + _mav_put_uint8_t(buf, 33, battery_function); + _mav_put_uint8_t(buf, 34, type); + _mav_put_int8_t(buf, 35, battery_remaining); + _mav_put_uint16_t_array(buf, 10, voltages, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); #else - mavlink_battery_status_t packet; - packet.current_consumed = current_consumed; - packet.energy_consumed = energy_consumed; - packet.temperature = temperature; - packet.current_battery = current_battery; - packet.id = id; - packet.battery_function = battery_function; - packet.type = type; - packet.battery_remaining = battery_remaining; - mav_array_memcpy(packet.voltages, voltages, sizeof(uint16_t)*10); + mavlink_battery_status_t packet; + packet.current_consumed = current_consumed; + packet.energy_consumed = energy_consumed; + packet.temperature = temperature; + packet.current_battery = current_battery; + packet.id = id; + packet.battery_function = battery_function; + packet.type = type; + packet.battery_remaining = battery_remaining; + mav_array_memcpy(packet.voltages, voltages, sizeof(uint16_t)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_BATTERY_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_BATTERY_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); } /** @@ -158,7 +170,7 @@ static inline uint16_t mavlink_msg_battery_status_pack_chan(uint8_t system_id, u */ static inline uint16_t mavlink_msg_battery_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_battery_status_t* battery_status) { - return mavlink_msg_battery_status_pack(system_id, component_id, msg, battery_status->id, battery_status->battery_function, battery_status->type, battery_status->temperature, battery_status->voltages, battery_status->current_battery, battery_status->current_consumed, battery_status->energy_consumed, battery_status->battery_remaining); + return mavlink_msg_battery_status_pack(system_id, component_id, msg, battery_status->id, battery_status->battery_function, battery_status->type, battery_status->temperature, battery_status->voltages, battery_status->current_battery, battery_status->current_consumed, battery_status->energy_consumed, battery_status->battery_remaining); } /** @@ -172,7 +184,7 @@ static inline uint16_t mavlink_msg_battery_status_encode(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_battery_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_battery_status_t* battery_status) { - return mavlink_msg_battery_status_pack_chan(system_id, component_id, chan, msg, battery_status->id, battery_status->battery_function, battery_status->type, battery_status->temperature, battery_status->voltages, battery_status->current_battery, battery_status->current_consumed, battery_status->energy_consumed, battery_status->battery_remaining); + return mavlink_msg_battery_status_pack_chan(system_id, component_id, chan, msg, battery_status->id, battery_status->battery_function, battery_status->type, battery_status->temperature, battery_status->voltages, battery_status->current_battery, battery_status->current_consumed, battery_status->energy_consumed, battery_status->battery_remaining); } /** @@ -183,10 +195,10 @@ static inline uint16_t mavlink_msg_battery_status_encode_chan(uint8_t system_id, * @param battery_function Function of the battery * @param type Type (chemistry) of the battery * @param temperature Temperature of the battery in centi-degrees celsius. INT16_MAX for unknown temperature. - * @param voltages Battery voltage of cells, in millivolts (1 = 1 millivolt) + * @param voltages Battery voltage of cells, in millivolts (1 = 1 millivolt). Cells above the valid cell count for this battery should have the UINT16_MAX value. * @param current_battery Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current * @param current_consumed Consumed charge, in milliampere hours (1 = 1 mAh), -1: autopilot does not provide mAh consumption estimate - * @param energy_consumed Consumed energy, in 100*Joules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate + * @param energy_consumed Consumed energy, in HectoJoules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate * @param battery_remaining Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot does not estimate the remaining battery */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -194,37 +206,43 @@ static inline uint16_t mavlink_msg_battery_status_encode_chan(uint8_t system_id, static inline void mavlink_msg_battery_status_send(mavlink_channel_t chan, uint8_t id, uint8_t battery_function, uint8_t type, int16_t temperature, const uint16_t *voltages, int16_t current_battery, int32_t current_consumed, int32_t energy_consumed, int8_t battery_remaining) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_BATTERY_STATUS_LEN]; - _mav_put_int32_t(buf, 0, current_consumed); - _mav_put_int32_t(buf, 4, energy_consumed); - _mav_put_int16_t(buf, 8, temperature); - _mav_put_int16_t(buf, 30, current_battery); - _mav_put_uint8_t(buf, 32, id); - _mav_put_uint8_t(buf, 33, battery_function); - _mav_put_uint8_t(buf, 34, type); - _mav_put_int8_t(buf, 35, battery_remaining); - _mav_put_uint16_t_array(buf, 10, voltages, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, buf, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); + char buf[MAVLINK_MSG_ID_BATTERY_STATUS_LEN]; + _mav_put_int32_t(buf, 0, current_consumed); + _mav_put_int32_t(buf, 4, energy_consumed); + _mav_put_int16_t(buf, 8, temperature); + _mav_put_int16_t(buf, 30, current_battery); + _mav_put_uint8_t(buf, 32, id); + _mav_put_uint8_t(buf, 33, battery_function); + _mav_put_uint8_t(buf, 34, type); + _mav_put_int8_t(buf, 35, battery_remaining); + _mav_put_uint16_t_array(buf, 10, voltages, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, buf, MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, buf, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); + mavlink_battery_status_t packet; + packet.current_consumed = current_consumed; + packet.energy_consumed = energy_consumed; + packet.temperature = temperature; + packet.current_battery = current_battery; + packet.id = id; + packet.battery_function = battery_function; + packet.type = type; + packet.battery_remaining = battery_remaining; + mav_array_memcpy(packet.voltages, voltages, sizeof(uint16_t)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, (const char *)&packet, MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); #endif +} + +/** + * @brief Send a battery_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_battery_status_send_struct(mavlink_channel_t chan, const mavlink_battery_status_t* battery_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_battery_status_send(chan, battery_status->id, battery_status->battery_function, battery_status->type, battery_status->temperature, battery_status->voltages, battery_status->current_battery, battery_status->current_consumed, battery_status->energy_consumed, battery_status->battery_remaining); #else - mavlink_battery_status_t packet; - packet.current_consumed = current_consumed; - packet.energy_consumed = energy_consumed; - packet.temperature = temperature; - packet.current_battery = current_battery; - packet.id = id; - packet.battery_function = battery_function; - packet.type = type; - packet.battery_remaining = battery_remaining; - mav_array_memcpy(packet.voltages, voltages, sizeof(uint16_t)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, (const char *)&packet, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, (const char *)&packet, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, (const char *)battery_status, MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); #endif } @@ -239,37 +257,29 @@ static inline void mavlink_msg_battery_status_send(mavlink_channel_t chan, uint8 static inline void mavlink_msg_battery_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t id, uint8_t battery_function, uint8_t type, int16_t temperature, const uint16_t *voltages, int16_t current_battery, int32_t current_consumed, int32_t energy_consumed, int8_t battery_remaining) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, current_consumed); - _mav_put_int32_t(buf, 4, energy_consumed); - _mav_put_int16_t(buf, 8, temperature); - _mav_put_int16_t(buf, 30, current_battery); - _mav_put_uint8_t(buf, 32, id); - _mav_put_uint8_t(buf, 33, battery_function); - _mav_put_uint8_t(buf, 34, type); - _mav_put_int8_t(buf, 35, battery_remaining); - _mav_put_uint16_t_array(buf, 10, voltages, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, buf, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, buf, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); -#endif -#else - mavlink_battery_status_t *packet = (mavlink_battery_status_t *)msgbuf; - packet->current_consumed = current_consumed; - packet->energy_consumed = energy_consumed; - packet->temperature = temperature; - packet->current_battery = current_battery; - packet->id = id; - packet->battery_function = battery_function; - packet->type = type; - packet->battery_remaining = battery_remaining; - mav_array_memcpy(packet->voltages, voltages, sizeof(uint16_t)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, (const char *)packet, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, current_consumed); + _mav_put_int32_t(buf, 4, energy_consumed); + _mav_put_int16_t(buf, 8, temperature); + _mav_put_int16_t(buf, 30, current_battery); + _mav_put_uint8_t(buf, 32, id); + _mav_put_uint8_t(buf, 33, battery_function); + _mav_put_uint8_t(buf, 34, type); + _mav_put_int8_t(buf, 35, battery_remaining); + _mav_put_uint16_t_array(buf, 10, voltages, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, buf, MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, (const char *)packet, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); -#endif + mavlink_battery_status_t *packet = (mavlink_battery_status_t *)msgbuf; + packet->current_consumed = current_consumed; + packet->energy_consumed = energy_consumed; + packet->temperature = temperature; + packet->current_battery = current_battery; + packet->id = id; + packet->battery_function = battery_function; + packet->type = type; + packet->battery_remaining = battery_remaining; + mav_array_memcpy(packet->voltages, voltages, sizeof(uint16_t)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_BATTERY_STATUS, (const char *)packet, MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_LEN, MAVLINK_MSG_ID_BATTERY_STATUS_CRC); #endif } #endif @@ -286,7 +296,7 @@ static inline void mavlink_msg_battery_status_send_buf(mavlink_message_t *msgbuf */ static inline uint8_t mavlink_msg_battery_status_get_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -296,7 +306,7 @@ static inline uint8_t mavlink_msg_battery_status_get_id(const mavlink_message_t* */ static inline uint8_t mavlink_msg_battery_status_get_battery_function(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 33); + return _MAV_RETURN_uint8_t(msg, 33); } /** @@ -306,7 +316,7 @@ static inline uint8_t mavlink_msg_battery_status_get_battery_function(const mavl */ static inline uint8_t mavlink_msg_battery_status_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -316,17 +326,17 @@ static inline uint8_t mavlink_msg_battery_status_get_type(const mavlink_message_ */ static inline int16_t mavlink_msg_battery_status_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 8); + return _MAV_RETURN_int16_t(msg, 8); } /** * @brief Get field voltages from battery_status message * - * @return Battery voltage of cells, in millivolts (1 = 1 millivolt) + * @return Battery voltage of cells, in millivolts (1 = 1 millivolt). Cells above the valid cell count for this battery should have the UINT16_MAX value. */ static inline uint16_t mavlink_msg_battery_status_get_voltages(const mavlink_message_t* msg, uint16_t *voltages) { - return _MAV_RETURN_uint16_t_array(msg, voltages, 10, 10); + return _MAV_RETURN_uint16_t_array(msg, voltages, 10, 10); } /** @@ -336,7 +346,7 @@ static inline uint16_t mavlink_msg_battery_status_get_voltages(const mavlink_mes */ static inline int16_t mavlink_msg_battery_status_get_current_battery(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 30); + return _MAV_RETURN_int16_t(msg, 30); } /** @@ -346,17 +356,17 @@ static inline int16_t mavlink_msg_battery_status_get_current_battery(const mavli */ static inline int32_t mavlink_msg_battery_status_get_current_consumed(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** * @brief Get field energy_consumed from battery_status message * - * @return Consumed energy, in 100*Joules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate + * @return Consumed energy, in HectoJoules (intergrated U*I*dt) (1 = 100 Joule), -1: autopilot does not provide energy consumption estimate */ static inline int32_t mavlink_msg_battery_status_get_energy_consumed(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -366,7 +376,7 @@ static inline int32_t mavlink_msg_battery_status_get_energy_consumed(const mavli */ static inline int8_t mavlink_msg_battery_status_get_battery_remaining(const mavlink_message_t* msg) { - return _MAV_RETURN_int8_t(msg, 35); + return _MAV_RETURN_int8_t(msg, 35); } /** @@ -377,17 +387,19 @@ static inline int8_t mavlink_msg_battery_status_get_battery_remaining(const mavl */ static inline void mavlink_msg_battery_status_decode(const mavlink_message_t* msg, mavlink_battery_status_t* battery_status) { -#if MAVLINK_NEED_BYTE_SWAP - battery_status->current_consumed = mavlink_msg_battery_status_get_current_consumed(msg); - battery_status->energy_consumed = mavlink_msg_battery_status_get_energy_consumed(msg); - battery_status->temperature = mavlink_msg_battery_status_get_temperature(msg); - mavlink_msg_battery_status_get_voltages(msg, battery_status->voltages); - battery_status->current_battery = mavlink_msg_battery_status_get_current_battery(msg); - battery_status->id = mavlink_msg_battery_status_get_id(msg); - battery_status->battery_function = mavlink_msg_battery_status_get_battery_function(msg); - battery_status->type = mavlink_msg_battery_status_get_type(msg); - battery_status->battery_remaining = mavlink_msg_battery_status_get_battery_remaining(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + battery_status->current_consumed = mavlink_msg_battery_status_get_current_consumed(msg); + battery_status->energy_consumed = mavlink_msg_battery_status_get_energy_consumed(msg); + battery_status->temperature = mavlink_msg_battery_status_get_temperature(msg); + mavlink_msg_battery_status_get_voltages(msg, battery_status->voltages); + battery_status->current_battery = mavlink_msg_battery_status_get_current_battery(msg); + battery_status->id = mavlink_msg_battery_status_get_id(msg); + battery_status->battery_function = mavlink_msg_battery_status_get_battery_function(msg); + battery_status->type = mavlink_msg_battery_status_get_type(msg); + battery_status->battery_remaining = mavlink_msg_battery_status_get_battery_remaining(msg); #else - memcpy(battery_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_BATTERY_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_BATTERY_STATUS_LEN? msg->len : MAVLINK_MSG_ID_BATTERY_STATUS_LEN; + memset(battery_status, 0, MAVLINK_MSG_ID_BATTERY_STATUS_LEN); + memcpy(battery_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_camera_trigger.h b/vendor/libraries/mavlink/common/mavlink_msg_camera_trigger.h new file mode 100644 index 0000000000..71bb1c1c86 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_camera_trigger.h @@ -0,0 +1,238 @@ +#pragma once +// MESSAGE CAMERA_TRIGGER PACKING + +#define MAVLINK_MSG_ID_CAMERA_TRIGGER 112 + +MAVPACKED( +typedef struct __mavlink_camera_trigger_t { + uint64_t time_usec; /*< Timestamp for the image frame in microseconds*/ + uint32_t seq; /*< Image frame sequence*/ +}) mavlink_camera_trigger_t; + +#define MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN 12 +#define MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN 12 +#define MAVLINK_MSG_ID_112_LEN 12 +#define MAVLINK_MSG_ID_112_MIN_LEN 12 + +#define MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC 174 +#define MAVLINK_MSG_ID_112_CRC 174 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_CAMERA_TRIGGER { \ + 112, \ + "CAMERA_TRIGGER", \ + 2, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_trigger_t, time_usec) }, \ + { "seq", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_camera_trigger_t, seq) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_CAMERA_TRIGGER { \ + "CAMERA_TRIGGER", \ + 2, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_camera_trigger_t, time_usec) }, \ + { "seq", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_camera_trigger_t, seq) }, \ + } \ +} +#endif + +/** + * @brief Pack a camera_trigger message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp for the image frame in microseconds + * @param seq Image frame sequence + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_camera_trigger_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, uint32_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN); +#else + mavlink_camera_trigger_t packet; + packet.time_usec = time_usec; + packet.seq = seq; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_CAMERA_TRIGGER; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC); +} + +/** + * @brief Pack a camera_trigger message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp for the image frame in microseconds + * @param seq Image frame sequence + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_camera_trigger_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,uint32_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN); +#else + mavlink_camera_trigger_t packet; + packet.time_usec = time_usec; + packet.seq = seq; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_CAMERA_TRIGGER; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC); +} + +/** + * @brief Encode a camera_trigger struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param camera_trigger C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_camera_trigger_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_camera_trigger_t* camera_trigger) +{ + return mavlink_msg_camera_trigger_pack(system_id, component_id, msg, camera_trigger->time_usec, camera_trigger->seq); +} + +/** + * @brief Encode a camera_trigger struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param camera_trigger C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_camera_trigger_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_camera_trigger_t* camera_trigger) +{ + return mavlink_msg_camera_trigger_pack_chan(system_id, component_id, chan, msg, camera_trigger->time_usec, camera_trigger->seq); +} + +/** + * @brief Send a camera_trigger message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp for the image frame in microseconds + * @param seq Image frame sequence + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_camera_trigger_send(mavlink_channel_t chan, uint64_t time_usec, uint32_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_TRIGGER, buf, MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC); +#else + mavlink_camera_trigger_t packet; + packet.time_usec = time_usec; + packet.seq = seq; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_TRIGGER, (const char *)&packet, MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC); +#endif +} + +/** + * @brief Send a camera_trigger message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_camera_trigger_send_struct(mavlink_channel_t chan, const mavlink_camera_trigger_t* camera_trigger) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_camera_trigger_send(chan, camera_trigger->time_usec, camera_trigger->seq); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_TRIGGER, (const char *)camera_trigger, MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC); +#endif +} + +#if MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_camera_trigger_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint32_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_TRIGGER, buf, MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC); +#else + mavlink_camera_trigger_t *packet = (mavlink_camera_trigger_t *)msgbuf; + packet->time_usec = time_usec; + packet->seq = seq; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CAMERA_TRIGGER, (const char *)packet, MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN, MAVLINK_MSG_ID_CAMERA_TRIGGER_CRC); +#endif +} +#endif + +#endif + +// MESSAGE CAMERA_TRIGGER UNPACKING + + +/** + * @brief Get field time_usec from camera_trigger message + * + * @return Timestamp for the image frame in microseconds + */ +static inline uint64_t mavlink_msg_camera_trigger_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field seq from camera_trigger message + * + * @return Image frame sequence + */ +static inline uint32_t mavlink_msg_camera_trigger_get_seq(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 8); +} + +/** + * @brief Decode a camera_trigger message into a struct + * + * @param msg The message to decode + * @param camera_trigger C-struct to decode the message contents into + */ +static inline void mavlink_msg_camera_trigger_decode(const mavlink_message_t* msg, mavlink_camera_trigger_t* camera_trigger) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + camera_trigger->time_usec = mavlink_msg_camera_trigger_get_time_usec(msg); + camera_trigger->seq = mavlink_msg_camera_trigger_get_seq(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN? msg->len : MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN; + memset(camera_trigger, 0, MAVLINK_MSG_ID_CAMERA_TRIGGER_LEN); + memcpy(camera_trigger, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control.h b/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control.h index 3f0987f10a..b6e76f7f7a 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE CHANGE_OPERATOR_CONTROL PACKING #define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL 5 -typedef struct __mavlink_change_operator_control_t -{ - uint8_t target_system; ///< System the GCS requests control for - uint8_t control_request; ///< 0: request control of this MAV, 1: Release control of this MAV - uint8_t version; ///< 0: key as plaintext, 1-255: future, different hashing/encryption variants. The GCS should in general use the safest mode possible initially and then gradually move down the encryption level if it gets a NACK message indicating an encryption mismatch. - char passkey[25]; ///< Password / Key, depending on version plaintext or encrypted. 25 or less characters, NULL terminated. The characters may involve A-Z, a-z, 0-9, and "!?,.-" -} mavlink_change_operator_control_t; +MAVPACKED( +typedef struct __mavlink_change_operator_control_t { + uint8_t target_system; /*< System the GCS requests control for*/ + uint8_t control_request; /*< 0: request control of this MAV, 1: Release control of this MAV*/ + uint8_t version; /*< 0: key as plaintext, 1-255: future, different hashing/encryption variants. The GCS should in general use the safest mode possible initially and then gradually move down the encryption level if it gets a NACK message indicating an encryption mismatch.*/ + char passkey[25]; /*< Password / Key, depending on version plaintext or encrypted. 25 or less characters, NULL terminated. The characters may involve A-Z, a-z, 0-9, and "!?,.-"*/ +}) mavlink_change_operator_control_t; #define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN 28 +#define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN 28 #define MAVLINK_MSG_ID_5_LEN 28 +#define MAVLINK_MSG_ID_5_MIN_LEN 28 #define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC 217 #define MAVLINK_MSG_ID_5_CRC 217 #define MAVLINK_MSG_CHANGE_OPERATOR_CONTROL_FIELD_PASSKEY_LEN 25 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL { \ - "CHANGE_OPERATOR_CONTROL", \ - 4, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_change_operator_control_t, target_system) }, \ + 5, \ + "CHANGE_OPERATOR_CONTROL", \ + 4, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_change_operator_control_t, target_system) }, \ { "control_request", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_change_operator_control_t, control_request) }, \ { "version", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_change_operator_control_t, version) }, \ { "passkey", NULL, MAVLINK_TYPE_CHAR, 25, 3, offsetof(mavlink_change_operator_control_t, passkey) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL { \ + "CHANGE_OPERATOR_CONTROL", \ + 4, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_change_operator_control_t, target_system) }, \ + { "control_request", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_change_operator_control_t, control_request) }, \ + { "version", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_change_operator_control_t, version) }, \ + { "passkey", NULL, MAVLINK_TYPE_CHAR, 25, 3, offsetof(mavlink_change_operator_control_t, passkey) }, \ + } \ +} +#endif /** * @brief Pack a change_operator_control message @@ -42,30 +57,26 @@ typedef struct __mavlink_change_operator_control_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_change_operator_control_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t control_request, uint8_t version, const char *passkey) + uint8_t target_system, uint8_t control_request, uint8_t version, const char *passkey) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, version); - _mav_put_char_array(buf, 3, passkey, 25); + char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, version); + _mav_put_char_array(buf, 3, passkey, 25); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); #else - mavlink_change_operator_control_t packet; - packet.target_system = target_system; - packet.control_request = control_request; - packet.version = version; - mav_array_memcpy(packet.passkey, passkey, sizeof(char)*25); + mavlink_change_operator_control_t packet; + packet.target_system = target_system; + packet.control_request = control_request; + packet.version = version; + mav_array_memcpy(packet.passkey, passkey, sizeof(char)*25); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); } /** @@ -81,31 +92,27 @@ static inline uint16_t mavlink_msg_change_operator_control_pack(uint8_t system_i * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_change_operator_control_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t control_request,uint8_t version,const char *passkey) + mavlink_message_t* msg, + uint8_t target_system,uint8_t control_request,uint8_t version,const char *passkey) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, version); - _mav_put_char_array(buf, 3, passkey, 25); + char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, version); + _mav_put_char_array(buf, 3, passkey, 25); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); #else - mavlink_change_operator_control_t packet; - packet.target_system = target_system; - packet.control_request = control_request; - packet.version = version; - mav_array_memcpy(packet.passkey, passkey, sizeof(char)*25); + mavlink_change_operator_control_t packet; + packet.target_system = target_system; + packet.control_request = control_request; + packet.version = version; + mav_array_memcpy(packet.passkey, passkey, sizeof(char)*25); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); } /** @@ -118,7 +125,7 @@ static inline uint16_t mavlink_msg_change_operator_control_pack_chan(uint8_t sys */ static inline uint16_t mavlink_msg_change_operator_control_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_change_operator_control_t* change_operator_control) { - return mavlink_msg_change_operator_control_pack(system_id, component_id, msg, change_operator_control->target_system, change_operator_control->control_request, change_operator_control->version, change_operator_control->passkey); + return mavlink_msg_change_operator_control_pack(system_id, component_id, msg, change_operator_control->target_system, change_operator_control->control_request, change_operator_control->version, change_operator_control->passkey); } /** @@ -132,7 +139,7 @@ static inline uint16_t mavlink_msg_change_operator_control_encode(uint8_t system */ static inline uint16_t mavlink_msg_change_operator_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_change_operator_control_t* change_operator_control) { - return mavlink_msg_change_operator_control_pack_chan(system_id, component_id, chan, msg, change_operator_control->target_system, change_operator_control->control_request, change_operator_control->version, change_operator_control->passkey); + return mavlink_msg_change_operator_control_pack_chan(system_id, component_id, chan, msg, change_operator_control->target_system, change_operator_control->control_request, change_operator_control->version, change_operator_control->passkey); } /** @@ -149,27 +156,33 @@ static inline uint16_t mavlink_msg_change_operator_control_encode_chan(uint8_t s static inline void mavlink_msg_change_operator_control_send(mavlink_channel_t chan, uint8_t target_system, uint8_t control_request, uint8_t version, const char *passkey) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, version); - _mav_put_char_array(buf, 3, passkey, 25); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); + char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, version); + _mav_put_char_array(buf, 3, passkey, 25); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); + mavlink_change_operator_control_t packet; + packet.target_system = target_system; + packet.control_request = control_request; + packet.version = version; + mav_array_memcpy(packet.passkey, passkey, sizeof(char)*25); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); #endif +} + +/** + * @brief Send a change_operator_control message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_change_operator_control_send_struct(mavlink_channel_t chan, const mavlink_change_operator_control_t* change_operator_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_change_operator_control_send(chan, change_operator_control->target_system, change_operator_control->control_request, change_operator_control->version, change_operator_control->passkey); #else - mavlink_change_operator_control_t packet; - packet.target_system = target_system; - packet.control_request = control_request; - packet.version = version; - mav_array_memcpy(packet.passkey, passkey, sizeof(char)*25); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, (const char *)change_operator_control, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); #endif } @@ -184,27 +197,19 @@ static inline void mavlink_msg_change_operator_control_send(mavlink_channel_t ch static inline void mavlink_msg_change_operator_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t control_request, uint8_t version, const char *passkey) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, version); - _mav_put_char_array(buf, 3, passkey, 25); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, version); + _mav_put_char_array(buf, 3, passkey, 25); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); -#endif -#else - mavlink_change_operator_control_t *packet = (mavlink_change_operator_control_t *)msgbuf; - packet->target_system = target_system; - packet->control_request = control_request; - packet->version = version; - mav_array_memcpy(packet->passkey, passkey, sizeof(char)*25); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, (const char *)packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, (const char *)packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); -#endif + mavlink_change_operator_control_t *packet = (mavlink_change_operator_control_t *)msgbuf; + packet->target_system = target_system; + packet->control_request = control_request; + packet->version = version; + mav_array_memcpy(packet->passkey, passkey, sizeof(char)*25); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL, (const char *)packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_CRC); #endif } #endif @@ -221,7 +226,7 @@ static inline void mavlink_msg_change_operator_control_send_buf(mavlink_message_ */ static inline uint8_t mavlink_msg_change_operator_control_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -231,7 +236,7 @@ static inline uint8_t mavlink_msg_change_operator_control_get_target_system(cons */ static inline uint8_t mavlink_msg_change_operator_control_get_control_request(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -241,7 +246,7 @@ static inline uint8_t mavlink_msg_change_operator_control_get_control_request(co */ static inline uint8_t mavlink_msg_change_operator_control_get_version(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -251,7 +256,7 @@ static inline uint8_t mavlink_msg_change_operator_control_get_version(const mavl */ static inline uint16_t mavlink_msg_change_operator_control_get_passkey(const mavlink_message_t* msg, char *passkey) { - return _MAV_RETURN_char_array(msg, passkey, 25, 3); + return _MAV_RETURN_char_array(msg, passkey, 25, 3); } /** @@ -262,12 +267,14 @@ static inline uint16_t mavlink_msg_change_operator_control_get_passkey(const mav */ static inline void mavlink_msg_change_operator_control_decode(const mavlink_message_t* msg, mavlink_change_operator_control_t* change_operator_control) { -#if MAVLINK_NEED_BYTE_SWAP - change_operator_control->target_system = mavlink_msg_change_operator_control_get_target_system(msg); - change_operator_control->control_request = mavlink_msg_change_operator_control_get_control_request(msg); - change_operator_control->version = mavlink_msg_change_operator_control_get_version(msg); - mavlink_msg_change_operator_control_get_passkey(msg, change_operator_control->passkey); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + change_operator_control->target_system = mavlink_msg_change_operator_control_get_target_system(msg); + change_operator_control->control_request = mavlink_msg_change_operator_control_get_control_request(msg); + change_operator_control->version = mavlink_msg_change_operator_control_get_version(msg); + mavlink_msg_change_operator_control_get_passkey(msg, change_operator_control->passkey); #else - memcpy(change_operator_control, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN? msg->len : MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN; + memset(change_operator_control, 0, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_LEN); + memcpy(change_operator_control, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control_ack.h b/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control_ack.h index 768e7ed5ca..16bcec880b 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control_ack.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_change_operator_control_ack.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE CHANGE_OPERATOR_CONTROL_ACK PACKING #define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK 6 -typedef struct __mavlink_change_operator_control_ack_t -{ - uint8_t gcs_system_id; ///< ID of the GCS this message - uint8_t control_request; ///< 0: request control of this MAV, 1: Release control of this MAV - uint8_t ack; ///< 0: ACK, 1: NACK: Wrong passkey, 2: NACK: Unsupported passkey encryption method, 3: NACK: Already under control -} mavlink_change_operator_control_ack_t; +MAVPACKED( +typedef struct __mavlink_change_operator_control_ack_t { + uint8_t gcs_system_id; /*< ID of the GCS this message */ + uint8_t control_request; /*< 0: request control of this MAV, 1: Release control of this MAV*/ + uint8_t ack; /*< 0: ACK, 1: NACK: Wrong passkey, 2: NACK: Unsupported passkey encryption method, 3: NACK: Already under control*/ +}) mavlink_change_operator_control_ack_t; #define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN 3 +#define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN 3 #define MAVLINK_MSG_ID_6_LEN 3 +#define MAVLINK_MSG_ID_6_MIN_LEN 3 #define MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC 104 #define MAVLINK_MSG_ID_6_CRC 104 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK { \ - "CHANGE_OPERATOR_CONTROL_ACK", \ - 3, \ - { { "gcs_system_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_change_operator_control_ack_t, gcs_system_id) }, \ + 6, \ + "CHANGE_OPERATOR_CONTROL_ACK", \ + 3, \ + { { "gcs_system_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_change_operator_control_ack_t, gcs_system_id) }, \ { "control_request", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_change_operator_control_ack_t, control_request) }, \ { "ack", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_change_operator_control_ack_t, ack) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_CHANGE_OPERATOR_CONTROL_ACK { \ + "CHANGE_OPERATOR_CONTROL_ACK", \ + 3, \ + { { "gcs_system_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_change_operator_control_ack_t, gcs_system_id) }, \ + { "control_request", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_change_operator_control_ack_t, control_request) }, \ + { "ack", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_change_operator_control_ack_t, ack) }, \ + } \ +} +#endif /** * @brief Pack a change_operator_control_ack message @@ -39,30 +53,26 @@ typedef struct __mavlink_change_operator_control_ack_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_change_operator_control_ack_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t gcs_system_id, uint8_t control_request, uint8_t ack) + uint8_t gcs_system_id, uint8_t control_request, uint8_t ack) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN]; - _mav_put_uint8_t(buf, 0, gcs_system_id); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, ack); + char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN]; + _mav_put_uint8_t(buf, 0, gcs_system_id); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, ack); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); #else - mavlink_change_operator_control_ack_t packet; - packet.gcs_system_id = gcs_system_id; - packet.control_request = control_request; - packet.ack = ack; + mavlink_change_operator_control_ack_t packet; + packet.gcs_system_id = gcs_system_id; + packet.control_request = control_request; + packet.ack = ack; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_change_operator_control_ack_pack(uint8_t syst * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_change_operator_control_ack_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t gcs_system_id,uint8_t control_request,uint8_t ack) + mavlink_message_t* msg, + uint8_t gcs_system_id,uint8_t control_request,uint8_t ack) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN]; - _mav_put_uint8_t(buf, 0, gcs_system_id); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, ack); + char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN]; + _mav_put_uint8_t(buf, 0, gcs_system_id); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, ack); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); #else - mavlink_change_operator_control_ack_t packet; - packet.gcs_system_id = gcs_system_id; - packet.control_request = control_request; - packet.ack = ack; + mavlink_change_operator_control_ack_t packet; + packet.gcs_system_id = gcs_system_id; + packet.control_request = control_request; + packet.ack = ack; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_change_operator_control_ack_pack_chan(uint8_t */ static inline uint16_t mavlink_msg_change_operator_control_ack_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_change_operator_control_ack_t* change_operator_control_ack) { - return mavlink_msg_change_operator_control_ack_pack(system_id, component_id, msg, change_operator_control_ack->gcs_system_id, change_operator_control_ack->control_request, change_operator_control_ack->ack); + return mavlink_msg_change_operator_control_ack_pack(system_id, component_id, msg, change_operator_control_ack->gcs_system_id, change_operator_control_ack->control_request, change_operator_control_ack->ack); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_change_operator_control_ack_encode(uint8_t sy */ static inline uint16_t mavlink_msg_change_operator_control_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_change_operator_control_ack_t* change_operator_control_ack) { - return mavlink_msg_change_operator_control_ack_pack_chan(system_id, component_id, chan, msg, change_operator_control_ack->gcs_system_id, change_operator_control_ack->control_request, change_operator_control_ack->ack); + return mavlink_msg_change_operator_control_ack_pack_chan(system_id, component_id, chan, msg, change_operator_control_ack->gcs_system_id, change_operator_control_ack->control_request, change_operator_control_ack->ack); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_change_operator_control_ack_encode_chan(uint8 static inline void mavlink_msg_change_operator_control_ack_send(mavlink_channel_t chan, uint8_t gcs_system_id, uint8_t control_request, uint8_t ack) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN]; - _mav_put_uint8_t(buf, 0, gcs_system_id); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, ack); + char buf[MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN]; + _mav_put_uint8_t(buf, 0, gcs_system_id); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, ack); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); + mavlink_change_operator_control_ack_t packet; + packet.gcs_system_id = gcs_system_id; + packet.control_request = control_request; + packet.ack = ack; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, (const char *)&packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); #endif -#else - mavlink_change_operator_control_ack_t packet; - packet.gcs_system_id = gcs_system_id; - packet.control_request = control_request; - packet.ack = ack; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, (const char *)&packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); +/** + * @brief Send a change_operator_control_ack message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_change_operator_control_ack_send_struct(mavlink_channel_t chan, const mavlink_change_operator_control_ack_t* change_operator_control_ack) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_change_operator_control_ack_send(chan, change_operator_control_ack->gcs_system_id, change_operator_control_ack->control_request, change_operator_control_ack->ack); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, (const char *)&packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, (const char *)change_operator_control_ack, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_change_operator_control_ack_send(mavlink_channel_ static inline void mavlink_msg_change_operator_control_ack_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t gcs_system_id, uint8_t control_request, uint8_t ack) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, gcs_system_id); - _mav_put_uint8_t(buf, 1, control_request); - _mav_put_uint8_t(buf, 2, ack); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, gcs_system_id); + _mav_put_uint8_t(buf, 1, control_request); + _mav_put_uint8_t(buf, 2, ack); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, buf, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); #else - mavlink_change_operator_control_ack_t *packet = (mavlink_change_operator_control_ack_t *)msgbuf; - packet->gcs_system_id = gcs_system_id; - packet->control_request = control_request; - packet->ack = ack; + mavlink_change_operator_control_ack_t *packet = (mavlink_change_operator_control_ack_t *)msgbuf; + packet->gcs_system_id = gcs_system_id; + packet->control_request = control_request; + packet->ack = ack; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, (const char *)packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, (const char *)packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK, (const char *)packet, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_change_operator_control_ack_send_buf(mavlink_mess */ static inline uint8_t mavlink_msg_change_operator_control_ack_get_gcs_system_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_change_operator_control_ack_get_gcs_system_id( */ static inline uint8_t mavlink_msg_change_operator_control_ack_get_control_request(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_change_operator_control_ack_get_control_reques */ static inline uint8_t mavlink_msg_change_operator_control_ack_get_ack(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -247,11 +251,13 @@ static inline uint8_t mavlink_msg_change_operator_control_ack_get_ack(const mavl */ static inline void mavlink_msg_change_operator_control_ack_decode(const mavlink_message_t* msg, mavlink_change_operator_control_ack_t* change_operator_control_ack) { -#if MAVLINK_NEED_BYTE_SWAP - change_operator_control_ack->gcs_system_id = mavlink_msg_change_operator_control_ack_get_gcs_system_id(msg); - change_operator_control_ack->control_request = mavlink_msg_change_operator_control_ack_get_control_request(msg); - change_operator_control_ack->ack = mavlink_msg_change_operator_control_ack_get_ack(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + change_operator_control_ack->gcs_system_id = mavlink_msg_change_operator_control_ack_get_gcs_system_id(msg); + change_operator_control_ack->control_request = mavlink_msg_change_operator_control_ack_get_control_request(msg); + change_operator_control_ack->ack = mavlink_msg_change_operator_control_ack_get_ack(msg); #else - memcpy(change_operator_control_ack, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN? msg->len : MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN; + memset(change_operator_control_ack, 0, MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_LEN); + memcpy(change_operator_control_ack, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_collision.h b/vendor/libraries/mavlink/common/mavlink_msg_collision.h new file mode 100644 index 0000000000..b888c20a24 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_collision.h @@ -0,0 +1,363 @@ +#pragma once +// MESSAGE COLLISION PACKING + +#define MAVLINK_MSG_ID_COLLISION 247 + +MAVPACKED( +typedef struct __mavlink_collision_t { + uint32_t id; /*< Unique identifier, domain based on src field*/ + float time_to_minimum_delta; /*< Estimated time until collision occurs (seconds)*/ + float altitude_minimum_delta; /*< Closest vertical distance in meters between vehicle and object*/ + float horizontal_minimum_delta; /*< Closest horizontal distance in meteres between vehicle and object*/ + uint8_t src; /*< Collision data source*/ + uint8_t action; /*< Action that is being taken to avoid this collision*/ + uint8_t threat_level; /*< How concerned the aircraft is about this collision*/ +}) mavlink_collision_t; + +#define MAVLINK_MSG_ID_COLLISION_LEN 19 +#define MAVLINK_MSG_ID_COLLISION_MIN_LEN 19 +#define MAVLINK_MSG_ID_247_LEN 19 +#define MAVLINK_MSG_ID_247_MIN_LEN 19 + +#define MAVLINK_MSG_ID_COLLISION_CRC 81 +#define MAVLINK_MSG_ID_247_CRC 81 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_COLLISION { \ + 247, \ + "COLLISION", \ + 7, \ + { { "id", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_collision_t, id) }, \ + { "time_to_minimum_delta", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_collision_t, time_to_minimum_delta) }, \ + { "altitude_minimum_delta", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_collision_t, altitude_minimum_delta) }, \ + { "horizontal_minimum_delta", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_collision_t, horizontal_minimum_delta) }, \ + { "src", NULL, MAVLINK_TYPE_UINT8_T, 0, 16, offsetof(mavlink_collision_t, src) }, \ + { "action", NULL, MAVLINK_TYPE_UINT8_T, 0, 17, offsetof(mavlink_collision_t, action) }, \ + { "threat_level", NULL, MAVLINK_TYPE_UINT8_T, 0, 18, offsetof(mavlink_collision_t, threat_level) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_COLLISION { \ + "COLLISION", \ + 7, \ + { { "id", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_collision_t, id) }, \ + { "time_to_minimum_delta", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_collision_t, time_to_minimum_delta) }, \ + { "altitude_minimum_delta", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_collision_t, altitude_minimum_delta) }, \ + { "horizontal_minimum_delta", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_collision_t, horizontal_minimum_delta) }, \ + { "src", NULL, MAVLINK_TYPE_UINT8_T, 0, 16, offsetof(mavlink_collision_t, src) }, \ + { "action", NULL, MAVLINK_TYPE_UINT8_T, 0, 17, offsetof(mavlink_collision_t, action) }, \ + { "threat_level", NULL, MAVLINK_TYPE_UINT8_T, 0, 18, offsetof(mavlink_collision_t, threat_level) }, \ + } \ +} +#endif + +/** + * @brief Pack a collision message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param src Collision data source + * @param id Unique identifier, domain based on src field + * @param action Action that is being taken to avoid this collision + * @param threat_level How concerned the aircraft is about this collision + * @param time_to_minimum_delta Estimated time until collision occurs (seconds) + * @param altitude_minimum_delta Closest vertical distance in meters between vehicle and object + * @param horizontal_minimum_delta Closest horizontal distance in meteres between vehicle and object + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_collision_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t src, uint32_t id, uint8_t action, uint8_t threat_level, float time_to_minimum_delta, float altitude_minimum_delta, float horizontal_minimum_delta) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_COLLISION_LEN]; + _mav_put_uint32_t(buf, 0, id); + _mav_put_float(buf, 4, time_to_minimum_delta); + _mav_put_float(buf, 8, altitude_minimum_delta); + _mav_put_float(buf, 12, horizontal_minimum_delta); + _mav_put_uint8_t(buf, 16, src); + _mav_put_uint8_t(buf, 17, action); + _mav_put_uint8_t(buf, 18, threat_level); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COLLISION_LEN); +#else + mavlink_collision_t packet; + packet.id = id; + packet.time_to_minimum_delta = time_to_minimum_delta; + packet.altitude_minimum_delta = altitude_minimum_delta; + packet.horizontal_minimum_delta = horizontal_minimum_delta; + packet.src = src; + packet.action = action; + packet.threat_level = threat_level; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COLLISION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_COLLISION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COLLISION_MIN_LEN, MAVLINK_MSG_ID_COLLISION_LEN, MAVLINK_MSG_ID_COLLISION_CRC); +} + +/** + * @brief Pack a collision message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param src Collision data source + * @param id Unique identifier, domain based on src field + * @param action Action that is being taken to avoid this collision + * @param threat_level How concerned the aircraft is about this collision + * @param time_to_minimum_delta Estimated time until collision occurs (seconds) + * @param altitude_minimum_delta Closest vertical distance in meters between vehicle and object + * @param horizontal_minimum_delta Closest horizontal distance in meteres between vehicle and object + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_collision_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t src,uint32_t id,uint8_t action,uint8_t threat_level,float time_to_minimum_delta,float altitude_minimum_delta,float horizontal_minimum_delta) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_COLLISION_LEN]; + _mav_put_uint32_t(buf, 0, id); + _mav_put_float(buf, 4, time_to_minimum_delta); + _mav_put_float(buf, 8, altitude_minimum_delta); + _mav_put_float(buf, 12, horizontal_minimum_delta); + _mav_put_uint8_t(buf, 16, src); + _mav_put_uint8_t(buf, 17, action); + _mav_put_uint8_t(buf, 18, threat_level); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COLLISION_LEN); +#else + mavlink_collision_t packet; + packet.id = id; + packet.time_to_minimum_delta = time_to_minimum_delta; + packet.altitude_minimum_delta = altitude_minimum_delta; + packet.horizontal_minimum_delta = horizontal_minimum_delta; + packet.src = src; + packet.action = action; + packet.threat_level = threat_level; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COLLISION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_COLLISION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COLLISION_MIN_LEN, MAVLINK_MSG_ID_COLLISION_LEN, MAVLINK_MSG_ID_COLLISION_CRC); +} + +/** + * @brief Encode a collision struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param collision C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_collision_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_collision_t* collision) +{ + return mavlink_msg_collision_pack(system_id, component_id, msg, collision->src, collision->id, collision->action, collision->threat_level, collision->time_to_minimum_delta, collision->altitude_minimum_delta, collision->horizontal_minimum_delta); +} + +/** + * @brief Encode a collision struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param collision C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_collision_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_collision_t* collision) +{ + return mavlink_msg_collision_pack_chan(system_id, component_id, chan, msg, collision->src, collision->id, collision->action, collision->threat_level, collision->time_to_minimum_delta, collision->altitude_minimum_delta, collision->horizontal_minimum_delta); +} + +/** + * @brief Send a collision message + * @param chan MAVLink channel to send the message + * + * @param src Collision data source + * @param id Unique identifier, domain based on src field + * @param action Action that is being taken to avoid this collision + * @param threat_level How concerned the aircraft is about this collision + * @param time_to_minimum_delta Estimated time until collision occurs (seconds) + * @param altitude_minimum_delta Closest vertical distance in meters between vehicle and object + * @param horizontal_minimum_delta Closest horizontal distance in meteres between vehicle and object + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_collision_send(mavlink_channel_t chan, uint8_t src, uint32_t id, uint8_t action, uint8_t threat_level, float time_to_minimum_delta, float altitude_minimum_delta, float horizontal_minimum_delta) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_COLLISION_LEN]; + _mav_put_uint32_t(buf, 0, id); + _mav_put_float(buf, 4, time_to_minimum_delta); + _mav_put_float(buf, 8, altitude_minimum_delta); + _mav_put_float(buf, 12, horizontal_minimum_delta); + _mav_put_uint8_t(buf, 16, src); + _mav_put_uint8_t(buf, 17, action); + _mav_put_uint8_t(buf, 18, threat_level); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COLLISION, buf, MAVLINK_MSG_ID_COLLISION_MIN_LEN, MAVLINK_MSG_ID_COLLISION_LEN, MAVLINK_MSG_ID_COLLISION_CRC); +#else + mavlink_collision_t packet; + packet.id = id; + packet.time_to_minimum_delta = time_to_minimum_delta; + packet.altitude_minimum_delta = altitude_minimum_delta; + packet.horizontal_minimum_delta = horizontal_minimum_delta; + packet.src = src; + packet.action = action; + packet.threat_level = threat_level; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COLLISION, (const char *)&packet, MAVLINK_MSG_ID_COLLISION_MIN_LEN, MAVLINK_MSG_ID_COLLISION_LEN, MAVLINK_MSG_ID_COLLISION_CRC); +#endif +} + +/** + * @brief Send a collision message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_collision_send_struct(mavlink_channel_t chan, const mavlink_collision_t* collision) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_collision_send(chan, collision->src, collision->id, collision->action, collision->threat_level, collision->time_to_minimum_delta, collision->altitude_minimum_delta, collision->horizontal_minimum_delta); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COLLISION, (const char *)collision, MAVLINK_MSG_ID_COLLISION_MIN_LEN, MAVLINK_MSG_ID_COLLISION_LEN, MAVLINK_MSG_ID_COLLISION_CRC); +#endif +} + +#if MAVLINK_MSG_ID_COLLISION_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_collision_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t src, uint32_t id, uint8_t action, uint8_t threat_level, float time_to_minimum_delta, float altitude_minimum_delta, float horizontal_minimum_delta) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, id); + _mav_put_float(buf, 4, time_to_minimum_delta); + _mav_put_float(buf, 8, altitude_minimum_delta); + _mav_put_float(buf, 12, horizontal_minimum_delta); + _mav_put_uint8_t(buf, 16, src); + _mav_put_uint8_t(buf, 17, action); + _mav_put_uint8_t(buf, 18, threat_level); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COLLISION, buf, MAVLINK_MSG_ID_COLLISION_MIN_LEN, MAVLINK_MSG_ID_COLLISION_LEN, MAVLINK_MSG_ID_COLLISION_CRC); +#else + mavlink_collision_t *packet = (mavlink_collision_t *)msgbuf; + packet->id = id; + packet->time_to_minimum_delta = time_to_minimum_delta; + packet->altitude_minimum_delta = altitude_minimum_delta; + packet->horizontal_minimum_delta = horizontal_minimum_delta; + packet->src = src; + packet->action = action; + packet->threat_level = threat_level; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COLLISION, (const char *)packet, MAVLINK_MSG_ID_COLLISION_MIN_LEN, MAVLINK_MSG_ID_COLLISION_LEN, MAVLINK_MSG_ID_COLLISION_CRC); +#endif +} +#endif + +#endif + +// MESSAGE COLLISION UNPACKING + + +/** + * @brief Get field src from collision message + * + * @return Collision data source + */ +static inline uint8_t mavlink_msg_collision_get_src(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 16); +} + +/** + * @brief Get field id from collision message + * + * @return Unique identifier, domain based on src field + */ +static inline uint32_t mavlink_msg_collision_get_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 0); +} + +/** + * @brief Get field action from collision message + * + * @return Action that is being taken to avoid this collision + */ +static inline uint8_t mavlink_msg_collision_get_action(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 17); +} + +/** + * @brief Get field threat_level from collision message + * + * @return How concerned the aircraft is about this collision + */ +static inline uint8_t mavlink_msg_collision_get_threat_level(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 18); +} + +/** + * @brief Get field time_to_minimum_delta from collision message + * + * @return Estimated time until collision occurs (seconds) + */ +static inline float mavlink_msg_collision_get_time_to_minimum_delta(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Get field altitude_minimum_delta from collision message + * + * @return Closest vertical distance in meters between vehicle and object + */ +static inline float mavlink_msg_collision_get_altitude_minimum_delta(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field horizontal_minimum_delta from collision message + * + * @return Closest horizontal distance in meteres between vehicle and object + */ +static inline float mavlink_msg_collision_get_horizontal_minimum_delta(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Decode a collision message into a struct + * + * @param msg The message to decode + * @param collision C-struct to decode the message contents into + */ +static inline void mavlink_msg_collision_decode(const mavlink_message_t* msg, mavlink_collision_t* collision) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + collision->id = mavlink_msg_collision_get_id(msg); + collision->time_to_minimum_delta = mavlink_msg_collision_get_time_to_minimum_delta(msg); + collision->altitude_minimum_delta = mavlink_msg_collision_get_altitude_minimum_delta(msg); + collision->horizontal_minimum_delta = mavlink_msg_collision_get_horizontal_minimum_delta(msg); + collision->src = mavlink_msg_collision_get_src(msg); + collision->action = mavlink_msg_collision_get_action(msg); + collision->threat_level = mavlink_msg_collision_get_threat_level(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_COLLISION_LEN? msg->len : MAVLINK_MSG_ID_COLLISION_LEN; + memset(collision, 0, MAVLINK_MSG_ID_COLLISION_LEN); + memcpy(collision, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_command_ack.h b/vendor/libraries/mavlink/common/mavlink_msg_command_ack.h index d3d1630419..7ace685119 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_command_ack.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_command_ack.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE COMMAND_ACK PACKING #define MAVLINK_MSG_ID_COMMAND_ACK 77 -typedef struct __mavlink_command_ack_t -{ - uint16_t command; ///< Command ID, as defined by MAV_CMD enum. - uint8_t result; ///< See MAV_RESULT enum -} mavlink_command_ack_t; +MAVPACKED( +typedef struct __mavlink_command_ack_t { + uint16_t command; /*< Command ID, as defined by MAV_CMD enum.*/ + uint8_t result; /*< See MAV_RESULT enum*/ +}) mavlink_command_ack_t; #define MAVLINK_MSG_ID_COMMAND_ACK_LEN 3 +#define MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN 3 #define MAVLINK_MSG_ID_77_LEN 3 +#define MAVLINK_MSG_ID_77_MIN_LEN 3 #define MAVLINK_MSG_ID_COMMAND_ACK_CRC 143 #define MAVLINK_MSG_ID_77_CRC 143 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_COMMAND_ACK { \ - "COMMAND_ACK", \ - 2, \ - { { "command", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_command_ack_t, command) }, \ + 77, \ + "COMMAND_ACK", \ + 2, \ + { { "command", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_command_ack_t, command) }, \ { "result", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_command_ack_t, result) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_COMMAND_ACK { \ + "COMMAND_ACK", \ + 2, \ + { { "command", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_command_ack_t, command) }, \ + { "result", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_command_ack_t, result) }, \ + } \ +} +#endif /** * @brief Pack a command_ack message @@ -36,28 +49,24 @@ typedef struct __mavlink_command_ack_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_command_ack_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t command, uint8_t result) + uint16_t command, uint8_t result) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_ACK_LEN]; - _mav_put_uint16_t(buf, 0, command); - _mav_put_uint8_t(buf, 2, result); + char buf[MAVLINK_MSG_ID_COMMAND_ACK_LEN]; + _mav_put_uint16_t(buf, 0, command); + _mav_put_uint8_t(buf, 2, result); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMMAND_ACK_LEN); #else - mavlink_command_ack_t packet; - packet.command = command; - packet.result = result; + mavlink_command_ack_t packet; + packet.command = command; + packet.result = result; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMMAND_ACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMMAND_ACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_ACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMMAND_ACK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_command_ack_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_command_ack_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t command,uint8_t result) + mavlink_message_t* msg, + uint16_t command,uint8_t result) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_ACK_LEN]; - _mav_put_uint16_t(buf, 0, command); - _mav_put_uint8_t(buf, 2, result); + char buf[MAVLINK_MSG_ID_COMMAND_ACK_LEN]; + _mav_put_uint16_t(buf, 0, command); + _mav_put_uint8_t(buf, 2, result); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMMAND_ACK_LEN); #else - mavlink_command_ack_t packet; - packet.command = command; - packet.result = result; + mavlink_command_ack_t packet; + packet.command = command; + packet.result = result; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMMAND_ACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMMAND_ACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_ACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMMAND_ACK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_command_ack_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_command_ack_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_command_ack_t* command_ack) { - return mavlink_msg_command_ack_pack(system_id, component_id, msg, command_ack->command, command_ack->result); + return mavlink_msg_command_ack_pack(system_id, component_id, msg, command_ack->command, command_ack->result); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_command_ack_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_command_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_command_ack_t* command_ack) { - return mavlink_msg_command_ack_pack_chan(system_id, component_id, chan, msg, command_ack->command, command_ack->result); + return mavlink_msg_command_ack_pack_chan(system_id, component_id, chan, msg, command_ack->command, command_ack->result); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_command_ack_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_command_ack_send(mavlink_channel_t chan, uint16_t command, uint8_t result) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_ACK_LEN]; - _mav_put_uint16_t(buf, 0, command); - _mav_put_uint8_t(buf, 2, result); + char buf[MAVLINK_MSG_ID_COMMAND_ACK_LEN]; + _mav_put_uint16_t(buf, 0, command); + _mav_put_uint8_t(buf, 2, result); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, buf, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, buf, MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, buf, MAVLINK_MSG_ID_COMMAND_ACK_LEN); + mavlink_command_ack_t packet; + packet.command = command; + packet.result = result; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); #endif -#else - mavlink_command_ack_t packet; - packet.command = command; - packet.result = result; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); +/** + * @brief Send a command_ack message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_command_ack_send_struct(mavlink_channel_t chan, const mavlink_command_ack_t* command_ack) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_command_ack_send(chan, command_ack->command, command_ack->result); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, (const char *)command_ack, MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_command_ack_send(mavlink_channel_t chan, uint16_t static inline void mavlink_msg_command_ack_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t command, uint8_t result) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, command); - _mav_put_uint8_t(buf, 2, result); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, command); + _mav_put_uint8_t(buf, 2, result); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, buf, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, buf, MAVLINK_MSG_ID_COMMAND_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, buf, MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); #else - mavlink_command_ack_t *packet = (mavlink_command_ack_t *)msgbuf; - packet->command = command; - packet->result = result; + mavlink_command_ack_t *packet = (mavlink_command_ack_t *)msgbuf; + packet->command = command; + packet->result = result; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, (const char *)packet, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, (const char *)packet, MAVLINK_MSG_ID_COMMAND_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_ACK, (const char *)packet, MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN, MAVLINK_MSG_ID_COMMAND_ACK_LEN, MAVLINK_MSG_ID_COMMAND_ACK_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_command_ack_send_buf(mavlink_message_t *msgbuf, m */ static inline uint16_t mavlink_msg_command_ack_get_command(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint16_t mavlink_msg_command_ack_get_command(const mavlink_message */ static inline uint8_t mavlink_msg_command_ack_get_result(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_command_ack_get_result(const mavlink_message_t */ static inline void mavlink_msg_command_ack_decode(const mavlink_message_t* msg, mavlink_command_ack_t* command_ack) { -#if MAVLINK_NEED_BYTE_SWAP - command_ack->command = mavlink_msg_command_ack_get_command(msg); - command_ack->result = mavlink_msg_command_ack_get_result(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + command_ack->command = mavlink_msg_command_ack_get_command(msg); + command_ack->result = mavlink_msg_command_ack_get_result(msg); #else - memcpy(command_ack, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_COMMAND_ACK_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_COMMAND_ACK_LEN? msg->len : MAVLINK_MSG_ID_COMMAND_ACK_LEN; + memset(command_ack, 0, MAVLINK_MSG_ID_COMMAND_ACK_LEN); + memcpy(command_ack, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_command_int.h b/vendor/libraries/mavlink/common/mavlink_msg_command_int.h index 4713d01e1c..763634642e 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_command_int.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_command_int.h @@ -1,36 +1,41 @@ +#pragma once // MESSAGE COMMAND_INT PACKING #define MAVLINK_MSG_ID_COMMAND_INT 75 -typedef struct __mavlink_command_int_t -{ - float param1; ///< PARAM1, see MAV_CMD enum - float param2; ///< PARAM2, see MAV_CMD enum - float param3; ///< PARAM3, see MAV_CMD enum - float param4; ///< PARAM4, see MAV_CMD enum - int32_t x; ///< PARAM5 / local: x position in meters * 1e4, global: latitude in degrees * 10^7 - int32_t y; ///< PARAM6 / local: y position in meters * 1e4, global: longitude in degrees * 10^7 - float z; ///< PARAM7 / z position: global: altitude in meters (relative or absolute, depending on frame. - uint16_t command; ///< The scheduled action for the mission item. see MAV_CMD in common.xml MAVLink specs - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t frame; ///< The coordinate system of the COMMAND. see MAV_FRAME in mavlink_types.h - uint8_t current; ///< false:0, true:1 - uint8_t autocontinue; ///< autocontinue to next wp -} mavlink_command_int_t; +MAVPACKED( +typedef struct __mavlink_command_int_t { + float param1; /*< PARAM1, see MAV_CMD enum*/ + float param2; /*< PARAM2, see MAV_CMD enum*/ + float param3; /*< PARAM3, see MAV_CMD enum*/ + float param4; /*< PARAM4, see MAV_CMD enum*/ + int32_t x; /*< PARAM5 / local: x position in meters * 1e4, global: latitude in degrees * 10^7*/ + int32_t y; /*< PARAM6 / local: y position in meters * 1e4, global: longitude in degrees * 10^7*/ + float z; /*< PARAM7 / z position: global: altitude in meters (relative or absolute, depending on frame.*/ + uint16_t command; /*< The scheduled action for the mission item. see MAV_CMD in common.xml MAVLink specs*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t frame; /*< The coordinate system of the COMMAND. see MAV_FRAME in mavlink_types.h*/ + uint8_t current; /*< false:0, true:1*/ + uint8_t autocontinue; /*< autocontinue to next wp*/ +}) mavlink_command_int_t; #define MAVLINK_MSG_ID_COMMAND_INT_LEN 35 +#define MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN 35 #define MAVLINK_MSG_ID_75_LEN 35 +#define MAVLINK_MSG_ID_75_MIN_LEN 35 #define MAVLINK_MSG_ID_COMMAND_INT_CRC 158 #define MAVLINK_MSG_ID_75_CRC 158 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_COMMAND_INT { \ - "COMMAND_INT", \ - 13, \ - { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_command_int_t, param1) }, \ + 75, \ + "COMMAND_INT", \ + 13, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_command_int_t, param1) }, \ { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_command_int_t, param2) }, \ { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_command_int_t, param3) }, \ { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_command_int_t, param4) }, \ @@ -45,7 +50,26 @@ typedef struct __mavlink_command_int_t { "autocontinue", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_command_int_t, autocontinue) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_COMMAND_INT { \ + "COMMAND_INT", \ + 13, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_command_int_t, param1) }, \ + { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_command_int_t, param2) }, \ + { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_command_int_t, param3) }, \ + { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_command_int_t, param4) }, \ + { "x", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_command_int_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_command_int_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_command_int_t, z) }, \ + { "command", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_command_int_t, command) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 30, offsetof(mavlink_command_int_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 31, offsetof(mavlink_command_int_t, target_component) }, \ + { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_command_int_t, frame) }, \ + { "current", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_command_int_t, current) }, \ + { "autocontinue", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_command_int_t, autocontinue) }, \ + } \ +} +#endif /** * @brief Pack a command_int message @@ -69,50 +93,46 @@ typedef struct __mavlink_command_int_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_command_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) + uint8_t target_system, uint8_t target_component, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_INT_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, frame); - _mav_put_uint8_t(buf, 33, current); - _mav_put_uint8_t(buf, 34, autocontinue); + char buf[MAVLINK_MSG_ID_COMMAND_INT_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, frame); + _mav_put_uint8_t(buf, 33, current); + _mav_put_uint8_t(buf, 34, autocontinue); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMMAND_INT_LEN); #else - mavlink_command_int_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; + mavlink_command_int_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMMAND_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMMAND_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMMAND_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); } /** @@ -137,51 +157,47 @@ static inline uint16_t mavlink_msg_command_int_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_command_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t frame,uint16_t command,uint8_t current,uint8_t autocontinue,float param1,float param2,float param3,float param4,int32_t x,int32_t y,float z) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t frame,uint16_t command,uint8_t current,uint8_t autocontinue,float param1,float param2,float param3,float param4,int32_t x,int32_t y,float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_INT_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, frame); - _mav_put_uint8_t(buf, 33, current); - _mav_put_uint8_t(buf, 34, autocontinue); + char buf[MAVLINK_MSG_ID_COMMAND_INT_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, frame); + _mav_put_uint8_t(buf, 33, current); + _mav_put_uint8_t(buf, 34, autocontinue); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMMAND_INT_LEN); #else - mavlink_command_int_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; + mavlink_command_int_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMMAND_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMMAND_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMMAND_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); } /** @@ -194,7 +210,7 @@ static inline uint16_t mavlink_msg_command_int_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_command_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_command_int_t* command_int) { - return mavlink_msg_command_int_pack(system_id, component_id, msg, command_int->target_system, command_int->target_component, command_int->frame, command_int->command, command_int->current, command_int->autocontinue, command_int->param1, command_int->param2, command_int->param3, command_int->param4, command_int->x, command_int->y, command_int->z); + return mavlink_msg_command_int_pack(system_id, component_id, msg, command_int->target_system, command_int->target_component, command_int->frame, command_int->command, command_int->current, command_int->autocontinue, command_int->param1, command_int->param2, command_int->param3, command_int->param4, command_int->x, command_int->y, command_int->z); } /** @@ -208,7 +224,7 @@ static inline uint16_t mavlink_msg_command_int_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_command_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_command_int_t* command_int) { - return mavlink_msg_command_int_pack_chan(system_id, component_id, chan, msg, command_int->target_system, command_int->target_component, command_int->frame, command_int->command, command_int->current, command_int->autocontinue, command_int->param1, command_int->param2, command_int->param3, command_int->param4, command_int->x, command_int->y, command_int->z); + return mavlink_msg_command_int_pack_chan(system_id, component_id, chan, msg, command_int->target_system, command_int->target_component, command_int->frame, command_int->command, command_int->current, command_int->autocontinue, command_int->param1, command_int->param2, command_int->param3, command_int->param4, command_int->x, command_int->y, command_int->z); } /** @@ -234,47 +250,53 @@ static inline uint16_t mavlink_msg_command_int_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_command_int_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_INT_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, frame); - _mav_put_uint8_t(buf, 33, current); - _mav_put_uint8_t(buf, 34, autocontinue); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, buf, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); + char buf[MAVLINK_MSG_ID_COMMAND_INT_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, frame); + _mav_put_uint8_t(buf, 33, current); + _mav_put_uint8_t(buf, 34, autocontinue); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, buf, MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, buf, MAVLINK_MSG_ID_COMMAND_INT_LEN); + mavlink_command_int_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); #endif +} + +/** + * @brief Send a command_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_command_int_send_struct(mavlink_channel_t chan, const mavlink_command_int_t* command_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_command_int_send(chan, command_int->target_system, command_int->target_component, command_int->frame, command_int->command, command_int->current, command_int->autocontinue, command_int->param1, command_int->param2, command_int->param3, command_int->param4, command_int->x, command_int->y, command_int->z); #else - mavlink_command_int_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_INT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, (const char *)command_int, MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); #endif } @@ -289,47 +311,39 @@ static inline void mavlink_msg_command_int_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_command_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, frame); - _mav_put_uint8_t(buf, 33, current); - _mav_put_uint8_t(buf, 34, autocontinue); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, buf, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, frame); + _mav_put_uint8_t(buf, 33, current); + _mav_put_uint8_t(buf, 34, autocontinue); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, buf, MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, buf, MAVLINK_MSG_ID_COMMAND_INT_LEN); -#endif -#else - mavlink_command_int_t *packet = (mavlink_command_int_t *)msgbuf; - packet->param1 = param1; - packet->param2 = param2; - packet->param3 = param3; - packet->param4 = param4; - packet->x = x; - packet->y = y; - packet->z = z; - packet->command = command; - packet->target_system = target_system; - packet->target_component = target_component; - packet->frame = frame; - packet->current = current; - packet->autocontinue = autocontinue; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, (const char *)packet, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, (const char *)packet, MAVLINK_MSG_ID_COMMAND_INT_LEN); -#endif + mavlink_command_int_t *packet = (mavlink_command_int_t *)msgbuf; + packet->param1 = param1; + packet->param2 = param2; + packet->param3 = param3; + packet->param4 = param4; + packet->x = x; + packet->y = y; + packet->z = z; + packet->command = command; + packet->target_system = target_system; + packet->target_component = target_component; + packet->frame = frame; + packet->current = current; + packet->autocontinue = autocontinue; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_INT, (const char *)packet, MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN, MAVLINK_MSG_ID_COMMAND_INT_LEN, MAVLINK_MSG_ID_COMMAND_INT_CRC); #endif } #endif @@ -346,7 +360,7 @@ static inline void mavlink_msg_command_int_send_buf(mavlink_message_t *msgbuf, m */ static inline uint8_t mavlink_msg_command_int_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 30); + return _MAV_RETURN_uint8_t(msg, 30); } /** @@ -356,7 +370,7 @@ static inline uint8_t mavlink_msg_command_int_get_target_system(const mavlink_me */ static inline uint8_t mavlink_msg_command_int_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 31); + return _MAV_RETURN_uint8_t(msg, 31); } /** @@ -366,7 +380,7 @@ static inline uint8_t mavlink_msg_command_int_get_target_component(const mavlink */ static inline uint8_t mavlink_msg_command_int_get_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -376,7 +390,7 @@ static inline uint8_t mavlink_msg_command_int_get_frame(const mavlink_message_t* */ static inline uint16_t mavlink_msg_command_int_get_command(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -386,7 +400,7 @@ static inline uint16_t mavlink_msg_command_int_get_command(const mavlink_message */ static inline uint8_t mavlink_msg_command_int_get_current(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 33); + return _MAV_RETURN_uint8_t(msg, 33); } /** @@ -396,7 +410,7 @@ static inline uint8_t mavlink_msg_command_int_get_current(const mavlink_message_ */ static inline uint8_t mavlink_msg_command_int_get_autocontinue(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -406,7 +420,7 @@ static inline uint8_t mavlink_msg_command_int_get_autocontinue(const mavlink_mes */ static inline float mavlink_msg_command_int_get_param1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -416,7 +430,7 @@ static inline float mavlink_msg_command_int_get_param1(const mavlink_message_t* */ static inline float mavlink_msg_command_int_get_param2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -426,7 +440,7 @@ static inline float mavlink_msg_command_int_get_param2(const mavlink_message_t* */ static inline float mavlink_msg_command_int_get_param3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -436,7 +450,7 @@ static inline float mavlink_msg_command_int_get_param3(const mavlink_message_t* */ static inline float mavlink_msg_command_int_get_param4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -446,7 +460,7 @@ static inline float mavlink_msg_command_int_get_param4(const mavlink_message_t* */ static inline int32_t mavlink_msg_command_int_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -456,7 +470,7 @@ static inline int32_t mavlink_msg_command_int_get_x(const mavlink_message_t* msg */ static inline int32_t mavlink_msg_command_int_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 20); + return _MAV_RETURN_int32_t(msg, 20); } /** @@ -466,7 +480,7 @@ static inline int32_t mavlink_msg_command_int_get_y(const mavlink_message_t* msg */ static inline float mavlink_msg_command_int_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -477,21 +491,23 @@ static inline float mavlink_msg_command_int_get_z(const mavlink_message_t* msg) */ static inline void mavlink_msg_command_int_decode(const mavlink_message_t* msg, mavlink_command_int_t* command_int) { -#if MAVLINK_NEED_BYTE_SWAP - command_int->param1 = mavlink_msg_command_int_get_param1(msg); - command_int->param2 = mavlink_msg_command_int_get_param2(msg); - command_int->param3 = mavlink_msg_command_int_get_param3(msg); - command_int->param4 = mavlink_msg_command_int_get_param4(msg); - command_int->x = mavlink_msg_command_int_get_x(msg); - command_int->y = mavlink_msg_command_int_get_y(msg); - command_int->z = mavlink_msg_command_int_get_z(msg); - command_int->command = mavlink_msg_command_int_get_command(msg); - command_int->target_system = mavlink_msg_command_int_get_target_system(msg); - command_int->target_component = mavlink_msg_command_int_get_target_component(msg); - command_int->frame = mavlink_msg_command_int_get_frame(msg); - command_int->current = mavlink_msg_command_int_get_current(msg); - command_int->autocontinue = mavlink_msg_command_int_get_autocontinue(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + command_int->param1 = mavlink_msg_command_int_get_param1(msg); + command_int->param2 = mavlink_msg_command_int_get_param2(msg); + command_int->param3 = mavlink_msg_command_int_get_param3(msg); + command_int->param4 = mavlink_msg_command_int_get_param4(msg); + command_int->x = mavlink_msg_command_int_get_x(msg); + command_int->y = mavlink_msg_command_int_get_y(msg); + command_int->z = mavlink_msg_command_int_get_z(msg); + command_int->command = mavlink_msg_command_int_get_command(msg); + command_int->target_system = mavlink_msg_command_int_get_target_system(msg); + command_int->target_component = mavlink_msg_command_int_get_target_component(msg); + command_int->frame = mavlink_msg_command_int_get_frame(msg); + command_int->current = mavlink_msg_command_int_get_current(msg); + command_int->autocontinue = mavlink_msg_command_int_get_autocontinue(msg); #else - memcpy(command_int, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_COMMAND_INT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_COMMAND_INT_LEN? msg->len : MAVLINK_MSG_ID_COMMAND_INT_LEN; + memset(command_int, 0, MAVLINK_MSG_ID_COMMAND_INT_LEN); + memcpy(command_int, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_command_long.h b/vendor/libraries/mavlink/common/mavlink_msg_command_long.h index 161896b973..f7c62cb352 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_command_long.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_command_long.h @@ -1,34 +1,39 @@ +#pragma once // MESSAGE COMMAND_LONG PACKING #define MAVLINK_MSG_ID_COMMAND_LONG 76 -typedef struct __mavlink_command_long_t -{ - float param1; ///< Parameter 1, as defined by MAV_CMD enum. - float param2; ///< Parameter 2, as defined by MAV_CMD enum. - float param3; ///< Parameter 3, as defined by MAV_CMD enum. - float param4; ///< Parameter 4, as defined by MAV_CMD enum. - float param5; ///< Parameter 5, as defined by MAV_CMD enum. - float param6; ///< Parameter 6, as defined by MAV_CMD enum. - float param7; ///< Parameter 7, as defined by MAV_CMD enum. - uint16_t command; ///< Command ID, as defined by MAV_CMD enum. - uint8_t target_system; ///< System which should execute the command - uint8_t target_component; ///< Component which should execute the command, 0 for all components - uint8_t confirmation; ///< 0: First transmission of this command. 1-255: Confirmation transmissions (e.g. for kill command) -} mavlink_command_long_t; +MAVPACKED( +typedef struct __mavlink_command_long_t { + float param1; /*< Parameter 1, as defined by MAV_CMD enum.*/ + float param2; /*< Parameter 2, as defined by MAV_CMD enum.*/ + float param3; /*< Parameter 3, as defined by MAV_CMD enum.*/ + float param4; /*< Parameter 4, as defined by MAV_CMD enum.*/ + float param5; /*< Parameter 5, as defined by MAV_CMD enum.*/ + float param6; /*< Parameter 6, as defined by MAV_CMD enum.*/ + float param7; /*< Parameter 7, as defined by MAV_CMD enum.*/ + uint16_t command; /*< Command ID, as defined by MAV_CMD enum.*/ + uint8_t target_system; /*< System which should execute the command*/ + uint8_t target_component; /*< Component which should execute the command, 0 for all components*/ + uint8_t confirmation; /*< 0: First transmission of this command. 1-255: Confirmation transmissions (e.g. for kill command)*/ +}) mavlink_command_long_t; #define MAVLINK_MSG_ID_COMMAND_LONG_LEN 33 +#define MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN 33 #define MAVLINK_MSG_ID_76_LEN 33 +#define MAVLINK_MSG_ID_76_MIN_LEN 33 #define MAVLINK_MSG_ID_COMMAND_LONG_CRC 152 #define MAVLINK_MSG_ID_76_CRC 152 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_COMMAND_LONG { \ - "COMMAND_LONG", \ - 11, \ - { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_command_long_t, param1) }, \ + 76, \ + "COMMAND_LONG", \ + 11, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_command_long_t, param1) }, \ { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_command_long_t, param2) }, \ { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_command_long_t, param3) }, \ { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_command_long_t, param4) }, \ @@ -41,7 +46,24 @@ typedef struct __mavlink_command_long_t { "confirmation", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_command_long_t, confirmation) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_COMMAND_LONG { \ + "COMMAND_LONG", \ + 11, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_command_long_t, param1) }, \ + { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_command_long_t, param2) }, \ + { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_command_long_t, param3) }, \ + { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_command_long_t, param4) }, \ + { "param5", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_command_long_t, param5) }, \ + { "param6", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_command_long_t, param6) }, \ + { "param7", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_command_long_t, param7) }, \ + { "command", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_command_long_t, command) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 30, offsetof(mavlink_command_long_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 31, offsetof(mavlink_command_long_t, target_component) }, \ + { "confirmation", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_command_long_t, confirmation) }, \ + } \ +} +#endif /** * @brief Pack a command_long message @@ -63,46 +85,42 @@ typedef struct __mavlink_command_long_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_command_long_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t command, uint8_t confirmation, float param1, float param2, float param3, float param4, float param5, float param6, float param7) + uint8_t target_system, uint8_t target_component, uint16_t command, uint8_t confirmation, float param1, float param2, float param3, float param4, float param5, float param6, float param7) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_LONG_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, param5); - _mav_put_float(buf, 20, param6); - _mav_put_float(buf, 24, param7); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, confirmation); + char buf[MAVLINK_MSG_ID_COMMAND_LONG_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, param5); + _mav_put_float(buf, 20, param6); + _mav_put_float(buf, 24, param7); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, confirmation); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMMAND_LONG_LEN); #else - mavlink_command_long_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.param5 = param5; - packet.param6 = param6; - packet.param7 = param7; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.confirmation = confirmation; + mavlink_command_long_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.param5 = param5; + packet.param6 = param6; + packet.param7 = param7; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.confirmation = confirmation; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMMAND_LONG_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMMAND_LONG; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_LONG_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMMAND_LONG; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); } /** @@ -125,47 +143,43 @@ static inline uint16_t mavlink_msg_command_long_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_command_long_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t command,uint8_t confirmation,float param1,float param2,float param3,float param4,float param5,float param6,float param7) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t command,uint8_t confirmation,float param1,float param2,float param3,float param4,float param5,float param6,float param7) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_LONG_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, param5); - _mav_put_float(buf, 20, param6); - _mav_put_float(buf, 24, param7); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, confirmation); + char buf[MAVLINK_MSG_ID_COMMAND_LONG_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, param5); + _mav_put_float(buf, 20, param6); + _mav_put_float(buf, 24, param7); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, confirmation); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_COMMAND_LONG_LEN); #else - mavlink_command_long_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.param5 = param5; - packet.param6 = param6; - packet.param7 = param7; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.confirmation = confirmation; + mavlink_command_long_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.param5 = param5; + packet.param6 = param6; + packet.param7 = param7; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.confirmation = confirmation; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_COMMAND_LONG_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_COMMAND_LONG; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_LONG_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_COMMAND_LONG; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); } /** @@ -178,7 +192,7 @@ static inline uint16_t mavlink_msg_command_long_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_command_long_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_command_long_t* command_long) { - return mavlink_msg_command_long_pack(system_id, component_id, msg, command_long->target_system, command_long->target_component, command_long->command, command_long->confirmation, command_long->param1, command_long->param2, command_long->param3, command_long->param4, command_long->param5, command_long->param6, command_long->param7); + return mavlink_msg_command_long_pack(system_id, component_id, msg, command_long->target_system, command_long->target_component, command_long->command, command_long->confirmation, command_long->param1, command_long->param2, command_long->param3, command_long->param4, command_long->param5, command_long->param6, command_long->param7); } /** @@ -192,7 +206,7 @@ static inline uint16_t mavlink_msg_command_long_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_command_long_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_command_long_t* command_long) { - return mavlink_msg_command_long_pack_chan(system_id, component_id, chan, msg, command_long->target_system, command_long->target_component, command_long->command, command_long->confirmation, command_long->param1, command_long->param2, command_long->param3, command_long->param4, command_long->param5, command_long->param6, command_long->param7); + return mavlink_msg_command_long_pack_chan(system_id, component_id, chan, msg, command_long->target_system, command_long->target_component, command_long->command, command_long->confirmation, command_long->param1, command_long->param2, command_long->param3, command_long->param4, command_long->param5, command_long->param6, command_long->param7); } /** @@ -216,43 +230,49 @@ static inline uint16_t mavlink_msg_command_long_encode_chan(uint8_t system_id, u static inline void mavlink_msg_command_long_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t command, uint8_t confirmation, float param1, float param2, float param3, float param4, float param5, float param6, float param7) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_COMMAND_LONG_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, param5); - _mav_put_float(buf, 20, param6); - _mav_put_float(buf, 24, param7); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, confirmation); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, buf, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); + char buf[MAVLINK_MSG_ID_COMMAND_LONG_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, param5); + _mav_put_float(buf, 20, param6); + _mav_put_float(buf, 24, param7); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, confirmation); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, buf, MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, buf, MAVLINK_MSG_ID_COMMAND_LONG_LEN); + mavlink_command_long_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.param5 = param5; + packet.param6 = param6; + packet.param7 = param7; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.confirmation = confirmation; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); #endif +} + +/** + * @brief Send a command_long message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_command_long_send_struct(mavlink_channel_t chan, const mavlink_command_long_t* command_long) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_command_long_send(chan, command_long->target_system, command_long->target_component, command_long->command, command_long->confirmation, command_long->param1, command_long->param2, command_long->param3, command_long->param4, command_long->param5, command_long->param6, command_long->param7); #else - mavlink_command_long_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.param5 = param5; - packet.param6 = param6; - packet.param7 = param7; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.confirmation = confirmation; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, (const char *)&packet, MAVLINK_MSG_ID_COMMAND_LONG_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, (const char *)command_long, MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); #endif } @@ -267,43 +287,35 @@ static inline void mavlink_msg_command_long_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_command_long_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t command, uint8_t confirmation, float param1, float param2, float param3, float param4, float param5, float param6, float param7) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, param5); - _mav_put_float(buf, 20, param6); - _mav_put_float(buf, 24, param7); - _mav_put_uint16_t(buf, 28, command); - _mav_put_uint8_t(buf, 30, target_system); - _mav_put_uint8_t(buf, 31, target_component); - _mav_put_uint8_t(buf, 32, confirmation); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, buf, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, param5); + _mav_put_float(buf, 20, param6); + _mav_put_float(buf, 24, param7); + _mav_put_uint16_t(buf, 28, command); + _mav_put_uint8_t(buf, 30, target_system); + _mav_put_uint8_t(buf, 31, target_component); + _mav_put_uint8_t(buf, 32, confirmation); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, buf, MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, buf, MAVLINK_MSG_ID_COMMAND_LONG_LEN); -#endif -#else - mavlink_command_long_t *packet = (mavlink_command_long_t *)msgbuf; - packet->param1 = param1; - packet->param2 = param2; - packet->param3 = param3; - packet->param4 = param4; - packet->param5 = param5; - packet->param6 = param6; - packet->param7 = param7; - packet->command = command; - packet->target_system = target_system; - packet->target_component = target_component; - packet->confirmation = confirmation; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, (const char *)packet, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, (const char *)packet, MAVLINK_MSG_ID_COMMAND_LONG_LEN); -#endif + mavlink_command_long_t *packet = (mavlink_command_long_t *)msgbuf; + packet->param1 = param1; + packet->param2 = param2; + packet->param3 = param3; + packet->param4 = param4; + packet->param5 = param5; + packet->param6 = param6; + packet->param7 = param7; + packet->command = command; + packet->target_system = target_system; + packet->target_component = target_component; + packet->confirmation = confirmation; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_COMMAND_LONG, (const char *)packet, MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN, MAVLINK_MSG_ID_COMMAND_LONG_LEN, MAVLINK_MSG_ID_COMMAND_LONG_CRC); #endif } #endif @@ -320,7 +332,7 @@ static inline void mavlink_msg_command_long_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_command_long_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 30); + return _MAV_RETURN_uint8_t(msg, 30); } /** @@ -330,7 +342,7 @@ static inline uint8_t mavlink_msg_command_long_get_target_system(const mavlink_m */ static inline uint8_t mavlink_msg_command_long_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 31); + return _MAV_RETURN_uint8_t(msg, 31); } /** @@ -340,7 +352,7 @@ static inline uint8_t mavlink_msg_command_long_get_target_component(const mavlin */ static inline uint16_t mavlink_msg_command_long_get_command(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -350,7 +362,7 @@ static inline uint16_t mavlink_msg_command_long_get_command(const mavlink_messag */ static inline uint8_t mavlink_msg_command_long_get_confirmation(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -360,7 +372,7 @@ static inline uint8_t mavlink_msg_command_long_get_confirmation(const mavlink_me */ static inline float mavlink_msg_command_long_get_param1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -370,7 +382,7 @@ static inline float mavlink_msg_command_long_get_param1(const mavlink_message_t* */ static inline float mavlink_msg_command_long_get_param2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -380,7 +392,7 @@ static inline float mavlink_msg_command_long_get_param2(const mavlink_message_t* */ static inline float mavlink_msg_command_long_get_param3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -390,7 +402,7 @@ static inline float mavlink_msg_command_long_get_param3(const mavlink_message_t* */ static inline float mavlink_msg_command_long_get_param4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -400,7 +412,7 @@ static inline float mavlink_msg_command_long_get_param4(const mavlink_message_t* */ static inline float mavlink_msg_command_long_get_param5(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -410,7 +422,7 @@ static inline float mavlink_msg_command_long_get_param5(const mavlink_message_t* */ static inline float mavlink_msg_command_long_get_param6(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -420,7 +432,7 @@ static inline float mavlink_msg_command_long_get_param6(const mavlink_message_t* */ static inline float mavlink_msg_command_long_get_param7(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -431,19 +443,21 @@ static inline float mavlink_msg_command_long_get_param7(const mavlink_message_t* */ static inline void mavlink_msg_command_long_decode(const mavlink_message_t* msg, mavlink_command_long_t* command_long) { -#if MAVLINK_NEED_BYTE_SWAP - command_long->param1 = mavlink_msg_command_long_get_param1(msg); - command_long->param2 = mavlink_msg_command_long_get_param2(msg); - command_long->param3 = mavlink_msg_command_long_get_param3(msg); - command_long->param4 = mavlink_msg_command_long_get_param4(msg); - command_long->param5 = mavlink_msg_command_long_get_param5(msg); - command_long->param6 = mavlink_msg_command_long_get_param6(msg); - command_long->param7 = mavlink_msg_command_long_get_param7(msg); - command_long->command = mavlink_msg_command_long_get_command(msg); - command_long->target_system = mavlink_msg_command_long_get_target_system(msg); - command_long->target_component = mavlink_msg_command_long_get_target_component(msg); - command_long->confirmation = mavlink_msg_command_long_get_confirmation(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + command_long->param1 = mavlink_msg_command_long_get_param1(msg); + command_long->param2 = mavlink_msg_command_long_get_param2(msg); + command_long->param3 = mavlink_msg_command_long_get_param3(msg); + command_long->param4 = mavlink_msg_command_long_get_param4(msg); + command_long->param5 = mavlink_msg_command_long_get_param5(msg); + command_long->param6 = mavlink_msg_command_long_get_param6(msg); + command_long->param7 = mavlink_msg_command_long_get_param7(msg); + command_long->command = mavlink_msg_command_long_get_command(msg); + command_long->target_system = mavlink_msg_command_long_get_target_system(msg); + command_long->target_component = mavlink_msg_command_long_get_target_component(msg); + command_long->confirmation = mavlink_msg_command_long_get_confirmation(msg); #else - memcpy(command_long, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_COMMAND_LONG_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_COMMAND_LONG_LEN? msg->len : MAVLINK_MSG_ID_COMMAND_LONG_LEN; + memset(command_long, 0, MAVLINK_MSG_ID_COMMAND_LONG_LEN); + memcpy(command_long, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_control_system_state.h b/vendor/libraries/mavlink/common/mavlink_msg_control_system_state.h new file mode 100644 index 0000000000..8914b6ae10 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_control_system_state.h @@ -0,0 +1,607 @@ +#pragma once +// MESSAGE CONTROL_SYSTEM_STATE PACKING + +#define MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE 146 + +MAVPACKED( +typedef struct __mavlink_control_system_state_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float x_acc; /*< X acceleration in body frame*/ + float y_acc; /*< Y acceleration in body frame*/ + float z_acc; /*< Z acceleration in body frame*/ + float x_vel; /*< X velocity in body frame*/ + float y_vel; /*< Y velocity in body frame*/ + float z_vel; /*< Z velocity in body frame*/ + float x_pos; /*< X position in local frame*/ + float y_pos; /*< Y position in local frame*/ + float z_pos; /*< Z position in local frame*/ + float airspeed; /*< Airspeed, set to -1 if unknown*/ + float vel_variance[3]; /*< Variance of body velocity estimate*/ + float pos_variance[3]; /*< Variance in local position*/ + float q[4]; /*< The attitude, represented as Quaternion*/ + float roll_rate; /*< Angular rate in roll axis*/ + float pitch_rate; /*< Angular rate in pitch axis*/ + float yaw_rate; /*< Angular rate in yaw axis*/ +}) mavlink_control_system_state_t; + +#define MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN 100 +#define MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN 100 +#define MAVLINK_MSG_ID_146_LEN 100 +#define MAVLINK_MSG_ID_146_MIN_LEN 100 + +#define MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC 103 +#define MAVLINK_MSG_ID_146_CRC 103 + +#define MAVLINK_MSG_CONTROL_SYSTEM_STATE_FIELD_VEL_VARIANCE_LEN 3 +#define MAVLINK_MSG_CONTROL_SYSTEM_STATE_FIELD_POS_VARIANCE_LEN 3 +#define MAVLINK_MSG_CONTROL_SYSTEM_STATE_FIELD_Q_LEN 4 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_CONTROL_SYSTEM_STATE { \ + 146, \ + "CONTROL_SYSTEM_STATE", \ + 17, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_control_system_state_t, time_usec) }, \ + { "x_acc", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_control_system_state_t, x_acc) }, \ + { "y_acc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_control_system_state_t, y_acc) }, \ + { "z_acc", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_control_system_state_t, z_acc) }, \ + { "x_vel", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_control_system_state_t, x_vel) }, \ + { "y_vel", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_control_system_state_t, y_vel) }, \ + { "z_vel", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_control_system_state_t, z_vel) }, \ + { "x_pos", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_control_system_state_t, x_pos) }, \ + { "y_pos", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_control_system_state_t, y_pos) }, \ + { "z_pos", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_control_system_state_t, z_pos) }, \ + { "airspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_control_system_state_t, airspeed) }, \ + { "vel_variance", NULL, MAVLINK_TYPE_FLOAT, 3, 48, offsetof(mavlink_control_system_state_t, vel_variance) }, \ + { "pos_variance", NULL, MAVLINK_TYPE_FLOAT, 3, 60, offsetof(mavlink_control_system_state_t, pos_variance) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 72, offsetof(mavlink_control_system_state_t, q) }, \ + { "roll_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 88, offsetof(mavlink_control_system_state_t, roll_rate) }, \ + { "pitch_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 92, offsetof(mavlink_control_system_state_t, pitch_rate) }, \ + { "yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 96, offsetof(mavlink_control_system_state_t, yaw_rate) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_CONTROL_SYSTEM_STATE { \ + "CONTROL_SYSTEM_STATE", \ + 17, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_control_system_state_t, time_usec) }, \ + { "x_acc", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_control_system_state_t, x_acc) }, \ + { "y_acc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_control_system_state_t, y_acc) }, \ + { "z_acc", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_control_system_state_t, z_acc) }, \ + { "x_vel", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_control_system_state_t, x_vel) }, \ + { "y_vel", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_control_system_state_t, y_vel) }, \ + { "z_vel", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_control_system_state_t, z_vel) }, \ + { "x_pos", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_control_system_state_t, x_pos) }, \ + { "y_pos", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_control_system_state_t, y_pos) }, \ + { "z_pos", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_control_system_state_t, z_pos) }, \ + { "airspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_control_system_state_t, airspeed) }, \ + { "vel_variance", NULL, MAVLINK_TYPE_FLOAT, 3, 48, offsetof(mavlink_control_system_state_t, vel_variance) }, \ + { "pos_variance", NULL, MAVLINK_TYPE_FLOAT, 3, 60, offsetof(mavlink_control_system_state_t, pos_variance) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 72, offsetof(mavlink_control_system_state_t, q) }, \ + { "roll_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 88, offsetof(mavlink_control_system_state_t, roll_rate) }, \ + { "pitch_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 92, offsetof(mavlink_control_system_state_t, pitch_rate) }, \ + { "yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 96, offsetof(mavlink_control_system_state_t, yaw_rate) }, \ + } \ +} +#endif + +/** + * @brief Pack a control_system_state message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param x_acc X acceleration in body frame + * @param y_acc Y acceleration in body frame + * @param z_acc Z acceleration in body frame + * @param x_vel X velocity in body frame + * @param y_vel Y velocity in body frame + * @param z_vel Z velocity in body frame + * @param x_pos X position in local frame + * @param y_pos Y position in local frame + * @param z_pos Z position in local frame + * @param airspeed Airspeed, set to -1 if unknown + * @param vel_variance Variance of body velocity estimate + * @param pos_variance Variance in local position + * @param q The attitude, represented as Quaternion + * @param roll_rate Angular rate in roll axis + * @param pitch_rate Angular rate in pitch axis + * @param yaw_rate Angular rate in yaw axis + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_control_system_state_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, float x_acc, float y_acc, float z_acc, float x_vel, float y_vel, float z_vel, float x_pos, float y_pos, float z_pos, float airspeed, const float *vel_variance, const float *pos_variance, const float *q, float roll_rate, float pitch_rate, float yaw_rate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x_acc); + _mav_put_float(buf, 12, y_acc); + _mav_put_float(buf, 16, z_acc); + _mav_put_float(buf, 20, x_vel); + _mav_put_float(buf, 24, y_vel); + _mav_put_float(buf, 28, z_vel); + _mav_put_float(buf, 32, x_pos); + _mav_put_float(buf, 36, y_pos); + _mav_put_float(buf, 40, z_pos); + _mav_put_float(buf, 44, airspeed); + _mav_put_float(buf, 88, roll_rate); + _mav_put_float(buf, 92, pitch_rate); + _mav_put_float(buf, 96, yaw_rate); + _mav_put_float_array(buf, 48, vel_variance, 3); + _mav_put_float_array(buf, 60, pos_variance, 3); + _mav_put_float_array(buf, 72, q, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN); +#else + mavlink_control_system_state_t packet; + packet.time_usec = time_usec; + packet.x_acc = x_acc; + packet.y_acc = y_acc; + packet.z_acc = z_acc; + packet.x_vel = x_vel; + packet.y_vel = y_vel; + packet.z_vel = z_vel; + packet.x_pos = x_pos; + packet.y_pos = y_pos; + packet.z_pos = z_pos; + packet.airspeed = airspeed; + packet.roll_rate = roll_rate; + packet.pitch_rate = pitch_rate; + packet.yaw_rate = yaw_rate; + mav_array_memcpy(packet.vel_variance, vel_variance, sizeof(float)*3); + mav_array_memcpy(packet.pos_variance, pos_variance, sizeof(float)*3); + mav_array_memcpy(packet.q, q, sizeof(float)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC); +} + +/** + * @brief Pack a control_system_state message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param x_acc X acceleration in body frame + * @param y_acc Y acceleration in body frame + * @param z_acc Z acceleration in body frame + * @param x_vel X velocity in body frame + * @param y_vel Y velocity in body frame + * @param z_vel Z velocity in body frame + * @param x_pos X position in local frame + * @param y_pos Y position in local frame + * @param z_pos Z position in local frame + * @param airspeed Airspeed, set to -1 if unknown + * @param vel_variance Variance of body velocity estimate + * @param pos_variance Variance in local position + * @param q The attitude, represented as Quaternion + * @param roll_rate Angular rate in roll axis + * @param pitch_rate Angular rate in pitch axis + * @param yaw_rate Angular rate in yaw axis + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_control_system_state_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,float x_acc,float y_acc,float z_acc,float x_vel,float y_vel,float z_vel,float x_pos,float y_pos,float z_pos,float airspeed,const float *vel_variance,const float *pos_variance,const float *q,float roll_rate,float pitch_rate,float yaw_rate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x_acc); + _mav_put_float(buf, 12, y_acc); + _mav_put_float(buf, 16, z_acc); + _mav_put_float(buf, 20, x_vel); + _mav_put_float(buf, 24, y_vel); + _mav_put_float(buf, 28, z_vel); + _mav_put_float(buf, 32, x_pos); + _mav_put_float(buf, 36, y_pos); + _mav_put_float(buf, 40, z_pos); + _mav_put_float(buf, 44, airspeed); + _mav_put_float(buf, 88, roll_rate); + _mav_put_float(buf, 92, pitch_rate); + _mav_put_float(buf, 96, yaw_rate); + _mav_put_float_array(buf, 48, vel_variance, 3); + _mav_put_float_array(buf, 60, pos_variance, 3); + _mav_put_float_array(buf, 72, q, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN); +#else + mavlink_control_system_state_t packet; + packet.time_usec = time_usec; + packet.x_acc = x_acc; + packet.y_acc = y_acc; + packet.z_acc = z_acc; + packet.x_vel = x_vel; + packet.y_vel = y_vel; + packet.z_vel = z_vel; + packet.x_pos = x_pos; + packet.y_pos = y_pos; + packet.z_pos = z_pos; + packet.airspeed = airspeed; + packet.roll_rate = roll_rate; + packet.pitch_rate = pitch_rate; + packet.yaw_rate = yaw_rate; + mav_array_memcpy(packet.vel_variance, vel_variance, sizeof(float)*3); + mav_array_memcpy(packet.pos_variance, pos_variance, sizeof(float)*3); + mav_array_memcpy(packet.q, q, sizeof(float)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC); +} + +/** + * @brief Encode a control_system_state struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param control_system_state C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_control_system_state_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_control_system_state_t* control_system_state) +{ + return mavlink_msg_control_system_state_pack(system_id, component_id, msg, control_system_state->time_usec, control_system_state->x_acc, control_system_state->y_acc, control_system_state->z_acc, control_system_state->x_vel, control_system_state->y_vel, control_system_state->z_vel, control_system_state->x_pos, control_system_state->y_pos, control_system_state->z_pos, control_system_state->airspeed, control_system_state->vel_variance, control_system_state->pos_variance, control_system_state->q, control_system_state->roll_rate, control_system_state->pitch_rate, control_system_state->yaw_rate); +} + +/** + * @brief Encode a control_system_state struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param control_system_state C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_control_system_state_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_control_system_state_t* control_system_state) +{ + return mavlink_msg_control_system_state_pack_chan(system_id, component_id, chan, msg, control_system_state->time_usec, control_system_state->x_acc, control_system_state->y_acc, control_system_state->z_acc, control_system_state->x_vel, control_system_state->y_vel, control_system_state->z_vel, control_system_state->x_pos, control_system_state->y_pos, control_system_state->z_pos, control_system_state->airspeed, control_system_state->vel_variance, control_system_state->pos_variance, control_system_state->q, control_system_state->roll_rate, control_system_state->pitch_rate, control_system_state->yaw_rate); +} + +/** + * @brief Send a control_system_state message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param x_acc X acceleration in body frame + * @param y_acc Y acceleration in body frame + * @param z_acc Z acceleration in body frame + * @param x_vel X velocity in body frame + * @param y_vel Y velocity in body frame + * @param z_vel Z velocity in body frame + * @param x_pos X position in local frame + * @param y_pos Y position in local frame + * @param z_pos Z position in local frame + * @param airspeed Airspeed, set to -1 if unknown + * @param vel_variance Variance of body velocity estimate + * @param pos_variance Variance in local position + * @param q The attitude, represented as Quaternion + * @param roll_rate Angular rate in roll axis + * @param pitch_rate Angular rate in pitch axis + * @param yaw_rate Angular rate in yaw axis + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_control_system_state_send(mavlink_channel_t chan, uint64_t time_usec, float x_acc, float y_acc, float z_acc, float x_vel, float y_vel, float z_vel, float x_pos, float y_pos, float z_pos, float airspeed, const float *vel_variance, const float *pos_variance, const float *q, float roll_rate, float pitch_rate, float yaw_rate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x_acc); + _mav_put_float(buf, 12, y_acc); + _mav_put_float(buf, 16, z_acc); + _mav_put_float(buf, 20, x_vel); + _mav_put_float(buf, 24, y_vel); + _mav_put_float(buf, 28, z_vel); + _mav_put_float(buf, 32, x_pos); + _mav_put_float(buf, 36, y_pos); + _mav_put_float(buf, 40, z_pos); + _mav_put_float(buf, 44, airspeed); + _mav_put_float(buf, 88, roll_rate); + _mav_put_float(buf, 92, pitch_rate); + _mav_put_float(buf, 96, yaw_rate); + _mav_put_float_array(buf, 48, vel_variance, 3); + _mav_put_float_array(buf, 60, pos_variance, 3); + _mav_put_float_array(buf, 72, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE, buf, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC); +#else + mavlink_control_system_state_t packet; + packet.time_usec = time_usec; + packet.x_acc = x_acc; + packet.y_acc = y_acc; + packet.z_acc = z_acc; + packet.x_vel = x_vel; + packet.y_vel = y_vel; + packet.z_vel = z_vel; + packet.x_pos = x_pos; + packet.y_pos = y_pos; + packet.z_pos = z_pos; + packet.airspeed = airspeed; + packet.roll_rate = roll_rate; + packet.pitch_rate = pitch_rate; + packet.yaw_rate = yaw_rate; + mav_array_memcpy(packet.vel_variance, vel_variance, sizeof(float)*3); + mav_array_memcpy(packet.pos_variance, pos_variance, sizeof(float)*3); + mav_array_memcpy(packet.q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE, (const char *)&packet, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC); +#endif +} + +/** + * @brief Send a control_system_state message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_control_system_state_send_struct(mavlink_channel_t chan, const mavlink_control_system_state_t* control_system_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_control_system_state_send(chan, control_system_state->time_usec, control_system_state->x_acc, control_system_state->y_acc, control_system_state->z_acc, control_system_state->x_vel, control_system_state->y_vel, control_system_state->z_vel, control_system_state->x_pos, control_system_state->y_pos, control_system_state->z_pos, control_system_state->airspeed, control_system_state->vel_variance, control_system_state->pos_variance, control_system_state->q, control_system_state->roll_rate, control_system_state->pitch_rate, control_system_state->yaw_rate); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE, (const char *)control_system_state, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC); +#endif +} + +#if MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_control_system_state_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float x_acc, float y_acc, float z_acc, float x_vel, float y_vel, float z_vel, float x_pos, float y_pos, float z_pos, float airspeed, const float *vel_variance, const float *pos_variance, const float *q, float roll_rate, float pitch_rate, float yaw_rate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x_acc); + _mav_put_float(buf, 12, y_acc); + _mav_put_float(buf, 16, z_acc); + _mav_put_float(buf, 20, x_vel); + _mav_put_float(buf, 24, y_vel); + _mav_put_float(buf, 28, z_vel); + _mav_put_float(buf, 32, x_pos); + _mav_put_float(buf, 36, y_pos); + _mav_put_float(buf, 40, z_pos); + _mav_put_float(buf, 44, airspeed); + _mav_put_float(buf, 88, roll_rate); + _mav_put_float(buf, 92, pitch_rate); + _mav_put_float(buf, 96, yaw_rate); + _mav_put_float_array(buf, 48, vel_variance, 3); + _mav_put_float_array(buf, 60, pos_variance, 3); + _mav_put_float_array(buf, 72, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE, buf, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC); +#else + mavlink_control_system_state_t *packet = (mavlink_control_system_state_t *)msgbuf; + packet->time_usec = time_usec; + packet->x_acc = x_acc; + packet->y_acc = y_acc; + packet->z_acc = z_acc; + packet->x_vel = x_vel; + packet->y_vel = y_vel; + packet->z_vel = z_vel; + packet->x_pos = x_pos; + packet->y_pos = y_pos; + packet->z_pos = z_pos; + packet->airspeed = airspeed; + packet->roll_rate = roll_rate; + packet->pitch_rate = pitch_rate; + packet->yaw_rate = yaw_rate; + mav_array_memcpy(packet->vel_variance, vel_variance, sizeof(float)*3); + mav_array_memcpy(packet->pos_variance, pos_variance, sizeof(float)*3); + mav_array_memcpy(packet->q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE, (const char *)packet, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_CRC); +#endif +} +#endif + +#endif + +// MESSAGE CONTROL_SYSTEM_STATE UNPACKING + + +/** + * @brief Get field time_usec from control_system_state message + * + * @return Timestamp (micros since boot or Unix epoch) + */ +static inline uint64_t mavlink_msg_control_system_state_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field x_acc from control_system_state message + * + * @return X acceleration in body frame + */ +static inline float mavlink_msg_control_system_state_get_x_acc(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field y_acc from control_system_state message + * + * @return Y acceleration in body frame + */ +static inline float mavlink_msg_control_system_state_get_y_acc(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field z_acc from control_system_state message + * + * @return Z acceleration in body frame + */ +static inline float mavlink_msg_control_system_state_get_z_acc(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field x_vel from control_system_state message + * + * @return X velocity in body frame + */ +static inline float mavlink_msg_control_system_state_get_x_vel(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field y_vel from control_system_state message + * + * @return Y velocity in body frame + */ +static inline float mavlink_msg_control_system_state_get_y_vel(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field z_vel from control_system_state message + * + * @return Z velocity in body frame + */ +static inline float mavlink_msg_control_system_state_get_z_vel(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Get field x_pos from control_system_state message + * + * @return X position in local frame + */ +static inline float mavlink_msg_control_system_state_get_x_pos(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 32); +} + +/** + * @brief Get field y_pos from control_system_state message + * + * @return Y position in local frame + */ +static inline float mavlink_msg_control_system_state_get_y_pos(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 36); +} + +/** + * @brief Get field z_pos from control_system_state message + * + * @return Z position in local frame + */ +static inline float mavlink_msg_control_system_state_get_z_pos(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 40); +} + +/** + * @brief Get field airspeed from control_system_state message + * + * @return Airspeed, set to -1 if unknown + */ +static inline float mavlink_msg_control_system_state_get_airspeed(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 44); +} + +/** + * @brief Get field vel_variance from control_system_state message + * + * @return Variance of body velocity estimate + */ +static inline uint16_t mavlink_msg_control_system_state_get_vel_variance(const mavlink_message_t* msg, float *vel_variance) +{ + return _MAV_RETURN_float_array(msg, vel_variance, 3, 48); +} + +/** + * @brief Get field pos_variance from control_system_state message + * + * @return Variance in local position + */ +static inline uint16_t mavlink_msg_control_system_state_get_pos_variance(const mavlink_message_t* msg, float *pos_variance) +{ + return _MAV_RETURN_float_array(msg, pos_variance, 3, 60); +} + +/** + * @brief Get field q from control_system_state message + * + * @return The attitude, represented as Quaternion + */ +static inline uint16_t mavlink_msg_control_system_state_get_q(const mavlink_message_t* msg, float *q) +{ + return _MAV_RETURN_float_array(msg, q, 4, 72); +} + +/** + * @brief Get field roll_rate from control_system_state message + * + * @return Angular rate in roll axis + */ +static inline float mavlink_msg_control_system_state_get_roll_rate(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 88); +} + +/** + * @brief Get field pitch_rate from control_system_state message + * + * @return Angular rate in pitch axis + */ +static inline float mavlink_msg_control_system_state_get_pitch_rate(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 92); +} + +/** + * @brief Get field yaw_rate from control_system_state message + * + * @return Angular rate in yaw axis + */ +static inline float mavlink_msg_control_system_state_get_yaw_rate(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 96); +} + +/** + * @brief Decode a control_system_state message into a struct + * + * @param msg The message to decode + * @param control_system_state C-struct to decode the message contents into + */ +static inline void mavlink_msg_control_system_state_decode(const mavlink_message_t* msg, mavlink_control_system_state_t* control_system_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + control_system_state->time_usec = mavlink_msg_control_system_state_get_time_usec(msg); + control_system_state->x_acc = mavlink_msg_control_system_state_get_x_acc(msg); + control_system_state->y_acc = mavlink_msg_control_system_state_get_y_acc(msg); + control_system_state->z_acc = mavlink_msg_control_system_state_get_z_acc(msg); + control_system_state->x_vel = mavlink_msg_control_system_state_get_x_vel(msg); + control_system_state->y_vel = mavlink_msg_control_system_state_get_y_vel(msg); + control_system_state->z_vel = mavlink_msg_control_system_state_get_z_vel(msg); + control_system_state->x_pos = mavlink_msg_control_system_state_get_x_pos(msg); + control_system_state->y_pos = mavlink_msg_control_system_state_get_y_pos(msg); + control_system_state->z_pos = mavlink_msg_control_system_state_get_z_pos(msg); + control_system_state->airspeed = mavlink_msg_control_system_state_get_airspeed(msg); + mavlink_msg_control_system_state_get_vel_variance(msg, control_system_state->vel_variance); + mavlink_msg_control_system_state_get_pos_variance(msg, control_system_state->pos_variance); + mavlink_msg_control_system_state_get_q(msg, control_system_state->q); + control_system_state->roll_rate = mavlink_msg_control_system_state_get_roll_rate(msg); + control_system_state->pitch_rate = mavlink_msg_control_system_state_get_pitch_rate(msg); + control_system_state->yaw_rate = mavlink_msg_control_system_state_get_yaw_rate(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN? msg->len : MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN; + memset(control_system_state, 0, MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_LEN); + memcpy(control_system_state, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_data_stream.h b/vendor/libraries/mavlink/common/mavlink_msg_data_stream.h index 640ffebf44..cceca20fae 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_data_stream.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_data_stream.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE DATA_STREAM PACKING #define MAVLINK_MSG_ID_DATA_STREAM 67 -typedef struct __mavlink_data_stream_t -{ - uint16_t message_rate; ///< The requested interval between two messages of this type - uint8_t stream_id; ///< The ID of the requested data stream - uint8_t on_off; ///< 1 stream is enabled, 0 stream is stopped. -} mavlink_data_stream_t; +MAVPACKED( +typedef struct __mavlink_data_stream_t { + uint16_t message_rate; /*< The message rate*/ + uint8_t stream_id; /*< The ID of the requested data stream*/ + uint8_t on_off; /*< 1 stream is enabled, 0 stream is stopped.*/ +}) mavlink_data_stream_t; #define MAVLINK_MSG_ID_DATA_STREAM_LEN 4 +#define MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN 4 #define MAVLINK_MSG_ID_67_LEN 4 +#define MAVLINK_MSG_ID_67_MIN_LEN 4 #define MAVLINK_MSG_ID_DATA_STREAM_CRC 21 #define MAVLINK_MSG_ID_67_CRC 21 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DATA_STREAM { \ - "DATA_STREAM", \ - 3, \ - { { "message_rate", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_data_stream_t, message_rate) }, \ + 67, \ + "DATA_STREAM", \ + 3, \ + { { "message_rate", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_data_stream_t, message_rate) }, \ { "stream_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_data_stream_t, stream_id) }, \ { "on_off", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_data_stream_t, on_off) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DATA_STREAM { \ + "DATA_STREAM", \ + 3, \ + { { "message_rate", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_data_stream_t, message_rate) }, \ + { "stream_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_data_stream_t, stream_id) }, \ + { "on_off", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_data_stream_t, on_off) }, \ + } \ +} +#endif /** * @brief Pack a data_stream message @@ -34,35 +48,31 @@ typedef struct __mavlink_data_stream_t * @param msg The MAVLink message to compress the data into * * @param stream_id The ID of the requested data stream - * @param message_rate The requested interval between two messages of this type + * @param message_rate The message rate * @param on_off 1 stream is enabled, 0 stream is stopped. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data_stream_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t stream_id, uint16_t message_rate, uint8_t on_off) + uint8_t stream_id, uint16_t message_rate, uint8_t on_off) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA_STREAM_LEN]; - _mav_put_uint16_t(buf, 0, message_rate); - _mav_put_uint8_t(buf, 2, stream_id); - _mav_put_uint8_t(buf, 3, on_off); + char buf[MAVLINK_MSG_ID_DATA_STREAM_LEN]; + _mav_put_uint16_t(buf, 0, message_rate); + _mav_put_uint8_t(buf, 2, stream_id); + _mav_put_uint8_t(buf, 3, on_off); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA_STREAM_LEN); #else - mavlink_data_stream_t packet; - packet.message_rate = message_rate; - packet.stream_id = stream_id; - packet.on_off = on_off; + mavlink_data_stream_t packet; + packet.message_rate = message_rate; + packet.stream_id = stream_id; + packet.on_off = on_off; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA_STREAM_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA_STREAM; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA_STREAM_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA_STREAM; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); } /** @@ -72,36 +82,32 @@ static inline uint16_t mavlink_msg_data_stream_pack(uint8_t system_id, uint8_t c * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param stream_id The ID of the requested data stream - * @param message_rate The requested interval between two messages of this type + * @param message_rate The message rate * @param on_off 1 stream is enabled, 0 stream is stopped. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data_stream_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t stream_id,uint16_t message_rate,uint8_t on_off) + mavlink_message_t* msg, + uint8_t stream_id,uint16_t message_rate,uint8_t on_off) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA_STREAM_LEN]; - _mav_put_uint16_t(buf, 0, message_rate); - _mav_put_uint8_t(buf, 2, stream_id); - _mav_put_uint8_t(buf, 3, on_off); + char buf[MAVLINK_MSG_ID_DATA_STREAM_LEN]; + _mav_put_uint16_t(buf, 0, message_rate); + _mav_put_uint8_t(buf, 2, stream_id); + _mav_put_uint8_t(buf, 3, on_off); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA_STREAM_LEN); #else - mavlink_data_stream_t packet; - packet.message_rate = message_rate; - packet.stream_id = stream_id; - packet.on_off = on_off; + mavlink_data_stream_t packet; + packet.message_rate = message_rate; + packet.stream_id = stream_id; + packet.on_off = on_off; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA_STREAM_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA_STREAM; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA_STREAM_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA_STREAM; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_data_stream_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_data_stream_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_data_stream_t* data_stream) { - return mavlink_msg_data_stream_pack(system_id, component_id, msg, data_stream->stream_id, data_stream->message_rate, data_stream->on_off); + return mavlink_msg_data_stream_pack(system_id, component_id, msg, data_stream->stream_id, data_stream->message_rate, data_stream->on_off); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_data_stream_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_data_stream_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data_stream_t* data_stream) { - return mavlink_msg_data_stream_pack_chan(system_id, component_id, chan, msg, data_stream->stream_id, data_stream->message_rate, data_stream->on_off); + return mavlink_msg_data_stream_pack_chan(system_id, component_id, chan, msg, data_stream->stream_id, data_stream->message_rate, data_stream->on_off); } /** @@ -136,7 +142,7 @@ static inline uint16_t mavlink_msg_data_stream_encode_chan(uint8_t system_id, ui * @param chan MAVLink channel to send the message * * @param stream_id The ID of the requested data stream - * @param message_rate The requested interval between two messages of this type + * @param message_rate The message rate * @param on_off 1 stream is enabled, 0 stream is stopped. */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_data_stream_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_data_stream_send(mavlink_channel_t chan, uint8_t stream_id, uint16_t message_rate, uint8_t on_off) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA_STREAM_LEN]; - _mav_put_uint16_t(buf, 0, message_rate); - _mav_put_uint8_t(buf, 2, stream_id); - _mav_put_uint8_t(buf, 3, on_off); + char buf[MAVLINK_MSG_ID_DATA_STREAM_LEN]; + _mav_put_uint16_t(buf, 0, message_rate); + _mav_put_uint8_t(buf, 2, stream_id); + _mav_put_uint8_t(buf, 3, on_off); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, buf, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, buf, MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, buf, MAVLINK_MSG_ID_DATA_STREAM_LEN); + mavlink_data_stream_t packet; + packet.message_rate = message_rate; + packet.stream_id = stream_id; + packet.on_off = on_off; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, (const char *)&packet, MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); #endif -#else - mavlink_data_stream_t packet; - packet.message_rate = message_rate; - packet.stream_id = stream_id; - packet.on_off = on_off; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, (const char *)&packet, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); +/** + * @brief Send a data_stream message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_data_stream_send_struct(mavlink_channel_t chan, const mavlink_data_stream_t* data_stream) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_data_stream_send(chan, data_stream->stream_id, data_stream->message_rate, data_stream->on_off); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, (const char *)&packet, MAVLINK_MSG_ID_DATA_STREAM_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, (const char *)data_stream, MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_data_stream_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_data_stream_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t stream_id, uint16_t message_rate, uint8_t on_off) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, message_rate); - _mav_put_uint8_t(buf, 2, stream_id); - _mav_put_uint8_t(buf, 3, on_off); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, message_rate); + _mav_put_uint8_t(buf, 2, stream_id); + _mav_put_uint8_t(buf, 3, on_off); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, buf, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, buf, MAVLINK_MSG_ID_DATA_STREAM_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, buf, MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); #else - mavlink_data_stream_t *packet = (mavlink_data_stream_t *)msgbuf; - packet->message_rate = message_rate; - packet->stream_id = stream_id; - packet->on_off = on_off; + mavlink_data_stream_t *packet = (mavlink_data_stream_t *)msgbuf; + packet->message_rate = message_rate; + packet->stream_id = stream_id; + packet->on_off = on_off; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, (const char *)packet, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, (const char *)packet, MAVLINK_MSG_ID_DATA_STREAM_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_STREAM, (const char *)packet, MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_DATA_STREAM_LEN, MAVLINK_MSG_ID_DATA_STREAM_CRC); #endif } #endif @@ -216,17 +220,17 @@ static inline void mavlink_msg_data_stream_send_buf(mavlink_message_t *msgbuf, m */ static inline uint8_t mavlink_msg_data_stream_get_stream_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** * @brief Get field message_rate from data_stream message * - * @return The requested interval between two messages of this type + * @return The message rate */ static inline uint16_t mavlink_msg_data_stream_get_message_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -236,7 +240,7 @@ static inline uint16_t mavlink_msg_data_stream_get_message_rate(const mavlink_me */ static inline uint8_t mavlink_msg_data_stream_get_on_off(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -247,11 +251,13 @@ static inline uint8_t mavlink_msg_data_stream_get_on_off(const mavlink_message_t */ static inline void mavlink_msg_data_stream_decode(const mavlink_message_t* msg, mavlink_data_stream_t* data_stream) { -#if MAVLINK_NEED_BYTE_SWAP - data_stream->message_rate = mavlink_msg_data_stream_get_message_rate(msg); - data_stream->stream_id = mavlink_msg_data_stream_get_stream_id(msg); - data_stream->on_off = mavlink_msg_data_stream_get_on_off(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + data_stream->message_rate = mavlink_msg_data_stream_get_message_rate(msg); + data_stream->stream_id = mavlink_msg_data_stream_get_stream_id(msg); + data_stream->on_off = mavlink_msg_data_stream_get_on_off(msg); #else - memcpy(data_stream, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DATA_STREAM_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DATA_STREAM_LEN? msg->len : MAVLINK_MSG_ID_DATA_STREAM_LEN; + memset(data_stream, 0, MAVLINK_MSG_ID_DATA_STREAM_LEN); + memcpy(data_stream, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_data_transmission_handshake.h b/vendor/libraries/mavlink/common/mavlink_msg_data_transmission_handshake.h index d84a73709d..f607e39768 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_data_transmission_handshake.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_data_transmission_handshake.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE DATA_TRANSMISSION_HANDSHAKE PACKING #define MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE 130 -typedef struct __mavlink_data_transmission_handshake_t -{ - uint32_t size; ///< total data size in bytes (set on ACK only) - uint16_t width; ///< Width of a matrix or image - uint16_t height; ///< Height of a matrix or image - uint16_t packets; ///< number of packets beeing sent (set on ACK only) - uint8_t type; ///< type of requested/acknowledged data (as defined in ENUM DATA_TYPES in mavlink/include/mavlink_types.h) - uint8_t payload; ///< payload size per packet (normally 253 byte, see DATA field size in message ENCAPSULATED_DATA) (set on ACK only) - uint8_t jpg_quality; ///< JPEG quality out of [1,100] -} mavlink_data_transmission_handshake_t; +MAVPACKED( +typedef struct __mavlink_data_transmission_handshake_t { + uint32_t size; /*< total data size in bytes (set on ACK only)*/ + uint16_t width; /*< Width of a matrix or image*/ + uint16_t height; /*< Height of a matrix or image*/ + uint16_t packets; /*< number of packets beeing sent (set on ACK only)*/ + uint8_t type; /*< type of requested/acknowledged data (as defined in ENUM DATA_TYPES in mavlink/include/mavlink_types.h)*/ + uint8_t payload; /*< payload size per packet (normally 253 byte, see DATA field size in message ENCAPSULATED_DATA) (set on ACK only)*/ + uint8_t jpg_quality; /*< JPEG quality out of [1,100]*/ +}) mavlink_data_transmission_handshake_t; #define MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN 13 +#define MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN 13 #define MAVLINK_MSG_ID_130_LEN 13 +#define MAVLINK_MSG_ID_130_MIN_LEN 13 #define MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC 29 #define MAVLINK_MSG_ID_130_CRC 29 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DATA_TRANSMISSION_HANDSHAKE { \ - "DATA_TRANSMISSION_HANDSHAKE", \ - 7, \ - { { "size", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_data_transmission_handshake_t, size) }, \ + 130, \ + "DATA_TRANSMISSION_HANDSHAKE", \ + 7, \ + { { "size", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_data_transmission_handshake_t, size) }, \ { "width", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_data_transmission_handshake_t, width) }, \ { "height", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_data_transmission_handshake_t, height) }, \ { "packets", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_data_transmission_handshake_t, packets) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_data_transmission_handshake_t { "jpg_quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_data_transmission_handshake_t, jpg_quality) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DATA_TRANSMISSION_HANDSHAKE { \ + "DATA_TRANSMISSION_HANDSHAKE", \ + 7, \ + { { "size", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_data_transmission_handshake_t, size) }, \ + { "width", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_data_transmission_handshake_t, width) }, \ + { "height", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_data_transmission_handshake_t, height) }, \ + { "packets", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_data_transmission_handshake_t, packets) }, \ + { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_data_transmission_handshake_t, type) }, \ + { "payload", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_data_transmission_handshake_t, payload) }, \ + { "jpg_quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_data_transmission_handshake_t, jpg_quality) }, \ + } \ +} +#endif /** * @brief Pack a data_transmission_handshake message @@ -51,38 +69,34 @@ typedef struct __mavlink_data_transmission_handshake_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data_transmission_handshake_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t type, uint32_t size, uint16_t width, uint16_t height, uint16_t packets, uint8_t payload, uint8_t jpg_quality) + uint8_t type, uint32_t size, uint16_t width, uint16_t height, uint16_t packets, uint8_t payload, uint8_t jpg_quality) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN]; - _mav_put_uint32_t(buf, 0, size); - _mav_put_uint16_t(buf, 4, width); - _mav_put_uint16_t(buf, 6, height); - _mav_put_uint16_t(buf, 8, packets); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, payload); - _mav_put_uint8_t(buf, 12, jpg_quality); + char buf[MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN]; + _mav_put_uint32_t(buf, 0, size); + _mav_put_uint16_t(buf, 4, width); + _mav_put_uint16_t(buf, 6, height); + _mav_put_uint16_t(buf, 8, packets); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, payload); + _mav_put_uint8_t(buf, 12, jpg_quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); #else - mavlink_data_transmission_handshake_t packet; - packet.size = size; - packet.width = width; - packet.height = height; - packet.packets = packets; - packet.type = type; - packet.payload = payload; - packet.jpg_quality = jpg_quality; + mavlink_data_transmission_handshake_t packet; + packet.size = size; + packet.width = width; + packet.height = height; + packet.packets = packets; + packet.type = type; + packet.payload = payload; + packet.jpg_quality = jpg_quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_pack(uint8_t syst * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_data_transmission_handshake_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t type,uint32_t size,uint16_t width,uint16_t height,uint16_t packets,uint8_t payload,uint8_t jpg_quality) + mavlink_message_t* msg, + uint8_t type,uint32_t size,uint16_t width,uint16_t height,uint16_t packets,uint8_t payload,uint8_t jpg_quality) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN]; - _mav_put_uint32_t(buf, 0, size); - _mav_put_uint16_t(buf, 4, width); - _mav_put_uint16_t(buf, 6, height); - _mav_put_uint16_t(buf, 8, packets); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, payload); - _mav_put_uint8_t(buf, 12, jpg_quality); + char buf[MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN]; + _mav_put_uint32_t(buf, 0, size); + _mav_put_uint16_t(buf, 4, width); + _mav_put_uint16_t(buf, 6, height); + _mav_put_uint16_t(buf, 8, packets); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, payload); + _mav_put_uint8_t(buf, 12, jpg_quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); #else - mavlink_data_transmission_handshake_t packet; - packet.size = size; - packet.width = width; - packet.height = height; - packet.packets = packets; - packet.type = type; - packet.payload = payload; - packet.jpg_quality = jpg_quality; + mavlink_data_transmission_handshake_t packet; + packet.size = size; + packet.width = width; + packet.height = height; + packet.packets = packets; + packet.type = type; + packet.payload = payload; + packet.jpg_quality = jpg_quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_pack_chan(uint8_t */ static inline uint16_t mavlink_msg_data_transmission_handshake_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_data_transmission_handshake_t* data_transmission_handshake) { - return mavlink_msg_data_transmission_handshake_pack(system_id, component_id, msg, data_transmission_handshake->type, data_transmission_handshake->size, data_transmission_handshake->width, data_transmission_handshake->height, data_transmission_handshake->packets, data_transmission_handshake->payload, data_transmission_handshake->jpg_quality); + return mavlink_msg_data_transmission_handshake_pack(system_id, component_id, msg, data_transmission_handshake->type, data_transmission_handshake->size, data_transmission_handshake->width, data_transmission_handshake->height, data_transmission_handshake->packets, data_transmission_handshake->payload, data_transmission_handshake->jpg_quality); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_encode(uint8_t sy */ static inline uint16_t mavlink_msg_data_transmission_handshake_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_data_transmission_handshake_t* data_transmission_handshake) { - return mavlink_msg_data_transmission_handshake_pack_chan(system_id, component_id, chan, msg, data_transmission_handshake->type, data_transmission_handshake->size, data_transmission_handshake->width, data_transmission_handshake->height, data_transmission_handshake->packets, data_transmission_handshake->payload, data_transmission_handshake->jpg_quality); + return mavlink_msg_data_transmission_handshake_pack_chan(system_id, component_id, chan, msg, data_transmission_handshake->type, data_transmission_handshake->size, data_transmission_handshake->width, data_transmission_handshake->height, data_transmission_handshake->packets, data_transmission_handshake->payload, data_transmission_handshake->jpg_quality); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_encode_chan(uint8 static inline void mavlink_msg_data_transmission_handshake_send(mavlink_channel_t chan, uint8_t type, uint32_t size, uint16_t width, uint16_t height, uint16_t packets, uint8_t payload, uint8_t jpg_quality) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN]; - _mav_put_uint32_t(buf, 0, size); - _mav_put_uint16_t(buf, 4, width); - _mav_put_uint16_t(buf, 6, height); - _mav_put_uint16_t(buf, 8, packets); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, payload); - _mav_put_uint8_t(buf, 12, jpg_quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); + char buf[MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN]; + _mav_put_uint32_t(buf, 0, size); + _mav_put_uint16_t(buf, 4, width); + _mav_put_uint16_t(buf, 6, height); + _mav_put_uint16_t(buf, 8, packets); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, payload); + _mav_put_uint8_t(buf, 12, jpg_quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); + mavlink_data_transmission_handshake_t packet; + packet.size = size; + packet.width = width; + packet.height = height; + packet.packets = packets; + packet.type = type; + packet.payload = payload; + packet.jpg_quality = jpg_quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, (const char *)&packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); #endif +} + +/** + * @brief Send a data_transmission_handshake message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_data_transmission_handshake_send_struct(mavlink_channel_t chan, const mavlink_data_transmission_handshake_t* data_transmission_handshake) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_data_transmission_handshake_send(chan, data_transmission_handshake->type, data_transmission_handshake->size, data_transmission_handshake->width, data_transmission_handshake->height, data_transmission_handshake->packets, data_transmission_handshake->payload, data_transmission_handshake->jpg_quality); #else - mavlink_data_transmission_handshake_t packet; - packet.size = size; - packet.width = width; - packet.height = height; - packet.packets = packets; - packet.type = type; - packet.payload = payload; - packet.jpg_quality = jpg_quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, (const char *)&packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, (const char *)&packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, (const char *)data_transmission_handshake, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_data_transmission_handshake_send(mavlink_channel_ static inline void mavlink_msg_data_transmission_handshake_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t type, uint32_t size, uint16_t width, uint16_t height, uint16_t packets, uint8_t payload, uint8_t jpg_quality) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, size); - _mav_put_uint16_t(buf, 4, width); - _mav_put_uint16_t(buf, 6, height); - _mav_put_uint16_t(buf, 8, packets); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, payload); - _mav_put_uint8_t(buf, 12, jpg_quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); -#endif -#else - mavlink_data_transmission_handshake_t *packet = (mavlink_data_transmission_handshake_t *)msgbuf; - packet->size = size; - packet->width = width; - packet->height = height; - packet->packets = packets; - packet->type = type; - packet->payload = payload; - packet->jpg_quality = jpg_quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, (const char *)packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, size); + _mav_put_uint16_t(buf, 4, width); + _mav_put_uint16_t(buf, 6, height); + _mav_put_uint16_t(buf, 8, packets); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, payload); + _mav_put_uint8_t(buf, 12, jpg_quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, buf, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, (const char *)packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); -#endif + mavlink_data_transmission_handshake_t *packet = (mavlink_data_transmission_handshake_t *)msgbuf; + packet->size = size; + packet->width = width; + packet->height = height; + packet->packets = packets; + packet->type = type; + packet->payload = payload; + packet->jpg_quality = jpg_quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, (const char *)packet, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_data_transmission_handshake_send_buf(mavlink_mess */ static inline uint8_t mavlink_msg_data_transmission_handshake_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 10); + return _MAV_RETURN_uint8_t(msg, 10); } /** @@ -278,7 +286,7 @@ static inline uint8_t mavlink_msg_data_transmission_handshake_get_type(const mav */ static inline uint32_t mavlink_msg_data_transmission_handshake_get_size(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -288,7 +296,7 @@ static inline uint32_t mavlink_msg_data_transmission_handshake_get_size(const ma */ static inline uint16_t mavlink_msg_data_transmission_handshake_get_width(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -298,7 +306,7 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_get_width(const m */ static inline uint16_t mavlink_msg_data_transmission_handshake_get_height(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -308,7 +316,7 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_get_height(const */ static inline uint16_t mavlink_msg_data_transmission_handshake_get_packets(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -318,7 +326,7 @@ static inline uint16_t mavlink_msg_data_transmission_handshake_get_packets(const */ static inline uint8_t mavlink_msg_data_transmission_handshake_get_payload(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 11); + return _MAV_RETURN_uint8_t(msg, 11); } /** @@ -328,7 +336,7 @@ static inline uint8_t mavlink_msg_data_transmission_handshake_get_payload(const */ static inline uint8_t mavlink_msg_data_transmission_handshake_get_jpg_quality(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -339,15 +347,17 @@ static inline uint8_t mavlink_msg_data_transmission_handshake_get_jpg_quality(co */ static inline void mavlink_msg_data_transmission_handshake_decode(const mavlink_message_t* msg, mavlink_data_transmission_handshake_t* data_transmission_handshake) { -#if MAVLINK_NEED_BYTE_SWAP - data_transmission_handshake->size = mavlink_msg_data_transmission_handshake_get_size(msg); - data_transmission_handshake->width = mavlink_msg_data_transmission_handshake_get_width(msg); - data_transmission_handshake->height = mavlink_msg_data_transmission_handshake_get_height(msg); - data_transmission_handshake->packets = mavlink_msg_data_transmission_handshake_get_packets(msg); - data_transmission_handshake->type = mavlink_msg_data_transmission_handshake_get_type(msg); - data_transmission_handshake->payload = mavlink_msg_data_transmission_handshake_get_payload(msg); - data_transmission_handshake->jpg_quality = mavlink_msg_data_transmission_handshake_get_jpg_quality(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + data_transmission_handshake->size = mavlink_msg_data_transmission_handshake_get_size(msg); + data_transmission_handshake->width = mavlink_msg_data_transmission_handshake_get_width(msg); + data_transmission_handshake->height = mavlink_msg_data_transmission_handshake_get_height(msg); + data_transmission_handshake->packets = mavlink_msg_data_transmission_handshake_get_packets(msg); + data_transmission_handshake->type = mavlink_msg_data_transmission_handshake_get_type(msg); + data_transmission_handshake->payload = mavlink_msg_data_transmission_handshake_get_payload(msg); + data_transmission_handshake->jpg_quality = mavlink_msg_data_transmission_handshake_get_jpg_quality(msg); #else - memcpy(data_transmission_handshake, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN? msg->len : MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN; + memset(data_transmission_handshake, 0, MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_LEN); + memcpy(data_transmission_handshake, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_debug.h b/vendor/libraries/mavlink/common/mavlink_msg_debug.h index 2102af8623..d762a89dee 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_debug.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_debug.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE DEBUG PACKING #define MAVLINK_MSG_ID_DEBUG 254 -typedef struct __mavlink_debug_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float value; ///< DEBUG value - uint8_t ind; ///< index of debug variable -} mavlink_debug_t; +MAVPACKED( +typedef struct __mavlink_debug_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float value; /*< DEBUG value*/ + uint8_t ind; /*< index of debug variable*/ +}) mavlink_debug_t; #define MAVLINK_MSG_ID_DEBUG_LEN 9 +#define MAVLINK_MSG_ID_DEBUG_MIN_LEN 9 #define MAVLINK_MSG_ID_254_LEN 9 +#define MAVLINK_MSG_ID_254_MIN_LEN 9 #define MAVLINK_MSG_ID_DEBUG_CRC 46 #define MAVLINK_MSG_ID_254_CRC 46 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DEBUG { \ - "DEBUG", \ - 3, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_debug_t, time_boot_ms) }, \ + 254, \ + "DEBUG", \ + 3, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_debug_t, time_boot_ms) }, \ { "value", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_debug_t, value) }, \ { "ind", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_debug_t, ind) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DEBUG { \ + "DEBUG", \ + 3, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_debug_t, time_boot_ms) }, \ + { "value", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_debug_t, value) }, \ + { "ind", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_debug_t, ind) }, \ + } \ +} +#endif /** * @brief Pack a debug message @@ -39,30 +53,26 @@ typedef struct __mavlink_debug_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_debug_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t ind, float value) + uint32_t time_boot_ms, uint8_t ind, float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DEBUG_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_uint8_t(buf, 8, ind); + char buf[MAVLINK_MSG_ID_DEBUG_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_uint8_t(buf, 8, ind); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DEBUG_LEN); #else - mavlink_debug_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - packet.ind = ind; + mavlink_debug_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + packet.ind = ind; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DEBUG_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DEBUG; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DEBUG_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DEBUG; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DEBUG_MIN_LEN, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_debug_pack(uint8_t system_id, uint8_t compone * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_debug_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t ind,float value) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t ind,float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DEBUG_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_uint8_t(buf, 8, ind); + char buf[MAVLINK_MSG_ID_DEBUG_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_uint8_t(buf, 8, ind); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DEBUG_LEN); #else - mavlink_debug_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - packet.ind = ind; + mavlink_debug_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + packet.ind = ind; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DEBUG_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DEBUG; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DEBUG_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DEBUG; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DEBUG_MIN_LEN, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_debug_pack_chan(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_debug_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_debug_t* debug) { - return mavlink_msg_debug_pack(system_id, component_id, msg, debug->time_boot_ms, debug->ind, debug->value); + return mavlink_msg_debug_pack(system_id, component_id, msg, debug->time_boot_ms, debug->ind, debug->value); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_debug_encode(uint8_t system_id, uint8_t compo */ static inline uint16_t mavlink_msg_debug_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_debug_t* debug) { - return mavlink_msg_debug_pack_chan(system_id, component_id, chan, msg, debug->time_boot_ms, debug->ind, debug->value); + return mavlink_msg_debug_pack_chan(system_id, component_id, chan, msg, debug->time_boot_ms, debug->ind, debug->value); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_debug_encode_chan(uint8_t system_id, uint8_t static inline void mavlink_msg_debug_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t ind, float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DEBUG_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_uint8_t(buf, 8, ind); + char buf[MAVLINK_MSG_ID_DEBUG_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_uint8_t(buf, 8, ind); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, buf, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, buf, MAVLINK_MSG_ID_DEBUG_MIN_LEN, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, buf, MAVLINK_MSG_ID_DEBUG_LEN); + mavlink_debug_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + packet.ind = ind; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, (const char *)&packet, MAVLINK_MSG_ID_DEBUG_MIN_LEN, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); #endif -#else - mavlink_debug_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - packet.ind = ind; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, (const char *)&packet, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); +/** + * @brief Send a debug message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_debug_send_struct(mavlink_channel_t chan, const mavlink_debug_t* debug) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_debug_send(chan, debug->time_boot_ms, debug->ind, debug->value); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, (const char *)&packet, MAVLINK_MSG_ID_DEBUG_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, (const char *)debug, MAVLINK_MSG_ID_DEBUG_MIN_LEN, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_debug_send(mavlink_channel_t chan, uint32_t time_ static inline void mavlink_msg_debug_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t ind, float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_uint8_t(buf, 8, ind); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_uint8_t(buf, 8, ind); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, buf, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, buf, MAVLINK_MSG_ID_DEBUG_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, buf, MAVLINK_MSG_ID_DEBUG_MIN_LEN, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); #else - mavlink_debug_t *packet = (mavlink_debug_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->value = value; - packet->ind = ind; + mavlink_debug_t *packet = (mavlink_debug_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->value = value; + packet->ind = ind; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, (const char *)packet, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, (const char *)packet, MAVLINK_MSG_ID_DEBUG_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG, (const char *)packet, MAVLINK_MSG_ID_DEBUG_MIN_LEN, MAVLINK_MSG_ID_DEBUG_LEN, MAVLINK_MSG_ID_DEBUG_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_debug_send_buf(mavlink_message_t *msgbuf, mavlink */ static inline uint32_t mavlink_msg_debug_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -226,7 +230,7 @@ static inline uint32_t mavlink_msg_debug_get_time_boot_ms(const mavlink_message_ */ static inline uint8_t mavlink_msg_debug_get_ind(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 8); + return _MAV_RETURN_uint8_t(msg, 8); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_debug_get_ind(const mavlink_message_t* msg) */ static inline float mavlink_msg_debug_get_value(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -247,11 +251,13 @@ static inline float mavlink_msg_debug_get_value(const mavlink_message_t* msg) */ static inline void mavlink_msg_debug_decode(const mavlink_message_t* msg, mavlink_debug_t* debug) { -#if MAVLINK_NEED_BYTE_SWAP - debug->time_boot_ms = mavlink_msg_debug_get_time_boot_ms(msg); - debug->value = mavlink_msg_debug_get_value(msg); - debug->ind = mavlink_msg_debug_get_ind(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + debug->time_boot_ms = mavlink_msg_debug_get_time_boot_ms(msg); + debug->value = mavlink_msg_debug_get_value(msg); + debug->ind = mavlink_msg_debug_get_ind(msg); #else - memcpy(debug, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DEBUG_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DEBUG_LEN? msg->len : MAVLINK_MSG_ID_DEBUG_LEN; + memset(debug, 0, MAVLINK_MSG_ID_DEBUG_LEN); + memcpy(debug, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_debug_vect.h b/vendor/libraries/mavlink/common/mavlink_msg_debug_vect.h index 67c339e898..ac485af943 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_debug_vect.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_debug_vect.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE DEBUG_VECT PACKING #define MAVLINK_MSG_ID_DEBUG_VECT 250 -typedef struct __mavlink_debug_vect_t -{ - uint64_t time_usec; ///< Timestamp - float x; ///< x - float y; ///< y - float z; ///< z - char name[10]; ///< Name -} mavlink_debug_vect_t; +MAVPACKED( +typedef struct __mavlink_debug_vect_t { + uint64_t time_usec; /*< Timestamp*/ + float x; /*< x*/ + float y; /*< y*/ + float z; /*< z*/ + char name[10]; /*< Name*/ +}) mavlink_debug_vect_t; #define MAVLINK_MSG_ID_DEBUG_VECT_LEN 30 +#define MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN 30 #define MAVLINK_MSG_ID_250_LEN 30 +#define MAVLINK_MSG_ID_250_MIN_LEN 30 #define MAVLINK_MSG_ID_DEBUG_VECT_CRC 49 #define MAVLINK_MSG_ID_250_CRC 49 #define MAVLINK_MSG_DEBUG_VECT_FIELD_NAME_LEN 10 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DEBUG_VECT { \ - "DEBUG_VECT", \ - 5, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_debug_vect_t, time_usec) }, \ + 250, \ + "DEBUG_VECT", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_debug_vect_t, time_usec) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_debug_vect_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_debug_vect_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_debug_vect_t, z) }, \ { "name", NULL, MAVLINK_TYPE_CHAR, 10, 20, offsetof(mavlink_debug_vect_t, name) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DEBUG_VECT { \ + "DEBUG_VECT", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_debug_vect_t, time_usec) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_debug_vect_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_debug_vect_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_debug_vect_t, z) }, \ + { "name", NULL, MAVLINK_TYPE_CHAR, 10, 20, offsetof(mavlink_debug_vect_t, name) }, \ + } \ +} +#endif /** * @brief Pack a debug_vect message @@ -45,32 +61,28 @@ typedef struct __mavlink_debug_vect_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_debug_vect_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - const char *name, uint64_t time_usec, float x, float y, float z) + const char *name, uint64_t time_usec, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DEBUG_VECT_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_char_array(buf, 20, name, 10); + char buf[MAVLINK_MSG_ID_DEBUG_VECT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_char_array(buf, 20, name, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DEBUG_VECT_LEN); #else - mavlink_debug_vect_t packet; - packet.time_usec = time_usec; - packet.x = x; - packet.y = y; - packet.z = z; - mav_array_memcpy(packet.name, name, sizeof(char)*10); + mavlink_debug_vect_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + mav_array_memcpy(packet.name, name, sizeof(char)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DEBUG_VECT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DEBUG_VECT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DEBUG_VECT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DEBUG_VECT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); } /** @@ -87,33 +99,29 @@ static inline uint16_t mavlink_msg_debug_vect_pack(uint8_t system_id, uint8_t co * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_debug_vect_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - const char *name,uint64_t time_usec,float x,float y,float z) + mavlink_message_t* msg, + const char *name,uint64_t time_usec,float x,float y,float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DEBUG_VECT_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_char_array(buf, 20, name, 10); + char buf[MAVLINK_MSG_ID_DEBUG_VECT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_char_array(buf, 20, name, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DEBUG_VECT_LEN); #else - mavlink_debug_vect_t packet; - packet.time_usec = time_usec; - packet.x = x; - packet.y = y; - packet.z = z; - mav_array_memcpy(packet.name, name, sizeof(char)*10); + mavlink_debug_vect_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + mav_array_memcpy(packet.name, name, sizeof(char)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DEBUG_VECT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DEBUG_VECT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DEBUG_VECT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DEBUG_VECT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); } /** @@ -126,7 +134,7 @@ static inline uint16_t mavlink_msg_debug_vect_pack_chan(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_debug_vect_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_debug_vect_t* debug_vect) { - return mavlink_msg_debug_vect_pack(system_id, component_id, msg, debug_vect->name, debug_vect->time_usec, debug_vect->x, debug_vect->y, debug_vect->z); + return mavlink_msg_debug_vect_pack(system_id, component_id, msg, debug_vect->name, debug_vect->time_usec, debug_vect->x, debug_vect->y, debug_vect->z); } /** @@ -140,7 +148,7 @@ static inline uint16_t mavlink_msg_debug_vect_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_debug_vect_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_debug_vect_t* debug_vect) { - return mavlink_msg_debug_vect_pack_chan(system_id, component_id, chan, msg, debug_vect->name, debug_vect->time_usec, debug_vect->x, debug_vect->y, debug_vect->z); + return mavlink_msg_debug_vect_pack_chan(system_id, component_id, chan, msg, debug_vect->name, debug_vect->time_usec, debug_vect->x, debug_vect->y, debug_vect->z); } /** @@ -158,29 +166,35 @@ static inline uint16_t mavlink_msg_debug_vect_encode_chan(uint8_t system_id, uin static inline void mavlink_msg_debug_vect_send(mavlink_channel_t chan, const char *name, uint64_t time_usec, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DEBUG_VECT_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_char_array(buf, 20, name, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, buf, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); + char buf[MAVLINK_MSG_ID_DEBUG_VECT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_char_array(buf, 20, name, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, buf, MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, buf, MAVLINK_MSG_ID_DEBUG_VECT_LEN); + mavlink_debug_vect_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + mav_array_memcpy(packet.name, name, sizeof(char)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, (const char *)&packet, MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); #endif +} + +/** + * @brief Send a debug_vect message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_debug_vect_send_struct(mavlink_channel_t chan, const mavlink_debug_vect_t* debug_vect) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_debug_vect_send(chan, debug_vect->name, debug_vect->time_usec, debug_vect->x, debug_vect->y, debug_vect->z); #else - mavlink_debug_vect_t packet; - packet.time_usec = time_usec; - packet.x = x; - packet.y = y; - packet.z = z; - mav_array_memcpy(packet.name, name, sizeof(char)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, (const char *)&packet, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, (const char *)&packet, MAVLINK_MSG_ID_DEBUG_VECT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, (const char *)debug_vect, MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); #endif } @@ -195,29 +209,21 @@ static inline void mavlink_msg_debug_vect_send(mavlink_channel_t chan, const cha static inline void mavlink_msg_debug_vect_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, const char *name, uint64_t time_usec, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_char_array(buf, 20, name, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, buf, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_char_array(buf, 20, name, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, buf, MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, buf, MAVLINK_MSG_ID_DEBUG_VECT_LEN); -#endif -#else - mavlink_debug_vect_t *packet = (mavlink_debug_vect_t *)msgbuf; - packet->time_usec = time_usec; - packet->x = x; - packet->y = y; - packet->z = z; - mav_array_memcpy(packet->name, name, sizeof(char)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, (const char *)packet, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, (const char *)packet, MAVLINK_MSG_ID_DEBUG_VECT_LEN); -#endif + mavlink_debug_vect_t *packet = (mavlink_debug_vect_t *)msgbuf; + packet->time_usec = time_usec; + packet->x = x; + packet->y = y; + packet->z = z; + mav_array_memcpy(packet->name, name, sizeof(char)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DEBUG_VECT, (const char *)packet, MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN, MAVLINK_MSG_ID_DEBUG_VECT_LEN, MAVLINK_MSG_ID_DEBUG_VECT_CRC); #endif } #endif @@ -234,7 +240,7 @@ static inline void mavlink_msg_debug_vect_send_buf(mavlink_message_t *msgbuf, ma */ static inline uint16_t mavlink_msg_debug_vect_get_name(const mavlink_message_t* msg, char *name) { - return _MAV_RETURN_char_array(msg, name, 10, 20); + return _MAV_RETURN_char_array(msg, name, 10, 20); } /** @@ -244,7 +250,7 @@ static inline uint16_t mavlink_msg_debug_vect_get_name(const mavlink_message_t* */ static inline uint64_t mavlink_msg_debug_vect_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -254,7 +260,7 @@ static inline uint64_t mavlink_msg_debug_vect_get_time_usec(const mavlink_messag */ static inline float mavlink_msg_debug_vect_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -264,7 +270,7 @@ static inline float mavlink_msg_debug_vect_get_x(const mavlink_message_t* msg) */ static inline float mavlink_msg_debug_vect_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -274,7 +280,7 @@ static inline float mavlink_msg_debug_vect_get_y(const mavlink_message_t* msg) */ static inline float mavlink_msg_debug_vect_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -285,13 +291,15 @@ static inline float mavlink_msg_debug_vect_get_z(const mavlink_message_t* msg) */ static inline void mavlink_msg_debug_vect_decode(const mavlink_message_t* msg, mavlink_debug_vect_t* debug_vect) { -#if MAVLINK_NEED_BYTE_SWAP - debug_vect->time_usec = mavlink_msg_debug_vect_get_time_usec(msg); - debug_vect->x = mavlink_msg_debug_vect_get_x(msg); - debug_vect->y = mavlink_msg_debug_vect_get_y(msg); - debug_vect->z = mavlink_msg_debug_vect_get_z(msg); - mavlink_msg_debug_vect_get_name(msg, debug_vect->name); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + debug_vect->time_usec = mavlink_msg_debug_vect_get_time_usec(msg); + debug_vect->x = mavlink_msg_debug_vect_get_x(msg); + debug_vect->y = mavlink_msg_debug_vect_get_y(msg); + debug_vect->z = mavlink_msg_debug_vect_get_z(msg); + mavlink_msg_debug_vect_get_name(msg, debug_vect->name); #else - memcpy(debug_vect, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DEBUG_VECT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DEBUG_VECT_LEN? msg->len : MAVLINK_MSG_ID_DEBUG_VECT_LEN; + memset(debug_vect, 0, MAVLINK_MSG_ID_DEBUG_VECT_LEN); + memcpy(debug_vect, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_distance_sensor.h b/vendor/libraries/mavlink/common/mavlink_msg_distance_sensor.h index 8743b64852..2a52e69293 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_distance_sensor.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_distance_sensor.h @@ -1,31 +1,36 @@ +#pragma once // MESSAGE DISTANCE_SENSOR PACKING #define MAVLINK_MSG_ID_DISTANCE_SENSOR 132 -typedef struct __mavlink_distance_sensor_t -{ - uint32_t time_boot_ms; ///< Time since system boot - uint16_t min_distance; ///< Minimum distance the sensor can measure in centimeters - uint16_t max_distance; ///< Maximum distance the sensor can measure in centimeters - uint16_t current_distance; ///< Current distance reading - uint8_t type; ///< Type from MAV_DISTANCE_SENSOR enum. - uint8_t id; ///< Onboard ID of the sensor - uint8_t orientation; ///< Direction the sensor faces from FIXME enum. - uint8_t covariance; ///< Measurement covariance in centimeters, 0 for unknown / invalid readings -} mavlink_distance_sensor_t; +MAVPACKED( +typedef struct __mavlink_distance_sensor_t { + uint32_t time_boot_ms; /*< Time since system boot*/ + uint16_t min_distance; /*< Minimum distance the sensor can measure in centimeters*/ + uint16_t max_distance; /*< Maximum distance the sensor can measure in centimeters*/ + uint16_t current_distance; /*< Current distance reading*/ + uint8_t type; /*< Type from MAV_DISTANCE_SENSOR enum.*/ + uint8_t id; /*< Onboard ID of the sensor*/ + uint8_t orientation; /*< Direction the sensor faces from MAV_SENSOR_ORIENTATION enum.*/ + uint8_t covariance; /*< Measurement covariance in centimeters, 0 for unknown / invalid readings*/ +}) mavlink_distance_sensor_t; #define MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN 14 +#define MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN 14 #define MAVLINK_MSG_ID_132_LEN 14 +#define MAVLINK_MSG_ID_132_MIN_LEN 14 #define MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC 85 #define MAVLINK_MSG_ID_132_CRC 85 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_DISTANCE_SENSOR { \ - "DISTANCE_SENSOR", \ - 8, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_distance_sensor_t, time_boot_ms) }, \ + 132, \ + "DISTANCE_SENSOR", \ + 8, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_distance_sensor_t, time_boot_ms) }, \ { "min_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_distance_sensor_t, min_distance) }, \ { "max_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_distance_sensor_t, max_distance) }, \ { "current_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_distance_sensor_t, current_distance) }, \ @@ -35,7 +40,21 @@ typedef struct __mavlink_distance_sensor_t { "covariance", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_distance_sensor_t, covariance) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_DISTANCE_SENSOR { \ + "DISTANCE_SENSOR", \ + 8, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_distance_sensor_t, time_boot_ms) }, \ + { "min_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_distance_sensor_t, min_distance) }, \ + { "max_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_distance_sensor_t, max_distance) }, \ + { "current_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_distance_sensor_t, current_distance) }, \ + { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_distance_sensor_t, type) }, \ + { "id", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_distance_sensor_t, id) }, \ + { "orientation", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_distance_sensor_t, orientation) }, \ + { "covariance", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_distance_sensor_t, covariance) }, \ + } \ +} +#endif /** * @brief Pack a distance_sensor message @@ -49,45 +68,41 @@ typedef struct __mavlink_distance_sensor_t * @param current_distance Current distance reading * @param type Type from MAV_DISTANCE_SENSOR enum. * @param id Onboard ID of the sensor - * @param orientation Direction the sensor faces from FIXME enum. + * @param orientation Direction the sensor faces from MAV_SENSOR_ORIENTATION enum. * @param covariance Measurement covariance in centimeters, 0 for unknown / invalid readings * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_distance_sensor_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint16_t min_distance, uint16_t max_distance, uint16_t current_distance, uint8_t type, uint8_t id, uint8_t orientation, uint8_t covariance) + uint32_t time_boot_ms, uint16_t min_distance, uint16_t max_distance, uint16_t current_distance, uint8_t type, uint8_t id, uint8_t orientation, uint8_t covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, min_distance); - _mav_put_uint16_t(buf, 6, max_distance); - _mav_put_uint16_t(buf, 8, current_distance); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, id); - _mav_put_uint8_t(buf, 12, orientation); - _mav_put_uint8_t(buf, 13, covariance); + char buf[MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, min_distance); + _mav_put_uint16_t(buf, 6, max_distance); + _mav_put_uint16_t(buf, 8, current_distance); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, id); + _mav_put_uint8_t(buf, 12, orientation); + _mav_put_uint8_t(buf, 13, covariance); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); #else - mavlink_distance_sensor_t packet; - packet.time_boot_ms = time_boot_ms; - packet.min_distance = min_distance; - packet.max_distance = max_distance; - packet.current_distance = current_distance; - packet.type = type; - packet.id = id; - packet.orientation = orientation; - packet.covariance = covariance; + mavlink_distance_sensor_t packet; + packet.time_boot_ms = time_boot_ms; + packet.min_distance = min_distance; + packet.max_distance = max_distance; + packet.current_distance = current_distance; + packet.type = type; + packet.id = id; + packet.orientation = orientation; + packet.covariance = covariance; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DISTANCE_SENSOR; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DISTANCE_SENSOR; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); } /** @@ -102,46 +117,42 @@ static inline uint16_t mavlink_msg_distance_sensor_pack(uint8_t system_id, uint8 * @param current_distance Current distance reading * @param type Type from MAV_DISTANCE_SENSOR enum. * @param id Onboard ID of the sensor - * @param orientation Direction the sensor faces from FIXME enum. + * @param orientation Direction the sensor faces from MAV_SENSOR_ORIENTATION enum. * @param covariance Measurement covariance in centimeters, 0 for unknown / invalid readings * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_distance_sensor_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint16_t min_distance,uint16_t max_distance,uint16_t current_distance,uint8_t type,uint8_t id,uint8_t orientation,uint8_t covariance) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint16_t min_distance,uint16_t max_distance,uint16_t current_distance,uint8_t type,uint8_t id,uint8_t orientation,uint8_t covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, min_distance); - _mav_put_uint16_t(buf, 6, max_distance); - _mav_put_uint16_t(buf, 8, current_distance); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, id); - _mav_put_uint8_t(buf, 12, orientation); - _mav_put_uint8_t(buf, 13, covariance); + char buf[MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, min_distance); + _mav_put_uint16_t(buf, 6, max_distance); + _mav_put_uint16_t(buf, 8, current_distance); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, id); + _mav_put_uint8_t(buf, 12, orientation); + _mav_put_uint8_t(buf, 13, covariance); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); #else - mavlink_distance_sensor_t packet; - packet.time_boot_ms = time_boot_ms; - packet.min_distance = min_distance; - packet.max_distance = max_distance; - packet.current_distance = current_distance; - packet.type = type; - packet.id = id; - packet.orientation = orientation; - packet.covariance = covariance; + mavlink_distance_sensor_t packet; + packet.time_boot_ms = time_boot_ms; + packet.min_distance = min_distance; + packet.max_distance = max_distance; + packet.current_distance = current_distance; + packet.type = type; + packet.id = id; + packet.orientation = orientation; + packet.covariance = covariance; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_DISTANCE_SENSOR; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_DISTANCE_SENSOR; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); } /** @@ -154,7 +165,7 @@ static inline uint16_t mavlink_msg_distance_sensor_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_distance_sensor_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_distance_sensor_t* distance_sensor) { - return mavlink_msg_distance_sensor_pack(system_id, component_id, msg, distance_sensor->time_boot_ms, distance_sensor->min_distance, distance_sensor->max_distance, distance_sensor->current_distance, distance_sensor->type, distance_sensor->id, distance_sensor->orientation, distance_sensor->covariance); + return mavlink_msg_distance_sensor_pack(system_id, component_id, msg, distance_sensor->time_boot_ms, distance_sensor->min_distance, distance_sensor->max_distance, distance_sensor->current_distance, distance_sensor->type, distance_sensor->id, distance_sensor->orientation, distance_sensor->covariance); } /** @@ -168,7 +179,7 @@ static inline uint16_t mavlink_msg_distance_sensor_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_distance_sensor_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_distance_sensor_t* distance_sensor) { - return mavlink_msg_distance_sensor_pack_chan(system_id, component_id, chan, msg, distance_sensor->time_boot_ms, distance_sensor->min_distance, distance_sensor->max_distance, distance_sensor->current_distance, distance_sensor->type, distance_sensor->id, distance_sensor->orientation, distance_sensor->covariance); + return mavlink_msg_distance_sensor_pack_chan(system_id, component_id, chan, msg, distance_sensor->time_boot_ms, distance_sensor->min_distance, distance_sensor->max_distance, distance_sensor->current_distance, distance_sensor->type, distance_sensor->id, distance_sensor->orientation, distance_sensor->covariance); } /** @@ -181,7 +192,7 @@ static inline uint16_t mavlink_msg_distance_sensor_encode_chan(uint8_t system_id * @param current_distance Current distance reading * @param type Type from MAV_DISTANCE_SENSOR enum. * @param id Onboard ID of the sensor - * @param orientation Direction the sensor faces from FIXME enum. + * @param orientation Direction the sensor faces from MAV_SENSOR_ORIENTATION enum. * @param covariance Measurement covariance in centimeters, 0 for unknown / invalid readings */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -189,37 +200,43 @@ static inline uint16_t mavlink_msg_distance_sensor_encode_chan(uint8_t system_id static inline void mavlink_msg_distance_sensor_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint16_t min_distance, uint16_t max_distance, uint16_t current_distance, uint8_t type, uint8_t id, uint8_t orientation, uint8_t covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, min_distance); - _mav_put_uint16_t(buf, 6, max_distance); - _mav_put_uint16_t(buf, 8, current_distance); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, id); - _mav_put_uint8_t(buf, 12, orientation); - _mav_put_uint8_t(buf, 13, covariance); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); + char buf[MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, min_distance); + _mav_put_uint16_t(buf, 6, max_distance); + _mav_put_uint16_t(buf, 8, current_distance); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, id); + _mav_put_uint8_t(buf, 12, orientation); + _mav_put_uint8_t(buf, 13, covariance); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); + mavlink_distance_sensor_t packet; + packet.time_boot_ms = time_boot_ms; + packet.min_distance = min_distance; + packet.max_distance = max_distance; + packet.current_distance = current_distance; + packet.type = type; + packet.id = id; + packet.orientation = orientation; + packet.covariance = covariance; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, (const char *)&packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); #endif +} + +/** + * @brief Send a distance_sensor message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_distance_sensor_send_struct(mavlink_channel_t chan, const mavlink_distance_sensor_t* distance_sensor) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_distance_sensor_send(chan, distance_sensor->time_boot_ms, distance_sensor->min_distance, distance_sensor->max_distance, distance_sensor->current_distance, distance_sensor->type, distance_sensor->id, distance_sensor->orientation, distance_sensor->covariance); #else - mavlink_distance_sensor_t packet; - packet.time_boot_ms = time_boot_ms; - packet.min_distance = min_distance; - packet.max_distance = max_distance; - packet.current_distance = current_distance; - packet.type = type; - packet.id = id; - packet.orientation = orientation; - packet.covariance = covariance; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, (const char *)&packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, (const char *)&packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, (const char *)distance_sensor, MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); #endif } @@ -234,37 +251,29 @@ static inline void mavlink_msg_distance_sensor_send(mavlink_channel_t chan, uint static inline void mavlink_msg_distance_sensor_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint16_t min_distance, uint16_t max_distance, uint16_t current_distance, uint8_t type, uint8_t id, uint8_t orientation, uint8_t covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, min_distance); - _mav_put_uint16_t(buf, 6, max_distance); - _mav_put_uint16_t(buf, 8, current_distance); - _mav_put_uint8_t(buf, 10, type); - _mav_put_uint8_t(buf, 11, id); - _mav_put_uint8_t(buf, 12, orientation); - _mav_put_uint8_t(buf, 13, covariance); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); -#endif -#else - mavlink_distance_sensor_t *packet = (mavlink_distance_sensor_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->min_distance = min_distance; - packet->max_distance = max_distance; - packet->current_distance = current_distance; - packet->type = type; - packet->id = id; - packet->orientation = orientation; - packet->covariance = covariance; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, (const char *)packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, min_distance); + _mav_put_uint16_t(buf, 6, max_distance); + _mav_put_uint16_t(buf, 8, current_distance); + _mav_put_uint8_t(buf, 10, type); + _mav_put_uint8_t(buf, 11, id); + _mav_put_uint8_t(buf, 12, orientation); + _mav_put_uint8_t(buf, 13, covariance); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, buf, MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, (const char *)packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); -#endif + mavlink_distance_sensor_t *packet = (mavlink_distance_sensor_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->min_distance = min_distance; + packet->max_distance = max_distance; + packet->current_distance = current_distance; + packet->type = type; + packet->id = id; + packet->orientation = orientation; + packet->covariance = covariance; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_DISTANCE_SENSOR, (const char *)packet, MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN, MAVLINK_MSG_ID_DISTANCE_SENSOR_CRC); #endif } #endif @@ -281,7 +290,7 @@ static inline void mavlink_msg_distance_sensor_send_buf(mavlink_message_t *msgbu */ static inline uint32_t mavlink_msg_distance_sensor_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -291,7 +300,7 @@ static inline uint32_t mavlink_msg_distance_sensor_get_time_boot_ms(const mavlin */ static inline uint16_t mavlink_msg_distance_sensor_get_min_distance(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -301,7 +310,7 @@ static inline uint16_t mavlink_msg_distance_sensor_get_min_distance(const mavlin */ static inline uint16_t mavlink_msg_distance_sensor_get_max_distance(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -311,7 +320,7 @@ static inline uint16_t mavlink_msg_distance_sensor_get_max_distance(const mavlin */ static inline uint16_t mavlink_msg_distance_sensor_get_current_distance(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -321,7 +330,7 @@ static inline uint16_t mavlink_msg_distance_sensor_get_current_distance(const ma */ static inline uint8_t mavlink_msg_distance_sensor_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 10); + return _MAV_RETURN_uint8_t(msg, 10); } /** @@ -331,17 +340,17 @@ static inline uint8_t mavlink_msg_distance_sensor_get_type(const mavlink_message */ static inline uint8_t mavlink_msg_distance_sensor_get_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 11); + return _MAV_RETURN_uint8_t(msg, 11); } /** * @brief Get field orientation from distance_sensor message * - * @return Direction the sensor faces from FIXME enum. + * @return Direction the sensor faces from MAV_SENSOR_ORIENTATION enum. */ static inline uint8_t mavlink_msg_distance_sensor_get_orientation(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -351,7 +360,7 @@ static inline uint8_t mavlink_msg_distance_sensor_get_orientation(const mavlink_ */ static inline uint8_t mavlink_msg_distance_sensor_get_covariance(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 13); + return _MAV_RETURN_uint8_t(msg, 13); } /** @@ -362,16 +371,18 @@ static inline uint8_t mavlink_msg_distance_sensor_get_covariance(const mavlink_m */ static inline void mavlink_msg_distance_sensor_decode(const mavlink_message_t* msg, mavlink_distance_sensor_t* distance_sensor) { -#if MAVLINK_NEED_BYTE_SWAP - distance_sensor->time_boot_ms = mavlink_msg_distance_sensor_get_time_boot_ms(msg); - distance_sensor->min_distance = mavlink_msg_distance_sensor_get_min_distance(msg); - distance_sensor->max_distance = mavlink_msg_distance_sensor_get_max_distance(msg); - distance_sensor->current_distance = mavlink_msg_distance_sensor_get_current_distance(msg); - distance_sensor->type = mavlink_msg_distance_sensor_get_type(msg); - distance_sensor->id = mavlink_msg_distance_sensor_get_id(msg); - distance_sensor->orientation = mavlink_msg_distance_sensor_get_orientation(msg); - distance_sensor->covariance = mavlink_msg_distance_sensor_get_covariance(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + distance_sensor->time_boot_ms = mavlink_msg_distance_sensor_get_time_boot_ms(msg); + distance_sensor->min_distance = mavlink_msg_distance_sensor_get_min_distance(msg); + distance_sensor->max_distance = mavlink_msg_distance_sensor_get_max_distance(msg); + distance_sensor->current_distance = mavlink_msg_distance_sensor_get_current_distance(msg); + distance_sensor->type = mavlink_msg_distance_sensor_get_type(msg); + distance_sensor->id = mavlink_msg_distance_sensor_get_id(msg); + distance_sensor->orientation = mavlink_msg_distance_sensor_get_orientation(msg); + distance_sensor->covariance = mavlink_msg_distance_sensor_get_covariance(msg); #else - memcpy(distance_sensor, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN? msg->len : MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN; + memset(distance_sensor, 0, MAVLINK_MSG_ID_DISTANCE_SENSOR_LEN); + memcpy(distance_sensor, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_encapsulated_data.h b/vendor/libraries/mavlink/common/mavlink_msg_encapsulated_data.h index dacd7c9f40..5e9bc926ec 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_encapsulated_data.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_encapsulated_data.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE ENCAPSULATED_DATA PACKING #define MAVLINK_MSG_ID_ENCAPSULATED_DATA 131 -typedef struct __mavlink_encapsulated_data_t -{ - uint16_t seqnr; ///< sequence number (starting with 0 on every transmission) - uint8_t data[253]; ///< image data bytes -} mavlink_encapsulated_data_t; +MAVPACKED( +typedef struct __mavlink_encapsulated_data_t { + uint16_t seqnr; /*< sequence number (starting with 0 on every transmission)*/ + uint8_t data[253]; /*< image data bytes*/ +}) mavlink_encapsulated_data_t; #define MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN 255 +#define MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN 255 #define MAVLINK_MSG_ID_131_LEN 255 +#define MAVLINK_MSG_ID_131_MIN_LEN 255 #define MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC 223 #define MAVLINK_MSG_ID_131_CRC 223 #define MAVLINK_MSG_ENCAPSULATED_DATA_FIELD_DATA_LEN 253 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_ENCAPSULATED_DATA { \ - "ENCAPSULATED_DATA", \ - 2, \ - { { "seqnr", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_encapsulated_data_t, seqnr) }, \ + 131, \ + "ENCAPSULATED_DATA", \ + 2, \ + { { "seqnr", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_encapsulated_data_t, seqnr) }, \ { "data", NULL, MAVLINK_TYPE_UINT8_T, 253, 2, offsetof(mavlink_encapsulated_data_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_ENCAPSULATED_DATA { \ + "ENCAPSULATED_DATA", \ + 2, \ + { { "seqnr", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_encapsulated_data_t, seqnr) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 253, 2, offsetof(mavlink_encapsulated_data_t, data) }, \ + } \ +} +#endif /** * @brief Pack a encapsulated_data message @@ -36,26 +49,22 @@ typedef struct __mavlink_encapsulated_data_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_encapsulated_data_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t seqnr, const uint8_t *data) + uint16_t seqnr, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN]; - _mav_put_uint16_t(buf, 0, seqnr); - _mav_put_uint8_t_array(buf, 2, data, 253); + char buf[MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN]; + _mav_put_uint16_t(buf, 0, seqnr); + _mav_put_uint8_t_array(buf, 2, data, 253); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); #else - mavlink_encapsulated_data_t packet; - packet.seqnr = seqnr; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*253); + mavlink_encapsulated_data_t packet; + packet.seqnr = seqnr; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*253); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ENCAPSULATED_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ENCAPSULATED_DATA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); } /** @@ -69,27 +78,23 @@ static inline uint16_t mavlink_msg_encapsulated_data_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_encapsulated_data_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t seqnr,const uint8_t *data) + mavlink_message_t* msg, + uint16_t seqnr,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN]; - _mav_put_uint16_t(buf, 0, seqnr); - _mav_put_uint8_t_array(buf, 2, data, 253); + char buf[MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN]; + _mav_put_uint16_t(buf, 0, seqnr); + _mav_put_uint8_t_array(buf, 2, data, 253); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); #else - mavlink_encapsulated_data_t packet; - packet.seqnr = seqnr; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*253); + mavlink_encapsulated_data_t packet; + packet.seqnr = seqnr; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*253); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_ENCAPSULATED_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_ENCAPSULATED_DATA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); } /** @@ -102,7 +107,7 @@ static inline uint16_t mavlink_msg_encapsulated_data_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_encapsulated_data_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_encapsulated_data_t* encapsulated_data) { - return mavlink_msg_encapsulated_data_pack(system_id, component_id, msg, encapsulated_data->seqnr, encapsulated_data->data); + return mavlink_msg_encapsulated_data_pack(system_id, component_id, msg, encapsulated_data->seqnr, encapsulated_data->data); } /** @@ -116,7 +121,7 @@ static inline uint16_t mavlink_msg_encapsulated_data_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_encapsulated_data_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_encapsulated_data_t* encapsulated_data) { - return mavlink_msg_encapsulated_data_pack_chan(system_id, component_id, chan, msg, encapsulated_data->seqnr, encapsulated_data->data); + return mavlink_msg_encapsulated_data_pack_chan(system_id, component_id, chan, msg, encapsulated_data->seqnr, encapsulated_data->data); } /** @@ -131,23 +136,29 @@ static inline uint16_t mavlink_msg_encapsulated_data_encode_chan(uint8_t system_ static inline void mavlink_msg_encapsulated_data_send(mavlink_channel_t chan, uint16_t seqnr, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN]; - _mav_put_uint16_t(buf, 0, seqnr); - _mav_put_uint8_t_array(buf, 2, data, 253); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); + char buf[MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN]; + _mav_put_uint16_t(buf, 0, seqnr); + _mav_put_uint8_t_array(buf, 2, data, 253); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); + mavlink_encapsulated_data_t packet; + packet.seqnr = seqnr; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*253); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, (const char *)&packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); #endif +} + +/** + * @brief Send a encapsulated_data message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_encapsulated_data_send_struct(mavlink_channel_t chan, const mavlink_encapsulated_data_t* encapsulated_data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_encapsulated_data_send(chan, encapsulated_data->seqnr, encapsulated_data->data); #else - mavlink_encapsulated_data_t packet; - packet.seqnr = seqnr; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*253); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, (const char *)&packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, (const char *)&packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, (const char *)encapsulated_data, MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); #endif } @@ -162,23 +173,15 @@ static inline void mavlink_msg_encapsulated_data_send(mavlink_channel_t chan, ui static inline void mavlink_msg_encapsulated_data_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t seqnr, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, seqnr); - _mav_put_uint8_t_array(buf, 2, data, 253); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); -#endif + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, seqnr); + _mav_put_uint8_t_array(buf, 2, data, 253); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, buf, MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); #else - mavlink_encapsulated_data_t *packet = (mavlink_encapsulated_data_t *)msgbuf; - packet->seqnr = seqnr; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*253); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, (const char *)packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, (const char *)packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); -#endif + mavlink_encapsulated_data_t *packet = (mavlink_encapsulated_data_t *)msgbuf; + packet->seqnr = seqnr; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*253); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ENCAPSULATED_DATA, (const char *)packet, MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN, MAVLINK_MSG_ID_ENCAPSULATED_DATA_CRC); #endif } #endif @@ -195,7 +198,7 @@ static inline void mavlink_msg_encapsulated_data_send_buf(mavlink_message_t *msg */ static inline uint16_t mavlink_msg_encapsulated_data_get_seqnr(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -205,7 +208,7 @@ static inline uint16_t mavlink_msg_encapsulated_data_get_seqnr(const mavlink_mes */ static inline uint16_t mavlink_msg_encapsulated_data_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 253, 2); + return _MAV_RETURN_uint8_t_array(msg, data, 253, 2); } /** @@ -216,10 +219,12 @@ static inline uint16_t mavlink_msg_encapsulated_data_get_data(const mavlink_mess */ static inline void mavlink_msg_encapsulated_data_decode(const mavlink_message_t* msg, mavlink_encapsulated_data_t* encapsulated_data) { -#if MAVLINK_NEED_BYTE_SWAP - encapsulated_data->seqnr = mavlink_msg_encapsulated_data_get_seqnr(msg); - mavlink_msg_encapsulated_data_get_data(msg, encapsulated_data->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + encapsulated_data->seqnr = mavlink_msg_encapsulated_data_get_seqnr(msg); + mavlink_msg_encapsulated_data_get_data(msg, encapsulated_data->data); #else - memcpy(encapsulated_data, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN? msg->len : MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN; + memset(encapsulated_data, 0, MAVLINK_MSG_ID_ENCAPSULATED_DATA_LEN); + memcpy(encapsulated_data, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_estimator_status.h b/vendor/libraries/mavlink/common/mavlink_msg_estimator_status.h new file mode 100644 index 0000000000..2b7c6c09a3 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_estimator_status.h @@ -0,0 +1,438 @@ +#pragma once +// MESSAGE ESTIMATOR_STATUS PACKING + +#define MAVLINK_MSG_ID_ESTIMATOR_STATUS 230 + +MAVPACKED( +typedef struct __mavlink_estimator_status_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float vel_ratio; /*< Velocity innovation test ratio*/ + float pos_horiz_ratio; /*< Horizontal position innovation test ratio*/ + float pos_vert_ratio; /*< Vertical position innovation test ratio*/ + float mag_ratio; /*< Magnetometer innovation test ratio*/ + float hagl_ratio; /*< Height above terrain innovation test ratio*/ + float tas_ratio; /*< True airspeed innovation test ratio*/ + float pos_horiz_accuracy; /*< Horizontal position 1-STD accuracy relative to the EKF local origin (m)*/ + float pos_vert_accuracy; /*< Vertical position 1-STD accuracy relative to the EKF local origin (m)*/ + uint16_t flags; /*< Integer bitmask indicating which EKF outputs are valid. See definition for ESTIMATOR_STATUS_FLAGS.*/ +}) mavlink_estimator_status_t; + +#define MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN 42 +#define MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN 42 +#define MAVLINK_MSG_ID_230_LEN 42 +#define MAVLINK_MSG_ID_230_MIN_LEN 42 + +#define MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC 163 +#define MAVLINK_MSG_ID_230_CRC 163 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_ESTIMATOR_STATUS { \ + 230, \ + "ESTIMATOR_STATUS", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_estimator_status_t, time_usec) }, \ + { "vel_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_estimator_status_t, vel_ratio) }, \ + { "pos_horiz_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_estimator_status_t, pos_horiz_ratio) }, \ + { "pos_vert_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_estimator_status_t, pos_vert_ratio) }, \ + { "mag_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_estimator_status_t, mag_ratio) }, \ + { "hagl_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_estimator_status_t, hagl_ratio) }, \ + { "tas_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_estimator_status_t, tas_ratio) }, \ + { "pos_horiz_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_estimator_status_t, pos_horiz_accuracy) }, \ + { "pos_vert_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_estimator_status_t, pos_vert_accuracy) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 40, offsetof(mavlink_estimator_status_t, flags) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_ESTIMATOR_STATUS { \ + "ESTIMATOR_STATUS", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_estimator_status_t, time_usec) }, \ + { "vel_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_estimator_status_t, vel_ratio) }, \ + { "pos_horiz_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_estimator_status_t, pos_horiz_ratio) }, \ + { "pos_vert_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_estimator_status_t, pos_vert_ratio) }, \ + { "mag_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_estimator_status_t, mag_ratio) }, \ + { "hagl_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_estimator_status_t, hagl_ratio) }, \ + { "tas_ratio", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_estimator_status_t, tas_ratio) }, \ + { "pos_horiz_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_estimator_status_t, pos_horiz_accuracy) }, \ + { "pos_vert_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_estimator_status_t, pos_vert_accuracy) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 40, offsetof(mavlink_estimator_status_t, flags) }, \ + } \ +} +#endif + +/** + * @brief Pack a estimator_status message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param flags Integer bitmask indicating which EKF outputs are valid. See definition for ESTIMATOR_STATUS_FLAGS. + * @param vel_ratio Velocity innovation test ratio + * @param pos_horiz_ratio Horizontal position innovation test ratio + * @param pos_vert_ratio Vertical position innovation test ratio + * @param mag_ratio Magnetometer innovation test ratio + * @param hagl_ratio Height above terrain innovation test ratio + * @param tas_ratio True airspeed innovation test ratio + * @param pos_horiz_accuracy Horizontal position 1-STD accuracy relative to the EKF local origin (m) + * @param pos_vert_accuracy Vertical position 1-STD accuracy relative to the EKF local origin (m) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_estimator_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, uint16_t flags, float vel_ratio, float pos_horiz_ratio, float pos_vert_ratio, float mag_ratio, float hagl_ratio, float tas_ratio, float pos_horiz_accuracy, float pos_vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vel_ratio); + _mav_put_float(buf, 12, pos_horiz_ratio); + _mav_put_float(buf, 16, pos_vert_ratio); + _mav_put_float(buf, 20, mag_ratio); + _mav_put_float(buf, 24, hagl_ratio); + _mav_put_float(buf, 28, tas_ratio); + _mav_put_float(buf, 32, pos_horiz_accuracy); + _mav_put_float(buf, 36, pos_vert_accuracy); + _mav_put_uint16_t(buf, 40, flags); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN); +#else + mavlink_estimator_status_t packet; + packet.time_usec = time_usec; + packet.vel_ratio = vel_ratio; + packet.pos_horiz_ratio = pos_horiz_ratio; + packet.pos_vert_ratio = pos_vert_ratio; + packet.mag_ratio = mag_ratio; + packet.hagl_ratio = hagl_ratio; + packet.tas_ratio = tas_ratio; + packet.pos_horiz_accuracy = pos_horiz_accuracy; + packet.pos_vert_accuracy = pos_vert_accuracy; + packet.flags = flags; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_ESTIMATOR_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC); +} + +/** + * @brief Pack a estimator_status message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param flags Integer bitmask indicating which EKF outputs are valid. See definition for ESTIMATOR_STATUS_FLAGS. + * @param vel_ratio Velocity innovation test ratio + * @param pos_horiz_ratio Horizontal position innovation test ratio + * @param pos_vert_ratio Vertical position innovation test ratio + * @param mag_ratio Magnetometer innovation test ratio + * @param hagl_ratio Height above terrain innovation test ratio + * @param tas_ratio True airspeed innovation test ratio + * @param pos_horiz_accuracy Horizontal position 1-STD accuracy relative to the EKF local origin (m) + * @param pos_vert_accuracy Vertical position 1-STD accuracy relative to the EKF local origin (m) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_estimator_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,uint16_t flags,float vel_ratio,float pos_horiz_ratio,float pos_vert_ratio,float mag_ratio,float hagl_ratio,float tas_ratio,float pos_horiz_accuracy,float pos_vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vel_ratio); + _mav_put_float(buf, 12, pos_horiz_ratio); + _mav_put_float(buf, 16, pos_vert_ratio); + _mav_put_float(buf, 20, mag_ratio); + _mav_put_float(buf, 24, hagl_ratio); + _mav_put_float(buf, 28, tas_ratio); + _mav_put_float(buf, 32, pos_horiz_accuracy); + _mav_put_float(buf, 36, pos_vert_accuracy); + _mav_put_uint16_t(buf, 40, flags); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN); +#else + mavlink_estimator_status_t packet; + packet.time_usec = time_usec; + packet.vel_ratio = vel_ratio; + packet.pos_horiz_ratio = pos_horiz_ratio; + packet.pos_vert_ratio = pos_vert_ratio; + packet.mag_ratio = mag_ratio; + packet.hagl_ratio = hagl_ratio; + packet.tas_ratio = tas_ratio; + packet.pos_horiz_accuracy = pos_horiz_accuracy; + packet.pos_vert_accuracy = pos_vert_accuracy; + packet.flags = flags; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_ESTIMATOR_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC); +} + +/** + * @brief Encode a estimator_status struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param estimator_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_estimator_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_estimator_status_t* estimator_status) +{ + return mavlink_msg_estimator_status_pack(system_id, component_id, msg, estimator_status->time_usec, estimator_status->flags, estimator_status->vel_ratio, estimator_status->pos_horiz_ratio, estimator_status->pos_vert_ratio, estimator_status->mag_ratio, estimator_status->hagl_ratio, estimator_status->tas_ratio, estimator_status->pos_horiz_accuracy, estimator_status->pos_vert_accuracy); +} + +/** + * @brief Encode a estimator_status struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param estimator_status C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_estimator_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_estimator_status_t* estimator_status) +{ + return mavlink_msg_estimator_status_pack_chan(system_id, component_id, chan, msg, estimator_status->time_usec, estimator_status->flags, estimator_status->vel_ratio, estimator_status->pos_horiz_ratio, estimator_status->pos_vert_ratio, estimator_status->mag_ratio, estimator_status->hagl_ratio, estimator_status->tas_ratio, estimator_status->pos_horiz_accuracy, estimator_status->pos_vert_accuracy); +} + +/** + * @brief Send a estimator_status message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param flags Integer bitmask indicating which EKF outputs are valid. See definition for ESTIMATOR_STATUS_FLAGS. + * @param vel_ratio Velocity innovation test ratio + * @param pos_horiz_ratio Horizontal position innovation test ratio + * @param pos_vert_ratio Vertical position innovation test ratio + * @param mag_ratio Magnetometer innovation test ratio + * @param hagl_ratio Height above terrain innovation test ratio + * @param tas_ratio True airspeed innovation test ratio + * @param pos_horiz_accuracy Horizontal position 1-STD accuracy relative to the EKF local origin (m) + * @param pos_vert_accuracy Vertical position 1-STD accuracy relative to the EKF local origin (m) + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_estimator_status_send(mavlink_channel_t chan, uint64_t time_usec, uint16_t flags, float vel_ratio, float pos_horiz_ratio, float pos_vert_ratio, float mag_ratio, float hagl_ratio, float tas_ratio, float pos_horiz_accuracy, float pos_vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vel_ratio); + _mav_put_float(buf, 12, pos_horiz_ratio); + _mav_put_float(buf, 16, pos_vert_ratio); + _mav_put_float(buf, 20, mag_ratio); + _mav_put_float(buf, 24, hagl_ratio); + _mav_put_float(buf, 28, tas_ratio); + _mav_put_float(buf, 32, pos_horiz_accuracy); + _mav_put_float(buf, 36, pos_vert_accuracy); + _mav_put_uint16_t(buf, 40, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ESTIMATOR_STATUS, buf, MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC); +#else + mavlink_estimator_status_t packet; + packet.time_usec = time_usec; + packet.vel_ratio = vel_ratio; + packet.pos_horiz_ratio = pos_horiz_ratio; + packet.pos_vert_ratio = pos_vert_ratio; + packet.mag_ratio = mag_ratio; + packet.hagl_ratio = hagl_ratio; + packet.tas_ratio = tas_ratio; + packet.pos_horiz_accuracy = pos_horiz_accuracy; + packet.pos_vert_accuracy = pos_vert_accuracy; + packet.flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ESTIMATOR_STATUS, (const char *)&packet, MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC); +#endif +} + +/** + * @brief Send a estimator_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_estimator_status_send_struct(mavlink_channel_t chan, const mavlink_estimator_status_t* estimator_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_estimator_status_send(chan, estimator_status->time_usec, estimator_status->flags, estimator_status->vel_ratio, estimator_status->pos_horiz_ratio, estimator_status->pos_vert_ratio, estimator_status->mag_ratio, estimator_status->hagl_ratio, estimator_status->tas_ratio, estimator_status->pos_horiz_accuracy, estimator_status->pos_vert_accuracy); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ESTIMATOR_STATUS, (const char *)estimator_status, MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC); +#endif +} + +#if MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_estimator_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint16_t flags, float vel_ratio, float pos_horiz_ratio, float pos_vert_ratio, float mag_ratio, float hagl_ratio, float tas_ratio, float pos_horiz_accuracy, float pos_vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vel_ratio); + _mav_put_float(buf, 12, pos_horiz_ratio); + _mav_put_float(buf, 16, pos_vert_ratio); + _mav_put_float(buf, 20, mag_ratio); + _mav_put_float(buf, 24, hagl_ratio); + _mav_put_float(buf, 28, tas_ratio); + _mav_put_float(buf, 32, pos_horiz_accuracy); + _mav_put_float(buf, 36, pos_vert_accuracy); + _mav_put_uint16_t(buf, 40, flags); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ESTIMATOR_STATUS, buf, MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC); +#else + mavlink_estimator_status_t *packet = (mavlink_estimator_status_t *)msgbuf; + packet->time_usec = time_usec; + packet->vel_ratio = vel_ratio; + packet->pos_horiz_ratio = pos_horiz_ratio; + packet->pos_vert_ratio = pos_vert_ratio; + packet->mag_ratio = mag_ratio; + packet->hagl_ratio = hagl_ratio; + packet->tas_ratio = tas_ratio; + packet->pos_horiz_accuracy = pos_horiz_accuracy; + packet->pos_vert_accuracy = pos_vert_accuracy; + packet->flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_ESTIMATOR_STATUS, (const char *)packet, MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN, MAVLINK_MSG_ID_ESTIMATOR_STATUS_CRC); +#endif +} +#endif + +#endif + +// MESSAGE ESTIMATOR_STATUS UNPACKING + + +/** + * @brief Get field time_usec from estimator_status message + * + * @return Timestamp (micros since boot or Unix epoch) + */ +static inline uint64_t mavlink_msg_estimator_status_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field flags from estimator_status message + * + * @return Integer bitmask indicating which EKF outputs are valid. See definition for ESTIMATOR_STATUS_FLAGS. + */ +static inline uint16_t mavlink_msg_estimator_status_get_flags(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 40); +} + +/** + * @brief Get field vel_ratio from estimator_status message + * + * @return Velocity innovation test ratio + */ +static inline float mavlink_msg_estimator_status_get_vel_ratio(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field pos_horiz_ratio from estimator_status message + * + * @return Horizontal position innovation test ratio + */ +static inline float mavlink_msg_estimator_status_get_pos_horiz_ratio(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field pos_vert_ratio from estimator_status message + * + * @return Vertical position innovation test ratio + */ +static inline float mavlink_msg_estimator_status_get_pos_vert_ratio(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field mag_ratio from estimator_status message + * + * @return Magnetometer innovation test ratio + */ +static inline float mavlink_msg_estimator_status_get_mag_ratio(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field hagl_ratio from estimator_status message + * + * @return Height above terrain innovation test ratio + */ +static inline float mavlink_msg_estimator_status_get_hagl_ratio(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field tas_ratio from estimator_status message + * + * @return True airspeed innovation test ratio + */ +static inline float mavlink_msg_estimator_status_get_tas_ratio(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Get field pos_horiz_accuracy from estimator_status message + * + * @return Horizontal position 1-STD accuracy relative to the EKF local origin (m) + */ +static inline float mavlink_msg_estimator_status_get_pos_horiz_accuracy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 32); +} + +/** + * @brief Get field pos_vert_accuracy from estimator_status message + * + * @return Vertical position 1-STD accuracy relative to the EKF local origin (m) + */ +static inline float mavlink_msg_estimator_status_get_pos_vert_accuracy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 36); +} + +/** + * @brief Decode a estimator_status message into a struct + * + * @param msg The message to decode + * @param estimator_status C-struct to decode the message contents into + */ +static inline void mavlink_msg_estimator_status_decode(const mavlink_message_t* msg, mavlink_estimator_status_t* estimator_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + estimator_status->time_usec = mavlink_msg_estimator_status_get_time_usec(msg); + estimator_status->vel_ratio = mavlink_msg_estimator_status_get_vel_ratio(msg); + estimator_status->pos_horiz_ratio = mavlink_msg_estimator_status_get_pos_horiz_ratio(msg); + estimator_status->pos_vert_ratio = mavlink_msg_estimator_status_get_pos_vert_ratio(msg); + estimator_status->mag_ratio = mavlink_msg_estimator_status_get_mag_ratio(msg); + estimator_status->hagl_ratio = mavlink_msg_estimator_status_get_hagl_ratio(msg); + estimator_status->tas_ratio = mavlink_msg_estimator_status_get_tas_ratio(msg); + estimator_status->pos_horiz_accuracy = mavlink_msg_estimator_status_get_pos_horiz_accuracy(msg); + estimator_status->pos_vert_accuracy = mavlink_msg_estimator_status_get_pos_vert_accuracy(msg); + estimator_status->flags = mavlink_msg_estimator_status_get_flags(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN? msg->len : MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN; + memset(estimator_status, 0, MAVLINK_MSG_ID_ESTIMATOR_STATUS_LEN); + memcpy(estimator_status, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_extended_sys_state.h b/vendor/libraries/mavlink/common/mavlink_msg_extended_sys_state.h new file mode 100644 index 0000000000..329a774afb --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_extended_sys_state.h @@ -0,0 +1,238 @@ +#pragma once +// MESSAGE EXTENDED_SYS_STATE PACKING + +#define MAVLINK_MSG_ID_EXTENDED_SYS_STATE 245 + +MAVPACKED( +typedef struct __mavlink_extended_sys_state_t { + uint8_t vtol_state; /*< The VTOL state if applicable. Is set to MAV_VTOL_STATE_UNDEFINED if UAV is not in VTOL configuration.*/ + uint8_t landed_state; /*< The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown.*/ +}) mavlink_extended_sys_state_t; + +#define MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN 2 +#define MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN 2 +#define MAVLINK_MSG_ID_245_LEN 2 +#define MAVLINK_MSG_ID_245_MIN_LEN 2 + +#define MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC 130 +#define MAVLINK_MSG_ID_245_CRC 130 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_EXTENDED_SYS_STATE { \ + 245, \ + "EXTENDED_SYS_STATE", \ + 2, \ + { { "vtol_state", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_extended_sys_state_t, vtol_state) }, \ + { "landed_state", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_extended_sys_state_t, landed_state) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_EXTENDED_SYS_STATE { \ + "EXTENDED_SYS_STATE", \ + 2, \ + { { "vtol_state", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_extended_sys_state_t, vtol_state) }, \ + { "landed_state", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_extended_sys_state_t, landed_state) }, \ + } \ +} +#endif + +/** + * @brief Pack a extended_sys_state message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param vtol_state The VTOL state if applicable. Is set to MAV_VTOL_STATE_UNDEFINED if UAV is not in VTOL configuration. + * @param landed_state The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_extended_sys_state_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t vtol_state, uint8_t landed_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN]; + _mav_put_uint8_t(buf, 0, vtol_state); + _mav_put_uint8_t(buf, 1, landed_state); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN); +#else + mavlink_extended_sys_state_t packet; + packet.vtol_state = vtol_state; + packet.landed_state = landed_state; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_EXTENDED_SYS_STATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC); +} + +/** + * @brief Pack a extended_sys_state message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param vtol_state The VTOL state if applicable. Is set to MAV_VTOL_STATE_UNDEFINED if UAV is not in VTOL configuration. + * @param landed_state The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_extended_sys_state_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t vtol_state,uint8_t landed_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN]; + _mav_put_uint8_t(buf, 0, vtol_state); + _mav_put_uint8_t(buf, 1, landed_state); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN); +#else + mavlink_extended_sys_state_t packet; + packet.vtol_state = vtol_state; + packet.landed_state = landed_state; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_EXTENDED_SYS_STATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC); +} + +/** + * @brief Encode a extended_sys_state struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param extended_sys_state C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_extended_sys_state_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_extended_sys_state_t* extended_sys_state) +{ + return mavlink_msg_extended_sys_state_pack(system_id, component_id, msg, extended_sys_state->vtol_state, extended_sys_state->landed_state); +} + +/** + * @brief Encode a extended_sys_state struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param extended_sys_state C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_extended_sys_state_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_extended_sys_state_t* extended_sys_state) +{ + return mavlink_msg_extended_sys_state_pack_chan(system_id, component_id, chan, msg, extended_sys_state->vtol_state, extended_sys_state->landed_state); +} + +/** + * @brief Send a extended_sys_state message + * @param chan MAVLink channel to send the message + * + * @param vtol_state The VTOL state if applicable. Is set to MAV_VTOL_STATE_UNDEFINED if UAV is not in VTOL configuration. + * @param landed_state The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_extended_sys_state_send(mavlink_channel_t chan, uint8_t vtol_state, uint8_t landed_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN]; + _mav_put_uint8_t(buf, 0, vtol_state); + _mav_put_uint8_t(buf, 1, landed_state); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EXTENDED_SYS_STATE, buf, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC); +#else + mavlink_extended_sys_state_t packet; + packet.vtol_state = vtol_state; + packet.landed_state = landed_state; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EXTENDED_SYS_STATE, (const char *)&packet, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC); +#endif +} + +/** + * @brief Send a extended_sys_state message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_extended_sys_state_send_struct(mavlink_channel_t chan, const mavlink_extended_sys_state_t* extended_sys_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_extended_sys_state_send(chan, extended_sys_state->vtol_state, extended_sys_state->landed_state); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EXTENDED_SYS_STATE, (const char *)extended_sys_state, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC); +#endif +} + +#if MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_extended_sys_state_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t vtol_state, uint8_t landed_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, vtol_state); + _mav_put_uint8_t(buf, 1, landed_state); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EXTENDED_SYS_STATE, buf, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC); +#else + mavlink_extended_sys_state_t *packet = (mavlink_extended_sys_state_t *)msgbuf; + packet->vtol_state = vtol_state; + packet->landed_state = landed_state; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_EXTENDED_SYS_STATE, (const char *)packet, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_CRC); +#endif +} +#endif + +#endif + +// MESSAGE EXTENDED_SYS_STATE UNPACKING + + +/** + * @brief Get field vtol_state from extended_sys_state message + * + * @return The VTOL state if applicable. Is set to MAV_VTOL_STATE_UNDEFINED if UAV is not in VTOL configuration. + */ +static inline uint8_t mavlink_msg_extended_sys_state_get_vtol_state(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field landed_state from extended_sys_state message + * + * @return The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + */ +static inline uint8_t mavlink_msg_extended_sys_state_get_landed_state(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Decode a extended_sys_state message into a struct + * + * @param msg The message to decode + * @param extended_sys_state C-struct to decode the message contents into + */ +static inline void mavlink_msg_extended_sys_state_decode(const mavlink_message_t* msg, mavlink_extended_sys_state_t* extended_sys_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + extended_sys_state->vtol_state = mavlink_msg_extended_sys_state_get_vtol_state(msg); + extended_sys_state->landed_state = mavlink_msg_extended_sys_state_get_landed_state(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN? msg->len : MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN; + memset(extended_sys_state, 0, MAVLINK_MSG_ID_EXTENDED_SYS_STATE_LEN); + memcpy(extended_sys_state, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_file_transfer_protocol.h b/vendor/libraries/mavlink/common/mavlink_msg_file_transfer_protocol.h index f77cd943c1..07b5a3ef64 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_file_transfer_protocol.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_file_transfer_protocol.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE FILE_TRANSFER_PROTOCOL PACKING #define MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL 110 -typedef struct __mavlink_file_transfer_protocol_t -{ - uint8_t target_network; ///< Network ID (0 for broadcast) - uint8_t target_system; ///< System ID (0 for broadcast) - uint8_t target_component; ///< Component ID (0 for broadcast) - uint8_t payload[251]; ///< Variable length payload. The length is defined by the remaining message length when subtracting the header and other fields. The entire content of this block is opaque unless you understand any the encoding message_type. The particular encoding used can be extension specific and might not always be documented as part of the mavlink specification. -} mavlink_file_transfer_protocol_t; +MAVPACKED( +typedef struct __mavlink_file_transfer_protocol_t { + uint8_t target_network; /*< Network ID (0 for broadcast)*/ + uint8_t target_system; /*< System ID (0 for broadcast)*/ + uint8_t target_component; /*< Component ID (0 for broadcast)*/ + uint8_t payload[251]; /*< Variable length payload. The length is defined by the remaining message length when subtracting the header and other fields. The entire content of this block is opaque unless you understand any the encoding message_type. The particular encoding used can be extension specific and might not always be documented as part of the mavlink specification.*/ +}) mavlink_file_transfer_protocol_t; #define MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN 254 +#define MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN 254 #define MAVLINK_MSG_ID_110_LEN 254 +#define MAVLINK_MSG_ID_110_MIN_LEN 254 #define MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC 84 #define MAVLINK_MSG_ID_110_CRC 84 #define MAVLINK_MSG_FILE_TRANSFER_PROTOCOL_FIELD_PAYLOAD_LEN 251 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_FILE_TRANSFER_PROTOCOL { \ - "FILE_TRANSFER_PROTOCOL", \ - 4, \ - { { "target_network", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_file_transfer_protocol_t, target_network) }, \ + 110, \ + "FILE_TRANSFER_PROTOCOL", \ + 4, \ + { { "target_network", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_file_transfer_protocol_t, target_network) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_file_transfer_protocol_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_file_transfer_protocol_t, target_component) }, \ { "payload", NULL, MAVLINK_TYPE_UINT8_T, 251, 3, offsetof(mavlink_file_transfer_protocol_t, payload) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_FILE_TRANSFER_PROTOCOL { \ + "FILE_TRANSFER_PROTOCOL", \ + 4, \ + { { "target_network", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_file_transfer_protocol_t, target_network) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_file_transfer_protocol_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_file_transfer_protocol_t, target_component) }, \ + { "payload", NULL, MAVLINK_TYPE_UINT8_T, 251, 3, offsetof(mavlink_file_transfer_protocol_t, payload) }, \ + } \ +} +#endif /** * @brief Pack a file_transfer_protocol message @@ -42,30 +57,26 @@ typedef struct __mavlink_file_transfer_protocol_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_file_transfer_protocol_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_network, uint8_t target_system, uint8_t target_component, const uint8_t *payload) + uint8_t target_network, uint8_t target_system, uint8_t target_component, const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN]; - _mav_put_uint8_t(buf, 0, target_network); - _mav_put_uint8_t(buf, 1, target_system); - _mav_put_uint8_t(buf, 2, target_component); - _mav_put_uint8_t_array(buf, 3, payload, 251); + char buf[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN]; + _mav_put_uint8_t(buf, 0, target_network); + _mav_put_uint8_t(buf, 1, target_system); + _mav_put_uint8_t(buf, 2, target_component); + _mav_put_uint8_t_array(buf, 3, payload, 251); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); #else - mavlink_file_transfer_protocol_t packet; - packet.target_network = target_network; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*251); + mavlink_file_transfer_protocol_t packet; + packet.target_network = target_network; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*251); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); } /** @@ -81,31 +92,27 @@ static inline uint16_t mavlink_msg_file_transfer_protocol_pack(uint8_t system_id * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_file_transfer_protocol_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_network,uint8_t target_system,uint8_t target_component,const uint8_t *payload) + mavlink_message_t* msg, + uint8_t target_network,uint8_t target_system,uint8_t target_component,const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN]; - _mav_put_uint8_t(buf, 0, target_network); - _mav_put_uint8_t(buf, 1, target_system); - _mav_put_uint8_t(buf, 2, target_component); - _mav_put_uint8_t_array(buf, 3, payload, 251); + char buf[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN]; + _mav_put_uint8_t(buf, 0, target_network); + _mav_put_uint8_t(buf, 1, target_system); + _mav_put_uint8_t(buf, 2, target_component); + _mav_put_uint8_t_array(buf, 3, payload, 251); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); #else - mavlink_file_transfer_protocol_t packet; - packet.target_network = target_network; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*251); + mavlink_file_transfer_protocol_t packet; + packet.target_network = target_network; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*251); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); } /** @@ -118,7 +125,7 @@ static inline uint16_t mavlink_msg_file_transfer_protocol_pack_chan(uint8_t syst */ static inline uint16_t mavlink_msg_file_transfer_protocol_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_file_transfer_protocol_t* file_transfer_protocol) { - return mavlink_msg_file_transfer_protocol_pack(system_id, component_id, msg, file_transfer_protocol->target_network, file_transfer_protocol->target_system, file_transfer_protocol->target_component, file_transfer_protocol->payload); + return mavlink_msg_file_transfer_protocol_pack(system_id, component_id, msg, file_transfer_protocol->target_network, file_transfer_protocol->target_system, file_transfer_protocol->target_component, file_transfer_protocol->payload); } /** @@ -132,7 +139,7 @@ static inline uint16_t mavlink_msg_file_transfer_protocol_encode(uint8_t system_ */ static inline uint16_t mavlink_msg_file_transfer_protocol_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_file_transfer_protocol_t* file_transfer_protocol) { - return mavlink_msg_file_transfer_protocol_pack_chan(system_id, component_id, chan, msg, file_transfer_protocol->target_network, file_transfer_protocol->target_system, file_transfer_protocol->target_component, file_transfer_protocol->payload); + return mavlink_msg_file_transfer_protocol_pack_chan(system_id, component_id, chan, msg, file_transfer_protocol->target_network, file_transfer_protocol->target_system, file_transfer_protocol->target_component, file_transfer_protocol->payload); } /** @@ -149,27 +156,33 @@ static inline uint16_t mavlink_msg_file_transfer_protocol_encode_chan(uint8_t sy static inline void mavlink_msg_file_transfer_protocol_send(mavlink_channel_t chan, uint8_t target_network, uint8_t target_system, uint8_t target_component, const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN]; - _mav_put_uint8_t(buf, 0, target_network); - _mav_put_uint8_t(buf, 1, target_system); - _mav_put_uint8_t(buf, 2, target_component); - _mav_put_uint8_t_array(buf, 3, payload, 251); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); + char buf[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN]; + _mav_put_uint8_t(buf, 0, target_network); + _mav_put_uint8_t(buf, 1, target_system); + _mav_put_uint8_t(buf, 2, target_component); + _mav_put_uint8_t_array(buf, 3, payload, 251); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); + mavlink_file_transfer_protocol_t packet; + packet.target_network = target_network; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*251); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, (const char *)&packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); #endif +} + +/** + * @brief Send a file_transfer_protocol message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_file_transfer_protocol_send_struct(mavlink_channel_t chan, const mavlink_file_transfer_protocol_t* file_transfer_protocol) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_file_transfer_protocol_send(chan, file_transfer_protocol->target_network, file_transfer_protocol->target_system, file_transfer_protocol->target_component, file_transfer_protocol->payload); #else - mavlink_file_transfer_protocol_t packet; - packet.target_network = target_network; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*251); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, (const char *)&packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, (const char *)&packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, (const char *)file_transfer_protocol, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); #endif } @@ -184,27 +197,19 @@ static inline void mavlink_msg_file_transfer_protocol_send(mavlink_channel_t cha static inline void mavlink_msg_file_transfer_protocol_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_network, uint8_t target_system, uint8_t target_component, const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_network); - _mav_put_uint8_t(buf, 1, target_system); - _mav_put_uint8_t(buf, 2, target_component); - _mav_put_uint8_t_array(buf, 3, payload, 251); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_network); + _mav_put_uint8_t(buf, 1, target_system); + _mav_put_uint8_t(buf, 2, target_component); + _mav_put_uint8_t_array(buf, 3, payload, 251); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, buf, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); -#endif -#else - mavlink_file_transfer_protocol_t *packet = (mavlink_file_transfer_protocol_t *)msgbuf; - packet->target_network = target_network; - packet->target_system = target_system; - packet->target_component = target_component; - mav_array_memcpy(packet->payload, payload, sizeof(uint8_t)*251); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, (const char *)packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, (const char *)packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); -#endif + mavlink_file_transfer_protocol_t *packet = (mavlink_file_transfer_protocol_t *)msgbuf; + packet->target_network = target_network; + packet->target_system = target_system; + packet->target_component = target_component; + mav_array_memcpy(packet->payload, payload, sizeof(uint8_t)*251); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL, (const char *)packet, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_CRC); #endif } #endif @@ -221,7 +226,7 @@ static inline void mavlink_msg_file_transfer_protocol_send_buf(mavlink_message_t */ static inline uint8_t mavlink_msg_file_transfer_protocol_get_target_network(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -231,7 +236,7 @@ static inline uint8_t mavlink_msg_file_transfer_protocol_get_target_network(cons */ static inline uint8_t mavlink_msg_file_transfer_protocol_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -241,7 +246,7 @@ static inline uint8_t mavlink_msg_file_transfer_protocol_get_target_system(const */ static inline uint8_t mavlink_msg_file_transfer_protocol_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -251,7 +256,7 @@ static inline uint8_t mavlink_msg_file_transfer_protocol_get_target_component(co */ static inline uint16_t mavlink_msg_file_transfer_protocol_get_payload(const mavlink_message_t* msg, uint8_t *payload) { - return _MAV_RETURN_uint8_t_array(msg, payload, 251, 3); + return _MAV_RETURN_uint8_t_array(msg, payload, 251, 3); } /** @@ -262,12 +267,14 @@ static inline uint16_t mavlink_msg_file_transfer_protocol_get_payload(const mavl */ static inline void mavlink_msg_file_transfer_protocol_decode(const mavlink_message_t* msg, mavlink_file_transfer_protocol_t* file_transfer_protocol) { -#if MAVLINK_NEED_BYTE_SWAP - file_transfer_protocol->target_network = mavlink_msg_file_transfer_protocol_get_target_network(msg); - file_transfer_protocol->target_system = mavlink_msg_file_transfer_protocol_get_target_system(msg); - file_transfer_protocol->target_component = mavlink_msg_file_transfer_protocol_get_target_component(msg); - mavlink_msg_file_transfer_protocol_get_payload(msg, file_transfer_protocol->payload); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + file_transfer_protocol->target_network = mavlink_msg_file_transfer_protocol_get_target_network(msg); + file_transfer_protocol->target_system = mavlink_msg_file_transfer_protocol_get_target_system(msg); + file_transfer_protocol->target_component = mavlink_msg_file_transfer_protocol_get_target_component(msg); + mavlink_msg_file_transfer_protocol_get_payload(msg, file_transfer_protocol->payload); #else - memcpy(file_transfer_protocol, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN? msg->len : MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN; + memset(file_transfer_protocol, 0, MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN); + memcpy(file_transfer_protocol, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_follow_target.h b/vendor/libraries/mavlink/common/mavlink_msg_follow_target.h new file mode 100644 index 0000000000..bfd45f649e --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_follow_target.h @@ -0,0 +1,459 @@ +#pragma once +// MESSAGE FOLLOW_TARGET PACKING + +#define MAVLINK_MSG_ID_FOLLOW_TARGET 144 + +MAVPACKED( +typedef struct __mavlink_follow_target_t { + uint64_t timestamp; /*< Timestamp in milliseconds since system boot*/ + uint64_t custom_state; /*< button states or switches of a tracker device*/ + int32_t lat; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t lon; /*< Longitude (WGS84), in degrees * 1E7*/ + float alt; /*< AMSL, in meters*/ + float vel[3]; /*< target velocity (0,0,0) for unknown*/ + float acc[3]; /*< linear target acceleration (0,0,0) for unknown*/ + float attitude_q[4]; /*< (1 0 0 0 for unknown)*/ + float rates[3]; /*< (0 0 0 for unknown)*/ + float position_cov[3]; /*< eph epv*/ + uint8_t est_capabilities; /*< bit positions for tracker reporting capabilities (POS = 0, VEL = 1, ACCEL = 2, ATT + RATES = 3)*/ +}) mavlink_follow_target_t; + +#define MAVLINK_MSG_ID_FOLLOW_TARGET_LEN 93 +#define MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN 93 +#define MAVLINK_MSG_ID_144_LEN 93 +#define MAVLINK_MSG_ID_144_MIN_LEN 93 + +#define MAVLINK_MSG_ID_FOLLOW_TARGET_CRC 127 +#define MAVLINK_MSG_ID_144_CRC 127 + +#define MAVLINK_MSG_FOLLOW_TARGET_FIELD_VEL_LEN 3 +#define MAVLINK_MSG_FOLLOW_TARGET_FIELD_ACC_LEN 3 +#define MAVLINK_MSG_FOLLOW_TARGET_FIELD_ATTITUDE_Q_LEN 4 +#define MAVLINK_MSG_FOLLOW_TARGET_FIELD_RATES_LEN 3 +#define MAVLINK_MSG_FOLLOW_TARGET_FIELD_POSITION_COV_LEN 3 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_FOLLOW_TARGET { \ + 144, \ + "FOLLOW_TARGET", \ + 11, \ + { { "timestamp", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_follow_target_t, timestamp) }, \ + { "custom_state", NULL, MAVLINK_TYPE_UINT64_T, 0, 8, offsetof(mavlink_follow_target_t, custom_state) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_follow_target_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_follow_target_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_follow_target_t, alt) }, \ + { "vel", NULL, MAVLINK_TYPE_FLOAT, 3, 28, offsetof(mavlink_follow_target_t, vel) }, \ + { "acc", NULL, MAVLINK_TYPE_FLOAT, 3, 40, offsetof(mavlink_follow_target_t, acc) }, \ + { "attitude_q", NULL, MAVLINK_TYPE_FLOAT, 4, 52, offsetof(mavlink_follow_target_t, attitude_q) }, \ + { "rates", NULL, MAVLINK_TYPE_FLOAT, 3, 68, offsetof(mavlink_follow_target_t, rates) }, \ + { "position_cov", NULL, MAVLINK_TYPE_FLOAT, 3, 80, offsetof(mavlink_follow_target_t, position_cov) }, \ + { "est_capabilities", NULL, MAVLINK_TYPE_UINT8_T, 0, 92, offsetof(mavlink_follow_target_t, est_capabilities) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_FOLLOW_TARGET { \ + "FOLLOW_TARGET", \ + 11, \ + { { "timestamp", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_follow_target_t, timestamp) }, \ + { "custom_state", NULL, MAVLINK_TYPE_UINT64_T, 0, 8, offsetof(mavlink_follow_target_t, custom_state) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_follow_target_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_follow_target_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_follow_target_t, alt) }, \ + { "vel", NULL, MAVLINK_TYPE_FLOAT, 3, 28, offsetof(mavlink_follow_target_t, vel) }, \ + { "acc", NULL, MAVLINK_TYPE_FLOAT, 3, 40, offsetof(mavlink_follow_target_t, acc) }, \ + { "attitude_q", NULL, MAVLINK_TYPE_FLOAT, 4, 52, offsetof(mavlink_follow_target_t, attitude_q) }, \ + { "rates", NULL, MAVLINK_TYPE_FLOAT, 3, 68, offsetof(mavlink_follow_target_t, rates) }, \ + { "position_cov", NULL, MAVLINK_TYPE_FLOAT, 3, 80, offsetof(mavlink_follow_target_t, position_cov) }, \ + { "est_capabilities", NULL, MAVLINK_TYPE_UINT8_T, 0, 92, offsetof(mavlink_follow_target_t, est_capabilities) }, \ + } \ +} +#endif + +/** + * @brief Pack a follow_target message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param timestamp Timestamp in milliseconds since system boot + * @param est_capabilities bit positions for tracker reporting capabilities (POS = 0, VEL = 1, ACCEL = 2, ATT + RATES = 3) + * @param lat Latitude (WGS84), in degrees * 1E7 + * @param lon Longitude (WGS84), in degrees * 1E7 + * @param alt AMSL, in meters + * @param vel target velocity (0,0,0) for unknown + * @param acc linear target acceleration (0,0,0) for unknown + * @param attitude_q (1 0 0 0 for unknown) + * @param rates (0 0 0 for unknown) + * @param position_cov eph epv + * @param custom_state button states or switches of a tracker device + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_follow_target_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t timestamp, uint8_t est_capabilities, int32_t lat, int32_t lon, float alt, const float *vel, const float *acc, const float *attitude_q, const float *rates, const float *position_cov, uint64_t custom_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_FOLLOW_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, timestamp); + _mav_put_uint64_t(buf, 8, custom_state); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lon); + _mav_put_float(buf, 24, alt); + _mav_put_uint8_t(buf, 92, est_capabilities); + _mav_put_float_array(buf, 28, vel, 3); + _mav_put_float_array(buf, 40, acc, 3); + _mav_put_float_array(buf, 52, attitude_q, 4); + _mav_put_float_array(buf, 68, rates, 3); + _mav_put_float_array(buf, 80, position_cov, 3); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN); +#else + mavlink_follow_target_t packet; + packet.timestamp = timestamp; + packet.custom_state = custom_state; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.est_capabilities = est_capabilities; + mav_array_memcpy(packet.vel, vel, sizeof(float)*3); + mav_array_memcpy(packet.acc, acc, sizeof(float)*3); + mav_array_memcpy(packet.attitude_q, attitude_q, sizeof(float)*4); + mav_array_memcpy(packet.rates, rates, sizeof(float)*3); + mav_array_memcpy(packet.position_cov, position_cov, sizeof(float)*3); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_FOLLOW_TARGET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_CRC); +} + +/** + * @brief Pack a follow_target message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param timestamp Timestamp in milliseconds since system boot + * @param est_capabilities bit positions for tracker reporting capabilities (POS = 0, VEL = 1, ACCEL = 2, ATT + RATES = 3) + * @param lat Latitude (WGS84), in degrees * 1E7 + * @param lon Longitude (WGS84), in degrees * 1E7 + * @param alt AMSL, in meters + * @param vel target velocity (0,0,0) for unknown + * @param acc linear target acceleration (0,0,0) for unknown + * @param attitude_q (1 0 0 0 for unknown) + * @param rates (0 0 0 for unknown) + * @param position_cov eph epv + * @param custom_state button states or switches of a tracker device + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_follow_target_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t timestamp,uint8_t est_capabilities,int32_t lat,int32_t lon,float alt,const float *vel,const float *acc,const float *attitude_q,const float *rates,const float *position_cov,uint64_t custom_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_FOLLOW_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, timestamp); + _mav_put_uint64_t(buf, 8, custom_state); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lon); + _mav_put_float(buf, 24, alt); + _mav_put_uint8_t(buf, 92, est_capabilities); + _mav_put_float_array(buf, 28, vel, 3); + _mav_put_float_array(buf, 40, acc, 3); + _mav_put_float_array(buf, 52, attitude_q, 4); + _mav_put_float_array(buf, 68, rates, 3); + _mav_put_float_array(buf, 80, position_cov, 3); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN); +#else + mavlink_follow_target_t packet; + packet.timestamp = timestamp; + packet.custom_state = custom_state; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.est_capabilities = est_capabilities; + mav_array_memcpy(packet.vel, vel, sizeof(float)*3); + mav_array_memcpy(packet.acc, acc, sizeof(float)*3); + mav_array_memcpy(packet.attitude_q, attitude_q, sizeof(float)*4); + mav_array_memcpy(packet.rates, rates, sizeof(float)*3); + mav_array_memcpy(packet.position_cov, position_cov, sizeof(float)*3); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_FOLLOW_TARGET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_CRC); +} + +/** + * @brief Encode a follow_target struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param follow_target C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_follow_target_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_follow_target_t* follow_target) +{ + return mavlink_msg_follow_target_pack(system_id, component_id, msg, follow_target->timestamp, follow_target->est_capabilities, follow_target->lat, follow_target->lon, follow_target->alt, follow_target->vel, follow_target->acc, follow_target->attitude_q, follow_target->rates, follow_target->position_cov, follow_target->custom_state); +} + +/** + * @brief Encode a follow_target struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param follow_target C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_follow_target_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_follow_target_t* follow_target) +{ + return mavlink_msg_follow_target_pack_chan(system_id, component_id, chan, msg, follow_target->timestamp, follow_target->est_capabilities, follow_target->lat, follow_target->lon, follow_target->alt, follow_target->vel, follow_target->acc, follow_target->attitude_q, follow_target->rates, follow_target->position_cov, follow_target->custom_state); +} + +/** + * @brief Send a follow_target message + * @param chan MAVLink channel to send the message + * + * @param timestamp Timestamp in milliseconds since system boot + * @param est_capabilities bit positions for tracker reporting capabilities (POS = 0, VEL = 1, ACCEL = 2, ATT + RATES = 3) + * @param lat Latitude (WGS84), in degrees * 1E7 + * @param lon Longitude (WGS84), in degrees * 1E7 + * @param alt AMSL, in meters + * @param vel target velocity (0,0,0) for unknown + * @param acc linear target acceleration (0,0,0) for unknown + * @param attitude_q (1 0 0 0 for unknown) + * @param rates (0 0 0 for unknown) + * @param position_cov eph epv + * @param custom_state button states or switches of a tracker device + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_follow_target_send(mavlink_channel_t chan, uint64_t timestamp, uint8_t est_capabilities, int32_t lat, int32_t lon, float alt, const float *vel, const float *acc, const float *attitude_q, const float *rates, const float *position_cov, uint64_t custom_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_FOLLOW_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, timestamp); + _mav_put_uint64_t(buf, 8, custom_state); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lon); + _mav_put_float(buf, 24, alt); + _mav_put_uint8_t(buf, 92, est_capabilities); + _mav_put_float_array(buf, 28, vel, 3); + _mav_put_float_array(buf, 40, acc, 3); + _mav_put_float_array(buf, 52, attitude_q, 4); + _mav_put_float_array(buf, 68, rates, 3); + _mav_put_float_array(buf, 80, position_cov, 3); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FOLLOW_TARGET, buf, MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_CRC); +#else + mavlink_follow_target_t packet; + packet.timestamp = timestamp; + packet.custom_state = custom_state; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.est_capabilities = est_capabilities; + mav_array_memcpy(packet.vel, vel, sizeof(float)*3); + mav_array_memcpy(packet.acc, acc, sizeof(float)*3); + mav_array_memcpy(packet.attitude_q, attitude_q, sizeof(float)*4); + mav_array_memcpy(packet.rates, rates, sizeof(float)*3); + mav_array_memcpy(packet.position_cov, position_cov, sizeof(float)*3); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FOLLOW_TARGET, (const char *)&packet, MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_CRC); +#endif +} + +/** + * @brief Send a follow_target message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_follow_target_send_struct(mavlink_channel_t chan, const mavlink_follow_target_t* follow_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_follow_target_send(chan, follow_target->timestamp, follow_target->est_capabilities, follow_target->lat, follow_target->lon, follow_target->alt, follow_target->vel, follow_target->acc, follow_target->attitude_q, follow_target->rates, follow_target->position_cov, follow_target->custom_state); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FOLLOW_TARGET, (const char *)follow_target, MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_CRC); +#endif +} + +#if MAVLINK_MSG_ID_FOLLOW_TARGET_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_follow_target_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t timestamp, uint8_t est_capabilities, int32_t lat, int32_t lon, float alt, const float *vel, const float *acc, const float *attitude_q, const float *rates, const float *position_cov, uint64_t custom_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, timestamp); + _mav_put_uint64_t(buf, 8, custom_state); + _mav_put_int32_t(buf, 16, lat); + _mav_put_int32_t(buf, 20, lon); + _mav_put_float(buf, 24, alt); + _mav_put_uint8_t(buf, 92, est_capabilities); + _mav_put_float_array(buf, 28, vel, 3); + _mav_put_float_array(buf, 40, acc, 3); + _mav_put_float_array(buf, 52, attitude_q, 4); + _mav_put_float_array(buf, 68, rates, 3); + _mav_put_float_array(buf, 80, position_cov, 3); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FOLLOW_TARGET, buf, MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_CRC); +#else + mavlink_follow_target_t *packet = (mavlink_follow_target_t *)msgbuf; + packet->timestamp = timestamp; + packet->custom_state = custom_state; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->est_capabilities = est_capabilities; + mav_array_memcpy(packet->vel, vel, sizeof(float)*3); + mav_array_memcpy(packet->acc, acc, sizeof(float)*3); + mav_array_memcpy(packet->attitude_q, attitude_q, sizeof(float)*4); + mav_array_memcpy(packet->rates, rates, sizeof(float)*3); + mav_array_memcpy(packet->position_cov, position_cov, sizeof(float)*3); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_FOLLOW_TARGET, (const char *)packet, MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN, MAVLINK_MSG_ID_FOLLOW_TARGET_CRC); +#endif +} +#endif + +#endif + +// MESSAGE FOLLOW_TARGET UNPACKING + + +/** + * @brief Get field timestamp from follow_target message + * + * @return Timestamp in milliseconds since system boot + */ +static inline uint64_t mavlink_msg_follow_target_get_timestamp(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field est_capabilities from follow_target message + * + * @return bit positions for tracker reporting capabilities (POS = 0, VEL = 1, ACCEL = 2, ATT + RATES = 3) + */ +static inline uint8_t mavlink_msg_follow_target_get_est_capabilities(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 92); +} + +/** + * @brief Get field lat from follow_target message + * + * @return Latitude (WGS84), in degrees * 1E7 + */ +static inline int32_t mavlink_msg_follow_target_get_lat(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 16); +} + +/** + * @brief Get field lon from follow_target message + * + * @return Longitude (WGS84), in degrees * 1E7 + */ +static inline int32_t mavlink_msg_follow_target_get_lon(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 20); +} + +/** + * @brief Get field alt from follow_target message + * + * @return AMSL, in meters + */ +static inline float mavlink_msg_follow_target_get_alt(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field vel from follow_target message + * + * @return target velocity (0,0,0) for unknown + */ +static inline uint16_t mavlink_msg_follow_target_get_vel(const mavlink_message_t* msg, float *vel) +{ + return _MAV_RETURN_float_array(msg, vel, 3, 28); +} + +/** + * @brief Get field acc from follow_target message + * + * @return linear target acceleration (0,0,0) for unknown + */ +static inline uint16_t mavlink_msg_follow_target_get_acc(const mavlink_message_t* msg, float *acc) +{ + return _MAV_RETURN_float_array(msg, acc, 3, 40); +} + +/** + * @brief Get field attitude_q from follow_target message + * + * @return (1 0 0 0 for unknown) + */ +static inline uint16_t mavlink_msg_follow_target_get_attitude_q(const mavlink_message_t* msg, float *attitude_q) +{ + return _MAV_RETURN_float_array(msg, attitude_q, 4, 52); +} + +/** + * @brief Get field rates from follow_target message + * + * @return (0 0 0 for unknown) + */ +static inline uint16_t mavlink_msg_follow_target_get_rates(const mavlink_message_t* msg, float *rates) +{ + return _MAV_RETURN_float_array(msg, rates, 3, 68); +} + +/** + * @brief Get field position_cov from follow_target message + * + * @return eph epv + */ +static inline uint16_t mavlink_msg_follow_target_get_position_cov(const mavlink_message_t* msg, float *position_cov) +{ + return _MAV_RETURN_float_array(msg, position_cov, 3, 80); +} + +/** + * @brief Get field custom_state from follow_target message + * + * @return button states or switches of a tracker device + */ +static inline uint64_t mavlink_msg_follow_target_get_custom_state(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 8); +} + +/** + * @brief Decode a follow_target message into a struct + * + * @param msg The message to decode + * @param follow_target C-struct to decode the message contents into + */ +static inline void mavlink_msg_follow_target_decode(const mavlink_message_t* msg, mavlink_follow_target_t* follow_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + follow_target->timestamp = mavlink_msg_follow_target_get_timestamp(msg); + follow_target->custom_state = mavlink_msg_follow_target_get_custom_state(msg); + follow_target->lat = mavlink_msg_follow_target_get_lat(msg); + follow_target->lon = mavlink_msg_follow_target_get_lon(msg); + follow_target->alt = mavlink_msg_follow_target_get_alt(msg); + mavlink_msg_follow_target_get_vel(msg, follow_target->vel); + mavlink_msg_follow_target_get_acc(msg, follow_target->acc); + mavlink_msg_follow_target_get_attitude_q(msg, follow_target->attitude_q); + mavlink_msg_follow_target_get_rates(msg, follow_target->rates); + mavlink_msg_follow_target_get_position_cov(msg, follow_target->position_cov); + follow_target->est_capabilities = mavlink_msg_follow_target_get_est_capabilities(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_FOLLOW_TARGET_LEN? msg->len : MAVLINK_MSG_ID_FOLLOW_TARGET_LEN; + memset(follow_target, 0, MAVLINK_MSG_ID_FOLLOW_TARGET_LEN); + memcpy(follow_target, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_global_position_int.h b/vendor/libraries/mavlink/common/mavlink_msg_global_position_int.h index f51b7821e2..ef6267d2e1 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_global_position_int.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_global_position_int.h @@ -1,32 +1,37 @@ +#pragma once // MESSAGE GLOBAL_POSITION_INT PACKING #define MAVLINK_MSG_ID_GLOBAL_POSITION_INT 33 -typedef struct __mavlink_global_position_int_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - int32_t lat; ///< Latitude, expressed as * 1E7 - int32_t lon; ///< Longitude, expressed as * 1E7 - int32_t alt; ///< Altitude in meters, expressed as * 1000 (millimeters), AMSL (not WGS84 - note that virtually all GPS modules provide the AMSL as well) - int32_t relative_alt; ///< Altitude above ground in meters, expressed as * 1000 (millimeters) - int16_t vx; ///< Ground X Speed (Latitude), expressed as m/s * 100 - int16_t vy; ///< Ground Y Speed (Longitude), expressed as m/s * 100 - int16_t vz; ///< Ground Z Speed (Altitude), expressed as m/s * 100 - uint16_t hdg; ///< Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX -} mavlink_global_position_int_t; +MAVPACKED( +typedef struct __mavlink_global_position_int_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + int32_t lat; /*< Latitude, expressed as degrees * 1E7*/ + int32_t lon; /*< Longitude, expressed as degrees * 1E7*/ + int32_t alt; /*< Altitude in meters, expressed as * 1000 (millimeters), AMSL (not WGS84 - note that virtually all GPS modules provide the AMSL as well)*/ + int32_t relative_alt; /*< Altitude above ground in meters, expressed as * 1000 (millimeters)*/ + int16_t vx; /*< Ground X Speed (Latitude, positive north), expressed as m/s * 100*/ + int16_t vy; /*< Ground Y Speed (Longitude, positive east), expressed as m/s * 100*/ + int16_t vz; /*< Ground Z Speed (Altitude, positive down), expressed as m/s * 100*/ + uint16_t hdg; /*< Vehicle heading (yaw angle) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX*/ +}) mavlink_global_position_int_t; #define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN 28 +#define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN 28 #define MAVLINK_MSG_ID_33_LEN 28 +#define MAVLINK_MSG_ID_33_MIN_LEN 28 #define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC 104 #define MAVLINK_MSG_ID_33_CRC 104 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT { \ - "GLOBAL_POSITION_INT", \ - 9, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_global_position_int_t, time_boot_ms) }, \ + 33, \ + "GLOBAL_POSITION_INT", \ + 9, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_global_position_int_t, time_boot_ms) }, \ { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_global_position_int_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_global_position_int_t, lon) }, \ { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_global_position_int_t, alt) }, \ @@ -37,7 +42,22 @@ typedef struct __mavlink_global_position_int_t { "hdg", NULL, MAVLINK_TYPE_UINT16_T, 0, 26, offsetof(mavlink_global_position_int_t, hdg) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT { \ + "GLOBAL_POSITION_INT", \ + 9, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_global_position_int_t, time_boot_ms) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_global_position_int_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_global_position_int_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_global_position_int_t, alt) }, \ + { "relative_alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_global_position_int_t, relative_alt) }, \ + { "vx", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_global_position_int_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_INT16_T, 0, 22, offsetof(mavlink_global_position_int_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_INT16_T, 0, 24, offsetof(mavlink_global_position_int_t, vz) }, \ + { "hdg", NULL, MAVLINK_TYPE_UINT16_T, 0, 26, offsetof(mavlink_global_position_int_t, hdg) }, \ + } \ +} +#endif /** * @brief Pack a global_position_int message @@ -46,53 +66,49 @@ typedef struct __mavlink_global_position_int_t * @param msg The MAVLink message to compress the data into * * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param lat Latitude, expressed as * 1E7 - * @param lon Longitude, expressed as * 1E7 + * @param lat Latitude, expressed as degrees * 1E7 + * @param lon Longitude, expressed as degrees * 1E7 * @param alt Altitude in meters, expressed as * 1000 (millimeters), AMSL (not WGS84 - note that virtually all GPS modules provide the AMSL as well) * @param relative_alt Altitude above ground in meters, expressed as * 1000 (millimeters) - * @param vx Ground X Speed (Latitude), expressed as m/s * 100 - * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 - * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX + * @param vx Ground X Speed (Latitude, positive north), expressed as m/s * 100 + * @param vy Ground Y Speed (Longitude, positive east), expressed as m/s * 100 + * @param vz Ground Z Speed (Altitude, positive down), expressed as m/s * 100 + * @param hdg Vehicle heading (yaw angle) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_position_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, int16_t vx, int16_t vy, int16_t vz, uint16_t hdg) + uint32_t time_boot_ms, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, int16_t vx, int16_t vy, int16_t vz, uint16_t hdg) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat); - _mav_put_int32_t(buf, 8, lon); - _mav_put_int32_t(buf, 12, alt); - _mav_put_int32_t(buf, 16, relative_alt); - _mav_put_int16_t(buf, 20, vx); - _mav_put_int16_t(buf, 22, vy); - _mav_put_int16_t(buf, 24, vz); - _mav_put_uint16_t(buf, 26, hdg); + char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, alt); + _mav_put_int32_t(buf, 16, relative_alt); + _mav_put_int16_t(buf, 20, vx); + _mav_put_int16_t(buf, 22, vy); + _mav_put_int16_t(buf, 24, vz); + _mav_put_uint16_t(buf, 26, hdg); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); #else - mavlink_global_position_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.relative_alt = relative_alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.hdg = hdg; + mavlink_global_position_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.relative_alt = relative_alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.hdg = hdg; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); } /** @@ -102,54 +118,50 @@ static inline uint16_t mavlink_msg_global_position_int_pack(uint8_t system_id, u * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param lat Latitude, expressed as * 1E7 - * @param lon Longitude, expressed as * 1E7 + * @param lat Latitude, expressed as degrees * 1E7 + * @param lon Longitude, expressed as degrees * 1E7 * @param alt Altitude in meters, expressed as * 1000 (millimeters), AMSL (not WGS84 - note that virtually all GPS modules provide the AMSL as well) * @param relative_alt Altitude above ground in meters, expressed as * 1000 (millimeters) - * @param vx Ground X Speed (Latitude), expressed as m/s * 100 - * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 - * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX + * @param vx Ground X Speed (Latitude, positive north), expressed as m/s * 100 + * @param vy Ground Y Speed (Longitude, positive east), expressed as m/s * 100 + * @param vz Ground Z Speed (Altitude, positive down), expressed as m/s * 100 + * @param hdg Vehicle heading (yaw angle) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_position_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,int32_t lat,int32_t lon,int32_t alt,int32_t relative_alt,int16_t vx,int16_t vy,int16_t vz,uint16_t hdg) + mavlink_message_t* msg, + uint32_t time_boot_ms,int32_t lat,int32_t lon,int32_t alt,int32_t relative_alt,int16_t vx,int16_t vy,int16_t vz,uint16_t hdg) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat); - _mav_put_int32_t(buf, 8, lon); - _mav_put_int32_t(buf, 12, alt); - _mav_put_int32_t(buf, 16, relative_alt); - _mav_put_int16_t(buf, 20, vx); - _mav_put_int16_t(buf, 22, vy); - _mav_put_int16_t(buf, 24, vz); - _mav_put_uint16_t(buf, 26, hdg); + char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, alt); + _mav_put_int32_t(buf, 16, relative_alt); + _mav_put_int16_t(buf, 20, vx); + _mav_put_int16_t(buf, 22, vy); + _mav_put_int16_t(buf, 24, vz); + _mav_put_uint16_t(buf, 26, hdg); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); #else - mavlink_global_position_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.relative_alt = relative_alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.hdg = hdg; + mavlink_global_position_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.relative_alt = relative_alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.hdg = hdg; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); } /** @@ -162,7 +174,7 @@ static inline uint16_t mavlink_msg_global_position_int_pack_chan(uint8_t system_ */ static inline uint16_t mavlink_msg_global_position_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_global_position_int_t* global_position_int) { - return mavlink_msg_global_position_int_pack(system_id, component_id, msg, global_position_int->time_boot_ms, global_position_int->lat, global_position_int->lon, global_position_int->alt, global_position_int->relative_alt, global_position_int->vx, global_position_int->vy, global_position_int->vz, global_position_int->hdg); + return mavlink_msg_global_position_int_pack(system_id, component_id, msg, global_position_int->time_boot_ms, global_position_int->lat, global_position_int->lon, global_position_int->alt, global_position_int->relative_alt, global_position_int->vx, global_position_int->vy, global_position_int->vz, global_position_int->hdg); } /** @@ -176,7 +188,7 @@ static inline uint16_t mavlink_msg_global_position_int_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_global_position_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_global_position_int_t* global_position_int) { - return mavlink_msg_global_position_int_pack_chan(system_id, component_id, chan, msg, global_position_int->time_boot_ms, global_position_int->lat, global_position_int->lon, global_position_int->alt, global_position_int->relative_alt, global_position_int->vx, global_position_int->vy, global_position_int->vz, global_position_int->hdg); + return mavlink_msg_global_position_int_pack_chan(system_id, component_id, chan, msg, global_position_int->time_boot_ms, global_position_int->lat, global_position_int->lon, global_position_int->alt, global_position_int->relative_alt, global_position_int->vx, global_position_int->vy, global_position_int->vz, global_position_int->hdg); } /** @@ -184,53 +196,59 @@ static inline uint16_t mavlink_msg_global_position_int_encode_chan(uint8_t syste * @param chan MAVLink channel to send the message * * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param lat Latitude, expressed as * 1E7 - * @param lon Longitude, expressed as * 1E7 + * @param lat Latitude, expressed as degrees * 1E7 + * @param lon Longitude, expressed as degrees * 1E7 * @param alt Altitude in meters, expressed as * 1000 (millimeters), AMSL (not WGS84 - note that virtually all GPS modules provide the AMSL as well) * @param relative_alt Altitude above ground in meters, expressed as * 1000 (millimeters) - * @param vx Ground X Speed (Latitude), expressed as m/s * 100 - * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 - * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param hdg Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX + * @param vx Ground X Speed (Latitude, positive north), expressed as m/s * 100 + * @param vy Ground Y Speed (Longitude, positive east), expressed as m/s * 100 + * @param vz Ground Z Speed (Altitude, positive down), expressed as m/s * 100 + * @param hdg Vehicle heading (yaw angle) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS static inline void mavlink_msg_global_position_int_send(mavlink_channel_t chan, uint32_t time_boot_ms, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, int16_t vx, int16_t vy, int16_t vz, uint16_t hdg) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat); - _mav_put_int32_t(buf, 8, lon); - _mav_put_int32_t(buf, 12, alt); - _mav_put_int32_t(buf, 16, relative_alt); - _mav_put_int16_t(buf, 20, vx); - _mav_put_int16_t(buf, 22, vy); - _mav_put_int16_t(buf, 24, vz); - _mav_put_uint16_t(buf, 26, hdg); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); + char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, alt); + _mav_put_int32_t(buf, 16, relative_alt); + _mav_put_int16_t(buf, 20, vx); + _mav_put_int16_t(buf, 22, vy); + _mav_put_int16_t(buf, 24, vz); + _mav_put_uint16_t(buf, 26, hdg); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); + mavlink_global_position_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.relative_alt = relative_alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.hdg = hdg; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); #endif +} + +/** + * @brief Send a global_position_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_global_position_int_send_struct(mavlink_channel_t chan, const mavlink_global_position_int_t* global_position_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_global_position_int_send(chan, global_position_int->time_boot_ms, global_position_int->lat, global_position_int->lon, global_position_int->alt, global_position_int->relative_alt, global_position_int->vx, global_position_int->vy, global_position_int->vz, global_position_int->hdg); #else - mavlink_global_position_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.relative_alt = relative_alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.hdg = hdg; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, (const char *)global_position_int, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); #endif } @@ -245,39 +263,31 @@ static inline void mavlink_msg_global_position_int_send(mavlink_channel_t chan, static inline void mavlink_msg_global_position_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, int16_t vx, int16_t vy, int16_t vz, uint16_t hdg) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat); - _mav_put_int32_t(buf, 8, lon); - _mav_put_int32_t(buf, 12, alt); - _mav_put_int32_t(buf, 16, relative_alt); - _mav_put_int16_t(buf, 20, vx); - _mav_put_int16_t(buf, 22, vy); - _mav_put_int16_t(buf, 24, vz); - _mav_put_uint16_t(buf, 26, hdg); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); -#endif -#else - mavlink_global_position_int_t *packet = (mavlink_global_position_int_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->relative_alt = relative_alt; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->hdg = hdg; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat); + _mav_put_int32_t(buf, 8, lon); + _mav_put_int32_t(buf, 12, alt); + _mav_put_int32_t(buf, 16, relative_alt); + _mav_put_int16_t(buf, 20, vx); + _mav_put_int16_t(buf, 22, vy); + _mav_put_int16_t(buf, 24, vz); + _mav_put_uint16_t(buf, 26, hdg); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); -#endif + mavlink_global_position_int_t *packet = (mavlink_global_position_int_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->relative_alt = relative_alt; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->hdg = hdg; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_CRC); #endif } #endif @@ -294,27 +304,27 @@ static inline void mavlink_msg_global_position_int_send_buf(mavlink_message_t *m */ static inline uint32_t mavlink_msg_global_position_int_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** * @brief Get field lat from global_position_int message * - * @return Latitude, expressed as * 1E7 + * @return Latitude, expressed as degrees * 1E7 */ static inline int32_t mavlink_msg_global_position_int_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** * @brief Get field lon from global_position_int message * - * @return Longitude, expressed as * 1E7 + * @return Longitude, expressed as degrees * 1E7 */ static inline int32_t mavlink_msg_global_position_int_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -324,7 +334,7 @@ static inline int32_t mavlink_msg_global_position_int_get_lon(const mavlink_mess */ static inline int32_t mavlink_msg_global_position_int_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -334,47 +344,47 @@ static inline int32_t mavlink_msg_global_position_int_get_alt(const mavlink_mess */ static inline int32_t mavlink_msg_global_position_int_get_relative_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** * @brief Get field vx from global_position_int message * - * @return Ground X Speed (Latitude), expressed as m/s * 100 + * @return Ground X Speed (Latitude, positive north), expressed as m/s * 100 */ static inline int16_t mavlink_msg_global_position_int_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 20); + return _MAV_RETURN_int16_t(msg, 20); } /** * @brief Get field vy from global_position_int message * - * @return Ground Y Speed (Longitude), expressed as m/s * 100 + * @return Ground Y Speed (Longitude, positive east), expressed as m/s * 100 */ static inline int16_t mavlink_msg_global_position_int_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 22); + return _MAV_RETURN_int16_t(msg, 22); } /** * @brief Get field vz from global_position_int message * - * @return Ground Z Speed (Altitude), expressed as m/s * 100 + * @return Ground Z Speed (Altitude, positive down), expressed as m/s * 100 */ static inline int16_t mavlink_msg_global_position_int_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 24); + return _MAV_RETURN_int16_t(msg, 24); } /** * @brief Get field hdg from global_position_int message * - * @return Compass heading in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX + * @return Vehicle heading (yaw angle) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_global_position_int_get_hdg(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 26); + return _MAV_RETURN_uint16_t(msg, 26); } /** @@ -385,17 +395,19 @@ static inline uint16_t mavlink_msg_global_position_int_get_hdg(const mavlink_mes */ static inline void mavlink_msg_global_position_int_decode(const mavlink_message_t* msg, mavlink_global_position_int_t* global_position_int) { -#if MAVLINK_NEED_BYTE_SWAP - global_position_int->time_boot_ms = mavlink_msg_global_position_int_get_time_boot_ms(msg); - global_position_int->lat = mavlink_msg_global_position_int_get_lat(msg); - global_position_int->lon = mavlink_msg_global_position_int_get_lon(msg); - global_position_int->alt = mavlink_msg_global_position_int_get_alt(msg); - global_position_int->relative_alt = mavlink_msg_global_position_int_get_relative_alt(msg); - global_position_int->vx = mavlink_msg_global_position_int_get_vx(msg); - global_position_int->vy = mavlink_msg_global_position_int_get_vy(msg); - global_position_int->vz = mavlink_msg_global_position_int_get_vz(msg); - global_position_int->hdg = mavlink_msg_global_position_int_get_hdg(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + global_position_int->time_boot_ms = mavlink_msg_global_position_int_get_time_boot_ms(msg); + global_position_int->lat = mavlink_msg_global_position_int_get_lat(msg); + global_position_int->lon = mavlink_msg_global_position_int_get_lon(msg); + global_position_int->alt = mavlink_msg_global_position_int_get_alt(msg); + global_position_int->relative_alt = mavlink_msg_global_position_int_get_relative_alt(msg); + global_position_int->vx = mavlink_msg_global_position_int_get_vx(msg); + global_position_int->vy = mavlink_msg_global_position_int_get_vy(msg); + global_position_int->vz = mavlink_msg_global_position_int_get_vz(msg); + global_position_int->hdg = mavlink_msg_global_position_int_get_hdg(msg); #else - memcpy(global_position_int, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN? msg->len : MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN; + memset(global_position_int, 0, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_LEN); + memcpy(global_position_int, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_global_position_int_cov.h b/vendor/libraries/mavlink/common/mavlink_msg_global_position_int_cov.h index 4d053ba75f..0d33faf58b 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_global_position_int_cov.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_global_position_int_cov.h @@ -1,47 +1,66 @@ +#pragma once // MESSAGE GLOBAL_POSITION_INT_COV PACKING #define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV 63 -typedef struct __mavlink_global_position_int_cov_t -{ - uint64_t time_utc; ///< Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - int32_t lat; ///< Latitude, expressed as degrees * 1E7 - int32_t lon; ///< Longitude, expressed as degrees * 1E7 - int32_t alt; ///< Altitude in meters, expressed as * 1000 (millimeters), above MSL - int32_t relative_alt; ///< Altitude above ground in meters, expressed as * 1000 (millimeters) - float vx; ///< Ground X Speed (Latitude), expressed as m/s - float vy; ///< Ground Y Speed (Longitude), expressed as m/s - float vz; ///< Ground Z Speed (Altitude), expressed as m/s - float covariance[36]; ///< Covariance matrix (first six entries are the first ROW, next six entries are the second row, etc.) - uint8_t estimator_type; ///< Class id of the estimator this estimate originated from. -} mavlink_global_position_int_cov_t; +MAVPACKED( +typedef struct __mavlink_global_position_int_cov_t { + uint64_t time_usec; /*< Timestamp (microseconds since system boot or since UNIX epoch)*/ + int32_t lat; /*< Latitude, expressed as degrees * 1E7*/ + int32_t lon; /*< Longitude, expressed as degrees * 1E7*/ + int32_t alt; /*< Altitude in meters, expressed as * 1000 (millimeters), above MSL*/ + int32_t relative_alt; /*< Altitude above ground in meters, expressed as * 1000 (millimeters)*/ + float vx; /*< Ground X Speed (Latitude), expressed as m/s*/ + float vy; /*< Ground Y Speed (Longitude), expressed as m/s*/ + float vz; /*< Ground Z Speed (Altitude), expressed as m/s*/ + float covariance[36]; /*< Covariance matrix (first six entries are the first ROW, next six entries are the second row, etc.)*/ + uint8_t estimator_type; /*< Class id of the estimator this estimate originated from.*/ +}) mavlink_global_position_int_cov_t; -#define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN 185 -#define MAVLINK_MSG_ID_63_LEN 185 +#define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN 181 +#define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN 181 +#define MAVLINK_MSG_ID_63_LEN 181 +#define MAVLINK_MSG_ID_63_MIN_LEN 181 -#define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC 51 -#define MAVLINK_MSG_ID_63_CRC 51 +#define MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC 119 +#define MAVLINK_MSG_ID_63_CRC 119 #define MAVLINK_MSG_GLOBAL_POSITION_INT_COV_FIELD_COVARIANCE_LEN 36 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT_COV { \ - "GLOBAL_POSITION_INT_COV", \ - 11, \ - { { "time_utc", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_global_position_int_cov_t, time_utc) }, \ - { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_global_position_int_cov_t, time_boot_ms) }, \ - { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_global_position_int_cov_t, lat) }, \ - { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_global_position_int_cov_t, lon) }, \ - { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_global_position_int_cov_t, alt) }, \ - { "relative_alt", NULL, MAVLINK_TYPE_INT32_T, 0, 24, offsetof(mavlink_global_position_int_cov_t, relative_alt) }, \ - { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_global_position_int_cov_t, vx) }, \ - { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_global_position_int_cov_t, vy) }, \ - { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_global_position_int_cov_t, vz) }, \ - { "covariance", NULL, MAVLINK_TYPE_FLOAT, 36, 40, offsetof(mavlink_global_position_int_cov_t, covariance) }, \ - { "estimator_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 184, offsetof(mavlink_global_position_int_cov_t, estimator_type) }, \ + 63, \ + "GLOBAL_POSITION_INT_COV", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_global_position_int_cov_t, time_usec) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_global_position_int_cov_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_global_position_int_cov_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_global_position_int_cov_t, alt) }, \ + { "relative_alt", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_global_position_int_cov_t, relative_alt) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_global_position_int_cov_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_global_position_int_cov_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_global_position_int_cov_t, vz) }, \ + { "covariance", NULL, MAVLINK_TYPE_FLOAT, 36, 36, offsetof(mavlink_global_position_int_cov_t, covariance) }, \ + { "estimator_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 180, offsetof(mavlink_global_position_int_cov_t, estimator_type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GLOBAL_POSITION_INT_COV { \ + "GLOBAL_POSITION_INT_COV", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_global_position_int_cov_t, time_usec) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_global_position_int_cov_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_global_position_int_cov_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_global_position_int_cov_t, alt) }, \ + { "relative_alt", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_global_position_int_cov_t, relative_alt) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_global_position_int_cov_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_global_position_int_cov_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_global_position_int_cov_t, vz) }, \ + { "covariance", NULL, MAVLINK_TYPE_FLOAT, 36, 36, offsetof(mavlink_global_position_int_cov_t, covariance) }, \ + { "estimator_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 180, offsetof(mavlink_global_position_int_cov_t, estimator_type) }, \ + } \ +} +#endif /** * @brief Pack a global_position_int_cov message @@ -49,8 +68,7 @@ typedef struct __mavlink_global_position_int_cov_t * @param component_id ID of this component (e.g. 200 for IMU) * @param msg The MAVLink message to compress the data into * - * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param time_utc Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param estimator_type Class id of the estimator this estimate originated from. * @param lat Latitude, expressed as degrees * 1E7 * @param lon Longitude, expressed as degrees * 1E7 @@ -63,44 +81,38 @@ typedef struct __mavlink_global_position_int_cov_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_position_int_cov_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint64_t time_utc, uint8_t estimator_type, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, float vx, float vy, float vz, const float *covariance) + uint64_t time_usec, uint8_t estimator_type, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, float vx, float vy, float vz, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN]; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_int32_t(buf, 12, lat); - _mav_put_int32_t(buf, 16, lon); - _mav_put_int32_t(buf, 20, alt); - _mav_put_int32_t(buf, 24, relative_alt); - _mav_put_float(buf, 28, vx); - _mav_put_float(buf, 32, vy); - _mav_put_float(buf, 36, vz); - _mav_put_uint8_t(buf, 184, estimator_type); - _mav_put_float_array(buf, 40, covariance, 36); + char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_int32_t(buf, 20, relative_alt); + _mav_put_float(buf, 24, vx); + _mav_put_float(buf, 28, vy); + _mav_put_float(buf, 32, vz); + _mav_put_uint8_t(buf, 180, estimator_type); + _mav_put_float_array(buf, 36, covariance, 36); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); #else - mavlink_global_position_int_cov_t packet; - packet.time_utc = time_utc; - packet.time_boot_ms = time_boot_ms; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.relative_alt = relative_alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.estimator_type = estimator_type; - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); + mavlink_global_position_int_cov_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.relative_alt = relative_alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.estimator_type = estimator_type; + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); } /** @@ -109,8 +121,7 @@ static inline uint16_t mavlink_msg_global_position_int_cov_pack(uint8_t system_i * @param component_id ID of this component (e.g. 200 for IMU) * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into - * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param time_utc Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param estimator_type Class id of the estimator this estimate originated from. * @param lat Latitude, expressed as degrees * 1E7 * @param lon Longitude, expressed as degrees * 1E7 @@ -123,45 +134,39 @@ static inline uint16_t mavlink_msg_global_position_int_cov_pack(uint8_t system_i * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_position_int_cov_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint64_t time_utc,uint8_t estimator_type,int32_t lat,int32_t lon,int32_t alt,int32_t relative_alt,float vx,float vy,float vz,const float *covariance) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t estimator_type,int32_t lat,int32_t lon,int32_t alt,int32_t relative_alt,float vx,float vy,float vz,const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN]; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_int32_t(buf, 12, lat); - _mav_put_int32_t(buf, 16, lon); - _mav_put_int32_t(buf, 20, alt); - _mav_put_int32_t(buf, 24, relative_alt); - _mav_put_float(buf, 28, vx); - _mav_put_float(buf, 32, vy); - _mav_put_float(buf, 36, vz); - _mav_put_uint8_t(buf, 184, estimator_type); - _mav_put_float_array(buf, 40, covariance, 36); + char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_int32_t(buf, 20, relative_alt); + _mav_put_float(buf, 24, vx); + _mav_put_float(buf, 28, vy); + _mav_put_float(buf, 32, vz); + _mav_put_uint8_t(buf, 180, estimator_type); + _mav_put_float_array(buf, 36, covariance, 36); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); #else - mavlink_global_position_int_cov_t packet; - packet.time_utc = time_utc; - packet.time_boot_ms = time_boot_ms; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.relative_alt = relative_alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.estimator_type = estimator_type; - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); + mavlink_global_position_int_cov_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.relative_alt = relative_alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.estimator_type = estimator_type; + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); } /** @@ -174,7 +179,7 @@ static inline uint16_t mavlink_msg_global_position_int_cov_pack_chan(uint8_t sys */ static inline uint16_t mavlink_msg_global_position_int_cov_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_global_position_int_cov_t* global_position_int_cov) { - return mavlink_msg_global_position_int_cov_pack(system_id, component_id, msg, global_position_int_cov->time_boot_ms, global_position_int_cov->time_utc, global_position_int_cov->estimator_type, global_position_int_cov->lat, global_position_int_cov->lon, global_position_int_cov->alt, global_position_int_cov->relative_alt, global_position_int_cov->vx, global_position_int_cov->vy, global_position_int_cov->vz, global_position_int_cov->covariance); + return mavlink_msg_global_position_int_cov_pack(system_id, component_id, msg, global_position_int_cov->time_usec, global_position_int_cov->estimator_type, global_position_int_cov->lat, global_position_int_cov->lon, global_position_int_cov->alt, global_position_int_cov->relative_alt, global_position_int_cov->vx, global_position_int_cov->vy, global_position_int_cov->vz, global_position_int_cov->covariance); } /** @@ -188,15 +193,14 @@ static inline uint16_t mavlink_msg_global_position_int_cov_encode(uint8_t system */ static inline uint16_t mavlink_msg_global_position_int_cov_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_global_position_int_cov_t* global_position_int_cov) { - return mavlink_msg_global_position_int_cov_pack_chan(system_id, component_id, chan, msg, global_position_int_cov->time_boot_ms, global_position_int_cov->time_utc, global_position_int_cov->estimator_type, global_position_int_cov->lat, global_position_int_cov->lon, global_position_int_cov->alt, global_position_int_cov->relative_alt, global_position_int_cov->vx, global_position_int_cov->vy, global_position_int_cov->vz, global_position_int_cov->covariance); + return mavlink_msg_global_position_int_cov_pack_chan(system_id, component_id, chan, msg, global_position_int_cov->time_usec, global_position_int_cov->estimator_type, global_position_int_cov->lat, global_position_int_cov->lon, global_position_int_cov->alt, global_position_int_cov->relative_alt, global_position_int_cov->vx, global_position_int_cov->vy, global_position_int_cov->vz, global_position_int_cov->covariance); } /** * @brief Send a global_position_int_cov message * @param chan MAVLink channel to send the message * - * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param time_utc Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param estimator_type Class id of the estimator this estimate originated from. * @param lat Latitude, expressed as degrees * 1E7 * @param lon Longitude, expressed as degrees * 1E7 @@ -209,44 +213,48 @@ static inline uint16_t mavlink_msg_global_position_int_cov_encode_chan(uint8_t s */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS -static inline void mavlink_msg_global_position_int_cov_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint64_t time_utc, uint8_t estimator_type, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, float vx, float vy, float vz, const float *covariance) +static inline void mavlink_msg_global_position_int_cov_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t estimator_type, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, float vx, float vy, float vz, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN]; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_int32_t(buf, 12, lat); - _mav_put_int32_t(buf, 16, lon); - _mav_put_int32_t(buf, 20, alt); - _mav_put_int32_t(buf, 24, relative_alt); - _mav_put_float(buf, 28, vx); - _mav_put_float(buf, 32, vy); - _mav_put_float(buf, 36, vz); - _mav_put_uint8_t(buf, 184, estimator_type); - _mav_put_float_array(buf, 40, covariance, 36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); + char buf[MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_int32_t(buf, 20, relative_alt); + _mav_put_float(buf, 24, vx); + _mav_put_float(buf, 28, vy); + _mav_put_float(buf, 32, vz); + _mav_put_uint8_t(buf, 180, estimator_type); + _mav_put_float_array(buf, 36, covariance, 36); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); + mavlink_global_position_int_cov_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.relative_alt = relative_alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.estimator_type = estimator_type; + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); #endif +} + +/** + * @brief Send a global_position_int_cov message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_global_position_int_cov_send_struct(mavlink_channel_t chan, const mavlink_global_position_int_cov_t* global_position_int_cov) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_global_position_int_cov_send(chan, global_position_int_cov->time_usec, global_position_int_cov->estimator_type, global_position_int_cov->lat, global_position_int_cov->lon, global_position_int_cov->alt, global_position_int_cov->relative_alt, global_position_int_cov->vx, global_position_int_cov->vy, global_position_int_cov->vz, global_position_int_cov->covariance); #else - mavlink_global_position_int_cov_t packet; - packet.time_utc = time_utc; - packet.time_boot_ms = time_boot_ms; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.relative_alt = relative_alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.estimator_type = estimator_type; - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, (const char *)global_position_int_cov, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); #endif } @@ -258,44 +266,34 @@ static inline void mavlink_msg_global_position_int_cov_send(mavlink_channel_t ch is usually the receive buffer for the channel, and allows a reply to an incoming message with minimum stack space usage. */ -static inline void mavlink_msg_global_position_int_cov_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint64_t time_utc, uint8_t estimator_type, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, float vx, float vy, float vz, const float *covariance) +static inline void mavlink_msg_global_position_int_cov_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t estimator_type, int32_t lat, int32_t lon, int32_t alt, int32_t relative_alt, float vx, float vy, float vz, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_int32_t(buf, 12, lat); - _mav_put_int32_t(buf, 16, lon); - _mav_put_int32_t(buf, 20, alt); - _mav_put_int32_t(buf, 24, relative_alt); - _mav_put_float(buf, 28, vx); - _mav_put_float(buf, 32, vy); - _mav_put_float(buf, 36, vz); - _mav_put_uint8_t(buf, 184, estimator_type); - _mav_put_float_array(buf, 40, covariance, 36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); -#endif -#else - mavlink_global_position_int_cov_t *packet = (mavlink_global_position_int_cov_t *)msgbuf; - packet->time_utc = time_utc; - packet->time_boot_ms = time_boot_ms; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->relative_alt = relative_alt; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->estimator_type = estimator_type; - mav_array_memcpy(packet->covariance, covariance, sizeof(float)*36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_int32_t(buf, 20, relative_alt); + _mav_put_float(buf, 24, vx); + _mav_put_float(buf, 28, vy); + _mav_put_float(buf, 32, vz); + _mav_put_uint8_t(buf, 180, estimator_type); + _mav_put_float_array(buf, 36, covariance, 36); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, buf, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); -#endif + mavlink_global_position_int_cov_t *packet = (mavlink_global_position_int_cov_t *)msgbuf; + packet->time_usec = time_usec; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->relative_alt = relative_alt; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->estimator_type = estimator_type; + mav_array_memcpy(packet->covariance, covariance, sizeof(float)*36); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_CRC); #endif } #endif @@ -306,23 +304,13 @@ static inline void mavlink_msg_global_position_int_cov_send_buf(mavlink_message_ /** - * @brief Get field time_boot_ms from global_position_int_cov message - * - * @return Timestamp (milliseconds since system boot) - */ -static inline uint32_t mavlink_msg_global_position_int_cov_get_time_boot_ms(const mavlink_message_t* msg) -{ - return _MAV_RETURN_uint32_t(msg, 8); -} - -/** - * @brief Get field time_utc from global_position_int_cov message + * @brief Get field time_usec from global_position_int_cov message * - * @return Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @return Timestamp (microseconds since system boot or since UNIX epoch) */ -static inline uint64_t mavlink_msg_global_position_int_cov_get_time_utc(const mavlink_message_t* msg) +static inline uint64_t mavlink_msg_global_position_int_cov_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -332,7 +320,7 @@ static inline uint64_t mavlink_msg_global_position_int_cov_get_time_utc(const ma */ static inline uint8_t mavlink_msg_global_position_int_cov_get_estimator_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 184); + return _MAV_RETURN_uint8_t(msg, 180); } /** @@ -342,7 +330,7 @@ static inline uint8_t mavlink_msg_global_position_int_cov_get_estimator_type(con */ static inline int32_t mavlink_msg_global_position_int_cov_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -352,7 +340,7 @@ static inline int32_t mavlink_msg_global_position_int_cov_get_lat(const mavlink_ */ static inline int32_t mavlink_msg_global_position_int_cov_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -362,7 +350,7 @@ static inline int32_t mavlink_msg_global_position_int_cov_get_lon(const mavlink_ */ static inline int32_t mavlink_msg_global_position_int_cov_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 20); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -372,7 +360,7 @@ static inline int32_t mavlink_msg_global_position_int_cov_get_alt(const mavlink_ */ static inline int32_t mavlink_msg_global_position_int_cov_get_relative_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 24); + return _MAV_RETURN_int32_t(msg, 20); } /** @@ -382,7 +370,7 @@ static inline int32_t mavlink_msg_global_position_int_cov_get_relative_alt(const */ static inline float mavlink_msg_global_position_int_cov_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 24); } /** @@ -392,7 +380,7 @@ static inline float mavlink_msg_global_position_int_cov_get_vx(const mavlink_mes */ static inline float mavlink_msg_global_position_int_cov_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 28); } /** @@ -402,7 +390,7 @@ static inline float mavlink_msg_global_position_int_cov_get_vy(const mavlink_mes */ static inline float mavlink_msg_global_position_int_cov_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 32); } /** @@ -412,7 +400,7 @@ static inline float mavlink_msg_global_position_int_cov_get_vz(const mavlink_mes */ static inline uint16_t mavlink_msg_global_position_int_cov_get_covariance(const mavlink_message_t* msg, float *covariance) { - return _MAV_RETURN_float_array(msg, covariance, 36, 40); + return _MAV_RETURN_float_array(msg, covariance, 36, 36); } /** @@ -423,19 +411,20 @@ static inline uint16_t mavlink_msg_global_position_int_cov_get_covariance(const */ static inline void mavlink_msg_global_position_int_cov_decode(const mavlink_message_t* msg, mavlink_global_position_int_cov_t* global_position_int_cov) { -#if MAVLINK_NEED_BYTE_SWAP - global_position_int_cov->time_utc = mavlink_msg_global_position_int_cov_get_time_utc(msg); - global_position_int_cov->time_boot_ms = mavlink_msg_global_position_int_cov_get_time_boot_ms(msg); - global_position_int_cov->lat = mavlink_msg_global_position_int_cov_get_lat(msg); - global_position_int_cov->lon = mavlink_msg_global_position_int_cov_get_lon(msg); - global_position_int_cov->alt = mavlink_msg_global_position_int_cov_get_alt(msg); - global_position_int_cov->relative_alt = mavlink_msg_global_position_int_cov_get_relative_alt(msg); - global_position_int_cov->vx = mavlink_msg_global_position_int_cov_get_vx(msg); - global_position_int_cov->vy = mavlink_msg_global_position_int_cov_get_vy(msg); - global_position_int_cov->vz = mavlink_msg_global_position_int_cov_get_vz(msg); - mavlink_msg_global_position_int_cov_get_covariance(msg, global_position_int_cov->covariance); - global_position_int_cov->estimator_type = mavlink_msg_global_position_int_cov_get_estimator_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + global_position_int_cov->time_usec = mavlink_msg_global_position_int_cov_get_time_usec(msg); + global_position_int_cov->lat = mavlink_msg_global_position_int_cov_get_lat(msg); + global_position_int_cov->lon = mavlink_msg_global_position_int_cov_get_lon(msg); + global_position_int_cov->alt = mavlink_msg_global_position_int_cov_get_alt(msg); + global_position_int_cov->relative_alt = mavlink_msg_global_position_int_cov_get_relative_alt(msg); + global_position_int_cov->vx = mavlink_msg_global_position_int_cov_get_vx(msg); + global_position_int_cov->vy = mavlink_msg_global_position_int_cov_get_vy(msg); + global_position_int_cov->vz = mavlink_msg_global_position_int_cov_get_vz(msg); + mavlink_msg_global_position_int_cov_get_covariance(msg, global_position_int_cov->covariance); + global_position_int_cov->estimator_type = mavlink_msg_global_position_int_cov_get_estimator_type(msg); #else - memcpy(global_position_int_cov, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN? msg->len : MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN; + memset(global_position_int_cov, 0, MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_LEN); + memcpy(global_position_int_cov, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_global_vision_position_estimate.h b/vendor/libraries/mavlink/common/mavlink_msg_global_vision_position_estimate.h index b2b75d7ef5..6b65eb0631 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_global_vision_position_estimate.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_global_vision_position_estimate.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE GLOBAL_VISION_POSITION_ESTIMATE PACKING #define MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE 101 -typedef struct __mavlink_global_vision_position_estimate_t -{ - uint64_t usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - float x; ///< Global X position - float y; ///< Global Y position - float z; ///< Global Z position - float roll; ///< Roll angle in rad - float pitch; ///< Pitch angle in rad - float yaw; ///< Yaw angle in rad -} mavlink_global_vision_position_estimate_t; +MAVPACKED( +typedef struct __mavlink_global_vision_position_estimate_t { + uint64_t usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + float x; /*< Global X position*/ + float y; /*< Global Y position*/ + float z; /*< Global Z position*/ + float roll; /*< Roll angle in rad*/ + float pitch; /*< Pitch angle in rad*/ + float yaw; /*< Yaw angle in rad*/ +}) mavlink_global_vision_position_estimate_t; #define MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN 32 +#define MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN 32 #define MAVLINK_MSG_ID_101_LEN 32 +#define MAVLINK_MSG_ID_101_MIN_LEN 32 #define MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC 102 #define MAVLINK_MSG_ID_101_CRC 102 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE { \ - "GLOBAL_VISION_POSITION_ESTIMATE", \ - 7, \ - { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_global_vision_position_estimate_t, usec) }, \ + 101, \ + "GLOBAL_VISION_POSITION_ESTIMATE", \ + 7, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_global_vision_position_estimate_t, usec) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_global_vision_position_estimate_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_global_vision_position_estimate_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_global_vision_position_estimate_t, z) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_global_vision_position_estimate_t { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_global_vision_position_estimate_t, yaw) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GLOBAL_VISION_POSITION_ESTIMATE { \ + "GLOBAL_VISION_POSITION_ESTIMATE", \ + 7, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_global_vision_position_estimate_t, usec) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_global_vision_position_estimate_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_global_vision_position_estimate_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_global_vision_position_estimate_t, z) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_global_vision_position_estimate_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_global_vision_position_estimate_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_global_vision_position_estimate_t, yaw) }, \ + } \ +} +#endif /** * @brief Pack a global_vision_position_estimate message @@ -51,38 +69,34 @@ typedef struct __mavlink_global_vision_position_estimate_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_vision_position_estimate_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) + uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); + char buf[MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); #else - mavlink_global_vision_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_global_vision_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_global_vision_position_estimate_pack(uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_global_vision_position_estimate_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t usec,float x,float y,float z,float roll,float pitch,float yaw) + mavlink_message_t* msg, + uint64_t usec,float x,float y,float z,float roll,float pitch,float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); + char buf[MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); #else - mavlink_global_vision_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_global_vision_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_global_vision_position_estimate_pack_chan(uin */ static inline uint16_t mavlink_msg_global_vision_position_estimate_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_global_vision_position_estimate_t* global_vision_position_estimate) { - return mavlink_msg_global_vision_position_estimate_pack(system_id, component_id, msg, global_vision_position_estimate->usec, global_vision_position_estimate->x, global_vision_position_estimate->y, global_vision_position_estimate->z, global_vision_position_estimate->roll, global_vision_position_estimate->pitch, global_vision_position_estimate->yaw); + return mavlink_msg_global_vision_position_estimate_pack(system_id, component_id, msg, global_vision_position_estimate->usec, global_vision_position_estimate->x, global_vision_position_estimate->y, global_vision_position_estimate->z, global_vision_position_estimate->roll, global_vision_position_estimate->pitch, global_vision_position_estimate->yaw); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_global_vision_position_estimate_encode(uint8_ */ static inline uint16_t mavlink_msg_global_vision_position_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_global_vision_position_estimate_t* global_vision_position_estimate) { - return mavlink_msg_global_vision_position_estimate_pack_chan(system_id, component_id, chan, msg, global_vision_position_estimate->usec, global_vision_position_estimate->x, global_vision_position_estimate->y, global_vision_position_estimate->z, global_vision_position_estimate->roll, global_vision_position_estimate->pitch, global_vision_position_estimate->yaw); + return mavlink_msg_global_vision_position_estimate_pack_chan(system_id, component_id, chan, msg, global_vision_position_estimate->usec, global_vision_position_estimate->x, global_vision_position_estimate->y, global_vision_position_estimate->z, global_vision_position_estimate->roll, global_vision_position_estimate->pitch, global_vision_position_estimate->yaw); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_global_vision_position_estimate_encode_chan(u static inline void mavlink_msg_global_vision_position_estimate_send(mavlink_channel_t chan, uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); + char buf[MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); + mavlink_global_vision_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); #endif +} + +/** + * @brief Send a global_vision_position_estimate message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_global_vision_position_estimate_send_struct(mavlink_channel_t chan, const mavlink_global_vision_position_estimate_t* global_vision_position_estimate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_global_vision_position_estimate_send(chan, global_vision_position_estimate->usec, global_vision_position_estimate->x, global_vision_position_estimate->y, global_vision_position_estimate->z, global_vision_position_estimate->roll, global_vision_position_estimate->pitch, global_vision_position_estimate->yaw); #else - mavlink_global_vision_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, (const char *)global_vision_position_estimate, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_global_vision_position_estimate_send(mavlink_chan static inline void mavlink_msg_global_vision_position_estimate_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); -#endif -#else - mavlink_global_vision_position_estimate_t *packet = (mavlink_global_vision_position_estimate_t *)msgbuf; - packet->usec = usec; - packet->x = x; - packet->y = y; - packet->z = z; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); -#endif + mavlink_global_vision_position_estimate_t *packet = (mavlink_global_vision_position_estimate_t *)msgbuf; + packet->usec = usec; + packet->x = x; + packet->y = y; + packet->z = z; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_global_vision_position_estimate_send_buf(mavlink_ */ static inline uint64_t mavlink_msg_global_vision_position_estimate_get_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline uint64_t mavlink_msg_global_vision_position_estimate_get_usec(cons */ static inline float mavlink_msg_global_vision_position_estimate_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_global_vision_position_estimate_get_x(const mavl */ static inline float mavlink_msg_global_vision_position_estimate_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_global_vision_position_estimate_get_y(const mavl */ static inline float mavlink_msg_global_vision_position_estimate_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_global_vision_position_estimate_get_z(const mavl */ static inline float mavlink_msg_global_vision_position_estimate_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_global_vision_position_estimate_get_roll(const m */ static inline float mavlink_msg_global_vision_position_estimate_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_global_vision_position_estimate_get_pitch(const */ static inline float mavlink_msg_global_vision_position_estimate_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_global_vision_position_estimate_get_yaw(const ma */ static inline void mavlink_msg_global_vision_position_estimate_decode(const mavlink_message_t* msg, mavlink_global_vision_position_estimate_t* global_vision_position_estimate) { -#if MAVLINK_NEED_BYTE_SWAP - global_vision_position_estimate->usec = mavlink_msg_global_vision_position_estimate_get_usec(msg); - global_vision_position_estimate->x = mavlink_msg_global_vision_position_estimate_get_x(msg); - global_vision_position_estimate->y = mavlink_msg_global_vision_position_estimate_get_y(msg); - global_vision_position_estimate->z = mavlink_msg_global_vision_position_estimate_get_z(msg); - global_vision_position_estimate->roll = mavlink_msg_global_vision_position_estimate_get_roll(msg); - global_vision_position_estimate->pitch = mavlink_msg_global_vision_position_estimate_get_pitch(msg); - global_vision_position_estimate->yaw = mavlink_msg_global_vision_position_estimate_get_yaw(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + global_vision_position_estimate->usec = mavlink_msg_global_vision_position_estimate_get_usec(msg); + global_vision_position_estimate->x = mavlink_msg_global_vision_position_estimate_get_x(msg); + global_vision_position_estimate->y = mavlink_msg_global_vision_position_estimate_get_y(msg); + global_vision_position_estimate->z = mavlink_msg_global_vision_position_estimate_get_z(msg); + global_vision_position_estimate->roll = mavlink_msg_global_vision_position_estimate_get_roll(msg); + global_vision_position_estimate->pitch = mavlink_msg_global_vision_position_estimate_get_pitch(msg); + global_vision_position_estimate->yaw = mavlink_msg_global_vision_position_estimate_get_yaw(msg); #else - memcpy(global_vision_position_estimate, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN? msg->len : MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN; + memset(global_vision_position_estimate, 0, MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_LEN); + memcpy(global_vision_position_estimate, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps2_raw.h b/vendor/libraries/mavlink/common/mavlink_msg_gps2_raw.h index 9101b24583..aeccc4eb33 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_gps2_raw.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps2_raw.h @@ -1,35 +1,40 @@ +#pragma once // MESSAGE GPS2_RAW PACKING #define MAVLINK_MSG_ID_GPS2_RAW 124 -typedef struct __mavlink_gps2_raw_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - int32_t lat; ///< Latitude (WGS84), in degrees * 1E7 - int32_t lon; ///< Longitude (WGS84), in degrees * 1E7 - int32_t alt; ///< Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) - uint32_t dgps_age; ///< Age of DGPS info - uint16_t eph; ///< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX - uint16_t epv; ///< GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX - uint16_t vel; ///< GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX - uint16_t cog; ///< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX - uint8_t fix_type; ///< 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS fix, 5: RTK Fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. - uint8_t satellites_visible; ///< Number of satellites visible. If unknown, set to 255 - uint8_t dgps_numch; ///< Number of DGPS satellites -} mavlink_gps2_raw_t; +MAVPACKED( +typedef struct __mavlink_gps2_raw_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + int32_t lat; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t lon; /*< Longitude (WGS84), in degrees * 1E7*/ + int32_t alt; /*< Altitude (AMSL, not WGS84), in meters * 1000 (positive for up)*/ + uint32_t dgps_age; /*< Age of DGPS info*/ + uint16_t eph; /*< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX*/ + uint16_t epv; /*< GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX*/ + uint16_t vel; /*< GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX*/ + uint16_t cog; /*< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX*/ + uint8_t fix_type; /*< See the GPS_FIX_TYPE enum.*/ + uint8_t satellites_visible; /*< Number of satellites visible. If unknown, set to 255*/ + uint8_t dgps_numch; /*< Number of DGPS satellites*/ +}) mavlink_gps2_raw_t; #define MAVLINK_MSG_ID_GPS2_RAW_LEN 35 +#define MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN 35 #define MAVLINK_MSG_ID_124_LEN 35 +#define MAVLINK_MSG_ID_124_MIN_LEN 35 #define MAVLINK_MSG_ID_GPS2_RAW_CRC 87 #define MAVLINK_MSG_ID_124_CRC 87 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GPS2_RAW { \ - "GPS2_RAW", \ - 12, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps2_raw_t, time_usec) }, \ + 124, \ + "GPS2_RAW", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps2_raw_t, time_usec) }, \ { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps2_raw_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps2_raw_t, lon) }, \ { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps2_raw_t, alt) }, \ @@ -43,7 +48,25 @@ typedef struct __mavlink_gps2_raw_t { "dgps_numch", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_gps2_raw_t, dgps_numch) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GPS2_RAW { \ + "GPS2_RAW", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps2_raw_t, time_usec) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps2_raw_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps2_raw_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps2_raw_t, alt) }, \ + { "dgps_age", NULL, MAVLINK_TYPE_UINT32_T, 0, 20, offsetof(mavlink_gps2_raw_t, dgps_age) }, \ + { "eph", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_gps2_raw_t, eph) }, \ + { "epv", NULL, MAVLINK_TYPE_UINT16_T, 0, 26, offsetof(mavlink_gps2_raw_t, epv) }, \ + { "vel", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_gps2_raw_t, vel) }, \ + { "cog", NULL, MAVLINK_TYPE_UINT16_T, 0, 30, offsetof(mavlink_gps2_raw_t, cog) }, \ + { "fix_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_gps2_raw_t, fix_type) }, \ + { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_gps2_raw_t, satellites_visible) }, \ + { "dgps_numch", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_gps2_raw_t, dgps_numch) }, \ + } \ +} +#endif /** * @brief Pack a gps2_raw message @@ -52,7 +75,7 @@ typedef struct __mavlink_gps2_raw_t * @param msg The MAVLink message to compress the data into * * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) - * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS fix, 5: RTK Fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @param fix_type See the GPS_FIX_TYPE enum. * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) @@ -66,48 +89,44 @@ typedef struct __mavlink_gps2_raw_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps2_raw_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible, uint8_t dgps_numch, uint32_t dgps_age) + uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible, uint8_t dgps_numch, uint32_t dgps_age) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS2_RAW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint32_t(buf, 20, dgps_age); - _mav_put_uint16_t(buf, 24, eph); - _mav_put_uint16_t(buf, 26, epv); - _mav_put_uint16_t(buf, 28, vel); - _mav_put_uint16_t(buf, 30, cog); - _mav_put_uint8_t(buf, 32, fix_type); - _mav_put_uint8_t(buf, 33, satellites_visible); - _mav_put_uint8_t(buf, 34, dgps_numch); + char buf[MAVLINK_MSG_ID_GPS2_RAW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint32_t(buf, 20, dgps_age); + _mav_put_uint16_t(buf, 24, eph); + _mav_put_uint16_t(buf, 26, epv); + _mav_put_uint16_t(buf, 28, vel); + _mav_put_uint16_t(buf, 30, cog); + _mav_put_uint8_t(buf, 32, fix_type); + _mav_put_uint8_t(buf, 33, satellites_visible); + _mav_put_uint8_t(buf, 34, dgps_numch); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS2_RAW_LEN); #else - mavlink_gps2_raw_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.dgps_age = dgps_age; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; - packet.dgps_numch = dgps_numch; + mavlink_gps2_raw_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.dgps_age = dgps_age; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + packet.dgps_numch = dgps_numch; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS2_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS2_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS2_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS2_RAW; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); } /** @@ -117,7 +136,7 @@ static inline uint16_t mavlink_msg_gps2_raw_pack(uint8_t system_id, uint8_t comp * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) - * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS fix, 5: RTK Fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @param fix_type See the GPS_FIX_TYPE enum. * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) @@ -131,49 +150,45 @@ static inline uint16_t mavlink_msg_gps2_raw_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps2_raw_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t fix_type,int32_t lat,int32_t lon,int32_t alt,uint16_t eph,uint16_t epv,uint16_t vel,uint16_t cog,uint8_t satellites_visible,uint8_t dgps_numch,uint32_t dgps_age) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t fix_type,int32_t lat,int32_t lon,int32_t alt,uint16_t eph,uint16_t epv,uint16_t vel,uint16_t cog,uint8_t satellites_visible,uint8_t dgps_numch,uint32_t dgps_age) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS2_RAW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint32_t(buf, 20, dgps_age); - _mav_put_uint16_t(buf, 24, eph); - _mav_put_uint16_t(buf, 26, epv); - _mav_put_uint16_t(buf, 28, vel); - _mav_put_uint16_t(buf, 30, cog); - _mav_put_uint8_t(buf, 32, fix_type); - _mav_put_uint8_t(buf, 33, satellites_visible); - _mav_put_uint8_t(buf, 34, dgps_numch); + char buf[MAVLINK_MSG_ID_GPS2_RAW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint32_t(buf, 20, dgps_age); + _mav_put_uint16_t(buf, 24, eph); + _mav_put_uint16_t(buf, 26, epv); + _mav_put_uint16_t(buf, 28, vel); + _mav_put_uint16_t(buf, 30, cog); + _mav_put_uint8_t(buf, 32, fix_type); + _mav_put_uint8_t(buf, 33, satellites_visible); + _mav_put_uint8_t(buf, 34, dgps_numch); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS2_RAW_LEN); #else - mavlink_gps2_raw_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.dgps_age = dgps_age; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; - packet.dgps_numch = dgps_numch; + mavlink_gps2_raw_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.dgps_age = dgps_age; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + packet.dgps_numch = dgps_numch; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS2_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS2_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS2_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS2_RAW; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); } /** @@ -186,7 +201,7 @@ static inline uint16_t mavlink_msg_gps2_raw_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_gps2_raw_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps2_raw_t* gps2_raw) { - return mavlink_msg_gps2_raw_pack(system_id, component_id, msg, gps2_raw->time_usec, gps2_raw->fix_type, gps2_raw->lat, gps2_raw->lon, gps2_raw->alt, gps2_raw->eph, gps2_raw->epv, gps2_raw->vel, gps2_raw->cog, gps2_raw->satellites_visible, gps2_raw->dgps_numch, gps2_raw->dgps_age); + return mavlink_msg_gps2_raw_pack(system_id, component_id, msg, gps2_raw->time_usec, gps2_raw->fix_type, gps2_raw->lat, gps2_raw->lon, gps2_raw->alt, gps2_raw->eph, gps2_raw->epv, gps2_raw->vel, gps2_raw->cog, gps2_raw->satellites_visible, gps2_raw->dgps_numch, gps2_raw->dgps_age); } /** @@ -200,7 +215,7 @@ static inline uint16_t mavlink_msg_gps2_raw_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_gps2_raw_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps2_raw_t* gps2_raw) { - return mavlink_msg_gps2_raw_pack_chan(system_id, component_id, chan, msg, gps2_raw->time_usec, gps2_raw->fix_type, gps2_raw->lat, gps2_raw->lon, gps2_raw->alt, gps2_raw->eph, gps2_raw->epv, gps2_raw->vel, gps2_raw->cog, gps2_raw->satellites_visible, gps2_raw->dgps_numch, gps2_raw->dgps_age); + return mavlink_msg_gps2_raw_pack_chan(system_id, component_id, chan, msg, gps2_raw->time_usec, gps2_raw->fix_type, gps2_raw->lat, gps2_raw->lon, gps2_raw->alt, gps2_raw->eph, gps2_raw->epv, gps2_raw->vel, gps2_raw->cog, gps2_raw->satellites_visible, gps2_raw->dgps_numch, gps2_raw->dgps_age); } /** @@ -208,7 +223,7 @@ static inline uint16_t mavlink_msg_gps2_raw_encode_chan(uint8_t system_id, uint8 * @param chan MAVLink channel to send the message * * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) - * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS fix, 5: RTK Fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @param fix_type See the GPS_FIX_TYPE enum. * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) @@ -225,45 +240,51 @@ static inline uint16_t mavlink_msg_gps2_raw_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_gps2_raw_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible, uint8_t dgps_numch, uint32_t dgps_age) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS2_RAW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint32_t(buf, 20, dgps_age); - _mav_put_uint16_t(buf, 24, eph); - _mav_put_uint16_t(buf, 26, epv); - _mav_put_uint16_t(buf, 28, vel); - _mav_put_uint16_t(buf, 30, cog); - _mav_put_uint8_t(buf, 32, fix_type); - _mav_put_uint8_t(buf, 33, satellites_visible); - _mav_put_uint8_t(buf, 34, dgps_numch); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, buf, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); + char buf[MAVLINK_MSG_ID_GPS2_RAW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint32_t(buf, 20, dgps_age); + _mav_put_uint16_t(buf, 24, eph); + _mav_put_uint16_t(buf, 26, epv); + _mav_put_uint16_t(buf, 28, vel); + _mav_put_uint16_t(buf, 30, cog); + _mav_put_uint8_t(buf, 32, fix_type); + _mav_put_uint8_t(buf, 33, satellites_visible); + _mav_put_uint8_t(buf, 34, dgps_numch); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, buf, MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, buf, MAVLINK_MSG_ID_GPS2_RAW_LEN); + mavlink_gps2_raw_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.dgps_age = dgps_age; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + packet.dgps_numch = dgps_numch; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, (const char *)&packet, MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); #endif +} + +/** + * @brief Send a gps2_raw message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps2_raw_send_struct(mavlink_channel_t chan, const mavlink_gps2_raw_t* gps2_raw) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps2_raw_send(chan, gps2_raw->time_usec, gps2_raw->fix_type, gps2_raw->lat, gps2_raw->lon, gps2_raw->alt, gps2_raw->eph, gps2_raw->epv, gps2_raw->vel, gps2_raw->cog, gps2_raw->satellites_visible, gps2_raw->dgps_numch, gps2_raw->dgps_age); #else - mavlink_gps2_raw_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.dgps_age = dgps_age; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; - packet.dgps_numch = dgps_numch; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, (const char *)&packet, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, (const char *)&packet, MAVLINK_MSG_ID_GPS2_RAW_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, (const char *)gps2_raw, MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); #endif } @@ -278,45 +299,37 @@ static inline void mavlink_msg_gps2_raw_send(mavlink_channel_t chan, uint64_t ti static inline void mavlink_msg_gps2_raw_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible, uint8_t dgps_numch, uint32_t dgps_age) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint32_t(buf, 20, dgps_age); - _mav_put_uint16_t(buf, 24, eph); - _mav_put_uint16_t(buf, 26, epv); - _mav_put_uint16_t(buf, 28, vel); - _mav_put_uint16_t(buf, 30, cog); - _mav_put_uint8_t(buf, 32, fix_type); - _mav_put_uint8_t(buf, 33, satellites_visible); - _mav_put_uint8_t(buf, 34, dgps_numch); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, buf, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint32_t(buf, 20, dgps_age); + _mav_put_uint16_t(buf, 24, eph); + _mav_put_uint16_t(buf, 26, epv); + _mav_put_uint16_t(buf, 28, vel); + _mav_put_uint16_t(buf, 30, cog); + _mav_put_uint8_t(buf, 32, fix_type); + _mav_put_uint8_t(buf, 33, satellites_visible); + _mav_put_uint8_t(buf, 34, dgps_numch); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, buf, MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, buf, MAVLINK_MSG_ID_GPS2_RAW_LEN); -#endif -#else - mavlink_gps2_raw_t *packet = (mavlink_gps2_raw_t *)msgbuf; - packet->time_usec = time_usec; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->dgps_age = dgps_age; - packet->eph = eph; - packet->epv = epv; - packet->vel = vel; - packet->cog = cog; - packet->fix_type = fix_type; - packet->satellites_visible = satellites_visible; - packet->dgps_numch = dgps_numch; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, (const char *)packet, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, (const char *)packet, MAVLINK_MSG_ID_GPS2_RAW_LEN); -#endif + mavlink_gps2_raw_t *packet = (mavlink_gps2_raw_t *)msgbuf; + packet->time_usec = time_usec; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->dgps_age = dgps_age; + packet->eph = eph; + packet->epv = epv; + packet->vel = vel; + packet->cog = cog; + packet->fix_type = fix_type; + packet->satellites_visible = satellites_visible; + packet->dgps_numch = dgps_numch; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RAW, (const char *)packet, MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN, MAVLINK_MSG_ID_GPS2_RAW_LEN, MAVLINK_MSG_ID_GPS2_RAW_CRC); #endif } #endif @@ -333,17 +346,17 @@ static inline void mavlink_msg_gps2_raw_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint64_t mavlink_msg_gps2_raw_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** * @brief Get field fix_type from gps2_raw message * - * @return 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS fix, 5: RTK Fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @return See the GPS_FIX_TYPE enum. */ static inline uint8_t mavlink_msg_gps2_raw_get_fix_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -353,7 +366,7 @@ static inline uint8_t mavlink_msg_gps2_raw_get_fix_type(const mavlink_message_t* */ static inline int32_t mavlink_msg_gps2_raw_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -363,7 +376,7 @@ static inline int32_t mavlink_msg_gps2_raw_get_lat(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_gps2_raw_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -373,7 +386,7 @@ static inline int32_t mavlink_msg_gps2_raw_get_lon(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_gps2_raw_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -383,7 +396,7 @@ static inline int32_t mavlink_msg_gps2_raw_get_alt(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_gps2_raw_get_eph(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -393,7 +406,7 @@ static inline uint16_t mavlink_msg_gps2_raw_get_eph(const mavlink_message_t* msg */ static inline uint16_t mavlink_msg_gps2_raw_get_epv(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 26); + return _MAV_RETURN_uint16_t(msg, 26); } /** @@ -403,7 +416,7 @@ static inline uint16_t mavlink_msg_gps2_raw_get_epv(const mavlink_message_t* msg */ static inline uint16_t mavlink_msg_gps2_raw_get_vel(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -413,7 +426,7 @@ static inline uint16_t mavlink_msg_gps2_raw_get_vel(const mavlink_message_t* msg */ static inline uint16_t mavlink_msg_gps2_raw_get_cog(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 30); + return _MAV_RETURN_uint16_t(msg, 30); } /** @@ -423,7 +436,7 @@ static inline uint16_t mavlink_msg_gps2_raw_get_cog(const mavlink_message_t* msg */ static inline uint8_t mavlink_msg_gps2_raw_get_satellites_visible(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 33); + return _MAV_RETURN_uint8_t(msg, 33); } /** @@ -433,7 +446,7 @@ static inline uint8_t mavlink_msg_gps2_raw_get_satellites_visible(const mavlink_ */ static inline uint8_t mavlink_msg_gps2_raw_get_dgps_numch(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -443,7 +456,7 @@ static inline uint8_t mavlink_msg_gps2_raw_get_dgps_numch(const mavlink_message_ */ static inline uint32_t mavlink_msg_gps2_raw_get_dgps_age(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 20); + return _MAV_RETURN_uint32_t(msg, 20); } /** @@ -454,20 +467,22 @@ static inline uint32_t mavlink_msg_gps2_raw_get_dgps_age(const mavlink_message_t */ static inline void mavlink_msg_gps2_raw_decode(const mavlink_message_t* msg, mavlink_gps2_raw_t* gps2_raw) { -#if MAVLINK_NEED_BYTE_SWAP - gps2_raw->time_usec = mavlink_msg_gps2_raw_get_time_usec(msg); - gps2_raw->lat = mavlink_msg_gps2_raw_get_lat(msg); - gps2_raw->lon = mavlink_msg_gps2_raw_get_lon(msg); - gps2_raw->alt = mavlink_msg_gps2_raw_get_alt(msg); - gps2_raw->dgps_age = mavlink_msg_gps2_raw_get_dgps_age(msg); - gps2_raw->eph = mavlink_msg_gps2_raw_get_eph(msg); - gps2_raw->epv = mavlink_msg_gps2_raw_get_epv(msg); - gps2_raw->vel = mavlink_msg_gps2_raw_get_vel(msg); - gps2_raw->cog = mavlink_msg_gps2_raw_get_cog(msg); - gps2_raw->fix_type = mavlink_msg_gps2_raw_get_fix_type(msg); - gps2_raw->satellites_visible = mavlink_msg_gps2_raw_get_satellites_visible(msg); - gps2_raw->dgps_numch = mavlink_msg_gps2_raw_get_dgps_numch(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps2_raw->time_usec = mavlink_msg_gps2_raw_get_time_usec(msg); + gps2_raw->lat = mavlink_msg_gps2_raw_get_lat(msg); + gps2_raw->lon = mavlink_msg_gps2_raw_get_lon(msg); + gps2_raw->alt = mavlink_msg_gps2_raw_get_alt(msg); + gps2_raw->dgps_age = mavlink_msg_gps2_raw_get_dgps_age(msg); + gps2_raw->eph = mavlink_msg_gps2_raw_get_eph(msg); + gps2_raw->epv = mavlink_msg_gps2_raw_get_epv(msg); + gps2_raw->vel = mavlink_msg_gps2_raw_get_vel(msg); + gps2_raw->cog = mavlink_msg_gps2_raw_get_cog(msg); + gps2_raw->fix_type = mavlink_msg_gps2_raw_get_fix_type(msg); + gps2_raw->satellites_visible = mavlink_msg_gps2_raw_get_satellites_visible(msg); + gps2_raw->dgps_numch = mavlink_msg_gps2_raw_get_dgps_numch(msg); #else - memcpy(gps2_raw, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GPS2_RAW_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS2_RAW_LEN? msg->len : MAVLINK_MSG_ID_GPS2_RAW_LEN; + memset(gps2_raw, 0, MAVLINK_MSG_ID_GPS2_RAW_LEN); + memcpy(gps2_raw, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps2_rtk.h b/vendor/libraries/mavlink/common/mavlink_msg_gps2_rtk.h index 4c2d93c6e9..e383647232 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_gps2_rtk.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps2_rtk.h @@ -1,36 +1,41 @@ +#pragma once // MESSAGE GPS2_RTK PACKING #define MAVLINK_MSG_ID_GPS2_RTK 128 -typedef struct __mavlink_gps2_rtk_t -{ - uint32_t time_last_baseline_ms; ///< Time since boot of last baseline message received in ms. - uint32_t tow; ///< GPS Time of Week of last baseline - int32_t baseline_a_mm; ///< Current baseline in ECEF x or NED north component in mm. - int32_t baseline_b_mm; ///< Current baseline in ECEF y or NED east component in mm. - int32_t baseline_c_mm; ///< Current baseline in ECEF z or NED down component in mm. - uint32_t accuracy; ///< Current estimate of baseline accuracy. - int32_t iar_num_hypotheses; ///< Current number of integer ambiguity hypotheses. - uint16_t wn; ///< GPS Week Number of last baseline - uint8_t rtk_receiver_id; ///< Identification of connected RTK receiver. - uint8_t rtk_health; ///< GPS-specific health report for RTK data. - uint8_t rtk_rate; ///< Rate of baseline messages being received by GPS, in HZ - uint8_t nsats; ///< Current number of sats used for RTK calculation. - uint8_t baseline_coords_type; ///< Coordinate system of baseline. 0 == ECEF, 1 == NED -} mavlink_gps2_rtk_t; +MAVPACKED( +typedef struct __mavlink_gps2_rtk_t { + uint32_t time_last_baseline_ms; /*< Time since boot of last baseline message received in ms.*/ + uint32_t tow; /*< GPS Time of Week of last baseline*/ + int32_t baseline_a_mm; /*< Current baseline in ECEF x or NED north component in mm.*/ + int32_t baseline_b_mm; /*< Current baseline in ECEF y or NED east component in mm.*/ + int32_t baseline_c_mm; /*< Current baseline in ECEF z or NED down component in mm.*/ + uint32_t accuracy; /*< Current estimate of baseline accuracy.*/ + int32_t iar_num_hypotheses; /*< Current number of integer ambiguity hypotheses.*/ + uint16_t wn; /*< GPS Week Number of last baseline*/ + uint8_t rtk_receiver_id; /*< Identification of connected RTK receiver.*/ + uint8_t rtk_health; /*< GPS-specific health report for RTK data.*/ + uint8_t rtk_rate; /*< Rate of baseline messages being received by GPS, in HZ*/ + uint8_t nsats; /*< Current number of sats used for RTK calculation.*/ + uint8_t baseline_coords_type; /*< Coordinate system of baseline. 0 == ECEF, 1 == NED*/ +}) mavlink_gps2_rtk_t; #define MAVLINK_MSG_ID_GPS2_RTK_LEN 35 +#define MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN 35 #define MAVLINK_MSG_ID_128_LEN 35 +#define MAVLINK_MSG_ID_128_MIN_LEN 35 #define MAVLINK_MSG_ID_GPS2_RTK_CRC 226 #define MAVLINK_MSG_ID_128_CRC 226 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GPS2_RTK { \ - "GPS2_RTK", \ - 13, \ - { { "time_last_baseline_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_gps2_rtk_t, time_last_baseline_ms) }, \ + 128, \ + "GPS2_RTK", \ + 13, \ + { { "time_last_baseline_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_gps2_rtk_t, time_last_baseline_ms) }, \ { "tow", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_gps2_rtk_t, tow) }, \ { "baseline_a_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps2_rtk_t, baseline_a_mm) }, \ { "baseline_b_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps2_rtk_t, baseline_b_mm) }, \ @@ -45,7 +50,26 @@ typedef struct __mavlink_gps2_rtk_t { "baseline_coords_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_gps2_rtk_t, baseline_coords_type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GPS2_RTK { \ + "GPS2_RTK", \ + 13, \ + { { "time_last_baseline_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_gps2_rtk_t, time_last_baseline_ms) }, \ + { "tow", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_gps2_rtk_t, tow) }, \ + { "baseline_a_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps2_rtk_t, baseline_a_mm) }, \ + { "baseline_b_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps2_rtk_t, baseline_b_mm) }, \ + { "baseline_c_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps2_rtk_t, baseline_c_mm) }, \ + { "accuracy", NULL, MAVLINK_TYPE_UINT32_T, 0, 20, offsetof(mavlink_gps2_rtk_t, accuracy) }, \ + { "iar_num_hypotheses", NULL, MAVLINK_TYPE_INT32_T, 0, 24, offsetof(mavlink_gps2_rtk_t, iar_num_hypotheses) }, \ + { "wn", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_gps2_rtk_t, wn) }, \ + { "rtk_receiver_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 30, offsetof(mavlink_gps2_rtk_t, rtk_receiver_id) }, \ + { "rtk_health", NULL, MAVLINK_TYPE_UINT8_T, 0, 31, offsetof(mavlink_gps2_rtk_t, rtk_health) }, \ + { "rtk_rate", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_gps2_rtk_t, rtk_rate) }, \ + { "nsats", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_gps2_rtk_t, nsats) }, \ + { "baseline_coords_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_gps2_rtk_t, baseline_coords_type) }, \ + } \ +} +#endif /** * @brief Pack a gps2_rtk message @@ -69,50 +93,46 @@ typedef struct __mavlink_gps2_rtk_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps2_rtk_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) + uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS2_RTK_LEN]; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); + char buf[MAVLINK_MSG_ID_GPS2_RTK_LEN]; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS2_RTK_LEN); #else - mavlink_gps2_rtk_t packet; - packet.time_last_baseline_ms = time_last_baseline_ms; - packet.tow = tow; - packet.baseline_a_mm = baseline_a_mm; - packet.baseline_b_mm = baseline_b_mm; - packet.baseline_c_mm = baseline_c_mm; - packet.accuracy = accuracy; - packet.iar_num_hypotheses = iar_num_hypotheses; - packet.wn = wn; - packet.rtk_receiver_id = rtk_receiver_id; - packet.rtk_health = rtk_health; - packet.rtk_rate = rtk_rate; - packet.nsats = nsats; - packet.baseline_coords_type = baseline_coords_type; + mavlink_gps2_rtk_t packet; + packet.time_last_baseline_ms = time_last_baseline_ms; + packet.tow = tow; + packet.baseline_a_mm = baseline_a_mm; + packet.baseline_b_mm = baseline_b_mm; + packet.baseline_c_mm = baseline_c_mm; + packet.accuracy = accuracy; + packet.iar_num_hypotheses = iar_num_hypotheses; + packet.wn = wn; + packet.rtk_receiver_id = rtk_receiver_id; + packet.rtk_health = rtk_health; + packet.rtk_rate = rtk_rate; + packet.nsats = nsats; + packet.baseline_coords_type = baseline_coords_type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS2_RTK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS2_RTK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS2_RTK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS2_RTK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); } /** @@ -137,51 +157,47 @@ static inline uint16_t mavlink_msg_gps2_rtk_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps2_rtk_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_last_baseline_ms,uint8_t rtk_receiver_id,uint16_t wn,uint32_t tow,uint8_t rtk_health,uint8_t rtk_rate,uint8_t nsats,uint8_t baseline_coords_type,int32_t baseline_a_mm,int32_t baseline_b_mm,int32_t baseline_c_mm,uint32_t accuracy,int32_t iar_num_hypotheses) + mavlink_message_t* msg, + uint32_t time_last_baseline_ms,uint8_t rtk_receiver_id,uint16_t wn,uint32_t tow,uint8_t rtk_health,uint8_t rtk_rate,uint8_t nsats,uint8_t baseline_coords_type,int32_t baseline_a_mm,int32_t baseline_b_mm,int32_t baseline_c_mm,uint32_t accuracy,int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS2_RTK_LEN]; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); + char buf[MAVLINK_MSG_ID_GPS2_RTK_LEN]; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS2_RTK_LEN); #else - mavlink_gps2_rtk_t packet; - packet.time_last_baseline_ms = time_last_baseline_ms; - packet.tow = tow; - packet.baseline_a_mm = baseline_a_mm; - packet.baseline_b_mm = baseline_b_mm; - packet.baseline_c_mm = baseline_c_mm; - packet.accuracy = accuracy; - packet.iar_num_hypotheses = iar_num_hypotheses; - packet.wn = wn; - packet.rtk_receiver_id = rtk_receiver_id; - packet.rtk_health = rtk_health; - packet.rtk_rate = rtk_rate; - packet.nsats = nsats; - packet.baseline_coords_type = baseline_coords_type; + mavlink_gps2_rtk_t packet; + packet.time_last_baseline_ms = time_last_baseline_ms; + packet.tow = tow; + packet.baseline_a_mm = baseline_a_mm; + packet.baseline_b_mm = baseline_b_mm; + packet.baseline_c_mm = baseline_c_mm; + packet.accuracy = accuracy; + packet.iar_num_hypotheses = iar_num_hypotheses; + packet.wn = wn; + packet.rtk_receiver_id = rtk_receiver_id; + packet.rtk_health = rtk_health; + packet.rtk_rate = rtk_rate; + packet.nsats = nsats; + packet.baseline_coords_type = baseline_coords_type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS2_RTK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS2_RTK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS2_RTK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS2_RTK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); } /** @@ -194,7 +210,7 @@ static inline uint16_t mavlink_msg_gps2_rtk_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_gps2_rtk_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps2_rtk_t* gps2_rtk) { - return mavlink_msg_gps2_rtk_pack(system_id, component_id, msg, gps2_rtk->time_last_baseline_ms, gps2_rtk->rtk_receiver_id, gps2_rtk->wn, gps2_rtk->tow, gps2_rtk->rtk_health, gps2_rtk->rtk_rate, gps2_rtk->nsats, gps2_rtk->baseline_coords_type, gps2_rtk->baseline_a_mm, gps2_rtk->baseline_b_mm, gps2_rtk->baseline_c_mm, gps2_rtk->accuracy, gps2_rtk->iar_num_hypotheses); + return mavlink_msg_gps2_rtk_pack(system_id, component_id, msg, gps2_rtk->time_last_baseline_ms, gps2_rtk->rtk_receiver_id, gps2_rtk->wn, gps2_rtk->tow, gps2_rtk->rtk_health, gps2_rtk->rtk_rate, gps2_rtk->nsats, gps2_rtk->baseline_coords_type, gps2_rtk->baseline_a_mm, gps2_rtk->baseline_b_mm, gps2_rtk->baseline_c_mm, gps2_rtk->accuracy, gps2_rtk->iar_num_hypotheses); } /** @@ -208,7 +224,7 @@ static inline uint16_t mavlink_msg_gps2_rtk_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_gps2_rtk_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps2_rtk_t* gps2_rtk) { - return mavlink_msg_gps2_rtk_pack_chan(system_id, component_id, chan, msg, gps2_rtk->time_last_baseline_ms, gps2_rtk->rtk_receiver_id, gps2_rtk->wn, gps2_rtk->tow, gps2_rtk->rtk_health, gps2_rtk->rtk_rate, gps2_rtk->nsats, gps2_rtk->baseline_coords_type, gps2_rtk->baseline_a_mm, gps2_rtk->baseline_b_mm, gps2_rtk->baseline_c_mm, gps2_rtk->accuracy, gps2_rtk->iar_num_hypotheses); + return mavlink_msg_gps2_rtk_pack_chan(system_id, component_id, chan, msg, gps2_rtk->time_last_baseline_ms, gps2_rtk->rtk_receiver_id, gps2_rtk->wn, gps2_rtk->tow, gps2_rtk->rtk_health, gps2_rtk->rtk_rate, gps2_rtk->nsats, gps2_rtk->baseline_coords_type, gps2_rtk->baseline_a_mm, gps2_rtk->baseline_b_mm, gps2_rtk->baseline_c_mm, gps2_rtk->accuracy, gps2_rtk->iar_num_hypotheses); } /** @@ -234,47 +250,53 @@ static inline uint16_t mavlink_msg_gps2_rtk_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_gps2_rtk_send(mavlink_channel_t chan, uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS2_RTK_LEN]; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, buf, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); + char buf[MAVLINK_MSG_ID_GPS2_RTK_LEN]; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, buf, MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, buf, MAVLINK_MSG_ID_GPS2_RTK_LEN); + mavlink_gps2_rtk_t packet; + packet.time_last_baseline_ms = time_last_baseline_ms; + packet.tow = tow; + packet.baseline_a_mm = baseline_a_mm; + packet.baseline_b_mm = baseline_b_mm; + packet.baseline_c_mm = baseline_c_mm; + packet.accuracy = accuracy; + packet.iar_num_hypotheses = iar_num_hypotheses; + packet.wn = wn; + packet.rtk_receiver_id = rtk_receiver_id; + packet.rtk_health = rtk_health; + packet.rtk_rate = rtk_rate; + packet.nsats = nsats; + packet.baseline_coords_type = baseline_coords_type; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, (const char *)&packet, MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); #endif +} + +/** + * @brief Send a gps2_rtk message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps2_rtk_send_struct(mavlink_channel_t chan, const mavlink_gps2_rtk_t* gps2_rtk) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps2_rtk_send(chan, gps2_rtk->time_last_baseline_ms, gps2_rtk->rtk_receiver_id, gps2_rtk->wn, gps2_rtk->tow, gps2_rtk->rtk_health, gps2_rtk->rtk_rate, gps2_rtk->nsats, gps2_rtk->baseline_coords_type, gps2_rtk->baseline_a_mm, gps2_rtk->baseline_b_mm, gps2_rtk->baseline_c_mm, gps2_rtk->accuracy, gps2_rtk->iar_num_hypotheses); #else - mavlink_gps2_rtk_t packet; - packet.time_last_baseline_ms = time_last_baseline_ms; - packet.tow = tow; - packet.baseline_a_mm = baseline_a_mm; - packet.baseline_b_mm = baseline_b_mm; - packet.baseline_c_mm = baseline_c_mm; - packet.accuracy = accuracy; - packet.iar_num_hypotheses = iar_num_hypotheses; - packet.wn = wn; - packet.rtk_receiver_id = rtk_receiver_id; - packet.rtk_health = rtk_health; - packet.rtk_rate = rtk_rate; - packet.nsats = nsats; - packet.baseline_coords_type = baseline_coords_type; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, (const char *)&packet, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, (const char *)&packet, MAVLINK_MSG_ID_GPS2_RTK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, (const char *)gps2_rtk, MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); #endif } @@ -289,47 +311,39 @@ static inline void mavlink_msg_gps2_rtk_send(mavlink_channel_t chan, uint32_t ti static inline void mavlink_msg_gps2_rtk_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, buf, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, buf, MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, buf, MAVLINK_MSG_ID_GPS2_RTK_LEN); -#endif -#else - mavlink_gps2_rtk_t *packet = (mavlink_gps2_rtk_t *)msgbuf; - packet->time_last_baseline_ms = time_last_baseline_ms; - packet->tow = tow; - packet->baseline_a_mm = baseline_a_mm; - packet->baseline_b_mm = baseline_b_mm; - packet->baseline_c_mm = baseline_c_mm; - packet->accuracy = accuracy; - packet->iar_num_hypotheses = iar_num_hypotheses; - packet->wn = wn; - packet->rtk_receiver_id = rtk_receiver_id; - packet->rtk_health = rtk_health; - packet->rtk_rate = rtk_rate; - packet->nsats = nsats; - packet->baseline_coords_type = baseline_coords_type; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, (const char *)packet, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, (const char *)packet, MAVLINK_MSG_ID_GPS2_RTK_LEN); -#endif + mavlink_gps2_rtk_t *packet = (mavlink_gps2_rtk_t *)msgbuf; + packet->time_last_baseline_ms = time_last_baseline_ms; + packet->tow = tow; + packet->baseline_a_mm = baseline_a_mm; + packet->baseline_b_mm = baseline_b_mm; + packet->baseline_c_mm = baseline_c_mm; + packet->accuracy = accuracy; + packet->iar_num_hypotheses = iar_num_hypotheses; + packet->wn = wn; + packet->rtk_receiver_id = rtk_receiver_id; + packet->rtk_health = rtk_health; + packet->rtk_rate = rtk_rate; + packet->nsats = nsats; + packet->baseline_coords_type = baseline_coords_type; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS2_RTK, (const char *)packet, MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS2_RTK_LEN, MAVLINK_MSG_ID_GPS2_RTK_CRC); #endif } #endif @@ -346,7 +360,7 @@ static inline void mavlink_msg_gps2_rtk_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint32_t mavlink_msg_gps2_rtk_get_time_last_baseline_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -356,7 +370,7 @@ static inline uint32_t mavlink_msg_gps2_rtk_get_time_last_baseline_ms(const mavl */ static inline uint8_t mavlink_msg_gps2_rtk_get_rtk_receiver_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 30); + return _MAV_RETURN_uint8_t(msg, 30); } /** @@ -366,7 +380,7 @@ static inline uint8_t mavlink_msg_gps2_rtk_get_rtk_receiver_id(const mavlink_mes */ static inline uint16_t mavlink_msg_gps2_rtk_get_wn(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -376,7 +390,7 @@ static inline uint16_t mavlink_msg_gps2_rtk_get_wn(const mavlink_message_t* msg) */ static inline uint32_t mavlink_msg_gps2_rtk_get_tow(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 4); + return _MAV_RETURN_uint32_t(msg, 4); } /** @@ -386,7 +400,7 @@ static inline uint32_t mavlink_msg_gps2_rtk_get_tow(const mavlink_message_t* msg */ static inline uint8_t mavlink_msg_gps2_rtk_get_rtk_health(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 31); + return _MAV_RETURN_uint8_t(msg, 31); } /** @@ -396,7 +410,7 @@ static inline uint8_t mavlink_msg_gps2_rtk_get_rtk_health(const mavlink_message_ */ static inline uint8_t mavlink_msg_gps2_rtk_get_rtk_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -406,7 +420,7 @@ static inline uint8_t mavlink_msg_gps2_rtk_get_rtk_rate(const mavlink_message_t* */ static inline uint8_t mavlink_msg_gps2_rtk_get_nsats(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 33); + return _MAV_RETURN_uint8_t(msg, 33); } /** @@ -416,7 +430,7 @@ static inline uint8_t mavlink_msg_gps2_rtk_get_nsats(const mavlink_message_t* ms */ static inline uint8_t mavlink_msg_gps2_rtk_get_baseline_coords_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -426,7 +440,7 @@ static inline uint8_t mavlink_msg_gps2_rtk_get_baseline_coords_type(const mavlin */ static inline int32_t mavlink_msg_gps2_rtk_get_baseline_a_mm(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -436,7 +450,7 @@ static inline int32_t mavlink_msg_gps2_rtk_get_baseline_a_mm(const mavlink_messa */ static inline int32_t mavlink_msg_gps2_rtk_get_baseline_b_mm(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -446,7 +460,7 @@ static inline int32_t mavlink_msg_gps2_rtk_get_baseline_b_mm(const mavlink_messa */ static inline int32_t mavlink_msg_gps2_rtk_get_baseline_c_mm(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -456,7 +470,7 @@ static inline int32_t mavlink_msg_gps2_rtk_get_baseline_c_mm(const mavlink_messa */ static inline uint32_t mavlink_msg_gps2_rtk_get_accuracy(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 20); + return _MAV_RETURN_uint32_t(msg, 20); } /** @@ -466,7 +480,7 @@ static inline uint32_t mavlink_msg_gps2_rtk_get_accuracy(const mavlink_message_t */ static inline int32_t mavlink_msg_gps2_rtk_get_iar_num_hypotheses(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 24); + return _MAV_RETURN_int32_t(msg, 24); } /** @@ -477,21 +491,23 @@ static inline int32_t mavlink_msg_gps2_rtk_get_iar_num_hypotheses(const mavlink_ */ static inline void mavlink_msg_gps2_rtk_decode(const mavlink_message_t* msg, mavlink_gps2_rtk_t* gps2_rtk) { -#if MAVLINK_NEED_BYTE_SWAP - gps2_rtk->time_last_baseline_ms = mavlink_msg_gps2_rtk_get_time_last_baseline_ms(msg); - gps2_rtk->tow = mavlink_msg_gps2_rtk_get_tow(msg); - gps2_rtk->baseline_a_mm = mavlink_msg_gps2_rtk_get_baseline_a_mm(msg); - gps2_rtk->baseline_b_mm = mavlink_msg_gps2_rtk_get_baseline_b_mm(msg); - gps2_rtk->baseline_c_mm = mavlink_msg_gps2_rtk_get_baseline_c_mm(msg); - gps2_rtk->accuracy = mavlink_msg_gps2_rtk_get_accuracy(msg); - gps2_rtk->iar_num_hypotheses = mavlink_msg_gps2_rtk_get_iar_num_hypotheses(msg); - gps2_rtk->wn = mavlink_msg_gps2_rtk_get_wn(msg); - gps2_rtk->rtk_receiver_id = mavlink_msg_gps2_rtk_get_rtk_receiver_id(msg); - gps2_rtk->rtk_health = mavlink_msg_gps2_rtk_get_rtk_health(msg); - gps2_rtk->rtk_rate = mavlink_msg_gps2_rtk_get_rtk_rate(msg); - gps2_rtk->nsats = mavlink_msg_gps2_rtk_get_nsats(msg); - gps2_rtk->baseline_coords_type = mavlink_msg_gps2_rtk_get_baseline_coords_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps2_rtk->time_last_baseline_ms = mavlink_msg_gps2_rtk_get_time_last_baseline_ms(msg); + gps2_rtk->tow = mavlink_msg_gps2_rtk_get_tow(msg); + gps2_rtk->baseline_a_mm = mavlink_msg_gps2_rtk_get_baseline_a_mm(msg); + gps2_rtk->baseline_b_mm = mavlink_msg_gps2_rtk_get_baseline_b_mm(msg); + gps2_rtk->baseline_c_mm = mavlink_msg_gps2_rtk_get_baseline_c_mm(msg); + gps2_rtk->accuracy = mavlink_msg_gps2_rtk_get_accuracy(msg); + gps2_rtk->iar_num_hypotheses = mavlink_msg_gps2_rtk_get_iar_num_hypotheses(msg); + gps2_rtk->wn = mavlink_msg_gps2_rtk_get_wn(msg); + gps2_rtk->rtk_receiver_id = mavlink_msg_gps2_rtk_get_rtk_receiver_id(msg); + gps2_rtk->rtk_health = mavlink_msg_gps2_rtk_get_rtk_health(msg); + gps2_rtk->rtk_rate = mavlink_msg_gps2_rtk_get_rtk_rate(msg); + gps2_rtk->nsats = mavlink_msg_gps2_rtk_get_nsats(msg); + gps2_rtk->baseline_coords_type = mavlink_msg_gps2_rtk_get_baseline_coords_type(msg); #else - memcpy(gps2_rtk, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GPS2_RTK_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS2_RTK_LEN? msg->len : MAVLINK_MSG_ID_GPS2_RTK_LEN; + memset(gps2_rtk, 0, MAVLINK_MSG_ID_GPS2_RTK_LEN); + memcpy(gps2_rtk, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps_global_origin.h b/vendor/libraries/mavlink/common/mavlink_msg_gps_global_origin.h index 5ae4c9b13b..3008058f10 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_gps_global_origin.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps_global_origin.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE GPS_GLOBAL_ORIGIN PACKING #define MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN 49 -typedef struct __mavlink_gps_global_origin_t -{ - int32_t latitude; ///< Latitude (WGS84), in degrees * 1E7 - int32_t longitude; ///< Longitude (WGS84), in degrees * 1E7 - int32_t altitude; ///< Altitude (AMSL), in meters * 1000 (positive for up) -} mavlink_gps_global_origin_t; +MAVPACKED( +typedef struct __mavlink_gps_global_origin_t { + int32_t latitude; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t longitude; /*< Longitude (WGS84), in degrees * 1E7*/ + int32_t altitude; /*< Altitude (AMSL), in meters * 1000 (positive for up)*/ +}) mavlink_gps_global_origin_t; #define MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN 12 +#define MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN 12 #define MAVLINK_MSG_ID_49_LEN 12 +#define MAVLINK_MSG_ID_49_MIN_LEN 12 #define MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC 39 #define MAVLINK_MSG_ID_49_CRC 39 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN { \ - "GPS_GLOBAL_ORIGIN", \ - 3, \ - { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_gps_global_origin_t, latitude) }, \ + 49, \ + "GPS_GLOBAL_ORIGIN", \ + 3, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_gps_global_origin_t, latitude) }, \ { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_gps_global_origin_t, longitude) }, \ { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps_global_origin_t, altitude) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GPS_GLOBAL_ORIGIN { \ + "GPS_GLOBAL_ORIGIN", \ + 3, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_gps_global_origin_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_gps_global_origin_t, longitude) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps_global_origin_t, altitude) }, \ + } \ +} +#endif /** * @brief Pack a gps_global_origin message @@ -39,30 +53,26 @@ typedef struct __mavlink_gps_global_origin_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_global_origin_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - int32_t latitude, int32_t longitude, int32_t altitude) + int32_t latitude, int32_t longitude, int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN]; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); + char buf[MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); #else - mavlink_gps_global_origin_t packet; - packet.latitude = latitude; - packet.longitude = longitude; - packet.altitude = altitude; + mavlink_gps_global_origin_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_gps_global_origin_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_global_origin_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - int32_t latitude,int32_t longitude,int32_t altitude) + mavlink_message_t* msg, + int32_t latitude,int32_t longitude,int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN]; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); + char buf[MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); #else - mavlink_gps_global_origin_t packet; - packet.latitude = latitude; - packet.longitude = longitude; - packet.altitude = altitude; + mavlink_gps_global_origin_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_gps_global_origin_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_gps_global_origin_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps_global_origin_t* gps_global_origin) { - return mavlink_msg_gps_global_origin_pack(system_id, component_id, msg, gps_global_origin->latitude, gps_global_origin->longitude, gps_global_origin->altitude); + return mavlink_msg_gps_global_origin_pack(system_id, component_id, msg, gps_global_origin->latitude, gps_global_origin->longitude, gps_global_origin->altitude); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_gps_global_origin_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_gps_global_origin_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_global_origin_t* gps_global_origin) { - return mavlink_msg_gps_global_origin_pack_chan(system_id, component_id, chan, msg, gps_global_origin->latitude, gps_global_origin->longitude, gps_global_origin->altitude); + return mavlink_msg_gps_global_origin_pack_chan(system_id, component_id, chan, msg, gps_global_origin->latitude, gps_global_origin->longitude, gps_global_origin->altitude); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_gps_global_origin_encode_chan(uint8_t system_ static inline void mavlink_msg_gps_global_origin_send(mavlink_channel_t chan, int32_t latitude, int32_t longitude, int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN]; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); + char buf[MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); + mavlink_gps_global_origin_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, (const char *)&packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); #endif -#else - mavlink_gps_global_origin_t packet; - packet.latitude = latitude; - packet.longitude = longitude; - packet.altitude = altitude; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, (const char *)&packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); +/** + * @brief Send a gps_global_origin message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps_global_origin_send_struct(mavlink_channel_t chan, const mavlink_gps_global_origin_t* gps_global_origin) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps_global_origin_send(chan, gps_global_origin->latitude, gps_global_origin->longitude, gps_global_origin->altitude); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, (const char *)&packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, (const char *)gps_global_origin, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_gps_global_origin_send(mavlink_channel_t chan, in static inline void mavlink_msg_gps_global_origin_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int32_t latitude, int32_t longitude, int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); #else - mavlink_gps_global_origin_t *packet = (mavlink_gps_global_origin_t *)msgbuf; - packet->latitude = latitude; - packet->longitude = longitude; - packet->altitude = altitude; + mavlink_gps_global_origin_t *packet = (mavlink_gps_global_origin_t *)msgbuf; + packet->latitude = latitude; + packet->longitude = longitude; + packet->altitude = altitude; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, (const char *)packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, (const char *)packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN, (const char *)packet, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_gps_global_origin_send_buf(mavlink_message_t *msg */ static inline int32_t mavlink_msg_gps_global_origin_get_latitude(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -226,7 +230,7 @@ static inline int32_t mavlink_msg_gps_global_origin_get_latitude(const mavlink_m */ static inline int32_t mavlink_msg_gps_global_origin_get_longitude(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -236,7 +240,7 @@ static inline int32_t mavlink_msg_gps_global_origin_get_longitude(const mavlink_ */ static inline int32_t mavlink_msg_gps_global_origin_get_altitude(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -247,11 +251,13 @@ static inline int32_t mavlink_msg_gps_global_origin_get_altitude(const mavlink_m */ static inline void mavlink_msg_gps_global_origin_decode(const mavlink_message_t* msg, mavlink_gps_global_origin_t* gps_global_origin) { -#if MAVLINK_NEED_BYTE_SWAP - gps_global_origin->latitude = mavlink_msg_gps_global_origin_get_latitude(msg); - gps_global_origin->longitude = mavlink_msg_gps_global_origin_get_longitude(msg); - gps_global_origin->altitude = mavlink_msg_gps_global_origin_get_altitude(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps_global_origin->latitude = mavlink_msg_gps_global_origin_get_latitude(msg); + gps_global_origin->longitude = mavlink_msg_gps_global_origin_get_longitude(msg); + gps_global_origin->altitude = mavlink_msg_gps_global_origin_get_altitude(msg); #else - memcpy(gps_global_origin, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN? msg->len : MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN; + memset(gps_global_origin, 0, MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_LEN); + memcpy(gps_global_origin, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps_inject_data.h b/vendor/libraries/mavlink/common/mavlink_msg_gps_inject_data.h index 362e2d7b9a..4fbd5fc976 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_gps_inject_data.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps_inject_data.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE GPS_INJECT_DATA PACKING #define MAVLINK_MSG_ID_GPS_INJECT_DATA 123 -typedef struct __mavlink_gps_inject_data_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t len; ///< data length - uint8_t data[110]; ///< raw data (110 is enough for 12 satellites of RTCMv2) -} mavlink_gps_inject_data_t; +MAVPACKED( +typedef struct __mavlink_gps_inject_data_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t len; /*< data length*/ + uint8_t data[110]; /*< raw data (110 is enough for 12 satellites of RTCMv2)*/ +}) mavlink_gps_inject_data_t; #define MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN 113 +#define MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN 113 #define MAVLINK_MSG_ID_123_LEN 113 +#define MAVLINK_MSG_ID_123_MIN_LEN 113 #define MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC 250 #define MAVLINK_MSG_ID_123_CRC 250 #define MAVLINK_MSG_GPS_INJECT_DATA_FIELD_DATA_LEN 110 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GPS_INJECT_DATA { \ - "GPS_INJECT_DATA", \ - 4, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_inject_data_t, target_system) }, \ + 123, \ + "GPS_INJECT_DATA", \ + 4, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_inject_data_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gps_inject_data_t, target_component) }, \ { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gps_inject_data_t, len) }, \ { "data", NULL, MAVLINK_TYPE_UINT8_T, 110, 3, offsetof(mavlink_gps_inject_data_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GPS_INJECT_DATA { \ + "GPS_INJECT_DATA", \ + 4, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_inject_data_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gps_inject_data_t, target_component) }, \ + { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_gps_inject_data_t, len) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 110, 3, offsetof(mavlink_gps_inject_data_t, data) }, \ + } \ +} +#endif /** * @brief Pack a gps_inject_data message @@ -42,30 +57,26 @@ typedef struct __mavlink_gps_inject_data_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_inject_data_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t len, const uint8_t *data) + uint8_t target_system, uint8_t target_component, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, len); - _mav_put_uint8_t_array(buf, 3, data, 110); + char buf[MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, len); + _mav_put_uint8_t_array(buf, 3, data, 110); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); #else - mavlink_gps_inject_data_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*110); + mavlink_gps_inject_data_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*110); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_INJECT_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_INJECT_DATA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); } /** @@ -81,31 +92,27 @@ static inline uint16_t mavlink_msg_gps_inject_data_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_inject_data_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t len,const uint8_t *data) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t len,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, len); - _mav_put_uint8_t_array(buf, 3, data, 110); + char buf[MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, len); + _mav_put_uint8_t_array(buf, 3, data, 110); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); #else - mavlink_gps_inject_data_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*110); + mavlink_gps_inject_data_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*110); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_INJECT_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_INJECT_DATA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); } /** @@ -118,7 +125,7 @@ static inline uint16_t mavlink_msg_gps_inject_data_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_gps_inject_data_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps_inject_data_t* gps_inject_data) { - return mavlink_msg_gps_inject_data_pack(system_id, component_id, msg, gps_inject_data->target_system, gps_inject_data->target_component, gps_inject_data->len, gps_inject_data->data); + return mavlink_msg_gps_inject_data_pack(system_id, component_id, msg, gps_inject_data->target_system, gps_inject_data->target_component, gps_inject_data->len, gps_inject_data->data); } /** @@ -132,7 +139,7 @@ static inline uint16_t mavlink_msg_gps_inject_data_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_gps_inject_data_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_inject_data_t* gps_inject_data) { - return mavlink_msg_gps_inject_data_pack_chan(system_id, component_id, chan, msg, gps_inject_data->target_system, gps_inject_data->target_component, gps_inject_data->len, gps_inject_data->data); + return mavlink_msg_gps_inject_data_pack_chan(system_id, component_id, chan, msg, gps_inject_data->target_system, gps_inject_data->target_component, gps_inject_data->len, gps_inject_data->data); } /** @@ -149,27 +156,33 @@ static inline uint16_t mavlink_msg_gps_inject_data_encode_chan(uint8_t system_id static inline void mavlink_msg_gps_inject_data_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, len); - _mav_put_uint8_t_array(buf, 3, data, 110); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); + char buf[MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, len); + _mav_put_uint8_t_array(buf, 3, data, 110); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); + mavlink_gps_inject_data_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*110); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, (const char *)&packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); #endif +} + +/** + * @brief Send a gps_inject_data message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps_inject_data_send_struct(mavlink_channel_t chan, const mavlink_gps_inject_data_t* gps_inject_data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps_inject_data_send(chan, gps_inject_data->target_system, gps_inject_data->target_component, gps_inject_data->len, gps_inject_data->data); #else - mavlink_gps_inject_data_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.len = len; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*110); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, (const char *)&packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, (const char *)&packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, (const char *)gps_inject_data, MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); #endif } @@ -184,27 +197,19 @@ static inline void mavlink_msg_gps_inject_data_send(mavlink_channel_t chan, uint static inline void mavlink_msg_gps_inject_data_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t len, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, len); - _mav_put_uint8_t_array(buf, 3, data, 110); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, len); + _mav_put_uint8_t_array(buf, 3, data, 110); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, buf, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); -#endif -#else - mavlink_gps_inject_data_t *packet = (mavlink_gps_inject_data_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; - packet->len = len; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*110); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, (const char *)packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, (const char *)packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); -#endif + mavlink_gps_inject_data_t *packet = (mavlink_gps_inject_data_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->len = len; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*110); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INJECT_DATA, (const char *)packet, MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN, MAVLINK_MSG_ID_GPS_INJECT_DATA_CRC); #endif } #endif @@ -221,7 +226,7 @@ static inline void mavlink_msg_gps_inject_data_send_buf(mavlink_message_t *msgbu */ static inline uint8_t mavlink_msg_gps_inject_data_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -231,7 +236,7 @@ static inline uint8_t mavlink_msg_gps_inject_data_get_target_system(const mavlin */ static inline uint8_t mavlink_msg_gps_inject_data_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -241,7 +246,7 @@ static inline uint8_t mavlink_msg_gps_inject_data_get_target_component(const mav */ static inline uint8_t mavlink_msg_gps_inject_data_get_len(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -251,7 +256,7 @@ static inline uint8_t mavlink_msg_gps_inject_data_get_len(const mavlink_message_ */ static inline uint16_t mavlink_msg_gps_inject_data_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 110, 3); + return _MAV_RETURN_uint8_t_array(msg, data, 110, 3); } /** @@ -262,12 +267,14 @@ static inline uint16_t mavlink_msg_gps_inject_data_get_data(const mavlink_messag */ static inline void mavlink_msg_gps_inject_data_decode(const mavlink_message_t* msg, mavlink_gps_inject_data_t* gps_inject_data) { -#if MAVLINK_NEED_BYTE_SWAP - gps_inject_data->target_system = mavlink_msg_gps_inject_data_get_target_system(msg); - gps_inject_data->target_component = mavlink_msg_gps_inject_data_get_target_component(msg); - gps_inject_data->len = mavlink_msg_gps_inject_data_get_len(msg); - mavlink_msg_gps_inject_data_get_data(msg, gps_inject_data->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps_inject_data->target_system = mavlink_msg_gps_inject_data_get_target_system(msg); + gps_inject_data->target_component = mavlink_msg_gps_inject_data_get_target_component(msg); + gps_inject_data->len = mavlink_msg_gps_inject_data_get_len(msg); + mavlink_msg_gps_inject_data_get_data(msg, gps_inject_data->data); #else - memcpy(gps_inject_data, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN? msg->len : MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN; + memset(gps_inject_data, 0, MAVLINK_MSG_ID_GPS_INJECT_DATA_LEN); + memcpy(gps_inject_data, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps_input.h b/vendor/libraries/mavlink/common/mavlink_msg_gps_input.h new file mode 100644 index 0000000000..5fb9e9c5a5 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps_input.h @@ -0,0 +1,638 @@ +#pragma once +// MESSAGE GPS_INPUT PACKING + +#define MAVLINK_MSG_ID_GPS_INPUT 232 + +MAVPACKED( +typedef struct __mavlink_gps_input_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + uint32_t time_week_ms; /*< GPS time (milliseconds from start of GPS week)*/ + int32_t lat; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t lon; /*< Longitude (WGS84), in degrees * 1E7*/ + float alt; /*< Altitude (AMSL, not WGS84), in m (positive for up)*/ + float hdop; /*< GPS HDOP horizontal dilution of position in m*/ + float vdop; /*< GPS VDOP vertical dilution of position in m*/ + float vn; /*< GPS velocity in m/s in NORTH direction in earth-fixed NED frame*/ + float ve; /*< GPS velocity in m/s in EAST direction in earth-fixed NED frame*/ + float vd; /*< GPS velocity in m/s in DOWN direction in earth-fixed NED frame*/ + float speed_accuracy; /*< GPS speed accuracy in m/s*/ + float horiz_accuracy; /*< GPS horizontal accuracy in m*/ + float vert_accuracy; /*< GPS vertical accuracy in m*/ + uint16_t ignore_flags; /*< Flags indicating which fields to ignore (see GPS_INPUT_IGNORE_FLAGS enum). All other fields must be provided.*/ + uint16_t time_week; /*< GPS week number*/ + uint8_t gps_id; /*< ID of the GPS for multiple GPS inputs*/ + uint8_t fix_type; /*< 0-1: no fix, 2: 2D fix, 3: 3D fix. 4: 3D with DGPS. 5: 3D with RTK*/ + uint8_t satellites_visible; /*< Number of satellites visible.*/ +}) mavlink_gps_input_t; + +#define MAVLINK_MSG_ID_GPS_INPUT_LEN 63 +#define MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN 63 +#define MAVLINK_MSG_ID_232_LEN 63 +#define MAVLINK_MSG_ID_232_MIN_LEN 63 + +#define MAVLINK_MSG_ID_GPS_INPUT_CRC 151 +#define MAVLINK_MSG_ID_232_CRC 151 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GPS_INPUT { \ + 232, \ + "GPS_INPUT", \ + 18, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps_input_t, time_usec) }, \ + { "time_week_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_gps_input_t, time_week_ms) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps_input_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps_input_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_gps_input_t, alt) }, \ + { "hdop", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_gps_input_t, hdop) }, \ + { "vdop", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_gps_input_t, vdop) }, \ + { "vn", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_gps_input_t, vn) }, \ + { "ve", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_gps_input_t, ve) }, \ + { "vd", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_gps_input_t, vd) }, \ + { "speed_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_gps_input_t, speed_accuracy) }, \ + { "horiz_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_gps_input_t, horiz_accuracy) }, \ + { "vert_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 52, offsetof(mavlink_gps_input_t, vert_accuracy) }, \ + { "ignore_flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 56, offsetof(mavlink_gps_input_t, ignore_flags) }, \ + { "time_week", NULL, MAVLINK_TYPE_UINT16_T, 0, 58, offsetof(mavlink_gps_input_t, time_week) }, \ + { "gps_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 60, offsetof(mavlink_gps_input_t, gps_id) }, \ + { "fix_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 61, offsetof(mavlink_gps_input_t, fix_type) }, \ + { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 62, offsetof(mavlink_gps_input_t, satellites_visible) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GPS_INPUT { \ + "GPS_INPUT", \ + 18, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps_input_t, time_usec) }, \ + { "time_week_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_gps_input_t, time_week_ms) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps_input_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps_input_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_gps_input_t, alt) }, \ + { "hdop", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_gps_input_t, hdop) }, \ + { "vdop", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_gps_input_t, vdop) }, \ + { "vn", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_gps_input_t, vn) }, \ + { "ve", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_gps_input_t, ve) }, \ + { "vd", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_gps_input_t, vd) }, \ + { "speed_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_gps_input_t, speed_accuracy) }, \ + { "horiz_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_gps_input_t, horiz_accuracy) }, \ + { "vert_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 52, offsetof(mavlink_gps_input_t, vert_accuracy) }, \ + { "ignore_flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 56, offsetof(mavlink_gps_input_t, ignore_flags) }, \ + { "time_week", NULL, MAVLINK_TYPE_UINT16_T, 0, 58, offsetof(mavlink_gps_input_t, time_week) }, \ + { "gps_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 60, offsetof(mavlink_gps_input_t, gps_id) }, \ + { "fix_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 61, offsetof(mavlink_gps_input_t, fix_type) }, \ + { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 62, offsetof(mavlink_gps_input_t, satellites_visible) }, \ + } \ +} +#endif + +/** + * @brief Pack a gps_input message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param gps_id ID of the GPS for multiple GPS inputs + * @param ignore_flags Flags indicating which fields to ignore (see GPS_INPUT_IGNORE_FLAGS enum). All other fields must be provided. + * @param time_week_ms GPS time (milliseconds from start of GPS week) + * @param time_week GPS week number + * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix. 4: 3D with DGPS. 5: 3D with RTK + * @param lat Latitude (WGS84), in degrees * 1E7 + * @param lon Longitude (WGS84), in degrees * 1E7 + * @param alt Altitude (AMSL, not WGS84), in m (positive for up) + * @param hdop GPS HDOP horizontal dilution of position in m + * @param vdop GPS VDOP vertical dilution of position in m + * @param vn GPS velocity in m/s in NORTH direction in earth-fixed NED frame + * @param ve GPS velocity in m/s in EAST direction in earth-fixed NED frame + * @param vd GPS velocity in m/s in DOWN direction in earth-fixed NED frame + * @param speed_accuracy GPS speed accuracy in m/s + * @param horiz_accuracy GPS horizontal accuracy in m + * @param vert_accuracy GPS vertical accuracy in m + * @param satellites_visible Number of satellites visible. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gps_input_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, uint8_t gps_id, uint16_t ignore_flags, uint32_t time_week_ms, uint16_t time_week, uint8_t fix_type, int32_t lat, int32_t lon, float alt, float hdop, float vdop, float vn, float ve, float vd, float speed_accuracy, float horiz_accuracy, float vert_accuracy, uint8_t satellites_visible) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GPS_INPUT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, time_week_ms); + _mav_put_int32_t(buf, 12, lat); + _mav_put_int32_t(buf, 16, lon); + _mav_put_float(buf, 20, alt); + _mav_put_float(buf, 24, hdop); + _mav_put_float(buf, 28, vdop); + _mav_put_float(buf, 32, vn); + _mav_put_float(buf, 36, ve); + _mav_put_float(buf, 40, vd); + _mav_put_float(buf, 44, speed_accuracy); + _mav_put_float(buf, 48, horiz_accuracy); + _mav_put_float(buf, 52, vert_accuracy); + _mav_put_uint16_t(buf, 56, ignore_flags); + _mav_put_uint16_t(buf, 58, time_week); + _mav_put_uint8_t(buf, 60, gps_id); + _mav_put_uint8_t(buf, 61, fix_type); + _mav_put_uint8_t(buf, 62, satellites_visible); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_INPUT_LEN); +#else + mavlink_gps_input_t packet; + packet.time_usec = time_usec; + packet.time_week_ms = time_week_ms; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.hdop = hdop; + packet.vdop = vdop; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; + packet.speed_accuracy = speed_accuracy; + packet.horiz_accuracy = horiz_accuracy; + packet.vert_accuracy = vert_accuracy; + packet.ignore_flags = ignore_flags; + packet.time_week = time_week; + packet.gps_id = gps_id; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_INPUT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GPS_INPUT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN, MAVLINK_MSG_ID_GPS_INPUT_LEN, MAVLINK_MSG_ID_GPS_INPUT_CRC); +} + +/** + * @brief Pack a gps_input message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param gps_id ID of the GPS for multiple GPS inputs + * @param ignore_flags Flags indicating which fields to ignore (see GPS_INPUT_IGNORE_FLAGS enum). All other fields must be provided. + * @param time_week_ms GPS time (milliseconds from start of GPS week) + * @param time_week GPS week number + * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix. 4: 3D with DGPS. 5: 3D with RTK + * @param lat Latitude (WGS84), in degrees * 1E7 + * @param lon Longitude (WGS84), in degrees * 1E7 + * @param alt Altitude (AMSL, not WGS84), in m (positive for up) + * @param hdop GPS HDOP horizontal dilution of position in m + * @param vdop GPS VDOP vertical dilution of position in m + * @param vn GPS velocity in m/s in NORTH direction in earth-fixed NED frame + * @param ve GPS velocity in m/s in EAST direction in earth-fixed NED frame + * @param vd GPS velocity in m/s in DOWN direction in earth-fixed NED frame + * @param speed_accuracy GPS speed accuracy in m/s + * @param horiz_accuracy GPS horizontal accuracy in m + * @param vert_accuracy GPS vertical accuracy in m + * @param satellites_visible Number of satellites visible. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gps_input_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,uint8_t gps_id,uint16_t ignore_flags,uint32_t time_week_ms,uint16_t time_week,uint8_t fix_type,int32_t lat,int32_t lon,float alt,float hdop,float vdop,float vn,float ve,float vd,float speed_accuracy,float horiz_accuracy,float vert_accuracy,uint8_t satellites_visible) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GPS_INPUT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, time_week_ms); + _mav_put_int32_t(buf, 12, lat); + _mav_put_int32_t(buf, 16, lon); + _mav_put_float(buf, 20, alt); + _mav_put_float(buf, 24, hdop); + _mav_put_float(buf, 28, vdop); + _mav_put_float(buf, 32, vn); + _mav_put_float(buf, 36, ve); + _mav_put_float(buf, 40, vd); + _mav_put_float(buf, 44, speed_accuracy); + _mav_put_float(buf, 48, horiz_accuracy); + _mav_put_float(buf, 52, vert_accuracy); + _mav_put_uint16_t(buf, 56, ignore_flags); + _mav_put_uint16_t(buf, 58, time_week); + _mav_put_uint8_t(buf, 60, gps_id); + _mav_put_uint8_t(buf, 61, fix_type); + _mav_put_uint8_t(buf, 62, satellites_visible); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_INPUT_LEN); +#else + mavlink_gps_input_t packet; + packet.time_usec = time_usec; + packet.time_week_ms = time_week_ms; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.hdop = hdop; + packet.vdop = vdop; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; + packet.speed_accuracy = speed_accuracy; + packet.horiz_accuracy = horiz_accuracy; + packet.vert_accuracy = vert_accuracy; + packet.ignore_flags = ignore_flags; + packet.time_week = time_week; + packet.gps_id = gps_id; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_INPUT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GPS_INPUT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN, MAVLINK_MSG_ID_GPS_INPUT_LEN, MAVLINK_MSG_ID_GPS_INPUT_CRC); +} + +/** + * @brief Encode a gps_input struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gps_input C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gps_input_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps_input_t* gps_input) +{ + return mavlink_msg_gps_input_pack(system_id, component_id, msg, gps_input->time_usec, gps_input->gps_id, gps_input->ignore_flags, gps_input->time_week_ms, gps_input->time_week, gps_input->fix_type, gps_input->lat, gps_input->lon, gps_input->alt, gps_input->hdop, gps_input->vdop, gps_input->vn, gps_input->ve, gps_input->vd, gps_input->speed_accuracy, gps_input->horiz_accuracy, gps_input->vert_accuracy, gps_input->satellites_visible); +} + +/** + * @brief Encode a gps_input struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gps_input C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gps_input_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_input_t* gps_input) +{ + return mavlink_msg_gps_input_pack_chan(system_id, component_id, chan, msg, gps_input->time_usec, gps_input->gps_id, gps_input->ignore_flags, gps_input->time_week_ms, gps_input->time_week, gps_input->fix_type, gps_input->lat, gps_input->lon, gps_input->alt, gps_input->hdop, gps_input->vdop, gps_input->vn, gps_input->ve, gps_input->vd, gps_input->speed_accuracy, gps_input->horiz_accuracy, gps_input->vert_accuracy, gps_input->satellites_visible); +} + +/** + * @brief Send a gps_input message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param gps_id ID of the GPS for multiple GPS inputs + * @param ignore_flags Flags indicating which fields to ignore (see GPS_INPUT_IGNORE_FLAGS enum). All other fields must be provided. + * @param time_week_ms GPS time (milliseconds from start of GPS week) + * @param time_week GPS week number + * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix. 4: 3D with DGPS. 5: 3D with RTK + * @param lat Latitude (WGS84), in degrees * 1E7 + * @param lon Longitude (WGS84), in degrees * 1E7 + * @param alt Altitude (AMSL, not WGS84), in m (positive for up) + * @param hdop GPS HDOP horizontal dilution of position in m + * @param vdop GPS VDOP vertical dilution of position in m + * @param vn GPS velocity in m/s in NORTH direction in earth-fixed NED frame + * @param ve GPS velocity in m/s in EAST direction in earth-fixed NED frame + * @param vd GPS velocity in m/s in DOWN direction in earth-fixed NED frame + * @param speed_accuracy GPS speed accuracy in m/s + * @param horiz_accuracy GPS horizontal accuracy in m + * @param vert_accuracy GPS vertical accuracy in m + * @param satellites_visible Number of satellites visible. + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gps_input_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t gps_id, uint16_t ignore_flags, uint32_t time_week_ms, uint16_t time_week, uint8_t fix_type, int32_t lat, int32_t lon, float alt, float hdop, float vdop, float vn, float ve, float vd, float speed_accuracy, float horiz_accuracy, float vert_accuracy, uint8_t satellites_visible) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GPS_INPUT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, time_week_ms); + _mav_put_int32_t(buf, 12, lat); + _mav_put_int32_t(buf, 16, lon); + _mav_put_float(buf, 20, alt); + _mav_put_float(buf, 24, hdop); + _mav_put_float(buf, 28, vdop); + _mav_put_float(buf, 32, vn); + _mav_put_float(buf, 36, ve); + _mav_put_float(buf, 40, vd); + _mav_put_float(buf, 44, speed_accuracy); + _mav_put_float(buf, 48, horiz_accuracy); + _mav_put_float(buf, 52, vert_accuracy); + _mav_put_uint16_t(buf, 56, ignore_flags); + _mav_put_uint16_t(buf, 58, time_week); + _mav_put_uint8_t(buf, 60, gps_id); + _mav_put_uint8_t(buf, 61, fix_type); + _mav_put_uint8_t(buf, 62, satellites_visible); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INPUT, buf, MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN, MAVLINK_MSG_ID_GPS_INPUT_LEN, MAVLINK_MSG_ID_GPS_INPUT_CRC); +#else + mavlink_gps_input_t packet; + packet.time_usec = time_usec; + packet.time_week_ms = time_week_ms; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.hdop = hdop; + packet.vdop = vdop; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; + packet.speed_accuracy = speed_accuracy; + packet.horiz_accuracy = horiz_accuracy; + packet.vert_accuracy = vert_accuracy; + packet.ignore_flags = ignore_flags; + packet.time_week = time_week; + packet.gps_id = gps_id; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INPUT, (const char *)&packet, MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN, MAVLINK_MSG_ID_GPS_INPUT_LEN, MAVLINK_MSG_ID_GPS_INPUT_CRC); +#endif +} + +/** + * @brief Send a gps_input message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps_input_send_struct(mavlink_channel_t chan, const mavlink_gps_input_t* gps_input) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps_input_send(chan, gps_input->time_usec, gps_input->gps_id, gps_input->ignore_flags, gps_input->time_week_ms, gps_input->time_week, gps_input->fix_type, gps_input->lat, gps_input->lon, gps_input->alt, gps_input->hdop, gps_input->vdop, gps_input->vn, gps_input->ve, gps_input->vd, gps_input->speed_accuracy, gps_input->horiz_accuracy, gps_input->vert_accuracy, gps_input->satellites_visible); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INPUT, (const char *)gps_input, MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN, MAVLINK_MSG_ID_GPS_INPUT_LEN, MAVLINK_MSG_ID_GPS_INPUT_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GPS_INPUT_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gps_input_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t gps_id, uint16_t ignore_flags, uint32_t time_week_ms, uint16_t time_week, uint8_t fix_type, int32_t lat, int32_t lon, float alt, float hdop, float vdop, float vn, float ve, float vd, float speed_accuracy, float horiz_accuracy, float vert_accuracy, uint8_t satellites_visible) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, time_week_ms); + _mav_put_int32_t(buf, 12, lat); + _mav_put_int32_t(buf, 16, lon); + _mav_put_float(buf, 20, alt); + _mav_put_float(buf, 24, hdop); + _mav_put_float(buf, 28, vdop); + _mav_put_float(buf, 32, vn); + _mav_put_float(buf, 36, ve); + _mav_put_float(buf, 40, vd); + _mav_put_float(buf, 44, speed_accuracy); + _mav_put_float(buf, 48, horiz_accuracy); + _mav_put_float(buf, 52, vert_accuracy); + _mav_put_uint16_t(buf, 56, ignore_flags); + _mav_put_uint16_t(buf, 58, time_week); + _mav_put_uint8_t(buf, 60, gps_id); + _mav_put_uint8_t(buf, 61, fix_type); + _mav_put_uint8_t(buf, 62, satellites_visible); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INPUT, buf, MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN, MAVLINK_MSG_ID_GPS_INPUT_LEN, MAVLINK_MSG_ID_GPS_INPUT_CRC); +#else + mavlink_gps_input_t *packet = (mavlink_gps_input_t *)msgbuf; + packet->time_usec = time_usec; + packet->time_week_ms = time_week_ms; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->hdop = hdop; + packet->vdop = vdop; + packet->vn = vn; + packet->ve = ve; + packet->vd = vd; + packet->speed_accuracy = speed_accuracy; + packet->horiz_accuracy = horiz_accuracy; + packet->vert_accuracy = vert_accuracy; + packet->ignore_flags = ignore_flags; + packet->time_week = time_week; + packet->gps_id = gps_id; + packet->fix_type = fix_type; + packet->satellites_visible = satellites_visible; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_INPUT, (const char *)packet, MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN, MAVLINK_MSG_ID_GPS_INPUT_LEN, MAVLINK_MSG_ID_GPS_INPUT_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GPS_INPUT UNPACKING + + +/** + * @brief Get field time_usec from gps_input message + * + * @return Timestamp (micros since boot or Unix epoch) + */ +static inline uint64_t mavlink_msg_gps_input_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field gps_id from gps_input message + * + * @return ID of the GPS for multiple GPS inputs + */ +static inline uint8_t mavlink_msg_gps_input_get_gps_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 60); +} + +/** + * @brief Get field ignore_flags from gps_input message + * + * @return Flags indicating which fields to ignore (see GPS_INPUT_IGNORE_FLAGS enum). All other fields must be provided. + */ +static inline uint16_t mavlink_msg_gps_input_get_ignore_flags(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 56); +} + +/** + * @brief Get field time_week_ms from gps_input message + * + * @return GPS time (milliseconds from start of GPS week) + */ +static inline uint32_t mavlink_msg_gps_input_get_time_week_ms(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 8); +} + +/** + * @brief Get field time_week from gps_input message + * + * @return GPS week number + */ +static inline uint16_t mavlink_msg_gps_input_get_time_week(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 58); +} + +/** + * @brief Get field fix_type from gps_input message + * + * @return 0-1: no fix, 2: 2D fix, 3: 3D fix. 4: 3D with DGPS. 5: 3D with RTK + */ +static inline uint8_t mavlink_msg_gps_input_get_fix_type(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 61); +} + +/** + * @brief Get field lat from gps_input message + * + * @return Latitude (WGS84), in degrees * 1E7 + */ +static inline int32_t mavlink_msg_gps_input_get_lat(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 12); +} + +/** + * @brief Get field lon from gps_input message + * + * @return Longitude (WGS84), in degrees * 1E7 + */ +static inline int32_t mavlink_msg_gps_input_get_lon(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 16); +} + +/** + * @brief Get field alt from gps_input message + * + * @return Altitude (AMSL, not WGS84), in m (positive for up) + */ +static inline float mavlink_msg_gps_input_get_alt(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field hdop from gps_input message + * + * @return GPS HDOP horizontal dilution of position in m + */ +static inline float mavlink_msg_gps_input_get_hdop(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field vdop from gps_input message + * + * @return GPS VDOP vertical dilution of position in m + */ +static inline float mavlink_msg_gps_input_get_vdop(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Get field vn from gps_input message + * + * @return GPS velocity in m/s in NORTH direction in earth-fixed NED frame + */ +static inline float mavlink_msg_gps_input_get_vn(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 32); +} + +/** + * @brief Get field ve from gps_input message + * + * @return GPS velocity in m/s in EAST direction in earth-fixed NED frame + */ +static inline float mavlink_msg_gps_input_get_ve(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 36); +} + +/** + * @brief Get field vd from gps_input message + * + * @return GPS velocity in m/s in DOWN direction in earth-fixed NED frame + */ +static inline float mavlink_msg_gps_input_get_vd(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 40); +} + +/** + * @brief Get field speed_accuracy from gps_input message + * + * @return GPS speed accuracy in m/s + */ +static inline float mavlink_msg_gps_input_get_speed_accuracy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 44); +} + +/** + * @brief Get field horiz_accuracy from gps_input message + * + * @return GPS horizontal accuracy in m + */ +static inline float mavlink_msg_gps_input_get_horiz_accuracy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 48); +} + +/** + * @brief Get field vert_accuracy from gps_input message + * + * @return GPS vertical accuracy in m + */ +static inline float mavlink_msg_gps_input_get_vert_accuracy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 52); +} + +/** + * @brief Get field satellites_visible from gps_input message + * + * @return Number of satellites visible. + */ +static inline uint8_t mavlink_msg_gps_input_get_satellites_visible(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 62); +} + +/** + * @brief Decode a gps_input message into a struct + * + * @param msg The message to decode + * @param gps_input C-struct to decode the message contents into + */ +static inline void mavlink_msg_gps_input_decode(const mavlink_message_t* msg, mavlink_gps_input_t* gps_input) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps_input->time_usec = mavlink_msg_gps_input_get_time_usec(msg); + gps_input->time_week_ms = mavlink_msg_gps_input_get_time_week_ms(msg); + gps_input->lat = mavlink_msg_gps_input_get_lat(msg); + gps_input->lon = mavlink_msg_gps_input_get_lon(msg); + gps_input->alt = mavlink_msg_gps_input_get_alt(msg); + gps_input->hdop = mavlink_msg_gps_input_get_hdop(msg); + gps_input->vdop = mavlink_msg_gps_input_get_vdop(msg); + gps_input->vn = mavlink_msg_gps_input_get_vn(msg); + gps_input->ve = mavlink_msg_gps_input_get_ve(msg); + gps_input->vd = mavlink_msg_gps_input_get_vd(msg); + gps_input->speed_accuracy = mavlink_msg_gps_input_get_speed_accuracy(msg); + gps_input->horiz_accuracy = mavlink_msg_gps_input_get_horiz_accuracy(msg); + gps_input->vert_accuracy = mavlink_msg_gps_input_get_vert_accuracy(msg); + gps_input->ignore_flags = mavlink_msg_gps_input_get_ignore_flags(msg); + gps_input->time_week = mavlink_msg_gps_input_get_time_week(msg); + gps_input->gps_id = mavlink_msg_gps_input_get_gps_id(msg); + gps_input->fix_type = mavlink_msg_gps_input_get_fix_type(msg); + gps_input->satellites_visible = mavlink_msg_gps_input_get_satellites_visible(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS_INPUT_LEN? msg->len : MAVLINK_MSG_ID_GPS_INPUT_LEN; + memset(gps_input, 0, MAVLINK_MSG_ID_GPS_INPUT_LEN); + memcpy(gps_input, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps_raw_int.h b/vendor/libraries/mavlink/common/mavlink_msg_gps_raw_int.h index b66171dac3..3033b6d5fc 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_gps_raw_int.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps_raw_int.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE GPS_RAW_INT PACKING #define MAVLINK_MSG_ID_GPS_RAW_INT 24 -typedef struct __mavlink_gps_raw_int_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - int32_t lat; ///< Latitude (WGS84), in degrees * 1E7 - int32_t lon; ///< Longitude (WGS84), in degrees * 1E7 - int32_t alt; ///< Altitude (AMSL, NOT WGS84), in meters * 1000 (positive for up). Note that virtually all GPS modules provide the AMSL altitude in addition to the WGS84 altitude. - uint16_t eph; ///< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX - uint16_t epv; ///< GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX - uint16_t vel; ///< GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX - uint16_t cog; ///< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX - uint8_t fix_type; ///< 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS, 5: RTK. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. - uint8_t satellites_visible; ///< Number of satellites visible. If unknown, set to 255 -} mavlink_gps_raw_int_t; +MAVPACKED( +typedef struct __mavlink_gps_raw_int_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + int32_t lat; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t lon; /*< Longitude (WGS84), in degrees * 1E7*/ + int32_t alt; /*< Altitude (AMSL, NOT WGS84), in meters * 1000 (positive for up). Note that virtually all GPS modules provide the AMSL altitude in addition to the WGS84 altitude.*/ + uint16_t eph; /*< GPS HDOP horizontal dilution of position (unitless). If unknown, set to: UINT16_MAX*/ + uint16_t epv; /*< GPS VDOP vertical dilution of position (unitless). If unknown, set to: UINT16_MAX*/ + uint16_t vel; /*< GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX*/ + uint16_t cog; /*< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX*/ + uint8_t fix_type; /*< See the GPS_FIX_TYPE enum.*/ + uint8_t satellites_visible; /*< Number of satellites visible. If unknown, set to 255*/ +}) mavlink_gps_raw_int_t; #define MAVLINK_MSG_ID_GPS_RAW_INT_LEN 30 +#define MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN 30 #define MAVLINK_MSG_ID_24_LEN 30 +#define MAVLINK_MSG_ID_24_MIN_LEN 30 #define MAVLINK_MSG_ID_GPS_RAW_INT_CRC 24 #define MAVLINK_MSG_ID_24_CRC 24 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GPS_RAW_INT { \ - "GPS_RAW_INT", \ - 10, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps_raw_int_t, time_usec) }, \ + 24, \ + "GPS_RAW_INT", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps_raw_int_t, time_usec) }, \ { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps_raw_int_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps_raw_int_t, lon) }, \ { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps_raw_int_t, alt) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_gps_raw_int_t { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 29, offsetof(mavlink_gps_raw_int_t, satellites_visible) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GPS_RAW_INT { \ + "GPS_RAW_INT", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_gps_raw_int_t, time_usec) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps_raw_int_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps_raw_int_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps_raw_int_t, alt) }, \ + { "eph", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_gps_raw_int_t, eph) }, \ + { "epv", NULL, MAVLINK_TYPE_UINT16_T, 0, 22, offsetof(mavlink_gps_raw_int_t, epv) }, \ + { "vel", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_gps_raw_int_t, vel) }, \ + { "cog", NULL, MAVLINK_TYPE_UINT16_T, 0, 26, offsetof(mavlink_gps_raw_int_t, cog) }, \ + { "fix_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 28, offsetof(mavlink_gps_raw_int_t, fix_type) }, \ + { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 29, offsetof(mavlink_gps_raw_int_t, satellites_visible) }, \ + } \ +} +#endif /** * @brief Pack a gps_raw_int message @@ -48,56 +69,52 @@ typedef struct __mavlink_gps_raw_int_t * @param msg The MAVLink message to compress the data into * * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) - * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS, 5: RTK. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @param fix_type See the GPS_FIX_TYPE enum. * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (AMSL, NOT WGS84), in meters * 1000 (positive for up). Note that virtually all GPS modules provide the AMSL altitude in addition to the WGS84 altitude. - * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX - * @param epv GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param eph GPS HDOP horizontal dilution of position (unitless). If unknown, set to: UINT16_MAX + * @param epv GPS VDOP vertical dilution of position (unitless). If unknown, set to: UINT16_MAX * @param vel GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @param satellites_visible Number of satellites visible. If unknown, set to 255 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_raw_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible) + uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_RAW_INT_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_uint16_t(buf, 26, cog); - _mav_put_uint8_t(buf, 28, fix_type); - _mav_put_uint8_t(buf, 29, satellites_visible); + char buf[MAVLINK_MSG_ID_GPS_RAW_INT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_uint16_t(buf, 26, cog); + _mav_put_uint8_t(buf, 28, fix_type); + _mav_put_uint8_t(buf, 29, satellites_visible); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); #else - mavlink_gps_raw_int_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; + mavlink_gps_raw_int_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_RAW_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_RAW_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); } /** @@ -107,57 +124,53 @@ static inline uint16_t mavlink_msg_gps_raw_int_pack(uint8_t system_id, uint8_t c * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) - * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS, 5: RTK. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @param fix_type See the GPS_FIX_TYPE enum. * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (AMSL, NOT WGS84), in meters * 1000 (positive for up). Note that virtually all GPS modules provide the AMSL altitude in addition to the WGS84 altitude. - * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX - * @param epv GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param eph GPS HDOP horizontal dilution of position (unitless). If unknown, set to: UINT16_MAX + * @param epv GPS VDOP vertical dilution of position (unitless). If unknown, set to: UINT16_MAX * @param vel GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @param satellites_visible Number of satellites visible. If unknown, set to 255 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_raw_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t fix_type,int32_t lat,int32_t lon,int32_t alt,uint16_t eph,uint16_t epv,uint16_t vel,uint16_t cog,uint8_t satellites_visible) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t fix_type,int32_t lat,int32_t lon,int32_t alt,uint16_t eph,uint16_t epv,uint16_t vel,uint16_t cog,uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_RAW_INT_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_uint16_t(buf, 26, cog); - _mav_put_uint8_t(buf, 28, fix_type); - _mav_put_uint8_t(buf, 29, satellites_visible); + char buf[MAVLINK_MSG_ID_GPS_RAW_INT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_uint16_t(buf, 26, cog); + _mav_put_uint8_t(buf, 28, fix_type); + _mav_put_uint8_t(buf, 29, satellites_visible); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); #else - mavlink_gps_raw_int_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; + mavlink_gps_raw_int_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_RAW_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_RAW_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_gps_raw_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps_raw_int_t* gps_raw_int) { - return mavlink_msg_gps_raw_int_pack(system_id, component_id, msg, gps_raw_int->time_usec, gps_raw_int->fix_type, gps_raw_int->lat, gps_raw_int->lon, gps_raw_int->alt, gps_raw_int->eph, gps_raw_int->epv, gps_raw_int->vel, gps_raw_int->cog, gps_raw_int->satellites_visible); + return mavlink_msg_gps_raw_int_pack(system_id, component_id, msg, gps_raw_int->time_usec, gps_raw_int->fix_type, gps_raw_int->lat, gps_raw_int->lon, gps_raw_int->alt, gps_raw_int->eph, gps_raw_int->epv, gps_raw_int->vel, gps_raw_int->cog, gps_raw_int->satellites_visible); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_gps_raw_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_raw_int_t* gps_raw_int) { - return mavlink_msg_gps_raw_int_pack_chan(system_id, component_id, chan, msg, gps_raw_int->time_usec, gps_raw_int->fix_type, gps_raw_int->lat, gps_raw_int->lon, gps_raw_int->alt, gps_raw_int->eph, gps_raw_int->epv, gps_raw_int->vel, gps_raw_int->cog, gps_raw_int->satellites_visible); + return mavlink_msg_gps_raw_int_pack_chan(system_id, component_id, chan, msg, gps_raw_int->time_usec, gps_raw_int->fix_type, gps_raw_int->lat, gps_raw_int->lon, gps_raw_int->alt, gps_raw_int->eph, gps_raw_int->epv, gps_raw_int->vel, gps_raw_int->cog, gps_raw_int->satellites_visible); } /** @@ -192,12 +205,12 @@ static inline uint16_t mavlink_msg_gps_raw_int_encode_chan(uint8_t system_id, ui * @param chan MAVLink channel to send the message * * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) - * @param fix_type 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS, 5: RTK. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @param fix_type See the GPS_FIX_TYPE enum. * @param lat Latitude (WGS84), in degrees * 1E7 * @param lon Longitude (WGS84), in degrees * 1E7 * @param alt Altitude (AMSL, NOT WGS84), in meters * 1000 (positive for up). Note that virtually all GPS modules provide the AMSL altitude in addition to the WGS84 altitude. - * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX - * @param epv GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @param eph GPS HDOP horizontal dilution of position (unitless). If unknown, set to: UINT16_MAX + * @param epv GPS VDOP vertical dilution of position (unitless). If unknown, set to: UINT16_MAX * @param vel GPS ground speed (m/s * 100). If unknown, set to: UINT16_MAX * @param cog Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: UINT16_MAX * @param satellites_visible Number of satellites visible. If unknown, set to 255 @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_gps_raw_int_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_gps_raw_int_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_RAW_INT_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_uint16_t(buf, 26, cog); - _mav_put_uint8_t(buf, 28, fix_type); - _mav_put_uint8_t(buf, 29, satellites_visible); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, buf, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); + char buf[MAVLINK_MSG_ID_GPS_RAW_INT_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_uint16_t(buf, 26, cog); + _mav_put_uint8_t(buf, 28, fix_type); + _mav_put_uint8_t(buf, 29, satellites_visible); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, buf, MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, buf, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); + mavlink_gps_raw_int_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, (const char *)&packet, MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); #endif +} + +/** + * @brief Send a gps_raw_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps_raw_int_send_struct(mavlink_channel_t chan, const mavlink_gps_raw_int_t* gps_raw_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps_raw_int_send(chan, gps_raw_int->time_usec, gps_raw_int->fix_type, gps_raw_int->lat, gps_raw_int->lon, gps_raw_int->alt, gps_raw_int->eph, gps_raw_int->epv, gps_raw_int->vel, gps_raw_int->cog, gps_raw_int->satellites_visible); #else - mavlink_gps_raw_int_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, (const char *)&packet, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, (const char *)&packet, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, (const char *)gps_raw_int, MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_gps_raw_int_send(mavlink_channel_t chan, uint64_t static inline void mavlink_msg_gps_raw_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, uint16_t cog, uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_uint16_t(buf, 26, cog); - _mav_put_uint8_t(buf, 28, fix_type); - _mav_put_uint8_t(buf, 29, satellites_visible); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, buf, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, buf, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); -#endif -#else - mavlink_gps_raw_int_t *packet = (mavlink_gps_raw_int_t *)msgbuf; - packet->time_usec = time_usec; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->eph = eph; - packet->epv = epv; - packet->vel = vel; - packet->cog = cog; - packet->fix_type = fix_type; - packet->satellites_visible = satellites_visible; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, (const char *)packet, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_uint16_t(buf, 26, cog); + _mav_put_uint8_t(buf, 28, fix_type); + _mav_put_uint8_t(buf, 29, satellites_visible); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, buf, MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, (const char *)packet, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); -#endif + mavlink_gps_raw_int_t *packet = (mavlink_gps_raw_int_t *)msgbuf; + packet->time_usec = time_usec; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->eph = eph; + packet->epv = epv; + packet->vel = vel; + packet->cog = cog; + packet->fix_type = fix_type; + packet->satellites_visible = satellites_visible; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RAW_INT, (const char *)packet, MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_LEN, MAVLINK_MSG_ID_GPS_RAW_INT_CRC); #endif } #endif @@ -307,17 +318,17 @@ static inline void mavlink_msg_gps_raw_int_send_buf(mavlink_message_t *msgbuf, m */ static inline uint64_t mavlink_msg_gps_raw_int_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** * @brief Get field fix_type from gps_raw_int message * - * @return 0-1: no fix, 2: 2D fix, 3: 3D fix, 4: DGPS, 5: RTK. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. + * @return See the GPS_FIX_TYPE enum. */ static inline uint8_t mavlink_msg_gps_raw_int_get_fix_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 28); + return _MAV_RETURN_uint8_t(msg, 28); } /** @@ -327,7 +338,7 @@ static inline uint8_t mavlink_msg_gps_raw_int_get_fix_type(const mavlink_message */ static inline int32_t mavlink_msg_gps_raw_int_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -337,7 +348,7 @@ static inline int32_t mavlink_msg_gps_raw_int_get_lat(const mavlink_message_t* m */ static inline int32_t mavlink_msg_gps_raw_int_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -347,27 +358,27 @@ static inline int32_t mavlink_msg_gps_raw_int_get_lon(const mavlink_message_t* m */ static inline int32_t mavlink_msg_gps_raw_int_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** * @brief Get field eph from gps_raw_int message * - * @return GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @return GPS HDOP horizontal dilution of position (unitless). If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_gps_raw_int_get_eph(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 20); + return _MAV_RETURN_uint16_t(msg, 20); } /** * @brief Get field epv from gps_raw_int message * - * @return GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: UINT16_MAX + * @return GPS VDOP vertical dilution of position (unitless). If unknown, set to: UINT16_MAX */ static inline uint16_t mavlink_msg_gps_raw_int_get_epv(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 22); + return _MAV_RETURN_uint16_t(msg, 22); } /** @@ -377,7 +388,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_get_epv(const mavlink_message_t* */ static inline uint16_t mavlink_msg_gps_raw_int_get_vel(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -387,7 +398,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_get_vel(const mavlink_message_t* */ static inline uint16_t mavlink_msg_gps_raw_int_get_cog(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 26); + return _MAV_RETURN_uint16_t(msg, 26); } /** @@ -397,7 +408,7 @@ static inline uint16_t mavlink_msg_gps_raw_int_get_cog(const mavlink_message_t* */ static inline uint8_t mavlink_msg_gps_raw_int_get_satellites_visible(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 29); + return _MAV_RETURN_uint8_t(msg, 29); } /** @@ -408,18 +419,20 @@ static inline uint8_t mavlink_msg_gps_raw_int_get_satellites_visible(const mavli */ static inline void mavlink_msg_gps_raw_int_decode(const mavlink_message_t* msg, mavlink_gps_raw_int_t* gps_raw_int) { -#if MAVLINK_NEED_BYTE_SWAP - gps_raw_int->time_usec = mavlink_msg_gps_raw_int_get_time_usec(msg); - gps_raw_int->lat = mavlink_msg_gps_raw_int_get_lat(msg); - gps_raw_int->lon = mavlink_msg_gps_raw_int_get_lon(msg); - gps_raw_int->alt = mavlink_msg_gps_raw_int_get_alt(msg); - gps_raw_int->eph = mavlink_msg_gps_raw_int_get_eph(msg); - gps_raw_int->epv = mavlink_msg_gps_raw_int_get_epv(msg); - gps_raw_int->vel = mavlink_msg_gps_raw_int_get_vel(msg); - gps_raw_int->cog = mavlink_msg_gps_raw_int_get_cog(msg); - gps_raw_int->fix_type = mavlink_msg_gps_raw_int_get_fix_type(msg); - gps_raw_int->satellites_visible = mavlink_msg_gps_raw_int_get_satellites_visible(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps_raw_int->time_usec = mavlink_msg_gps_raw_int_get_time_usec(msg); + gps_raw_int->lat = mavlink_msg_gps_raw_int_get_lat(msg); + gps_raw_int->lon = mavlink_msg_gps_raw_int_get_lon(msg); + gps_raw_int->alt = mavlink_msg_gps_raw_int_get_alt(msg); + gps_raw_int->eph = mavlink_msg_gps_raw_int_get_eph(msg); + gps_raw_int->epv = mavlink_msg_gps_raw_int_get_epv(msg); + gps_raw_int->vel = mavlink_msg_gps_raw_int_get_vel(msg); + gps_raw_int->cog = mavlink_msg_gps_raw_int_get_cog(msg); + gps_raw_int->fix_type = mavlink_msg_gps_raw_int_get_fix_type(msg); + gps_raw_int->satellites_visible = mavlink_msg_gps_raw_int_get_satellites_visible(msg); #else - memcpy(gps_raw_int, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GPS_RAW_INT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS_RAW_INT_LEN? msg->len : MAVLINK_MSG_ID_GPS_RAW_INT_LEN; + memset(gps_raw_int, 0, MAVLINK_MSG_ID_GPS_RAW_INT_LEN); + memcpy(gps_raw_int, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps_rtcm_data.h b/vendor/libraries/mavlink/common/mavlink_msg_gps_rtcm_data.h new file mode 100644 index 0000000000..309a97be23 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps_rtcm_data.h @@ -0,0 +1,255 @@ +#pragma once +// MESSAGE GPS_RTCM_DATA PACKING + +#define MAVLINK_MSG_ID_GPS_RTCM_DATA 233 + +MAVPACKED( +typedef struct __mavlink_gps_rtcm_data_t { + uint8_t flags; /*< LSB: 1 means message is fragmented, next 2 bits are the fragment ID, the remaining 5 bits are used for the sequence ID. Messages are only to be flushed to the GPS when the entire message has been reconstructed on the autopilot. The fragment ID specifies which order the fragments should be assembled into a buffer, while the sequence ID is used to detect a mismatch between different buffers. The buffer is considered fully reconstructed when either all 4 fragments are present, or all the fragments before the first fragment with a non full payload is received. This management is used to ensure that normal GPS operation doesn't corrupt RTCM data, and to recover from a unreliable transport delivery order.*/ + uint8_t len; /*< data length*/ + uint8_t data[180]; /*< RTCM message (may be fragmented)*/ +}) mavlink_gps_rtcm_data_t; + +#define MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN 182 +#define MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN 182 +#define MAVLINK_MSG_ID_233_LEN 182 +#define MAVLINK_MSG_ID_233_MIN_LEN 182 + +#define MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC 35 +#define MAVLINK_MSG_ID_233_CRC 35 + +#define MAVLINK_MSG_GPS_RTCM_DATA_FIELD_DATA_LEN 180 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_GPS_RTCM_DATA { \ + 233, \ + "GPS_RTCM_DATA", \ + 3, \ + { { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_rtcm_data_t, flags) }, \ + { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gps_rtcm_data_t, len) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 180, 2, offsetof(mavlink_gps_rtcm_data_t, data) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_GPS_RTCM_DATA { \ + "GPS_RTCM_DATA", \ + 3, \ + { { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_rtcm_data_t, flags) }, \ + { "len", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_gps_rtcm_data_t, len) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 180, 2, offsetof(mavlink_gps_rtcm_data_t, data) }, \ + } \ +} +#endif + +/** + * @brief Pack a gps_rtcm_data message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param flags LSB: 1 means message is fragmented, next 2 bits are the fragment ID, the remaining 5 bits are used for the sequence ID. Messages are only to be flushed to the GPS when the entire message has been reconstructed on the autopilot. The fragment ID specifies which order the fragments should be assembled into a buffer, while the sequence ID is used to detect a mismatch between different buffers. The buffer is considered fully reconstructed when either all 4 fragments are present, or all the fragments before the first fragment with a non full payload is received. This management is used to ensure that normal GPS operation doesn't corrupt RTCM data, and to recover from a unreliable transport delivery order. + * @param len data length + * @param data RTCM message (may be fragmented) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gps_rtcm_data_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t flags, uint8_t len, const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN]; + _mav_put_uint8_t(buf, 0, flags); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 180); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN); +#else + mavlink_gps_rtcm_data_t packet; + packet.flags = flags; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*180); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GPS_RTCM_DATA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC); +} + +/** + * @brief Pack a gps_rtcm_data message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param flags LSB: 1 means message is fragmented, next 2 bits are the fragment ID, the remaining 5 bits are used for the sequence ID. Messages are only to be flushed to the GPS when the entire message has been reconstructed on the autopilot. The fragment ID specifies which order the fragments should be assembled into a buffer, while the sequence ID is used to detect a mismatch between different buffers. The buffer is considered fully reconstructed when either all 4 fragments are present, or all the fragments before the first fragment with a non full payload is received. This management is used to ensure that normal GPS operation doesn't corrupt RTCM data, and to recover from a unreliable transport delivery order. + * @param len data length + * @param data RTCM message (may be fragmented) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_gps_rtcm_data_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t flags,uint8_t len,const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN]; + _mav_put_uint8_t(buf, 0, flags); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 180); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN); +#else + mavlink_gps_rtcm_data_t packet; + packet.flags = flags; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*180); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_GPS_RTCM_DATA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC); +} + +/** + * @brief Encode a gps_rtcm_data struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param gps_rtcm_data C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gps_rtcm_data_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps_rtcm_data_t* gps_rtcm_data) +{ + return mavlink_msg_gps_rtcm_data_pack(system_id, component_id, msg, gps_rtcm_data->flags, gps_rtcm_data->len, gps_rtcm_data->data); +} + +/** + * @brief Encode a gps_rtcm_data struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param gps_rtcm_data C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_gps_rtcm_data_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_rtcm_data_t* gps_rtcm_data) +{ + return mavlink_msg_gps_rtcm_data_pack_chan(system_id, component_id, chan, msg, gps_rtcm_data->flags, gps_rtcm_data->len, gps_rtcm_data->data); +} + +/** + * @brief Send a gps_rtcm_data message + * @param chan MAVLink channel to send the message + * + * @param flags LSB: 1 means message is fragmented, next 2 bits are the fragment ID, the remaining 5 bits are used for the sequence ID. Messages are only to be flushed to the GPS when the entire message has been reconstructed on the autopilot. The fragment ID specifies which order the fragments should be assembled into a buffer, while the sequence ID is used to detect a mismatch between different buffers. The buffer is considered fully reconstructed when either all 4 fragments are present, or all the fragments before the first fragment with a non full payload is received. This management is used to ensure that normal GPS operation doesn't corrupt RTCM data, and to recover from a unreliable transport delivery order. + * @param len data length + * @param data RTCM message (may be fragmented) + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_gps_rtcm_data_send(mavlink_channel_t chan, uint8_t flags, uint8_t len, const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN]; + _mav_put_uint8_t(buf, 0, flags); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 180); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTCM_DATA, buf, MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC); +#else + mavlink_gps_rtcm_data_t packet; + packet.flags = flags; + packet.len = len; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*180); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTCM_DATA, (const char *)&packet, MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC); +#endif +} + +/** + * @brief Send a gps_rtcm_data message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps_rtcm_data_send_struct(mavlink_channel_t chan, const mavlink_gps_rtcm_data_t* gps_rtcm_data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps_rtcm_data_send(chan, gps_rtcm_data->flags, gps_rtcm_data->len, gps_rtcm_data->data); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTCM_DATA, (const char *)gps_rtcm_data, MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC); +#endif +} + +#if MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_gps_rtcm_data_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t flags, uint8_t len, const uint8_t *data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, flags); + _mav_put_uint8_t(buf, 1, len); + _mav_put_uint8_t_array(buf, 2, data, 180); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTCM_DATA, buf, MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC); +#else + mavlink_gps_rtcm_data_t *packet = (mavlink_gps_rtcm_data_t *)msgbuf; + packet->flags = flags; + packet->len = len; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*180); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTCM_DATA, (const char *)packet, MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN, MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC); +#endif +} +#endif + +#endif + +// MESSAGE GPS_RTCM_DATA UNPACKING + + +/** + * @brief Get field flags from gps_rtcm_data message + * + * @return LSB: 1 means message is fragmented, next 2 bits are the fragment ID, the remaining 5 bits are used for the sequence ID. Messages are only to be flushed to the GPS when the entire message has been reconstructed on the autopilot. The fragment ID specifies which order the fragments should be assembled into a buffer, while the sequence ID is used to detect a mismatch between different buffers. The buffer is considered fully reconstructed when either all 4 fragments are present, or all the fragments before the first fragment with a non full payload is received. This management is used to ensure that normal GPS operation doesn't corrupt RTCM data, and to recover from a unreliable transport delivery order. + */ +static inline uint8_t mavlink_msg_gps_rtcm_data_get_flags(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field len from gps_rtcm_data message + * + * @return data length + */ +static inline uint8_t mavlink_msg_gps_rtcm_data_get_len(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Get field data from gps_rtcm_data message + * + * @return RTCM message (may be fragmented) + */ +static inline uint16_t mavlink_msg_gps_rtcm_data_get_data(const mavlink_message_t* msg, uint8_t *data) +{ + return _MAV_RETURN_uint8_t_array(msg, data, 180, 2); +} + +/** + * @brief Decode a gps_rtcm_data message into a struct + * + * @param msg The message to decode + * @param gps_rtcm_data C-struct to decode the message contents into + */ +static inline void mavlink_msg_gps_rtcm_data_decode(const mavlink_message_t* msg, mavlink_gps_rtcm_data_t* gps_rtcm_data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps_rtcm_data->flags = mavlink_msg_gps_rtcm_data_get_flags(msg); + gps_rtcm_data->len = mavlink_msg_gps_rtcm_data_get_len(msg); + mavlink_msg_gps_rtcm_data_get_data(msg, gps_rtcm_data->data); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN? msg->len : MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN; + memset(gps_rtcm_data, 0, MAVLINK_MSG_ID_GPS_RTCM_DATA_LEN); + memcpy(gps_rtcm_data, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps_rtk.h b/vendor/libraries/mavlink/common/mavlink_msg_gps_rtk.h index 31052ec253..3b25c802af 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_gps_rtk.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps_rtk.h @@ -1,36 +1,41 @@ +#pragma once // MESSAGE GPS_RTK PACKING #define MAVLINK_MSG_ID_GPS_RTK 127 -typedef struct __mavlink_gps_rtk_t -{ - uint32_t time_last_baseline_ms; ///< Time since boot of last baseline message received in ms. - uint32_t tow; ///< GPS Time of Week of last baseline - int32_t baseline_a_mm; ///< Current baseline in ECEF x or NED north component in mm. - int32_t baseline_b_mm; ///< Current baseline in ECEF y or NED east component in mm. - int32_t baseline_c_mm; ///< Current baseline in ECEF z or NED down component in mm. - uint32_t accuracy; ///< Current estimate of baseline accuracy. - int32_t iar_num_hypotheses; ///< Current number of integer ambiguity hypotheses. - uint16_t wn; ///< GPS Week Number of last baseline - uint8_t rtk_receiver_id; ///< Identification of connected RTK receiver. - uint8_t rtk_health; ///< GPS-specific health report for RTK data. - uint8_t rtk_rate; ///< Rate of baseline messages being received by GPS, in HZ - uint8_t nsats; ///< Current number of sats used for RTK calculation. - uint8_t baseline_coords_type; ///< Coordinate system of baseline. 0 == ECEF, 1 == NED -} mavlink_gps_rtk_t; +MAVPACKED( +typedef struct __mavlink_gps_rtk_t { + uint32_t time_last_baseline_ms; /*< Time since boot of last baseline message received in ms.*/ + uint32_t tow; /*< GPS Time of Week of last baseline*/ + int32_t baseline_a_mm; /*< Current baseline in ECEF x or NED north component in mm.*/ + int32_t baseline_b_mm; /*< Current baseline in ECEF y or NED east component in mm.*/ + int32_t baseline_c_mm; /*< Current baseline in ECEF z or NED down component in mm.*/ + uint32_t accuracy; /*< Current estimate of baseline accuracy.*/ + int32_t iar_num_hypotheses; /*< Current number of integer ambiguity hypotheses.*/ + uint16_t wn; /*< GPS Week Number of last baseline*/ + uint8_t rtk_receiver_id; /*< Identification of connected RTK receiver.*/ + uint8_t rtk_health; /*< GPS-specific health report for RTK data.*/ + uint8_t rtk_rate; /*< Rate of baseline messages being received by GPS, in HZ*/ + uint8_t nsats; /*< Current number of sats used for RTK calculation.*/ + uint8_t baseline_coords_type; /*< Coordinate system of baseline. 0 == ECEF, 1 == NED*/ +}) mavlink_gps_rtk_t; #define MAVLINK_MSG_ID_GPS_RTK_LEN 35 +#define MAVLINK_MSG_ID_GPS_RTK_MIN_LEN 35 #define MAVLINK_MSG_ID_127_LEN 35 +#define MAVLINK_MSG_ID_127_MIN_LEN 35 #define MAVLINK_MSG_ID_GPS_RTK_CRC 25 #define MAVLINK_MSG_ID_127_CRC 25 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GPS_RTK { \ - "GPS_RTK", \ - 13, \ - { { "time_last_baseline_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_gps_rtk_t, time_last_baseline_ms) }, \ + 127, \ + "GPS_RTK", \ + 13, \ + { { "time_last_baseline_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_gps_rtk_t, time_last_baseline_ms) }, \ { "tow", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_gps_rtk_t, tow) }, \ { "baseline_a_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps_rtk_t, baseline_a_mm) }, \ { "baseline_b_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps_rtk_t, baseline_b_mm) }, \ @@ -45,7 +50,26 @@ typedef struct __mavlink_gps_rtk_t { "baseline_coords_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_gps_rtk_t, baseline_coords_type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GPS_RTK { \ + "GPS_RTK", \ + 13, \ + { { "time_last_baseline_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_gps_rtk_t, time_last_baseline_ms) }, \ + { "tow", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_gps_rtk_t, tow) }, \ + { "baseline_a_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_gps_rtk_t, baseline_a_mm) }, \ + { "baseline_b_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_gps_rtk_t, baseline_b_mm) }, \ + { "baseline_c_mm", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_gps_rtk_t, baseline_c_mm) }, \ + { "accuracy", NULL, MAVLINK_TYPE_UINT32_T, 0, 20, offsetof(mavlink_gps_rtk_t, accuracy) }, \ + { "iar_num_hypotheses", NULL, MAVLINK_TYPE_INT32_T, 0, 24, offsetof(mavlink_gps_rtk_t, iar_num_hypotheses) }, \ + { "wn", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_gps_rtk_t, wn) }, \ + { "rtk_receiver_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 30, offsetof(mavlink_gps_rtk_t, rtk_receiver_id) }, \ + { "rtk_health", NULL, MAVLINK_TYPE_UINT8_T, 0, 31, offsetof(mavlink_gps_rtk_t, rtk_health) }, \ + { "rtk_rate", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_gps_rtk_t, rtk_rate) }, \ + { "nsats", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_gps_rtk_t, nsats) }, \ + { "baseline_coords_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_gps_rtk_t, baseline_coords_type) }, \ + } \ +} +#endif /** * @brief Pack a gps_rtk message @@ -69,50 +93,46 @@ typedef struct __mavlink_gps_rtk_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_rtk_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) + uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_RTK_LEN]; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); + char buf[MAVLINK_MSG_ID_GPS_RTK_LEN]; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_RTK_LEN); #else - mavlink_gps_rtk_t packet; - packet.time_last_baseline_ms = time_last_baseline_ms; - packet.tow = tow; - packet.baseline_a_mm = baseline_a_mm; - packet.baseline_b_mm = baseline_b_mm; - packet.baseline_c_mm = baseline_c_mm; - packet.accuracy = accuracy; - packet.iar_num_hypotheses = iar_num_hypotheses; - packet.wn = wn; - packet.rtk_receiver_id = rtk_receiver_id; - packet.rtk_health = rtk_health; - packet.rtk_rate = rtk_rate; - packet.nsats = nsats; - packet.baseline_coords_type = baseline_coords_type; + mavlink_gps_rtk_t packet; + packet.time_last_baseline_ms = time_last_baseline_ms; + packet.tow = tow; + packet.baseline_a_mm = baseline_a_mm; + packet.baseline_b_mm = baseline_b_mm; + packet.baseline_c_mm = baseline_c_mm; + packet.accuracy = accuracy; + packet.iar_num_hypotheses = iar_num_hypotheses; + packet.wn = wn; + packet.rtk_receiver_id = rtk_receiver_id; + packet.rtk_health = rtk_health; + packet.rtk_rate = rtk_rate; + packet.nsats = nsats; + packet.baseline_coords_type = baseline_coords_type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_RTK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_RTK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_RTK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_RTK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); } /** @@ -137,51 +157,47 @@ static inline uint16_t mavlink_msg_gps_rtk_pack(uint8_t system_id, uint8_t compo * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_rtk_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_last_baseline_ms,uint8_t rtk_receiver_id,uint16_t wn,uint32_t tow,uint8_t rtk_health,uint8_t rtk_rate,uint8_t nsats,uint8_t baseline_coords_type,int32_t baseline_a_mm,int32_t baseline_b_mm,int32_t baseline_c_mm,uint32_t accuracy,int32_t iar_num_hypotheses) + mavlink_message_t* msg, + uint32_t time_last_baseline_ms,uint8_t rtk_receiver_id,uint16_t wn,uint32_t tow,uint8_t rtk_health,uint8_t rtk_rate,uint8_t nsats,uint8_t baseline_coords_type,int32_t baseline_a_mm,int32_t baseline_b_mm,int32_t baseline_c_mm,uint32_t accuracy,int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_RTK_LEN]; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); + char buf[MAVLINK_MSG_ID_GPS_RTK_LEN]; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_RTK_LEN); #else - mavlink_gps_rtk_t packet; - packet.time_last_baseline_ms = time_last_baseline_ms; - packet.tow = tow; - packet.baseline_a_mm = baseline_a_mm; - packet.baseline_b_mm = baseline_b_mm; - packet.baseline_c_mm = baseline_c_mm; - packet.accuracy = accuracy; - packet.iar_num_hypotheses = iar_num_hypotheses; - packet.wn = wn; - packet.rtk_receiver_id = rtk_receiver_id; - packet.rtk_health = rtk_health; - packet.rtk_rate = rtk_rate; - packet.nsats = nsats; - packet.baseline_coords_type = baseline_coords_type; + mavlink_gps_rtk_t packet; + packet.time_last_baseline_ms = time_last_baseline_ms; + packet.tow = tow; + packet.baseline_a_mm = baseline_a_mm; + packet.baseline_b_mm = baseline_b_mm; + packet.baseline_c_mm = baseline_c_mm; + packet.accuracy = accuracy; + packet.iar_num_hypotheses = iar_num_hypotheses; + packet.wn = wn; + packet.rtk_receiver_id = rtk_receiver_id; + packet.rtk_health = rtk_health; + packet.rtk_rate = rtk_rate; + packet.nsats = nsats; + packet.baseline_coords_type = baseline_coords_type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_RTK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_RTK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_RTK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_RTK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); } /** @@ -194,7 +210,7 @@ static inline uint16_t mavlink_msg_gps_rtk_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_gps_rtk_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps_rtk_t* gps_rtk) { - return mavlink_msg_gps_rtk_pack(system_id, component_id, msg, gps_rtk->time_last_baseline_ms, gps_rtk->rtk_receiver_id, gps_rtk->wn, gps_rtk->tow, gps_rtk->rtk_health, gps_rtk->rtk_rate, gps_rtk->nsats, gps_rtk->baseline_coords_type, gps_rtk->baseline_a_mm, gps_rtk->baseline_b_mm, gps_rtk->baseline_c_mm, gps_rtk->accuracy, gps_rtk->iar_num_hypotheses); + return mavlink_msg_gps_rtk_pack(system_id, component_id, msg, gps_rtk->time_last_baseline_ms, gps_rtk->rtk_receiver_id, gps_rtk->wn, gps_rtk->tow, gps_rtk->rtk_health, gps_rtk->rtk_rate, gps_rtk->nsats, gps_rtk->baseline_coords_type, gps_rtk->baseline_a_mm, gps_rtk->baseline_b_mm, gps_rtk->baseline_c_mm, gps_rtk->accuracy, gps_rtk->iar_num_hypotheses); } /** @@ -208,7 +224,7 @@ static inline uint16_t mavlink_msg_gps_rtk_encode(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_gps_rtk_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_rtk_t* gps_rtk) { - return mavlink_msg_gps_rtk_pack_chan(system_id, component_id, chan, msg, gps_rtk->time_last_baseline_ms, gps_rtk->rtk_receiver_id, gps_rtk->wn, gps_rtk->tow, gps_rtk->rtk_health, gps_rtk->rtk_rate, gps_rtk->nsats, gps_rtk->baseline_coords_type, gps_rtk->baseline_a_mm, gps_rtk->baseline_b_mm, gps_rtk->baseline_c_mm, gps_rtk->accuracy, gps_rtk->iar_num_hypotheses); + return mavlink_msg_gps_rtk_pack_chan(system_id, component_id, chan, msg, gps_rtk->time_last_baseline_ms, gps_rtk->rtk_receiver_id, gps_rtk->wn, gps_rtk->tow, gps_rtk->rtk_health, gps_rtk->rtk_rate, gps_rtk->nsats, gps_rtk->baseline_coords_type, gps_rtk->baseline_a_mm, gps_rtk->baseline_b_mm, gps_rtk->baseline_c_mm, gps_rtk->accuracy, gps_rtk->iar_num_hypotheses); } /** @@ -234,47 +250,53 @@ static inline uint16_t mavlink_msg_gps_rtk_encode_chan(uint8_t system_id, uint8_ static inline void mavlink_msg_gps_rtk_send(mavlink_channel_t chan, uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_RTK_LEN]; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, buf, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); + char buf[MAVLINK_MSG_ID_GPS_RTK_LEN]; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, buf, MAVLINK_MSG_ID_GPS_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, buf, MAVLINK_MSG_ID_GPS_RTK_LEN); + mavlink_gps_rtk_t packet; + packet.time_last_baseline_ms = time_last_baseline_ms; + packet.tow = tow; + packet.baseline_a_mm = baseline_a_mm; + packet.baseline_b_mm = baseline_b_mm; + packet.baseline_c_mm = baseline_c_mm; + packet.accuracy = accuracy; + packet.iar_num_hypotheses = iar_num_hypotheses; + packet.wn = wn; + packet.rtk_receiver_id = rtk_receiver_id; + packet.rtk_health = rtk_health; + packet.rtk_rate = rtk_rate; + packet.nsats = nsats; + packet.baseline_coords_type = baseline_coords_type; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, (const char *)&packet, MAVLINK_MSG_ID_GPS_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); #endif +} + +/** + * @brief Send a gps_rtk message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps_rtk_send_struct(mavlink_channel_t chan, const mavlink_gps_rtk_t* gps_rtk) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps_rtk_send(chan, gps_rtk->time_last_baseline_ms, gps_rtk->rtk_receiver_id, gps_rtk->wn, gps_rtk->tow, gps_rtk->rtk_health, gps_rtk->rtk_rate, gps_rtk->nsats, gps_rtk->baseline_coords_type, gps_rtk->baseline_a_mm, gps_rtk->baseline_b_mm, gps_rtk->baseline_c_mm, gps_rtk->accuracy, gps_rtk->iar_num_hypotheses); #else - mavlink_gps_rtk_t packet; - packet.time_last_baseline_ms = time_last_baseline_ms; - packet.tow = tow; - packet.baseline_a_mm = baseline_a_mm; - packet.baseline_b_mm = baseline_b_mm; - packet.baseline_c_mm = baseline_c_mm; - packet.accuracy = accuracy; - packet.iar_num_hypotheses = iar_num_hypotheses; - packet.wn = wn; - packet.rtk_receiver_id = rtk_receiver_id; - packet.rtk_health = rtk_health; - packet.rtk_rate = rtk_rate; - packet.nsats = nsats; - packet.baseline_coords_type = baseline_coords_type; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, (const char *)&packet, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, (const char *)&packet, MAVLINK_MSG_ID_GPS_RTK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, (const char *)gps_rtk, MAVLINK_MSG_ID_GPS_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); #endif } @@ -289,47 +311,39 @@ static inline void mavlink_msg_gps_rtk_send(mavlink_channel_t chan, uint32_t tim static inline void mavlink_msg_gps_rtk_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_last_baseline_ms, uint8_t rtk_receiver_id, uint16_t wn, uint32_t tow, uint8_t rtk_health, uint8_t rtk_rate, uint8_t nsats, uint8_t baseline_coords_type, int32_t baseline_a_mm, int32_t baseline_b_mm, int32_t baseline_c_mm, uint32_t accuracy, int32_t iar_num_hypotheses) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_last_baseline_ms); - _mav_put_uint32_t(buf, 4, tow); - _mav_put_int32_t(buf, 8, baseline_a_mm); - _mav_put_int32_t(buf, 12, baseline_b_mm); - _mav_put_int32_t(buf, 16, baseline_c_mm); - _mav_put_uint32_t(buf, 20, accuracy); - _mav_put_int32_t(buf, 24, iar_num_hypotheses); - _mav_put_uint16_t(buf, 28, wn); - _mav_put_uint8_t(buf, 30, rtk_receiver_id); - _mav_put_uint8_t(buf, 31, rtk_health); - _mav_put_uint8_t(buf, 32, rtk_rate); - _mav_put_uint8_t(buf, 33, nsats); - _mav_put_uint8_t(buf, 34, baseline_coords_type); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, buf, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_last_baseline_ms); + _mav_put_uint32_t(buf, 4, tow); + _mav_put_int32_t(buf, 8, baseline_a_mm); + _mav_put_int32_t(buf, 12, baseline_b_mm); + _mav_put_int32_t(buf, 16, baseline_c_mm); + _mav_put_uint32_t(buf, 20, accuracy); + _mav_put_int32_t(buf, 24, iar_num_hypotheses); + _mav_put_uint16_t(buf, 28, wn); + _mav_put_uint8_t(buf, 30, rtk_receiver_id); + _mav_put_uint8_t(buf, 31, rtk_health); + _mav_put_uint8_t(buf, 32, rtk_rate); + _mav_put_uint8_t(buf, 33, nsats); + _mav_put_uint8_t(buf, 34, baseline_coords_type); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, buf, MAVLINK_MSG_ID_GPS_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, buf, MAVLINK_MSG_ID_GPS_RTK_LEN); -#endif -#else - mavlink_gps_rtk_t *packet = (mavlink_gps_rtk_t *)msgbuf; - packet->time_last_baseline_ms = time_last_baseline_ms; - packet->tow = tow; - packet->baseline_a_mm = baseline_a_mm; - packet->baseline_b_mm = baseline_b_mm; - packet->baseline_c_mm = baseline_c_mm; - packet->accuracy = accuracy; - packet->iar_num_hypotheses = iar_num_hypotheses; - packet->wn = wn; - packet->rtk_receiver_id = rtk_receiver_id; - packet->rtk_health = rtk_health; - packet->rtk_rate = rtk_rate; - packet->nsats = nsats; - packet->baseline_coords_type = baseline_coords_type; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, (const char *)packet, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, (const char *)packet, MAVLINK_MSG_ID_GPS_RTK_LEN); -#endif + mavlink_gps_rtk_t *packet = (mavlink_gps_rtk_t *)msgbuf; + packet->time_last_baseline_ms = time_last_baseline_ms; + packet->tow = tow; + packet->baseline_a_mm = baseline_a_mm; + packet->baseline_b_mm = baseline_b_mm; + packet->baseline_c_mm = baseline_c_mm; + packet->accuracy = accuracy; + packet->iar_num_hypotheses = iar_num_hypotheses; + packet->wn = wn; + packet->rtk_receiver_id = rtk_receiver_id; + packet->rtk_health = rtk_health; + packet->rtk_rate = rtk_rate; + packet->nsats = nsats; + packet->baseline_coords_type = baseline_coords_type; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_RTK, (const char *)packet, MAVLINK_MSG_ID_GPS_RTK_MIN_LEN, MAVLINK_MSG_ID_GPS_RTK_LEN, MAVLINK_MSG_ID_GPS_RTK_CRC); #endif } #endif @@ -346,7 +360,7 @@ static inline void mavlink_msg_gps_rtk_send_buf(mavlink_message_t *msgbuf, mavli */ static inline uint32_t mavlink_msg_gps_rtk_get_time_last_baseline_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -356,7 +370,7 @@ static inline uint32_t mavlink_msg_gps_rtk_get_time_last_baseline_ms(const mavli */ static inline uint8_t mavlink_msg_gps_rtk_get_rtk_receiver_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 30); + return _MAV_RETURN_uint8_t(msg, 30); } /** @@ -366,7 +380,7 @@ static inline uint8_t mavlink_msg_gps_rtk_get_rtk_receiver_id(const mavlink_mess */ static inline uint16_t mavlink_msg_gps_rtk_get_wn(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -376,7 +390,7 @@ static inline uint16_t mavlink_msg_gps_rtk_get_wn(const mavlink_message_t* msg) */ static inline uint32_t mavlink_msg_gps_rtk_get_tow(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 4); + return _MAV_RETURN_uint32_t(msg, 4); } /** @@ -386,7 +400,7 @@ static inline uint32_t mavlink_msg_gps_rtk_get_tow(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_gps_rtk_get_rtk_health(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 31); + return _MAV_RETURN_uint8_t(msg, 31); } /** @@ -396,7 +410,7 @@ static inline uint8_t mavlink_msg_gps_rtk_get_rtk_health(const mavlink_message_t */ static inline uint8_t mavlink_msg_gps_rtk_get_rtk_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -406,7 +420,7 @@ static inline uint8_t mavlink_msg_gps_rtk_get_rtk_rate(const mavlink_message_t* */ static inline uint8_t mavlink_msg_gps_rtk_get_nsats(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 33); + return _MAV_RETURN_uint8_t(msg, 33); } /** @@ -416,7 +430,7 @@ static inline uint8_t mavlink_msg_gps_rtk_get_nsats(const mavlink_message_t* msg */ static inline uint8_t mavlink_msg_gps_rtk_get_baseline_coords_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -426,7 +440,7 @@ static inline uint8_t mavlink_msg_gps_rtk_get_baseline_coords_type(const mavlink */ static inline int32_t mavlink_msg_gps_rtk_get_baseline_a_mm(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -436,7 +450,7 @@ static inline int32_t mavlink_msg_gps_rtk_get_baseline_a_mm(const mavlink_messag */ static inline int32_t mavlink_msg_gps_rtk_get_baseline_b_mm(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -446,7 +460,7 @@ static inline int32_t mavlink_msg_gps_rtk_get_baseline_b_mm(const mavlink_messag */ static inline int32_t mavlink_msg_gps_rtk_get_baseline_c_mm(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -456,7 +470,7 @@ static inline int32_t mavlink_msg_gps_rtk_get_baseline_c_mm(const mavlink_messag */ static inline uint32_t mavlink_msg_gps_rtk_get_accuracy(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 20); + return _MAV_RETURN_uint32_t(msg, 20); } /** @@ -466,7 +480,7 @@ static inline uint32_t mavlink_msg_gps_rtk_get_accuracy(const mavlink_message_t* */ static inline int32_t mavlink_msg_gps_rtk_get_iar_num_hypotheses(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 24); + return _MAV_RETURN_int32_t(msg, 24); } /** @@ -477,21 +491,23 @@ static inline int32_t mavlink_msg_gps_rtk_get_iar_num_hypotheses(const mavlink_m */ static inline void mavlink_msg_gps_rtk_decode(const mavlink_message_t* msg, mavlink_gps_rtk_t* gps_rtk) { -#if MAVLINK_NEED_BYTE_SWAP - gps_rtk->time_last_baseline_ms = mavlink_msg_gps_rtk_get_time_last_baseline_ms(msg); - gps_rtk->tow = mavlink_msg_gps_rtk_get_tow(msg); - gps_rtk->baseline_a_mm = mavlink_msg_gps_rtk_get_baseline_a_mm(msg); - gps_rtk->baseline_b_mm = mavlink_msg_gps_rtk_get_baseline_b_mm(msg); - gps_rtk->baseline_c_mm = mavlink_msg_gps_rtk_get_baseline_c_mm(msg); - gps_rtk->accuracy = mavlink_msg_gps_rtk_get_accuracy(msg); - gps_rtk->iar_num_hypotheses = mavlink_msg_gps_rtk_get_iar_num_hypotheses(msg); - gps_rtk->wn = mavlink_msg_gps_rtk_get_wn(msg); - gps_rtk->rtk_receiver_id = mavlink_msg_gps_rtk_get_rtk_receiver_id(msg); - gps_rtk->rtk_health = mavlink_msg_gps_rtk_get_rtk_health(msg); - gps_rtk->rtk_rate = mavlink_msg_gps_rtk_get_rtk_rate(msg); - gps_rtk->nsats = mavlink_msg_gps_rtk_get_nsats(msg); - gps_rtk->baseline_coords_type = mavlink_msg_gps_rtk_get_baseline_coords_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps_rtk->time_last_baseline_ms = mavlink_msg_gps_rtk_get_time_last_baseline_ms(msg); + gps_rtk->tow = mavlink_msg_gps_rtk_get_tow(msg); + gps_rtk->baseline_a_mm = mavlink_msg_gps_rtk_get_baseline_a_mm(msg); + gps_rtk->baseline_b_mm = mavlink_msg_gps_rtk_get_baseline_b_mm(msg); + gps_rtk->baseline_c_mm = mavlink_msg_gps_rtk_get_baseline_c_mm(msg); + gps_rtk->accuracy = mavlink_msg_gps_rtk_get_accuracy(msg); + gps_rtk->iar_num_hypotheses = mavlink_msg_gps_rtk_get_iar_num_hypotheses(msg); + gps_rtk->wn = mavlink_msg_gps_rtk_get_wn(msg); + gps_rtk->rtk_receiver_id = mavlink_msg_gps_rtk_get_rtk_receiver_id(msg); + gps_rtk->rtk_health = mavlink_msg_gps_rtk_get_rtk_health(msg); + gps_rtk->rtk_rate = mavlink_msg_gps_rtk_get_rtk_rate(msg); + gps_rtk->nsats = mavlink_msg_gps_rtk_get_nsats(msg); + gps_rtk->baseline_coords_type = mavlink_msg_gps_rtk_get_baseline_coords_type(msg); #else - memcpy(gps_rtk, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GPS_RTK_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS_RTK_LEN? msg->len : MAVLINK_MSG_ID_GPS_RTK_LEN; + memset(gps_rtk, 0, MAVLINK_MSG_ID_GPS_RTK_LEN); + memcpy(gps_rtk, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_gps_status.h b/vendor/libraries/mavlink/common/mavlink_msg_gps_status.h index 10659d0dd8..8511be97ce 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_gps_status.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_gps_status.h @@ -1,19 +1,22 @@ +#pragma once // MESSAGE GPS_STATUS PACKING #define MAVLINK_MSG_ID_GPS_STATUS 25 -typedef struct __mavlink_gps_status_t -{ - uint8_t satellites_visible; ///< Number of satellites visible - uint8_t satellite_prn[20]; ///< Global satellite ID - uint8_t satellite_used[20]; ///< 0: Satellite not used, 1: used for localization - uint8_t satellite_elevation[20]; ///< Elevation (0: right on top of receiver, 90: on the horizon) of satellite - uint8_t satellite_azimuth[20]; ///< Direction of satellite, 0: 0 deg, 255: 360 deg. - uint8_t satellite_snr[20]; ///< Signal to noise ratio of satellite -} mavlink_gps_status_t; +MAVPACKED( +typedef struct __mavlink_gps_status_t { + uint8_t satellites_visible; /*< Number of satellites visible*/ + uint8_t satellite_prn[20]; /*< Global satellite ID*/ + uint8_t satellite_used[20]; /*< 0: Satellite not used, 1: used for localization*/ + uint8_t satellite_elevation[20]; /*< Elevation (0: right on top of receiver, 90: on the horizon) of satellite*/ + uint8_t satellite_azimuth[20]; /*< Direction of satellite, 0: 0 deg, 255: 360 deg.*/ + uint8_t satellite_snr[20]; /*< Signal to noise ratio of satellite*/ +}) mavlink_gps_status_t; #define MAVLINK_MSG_ID_GPS_STATUS_LEN 101 +#define MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN 101 #define MAVLINK_MSG_ID_25_LEN 101 +#define MAVLINK_MSG_ID_25_MIN_LEN 101 #define MAVLINK_MSG_ID_GPS_STATUS_CRC 23 #define MAVLINK_MSG_ID_25_CRC 23 @@ -24,10 +27,12 @@ typedef struct __mavlink_gps_status_t #define MAVLINK_MSG_GPS_STATUS_FIELD_SATELLITE_AZIMUTH_LEN 20 #define MAVLINK_MSG_GPS_STATUS_FIELD_SATELLITE_SNR_LEN 20 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_GPS_STATUS { \ - "GPS_STATUS", \ - 6, \ - { { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_status_t, satellites_visible) }, \ + 25, \ + "GPS_STATUS", \ + 6, \ + { { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_status_t, satellites_visible) }, \ { "satellite_prn", NULL, MAVLINK_TYPE_UINT8_T, 20, 1, offsetof(mavlink_gps_status_t, satellite_prn) }, \ { "satellite_used", NULL, MAVLINK_TYPE_UINT8_T, 20, 21, offsetof(mavlink_gps_status_t, satellite_used) }, \ { "satellite_elevation", NULL, MAVLINK_TYPE_UINT8_T, 20, 41, offsetof(mavlink_gps_status_t, satellite_elevation) }, \ @@ -35,7 +40,19 @@ typedef struct __mavlink_gps_status_t { "satellite_snr", NULL, MAVLINK_TYPE_UINT8_T, 20, 81, offsetof(mavlink_gps_status_t, satellite_snr) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_GPS_STATUS { \ + "GPS_STATUS", \ + 6, \ + { { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_gps_status_t, satellites_visible) }, \ + { "satellite_prn", NULL, MAVLINK_TYPE_UINT8_T, 20, 1, offsetof(mavlink_gps_status_t, satellite_prn) }, \ + { "satellite_used", NULL, MAVLINK_TYPE_UINT8_T, 20, 21, offsetof(mavlink_gps_status_t, satellite_used) }, \ + { "satellite_elevation", NULL, MAVLINK_TYPE_UINT8_T, 20, 41, offsetof(mavlink_gps_status_t, satellite_elevation) }, \ + { "satellite_azimuth", NULL, MAVLINK_TYPE_UINT8_T, 20, 61, offsetof(mavlink_gps_status_t, satellite_azimuth) }, \ + { "satellite_snr", NULL, MAVLINK_TYPE_UINT8_T, 20, 81, offsetof(mavlink_gps_status_t, satellite_snr) }, \ + } \ +} +#endif /** * @brief Pack a gps_status message @@ -52,34 +69,30 @@ typedef struct __mavlink_gps_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t satellites_visible, const uint8_t *satellite_prn, const uint8_t *satellite_used, const uint8_t *satellite_elevation, const uint8_t *satellite_azimuth, const uint8_t *satellite_snr) + uint8_t satellites_visible, const uint8_t *satellite_prn, const uint8_t *satellite_used, const uint8_t *satellite_elevation, const uint8_t *satellite_azimuth, const uint8_t *satellite_snr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_STATUS_LEN]; - _mav_put_uint8_t(buf, 0, satellites_visible); - _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); - _mav_put_uint8_t_array(buf, 21, satellite_used, 20); - _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); - _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); - _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); + char buf[MAVLINK_MSG_ID_GPS_STATUS_LEN]; + _mav_put_uint8_t(buf, 0, satellites_visible); + _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); + _mav_put_uint8_t_array(buf, 21, satellite_used, 20); + _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); + _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); + _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_STATUS_LEN); #else - mavlink_gps_status_t packet; - packet.satellites_visible = satellites_visible; - mav_array_memcpy(packet.satellite_prn, satellite_prn, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_used, satellite_used, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_snr, satellite_snr, sizeof(uint8_t)*20); + mavlink_gps_status_t packet; + packet.satellites_visible = satellites_visible; + mav_array_memcpy(packet.satellite_prn, satellite_prn, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_used, satellite_used, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_snr, satellite_snr, sizeof(uint8_t)*20); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); } /** @@ -97,35 +110,31 @@ static inline uint16_t mavlink_msg_gps_status_pack(uint8_t system_id, uint8_t co * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_gps_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t satellites_visible,const uint8_t *satellite_prn,const uint8_t *satellite_used,const uint8_t *satellite_elevation,const uint8_t *satellite_azimuth,const uint8_t *satellite_snr) + mavlink_message_t* msg, + uint8_t satellites_visible,const uint8_t *satellite_prn,const uint8_t *satellite_used,const uint8_t *satellite_elevation,const uint8_t *satellite_azimuth,const uint8_t *satellite_snr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_STATUS_LEN]; - _mav_put_uint8_t(buf, 0, satellites_visible); - _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); - _mav_put_uint8_t_array(buf, 21, satellite_used, 20); - _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); - _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); - _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); + char buf[MAVLINK_MSG_ID_GPS_STATUS_LEN]; + _mav_put_uint8_t(buf, 0, satellites_visible); + _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); + _mav_put_uint8_t_array(buf, 21, satellite_used, 20); + _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); + _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); + _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_GPS_STATUS_LEN); #else - mavlink_gps_status_t packet; - packet.satellites_visible = satellites_visible; - mav_array_memcpy(packet.satellite_prn, satellite_prn, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_used, satellite_used, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_snr, satellite_snr, sizeof(uint8_t)*20); + mavlink_gps_status_t packet; + packet.satellites_visible = satellites_visible; + mav_array_memcpy(packet.satellite_prn, satellite_prn, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_used, satellite_used, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_snr, satellite_snr, sizeof(uint8_t)*20); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_GPS_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_GPS_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_GPS_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_gps_status_pack_chan(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_gps_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_gps_status_t* gps_status) { - return mavlink_msg_gps_status_pack(system_id, component_id, msg, gps_status->satellites_visible, gps_status->satellite_prn, gps_status->satellite_used, gps_status->satellite_elevation, gps_status->satellite_azimuth, gps_status->satellite_snr); + return mavlink_msg_gps_status_pack(system_id, component_id, msg, gps_status->satellites_visible, gps_status->satellite_prn, gps_status->satellite_used, gps_status->satellite_elevation, gps_status->satellite_azimuth, gps_status->satellite_snr); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_gps_status_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_gps_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_gps_status_t* gps_status) { - return mavlink_msg_gps_status_pack_chan(system_id, component_id, chan, msg, gps_status->satellites_visible, gps_status->satellite_prn, gps_status->satellite_used, gps_status->satellite_elevation, gps_status->satellite_azimuth, gps_status->satellite_snr); + return mavlink_msg_gps_status_pack_chan(system_id, component_id, chan, msg, gps_status->satellites_visible, gps_status->satellite_prn, gps_status->satellite_used, gps_status->satellite_elevation, gps_status->satellite_azimuth, gps_status->satellite_snr); } /** @@ -171,31 +180,37 @@ static inline uint16_t mavlink_msg_gps_status_encode_chan(uint8_t system_id, uin static inline void mavlink_msg_gps_status_send(mavlink_channel_t chan, uint8_t satellites_visible, const uint8_t *satellite_prn, const uint8_t *satellite_used, const uint8_t *satellite_elevation, const uint8_t *satellite_azimuth, const uint8_t *satellite_snr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_GPS_STATUS_LEN]; - _mav_put_uint8_t(buf, 0, satellites_visible); - _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); - _mav_put_uint8_t_array(buf, 21, satellite_used, 20); - _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); - _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); - _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, buf, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); + char buf[MAVLINK_MSG_ID_GPS_STATUS_LEN]; + _mav_put_uint8_t(buf, 0, satellites_visible); + _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); + _mav_put_uint8_t_array(buf, 21, satellite_used, 20); + _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); + _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); + _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, buf, MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, buf, MAVLINK_MSG_ID_GPS_STATUS_LEN); + mavlink_gps_status_t packet; + packet.satellites_visible = satellites_visible; + mav_array_memcpy(packet.satellite_prn, satellite_prn, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_used, satellite_used, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); + mav_array_memcpy(packet.satellite_snr, satellite_snr, sizeof(uint8_t)*20); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); #endif +} + +/** + * @brief Send a gps_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_gps_status_send_struct(mavlink_channel_t chan, const mavlink_gps_status_t* gps_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_gps_status_send(chan, gps_status->satellites_visible, gps_status->satellite_prn, gps_status->satellite_used, gps_status->satellite_elevation, gps_status->satellite_azimuth, gps_status->satellite_snr); #else - mavlink_gps_status_t packet; - packet.satellites_visible = satellites_visible; - mav_array_memcpy(packet.satellite_prn, satellite_prn, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_used, satellite_used, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); - mav_array_memcpy(packet.satellite_snr, satellite_snr, sizeof(uint8_t)*20); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_GPS_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, (const char *)gps_status, MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); #endif } @@ -210,31 +225,23 @@ static inline void mavlink_msg_gps_status_send(mavlink_channel_t chan, uint8_t s static inline void mavlink_msg_gps_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t satellites_visible, const uint8_t *satellite_prn, const uint8_t *satellite_used, const uint8_t *satellite_elevation, const uint8_t *satellite_azimuth, const uint8_t *satellite_snr) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, satellites_visible); - _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); - _mav_put_uint8_t_array(buf, 21, satellite_used, 20); - _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); - _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); - _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, buf, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, satellites_visible); + _mav_put_uint8_t_array(buf, 1, satellite_prn, 20); + _mav_put_uint8_t_array(buf, 21, satellite_used, 20); + _mav_put_uint8_t_array(buf, 41, satellite_elevation, 20); + _mav_put_uint8_t_array(buf, 61, satellite_azimuth, 20); + _mav_put_uint8_t_array(buf, 81, satellite_snr, 20); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, buf, MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, buf, MAVLINK_MSG_ID_GPS_STATUS_LEN); -#endif -#else - mavlink_gps_status_t *packet = (mavlink_gps_status_t *)msgbuf; - packet->satellites_visible = satellites_visible; - mav_array_memcpy(packet->satellite_prn, satellite_prn, sizeof(uint8_t)*20); - mav_array_memcpy(packet->satellite_used, satellite_used, sizeof(uint8_t)*20); - mav_array_memcpy(packet->satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); - mav_array_memcpy(packet->satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); - mav_array_memcpy(packet->satellite_snr, satellite_snr, sizeof(uint8_t)*20); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, (const char *)packet, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, (const char *)packet, MAVLINK_MSG_ID_GPS_STATUS_LEN); -#endif + mavlink_gps_status_t *packet = (mavlink_gps_status_t *)msgbuf; + packet->satellites_visible = satellites_visible; + mav_array_memcpy(packet->satellite_prn, satellite_prn, sizeof(uint8_t)*20); + mav_array_memcpy(packet->satellite_used, satellite_used, sizeof(uint8_t)*20); + mav_array_memcpy(packet->satellite_elevation, satellite_elevation, sizeof(uint8_t)*20); + mav_array_memcpy(packet->satellite_azimuth, satellite_azimuth, sizeof(uint8_t)*20); + mav_array_memcpy(packet->satellite_snr, satellite_snr, sizeof(uint8_t)*20); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_GPS_STATUS, (const char *)packet, MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN, MAVLINK_MSG_ID_GPS_STATUS_LEN, MAVLINK_MSG_ID_GPS_STATUS_CRC); #endif } #endif @@ -251,7 +258,7 @@ static inline void mavlink_msg_gps_status_send_buf(mavlink_message_t *msgbuf, ma */ static inline uint8_t mavlink_msg_gps_status_get_satellites_visible(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -261,7 +268,7 @@ static inline uint8_t mavlink_msg_gps_status_get_satellites_visible(const mavlin */ static inline uint16_t mavlink_msg_gps_status_get_satellite_prn(const mavlink_message_t* msg, uint8_t *satellite_prn) { - return _MAV_RETURN_uint8_t_array(msg, satellite_prn, 20, 1); + return _MAV_RETURN_uint8_t_array(msg, satellite_prn, 20, 1); } /** @@ -271,7 +278,7 @@ static inline uint16_t mavlink_msg_gps_status_get_satellite_prn(const mavlink_me */ static inline uint16_t mavlink_msg_gps_status_get_satellite_used(const mavlink_message_t* msg, uint8_t *satellite_used) { - return _MAV_RETURN_uint8_t_array(msg, satellite_used, 20, 21); + return _MAV_RETURN_uint8_t_array(msg, satellite_used, 20, 21); } /** @@ -281,7 +288,7 @@ static inline uint16_t mavlink_msg_gps_status_get_satellite_used(const mavlink_m */ static inline uint16_t mavlink_msg_gps_status_get_satellite_elevation(const mavlink_message_t* msg, uint8_t *satellite_elevation) { - return _MAV_RETURN_uint8_t_array(msg, satellite_elevation, 20, 41); + return _MAV_RETURN_uint8_t_array(msg, satellite_elevation, 20, 41); } /** @@ -291,7 +298,7 @@ static inline uint16_t mavlink_msg_gps_status_get_satellite_elevation(const mavl */ static inline uint16_t mavlink_msg_gps_status_get_satellite_azimuth(const mavlink_message_t* msg, uint8_t *satellite_azimuth) { - return _MAV_RETURN_uint8_t_array(msg, satellite_azimuth, 20, 61); + return _MAV_RETURN_uint8_t_array(msg, satellite_azimuth, 20, 61); } /** @@ -301,7 +308,7 @@ static inline uint16_t mavlink_msg_gps_status_get_satellite_azimuth(const mavlin */ static inline uint16_t mavlink_msg_gps_status_get_satellite_snr(const mavlink_message_t* msg, uint8_t *satellite_snr) { - return _MAV_RETURN_uint8_t_array(msg, satellite_snr, 20, 81); + return _MAV_RETURN_uint8_t_array(msg, satellite_snr, 20, 81); } /** @@ -312,14 +319,16 @@ static inline uint16_t mavlink_msg_gps_status_get_satellite_snr(const mavlink_me */ static inline void mavlink_msg_gps_status_decode(const mavlink_message_t* msg, mavlink_gps_status_t* gps_status) { -#if MAVLINK_NEED_BYTE_SWAP - gps_status->satellites_visible = mavlink_msg_gps_status_get_satellites_visible(msg); - mavlink_msg_gps_status_get_satellite_prn(msg, gps_status->satellite_prn); - mavlink_msg_gps_status_get_satellite_used(msg, gps_status->satellite_used); - mavlink_msg_gps_status_get_satellite_elevation(msg, gps_status->satellite_elevation); - mavlink_msg_gps_status_get_satellite_azimuth(msg, gps_status->satellite_azimuth); - mavlink_msg_gps_status_get_satellite_snr(msg, gps_status->satellite_snr); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + gps_status->satellites_visible = mavlink_msg_gps_status_get_satellites_visible(msg); + mavlink_msg_gps_status_get_satellite_prn(msg, gps_status->satellite_prn); + mavlink_msg_gps_status_get_satellite_used(msg, gps_status->satellite_used); + mavlink_msg_gps_status_get_satellite_elevation(msg, gps_status->satellite_elevation); + mavlink_msg_gps_status_get_satellite_azimuth(msg, gps_status->satellite_azimuth); + mavlink_msg_gps_status_get_satellite_snr(msg, gps_status->satellite_snr); #else - memcpy(gps_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_GPS_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_GPS_STATUS_LEN? msg->len : MAVLINK_MSG_ID_GPS_STATUS_LEN; + memset(gps_status, 0, MAVLINK_MSG_ID_GPS_STATUS_LEN); + memcpy(gps_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_heartbeat.h b/vendor/libraries/mavlink/common/mavlink_msg_heartbeat.h index 733886b9a9..66020ff41f 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_heartbeat.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_heartbeat.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE HEARTBEAT PACKING #define MAVLINK_MSG_ID_HEARTBEAT 0 -typedef struct __mavlink_heartbeat_t -{ - uint32_t custom_mode; ///< A bitfield for use for autopilot-specific flags. - uint8_t type; ///< Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM) - uint8_t autopilot; ///< Autopilot type / class. defined in MAV_AUTOPILOT ENUM - uint8_t base_mode; ///< System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h - uint8_t system_status; ///< System status flag, see MAV_STATE ENUM - uint8_t mavlink_version; ///< MAVLink version, not writable by user, gets added by protocol because of magic data type: uint8_t_mavlink_version -} mavlink_heartbeat_t; +MAVPACKED( +typedef struct __mavlink_heartbeat_t { + uint32_t custom_mode; /*< A bitfield for use for autopilot-specific flags.*/ + uint8_t type; /*< Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM)*/ + uint8_t autopilot; /*< Autopilot type / class. defined in MAV_AUTOPILOT ENUM*/ + uint8_t base_mode; /*< System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h*/ + uint8_t system_status; /*< System status flag, see MAV_STATE ENUM*/ + uint8_t mavlink_version; /*< MAVLink version, not writable by user, gets added by protocol because of magic data type: uint8_t_mavlink_version*/ +}) mavlink_heartbeat_t; #define MAVLINK_MSG_ID_HEARTBEAT_LEN 9 +#define MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN 9 #define MAVLINK_MSG_ID_0_LEN 9 +#define MAVLINK_MSG_ID_0_MIN_LEN 9 #define MAVLINK_MSG_ID_HEARTBEAT_CRC 50 #define MAVLINK_MSG_ID_0_CRC 50 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HEARTBEAT { \ - "HEARTBEAT", \ - 6, \ - { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_heartbeat_t, custom_mode) }, \ + 0, \ + "HEARTBEAT", \ + 6, \ + { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_heartbeat_t, custom_mode) }, \ { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_heartbeat_t, type) }, \ { "autopilot", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_heartbeat_t, autopilot) }, \ { "base_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_heartbeat_t, base_mode) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_heartbeat_t { "mavlink_version", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_heartbeat_t, mavlink_version) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HEARTBEAT { \ + "HEARTBEAT", \ + 6, \ + { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_heartbeat_t, custom_mode) }, \ + { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_heartbeat_t, type) }, \ + { "autopilot", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_heartbeat_t, autopilot) }, \ + { "base_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_heartbeat_t, base_mode) }, \ + { "system_status", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_heartbeat_t, system_status) }, \ + { "mavlink_version", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_heartbeat_t, mavlink_version) }, \ + } \ +} +#endif /** * @brief Pack a heartbeat message @@ -47,36 +64,32 @@ typedef struct __mavlink_heartbeat_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_heartbeat_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t type, uint8_t autopilot, uint8_t base_mode, uint32_t custom_mode, uint8_t system_status) + uint8_t type, uint8_t autopilot, uint8_t base_mode, uint32_t custom_mode, uint8_t system_status) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HEARTBEAT_LEN]; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, type); - _mav_put_uint8_t(buf, 5, autopilot); - _mav_put_uint8_t(buf, 6, base_mode); - _mav_put_uint8_t(buf, 7, system_status); - _mav_put_uint8_t(buf, 8, 3); + char buf[MAVLINK_MSG_ID_HEARTBEAT_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, type); + _mav_put_uint8_t(buf, 5, autopilot); + _mav_put_uint8_t(buf, 6, base_mode); + _mav_put_uint8_t(buf, 7, system_status); + _mav_put_uint8_t(buf, 8, 3); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HEARTBEAT_LEN); #else - mavlink_heartbeat_t packet; - packet.custom_mode = custom_mode; - packet.type = type; - packet.autopilot = autopilot; - packet.base_mode = base_mode; - packet.system_status = system_status; - packet.mavlink_version = 3; + mavlink_heartbeat_t packet; + packet.custom_mode = custom_mode; + packet.type = type; + packet.autopilot = autopilot; + packet.base_mode = base_mode; + packet.system_status = system_status; + packet.mavlink_version = 3; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HEARTBEAT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HEARTBEAT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HEARTBEAT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HEARTBEAT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); } /** @@ -93,37 +106,33 @@ static inline uint16_t mavlink_msg_heartbeat_pack(uint8_t system_id, uint8_t com * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_heartbeat_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t type,uint8_t autopilot,uint8_t base_mode,uint32_t custom_mode,uint8_t system_status) + mavlink_message_t* msg, + uint8_t type,uint8_t autopilot,uint8_t base_mode,uint32_t custom_mode,uint8_t system_status) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HEARTBEAT_LEN]; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, type); - _mav_put_uint8_t(buf, 5, autopilot); - _mav_put_uint8_t(buf, 6, base_mode); - _mav_put_uint8_t(buf, 7, system_status); - _mav_put_uint8_t(buf, 8, 3); + char buf[MAVLINK_MSG_ID_HEARTBEAT_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, type); + _mav_put_uint8_t(buf, 5, autopilot); + _mav_put_uint8_t(buf, 6, base_mode); + _mav_put_uint8_t(buf, 7, system_status); + _mav_put_uint8_t(buf, 8, 3); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HEARTBEAT_LEN); #else - mavlink_heartbeat_t packet; - packet.custom_mode = custom_mode; - packet.type = type; - packet.autopilot = autopilot; - packet.base_mode = base_mode; - packet.system_status = system_status; - packet.mavlink_version = 3; + mavlink_heartbeat_t packet; + packet.custom_mode = custom_mode; + packet.type = type; + packet.autopilot = autopilot; + packet.base_mode = base_mode; + packet.system_status = system_status; + packet.mavlink_version = 3; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HEARTBEAT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HEARTBEAT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HEARTBEAT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HEARTBEAT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); } /** @@ -136,7 +145,7 @@ static inline uint16_t mavlink_msg_heartbeat_pack_chan(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_heartbeat_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_heartbeat_t* heartbeat) { - return mavlink_msg_heartbeat_pack(system_id, component_id, msg, heartbeat->type, heartbeat->autopilot, heartbeat->base_mode, heartbeat->custom_mode, heartbeat->system_status); + return mavlink_msg_heartbeat_pack(system_id, component_id, msg, heartbeat->type, heartbeat->autopilot, heartbeat->base_mode, heartbeat->custom_mode, heartbeat->system_status); } /** @@ -150,7 +159,7 @@ static inline uint16_t mavlink_msg_heartbeat_encode(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_heartbeat_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_heartbeat_t* heartbeat) { - return mavlink_msg_heartbeat_pack_chan(system_id, component_id, chan, msg, heartbeat->type, heartbeat->autopilot, heartbeat->base_mode, heartbeat->custom_mode, heartbeat->system_status); + return mavlink_msg_heartbeat_pack_chan(system_id, component_id, chan, msg, heartbeat->type, heartbeat->autopilot, heartbeat->base_mode, heartbeat->custom_mode, heartbeat->system_status); } /** @@ -168,33 +177,39 @@ static inline uint16_t mavlink_msg_heartbeat_encode_chan(uint8_t system_id, uint static inline void mavlink_msg_heartbeat_send(mavlink_channel_t chan, uint8_t type, uint8_t autopilot, uint8_t base_mode, uint32_t custom_mode, uint8_t system_status) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HEARTBEAT_LEN]; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, type); - _mav_put_uint8_t(buf, 5, autopilot); - _mav_put_uint8_t(buf, 6, base_mode); - _mav_put_uint8_t(buf, 7, system_status); - _mav_put_uint8_t(buf, 8, 3); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, buf, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); + char buf[MAVLINK_MSG_ID_HEARTBEAT_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, type); + _mav_put_uint8_t(buf, 5, autopilot); + _mav_put_uint8_t(buf, 6, base_mode); + _mav_put_uint8_t(buf, 7, system_status); + _mav_put_uint8_t(buf, 8, 3); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, buf, MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, buf, MAVLINK_MSG_ID_HEARTBEAT_LEN); + mavlink_heartbeat_t packet; + packet.custom_mode = custom_mode; + packet.type = type; + packet.autopilot = autopilot; + packet.base_mode = base_mode; + packet.system_status = system_status; + packet.mavlink_version = 3; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, (const char *)&packet, MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); #endif +} + +/** + * @brief Send a heartbeat message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_heartbeat_send_struct(mavlink_channel_t chan, const mavlink_heartbeat_t* heartbeat) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_heartbeat_send(chan, heartbeat->type, heartbeat->autopilot, heartbeat->base_mode, heartbeat->custom_mode, heartbeat->system_status); #else - mavlink_heartbeat_t packet; - packet.custom_mode = custom_mode; - packet.type = type; - packet.autopilot = autopilot; - packet.base_mode = base_mode; - packet.system_status = system_status; - packet.mavlink_version = 3; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, (const char *)&packet, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, (const char *)&packet, MAVLINK_MSG_ID_HEARTBEAT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, (const char *)heartbeat, MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); #endif } @@ -209,33 +224,25 @@ static inline void mavlink_msg_heartbeat_send(mavlink_channel_t chan, uint8_t ty static inline void mavlink_msg_heartbeat_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t type, uint8_t autopilot, uint8_t base_mode, uint32_t custom_mode, uint8_t system_status) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, type); - _mav_put_uint8_t(buf, 5, autopilot); - _mav_put_uint8_t(buf, 6, base_mode); - _mav_put_uint8_t(buf, 7, system_status); - _mav_put_uint8_t(buf, 8, 3); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, buf, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, type); + _mav_put_uint8_t(buf, 5, autopilot); + _mav_put_uint8_t(buf, 6, base_mode); + _mav_put_uint8_t(buf, 7, system_status); + _mav_put_uint8_t(buf, 8, 3); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, buf, MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, buf, MAVLINK_MSG_ID_HEARTBEAT_LEN); -#endif -#else - mavlink_heartbeat_t *packet = (mavlink_heartbeat_t *)msgbuf; - packet->custom_mode = custom_mode; - packet->type = type; - packet->autopilot = autopilot; - packet->base_mode = base_mode; - packet->system_status = system_status; - packet->mavlink_version = 3; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, (const char *)packet, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, (const char *)packet, MAVLINK_MSG_ID_HEARTBEAT_LEN); -#endif + mavlink_heartbeat_t *packet = (mavlink_heartbeat_t *)msgbuf; + packet->custom_mode = custom_mode; + packet->type = type; + packet->autopilot = autopilot; + packet->base_mode = base_mode; + packet->system_status = system_status; + packet->mavlink_version = 3; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HEARTBEAT, (const char *)packet, MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN, MAVLINK_MSG_ID_HEARTBEAT_LEN, MAVLINK_MSG_ID_HEARTBEAT_CRC); #endif } #endif @@ -252,7 +259,7 @@ static inline void mavlink_msg_heartbeat_send_buf(mavlink_message_t *msgbuf, mav */ static inline uint8_t mavlink_msg_heartbeat_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -262,7 +269,7 @@ static inline uint8_t mavlink_msg_heartbeat_get_type(const mavlink_message_t* ms */ static inline uint8_t mavlink_msg_heartbeat_get_autopilot(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -272,7 +279,7 @@ static inline uint8_t mavlink_msg_heartbeat_get_autopilot(const mavlink_message_ */ static inline uint8_t mavlink_msg_heartbeat_get_base_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -282,7 +289,7 @@ static inline uint8_t mavlink_msg_heartbeat_get_base_mode(const mavlink_message_ */ static inline uint32_t mavlink_msg_heartbeat_get_custom_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -292,7 +299,7 @@ static inline uint32_t mavlink_msg_heartbeat_get_custom_mode(const mavlink_messa */ static inline uint8_t mavlink_msg_heartbeat_get_system_status(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -302,7 +309,7 @@ static inline uint8_t mavlink_msg_heartbeat_get_system_status(const mavlink_mess */ static inline uint8_t mavlink_msg_heartbeat_get_mavlink_version(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 8); + return _MAV_RETURN_uint8_t(msg, 8); } /** @@ -313,14 +320,16 @@ static inline uint8_t mavlink_msg_heartbeat_get_mavlink_version(const mavlink_me */ static inline void mavlink_msg_heartbeat_decode(const mavlink_message_t* msg, mavlink_heartbeat_t* heartbeat) { -#if MAVLINK_NEED_BYTE_SWAP - heartbeat->custom_mode = mavlink_msg_heartbeat_get_custom_mode(msg); - heartbeat->type = mavlink_msg_heartbeat_get_type(msg); - heartbeat->autopilot = mavlink_msg_heartbeat_get_autopilot(msg); - heartbeat->base_mode = mavlink_msg_heartbeat_get_base_mode(msg); - heartbeat->system_status = mavlink_msg_heartbeat_get_system_status(msg); - heartbeat->mavlink_version = mavlink_msg_heartbeat_get_mavlink_version(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + heartbeat->custom_mode = mavlink_msg_heartbeat_get_custom_mode(msg); + heartbeat->type = mavlink_msg_heartbeat_get_type(msg); + heartbeat->autopilot = mavlink_msg_heartbeat_get_autopilot(msg); + heartbeat->base_mode = mavlink_msg_heartbeat_get_base_mode(msg); + heartbeat->system_status = mavlink_msg_heartbeat_get_system_status(msg); + heartbeat->mavlink_version = mavlink_msg_heartbeat_get_mavlink_version(msg); #else - memcpy(heartbeat, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HEARTBEAT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HEARTBEAT_LEN? msg->len : MAVLINK_MSG_ID_HEARTBEAT_LEN; + memset(heartbeat, 0, MAVLINK_MSG_ID_HEARTBEAT_LEN); + memcpy(heartbeat, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_high_latency.h b/vendor/libraries/mavlink/common/mavlink_msg_high_latency.h new file mode 100644 index 0000000000..7c87e5c2d9 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_high_latency.h @@ -0,0 +1,788 @@ +#pragma once +// MESSAGE HIGH_LATENCY PACKING + +#define MAVLINK_MSG_ID_HIGH_LATENCY 234 + +MAVPACKED( +typedef struct __mavlink_high_latency_t { + uint32_t custom_mode; /*< A bitfield for use for autopilot-specific flags.*/ + int32_t latitude; /*< Latitude, expressed as degrees * 1E7*/ + int32_t longitude; /*< Longitude, expressed as degrees * 1E7*/ + int16_t roll; /*< roll (centidegrees)*/ + int16_t pitch; /*< pitch (centidegrees)*/ + uint16_t heading; /*< heading (centidegrees)*/ + int16_t heading_sp; /*< heading setpoint (centidegrees)*/ + int16_t altitude_amsl; /*< Altitude above mean sea level (meters)*/ + int16_t altitude_sp; /*< Altitude setpoint relative to the home position (meters)*/ + uint16_t wp_distance; /*< distance to target (meters)*/ + uint8_t base_mode; /*< System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h*/ + uint8_t landed_state; /*< The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown.*/ + int8_t throttle; /*< throttle (percentage)*/ + uint8_t airspeed; /*< airspeed (m/s)*/ + uint8_t airspeed_sp; /*< airspeed setpoint (m/s)*/ + uint8_t groundspeed; /*< groundspeed (m/s)*/ + int8_t climb_rate; /*< climb rate (m/s)*/ + uint8_t gps_nsat; /*< Number of satellites visible. If unknown, set to 255*/ + uint8_t gps_fix_type; /*< See the GPS_FIX_TYPE enum.*/ + uint8_t battery_remaining; /*< Remaining battery (percentage)*/ + int8_t temperature; /*< Autopilot temperature (degrees C)*/ + int8_t temperature_air; /*< Air temperature (degrees C) from airspeed sensor*/ + uint8_t failsafe; /*< failsafe (each bit represents a failsafe where 0=ok, 1=failsafe active (bit0:RC, bit1:batt, bit2:GPS, bit3:GCS, bit4:fence)*/ + uint8_t wp_num; /*< current waypoint number*/ +}) mavlink_high_latency_t; + +#define MAVLINK_MSG_ID_HIGH_LATENCY_LEN 40 +#define MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN 40 +#define MAVLINK_MSG_ID_234_LEN 40 +#define MAVLINK_MSG_ID_234_MIN_LEN 40 + +#define MAVLINK_MSG_ID_HIGH_LATENCY_CRC 150 +#define MAVLINK_MSG_ID_234_CRC 150 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_HIGH_LATENCY { \ + 234, \ + "HIGH_LATENCY", \ + 24, \ + { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_high_latency_t, custom_mode) }, \ + { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_high_latency_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_high_latency_t, longitude) }, \ + { "roll", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_high_latency_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_high_latency_t, pitch) }, \ + { "heading", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_high_latency_t, heading) }, \ + { "heading_sp", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_high_latency_t, heading_sp) }, \ + { "altitude_amsl", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_high_latency_t, altitude_amsl) }, \ + { "altitude_sp", NULL, MAVLINK_TYPE_INT16_T, 0, 22, offsetof(mavlink_high_latency_t, altitude_sp) }, \ + { "wp_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_high_latency_t, wp_distance) }, \ + { "base_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 26, offsetof(mavlink_high_latency_t, base_mode) }, \ + { "landed_state", NULL, MAVLINK_TYPE_UINT8_T, 0, 27, offsetof(mavlink_high_latency_t, landed_state) }, \ + { "throttle", NULL, MAVLINK_TYPE_INT8_T, 0, 28, offsetof(mavlink_high_latency_t, throttle) }, \ + { "airspeed", NULL, MAVLINK_TYPE_UINT8_T, 0, 29, offsetof(mavlink_high_latency_t, airspeed) }, \ + { "airspeed_sp", NULL, MAVLINK_TYPE_UINT8_T, 0, 30, offsetof(mavlink_high_latency_t, airspeed_sp) }, \ + { "groundspeed", NULL, MAVLINK_TYPE_UINT8_T, 0, 31, offsetof(mavlink_high_latency_t, groundspeed) }, \ + { "climb_rate", NULL, MAVLINK_TYPE_INT8_T, 0, 32, offsetof(mavlink_high_latency_t, climb_rate) }, \ + { "gps_nsat", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_high_latency_t, gps_nsat) }, \ + { "gps_fix_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_high_latency_t, gps_fix_type) }, \ + { "battery_remaining", NULL, MAVLINK_TYPE_UINT8_T, 0, 35, offsetof(mavlink_high_latency_t, battery_remaining) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT8_T, 0, 36, offsetof(mavlink_high_latency_t, temperature) }, \ + { "temperature_air", NULL, MAVLINK_TYPE_INT8_T, 0, 37, offsetof(mavlink_high_latency_t, temperature_air) }, \ + { "failsafe", NULL, MAVLINK_TYPE_UINT8_T, 0, 38, offsetof(mavlink_high_latency_t, failsafe) }, \ + { "wp_num", NULL, MAVLINK_TYPE_UINT8_T, 0, 39, offsetof(mavlink_high_latency_t, wp_num) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_HIGH_LATENCY { \ + "HIGH_LATENCY", \ + 24, \ + { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_high_latency_t, custom_mode) }, \ + { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_high_latency_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_high_latency_t, longitude) }, \ + { "roll", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_high_latency_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_high_latency_t, pitch) }, \ + { "heading", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_high_latency_t, heading) }, \ + { "heading_sp", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_high_latency_t, heading_sp) }, \ + { "altitude_amsl", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_high_latency_t, altitude_amsl) }, \ + { "altitude_sp", NULL, MAVLINK_TYPE_INT16_T, 0, 22, offsetof(mavlink_high_latency_t, altitude_sp) }, \ + { "wp_distance", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_high_latency_t, wp_distance) }, \ + { "base_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 26, offsetof(mavlink_high_latency_t, base_mode) }, \ + { "landed_state", NULL, MAVLINK_TYPE_UINT8_T, 0, 27, offsetof(mavlink_high_latency_t, landed_state) }, \ + { "throttle", NULL, MAVLINK_TYPE_INT8_T, 0, 28, offsetof(mavlink_high_latency_t, throttle) }, \ + { "airspeed", NULL, MAVLINK_TYPE_UINT8_T, 0, 29, offsetof(mavlink_high_latency_t, airspeed) }, \ + { "airspeed_sp", NULL, MAVLINK_TYPE_UINT8_T, 0, 30, offsetof(mavlink_high_latency_t, airspeed_sp) }, \ + { "groundspeed", NULL, MAVLINK_TYPE_UINT8_T, 0, 31, offsetof(mavlink_high_latency_t, groundspeed) }, \ + { "climb_rate", NULL, MAVLINK_TYPE_INT8_T, 0, 32, offsetof(mavlink_high_latency_t, climb_rate) }, \ + { "gps_nsat", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_high_latency_t, gps_nsat) }, \ + { "gps_fix_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_high_latency_t, gps_fix_type) }, \ + { "battery_remaining", NULL, MAVLINK_TYPE_UINT8_T, 0, 35, offsetof(mavlink_high_latency_t, battery_remaining) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT8_T, 0, 36, offsetof(mavlink_high_latency_t, temperature) }, \ + { "temperature_air", NULL, MAVLINK_TYPE_INT8_T, 0, 37, offsetof(mavlink_high_latency_t, temperature_air) }, \ + { "failsafe", NULL, MAVLINK_TYPE_UINT8_T, 0, 38, offsetof(mavlink_high_latency_t, failsafe) }, \ + { "wp_num", NULL, MAVLINK_TYPE_UINT8_T, 0, 39, offsetof(mavlink_high_latency_t, wp_num) }, \ + } \ +} +#endif + +/** + * @brief Pack a high_latency message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param base_mode System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h + * @param custom_mode A bitfield for use for autopilot-specific flags. + * @param landed_state The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + * @param roll roll (centidegrees) + * @param pitch pitch (centidegrees) + * @param heading heading (centidegrees) + * @param throttle throttle (percentage) + * @param heading_sp heading setpoint (centidegrees) + * @param latitude Latitude, expressed as degrees * 1E7 + * @param longitude Longitude, expressed as degrees * 1E7 + * @param altitude_amsl Altitude above mean sea level (meters) + * @param altitude_sp Altitude setpoint relative to the home position (meters) + * @param airspeed airspeed (m/s) + * @param airspeed_sp airspeed setpoint (m/s) + * @param groundspeed groundspeed (m/s) + * @param climb_rate climb rate (m/s) + * @param gps_nsat Number of satellites visible. If unknown, set to 255 + * @param gps_fix_type See the GPS_FIX_TYPE enum. + * @param battery_remaining Remaining battery (percentage) + * @param temperature Autopilot temperature (degrees C) + * @param temperature_air Air temperature (degrees C) from airspeed sensor + * @param failsafe failsafe (each bit represents a failsafe where 0=ok, 1=failsafe active (bit0:RC, bit1:batt, bit2:GPS, bit3:GCS, bit4:fence) + * @param wp_num current waypoint number + * @param wp_distance distance to target (meters) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_high_latency_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t base_mode, uint32_t custom_mode, uint8_t landed_state, int16_t roll, int16_t pitch, uint16_t heading, int8_t throttle, int16_t heading_sp, int32_t latitude, int32_t longitude, int16_t altitude_amsl, int16_t altitude_sp, uint8_t airspeed, uint8_t airspeed_sp, uint8_t groundspeed, int8_t climb_rate, uint8_t gps_nsat, uint8_t gps_fix_type, uint8_t battery_remaining, int8_t temperature, int8_t temperature_air, uint8_t failsafe, uint8_t wp_num, uint16_t wp_distance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HIGH_LATENCY_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_int32_t(buf, 4, latitude); + _mav_put_int32_t(buf, 8, longitude); + _mav_put_int16_t(buf, 12, roll); + _mav_put_int16_t(buf, 14, pitch); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_int16_t(buf, 18, heading_sp); + _mav_put_int16_t(buf, 20, altitude_amsl); + _mav_put_int16_t(buf, 22, altitude_sp); + _mav_put_uint16_t(buf, 24, wp_distance); + _mav_put_uint8_t(buf, 26, base_mode); + _mav_put_uint8_t(buf, 27, landed_state); + _mav_put_int8_t(buf, 28, throttle); + _mav_put_uint8_t(buf, 29, airspeed); + _mav_put_uint8_t(buf, 30, airspeed_sp); + _mav_put_uint8_t(buf, 31, groundspeed); + _mav_put_int8_t(buf, 32, climb_rate); + _mav_put_uint8_t(buf, 33, gps_nsat); + _mav_put_uint8_t(buf, 34, gps_fix_type); + _mav_put_uint8_t(buf, 35, battery_remaining); + _mav_put_int8_t(buf, 36, temperature); + _mav_put_int8_t(buf, 37, temperature_air); + _mav_put_uint8_t(buf, 38, failsafe); + _mav_put_uint8_t(buf, 39, wp_num); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIGH_LATENCY_LEN); +#else + mavlink_high_latency_t packet; + packet.custom_mode = custom_mode; + packet.latitude = latitude; + packet.longitude = longitude; + packet.roll = roll; + packet.pitch = pitch; + packet.heading = heading; + packet.heading_sp = heading_sp; + packet.altitude_amsl = altitude_amsl; + packet.altitude_sp = altitude_sp; + packet.wp_distance = wp_distance; + packet.base_mode = base_mode; + packet.landed_state = landed_state; + packet.throttle = throttle; + packet.airspeed = airspeed; + packet.airspeed_sp = airspeed_sp; + packet.groundspeed = groundspeed; + packet.climb_rate = climb_rate; + packet.gps_nsat = gps_nsat; + packet.gps_fix_type = gps_fix_type; + packet.battery_remaining = battery_remaining; + packet.temperature = temperature; + packet.temperature_air = temperature_air; + packet.failsafe = failsafe; + packet.wp_num = wp_num; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIGH_LATENCY_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_HIGH_LATENCY; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_CRC); +} + +/** + * @brief Pack a high_latency message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param base_mode System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h + * @param custom_mode A bitfield for use for autopilot-specific flags. + * @param landed_state The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + * @param roll roll (centidegrees) + * @param pitch pitch (centidegrees) + * @param heading heading (centidegrees) + * @param throttle throttle (percentage) + * @param heading_sp heading setpoint (centidegrees) + * @param latitude Latitude, expressed as degrees * 1E7 + * @param longitude Longitude, expressed as degrees * 1E7 + * @param altitude_amsl Altitude above mean sea level (meters) + * @param altitude_sp Altitude setpoint relative to the home position (meters) + * @param airspeed airspeed (m/s) + * @param airspeed_sp airspeed setpoint (m/s) + * @param groundspeed groundspeed (m/s) + * @param climb_rate climb rate (m/s) + * @param gps_nsat Number of satellites visible. If unknown, set to 255 + * @param gps_fix_type See the GPS_FIX_TYPE enum. + * @param battery_remaining Remaining battery (percentage) + * @param temperature Autopilot temperature (degrees C) + * @param temperature_air Air temperature (degrees C) from airspeed sensor + * @param failsafe failsafe (each bit represents a failsafe where 0=ok, 1=failsafe active (bit0:RC, bit1:batt, bit2:GPS, bit3:GCS, bit4:fence) + * @param wp_num current waypoint number + * @param wp_distance distance to target (meters) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_high_latency_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t base_mode,uint32_t custom_mode,uint8_t landed_state,int16_t roll,int16_t pitch,uint16_t heading,int8_t throttle,int16_t heading_sp,int32_t latitude,int32_t longitude,int16_t altitude_amsl,int16_t altitude_sp,uint8_t airspeed,uint8_t airspeed_sp,uint8_t groundspeed,int8_t climb_rate,uint8_t gps_nsat,uint8_t gps_fix_type,uint8_t battery_remaining,int8_t temperature,int8_t temperature_air,uint8_t failsafe,uint8_t wp_num,uint16_t wp_distance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HIGH_LATENCY_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_int32_t(buf, 4, latitude); + _mav_put_int32_t(buf, 8, longitude); + _mav_put_int16_t(buf, 12, roll); + _mav_put_int16_t(buf, 14, pitch); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_int16_t(buf, 18, heading_sp); + _mav_put_int16_t(buf, 20, altitude_amsl); + _mav_put_int16_t(buf, 22, altitude_sp); + _mav_put_uint16_t(buf, 24, wp_distance); + _mav_put_uint8_t(buf, 26, base_mode); + _mav_put_uint8_t(buf, 27, landed_state); + _mav_put_int8_t(buf, 28, throttle); + _mav_put_uint8_t(buf, 29, airspeed); + _mav_put_uint8_t(buf, 30, airspeed_sp); + _mav_put_uint8_t(buf, 31, groundspeed); + _mav_put_int8_t(buf, 32, climb_rate); + _mav_put_uint8_t(buf, 33, gps_nsat); + _mav_put_uint8_t(buf, 34, gps_fix_type); + _mav_put_uint8_t(buf, 35, battery_remaining); + _mav_put_int8_t(buf, 36, temperature); + _mav_put_int8_t(buf, 37, temperature_air); + _mav_put_uint8_t(buf, 38, failsafe); + _mav_put_uint8_t(buf, 39, wp_num); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIGH_LATENCY_LEN); +#else + mavlink_high_latency_t packet; + packet.custom_mode = custom_mode; + packet.latitude = latitude; + packet.longitude = longitude; + packet.roll = roll; + packet.pitch = pitch; + packet.heading = heading; + packet.heading_sp = heading_sp; + packet.altitude_amsl = altitude_amsl; + packet.altitude_sp = altitude_sp; + packet.wp_distance = wp_distance; + packet.base_mode = base_mode; + packet.landed_state = landed_state; + packet.throttle = throttle; + packet.airspeed = airspeed; + packet.airspeed_sp = airspeed_sp; + packet.groundspeed = groundspeed; + packet.climb_rate = climb_rate; + packet.gps_nsat = gps_nsat; + packet.gps_fix_type = gps_fix_type; + packet.battery_remaining = battery_remaining; + packet.temperature = temperature; + packet.temperature_air = temperature_air; + packet.failsafe = failsafe; + packet.wp_num = wp_num; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIGH_LATENCY_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_HIGH_LATENCY; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_CRC); +} + +/** + * @brief Encode a high_latency struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param high_latency C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_high_latency_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_high_latency_t* high_latency) +{ + return mavlink_msg_high_latency_pack(system_id, component_id, msg, high_latency->base_mode, high_latency->custom_mode, high_latency->landed_state, high_latency->roll, high_latency->pitch, high_latency->heading, high_latency->throttle, high_latency->heading_sp, high_latency->latitude, high_latency->longitude, high_latency->altitude_amsl, high_latency->altitude_sp, high_latency->airspeed, high_latency->airspeed_sp, high_latency->groundspeed, high_latency->climb_rate, high_latency->gps_nsat, high_latency->gps_fix_type, high_latency->battery_remaining, high_latency->temperature, high_latency->temperature_air, high_latency->failsafe, high_latency->wp_num, high_latency->wp_distance); +} + +/** + * @brief Encode a high_latency struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param high_latency C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_high_latency_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_high_latency_t* high_latency) +{ + return mavlink_msg_high_latency_pack_chan(system_id, component_id, chan, msg, high_latency->base_mode, high_latency->custom_mode, high_latency->landed_state, high_latency->roll, high_latency->pitch, high_latency->heading, high_latency->throttle, high_latency->heading_sp, high_latency->latitude, high_latency->longitude, high_latency->altitude_amsl, high_latency->altitude_sp, high_latency->airspeed, high_latency->airspeed_sp, high_latency->groundspeed, high_latency->climb_rate, high_latency->gps_nsat, high_latency->gps_fix_type, high_latency->battery_remaining, high_latency->temperature, high_latency->temperature_air, high_latency->failsafe, high_latency->wp_num, high_latency->wp_distance); +} + +/** + * @brief Send a high_latency message + * @param chan MAVLink channel to send the message + * + * @param base_mode System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h + * @param custom_mode A bitfield for use for autopilot-specific flags. + * @param landed_state The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + * @param roll roll (centidegrees) + * @param pitch pitch (centidegrees) + * @param heading heading (centidegrees) + * @param throttle throttle (percentage) + * @param heading_sp heading setpoint (centidegrees) + * @param latitude Latitude, expressed as degrees * 1E7 + * @param longitude Longitude, expressed as degrees * 1E7 + * @param altitude_amsl Altitude above mean sea level (meters) + * @param altitude_sp Altitude setpoint relative to the home position (meters) + * @param airspeed airspeed (m/s) + * @param airspeed_sp airspeed setpoint (m/s) + * @param groundspeed groundspeed (m/s) + * @param climb_rate climb rate (m/s) + * @param gps_nsat Number of satellites visible. If unknown, set to 255 + * @param gps_fix_type See the GPS_FIX_TYPE enum. + * @param battery_remaining Remaining battery (percentage) + * @param temperature Autopilot temperature (degrees C) + * @param temperature_air Air temperature (degrees C) from airspeed sensor + * @param failsafe failsafe (each bit represents a failsafe where 0=ok, 1=failsafe active (bit0:RC, bit1:batt, bit2:GPS, bit3:GCS, bit4:fence) + * @param wp_num current waypoint number + * @param wp_distance distance to target (meters) + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_high_latency_send(mavlink_channel_t chan, uint8_t base_mode, uint32_t custom_mode, uint8_t landed_state, int16_t roll, int16_t pitch, uint16_t heading, int8_t throttle, int16_t heading_sp, int32_t latitude, int32_t longitude, int16_t altitude_amsl, int16_t altitude_sp, uint8_t airspeed, uint8_t airspeed_sp, uint8_t groundspeed, int8_t climb_rate, uint8_t gps_nsat, uint8_t gps_fix_type, uint8_t battery_remaining, int8_t temperature, int8_t temperature_air, uint8_t failsafe, uint8_t wp_num, uint16_t wp_distance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HIGH_LATENCY_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_int32_t(buf, 4, latitude); + _mav_put_int32_t(buf, 8, longitude); + _mav_put_int16_t(buf, 12, roll); + _mav_put_int16_t(buf, 14, pitch); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_int16_t(buf, 18, heading_sp); + _mav_put_int16_t(buf, 20, altitude_amsl); + _mav_put_int16_t(buf, 22, altitude_sp); + _mav_put_uint16_t(buf, 24, wp_distance); + _mav_put_uint8_t(buf, 26, base_mode); + _mav_put_uint8_t(buf, 27, landed_state); + _mav_put_int8_t(buf, 28, throttle); + _mav_put_uint8_t(buf, 29, airspeed); + _mav_put_uint8_t(buf, 30, airspeed_sp); + _mav_put_uint8_t(buf, 31, groundspeed); + _mav_put_int8_t(buf, 32, climb_rate); + _mav_put_uint8_t(buf, 33, gps_nsat); + _mav_put_uint8_t(buf, 34, gps_fix_type); + _mav_put_uint8_t(buf, 35, battery_remaining); + _mav_put_int8_t(buf, 36, temperature); + _mav_put_int8_t(buf, 37, temperature_air); + _mav_put_uint8_t(buf, 38, failsafe); + _mav_put_uint8_t(buf, 39, wp_num); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGH_LATENCY, buf, MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_CRC); +#else + mavlink_high_latency_t packet; + packet.custom_mode = custom_mode; + packet.latitude = latitude; + packet.longitude = longitude; + packet.roll = roll; + packet.pitch = pitch; + packet.heading = heading; + packet.heading_sp = heading_sp; + packet.altitude_amsl = altitude_amsl; + packet.altitude_sp = altitude_sp; + packet.wp_distance = wp_distance; + packet.base_mode = base_mode; + packet.landed_state = landed_state; + packet.throttle = throttle; + packet.airspeed = airspeed; + packet.airspeed_sp = airspeed_sp; + packet.groundspeed = groundspeed; + packet.climb_rate = climb_rate; + packet.gps_nsat = gps_nsat; + packet.gps_fix_type = gps_fix_type; + packet.battery_remaining = battery_remaining; + packet.temperature = temperature; + packet.temperature_air = temperature_air; + packet.failsafe = failsafe; + packet.wp_num = wp_num; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGH_LATENCY, (const char *)&packet, MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_CRC); +#endif +} + +/** + * @brief Send a high_latency message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_high_latency_send_struct(mavlink_channel_t chan, const mavlink_high_latency_t* high_latency) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_high_latency_send(chan, high_latency->base_mode, high_latency->custom_mode, high_latency->landed_state, high_latency->roll, high_latency->pitch, high_latency->heading, high_latency->throttle, high_latency->heading_sp, high_latency->latitude, high_latency->longitude, high_latency->altitude_amsl, high_latency->altitude_sp, high_latency->airspeed, high_latency->airspeed_sp, high_latency->groundspeed, high_latency->climb_rate, high_latency->gps_nsat, high_latency->gps_fix_type, high_latency->battery_remaining, high_latency->temperature, high_latency->temperature_air, high_latency->failsafe, high_latency->wp_num, high_latency->wp_distance); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGH_LATENCY, (const char *)high_latency, MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_CRC); +#endif +} + +#if MAVLINK_MSG_ID_HIGH_LATENCY_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_high_latency_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t base_mode, uint32_t custom_mode, uint8_t landed_state, int16_t roll, int16_t pitch, uint16_t heading, int8_t throttle, int16_t heading_sp, int32_t latitude, int32_t longitude, int16_t altitude_amsl, int16_t altitude_sp, uint8_t airspeed, uint8_t airspeed_sp, uint8_t groundspeed, int8_t climb_rate, uint8_t gps_nsat, uint8_t gps_fix_type, uint8_t battery_remaining, int8_t temperature, int8_t temperature_air, uint8_t failsafe, uint8_t wp_num, uint16_t wp_distance) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_int32_t(buf, 4, latitude); + _mav_put_int32_t(buf, 8, longitude); + _mav_put_int16_t(buf, 12, roll); + _mav_put_int16_t(buf, 14, pitch); + _mav_put_uint16_t(buf, 16, heading); + _mav_put_int16_t(buf, 18, heading_sp); + _mav_put_int16_t(buf, 20, altitude_amsl); + _mav_put_int16_t(buf, 22, altitude_sp); + _mav_put_uint16_t(buf, 24, wp_distance); + _mav_put_uint8_t(buf, 26, base_mode); + _mav_put_uint8_t(buf, 27, landed_state); + _mav_put_int8_t(buf, 28, throttle); + _mav_put_uint8_t(buf, 29, airspeed); + _mav_put_uint8_t(buf, 30, airspeed_sp); + _mav_put_uint8_t(buf, 31, groundspeed); + _mav_put_int8_t(buf, 32, climb_rate); + _mav_put_uint8_t(buf, 33, gps_nsat); + _mav_put_uint8_t(buf, 34, gps_fix_type); + _mav_put_uint8_t(buf, 35, battery_remaining); + _mav_put_int8_t(buf, 36, temperature); + _mav_put_int8_t(buf, 37, temperature_air); + _mav_put_uint8_t(buf, 38, failsafe); + _mav_put_uint8_t(buf, 39, wp_num); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGH_LATENCY, buf, MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_CRC); +#else + mavlink_high_latency_t *packet = (mavlink_high_latency_t *)msgbuf; + packet->custom_mode = custom_mode; + packet->latitude = latitude; + packet->longitude = longitude; + packet->roll = roll; + packet->pitch = pitch; + packet->heading = heading; + packet->heading_sp = heading_sp; + packet->altitude_amsl = altitude_amsl; + packet->altitude_sp = altitude_sp; + packet->wp_distance = wp_distance; + packet->base_mode = base_mode; + packet->landed_state = landed_state; + packet->throttle = throttle; + packet->airspeed = airspeed; + packet->airspeed_sp = airspeed_sp; + packet->groundspeed = groundspeed; + packet->climb_rate = climb_rate; + packet->gps_nsat = gps_nsat; + packet->gps_fix_type = gps_fix_type; + packet->battery_remaining = battery_remaining; + packet->temperature = temperature; + packet->temperature_air = temperature_air; + packet->failsafe = failsafe; + packet->wp_num = wp_num; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGH_LATENCY, (const char *)packet, MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_LEN, MAVLINK_MSG_ID_HIGH_LATENCY_CRC); +#endif +} +#endif + +#endif + +// MESSAGE HIGH_LATENCY UNPACKING + + +/** + * @brief Get field base_mode from high_latency message + * + * @return System mode bitfield, see MAV_MODE_FLAG ENUM in mavlink/include/mavlink_types.h + */ +static inline uint8_t mavlink_msg_high_latency_get_base_mode(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 26); +} + +/** + * @brief Get field custom_mode from high_latency message + * + * @return A bitfield for use for autopilot-specific flags. + */ +static inline uint32_t mavlink_msg_high_latency_get_custom_mode(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 0); +} + +/** + * @brief Get field landed_state from high_latency message + * + * @return The landed state. Is set to MAV_LANDED_STATE_UNDEFINED if landed state is unknown. + */ +static inline uint8_t mavlink_msg_high_latency_get_landed_state(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 27); +} + +/** + * @brief Get field roll from high_latency message + * + * @return roll (centidegrees) + */ +static inline int16_t mavlink_msg_high_latency_get_roll(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 12); +} + +/** + * @brief Get field pitch from high_latency message + * + * @return pitch (centidegrees) + */ +static inline int16_t mavlink_msg_high_latency_get_pitch(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 14); +} + +/** + * @brief Get field heading from high_latency message + * + * @return heading (centidegrees) + */ +static inline uint16_t mavlink_msg_high_latency_get_heading(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 16); +} + +/** + * @brief Get field throttle from high_latency message + * + * @return throttle (percentage) + */ +static inline int8_t mavlink_msg_high_latency_get_throttle(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int8_t(msg, 28); +} + +/** + * @brief Get field heading_sp from high_latency message + * + * @return heading setpoint (centidegrees) + */ +static inline int16_t mavlink_msg_high_latency_get_heading_sp(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 18); +} + +/** + * @brief Get field latitude from high_latency message + * + * @return Latitude, expressed as degrees * 1E7 + */ +static inline int32_t mavlink_msg_high_latency_get_latitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 4); +} + +/** + * @brief Get field longitude from high_latency message + * + * @return Longitude, expressed as degrees * 1E7 + */ +static inline int32_t mavlink_msg_high_latency_get_longitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 8); +} + +/** + * @brief Get field altitude_amsl from high_latency message + * + * @return Altitude above mean sea level (meters) + */ +static inline int16_t mavlink_msg_high_latency_get_altitude_amsl(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 20); +} + +/** + * @brief Get field altitude_sp from high_latency message + * + * @return Altitude setpoint relative to the home position (meters) + */ +static inline int16_t mavlink_msg_high_latency_get_altitude_sp(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 22); +} + +/** + * @brief Get field airspeed from high_latency message + * + * @return airspeed (m/s) + */ +static inline uint8_t mavlink_msg_high_latency_get_airspeed(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 29); +} + +/** + * @brief Get field airspeed_sp from high_latency message + * + * @return airspeed setpoint (m/s) + */ +static inline uint8_t mavlink_msg_high_latency_get_airspeed_sp(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 30); +} + +/** + * @brief Get field groundspeed from high_latency message + * + * @return groundspeed (m/s) + */ +static inline uint8_t mavlink_msg_high_latency_get_groundspeed(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 31); +} + +/** + * @brief Get field climb_rate from high_latency message + * + * @return climb rate (m/s) + */ +static inline int8_t mavlink_msg_high_latency_get_climb_rate(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int8_t(msg, 32); +} + +/** + * @brief Get field gps_nsat from high_latency message + * + * @return Number of satellites visible. If unknown, set to 255 + */ +static inline uint8_t mavlink_msg_high_latency_get_gps_nsat(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 33); +} + +/** + * @brief Get field gps_fix_type from high_latency message + * + * @return See the GPS_FIX_TYPE enum. + */ +static inline uint8_t mavlink_msg_high_latency_get_gps_fix_type(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 34); +} + +/** + * @brief Get field battery_remaining from high_latency message + * + * @return Remaining battery (percentage) + */ +static inline uint8_t mavlink_msg_high_latency_get_battery_remaining(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 35); +} + +/** + * @brief Get field temperature from high_latency message + * + * @return Autopilot temperature (degrees C) + */ +static inline int8_t mavlink_msg_high_latency_get_temperature(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int8_t(msg, 36); +} + +/** + * @brief Get field temperature_air from high_latency message + * + * @return Air temperature (degrees C) from airspeed sensor + */ +static inline int8_t mavlink_msg_high_latency_get_temperature_air(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int8_t(msg, 37); +} + +/** + * @brief Get field failsafe from high_latency message + * + * @return failsafe (each bit represents a failsafe where 0=ok, 1=failsafe active (bit0:RC, bit1:batt, bit2:GPS, bit3:GCS, bit4:fence) + */ +static inline uint8_t mavlink_msg_high_latency_get_failsafe(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 38); +} + +/** + * @brief Get field wp_num from high_latency message + * + * @return current waypoint number + */ +static inline uint8_t mavlink_msg_high_latency_get_wp_num(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 39); +} + +/** + * @brief Get field wp_distance from high_latency message + * + * @return distance to target (meters) + */ +static inline uint16_t mavlink_msg_high_latency_get_wp_distance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 24); +} + +/** + * @brief Decode a high_latency message into a struct + * + * @param msg The message to decode + * @param high_latency C-struct to decode the message contents into + */ +static inline void mavlink_msg_high_latency_decode(const mavlink_message_t* msg, mavlink_high_latency_t* high_latency) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + high_latency->custom_mode = mavlink_msg_high_latency_get_custom_mode(msg); + high_latency->latitude = mavlink_msg_high_latency_get_latitude(msg); + high_latency->longitude = mavlink_msg_high_latency_get_longitude(msg); + high_latency->roll = mavlink_msg_high_latency_get_roll(msg); + high_latency->pitch = mavlink_msg_high_latency_get_pitch(msg); + high_latency->heading = mavlink_msg_high_latency_get_heading(msg); + high_latency->heading_sp = mavlink_msg_high_latency_get_heading_sp(msg); + high_latency->altitude_amsl = mavlink_msg_high_latency_get_altitude_amsl(msg); + high_latency->altitude_sp = mavlink_msg_high_latency_get_altitude_sp(msg); + high_latency->wp_distance = mavlink_msg_high_latency_get_wp_distance(msg); + high_latency->base_mode = mavlink_msg_high_latency_get_base_mode(msg); + high_latency->landed_state = mavlink_msg_high_latency_get_landed_state(msg); + high_latency->throttle = mavlink_msg_high_latency_get_throttle(msg); + high_latency->airspeed = mavlink_msg_high_latency_get_airspeed(msg); + high_latency->airspeed_sp = mavlink_msg_high_latency_get_airspeed_sp(msg); + high_latency->groundspeed = mavlink_msg_high_latency_get_groundspeed(msg); + high_latency->climb_rate = mavlink_msg_high_latency_get_climb_rate(msg); + high_latency->gps_nsat = mavlink_msg_high_latency_get_gps_nsat(msg); + high_latency->gps_fix_type = mavlink_msg_high_latency_get_gps_fix_type(msg); + high_latency->battery_remaining = mavlink_msg_high_latency_get_battery_remaining(msg); + high_latency->temperature = mavlink_msg_high_latency_get_temperature(msg); + high_latency->temperature_air = mavlink_msg_high_latency_get_temperature_air(msg); + high_latency->failsafe = mavlink_msg_high_latency_get_failsafe(msg); + high_latency->wp_num = mavlink_msg_high_latency_get_wp_num(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_HIGH_LATENCY_LEN? msg->len : MAVLINK_MSG_ID_HIGH_LATENCY_LEN; + memset(high_latency, 0, MAVLINK_MSG_ID_HIGH_LATENCY_LEN); + memcpy(high_latency, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_highres_imu.h b/vendor/libraries/mavlink/common/mavlink_msg_highres_imu.h index 2749cb097f..be7e5d33d2 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_highres_imu.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_highres_imu.h @@ -1,38 +1,43 @@ +#pragma once // MESSAGE HIGHRES_IMU PACKING #define MAVLINK_MSG_ID_HIGHRES_IMU 105 -typedef struct __mavlink_highres_imu_t -{ - uint64_t time_usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - float xacc; ///< X acceleration (m/s^2) - float yacc; ///< Y acceleration (m/s^2) - float zacc; ///< Z acceleration (m/s^2) - float xgyro; ///< Angular speed around X axis (rad / sec) - float ygyro; ///< Angular speed around Y axis (rad / sec) - float zgyro; ///< Angular speed around Z axis (rad / sec) - float xmag; ///< X Magnetic field (Gauss) - float ymag; ///< Y Magnetic field (Gauss) - float zmag; ///< Z Magnetic field (Gauss) - float abs_pressure; ///< Absolute pressure in millibar - float diff_pressure; ///< Differential pressure in millibar - float pressure_alt; ///< Altitude calculated from pressure - float temperature; ///< Temperature in degrees celsius - uint16_t fields_updated; ///< Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature -} mavlink_highres_imu_t; +MAVPACKED( +typedef struct __mavlink_highres_imu_t { + uint64_t time_usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + float xacc; /*< X acceleration (m/s^2)*/ + float yacc; /*< Y acceleration (m/s^2)*/ + float zacc; /*< Z acceleration (m/s^2)*/ + float xgyro; /*< Angular speed around X axis (rad / sec)*/ + float ygyro; /*< Angular speed around Y axis (rad / sec)*/ + float zgyro; /*< Angular speed around Z axis (rad / sec)*/ + float xmag; /*< X Magnetic field (Gauss)*/ + float ymag; /*< Y Magnetic field (Gauss)*/ + float zmag; /*< Z Magnetic field (Gauss)*/ + float abs_pressure; /*< Absolute pressure in millibar*/ + float diff_pressure; /*< Differential pressure in millibar*/ + float pressure_alt; /*< Altitude calculated from pressure*/ + float temperature; /*< Temperature in degrees celsius*/ + uint16_t fields_updated; /*< Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature*/ +}) mavlink_highres_imu_t; #define MAVLINK_MSG_ID_HIGHRES_IMU_LEN 62 +#define MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN 62 #define MAVLINK_MSG_ID_105_LEN 62 +#define MAVLINK_MSG_ID_105_MIN_LEN 62 #define MAVLINK_MSG_ID_HIGHRES_IMU_CRC 93 #define MAVLINK_MSG_ID_105_CRC 93 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIGHRES_IMU { \ - "HIGHRES_IMU", \ - 15, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_highres_imu_t, time_usec) }, \ + 105, \ + "HIGHRES_IMU", \ + 15, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_highres_imu_t, time_usec) }, \ { "xacc", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_highres_imu_t, xacc) }, \ { "yacc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_highres_imu_t, yacc) }, \ { "zacc", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_highres_imu_t, zacc) }, \ @@ -49,7 +54,28 @@ typedef struct __mavlink_highres_imu_t { "fields_updated", NULL, MAVLINK_TYPE_UINT16_T, 0, 60, offsetof(mavlink_highres_imu_t, fields_updated) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIGHRES_IMU { \ + "HIGHRES_IMU", \ + 15, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_highres_imu_t, time_usec) }, \ + { "xacc", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_highres_imu_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_highres_imu_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_highres_imu_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_highres_imu_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_highres_imu_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_highres_imu_t, zgyro) }, \ + { "xmag", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_highres_imu_t, xmag) }, \ + { "ymag", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_highres_imu_t, ymag) }, \ + { "zmag", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_highres_imu_t, zmag) }, \ + { "abs_pressure", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_highres_imu_t, abs_pressure) }, \ + { "diff_pressure", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_highres_imu_t, diff_pressure) }, \ + { "pressure_alt", NULL, MAVLINK_TYPE_FLOAT, 0, 52, offsetof(mavlink_highres_imu_t, pressure_alt) }, \ + { "temperature", NULL, MAVLINK_TYPE_FLOAT, 0, 56, offsetof(mavlink_highres_imu_t, temperature) }, \ + { "fields_updated", NULL, MAVLINK_TYPE_UINT16_T, 0, 60, offsetof(mavlink_highres_imu_t, fields_updated) }, \ + } \ +} +#endif /** * @brief Pack a highres_imu message @@ -75,54 +101,50 @@ typedef struct __mavlink_highres_imu_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_highres_imu_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint16_t fields_updated) + uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint16_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIGHRES_IMU_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint16_t(buf, 60, fields_updated); + char buf[MAVLINK_MSG_ID_HIGHRES_IMU_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint16_t(buf, 60, fields_updated); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); #else - mavlink_highres_imu_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - packet.abs_pressure = abs_pressure; - packet.diff_pressure = diff_pressure; - packet.pressure_alt = pressure_alt; - packet.temperature = temperature; - packet.fields_updated = fields_updated; + mavlink_highres_imu_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + packet.abs_pressure = abs_pressure; + packet.diff_pressure = diff_pressure; + packet.pressure_alt = pressure_alt; + packet.temperature = temperature; + packet.fields_updated = fields_updated; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIGHRES_IMU; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIGHRES_IMU; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); } /** @@ -149,55 +171,51 @@ static inline uint16_t mavlink_msg_highres_imu_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_highres_imu_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,float xmag,float ymag,float zmag,float abs_pressure,float diff_pressure,float pressure_alt,float temperature,uint16_t fields_updated) + mavlink_message_t* msg, + uint64_t time_usec,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,float xmag,float ymag,float zmag,float abs_pressure,float diff_pressure,float pressure_alt,float temperature,uint16_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIGHRES_IMU_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint16_t(buf, 60, fields_updated); + char buf[MAVLINK_MSG_ID_HIGHRES_IMU_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint16_t(buf, 60, fields_updated); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); #else - mavlink_highres_imu_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - packet.abs_pressure = abs_pressure; - packet.diff_pressure = diff_pressure; - packet.pressure_alt = pressure_alt; - packet.temperature = temperature; - packet.fields_updated = fields_updated; + mavlink_highres_imu_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + packet.abs_pressure = abs_pressure; + packet.diff_pressure = diff_pressure; + packet.pressure_alt = pressure_alt; + packet.temperature = temperature; + packet.fields_updated = fields_updated; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIGHRES_IMU; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIGHRES_IMU; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); } /** @@ -210,7 +228,7 @@ static inline uint16_t mavlink_msg_highres_imu_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_highres_imu_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_highres_imu_t* highres_imu) { - return mavlink_msg_highres_imu_pack(system_id, component_id, msg, highres_imu->time_usec, highres_imu->xacc, highres_imu->yacc, highres_imu->zacc, highres_imu->xgyro, highres_imu->ygyro, highres_imu->zgyro, highres_imu->xmag, highres_imu->ymag, highres_imu->zmag, highres_imu->abs_pressure, highres_imu->diff_pressure, highres_imu->pressure_alt, highres_imu->temperature, highres_imu->fields_updated); + return mavlink_msg_highres_imu_pack(system_id, component_id, msg, highres_imu->time_usec, highres_imu->xacc, highres_imu->yacc, highres_imu->zacc, highres_imu->xgyro, highres_imu->ygyro, highres_imu->zgyro, highres_imu->xmag, highres_imu->ymag, highres_imu->zmag, highres_imu->abs_pressure, highres_imu->diff_pressure, highres_imu->pressure_alt, highres_imu->temperature, highres_imu->fields_updated); } /** @@ -224,7 +242,7 @@ static inline uint16_t mavlink_msg_highres_imu_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_highres_imu_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_highres_imu_t* highres_imu) { - return mavlink_msg_highres_imu_pack_chan(system_id, component_id, chan, msg, highres_imu->time_usec, highres_imu->xacc, highres_imu->yacc, highres_imu->zacc, highres_imu->xgyro, highres_imu->ygyro, highres_imu->zgyro, highres_imu->xmag, highres_imu->ymag, highres_imu->zmag, highres_imu->abs_pressure, highres_imu->diff_pressure, highres_imu->pressure_alt, highres_imu->temperature, highres_imu->fields_updated); + return mavlink_msg_highres_imu_pack_chan(system_id, component_id, chan, msg, highres_imu->time_usec, highres_imu->xacc, highres_imu->yacc, highres_imu->zacc, highres_imu->xgyro, highres_imu->ygyro, highres_imu->zgyro, highres_imu->xmag, highres_imu->ymag, highres_imu->zmag, highres_imu->abs_pressure, highres_imu->diff_pressure, highres_imu->pressure_alt, highres_imu->temperature, highres_imu->fields_updated); } /** @@ -252,51 +270,57 @@ static inline uint16_t mavlink_msg_highres_imu_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_highres_imu_send(mavlink_channel_t chan, uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint16_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIGHRES_IMU_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint16_t(buf, 60, fields_updated); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, buf, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); + char buf[MAVLINK_MSG_ID_HIGHRES_IMU_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint16_t(buf, 60, fields_updated); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, buf, MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, buf, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); + mavlink_highres_imu_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + packet.abs_pressure = abs_pressure; + packet.diff_pressure = diff_pressure; + packet.pressure_alt = pressure_alt; + packet.temperature = temperature; + packet.fields_updated = fields_updated; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, (const char *)&packet, MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); #endif +} + +/** + * @brief Send a highres_imu message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_highres_imu_send_struct(mavlink_channel_t chan, const mavlink_highres_imu_t* highres_imu) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_highres_imu_send(chan, highres_imu->time_usec, highres_imu->xacc, highres_imu->yacc, highres_imu->zacc, highres_imu->xgyro, highres_imu->ygyro, highres_imu->zgyro, highres_imu->xmag, highres_imu->ymag, highres_imu->zmag, highres_imu->abs_pressure, highres_imu->diff_pressure, highres_imu->pressure_alt, highres_imu->temperature, highres_imu->fields_updated); #else - mavlink_highres_imu_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - packet.abs_pressure = abs_pressure; - packet.diff_pressure = diff_pressure; - packet.pressure_alt = pressure_alt; - packet.temperature = temperature; - packet.fields_updated = fields_updated; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, (const char *)&packet, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, (const char *)&packet, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, (const char *)highres_imu, MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); #endif } @@ -311,51 +335,43 @@ static inline void mavlink_msg_highres_imu_send(mavlink_channel_t chan, uint64_t static inline void mavlink_msg_highres_imu_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint16_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint16_t(buf, 60, fields_updated); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, buf, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint16_t(buf, 60, fields_updated); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, buf, MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, buf, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); -#endif -#else - mavlink_highres_imu_t *packet = (mavlink_highres_imu_t *)msgbuf; - packet->time_usec = time_usec; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - packet->xgyro = xgyro; - packet->ygyro = ygyro; - packet->zgyro = zgyro; - packet->xmag = xmag; - packet->ymag = ymag; - packet->zmag = zmag; - packet->abs_pressure = abs_pressure; - packet->diff_pressure = diff_pressure; - packet->pressure_alt = pressure_alt; - packet->temperature = temperature; - packet->fields_updated = fields_updated; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, (const char *)packet, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, (const char *)packet, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); -#endif + mavlink_highres_imu_t *packet = (mavlink_highres_imu_t *)msgbuf; + packet->time_usec = time_usec; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->xmag = xmag; + packet->ymag = ymag; + packet->zmag = zmag; + packet->abs_pressure = abs_pressure; + packet->diff_pressure = diff_pressure; + packet->pressure_alt = pressure_alt; + packet->temperature = temperature; + packet->fields_updated = fields_updated; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIGHRES_IMU, (const char *)packet, MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_LEN, MAVLINK_MSG_ID_HIGHRES_IMU_CRC); #endif } #endif @@ -372,7 +388,7 @@ static inline void mavlink_msg_highres_imu_send_buf(mavlink_message_t *msgbuf, m */ static inline uint64_t mavlink_msg_highres_imu_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -382,7 +398,7 @@ static inline uint64_t mavlink_msg_highres_imu_get_time_usec(const mavlink_messa */ static inline float mavlink_msg_highres_imu_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -392,7 +408,7 @@ static inline float mavlink_msg_highres_imu_get_xacc(const mavlink_message_t* ms */ static inline float mavlink_msg_highres_imu_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -402,7 +418,7 @@ static inline float mavlink_msg_highres_imu_get_yacc(const mavlink_message_t* ms */ static inline float mavlink_msg_highres_imu_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -412,7 +428,7 @@ static inline float mavlink_msg_highres_imu_get_zacc(const mavlink_message_t* ms */ static inline float mavlink_msg_highres_imu_get_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -422,7 +438,7 @@ static inline float mavlink_msg_highres_imu_get_xgyro(const mavlink_message_t* m */ static inline float mavlink_msg_highres_imu_get_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -432,7 +448,7 @@ static inline float mavlink_msg_highres_imu_get_ygyro(const mavlink_message_t* m */ static inline float mavlink_msg_highres_imu_get_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -442,7 +458,7 @@ static inline float mavlink_msg_highres_imu_get_zgyro(const mavlink_message_t* m */ static inline float mavlink_msg_highres_imu_get_xmag(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -452,7 +468,7 @@ static inline float mavlink_msg_highres_imu_get_xmag(const mavlink_message_t* ms */ static inline float mavlink_msg_highres_imu_get_ymag(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -462,7 +478,7 @@ static inline float mavlink_msg_highres_imu_get_ymag(const mavlink_message_t* ms */ static inline float mavlink_msg_highres_imu_get_zmag(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -472,7 +488,7 @@ static inline float mavlink_msg_highres_imu_get_zmag(const mavlink_message_t* ms */ static inline float mavlink_msg_highres_imu_get_abs_pressure(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -482,7 +498,7 @@ static inline float mavlink_msg_highres_imu_get_abs_pressure(const mavlink_messa */ static inline float mavlink_msg_highres_imu_get_diff_pressure(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 48); + return _MAV_RETURN_float(msg, 48); } /** @@ -492,7 +508,7 @@ static inline float mavlink_msg_highres_imu_get_diff_pressure(const mavlink_mess */ static inline float mavlink_msg_highres_imu_get_pressure_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 52); + return _MAV_RETURN_float(msg, 52); } /** @@ -502,7 +518,7 @@ static inline float mavlink_msg_highres_imu_get_pressure_alt(const mavlink_messa */ static inline float mavlink_msg_highres_imu_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 56); + return _MAV_RETURN_float(msg, 56); } /** @@ -512,7 +528,7 @@ static inline float mavlink_msg_highres_imu_get_temperature(const mavlink_messag */ static inline uint16_t mavlink_msg_highres_imu_get_fields_updated(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 60); + return _MAV_RETURN_uint16_t(msg, 60); } /** @@ -523,23 +539,25 @@ static inline uint16_t mavlink_msg_highres_imu_get_fields_updated(const mavlink_ */ static inline void mavlink_msg_highres_imu_decode(const mavlink_message_t* msg, mavlink_highres_imu_t* highres_imu) { -#if MAVLINK_NEED_BYTE_SWAP - highres_imu->time_usec = mavlink_msg_highres_imu_get_time_usec(msg); - highres_imu->xacc = mavlink_msg_highres_imu_get_xacc(msg); - highres_imu->yacc = mavlink_msg_highres_imu_get_yacc(msg); - highres_imu->zacc = mavlink_msg_highres_imu_get_zacc(msg); - highres_imu->xgyro = mavlink_msg_highres_imu_get_xgyro(msg); - highres_imu->ygyro = mavlink_msg_highres_imu_get_ygyro(msg); - highres_imu->zgyro = mavlink_msg_highres_imu_get_zgyro(msg); - highres_imu->xmag = mavlink_msg_highres_imu_get_xmag(msg); - highres_imu->ymag = mavlink_msg_highres_imu_get_ymag(msg); - highres_imu->zmag = mavlink_msg_highres_imu_get_zmag(msg); - highres_imu->abs_pressure = mavlink_msg_highres_imu_get_abs_pressure(msg); - highres_imu->diff_pressure = mavlink_msg_highres_imu_get_diff_pressure(msg); - highres_imu->pressure_alt = mavlink_msg_highres_imu_get_pressure_alt(msg); - highres_imu->temperature = mavlink_msg_highres_imu_get_temperature(msg); - highres_imu->fields_updated = mavlink_msg_highres_imu_get_fields_updated(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + highres_imu->time_usec = mavlink_msg_highres_imu_get_time_usec(msg); + highres_imu->xacc = mavlink_msg_highres_imu_get_xacc(msg); + highres_imu->yacc = mavlink_msg_highres_imu_get_yacc(msg); + highres_imu->zacc = mavlink_msg_highres_imu_get_zacc(msg); + highres_imu->xgyro = mavlink_msg_highres_imu_get_xgyro(msg); + highres_imu->ygyro = mavlink_msg_highres_imu_get_ygyro(msg); + highres_imu->zgyro = mavlink_msg_highres_imu_get_zgyro(msg); + highres_imu->xmag = mavlink_msg_highres_imu_get_xmag(msg); + highres_imu->ymag = mavlink_msg_highres_imu_get_ymag(msg); + highres_imu->zmag = mavlink_msg_highres_imu_get_zmag(msg); + highres_imu->abs_pressure = mavlink_msg_highres_imu_get_abs_pressure(msg); + highres_imu->diff_pressure = mavlink_msg_highres_imu_get_diff_pressure(msg); + highres_imu->pressure_alt = mavlink_msg_highres_imu_get_pressure_alt(msg); + highres_imu->temperature = mavlink_msg_highres_imu_get_temperature(msg); + highres_imu->fields_updated = mavlink_msg_highres_imu_get_fields_updated(msg); #else - memcpy(highres_imu, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIGHRES_IMU_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIGHRES_IMU_LEN? msg->len : MAVLINK_MSG_ID_HIGHRES_IMU_LEN; + memset(highres_imu, 0, MAVLINK_MSG_ID_HIGHRES_IMU_LEN); + memcpy(highres_imu, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_actuator_controls.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_actuator_controls.h new file mode 100644 index 0000000000..f60e920e5a --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_actuator_controls.h @@ -0,0 +1,280 @@ +#pragma once +// MESSAGE HIL_ACTUATOR_CONTROLS PACKING + +#define MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS 93 + +MAVPACKED( +typedef struct __mavlink_hil_actuator_controls_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + uint64_t flags; /*< Flags as bitfield, reserved for future use.*/ + float controls[16]; /*< Control outputs -1 .. 1. Channel assignment depends on the simulated hardware.*/ + uint8_t mode; /*< System mode (MAV_MODE), includes arming state.*/ +}) mavlink_hil_actuator_controls_t; + +#define MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN 81 +#define MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN 81 +#define MAVLINK_MSG_ID_93_LEN 81 +#define MAVLINK_MSG_ID_93_MIN_LEN 81 + +#define MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC 47 +#define MAVLINK_MSG_ID_93_CRC 47 + +#define MAVLINK_MSG_HIL_ACTUATOR_CONTROLS_FIELD_CONTROLS_LEN 16 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_HIL_ACTUATOR_CONTROLS { \ + 93, \ + "HIL_ACTUATOR_CONTROLS", \ + 4, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_actuator_controls_t, time_usec) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT64_T, 0, 8, offsetof(mavlink_hil_actuator_controls_t, flags) }, \ + { "controls", NULL, MAVLINK_TYPE_FLOAT, 16, 16, offsetof(mavlink_hil_actuator_controls_t, controls) }, \ + { "mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 80, offsetof(mavlink_hil_actuator_controls_t, mode) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_HIL_ACTUATOR_CONTROLS { \ + "HIL_ACTUATOR_CONTROLS", \ + 4, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_actuator_controls_t, time_usec) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT64_T, 0, 8, offsetof(mavlink_hil_actuator_controls_t, flags) }, \ + { "controls", NULL, MAVLINK_TYPE_FLOAT, 16, 16, offsetof(mavlink_hil_actuator_controls_t, controls) }, \ + { "mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 80, offsetof(mavlink_hil_actuator_controls_t, mode) }, \ + } \ +} +#endif + +/** + * @brief Pack a hil_actuator_controls message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) + * @param controls Control outputs -1 .. 1. Channel assignment depends on the simulated hardware. + * @param mode System mode (MAV_MODE), includes arming state. + * @param flags Flags as bitfield, reserved for future use. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_hil_actuator_controls_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, const float *controls, uint8_t mode, uint64_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint64_t(buf, 8, flags); + _mav_put_uint8_t(buf, 80, mode); + _mav_put_float_array(buf, 16, controls, 16); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN); +#else + mavlink_hil_actuator_controls_t packet; + packet.time_usec = time_usec; + packet.flags = flags; + packet.mode = mode; + mav_array_memcpy(packet.controls, controls, sizeof(float)*16); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC); +} + +/** + * @brief Pack a hil_actuator_controls message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) + * @param controls Control outputs -1 .. 1. Channel assignment depends on the simulated hardware. + * @param mode System mode (MAV_MODE), includes arming state. + * @param flags Flags as bitfield, reserved for future use. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_hil_actuator_controls_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,const float *controls,uint8_t mode,uint64_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint64_t(buf, 8, flags); + _mav_put_uint8_t(buf, 80, mode); + _mav_put_float_array(buf, 16, controls, 16); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN); +#else + mavlink_hil_actuator_controls_t packet; + packet.time_usec = time_usec; + packet.flags = flags; + packet.mode = mode; + mav_array_memcpy(packet.controls, controls, sizeof(float)*16); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC); +} + +/** + * @brief Encode a hil_actuator_controls struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param hil_actuator_controls C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_actuator_controls_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_actuator_controls_t* hil_actuator_controls) +{ + return mavlink_msg_hil_actuator_controls_pack(system_id, component_id, msg, hil_actuator_controls->time_usec, hil_actuator_controls->controls, hil_actuator_controls->mode, hil_actuator_controls->flags); +} + +/** + * @brief Encode a hil_actuator_controls struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param hil_actuator_controls C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_hil_actuator_controls_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_actuator_controls_t* hil_actuator_controls) +{ + return mavlink_msg_hil_actuator_controls_pack_chan(system_id, component_id, chan, msg, hil_actuator_controls->time_usec, hil_actuator_controls->controls, hil_actuator_controls->mode, hil_actuator_controls->flags); +} + +/** + * @brief Send a hil_actuator_controls message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) + * @param controls Control outputs -1 .. 1. Channel assignment depends on the simulated hardware. + * @param mode System mode (MAV_MODE), includes arming state. + * @param flags Flags as bitfield, reserved for future use. + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_hil_actuator_controls_send(mavlink_channel_t chan, uint64_t time_usec, const float *controls, uint8_t mode, uint64_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint64_t(buf, 8, flags); + _mav_put_uint8_t(buf, 80, mode); + _mav_put_float_array(buf, 16, controls, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS, buf, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC); +#else + mavlink_hil_actuator_controls_t packet; + packet.time_usec = time_usec; + packet.flags = flags; + packet.mode = mode; + mav_array_memcpy(packet.controls, controls, sizeof(float)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS, (const char *)&packet, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC); +#endif +} + +/** + * @brief Send a hil_actuator_controls message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_actuator_controls_send_struct(mavlink_channel_t chan, const mavlink_hil_actuator_controls_t* hil_actuator_controls) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_actuator_controls_send(chan, hil_actuator_controls->time_usec, hil_actuator_controls->controls, hil_actuator_controls->mode, hil_actuator_controls->flags); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS, (const char *)hil_actuator_controls, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC); +#endif +} + +#if MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_hil_actuator_controls_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, const float *controls, uint8_t mode, uint64_t flags) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint64_t(buf, 8, flags); + _mav_put_uint8_t(buf, 80, mode); + _mav_put_float_array(buf, 16, controls, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS, buf, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC); +#else + mavlink_hil_actuator_controls_t *packet = (mavlink_hil_actuator_controls_t *)msgbuf; + packet->time_usec = time_usec; + packet->flags = flags; + packet->mode = mode; + mav_array_memcpy(packet->controls, controls, sizeof(float)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS, (const char *)packet, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_CRC); +#endif +} +#endif + +#endif + +// MESSAGE HIL_ACTUATOR_CONTROLS UNPACKING + + +/** + * @brief Get field time_usec from hil_actuator_controls message + * + * @return Timestamp (microseconds since UNIX epoch or microseconds since system boot) + */ +static inline uint64_t mavlink_msg_hil_actuator_controls_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field controls from hil_actuator_controls message + * + * @return Control outputs -1 .. 1. Channel assignment depends on the simulated hardware. + */ +static inline uint16_t mavlink_msg_hil_actuator_controls_get_controls(const mavlink_message_t* msg, float *controls) +{ + return _MAV_RETURN_float_array(msg, controls, 16, 16); +} + +/** + * @brief Get field mode from hil_actuator_controls message + * + * @return System mode (MAV_MODE), includes arming state. + */ +static inline uint8_t mavlink_msg_hil_actuator_controls_get_mode(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 80); +} + +/** + * @brief Get field flags from hil_actuator_controls message + * + * @return Flags as bitfield, reserved for future use. + */ +static inline uint64_t mavlink_msg_hil_actuator_controls_get_flags(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 8); +} + +/** + * @brief Decode a hil_actuator_controls message into a struct + * + * @param msg The message to decode + * @param hil_actuator_controls C-struct to decode the message contents into + */ +static inline void mavlink_msg_hil_actuator_controls_decode(const mavlink_message_t* msg, mavlink_hil_actuator_controls_t* hil_actuator_controls) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_actuator_controls->time_usec = mavlink_msg_hil_actuator_controls_get_time_usec(msg); + hil_actuator_controls->flags = mavlink_msg_hil_actuator_controls_get_flags(msg); + mavlink_msg_hil_actuator_controls_get_controls(msg, hil_actuator_controls->controls); + hil_actuator_controls->mode = mavlink_msg_hil_actuator_controls_get_mode(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN? msg->len : MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN; + memset(hil_actuator_controls, 0, MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_LEN); + memcpy(hil_actuator_controls, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_controls.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_controls.h index f7507b1cf7..39dca7eec9 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_hil_controls.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_controls.h @@ -1,34 +1,39 @@ +#pragma once // MESSAGE HIL_CONTROLS PACKING #define MAVLINK_MSG_ID_HIL_CONTROLS 91 -typedef struct __mavlink_hil_controls_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - float roll_ailerons; ///< Control output -1 .. 1 - float pitch_elevator; ///< Control output -1 .. 1 - float yaw_rudder; ///< Control output -1 .. 1 - float throttle; ///< Throttle 0 .. 1 - float aux1; ///< Aux 1, -1 .. 1 - float aux2; ///< Aux 2, -1 .. 1 - float aux3; ///< Aux 3, -1 .. 1 - float aux4; ///< Aux 4, -1 .. 1 - uint8_t mode; ///< System mode (MAV_MODE) - uint8_t nav_mode; ///< Navigation mode (MAV_NAV_MODE) -} mavlink_hil_controls_t; +MAVPACKED( +typedef struct __mavlink_hil_controls_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + float roll_ailerons; /*< Control output -1 .. 1*/ + float pitch_elevator; /*< Control output -1 .. 1*/ + float yaw_rudder; /*< Control output -1 .. 1*/ + float throttle; /*< Throttle 0 .. 1*/ + float aux1; /*< Aux 1, -1 .. 1*/ + float aux2; /*< Aux 2, -1 .. 1*/ + float aux3; /*< Aux 3, -1 .. 1*/ + float aux4; /*< Aux 4, -1 .. 1*/ + uint8_t mode; /*< System mode (MAV_MODE)*/ + uint8_t nav_mode; /*< Navigation mode (MAV_NAV_MODE)*/ +}) mavlink_hil_controls_t; #define MAVLINK_MSG_ID_HIL_CONTROLS_LEN 42 +#define MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN 42 #define MAVLINK_MSG_ID_91_LEN 42 +#define MAVLINK_MSG_ID_91_MIN_LEN 42 #define MAVLINK_MSG_ID_HIL_CONTROLS_CRC 63 #define MAVLINK_MSG_ID_91_CRC 63 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIL_CONTROLS { \ - "HIL_CONTROLS", \ - 11, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_controls_t, time_usec) }, \ + 91, \ + "HIL_CONTROLS", \ + 11, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_controls_t, time_usec) }, \ { "roll_ailerons", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_hil_controls_t, roll_ailerons) }, \ { "pitch_elevator", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_controls_t, pitch_elevator) }, \ { "yaw_rudder", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_controls_t, yaw_rudder) }, \ @@ -41,7 +46,24 @@ typedef struct __mavlink_hil_controls_t { "nav_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_hil_controls_t, nav_mode) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIL_CONTROLS { \ + "HIL_CONTROLS", \ + 11, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_controls_t, time_usec) }, \ + { "roll_ailerons", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_hil_controls_t, roll_ailerons) }, \ + { "pitch_elevator", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_controls_t, pitch_elevator) }, \ + { "yaw_rudder", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_controls_t, yaw_rudder) }, \ + { "throttle", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_hil_controls_t, throttle) }, \ + { "aux1", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_hil_controls_t, aux1) }, \ + { "aux2", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_hil_controls_t, aux2) }, \ + { "aux3", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_hil_controls_t, aux3) }, \ + { "aux4", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_hil_controls_t, aux4) }, \ + { "mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_hil_controls_t, mode) }, \ + { "nav_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_hil_controls_t, nav_mode) }, \ + } \ +} +#endif /** * @brief Pack a hil_controls message @@ -63,46 +85,42 @@ typedef struct __mavlink_hil_controls_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_controls_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, float roll_ailerons, float pitch_elevator, float yaw_rudder, float throttle, float aux1, float aux2, float aux3, float aux4, uint8_t mode, uint8_t nav_mode) + uint64_t time_usec, float roll_ailerons, float pitch_elevator, float yaw_rudder, float throttle, float aux1, float aux2, float aux3, float aux4, uint8_t mode, uint8_t nav_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_CONTROLS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll_ailerons); - _mav_put_float(buf, 12, pitch_elevator); - _mav_put_float(buf, 16, yaw_rudder); - _mav_put_float(buf, 20, throttle); - _mav_put_float(buf, 24, aux1); - _mav_put_float(buf, 28, aux2); - _mav_put_float(buf, 32, aux3); - _mav_put_float(buf, 36, aux4); - _mav_put_uint8_t(buf, 40, mode); - _mav_put_uint8_t(buf, 41, nav_mode); + char buf[MAVLINK_MSG_ID_HIL_CONTROLS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll_ailerons); + _mav_put_float(buf, 12, pitch_elevator); + _mav_put_float(buf, 16, yaw_rudder); + _mav_put_float(buf, 20, throttle); + _mav_put_float(buf, 24, aux1); + _mav_put_float(buf, 28, aux2); + _mav_put_float(buf, 32, aux3); + _mav_put_float(buf, 36, aux4); + _mav_put_uint8_t(buf, 40, mode); + _mav_put_uint8_t(buf, 41, nav_mode); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); #else - mavlink_hil_controls_t packet; - packet.time_usec = time_usec; - packet.roll_ailerons = roll_ailerons; - packet.pitch_elevator = pitch_elevator; - packet.yaw_rudder = yaw_rudder; - packet.throttle = throttle; - packet.aux1 = aux1; - packet.aux2 = aux2; - packet.aux3 = aux3; - packet.aux4 = aux4; - packet.mode = mode; - packet.nav_mode = nav_mode; + mavlink_hil_controls_t packet; + packet.time_usec = time_usec; + packet.roll_ailerons = roll_ailerons; + packet.pitch_elevator = pitch_elevator; + packet.yaw_rudder = yaw_rudder; + packet.throttle = throttle; + packet.aux1 = aux1; + packet.aux2 = aux2; + packet.aux3 = aux3; + packet.aux4 = aux4; + packet.mode = mode; + packet.nav_mode = nav_mode; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_CONTROLS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_CONTROLS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); } /** @@ -125,47 +143,43 @@ static inline uint16_t mavlink_msg_hil_controls_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_controls_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,float roll_ailerons,float pitch_elevator,float yaw_rudder,float throttle,float aux1,float aux2,float aux3,float aux4,uint8_t mode,uint8_t nav_mode) + mavlink_message_t* msg, + uint64_t time_usec,float roll_ailerons,float pitch_elevator,float yaw_rudder,float throttle,float aux1,float aux2,float aux3,float aux4,uint8_t mode,uint8_t nav_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_CONTROLS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll_ailerons); - _mav_put_float(buf, 12, pitch_elevator); - _mav_put_float(buf, 16, yaw_rudder); - _mav_put_float(buf, 20, throttle); - _mav_put_float(buf, 24, aux1); - _mav_put_float(buf, 28, aux2); - _mav_put_float(buf, 32, aux3); - _mav_put_float(buf, 36, aux4); - _mav_put_uint8_t(buf, 40, mode); - _mav_put_uint8_t(buf, 41, nav_mode); + char buf[MAVLINK_MSG_ID_HIL_CONTROLS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll_ailerons); + _mav_put_float(buf, 12, pitch_elevator); + _mav_put_float(buf, 16, yaw_rudder); + _mav_put_float(buf, 20, throttle); + _mav_put_float(buf, 24, aux1); + _mav_put_float(buf, 28, aux2); + _mav_put_float(buf, 32, aux3); + _mav_put_float(buf, 36, aux4); + _mav_put_uint8_t(buf, 40, mode); + _mav_put_uint8_t(buf, 41, nav_mode); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); #else - mavlink_hil_controls_t packet; - packet.time_usec = time_usec; - packet.roll_ailerons = roll_ailerons; - packet.pitch_elevator = pitch_elevator; - packet.yaw_rudder = yaw_rudder; - packet.throttle = throttle; - packet.aux1 = aux1; - packet.aux2 = aux2; - packet.aux3 = aux3; - packet.aux4 = aux4; - packet.mode = mode; - packet.nav_mode = nav_mode; + mavlink_hil_controls_t packet; + packet.time_usec = time_usec; + packet.roll_ailerons = roll_ailerons; + packet.pitch_elevator = pitch_elevator; + packet.yaw_rudder = yaw_rudder; + packet.throttle = throttle; + packet.aux1 = aux1; + packet.aux2 = aux2; + packet.aux3 = aux3; + packet.aux4 = aux4; + packet.mode = mode; + packet.nav_mode = nav_mode; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_CONTROLS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_CONTROLS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); } /** @@ -178,7 +192,7 @@ static inline uint16_t mavlink_msg_hil_controls_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_hil_controls_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_controls_t* hil_controls) { - return mavlink_msg_hil_controls_pack(system_id, component_id, msg, hil_controls->time_usec, hil_controls->roll_ailerons, hil_controls->pitch_elevator, hil_controls->yaw_rudder, hil_controls->throttle, hil_controls->aux1, hil_controls->aux2, hil_controls->aux3, hil_controls->aux4, hil_controls->mode, hil_controls->nav_mode); + return mavlink_msg_hil_controls_pack(system_id, component_id, msg, hil_controls->time_usec, hil_controls->roll_ailerons, hil_controls->pitch_elevator, hil_controls->yaw_rudder, hil_controls->throttle, hil_controls->aux1, hil_controls->aux2, hil_controls->aux3, hil_controls->aux4, hil_controls->mode, hil_controls->nav_mode); } /** @@ -192,7 +206,7 @@ static inline uint16_t mavlink_msg_hil_controls_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_hil_controls_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_controls_t* hil_controls) { - return mavlink_msg_hil_controls_pack_chan(system_id, component_id, chan, msg, hil_controls->time_usec, hil_controls->roll_ailerons, hil_controls->pitch_elevator, hil_controls->yaw_rudder, hil_controls->throttle, hil_controls->aux1, hil_controls->aux2, hil_controls->aux3, hil_controls->aux4, hil_controls->mode, hil_controls->nav_mode); + return mavlink_msg_hil_controls_pack_chan(system_id, component_id, chan, msg, hil_controls->time_usec, hil_controls->roll_ailerons, hil_controls->pitch_elevator, hil_controls->yaw_rudder, hil_controls->throttle, hil_controls->aux1, hil_controls->aux2, hil_controls->aux3, hil_controls->aux4, hil_controls->mode, hil_controls->nav_mode); } /** @@ -216,43 +230,49 @@ static inline uint16_t mavlink_msg_hil_controls_encode_chan(uint8_t system_id, u static inline void mavlink_msg_hil_controls_send(mavlink_channel_t chan, uint64_t time_usec, float roll_ailerons, float pitch_elevator, float yaw_rudder, float throttle, float aux1, float aux2, float aux3, float aux4, uint8_t mode, uint8_t nav_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_CONTROLS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll_ailerons); - _mav_put_float(buf, 12, pitch_elevator); - _mav_put_float(buf, 16, yaw_rudder); - _mav_put_float(buf, 20, throttle); - _mav_put_float(buf, 24, aux1); - _mav_put_float(buf, 28, aux2); - _mav_put_float(buf, 32, aux3); - _mav_put_float(buf, 36, aux4); - _mav_put_uint8_t(buf, 40, mode); - _mav_put_uint8_t(buf, 41, nav_mode); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, buf, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); + char buf[MAVLINK_MSG_ID_HIL_CONTROLS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll_ailerons); + _mav_put_float(buf, 12, pitch_elevator); + _mav_put_float(buf, 16, yaw_rudder); + _mav_put_float(buf, 20, throttle); + _mav_put_float(buf, 24, aux1); + _mav_put_float(buf, 28, aux2); + _mav_put_float(buf, 32, aux3); + _mav_put_float(buf, 36, aux4); + _mav_put_uint8_t(buf, 40, mode); + _mav_put_uint8_t(buf, 41, nav_mode); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, buf, MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, buf, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); + mavlink_hil_controls_t packet; + packet.time_usec = time_usec; + packet.roll_ailerons = roll_ailerons; + packet.pitch_elevator = pitch_elevator; + packet.yaw_rudder = yaw_rudder; + packet.throttle = throttle; + packet.aux1 = aux1; + packet.aux2 = aux2; + packet.aux3 = aux3; + packet.aux4 = aux4; + packet.mode = mode; + packet.nav_mode = nav_mode; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, (const char *)&packet, MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); #endif +} + +/** + * @brief Send a hil_controls message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_controls_send_struct(mavlink_channel_t chan, const mavlink_hil_controls_t* hil_controls) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_controls_send(chan, hil_controls->time_usec, hil_controls->roll_ailerons, hil_controls->pitch_elevator, hil_controls->yaw_rudder, hil_controls->throttle, hil_controls->aux1, hil_controls->aux2, hil_controls->aux3, hil_controls->aux4, hil_controls->mode, hil_controls->nav_mode); #else - mavlink_hil_controls_t packet; - packet.time_usec = time_usec; - packet.roll_ailerons = roll_ailerons; - packet.pitch_elevator = pitch_elevator; - packet.yaw_rudder = yaw_rudder; - packet.throttle = throttle; - packet.aux1 = aux1; - packet.aux2 = aux2; - packet.aux3 = aux3; - packet.aux4 = aux4; - packet.mode = mode; - packet.nav_mode = nav_mode; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, (const char *)&packet, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, (const char *)&packet, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, (const char *)hil_controls, MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); #endif } @@ -267,43 +287,35 @@ static inline void mavlink_msg_hil_controls_send(mavlink_channel_t chan, uint64_ static inline void mavlink_msg_hil_controls_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float roll_ailerons, float pitch_elevator, float yaw_rudder, float throttle, float aux1, float aux2, float aux3, float aux4, uint8_t mode, uint8_t nav_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll_ailerons); - _mav_put_float(buf, 12, pitch_elevator); - _mav_put_float(buf, 16, yaw_rudder); - _mav_put_float(buf, 20, throttle); - _mav_put_float(buf, 24, aux1); - _mav_put_float(buf, 28, aux2); - _mav_put_float(buf, 32, aux3); - _mav_put_float(buf, 36, aux4); - _mav_put_uint8_t(buf, 40, mode); - _mav_put_uint8_t(buf, 41, nav_mode); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, buf, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll_ailerons); + _mav_put_float(buf, 12, pitch_elevator); + _mav_put_float(buf, 16, yaw_rudder); + _mav_put_float(buf, 20, throttle); + _mav_put_float(buf, 24, aux1); + _mav_put_float(buf, 28, aux2); + _mav_put_float(buf, 32, aux3); + _mav_put_float(buf, 36, aux4); + _mav_put_uint8_t(buf, 40, mode); + _mav_put_uint8_t(buf, 41, nav_mode); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, buf, MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, buf, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); -#endif -#else - mavlink_hil_controls_t *packet = (mavlink_hil_controls_t *)msgbuf; - packet->time_usec = time_usec; - packet->roll_ailerons = roll_ailerons; - packet->pitch_elevator = pitch_elevator; - packet->yaw_rudder = yaw_rudder; - packet->throttle = throttle; - packet->aux1 = aux1; - packet->aux2 = aux2; - packet->aux3 = aux3; - packet->aux4 = aux4; - packet->mode = mode; - packet->nav_mode = nav_mode; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, (const char *)packet, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, (const char *)packet, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); -#endif + mavlink_hil_controls_t *packet = (mavlink_hil_controls_t *)msgbuf; + packet->time_usec = time_usec; + packet->roll_ailerons = roll_ailerons; + packet->pitch_elevator = pitch_elevator; + packet->yaw_rudder = yaw_rudder; + packet->throttle = throttle; + packet->aux1 = aux1; + packet->aux2 = aux2; + packet->aux3 = aux3; + packet->aux4 = aux4; + packet->mode = mode; + packet->nav_mode = nav_mode; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_CONTROLS, (const char *)packet, MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_LEN, MAVLINK_MSG_ID_HIL_CONTROLS_CRC); #endif } #endif @@ -320,7 +332,7 @@ static inline void mavlink_msg_hil_controls_send_buf(mavlink_message_t *msgbuf, */ static inline uint64_t mavlink_msg_hil_controls_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -330,7 +342,7 @@ static inline uint64_t mavlink_msg_hil_controls_get_time_usec(const mavlink_mess */ static inline float mavlink_msg_hil_controls_get_roll_ailerons(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -340,7 +352,7 @@ static inline float mavlink_msg_hil_controls_get_roll_ailerons(const mavlink_mes */ static inline float mavlink_msg_hil_controls_get_pitch_elevator(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -350,7 +362,7 @@ static inline float mavlink_msg_hil_controls_get_pitch_elevator(const mavlink_me */ static inline float mavlink_msg_hil_controls_get_yaw_rudder(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -360,7 +372,7 @@ static inline float mavlink_msg_hil_controls_get_yaw_rudder(const mavlink_messag */ static inline float mavlink_msg_hil_controls_get_throttle(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -370,7 +382,7 @@ static inline float mavlink_msg_hil_controls_get_throttle(const mavlink_message_ */ static inline float mavlink_msg_hil_controls_get_aux1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -380,7 +392,7 @@ static inline float mavlink_msg_hil_controls_get_aux1(const mavlink_message_t* m */ static inline float mavlink_msg_hil_controls_get_aux2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -390,7 +402,7 @@ static inline float mavlink_msg_hil_controls_get_aux2(const mavlink_message_t* m */ static inline float mavlink_msg_hil_controls_get_aux3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -400,7 +412,7 @@ static inline float mavlink_msg_hil_controls_get_aux3(const mavlink_message_t* m */ static inline float mavlink_msg_hil_controls_get_aux4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -410,7 +422,7 @@ static inline float mavlink_msg_hil_controls_get_aux4(const mavlink_message_t* m */ static inline uint8_t mavlink_msg_hil_controls_get_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 40); + return _MAV_RETURN_uint8_t(msg, 40); } /** @@ -420,7 +432,7 @@ static inline uint8_t mavlink_msg_hil_controls_get_mode(const mavlink_message_t* */ static inline uint8_t mavlink_msg_hil_controls_get_nav_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 41); + return _MAV_RETURN_uint8_t(msg, 41); } /** @@ -431,19 +443,21 @@ static inline uint8_t mavlink_msg_hil_controls_get_nav_mode(const mavlink_messag */ static inline void mavlink_msg_hil_controls_decode(const mavlink_message_t* msg, mavlink_hil_controls_t* hil_controls) { -#if MAVLINK_NEED_BYTE_SWAP - hil_controls->time_usec = mavlink_msg_hil_controls_get_time_usec(msg); - hil_controls->roll_ailerons = mavlink_msg_hil_controls_get_roll_ailerons(msg); - hil_controls->pitch_elevator = mavlink_msg_hil_controls_get_pitch_elevator(msg); - hil_controls->yaw_rudder = mavlink_msg_hil_controls_get_yaw_rudder(msg); - hil_controls->throttle = mavlink_msg_hil_controls_get_throttle(msg); - hil_controls->aux1 = mavlink_msg_hil_controls_get_aux1(msg); - hil_controls->aux2 = mavlink_msg_hil_controls_get_aux2(msg); - hil_controls->aux3 = mavlink_msg_hil_controls_get_aux3(msg); - hil_controls->aux4 = mavlink_msg_hil_controls_get_aux4(msg); - hil_controls->mode = mavlink_msg_hil_controls_get_mode(msg); - hil_controls->nav_mode = mavlink_msg_hil_controls_get_nav_mode(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_controls->time_usec = mavlink_msg_hil_controls_get_time_usec(msg); + hil_controls->roll_ailerons = mavlink_msg_hil_controls_get_roll_ailerons(msg); + hil_controls->pitch_elevator = mavlink_msg_hil_controls_get_pitch_elevator(msg); + hil_controls->yaw_rudder = mavlink_msg_hil_controls_get_yaw_rudder(msg); + hil_controls->throttle = mavlink_msg_hil_controls_get_throttle(msg); + hil_controls->aux1 = mavlink_msg_hil_controls_get_aux1(msg); + hil_controls->aux2 = mavlink_msg_hil_controls_get_aux2(msg); + hil_controls->aux3 = mavlink_msg_hil_controls_get_aux3(msg); + hil_controls->aux4 = mavlink_msg_hil_controls_get_aux4(msg); + hil_controls->mode = mavlink_msg_hil_controls_get_mode(msg); + hil_controls->nav_mode = mavlink_msg_hil_controls_get_nav_mode(msg); #else - memcpy(hil_controls, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIL_CONTROLS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_CONTROLS_LEN? msg->len : MAVLINK_MSG_ID_HIL_CONTROLS_LEN; + memset(hil_controls, 0, MAVLINK_MSG_ID_HIL_CONTROLS_LEN); + memcpy(hil_controls, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_gps.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_gps.h index c140a70ebf..393006fcef 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_hil_gps.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_gps.h @@ -1,36 +1,41 @@ +#pragma once // MESSAGE HIL_GPS PACKING #define MAVLINK_MSG_ID_HIL_GPS 113 -typedef struct __mavlink_hil_gps_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - int32_t lat; ///< Latitude (WGS84), in degrees * 1E7 - int32_t lon; ///< Longitude (WGS84), in degrees * 1E7 - int32_t alt; ///< Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) - uint16_t eph; ///< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 - uint16_t epv; ///< GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: 65535 - uint16_t vel; ///< GPS ground speed (m/s * 100). If unknown, set to: 65535 - int16_t vn; ///< GPS velocity in cm/s in NORTH direction in earth-fixed NED frame - int16_t ve; ///< GPS velocity in cm/s in EAST direction in earth-fixed NED frame - int16_t vd; ///< GPS velocity in cm/s in DOWN direction in earth-fixed NED frame - uint16_t cog; ///< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535 - uint8_t fix_type; ///< 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix. - uint8_t satellites_visible; ///< Number of satellites visible. If unknown, set to 255 -} mavlink_hil_gps_t; +MAVPACKED( +typedef struct __mavlink_hil_gps_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + int32_t lat; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t lon; /*< Longitude (WGS84), in degrees * 1E7*/ + int32_t alt; /*< Altitude (AMSL, not WGS84), in meters * 1000 (positive for up)*/ + uint16_t eph; /*< GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535*/ + uint16_t epv; /*< GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: 65535*/ + uint16_t vel; /*< GPS ground speed in cm/s. If unknown, set to: 65535*/ + int16_t vn; /*< GPS velocity in cm/s in NORTH direction in earth-fixed NED frame*/ + int16_t ve; /*< GPS velocity in cm/s in EAST direction in earth-fixed NED frame*/ + int16_t vd; /*< GPS velocity in cm/s in DOWN direction in earth-fixed NED frame*/ + uint16_t cog; /*< Course over ground (NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. If unknown, set to: 65535*/ + uint8_t fix_type; /*< 0-1: no fix, 2: 2D fix, 3: 3D fix. Some applications will not use the value of this field unless it is at least two, so always correctly fill in the fix.*/ + uint8_t satellites_visible; /*< Number of satellites visible. If unknown, set to 255*/ +}) mavlink_hil_gps_t; #define MAVLINK_MSG_ID_HIL_GPS_LEN 36 +#define MAVLINK_MSG_ID_HIL_GPS_MIN_LEN 36 #define MAVLINK_MSG_ID_113_LEN 36 +#define MAVLINK_MSG_ID_113_MIN_LEN 36 #define MAVLINK_MSG_ID_HIL_GPS_CRC 124 #define MAVLINK_MSG_ID_113_CRC 124 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIL_GPS { \ - "HIL_GPS", \ - 13, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_gps_t, time_usec) }, \ + 113, \ + "HIL_GPS", \ + 13, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_gps_t, time_usec) }, \ { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_hil_gps_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_hil_gps_t, lon) }, \ { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_hil_gps_t, alt) }, \ @@ -45,7 +50,26 @@ typedef struct __mavlink_hil_gps_t { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 35, offsetof(mavlink_hil_gps_t, satellites_visible) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIL_GPS { \ + "HIL_GPS", \ + 13, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_gps_t, time_usec) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_hil_gps_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_hil_gps_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_hil_gps_t, alt) }, \ + { "eph", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_hil_gps_t, eph) }, \ + { "epv", NULL, MAVLINK_TYPE_UINT16_T, 0, 22, offsetof(mavlink_hil_gps_t, epv) }, \ + { "vel", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_hil_gps_t, vel) }, \ + { "vn", NULL, MAVLINK_TYPE_INT16_T, 0, 26, offsetof(mavlink_hil_gps_t, vn) }, \ + { "ve", NULL, MAVLINK_TYPE_INT16_T, 0, 28, offsetof(mavlink_hil_gps_t, ve) }, \ + { "vd", NULL, MAVLINK_TYPE_INT16_T, 0, 30, offsetof(mavlink_hil_gps_t, vd) }, \ + { "cog", NULL, MAVLINK_TYPE_UINT16_T, 0, 32, offsetof(mavlink_hil_gps_t, cog) }, \ + { "fix_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_hil_gps_t, fix_type) }, \ + { "satellites_visible", NULL, MAVLINK_TYPE_UINT8_T, 0, 35, offsetof(mavlink_hil_gps_t, satellites_visible) }, \ + } \ +} +#endif /** * @brief Pack a hil_gps message @@ -60,7 +84,7 @@ typedef struct __mavlink_hil_gps_t * @param alt Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 * @param epv GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: 65535 - * @param vel GPS ground speed (m/s * 100). If unknown, set to: 65535 + * @param vel GPS ground speed in cm/s. If unknown, set to: 65535 * @param vn GPS velocity in cm/s in NORTH direction in earth-fixed NED frame * @param ve GPS velocity in cm/s in EAST direction in earth-fixed NED frame * @param vd GPS velocity in cm/s in DOWN direction in earth-fixed NED frame @@ -69,50 +93,46 @@ typedef struct __mavlink_hil_gps_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_gps_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, int16_t vn, int16_t ve, int16_t vd, uint16_t cog, uint8_t satellites_visible) + uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, int16_t vn, int16_t ve, int16_t vd, uint16_t cog, uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_GPS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_int16_t(buf, 26, vn); - _mav_put_int16_t(buf, 28, ve); - _mav_put_int16_t(buf, 30, vd); - _mav_put_uint16_t(buf, 32, cog); - _mav_put_uint8_t(buf, 34, fix_type); - _mav_put_uint8_t(buf, 35, satellites_visible); + char buf[MAVLINK_MSG_ID_HIL_GPS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_int16_t(buf, 26, vn); + _mav_put_int16_t(buf, 28, ve); + _mav_put_int16_t(buf, 30, vd); + _mav_put_uint16_t(buf, 32, cog); + _mav_put_uint8_t(buf, 34, fix_type); + _mav_put_uint8_t(buf, 35, satellites_visible); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_GPS_LEN); #else - mavlink_hil_gps_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.vn = vn; - packet.ve = ve; - packet.vd = vd; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; + mavlink_hil_gps_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_GPS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_GPS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_GPS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_GPS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_GPS_MIN_LEN, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); } /** @@ -128,7 +148,7 @@ static inline uint16_t mavlink_msg_hil_gps_pack(uint8_t system_id, uint8_t compo * @param alt Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 * @param epv GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: 65535 - * @param vel GPS ground speed (m/s * 100). If unknown, set to: 65535 + * @param vel GPS ground speed in cm/s. If unknown, set to: 65535 * @param vn GPS velocity in cm/s in NORTH direction in earth-fixed NED frame * @param ve GPS velocity in cm/s in EAST direction in earth-fixed NED frame * @param vd GPS velocity in cm/s in DOWN direction in earth-fixed NED frame @@ -137,51 +157,47 @@ static inline uint16_t mavlink_msg_hil_gps_pack(uint8_t system_id, uint8_t compo * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_gps_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t fix_type,int32_t lat,int32_t lon,int32_t alt,uint16_t eph,uint16_t epv,uint16_t vel,int16_t vn,int16_t ve,int16_t vd,uint16_t cog,uint8_t satellites_visible) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t fix_type,int32_t lat,int32_t lon,int32_t alt,uint16_t eph,uint16_t epv,uint16_t vel,int16_t vn,int16_t ve,int16_t vd,uint16_t cog,uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_GPS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_int16_t(buf, 26, vn); - _mav_put_int16_t(buf, 28, ve); - _mav_put_int16_t(buf, 30, vd); - _mav_put_uint16_t(buf, 32, cog); - _mav_put_uint8_t(buf, 34, fix_type); - _mav_put_uint8_t(buf, 35, satellites_visible); + char buf[MAVLINK_MSG_ID_HIL_GPS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_int16_t(buf, 26, vn); + _mav_put_int16_t(buf, 28, ve); + _mav_put_int16_t(buf, 30, vd); + _mav_put_uint16_t(buf, 32, cog); + _mav_put_uint8_t(buf, 34, fix_type); + _mav_put_uint8_t(buf, 35, satellites_visible); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_GPS_LEN); #else - mavlink_hil_gps_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.vn = vn; - packet.ve = ve; - packet.vd = vd; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; + mavlink_hil_gps_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_GPS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_GPS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_GPS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_GPS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_GPS_MIN_LEN, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); } /** @@ -194,7 +210,7 @@ static inline uint16_t mavlink_msg_hil_gps_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_hil_gps_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_gps_t* hil_gps) { - return mavlink_msg_hil_gps_pack(system_id, component_id, msg, hil_gps->time_usec, hil_gps->fix_type, hil_gps->lat, hil_gps->lon, hil_gps->alt, hil_gps->eph, hil_gps->epv, hil_gps->vel, hil_gps->vn, hil_gps->ve, hil_gps->vd, hil_gps->cog, hil_gps->satellites_visible); + return mavlink_msg_hil_gps_pack(system_id, component_id, msg, hil_gps->time_usec, hil_gps->fix_type, hil_gps->lat, hil_gps->lon, hil_gps->alt, hil_gps->eph, hil_gps->epv, hil_gps->vel, hil_gps->vn, hil_gps->ve, hil_gps->vd, hil_gps->cog, hil_gps->satellites_visible); } /** @@ -208,7 +224,7 @@ static inline uint16_t mavlink_msg_hil_gps_encode(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_hil_gps_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_gps_t* hil_gps) { - return mavlink_msg_hil_gps_pack_chan(system_id, component_id, chan, msg, hil_gps->time_usec, hil_gps->fix_type, hil_gps->lat, hil_gps->lon, hil_gps->alt, hil_gps->eph, hil_gps->epv, hil_gps->vel, hil_gps->vn, hil_gps->ve, hil_gps->vd, hil_gps->cog, hil_gps->satellites_visible); + return mavlink_msg_hil_gps_pack_chan(system_id, component_id, chan, msg, hil_gps->time_usec, hil_gps->fix_type, hil_gps->lat, hil_gps->lon, hil_gps->alt, hil_gps->eph, hil_gps->epv, hil_gps->vel, hil_gps->vn, hil_gps->ve, hil_gps->vd, hil_gps->cog, hil_gps->satellites_visible); } /** @@ -222,7 +238,7 @@ static inline uint16_t mavlink_msg_hil_gps_encode_chan(uint8_t system_id, uint8_ * @param alt Altitude (AMSL, not WGS84), in meters * 1000 (positive for up) * @param eph GPS HDOP horizontal dilution of position in cm (m*100). If unknown, set to: 65535 * @param epv GPS VDOP vertical dilution of position in cm (m*100). If unknown, set to: 65535 - * @param vel GPS ground speed (m/s * 100). If unknown, set to: 65535 + * @param vel GPS ground speed in cm/s. If unknown, set to: 65535 * @param vn GPS velocity in cm/s in NORTH direction in earth-fixed NED frame * @param ve GPS velocity in cm/s in EAST direction in earth-fixed NED frame * @param vd GPS velocity in cm/s in DOWN direction in earth-fixed NED frame @@ -234,47 +250,53 @@ static inline uint16_t mavlink_msg_hil_gps_encode_chan(uint8_t system_id, uint8_ static inline void mavlink_msg_hil_gps_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, int16_t vn, int16_t ve, int16_t vd, uint16_t cog, uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_GPS_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_int16_t(buf, 26, vn); - _mav_put_int16_t(buf, 28, ve); - _mav_put_int16_t(buf, 30, vd); - _mav_put_uint16_t(buf, 32, cog); - _mav_put_uint8_t(buf, 34, fix_type); - _mav_put_uint8_t(buf, 35, satellites_visible); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, buf, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); + char buf[MAVLINK_MSG_ID_HIL_GPS_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_int16_t(buf, 26, vn); + _mav_put_int16_t(buf, 28, ve); + _mav_put_int16_t(buf, 30, vd); + _mav_put_uint16_t(buf, 32, cog); + _mav_put_uint8_t(buf, 34, fix_type); + _mav_put_uint8_t(buf, 35, satellites_visible); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, buf, MAVLINK_MSG_ID_HIL_GPS_MIN_LEN, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, buf, MAVLINK_MSG_ID_HIL_GPS_LEN); + mavlink_hil_gps_t packet; + packet.time_usec = time_usec; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.eph = eph; + packet.epv = epv; + packet.vel = vel; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; + packet.cog = cog; + packet.fix_type = fix_type; + packet.satellites_visible = satellites_visible; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, (const char *)&packet, MAVLINK_MSG_ID_HIL_GPS_MIN_LEN, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); #endif +} + +/** + * @brief Send a hil_gps message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_gps_send_struct(mavlink_channel_t chan, const mavlink_hil_gps_t* hil_gps) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_gps_send(chan, hil_gps->time_usec, hil_gps->fix_type, hil_gps->lat, hil_gps->lon, hil_gps->alt, hil_gps->eph, hil_gps->epv, hil_gps->vel, hil_gps->vn, hil_gps->ve, hil_gps->vd, hil_gps->cog, hil_gps->satellites_visible); #else - mavlink_hil_gps_t packet; - packet.time_usec = time_usec; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.eph = eph; - packet.epv = epv; - packet.vel = vel; - packet.vn = vn; - packet.ve = ve; - packet.vd = vd; - packet.cog = cog; - packet.fix_type = fix_type; - packet.satellites_visible = satellites_visible; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, (const char *)&packet, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, (const char *)&packet, MAVLINK_MSG_ID_HIL_GPS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, (const char *)hil_gps, MAVLINK_MSG_ID_HIL_GPS_MIN_LEN, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); #endif } @@ -289,47 +311,39 @@ static inline void mavlink_msg_hil_gps_send(mavlink_channel_t chan, uint64_t tim static inline void mavlink_msg_hil_gps_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t fix_type, int32_t lat, int32_t lon, int32_t alt, uint16_t eph, uint16_t epv, uint16_t vel, int16_t vn, int16_t ve, int16_t vd, uint16_t cog, uint8_t satellites_visible) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_int32_t(buf, 16, alt); - _mav_put_uint16_t(buf, 20, eph); - _mav_put_uint16_t(buf, 22, epv); - _mav_put_uint16_t(buf, 24, vel); - _mav_put_int16_t(buf, 26, vn); - _mav_put_int16_t(buf, 28, ve); - _mav_put_int16_t(buf, 30, vd); - _mav_put_uint16_t(buf, 32, cog); - _mav_put_uint8_t(buf, 34, fix_type); - _mav_put_uint8_t(buf, 35, satellites_visible); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, buf, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_int32_t(buf, 16, alt); + _mav_put_uint16_t(buf, 20, eph); + _mav_put_uint16_t(buf, 22, epv); + _mav_put_uint16_t(buf, 24, vel); + _mav_put_int16_t(buf, 26, vn); + _mav_put_int16_t(buf, 28, ve); + _mav_put_int16_t(buf, 30, vd); + _mav_put_uint16_t(buf, 32, cog); + _mav_put_uint8_t(buf, 34, fix_type); + _mav_put_uint8_t(buf, 35, satellites_visible); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, buf, MAVLINK_MSG_ID_HIL_GPS_MIN_LEN, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, buf, MAVLINK_MSG_ID_HIL_GPS_LEN); -#endif -#else - mavlink_hil_gps_t *packet = (mavlink_hil_gps_t *)msgbuf; - packet->time_usec = time_usec; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->eph = eph; - packet->epv = epv; - packet->vel = vel; - packet->vn = vn; - packet->ve = ve; - packet->vd = vd; - packet->cog = cog; - packet->fix_type = fix_type; - packet->satellites_visible = satellites_visible; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, (const char *)packet, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, (const char *)packet, MAVLINK_MSG_ID_HIL_GPS_LEN); -#endif + mavlink_hil_gps_t *packet = (mavlink_hil_gps_t *)msgbuf; + packet->time_usec = time_usec; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->eph = eph; + packet->epv = epv; + packet->vel = vel; + packet->vn = vn; + packet->ve = ve; + packet->vd = vd; + packet->cog = cog; + packet->fix_type = fix_type; + packet->satellites_visible = satellites_visible; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_GPS, (const char *)packet, MAVLINK_MSG_ID_HIL_GPS_MIN_LEN, MAVLINK_MSG_ID_HIL_GPS_LEN, MAVLINK_MSG_ID_HIL_GPS_CRC); #endif } #endif @@ -346,7 +360,7 @@ static inline void mavlink_msg_hil_gps_send_buf(mavlink_message_t *msgbuf, mavli */ static inline uint64_t mavlink_msg_hil_gps_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -356,7 +370,7 @@ static inline uint64_t mavlink_msg_hil_gps_get_time_usec(const mavlink_message_t */ static inline uint8_t mavlink_msg_hil_gps_get_fix_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -366,7 +380,7 @@ static inline uint8_t mavlink_msg_hil_gps_get_fix_type(const mavlink_message_t* */ static inline int32_t mavlink_msg_hil_gps_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -376,7 +390,7 @@ static inline int32_t mavlink_msg_hil_gps_get_lat(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_hil_gps_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -386,7 +400,7 @@ static inline int32_t mavlink_msg_hil_gps_get_lon(const mavlink_message_t* msg) */ static inline int32_t mavlink_msg_hil_gps_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -396,7 +410,7 @@ static inline int32_t mavlink_msg_hil_gps_get_alt(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_hil_gps_get_eph(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 20); + return _MAV_RETURN_uint16_t(msg, 20); } /** @@ -406,17 +420,17 @@ static inline uint16_t mavlink_msg_hil_gps_get_eph(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_hil_gps_get_epv(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 22); + return _MAV_RETURN_uint16_t(msg, 22); } /** * @brief Get field vel from hil_gps message * - * @return GPS ground speed (m/s * 100). If unknown, set to: 65535 + * @return GPS ground speed in cm/s. If unknown, set to: 65535 */ static inline uint16_t mavlink_msg_hil_gps_get_vel(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -426,7 +440,7 @@ static inline uint16_t mavlink_msg_hil_gps_get_vel(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_hil_gps_get_vn(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 26); + return _MAV_RETURN_int16_t(msg, 26); } /** @@ -436,7 +450,7 @@ static inline int16_t mavlink_msg_hil_gps_get_vn(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_hil_gps_get_ve(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 28); + return _MAV_RETURN_int16_t(msg, 28); } /** @@ -446,7 +460,7 @@ static inline int16_t mavlink_msg_hil_gps_get_ve(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_hil_gps_get_vd(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 30); + return _MAV_RETURN_int16_t(msg, 30); } /** @@ -456,7 +470,7 @@ static inline int16_t mavlink_msg_hil_gps_get_vd(const mavlink_message_t* msg) */ static inline uint16_t mavlink_msg_hil_gps_get_cog(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 32); + return _MAV_RETURN_uint16_t(msg, 32); } /** @@ -466,7 +480,7 @@ static inline uint16_t mavlink_msg_hil_gps_get_cog(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_hil_gps_get_satellites_visible(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 35); + return _MAV_RETURN_uint8_t(msg, 35); } /** @@ -477,21 +491,23 @@ static inline uint8_t mavlink_msg_hil_gps_get_satellites_visible(const mavlink_m */ static inline void mavlink_msg_hil_gps_decode(const mavlink_message_t* msg, mavlink_hil_gps_t* hil_gps) { -#if MAVLINK_NEED_BYTE_SWAP - hil_gps->time_usec = mavlink_msg_hil_gps_get_time_usec(msg); - hil_gps->lat = mavlink_msg_hil_gps_get_lat(msg); - hil_gps->lon = mavlink_msg_hil_gps_get_lon(msg); - hil_gps->alt = mavlink_msg_hil_gps_get_alt(msg); - hil_gps->eph = mavlink_msg_hil_gps_get_eph(msg); - hil_gps->epv = mavlink_msg_hil_gps_get_epv(msg); - hil_gps->vel = mavlink_msg_hil_gps_get_vel(msg); - hil_gps->vn = mavlink_msg_hil_gps_get_vn(msg); - hil_gps->ve = mavlink_msg_hil_gps_get_ve(msg); - hil_gps->vd = mavlink_msg_hil_gps_get_vd(msg); - hil_gps->cog = mavlink_msg_hil_gps_get_cog(msg); - hil_gps->fix_type = mavlink_msg_hil_gps_get_fix_type(msg); - hil_gps->satellites_visible = mavlink_msg_hil_gps_get_satellites_visible(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_gps->time_usec = mavlink_msg_hil_gps_get_time_usec(msg); + hil_gps->lat = mavlink_msg_hil_gps_get_lat(msg); + hil_gps->lon = mavlink_msg_hil_gps_get_lon(msg); + hil_gps->alt = mavlink_msg_hil_gps_get_alt(msg); + hil_gps->eph = mavlink_msg_hil_gps_get_eph(msg); + hil_gps->epv = mavlink_msg_hil_gps_get_epv(msg); + hil_gps->vel = mavlink_msg_hil_gps_get_vel(msg); + hil_gps->vn = mavlink_msg_hil_gps_get_vn(msg); + hil_gps->ve = mavlink_msg_hil_gps_get_ve(msg); + hil_gps->vd = mavlink_msg_hil_gps_get_vd(msg); + hil_gps->cog = mavlink_msg_hil_gps_get_cog(msg); + hil_gps->fix_type = mavlink_msg_hil_gps_get_fix_type(msg); + hil_gps->satellites_visible = mavlink_msg_hil_gps_get_satellites_visible(msg); #else - memcpy(hil_gps, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIL_GPS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_GPS_LEN? msg->len : MAVLINK_MSG_ID_HIL_GPS_LEN; + memset(hil_gps, 0, MAVLINK_MSG_ID_HIL_GPS_LEN); + memcpy(hil_gps, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_optical_flow.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_optical_flow.h index 7acb0b8771..9d1cf8e7d7 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_hil_optical_flow.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_optical_flow.h @@ -1,35 +1,40 @@ +#pragma once // MESSAGE HIL_OPTICAL_FLOW PACKING #define MAVLINK_MSG_ID_HIL_OPTICAL_FLOW 114 -typedef struct __mavlink_hil_optical_flow_t -{ - uint64_t time_usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - uint32_t integration_time_us; ///< Integration time in microseconds. Divide integrated_x and integrated_y by the integration time to obtain average flow. The integration time also indicates the. - float integrated_x; ///< Flow in radians around X axis (Sensor RH rotation about the X axis induces a positive flow. Sensor linear motion along the positive Y axis induces a negative flow.) - float integrated_y; ///< Flow in radians around Y axis (Sensor RH rotation about the Y axis induces a positive flow. Sensor linear motion along the positive X axis induces a positive flow.) - float integrated_xgyro; ///< RH rotation around X axis (rad) - float integrated_ygyro; ///< RH rotation around Y axis (rad) - float integrated_zgyro; ///< RH rotation around Z axis (rad) - uint32_t time_delta_distance_us; ///< Time in microseconds since the distance was sampled. - float distance; ///< Distance to the center of the flow field in meters. Positive value (including zero): distance known. Negative value: Unknown distance. - int16_t temperature; ///< Temperature * 100 in centi-degrees Celsius - uint8_t sensor_id; ///< Sensor ID - uint8_t quality; ///< Optical flow quality / confidence. 0: no valid flow, 255: maximum quality -} mavlink_hil_optical_flow_t; +MAVPACKED( +typedef struct __mavlink_hil_optical_flow_t { + uint64_t time_usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + uint32_t integration_time_us; /*< Integration time in microseconds. Divide integrated_x and integrated_y by the integration time to obtain average flow. The integration time also indicates the.*/ + float integrated_x; /*< Flow in radians around X axis (Sensor RH rotation about the X axis induces a positive flow. Sensor linear motion along the positive Y axis induces a negative flow.)*/ + float integrated_y; /*< Flow in radians around Y axis (Sensor RH rotation about the Y axis induces a positive flow. Sensor linear motion along the positive X axis induces a positive flow.)*/ + float integrated_xgyro; /*< RH rotation around X axis (rad)*/ + float integrated_ygyro; /*< RH rotation around Y axis (rad)*/ + float integrated_zgyro; /*< RH rotation around Z axis (rad)*/ + uint32_t time_delta_distance_us; /*< Time in microseconds since the distance was sampled.*/ + float distance; /*< Distance to the center of the flow field in meters. Positive value (including zero): distance known. Negative value: Unknown distance.*/ + int16_t temperature; /*< Temperature * 100 in centi-degrees Celsius*/ + uint8_t sensor_id; /*< Sensor ID*/ + uint8_t quality; /*< Optical flow quality / confidence. 0: no valid flow, 255: maximum quality*/ +}) mavlink_hil_optical_flow_t; #define MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN 44 +#define MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN 44 #define MAVLINK_MSG_ID_114_LEN 44 +#define MAVLINK_MSG_ID_114_MIN_LEN 44 #define MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC 237 #define MAVLINK_MSG_ID_114_CRC 237 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW { \ - "HIL_OPTICAL_FLOW", \ - 12, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_optical_flow_t, time_usec) }, \ + 114, \ + "HIL_OPTICAL_FLOW", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_optical_flow_t, time_usec) }, \ { "integration_time_us", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_hil_optical_flow_t, integration_time_us) }, \ { "integrated_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_optical_flow_t, integrated_x) }, \ { "integrated_y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_optical_flow_t, integrated_y) }, \ @@ -43,7 +48,25 @@ typedef struct __mavlink_hil_optical_flow_t { "quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 43, offsetof(mavlink_hil_optical_flow_t, quality) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIL_OPTICAL_FLOW { \ + "HIL_OPTICAL_FLOW", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_optical_flow_t, time_usec) }, \ + { "integration_time_us", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_hil_optical_flow_t, integration_time_us) }, \ + { "integrated_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_optical_flow_t, integrated_x) }, \ + { "integrated_y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_optical_flow_t, integrated_y) }, \ + { "integrated_xgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_hil_optical_flow_t, integrated_xgyro) }, \ + { "integrated_ygyro", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_hil_optical_flow_t, integrated_ygyro) }, \ + { "integrated_zgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_hil_optical_flow_t, integrated_zgyro) }, \ + { "time_delta_distance_us", NULL, MAVLINK_TYPE_UINT32_T, 0, 32, offsetof(mavlink_hil_optical_flow_t, time_delta_distance_us) }, \ + { "distance", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_hil_optical_flow_t, distance) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 40, offsetof(mavlink_hil_optical_flow_t, temperature) }, \ + { "sensor_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_hil_optical_flow_t, sensor_id) }, \ + { "quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 43, offsetof(mavlink_hil_optical_flow_t, quality) }, \ + } \ +} +#endif /** * @brief Pack a hil_optical_flow message @@ -66,48 +89,44 @@ typedef struct __mavlink_hil_optical_flow_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_optical_flow_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) + uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); + char buf[MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); #else - mavlink_hil_optical_flow_t packet; - packet.time_usec = time_usec; - packet.integration_time_us = integration_time_us; - packet.integrated_x = integrated_x; - packet.integrated_y = integrated_y; - packet.integrated_xgyro = integrated_xgyro; - packet.integrated_ygyro = integrated_ygyro; - packet.integrated_zgyro = integrated_zgyro; - packet.time_delta_distance_us = time_delta_distance_us; - packet.distance = distance; - packet.temperature = temperature; - packet.sensor_id = sensor_id; - packet.quality = quality; + mavlink_hil_optical_flow_t packet; + packet.time_usec = time_usec; + packet.integration_time_us = integration_time_us; + packet.integrated_x = integrated_x; + packet.integrated_y = integrated_y; + packet.integrated_xgyro = integrated_xgyro; + packet.integrated_ygyro = integrated_ygyro; + packet.integrated_zgyro = integrated_zgyro; + packet.time_delta_distance_us = time_delta_distance_us; + packet.distance = distance; + packet.temperature = temperature; + packet.sensor_id = sensor_id; + packet.quality = quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_OPTICAL_FLOW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_OPTICAL_FLOW; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); } /** @@ -131,49 +150,45 @@ static inline uint16_t mavlink_msg_hil_optical_flow_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_optical_flow_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t sensor_id,uint32_t integration_time_us,float integrated_x,float integrated_y,float integrated_xgyro,float integrated_ygyro,float integrated_zgyro,int16_t temperature,uint8_t quality,uint32_t time_delta_distance_us,float distance) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t sensor_id,uint32_t integration_time_us,float integrated_x,float integrated_y,float integrated_xgyro,float integrated_ygyro,float integrated_zgyro,int16_t temperature,uint8_t quality,uint32_t time_delta_distance_us,float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); + char buf[MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); #else - mavlink_hil_optical_flow_t packet; - packet.time_usec = time_usec; - packet.integration_time_us = integration_time_us; - packet.integrated_x = integrated_x; - packet.integrated_y = integrated_y; - packet.integrated_xgyro = integrated_xgyro; - packet.integrated_ygyro = integrated_ygyro; - packet.integrated_zgyro = integrated_zgyro; - packet.time_delta_distance_us = time_delta_distance_us; - packet.distance = distance; - packet.temperature = temperature; - packet.sensor_id = sensor_id; - packet.quality = quality; + mavlink_hil_optical_flow_t packet; + packet.time_usec = time_usec; + packet.integration_time_us = integration_time_us; + packet.integrated_x = integrated_x; + packet.integrated_y = integrated_y; + packet.integrated_xgyro = integrated_xgyro; + packet.integrated_ygyro = integrated_ygyro; + packet.integrated_zgyro = integrated_zgyro; + packet.time_delta_distance_us = time_delta_distance_us; + packet.distance = distance; + packet.temperature = temperature; + packet.sensor_id = sensor_id; + packet.quality = quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_OPTICAL_FLOW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_OPTICAL_FLOW; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); } /** @@ -186,7 +201,7 @@ static inline uint16_t mavlink_msg_hil_optical_flow_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_hil_optical_flow_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_optical_flow_t* hil_optical_flow) { - return mavlink_msg_hil_optical_flow_pack(system_id, component_id, msg, hil_optical_flow->time_usec, hil_optical_flow->sensor_id, hil_optical_flow->integration_time_us, hil_optical_flow->integrated_x, hil_optical_flow->integrated_y, hil_optical_flow->integrated_xgyro, hil_optical_flow->integrated_ygyro, hil_optical_flow->integrated_zgyro, hil_optical_flow->temperature, hil_optical_flow->quality, hil_optical_flow->time_delta_distance_us, hil_optical_flow->distance); + return mavlink_msg_hil_optical_flow_pack(system_id, component_id, msg, hil_optical_flow->time_usec, hil_optical_flow->sensor_id, hil_optical_flow->integration_time_us, hil_optical_flow->integrated_x, hil_optical_flow->integrated_y, hil_optical_flow->integrated_xgyro, hil_optical_flow->integrated_ygyro, hil_optical_flow->integrated_zgyro, hil_optical_flow->temperature, hil_optical_flow->quality, hil_optical_flow->time_delta_distance_us, hil_optical_flow->distance); } /** @@ -200,7 +215,7 @@ static inline uint16_t mavlink_msg_hil_optical_flow_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_hil_optical_flow_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_optical_flow_t* hil_optical_flow) { - return mavlink_msg_hil_optical_flow_pack_chan(system_id, component_id, chan, msg, hil_optical_flow->time_usec, hil_optical_flow->sensor_id, hil_optical_flow->integration_time_us, hil_optical_flow->integrated_x, hil_optical_flow->integrated_y, hil_optical_flow->integrated_xgyro, hil_optical_flow->integrated_ygyro, hil_optical_flow->integrated_zgyro, hil_optical_flow->temperature, hil_optical_flow->quality, hil_optical_flow->time_delta_distance_us, hil_optical_flow->distance); + return mavlink_msg_hil_optical_flow_pack_chan(system_id, component_id, chan, msg, hil_optical_flow->time_usec, hil_optical_flow->sensor_id, hil_optical_flow->integration_time_us, hil_optical_flow->integrated_x, hil_optical_flow->integrated_y, hil_optical_flow->integrated_xgyro, hil_optical_flow->integrated_ygyro, hil_optical_flow->integrated_zgyro, hil_optical_flow->temperature, hil_optical_flow->quality, hil_optical_flow->time_delta_distance_us, hil_optical_flow->distance); } /** @@ -225,45 +240,51 @@ static inline uint16_t mavlink_msg_hil_optical_flow_encode_chan(uint8_t system_i static inline void mavlink_msg_hil_optical_flow_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); + char buf[MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); + mavlink_hil_optical_flow_t packet; + packet.time_usec = time_usec; + packet.integration_time_us = integration_time_us; + packet.integrated_x = integrated_x; + packet.integrated_y = integrated_y; + packet.integrated_xgyro = integrated_xgyro; + packet.integrated_ygyro = integrated_ygyro; + packet.integrated_zgyro = integrated_zgyro; + packet.time_delta_distance_us = time_delta_distance_us; + packet.distance = distance; + packet.temperature = temperature; + packet.sensor_id = sensor_id; + packet.quality = quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, (const char *)&packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); #endif +} + +/** + * @brief Send a hil_optical_flow message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_optical_flow_send_struct(mavlink_channel_t chan, const mavlink_hil_optical_flow_t* hil_optical_flow) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_optical_flow_send(chan, hil_optical_flow->time_usec, hil_optical_flow->sensor_id, hil_optical_flow->integration_time_us, hil_optical_flow->integrated_x, hil_optical_flow->integrated_y, hil_optical_flow->integrated_xgyro, hil_optical_flow->integrated_ygyro, hil_optical_flow->integrated_zgyro, hil_optical_flow->temperature, hil_optical_flow->quality, hil_optical_flow->time_delta_distance_us, hil_optical_flow->distance); #else - mavlink_hil_optical_flow_t packet; - packet.time_usec = time_usec; - packet.integration_time_us = integration_time_us; - packet.integrated_x = integrated_x; - packet.integrated_y = integrated_y; - packet.integrated_xgyro = integrated_xgyro; - packet.integrated_ygyro = integrated_ygyro; - packet.integrated_zgyro = integrated_zgyro; - packet.time_delta_distance_us = time_delta_distance_us; - packet.distance = distance; - packet.temperature = temperature; - packet.sensor_id = sensor_id; - packet.quality = quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, (const char *)&packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, (const char *)&packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, (const char *)hil_optical_flow, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); #endif } @@ -278,45 +299,37 @@ static inline void mavlink_msg_hil_optical_flow_send(mavlink_channel_t chan, uin static inline void mavlink_msg_hil_optical_flow_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); -#endif -#else - mavlink_hil_optical_flow_t *packet = (mavlink_hil_optical_flow_t *)msgbuf; - packet->time_usec = time_usec; - packet->integration_time_us = integration_time_us; - packet->integrated_x = integrated_x; - packet->integrated_y = integrated_y; - packet->integrated_xgyro = integrated_xgyro; - packet->integrated_ygyro = integrated_ygyro; - packet->integrated_zgyro = integrated_zgyro; - packet->time_delta_distance_us = time_delta_distance_us; - packet->distance = distance; - packet->temperature = temperature; - packet->sensor_id = sensor_id; - packet->quality = quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, (const char *)packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, (const char *)packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); -#endif + mavlink_hil_optical_flow_t *packet = (mavlink_hil_optical_flow_t *)msgbuf; + packet->time_usec = time_usec; + packet->integration_time_us = integration_time_us; + packet->integrated_x = integrated_x; + packet->integrated_y = integrated_y; + packet->integrated_xgyro = integrated_xgyro; + packet->integrated_ygyro = integrated_ygyro; + packet->integrated_zgyro = integrated_zgyro; + packet->time_delta_distance_us = time_delta_distance_us; + packet->distance = distance; + packet->temperature = temperature; + packet->sensor_id = sensor_id; + packet->quality = quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW, (const char *)packet, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_CRC); #endif } #endif @@ -333,7 +346,7 @@ static inline void mavlink_msg_hil_optical_flow_send_buf(mavlink_message_t *msgb */ static inline uint64_t mavlink_msg_hil_optical_flow_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -343,7 +356,7 @@ static inline uint64_t mavlink_msg_hil_optical_flow_get_time_usec(const mavlink_ */ static inline uint8_t mavlink_msg_hil_optical_flow_get_sensor_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 42); + return _MAV_RETURN_uint8_t(msg, 42); } /** @@ -353,7 +366,7 @@ static inline uint8_t mavlink_msg_hil_optical_flow_get_sensor_id(const mavlink_m */ static inline uint32_t mavlink_msg_hil_optical_flow_get_integration_time_us(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 8); + return _MAV_RETURN_uint32_t(msg, 8); } /** @@ -363,7 +376,7 @@ static inline uint32_t mavlink_msg_hil_optical_flow_get_integration_time_us(cons */ static inline float mavlink_msg_hil_optical_flow_get_integrated_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -373,7 +386,7 @@ static inline float mavlink_msg_hil_optical_flow_get_integrated_x(const mavlink_ */ static inline float mavlink_msg_hil_optical_flow_get_integrated_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -383,7 +396,7 @@ static inline float mavlink_msg_hil_optical_flow_get_integrated_y(const mavlink_ */ static inline float mavlink_msg_hil_optical_flow_get_integrated_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -393,7 +406,7 @@ static inline float mavlink_msg_hil_optical_flow_get_integrated_xgyro(const mavl */ static inline float mavlink_msg_hil_optical_flow_get_integrated_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -403,7 +416,7 @@ static inline float mavlink_msg_hil_optical_flow_get_integrated_ygyro(const mavl */ static inline float mavlink_msg_hil_optical_flow_get_integrated_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -413,7 +426,7 @@ static inline float mavlink_msg_hil_optical_flow_get_integrated_zgyro(const mavl */ static inline int16_t mavlink_msg_hil_optical_flow_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 40); + return _MAV_RETURN_int16_t(msg, 40); } /** @@ -423,7 +436,7 @@ static inline int16_t mavlink_msg_hil_optical_flow_get_temperature(const mavlink */ static inline uint8_t mavlink_msg_hil_optical_flow_get_quality(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 43); + return _MAV_RETURN_uint8_t(msg, 43); } /** @@ -433,7 +446,7 @@ static inline uint8_t mavlink_msg_hil_optical_flow_get_quality(const mavlink_mes */ static inline uint32_t mavlink_msg_hil_optical_flow_get_time_delta_distance_us(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 32); + return _MAV_RETURN_uint32_t(msg, 32); } /** @@ -443,7 +456,7 @@ static inline uint32_t mavlink_msg_hil_optical_flow_get_time_delta_distance_us(c */ static inline float mavlink_msg_hil_optical_flow_get_distance(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -454,20 +467,22 @@ static inline float mavlink_msg_hil_optical_flow_get_distance(const mavlink_mess */ static inline void mavlink_msg_hil_optical_flow_decode(const mavlink_message_t* msg, mavlink_hil_optical_flow_t* hil_optical_flow) { -#if MAVLINK_NEED_BYTE_SWAP - hil_optical_flow->time_usec = mavlink_msg_hil_optical_flow_get_time_usec(msg); - hil_optical_flow->integration_time_us = mavlink_msg_hil_optical_flow_get_integration_time_us(msg); - hil_optical_flow->integrated_x = mavlink_msg_hil_optical_flow_get_integrated_x(msg); - hil_optical_flow->integrated_y = mavlink_msg_hil_optical_flow_get_integrated_y(msg); - hil_optical_flow->integrated_xgyro = mavlink_msg_hil_optical_flow_get_integrated_xgyro(msg); - hil_optical_flow->integrated_ygyro = mavlink_msg_hil_optical_flow_get_integrated_ygyro(msg); - hil_optical_flow->integrated_zgyro = mavlink_msg_hil_optical_flow_get_integrated_zgyro(msg); - hil_optical_flow->time_delta_distance_us = mavlink_msg_hil_optical_flow_get_time_delta_distance_us(msg); - hil_optical_flow->distance = mavlink_msg_hil_optical_flow_get_distance(msg); - hil_optical_flow->temperature = mavlink_msg_hil_optical_flow_get_temperature(msg); - hil_optical_flow->sensor_id = mavlink_msg_hil_optical_flow_get_sensor_id(msg); - hil_optical_flow->quality = mavlink_msg_hil_optical_flow_get_quality(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_optical_flow->time_usec = mavlink_msg_hil_optical_flow_get_time_usec(msg); + hil_optical_flow->integration_time_us = mavlink_msg_hil_optical_flow_get_integration_time_us(msg); + hil_optical_flow->integrated_x = mavlink_msg_hil_optical_flow_get_integrated_x(msg); + hil_optical_flow->integrated_y = mavlink_msg_hil_optical_flow_get_integrated_y(msg); + hil_optical_flow->integrated_xgyro = mavlink_msg_hil_optical_flow_get_integrated_xgyro(msg); + hil_optical_flow->integrated_ygyro = mavlink_msg_hil_optical_flow_get_integrated_ygyro(msg); + hil_optical_flow->integrated_zgyro = mavlink_msg_hil_optical_flow_get_integrated_zgyro(msg); + hil_optical_flow->time_delta_distance_us = mavlink_msg_hil_optical_flow_get_time_delta_distance_us(msg); + hil_optical_flow->distance = mavlink_msg_hil_optical_flow_get_distance(msg); + hil_optical_flow->temperature = mavlink_msg_hil_optical_flow_get_temperature(msg); + hil_optical_flow->sensor_id = mavlink_msg_hil_optical_flow_get_sensor_id(msg); + hil_optical_flow->quality = mavlink_msg_hil_optical_flow_get_quality(msg); #else - memcpy(hil_optical_flow, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN? msg->len : MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN; + memset(hil_optical_flow, 0, MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_LEN); + memcpy(hil_optical_flow, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_rc_inputs_raw.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_rc_inputs_raw.h index 227cd9d94e..04b8a45a44 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_hil_rc_inputs_raw.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_rc_inputs_raw.h @@ -1,37 +1,42 @@ +#pragma once // MESSAGE HIL_RC_INPUTS_RAW PACKING #define MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW 92 -typedef struct __mavlink_hil_rc_inputs_raw_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - uint16_t chan1_raw; ///< RC channel 1 value, in microseconds - uint16_t chan2_raw; ///< RC channel 2 value, in microseconds - uint16_t chan3_raw; ///< RC channel 3 value, in microseconds - uint16_t chan4_raw; ///< RC channel 4 value, in microseconds - uint16_t chan5_raw; ///< RC channel 5 value, in microseconds - uint16_t chan6_raw; ///< RC channel 6 value, in microseconds - uint16_t chan7_raw; ///< RC channel 7 value, in microseconds - uint16_t chan8_raw; ///< RC channel 8 value, in microseconds - uint16_t chan9_raw; ///< RC channel 9 value, in microseconds - uint16_t chan10_raw; ///< RC channel 10 value, in microseconds - uint16_t chan11_raw; ///< RC channel 11 value, in microseconds - uint16_t chan12_raw; ///< RC channel 12 value, in microseconds - uint8_t rssi; ///< Receive signal strength indicator, 0: 0%, 255: 100% -} mavlink_hil_rc_inputs_raw_t; +MAVPACKED( +typedef struct __mavlink_hil_rc_inputs_raw_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + uint16_t chan1_raw; /*< RC channel 1 value, in microseconds*/ + uint16_t chan2_raw; /*< RC channel 2 value, in microseconds*/ + uint16_t chan3_raw; /*< RC channel 3 value, in microseconds*/ + uint16_t chan4_raw; /*< RC channel 4 value, in microseconds*/ + uint16_t chan5_raw; /*< RC channel 5 value, in microseconds*/ + uint16_t chan6_raw; /*< RC channel 6 value, in microseconds*/ + uint16_t chan7_raw; /*< RC channel 7 value, in microseconds*/ + uint16_t chan8_raw; /*< RC channel 8 value, in microseconds*/ + uint16_t chan9_raw; /*< RC channel 9 value, in microseconds*/ + uint16_t chan10_raw; /*< RC channel 10 value, in microseconds*/ + uint16_t chan11_raw; /*< RC channel 11 value, in microseconds*/ + uint16_t chan12_raw; /*< RC channel 12 value, in microseconds*/ + uint8_t rssi; /*< Receive signal strength indicator, 0: 0%, 255: 100%*/ +}) mavlink_hil_rc_inputs_raw_t; #define MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN 33 +#define MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN 33 #define MAVLINK_MSG_ID_92_LEN 33 +#define MAVLINK_MSG_ID_92_MIN_LEN 33 #define MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC 54 #define MAVLINK_MSG_ID_92_CRC 54 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW { \ - "HIL_RC_INPUTS_RAW", \ - 14, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_rc_inputs_raw_t, time_usec) }, \ + 92, \ + "HIL_RC_INPUTS_RAW", \ + 14, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_rc_inputs_raw_t, time_usec) }, \ { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_hil_rc_inputs_raw_t, chan1_raw) }, \ { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_hil_rc_inputs_raw_t, chan2_raw) }, \ { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_hil_rc_inputs_raw_t, chan3_raw) }, \ @@ -47,7 +52,27 @@ typedef struct __mavlink_hil_rc_inputs_raw_t { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_hil_rc_inputs_raw_t, rssi) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIL_RC_INPUTS_RAW { \ + "HIL_RC_INPUTS_RAW", \ + 14, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_rc_inputs_raw_t, time_usec) }, \ + { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_hil_rc_inputs_raw_t, chan1_raw) }, \ + { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_hil_rc_inputs_raw_t, chan2_raw) }, \ + { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_hil_rc_inputs_raw_t, chan3_raw) }, \ + { "chan4_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 14, offsetof(mavlink_hil_rc_inputs_raw_t, chan4_raw) }, \ + { "chan5_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_hil_rc_inputs_raw_t, chan5_raw) }, \ + { "chan6_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_hil_rc_inputs_raw_t, chan6_raw) }, \ + { "chan7_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_hil_rc_inputs_raw_t, chan7_raw) }, \ + { "chan8_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 22, offsetof(mavlink_hil_rc_inputs_raw_t, chan8_raw) }, \ + { "chan9_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_hil_rc_inputs_raw_t, chan9_raw) }, \ + { "chan10_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 26, offsetof(mavlink_hil_rc_inputs_raw_t, chan10_raw) }, \ + { "chan11_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_hil_rc_inputs_raw_t, chan11_raw) }, \ + { "chan12_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 30, offsetof(mavlink_hil_rc_inputs_raw_t, chan12_raw) }, \ + { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_hil_rc_inputs_raw_t, rssi) }, \ + } \ +} +#endif /** * @brief Pack a hil_rc_inputs_raw message @@ -72,52 +97,48 @@ typedef struct __mavlink_hil_rc_inputs_raw_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint8_t rssi) + uint64_t time_usec, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 8, chan1_raw); - _mav_put_uint16_t(buf, 10, chan2_raw); - _mav_put_uint16_t(buf, 12, chan3_raw); - _mav_put_uint16_t(buf, 14, chan4_raw); - _mav_put_uint16_t(buf, 16, chan5_raw); - _mav_put_uint16_t(buf, 18, chan6_raw); - _mav_put_uint16_t(buf, 20, chan7_raw); - _mav_put_uint16_t(buf, 22, chan8_raw); - _mav_put_uint16_t(buf, 24, chan9_raw); - _mav_put_uint16_t(buf, 26, chan10_raw); - _mav_put_uint16_t(buf, 28, chan11_raw); - _mav_put_uint16_t(buf, 30, chan12_raw); - _mav_put_uint8_t(buf, 32, rssi); + char buf[MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 8, chan1_raw); + _mav_put_uint16_t(buf, 10, chan2_raw); + _mav_put_uint16_t(buf, 12, chan3_raw); + _mav_put_uint16_t(buf, 14, chan4_raw); + _mav_put_uint16_t(buf, 16, chan5_raw); + _mav_put_uint16_t(buf, 18, chan6_raw); + _mav_put_uint16_t(buf, 20, chan7_raw); + _mav_put_uint16_t(buf, 22, chan8_raw); + _mav_put_uint16_t(buf, 24, chan9_raw); + _mav_put_uint16_t(buf, 26, chan10_raw); + _mav_put_uint16_t(buf, 28, chan11_raw); + _mav_put_uint16_t(buf, 30, chan12_raw); + _mav_put_uint8_t(buf, 32, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); #else - mavlink_hil_rc_inputs_raw_t packet; - packet.time_usec = time_usec; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.chan9_raw = chan9_raw; - packet.chan10_raw = chan10_raw; - packet.chan11_raw = chan11_raw; - packet.chan12_raw = chan12_raw; - packet.rssi = rssi; + mavlink_hil_rc_inputs_raw_t packet; + packet.time_usec = time_usec; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.chan9_raw = chan9_raw; + packet.chan10_raw = chan10_raw; + packet.chan11_raw = chan11_raw; + packet.chan12_raw = chan12_raw; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); } /** @@ -143,53 +164,49 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw,uint16_t chan9_raw,uint16_t chan10_raw,uint16_t chan11_raw,uint16_t chan12_raw,uint8_t rssi) + mavlink_message_t* msg, + uint64_t time_usec,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw,uint16_t chan9_raw,uint16_t chan10_raw,uint16_t chan11_raw,uint16_t chan12_raw,uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 8, chan1_raw); - _mav_put_uint16_t(buf, 10, chan2_raw); - _mav_put_uint16_t(buf, 12, chan3_raw); - _mav_put_uint16_t(buf, 14, chan4_raw); - _mav_put_uint16_t(buf, 16, chan5_raw); - _mav_put_uint16_t(buf, 18, chan6_raw); - _mav_put_uint16_t(buf, 20, chan7_raw); - _mav_put_uint16_t(buf, 22, chan8_raw); - _mav_put_uint16_t(buf, 24, chan9_raw); - _mav_put_uint16_t(buf, 26, chan10_raw); - _mav_put_uint16_t(buf, 28, chan11_raw); - _mav_put_uint16_t(buf, 30, chan12_raw); - _mav_put_uint8_t(buf, 32, rssi); + char buf[MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 8, chan1_raw); + _mav_put_uint16_t(buf, 10, chan2_raw); + _mav_put_uint16_t(buf, 12, chan3_raw); + _mav_put_uint16_t(buf, 14, chan4_raw); + _mav_put_uint16_t(buf, 16, chan5_raw); + _mav_put_uint16_t(buf, 18, chan6_raw); + _mav_put_uint16_t(buf, 20, chan7_raw); + _mav_put_uint16_t(buf, 22, chan8_raw); + _mav_put_uint16_t(buf, 24, chan9_raw); + _mav_put_uint16_t(buf, 26, chan10_raw); + _mav_put_uint16_t(buf, 28, chan11_raw); + _mav_put_uint16_t(buf, 30, chan12_raw); + _mav_put_uint8_t(buf, 32, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); #else - mavlink_hil_rc_inputs_raw_t packet; - packet.time_usec = time_usec; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.chan9_raw = chan9_raw; - packet.chan10_raw = chan10_raw; - packet.chan11_raw = chan11_raw; - packet.chan12_raw = chan12_raw; - packet.rssi = rssi; + mavlink_hil_rc_inputs_raw_t packet; + packet.time_usec = time_usec; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.chan9_raw = chan9_raw; + packet.chan10_raw = chan10_raw; + packet.chan11_raw = chan11_raw; + packet.chan12_raw = chan12_raw; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); } /** @@ -202,7 +219,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_rc_inputs_raw_t* hil_rc_inputs_raw) { - return mavlink_msg_hil_rc_inputs_raw_pack(system_id, component_id, msg, hil_rc_inputs_raw->time_usec, hil_rc_inputs_raw->chan1_raw, hil_rc_inputs_raw->chan2_raw, hil_rc_inputs_raw->chan3_raw, hil_rc_inputs_raw->chan4_raw, hil_rc_inputs_raw->chan5_raw, hil_rc_inputs_raw->chan6_raw, hil_rc_inputs_raw->chan7_raw, hil_rc_inputs_raw->chan8_raw, hil_rc_inputs_raw->chan9_raw, hil_rc_inputs_raw->chan10_raw, hil_rc_inputs_raw->chan11_raw, hil_rc_inputs_raw->chan12_raw, hil_rc_inputs_raw->rssi); + return mavlink_msg_hil_rc_inputs_raw_pack(system_id, component_id, msg, hil_rc_inputs_raw->time_usec, hil_rc_inputs_raw->chan1_raw, hil_rc_inputs_raw->chan2_raw, hil_rc_inputs_raw->chan3_raw, hil_rc_inputs_raw->chan4_raw, hil_rc_inputs_raw->chan5_raw, hil_rc_inputs_raw->chan6_raw, hil_rc_inputs_raw->chan7_raw, hil_rc_inputs_raw->chan8_raw, hil_rc_inputs_raw->chan9_raw, hil_rc_inputs_raw->chan10_raw, hil_rc_inputs_raw->chan11_raw, hil_rc_inputs_raw->chan12_raw, hil_rc_inputs_raw->rssi); } /** @@ -216,7 +233,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_rc_inputs_raw_t* hil_rc_inputs_raw) { - return mavlink_msg_hil_rc_inputs_raw_pack_chan(system_id, component_id, chan, msg, hil_rc_inputs_raw->time_usec, hil_rc_inputs_raw->chan1_raw, hil_rc_inputs_raw->chan2_raw, hil_rc_inputs_raw->chan3_raw, hil_rc_inputs_raw->chan4_raw, hil_rc_inputs_raw->chan5_raw, hil_rc_inputs_raw->chan6_raw, hil_rc_inputs_raw->chan7_raw, hil_rc_inputs_raw->chan8_raw, hil_rc_inputs_raw->chan9_raw, hil_rc_inputs_raw->chan10_raw, hil_rc_inputs_raw->chan11_raw, hil_rc_inputs_raw->chan12_raw, hil_rc_inputs_raw->rssi); + return mavlink_msg_hil_rc_inputs_raw_pack_chan(system_id, component_id, chan, msg, hil_rc_inputs_raw->time_usec, hil_rc_inputs_raw->chan1_raw, hil_rc_inputs_raw->chan2_raw, hil_rc_inputs_raw->chan3_raw, hil_rc_inputs_raw->chan4_raw, hil_rc_inputs_raw->chan5_raw, hil_rc_inputs_raw->chan6_raw, hil_rc_inputs_raw->chan7_raw, hil_rc_inputs_raw->chan8_raw, hil_rc_inputs_raw->chan9_raw, hil_rc_inputs_raw->chan10_raw, hil_rc_inputs_raw->chan11_raw, hil_rc_inputs_raw->chan12_raw, hil_rc_inputs_raw->rssi); } /** @@ -243,49 +260,55 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_encode_chan(uint8_t system_ static inline void mavlink_msg_hil_rc_inputs_raw_send(mavlink_channel_t chan, uint64_t time_usec, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 8, chan1_raw); - _mav_put_uint16_t(buf, 10, chan2_raw); - _mav_put_uint16_t(buf, 12, chan3_raw); - _mav_put_uint16_t(buf, 14, chan4_raw); - _mav_put_uint16_t(buf, 16, chan5_raw); - _mav_put_uint16_t(buf, 18, chan6_raw); - _mav_put_uint16_t(buf, 20, chan7_raw); - _mav_put_uint16_t(buf, 22, chan8_raw); - _mav_put_uint16_t(buf, 24, chan9_raw); - _mav_put_uint16_t(buf, 26, chan10_raw); - _mav_put_uint16_t(buf, 28, chan11_raw); - _mav_put_uint16_t(buf, 30, chan12_raw); - _mav_put_uint8_t(buf, 32, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); + char buf[MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 8, chan1_raw); + _mav_put_uint16_t(buf, 10, chan2_raw); + _mav_put_uint16_t(buf, 12, chan3_raw); + _mav_put_uint16_t(buf, 14, chan4_raw); + _mav_put_uint16_t(buf, 16, chan5_raw); + _mav_put_uint16_t(buf, 18, chan6_raw); + _mav_put_uint16_t(buf, 20, chan7_raw); + _mav_put_uint16_t(buf, 22, chan8_raw); + _mav_put_uint16_t(buf, 24, chan9_raw); + _mav_put_uint16_t(buf, 26, chan10_raw); + _mav_put_uint16_t(buf, 28, chan11_raw); + _mav_put_uint16_t(buf, 30, chan12_raw); + _mav_put_uint8_t(buf, 32, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); + mavlink_hil_rc_inputs_raw_t packet; + packet.time_usec = time_usec; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.chan9_raw = chan9_raw; + packet.chan10_raw = chan10_raw; + packet.chan11_raw = chan11_raw; + packet.chan12_raw = chan12_raw; + packet.rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, (const char *)&packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); #endif +} + +/** + * @brief Send a hil_rc_inputs_raw message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_rc_inputs_raw_send_struct(mavlink_channel_t chan, const mavlink_hil_rc_inputs_raw_t* hil_rc_inputs_raw) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_rc_inputs_raw_send(chan, hil_rc_inputs_raw->time_usec, hil_rc_inputs_raw->chan1_raw, hil_rc_inputs_raw->chan2_raw, hil_rc_inputs_raw->chan3_raw, hil_rc_inputs_raw->chan4_raw, hil_rc_inputs_raw->chan5_raw, hil_rc_inputs_raw->chan6_raw, hil_rc_inputs_raw->chan7_raw, hil_rc_inputs_raw->chan8_raw, hil_rc_inputs_raw->chan9_raw, hil_rc_inputs_raw->chan10_raw, hil_rc_inputs_raw->chan11_raw, hil_rc_inputs_raw->chan12_raw, hil_rc_inputs_raw->rssi); #else - mavlink_hil_rc_inputs_raw_t packet; - packet.time_usec = time_usec; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.chan9_raw = chan9_raw; - packet.chan10_raw = chan10_raw; - packet.chan11_raw = chan11_raw; - packet.chan12_raw = chan12_raw; - packet.rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, (const char *)&packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, (const char *)&packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, (const char *)hil_rc_inputs_raw, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); #endif } @@ -300,49 +323,41 @@ static inline void mavlink_msg_hil_rc_inputs_raw_send(mavlink_channel_t chan, ui static inline void mavlink_msg_hil_rc_inputs_raw_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 8, chan1_raw); - _mav_put_uint16_t(buf, 10, chan2_raw); - _mav_put_uint16_t(buf, 12, chan3_raw); - _mav_put_uint16_t(buf, 14, chan4_raw); - _mav_put_uint16_t(buf, 16, chan5_raw); - _mav_put_uint16_t(buf, 18, chan6_raw); - _mav_put_uint16_t(buf, 20, chan7_raw); - _mav_put_uint16_t(buf, 22, chan8_raw); - _mav_put_uint16_t(buf, 24, chan9_raw); - _mav_put_uint16_t(buf, 26, chan10_raw); - _mav_put_uint16_t(buf, 28, chan11_raw); - _mav_put_uint16_t(buf, 30, chan12_raw); - _mav_put_uint8_t(buf, 32, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 8, chan1_raw); + _mav_put_uint16_t(buf, 10, chan2_raw); + _mav_put_uint16_t(buf, 12, chan3_raw); + _mav_put_uint16_t(buf, 14, chan4_raw); + _mav_put_uint16_t(buf, 16, chan5_raw); + _mav_put_uint16_t(buf, 18, chan6_raw); + _mav_put_uint16_t(buf, 20, chan7_raw); + _mav_put_uint16_t(buf, 22, chan8_raw); + _mav_put_uint16_t(buf, 24, chan9_raw); + _mav_put_uint16_t(buf, 26, chan10_raw); + _mav_put_uint16_t(buf, 28, chan11_raw); + _mav_put_uint16_t(buf, 30, chan12_raw); + _mav_put_uint8_t(buf, 32, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, buf, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); -#endif -#else - mavlink_hil_rc_inputs_raw_t *packet = (mavlink_hil_rc_inputs_raw_t *)msgbuf; - packet->time_usec = time_usec; - packet->chan1_raw = chan1_raw; - packet->chan2_raw = chan2_raw; - packet->chan3_raw = chan3_raw; - packet->chan4_raw = chan4_raw; - packet->chan5_raw = chan5_raw; - packet->chan6_raw = chan6_raw; - packet->chan7_raw = chan7_raw; - packet->chan8_raw = chan8_raw; - packet->chan9_raw = chan9_raw; - packet->chan10_raw = chan10_raw; - packet->chan11_raw = chan11_raw; - packet->chan12_raw = chan12_raw; - packet->rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, (const char *)packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, (const char *)packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); -#endif + mavlink_hil_rc_inputs_raw_t *packet = (mavlink_hil_rc_inputs_raw_t *)msgbuf; + packet->time_usec = time_usec; + packet->chan1_raw = chan1_raw; + packet->chan2_raw = chan2_raw; + packet->chan3_raw = chan3_raw; + packet->chan4_raw = chan4_raw; + packet->chan5_raw = chan5_raw; + packet->chan6_raw = chan6_raw; + packet->chan7_raw = chan7_raw; + packet->chan8_raw = chan8_raw; + packet->chan9_raw = chan9_raw; + packet->chan10_raw = chan10_raw; + packet->chan11_raw = chan11_raw; + packet->chan12_raw = chan12_raw; + packet->rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW, (const char *)packet, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_CRC); #endif } #endif @@ -359,7 +374,7 @@ static inline void mavlink_msg_hil_rc_inputs_raw_send_buf(mavlink_message_t *msg */ static inline uint64_t mavlink_msg_hil_rc_inputs_raw_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -369,7 +384,7 @@ static inline uint64_t mavlink_msg_hil_rc_inputs_raw_get_time_usec(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan1_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -379,7 +394,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan1_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan2_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 10); + return _MAV_RETURN_uint16_t(msg, 10); } /** @@ -389,7 +404,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan2_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan3_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -399,7 +414,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan3_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan4_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 14); + return _MAV_RETURN_uint16_t(msg, 14); } /** @@ -409,7 +424,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan4_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan5_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** @@ -419,7 +434,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan5_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan6_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -429,7 +444,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan6_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan7_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 20); + return _MAV_RETURN_uint16_t(msg, 20); } /** @@ -439,7 +454,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan7_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan8_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 22); + return _MAV_RETURN_uint16_t(msg, 22); } /** @@ -449,7 +464,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan8_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan9_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -459,7 +474,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan9_raw(const mavlink */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan10_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 26); + return _MAV_RETURN_uint16_t(msg, 26); } /** @@ -469,7 +484,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan10_raw(const mavlin */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan11_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -479,7 +494,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan11_raw(const mavlin */ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan12_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 30); + return _MAV_RETURN_uint16_t(msg, 30); } /** @@ -489,7 +504,7 @@ static inline uint16_t mavlink_msg_hil_rc_inputs_raw_get_chan12_raw(const mavlin */ static inline uint8_t mavlink_msg_hil_rc_inputs_raw_get_rssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -500,22 +515,24 @@ static inline uint8_t mavlink_msg_hil_rc_inputs_raw_get_rssi(const mavlink_messa */ static inline void mavlink_msg_hil_rc_inputs_raw_decode(const mavlink_message_t* msg, mavlink_hil_rc_inputs_raw_t* hil_rc_inputs_raw) { -#if MAVLINK_NEED_BYTE_SWAP - hil_rc_inputs_raw->time_usec = mavlink_msg_hil_rc_inputs_raw_get_time_usec(msg); - hil_rc_inputs_raw->chan1_raw = mavlink_msg_hil_rc_inputs_raw_get_chan1_raw(msg); - hil_rc_inputs_raw->chan2_raw = mavlink_msg_hil_rc_inputs_raw_get_chan2_raw(msg); - hil_rc_inputs_raw->chan3_raw = mavlink_msg_hil_rc_inputs_raw_get_chan3_raw(msg); - hil_rc_inputs_raw->chan4_raw = mavlink_msg_hil_rc_inputs_raw_get_chan4_raw(msg); - hil_rc_inputs_raw->chan5_raw = mavlink_msg_hil_rc_inputs_raw_get_chan5_raw(msg); - hil_rc_inputs_raw->chan6_raw = mavlink_msg_hil_rc_inputs_raw_get_chan6_raw(msg); - hil_rc_inputs_raw->chan7_raw = mavlink_msg_hil_rc_inputs_raw_get_chan7_raw(msg); - hil_rc_inputs_raw->chan8_raw = mavlink_msg_hil_rc_inputs_raw_get_chan8_raw(msg); - hil_rc_inputs_raw->chan9_raw = mavlink_msg_hil_rc_inputs_raw_get_chan9_raw(msg); - hil_rc_inputs_raw->chan10_raw = mavlink_msg_hil_rc_inputs_raw_get_chan10_raw(msg); - hil_rc_inputs_raw->chan11_raw = mavlink_msg_hil_rc_inputs_raw_get_chan11_raw(msg); - hil_rc_inputs_raw->chan12_raw = mavlink_msg_hil_rc_inputs_raw_get_chan12_raw(msg); - hil_rc_inputs_raw->rssi = mavlink_msg_hil_rc_inputs_raw_get_rssi(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_rc_inputs_raw->time_usec = mavlink_msg_hil_rc_inputs_raw_get_time_usec(msg); + hil_rc_inputs_raw->chan1_raw = mavlink_msg_hil_rc_inputs_raw_get_chan1_raw(msg); + hil_rc_inputs_raw->chan2_raw = mavlink_msg_hil_rc_inputs_raw_get_chan2_raw(msg); + hil_rc_inputs_raw->chan3_raw = mavlink_msg_hil_rc_inputs_raw_get_chan3_raw(msg); + hil_rc_inputs_raw->chan4_raw = mavlink_msg_hil_rc_inputs_raw_get_chan4_raw(msg); + hil_rc_inputs_raw->chan5_raw = mavlink_msg_hil_rc_inputs_raw_get_chan5_raw(msg); + hil_rc_inputs_raw->chan6_raw = mavlink_msg_hil_rc_inputs_raw_get_chan6_raw(msg); + hil_rc_inputs_raw->chan7_raw = mavlink_msg_hil_rc_inputs_raw_get_chan7_raw(msg); + hil_rc_inputs_raw->chan8_raw = mavlink_msg_hil_rc_inputs_raw_get_chan8_raw(msg); + hil_rc_inputs_raw->chan9_raw = mavlink_msg_hil_rc_inputs_raw_get_chan9_raw(msg); + hil_rc_inputs_raw->chan10_raw = mavlink_msg_hil_rc_inputs_raw_get_chan10_raw(msg); + hil_rc_inputs_raw->chan11_raw = mavlink_msg_hil_rc_inputs_raw_get_chan11_raw(msg); + hil_rc_inputs_raw->chan12_raw = mavlink_msg_hil_rc_inputs_raw_get_chan12_raw(msg); + hil_rc_inputs_raw->rssi = mavlink_msg_hil_rc_inputs_raw_get_rssi(msg); #else - memcpy(hil_rc_inputs_raw, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN? msg->len : MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN; + memset(hil_rc_inputs_raw, 0, MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_LEN); + memcpy(hil_rc_inputs_raw, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_sensor.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_sensor.h index 8672f8b8a3..e7f561da33 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_hil_sensor.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_sensor.h @@ -1,38 +1,43 @@ +#pragma once // MESSAGE HIL_SENSOR PACKING #define MAVLINK_MSG_ID_HIL_SENSOR 107 -typedef struct __mavlink_hil_sensor_t -{ - uint64_t time_usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - float xacc; ///< X acceleration (m/s^2) - float yacc; ///< Y acceleration (m/s^2) - float zacc; ///< Z acceleration (m/s^2) - float xgyro; ///< Angular speed around X axis in body frame (rad / sec) - float ygyro; ///< Angular speed around Y axis in body frame (rad / sec) - float zgyro; ///< Angular speed around Z axis in body frame (rad / sec) - float xmag; ///< X Magnetic field (Gauss) - float ymag; ///< Y Magnetic field (Gauss) - float zmag; ///< Z Magnetic field (Gauss) - float abs_pressure; ///< Absolute pressure in millibar - float diff_pressure; ///< Differential pressure (airspeed) in millibar - float pressure_alt; ///< Altitude calculated from pressure - float temperature; ///< Temperature in degrees celsius - uint32_t fields_updated; ///< Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature -} mavlink_hil_sensor_t; +MAVPACKED( +typedef struct __mavlink_hil_sensor_t { + uint64_t time_usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + float xacc; /*< X acceleration (m/s^2)*/ + float yacc; /*< Y acceleration (m/s^2)*/ + float zacc; /*< Z acceleration (m/s^2)*/ + float xgyro; /*< Angular speed around X axis in body frame (rad / sec)*/ + float ygyro; /*< Angular speed around Y axis in body frame (rad / sec)*/ + float zgyro; /*< Angular speed around Z axis in body frame (rad / sec)*/ + float xmag; /*< X Magnetic field (Gauss)*/ + float ymag; /*< Y Magnetic field (Gauss)*/ + float zmag; /*< Z Magnetic field (Gauss)*/ + float abs_pressure; /*< Absolute pressure in millibar*/ + float diff_pressure; /*< Differential pressure (airspeed) in millibar*/ + float pressure_alt; /*< Altitude calculated from pressure*/ + float temperature; /*< Temperature in degrees celsius*/ + uint32_t fields_updated; /*< Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature, bit 31: full reset of attitude/position/velocities/etc was performed in sim.*/ +}) mavlink_hil_sensor_t; #define MAVLINK_MSG_ID_HIL_SENSOR_LEN 64 +#define MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN 64 #define MAVLINK_MSG_ID_107_LEN 64 +#define MAVLINK_MSG_ID_107_MIN_LEN 64 #define MAVLINK_MSG_ID_HIL_SENSOR_CRC 108 #define MAVLINK_MSG_ID_107_CRC 108 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIL_SENSOR { \ - "HIL_SENSOR", \ - 15, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_sensor_t, time_usec) }, \ + 107, \ + "HIL_SENSOR", \ + 15, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_sensor_t, time_usec) }, \ { "xacc", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_hil_sensor_t, xacc) }, \ { "yacc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_sensor_t, yacc) }, \ { "zacc", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_sensor_t, zacc) }, \ @@ -49,7 +54,28 @@ typedef struct __mavlink_hil_sensor_t { "fields_updated", NULL, MAVLINK_TYPE_UINT32_T, 0, 60, offsetof(mavlink_hil_sensor_t, fields_updated) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIL_SENSOR { \ + "HIL_SENSOR", \ + 15, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_sensor_t, time_usec) }, \ + { "xacc", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_hil_sensor_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_sensor_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_sensor_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_hil_sensor_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_hil_sensor_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_hil_sensor_t, zgyro) }, \ + { "xmag", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_hil_sensor_t, xmag) }, \ + { "ymag", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_hil_sensor_t, ymag) }, \ + { "zmag", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_hil_sensor_t, zmag) }, \ + { "abs_pressure", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_hil_sensor_t, abs_pressure) }, \ + { "diff_pressure", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_hil_sensor_t, diff_pressure) }, \ + { "pressure_alt", NULL, MAVLINK_TYPE_FLOAT, 0, 52, offsetof(mavlink_hil_sensor_t, pressure_alt) }, \ + { "temperature", NULL, MAVLINK_TYPE_FLOAT, 0, 56, offsetof(mavlink_hil_sensor_t, temperature) }, \ + { "fields_updated", NULL, MAVLINK_TYPE_UINT32_T, 0, 60, offsetof(mavlink_hil_sensor_t, fields_updated) }, \ + } \ +} +#endif /** * @brief Pack a hil_sensor message @@ -71,58 +97,54 @@ typedef struct __mavlink_hil_sensor_t * @param diff_pressure Differential pressure (airspeed) in millibar * @param pressure_alt Altitude calculated from pressure * @param temperature Temperature in degrees celsius - * @param fields_updated Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature + * @param fields_updated Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature, bit 31: full reset of attitude/position/velocities/etc was performed in sim. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_sensor_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint32_t fields_updated) + uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint32_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_SENSOR_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint32_t(buf, 60, fields_updated); + char buf[MAVLINK_MSG_ID_HIL_SENSOR_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint32_t(buf, 60, fields_updated); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_SENSOR_LEN); #else - mavlink_hil_sensor_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - packet.abs_pressure = abs_pressure; - packet.diff_pressure = diff_pressure; - packet.pressure_alt = pressure_alt; - packet.temperature = temperature; - packet.fields_updated = fields_updated; + mavlink_hil_sensor_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + packet.abs_pressure = abs_pressure; + packet.diff_pressure = diff_pressure; + packet.pressure_alt = pressure_alt; + packet.temperature = temperature; + packet.fields_updated = fields_updated; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_SENSOR_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_SENSOR; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_SENSOR_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_SENSOR; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); } /** @@ -145,59 +167,55 @@ static inline uint16_t mavlink_msg_hil_sensor_pack(uint8_t system_id, uint8_t co * @param diff_pressure Differential pressure (airspeed) in millibar * @param pressure_alt Altitude calculated from pressure * @param temperature Temperature in degrees celsius - * @param fields_updated Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature + * @param fields_updated Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature, bit 31: full reset of attitude/position/velocities/etc was performed in sim. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_sensor_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,float xmag,float ymag,float zmag,float abs_pressure,float diff_pressure,float pressure_alt,float temperature,uint32_t fields_updated) + mavlink_message_t* msg, + uint64_t time_usec,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,float xmag,float ymag,float zmag,float abs_pressure,float diff_pressure,float pressure_alt,float temperature,uint32_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_SENSOR_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint32_t(buf, 60, fields_updated); + char buf[MAVLINK_MSG_ID_HIL_SENSOR_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint32_t(buf, 60, fields_updated); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_SENSOR_LEN); #else - mavlink_hil_sensor_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - packet.abs_pressure = abs_pressure; - packet.diff_pressure = diff_pressure; - packet.pressure_alt = pressure_alt; - packet.temperature = temperature; - packet.fields_updated = fields_updated; + mavlink_hil_sensor_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + packet.abs_pressure = abs_pressure; + packet.diff_pressure = diff_pressure; + packet.pressure_alt = pressure_alt; + packet.temperature = temperature; + packet.fields_updated = fields_updated; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_SENSOR_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_SENSOR; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_SENSOR_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_SENSOR; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); } /** @@ -210,7 +228,7 @@ static inline uint16_t mavlink_msg_hil_sensor_pack_chan(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_hil_sensor_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_sensor_t* hil_sensor) { - return mavlink_msg_hil_sensor_pack(system_id, component_id, msg, hil_sensor->time_usec, hil_sensor->xacc, hil_sensor->yacc, hil_sensor->zacc, hil_sensor->xgyro, hil_sensor->ygyro, hil_sensor->zgyro, hil_sensor->xmag, hil_sensor->ymag, hil_sensor->zmag, hil_sensor->abs_pressure, hil_sensor->diff_pressure, hil_sensor->pressure_alt, hil_sensor->temperature, hil_sensor->fields_updated); + return mavlink_msg_hil_sensor_pack(system_id, component_id, msg, hil_sensor->time_usec, hil_sensor->xacc, hil_sensor->yacc, hil_sensor->zacc, hil_sensor->xgyro, hil_sensor->ygyro, hil_sensor->zgyro, hil_sensor->xmag, hil_sensor->ymag, hil_sensor->zmag, hil_sensor->abs_pressure, hil_sensor->diff_pressure, hil_sensor->pressure_alt, hil_sensor->temperature, hil_sensor->fields_updated); } /** @@ -224,7 +242,7 @@ static inline uint16_t mavlink_msg_hil_sensor_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_hil_sensor_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_sensor_t* hil_sensor) { - return mavlink_msg_hil_sensor_pack_chan(system_id, component_id, chan, msg, hil_sensor->time_usec, hil_sensor->xacc, hil_sensor->yacc, hil_sensor->zacc, hil_sensor->xgyro, hil_sensor->ygyro, hil_sensor->zgyro, hil_sensor->xmag, hil_sensor->ymag, hil_sensor->zmag, hil_sensor->abs_pressure, hil_sensor->diff_pressure, hil_sensor->pressure_alt, hil_sensor->temperature, hil_sensor->fields_updated); + return mavlink_msg_hil_sensor_pack_chan(system_id, component_id, chan, msg, hil_sensor->time_usec, hil_sensor->xacc, hil_sensor->yacc, hil_sensor->zacc, hil_sensor->xgyro, hil_sensor->ygyro, hil_sensor->zgyro, hil_sensor->xmag, hil_sensor->ymag, hil_sensor->zmag, hil_sensor->abs_pressure, hil_sensor->diff_pressure, hil_sensor->pressure_alt, hil_sensor->temperature, hil_sensor->fields_updated); } /** @@ -245,58 +263,64 @@ static inline uint16_t mavlink_msg_hil_sensor_encode_chan(uint8_t system_id, uin * @param diff_pressure Differential pressure (airspeed) in millibar * @param pressure_alt Altitude calculated from pressure * @param temperature Temperature in degrees celsius - * @param fields_updated Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature + * @param fields_updated Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature, bit 31: full reset of attitude/position/velocities/etc was performed in sim. */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS static inline void mavlink_msg_hil_sensor_send(mavlink_channel_t chan, uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint32_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_SENSOR_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint32_t(buf, 60, fields_updated); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, buf, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); + char buf[MAVLINK_MSG_ID_HIL_SENSOR_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint32_t(buf, 60, fields_updated); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, buf, MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, buf, MAVLINK_MSG_ID_HIL_SENSOR_LEN); + mavlink_hil_sensor_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + packet.abs_pressure = abs_pressure; + packet.diff_pressure = diff_pressure; + packet.pressure_alt = pressure_alt; + packet.temperature = temperature; + packet.fields_updated = fields_updated; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, (const char *)&packet, MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); #endif +} + +/** + * @brief Send a hil_sensor message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_sensor_send_struct(mavlink_channel_t chan, const mavlink_hil_sensor_t* hil_sensor) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_sensor_send(chan, hil_sensor->time_usec, hil_sensor->xacc, hil_sensor->yacc, hil_sensor->zacc, hil_sensor->xgyro, hil_sensor->ygyro, hil_sensor->zgyro, hil_sensor->xmag, hil_sensor->ymag, hil_sensor->zmag, hil_sensor->abs_pressure, hil_sensor->diff_pressure, hil_sensor->pressure_alt, hil_sensor->temperature, hil_sensor->fields_updated); #else - mavlink_hil_sensor_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - packet.abs_pressure = abs_pressure; - packet.diff_pressure = diff_pressure; - packet.pressure_alt = pressure_alt; - packet.temperature = temperature; - packet.fields_updated = fields_updated; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, (const char *)&packet, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, (const char *)&packet, MAVLINK_MSG_ID_HIL_SENSOR_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, (const char *)hil_sensor, MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); #endif } @@ -311,51 +335,43 @@ static inline void mavlink_msg_hil_sensor_send(mavlink_channel_t chan, uint64_t static inline void mavlink_msg_hil_sensor_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float xmag, float ymag, float zmag, float abs_pressure, float diff_pressure, float pressure_alt, float temperature, uint32_t fields_updated) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, xacc); - _mav_put_float(buf, 12, yacc); - _mav_put_float(buf, 16, zacc); - _mav_put_float(buf, 20, xgyro); - _mav_put_float(buf, 24, ygyro); - _mav_put_float(buf, 28, zgyro); - _mav_put_float(buf, 32, xmag); - _mav_put_float(buf, 36, ymag); - _mav_put_float(buf, 40, zmag); - _mav_put_float(buf, 44, abs_pressure); - _mav_put_float(buf, 48, diff_pressure); - _mav_put_float(buf, 52, pressure_alt); - _mav_put_float(buf, 56, temperature); - _mav_put_uint32_t(buf, 60, fields_updated); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, buf, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, xacc); + _mav_put_float(buf, 12, yacc); + _mav_put_float(buf, 16, zacc); + _mav_put_float(buf, 20, xgyro); + _mav_put_float(buf, 24, ygyro); + _mav_put_float(buf, 28, zgyro); + _mav_put_float(buf, 32, xmag); + _mav_put_float(buf, 36, ymag); + _mav_put_float(buf, 40, zmag); + _mav_put_float(buf, 44, abs_pressure); + _mav_put_float(buf, 48, diff_pressure); + _mav_put_float(buf, 52, pressure_alt); + _mav_put_float(buf, 56, temperature); + _mav_put_uint32_t(buf, 60, fields_updated); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, buf, MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, buf, MAVLINK_MSG_ID_HIL_SENSOR_LEN); -#endif -#else - mavlink_hil_sensor_t *packet = (mavlink_hil_sensor_t *)msgbuf; - packet->time_usec = time_usec; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - packet->xgyro = xgyro; - packet->ygyro = ygyro; - packet->zgyro = zgyro; - packet->xmag = xmag; - packet->ymag = ymag; - packet->zmag = zmag; - packet->abs_pressure = abs_pressure; - packet->diff_pressure = diff_pressure; - packet->pressure_alt = pressure_alt; - packet->temperature = temperature; - packet->fields_updated = fields_updated; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, (const char *)packet, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, (const char *)packet, MAVLINK_MSG_ID_HIL_SENSOR_LEN); -#endif + mavlink_hil_sensor_t *packet = (mavlink_hil_sensor_t *)msgbuf; + packet->time_usec = time_usec; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->xmag = xmag; + packet->ymag = ymag; + packet->zmag = zmag; + packet->abs_pressure = abs_pressure; + packet->diff_pressure = diff_pressure; + packet->pressure_alt = pressure_alt; + packet->temperature = temperature; + packet->fields_updated = fields_updated; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_SENSOR, (const char *)packet, MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN, MAVLINK_MSG_ID_HIL_SENSOR_LEN, MAVLINK_MSG_ID_HIL_SENSOR_CRC); #endif } #endif @@ -372,7 +388,7 @@ static inline void mavlink_msg_hil_sensor_send_buf(mavlink_message_t *msgbuf, ma */ static inline uint64_t mavlink_msg_hil_sensor_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -382,7 +398,7 @@ static inline uint64_t mavlink_msg_hil_sensor_get_time_usec(const mavlink_messag */ static inline float mavlink_msg_hil_sensor_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -392,7 +408,7 @@ static inline float mavlink_msg_hil_sensor_get_xacc(const mavlink_message_t* msg */ static inline float mavlink_msg_hil_sensor_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -402,7 +418,7 @@ static inline float mavlink_msg_hil_sensor_get_yacc(const mavlink_message_t* msg */ static inline float mavlink_msg_hil_sensor_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -412,7 +428,7 @@ static inline float mavlink_msg_hil_sensor_get_zacc(const mavlink_message_t* msg */ static inline float mavlink_msg_hil_sensor_get_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -422,7 +438,7 @@ static inline float mavlink_msg_hil_sensor_get_xgyro(const mavlink_message_t* ms */ static inline float mavlink_msg_hil_sensor_get_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -432,7 +448,7 @@ static inline float mavlink_msg_hil_sensor_get_ygyro(const mavlink_message_t* ms */ static inline float mavlink_msg_hil_sensor_get_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -442,7 +458,7 @@ static inline float mavlink_msg_hil_sensor_get_zgyro(const mavlink_message_t* ms */ static inline float mavlink_msg_hil_sensor_get_xmag(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -452,7 +468,7 @@ static inline float mavlink_msg_hil_sensor_get_xmag(const mavlink_message_t* msg */ static inline float mavlink_msg_hil_sensor_get_ymag(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -462,7 +478,7 @@ static inline float mavlink_msg_hil_sensor_get_ymag(const mavlink_message_t* msg */ static inline float mavlink_msg_hil_sensor_get_zmag(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -472,7 +488,7 @@ static inline float mavlink_msg_hil_sensor_get_zmag(const mavlink_message_t* msg */ static inline float mavlink_msg_hil_sensor_get_abs_pressure(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -482,7 +498,7 @@ static inline float mavlink_msg_hil_sensor_get_abs_pressure(const mavlink_messag */ static inline float mavlink_msg_hil_sensor_get_diff_pressure(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 48); + return _MAV_RETURN_float(msg, 48); } /** @@ -492,7 +508,7 @@ static inline float mavlink_msg_hil_sensor_get_diff_pressure(const mavlink_messa */ static inline float mavlink_msg_hil_sensor_get_pressure_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 52); + return _MAV_RETURN_float(msg, 52); } /** @@ -502,17 +518,17 @@ static inline float mavlink_msg_hil_sensor_get_pressure_alt(const mavlink_messag */ static inline float mavlink_msg_hil_sensor_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 56); + return _MAV_RETURN_float(msg, 56); } /** * @brief Get field fields_updated from hil_sensor message * - * @return Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature + * @return Bitmask for fields that have updated since last message, bit 0 = xacc, bit 12: temperature, bit 31: full reset of attitude/position/velocities/etc was performed in sim. */ static inline uint32_t mavlink_msg_hil_sensor_get_fields_updated(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 60); + return _MAV_RETURN_uint32_t(msg, 60); } /** @@ -523,23 +539,25 @@ static inline uint32_t mavlink_msg_hil_sensor_get_fields_updated(const mavlink_m */ static inline void mavlink_msg_hil_sensor_decode(const mavlink_message_t* msg, mavlink_hil_sensor_t* hil_sensor) { -#if MAVLINK_NEED_BYTE_SWAP - hil_sensor->time_usec = mavlink_msg_hil_sensor_get_time_usec(msg); - hil_sensor->xacc = mavlink_msg_hil_sensor_get_xacc(msg); - hil_sensor->yacc = mavlink_msg_hil_sensor_get_yacc(msg); - hil_sensor->zacc = mavlink_msg_hil_sensor_get_zacc(msg); - hil_sensor->xgyro = mavlink_msg_hil_sensor_get_xgyro(msg); - hil_sensor->ygyro = mavlink_msg_hil_sensor_get_ygyro(msg); - hil_sensor->zgyro = mavlink_msg_hil_sensor_get_zgyro(msg); - hil_sensor->xmag = mavlink_msg_hil_sensor_get_xmag(msg); - hil_sensor->ymag = mavlink_msg_hil_sensor_get_ymag(msg); - hil_sensor->zmag = mavlink_msg_hil_sensor_get_zmag(msg); - hil_sensor->abs_pressure = mavlink_msg_hil_sensor_get_abs_pressure(msg); - hil_sensor->diff_pressure = mavlink_msg_hil_sensor_get_diff_pressure(msg); - hil_sensor->pressure_alt = mavlink_msg_hil_sensor_get_pressure_alt(msg); - hil_sensor->temperature = mavlink_msg_hil_sensor_get_temperature(msg); - hil_sensor->fields_updated = mavlink_msg_hil_sensor_get_fields_updated(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_sensor->time_usec = mavlink_msg_hil_sensor_get_time_usec(msg); + hil_sensor->xacc = mavlink_msg_hil_sensor_get_xacc(msg); + hil_sensor->yacc = mavlink_msg_hil_sensor_get_yacc(msg); + hil_sensor->zacc = mavlink_msg_hil_sensor_get_zacc(msg); + hil_sensor->xgyro = mavlink_msg_hil_sensor_get_xgyro(msg); + hil_sensor->ygyro = mavlink_msg_hil_sensor_get_ygyro(msg); + hil_sensor->zgyro = mavlink_msg_hil_sensor_get_zgyro(msg); + hil_sensor->xmag = mavlink_msg_hil_sensor_get_xmag(msg); + hil_sensor->ymag = mavlink_msg_hil_sensor_get_ymag(msg); + hil_sensor->zmag = mavlink_msg_hil_sensor_get_zmag(msg); + hil_sensor->abs_pressure = mavlink_msg_hil_sensor_get_abs_pressure(msg); + hil_sensor->diff_pressure = mavlink_msg_hil_sensor_get_diff_pressure(msg); + hil_sensor->pressure_alt = mavlink_msg_hil_sensor_get_pressure_alt(msg); + hil_sensor->temperature = mavlink_msg_hil_sensor_get_temperature(msg); + hil_sensor->fields_updated = mavlink_msg_hil_sensor_get_fields_updated(msg); #else - memcpy(hil_sensor, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIL_SENSOR_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_SENSOR_LEN? msg->len : MAVLINK_MSG_ID_HIL_SENSOR_LEN; + memset(hil_sensor, 0, MAVLINK_MSG_ID_HIL_SENSOR_LEN); + memcpy(hil_sensor, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_state.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_state.h index 923ed60b95..722c5835be 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_hil_state.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_state.h @@ -1,39 +1,44 @@ +#pragma once // MESSAGE HIL_STATE PACKING #define MAVLINK_MSG_ID_HIL_STATE 90 -typedef struct __mavlink_hil_state_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - float roll; ///< Roll angle (rad) - float pitch; ///< Pitch angle (rad) - float yaw; ///< Yaw angle (rad) - float rollspeed; ///< Body frame roll / phi angular speed (rad/s) - float pitchspeed; ///< Body frame pitch / theta angular speed (rad/s) - float yawspeed; ///< Body frame yaw / psi angular speed (rad/s) - int32_t lat; ///< Latitude, expressed as * 1E7 - int32_t lon; ///< Longitude, expressed as * 1E7 - int32_t alt; ///< Altitude in meters, expressed as * 1000 (millimeters) - int16_t vx; ///< Ground X Speed (Latitude), expressed as m/s * 100 - int16_t vy; ///< Ground Y Speed (Longitude), expressed as m/s * 100 - int16_t vz; ///< Ground Z Speed (Altitude), expressed as m/s * 100 - int16_t xacc; ///< X acceleration (mg) - int16_t yacc; ///< Y acceleration (mg) - int16_t zacc; ///< Z acceleration (mg) -} mavlink_hil_state_t; +MAVPACKED( +typedef struct __mavlink_hil_state_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + float roll; /*< Roll angle (rad)*/ + float pitch; /*< Pitch angle (rad)*/ + float yaw; /*< Yaw angle (rad)*/ + float rollspeed; /*< Body frame roll / phi angular speed (rad/s)*/ + float pitchspeed; /*< Body frame pitch / theta angular speed (rad/s)*/ + float yawspeed; /*< Body frame yaw / psi angular speed (rad/s)*/ + int32_t lat; /*< Latitude, expressed as * 1E7*/ + int32_t lon; /*< Longitude, expressed as * 1E7*/ + int32_t alt; /*< Altitude in meters, expressed as * 1000 (millimeters)*/ + int16_t vx; /*< Ground X Speed (Latitude), expressed as m/s * 100*/ + int16_t vy; /*< Ground Y Speed (Longitude), expressed as m/s * 100*/ + int16_t vz; /*< Ground Z Speed (Altitude), expressed as m/s * 100*/ + int16_t xacc; /*< X acceleration (mg)*/ + int16_t yacc; /*< Y acceleration (mg)*/ + int16_t zacc; /*< Z acceleration (mg)*/ +}) mavlink_hil_state_t; #define MAVLINK_MSG_ID_HIL_STATE_LEN 56 +#define MAVLINK_MSG_ID_HIL_STATE_MIN_LEN 56 #define MAVLINK_MSG_ID_90_LEN 56 +#define MAVLINK_MSG_ID_90_MIN_LEN 56 #define MAVLINK_MSG_ID_HIL_STATE_CRC 183 #define MAVLINK_MSG_ID_90_CRC 183 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIL_STATE { \ - "HIL_STATE", \ - 16, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_state_t, time_usec) }, \ + 90, \ + "HIL_STATE", \ + 16, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_state_t, time_usec) }, \ { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_hil_state_t, roll) }, \ { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_state_t, pitch) }, \ { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_state_t, yaw) }, \ @@ -51,7 +56,29 @@ typedef struct __mavlink_hil_state_t { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 54, offsetof(mavlink_hil_state_t, zacc) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIL_STATE { \ + "HIL_STATE", \ + 16, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_state_t, time_usec) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_hil_state_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_hil_state_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_hil_state_t, yaw) }, \ + { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_hil_state_t, rollspeed) }, \ + { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_hil_state_t, pitchspeed) }, \ + { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_hil_state_t, yawspeed) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 32, offsetof(mavlink_hil_state_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 36, offsetof(mavlink_hil_state_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 40, offsetof(mavlink_hil_state_t, alt) }, \ + { "vx", NULL, MAVLINK_TYPE_INT16_T, 0, 44, offsetof(mavlink_hil_state_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_INT16_T, 0, 46, offsetof(mavlink_hil_state_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_INT16_T, 0, 48, offsetof(mavlink_hil_state_t, vz) }, \ + { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 50, offsetof(mavlink_hil_state_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 52, offsetof(mavlink_hil_state_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 54, offsetof(mavlink_hil_state_t, zacc) }, \ + } \ +} +#endif /** * @brief Pack a hil_state message @@ -78,56 +105,52 @@ typedef struct __mavlink_hil_state_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_state_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, int16_t xacc, int16_t yacc, int16_t zacc) + uint64_t time_usec, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, int16_t xacc, int16_t yacc, int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_STATE_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll); - _mav_put_float(buf, 12, pitch); - _mav_put_float(buf, 16, yaw); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_int32_t(buf, 32, lat); - _mav_put_int32_t(buf, 36, lon); - _mav_put_int32_t(buf, 40, alt); - _mav_put_int16_t(buf, 44, vx); - _mav_put_int16_t(buf, 46, vy); - _mav_put_int16_t(buf, 48, vz); - _mav_put_int16_t(buf, 50, xacc); - _mav_put_int16_t(buf, 52, yacc); - _mav_put_int16_t(buf, 54, zacc); + char buf[MAVLINK_MSG_ID_HIL_STATE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll); + _mav_put_float(buf, 12, pitch); + _mav_put_float(buf, 16, yaw); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); + _mav_put_int32_t(buf, 32, lat); + _mav_put_int32_t(buf, 36, lon); + _mav_put_int32_t(buf, 40, alt); + _mav_put_int16_t(buf, 44, vx); + _mav_put_int16_t(buf, 46, vy); + _mav_put_int16_t(buf, 48, vz); + _mav_put_int16_t(buf, 50, xacc); + _mav_put_int16_t(buf, 52, yacc); + _mav_put_int16_t(buf, 54, zacc); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_STATE_LEN); #else - mavlink_hil_state_t packet; - packet.time_usec = time_usec; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; + mavlink_hil_state_t packet; + packet.time_usec = time_usec; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_STATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_STATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_STATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_STATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_STATE_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); } /** @@ -155,57 +178,53 @@ static inline uint16_t mavlink_msg_hil_state_pack(uint8_t system_id, uint8_t com * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_state_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,float roll,float pitch,float yaw,float rollspeed,float pitchspeed,float yawspeed,int32_t lat,int32_t lon,int32_t alt,int16_t vx,int16_t vy,int16_t vz,int16_t xacc,int16_t yacc,int16_t zacc) + mavlink_message_t* msg, + uint64_t time_usec,float roll,float pitch,float yaw,float rollspeed,float pitchspeed,float yawspeed,int32_t lat,int32_t lon,int32_t alt,int16_t vx,int16_t vy,int16_t vz,int16_t xacc,int16_t yacc,int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_STATE_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll); - _mav_put_float(buf, 12, pitch); - _mav_put_float(buf, 16, yaw); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_int32_t(buf, 32, lat); - _mav_put_int32_t(buf, 36, lon); - _mav_put_int32_t(buf, 40, alt); - _mav_put_int16_t(buf, 44, vx); - _mav_put_int16_t(buf, 46, vy); - _mav_put_int16_t(buf, 48, vz); - _mav_put_int16_t(buf, 50, xacc); - _mav_put_int16_t(buf, 52, yacc); - _mav_put_int16_t(buf, 54, zacc); + char buf[MAVLINK_MSG_ID_HIL_STATE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll); + _mav_put_float(buf, 12, pitch); + _mav_put_float(buf, 16, yaw); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); + _mav_put_int32_t(buf, 32, lat); + _mav_put_int32_t(buf, 36, lon); + _mav_put_int32_t(buf, 40, alt); + _mav_put_int16_t(buf, 44, vx); + _mav_put_int16_t(buf, 46, vy); + _mav_put_int16_t(buf, 48, vz); + _mav_put_int16_t(buf, 50, xacc); + _mav_put_int16_t(buf, 52, yacc); + _mav_put_int16_t(buf, 54, zacc); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_STATE_LEN); #else - mavlink_hil_state_t packet; - packet.time_usec = time_usec; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; + mavlink_hil_state_t packet; + packet.time_usec = time_usec; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_STATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_STATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_STATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_STATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_STATE_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); } /** @@ -218,7 +237,7 @@ static inline uint16_t mavlink_msg_hil_state_pack_chan(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_hil_state_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_state_t* hil_state) { - return mavlink_msg_hil_state_pack(system_id, component_id, msg, hil_state->time_usec, hil_state->roll, hil_state->pitch, hil_state->yaw, hil_state->rollspeed, hil_state->pitchspeed, hil_state->yawspeed, hil_state->lat, hil_state->lon, hil_state->alt, hil_state->vx, hil_state->vy, hil_state->vz, hil_state->xacc, hil_state->yacc, hil_state->zacc); + return mavlink_msg_hil_state_pack(system_id, component_id, msg, hil_state->time_usec, hil_state->roll, hil_state->pitch, hil_state->yaw, hil_state->rollspeed, hil_state->pitchspeed, hil_state->yawspeed, hil_state->lat, hil_state->lon, hil_state->alt, hil_state->vx, hil_state->vy, hil_state->vz, hil_state->xacc, hil_state->yacc, hil_state->zacc); } /** @@ -232,7 +251,7 @@ static inline uint16_t mavlink_msg_hil_state_encode(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_hil_state_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_state_t* hil_state) { - return mavlink_msg_hil_state_pack_chan(system_id, component_id, chan, msg, hil_state->time_usec, hil_state->roll, hil_state->pitch, hil_state->yaw, hil_state->rollspeed, hil_state->pitchspeed, hil_state->yawspeed, hil_state->lat, hil_state->lon, hil_state->alt, hil_state->vx, hil_state->vy, hil_state->vz, hil_state->xacc, hil_state->yacc, hil_state->zacc); + return mavlink_msg_hil_state_pack_chan(system_id, component_id, chan, msg, hil_state->time_usec, hil_state->roll, hil_state->pitch, hil_state->yaw, hil_state->rollspeed, hil_state->pitchspeed, hil_state->yawspeed, hil_state->lat, hil_state->lon, hil_state->alt, hil_state->vx, hil_state->vy, hil_state->vz, hil_state->xacc, hil_state->yacc, hil_state->zacc); } /** @@ -261,53 +280,59 @@ static inline uint16_t mavlink_msg_hil_state_encode_chan(uint8_t system_id, uint static inline void mavlink_msg_hil_state_send(mavlink_channel_t chan, uint64_t time_usec, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, int16_t xacc, int16_t yacc, int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_STATE_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll); - _mav_put_float(buf, 12, pitch); - _mav_put_float(buf, 16, yaw); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_int32_t(buf, 32, lat); - _mav_put_int32_t(buf, 36, lon); - _mav_put_int32_t(buf, 40, alt); - _mav_put_int16_t(buf, 44, vx); - _mav_put_int16_t(buf, 46, vy); - _mav_put_int16_t(buf, 48, vz); - _mav_put_int16_t(buf, 50, xacc); - _mav_put_int16_t(buf, 52, yacc); - _mav_put_int16_t(buf, 54, zacc); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, buf, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); + char buf[MAVLINK_MSG_ID_HIL_STATE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll); + _mav_put_float(buf, 12, pitch); + _mav_put_float(buf, 16, yaw); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); + _mav_put_int32_t(buf, 32, lat); + _mav_put_int32_t(buf, 36, lon); + _mav_put_int32_t(buf, 40, alt); + _mav_put_int16_t(buf, 44, vx); + _mav_put_int16_t(buf, 46, vy); + _mav_put_int16_t(buf, 48, vz); + _mav_put_int16_t(buf, 50, xacc); + _mav_put_int16_t(buf, 52, yacc); + _mav_put_int16_t(buf, 54, zacc); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, buf, MAVLINK_MSG_ID_HIL_STATE_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, buf, MAVLINK_MSG_ID_HIL_STATE_LEN); + mavlink_hil_state_t packet; + packet.time_usec = time_usec; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, (const char *)&packet, MAVLINK_MSG_ID_HIL_STATE_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); #endif +} + +/** + * @brief Send a hil_state message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_state_send_struct(mavlink_channel_t chan, const mavlink_hil_state_t* hil_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_state_send(chan, hil_state->time_usec, hil_state->roll, hil_state->pitch, hil_state->yaw, hil_state->rollspeed, hil_state->pitchspeed, hil_state->yawspeed, hil_state->lat, hil_state->lon, hil_state->alt, hil_state->vx, hil_state->vy, hil_state->vz, hil_state->xacc, hil_state->yacc, hil_state->zacc); #else - mavlink_hil_state_t packet; - packet.time_usec = time_usec; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, (const char *)&packet, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, (const char *)&packet, MAVLINK_MSG_ID_HIL_STATE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, (const char *)hil_state, MAVLINK_MSG_ID_HIL_STATE_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); #endif } @@ -322,53 +347,45 @@ static inline void mavlink_msg_hil_state_send(mavlink_channel_t chan, uint64_t t static inline void mavlink_msg_hil_state_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float roll, float pitch, float yaw, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, int16_t xacc, int16_t yacc, int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, roll); - _mav_put_float(buf, 12, pitch); - _mav_put_float(buf, 16, yaw); - _mav_put_float(buf, 20, rollspeed); - _mav_put_float(buf, 24, pitchspeed); - _mav_put_float(buf, 28, yawspeed); - _mav_put_int32_t(buf, 32, lat); - _mav_put_int32_t(buf, 36, lon); - _mav_put_int32_t(buf, 40, alt); - _mav_put_int16_t(buf, 44, vx); - _mav_put_int16_t(buf, 46, vy); - _mav_put_int16_t(buf, 48, vz); - _mav_put_int16_t(buf, 50, xacc); - _mav_put_int16_t(buf, 52, yacc); - _mav_put_int16_t(buf, 54, zacc); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, buf, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, roll); + _mav_put_float(buf, 12, pitch); + _mav_put_float(buf, 16, yaw); + _mav_put_float(buf, 20, rollspeed); + _mav_put_float(buf, 24, pitchspeed); + _mav_put_float(buf, 28, yawspeed); + _mav_put_int32_t(buf, 32, lat); + _mav_put_int32_t(buf, 36, lon); + _mav_put_int32_t(buf, 40, alt); + _mav_put_int16_t(buf, 44, vx); + _mav_put_int16_t(buf, 46, vy); + _mav_put_int16_t(buf, 48, vz); + _mav_put_int16_t(buf, 50, xacc); + _mav_put_int16_t(buf, 52, yacc); + _mav_put_int16_t(buf, 54, zacc); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, buf, MAVLINK_MSG_ID_HIL_STATE_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, buf, MAVLINK_MSG_ID_HIL_STATE_LEN); -#endif -#else - mavlink_hil_state_t *packet = (mavlink_hil_state_t *)msgbuf; - packet->time_usec = time_usec; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->rollspeed = rollspeed; - packet->pitchspeed = pitchspeed; - packet->yawspeed = yawspeed; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, (const char *)packet, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, (const char *)packet, MAVLINK_MSG_ID_HIL_STATE_LEN); -#endif + mavlink_hil_state_t *packet = (mavlink_hil_state_t *)msgbuf; + packet->time_usec = time_usec; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->rollspeed = rollspeed; + packet->pitchspeed = pitchspeed; + packet->yawspeed = yawspeed; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE, (const char *)packet, MAVLINK_MSG_ID_HIL_STATE_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_LEN, MAVLINK_MSG_ID_HIL_STATE_CRC); #endif } #endif @@ -385,7 +402,7 @@ static inline void mavlink_msg_hil_state_send_buf(mavlink_message_t *msgbuf, mav */ static inline uint64_t mavlink_msg_hil_state_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -395,7 +412,7 @@ static inline uint64_t mavlink_msg_hil_state_get_time_usec(const mavlink_message */ static inline float mavlink_msg_hil_state_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -405,7 +422,7 @@ static inline float mavlink_msg_hil_state_get_roll(const mavlink_message_t* msg) */ static inline float mavlink_msg_hil_state_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -415,7 +432,7 @@ static inline float mavlink_msg_hil_state_get_pitch(const mavlink_message_t* msg */ static inline float mavlink_msg_hil_state_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -425,7 +442,7 @@ static inline float mavlink_msg_hil_state_get_yaw(const mavlink_message_t* msg) */ static inline float mavlink_msg_hil_state_get_rollspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -435,7 +452,7 @@ static inline float mavlink_msg_hil_state_get_rollspeed(const mavlink_message_t* */ static inline float mavlink_msg_hil_state_get_pitchspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -445,7 +462,7 @@ static inline float mavlink_msg_hil_state_get_pitchspeed(const mavlink_message_t */ static inline float mavlink_msg_hil_state_get_yawspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -455,7 +472,7 @@ static inline float mavlink_msg_hil_state_get_yawspeed(const mavlink_message_t* */ static inline int32_t mavlink_msg_hil_state_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 32); + return _MAV_RETURN_int32_t(msg, 32); } /** @@ -465,7 +482,7 @@ static inline int32_t mavlink_msg_hil_state_get_lat(const mavlink_message_t* msg */ static inline int32_t mavlink_msg_hil_state_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 36); + return _MAV_RETURN_int32_t(msg, 36); } /** @@ -475,7 +492,7 @@ static inline int32_t mavlink_msg_hil_state_get_lon(const mavlink_message_t* msg */ static inline int32_t mavlink_msg_hil_state_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 40); + return _MAV_RETURN_int32_t(msg, 40); } /** @@ -485,7 +502,7 @@ static inline int32_t mavlink_msg_hil_state_get_alt(const mavlink_message_t* msg */ static inline int16_t mavlink_msg_hil_state_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 44); + return _MAV_RETURN_int16_t(msg, 44); } /** @@ -495,7 +512,7 @@ static inline int16_t mavlink_msg_hil_state_get_vx(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_hil_state_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 46); + return _MAV_RETURN_int16_t(msg, 46); } /** @@ -505,7 +522,7 @@ static inline int16_t mavlink_msg_hil_state_get_vy(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_hil_state_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 48); + return _MAV_RETURN_int16_t(msg, 48); } /** @@ -515,7 +532,7 @@ static inline int16_t mavlink_msg_hil_state_get_vz(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_hil_state_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 50); + return _MAV_RETURN_int16_t(msg, 50); } /** @@ -525,7 +542,7 @@ static inline int16_t mavlink_msg_hil_state_get_xacc(const mavlink_message_t* ms */ static inline int16_t mavlink_msg_hil_state_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 52); + return _MAV_RETURN_int16_t(msg, 52); } /** @@ -535,7 +552,7 @@ static inline int16_t mavlink_msg_hil_state_get_yacc(const mavlink_message_t* ms */ static inline int16_t mavlink_msg_hil_state_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 54); + return _MAV_RETURN_int16_t(msg, 54); } /** @@ -546,24 +563,26 @@ static inline int16_t mavlink_msg_hil_state_get_zacc(const mavlink_message_t* ms */ static inline void mavlink_msg_hil_state_decode(const mavlink_message_t* msg, mavlink_hil_state_t* hil_state) { -#if MAVLINK_NEED_BYTE_SWAP - hil_state->time_usec = mavlink_msg_hil_state_get_time_usec(msg); - hil_state->roll = mavlink_msg_hil_state_get_roll(msg); - hil_state->pitch = mavlink_msg_hil_state_get_pitch(msg); - hil_state->yaw = mavlink_msg_hil_state_get_yaw(msg); - hil_state->rollspeed = mavlink_msg_hil_state_get_rollspeed(msg); - hil_state->pitchspeed = mavlink_msg_hil_state_get_pitchspeed(msg); - hil_state->yawspeed = mavlink_msg_hil_state_get_yawspeed(msg); - hil_state->lat = mavlink_msg_hil_state_get_lat(msg); - hil_state->lon = mavlink_msg_hil_state_get_lon(msg); - hil_state->alt = mavlink_msg_hil_state_get_alt(msg); - hil_state->vx = mavlink_msg_hil_state_get_vx(msg); - hil_state->vy = mavlink_msg_hil_state_get_vy(msg); - hil_state->vz = mavlink_msg_hil_state_get_vz(msg); - hil_state->xacc = mavlink_msg_hil_state_get_xacc(msg); - hil_state->yacc = mavlink_msg_hil_state_get_yacc(msg); - hil_state->zacc = mavlink_msg_hil_state_get_zacc(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_state->time_usec = mavlink_msg_hil_state_get_time_usec(msg); + hil_state->roll = mavlink_msg_hil_state_get_roll(msg); + hil_state->pitch = mavlink_msg_hil_state_get_pitch(msg); + hil_state->yaw = mavlink_msg_hil_state_get_yaw(msg); + hil_state->rollspeed = mavlink_msg_hil_state_get_rollspeed(msg); + hil_state->pitchspeed = mavlink_msg_hil_state_get_pitchspeed(msg); + hil_state->yawspeed = mavlink_msg_hil_state_get_yawspeed(msg); + hil_state->lat = mavlink_msg_hil_state_get_lat(msg); + hil_state->lon = mavlink_msg_hil_state_get_lon(msg); + hil_state->alt = mavlink_msg_hil_state_get_alt(msg); + hil_state->vx = mavlink_msg_hil_state_get_vx(msg); + hil_state->vy = mavlink_msg_hil_state_get_vy(msg); + hil_state->vz = mavlink_msg_hil_state_get_vz(msg); + hil_state->xacc = mavlink_msg_hil_state_get_xacc(msg); + hil_state->yacc = mavlink_msg_hil_state_get_yacc(msg); + hil_state->zacc = mavlink_msg_hil_state_get_zacc(msg); #else - memcpy(hil_state, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIL_STATE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_STATE_LEN? msg->len : MAVLINK_MSG_ID_HIL_STATE_LEN; + memset(hil_state, 0, MAVLINK_MSG_ID_HIL_STATE_LEN); + memcpy(hil_state, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_hil_state_quaternion.h b/vendor/libraries/mavlink/common/mavlink_msg_hil_state_quaternion.h index 344a19e183..3ad80714a9 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_hil_state_quaternion.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_hil_state_quaternion.h @@ -1,39 +1,44 @@ +#pragma once // MESSAGE HIL_STATE_QUATERNION PACKING #define MAVLINK_MSG_ID_HIL_STATE_QUATERNION 115 -typedef struct __mavlink_hil_state_quaternion_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - float attitude_quaternion[4]; ///< Vehicle attitude expressed as normalized quaternion in w, x, y, z order (with 1 0 0 0 being the null-rotation) - float rollspeed; ///< Body frame roll / phi angular speed (rad/s) - float pitchspeed; ///< Body frame pitch / theta angular speed (rad/s) - float yawspeed; ///< Body frame yaw / psi angular speed (rad/s) - int32_t lat; ///< Latitude, expressed as * 1E7 - int32_t lon; ///< Longitude, expressed as * 1E7 - int32_t alt; ///< Altitude in meters, expressed as * 1000 (millimeters) - int16_t vx; ///< Ground X Speed (Latitude), expressed as m/s * 100 - int16_t vy; ///< Ground Y Speed (Longitude), expressed as m/s * 100 - int16_t vz; ///< Ground Z Speed (Altitude), expressed as m/s * 100 - uint16_t ind_airspeed; ///< Indicated airspeed, expressed as m/s * 100 - uint16_t true_airspeed; ///< True airspeed, expressed as m/s * 100 - int16_t xacc; ///< X acceleration (mg) - int16_t yacc; ///< Y acceleration (mg) - int16_t zacc; ///< Z acceleration (mg) -} mavlink_hil_state_quaternion_t; +MAVPACKED( +typedef struct __mavlink_hil_state_quaternion_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + float attitude_quaternion[4]; /*< Vehicle attitude expressed as normalized quaternion in w, x, y, z order (with 1 0 0 0 being the null-rotation)*/ + float rollspeed; /*< Body frame roll / phi angular speed (rad/s)*/ + float pitchspeed; /*< Body frame pitch / theta angular speed (rad/s)*/ + float yawspeed; /*< Body frame yaw / psi angular speed (rad/s)*/ + int32_t lat; /*< Latitude, expressed as * 1E7*/ + int32_t lon; /*< Longitude, expressed as * 1E7*/ + int32_t alt; /*< Altitude in meters, expressed as * 1000 (millimeters)*/ + int16_t vx; /*< Ground X Speed (Latitude), expressed as cm/s*/ + int16_t vy; /*< Ground Y Speed (Longitude), expressed as cm/s*/ + int16_t vz; /*< Ground Z Speed (Altitude), expressed as cm/s*/ + uint16_t ind_airspeed; /*< Indicated airspeed, expressed as cm/s*/ + uint16_t true_airspeed; /*< True airspeed, expressed as cm/s*/ + int16_t xacc; /*< X acceleration (mg)*/ + int16_t yacc; /*< Y acceleration (mg)*/ + int16_t zacc; /*< Z acceleration (mg)*/ +}) mavlink_hil_state_quaternion_t; #define MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN 64 +#define MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN 64 #define MAVLINK_MSG_ID_115_LEN 64 +#define MAVLINK_MSG_ID_115_MIN_LEN 64 #define MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC 4 #define MAVLINK_MSG_ID_115_CRC 4 #define MAVLINK_MSG_HIL_STATE_QUATERNION_FIELD_ATTITUDE_QUATERNION_LEN 4 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION { \ - "HIL_STATE_QUATERNION", \ - 16, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_state_quaternion_t, time_usec) }, \ + 115, \ + "HIL_STATE_QUATERNION", \ + 16, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_state_quaternion_t, time_usec) }, \ { "attitude_quaternion", NULL, MAVLINK_TYPE_FLOAT, 4, 8, offsetof(mavlink_hil_state_quaternion_t, attitude_quaternion) }, \ { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_hil_state_quaternion_t, rollspeed) }, \ { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_hil_state_quaternion_t, pitchspeed) }, \ @@ -51,7 +56,29 @@ typedef struct __mavlink_hil_state_quaternion_t { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 62, offsetof(mavlink_hil_state_quaternion_t, zacc) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_HIL_STATE_QUATERNION { \ + "HIL_STATE_QUATERNION", \ + 16, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_hil_state_quaternion_t, time_usec) }, \ + { "attitude_quaternion", NULL, MAVLINK_TYPE_FLOAT, 4, 8, offsetof(mavlink_hil_state_quaternion_t, attitude_quaternion) }, \ + { "rollspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_hil_state_quaternion_t, rollspeed) }, \ + { "pitchspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_hil_state_quaternion_t, pitchspeed) }, \ + { "yawspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_hil_state_quaternion_t, yawspeed) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 36, offsetof(mavlink_hil_state_quaternion_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 40, offsetof(mavlink_hil_state_quaternion_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_INT32_T, 0, 44, offsetof(mavlink_hil_state_quaternion_t, alt) }, \ + { "vx", NULL, MAVLINK_TYPE_INT16_T, 0, 48, offsetof(mavlink_hil_state_quaternion_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_INT16_T, 0, 50, offsetof(mavlink_hil_state_quaternion_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_INT16_T, 0, 52, offsetof(mavlink_hil_state_quaternion_t, vz) }, \ + { "ind_airspeed", NULL, MAVLINK_TYPE_UINT16_T, 0, 54, offsetof(mavlink_hil_state_quaternion_t, ind_airspeed) }, \ + { "true_airspeed", NULL, MAVLINK_TYPE_UINT16_T, 0, 56, offsetof(mavlink_hil_state_quaternion_t, true_airspeed) }, \ + { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 58, offsetof(mavlink_hil_state_quaternion_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 60, offsetof(mavlink_hil_state_quaternion_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 62, offsetof(mavlink_hil_state_quaternion_t, zacc) }, \ + } \ +} +#endif /** * @brief Pack a hil_state_quaternion message @@ -67,65 +94,61 @@ typedef struct __mavlink_hil_state_quaternion_t * @param lat Latitude, expressed as * 1E7 * @param lon Longitude, expressed as * 1E7 * @param alt Altitude in meters, expressed as * 1000 (millimeters) - * @param vx Ground X Speed (Latitude), expressed as m/s * 100 - * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 - * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param ind_airspeed Indicated airspeed, expressed as m/s * 100 - * @param true_airspeed True airspeed, expressed as m/s * 100 + * @param vx Ground X Speed (Latitude), expressed as cm/s + * @param vy Ground Y Speed (Longitude), expressed as cm/s + * @param vz Ground Z Speed (Altitude), expressed as cm/s + * @param ind_airspeed Indicated airspeed, expressed as cm/s + * @param true_airspeed True airspeed, expressed as cm/s * @param xacc X acceleration (mg) * @param yacc Y acceleration (mg) * @param zacc Z acceleration (mg) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_state_quaternion_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, const float *attitude_quaternion, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, uint16_t ind_airspeed, uint16_t true_airspeed, int16_t xacc, int16_t yacc, int16_t zacc) + uint64_t time_usec, const float *attitude_quaternion, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, uint16_t ind_airspeed, uint16_t true_airspeed, int16_t xacc, int16_t yacc, int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, rollspeed); - _mav_put_float(buf, 28, pitchspeed); - _mav_put_float(buf, 32, yawspeed); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lon); - _mav_put_int32_t(buf, 44, alt); - _mav_put_int16_t(buf, 48, vx); - _mav_put_int16_t(buf, 50, vy); - _mav_put_int16_t(buf, 52, vz); - _mav_put_uint16_t(buf, 54, ind_airspeed); - _mav_put_uint16_t(buf, 56, true_airspeed); - _mav_put_int16_t(buf, 58, xacc); - _mav_put_int16_t(buf, 60, yacc); - _mav_put_int16_t(buf, 62, zacc); - _mav_put_float_array(buf, 8, attitude_quaternion, 4); + char buf[MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lon); + _mav_put_int32_t(buf, 44, alt); + _mav_put_int16_t(buf, 48, vx); + _mav_put_int16_t(buf, 50, vy); + _mav_put_int16_t(buf, 52, vz); + _mav_put_uint16_t(buf, 54, ind_airspeed); + _mav_put_uint16_t(buf, 56, true_airspeed); + _mav_put_int16_t(buf, 58, xacc); + _mav_put_int16_t(buf, 60, yacc); + _mav_put_int16_t(buf, 62, zacc); + _mav_put_float_array(buf, 8, attitude_quaternion, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); #else - mavlink_hil_state_quaternion_t packet; - packet.time_usec = time_usec; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.ind_airspeed = ind_airspeed; - packet.true_airspeed = true_airspeed; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - mav_array_memcpy(packet.attitude_quaternion, attitude_quaternion, sizeof(float)*4); + mavlink_hil_state_quaternion_t packet; + packet.time_usec = time_usec; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.ind_airspeed = ind_airspeed; + packet.true_airspeed = true_airspeed; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + mav_array_memcpy(packet.attitude_quaternion, attitude_quaternion, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_STATE_QUATERNION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_STATE_QUATERNION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); } /** @@ -142,66 +165,62 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_pack(uint8_t system_id, * @param lat Latitude, expressed as * 1E7 * @param lon Longitude, expressed as * 1E7 * @param alt Altitude in meters, expressed as * 1000 (millimeters) - * @param vx Ground X Speed (Latitude), expressed as m/s * 100 - * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 - * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param ind_airspeed Indicated airspeed, expressed as m/s * 100 - * @param true_airspeed True airspeed, expressed as m/s * 100 + * @param vx Ground X Speed (Latitude), expressed as cm/s + * @param vy Ground Y Speed (Longitude), expressed as cm/s + * @param vz Ground Z Speed (Altitude), expressed as cm/s + * @param ind_airspeed Indicated airspeed, expressed as cm/s + * @param true_airspeed True airspeed, expressed as cm/s * @param xacc X acceleration (mg) * @param yacc Y acceleration (mg) * @param zacc Z acceleration (mg) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_hil_state_quaternion_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,const float *attitude_quaternion,float rollspeed,float pitchspeed,float yawspeed,int32_t lat,int32_t lon,int32_t alt,int16_t vx,int16_t vy,int16_t vz,uint16_t ind_airspeed,uint16_t true_airspeed,int16_t xacc,int16_t yacc,int16_t zacc) + mavlink_message_t* msg, + uint64_t time_usec,const float *attitude_quaternion,float rollspeed,float pitchspeed,float yawspeed,int32_t lat,int32_t lon,int32_t alt,int16_t vx,int16_t vy,int16_t vz,uint16_t ind_airspeed,uint16_t true_airspeed,int16_t xacc,int16_t yacc,int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, rollspeed); - _mav_put_float(buf, 28, pitchspeed); - _mav_put_float(buf, 32, yawspeed); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lon); - _mav_put_int32_t(buf, 44, alt); - _mav_put_int16_t(buf, 48, vx); - _mav_put_int16_t(buf, 50, vy); - _mav_put_int16_t(buf, 52, vz); - _mav_put_uint16_t(buf, 54, ind_airspeed); - _mav_put_uint16_t(buf, 56, true_airspeed); - _mav_put_int16_t(buf, 58, xacc); - _mav_put_int16_t(buf, 60, yacc); - _mav_put_int16_t(buf, 62, zacc); - _mav_put_float_array(buf, 8, attitude_quaternion, 4); + char buf[MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lon); + _mav_put_int32_t(buf, 44, alt); + _mav_put_int16_t(buf, 48, vx); + _mav_put_int16_t(buf, 50, vy); + _mav_put_int16_t(buf, 52, vz); + _mav_put_uint16_t(buf, 54, ind_airspeed); + _mav_put_uint16_t(buf, 56, true_airspeed); + _mav_put_int16_t(buf, 58, xacc); + _mav_put_int16_t(buf, 60, yacc); + _mav_put_int16_t(buf, 62, zacc); + _mav_put_float_array(buf, 8, attitude_quaternion, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); #else - mavlink_hil_state_quaternion_t packet; - packet.time_usec = time_usec; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.ind_airspeed = ind_airspeed; - packet.true_airspeed = true_airspeed; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - mav_array_memcpy(packet.attitude_quaternion, attitude_quaternion, sizeof(float)*4); + mavlink_hil_state_quaternion_t packet; + packet.time_usec = time_usec; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.ind_airspeed = ind_airspeed; + packet.true_airspeed = true_airspeed; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + mav_array_memcpy(packet.attitude_quaternion, attitude_quaternion, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_HIL_STATE_QUATERNION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_HIL_STATE_QUATERNION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); } /** @@ -214,7 +233,7 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_pack_chan(uint8_t system */ static inline uint16_t mavlink_msg_hil_state_quaternion_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_hil_state_quaternion_t* hil_state_quaternion) { - return mavlink_msg_hil_state_quaternion_pack(system_id, component_id, msg, hil_state_quaternion->time_usec, hil_state_quaternion->attitude_quaternion, hil_state_quaternion->rollspeed, hil_state_quaternion->pitchspeed, hil_state_quaternion->yawspeed, hil_state_quaternion->lat, hil_state_quaternion->lon, hil_state_quaternion->alt, hil_state_quaternion->vx, hil_state_quaternion->vy, hil_state_quaternion->vz, hil_state_quaternion->ind_airspeed, hil_state_quaternion->true_airspeed, hil_state_quaternion->xacc, hil_state_quaternion->yacc, hil_state_quaternion->zacc); + return mavlink_msg_hil_state_quaternion_pack(system_id, component_id, msg, hil_state_quaternion->time_usec, hil_state_quaternion->attitude_quaternion, hil_state_quaternion->rollspeed, hil_state_quaternion->pitchspeed, hil_state_quaternion->yawspeed, hil_state_quaternion->lat, hil_state_quaternion->lon, hil_state_quaternion->alt, hil_state_quaternion->vx, hil_state_quaternion->vy, hil_state_quaternion->vz, hil_state_quaternion->ind_airspeed, hil_state_quaternion->true_airspeed, hil_state_quaternion->xacc, hil_state_quaternion->yacc, hil_state_quaternion->zacc); } /** @@ -228,7 +247,7 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_encode(uint8_t system_id */ static inline uint16_t mavlink_msg_hil_state_quaternion_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_hil_state_quaternion_t* hil_state_quaternion) { - return mavlink_msg_hil_state_quaternion_pack_chan(system_id, component_id, chan, msg, hil_state_quaternion->time_usec, hil_state_quaternion->attitude_quaternion, hil_state_quaternion->rollspeed, hil_state_quaternion->pitchspeed, hil_state_quaternion->yawspeed, hil_state_quaternion->lat, hil_state_quaternion->lon, hil_state_quaternion->alt, hil_state_quaternion->vx, hil_state_quaternion->vy, hil_state_quaternion->vz, hil_state_quaternion->ind_airspeed, hil_state_quaternion->true_airspeed, hil_state_quaternion->xacc, hil_state_quaternion->yacc, hil_state_quaternion->zacc); + return mavlink_msg_hil_state_quaternion_pack_chan(system_id, component_id, chan, msg, hil_state_quaternion->time_usec, hil_state_quaternion->attitude_quaternion, hil_state_quaternion->rollspeed, hil_state_quaternion->pitchspeed, hil_state_quaternion->yawspeed, hil_state_quaternion->lat, hil_state_quaternion->lon, hil_state_quaternion->alt, hil_state_quaternion->vx, hil_state_quaternion->vy, hil_state_quaternion->vz, hil_state_quaternion->ind_airspeed, hil_state_quaternion->true_airspeed, hil_state_quaternion->xacc, hil_state_quaternion->yacc, hil_state_quaternion->zacc); } /** @@ -243,11 +262,11 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_encode_chan(uint8_t syst * @param lat Latitude, expressed as * 1E7 * @param lon Longitude, expressed as * 1E7 * @param alt Altitude in meters, expressed as * 1000 (millimeters) - * @param vx Ground X Speed (Latitude), expressed as m/s * 100 - * @param vy Ground Y Speed (Longitude), expressed as m/s * 100 - * @param vz Ground Z Speed (Altitude), expressed as m/s * 100 - * @param ind_airspeed Indicated airspeed, expressed as m/s * 100 - * @param true_airspeed True airspeed, expressed as m/s * 100 + * @param vx Ground X Speed (Latitude), expressed as cm/s + * @param vy Ground Y Speed (Longitude), expressed as cm/s + * @param vz Ground Z Speed (Altitude), expressed as cm/s + * @param ind_airspeed Indicated airspeed, expressed as cm/s + * @param true_airspeed True airspeed, expressed as cm/s * @param xacc X acceleration (mg) * @param yacc Y acceleration (mg) * @param zacc Z acceleration (mg) @@ -257,51 +276,57 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_encode_chan(uint8_t syst static inline void mavlink_msg_hil_state_quaternion_send(mavlink_channel_t chan, uint64_t time_usec, const float *attitude_quaternion, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, uint16_t ind_airspeed, uint16_t true_airspeed, int16_t xacc, int16_t yacc, int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, rollspeed); - _mav_put_float(buf, 28, pitchspeed); - _mav_put_float(buf, 32, yawspeed); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lon); - _mav_put_int32_t(buf, 44, alt); - _mav_put_int16_t(buf, 48, vx); - _mav_put_int16_t(buf, 50, vy); - _mav_put_int16_t(buf, 52, vz); - _mav_put_uint16_t(buf, 54, ind_airspeed); - _mav_put_uint16_t(buf, 56, true_airspeed); - _mav_put_int16_t(buf, 58, xacc); - _mav_put_int16_t(buf, 60, yacc); - _mav_put_int16_t(buf, 62, zacc); - _mav_put_float_array(buf, 8, attitude_quaternion, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); + char buf[MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lon); + _mav_put_int32_t(buf, 44, alt); + _mav_put_int16_t(buf, 48, vx); + _mav_put_int16_t(buf, 50, vy); + _mav_put_int16_t(buf, 52, vz); + _mav_put_uint16_t(buf, 54, ind_airspeed); + _mav_put_uint16_t(buf, 56, true_airspeed); + _mav_put_int16_t(buf, 58, xacc); + _mav_put_int16_t(buf, 60, yacc); + _mav_put_int16_t(buf, 62, zacc); + _mav_put_float_array(buf, 8, attitude_quaternion, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); + mavlink_hil_state_quaternion_t packet; + packet.time_usec = time_usec; + packet.rollspeed = rollspeed; + packet.pitchspeed = pitchspeed; + packet.yawspeed = yawspeed; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.ind_airspeed = ind_airspeed; + packet.true_airspeed = true_airspeed; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + mav_array_memcpy(packet.attitude_quaternion, attitude_quaternion, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, (const char *)&packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); #endif +} + +/** + * @brief Send a hil_state_quaternion message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_hil_state_quaternion_send_struct(mavlink_channel_t chan, const mavlink_hil_state_quaternion_t* hil_state_quaternion) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_hil_state_quaternion_send(chan, hil_state_quaternion->time_usec, hil_state_quaternion->attitude_quaternion, hil_state_quaternion->rollspeed, hil_state_quaternion->pitchspeed, hil_state_quaternion->yawspeed, hil_state_quaternion->lat, hil_state_quaternion->lon, hil_state_quaternion->alt, hil_state_quaternion->vx, hil_state_quaternion->vy, hil_state_quaternion->vz, hil_state_quaternion->ind_airspeed, hil_state_quaternion->true_airspeed, hil_state_quaternion->xacc, hil_state_quaternion->yacc, hil_state_quaternion->zacc); #else - mavlink_hil_state_quaternion_t packet; - packet.time_usec = time_usec; - packet.rollspeed = rollspeed; - packet.pitchspeed = pitchspeed; - packet.yawspeed = yawspeed; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.ind_airspeed = ind_airspeed; - packet.true_airspeed = true_airspeed; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - mav_array_memcpy(packet.attitude_quaternion, attitude_quaternion, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, (const char *)&packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, (const char *)&packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, (const char *)hil_state_quaternion, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); #endif } @@ -316,51 +341,43 @@ static inline void mavlink_msg_hil_state_quaternion_send(mavlink_channel_t chan, static inline void mavlink_msg_hil_state_quaternion_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, const float *attitude_quaternion, float rollspeed, float pitchspeed, float yawspeed, int32_t lat, int32_t lon, int32_t alt, int16_t vx, int16_t vy, int16_t vz, uint16_t ind_airspeed, uint16_t true_airspeed, int16_t xacc, int16_t yacc, int16_t zacc) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 24, rollspeed); - _mav_put_float(buf, 28, pitchspeed); - _mav_put_float(buf, 32, yawspeed); - _mav_put_int32_t(buf, 36, lat); - _mav_put_int32_t(buf, 40, lon); - _mav_put_int32_t(buf, 44, alt); - _mav_put_int16_t(buf, 48, vx); - _mav_put_int16_t(buf, 50, vy); - _mav_put_int16_t(buf, 52, vz); - _mav_put_uint16_t(buf, 54, ind_airspeed); - _mav_put_uint16_t(buf, 56, true_airspeed); - _mav_put_int16_t(buf, 58, xacc); - _mav_put_int16_t(buf, 60, yacc); - _mav_put_int16_t(buf, 62, zacc); - _mav_put_float_array(buf, 8, attitude_quaternion, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 24, rollspeed); + _mav_put_float(buf, 28, pitchspeed); + _mav_put_float(buf, 32, yawspeed); + _mav_put_int32_t(buf, 36, lat); + _mav_put_int32_t(buf, 40, lon); + _mav_put_int32_t(buf, 44, alt); + _mav_put_int16_t(buf, 48, vx); + _mav_put_int16_t(buf, 50, vy); + _mav_put_int16_t(buf, 52, vz); + _mav_put_uint16_t(buf, 54, ind_airspeed); + _mav_put_uint16_t(buf, 56, true_airspeed); + _mav_put_int16_t(buf, 58, xacc); + _mav_put_int16_t(buf, 60, yacc); + _mav_put_int16_t(buf, 62, zacc); + _mav_put_float_array(buf, 8, attitude_quaternion, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, buf, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); -#endif -#else - mavlink_hil_state_quaternion_t *packet = (mavlink_hil_state_quaternion_t *)msgbuf; - packet->time_usec = time_usec; - packet->rollspeed = rollspeed; - packet->pitchspeed = pitchspeed; - packet->yawspeed = yawspeed; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->ind_airspeed = ind_airspeed; - packet->true_airspeed = true_airspeed; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - mav_array_memcpy(packet->attitude_quaternion, attitude_quaternion, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, (const char *)packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, (const char *)packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); -#endif + mavlink_hil_state_quaternion_t *packet = (mavlink_hil_state_quaternion_t *)msgbuf; + packet->time_usec = time_usec; + packet->rollspeed = rollspeed; + packet->pitchspeed = pitchspeed; + packet->yawspeed = yawspeed; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->ind_airspeed = ind_airspeed; + packet->true_airspeed = true_airspeed; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + mav_array_memcpy(packet->attitude_quaternion, attitude_quaternion, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HIL_STATE_QUATERNION, (const char *)packet, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_CRC); #endif } #endif @@ -377,7 +394,7 @@ static inline void mavlink_msg_hil_state_quaternion_send_buf(mavlink_message_t * */ static inline uint64_t mavlink_msg_hil_state_quaternion_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -387,7 +404,7 @@ static inline uint64_t mavlink_msg_hil_state_quaternion_get_time_usec(const mavl */ static inline uint16_t mavlink_msg_hil_state_quaternion_get_attitude_quaternion(const mavlink_message_t* msg, float *attitude_quaternion) { - return _MAV_RETURN_float_array(msg, attitude_quaternion, 4, 8); + return _MAV_RETURN_float_array(msg, attitude_quaternion, 4, 8); } /** @@ -397,7 +414,7 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_get_attitude_quaternion( */ static inline float mavlink_msg_hil_state_quaternion_get_rollspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -407,7 +424,7 @@ static inline float mavlink_msg_hil_state_quaternion_get_rollspeed(const mavlink */ static inline float mavlink_msg_hil_state_quaternion_get_pitchspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -417,7 +434,7 @@ static inline float mavlink_msg_hil_state_quaternion_get_pitchspeed(const mavlin */ static inline float mavlink_msg_hil_state_quaternion_get_yawspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -427,7 +444,7 @@ static inline float mavlink_msg_hil_state_quaternion_get_yawspeed(const mavlink_ */ static inline int32_t mavlink_msg_hil_state_quaternion_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 36); + return _MAV_RETURN_int32_t(msg, 36); } /** @@ -437,7 +454,7 @@ static inline int32_t mavlink_msg_hil_state_quaternion_get_lat(const mavlink_mes */ static inline int32_t mavlink_msg_hil_state_quaternion_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 40); + return _MAV_RETURN_int32_t(msg, 40); } /** @@ -447,57 +464,57 @@ static inline int32_t mavlink_msg_hil_state_quaternion_get_lon(const mavlink_mes */ static inline int32_t mavlink_msg_hil_state_quaternion_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 44); + return _MAV_RETURN_int32_t(msg, 44); } /** * @brief Get field vx from hil_state_quaternion message * - * @return Ground X Speed (Latitude), expressed as m/s * 100 + * @return Ground X Speed (Latitude), expressed as cm/s */ static inline int16_t mavlink_msg_hil_state_quaternion_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 48); + return _MAV_RETURN_int16_t(msg, 48); } /** * @brief Get field vy from hil_state_quaternion message * - * @return Ground Y Speed (Longitude), expressed as m/s * 100 + * @return Ground Y Speed (Longitude), expressed as cm/s */ static inline int16_t mavlink_msg_hil_state_quaternion_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 50); + return _MAV_RETURN_int16_t(msg, 50); } /** * @brief Get field vz from hil_state_quaternion message * - * @return Ground Z Speed (Altitude), expressed as m/s * 100 + * @return Ground Z Speed (Altitude), expressed as cm/s */ static inline int16_t mavlink_msg_hil_state_quaternion_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 52); + return _MAV_RETURN_int16_t(msg, 52); } /** * @brief Get field ind_airspeed from hil_state_quaternion message * - * @return Indicated airspeed, expressed as m/s * 100 + * @return Indicated airspeed, expressed as cm/s */ static inline uint16_t mavlink_msg_hil_state_quaternion_get_ind_airspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 54); + return _MAV_RETURN_uint16_t(msg, 54); } /** * @brief Get field true_airspeed from hil_state_quaternion message * - * @return True airspeed, expressed as m/s * 100 + * @return True airspeed, expressed as cm/s */ static inline uint16_t mavlink_msg_hil_state_quaternion_get_true_airspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 56); + return _MAV_RETURN_uint16_t(msg, 56); } /** @@ -507,7 +524,7 @@ static inline uint16_t mavlink_msg_hil_state_quaternion_get_true_airspeed(const */ static inline int16_t mavlink_msg_hil_state_quaternion_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 58); + return _MAV_RETURN_int16_t(msg, 58); } /** @@ -517,7 +534,7 @@ static inline int16_t mavlink_msg_hil_state_quaternion_get_xacc(const mavlink_me */ static inline int16_t mavlink_msg_hil_state_quaternion_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 60); + return _MAV_RETURN_int16_t(msg, 60); } /** @@ -527,7 +544,7 @@ static inline int16_t mavlink_msg_hil_state_quaternion_get_yacc(const mavlink_me */ static inline int16_t mavlink_msg_hil_state_quaternion_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 62); + return _MAV_RETURN_int16_t(msg, 62); } /** @@ -538,24 +555,26 @@ static inline int16_t mavlink_msg_hil_state_quaternion_get_zacc(const mavlink_me */ static inline void mavlink_msg_hil_state_quaternion_decode(const mavlink_message_t* msg, mavlink_hil_state_quaternion_t* hil_state_quaternion) { -#if MAVLINK_NEED_BYTE_SWAP - hil_state_quaternion->time_usec = mavlink_msg_hil_state_quaternion_get_time_usec(msg); - mavlink_msg_hil_state_quaternion_get_attitude_quaternion(msg, hil_state_quaternion->attitude_quaternion); - hil_state_quaternion->rollspeed = mavlink_msg_hil_state_quaternion_get_rollspeed(msg); - hil_state_quaternion->pitchspeed = mavlink_msg_hil_state_quaternion_get_pitchspeed(msg); - hil_state_quaternion->yawspeed = mavlink_msg_hil_state_quaternion_get_yawspeed(msg); - hil_state_quaternion->lat = mavlink_msg_hil_state_quaternion_get_lat(msg); - hil_state_quaternion->lon = mavlink_msg_hil_state_quaternion_get_lon(msg); - hil_state_quaternion->alt = mavlink_msg_hil_state_quaternion_get_alt(msg); - hil_state_quaternion->vx = mavlink_msg_hil_state_quaternion_get_vx(msg); - hil_state_quaternion->vy = mavlink_msg_hil_state_quaternion_get_vy(msg); - hil_state_quaternion->vz = mavlink_msg_hil_state_quaternion_get_vz(msg); - hil_state_quaternion->ind_airspeed = mavlink_msg_hil_state_quaternion_get_ind_airspeed(msg); - hil_state_quaternion->true_airspeed = mavlink_msg_hil_state_quaternion_get_true_airspeed(msg); - hil_state_quaternion->xacc = mavlink_msg_hil_state_quaternion_get_xacc(msg); - hil_state_quaternion->yacc = mavlink_msg_hil_state_quaternion_get_yacc(msg); - hil_state_quaternion->zacc = mavlink_msg_hil_state_quaternion_get_zacc(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + hil_state_quaternion->time_usec = mavlink_msg_hil_state_quaternion_get_time_usec(msg); + mavlink_msg_hil_state_quaternion_get_attitude_quaternion(msg, hil_state_quaternion->attitude_quaternion); + hil_state_quaternion->rollspeed = mavlink_msg_hil_state_quaternion_get_rollspeed(msg); + hil_state_quaternion->pitchspeed = mavlink_msg_hil_state_quaternion_get_pitchspeed(msg); + hil_state_quaternion->yawspeed = mavlink_msg_hil_state_quaternion_get_yawspeed(msg); + hil_state_quaternion->lat = mavlink_msg_hil_state_quaternion_get_lat(msg); + hil_state_quaternion->lon = mavlink_msg_hil_state_quaternion_get_lon(msg); + hil_state_quaternion->alt = mavlink_msg_hil_state_quaternion_get_alt(msg); + hil_state_quaternion->vx = mavlink_msg_hil_state_quaternion_get_vx(msg); + hil_state_quaternion->vy = mavlink_msg_hil_state_quaternion_get_vy(msg); + hil_state_quaternion->vz = mavlink_msg_hil_state_quaternion_get_vz(msg); + hil_state_quaternion->ind_airspeed = mavlink_msg_hil_state_quaternion_get_ind_airspeed(msg); + hil_state_quaternion->true_airspeed = mavlink_msg_hil_state_quaternion_get_true_airspeed(msg); + hil_state_quaternion->xacc = mavlink_msg_hil_state_quaternion_get_xacc(msg); + hil_state_quaternion->yacc = mavlink_msg_hil_state_quaternion_get_yacc(msg); + hil_state_quaternion->zacc = mavlink_msg_hil_state_quaternion_get_zacc(msg); #else - memcpy(hil_state_quaternion, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN? msg->len : MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN; + memset(hil_state_quaternion, 0, MAVLINK_MSG_ID_HIL_STATE_QUATERNION_LEN); + memcpy(hil_state_quaternion, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_home_position.h b/vendor/libraries/mavlink/common/mavlink_msg_home_position.h new file mode 100644 index 0000000000..d5ac5e5fa6 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_home_position.h @@ -0,0 +1,430 @@ +#pragma once +// MESSAGE HOME_POSITION PACKING + +#define MAVLINK_MSG_ID_HOME_POSITION 242 + +MAVPACKED( +typedef struct __mavlink_home_position_t { + int32_t latitude; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t longitude; /*< Longitude (WGS84, in degrees * 1E7*/ + int32_t altitude; /*< Altitude (AMSL), in meters * 1000 (positive for up)*/ + float x; /*< Local X position of this position in the local coordinate frame*/ + float y; /*< Local Y position of this position in the local coordinate frame*/ + float z; /*< Local Z position of this position in the local coordinate frame*/ + float q[4]; /*< World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground*/ + float approach_x; /*< Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone.*/ + float approach_y; /*< Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone.*/ + float approach_z; /*< Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone.*/ +}) mavlink_home_position_t; + +#define MAVLINK_MSG_ID_HOME_POSITION_LEN 52 +#define MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN 52 +#define MAVLINK_MSG_ID_242_LEN 52 +#define MAVLINK_MSG_ID_242_MIN_LEN 52 + +#define MAVLINK_MSG_ID_HOME_POSITION_CRC 104 +#define MAVLINK_MSG_ID_242_CRC 104 + +#define MAVLINK_MSG_HOME_POSITION_FIELD_Q_LEN 4 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_HOME_POSITION { \ + 242, \ + "HOME_POSITION", \ + 10, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_home_position_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_home_position_t, longitude) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_home_position_t, altitude) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_home_position_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_home_position_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_home_position_t, z) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 24, offsetof(mavlink_home_position_t, q) }, \ + { "approach_x", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_home_position_t, approach_x) }, \ + { "approach_y", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_home_position_t, approach_y) }, \ + { "approach_z", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_home_position_t, approach_z) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_HOME_POSITION { \ + "HOME_POSITION", \ + 10, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_home_position_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_home_position_t, longitude) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_home_position_t, altitude) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_home_position_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_home_position_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_home_position_t, z) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 24, offsetof(mavlink_home_position_t, q) }, \ + { "approach_x", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_home_position_t, approach_x) }, \ + { "approach_y", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_home_position_t, approach_y) }, \ + { "approach_z", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_home_position_t, approach_z) }, \ + } \ +} +#endif + +/** + * @brief Pack a home_position message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param latitude Latitude (WGS84), in degrees * 1E7 + * @param longitude Longitude (WGS84, in degrees * 1E7 + * @param altitude Altitude (AMSL), in meters * 1000 (positive for up) + * @param x Local X position of this position in the local coordinate frame + * @param y Local Y position of this position in the local coordinate frame + * @param z Local Z position of this position in the local coordinate frame + * @param q World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + * @param approach_x Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_y Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_z Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_home_position_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + int32_t latitude, int32_t longitude, int32_t altitude, float x, float y, float z, const float *q, float approach_x, float approach_y, float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HOME_POSITION_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_float_array(buf, 24, q, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HOME_POSITION_LEN); +#else + mavlink_home_position_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.x = x; + packet.y = y; + packet.z = z; + packet.approach_x = approach_x; + packet.approach_y = approach_y; + packet.approach_z = approach_z; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HOME_POSITION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_HOME_POSITION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_HOME_POSITION_LEN, MAVLINK_MSG_ID_HOME_POSITION_CRC); +} + +/** + * @brief Pack a home_position message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param latitude Latitude (WGS84), in degrees * 1E7 + * @param longitude Longitude (WGS84, in degrees * 1E7 + * @param altitude Altitude (AMSL), in meters * 1000 (positive for up) + * @param x Local X position of this position in the local coordinate frame + * @param y Local Y position of this position in the local coordinate frame + * @param z Local Z position of this position in the local coordinate frame + * @param q World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + * @param approach_x Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_y Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_z Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_home_position_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + int32_t latitude,int32_t longitude,int32_t altitude,float x,float y,float z,const float *q,float approach_x,float approach_y,float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HOME_POSITION_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_float_array(buf, 24, q, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_HOME_POSITION_LEN); +#else + mavlink_home_position_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.x = x; + packet.y = y; + packet.z = z; + packet.approach_x = approach_x; + packet.approach_y = approach_y; + packet.approach_z = approach_z; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_HOME_POSITION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_HOME_POSITION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_HOME_POSITION_LEN, MAVLINK_MSG_ID_HOME_POSITION_CRC); +} + +/** + * @brief Encode a home_position struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param home_position C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_home_position_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_home_position_t* home_position) +{ + return mavlink_msg_home_position_pack(system_id, component_id, msg, home_position->latitude, home_position->longitude, home_position->altitude, home_position->x, home_position->y, home_position->z, home_position->q, home_position->approach_x, home_position->approach_y, home_position->approach_z); +} + +/** + * @brief Encode a home_position struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param home_position C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_home_position_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_home_position_t* home_position) +{ + return mavlink_msg_home_position_pack_chan(system_id, component_id, chan, msg, home_position->latitude, home_position->longitude, home_position->altitude, home_position->x, home_position->y, home_position->z, home_position->q, home_position->approach_x, home_position->approach_y, home_position->approach_z); +} + +/** + * @brief Send a home_position message + * @param chan MAVLink channel to send the message + * + * @param latitude Latitude (WGS84), in degrees * 1E7 + * @param longitude Longitude (WGS84, in degrees * 1E7 + * @param altitude Altitude (AMSL), in meters * 1000 (positive for up) + * @param x Local X position of this position in the local coordinate frame + * @param y Local Y position of this position in the local coordinate frame + * @param z Local Z position of this position in the local coordinate frame + * @param q World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + * @param approach_x Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_y Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_z Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_home_position_send(mavlink_channel_t chan, int32_t latitude, int32_t longitude, int32_t altitude, float x, float y, float z, const float *q, float approach_x, float approach_y, float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_HOME_POSITION_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_float_array(buf, 24, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HOME_POSITION, buf, MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_HOME_POSITION_LEN, MAVLINK_MSG_ID_HOME_POSITION_CRC); +#else + mavlink_home_position_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.x = x; + packet.y = y; + packet.z = z; + packet.approach_x = approach_x; + packet.approach_y = approach_y; + packet.approach_z = approach_z; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HOME_POSITION, (const char *)&packet, MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_HOME_POSITION_LEN, MAVLINK_MSG_ID_HOME_POSITION_CRC); +#endif +} + +/** + * @brief Send a home_position message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_home_position_send_struct(mavlink_channel_t chan, const mavlink_home_position_t* home_position) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_home_position_send(chan, home_position->latitude, home_position->longitude, home_position->altitude, home_position->x, home_position->y, home_position->z, home_position->q, home_position->approach_x, home_position->approach_y, home_position->approach_z); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HOME_POSITION, (const char *)home_position, MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_HOME_POSITION_LEN, MAVLINK_MSG_ID_HOME_POSITION_CRC); +#endif +} + +#if MAVLINK_MSG_ID_HOME_POSITION_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_home_position_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int32_t latitude, int32_t longitude, int32_t altitude, float x, float y, float z, const float *q, float approach_x, float approach_y, float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_float_array(buf, 24, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HOME_POSITION, buf, MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_HOME_POSITION_LEN, MAVLINK_MSG_ID_HOME_POSITION_CRC); +#else + mavlink_home_position_t *packet = (mavlink_home_position_t *)msgbuf; + packet->latitude = latitude; + packet->longitude = longitude; + packet->altitude = altitude; + packet->x = x; + packet->y = y; + packet->z = z; + packet->approach_x = approach_x; + packet->approach_y = approach_y; + packet->approach_z = approach_z; + mav_array_memcpy(packet->q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_HOME_POSITION, (const char *)packet, MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_HOME_POSITION_LEN, MAVLINK_MSG_ID_HOME_POSITION_CRC); +#endif +} +#endif + +#endif + +// MESSAGE HOME_POSITION UNPACKING + + +/** + * @brief Get field latitude from home_position message + * + * @return Latitude (WGS84), in degrees * 1E7 + */ +static inline int32_t mavlink_msg_home_position_get_latitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 0); +} + +/** + * @brief Get field longitude from home_position message + * + * @return Longitude (WGS84, in degrees * 1E7 + */ +static inline int32_t mavlink_msg_home_position_get_longitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 4); +} + +/** + * @brief Get field altitude from home_position message + * + * @return Altitude (AMSL), in meters * 1000 (positive for up) + */ +static inline int32_t mavlink_msg_home_position_get_altitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 8); +} + +/** + * @brief Get field x from home_position message + * + * @return Local X position of this position in the local coordinate frame + */ +static inline float mavlink_msg_home_position_get_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field y from home_position message + * + * @return Local Y position of this position in the local coordinate frame + */ +static inline float mavlink_msg_home_position_get_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field z from home_position message + * + * @return Local Z position of this position in the local coordinate frame + */ +static inline float mavlink_msg_home_position_get_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field q from home_position message + * + * @return World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + */ +static inline uint16_t mavlink_msg_home_position_get_q(const mavlink_message_t* msg, float *q) +{ + return _MAV_RETURN_float_array(msg, q, 4, 24); +} + +/** + * @brief Get field approach_x from home_position message + * + * @return Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +static inline float mavlink_msg_home_position_get_approach_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 40); +} + +/** + * @brief Get field approach_y from home_position message + * + * @return Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +static inline float mavlink_msg_home_position_get_approach_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 44); +} + +/** + * @brief Get field approach_z from home_position message + * + * @return Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +static inline float mavlink_msg_home_position_get_approach_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 48); +} + +/** + * @brief Decode a home_position message into a struct + * + * @param msg The message to decode + * @param home_position C-struct to decode the message contents into + */ +static inline void mavlink_msg_home_position_decode(const mavlink_message_t* msg, mavlink_home_position_t* home_position) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + home_position->latitude = mavlink_msg_home_position_get_latitude(msg); + home_position->longitude = mavlink_msg_home_position_get_longitude(msg); + home_position->altitude = mavlink_msg_home_position_get_altitude(msg); + home_position->x = mavlink_msg_home_position_get_x(msg); + home_position->y = mavlink_msg_home_position_get_y(msg); + home_position->z = mavlink_msg_home_position_get_z(msg); + mavlink_msg_home_position_get_q(msg, home_position->q); + home_position->approach_x = mavlink_msg_home_position_get_approach_x(msg); + home_position->approach_y = mavlink_msg_home_position_get_approach_y(msg); + home_position->approach_z = mavlink_msg_home_position_get_approach_z(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_HOME_POSITION_LEN? msg->len : MAVLINK_MSG_ID_HOME_POSITION_LEN; + memset(home_position, 0, MAVLINK_MSG_ID_HOME_POSITION_LEN); + memcpy(home_position, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_landing_target.h b/vendor/libraries/mavlink/common/mavlink_msg_landing_target.h new file mode 100644 index 0000000000..c79dc667c4 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_landing_target.h @@ -0,0 +1,388 @@ +#pragma once +// MESSAGE LANDING_TARGET PACKING + +#define MAVLINK_MSG_ID_LANDING_TARGET 149 + +MAVPACKED( +typedef struct __mavlink_landing_target_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float angle_x; /*< X-axis angular offset (in radians) of the target from the center of the image*/ + float angle_y; /*< Y-axis angular offset (in radians) of the target from the center of the image*/ + float distance; /*< Distance to the target from the vehicle in meters*/ + float size_x; /*< Size in radians of target along x-axis*/ + float size_y; /*< Size in radians of target along y-axis*/ + uint8_t target_num; /*< The ID of the target if multiple targets are present*/ + uint8_t frame; /*< MAV_FRAME enum specifying the whether the following feilds are earth-frame, body-frame, etc.*/ +}) mavlink_landing_target_t; + +#define MAVLINK_MSG_ID_LANDING_TARGET_LEN 30 +#define MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN 30 +#define MAVLINK_MSG_ID_149_LEN 30 +#define MAVLINK_MSG_ID_149_MIN_LEN 30 + +#define MAVLINK_MSG_ID_LANDING_TARGET_CRC 200 +#define MAVLINK_MSG_ID_149_CRC 200 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_LANDING_TARGET { \ + 149, \ + "LANDING_TARGET", \ + 8, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_landing_target_t, time_usec) }, \ + { "angle_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_landing_target_t, angle_x) }, \ + { "angle_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_landing_target_t, angle_y) }, \ + { "distance", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_landing_target_t, distance) }, \ + { "size_x", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_landing_target_t, size_x) }, \ + { "size_y", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_landing_target_t, size_y) }, \ + { "target_num", NULL, MAVLINK_TYPE_UINT8_T, 0, 28, offsetof(mavlink_landing_target_t, target_num) }, \ + { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 29, offsetof(mavlink_landing_target_t, frame) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_LANDING_TARGET { \ + "LANDING_TARGET", \ + 8, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_landing_target_t, time_usec) }, \ + { "angle_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_landing_target_t, angle_x) }, \ + { "angle_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_landing_target_t, angle_y) }, \ + { "distance", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_landing_target_t, distance) }, \ + { "size_x", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_landing_target_t, size_x) }, \ + { "size_y", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_landing_target_t, size_y) }, \ + { "target_num", NULL, MAVLINK_TYPE_UINT8_T, 0, 28, offsetof(mavlink_landing_target_t, target_num) }, \ + { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 29, offsetof(mavlink_landing_target_t, frame) }, \ + } \ +} +#endif + +/** + * @brief Pack a landing_target message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param target_num The ID of the target if multiple targets are present + * @param frame MAV_FRAME enum specifying the whether the following feilds are earth-frame, body-frame, etc. + * @param angle_x X-axis angular offset (in radians) of the target from the center of the image + * @param angle_y Y-axis angular offset (in radians) of the target from the center of the image + * @param distance Distance to the target from the vehicle in meters + * @param size_x Size in radians of target along x-axis + * @param size_y Size in radians of target along y-axis + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_landing_target_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, uint8_t target_num, uint8_t frame, float angle_x, float angle_y, float distance, float size_x, float size_y) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_LANDING_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, angle_x); + _mav_put_float(buf, 12, angle_y); + _mav_put_float(buf, 16, distance); + _mav_put_float(buf, 20, size_x); + _mav_put_float(buf, 24, size_y); + _mav_put_uint8_t(buf, 28, target_num); + _mav_put_uint8_t(buf, 29, frame); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LANDING_TARGET_LEN); +#else + mavlink_landing_target_t packet; + packet.time_usec = time_usec; + packet.angle_x = angle_x; + packet.angle_y = angle_y; + packet.distance = distance; + packet.size_x = size_x; + packet.size_y = size_y; + packet.target_num = target_num; + packet.frame = frame; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LANDING_TARGET_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_LANDING_TARGET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN, MAVLINK_MSG_ID_LANDING_TARGET_LEN, MAVLINK_MSG_ID_LANDING_TARGET_CRC); +} + +/** + * @brief Pack a landing_target message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param target_num The ID of the target if multiple targets are present + * @param frame MAV_FRAME enum specifying the whether the following feilds are earth-frame, body-frame, etc. + * @param angle_x X-axis angular offset (in radians) of the target from the center of the image + * @param angle_y Y-axis angular offset (in radians) of the target from the center of the image + * @param distance Distance to the target from the vehicle in meters + * @param size_x Size in radians of target along x-axis + * @param size_y Size in radians of target along y-axis + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_landing_target_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,uint8_t target_num,uint8_t frame,float angle_x,float angle_y,float distance,float size_x,float size_y) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_LANDING_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, angle_x); + _mav_put_float(buf, 12, angle_y); + _mav_put_float(buf, 16, distance); + _mav_put_float(buf, 20, size_x); + _mav_put_float(buf, 24, size_y); + _mav_put_uint8_t(buf, 28, target_num); + _mav_put_uint8_t(buf, 29, frame); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LANDING_TARGET_LEN); +#else + mavlink_landing_target_t packet; + packet.time_usec = time_usec; + packet.angle_x = angle_x; + packet.angle_y = angle_y; + packet.distance = distance; + packet.size_x = size_x; + packet.size_y = size_y; + packet.target_num = target_num; + packet.frame = frame; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LANDING_TARGET_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_LANDING_TARGET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN, MAVLINK_MSG_ID_LANDING_TARGET_LEN, MAVLINK_MSG_ID_LANDING_TARGET_CRC); +} + +/** + * @brief Encode a landing_target struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param landing_target C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_landing_target_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_landing_target_t* landing_target) +{ + return mavlink_msg_landing_target_pack(system_id, component_id, msg, landing_target->time_usec, landing_target->target_num, landing_target->frame, landing_target->angle_x, landing_target->angle_y, landing_target->distance, landing_target->size_x, landing_target->size_y); +} + +/** + * @brief Encode a landing_target struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param landing_target C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_landing_target_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_landing_target_t* landing_target) +{ + return mavlink_msg_landing_target_pack_chan(system_id, component_id, chan, msg, landing_target->time_usec, landing_target->target_num, landing_target->frame, landing_target->angle_x, landing_target->angle_y, landing_target->distance, landing_target->size_x, landing_target->size_y); +} + +/** + * @brief Send a landing_target message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param target_num The ID of the target if multiple targets are present + * @param frame MAV_FRAME enum specifying the whether the following feilds are earth-frame, body-frame, etc. + * @param angle_x X-axis angular offset (in radians) of the target from the center of the image + * @param angle_y Y-axis angular offset (in radians) of the target from the center of the image + * @param distance Distance to the target from the vehicle in meters + * @param size_x Size in radians of target along x-axis + * @param size_y Size in radians of target along y-axis + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_landing_target_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t target_num, uint8_t frame, float angle_x, float angle_y, float distance, float size_x, float size_y) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_LANDING_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, angle_x); + _mav_put_float(buf, 12, angle_y); + _mav_put_float(buf, 16, distance); + _mav_put_float(buf, 20, size_x); + _mav_put_float(buf, 24, size_y); + _mav_put_uint8_t(buf, 28, target_num); + _mav_put_uint8_t(buf, 29, frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LANDING_TARGET, buf, MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN, MAVLINK_MSG_ID_LANDING_TARGET_LEN, MAVLINK_MSG_ID_LANDING_TARGET_CRC); +#else + mavlink_landing_target_t packet; + packet.time_usec = time_usec; + packet.angle_x = angle_x; + packet.angle_y = angle_y; + packet.distance = distance; + packet.size_x = size_x; + packet.size_y = size_y; + packet.target_num = target_num; + packet.frame = frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LANDING_TARGET, (const char *)&packet, MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN, MAVLINK_MSG_ID_LANDING_TARGET_LEN, MAVLINK_MSG_ID_LANDING_TARGET_CRC); +#endif +} + +/** + * @brief Send a landing_target message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_landing_target_send_struct(mavlink_channel_t chan, const mavlink_landing_target_t* landing_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_landing_target_send(chan, landing_target->time_usec, landing_target->target_num, landing_target->frame, landing_target->angle_x, landing_target->angle_y, landing_target->distance, landing_target->size_x, landing_target->size_y); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LANDING_TARGET, (const char *)landing_target, MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN, MAVLINK_MSG_ID_LANDING_TARGET_LEN, MAVLINK_MSG_ID_LANDING_TARGET_CRC); +#endif +} + +#if MAVLINK_MSG_ID_LANDING_TARGET_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_landing_target_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t target_num, uint8_t frame, float angle_x, float angle_y, float distance, float size_x, float size_y) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, angle_x); + _mav_put_float(buf, 12, angle_y); + _mav_put_float(buf, 16, distance); + _mav_put_float(buf, 20, size_x); + _mav_put_float(buf, 24, size_y); + _mav_put_uint8_t(buf, 28, target_num); + _mav_put_uint8_t(buf, 29, frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LANDING_TARGET, buf, MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN, MAVLINK_MSG_ID_LANDING_TARGET_LEN, MAVLINK_MSG_ID_LANDING_TARGET_CRC); +#else + mavlink_landing_target_t *packet = (mavlink_landing_target_t *)msgbuf; + packet->time_usec = time_usec; + packet->angle_x = angle_x; + packet->angle_y = angle_y; + packet->distance = distance; + packet->size_x = size_x; + packet->size_y = size_y; + packet->target_num = target_num; + packet->frame = frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LANDING_TARGET, (const char *)packet, MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN, MAVLINK_MSG_ID_LANDING_TARGET_LEN, MAVLINK_MSG_ID_LANDING_TARGET_CRC); +#endif +} +#endif + +#endif + +// MESSAGE LANDING_TARGET UNPACKING + + +/** + * @brief Get field time_usec from landing_target message + * + * @return Timestamp (micros since boot or Unix epoch) + */ +static inline uint64_t mavlink_msg_landing_target_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field target_num from landing_target message + * + * @return The ID of the target if multiple targets are present + */ +static inline uint8_t mavlink_msg_landing_target_get_target_num(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 28); +} + +/** + * @brief Get field frame from landing_target message + * + * @return MAV_FRAME enum specifying the whether the following feilds are earth-frame, body-frame, etc. + */ +static inline uint8_t mavlink_msg_landing_target_get_frame(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 29); +} + +/** + * @brief Get field angle_x from landing_target message + * + * @return X-axis angular offset (in radians) of the target from the center of the image + */ +static inline float mavlink_msg_landing_target_get_angle_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field angle_y from landing_target message + * + * @return Y-axis angular offset (in radians) of the target from the center of the image + */ +static inline float mavlink_msg_landing_target_get_angle_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field distance from landing_target message + * + * @return Distance to the target from the vehicle in meters + */ +static inline float mavlink_msg_landing_target_get_distance(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field size_x from landing_target message + * + * @return Size in radians of target along x-axis + */ +static inline float mavlink_msg_landing_target_get_size_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field size_y from landing_target message + * + * @return Size in radians of target along y-axis + */ +static inline float mavlink_msg_landing_target_get_size_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Decode a landing_target message into a struct + * + * @param msg The message to decode + * @param landing_target C-struct to decode the message contents into + */ +static inline void mavlink_msg_landing_target_decode(const mavlink_message_t* msg, mavlink_landing_target_t* landing_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + landing_target->time_usec = mavlink_msg_landing_target_get_time_usec(msg); + landing_target->angle_x = mavlink_msg_landing_target_get_angle_x(msg); + landing_target->angle_y = mavlink_msg_landing_target_get_angle_y(msg); + landing_target->distance = mavlink_msg_landing_target_get_distance(msg); + landing_target->size_x = mavlink_msg_landing_target_get_size_x(msg); + landing_target->size_y = mavlink_msg_landing_target_get_size_y(msg); + landing_target->target_num = mavlink_msg_landing_target_get_target_num(msg); + landing_target->frame = mavlink_msg_landing_target_get_frame(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_LANDING_TARGET_LEN? msg->len : MAVLINK_MSG_ID_LANDING_TARGET_LEN; + memset(landing_target, 0, MAVLINK_MSG_ID_LANDING_TARGET_LEN); + memcpy(landing_target, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned.h b/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned.h index e18a948695..4634032dab 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE LOCAL_POSITION_NED PACKING #define MAVLINK_MSG_ID_LOCAL_POSITION_NED 32 -typedef struct __mavlink_local_position_ned_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float x; ///< X Position - float y; ///< Y Position - float z; ///< Z Position - float vx; ///< X Speed - float vy; ///< Y Speed - float vz; ///< Z Speed -} mavlink_local_position_ned_t; +MAVPACKED( +typedef struct __mavlink_local_position_ned_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float x; /*< X Position*/ + float y; /*< Y Position*/ + float z; /*< Z Position*/ + float vx; /*< X Speed*/ + float vy; /*< Y Speed*/ + float vz; /*< Z Speed*/ +}) mavlink_local_position_ned_t; #define MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN 28 +#define MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN 28 #define MAVLINK_MSG_ID_32_LEN 28 +#define MAVLINK_MSG_ID_32_MIN_LEN 28 #define MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC 185 #define MAVLINK_MSG_ID_32_CRC 185 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED { \ - "LOCAL_POSITION_NED", \ - 7, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_local_position_ned_t, time_boot_ms) }, \ + 32, \ + "LOCAL_POSITION_NED", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_local_position_ned_t, time_boot_ms) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_local_position_ned_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_local_position_ned_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_local_position_ned_t, z) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_local_position_ned_t { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_local_position_ned_t, vz) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED { \ + "LOCAL_POSITION_NED", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_local_position_ned_t, time_boot_ms) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_local_position_ned_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_local_position_ned_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_local_position_ned_t, z) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_local_position_ned_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_local_position_ned_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_local_position_ned_t, vz) }, \ + } \ +} +#endif /** * @brief Pack a local_position_ned message @@ -51,38 +69,34 @@ typedef struct __mavlink_local_position_ned_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_local_position_ned_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, float x, float y, float z, float vx, float vy, float vz) + uint32_t time_boot_ms, float x, float y, float z, float vx, float vy, float vz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); #else - mavlink_local_position_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; + mavlink_local_position_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_local_position_ned_pack(uint8_t system_id, ui * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_local_position_ned_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,float x,float y,float z,float vx,float vy,float vz) + mavlink_message_t* msg, + uint32_t time_boot_ms,float x,float y,float z,float vx,float vy,float vz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); #else - mavlink_local_position_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; + mavlink_local_position_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_local_position_ned_pack_chan(uint8_t system_i */ static inline uint16_t mavlink_msg_local_position_ned_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_local_position_ned_t* local_position_ned) { - return mavlink_msg_local_position_ned_pack(system_id, component_id, msg, local_position_ned->time_boot_ms, local_position_ned->x, local_position_ned->y, local_position_ned->z, local_position_ned->vx, local_position_ned->vy, local_position_ned->vz); + return mavlink_msg_local_position_ned_pack(system_id, component_id, msg, local_position_ned->time_boot_ms, local_position_ned->x, local_position_ned->y, local_position_ned->z, local_position_ned->vx, local_position_ned->vy, local_position_ned->vz); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_local_position_ned_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_local_position_ned_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_local_position_ned_t* local_position_ned) { - return mavlink_msg_local_position_ned_pack_chan(system_id, component_id, chan, msg, local_position_ned->time_boot_ms, local_position_ned->x, local_position_ned->y, local_position_ned->z, local_position_ned->vx, local_position_ned->vy, local_position_ned->vz); + return mavlink_msg_local_position_ned_pack_chan(system_id, component_id, chan, msg, local_position_ned->time_boot_ms, local_position_ned->x, local_position_ned->y, local_position_ned->z, local_position_ned->vx, local_position_ned->vy, local_position_ned->vz); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_local_position_ned_encode_chan(uint8_t system static inline void mavlink_msg_local_position_ned_send(mavlink_channel_t chan, uint32_t time_boot_ms, float x, float y, float z, float vx, float vy, float vz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); + mavlink_local_position_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); #endif +} + +/** + * @brief Send a local_position_ned message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_local_position_ned_send_struct(mavlink_channel_t chan, const mavlink_local_position_ned_t* local_position_ned) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_local_position_ned_send(chan, local_position_ned->time_boot_ms, local_position_ned->x, local_position_ned->y, local_position_ned->z, local_position_ned->vx, local_position_ned->vy, local_position_ned->vz); #else - mavlink_local_position_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, (const char *)local_position_ned, MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_local_position_ned_send(mavlink_channel_t chan, u static inline void mavlink_msg_local_position_ned_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float x, float y, float z, float vx, float vy, float vz) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); -#endif -#else - mavlink_local_position_ned_t *packet = (mavlink_local_position_ned_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->x = x; - packet->y = y; - packet->z = z; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); -#endif + mavlink_local_position_ned_t *packet = (mavlink_local_position_ned_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->x = x; + packet->y = y; + packet->z = z; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_local_position_ned_send_buf(mavlink_message_t *ms */ static inline uint32_t mavlink_msg_local_position_ned_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline uint32_t mavlink_msg_local_position_ned_get_time_boot_ms(const mav */ static inline float mavlink_msg_local_position_ned_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_local_position_ned_get_x(const mavlink_message_t */ static inline float mavlink_msg_local_position_ned_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_local_position_ned_get_y(const mavlink_message_t */ static inline float mavlink_msg_local_position_ned_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_local_position_ned_get_z(const mavlink_message_t */ static inline float mavlink_msg_local_position_ned_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_local_position_ned_get_vx(const mavlink_message_ */ static inline float mavlink_msg_local_position_ned_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_local_position_ned_get_vy(const mavlink_message_ */ static inline float mavlink_msg_local_position_ned_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_local_position_ned_get_vz(const mavlink_message_ */ static inline void mavlink_msg_local_position_ned_decode(const mavlink_message_t* msg, mavlink_local_position_ned_t* local_position_ned) { -#if MAVLINK_NEED_BYTE_SWAP - local_position_ned->time_boot_ms = mavlink_msg_local_position_ned_get_time_boot_ms(msg); - local_position_ned->x = mavlink_msg_local_position_ned_get_x(msg); - local_position_ned->y = mavlink_msg_local_position_ned_get_y(msg); - local_position_ned->z = mavlink_msg_local_position_ned_get_z(msg); - local_position_ned->vx = mavlink_msg_local_position_ned_get_vx(msg); - local_position_ned->vy = mavlink_msg_local_position_ned_get_vy(msg); - local_position_ned->vz = mavlink_msg_local_position_ned_get_vz(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + local_position_ned->time_boot_ms = mavlink_msg_local_position_ned_get_time_boot_ms(msg); + local_position_ned->x = mavlink_msg_local_position_ned_get_x(msg); + local_position_ned->y = mavlink_msg_local_position_ned_get_y(msg); + local_position_ned->z = mavlink_msg_local_position_ned_get_z(msg); + local_position_ned->vx = mavlink_msg_local_position_ned_get_vx(msg); + local_position_ned->vy = mavlink_msg_local_position_ned_get_vy(msg); + local_position_ned->vz = mavlink_msg_local_position_ned_get_vz(msg); #else - memcpy(local_position_ned, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN? msg->len : MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN; + memset(local_position_ned, 0, MAVLINK_MSG_ID_LOCAL_POSITION_NED_LEN); + memcpy(local_position_ned, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_cov.h b/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_cov.h index 0a94af383c..e697e46ecf 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_cov.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_cov.h @@ -1,45 +1,72 @@ +#pragma once // MESSAGE LOCAL_POSITION_NED_COV PACKING #define MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV 64 -typedef struct __mavlink_local_position_ned_cov_t -{ - uint64_t time_utc; ///< Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float x; ///< X Position - float y; ///< Y Position - float z; ///< Z Position - float vx; ///< X Speed - float vy; ///< Y Speed - float vz; ///< Z Speed - float covariance[36]; ///< Covariance matrix (first six entries are the first ROW, next six entries are the second row, etc.) - uint8_t estimator_type; ///< Class id of the estimator this estimate originated from. -} mavlink_local_position_ned_cov_t; - -#define MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN 181 -#define MAVLINK_MSG_ID_64_LEN 181 - -#define MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC 82 -#define MAVLINK_MSG_ID_64_CRC 82 - -#define MAVLINK_MSG_LOCAL_POSITION_NED_COV_FIELD_COVARIANCE_LEN 36 +MAVPACKED( +typedef struct __mavlink_local_position_ned_cov_t { + uint64_t time_usec; /*< Timestamp (microseconds since system boot or since UNIX epoch)*/ + float x; /*< X Position*/ + float y; /*< Y Position*/ + float z; /*< Z Position*/ + float vx; /*< X Speed (m/s)*/ + float vy; /*< Y Speed (m/s)*/ + float vz; /*< Z Speed (m/s)*/ + float ax; /*< X Acceleration (m/s^2)*/ + float ay; /*< Y Acceleration (m/s^2)*/ + float az; /*< Z Acceleration (m/s^2)*/ + float covariance[45]; /*< Covariance matrix upper right triangular (first nine entries are the first ROW, next eight entries are the second row, etc.)*/ + uint8_t estimator_type; /*< Class id of the estimator this estimate originated from.*/ +}) mavlink_local_position_ned_cov_t; + +#define MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN 225 +#define MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN 225 +#define MAVLINK_MSG_ID_64_LEN 225 +#define MAVLINK_MSG_ID_64_MIN_LEN 225 + +#define MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC 191 +#define MAVLINK_MSG_ID_64_CRC 191 + +#define MAVLINK_MSG_LOCAL_POSITION_NED_COV_FIELD_COVARIANCE_LEN 45 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_COV { \ - "LOCAL_POSITION_NED_COV", \ - 10, \ - { { "time_utc", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_local_position_ned_cov_t, time_utc) }, \ - { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_local_position_ned_cov_t, time_boot_ms) }, \ - { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_local_position_ned_cov_t, x) }, \ - { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_local_position_ned_cov_t, y) }, \ - { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_local_position_ned_cov_t, z) }, \ - { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_local_position_ned_cov_t, vx) }, \ - { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_local_position_ned_cov_t, vy) }, \ - { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_local_position_ned_cov_t, vz) }, \ - { "covariance", NULL, MAVLINK_TYPE_FLOAT, 36, 36, offsetof(mavlink_local_position_ned_cov_t, covariance) }, \ - { "estimator_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 180, offsetof(mavlink_local_position_ned_cov_t, estimator_type) }, \ + 64, \ + "LOCAL_POSITION_NED_COV", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_local_position_ned_cov_t, time_usec) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_local_position_ned_cov_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_local_position_ned_cov_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_local_position_ned_cov_t, z) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_local_position_ned_cov_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_local_position_ned_cov_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_local_position_ned_cov_t, vz) }, \ + { "ax", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_local_position_ned_cov_t, ax) }, \ + { "ay", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_local_position_ned_cov_t, ay) }, \ + { "az", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_local_position_ned_cov_t, az) }, \ + { "covariance", NULL, MAVLINK_TYPE_FLOAT, 45, 44, offsetof(mavlink_local_position_ned_cov_t, covariance) }, \ + { "estimator_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 224, offsetof(mavlink_local_position_ned_cov_t, estimator_type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_COV { \ + "LOCAL_POSITION_NED_COV", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_local_position_ned_cov_t, time_usec) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_local_position_ned_cov_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_local_position_ned_cov_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_local_position_ned_cov_t, z) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_local_position_ned_cov_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_local_position_ned_cov_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_local_position_ned_cov_t, vz) }, \ + { "ax", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_local_position_ned_cov_t, ax) }, \ + { "ay", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_local_position_ned_cov_t, ay) }, \ + { "az", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_local_position_ned_cov_t, az) }, \ + { "covariance", NULL, MAVLINK_TYPE_FLOAT, 45, 44, offsetof(mavlink_local_position_ned_cov_t, covariance) }, \ + { "estimator_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 224, offsetof(mavlink_local_position_ned_cov_t, estimator_type) }, \ + } \ +} +#endif /** * @brief Pack a local_position_ned_cov message @@ -47,55 +74,57 @@ typedef struct __mavlink_local_position_ned_cov_t * @param component_id ID of this component (e.g. 200 for IMU) * @param msg The MAVLink message to compress the data into * - * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param time_utc Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param estimator_type Class id of the estimator this estimate originated from. * @param x X Position * @param y Y Position * @param z Z Position - * @param vx X Speed - * @param vy Y Speed - * @param vz Z Speed - * @param covariance Covariance matrix (first six entries are the first ROW, next six entries are the second row, etc.) + * @param vx X Speed (m/s) + * @param vy Y Speed (m/s) + * @param vz Z Speed (m/s) + * @param ax X Acceleration (m/s^2) + * @param ay Y Acceleration (m/s^2) + * @param az Z Acceleration (m/s^2) + * @param covariance Covariance matrix upper right triangular (first nine entries are the first ROW, next eight entries are the second row, etc.) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_local_position_ned_cov_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint64_t time_utc, uint8_t estimator_type, float x, float y, float z, float vx, float vy, float vz, const float *covariance) + uint64_t time_usec, uint8_t estimator_type, float x, float y, float z, float vx, float vy, float vz, float ax, float ay, float az, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN]; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_float(buf, 12, x); - _mav_put_float(buf, 16, y); - _mav_put_float(buf, 20, z); - _mav_put_float(buf, 24, vx); - _mav_put_float(buf, 28, vy); - _mav_put_float(buf, 32, vz); - _mav_put_uint8_t(buf, 180, estimator_type); - _mav_put_float_array(buf, 36, covariance, 36); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, vx); + _mav_put_float(buf, 24, vy); + _mav_put_float(buf, 28, vz); + _mav_put_float(buf, 32, ax); + _mav_put_float(buf, 36, ay); + _mav_put_float(buf, 40, az); + _mav_put_uint8_t(buf, 224, estimator_type); + _mav_put_float_array(buf, 44, covariance, 45); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); #else - mavlink_local_position_ned_cov_t packet; - packet.time_utc = time_utc; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.estimator_type = estimator_type; - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); + mavlink_local_position_ned_cov_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.ax = ax; + packet.ay = ay; + packet.az = az; + packet.estimator_type = estimator_type; + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*45); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); } /** @@ -104,56 +133,58 @@ static inline uint16_t mavlink_msg_local_position_ned_cov_pack(uint8_t system_id * @param component_id ID of this component (e.g. 200 for IMU) * @param chan The MAVLink channel this message will be sent over * @param msg The MAVLink message to compress the data into - * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param time_utc Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param estimator_type Class id of the estimator this estimate originated from. * @param x X Position * @param y Y Position * @param z Z Position - * @param vx X Speed - * @param vy Y Speed - * @param vz Z Speed - * @param covariance Covariance matrix (first six entries are the first ROW, next six entries are the second row, etc.) + * @param vx X Speed (m/s) + * @param vy Y Speed (m/s) + * @param vz Z Speed (m/s) + * @param ax X Acceleration (m/s^2) + * @param ay Y Acceleration (m/s^2) + * @param az Z Acceleration (m/s^2) + * @param covariance Covariance matrix upper right triangular (first nine entries are the first ROW, next eight entries are the second row, etc.) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_local_position_ned_cov_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint64_t time_utc,uint8_t estimator_type,float x,float y,float z,float vx,float vy,float vz,const float *covariance) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t estimator_type,float x,float y,float z,float vx,float vy,float vz,float ax,float ay,float az,const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN]; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_float(buf, 12, x); - _mav_put_float(buf, 16, y); - _mav_put_float(buf, 20, z); - _mav_put_float(buf, 24, vx); - _mav_put_float(buf, 28, vy); - _mav_put_float(buf, 32, vz); - _mav_put_uint8_t(buf, 180, estimator_type); - _mav_put_float_array(buf, 36, covariance, 36); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, vx); + _mav_put_float(buf, 24, vy); + _mav_put_float(buf, 28, vz); + _mav_put_float(buf, 32, ax); + _mav_put_float(buf, 36, ay); + _mav_put_float(buf, 40, az); + _mav_put_uint8_t(buf, 224, estimator_type); + _mav_put_float_array(buf, 44, covariance, 45); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); #else - mavlink_local_position_ned_cov_t packet; - packet.time_utc = time_utc; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.estimator_type = estimator_type; - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); + mavlink_local_position_ned_cov_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.ax = ax; + packet.ay = ay; + packet.az = az; + packet.estimator_type = estimator_type; + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*45); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); } /** @@ -166,7 +197,7 @@ static inline uint16_t mavlink_msg_local_position_ned_cov_pack_chan(uint8_t syst */ static inline uint16_t mavlink_msg_local_position_ned_cov_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_local_position_ned_cov_t* local_position_ned_cov) { - return mavlink_msg_local_position_ned_cov_pack(system_id, component_id, msg, local_position_ned_cov->time_boot_ms, local_position_ned_cov->time_utc, local_position_ned_cov->estimator_type, local_position_ned_cov->x, local_position_ned_cov->y, local_position_ned_cov->z, local_position_ned_cov->vx, local_position_ned_cov->vy, local_position_ned_cov->vz, local_position_ned_cov->covariance); + return mavlink_msg_local_position_ned_cov_pack(system_id, component_id, msg, local_position_ned_cov->time_usec, local_position_ned_cov->estimator_type, local_position_ned_cov->x, local_position_ned_cov->y, local_position_ned_cov->z, local_position_ned_cov->vx, local_position_ned_cov->vy, local_position_ned_cov->vz, local_position_ned_cov->ax, local_position_ned_cov->ay, local_position_ned_cov->az, local_position_ned_cov->covariance); } /** @@ -180,62 +211,74 @@ static inline uint16_t mavlink_msg_local_position_ned_cov_encode(uint8_t system_ */ static inline uint16_t mavlink_msg_local_position_ned_cov_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_local_position_ned_cov_t* local_position_ned_cov) { - return mavlink_msg_local_position_ned_cov_pack_chan(system_id, component_id, chan, msg, local_position_ned_cov->time_boot_ms, local_position_ned_cov->time_utc, local_position_ned_cov->estimator_type, local_position_ned_cov->x, local_position_ned_cov->y, local_position_ned_cov->z, local_position_ned_cov->vx, local_position_ned_cov->vy, local_position_ned_cov->vz, local_position_ned_cov->covariance); + return mavlink_msg_local_position_ned_cov_pack_chan(system_id, component_id, chan, msg, local_position_ned_cov->time_usec, local_position_ned_cov->estimator_type, local_position_ned_cov->x, local_position_ned_cov->y, local_position_ned_cov->z, local_position_ned_cov->vx, local_position_ned_cov->vy, local_position_ned_cov->vz, local_position_ned_cov->ax, local_position_ned_cov->ay, local_position_ned_cov->az, local_position_ned_cov->covariance); } /** * @brief Send a local_position_ned_cov message * @param chan MAVLink channel to send the message * - * @param time_boot_ms Timestamp (milliseconds since system boot) - * @param time_utc Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @param time_usec Timestamp (microseconds since system boot or since UNIX epoch) * @param estimator_type Class id of the estimator this estimate originated from. * @param x X Position * @param y Y Position * @param z Z Position - * @param vx X Speed - * @param vy Y Speed - * @param vz Z Speed - * @param covariance Covariance matrix (first six entries are the first ROW, next six entries are the second row, etc.) + * @param vx X Speed (m/s) + * @param vy Y Speed (m/s) + * @param vz Z Speed (m/s) + * @param ax X Acceleration (m/s^2) + * @param ay Y Acceleration (m/s^2) + * @param az Z Acceleration (m/s^2) + * @param covariance Covariance matrix upper right triangular (first nine entries are the first ROW, next eight entries are the second row, etc.) */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS -static inline void mavlink_msg_local_position_ned_cov_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint64_t time_utc, uint8_t estimator_type, float x, float y, float z, float vx, float vy, float vz, const float *covariance) +static inline void mavlink_msg_local_position_ned_cov_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t estimator_type, float x, float y, float z, float vx, float vy, float vz, float ax, float ay, float az, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN]; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_float(buf, 12, x); - _mav_put_float(buf, 16, y); - _mav_put_float(buf, 20, z); - _mav_put_float(buf, 24, vx); - _mav_put_float(buf, 28, vy); - _mav_put_float(buf, 32, vz); - _mav_put_uint8_t(buf, 180, estimator_type); - _mav_put_float_array(buf, 36, covariance, 36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, vx); + _mav_put_float(buf, 24, vy); + _mav_put_float(buf, 28, vz); + _mav_put_float(buf, 32, ax); + _mav_put_float(buf, 36, ay); + _mav_put_float(buf, 40, az); + _mav_put_uint8_t(buf, 224, estimator_type); + _mav_put_float_array(buf, 44, covariance, 45); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); + mavlink_local_position_ned_cov_t packet; + packet.time_usec = time_usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.ax = ax; + packet.ay = ay; + packet.az = az; + packet.estimator_type = estimator_type; + mav_array_memcpy(packet.covariance, covariance, sizeof(float)*45); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); #endif +} + +/** + * @brief Send a local_position_ned_cov message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_local_position_ned_cov_send_struct(mavlink_channel_t chan, const mavlink_local_position_ned_cov_t* local_position_ned_cov) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_local_position_ned_cov_send(chan, local_position_ned_cov->time_usec, local_position_ned_cov->estimator_type, local_position_ned_cov->x, local_position_ned_cov->y, local_position_ned_cov->z, local_position_ned_cov->vx, local_position_ned_cov->vy, local_position_ned_cov->vz, local_position_ned_cov->ax, local_position_ned_cov->ay, local_position_ned_cov->az, local_position_ned_cov->covariance); #else - mavlink_local_position_ned_cov_t packet; - packet.time_utc = time_utc; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.estimator_type = estimator_type; - mav_array_memcpy(packet.covariance, covariance, sizeof(float)*36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, (const char *)local_position_ned_cov, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); #endif } @@ -247,42 +290,38 @@ static inline void mavlink_msg_local_position_ned_cov_send(mavlink_channel_t cha is usually the receive buffer for the channel, and allows a reply to an incoming message with minimum stack space usage. */ -static inline void mavlink_msg_local_position_ned_cov_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint64_t time_utc, uint8_t estimator_type, float x, float y, float z, float vx, float vy, float vz, const float *covariance) +static inline void mavlink_msg_local_position_ned_cov_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t estimator_type, float x, float y, float z, float vx, float vy, float vz, float ax, float ay, float az, const float *covariance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 8, time_boot_ms); - _mav_put_float(buf, 12, x); - _mav_put_float(buf, 16, y); - _mav_put_float(buf, 20, z); - _mav_put_float(buf, 24, vx); - _mav_put_float(buf, 28, vy); - _mav_put_float(buf, 32, vz); - _mav_put_uint8_t(buf, 180, estimator_type); - _mav_put_float_array(buf, 36, covariance, 36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); -#endif -#else - mavlink_local_position_ned_cov_t *packet = (mavlink_local_position_ned_cov_t *)msgbuf; - packet->time_utc = time_utc; - packet->time_boot_ms = time_boot_ms; - packet->x = x; - packet->y = y; - packet->z = z; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->estimator_type = estimator_type; - mav_array_memcpy(packet->covariance, covariance, sizeof(float)*36); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, vx); + _mav_put_float(buf, 24, vy); + _mav_put_float(buf, 28, vz); + _mav_put_float(buf, 32, ax); + _mav_put_float(buf, 36, ay); + _mav_put_float(buf, 40, az); + _mav_put_uint8_t(buf, 224, estimator_type); + _mav_put_float_array(buf, 44, covariance, 45); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); -#endif + mavlink_local_position_ned_cov_t *packet = (mavlink_local_position_ned_cov_t *)msgbuf; + packet->time_usec = time_usec; + packet->x = x; + packet->y = y; + packet->z = z; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->ax = ax; + packet->ay = ay; + packet->az = az; + packet->estimator_type = estimator_type; + mav_array_memcpy(packet->covariance, covariance, sizeof(float)*45); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_CRC); #endif } #endif @@ -293,23 +332,13 @@ static inline void mavlink_msg_local_position_ned_cov_send_buf(mavlink_message_t /** - * @brief Get field time_boot_ms from local_position_ned_cov message - * - * @return Timestamp (milliseconds since system boot) - */ -static inline uint32_t mavlink_msg_local_position_ned_cov_get_time_boot_ms(const mavlink_message_t* msg) -{ - return _MAV_RETURN_uint32_t(msg, 8); -} - -/** - * @brief Get field time_utc from local_position_ned_cov message + * @brief Get field time_usec from local_position_ned_cov message * - * @return Timestamp (microseconds since UNIX epoch) in UTC. 0 for unknown. Commonly filled by the precision time source of a GPS receiver. + * @return Timestamp (microseconds since system boot or since UNIX epoch) */ -static inline uint64_t mavlink_msg_local_position_ned_cov_get_time_utc(const mavlink_message_t* msg) +static inline uint64_t mavlink_msg_local_position_ned_cov_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -319,7 +348,7 @@ static inline uint64_t mavlink_msg_local_position_ned_cov_get_time_utc(const mav */ static inline uint8_t mavlink_msg_local_position_ned_cov_get_estimator_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 180); + return _MAV_RETURN_uint8_t(msg, 224); } /** @@ -329,7 +358,7 @@ static inline uint8_t mavlink_msg_local_position_ned_cov_get_estimator_type(cons */ static inline float mavlink_msg_local_position_ned_cov_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 8); } /** @@ -339,7 +368,7 @@ static inline float mavlink_msg_local_position_ned_cov_get_x(const mavlink_messa */ static inline float mavlink_msg_local_position_ned_cov_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 12); } /** @@ -349,47 +378,77 @@ static inline float mavlink_msg_local_position_ned_cov_get_y(const mavlink_messa */ static inline float mavlink_msg_local_position_ned_cov_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 16); } /** * @brief Get field vx from local_position_ned_cov message * - * @return X Speed + * @return X Speed (m/s) */ static inline float mavlink_msg_local_position_ned_cov_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 20); } /** * @brief Get field vy from local_position_ned_cov message * - * @return Y Speed + * @return Y Speed (m/s) */ static inline float mavlink_msg_local_position_ned_cov_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 24); } /** * @brief Get field vz from local_position_ned_cov message * - * @return Z Speed + * @return Z Speed (m/s) */ static inline float mavlink_msg_local_position_ned_cov_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Get field ax from local_position_ned_cov message + * + * @return X Acceleration (m/s^2) + */ +static inline float mavlink_msg_local_position_ned_cov_get_ax(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 32); +} + +/** + * @brief Get field ay from local_position_ned_cov message + * + * @return Y Acceleration (m/s^2) + */ +static inline float mavlink_msg_local_position_ned_cov_get_ay(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 36); +} + +/** + * @brief Get field az from local_position_ned_cov message + * + * @return Z Acceleration (m/s^2) + */ +static inline float mavlink_msg_local_position_ned_cov_get_az(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 40); } /** * @brief Get field covariance from local_position_ned_cov message * - * @return Covariance matrix (first six entries are the first ROW, next six entries are the second row, etc.) + * @return Covariance matrix upper right triangular (first nine entries are the first ROW, next eight entries are the second row, etc.) */ static inline uint16_t mavlink_msg_local_position_ned_cov_get_covariance(const mavlink_message_t* msg, float *covariance) { - return _MAV_RETURN_float_array(msg, covariance, 36, 36); + return _MAV_RETURN_float_array(msg, covariance, 45, 44); } /** @@ -400,18 +459,22 @@ static inline uint16_t mavlink_msg_local_position_ned_cov_get_covariance(const m */ static inline void mavlink_msg_local_position_ned_cov_decode(const mavlink_message_t* msg, mavlink_local_position_ned_cov_t* local_position_ned_cov) { -#if MAVLINK_NEED_BYTE_SWAP - local_position_ned_cov->time_utc = mavlink_msg_local_position_ned_cov_get_time_utc(msg); - local_position_ned_cov->time_boot_ms = mavlink_msg_local_position_ned_cov_get_time_boot_ms(msg); - local_position_ned_cov->x = mavlink_msg_local_position_ned_cov_get_x(msg); - local_position_ned_cov->y = mavlink_msg_local_position_ned_cov_get_y(msg); - local_position_ned_cov->z = mavlink_msg_local_position_ned_cov_get_z(msg); - local_position_ned_cov->vx = mavlink_msg_local_position_ned_cov_get_vx(msg); - local_position_ned_cov->vy = mavlink_msg_local_position_ned_cov_get_vy(msg); - local_position_ned_cov->vz = mavlink_msg_local_position_ned_cov_get_vz(msg); - mavlink_msg_local_position_ned_cov_get_covariance(msg, local_position_ned_cov->covariance); - local_position_ned_cov->estimator_type = mavlink_msg_local_position_ned_cov_get_estimator_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + local_position_ned_cov->time_usec = mavlink_msg_local_position_ned_cov_get_time_usec(msg); + local_position_ned_cov->x = mavlink_msg_local_position_ned_cov_get_x(msg); + local_position_ned_cov->y = mavlink_msg_local_position_ned_cov_get_y(msg); + local_position_ned_cov->z = mavlink_msg_local_position_ned_cov_get_z(msg); + local_position_ned_cov->vx = mavlink_msg_local_position_ned_cov_get_vx(msg); + local_position_ned_cov->vy = mavlink_msg_local_position_ned_cov_get_vy(msg); + local_position_ned_cov->vz = mavlink_msg_local_position_ned_cov_get_vz(msg); + local_position_ned_cov->ax = mavlink_msg_local_position_ned_cov_get_ax(msg); + local_position_ned_cov->ay = mavlink_msg_local_position_ned_cov_get_ay(msg); + local_position_ned_cov->az = mavlink_msg_local_position_ned_cov_get_az(msg); + mavlink_msg_local_position_ned_cov_get_covariance(msg, local_position_ned_cov->covariance); + local_position_ned_cov->estimator_type = mavlink_msg_local_position_ned_cov_get_estimator_type(msg); #else - memcpy(local_position_ned_cov, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN? msg->len : MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN; + memset(local_position_ned_cov, 0, MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_LEN); + memcpy(local_position_ned_cov, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_system_global_offset.h b/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_system_global_offset.h index af7d195b01..e87bcaac9d 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_system_global_offset.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_local_position_ned_system_global_offset.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET PACKING #define MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET 89 -typedef struct __mavlink_local_position_ned_system_global_offset_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float x; ///< X Position - float y; ///< Y Position - float z; ///< Z Position - float roll; ///< Roll - float pitch; ///< Pitch - float yaw; ///< Yaw -} mavlink_local_position_ned_system_global_offset_t; +MAVPACKED( +typedef struct __mavlink_local_position_ned_system_global_offset_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float x; /*< X Position*/ + float y; /*< Y Position*/ + float z; /*< Z Position*/ + float roll; /*< Roll*/ + float pitch; /*< Pitch*/ + float yaw; /*< Yaw*/ +}) mavlink_local_position_ned_system_global_offset_t; #define MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN 28 +#define MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN 28 #define MAVLINK_MSG_ID_89_LEN 28 +#define MAVLINK_MSG_ID_89_MIN_LEN 28 #define MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC 231 #define MAVLINK_MSG_ID_89_CRC 231 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET { \ - "LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET", \ - 7, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_local_position_ned_system_global_offset_t, time_boot_ms) }, \ + 89, \ + "LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_local_position_ned_system_global_offset_t, time_boot_ms) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_local_position_ned_system_global_offset_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_local_position_ned_system_global_offset_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_local_position_ned_system_global_offset_t, z) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_local_position_ned_system_global_offset_t { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_local_position_ned_system_global_offset_t, yaw) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET { \ + "LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_local_position_ned_system_global_offset_t, time_boot_ms) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_local_position_ned_system_global_offset_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_local_position_ned_system_global_offset_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_local_position_ned_system_global_offset_t, z) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_local_position_ned_system_global_offset_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_local_position_ned_system_global_offset_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_local_position_ned_system_global_offset_t, yaw) }, \ + } \ +} +#endif /** * @brief Pack a local_position_ned_system_global_offset message @@ -51,38 +69,34 @@ typedef struct __mavlink_local_position_ned_system_global_offset_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, float x, float y, float z, float roll, float pitch, float yaw) + uint32_t time_boot_ms, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); #else - mavlink_local_position_ned_system_global_offset_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_local_position_ned_system_global_offset_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_pack( * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,float x,float y,float z,float roll,float pitch,float yaw) + mavlink_message_t* msg, + uint32_t time_boot_ms,float x,float y,float z,float roll,float pitch,float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); #else - mavlink_local_position_ned_system_global_offset_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_local_position_ned_system_global_offset_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_pack_ */ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_local_position_ned_system_global_offset_t* local_position_ned_system_global_offset) { - return mavlink_msg_local_position_ned_system_global_offset_pack(system_id, component_id, msg, local_position_ned_system_global_offset->time_boot_ms, local_position_ned_system_global_offset->x, local_position_ned_system_global_offset->y, local_position_ned_system_global_offset->z, local_position_ned_system_global_offset->roll, local_position_ned_system_global_offset->pitch, local_position_ned_system_global_offset->yaw); + return mavlink_msg_local_position_ned_system_global_offset_pack(system_id, component_id, msg, local_position_ned_system_global_offset->time_boot_ms, local_position_ned_system_global_offset->x, local_position_ned_system_global_offset->y, local_position_ned_system_global_offset->z, local_position_ned_system_global_offset->roll, local_position_ned_system_global_offset->pitch, local_position_ned_system_global_offset->yaw); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_encod */ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_local_position_ned_system_global_offset_t* local_position_ned_system_global_offset) { - return mavlink_msg_local_position_ned_system_global_offset_pack_chan(system_id, component_id, chan, msg, local_position_ned_system_global_offset->time_boot_ms, local_position_ned_system_global_offset->x, local_position_ned_system_global_offset->y, local_position_ned_system_global_offset->z, local_position_ned_system_global_offset->roll, local_position_ned_system_global_offset->pitch, local_position_ned_system_global_offset->yaw); + return mavlink_msg_local_position_ned_system_global_offset_pack_chan(system_id, component_id, chan, msg, local_position_ned_system_global_offset->time_boot_ms, local_position_ned_system_global_offset->x, local_position_ned_system_global_offset->y, local_position_ned_system_global_offset->z, local_position_ned_system_global_offset->roll, local_position_ned_system_global_offset->pitch, local_position_ned_system_global_offset->yaw); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_local_position_ned_system_global_offset_encod static inline void mavlink_msg_local_position_ned_system_global_offset_send(mavlink_channel_t chan, uint32_t time_boot_ms, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); + char buf[MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); + mavlink_local_position_ned_system_global_offset_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); #endif +} + +/** + * @brief Send a local_position_ned_system_global_offset message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_local_position_ned_system_global_offset_send_struct(mavlink_channel_t chan, const mavlink_local_position_ned_system_global_offset_t* local_position_ned_system_global_offset) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_local_position_ned_system_global_offset_send(chan, local_position_ned_system_global_offset->time_boot_ms, local_position_ned_system_global_offset->x, local_position_ned_system_global_offset->y, local_position_ned_system_global_offset->z, local_position_ned_system_global_offset->roll, local_position_ned_system_global_offset->pitch, local_position_ned_system_global_offset->yaw); #else - mavlink_local_position_ned_system_global_offset_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, (const char *)&packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, (const char *)local_position_ned_system_global_offset, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_local_position_ned_system_global_offset_send(mavl static inline void mavlink_msg_local_position_ned_system_global_offset_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); -#endif -#else - mavlink_local_position_ned_system_global_offset_t *packet = (mavlink_local_position_ned_system_global_offset_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->x = x; - packet->y = y; - packet->z = z; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, buf, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); -#endif + mavlink_local_position_ned_system_global_offset_t *packet = (mavlink_local_position_ned_system_global_offset_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->x = x; + packet->y = y; + packet->z = z; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET, (const char *)packet, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_local_position_ned_system_global_offset_send_buf( */ static inline uint32_t mavlink_msg_local_position_ned_system_global_offset_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline uint32_t mavlink_msg_local_position_ned_system_global_offset_get_t */ static inline float mavlink_msg_local_position_ned_system_global_offset_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_local_position_ned_system_global_offset_get_x(co */ static inline float mavlink_msg_local_position_ned_system_global_offset_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_local_position_ned_system_global_offset_get_y(co */ static inline float mavlink_msg_local_position_ned_system_global_offset_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_local_position_ned_system_global_offset_get_z(co */ static inline float mavlink_msg_local_position_ned_system_global_offset_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_local_position_ned_system_global_offset_get_roll */ static inline float mavlink_msg_local_position_ned_system_global_offset_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_local_position_ned_system_global_offset_get_pitc */ static inline float mavlink_msg_local_position_ned_system_global_offset_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_local_position_ned_system_global_offset_get_yaw( */ static inline void mavlink_msg_local_position_ned_system_global_offset_decode(const mavlink_message_t* msg, mavlink_local_position_ned_system_global_offset_t* local_position_ned_system_global_offset) { -#if MAVLINK_NEED_BYTE_SWAP - local_position_ned_system_global_offset->time_boot_ms = mavlink_msg_local_position_ned_system_global_offset_get_time_boot_ms(msg); - local_position_ned_system_global_offset->x = mavlink_msg_local_position_ned_system_global_offset_get_x(msg); - local_position_ned_system_global_offset->y = mavlink_msg_local_position_ned_system_global_offset_get_y(msg); - local_position_ned_system_global_offset->z = mavlink_msg_local_position_ned_system_global_offset_get_z(msg); - local_position_ned_system_global_offset->roll = mavlink_msg_local_position_ned_system_global_offset_get_roll(msg); - local_position_ned_system_global_offset->pitch = mavlink_msg_local_position_ned_system_global_offset_get_pitch(msg); - local_position_ned_system_global_offset->yaw = mavlink_msg_local_position_ned_system_global_offset_get_yaw(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + local_position_ned_system_global_offset->time_boot_ms = mavlink_msg_local_position_ned_system_global_offset_get_time_boot_ms(msg); + local_position_ned_system_global_offset->x = mavlink_msg_local_position_ned_system_global_offset_get_x(msg); + local_position_ned_system_global_offset->y = mavlink_msg_local_position_ned_system_global_offset_get_y(msg); + local_position_ned_system_global_offset->z = mavlink_msg_local_position_ned_system_global_offset_get_z(msg); + local_position_ned_system_global_offset->roll = mavlink_msg_local_position_ned_system_global_offset_get_roll(msg); + local_position_ned_system_global_offset->pitch = mavlink_msg_local_position_ned_system_global_offset_get_pitch(msg); + local_position_ned_system_global_offset->yaw = mavlink_msg_local_position_ned_system_global_offset_get_yaw(msg); #else - memcpy(local_position_ned_system_global_offset, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN? msg->len : MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN; + memset(local_position_ned_system_global_offset, 0, MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_LEN); + memcpy(local_position_ned_system_global_offset, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_log_data.h b/vendor/libraries/mavlink/common/mavlink_msg_log_data.h index 48641f3eb0..f4adf2f096 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_log_data.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_log_data.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE LOG_DATA PACKING #define MAVLINK_MSG_ID_LOG_DATA 120 -typedef struct __mavlink_log_data_t -{ - uint32_t ofs; ///< Offset into the log - uint16_t id; ///< Log id (from LOG_ENTRY reply) - uint8_t count; ///< Number of bytes (zero for end of log) - uint8_t data[90]; ///< log data -} mavlink_log_data_t; +MAVPACKED( +typedef struct __mavlink_log_data_t { + uint32_t ofs; /*< Offset into the log*/ + uint16_t id; /*< Log id (from LOG_ENTRY reply)*/ + uint8_t count; /*< Number of bytes (zero for end of log)*/ + uint8_t data[90]; /*< log data*/ +}) mavlink_log_data_t; #define MAVLINK_MSG_ID_LOG_DATA_LEN 97 +#define MAVLINK_MSG_ID_LOG_DATA_MIN_LEN 97 #define MAVLINK_MSG_ID_120_LEN 97 +#define MAVLINK_MSG_ID_120_MIN_LEN 97 #define MAVLINK_MSG_ID_LOG_DATA_CRC 134 #define MAVLINK_MSG_ID_120_CRC 134 #define MAVLINK_MSG_LOG_DATA_FIELD_DATA_LEN 90 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOG_DATA { \ - "LOG_DATA", \ - 4, \ - { { "ofs", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_data_t, ofs) }, \ + 120, \ + "LOG_DATA", \ + 4, \ + { { "ofs", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_data_t, ofs) }, \ { "id", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_log_data_t, id) }, \ { "count", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_log_data_t, count) }, \ { "data", NULL, MAVLINK_TYPE_UINT8_T, 90, 7, offsetof(mavlink_log_data_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOG_DATA { \ + "LOG_DATA", \ + 4, \ + { { "ofs", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_data_t, ofs) }, \ + { "id", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_log_data_t, id) }, \ + { "count", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_log_data_t, count) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 90, 7, offsetof(mavlink_log_data_t, data) }, \ + } \ +} +#endif /** * @brief Pack a log_data message @@ -42,30 +57,26 @@ typedef struct __mavlink_log_data_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_data_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t id, uint32_t ofs, uint8_t count, const uint8_t *data) + uint16_t id, uint32_t ofs, uint8_t count, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_DATA_LEN]; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint16_t(buf, 4, id); - _mav_put_uint8_t(buf, 6, count); - _mav_put_uint8_t_array(buf, 7, data, 90); + char buf[MAVLINK_MSG_ID_LOG_DATA_LEN]; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint16_t(buf, 4, id); + _mav_put_uint8_t(buf, 6, count); + _mav_put_uint8_t_array(buf, 7, data, 90); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_DATA_LEN); #else - mavlink_log_data_t packet; - packet.ofs = ofs; - packet.id = id; - packet.count = count; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*90); + mavlink_log_data_t packet; + packet.ofs = ofs; + packet.id = id; + packet.count = count; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*90); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_DATA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); } /** @@ -81,31 +92,27 @@ static inline uint16_t mavlink_msg_log_data_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_data_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t id,uint32_t ofs,uint8_t count,const uint8_t *data) + mavlink_message_t* msg, + uint16_t id,uint32_t ofs,uint8_t count,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_DATA_LEN]; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint16_t(buf, 4, id); - _mav_put_uint8_t(buf, 6, count); - _mav_put_uint8_t_array(buf, 7, data, 90); + char buf[MAVLINK_MSG_ID_LOG_DATA_LEN]; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint16_t(buf, 4, id); + _mav_put_uint8_t(buf, 6, count); + _mav_put_uint8_t_array(buf, 7, data, 90); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_DATA_LEN); #else - mavlink_log_data_t packet; - packet.ofs = ofs; - packet.id = id; - packet.count = count; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*90); + mavlink_log_data_t packet; + packet.ofs = ofs; + packet.id = id; + packet.count = count; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*90); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_DATA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); } /** @@ -118,7 +125,7 @@ static inline uint16_t mavlink_msg_log_data_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_log_data_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_log_data_t* log_data) { - return mavlink_msg_log_data_pack(system_id, component_id, msg, log_data->id, log_data->ofs, log_data->count, log_data->data); + return mavlink_msg_log_data_pack(system_id, component_id, msg, log_data->id, log_data->ofs, log_data->count, log_data->data); } /** @@ -132,7 +139,7 @@ static inline uint16_t mavlink_msg_log_data_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_log_data_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_log_data_t* log_data) { - return mavlink_msg_log_data_pack_chan(system_id, component_id, chan, msg, log_data->id, log_data->ofs, log_data->count, log_data->data); + return mavlink_msg_log_data_pack_chan(system_id, component_id, chan, msg, log_data->id, log_data->ofs, log_data->count, log_data->data); } /** @@ -149,27 +156,33 @@ static inline uint16_t mavlink_msg_log_data_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_log_data_send(mavlink_channel_t chan, uint16_t id, uint32_t ofs, uint8_t count, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_DATA_LEN]; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint16_t(buf, 4, id); - _mav_put_uint8_t(buf, 6, count); - _mav_put_uint8_t_array(buf, 7, data, 90); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, buf, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); + char buf[MAVLINK_MSG_ID_LOG_DATA_LEN]; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint16_t(buf, 4, id); + _mav_put_uint8_t(buf, 6, count); + _mav_put_uint8_t_array(buf, 7, data, 90); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, buf, MAVLINK_MSG_ID_LOG_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, buf, MAVLINK_MSG_ID_LOG_DATA_LEN); + mavlink_log_data_t packet; + packet.ofs = ofs; + packet.id = id; + packet.count = count; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*90); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, (const char *)&packet, MAVLINK_MSG_ID_LOG_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); #endif +} + +/** + * @brief Send a log_data message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_log_data_send_struct(mavlink_channel_t chan, const mavlink_log_data_t* log_data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_log_data_send(chan, log_data->id, log_data->ofs, log_data->count, log_data->data); #else - mavlink_log_data_t packet; - packet.ofs = ofs; - packet.id = id; - packet.count = count; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*90); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, (const char *)&packet, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, (const char *)&packet, MAVLINK_MSG_ID_LOG_DATA_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, (const char *)log_data, MAVLINK_MSG_ID_LOG_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); #endif } @@ -184,27 +197,19 @@ static inline void mavlink_msg_log_data_send(mavlink_channel_t chan, uint16_t id static inline void mavlink_msg_log_data_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t id, uint32_t ofs, uint8_t count, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint16_t(buf, 4, id); - _mav_put_uint8_t(buf, 6, count); - _mav_put_uint8_t_array(buf, 7, data, 90); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, buf, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint16_t(buf, 4, id); + _mav_put_uint8_t(buf, 6, count); + _mav_put_uint8_t_array(buf, 7, data, 90); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, buf, MAVLINK_MSG_ID_LOG_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, buf, MAVLINK_MSG_ID_LOG_DATA_LEN); -#endif -#else - mavlink_log_data_t *packet = (mavlink_log_data_t *)msgbuf; - packet->ofs = ofs; - packet->id = id; - packet->count = count; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*90); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, (const char *)packet, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, (const char *)packet, MAVLINK_MSG_ID_LOG_DATA_LEN); -#endif + mavlink_log_data_t *packet = (mavlink_log_data_t *)msgbuf; + packet->ofs = ofs; + packet->id = id; + packet->count = count; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*90); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_DATA, (const char *)packet, MAVLINK_MSG_ID_LOG_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_DATA_LEN, MAVLINK_MSG_ID_LOG_DATA_CRC); #endif } #endif @@ -221,7 +226,7 @@ static inline void mavlink_msg_log_data_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint16_t mavlink_msg_log_data_get_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -231,7 +236,7 @@ static inline uint16_t mavlink_msg_log_data_get_id(const mavlink_message_t* msg) */ static inline uint32_t mavlink_msg_log_data_get_ofs(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -241,7 +246,7 @@ static inline uint32_t mavlink_msg_log_data_get_ofs(const mavlink_message_t* msg */ static inline uint8_t mavlink_msg_log_data_get_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -251,7 +256,7 @@ static inline uint8_t mavlink_msg_log_data_get_count(const mavlink_message_t* ms */ static inline uint16_t mavlink_msg_log_data_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 90, 7); + return _MAV_RETURN_uint8_t_array(msg, data, 90, 7); } /** @@ -262,12 +267,14 @@ static inline uint16_t mavlink_msg_log_data_get_data(const mavlink_message_t* ms */ static inline void mavlink_msg_log_data_decode(const mavlink_message_t* msg, mavlink_log_data_t* log_data) { -#if MAVLINK_NEED_BYTE_SWAP - log_data->ofs = mavlink_msg_log_data_get_ofs(msg); - log_data->id = mavlink_msg_log_data_get_id(msg); - log_data->count = mavlink_msg_log_data_get_count(msg); - mavlink_msg_log_data_get_data(msg, log_data->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + log_data->ofs = mavlink_msg_log_data_get_ofs(msg); + log_data->id = mavlink_msg_log_data_get_id(msg); + log_data->count = mavlink_msg_log_data_get_count(msg); + mavlink_msg_log_data_get_data(msg, log_data->data); #else - memcpy(log_data, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOG_DATA_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOG_DATA_LEN? msg->len : MAVLINK_MSG_ID_LOG_DATA_LEN; + memset(log_data, 0, MAVLINK_MSG_ID_LOG_DATA_LEN); + memcpy(log_data, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_log_entry.h b/vendor/libraries/mavlink/common/mavlink_msg_log_entry.h index 8ecaec3ae2..733e4e7f9e 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_log_entry.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_log_entry.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE LOG_ENTRY PACKING #define MAVLINK_MSG_ID_LOG_ENTRY 118 -typedef struct __mavlink_log_entry_t -{ - uint32_t time_utc; ///< UTC timestamp of log in seconds since 1970, or 0 if not available - uint32_t size; ///< Size of the log (may be approximate) in bytes - uint16_t id; ///< Log id - uint16_t num_logs; ///< Total number of logs - uint16_t last_log_num; ///< High log number -} mavlink_log_entry_t; +MAVPACKED( +typedef struct __mavlink_log_entry_t { + uint32_t time_utc; /*< UTC timestamp of log in seconds since 1970, or 0 if not available*/ + uint32_t size; /*< Size of the log (may be approximate) in bytes*/ + uint16_t id; /*< Log id*/ + uint16_t num_logs; /*< Total number of logs*/ + uint16_t last_log_num; /*< High log number*/ +}) mavlink_log_entry_t; #define MAVLINK_MSG_ID_LOG_ENTRY_LEN 14 +#define MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN 14 #define MAVLINK_MSG_ID_118_LEN 14 +#define MAVLINK_MSG_ID_118_MIN_LEN 14 #define MAVLINK_MSG_ID_LOG_ENTRY_CRC 56 #define MAVLINK_MSG_ID_118_CRC 56 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOG_ENTRY { \ - "LOG_ENTRY", \ - 5, \ - { { "time_utc", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_entry_t, time_utc) }, \ + 118, \ + "LOG_ENTRY", \ + 5, \ + { { "time_utc", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_entry_t, time_utc) }, \ { "size", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_log_entry_t, size) }, \ { "id", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_log_entry_t, id) }, \ { "num_logs", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_log_entry_t, num_logs) }, \ { "last_log_num", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_log_entry_t, last_log_num) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOG_ENTRY { \ + "LOG_ENTRY", \ + 5, \ + { { "time_utc", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_entry_t, time_utc) }, \ + { "size", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_log_entry_t, size) }, \ + { "id", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_log_entry_t, id) }, \ + { "num_logs", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_log_entry_t, num_logs) }, \ + { "last_log_num", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_log_entry_t, last_log_num) }, \ + } \ +} +#endif /** * @brief Pack a log_entry message @@ -45,34 +61,30 @@ typedef struct __mavlink_log_entry_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_entry_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t id, uint16_t num_logs, uint16_t last_log_num, uint32_t time_utc, uint32_t size) + uint16_t id, uint16_t num_logs, uint16_t last_log_num, uint32_t time_utc, uint32_t size) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_ENTRY_LEN]; - _mav_put_uint32_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 4, size); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint16_t(buf, 10, num_logs); - _mav_put_uint16_t(buf, 12, last_log_num); + char buf[MAVLINK_MSG_ID_LOG_ENTRY_LEN]; + _mav_put_uint32_t(buf, 0, time_utc); + _mav_put_uint32_t(buf, 4, size); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint16_t(buf, 10, num_logs); + _mav_put_uint16_t(buf, 12, last_log_num); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_ENTRY_LEN); #else - mavlink_log_entry_t packet; - packet.time_utc = time_utc; - packet.size = size; - packet.id = id; - packet.num_logs = num_logs; - packet.last_log_num = last_log_num; + mavlink_log_entry_t packet; + packet.time_utc = time_utc; + packet.size = size; + packet.id = id; + packet.num_logs = num_logs; + packet.last_log_num = last_log_num; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_ENTRY_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_ENTRY; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_ENTRY_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_ENTRY; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); } /** @@ -89,35 +101,31 @@ static inline uint16_t mavlink_msg_log_entry_pack(uint8_t system_id, uint8_t com * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_entry_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t id,uint16_t num_logs,uint16_t last_log_num,uint32_t time_utc,uint32_t size) + mavlink_message_t* msg, + uint16_t id,uint16_t num_logs,uint16_t last_log_num,uint32_t time_utc,uint32_t size) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_ENTRY_LEN]; - _mav_put_uint32_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 4, size); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint16_t(buf, 10, num_logs); - _mav_put_uint16_t(buf, 12, last_log_num); + char buf[MAVLINK_MSG_ID_LOG_ENTRY_LEN]; + _mav_put_uint32_t(buf, 0, time_utc); + _mav_put_uint32_t(buf, 4, size); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint16_t(buf, 10, num_logs); + _mav_put_uint16_t(buf, 12, last_log_num); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_ENTRY_LEN); #else - mavlink_log_entry_t packet; - packet.time_utc = time_utc; - packet.size = size; - packet.id = id; - packet.num_logs = num_logs; - packet.last_log_num = last_log_num; + mavlink_log_entry_t packet; + packet.time_utc = time_utc; + packet.size = size; + packet.id = id; + packet.num_logs = num_logs; + packet.last_log_num = last_log_num; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_ENTRY_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_ENTRY; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_ENTRY_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_ENTRY; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); } /** @@ -130,7 +138,7 @@ static inline uint16_t mavlink_msg_log_entry_pack_chan(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_log_entry_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_log_entry_t* log_entry) { - return mavlink_msg_log_entry_pack(system_id, component_id, msg, log_entry->id, log_entry->num_logs, log_entry->last_log_num, log_entry->time_utc, log_entry->size); + return mavlink_msg_log_entry_pack(system_id, component_id, msg, log_entry->id, log_entry->num_logs, log_entry->last_log_num, log_entry->time_utc, log_entry->size); } /** @@ -144,7 +152,7 @@ static inline uint16_t mavlink_msg_log_entry_encode(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_log_entry_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_log_entry_t* log_entry) { - return mavlink_msg_log_entry_pack_chan(system_id, component_id, chan, msg, log_entry->id, log_entry->num_logs, log_entry->last_log_num, log_entry->time_utc, log_entry->size); + return mavlink_msg_log_entry_pack_chan(system_id, component_id, chan, msg, log_entry->id, log_entry->num_logs, log_entry->last_log_num, log_entry->time_utc, log_entry->size); } /** @@ -162,31 +170,37 @@ static inline uint16_t mavlink_msg_log_entry_encode_chan(uint8_t system_id, uint static inline void mavlink_msg_log_entry_send(mavlink_channel_t chan, uint16_t id, uint16_t num_logs, uint16_t last_log_num, uint32_t time_utc, uint32_t size) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_ENTRY_LEN]; - _mav_put_uint32_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 4, size); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint16_t(buf, 10, num_logs); - _mav_put_uint16_t(buf, 12, last_log_num); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, buf, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); + char buf[MAVLINK_MSG_ID_LOG_ENTRY_LEN]; + _mav_put_uint32_t(buf, 0, time_utc); + _mav_put_uint32_t(buf, 4, size); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint16_t(buf, 10, num_logs); + _mav_put_uint16_t(buf, 12, last_log_num); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, buf, MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, buf, MAVLINK_MSG_ID_LOG_ENTRY_LEN); + mavlink_log_entry_t packet; + packet.time_utc = time_utc; + packet.size = size; + packet.id = id; + packet.num_logs = num_logs; + packet.last_log_num = last_log_num; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, (const char *)&packet, MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); #endif +} + +/** + * @brief Send a log_entry message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_log_entry_send_struct(mavlink_channel_t chan, const mavlink_log_entry_t* log_entry) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_log_entry_send(chan, log_entry->id, log_entry->num_logs, log_entry->last_log_num, log_entry->time_utc, log_entry->size); #else - mavlink_log_entry_t packet; - packet.time_utc = time_utc; - packet.size = size; - packet.id = id; - packet.num_logs = num_logs; - packet.last_log_num = last_log_num; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, (const char *)&packet, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, (const char *)&packet, MAVLINK_MSG_ID_LOG_ENTRY_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, (const char *)log_entry, MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); #endif } @@ -201,31 +215,23 @@ static inline void mavlink_msg_log_entry_send(mavlink_channel_t chan, uint16_t i static inline void mavlink_msg_log_entry_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t id, uint16_t num_logs, uint16_t last_log_num, uint32_t time_utc, uint32_t size) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_utc); - _mav_put_uint32_t(buf, 4, size); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint16_t(buf, 10, num_logs); - _mav_put_uint16_t(buf, 12, last_log_num); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, buf, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_utc); + _mav_put_uint32_t(buf, 4, size); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint16_t(buf, 10, num_logs); + _mav_put_uint16_t(buf, 12, last_log_num); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, buf, MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, buf, MAVLINK_MSG_ID_LOG_ENTRY_LEN); -#endif -#else - mavlink_log_entry_t *packet = (mavlink_log_entry_t *)msgbuf; - packet->time_utc = time_utc; - packet->size = size; - packet->id = id; - packet->num_logs = num_logs; - packet->last_log_num = last_log_num; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, (const char *)packet, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, (const char *)packet, MAVLINK_MSG_ID_LOG_ENTRY_LEN); -#endif + mavlink_log_entry_t *packet = (mavlink_log_entry_t *)msgbuf; + packet->time_utc = time_utc; + packet->size = size; + packet->id = id; + packet->num_logs = num_logs; + packet->last_log_num = last_log_num; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ENTRY, (const char *)packet, MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN, MAVLINK_MSG_ID_LOG_ENTRY_LEN, MAVLINK_MSG_ID_LOG_ENTRY_CRC); #endif } #endif @@ -242,7 +248,7 @@ static inline void mavlink_msg_log_entry_send_buf(mavlink_message_t *msgbuf, mav */ static inline uint16_t mavlink_msg_log_entry_get_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -252,7 +258,7 @@ static inline uint16_t mavlink_msg_log_entry_get_id(const mavlink_message_t* msg */ static inline uint16_t mavlink_msg_log_entry_get_num_logs(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 10); + return _MAV_RETURN_uint16_t(msg, 10); } /** @@ -262,7 +268,7 @@ static inline uint16_t mavlink_msg_log_entry_get_num_logs(const mavlink_message_ */ static inline uint16_t mavlink_msg_log_entry_get_last_log_num(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -272,7 +278,7 @@ static inline uint16_t mavlink_msg_log_entry_get_last_log_num(const mavlink_mess */ static inline uint32_t mavlink_msg_log_entry_get_time_utc(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -282,7 +288,7 @@ static inline uint32_t mavlink_msg_log_entry_get_time_utc(const mavlink_message_ */ static inline uint32_t mavlink_msg_log_entry_get_size(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 4); + return _MAV_RETURN_uint32_t(msg, 4); } /** @@ -293,13 +299,15 @@ static inline uint32_t mavlink_msg_log_entry_get_size(const mavlink_message_t* m */ static inline void mavlink_msg_log_entry_decode(const mavlink_message_t* msg, mavlink_log_entry_t* log_entry) { -#if MAVLINK_NEED_BYTE_SWAP - log_entry->time_utc = mavlink_msg_log_entry_get_time_utc(msg); - log_entry->size = mavlink_msg_log_entry_get_size(msg); - log_entry->id = mavlink_msg_log_entry_get_id(msg); - log_entry->num_logs = mavlink_msg_log_entry_get_num_logs(msg); - log_entry->last_log_num = mavlink_msg_log_entry_get_last_log_num(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + log_entry->time_utc = mavlink_msg_log_entry_get_time_utc(msg); + log_entry->size = mavlink_msg_log_entry_get_size(msg); + log_entry->id = mavlink_msg_log_entry_get_id(msg); + log_entry->num_logs = mavlink_msg_log_entry_get_num_logs(msg); + log_entry->last_log_num = mavlink_msg_log_entry_get_last_log_num(msg); #else - memcpy(log_entry, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOG_ENTRY_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOG_ENTRY_LEN? msg->len : MAVLINK_MSG_ID_LOG_ENTRY_LEN; + memset(log_entry, 0, MAVLINK_MSG_ID_LOG_ENTRY_LEN); + memcpy(log_entry, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_log_erase.h b/vendor/libraries/mavlink/common/mavlink_msg_log_erase.h index 957c4d4cc0..d603771c94 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_log_erase.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_log_erase.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE LOG_ERASE PACKING #define MAVLINK_MSG_ID_LOG_ERASE 121 -typedef struct __mavlink_log_erase_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_log_erase_t; +MAVPACKED( +typedef struct __mavlink_log_erase_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_log_erase_t; #define MAVLINK_MSG_ID_LOG_ERASE_LEN 2 +#define MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN 2 #define MAVLINK_MSG_ID_121_LEN 2 +#define MAVLINK_MSG_ID_121_MIN_LEN 2 #define MAVLINK_MSG_ID_LOG_ERASE_CRC 237 #define MAVLINK_MSG_ID_121_CRC 237 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOG_ERASE { \ - "LOG_ERASE", \ - 2, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_log_erase_t, target_system) }, \ + 121, \ + "LOG_ERASE", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_log_erase_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_log_erase_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOG_ERASE { \ + "LOG_ERASE", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_log_erase_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_log_erase_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a log_erase message @@ -36,28 +49,24 @@ typedef struct __mavlink_log_erase_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_erase_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component) + uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_ERASE_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_LOG_ERASE_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_ERASE_LEN); #else - mavlink_log_erase_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_erase_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_ERASE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_ERASE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_ERASE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_ERASE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_log_erase_pack(uint8_t system_id, uint8_t com * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_erase_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_ERASE_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_LOG_ERASE_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_ERASE_LEN); #else - mavlink_log_erase_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_erase_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_ERASE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_ERASE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_ERASE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_ERASE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_log_erase_pack_chan(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_log_erase_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_log_erase_t* log_erase) { - return mavlink_msg_log_erase_pack(system_id, component_id, msg, log_erase->target_system, log_erase->target_component); + return mavlink_msg_log_erase_pack(system_id, component_id, msg, log_erase->target_system, log_erase->target_component); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_log_erase_encode(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_log_erase_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_log_erase_t* log_erase) { - return mavlink_msg_log_erase_pack_chan(system_id, component_id, chan, msg, log_erase->target_system, log_erase->target_component); + return mavlink_msg_log_erase_pack_chan(system_id, component_id, chan, msg, log_erase->target_system, log_erase->target_component); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_log_erase_encode_chan(uint8_t system_id, uint static inline void mavlink_msg_log_erase_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_ERASE_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_LOG_ERASE_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, buf, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, buf, MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, buf, MAVLINK_MSG_ID_LOG_ERASE_LEN); + mavlink_log_erase_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, (const char *)&packet, MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); #endif -#else - mavlink_log_erase_t packet; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, (const char *)&packet, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); +/** + * @brief Send a log_erase message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_log_erase_send_struct(mavlink_channel_t chan, const mavlink_log_erase_t* log_erase) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_log_erase_send(chan, log_erase->target_system, log_erase->target_component); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, (const char *)&packet, MAVLINK_MSG_ID_LOG_ERASE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, (const char *)log_erase, MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_log_erase_send(mavlink_channel_t chan, uint8_t ta static inline void mavlink_msg_log_erase_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, buf, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, buf, MAVLINK_MSG_ID_LOG_ERASE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, buf, MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); #else - mavlink_log_erase_t *packet = (mavlink_log_erase_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_log_erase_t *packet = (mavlink_log_erase_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, (const char *)packet, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, (const char *)packet, MAVLINK_MSG_ID_LOG_ERASE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_ERASE, (const char *)packet, MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN, MAVLINK_MSG_ID_LOG_ERASE_LEN, MAVLINK_MSG_ID_LOG_ERASE_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_log_erase_send_buf(mavlink_message_t *msgbuf, mav */ static inline uint8_t mavlink_msg_log_erase_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint8_t mavlink_msg_log_erase_get_target_system(const mavlink_mess */ static inline uint8_t mavlink_msg_log_erase_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_log_erase_get_target_component(const mavlink_m */ static inline void mavlink_msg_log_erase_decode(const mavlink_message_t* msg, mavlink_log_erase_t* log_erase) { -#if MAVLINK_NEED_BYTE_SWAP - log_erase->target_system = mavlink_msg_log_erase_get_target_system(msg); - log_erase->target_component = mavlink_msg_log_erase_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + log_erase->target_system = mavlink_msg_log_erase_get_target_system(msg); + log_erase->target_component = mavlink_msg_log_erase_get_target_component(msg); #else - memcpy(log_erase, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOG_ERASE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOG_ERASE_LEN? msg->len : MAVLINK_MSG_ID_LOG_ERASE_LEN; + memset(log_erase, 0, MAVLINK_MSG_ID_LOG_ERASE_LEN); + memcpy(log_erase, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_log_request_data.h b/vendor/libraries/mavlink/common/mavlink_msg_log_request_data.h index ef5cbb67cb..3fb3d62e49 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_log_request_data.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_log_request_data.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE LOG_REQUEST_DATA PACKING #define MAVLINK_MSG_ID_LOG_REQUEST_DATA 119 -typedef struct __mavlink_log_request_data_t -{ - uint32_t ofs; ///< Offset into the log - uint32_t count; ///< Number of bytes - uint16_t id; ///< Log id (from LOG_ENTRY reply) - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_log_request_data_t; +MAVPACKED( +typedef struct __mavlink_log_request_data_t { + uint32_t ofs; /*< Offset into the log*/ + uint32_t count; /*< Number of bytes*/ + uint16_t id; /*< Log id (from LOG_ENTRY reply)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_log_request_data_t; #define MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN 12 +#define MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN 12 #define MAVLINK_MSG_ID_119_LEN 12 +#define MAVLINK_MSG_ID_119_MIN_LEN 12 #define MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC 116 #define MAVLINK_MSG_ID_119_CRC 116 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOG_REQUEST_DATA { \ - "LOG_REQUEST_DATA", \ - 5, \ - { { "ofs", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_request_data_t, ofs) }, \ + 119, \ + "LOG_REQUEST_DATA", \ + 5, \ + { { "ofs", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_request_data_t, ofs) }, \ { "count", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_log_request_data_t, count) }, \ { "id", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_log_request_data_t, id) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_log_request_data_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_log_request_data_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOG_REQUEST_DATA { \ + "LOG_REQUEST_DATA", \ + 5, \ + { { "ofs", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_log_request_data_t, ofs) }, \ + { "count", NULL, MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_log_request_data_t, count) }, \ + { "id", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_log_request_data_t, id) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_log_request_data_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 11, offsetof(mavlink_log_request_data_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a log_request_data message @@ -45,34 +61,30 @@ typedef struct __mavlink_log_request_data_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_request_data_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t id, uint32_t ofs, uint32_t count) + uint8_t target_system, uint8_t target_component, uint16_t id, uint32_t ofs, uint32_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN]; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint32_t(buf, 4, count); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint8_t(buf, 10, target_system); - _mav_put_uint8_t(buf, 11, target_component); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN]; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint32_t(buf, 4, count); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint8_t(buf, 10, target_system); + _mav_put_uint8_t(buf, 11, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); #else - mavlink_log_request_data_t packet; - packet.ofs = ofs; - packet.count = count; - packet.id = id; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_request_data_t packet; + packet.ofs = ofs; + packet.count = count; + packet.id = id; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_DATA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); } /** @@ -89,35 +101,31 @@ static inline uint16_t mavlink_msg_log_request_data_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_request_data_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t id,uint32_t ofs,uint32_t count) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t id,uint32_t ofs,uint32_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN]; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint32_t(buf, 4, count); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint8_t(buf, 10, target_system); - _mav_put_uint8_t(buf, 11, target_component); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN]; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint32_t(buf, 4, count); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint8_t(buf, 10, target_system); + _mav_put_uint8_t(buf, 11, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); #else - mavlink_log_request_data_t packet; - packet.ofs = ofs; - packet.count = count; - packet.id = id; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_request_data_t packet; + packet.ofs = ofs; + packet.count = count; + packet.id = id; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_DATA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); } /** @@ -130,7 +138,7 @@ static inline uint16_t mavlink_msg_log_request_data_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_log_request_data_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_log_request_data_t* log_request_data) { - return mavlink_msg_log_request_data_pack(system_id, component_id, msg, log_request_data->target_system, log_request_data->target_component, log_request_data->id, log_request_data->ofs, log_request_data->count); + return mavlink_msg_log_request_data_pack(system_id, component_id, msg, log_request_data->target_system, log_request_data->target_component, log_request_data->id, log_request_data->ofs, log_request_data->count); } /** @@ -144,7 +152,7 @@ static inline uint16_t mavlink_msg_log_request_data_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_log_request_data_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_log_request_data_t* log_request_data) { - return mavlink_msg_log_request_data_pack_chan(system_id, component_id, chan, msg, log_request_data->target_system, log_request_data->target_component, log_request_data->id, log_request_data->ofs, log_request_data->count); + return mavlink_msg_log_request_data_pack_chan(system_id, component_id, chan, msg, log_request_data->target_system, log_request_data->target_component, log_request_data->id, log_request_data->ofs, log_request_data->count); } /** @@ -162,31 +170,37 @@ static inline uint16_t mavlink_msg_log_request_data_encode_chan(uint8_t system_i static inline void mavlink_msg_log_request_data_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t id, uint32_t ofs, uint32_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN]; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint32_t(buf, 4, count); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint8_t(buf, 10, target_system); - _mav_put_uint8_t(buf, 11, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN]; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint32_t(buf, 4, count); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint8_t(buf, 10, target_system); + _mav_put_uint8_t(buf, 11, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); + mavlink_log_request_data_t packet; + packet.ofs = ofs; + packet.count = count; + packet.id = id; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); #endif +} + +/** + * @brief Send a log_request_data message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_log_request_data_send_struct(mavlink_channel_t chan, const mavlink_log_request_data_t* log_request_data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_log_request_data_send(chan, log_request_data->target_system, log_request_data->target_component, log_request_data->id, log_request_data->ofs, log_request_data->count); #else - mavlink_log_request_data_t packet; - packet.ofs = ofs; - packet.count = count; - packet.id = id; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, (const char *)log_request_data, MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); #endif } @@ -201,31 +215,23 @@ static inline void mavlink_msg_log_request_data_send(mavlink_channel_t chan, uin static inline void mavlink_msg_log_request_data_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t id, uint32_t ofs, uint32_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, ofs); - _mav_put_uint32_t(buf, 4, count); - _mav_put_uint16_t(buf, 8, id); - _mav_put_uint8_t(buf, 10, target_system); - _mav_put_uint8_t(buf, 11, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, ofs); + _mav_put_uint32_t(buf, 4, count); + _mav_put_uint16_t(buf, 8, id); + _mav_put_uint8_t(buf, 10, target_system); + _mav_put_uint8_t(buf, 11, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, buf, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); -#endif -#else - mavlink_log_request_data_t *packet = (mavlink_log_request_data_t *)msgbuf; - packet->ofs = ofs; - packet->count = count; - packet->id = id; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); -#endif + mavlink_log_request_data_t *packet = (mavlink_log_request_data_t *)msgbuf; + packet->ofs = ofs; + packet->count = count; + packet->id = id; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_DATA, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN, MAVLINK_MSG_ID_LOG_REQUEST_DATA_CRC); #endif } #endif @@ -242,7 +248,7 @@ static inline void mavlink_msg_log_request_data_send_buf(mavlink_message_t *msgb */ static inline uint8_t mavlink_msg_log_request_data_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 10); + return _MAV_RETURN_uint8_t(msg, 10); } /** @@ -252,7 +258,7 @@ static inline uint8_t mavlink_msg_log_request_data_get_target_system(const mavli */ static inline uint8_t mavlink_msg_log_request_data_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 11); + return _MAV_RETURN_uint8_t(msg, 11); } /** @@ -262,7 +268,7 @@ static inline uint8_t mavlink_msg_log_request_data_get_target_component(const ma */ static inline uint16_t mavlink_msg_log_request_data_get_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -272,7 +278,7 @@ static inline uint16_t mavlink_msg_log_request_data_get_id(const mavlink_message */ static inline uint32_t mavlink_msg_log_request_data_get_ofs(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -282,7 +288,7 @@ static inline uint32_t mavlink_msg_log_request_data_get_ofs(const mavlink_messag */ static inline uint32_t mavlink_msg_log_request_data_get_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 4); + return _MAV_RETURN_uint32_t(msg, 4); } /** @@ -293,13 +299,15 @@ static inline uint32_t mavlink_msg_log_request_data_get_count(const mavlink_mess */ static inline void mavlink_msg_log_request_data_decode(const mavlink_message_t* msg, mavlink_log_request_data_t* log_request_data) { -#if MAVLINK_NEED_BYTE_SWAP - log_request_data->ofs = mavlink_msg_log_request_data_get_ofs(msg); - log_request_data->count = mavlink_msg_log_request_data_get_count(msg); - log_request_data->id = mavlink_msg_log_request_data_get_id(msg); - log_request_data->target_system = mavlink_msg_log_request_data_get_target_system(msg); - log_request_data->target_component = mavlink_msg_log_request_data_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + log_request_data->ofs = mavlink_msg_log_request_data_get_ofs(msg); + log_request_data->count = mavlink_msg_log_request_data_get_count(msg); + log_request_data->id = mavlink_msg_log_request_data_get_id(msg); + log_request_data->target_system = mavlink_msg_log_request_data_get_target_system(msg); + log_request_data->target_component = mavlink_msg_log_request_data_get_target_component(msg); #else - memcpy(log_request_data, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN? msg->len : MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN; + memset(log_request_data, 0, MAVLINK_MSG_ID_LOG_REQUEST_DATA_LEN); + memcpy(log_request_data, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_log_request_end.h b/vendor/libraries/mavlink/common/mavlink_msg_log_request_end.h index 23fcca29f7..dc0c1e59af 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_log_request_end.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_log_request_end.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE LOG_REQUEST_END PACKING #define MAVLINK_MSG_ID_LOG_REQUEST_END 122 -typedef struct __mavlink_log_request_end_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_log_request_end_t; +MAVPACKED( +typedef struct __mavlink_log_request_end_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_log_request_end_t; #define MAVLINK_MSG_ID_LOG_REQUEST_END_LEN 2 +#define MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN 2 #define MAVLINK_MSG_ID_122_LEN 2 +#define MAVLINK_MSG_ID_122_MIN_LEN 2 #define MAVLINK_MSG_ID_LOG_REQUEST_END_CRC 203 #define MAVLINK_MSG_ID_122_CRC 203 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOG_REQUEST_END { \ - "LOG_REQUEST_END", \ - 2, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_log_request_end_t, target_system) }, \ + 122, \ + "LOG_REQUEST_END", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_log_request_end_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_log_request_end_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOG_REQUEST_END { \ + "LOG_REQUEST_END", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_log_request_end_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_log_request_end_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a log_request_end message @@ -36,28 +49,24 @@ typedef struct __mavlink_log_request_end_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_request_end_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component) + uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_END_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_END_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); #else - mavlink_log_request_end_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_request_end_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_END; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_END; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_log_request_end_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_request_end_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_END_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_END_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); #else - mavlink_log_request_end_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_request_end_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_END; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_END; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_log_request_end_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_log_request_end_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_log_request_end_t* log_request_end) { - return mavlink_msg_log_request_end_pack(system_id, component_id, msg, log_request_end->target_system, log_request_end->target_component); + return mavlink_msg_log_request_end_pack(system_id, component_id, msg, log_request_end->target_system, log_request_end->target_component); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_log_request_end_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_log_request_end_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_log_request_end_t* log_request_end) { - return mavlink_msg_log_request_end_pack_chan(system_id, component_id, chan, msg, log_request_end->target_system, log_request_end->target_component); + return mavlink_msg_log_request_end_pack_chan(system_id, component_id, chan, msg, log_request_end->target_system, log_request_end->target_component); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_log_request_end_encode_chan(uint8_t system_id static inline void mavlink_msg_log_request_end_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_END_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_END_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, buf, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, buf, MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, buf, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); + mavlink_log_request_end_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); #endif -#else - mavlink_log_request_end_t packet; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); +/** + * @brief Send a log_request_end message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_log_request_end_send_struct(mavlink_channel_t chan, const mavlink_log_request_end_t* log_request_end) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_log_request_end_send(chan, log_request_end->target_system, log_request_end->target_component); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, (const char *)log_request_end, MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_log_request_end_send(mavlink_channel_t chan, uint static inline void mavlink_msg_log_request_end_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, buf, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, buf, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, buf, MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); #else - mavlink_log_request_end_t *packet = (mavlink_log_request_end_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_log_request_end_t *packet = (mavlink_log_request_end_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_END, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN, MAVLINK_MSG_ID_LOG_REQUEST_END_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_log_request_end_send_buf(mavlink_message_t *msgbu */ static inline uint8_t mavlink_msg_log_request_end_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint8_t mavlink_msg_log_request_end_get_target_system(const mavlin */ static inline uint8_t mavlink_msg_log_request_end_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_log_request_end_get_target_component(const mav */ static inline void mavlink_msg_log_request_end_decode(const mavlink_message_t* msg, mavlink_log_request_end_t* log_request_end) { -#if MAVLINK_NEED_BYTE_SWAP - log_request_end->target_system = mavlink_msg_log_request_end_get_target_system(msg); - log_request_end->target_component = mavlink_msg_log_request_end_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + log_request_end->target_system = mavlink_msg_log_request_end_get_target_system(msg); + log_request_end->target_component = mavlink_msg_log_request_end_get_target_component(msg); #else - memcpy(log_request_end, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOG_REQUEST_END_LEN? msg->len : MAVLINK_MSG_ID_LOG_REQUEST_END_LEN; + memset(log_request_end, 0, MAVLINK_MSG_ID_LOG_REQUEST_END_LEN); + memcpy(log_request_end, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_log_request_list.h b/vendor/libraries/mavlink/common/mavlink_msg_log_request_list.h index e511b53125..f4b00c9952 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_log_request_list.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_log_request_list.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE LOG_REQUEST_LIST PACKING #define MAVLINK_MSG_ID_LOG_REQUEST_LIST 117 -typedef struct __mavlink_log_request_list_t -{ - uint16_t start; ///< First log id (0 for first available) - uint16_t end; ///< Last log id (0xffff for last available) - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_log_request_list_t; +MAVPACKED( +typedef struct __mavlink_log_request_list_t { + uint16_t start; /*< First log id (0 for first available)*/ + uint16_t end; /*< Last log id (0xffff for last available)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_log_request_list_t; #define MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN 6 +#define MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN 6 #define MAVLINK_MSG_ID_117_LEN 6 +#define MAVLINK_MSG_ID_117_MIN_LEN 6 #define MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC 128 #define MAVLINK_MSG_ID_117_CRC 128 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_LOG_REQUEST_LIST { \ - "LOG_REQUEST_LIST", \ - 4, \ - { { "start", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_log_request_list_t, start) }, \ + 117, \ + "LOG_REQUEST_LIST", \ + 4, \ + { { "start", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_log_request_list_t, start) }, \ { "end", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_log_request_list_t, end) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_log_request_list_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_log_request_list_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_LOG_REQUEST_LIST { \ + "LOG_REQUEST_LIST", \ + 4, \ + { { "start", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_log_request_list_t, start) }, \ + { "end", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_log_request_list_t, end) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_log_request_list_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_log_request_list_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a log_request_list message @@ -42,32 +57,28 @@ typedef struct __mavlink_log_request_list_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_request_list_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t start, uint16_t end) + uint8_t target_system, uint8_t target_component, uint16_t start, uint16_t end) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN]; - _mav_put_uint16_t(buf, 0, start); - _mav_put_uint16_t(buf, 2, end); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN]; + _mav_put_uint16_t(buf, 0, start); + _mav_put_uint16_t(buf, 2, end); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); #else - mavlink_log_request_list_t packet; - packet.start = start; - packet.end = end; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_request_list_t packet; + packet.start = start; + packet.end = end; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_LIST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_log_request_list_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_log_request_list_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t start,uint16_t end) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t start,uint16_t end) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN]; - _mav_put_uint16_t(buf, 0, start); - _mav_put_uint16_t(buf, 2, end); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN]; + _mav_put_uint16_t(buf, 0, start); + _mav_put_uint16_t(buf, 2, end); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); #else - mavlink_log_request_list_t packet; - packet.start = start; - packet.end = end; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_log_request_list_t packet; + packet.start = start; + packet.end = end; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_LOG_REQUEST_LIST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_log_request_list_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_log_request_list_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_log_request_list_t* log_request_list) { - return mavlink_msg_log_request_list_pack(system_id, component_id, msg, log_request_list->target_system, log_request_list->target_component, log_request_list->start, log_request_list->end); + return mavlink_msg_log_request_list_pack(system_id, component_id, msg, log_request_list->target_system, log_request_list->target_component, log_request_list->start, log_request_list->end); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_log_request_list_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_log_request_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_log_request_list_t* log_request_list) { - return mavlink_msg_log_request_list_pack_chan(system_id, component_id, chan, msg, log_request_list->target_system, log_request_list->target_component, log_request_list->start, log_request_list->end); + return mavlink_msg_log_request_list_pack_chan(system_id, component_id, chan, msg, log_request_list->target_system, log_request_list->target_component, log_request_list->start, log_request_list->end); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_log_request_list_encode_chan(uint8_t system_i static inline void mavlink_msg_log_request_list_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t start, uint16_t end) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN]; - _mav_put_uint16_t(buf, 0, start); - _mav_put_uint16_t(buf, 2, end); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); + char buf[MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN]; + _mav_put_uint16_t(buf, 0, start); + _mav_put_uint16_t(buf, 2, end); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); + mavlink_log_request_list_t packet; + packet.start = start; + packet.end = end; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); #endif +} + +/** + * @brief Send a log_request_list message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_log_request_list_send_struct(mavlink_channel_t chan, const mavlink_log_request_list_t* log_request_list) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_log_request_list_send(chan, log_request_list->target_system, log_request_list->target_component, log_request_list->start, log_request_list->end); #else - mavlink_log_request_list_t packet; - packet.start = start; - packet.end = end; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, (const char *)log_request_list, MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_log_request_list_send(mavlink_channel_t chan, uin static inline void mavlink_msg_log_request_list_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t start, uint16_t end) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, start); - _mav_put_uint16_t(buf, 2, end); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); -#endif -#else - mavlink_log_request_list_t *packet = (mavlink_log_request_list_t *)msgbuf; - packet->start = start; - packet->end = end; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, start); + _mav_put_uint16_t(buf, 2, end); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, buf, MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); -#endif + mavlink_log_request_list_t *packet = (mavlink_log_request_list_t *)msgbuf; + packet->start = start; + packet->end = end; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_LOG_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN, MAVLINK_MSG_ID_LOG_REQUEST_LIST_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_log_request_list_send_buf(mavlink_message_t *msgb */ static inline uint8_t mavlink_msg_log_request_list_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -239,7 +244,7 @@ static inline uint8_t mavlink_msg_log_request_list_get_target_system(const mavli */ static inline uint8_t mavlink_msg_log_request_list_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -249,7 +254,7 @@ static inline uint8_t mavlink_msg_log_request_list_get_target_component(const ma */ static inline uint16_t mavlink_msg_log_request_list_get_start(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -259,7 +264,7 @@ static inline uint16_t mavlink_msg_log_request_list_get_start(const mavlink_mess */ static inline uint16_t mavlink_msg_log_request_list_get_end(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 2); + return _MAV_RETURN_uint16_t(msg, 2); } /** @@ -270,12 +275,14 @@ static inline uint16_t mavlink_msg_log_request_list_get_end(const mavlink_messag */ static inline void mavlink_msg_log_request_list_decode(const mavlink_message_t* msg, mavlink_log_request_list_t* log_request_list) { -#if MAVLINK_NEED_BYTE_SWAP - log_request_list->start = mavlink_msg_log_request_list_get_start(msg); - log_request_list->end = mavlink_msg_log_request_list_get_end(msg); - log_request_list->target_system = mavlink_msg_log_request_list_get_target_system(msg); - log_request_list->target_component = mavlink_msg_log_request_list_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + log_request_list->start = mavlink_msg_log_request_list_get_start(msg); + log_request_list->end = mavlink_msg_log_request_list_get_end(msg); + log_request_list->target_system = mavlink_msg_log_request_list_get_target_system(msg); + log_request_list->target_component = mavlink_msg_log_request_list_get_target_component(msg); #else - memcpy(log_request_list, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN? msg->len : MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN; + memset(log_request_list, 0, MAVLINK_MSG_ID_LOG_REQUEST_LIST_LEN); + memcpy(log_request_list, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_manual_control.h b/vendor/libraries/mavlink/common/mavlink_msg_manual_control.h index e93b759d0a..05a25665d4 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_manual_control.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_manual_control.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE MANUAL_CONTROL PACKING #define MAVLINK_MSG_ID_MANUAL_CONTROL 69 -typedef struct __mavlink_manual_control_t -{ - int16_t x; ///< X-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to forward(1000)-backward(-1000) movement on a joystick and the pitch of a vehicle. - int16_t y; ///< Y-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to left(-1000)-right(1000) movement on a joystick and the roll of a vehicle. - int16_t z; ///< Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. - int16_t r; ///< R-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a twisting of the joystick, with counter-clockwise being 1000 and clockwise being -1000, and the yaw of a vehicle. - uint16_t buttons; ///< A bitfield corresponding to the joystick buttons' current state, 1 for pressed, 0 for released. The lowest bit corresponds to Button 1. - uint8_t target; ///< The system to be controlled. -} mavlink_manual_control_t; +MAVPACKED( +typedef struct __mavlink_manual_control_t { + int16_t x; /*< X-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to forward(1000)-backward(-1000) movement on a joystick and the pitch of a vehicle.*/ + int16_t y; /*< Y-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to left(-1000)-right(1000) movement on a joystick and the roll of a vehicle.*/ + int16_t z; /*< Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. Positive values are positive thrust, negative values are negative thrust.*/ + int16_t r; /*< R-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a twisting of the joystick, with counter-clockwise being 1000 and clockwise being -1000, and the yaw of a vehicle.*/ + uint16_t buttons; /*< A bitfield corresponding to the joystick buttons' current state, 1 for pressed, 0 for released. The lowest bit corresponds to Button 1.*/ + uint8_t target; /*< The system to be controlled.*/ +}) mavlink_manual_control_t; #define MAVLINK_MSG_ID_MANUAL_CONTROL_LEN 11 +#define MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN 11 #define MAVLINK_MSG_ID_69_LEN 11 +#define MAVLINK_MSG_ID_69_MIN_LEN 11 #define MAVLINK_MSG_ID_MANUAL_CONTROL_CRC 243 #define MAVLINK_MSG_ID_69_CRC 243 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MANUAL_CONTROL { \ - "MANUAL_CONTROL", \ - 6, \ - { { "x", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_manual_control_t, x) }, \ + 69, \ + "MANUAL_CONTROL", \ + 6, \ + { { "x", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_manual_control_t, x) }, \ { "y", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_manual_control_t, y) }, \ { "z", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_manual_control_t, z) }, \ { "r", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_manual_control_t, r) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_manual_control_t { "target", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_manual_control_t, target) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MANUAL_CONTROL { \ + "MANUAL_CONTROL", \ + 6, \ + { { "x", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_manual_control_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_manual_control_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_manual_control_t, z) }, \ + { "r", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_manual_control_t, r) }, \ + { "buttons", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_manual_control_t, buttons) }, \ + { "target", NULL, MAVLINK_TYPE_UINT8_T, 0, 10, offsetof(mavlink_manual_control_t, target) }, \ + } \ +} +#endif /** * @brief Pack a manual_control message @@ -42,42 +59,38 @@ typedef struct __mavlink_manual_control_t * @param target The system to be controlled. * @param x X-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to forward(1000)-backward(-1000) movement on a joystick and the pitch of a vehicle. * @param y Y-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to left(-1000)-right(1000) movement on a joystick and the roll of a vehicle. - * @param z Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. + * @param z Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. Positive values are positive thrust, negative values are negative thrust. * @param r R-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a twisting of the joystick, with counter-clockwise being 1000 and clockwise being -1000, and the yaw of a vehicle. * @param buttons A bitfield corresponding to the joystick buttons' current state, 1 for pressed, 0 for released. The lowest bit corresponds to Button 1. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_manual_control_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target, int16_t x, int16_t y, int16_t z, int16_t r, uint16_t buttons) + uint8_t target, int16_t x, int16_t y, int16_t z, int16_t r, uint16_t buttons) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MANUAL_CONTROL_LEN]; - _mav_put_int16_t(buf, 0, x); - _mav_put_int16_t(buf, 2, y); - _mav_put_int16_t(buf, 4, z); - _mav_put_int16_t(buf, 6, r); - _mav_put_uint16_t(buf, 8, buttons); - _mav_put_uint8_t(buf, 10, target); + char buf[MAVLINK_MSG_ID_MANUAL_CONTROL_LEN]; + _mav_put_int16_t(buf, 0, x); + _mav_put_int16_t(buf, 2, y); + _mav_put_int16_t(buf, 4, z); + _mav_put_int16_t(buf, 6, r); + _mav_put_uint16_t(buf, 8, buttons); + _mav_put_uint8_t(buf, 10, target); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); #else - mavlink_manual_control_t packet; - packet.x = x; - packet.y = y; - packet.z = z; - packet.r = r; - packet.buttons = buttons; - packet.target = target; + mavlink_manual_control_t packet; + packet.x = x; + packet.y = y; + packet.z = z; + packet.r = r; + packet.buttons = buttons; + packet.target = target; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MANUAL_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MANUAL_CONTROL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); } /** @@ -89,43 +102,39 @@ static inline uint16_t mavlink_msg_manual_control_pack(uint8_t system_id, uint8_ * @param target The system to be controlled. * @param x X-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to forward(1000)-backward(-1000) movement on a joystick and the pitch of a vehicle. * @param y Y-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to left(-1000)-right(1000) movement on a joystick and the roll of a vehicle. - * @param z Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. + * @param z Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. Positive values are positive thrust, negative values are negative thrust. * @param r R-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a twisting of the joystick, with counter-clockwise being 1000 and clockwise being -1000, and the yaw of a vehicle. * @param buttons A bitfield corresponding to the joystick buttons' current state, 1 for pressed, 0 for released. The lowest bit corresponds to Button 1. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_manual_control_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target,int16_t x,int16_t y,int16_t z,int16_t r,uint16_t buttons) + mavlink_message_t* msg, + uint8_t target,int16_t x,int16_t y,int16_t z,int16_t r,uint16_t buttons) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MANUAL_CONTROL_LEN]; - _mav_put_int16_t(buf, 0, x); - _mav_put_int16_t(buf, 2, y); - _mav_put_int16_t(buf, 4, z); - _mav_put_int16_t(buf, 6, r); - _mav_put_uint16_t(buf, 8, buttons); - _mav_put_uint8_t(buf, 10, target); + char buf[MAVLINK_MSG_ID_MANUAL_CONTROL_LEN]; + _mav_put_int16_t(buf, 0, x); + _mav_put_int16_t(buf, 2, y); + _mav_put_int16_t(buf, 4, z); + _mav_put_int16_t(buf, 6, r); + _mav_put_uint16_t(buf, 8, buttons); + _mav_put_uint8_t(buf, 10, target); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); #else - mavlink_manual_control_t packet; - packet.x = x; - packet.y = y; - packet.z = z; - packet.r = r; - packet.buttons = buttons; - packet.target = target; + mavlink_manual_control_t packet; + packet.x = x; + packet.y = y; + packet.z = z; + packet.r = r; + packet.buttons = buttons; + packet.target = target; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MANUAL_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MANUAL_CONTROL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_manual_control_pack_chan(uint8_t system_id, u */ static inline uint16_t mavlink_msg_manual_control_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_manual_control_t* manual_control) { - return mavlink_msg_manual_control_pack(system_id, component_id, msg, manual_control->target, manual_control->x, manual_control->y, manual_control->z, manual_control->r, manual_control->buttons); + return mavlink_msg_manual_control_pack(system_id, component_id, msg, manual_control->target, manual_control->x, manual_control->y, manual_control->z, manual_control->r, manual_control->buttons); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_manual_control_encode(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_manual_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_manual_control_t* manual_control) { - return mavlink_msg_manual_control_pack_chan(system_id, component_id, chan, msg, manual_control->target, manual_control->x, manual_control->y, manual_control->z, manual_control->r, manual_control->buttons); + return mavlink_msg_manual_control_pack_chan(system_id, component_id, chan, msg, manual_control->target, manual_control->x, manual_control->y, manual_control->z, manual_control->r, manual_control->buttons); } /** @@ -162,7 +171,7 @@ static inline uint16_t mavlink_msg_manual_control_encode_chan(uint8_t system_id, * @param target The system to be controlled. * @param x X-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to forward(1000)-backward(-1000) movement on a joystick and the pitch of a vehicle. * @param y Y-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to left(-1000)-right(1000) movement on a joystick and the roll of a vehicle. - * @param z Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. + * @param z Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. Positive values are positive thrust, negative values are negative thrust. * @param r R-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a twisting of the joystick, with counter-clockwise being 1000 and clockwise being -1000, and the yaw of a vehicle. * @param buttons A bitfield corresponding to the joystick buttons' current state, 1 for pressed, 0 for released. The lowest bit corresponds to Button 1. */ @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_manual_control_encode_chan(uint8_t system_id, static inline void mavlink_msg_manual_control_send(mavlink_channel_t chan, uint8_t target, int16_t x, int16_t y, int16_t z, int16_t r, uint16_t buttons) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MANUAL_CONTROL_LEN]; - _mav_put_int16_t(buf, 0, x); - _mav_put_int16_t(buf, 2, y); - _mav_put_int16_t(buf, 4, z); - _mav_put_int16_t(buf, 6, r); - _mav_put_uint16_t(buf, 8, buttons); - _mav_put_uint8_t(buf, 10, target); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, buf, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); + char buf[MAVLINK_MSG_ID_MANUAL_CONTROL_LEN]; + _mav_put_int16_t(buf, 0, x); + _mav_put_int16_t(buf, 2, y); + _mav_put_int16_t(buf, 4, z); + _mav_put_int16_t(buf, 6, r); + _mav_put_uint16_t(buf, 8, buttons); + _mav_put_uint8_t(buf, 10, target); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, buf, MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, buf, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); + mavlink_manual_control_t packet; + packet.x = x; + packet.y = y; + packet.z = z; + packet.r = r; + packet.buttons = buttons; + packet.target = target; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); #endif +} + +/** + * @brief Send a manual_control message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_manual_control_send_struct(mavlink_channel_t chan, const mavlink_manual_control_t* manual_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_manual_control_send(chan, manual_control->target, manual_control->x, manual_control->y, manual_control->z, manual_control->r, manual_control->buttons); #else - mavlink_manual_control_t packet; - packet.x = x; - packet.y = y; - packet.z = z; - packet.r = r; - packet.buttons = buttons; - packet.target = target; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, (const char *)manual_control, MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_manual_control_send(mavlink_channel_t chan, uint8 static inline void mavlink_msg_manual_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target, int16_t x, int16_t y, int16_t z, int16_t r, uint16_t buttons) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int16_t(buf, 0, x); - _mav_put_int16_t(buf, 2, y); - _mav_put_int16_t(buf, 4, z); - _mav_put_int16_t(buf, 6, r); - _mav_put_uint16_t(buf, 8, buttons); - _mav_put_uint8_t(buf, 10, target); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, buf, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); + char *buf = (char *)msgbuf; + _mav_put_int16_t(buf, 0, x); + _mav_put_int16_t(buf, 2, y); + _mav_put_int16_t(buf, 4, z); + _mav_put_int16_t(buf, 6, r); + _mav_put_uint16_t(buf, 8, buttons); + _mav_put_uint8_t(buf, 10, target); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, buf, MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, buf, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); -#endif -#else - mavlink_manual_control_t *packet = (mavlink_manual_control_t *)msgbuf; - packet->x = x; - packet->y = y; - packet->z = z; - packet->r = r; - packet->buttons = buttons; - packet->target = target; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); -#endif + mavlink_manual_control_t *packet = (mavlink_manual_control_t *)msgbuf; + packet->x = x; + packet->y = y; + packet->z = z; + packet->r = r; + packet->buttons = buttons; + packet->target = target; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN, MAVLINK_MSG_ID_MANUAL_CONTROL_CRC); #endif } #endif @@ -255,7 +262,7 @@ static inline void mavlink_msg_manual_control_send_buf(mavlink_message_t *msgbuf */ static inline uint8_t mavlink_msg_manual_control_get_target(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 10); + return _MAV_RETURN_uint8_t(msg, 10); } /** @@ -265,7 +272,7 @@ static inline uint8_t mavlink_msg_manual_control_get_target(const mavlink_messag */ static inline int16_t mavlink_msg_manual_control_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 0); + return _MAV_RETURN_int16_t(msg, 0); } /** @@ -275,17 +282,17 @@ static inline int16_t mavlink_msg_manual_control_get_x(const mavlink_message_t* */ static inline int16_t mavlink_msg_manual_control_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 2); + return _MAV_RETURN_int16_t(msg, 2); } /** * @brief Get field z from manual_control message * - * @return Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. + * @return Z-axis, normalized to the range [-1000,1000]. A value of INT16_MAX indicates that this axis is invalid. Generally corresponds to a separate slider movement with maximum being 1000 and minimum being -1000 on a joystick and the thrust of a vehicle. Positive values are positive thrust, negative values are negative thrust. */ static inline int16_t mavlink_msg_manual_control_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 4); + return _MAV_RETURN_int16_t(msg, 4); } /** @@ -295,7 +302,7 @@ static inline int16_t mavlink_msg_manual_control_get_z(const mavlink_message_t* */ static inline int16_t mavlink_msg_manual_control_get_r(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 6); + return _MAV_RETURN_int16_t(msg, 6); } /** @@ -305,7 +312,7 @@ static inline int16_t mavlink_msg_manual_control_get_r(const mavlink_message_t* */ static inline uint16_t mavlink_msg_manual_control_get_buttons(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -316,14 +323,16 @@ static inline uint16_t mavlink_msg_manual_control_get_buttons(const mavlink_mess */ static inline void mavlink_msg_manual_control_decode(const mavlink_message_t* msg, mavlink_manual_control_t* manual_control) { -#if MAVLINK_NEED_BYTE_SWAP - manual_control->x = mavlink_msg_manual_control_get_x(msg); - manual_control->y = mavlink_msg_manual_control_get_y(msg); - manual_control->z = mavlink_msg_manual_control_get_z(msg); - manual_control->r = mavlink_msg_manual_control_get_r(msg); - manual_control->buttons = mavlink_msg_manual_control_get_buttons(msg); - manual_control->target = mavlink_msg_manual_control_get_target(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + manual_control->x = mavlink_msg_manual_control_get_x(msg); + manual_control->y = mavlink_msg_manual_control_get_y(msg); + manual_control->z = mavlink_msg_manual_control_get_z(msg); + manual_control->r = mavlink_msg_manual_control_get_r(msg); + manual_control->buttons = mavlink_msg_manual_control_get_buttons(msg); + manual_control->target = mavlink_msg_manual_control_get_target(msg); #else - memcpy(manual_control, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MANUAL_CONTROL_LEN? msg->len : MAVLINK_MSG_ID_MANUAL_CONTROL_LEN; + memset(manual_control, 0, MAVLINK_MSG_ID_MANUAL_CONTROL_LEN); + memcpy(manual_control, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_manual_setpoint.h b/vendor/libraries/mavlink/common/mavlink_msg_manual_setpoint.h index b276267269..04d50a834a 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_manual_setpoint.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_manual_setpoint.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE MANUAL_SETPOINT PACKING #define MAVLINK_MSG_ID_MANUAL_SETPOINT 81 -typedef struct __mavlink_manual_setpoint_t -{ - uint32_t time_boot_ms; ///< Timestamp in milliseconds since system boot - float roll; ///< Desired roll rate in radians per second - float pitch; ///< Desired pitch rate in radians per second - float yaw; ///< Desired yaw rate in radians per second - float thrust; ///< Collective thrust, normalized to 0 .. 1 - uint8_t mode_switch; ///< Flight mode switch position, 0.. 255 - uint8_t manual_override_switch; ///< Override mode switch position, 0.. 255 -} mavlink_manual_setpoint_t; +MAVPACKED( +typedef struct __mavlink_manual_setpoint_t { + uint32_t time_boot_ms; /*< Timestamp in milliseconds since system boot*/ + float roll; /*< Desired roll rate in radians per second*/ + float pitch; /*< Desired pitch rate in radians per second*/ + float yaw; /*< Desired yaw rate in radians per second*/ + float thrust; /*< Collective thrust, normalized to 0 .. 1*/ + uint8_t mode_switch; /*< Flight mode switch position, 0.. 255*/ + uint8_t manual_override_switch; /*< Override mode switch position, 0.. 255*/ +}) mavlink_manual_setpoint_t; #define MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN 22 +#define MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN 22 #define MAVLINK_MSG_ID_81_LEN 22 +#define MAVLINK_MSG_ID_81_MIN_LEN 22 #define MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC 106 #define MAVLINK_MSG_ID_81_CRC 106 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT { \ - "MANUAL_SETPOINT", \ - 7, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_manual_setpoint_t, time_boot_ms) }, \ + 81, \ + "MANUAL_SETPOINT", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_manual_setpoint_t, time_boot_ms) }, \ { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_manual_setpoint_t, roll) }, \ { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_manual_setpoint_t, pitch) }, \ { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_manual_setpoint_t, yaw) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_manual_setpoint_t { "manual_override_switch", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_manual_setpoint_t, manual_override_switch) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MANUAL_SETPOINT { \ + "MANUAL_SETPOINT", \ + 7, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_manual_setpoint_t, time_boot_ms) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_manual_setpoint_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_manual_setpoint_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_manual_setpoint_t, yaw) }, \ + { "thrust", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_manual_setpoint_t, thrust) }, \ + { "mode_switch", NULL, MAVLINK_TYPE_UINT8_T, 0, 20, offsetof(mavlink_manual_setpoint_t, mode_switch) }, \ + { "manual_override_switch", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_manual_setpoint_t, manual_override_switch) }, \ + } \ +} +#endif /** * @brief Pack a manual_setpoint message @@ -51,38 +69,34 @@ typedef struct __mavlink_manual_setpoint_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_manual_setpoint_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, float roll, float pitch, float yaw, float thrust, uint8_t mode_switch, uint8_t manual_override_switch) + uint32_t time_boot_ms, float roll, float pitch, float yaw, float thrust, uint8_t mode_switch, uint8_t manual_override_switch) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, thrust); - _mav_put_uint8_t(buf, 20, mode_switch); - _mav_put_uint8_t(buf, 21, manual_override_switch); + char buf[MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, thrust); + _mav_put_uint8_t(buf, 20, mode_switch); + _mav_put_uint8_t(buf, 21, manual_override_switch); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); #else - mavlink_manual_setpoint_t packet; - packet.time_boot_ms = time_boot_ms; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.thrust = thrust; - packet.mode_switch = mode_switch; - packet.manual_override_switch = manual_override_switch; + mavlink_manual_setpoint_t packet; + packet.time_boot_ms = time_boot_ms; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.thrust = thrust; + packet.mode_switch = mode_switch; + packet.manual_override_switch = manual_override_switch; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MANUAL_SETPOINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MANUAL_SETPOINT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_manual_setpoint_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_manual_setpoint_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,float roll,float pitch,float yaw,float thrust,uint8_t mode_switch,uint8_t manual_override_switch) + mavlink_message_t* msg, + uint32_t time_boot_ms,float roll,float pitch,float yaw,float thrust,uint8_t mode_switch,uint8_t manual_override_switch) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, thrust); - _mav_put_uint8_t(buf, 20, mode_switch); - _mav_put_uint8_t(buf, 21, manual_override_switch); + char buf[MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, thrust); + _mav_put_uint8_t(buf, 20, mode_switch); + _mav_put_uint8_t(buf, 21, manual_override_switch); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); #else - mavlink_manual_setpoint_t packet; - packet.time_boot_ms = time_boot_ms; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.thrust = thrust; - packet.mode_switch = mode_switch; - packet.manual_override_switch = manual_override_switch; + mavlink_manual_setpoint_t packet; + packet.time_boot_ms = time_boot_ms; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.thrust = thrust; + packet.mode_switch = mode_switch; + packet.manual_override_switch = manual_override_switch; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MANUAL_SETPOINT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MANUAL_SETPOINT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_manual_setpoint_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_manual_setpoint_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_manual_setpoint_t* manual_setpoint) { - return mavlink_msg_manual_setpoint_pack(system_id, component_id, msg, manual_setpoint->time_boot_ms, manual_setpoint->roll, manual_setpoint->pitch, manual_setpoint->yaw, manual_setpoint->thrust, manual_setpoint->mode_switch, manual_setpoint->manual_override_switch); + return mavlink_msg_manual_setpoint_pack(system_id, component_id, msg, manual_setpoint->time_boot_ms, manual_setpoint->roll, manual_setpoint->pitch, manual_setpoint->yaw, manual_setpoint->thrust, manual_setpoint->mode_switch, manual_setpoint->manual_override_switch); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_manual_setpoint_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_manual_setpoint_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_manual_setpoint_t* manual_setpoint) { - return mavlink_msg_manual_setpoint_pack_chan(system_id, component_id, chan, msg, manual_setpoint->time_boot_ms, manual_setpoint->roll, manual_setpoint->pitch, manual_setpoint->yaw, manual_setpoint->thrust, manual_setpoint->mode_switch, manual_setpoint->manual_override_switch); + return mavlink_msg_manual_setpoint_pack_chan(system_id, component_id, chan, msg, manual_setpoint->time_boot_ms, manual_setpoint->roll, manual_setpoint->pitch, manual_setpoint->yaw, manual_setpoint->thrust, manual_setpoint->mode_switch, manual_setpoint->manual_override_switch); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_manual_setpoint_encode_chan(uint8_t system_id static inline void mavlink_msg_manual_setpoint_send(mavlink_channel_t chan, uint32_t time_boot_ms, float roll, float pitch, float yaw, float thrust, uint8_t mode_switch, uint8_t manual_override_switch) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, thrust); - _mav_put_uint8_t(buf, 20, mode_switch); - _mav_put_uint8_t(buf, 21, manual_override_switch); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); + char buf[MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, thrust); + _mav_put_uint8_t(buf, 20, mode_switch); + _mav_put_uint8_t(buf, 21, manual_override_switch); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); + mavlink_manual_setpoint_t packet; + packet.time_boot_ms = time_boot_ms; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.thrust = thrust; + packet.mode_switch = mode_switch; + packet.manual_override_switch = manual_override_switch; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, (const char *)&packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); #endif +} + +/** + * @brief Send a manual_setpoint message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_manual_setpoint_send_struct(mavlink_channel_t chan, const mavlink_manual_setpoint_t* manual_setpoint) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_manual_setpoint_send(chan, manual_setpoint->time_boot_ms, manual_setpoint->roll, manual_setpoint->pitch, manual_setpoint->yaw, manual_setpoint->thrust, manual_setpoint->mode_switch, manual_setpoint->manual_override_switch); #else - mavlink_manual_setpoint_t packet; - packet.time_boot_ms = time_boot_ms; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.thrust = thrust; - packet.mode_switch = mode_switch; - packet.manual_override_switch = manual_override_switch; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, (const char *)&packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, (const char *)&packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, (const char *)manual_setpoint, MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_manual_setpoint_send(mavlink_channel_t chan, uint static inline void mavlink_msg_manual_setpoint_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float roll, float pitch, float yaw, float thrust, uint8_t mode_switch, uint8_t manual_override_switch) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, roll); - _mav_put_float(buf, 8, pitch); - _mav_put_float(buf, 12, yaw); - _mav_put_float(buf, 16, thrust); - _mav_put_uint8_t(buf, 20, mode_switch); - _mav_put_uint8_t(buf, 21, manual_override_switch); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); -#endif -#else - mavlink_manual_setpoint_t *packet = (mavlink_manual_setpoint_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->thrust = thrust; - packet->mode_switch = mode_switch; - packet->manual_override_switch = manual_override_switch; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, (const char *)packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, roll); + _mav_put_float(buf, 8, pitch); + _mav_put_float(buf, 12, yaw); + _mav_put_float(buf, 16, thrust); + _mav_put_uint8_t(buf, 20, mode_switch); + _mav_put_uint8_t(buf, 21, manual_override_switch); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, buf, MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, (const char *)packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); -#endif + mavlink_manual_setpoint_t *packet = (mavlink_manual_setpoint_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->thrust = thrust; + packet->mode_switch = mode_switch; + packet->manual_override_switch = manual_override_switch; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MANUAL_SETPOINT, (const char *)packet, MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN, MAVLINK_MSG_ID_MANUAL_SETPOINT_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_manual_setpoint_send_buf(mavlink_message_t *msgbu */ static inline uint32_t mavlink_msg_manual_setpoint_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline uint32_t mavlink_msg_manual_setpoint_get_time_boot_ms(const mavlin */ static inline float mavlink_msg_manual_setpoint_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_manual_setpoint_get_roll(const mavlink_message_t */ static inline float mavlink_msg_manual_setpoint_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_manual_setpoint_get_pitch(const mavlink_message_ */ static inline float mavlink_msg_manual_setpoint_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_manual_setpoint_get_yaw(const mavlink_message_t* */ static inline float mavlink_msg_manual_setpoint_get_thrust(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_manual_setpoint_get_thrust(const mavlink_message */ static inline uint8_t mavlink_msg_manual_setpoint_get_mode_switch(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 20); + return _MAV_RETURN_uint8_t(msg, 20); } /** @@ -328,7 +336,7 @@ static inline uint8_t mavlink_msg_manual_setpoint_get_mode_switch(const mavlink_ */ static inline uint8_t mavlink_msg_manual_setpoint_get_manual_override_switch(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 21); + return _MAV_RETURN_uint8_t(msg, 21); } /** @@ -339,15 +347,17 @@ static inline uint8_t mavlink_msg_manual_setpoint_get_manual_override_switch(con */ static inline void mavlink_msg_manual_setpoint_decode(const mavlink_message_t* msg, mavlink_manual_setpoint_t* manual_setpoint) { -#if MAVLINK_NEED_BYTE_SWAP - manual_setpoint->time_boot_ms = mavlink_msg_manual_setpoint_get_time_boot_ms(msg); - manual_setpoint->roll = mavlink_msg_manual_setpoint_get_roll(msg); - manual_setpoint->pitch = mavlink_msg_manual_setpoint_get_pitch(msg); - manual_setpoint->yaw = mavlink_msg_manual_setpoint_get_yaw(msg); - manual_setpoint->thrust = mavlink_msg_manual_setpoint_get_thrust(msg); - manual_setpoint->mode_switch = mavlink_msg_manual_setpoint_get_mode_switch(msg); - manual_setpoint->manual_override_switch = mavlink_msg_manual_setpoint_get_manual_override_switch(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + manual_setpoint->time_boot_ms = mavlink_msg_manual_setpoint_get_time_boot_ms(msg); + manual_setpoint->roll = mavlink_msg_manual_setpoint_get_roll(msg); + manual_setpoint->pitch = mavlink_msg_manual_setpoint_get_pitch(msg); + manual_setpoint->yaw = mavlink_msg_manual_setpoint_get_yaw(msg); + manual_setpoint->thrust = mavlink_msg_manual_setpoint_get_thrust(msg); + manual_setpoint->mode_switch = mavlink_msg_manual_setpoint_get_mode_switch(msg); + manual_setpoint->manual_override_switch = mavlink_msg_manual_setpoint_get_manual_override_switch(msg); #else - memcpy(manual_setpoint, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN? msg->len : MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN; + memset(manual_setpoint, 0, MAVLINK_MSG_ID_MANUAL_SETPOINT_LEN); + memcpy(manual_setpoint, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_memory_vect.h b/vendor/libraries/mavlink/common/mavlink_msg_memory_vect.h index 2eb60cc0e6..efc0e62393 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_memory_vect.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_memory_vect.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE MEMORY_VECT PACKING #define MAVLINK_MSG_ID_MEMORY_VECT 249 -typedef struct __mavlink_memory_vect_t -{ - uint16_t address; ///< Starting address of the debug variables - uint8_t ver; ///< Version code of the type variable. 0=unknown, type ignored and assumed int16_t. 1=as below - uint8_t type; ///< Type code of the memory variables. for ver = 1: 0=16 x int16_t, 1=16 x uint16_t, 2=16 x Q15, 3=16 x 1Q14 - int8_t value[32]; ///< Memory contents at specified address -} mavlink_memory_vect_t; +MAVPACKED( +typedef struct __mavlink_memory_vect_t { + uint16_t address; /*< Starting address of the debug variables*/ + uint8_t ver; /*< Version code of the type variable. 0=unknown, type ignored and assumed int16_t. 1=as below*/ + uint8_t type; /*< Type code of the memory variables. for ver = 1: 0=16 x int16_t, 1=16 x uint16_t, 2=16 x Q15, 3=16 x 1Q14*/ + int8_t value[32]; /*< Memory contents at specified address*/ +}) mavlink_memory_vect_t; #define MAVLINK_MSG_ID_MEMORY_VECT_LEN 36 +#define MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN 36 #define MAVLINK_MSG_ID_249_LEN 36 +#define MAVLINK_MSG_ID_249_MIN_LEN 36 #define MAVLINK_MSG_ID_MEMORY_VECT_CRC 204 #define MAVLINK_MSG_ID_249_CRC 204 #define MAVLINK_MSG_MEMORY_VECT_FIELD_VALUE_LEN 32 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MEMORY_VECT { \ - "MEMORY_VECT", \ - 4, \ - { { "address", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_memory_vect_t, address) }, \ + 249, \ + "MEMORY_VECT", \ + 4, \ + { { "address", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_memory_vect_t, address) }, \ { "ver", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_memory_vect_t, ver) }, \ { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_memory_vect_t, type) }, \ { "value", NULL, MAVLINK_TYPE_INT8_T, 32, 4, offsetof(mavlink_memory_vect_t, value) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MEMORY_VECT { \ + "MEMORY_VECT", \ + 4, \ + { { "address", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_memory_vect_t, address) }, \ + { "ver", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_memory_vect_t, ver) }, \ + { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_memory_vect_t, type) }, \ + { "value", NULL, MAVLINK_TYPE_INT8_T, 32, 4, offsetof(mavlink_memory_vect_t, value) }, \ + } \ +} +#endif /** * @brief Pack a memory_vect message @@ -42,30 +57,26 @@ typedef struct __mavlink_memory_vect_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_memory_vect_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t address, uint8_t ver, uint8_t type, const int8_t *value) + uint16_t address, uint8_t ver, uint8_t type, const int8_t *value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MEMORY_VECT_LEN]; - _mav_put_uint16_t(buf, 0, address); - _mav_put_uint8_t(buf, 2, ver); - _mav_put_uint8_t(buf, 3, type); - _mav_put_int8_t_array(buf, 4, value, 32); + char buf[MAVLINK_MSG_ID_MEMORY_VECT_LEN]; + _mav_put_uint16_t(buf, 0, address); + _mav_put_uint8_t(buf, 2, ver); + _mav_put_uint8_t(buf, 3, type); + _mav_put_int8_t_array(buf, 4, value, 32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MEMORY_VECT_LEN); #else - mavlink_memory_vect_t packet; - packet.address = address; - packet.ver = ver; - packet.type = type; - mav_array_memcpy(packet.value, value, sizeof(int8_t)*32); + mavlink_memory_vect_t packet; + packet.address = address; + packet.ver = ver; + packet.type = type; + mav_array_memcpy(packet.value, value, sizeof(int8_t)*32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MEMORY_VECT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MEMORY_VECT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MEMORY_VECT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MEMORY_VECT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); } /** @@ -81,31 +92,27 @@ static inline uint16_t mavlink_msg_memory_vect_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_memory_vect_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t address,uint8_t ver,uint8_t type,const int8_t *value) + mavlink_message_t* msg, + uint16_t address,uint8_t ver,uint8_t type,const int8_t *value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MEMORY_VECT_LEN]; - _mav_put_uint16_t(buf, 0, address); - _mav_put_uint8_t(buf, 2, ver); - _mav_put_uint8_t(buf, 3, type); - _mav_put_int8_t_array(buf, 4, value, 32); + char buf[MAVLINK_MSG_ID_MEMORY_VECT_LEN]; + _mav_put_uint16_t(buf, 0, address); + _mav_put_uint8_t(buf, 2, ver); + _mav_put_uint8_t(buf, 3, type); + _mav_put_int8_t_array(buf, 4, value, 32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MEMORY_VECT_LEN); #else - mavlink_memory_vect_t packet; - packet.address = address; - packet.ver = ver; - packet.type = type; - mav_array_memcpy(packet.value, value, sizeof(int8_t)*32); + mavlink_memory_vect_t packet; + packet.address = address; + packet.ver = ver; + packet.type = type; + mav_array_memcpy(packet.value, value, sizeof(int8_t)*32); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MEMORY_VECT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MEMORY_VECT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MEMORY_VECT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MEMORY_VECT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); } /** @@ -118,7 +125,7 @@ static inline uint16_t mavlink_msg_memory_vect_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_memory_vect_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_memory_vect_t* memory_vect) { - return mavlink_msg_memory_vect_pack(system_id, component_id, msg, memory_vect->address, memory_vect->ver, memory_vect->type, memory_vect->value); + return mavlink_msg_memory_vect_pack(system_id, component_id, msg, memory_vect->address, memory_vect->ver, memory_vect->type, memory_vect->value); } /** @@ -132,7 +139,7 @@ static inline uint16_t mavlink_msg_memory_vect_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_memory_vect_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_memory_vect_t* memory_vect) { - return mavlink_msg_memory_vect_pack_chan(system_id, component_id, chan, msg, memory_vect->address, memory_vect->ver, memory_vect->type, memory_vect->value); + return mavlink_msg_memory_vect_pack_chan(system_id, component_id, chan, msg, memory_vect->address, memory_vect->ver, memory_vect->type, memory_vect->value); } /** @@ -149,27 +156,33 @@ static inline uint16_t mavlink_msg_memory_vect_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_memory_vect_send(mavlink_channel_t chan, uint16_t address, uint8_t ver, uint8_t type, const int8_t *value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MEMORY_VECT_LEN]; - _mav_put_uint16_t(buf, 0, address); - _mav_put_uint8_t(buf, 2, ver); - _mav_put_uint8_t(buf, 3, type); - _mav_put_int8_t_array(buf, 4, value, 32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, buf, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); + char buf[MAVLINK_MSG_ID_MEMORY_VECT_LEN]; + _mav_put_uint16_t(buf, 0, address); + _mav_put_uint8_t(buf, 2, ver); + _mav_put_uint8_t(buf, 3, type); + _mav_put_int8_t_array(buf, 4, value, 32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, buf, MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, buf, MAVLINK_MSG_ID_MEMORY_VECT_LEN); + mavlink_memory_vect_t packet; + packet.address = address; + packet.ver = ver; + packet.type = type; + mav_array_memcpy(packet.value, value, sizeof(int8_t)*32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, (const char *)&packet, MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); #endif +} + +/** + * @brief Send a memory_vect message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_memory_vect_send_struct(mavlink_channel_t chan, const mavlink_memory_vect_t* memory_vect) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_memory_vect_send(chan, memory_vect->address, memory_vect->ver, memory_vect->type, memory_vect->value); #else - mavlink_memory_vect_t packet; - packet.address = address; - packet.ver = ver; - packet.type = type; - mav_array_memcpy(packet.value, value, sizeof(int8_t)*32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, (const char *)&packet, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, (const char *)&packet, MAVLINK_MSG_ID_MEMORY_VECT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, (const char *)memory_vect, MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); #endif } @@ -184,27 +197,19 @@ static inline void mavlink_msg_memory_vect_send(mavlink_channel_t chan, uint16_t static inline void mavlink_msg_memory_vect_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t address, uint8_t ver, uint8_t type, const int8_t *value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, address); - _mav_put_uint8_t(buf, 2, ver); - _mav_put_uint8_t(buf, 3, type); - _mav_put_int8_t_array(buf, 4, value, 32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, buf, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, address); + _mav_put_uint8_t(buf, 2, ver); + _mav_put_uint8_t(buf, 3, type); + _mav_put_int8_t_array(buf, 4, value, 32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, buf, MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, buf, MAVLINK_MSG_ID_MEMORY_VECT_LEN); -#endif -#else - mavlink_memory_vect_t *packet = (mavlink_memory_vect_t *)msgbuf; - packet->address = address; - packet->ver = ver; - packet->type = type; - mav_array_memcpy(packet->value, value, sizeof(int8_t)*32); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, (const char *)packet, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, (const char *)packet, MAVLINK_MSG_ID_MEMORY_VECT_LEN); -#endif + mavlink_memory_vect_t *packet = (mavlink_memory_vect_t *)msgbuf; + packet->address = address; + packet->ver = ver; + packet->type = type; + mav_array_memcpy(packet->value, value, sizeof(int8_t)*32); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MEMORY_VECT, (const char *)packet, MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN, MAVLINK_MSG_ID_MEMORY_VECT_LEN, MAVLINK_MSG_ID_MEMORY_VECT_CRC); #endif } #endif @@ -221,7 +226,7 @@ static inline void mavlink_msg_memory_vect_send_buf(mavlink_message_t *msgbuf, m */ static inline uint16_t mavlink_msg_memory_vect_get_address(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -231,7 +236,7 @@ static inline uint16_t mavlink_msg_memory_vect_get_address(const mavlink_message */ static inline uint8_t mavlink_msg_memory_vect_get_ver(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -241,7 +246,7 @@ static inline uint8_t mavlink_msg_memory_vect_get_ver(const mavlink_message_t* m */ static inline uint8_t mavlink_msg_memory_vect_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -251,7 +256,7 @@ static inline uint8_t mavlink_msg_memory_vect_get_type(const mavlink_message_t* */ static inline uint16_t mavlink_msg_memory_vect_get_value(const mavlink_message_t* msg, int8_t *value) { - return _MAV_RETURN_int8_t_array(msg, value, 32, 4); + return _MAV_RETURN_int8_t_array(msg, value, 32, 4); } /** @@ -262,12 +267,14 @@ static inline uint16_t mavlink_msg_memory_vect_get_value(const mavlink_message_t */ static inline void mavlink_msg_memory_vect_decode(const mavlink_message_t* msg, mavlink_memory_vect_t* memory_vect) { -#if MAVLINK_NEED_BYTE_SWAP - memory_vect->address = mavlink_msg_memory_vect_get_address(msg); - memory_vect->ver = mavlink_msg_memory_vect_get_ver(msg); - memory_vect->type = mavlink_msg_memory_vect_get_type(msg); - mavlink_msg_memory_vect_get_value(msg, memory_vect->value); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + memory_vect->address = mavlink_msg_memory_vect_get_address(msg); + memory_vect->ver = mavlink_msg_memory_vect_get_ver(msg); + memory_vect->type = mavlink_msg_memory_vect_get_type(msg); + mavlink_msg_memory_vect_get_value(msg, memory_vect->value); #else - memcpy(memory_vect, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MEMORY_VECT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MEMORY_VECT_LEN? msg->len : MAVLINK_MSG_ID_MEMORY_VECT_LEN; + memset(memory_vect, 0, MAVLINK_MSG_ID_MEMORY_VECT_LEN); + memcpy(memory_vect, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_message_interval.h b/vendor/libraries/mavlink/common/mavlink_msg_message_interval.h new file mode 100644 index 0000000000..95b501ffe5 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_message_interval.h @@ -0,0 +1,238 @@ +#pragma once +// MESSAGE MESSAGE_INTERVAL PACKING + +#define MAVLINK_MSG_ID_MESSAGE_INTERVAL 244 + +MAVPACKED( +typedef struct __mavlink_message_interval_t { + int32_t interval_us; /*< The interval between two messages, in microseconds. A value of -1 indicates this stream is disabled, 0 indicates it is not available, > 0 indicates the interval at which it is sent.*/ + uint16_t message_id; /*< The ID of the requested MAVLink message. v1.0 is limited to 254 messages.*/ +}) mavlink_message_interval_t; + +#define MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN 6 +#define MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN 6 +#define MAVLINK_MSG_ID_244_LEN 6 +#define MAVLINK_MSG_ID_244_MIN_LEN 6 + +#define MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC 95 +#define MAVLINK_MSG_ID_244_CRC 95 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_MESSAGE_INTERVAL { \ + 244, \ + "MESSAGE_INTERVAL", \ + 2, \ + { { "interval_us", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_message_interval_t, interval_us) }, \ + { "message_id", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_message_interval_t, message_id) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_MESSAGE_INTERVAL { \ + "MESSAGE_INTERVAL", \ + 2, \ + { { "interval_us", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_message_interval_t, interval_us) }, \ + { "message_id", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_message_interval_t, message_id) }, \ + } \ +} +#endif + +/** + * @brief Pack a message_interval message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param message_id The ID of the requested MAVLink message. v1.0 is limited to 254 messages. + * @param interval_us The interval between two messages, in microseconds. A value of -1 indicates this stream is disabled, 0 indicates it is not available, > 0 indicates the interval at which it is sent. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_message_interval_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint16_t message_id, int32_t interval_us) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN]; + _mav_put_int32_t(buf, 0, interval_us); + _mav_put_uint16_t(buf, 4, message_id); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN); +#else + mavlink_message_interval_t packet; + packet.interval_us = interval_us; + packet.message_id = message_id; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MESSAGE_INTERVAL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC); +} + +/** + * @brief Pack a message_interval message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param message_id The ID of the requested MAVLink message. v1.0 is limited to 254 messages. + * @param interval_us The interval between two messages, in microseconds. A value of -1 indicates this stream is disabled, 0 indicates it is not available, > 0 indicates the interval at which it is sent. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_message_interval_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint16_t message_id,int32_t interval_us) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN]; + _mav_put_int32_t(buf, 0, interval_us); + _mav_put_uint16_t(buf, 4, message_id); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN); +#else + mavlink_message_interval_t packet; + packet.interval_us = interval_us; + packet.message_id = message_id; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MESSAGE_INTERVAL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC); +} + +/** + * @brief Encode a message_interval struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param message_interval C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_message_interval_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_message_interval_t* message_interval) +{ + return mavlink_msg_message_interval_pack(system_id, component_id, msg, message_interval->message_id, message_interval->interval_us); +} + +/** + * @brief Encode a message_interval struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param message_interval C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_message_interval_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_message_interval_t* message_interval) +{ + return mavlink_msg_message_interval_pack_chan(system_id, component_id, chan, msg, message_interval->message_id, message_interval->interval_us); +} + +/** + * @brief Send a message_interval message + * @param chan MAVLink channel to send the message + * + * @param message_id The ID of the requested MAVLink message. v1.0 is limited to 254 messages. + * @param interval_us The interval between two messages, in microseconds. A value of -1 indicates this stream is disabled, 0 indicates it is not available, > 0 indicates the interval at which it is sent. + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_message_interval_send(mavlink_channel_t chan, uint16_t message_id, int32_t interval_us) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN]; + _mav_put_int32_t(buf, 0, interval_us); + _mav_put_uint16_t(buf, 4, message_id); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MESSAGE_INTERVAL, buf, MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC); +#else + mavlink_message_interval_t packet; + packet.interval_us = interval_us; + packet.message_id = message_id; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MESSAGE_INTERVAL, (const char *)&packet, MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC); +#endif +} + +/** + * @brief Send a message_interval message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_message_interval_send_struct(mavlink_channel_t chan, const mavlink_message_interval_t* message_interval) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_message_interval_send(chan, message_interval->message_id, message_interval->interval_us); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MESSAGE_INTERVAL, (const char *)message_interval, MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC); +#endif +} + +#if MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_message_interval_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t message_id, int32_t interval_us) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, interval_us); + _mav_put_uint16_t(buf, 4, message_id); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MESSAGE_INTERVAL, buf, MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC); +#else + mavlink_message_interval_t *packet = (mavlink_message_interval_t *)msgbuf; + packet->interval_us = interval_us; + packet->message_id = message_id; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MESSAGE_INTERVAL, (const char *)packet, MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN, MAVLINK_MSG_ID_MESSAGE_INTERVAL_CRC); +#endif +} +#endif + +#endif + +// MESSAGE MESSAGE_INTERVAL UNPACKING + + +/** + * @brief Get field message_id from message_interval message + * + * @return The ID of the requested MAVLink message. v1.0 is limited to 254 messages. + */ +static inline uint16_t mavlink_msg_message_interval_get_message_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 4); +} + +/** + * @brief Get field interval_us from message_interval message + * + * @return The interval between two messages, in microseconds. A value of -1 indicates this stream is disabled, 0 indicates it is not available, > 0 indicates the interval at which it is sent. + */ +static inline int32_t mavlink_msg_message_interval_get_interval_us(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 0); +} + +/** + * @brief Decode a message_interval message into a struct + * + * @param msg The message to decode + * @param message_interval C-struct to decode the message contents into + */ +static inline void mavlink_msg_message_interval_decode(const mavlink_message_t* msg, mavlink_message_interval_t* message_interval) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + message_interval->interval_us = mavlink_msg_message_interval_get_interval_us(msg); + message_interval->message_id = mavlink_msg_message_interval_get_message_id(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN? msg->len : MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN; + memset(message_interval, 0, MAVLINK_MSG_ID_MESSAGE_INTERVAL_LEN); + memcpy(message_interval, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_ack.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_ack.h index 43afd00f7e..9616a0fe84 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_ack.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_ack.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE MISSION_ACK PACKING #define MAVLINK_MSG_ID_MISSION_ACK 47 -typedef struct __mavlink_mission_ack_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t type; ///< See MAV_MISSION_RESULT enum -} mavlink_mission_ack_t; +MAVPACKED( +typedef struct __mavlink_mission_ack_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t type; /*< See MAV_MISSION_RESULT enum*/ +}) mavlink_mission_ack_t; #define MAVLINK_MSG_ID_MISSION_ACK_LEN 3 +#define MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN 3 #define MAVLINK_MSG_ID_47_LEN 3 +#define MAVLINK_MSG_ID_47_MIN_LEN 3 #define MAVLINK_MSG_ID_MISSION_ACK_CRC 153 #define MAVLINK_MSG_ID_47_CRC 153 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_ACK { \ - "MISSION_ACK", \ - 3, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_ack_t, target_system) }, \ + 47, \ + "MISSION_ACK", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_ack_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mission_ack_t, target_component) }, \ { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_ack_t, type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_ACK { \ + "MISSION_ACK", \ + 3, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_ack_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mission_ack_t, target_component) }, \ + { "type", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_ack_t, type) }, \ + } \ +} +#endif /** * @brief Pack a mission_ack message @@ -39,30 +53,26 @@ typedef struct __mavlink_mission_ack_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_ack_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t type) + uint8_t target_system, uint8_t target_component, uint8_t type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ACK_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, type); + char buf[MAVLINK_MSG_ID_MISSION_ACK_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ACK_LEN); #else - mavlink_mission_ack_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.type = type; + mavlink_mission_ack_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.type = type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ACK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_mission_ack_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_ack_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t type) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ACK_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, type); + char buf[MAVLINK_MSG_ID_MISSION_ACK_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, type); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ACK_LEN); #else - mavlink_mission_ack_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.type = type; + mavlink_mission_ack_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.type = type; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ACK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ACK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ACK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ACK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_mission_ack_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_mission_ack_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_ack_t* mission_ack) { - return mavlink_msg_mission_ack_pack(system_id, component_id, msg, mission_ack->target_system, mission_ack->target_component, mission_ack->type); + return mavlink_msg_mission_ack_pack(system_id, component_id, msg, mission_ack->target_system, mission_ack->target_component, mission_ack->type); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_mission_ack_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_mission_ack_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_ack_t* mission_ack) { - return mavlink_msg_mission_ack_pack_chan(system_id, component_id, chan, msg, mission_ack->target_system, mission_ack->target_component, mission_ack->type); + return mavlink_msg_mission_ack_pack_chan(system_id, component_id, chan, msg, mission_ack->target_system, mission_ack->target_component, mission_ack->type); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_mission_ack_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_mission_ack_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ACK_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, type); + char buf[MAVLINK_MSG_ID_MISSION_ACK_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, type); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, buf, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, buf, MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, buf, MAVLINK_MSG_ID_MISSION_ACK_LEN); + mavlink_mission_ack_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + packet.type = type; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); #endif -#else - mavlink_mission_ack_t packet; - packet.target_system = target_system; - packet.target_component = target_component; - packet.type = type; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); +/** + * @brief Send a mission_ack message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_ack_send_struct(mavlink_channel_t chan, const mavlink_mission_ack_t* mission_ack) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_ack_send(chan, mission_ack->target_system, mission_ack->target_component, mission_ack->type); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, (const char *)mission_ack, MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_mission_ack_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_mission_ack_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); - _mav_put_uint8_t(buf, 2, type); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); + _mav_put_uint8_t(buf, 2, type); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, buf, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, buf, MAVLINK_MSG_ID_MISSION_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, buf, MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); #else - mavlink_mission_ack_t *packet = (mavlink_mission_ack_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; - packet->type = type; + mavlink_mission_ack_t *packet = (mavlink_mission_ack_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; + packet->type = type; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, (const char *)packet, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, (const char *)packet, MAVLINK_MSG_ID_MISSION_ACK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ACK, (const char *)packet, MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN, MAVLINK_MSG_ID_MISSION_ACK_LEN, MAVLINK_MSG_ID_MISSION_ACK_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_mission_ack_send_buf(mavlink_message_t *msgbuf, m */ static inline uint8_t mavlink_msg_mission_ack_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_mission_ack_get_target_system(const mavlink_me */ static inline uint8_t mavlink_msg_mission_ack_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_mission_ack_get_target_component(const mavlink */ static inline uint8_t mavlink_msg_mission_ack_get_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -247,11 +251,13 @@ static inline uint8_t mavlink_msg_mission_ack_get_type(const mavlink_message_t* */ static inline void mavlink_msg_mission_ack_decode(const mavlink_message_t* msg, mavlink_mission_ack_t* mission_ack) { -#if MAVLINK_NEED_BYTE_SWAP - mission_ack->target_system = mavlink_msg_mission_ack_get_target_system(msg); - mission_ack->target_component = mavlink_msg_mission_ack_get_target_component(msg); - mission_ack->type = mavlink_msg_mission_ack_get_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_ack->target_system = mavlink_msg_mission_ack_get_target_system(msg); + mission_ack->target_component = mavlink_msg_mission_ack_get_target_component(msg); + mission_ack->type = mavlink_msg_mission_ack_get_type(msg); #else - memcpy(mission_ack, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_ACK_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_ACK_LEN? msg->len : MAVLINK_MSG_ID_MISSION_ACK_LEN; + memset(mission_ack, 0, MAVLINK_MSG_ID_MISSION_ACK_LEN); + memcpy(mission_ack, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_clear_all.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_clear_all.h index 120986873f..fa7e20e43c 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_clear_all.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_clear_all.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE MISSION_CLEAR_ALL PACKING #define MAVLINK_MSG_ID_MISSION_CLEAR_ALL 45 -typedef struct __mavlink_mission_clear_all_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mission_clear_all_t; +MAVPACKED( +typedef struct __mavlink_mission_clear_all_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_clear_all_t; #define MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN 2 +#define MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN 2 #define MAVLINK_MSG_ID_45_LEN 2 +#define MAVLINK_MSG_ID_45_MIN_LEN 2 #define MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC 232 #define MAVLINK_MSG_ID_45_CRC 232 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL { \ - "MISSION_CLEAR_ALL", \ - 2, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_clear_all_t, target_system) }, \ + 45, \ + "MISSION_CLEAR_ALL", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_clear_all_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mission_clear_all_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_CLEAR_ALL { \ + "MISSION_CLEAR_ALL", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_clear_all_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mission_clear_all_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mission_clear_all message @@ -36,28 +49,24 @@ typedef struct __mavlink_mission_clear_all_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_clear_all_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component) + uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); #else - mavlink_mission_clear_all_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_clear_all_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_CLEAR_ALL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_CLEAR_ALL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_mission_clear_all_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_clear_all_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); #else - mavlink_mission_clear_all_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_clear_all_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_CLEAR_ALL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_CLEAR_ALL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_mission_clear_all_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_mission_clear_all_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_clear_all_t* mission_clear_all) { - return mavlink_msg_mission_clear_all_pack(system_id, component_id, msg, mission_clear_all->target_system, mission_clear_all->target_component); + return mavlink_msg_mission_clear_all_pack(system_id, component_id, msg, mission_clear_all->target_system, mission_clear_all->target_component); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_mission_clear_all_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_mission_clear_all_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_clear_all_t* mission_clear_all) { - return mavlink_msg_mission_clear_all_pack_chan(system_id, component_id, chan, msg, mission_clear_all->target_system, mission_clear_all->target_component); + return mavlink_msg_mission_clear_all_pack_chan(system_id, component_id, chan, msg, mission_clear_all->target_system, mission_clear_all->target_component); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_mission_clear_all_encode_chan(uint8_t system_ static inline void mavlink_msg_mission_clear_all_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); + mavlink_mission_clear_all_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, (const char *)&packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); #endif -#else - mavlink_mission_clear_all_t packet; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, (const char *)&packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); +/** + * @brief Send a mission_clear_all message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_clear_all_send_struct(mavlink_channel_t chan, const mavlink_mission_clear_all_t* mission_clear_all) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_clear_all_send(chan, mission_clear_all->target_system, mission_clear_all->target_component); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, (const char *)&packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, (const char *)mission_clear_all, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_mission_clear_all_send(mavlink_channel_t chan, ui static inline void mavlink_msg_mission_clear_all_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, buf, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); #else - mavlink_mission_clear_all_t *packet = (mavlink_mission_clear_all_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_mission_clear_all_t *packet = (mavlink_mission_clear_all_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, (const char *)packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, (const char *)packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CLEAR_ALL, (const char *)packet, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_mission_clear_all_send_buf(mavlink_message_t *msg */ static inline uint8_t mavlink_msg_mission_clear_all_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint8_t mavlink_msg_mission_clear_all_get_target_system(const mavl */ static inline uint8_t mavlink_msg_mission_clear_all_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_mission_clear_all_get_target_component(const m */ static inline void mavlink_msg_mission_clear_all_decode(const mavlink_message_t* msg, mavlink_mission_clear_all_t* mission_clear_all) { -#if MAVLINK_NEED_BYTE_SWAP - mission_clear_all->target_system = mavlink_msg_mission_clear_all_get_target_system(msg); - mission_clear_all->target_component = mavlink_msg_mission_clear_all_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_clear_all->target_system = mavlink_msg_mission_clear_all_get_target_system(msg); + mission_clear_all->target_component = mavlink_msg_mission_clear_all_get_target_component(msg); #else - memcpy(mission_clear_all, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN? msg->len : MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN; + memset(mission_clear_all, 0, MAVLINK_MSG_ID_MISSION_CLEAR_ALL_LEN); + memcpy(mission_clear_all, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_count.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_count.h index 7e4748eaef..6ba66ff6f4 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_count.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_count.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE MISSION_COUNT PACKING #define MAVLINK_MSG_ID_MISSION_COUNT 44 -typedef struct __mavlink_mission_count_t -{ - uint16_t count; ///< Number of mission items in the sequence - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mission_count_t; +MAVPACKED( +typedef struct __mavlink_mission_count_t { + uint16_t count; /*< Number of mission items in the sequence*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_count_t; #define MAVLINK_MSG_ID_MISSION_COUNT_LEN 4 +#define MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN 4 #define MAVLINK_MSG_ID_44_LEN 4 +#define MAVLINK_MSG_ID_44_MIN_LEN 4 #define MAVLINK_MSG_ID_MISSION_COUNT_CRC 221 #define MAVLINK_MSG_ID_44_CRC 221 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_COUNT { \ - "MISSION_COUNT", \ - 3, \ - { { "count", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_count_t, count) }, \ + 44, \ + "MISSION_COUNT", \ + 3, \ + { { "count", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_count_t, count) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_count_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_count_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_COUNT { \ + "MISSION_COUNT", \ + 3, \ + { { "count", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_count_t, count) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_count_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_count_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mission_count message @@ -39,30 +53,26 @@ typedef struct __mavlink_mission_count_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_count_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t count) + uint8_t target_system, uint8_t target_component, uint16_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_COUNT_LEN]; - _mav_put_uint16_t(buf, 0, count); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_COUNT_LEN]; + _mav_put_uint16_t(buf, 0, count); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_COUNT_LEN); #else - mavlink_mission_count_t packet; - packet.count = count; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_count_t packet; + packet.count = count; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_COUNT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_COUNT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_COUNT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_COUNT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_mission_count_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_count_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t count) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_COUNT_LEN]; - _mav_put_uint16_t(buf, 0, count); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_COUNT_LEN]; + _mav_put_uint16_t(buf, 0, count); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_COUNT_LEN); #else - mavlink_mission_count_t packet; - packet.count = count; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_count_t packet; + packet.count = count; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_COUNT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_COUNT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_COUNT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_COUNT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_mission_count_pack_chan(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_mission_count_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_count_t* mission_count) { - return mavlink_msg_mission_count_pack(system_id, component_id, msg, mission_count->target_system, mission_count->target_component, mission_count->count); + return mavlink_msg_mission_count_pack(system_id, component_id, msg, mission_count->target_system, mission_count->target_component, mission_count->count); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_mission_count_encode(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_mission_count_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_count_t* mission_count) { - return mavlink_msg_mission_count_pack_chan(system_id, component_id, chan, msg, mission_count->target_system, mission_count->target_component, mission_count->count); + return mavlink_msg_mission_count_pack_chan(system_id, component_id, chan, msg, mission_count->target_system, mission_count->target_component, mission_count->count); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_mission_count_encode_chan(uint8_t system_id, static inline void mavlink_msg_mission_count_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_COUNT_LEN]; - _mav_put_uint16_t(buf, 0, count); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_COUNT_LEN]; + _mav_put_uint16_t(buf, 0, count); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, buf, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, buf, MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, buf, MAVLINK_MSG_ID_MISSION_COUNT_LEN); + mavlink_mission_count_t packet; + packet.count = count; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); #endif -#else - mavlink_mission_count_t packet; - packet.count = count; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); +/** + * @brief Send a mission_count message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_count_send_struct(mavlink_channel_t chan, const mavlink_mission_count_t* mission_count) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_count_send(chan, mission_count->target_system, mission_count->target_component, mission_count->count); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_COUNT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, (const char *)mission_count, MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_mission_count_send(mavlink_channel_t chan, uint8_ static inline void mavlink_msg_mission_count_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t count) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, count); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, count); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, buf, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, buf, MAVLINK_MSG_ID_MISSION_COUNT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, buf, MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); #else - mavlink_mission_count_t *packet = (mavlink_mission_count_t *)msgbuf; - packet->count = count; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_mission_count_t *packet = (mavlink_mission_count_t *)msgbuf; + packet->count = count; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, (const char *)packet, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, (const char *)packet, MAVLINK_MSG_ID_MISSION_COUNT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_COUNT, (const char *)packet, MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN, MAVLINK_MSG_ID_MISSION_COUNT_LEN, MAVLINK_MSG_ID_MISSION_COUNT_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_mission_count_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_mission_count_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_mission_count_get_target_system(const mavlink_ */ static inline uint8_t mavlink_msg_mission_count_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_mission_count_get_target_component(const mavli */ static inline uint16_t mavlink_msg_mission_count_get_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -247,11 +251,13 @@ static inline uint16_t mavlink_msg_mission_count_get_count(const mavlink_message */ static inline void mavlink_msg_mission_count_decode(const mavlink_message_t* msg, mavlink_mission_count_t* mission_count) { -#if MAVLINK_NEED_BYTE_SWAP - mission_count->count = mavlink_msg_mission_count_get_count(msg); - mission_count->target_system = mavlink_msg_mission_count_get_target_system(msg); - mission_count->target_component = mavlink_msg_mission_count_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_count->count = mavlink_msg_mission_count_get_count(msg); + mission_count->target_system = mavlink_msg_mission_count_get_target_system(msg); + mission_count->target_component = mavlink_msg_mission_count_get_target_component(msg); #else - memcpy(mission_count, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_COUNT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_COUNT_LEN? msg->len : MAVLINK_MSG_ID_MISSION_COUNT_LEN; + memset(mission_count, 0, MAVLINK_MSG_ID_MISSION_COUNT_LEN); + memcpy(mission_count, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_current.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_current.h index 201b7a6fb4..802632d34d 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_current.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_current.h @@ -1,27 +1,39 @@ +#pragma once // MESSAGE MISSION_CURRENT PACKING #define MAVLINK_MSG_ID_MISSION_CURRENT 42 -typedef struct __mavlink_mission_current_t -{ - uint16_t seq; ///< Sequence -} mavlink_mission_current_t; +MAVPACKED( +typedef struct __mavlink_mission_current_t { + uint16_t seq; /*< Sequence*/ +}) mavlink_mission_current_t; #define MAVLINK_MSG_ID_MISSION_CURRENT_LEN 2 +#define MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN 2 #define MAVLINK_MSG_ID_42_LEN 2 +#define MAVLINK_MSG_ID_42_MIN_LEN 2 #define MAVLINK_MSG_ID_MISSION_CURRENT_CRC 28 #define MAVLINK_MSG_ID_42_CRC 28 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_CURRENT { \ - "MISSION_CURRENT", \ - 1, \ - { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_current_t, seq) }, \ + 42, \ + "MISSION_CURRENT", \ + 1, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_current_t, seq) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_CURRENT { \ + "MISSION_CURRENT", \ + 1, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_current_t, seq) }, \ + } \ +} +#endif /** * @brief Pack a mission_current message @@ -33,26 +45,22 @@ typedef struct __mavlink_mission_current_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_current_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t seq) + uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_CURRENT_LEN]; - _mav_put_uint16_t(buf, 0, seq); + char buf[MAVLINK_MSG_ID_MISSION_CURRENT_LEN]; + _mav_put_uint16_t(buf, 0, seq); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); #else - mavlink_mission_current_t packet; - packet.seq = seq; + mavlink_mission_current_t packet; + packet.seq = seq; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_CURRENT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_CURRENT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); } /** @@ -65,27 +73,23 @@ static inline uint16_t mavlink_msg_mission_current_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_current_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t seq) + mavlink_message_t* msg, + uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_CURRENT_LEN]; - _mav_put_uint16_t(buf, 0, seq); + char buf[MAVLINK_MSG_ID_MISSION_CURRENT_LEN]; + _mav_put_uint16_t(buf, 0, seq); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); #else - mavlink_mission_current_t packet; - packet.seq = seq; + mavlink_mission_current_t packet; + packet.seq = seq; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_CURRENT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_CURRENT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); } /** @@ -98,7 +102,7 @@ static inline uint16_t mavlink_msg_mission_current_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_mission_current_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_current_t* mission_current) { - return mavlink_msg_mission_current_pack(system_id, component_id, msg, mission_current->seq); + return mavlink_msg_mission_current_pack(system_id, component_id, msg, mission_current->seq); } /** @@ -112,7 +116,7 @@ static inline uint16_t mavlink_msg_mission_current_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_mission_current_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_current_t* mission_current) { - return mavlink_msg_mission_current_pack_chan(system_id, component_id, chan, msg, mission_current->seq); + return mavlink_msg_mission_current_pack_chan(system_id, component_id, chan, msg, mission_current->seq); } /** @@ -126,23 +130,29 @@ static inline uint16_t mavlink_msg_mission_current_encode_chan(uint8_t system_id static inline void mavlink_msg_mission_current_send(mavlink_channel_t chan, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_CURRENT_LEN]; - _mav_put_uint16_t(buf, 0, seq); + char buf[MAVLINK_MSG_ID_MISSION_CURRENT_LEN]; + _mav_put_uint16_t(buf, 0, seq); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, buf, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, buf, MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, buf, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); + mavlink_mission_current_t packet; + packet.seq = seq; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); #endif -#else - mavlink_mission_current_t packet; - packet.seq = seq; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); +/** + * @brief Send a mission_current message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_current_send_struct(mavlink_channel_t chan, const mavlink_mission_current_t* mission_current) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_current_send(chan, mission_current->seq); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, (const char *)mission_current, MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); #endif } @@ -157,23 +167,15 @@ static inline void mavlink_msg_mission_current_send(mavlink_channel_t chan, uint static inline void mavlink_msg_mission_current_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, seq); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, seq); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, buf, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, buf, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, buf, MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); #else - mavlink_mission_current_t *packet = (mavlink_mission_current_t *)msgbuf; - packet->seq = seq; + mavlink_mission_current_t *packet = (mavlink_mission_current_t *)msgbuf; + packet->seq = seq; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, (const char *)packet, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, (const char *)packet, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_CURRENT, (const char *)packet, MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_CURRENT_CRC); #endif } #endif @@ -190,7 +192,7 @@ static inline void mavlink_msg_mission_current_send_buf(mavlink_message_t *msgbu */ static inline uint16_t mavlink_msg_mission_current_get_seq(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -201,9 +203,11 @@ static inline uint16_t mavlink_msg_mission_current_get_seq(const mavlink_message */ static inline void mavlink_msg_mission_current_decode(const mavlink_message_t* msg, mavlink_mission_current_t* mission_current) { -#if MAVLINK_NEED_BYTE_SWAP - mission_current->seq = mavlink_msg_mission_current_get_seq(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_current->seq = mavlink_msg_mission_current_get_seq(msg); #else - memcpy(mission_current, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_CURRENT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_CURRENT_LEN? msg->len : MAVLINK_MSG_ID_MISSION_CURRENT_LEN; + memset(mission_current, 0, MAVLINK_MSG_ID_MISSION_CURRENT_LEN); + memcpy(mission_current, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_item.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_item.h index ef9394f00c..afcf519d41 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_item.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_item.h @@ -1,37 +1,42 @@ +#pragma once // MESSAGE MISSION_ITEM PACKING #define MAVLINK_MSG_ID_MISSION_ITEM 39 -typedef struct __mavlink_mission_item_t -{ - float param1; ///< PARAM1, see MAV_CMD enum - float param2; ///< PARAM2, see MAV_CMD enum - float param3; ///< PARAM3, see MAV_CMD enum - float param4; ///< PARAM4, see MAV_CMD enum - float x; ///< PARAM5 / local: x position, global: latitude - float y; ///< PARAM6 / y position: global: longitude - float z; ///< PARAM7 / z position: global: altitude (relative or absolute, depending on frame. - uint16_t seq; ///< Sequence - uint16_t command; ///< The scheduled action for the MISSION. see MAV_CMD in common.xml MAVLink specs - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t frame; ///< The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h - uint8_t current; ///< false:0, true:1 - uint8_t autocontinue; ///< autocontinue to next wp -} mavlink_mission_item_t; +MAVPACKED( +typedef struct __mavlink_mission_item_t { + float param1; /*< PARAM1, see MAV_CMD enum*/ + float param2; /*< PARAM2, see MAV_CMD enum*/ + float param3; /*< PARAM3, see MAV_CMD enum*/ + float param4; /*< PARAM4, see MAV_CMD enum*/ + float x; /*< PARAM5 / local: x position, global: latitude*/ + float y; /*< PARAM6 / y position: global: longitude*/ + float z; /*< PARAM7 / z position: global: altitude (relative or absolute, depending on frame.*/ + uint16_t seq; /*< Sequence*/ + uint16_t command; /*< The scheduled action for the MISSION. see MAV_CMD in common.xml MAVLink specs*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t frame; /*< The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h*/ + uint8_t current; /*< false:0, true:1*/ + uint8_t autocontinue; /*< autocontinue to next wp*/ +}) mavlink_mission_item_t; #define MAVLINK_MSG_ID_MISSION_ITEM_LEN 37 +#define MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN 37 #define MAVLINK_MSG_ID_39_LEN 37 +#define MAVLINK_MSG_ID_39_MIN_LEN 37 #define MAVLINK_MSG_ID_MISSION_ITEM_CRC 254 #define MAVLINK_MSG_ID_39_CRC 254 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_ITEM { \ - "MISSION_ITEM", \ - 14, \ - { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mission_item_t, param1) }, \ + 39, \ + "MISSION_ITEM", \ + 14, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mission_item_t, param1) }, \ { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mission_item_t, param2) }, \ { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mission_item_t, param3) }, \ { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_mission_item_t, param4) }, \ @@ -47,7 +52,27 @@ typedef struct __mavlink_mission_item_t { "autocontinue", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_mission_item_t, autocontinue) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_ITEM { \ + "MISSION_ITEM", \ + 14, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mission_item_t, param1) }, \ + { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mission_item_t, param2) }, \ + { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mission_item_t, param3) }, \ + { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_mission_item_t, param4) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_mission_item_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_mission_item_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_mission_item_t, z) }, \ + { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_mission_item_t, seq) }, \ + { "command", NULL, MAVLINK_TYPE_UINT16_T, 0, 30, offsetof(mavlink_mission_item_t, command) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_mission_item_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_mission_item_t, target_component) }, \ + { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_mission_item_t, frame) }, \ + { "current", NULL, MAVLINK_TYPE_UINT8_T, 0, 35, offsetof(mavlink_mission_item_t, current) }, \ + { "autocontinue", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_mission_item_t, autocontinue) }, \ + } \ +} +#endif /** * @brief Pack a mission_item message @@ -72,52 +97,48 @@ typedef struct __mavlink_mission_item_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_item_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, float x, float y, float z) + uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, x); - _mav_put_float(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, x); + _mav_put_float(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ITEM_LEN); #else - mavlink_mission_item_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.seq = seq; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; + mavlink_mission_item_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.seq = seq; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ITEM_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); } /** @@ -143,53 +164,49 @@ static inline uint16_t mavlink_msg_mission_item_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_item_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t seq,uint8_t frame,uint16_t command,uint8_t current,uint8_t autocontinue,float param1,float param2,float param3,float param4,float x,float y,float z) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t seq,uint8_t frame,uint16_t command,uint8_t current,uint8_t autocontinue,float param1,float param2,float param3,float param4,float x,float y,float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, x); - _mav_put_float(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, x); + _mav_put_float(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ITEM_LEN); #else - mavlink_mission_item_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.seq = seq; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; + mavlink_mission_item_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.seq = seq; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ITEM_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); } /** @@ -202,7 +219,7 @@ static inline uint16_t mavlink_msg_mission_item_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_mission_item_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_item_t* mission_item) { - return mavlink_msg_mission_item_pack(system_id, component_id, msg, mission_item->target_system, mission_item->target_component, mission_item->seq, mission_item->frame, mission_item->command, mission_item->current, mission_item->autocontinue, mission_item->param1, mission_item->param2, mission_item->param3, mission_item->param4, mission_item->x, mission_item->y, mission_item->z); + return mavlink_msg_mission_item_pack(system_id, component_id, msg, mission_item->target_system, mission_item->target_component, mission_item->seq, mission_item->frame, mission_item->command, mission_item->current, mission_item->autocontinue, mission_item->param1, mission_item->param2, mission_item->param3, mission_item->param4, mission_item->x, mission_item->y, mission_item->z); } /** @@ -216,7 +233,7 @@ static inline uint16_t mavlink_msg_mission_item_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_mission_item_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_item_t* mission_item) { - return mavlink_msg_mission_item_pack_chan(system_id, component_id, chan, msg, mission_item->target_system, mission_item->target_component, mission_item->seq, mission_item->frame, mission_item->command, mission_item->current, mission_item->autocontinue, mission_item->param1, mission_item->param2, mission_item->param3, mission_item->param4, mission_item->x, mission_item->y, mission_item->z); + return mavlink_msg_mission_item_pack_chan(system_id, component_id, chan, msg, mission_item->target_system, mission_item->target_component, mission_item->seq, mission_item->frame, mission_item->command, mission_item->current, mission_item->autocontinue, mission_item->param1, mission_item->param2, mission_item->param3, mission_item->param4, mission_item->x, mission_item->y, mission_item->z); } /** @@ -243,49 +260,55 @@ static inline uint16_t mavlink_msg_mission_item_encode_chan(uint8_t system_id, u static inline void mavlink_msg_mission_item_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, x); - _mav_put_float(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, buf, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, x); + _mav_put_float(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, buf, MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, buf, MAVLINK_MSG_ID_MISSION_ITEM_LEN); + mavlink_mission_item_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.seq = seq; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); #endif +} + +/** + * @brief Send a mission_item message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_item_send_struct(mavlink_channel_t chan, const mavlink_mission_item_t* mission_item) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_item_send(chan, mission_item->target_system, mission_item->target_component, mission_item->seq, mission_item->frame, mission_item->command, mission_item->current, mission_item->autocontinue, mission_item->param1, mission_item->param2, mission_item->param3, mission_item->param4, mission_item->x, mission_item->y, mission_item->z); #else - mavlink_mission_item_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.seq = seq; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, (const char *)mission_item, MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); #endif } @@ -300,49 +323,41 @@ static inline void mavlink_msg_mission_item_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_mission_item_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_float(buf, 16, x); - _mav_put_float(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, buf, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_float(buf, 16, x); + _mav_put_float(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, buf, MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, buf, MAVLINK_MSG_ID_MISSION_ITEM_LEN); -#endif -#else - mavlink_mission_item_t *packet = (mavlink_mission_item_t *)msgbuf; - packet->param1 = param1; - packet->param2 = param2; - packet->param3 = param3; - packet->param4 = param4; - packet->x = x; - packet->y = y; - packet->z = z; - packet->seq = seq; - packet->command = command; - packet->target_system = target_system; - packet->target_component = target_component; - packet->frame = frame; - packet->current = current; - packet->autocontinue = autocontinue; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_LEN); -#endif + mavlink_mission_item_t *packet = (mavlink_mission_item_t *)msgbuf; + packet->param1 = param1; + packet->param2 = param2; + packet->param3 = param3; + packet->param4 = param4; + packet->x = x; + packet->y = y; + packet->z = z; + packet->seq = seq; + packet->command = command; + packet->target_system = target_system; + packet->target_component = target_component; + packet->frame = frame; + packet->current = current; + packet->autocontinue = autocontinue; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_LEN, MAVLINK_MSG_ID_MISSION_ITEM_CRC); #endif } #endif @@ -359,7 +374,7 @@ static inline void mavlink_msg_mission_item_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_mission_item_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -369,7 +384,7 @@ static inline uint8_t mavlink_msg_mission_item_get_target_system(const mavlink_m */ static inline uint8_t mavlink_msg_mission_item_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 33); + return _MAV_RETURN_uint8_t(msg, 33); } /** @@ -379,7 +394,7 @@ static inline uint8_t mavlink_msg_mission_item_get_target_component(const mavlin */ static inline uint16_t mavlink_msg_mission_item_get_seq(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -389,7 +404,7 @@ static inline uint16_t mavlink_msg_mission_item_get_seq(const mavlink_message_t* */ static inline uint8_t mavlink_msg_mission_item_get_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -399,7 +414,7 @@ static inline uint8_t mavlink_msg_mission_item_get_frame(const mavlink_message_t */ static inline uint16_t mavlink_msg_mission_item_get_command(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 30); + return _MAV_RETURN_uint16_t(msg, 30); } /** @@ -409,7 +424,7 @@ static inline uint16_t mavlink_msg_mission_item_get_command(const mavlink_messag */ static inline uint8_t mavlink_msg_mission_item_get_current(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 35); + return _MAV_RETURN_uint8_t(msg, 35); } /** @@ -419,7 +434,7 @@ static inline uint8_t mavlink_msg_mission_item_get_current(const mavlink_message */ static inline uint8_t mavlink_msg_mission_item_get_autocontinue(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 36); + return _MAV_RETURN_uint8_t(msg, 36); } /** @@ -429,7 +444,7 @@ static inline uint8_t mavlink_msg_mission_item_get_autocontinue(const mavlink_me */ static inline float mavlink_msg_mission_item_get_param1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -439,7 +454,7 @@ static inline float mavlink_msg_mission_item_get_param1(const mavlink_message_t* */ static inline float mavlink_msg_mission_item_get_param2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -449,7 +464,7 @@ static inline float mavlink_msg_mission_item_get_param2(const mavlink_message_t* */ static inline float mavlink_msg_mission_item_get_param3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -459,7 +474,7 @@ static inline float mavlink_msg_mission_item_get_param3(const mavlink_message_t* */ static inline float mavlink_msg_mission_item_get_param4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -469,7 +484,7 @@ static inline float mavlink_msg_mission_item_get_param4(const mavlink_message_t* */ static inline float mavlink_msg_mission_item_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -479,7 +494,7 @@ static inline float mavlink_msg_mission_item_get_x(const mavlink_message_t* msg) */ static inline float mavlink_msg_mission_item_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -489,7 +504,7 @@ static inline float mavlink_msg_mission_item_get_y(const mavlink_message_t* msg) */ static inline float mavlink_msg_mission_item_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -500,22 +515,24 @@ static inline float mavlink_msg_mission_item_get_z(const mavlink_message_t* msg) */ static inline void mavlink_msg_mission_item_decode(const mavlink_message_t* msg, mavlink_mission_item_t* mission_item) { -#if MAVLINK_NEED_BYTE_SWAP - mission_item->param1 = mavlink_msg_mission_item_get_param1(msg); - mission_item->param2 = mavlink_msg_mission_item_get_param2(msg); - mission_item->param3 = mavlink_msg_mission_item_get_param3(msg); - mission_item->param4 = mavlink_msg_mission_item_get_param4(msg); - mission_item->x = mavlink_msg_mission_item_get_x(msg); - mission_item->y = mavlink_msg_mission_item_get_y(msg); - mission_item->z = mavlink_msg_mission_item_get_z(msg); - mission_item->seq = mavlink_msg_mission_item_get_seq(msg); - mission_item->command = mavlink_msg_mission_item_get_command(msg); - mission_item->target_system = mavlink_msg_mission_item_get_target_system(msg); - mission_item->target_component = mavlink_msg_mission_item_get_target_component(msg); - mission_item->frame = mavlink_msg_mission_item_get_frame(msg); - mission_item->current = mavlink_msg_mission_item_get_current(msg); - mission_item->autocontinue = mavlink_msg_mission_item_get_autocontinue(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_item->param1 = mavlink_msg_mission_item_get_param1(msg); + mission_item->param2 = mavlink_msg_mission_item_get_param2(msg); + mission_item->param3 = mavlink_msg_mission_item_get_param3(msg); + mission_item->param4 = mavlink_msg_mission_item_get_param4(msg); + mission_item->x = mavlink_msg_mission_item_get_x(msg); + mission_item->y = mavlink_msg_mission_item_get_y(msg); + mission_item->z = mavlink_msg_mission_item_get_z(msg); + mission_item->seq = mavlink_msg_mission_item_get_seq(msg); + mission_item->command = mavlink_msg_mission_item_get_command(msg); + mission_item->target_system = mavlink_msg_mission_item_get_target_system(msg); + mission_item->target_component = mavlink_msg_mission_item_get_target_component(msg); + mission_item->frame = mavlink_msg_mission_item_get_frame(msg); + mission_item->current = mavlink_msg_mission_item_get_current(msg); + mission_item->autocontinue = mavlink_msg_mission_item_get_autocontinue(msg); #else - memcpy(mission_item, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_ITEM_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_ITEM_LEN? msg->len : MAVLINK_MSG_ID_MISSION_ITEM_LEN; + memset(mission_item, 0, MAVLINK_MSG_ID_MISSION_ITEM_LEN); + memcpy(mission_item, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_item_int.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_item_int.h index 58d102e7b2..66847236f2 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_item_int.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_item_int.h @@ -1,37 +1,42 @@ +#pragma once // MESSAGE MISSION_ITEM_INT PACKING #define MAVLINK_MSG_ID_MISSION_ITEM_INT 73 -typedef struct __mavlink_mission_item_int_t -{ - float param1; ///< PARAM1, see MAV_CMD enum - float param2; ///< PARAM2, see MAV_CMD enum - float param3; ///< PARAM3, see MAV_CMD enum - float param4; ///< PARAM4, see MAV_CMD enum - int32_t x; ///< PARAM5 / local: x position in meters * 1e4, global: latitude in degrees * 10^7 - int32_t y; ///< PARAM6 / y position: local: x position in meters * 1e4, global: longitude in degrees *10^7 - float z; ///< PARAM7 / z position: global: altitude in meters (relative or absolute, depending on frame. - uint16_t seq; ///< Waypoint ID (sequence number). Starts at zero. Increases monotonically for each waypoint, no gaps in the sequence (0,1,2,3,4). - uint16_t command; ///< The scheduled action for the MISSION. see MAV_CMD in common.xml MAVLink specs - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t frame; ///< The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h - uint8_t current; ///< false:0, true:1 - uint8_t autocontinue; ///< autocontinue to next wp -} mavlink_mission_item_int_t; +MAVPACKED( +typedef struct __mavlink_mission_item_int_t { + float param1; /*< PARAM1, see MAV_CMD enum*/ + float param2; /*< PARAM2, see MAV_CMD enum*/ + float param3; /*< PARAM3, see MAV_CMD enum*/ + float param4; /*< PARAM4, see MAV_CMD enum*/ + int32_t x; /*< PARAM5 / local: x position in meters * 1e4, global: latitude in degrees * 10^7*/ + int32_t y; /*< PARAM6 / y position: local: x position in meters * 1e4, global: longitude in degrees *10^7*/ + float z; /*< PARAM7 / z position: global: altitude in meters (relative or absolute, depending on frame.*/ + uint16_t seq; /*< Waypoint ID (sequence number). Starts at zero. Increases monotonically for each waypoint, no gaps in the sequence (0,1,2,3,4).*/ + uint16_t command; /*< The scheduled action for the MISSION. see MAV_CMD in common.xml MAVLink specs*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t frame; /*< The coordinate system of the MISSION. see MAV_FRAME in mavlink_types.h*/ + uint8_t current; /*< false:0, true:1*/ + uint8_t autocontinue; /*< autocontinue to next wp*/ +}) mavlink_mission_item_int_t; #define MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN 37 +#define MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN 37 #define MAVLINK_MSG_ID_73_LEN 37 +#define MAVLINK_MSG_ID_73_MIN_LEN 37 #define MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC 38 #define MAVLINK_MSG_ID_73_CRC 38 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_ITEM_INT { \ - "MISSION_ITEM_INT", \ - 14, \ - { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mission_item_int_t, param1) }, \ + 73, \ + "MISSION_ITEM_INT", \ + 14, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mission_item_int_t, param1) }, \ { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mission_item_int_t, param2) }, \ { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mission_item_int_t, param3) }, \ { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_mission_item_int_t, param4) }, \ @@ -47,7 +52,27 @@ typedef struct __mavlink_mission_item_int_t { "autocontinue", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_mission_item_int_t, autocontinue) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_ITEM_INT { \ + "MISSION_ITEM_INT", \ + 14, \ + { { "param1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_mission_item_int_t, param1) }, \ + { "param2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_mission_item_int_t, param2) }, \ + { "param3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_mission_item_int_t, param3) }, \ + { "param4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_mission_item_int_t, param4) }, \ + { "x", NULL, MAVLINK_TYPE_INT32_T, 0, 16, offsetof(mavlink_mission_item_int_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_INT32_T, 0, 20, offsetof(mavlink_mission_item_int_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_mission_item_int_t, z) }, \ + { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_mission_item_int_t, seq) }, \ + { "command", NULL, MAVLINK_TYPE_UINT16_T, 0, 30, offsetof(mavlink_mission_item_int_t, command) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 32, offsetof(mavlink_mission_item_int_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 33, offsetof(mavlink_mission_item_int_t, target_component) }, \ + { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 34, offsetof(mavlink_mission_item_int_t, frame) }, \ + { "current", NULL, MAVLINK_TYPE_UINT8_T, 0, 35, offsetof(mavlink_mission_item_int_t, current) }, \ + { "autocontinue", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_mission_item_int_t, autocontinue) }, \ + } \ +} +#endif /** * @brief Pack a mission_item_int message @@ -72,52 +97,48 @@ typedef struct __mavlink_mission_item_int_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_item_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) + uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); #else - mavlink_mission_item_int_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.seq = seq; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; + mavlink_mission_item_int_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.seq = seq; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); } /** @@ -143,53 +164,49 @@ static inline uint16_t mavlink_msg_mission_item_int_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_item_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t seq,uint8_t frame,uint16_t command,uint8_t current,uint8_t autocontinue,float param1,float param2,float param3,float param4,int32_t x,int32_t y,float z) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t seq,uint8_t frame,uint16_t command,uint8_t current,uint8_t autocontinue,float param1,float param2,float param3,float param4,int32_t x,int32_t y,float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); #else - mavlink_mission_item_int_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.seq = seq; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; + mavlink_mission_item_int_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.seq = seq; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); } /** @@ -202,7 +219,7 @@ static inline uint16_t mavlink_msg_mission_item_int_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_mission_item_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_item_int_t* mission_item_int) { - return mavlink_msg_mission_item_int_pack(system_id, component_id, msg, mission_item_int->target_system, mission_item_int->target_component, mission_item_int->seq, mission_item_int->frame, mission_item_int->command, mission_item_int->current, mission_item_int->autocontinue, mission_item_int->param1, mission_item_int->param2, mission_item_int->param3, mission_item_int->param4, mission_item_int->x, mission_item_int->y, mission_item_int->z); + return mavlink_msg_mission_item_int_pack(system_id, component_id, msg, mission_item_int->target_system, mission_item_int->target_component, mission_item_int->seq, mission_item_int->frame, mission_item_int->command, mission_item_int->current, mission_item_int->autocontinue, mission_item_int->param1, mission_item_int->param2, mission_item_int->param3, mission_item_int->param4, mission_item_int->x, mission_item_int->y, mission_item_int->z); } /** @@ -216,7 +233,7 @@ static inline uint16_t mavlink_msg_mission_item_int_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_mission_item_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_item_int_t* mission_item_int) { - return mavlink_msg_mission_item_int_pack_chan(system_id, component_id, chan, msg, mission_item_int->target_system, mission_item_int->target_component, mission_item_int->seq, mission_item_int->frame, mission_item_int->command, mission_item_int->current, mission_item_int->autocontinue, mission_item_int->param1, mission_item_int->param2, mission_item_int->param3, mission_item_int->param4, mission_item_int->x, mission_item_int->y, mission_item_int->z); + return mavlink_msg_mission_item_int_pack_chan(system_id, component_id, chan, msg, mission_item_int->target_system, mission_item_int->target_component, mission_item_int->seq, mission_item_int->frame, mission_item_int->command, mission_item_int->current, mission_item_int->autocontinue, mission_item_int->param1, mission_item_int->param2, mission_item_int->param3, mission_item_int->param4, mission_item_int->x, mission_item_int->y, mission_item_int->z); } /** @@ -243,49 +260,55 @@ static inline uint16_t mavlink_msg_mission_item_int_encode_chan(uint8_t system_i static inline void mavlink_msg_mission_item_int_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN]; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN]; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); + mavlink_mission_item_int_t packet; + packet.param1 = param1; + packet.param2 = param2; + packet.param3 = param3; + packet.param4 = param4; + packet.x = x; + packet.y = y; + packet.z = z; + packet.seq = seq; + packet.command = command; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + packet.current = current; + packet.autocontinue = autocontinue; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); #endif +} + +/** + * @brief Send a mission_item_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_item_int_send_struct(mavlink_channel_t chan, const mavlink_mission_item_int_t* mission_item_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_item_int_send(chan, mission_item_int->target_system, mission_item_int->target_component, mission_item_int->seq, mission_item_int->frame, mission_item_int->command, mission_item_int->current, mission_item_int->autocontinue, mission_item_int->param1, mission_item_int->param2, mission_item_int->param3, mission_item_int->param4, mission_item_int->x, mission_item_int->y, mission_item_int->z); #else - mavlink_mission_item_int_t packet; - packet.param1 = param1; - packet.param2 = param2; - packet.param3 = param3; - packet.param4 = param4; - packet.x = x; - packet.y = y; - packet.z = z; - packet.seq = seq; - packet.command = command; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - packet.current = current; - packet.autocontinue = autocontinue; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, (const char *)mission_item_int, MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); #endif } @@ -300,49 +323,41 @@ static inline void mavlink_msg_mission_item_int_send(mavlink_channel_t chan, uin static inline void mavlink_msg_mission_item_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq, uint8_t frame, uint16_t command, uint8_t current, uint8_t autocontinue, float param1, float param2, float param3, float param4, int32_t x, int32_t y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, param1); - _mav_put_float(buf, 4, param2); - _mav_put_float(buf, 8, param3); - _mav_put_float(buf, 12, param4); - _mav_put_int32_t(buf, 16, x); - _mav_put_int32_t(buf, 20, y); - _mav_put_float(buf, 24, z); - _mav_put_uint16_t(buf, 28, seq); - _mav_put_uint16_t(buf, 30, command); - _mav_put_uint8_t(buf, 32, target_system); - _mav_put_uint8_t(buf, 33, target_component); - _mav_put_uint8_t(buf, 34, frame); - _mav_put_uint8_t(buf, 35, current); - _mav_put_uint8_t(buf, 36, autocontinue); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, param1); + _mav_put_float(buf, 4, param2); + _mav_put_float(buf, 8, param3); + _mav_put_float(buf, 12, param4); + _mav_put_int32_t(buf, 16, x); + _mav_put_int32_t(buf, 20, y); + _mav_put_float(buf, 24, z); + _mav_put_uint16_t(buf, 28, seq); + _mav_put_uint16_t(buf, 30, command); + _mav_put_uint8_t(buf, 32, target_system); + _mav_put_uint8_t(buf, 33, target_component); + _mav_put_uint8_t(buf, 34, frame); + _mav_put_uint8_t(buf, 35, current); + _mav_put_uint8_t(buf, 36, autocontinue); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, buf, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); -#endif -#else - mavlink_mission_item_int_t *packet = (mavlink_mission_item_int_t *)msgbuf; - packet->param1 = param1; - packet->param2 = param2; - packet->param3 = param3; - packet->param4 = param4; - packet->x = x; - packet->y = y; - packet->z = z; - packet->seq = seq; - packet->command = command; - packet->target_system = target_system; - packet->target_component = target_component; - packet->frame = frame; - packet->current = current; - packet->autocontinue = autocontinue; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); -#endif + mavlink_mission_item_int_t *packet = (mavlink_mission_item_int_t *)msgbuf; + packet->param1 = param1; + packet->param2 = param2; + packet->param3 = param3; + packet->param4 = param4; + packet->x = x; + packet->y = y; + packet->z = z; + packet->seq = seq; + packet->command = command; + packet->target_system = target_system; + packet->target_component = target_component; + packet->frame = frame; + packet->current = current; + packet->autocontinue = autocontinue; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_INT, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN, MAVLINK_MSG_ID_MISSION_ITEM_INT_CRC); #endif } #endif @@ -359,7 +374,7 @@ static inline void mavlink_msg_mission_item_int_send_buf(mavlink_message_t *msgb */ static inline uint8_t mavlink_msg_mission_item_int_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 32); + return _MAV_RETURN_uint8_t(msg, 32); } /** @@ -369,7 +384,7 @@ static inline uint8_t mavlink_msg_mission_item_int_get_target_system(const mavli */ static inline uint8_t mavlink_msg_mission_item_int_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 33); + return _MAV_RETURN_uint8_t(msg, 33); } /** @@ -379,7 +394,7 @@ static inline uint8_t mavlink_msg_mission_item_int_get_target_component(const ma */ static inline uint16_t mavlink_msg_mission_item_int_get_seq(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -389,7 +404,7 @@ static inline uint16_t mavlink_msg_mission_item_int_get_seq(const mavlink_messag */ static inline uint8_t mavlink_msg_mission_item_int_get_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 34); + return _MAV_RETURN_uint8_t(msg, 34); } /** @@ -399,7 +414,7 @@ static inline uint8_t mavlink_msg_mission_item_int_get_frame(const mavlink_messa */ static inline uint16_t mavlink_msg_mission_item_int_get_command(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 30); + return _MAV_RETURN_uint16_t(msg, 30); } /** @@ -409,7 +424,7 @@ static inline uint16_t mavlink_msg_mission_item_int_get_command(const mavlink_me */ static inline uint8_t mavlink_msg_mission_item_int_get_current(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 35); + return _MAV_RETURN_uint8_t(msg, 35); } /** @@ -419,7 +434,7 @@ static inline uint8_t mavlink_msg_mission_item_int_get_current(const mavlink_mes */ static inline uint8_t mavlink_msg_mission_item_int_get_autocontinue(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 36); + return _MAV_RETURN_uint8_t(msg, 36); } /** @@ -429,7 +444,7 @@ static inline uint8_t mavlink_msg_mission_item_int_get_autocontinue(const mavlin */ static inline float mavlink_msg_mission_item_int_get_param1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -439,7 +454,7 @@ static inline float mavlink_msg_mission_item_int_get_param1(const mavlink_messag */ static inline float mavlink_msg_mission_item_int_get_param2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -449,7 +464,7 @@ static inline float mavlink_msg_mission_item_int_get_param2(const mavlink_messag */ static inline float mavlink_msg_mission_item_int_get_param3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -459,7 +474,7 @@ static inline float mavlink_msg_mission_item_int_get_param3(const mavlink_messag */ static inline float mavlink_msg_mission_item_int_get_param4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -469,7 +484,7 @@ static inline float mavlink_msg_mission_item_int_get_param4(const mavlink_messag */ static inline int32_t mavlink_msg_mission_item_int_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 16); + return _MAV_RETURN_int32_t(msg, 16); } /** @@ -479,7 +494,7 @@ static inline int32_t mavlink_msg_mission_item_int_get_x(const mavlink_message_t */ static inline int32_t mavlink_msg_mission_item_int_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 20); + return _MAV_RETURN_int32_t(msg, 20); } /** @@ -489,7 +504,7 @@ static inline int32_t mavlink_msg_mission_item_int_get_y(const mavlink_message_t */ static inline float mavlink_msg_mission_item_int_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -500,22 +515,24 @@ static inline float mavlink_msg_mission_item_int_get_z(const mavlink_message_t* */ static inline void mavlink_msg_mission_item_int_decode(const mavlink_message_t* msg, mavlink_mission_item_int_t* mission_item_int) { -#if MAVLINK_NEED_BYTE_SWAP - mission_item_int->param1 = mavlink_msg_mission_item_int_get_param1(msg); - mission_item_int->param2 = mavlink_msg_mission_item_int_get_param2(msg); - mission_item_int->param3 = mavlink_msg_mission_item_int_get_param3(msg); - mission_item_int->param4 = mavlink_msg_mission_item_int_get_param4(msg); - mission_item_int->x = mavlink_msg_mission_item_int_get_x(msg); - mission_item_int->y = mavlink_msg_mission_item_int_get_y(msg); - mission_item_int->z = mavlink_msg_mission_item_int_get_z(msg); - mission_item_int->seq = mavlink_msg_mission_item_int_get_seq(msg); - mission_item_int->command = mavlink_msg_mission_item_int_get_command(msg); - mission_item_int->target_system = mavlink_msg_mission_item_int_get_target_system(msg); - mission_item_int->target_component = mavlink_msg_mission_item_int_get_target_component(msg); - mission_item_int->frame = mavlink_msg_mission_item_int_get_frame(msg); - mission_item_int->current = mavlink_msg_mission_item_int_get_current(msg); - mission_item_int->autocontinue = mavlink_msg_mission_item_int_get_autocontinue(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_item_int->param1 = mavlink_msg_mission_item_int_get_param1(msg); + mission_item_int->param2 = mavlink_msg_mission_item_int_get_param2(msg); + mission_item_int->param3 = mavlink_msg_mission_item_int_get_param3(msg); + mission_item_int->param4 = mavlink_msg_mission_item_int_get_param4(msg); + mission_item_int->x = mavlink_msg_mission_item_int_get_x(msg); + mission_item_int->y = mavlink_msg_mission_item_int_get_y(msg); + mission_item_int->z = mavlink_msg_mission_item_int_get_z(msg); + mission_item_int->seq = mavlink_msg_mission_item_int_get_seq(msg); + mission_item_int->command = mavlink_msg_mission_item_int_get_command(msg); + mission_item_int->target_system = mavlink_msg_mission_item_int_get_target_system(msg); + mission_item_int->target_component = mavlink_msg_mission_item_int_get_target_component(msg); + mission_item_int->frame = mavlink_msg_mission_item_int_get_frame(msg); + mission_item_int->current = mavlink_msg_mission_item_int_get_current(msg); + mission_item_int->autocontinue = mavlink_msg_mission_item_int_get_autocontinue(msg); #else - memcpy(mission_item_int, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN? msg->len : MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN; + memset(mission_item_int, 0, MAVLINK_MSG_ID_MISSION_ITEM_INT_LEN); + memcpy(mission_item_int, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_item_reached.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_item_reached.h index 9dfa280433..1ad0e29cef 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_item_reached.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_item_reached.h @@ -1,27 +1,39 @@ +#pragma once // MESSAGE MISSION_ITEM_REACHED PACKING #define MAVLINK_MSG_ID_MISSION_ITEM_REACHED 46 -typedef struct __mavlink_mission_item_reached_t -{ - uint16_t seq; ///< Sequence -} mavlink_mission_item_reached_t; +MAVPACKED( +typedef struct __mavlink_mission_item_reached_t { + uint16_t seq; /*< Sequence*/ +}) mavlink_mission_item_reached_t; #define MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN 2 +#define MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN 2 #define MAVLINK_MSG_ID_46_LEN 2 +#define MAVLINK_MSG_ID_46_MIN_LEN 2 #define MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC 11 #define MAVLINK_MSG_ID_46_CRC 11 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED { \ - "MISSION_ITEM_REACHED", \ - 1, \ - { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_item_reached_t, seq) }, \ + 46, \ + "MISSION_ITEM_REACHED", \ + 1, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_item_reached_t, seq) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_ITEM_REACHED { \ + "MISSION_ITEM_REACHED", \ + 1, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_item_reached_t, seq) }, \ + } \ +} +#endif /** * @brief Pack a mission_item_reached message @@ -33,26 +45,22 @@ typedef struct __mavlink_mission_item_reached_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_item_reached_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t seq) + uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN]; - _mav_put_uint16_t(buf, 0, seq); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN]; + _mav_put_uint16_t(buf, 0, seq); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); #else - mavlink_mission_item_reached_t packet; - packet.seq = seq; + mavlink_mission_item_reached_t packet; + packet.seq = seq; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_REACHED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_REACHED; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); } /** @@ -65,27 +73,23 @@ static inline uint16_t mavlink_msg_mission_item_reached_pack(uint8_t system_id, * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_item_reached_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t seq) + mavlink_message_t* msg, + uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN]; - _mav_put_uint16_t(buf, 0, seq); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN]; + _mav_put_uint16_t(buf, 0, seq); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); #else - mavlink_mission_item_reached_t packet; - packet.seq = seq; + mavlink_mission_item_reached_t packet; + packet.seq = seq; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_REACHED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_ITEM_REACHED; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); } /** @@ -98,7 +102,7 @@ static inline uint16_t mavlink_msg_mission_item_reached_pack_chan(uint8_t system */ static inline uint16_t mavlink_msg_mission_item_reached_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_item_reached_t* mission_item_reached) { - return mavlink_msg_mission_item_reached_pack(system_id, component_id, msg, mission_item_reached->seq); + return mavlink_msg_mission_item_reached_pack(system_id, component_id, msg, mission_item_reached->seq); } /** @@ -112,7 +116,7 @@ static inline uint16_t mavlink_msg_mission_item_reached_encode(uint8_t system_id */ static inline uint16_t mavlink_msg_mission_item_reached_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_item_reached_t* mission_item_reached) { - return mavlink_msg_mission_item_reached_pack_chan(system_id, component_id, chan, msg, mission_item_reached->seq); + return mavlink_msg_mission_item_reached_pack_chan(system_id, component_id, chan, msg, mission_item_reached->seq); } /** @@ -126,23 +130,29 @@ static inline uint16_t mavlink_msg_mission_item_reached_encode_chan(uint8_t syst static inline void mavlink_msg_mission_item_reached_send(mavlink_channel_t chan, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN]; - _mav_put_uint16_t(buf, 0, seq); + char buf[MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN]; + _mav_put_uint16_t(buf, 0, seq); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); + mavlink_mission_item_reached_t packet; + packet.seq = seq; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); #endif -#else - mavlink_mission_item_reached_t packet; - packet.seq = seq; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); +/** + * @brief Send a mission_item_reached message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_item_reached_send_struct(mavlink_channel_t chan, const mavlink_mission_item_reached_t* mission_item_reached) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_item_reached_send(chan, mission_item_reached->seq); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, (const char *)&packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, (const char *)mission_item_reached, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); #endif } @@ -157,23 +167,15 @@ static inline void mavlink_msg_mission_item_reached_send(mavlink_channel_t chan, static inline void mavlink_msg_mission_item_reached_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, seq); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, seq); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, buf, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); #else - mavlink_mission_item_reached_t *packet = (mavlink_mission_item_reached_t *)msgbuf; - packet->seq = seq; + mavlink_mission_item_reached_t *packet = (mavlink_mission_item_reached_t *)msgbuf; + packet->seq = seq; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_ITEM_REACHED, (const char *)packet, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_CRC); #endif } #endif @@ -190,7 +192,7 @@ static inline void mavlink_msg_mission_item_reached_send_buf(mavlink_message_t * */ static inline uint16_t mavlink_msg_mission_item_reached_get_seq(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -201,9 +203,11 @@ static inline uint16_t mavlink_msg_mission_item_reached_get_seq(const mavlink_me */ static inline void mavlink_msg_mission_item_reached_decode(const mavlink_message_t* msg, mavlink_mission_item_reached_t* mission_item_reached) { -#if MAVLINK_NEED_BYTE_SWAP - mission_item_reached->seq = mavlink_msg_mission_item_reached_get_seq(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_item_reached->seq = mavlink_msg_mission_item_reached_get_seq(msg); #else - memcpy(mission_item_reached, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN? msg->len : MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN; + memset(mission_item_reached, 0, MAVLINK_MSG_ID_MISSION_ITEM_REACHED_LEN); + memcpy(mission_item_reached, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_request.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_request.h index 29b0ef6ef5..9d6d48ec34 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_request.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_request.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE MISSION_REQUEST PACKING #define MAVLINK_MSG_ID_MISSION_REQUEST 40 -typedef struct __mavlink_mission_request_t -{ - uint16_t seq; ///< Sequence - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mission_request_t; +MAVPACKED( +typedef struct __mavlink_mission_request_t { + uint16_t seq; /*< Sequence*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_request_t; #define MAVLINK_MSG_ID_MISSION_REQUEST_LEN 4 +#define MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN 4 #define MAVLINK_MSG_ID_40_LEN 4 +#define MAVLINK_MSG_ID_40_MIN_LEN 4 #define MAVLINK_MSG_ID_MISSION_REQUEST_CRC 230 #define MAVLINK_MSG_ID_40_CRC 230 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_REQUEST { \ - "MISSION_REQUEST", \ - 3, \ - { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_request_t, seq) }, \ + 40, \ + "MISSION_REQUEST", \ + 3, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_request_t, seq) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_request_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_request_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_REQUEST { \ + "MISSION_REQUEST", \ + 3, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_request_t, seq) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_request_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_request_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mission_request message @@ -39,30 +53,26 @@ typedef struct __mavlink_mission_request_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_request_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t seq) + uint8_t target_system, uint8_t target_component, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LEN]; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); #else - mavlink_mission_request_t packet; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_request_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_mission_request_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_request_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t seq) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LEN]; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); #else - mavlink_mission_request_t packet; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_request_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_mission_request_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_mission_request_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_request_t* mission_request) { - return mavlink_msg_mission_request_pack(system_id, component_id, msg, mission_request->target_system, mission_request->target_component, mission_request->seq); + return mavlink_msg_mission_request_pack(system_id, component_id, msg, mission_request->target_system, mission_request->target_component, mission_request->seq); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_mission_request_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_mission_request_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_request_t* mission_request) { - return mavlink_msg_mission_request_pack_chan(system_id, component_id, chan, msg, mission_request->target_system, mission_request->target_component, mission_request->seq); + return mavlink_msg_mission_request_pack_chan(system_id, component_id, chan, msg, mission_request->target_system, mission_request->target_component, mission_request->seq); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_mission_request_encode_chan(uint8_t system_id static inline void mavlink_msg_mission_request_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LEN]; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); + mavlink_mission_request_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); #endif -#else - mavlink_mission_request_t packet; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); +/** + * @brief Send a mission_request message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_request_send_struct(mavlink_channel_t chan, const mavlink_mission_request_t* mission_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_request_send(chan, mission_request->target_system, mission_request->target_component, mission_request->seq); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, (const char *)mission_request, MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_mission_request_send(mavlink_channel_t chan, uint static inline void mavlink_msg_mission_request_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); #else - mavlink_mission_request_t *packet = (mavlink_mission_request_t *)msgbuf; - packet->seq = seq; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_mission_request_t *packet = (mavlink_mission_request_t *)msgbuf; + packet->seq = seq; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_mission_request_send_buf(mavlink_message_t *msgbu */ static inline uint8_t mavlink_msg_mission_request_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_mission_request_get_target_system(const mavlin */ static inline uint8_t mavlink_msg_mission_request_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_mission_request_get_target_component(const mav */ static inline uint16_t mavlink_msg_mission_request_get_seq(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -247,11 +251,13 @@ static inline uint16_t mavlink_msg_mission_request_get_seq(const mavlink_message */ static inline void mavlink_msg_mission_request_decode(const mavlink_message_t* msg, mavlink_mission_request_t* mission_request) { -#if MAVLINK_NEED_BYTE_SWAP - mission_request->seq = mavlink_msg_mission_request_get_seq(msg); - mission_request->target_system = mavlink_msg_mission_request_get_target_system(msg); - mission_request->target_component = mavlink_msg_mission_request_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_request->seq = mavlink_msg_mission_request_get_seq(msg); + mission_request->target_system = mavlink_msg_mission_request_get_target_system(msg); + mission_request->target_component = mavlink_msg_mission_request_get_target_component(msg); #else - memcpy(mission_request, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_REQUEST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_REQUEST_LEN? msg->len : MAVLINK_MSG_ID_MISSION_REQUEST_LEN; + memset(mission_request, 0, MAVLINK_MSG_ID_MISSION_REQUEST_LEN); + memcpy(mission_request, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_request_int.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_request_int.h new file mode 100644 index 0000000000..3257f94c07 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_request_int.h @@ -0,0 +1,263 @@ +#pragma once +// MESSAGE MISSION_REQUEST_INT PACKING + +#define MAVLINK_MSG_ID_MISSION_REQUEST_INT 51 + +MAVPACKED( +typedef struct __mavlink_mission_request_int_t { + uint16_t seq; /*< Sequence*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_request_int_t; + +#define MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN 4 +#define MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN 4 +#define MAVLINK_MSG_ID_51_LEN 4 +#define MAVLINK_MSG_ID_51_MIN_LEN 4 + +#define MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC 196 +#define MAVLINK_MSG_ID_51_CRC 196 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_MISSION_REQUEST_INT { \ + 51, \ + "MISSION_REQUEST_INT", \ + 3, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_request_int_t, seq) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_request_int_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_request_int_t, target_component) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_MISSION_REQUEST_INT { \ + "MISSION_REQUEST_INT", \ + 3, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_request_int_t, seq) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_request_int_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_request_int_t, target_component) }, \ + } \ +} +#endif + +/** + * @brief Pack a mission_request_int message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID + * @param target_component Component ID + * @param seq Sequence + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_mission_request_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, uint8_t target_component, uint16_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN); +#else + mavlink_mission_request_int_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC); +} + +/** + * @brief Pack a mission_request_int message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID + * @param target_component Component ID + * @param seq Sequence + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_mission_request_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN); +#else + mavlink_mission_request_int_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC); +} + +/** + * @brief Encode a mission_request_int struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param mission_request_int C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_request_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_request_int_t* mission_request_int) +{ + return mavlink_msg_mission_request_int_pack(system_id, component_id, msg, mission_request_int->target_system, mission_request_int->target_component, mission_request_int->seq); +} + +/** + * @brief Encode a mission_request_int struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param mission_request_int C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_mission_request_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_request_int_t* mission_request_int) +{ + return mavlink_msg_mission_request_int_pack_chan(system_id, component_id, chan, msg, mission_request_int->target_system, mission_request_int->target_component, mission_request_int->seq); +} + +/** + * @brief Send a mission_request_int message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID + * @param target_component Component ID + * @param seq Sequence + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_mission_request_int_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_INT, buf, MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC); +#else + mavlink_mission_request_int_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_INT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC); +#endif +} + +/** + * @brief Send a mission_request_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_request_int_send_struct(mavlink_channel_t chan, const mavlink_mission_request_int_t* mission_request_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_request_int_send(chan, mission_request_int->target_system, mission_request_int->target_component, mission_request_int->seq); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_INT, (const char *)mission_request_int, MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC); +#endif +} + +#if MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_mission_request_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_INT, buf, MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC); +#else + mavlink_mission_request_int_t *packet = (mavlink_mission_request_int_t *)msgbuf; + packet->seq = seq; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_INT, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_INT_CRC); +#endif +} +#endif + +#endif + +// MESSAGE MISSION_REQUEST_INT UNPACKING + + +/** + * @brief Get field target_system from mission_request_int message + * + * @return System ID + */ +static inline uint8_t mavlink_msg_mission_request_int_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 2); +} + +/** + * @brief Get field target_component from mission_request_int message + * + * @return Component ID + */ +static inline uint8_t mavlink_msg_mission_request_int_get_target_component(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 3); +} + +/** + * @brief Get field seq from mission_request_int message + * + * @return Sequence + */ +static inline uint16_t mavlink_msg_mission_request_int_get_seq(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint16_t(msg, 0); +} + +/** + * @brief Decode a mission_request_int message into a struct + * + * @param msg The message to decode + * @param mission_request_int C-struct to decode the message contents into + */ +static inline void mavlink_msg_mission_request_int_decode(const mavlink_message_t* msg, mavlink_mission_request_int_t* mission_request_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_request_int->seq = mavlink_msg_mission_request_int_get_seq(msg); + mission_request_int->target_system = mavlink_msg_mission_request_int_get_target_system(msg); + mission_request_int->target_component = mavlink_msg_mission_request_int_get_target_component(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN? msg->len : MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN; + memset(mission_request_int, 0, MAVLINK_MSG_ID_MISSION_REQUEST_INT_LEN); + memcpy(mission_request_int, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_request_list.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_request_list.h index a275348acc..64c211ba62 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_request_list.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_request_list.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE MISSION_REQUEST_LIST PACKING #define MAVLINK_MSG_ID_MISSION_REQUEST_LIST 43 -typedef struct __mavlink_mission_request_list_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mission_request_list_t; +MAVPACKED( +typedef struct __mavlink_mission_request_list_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_request_list_t; #define MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN 2 +#define MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN 2 #define MAVLINK_MSG_ID_43_LEN 2 +#define MAVLINK_MSG_ID_43_MIN_LEN 2 #define MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC 132 #define MAVLINK_MSG_ID_43_CRC 132 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST { \ - "MISSION_REQUEST_LIST", \ - 2, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_request_list_t, target_system) }, \ + 43, \ + "MISSION_REQUEST_LIST", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_request_list_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mission_request_list_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_REQUEST_LIST { \ + "MISSION_REQUEST_LIST", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_mission_request_list_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_mission_request_list_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mission_request_list message @@ -36,28 +49,24 @@ typedef struct __mavlink_mission_request_list_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_request_list_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component) + uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); #else - mavlink_mission_request_list_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_request_list_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_LIST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_mission_request_list_pack(uint8_t system_id, * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_request_list_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); #else - mavlink_mission_request_list_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_request_list_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_LIST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_mission_request_list_pack_chan(uint8_t system */ static inline uint16_t mavlink_msg_mission_request_list_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_request_list_t* mission_request_list) { - return mavlink_msg_mission_request_list_pack(system_id, component_id, msg, mission_request_list->target_system, mission_request_list->target_component); + return mavlink_msg_mission_request_list_pack(system_id, component_id, msg, mission_request_list->target_system, mission_request_list->target_component); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_mission_request_list_encode(uint8_t system_id */ static inline uint16_t mavlink_msg_mission_request_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_request_list_t* mission_request_list) { - return mavlink_msg_mission_request_list_pack_chan(system_id, component_id, chan, msg, mission_request_list->target_system, mission_request_list->target_component); + return mavlink_msg_mission_request_list_pack_chan(system_id, component_id, chan, msg, mission_request_list->target_system, mission_request_list->target_component); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_mission_request_list_encode_chan(uint8_t syst static inline void mavlink_msg_mission_request_list_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); + mavlink_mission_request_list_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); #endif -#else - mavlink_mission_request_list_t packet; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); +/** + * @brief Send a mission_request_list message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_request_list_send_struct(mavlink_channel_t chan, const mavlink_mission_request_list_t* mission_request_list) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_request_list_send(chan, mission_request_list->target_system, mission_request_list->target_component); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, (const char *)mission_request_list, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_mission_request_list_send(mavlink_channel_t chan, static inline void mavlink_msg_mission_request_list_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); #else - mavlink_mission_request_list_t *packet = (mavlink_mission_request_list_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_mission_request_list_t *packet = (mavlink_mission_request_list_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_mission_request_list_send_buf(mavlink_message_t * */ static inline uint8_t mavlink_msg_mission_request_list_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint8_t mavlink_msg_mission_request_list_get_target_system(const m */ static inline uint8_t mavlink_msg_mission_request_list_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_mission_request_list_get_target_component(cons */ static inline void mavlink_msg_mission_request_list_decode(const mavlink_message_t* msg, mavlink_mission_request_list_t* mission_request_list) { -#if MAVLINK_NEED_BYTE_SWAP - mission_request_list->target_system = mavlink_msg_mission_request_list_get_target_system(msg); - mission_request_list->target_component = mavlink_msg_mission_request_list_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_request_list->target_system = mavlink_msg_mission_request_list_get_target_system(msg); + mission_request_list->target_component = mavlink_msg_mission_request_list_get_target_component(msg); #else - memcpy(mission_request_list, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN? msg->len : MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN; + memset(mission_request_list, 0, MAVLINK_MSG_ID_MISSION_REQUEST_LIST_LEN); + memcpy(mission_request_list, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_request_partial_list.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_request_partial_list.h index 79a88dc084..aa7576321a 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_request_partial_list.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_request_partial_list.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE MISSION_REQUEST_PARTIAL_LIST PACKING #define MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST 37 -typedef struct __mavlink_mission_request_partial_list_t -{ - int16_t start_index; ///< Start index, 0 by default - int16_t end_index; ///< End index, -1 by default (-1: send list to end). Else a valid index of the list - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mission_request_partial_list_t; +MAVPACKED( +typedef struct __mavlink_mission_request_partial_list_t { + int16_t start_index; /*< Start index, 0 by default*/ + int16_t end_index; /*< End index, -1 by default (-1: send list to end). Else a valid index of the list*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_request_partial_list_t; #define MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN 6 +#define MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN 6 #define MAVLINK_MSG_ID_37_LEN 6 +#define MAVLINK_MSG_ID_37_MIN_LEN 6 #define MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC 212 #define MAVLINK_MSG_ID_37_CRC 212 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST { \ - "MISSION_REQUEST_PARTIAL_LIST", \ - 4, \ - { { "start_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_mission_request_partial_list_t, start_index) }, \ + 37, \ + "MISSION_REQUEST_PARTIAL_LIST", \ + 4, \ + { { "start_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_mission_request_partial_list_t, start_index) }, \ { "end_index", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_mission_request_partial_list_t, end_index) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_mission_request_partial_list_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_mission_request_partial_list_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_REQUEST_PARTIAL_LIST { \ + "MISSION_REQUEST_PARTIAL_LIST", \ + 4, \ + { { "start_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_mission_request_partial_list_t, start_index) }, \ + { "end_index", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_mission_request_partial_list_t, end_index) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_mission_request_partial_list_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_mission_request_partial_list_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mission_request_partial_list message @@ -42,32 +57,28 @@ typedef struct __mavlink_mission_request_partial_list_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_request_partial_list_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) + uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN]; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN]; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); #else - mavlink_mission_request_partial_list_t packet; - packet.start_index = start_index; - packet.end_index = end_index; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_request_partial_list_t packet; + packet.start_index = start_index; + packet.end_index = end_index; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_mission_request_partial_list_pack(uint8_t sys * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_request_partial_list_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,int16_t start_index,int16_t end_index) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,int16_t start_index,int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN]; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN]; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); #else - mavlink_mission_request_partial_list_t packet; - packet.start_index = start_index; - packet.end_index = end_index; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_request_partial_list_t packet; + packet.start_index = start_index; + packet.end_index = end_index; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_mission_request_partial_list_pack_chan(uint8_ */ static inline uint16_t mavlink_msg_mission_request_partial_list_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_request_partial_list_t* mission_request_partial_list) { - return mavlink_msg_mission_request_partial_list_pack(system_id, component_id, msg, mission_request_partial_list->target_system, mission_request_partial_list->target_component, mission_request_partial_list->start_index, mission_request_partial_list->end_index); + return mavlink_msg_mission_request_partial_list_pack(system_id, component_id, msg, mission_request_partial_list->target_system, mission_request_partial_list->target_component, mission_request_partial_list->start_index, mission_request_partial_list->end_index); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_mission_request_partial_list_encode(uint8_t s */ static inline uint16_t mavlink_msg_mission_request_partial_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_request_partial_list_t* mission_request_partial_list) { - return mavlink_msg_mission_request_partial_list_pack_chan(system_id, component_id, chan, msg, mission_request_partial_list->target_system, mission_request_partial_list->target_component, mission_request_partial_list->start_index, mission_request_partial_list->end_index); + return mavlink_msg_mission_request_partial_list_pack_chan(system_id, component_id, chan, msg, mission_request_partial_list->target_system, mission_request_partial_list->target_component, mission_request_partial_list->start_index, mission_request_partial_list->end_index); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_mission_request_partial_list_encode_chan(uint static inline void mavlink_msg_mission_request_partial_list_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN]; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); + char buf[MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN]; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); + mavlink_mission_request_partial_list_t packet; + packet.start_index = start_index; + packet.end_index = end_index; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); #endif +} + +/** + * @brief Send a mission_request_partial_list message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_request_partial_list_send_struct(mavlink_channel_t chan, const mavlink_mission_request_partial_list_t* mission_request_partial_list) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_request_partial_list_send(chan, mission_request_partial_list->target_system, mission_request_partial_list->target_component, mission_request_partial_list->start_index, mission_request_partial_list->end_index); #else - mavlink_mission_request_partial_list_t packet; - packet.start_index = start_index; - packet.end_index = end_index; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, (const char *)mission_request_partial_list, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_mission_request_partial_list_send(mavlink_channel static inline void mavlink_msg_mission_request_partial_list_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); -#endif -#else - mavlink_mission_request_partial_list_t *packet = (mavlink_mission_request_partial_list_t *)msgbuf; - packet->start_index = start_index; - packet->end_index = end_index; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); + char *buf = (char *)msgbuf; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); -#endif + mavlink_mission_request_partial_list_t *packet = (mavlink_mission_request_partial_list_t *)msgbuf; + packet->start_index = start_index; + packet->end_index = end_index; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_mission_request_partial_list_send_buf(mavlink_mes */ static inline uint8_t mavlink_msg_mission_request_partial_list_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -239,7 +244,7 @@ static inline uint8_t mavlink_msg_mission_request_partial_list_get_target_system */ static inline uint8_t mavlink_msg_mission_request_partial_list_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -249,7 +254,7 @@ static inline uint8_t mavlink_msg_mission_request_partial_list_get_target_compon */ static inline int16_t mavlink_msg_mission_request_partial_list_get_start_index(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 0); + return _MAV_RETURN_int16_t(msg, 0); } /** @@ -259,7 +264,7 @@ static inline int16_t mavlink_msg_mission_request_partial_list_get_start_index(c */ static inline int16_t mavlink_msg_mission_request_partial_list_get_end_index(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 2); + return _MAV_RETURN_int16_t(msg, 2); } /** @@ -270,12 +275,14 @@ static inline int16_t mavlink_msg_mission_request_partial_list_get_end_index(con */ static inline void mavlink_msg_mission_request_partial_list_decode(const mavlink_message_t* msg, mavlink_mission_request_partial_list_t* mission_request_partial_list) { -#if MAVLINK_NEED_BYTE_SWAP - mission_request_partial_list->start_index = mavlink_msg_mission_request_partial_list_get_start_index(msg); - mission_request_partial_list->end_index = mavlink_msg_mission_request_partial_list_get_end_index(msg); - mission_request_partial_list->target_system = mavlink_msg_mission_request_partial_list_get_target_system(msg); - mission_request_partial_list->target_component = mavlink_msg_mission_request_partial_list_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_request_partial_list->start_index = mavlink_msg_mission_request_partial_list_get_start_index(msg); + mission_request_partial_list->end_index = mavlink_msg_mission_request_partial_list_get_end_index(msg); + mission_request_partial_list->target_system = mavlink_msg_mission_request_partial_list_get_target_system(msg); + mission_request_partial_list->target_component = mavlink_msg_mission_request_partial_list_get_target_component(msg); #else - memcpy(mission_request_partial_list, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN? msg->len : MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN; + memset(mission_request_partial_list, 0, MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_LEN); + memcpy(mission_request_partial_list, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_set_current.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_set_current.h index 0c2a3ada4e..50942fc443 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_set_current.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_set_current.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE MISSION_SET_CURRENT PACKING #define MAVLINK_MSG_ID_MISSION_SET_CURRENT 41 -typedef struct __mavlink_mission_set_current_t -{ - uint16_t seq; ///< Sequence - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mission_set_current_t; +MAVPACKED( +typedef struct __mavlink_mission_set_current_t { + uint16_t seq; /*< Sequence*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_set_current_t; #define MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN 4 +#define MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN 4 #define MAVLINK_MSG_ID_41_LEN 4 +#define MAVLINK_MSG_ID_41_MIN_LEN 4 #define MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC 28 #define MAVLINK_MSG_ID_41_CRC 28 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT { \ - "MISSION_SET_CURRENT", \ - 3, \ - { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_set_current_t, seq) }, \ + 41, \ + "MISSION_SET_CURRENT", \ + 3, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_set_current_t, seq) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_set_current_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_set_current_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_SET_CURRENT { \ + "MISSION_SET_CURRENT", \ + 3, \ + { { "seq", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_mission_set_current_t, seq) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_mission_set_current_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_mission_set_current_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mission_set_current message @@ -39,30 +53,26 @@ typedef struct __mavlink_mission_set_current_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_set_current_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t seq) + uint8_t target_system, uint8_t target_component, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN]; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); #else - mavlink_mission_set_current_t packet; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_set_current_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_SET_CURRENT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_SET_CURRENT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_mission_set_current_pack(uint8_t system_id, u * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_set_current_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t seq) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN]; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); #else - mavlink_mission_set_current_t packet; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_set_current_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_SET_CURRENT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_SET_CURRENT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_mission_set_current_pack_chan(uint8_t system_ */ static inline uint16_t mavlink_msg_mission_set_current_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_set_current_t* mission_set_current) { - return mavlink_msg_mission_set_current_pack(system_id, component_id, msg, mission_set_current->target_system, mission_set_current->target_component, mission_set_current->seq); + return mavlink_msg_mission_set_current_pack(system_id, component_id, msg, mission_set_current->target_system, mission_set_current->target_component, mission_set_current->seq); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_mission_set_current_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_mission_set_current_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_set_current_t* mission_set_current) { - return mavlink_msg_mission_set_current_pack_chan(system_id, component_id, chan, msg, mission_set_current->target_system, mission_set_current->target_component, mission_set_current->seq); + return mavlink_msg_mission_set_current_pack_chan(system_id, component_id, chan, msg, mission_set_current->target_system, mission_set_current->target_component, mission_set_current->seq); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_mission_set_current_encode_chan(uint8_t syste static inline void mavlink_msg_mission_set_current_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN]; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char buf[MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN]; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); + mavlink_mission_set_current_t packet; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); #endif -#else - mavlink_mission_set_current_t packet; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); +/** + * @brief Send a mission_set_current message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_set_current_send_struct(mavlink_channel_t chan, const mavlink_mission_set_current_t* mission_set_current) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_set_current_send(chan, mission_set_current->target_system, mission_set_current->target_component, mission_set_current->seq); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, (const char *)&packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, (const char *)mission_set_current, MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_mission_set_current_send(mavlink_channel_t chan, static inline void mavlink_msg_mission_set_current_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t seq) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, seq); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, seq); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, buf, MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); #else - mavlink_mission_set_current_t *packet = (mavlink_mission_set_current_t *)msgbuf; - packet->seq = seq; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_mission_set_current_t *packet = (mavlink_mission_set_current_t *)msgbuf; + packet->seq = seq; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, (const char *)packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, (const char *)packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_SET_CURRENT, (const char *)packet, MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN, MAVLINK_MSG_ID_MISSION_SET_CURRENT_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_mission_set_current_send_buf(mavlink_message_t *m */ static inline uint8_t mavlink_msg_mission_set_current_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_mission_set_current_get_target_system(const ma */ static inline uint8_t mavlink_msg_mission_set_current_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_mission_set_current_get_target_component(const */ static inline uint16_t mavlink_msg_mission_set_current_get_seq(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -247,11 +251,13 @@ static inline uint16_t mavlink_msg_mission_set_current_get_seq(const mavlink_mes */ static inline void mavlink_msg_mission_set_current_decode(const mavlink_message_t* msg, mavlink_mission_set_current_t* mission_set_current) { -#if MAVLINK_NEED_BYTE_SWAP - mission_set_current->seq = mavlink_msg_mission_set_current_get_seq(msg); - mission_set_current->target_system = mavlink_msg_mission_set_current_get_target_system(msg); - mission_set_current->target_component = mavlink_msg_mission_set_current_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_set_current->seq = mavlink_msg_mission_set_current_get_seq(msg); + mission_set_current->target_system = mavlink_msg_mission_set_current_get_target_system(msg); + mission_set_current->target_component = mavlink_msg_mission_set_current_get_target_component(msg); #else - memcpy(mission_set_current, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN? msg->len : MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN; + memset(mission_set_current, 0, MAVLINK_MSG_ID_MISSION_SET_CURRENT_LEN); + memcpy(mission_set_current, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_mission_write_partial_list.h b/vendor/libraries/mavlink/common/mavlink_msg_mission_write_partial_list.h index 17a5a6bdd8..756941b408 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_mission_write_partial_list.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_mission_write_partial_list.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE MISSION_WRITE_PARTIAL_LIST PACKING #define MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST 38 -typedef struct __mavlink_mission_write_partial_list_t -{ - int16_t start_index; ///< Start index, 0 by default and smaller / equal to the largest index of the current onboard list. - int16_t end_index; ///< End index, equal or greater than start index. - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_mission_write_partial_list_t; +MAVPACKED( +typedef struct __mavlink_mission_write_partial_list_t { + int16_t start_index; /*< Start index, 0 by default and smaller / equal to the largest index of the current onboard list.*/ + int16_t end_index; /*< End index, equal or greater than start index.*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_mission_write_partial_list_t; #define MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN 6 +#define MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN 6 #define MAVLINK_MSG_ID_38_LEN 6 +#define MAVLINK_MSG_ID_38_MIN_LEN 6 #define MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC 9 #define MAVLINK_MSG_ID_38_CRC 9 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST { \ - "MISSION_WRITE_PARTIAL_LIST", \ - 4, \ - { { "start_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_mission_write_partial_list_t, start_index) }, \ + 38, \ + "MISSION_WRITE_PARTIAL_LIST", \ + 4, \ + { { "start_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_mission_write_partial_list_t, start_index) }, \ { "end_index", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_mission_write_partial_list_t, end_index) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_mission_write_partial_list_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_mission_write_partial_list_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_MISSION_WRITE_PARTIAL_LIST { \ + "MISSION_WRITE_PARTIAL_LIST", \ + 4, \ + { { "start_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_mission_write_partial_list_t, start_index) }, \ + { "end_index", NULL, MAVLINK_TYPE_INT16_T, 0, 2, offsetof(mavlink_mission_write_partial_list_t, end_index) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_mission_write_partial_list_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_mission_write_partial_list_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a mission_write_partial_list message @@ -42,32 +57,28 @@ typedef struct __mavlink_mission_write_partial_list_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_write_partial_list_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) + uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN]; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); + char buf[MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN]; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); #else - mavlink_mission_write_partial_list_t packet; - packet.start_index = start_index; - packet.end_index = end_index; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_write_partial_list_t packet; + packet.start_index = start_index; + packet.end_index = end_index; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_mission_write_partial_list_pack(uint8_t syste * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_mission_write_partial_list_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,int16_t start_index,int16_t end_index) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,int16_t start_index,int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN]; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); + char buf[MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN]; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); #else - mavlink_mission_write_partial_list_t packet; - packet.start_index = start_index; - packet.end_index = end_index; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_mission_write_partial_list_t packet; + packet.start_index = start_index; + packet.end_index = end_index; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_mission_write_partial_list_pack_chan(uint8_t */ static inline uint16_t mavlink_msg_mission_write_partial_list_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_mission_write_partial_list_t* mission_write_partial_list) { - return mavlink_msg_mission_write_partial_list_pack(system_id, component_id, msg, mission_write_partial_list->target_system, mission_write_partial_list->target_component, mission_write_partial_list->start_index, mission_write_partial_list->end_index); + return mavlink_msg_mission_write_partial_list_pack(system_id, component_id, msg, mission_write_partial_list->target_system, mission_write_partial_list->target_component, mission_write_partial_list->start_index, mission_write_partial_list->end_index); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_mission_write_partial_list_encode(uint8_t sys */ static inline uint16_t mavlink_msg_mission_write_partial_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_mission_write_partial_list_t* mission_write_partial_list) { - return mavlink_msg_mission_write_partial_list_pack_chan(system_id, component_id, chan, msg, mission_write_partial_list->target_system, mission_write_partial_list->target_component, mission_write_partial_list->start_index, mission_write_partial_list->end_index); + return mavlink_msg_mission_write_partial_list_pack_chan(system_id, component_id, chan, msg, mission_write_partial_list->target_system, mission_write_partial_list->target_component, mission_write_partial_list->start_index, mission_write_partial_list->end_index); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_mission_write_partial_list_encode_chan(uint8_ static inline void mavlink_msg_mission_write_partial_list_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN]; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); + char buf[MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN]; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); + mavlink_mission_write_partial_list_t packet; + packet.start_index = start_index; + packet.end_index = end_index; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); #endif +} + +/** + * @brief Send a mission_write_partial_list message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_mission_write_partial_list_send_struct(mavlink_channel_t chan, const mavlink_mission_write_partial_list_t* mission_write_partial_list) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_mission_write_partial_list_send(chan, mission_write_partial_list->target_system, mission_write_partial_list->target_component, mission_write_partial_list->start_index, mission_write_partial_list->end_index); #else - mavlink_mission_write_partial_list_t packet; - packet.start_index = start_index; - packet.end_index = end_index; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, (const char *)&packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, (const char *)mission_write_partial_list, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_mission_write_partial_list_send(mavlink_channel_t static inline void mavlink_msg_mission_write_partial_list_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, int16_t start_index, int16_t end_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int16_t(buf, 0, start_index); - _mav_put_int16_t(buf, 2, end_index); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); -#endif -#else - mavlink_mission_write_partial_list_t *packet = (mavlink_mission_write_partial_list_t *)msgbuf; - packet->start_index = start_index; - packet->end_index = end_index; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); + char *buf = (char *)msgbuf; + _mav_put_int16_t(buf, 0, start_index); + _mav_put_int16_t(buf, 2, end_index); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, buf, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); -#endif + mavlink_mission_write_partial_list_t *packet = (mavlink_mission_write_partial_list_t *)msgbuf; + packet->start_index = start_index; + packet->end_index = end_index; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST, (const char *)packet, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_mission_write_partial_list_send_buf(mavlink_messa */ static inline uint8_t mavlink_msg_mission_write_partial_list_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -239,7 +244,7 @@ static inline uint8_t mavlink_msg_mission_write_partial_list_get_target_system(c */ static inline uint8_t mavlink_msg_mission_write_partial_list_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -249,7 +254,7 @@ static inline uint8_t mavlink_msg_mission_write_partial_list_get_target_componen */ static inline int16_t mavlink_msg_mission_write_partial_list_get_start_index(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 0); + return _MAV_RETURN_int16_t(msg, 0); } /** @@ -259,7 +264,7 @@ static inline int16_t mavlink_msg_mission_write_partial_list_get_start_index(con */ static inline int16_t mavlink_msg_mission_write_partial_list_get_end_index(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 2); + return _MAV_RETURN_int16_t(msg, 2); } /** @@ -270,12 +275,14 @@ static inline int16_t mavlink_msg_mission_write_partial_list_get_end_index(const */ static inline void mavlink_msg_mission_write_partial_list_decode(const mavlink_message_t* msg, mavlink_mission_write_partial_list_t* mission_write_partial_list) { -#if MAVLINK_NEED_BYTE_SWAP - mission_write_partial_list->start_index = mavlink_msg_mission_write_partial_list_get_start_index(msg); - mission_write_partial_list->end_index = mavlink_msg_mission_write_partial_list_get_end_index(msg); - mission_write_partial_list->target_system = mavlink_msg_mission_write_partial_list_get_target_system(msg); - mission_write_partial_list->target_component = mavlink_msg_mission_write_partial_list_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mission_write_partial_list->start_index = mavlink_msg_mission_write_partial_list_get_start_index(msg); + mission_write_partial_list->end_index = mavlink_msg_mission_write_partial_list_get_end_index(msg); + mission_write_partial_list->target_system = mavlink_msg_mission_write_partial_list_get_target_system(msg); + mission_write_partial_list->target_component = mavlink_msg_mission_write_partial_list_get_target_component(msg); #else - memcpy(mission_write_partial_list, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN? msg->len : MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN; + memset(mission_write_partial_list, 0, MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_LEN); + memcpy(mission_write_partial_list, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_named_value_float.h b/vendor/libraries/mavlink/common/mavlink_msg_named_value_float.h index df82704a4b..99cf094940 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_named_value_float.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_named_value_float.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE NAMED_VALUE_FLOAT PACKING #define MAVLINK_MSG_ID_NAMED_VALUE_FLOAT 251 -typedef struct __mavlink_named_value_float_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float value; ///< Floating point value - char name[10]; ///< Name of the debug variable -} mavlink_named_value_float_t; +MAVPACKED( +typedef struct __mavlink_named_value_float_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float value; /*< Floating point value*/ + char name[10]; /*< Name of the debug variable*/ +}) mavlink_named_value_float_t; #define MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN 18 +#define MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN 18 #define MAVLINK_MSG_ID_251_LEN 18 +#define MAVLINK_MSG_ID_251_MIN_LEN 18 #define MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC 170 #define MAVLINK_MSG_ID_251_CRC 170 #define MAVLINK_MSG_NAMED_VALUE_FLOAT_FIELD_NAME_LEN 10 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT { \ - "NAMED_VALUE_FLOAT", \ - 3, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_named_value_float_t, time_boot_ms) }, \ + 251, \ + "NAMED_VALUE_FLOAT", \ + 3, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_named_value_float_t, time_boot_ms) }, \ { "value", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_named_value_float_t, value) }, \ { "name", NULL, MAVLINK_TYPE_CHAR, 10, 8, offsetof(mavlink_named_value_float_t, name) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_NAMED_VALUE_FLOAT { \ + "NAMED_VALUE_FLOAT", \ + 3, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_named_value_float_t, time_boot_ms) }, \ + { "value", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_named_value_float_t, value) }, \ + { "name", NULL, MAVLINK_TYPE_CHAR, 10, 8, offsetof(mavlink_named_value_float_t, name) }, \ + } \ +} +#endif /** * @brief Pack a named_value_float message @@ -39,28 +53,24 @@ typedef struct __mavlink_named_value_float_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_named_value_float_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, const char *name, float value) + uint32_t time_boot_ms, const char *name, float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); + char buf[MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); #else - mavlink_named_value_float_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - mav_array_memcpy(packet.name, name, sizeof(char)*10); + mavlink_named_value_float_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + mav_array_memcpy(packet.name, name, sizeof(char)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_FLOAT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_FLOAT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); } /** @@ -75,29 +85,25 @@ static inline uint16_t mavlink_msg_named_value_float_pack(uint8_t system_id, uin * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_named_value_float_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,const char *name,float value) + mavlink_message_t* msg, + uint32_t time_boot_ms,const char *name,float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); + char buf[MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); #else - mavlink_named_value_float_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - mav_array_memcpy(packet.name, name, sizeof(char)*10); + mavlink_named_value_float_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + mav_array_memcpy(packet.name, name, sizeof(char)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_FLOAT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_FLOAT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); } /** @@ -110,7 +116,7 @@ static inline uint16_t mavlink_msg_named_value_float_pack_chan(uint8_t system_id */ static inline uint16_t mavlink_msg_named_value_float_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_named_value_float_t* named_value_float) { - return mavlink_msg_named_value_float_pack(system_id, component_id, msg, named_value_float->time_boot_ms, named_value_float->name, named_value_float->value); + return mavlink_msg_named_value_float_pack(system_id, component_id, msg, named_value_float->time_boot_ms, named_value_float->name, named_value_float->value); } /** @@ -124,7 +130,7 @@ static inline uint16_t mavlink_msg_named_value_float_encode(uint8_t system_id, u */ static inline uint16_t mavlink_msg_named_value_float_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_named_value_float_t* named_value_float) { - return mavlink_msg_named_value_float_pack_chan(system_id, component_id, chan, msg, named_value_float->time_boot_ms, named_value_float->name, named_value_float->value); + return mavlink_msg_named_value_float_pack_chan(system_id, component_id, chan, msg, named_value_float->time_boot_ms, named_value_float->name, named_value_float->value); } /** @@ -140,25 +146,31 @@ static inline uint16_t mavlink_msg_named_value_float_encode_chan(uint8_t system_ static inline void mavlink_msg_named_value_float_send(mavlink_channel_t chan, uint32_t time_boot_ms, const char *name, float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); + char buf[MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); + mavlink_named_value_float_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + mav_array_memcpy(packet.name, name, sizeof(char)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, (const char *)&packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); #endif +} + +/** + * @brief Send a named_value_float message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_named_value_float_send_struct(mavlink_channel_t chan, const mavlink_named_value_float_t* named_value_float) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_named_value_float_send(chan, named_value_float->time_boot_ms, named_value_float->name, named_value_float->value); #else - mavlink_named_value_float_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - mav_array_memcpy(packet.name, name, sizeof(char)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, (const char *)&packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, (const char *)&packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, (const char *)named_value_float, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); #endif } @@ -173,25 +185,17 @@ static inline void mavlink_msg_named_value_float_send(mavlink_channel_t chan, ui static inline void mavlink_msg_named_value_float_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, const char *name, float value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, buf, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); -#endif -#else - mavlink_named_value_float_t *packet = (mavlink_named_value_float_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->value = value; - mav_array_memcpy(packet->name, name, sizeof(char)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, (const char *)packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, (const char *)packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); -#endif + mavlink_named_value_float_t *packet = (mavlink_named_value_float_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->value = value; + mav_array_memcpy(packet->name, name, sizeof(char)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT, (const char *)packet, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_CRC); #endif } #endif @@ -208,7 +212,7 @@ static inline void mavlink_msg_named_value_float_send_buf(mavlink_message_t *msg */ static inline uint32_t mavlink_msg_named_value_float_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -218,7 +222,7 @@ static inline uint32_t mavlink_msg_named_value_float_get_time_boot_ms(const mavl */ static inline uint16_t mavlink_msg_named_value_float_get_name(const mavlink_message_t* msg, char *name) { - return _MAV_RETURN_char_array(msg, name, 10, 8); + return _MAV_RETURN_char_array(msg, name, 10, 8); } /** @@ -228,7 +232,7 @@ static inline uint16_t mavlink_msg_named_value_float_get_name(const mavlink_mess */ static inline float mavlink_msg_named_value_float_get_value(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -239,11 +243,13 @@ static inline float mavlink_msg_named_value_float_get_value(const mavlink_messag */ static inline void mavlink_msg_named_value_float_decode(const mavlink_message_t* msg, mavlink_named_value_float_t* named_value_float) { -#if MAVLINK_NEED_BYTE_SWAP - named_value_float->time_boot_ms = mavlink_msg_named_value_float_get_time_boot_ms(msg); - named_value_float->value = mavlink_msg_named_value_float_get_value(msg); - mavlink_msg_named_value_float_get_name(msg, named_value_float->name); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + named_value_float->time_boot_ms = mavlink_msg_named_value_float_get_time_boot_ms(msg); + named_value_float->value = mavlink_msg_named_value_float_get_value(msg); + mavlink_msg_named_value_float_get_name(msg, named_value_float->name); #else - memcpy(named_value_float, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN? msg->len : MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN; + memset(named_value_float, 0, MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_LEN); + memcpy(named_value_float, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_named_value_int.h b/vendor/libraries/mavlink/common/mavlink_msg_named_value_int.h index cfdd73d61e..b0b3b96603 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_named_value_int.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_named_value_int.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE NAMED_VALUE_INT PACKING #define MAVLINK_MSG_ID_NAMED_VALUE_INT 252 -typedef struct __mavlink_named_value_int_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - int32_t value; ///< Signed integer value - char name[10]; ///< Name of the debug variable -} mavlink_named_value_int_t; +MAVPACKED( +typedef struct __mavlink_named_value_int_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + int32_t value; /*< Signed integer value*/ + char name[10]; /*< Name of the debug variable*/ +}) mavlink_named_value_int_t; #define MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN 18 +#define MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN 18 #define MAVLINK_MSG_ID_252_LEN 18 +#define MAVLINK_MSG_ID_252_MIN_LEN 18 #define MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC 44 #define MAVLINK_MSG_ID_252_CRC 44 #define MAVLINK_MSG_NAMED_VALUE_INT_FIELD_NAME_LEN 10 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT { \ - "NAMED_VALUE_INT", \ - 3, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_named_value_int_t, time_boot_ms) }, \ + 252, \ + "NAMED_VALUE_INT", \ + 3, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_named_value_int_t, time_boot_ms) }, \ { "value", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_named_value_int_t, value) }, \ { "name", NULL, MAVLINK_TYPE_CHAR, 10, 8, offsetof(mavlink_named_value_int_t, name) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_NAMED_VALUE_INT { \ + "NAMED_VALUE_INT", \ + 3, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_named_value_int_t, time_boot_ms) }, \ + { "value", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_named_value_int_t, value) }, \ + { "name", NULL, MAVLINK_TYPE_CHAR, 10, 8, offsetof(mavlink_named_value_int_t, name) }, \ + } \ +} +#endif /** * @brief Pack a named_value_int message @@ -39,28 +53,24 @@ typedef struct __mavlink_named_value_int_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_named_value_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, const char *name, int32_t value) + uint32_t time_boot_ms, const char *name, int32_t value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); + char buf[MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); #else - mavlink_named_value_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - mav_array_memcpy(packet.name, name, sizeof(char)*10); + mavlink_named_value_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + mav_array_memcpy(packet.name, name, sizeof(char)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); } /** @@ -75,29 +85,25 @@ static inline uint16_t mavlink_msg_named_value_int_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_named_value_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,const char *name,int32_t value) + mavlink_message_t* msg, + uint32_t time_boot_ms,const char *name,int32_t value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); + char buf[MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); #else - mavlink_named_value_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - mav_array_memcpy(packet.name, name, sizeof(char)*10); + mavlink_named_value_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + mav_array_memcpy(packet.name, name, sizeof(char)*10); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_NAMED_VALUE_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); } /** @@ -110,7 +116,7 @@ static inline uint16_t mavlink_msg_named_value_int_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_named_value_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_named_value_int_t* named_value_int) { - return mavlink_msg_named_value_int_pack(system_id, component_id, msg, named_value_int->time_boot_ms, named_value_int->name, named_value_int->value); + return mavlink_msg_named_value_int_pack(system_id, component_id, msg, named_value_int->time_boot_ms, named_value_int->name, named_value_int->value); } /** @@ -124,7 +130,7 @@ static inline uint16_t mavlink_msg_named_value_int_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_named_value_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_named_value_int_t* named_value_int) { - return mavlink_msg_named_value_int_pack_chan(system_id, component_id, chan, msg, named_value_int->time_boot_ms, named_value_int->name, named_value_int->value); + return mavlink_msg_named_value_int_pack_chan(system_id, component_id, chan, msg, named_value_int->time_boot_ms, named_value_int->name, named_value_int->value); } /** @@ -140,25 +146,31 @@ static inline uint16_t mavlink_msg_named_value_int_encode_chan(uint8_t system_id static inline void mavlink_msg_named_value_int_send(mavlink_channel_t chan, uint32_t time_boot_ms, const char *name, int32_t value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); + char buf[MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); + mavlink_named_value_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.value = value; + mav_array_memcpy(packet.name, name, sizeof(char)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, (const char *)&packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); #endif +} + +/** + * @brief Send a named_value_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_named_value_int_send_struct(mavlink_channel_t chan, const mavlink_named_value_int_t* named_value_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_named_value_int_send(chan, named_value_int->time_boot_ms, named_value_int->name, named_value_int->value); #else - mavlink_named_value_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.value = value; - mav_array_memcpy(packet.name, name, sizeof(char)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, (const char *)&packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, (const char *)&packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, (const char *)named_value_int, MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); #endif } @@ -173,25 +185,17 @@ static inline void mavlink_msg_named_value_int_send(mavlink_channel_t chan, uint static inline void mavlink_msg_named_value_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, const char *name, int32_t value) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, value); - _mav_put_char_array(buf, 8, name, 10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, value); + _mav_put_char_array(buf, 8, name, 10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, buf, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); -#endif -#else - mavlink_named_value_int_t *packet = (mavlink_named_value_int_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->value = value; - mav_array_memcpy(packet->name, name, sizeof(char)*10); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, (const char *)packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, (const char *)packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); -#endif + mavlink_named_value_int_t *packet = (mavlink_named_value_int_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->value = value; + mav_array_memcpy(packet->name, name, sizeof(char)*10); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAMED_VALUE_INT, (const char *)packet, MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN, MAVLINK_MSG_ID_NAMED_VALUE_INT_CRC); #endif } #endif @@ -208,7 +212,7 @@ static inline void mavlink_msg_named_value_int_send_buf(mavlink_message_t *msgbu */ static inline uint32_t mavlink_msg_named_value_int_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -218,7 +222,7 @@ static inline uint32_t mavlink_msg_named_value_int_get_time_boot_ms(const mavlin */ static inline uint16_t mavlink_msg_named_value_int_get_name(const mavlink_message_t* msg, char *name) { - return _MAV_RETURN_char_array(msg, name, 10, 8); + return _MAV_RETURN_char_array(msg, name, 10, 8); } /** @@ -228,7 +232,7 @@ static inline uint16_t mavlink_msg_named_value_int_get_name(const mavlink_messag */ static inline int32_t mavlink_msg_named_value_int_get_value(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -239,11 +243,13 @@ static inline int32_t mavlink_msg_named_value_int_get_value(const mavlink_messag */ static inline void mavlink_msg_named_value_int_decode(const mavlink_message_t* msg, mavlink_named_value_int_t* named_value_int) { -#if MAVLINK_NEED_BYTE_SWAP - named_value_int->time_boot_ms = mavlink_msg_named_value_int_get_time_boot_ms(msg); - named_value_int->value = mavlink_msg_named_value_int_get_value(msg); - mavlink_msg_named_value_int_get_name(msg, named_value_int->name); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + named_value_int->time_boot_ms = mavlink_msg_named_value_int_get_time_boot_ms(msg); + named_value_int->value = mavlink_msg_named_value_int_get_value(msg); + mavlink_msg_named_value_int_get_name(msg, named_value_int->name); #else - memcpy(named_value_int, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN? msg->len : MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN; + memset(named_value_int, 0, MAVLINK_MSG_ID_NAMED_VALUE_INT_LEN); + memcpy(named_value_int, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_nav_controller_output.h b/vendor/libraries/mavlink/common/mavlink_msg_nav_controller_output.h index b9a748b222..5f2d40f60d 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_nav_controller_output.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_nav_controller_output.h @@ -1,31 +1,36 @@ +#pragma once // MESSAGE NAV_CONTROLLER_OUTPUT PACKING #define MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT 62 -typedef struct __mavlink_nav_controller_output_t -{ - float nav_roll; ///< Current desired roll in degrees - float nav_pitch; ///< Current desired pitch in degrees - float alt_error; ///< Current altitude error in meters - float aspd_error; ///< Current airspeed error in meters/second - float xtrack_error; ///< Current crosstrack error on x-y plane in meters - int16_t nav_bearing; ///< Current desired heading in degrees - int16_t target_bearing; ///< Bearing to current MISSION/target in degrees - uint16_t wp_dist; ///< Distance to active MISSION in meters -} mavlink_nav_controller_output_t; +MAVPACKED( +typedef struct __mavlink_nav_controller_output_t { + float nav_roll; /*< Current desired roll in degrees*/ + float nav_pitch; /*< Current desired pitch in degrees*/ + float alt_error; /*< Current altitude error in meters*/ + float aspd_error; /*< Current airspeed error in meters/second*/ + float xtrack_error; /*< Current crosstrack error on x-y plane in meters*/ + int16_t nav_bearing; /*< Current desired heading in degrees*/ + int16_t target_bearing; /*< Bearing to current MISSION/target in degrees*/ + uint16_t wp_dist; /*< Distance to active MISSION in meters*/ +}) mavlink_nav_controller_output_t; #define MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN 26 +#define MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN 26 #define MAVLINK_MSG_ID_62_LEN 26 +#define MAVLINK_MSG_ID_62_MIN_LEN 26 #define MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC 183 #define MAVLINK_MSG_ID_62_CRC 183 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT { \ - "NAV_CONTROLLER_OUTPUT", \ - 8, \ - { { "nav_roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_nav_controller_output_t, nav_roll) }, \ + 62, \ + "NAV_CONTROLLER_OUTPUT", \ + 8, \ + { { "nav_roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_nav_controller_output_t, nav_roll) }, \ { "nav_pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_nav_controller_output_t, nav_pitch) }, \ { "alt_error", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_nav_controller_output_t, alt_error) }, \ { "aspd_error", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_nav_controller_output_t, aspd_error) }, \ @@ -35,7 +40,21 @@ typedef struct __mavlink_nav_controller_output_t { "wp_dist", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_nav_controller_output_t, wp_dist) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_NAV_CONTROLLER_OUTPUT { \ + "NAV_CONTROLLER_OUTPUT", \ + 8, \ + { { "nav_roll", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_nav_controller_output_t, nav_roll) }, \ + { "nav_pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_nav_controller_output_t, nav_pitch) }, \ + { "alt_error", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_nav_controller_output_t, alt_error) }, \ + { "aspd_error", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_nav_controller_output_t, aspd_error) }, \ + { "xtrack_error", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_nav_controller_output_t, xtrack_error) }, \ + { "nav_bearing", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_nav_controller_output_t, nav_bearing) }, \ + { "target_bearing", NULL, MAVLINK_TYPE_INT16_T, 0, 22, offsetof(mavlink_nav_controller_output_t, target_bearing) }, \ + { "wp_dist", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_nav_controller_output_t, wp_dist) }, \ + } \ +} +#endif /** * @brief Pack a nav_controller_output message @@ -54,40 +73,36 @@ typedef struct __mavlink_nav_controller_output_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_nav_controller_output_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float nav_roll, float nav_pitch, int16_t nav_bearing, int16_t target_bearing, uint16_t wp_dist, float alt_error, float aspd_error, float xtrack_error) + float nav_roll, float nav_pitch, int16_t nav_bearing, int16_t target_bearing, uint16_t wp_dist, float alt_error, float aspd_error, float xtrack_error) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN]; - _mav_put_float(buf, 0, nav_roll); - _mav_put_float(buf, 4, nav_pitch); - _mav_put_float(buf, 8, alt_error); - _mav_put_float(buf, 12, aspd_error); - _mav_put_float(buf, 16, xtrack_error); - _mav_put_int16_t(buf, 20, nav_bearing); - _mav_put_int16_t(buf, 22, target_bearing); - _mav_put_uint16_t(buf, 24, wp_dist); + char buf[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN]; + _mav_put_float(buf, 0, nav_roll); + _mav_put_float(buf, 4, nav_pitch); + _mav_put_float(buf, 8, alt_error); + _mav_put_float(buf, 12, aspd_error); + _mav_put_float(buf, 16, xtrack_error); + _mav_put_int16_t(buf, 20, nav_bearing); + _mav_put_int16_t(buf, 22, target_bearing); + _mav_put_uint16_t(buf, 24, wp_dist); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); #else - mavlink_nav_controller_output_t packet; - packet.nav_roll = nav_roll; - packet.nav_pitch = nav_pitch; - packet.alt_error = alt_error; - packet.aspd_error = aspd_error; - packet.xtrack_error = xtrack_error; - packet.nav_bearing = nav_bearing; - packet.target_bearing = target_bearing; - packet.wp_dist = wp_dist; + mavlink_nav_controller_output_t packet; + packet.nav_roll = nav_roll; + packet.nav_pitch = nav_pitch; + packet.alt_error = alt_error; + packet.aspd_error = aspd_error; + packet.xtrack_error = xtrack_error; + packet.nav_bearing = nav_bearing; + packet.target_bearing = target_bearing; + packet.wp_dist = wp_dist; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); } /** @@ -107,41 +122,37 @@ static inline uint16_t mavlink_msg_nav_controller_output_pack(uint8_t system_id, * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_nav_controller_output_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float nav_roll,float nav_pitch,int16_t nav_bearing,int16_t target_bearing,uint16_t wp_dist,float alt_error,float aspd_error,float xtrack_error) + mavlink_message_t* msg, + float nav_roll,float nav_pitch,int16_t nav_bearing,int16_t target_bearing,uint16_t wp_dist,float alt_error,float aspd_error,float xtrack_error) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN]; - _mav_put_float(buf, 0, nav_roll); - _mav_put_float(buf, 4, nav_pitch); - _mav_put_float(buf, 8, alt_error); - _mav_put_float(buf, 12, aspd_error); - _mav_put_float(buf, 16, xtrack_error); - _mav_put_int16_t(buf, 20, nav_bearing); - _mav_put_int16_t(buf, 22, target_bearing); - _mav_put_uint16_t(buf, 24, wp_dist); + char buf[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN]; + _mav_put_float(buf, 0, nav_roll); + _mav_put_float(buf, 4, nav_pitch); + _mav_put_float(buf, 8, alt_error); + _mav_put_float(buf, 12, aspd_error); + _mav_put_float(buf, 16, xtrack_error); + _mav_put_int16_t(buf, 20, nav_bearing); + _mav_put_int16_t(buf, 22, target_bearing); + _mav_put_uint16_t(buf, 24, wp_dist); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); #else - mavlink_nav_controller_output_t packet; - packet.nav_roll = nav_roll; - packet.nav_pitch = nav_pitch; - packet.alt_error = alt_error; - packet.aspd_error = aspd_error; - packet.xtrack_error = xtrack_error; - packet.nav_bearing = nav_bearing; - packet.target_bearing = target_bearing; - packet.wp_dist = wp_dist; + mavlink_nav_controller_output_t packet; + packet.nav_roll = nav_roll; + packet.nav_pitch = nav_pitch; + packet.alt_error = alt_error; + packet.aspd_error = aspd_error; + packet.xtrack_error = xtrack_error; + packet.nav_bearing = nav_bearing; + packet.target_bearing = target_bearing; + packet.wp_dist = wp_dist; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); } /** @@ -154,7 +165,7 @@ static inline uint16_t mavlink_msg_nav_controller_output_pack_chan(uint8_t syste */ static inline uint16_t mavlink_msg_nav_controller_output_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_nav_controller_output_t* nav_controller_output) { - return mavlink_msg_nav_controller_output_pack(system_id, component_id, msg, nav_controller_output->nav_roll, nav_controller_output->nav_pitch, nav_controller_output->nav_bearing, nav_controller_output->target_bearing, nav_controller_output->wp_dist, nav_controller_output->alt_error, nav_controller_output->aspd_error, nav_controller_output->xtrack_error); + return mavlink_msg_nav_controller_output_pack(system_id, component_id, msg, nav_controller_output->nav_roll, nav_controller_output->nav_pitch, nav_controller_output->nav_bearing, nav_controller_output->target_bearing, nav_controller_output->wp_dist, nav_controller_output->alt_error, nav_controller_output->aspd_error, nav_controller_output->xtrack_error); } /** @@ -168,7 +179,7 @@ static inline uint16_t mavlink_msg_nav_controller_output_encode(uint8_t system_i */ static inline uint16_t mavlink_msg_nav_controller_output_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_nav_controller_output_t* nav_controller_output) { - return mavlink_msg_nav_controller_output_pack_chan(system_id, component_id, chan, msg, nav_controller_output->nav_roll, nav_controller_output->nav_pitch, nav_controller_output->nav_bearing, nav_controller_output->target_bearing, nav_controller_output->wp_dist, nav_controller_output->alt_error, nav_controller_output->aspd_error, nav_controller_output->xtrack_error); + return mavlink_msg_nav_controller_output_pack_chan(system_id, component_id, chan, msg, nav_controller_output->nav_roll, nav_controller_output->nav_pitch, nav_controller_output->nav_bearing, nav_controller_output->target_bearing, nav_controller_output->wp_dist, nav_controller_output->alt_error, nav_controller_output->aspd_error, nav_controller_output->xtrack_error); } /** @@ -189,37 +200,43 @@ static inline uint16_t mavlink_msg_nav_controller_output_encode_chan(uint8_t sys static inline void mavlink_msg_nav_controller_output_send(mavlink_channel_t chan, float nav_roll, float nav_pitch, int16_t nav_bearing, int16_t target_bearing, uint16_t wp_dist, float alt_error, float aspd_error, float xtrack_error) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN]; - _mav_put_float(buf, 0, nav_roll); - _mav_put_float(buf, 4, nav_pitch); - _mav_put_float(buf, 8, alt_error); - _mav_put_float(buf, 12, aspd_error); - _mav_put_float(buf, 16, xtrack_error); - _mav_put_int16_t(buf, 20, nav_bearing); - _mav_put_int16_t(buf, 22, target_bearing); - _mav_put_uint16_t(buf, 24, wp_dist); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); + char buf[MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN]; + _mav_put_float(buf, 0, nav_roll); + _mav_put_float(buf, 4, nav_pitch); + _mav_put_float(buf, 8, alt_error); + _mav_put_float(buf, 12, aspd_error); + _mav_put_float(buf, 16, xtrack_error); + _mav_put_int16_t(buf, 20, nav_bearing); + _mav_put_int16_t(buf, 22, target_bearing); + _mav_put_uint16_t(buf, 24, wp_dist); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); + mavlink_nav_controller_output_t packet; + packet.nav_roll = nav_roll; + packet.nav_pitch = nav_pitch; + packet.alt_error = alt_error; + packet.aspd_error = aspd_error; + packet.xtrack_error = xtrack_error; + packet.nav_bearing = nav_bearing; + packet.target_bearing = target_bearing; + packet.wp_dist = wp_dist; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, (const char *)&packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); #endif +} + +/** + * @brief Send a nav_controller_output message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_nav_controller_output_send_struct(mavlink_channel_t chan, const mavlink_nav_controller_output_t* nav_controller_output) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_nav_controller_output_send(chan, nav_controller_output->nav_roll, nav_controller_output->nav_pitch, nav_controller_output->nav_bearing, nav_controller_output->target_bearing, nav_controller_output->wp_dist, nav_controller_output->alt_error, nav_controller_output->aspd_error, nav_controller_output->xtrack_error); #else - mavlink_nav_controller_output_t packet; - packet.nav_roll = nav_roll; - packet.nav_pitch = nav_pitch; - packet.alt_error = alt_error; - packet.aspd_error = aspd_error; - packet.xtrack_error = xtrack_error; - packet.nav_bearing = nav_bearing; - packet.target_bearing = target_bearing; - packet.wp_dist = wp_dist; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, (const char *)&packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, (const char *)&packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, (const char *)nav_controller_output, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); #endif } @@ -234,37 +251,29 @@ static inline void mavlink_msg_nav_controller_output_send(mavlink_channel_t chan static inline void mavlink_msg_nav_controller_output_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float nav_roll, float nav_pitch, int16_t nav_bearing, int16_t target_bearing, uint16_t wp_dist, float alt_error, float aspd_error, float xtrack_error) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, nav_roll); - _mav_put_float(buf, 4, nav_pitch); - _mav_put_float(buf, 8, alt_error); - _mav_put_float(buf, 12, aspd_error); - _mav_put_float(buf, 16, xtrack_error); - _mav_put_int16_t(buf, 20, nav_bearing); - _mav_put_int16_t(buf, 22, target_bearing); - _mav_put_uint16_t(buf, 24, wp_dist); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); -#endif -#else - mavlink_nav_controller_output_t *packet = (mavlink_nav_controller_output_t *)msgbuf; - packet->nav_roll = nav_roll; - packet->nav_pitch = nav_pitch; - packet->alt_error = alt_error; - packet->aspd_error = aspd_error; - packet->xtrack_error = xtrack_error; - packet->nav_bearing = nav_bearing; - packet->target_bearing = target_bearing; - packet->wp_dist = wp_dist; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, (const char *)packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, nav_roll); + _mav_put_float(buf, 4, nav_pitch); + _mav_put_float(buf, 8, alt_error); + _mav_put_float(buf, 12, aspd_error); + _mav_put_float(buf, 16, xtrack_error); + _mav_put_int16_t(buf, 20, nav_bearing); + _mav_put_int16_t(buf, 22, target_bearing); + _mav_put_uint16_t(buf, 24, wp_dist); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, buf, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, (const char *)packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); -#endif + mavlink_nav_controller_output_t *packet = (mavlink_nav_controller_output_t *)msgbuf; + packet->nav_roll = nav_roll; + packet->nav_pitch = nav_pitch; + packet->alt_error = alt_error; + packet->aspd_error = aspd_error; + packet->xtrack_error = xtrack_error; + packet->nav_bearing = nav_bearing; + packet->target_bearing = target_bearing; + packet->wp_dist = wp_dist; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT, (const char *)packet, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_CRC); #endif } #endif @@ -281,7 +290,7 @@ static inline void mavlink_msg_nav_controller_output_send_buf(mavlink_message_t */ static inline float mavlink_msg_nav_controller_output_get_nav_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -291,7 +300,7 @@ static inline float mavlink_msg_nav_controller_output_get_nav_roll(const mavlink */ static inline float mavlink_msg_nav_controller_output_get_nav_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -301,7 +310,7 @@ static inline float mavlink_msg_nav_controller_output_get_nav_pitch(const mavlin */ static inline int16_t mavlink_msg_nav_controller_output_get_nav_bearing(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 20); + return _MAV_RETURN_int16_t(msg, 20); } /** @@ -311,7 +320,7 @@ static inline int16_t mavlink_msg_nav_controller_output_get_nav_bearing(const ma */ static inline int16_t mavlink_msg_nav_controller_output_get_target_bearing(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 22); + return _MAV_RETURN_int16_t(msg, 22); } /** @@ -321,7 +330,7 @@ static inline int16_t mavlink_msg_nav_controller_output_get_target_bearing(const */ static inline uint16_t mavlink_msg_nav_controller_output_get_wp_dist(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -331,7 +340,7 @@ static inline uint16_t mavlink_msg_nav_controller_output_get_wp_dist(const mavli */ static inline float mavlink_msg_nav_controller_output_get_alt_error(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -341,7 +350,7 @@ static inline float mavlink_msg_nav_controller_output_get_alt_error(const mavlin */ static inline float mavlink_msg_nav_controller_output_get_aspd_error(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -351,7 +360,7 @@ static inline float mavlink_msg_nav_controller_output_get_aspd_error(const mavli */ static inline float mavlink_msg_nav_controller_output_get_xtrack_error(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -362,16 +371,18 @@ static inline float mavlink_msg_nav_controller_output_get_xtrack_error(const mav */ static inline void mavlink_msg_nav_controller_output_decode(const mavlink_message_t* msg, mavlink_nav_controller_output_t* nav_controller_output) { -#if MAVLINK_NEED_BYTE_SWAP - nav_controller_output->nav_roll = mavlink_msg_nav_controller_output_get_nav_roll(msg); - nav_controller_output->nav_pitch = mavlink_msg_nav_controller_output_get_nav_pitch(msg); - nav_controller_output->alt_error = mavlink_msg_nav_controller_output_get_alt_error(msg); - nav_controller_output->aspd_error = mavlink_msg_nav_controller_output_get_aspd_error(msg); - nav_controller_output->xtrack_error = mavlink_msg_nav_controller_output_get_xtrack_error(msg); - nav_controller_output->nav_bearing = mavlink_msg_nav_controller_output_get_nav_bearing(msg); - nav_controller_output->target_bearing = mavlink_msg_nav_controller_output_get_target_bearing(msg); - nav_controller_output->wp_dist = mavlink_msg_nav_controller_output_get_wp_dist(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + nav_controller_output->nav_roll = mavlink_msg_nav_controller_output_get_nav_roll(msg); + nav_controller_output->nav_pitch = mavlink_msg_nav_controller_output_get_nav_pitch(msg); + nav_controller_output->alt_error = mavlink_msg_nav_controller_output_get_alt_error(msg); + nav_controller_output->aspd_error = mavlink_msg_nav_controller_output_get_aspd_error(msg); + nav_controller_output->xtrack_error = mavlink_msg_nav_controller_output_get_xtrack_error(msg); + nav_controller_output->nav_bearing = mavlink_msg_nav_controller_output_get_nav_bearing(msg); + nav_controller_output->target_bearing = mavlink_msg_nav_controller_output_get_target_bearing(msg); + nav_controller_output->wp_dist = mavlink_msg_nav_controller_output_get_wp_dist(msg); #else - memcpy(nav_controller_output, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN? msg->len : MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN; + memset(nav_controller_output, 0, MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_LEN); + memcpy(nav_controller_output, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_optical_flow.h b/vendor/libraries/mavlink/common/mavlink_msg_optical_flow.h index 6a2efc664f..56b9a3c676 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_optical_flow.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_optical_flow.h @@ -1,31 +1,36 @@ +#pragma once // MESSAGE OPTICAL_FLOW PACKING #define MAVLINK_MSG_ID_OPTICAL_FLOW 100 -typedef struct __mavlink_optical_flow_t -{ - uint64_t time_usec; ///< Timestamp (UNIX) - float flow_comp_m_x; ///< Flow in meters in x-sensor direction, angular-speed compensated - float flow_comp_m_y; ///< Flow in meters in y-sensor direction, angular-speed compensated - float ground_distance; ///< Ground distance in meters. Positive value: distance known. Negative value: Unknown distance - int16_t flow_x; ///< Flow in pixels * 10 in x-sensor direction (dezi-pixels) - int16_t flow_y; ///< Flow in pixels * 10 in y-sensor direction (dezi-pixels) - uint8_t sensor_id; ///< Sensor ID - uint8_t quality; ///< Optical flow quality / confidence. 0: bad, 255: maximum quality -} mavlink_optical_flow_t; +MAVPACKED( +typedef struct __mavlink_optical_flow_t { + uint64_t time_usec; /*< Timestamp (UNIX)*/ + float flow_comp_m_x; /*< Flow in meters in x-sensor direction, angular-speed compensated*/ + float flow_comp_m_y; /*< Flow in meters in y-sensor direction, angular-speed compensated*/ + float ground_distance; /*< Ground distance in meters. Positive value: distance known. Negative value: Unknown distance*/ + int16_t flow_x; /*< Flow in pixels * 10 in x-sensor direction (dezi-pixels)*/ + int16_t flow_y; /*< Flow in pixels * 10 in y-sensor direction (dezi-pixels)*/ + uint8_t sensor_id; /*< Sensor ID*/ + uint8_t quality; /*< Optical flow quality / confidence. 0: bad, 255: maximum quality*/ +}) mavlink_optical_flow_t; #define MAVLINK_MSG_ID_OPTICAL_FLOW_LEN 26 +#define MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN 26 #define MAVLINK_MSG_ID_100_LEN 26 +#define MAVLINK_MSG_ID_100_MIN_LEN 26 #define MAVLINK_MSG_ID_OPTICAL_FLOW_CRC 175 #define MAVLINK_MSG_ID_100_CRC 175 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_OPTICAL_FLOW { \ - "OPTICAL_FLOW", \ - 8, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_optical_flow_t, time_usec) }, \ + 100, \ + "OPTICAL_FLOW", \ + 8, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_optical_flow_t, time_usec) }, \ { "flow_comp_m_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_optical_flow_t, flow_comp_m_x) }, \ { "flow_comp_m_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_optical_flow_t, flow_comp_m_y) }, \ { "ground_distance", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_optical_flow_t, ground_distance) }, \ @@ -35,7 +40,21 @@ typedef struct __mavlink_optical_flow_t { "quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 25, offsetof(mavlink_optical_flow_t, quality) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_OPTICAL_FLOW { \ + "OPTICAL_FLOW", \ + 8, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_optical_flow_t, time_usec) }, \ + { "flow_comp_m_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_optical_flow_t, flow_comp_m_x) }, \ + { "flow_comp_m_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_optical_flow_t, flow_comp_m_y) }, \ + { "ground_distance", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_optical_flow_t, ground_distance) }, \ + { "flow_x", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_optical_flow_t, flow_x) }, \ + { "flow_y", NULL, MAVLINK_TYPE_INT16_T, 0, 22, offsetof(mavlink_optical_flow_t, flow_y) }, \ + { "sensor_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_optical_flow_t, sensor_id) }, \ + { "quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 25, offsetof(mavlink_optical_flow_t, quality) }, \ + } \ +} +#endif /** * @brief Pack a optical_flow message @@ -54,40 +73,36 @@ typedef struct __mavlink_optical_flow_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_optical_flow_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t sensor_id, int16_t flow_x, int16_t flow_y, float flow_comp_m_x, float flow_comp_m_y, uint8_t quality, float ground_distance) + uint64_t time_usec, uint8_t sensor_id, int16_t flow_x, int16_t flow_y, float flow_comp_m_x, float flow_comp_m_y, uint8_t quality, float ground_distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, flow_comp_m_x); - _mav_put_float(buf, 12, flow_comp_m_y); - _mav_put_float(buf, 16, ground_distance); - _mav_put_int16_t(buf, 20, flow_x); - _mav_put_int16_t(buf, 22, flow_y); - _mav_put_uint8_t(buf, 24, sensor_id); - _mav_put_uint8_t(buf, 25, quality); + char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, flow_comp_m_x); + _mav_put_float(buf, 12, flow_comp_m_y); + _mav_put_float(buf, 16, ground_distance); + _mav_put_int16_t(buf, 20, flow_x); + _mav_put_int16_t(buf, 22, flow_y); + _mav_put_uint8_t(buf, 24, sensor_id); + _mav_put_uint8_t(buf, 25, quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); #else - mavlink_optical_flow_t packet; - packet.time_usec = time_usec; - packet.flow_comp_m_x = flow_comp_m_x; - packet.flow_comp_m_y = flow_comp_m_y; - packet.ground_distance = ground_distance; - packet.flow_x = flow_x; - packet.flow_y = flow_y; - packet.sensor_id = sensor_id; - packet.quality = quality; + mavlink_optical_flow_t packet; + packet.time_usec = time_usec; + packet.flow_comp_m_x = flow_comp_m_x; + packet.flow_comp_m_y = flow_comp_m_y; + packet.ground_distance = ground_distance; + packet.flow_x = flow_x; + packet.flow_y = flow_y; + packet.sensor_id = sensor_id; + packet.quality = quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); } /** @@ -107,41 +122,37 @@ static inline uint16_t mavlink_msg_optical_flow_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_optical_flow_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t sensor_id,int16_t flow_x,int16_t flow_y,float flow_comp_m_x,float flow_comp_m_y,uint8_t quality,float ground_distance) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t sensor_id,int16_t flow_x,int16_t flow_y,float flow_comp_m_x,float flow_comp_m_y,uint8_t quality,float ground_distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, flow_comp_m_x); - _mav_put_float(buf, 12, flow_comp_m_y); - _mav_put_float(buf, 16, ground_distance); - _mav_put_int16_t(buf, 20, flow_x); - _mav_put_int16_t(buf, 22, flow_y); - _mav_put_uint8_t(buf, 24, sensor_id); - _mav_put_uint8_t(buf, 25, quality); + char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, flow_comp_m_x); + _mav_put_float(buf, 12, flow_comp_m_y); + _mav_put_float(buf, 16, ground_distance); + _mav_put_int16_t(buf, 20, flow_x); + _mav_put_int16_t(buf, 22, flow_y); + _mav_put_uint8_t(buf, 24, sensor_id); + _mav_put_uint8_t(buf, 25, quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); #else - mavlink_optical_flow_t packet; - packet.time_usec = time_usec; - packet.flow_comp_m_x = flow_comp_m_x; - packet.flow_comp_m_y = flow_comp_m_y; - packet.ground_distance = ground_distance; - packet.flow_x = flow_x; - packet.flow_y = flow_y; - packet.sensor_id = sensor_id; - packet.quality = quality; + mavlink_optical_flow_t packet; + packet.time_usec = time_usec; + packet.flow_comp_m_x = flow_comp_m_x; + packet.flow_comp_m_y = flow_comp_m_y; + packet.ground_distance = ground_distance; + packet.flow_x = flow_x; + packet.flow_y = flow_y; + packet.sensor_id = sensor_id; + packet.quality = quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); } /** @@ -154,7 +165,7 @@ static inline uint16_t mavlink_msg_optical_flow_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_optical_flow_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_optical_flow_t* optical_flow) { - return mavlink_msg_optical_flow_pack(system_id, component_id, msg, optical_flow->time_usec, optical_flow->sensor_id, optical_flow->flow_x, optical_flow->flow_y, optical_flow->flow_comp_m_x, optical_flow->flow_comp_m_y, optical_flow->quality, optical_flow->ground_distance); + return mavlink_msg_optical_flow_pack(system_id, component_id, msg, optical_flow->time_usec, optical_flow->sensor_id, optical_flow->flow_x, optical_flow->flow_y, optical_flow->flow_comp_m_x, optical_flow->flow_comp_m_y, optical_flow->quality, optical_flow->ground_distance); } /** @@ -168,7 +179,7 @@ static inline uint16_t mavlink_msg_optical_flow_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_optical_flow_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_optical_flow_t* optical_flow) { - return mavlink_msg_optical_flow_pack_chan(system_id, component_id, chan, msg, optical_flow->time_usec, optical_flow->sensor_id, optical_flow->flow_x, optical_flow->flow_y, optical_flow->flow_comp_m_x, optical_flow->flow_comp_m_y, optical_flow->quality, optical_flow->ground_distance); + return mavlink_msg_optical_flow_pack_chan(system_id, component_id, chan, msg, optical_flow->time_usec, optical_flow->sensor_id, optical_flow->flow_x, optical_flow->flow_y, optical_flow->flow_comp_m_x, optical_flow->flow_comp_m_y, optical_flow->quality, optical_flow->ground_distance); } /** @@ -189,37 +200,43 @@ static inline uint16_t mavlink_msg_optical_flow_encode_chan(uint8_t system_id, u static inline void mavlink_msg_optical_flow_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t sensor_id, int16_t flow_x, int16_t flow_y, float flow_comp_m_x, float flow_comp_m_y, uint8_t quality, float ground_distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, flow_comp_m_x); - _mav_put_float(buf, 12, flow_comp_m_y); - _mav_put_float(buf, 16, ground_distance); - _mav_put_int16_t(buf, 20, flow_x); - _mav_put_int16_t(buf, 22, flow_y); - _mav_put_uint8_t(buf, 24, sensor_id); - _mav_put_uint8_t(buf, 25, quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); + char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, flow_comp_m_x); + _mav_put_float(buf, 12, flow_comp_m_y); + _mav_put_float(buf, 16, ground_distance); + _mav_put_int16_t(buf, 20, flow_x); + _mav_put_int16_t(buf, 22, flow_y); + _mav_put_uint8_t(buf, 24, sensor_id); + _mav_put_uint8_t(buf, 25, quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); + mavlink_optical_flow_t packet; + packet.time_usec = time_usec; + packet.flow_comp_m_x = flow_comp_m_x; + packet.flow_comp_m_y = flow_comp_m_y; + packet.ground_distance = ground_distance; + packet.flow_x = flow_x; + packet.flow_y = flow_y; + packet.sensor_id = sensor_id; + packet.quality = quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, (const char *)&packet, MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); #endif +} + +/** + * @brief Send a optical_flow message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_optical_flow_send_struct(mavlink_channel_t chan, const mavlink_optical_flow_t* optical_flow) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_optical_flow_send(chan, optical_flow->time_usec, optical_flow->sensor_id, optical_flow->flow_x, optical_flow->flow_y, optical_flow->flow_comp_m_x, optical_flow->flow_comp_m_y, optical_flow->quality, optical_flow->ground_distance); #else - mavlink_optical_flow_t packet; - packet.time_usec = time_usec; - packet.flow_comp_m_x = flow_comp_m_x; - packet.flow_comp_m_y = flow_comp_m_y; - packet.ground_distance = ground_distance; - packet.flow_x = flow_x; - packet.flow_y = flow_y; - packet.sensor_id = sensor_id; - packet.quality = quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, (const char *)&packet, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, (const char *)&packet, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, (const char *)optical_flow, MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); #endif } @@ -234,37 +251,29 @@ static inline void mavlink_msg_optical_flow_send(mavlink_channel_t chan, uint64_ static inline void mavlink_msg_optical_flow_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t sensor_id, int16_t flow_x, int16_t flow_y, float flow_comp_m_x, float flow_comp_m_y, uint8_t quality, float ground_distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_float(buf, 8, flow_comp_m_x); - _mav_put_float(buf, 12, flow_comp_m_y); - _mav_put_float(buf, 16, ground_distance); - _mav_put_int16_t(buf, 20, flow_x); - _mav_put_int16_t(buf, 22, flow_y); - _mav_put_uint8_t(buf, 24, sensor_id); - _mav_put_uint8_t(buf, 25, quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); -#endif -#else - mavlink_optical_flow_t *packet = (mavlink_optical_flow_t *)msgbuf; - packet->time_usec = time_usec; - packet->flow_comp_m_x = flow_comp_m_x; - packet->flow_comp_m_y = flow_comp_m_y; - packet->ground_distance = ground_distance; - packet->flow_x = flow_x; - packet->flow_y = flow_y; - packet->sensor_id = sensor_id; - packet->quality = quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, (const char *)packet, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, flow_comp_m_x); + _mav_put_float(buf, 12, flow_comp_m_y); + _mav_put_float(buf, 16, ground_distance); + _mav_put_int16_t(buf, 20, flow_x); + _mav_put_int16_t(buf, 22, flow_y); + _mav_put_uint8_t(buf, 24, sensor_id); + _mav_put_uint8_t(buf, 25, quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, (const char *)packet, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); -#endif + mavlink_optical_flow_t *packet = (mavlink_optical_flow_t *)msgbuf; + packet->time_usec = time_usec; + packet->flow_comp_m_x = flow_comp_m_x; + packet->flow_comp_m_y = flow_comp_m_y; + packet->ground_distance = ground_distance; + packet->flow_x = flow_x; + packet->flow_y = flow_y; + packet->sensor_id = sensor_id; + packet->quality = quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW, (const char *)packet, MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_CRC); #endif } #endif @@ -281,7 +290,7 @@ static inline void mavlink_msg_optical_flow_send_buf(mavlink_message_t *msgbuf, */ static inline uint64_t mavlink_msg_optical_flow_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -291,7 +300,7 @@ static inline uint64_t mavlink_msg_optical_flow_get_time_usec(const mavlink_mess */ static inline uint8_t mavlink_msg_optical_flow_get_sensor_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 24); + return _MAV_RETURN_uint8_t(msg, 24); } /** @@ -301,7 +310,7 @@ static inline uint8_t mavlink_msg_optical_flow_get_sensor_id(const mavlink_messa */ static inline int16_t mavlink_msg_optical_flow_get_flow_x(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 20); + return _MAV_RETURN_int16_t(msg, 20); } /** @@ -311,7 +320,7 @@ static inline int16_t mavlink_msg_optical_flow_get_flow_x(const mavlink_message_ */ static inline int16_t mavlink_msg_optical_flow_get_flow_y(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 22); + return _MAV_RETURN_int16_t(msg, 22); } /** @@ -321,7 +330,7 @@ static inline int16_t mavlink_msg_optical_flow_get_flow_y(const mavlink_message_ */ static inline float mavlink_msg_optical_flow_get_flow_comp_m_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -331,7 +340,7 @@ static inline float mavlink_msg_optical_flow_get_flow_comp_m_x(const mavlink_mes */ static inline float mavlink_msg_optical_flow_get_flow_comp_m_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -341,7 +350,7 @@ static inline float mavlink_msg_optical_flow_get_flow_comp_m_y(const mavlink_mes */ static inline uint8_t mavlink_msg_optical_flow_get_quality(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 25); + return _MAV_RETURN_uint8_t(msg, 25); } /** @@ -351,7 +360,7 @@ static inline uint8_t mavlink_msg_optical_flow_get_quality(const mavlink_message */ static inline float mavlink_msg_optical_flow_get_ground_distance(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -362,16 +371,18 @@ static inline float mavlink_msg_optical_flow_get_ground_distance(const mavlink_m */ static inline void mavlink_msg_optical_flow_decode(const mavlink_message_t* msg, mavlink_optical_flow_t* optical_flow) { -#if MAVLINK_NEED_BYTE_SWAP - optical_flow->time_usec = mavlink_msg_optical_flow_get_time_usec(msg); - optical_flow->flow_comp_m_x = mavlink_msg_optical_flow_get_flow_comp_m_x(msg); - optical_flow->flow_comp_m_y = mavlink_msg_optical_flow_get_flow_comp_m_y(msg); - optical_flow->ground_distance = mavlink_msg_optical_flow_get_ground_distance(msg); - optical_flow->flow_x = mavlink_msg_optical_flow_get_flow_x(msg); - optical_flow->flow_y = mavlink_msg_optical_flow_get_flow_y(msg); - optical_flow->sensor_id = mavlink_msg_optical_flow_get_sensor_id(msg); - optical_flow->quality = mavlink_msg_optical_flow_get_quality(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + optical_flow->time_usec = mavlink_msg_optical_flow_get_time_usec(msg); + optical_flow->flow_comp_m_x = mavlink_msg_optical_flow_get_flow_comp_m_x(msg); + optical_flow->flow_comp_m_y = mavlink_msg_optical_flow_get_flow_comp_m_y(msg); + optical_flow->ground_distance = mavlink_msg_optical_flow_get_ground_distance(msg); + optical_flow->flow_x = mavlink_msg_optical_flow_get_flow_x(msg); + optical_flow->flow_y = mavlink_msg_optical_flow_get_flow_y(msg); + optical_flow->sensor_id = mavlink_msg_optical_flow_get_sensor_id(msg); + optical_flow->quality = mavlink_msg_optical_flow_get_quality(msg); #else - memcpy(optical_flow, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_OPTICAL_FLOW_LEN? msg->len : MAVLINK_MSG_ID_OPTICAL_FLOW_LEN; + memset(optical_flow, 0, MAVLINK_MSG_ID_OPTICAL_FLOW_LEN); + memcpy(optical_flow, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_optical_flow_rad.h b/vendor/libraries/mavlink/common/mavlink_msg_optical_flow_rad.h index 427b56ac21..c4326eb046 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_optical_flow_rad.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_optical_flow_rad.h @@ -1,35 +1,40 @@ +#pragma once // MESSAGE OPTICAL_FLOW_RAD PACKING #define MAVLINK_MSG_ID_OPTICAL_FLOW_RAD 106 -typedef struct __mavlink_optical_flow_rad_t -{ - uint64_t time_usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - uint32_t integration_time_us; ///< Integration time in microseconds. Divide integrated_x and integrated_y by the integration time to obtain average flow. The integration time also indicates the. - float integrated_x; ///< Flow in radians around X axis (Sensor RH rotation about the X axis induces a positive flow. Sensor linear motion along the positive Y axis induces a negative flow.) - float integrated_y; ///< Flow in radians around Y axis (Sensor RH rotation about the Y axis induces a positive flow. Sensor linear motion along the positive X axis induces a positive flow.) - float integrated_xgyro; ///< RH rotation around X axis (rad) - float integrated_ygyro; ///< RH rotation around Y axis (rad) - float integrated_zgyro; ///< RH rotation around Z axis (rad) - uint32_t time_delta_distance_us; ///< Time in microseconds since the distance was sampled. - float distance; ///< Distance to the center of the flow field in meters. Positive value (including zero): distance known. Negative value: Unknown distance. - int16_t temperature; ///< Temperature * 100 in centi-degrees Celsius - uint8_t sensor_id; ///< Sensor ID - uint8_t quality; ///< Optical flow quality / confidence. 0: no valid flow, 255: maximum quality -} mavlink_optical_flow_rad_t; +MAVPACKED( +typedef struct __mavlink_optical_flow_rad_t { + uint64_t time_usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + uint32_t integration_time_us; /*< Integration time in microseconds. Divide integrated_x and integrated_y by the integration time to obtain average flow. The integration time also indicates the.*/ + float integrated_x; /*< Flow in radians around X axis (Sensor RH rotation about the X axis induces a positive flow. Sensor linear motion along the positive Y axis induces a negative flow.)*/ + float integrated_y; /*< Flow in radians around Y axis (Sensor RH rotation about the Y axis induces a positive flow. Sensor linear motion along the positive X axis induces a positive flow.)*/ + float integrated_xgyro; /*< RH rotation around X axis (rad)*/ + float integrated_ygyro; /*< RH rotation around Y axis (rad)*/ + float integrated_zgyro; /*< RH rotation around Z axis (rad)*/ + uint32_t time_delta_distance_us; /*< Time in microseconds since the distance was sampled.*/ + float distance; /*< Distance to the center of the flow field in meters. Positive value (including zero): distance known. Negative value: Unknown distance.*/ + int16_t temperature; /*< Temperature * 100 in centi-degrees Celsius*/ + uint8_t sensor_id; /*< Sensor ID*/ + uint8_t quality; /*< Optical flow quality / confidence. 0: no valid flow, 255: maximum quality*/ +}) mavlink_optical_flow_rad_t; #define MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN 44 +#define MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN 44 #define MAVLINK_MSG_ID_106_LEN 44 +#define MAVLINK_MSG_ID_106_MIN_LEN 44 #define MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC 138 #define MAVLINK_MSG_ID_106_CRC 138 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_OPTICAL_FLOW_RAD { \ - "OPTICAL_FLOW_RAD", \ - 12, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_optical_flow_rad_t, time_usec) }, \ + 106, \ + "OPTICAL_FLOW_RAD", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_optical_flow_rad_t, time_usec) }, \ { "integration_time_us", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_optical_flow_rad_t, integration_time_us) }, \ { "integrated_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_optical_flow_rad_t, integrated_x) }, \ { "integrated_y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_optical_flow_rad_t, integrated_y) }, \ @@ -43,7 +48,25 @@ typedef struct __mavlink_optical_flow_rad_t { "quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 43, offsetof(mavlink_optical_flow_rad_t, quality) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_OPTICAL_FLOW_RAD { \ + "OPTICAL_FLOW_RAD", \ + 12, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_optical_flow_rad_t, time_usec) }, \ + { "integration_time_us", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_optical_flow_rad_t, integration_time_us) }, \ + { "integrated_x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_optical_flow_rad_t, integrated_x) }, \ + { "integrated_y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_optical_flow_rad_t, integrated_y) }, \ + { "integrated_xgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_optical_flow_rad_t, integrated_xgyro) }, \ + { "integrated_ygyro", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_optical_flow_rad_t, integrated_ygyro) }, \ + { "integrated_zgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_optical_flow_rad_t, integrated_zgyro) }, \ + { "time_delta_distance_us", NULL, MAVLINK_TYPE_UINT32_T, 0, 32, offsetof(mavlink_optical_flow_rad_t, time_delta_distance_us) }, \ + { "distance", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_optical_flow_rad_t, distance) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 40, offsetof(mavlink_optical_flow_rad_t, temperature) }, \ + { "sensor_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_optical_flow_rad_t, sensor_id) }, \ + { "quality", NULL, MAVLINK_TYPE_UINT8_T, 0, 43, offsetof(mavlink_optical_flow_rad_t, quality) }, \ + } \ +} +#endif /** * @brief Pack a optical_flow_rad message @@ -66,48 +89,44 @@ typedef struct __mavlink_optical_flow_rad_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_optical_flow_rad_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) + uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); + char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); #else - mavlink_optical_flow_rad_t packet; - packet.time_usec = time_usec; - packet.integration_time_us = integration_time_us; - packet.integrated_x = integrated_x; - packet.integrated_y = integrated_y; - packet.integrated_xgyro = integrated_xgyro; - packet.integrated_ygyro = integrated_ygyro; - packet.integrated_zgyro = integrated_zgyro; - packet.time_delta_distance_us = time_delta_distance_us; - packet.distance = distance; - packet.temperature = temperature; - packet.sensor_id = sensor_id; - packet.quality = quality; + mavlink_optical_flow_rad_t packet; + packet.time_usec = time_usec; + packet.integration_time_us = integration_time_us; + packet.integrated_x = integrated_x; + packet.integrated_y = integrated_y; + packet.integrated_xgyro = integrated_xgyro; + packet.integrated_ygyro = integrated_ygyro; + packet.integrated_zgyro = integrated_zgyro; + packet.time_delta_distance_us = time_delta_distance_us; + packet.distance = distance; + packet.temperature = temperature; + packet.sensor_id = sensor_id; + packet.quality = quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW_RAD; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW_RAD; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); } /** @@ -131,49 +150,45 @@ static inline uint16_t mavlink_msg_optical_flow_rad_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_optical_flow_rad_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t sensor_id,uint32_t integration_time_us,float integrated_x,float integrated_y,float integrated_xgyro,float integrated_ygyro,float integrated_zgyro,int16_t temperature,uint8_t quality,uint32_t time_delta_distance_us,float distance) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t sensor_id,uint32_t integration_time_us,float integrated_x,float integrated_y,float integrated_xgyro,float integrated_ygyro,float integrated_zgyro,int16_t temperature,uint8_t quality,uint32_t time_delta_distance_us,float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); + char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); #else - mavlink_optical_flow_rad_t packet; - packet.time_usec = time_usec; - packet.integration_time_us = integration_time_us; - packet.integrated_x = integrated_x; - packet.integrated_y = integrated_y; - packet.integrated_xgyro = integrated_xgyro; - packet.integrated_ygyro = integrated_ygyro; - packet.integrated_zgyro = integrated_zgyro; - packet.time_delta_distance_us = time_delta_distance_us; - packet.distance = distance; - packet.temperature = temperature; - packet.sensor_id = sensor_id; - packet.quality = quality; + mavlink_optical_flow_rad_t packet; + packet.time_usec = time_usec; + packet.integration_time_us = integration_time_us; + packet.integrated_x = integrated_x; + packet.integrated_y = integrated_y; + packet.integrated_xgyro = integrated_xgyro; + packet.integrated_ygyro = integrated_ygyro; + packet.integrated_zgyro = integrated_zgyro; + packet.time_delta_distance_us = time_delta_distance_us; + packet.distance = distance; + packet.temperature = temperature; + packet.sensor_id = sensor_id; + packet.quality = quality; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW_RAD; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_OPTICAL_FLOW_RAD; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); } /** @@ -186,7 +201,7 @@ static inline uint16_t mavlink_msg_optical_flow_rad_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_optical_flow_rad_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_optical_flow_rad_t* optical_flow_rad) { - return mavlink_msg_optical_flow_rad_pack(system_id, component_id, msg, optical_flow_rad->time_usec, optical_flow_rad->sensor_id, optical_flow_rad->integration_time_us, optical_flow_rad->integrated_x, optical_flow_rad->integrated_y, optical_flow_rad->integrated_xgyro, optical_flow_rad->integrated_ygyro, optical_flow_rad->integrated_zgyro, optical_flow_rad->temperature, optical_flow_rad->quality, optical_flow_rad->time_delta_distance_us, optical_flow_rad->distance); + return mavlink_msg_optical_flow_rad_pack(system_id, component_id, msg, optical_flow_rad->time_usec, optical_flow_rad->sensor_id, optical_flow_rad->integration_time_us, optical_flow_rad->integrated_x, optical_flow_rad->integrated_y, optical_flow_rad->integrated_xgyro, optical_flow_rad->integrated_ygyro, optical_flow_rad->integrated_zgyro, optical_flow_rad->temperature, optical_flow_rad->quality, optical_flow_rad->time_delta_distance_us, optical_flow_rad->distance); } /** @@ -200,7 +215,7 @@ static inline uint16_t mavlink_msg_optical_flow_rad_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_optical_flow_rad_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_optical_flow_rad_t* optical_flow_rad) { - return mavlink_msg_optical_flow_rad_pack_chan(system_id, component_id, chan, msg, optical_flow_rad->time_usec, optical_flow_rad->sensor_id, optical_flow_rad->integration_time_us, optical_flow_rad->integrated_x, optical_flow_rad->integrated_y, optical_flow_rad->integrated_xgyro, optical_flow_rad->integrated_ygyro, optical_flow_rad->integrated_zgyro, optical_flow_rad->temperature, optical_flow_rad->quality, optical_flow_rad->time_delta_distance_us, optical_flow_rad->distance); + return mavlink_msg_optical_flow_rad_pack_chan(system_id, component_id, chan, msg, optical_flow_rad->time_usec, optical_flow_rad->sensor_id, optical_flow_rad->integration_time_us, optical_flow_rad->integrated_x, optical_flow_rad->integrated_y, optical_flow_rad->integrated_xgyro, optical_flow_rad->integrated_ygyro, optical_flow_rad->integrated_zgyro, optical_flow_rad->temperature, optical_flow_rad->quality, optical_flow_rad->time_delta_distance_us, optical_flow_rad->distance); } /** @@ -225,45 +240,51 @@ static inline uint16_t mavlink_msg_optical_flow_rad_encode_chan(uint8_t system_i static inline void mavlink_msg_optical_flow_rad_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); + char buf[MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); + mavlink_optical_flow_rad_t packet; + packet.time_usec = time_usec; + packet.integration_time_us = integration_time_us; + packet.integrated_x = integrated_x; + packet.integrated_y = integrated_y; + packet.integrated_xgyro = integrated_xgyro; + packet.integrated_ygyro = integrated_ygyro; + packet.integrated_zgyro = integrated_zgyro; + packet.time_delta_distance_us = time_delta_distance_us; + packet.distance = distance; + packet.temperature = temperature; + packet.sensor_id = sensor_id; + packet.quality = quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, (const char *)&packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); #endif +} + +/** + * @brief Send a optical_flow_rad message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_optical_flow_rad_send_struct(mavlink_channel_t chan, const mavlink_optical_flow_rad_t* optical_flow_rad) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_optical_flow_rad_send(chan, optical_flow_rad->time_usec, optical_flow_rad->sensor_id, optical_flow_rad->integration_time_us, optical_flow_rad->integrated_x, optical_flow_rad->integrated_y, optical_flow_rad->integrated_xgyro, optical_flow_rad->integrated_ygyro, optical_flow_rad->integrated_zgyro, optical_flow_rad->temperature, optical_flow_rad->quality, optical_flow_rad->time_delta_distance_us, optical_flow_rad->distance); #else - mavlink_optical_flow_rad_t packet; - packet.time_usec = time_usec; - packet.integration_time_us = integration_time_us; - packet.integrated_x = integrated_x; - packet.integrated_y = integrated_y; - packet.integrated_xgyro = integrated_xgyro; - packet.integrated_ygyro = integrated_ygyro; - packet.integrated_zgyro = integrated_zgyro; - packet.time_delta_distance_us = time_delta_distance_us; - packet.distance = distance; - packet.temperature = temperature; - packet.sensor_id = sensor_id; - packet.quality = quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, (const char *)&packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, (const char *)&packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, (const char *)optical_flow_rad, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); #endif } @@ -278,45 +299,37 @@ static inline void mavlink_msg_optical_flow_rad_send(mavlink_channel_t chan, uin static inline void mavlink_msg_optical_flow_rad_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t sensor_id, uint32_t integration_time_us, float integrated_x, float integrated_y, float integrated_xgyro, float integrated_ygyro, float integrated_zgyro, int16_t temperature, uint8_t quality, uint32_t time_delta_distance_us, float distance) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, integration_time_us); - _mav_put_float(buf, 12, integrated_x); - _mav_put_float(buf, 16, integrated_y); - _mav_put_float(buf, 20, integrated_xgyro); - _mav_put_float(buf, 24, integrated_ygyro); - _mav_put_float(buf, 28, integrated_zgyro); - _mav_put_uint32_t(buf, 32, time_delta_distance_us); - _mav_put_float(buf, 36, distance); - _mav_put_int16_t(buf, 40, temperature); - _mav_put_uint8_t(buf, 42, sensor_id); - _mav_put_uint8_t(buf, 43, quality); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, integration_time_us); + _mav_put_float(buf, 12, integrated_x); + _mav_put_float(buf, 16, integrated_y); + _mav_put_float(buf, 20, integrated_xgyro); + _mav_put_float(buf, 24, integrated_ygyro); + _mav_put_float(buf, 28, integrated_zgyro); + _mav_put_uint32_t(buf, 32, time_delta_distance_us); + _mav_put_float(buf, 36, distance); + _mav_put_int16_t(buf, 40, temperature); + _mav_put_uint8_t(buf, 42, sensor_id); + _mav_put_uint8_t(buf, 43, quality); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, buf, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); -#endif -#else - mavlink_optical_flow_rad_t *packet = (mavlink_optical_flow_rad_t *)msgbuf; - packet->time_usec = time_usec; - packet->integration_time_us = integration_time_us; - packet->integrated_x = integrated_x; - packet->integrated_y = integrated_y; - packet->integrated_xgyro = integrated_xgyro; - packet->integrated_ygyro = integrated_ygyro; - packet->integrated_zgyro = integrated_zgyro; - packet->time_delta_distance_us = time_delta_distance_us; - packet->distance = distance; - packet->temperature = temperature; - packet->sensor_id = sensor_id; - packet->quality = quality; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, (const char *)packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, (const char *)packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); -#endif + mavlink_optical_flow_rad_t *packet = (mavlink_optical_flow_rad_t *)msgbuf; + packet->time_usec = time_usec; + packet->integration_time_us = integration_time_us; + packet->integrated_x = integrated_x; + packet->integrated_y = integrated_y; + packet->integrated_xgyro = integrated_xgyro; + packet->integrated_ygyro = integrated_ygyro; + packet->integrated_zgyro = integrated_zgyro; + packet->time_delta_distance_us = time_delta_distance_us; + packet->distance = distance; + packet->temperature = temperature; + packet->sensor_id = sensor_id; + packet->quality = quality; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD, (const char *)packet, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_CRC); #endif } #endif @@ -333,7 +346,7 @@ static inline void mavlink_msg_optical_flow_rad_send_buf(mavlink_message_t *msgb */ static inline uint64_t mavlink_msg_optical_flow_rad_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -343,7 +356,7 @@ static inline uint64_t mavlink_msg_optical_flow_rad_get_time_usec(const mavlink_ */ static inline uint8_t mavlink_msg_optical_flow_rad_get_sensor_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 42); + return _MAV_RETURN_uint8_t(msg, 42); } /** @@ -353,7 +366,7 @@ static inline uint8_t mavlink_msg_optical_flow_rad_get_sensor_id(const mavlink_m */ static inline uint32_t mavlink_msg_optical_flow_rad_get_integration_time_us(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 8); + return _MAV_RETURN_uint32_t(msg, 8); } /** @@ -363,7 +376,7 @@ static inline uint32_t mavlink_msg_optical_flow_rad_get_integration_time_us(cons */ static inline float mavlink_msg_optical_flow_rad_get_integrated_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -373,7 +386,7 @@ static inline float mavlink_msg_optical_flow_rad_get_integrated_x(const mavlink_ */ static inline float mavlink_msg_optical_flow_rad_get_integrated_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -383,7 +396,7 @@ static inline float mavlink_msg_optical_flow_rad_get_integrated_y(const mavlink_ */ static inline float mavlink_msg_optical_flow_rad_get_integrated_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -393,7 +406,7 @@ static inline float mavlink_msg_optical_flow_rad_get_integrated_xgyro(const mavl */ static inline float mavlink_msg_optical_flow_rad_get_integrated_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -403,7 +416,7 @@ static inline float mavlink_msg_optical_flow_rad_get_integrated_ygyro(const mavl */ static inline float mavlink_msg_optical_flow_rad_get_integrated_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -413,7 +426,7 @@ static inline float mavlink_msg_optical_flow_rad_get_integrated_zgyro(const mavl */ static inline int16_t mavlink_msg_optical_flow_rad_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 40); + return _MAV_RETURN_int16_t(msg, 40); } /** @@ -423,7 +436,7 @@ static inline int16_t mavlink_msg_optical_flow_rad_get_temperature(const mavlink */ static inline uint8_t mavlink_msg_optical_flow_rad_get_quality(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 43); + return _MAV_RETURN_uint8_t(msg, 43); } /** @@ -433,7 +446,7 @@ static inline uint8_t mavlink_msg_optical_flow_rad_get_quality(const mavlink_mes */ static inline uint32_t mavlink_msg_optical_flow_rad_get_time_delta_distance_us(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 32); + return _MAV_RETURN_uint32_t(msg, 32); } /** @@ -443,7 +456,7 @@ static inline uint32_t mavlink_msg_optical_flow_rad_get_time_delta_distance_us(c */ static inline float mavlink_msg_optical_flow_rad_get_distance(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -454,20 +467,22 @@ static inline float mavlink_msg_optical_flow_rad_get_distance(const mavlink_mess */ static inline void mavlink_msg_optical_flow_rad_decode(const mavlink_message_t* msg, mavlink_optical_flow_rad_t* optical_flow_rad) { -#if MAVLINK_NEED_BYTE_SWAP - optical_flow_rad->time_usec = mavlink_msg_optical_flow_rad_get_time_usec(msg); - optical_flow_rad->integration_time_us = mavlink_msg_optical_flow_rad_get_integration_time_us(msg); - optical_flow_rad->integrated_x = mavlink_msg_optical_flow_rad_get_integrated_x(msg); - optical_flow_rad->integrated_y = mavlink_msg_optical_flow_rad_get_integrated_y(msg); - optical_flow_rad->integrated_xgyro = mavlink_msg_optical_flow_rad_get_integrated_xgyro(msg); - optical_flow_rad->integrated_ygyro = mavlink_msg_optical_flow_rad_get_integrated_ygyro(msg); - optical_flow_rad->integrated_zgyro = mavlink_msg_optical_flow_rad_get_integrated_zgyro(msg); - optical_flow_rad->time_delta_distance_us = mavlink_msg_optical_flow_rad_get_time_delta_distance_us(msg); - optical_flow_rad->distance = mavlink_msg_optical_flow_rad_get_distance(msg); - optical_flow_rad->temperature = mavlink_msg_optical_flow_rad_get_temperature(msg); - optical_flow_rad->sensor_id = mavlink_msg_optical_flow_rad_get_sensor_id(msg); - optical_flow_rad->quality = mavlink_msg_optical_flow_rad_get_quality(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + optical_flow_rad->time_usec = mavlink_msg_optical_flow_rad_get_time_usec(msg); + optical_flow_rad->integration_time_us = mavlink_msg_optical_flow_rad_get_integration_time_us(msg); + optical_flow_rad->integrated_x = mavlink_msg_optical_flow_rad_get_integrated_x(msg); + optical_flow_rad->integrated_y = mavlink_msg_optical_flow_rad_get_integrated_y(msg); + optical_flow_rad->integrated_xgyro = mavlink_msg_optical_flow_rad_get_integrated_xgyro(msg); + optical_flow_rad->integrated_ygyro = mavlink_msg_optical_flow_rad_get_integrated_ygyro(msg); + optical_flow_rad->integrated_zgyro = mavlink_msg_optical_flow_rad_get_integrated_zgyro(msg); + optical_flow_rad->time_delta_distance_us = mavlink_msg_optical_flow_rad_get_time_delta_distance_us(msg); + optical_flow_rad->distance = mavlink_msg_optical_flow_rad_get_distance(msg); + optical_flow_rad->temperature = mavlink_msg_optical_flow_rad_get_temperature(msg); + optical_flow_rad->sensor_id = mavlink_msg_optical_flow_rad_get_sensor_id(msg); + optical_flow_rad->quality = mavlink_msg_optical_flow_rad_get_quality(msg); #else - memcpy(optical_flow_rad, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN? msg->len : MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN; + memset(optical_flow_rad, 0, MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_LEN); + memcpy(optical_flow_rad, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_param_map_rc.h b/vendor/libraries/mavlink/common/mavlink_msg_param_map_rc.h index 8f6ee0ee42..5b64b7f890 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_param_map_rc.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_param_map_rc.h @@ -1,32 +1,37 @@ +#pragma once // MESSAGE PARAM_MAP_RC PACKING #define MAVLINK_MSG_ID_PARAM_MAP_RC 50 -typedef struct __mavlink_param_map_rc_t -{ - float param_value0; ///< Initial parameter value - float scale; ///< Scale, maps the RC range [-1, 1] to a parameter value - float param_value_min; ///< Minimum param value. The protocol does not define if this overwrites an onboard minimum value. (Depends on implementation) - float param_value_max; ///< Maximum param value. The protocol does not define if this overwrites an onboard maximum value. (Depends on implementation) - int16_t param_index; ///< Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored), send -2 to disable any existing map for this rc_channel_index. - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - char param_id[16]; ///< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string - uint8_t parameter_rc_channel_index; ///< Index of parameter RC channel. Not equal to the RC channel id. Typically correpsonds to a potentiometer-knob on the RC. -} mavlink_param_map_rc_t; +MAVPACKED( +typedef struct __mavlink_param_map_rc_t { + float param_value0; /*< Initial parameter value*/ + float scale; /*< Scale, maps the RC range [-1, 1] to a parameter value*/ + float param_value_min; /*< Minimum param value. The protocol does not define if this overwrites an onboard minimum value. (Depends on implementation)*/ + float param_value_max; /*< Maximum param value. The protocol does not define if this overwrites an onboard maximum value. (Depends on implementation)*/ + int16_t param_index; /*< Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored), send -2 to disable any existing map for this rc_channel_index.*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + char param_id[16]; /*< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string*/ + uint8_t parameter_rc_channel_index; /*< Index of parameter RC channel. Not equal to the RC channel id. Typically correpsonds to a potentiometer-knob on the RC.*/ +}) mavlink_param_map_rc_t; #define MAVLINK_MSG_ID_PARAM_MAP_RC_LEN 37 +#define MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN 37 #define MAVLINK_MSG_ID_50_LEN 37 +#define MAVLINK_MSG_ID_50_MIN_LEN 37 #define MAVLINK_MSG_ID_PARAM_MAP_RC_CRC 78 #define MAVLINK_MSG_ID_50_CRC 78 #define MAVLINK_MSG_PARAM_MAP_RC_FIELD_PARAM_ID_LEN 16 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_PARAM_MAP_RC { \ - "PARAM_MAP_RC", \ - 9, \ - { { "param_value0", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_map_rc_t, param_value0) }, \ + 50, \ + "PARAM_MAP_RC", \ + 9, \ + { { "param_value0", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_map_rc_t, param_value0) }, \ { "scale", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_param_map_rc_t, scale) }, \ { "param_value_min", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_param_map_rc_t, param_value_min) }, \ { "param_value_max", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_param_map_rc_t, param_value_max) }, \ @@ -37,7 +42,22 @@ typedef struct __mavlink_param_map_rc_t { "parameter_rc_channel_index", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_param_map_rc_t, parameter_rc_channel_index) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_PARAM_MAP_RC { \ + "PARAM_MAP_RC", \ + 9, \ + { { "param_value0", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_map_rc_t, param_value0) }, \ + { "scale", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_param_map_rc_t, scale) }, \ + { "param_value_min", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_param_map_rc_t, param_value_min) }, \ + { "param_value_max", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_param_map_rc_t, param_value_max) }, \ + { "param_index", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_param_map_rc_t, param_index) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 18, offsetof(mavlink_param_map_rc_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 19, offsetof(mavlink_param_map_rc_t, target_component) }, \ + { "param_id", NULL, MAVLINK_TYPE_CHAR, 16, 20, offsetof(mavlink_param_map_rc_t, param_id) }, \ + { "parameter_rc_channel_index", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_param_map_rc_t, parameter_rc_channel_index) }, \ + } \ +} +#endif /** * @brief Pack a param_map_rc message @@ -57,40 +77,36 @@ typedef struct __mavlink_param_map_rc_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_map_rc_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index, uint8_t parameter_rc_channel_index, float param_value0, float scale, float param_value_min, float param_value_max) + uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index, uint8_t parameter_rc_channel_index, float param_value0, float scale, float param_value_min, float param_value_max) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_MAP_RC_LEN]; - _mav_put_float(buf, 0, param_value0); - _mav_put_float(buf, 4, scale); - _mav_put_float(buf, 8, param_value_min); - _mav_put_float(buf, 12, param_value_max); - _mav_put_int16_t(buf, 16, param_index); - _mav_put_uint8_t(buf, 18, target_system); - _mav_put_uint8_t(buf, 19, target_component); - _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); - _mav_put_char_array(buf, 20, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_MAP_RC_LEN]; + _mav_put_float(buf, 0, param_value0); + _mav_put_float(buf, 4, scale); + _mav_put_float(buf, 8, param_value_min); + _mav_put_float(buf, 12, param_value_max); + _mav_put_int16_t(buf, 16, param_index); + _mav_put_uint8_t(buf, 18, target_system); + _mav_put_uint8_t(buf, 19, target_component); + _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); + _mav_put_char_array(buf, 20, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); #else - mavlink_param_map_rc_t packet; - packet.param_value0 = param_value0; - packet.scale = scale; - packet.param_value_min = param_value_min; - packet.param_value_max = param_value_max; - packet.param_index = param_index; - packet.target_system = target_system; - packet.target_component = target_component; - packet.parameter_rc_channel_index = parameter_rc_channel_index; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_map_rc_t packet; + packet.param_value0 = param_value0; + packet.scale = scale; + packet.param_value_min = param_value_min; + packet.param_value_max = param_value_max; + packet.param_index = param_index; + packet.target_system = target_system; + packet.target_component = target_component; + packet.parameter_rc_channel_index = parameter_rc_channel_index; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_MAP_RC; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_MAP_RC; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); } /** @@ -111,41 +127,37 @@ static inline uint16_t mavlink_msg_param_map_rc_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_map_rc_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,const char *param_id,int16_t param_index,uint8_t parameter_rc_channel_index,float param_value0,float scale,float param_value_min,float param_value_max) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,const char *param_id,int16_t param_index,uint8_t parameter_rc_channel_index,float param_value0,float scale,float param_value_min,float param_value_max) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_MAP_RC_LEN]; - _mav_put_float(buf, 0, param_value0); - _mav_put_float(buf, 4, scale); - _mav_put_float(buf, 8, param_value_min); - _mav_put_float(buf, 12, param_value_max); - _mav_put_int16_t(buf, 16, param_index); - _mav_put_uint8_t(buf, 18, target_system); - _mav_put_uint8_t(buf, 19, target_component); - _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); - _mav_put_char_array(buf, 20, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_MAP_RC_LEN]; + _mav_put_float(buf, 0, param_value0); + _mav_put_float(buf, 4, scale); + _mav_put_float(buf, 8, param_value_min); + _mav_put_float(buf, 12, param_value_max); + _mav_put_int16_t(buf, 16, param_index); + _mav_put_uint8_t(buf, 18, target_system); + _mav_put_uint8_t(buf, 19, target_component); + _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); + _mav_put_char_array(buf, 20, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); #else - mavlink_param_map_rc_t packet; - packet.param_value0 = param_value0; - packet.scale = scale; - packet.param_value_min = param_value_min; - packet.param_value_max = param_value_max; - packet.param_index = param_index; - packet.target_system = target_system; - packet.target_component = target_component; - packet.parameter_rc_channel_index = parameter_rc_channel_index; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_map_rc_t packet; + packet.param_value0 = param_value0; + packet.scale = scale; + packet.param_value_min = param_value_min; + packet.param_value_max = param_value_max; + packet.param_index = param_index; + packet.target_system = target_system; + packet.target_component = target_component; + packet.parameter_rc_channel_index = parameter_rc_channel_index; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_MAP_RC; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_MAP_RC; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); } /** @@ -158,7 +170,7 @@ static inline uint16_t mavlink_msg_param_map_rc_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_param_map_rc_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_param_map_rc_t* param_map_rc) { - return mavlink_msg_param_map_rc_pack(system_id, component_id, msg, param_map_rc->target_system, param_map_rc->target_component, param_map_rc->param_id, param_map_rc->param_index, param_map_rc->parameter_rc_channel_index, param_map_rc->param_value0, param_map_rc->scale, param_map_rc->param_value_min, param_map_rc->param_value_max); + return mavlink_msg_param_map_rc_pack(system_id, component_id, msg, param_map_rc->target_system, param_map_rc->target_component, param_map_rc->param_id, param_map_rc->param_index, param_map_rc->parameter_rc_channel_index, param_map_rc->param_value0, param_map_rc->scale, param_map_rc->param_value_min, param_map_rc->param_value_max); } /** @@ -172,7 +184,7 @@ static inline uint16_t mavlink_msg_param_map_rc_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_param_map_rc_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_map_rc_t* param_map_rc) { - return mavlink_msg_param_map_rc_pack_chan(system_id, component_id, chan, msg, param_map_rc->target_system, param_map_rc->target_component, param_map_rc->param_id, param_map_rc->param_index, param_map_rc->parameter_rc_channel_index, param_map_rc->param_value0, param_map_rc->scale, param_map_rc->param_value_min, param_map_rc->param_value_max); + return mavlink_msg_param_map_rc_pack_chan(system_id, component_id, chan, msg, param_map_rc->target_system, param_map_rc->target_component, param_map_rc->param_id, param_map_rc->param_index, param_map_rc->parameter_rc_channel_index, param_map_rc->param_value0, param_map_rc->scale, param_map_rc->param_value_min, param_map_rc->param_value_max); } /** @@ -194,37 +206,43 @@ static inline uint16_t mavlink_msg_param_map_rc_encode_chan(uint8_t system_id, u static inline void mavlink_msg_param_map_rc_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index, uint8_t parameter_rc_channel_index, float param_value0, float scale, float param_value_min, float param_value_max) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_MAP_RC_LEN]; - _mav_put_float(buf, 0, param_value0); - _mav_put_float(buf, 4, scale); - _mav_put_float(buf, 8, param_value_min); - _mav_put_float(buf, 12, param_value_max); - _mav_put_int16_t(buf, 16, param_index); - _mav_put_uint8_t(buf, 18, target_system); - _mav_put_uint8_t(buf, 19, target_component); - _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); - _mav_put_char_array(buf, 20, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, buf, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); + char buf[MAVLINK_MSG_ID_PARAM_MAP_RC_LEN]; + _mav_put_float(buf, 0, param_value0); + _mav_put_float(buf, 4, scale); + _mav_put_float(buf, 8, param_value_min); + _mav_put_float(buf, 12, param_value_max); + _mav_put_int16_t(buf, 16, param_index); + _mav_put_uint8_t(buf, 18, target_system); + _mav_put_uint8_t(buf, 19, target_component); + _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); + _mav_put_char_array(buf, 20, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, buf, MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, buf, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); + mavlink_param_map_rc_t packet; + packet.param_value0 = param_value0; + packet.scale = scale; + packet.param_value_min = param_value_min; + packet.param_value_max = param_value_max; + packet.param_index = param_index; + packet.target_system = target_system; + packet.target_component = target_component; + packet.parameter_rc_channel_index = parameter_rc_channel_index; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, (const char *)&packet, MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); #endif +} + +/** + * @brief Send a param_map_rc message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_param_map_rc_send_struct(mavlink_channel_t chan, const mavlink_param_map_rc_t* param_map_rc) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_param_map_rc_send(chan, param_map_rc->target_system, param_map_rc->target_component, param_map_rc->param_id, param_map_rc->param_index, param_map_rc->parameter_rc_channel_index, param_map_rc->param_value0, param_map_rc->scale, param_map_rc->param_value_min, param_map_rc->param_value_max); #else - mavlink_param_map_rc_t packet; - packet.param_value0 = param_value0; - packet.scale = scale; - packet.param_value_min = param_value_min; - packet.param_value_max = param_value_max; - packet.param_index = param_index; - packet.target_system = target_system; - packet.target_component = target_component; - packet.parameter_rc_channel_index = parameter_rc_channel_index; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, (const char *)&packet, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, (const char *)&packet, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, (const char *)param_map_rc, MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); #endif } @@ -239,37 +257,29 @@ static inline void mavlink_msg_param_map_rc_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_param_map_rc_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index, uint8_t parameter_rc_channel_index, float param_value0, float scale, float param_value_min, float param_value_max) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, param_value0); - _mav_put_float(buf, 4, scale); - _mav_put_float(buf, 8, param_value_min); - _mav_put_float(buf, 12, param_value_max); - _mav_put_int16_t(buf, 16, param_index); - _mav_put_uint8_t(buf, 18, target_system); - _mav_put_uint8_t(buf, 19, target_component); - _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); - _mav_put_char_array(buf, 20, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, buf, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, buf, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); -#endif -#else - mavlink_param_map_rc_t *packet = (mavlink_param_map_rc_t *)msgbuf; - packet->param_value0 = param_value0; - packet->scale = scale; - packet->param_value_min = param_value_min; - packet->param_value_max = param_value_max; - packet->param_index = param_index; - packet->target_system = target_system; - packet->target_component = target_component; - packet->parameter_rc_channel_index = parameter_rc_channel_index; - mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, (const char *)packet, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, param_value0); + _mav_put_float(buf, 4, scale); + _mav_put_float(buf, 8, param_value_min); + _mav_put_float(buf, 12, param_value_max); + _mav_put_int16_t(buf, 16, param_index); + _mav_put_uint8_t(buf, 18, target_system); + _mav_put_uint8_t(buf, 19, target_component); + _mav_put_uint8_t(buf, 36, parameter_rc_channel_index); + _mav_put_char_array(buf, 20, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, buf, MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, (const char *)packet, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); -#endif + mavlink_param_map_rc_t *packet = (mavlink_param_map_rc_t *)msgbuf; + packet->param_value0 = param_value0; + packet->scale = scale; + packet->param_value_min = param_value_min; + packet->param_value_max = param_value_max; + packet->param_index = param_index; + packet->target_system = target_system; + packet->target_component = target_component; + packet->parameter_rc_channel_index = parameter_rc_channel_index; + mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_MAP_RC, (const char *)packet, MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN, MAVLINK_MSG_ID_PARAM_MAP_RC_CRC); #endif } #endif @@ -286,7 +296,7 @@ static inline void mavlink_msg_param_map_rc_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_param_map_rc_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 18); + return _MAV_RETURN_uint8_t(msg, 18); } /** @@ -296,7 +306,7 @@ static inline uint8_t mavlink_msg_param_map_rc_get_target_system(const mavlink_m */ static inline uint8_t mavlink_msg_param_map_rc_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 19); + return _MAV_RETURN_uint8_t(msg, 19); } /** @@ -306,7 +316,7 @@ static inline uint8_t mavlink_msg_param_map_rc_get_target_component(const mavlin */ static inline uint16_t mavlink_msg_param_map_rc_get_param_id(const mavlink_message_t* msg, char *param_id) { - return _MAV_RETURN_char_array(msg, param_id, 16, 20); + return _MAV_RETURN_char_array(msg, param_id, 16, 20); } /** @@ -316,7 +326,7 @@ static inline uint16_t mavlink_msg_param_map_rc_get_param_id(const mavlink_messa */ static inline int16_t mavlink_msg_param_map_rc_get_param_index(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 16); + return _MAV_RETURN_int16_t(msg, 16); } /** @@ -326,7 +336,7 @@ static inline int16_t mavlink_msg_param_map_rc_get_param_index(const mavlink_mes */ static inline uint8_t mavlink_msg_param_map_rc_get_parameter_rc_channel_index(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 36); + return _MAV_RETURN_uint8_t(msg, 36); } /** @@ -336,7 +346,7 @@ static inline uint8_t mavlink_msg_param_map_rc_get_parameter_rc_channel_index(co */ static inline float mavlink_msg_param_map_rc_get_param_value0(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -346,7 +356,7 @@ static inline float mavlink_msg_param_map_rc_get_param_value0(const mavlink_mess */ static inline float mavlink_msg_param_map_rc_get_scale(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -356,7 +366,7 @@ static inline float mavlink_msg_param_map_rc_get_scale(const mavlink_message_t* */ static inline float mavlink_msg_param_map_rc_get_param_value_min(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -366,7 +376,7 @@ static inline float mavlink_msg_param_map_rc_get_param_value_min(const mavlink_m */ static inline float mavlink_msg_param_map_rc_get_param_value_max(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -377,17 +387,19 @@ static inline float mavlink_msg_param_map_rc_get_param_value_max(const mavlink_m */ static inline void mavlink_msg_param_map_rc_decode(const mavlink_message_t* msg, mavlink_param_map_rc_t* param_map_rc) { -#if MAVLINK_NEED_BYTE_SWAP - param_map_rc->param_value0 = mavlink_msg_param_map_rc_get_param_value0(msg); - param_map_rc->scale = mavlink_msg_param_map_rc_get_scale(msg); - param_map_rc->param_value_min = mavlink_msg_param_map_rc_get_param_value_min(msg); - param_map_rc->param_value_max = mavlink_msg_param_map_rc_get_param_value_max(msg); - param_map_rc->param_index = mavlink_msg_param_map_rc_get_param_index(msg); - param_map_rc->target_system = mavlink_msg_param_map_rc_get_target_system(msg); - param_map_rc->target_component = mavlink_msg_param_map_rc_get_target_component(msg); - mavlink_msg_param_map_rc_get_param_id(msg, param_map_rc->param_id); - param_map_rc->parameter_rc_channel_index = mavlink_msg_param_map_rc_get_parameter_rc_channel_index(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + param_map_rc->param_value0 = mavlink_msg_param_map_rc_get_param_value0(msg); + param_map_rc->scale = mavlink_msg_param_map_rc_get_scale(msg); + param_map_rc->param_value_min = mavlink_msg_param_map_rc_get_param_value_min(msg); + param_map_rc->param_value_max = mavlink_msg_param_map_rc_get_param_value_max(msg); + param_map_rc->param_index = mavlink_msg_param_map_rc_get_param_index(msg); + param_map_rc->target_system = mavlink_msg_param_map_rc_get_target_system(msg); + param_map_rc->target_component = mavlink_msg_param_map_rc_get_target_component(msg); + mavlink_msg_param_map_rc_get_param_id(msg, param_map_rc->param_id); + param_map_rc->parameter_rc_channel_index = mavlink_msg_param_map_rc_get_parameter_rc_channel_index(msg); #else - memcpy(param_map_rc, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_PARAM_MAP_RC_LEN? msg->len : MAVLINK_MSG_ID_PARAM_MAP_RC_LEN; + memset(param_map_rc, 0, MAVLINK_MSG_ID_PARAM_MAP_RC_LEN); + memcpy(param_map_rc, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_param_request_list.h b/vendor/libraries/mavlink/common/mavlink_msg_param_request_list.h index f9466b002e..2c5da24bc6 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_param_request_list.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_param_request_list.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE PARAM_REQUEST_LIST PACKING #define MAVLINK_MSG_ID_PARAM_REQUEST_LIST 21 -typedef struct __mavlink_param_request_list_t -{ - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_param_request_list_t; +MAVPACKED( +typedef struct __mavlink_param_request_list_t { + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_param_request_list_t; #define MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN 2 +#define MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN 2 #define MAVLINK_MSG_ID_21_LEN 2 +#define MAVLINK_MSG_ID_21_MIN_LEN 2 #define MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC 159 #define MAVLINK_MSG_ID_21_CRC 159 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST { \ - "PARAM_REQUEST_LIST", \ - 2, \ - { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_param_request_list_t, target_system) }, \ + 21, \ + "PARAM_REQUEST_LIST", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_param_request_list_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_param_request_list_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_PARAM_REQUEST_LIST { \ + "PARAM_REQUEST_LIST", \ + 2, \ + { { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_param_request_list_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_param_request_list_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a param_request_list message @@ -36,28 +49,24 @@ typedef struct __mavlink_param_request_list_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_request_list_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component) + uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); #else - mavlink_param_request_list_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_param_request_list_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_LIST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_param_request_list_pack(uint8_t system_id, ui * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_request_list_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); #else - mavlink_param_request_list_t packet; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_param_request_list_t packet; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_LIST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_LIST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_param_request_list_pack_chan(uint8_t system_i */ static inline uint16_t mavlink_msg_param_request_list_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_param_request_list_t* param_request_list) { - return mavlink_msg_param_request_list_pack(system_id, component_id, msg, param_request_list->target_system, param_request_list->target_component); + return mavlink_msg_param_request_list_pack(system_id, component_id, msg, param_request_list->target_system, param_request_list->target_component); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_param_request_list_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_param_request_list_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_request_list_t* param_request_list) { - return mavlink_msg_param_request_list_pack_chan(system_id, component_id, chan, msg, param_request_list->target_system, param_request_list->target_component); + return mavlink_msg_param_request_list_pack_chan(system_id, component_id, chan, msg, param_request_list->target_system, param_request_list->target_component); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_param_request_list_encode_chan(uint8_t system static inline void mavlink_msg_param_request_list_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN]; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char buf[MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN]; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); + mavlink_param_request_list_t packet; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); #endif -#else - mavlink_param_request_list_t packet; - packet.target_system = target_system; - packet.target_component = target_component; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); +/** + * @brief Send a param_request_list message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_param_request_list_send_struct(mavlink_channel_t chan, const mavlink_param_request_list_t* param_request_list) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_param_request_list_send(chan, param_request_list->target_system, param_request_list->target_component); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, (const char *)&packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, (const char *)param_request_list, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_param_request_list_send(mavlink_channel_t chan, u static inline void mavlink_msg_param_request_list_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, target_system); - _mav_put_uint8_t(buf, 1, target_component); + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, target_system); + _mav_put_uint8_t(buf, 1, target_component); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, buf, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); #else - mavlink_param_request_list_t *packet = (mavlink_param_request_list_t *)msgbuf; - packet->target_system = target_system; - packet->target_component = target_component; + mavlink_param_request_list_t *packet = (mavlink_param_request_list_t *)msgbuf; + packet->target_system = target_system; + packet->target_component = target_component; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_LIST, (const char *)packet, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_param_request_list_send_buf(mavlink_message_t *ms */ static inline uint8_t mavlink_msg_param_request_list_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint8_t mavlink_msg_param_request_list_get_target_system(const mav */ static inline uint8_t mavlink_msg_param_request_list_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 1); + return _MAV_RETURN_uint8_t(msg, 1); } /** @@ -224,10 +227,12 @@ static inline uint8_t mavlink_msg_param_request_list_get_target_component(const */ static inline void mavlink_msg_param_request_list_decode(const mavlink_message_t* msg, mavlink_param_request_list_t* param_request_list) { -#if MAVLINK_NEED_BYTE_SWAP - param_request_list->target_system = mavlink_msg_param_request_list_get_target_system(msg); - param_request_list->target_component = mavlink_msg_param_request_list_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + param_request_list->target_system = mavlink_msg_param_request_list_get_target_system(msg); + param_request_list->target_component = mavlink_msg_param_request_list_get_target_component(msg); #else - memcpy(param_request_list, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN? msg->len : MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN; + memset(param_request_list, 0, MAVLINK_MSG_ID_PARAM_REQUEST_LIST_LEN); + memcpy(param_request_list, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_param_request_read.h b/vendor/libraries/mavlink/common/mavlink_msg_param_request_read.h index 730cff0669..5381596727 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_param_request_read.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_param_request_read.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE PARAM_REQUEST_READ PACKING #define MAVLINK_MSG_ID_PARAM_REQUEST_READ 20 -typedef struct __mavlink_param_request_read_t -{ - int16_t param_index; ///< Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored) - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - char param_id[16]; ///< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string -} mavlink_param_request_read_t; +MAVPACKED( +typedef struct __mavlink_param_request_read_t { + int16_t param_index; /*< Parameter index. Send -1 to use the param ID field as identifier (else the param id will be ignored)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + char param_id[16]; /*< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string*/ +}) mavlink_param_request_read_t; #define MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN 20 +#define MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN 20 #define MAVLINK_MSG_ID_20_LEN 20 +#define MAVLINK_MSG_ID_20_MIN_LEN 20 #define MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC 214 #define MAVLINK_MSG_ID_20_CRC 214 #define MAVLINK_MSG_PARAM_REQUEST_READ_FIELD_PARAM_ID_LEN 16 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ { \ - "PARAM_REQUEST_READ", \ - 4, \ - { { "param_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_param_request_read_t, param_index) }, \ + 20, \ + "PARAM_REQUEST_READ", \ + 4, \ + { { "param_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_param_request_read_t, param_index) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_param_request_read_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_param_request_read_t, target_component) }, \ { "param_id", NULL, MAVLINK_TYPE_CHAR, 16, 4, offsetof(mavlink_param_request_read_t, param_id) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_PARAM_REQUEST_READ { \ + "PARAM_REQUEST_READ", \ + 4, \ + { { "param_index", NULL, MAVLINK_TYPE_INT16_T, 0, 0, offsetof(mavlink_param_request_read_t, param_index) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_param_request_read_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_param_request_read_t, target_component) }, \ + { "param_id", NULL, MAVLINK_TYPE_CHAR, 16, 4, offsetof(mavlink_param_request_read_t, param_id) }, \ + } \ +} +#endif /** * @brief Pack a param_request_read message @@ -42,30 +57,26 @@ typedef struct __mavlink_param_request_read_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_request_read_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index) + uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN]; - _mav_put_int16_t(buf, 0, param_index); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_char_array(buf, 4, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN]; + _mav_put_int16_t(buf, 0, param_index); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_char_array(buf, 4, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); #else - mavlink_param_request_read_t packet; - packet.param_index = param_index; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_request_read_t packet; + packet.param_index = param_index; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_READ; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_READ; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); } /** @@ -81,31 +92,27 @@ static inline uint16_t mavlink_msg_param_request_read_pack(uint8_t system_id, ui * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_request_read_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,const char *param_id,int16_t param_index) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,const char *param_id,int16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN]; - _mav_put_int16_t(buf, 0, param_index); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_char_array(buf, 4, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN]; + _mav_put_int16_t(buf, 0, param_index); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_char_array(buf, 4, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); #else - mavlink_param_request_read_t packet; - packet.param_index = param_index; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_request_read_t packet; + packet.param_index = param_index; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_READ; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_REQUEST_READ; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); } /** @@ -118,7 +125,7 @@ static inline uint16_t mavlink_msg_param_request_read_pack_chan(uint8_t system_i */ static inline uint16_t mavlink_msg_param_request_read_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_param_request_read_t* param_request_read) { - return mavlink_msg_param_request_read_pack(system_id, component_id, msg, param_request_read->target_system, param_request_read->target_component, param_request_read->param_id, param_request_read->param_index); + return mavlink_msg_param_request_read_pack(system_id, component_id, msg, param_request_read->target_system, param_request_read->target_component, param_request_read->param_id, param_request_read->param_index); } /** @@ -132,7 +139,7 @@ static inline uint16_t mavlink_msg_param_request_read_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_param_request_read_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_request_read_t* param_request_read) { - return mavlink_msg_param_request_read_pack_chan(system_id, component_id, chan, msg, param_request_read->target_system, param_request_read->target_component, param_request_read->param_id, param_request_read->param_index); + return mavlink_msg_param_request_read_pack_chan(system_id, component_id, chan, msg, param_request_read->target_system, param_request_read->target_component, param_request_read->param_id, param_request_read->param_index); } /** @@ -149,27 +156,33 @@ static inline uint16_t mavlink_msg_param_request_read_encode_chan(uint8_t system static inline void mavlink_msg_param_request_read_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN]; - _mav_put_int16_t(buf, 0, param_index); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_char_array(buf, 4, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); + char buf[MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN]; + _mav_put_int16_t(buf, 0, param_index); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_char_array(buf, 4, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); + mavlink_param_request_read_t packet; + packet.param_index = param_index; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, (const char *)&packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); #endif +} + +/** + * @brief Send a param_request_read message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_param_request_read_send_struct(mavlink_channel_t chan, const mavlink_param_request_read_t* param_request_read) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_param_request_read_send(chan, param_request_read->target_system, param_request_read->target_component, param_request_read->param_id, param_request_read->param_index); #else - mavlink_param_request_read_t packet; - packet.param_index = param_index; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, (const char *)&packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, (const char *)&packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, (const char *)param_request_read, MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); #endif } @@ -184,27 +197,19 @@ static inline void mavlink_msg_param_request_read_send(mavlink_channel_t chan, u static inline void mavlink_msg_param_request_read_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, const char *param_id, int16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int16_t(buf, 0, param_index); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_char_array(buf, 4, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); + char *buf = (char *)msgbuf; + _mav_put_int16_t(buf, 0, param_index); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_char_array(buf, 4, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, buf, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); -#endif -#else - mavlink_param_request_read_t *packet = (mavlink_param_request_read_t *)msgbuf; - packet->param_index = param_index; - packet->target_system = target_system; - packet->target_component = target_component; - mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, (const char *)packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, (const char *)packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); -#endif + mavlink_param_request_read_t *packet = (mavlink_param_request_read_t *)msgbuf; + packet->param_index = param_index; + packet->target_system = target_system; + packet->target_component = target_component; + mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_REQUEST_READ, (const char *)packet, MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN, MAVLINK_MSG_ID_PARAM_REQUEST_READ_CRC); #endif } #endif @@ -221,7 +226,7 @@ static inline void mavlink_msg_param_request_read_send_buf(mavlink_message_t *ms */ static inline uint8_t mavlink_msg_param_request_read_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -231,7 +236,7 @@ static inline uint8_t mavlink_msg_param_request_read_get_target_system(const mav */ static inline uint8_t mavlink_msg_param_request_read_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -241,7 +246,7 @@ static inline uint8_t mavlink_msg_param_request_read_get_target_component(const */ static inline uint16_t mavlink_msg_param_request_read_get_param_id(const mavlink_message_t* msg, char *param_id) { - return _MAV_RETURN_char_array(msg, param_id, 16, 4); + return _MAV_RETURN_char_array(msg, param_id, 16, 4); } /** @@ -251,7 +256,7 @@ static inline uint16_t mavlink_msg_param_request_read_get_param_id(const mavlink */ static inline int16_t mavlink_msg_param_request_read_get_param_index(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 0); + return _MAV_RETURN_int16_t(msg, 0); } /** @@ -262,12 +267,14 @@ static inline int16_t mavlink_msg_param_request_read_get_param_index(const mavli */ static inline void mavlink_msg_param_request_read_decode(const mavlink_message_t* msg, mavlink_param_request_read_t* param_request_read) { -#if MAVLINK_NEED_BYTE_SWAP - param_request_read->param_index = mavlink_msg_param_request_read_get_param_index(msg); - param_request_read->target_system = mavlink_msg_param_request_read_get_target_system(msg); - param_request_read->target_component = mavlink_msg_param_request_read_get_target_component(msg); - mavlink_msg_param_request_read_get_param_id(msg, param_request_read->param_id); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + param_request_read->param_index = mavlink_msg_param_request_read_get_param_index(msg); + param_request_read->target_system = mavlink_msg_param_request_read_get_target_system(msg); + param_request_read->target_component = mavlink_msg_param_request_read_get_target_component(msg); + mavlink_msg_param_request_read_get_param_id(msg, param_request_read->param_id); #else - memcpy(param_request_read, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN? msg->len : MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN; + memset(param_request_read, 0, MAVLINK_MSG_ID_PARAM_REQUEST_READ_LEN); + memcpy(param_request_read, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_param_set.h b/vendor/libraries/mavlink/common/mavlink_msg_param_set.h index f669af1a25..cc73109bce 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_param_set.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_param_set.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE PARAM_SET PACKING #define MAVLINK_MSG_ID_PARAM_SET 23 -typedef struct __mavlink_param_set_t -{ - float param_value; ///< Onboard parameter value - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - char param_id[16]; ///< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string - uint8_t param_type; ///< Onboard parameter type: see the MAV_PARAM_TYPE enum for supported data types. -} mavlink_param_set_t; +MAVPACKED( +typedef struct __mavlink_param_set_t { + float param_value; /*< Onboard parameter value*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + char param_id[16]; /*< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string*/ + uint8_t param_type; /*< Onboard parameter type: see the MAV_PARAM_TYPE enum for supported data types.*/ +}) mavlink_param_set_t; #define MAVLINK_MSG_ID_PARAM_SET_LEN 23 +#define MAVLINK_MSG_ID_PARAM_SET_MIN_LEN 23 #define MAVLINK_MSG_ID_23_LEN 23 +#define MAVLINK_MSG_ID_23_MIN_LEN 23 #define MAVLINK_MSG_ID_PARAM_SET_CRC 168 #define MAVLINK_MSG_ID_23_CRC 168 #define MAVLINK_MSG_PARAM_SET_FIELD_PARAM_ID_LEN 16 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_PARAM_SET { \ - "PARAM_SET", \ - 5, \ - { { "param_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_set_t, param_value) }, \ + 23, \ + "PARAM_SET", \ + 5, \ + { { "param_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_set_t, param_value) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_param_set_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_param_set_t, target_component) }, \ { "param_id", NULL, MAVLINK_TYPE_CHAR, 16, 6, offsetof(mavlink_param_set_t, param_id) }, \ { "param_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 22, offsetof(mavlink_param_set_t, param_type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_PARAM_SET { \ + "PARAM_SET", \ + 5, \ + { { "param_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_set_t, param_value) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_param_set_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_param_set_t, target_component) }, \ + { "param_id", NULL, MAVLINK_TYPE_CHAR, 16, 6, offsetof(mavlink_param_set_t, param_id) }, \ + { "param_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 22, offsetof(mavlink_param_set_t, param_type) }, \ + } \ +} +#endif /** * @brief Pack a param_set message @@ -45,32 +61,28 @@ typedef struct __mavlink_param_set_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_set_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, const char *param_id, float param_value, uint8_t param_type) + uint8_t target_system, uint8_t target_component, const char *param_id, float param_value, uint8_t param_type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_SET_LEN]; - _mav_put_float(buf, 0, param_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 22, param_type); - _mav_put_char_array(buf, 6, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_SET_LEN]; + _mav_put_float(buf, 0, param_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 22, param_type); + _mav_put_char_array(buf, 6, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_SET_LEN); #else - mavlink_param_set_t packet; - packet.param_value = param_value; - packet.target_system = target_system; - packet.target_component = target_component; - packet.param_type = param_type; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_set_t packet; + packet.param_value = param_value; + packet.target_system = target_system; + packet.target_component = target_component; + packet.param_type = param_type; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_SET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_SET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_SET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_SET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_SET_MIN_LEN, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); } /** @@ -87,33 +99,29 @@ static inline uint16_t mavlink_msg_param_set_pack(uint8_t system_id, uint8_t com * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_set_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,const char *param_id,float param_value,uint8_t param_type) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,const char *param_id,float param_value,uint8_t param_type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_SET_LEN]; - _mav_put_float(buf, 0, param_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 22, param_type); - _mav_put_char_array(buf, 6, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_SET_LEN]; + _mav_put_float(buf, 0, param_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 22, param_type); + _mav_put_char_array(buf, 6, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_SET_LEN); #else - mavlink_param_set_t packet; - packet.param_value = param_value; - packet.target_system = target_system; - packet.target_component = target_component; - packet.param_type = param_type; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_set_t packet; + packet.param_value = param_value; + packet.target_system = target_system; + packet.target_component = target_component; + packet.param_type = param_type; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_SET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_SET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_SET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_SET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_SET_MIN_LEN, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); } /** @@ -126,7 +134,7 @@ static inline uint16_t mavlink_msg_param_set_pack_chan(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_param_set_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_param_set_t* param_set) { - return mavlink_msg_param_set_pack(system_id, component_id, msg, param_set->target_system, param_set->target_component, param_set->param_id, param_set->param_value, param_set->param_type); + return mavlink_msg_param_set_pack(system_id, component_id, msg, param_set->target_system, param_set->target_component, param_set->param_id, param_set->param_value, param_set->param_type); } /** @@ -140,7 +148,7 @@ static inline uint16_t mavlink_msg_param_set_encode(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_param_set_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_set_t* param_set) { - return mavlink_msg_param_set_pack_chan(system_id, component_id, chan, msg, param_set->target_system, param_set->target_component, param_set->param_id, param_set->param_value, param_set->param_type); + return mavlink_msg_param_set_pack_chan(system_id, component_id, chan, msg, param_set->target_system, param_set->target_component, param_set->param_id, param_set->param_value, param_set->param_type); } /** @@ -158,29 +166,35 @@ static inline uint16_t mavlink_msg_param_set_encode_chan(uint8_t system_id, uint static inline void mavlink_msg_param_set_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, const char *param_id, float param_value, uint8_t param_type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_SET_LEN]; - _mav_put_float(buf, 0, param_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 22, param_type); - _mav_put_char_array(buf, 6, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, buf, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); + char buf[MAVLINK_MSG_ID_PARAM_SET_LEN]; + _mav_put_float(buf, 0, param_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 22, param_type); + _mav_put_char_array(buf, 6, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, buf, MAVLINK_MSG_ID_PARAM_SET_MIN_LEN, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, buf, MAVLINK_MSG_ID_PARAM_SET_LEN); + mavlink_param_set_t packet; + packet.param_value = param_value; + packet.target_system = target_system; + packet.target_component = target_component; + packet.param_type = param_type; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, (const char *)&packet, MAVLINK_MSG_ID_PARAM_SET_MIN_LEN, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); #endif +} + +/** + * @brief Send a param_set message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_param_set_send_struct(mavlink_channel_t chan, const mavlink_param_set_t* param_set) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_param_set_send(chan, param_set->target_system, param_set->target_component, param_set->param_id, param_set->param_value, param_set->param_type); #else - mavlink_param_set_t packet; - packet.param_value = param_value; - packet.target_system = target_system; - packet.target_component = target_component; - packet.param_type = param_type; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, (const char *)&packet, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, (const char *)&packet, MAVLINK_MSG_ID_PARAM_SET_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, (const char *)param_set, MAVLINK_MSG_ID_PARAM_SET_MIN_LEN, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); #endif } @@ -195,29 +209,21 @@ static inline void mavlink_msg_param_set_send(mavlink_channel_t chan, uint8_t ta static inline void mavlink_msg_param_set_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, const char *param_id, float param_value, uint8_t param_type) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, param_value); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, target_component); - _mav_put_uint8_t(buf, 22, param_type); - _mav_put_char_array(buf, 6, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, buf, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, param_value); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, target_component); + _mav_put_uint8_t(buf, 22, param_type); + _mav_put_char_array(buf, 6, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, buf, MAVLINK_MSG_ID_PARAM_SET_MIN_LEN, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, buf, MAVLINK_MSG_ID_PARAM_SET_LEN); -#endif -#else - mavlink_param_set_t *packet = (mavlink_param_set_t *)msgbuf; - packet->param_value = param_value; - packet->target_system = target_system; - packet->target_component = target_component; - packet->param_type = param_type; - mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, (const char *)packet, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, (const char *)packet, MAVLINK_MSG_ID_PARAM_SET_LEN); -#endif + mavlink_param_set_t *packet = (mavlink_param_set_t *)msgbuf; + packet->param_value = param_value; + packet->target_system = target_system; + packet->target_component = target_component; + packet->param_type = param_type; + mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_SET, (const char *)packet, MAVLINK_MSG_ID_PARAM_SET_MIN_LEN, MAVLINK_MSG_ID_PARAM_SET_LEN, MAVLINK_MSG_ID_PARAM_SET_CRC); #endif } #endif @@ -234,7 +240,7 @@ static inline void mavlink_msg_param_set_send_buf(mavlink_message_t *msgbuf, mav */ static inline uint8_t mavlink_msg_param_set_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -244,7 +250,7 @@ static inline uint8_t mavlink_msg_param_set_get_target_system(const mavlink_mess */ static inline uint8_t mavlink_msg_param_set_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -254,7 +260,7 @@ static inline uint8_t mavlink_msg_param_set_get_target_component(const mavlink_m */ static inline uint16_t mavlink_msg_param_set_get_param_id(const mavlink_message_t* msg, char *param_id) { - return _MAV_RETURN_char_array(msg, param_id, 16, 6); + return _MAV_RETURN_char_array(msg, param_id, 16, 6); } /** @@ -264,7 +270,7 @@ static inline uint16_t mavlink_msg_param_set_get_param_id(const mavlink_message_ */ static inline float mavlink_msg_param_set_get_param_value(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -274,7 +280,7 @@ static inline float mavlink_msg_param_set_get_param_value(const mavlink_message_ */ static inline uint8_t mavlink_msg_param_set_get_param_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 22); + return _MAV_RETURN_uint8_t(msg, 22); } /** @@ -285,13 +291,15 @@ static inline uint8_t mavlink_msg_param_set_get_param_type(const mavlink_message */ static inline void mavlink_msg_param_set_decode(const mavlink_message_t* msg, mavlink_param_set_t* param_set) { -#if MAVLINK_NEED_BYTE_SWAP - param_set->param_value = mavlink_msg_param_set_get_param_value(msg); - param_set->target_system = mavlink_msg_param_set_get_target_system(msg); - param_set->target_component = mavlink_msg_param_set_get_target_component(msg); - mavlink_msg_param_set_get_param_id(msg, param_set->param_id); - param_set->param_type = mavlink_msg_param_set_get_param_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + param_set->param_value = mavlink_msg_param_set_get_param_value(msg); + param_set->target_system = mavlink_msg_param_set_get_target_system(msg); + param_set->target_component = mavlink_msg_param_set_get_target_component(msg); + mavlink_msg_param_set_get_param_id(msg, param_set->param_id); + param_set->param_type = mavlink_msg_param_set_get_param_type(msg); #else - memcpy(param_set, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_PARAM_SET_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_PARAM_SET_LEN? msg->len : MAVLINK_MSG_ID_PARAM_SET_LEN; + memset(param_set, 0, MAVLINK_MSG_ID_PARAM_SET_LEN); + memcpy(param_set, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_param_value.h b/vendor/libraries/mavlink/common/mavlink_msg_param_value.h index c27957913f..e2cb891d02 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_param_value.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_param_value.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE PARAM_VALUE PACKING #define MAVLINK_MSG_ID_PARAM_VALUE 22 -typedef struct __mavlink_param_value_t -{ - float param_value; ///< Onboard parameter value - uint16_t param_count; ///< Total number of onboard parameters - uint16_t param_index; ///< Index of this onboard parameter - char param_id[16]; ///< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string - uint8_t param_type; ///< Onboard parameter type: see the MAV_PARAM_TYPE enum for supported data types. -} mavlink_param_value_t; +MAVPACKED( +typedef struct __mavlink_param_value_t { + float param_value; /*< Onboard parameter value*/ + uint16_t param_count; /*< Total number of onboard parameters*/ + uint16_t param_index; /*< Index of this onboard parameter*/ + char param_id[16]; /*< Onboard parameter id, terminated by NULL if the length is less than 16 human-readable chars and WITHOUT null termination (NULL) byte if the length is exactly 16 chars - applications have to provide 16+1 bytes storage if the ID is stored as string*/ + uint8_t param_type; /*< Onboard parameter type: see the MAV_PARAM_TYPE enum for supported data types.*/ +}) mavlink_param_value_t; #define MAVLINK_MSG_ID_PARAM_VALUE_LEN 25 +#define MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN 25 #define MAVLINK_MSG_ID_22_LEN 25 +#define MAVLINK_MSG_ID_22_MIN_LEN 25 #define MAVLINK_MSG_ID_PARAM_VALUE_CRC 220 #define MAVLINK_MSG_ID_22_CRC 220 #define MAVLINK_MSG_PARAM_VALUE_FIELD_PARAM_ID_LEN 16 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_PARAM_VALUE { \ - "PARAM_VALUE", \ - 5, \ - { { "param_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_value_t, param_value) }, \ + 22, \ + "PARAM_VALUE", \ + 5, \ + { { "param_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_value_t, param_value) }, \ { "param_count", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_param_value_t, param_count) }, \ { "param_index", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_param_value_t, param_index) }, \ { "param_id", NULL, MAVLINK_TYPE_CHAR, 16, 8, offsetof(mavlink_param_value_t, param_id) }, \ { "param_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_param_value_t, param_type) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_PARAM_VALUE { \ + "PARAM_VALUE", \ + 5, \ + { { "param_value", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_param_value_t, param_value) }, \ + { "param_count", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_param_value_t, param_count) }, \ + { "param_index", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_param_value_t, param_index) }, \ + { "param_id", NULL, MAVLINK_TYPE_CHAR, 16, 8, offsetof(mavlink_param_value_t, param_id) }, \ + { "param_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_param_value_t, param_type) }, \ + } \ +} +#endif /** * @brief Pack a param_value message @@ -45,32 +61,28 @@ typedef struct __mavlink_param_value_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_value_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - const char *param_id, float param_value, uint8_t param_type, uint16_t param_count, uint16_t param_index) + const char *param_id, float param_value, uint8_t param_type, uint16_t param_count, uint16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_VALUE_LEN]; - _mav_put_float(buf, 0, param_value); - _mav_put_uint16_t(buf, 4, param_count); - _mav_put_uint16_t(buf, 6, param_index); - _mav_put_uint8_t(buf, 24, param_type); - _mav_put_char_array(buf, 8, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_VALUE_LEN]; + _mav_put_float(buf, 0, param_value); + _mav_put_uint16_t(buf, 4, param_count); + _mav_put_uint16_t(buf, 6, param_index); + _mav_put_uint8_t(buf, 24, param_type); + _mav_put_char_array(buf, 8, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_VALUE_LEN); #else - mavlink_param_value_t packet; - packet.param_value = param_value; - packet.param_count = param_count; - packet.param_index = param_index; - packet.param_type = param_type; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_value_t packet; + packet.param_value = param_value; + packet.param_count = param_count; + packet.param_index = param_index; + packet.param_type = param_type; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_VALUE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_VALUE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_VALUE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_VALUE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); } /** @@ -87,33 +99,29 @@ static inline uint16_t mavlink_msg_param_value_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_param_value_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - const char *param_id,float param_value,uint8_t param_type,uint16_t param_count,uint16_t param_index) + mavlink_message_t* msg, + const char *param_id,float param_value,uint8_t param_type,uint16_t param_count,uint16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_VALUE_LEN]; - _mav_put_float(buf, 0, param_value); - _mav_put_uint16_t(buf, 4, param_count); - _mav_put_uint16_t(buf, 6, param_index); - _mav_put_uint8_t(buf, 24, param_type); - _mav_put_char_array(buf, 8, param_id, 16); + char buf[MAVLINK_MSG_ID_PARAM_VALUE_LEN]; + _mav_put_float(buf, 0, param_value); + _mav_put_uint16_t(buf, 4, param_count); + _mav_put_uint16_t(buf, 6, param_index); + _mav_put_uint8_t(buf, 24, param_type); + _mav_put_char_array(buf, 8, param_id, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PARAM_VALUE_LEN); #else - mavlink_param_value_t packet; - packet.param_value = param_value; - packet.param_count = param_count; - packet.param_index = param_index; - packet.param_type = param_type; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + mavlink_param_value_t packet; + packet.param_value = param_value; + packet.param_count = param_count; + packet.param_index = param_index; + packet.param_type = param_type; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PARAM_VALUE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PARAM_VALUE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_VALUE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PARAM_VALUE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); } /** @@ -126,7 +134,7 @@ static inline uint16_t mavlink_msg_param_value_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_param_value_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_param_value_t* param_value) { - return mavlink_msg_param_value_pack(system_id, component_id, msg, param_value->param_id, param_value->param_value, param_value->param_type, param_value->param_count, param_value->param_index); + return mavlink_msg_param_value_pack(system_id, component_id, msg, param_value->param_id, param_value->param_value, param_value->param_type, param_value->param_count, param_value->param_index); } /** @@ -140,7 +148,7 @@ static inline uint16_t mavlink_msg_param_value_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_param_value_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_param_value_t* param_value) { - return mavlink_msg_param_value_pack_chan(system_id, component_id, chan, msg, param_value->param_id, param_value->param_value, param_value->param_type, param_value->param_count, param_value->param_index); + return mavlink_msg_param_value_pack_chan(system_id, component_id, chan, msg, param_value->param_id, param_value->param_value, param_value->param_type, param_value->param_count, param_value->param_index); } /** @@ -158,29 +166,35 @@ static inline uint16_t mavlink_msg_param_value_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_param_value_send(mavlink_channel_t chan, const char *param_id, float param_value, uint8_t param_type, uint16_t param_count, uint16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PARAM_VALUE_LEN]; - _mav_put_float(buf, 0, param_value); - _mav_put_uint16_t(buf, 4, param_count); - _mav_put_uint16_t(buf, 6, param_index); - _mav_put_uint8_t(buf, 24, param_type); - _mav_put_char_array(buf, 8, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, buf, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); + char buf[MAVLINK_MSG_ID_PARAM_VALUE_LEN]; + _mav_put_float(buf, 0, param_value); + _mav_put_uint16_t(buf, 4, param_count); + _mav_put_uint16_t(buf, 6, param_index); + _mav_put_uint8_t(buf, 24, param_type); + _mav_put_char_array(buf, 8, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, buf, MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, buf, MAVLINK_MSG_ID_PARAM_VALUE_LEN); + mavlink_param_value_t packet; + packet.param_value = param_value; + packet.param_count = param_count; + packet.param_index = param_index; + packet.param_type = param_type; + mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, (const char *)&packet, MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); #endif +} + +/** + * @brief Send a param_value message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_param_value_send_struct(mavlink_channel_t chan, const mavlink_param_value_t* param_value) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_param_value_send(chan, param_value->param_id, param_value->param_value, param_value->param_type, param_value->param_count, param_value->param_index); #else - mavlink_param_value_t packet; - packet.param_value = param_value; - packet.param_count = param_count; - packet.param_index = param_index; - packet.param_type = param_type; - mav_array_memcpy(packet.param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, (const char *)&packet, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, (const char *)&packet, MAVLINK_MSG_ID_PARAM_VALUE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, (const char *)param_value, MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); #endif } @@ -195,29 +209,21 @@ static inline void mavlink_msg_param_value_send(mavlink_channel_t chan, const ch static inline void mavlink_msg_param_value_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, const char *param_id, float param_value, uint8_t param_type, uint16_t param_count, uint16_t param_index) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, param_value); - _mav_put_uint16_t(buf, 4, param_count); - _mav_put_uint16_t(buf, 6, param_index); - _mav_put_uint8_t(buf, 24, param_type); - _mav_put_char_array(buf, 8, param_id, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, buf, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, param_value); + _mav_put_uint16_t(buf, 4, param_count); + _mav_put_uint16_t(buf, 6, param_index); + _mav_put_uint8_t(buf, 24, param_type); + _mav_put_char_array(buf, 8, param_id, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, buf, MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, buf, MAVLINK_MSG_ID_PARAM_VALUE_LEN); -#endif -#else - mavlink_param_value_t *packet = (mavlink_param_value_t *)msgbuf; - packet->param_value = param_value; - packet->param_count = param_count; - packet->param_index = param_index; - packet->param_type = param_type; - mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, (const char *)packet, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, (const char *)packet, MAVLINK_MSG_ID_PARAM_VALUE_LEN); -#endif + mavlink_param_value_t *packet = (mavlink_param_value_t *)msgbuf; + packet->param_value = param_value; + packet->param_count = param_count; + packet->param_index = param_index; + packet->param_type = param_type; + mav_array_memcpy(packet->param_id, param_id, sizeof(char)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PARAM_VALUE, (const char *)packet, MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN, MAVLINK_MSG_ID_PARAM_VALUE_LEN, MAVLINK_MSG_ID_PARAM_VALUE_CRC); #endif } #endif @@ -234,7 +240,7 @@ static inline void mavlink_msg_param_value_send_buf(mavlink_message_t *msgbuf, m */ static inline uint16_t mavlink_msg_param_value_get_param_id(const mavlink_message_t* msg, char *param_id) { - return _MAV_RETURN_char_array(msg, param_id, 16, 8); + return _MAV_RETURN_char_array(msg, param_id, 16, 8); } /** @@ -244,7 +250,7 @@ static inline uint16_t mavlink_msg_param_value_get_param_id(const mavlink_messag */ static inline float mavlink_msg_param_value_get_param_value(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -254,7 +260,7 @@ static inline float mavlink_msg_param_value_get_param_value(const mavlink_messag */ static inline uint8_t mavlink_msg_param_value_get_param_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 24); + return _MAV_RETURN_uint8_t(msg, 24); } /** @@ -264,7 +270,7 @@ static inline uint8_t mavlink_msg_param_value_get_param_type(const mavlink_messa */ static inline uint16_t mavlink_msg_param_value_get_param_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -274,7 +280,7 @@ static inline uint16_t mavlink_msg_param_value_get_param_count(const mavlink_mes */ static inline uint16_t mavlink_msg_param_value_get_param_index(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -285,13 +291,15 @@ static inline uint16_t mavlink_msg_param_value_get_param_index(const mavlink_mes */ static inline void mavlink_msg_param_value_decode(const mavlink_message_t* msg, mavlink_param_value_t* param_value) { -#if MAVLINK_NEED_BYTE_SWAP - param_value->param_value = mavlink_msg_param_value_get_param_value(msg); - param_value->param_count = mavlink_msg_param_value_get_param_count(msg); - param_value->param_index = mavlink_msg_param_value_get_param_index(msg); - mavlink_msg_param_value_get_param_id(msg, param_value->param_id); - param_value->param_type = mavlink_msg_param_value_get_param_type(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + param_value->param_value = mavlink_msg_param_value_get_param_value(msg); + param_value->param_count = mavlink_msg_param_value_get_param_count(msg); + param_value->param_index = mavlink_msg_param_value_get_param_index(msg); + mavlink_msg_param_value_get_param_id(msg, param_value->param_id); + param_value->param_type = mavlink_msg_param_value_get_param_type(msg); #else - memcpy(param_value, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_PARAM_VALUE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_PARAM_VALUE_LEN? msg->len : MAVLINK_MSG_ID_PARAM_VALUE_LEN; + memset(param_value, 0, MAVLINK_MSG_ID_PARAM_VALUE_LEN); + memcpy(param_value, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_ping.h b/vendor/libraries/mavlink/common/mavlink_msg_ping.h index 6564ed0a65..1e18bc6726 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_ping.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_ping.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE PING PACKING #define MAVLINK_MSG_ID_PING 4 -typedef struct __mavlink_ping_t -{ - uint64_t time_usec; ///< Unix timestamp in microseconds or since system boot if smaller than MAVLink epoch (1.1.2009) - uint32_t seq; ///< PING sequence - uint8_t target_system; ///< 0: request ping from all receiving systems, if greater than 0: message is a ping response and number is the system id of the requesting system - uint8_t target_component; ///< 0: request ping from all receiving components, if greater than 0: message is a ping response and number is the system id of the requesting system -} mavlink_ping_t; +MAVPACKED( +typedef struct __mavlink_ping_t { + uint64_t time_usec; /*< Unix timestamp in microseconds or since system boot if smaller than MAVLink epoch (1.1.2009)*/ + uint32_t seq; /*< PING sequence*/ + uint8_t target_system; /*< 0: request ping from all receiving systems, if greater than 0: message is a ping response and number is the system id of the requesting system*/ + uint8_t target_component; /*< 0: request ping from all receiving components, if greater than 0: message is a ping response and number is the system id of the requesting system*/ +}) mavlink_ping_t; #define MAVLINK_MSG_ID_PING_LEN 14 +#define MAVLINK_MSG_ID_PING_MIN_LEN 14 #define MAVLINK_MSG_ID_4_LEN 14 +#define MAVLINK_MSG_ID_4_MIN_LEN 14 #define MAVLINK_MSG_ID_PING_CRC 237 #define MAVLINK_MSG_ID_4_CRC 237 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_PING { \ - "PING", \ - 4, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_ping_t, time_usec) }, \ + 4, \ + "PING", \ + 4, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_ping_t, time_usec) }, \ { "seq", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_ping_t, seq) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_ping_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_ping_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_PING { \ + "PING", \ + 4, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_ping_t, time_usec) }, \ + { "seq", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_ping_t, seq) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_ping_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 13, offsetof(mavlink_ping_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a ping message @@ -42,32 +57,28 @@ typedef struct __mavlink_ping_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ping_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint32_t seq, uint8_t target_system, uint8_t target_component) + uint64_t time_usec, uint32_t seq, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PING_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, seq); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); + char buf[MAVLINK_MSG_ID_PING_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PING_LEN); #else - mavlink_ping_t packet; - packet.time_usec = time_usec; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_ping_t packet; + packet.time_usec = time_usec; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PING_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PING; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PING_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PING; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_PING_MIN_LEN, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_ping_pack(uint8_t system_id, uint8_t componen * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_ping_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint32_t seq,uint8_t target_system,uint8_t target_component) + mavlink_message_t* msg, + uint64_t time_usec,uint32_t seq,uint8_t target_system,uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PING_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, seq); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); + char buf[MAVLINK_MSG_ID_PING_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_PING_LEN); #else - mavlink_ping_t packet; - packet.time_usec = time_usec; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_ping_t packet; + packet.time_usec = time_usec; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_PING_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_PING; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PING_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_PING; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_PING_MIN_LEN, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_ping_pack_chan(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_ping_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_ping_t* ping) { - return mavlink_msg_ping_pack(system_id, component_id, msg, ping->time_usec, ping->seq, ping->target_system, ping->target_component); + return mavlink_msg_ping_pack(system_id, component_id, msg, ping->time_usec, ping->seq, ping->target_system, ping->target_component); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_ping_encode(uint8_t system_id, uint8_t compon */ static inline uint16_t mavlink_msg_ping_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_ping_t* ping) { - return mavlink_msg_ping_pack_chan(system_id, component_id, chan, msg, ping->time_usec, ping->seq, ping->target_system, ping->target_component); + return mavlink_msg_ping_pack_chan(system_id, component_id, chan, msg, ping->time_usec, ping->seq, ping->target_system, ping->target_component); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_ping_encode_chan(uint8_t system_id, uint8_t c static inline void mavlink_msg_ping_send(mavlink_channel_t chan, uint64_t time_usec, uint32_t seq, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_PING_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, seq); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, buf, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); + char buf[MAVLINK_MSG_ID_PING_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, buf, MAVLINK_MSG_ID_PING_MIN_LEN, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, buf, MAVLINK_MSG_ID_PING_LEN); + mavlink_ping_t packet; + packet.time_usec = time_usec; + packet.seq = seq; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, (const char *)&packet, MAVLINK_MSG_ID_PING_MIN_LEN, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); #endif +} + +/** + * @brief Send a ping message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_ping_send_struct(mavlink_channel_t chan, const mavlink_ping_t* ping) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_ping_send(chan, ping->time_usec, ping->seq, ping->target_system, ping->target_component); #else - mavlink_ping_t packet; - packet.time_usec = time_usec; - packet.seq = seq; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, (const char *)&packet, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, (const char *)&packet, MAVLINK_MSG_ID_PING_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, (const char *)ping, MAVLINK_MSG_ID_PING_MIN_LEN, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_ping_send(mavlink_channel_t chan, uint64_t time_u static inline void mavlink_msg_ping_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint32_t seq, uint8_t target_system, uint8_t target_component) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint32_t(buf, 8, seq); - _mav_put_uint8_t(buf, 12, target_system); - _mav_put_uint8_t(buf, 13, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, buf, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, buf, MAVLINK_MSG_ID_PING_LEN); -#endif -#else - mavlink_ping_t *packet = (mavlink_ping_t *)msgbuf; - packet->time_usec = time_usec; - packet->seq = seq; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, (const char *)packet, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint32_t(buf, 8, seq); + _mav_put_uint8_t(buf, 12, target_system); + _mav_put_uint8_t(buf, 13, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, buf, MAVLINK_MSG_ID_PING_MIN_LEN, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, (const char *)packet, MAVLINK_MSG_ID_PING_LEN); -#endif + mavlink_ping_t *packet = (mavlink_ping_t *)msgbuf; + packet->time_usec = time_usec; + packet->seq = seq; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_PING, (const char *)packet, MAVLINK_MSG_ID_PING_MIN_LEN, MAVLINK_MSG_ID_PING_LEN, MAVLINK_MSG_ID_PING_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_ping_send_buf(mavlink_message_t *msgbuf, mavlink_ */ static inline uint64_t mavlink_msg_ping_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -239,7 +244,7 @@ static inline uint64_t mavlink_msg_ping_get_time_usec(const mavlink_message_t* m */ static inline uint32_t mavlink_msg_ping_get_seq(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 8); + return _MAV_RETURN_uint32_t(msg, 8); } /** @@ -249,7 +254,7 @@ static inline uint32_t mavlink_msg_ping_get_seq(const mavlink_message_t* msg) */ static inline uint8_t mavlink_msg_ping_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -259,7 +264,7 @@ static inline uint8_t mavlink_msg_ping_get_target_system(const mavlink_message_t */ static inline uint8_t mavlink_msg_ping_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 13); + return _MAV_RETURN_uint8_t(msg, 13); } /** @@ -270,12 +275,14 @@ static inline uint8_t mavlink_msg_ping_get_target_component(const mavlink_messag */ static inline void mavlink_msg_ping_decode(const mavlink_message_t* msg, mavlink_ping_t* ping) { -#if MAVLINK_NEED_BYTE_SWAP - ping->time_usec = mavlink_msg_ping_get_time_usec(msg); - ping->seq = mavlink_msg_ping_get_seq(msg); - ping->target_system = mavlink_msg_ping_get_target_system(msg); - ping->target_component = mavlink_msg_ping_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + ping->time_usec = mavlink_msg_ping_get_time_usec(msg); + ping->seq = mavlink_msg_ping_get_seq(msg); + ping->target_system = mavlink_msg_ping_get_target_system(msg); + ping->target_component = mavlink_msg_ping_get_target_component(msg); #else - memcpy(ping, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_PING_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_PING_LEN? msg->len : MAVLINK_MSG_ID_PING_LEN; + memset(ping, 0, MAVLINK_MSG_ID_PING_LEN); + memcpy(ping, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_position_target_global_int.h b/vendor/libraries/mavlink/common/mavlink_msg_position_target_global_int.h index b9601467a4..160a5fa4f0 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_position_target_global_int.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_position_target_global_int.h @@ -1,37 +1,42 @@ +#pragma once // MESSAGE POSITION_TARGET_GLOBAL_INT PACKING #define MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT 87 -typedef struct __mavlink_position_target_global_int_t -{ - uint32_t time_boot_ms; ///< Timestamp in milliseconds since system boot. The rationale for the timestamp in the setpoint is to allow the system to compensate for the transport delay of the setpoint. This allows the system to compensate processing latency. - int32_t lat_int; ///< X Position in WGS84 frame in 1e7 * meters - int32_t lon_int; ///< Y Position in WGS84 frame in 1e7 * meters - float alt; ///< Altitude in meters in AMSL altitude, not WGS84 if absolute or relative, above terrain if GLOBAL_TERRAIN_ALT_INT - float vx; ///< X velocity in NED frame in meter / s - float vy; ///< Y velocity in NED frame in meter / s - float vz; ///< Z velocity in NED frame in meter / s - float afx; ///< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afy; ///< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afz; ///< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float yaw; ///< yaw setpoint in rad - float yaw_rate; ///< yaw rate setpoint in rad/s - uint16_t type_mask; ///< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate - uint8_t coordinate_frame; ///< Valid options are: MAV_FRAME_GLOBAL_INT = 5, MAV_FRAME_GLOBAL_RELATIVE_ALT_INT = 6, MAV_FRAME_GLOBAL_TERRAIN_ALT_INT = 11 -} mavlink_position_target_global_int_t; +MAVPACKED( +typedef struct __mavlink_position_target_global_int_t { + uint32_t time_boot_ms; /*< Timestamp in milliseconds since system boot. The rationale for the timestamp in the setpoint is to allow the system to compensate for the transport delay of the setpoint. This allows the system to compensate processing latency.*/ + int32_t lat_int; /*< X Position in WGS84 frame in 1e7 * meters*/ + int32_t lon_int; /*< Y Position in WGS84 frame in 1e7 * meters*/ + float alt; /*< Altitude in meters in AMSL altitude, not WGS84 if absolute or relative, above terrain if GLOBAL_TERRAIN_ALT_INT*/ + float vx; /*< X velocity in NED frame in meter / s*/ + float vy; /*< Y velocity in NED frame in meter / s*/ + float vz; /*< Z velocity in NED frame in meter / s*/ + float afx; /*< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afy; /*< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afz; /*< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float yaw; /*< yaw setpoint in rad*/ + float yaw_rate; /*< yaw rate setpoint in rad/s*/ + uint16_t type_mask; /*< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate*/ + uint8_t coordinate_frame; /*< Valid options are: MAV_FRAME_GLOBAL_INT = 5, MAV_FRAME_GLOBAL_RELATIVE_ALT_INT = 6, MAV_FRAME_GLOBAL_TERRAIN_ALT_INT = 11*/ +}) mavlink_position_target_global_int_t; #define MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN 51 +#define MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN 51 #define MAVLINK_MSG_ID_87_LEN 51 +#define MAVLINK_MSG_ID_87_MIN_LEN 51 #define MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC 150 #define MAVLINK_MSG_ID_87_CRC 150 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_POSITION_TARGET_GLOBAL_INT { \ - "POSITION_TARGET_GLOBAL_INT", \ - 14, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_position_target_global_int_t, time_boot_ms) }, \ + 87, \ + "POSITION_TARGET_GLOBAL_INT", \ + 14, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_position_target_global_int_t, time_boot_ms) }, \ { "lat_int", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_position_target_global_int_t, lat_int) }, \ { "lon_int", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_position_target_global_int_t, lon_int) }, \ { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_position_target_global_int_t, alt) }, \ @@ -47,7 +52,27 @@ typedef struct __mavlink_position_target_global_int_t { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 50, offsetof(mavlink_position_target_global_int_t, coordinate_frame) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_POSITION_TARGET_GLOBAL_INT { \ + "POSITION_TARGET_GLOBAL_INT", \ + 14, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_position_target_global_int_t, time_boot_ms) }, \ + { "lat_int", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_position_target_global_int_t, lat_int) }, \ + { "lon_int", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_position_target_global_int_t, lon_int) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_position_target_global_int_t, alt) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_position_target_global_int_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_position_target_global_int_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_position_target_global_int_t, vz) }, \ + { "afx", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_position_target_global_int_t, afx) }, \ + { "afy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_position_target_global_int_t, afy) }, \ + { "afz", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_position_target_global_int_t, afz) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_position_target_global_int_t, yaw) }, \ + { "yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_position_target_global_int_t, yaw_rate) }, \ + { "type_mask", NULL, MAVLINK_TYPE_UINT16_T, 0, 48, offsetof(mavlink_position_target_global_int_t, type_mask) }, \ + { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 50, offsetof(mavlink_position_target_global_int_t, coordinate_frame) }, \ + } \ +} +#endif /** * @brief Pack a position_target_global_int message @@ -72,52 +97,48 @@ typedef struct __mavlink_position_target_global_int_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_position_target_global_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) + uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); + char buf[MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); #else - mavlink_position_target_global_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat_int = lat_int; - packet.lon_int = lon_int; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.coordinate_frame = coordinate_frame; + mavlink_position_target_global_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat_int = lat_int; + packet.lon_int = lon_int; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); } /** @@ -143,53 +164,49 @@ static inline uint16_t mavlink_msg_position_target_global_int_pack(uint8_t syste * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_position_target_global_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t coordinate_frame,uint16_t type_mask,int32_t lat_int,int32_t lon_int,float alt,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t coordinate_frame,uint16_t type_mask,int32_t lat_int,int32_t lon_int,float alt,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); + char buf[MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); #else - mavlink_position_target_global_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat_int = lat_int; - packet.lon_int = lon_int; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.coordinate_frame = coordinate_frame; + mavlink_position_target_global_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat_int = lat_int; + packet.lon_int = lon_int; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); } /** @@ -202,7 +219,7 @@ static inline uint16_t mavlink_msg_position_target_global_int_pack_chan(uint8_t */ static inline uint16_t mavlink_msg_position_target_global_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_position_target_global_int_t* position_target_global_int) { - return mavlink_msg_position_target_global_int_pack(system_id, component_id, msg, position_target_global_int->time_boot_ms, position_target_global_int->coordinate_frame, position_target_global_int->type_mask, position_target_global_int->lat_int, position_target_global_int->lon_int, position_target_global_int->alt, position_target_global_int->vx, position_target_global_int->vy, position_target_global_int->vz, position_target_global_int->afx, position_target_global_int->afy, position_target_global_int->afz, position_target_global_int->yaw, position_target_global_int->yaw_rate); + return mavlink_msg_position_target_global_int_pack(system_id, component_id, msg, position_target_global_int->time_boot_ms, position_target_global_int->coordinate_frame, position_target_global_int->type_mask, position_target_global_int->lat_int, position_target_global_int->lon_int, position_target_global_int->alt, position_target_global_int->vx, position_target_global_int->vy, position_target_global_int->vz, position_target_global_int->afx, position_target_global_int->afy, position_target_global_int->afz, position_target_global_int->yaw, position_target_global_int->yaw_rate); } /** @@ -216,7 +233,7 @@ static inline uint16_t mavlink_msg_position_target_global_int_encode(uint8_t sys */ static inline uint16_t mavlink_msg_position_target_global_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_position_target_global_int_t* position_target_global_int) { - return mavlink_msg_position_target_global_int_pack_chan(system_id, component_id, chan, msg, position_target_global_int->time_boot_ms, position_target_global_int->coordinate_frame, position_target_global_int->type_mask, position_target_global_int->lat_int, position_target_global_int->lon_int, position_target_global_int->alt, position_target_global_int->vx, position_target_global_int->vy, position_target_global_int->vz, position_target_global_int->afx, position_target_global_int->afy, position_target_global_int->afz, position_target_global_int->yaw, position_target_global_int->yaw_rate); + return mavlink_msg_position_target_global_int_pack_chan(system_id, component_id, chan, msg, position_target_global_int->time_boot_ms, position_target_global_int->coordinate_frame, position_target_global_int->type_mask, position_target_global_int->lat_int, position_target_global_int->lon_int, position_target_global_int->alt, position_target_global_int->vx, position_target_global_int->vy, position_target_global_int->vz, position_target_global_int->afx, position_target_global_int->afy, position_target_global_int->afz, position_target_global_int->yaw, position_target_global_int->yaw_rate); } /** @@ -243,49 +260,55 @@ static inline uint16_t mavlink_msg_position_target_global_int_encode_chan(uint8_ static inline void mavlink_msg_position_target_global_int_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); + char buf[MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); + mavlink_position_target_global_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat_int = lat_int; + packet.lon_int = lon_int; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, (const char *)&packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); #endif +} + +/** + * @brief Send a position_target_global_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_position_target_global_int_send_struct(mavlink_channel_t chan, const mavlink_position_target_global_int_t* position_target_global_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_position_target_global_int_send(chan, position_target_global_int->time_boot_ms, position_target_global_int->coordinate_frame, position_target_global_int->type_mask, position_target_global_int->lat_int, position_target_global_int->lon_int, position_target_global_int->alt, position_target_global_int->vx, position_target_global_int->vy, position_target_global_int->vz, position_target_global_int->afx, position_target_global_int->afy, position_target_global_int->afz, position_target_global_int->yaw, position_target_global_int->yaw_rate); #else - mavlink_position_target_global_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat_int = lat_int; - packet.lon_int = lon_int; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, (const char *)&packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, (const char *)&packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, (const char *)position_target_global_int, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); #endif } @@ -300,49 +323,41 @@ static inline void mavlink_msg_position_target_global_int_send(mavlink_channel_t static inline void mavlink_msg_position_target_global_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); -#endif -#else - mavlink_position_target_global_int_t *packet = (mavlink_position_target_global_int_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->lat_int = lat_int; - packet->lon_int = lon_int; - packet->alt = alt; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->afx = afx; - packet->afy = afy; - packet->afz = afz; - packet->yaw = yaw; - packet->yaw_rate = yaw_rate; - packet->type_mask = type_mask; - packet->coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, (const char *)packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, (const char *)packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + mavlink_position_target_global_int_t *packet = (mavlink_position_target_global_int_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->lat_int = lat_int; + packet->lon_int = lon_int; + packet->alt = alt; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->afx = afx; + packet->afy = afy; + packet->afz = afz; + packet->yaw = yaw; + packet->yaw_rate = yaw_rate; + packet->type_mask = type_mask; + packet->coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT, (const char *)packet, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_CRC); #endif } #endif @@ -359,7 +374,7 @@ static inline void mavlink_msg_position_target_global_int_send_buf(mavlink_messa */ static inline uint32_t mavlink_msg_position_target_global_int_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -369,7 +384,7 @@ static inline uint32_t mavlink_msg_position_target_global_int_get_time_boot_ms(c */ static inline uint8_t mavlink_msg_position_target_global_int_get_coordinate_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 50); + return _MAV_RETURN_uint8_t(msg, 50); } /** @@ -379,7 +394,7 @@ static inline uint8_t mavlink_msg_position_target_global_int_get_coordinate_fram */ static inline uint16_t mavlink_msg_position_target_global_int_get_type_mask(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 48); + return _MAV_RETURN_uint16_t(msg, 48); } /** @@ -389,7 +404,7 @@ static inline uint16_t mavlink_msg_position_target_global_int_get_type_mask(cons */ static inline int32_t mavlink_msg_position_target_global_int_get_lat_int(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -399,7 +414,7 @@ static inline int32_t mavlink_msg_position_target_global_int_get_lat_int(const m */ static inline int32_t mavlink_msg_position_target_global_int_get_lon_int(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -409,7 +424,7 @@ static inline int32_t mavlink_msg_position_target_global_int_get_lon_int(const m */ static inline float mavlink_msg_position_target_global_int_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -419,7 +434,7 @@ static inline float mavlink_msg_position_target_global_int_get_alt(const mavlink */ static inline float mavlink_msg_position_target_global_int_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -429,7 +444,7 @@ static inline float mavlink_msg_position_target_global_int_get_vx(const mavlink_ */ static inline float mavlink_msg_position_target_global_int_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -439,7 +454,7 @@ static inline float mavlink_msg_position_target_global_int_get_vy(const mavlink_ */ static inline float mavlink_msg_position_target_global_int_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -449,7 +464,7 @@ static inline float mavlink_msg_position_target_global_int_get_vz(const mavlink_ */ static inline float mavlink_msg_position_target_global_int_get_afx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -459,7 +474,7 @@ static inline float mavlink_msg_position_target_global_int_get_afx(const mavlink */ static inline float mavlink_msg_position_target_global_int_get_afy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -469,7 +484,7 @@ static inline float mavlink_msg_position_target_global_int_get_afy(const mavlink */ static inline float mavlink_msg_position_target_global_int_get_afz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -479,7 +494,7 @@ static inline float mavlink_msg_position_target_global_int_get_afz(const mavlink */ static inline float mavlink_msg_position_target_global_int_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -489,7 +504,7 @@ static inline float mavlink_msg_position_target_global_int_get_yaw(const mavlink */ static inline float mavlink_msg_position_target_global_int_get_yaw_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -500,22 +515,24 @@ static inline float mavlink_msg_position_target_global_int_get_yaw_rate(const ma */ static inline void mavlink_msg_position_target_global_int_decode(const mavlink_message_t* msg, mavlink_position_target_global_int_t* position_target_global_int) { -#if MAVLINK_NEED_BYTE_SWAP - position_target_global_int->time_boot_ms = mavlink_msg_position_target_global_int_get_time_boot_ms(msg); - position_target_global_int->lat_int = mavlink_msg_position_target_global_int_get_lat_int(msg); - position_target_global_int->lon_int = mavlink_msg_position_target_global_int_get_lon_int(msg); - position_target_global_int->alt = mavlink_msg_position_target_global_int_get_alt(msg); - position_target_global_int->vx = mavlink_msg_position_target_global_int_get_vx(msg); - position_target_global_int->vy = mavlink_msg_position_target_global_int_get_vy(msg); - position_target_global_int->vz = mavlink_msg_position_target_global_int_get_vz(msg); - position_target_global_int->afx = mavlink_msg_position_target_global_int_get_afx(msg); - position_target_global_int->afy = mavlink_msg_position_target_global_int_get_afy(msg); - position_target_global_int->afz = mavlink_msg_position_target_global_int_get_afz(msg); - position_target_global_int->yaw = mavlink_msg_position_target_global_int_get_yaw(msg); - position_target_global_int->yaw_rate = mavlink_msg_position_target_global_int_get_yaw_rate(msg); - position_target_global_int->type_mask = mavlink_msg_position_target_global_int_get_type_mask(msg); - position_target_global_int->coordinate_frame = mavlink_msg_position_target_global_int_get_coordinate_frame(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + position_target_global_int->time_boot_ms = mavlink_msg_position_target_global_int_get_time_boot_ms(msg); + position_target_global_int->lat_int = mavlink_msg_position_target_global_int_get_lat_int(msg); + position_target_global_int->lon_int = mavlink_msg_position_target_global_int_get_lon_int(msg); + position_target_global_int->alt = mavlink_msg_position_target_global_int_get_alt(msg); + position_target_global_int->vx = mavlink_msg_position_target_global_int_get_vx(msg); + position_target_global_int->vy = mavlink_msg_position_target_global_int_get_vy(msg); + position_target_global_int->vz = mavlink_msg_position_target_global_int_get_vz(msg); + position_target_global_int->afx = mavlink_msg_position_target_global_int_get_afx(msg); + position_target_global_int->afy = mavlink_msg_position_target_global_int_get_afy(msg); + position_target_global_int->afz = mavlink_msg_position_target_global_int_get_afz(msg); + position_target_global_int->yaw = mavlink_msg_position_target_global_int_get_yaw(msg); + position_target_global_int->yaw_rate = mavlink_msg_position_target_global_int_get_yaw_rate(msg); + position_target_global_int->type_mask = mavlink_msg_position_target_global_int_get_type_mask(msg); + position_target_global_int->coordinate_frame = mavlink_msg_position_target_global_int_get_coordinate_frame(msg); #else - memcpy(position_target_global_int, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN? msg->len : MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN; + memset(position_target_global_int, 0, MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_LEN); + memcpy(position_target_global_int, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_position_target_local_ned.h b/vendor/libraries/mavlink/common/mavlink_msg_position_target_local_ned.h index d23d445b7b..3464e9aad8 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_position_target_local_ned.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_position_target_local_ned.h @@ -1,37 +1,42 @@ +#pragma once // MESSAGE POSITION_TARGET_LOCAL_NED PACKING #define MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED 85 -typedef struct __mavlink_position_target_local_ned_t -{ - uint32_t time_boot_ms; ///< Timestamp in milliseconds since system boot - float x; ///< X Position in NED frame in meters - float y; ///< Y Position in NED frame in meters - float z; ///< Z Position in NED frame in meters (note, altitude is negative in NED) - float vx; ///< X velocity in NED frame in meter / s - float vy; ///< Y velocity in NED frame in meter / s - float vz; ///< Z velocity in NED frame in meter / s - float afx; ///< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afy; ///< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afz; ///< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float yaw; ///< yaw setpoint in rad - float yaw_rate; ///< yaw rate setpoint in rad/s - uint16_t type_mask; ///< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate - uint8_t coordinate_frame; ///< Valid options are: MAV_FRAME_LOCAL_NED = 1, MAV_FRAME_LOCAL_OFFSET_NED = 7, MAV_FRAME_BODY_NED = 8, MAV_FRAME_BODY_OFFSET_NED = 9 -} mavlink_position_target_local_ned_t; +MAVPACKED( +typedef struct __mavlink_position_target_local_ned_t { + uint32_t time_boot_ms; /*< Timestamp in milliseconds since system boot*/ + float x; /*< X Position in NED frame in meters*/ + float y; /*< Y Position in NED frame in meters*/ + float z; /*< Z Position in NED frame in meters (note, altitude is negative in NED)*/ + float vx; /*< X velocity in NED frame in meter / s*/ + float vy; /*< Y velocity in NED frame in meter / s*/ + float vz; /*< Z velocity in NED frame in meter / s*/ + float afx; /*< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afy; /*< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afz; /*< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float yaw; /*< yaw setpoint in rad*/ + float yaw_rate; /*< yaw rate setpoint in rad/s*/ + uint16_t type_mask; /*< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate*/ + uint8_t coordinate_frame; /*< Valid options are: MAV_FRAME_LOCAL_NED = 1, MAV_FRAME_LOCAL_OFFSET_NED = 7, MAV_FRAME_BODY_NED = 8, MAV_FRAME_BODY_OFFSET_NED = 9*/ +}) mavlink_position_target_local_ned_t; #define MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN 51 +#define MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN 51 #define MAVLINK_MSG_ID_85_LEN 51 +#define MAVLINK_MSG_ID_85_MIN_LEN 51 #define MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC 140 #define MAVLINK_MSG_ID_85_CRC 140 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_POSITION_TARGET_LOCAL_NED { \ - "POSITION_TARGET_LOCAL_NED", \ - 14, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_position_target_local_ned_t, time_boot_ms) }, \ + 85, \ + "POSITION_TARGET_LOCAL_NED", \ + 14, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_position_target_local_ned_t, time_boot_ms) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_position_target_local_ned_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_position_target_local_ned_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_position_target_local_ned_t, z) }, \ @@ -47,7 +52,27 @@ typedef struct __mavlink_position_target_local_ned_t { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 50, offsetof(mavlink_position_target_local_ned_t, coordinate_frame) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_POSITION_TARGET_LOCAL_NED { \ + "POSITION_TARGET_LOCAL_NED", \ + 14, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_position_target_local_ned_t, time_boot_ms) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_position_target_local_ned_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_position_target_local_ned_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_position_target_local_ned_t, z) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_position_target_local_ned_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_position_target_local_ned_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_position_target_local_ned_t, vz) }, \ + { "afx", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_position_target_local_ned_t, afx) }, \ + { "afy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_position_target_local_ned_t, afy) }, \ + { "afz", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_position_target_local_ned_t, afz) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_position_target_local_ned_t, yaw) }, \ + { "yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_position_target_local_ned_t, yaw_rate) }, \ + { "type_mask", NULL, MAVLINK_TYPE_UINT16_T, 0, 48, offsetof(mavlink_position_target_local_ned_t, type_mask) }, \ + { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 50, offsetof(mavlink_position_target_local_ned_t, coordinate_frame) }, \ + } \ +} +#endif /** * @brief Pack a position_target_local_ned message @@ -72,52 +97,48 @@ typedef struct __mavlink_position_target_local_ned_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_position_target_local_ned_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) + uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); + char buf[MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); #else - mavlink_position_target_local_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.coordinate_frame = coordinate_frame; + mavlink_position_target_local_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); } /** @@ -143,53 +164,49 @@ static inline uint16_t mavlink_msg_position_target_local_ned_pack(uint8_t system * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_position_target_local_ned_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t coordinate_frame,uint16_t type_mask,float x,float y,float z,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t coordinate_frame,uint16_t type_mask,float x,float y,float z,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); + char buf[MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); #else - mavlink_position_target_local_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.coordinate_frame = coordinate_frame; + mavlink_position_target_local_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); } /** @@ -202,7 +219,7 @@ static inline uint16_t mavlink_msg_position_target_local_ned_pack_chan(uint8_t s */ static inline uint16_t mavlink_msg_position_target_local_ned_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_position_target_local_ned_t* position_target_local_ned) { - return mavlink_msg_position_target_local_ned_pack(system_id, component_id, msg, position_target_local_ned->time_boot_ms, position_target_local_ned->coordinate_frame, position_target_local_ned->type_mask, position_target_local_ned->x, position_target_local_ned->y, position_target_local_ned->z, position_target_local_ned->vx, position_target_local_ned->vy, position_target_local_ned->vz, position_target_local_ned->afx, position_target_local_ned->afy, position_target_local_ned->afz, position_target_local_ned->yaw, position_target_local_ned->yaw_rate); + return mavlink_msg_position_target_local_ned_pack(system_id, component_id, msg, position_target_local_ned->time_boot_ms, position_target_local_ned->coordinate_frame, position_target_local_ned->type_mask, position_target_local_ned->x, position_target_local_ned->y, position_target_local_ned->z, position_target_local_ned->vx, position_target_local_ned->vy, position_target_local_ned->vz, position_target_local_ned->afx, position_target_local_ned->afy, position_target_local_ned->afz, position_target_local_ned->yaw, position_target_local_ned->yaw_rate); } /** @@ -216,7 +233,7 @@ static inline uint16_t mavlink_msg_position_target_local_ned_encode(uint8_t syst */ static inline uint16_t mavlink_msg_position_target_local_ned_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_position_target_local_ned_t* position_target_local_ned) { - return mavlink_msg_position_target_local_ned_pack_chan(system_id, component_id, chan, msg, position_target_local_ned->time_boot_ms, position_target_local_ned->coordinate_frame, position_target_local_ned->type_mask, position_target_local_ned->x, position_target_local_ned->y, position_target_local_ned->z, position_target_local_ned->vx, position_target_local_ned->vy, position_target_local_ned->vz, position_target_local_ned->afx, position_target_local_ned->afy, position_target_local_ned->afz, position_target_local_ned->yaw, position_target_local_ned->yaw_rate); + return mavlink_msg_position_target_local_ned_pack_chan(system_id, component_id, chan, msg, position_target_local_ned->time_boot_ms, position_target_local_ned->coordinate_frame, position_target_local_ned->type_mask, position_target_local_ned->x, position_target_local_ned->y, position_target_local_ned->z, position_target_local_ned->vx, position_target_local_ned->vy, position_target_local_ned->vz, position_target_local_ned->afx, position_target_local_ned->afy, position_target_local_ned->afz, position_target_local_ned->yaw, position_target_local_ned->yaw_rate); } /** @@ -243,49 +260,55 @@ static inline uint16_t mavlink_msg_position_target_local_ned_encode_chan(uint8_t static inline void mavlink_msg_position_target_local_ned_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); + char buf[MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); + mavlink_position_target_local_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, (const char *)&packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); #endif +} + +/** + * @brief Send a position_target_local_ned message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_position_target_local_ned_send_struct(mavlink_channel_t chan, const mavlink_position_target_local_ned_t* position_target_local_ned) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_position_target_local_ned_send(chan, position_target_local_ned->time_boot_ms, position_target_local_ned->coordinate_frame, position_target_local_ned->type_mask, position_target_local_ned->x, position_target_local_ned->y, position_target_local_ned->z, position_target_local_ned->vx, position_target_local_ned->vy, position_target_local_ned->vz, position_target_local_ned->afx, position_target_local_ned->afy, position_target_local_ned->afz, position_target_local_ned->yaw, position_target_local_ned->yaw_rate); #else - mavlink_position_target_local_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, (const char *)&packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, (const char *)&packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, (const char *)position_target_local_ned, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); #endif } @@ -300,49 +323,41 @@ static inline void mavlink_msg_position_target_local_ned_send(mavlink_channel_t static inline void mavlink_msg_position_target_local_ned_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); -#endif -#else - mavlink_position_target_local_ned_t *packet = (mavlink_position_target_local_ned_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->x = x; - packet->y = y; - packet->z = z; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->afx = afx; - packet->afy = afy; - packet->afz = afz; - packet->yaw = yaw; - packet->yaw_rate = yaw_rate; - packet->type_mask = type_mask; - packet->coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, (const char *)packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, (const char *)packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); -#endif + mavlink_position_target_local_ned_t *packet = (mavlink_position_target_local_ned_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->x = x; + packet->y = y; + packet->z = z; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->afx = afx; + packet->afy = afy; + packet->afz = afz; + packet->yaw = yaw; + packet->yaw_rate = yaw_rate; + packet->type_mask = type_mask; + packet->coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED, (const char *)packet, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_CRC); #endif } #endif @@ -359,7 +374,7 @@ static inline void mavlink_msg_position_target_local_ned_send_buf(mavlink_messag */ static inline uint32_t mavlink_msg_position_target_local_ned_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -369,7 +384,7 @@ static inline uint32_t mavlink_msg_position_target_local_ned_get_time_boot_ms(co */ static inline uint8_t mavlink_msg_position_target_local_ned_get_coordinate_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 50); + return _MAV_RETURN_uint8_t(msg, 50); } /** @@ -379,7 +394,7 @@ static inline uint8_t mavlink_msg_position_target_local_ned_get_coordinate_frame */ static inline uint16_t mavlink_msg_position_target_local_ned_get_type_mask(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 48); + return _MAV_RETURN_uint16_t(msg, 48); } /** @@ -389,7 +404,7 @@ static inline uint16_t mavlink_msg_position_target_local_ned_get_type_mask(const */ static inline float mavlink_msg_position_target_local_ned_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -399,7 +414,7 @@ static inline float mavlink_msg_position_target_local_ned_get_x(const mavlink_me */ static inline float mavlink_msg_position_target_local_ned_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -409,7 +424,7 @@ static inline float mavlink_msg_position_target_local_ned_get_y(const mavlink_me */ static inline float mavlink_msg_position_target_local_ned_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -419,7 +434,7 @@ static inline float mavlink_msg_position_target_local_ned_get_z(const mavlink_me */ static inline float mavlink_msg_position_target_local_ned_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -429,7 +444,7 @@ static inline float mavlink_msg_position_target_local_ned_get_vx(const mavlink_m */ static inline float mavlink_msg_position_target_local_ned_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -439,7 +454,7 @@ static inline float mavlink_msg_position_target_local_ned_get_vy(const mavlink_m */ static inline float mavlink_msg_position_target_local_ned_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -449,7 +464,7 @@ static inline float mavlink_msg_position_target_local_ned_get_vz(const mavlink_m */ static inline float mavlink_msg_position_target_local_ned_get_afx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -459,7 +474,7 @@ static inline float mavlink_msg_position_target_local_ned_get_afx(const mavlink_ */ static inline float mavlink_msg_position_target_local_ned_get_afy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -469,7 +484,7 @@ static inline float mavlink_msg_position_target_local_ned_get_afy(const mavlink_ */ static inline float mavlink_msg_position_target_local_ned_get_afz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -479,7 +494,7 @@ static inline float mavlink_msg_position_target_local_ned_get_afz(const mavlink_ */ static inline float mavlink_msg_position_target_local_ned_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -489,7 +504,7 @@ static inline float mavlink_msg_position_target_local_ned_get_yaw(const mavlink_ */ static inline float mavlink_msg_position_target_local_ned_get_yaw_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -500,22 +515,24 @@ static inline float mavlink_msg_position_target_local_ned_get_yaw_rate(const mav */ static inline void mavlink_msg_position_target_local_ned_decode(const mavlink_message_t* msg, mavlink_position_target_local_ned_t* position_target_local_ned) { -#if MAVLINK_NEED_BYTE_SWAP - position_target_local_ned->time_boot_ms = mavlink_msg_position_target_local_ned_get_time_boot_ms(msg); - position_target_local_ned->x = mavlink_msg_position_target_local_ned_get_x(msg); - position_target_local_ned->y = mavlink_msg_position_target_local_ned_get_y(msg); - position_target_local_ned->z = mavlink_msg_position_target_local_ned_get_z(msg); - position_target_local_ned->vx = mavlink_msg_position_target_local_ned_get_vx(msg); - position_target_local_ned->vy = mavlink_msg_position_target_local_ned_get_vy(msg); - position_target_local_ned->vz = mavlink_msg_position_target_local_ned_get_vz(msg); - position_target_local_ned->afx = mavlink_msg_position_target_local_ned_get_afx(msg); - position_target_local_ned->afy = mavlink_msg_position_target_local_ned_get_afy(msg); - position_target_local_ned->afz = mavlink_msg_position_target_local_ned_get_afz(msg); - position_target_local_ned->yaw = mavlink_msg_position_target_local_ned_get_yaw(msg); - position_target_local_ned->yaw_rate = mavlink_msg_position_target_local_ned_get_yaw_rate(msg); - position_target_local_ned->type_mask = mavlink_msg_position_target_local_ned_get_type_mask(msg); - position_target_local_ned->coordinate_frame = mavlink_msg_position_target_local_ned_get_coordinate_frame(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + position_target_local_ned->time_boot_ms = mavlink_msg_position_target_local_ned_get_time_boot_ms(msg); + position_target_local_ned->x = mavlink_msg_position_target_local_ned_get_x(msg); + position_target_local_ned->y = mavlink_msg_position_target_local_ned_get_y(msg); + position_target_local_ned->z = mavlink_msg_position_target_local_ned_get_z(msg); + position_target_local_ned->vx = mavlink_msg_position_target_local_ned_get_vx(msg); + position_target_local_ned->vy = mavlink_msg_position_target_local_ned_get_vy(msg); + position_target_local_ned->vz = mavlink_msg_position_target_local_ned_get_vz(msg); + position_target_local_ned->afx = mavlink_msg_position_target_local_ned_get_afx(msg); + position_target_local_ned->afy = mavlink_msg_position_target_local_ned_get_afy(msg); + position_target_local_ned->afz = mavlink_msg_position_target_local_ned_get_afz(msg); + position_target_local_ned->yaw = mavlink_msg_position_target_local_ned_get_yaw(msg); + position_target_local_ned->yaw_rate = mavlink_msg_position_target_local_ned_get_yaw_rate(msg); + position_target_local_ned->type_mask = mavlink_msg_position_target_local_ned_get_type_mask(msg); + position_target_local_ned->coordinate_frame = mavlink_msg_position_target_local_ned_get_coordinate_frame(msg); #else - memcpy(position_target_local_ned, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN? msg->len : MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN; + memset(position_target_local_ned, 0, MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_LEN); + memcpy(position_target_local_ned, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_power_status.h b/vendor/libraries/mavlink/common/mavlink_msg_power_status.h index 1a6259aa3d..dca62b5868 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_power_status.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_power_status.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE POWER_STATUS PACKING #define MAVLINK_MSG_ID_POWER_STATUS 125 -typedef struct __mavlink_power_status_t -{ - uint16_t Vcc; ///< 5V rail voltage in millivolts - uint16_t Vservo; ///< servo rail voltage in millivolts - uint16_t flags; ///< power supply status flags (see MAV_POWER_STATUS enum) -} mavlink_power_status_t; +MAVPACKED( +typedef struct __mavlink_power_status_t { + uint16_t Vcc; /*< 5V rail voltage in millivolts*/ + uint16_t Vservo; /*< servo rail voltage in millivolts*/ + uint16_t flags; /*< power supply status flags (see MAV_POWER_STATUS enum)*/ +}) mavlink_power_status_t; #define MAVLINK_MSG_ID_POWER_STATUS_LEN 6 +#define MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN 6 #define MAVLINK_MSG_ID_125_LEN 6 +#define MAVLINK_MSG_ID_125_MIN_LEN 6 #define MAVLINK_MSG_ID_POWER_STATUS_CRC 203 #define MAVLINK_MSG_ID_125_CRC 203 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_POWER_STATUS { \ - "POWER_STATUS", \ - 3, \ - { { "Vcc", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_power_status_t, Vcc) }, \ + 125, \ + "POWER_STATUS", \ + 3, \ + { { "Vcc", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_power_status_t, Vcc) }, \ { "Vservo", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_power_status_t, Vservo) }, \ { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_power_status_t, flags) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_POWER_STATUS { \ + "POWER_STATUS", \ + 3, \ + { { "Vcc", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_power_status_t, Vcc) }, \ + { "Vservo", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_power_status_t, Vservo) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_power_status_t, flags) }, \ + } \ +} +#endif /** * @brief Pack a power_status message @@ -39,30 +53,26 @@ typedef struct __mavlink_power_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_power_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint16_t Vcc, uint16_t Vservo, uint16_t flags) + uint16_t Vcc, uint16_t Vservo, uint16_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POWER_STATUS_LEN]; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint16_t(buf, 2, Vservo); - _mav_put_uint16_t(buf, 4, flags); + char buf[MAVLINK_MSG_ID_POWER_STATUS_LEN]; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint16_t(buf, 2, Vservo); + _mav_put_uint16_t(buf, 4, flags); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_POWER_STATUS_LEN); #else - mavlink_power_status_t packet; - packet.Vcc = Vcc; - packet.Vservo = Vservo; - packet.flags = flags; + mavlink_power_status_t packet; + packet.Vcc = Vcc; + packet.Vservo = Vservo; + packet.flags = flags; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_POWER_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_POWER_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POWER_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_POWER_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_power_status_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_power_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint16_t Vcc,uint16_t Vservo,uint16_t flags) + mavlink_message_t* msg, + uint16_t Vcc,uint16_t Vservo,uint16_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POWER_STATUS_LEN]; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint16_t(buf, 2, Vservo); - _mav_put_uint16_t(buf, 4, flags); + char buf[MAVLINK_MSG_ID_POWER_STATUS_LEN]; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint16_t(buf, 2, Vservo); + _mav_put_uint16_t(buf, 4, flags); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_POWER_STATUS_LEN); #else - mavlink_power_status_t packet; - packet.Vcc = Vcc; - packet.Vservo = Vservo; - packet.flags = flags; + mavlink_power_status_t packet; + packet.Vcc = Vcc; + packet.Vservo = Vservo; + packet.flags = flags; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_POWER_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_POWER_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POWER_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_POWER_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_power_status_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_power_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_power_status_t* power_status) { - return mavlink_msg_power_status_pack(system_id, component_id, msg, power_status->Vcc, power_status->Vservo, power_status->flags); + return mavlink_msg_power_status_pack(system_id, component_id, msg, power_status->Vcc, power_status->Vservo, power_status->flags); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_power_status_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_power_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_power_status_t* power_status) { - return mavlink_msg_power_status_pack_chan(system_id, component_id, chan, msg, power_status->Vcc, power_status->Vservo, power_status->flags); + return mavlink_msg_power_status_pack_chan(system_id, component_id, chan, msg, power_status->Vcc, power_status->Vservo, power_status->flags); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_power_status_encode_chan(uint8_t system_id, u static inline void mavlink_msg_power_status_send(mavlink_channel_t chan, uint16_t Vcc, uint16_t Vservo, uint16_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_POWER_STATUS_LEN]; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint16_t(buf, 2, Vservo); - _mav_put_uint16_t(buf, 4, flags); + char buf[MAVLINK_MSG_ID_POWER_STATUS_LEN]; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint16_t(buf, 2, Vservo); + _mav_put_uint16_t(buf, 4, flags); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, buf, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, buf, MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, buf, MAVLINK_MSG_ID_POWER_STATUS_LEN); + mavlink_power_status_t packet; + packet.Vcc = Vcc; + packet.Vservo = Vservo; + packet.flags = flags; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, (const char *)&packet, MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); #endif -#else - mavlink_power_status_t packet; - packet.Vcc = Vcc; - packet.Vservo = Vservo; - packet.flags = flags; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, (const char *)&packet, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); +/** + * @brief Send a power_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_power_status_send_struct(mavlink_channel_t chan, const mavlink_power_status_t* power_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_power_status_send(chan, power_status->Vcc, power_status->Vservo, power_status->flags); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, (const char *)&packet, MAVLINK_MSG_ID_POWER_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, (const char *)power_status, MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_power_status_send(mavlink_channel_t chan, uint16_ static inline void mavlink_msg_power_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint16_t Vcc, uint16_t Vservo, uint16_t flags) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, Vcc); - _mav_put_uint16_t(buf, 2, Vservo); - _mav_put_uint16_t(buf, 4, flags); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, Vcc); + _mav_put_uint16_t(buf, 2, Vservo); + _mav_put_uint16_t(buf, 4, flags); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, buf, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, buf, MAVLINK_MSG_ID_POWER_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, buf, MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); #else - mavlink_power_status_t *packet = (mavlink_power_status_t *)msgbuf; - packet->Vcc = Vcc; - packet->Vservo = Vservo; - packet->flags = flags; + mavlink_power_status_t *packet = (mavlink_power_status_t *)msgbuf; + packet->Vcc = Vcc; + packet->Vservo = Vservo; + packet->flags = flags; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, (const char *)packet, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, (const char *)packet, MAVLINK_MSG_ID_POWER_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_POWER_STATUS, (const char *)packet, MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN, MAVLINK_MSG_ID_POWER_STATUS_LEN, MAVLINK_MSG_ID_POWER_STATUS_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_power_status_send_buf(mavlink_message_t *msgbuf, */ static inline uint16_t mavlink_msg_power_status_get_Vcc(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -226,7 +230,7 @@ static inline uint16_t mavlink_msg_power_status_get_Vcc(const mavlink_message_t* */ static inline uint16_t mavlink_msg_power_status_get_Vservo(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 2); + return _MAV_RETURN_uint16_t(msg, 2); } /** @@ -236,7 +240,7 @@ static inline uint16_t mavlink_msg_power_status_get_Vservo(const mavlink_message */ static inline uint16_t mavlink_msg_power_status_get_flags(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -247,11 +251,13 @@ static inline uint16_t mavlink_msg_power_status_get_flags(const mavlink_message_ */ static inline void mavlink_msg_power_status_decode(const mavlink_message_t* msg, mavlink_power_status_t* power_status) { -#if MAVLINK_NEED_BYTE_SWAP - power_status->Vcc = mavlink_msg_power_status_get_Vcc(msg); - power_status->Vservo = mavlink_msg_power_status_get_Vservo(msg); - power_status->flags = mavlink_msg_power_status_get_flags(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + power_status->Vcc = mavlink_msg_power_status_get_Vcc(msg); + power_status->Vservo = mavlink_msg_power_status_get_Vservo(msg); + power_status->flags = mavlink_msg_power_status_get_flags(msg); #else - memcpy(power_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_POWER_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_POWER_STATUS_LEN? msg->len : MAVLINK_MSG_ID_POWER_STATUS_LEN; + memset(power_status, 0, MAVLINK_MSG_ID_POWER_STATUS_LEN); + memcpy(power_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_radio_status.h b/vendor/libraries/mavlink/common/mavlink_msg_radio_status.h index dbd187ecd3..8d266bb4e8 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_radio_status.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_radio_status.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE RADIO_STATUS PACKING #define MAVLINK_MSG_ID_RADIO_STATUS 109 -typedef struct __mavlink_radio_status_t -{ - uint16_t rxerrors; ///< Receive errors - uint16_t fixed; ///< Count of error corrected packets - uint8_t rssi; ///< Local signal strength - uint8_t remrssi; ///< Remote signal strength - uint8_t txbuf; ///< Remaining free buffer space in percent. - uint8_t noise; ///< Background noise level - uint8_t remnoise; ///< Remote background noise level -} mavlink_radio_status_t; +MAVPACKED( +typedef struct __mavlink_radio_status_t { + uint16_t rxerrors; /*< Receive errors*/ + uint16_t fixed; /*< Count of error corrected packets*/ + uint8_t rssi; /*< Local signal strength*/ + uint8_t remrssi; /*< Remote signal strength*/ + uint8_t txbuf; /*< Remaining free buffer space in percent.*/ + uint8_t noise; /*< Background noise level*/ + uint8_t remnoise; /*< Remote background noise level*/ +}) mavlink_radio_status_t; #define MAVLINK_MSG_ID_RADIO_STATUS_LEN 9 +#define MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN 9 #define MAVLINK_MSG_ID_109_LEN 9 +#define MAVLINK_MSG_ID_109_MIN_LEN 9 #define MAVLINK_MSG_ID_RADIO_STATUS_CRC 185 #define MAVLINK_MSG_ID_109_CRC 185 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RADIO_STATUS { \ - "RADIO_STATUS", \ - 7, \ - { { "rxerrors", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_radio_status_t, rxerrors) }, \ + 109, \ + "RADIO_STATUS", \ + 7, \ + { { "rxerrors", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_radio_status_t, rxerrors) }, \ { "fixed", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_radio_status_t, fixed) }, \ { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_radio_status_t, rssi) }, \ { "remrssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_radio_status_t, remrssi) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_radio_status_t { "remnoise", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_radio_status_t, remnoise) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RADIO_STATUS { \ + "RADIO_STATUS", \ + 7, \ + { { "rxerrors", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_radio_status_t, rxerrors) }, \ + { "fixed", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_radio_status_t, fixed) }, \ + { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_radio_status_t, rssi) }, \ + { "remrssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_radio_status_t, remrssi) }, \ + { "txbuf", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_radio_status_t, txbuf) }, \ + { "noise", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_radio_status_t, noise) }, \ + { "remnoise", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_radio_status_t, remnoise) }, \ + } \ +} +#endif /** * @brief Pack a radio_status message @@ -51,38 +69,34 @@ typedef struct __mavlink_radio_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_radio_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) + uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RADIO_STATUS_LEN]; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); + char buf[MAVLINK_MSG_ID_RADIO_STATUS_LEN]; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RADIO_STATUS_LEN); #else - mavlink_radio_status_t packet; - packet.rxerrors = rxerrors; - packet.fixed = fixed; - packet.rssi = rssi; - packet.remrssi = remrssi; - packet.txbuf = txbuf; - packet.noise = noise; - packet.remnoise = remnoise; + mavlink_radio_status_t packet; + packet.rxerrors = rxerrors; + packet.fixed = fixed; + packet.rssi = rssi; + packet.remrssi = remrssi; + packet.txbuf = txbuf; + packet.noise = noise; + packet.remnoise = remnoise; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RADIO_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RADIO_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RADIO_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RADIO_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_radio_status_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_radio_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t rssi,uint8_t remrssi,uint8_t txbuf,uint8_t noise,uint8_t remnoise,uint16_t rxerrors,uint16_t fixed) + mavlink_message_t* msg, + uint8_t rssi,uint8_t remrssi,uint8_t txbuf,uint8_t noise,uint8_t remnoise,uint16_t rxerrors,uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RADIO_STATUS_LEN]; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); + char buf[MAVLINK_MSG_ID_RADIO_STATUS_LEN]; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RADIO_STATUS_LEN); #else - mavlink_radio_status_t packet; - packet.rxerrors = rxerrors; - packet.fixed = fixed; - packet.rssi = rssi; - packet.remrssi = remrssi; - packet.txbuf = txbuf; - packet.noise = noise; - packet.remnoise = remnoise; + mavlink_radio_status_t packet; + packet.rxerrors = rxerrors; + packet.fixed = fixed; + packet.rssi = rssi; + packet.remrssi = remrssi; + packet.txbuf = txbuf; + packet.noise = noise; + packet.remnoise = remnoise; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RADIO_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RADIO_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RADIO_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RADIO_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_radio_status_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_radio_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_radio_status_t* radio_status) { - return mavlink_msg_radio_status_pack(system_id, component_id, msg, radio_status->rssi, radio_status->remrssi, radio_status->txbuf, radio_status->noise, radio_status->remnoise, radio_status->rxerrors, radio_status->fixed); + return mavlink_msg_radio_status_pack(system_id, component_id, msg, radio_status->rssi, radio_status->remrssi, radio_status->txbuf, radio_status->noise, radio_status->remnoise, radio_status->rxerrors, radio_status->fixed); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_radio_status_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_radio_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_radio_status_t* radio_status) { - return mavlink_msg_radio_status_pack_chan(system_id, component_id, chan, msg, radio_status->rssi, radio_status->remrssi, radio_status->txbuf, radio_status->noise, radio_status->remnoise, radio_status->rxerrors, radio_status->fixed); + return mavlink_msg_radio_status_pack_chan(system_id, component_id, chan, msg, radio_status->rssi, radio_status->remrssi, radio_status->txbuf, radio_status->noise, radio_status->remnoise, radio_status->rxerrors, radio_status->fixed); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_radio_status_encode_chan(uint8_t system_id, u static inline void mavlink_msg_radio_status_send(mavlink_channel_t chan, uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RADIO_STATUS_LEN]; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, buf, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); + char buf[MAVLINK_MSG_ID_RADIO_STATUS_LEN]; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, buf, MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, buf, MAVLINK_MSG_ID_RADIO_STATUS_LEN); + mavlink_radio_status_t packet; + packet.rxerrors = rxerrors; + packet.fixed = fixed; + packet.rssi = rssi; + packet.remrssi = remrssi; + packet.txbuf = txbuf; + packet.noise = noise; + packet.remnoise = remnoise; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, (const char *)&packet, MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); #endif +} + +/** + * @brief Send a radio_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_radio_status_send_struct(mavlink_channel_t chan, const mavlink_radio_status_t* radio_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_radio_status_send(chan, radio_status->rssi, radio_status->remrssi, radio_status->txbuf, radio_status->noise, radio_status->remnoise, radio_status->rxerrors, radio_status->fixed); #else - mavlink_radio_status_t packet; - packet.rxerrors = rxerrors; - packet.fixed = fixed; - packet.rssi = rssi; - packet.remrssi = remrssi; - packet.txbuf = txbuf; - packet.noise = noise; - packet.remnoise = remnoise; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, (const char *)&packet, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, (const char *)&packet, MAVLINK_MSG_ID_RADIO_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, (const char *)radio_status, MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_radio_status_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_radio_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t rssi, uint8_t remrssi, uint8_t txbuf, uint8_t noise, uint8_t remnoise, uint16_t rxerrors, uint16_t fixed) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, rxerrors); - _mav_put_uint16_t(buf, 2, fixed); - _mav_put_uint8_t(buf, 4, rssi); - _mav_put_uint8_t(buf, 5, remrssi); - _mav_put_uint8_t(buf, 6, txbuf); - _mav_put_uint8_t(buf, 7, noise); - _mav_put_uint8_t(buf, 8, remnoise); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, buf, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, buf, MAVLINK_MSG_ID_RADIO_STATUS_LEN); -#endif -#else - mavlink_radio_status_t *packet = (mavlink_radio_status_t *)msgbuf; - packet->rxerrors = rxerrors; - packet->fixed = fixed; - packet->rssi = rssi; - packet->remrssi = remrssi; - packet->txbuf = txbuf; - packet->noise = noise; - packet->remnoise = remnoise; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, (const char *)packet, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, rxerrors); + _mav_put_uint16_t(buf, 2, fixed); + _mav_put_uint8_t(buf, 4, rssi); + _mav_put_uint8_t(buf, 5, remrssi); + _mav_put_uint8_t(buf, 6, txbuf); + _mav_put_uint8_t(buf, 7, noise); + _mav_put_uint8_t(buf, 8, remnoise); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, buf, MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, (const char *)packet, MAVLINK_MSG_ID_RADIO_STATUS_LEN); -#endif + mavlink_radio_status_t *packet = (mavlink_radio_status_t *)msgbuf; + packet->rxerrors = rxerrors; + packet->fixed = fixed; + packet->rssi = rssi; + packet->remrssi = remrssi; + packet->txbuf = txbuf; + packet->noise = noise; + packet->remnoise = remnoise; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RADIO_STATUS, (const char *)packet, MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN, MAVLINK_MSG_ID_RADIO_STATUS_LEN, MAVLINK_MSG_ID_RADIO_STATUS_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_radio_status_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_radio_status_get_rssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -278,7 +286,7 @@ static inline uint8_t mavlink_msg_radio_status_get_rssi(const mavlink_message_t* */ static inline uint8_t mavlink_msg_radio_status_get_remrssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -288,7 +296,7 @@ static inline uint8_t mavlink_msg_radio_status_get_remrssi(const mavlink_message */ static inline uint8_t mavlink_msg_radio_status_get_txbuf(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -298,7 +306,7 @@ static inline uint8_t mavlink_msg_radio_status_get_txbuf(const mavlink_message_t */ static inline uint8_t mavlink_msg_radio_status_get_noise(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -308,7 +316,7 @@ static inline uint8_t mavlink_msg_radio_status_get_noise(const mavlink_message_t */ static inline uint8_t mavlink_msg_radio_status_get_remnoise(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 8); + return _MAV_RETURN_uint8_t(msg, 8); } /** @@ -318,7 +326,7 @@ static inline uint8_t mavlink_msg_radio_status_get_remnoise(const mavlink_messag */ static inline uint16_t mavlink_msg_radio_status_get_rxerrors(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -328,7 +336,7 @@ static inline uint16_t mavlink_msg_radio_status_get_rxerrors(const mavlink_messa */ static inline uint16_t mavlink_msg_radio_status_get_fixed(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 2); + return _MAV_RETURN_uint16_t(msg, 2); } /** @@ -339,15 +347,17 @@ static inline uint16_t mavlink_msg_radio_status_get_fixed(const mavlink_message_ */ static inline void mavlink_msg_radio_status_decode(const mavlink_message_t* msg, mavlink_radio_status_t* radio_status) { -#if MAVLINK_NEED_BYTE_SWAP - radio_status->rxerrors = mavlink_msg_radio_status_get_rxerrors(msg); - radio_status->fixed = mavlink_msg_radio_status_get_fixed(msg); - radio_status->rssi = mavlink_msg_radio_status_get_rssi(msg); - radio_status->remrssi = mavlink_msg_radio_status_get_remrssi(msg); - radio_status->txbuf = mavlink_msg_radio_status_get_txbuf(msg); - radio_status->noise = mavlink_msg_radio_status_get_noise(msg); - radio_status->remnoise = mavlink_msg_radio_status_get_remnoise(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + radio_status->rxerrors = mavlink_msg_radio_status_get_rxerrors(msg); + radio_status->fixed = mavlink_msg_radio_status_get_fixed(msg); + radio_status->rssi = mavlink_msg_radio_status_get_rssi(msg); + radio_status->remrssi = mavlink_msg_radio_status_get_remrssi(msg); + radio_status->txbuf = mavlink_msg_radio_status_get_txbuf(msg); + radio_status->noise = mavlink_msg_radio_status_get_noise(msg); + radio_status->remnoise = mavlink_msg_radio_status_get_remnoise(msg); #else - memcpy(radio_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RADIO_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RADIO_STATUS_LEN? msg->len : MAVLINK_MSG_ID_RADIO_STATUS_LEN; + memset(radio_status, 0, MAVLINK_MSG_ID_RADIO_STATUS_LEN); + memcpy(radio_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_raw_imu.h b/vendor/libraries/mavlink/common/mavlink_msg_raw_imu.h index a98e8ce721..23833bc8b3 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_raw_imu.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_raw_imu.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE RAW_IMU PACKING #define MAVLINK_MSG_ID_RAW_IMU 27 -typedef struct __mavlink_raw_imu_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - int16_t xacc; ///< X acceleration (raw) - int16_t yacc; ///< Y acceleration (raw) - int16_t zacc; ///< Z acceleration (raw) - int16_t xgyro; ///< Angular speed around X axis (raw) - int16_t ygyro; ///< Angular speed around Y axis (raw) - int16_t zgyro; ///< Angular speed around Z axis (raw) - int16_t xmag; ///< X Magnetic field (raw) - int16_t ymag; ///< Y Magnetic field (raw) - int16_t zmag; ///< Z Magnetic field (raw) -} mavlink_raw_imu_t; +MAVPACKED( +typedef struct __mavlink_raw_imu_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + int16_t xacc; /*< X acceleration (raw)*/ + int16_t yacc; /*< Y acceleration (raw)*/ + int16_t zacc; /*< Z acceleration (raw)*/ + int16_t xgyro; /*< Angular speed around X axis (raw)*/ + int16_t ygyro; /*< Angular speed around Y axis (raw)*/ + int16_t zgyro; /*< Angular speed around Z axis (raw)*/ + int16_t xmag; /*< X Magnetic field (raw)*/ + int16_t ymag; /*< Y Magnetic field (raw)*/ + int16_t zmag; /*< Z Magnetic field (raw)*/ +}) mavlink_raw_imu_t; #define MAVLINK_MSG_ID_RAW_IMU_LEN 26 +#define MAVLINK_MSG_ID_RAW_IMU_MIN_LEN 26 #define MAVLINK_MSG_ID_27_LEN 26 +#define MAVLINK_MSG_ID_27_MIN_LEN 26 #define MAVLINK_MSG_ID_RAW_IMU_CRC 144 #define MAVLINK_MSG_ID_27_CRC 144 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RAW_IMU { \ - "RAW_IMU", \ - 10, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_raw_imu_t, time_usec) }, \ + 27, \ + "RAW_IMU", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_raw_imu_t, time_usec) }, \ { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_raw_imu_t, xacc) }, \ { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_raw_imu_t, yacc) }, \ { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_raw_imu_t, zacc) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_raw_imu_t { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 24, offsetof(mavlink_raw_imu_t, zmag) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RAW_IMU { \ + "RAW_IMU", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_raw_imu_t, time_usec) }, \ + { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_raw_imu_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_raw_imu_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_raw_imu_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_raw_imu_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_raw_imu_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_raw_imu_t, zgyro) }, \ + { "xmag", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_raw_imu_t, xmag) }, \ + { "ymag", NULL, MAVLINK_TYPE_INT16_T, 0, 22, offsetof(mavlink_raw_imu_t, ymag) }, \ + { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 24, offsetof(mavlink_raw_imu_t, zmag) }, \ + } \ +} +#endif /** * @brief Pack a raw_imu message @@ -60,44 +81,40 @@ typedef struct __mavlink_raw_imu_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_raw_imu_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) + uint64_t time_usec, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RAW_IMU_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, xacc); - _mav_put_int16_t(buf, 10, yacc); - _mav_put_int16_t(buf, 12, zacc); - _mav_put_int16_t(buf, 14, xgyro); - _mav_put_int16_t(buf, 16, ygyro); - _mav_put_int16_t(buf, 18, zgyro); - _mav_put_int16_t(buf, 20, xmag); - _mav_put_int16_t(buf, 22, ymag); - _mav_put_int16_t(buf, 24, zmag); + char buf[MAVLINK_MSG_ID_RAW_IMU_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, xacc); + _mav_put_int16_t(buf, 10, yacc); + _mav_put_int16_t(buf, 12, zacc); + _mav_put_int16_t(buf, 14, xgyro); + _mav_put_int16_t(buf, 16, ygyro); + _mav_put_int16_t(buf, 18, zgyro); + _mav_put_int16_t(buf, 20, xmag); + _mav_put_int16_t(buf, 22, ymag); + _mav_put_int16_t(buf, 24, zmag); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RAW_IMU_LEN); #else - mavlink_raw_imu_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; + mavlink_raw_imu_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RAW_IMU_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RAW_IMU; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RAW_IMU_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RAW_IMU; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RAW_IMU_MIN_LEN, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_raw_imu_pack(uint8_t system_id, uint8_t compo * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_raw_imu_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,int16_t xacc,int16_t yacc,int16_t zacc,int16_t xgyro,int16_t ygyro,int16_t zgyro,int16_t xmag,int16_t ymag,int16_t zmag) + mavlink_message_t* msg, + uint64_t time_usec,int16_t xacc,int16_t yacc,int16_t zacc,int16_t xgyro,int16_t ygyro,int16_t zgyro,int16_t xmag,int16_t ymag,int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RAW_IMU_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, xacc); - _mav_put_int16_t(buf, 10, yacc); - _mav_put_int16_t(buf, 12, zacc); - _mav_put_int16_t(buf, 14, xgyro); - _mav_put_int16_t(buf, 16, ygyro); - _mav_put_int16_t(buf, 18, zgyro); - _mav_put_int16_t(buf, 20, xmag); - _mav_put_int16_t(buf, 22, ymag); - _mav_put_int16_t(buf, 24, zmag); + char buf[MAVLINK_MSG_ID_RAW_IMU_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, xacc); + _mav_put_int16_t(buf, 10, yacc); + _mav_put_int16_t(buf, 12, zacc); + _mav_put_int16_t(buf, 14, xgyro); + _mav_put_int16_t(buf, 16, ygyro); + _mav_put_int16_t(buf, 18, zgyro); + _mav_put_int16_t(buf, 20, xmag); + _mav_put_int16_t(buf, 22, ymag); + _mav_put_int16_t(buf, 24, zmag); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RAW_IMU_LEN); #else - mavlink_raw_imu_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; + mavlink_raw_imu_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RAW_IMU_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RAW_IMU; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RAW_IMU_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RAW_IMU; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RAW_IMU_MIN_LEN, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_raw_imu_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_raw_imu_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_raw_imu_t* raw_imu) { - return mavlink_msg_raw_imu_pack(system_id, component_id, msg, raw_imu->time_usec, raw_imu->xacc, raw_imu->yacc, raw_imu->zacc, raw_imu->xgyro, raw_imu->ygyro, raw_imu->zgyro, raw_imu->xmag, raw_imu->ymag, raw_imu->zmag); + return mavlink_msg_raw_imu_pack(system_id, component_id, msg, raw_imu->time_usec, raw_imu->xacc, raw_imu->yacc, raw_imu->zacc, raw_imu->xgyro, raw_imu->ygyro, raw_imu->zgyro, raw_imu->xmag, raw_imu->ymag, raw_imu->zmag); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_raw_imu_encode(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_raw_imu_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_raw_imu_t* raw_imu) { - return mavlink_msg_raw_imu_pack_chan(system_id, component_id, chan, msg, raw_imu->time_usec, raw_imu->xacc, raw_imu->yacc, raw_imu->zacc, raw_imu->xgyro, raw_imu->ygyro, raw_imu->zgyro, raw_imu->xmag, raw_imu->ymag, raw_imu->zmag); + return mavlink_msg_raw_imu_pack_chan(system_id, component_id, chan, msg, raw_imu->time_usec, raw_imu->xacc, raw_imu->yacc, raw_imu->zacc, raw_imu->xgyro, raw_imu->ygyro, raw_imu->zgyro, raw_imu->xmag, raw_imu->ymag, raw_imu->zmag); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_raw_imu_encode_chan(uint8_t system_id, uint8_ static inline void mavlink_msg_raw_imu_send(mavlink_channel_t chan, uint64_t time_usec, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RAW_IMU_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, xacc); - _mav_put_int16_t(buf, 10, yacc); - _mav_put_int16_t(buf, 12, zacc); - _mav_put_int16_t(buf, 14, xgyro); - _mav_put_int16_t(buf, 16, ygyro); - _mav_put_int16_t(buf, 18, zgyro); - _mav_put_int16_t(buf, 20, xmag); - _mav_put_int16_t(buf, 22, ymag); - _mav_put_int16_t(buf, 24, zmag); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, buf, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); + char buf[MAVLINK_MSG_ID_RAW_IMU_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, xacc); + _mav_put_int16_t(buf, 10, yacc); + _mav_put_int16_t(buf, 12, zacc); + _mav_put_int16_t(buf, 14, xgyro); + _mav_put_int16_t(buf, 16, ygyro); + _mav_put_int16_t(buf, 18, zgyro); + _mav_put_int16_t(buf, 20, xmag); + _mav_put_int16_t(buf, 22, ymag); + _mav_put_int16_t(buf, 24, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, buf, MAVLINK_MSG_ID_RAW_IMU_MIN_LEN, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, buf, MAVLINK_MSG_ID_RAW_IMU_LEN); + mavlink_raw_imu_t packet; + packet.time_usec = time_usec; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, (const char *)&packet, MAVLINK_MSG_ID_RAW_IMU_MIN_LEN, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); #endif +} + +/** + * @brief Send a raw_imu message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_raw_imu_send_struct(mavlink_channel_t chan, const mavlink_raw_imu_t* raw_imu) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_raw_imu_send(chan, raw_imu->time_usec, raw_imu->xacc, raw_imu->yacc, raw_imu->zacc, raw_imu->xgyro, raw_imu->ygyro, raw_imu->zgyro, raw_imu->xmag, raw_imu->ymag, raw_imu->zmag); #else - mavlink_raw_imu_t packet; - packet.time_usec = time_usec; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, (const char *)&packet, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, (const char *)&packet, MAVLINK_MSG_ID_RAW_IMU_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, (const char *)raw_imu, MAVLINK_MSG_ID_RAW_IMU_MIN_LEN, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_raw_imu_send(mavlink_channel_t chan, uint64_t tim static inline void mavlink_msg_raw_imu_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, xacc); - _mav_put_int16_t(buf, 10, yacc); - _mav_put_int16_t(buf, 12, zacc); - _mav_put_int16_t(buf, 14, xgyro); - _mav_put_int16_t(buf, 16, ygyro); - _mav_put_int16_t(buf, 18, zgyro); - _mav_put_int16_t(buf, 20, xmag); - _mav_put_int16_t(buf, 22, ymag); - _mav_put_int16_t(buf, 24, zmag); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, buf, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, buf, MAVLINK_MSG_ID_RAW_IMU_LEN); -#endif -#else - mavlink_raw_imu_t *packet = (mavlink_raw_imu_t *)msgbuf; - packet->time_usec = time_usec; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - packet->xgyro = xgyro; - packet->ygyro = ygyro; - packet->zgyro = zgyro; - packet->xmag = xmag; - packet->ymag = ymag; - packet->zmag = zmag; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, (const char *)packet, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, xacc); + _mav_put_int16_t(buf, 10, yacc); + _mav_put_int16_t(buf, 12, zacc); + _mav_put_int16_t(buf, 14, xgyro); + _mav_put_int16_t(buf, 16, ygyro); + _mav_put_int16_t(buf, 18, zgyro); + _mav_put_int16_t(buf, 20, xmag); + _mav_put_int16_t(buf, 22, ymag); + _mav_put_int16_t(buf, 24, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, buf, MAVLINK_MSG_ID_RAW_IMU_MIN_LEN, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, (const char *)packet, MAVLINK_MSG_ID_RAW_IMU_LEN); -#endif + mavlink_raw_imu_t *packet = (mavlink_raw_imu_t *)msgbuf; + packet->time_usec = time_usec; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->xmag = xmag; + packet->ymag = ymag; + packet->zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_IMU, (const char *)packet, MAVLINK_MSG_ID_RAW_IMU_MIN_LEN, MAVLINK_MSG_ID_RAW_IMU_LEN, MAVLINK_MSG_ID_RAW_IMU_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_raw_imu_send_buf(mavlink_message_t *msgbuf, mavli */ static inline uint64_t mavlink_msg_raw_imu_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -317,7 +328,7 @@ static inline uint64_t mavlink_msg_raw_imu_get_time_usec(const mavlink_message_t */ static inline int16_t mavlink_msg_raw_imu_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 8); + return _MAV_RETURN_int16_t(msg, 8); } /** @@ -327,7 +338,7 @@ static inline int16_t mavlink_msg_raw_imu_get_xacc(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_raw_imu_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 10); + return _MAV_RETURN_int16_t(msg, 10); } /** @@ -337,7 +348,7 @@ static inline int16_t mavlink_msg_raw_imu_get_yacc(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_raw_imu_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 12); + return _MAV_RETURN_int16_t(msg, 12); } /** @@ -347,7 +358,7 @@ static inline int16_t mavlink_msg_raw_imu_get_zacc(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_raw_imu_get_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 14); + return _MAV_RETURN_int16_t(msg, 14); } /** @@ -357,7 +368,7 @@ static inline int16_t mavlink_msg_raw_imu_get_xgyro(const mavlink_message_t* msg */ static inline int16_t mavlink_msg_raw_imu_get_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 16); + return _MAV_RETURN_int16_t(msg, 16); } /** @@ -367,7 +378,7 @@ static inline int16_t mavlink_msg_raw_imu_get_ygyro(const mavlink_message_t* msg */ static inline int16_t mavlink_msg_raw_imu_get_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 18); + return _MAV_RETURN_int16_t(msg, 18); } /** @@ -377,7 +388,7 @@ static inline int16_t mavlink_msg_raw_imu_get_zgyro(const mavlink_message_t* msg */ static inline int16_t mavlink_msg_raw_imu_get_xmag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 20); + return _MAV_RETURN_int16_t(msg, 20); } /** @@ -387,7 +398,7 @@ static inline int16_t mavlink_msg_raw_imu_get_xmag(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_raw_imu_get_ymag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 22); + return _MAV_RETURN_int16_t(msg, 22); } /** @@ -397,7 +408,7 @@ static inline int16_t mavlink_msg_raw_imu_get_ymag(const mavlink_message_t* msg) */ static inline int16_t mavlink_msg_raw_imu_get_zmag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 24); + return _MAV_RETURN_int16_t(msg, 24); } /** @@ -408,18 +419,20 @@ static inline int16_t mavlink_msg_raw_imu_get_zmag(const mavlink_message_t* msg) */ static inline void mavlink_msg_raw_imu_decode(const mavlink_message_t* msg, mavlink_raw_imu_t* raw_imu) { -#if MAVLINK_NEED_BYTE_SWAP - raw_imu->time_usec = mavlink_msg_raw_imu_get_time_usec(msg); - raw_imu->xacc = mavlink_msg_raw_imu_get_xacc(msg); - raw_imu->yacc = mavlink_msg_raw_imu_get_yacc(msg); - raw_imu->zacc = mavlink_msg_raw_imu_get_zacc(msg); - raw_imu->xgyro = mavlink_msg_raw_imu_get_xgyro(msg); - raw_imu->ygyro = mavlink_msg_raw_imu_get_ygyro(msg); - raw_imu->zgyro = mavlink_msg_raw_imu_get_zgyro(msg); - raw_imu->xmag = mavlink_msg_raw_imu_get_xmag(msg); - raw_imu->ymag = mavlink_msg_raw_imu_get_ymag(msg); - raw_imu->zmag = mavlink_msg_raw_imu_get_zmag(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + raw_imu->time_usec = mavlink_msg_raw_imu_get_time_usec(msg); + raw_imu->xacc = mavlink_msg_raw_imu_get_xacc(msg); + raw_imu->yacc = mavlink_msg_raw_imu_get_yacc(msg); + raw_imu->zacc = mavlink_msg_raw_imu_get_zacc(msg); + raw_imu->xgyro = mavlink_msg_raw_imu_get_xgyro(msg); + raw_imu->ygyro = mavlink_msg_raw_imu_get_ygyro(msg); + raw_imu->zgyro = mavlink_msg_raw_imu_get_zgyro(msg); + raw_imu->xmag = mavlink_msg_raw_imu_get_xmag(msg); + raw_imu->ymag = mavlink_msg_raw_imu_get_ymag(msg); + raw_imu->zmag = mavlink_msg_raw_imu_get_zmag(msg); #else - memcpy(raw_imu, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RAW_IMU_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RAW_IMU_LEN? msg->len : MAVLINK_MSG_ID_RAW_IMU_LEN; + memset(raw_imu, 0, MAVLINK_MSG_ID_RAW_IMU_LEN); + memcpy(raw_imu, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_raw_pressure.h b/vendor/libraries/mavlink/common/mavlink_msg_raw_pressure.h index 6bd37fcaee..2d2ead97ec 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_raw_pressure.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_raw_pressure.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE RAW_PRESSURE PACKING #define MAVLINK_MSG_ID_RAW_PRESSURE 28 -typedef struct __mavlink_raw_pressure_t -{ - uint64_t time_usec; ///< Timestamp (microseconds since UNIX epoch or microseconds since system boot) - int16_t press_abs; ///< Absolute pressure (raw) - int16_t press_diff1; ///< Differential pressure 1 (raw) - int16_t press_diff2; ///< Differential pressure 2 (raw) - int16_t temperature; ///< Raw Temperature measurement (raw) -} mavlink_raw_pressure_t; +MAVPACKED( +typedef struct __mavlink_raw_pressure_t { + uint64_t time_usec; /*< Timestamp (microseconds since UNIX epoch or microseconds since system boot)*/ + int16_t press_abs; /*< Absolute pressure (raw)*/ + int16_t press_diff1; /*< Differential pressure 1 (raw, 0 if nonexistant)*/ + int16_t press_diff2; /*< Differential pressure 2 (raw, 0 if nonexistant)*/ + int16_t temperature; /*< Raw Temperature measurement (raw)*/ +}) mavlink_raw_pressure_t; #define MAVLINK_MSG_ID_RAW_PRESSURE_LEN 16 +#define MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN 16 #define MAVLINK_MSG_ID_28_LEN 16 +#define MAVLINK_MSG_ID_28_MIN_LEN 16 #define MAVLINK_MSG_ID_RAW_PRESSURE_CRC 67 #define MAVLINK_MSG_ID_28_CRC 67 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RAW_PRESSURE { \ - "RAW_PRESSURE", \ - 5, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_raw_pressure_t, time_usec) }, \ + 28, \ + "RAW_PRESSURE", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_raw_pressure_t, time_usec) }, \ { "press_abs", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_raw_pressure_t, press_abs) }, \ { "press_diff1", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_raw_pressure_t, press_diff1) }, \ { "press_diff2", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_raw_pressure_t, press_diff2) }, \ { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_raw_pressure_t, temperature) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RAW_PRESSURE { \ + "RAW_PRESSURE", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_raw_pressure_t, time_usec) }, \ + { "press_abs", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_raw_pressure_t, press_abs) }, \ + { "press_diff1", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_raw_pressure_t, press_diff1) }, \ + { "press_diff2", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_raw_pressure_t, press_diff2) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_raw_pressure_t, temperature) }, \ + } \ +} +#endif /** * @brief Pack a raw_pressure message @@ -39,40 +55,36 @@ typedef struct __mavlink_raw_pressure_t * * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param press_abs Absolute pressure (raw) - * @param press_diff1 Differential pressure 1 (raw) - * @param press_diff2 Differential pressure 2 (raw) + * @param press_diff1 Differential pressure 1 (raw, 0 if nonexistant) + * @param press_diff2 Differential pressure 2 (raw, 0 if nonexistant) * @param temperature Raw Temperature measurement (raw) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_raw_pressure_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, int16_t press_abs, int16_t press_diff1, int16_t press_diff2, int16_t temperature) + uint64_t time_usec, int16_t press_abs, int16_t press_diff1, int16_t press_diff2, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RAW_PRESSURE_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, press_abs); - _mav_put_int16_t(buf, 10, press_diff1); - _mav_put_int16_t(buf, 12, press_diff2); - _mav_put_int16_t(buf, 14, temperature); + char buf[MAVLINK_MSG_ID_RAW_PRESSURE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, press_abs); + _mav_put_int16_t(buf, 10, press_diff1); + _mav_put_int16_t(buf, 12, press_diff2); + _mav_put_int16_t(buf, 14, temperature); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); #else - mavlink_raw_pressure_t packet; - packet.time_usec = time_usec; - packet.press_abs = press_abs; - packet.press_diff1 = press_diff1; - packet.press_diff2 = press_diff2; - packet.temperature = temperature; + mavlink_raw_pressure_t packet; + packet.time_usec = time_usec; + packet.press_abs = press_abs; + packet.press_diff1 = press_diff1; + packet.press_diff2 = press_diff2; + packet.temperature = temperature; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RAW_PRESSURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RAW_PRESSURE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); } /** @@ -83,41 +95,37 @@ static inline uint16_t mavlink_msg_raw_pressure_pack(uint8_t system_id, uint8_t * @param msg The MAVLink message to compress the data into * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param press_abs Absolute pressure (raw) - * @param press_diff1 Differential pressure 1 (raw) - * @param press_diff2 Differential pressure 2 (raw) + * @param press_diff1 Differential pressure 1 (raw, 0 if nonexistant) + * @param press_diff2 Differential pressure 2 (raw, 0 if nonexistant) * @param temperature Raw Temperature measurement (raw) * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_raw_pressure_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,int16_t press_abs,int16_t press_diff1,int16_t press_diff2,int16_t temperature) + mavlink_message_t* msg, + uint64_t time_usec,int16_t press_abs,int16_t press_diff1,int16_t press_diff2,int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RAW_PRESSURE_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, press_abs); - _mav_put_int16_t(buf, 10, press_diff1); - _mav_put_int16_t(buf, 12, press_diff2); - _mav_put_int16_t(buf, 14, temperature); + char buf[MAVLINK_MSG_ID_RAW_PRESSURE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, press_abs); + _mav_put_int16_t(buf, 10, press_diff1); + _mav_put_int16_t(buf, 12, press_diff2); + _mav_put_int16_t(buf, 14, temperature); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); #else - mavlink_raw_pressure_t packet; - packet.time_usec = time_usec; - packet.press_abs = press_abs; - packet.press_diff1 = press_diff1; - packet.press_diff2 = press_diff2; - packet.temperature = temperature; + mavlink_raw_pressure_t packet; + packet.time_usec = time_usec; + packet.press_abs = press_abs; + packet.press_diff1 = press_diff1; + packet.press_diff2 = press_diff2; + packet.temperature = temperature; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RAW_PRESSURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RAW_PRESSURE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); } /** @@ -130,7 +138,7 @@ static inline uint16_t mavlink_msg_raw_pressure_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_raw_pressure_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_raw_pressure_t* raw_pressure) { - return mavlink_msg_raw_pressure_pack(system_id, component_id, msg, raw_pressure->time_usec, raw_pressure->press_abs, raw_pressure->press_diff1, raw_pressure->press_diff2, raw_pressure->temperature); + return mavlink_msg_raw_pressure_pack(system_id, component_id, msg, raw_pressure->time_usec, raw_pressure->press_abs, raw_pressure->press_diff1, raw_pressure->press_diff2, raw_pressure->temperature); } /** @@ -144,7 +152,7 @@ static inline uint16_t mavlink_msg_raw_pressure_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_raw_pressure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_raw_pressure_t* raw_pressure) { - return mavlink_msg_raw_pressure_pack_chan(system_id, component_id, chan, msg, raw_pressure->time_usec, raw_pressure->press_abs, raw_pressure->press_diff1, raw_pressure->press_diff2, raw_pressure->temperature); + return mavlink_msg_raw_pressure_pack_chan(system_id, component_id, chan, msg, raw_pressure->time_usec, raw_pressure->press_abs, raw_pressure->press_diff1, raw_pressure->press_diff2, raw_pressure->temperature); } /** @@ -153,8 +161,8 @@ static inline uint16_t mavlink_msg_raw_pressure_encode_chan(uint8_t system_id, u * * @param time_usec Timestamp (microseconds since UNIX epoch or microseconds since system boot) * @param press_abs Absolute pressure (raw) - * @param press_diff1 Differential pressure 1 (raw) - * @param press_diff2 Differential pressure 2 (raw) + * @param press_diff1 Differential pressure 1 (raw, 0 if nonexistant) + * @param press_diff2 Differential pressure 2 (raw, 0 if nonexistant) * @param temperature Raw Temperature measurement (raw) */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -162,31 +170,37 @@ static inline uint16_t mavlink_msg_raw_pressure_encode_chan(uint8_t system_id, u static inline void mavlink_msg_raw_pressure_send(mavlink_channel_t chan, uint64_t time_usec, int16_t press_abs, int16_t press_diff1, int16_t press_diff2, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RAW_PRESSURE_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, press_abs); - _mav_put_int16_t(buf, 10, press_diff1); - _mav_put_int16_t(buf, 12, press_diff2); - _mav_put_int16_t(buf, 14, temperature); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, buf, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); + char buf[MAVLINK_MSG_ID_RAW_PRESSURE_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, press_abs); + _mav_put_int16_t(buf, 10, press_diff1); + _mav_put_int16_t(buf, 12, press_diff2); + _mav_put_int16_t(buf, 14, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, buf, MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, buf, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); + mavlink_raw_pressure_t packet; + packet.time_usec = time_usec; + packet.press_abs = press_abs; + packet.press_diff1 = press_diff1; + packet.press_diff2 = press_diff2; + packet.temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, (const char *)&packet, MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); #endif +} + +/** + * @brief Send a raw_pressure message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_raw_pressure_send_struct(mavlink_channel_t chan, const mavlink_raw_pressure_t* raw_pressure) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_raw_pressure_send(chan, raw_pressure->time_usec, raw_pressure->press_abs, raw_pressure->press_diff1, raw_pressure->press_diff2, raw_pressure->temperature); #else - mavlink_raw_pressure_t packet; - packet.time_usec = time_usec; - packet.press_abs = press_abs; - packet.press_diff1 = press_diff1; - packet.press_diff2 = press_diff2; - packet.temperature = temperature; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, (const char *)&packet, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, (const char *)&packet, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, (const char *)raw_pressure, MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); #endif } @@ -201,31 +215,23 @@ static inline void mavlink_msg_raw_pressure_send(mavlink_channel_t chan, uint64_ static inline void mavlink_msg_raw_pressure_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, int16_t press_abs, int16_t press_diff1, int16_t press_diff2, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_int16_t(buf, 8, press_abs); - _mav_put_int16_t(buf, 10, press_diff1); - _mav_put_int16_t(buf, 12, press_diff2); - _mav_put_int16_t(buf, 14, temperature); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, buf, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_int16_t(buf, 8, press_abs); + _mav_put_int16_t(buf, 10, press_diff1); + _mav_put_int16_t(buf, 12, press_diff2); + _mav_put_int16_t(buf, 14, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, buf, MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, buf, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); -#endif -#else - mavlink_raw_pressure_t *packet = (mavlink_raw_pressure_t *)msgbuf; - packet->time_usec = time_usec; - packet->press_abs = press_abs; - packet->press_diff1 = press_diff1; - packet->press_diff2 = press_diff2; - packet->temperature = temperature; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, (const char *)packet, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, (const char *)packet, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); -#endif + mavlink_raw_pressure_t *packet = (mavlink_raw_pressure_t *)msgbuf; + packet->time_usec = time_usec; + packet->press_abs = press_abs; + packet->press_diff1 = press_diff1; + packet->press_diff2 = press_diff2; + packet->temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RAW_PRESSURE, (const char *)packet, MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_LEN, MAVLINK_MSG_ID_RAW_PRESSURE_CRC); #endif } #endif @@ -242,7 +248,7 @@ static inline void mavlink_msg_raw_pressure_send_buf(mavlink_message_t *msgbuf, */ static inline uint64_t mavlink_msg_raw_pressure_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -252,27 +258,27 @@ static inline uint64_t mavlink_msg_raw_pressure_get_time_usec(const mavlink_mess */ static inline int16_t mavlink_msg_raw_pressure_get_press_abs(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 8); + return _MAV_RETURN_int16_t(msg, 8); } /** * @brief Get field press_diff1 from raw_pressure message * - * @return Differential pressure 1 (raw) + * @return Differential pressure 1 (raw, 0 if nonexistant) */ static inline int16_t mavlink_msg_raw_pressure_get_press_diff1(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 10); + return _MAV_RETURN_int16_t(msg, 10); } /** * @brief Get field press_diff2 from raw_pressure message * - * @return Differential pressure 2 (raw) + * @return Differential pressure 2 (raw, 0 if nonexistant) */ static inline int16_t mavlink_msg_raw_pressure_get_press_diff2(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 12); + return _MAV_RETURN_int16_t(msg, 12); } /** @@ -282,7 +288,7 @@ static inline int16_t mavlink_msg_raw_pressure_get_press_diff2(const mavlink_mes */ static inline int16_t mavlink_msg_raw_pressure_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 14); + return _MAV_RETURN_int16_t(msg, 14); } /** @@ -293,13 +299,15 @@ static inline int16_t mavlink_msg_raw_pressure_get_temperature(const mavlink_mes */ static inline void mavlink_msg_raw_pressure_decode(const mavlink_message_t* msg, mavlink_raw_pressure_t* raw_pressure) { -#if MAVLINK_NEED_BYTE_SWAP - raw_pressure->time_usec = mavlink_msg_raw_pressure_get_time_usec(msg); - raw_pressure->press_abs = mavlink_msg_raw_pressure_get_press_abs(msg); - raw_pressure->press_diff1 = mavlink_msg_raw_pressure_get_press_diff1(msg); - raw_pressure->press_diff2 = mavlink_msg_raw_pressure_get_press_diff2(msg); - raw_pressure->temperature = mavlink_msg_raw_pressure_get_temperature(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + raw_pressure->time_usec = mavlink_msg_raw_pressure_get_time_usec(msg); + raw_pressure->press_abs = mavlink_msg_raw_pressure_get_press_abs(msg); + raw_pressure->press_diff1 = mavlink_msg_raw_pressure_get_press_diff1(msg); + raw_pressure->press_diff2 = mavlink_msg_raw_pressure_get_press_diff2(msg); + raw_pressure->temperature = mavlink_msg_raw_pressure_get_temperature(msg); #else - memcpy(raw_pressure, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RAW_PRESSURE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RAW_PRESSURE_LEN? msg->len : MAVLINK_MSG_ID_RAW_PRESSURE_LEN; + memset(raw_pressure, 0, MAVLINK_MSG_ID_RAW_PRESSURE_LEN); + memcpy(raw_pressure, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels.h b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels.h index 479af122ff..f7637379b4 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels.h @@ -1,44 +1,49 @@ +#pragma once // MESSAGE RC_CHANNELS PACKING #define MAVLINK_MSG_ID_RC_CHANNELS 65 -typedef struct __mavlink_rc_channels_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - uint16_t chan1_raw; ///< RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan2_raw; ///< RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan3_raw; ///< RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan4_raw; ///< RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan5_raw; ///< RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan6_raw; ///< RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan7_raw; ///< RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan8_raw; ///< RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan9_raw; ///< RC channel 9 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan10_raw; ///< RC channel 10 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan11_raw; ///< RC channel 11 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan12_raw; ///< RC channel 12 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan13_raw; ///< RC channel 13 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan14_raw; ///< RC channel 14 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan15_raw; ///< RC channel 15 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan16_raw; ///< RC channel 16 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan17_raw; ///< RC channel 17 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan18_raw; ///< RC channel 18 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint8_t chancount; ///< Total number of RC channels being received. This can be larger than 18, indicating that more channels are available but not given in this message. This value should be 0 when no RC channels are available. - uint8_t rssi; ///< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. -} mavlink_rc_channels_t; +MAVPACKED( +typedef struct __mavlink_rc_channels_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + uint16_t chan1_raw; /*< RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan2_raw; /*< RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan3_raw; /*< RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan4_raw; /*< RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan5_raw; /*< RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan6_raw; /*< RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan7_raw; /*< RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan8_raw; /*< RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan9_raw; /*< RC channel 9 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan10_raw; /*< RC channel 10 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan11_raw; /*< RC channel 11 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan12_raw; /*< RC channel 12 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan13_raw; /*< RC channel 13 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan14_raw; /*< RC channel 14 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan15_raw; /*< RC channel 15 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan16_raw; /*< RC channel 16 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan17_raw; /*< RC channel 17 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan18_raw; /*< RC channel 18 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint8_t chancount; /*< Total number of RC channels being received. This can be larger than 18, indicating that more channels are available but not given in this message. This value should be 0 when no RC channels are available.*/ + uint8_t rssi; /*< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown.*/ +}) mavlink_rc_channels_t; #define MAVLINK_MSG_ID_RC_CHANNELS_LEN 42 +#define MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN 42 #define MAVLINK_MSG_ID_65_LEN 42 +#define MAVLINK_MSG_ID_65_MIN_LEN 42 #define MAVLINK_MSG_ID_RC_CHANNELS_CRC 118 #define MAVLINK_MSG_ID_65_CRC 118 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RC_CHANNELS { \ - "RC_CHANNELS", \ - 21, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_t, time_boot_ms) }, \ + 65, \ + "RC_CHANNELS", \ + 21, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_t, time_boot_ms) }, \ { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_rc_channels_t, chan1_raw) }, \ { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_rc_channels_t, chan2_raw) }, \ { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_rc_channels_t, chan3_raw) }, \ @@ -61,7 +66,34 @@ typedef struct __mavlink_rc_channels_t { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_rc_channels_t, rssi) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RC_CHANNELS { \ + "RC_CHANNELS", \ + 21, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_t, time_boot_ms) }, \ + { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_rc_channels_t, chan1_raw) }, \ + { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_rc_channels_t, chan2_raw) }, \ + { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_rc_channels_t, chan3_raw) }, \ + { "chan4_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_rc_channels_t, chan4_raw) }, \ + { "chan5_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_rc_channels_t, chan5_raw) }, \ + { "chan6_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 14, offsetof(mavlink_rc_channels_t, chan6_raw) }, \ + { "chan7_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_rc_channels_t, chan7_raw) }, \ + { "chan8_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_rc_channels_t, chan8_raw) }, \ + { "chan9_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_rc_channels_t, chan9_raw) }, \ + { "chan10_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 22, offsetof(mavlink_rc_channels_t, chan10_raw) }, \ + { "chan11_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_rc_channels_t, chan11_raw) }, \ + { "chan12_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 26, offsetof(mavlink_rc_channels_t, chan12_raw) }, \ + { "chan13_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_rc_channels_t, chan13_raw) }, \ + { "chan14_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 30, offsetof(mavlink_rc_channels_t, chan14_raw) }, \ + { "chan15_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 32, offsetof(mavlink_rc_channels_t, chan15_raw) }, \ + { "chan16_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 34, offsetof(mavlink_rc_channels_t, chan16_raw) }, \ + { "chan17_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 36, offsetof(mavlink_rc_channels_t, chan17_raw) }, \ + { "chan18_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 38, offsetof(mavlink_rc_channels_t, chan18_raw) }, \ + { "chancount", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_rc_channels_t, chancount) }, \ + { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_rc_channels_t, rssi) }, \ + } \ +} +#endif /** * @brief Pack a rc_channels message @@ -93,66 +125,62 @@ typedef struct __mavlink_rc_channels_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t chancount, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint16_t chan13_raw, uint16_t chan14_raw, uint16_t chan15_raw, uint16_t chan16_raw, uint16_t chan17_raw, uint16_t chan18_raw, uint8_t rssi) + uint32_t time_boot_ms, uint8_t chancount, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint16_t chan13_raw, uint16_t chan14_raw, uint16_t chan15_raw, uint16_t chan16_raw, uint16_t chan17_raw, uint16_t chan18_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint16_t(buf, 20, chan9_raw); - _mav_put_uint16_t(buf, 22, chan10_raw); - _mav_put_uint16_t(buf, 24, chan11_raw); - _mav_put_uint16_t(buf, 26, chan12_raw); - _mav_put_uint16_t(buf, 28, chan13_raw); - _mav_put_uint16_t(buf, 30, chan14_raw); - _mav_put_uint16_t(buf, 32, chan15_raw); - _mav_put_uint16_t(buf, 34, chan16_raw); - _mav_put_uint16_t(buf, 36, chan17_raw); - _mav_put_uint16_t(buf, 38, chan18_raw); - _mav_put_uint8_t(buf, 40, chancount); - _mav_put_uint8_t(buf, 41, rssi); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint16_t(buf, 20, chan9_raw); + _mav_put_uint16_t(buf, 22, chan10_raw); + _mav_put_uint16_t(buf, 24, chan11_raw); + _mav_put_uint16_t(buf, 26, chan12_raw); + _mav_put_uint16_t(buf, 28, chan13_raw); + _mav_put_uint16_t(buf, 30, chan14_raw); + _mav_put_uint16_t(buf, 32, chan15_raw); + _mav_put_uint16_t(buf, 34, chan16_raw); + _mav_put_uint16_t(buf, 36, chan17_raw); + _mav_put_uint16_t(buf, 38, chan18_raw); + _mav_put_uint8_t(buf, 40, chancount); + _mav_put_uint8_t(buf, 41, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_LEN); #else - mavlink_rc_channels_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.chan9_raw = chan9_raw; - packet.chan10_raw = chan10_raw; - packet.chan11_raw = chan11_raw; - packet.chan12_raw = chan12_raw; - packet.chan13_raw = chan13_raw; - packet.chan14_raw = chan14_raw; - packet.chan15_raw = chan15_raw; - packet.chan16_raw = chan16_raw; - packet.chan17_raw = chan17_raw; - packet.chan18_raw = chan18_raw; - packet.chancount = chancount; - packet.rssi = rssi; + mavlink_rc_channels_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.chan9_raw = chan9_raw; + packet.chan10_raw = chan10_raw; + packet.chan11_raw = chan11_raw; + packet.chan12_raw = chan12_raw; + packet.chan13_raw = chan13_raw; + packet.chan14_raw = chan14_raw; + packet.chan15_raw = chan15_raw; + packet.chan16_raw = chan16_raw; + packet.chan17_raw = chan17_raw; + packet.chan18_raw = chan18_raw; + packet.chancount = chancount; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); } /** @@ -185,67 +213,63 @@ static inline uint16_t mavlink_msg_rc_channels_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t chancount,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw,uint16_t chan9_raw,uint16_t chan10_raw,uint16_t chan11_raw,uint16_t chan12_raw,uint16_t chan13_raw,uint16_t chan14_raw,uint16_t chan15_raw,uint16_t chan16_raw,uint16_t chan17_raw,uint16_t chan18_raw,uint8_t rssi) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t chancount,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw,uint16_t chan9_raw,uint16_t chan10_raw,uint16_t chan11_raw,uint16_t chan12_raw,uint16_t chan13_raw,uint16_t chan14_raw,uint16_t chan15_raw,uint16_t chan16_raw,uint16_t chan17_raw,uint16_t chan18_raw,uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint16_t(buf, 20, chan9_raw); - _mav_put_uint16_t(buf, 22, chan10_raw); - _mav_put_uint16_t(buf, 24, chan11_raw); - _mav_put_uint16_t(buf, 26, chan12_raw); - _mav_put_uint16_t(buf, 28, chan13_raw); - _mav_put_uint16_t(buf, 30, chan14_raw); - _mav_put_uint16_t(buf, 32, chan15_raw); - _mav_put_uint16_t(buf, 34, chan16_raw); - _mav_put_uint16_t(buf, 36, chan17_raw); - _mav_put_uint16_t(buf, 38, chan18_raw); - _mav_put_uint8_t(buf, 40, chancount); - _mav_put_uint8_t(buf, 41, rssi); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint16_t(buf, 20, chan9_raw); + _mav_put_uint16_t(buf, 22, chan10_raw); + _mav_put_uint16_t(buf, 24, chan11_raw); + _mav_put_uint16_t(buf, 26, chan12_raw); + _mav_put_uint16_t(buf, 28, chan13_raw); + _mav_put_uint16_t(buf, 30, chan14_raw); + _mav_put_uint16_t(buf, 32, chan15_raw); + _mav_put_uint16_t(buf, 34, chan16_raw); + _mav_put_uint16_t(buf, 36, chan17_raw); + _mav_put_uint16_t(buf, 38, chan18_raw); + _mav_put_uint8_t(buf, 40, chancount); + _mav_put_uint8_t(buf, 41, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_LEN); #else - mavlink_rc_channels_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.chan9_raw = chan9_raw; - packet.chan10_raw = chan10_raw; - packet.chan11_raw = chan11_raw; - packet.chan12_raw = chan12_raw; - packet.chan13_raw = chan13_raw; - packet.chan14_raw = chan14_raw; - packet.chan15_raw = chan15_raw; - packet.chan16_raw = chan16_raw; - packet.chan17_raw = chan17_raw; - packet.chan18_raw = chan18_raw; - packet.chancount = chancount; - packet.rssi = rssi; + mavlink_rc_channels_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.chan9_raw = chan9_raw; + packet.chan10_raw = chan10_raw; + packet.chan11_raw = chan11_raw; + packet.chan12_raw = chan12_raw; + packet.chan13_raw = chan13_raw; + packet.chan14_raw = chan14_raw; + packet.chan15_raw = chan15_raw; + packet.chan16_raw = chan16_raw; + packet.chan17_raw = chan17_raw; + packet.chan18_raw = chan18_raw; + packet.chancount = chancount; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); } /** @@ -258,7 +282,7 @@ static inline uint16_t mavlink_msg_rc_channels_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_rc_channels_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rc_channels_t* rc_channels) { - return mavlink_msg_rc_channels_pack(system_id, component_id, msg, rc_channels->time_boot_ms, rc_channels->chancount, rc_channels->chan1_raw, rc_channels->chan2_raw, rc_channels->chan3_raw, rc_channels->chan4_raw, rc_channels->chan5_raw, rc_channels->chan6_raw, rc_channels->chan7_raw, rc_channels->chan8_raw, rc_channels->chan9_raw, rc_channels->chan10_raw, rc_channels->chan11_raw, rc_channels->chan12_raw, rc_channels->chan13_raw, rc_channels->chan14_raw, rc_channels->chan15_raw, rc_channels->chan16_raw, rc_channels->chan17_raw, rc_channels->chan18_raw, rc_channels->rssi); + return mavlink_msg_rc_channels_pack(system_id, component_id, msg, rc_channels->time_boot_ms, rc_channels->chancount, rc_channels->chan1_raw, rc_channels->chan2_raw, rc_channels->chan3_raw, rc_channels->chan4_raw, rc_channels->chan5_raw, rc_channels->chan6_raw, rc_channels->chan7_raw, rc_channels->chan8_raw, rc_channels->chan9_raw, rc_channels->chan10_raw, rc_channels->chan11_raw, rc_channels->chan12_raw, rc_channels->chan13_raw, rc_channels->chan14_raw, rc_channels->chan15_raw, rc_channels->chan16_raw, rc_channels->chan17_raw, rc_channels->chan18_raw, rc_channels->rssi); } /** @@ -272,7 +296,7 @@ static inline uint16_t mavlink_msg_rc_channels_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_rc_channels_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rc_channels_t* rc_channels) { - return mavlink_msg_rc_channels_pack_chan(system_id, component_id, chan, msg, rc_channels->time_boot_ms, rc_channels->chancount, rc_channels->chan1_raw, rc_channels->chan2_raw, rc_channels->chan3_raw, rc_channels->chan4_raw, rc_channels->chan5_raw, rc_channels->chan6_raw, rc_channels->chan7_raw, rc_channels->chan8_raw, rc_channels->chan9_raw, rc_channels->chan10_raw, rc_channels->chan11_raw, rc_channels->chan12_raw, rc_channels->chan13_raw, rc_channels->chan14_raw, rc_channels->chan15_raw, rc_channels->chan16_raw, rc_channels->chan17_raw, rc_channels->chan18_raw, rc_channels->rssi); + return mavlink_msg_rc_channels_pack_chan(system_id, component_id, chan, msg, rc_channels->time_boot_ms, rc_channels->chancount, rc_channels->chan1_raw, rc_channels->chan2_raw, rc_channels->chan3_raw, rc_channels->chan4_raw, rc_channels->chan5_raw, rc_channels->chan6_raw, rc_channels->chan7_raw, rc_channels->chan8_raw, rc_channels->chan9_raw, rc_channels->chan10_raw, rc_channels->chan11_raw, rc_channels->chan12_raw, rc_channels->chan13_raw, rc_channels->chan14_raw, rc_channels->chan15_raw, rc_channels->chan16_raw, rc_channels->chan17_raw, rc_channels->chan18_raw, rc_channels->rssi); } /** @@ -306,63 +330,69 @@ static inline uint16_t mavlink_msg_rc_channels_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_rc_channels_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t chancount, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint16_t chan13_raw, uint16_t chan14_raw, uint16_t chan15_raw, uint16_t chan16_raw, uint16_t chan17_raw, uint16_t chan18_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint16_t(buf, 20, chan9_raw); - _mav_put_uint16_t(buf, 22, chan10_raw); - _mav_put_uint16_t(buf, 24, chan11_raw); - _mav_put_uint16_t(buf, 26, chan12_raw); - _mav_put_uint16_t(buf, 28, chan13_raw); - _mav_put_uint16_t(buf, 30, chan14_raw); - _mav_put_uint16_t(buf, 32, chan15_raw); - _mav_put_uint16_t(buf, 34, chan16_raw); - _mav_put_uint16_t(buf, 36, chan17_raw); - _mav_put_uint16_t(buf, 38, chan18_raw); - _mav_put_uint8_t(buf, 40, chancount); - _mav_put_uint8_t(buf, 41, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, buf, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint16_t(buf, 20, chan9_raw); + _mav_put_uint16_t(buf, 22, chan10_raw); + _mav_put_uint16_t(buf, 24, chan11_raw); + _mav_put_uint16_t(buf, 26, chan12_raw); + _mav_put_uint16_t(buf, 28, chan13_raw); + _mav_put_uint16_t(buf, 30, chan14_raw); + _mav_put_uint16_t(buf, 32, chan15_raw); + _mav_put_uint16_t(buf, 34, chan16_raw); + _mav_put_uint16_t(buf, 36, chan17_raw); + _mav_put_uint16_t(buf, 38, chan18_raw); + _mav_put_uint8_t(buf, 40, chancount); + _mav_put_uint8_t(buf, 41, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, buf, MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, buf, MAVLINK_MSG_ID_RC_CHANNELS_LEN); + mavlink_rc_channels_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.chan9_raw = chan9_raw; + packet.chan10_raw = chan10_raw; + packet.chan11_raw = chan11_raw; + packet.chan12_raw = chan12_raw; + packet.chan13_raw = chan13_raw; + packet.chan14_raw = chan14_raw; + packet.chan15_raw = chan15_raw; + packet.chan16_raw = chan16_raw; + packet.chan17_raw = chan17_raw; + packet.chan18_raw = chan18_raw; + packet.chancount = chancount; + packet.rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); #endif +} + +/** + * @brief Send a rc_channels message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rc_channels_send_struct(mavlink_channel_t chan, const mavlink_rc_channels_t* rc_channels) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rc_channels_send(chan, rc_channels->time_boot_ms, rc_channels->chancount, rc_channels->chan1_raw, rc_channels->chan2_raw, rc_channels->chan3_raw, rc_channels->chan4_raw, rc_channels->chan5_raw, rc_channels->chan6_raw, rc_channels->chan7_raw, rc_channels->chan8_raw, rc_channels->chan9_raw, rc_channels->chan10_raw, rc_channels->chan11_raw, rc_channels->chan12_raw, rc_channels->chan13_raw, rc_channels->chan14_raw, rc_channels->chan15_raw, rc_channels->chan16_raw, rc_channels->chan17_raw, rc_channels->chan18_raw, rc_channels->rssi); #else - mavlink_rc_channels_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.chan9_raw = chan9_raw; - packet.chan10_raw = chan10_raw; - packet.chan11_raw = chan11_raw; - packet.chan12_raw = chan12_raw; - packet.chan13_raw = chan13_raw; - packet.chan14_raw = chan14_raw; - packet.chan15_raw = chan15_raw; - packet.chan16_raw = chan16_raw; - packet.chan17_raw = chan17_raw; - packet.chan18_raw = chan18_raw; - packet.chancount = chancount; - packet.rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, (const char *)rc_channels, MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); #endif } @@ -377,63 +407,55 @@ static inline void mavlink_msg_rc_channels_send(mavlink_channel_t chan, uint32_t static inline void mavlink_msg_rc_channels_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t chancount, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint16_t chan9_raw, uint16_t chan10_raw, uint16_t chan11_raw, uint16_t chan12_raw, uint16_t chan13_raw, uint16_t chan14_raw, uint16_t chan15_raw, uint16_t chan16_raw, uint16_t chan17_raw, uint16_t chan18_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint16_t(buf, 20, chan9_raw); - _mav_put_uint16_t(buf, 22, chan10_raw); - _mav_put_uint16_t(buf, 24, chan11_raw); - _mav_put_uint16_t(buf, 26, chan12_raw); - _mav_put_uint16_t(buf, 28, chan13_raw); - _mav_put_uint16_t(buf, 30, chan14_raw); - _mav_put_uint16_t(buf, 32, chan15_raw); - _mav_put_uint16_t(buf, 34, chan16_raw); - _mav_put_uint16_t(buf, 36, chan17_raw); - _mav_put_uint16_t(buf, 38, chan18_raw); - _mav_put_uint8_t(buf, 40, chancount); - _mav_put_uint8_t(buf, 41, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, buf, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint16_t(buf, 20, chan9_raw); + _mav_put_uint16_t(buf, 22, chan10_raw); + _mav_put_uint16_t(buf, 24, chan11_raw); + _mav_put_uint16_t(buf, 26, chan12_raw); + _mav_put_uint16_t(buf, 28, chan13_raw); + _mav_put_uint16_t(buf, 30, chan14_raw); + _mav_put_uint16_t(buf, 32, chan15_raw); + _mav_put_uint16_t(buf, 34, chan16_raw); + _mav_put_uint16_t(buf, 36, chan17_raw); + _mav_put_uint16_t(buf, 38, chan18_raw); + _mav_put_uint8_t(buf, 40, chancount); + _mav_put_uint8_t(buf, 41, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, buf, MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, buf, MAVLINK_MSG_ID_RC_CHANNELS_LEN); -#endif -#else - mavlink_rc_channels_t *packet = (mavlink_rc_channels_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->chan1_raw = chan1_raw; - packet->chan2_raw = chan2_raw; - packet->chan3_raw = chan3_raw; - packet->chan4_raw = chan4_raw; - packet->chan5_raw = chan5_raw; - packet->chan6_raw = chan6_raw; - packet->chan7_raw = chan7_raw; - packet->chan8_raw = chan8_raw; - packet->chan9_raw = chan9_raw; - packet->chan10_raw = chan10_raw; - packet->chan11_raw = chan11_raw; - packet->chan12_raw = chan12_raw; - packet->chan13_raw = chan13_raw; - packet->chan14_raw = chan14_raw; - packet->chan15_raw = chan15_raw; - packet->chan16_raw = chan16_raw; - packet->chan17_raw = chan17_raw; - packet->chan18_raw = chan18_raw; - packet->chancount = chancount; - packet->rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_LEN); -#endif + mavlink_rc_channels_t *packet = (mavlink_rc_channels_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->chan1_raw = chan1_raw; + packet->chan2_raw = chan2_raw; + packet->chan3_raw = chan3_raw; + packet->chan4_raw = chan4_raw; + packet->chan5_raw = chan5_raw; + packet->chan6_raw = chan6_raw; + packet->chan7_raw = chan7_raw; + packet->chan8_raw = chan8_raw; + packet->chan9_raw = chan9_raw; + packet->chan10_raw = chan10_raw; + packet->chan11_raw = chan11_raw; + packet->chan12_raw = chan12_raw; + packet->chan13_raw = chan13_raw; + packet->chan14_raw = chan14_raw; + packet->chan15_raw = chan15_raw; + packet->chan16_raw = chan16_raw; + packet->chan17_raw = chan17_raw; + packet->chan18_raw = chan18_raw; + packet->chancount = chancount; + packet->rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_LEN, MAVLINK_MSG_ID_RC_CHANNELS_CRC); #endif } #endif @@ -450,7 +472,7 @@ static inline void mavlink_msg_rc_channels_send_buf(mavlink_message_t *msgbuf, m */ static inline uint32_t mavlink_msg_rc_channels_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -460,7 +482,7 @@ static inline uint32_t mavlink_msg_rc_channels_get_time_boot_ms(const mavlink_me */ static inline uint8_t mavlink_msg_rc_channels_get_chancount(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 40); + return _MAV_RETURN_uint8_t(msg, 40); } /** @@ -470,7 +492,7 @@ static inline uint8_t mavlink_msg_rc_channels_get_chancount(const mavlink_messag */ static inline uint16_t mavlink_msg_rc_channels_get_chan1_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -480,7 +502,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan1_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan2_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -490,7 +512,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan2_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan3_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -500,7 +522,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan3_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan4_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 10); + return _MAV_RETURN_uint16_t(msg, 10); } /** @@ -510,7 +532,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan4_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan5_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -520,7 +542,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan5_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan6_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 14); + return _MAV_RETURN_uint16_t(msg, 14); } /** @@ -530,7 +552,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan6_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan7_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** @@ -540,7 +562,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan7_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan8_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -550,7 +572,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan8_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan9_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 20); + return _MAV_RETURN_uint16_t(msg, 20); } /** @@ -560,7 +582,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan9_raw(const mavlink_messa */ static inline uint16_t mavlink_msg_rc_channels_get_chan10_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 22); + return _MAV_RETURN_uint16_t(msg, 22); } /** @@ -570,7 +592,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan10_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan11_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -580,7 +602,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan11_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan12_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 26); + return _MAV_RETURN_uint16_t(msg, 26); } /** @@ -590,7 +612,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan12_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan13_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -600,7 +622,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan13_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan14_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 30); + return _MAV_RETURN_uint16_t(msg, 30); } /** @@ -610,7 +632,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan14_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan15_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 32); + return _MAV_RETURN_uint16_t(msg, 32); } /** @@ -620,7 +642,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan15_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan16_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 34); + return _MAV_RETURN_uint16_t(msg, 34); } /** @@ -630,7 +652,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan16_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan17_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 36); + return _MAV_RETURN_uint16_t(msg, 36); } /** @@ -640,7 +662,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan17_raw(const mavlink_mess */ static inline uint16_t mavlink_msg_rc_channels_get_chan18_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 38); + return _MAV_RETURN_uint16_t(msg, 38); } /** @@ -650,7 +672,7 @@ static inline uint16_t mavlink_msg_rc_channels_get_chan18_raw(const mavlink_mess */ static inline uint8_t mavlink_msg_rc_channels_get_rssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 41); + return _MAV_RETURN_uint8_t(msg, 41); } /** @@ -661,29 +683,31 @@ static inline uint8_t mavlink_msg_rc_channels_get_rssi(const mavlink_message_t* */ static inline void mavlink_msg_rc_channels_decode(const mavlink_message_t* msg, mavlink_rc_channels_t* rc_channels) { -#if MAVLINK_NEED_BYTE_SWAP - rc_channels->time_boot_ms = mavlink_msg_rc_channels_get_time_boot_ms(msg); - rc_channels->chan1_raw = mavlink_msg_rc_channels_get_chan1_raw(msg); - rc_channels->chan2_raw = mavlink_msg_rc_channels_get_chan2_raw(msg); - rc_channels->chan3_raw = mavlink_msg_rc_channels_get_chan3_raw(msg); - rc_channels->chan4_raw = mavlink_msg_rc_channels_get_chan4_raw(msg); - rc_channels->chan5_raw = mavlink_msg_rc_channels_get_chan5_raw(msg); - rc_channels->chan6_raw = mavlink_msg_rc_channels_get_chan6_raw(msg); - rc_channels->chan7_raw = mavlink_msg_rc_channels_get_chan7_raw(msg); - rc_channels->chan8_raw = mavlink_msg_rc_channels_get_chan8_raw(msg); - rc_channels->chan9_raw = mavlink_msg_rc_channels_get_chan9_raw(msg); - rc_channels->chan10_raw = mavlink_msg_rc_channels_get_chan10_raw(msg); - rc_channels->chan11_raw = mavlink_msg_rc_channels_get_chan11_raw(msg); - rc_channels->chan12_raw = mavlink_msg_rc_channels_get_chan12_raw(msg); - rc_channels->chan13_raw = mavlink_msg_rc_channels_get_chan13_raw(msg); - rc_channels->chan14_raw = mavlink_msg_rc_channels_get_chan14_raw(msg); - rc_channels->chan15_raw = mavlink_msg_rc_channels_get_chan15_raw(msg); - rc_channels->chan16_raw = mavlink_msg_rc_channels_get_chan16_raw(msg); - rc_channels->chan17_raw = mavlink_msg_rc_channels_get_chan17_raw(msg); - rc_channels->chan18_raw = mavlink_msg_rc_channels_get_chan18_raw(msg); - rc_channels->chancount = mavlink_msg_rc_channels_get_chancount(msg); - rc_channels->rssi = mavlink_msg_rc_channels_get_rssi(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rc_channels->time_boot_ms = mavlink_msg_rc_channels_get_time_boot_ms(msg); + rc_channels->chan1_raw = mavlink_msg_rc_channels_get_chan1_raw(msg); + rc_channels->chan2_raw = mavlink_msg_rc_channels_get_chan2_raw(msg); + rc_channels->chan3_raw = mavlink_msg_rc_channels_get_chan3_raw(msg); + rc_channels->chan4_raw = mavlink_msg_rc_channels_get_chan4_raw(msg); + rc_channels->chan5_raw = mavlink_msg_rc_channels_get_chan5_raw(msg); + rc_channels->chan6_raw = mavlink_msg_rc_channels_get_chan6_raw(msg); + rc_channels->chan7_raw = mavlink_msg_rc_channels_get_chan7_raw(msg); + rc_channels->chan8_raw = mavlink_msg_rc_channels_get_chan8_raw(msg); + rc_channels->chan9_raw = mavlink_msg_rc_channels_get_chan9_raw(msg); + rc_channels->chan10_raw = mavlink_msg_rc_channels_get_chan10_raw(msg); + rc_channels->chan11_raw = mavlink_msg_rc_channels_get_chan11_raw(msg); + rc_channels->chan12_raw = mavlink_msg_rc_channels_get_chan12_raw(msg); + rc_channels->chan13_raw = mavlink_msg_rc_channels_get_chan13_raw(msg); + rc_channels->chan14_raw = mavlink_msg_rc_channels_get_chan14_raw(msg); + rc_channels->chan15_raw = mavlink_msg_rc_channels_get_chan15_raw(msg); + rc_channels->chan16_raw = mavlink_msg_rc_channels_get_chan16_raw(msg); + rc_channels->chan17_raw = mavlink_msg_rc_channels_get_chan17_raw(msg); + rc_channels->chan18_raw = mavlink_msg_rc_channels_get_chan18_raw(msg); + rc_channels->chancount = mavlink_msg_rc_channels_get_chancount(msg); + rc_channels->rssi = mavlink_msg_rc_channels_get_rssi(msg); #else - memcpy(rc_channels, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RC_CHANNELS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RC_CHANNELS_LEN? msg->len : MAVLINK_MSG_ID_RC_CHANNELS_LEN; + memset(rc_channels, 0, MAVLINK_MSG_ID_RC_CHANNELS_LEN); + memcpy(rc_channels, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_override.h b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_override.h index 15d4c6f958..970e926935 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_override.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_override.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE RC_CHANNELS_OVERRIDE PACKING #define MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE 70 -typedef struct __mavlink_rc_channels_override_t -{ - uint16_t chan1_raw; ///< RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint16_t chan2_raw; ///< RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint16_t chan3_raw; ///< RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint16_t chan4_raw; ///< RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint16_t chan5_raw; ///< RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint16_t chan6_raw; ///< RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint16_t chan7_raw; ///< RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint16_t chan8_raw; ///< RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field. - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_rc_channels_override_t; +MAVPACKED( +typedef struct __mavlink_rc_channels_override_t { + uint16_t chan1_raw; /*< RC channel 1 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint16_t chan2_raw; /*< RC channel 2 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint16_t chan3_raw; /*< RC channel 3 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint16_t chan4_raw; /*< RC channel 4 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint16_t chan5_raw; /*< RC channel 5 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint16_t chan6_raw; /*< RC channel 6 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint16_t chan7_raw; /*< RC channel 7 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint16_t chan8_raw; /*< RC channel 8 value, in microseconds. A value of UINT16_MAX means to ignore this field.*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_rc_channels_override_t; #define MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN 18 +#define MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN 18 #define MAVLINK_MSG_ID_70_LEN 18 +#define MAVLINK_MSG_ID_70_MIN_LEN 18 #define MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC 124 #define MAVLINK_MSG_ID_70_CRC 124 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE { \ - "RC_CHANNELS_OVERRIDE", \ - 10, \ - { { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_rc_channels_override_t, chan1_raw) }, \ + 70, \ + "RC_CHANNELS_OVERRIDE", \ + 10, \ + { { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_rc_channels_override_t, chan1_raw) }, \ { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_rc_channels_override_t, chan2_raw) }, \ { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_rc_channels_override_t, chan3_raw) }, \ { "chan4_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_rc_channels_override_t, chan4_raw) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_rc_channels_override_t { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 17, offsetof(mavlink_rc_channels_override_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RC_CHANNELS_OVERRIDE { \ + "RC_CHANNELS_OVERRIDE", \ + 10, \ + { { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_rc_channels_override_t, chan1_raw) }, \ + { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 2, offsetof(mavlink_rc_channels_override_t, chan2_raw) }, \ + { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_rc_channels_override_t, chan3_raw) }, \ + { "chan4_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_rc_channels_override_t, chan4_raw) }, \ + { "chan5_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_rc_channels_override_t, chan5_raw) }, \ + { "chan6_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_rc_channels_override_t, chan6_raw) }, \ + { "chan7_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_rc_channels_override_t, chan7_raw) }, \ + { "chan8_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 14, offsetof(mavlink_rc_channels_override_t, chan8_raw) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 16, offsetof(mavlink_rc_channels_override_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 17, offsetof(mavlink_rc_channels_override_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a rc_channels_override message @@ -60,44 +81,40 @@ typedef struct __mavlink_rc_channels_override_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_override_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw) + uint8_t target_system, uint8_t target_component, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN]; - _mav_put_uint16_t(buf, 0, chan1_raw); - _mav_put_uint16_t(buf, 2, chan2_raw); - _mav_put_uint16_t(buf, 4, chan3_raw); - _mav_put_uint16_t(buf, 6, chan4_raw); - _mav_put_uint16_t(buf, 8, chan5_raw); - _mav_put_uint16_t(buf, 10, chan6_raw); - _mav_put_uint16_t(buf, 12, chan7_raw); - _mav_put_uint16_t(buf, 14, chan8_raw); - _mav_put_uint8_t(buf, 16, target_system); - _mav_put_uint8_t(buf, 17, target_component); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN]; + _mav_put_uint16_t(buf, 0, chan1_raw); + _mav_put_uint16_t(buf, 2, chan2_raw); + _mav_put_uint16_t(buf, 4, chan3_raw); + _mav_put_uint16_t(buf, 6, chan4_raw); + _mav_put_uint16_t(buf, 8, chan5_raw); + _mav_put_uint16_t(buf, 10, chan6_raw); + _mav_put_uint16_t(buf, 12, chan7_raw); + _mav_put_uint16_t(buf, 14, chan8_raw); + _mav_put_uint8_t(buf, 16, target_system); + _mav_put_uint8_t(buf, 17, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); #else - mavlink_rc_channels_override_t packet; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_rc_channels_override_t packet; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_rc_channels_override_pack(uint8_t system_id, * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_override_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN]; - _mav_put_uint16_t(buf, 0, chan1_raw); - _mav_put_uint16_t(buf, 2, chan2_raw); - _mav_put_uint16_t(buf, 4, chan3_raw); - _mav_put_uint16_t(buf, 6, chan4_raw); - _mav_put_uint16_t(buf, 8, chan5_raw); - _mav_put_uint16_t(buf, 10, chan6_raw); - _mav_put_uint16_t(buf, 12, chan7_raw); - _mav_put_uint16_t(buf, 14, chan8_raw); - _mav_put_uint8_t(buf, 16, target_system); - _mav_put_uint8_t(buf, 17, target_component); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN]; + _mav_put_uint16_t(buf, 0, chan1_raw); + _mav_put_uint16_t(buf, 2, chan2_raw); + _mav_put_uint16_t(buf, 4, chan3_raw); + _mav_put_uint16_t(buf, 6, chan4_raw); + _mav_put_uint16_t(buf, 8, chan5_raw); + _mav_put_uint16_t(buf, 10, chan6_raw); + _mav_put_uint16_t(buf, 12, chan7_raw); + _mav_put_uint16_t(buf, 14, chan8_raw); + _mav_put_uint8_t(buf, 16, target_system); + _mav_put_uint8_t(buf, 17, target_component); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); #else - mavlink_rc_channels_override_t packet; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.target_system = target_system; - packet.target_component = target_component; + mavlink_rc_channels_override_t packet; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.target_system = target_system; + packet.target_component = target_component; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_pack_chan(uint8_t system */ static inline uint16_t mavlink_msg_rc_channels_override_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rc_channels_override_t* rc_channels_override) { - return mavlink_msg_rc_channels_override_pack(system_id, component_id, msg, rc_channels_override->target_system, rc_channels_override->target_component, rc_channels_override->chan1_raw, rc_channels_override->chan2_raw, rc_channels_override->chan3_raw, rc_channels_override->chan4_raw, rc_channels_override->chan5_raw, rc_channels_override->chan6_raw, rc_channels_override->chan7_raw, rc_channels_override->chan8_raw); + return mavlink_msg_rc_channels_override_pack(system_id, component_id, msg, rc_channels_override->target_system, rc_channels_override->target_component, rc_channels_override->chan1_raw, rc_channels_override->chan2_raw, rc_channels_override->chan3_raw, rc_channels_override->chan4_raw, rc_channels_override->chan5_raw, rc_channels_override->chan6_raw, rc_channels_override->chan7_raw, rc_channels_override->chan8_raw); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_encode(uint8_t system_id */ static inline uint16_t mavlink_msg_rc_channels_override_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rc_channels_override_t* rc_channels_override) { - return mavlink_msg_rc_channels_override_pack_chan(system_id, component_id, chan, msg, rc_channels_override->target_system, rc_channels_override->target_component, rc_channels_override->chan1_raw, rc_channels_override->chan2_raw, rc_channels_override->chan3_raw, rc_channels_override->chan4_raw, rc_channels_override->chan5_raw, rc_channels_override->chan6_raw, rc_channels_override->chan7_raw, rc_channels_override->chan8_raw); + return mavlink_msg_rc_channels_override_pack_chan(system_id, component_id, chan, msg, rc_channels_override->target_system, rc_channels_override->target_component, rc_channels_override->chan1_raw, rc_channels_override->chan2_raw, rc_channels_override->chan3_raw, rc_channels_override->chan4_raw, rc_channels_override->chan5_raw, rc_channels_override->chan6_raw, rc_channels_override->chan7_raw, rc_channels_override->chan8_raw); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_rc_channels_override_encode_chan(uint8_t syst static inline void mavlink_msg_rc_channels_override_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN]; - _mav_put_uint16_t(buf, 0, chan1_raw); - _mav_put_uint16_t(buf, 2, chan2_raw); - _mav_put_uint16_t(buf, 4, chan3_raw); - _mav_put_uint16_t(buf, 6, chan4_raw); - _mav_put_uint16_t(buf, 8, chan5_raw); - _mav_put_uint16_t(buf, 10, chan6_raw); - _mav_put_uint16_t(buf, 12, chan7_raw); - _mav_put_uint16_t(buf, 14, chan8_raw); - _mav_put_uint8_t(buf, 16, target_system); - _mav_put_uint8_t(buf, 17, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN]; + _mav_put_uint16_t(buf, 0, chan1_raw); + _mav_put_uint16_t(buf, 2, chan2_raw); + _mav_put_uint16_t(buf, 4, chan3_raw); + _mav_put_uint16_t(buf, 6, chan4_raw); + _mav_put_uint16_t(buf, 8, chan5_raw); + _mav_put_uint16_t(buf, 10, chan6_raw); + _mav_put_uint16_t(buf, 12, chan7_raw); + _mav_put_uint16_t(buf, 14, chan8_raw); + _mav_put_uint8_t(buf, 16, target_system); + _mav_put_uint8_t(buf, 17, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); + mavlink_rc_channels_override_t packet; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.target_system = target_system; + packet.target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); #endif +} + +/** + * @brief Send a rc_channels_override message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rc_channels_override_send_struct(mavlink_channel_t chan, const mavlink_rc_channels_override_t* rc_channels_override) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rc_channels_override_send(chan, rc_channels_override->target_system, rc_channels_override->target_component, rc_channels_override->chan1_raw, rc_channels_override->chan2_raw, rc_channels_override->chan3_raw, rc_channels_override->chan4_raw, rc_channels_override->chan5_raw, rc_channels_override->chan6_raw, rc_channels_override->chan7_raw, rc_channels_override->chan8_raw); #else - mavlink_rc_channels_override_t packet; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.target_system = target_system; - packet.target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, (const char *)rc_channels_override, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_rc_channels_override_send(mavlink_channel_t chan, static inline void mavlink_msg_rc_channels_override_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, chan1_raw); - _mav_put_uint16_t(buf, 2, chan2_raw); - _mav_put_uint16_t(buf, 4, chan3_raw); - _mav_put_uint16_t(buf, 6, chan4_raw); - _mav_put_uint16_t(buf, 8, chan5_raw); - _mav_put_uint16_t(buf, 10, chan6_raw); - _mav_put_uint16_t(buf, 12, chan7_raw); - _mav_put_uint16_t(buf, 14, chan8_raw); - _mav_put_uint8_t(buf, 16, target_system); - _mav_put_uint8_t(buf, 17, target_component); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); -#endif -#else - mavlink_rc_channels_override_t *packet = (mavlink_rc_channels_override_t *)msgbuf; - packet->chan1_raw = chan1_raw; - packet->chan2_raw = chan2_raw; - packet->chan3_raw = chan3_raw; - packet->chan4_raw = chan4_raw; - packet->chan5_raw = chan5_raw; - packet->chan6_raw = chan6_raw; - packet->chan7_raw = chan7_raw; - packet->chan8_raw = chan8_raw; - packet->target_system = target_system; - packet->target_component = target_component; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, chan1_raw); + _mav_put_uint16_t(buf, 2, chan2_raw); + _mav_put_uint16_t(buf, 4, chan3_raw); + _mav_put_uint16_t(buf, 6, chan4_raw); + _mav_put_uint16_t(buf, 8, chan5_raw); + _mav_put_uint16_t(buf, 10, chan6_raw); + _mav_put_uint16_t(buf, 12, chan7_raw); + _mav_put_uint16_t(buf, 14, chan8_raw); + _mav_put_uint8_t(buf, 16, target_system); + _mav_put_uint8_t(buf, 17, target_component); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, buf, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); -#endif + mavlink_rc_channels_override_t *packet = (mavlink_rc_channels_override_t *)msgbuf; + packet->chan1_raw = chan1_raw; + packet->chan2_raw = chan2_raw; + packet->chan3_raw = chan3_raw; + packet->chan4_raw = chan4_raw; + packet->chan5_raw = chan5_raw; + packet->chan6_raw = chan6_raw; + packet->chan7_raw = chan7_raw; + packet->chan8_raw = chan8_raw; + packet->target_system = target_system; + packet->target_component = target_component; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_rc_channels_override_send_buf(mavlink_message_t * */ static inline uint8_t mavlink_msg_rc_channels_override_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 16); + return _MAV_RETURN_uint8_t(msg, 16); } /** @@ -317,7 +328,7 @@ static inline uint8_t mavlink_msg_rc_channels_override_get_target_system(const m */ static inline uint8_t mavlink_msg_rc_channels_override_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 17); + return _MAV_RETURN_uint8_t(msg, 17); } /** @@ -327,7 +338,7 @@ static inline uint8_t mavlink_msg_rc_channels_override_get_target_component(cons */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan1_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -337,7 +348,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan1_raw(const mavl */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan2_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 2); + return _MAV_RETURN_uint16_t(msg, 2); } /** @@ -347,7 +358,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan2_raw(const mavl */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan3_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -357,7 +368,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan3_raw(const mavl */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan4_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -367,7 +378,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan4_raw(const mavl */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan5_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -377,7 +388,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan5_raw(const mavl */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan6_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 10); + return _MAV_RETURN_uint16_t(msg, 10); } /** @@ -387,7 +398,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan6_raw(const mavl */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan7_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -397,7 +408,7 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan7_raw(const mavl */ static inline uint16_t mavlink_msg_rc_channels_override_get_chan8_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 14); + return _MAV_RETURN_uint16_t(msg, 14); } /** @@ -408,18 +419,20 @@ static inline uint16_t mavlink_msg_rc_channels_override_get_chan8_raw(const mavl */ static inline void mavlink_msg_rc_channels_override_decode(const mavlink_message_t* msg, mavlink_rc_channels_override_t* rc_channels_override) { -#if MAVLINK_NEED_BYTE_SWAP - rc_channels_override->chan1_raw = mavlink_msg_rc_channels_override_get_chan1_raw(msg); - rc_channels_override->chan2_raw = mavlink_msg_rc_channels_override_get_chan2_raw(msg); - rc_channels_override->chan3_raw = mavlink_msg_rc_channels_override_get_chan3_raw(msg); - rc_channels_override->chan4_raw = mavlink_msg_rc_channels_override_get_chan4_raw(msg); - rc_channels_override->chan5_raw = mavlink_msg_rc_channels_override_get_chan5_raw(msg); - rc_channels_override->chan6_raw = mavlink_msg_rc_channels_override_get_chan6_raw(msg); - rc_channels_override->chan7_raw = mavlink_msg_rc_channels_override_get_chan7_raw(msg); - rc_channels_override->chan8_raw = mavlink_msg_rc_channels_override_get_chan8_raw(msg); - rc_channels_override->target_system = mavlink_msg_rc_channels_override_get_target_system(msg); - rc_channels_override->target_component = mavlink_msg_rc_channels_override_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rc_channels_override->chan1_raw = mavlink_msg_rc_channels_override_get_chan1_raw(msg); + rc_channels_override->chan2_raw = mavlink_msg_rc_channels_override_get_chan2_raw(msg); + rc_channels_override->chan3_raw = mavlink_msg_rc_channels_override_get_chan3_raw(msg); + rc_channels_override->chan4_raw = mavlink_msg_rc_channels_override_get_chan4_raw(msg); + rc_channels_override->chan5_raw = mavlink_msg_rc_channels_override_get_chan5_raw(msg); + rc_channels_override->chan6_raw = mavlink_msg_rc_channels_override_get_chan6_raw(msg); + rc_channels_override->chan7_raw = mavlink_msg_rc_channels_override_get_chan7_raw(msg); + rc_channels_override->chan8_raw = mavlink_msg_rc_channels_override_get_chan8_raw(msg); + rc_channels_override->target_system = mavlink_msg_rc_channels_override_get_target_system(msg); + rc_channels_override->target_component = mavlink_msg_rc_channels_override_get_target_component(msg); #else - memcpy(rc_channels_override, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN? msg->len : MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN; + memset(rc_channels_override, 0, MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_LEN); + memcpy(rc_channels_override, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_raw.h b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_raw.h index d75a5934aa..87d1b4a82f 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_raw.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_raw.h @@ -1,34 +1,39 @@ +#pragma once // MESSAGE RC_CHANNELS_RAW PACKING #define MAVLINK_MSG_ID_RC_CHANNELS_RAW 35 -typedef struct __mavlink_rc_channels_raw_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - uint16_t chan1_raw; ///< RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan2_raw; ///< RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan3_raw; ///< RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan4_raw; ///< RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan5_raw; ///< RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan6_raw; ///< RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan7_raw; ///< RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint16_t chan8_raw; ///< RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused. - uint8_t port; ///< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - uint8_t rssi; ///< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. -} mavlink_rc_channels_raw_t; +MAVPACKED( +typedef struct __mavlink_rc_channels_raw_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + uint16_t chan1_raw; /*< RC channel 1 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan2_raw; /*< RC channel 2 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan3_raw; /*< RC channel 3 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan4_raw; /*< RC channel 4 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan5_raw; /*< RC channel 5 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan6_raw; /*< RC channel 6 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan7_raw; /*< RC channel 7 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint16_t chan8_raw; /*< RC channel 8 value, in microseconds. A value of UINT16_MAX implies the channel is unused.*/ + uint8_t port; /*< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos.*/ + uint8_t rssi; /*< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown.*/ +}) mavlink_rc_channels_raw_t; #define MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN 22 +#define MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN 22 #define MAVLINK_MSG_ID_35_LEN 22 +#define MAVLINK_MSG_ID_35_MIN_LEN 22 #define MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC 244 #define MAVLINK_MSG_ID_35_CRC 244 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW { \ - "RC_CHANNELS_RAW", \ - 11, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_raw_t, time_boot_ms) }, \ + 35, \ + "RC_CHANNELS_RAW", \ + 11, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_raw_t, time_boot_ms) }, \ { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_rc_channels_raw_t, chan1_raw) }, \ { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_rc_channels_raw_t, chan2_raw) }, \ { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_rc_channels_raw_t, chan3_raw) }, \ @@ -41,7 +46,24 @@ typedef struct __mavlink_rc_channels_raw_t { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_rc_channels_raw_t, rssi) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RC_CHANNELS_RAW { \ + "RC_CHANNELS_RAW", \ + 11, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_raw_t, time_boot_ms) }, \ + { "chan1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_rc_channels_raw_t, chan1_raw) }, \ + { "chan2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_rc_channels_raw_t, chan2_raw) }, \ + { "chan3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_rc_channels_raw_t, chan3_raw) }, \ + { "chan4_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_rc_channels_raw_t, chan4_raw) }, \ + { "chan5_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_rc_channels_raw_t, chan5_raw) }, \ + { "chan6_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 14, offsetof(mavlink_rc_channels_raw_t, chan6_raw) }, \ + { "chan7_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_rc_channels_raw_t, chan7_raw) }, \ + { "chan8_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_rc_channels_raw_t, chan8_raw) }, \ + { "port", NULL, MAVLINK_TYPE_UINT8_T, 0, 20, offsetof(mavlink_rc_channels_raw_t, port) }, \ + { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_rc_channels_raw_t, rssi) }, \ + } \ +} +#endif /** * @brief Pack a rc_channels_raw message @@ -63,46 +85,42 @@ typedef struct __mavlink_rc_channels_raw_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_raw_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t port, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint8_t rssi) + uint32_t time_boot_ms, uint8_t port, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); #else - mavlink_rc_channels_raw_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.port = port; - packet.rssi = rssi; + mavlink_rc_channels_raw_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.port = port; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_RAW; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); } /** @@ -125,47 +143,43 @@ static inline uint16_t mavlink_msg_rc_channels_raw_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_raw_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t port,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw,uint8_t rssi) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t port,uint16_t chan1_raw,uint16_t chan2_raw,uint16_t chan3_raw,uint16_t chan4_raw,uint16_t chan5_raw,uint16_t chan6_raw,uint16_t chan7_raw,uint16_t chan8_raw,uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); #else - mavlink_rc_channels_raw_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.port = port; - packet.rssi = rssi; + mavlink_rc_channels_raw_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.port = port; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_RAW; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); } /** @@ -178,7 +192,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_rc_channels_raw_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rc_channels_raw_t* rc_channels_raw) { - return mavlink_msg_rc_channels_raw_pack(system_id, component_id, msg, rc_channels_raw->time_boot_ms, rc_channels_raw->port, rc_channels_raw->chan1_raw, rc_channels_raw->chan2_raw, rc_channels_raw->chan3_raw, rc_channels_raw->chan4_raw, rc_channels_raw->chan5_raw, rc_channels_raw->chan6_raw, rc_channels_raw->chan7_raw, rc_channels_raw->chan8_raw, rc_channels_raw->rssi); + return mavlink_msg_rc_channels_raw_pack(system_id, component_id, msg, rc_channels_raw->time_boot_ms, rc_channels_raw->port, rc_channels_raw->chan1_raw, rc_channels_raw->chan2_raw, rc_channels_raw->chan3_raw, rc_channels_raw->chan4_raw, rc_channels_raw->chan5_raw, rc_channels_raw->chan6_raw, rc_channels_raw->chan7_raw, rc_channels_raw->chan8_raw, rc_channels_raw->rssi); } /** @@ -192,7 +206,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_rc_channels_raw_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rc_channels_raw_t* rc_channels_raw) { - return mavlink_msg_rc_channels_raw_pack_chan(system_id, component_id, chan, msg, rc_channels_raw->time_boot_ms, rc_channels_raw->port, rc_channels_raw->chan1_raw, rc_channels_raw->chan2_raw, rc_channels_raw->chan3_raw, rc_channels_raw->chan4_raw, rc_channels_raw->chan5_raw, rc_channels_raw->chan6_raw, rc_channels_raw->chan7_raw, rc_channels_raw->chan8_raw, rc_channels_raw->rssi); + return mavlink_msg_rc_channels_raw_pack_chan(system_id, component_id, chan, msg, rc_channels_raw->time_boot_ms, rc_channels_raw->port, rc_channels_raw->chan1_raw, rc_channels_raw->chan2_raw, rc_channels_raw->chan3_raw, rc_channels_raw->chan4_raw, rc_channels_raw->chan5_raw, rc_channels_raw->chan6_raw, rc_channels_raw->chan7_raw, rc_channels_raw->chan8_raw, rc_channels_raw->rssi); } /** @@ -216,43 +230,49 @@ static inline uint16_t mavlink_msg_rc_channels_raw_encode_chan(uint8_t system_id static inline void mavlink_msg_rc_channels_raw_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t port, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); + mavlink_rc_channels_raw_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_raw = chan1_raw; + packet.chan2_raw = chan2_raw; + packet.chan3_raw = chan3_raw; + packet.chan4_raw = chan4_raw; + packet.chan5_raw = chan5_raw; + packet.chan6_raw = chan6_raw; + packet.chan7_raw = chan7_raw; + packet.chan8_raw = chan8_raw; + packet.port = port; + packet.rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); #endif +} + +/** + * @brief Send a rc_channels_raw message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rc_channels_raw_send_struct(mavlink_channel_t chan, const mavlink_rc_channels_raw_t* rc_channels_raw) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rc_channels_raw_send(chan, rc_channels_raw->time_boot_ms, rc_channels_raw->port, rc_channels_raw->chan1_raw, rc_channels_raw->chan2_raw, rc_channels_raw->chan3_raw, rc_channels_raw->chan4_raw, rc_channels_raw->chan5_raw, rc_channels_raw->chan6_raw, rc_channels_raw->chan7_raw, rc_channels_raw->chan8_raw, rc_channels_raw->rssi); #else - mavlink_rc_channels_raw_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_raw = chan1_raw; - packet.chan2_raw = chan2_raw; - packet.chan3_raw = chan3_raw; - packet.chan4_raw = chan4_raw; - packet.chan5_raw = chan5_raw; - packet.chan6_raw = chan6_raw; - packet.chan7_raw = chan7_raw; - packet.chan8_raw = chan8_raw; - packet.port = port; - packet.rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, (const char *)rc_channels_raw, MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); #endif } @@ -267,43 +287,35 @@ static inline void mavlink_msg_rc_channels_raw_send(mavlink_channel_t chan, uint static inline void mavlink_msg_rc_channels_raw_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t port, uint16_t chan1_raw, uint16_t chan2_raw, uint16_t chan3_raw, uint16_t chan4_raw, uint16_t chan5_raw, uint16_t chan6_raw, uint16_t chan7_raw, uint16_t chan8_raw, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_uint16_t(buf, 4, chan1_raw); - _mav_put_uint16_t(buf, 6, chan2_raw); - _mav_put_uint16_t(buf, 8, chan3_raw); - _mav_put_uint16_t(buf, 10, chan4_raw); - _mav_put_uint16_t(buf, 12, chan5_raw); - _mav_put_uint16_t(buf, 14, chan6_raw); - _mav_put_uint16_t(buf, 16, chan7_raw); - _mav_put_uint16_t(buf, 18, chan8_raw); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_uint16_t(buf, 4, chan1_raw); + _mav_put_uint16_t(buf, 6, chan2_raw); + _mav_put_uint16_t(buf, 8, chan3_raw); + _mav_put_uint16_t(buf, 10, chan4_raw); + _mav_put_uint16_t(buf, 12, chan5_raw); + _mav_put_uint16_t(buf, 14, chan6_raw); + _mav_put_uint16_t(buf, 16, chan7_raw); + _mav_put_uint16_t(buf, 18, chan8_raw); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, buf, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); -#endif -#else - mavlink_rc_channels_raw_t *packet = (mavlink_rc_channels_raw_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->chan1_raw = chan1_raw; - packet->chan2_raw = chan2_raw; - packet->chan3_raw = chan3_raw; - packet->chan4_raw = chan4_raw; - packet->chan5_raw = chan5_raw; - packet->chan6_raw = chan6_raw; - packet->chan7_raw = chan7_raw; - packet->chan8_raw = chan8_raw; - packet->port = port; - packet->rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); -#endif + mavlink_rc_channels_raw_t *packet = (mavlink_rc_channels_raw_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->chan1_raw = chan1_raw; + packet->chan2_raw = chan2_raw; + packet->chan3_raw = chan3_raw; + packet->chan4_raw = chan4_raw; + packet->chan5_raw = chan5_raw; + packet->chan6_raw = chan6_raw; + packet->chan7_raw = chan7_raw; + packet->chan8_raw = chan8_raw; + packet->port = port; + packet->rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_RAW, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN, MAVLINK_MSG_ID_RC_CHANNELS_RAW_CRC); #endif } #endif @@ -320,7 +332,7 @@ static inline void mavlink_msg_rc_channels_raw_send_buf(mavlink_message_t *msgbu */ static inline uint32_t mavlink_msg_rc_channels_raw_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -330,7 +342,7 @@ static inline uint32_t mavlink_msg_rc_channels_raw_get_time_boot_ms(const mavlin */ static inline uint8_t mavlink_msg_rc_channels_raw_get_port(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 20); + return _MAV_RETURN_uint8_t(msg, 20); } /** @@ -340,7 +352,7 @@ static inline uint8_t mavlink_msg_rc_channels_raw_get_port(const mavlink_message */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan1_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -350,7 +362,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan1_raw(const mavlink_m */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan2_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -360,7 +372,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan2_raw(const mavlink_m */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan3_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -370,7 +382,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan3_raw(const mavlink_m */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan4_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 10); + return _MAV_RETURN_uint16_t(msg, 10); } /** @@ -380,7 +392,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan4_raw(const mavlink_m */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan5_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -390,7 +402,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan5_raw(const mavlink_m */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan6_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 14); + return _MAV_RETURN_uint16_t(msg, 14); } /** @@ -400,7 +412,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan6_raw(const mavlink_m */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan7_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** @@ -410,7 +422,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan7_raw(const mavlink_m */ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan8_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -420,7 +432,7 @@ static inline uint16_t mavlink_msg_rc_channels_raw_get_chan8_raw(const mavlink_m */ static inline uint8_t mavlink_msg_rc_channels_raw_get_rssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 21); + return _MAV_RETURN_uint8_t(msg, 21); } /** @@ -431,19 +443,21 @@ static inline uint8_t mavlink_msg_rc_channels_raw_get_rssi(const mavlink_message */ static inline void mavlink_msg_rc_channels_raw_decode(const mavlink_message_t* msg, mavlink_rc_channels_raw_t* rc_channels_raw) { -#if MAVLINK_NEED_BYTE_SWAP - rc_channels_raw->time_boot_ms = mavlink_msg_rc_channels_raw_get_time_boot_ms(msg); - rc_channels_raw->chan1_raw = mavlink_msg_rc_channels_raw_get_chan1_raw(msg); - rc_channels_raw->chan2_raw = mavlink_msg_rc_channels_raw_get_chan2_raw(msg); - rc_channels_raw->chan3_raw = mavlink_msg_rc_channels_raw_get_chan3_raw(msg); - rc_channels_raw->chan4_raw = mavlink_msg_rc_channels_raw_get_chan4_raw(msg); - rc_channels_raw->chan5_raw = mavlink_msg_rc_channels_raw_get_chan5_raw(msg); - rc_channels_raw->chan6_raw = mavlink_msg_rc_channels_raw_get_chan6_raw(msg); - rc_channels_raw->chan7_raw = mavlink_msg_rc_channels_raw_get_chan7_raw(msg); - rc_channels_raw->chan8_raw = mavlink_msg_rc_channels_raw_get_chan8_raw(msg); - rc_channels_raw->port = mavlink_msg_rc_channels_raw_get_port(msg); - rc_channels_raw->rssi = mavlink_msg_rc_channels_raw_get_rssi(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rc_channels_raw->time_boot_ms = mavlink_msg_rc_channels_raw_get_time_boot_ms(msg); + rc_channels_raw->chan1_raw = mavlink_msg_rc_channels_raw_get_chan1_raw(msg); + rc_channels_raw->chan2_raw = mavlink_msg_rc_channels_raw_get_chan2_raw(msg); + rc_channels_raw->chan3_raw = mavlink_msg_rc_channels_raw_get_chan3_raw(msg); + rc_channels_raw->chan4_raw = mavlink_msg_rc_channels_raw_get_chan4_raw(msg); + rc_channels_raw->chan5_raw = mavlink_msg_rc_channels_raw_get_chan5_raw(msg); + rc_channels_raw->chan6_raw = mavlink_msg_rc_channels_raw_get_chan6_raw(msg); + rc_channels_raw->chan7_raw = mavlink_msg_rc_channels_raw_get_chan7_raw(msg); + rc_channels_raw->chan8_raw = mavlink_msg_rc_channels_raw_get_chan8_raw(msg); + rc_channels_raw->port = mavlink_msg_rc_channels_raw_get_port(msg); + rc_channels_raw->rssi = mavlink_msg_rc_channels_raw_get_rssi(msg); #else - memcpy(rc_channels_raw, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN? msg->len : MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN; + memset(rc_channels_raw, 0, MAVLINK_MSG_ID_RC_CHANNELS_RAW_LEN); + memcpy(rc_channels_raw, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_scaled.h b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_scaled.h index f400f987dd..5b04333149 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_scaled.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_rc_channels_scaled.h @@ -1,34 +1,39 @@ +#pragma once // MESSAGE RC_CHANNELS_SCALED PACKING #define MAVLINK_MSG_ID_RC_CHANNELS_SCALED 34 -typedef struct __mavlink_rc_channels_scaled_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - int16_t chan1_scaled; ///< RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - int16_t chan2_scaled; ///< RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - int16_t chan3_scaled; ///< RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - int16_t chan4_scaled; ///< RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - int16_t chan5_scaled; ///< RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - int16_t chan6_scaled; ///< RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - int16_t chan7_scaled; ///< RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - int16_t chan8_scaled; ///< RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX. - uint8_t port; ///< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos. - uint8_t rssi; ///< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown. -} mavlink_rc_channels_scaled_t; +MAVPACKED( +typedef struct __mavlink_rc_channels_scaled_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + int16_t chan1_scaled; /*< RC channel 1 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + int16_t chan2_scaled; /*< RC channel 2 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + int16_t chan3_scaled; /*< RC channel 3 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + int16_t chan4_scaled; /*< RC channel 4 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + int16_t chan5_scaled; /*< RC channel 5 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + int16_t chan6_scaled; /*< RC channel 6 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + int16_t chan7_scaled; /*< RC channel 7 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + int16_t chan8_scaled; /*< RC channel 8 value scaled, (-100%) -10000, (0%) 0, (100%) 10000, (invalid) INT16_MAX.*/ + uint8_t port; /*< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows for more than 8 servos.*/ + uint8_t rssi; /*< Receive signal strength indicator, 0: 0%, 100: 100%, 255: invalid/unknown.*/ +}) mavlink_rc_channels_scaled_t; #define MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN 22 +#define MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN 22 #define MAVLINK_MSG_ID_34_LEN 22 +#define MAVLINK_MSG_ID_34_MIN_LEN 22 #define MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC 237 #define MAVLINK_MSG_ID_34_CRC 237 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED { \ - "RC_CHANNELS_SCALED", \ - 11, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_scaled_t, time_boot_ms) }, \ + 34, \ + "RC_CHANNELS_SCALED", \ + 11, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_scaled_t, time_boot_ms) }, \ { "chan1_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_rc_channels_scaled_t, chan1_scaled) }, \ { "chan2_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_rc_channels_scaled_t, chan2_scaled) }, \ { "chan3_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_rc_channels_scaled_t, chan3_scaled) }, \ @@ -41,7 +46,24 @@ typedef struct __mavlink_rc_channels_scaled_t { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_rc_channels_scaled_t, rssi) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_RC_CHANNELS_SCALED { \ + "RC_CHANNELS_SCALED", \ + 11, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_rc_channels_scaled_t, time_boot_ms) }, \ + { "chan1_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_rc_channels_scaled_t, chan1_scaled) }, \ + { "chan2_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_rc_channels_scaled_t, chan2_scaled) }, \ + { "chan3_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_rc_channels_scaled_t, chan3_scaled) }, \ + { "chan4_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_rc_channels_scaled_t, chan4_scaled) }, \ + { "chan5_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_rc_channels_scaled_t, chan5_scaled) }, \ + { "chan6_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_rc_channels_scaled_t, chan6_scaled) }, \ + { "chan7_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_rc_channels_scaled_t, chan7_scaled) }, \ + { "chan8_scaled", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_rc_channels_scaled_t, chan8_scaled) }, \ + { "port", NULL, MAVLINK_TYPE_UINT8_T, 0, 20, offsetof(mavlink_rc_channels_scaled_t, port) }, \ + { "rssi", NULL, MAVLINK_TYPE_UINT8_T, 0, 21, offsetof(mavlink_rc_channels_scaled_t, rssi) }, \ + } \ +} +#endif /** * @brief Pack a rc_channels_scaled message @@ -63,46 +85,42 @@ typedef struct __mavlink_rc_channels_scaled_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_scaled_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t port, int16_t chan1_scaled, int16_t chan2_scaled, int16_t chan3_scaled, int16_t chan4_scaled, int16_t chan5_scaled, int16_t chan6_scaled, int16_t chan7_scaled, int16_t chan8_scaled, uint8_t rssi) + uint32_t time_boot_ms, uint8_t port, int16_t chan1_scaled, int16_t chan2_scaled, int16_t chan3_scaled, int16_t chan4_scaled, int16_t chan5_scaled, int16_t chan6_scaled, int16_t chan7_scaled, int16_t chan8_scaled, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, chan1_scaled); - _mav_put_int16_t(buf, 6, chan2_scaled); - _mav_put_int16_t(buf, 8, chan3_scaled); - _mav_put_int16_t(buf, 10, chan4_scaled); - _mav_put_int16_t(buf, 12, chan5_scaled); - _mav_put_int16_t(buf, 14, chan6_scaled); - _mav_put_int16_t(buf, 16, chan7_scaled); - _mav_put_int16_t(buf, 18, chan8_scaled); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, chan1_scaled); + _mav_put_int16_t(buf, 6, chan2_scaled); + _mav_put_int16_t(buf, 8, chan3_scaled); + _mav_put_int16_t(buf, 10, chan4_scaled); + _mav_put_int16_t(buf, 12, chan5_scaled); + _mav_put_int16_t(buf, 14, chan6_scaled); + _mav_put_int16_t(buf, 16, chan7_scaled); + _mav_put_int16_t(buf, 18, chan8_scaled); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); #else - mavlink_rc_channels_scaled_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_scaled = chan1_scaled; - packet.chan2_scaled = chan2_scaled; - packet.chan3_scaled = chan3_scaled; - packet.chan4_scaled = chan4_scaled; - packet.chan5_scaled = chan5_scaled; - packet.chan6_scaled = chan6_scaled; - packet.chan7_scaled = chan7_scaled; - packet.chan8_scaled = chan8_scaled; - packet.port = port; - packet.rssi = rssi; + mavlink_rc_channels_scaled_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_scaled = chan1_scaled; + packet.chan2_scaled = chan2_scaled; + packet.chan3_scaled = chan3_scaled; + packet.chan4_scaled = chan4_scaled; + packet.chan5_scaled = chan5_scaled; + packet.chan6_scaled = chan6_scaled; + packet.chan7_scaled = chan7_scaled; + packet.chan8_scaled = chan8_scaled; + packet.port = port; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_SCALED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_SCALED; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); } /** @@ -125,47 +143,43 @@ static inline uint16_t mavlink_msg_rc_channels_scaled_pack(uint8_t system_id, ui * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_rc_channels_scaled_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t port,int16_t chan1_scaled,int16_t chan2_scaled,int16_t chan3_scaled,int16_t chan4_scaled,int16_t chan5_scaled,int16_t chan6_scaled,int16_t chan7_scaled,int16_t chan8_scaled,uint8_t rssi) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t port,int16_t chan1_scaled,int16_t chan2_scaled,int16_t chan3_scaled,int16_t chan4_scaled,int16_t chan5_scaled,int16_t chan6_scaled,int16_t chan7_scaled,int16_t chan8_scaled,uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, chan1_scaled); - _mav_put_int16_t(buf, 6, chan2_scaled); - _mav_put_int16_t(buf, 8, chan3_scaled); - _mav_put_int16_t(buf, 10, chan4_scaled); - _mav_put_int16_t(buf, 12, chan5_scaled); - _mav_put_int16_t(buf, 14, chan6_scaled); - _mav_put_int16_t(buf, 16, chan7_scaled); - _mav_put_int16_t(buf, 18, chan8_scaled); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, chan1_scaled); + _mav_put_int16_t(buf, 6, chan2_scaled); + _mav_put_int16_t(buf, 8, chan3_scaled); + _mav_put_int16_t(buf, 10, chan4_scaled); + _mav_put_int16_t(buf, 12, chan5_scaled); + _mav_put_int16_t(buf, 14, chan6_scaled); + _mav_put_int16_t(buf, 16, chan7_scaled); + _mav_put_int16_t(buf, 18, chan8_scaled); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); #else - mavlink_rc_channels_scaled_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_scaled = chan1_scaled; - packet.chan2_scaled = chan2_scaled; - packet.chan3_scaled = chan3_scaled; - packet.chan4_scaled = chan4_scaled; - packet.chan5_scaled = chan5_scaled; - packet.chan6_scaled = chan6_scaled; - packet.chan7_scaled = chan7_scaled; - packet.chan8_scaled = chan8_scaled; - packet.port = port; - packet.rssi = rssi; + mavlink_rc_channels_scaled_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_scaled = chan1_scaled; + packet.chan2_scaled = chan2_scaled; + packet.chan3_scaled = chan3_scaled; + packet.chan4_scaled = chan4_scaled; + packet.chan5_scaled = chan5_scaled; + packet.chan6_scaled = chan6_scaled; + packet.chan7_scaled = chan7_scaled; + packet.chan8_scaled = chan8_scaled; + packet.port = port; + packet.rssi = rssi; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_SCALED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_RC_CHANNELS_SCALED; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); } /** @@ -178,7 +192,7 @@ static inline uint16_t mavlink_msg_rc_channels_scaled_pack_chan(uint8_t system_i */ static inline uint16_t mavlink_msg_rc_channels_scaled_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_rc_channels_scaled_t* rc_channels_scaled) { - return mavlink_msg_rc_channels_scaled_pack(system_id, component_id, msg, rc_channels_scaled->time_boot_ms, rc_channels_scaled->port, rc_channels_scaled->chan1_scaled, rc_channels_scaled->chan2_scaled, rc_channels_scaled->chan3_scaled, rc_channels_scaled->chan4_scaled, rc_channels_scaled->chan5_scaled, rc_channels_scaled->chan6_scaled, rc_channels_scaled->chan7_scaled, rc_channels_scaled->chan8_scaled, rc_channels_scaled->rssi); + return mavlink_msg_rc_channels_scaled_pack(system_id, component_id, msg, rc_channels_scaled->time_boot_ms, rc_channels_scaled->port, rc_channels_scaled->chan1_scaled, rc_channels_scaled->chan2_scaled, rc_channels_scaled->chan3_scaled, rc_channels_scaled->chan4_scaled, rc_channels_scaled->chan5_scaled, rc_channels_scaled->chan6_scaled, rc_channels_scaled->chan7_scaled, rc_channels_scaled->chan8_scaled, rc_channels_scaled->rssi); } /** @@ -192,7 +206,7 @@ static inline uint16_t mavlink_msg_rc_channels_scaled_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_rc_channels_scaled_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_rc_channels_scaled_t* rc_channels_scaled) { - return mavlink_msg_rc_channels_scaled_pack_chan(system_id, component_id, chan, msg, rc_channels_scaled->time_boot_ms, rc_channels_scaled->port, rc_channels_scaled->chan1_scaled, rc_channels_scaled->chan2_scaled, rc_channels_scaled->chan3_scaled, rc_channels_scaled->chan4_scaled, rc_channels_scaled->chan5_scaled, rc_channels_scaled->chan6_scaled, rc_channels_scaled->chan7_scaled, rc_channels_scaled->chan8_scaled, rc_channels_scaled->rssi); + return mavlink_msg_rc_channels_scaled_pack_chan(system_id, component_id, chan, msg, rc_channels_scaled->time_boot_ms, rc_channels_scaled->port, rc_channels_scaled->chan1_scaled, rc_channels_scaled->chan2_scaled, rc_channels_scaled->chan3_scaled, rc_channels_scaled->chan4_scaled, rc_channels_scaled->chan5_scaled, rc_channels_scaled->chan6_scaled, rc_channels_scaled->chan7_scaled, rc_channels_scaled->chan8_scaled, rc_channels_scaled->rssi); } /** @@ -216,43 +230,49 @@ static inline uint16_t mavlink_msg_rc_channels_scaled_encode_chan(uint8_t system static inline void mavlink_msg_rc_channels_scaled_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t port, int16_t chan1_scaled, int16_t chan2_scaled, int16_t chan3_scaled, int16_t chan4_scaled, int16_t chan5_scaled, int16_t chan6_scaled, int16_t chan7_scaled, int16_t chan8_scaled, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, chan1_scaled); - _mav_put_int16_t(buf, 6, chan2_scaled); - _mav_put_int16_t(buf, 8, chan3_scaled); - _mav_put_int16_t(buf, 10, chan4_scaled); - _mav_put_int16_t(buf, 12, chan5_scaled); - _mav_put_int16_t(buf, 14, chan6_scaled); - _mav_put_int16_t(buf, 16, chan7_scaled); - _mav_put_int16_t(buf, 18, chan8_scaled); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); + char buf[MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, chan1_scaled); + _mav_put_int16_t(buf, 6, chan2_scaled); + _mav_put_int16_t(buf, 8, chan3_scaled); + _mav_put_int16_t(buf, 10, chan4_scaled); + _mav_put_int16_t(buf, 12, chan5_scaled); + _mav_put_int16_t(buf, 14, chan6_scaled); + _mav_put_int16_t(buf, 16, chan7_scaled); + _mav_put_int16_t(buf, 18, chan8_scaled); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); + mavlink_rc_channels_scaled_t packet; + packet.time_boot_ms = time_boot_ms; + packet.chan1_scaled = chan1_scaled; + packet.chan2_scaled = chan2_scaled; + packet.chan3_scaled = chan3_scaled; + packet.chan4_scaled = chan4_scaled; + packet.chan5_scaled = chan5_scaled; + packet.chan6_scaled = chan6_scaled; + packet.chan7_scaled = chan7_scaled; + packet.chan8_scaled = chan8_scaled; + packet.port = port; + packet.rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); #endif +} + +/** + * @brief Send a rc_channels_scaled message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_rc_channels_scaled_send_struct(mavlink_channel_t chan, const mavlink_rc_channels_scaled_t* rc_channels_scaled) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_rc_channels_scaled_send(chan, rc_channels_scaled->time_boot_ms, rc_channels_scaled->port, rc_channels_scaled->chan1_scaled, rc_channels_scaled->chan2_scaled, rc_channels_scaled->chan3_scaled, rc_channels_scaled->chan4_scaled, rc_channels_scaled->chan5_scaled, rc_channels_scaled->chan6_scaled, rc_channels_scaled->chan7_scaled, rc_channels_scaled->chan8_scaled, rc_channels_scaled->rssi); #else - mavlink_rc_channels_scaled_t packet; - packet.time_boot_ms = time_boot_ms; - packet.chan1_scaled = chan1_scaled; - packet.chan2_scaled = chan2_scaled; - packet.chan3_scaled = chan3_scaled; - packet.chan4_scaled = chan4_scaled; - packet.chan5_scaled = chan5_scaled; - packet.chan6_scaled = chan6_scaled; - packet.chan7_scaled = chan7_scaled; - packet.chan8_scaled = chan8_scaled; - packet.port = port; - packet.rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, (const char *)&packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, (const char *)rc_channels_scaled, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); #endif } @@ -267,43 +287,35 @@ static inline void mavlink_msg_rc_channels_scaled_send(mavlink_channel_t chan, u static inline void mavlink_msg_rc_channels_scaled_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t port, int16_t chan1_scaled, int16_t chan2_scaled, int16_t chan3_scaled, int16_t chan4_scaled, int16_t chan5_scaled, int16_t chan6_scaled, int16_t chan7_scaled, int16_t chan8_scaled, uint8_t rssi) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, chan1_scaled); - _mav_put_int16_t(buf, 6, chan2_scaled); - _mav_put_int16_t(buf, 8, chan3_scaled); - _mav_put_int16_t(buf, 10, chan4_scaled); - _mav_put_int16_t(buf, 12, chan5_scaled); - _mav_put_int16_t(buf, 14, chan6_scaled); - _mav_put_int16_t(buf, 16, chan7_scaled); - _mav_put_int16_t(buf, 18, chan8_scaled); - _mav_put_uint8_t(buf, 20, port); - _mav_put_uint8_t(buf, 21, rssi); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, chan1_scaled); + _mav_put_int16_t(buf, 6, chan2_scaled); + _mav_put_int16_t(buf, 8, chan3_scaled); + _mav_put_int16_t(buf, 10, chan4_scaled); + _mav_put_int16_t(buf, 12, chan5_scaled); + _mav_put_int16_t(buf, 14, chan6_scaled); + _mav_put_int16_t(buf, 16, chan7_scaled); + _mav_put_int16_t(buf, 18, chan8_scaled); + _mav_put_uint8_t(buf, 20, port); + _mav_put_uint8_t(buf, 21, rssi); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, buf, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); -#endif -#else - mavlink_rc_channels_scaled_t *packet = (mavlink_rc_channels_scaled_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->chan1_scaled = chan1_scaled; - packet->chan2_scaled = chan2_scaled; - packet->chan3_scaled = chan3_scaled; - packet->chan4_scaled = chan4_scaled; - packet->chan5_scaled = chan5_scaled; - packet->chan6_scaled = chan6_scaled; - packet->chan7_scaled = chan7_scaled; - packet->chan8_scaled = chan8_scaled; - packet->port = port; - packet->rssi = rssi; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); -#endif + mavlink_rc_channels_scaled_t *packet = (mavlink_rc_channels_scaled_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->chan1_scaled = chan1_scaled; + packet->chan2_scaled = chan2_scaled; + packet->chan3_scaled = chan3_scaled; + packet->chan4_scaled = chan4_scaled; + packet->chan5_scaled = chan5_scaled; + packet->chan6_scaled = chan6_scaled; + packet->chan7_scaled = chan7_scaled; + packet->chan8_scaled = chan8_scaled; + packet->port = port; + packet->rssi = rssi; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RC_CHANNELS_SCALED, (const char *)packet, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_CRC); #endif } #endif @@ -320,7 +332,7 @@ static inline void mavlink_msg_rc_channels_scaled_send_buf(mavlink_message_t *ms */ static inline uint32_t mavlink_msg_rc_channels_scaled_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -330,7 +342,7 @@ static inline uint32_t mavlink_msg_rc_channels_scaled_get_time_boot_ms(const mav */ static inline uint8_t mavlink_msg_rc_channels_scaled_get_port(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 20); + return _MAV_RETURN_uint8_t(msg, 20); } /** @@ -340,7 +352,7 @@ static inline uint8_t mavlink_msg_rc_channels_scaled_get_port(const mavlink_mess */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan1_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 4); + return _MAV_RETURN_int16_t(msg, 4); } /** @@ -350,7 +362,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan1_scaled(const mavl */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan2_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 6); + return _MAV_RETURN_int16_t(msg, 6); } /** @@ -360,7 +372,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan2_scaled(const mavl */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan3_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 8); + return _MAV_RETURN_int16_t(msg, 8); } /** @@ -370,7 +382,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan3_scaled(const mavl */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan4_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 10); + return _MAV_RETURN_int16_t(msg, 10); } /** @@ -380,7 +392,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan4_scaled(const mavl */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan5_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 12); + return _MAV_RETURN_int16_t(msg, 12); } /** @@ -390,7 +402,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan5_scaled(const mavl */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan6_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 14); + return _MAV_RETURN_int16_t(msg, 14); } /** @@ -400,7 +412,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan6_scaled(const mavl */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan7_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 16); + return _MAV_RETURN_int16_t(msg, 16); } /** @@ -410,7 +422,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan7_scaled(const mavl */ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan8_scaled(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 18); + return _MAV_RETURN_int16_t(msg, 18); } /** @@ -420,7 +432,7 @@ static inline int16_t mavlink_msg_rc_channels_scaled_get_chan8_scaled(const mavl */ static inline uint8_t mavlink_msg_rc_channels_scaled_get_rssi(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 21); + return _MAV_RETURN_uint8_t(msg, 21); } /** @@ -431,19 +443,21 @@ static inline uint8_t mavlink_msg_rc_channels_scaled_get_rssi(const mavlink_mess */ static inline void mavlink_msg_rc_channels_scaled_decode(const mavlink_message_t* msg, mavlink_rc_channels_scaled_t* rc_channels_scaled) { -#if MAVLINK_NEED_BYTE_SWAP - rc_channels_scaled->time_boot_ms = mavlink_msg_rc_channels_scaled_get_time_boot_ms(msg); - rc_channels_scaled->chan1_scaled = mavlink_msg_rc_channels_scaled_get_chan1_scaled(msg); - rc_channels_scaled->chan2_scaled = mavlink_msg_rc_channels_scaled_get_chan2_scaled(msg); - rc_channels_scaled->chan3_scaled = mavlink_msg_rc_channels_scaled_get_chan3_scaled(msg); - rc_channels_scaled->chan4_scaled = mavlink_msg_rc_channels_scaled_get_chan4_scaled(msg); - rc_channels_scaled->chan5_scaled = mavlink_msg_rc_channels_scaled_get_chan5_scaled(msg); - rc_channels_scaled->chan6_scaled = mavlink_msg_rc_channels_scaled_get_chan6_scaled(msg); - rc_channels_scaled->chan7_scaled = mavlink_msg_rc_channels_scaled_get_chan7_scaled(msg); - rc_channels_scaled->chan8_scaled = mavlink_msg_rc_channels_scaled_get_chan8_scaled(msg); - rc_channels_scaled->port = mavlink_msg_rc_channels_scaled_get_port(msg); - rc_channels_scaled->rssi = mavlink_msg_rc_channels_scaled_get_rssi(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + rc_channels_scaled->time_boot_ms = mavlink_msg_rc_channels_scaled_get_time_boot_ms(msg); + rc_channels_scaled->chan1_scaled = mavlink_msg_rc_channels_scaled_get_chan1_scaled(msg); + rc_channels_scaled->chan2_scaled = mavlink_msg_rc_channels_scaled_get_chan2_scaled(msg); + rc_channels_scaled->chan3_scaled = mavlink_msg_rc_channels_scaled_get_chan3_scaled(msg); + rc_channels_scaled->chan4_scaled = mavlink_msg_rc_channels_scaled_get_chan4_scaled(msg); + rc_channels_scaled->chan5_scaled = mavlink_msg_rc_channels_scaled_get_chan5_scaled(msg); + rc_channels_scaled->chan6_scaled = mavlink_msg_rc_channels_scaled_get_chan6_scaled(msg); + rc_channels_scaled->chan7_scaled = mavlink_msg_rc_channels_scaled_get_chan7_scaled(msg); + rc_channels_scaled->chan8_scaled = mavlink_msg_rc_channels_scaled_get_chan8_scaled(msg); + rc_channels_scaled->port = mavlink_msg_rc_channels_scaled_get_port(msg); + rc_channels_scaled->rssi = mavlink_msg_rc_channels_scaled_get_rssi(msg); #else - memcpy(rc_channels_scaled, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN? msg->len : MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN; + memset(rc_channels_scaled, 0, MAVLINK_MSG_ID_RC_CHANNELS_SCALED_LEN); + memcpy(rc_channels_scaled, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_request_data_stream.h b/vendor/libraries/mavlink/common/mavlink_msg_request_data_stream.h index 2ebcc54da5..047c2c342f 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_request_data_stream.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_request_data_stream.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE REQUEST_DATA_STREAM PACKING #define MAVLINK_MSG_ID_REQUEST_DATA_STREAM 66 -typedef struct __mavlink_request_data_stream_t -{ - uint16_t req_message_rate; ///< The requested interval between two messages of this type - uint8_t target_system; ///< The target requested to send the message stream. - uint8_t target_component; ///< The target requested to send the message stream. - uint8_t req_stream_id; ///< The ID of the requested data stream - uint8_t start_stop; ///< 1 to start sending, 0 to stop sending. -} mavlink_request_data_stream_t; +MAVPACKED( +typedef struct __mavlink_request_data_stream_t { + uint16_t req_message_rate; /*< The requested message rate*/ + uint8_t target_system; /*< The target requested to send the message stream.*/ + uint8_t target_component; /*< The target requested to send the message stream.*/ + uint8_t req_stream_id; /*< The ID of the requested data stream*/ + uint8_t start_stop; /*< 1 to start sending, 0 to stop sending.*/ +}) mavlink_request_data_stream_t; #define MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN 6 +#define MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN 6 #define MAVLINK_MSG_ID_66_LEN 6 +#define MAVLINK_MSG_ID_66_MIN_LEN 6 #define MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC 148 #define MAVLINK_MSG_ID_66_CRC 148 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM { \ - "REQUEST_DATA_STREAM", \ - 5, \ - { { "req_message_rate", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_request_data_stream_t, req_message_rate) }, \ + 66, \ + "REQUEST_DATA_STREAM", \ + 5, \ + { { "req_message_rate", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_request_data_stream_t, req_message_rate) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_request_data_stream_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_request_data_stream_t, target_component) }, \ { "req_stream_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_request_data_stream_t, req_stream_id) }, \ { "start_stop", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_request_data_stream_t, start_stop) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_REQUEST_DATA_STREAM { \ + "REQUEST_DATA_STREAM", \ + 5, \ + { { "req_message_rate", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_request_data_stream_t, req_message_rate) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_request_data_stream_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_request_data_stream_t, target_component) }, \ + { "req_stream_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_request_data_stream_t, req_stream_id) }, \ + { "start_stop", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_request_data_stream_t, start_stop) }, \ + } \ +} +#endif /** * @brief Pack a request_data_stream message @@ -40,39 +56,35 @@ typedef struct __mavlink_request_data_stream_t * @param target_system The target requested to send the message stream. * @param target_component The target requested to send the message stream. * @param req_stream_id The ID of the requested data stream - * @param req_message_rate The requested interval between two messages of this type + * @param req_message_rate The requested message rate * @param start_stop 1 to start sending, 0 to stop sending. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_request_data_stream_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t req_stream_id, uint16_t req_message_rate, uint8_t start_stop) + uint8_t target_system, uint8_t target_component, uint8_t req_stream_id, uint16_t req_message_rate, uint8_t start_stop) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN]; - _mav_put_uint16_t(buf, 0, req_message_rate); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_uint8_t(buf, 4, req_stream_id); - _mav_put_uint8_t(buf, 5, start_stop); + char buf[MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN]; + _mav_put_uint16_t(buf, 0, req_message_rate); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_uint8_t(buf, 4, req_stream_id); + _mav_put_uint8_t(buf, 5, start_stop); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); #else - mavlink_request_data_stream_t packet; - packet.req_message_rate = req_message_rate; - packet.target_system = target_system; - packet.target_component = target_component; - packet.req_stream_id = req_stream_id; - packet.start_stop = start_stop; + mavlink_request_data_stream_t packet; + packet.req_message_rate = req_message_rate; + packet.target_system = target_system; + packet.target_component = target_component; + packet.req_stream_id = req_stream_id; + packet.start_stop = start_stop; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_REQUEST_DATA_STREAM; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_REQUEST_DATA_STREAM; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); } /** @@ -84,40 +96,36 @@ static inline uint16_t mavlink_msg_request_data_stream_pack(uint8_t system_id, u * @param target_system The target requested to send the message stream. * @param target_component The target requested to send the message stream. * @param req_stream_id The ID of the requested data stream - * @param req_message_rate The requested interval between two messages of this type + * @param req_message_rate The requested message rate * @param start_stop 1 to start sending, 0 to stop sending. * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_request_data_stream_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t req_stream_id,uint16_t req_message_rate,uint8_t start_stop) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t req_stream_id,uint16_t req_message_rate,uint8_t start_stop) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN]; - _mav_put_uint16_t(buf, 0, req_message_rate); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_uint8_t(buf, 4, req_stream_id); - _mav_put_uint8_t(buf, 5, start_stop); + char buf[MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN]; + _mav_put_uint16_t(buf, 0, req_message_rate); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_uint8_t(buf, 4, req_stream_id); + _mav_put_uint8_t(buf, 5, start_stop); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); #else - mavlink_request_data_stream_t packet; - packet.req_message_rate = req_message_rate; - packet.target_system = target_system; - packet.target_component = target_component; - packet.req_stream_id = req_stream_id; - packet.start_stop = start_stop; + mavlink_request_data_stream_t packet; + packet.req_message_rate = req_message_rate; + packet.target_system = target_system; + packet.target_component = target_component; + packet.req_stream_id = req_stream_id; + packet.start_stop = start_stop; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_REQUEST_DATA_STREAM; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_REQUEST_DATA_STREAM; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); } /** @@ -130,7 +138,7 @@ static inline uint16_t mavlink_msg_request_data_stream_pack_chan(uint8_t system_ */ static inline uint16_t mavlink_msg_request_data_stream_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_request_data_stream_t* request_data_stream) { - return mavlink_msg_request_data_stream_pack(system_id, component_id, msg, request_data_stream->target_system, request_data_stream->target_component, request_data_stream->req_stream_id, request_data_stream->req_message_rate, request_data_stream->start_stop); + return mavlink_msg_request_data_stream_pack(system_id, component_id, msg, request_data_stream->target_system, request_data_stream->target_component, request_data_stream->req_stream_id, request_data_stream->req_message_rate, request_data_stream->start_stop); } /** @@ -144,7 +152,7 @@ static inline uint16_t mavlink_msg_request_data_stream_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_request_data_stream_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_request_data_stream_t* request_data_stream) { - return mavlink_msg_request_data_stream_pack_chan(system_id, component_id, chan, msg, request_data_stream->target_system, request_data_stream->target_component, request_data_stream->req_stream_id, request_data_stream->req_message_rate, request_data_stream->start_stop); + return mavlink_msg_request_data_stream_pack_chan(system_id, component_id, chan, msg, request_data_stream->target_system, request_data_stream->target_component, request_data_stream->req_stream_id, request_data_stream->req_message_rate, request_data_stream->start_stop); } /** @@ -154,7 +162,7 @@ static inline uint16_t mavlink_msg_request_data_stream_encode_chan(uint8_t syste * @param target_system The target requested to send the message stream. * @param target_component The target requested to send the message stream. * @param req_stream_id The ID of the requested data stream - * @param req_message_rate The requested interval between two messages of this type + * @param req_message_rate The requested message rate * @param start_stop 1 to start sending, 0 to stop sending. */ #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS @@ -162,31 +170,37 @@ static inline uint16_t mavlink_msg_request_data_stream_encode_chan(uint8_t syste static inline void mavlink_msg_request_data_stream_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t req_stream_id, uint16_t req_message_rate, uint8_t start_stop) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN]; - _mav_put_uint16_t(buf, 0, req_message_rate); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_uint8_t(buf, 4, req_stream_id); - _mav_put_uint8_t(buf, 5, start_stop); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); + char buf[MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN]; + _mav_put_uint16_t(buf, 0, req_message_rate); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_uint8_t(buf, 4, req_stream_id); + _mav_put_uint8_t(buf, 5, start_stop); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); + mavlink_request_data_stream_t packet; + packet.req_message_rate = req_message_rate; + packet.target_system = target_system; + packet.target_component = target_component; + packet.req_stream_id = req_stream_id; + packet.start_stop = start_stop; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, (const char *)&packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); #endif +} + +/** + * @brief Send a request_data_stream message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_request_data_stream_send_struct(mavlink_channel_t chan, const mavlink_request_data_stream_t* request_data_stream) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_request_data_stream_send(chan, request_data_stream->target_system, request_data_stream->target_component, request_data_stream->req_stream_id, request_data_stream->req_message_rate, request_data_stream->start_stop); #else - mavlink_request_data_stream_t packet; - packet.req_message_rate = req_message_rate; - packet.target_system = target_system; - packet.target_component = target_component; - packet.req_stream_id = req_stream_id; - packet.start_stop = start_stop; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, (const char *)&packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, (const char *)&packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, (const char *)request_data_stream, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); #endif } @@ -201,31 +215,23 @@ static inline void mavlink_msg_request_data_stream_send(mavlink_channel_t chan, static inline void mavlink_msg_request_data_stream_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t req_stream_id, uint16_t req_message_rate, uint8_t start_stop) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, req_message_rate); - _mav_put_uint8_t(buf, 2, target_system); - _mav_put_uint8_t(buf, 3, target_component); - _mav_put_uint8_t(buf, 4, req_stream_id); - _mav_put_uint8_t(buf, 5, start_stop); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, req_message_rate); + _mav_put_uint8_t(buf, 2, target_system); + _mav_put_uint8_t(buf, 3, target_component); + _mav_put_uint8_t(buf, 4, req_stream_id); + _mav_put_uint8_t(buf, 5, start_stop); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, buf, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); -#endif -#else - mavlink_request_data_stream_t *packet = (mavlink_request_data_stream_t *)msgbuf; - packet->req_message_rate = req_message_rate; - packet->target_system = target_system; - packet->target_component = target_component; - packet->req_stream_id = req_stream_id; - packet->start_stop = start_stop; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, (const char *)packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, (const char *)packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); -#endif + mavlink_request_data_stream_t *packet = (mavlink_request_data_stream_t *)msgbuf; + packet->req_message_rate = req_message_rate; + packet->target_system = target_system; + packet->target_component = target_component; + packet->req_stream_id = req_stream_id; + packet->start_stop = start_stop; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_REQUEST_DATA_STREAM, (const char *)packet, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_CRC); #endif } #endif @@ -242,7 +248,7 @@ static inline void mavlink_msg_request_data_stream_send_buf(mavlink_message_t *m */ static inline uint8_t mavlink_msg_request_data_stream_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -252,7 +258,7 @@ static inline uint8_t mavlink_msg_request_data_stream_get_target_system(const ma */ static inline uint8_t mavlink_msg_request_data_stream_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -262,17 +268,17 @@ static inline uint8_t mavlink_msg_request_data_stream_get_target_component(const */ static inline uint8_t mavlink_msg_request_data_stream_get_req_stream_id(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** * @brief Get field req_message_rate from request_data_stream message * - * @return The requested interval between two messages of this type + * @return The requested message rate */ static inline uint16_t mavlink_msg_request_data_stream_get_req_message_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -282,7 +288,7 @@ static inline uint16_t mavlink_msg_request_data_stream_get_req_message_rate(cons */ static inline uint8_t mavlink_msg_request_data_stream_get_start_stop(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -293,13 +299,15 @@ static inline uint8_t mavlink_msg_request_data_stream_get_start_stop(const mavli */ static inline void mavlink_msg_request_data_stream_decode(const mavlink_message_t* msg, mavlink_request_data_stream_t* request_data_stream) { -#if MAVLINK_NEED_BYTE_SWAP - request_data_stream->req_message_rate = mavlink_msg_request_data_stream_get_req_message_rate(msg); - request_data_stream->target_system = mavlink_msg_request_data_stream_get_target_system(msg); - request_data_stream->target_component = mavlink_msg_request_data_stream_get_target_component(msg); - request_data_stream->req_stream_id = mavlink_msg_request_data_stream_get_req_stream_id(msg); - request_data_stream->start_stop = mavlink_msg_request_data_stream_get_start_stop(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + request_data_stream->req_message_rate = mavlink_msg_request_data_stream_get_req_message_rate(msg); + request_data_stream->target_system = mavlink_msg_request_data_stream_get_target_system(msg); + request_data_stream->target_component = mavlink_msg_request_data_stream_get_target_component(msg); + request_data_stream->req_stream_id = mavlink_msg_request_data_stream_get_req_stream_id(msg); + request_data_stream->start_stop = mavlink_msg_request_data_stream_get_start_stop(msg); #else - memcpy(request_data_stream, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN? msg->len : MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN; + memset(request_data_stream, 0, MAVLINK_MSG_ID_REQUEST_DATA_STREAM_LEN); + memcpy(request_data_stream, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_resource_request.h b/vendor/libraries/mavlink/common/mavlink_msg_resource_request.h new file mode 100644 index 0000000000..69a11771f3 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_resource_request.h @@ -0,0 +1,306 @@ +#pragma once +// MESSAGE RESOURCE_REQUEST PACKING + +#define MAVLINK_MSG_ID_RESOURCE_REQUEST 142 + +MAVPACKED( +typedef struct __mavlink_resource_request_t { + uint8_t request_id; /*< Request ID. This ID should be re-used when sending back URI contents*/ + uint8_t uri_type; /*< The type of requested URI. 0 = a file via URL. 1 = a UAVCAN binary*/ + uint8_t uri[120]; /*< The requested unique resource identifier (URI). It is not necessarily a straight domain name (depends on the URI type enum)*/ + uint8_t transfer_type; /*< The way the autopilot wants to receive the URI. 0 = MAVLink FTP. 1 = binary stream.*/ + uint8_t storage[120]; /*< The storage path the autopilot wants the URI to be stored in. Will only be valid if the transfer_type has a storage associated (e.g. MAVLink FTP).*/ +}) mavlink_resource_request_t; + +#define MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN 243 +#define MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN 243 +#define MAVLINK_MSG_ID_142_LEN 243 +#define MAVLINK_MSG_ID_142_MIN_LEN 243 + +#define MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC 72 +#define MAVLINK_MSG_ID_142_CRC 72 + +#define MAVLINK_MSG_RESOURCE_REQUEST_FIELD_URI_LEN 120 +#define MAVLINK_MSG_RESOURCE_REQUEST_FIELD_STORAGE_LEN 120 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_RESOURCE_REQUEST { \ + 142, \ + "RESOURCE_REQUEST", \ + 5, \ + { { "request_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_resource_request_t, request_id) }, \ + { "uri_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_resource_request_t, uri_type) }, \ + { "uri", NULL, MAVLINK_TYPE_UINT8_T, 120, 2, offsetof(mavlink_resource_request_t, uri) }, \ + { "transfer_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 122, offsetof(mavlink_resource_request_t, transfer_type) }, \ + { "storage", NULL, MAVLINK_TYPE_UINT8_T, 120, 123, offsetof(mavlink_resource_request_t, storage) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_RESOURCE_REQUEST { \ + "RESOURCE_REQUEST", \ + 5, \ + { { "request_id", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_resource_request_t, request_id) }, \ + { "uri_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 1, offsetof(mavlink_resource_request_t, uri_type) }, \ + { "uri", NULL, MAVLINK_TYPE_UINT8_T, 120, 2, offsetof(mavlink_resource_request_t, uri) }, \ + { "transfer_type", NULL, MAVLINK_TYPE_UINT8_T, 0, 122, offsetof(mavlink_resource_request_t, transfer_type) }, \ + { "storage", NULL, MAVLINK_TYPE_UINT8_T, 120, 123, offsetof(mavlink_resource_request_t, storage) }, \ + } \ +} +#endif + +/** + * @brief Pack a resource_request message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param request_id Request ID. This ID should be re-used when sending back URI contents + * @param uri_type The type of requested URI. 0 = a file via URL. 1 = a UAVCAN binary + * @param uri The requested unique resource identifier (URI). It is not necessarily a straight domain name (depends on the URI type enum) + * @param transfer_type The way the autopilot wants to receive the URI. 0 = MAVLink FTP. 1 = binary stream. + * @param storage The storage path the autopilot wants the URI to be stored in. Will only be valid if the transfer_type has a storage associated (e.g. MAVLink FTP). + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_resource_request_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t request_id, uint8_t uri_type, const uint8_t *uri, uint8_t transfer_type, const uint8_t *storage) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, request_id); + _mav_put_uint8_t(buf, 1, uri_type); + _mav_put_uint8_t(buf, 122, transfer_type); + _mav_put_uint8_t_array(buf, 2, uri, 120); + _mav_put_uint8_t_array(buf, 123, storage, 120); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN); +#else + mavlink_resource_request_t packet; + packet.request_id = request_id; + packet.uri_type = uri_type; + packet.transfer_type = transfer_type; + mav_array_memcpy(packet.uri, uri, sizeof(uint8_t)*120); + mav_array_memcpy(packet.storage, storage, sizeof(uint8_t)*120); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_RESOURCE_REQUEST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC); +} + +/** + * @brief Pack a resource_request message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param request_id Request ID. This ID should be re-used when sending back URI contents + * @param uri_type The type of requested URI. 0 = a file via URL. 1 = a UAVCAN binary + * @param uri The requested unique resource identifier (URI). It is not necessarily a straight domain name (depends on the URI type enum) + * @param transfer_type The way the autopilot wants to receive the URI. 0 = MAVLink FTP. 1 = binary stream. + * @param storage The storage path the autopilot wants the URI to be stored in. Will only be valid if the transfer_type has a storage associated (e.g. MAVLink FTP). + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_resource_request_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t request_id,uint8_t uri_type,const uint8_t *uri,uint8_t transfer_type,const uint8_t *storage) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, request_id); + _mav_put_uint8_t(buf, 1, uri_type); + _mav_put_uint8_t(buf, 122, transfer_type); + _mav_put_uint8_t_array(buf, 2, uri, 120); + _mav_put_uint8_t_array(buf, 123, storage, 120); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN); +#else + mavlink_resource_request_t packet; + packet.request_id = request_id; + packet.uri_type = uri_type; + packet.transfer_type = transfer_type; + mav_array_memcpy(packet.uri, uri, sizeof(uint8_t)*120); + mav_array_memcpy(packet.storage, storage, sizeof(uint8_t)*120); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_RESOURCE_REQUEST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC); +} + +/** + * @brief Encode a resource_request struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param resource_request C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_resource_request_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_resource_request_t* resource_request) +{ + return mavlink_msg_resource_request_pack(system_id, component_id, msg, resource_request->request_id, resource_request->uri_type, resource_request->uri, resource_request->transfer_type, resource_request->storage); +} + +/** + * @brief Encode a resource_request struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param resource_request C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_resource_request_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_resource_request_t* resource_request) +{ + return mavlink_msg_resource_request_pack_chan(system_id, component_id, chan, msg, resource_request->request_id, resource_request->uri_type, resource_request->uri, resource_request->transfer_type, resource_request->storage); +} + +/** + * @brief Send a resource_request message + * @param chan MAVLink channel to send the message + * + * @param request_id Request ID. This ID should be re-used when sending back URI contents + * @param uri_type The type of requested URI. 0 = a file via URL. 1 = a UAVCAN binary + * @param uri The requested unique resource identifier (URI). It is not necessarily a straight domain name (depends on the URI type enum) + * @param transfer_type The way the autopilot wants to receive the URI. 0 = MAVLink FTP. 1 = binary stream. + * @param storage The storage path the autopilot wants the URI to be stored in. Will only be valid if the transfer_type has a storage associated (e.g. MAVLink FTP). + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_resource_request_send(mavlink_channel_t chan, uint8_t request_id, uint8_t uri_type, const uint8_t *uri, uint8_t transfer_type, const uint8_t *storage) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN]; + _mav_put_uint8_t(buf, 0, request_id); + _mav_put_uint8_t(buf, 1, uri_type); + _mav_put_uint8_t(buf, 122, transfer_type); + _mav_put_uint8_t_array(buf, 2, uri, 120); + _mav_put_uint8_t_array(buf, 123, storage, 120); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RESOURCE_REQUEST, buf, MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC); +#else + mavlink_resource_request_t packet; + packet.request_id = request_id; + packet.uri_type = uri_type; + packet.transfer_type = transfer_type; + mav_array_memcpy(packet.uri, uri, sizeof(uint8_t)*120); + mav_array_memcpy(packet.storage, storage, sizeof(uint8_t)*120); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RESOURCE_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC); +#endif +} + +/** + * @brief Send a resource_request message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_resource_request_send_struct(mavlink_channel_t chan, const mavlink_resource_request_t* resource_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_resource_request_send(chan, resource_request->request_id, resource_request->uri_type, resource_request->uri, resource_request->transfer_type, resource_request->storage); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RESOURCE_REQUEST, (const char *)resource_request, MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC); +#endif +} + +#if MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_resource_request_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t request_id, uint8_t uri_type, const uint8_t *uri, uint8_t transfer_type, const uint8_t *storage) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, request_id); + _mav_put_uint8_t(buf, 1, uri_type); + _mav_put_uint8_t(buf, 122, transfer_type); + _mav_put_uint8_t_array(buf, 2, uri, 120); + _mav_put_uint8_t_array(buf, 123, storage, 120); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RESOURCE_REQUEST, buf, MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC); +#else + mavlink_resource_request_t *packet = (mavlink_resource_request_t *)msgbuf; + packet->request_id = request_id; + packet->uri_type = uri_type; + packet->transfer_type = transfer_type; + mav_array_memcpy(packet->uri, uri, sizeof(uint8_t)*120); + mav_array_memcpy(packet->storage, storage, sizeof(uint8_t)*120); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_RESOURCE_REQUEST, (const char *)packet, MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN, MAVLINK_MSG_ID_RESOURCE_REQUEST_CRC); +#endif +} +#endif + +#endif + +// MESSAGE RESOURCE_REQUEST UNPACKING + + +/** + * @brief Get field request_id from resource_request message + * + * @return Request ID. This ID should be re-used when sending back URI contents + */ +static inline uint8_t mavlink_msg_resource_request_get_request_id(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 0); +} + +/** + * @brief Get field uri_type from resource_request message + * + * @return The type of requested URI. 0 = a file via URL. 1 = a UAVCAN binary + */ +static inline uint8_t mavlink_msg_resource_request_get_uri_type(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 1); +} + +/** + * @brief Get field uri from resource_request message + * + * @return The requested unique resource identifier (URI). It is not necessarily a straight domain name (depends on the URI type enum) + */ +static inline uint16_t mavlink_msg_resource_request_get_uri(const mavlink_message_t* msg, uint8_t *uri) +{ + return _MAV_RETURN_uint8_t_array(msg, uri, 120, 2); +} + +/** + * @brief Get field transfer_type from resource_request message + * + * @return The way the autopilot wants to receive the URI. 0 = MAVLink FTP. 1 = binary stream. + */ +static inline uint8_t mavlink_msg_resource_request_get_transfer_type(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 122); +} + +/** + * @brief Get field storage from resource_request message + * + * @return The storage path the autopilot wants the URI to be stored in. Will only be valid if the transfer_type has a storage associated (e.g. MAVLink FTP). + */ +static inline uint16_t mavlink_msg_resource_request_get_storage(const mavlink_message_t* msg, uint8_t *storage) +{ + return _MAV_RETURN_uint8_t_array(msg, storage, 120, 123); +} + +/** + * @brief Decode a resource_request message into a struct + * + * @param msg The message to decode + * @param resource_request C-struct to decode the message contents into + */ +static inline void mavlink_msg_resource_request_decode(const mavlink_message_t* msg, mavlink_resource_request_t* resource_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + resource_request->request_id = mavlink_msg_resource_request_get_request_id(msg); + resource_request->uri_type = mavlink_msg_resource_request_get_uri_type(msg); + mavlink_msg_resource_request_get_uri(msg, resource_request->uri); + resource_request->transfer_type = mavlink_msg_resource_request_get_transfer_type(msg); + mavlink_msg_resource_request_get_storage(msg, resource_request->storage); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN? msg->len : MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN; + memset(resource_request, 0, MAVLINK_MSG_ID_RESOURCE_REQUEST_LEN); + memcpy(resource_request, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_safety_allowed_area.h b/vendor/libraries/mavlink/common/mavlink_msg_safety_allowed_area.h index 0176dfcc8d..cad1c198e4 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_safety_allowed_area.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_safety_allowed_area.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE SAFETY_ALLOWED_AREA PACKING #define MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA 55 -typedef struct __mavlink_safety_allowed_area_t -{ - float p1x; ///< x position 1 / Latitude 1 - float p1y; ///< y position 1 / Longitude 1 - float p1z; ///< z position 1 / Altitude 1 - float p2x; ///< x position 2 / Latitude 2 - float p2y; ///< y position 2 / Longitude 2 - float p2z; ///< z position 2 / Altitude 2 - uint8_t frame; ///< Coordinate frame, as defined by MAV_FRAME enum in mavlink_types.h. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down. -} mavlink_safety_allowed_area_t; +MAVPACKED( +typedef struct __mavlink_safety_allowed_area_t { + float p1x; /*< x position 1 / Latitude 1*/ + float p1y; /*< y position 1 / Longitude 1*/ + float p1z; /*< z position 1 / Altitude 1*/ + float p2x; /*< x position 2 / Latitude 2*/ + float p2y; /*< y position 2 / Longitude 2*/ + float p2z; /*< z position 2 / Altitude 2*/ + uint8_t frame; /*< Coordinate frame, as defined by MAV_FRAME enum in mavlink_types.h. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down.*/ +}) mavlink_safety_allowed_area_t; #define MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN 25 +#define MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN 25 #define MAVLINK_MSG_ID_55_LEN 25 +#define MAVLINK_MSG_ID_55_MIN_LEN 25 #define MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC 3 #define MAVLINK_MSG_ID_55_CRC 3 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA { \ - "SAFETY_ALLOWED_AREA", \ - 7, \ - { { "p1x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_safety_allowed_area_t, p1x) }, \ + 55, \ + "SAFETY_ALLOWED_AREA", \ + 7, \ + { { "p1x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_safety_allowed_area_t, p1x) }, \ { "p1y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_safety_allowed_area_t, p1y) }, \ { "p1z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_safety_allowed_area_t, p1z) }, \ { "p2x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_safety_allowed_area_t, p2x) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_safety_allowed_area_t { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_safety_allowed_area_t, frame) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SAFETY_ALLOWED_AREA { \ + "SAFETY_ALLOWED_AREA", \ + 7, \ + { { "p1x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_safety_allowed_area_t, p1x) }, \ + { "p1y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_safety_allowed_area_t, p1y) }, \ + { "p1z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_safety_allowed_area_t, p1z) }, \ + { "p2x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_safety_allowed_area_t, p2x) }, \ + { "p2y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_safety_allowed_area_t, p2y) }, \ + { "p2z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_safety_allowed_area_t, p2z) }, \ + { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_safety_allowed_area_t, frame) }, \ + } \ +} +#endif /** * @brief Pack a safety_allowed_area message @@ -51,38 +69,34 @@ typedef struct __mavlink_safety_allowed_area_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_safety_allowed_area_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) + uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN]; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, frame); + char buf[MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN]; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); #else - mavlink_safety_allowed_area_t packet; - packet.p1x = p1x; - packet.p1y = p1y; - packet.p1z = p1z; - packet.p2x = p2x; - packet.p2y = p2y; - packet.p2z = p2z; - packet.frame = frame; + mavlink_safety_allowed_area_t packet; + packet.p1x = p1x; + packet.p1y = p1y; + packet.p1z = p1z; + packet.p2x = p2x; + packet.p2y = p2y; + packet.p2z = p2z; + packet.frame = frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_safety_allowed_area_pack(uint8_t system_id, u * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_safety_allowed_area_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t frame,float p1x,float p1y,float p1z,float p2x,float p2y,float p2z) + mavlink_message_t* msg, + uint8_t frame,float p1x,float p1y,float p1z,float p2x,float p2y,float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN]; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, frame); + char buf[MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN]; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); #else - mavlink_safety_allowed_area_t packet; - packet.p1x = p1x; - packet.p1y = p1y; - packet.p1z = p1z; - packet.p2x = p2x; - packet.p2y = p2y; - packet.p2z = p2z; - packet.frame = frame; + mavlink_safety_allowed_area_t packet; + packet.p1x = p1x; + packet.p1y = p1y; + packet.p1z = p1z; + packet.p2x = p2x; + packet.p2y = p2y; + packet.p2z = p2z; + packet.frame = frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_safety_allowed_area_pack_chan(uint8_t system_ */ static inline uint16_t mavlink_msg_safety_allowed_area_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_safety_allowed_area_t* safety_allowed_area) { - return mavlink_msg_safety_allowed_area_pack(system_id, component_id, msg, safety_allowed_area->frame, safety_allowed_area->p1x, safety_allowed_area->p1y, safety_allowed_area->p1z, safety_allowed_area->p2x, safety_allowed_area->p2y, safety_allowed_area->p2z); + return mavlink_msg_safety_allowed_area_pack(system_id, component_id, msg, safety_allowed_area->frame, safety_allowed_area->p1x, safety_allowed_area->p1y, safety_allowed_area->p1z, safety_allowed_area->p2x, safety_allowed_area->p2y, safety_allowed_area->p2z); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_safety_allowed_area_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_safety_allowed_area_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_safety_allowed_area_t* safety_allowed_area) { - return mavlink_msg_safety_allowed_area_pack_chan(system_id, component_id, chan, msg, safety_allowed_area->frame, safety_allowed_area->p1x, safety_allowed_area->p1y, safety_allowed_area->p1z, safety_allowed_area->p2x, safety_allowed_area->p2y, safety_allowed_area->p2z); + return mavlink_msg_safety_allowed_area_pack_chan(system_id, component_id, chan, msg, safety_allowed_area->frame, safety_allowed_area->p1x, safety_allowed_area->p1y, safety_allowed_area->p1z, safety_allowed_area->p2x, safety_allowed_area->p2y, safety_allowed_area->p2z); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_safety_allowed_area_encode_chan(uint8_t syste static inline void mavlink_msg_safety_allowed_area_send(mavlink_channel_t chan, uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN]; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); + char buf[MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN]; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); + mavlink_safety_allowed_area_t packet; + packet.p1x = p1x; + packet.p1y = p1y; + packet.p1z = p1z; + packet.p2x = p2x; + packet.p2y = p2y; + packet.p2z = p2z; + packet.frame = frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, (const char *)&packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); #endif +} + +/** + * @brief Send a safety_allowed_area message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_safety_allowed_area_send_struct(mavlink_channel_t chan, const mavlink_safety_allowed_area_t* safety_allowed_area) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_safety_allowed_area_send(chan, safety_allowed_area->frame, safety_allowed_area->p1x, safety_allowed_area->p1y, safety_allowed_area->p1z, safety_allowed_area->p2x, safety_allowed_area->p2y, safety_allowed_area->p2z); #else - mavlink_safety_allowed_area_t packet; - packet.p1x = p1x; - packet.p1y = p1y; - packet.p1z = p1z; - packet.p2x = p2x; - packet.p2y = p2y; - packet.p2z = p2z; - packet.frame = frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, (const char *)&packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, (const char *)&packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, (const char *)safety_allowed_area, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_safety_allowed_area_send(mavlink_channel_t chan, static inline void mavlink_msg_safety_allowed_area_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); -#endif -#else - mavlink_safety_allowed_area_t *packet = (mavlink_safety_allowed_area_t *)msgbuf; - packet->p1x = p1x; - packet->p1y = p1y; - packet->p1z = p1z; - packet->p2x = p2x; - packet->p2y = p2y; - packet->p2z = p2z; - packet->frame = frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, (const char *)packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, (const char *)packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); -#endif + mavlink_safety_allowed_area_t *packet = (mavlink_safety_allowed_area_t *)msgbuf; + packet->p1x = p1x; + packet->p1y = p1y; + packet->p1z = p1z; + packet->p2x = p2x; + packet->p2y = p2y; + packet->p2z = p2z; + packet->frame = frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA, (const char *)packet, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_safety_allowed_area_send_buf(mavlink_message_t *m */ static inline uint8_t mavlink_msg_safety_allowed_area_get_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 24); + return _MAV_RETURN_uint8_t(msg, 24); } /** @@ -278,7 +286,7 @@ static inline uint8_t mavlink_msg_safety_allowed_area_get_frame(const mavlink_me */ static inline float mavlink_msg_safety_allowed_area_get_p1x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_safety_allowed_area_get_p1x(const mavlink_messag */ static inline float mavlink_msg_safety_allowed_area_get_p1y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_safety_allowed_area_get_p1y(const mavlink_messag */ static inline float mavlink_msg_safety_allowed_area_get_p1z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_safety_allowed_area_get_p1z(const mavlink_messag */ static inline float mavlink_msg_safety_allowed_area_get_p2x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_safety_allowed_area_get_p2x(const mavlink_messag */ static inline float mavlink_msg_safety_allowed_area_get_p2y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_safety_allowed_area_get_p2y(const mavlink_messag */ static inline float mavlink_msg_safety_allowed_area_get_p2z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_safety_allowed_area_get_p2z(const mavlink_messag */ static inline void mavlink_msg_safety_allowed_area_decode(const mavlink_message_t* msg, mavlink_safety_allowed_area_t* safety_allowed_area) { -#if MAVLINK_NEED_BYTE_SWAP - safety_allowed_area->p1x = mavlink_msg_safety_allowed_area_get_p1x(msg); - safety_allowed_area->p1y = mavlink_msg_safety_allowed_area_get_p1y(msg); - safety_allowed_area->p1z = mavlink_msg_safety_allowed_area_get_p1z(msg); - safety_allowed_area->p2x = mavlink_msg_safety_allowed_area_get_p2x(msg); - safety_allowed_area->p2y = mavlink_msg_safety_allowed_area_get_p2y(msg); - safety_allowed_area->p2z = mavlink_msg_safety_allowed_area_get_p2z(msg); - safety_allowed_area->frame = mavlink_msg_safety_allowed_area_get_frame(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + safety_allowed_area->p1x = mavlink_msg_safety_allowed_area_get_p1x(msg); + safety_allowed_area->p1y = mavlink_msg_safety_allowed_area_get_p1y(msg); + safety_allowed_area->p1z = mavlink_msg_safety_allowed_area_get_p1z(msg); + safety_allowed_area->p2x = mavlink_msg_safety_allowed_area_get_p2x(msg); + safety_allowed_area->p2y = mavlink_msg_safety_allowed_area_get_p2y(msg); + safety_allowed_area->p2z = mavlink_msg_safety_allowed_area_get_p2z(msg); + safety_allowed_area->frame = mavlink_msg_safety_allowed_area_get_frame(msg); #else - memcpy(safety_allowed_area, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN? msg->len : MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN; + memset(safety_allowed_area, 0, MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_LEN); + memcpy(safety_allowed_area, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_safety_set_allowed_area.h b/vendor/libraries/mavlink/common/mavlink_msg_safety_set_allowed_area.h index dafbc260b4..293c1f002a 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_safety_set_allowed_area.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_safety_set_allowed_area.h @@ -1,32 +1,37 @@ +#pragma once // MESSAGE SAFETY_SET_ALLOWED_AREA PACKING #define MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA 54 -typedef struct __mavlink_safety_set_allowed_area_t -{ - float p1x; ///< x position 1 / Latitude 1 - float p1y; ///< y position 1 / Longitude 1 - float p1z; ///< z position 1 / Altitude 1 - float p2x; ///< x position 2 / Latitude 2 - float p2y; ///< y position 2 / Longitude 2 - float p2z; ///< z position 2 / Altitude 2 - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t frame; ///< Coordinate frame, as defined by MAV_FRAME enum in mavlink_types.h. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down. -} mavlink_safety_set_allowed_area_t; +MAVPACKED( +typedef struct __mavlink_safety_set_allowed_area_t { + float p1x; /*< x position 1 / Latitude 1*/ + float p1y; /*< y position 1 / Longitude 1*/ + float p1z; /*< z position 1 / Altitude 1*/ + float p2x; /*< x position 2 / Latitude 2*/ + float p2y; /*< y position 2 / Longitude 2*/ + float p2z; /*< z position 2 / Altitude 2*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t frame; /*< Coordinate frame, as defined by MAV_FRAME enum in mavlink_types.h. Can be either global, GPS, right-handed with Z axis up or local, right handed, Z axis down.*/ +}) mavlink_safety_set_allowed_area_t; #define MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN 27 +#define MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN 27 #define MAVLINK_MSG_ID_54_LEN 27 +#define MAVLINK_MSG_ID_54_MIN_LEN 27 #define MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC 15 #define MAVLINK_MSG_ID_54_CRC 15 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA { \ - "SAFETY_SET_ALLOWED_AREA", \ - 9, \ - { { "p1x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_safety_set_allowed_area_t, p1x) }, \ + 54, \ + "SAFETY_SET_ALLOWED_AREA", \ + 9, \ + { { "p1x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_safety_set_allowed_area_t, p1x) }, \ { "p1y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_safety_set_allowed_area_t, p1y) }, \ { "p1z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_safety_set_allowed_area_t, p1z) }, \ { "p2x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_safety_set_allowed_area_t, p2x) }, \ @@ -37,7 +42,22 @@ typedef struct __mavlink_safety_set_allowed_area_t { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 26, offsetof(mavlink_safety_set_allowed_area_t, frame) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SAFETY_SET_ALLOWED_AREA { \ + "SAFETY_SET_ALLOWED_AREA", \ + 9, \ + { { "p1x", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_safety_set_allowed_area_t, p1x) }, \ + { "p1y", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_safety_set_allowed_area_t, p1y) }, \ + { "p1z", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_safety_set_allowed_area_t, p1z) }, \ + { "p2x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_safety_set_allowed_area_t, p2x) }, \ + { "p2y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_safety_set_allowed_area_t, p2y) }, \ + { "p2z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_safety_set_allowed_area_t, p2z) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 24, offsetof(mavlink_safety_set_allowed_area_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 25, offsetof(mavlink_safety_set_allowed_area_t, target_component) }, \ + { "frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 26, offsetof(mavlink_safety_set_allowed_area_t, frame) }, \ + } \ +} +#endif /** * @brief Pack a safety_set_allowed_area message @@ -57,42 +77,38 @@ typedef struct __mavlink_safety_set_allowed_area_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_safety_set_allowed_area_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t target_component, uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) + uint8_t target_system, uint8_t target_component, uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN]; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); - _mav_put_uint8_t(buf, 26, frame); + char buf[MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN]; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, target_system); + _mav_put_uint8_t(buf, 25, target_component); + _mav_put_uint8_t(buf, 26, frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); #else - mavlink_safety_set_allowed_area_t packet; - packet.p1x = p1x; - packet.p1y = p1y; - packet.p1z = p1z; - packet.p2x = p2x; - packet.p2y = p2y; - packet.p2z = p2z; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; + mavlink_safety_set_allowed_area_t packet; + packet.p1x = p1x; + packet.p1y = p1y; + packet.p1z = p1z; + packet.p2x = p2x; + packet.p2y = p2y; + packet.p2z = p2z; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); } /** @@ -113,43 +129,39 @@ static inline uint16_t mavlink_msg_safety_set_allowed_area_pack(uint8_t system_i * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_safety_set_allowed_area_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t target_component,uint8_t frame,float p1x,float p1y,float p1z,float p2x,float p2y,float p2z) + mavlink_message_t* msg, + uint8_t target_system,uint8_t target_component,uint8_t frame,float p1x,float p1y,float p1z,float p2x,float p2y,float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN]; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); - _mav_put_uint8_t(buf, 26, frame); + char buf[MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN]; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, target_system); + _mav_put_uint8_t(buf, 25, target_component); + _mav_put_uint8_t(buf, 26, frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); #else - mavlink_safety_set_allowed_area_t packet; - packet.p1x = p1x; - packet.p1y = p1y; - packet.p1z = p1z; - packet.p2x = p2x; - packet.p2y = p2y; - packet.p2z = p2z; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; + mavlink_safety_set_allowed_area_t packet; + packet.p1x = p1x; + packet.p1y = p1y; + packet.p1z = p1z; + packet.p2x = p2x; + packet.p2y = p2y; + packet.p2z = p2z; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); } /** @@ -162,7 +174,7 @@ static inline uint16_t mavlink_msg_safety_set_allowed_area_pack_chan(uint8_t sys */ static inline uint16_t mavlink_msg_safety_set_allowed_area_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_safety_set_allowed_area_t* safety_set_allowed_area) { - return mavlink_msg_safety_set_allowed_area_pack(system_id, component_id, msg, safety_set_allowed_area->target_system, safety_set_allowed_area->target_component, safety_set_allowed_area->frame, safety_set_allowed_area->p1x, safety_set_allowed_area->p1y, safety_set_allowed_area->p1z, safety_set_allowed_area->p2x, safety_set_allowed_area->p2y, safety_set_allowed_area->p2z); + return mavlink_msg_safety_set_allowed_area_pack(system_id, component_id, msg, safety_set_allowed_area->target_system, safety_set_allowed_area->target_component, safety_set_allowed_area->frame, safety_set_allowed_area->p1x, safety_set_allowed_area->p1y, safety_set_allowed_area->p1z, safety_set_allowed_area->p2x, safety_set_allowed_area->p2y, safety_set_allowed_area->p2z); } /** @@ -176,7 +188,7 @@ static inline uint16_t mavlink_msg_safety_set_allowed_area_encode(uint8_t system */ static inline uint16_t mavlink_msg_safety_set_allowed_area_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_safety_set_allowed_area_t* safety_set_allowed_area) { - return mavlink_msg_safety_set_allowed_area_pack_chan(system_id, component_id, chan, msg, safety_set_allowed_area->target_system, safety_set_allowed_area->target_component, safety_set_allowed_area->frame, safety_set_allowed_area->p1x, safety_set_allowed_area->p1y, safety_set_allowed_area->p1z, safety_set_allowed_area->p2x, safety_set_allowed_area->p2y, safety_set_allowed_area->p2z); + return mavlink_msg_safety_set_allowed_area_pack_chan(system_id, component_id, chan, msg, safety_set_allowed_area->target_system, safety_set_allowed_area->target_component, safety_set_allowed_area->frame, safety_set_allowed_area->p1x, safety_set_allowed_area->p1y, safety_set_allowed_area->p1z, safety_set_allowed_area->p2x, safety_set_allowed_area->p2y, safety_set_allowed_area->p2z); } /** @@ -198,39 +210,45 @@ static inline uint16_t mavlink_msg_safety_set_allowed_area_encode_chan(uint8_t s static inline void mavlink_msg_safety_set_allowed_area_send(mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN]; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); - _mav_put_uint8_t(buf, 26, frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); + char buf[MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN]; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, target_system); + _mav_put_uint8_t(buf, 25, target_component); + _mav_put_uint8_t(buf, 26, frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); + mavlink_safety_set_allowed_area_t packet; + packet.p1x = p1x; + packet.p1y = p1y; + packet.p1z = p1z; + packet.p2x = p2x; + packet.p2y = p2y; + packet.p2z = p2z; + packet.target_system = target_system; + packet.target_component = target_component; + packet.frame = frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, (const char *)&packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); #endif +} + +/** + * @brief Send a safety_set_allowed_area message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_safety_set_allowed_area_send_struct(mavlink_channel_t chan, const mavlink_safety_set_allowed_area_t* safety_set_allowed_area) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_safety_set_allowed_area_send(chan, safety_set_allowed_area->target_system, safety_set_allowed_area->target_component, safety_set_allowed_area->frame, safety_set_allowed_area->p1x, safety_set_allowed_area->p1y, safety_set_allowed_area->p1z, safety_set_allowed_area->p2x, safety_set_allowed_area->p2y, safety_set_allowed_area->p2z); #else - mavlink_safety_set_allowed_area_t packet; - packet.p1x = p1x; - packet.p1y = p1y; - packet.p1z = p1z; - packet.p2x = p2x; - packet.p2y = p2y; - packet.p2z = p2z; - packet.target_system = target_system; - packet.target_component = target_component; - packet.frame = frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, (const char *)&packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, (const char *)&packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, (const char *)safety_set_allowed_area, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); #endif } @@ -245,39 +263,31 @@ static inline void mavlink_msg_safety_set_allowed_area_send(mavlink_channel_t ch static inline void mavlink_msg_safety_set_allowed_area_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t target_component, uint8_t frame, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, p1x); - _mav_put_float(buf, 4, p1y); - _mav_put_float(buf, 8, p1z); - _mav_put_float(buf, 12, p2x); - _mav_put_float(buf, 16, p2y); - _mav_put_float(buf, 20, p2z); - _mav_put_uint8_t(buf, 24, target_system); - _mav_put_uint8_t(buf, 25, target_component); - _mav_put_uint8_t(buf, 26, frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); -#endif -#else - mavlink_safety_set_allowed_area_t *packet = (mavlink_safety_set_allowed_area_t *)msgbuf; - packet->p1x = p1x; - packet->p1y = p1y; - packet->p1z = p1z; - packet->p2x = p2x; - packet->p2y = p2y; - packet->p2z = p2z; - packet->target_system = target_system; - packet->target_component = target_component; - packet->frame = frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, (const char *)packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, p1x); + _mav_put_float(buf, 4, p1y); + _mav_put_float(buf, 8, p1z); + _mav_put_float(buf, 12, p2x); + _mav_put_float(buf, 16, p2y); + _mav_put_float(buf, 20, p2z); + _mav_put_uint8_t(buf, 24, target_system); + _mav_put_uint8_t(buf, 25, target_component); + _mav_put_uint8_t(buf, 26, frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, buf, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, (const char *)packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); -#endif + mavlink_safety_set_allowed_area_t *packet = (mavlink_safety_set_allowed_area_t *)msgbuf; + packet->p1x = p1x; + packet->p1y = p1y; + packet->p1z = p1z; + packet->p2x = p2x; + packet->p2y = p2y; + packet->p2z = p2z; + packet->target_system = target_system; + packet->target_component = target_component; + packet->frame = frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA, (const char *)packet, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_CRC); #endif } #endif @@ -294,7 +304,7 @@ static inline void mavlink_msg_safety_set_allowed_area_send_buf(mavlink_message_ */ static inline uint8_t mavlink_msg_safety_set_allowed_area_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 24); + return _MAV_RETURN_uint8_t(msg, 24); } /** @@ -304,7 +314,7 @@ static inline uint8_t mavlink_msg_safety_set_allowed_area_get_target_system(cons */ static inline uint8_t mavlink_msg_safety_set_allowed_area_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 25); + return _MAV_RETURN_uint8_t(msg, 25); } /** @@ -314,7 +324,7 @@ static inline uint8_t mavlink_msg_safety_set_allowed_area_get_target_component(c */ static inline uint8_t mavlink_msg_safety_set_allowed_area_get_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 26); + return _MAV_RETURN_uint8_t(msg, 26); } /** @@ -324,7 +334,7 @@ static inline uint8_t mavlink_msg_safety_set_allowed_area_get_frame(const mavlin */ static inline float mavlink_msg_safety_set_allowed_area_get_p1x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -334,7 +344,7 @@ static inline float mavlink_msg_safety_set_allowed_area_get_p1x(const mavlink_me */ static inline float mavlink_msg_safety_set_allowed_area_get_p1y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -344,7 +354,7 @@ static inline float mavlink_msg_safety_set_allowed_area_get_p1y(const mavlink_me */ static inline float mavlink_msg_safety_set_allowed_area_get_p1z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -354,7 +364,7 @@ static inline float mavlink_msg_safety_set_allowed_area_get_p1z(const mavlink_me */ static inline float mavlink_msg_safety_set_allowed_area_get_p2x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -364,7 +374,7 @@ static inline float mavlink_msg_safety_set_allowed_area_get_p2x(const mavlink_me */ static inline float mavlink_msg_safety_set_allowed_area_get_p2y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -374,7 +384,7 @@ static inline float mavlink_msg_safety_set_allowed_area_get_p2y(const mavlink_me */ static inline float mavlink_msg_safety_set_allowed_area_get_p2z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -385,17 +395,19 @@ static inline float mavlink_msg_safety_set_allowed_area_get_p2z(const mavlink_me */ static inline void mavlink_msg_safety_set_allowed_area_decode(const mavlink_message_t* msg, mavlink_safety_set_allowed_area_t* safety_set_allowed_area) { -#if MAVLINK_NEED_BYTE_SWAP - safety_set_allowed_area->p1x = mavlink_msg_safety_set_allowed_area_get_p1x(msg); - safety_set_allowed_area->p1y = mavlink_msg_safety_set_allowed_area_get_p1y(msg); - safety_set_allowed_area->p1z = mavlink_msg_safety_set_allowed_area_get_p1z(msg); - safety_set_allowed_area->p2x = mavlink_msg_safety_set_allowed_area_get_p2x(msg); - safety_set_allowed_area->p2y = mavlink_msg_safety_set_allowed_area_get_p2y(msg); - safety_set_allowed_area->p2z = mavlink_msg_safety_set_allowed_area_get_p2z(msg); - safety_set_allowed_area->target_system = mavlink_msg_safety_set_allowed_area_get_target_system(msg); - safety_set_allowed_area->target_component = mavlink_msg_safety_set_allowed_area_get_target_component(msg); - safety_set_allowed_area->frame = mavlink_msg_safety_set_allowed_area_get_frame(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + safety_set_allowed_area->p1x = mavlink_msg_safety_set_allowed_area_get_p1x(msg); + safety_set_allowed_area->p1y = mavlink_msg_safety_set_allowed_area_get_p1y(msg); + safety_set_allowed_area->p1z = mavlink_msg_safety_set_allowed_area_get_p1z(msg); + safety_set_allowed_area->p2x = mavlink_msg_safety_set_allowed_area_get_p2x(msg); + safety_set_allowed_area->p2y = mavlink_msg_safety_set_allowed_area_get_p2y(msg); + safety_set_allowed_area->p2z = mavlink_msg_safety_set_allowed_area_get_p2z(msg); + safety_set_allowed_area->target_system = mavlink_msg_safety_set_allowed_area_get_target_system(msg); + safety_set_allowed_area->target_component = mavlink_msg_safety_set_allowed_area_get_target_component(msg); + safety_set_allowed_area->frame = mavlink_msg_safety_set_allowed_area_get_frame(msg); #else - memcpy(safety_set_allowed_area, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN? msg->len : MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN; + memset(safety_set_allowed_area, 0, MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_LEN); + memcpy(safety_set_allowed_area, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu.h b/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu.h index 1648a56f89..2994d999a5 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE SCALED_IMU PACKING #define MAVLINK_MSG_ID_SCALED_IMU 26 -typedef struct __mavlink_scaled_imu_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - int16_t xacc; ///< X acceleration (mg) - int16_t yacc; ///< Y acceleration (mg) - int16_t zacc; ///< Z acceleration (mg) - int16_t xgyro; ///< Angular speed around X axis (millirad /sec) - int16_t ygyro; ///< Angular speed around Y axis (millirad /sec) - int16_t zgyro; ///< Angular speed around Z axis (millirad /sec) - int16_t xmag; ///< X Magnetic field (milli tesla) - int16_t ymag; ///< Y Magnetic field (milli tesla) - int16_t zmag; ///< Z Magnetic field (milli tesla) -} mavlink_scaled_imu_t; +MAVPACKED( +typedef struct __mavlink_scaled_imu_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + int16_t xacc; /*< X acceleration (mg)*/ + int16_t yacc; /*< Y acceleration (mg)*/ + int16_t zacc; /*< Z acceleration (mg)*/ + int16_t xgyro; /*< Angular speed around X axis (millirad /sec)*/ + int16_t ygyro; /*< Angular speed around Y axis (millirad /sec)*/ + int16_t zgyro; /*< Angular speed around Z axis (millirad /sec)*/ + int16_t xmag; /*< X Magnetic field (milli tesla)*/ + int16_t ymag; /*< Y Magnetic field (milli tesla)*/ + int16_t zmag; /*< Z Magnetic field (milli tesla)*/ +}) mavlink_scaled_imu_t; #define MAVLINK_MSG_ID_SCALED_IMU_LEN 22 +#define MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN 22 #define MAVLINK_MSG_ID_26_LEN 22 +#define MAVLINK_MSG_ID_26_MIN_LEN 22 #define MAVLINK_MSG_ID_SCALED_IMU_CRC 170 #define MAVLINK_MSG_ID_26_CRC 170 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SCALED_IMU { \ - "SCALED_IMU", \ - 10, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu_t, time_boot_ms) }, \ + 26, \ + "SCALED_IMU", \ + 10, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu_t, time_boot_ms) }, \ { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_scaled_imu_t, xacc) }, \ { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_scaled_imu_t, yacc) }, \ { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_scaled_imu_t, zacc) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_scaled_imu_t { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_scaled_imu_t, zmag) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SCALED_IMU { \ + "SCALED_IMU", \ + 10, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu_t, time_boot_ms) }, \ + { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_scaled_imu_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_scaled_imu_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_scaled_imu_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_scaled_imu_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_imu_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_scaled_imu_t, zgyro) }, \ + { "xmag", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_scaled_imu_t, xmag) }, \ + { "ymag", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_scaled_imu_t, ymag) }, \ + { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_scaled_imu_t, zmag) }, \ + } \ +} +#endif /** * @brief Pack a scaled_imu message @@ -60,44 +81,40 @@ typedef struct __mavlink_scaled_imu_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_imu_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) + uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_IMU_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); + char buf[MAVLINK_MSG_ID_SCALED_IMU_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_IMU_LEN); #else - mavlink_scaled_imu_t packet; - packet.time_boot_ms = time_boot_ms; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; + mavlink_scaled_imu_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_IMU_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_IMU; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_IMU_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_IMU; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_scaled_imu_pack(uint8_t system_id, uint8_t co * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_imu_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,int16_t xacc,int16_t yacc,int16_t zacc,int16_t xgyro,int16_t ygyro,int16_t zgyro,int16_t xmag,int16_t ymag,int16_t zmag) + mavlink_message_t* msg, + uint32_t time_boot_ms,int16_t xacc,int16_t yacc,int16_t zacc,int16_t xgyro,int16_t ygyro,int16_t zgyro,int16_t xmag,int16_t ymag,int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_IMU_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); + char buf[MAVLINK_MSG_ID_SCALED_IMU_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_IMU_LEN); #else - mavlink_scaled_imu_t packet; - packet.time_boot_ms = time_boot_ms; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; + mavlink_scaled_imu_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_IMU_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_IMU; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_IMU_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_IMU; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_scaled_imu_pack_chan(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_scaled_imu_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_scaled_imu_t* scaled_imu) { - return mavlink_msg_scaled_imu_pack(system_id, component_id, msg, scaled_imu->time_boot_ms, scaled_imu->xacc, scaled_imu->yacc, scaled_imu->zacc, scaled_imu->xgyro, scaled_imu->ygyro, scaled_imu->zgyro, scaled_imu->xmag, scaled_imu->ymag, scaled_imu->zmag); + return mavlink_msg_scaled_imu_pack(system_id, component_id, msg, scaled_imu->time_boot_ms, scaled_imu->xacc, scaled_imu->yacc, scaled_imu->zacc, scaled_imu->xgyro, scaled_imu->ygyro, scaled_imu->zgyro, scaled_imu->xmag, scaled_imu->ymag, scaled_imu->zmag); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_scaled_imu_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_scaled_imu_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_imu_t* scaled_imu) { - return mavlink_msg_scaled_imu_pack_chan(system_id, component_id, chan, msg, scaled_imu->time_boot_ms, scaled_imu->xacc, scaled_imu->yacc, scaled_imu->zacc, scaled_imu->xgyro, scaled_imu->ygyro, scaled_imu->zgyro, scaled_imu->xmag, scaled_imu->ymag, scaled_imu->zmag); + return mavlink_msg_scaled_imu_pack_chan(system_id, component_id, chan, msg, scaled_imu->time_boot_ms, scaled_imu->xacc, scaled_imu->yacc, scaled_imu->zacc, scaled_imu->xgyro, scaled_imu->ygyro, scaled_imu->zgyro, scaled_imu->xmag, scaled_imu->ymag, scaled_imu->zmag); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_scaled_imu_encode_chan(uint8_t system_id, uin static inline void mavlink_msg_scaled_imu_send(mavlink_channel_t chan, uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_IMU_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, buf, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); + char buf[MAVLINK_MSG_ID_SCALED_IMU_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, buf, MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, buf, MAVLINK_MSG_ID_SCALED_IMU_LEN); + mavlink_scaled_imu_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, (const char *)&packet, MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); #endif +} + +/** + * @brief Send a scaled_imu message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_scaled_imu_send_struct(mavlink_channel_t chan, const mavlink_scaled_imu_t* scaled_imu) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_scaled_imu_send(chan, scaled_imu->time_boot_ms, scaled_imu->xacc, scaled_imu->yacc, scaled_imu->zacc, scaled_imu->xgyro, scaled_imu->ygyro, scaled_imu->zgyro, scaled_imu->xmag, scaled_imu->ymag, scaled_imu->zmag); #else - mavlink_scaled_imu_t packet; - packet.time_boot_ms = time_boot_ms; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, (const char *)&packet, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, (const char *)&packet, MAVLINK_MSG_ID_SCALED_IMU_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, (const char *)scaled_imu, MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_scaled_imu_send(mavlink_channel_t chan, uint32_t static inline void mavlink_msg_scaled_imu_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, buf, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, buf, MAVLINK_MSG_ID_SCALED_IMU_LEN); -#endif -#else - mavlink_scaled_imu_t *packet = (mavlink_scaled_imu_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - packet->xgyro = xgyro; - packet->ygyro = ygyro; - packet->zgyro = zgyro; - packet->xmag = xmag; - packet->ymag = ymag; - packet->zmag = zmag; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, (const char *)packet, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, buf, MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, (const char *)packet, MAVLINK_MSG_ID_SCALED_IMU_LEN); -#endif + mavlink_scaled_imu_t *packet = (mavlink_scaled_imu_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->xmag = xmag; + packet->ymag = ymag; + packet->zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU, (const char *)packet, MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU_LEN, MAVLINK_MSG_ID_SCALED_IMU_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_scaled_imu_send_buf(mavlink_message_t *msgbuf, ma */ static inline uint32_t mavlink_msg_scaled_imu_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -317,7 +328,7 @@ static inline uint32_t mavlink_msg_scaled_imu_get_time_boot_ms(const mavlink_mes */ static inline int16_t mavlink_msg_scaled_imu_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 4); + return _MAV_RETURN_int16_t(msg, 4); } /** @@ -327,7 +338,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_xacc(const mavlink_message_t* m */ static inline int16_t mavlink_msg_scaled_imu_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 6); + return _MAV_RETURN_int16_t(msg, 6); } /** @@ -337,7 +348,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_yacc(const mavlink_message_t* m */ static inline int16_t mavlink_msg_scaled_imu_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 8); + return _MAV_RETURN_int16_t(msg, 8); } /** @@ -347,7 +358,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_zacc(const mavlink_message_t* m */ static inline int16_t mavlink_msg_scaled_imu_get_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 10); + return _MAV_RETURN_int16_t(msg, 10); } /** @@ -357,7 +368,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_xgyro(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu_get_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 12); + return _MAV_RETURN_int16_t(msg, 12); } /** @@ -367,7 +378,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_ygyro(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu_get_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 14); + return _MAV_RETURN_int16_t(msg, 14); } /** @@ -377,7 +388,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_zgyro(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu_get_xmag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 16); + return _MAV_RETURN_int16_t(msg, 16); } /** @@ -387,7 +398,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_xmag(const mavlink_message_t* m */ static inline int16_t mavlink_msg_scaled_imu_get_ymag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 18); + return _MAV_RETURN_int16_t(msg, 18); } /** @@ -397,7 +408,7 @@ static inline int16_t mavlink_msg_scaled_imu_get_ymag(const mavlink_message_t* m */ static inline int16_t mavlink_msg_scaled_imu_get_zmag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 20); + return _MAV_RETURN_int16_t(msg, 20); } /** @@ -408,18 +419,20 @@ static inline int16_t mavlink_msg_scaled_imu_get_zmag(const mavlink_message_t* m */ static inline void mavlink_msg_scaled_imu_decode(const mavlink_message_t* msg, mavlink_scaled_imu_t* scaled_imu) { -#if MAVLINK_NEED_BYTE_SWAP - scaled_imu->time_boot_ms = mavlink_msg_scaled_imu_get_time_boot_ms(msg); - scaled_imu->xacc = mavlink_msg_scaled_imu_get_xacc(msg); - scaled_imu->yacc = mavlink_msg_scaled_imu_get_yacc(msg); - scaled_imu->zacc = mavlink_msg_scaled_imu_get_zacc(msg); - scaled_imu->xgyro = mavlink_msg_scaled_imu_get_xgyro(msg); - scaled_imu->ygyro = mavlink_msg_scaled_imu_get_ygyro(msg); - scaled_imu->zgyro = mavlink_msg_scaled_imu_get_zgyro(msg); - scaled_imu->xmag = mavlink_msg_scaled_imu_get_xmag(msg); - scaled_imu->ymag = mavlink_msg_scaled_imu_get_ymag(msg); - scaled_imu->zmag = mavlink_msg_scaled_imu_get_zmag(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + scaled_imu->time_boot_ms = mavlink_msg_scaled_imu_get_time_boot_ms(msg); + scaled_imu->xacc = mavlink_msg_scaled_imu_get_xacc(msg); + scaled_imu->yacc = mavlink_msg_scaled_imu_get_yacc(msg); + scaled_imu->zacc = mavlink_msg_scaled_imu_get_zacc(msg); + scaled_imu->xgyro = mavlink_msg_scaled_imu_get_xgyro(msg); + scaled_imu->ygyro = mavlink_msg_scaled_imu_get_ygyro(msg); + scaled_imu->zgyro = mavlink_msg_scaled_imu_get_zgyro(msg); + scaled_imu->xmag = mavlink_msg_scaled_imu_get_xmag(msg); + scaled_imu->ymag = mavlink_msg_scaled_imu_get_ymag(msg); + scaled_imu->zmag = mavlink_msg_scaled_imu_get_zmag(msg); #else - memcpy(scaled_imu, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SCALED_IMU_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SCALED_IMU_LEN? msg->len : MAVLINK_MSG_ID_SCALED_IMU_LEN; + memset(scaled_imu, 0, MAVLINK_MSG_ID_SCALED_IMU_LEN); + memcpy(scaled_imu, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu2.h b/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu2.h index 1dea121dde..c232691790 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu2.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu2.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE SCALED_IMU2 PACKING #define MAVLINK_MSG_ID_SCALED_IMU2 116 -typedef struct __mavlink_scaled_imu2_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - int16_t xacc; ///< X acceleration (mg) - int16_t yacc; ///< Y acceleration (mg) - int16_t zacc; ///< Z acceleration (mg) - int16_t xgyro; ///< Angular speed around X axis (millirad /sec) - int16_t ygyro; ///< Angular speed around Y axis (millirad /sec) - int16_t zgyro; ///< Angular speed around Z axis (millirad /sec) - int16_t xmag; ///< X Magnetic field (milli tesla) - int16_t ymag; ///< Y Magnetic field (milli tesla) - int16_t zmag; ///< Z Magnetic field (milli tesla) -} mavlink_scaled_imu2_t; +MAVPACKED( +typedef struct __mavlink_scaled_imu2_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + int16_t xacc; /*< X acceleration (mg)*/ + int16_t yacc; /*< Y acceleration (mg)*/ + int16_t zacc; /*< Z acceleration (mg)*/ + int16_t xgyro; /*< Angular speed around X axis (millirad /sec)*/ + int16_t ygyro; /*< Angular speed around Y axis (millirad /sec)*/ + int16_t zgyro; /*< Angular speed around Z axis (millirad /sec)*/ + int16_t xmag; /*< X Magnetic field (milli tesla)*/ + int16_t ymag; /*< Y Magnetic field (milli tesla)*/ + int16_t zmag; /*< Z Magnetic field (milli tesla)*/ +}) mavlink_scaled_imu2_t; #define MAVLINK_MSG_ID_SCALED_IMU2_LEN 22 +#define MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN 22 #define MAVLINK_MSG_ID_116_LEN 22 +#define MAVLINK_MSG_ID_116_MIN_LEN 22 #define MAVLINK_MSG_ID_SCALED_IMU2_CRC 76 #define MAVLINK_MSG_ID_116_CRC 76 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SCALED_IMU2 { \ - "SCALED_IMU2", \ - 10, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu2_t, time_boot_ms) }, \ + 116, \ + "SCALED_IMU2", \ + 10, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu2_t, time_boot_ms) }, \ { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_scaled_imu2_t, xacc) }, \ { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_scaled_imu2_t, yacc) }, \ { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_scaled_imu2_t, zacc) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_scaled_imu2_t { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_scaled_imu2_t, zmag) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SCALED_IMU2 { \ + "SCALED_IMU2", \ + 10, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu2_t, time_boot_ms) }, \ + { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_scaled_imu2_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_scaled_imu2_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_scaled_imu2_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_scaled_imu2_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_imu2_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_scaled_imu2_t, zgyro) }, \ + { "xmag", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_scaled_imu2_t, xmag) }, \ + { "ymag", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_scaled_imu2_t, ymag) }, \ + { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_scaled_imu2_t, zmag) }, \ + } \ +} +#endif /** * @brief Pack a scaled_imu2 message @@ -60,44 +81,40 @@ typedef struct __mavlink_scaled_imu2_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_imu2_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) + uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_IMU2_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); + char buf[MAVLINK_MSG_ID_SCALED_IMU2_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_IMU2_LEN); #else - mavlink_scaled_imu2_t packet; - packet.time_boot_ms = time_boot_ms; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; + mavlink_scaled_imu2_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_IMU2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_IMU2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_IMU2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_IMU2; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_scaled_imu2_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_imu2_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,int16_t xacc,int16_t yacc,int16_t zacc,int16_t xgyro,int16_t ygyro,int16_t zgyro,int16_t xmag,int16_t ymag,int16_t zmag) + mavlink_message_t* msg, + uint32_t time_boot_ms,int16_t xacc,int16_t yacc,int16_t zacc,int16_t xgyro,int16_t ygyro,int16_t zgyro,int16_t xmag,int16_t ymag,int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_IMU2_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); + char buf[MAVLINK_MSG_ID_SCALED_IMU2_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_IMU2_LEN); #else - mavlink_scaled_imu2_t packet; - packet.time_boot_ms = time_boot_ms; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; + mavlink_scaled_imu2_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_IMU2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_IMU2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_IMU2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_IMU2; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_scaled_imu2_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_scaled_imu2_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_scaled_imu2_t* scaled_imu2) { - return mavlink_msg_scaled_imu2_pack(system_id, component_id, msg, scaled_imu2->time_boot_ms, scaled_imu2->xacc, scaled_imu2->yacc, scaled_imu2->zacc, scaled_imu2->xgyro, scaled_imu2->ygyro, scaled_imu2->zgyro, scaled_imu2->xmag, scaled_imu2->ymag, scaled_imu2->zmag); + return mavlink_msg_scaled_imu2_pack(system_id, component_id, msg, scaled_imu2->time_boot_ms, scaled_imu2->xacc, scaled_imu2->yacc, scaled_imu2->zacc, scaled_imu2->xgyro, scaled_imu2->ygyro, scaled_imu2->zgyro, scaled_imu2->xmag, scaled_imu2->ymag, scaled_imu2->zmag); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_scaled_imu2_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_scaled_imu2_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_imu2_t* scaled_imu2) { - return mavlink_msg_scaled_imu2_pack_chan(system_id, component_id, chan, msg, scaled_imu2->time_boot_ms, scaled_imu2->xacc, scaled_imu2->yacc, scaled_imu2->zacc, scaled_imu2->xgyro, scaled_imu2->ygyro, scaled_imu2->zgyro, scaled_imu2->xmag, scaled_imu2->ymag, scaled_imu2->zmag); + return mavlink_msg_scaled_imu2_pack_chan(system_id, component_id, chan, msg, scaled_imu2->time_boot_ms, scaled_imu2->xacc, scaled_imu2->yacc, scaled_imu2->zacc, scaled_imu2->xgyro, scaled_imu2->ygyro, scaled_imu2->zgyro, scaled_imu2->xmag, scaled_imu2->ymag, scaled_imu2->zmag); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_scaled_imu2_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_scaled_imu2_send(mavlink_channel_t chan, uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_IMU2_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, buf, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); + char buf[MAVLINK_MSG_ID_SCALED_IMU2_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, buf, MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, buf, MAVLINK_MSG_ID_SCALED_IMU2_LEN); + mavlink_scaled_imu2_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, (const char *)&packet, MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); #endif +} + +/** + * @brief Send a scaled_imu2 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_scaled_imu2_send_struct(mavlink_channel_t chan, const mavlink_scaled_imu2_t* scaled_imu2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_scaled_imu2_send(chan, scaled_imu2->time_boot_ms, scaled_imu2->xacc, scaled_imu2->yacc, scaled_imu2->zacc, scaled_imu2->xgyro, scaled_imu2->ygyro, scaled_imu2->zgyro, scaled_imu2->xmag, scaled_imu2->ymag, scaled_imu2->zmag); #else - mavlink_scaled_imu2_t packet; - packet.time_boot_ms = time_boot_ms; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.xmag = xmag; - packet.ymag = ymag; - packet.zmag = zmag; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, (const char *)&packet, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, (const char *)&packet, MAVLINK_MSG_ID_SCALED_IMU2_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, (const char *)scaled_imu2, MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_scaled_imu2_send(mavlink_channel_t chan, uint32_t static inline void mavlink_msg_scaled_imu2_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int16_t(buf, 4, xacc); - _mav_put_int16_t(buf, 6, yacc); - _mav_put_int16_t(buf, 8, zacc); - _mav_put_int16_t(buf, 10, xgyro); - _mav_put_int16_t(buf, 12, ygyro); - _mav_put_int16_t(buf, 14, zgyro); - _mav_put_int16_t(buf, 16, xmag); - _mav_put_int16_t(buf, 18, ymag); - _mav_put_int16_t(buf, 20, zmag); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, buf, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, buf, MAVLINK_MSG_ID_SCALED_IMU2_LEN); -#endif -#else - mavlink_scaled_imu2_t *packet = (mavlink_scaled_imu2_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - packet->xgyro = xgyro; - packet->ygyro = ygyro; - packet->zgyro = zgyro; - packet->xmag = xmag; - packet->ymag = ymag; - packet->zmag = zmag; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, (const char *)packet, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, buf, MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, (const char *)packet, MAVLINK_MSG_ID_SCALED_IMU2_LEN); -#endif + mavlink_scaled_imu2_t *packet = (mavlink_scaled_imu2_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->xmag = xmag; + packet->ymag = ymag; + packet->zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU2, (const char *)packet, MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU2_LEN, MAVLINK_MSG_ID_SCALED_IMU2_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_scaled_imu2_send_buf(mavlink_message_t *msgbuf, m */ static inline uint32_t mavlink_msg_scaled_imu2_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -317,7 +328,7 @@ static inline uint32_t mavlink_msg_scaled_imu2_get_time_boot_ms(const mavlink_me */ static inline int16_t mavlink_msg_scaled_imu2_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 4); + return _MAV_RETURN_int16_t(msg, 4); } /** @@ -327,7 +338,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_xacc(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 6); + return _MAV_RETURN_int16_t(msg, 6); } /** @@ -337,7 +348,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_yacc(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 8); + return _MAV_RETURN_int16_t(msg, 8); } /** @@ -347,7 +358,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_zacc(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 10); + return _MAV_RETURN_int16_t(msg, 10); } /** @@ -357,7 +368,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_xgyro(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 12); + return _MAV_RETURN_int16_t(msg, 12); } /** @@ -367,7 +378,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_ygyro(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 14); + return _MAV_RETURN_int16_t(msg, 14); } /** @@ -377,7 +388,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_zgyro(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_xmag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 16); + return _MAV_RETURN_int16_t(msg, 16); } /** @@ -387,7 +398,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_xmag(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_ymag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 18); + return _MAV_RETURN_int16_t(msg, 18); } /** @@ -397,7 +408,7 @@ static inline int16_t mavlink_msg_scaled_imu2_get_ymag(const mavlink_message_t* */ static inline int16_t mavlink_msg_scaled_imu2_get_zmag(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 20); + return _MAV_RETURN_int16_t(msg, 20); } /** @@ -408,18 +419,20 @@ static inline int16_t mavlink_msg_scaled_imu2_get_zmag(const mavlink_message_t* */ static inline void mavlink_msg_scaled_imu2_decode(const mavlink_message_t* msg, mavlink_scaled_imu2_t* scaled_imu2) { -#if MAVLINK_NEED_BYTE_SWAP - scaled_imu2->time_boot_ms = mavlink_msg_scaled_imu2_get_time_boot_ms(msg); - scaled_imu2->xacc = mavlink_msg_scaled_imu2_get_xacc(msg); - scaled_imu2->yacc = mavlink_msg_scaled_imu2_get_yacc(msg); - scaled_imu2->zacc = mavlink_msg_scaled_imu2_get_zacc(msg); - scaled_imu2->xgyro = mavlink_msg_scaled_imu2_get_xgyro(msg); - scaled_imu2->ygyro = mavlink_msg_scaled_imu2_get_ygyro(msg); - scaled_imu2->zgyro = mavlink_msg_scaled_imu2_get_zgyro(msg); - scaled_imu2->xmag = mavlink_msg_scaled_imu2_get_xmag(msg); - scaled_imu2->ymag = mavlink_msg_scaled_imu2_get_ymag(msg); - scaled_imu2->zmag = mavlink_msg_scaled_imu2_get_zmag(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + scaled_imu2->time_boot_ms = mavlink_msg_scaled_imu2_get_time_boot_ms(msg); + scaled_imu2->xacc = mavlink_msg_scaled_imu2_get_xacc(msg); + scaled_imu2->yacc = mavlink_msg_scaled_imu2_get_yacc(msg); + scaled_imu2->zacc = mavlink_msg_scaled_imu2_get_zacc(msg); + scaled_imu2->xgyro = mavlink_msg_scaled_imu2_get_xgyro(msg); + scaled_imu2->ygyro = mavlink_msg_scaled_imu2_get_ygyro(msg); + scaled_imu2->zgyro = mavlink_msg_scaled_imu2_get_zgyro(msg); + scaled_imu2->xmag = mavlink_msg_scaled_imu2_get_xmag(msg); + scaled_imu2->ymag = mavlink_msg_scaled_imu2_get_ymag(msg); + scaled_imu2->zmag = mavlink_msg_scaled_imu2_get_zmag(msg); #else - memcpy(scaled_imu2, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SCALED_IMU2_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SCALED_IMU2_LEN? msg->len : MAVLINK_MSG_ID_SCALED_IMU2_LEN; + memset(scaled_imu2, 0, MAVLINK_MSG_ID_SCALED_IMU2_LEN); + memcpy(scaled_imu2, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu3.h b/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu3.h new file mode 100644 index 0000000000..22b9d86cf0 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_scaled_imu3.h @@ -0,0 +1,438 @@ +#pragma once +// MESSAGE SCALED_IMU3 PACKING + +#define MAVLINK_MSG_ID_SCALED_IMU3 129 + +MAVPACKED( +typedef struct __mavlink_scaled_imu3_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + int16_t xacc; /*< X acceleration (mg)*/ + int16_t yacc; /*< Y acceleration (mg)*/ + int16_t zacc; /*< Z acceleration (mg)*/ + int16_t xgyro; /*< Angular speed around X axis (millirad /sec)*/ + int16_t ygyro; /*< Angular speed around Y axis (millirad /sec)*/ + int16_t zgyro; /*< Angular speed around Z axis (millirad /sec)*/ + int16_t xmag; /*< X Magnetic field (milli tesla)*/ + int16_t ymag; /*< Y Magnetic field (milli tesla)*/ + int16_t zmag; /*< Z Magnetic field (milli tesla)*/ +}) mavlink_scaled_imu3_t; + +#define MAVLINK_MSG_ID_SCALED_IMU3_LEN 22 +#define MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN 22 +#define MAVLINK_MSG_ID_129_LEN 22 +#define MAVLINK_MSG_ID_129_MIN_LEN 22 + +#define MAVLINK_MSG_ID_SCALED_IMU3_CRC 46 +#define MAVLINK_MSG_ID_129_CRC 46 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_SCALED_IMU3 { \ + 129, \ + "SCALED_IMU3", \ + 10, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu3_t, time_boot_ms) }, \ + { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_scaled_imu3_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_scaled_imu3_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_scaled_imu3_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_scaled_imu3_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_imu3_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_scaled_imu3_t, zgyro) }, \ + { "xmag", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_scaled_imu3_t, xmag) }, \ + { "ymag", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_scaled_imu3_t, ymag) }, \ + { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_scaled_imu3_t, zmag) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_SCALED_IMU3 { \ + "SCALED_IMU3", \ + 10, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_imu3_t, time_boot_ms) }, \ + { "xacc", NULL, MAVLINK_TYPE_INT16_T, 0, 4, offsetof(mavlink_scaled_imu3_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_INT16_T, 0, 6, offsetof(mavlink_scaled_imu3_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_INT16_T, 0, 8, offsetof(mavlink_scaled_imu3_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 10, offsetof(mavlink_scaled_imu3_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_imu3_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_INT16_T, 0, 14, offsetof(mavlink_scaled_imu3_t, zgyro) }, \ + { "xmag", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_scaled_imu3_t, xmag) }, \ + { "ymag", NULL, MAVLINK_TYPE_INT16_T, 0, 18, offsetof(mavlink_scaled_imu3_t, ymag) }, \ + { "zmag", NULL, MAVLINK_TYPE_INT16_T, 0, 20, offsetof(mavlink_scaled_imu3_t, zmag) }, \ + } \ +} +#endif + +/** + * @brief Pack a scaled_imu3 message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param xacc X acceleration (mg) + * @param yacc Y acceleration (mg) + * @param zacc Z acceleration (mg) + * @param xgyro Angular speed around X axis (millirad /sec) + * @param ygyro Angular speed around Y axis (millirad /sec) + * @param zgyro Angular speed around Z axis (millirad /sec) + * @param xmag X Magnetic field (milli tesla) + * @param ymag Y Magnetic field (milli tesla) + * @param zmag Z Magnetic field (milli tesla) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_scaled_imu3_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SCALED_IMU3_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_IMU3_LEN); +#else + mavlink_scaled_imu3_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_IMU3_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_SCALED_IMU3; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU3_LEN, MAVLINK_MSG_ID_SCALED_IMU3_CRC); +} + +/** + * @brief Pack a scaled_imu3 message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param xacc X acceleration (mg) + * @param yacc Y acceleration (mg) + * @param zacc Z acceleration (mg) + * @param xgyro Angular speed around X axis (millirad /sec) + * @param ygyro Angular speed around Y axis (millirad /sec) + * @param zgyro Angular speed around Z axis (millirad /sec) + * @param xmag X Magnetic field (milli tesla) + * @param ymag Y Magnetic field (milli tesla) + * @param zmag Z Magnetic field (milli tesla) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_scaled_imu3_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint32_t time_boot_ms,int16_t xacc,int16_t yacc,int16_t zacc,int16_t xgyro,int16_t ygyro,int16_t zgyro,int16_t xmag,int16_t ymag,int16_t zmag) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SCALED_IMU3_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_IMU3_LEN); +#else + mavlink_scaled_imu3_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_IMU3_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_SCALED_IMU3; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU3_LEN, MAVLINK_MSG_ID_SCALED_IMU3_CRC); +} + +/** + * @brief Encode a scaled_imu3 struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param scaled_imu3 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_scaled_imu3_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_scaled_imu3_t* scaled_imu3) +{ + return mavlink_msg_scaled_imu3_pack(system_id, component_id, msg, scaled_imu3->time_boot_ms, scaled_imu3->xacc, scaled_imu3->yacc, scaled_imu3->zacc, scaled_imu3->xgyro, scaled_imu3->ygyro, scaled_imu3->zgyro, scaled_imu3->xmag, scaled_imu3->ymag, scaled_imu3->zmag); +} + +/** + * @brief Encode a scaled_imu3 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param scaled_imu3 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_scaled_imu3_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_imu3_t* scaled_imu3) +{ + return mavlink_msg_scaled_imu3_pack_chan(system_id, component_id, chan, msg, scaled_imu3->time_boot_ms, scaled_imu3->xacc, scaled_imu3->yacc, scaled_imu3->zacc, scaled_imu3->xgyro, scaled_imu3->ygyro, scaled_imu3->zgyro, scaled_imu3->xmag, scaled_imu3->ymag, scaled_imu3->zmag); +} + +/** + * @brief Send a scaled_imu3 message + * @param chan MAVLink channel to send the message + * + * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param xacc X acceleration (mg) + * @param yacc Y acceleration (mg) + * @param zacc Z acceleration (mg) + * @param xgyro Angular speed around X axis (millirad /sec) + * @param ygyro Angular speed around Y axis (millirad /sec) + * @param zgyro Angular speed around Z axis (millirad /sec) + * @param xmag X Magnetic field (milli tesla) + * @param ymag Y Magnetic field (milli tesla) + * @param zmag Z Magnetic field (milli tesla) + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_scaled_imu3_send(mavlink_channel_t chan, uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SCALED_IMU3_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU3, buf, MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU3_LEN, MAVLINK_MSG_ID_SCALED_IMU3_CRC); +#else + mavlink_scaled_imu3_t packet; + packet.time_boot_ms = time_boot_ms; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.xmag = xmag; + packet.ymag = ymag; + packet.zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU3, (const char *)&packet, MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU3_LEN, MAVLINK_MSG_ID_SCALED_IMU3_CRC); +#endif +} + +/** + * @brief Send a scaled_imu3 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_scaled_imu3_send_struct(mavlink_channel_t chan, const mavlink_scaled_imu3_t* scaled_imu3) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_scaled_imu3_send(chan, scaled_imu3->time_boot_ms, scaled_imu3->xacc, scaled_imu3->yacc, scaled_imu3->zacc, scaled_imu3->xgyro, scaled_imu3->ygyro, scaled_imu3->zgyro, scaled_imu3->xmag, scaled_imu3->ymag, scaled_imu3->zmag); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU3, (const char *)scaled_imu3, MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU3_LEN, MAVLINK_MSG_ID_SCALED_IMU3_CRC); +#endif +} + +#if MAVLINK_MSG_ID_SCALED_IMU3_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_scaled_imu3_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, int16_t xacc, int16_t yacc, int16_t zacc, int16_t xgyro, int16_t ygyro, int16_t zgyro, int16_t xmag, int16_t ymag, int16_t zmag) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int16_t(buf, 4, xacc); + _mav_put_int16_t(buf, 6, yacc); + _mav_put_int16_t(buf, 8, zacc); + _mav_put_int16_t(buf, 10, xgyro); + _mav_put_int16_t(buf, 12, ygyro); + _mav_put_int16_t(buf, 14, zgyro); + _mav_put_int16_t(buf, 16, xmag); + _mav_put_int16_t(buf, 18, ymag); + _mav_put_int16_t(buf, 20, zmag); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU3, buf, MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU3_LEN, MAVLINK_MSG_ID_SCALED_IMU3_CRC); +#else + mavlink_scaled_imu3_t *packet = (mavlink_scaled_imu3_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->xmag = xmag; + packet->ymag = ymag; + packet->zmag = zmag; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_IMU3, (const char *)packet, MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN, MAVLINK_MSG_ID_SCALED_IMU3_LEN, MAVLINK_MSG_ID_SCALED_IMU3_CRC); +#endif +} +#endif + +#endif + +// MESSAGE SCALED_IMU3 UNPACKING + + +/** + * @brief Get field time_boot_ms from scaled_imu3 message + * + * @return Timestamp (milliseconds since system boot) + */ +static inline uint32_t mavlink_msg_scaled_imu3_get_time_boot_ms(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 0); +} + +/** + * @brief Get field xacc from scaled_imu3 message + * + * @return X acceleration (mg) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_xacc(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 4); +} + +/** + * @brief Get field yacc from scaled_imu3 message + * + * @return Y acceleration (mg) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_yacc(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 6); +} + +/** + * @brief Get field zacc from scaled_imu3 message + * + * @return Z acceleration (mg) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_zacc(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 8); +} + +/** + * @brief Get field xgyro from scaled_imu3 message + * + * @return Angular speed around X axis (millirad /sec) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_xgyro(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 10); +} + +/** + * @brief Get field ygyro from scaled_imu3 message + * + * @return Angular speed around Y axis (millirad /sec) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_ygyro(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 12); +} + +/** + * @brief Get field zgyro from scaled_imu3 message + * + * @return Angular speed around Z axis (millirad /sec) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_zgyro(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 14); +} + +/** + * @brief Get field xmag from scaled_imu3 message + * + * @return X Magnetic field (milli tesla) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_xmag(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 16); +} + +/** + * @brief Get field ymag from scaled_imu3 message + * + * @return Y Magnetic field (milli tesla) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_ymag(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 18); +} + +/** + * @brief Get field zmag from scaled_imu3 message + * + * @return Z Magnetic field (milli tesla) + */ +static inline int16_t mavlink_msg_scaled_imu3_get_zmag(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 20); +} + +/** + * @brief Decode a scaled_imu3 message into a struct + * + * @param msg The message to decode + * @param scaled_imu3 C-struct to decode the message contents into + */ +static inline void mavlink_msg_scaled_imu3_decode(const mavlink_message_t* msg, mavlink_scaled_imu3_t* scaled_imu3) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + scaled_imu3->time_boot_ms = mavlink_msg_scaled_imu3_get_time_boot_ms(msg); + scaled_imu3->xacc = mavlink_msg_scaled_imu3_get_xacc(msg); + scaled_imu3->yacc = mavlink_msg_scaled_imu3_get_yacc(msg); + scaled_imu3->zacc = mavlink_msg_scaled_imu3_get_zacc(msg); + scaled_imu3->xgyro = mavlink_msg_scaled_imu3_get_xgyro(msg); + scaled_imu3->ygyro = mavlink_msg_scaled_imu3_get_ygyro(msg); + scaled_imu3->zgyro = mavlink_msg_scaled_imu3_get_zgyro(msg); + scaled_imu3->xmag = mavlink_msg_scaled_imu3_get_xmag(msg); + scaled_imu3->ymag = mavlink_msg_scaled_imu3_get_ymag(msg); + scaled_imu3->zmag = mavlink_msg_scaled_imu3_get_zmag(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_SCALED_IMU3_LEN? msg->len : MAVLINK_MSG_ID_SCALED_IMU3_LEN; + memset(scaled_imu3, 0, MAVLINK_MSG_ID_SCALED_IMU3_LEN); + memcpy(scaled_imu3, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure.h b/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure.h index e0d6d87662..0dcfc9277d 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE SCALED_PRESSURE PACKING #define MAVLINK_MSG_ID_SCALED_PRESSURE 29 -typedef struct __mavlink_scaled_pressure_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float press_abs; ///< Absolute pressure (hectopascal) - float press_diff; ///< Differential pressure 1 (hectopascal) - int16_t temperature; ///< Temperature measurement (0.01 degrees celsius) -} mavlink_scaled_pressure_t; +MAVPACKED( +typedef struct __mavlink_scaled_pressure_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float press_abs; /*< Absolute pressure (hectopascal)*/ + float press_diff; /*< Differential pressure 1 (hectopascal)*/ + int16_t temperature; /*< Temperature measurement (0.01 degrees celsius)*/ +}) mavlink_scaled_pressure_t; #define MAVLINK_MSG_ID_SCALED_PRESSURE_LEN 14 +#define MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN 14 #define MAVLINK_MSG_ID_29_LEN 14 +#define MAVLINK_MSG_ID_29_MIN_LEN 14 #define MAVLINK_MSG_ID_SCALED_PRESSURE_CRC 115 #define MAVLINK_MSG_ID_29_CRC 115 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SCALED_PRESSURE { \ - "SCALED_PRESSURE", \ - 4, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure_t, time_boot_ms) }, \ + 29, \ + "SCALED_PRESSURE", \ + 4, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure_t, time_boot_ms) }, \ { "press_abs", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_scaled_pressure_t, press_abs) }, \ { "press_diff", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_scaled_pressure_t, press_diff) }, \ { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_pressure_t, temperature) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SCALED_PRESSURE { \ + "SCALED_PRESSURE", \ + 4, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure_t, time_boot_ms) }, \ + { "press_abs", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_scaled_pressure_t, press_abs) }, \ + { "press_diff", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_scaled_pressure_t, press_diff) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_pressure_t, temperature) }, \ + } \ +} +#endif /** * @brief Pack a scaled_pressure message @@ -42,32 +57,28 @@ typedef struct __mavlink_scaled_pressure_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_pressure_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) + uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_PRESSURE_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); #else - mavlink_scaled_pressure_t packet; - packet.time_boot_ms = time_boot_ms; - packet.press_abs = press_abs; - packet.press_diff = press_diff; - packet.temperature = temperature; + mavlink_scaled_pressure_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_scaled_pressure_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_pressure_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,float press_abs,float press_diff,int16_t temperature) + mavlink_message_t* msg, + uint32_t time_boot_ms,float press_abs,float press_diff,int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_PRESSURE_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); #else - mavlink_scaled_pressure_t packet; - packet.time_boot_ms = time_boot_ms; - packet.press_abs = press_abs; - packet.press_diff = press_diff; - packet.temperature = temperature; + mavlink_scaled_pressure_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_scaled_pressure_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_scaled_pressure_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_scaled_pressure_t* scaled_pressure) { - return mavlink_msg_scaled_pressure_pack(system_id, component_id, msg, scaled_pressure->time_boot_ms, scaled_pressure->press_abs, scaled_pressure->press_diff, scaled_pressure->temperature); + return mavlink_msg_scaled_pressure_pack(system_id, component_id, msg, scaled_pressure->time_boot_ms, scaled_pressure->press_abs, scaled_pressure->press_diff, scaled_pressure->temperature); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_scaled_pressure_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_scaled_pressure_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_pressure_t* scaled_pressure) { - return mavlink_msg_scaled_pressure_pack_chan(system_id, component_id, chan, msg, scaled_pressure->time_boot_ms, scaled_pressure->press_abs, scaled_pressure->press_diff, scaled_pressure->temperature); + return mavlink_msg_scaled_pressure_pack_chan(system_id, component_id, chan, msg, scaled_pressure->time_boot_ms, scaled_pressure->press_abs, scaled_pressure->press_diff, scaled_pressure->temperature); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_scaled_pressure_encode_chan(uint8_t system_id static inline void mavlink_msg_scaled_pressure_send(mavlink_channel_t chan, uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_PRESSURE_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, buf, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, buf, MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, buf, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); + mavlink_scaled_pressure_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, (const char *)&packet, MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); #endif +} + +/** + * @brief Send a scaled_pressure message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_scaled_pressure_send_struct(mavlink_channel_t chan, const mavlink_scaled_pressure_t* scaled_pressure) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_scaled_pressure_send(chan, scaled_pressure->time_boot_ms, scaled_pressure->press_abs, scaled_pressure->press_diff, scaled_pressure->temperature); #else - mavlink_scaled_pressure_t packet; - packet.time_boot_ms = time_boot_ms; - packet.press_abs = press_abs; - packet.press_diff = press_diff; - packet.temperature = temperature; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, (const char *)&packet, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, (const char *)&packet, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, (const char *)scaled_pressure, MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_scaled_pressure_send(mavlink_channel_t chan, uint static inline void mavlink_msg_scaled_pressure_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, buf, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, buf, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); -#endif -#else - mavlink_scaled_pressure_t *packet = (mavlink_scaled_pressure_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->press_abs = press_abs; - packet->press_diff = press_diff; - packet->temperature = temperature; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, (const char *)packet, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, buf, MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, (const char *)packet, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); -#endif + mavlink_scaled_pressure_t *packet = (mavlink_scaled_pressure_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->press_abs = press_abs; + packet->press_diff = press_diff; + packet->temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE, (const char *)packet, MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_scaled_pressure_send_buf(mavlink_message_t *msgbu */ static inline uint32_t mavlink_msg_scaled_pressure_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -239,7 +244,7 @@ static inline uint32_t mavlink_msg_scaled_pressure_get_time_boot_ms(const mavlin */ static inline float mavlink_msg_scaled_pressure_get_press_abs(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -249,7 +254,7 @@ static inline float mavlink_msg_scaled_pressure_get_press_abs(const mavlink_mess */ static inline float mavlink_msg_scaled_pressure_get_press_diff(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -259,7 +264,7 @@ static inline float mavlink_msg_scaled_pressure_get_press_diff(const mavlink_mes */ static inline int16_t mavlink_msg_scaled_pressure_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 12); + return _MAV_RETURN_int16_t(msg, 12); } /** @@ -270,12 +275,14 @@ static inline int16_t mavlink_msg_scaled_pressure_get_temperature(const mavlink_ */ static inline void mavlink_msg_scaled_pressure_decode(const mavlink_message_t* msg, mavlink_scaled_pressure_t* scaled_pressure) { -#if MAVLINK_NEED_BYTE_SWAP - scaled_pressure->time_boot_ms = mavlink_msg_scaled_pressure_get_time_boot_ms(msg); - scaled_pressure->press_abs = mavlink_msg_scaled_pressure_get_press_abs(msg); - scaled_pressure->press_diff = mavlink_msg_scaled_pressure_get_press_diff(msg); - scaled_pressure->temperature = mavlink_msg_scaled_pressure_get_temperature(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + scaled_pressure->time_boot_ms = mavlink_msg_scaled_pressure_get_time_boot_ms(msg); + scaled_pressure->press_abs = mavlink_msg_scaled_pressure_get_press_abs(msg); + scaled_pressure->press_diff = mavlink_msg_scaled_pressure_get_press_diff(msg); + scaled_pressure->temperature = mavlink_msg_scaled_pressure_get_temperature(msg); #else - memcpy(scaled_pressure, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SCALED_PRESSURE_LEN? msg->len : MAVLINK_MSG_ID_SCALED_PRESSURE_LEN; + memset(scaled_pressure, 0, MAVLINK_MSG_ID_SCALED_PRESSURE_LEN); + memcpy(scaled_pressure, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure2.h b/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure2.h index 674f505963..1e7920b040 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure2.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure2.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE SCALED_PRESSURE2 PACKING #define MAVLINK_MSG_ID_SCALED_PRESSURE2 137 -typedef struct __mavlink_scaled_pressure2_t -{ - uint32_t time_boot_ms; ///< Timestamp (milliseconds since system boot) - float press_abs; ///< Absolute pressure (hectopascal) - float press_diff; ///< Differential pressure 1 (hectopascal) - int16_t temperature; ///< Temperature measurement (0.01 degrees celsius) -} mavlink_scaled_pressure2_t; +MAVPACKED( +typedef struct __mavlink_scaled_pressure2_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float press_abs; /*< Absolute pressure (hectopascal)*/ + float press_diff; /*< Differential pressure 1 (hectopascal)*/ + int16_t temperature; /*< Temperature measurement (0.01 degrees celsius)*/ +}) mavlink_scaled_pressure2_t; #define MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN 14 +#define MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN 14 #define MAVLINK_MSG_ID_137_LEN 14 +#define MAVLINK_MSG_ID_137_MIN_LEN 14 #define MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC 195 #define MAVLINK_MSG_ID_137_CRC 195 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SCALED_PRESSURE2 { \ - "SCALED_PRESSURE2", \ - 4, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure2_t, time_boot_ms) }, \ + 137, \ + "SCALED_PRESSURE2", \ + 4, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure2_t, time_boot_ms) }, \ { "press_abs", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_scaled_pressure2_t, press_abs) }, \ { "press_diff", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_scaled_pressure2_t, press_diff) }, \ { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_pressure2_t, temperature) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SCALED_PRESSURE2 { \ + "SCALED_PRESSURE2", \ + 4, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure2_t, time_boot_ms) }, \ + { "press_abs", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_scaled_pressure2_t, press_abs) }, \ + { "press_diff", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_scaled_pressure2_t, press_diff) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_pressure2_t, temperature) }, \ + } \ +} +#endif /** * @brief Pack a scaled_pressure2 message @@ -42,32 +57,28 @@ typedef struct __mavlink_scaled_pressure2_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_pressure2_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) + uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); #else - mavlink_scaled_pressure2_t packet; - packet.time_boot_ms = time_boot_ms; - packet.press_abs = press_abs; - packet.press_diff = press_diff; - packet.temperature = temperature; + mavlink_scaled_pressure2_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE2; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_scaled_pressure2_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_scaled_pressure2_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,float press_abs,float press_diff,int16_t temperature) + mavlink_message_t* msg, + uint32_t time_boot_ms,float press_abs,float press_diff,int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); #else - mavlink_scaled_pressure2_t packet; - packet.time_boot_ms = time_boot_ms; - packet.press_abs = press_abs; - packet.press_diff = press_diff; - packet.temperature = temperature; + mavlink_scaled_pressure2_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE2; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE2; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_scaled_pressure2_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_scaled_pressure2_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_scaled_pressure2_t* scaled_pressure2) { - return mavlink_msg_scaled_pressure2_pack(system_id, component_id, msg, scaled_pressure2->time_boot_ms, scaled_pressure2->press_abs, scaled_pressure2->press_diff, scaled_pressure2->temperature); + return mavlink_msg_scaled_pressure2_pack(system_id, component_id, msg, scaled_pressure2->time_boot_ms, scaled_pressure2->press_abs, scaled_pressure2->press_diff, scaled_pressure2->temperature); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_scaled_pressure2_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_scaled_pressure2_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_pressure2_t* scaled_pressure2) { - return mavlink_msg_scaled_pressure2_pack_chan(system_id, component_id, chan, msg, scaled_pressure2->time_boot_ms, scaled_pressure2->press_abs, scaled_pressure2->press_diff, scaled_pressure2->temperature); + return mavlink_msg_scaled_pressure2_pack_chan(system_id, component_id, chan, msg, scaled_pressure2->time_boot_ms, scaled_pressure2->press_abs, scaled_pressure2->press_diff, scaled_pressure2->temperature); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_scaled_pressure2_encode_chan(uint8_t system_i static inline void mavlink_msg_scaled_pressure2_send(mavlink_channel_t chan, uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); + mavlink_scaled_pressure2_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, (const char *)&packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); #endif +} + +/** + * @brief Send a scaled_pressure2 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_scaled_pressure2_send_struct(mavlink_channel_t chan, const mavlink_scaled_pressure2_t* scaled_pressure2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_scaled_pressure2_send(chan, scaled_pressure2->time_boot_ms, scaled_pressure2->press_abs, scaled_pressure2->press_diff, scaled_pressure2->temperature); #else - mavlink_scaled_pressure2_t packet; - packet.time_boot_ms = time_boot_ms; - packet.press_abs = press_abs; - packet.press_diff = press_diff; - packet.temperature = temperature; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, (const char *)&packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, (const char *)&packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, (const char *)scaled_pressure2, MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_scaled_pressure2_send(mavlink_channel_t chan, uin static inline void mavlink_msg_scaled_pressure2_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, press_abs); - _mav_put_float(buf, 8, press_diff); - _mav_put_int16_t(buf, 12, temperature); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); -#endif -#else - mavlink_scaled_pressure2_t *packet = (mavlink_scaled_pressure2_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->press_abs = press_abs; - packet->press_diff = press_diff; - packet->temperature = temperature; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, (const char *)packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, buf, MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, (const char *)packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); -#endif + mavlink_scaled_pressure2_t *packet = (mavlink_scaled_pressure2_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->press_abs = press_abs; + packet->press_diff = press_diff; + packet->temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE2, (const char *)packet, MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE2_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_scaled_pressure2_send_buf(mavlink_message_t *msgb */ static inline uint32_t mavlink_msg_scaled_pressure2_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -239,7 +244,7 @@ static inline uint32_t mavlink_msg_scaled_pressure2_get_time_boot_ms(const mavli */ static inline float mavlink_msg_scaled_pressure2_get_press_abs(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -249,7 +254,7 @@ static inline float mavlink_msg_scaled_pressure2_get_press_abs(const mavlink_mes */ static inline float mavlink_msg_scaled_pressure2_get_press_diff(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -259,7 +264,7 @@ static inline float mavlink_msg_scaled_pressure2_get_press_diff(const mavlink_me */ static inline int16_t mavlink_msg_scaled_pressure2_get_temperature(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 12); + return _MAV_RETURN_int16_t(msg, 12); } /** @@ -270,12 +275,14 @@ static inline int16_t mavlink_msg_scaled_pressure2_get_temperature(const mavlink */ static inline void mavlink_msg_scaled_pressure2_decode(const mavlink_message_t* msg, mavlink_scaled_pressure2_t* scaled_pressure2) { -#if MAVLINK_NEED_BYTE_SWAP - scaled_pressure2->time_boot_ms = mavlink_msg_scaled_pressure2_get_time_boot_ms(msg); - scaled_pressure2->press_abs = mavlink_msg_scaled_pressure2_get_press_abs(msg); - scaled_pressure2->press_diff = mavlink_msg_scaled_pressure2_get_press_diff(msg); - scaled_pressure2->temperature = mavlink_msg_scaled_pressure2_get_temperature(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + scaled_pressure2->time_boot_ms = mavlink_msg_scaled_pressure2_get_time_boot_ms(msg); + scaled_pressure2->press_abs = mavlink_msg_scaled_pressure2_get_press_abs(msg); + scaled_pressure2->press_diff = mavlink_msg_scaled_pressure2_get_press_diff(msg); + scaled_pressure2->temperature = mavlink_msg_scaled_pressure2_get_temperature(msg); #else - memcpy(scaled_pressure2, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN? msg->len : MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN; + memset(scaled_pressure2, 0, MAVLINK_MSG_ID_SCALED_PRESSURE2_LEN); + memcpy(scaled_pressure2, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure3.h b/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure3.h new file mode 100644 index 0000000000..a0b6586e90 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_scaled_pressure3.h @@ -0,0 +1,288 @@ +#pragma once +// MESSAGE SCALED_PRESSURE3 PACKING + +#define MAVLINK_MSG_ID_SCALED_PRESSURE3 143 + +MAVPACKED( +typedef struct __mavlink_scaled_pressure3_t { + uint32_t time_boot_ms; /*< Timestamp (milliseconds since system boot)*/ + float press_abs; /*< Absolute pressure (hectopascal)*/ + float press_diff; /*< Differential pressure 1 (hectopascal)*/ + int16_t temperature; /*< Temperature measurement (0.01 degrees celsius)*/ +}) mavlink_scaled_pressure3_t; + +#define MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN 14 +#define MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN 14 +#define MAVLINK_MSG_ID_143_LEN 14 +#define MAVLINK_MSG_ID_143_MIN_LEN 14 + +#define MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC 131 +#define MAVLINK_MSG_ID_143_CRC 131 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_SCALED_PRESSURE3 { \ + 143, \ + "SCALED_PRESSURE3", \ + 4, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure3_t, time_boot_ms) }, \ + { "press_abs", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_scaled_pressure3_t, press_abs) }, \ + { "press_diff", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_scaled_pressure3_t, press_diff) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_pressure3_t, temperature) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_SCALED_PRESSURE3 { \ + "SCALED_PRESSURE3", \ + 4, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_scaled_pressure3_t, time_boot_ms) }, \ + { "press_abs", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_scaled_pressure3_t, press_abs) }, \ + { "press_diff", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_scaled_pressure3_t, press_diff) }, \ + { "temperature", NULL, MAVLINK_TYPE_INT16_T, 0, 12, offsetof(mavlink_scaled_pressure3_t, temperature) }, \ + } \ +} +#endif + +/** + * @brief Pack a scaled_pressure3 message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param press_abs Absolute pressure (hectopascal) + * @param press_diff Differential pressure 1 (hectopascal) + * @param temperature Temperature measurement (0.01 degrees celsius) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_scaled_pressure3_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN); +#else + mavlink_scaled_pressure3_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE3; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC); +} + +/** + * @brief Pack a scaled_pressure3 message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param press_abs Absolute pressure (hectopascal) + * @param press_diff Differential pressure 1 (hectopascal) + * @param temperature Temperature measurement (0.01 degrees celsius) + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_scaled_pressure3_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint32_t time_boot_ms,float press_abs,float press_diff,int16_t temperature) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN); +#else + mavlink_scaled_pressure3_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_SCALED_PRESSURE3; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC); +} + +/** + * @brief Encode a scaled_pressure3 struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param scaled_pressure3 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_scaled_pressure3_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_scaled_pressure3_t* scaled_pressure3) +{ + return mavlink_msg_scaled_pressure3_pack(system_id, component_id, msg, scaled_pressure3->time_boot_ms, scaled_pressure3->press_abs, scaled_pressure3->press_diff, scaled_pressure3->temperature); +} + +/** + * @brief Encode a scaled_pressure3 struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param scaled_pressure3 C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_scaled_pressure3_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_scaled_pressure3_t* scaled_pressure3) +{ + return mavlink_msg_scaled_pressure3_pack_chan(system_id, component_id, chan, msg, scaled_pressure3->time_boot_ms, scaled_pressure3->press_abs, scaled_pressure3->press_diff, scaled_pressure3->temperature); +} + +/** + * @brief Send a scaled_pressure3 message + * @param chan MAVLink channel to send the message + * + * @param time_boot_ms Timestamp (milliseconds since system boot) + * @param press_abs Absolute pressure (hectopascal) + * @param press_diff Differential pressure 1 (hectopascal) + * @param temperature Temperature measurement (0.01 degrees celsius) + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_scaled_pressure3_send(mavlink_channel_t chan, uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE3, buf, MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC); +#else + mavlink_scaled_pressure3_t packet; + packet.time_boot_ms = time_boot_ms; + packet.press_abs = press_abs; + packet.press_diff = press_diff; + packet.temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE3, (const char *)&packet, MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC); +#endif +} + +/** + * @brief Send a scaled_pressure3 message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_scaled_pressure3_send_struct(mavlink_channel_t chan, const mavlink_scaled_pressure3_t* scaled_pressure3) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_scaled_pressure3_send(chan, scaled_pressure3->time_boot_ms, scaled_pressure3->press_abs, scaled_pressure3->press_diff, scaled_pressure3->temperature); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE3, (const char *)scaled_pressure3, MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC); +#endif +} + +#if MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_scaled_pressure3_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, float press_abs, float press_diff, int16_t temperature) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, press_abs); + _mav_put_float(buf, 8, press_diff); + _mav_put_int16_t(buf, 12, temperature); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE3, buf, MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC); +#else + mavlink_scaled_pressure3_t *packet = (mavlink_scaled_pressure3_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->press_abs = press_abs; + packet->press_diff = press_diff; + packet->temperature = temperature; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SCALED_PRESSURE3, (const char *)packet, MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN, MAVLINK_MSG_ID_SCALED_PRESSURE3_CRC); +#endif +} +#endif + +#endif + +// MESSAGE SCALED_PRESSURE3 UNPACKING + + +/** + * @brief Get field time_boot_ms from scaled_pressure3 message + * + * @return Timestamp (milliseconds since system boot) + */ +static inline uint32_t mavlink_msg_scaled_pressure3_get_time_boot_ms(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 0); +} + +/** + * @brief Get field press_abs from scaled_pressure3 message + * + * @return Absolute pressure (hectopascal) + */ +static inline float mavlink_msg_scaled_pressure3_get_press_abs(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 4); +} + +/** + * @brief Get field press_diff from scaled_pressure3 message + * + * @return Differential pressure 1 (hectopascal) + */ +static inline float mavlink_msg_scaled_pressure3_get_press_diff(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field temperature from scaled_pressure3 message + * + * @return Temperature measurement (0.01 degrees celsius) + */ +static inline int16_t mavlink_msg_scaled_pressure3_get_temperature(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int16_t(msg, 12); +} + +/** + * @brief Decode a scaled_pressure3 message into a struct + * + * @param msg The message to decode + * @param scaled_pressure3 C-struct to decode the message contents into + */ +static inline void mavlink_msg_scaled_pressure3_decode(const mavlink_message_t* msg, mavlink_scaled_pressure3_t* scaled_pressure3) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + scaled_pressure3->time_boot_ms = mavlink_msg_scaled_pressure3_get_time_boot_ms(msg); + scaled_pressure3->press_abs = mavlink_msg_scaled_pressure3_get_press_abs(msg); + scaled_pressure3->press_diff = mavlink_msg_scaled_pressure3_get_press_diff(msg); + scaled_pressure3->temperature = mavlink_msg_scaled_pressure3_get_temperature(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN? msg->len : MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN; + memset(scaled_pressure3, 0, MAVLINK_MSG_ID_SCALED_PRESSURE3_LEN); + memcpy(scaled_pressure3, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_serial_control.h b/vendor/libraries/mavlink/common/mavlink_msg_serial_control.h index cbf72bae31..ce9581185a 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_serial_control.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_serial_control.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE SERIAL_CONTROL PACKING #define MAVLINK_MSG_ID_SERIAL_CONTROL 126 -typedef struct __mavlink_serial_control_t -{ - uint32_t baudrate; ///< Baudrate of transfer. Zero means no change. - uint16_t timeout; ///< Timeout for reply data in milliseconds - uint8_t device; ///< See SERIAL_CONTROL_DEV enum - uint8_t flags; ///< See SERIAL_CONTROL_FLAG enum - uint8_t count; ///< how many bytes in this transfer - uint8_t data[70]; ///< serial data -} mavlink_serial_control_t; +MAVPACKED( +typedef struct __mavlink_serial_control_t { + uint32_t baudrate; /*< Baudrate of transfer. Zero means no change.*/ + uint16_t timeout; /*< Timeout for reply data in milliseconds*/ + uint8_t device; /*< See SERIAL_CONTROL_DEV enum*/ + uint8_t flags; /*< See SERIAL_CONTROL_FLAG enum*/ + uint8_t count; /*< how many bytes in this transfer*/ + uint8_t data[70]; /*< serial data*/ +}) mavlink_serial_control_t; #define MAVLINK_MSG_ID_SERIAL_CONTROL_LEN 79 +#define MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN 79 #define MAVLINK_MSG_ID_126_LEN 79 +#define MAVLINK_MSG_ID_126_MIN_LEN 79 #define MAVLINK_MSG_ID_SERIAL_CONTROL_CRC 220 #define MAVLINK_MSG_ID_126_CRC 220 #define MAVLINK_MSG_SERIAL_CONTROL_FIELD_DATA_LEN 70 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SERIAL_CONTROL { \ - "SERIAL_CONTROL", \ - 6, \ - { { "baudrate", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_serial_control_t, baudrate) }, \ + 126, \ + "SERIAL_CONTROL", \ + 6, \ + { { "baudrate", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_serial_control_t, baudrate) }, \ { "timeout", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_serial_control_t, timeout) }, \ { "device", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_serial_control_t, device) }, \ { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_serial_control_t, flags) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_serial_control_t { "data", NULL, MAVLINK_TYPE_UINT8_T, 70, 9, offsetof(mavlink_serial_control_t, data) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SERIAL_CONTROL { \ + "SERIAL_CONTROL", \ + 6, \ + { { "baudrate", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_serial_control_t, baudrate) }, \ + { "timeout", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_serial_control_t, timeout) }, \ + { "device", NULL, MAVLINK_TYPE_UINT8_T, 0, 6, offsetof(mavlink_serial_control_t, device) }, \ + { "flags", NULL, MAVLINK_TYPE_UINT8_T, 0, 7, offsetof(mavlink_serial_control_t, flags) }, \ + { "count", NULL, MAVLINK_TYPE_UINT8_T, 0, 8, offsetof(mavlink_serial_control_t, count) }, \ + { "data", NULL, MAVLINK_TYPE_UINT8_T, 70, 9, offsetof(mavlink_serial_control_t, data) }, \ + } \ +} +#endif /** * @brief Pack a serial_control message @@ -48,34 +65,30 @@ typedef struct __mavlink_serial_control_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_serial_control_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t device, uint8_t flags, uint16_t timeout, uint32_t baudrate, uint8_t count, const uint8_t *data) + uint8_t device, uint8_t flags, uint16_t timeout, uint32_t baudrate, uint8_t count, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SERIAL_CONTROL_LEN]; - _mav_put_uint32_t(buf, 0, baudrate); - _mav_put_uint16_t(buf, 4, timeout); - _mav_put_uint8_t(buf, 6, device); - _mav_put_uint8_t(buf, 7, flags); - _mav_put_uint8_t(buf, 8, count); - _mav_put_uint8_t_array(buf, 9, data, 70); + char buf[MAVLINK_MSG_ID_SERIAL_CONTROL_LEN]; + _mav_put_uint32_t(buf, 0, baudrate); + _mav_put_uint16_t(buf, 4, timeout); + _mav_put_uint8_t(buf, 6, device); + _mav_put_uint8_t(buf, 7, flags); + _mav_put_uint8_t(buf, 8, count); + _mav_put_uint8_t_array(buf, 9, data, 70); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); #else - mavlink_serial_control_t packet; - packet.baudrate = baudrate; - packet.timeout = timeout; - packet.device = device; - packet.flags = flags; - packet.count = count; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*70); + mavlink_serial_control_t packet; + packet.baudrate = baudrate; + packet.timeout = timeout; + packet.device = device; + packet.flags = flags; + packet.count = count; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*70); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SERIAL_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SERIAL_CONTROL; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); } /** @@ -93,35 +106,31 @@ static inline uint16_t mavlink_msg_serial_control_pack(uint8_t system_id, uint8_ * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_serial_control_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t device,uint8_t flags,uint16_t timeout,uint32_t baudrate,uint8_t count,const uint8_t *data) + mavlink_message_t* msg, + uint8_t device,uint8_t flags,uint16_t timeout,uint32_t baudrate,uint8_t count,const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SERIAL_CONTROL_LEN]; - _mav_put_uint32_t(buf, 0, baudrate); - _mav_put_uint16_t(buf, 4, timeout); - _mav_put_uint8_t(buf, 6, device); - _mav_put_uint8_t(buf, 7, flags); - _mav_put_uint8_t(buf, 8, count); - _mav_put_uint8_t_array(buf, 9, data, 70); + char buf[MAVLINK_MSG_ID_SERIAL_CONTROL_LEN]; + _mav_put_uint32_t(buf, 0, baudrate); + _mav_put_uint16_t(buf, 4, timeout); + _mav_put_uint8_t(buf, 6, device); + _mav_put_uint8_t(buf, 7, flags); + _mav_put_uint8_t(buf, 8, count); + _mav_put_uint8_t_array(buf, 9, data, 70); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); #else - mavlink_serial_control_t packet; - packet.baudrate = baudrate; - packet.timeout = timeout; - packet.device = device; - packet.flags = flags; - packet.count = count; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*70); + mavlink_serial_control_t packet; + packet.baudrate = baudrate; + packet.timeout = timeout; + packet.device = device; + packet.flags = flags; + packet.count = count; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*70); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SERIAL_CONTROL; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SERIAL_CONTROL; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); } /** @@ -134,7 +143,7 @@ static inline uint16_t mavlink_msg_serial_control_pack_chan(uint8_t system_id, u */ static inline uint16_t mavlink_msg_serial_control_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_serial_control_t* serial_control) { - return mavlink_msg_serial_control_pack(system_id, component_id, msg, serial_control->device, serial_control->flags, serial_control->timeout, serial_control->baudrate, serial_control->count, serial_control->data); + return mavlink_msg_serial_control_pack(system_id, component_id, msg, serial_control->device, serial_control->flags, serial_control->timeout, serial_control->baudrate, serial_control->count, serial_control->data); } /** @@ -148,7 +157,7 @@ static inline uint16_t mavlink_msg_serial_control_encode(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_serial_control_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_serial_control_t* serial_control) { - return mavlink_msg_serial_control_pack_chan(system_id, component_id, chan, msg, serial_control->device, serial_control->flags, serial_control->timeout, serial_control->baudrate, serial_control->count, serial_control->data); + return mavlink_msg_serial_control_pack_chan(system_id, component_id, chan, msg, serial_control->device, serial_control->flags, serial_control->timeout, serial_control->baudrate, serial_control->count, serial_control->data); } /** @@ -167,31 +176,37 @@ static inline uint16_t mavlink_msg_serial_control_encode_chan(uint8_t system_id, static inline void mavlink_msg_serial_control_send(mavlink_channel_t chan, uint8_t device, uint8_t flags, uint16_t timeout, uint32_t baudrate, uint8_t count, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SERIAL_CONTROL_LEN]; - _mav_put_uint32_t(buf, 0, baudrate); - _mav_put_uint16_t(buf, 4, timeout); - _mav_put_uint8_t(buf, 6, device); - _mav_put_uint8_t(buf, 7, flags); - _mav_put_uint8_t(buf, 8, count); - _mav_put_uint8_t_array(buf, 9, data, 70); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, buf, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); + char buf[MAVLINK_MSG_ID_SERIAL_CONTROL_LEN]; + _mav_put_uint32_t(buf, 0, baudrate); + _mav_put_uint16_t(buf, 4, timeout); + _mav_put_uint8_t(buf, 6, device); + _mav_put_uint8_t(buf, 7, flags); + _mav_put_uint8_t(buf, 8, count); + _mav_put_uint8_t_array(buf, 9, data, 70); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, buf, MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, buf, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); + mavlink_serial_control_t packet; + packet.baudrate = baudrate; + packet.timeout = timeout; + packet.device = device; + packet.flags = flags; + packet.count = count; + mav_array_memcpy(packet.data, data, sizeof(uint8_t)*70); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); #endif +} + +/** + * @brief Send a serial_control message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_serial_control_send_struct(mavlink_channel_t chan, const mavlink_serial_control_t* serial_control) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_serial_control_send(chan, serial_control->device, serial_control->flags, serial_control->timeout, serial_control->baudrate, serial_control->count, serial_control->data); #else - mavlink_serial_control_t packet; - packet.baudrate = baudrate; - packet.timeout = timeout; - packet.device = device; - packet.flags = flags; - packet.count = count; - mav_array_memcpy(packet.data, data, sizeof(uint8_t)*70); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, (const char *)&packet, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, (const char *)serial_control, MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); #endif } @@ -206,31 +221,23 @@ static inline void mavlink_msg_serial_control_send(mavlink_channel_t chan, uint8 static inline void mavlink_msg_serial_control_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t device, uint8_t flags, uint16_t timeout, uint32_t baudrate, uint8_t count, const uint8_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, baudrate); - _mav_put_uint16_t(buf, 4, timeout); - _mav_put_uint8_t(buf, 6, device); - _mav_put_uint8_t(buf, 7, flags); - _mav_put_uint8_t(buf, 8, count); - _mav_put_uint8_t_array(buf, 9, data, 70); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, buf, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, baudrate); + _mav_put_uint16_t(buf, 4, timeout); + _mav_put_uint8_t(buf, 6, device); + _mav_put_uint8_t(buf, 7, flags); + _mav_put_uint8_t(buf, 8, count); + _mav_put_uint8_t_array(buf, 9, data, 70); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, buf, MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, buf, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); -#endif -#else - mavlink_serial_control_t *packet = (mavlink_serial_control_t *)msgbuf; - packet->baudrate = baudrate; - packet->timeout = timeout; - packet->device = device; - packet->flags = flags; - packet->count = count; - mav_array_memcpy(packet->data, data, sizeof(uint8_t)*70); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); -#endif + mavlink_serial_control_t *packet = (mavlink_serial_control_t *)msgbuf; + packet->baudrate = baudrate; + packet->timeout = timeout; + packet->device = device; + packet->flags = flags; + packet->count = count; + mav_array_memcpy(packet->data, data, sizeof(uint8_t)*70); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERIAL_CONTROL, (const char *)packet, MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN, MAVLINK_MSG_ID_SERIAL_CONTROL_CRC); #endif } #endif @@ -247,7 +254,7 @@ static inline void mavlink_msg_serial_control_send_buf(mavlink_message_t *msgbuf */ static inline uint8_t mavlink_msg_serial_control_get_device(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 6); + return _MAV_RETURN_uint8_t(msg, 6); } /** @@ -257,7 +264,7 @@ static inline uint8_t mavlink_msg_serial_control_get_device(const mavlink_messag */ static inline uint8_t mavlink_msg_serial_control_get_flags(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 7); + return _MAV_RETURN_uint8_t(msg, 7); } /** @@ -267,7 +274,7 @@ static inline uint8_t mavlink_msg_serial_control_get_flags(const mavlink_message */ static inline uint16_t mavlink_msg_serial_control_get_timeout(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -277,7 +284,7 @@ static inline uint16_t mavlink_msg_serial_control_get_timeout(const mavlink_mess */ static inline uint32_t mavlink_msg_serial_control_get_baudrate(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -287,7 +294,7 @@ static inline uint32_t mavlink_msg_serial_control_get_baudrate(const mavlink_mes */ static inline uint8_t mavlink_msg_serial_control_get_count(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 8); + return _MAV_RETURN_uint8_t(msg, 8); } /** @@ -297,7 +304,7 @@ static inline uint8_t mavlink_msg_serial_control_get_count(const mavlink_message */ static inline uint16_t mavlink_msg_serial_control_get_data(const mavlink_message_t* msg, uint8_t *data) { - return _MAV_RETURN_uint8_t_array(msg, data, 70, 9); + return _MAV_RETURN_uint8_t_array(msg, data, 70, 9); } /** @@ -308,14 +315,16 @@ static inline uint16_t mavlink_msg_serial_control_get_data(const mavlink_message */ static inline void mavlink_msg_serial_control_decode(const mavlink_message_t* msg, mavlink_serial_control_t* serial_control) { -#if MAVLINK_NEED_BYTE_SWAP - serial_control->baudrate = mavlink_msg_serial_control_get_baudrate(msg); - serial_control->timeout = mavlink_msg_serial_control_get_timeout(msg); - serial_control->device = mavlink_msg_serial_control_get_device(msg); - serial_control->flags = mavlink_msg_serial_control_get_flags(msg); - serial_control->count = mavlink_msg_serial_control_get_count(msg); - mavlink_msg_serial_control_get_data(msg, serial_control->data); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + serial_control->baudrate = mavlink_msg_serial_control_get_baudrate(msg); + serial_control->timeout = mavlink_msg_serial_control_get_timeout(msg); + serial_control->device = mavlink_msg_serial_control_get_device(msg); + serial_control->flags = mavlink_msg_serial_control_get_flags(msg); + serial_control->count = mavlink_msg_serial_control_get_count(msg); + mavlink_msg_serial_control_get_data(msg, serial_control->data); #else - memcpy(serial_control, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SERIAL_CONTROL_LEN? msg->len : MAVLINK_MSG_ID_SERIAL_CONTROL_LEN; + memset(serial_control, 0, MAVLINK_MSG_ID_SERIAL_CONTROL_LEN); + memcpy(serial_control, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_servo_output_raw.h b/vendor/libraries/mavlink/common/mavlink_msg_servo_output_raw.h index e8408862ff..0bf3936cdc 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_servo_output_raw.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_servo_output_raw.h @@ -1,33 +1,38 @@ +#pragma once // MESSAGE SERVO_OUTPUT_RAW PACKING #define MAVLINK_MSG_ID_SERVO_OUTPUT_RAW 36 -typedef struct __mavlink_servo_output_raw_t -{ - uint32_t time_usec; ///< Timestamp (microseconds since system boot) - uint16_t servo1_raw; ///< Servo output 1 value, in microseconds - uint16_t servo2_raw; ///< Servo output 2 value, in microseconds - uint16_t servo3_raw; ///< Servo output 3 value, in microseconds - uint16_t servo4_raw; ///< Servo output 4 value, in microseconds - uint16_t servo5_raw; ///< Servo output 5 value, in microseconds - uint16_t servo6_raw; ///< Servo output 6 value, in microseconds - uint16_t servo7_raw; ///< Servo output 7 value, in microseconds - uint16_t servo8_raw; ///< Servo output 8 value, in microseconds - uint8_t port; ///< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows to encode more than 8 servos. -} mavlink_servo_output_raw_t; +MAVPACKED( +typedef struct __mavlink_servo_output_raw_t { + uint32_t time_usec; /*< Timestamp (microseconds since system boot)*/ + uint16_t servo1_raw; /*< Servo output 1 value, in microseconds*/ + uint16_t servo2_raw; /*< Servo output 2 value, in microseconds*/ + uint16_t servo3_raw; /*< Servo output 3 value, in microseconds*/ + uint16_t servo4_raw; /*< Servo output 4 value, in microseconds*/ + uint16_t servo5_raw; /*< Servo output 5 value, in microseconds*/ + uint16_t servo6_raw; /*< Servo output 6 value, in microseconds*/ + uint16_t servo7_raw; /*< Servo output 7 value, in microseconds*/ + uint16_t servo8_raw; /*< Servo output 8 value, in microseconds*/ + uint8_t port; /*< Servo output port (set of 8 outputs = 1 port). Most MAVs will just use one, but this allows to encode more than 8 servos.*/ +}) mavlink_servo_output_raw_t; #define MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN 21 +#define MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN 21 #define MAVLINK_MSG_ID_36_LEN 21 +#define MAVLINK_MSG_ID_36_MIN_LEN 21 #define MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC 222 #define MAVLINK_MSG_ID_36_CRC 222 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW { \ - "SERVO_OUTPUT_RAW", \ - 10, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_servo_output_raw_t, time_usec) }, \ + 36, \ + "SERVO_OUTPUT_RAW", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_servo_output_raw_t, time_usec) }, \ { "servo1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_servo_output_raw_t, servo1_raw) }, \ { "servo2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_servo_output_raw_t, servo2_raw) }, \ { "servo3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_servo_output_raw_t, servo3_raw) }, \ @@ -39,7 +44,23 @@ typedef struct __mavlink_servo_output_raw_t { "port", NULL, MAVLINK_TYPE_UINT8_T, 0, 20, offsetof(mavlink_servo_output_raw_t, port) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SERVO_OUTPUT_RAW { \ + "SERVO_OUTPUT_RAW", \ + 10, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_servo_output_raw_t, time_usec) }, \ + { "servo1_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 4, offsetof(mavlink_servo_output_raw_t, servo1_raw) }, \ + { "servo2_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 6, offsetof(mavlink_servo_output_raw_t, servo2_raw) }, \ + { "servo3_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_servo_output_raw_t, servo3_raw) }, \ + { "servo4_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 10, offsetof(mavlink_servo_output_raw_t, servo4_raw) }, \ + { "servo5_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_servo_output_raw_t, servo5_raw) }, \ + { "servo6_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 14, offsetof(mavlink_servo_output_raw_t, servo6_raw) }, \ + { "servo7_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_servo_output_raw_t, servo7_raw) }, \ + { "servo8_raw", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_servo_output_raw_t, servo8_raw) }, \ + { "port", NULL, MAVLINK_TYPE_UINT8_T, 0, 20, offsetof(mavlink_servo_output_raw_t, port) }, \ + } \ +} +#endif /** * @brief Pack a servo_output_raw message @@ -60,44 +81,40 @@ typedef struct __mavlink_servo_output_raw_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_servo_output_raw_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_usec, uint8_t port, uint16_t servo1_raw, uint16_t servo2_raw, uint16_t servo3_raw, uint16_t servo4_raw, uint16_t servo5_raw, uint16_t servo6_raw, uint16_t servo7_raw, uint16_t servo8_raw) + uint32_t time_usec, uint8_t port, uint16_t servo1_raw, uint16_t servo2_raw, uint16_t servo3_raw, uint16_t servo4_raw, uint16_t servo5_raw, uint16_t servo6_raw, uint16_t servo7_raw, uint16_t servo8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN]; - _mav_put_uint32_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 4, servo1_raw); - _mav_put_uint16_t(buf, 6, servo2_raw); - _mav_put_uint16_t(buf, 8, servo3_raw); - _mav_put_uint16_t(buf, 10, servo4_raw); - _mav_put_uint16_t(buf, 12, servo5_raw); - _mav_put_uint16_t(buf, 14, servo6_raw); - _mav_put_uint16_t(buf, 16, servo7_raw); - _mav_put_uint16_t(buf, 18, servo8_raw); - _mav_put_uint8_t(buf, 20, port); + char buf[MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN]; + _mav_put_uint32_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 4, servo1_raw); + _mav_put_uint16_t(buf, 6, servo2_raw); + _mav_put_uint16_t(buf, 8, servo3_raw); + _mav_put_uint16_t(buf, 10, servo4_raw); + _mav_put_uint16_t(buf, 12, servo5_raw); + _mav_put_uint16_t(buf, 14, servo6_raw); + _mav_put_uint16_t(buf, 16, servo7_raw); + _mav_put_uint16_t(buf, 18, servo8_raw); + _mav_put_uint8_t(buf, 20, port); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); #else - mavlink_servo_output_raw_t packet; - packet.time_usec = time_usec; - packet.servo1_raw = servo1_raw; - packet.servo2_raw = servo2_raw; - packet.servo3_raw = servo3_raw; - packet.servo4_raw = servo4_raw; - packet.servo5_raw = servo5_raw; - packet.servo6_raw = servo6_raw; - packet.servo7_raw = servo7_raw; - packet.servo8_raw = servo8_raw; - packet.port = port; + mavlink_servo_output_raw_t packet; + packet.time_usec = time_usec; + packet.servo1_raw = servo1_raw; + packet.servo2_raw = servo2_raw; + packet.servo3_raw = servo3_raw; + packet.servo4_raw = servo4_raw; + packet.servo5_raw = servo5_raw; + packet.servo6_raw = servo6_raw; + packet.servo7_raw = servo7_raw; + packet.servo8_raw = servo8_raw; + packet.port = port; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SERVO_OUTPUT_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SERVO_OUTPUT_RAW; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); } /** @@ -119,45 +136,41 @@ static inline uint16_t mavlink_msg_servo_output_raw_pack(uint8_t system_id, uint * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_servo_output_raw_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_usec,uint8_t port,uint16_t servo1_raw,uint16_t servo2_raw,uint16_t servo3_raw,uint16_t servo4_raw,uint16_t servo5_raw,uint16_t servo6_raw,uint16_t servo7_raw,uint16_t servo8_raw) + mavlink_message_t* msg, + uint32_t time_usec,uint8_t port,uint16_t servo1_raw,uint16_t servo2_raw,uint16_t servo3_raw,uint16_t servo4_raw,uint16_t servo5_raw,uint16_t servo6_raw,uint16_t servo7_raw,uint16_t servo8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN]; - _mav_put_uint32_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 4, servo1_raw); - _mav_put_uint16_t(buf, 6, servo2_raw); - _mav_put_uint16_t(buf, 8, servo3_raw); - _mav_put_uint16_t(buf, 10, servo4_raw); - _mav_put_uint16_t(buf, 12, servo5_raw); - _mav_put_uint16_t(buf, 14, servo6_raw); - _mav_put_uint16_t(buf, 16, servo7_raw); - _mav_put_uint16_t(buf, 18, servo8_raw); - _mav_put_uint8_t(buf, 20, port); + char buf[MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN]; + _mav_put_uint32_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 4, servo1_raw); + _mav_put_uint16_t(buf, 6, servo2_raw); + _mav_put_uint16_t(buf, 8, servo3_raw); + _mav_put_uint16_t(buf, 10, servo4_raw); + _mav_put_uint16_t(buf, 12, servo5_raw); + _mav_put_uint16_t(buf, 14, servo6_raw); + _mav_put_uint16_t(buf, 16, servo7_raw); + _mav_put_uint16_t(buf, 18, servo8_raw); + _mav_put_uint8_t(buf, 20, port); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); #else - mavlink_servo_output_raw_t packet; - packet.time_usec = time_usec; - packet.servo1_raw = servo1_raw; - packet.servo2_raw = servo2_raw; - packet.servo3_raw = servo3_raw; - packet.servo4_raw = servo4_raw; - packet.servo5_raw = servo5_raw; - packet.servo6_raw = servo6_raw; - packet.servo7_raw = servo7_raw; - packet.servo8_raw = servo8_raw; - packet.port = port; + mavlink_servo_output_raw_t packet; + packet.time_usec = time_usec; + packet.servo1_raw = servo1_raw; + packet.servo2_raw = servo2_raw; + packet.servo3_raw = servo3_raw; + packet.servo4_raw = servo4_raw; + packet.servo5_raw = servo5_raw; + packet.servo6_raw = servo6_raw; + packet.servo7_raw = servo7_raw; + packet.servo8_raw = servo8_raw; + packet.port = port; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SERVO_OUTPUT_RAW; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SERVO_OUTPUT_RAW; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); } /** @@ -170,7 +183,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_servo_output_raw_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_servo_output_raw_t* servo_output_raw) { - return mavlink_msg_servo_output_raw_pack(system_id, component_id, msg, servo_output_raw->time_usec, servo_output_raw->port, servo_output_raw->servo1_raw, servo_output_raw->servo2_raw, servo_output_raw->servo3_raw, servo_output_raw->servo4_raw, servo_output_raw->servo5_raw, servo_output_raw->servo6_raw, servo_output_raw->servo7_raw, servo_output_raw->servo8_raw); + return mavlink_msg_servo_output_raw_pack(system_id, component_id, msg, servo_output_raw->time_usec, servo_output_raw->port, servo_output_raw->servo1_raw, servo_output_raw->servo2_raw, servo_output_raw->servo3_raw, servo_output_raw->servo4_raw, servo_output_raw->servo5_raw, servo_output_raw->servo6_raw, servo_output_raw->servo7_raw, servo_output_raw->servo8_raw); } /** @@ -184,7 +197,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_encode(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_servo_output_raw_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_servo_output_raw_t* servo_output_raw) { - return mavlink_msg_servo_output_raw_pack_chan(system_id, component_id, chan, msg, servo_output_raw->time_usec, servo_output_raw->port, servo_output_raw->servo1_raw, servo_output_raw->servo2_raw, servo_output_raw->servo3_raw, servo_output_raw->servo4_raw, servo_output_raw->servo5_raw, servo_output_raw->servo6_raw, servo_output_raw->servo7_raw, servo_output_raw->servo8_raw); + return mavlink_msg_servo_output_raw_pack_chan(system_id, component_id, chan, msg, servo_output_raw->time_usec, servo_output_raw->port, servo_output_raw->servo1_raw, servo_output_raw->servo2_raw, servo_output_raw->servo3_raw, servo_output_raw->servo4_raw, servo_output_raw->servo5_raw, servo_output_raw->servo6_raw, servo_output_raw->servo7_raw, servo_output_raw->servo8_raw); } /** @@ -207,41 +220,47 @@ static inline uint16_t mavlink_msg_servo_output_raw_encode_chan(uint8_t system_i static inline void mavlink_msg_servo_output_raw_send(mavlink_channel_t chan, uint32_t time_usec, uint8_t port, uint16_t servo1_raw, uint16_t servo2_raw, uint16_t servo3_raw, uint16_t servo4_raw, uint16_t servo5_raw, uint16_t servo6_raw, uint16_t servo7_raw, uint16_t servo8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN]; - _mav_put_uint32_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 4, servo1_raw); - _mav_put_uint16_t(buf, 6, servo2_raw); - _mav_put_uint16_t(buf, 8, servo3_raw); - _mav_put_uint16_t(buf, 10, servo4_raw); - _mav_put_uint16_t(buf, 12, servo5_raw); - _mav_put_uint16_t(buf, 14, servo6_raw); - _mav_put_uint16_t(buf, 16, servo7_raw); - _mav_put_uint16_t(buf, 18, servo8_raw); - _mav_put_uint8_t(buf, 20, port); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); + char buf[MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN]; + _mav_put_uint32_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 4, servo1_raw); + _mav_put_uint16_t(buf, 6, servo2_raw); + _mav_put_uint16_t(buf, 8, servo3_raw); + _mav_put_uint16_t(buf, 10, servo4_raw); + _mav_put_uint16_t(buf, 12, servo5_raw); + _mav_put_uint16_t(buf, 14, servo6_raw); + _mav_put_uint16_t(buf, 16, servo7_raw); + _mav_put_uint16_t(buf, 18, servo8_raw); + _mav_put_uint8_t(buf, 20, port); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); + mavlink_servo_output_raw_t packet; + packet.time_usec = time_usec; + packet.servo1_raw = servo1_raw; + packet.servo2_raw = servo2_raw; + packet.servo3_raw = servo3_raw; + packet.servo4_raw = servo4_raw; + packet.servo5_raw = servo5_raw; + packet.servo6_raw = servo6_raw; + packet.servo7_raw = servo7_raw; + packet.servo8_raw = servo8_raw; + packet.port = port; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, (const char *)&packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); #endif +} + +/** + * @brief Send a servo_output_raw message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_servo_output_raw_send_struct(mavlink_channel_t chan, const mavlink_servo_output_raw_t* servo_output_raw) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_servo_output_raw_send(chan, servo_output_raw->time_usec, servo_output_raw->port, servo_output_raw->servo1_raw, servo_output_raw->servo2_raw, servo_output_raw->servo3_raw, servo_output_raw->servo4_raw, servo_output_raw->servo5_raw, servo_output_raw->servo6_raw, servo_output_raw->servo7_raw, servo_output_raw->servo8_raw); #else - mavlink_servo_output_raw_t packet; - packet.time_usec = time_usec; - packet.servo1_raw = servo1_raw; - packet.servo2_raw = servo2_raw; - packet.servo3_raw = servo3_raw; - packet.servo4_raw = servo4_raw; - packet.servo5_raw = servo5_raw; - packet.servo6_raw = servo6_raw; - packet.servo7_raw = servo7_raw; - packet.servo8_raw = servo8_raw; - packet.port = port; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, (const char *)&packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, (const char *)&packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, (const char *)servo_output_raw, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); #endif } @@ -256,41 +275,33 @@ static inline void mavlink_msg_servo_output_raw_send(mavlink_channel_t chan, uin static inline void mavlink_msg_servo_output_raw_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_usec, uint8_t port, uint16_t servo1_raw, uint16_t servo2_raw, uint16_t servo3_raw, uint16_t servo4_raw, uint16_t servo5_raw, uint16_t servo6_raw, uint16_t servo7_raw, uint16_t servo8_raw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_usec); - _mav_put_uint16_t(buf, 4, servo1_raw); - _mav_put_uint16_t(buf, 6, servo2_raw); - _mav_put_uint16_t(buf, 8, servo3_raw); - _mav_put_uint16_t(buf, 10, servo4_raw); - _mav_put_uint16_t(buf, 12, servo5_raw); - _mav_put_uint16_t(buf, 14, servo6_raw); - _mav_put_uint16_t(buf, 16, servo7_raw); - _mav_put_uint16_t(buf, 18, servo8_raw); - _mav_put_uint8_t(buf, 20, port); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); -#endif -#else - mavlink_servo_output_raw_t *packet = (mavlink_servo_output_raw_t *)msgbuf; - packet->time_usec = time_usec; - packet->servo1_raw = servo1_raw; - packet->servo2_raw = servo2_raw; - packet->servo3_raw = servo3_raw; - packet->servo4_raw = servo4_raw; - packet->servo5_raw = servo5_raw; - packet->servo6_raw = servo6_raw; - packet->servo7_raw = servo7_raw; - packet->servo8_raw = servo8_raw; - packet->port = port; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, (const char *)packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_usec); + _mav_put_uint16_t(buf, 4, servo1_raw); + _mav_put_uint16_t(buf, 6, servo2_raw); + _mav_put_uint16_t(buf, 8, servo3_raw); + _mav_put_uint16_t(buf, 10, servo4_raw); + _mav_put_uint16_t(buf, 12, servo5_raw); + _mav_put_uint16_t(buf, 14, servo6_raw); + _mav_put_uint16_t(buf, 16, servo7_raw); + _mav_put_uint16_t(buf, 18, servo8_raw); + _mav_put_uint8_t(buf, 20, port); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, buf, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, (const char *)packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); -#endif + mavlink_servo_output_raw_t *packet = (mavlink_servo_output_raw_t *)msgbuf; + packet->time_usec = time_usec; + packet->servo1_raw = servo1_raw; + packet->servo2_raw = servo2_raw; + packet->servo3_raw = servo3_raw; + packet->servo4_raw = servo4_raw; + packet->servo5_raw = servo5_raw; + packet->servo6_raw = servo6_raw; + packet->servo7_raw = servo7_raw; + packet->servo8_raw = servo8_raw; + packet->port = port; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW, (const char *)packet, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_CRC); #endif } #endif @@ -307,7 +318,7 @@ static inline void mavlink_msg_servo_output_raw_send_buf(mavlink_message_t *msgb */ static inline uint32_t mavlink_msg_servo_output_raw_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -317,7 +328,7 @@ static inline uint32_t mavlink_msg_servo_output_raw_get_time_usec(const mavlink_ */ static inline uint8_t mavlink_msg_servo_output_raw_get_port(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 20); + return _MAV_RETURN_uint8_t(msg, 20); } /** @@ -327,7 +338,7 @@ static inline uint8_t mavlink_msg_servo_output_raw_get_port(const mavlink_messag */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo1_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 4); + return _MAV_RETURN_uint16_t(msg, 4); } /** @@ -337,7 +348,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo1_raw(const mavlink */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo2_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 6); + return _MAV_RETURN_uint16_t(msg, 6); } /** @@ -347,7 +358,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo2_raw(const mavlink */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo3_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -357,7 +368,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo3_raw(const mavlink */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo4_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 10); + return _MAV_RETURN_uint16_t(msg, 10); } /** @@ -367,7 +378,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo4_raw(const mavlink */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo5_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -377,7 +388,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo5_raw(const mavlink */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo6_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 14); + return _MAV_RETURN_uint16_t(msg, 14); } /** @@ -387,7 +398,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo6_raw(const mavlink */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo7_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** @@ -397,7 +408,7 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo7_raw(const mavlink */ static inline uint16_t mavlink_msg_servo_output_raw_get_servo8_raw(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -408,18 +419,20 @@ static inline uint16_t mavlink_msg_servo_output_raw_get_servo8_raw(const mavlink */ static inline void mavlink_msg_servo_output_raw_decode(const mavlink_message_t* msg, mavlink_servo_output_raw_t* servo_output_raw) { -#if MAVLINK_NEED_BYTE_SWAP - servo_output_raw->time_usec = mavlink_msg_servo_output_raw_get_time_usec(msg); - servo_output_raw->servo1_raw = mavlink_msg_servo_output_raw_get_servo1_raw(msg); - servo_output_raw->servo2_raw = mavlink_msg_servo_output_raw_get_servo2_raw(msg); - servo_output_raw->servo3_raw = mavlink_msg_servo_output_raw_get_servo3_raw(msg); - servo_output_raw->servo4_raw = mavlink_msg_servo_output_raw_get_servo4_raw(msg); - servo_output_raw->servo5_raw = mavlink_msg_servo_output_raw_get_servo5_raw(msg); - servo_output_raw->servo6_raw = mavlink_msg_servo_output_raw_get_servo6_raw(msg); - servo_output_raw->servo7_raw = mavlink_msg_servo_output_raw_get_servo7_raw(msg); - servo_output_raw->servo8_raw = mavlink_msg_servo_output_raw_get_servo8_raw(msg); - servo_output_raw->port = mavlink_msg_servo_output_raw_get_port(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + servo_output_raw->time_usec = mavlink_msg_servo_output_raw_get_time_usec(msg); + servo_output_raw->servo1_raw = mavlink_msg_servo_output_raw_get_servo1_raw(msg); + servo_output_raw->servo2_raw = mavlink_msg_servo_output_raw_get_servo2_raw(msg); + servo_output_raw->servo3_raw = mavlink_msg_servo_output_raw_get_servo3_raw(msg); + servo_output_raw->servo4_raw = mavlink_msg_servo_output_raw_get_servo4_raw(msg); + servo_output_raw->servo5_raw = mavlink_msg_servo_output_raw_get_servo5_raw(msg); + servo_output_raw->servo6_raw = mavlink_msg_servo_output_raw_get_servo6_raw(msg); + servo_output_raw->servo7_raw = mavlink_msg_servo_output_raw_get_servo7_raw(msg); + servo_output_raw->servo8_raw = mavlink_msg_servo_output_raw_get_servo8_raw(msg); + servo_output_raw->port = mavlink_msg_servo_output_raw_get_port(msg); #else - memcpy(servo_output_raw, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN? msg->len : MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN; + memset(servo_output_raw, 0, MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_LEN); + memcpy(servo_output_raw, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_set_actuator_control_target.h b/vendor/libraries/mavlink/common/mavlink_msg_set_actuator_control_target.h index 50d68a7c28..f804d4bc85 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_set_actuator_control_target.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_set_actuator_control_target.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE SET_ACTUATOR_CONTROL_TARGET PACKING #define MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET 139 -typedef struct __mavlink_set_actuator_control_target_t -{ - uint64_t time_usec; ///< Timestamp (micros since boot or Unix epoch) - float controls[8]; ///< Actuator controls. Normed to -1..+1 where 0 is neutral position. Throttle for single rotation direction motors is 0..1, negative range for reverse direction. Standard mapping for attitude controls (group 0): (index 0-7): roll, pitch, yaw, throttle, flaps, spoilers, airbrakes, landing gear. Load a pass-through mixer to repurpose them as generic outputs. - uint8_t group_mlx; ///< Actuator group. The "_mlx" indicates this is a multi-instance message and a MAVLink parser should use this field to difference between instances. - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID -} mavlink_set_actuator_control_target_t; +MAVPACKED( +typedef struct __mavlink_set_actuator_control_target_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float controls[8]; /*< Actuator controls. Normed to -1..+1 where 0 is neutral position. Throttle for single rotation direction motors is 0..1, negative range for reverse direction. Standard mapping for attitude controls (group 0): (index 0-7): roll, pitch, yaw, throttle, flaps, spoilers, airbrakes, landing gear. Load a pass-through mixer to repurpose them as generic outputs.*/ + uint8_t group_mlx; /*< Actuator group. The "_mlx" indicates this is a multi-instance message and a MAVLink parser should use this field to difference between instances.*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ +}) mavlink_set_actuator_control_target_t; #define MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN 43 +#define MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN 43 #define MAVLINK_MSG_ID_139_LEN 43 +#define MAVLINK_MSG_ID_139_MIN_LEN 43 #define MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC 168 #define MAVLINK_MSG_ID_139_CRC 168 #define MAVLINK_MSG_SET_ACTUATOR_CONTROL_TARGET_FIELD_CONTROLS_LEN 8 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SET_ACTUATOR_CONTROL_TARGET { \ - "SET_ACTUATOR_CONTROL_TARGET", \ - 5, \ - { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_set_actuator_control_target_t, time_usec) }, \ + 139, \ + "SET_ACTUATOR_CONTROL_TARGET", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_set_actuator_control_target_t, time_usec) }, \ { "controls", NULL, MAVLINK_TYPE_FLOAT, 8, 8, offsetof(mavlink_set_actuator_control_target_t, controls) }, \ { "group_mlx", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_set_actuator_control_target_t, group_mlx) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_set_actuator_control_target_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_set_actuator_control_target_t, target_component) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SET_ACTUATOR_CONTROL_TARGET { \ + "SET_ACTUATOR_CONTROL_TARGET", \ + 5, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_set_actuator_control_target_t, time_usec) }, \ + { "controls", NULL, MAVLINK_TYPE_FLOAT, 8, 8, offsetof(mavlink_set_actuator_control_target_t, controls) }, \ + { "group_mlx", NULL, MAVLINK_TYPE_UINT8_T, 0, 40, offsetof(mavlink_set_actuator_control_target_t, group_mlx) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 41, offsetof(mavlink_set_actuator_control_target_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_set_actuator_control_target_t, target_component) }, \ + } \ +} +#endif /** * @brief Pack a set_actuator_control_target message @@ -45,32 +61,28 @@ typedef struct __mavlink_set_actuator_control_target_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_actuator_control_target_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_usec, uint8_t group_mlx, uint8_t target_system, uint8_t target_component, const float *controls) + uint64_t time_usec, uint8_t group_mlx, uint8_t target_system, uint8_t target_component, const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_uint8_t(buf, 41, target_system); - _mav_put_uint8_t(buf, 42, target_component); - _mav_put_float_array(buf, 8, controls, 8); + char buf[MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_uint8_t(buf, 41, target_system); + _mav_put_uint8_t(buf, 42, target_component); + _mav_put_float_array(buf, 8, controls, 8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); #else - mavlink_set_actuator_control_target_t packet; - packet.time_usec = time_usec; - packet.group_mlx = group_mlx; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.controls, controls, sizeof(float)*8); + mavlink_set_actuator_control_target_t packet; + packet.time_usec = time_usec; + packet.group_mlx = group_mlx; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.controls, controls, sizeof(float)*8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); } /** @@ -87,33 +99,29 @@ static inline uint16_t mavlink_msg_set_actuator_control_target_pack(uint8_t syst * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_actuator_control_target_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_usec,uint8_t group_mlx,uint8_t target_system,uint8_t target_component,const float *controls) + mavlink_message_t* msg, + uint64_t time_usec,uint8_t group_mlx,uint8_t target_system,uint8_t target_component,const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_uint8_t(buf, 41, target_system); - _mav_put_uint8_t(buf, 42, target_component); - _mav_put_float_array(buf, 8, controls, 8); + char buf[MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_uint8_t(buf, 41, target_system); + _mav_put_uint8_t(buf, 42, target_component); + _mav_put_float_array(buf, 8, controls, 8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); #else - mavlink_set_actuator_control_target_t packet; - packet.time_usec = time_usec; - packet.group_mlx = group_mlx; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.controls, controls, sizeof(float)*8); + mavlink_set_actuator_control_target_t packet; + packet.time_usec = time_usec; + packet.group_mlx = group_mlx; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.controls, controls, sizeof(float)*8); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); } /** @@ -126,7 +134,7 @@ static inline uint16_t mavlink_msg_set_actuator_control_target_pack_chan(uint8_t */ static inline uint16_t mavlink_msg_set_actuator_control_target_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_actuator_control_target_t* set_actuator_control_target) { - return mavlink_msg_set_actuator_control_target_pack(system_id, component_id, msg, set_actuator_control_target->time_usec, set_actuator_control_target->group_mlx, set_actuator_control_target->target_system, set_actuator_control_target->target_component, set_actuator_control_target->controls); + return mavlink_msg_set_actuator_control_target_pack(system_id, component_id, msg, set_actuator_control_target->time_usec, set_actuator_control_target->group_mlx, set_actuator_control_target->target_system, set_actuator_control_target->target_component, set_actuator_control_target->controls); } /** @@ -140,7 +148,7 @@ static inline uint16_t mavlink_msg_set_actuator_control_target_encode(uint8_t sy */ static inline uint16_t mavlink_msg_set_actuator_control_target_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_actuator_control_target_t* set_actuator_control_target) { - return mavlink_msg_set_actuator_control_target_pack_chan(system_id, component_id, chan, msg, set_actuator_control_target->time_usec, set_actuator_control_target->group_mlx, set_actuator_control_target->target_system, set_actuator_control_target->target_component, set_actuator_control_target->controls); + return mavlink_msg_set_actuator_control_target_pack_chan(system_id, component_id, chan, msg, set_actuator_control_target->time_usec, set_actuator_control_target->group_mlx, set_actuator_control_target->target_system, set_actuator_control_target->target_component, set_actuator_control_target->controls); } /** @@ -158,29 +166,35 @@ static inline uint16_t mavlink_msg_set_actuator_control_target_encode_chan(uint8 static inline void mavlink_msg_set_actuator_control_target_send(mavlink_channel_t chan, uint64_t time_usec, uint8_t group_mlx, uint8_t target_system, uint8_t target_component, const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN]; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_uint8_t(buf, 41, target_system); - _mav_put_uint8_t(buf, 42, target_component); - _mav_put_float_array(buf, 8, controls, 8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); + char buf[MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_uint8_t(buf, 41, target_system); + _mav_put_uint8_t(buf, 42, target_component); + _mav_put_float_array(buf, 8, controls, 8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); + mavlink_set_actuator_control_target_t packet; + packet.time_usec = time_usec; + packet.group_mlx = group_mlx; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.controls, controls, sizeof(float)*8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, (const char *)&packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); #endif +} + +/** + * @brief Send a set_actuator_control_target message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_actuator_control_target_send_struct(mavlink_channel_t chan, const mavlink_set_actuator_control_target_t* set_actuator_control_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_actuator_control_target_send(chan, set_actuator_control_target->time_usec, set_actuator_control_target->group_mlx, set_actuator_control_target->target_system, set_actuator_control_target->target_component, set_actuator_control_target->controls); #else - mavlink_set_actuator_control_target_t packet; - packet.time_usec = time_usec; - packet.group_mlx = group_mlx; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.controls, controls, sizeof(float)*8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, (const char *)&packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, (const char *)&packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, (const char *)set_actuator_control_target, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); #endif } @@ -195,29 +209,21 @@ static inline void mavlink_msg_set_actuator_control_target_send(mavlink_channel_ static inline void mavlink_msg_set_actuator_control_target_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, uint8_t group_mlx, uint8_t target_system, uint8_t target_component, const float *controls) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_usec); - _mav_put_uint8_t(buf, 40, group_mlx); - _mav_put_uint8_t(buf, 41, target_system); - _mav_put_uint8_t(buf, 42, target_component); - _mav_put_float_array(buf, 8, controls, 8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_uint8_t(buf, 40, group_mlx); + _mav_put_uint8_t(buf, 41, target_system); + _mav_put_uint8_t(buf, 42, target_component); + _mav_put_float_array(buf, 8, controls, 8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, buf, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); -#endif -#else - mavlink_set_actuator_control_target_t *packet = (mavlink_set_actuator_control_target_t *)msgbuf; - packet->time_usec = time_usec; - packet->group_mlx = group_mlx; - packet->target_system = target_system; - packet->target_component = target_component; - mav_array_memcpy(packet->controls, controls, sizeof(float)*8); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, (const char *)packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, (const char *)packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); -#endif + mavlink_set_actuator_control_target_t *packet = (mavlink_set_actuator_control_target_t *)msgbuf; + packet->time_usec = time_usec; + packet->group_mlx = group_mlx; + packet->target_system = target_system; + packet->target_component = target_component; + mav_array_memcpy(packet->controls, controls, sizeof(float)*8); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET, (const char *)packet, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_CRC); #endif } #endif @@ -234,7 +240,7 @@ static inline void mavlink_msg_set_actuator_control_target_send_buf(mavlink_mess */ static inline uint64_t mavlink_msg_set_actuator_control_target_get_time_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -244,7 +250,7 @@ static inline uint64_t mavlink_msg_set_actuator_control_target_get_time_usec(con */ static inline uint8_t mavlink_msg_set_actuator_control_target_get_group_mlx(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 40); + return _MAV_RETURN_uint8_t(msg, 40); } /** @@ -254,7 +260,7 @@ static inline uint8_t mavlink_msg_set_actuator_control_target_get_group_mlx(cons */ static inline uint8_t mavlink_msg_set_actuator_control_target_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 41); + return _MAV_RETURN_uint8_t(msg, 41); } /** @@ -264,7 +270,7 @@ static inline uint8_t mavlink_msg_set_actuator_control_target_get_target_system( */ static inline uint8_t mavlink_msg_set_actuator_control_target_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 42); + return _MAV_RETURN_uint8_t(msg, 42); } /** @@ -274,7 +280,7 @@ static inline uint8_t mavlink_msg_set_actuator_control_target_get_target_compone */ static inline uint16_t mavlink_msg_set_actuator_control_target_get_controls(const mavlink_message_t* msg, float *controls) { - return _MAV_RETURN_float_array(msg, controls, 8, 8); + return _MAV_RETURN_float_array(msg, controls, 8, 8); } /** @@ -285,13 +291,15 @@ static inline uint16_t mavlink_msg_set_actuator_control_target_get_controls(cons */ static inline void mavlink_msg_set_actuator_control_target_decode(const mavlink_message_t* msg, mavlink_set_actuator_control_target_t* set_actuator_control_target) { -#if MAVLINK_NEED_BYTE_SWAP - set_actuator_control_target->time_usec = mavlink_msg_set_actuator_control_target_get_time_usec(msg); - mavlink_msg_set_actuator_control_target_get_controls(msg, set_actuator_control_target->controls); - set_actuator_control_target->group_mlx = mavlink_msg_set_actuator_control_target_get_group_mlx(msg); - set_actuator_control_target->target_system = mavlink_msg_set_actuator_control_target_get_target_system(msg); - set_actuator_control_target->target_component = mavlink_msg_set_actuator_control_target_get_target_component(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_actuator_control_target->time_usec = mavlink_msg_set_actuator_control_target_get_time_usec(msg); + mavlink_msg_set_actuator_control_target_get_controls(msg, set_actuator_control_target->controls); + set_actuator_control_target->group_mlx = mavlink_msg_set_actuator_control_target_get_group_mlx(msg); + set_actuator_control_target->target_system = mavlink_msg_set_actuator_control_target_get_target_system(msg); + set_actuator_control_target->target_component = mavlink_msg_set_actuator_control_target_get_target_component(msg); #else - memcpy(set_actuator_control_target, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN? msg->len : MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN; + memset(set_actuator_control_target, 0, MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_LEN); + memcpy(set_actuator_control_target, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_set_attitude_target.h b/vendor/libraries/mavlink/common/mavlink_msg_set_attitude_target.h index 19ccc14796..1b68caa025 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_set_attitude_target.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_set_attitude_target.h @@ -1,32 +1,37 @@ +#pragma once // MESSAGE SET_ATTITUDE_TARGET PACKING #define MAVLINK_MSG_ID_SET_ATTITUDE_TARGET 82 -typedef struct __mavlink_set_attitude_target_t -{ - uint32_t time_boot_ms; ///< Timestamp in milliseconds since system boot - float q[4]; ///< Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0) - float body_roll_rate; ///< Body roll rate in radians per second - float body_pitch_rate; ///< Body roll rate in radians per second - float body_yaw_rate; ///< Body roll rate in radians per second - float thrust; ///< Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust) - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t type_mask; ///< Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 6: reserved, bit 7: throttle, bit 8: attitude -} mavlink_set_attitude_target_t; +MAVPACKED( +typedef struct __mavlink_set_attitude_target_t { + uint32_t time_boot_ms; /*< Timestamp in milliseconds since system boot*/ + float q[4]; /*< Attitude quaternion (w, x, y, z order, zero-rotation is 1, 0, 0, 0)*/ + float body_roll_rate; /*< Body roll rate in radians per second*/ + float body_pitch_rate; /*< Body roll rate in radians per second*/ + float body_yaw_rate; /*< Body roll rate in radians per second*/ + float thrust; /*< Collective thrust, normalized to 0 .. 1 (-1 .. 1 for vehicles capable of reverse trust)*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t type_mask; /*< Mappings: If any of these bits are set, the corresponding input should be ignored: bit 1: body roll rate, bit 2: body pitch rate, bit 3: body yaw rate. bit 4-bit 6: reserved, bit 7: throttle, bit 8: attitude*/ +}) mavlink_set_attitude_target_t; #define MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN 39 +#define MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN 39 #define MAVLINK_MSG_ID_82_LEN 39 +#define MAVLINK_MSG_ID_82_MIN_LEN 39 #define MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC 49 #define MAVLINK_MSG_ID_82_CRC 49 #define MAVLINK_MSG_SET_ATTITUDE_TARGET_FIELD_Q_LEN 4 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SET_ATTITUDE_TARGET { \ - "SET_ATTITUDE_TARGET", \ - 9, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_attitude_target_t, time_boot_ms) }, \ + 82, \ + "SET_ATTITUDE_TARGET", \ + 9, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_attitude_target_t, time_boot_ms) }, \ { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 4, offsetof(mavlink_set_attitude_target_t, q) }, \ { "body_roll_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_set_attitude_target_t, body_roll_rate) }, \ { "body_pitch_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_set_attitude_target_t, body_pitch_rate) }, \ @@ -37,7 +42,22 @@ typedef struct __mavlink_set_attitude_target_t { "type_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 38, offsetof(mavlink_set_attitude_target_t, type_mask) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SET_ATTITUDE_TARGET { \ + "SET_ATTITUDE_TARGET", \ + 9, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_attitude_target_t, time_boot_ms) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 4, offsetof(mavlink_set_attitude_target_t, q) }, \ + { "body_roll_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_set_attitude_target_t, body_roll_rate) }, \ + { "body_pitch_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_set_attitude_target_t, body_pitch_rate) }, \ + { "body_yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_set_attitude_target_t, body_yaw_rate) }, \ + { "thrust", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_set_attitude_target_t, thrust) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 36, offsetof(mavlink_set_attitude_target_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 37, offsetof(mavlink_set_attitude_target_t, target_component) }, \ + { "type_mask", NULL, MAVLINK_TYPE_UINT8_T, 0, 38, offsetof(mavlink_set_attitude_target_t, type_mask) }, \ + } \ +} +#endif /** * @brief Pack a set_attitude_target message @@ -57,40 +77,36 @@ typedef struct __mavlink_set_attitude_target_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_attitude_target_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) + uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, target_system); - _mav_put_uint8_t(buf, 37, target_component); - _mav_put_uint8_t(buf, 38, type_mask); - _mav_put_float_array(buf, 4, q, 4); + char buf[MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, target_system); + _mav_put_uint8_t(buf, 37, target_component); + _mav_put_uint8_t(buf, 38, type_mask); + _mav_put_float_array(buf, 4, q, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); #else - mavlink_set_attitude_target_t packet; - packet.time_boot_ms = time_boot_ms; - packet.body_roll_rate = body_roll_rate; - packet.body_pitch_rate = body_pitch_rate; - packet.body_yaw_rate = body_yaw_rate; - packet.thrust = thrust; - packet.target_system = target_system; - packet.target_component = target_component; - packet.type_mask = type_mask; - mav_array_memcpy(packet.q, q, sizeof(float)*4); + mavlink_set_attitude_target_t packet; + packet.time_boot_ms = time_boot_ms; + packet.body_roll_rate = body_roll_rate; + packet.body_pitch_rate = body_pitch_rate; + packet.body_yaw_rate = body_yaw_rate; + packet.thrust = thrust; + packet.target_system = target_system; + packet.target_component = target_component; + packet.type_mask = type_mask; + mav_array_memcpy(packet.q, q, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_ATTITUDE_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_ATTITUDE_TARGET; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); } /** @@ -111,41 +127,37 @@ static inline uint16_t mavlink_msg_set_attitude_target_pack(uint8_t system_id, u * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_attitude_target_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t target_system,uint8_t target_component,uint8_t type_mask,const float *q,float body_roll_rate,float body_pitch_rate,float body_yaw_rate,float thrust) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t target_system,uint8_t target_component,uint8_t type_mask,const float *q,float body_roll_rate,float body_pitch_rate,float body_yaw_rate,float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, target_system); - _mav_put_uint8_t(buf, 37, target_component); - _mav_put_uint8_t(buf, 38, type_mask); - _mav_put_float_array(buf, 4, q, 4); + char buf[MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, target_system); + _mav_put_uint8_t(buf, 37, target_component); + _mav_put_uint8_t(buf, 38, type_mask); + _mav_put_float_array(buf, 4, q, 4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); #else - mavlink_set_attitude_target_t packet; - packet.time_boot_ms = time_boot_ms; - packet.body_roll_rate = body_roll_rate; - packet.body_pitch_rate = body_pitch_rate; - packet.body_yaw_rate = body_yaw_rate; - packet.thrust = thrust; - packet.target_system = target_system; - packet.target_component = target_component; - packet.type_mask = type_mask; - mav_array_memcpy(packet.q, q, sizeof(float)*4); + mavlink_set_attitude_target_t packet; + packet.time_boot_ms = time_boot_ms; + packet.body_roll_rate = body_roll_rate; + packet.body_pitch_rate = body_pitch_rate; + packet.body_yaw_rate = body_yaw_rate; + packet.thrust = thrust; + packet.target_system = target_system; + packet.target_component = target_component; + packet.type_mask = type_mask; + mav_array_memcpy(packet.q, q, sizeof(float)*4); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_ATTITUDE_TARGET; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_ATTITUDE_TARGET; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); } /** @@ -158,7 +170,7 @@ static inline uint16_t mavlink_msg_set_attitude_target_pack_chan(uint8_t system_ */ static inline uint16_t mavlink_msg_set_attitude_target_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_attitude_target_t* set_attitude_target) { - return mavlink_msg_set_attitude_target_pack(system_id, component_id, msg, set_attitude_target->time_boot_ms, set_attitude_target->target_system, set_attitude_target->target_component, set_attitude_target->type_mask, set_attitude_target->q, set_attitude_target->body_roll_rate, set_attitude_target->body_pitch_rate, set_attitude_target->body_yaw_rate, set_attitude_target->thrust); + return mavlink_msg_set_attitude_target_pack(system_id, component_id, msg, set_attitude_target->time_boot_ms, set_attitude_target->target_system, set_attitude_target->target_component, set_attitude_target->type_mask, set_attitude_target->q, set_attitude_target->body_roll_rate, set_attitude_target->body_pitch_rate, set_attitude_target->body_yaw_rate, set_attitude_target->thrust); } /** @@ -172,7 +184,7 @@ static inline uint16_t mavlink_msg_set_attitude_target_encode(uint8_t system_id, */ static inline uint16_t mavlink_msg_set_attitude_target_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_attitude_target_t* set_attitude_target) { - return mavlink_msg_set_attitude_target_pack_chan(system_id, component_id, chan, msg, set_attitude_target->time_boot_ms, set_attitude_target->target_system, set_attitude_target->target_component, set_attitude_target->type_mask, set_attitude_target->q, set_attitude_target->body_roll_rate, set_attitude_target->body_pitch_rate, set_attitude_target->body_yaw_rate, set_attitude_target->thrust); + return mavlink_msg_set_attitude_target_pack_chan(system_id, component_id, chan, msg, set_attitude_target->time_boot_ms, set_attitude_target->target_system, set_attitude_target->target_component, set_attitude_target->type_mask, set_attitude_target->q, set_attitude_target->body_roll_rate, set_attitude_target->body_pitch_rate, set_attitude_target->body_yaw_rate, set_attitude_target->thrust); } /** @@ -194,37 +206,43 @@ static inline uint16_t mavlink_msg_set_attitude_target_encode_chan(uint8_t syste static inline void mavlink_msg_set_attitude_target_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, target_system); - _mav_put_uint8_t(buf, 37, target_component); - _mav_put_uint8_t(buf, 38, type_mask); - _mav_put_float_array(buf, 4, q, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); + char buf[MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, target_system); + _mav_put_uint8_t(buf, 37, target_component); + _mav_put_uint8_t(buf, 38, type_mask); + _mav_put_float_array(buf, 4, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); + mavlink_set_attitude_target_t packet; + packet.time_boot_ms = time_boot_ms; + packet.body_roll_rate = body_roll_rate; + packet.body_pitch_rate = body_pitch_rate; + packet.body_yaw_rate = body_yaw_rate; + packet.thrust = thrust; + packet.target_system = target_system; + packet.target_component = target_component; + packet.type_mask = type_mask; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, (const char *)&packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); #endif +} + +/** + * @brief Send a set_attitude_target message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_attitude_target_send_struct(mavlink_channel_t chan, const mavlink_set_attitude_target_t* set_attitude_target) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_attitude_target_send(chan, set_attitude_target->time_boot_ms, set_attitude_target->target_system, set_attitude_target->target_component, set_attitude_target->type_mask, set_attitude_target->q, set_attitude_target->body_roll_rate, set_attitude_target->body_pitch_rate, set_attitude_target->body_yaw_rate, set_attitude_target->thrust); #else - mavlink_set_attitude_target_t packet; - packet.time_boot_ms = time_boot_ms; - packet.body_roll_rate = body_roll_rate; - packet.body_pitch_rate = body_pitch_rate; - packet.body_yaw_rate = body_yaw_rate; - packet.thrust = thrust; - packet.target_system = target_system; - packet.target_component = target_component; - packet.type_mask = type_mask; - mav_array_memcpy(packet.q, q, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, (const char *)&packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, (const char *)&packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, (const char *)set_attitude_target, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); #endif } @@ -239,37 +257,29 @@ static inline void mavlink_msg_set_attitude_target_send(mavlink_channel_t chan, static inline void mavlink_msg_set_attitude_target_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t type_mask, const float *q, float body_roll_rate, float body_pitch_rate, float body_yaw_rate, float thrust) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 20, body_roll_rate); - _mav_put_float(buf, 24, body_pitch_rate); - _mav_put_float(buf, 28, body_yaw_rate); - _mav_put_float(buf, 32, thrust); - _mav_put_uint8_t(buf, 36, target_system); - _mav_put_uint8_t(buf, 37, target_component); - _mav_put_uint8_t(buf, 38, type_mask); - _mav_put_float_array(buf, 4, q, 4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); -#endif -#else - mavlink_set_attitude_target_t *packet = (mavlink_set_attitude_target_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->body_roll_rate = body_roll_rate; - packet->body_pitch_rate = body_pitch_rate; - packet->body_yaw_rate = body_yaw_rate; - packet->thrust = thrust; - packet->target_system = target_system; - packet->target_component = target_component; - packet->type_mask = type_mask; - mav_array_memcpy(packet->q, q, sizeof(float)*4); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, (const char *)packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 20, body_roll_rate); + _mav_put_float(buf, 24, body_pitch_rate); + _mav_put_float(buf, 28, body_yaw_rate); + _mav_put_float(buf, 32, thrust); + _mav_put_uint8_t(buf, 36, target_system); + _mav_put_uint8_t(buf, 37, target_component); + _mav_put_uint8_t(buf, 38, type_mask); + _mav_put_float_array(buf, 4, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, buf, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, (const char *)packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); -#endif + mavlink_set_attitude_target_t *packet = (mavlink_set_attitude_target_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->body_roll_rate = body_roll_rate; + packet->body_pitch_rate = body_pitch_rate; + packet->body_yaw_rate = body_yaw_rate; + packet->thrust = thrust; + packet->target_system = target_system; + packet->target_component = target_component; + packet->type_mask = type_mask; + mav_array_memcpy(packet->q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET, (const char *)packet, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_CRC); #endif } #endif @@ -286,7 +296,7 @@ static inline void mavlink_msg_set_attitude_target_send_buf(mavlink_message_t *m */ static inline uint32_t mavlink_msg_set_attitude_target_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -296,7 +306,7 @@ static inline uint32_t mavlink_msg_set_attitude_target_get_time_boot_ms(const ma */ static inline uint8_t mavlink_msg_set_attitude_target_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 36); + return _MAV_RETURN_uint8_t(msg, 36); } /** @@ -306,7 +316,7 @@ static inline uint8_t mavlink_msg_set_attitude_target_get_target_system(const ma */ static inline uint8_t mavlink_msg_set_attitude_target_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 37); + return _MAV_RETURN_uint8_t(msg, 37); } /** @@ -316,7 +326,7 @@ static inline uint8_t mavlink_msg_set_attitude_target_get_target_component(const */ static inline uint8_t mavlink_msg_set_attitude_target_get_type_mask(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 38); + return _MAV_RETURN_uint8_t(msg, 38); } /** @@ -326,7 +336,7 @@ static inline uint8_t mavlink_msg_set_attitude_target_get_type_mask(const mavlin */ static inline uint16_t mavlink_msg_set_attitude_target_get_q(const mavlink_message_t* msg, float *q) { - return _MAV_RETURN_float_array(msg, q, 4, 4); + return _MAV_RETURN_float_array(msg, q, 4, 4); } /** @@ -336,7 +346,7 @@ static inline uint16_t mavlink_msg_set_attitude_target_get_q(const mavlink_messa */ static inline float mavlink_msg_set_attitude_target_get_body_roll_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -346,7 +356,7 @@ static inline float mavlink_msg_set_attitude_target_get_body_roll_rate(const mav */ static inline float mavlink_msg_set_attitude_target_get_body_pitch_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -356,7 +366,7 @@ static inline float mavlink_msg_set_attitude_target_get_body_pitch_rate(const ma */ static inline float mavlink_msg_set_attitude_target_get_body_yaw_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -366,7 +376,7 @@ static inline float mavlink_msg_set_attitude_target_get_body_yaw_rate(const mavl */ static inline float mavlink_msg_set_attitude_target_get_thrust(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -377,17 +387,19 @@ static inline float mavlink_msg_set_attitude_target_get_thrust(const mavlink_mes */ static inline void mavlink_msg_set_attitude_target_decode(const mavlink_message_t* msg, mavlink_set_attitude_target_t* set_attitude_target) { -#if MAVLINK_NEED_BYTE_SWAP - set_attitude_target->time_boot_ms = mavlink_msg_set_attitude_target_get_time_boot_ms(msg); - mavlink_msg_set_attitude_target_get_q(msg, set_attitude_target->q); - set_attitude_target->body_roll_rate = mavlink_msg_set_attitude_target_get_body_roll_rate(msg); - set_attitude_target->body_pitch_rate = mavlink_msg_set_attitude_target_get_body_pitch_rate(msg); - set_attitude_target->body_yaw_rate = mavlink_msg_set_attitude_target_get_body_yaw_rate(msg); - set_attitude_target->thrust = mavlink_msg_set_attitude_target_get_thrust(msg); - set_attitude_target->target_system = mavlink_msg_set_attitude_target_get_target_system(msg); - set_attitude_target->target_component = mavlink_msg_set_attitude_target_get_target_component(msg); - set_attitude_target->type_mask = mavlink_msg_set_attitude_target_get_type_mask(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_attitude_target->time_boot_ms = mavlink_msg_set_attitude_target_get_time_boot_ms(msg); + mavlink_msg_set_attitude_target_get_q(msg, set_attitude_target->q); + set_attitude_target->body_roll_rate = mavlink_msg_set_attitude_target_get_body_roll_rate(msg); + set_attitude_target->body_pitch_rate = mavlink_msg_set_attitude_target_get_body_pitch_rate(msg); + set_attitude_target->body_yaw_rate = mavlink_msg_set_attitude_target_get_body_yaw_rate(msg); + set_attitude_target->thrust = mavlink_msg_set_attitude_target_get_thrust(msg); + set_attitude_target->target_system = mavlink_msg_set_attitude_target_get_target_system(msg); + set_attitude_target->target_component = mavlink_msg_set_attitude_target_get_target_component(msg); + set_attitude_target->type_mask = mavlink_msg_set_attitude_target_get_type_mask(msg); #else - memcpy(set_attitude_target, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN? msg->len : MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN; + memset(set_attitude_target, 0, MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_LEN); + memcpy(set_attitude_target, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_set_gps_global_origin.h b/vendor/libraries/mavlink/common/mavlink_msg_set_gps_global_origin.h index f5d918f437..a934c19324 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_set_gps_global_origin.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_set_gps_global_origin.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE SET_GPS_GLOBAL_ORIGIN PACKING #define MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN 48 -typedef struct __mavlink_set_gps_global_origin_t -{ - int32_t latitude; ///< Latitude (WGS84), in degrees * 1E7 - int32_t longitude; ///< Longitude (WGS84, in degrees * 1E7 - int32_t altitude; ///< Altitude (AMSL), in meters * 1000 (positive for up) - uint8_t target_system; ///< System ID -} mavlink_set_gps_global_origin_t; +MAVPACKED( +typedef struct __mavlink_set_gps_global_origin_t { + int32_t latitude; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t longitude; /*< Longitude (WGS84, in degrees * 1E7*/ + int32_t altitude; /*< Altitude (AMSL), in meters * 1000 (positive for up)*/ + uint8_t target_system; /*< System ID*/ +}) mavlink_set_gps_global_origin_t; #define MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN 13 +#define MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN 13 #define MAVLINK_MSG_ID_48_LEN 13 +#define MAVLINK_MSG_ID_48_MIN_LEN 13 #define MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC 41 #define MAVLINK_MSG_ID_48_CRC 41 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN { \ - "SET_GPS_GLOBAL_ORIGIN", \ - 4, \ - { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_set_gps_global_origin_t, latitude) }, \ + 48, \ + "SET_GPS_GLOBAL_ORIGIN", \ + 4, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_set_gps_global_origin_t, latitude) }, \ { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_set_gps_global_origin_t, longitude) }, \ { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_set_gps_global_origin_t, altitude) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_set_gps_global_origin_t, target_system) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SET_GPS_GLOBAL_ORIGIN { \ + "SET_GPS_GLOBAL_ORIGIN", \ + 4, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_set_gps_global_origin_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_set_gps_global_origin_t, longitude) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_set_gps_global_origin_t, altitude) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 12, offsetof(mavlink_set_gps_global_origin_t, target_system) }, \ + } \ +} +#endif /** * @brief Pack a set_gps_global_origin message @@ -42,32 +57,28 @@ typedef struct __mavlink_set_gps_global_origin_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_gps_global_origin_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, int32_t latitude, int32_t longitude, int32_t altitude) + uint8_t target_system, int32_t latitude, int32_t longitude, int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN]; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); - _mav_put_uint8_t(buf, 12, target_system); + char buf[MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_uint8_t(buf, 12, target_system); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); #else - mavlink_set_gps_global_origin_t packet; - packet.latitude = latitude; - packet.longitude = longitude; - packet.altitude = altitude; - packet.target_system = target_system; + mavlink_set_gps_global_origin_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.target_system = target_system; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_set_gps_global_origin_pack(uint8_t system_id, * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_gps_global_origin_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,int32_t latitude,int32_t longitude,int32_t altitude) + mavlink_message_t* msg, + uint8_t target_system,int32_t latitude,int32_t longitude,int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN]; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); - _mav_put_uint8_t(buf, 12, target_system); + char buf[MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_uint8_t(buf, 12, target_system); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); #else - mavlink_set_gps_global_origin_t packet; - packet.latitude = latitude; - packet.longitude = longitude; - packet.altitude = altitude; - packet.target_system = target_system; + mavlink_set_gps_global_origin_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.target_system = target_system; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_set_gps_global_origin_pack_chan(uint8_t syste */ static inline uint16_t mavlink_msg_set_gps_global_origin_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_gps_global_origin_t* set_gps_global_origin) { - return mavlink_msg_set_gps_global_origin_pack(system_id, component_id, msg, set_gps_global_origin->target_system, set_gps_global_origin->latitude, set_gps_global_origin->longitude, set_gps_global_origin->altitude); + return mavlink_msg_set_gps_global_origin_pack(system_id, component_id, msg, set_gps_global_origin->target_system, set_gps_global_origin->latitude, set_gps_global_origin->longitude, set_gps_global_origin->altitude); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_set_gps_global_origin_encode(uint8_t system_i */ static inline uint16_t mavlink_msg_set_gps_global_origin_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_gps_global_origin_t* set_gps_global_origin) { - return mavlink_msg_set_gps_global_origin_pack_chan(system_id, component_id, chan, msg, set_gps_global_origin->target_system, set_gps_global_origin->latitude, set_gps_global_origin->longitude, set_gps_global_origin->altitude); + return mavlink_msg_set_gps_global_origin_pack_chan(system_id, component_id, chan, msg, set_gps_global_origin->target_system, set_gps_global_origin->latitude, set_gps_global_origin->longitude, set_gps_global_origin->altitude); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_set_gps_global_origin_encode_chan(uint8_t sys static inline void mavlink_msg_set_gps_global_origin_send(mavlink_channel_t chan, uint8_t target_system, int32_t latitude, int32_t longitude, int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN]; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); - _mav_put_uint8_t(buf, 12, target_system); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); + char buf[MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_uint8_t(buf, 12, target_system); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); + mavlink_set_gps_global_origin_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.target_system = target_system; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, (const char *)&packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); #endif +} + +/** + * @brief Send a set_gps_global_origin message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_gps_global_origin_send_struct(mavlink_channel_t chan, const mavlink_set_gps_global_origin_t* set_gps_global_origin) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_gps_global_origin_send(chan, set_gps_global_origin->target_system, set_gps_global_origin->latitude, set_gps_global_origin->longitude, set_gps_global_origin->altitude); #else - mavlink_set_gps_global_origin_t packet; - packet.latitude = latitude; - packet.longitude = longitude; - packet.altitude = altitude; - packet.target_system = target_system; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, (const char *)&packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, (const char *)&packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, (const char *)set_gps_global_origin, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_set_gps_global_origin_send(mavlink_channel_t chan static inline void mavlink_msg_set_gps_global_origin_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, int32_t latitude, int32_t longitude, int32_t altitude) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, latitude); - _mav_put_int32_t(buf, 4, longitude); - _mav_put_int32_t(buf, 8, altitude); - _mav_put_uint8_t(buf, 12, target_system); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); -#endif -#else - mavlink_set_gps_global_origin_t *packet = (mavlink_set_gps_global_origin_t *)msgbuf; - packet->latitude = latitude; - packet->longitude = longitude; - packet->altitude = altitude; - packet->target_system = target_system; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, (const char *)packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_uint8_t(buf, 12, target_system); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, buf, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, (const char *)packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); -#endif + mavlink_set_gps_global_origin_t *packet = (mavlink_set_gps_global_origin_t *)msgbuf; + packet->latitude = latitude; + packet->longitude = longitude; + packet->altitude = altitude; + packet->target_system = target_system; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN, (const char *)packet, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_set_gps_global_origin_send_buf(mavlink_message_t */ static inline uint8_t mavlink_msg_set_gps_global_origin_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 12); + return _MAV_RETURN_uint8_t(msg, 12); } /** @@ -239,7 +244,7 @@ static inline uint8_t mavlink_msg_set_gps_global_origin_get_target_system(const */ static inline int32_t mavlink_msg_set_gps_global_origin_get_latitude(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -249,7 +254,7 @@ static inline int32_t mavlink_msg_set_gps_global_origin_get_latitude(const mavli */ static inline int32_t mavlink_msg_set_gps_global_origin_get_longitude(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -259,7 +264,7 @@ static inline int32_t mavlink_msg_set_gps_global_origin_get_longitude(const mavl */ static inline int32_t mavlink_msg_set_gps_global_origin_get_altitude(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -270,12 +275,14 @@ static inline int32_t mavlink_msg_set_gps_global_origin_get_altitude(const mavli */ static inline void mavlink_msg_set_gps_global_origin_decode(const mavlink_message_t* msg, mavlink_set_gps_global_origin_t* set_gps_global_origin) { -#if MAVLINK_NEED_BYTE_SWAP - set_gps_global_origin->latitude = mavlink_msg_set_gps_global_origin_get_latitude(msg); - set_gps_global_origin->longitude = mavlink_msg_set_gps_global_origin_get_longitude(msg); - set_gps_global_origin->altitude = mavlink_msg_set_gps_global_origin_get_altitude(msg); - set_gps_global_origin->target_system = mavlink_msg_set_gps_global_origin_get_target_system(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_gps_global_origin->latitude = mavlink_msg_set_gps_global_origin_get_latitude(msg); + set_gps_global_origin->longitude = mavlink_msg_set_gps_global_origin_get_longitude(msg); + set_gps_global_origin->altitude = mavlink_msg_set_gps_global_origin_get_altitude(msg); + set_gps_global_origin->target_system = mavlink_msg_set_gps_global_origin_get_target_system(msg); #else - memcpy(set_gps_global_origin, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN? msg->len : MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN; + memset(set_gps_global_origin, 0, MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_LEN); + memcpy(set_gps_global_origin, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_set_home_position.h b/vendor/libraries/mavlink/common/mavlink_msg_set_home_position.h new file mode 100644 index 0000000000..cd7c8d34c4 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_set_home_position.h @@ -0,0 +1,455 @@ +#pragma once +// MESSAGE SET_HOME_POSITION PACKING + +#define MAVLINK_MSG_ID_SET_HOME_POSITION 243 + +MAVPACKED( +typedef struct __mavlink_set_home_position_t { + int32_t latitude; /*< Latitude (WGS84), in degrees * 1E7*/ + int32_t longitude; /*< Longitude (WGS84, in degrees * 1E7*/ + int32_t altitude; /*< Altitude (AMSL), in meters * 1000 (positive for up)*/ + float x; /*< Local X position of this position in the local coordinate frame*/ + float y; /*< Local Y position of this position in the local coordinate frame*/ + float z; /*< Local Z position of this position in the local coordinate frame*/ + float q[4]; /*< World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground*/ + float approach_x; /*< Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone.*/ + float approach_y; /*< Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone.*/ + float approach_z; /*< Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone.*/ + uint8_t target_system; /*< System ID.*/ +}) mavlink_set_home_position_t; + +#define MAVLINK_MSG_ID_SET_HOME_POSITION_LEN 53 +#define MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN 53 +#define MAVLINK_MSG_ID_243_LEN 53 +#define MAVLINK_MSG_ID_243_MIN_LEN 53 + +#define MAVLINK_MSG_ID_SET_HOME_POSITION_CRC 85 +#define MAVLINK_MSG_ID_243_CRC 85 + +#define MAVLINK_MSG_SET_HOME_POSITION_FIELD_Q_LEN 4 + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_SET_HOME_POSITION { \ + 243, \ + "SET_HOME_POSITION", \ + 11, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_set_home_position_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_set_home_position_t, longitude) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_set_home_position_t, altitude) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_set_home_position_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_set_home_position_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_set_home_position_t, z) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 24, offsetof(mavlink_set_home_position_t, q) }, \ + { "approach_x", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_set_home_position_t, approach_x) }, \ + { "approach_y", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_set_home_position_t, approach_y) }, \ + { "approach_z", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_set_home_position_t, approach_z) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 52, offsetof(mavlink_set_home_position_t, target_system) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_SET_HOME_POSITION { \ + "SET_HOME_POSITION", \ + 11, \ + { { "latitude", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_set_home_position_t, latitude) }, \ + { "longitude", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_set_home_position_t, longitude) }, \ + { "altitude", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_set_home_position_t, altitude) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_set_home_position_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_set_home_position_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_set_home_position_t, z) }, \ + { "q", NULL, MAVLINK_TYPE_FLOAT, 4, 24, offsetof(mavlink_set_home_position_t, q) }, \ + { "approach_x", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_set_home_position_t, approach_x) }, \ + { "approach_y", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_set_home_position_t, approach_y) }, \ + { "approach_z", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_set_home_position_t, approach_z) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 52, offsetof(mavlink_set_home_position_t, target_system) }, \ + } \ +} +#endif + +/** + * @brief Pack a set_home_position message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param target_system System ID. + * @param latitude Latitude (WGS84), in degrees * 1E7 + * @param longitude Longitude (WGS84, in degrees * 1E7 + * @param altitude Altitude (AMSL), in meters * 1000 (positive for up) + * @param x Local X position of this position in the local coordinate frame + * @param y Local Y position of this position in the local coordinate frame + * @param z Local Z position of this position in the local coordinate frame + * @param q World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + * @param approach_x Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_y Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_z Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_set_home_position_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint8_t target_system, int32_t latitude, int32_t longitude, int32_t altitude, float x, float y, float z, const float *q, float approach_x, float approach_y, float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SET_HOME_POSITION_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_uint8_t(buf, 52, target_system); + _mav_put_float_array(buf, 24, q, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN); +#else + mavlink_set_home_position_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.x = x; + packet.y = y; + packet.z = z; + packet.approach_x = approach_x; + packet.approach_y = approach_y; + packet.approach_z = approach_z; + packet.target_system = target_system; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_SET_HOME_POSITION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_CRC); +} + +/** + * @brief Pack a set_home_position message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param target_system System ID. + * @param latitude Latitude (WGS84), in degrees * 1E7 + * @param longitude Longitude (WGS84, in degrees * 1E7 + * @param altitude Altitude (AMSL), in meters * 1000 (positive for up) + * @param x Local X position of this position in the local coordinate frame + * @param y Local Y position of this position in the local coordinate frame + * @param z Local Z position of this position in the local coordinate frame + * @param q World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + * @param approach_x Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_y Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_z Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_set_home_position_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint8_t target_system,int32_t latitude,int32_t longitude,int32_t altitude,float x,float y,float z,const float *q,float approach_x,float approach_y,float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SET_HOME_POSITION_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_uint8_t(buf, 52, target_system); + _mav_put_float_array(buf, 24, q, 4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN); +#else + mavlink_set_home_position_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.x = x; + packet.y = y; + packet.z = z; + packet.approach_x = approach_x; + packet.approach_y = approach_y; + packet.approach_z = approach_z; + packet.target_system = target_system; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_SET_HOME_POSITION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_CRC); +} + +/** + * @brief Encode a set_home_position struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param set_home_position C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_home_position_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_home_position_t* set_home_position) +{ + return mavlink_msg_set_home_position_pack(system_id, component_id, msg, set_home_position->target_system, set_home_position->latitude, set_home_position->longitude, set_home_position->altitude, set_home_position->x, set_home_position->y, set_home_position->z, set_home_position->q, set_home_position->approach_x, set_home_position->approach_y, set_home_position->approach_z); +} + +/** + * @brief Encode a set_home_position struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param set_home_position C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_set_home_position_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_home_position_t* set_home_position) +{ + return mavlink_msg_set_home_position_pack_chan(system_id, component_id, chan, msg, set_home_position->target_system, set_home_position->latitude, set_home_position->longitude, set_home_position->altitude, set_home_position->x, set_home_position->y, set_home_position->z, set_home_position->q, set_home_position->approach_x, set_home_position->approach_y, set_home_position->approach_z); +} + +/** + * @brief Send a set_home_position message + * @param chan MAVLink channel to send the message + * + * @param target_system System ID. + * @param latitude Latitude (WGS84), in degrees * 1E7 + * @param longitude Longitude (WGS84, in degrees * 1E7 + * @param altitude Altitude (AMSL), in meters * 1000 (positive for up) + * @param x Local X position of this position in the local coordinate frame + * @param y Local Y position of this position in the local coordinate frame + * @param z Local Z position of this position in the local coordinate frame + * @param q World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + * @param approach_x Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_y Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + * @param approach_z Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_set_home_position_send(mavlink_channel_t chan, uint8_t target_system, int32_t latitude, int32_t longitude, int32_t altitude, float x, float y, float z, const float *q, float approach_x, float approach_y, float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_SET_HOME_POSITION_LEN]; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_uint8_t(buf, 52, target_system); + _mav_put_float_array(buf, 24, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_HOME_POSITION, buf, MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_CRC); +#else + mavlink_set_home_position_t packet; + packet.latitude = latitude; + packet.longitude = longitude; + packet.altitude = altitude; + packet.x = x; + packet.y = y; + packet.z = z; + packet.approach_x = approach_x; + packet.approach_y = approach_y; + packet.approach_z = approach_z; + packet.target_system = target_system; + mav_array_memcpy(packet.q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_HOME_POSITION, (const char *)&packet, MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_CRC); +#endif +} + +/** + * @brief Send a set_home_position message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_home_position_send_struct(mavlink_channel_t chan, const mavlink_set_home_position_t* set_home_position) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_home_position_send(chan, set_home_position->target_system, set_home_position->latitude, set_home_position->longitude, set_home_position->altitude, set_home_position->x, set_home_position->y, set_home_position->z, set_home_position->q, set_home_position->approach_x, set_home_position->approach_y, set_home_position->approach_z); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_HOME_POSITION, (const char *)set_home_position, MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_CRC); +#endif +} + +#if MAVLINK_MSG_ID_SET_HOME_POSITION_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_set_home_position_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, int32_t latitude, int32_t longitude, int32_t altitude, float x, float y, float z, const float *q, float approach_x, float approach_y, float approach_z) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, latitude); + _mav_put_int32_t(buf, 4, longitude); + _mav_put_int32_t(buf, 8, altitude); + _mav_put_float(buf, 12, x); + _mav_put_float(buf, 16, y); + _mav_put_float(buf, 20, z); + _mav_put_float(buf, 40, approach_x); + _mav_put_float(buf, 44, approach_y); + _mav_put_float(buf, 48, approach_z); + _mav_put_uint8_t(buf, 52, target_system); + _mav_put_float_array(buf, 24, q, 4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_HOME_POSITION, buf, MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_CRC); +#else + mavlink_set_home_position_t *packet = (mavlink_set_home_position_t *)msgbuf; + packet->latitude = latitude; + packet->longitude = longitude; + packet->altitude = altitude; + packet->x = x; + packet->y = y; + packet->z = z; + packet->approach_x = approach_x; + packet->approach_y = approach_y; + packet->approach_z = approach_z; + packet->target_system = target_system; + mav_array_memcpy(packet->q, q, sizeof(float)*4); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_HOME_POSITION, (const char *)packet, MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN, MAVLINK_MSG_ID_SET_HOME_POSITION_CRC); +#endif +} +#endif + +#endif + +// MESSAGE SET_HOME_POSITION UNPACKING + + +/** + * @brief Get field target_system from set_home_position message + * + * @return System ID. + */ +static inline uint8_t mavlink_msg_set_home_position_get_target_system(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint8_t(msg, 52); +} + +/** + * @brief Get field latitude from set_home_position message + * + * @return Latitude (WGS84), in degrees * 1E7 + */ +static inline int32_t mavlink_msg_set_home_position_get_latitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 0); +} + +/** + * @brief Get field longitude from set_home_position message + * + * @return Longitude (WGS84, in degrees * 1E7 + */ +static inline int32_t mavlink_msg_set_home_position_get_longitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 4); +} + +/** + * @brief Get field altitude from set_home_position message + * + * @return Altitude (AMSL), in meters * 1000 (positive for up) + */ +static inline int32_t mavlink_msg_set_home_position_get_altitude(const mavlink_message_t* msg) +{ + return _MAV_RETURN_int32_t(msg, 8); +} + +/** + * @brief Get field x from set_home_position message + * + * @return Local X position of this position in the local coordinate frame + */ +static inline float mavlink_msg_set_home_position_get_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field y from set_home_position message + * + * @return Local Y position of this position in the local coordinate frame + */ +static inline float mavlink_msg_set_home_position_get_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field z from set_home_position message + * + * @return Local Z position of this position in the local coordinate frame + */ +static inline float mavlink_msg_set_home_position_get_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field q from set_home_position message + * + * @return World to surface normal and heading transformation of the takeoff position. Used to indicate the heading and slope of the ground + */ +static inline uint16_t mavlink_msg_set_home_position_get_q(const mavlink_message_t* msg, float *q) +{ + return _MAV_RETURN_float_array(msg, q, 4, 24); +} + +/** + * @brief Get field approach_x from set_home_position message + * + * @return Local X position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +static inline float mavlink_msg_set_home_position_get_approach_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 40); +} + +/** + * @brief Get field approach_y from set_home_position message + * + * @return Local Y position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +static inline float mavlink_msg_set_home_position_get_approach_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 44); +} + +/** + * @brief Get field approach_z from set_home_position message + * + * @return Local Z position of the end of the approach vector. Multicopters should set this position based on their takeoff path. Grass-landing fixed wing aircraft should set it the same way as multicopters. Runway-landing fixed wing aircraft should set it to the opposite direction of the takeoff, assuming the takeoff happened from the threshold / touchdown zone. + */ +static inline float mavlink_msg_set_home_position_get_approach_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 48); +} + +/** + * @brief Decode a set_home_position message into a struct + * + * @param msg The message to decode + * @param set_home_position C-struct to decode the message contents into + */ +static inline void mavlink_msg_set_home_position_decode(const mavlink_message_t* msg, mavlink_set_home_position_t* set_home_position) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_home_position->latitude = mavlink_msg_set_home_position_get_latitude(msg); + set_home_position->longitude = mavlink_msg_set_home_position_get_longitude(msg); + set_home_position->altitude = mavlink_msg_set_home_position_get_altitude(msg); + set_home_position->x = mavlink_msg_set_home_position_get_x(msg); + set_home_position->y = mavlink_msg_set_home_position_get_y(msg); + set_home_position->z = mavlink_msg_set_home_position_get_z(msg); + mavlink_msg_set_home_position_get_q(msg, set_home_position->q); + set_home_position->approach_x = mavlink_msg_set_home_position_get_approach_x(msg); + set_home_position->approach_y = mavlink_msg_set_home_position_get_approach_y(msg); + set_home_position->approach_z = mavlink_msg_set_home_position_get_approach_z(msg); + set_home_position->target_system = mavlink_msg_set_home_position_get_target_system(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_HOME_POSITION_LEN? msg->len : MAVLINK_MSG_ID_SET_HOME_POSITION_LEN; + memset(set_home_position, 0, MAVLINK_MSG_ID_SET_HOME_POSITION_LEN); + memcpy(set_home_position, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_set_mode.h b/vendor/libraries/mavlink/common/mavlink_msg_set_mode.h index 4b60a4120b..a4c6ef32bf 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_set_mode.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_set_mode.h @@ -1,31 +1,45 @@ +#pragma once // MESSAGE SET_MODE PACKING #define MAVLINK_MSG_ID_SET_MODE 11 -typedef struct __mavlink_set_mode_t -{ - uint32_t custom_mode; ///< The new autopilot-specific mode. This field can be ignored by an autopilot. - uint8_t target_system; ///< The system setting the mode - uint8_t base_mode; ///< The new base mode -} mavlink_set_mode_t; +MAVPACKED( +typedef struct __mavlink_set_mode_t { + uint32_t custom_mode; /*< The new autopilot-specific mode. This field can be ignored by an autopilot.*/ + uint8_t target_system; /*< The system setting the mode*/ + uint8_t base_mode; /*< The new base mode*/ +}) mavlink_set_mode_t; #define MAVLINK_MSG_ID_SET_MODE_LEN 6 +#define MAVLINK_MSG_ID_SET_MODE_MIN_LEN 6 #define MAVLINK_MSG_ID_11_LEN 6 +#define MAVLINK_MSG_ID_11_MIN_LEN 6 #define MAVLINK_MSG_ID_SET_MODE_CRC 89 #define MAVLINK_MSG_ID_11_CRC 89 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SET_MODE { \ - "SET_MODE", \ - 3, \ - { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_mode_t, custom_mode) }, \ + 11, \ + "SET_MODE", \ + 3, \ + { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_mode_t, custom_mode) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_set_mode_t, target_system) }, \ { "base_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_set_mode_t, base_mode) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SET_MODE { \ + "SET_MODE", \ + 3, \ + { { "custom_mode", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_mode_t, custom_mode) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_set_mode_t, target_system) }, \ + { "base_mode", NULL, MAVLINK_TYPE_UINT8_T, 0, 5, offsetof(mavlink_set_mode_t, base_mode) }, \ + } \ +} +#endif /** * @brief Pack a set_mode message @@ -39,30 +53,26 @@ typedef struct __mavlink_set_mode_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_mode_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_system, uint8_t base_mode, uint32_t custom_mode) + uint8_t target_system, uint8_t base_mode, uint32_t custom_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_MODE_LEN]; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, base_mode); + char buf[MAVLINK_MSG_ID_SET_MODE_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, base_mode); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_MODE_LEN); #else - mavlink_set_mode_t packet; - packet.custom_mode = custom_mode; - packet.target_system = target_system; - packet.base_mode = base_mode; + mavlink_set_mode_t packet; + packet.custom_mode = custom_mode; + packet.target_system = target_system; + packet.base_mode = base_mode; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_MODE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_MODE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_MODE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_MODE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_MODE_MIN_LEN, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); } /** @@ -77,31 +87,27 @@ static inline uint16_t mavlink_msg_set_mode_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_mode_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_system,uint8_t base_mode,uint32_t custom_mode) + mavlink_message_t* msg, + uint8_t target_system,uint8_t base_mode,uint32_t custom_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_MODE_LEN]; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, base_mode); + char buf[MAVLINK_MSG_ID_SET_MODE_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, base_mode); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_MODE_LEN); #else - mavlink_set_mode_t packet; - packet.custom_mode = custom_mode; - packet.target_system = target_system; - packet.base_mode = base_mode; + mavlink_set_mode_t packet; + packet.custom_mode = custom_mode; + packet.target_system = target_system; + packet.base_mode = base_mode; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_MODE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_MODE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_MODE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_MODE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_MODE_MIN_LEN, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); } /** @@ -114,7 +120,7 @@ static inline uint16_t mavlink_msg_set_mode_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_set_mode_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_mode_t* set_mode) { - return mavlink_msg_set_mode_pack(system_id, component_id, msg, set_mode->target_system, set_mode->base_mode, set_mode->custom_mode); + return mavlink_msg_set_mode_pack(system_id, component_id, msg, set_mode->target_system, set_mode->base_mode, set_mode->custom_mode); } /** @@ -128,7 +134,7 @@ static inline uint16_t mavlink_msg_set_mode_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_set_mode_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_mode_t* set_mode) { - return mavlink_msg_set_mode_pack_chan(system_id, component_id, chan, msg, set_mode->target_system, set_mode->base_mode, set_mode->custom_mode); + return mavlink_msg_set_mode_pack_chan(system_id, component_id, chan, msg, set_mode->target_system, set_mode->base_mode, set_mode->custom_mode); } /** @@ -144,27 +150,33 @@ static inline uint16_t mavlink_msg_set_mode_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_set_mode_send(mavlink_channel_t chan, uint8_t target_system, uint8_t base_mode, uint32_t custom_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_MODE_LEN]; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, base_mode); + char buf[MAVLINK_MSG_ID_SET_MODE_LEN]; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, base_mode); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, buf, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, buf, MAVLINK_MSG_ID_SET_MODE_MIN_LEN, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, buf, MAVLINK_MSG_ID_SET_MODE_LEN); + mavlink_set_mode_t packet; + packet.custom_mode = custom_mode; + packet.target_system = target_system; + packet.base_mode = base_mode; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, (const char *)&packet, MAVLINK_MSG_ID_SET_MODE_MIN_LEN, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); #endif -#else - mavlink_set_mode_t packet; - packet.custom_mode = custom_mode; - packet.target_system = target_system; - packet.base_mode = base_mode; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, (const char *)&packet, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); +/** + * @brief Send a set_mode message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_mode_send_struct(mavlink_channel_t chan, const mavlink_set_mode_t* set_mode) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_mode_send(chan, set_mode->target_system, set_mode->base_mode, set_mode->custom_mode); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, (const char *)&packet, MAVLINK_MSG_ID_SET_MODE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, (const char *)set_mode, MAVLINK_MSG_ID_SET_MODE_MIN_LEN, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); #endif } @@ -179,27 +191,19 @@ static inline void mavlink_msg_set_mode_send(mavlink_channel_t chan, uint8_t tar static inline void mavlink_msg_set_mode_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_system, uint8_t base_mode, uint32_t custom_mode) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, custom_mode); - _mav_put_uint8_t(buf, 4, target_system); - _mav_put_uint8_t(buf, 5, base_mode); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, custom_mode); + _mav_put_uint8_t(buf, 4, target_system); + _mav_put_uint8_t(buf, 5, base_mode); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, buf, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, buf, MAVLINK_MSG_ID_SET_MODE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, buf, MAVLINK_MSG_ID_SET_MODE_MIN_LEN, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); #else - mavlink_set_mode_t *packet = (mavlink_set_mode_t *)msgbuf; - packet->custom_mode = custom_mode; - packet->target_system = target_system; - packet->base_mode = base_mode; + mavlink_set_mode_t *packet = (mavlink_set_mode_t *)msgbuf; + packet->custom_mode = custom_mode; + packet->target_system = target_system; + packet->base_mode = base_mode; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, (const char *)packet, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, (const char *)packet, MAVLINK_MSG_ID_SET_MODE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_MODE, (const char *)packet, MAVLINK_MSG_ID_SET_MODE_MIN_LEN, MAVLINK_MSG_ID_SET_MODE_LEN, MAVLINK_MSG_ID_SET_MODE_CRC); #endif } #endif @@ -216,7 +220,7 @@ static inline void mavlink_msg_set_mode_send_buf(mavlink_message_t *msgbuf, mavl */ static inline uint8_t mavlink_msg_set_mode_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -226,7 +230,7 @@ static inline uint8_t mavlink_msg_set_mode_get_target_system(const mavlink_messa */ static inline uint8_t mavlink_msg_set_mode_get_base_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 5); + return _MAV_RETURN_uint8_t(msg, 5); } /** @@ -236,7 +240,7 @@ static inline uint8_t mavlink_msg_set_mode_get_base_mode(const mavlink_message_t */ static inline uint32_t mavlink_msg_set_mode_get_custom_mode(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -247,11 +251,13 @@ static inline uint32_t mavlink_msg_set_mode_get_custom_mode(const mavlink_messag */ static inline void mavlink_msg_set_mode_decode(const mavlink_message_t* msg, mavlink_set_mode_t* set_mode) { -#if MAVLINK_NEED_BYTE_SWAP - set_mode->custom_mode = mavlink_msg_set_mode_get_custom_mode(msg); - set_mode->target_system = mavlink_msg_set_mode_get_target_system(msg); - set_mode->base_mode = mavlink_msg_set_mode_get_base_mode(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_mode->custom_mode = mavlink_msg_set_mode_get_custom_mode(msg); + set_mode->target_system = mavlink_msg_set_mode_get_target_system(msg); + set_mode->base_mode = mavlink_msg_set_mode_get_base_mode(msg); #else - memcpy(set_mode, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SET_MODE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_MODE_LEN? msg->len : MAVLINK_MSG_ID_SET_MODE_LEN; + memset(set_mode, 0, MAVLINK_MSG_ID_SET_MODE_LEN); + memcpy(set_mode, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_global_int.h b/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_global_int.h index e528d73c2e..ec0c9c1a88 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_global_int.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_global_int.h @@ -1,39 +1,44 @@ +#pragma once // MESSAGE SET_POSITION_TARGET_GLOBAL_INT PACKING #define MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT 86 -typedef struct __mavlink_set_position_target_global_int_t -{ - uint32_t time_boot_ms; ///< Timestamp in milliseconds since system boot. The rationale for the timestamp in the setpoint is to allow the system to compensate for the transport delay of the setpoint. This allows the system to compensate processing latency. - int32_t lat_int; ///< X Position in WGS84 frame in 1e7 * meters - int32_t lon_int; ///< Y Position in WGS84 frame in 1e7 * meters - float alt; ///< Altitude in meters in AMSL altitude, not WGS84 if absolute or relative, above terrain if GLOBAL_TERRAIN_ALT_INT - float vx; ///< X velocity in NED frame in meter / s - float vy; ///< Y velocity in NED frame in meter / s - float vz; ///< Z velocity in NED frame in meter / s - float afx; ///< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afy; ///< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afz; ///< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float yaw; ///< yaw setpoint in rad - float yaw_rate; ///< yaw rate setpoint in rad/s - uint16_t type_mask; ///< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t coordinate_frame; ///< Valid options are: MAV_FRAME_GLOBAL_INT = 5, MAV_FRAME_GLOBAL_RELATIVE_ALT_INT = 6, MAV_FRAME_GLOBAL_TERRAIN_ALT_INT = 11 -} mavlink_set_position_target_global_int_t; +MAVPACKED( +typedef struct __mavlink_set_position_target_global_int_t { + uint32_t time_boot_ms; /*< Timestamp in milliseconds since system boot. The rationale for the timestamp in the setpoint is to allow the system to compensate for the transport delay of the setpoint. This allows the system to compensate processing latency.*/ + int32_t lat_int; /*< X Position in WGS84 frame in 1e7 * meters*/ + int32_t lon_int; /*< Y Position in WGS84 frame in 1e7 * meters*/ + float alt; /*< Altitude in meters in AMSL altitude, not WGS84 if absolute or relative, above terrain if GLOBAL_TERRAIN_ALT_INT*/ + float vx; /*< X velocity in NED frame in meter / s*/ + float vy; /*< Y velocity in NED frame in meter / s*/ + float vz; /*< Z velocity in NED frame in meter / s*/ + float afx; /*< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afy; /*< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afz; /*< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float yaw; /*< yaw setpoint in rad*/ + float yaw_rate; /*< yaw rate setpoint in rad/s*/ + uint16_t type_mask; /*< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t coordinate_frame; /*< Valid options are: MAV_FRAME_GLOBAL_INT = 5, MAV_FRAME_GLOBAL_RELATIVE_ALT_INT = 6, MAV_FRAME_GLOBAL_TERRAIN_ALT_INT = 11*/ +}) mavlink_set_position_target_global_int_t; #define MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN 53 +#define MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN 53 #define MAVLINK_MSG_ID_86_LEN 53 +#define MAVLINK_MSG_ID_86_MIN_LEN 53 #define MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC 5 #define MAVLINK_MSG_ID_86_CRC 5 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_GLOBAL_INT { \ - "SET_POSITION_TARGET_GLOBAL_INT", \ - 16, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_position_target_global_int_t, time_boot_ms) }, \ + 86, \ + "SET_POSITION_TARGET_GLOBAL_INT", \ + 16, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_position_target_global_int_t, time_boot_ms) }, \ { "lat_int", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_set_position_target_global_int_t, lat_int) }, \ { "lon_int", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_set_position_target_global_int_t, lon_int) }, \ { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_set_position_target_global_int_t, alt) }, \ @@ -51,7 +56,29 @@ typedef struct __mavlink_set_position_target_global_int_t { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 52, offsetof(mavlink_set_position_target_global_int_t, coordinate_frame) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_GLOBAL_INT { \ + "SET_POSITION_TARGET_GLOBAL_INT", \ + 16, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_position_target_global_int_t, time_boot_ms) }, \ + { "lat_int", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_set_position_target_global_int_t, lat_int) }, \ + { "lon_int", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_set_position_target_global_int_t, lon_int) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_set_position_target_global_int_t, alt) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_set_position_target_global_int_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_set_position_target_global_int_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_set_position_target_global_int_t, vz) }, \ + { "afx", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_set_position_target_global_int_t, afx) }, \ + { "afy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_set_position_target_global_int_t, afy) }, \ + { "afz", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_set_position_target_global_int_t, afz) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_set_position_target_global_int_t, yaw) }, \ + { "yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_set_position_target_global_int_t, yaw_rate) }, \ + { "type_mask", NULL, MAVLINK_TYPE_UINT16_T, 0, 48, offsetof(mavlink_set_position_target_global_int_t, type_mask) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 50, offsetof(mavlink_set_position_target_global_int_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 51, offsetof(mavlink_set_position_target_global_int_t, target_component) }, \ + { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 52, offsetof(mavlink_set_position_target_global_int_t, coordinate_frame) }, \ + } \ +} +#endif /** * @brief Pack a set_position_target_global_int message @@ -78,56 +105,52 @@ typedef struct __mavlink_set_position_target_global_int_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_position_target_global_int_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) + uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); + char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); #else - mavlink_set_position_target_global_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat_int = lat_int; - packet.lon_int = lon_int; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.target_system = target_system; - packet.target_component = target_component; - packet.coordinate_frame = coordinate_frame; + mavlink_set_position_target_global_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat_int = lat_int; + packet.lon_int = lon_int; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.target_system = target_system; + packet.target_component = target_component; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); } /** @@ -155,57 +178,53 @@ static inline uint16_t mavlink_msg_set_position_target_global_int_pack(uint8_t s * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_position_target_global_int_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t target_system,uint8_t target_component,uint8_t coordinate_frame,uint16_t type_mask,int32_t lat_int,int32_t lon_int,float alt,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t target_system,uint8_t target_component,uint8_t coordinate_frame,uint16_t type_mask,int32_t lat_int,int32_t lon_int,float alt,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); + char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); #else - mavlink_set_position_target_global_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat_int = lat_int; - packet.lon_int = lon_int; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.target_system = target_system; - packet.target_component = target_component; - packet.coordinate_frame = coordinate_frame; + mavlink_set_position_target_global_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat_int = lat_int; + packet.lon_int = lon_int; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.target_system = target_system; + packet.target_component = target_component; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); } /** @@ -218,7 +237,7 @@ static inline uint16_t mavlink_msg_set_position_target_global_int_pack_chan(uint */ static inline uint16_t mavlink_msg_set_position_target_global_int_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_position_target_global_int_t* set_position_target_global_int) { - return mavlink_msg_set_position_target_global_int_pack(system_id, component_id, msg, set_position_target_global_int->time_boot_ms, set_position_target_global_int->target_system, set_position_target_global_int->target_component, set_position_target_global_int->coordinate_frame, set_position_target_global_int->type_mask, set_position_target_global_int->lat_int, set_position_target_global_int->lon_int, set_position_target_global_int->alt, set_position_target_global_int->vx, set_position_target_global_int->vy, set_position_target_global_int->vz, set_position_target_global_int->afx, set_position_target_global_int->afy, set_position_target_global_int->afz, set_position_target_global_int->yaw, set_position_target_global_int->yaw_rate); + return mavlink_msg_set_position_target_global_int_pack(system_id, component_id, msg, set_position_target_global_int->time_boot_ms, set_position_target_global_int->target_system, set_position_target_global_int->target_component, set_position_target_global_int->coordinate_frame, set_position_target_global_int->type_mask, set_position_target_global_int->lat_int, set_position_target_global_int->lon_int, set_position_target_global_int->alt, set_position_target_global_int->vx, set_position_target_global_int->vy, set_position_target_global_int->vz, set_position_target_global_int->afx, set_position_target_global_int->afy, set_position_target_global_int->afz, set_position_target_global_int->yaw, set_position_target_global_int->yaw_rate); } /** @@ -232,7 +251,7 @@ static inline uint16_t mavlink_msg_set_position_target_global_int_encode(uint8_t */ static inline uint16_t mavlink_msg_set_position_target_global_int_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_position_target_global_int_t* set_position_target_global_int) { - return mavlink_msg_set_position_target_global_int_pack_chan(system_id, component_id, chan, msg, set_position_target_global_int->time_boot_ms, set_position_target_global_int->target_system, set_position_target_global_int->target_component, set_position_target_global_int->coordinate_frame, set_position_target_global_int->type_mask, set_position_target_global_int->lat_int, set_position_target_global_int->lon_int, set_position_target_global_int->alt, set_position_target_global_int->vx, set_position_target_global_int->vy, set_position_target_global_int->vz, set_position_target_global_int->afx, set_position_target_global_int->afy, set_position_target_global_int->afz, set_position_target_global_int->yaw, set_position_target_global_int->yaw_rate); + return mavlink_msg_set_position_target_global_int_pack_chan(system_id, component_id, chan, msg, set_position_target_global_int->time_boot_ms, set_position_target_global_int->target_system, set_position_target_global_int->target_component, set_position_target_global_int->coordinate_frame, set_position_target_global_int->type_mask, set_position_target_global_int->lat_int, set_position_target_global_int->lon_int, set_position_target_global_int->alt, set_position_target_global_int->vx, set_position_target_global_int->vy, set_position_target_global_int->vz, set_position_target_global_int->afx, set_position_target_global_int->afy, set_position_target_global_int->afz, set_position_target_global_int->yaw, set_position_target_global_int->yaw_rate); } /** @@ -261,53 +280,59 @@ static inline uint16_t mavlink_msg_set_position_target_global_int_encode_chan(ui static inline void mavlink_msg_set_position_target_global_int_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); + char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); + mavlink_set_position_target_global_int_t packet; + packet.time_boot_ms = time_boot_ms; + packet.lat_int = lat_int; + packet.lon_int = lon_int; + packet.alt = alt; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.target_system = target_system; + packet.target_component = target_component; + packet.coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, (const char *)&packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); #endif +} + +/** + * @brief Send a set_position_target_global_int message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_position_target_global_int_send_struct(mavlink_channel_t chan, const mavlink_set_position_target_global_int_t* set_position_target_global_int) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_position_target_global_int_send(chan, set_position_target_global_int->time_boot_ms, set_position_target_global_int->target_system, set_position_target_global_int->target_component, set_position_target_global_int->coordinate_frame, set_position_target_global_int->type_mask, set_position_target_global_int->lat_int, set_position_target_global_int->lon_int, set_position_target_global_int->alt, set_position_target_global_int->vx, set_position_target_global_int->vy, set_position_target_global_int->vz, set_position_target_global_int->afx, set_position_target_global_int->afy, set_position_target_global_int->afz, set_position_target_global_int->yaw, set_position_target_global_int->yaw_rate); #else - mavlink_set_position_target_global_int_t packet; - packet.time_boot_ms = time_boot_ms; - packet.lat_int = lat_int; - packet.lon_int = lon_int; - packet.alt = alt; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.target_system = target_system; - packet.target_component = target_component; - packet.coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, (const char *)&packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, (const char *)&packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, (const char *)set_position_target_global_int, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); #endif } @@ -322,53 +347,45 @@ static inline void mavlink_msg_set_position_target_global_int_send(mavlink_chann static inline void mavlink_msg_set_position_target_global_int_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, int32_t lat_int, int32_t lon_int, float alt, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_int32_t(buf, 4, lat_int); - _mav_put_int32_t(buf, 8, lon_int); - _mav_put_float(buf, 12, alt); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_int32_t(buf, 4, lat_int); + _mav_put_int32_t(buf, 8, lon_int); + _mav_put_float(buf, 12, alt); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); -#endif -#else - mavlink_set_position_target_global_int_t *packet = (mavlink_set_position_target_global_int_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->lat_int = lat_int; - packet->lon_int = lon_int; - packet->alt = alt; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->afx = afx; - packet->afy = afy; - packet->afz = afz; - packet->yaw = yaw; - packet->yaw_rate = yaw_rate; - packet->type_mask = type_mask; - packet->target_system = target_system; - packet->target_component = target_component; - packet->coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, (const char *)packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, (const char *)packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); -#endif + mavlink_set_position_target_global_int_t *packet = (mavlink_set_position_target_global_int_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->lat_int = lat_int; + packet->lon_int = lon_int; + packet->alt = alt; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->afx = afx; + packet->afy = afy; + packet->afz = afz; + packet->yaw = yaw; + packet->yaw_rate = yaw_rate; + packet->type_mask = type_mask; + packet->target_system = target_system; + packet->target_component = target_component; + packet->coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT, (const char *)packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_CRC); #endif } #endif @@ -385,7 +402,7 @@ static inline void mavlink_msg_set_position_target_global_int_send_buf(mavlink_m */ static inline uint32_t mavlink_msg_set_position_target_global_int_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -395,7 +412,7 @@ static inline uint32_t mavlink_msg_set_position_target_global_int_get_time_boot_ */ static inline uint8_t mavlink_msg_set_position_target_global_int_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 50); + return _MAV_RETURN_uint8_t(msg, 50); } /** @@ -405,7 +422,7 @@ static inline uint8_t mavlink_msg_set_position_target_global_int_get_target_syst */ static inline uint8_t mavlink_msg_set_position_target_global_int_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 51); + return _MAV_RETURN_uint8_t(msg, 51); } /** @@ -415,7 +432,7 @@ static inline uint8_t mavlink_msg_set_position_target_global_int_get_target_comp */ static inline uint8_t mavlink_msg_set_position_target_global_int_get_coordinate_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 52); + return _MAV_RETURN_uint8_t(msg, 52); } /** @@ -425,7 +442,7 @@ static inline uint8_t mavlink_msg_set_position_target_global_int_get_coordinate_ */ static inline uint16_t mavlink_msg_set_position_target_global_int_get_type_mask(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 48); + return _MAV_RETURN_uint16_t(msg, 48); } /** @@ -435,7 +452,7 @@ static inline uint16_t mavlink_msg_set_position_target_global_int_get_type_mask( */ static inline int32_t mavlink_msg_set_position_target_global_int_get_lat_int(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -445,7 +462,7 @@ static inline int32_t mavlink_msg_set_position_target_global_int_get_lat_int(con */ static inline int32_t mavlink_msg_set_position_target_global_int_get_lon_int(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -455,7 +472,7 @@ static inline int32_t mavlink_msg_set_position_target_global_int_get_lon_int(con */ static inline float mavlink_msg_set_position_target_global_int_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -465,7 +482,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_alt(const mav */ static inline float mavlink_msg_set_position_target_global_int_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -475,7 +492,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_vx(const mavl */ static inline float mavlink_msg_set_position_target_global_int_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -485,7 +502,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_vy(const mavl */ static inline float mavlink_msg_set_position_target_global_int_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -495,7 +512,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_vz(const mavl */ static inline float mavlink_msg_set_position_target_global_int_get_afx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -505,7 +522,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_afx(const mav */ static inline float mavlink_msg_set_position_target_global_int_get_afy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -515,7 +532,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_afy(const mav */ static inline float mavlink_msg_set_position_target_global_int_get_afz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -525,7 +542,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_afz(const mav */ static inline float mavlink_msg_set_position_target_global_int_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -535,7 +552,7 @@ static inline float mavlink_msg_set_position_target_global_int_get_yaw(const mav */ static inline float mavlink_msg_set_position_target_global_int_get_yaw_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -546,24 +563,26 @@ static inline float mavlink_msg_set_position_target_global_int_get_yaw_rate(cons */ static inline void mavlink_msg_set_position_target_global_int_decode(const mavlink_message_t* msg, mavlink_set_position_target_global_int_t* set_position_target_global_int) { -#if MAVLINK_NEED_BYTE_SWAP - set_position_target_global_int->time_boot_ms = mavlink_msg_set_position_target_global_int_get_time_boot_ms(msg); - set_position_target_global_int->lat_int = mavlink_msg_set_position_target_global_int_get_lat_int(msg); - set_position_target_global_int->lon_int = mavlink_msg_set_position_target_global_int_get_lon_int(msg); - set_position_target_global_int->alt = mavlink_msg_set_position_target_global_int_get_alt(msg); - set_position_target_global_int->vx = mavlink_msg_set_position_target_global_int_get_vx(msg); - set_position_target_global_int->vy = mavlink_msg_set_position_target_global_int_get_vy(msg); - set_position_target_global_int->vz = mavlink_msg_set_position_target_global_int_get_vz(msg); - set_position_target_global_int->afx = mavlink_msg_set_position_target_global_int_get_afx(msg); - set_position_target_global_int->afy = mavlink_msg_set_position_target_global_int_get_afy(msg); - set_position_target_global_int->afz = mavlink_msg_set_position_target_global_int_get_afz(msg); - set_position_target_global_int->yaw = mavlink_msg_set_position_target_global_int_get_yaw(msg); - set_position_target_global_int->yaw_rate = mavlink_msg_set_position_target_global_int_get_yaw_rate(msg); - set_position_target_global_int->type_mask = mavlink_msg_set_position_target_global_int_get_type_mask(msg); - set_position_target_global_int->target_system = mavlink_msg_set_position_target_global_int_get_target_system(msg); - set_position_target_global_int->target_component = mavlink_msg_set_position_target_global_int_get_target_component(msg); - set_position_target_global_int->coordinate_frame = mavlink_msg_set_position_target_global_int_get_coordinate_frame(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_position_target_global_int->time_boot_ms = mavlink_msg_set_position_target_global_int_get_time_boot_ms(msg); + set_position_target_global_int->lat_int = mavlink_msg_set_position_target_global_int_get_lat_int(msg); + set_position_target_global_int->lon_int = mavlink_msg_set_position_target_global_int_get_lon_int(msg); + set_position_target_global_int->alt = mavlink_msg_set_position_target_global_int_get_alt(msg); + set_position_target_global_int->vx = mavlink_msg_set_position_target_global_int_get_vx(msg); + set_position_target_global_int->vy = mavlink_msg_set_position_target_global_int_get_vy(msg); + set_position_target_global_int->vz = mavlink_msg_set_position_target_global_int_get_vz(msg); + set_position_target_global_int->afx = mavlink_msg_set_position_target_global_int_get_afx(msg); + set_position_target_global_int->afy = mavlink_msg_set_position_target_global_int_get_afy(msg); + set_position_target_global_int->afz = mavlink_msg_set_position_target_global_int_get_afz(msg); + set_position_target_global_int->yaw = mavlink_msg_set_position_target_global_int_get_yaw(msg); + set_position_target_global_int->yaw_rate = mavlink_msg_set_position_target_global_int_get_yaw_rate(msg); + set_position_target_global_int->type_mask = mavlink_msg_set_position_target_global_int_get_type_mask(msg); + set_position_target_global_int->target_system = mavlink_msg_set_position_target_global_int_get_target_system(msg); + set_position_target_global_int->target_component = mavlink_msg_set_position_target_global_int_get_target_component(msg); + set_position_target_global_int->coordinate_frame = mavlink_msg_set_position_target_global_int_get_coordinate_frame(msg); #else - memcpy(set_position_target_global_int, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN? msg->len : MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN; + memset(set_position_target_global_int, 0, MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_LEN); + memcpy(set_position_target_global_int, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_local_ned.h b/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_local_ned.h index 8fcc3cbc14..af4e8d68db 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_local_ned.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_set_position_target_local_ned.h @@ -1,39 +1,44 @@ +#pragma once // MESSAGE SET_POSITION_TARGET_LOCAL_NED PACKING #define MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED 84 -typedef struct __mavlink_set_position_target_local_ned_t -{ - uint32_t time_boot_ms; ///< Timestamp in milliseconds since system boot - float x; ///< X Position in NED frame in meters - float y; ///< Y Position in NED frame in meters - float z; ///< Z Position in NED frame in meters (note, altitude is negative in NED) - float vx; ///< X velocity in NED frame in meter / s - float vy; ///< Y velocity in NED frame in meter / s - float vz; ///< Z velocity in NED frame in meter / s - float afx; ///< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afy; ///< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float afz; ///< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N - float yaw; ///< yaw setpoint in rad - float yaw_rate; ///< yaw rate setpoint in rad/s - uint16_t type_mask; ///< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate - uint8_t target_system; ///< System ID - uint8_t target_component; ///< Component ID - uint8_t coordinate_frame; ///< Valid options are: MAV_FRAME_LOCAL_NED = 1, MAV_FRAME_LOCAL_OFFSET_NED = 7, MAV_FRAME_BODY_NED = 8, MAV_FRAME_BODY_OFFSET_NED = 9 -} mavlink_set_position_target_local_ned_t; +MAVPACKED( +typedef struct __mavlink_set_position_target_local_ned_t { + uint32_t time_boot_ms; /*< Timestamp in milliseconds since system boot*/ + float x; /*< X Position in NED frame in meters*/ + float y; /*< Y Position in NED frame in meters*/ + float z; /*< Z Position in NED frame in meters (note, altitude is negative in NED)*/ + float vx; /*< X velocity in NED frame in meter / s*/ + float vy; /*< Y velocity in NED frame in meter / s*/ + float vz; /*< Z velocity in NED frame in meter / s*/ + float afx; /*< X acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afy; /*< Y acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float afz; /*< Z acceleration or force (if bit 10 of type_mask is set) in NED frame in meter / s^2 or N*/ + float yaw; /*< yaw setpoint in rad*/ + float yaw_rate; /*< yaw rate setpoint in rad/s*/ + uint16_t type_mask; /*< Bitmask to indicate which dimensions should be ignored by the vehicle: a value of 0b0000000000000000 or 0b0000001000000000 indicates that none of the setpoint dimensions should be ignored. If bit 10 is set the floats afx afy afz should be interpreted as force instead of acceleration. Mapping: bit 1: x, bit 2: y, bit 3: z, bit 4: vx, bit 5: vy, bit 6: vz, bit 7: ax, bit 8: ay, bit 9: az, bit 10: is force setpoint, bit 11: yaw, bit 12: yaw rate*/ + uint8_t target_system; /*< System ID*/ + uint8_t target_component; /*< Component ID*/ + uint8_t coordinate_frame; /*< Valid options are: MAV_FRAME_LOCAL_NED = 1, MAV_FRAME_LOCAL_OFFSET_NED = 7, MAV_FRAME_BODY_NED = 8, MAV_FRAME_BODY_OFFSET_NED = 9*/ +}) mavlink_set_position_target_local_ned_t; #define MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN 53 +#define MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN 53 #define MAVLINK_MSG_ID_84_LEN 53 +#define MAVLINK_MSG_ID_84_MIN_LEN 53 #define MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC 143 #define MAVLINK_MSG_ID_84_CRC 143 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_LOCAL_NED { \ - "SET_POSITION_TARGET_LOCAL_NED", \ - 16, \ - { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_position_target_local_ned_t, time_boot_ms) }, \ + 84, \ + "SET_POSITION_TARGET_LOCAL_NED", \ + 16, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_position_target_local_ned_t, time_boot_ms) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_set_position_target_local_ned_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_set_position_target_local_ned_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_set_position_target_local_ned_t, z) }, \ @@ -51,7 +56,29 @@ typedef struct __mavlink_set_position_target_local_ned_t { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 52, offsetof(mavlink_set_position_target_local_ned_t, coordinate_frame) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SET_POSITION_TARGET_LOCAL_NED { \ + "SET_POSITION_TARGET_LOCAL_NED", \ + 16, \ + { { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_set_position_target_local_ned_t, time_boot_ms) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_set_position_target_local_ned_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_set_position_target_local_ned_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_set_position_target_local_ned_t, z) }, \ + { "vx", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_set_position_target_local_ned_t, vx) }, \ + { "vy", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_set_position_target_local_ned_t, vy) }, \ + { "vz", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_set_position_target_local_ned_t, vz) }, \ + { "afx", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_set_position_target_local_ned_t, afx) }, \ + { "afy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_set_position_target_local_ned_t, afy) }, \ + { "afz", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_set_position_target_local_ned_t, afz) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_set_position_target_local_ned_t, yaw) }, \ + { "yaw_rate", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_set_position_target_local_ned_t, yaw_rate) }, \ + { "type_mask", NULL, MAVLINK_TYPE_UINT16_T, 0, 48, offsetof(mavlink_set_position_target_local_ned_t, type_mask) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 50, offsetof(mavlink_set_position_target_local_ned_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 51, offsetof(mavlink_set_position_target_local_ned_t, target_component) }, \ + { "coordinate_frame", NULL, MAVLINK_TYPE_UINT8_T, 0, 52, offsetof(mavlink_set_position_target_local_ned_t, coordinate_frame) }, \ + } \ +} +#endif /** * @brief Pack a set_position_target_local_ned message @@ -78,56 +105,52 @@ typedef struct __mavlink_set_position_target_local_ned_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_position_target_local_ned_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) + uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); + char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); #else - mavlink_set_position_target_local_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.target_system = target_system; - packet.target_component = target_component; - packet.coordinate_frame = coordinate_frame; + mavlink_set_position_target_local_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.target_system = target_system; + packet.target_component = target_component; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); } /** @@ -155,57 +178,53 @@ static inline uint16_t mavlink_msg_set_position_target_local_ned_pack(uint8_t sy * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_set_position_target_local_ned_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t time_boot_ms,uint8_t target_system,uint8_t target_component,uint8_t coordinate_frame,uint16_t type_mask,float x,float y,float z,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) + mavlink_message_t* msg, + uint32_t time_boot_ms,uint8_t target_system,uint8_t target_component,uint8_t coordinate_frame,uint16_t type_mask,float x,float y,float z,float vx,float vy,float vz,float afx,float afy,float afz,float yaw,float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); + char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); #else - mavlink_set_position_target_local_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.target_system = target_system; - packet.target_component = target_component; - packet.coordinate_frame = coordinate_frame; + mavlink_set_position_target_local_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.target_system = target_system; + packet.target_component = target_component; + packet.coordinate_frame = coordinate_frame; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); } /** @@ -218,7 +237,7 @@ static inline uint16_t mavlink_msg_set_position_target_local_ned_pack_chan(uint8 */ static inline uint16_t mavlink_msg_set_position_target_local_ned_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_set_position_target_local_ned_t* set_position_target_local_ned) { - return mavlink_msg_set_position_target_local_ned_pack(system_id, component_id, msg, set_position_target_local_ned->time_boot_ms, set_position_target_local_ned->target_system, set_position_target_local_ned->target_component, set_position_target_local_ned->coordinate_frame, set_position_target_local_ned->type_mask, set_position_target_local_ned->x, set_position_target_local_ned->y, set_position_target_local_ned->z, set_position_target_local_ned->vx, set_position_target_local_ned->vy, set_position_target_local_ned->vz, set_position_target_local_ned->afx, set_position_target_local_ned->afy, set_position_target_local_ned->afz, set_position_target_local_ned->yaw, set_position_target_local_ned->yaw_rate); + return mavlink_msg_set_position_target_local_ned_pack(system_id, component_id, msg, set_position_target_local_ned->time_boot_ms, set_position_target_local_ned->target_system, set_position_target_local_ned->target_component, set_position_target_local_ned->coordinate_frame, set_position_target_local_ned->type_mask, set_position_target_local_ned->x, set_position_target_local_ned->y, set_position_target_local_ned->z, set_position_target_local_ned->vx, set_position_target_local_ned->vy, set_position_target_local_ned->vz, set_position_target_local_ned->afx, set_position_target_local_ned->afy, set_position_target_local_ned->afz, set_position_target_local_ned->yaw, set_position_target_local_ned->yaw_rate); } /** @@ -232,7 +251,7 @@ static inline uint16_t mavlink_msg_set_position_target_local_ned_encode(uint8_t */ static inline uint16_t mavlink_msg_set_position_target_local_ned_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_set_position_target_local_ned_t* set_position_target_local_ned) { - return mavlink_msg_set_position_target_local_ned_pack_chan(system_id, component_id, chan, msg, set_position_target_local_ned->time_boot_ms, set_position_target_local_ned->target_system, set_position_target_local_ned->target_component, set_position_target_local_ned->coordinate_frame, set_position_target_local_ned->type_mask, set_position_target_local_ned->x, set_position_target_local_ned->y, set_position_target_local_ned->z, set_position_target_local_ned->vx, set_position_target_local_ned->vy, set_position_target_local_ned->vz, set_position_target_local_ned->afx, set_position_target_local_ned->afy, set_position_target_local_ned->afz, set_position_target_local_ned->yaw, set_position_target_local_ned->yaw_rate); + return mavlink_msg_set_position_target_local_ned_pack_chan(system_id, component_id, chan, msg, set_position_target_local_ned->time_boot_ms, set_position_target_local_ned->target_system, set_position_target_local_ned->target_component, set_position_target_local_ned->coordinate_frame, set_position_target_local_ned->type_mask, set_position_target_local_ned->x, set_position_target_local_ned->y, set_position_target_local_ned->z, set_position_target_local_ned->vx, set_position_target_local_ned->vy, set_position_target_local_ned->vz, set_position_target_local_ned->afx, set_position_target_local_ned->afy, set_position_target_local_ned->afz, set_position_target_local_ned->yaw, set_position_target_local_ned->yaw_rate); } /** @@ -261,53 +280,59 @@ static inline uint16_t mavlink_msg_set_position_target_local_ned_encode_chan(uin static inline void mavlink_msg_set_position_target_local_ned_send(mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN]; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); + char buf[MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN]; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); + mavlink_set_position_target_local_ned_t packet; + packet.time_boot_ms = time_boot_ms; + packet.x = x; + packet.y = y; + packet.z = z; + packet.vx = vx; + packet.vy = vy; + packet.vz = vz; + packet.afx = afx; + packet.afy = afy; + packet.afz = afz; + packet.yaw = yaw; + packet.yaw_rate = yaw_rate; + packet.type_mask = type_mask; + packet.target_system = target_system; + packet.target_component = target_component; + packet.coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, (const char *)&packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); #endif +} + +/** + * @brief Send a set_position_target_local_ned message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_set_position_target_local_ned_send_struct(mavlink_channel_t chan, const mavlink_set_position_target_local_ned_t* set_position_target_local_ned) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_set_position_target_local_ned_send(chan, set_position_target_local_ned->time_boot_ms, set_position_target_local_ned->target_system, set_position_target_local_ned->target_component, set_position_target_local_ned->coordinate_frame, set_position_target_local_ned->type_mask, set_position_target_local_ned->x, set_position_target_local_ned->y, set_position_target_local_ned->z, set_position_target_local_ned->vx, set_position_target_local_ned->vy, set_position_target_local_ned->vz, set_position_target_local_ned->afx, set_position_target_local_ned->afy, set_position_target_local_ned->afz, set_position_target_local_ned->yaw, set_position_target_local_ned->yaw_rate); #else - mavlink_set_position_target_local_ned_t packet; - packet.time_boot_ms = time_boot_ms; - packet.x = x; - packet.y = y; - packet.z = z; - packet.vx = vx; - packet.vy = vy; - packet.vz = vz; - packet.afx = afx; - packet.afy = afy; - packet.afz = afz; - packet.yaw = yaw; - packet.yaw_rate = yaw_rate; - packet.type_mask = type_mask; - packet.target_system = target_system; - packet.target_component = target_component; - packet.coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, (const char *)&packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, (const char *)&packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, (const char *)set_position_target_local_ned, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); #endif } @@ -322,53 +347,45 @@ static inline void mavlink_msg_set_position_target_local_ned_send(mavlink_channe static inline void mavlink_msg_set_position_target_local_ned_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t time_boot_ms, uint8_t target_system, uint8_t target_component, uint8_t coordinate_frame, uint16_t type_mask, float x, float y, float z, float vx, float vy, float vz, float afx, float afy, float afz, float yaw, float yaw_rate) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, time_boot_ms); - _mav_put_float(buf, 4, x); - _mav_put_float(buf, 8, y); - _mav_put_float(buf, 12, z); - _mav_put_float(buf, 16, vx); - _mav_put_float(buf, 20, vy); - _mav_put_float(buf, 24, vz); - _mav_put_float(buf, 28, afx); - _mav_put_float(buf, 32, afy); - _mav_put_float(buf, 36, afz); - _mav_put_float(buf, 40, yaw); - _mav_put_float(buf, 44, yaw_rate); - _mav_put_uint16_t(buf, 48, type_mask); - _mav_put_uint8_t(buf, 50, target_system); - _mav_put_uint8_t(buf, 51, target_component); - _mav_put_uint8_t(buf, 52, coordinate_frame); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, time_boot_ms); + _mav_put_float(buf, 4, x); + _mav_put_float(buf, 8, y); + _mav_put_float(buf, 12, z); + _mav_put_float(buf, 16, vx); + _mav_put_float(buf, 20, vy); + _mav_put_float(buf, 24, vz); + _mav_put_float(buf, 28, afx); + _mav_put_float(buf, 32, afy); + _mav_put_float(buf, 36, afz); + _mav_put_float(buf, 40, yaw); + _mav_put_float(buf, 44, yaw_rate); + _mav_put_uint16_t(buf, 48, type_mask); + _mav_put_uint8_t(buf, 50, target_system); + _mav_put_uint8_t(buf, 51, target_component); + _mav_put_uint8_t(buf, 52, coordinate_frame); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, buf, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); -#endif -#else - mavlink_set_position_target_local_ned_t *packet = (mavlink_set_position_target_local_ned_t *)msgbuf; - packet->time_boot_ms = time_boot_ms; - packet->x = x; - packet->y = y; - packet->z = z; - packet->vx = vx; - packet->vy = vy; - packet->vz = vz; - packet->afx = afx; - packet->afy = afy; - packet->afz = afz; - packet->yaw = yaw; - packet->yaw_rate = yaw_rate; - packet->type_mask = type_mask; - packet->target_system = target_system; - packet->target_component = target_component; - packet->coordinate_frame = coordinate_frame; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, (const char *)packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, (const char *)packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); -#endif + mavlink_set_position_target_local_ned_t *packet = (mavlink_set_position_target_local_ned_t *)msgbuf; + packet->time_boot_ms = time_boot_ms; + packet->x = x; + packet->y = y; + packet->z = z; + packet->vx = vx; + packet->vy = vy; + packet->vz = vz; + packet->afx = afx; + packet->afy = afy; + packet->afz = afz; + packet->yaw = yaw; + packet->yaw_rate = yaw_rate; + packet->type_mask = type_mask; + packet->target_system = target_system; + packet->target_component = target_component; + packet->coordinate_frame = coordinate_frame; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED, (const char *)packet, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_CRC); #endif } #endif @@ -385,7 +402,7 @@ static inline void mavlink_msg_set_position_target_local_ned_send_buf(mavlink_me */ static inline uint32_t mavlink_msg_set_position_target_local_ned_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -395,7 +412,7 @@ static inline uint32_t mavlink_msg_set_position_target_local_ned_get_time_boot_m */ static inline uint8_t mavlink_msg_set_position_target_local_ned_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 50); + return _MAV_RETURN_uint8_t(msg, 50); } /** @@ -405,7 +422,7 @@ static inline uint8_t mavlink_msg_set_position_target_local_ned_get_target_syste */ static inline uint8_t mavlink_msg_set_position_target_local_ned_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 51); + return _MAV_RETURN_uint8_t(msg, 51); } /** @@ -415,7 +432,7 @@ static inline uint8_t mavlink_msg_set_position_target_local_ned_get_target_compo */ static inline uint8_t mavlink_msg_set_position_target_local_ned_get_coordinate_frame(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 52); + return _MAV_RETURN_uint8_t(msg, 52); } /** @@ -425,7 +442,7 @@ static inline uint8_t mavlink_msg_set_position_target_local_ned_get_coordinate_f */ static inline uint16_t mavlink_msg_set_position_target_local_ned_get_type_mask(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 48); + return _MAV_RETURN_uint16_t(msg, 48); } /** @@ -435,7 +452,7 @@ static inline uint16_t mavlink_msg_set_position_target_local_ned_get_type_mask(c */ static inline float mavlink_msg_set_position_target_local_ned_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -445,7 +462,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_x(const mavlin */ static inline float mavlink_msg_set_position_target_local_ned_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -455,7 +472,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_y(const mavlin */ static inline float mavlink_msg_set_position_target_local_ned_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -465,7 +482,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_z(const mavlin */ static inline float mavlink_msg_set_position_target_local_ned_get_vx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -475,7 +492,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_vx(const mavli */ static inline float mavlink_msg_set_position_target_local_ned_get_vy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -485,7 +502,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_vy(const mavli */ static inline float mavlink_msg_set_position_target_local_ned_get_vz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -495,7 +512,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_vz(const mavli */ static inline float mavlink_msg_set_position_target_local_ned_get_afx(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -505,7 +522,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_afx(const mavl */ static inline float mavlink_msg_set_position_target_local_ned_get_afy(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -515,7 +532,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_afy(const mavl */ static inline float mavlink_msg_set_position_target_local_ned_get_afz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -525,7 +542,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_afz(const mavl */ static inline float mavlink_msg_set_position_target_local_ned_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -535,7 +552,7 @@ static inline float mavlink_msg_set_position_target_local_ned_get_yaw(const mavl */ static inline float mavlink_msg_set_position_target_local_ned_get_yaw_rate(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -546,24 +563,26 @@ static inline float mavlink_msg_set_position_target_local_ned_get_yaw_rate(const */ static inline void mavlink_msg_set_position_target_local_ned_decode(const mavlink_message_t* msg, mavlink_set_position_target_local_ned_t* set_position_target_local_ned) { -#if MAVLINK_NEED_BYTE_SWAP - set_position_target_local_ned->time_boot_ms = mavlink_msg_set_position_target_local_ned_get_time_boot_ms(msg); - set_position_target_local_ned->x = mavlink_msg_set_position_target_local_ned_get_x(msg); - set_position_target_local_ned->y = mavlink_msg_set_position_target_local_ned_get_y(msg); - set_position_target_local_ned->z = mavlink_msg_set_position_target_local_ned_get_z(msg); - set_position_target_local_ned->vx = mavlink_msg_set_position_target_local_ned_get_vx(msg); - set_position_target_local_ned->vy = mavlink_msg_set_position_target_local_ned_get_vy(msg); - set_position_target_local_ned->vz = mavlink_msg_set_position_target_local_ned_get_vz(msg); - set_position_target_local_ned->afx = mavlink_msg_set_position_target_local_ned_get_afx(msg); - set_position_target_local_ned->afy = mavlink_msg_set_position_target_local_ned_get_afy(msg); - set_position_target_local_ned->afz = mavlink_msg_set_position_target_local_ned_get_afz(msg); - set_position_target_local_ned->yaw = mavlink_msg_set_position_target_local_ned_get_yaw(msg); - set_position_target_local_ned->yaw_rate = mavlink_msg_set_position_target_local_ned_get_yaw_rate(msg); - set_position_target_local_ned->type_mask = mavlink_msg_set_position_target_local_ned_get_type_mask(msg); - set_position_target_local_ned->target_system = mavlink_msg_set_position_target_local_ned_get_target_system(msg); - set_position_target_local_ned->target_component = mavlink_msg_set_position_target_local_ned_get_target_component(msg); - set_position_target_local_ned->coordinate_frame = mavlink_msg_set_position_target_local_ned_get_coordinate_frame(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + set_position_target_local_ned->time_boot_ms = mavlink_msg_set_position_target_local_ned_get_time_boot_ms(msg); + set_position_target_local_ned->x = mavlink_msg_set_position_target_local_ned_get_x(msg); + set_position_target_local_ned->y = mavlink_msg_set_position_target_local_ned_get_y(msg); + set_position_target_local_ned->z = mavlink_msg_set_position_target_local_ned_get_z(msg); + set_position_target_local_ned->vx = mavlink_msg_set_position_target_local_ned_get_vx(msg); + set_position_target_local_ned->vy = mavlink_msg_set_position_target_local_ned_get_vy(msg); + set_position_target_local_ned->vz = mavlink_msg_set_position_target_local_ned_get_vz(msg); + set_position_target_local_ned->afx = mavlink_msg_set_position_target_local_ned_get_afx(msg); + set_position_target_local_ned->afy = mavlink_msg_set_position_target_local_ned_get_afy(msg); + set_position_target_local_ned->afz = mavlink_msg_set_position_target_local_ned_get_afz(msg); + set_position_target_local_ned->yaw = mavlink_msg_set_position_target_local_ned_get_yaw(msg); + set_position_target_local_ned->yaw_rate = mavlink_msg_set_position_target_local_ned_get_yaw_rate(msg); + set_position_target_local_ned->type_mask = mavlink_msg_set_position_target_local_ned_get_type_mask(msg); + set_position_target_local_ned->target_system = mavlink_msg_set_position_target_local_ned_get_target_system(msg); + set_position_target_local_ned->target_component = mavlink_msg_set_position_target_local_ned_get_target_component(msg); + set_position_target_local_ned->coordinate_frame = mavlink_msg_set_position_target_local_ned_get_coordinate_frame(msg); #else - memcpy(set_position_target_local_ned, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN? msg->len : MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN; + memset(set_position_target_local_ned, 0, MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_LEN); + memcpy(set_position_target_local_ned, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_sim_state.h b/vendor/libraries/mavlink/common/mavlink_msg_sim_state.h index c47fc8c0c7..e49a07f1f4 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_sim_state.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_sim_state.h @@ -1,44 +1,49 @@ +#pragma once // MESSAGE SIM_STATE PACKING #define MAVLINK_MSG_ID_SIM_STATE 108 -typedef struct __mavlink_sim_state_t -{ - float q1; ///< True attitude quaternion component 1, w (1 in null-rotation) - float q2; ///< True attitude quaternion component 2, x (0 in null-rotation) - float q3; ///< True attitude quaternion component 3, y (0 in null-rotation) - float q4; ///< True attitude quaternion component 4, z (0 in null-rotation) - float roll; ///< Attitude roll expressed as Euler angles, not recommended except for human-readable outputs - float pitch; ///< Attitude pitch expressed as Euler angles, not recommended except for human-readable outputs - float yaw; ///< Attitude yaw expressed as Euler angles, not recommended except for human-readable outputs - float xacc; ///< X acceleration m/s/s - float yacc; ///< Y acceleration m/s/s - float zacc; ///< Z acceleration m/s/s - float xgyro; ///< Angular speed around X axis rad/s - float ygyro; ///< Angular speed around Y axis rad/s - float zgyro; ///< Angular speed around Z axis rad/s - float lat; ///< Latitude in degrees - float lon; ///< Longitude in degrees - float alt; ///< Altitude in meters - float std_dev_horz; ///< Horizontal position standard deviation - float std_dev_vert; ///< Vertical position standard deviation - float vn; ///< True velocity in m/s in NORTH direction in earth-fixed NED frame - float ve; ///< True velocity in m/s in EAST direction in earth-fixed NED frame - float vd; ///< True velocity in m/s in DOWN direction in earth-fixed NED frame -} mavlink_sim_state_t; +MAVPACKED( +typedef struct __mavlink_sim_state_t { + float q1; /*< True attitude quaternion component 1, w (1 in null-rotation)*/ + float q2; /*< True attitude quaternion component 2, x (0 in null-rotation)*/ + float q3; /*< True attitude quaternion component 3, y (0 in null-rotation)*/ + float q4; /*< True attitude quaternion component 4, z (0 in null-rotation)*/ + float roll; /*< Attitude roll expressed as Euler angles, not recommended except for human-readable outputs*/ + float pitch; /*< Attitude pitch expressed as Euler angles, not recommended except for human-readable outputs*/ + float yaw; /*< Attitude yaw expressed as Euler angles, not recommended except for human-readable outputs*/ + float xacc; /*< X acceleration m/s/s*/ + float yacc; /*< Y acceleration m/s/s*/ + float zacc; /*< Z acceleration m/s/s*/ + float xgyro; /*< Angular speed around X axis rad/s*/ + float ygyro; /*< Angular speed around Y axis rad/s*/ + float zgyro; /*< Angular speed around Z axis rad/s*/ + float lat; /*< Latitude in degrees*/ + float lon; /*< Longitude in degrees*/ + float alt; /*< Altitude in meters*/ + float std_dev_horz; /*< Horizontal position standard deviation*/ + float std_dev_vert; /*< Vertical position standard deviation*/ + float vn; /*< True velocity in m/s in NORTH direction in earth-fixed NED frame*/ + float ve; /*< True velocity in m/s in EAST direction in earth-fixed NED frame*/ + float vd; /*< True velocity in m/s in DOWN direction in earth-fixed NED frame*/ +}) mavlink_sim_state_t; #define MAVLINK_MSG_ID_SIM_STATE_LEN 84 +#define MAVLINK_MSG_ID_SIM_STATE_MIN_LEN 84 #define MAVLINK_MSG_ID_108_LEN 84 +#define MAVLINK_MSG_ID_108_MIN_LEN 84 #define MAVLINK_MSG_ID_SIM_STATE_CRC 32 #define MAVLINK_MSG_ID_108_CRC 32 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SIM_STATE { \ - "SIM_STATE", \ - 21, \ - { { "q1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_sim_state_t, q1) }, \ + 108, \ + "SIM_STATE", \ + 21, \ + { { "q1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_sim_state_t, q1) }, \ { "q2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_sim_state_t, q2) }, \ { "q3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_sim_state_t, q3) }, \ { "q4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_sim_state_t, q4) }, \ @@ -61,7 +66,34 @@ typedef struct __mavlink_sim_state_t { "vd", NULL, MAVLINK_TYPE_FLOAT, 0, 80, offsetof(mavlink_sim_state_t, vd) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SIM_STATE { \ + "SIM_STATE", \ + 21, \ + { { "q1", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_sim_state_t, q1) }, \ + { "q2", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_sim_state_t, q2) }, \ + { "q3", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_sim_state_t, q3) }, \ + { "q4", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_sim_state_t, q4) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_sim_state_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_sim_state_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_sim_state_t, yaw) }, \ + { "xacc", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_sim_state_t, xacc) }, \ + { "yacc", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_sim_state_t, yacc) }, \ + { "zacc", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_sim_state_t, zacc) }, \ + { "xgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 40, offsetof(mavlink_sim_state_t, xgyro) }, \ + { "ygyro", NULL, MAVLINK_TYPE_FLOAT, 0, 44, offsetof(mavlink_sim_state_t, ygyro) }, \ + { "zgyro", NULL, MAVLINK_TYPE_FLOAT, 0, 48, offsetof(mavlink_sim_state_t, zgyro) }, \ + { "lat", NULL, MAVLINK_TYPE_FLOAT, 0, 52, offsetof(mavlink_sim_state_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_FLOAT, 0, 56, offsetof(mavlink_sim_state_t, lon) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 60, offsetof(mavlink_sim_state_t, alt) }, \ + { "std_dev_horz", NULL, MAVLINK_TYPE_FLOAT, 0, 64, offsetof(mavlink_sim_state_t, std_dev_horz) }, \ + { "std_dev_vert", NULL, MAVLINK_TYPE_FLOAT, 0, 68, offsetof(mavlink_sim_state_t, std_dev_vert) }, \ + { "vn", NULL, MAVLINK_TYPE_FLOAT, 0, 72, offsetof(mavlink_sim_state_t, vn) }, \ + { "ve", NULL, MAVLINK_TYPE_FLOAT, 0, 76, offsetof(mavlink_sim_state_t, ve) }, \ + { "vd", NULL, MAVLINK_TYPE_FLOAT, 0, 80, offsetof(mavlink_sim_state_t, vd) }, \ + } \ +} +#endif /** * @brief Pack a sim_state message @@ -93,66 +125,62 @@ typedef struct __mavlink_sim_state_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_sim_state_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float q1, float q2, float q3, float q4, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float lat, float lon, float alt, float std_dev_horz, float std_dev_vert, float vn, float ve, float vd) + float q1, float q2, float q3, float q4, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float lat, float lon, float alt, float std_dev_horz, float std_dev_vert, float vn, float ve, float vd) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SIM_STATE_LEN]; - _mav_put_float(buf, 0, q1); - _mav_put_float(buf, 4, q2); - _mav_put_float(buf, 8, q3); - _mav_put_float(buf, 12, q4); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); - _mav_put_float(buf, 28, xacc); - _mav_put_float(buf, 32, yacc); - _mav_put_float(buf, 36, zacc); - _mav_put_float(buf, 40, xgyro); - _mav_put_float(buf, 44, ygyro); - _mav_put_float(buf, 48, zgyro); - _mav_put_float(buf, 52, lat); - _mav_put_float(buf, 56, lon); - _mav_put_float(buf, 60, alt); - _mav_put_float(buf, 64, std_dev_horz); - _mav_put_float(buf, 68, std_dev_vert); - _mav_put_float(buf, 72, vn); - _mav_put_float(buf, 76, ve); - _mav_put_float(buf, 80, vd); + char buf[MAVLINK_MSG_ID_SIM_STATE_LEN]; + _mav_put_float(buf, 0, q1); + _mav_put_float(buf, 4, q2); + _mav_put_float(buf, 8, q3); + _mav_put_float(buf, 12, q4); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); + _mav_put_float(buf, 28, xacc); + _mav_put_float(buf, 32, yacc); + _mav_put_float(buf, 36, zacc); + _mav_put_float(buf, 40, xgyro); + _mav_put_float(buf, 44, ygyro); + _mav_put_float(buf, 48, zgyro); + _mav_put_float(buf, 52, lat); + _mav_put_float(buf, 56, lon); + _mav_put_float(buf, 60, alt); + _mav_put_float(buf, 64, std_dev_horz); + _mav_put_float(buf, 68, std_dev_vert); + _mav_put_float(buf, 72, vn); + _mav_put_float(buf, 76, ve); + _mav_put_float(buf, 80, vd); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SIM_STATE_LEN); #else - mavlink_sim_state_t packet; - packet.q1 = q1; - packet.q2 = q2; - packet.q3 = q3; - packet.q4 = q4; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.std_dev_horz = std_dev_horz; - packet.std_dev_vert = std_dev_vert; - packet.vn = vn; - packet.ve = ve; - packet.vd = vd; + mavlink_sim_state_t packet; + packet.q1 = q1; + packet.q2 = q2; + packet.q3 = q3; + packet.q4 = q4; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.std_dev_horz = std_dev_horz; + packet.std_dev_vert = std_dev_vert; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SIM_STATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SIM_STATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SIM_STATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SIM_STATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SIM_STATE_MIN_LEN, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); } /** @@ -185,67 +213,63 @@ static inline uint16_t mavlink_msg_sim_state_pack(uint8_t system_id, uint8_t com * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_sim_state_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float q1,float q2,float q3,float q4,float roll,float pitch,float yaw,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,float lat,float lon,float alt,float std_dev_horz,float std_dev_vert,float vn,float ve,float vd) + mavlink_message_t* msg, + float q1,float q2,float q3,float q4,float roll,float pitch,float yaw,float xacc,float yacc,float zacc,float xgyro,float ygyro,float zgyro,float lat,float lon,float alt,float std_dev_horz,float std_dev_vert,float vn,float ve,float vd) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SIM_STATE_LEN]; - _mav_put_float(buf, 0, q1); - _mav_put_float(buf, 4, q2); - _mav_put_float(buf, 8, q3); - _mav_put_float(buf, 12, q4); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); - _mav_put_float(buf, 28, xacc); - _mav_put_float(buf, 32, yacc); - _mav_put_float(buf, 36, zacc); - _mav_put_float(buf, 40, xgyro); - _mav_put_float(buf, 44, ygyro); - _mav_put_float(buf, 48, zgyro); - _mav_put_float(buf, 52, lat); - _mav_put_float(buf, 56, lon); - _mav_put_float(buf, 60, alt); - _mav_put_float(buf, 64, std_dev_horz); - _mav_put_float(buf, 68, std_dev_vert); - _mav_put_float(buf, 72, vn); - _mav_put_float(buf, 76, ve); - _mav_put_float(buf, 80, vd); + char buf[MAVLINK_MSG_ID_SIM_STATE_LEN]; + _mav_put_float(buf, 0, q1); + _mav_put_float(buf, 4, q2); + _mav_put_float(buf, 8, q3); + _mav_put_float(buf, 12, q4); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); + _mav_put_float(buf, 28, xacc); + _mav_put_float(buf, 32, yacc); + _mav_put_float(buf, 36, zacc); + _mav_put_float(buf, 40, xgyro); + _mav_put_float(buf, 44, ygyro); + _mav_put_float(buf, 48, zgyro); + _mav_put_float(buf, 52, lat); + _mav_put_float(buf, 56, lon); + _mav_put_float(buf, 60, alt); + _mav_put_float(buf, 64, std_dev_horz); + _mav_put_float(buf, 68, std_dev_vert); + _mav_put_float(buf, 72, vn); + _mav_put_float(buf, 76, ve); + _mav_put_float(buf, 80, vd); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SIM_STATE_LEN); #else - mavlink_sim_state_t packet; - packet.q1 = q1; - packet.q2 = q2; - packet.q3 = q3; - packet.q4 = q4; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.std_dev_horz = std_dev_horz; - packet.std_dev_vert = std_dev_vert; - packet.vn = vn; - packet.ve = ve; - packet.vd = vd; + mavlink_sim_state_t packet; + packet.q1 = q1; + packet.q2 = q2; + packet.q3 = q3; + packet.q4 = q4; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.std_dev_horz = std_dev_horz; + packet.std_dev_vert = std_dev_vert; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SIM_STATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SIM_STATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SIM_STATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SIM_STATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SIM_STATE_MIN_LEN, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); } /** @@ -258,7 +282,7 @@ static inline uint16_t mavlink_msg_sim_state_pack_chan(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_sim_state_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_sim_state_t* sim_state) { - return mavlink_msg_sim_state_pack(system_id, component_id, msg, sim_state->q1, sim_state->q2, sim_state->q3, sim_state->q4, sim_state->roll, sim_state->pitch, sim_state->yaw, sim_state->xacc, sim_state->yacc, sim_state->zacc, sim_state->xgyro, sim_state->ygyro, sim_state->zgyro, sim_state->lat, sim_state->lon, sim_state->alt, sim_state->std_dev_horz, sim_state->std_dev_vert, sim_state->vn, sim_state->ve, sim_state->vd); + return mavlink_msg_sim_state_pack(system_id, component_id, msg, sim_state->q1, sim_state->q2, sim_state->q3, sim_state->q4, sim_state->roll, sim_state->pitch, sim_state->yaw, sim_state->xacc, sim_state->yacc, sim_state->zacc, sim_state->xgyro, sim_state->ygyro, sim_state->zgyro, sim_state->lat, sim_state->lon, sim_state->alt, sim_state->std_dev_horz, sim_state->std_dev_vert, sim_state->vn, sim_state->ve, sim_state->vd); } /** @@ -272,7 +296,7 @@ static inline uint16_t mavlink_msg_sim_state_encode(uint8_t system_id, uint8_t c */ static inline uint16_t mavlink_msg_sim_state_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_sim_state_t* sim_state) { - return mavlink_msg_sim_state_pack_chan(system_id, component_id, chan, msg, sim_state->q1, sim_state->q2, sim_state->q3, sim_state->q4, sim_state->roll, sim_state->pitch, sim_state->yaw, sim_state->xacc, sim_state->yacc, sim_state->zacc, sim_state->xgyro, sim_state->ygyro, sim_state->zgyro, sim_state->lat, sim_state->lon, sim_state->alt, sim_state->std_dev_horz, sim_state->std_dev_vert, sim_state->vn, sim_state->ve, sim_state->vd); + return mavlink_msg_sim_state_pack_chan(system_id, component_id, chan, msg, sim_state->q1, sim_state->q2, sim_state->q3, sim_state->q4, sim_state->roll, sim_state->pitch, sim_state->yaw, sim_state->xacc, sim_state->yacc, sim_state->zacc, sim_state->xgyro, sim_state->ygyro, sim_state->zgyro, sim_state->lat, sim_state->lon, sim_state->alt, sim_state->std_dev_horz, sim_state->std_dev_vert, sim_state->vn, sim_state->ve, sim_state->vd); } /** @@ -306,63 +330,69 @@ static inline uint16_t mavlink_msg_sim_state_encode_chan(uint8_t system_id, uint static inline void mavlink_msg_sim_state_send(mavlink_channel_t chan, float q1, float q2, float q3, float q4, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float lat, float lon, float alt, float std_dev_horz, float std_dev_vert, float vn, float ve, float vd) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SIM_STATE_LEN]; - _mav_put_float(buf, 0, q1); - _mav_put_float(buf, 4, q2); - _mav_put_float(buf, 8, q3); - _mav_put_float(buf, 12, q4); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); - _mav_put_float(buf, 28, xacc); - _mav_put_float(buf, 32, yacc); - _mav_put_float(buf, 36, zacc); - _mav_put_float(buf, 40, xgyro); - _mav_put_float(buf, 44, ygyro); - _mav_put_float(buf, 48, zgyro); - _mav_put_float(buf, 52, lat); - _mav_put_float(buf, 56, lon); - _mav_put_float(buf, 60, alt); - _mav_put_float(buf, 64, std_dev_horz); - _mav_put_float(buf, 68, std_dev_vert); - _mav_put_float(buf, 72, vn); - _mav_put_float(buf, 76, ve); - _mav_put_float(buf, 80, vd); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, buf, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); + char buf[MAVLINK_MSG_ID_SIM_STATE_LEN]; + _mav_put_float(buf, 0, q1); + _mav_put_float(buf, 4, q2); + _mav_put_float(buf, 8, q3); + _mav_put_float(buf, 12, q4); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); + _mav_put_float(buf, 28, xacc); + _mav_put_float(buf, 32, yacc); + _mav_put_float(buf, 36, zacc); + _mav_put_float(buf, 40, xgyro); + _mav_put_float(buf, 44, ygyro); + _mav_put_float(buf, 48, zgyro); + _mav_put_float(buf, 52, lat); + _mav_put_float(buf, 56, lon); + _mav_put_float(buf, 60, alt); + _mav_put_float(buf, 64, std_dev_horz); + _mav_put_float(buf, 68, std_dev_vert); + _mav_put_float(buf, 72, vn); + _mav_put_float(buf, 76, ve); + _mav_put_float(buf, 80, vd); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, buf, MAVLINK_MSG_ID_SIM_STATE_MIN_LEN, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, buf, MAVLINK_MSG_ID_SIM_STATE_LEN); + mavlink_sim_state_t packet; + packet.q1 = q1; + packet.q2 = q2; + packet.q3 = q3; + packet.q4 = q4; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + packet.xacc = xacc; + packet.yacc = yacc; + packet.zacc = zacc; + packet.xgyro = xgyro; + packet.ygyro = ygyro; + packet.zgyro = zgyro; + packet.lat = lat; + packet.lon = lon; + packet.alt = alt; + packet.std_dev_horz = std_dev_horz; + packet.std_dev_vert = std_dev_vert; + packet.vn = vn; + packet.ve = ve; + packet.vd = vd; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, (const char *)&packet, MAVLINK_MSG_ID_SIM_STATE_MIN_LEN, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); #endif +} + +/** + * @brief Send a sim_state message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_sim_state_send_struct(mavlink_channel_t chan, const mavlink_sim_state_t* sim_state) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_sim_state_send(chan, sim_state->q1, sim_state->q2, sim_state->q3, sim_state->q4, sim_state->roll, sim_state->pitch, sim_state->yaw, sim_state->xacc, sim_state->yacc, sim_state->zacc, sim_state->xgyro, sim_state->ygyro, sim_state->zgyro, sim_state->lat, sim_state->lon, sim_state->alt, sim_state->std_dev_horz, sim_state->std_dev_vert, sim_state->vn, sim_state->ve, sim_state->vd); #else - mavlink_sim_state_t packet; - packet.q1 = q1; - packet.q2 = q2; - packet.q3 = q3; - packet.q4 = q4; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - packet.xacc = xacc; - packet.yacc = yacc; - packet.zacc = zacc; - packet.xgyro = xgyro; - packet.ygyro = ygyro; - packet.zgyro = zgyro; - packet.lat = lat; - packet.lon = lon; - packet.alt = alt; - packet.std_dev_horz = std_dev_horz; - packet.std_dev_vert = std_dev_vert; - packet.vn = vn; - packet.ve = ve; - packet.vd = vd; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, (const char *)&packet, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, (const char *)&packet, MAVLINK_MSG_ID_SIM_STATE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, (const char *)sim_state, MAVLINK_MSG_ID_SIM_STATE_MIN_LEN, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); #endif } @@ -377,63 +407,55 @@ static inline void mavlink_msg_sim_state_send(mavlink_channel_t chan, float q1, static inline void mavlink_msg_sim_state_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float q1, float q2, float q3, float q4, float roll, float pitch, float yaw, float xacc, float yacc, float zacc, float xgyro, float ygyro, float zgyro, float lat, float lon, float alt, float std_dev_horz, float std_dev_vert, float vn, float ve, float vd) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, q1); - _mav_put_float(buf, 4, q2); - _mav_put_float(buf, 8, q3); - _mav_put_float(buf, 12, q4); - _mav_put_float(buf, 16, roll); - _mav_put_float(buf, 20, pitch); - _mav_put_float(buf, 24, yaw); - _mav_put_float(buf, 28, xacc); - _mav_put_float(buf, 32, yacc); - _mav_put_float(buf, 36, zacc); - _mav_put_float(buf, 40, xgyro); - _mav_put_float(buf, 44, ygyro); - _mav_put_float(buf, 48, zgyro); - _mav_put_float(buf, 52, lat); - _mav_put_float(buf, 56, lon); - _mav_put_float(buf, 60, alt); - _mav_put_float(buf, 64, std_dev_horz); - _mav_put_float(buf, 68, std_dev_vert); - _mav_put_float(buf, 72, vn); - _mav_put_float(buf, 76, ve); - _mav_put_float(buf, 80, vd); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, buf, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, q1); + _mav_put_float(buf, 4, q2); + _mav_put_float(buf, 8, q3); + _mav_put_float(buf, 12, q4); + _mav_put_float(buf, 16, roll); + _mav_put_float(buf, 20, pitch); + _mav_put_float(buf, 24, yaw); + _mav_put_float(buf, 28, xacc); + _mav_put_float(buf, 32, yacc); + _mav_put_float(buf, 36, zacc); + _mav_put_float(buf, 40, xgyro); + _mav_put_float(buf, 44, ygyro); + _mav_put_float(buf, 48, zgyro); + _mav_put_float(buf, 52, lat); + _mav_put_float(buf, 56, lon); + _mav_put_float(buf, 60, alt); + _mav_put_float(buf, 64, std_dev_horz); + _mav_put_float(buf, 68, std_dev_vert); + _mav_put_float(buf, 72, vn); + _mav_put_float(buf, 76, ve); + _mav_put_float(buf, 80, vd); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, buf, MAVLINK_MSG_ID_SIM_STATE_MIN_LEN, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, buf, MAVLINK_MSG_ID_SIM_STATE_LEN); -#endif -#else - mavlink_sim_state_t *packet = (mavlink_sim_state_t *)msgbuf; - packet->q1 = q1; - packet->q2 = q2; - packet->q3 = q3; - packet->q4 = q4; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - packet->xacc = xacc; - packet->yacc = yacc; - packet->zacc = zacc; - packet->xgyro = xgyro; - packet->ygyro = ygyro; - packet->zgyro = zgyro; - packet->lat = lat; - packet->lon = lon; - packet->alt = alt; - packet->std_dev_horz = std_dev_horz; - packet->std_dev_vert = std_dev_vert; - packet->vn = vn; - packet->ve = ve; - packet->vd = vd; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, (const char *)packet, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, (const char *)packet, MAVLINK_MSG_ID_SIM_STATE_LEN); -#endif + mavlink_sim_state_t *packet = (mavlink_sim_state_t *)msgbuf; + packet->q1 = q1; + packet->q2 = q2; + packet->q3 = q3; + packet->q4 = q4; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + packet->xacc = xacc; + packet->yacc = yacc; + packet->zacc = zacc; + packet->xgyro = xgyro; + packet->ygyro = ygyro; + packet->zgyro = zgyro; + packet->lat = lat; + packet->lon = lon; + packet->alt = alt; + packet->std_dev_horz = std_dev_horz; + packet->std_dev_vert = std_dev_vert; + packet->vn = vn; + packet->ve = ve; + packet->vd = vd; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SIM_STATE, (const char *)packet, MAVLINK_MSG_ID_SIM_STATE_MIN_LEN, MAVLINK_MSG_ID_SIM_STATE_LEN, MAVLINK_MSG_ID_SIM_STATE_CRC); #endif } #endif @@ -450,7 +472,7 @@ static inline void mavlink_msg_sim_state_send_buf(mavlink_message_t *msgbuf, mav */ static inline float mavlink_msg_sim_state_get_q1(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -460,7 +482,7 @@ static inline float mavlink_msg_sim_state_get_q1(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_q2(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -470,7 +492,7 @@ static inline float mavlink_msg_sim_state_get_q2(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_q3(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -480,7 +502,7 @@ static inline float mavlink_msg_sim_state_get_q3(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_q4(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -490,7 +512,7 @@ static inline float mavlink_msg_sim_state_get_q4(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -500,7 +522,7 @@ static inline float mavlink_msg_sim_state_get_roll(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -510,7 +532,7 @@ static inline float mavlink_msg_sim_state_get_pitch(const mavlink_message_t* msg */ static inline float mavlink_msg_sim_state_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -520,7 +542,7 @@ static inline float mavlink_msg_sim_state_get_yaw(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_xacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -530,7 +552,7 @@ static inline float mavlink_msg_sim_state_get_xacc(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_yacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 32); + return _MAV_RETURN_float(msg, 32); } /** @@ -540,7 +562,7 @@ static inline float mavlink_msg_sim_state_get_yacc(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_zacc(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 36); + return _MAV_RETURN_float(msg, 36); } /** @@ -550,7 +572,7 @@ static inline float mavlink_msg_sim_state_get_zacc(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_xgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 40); + return _MAV_RETURN_float(msg, 40); } /** @@ -560,7 +582,7 @@ static inline float mavlink_msg_sim_state_get_xgyro(const mavlink_message_t* msg */ static inline float mavlink_msg_sim_state_get_ygyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 44); + return _MAV_RETURN_float(msg, 44); } /** @@ -570,7 +592,7 @@ static inline float mavlink_msg_sim_state_get_ygyro(const mavlink_message_t* msg */ static inline float mavlink_msg_sim_state_get_zgyro(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 48); + return _MAV_RETURN_float(msg, 48); } /** @@ -580,7 +602,7 @@ static inline float mavlink_msg_sim_state_get_zgyro(const mavlink_message_t* msg */ static inline float mavlink_msg_sim_state_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 52); + return _MAV_RETURN_float(msg, 52); } /** @@ -590,7 +612,7 @@ static inline float mavlink_msg_sim_state_get_lat(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 56); + return _MAV_RETURN_float(msg, 56); } /** @@ -600,7 +622,7 @@ static inline float mavlink_msg_sim_state_get_lon(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 60); + return _MAV_RETURN_float(msg, 60); } /** @@ -610,7 +632,7 @@ static inline float mavlink_msg_sim_state_get_alt(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_std_dev_horz(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 64); + return _MAV_RETURN_float(msg, 64); } /** @@ -620,7 +642,7 @@ static inline float mavlink_msg_sim_state_get_std_dev_horz(const mavlink_message */ static inline float mavlink_msg_sim_state_get_std_dev_vert(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 68); + return _MAV_RETURN_float(msg, 68); } /** @@ -630,7 +652,7 @@ static inline float mavlink_msg_sim_state_get_std_dev_vert(const mavlink_message */ static inline float mavlink_msg_sim_state_get_vn(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 72); + return _MAV_RETURN_float(msg, 72); } /** @@ -640,7 +662,7 @@ static inline float mavlink_msg_sim_state_get_vn(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_ve(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 76); + return _MAV_RETURN_float(msg, 76); } /** @@ -650,7 +672,7 @@ static inline float mavlink_msg_sim_state_get_ve(const mavlink_message_t* msg) */ static inline float mavlink_msg_sim_state_get_vd(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 80); + return _MAV_RETURN_float(msg, 80); } /** @@ -661,29 +683,31 @@ static inline float mavlink_msg_sim_state_get_vd(const mavlink_message_t* msg) */ static inline void mavlink_msg_sim_state_decode(const mavlink_message_t* msg, mavlink_sim_state_t* sim_state) { -#if MAVLINK_NEED_BYTE_SWAP - sim_state->q1 = mavlink_msg_sim_state_get_q1(msg); - sim_state->q2 = mavlink_msg_sim_state_get_q2(msg); - sim_state->q3 = mavlink_msg_sim_state_get_q3(msg); - sim_state->q4 = mavlink_msg_sim_state_get_q4(msg); - sim_state->roll = mavlink_msg_sim_state_get_roll(msg); - sim_state->pitch = mavlink_msg_sim_state_get_pitch(msg); - sim_state->yaw = mavlink_msg_sim_state_get_yaw(msg); - sim_state->xacc = mavlink_msg_sim_state_get_xacc(msg); - sim_state->yacc = mavlink_msg_sim_state_get_yacc(msg); - sim_state->zacc = mavlink_msg_sim_state_get_zacc(msg); - sim_state->xgyro = mavlink_msg_sim_state_get_xgyro(msg); - sim_state->ygyro = mavlink_msg_sim_state_get_ygyro(msg); - sim_state->zgyro = mavlink_msg_sim_state_get_zgyro(msg); - sim_state->lat = mavlink_msg_sim_state_get_lat(msg); - sim_state->lon = mavlink_msg_sim_state_get_lon(msg); - sim_state->alt = mavlink_msg_sim_state_get_alt(msg); - sim_state->std_dev_horz = mavlink_msg_sim_state_get_std_dev_horz(msg); - sim_state->std_dev_vert = mavlink_msg_sim_state_get_std_dev_vert(msg); - sim_state->vn = mavlink_msg_sim_state_get_vn(msg); - sim_state->ve = mavlink_msg_sim_state_get_ve(msg); - sim_state->vd = mavlink_msg_sim_state_get_vd(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + sim_state->q1 = mavlink_msg_sim_state_get_q1(msg); + sim_state->q2 = mavlink_msg_sim_state_get_q2(msg); + sim_state->q3 = mavlink_msg_sim_state_get_q3(msg); + sim_state->q4 = mavlink_msg_sim_state_get_q4(msg); + sim_state->roll = mavlink_msg_sim_state_get_roll(msg); + sim_state->pitch = mavlink_msg_sim_state_get_pitch(msg); + sim_state->yaw = mavlink_msg_sim_state_get_yaw(msg); + sim_state->xacc = mavlink_msg_sim_state_get_xacc(msg); + sim_state->yacc = mavlink_msg_sim_state_get_yacc(msg); + sim_state->zacc = mavlink_msg_sim_state_get_zacc(msg); + sim_state->xgyro = mavlink_msg_sim_state_get_xgyro(msg); + sim_state->ygyro = mavlink_msg_sim_state_get_ygyro(msg); + sim_state->zgyro = mavlink_msg_sim_state_get_zgyro(msg); + sim_state->lat = mavlink_msg_sim_state_get_lat(msg); + sim_state->lon = mavlink_msg_sim_state_get_lon(msg); + sim_state->alt = mavlink_msg_sim_state_get_alt(msg); + sim_state->std_dev_horz = mavlink_msg_sim_state_get_std_dev_horz(msg); + sim_state->std_dev_vert = mavlink_msg_sim_state_get_std_dev_vert(msg); + sim_state->vn = mavlink_msg_sim_state_get_vn(msg); + sim_state->ve = mavlink_msg_sim_state_get_ve(msg); + sim_state->vd = mavlink_msg_sim_state_get_vd(msg); #else - memcpy(sim_state, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SIM_STATE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SIM_STATE_LEN? msg->len : MAVLINK_MSG_ID_SIM_STATE_LEN; + memset(sim_state, 0, MAVLINK_MSG_ID_SIM_STATE_LEN); + memcpy(sim_state, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_statustext.h b/vendor/libraries/mavlink/common/mavlink_msg_statustext.h index c8c2547b31..e1ed320a3d 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_statustext.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_statustext.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE STATUSTEXT PACKING #define MAVLINK_MSG_ID_STATUSTEXT 253 -typedef struct __mavlink_statustext_t -{ - uint8_t severity; ///< Severity of status. Relies on the definitions within RFC-5424. See enum MAV_SEVERITY. - char text[50]; ///< Status text message, without null termination character -} mavlink_statustext_t; +MAVPACKED( +typedef struct __mavlink_statustext_t { + uint8_t severity; /*< Severity of status. Relies on the definitions within RFC-5424. See enum MAV_SEVERITY.*/ + char text[50]; /*< Status text message, without null termination character*/ +}) mavlink_statustext_t; #define MAVLINK_MSG_ID_STATUSTEXT_LEN 51 +#define MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN 51 #define MAVLINK_MSG_ID_253_LEN 51 +#define MAVLINK_MSG_ID_253_MIN_LEN 51 #define MAVLINK_MSG_ID_STATUSTEXT_CRC 83 #define MAVLINK_MSG_ID_253_CRC 83 #define MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN 50 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_STATUSTEXT { \ - "STATUSTEXT", \ - 2, \ - { { "severity", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_statustext_t, severity) }, \ + 253, \ + "STATUSTEXT", \ + 2, \ + { { "severity", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_statustext_t, severity) }, \ { "text", NULL, MAVLINK_TYPE_CHAR, 50, 1, offsetof(mavlink_statustext_t, text) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_STATUSTEXT { \ + "STATUSTEXT", \ + 2, \ + { { "severity", NULL, MAVLINK_TYPE_UINT8_T, 0, 0, offsetof(mavlink_statustext_t, severity) }, \ + { "text", NULL, MAVLINK_TYPE_CHAR, 50, 1, offsetof(mavlink_statustext_t, text) }, \ + } \ +} +#endif /** * @brief Pack a statustext message @@ -36,26 +49,22 @@ typedef struct __mavlink_statustext_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_statustext_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t severity, const char *text) + uint8_t severity, const char *text) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_STATUSTEXT_LEN]; - _mav_put_uint8_t(buf, 0, severity); - _mav_put_char_array(buf, 1, text, 50); + char buf[MAVLINK_MSG_ID_STATUSTEXT_LEN]; + _mav_put_uint8_t(buf, 0, severity); + _mav_put_char_array(buf, 1, text, 50); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_STATUSTEXT_LEN); #else - mavlink_statustext_t packet; - packet.severity = severity; - mav_array_memcpy(packet.text, text, sizeof(char)*50); + mavlink_statustext_t packet; + packet.severity = severity; + mav_array_memcpy(packet.text, text, sizeof(char)*50); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_STATUSTEXT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_STATUSTEXT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_STATUSTEXT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_STATUSTEXT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); } /** @@ -69,27 +78,23 @@ static inline uint16_t mavlink_msg_statustext_pack(uint8_t system_id, uint8_t co * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_statustext_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t severity,const char *text) + mavlink_message_t* msg, + uint8_t severity,const char *text) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_STATUSTEXT_LEN]; - _mav_put_uint8_t(buf, 0, severity); - _mav_put_char_array(buf, 1, text, 50); + char buf[MAVLINK_MSG_ID_STATUSTEXT_LEN]; + _mav_put_uint8_t(buf, 0, severity); + _mav_put_char_array(buf, 1, text, 50); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_STATUSTEXT_LEN); #else - mavlink_statustext_t packet; - packet.severity = severity; - mav_array_memcpy(packet.text, text, sizeof(char)*50); + mavlink_statustext_t packet; + packet.severity = severity; + mav_array_memcpy(packet.text, text, sizeof(char)*50); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_STATUSTEXT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_STATUSTEXT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_STATUSTEXT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_STATUSTEXT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); } /** @@ -102,7 +107,7 @@ static inline uint16_t mavlink_msg_statustext_pack_chan(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_statustext_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_statustext_t* statustext) { - return mavlink_msg_statustext_pack(system_id, component_id, msg, statustext->severity, statustext->text); + return mavlink_msg_statustext_pack(system_id, component_id, msg, statustext->severity, statustext->text); } /** @@ -116,7 +121,7 @@ static inline uint16_t mavlink_msg_statustext_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_statustext_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_statustext_t* statustext) { - return mavlink_msg_statustext_pack_chan(system_id, component_id, chan, msg, statustext->severity, statustext->text); + return mavlink_msg_statustext_pack_chan(system_id, component_id, chan, msg, statustext->severity, statustext->text); } /** @@ -131,23 +136,29 @@ static inline uint16_t mavlink_msg_statustext_encode_chan(uint8_t system_id, uin static inline void mavlink_msg_statustext_send(mavlink_channel_t chan, uint8_t severity, const char *text) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_STATUSTEXT_LEN]; - _mav_put_uint8_t(buf, 0, severity); - _mav_put_char_array(buf, 1, text, 50); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, buf, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); + char buf[MAVLINK_MSG_ID_STATUSTEXT_LEN]; + _mav_put_uint8_t(buf, 0, severity); + _mav_put_char_array(buf, 1, text, 50); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, buf, MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, buf, MAVLINK_MSG_ID_STATUSTEXT_LEN); + mavlink_statustext_t packet; + packet.severity = severity; + mav_array_memcpy(packet.text, text, sizeof(char)*50); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, (const char *)&packet, MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); #endif +} + +/** + * @brief Send a statustext message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_statustext_send_struct(mavlink_channel_t chan, const mavlink_statustext_t* statustext) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_statustext_send(chan, statustext->severity, statustext->text); #else - mavlink_statustext_t packet; - packet.severity = severity; - mav_array_memcpy(packet.text, text, sizeof(char)*50); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, (const char *)&packet, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, (const char *)&packet, MAVLINK_MSG_ID_STATUSTEXT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, (const char *)statustext, MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); #endif } @@ -162,23 +173,15 @@ static inline void mavlink_msg_statustext_send(mavlink_channel_t chan, uint8_t s static inline void mavlink_msg_statustext_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t severity, const char *text) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint8_t(buf, 0, severity); - _mav_put_char_array(buf, 1, text, 50); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, buf, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, buf, MAVLINK_MSG_ID_STATUSTEXT_LEN); -#endif + char *buf = (char *)msgbuf; + _mav_put_uint8_t(buf, 0, severity); + _mav_put_char_array(buf, 1, text, 50); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, buf, MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); #else - mavlink_statustext_t *packet = (mavlink_statustext_t *)msgbuf; - packet->severity = severity; - mav_array_memcpy(packet->text, text, sizeof(char)*50); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, (const char *)packet, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, (const char *)packet, MAVLINK_MSG_ID_STATUSTEXT_LEN); -#endif + mavlink_statustext_t *packet = (mavlink_statustext_t *)msgbuf; + packet->severity = severity; + mav_array_memcpy(packet->text, text, sizeof(char)*50); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_STATUSTEXT, (const char *)packet, MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN, MAVLINK_MSG_ID_STATUSTEXT_LEN, MAVLINK_MSG_ID_STATUSTEXT_CRC); #endif } #endif @@ -195,7 +198,7 @@ static inline void mavlink_msg_statustext_send_buf(mavlink_message_t *msgbuf, ma */ static inline uint8_t mavlink_msg_statustext_get_severity(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 0); + return _MAV_RETURN_uint8_t(msg, 0); } /** @@ -205,7 +208,7 @@ static inline uint8_t mavlink_msg_statustext_get_severity(const mavlink_message_ */ static inline uint16_t mavlink_msg_statustext_get_text(const mavlink_message_t* msg, char *text) { - return _MAV_RETURN_char_array(msg, text, 50, 1); + return _MAV_RETURN_char_array(msg, text, 50, 1); } /** @@ -216,10 +219,12 @@ static inline uint16_t mavlink_msg_statustext_get_text(const mavlink_message_t* */ static inline void mavlink_msg_statustext_decode(const mavlink_message_t* msg, mavlink_statustext_t* statustext) { -#if MAVLINK_NEED_BYTE_SWAP - statustext->severity = mavlink_msg_statustext_get_severity(msg); - mavlink_msg_statustext_get_text(msg, statustext->text); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + statustext->severity = mavlink_msg_statustext_get_severity(msg); + mavlink_msg_statustext_get_text(msg, statustext->text); #else - memcpy(statustext, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_STATUSTEXT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_STATUSTEXT_LEN? msg->len : MAVLINK_MSG_ID_STATUSTEXT_LEN; + memset(statustext, 0, MAVLINK_MSG_ID_STATUSTEXT_LEN); + memcpy(statustext, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_sys_status.h b/vendor/libraries/mavlink/common/mavlink_msg_sys_status.h index 1b1730d5f5..28a85b53f5 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_sys_status.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_sys_status.h @@ -1,36 +1,41 @@ +#pragma once // MESSAGE SYS_STATUS PACKING #define MAVLINK_MSG_ID_SYS_STATUS 1 -typedef struct __mavlink_sys_status_t -{ - uint32_t onboard_control_sensors_present; ///< Bitmask showing which onboard controllers and sensors are present. Value of 0: not present. Value of 1: present. Indices defined by ENUM MAV_SYS_STATUS_SENSOR - uint32_t onboard_control_sensors_enabled; ///< Bitmask showing which onboard controllers and sensors are enabled: Value of 0: not enabled. Value of 1: enabled. Indices defined by ENUM MAV_SYS_STATUS_SENSOR - uint32_t onboard_control_sensors_health; ///< Bitmask showing which onboard controllers and sensors are operational or have an error: Value of 0: not enabled. Value of 1: enabled. Indices defined by ENUM MAV_SYS_STATUS_SENSOR - uint16_t load; ///< Maximum usage in percent of the mainloop time, (0%: 0, 100%: 1000) should be always below 1000 - uint16_t voltage_battery; ///< Battery voltage, in millivolts (1 = 1 millivolt) - int16_t current_battery; ///< Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current - uint16_t drop_rate_comm; ///< Communication drops in percent, (0%: 0, 100%: 10'000), (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV) - uint16_t errors_comm; ///< Communication errors (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV) - uint16_t errors_count1; ///< Autopilot-specific errors - uint16_t errors_count2; ///< Autopilot-specific errors - uint16_t errors_count3; ///< Autopilot-specific errors - uint16_t errors_count4; ///< Autopilot-specific errors - int8_t battery_remaining; ///< Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot estimate the remaining battery -} mavlink_sys_status_t; +MAVPACKED( +typedef struct __mavlink_sys_status_t { + uint32_t onboard_control_sensors_present; /*< Bitmask showing which onboard controllers and sensors are present. Value of 0: not present. Value of 1: present. Indices defined by ENUM MAV_SYS_STATUS_SENSOR*/ + uint32_t onboard_control_sensors_enabled; /*< Bitmask showing which onboard controllers and sensors are enabled: Value of 0: not enabled. Value of 1: enabled. Indices defined by ENUM MAV_SYS_STATUS_SENSOR*/ + uint32_t onboard_control_sensors_health; /*< Bitmask showing which onboard controllers and sensors are operational or have an error: Value of 0: not enabled. Value of 1: enabled. Indices defined by ENUM MAV_SYS_STATUS_SENSOR*/ + uint16_t load; /*< Maximum usage in percent of the mainloop time, (0%: 0, 100%: 1000) should be always below 1000*/ + uint16_t voltage_battery; /*< Battery voltage, in millivolts (1 = 1 millivolt)*/ + int16_t current_battery; /*< Battery current, in 10*milliamperes (1 = 10 milliampere), -1: autopilot does not measure the current*/ + uint16_t drop_rate_comm; /*< Communication drops in percent, (0%: 0, 100%: 10'000), (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV)*/ + uint16_t errors_comm; /*< Communication errors (UART, I2C, SPI, CAN), dropped packets on all links (packets that were corrupted on reception on the MAV)*/ + uint16_t errors_count1; /*< Autopilot-specific errors*/ + uint16_t errors_count2; /*< Autopilot-specific errors*/ + uint16_t errors_count3; /*< Autopilot-specific errors*/ + uint16_t errors_count4; /*< Autopilot-specific errors*/ + int8_t battery_remaining; /*< Remaining battery energy: (0%: 0, 100%: 100), -1: autopilot estimate the remaining battery*/ +}) mavlink_sys_status_t; #define MAVLINK_MSG_ID_SYS_STATUS_LEN 31 +#define MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN 31 #define MAVLINK_MSG_ID_1_LEN 31 +#define MAVLINK_MSG_ID_1_MIN_LEN 31 #define MAVLINK_MSG_ID_SYS_STATUS_CRC 124 #define MAVLINK_MSG_ID_1_CRC 124 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SYS_STATUS { \ - "SYS_STATUS", \ - 13, \ - { { "onboard_control_sensors_present", "0x%04x", MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_sys_status_t, onboard_control_sensors_present) }, \ + 1, \ + "SYS_STATUS", \ + 13, \ + { { "onboard_control_sensors_present", "0x%04x", MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_sys_status_t, onboard_control_sensors_present) }, \ { "onboard_control_sensors_enabled", "0x%04x", MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_sys_status_t, onboard_control_sensors_enabled) }, \ { "onboard_control_sensors_health", "0x%04x", MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_sys_status_t, onboard_control_sensors_health) }, \ { "load", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_sys_status_t, load) }, \ @@ -45,7 +50,26 @@ typedef struct __mavlink_sys_status_t { "battery_remaining", NULL, MAVLINK_TYPE_INT8_T, 0, 30, offsetof(mavlink_sys_status_t, battery_remaining) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SYS_STATUS { \ + "SYS_STATUS", \ + 13, \ + { { "onboard_control_sensors_present", "0x%04x", MAVLINK_TYPE_UINT32_T, 0, 0, offsetof(mavlink_sys_status_t, onboard_control_sensors_present) }, \ + { "onboard_control_sensors_enabled", "0x%04x", MAVLINK_TYPE_UINT32_T, 0, 4, offsetof(mavlink_sys_status_t, onboard_control_sensors_enabled) }, \ + { "onboard_control_sensors_health", "0x%04x", MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_sys_status_t, onboard_control_sensors_health) }, \ + { "load", NULL, MAVLINK_TYPE_UINT16_T, 0, 12, offsetof(mavlink_sys_status_t, load) }, \ + { "voltage_battery", NULL, MAVLINK_TYPE_UINT16_T, 0, 14, offsetof(mavlink_sys_status_t, voltage_battery) }, \ + { "current_battery", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_sys_status_t, current_battery) }, \ + { "drop_rate_comm", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_sys_status_t, drop_rate_comm) }, \ + { "errors_comm", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_sys_status_t, errors_comm) }, \ + { "errors_count1", NULL, MAVLINK_TYPE_UINT16_T, 0, 22, offsetof(mavlink_sys_status_t, errors_count1) }, \ + { "errors_count2", NULL, MAVLINK_TYPE_UINT16_T, 0, 24, offsetof(mavlink_sys_status_t, errors_count2) }, \ + { "errors_count3", NULL, MAVLINK_TYPE_UINT16_T, 0, 26, offsetof(mavlink_sys_status_t, errors_count3) }, \ + { "errors_count4", NULL, MAVLINK_TYPE_UINT16_T, 0, 28, offsetof(mavlink_sys_status_t, errors_count4) }, \ + { "battery_remaining", NULL, MAVLINK_TYPE_INT8_T, 0, 30, offsetof(mavlink_sys_status_t, battery_remaining) }, \ + } \ +} +#endif /** * @brief Pack a sys_status message @@ -69,50 +93,46 @@ typedef struct __mavlink_sys_status_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_sys_status_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint32_t onboard_control_sensors_present, uint32_t onboard_control_sensors_enabled, uint32_t onboard_control_sensors_health, uint16_t load, uint16_t voltage_battery, int16_t current_battery, int8_t battery_remaining, uint16_t drop_rate_comm, uint16_t errors_comm, uint16_t errors_count1, uint16_t errors_count2, uint16_t errors_count3, uint16_t errors_count4) + uint32_t onboard_control_sensors_present, uint32_t onboard_control_sensors_enabled, uint32_t onboard_control_sensors_health, uint16_t load, uint16_t voltage_battery, int16_t current_battery, int8_t battery_remaining, uint16_t drop_rate_comm, uint16_t errors_comm, uint16_t errors_count1, uint16_t errors_count2, uint16_t errors_count3, uint16_t errors_count4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SYS_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); - _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); - _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); - _mav_put_uint16_t(buf, 12, load); - _mav_put_uint16_t(buf, 14, voltage_battery); - _mav_put_int16_t(buf, 16, current_battery); - _mav_put_uint16_t(buf, 18, drop_rate_comm); - _mav_put_uint16_t(buf, 20, errors_comm); - _mav_put_uint16_t(buf, 22, errors_count1); - _mav_put_uint16_t(buf, 24, errors_count2); - _mav_put_uint16_t(buf, 26, errors_count3); - _mav_put_uint16_t(buf, 28, errors_count4); - _mav_put_int8_t(buf, 30, battery_remaining); + char buf[MAVLINK_MSG_ID_SYS_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); + _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); + _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); + _mav_put_uint16_t(buf, 12, load); + _mav_put_uint16_t(buf, 14, voltage_battery); + _mav_put_int16_t(buf, 16, current_battery); + _mav_put_uint16_t(buf, 18, drop_rate_comm); + _mav_put_uint16_t(buf, 20, errors_comm); + _mav_put_uint16_t(buf, 22, errors_count1); + _mav_put_uint16_t(buf, 24, errors_count2); + _mav_put_uint16_t(buf, 26, errors_count3); + _mav_put_uint16_t(buf, 28, errors_count4); + _mav_put_int8_t(buf, 30, battery_remaining); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SYS_STATUS_LEN); #else - mavlink_sys_status_t packet; - packet.onboard_control_sensors_present = onboard_control_sensors_present; - packet.onboard_control_sensors_enabled = onboard_control_sensors_enabled; - packet.onboard_control_sensors_health = onboard_control_sensors_health; - packet.load = load; - packet.voltage_battery = voltage_battery; - packet.current_battery = current_battery; - packet.drop_rate_comm = drop_rate_comm; - packet.errors_comm = errors_comm; - packet.errors_count1 = errors_count1; - packet.errors_count2 = errors_count2; - packet.errors_count3 = errors_count3; - packet.errors_count4 = errors_count4; - packet.battery_remaining = battery_remaining; + mavlink_sys_status_t packet; + packet.onboard_control_sensors_present = onboard_control_sensors_present; + packet.onboard_control_sensors_enabled = onboard_control_sensors_enabled; + packet.onboard_control_sensors_health = onboard_control_sensors_health; + packet.load = load; + packet.voltage_battery = voltage_battery; + packet.current_battery = current_battery; + packet.drop_rate_comm = drop_rate_comm; + packet.errors_comm = errors_comm; + packet.errors_count1 = errors_count1; + packet.errors_count2 = errors_count2; + packet.errors_count3 = errors_count3; + packet.errors_count4 = errors_count4; + packet.battery_remaining = battery_remaining; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SYS_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SYS_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SYS_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SYS_STATUS; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); } /** @@ -137,51 +157,47 @@ static inline uint16_t mavlink_msg_sys_status_pack(uint8_t system_id, uint8_t co * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_sys_status_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint32_t onboard_control_sensors_present,uint32_t onboard_control_sensors_enabled,uint32_t onboard_control_sensors_health,uint16_t load,uint16_t voltage_battery,int16_t current_battery,int8_t battery_remaining,uint16_t drop_rate_comm,uint16_t errors_comm,uint16_t errors_count1,uint16_t errors_count2,uint16_t errors_count3,uint16_t errors_count4) + mavlink_message_t* msg, + uint32_t onboard_control_sensors_present,uint32_t onboard_control_sensors_enabled,uint32_t onboard_control_sensors_health,uint16_t load,uint16_t voltage_battery,int16_t current_battery,int8_t battery_remaining,uint16_t drop_rate_comm,uint16_t errors_comm,uint16_t errors_count1,uint16_t errors_count2,uint16_t errors_count3,uint16_t errors_count4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SYS_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); - _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); - _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); - _mav_put_uint16_t(buf, 12, load); - _mav_put_uint16_t(buf, 14, voltage_battery); - _mav_put_int16_t(buf, 16, current_battery); - _mav_put_uint16_t(buf, 18, drop_rate_comm); - _mav_put_uint16_t(buf, 20, errors_comm); - _mav_put_uint16_t(buf, 22, errors_count1); - _mav_put_uint16_t(buf, 24, errors_count2); - _mav_put_uint16_t(buf, 26, errors_count3); - _mav_put_uint16_t(buf, 28, errors_count4); - _mav_put_int8_t(buf, 30, battery_remaining); + char buf[MAVLINK_MSG_ID_SYS_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); + _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); + _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); + _mav_put_uint16_t(buf, 12, load); + _mav_put_uint16_t(buf, 14, voltage_battery); + _mav_put_int16_t(buf, 16, current_battery); + _mav_put_uint16_t(buf, 18, drop_rate_comm); + _mav_put_uint16_t(buf, 20, errors_comm); + _mav_put_uint16_t(buf, 22, errors_count1); + _mav_put_uint16_t(buf, 24, errors_count2); + _mav_put_uint16_t(buf, 26, errors_count3); + _mav_put_uint16_t(buf, 28, errors_count4); + _mav_put_int8_t(buf, 30, battery_remaining); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SYS_STATUS_LEN); #else - mavlink_sys_status_t packet; - packet.onboard_control_sensors_present = onboard_control_sensors_present; - packet.onboard_control_sensors_enabled = onboard_control_sensors_enabled; - packet.onboard_control_sensors_health = onboard_control_sensors_health; - packet.load = load; - packet.voltage_battery = voltage_battery; - packet.current_battery = current_battery; - packet.drop_rate_comm = drop_rate_comm; - packet.errors_comm = errors_comm; - packet.errors_count1 = errors_count1; - packet.errors_count2 = errors_count2; - packet.errors_count3 = errors_count3; - packet.errors_count4 = errors_count4; - packet.battery_remaining = battery_remaining; + mavlink_sys_status_t packet; + packet.onboard_control_sensors_present = onboard_control_sensors_present; + packet.onboard_control_sensors_enabled = onboard_control_sensors_enabled; + packet.onboard_control_sensors_health = onboard_control_sensors_health; + packet.load = load; + packet.voltage_battery = voltage_battery; + packet.current_battery = current_battery; + packet.drop_rate_comm = drop_rate_comm; + packet.errors_comm = errors_comm; + packet.errors_count1 = errors_count1; + packet.errors_count2 = errors_count2; + packet.errors_count3 = errors_count3; + packet.errors_count4 = errors_count4; + packet.battery_remaining = battery_remaining; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SYS_STATUS_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SYS_STATUS; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SYS_STATUS_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SYS_STATUS; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); } /** @@ -194,7 +210,7 @@ static inline uint16_t mavlink_msg_sys_status_pack_chan(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_sys_status_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_sys_status_t* sys_status) { - return mavlink_msg_sys_status_pack(system_id, component_id, msg, sys_status->onboard_control_sensors_present, sys_status->onboard_control_sensors_enabled, sys_status->onboard_control_sensors_health, sys_status->load, sys_status->voltage_battery, sys_status->current_battery, sys_status->battery_remaining, sys_status->drop_rate_comm, sys_status->errors_comm, sys_status->errors_count1, sys_status->errors_count2, sys_status->errors_count3, sys_status->errors_count4); + return mavlink_msg_sys_status_pack(system_id, component_id, msg, sys_status->onboard_control_sensors_present, sys_status->onboard_control_sensors_enabled, sys_status->onboard_control_sensors_health, sys_status->load, sys_status->voltage_battery, sys_status->current_battery, sys_status->battery_remaining, sys_status->drop_rate_comm, sys_status->errors_comm, sys_status->errors_count1, sys_status->errors_count2, sys_status->errors_count3, sys_status->errors_count4); } /** @@ -208,7 +224,7 @@ static inline uint16_t mavlink_msg_sys_status_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_sys_status_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_sys_status_t* sys_status) { - return mavlink_msg_sys_status_pack_chan(system_id, component_id, chan, msg, sys_status->onboard_control_sensors_present, sys_status->onboard_control_sensors_enabled, sys_status->onboard_control_sensors_health, sys_status->load, sys_status->voltage_battery, sys_status->current_battery, sys_status->battery_remaining, sys_status->drop_rate_comm, sys_status->errors_comm, sys_status->errors_count1, sys_status->errors_count2, sys_status->errors_count3, sys_status->errors_count4); + return mavlink_msg_sys_status_pack_chan(system_id, component_id, chan, msg, sys_status->onboard_control_sensors_present, sys_status->onboard_control_sensors_enabled, sys_status->onboard_control_sensors_health, sys_status->load, sys_status->voltage_battery, sys_status->current_battery, sys_status->battery_remaining, sys_status->drop_rate_comm, sys_status->errors_comm, sys_status->errors_count1, sys_status->errors_count2, sys_status->errors_count3, sys_status->errors_count4); } /** @@ -234,47 +250,53 @@ static inline uint16_t mavlink_msg_sys_status_encode_chan(uint8_t system_id, uin static inline void mavlink_msg_sys_status_send(mavlink_channel_t chan, uint32_t onboard_control_sensors_present, uint32_t onboard_control_sensors_enabled, uint32_t onboard_control_sensors_health, uint16_t load, uint16_t voltage_battery, int16_t current_battery, int8_t battery_remaining, uint16_t drop_rate_comm, uint16_t errors_comm, uint16_t errors_count1, uint16_t errors_count2, uint16_t errors_count3, uint16_t errors_count4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SYS_STATUS_LEN]; - _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); - _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); - _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); - _mav_put_uint16_t(buf, 12, load); - _mav_put_uint16_t(buf, 14, voltage_battery); - _mav_put_int16_t(buf, 16, current_battery); - _mav_put_uint16_t(buf, 18, drop_rate_comm); - _mav_put_uint16_t(buf, 20, errors_comm); - _mav_put_uint16_t(buf, 22, errors_count1); - _mav_put_uint16_t(buf, 24, errors_count2); - _mav_put_uint16_t(buf, 26, errors_count3); - _mav_put_uint16_t(buf, 28, errors_count4); - _mav_put_int8_t(buf, 30, battery_remaining); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, buf, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); + char buf[MAVLINK_MSG_ID_SYS_STATUS_LEN]; + _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); + _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); + _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); + _mav_put_uint16_t(buf, 12, load); + _mav_put_uint16_t(buf, 14, voltage_battery); + _mav_put_int16_t(buf, 16, current_battery); + _mav_put_uint16_t(buf, 18, drop_rate_comm); + _mav_put_uint16_t(buf, 20, errors_comm); + _mav_put_uint16_t(buf, 22, errors_count1); + _mav_put_uint16_t(buf, 24, errors_count2); + _mav_put_uint16_t(buf, 26, errors_count3); + _mav_put_uint16_t(buf, 28, errors_count4); + _mav_put_int8_t(buf, 30, battery_remaining); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, buf, MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, buf, MAVLINK_MSG_ID_SYS_STATUS_LEN); + mavlink_sys_status_t packet; + packet.onboard_control_sensors_present = onboard_control_sensors_present; + packet.onboard_control_sensors_enabled = onboard_control_sensors_enabled; + packet.onboard_control_sensors_health = onboard_control_sensors_health; + packet.load = load; + packet.voltage_battery = voltage_battery; + packet.current_battery = current_battery; + packet.drop_rate_comm = drop_rate_comm; + packet.errors_comm = errors_comm; + packet.errors_count1 = errors_count1; + packet.errors_count2 = errors_count2; + packet.errors_count3 = errors_count3; + packet.errors_count4 = errors_count4; + packet.battery_remaining = battery_remaining; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); #endif +} + +/** + * @brief Send a sys_status message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_sys_status_send_struct(mavlink_channel_t chan, const mavlink_sys_status_t* sys_status) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_sys_status_send(chan, sys_status->onboard_control_sensors_present, sys_status->onboard_control_sensors_enabled, sys_status->onboard_control_sensors_health, sys_status->load, sys_status->voltage_battery, sys_status->current_battery, sys_status->battery_remaining, sys_status->drop_rate_comm, sys_status->errors_comm, sys_status->errors_count1, sys_status->errors_count2, sys_status->errors_count3, sys_status->errors_count4); #else - mavlink_sys_status_t packet; - packet.onboard_control_sensors_present = onboard_control_sensors_present; - packet.onboard_control_sensors_enabled = onboard_control_sensors_enabled; - packet.onboard_control_sensors_health = onboard_control_sensors_health; - packet.load = load; - packet.voltage_battery = voltage_battery; - packet.current_battery = current_battery; - packet.drop_rate_comm = drop_rate_comm; - packet.errors_comm = errors_comm; - packet.errors_count1 = errors_count1; - packet.errors_count2 = errors_count2; - packet.errors_count3 = errors_count3; - packet.errors_count4 = errors_count4; - packet.battery_remaining = battery_remaining; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, (const char *)&packet, MAVLINK_MSG_ID_SYS_STATUS_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, (const char *)sys_status, MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); #endif } @@ -289,47 +311,39 @@ static inline void mavlink_msg_sys_status_send(mavlink_channel_t chan, uint32_t static inline void mavlink_msg_sys_status_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint32_t onboard_control_sensors_present, uint32_t onboard_control_sensors_enabled, uint32_t onboard_control_sensors_health, uint16_t load, uint16_t voltage_battery, int16_t current_battery, int8_t battery_remaining, uint16_t drop_rate_comm, uint16_t errors_comm, uint16_t errors_count1, uint16_t errors_count2, uint16_t errors_count3, uint16_t errors_count4) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); - _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); - _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); - _mav_put_uint16_t(buf, 12, load); - _mav_put_uint16_t(buf, 14, voltage_battery); - _mav_put_int16_t(buf, 16, current_battery); - _mav_put_uint16_t(buf, 18, drop_rate_comm); - _mav_put_uint16_t(buf, 20, errors_comm); - _mav_put_uint16_t(buf, 22, errors_count1); - _mav_put_uint16_t(buf, 24, errors_count2); - _mav_put_uint16_t(buf, 26, errors_count3); - _mav_put_uint16_t(buf, 28, errors_count4); - _mav_put_int8_t(buf, 30, battery_remaining); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, buf, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint32_t(buf, 0, onboard_control_sensors_present); + _mav_put_uint32_t(buf, 4, onboard_control_sensors_enabled); + _mav_put_uint32_t(buf, 8, onboard_control_sensors_health); + _mav_put_uint16_t(buf, 12, load); + _mav_put_uint16_t(buf, 14, voltage_battery); + _mav_put_int16_t(buf, 16, current_battery); + _mav_put_uint16_t(buf, 18, drop_rate_comm); + _mav_put_uint16_t(buf, 20, errors_comm); + _mav_put_uint16_t(buf, 22, errors_count1); + _mav_put_uint16_t(buf, 24, errors_count2); + _mav_put_uint16_t(buf, 26, errors_count3); + _mav_put_uint16_t(buf, 28, errors_count4); + _mav_put_int8_t(buf, 30, battery_remaining); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, buf, MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, buf, MAVLINK_MSG_ID_SYS_STATUS_LEN); -#endif -#else - mavlink_sys_status_t *packet = (mavlink_sys_status_t *)msgbuf; - packet->onboard_control_sensors_present = onboard_control_sensors_present; - packet->onboard_control_sensors_enabled = onboard_control_sensors_enabled; - packet->onboard_control_sensors_health = onboard_control_sensors_health; - packet->load = load; - packet->voltage_battery = voltage_battery; - packet->current_battery = current_battery; - packet->drop_rate_comm = drop_rate_comm; - packet->errors_comm = errors_comm; - packet->errors_count1 = errors_count1; - packet->errors_count2 = errors_count2; - packet->errors_count3 = errors_count3; - packet->errors_count4 = errors_count4; - packet->battery_remaining = battery_remaining; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, (const char *)packet, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, (const char *)packet, MAVLINK_MSG_ID_SYS_STATUS_LEN); -#endif + mavlink_sys_status_t *packet = (mavlink_sys_status_t *)msgbuf; + packet->onboard_control_sensors_present = onboard_control_sensors_present; + packet->onboard_control_sensors_enabled = onboard_control_sensors_enabled; + packet->onboard_control_sensors_health = onboard_control_sensors_health; + packet->load = load; + packet->voltage_battery = voltage_battery; + packet->current_battery = current_battery; + packet->drop_rate_comm = drop_rate_comm; + packet->errors_comm = errors_comm; + packet->errors_count1 = errors_count1; + packet->errors_count2 = errors_count2; + packet->errors_count3 = errors_count3; + packet->errors_count4 = errors_count4; + packet->battery_remaining = battery_remaining; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYS_STATUS, (const char *)packet, MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN, MAVLINK_MSG_ID_SYS_STATUS_LEN, MAVLINK_MSG_ID_SYS_STATUS_CRC); #endif } #endif @@ -346,7 +360,7 @@ static inline void mavlink_msg_sys_status_send_buf(mavlink_message_t *msgbuf, ma */ static inline uint32_t mavlink_msg_sys_status_get_onboard_control_sensors_present(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 0); + return _MAV_RETURN_uint32_t(msg, 0); } /** @@ -356,7 +370,7 @@ static inline uint32_t mavlink_msg_sys_status_get_onboard_control_sensors_presen */ static inline uint32_t mavlink_msg_sys_status_get_onboard_control_sensors_enabled(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 4); + return _MAV_RETURN_uint32_t(msg, 4); } /** @@ -366,7 +380,7 @@ static inline uint32_t mavlink_msg_sys_status_get_onboard_control_sensors_enable */ static inline uint32_t mavlink_msg_sys_status_get_onboard_control_sensors_health(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 8); + return _MAV_RETURN_uint32_t(msg, 8); } /** @@ -376,7 +390,7 @@ static inline uint32_t mavlink_msg_sys_status_get_onboard_control_sensors_health */ static inline uint16_t mavlink_msg_sys_status_get_load(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 12); + return _MAV_RETURN_uint16_t(msg, 12); } /** @@ -386,7 +400,7 @@ static inline uint16_t mavlink_msg_sys_status_get_load(const mavlink_message_t* */ static inline uint16_t mavlink_msg_sys_status_get_voltage_battery(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 14); + return _MAV_RETURN_uint16_t(msg, 14); } /** @@ -396,7 +410,7 @@ static inline uint16_t mavlink_msg_sys_status_get_voltage_battery(const mavlink_ */ static inline int16_t mavlink_msg_sys_status_get_current_battery(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 16); + return _MAV_RETURN_int16_t(msg, 16); } /** @@ -406,7 +420,7 @@ static inline int16_t mavlink_msg_sys_status_get_current_battery(const mavlink_m */ static inline int8_t mavlink_msg_sys_status_get_battery_remaining(const mavlink_message_t* msg) { - return _MAV_RETURN_int8_t(msg, 30); + return _MAV_RETURN_int8_t(msg, 30); } /** @@ -416,7 +430,7 @@ static inline int8_t mavlink_msg_sys_status_get_battery_remaining(const mavlink_ */ static inline uint16_t mavlink_msg_sys_status_get_drop_rate_comm(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -426,7 +440,7 @@ static inline uint16_t mavlink_msg_sys_status_get_drop_rate_comm(const mavlink_m */ static inline uint16_t mavlink_msg_sys_status_get_errors_comm(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 20); + return _MAV_RETURN_uint16_t(msg, 20); } /** @@ -436,7 +450,7 @@ static inline uint16_t mavlink_msg_sys_status_get_errors_comm(const mavlink_mess */ static inline uint16_t mavlink_msg_sys_status_get_errors_count1(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 22); + return _MAV_RETURN_uint16_t(msg, 22); } /** @@ -446,7 +460,7 @@ static inline uint16_t mavlink_msg_sys_status_get_errors_count1(const mavlink_me */ static inline uint16_t mavlink_msg_sys_status_get_errors_count2(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 24); + return _MAV_RETURN_uint16_t(msg, 24); } /** @@ -456,7 +470,7 @@ static inline uint16_t mavlink_msg_sys_status_get_errors_count2(const mavlink_me */ static inline uint16_t mavlink_msg_sys_status_get_errors_count3(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 26); + return _MAV_RETURN_uint16_t(msg, 26); } /** @@ -466,7 +480,7 @@ static inline uint16_t mavlink_msg_sys_status_get_errors_count3(const mavlink_me */ static inline uint16_t mavlink_msg_sys_status_get_errors_count4(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 28); + return _MAV_RETURN_uint16_t(msg, 28); } /** @@ -477,21 +491,23 @@ static inline uint16_t mavlink_msg_sys_status_get_errors_count4(const mavlink_me */ static inline void mavlink_msg_sys_status_decode(const mavlink_message_t* msg, mavlink_sys_status_t* sys_status) { -#if MAVLINK_NEED_BYTE_SWAP - sys_status->onboard_control_sensors_present = mavlink_msg_sys_status_get_onboard_control_sensors_present(msg); - sys_status->onboard_control_sensors_enabled = mavlink_msg_sys_status_get_onboard_control_sensors_enabled(msg); - sys_status->onboard_control_sensors_health = mavlink_msg_sys_status_get_onboard_control_sensors_health(msg); - sys_status->load = mavlink_msg_sys_status_get_load(msg); - sys_status->voltage_battery = mavlink_msg_sys_status_get_voltage_battery(msg); - sys_status->current_battery = mavlink_msg_sys_status_get_current_battery(msg); - sys_status->drop_rate_comm = mavlink_msg_sys_status_get_drop_rate_comm(msg); - sys_status->errors_comm = mavlink_msg_sys_status_get_errors_comm(msg); - sys_status->errors_count1 = mavlink_msg_sys_status_get_errors_count1(msg); - sys_status->errors_count2 = mavlink_msg_sys_status_get_errors_count2(msg); - sys_status->errors_count3 = mavlink_msg_sys_status_get_errors_count3(msg); - sys_status->errors_count4 = mavlink_msg_sys_status_get_errors_count4(msg); - sys_status->battery_remaining = mavlink_msg_sys_status_get_battery_remaining(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + sys_status->onboard_control_sensors_present = mavlink_msg_sys_status_get_onboard_control_sensors_present(msg); + sys_status->onboard_control_sensors_enabled = mavlink_msg_sys_status_get_onboard_control_sensors_enabled(msg); + sys_status->onboard_control_sensors_health = mavlink_msg_sys_status_get_onboard_control_sensors_health(msg); + sys_status->load = mavlink_msg_sys_status_get_load(msg); + sys_status->voltage_battery = mavlink_msg_sys_status_get_voltage_battery(msg); + sys_status->current_battery = mavlink_msg_sys_status_get_current_battery(msg); + sys_status->drop_rate_comm = mavlink_msg_sys_status_get_drop_rate_comm(msg); + sys_status->errors_comm = mavlink_msg_sys_status_get_errors_comm(msg); + sys_status->errors_count1 = mavlink_msg_sys_status_get_errors_count1(msg); + sys_status->errors_count2 = mavlink_msg_sys_status_get_errors_count2(msg); + sys_status->errors_count3 = mavlink_msg_sys_status_get_errors_count3(msg); + sys_status->errors_count4 = mavlink_msg_sys_status_get_errors_count4(msg); + sys_status->battery_remaining = mavlink_msg_sys_status_get_battery_remaining(msg); #else - memcpy(sys_status, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SYS_STATUS_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SYS_STATUS_LEN? msg->len : MAVLINK_MSG_ID_SYS_STATUS_LEN; + memset(sys_status, 0, MAVLINK_MSG_ID_SYS_STATUS_LEN); + memcpy(sys_status, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_system_time.h b/vendor/libraries/mavlink/common/mavlink_msg_system_time.h index 988c669c36..0e9b2ce5a8 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_system_time.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_system_time.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE SYSTEM_TIME PACKING #define MAVLINK_MSG_ID_SYSTEM_TIME 2 -typedef struct __mavlink_system_time_t -{ - uint64_t time_unix_usec; ///< Timestamp of the master clock in microseconds since UNIX epoch. - uint32_t time_boot_ms; ///< Timestamp of the component clock since boot time in milliseconds. -} mavlink_system_time_t; +MAVPACKED( +typedef struct __mavlink_system_time_t { + uint64_t time_unix_usec; /*< Timestamp of the master clock in microseconds since UNIX epoch.*/ + uint32_t time_boot_ms; /*< Timestamp of the component clock since boot time in milliseconds.*/ +}) mavlink_system_time_t; #define MAVLINK_MSG_ID_SYSTEM_TIME_LEN 12 +#define MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN 12 #define MAVLINK_MSG_ID_2_LEN 12 +#define MAVLINK_MSG_ID_2_MIN_LEN 12 #define MAVLINK_MSG_ID_SYSTEM_TIME_CRC 137 #define MAVLINK_MSG_ID_2_CRC 137 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_SYSTEM_TIME { \ - "SYSTEM_TIME", \ - 2, \ - { { "time_unix_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_system_time_t, time_unix_usec) }, \ + 2, \ + "SYSTEM_TIME", \ + 2, \ + { { "time_unix_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_system_time_t, time_unix_usec) }, \ { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_system_time_t, time_boot_ms) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_SYSTEM_TIME { \ + "SYSTEM_TIME", \ + 2, \ + { { "time_unix_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_system_time_t, time_unix_usec) }, \ + { "time_boot_ms", NULL, MAVLINK_TYPE_UINT32_T, 0, 8, offsetof(mavlink_system_time_t, time_boot_ms) }, \ + } \ +} +#endif /** * @brief Pack a system_time message @@ -36,28 +49,24 @@ typedef struct __mavlink_system_time_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_system_time_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t time_unix_usec, uint32_t time_boot_ms) + uint64_t time_unix_usec, uint32_t time_boot_ms) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SYSTEM_TIME_LEN]; - _mav_put_uint64_t(buf, 0, time_unix_usec); - _mav_put_uint32_t(buf, 8, time_boot_ms); + char buf[MAVLINK_MSG_ID_SYSTEM_TIME_LEN]; + _mav_put_uint64_t(buf, 0, time_unix_usec); + _mav_put_uint32_t(buf, 8, time_boot_ms); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); #else - mavlink_system_time_t packet; - packet.time_unix_usec = time_unix_usec; - packet.time_boot_ms = time_boot_ms; + mavlink_system_time_t packet; + packet.time_unix_usec = time_unix_usec; + packet.time_boot_ms = time_boot_ms; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SYSTEM_TIME; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SYSTEM_TIME; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_system_time_pack(uint8_t system_id, uint8_t c * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_system_time_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t time_unix_usec,uint32_t time_boot_ms) + mavlink_message_t* msg, + uint64_t time_unix_usec,uint32_t time_boot_ms) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SYSTEM_TIME_LEN]; - _mav_put_uint64_t(buf, 0, time_unix_usec); - _mav_put_uint32_t(buf, 8, time_boot_ms); + char buf[MAVLINK_MSG_ID_SYSTEM_TIME_LEN]; + _mav_put_uint64_t(buf, 0, time_unix_usec); + _mav_put_uint32_t(buf, 8, time_boot_ms); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); #else - mavlink_system_time_t packet; - packet.time_unix_usec = time_unix_usec; - packet.time_boot_ms = time_boot_ms; + mavlink_system_time_t packet; + packet.time_unix_usec = time_unix_usec; + packet.time_boot_ms = time_boot_ms; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_SYSTEM_TIME; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_SYSTEM_TIME; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_system_time_pack_chan(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_system_time_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_system_time_t* system_time) { - return mavlink_msg_system_time_pack(system_id, component_id, msg, system_time->time_unix_usec, system_time->time_boot_ms); + return mavlink_msg_system_time_pack(system_id, component_id, msg, system_time->time_unix_usec, system_time->time_boot_ms); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_system_time_encode(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_system_time_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_system_time_t* system_time) { - return mavlink_msg_system_time_pack_chan(system_id, component_id, chan, msg, system_time->time_unix_usec, system_time->time_boot_ms); + return mavlink_msg_system_time_pack_chan(system_id, component_id, chan, msg, system_time->time_unix_usec, system_time->time_boot_ms); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_system_time_encode_chan(uint8_t system_id, ui static inline void mavlink_msg_system_time_send(mavlink_channel_t chan, uint64_t time_unix_usec, uint32_t time_boot_ms) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_SYSTEM_TIME_LEN]; - _mav_put_uint64_t(buf, 0, time_unix_usec); - _mav_put_uint32_t(buf, 8, time_boot_ms); + char buf[MAVLINK_MSG_ID_SYSTEM_TIME_LEN]; + _mav_put_uint64_t(buf, 0, time_unix_usec); + _mav_put_uint32_t(buf, 8, time_boot_ms); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, buf, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, buf, MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, buf, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); + mavlink_system_time_t packet; + packet.time_unix_usec = time_unix_usec; + packet.time_boot_ms = time_boot_ms; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, (const char *)&packet, MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); #endif -#else - mavlink_system_time_t packet; - packet.time_unix_usec = time_unix_usec; - packet.time_boot_ms = time_boot_ms; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, (const char *)&packet, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); +/** + * @brief Send a system_time message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_system_time_send_struct(mavlink_channel_t chan, const mavlink_system_time_t* system_time) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_system_time_send(chan, system_time->time_unix_usec, system_time->time_boot_ms); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, (const char *)&packet, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, (const char *)system_time, MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_system_time_send(mavlink_channel_t chan, uint64_t static inline void mavlink_msg_system_time_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_unix_usec, uint32_t time_boot_ms) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, time_unix_usec); - _mav_put_uint32_t(buf, 8, time_boot_ms); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_unix_usec); + _mav_put_uint32_t(buf, 8, time_boot_ms); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, buf, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, buf, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, buf, MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); #else - mavlink_system_time_t *packet = (mavlink_system_time_t *)msgbuf; - packet->time_unix_usec = time_unix_usec; - packet->time_boot_ms = time_boot_ms; + mavlink_system_time_t *packet = (mavlink_system_time_t *)msgbuf; + packet->time_unix_usec = time_unix_usec; + packet->time_boot_ms = time_boot_ms; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, (const char *)packet, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, (const char *)packet, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_SYSTEM_TIME, (const char *)packet, MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_LEN, MAVLINK_MSG_ID_SYSTEM_TIME_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_system_time_send_buf(mavlink_message_t *msgbuf, m */ static inline uint64_t mavlink_msg_system_time_get_time_unix_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline uint64_t mavlink_msg_system_time_get_time_unix_usec(const mavlink_ */ static inline uint32_t mavlink_msg_system_time_get_time_boot_ms(const mavlink_message_t* msg) { - return _MAV_RETURN_uint32_t(msg, 8); + return _MAV_RETURN_uint32_t(msg, 8); } /** @@ -224,10 +227,12 @@ static inline uint32_t mavlink_msg_system_time_get_time_boot_ms(const mavlink_me */ static inline void mavlink_msg_system_time_decode(const mavlink_message_t* msg, mavlink_system_time_t* system_time) { -#if MAVLINK_NEED_BYTE_SWAP - system_time->time_unix_usec = mavlink_msg_system_time_get_time_unix_usec(msg); - system_time->time_boot_ms = mavlink_msg_system_time_get_time_boot_ms(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + system_time->time_unix_usec = mavlink_msg_system_time_get_time_unix_usec(msg); + system_time->time_boot_ms = mavlink_msg_system_time_get_time_boot_ms(msg); #else - memcpy(system_time, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_SYSTEM_TIME_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_SYSTEM_TIME_LEN? msg->len : MAVLINK_MSG_ID_SYSTEM_TIME_LEN; + memset(system_time, 0, MAVLINK_MSG_ID_SYSTEM_TIME_LEN); + memcpy(system_time, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_terrain_check.h b/vendor/libraries/mavlink/common/mavlink_msg_terrain_check.h index ebdf71a231..820ff336c5 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_terrain_check.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_terrain_check.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE TERRAIN_CHECK PACKING #define MAVLINK_MSG_ID_TERRAIN_CHECK 135 -typedef struct __mavlink_terrain_check_t -{ - int32_t lat; ///< Latitude (degrees *10^7) - int32_t lon; ///< Longitude (degrees *10^7) -} mavlink_terrain_check_t; +MAVPACKED( +typedef struct __mavlink_terrain_check_t { + int32_t lat; /*< Latitude (degrees *10^7)*/ + int32_t lon; /*< Longitude (degrees *10^7)*/ +}) mavlink_terrain_check_t; #define MAVLINK_MSG_ID_TERRAIN_CHECK_LEN 8 +#define MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN 8 #define MAVLINK_MSG_ID_135_LEN 8 +#define MAVLINK_MSG_ID_135_MIN_LEN 8 #define MAVLINK_MSG_ID_TERRAIN_CHECK_CRC 203 #define MAVLINK_MSG_ID_135_CRC 203 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_TERRAIN_CHECK { \ - "TERRAIN_CHECK", \ - 2, \ - { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_check_t, lat) }, \ + 135, \ + "TERRAIN_CHECK", \ + 2, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_check_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_terrain_check_t, lon) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_TERRAIN_CHECK { \ + "TERRAIN_CHECK", \ + 2, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_check_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_terrain_check_t, lon) }, \ + } \ +} +#endif /** * @brief Pack a terrain_check message @@ -36,28 +49,24 @@ typedef struct __mavlink_terrain_check_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_check_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - int32_t lat, int32_t lon) + int32_t lat, int32_t lon) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_CHECK_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); + char buf[MAVLINK_MSG_ID_TERRAIN_CHECK_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); #else - mavlink_terrain_check_t packet; - packet.lat = lat; - packet.lon = lon; + mavlink_terrain_check_t packet; + packet.lat = lat; + packet.lon = lon; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_CHECK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_CHECK; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_terrain_check_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_check_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - int32_t lat,int32_t lon) + mavlink_message_t* msg, + int32_t lat,int32_t lon) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_CHECK_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); + char buf[MAVLINK_MSG_ID_TERRAIN_CHECK_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); #else - mavlink_terrain_check_t packet; - packet.lat = lat; - packet.lon = lon; + mavlink_terrain_check_t packet; + packet.lat = lat; + packet.lon = lon; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_CHECK; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_CHECK; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_terrain_check_pack_chan(uint8_t system_id, ui */ static inline uint16_t mavlink_msg_terrain_check_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_terrain_check_t* terrain_check) { - return mavlink_msg_terrain_check_pack(system_id, component_id, msg, terrain_check->lat, terrain_check->lon); + return mavlink_msg_terrain_check_pack(system_id, component_id, msg, terrain_check->lat, terrain_check->lon); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_terrain_check_encode(uint8_t system_id, uint8 */ static inline uint16_t mavlink_msg_terrain_check_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_terrain_check_t* terrain_check) { - return mavlink_msg_terrain_check_pack_chan(system_id, component_id, chan, msg, terrain_check->lat, terrain_check->lon); + return mavlink_msg_terrain_check_pack_chan(system_id, component_id, chan, msg, terrain_check->lat, terrain_check->lon); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_terrain_check_encode_chan(uint8_t system_id, static inline void mavlink_msg_terrain_check_send(mavlink_channel_t chan, int32_t lat, int32_t lon) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_CHECK_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); + char buf[MAVLINK_MSG_ID_TERRAIN_CHECK_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, buf, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, buf, MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, buf, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); + mavlink_terrain_check_t packet; + packet.lat = lat; + packet.lon = lon; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); #endif -#else - mavlink_terrain_check_t packet; - packet.lat = lat; - packet.lon = lon; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); +/** + * @brief Send a terrain_check message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_terrain_check_send_struct(mavlink_channel_t chan, const mavlink_terrain_check_t* terrain_check) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_terrain_check_send(chan, terrain_check->lat, terrain_check->lon); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, (const char *)terrain_check, MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_terrain_check_send(mavlink_channel_t chan, int32_ static inline void mavlink_msg_terrain_check_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int32_t lat, int32_t lon) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, buf, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, buf, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, buf, MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); #else - mavlink_terrain_check_t *packet = (mavlink_terrain_check_t *)msgbuf; - packet->lat = lat; - packet->lon = lon; + mavlink_terrain_check_t *packet = (mavlink_terrain_check_t *)msgbuf; + packet->lat = lat; + packet->lon = lon; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_CHECK, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN, MAVLINK_MSG_ID_TERRAIN_CHECK_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_terrain_check_send_buf(mavlink_message_t *msgbuf, */ static inline int32_t mavlink_msg_terrain_check_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline int32_t mavlink_msg_terrain_check_get_lat(const mavlink_message_t* */ static inline int32_t mavlink_msg_terrain_check_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -224,10 +227,12 @@ static inline int32_t mavlink_msg_terrain_check_get_lon(const mavlink_message_t* */ static inline void mavlink_msg_terrain_check_decode(const mavlink_message_t* msg, mavlink_terrain_check_t* terrain_check) { -#if MAVLINK_NEED_BYTE_SWAP - terrain_check->lat = mavlink_msg_terrain_check_get_lat(msg); - terrain_check->lon = mavlink_msg_terrain_check_get_lon(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + terrain_check->lat = mavlink_msg_terrain_check_get_lat(msg); + terrain_check->lon = mavlink_msg_terrain_check_get_lon(msg); #else - memcpy(terrain_check, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_TERRAIN_CHECK_LEN? msg->len : MAVLINK_MSG_ID_TERRAIN_CHECK_LEN; + memset(terrain_check, 0, MAVLINK_MSG_ID_TERRAIN_CHECK_LEN); + memcpy(terrain_check, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_terrain_data.h b/vendor/libraries/mavlink/common/mavlink_msg_terrain_data.h index 8fc0b4322d..ac9b9be650 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_terrain_data.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_terrain_data.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE TERRAIN_DATA PACKING #define MAVLINK_MSG_ID_TERRAIN_DATA 134 -typedef struct __mavlink_terrain_data_t -{ - int32_t lat; ///< Latitude of SW corner of first grid (degrees *10^7) - int32_t lon; ///< Longitude of SW corner of first grid (in degrees *10^7) - uint16_t grid_spacing; ///< Grid spacing in meters - int16_t data[16]; ///< Terrain data in meters AMSL - uint8_t gridbit; ///< bit within the terrain request mask -} mavlink_terrain_data_t; +MAVPACKED( +typedef struct __mavlink_terrain_data_t { + int32_t lat; /*< Latitude of SW corner of first grid (degrees *10^7)*/ + int32_t lon; /*< Longitude of SW corner of first grid (in degrees *10^7)*/ + uint16_t grid_spacing; /*< Grid spacing in meters*/ + int16_t data[16]; /*< Terrain data in meters AMSL*/ + uint8_t gridbit; /*< bit within the terrain request mask*/ +}) mavlink_terrain_data_t; #define MAVLINK_MSG_ID_TERRAIN_DATA_LEN 43 +#define MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN 43 #define MAVLINK_MSG_ID_134_LEN 43 +#define MAVLINK_MSG_ID_134_MIN_LEN 43 #define MAVLINK_MSG_ID_TERRAIN_DATA_CRC 229 #define MAVLINK_MSG_ID_134_CRC 229 #define MAVLINK_MSG_TERRAIN_DATA_FIELD_DATA_LEN 16 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_TERRAIN_DATA { \ - "TERRAIN_DATA", \ - 5, \ - { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_data_t, lat) }, \ + 134, \ + "TERRAIN_DATA", \ + 5, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_data_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_terrain_data_t, lon) }, \ { "grid_spacing", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_terrain_data_t, grid_spacing) }, \ { "data", NULL, MAVLINK_TYPE_INT16_T, 16, 10, offsetof(mavlink_terrain_data_t, data) }, \ { "gridbit", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_terrain_data_t, gridbit) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_TERRAIN_DATA { \ + "TERRAIN_DATA", \ + 5, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_data_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_terrain_data_t, lon) }, \ + { "grid_spacing", NULL, MAVLINK_TYPE_UINT16_T, 0, 8, offsetof(mavlink_terrain_data_t, grid_spacing) }, \ + { "data", NULL, MAVLINK_TYPE_INT16_T, 16, 10, offsetof(mavlink_terrain_data_t, data) }, \ + { "gridbit", NULL, MAVLINK_TYPE_UINT8_T, 0, 42, offsetof(mavlink_terrain_data_t, gridbit) }, \ + } \ +} +#endif /** * @brief Pack a terrain_data message @@ -45,32 +61,28 @@ typedef struct __mavlink_terrain_data_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_data_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - int32_t lat, int32_t lon, uint16_t grid_spacing, uint8_t gridbit, const int16_t *data) + int32_t lat, int32_t lon, uint16_t grid_spacing, uint8_t gridbit, const int16_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_DATA_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_uint16_t(buf, 8, grid_spacing); - _mav_put_uint8_t(buf, 42, gridbit); - _mav_put_int16_t_array(buf, 10, data, 16); + char buf[MAVLINK_MSG_ID_TERRAIN_DATA_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_uint16_t(buf, 8, grid_spacing); + _mav_put_uint8_t(buf, 42, gridbit); + _mav_put_int16_t_array(buf, 10, data, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); #else - mavlink_terrain_data_t packet; - packet.lat = lat; - packet.lon = lon; - packet.grid_spacing = grid_spacing; - packet.gridbit = gridbit; - mav_array_memcpy(packet.data, data, sizeof(int16_t)*16); + mavlink_terrain_data_t packet; + packet.lat = lat; + packet.lon = lon; + packet.grid_spacing = grid_spacing; + packet.gridbit = gridbit; + mav_array_memcpy(packet.data, data, sizeof(int16_t)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_DATA; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); } /** @@ -87,33 +99,29 @@ static inline uint16_t mavlink_msg_terrain_data_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_data_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - int32_t lat,int32_t lon,uint16_t grid_spacing,uint8_t gridbit,const int16_t *data) + mavlink_message_t* msg, + int32_t lat,int32_t lon,uint16_t grid_spacing,uint8_t gridbit,const int16_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_DATA_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_uint16_t(buf, 8, grid_spacing); - _mav_put_uint8_t(buf, 42, gridbit); - _mav_put_int16_t_array(buf, 10, data, 16); + char buf[MAVLINK_MSG_ID_TERRAIN_DATA_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_uint16_t(buf, 8, grid_spacing); + _mav_put_uint8_t(buf, 42, gridbit); + _mav_put_int16_t_array(buf, 10, data, 16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); #else - mavlink_terrain_data_t packet; - packet.lat = lat; - packet.lon = lon; - packet.grid_spacing = grid_spacing; - packet.gridbit = gridbit; - mav_array_memcpy(packet.data, data, sizeof(int16_t)*16); + mavlink_terrain_data_t packet; + packet.lat = lat; + packet.lon = lon; + packet.grid_spacing = grid_spacing; + packet.gridbit = gridbit; + mav_array_memcpy(packet.data, data, sizeof(int16_t)*16); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_DATA; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_DATA; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); } /** @@ -126,7 +134,7 @@ static inline uint16_t mavlink_msg_terrain_data_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_terrain_data_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_terrain_data_t* terrain_data) { - return mavlink_msg_terrain_data_pack(system_id, component_id, msg, terrain_data->lat, terrain_data->lon, terrain_data->grid_spacing, terrain_data->gridbit, terrain_data->data); + return mavlink_msg_terrain_data_pack(system_id, component_id, msg, terrain_data->lat, terrain_data->lon, terrain_data->grid_spacing, terrain_data->gridbit, terrain_data->data); } /** @@ -140,7 +148,7 @@ static inline uint16_t mavlink_msg_terrain_data_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_terrain_data_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_terrain_data_t* terrain_data) { - return mavlink_msg_terrain_data_pack_chan(system_id, component_id, chan, msg, terrain_data->lat, terrain_data->lon, terrain_data->grid_spacing, terrain_data->gridbit, terrain_data->data); + return mavlink_msg_terrain_data_pack_chan(system_id, component_id, chan, msg, terrain_data->lat, terrain_data->lon, terrain_data->grid_spacing, terrain_data->gridbit, terrain_data->data); } /** @@ -158,29 +166,35 @@ static inline uint16_t mavlink_msg_terrain_data_encode_chan(uint8_t system_id, u static inline void mavlink_msg_terrain_data_send(mavlink_channel_t chan, int32_t lat, int32_t lon, uint16_t grid_spacing, uint8_t gridbit, const int16_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_DATA_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_uint16_t(buf, 8, grid_spacing); - _mav_put_uint8_t(buf, 42, gridbit); - _mav_put_int16_t_array(buf, 10, data, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, buf, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); + char buf[MAVLINK_MSG_ID_TERRAIN_DATA_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_uint16_t(buf, 8, grid_spacing); + _mav_put_uint8_t(buf, 42, gridbit); + _mav_put_int16_t_array(buf, 10, data, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, buf, MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, buf, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); + mavlink_terrain_data_t packet; + packet.lat = lat; + packet.lon = lon; + packet.grid_spacing = grid_spacing; + packet.gridbit = gridbit; + mav_array_memcpy(packet.data, data, sizeof(int16_t)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); #endif +} + +/** + * @brief Send a terrain_data message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_terrain_data_send_struct(mavlink_channel_t chan, const mavlink_terrain_data_t* terrain_data) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_terrain_data_send(chan, terrain_data->lat, terrain_data->lon, terrain_data->grid_spacing, terrain_data->gridbit, terrain_data->data); #else - mavlink_terrain_data_t packet; - packet.lat = lat; - packet.lon = lon; - packet.grid_spacing = grid_spacing; - packet.gridbit = gridbit; - mav_array_memcpy(packet.data, data, sizeof(int16_t)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, (const char *)terrain_data, MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); #endif } @@ -195,29 +209,21 @@ static inline void mavlink_msg_terrain_data_send(mavlink_channel_t chan, int32_t static inline void mavlink_msg_terrain_data_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int32_t lat, int32_t lon, uint16_t grid_spacing, uint8_t gridbit, const int16_t *data) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_uint16_t(buf, 8, grid_spacing); - _mav_put_uint8_t(buf, 42, gridbit); - _mav_put_int16_t_array(buf, 10, data, 16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, buf, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_uint16_t(buf, 8, grid_spacing); + _mav_put_uint8_t(buf, 42, gridbit); + _mav_put_int16_t_array(buf, 10, data, 16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, buf, MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, buf, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); -#endif -#else - mavlink_terrain_data_t *packet = (mavlink_terrain_data_t *)msgbuf; - packet->lat = lat; - packet->lon = lon; - packet->grid_spacing = grid_spacing; - packet->gridbit = gridbit; - mav_array_memcpy(packet->data, data, sizeof(int16_t)*16); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); -#endif + mavlink_terrain_data_t *packet = (mavlink_terrain_data_t *)msgbuf; + packet->lat = lat; + packet->lon = lon; + packet->grid_spacing = grid_spacing; + packet->gridbit = gridbit; + mav_array_memcpy(packet->data, data, sizeof(int16_t)*16); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_DATA, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_LEN, MAVLINK_MSG_ID_TERRAIN_DATA_CRC); #endif } #endif @@ -234,7 +240,7 @@ static inline void mavlink_msg_terrain_data_send_buf(mavlink_message_t *msgbuf, */ static inline int32_t mavlink_msg_terrain_data_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -244,7 +250,7 @@ static inline int32_t mavlink_msg_terrain_data_get_lat(const mavlink_message_t* */ static inline int32_t mavlink_msg_terrain_data_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -254,7 +260,7 @@ static inline int32_t mavlink_msg_terrain_data_get_lon(const mavlink_message_t* */ static inline uint16_t mavlink_msg_terrain_data_get_grid_spacing(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 8); + return _MAV_RETURN_uint16_t(msg, 8); } /** @@ -264,7 +270,7 @@ static inline uint16_t mavlink_msg_terrain_data_get_grid_spacing(const mavlink_m */ static inline uint8_t mavlink_msg_terrain_data_get_gridbit(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 42); + return _MAV_RETURN_uint8_t(msg, 42); } /** @@ -274,7 +280,7 @@ static inline uint8_t mavlink_msg_terrain_data_get_gridbit(const mavlink_message */ static inline uint16_t mavlink_msg_terrain_data_get_data(const mavlink_message_t* msg, int16_t *data) { - return _MAV_RETURN_int16_t_array(msg, data, 16, 10); + return _MAV_RETURN_int16_t_array(msg, data, 16, 10); } /** @@ -285,13 +291,15 @@ static inline uint16_t mavlink_msg_terrain_data_get_data(const mavlink_message_t */ static inline void mavlink_msg_terrain_data_decode(const mavlink_message_t* msg, mavlink_terrain_data_t* terrain_data) { -#if MAVLINK_NEED_BYTE_SWAP - terrain_data->lat = mavlink_msg_terrain_data_get_lat(msg); - terrain_data->lon = mavlink_msg_terrain_data_get_lon(msg); - terrain_data->grid_spacing = mavlink_msg_terrain_data_get_grid_spacing(msg); - mavlink_msg_terrain_data_get_data(msg, terrain_data->data); - terrain_data->gridbit = mavlink_msg_terrain_data_get_gridbit(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + terrain_data->lat = mavlink_msg_terrain_data_get_lat(msg); + terrain_data->lon = mavlink_msg_terrain_data_get_lon(msg); + terrain_data->grid_spacing = mavlink_msg_terrain_data_get_grid_spacing(msg); + mavlink_msg_terrain_data_get_data(msg, terrain_data->data); + terrain_data->gridbit = mavlink_msg_terrain_data_get_gridbit(msg); #else - memcpy(terrain_data, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_TERRAIN_DATA_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_TERRAIN_DATA_LEN? msg->len : MAVLINK_MSG_ID_TERRAIN_DATA_LEN; + memset(terrain_data, 0, MAVLINK_MSG_ID_TERRAIN_DATA_LEN); + memcpy(terrain_data, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_terrain_report.h b/vendor/libraries/mavlink/common/mavlink_msg_terrain_report.h index 1b61dd4bf9..1374db5bc0 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_terrain_report.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_terrain_report.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE TERRAIN_REPORT PACKING #define MAVLINK_MSG_ID_TERRAIN_REPORT 136 -typedef struct __mavlink_terrain_report_t -{ - int32_t lat; ///< Latitude (degrees *10^7) - int32_t lon; ///< Longitude (degrees *10^7) - float terrain_height; ///< Terrain height in meters AMSL - float current_height; ///< Current vehicle height above lat/lon terrain height (meters) - uint16_t spacing; ///< grid spacing (zero if terrain at this location unavailable) - uint16_t pending; ///< Number of 4x4 terrain blocks waiting to be received or read from disk - uint16_t loaded; ///< Number of 4x4 terrain blocks in memory -} mavlink_terrain_report_t; +MAVPACKED( +typedef struct __mavlink_terrain_report_t { + int32_t lat; /*< Latitude (degrees *10^7)*/ + int32_t lon; /*< Longitude (degrees *10^7)*/ + float terrain_height; /*< Terrain height in meters AMSL*/ + float current_height; /*< Current vehicle height above lat/lon terrain height (meters)*/ + uint16_t spacing; /*< grid spacing (zero if terrain at this location unavailable)*/ + uint16_t pending; /*< Number of 4x4 terrain blocks waiting to be received or read from disk*/ + uint16_t loaded; /*< Number of 4x4 terrain blocks in memory*/ +}) mavlink_terrain_report_t; #define MAVLINK_MSG_ID_TERRAIN_REPORT_LEN 22 +#define MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN 22 #define MAVLINK_MSG_ID_136_LEN 22 +#define MAVLINK_MSG_ID_136_MIN_LEN 22 #define MAVLINK_MSG_ID_TERRAIN_REPORT_CRC 1 #define MAVLINK_MSG_ID_136_CRC 1 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_TERRAIN_REPORT { \ - "TERRAIN_REPORT", \ - 7, \ - { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_report_t, lat) }, \ + 136, \ + "TERRAIN_REPORT", \ + 7, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_report_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_terrain_report_t, lon) }, \ { "terrain_height", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_terrain_report_t, terrain_height) }, \ { "current_height", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_terrain_report_t, current_height) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_terrain_report_t { "loaded", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_terrain_report_t, loaded) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_TERRAIN_REPORT { \ + "TERRAIN_REPORT", \ + 7, \ + { { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 0, offsetof(mavlink_terrain_report_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 4, offsetof(mavlink_terrain_report_t, lon) }, \ + { "terrain_height", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_terrain_report_t, terrain_height) }, \ + { "current_height", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_terrain_report_t, current_height) }, \ + { "spacing", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_terrain_report_t, spacing) }, \ + { "pending", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_terrain_report_t, pending) }, \ + { "loaded", NULL, MAVLINK_TYPE_UINT16_T, 0, 20, offsetof(mavlink_terrain_report_t, loaded) }, \ + } \ +} +#endif /** * @brief Pack a terrain_report message @@ -51,38 +69,34 @@ typedef struct __mavlink_terrain_report_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_report_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - int32_t lat, int32_t lon, uint16_t spacing, float terrain_height, float current_height, uint16_t pending, uint16_t loaded) + int32_t lat, int32_t lon, uint16_t spacing, float terrain_height, float current_height, uint16_t pending, uint16_t loaded) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_REPORT_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_float(buf, 8, terrain_height); - _mav_put_float(buf, 12, current_height); - _mav_put_uint16_t(buf, 16, spacing); - _mav_put_uint16_t(buf, 18, pending); - _mav_put_uint16_t(buf, 20, loaded); + char buf[MAVLINK_MSG_ID_TERRAIN_REPORT_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_float(buf, 8, terrain_height); + _mav_put_float(buf, 12, current_height); + _mav_put_uint16_t(buf, 16, spacing); + _mav_put_uint16_t(buf, 18, pending); + _mav_put_uint16_t(buf, 20, loaded); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); #else - mavlink_terrain_report_t packet; - packet.lat = lat; - packet.lon = lon; - packet.terrain_height = terrain_height; - packet.current_height = current_height; - packet.spacing = spacing; - packet.pending = pending; - packet.loaded = loaded; + mavlink_terrain_report_t packet; + packet.lat = lat; + packet.lon = lon; + packet.terrain_height = terrain_height; + packet.current_height = current_height; + packet.spacing = spacing; + packet.pending = pending; + packet.loaded = loaded; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_REPORT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_REPORT; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_terrain_report_pack(uint8_t system_id, uint8_ * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_report_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - int32_t lat,int32_t lon,uint16_t spacing,float terrain_height,float current_height,uint16_t pending,uint16_t loaded) + mavlink_message_t* msg, + int32_t lat,int32_t lon,uint16_t spacing,float terrain_height,float current_height,uint16_t pending,uint16_t loaded) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_REPORT_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_float(buf, 8, terrain_height); - _mav_put_float(buf, 12, current_height); - _mav_put_uint16_t(buf, 16, spacing); - _mav_put_uint16_t(buf, 18, pending); - _mav_put_uint16_t(buf, 20, loaded); + char buf[MAVLINK_MSG_ID_TERRAIN_REPORT_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_float(buf, 8, terrain_height); + _mav_put_float(buf, 12, current_height); + _mav_put_uint16_t(buf, 16, spacing); + _mav_put_uint16_t(buf, 18, pending); + _mav_put_uint16_t(buf, 20, loaded); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); #else - mavlink_terrain_report_t packet; - packet.lat = lat; - packet.lon = lon; - packet.terrain_height = terrain_height; - packet.current_height = current_height; - packet.spacing = spacing; - packet.pending = pending; - packet.loaded = loaded; + mavlink_terrain_report_t packet; + packet.lat = lat; + packet.lon = lon; + packet.terrain_height = terrain_height; + packet.current_height = current_height; + packet.spacing = spacing; + packet.pending = pending; + packet.loaded = loaded; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_REPORT; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_REPORT; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_terrain_report_pack_chan(uint8_t system_id, u */ static inline uint16_t mavlink_msg_terrain_report_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_terrain_report_t* terrain_report) { - return mavlink_msg_terrain_report_pack(system_id, component_id, msg, terrain_report->lat, terrain_report->lon, terrain_report->spacing, terrain_report->terrain_height, terrain_report->current_height, terrain_report->pending, terrain_report->loaded); + return mavlink_msg_terrain_report_pack(system_id, component_id, msg, terrain_report->lat, terrain_report->lon, terrain_report->spacing, terrain_report->terrain_height, terrain_report->current_height, terrain_report->pending, terrain_report->loaded); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_terrain_report_encode(uint8_t system_id, uint */ static inline uint16_t mavlink_msg_terrain_report_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_terrain_report_t* terrain_report) { - return mavlink_msg_terrain_report_pack_chan(system_id, component_id, chan, msg, terrain_report->lat, terrain_report->lon, terrain_report->spacing, terrain_report->terrain_height, terrain_report->current_height, terrain_report->pending, terrain_report->loaded); + return mavlink_msg_terrain_report_pack_chan(system_id, component_id, chan, msg, terrain_report->lat, terrain_report->lon, terrain_report->spacing, terrain_report->terrain_height, terrain_report->current_height, terrain_report->pending, terrain_report->loaded); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_terrain_report_encode_chan(uint8_t system_id, static inline void mavlink_msg_terrain_report_send(mavlink_channel_t chan, int32_t lat, int32_t lon, uint16_t spacing, float terrain_height, float current_height, uint16_t pending, uint16_t loaded) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_REPORT_LEN]; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_float(buf, 8, terrain_height); - _mav_put_float(buf, 12, current_height); - _mav_put_uint16_t(buf, 16, spacing); - _mav_put_uint16_t(buf, 18, pending); - _mav_put_uint16_t(buf, 20, loaded); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, buf, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); + char buf[MAVLINK_MSG_ID_TERRAIN_REPORT_LEN]; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_float(buf, 8, terrain_height); + _mav_put_float(buf, 12, current_height); + _mav_put_uint16_t(buf, 16, spacing); + _mav_put_uint16_t(buf, 18, pending); + _mav_put_uint16_t(buf, 20, loaded); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, buf, MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, buf, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); + mavlink_terrain_report_t packet; + packet.lat = lat; + packet.lon = lon; + packet.terrain_height = terrain_height; + packet.current_height = current_height; + packet.spacing = spacing; + packet.pending = pending; + packet.loaded = loaded; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); #endif +} + +/** + * @brief Send a terrain_report message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_terrain_report_send_struct(mavlink_channel_t chan, const mavlink_terrain_report_t* terrain_report) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_terrain_report_send(chan, terrain_report->lat, terrain_report->lon, terrain_report->spacing, terrain_report->terrain_height, terrain_report->current_height, terrain_report->pending, terrain_report->loaded); #else - mavlink_terrain_report_t packet; - packet.lat = lat; - packet.lon = lon; - packet.terrain_height = terrain_height; - packet.current_height = current_height; - packet.spacing = spacing; - packet.pending = pending; - packet.loaded = loaded; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, (const char *)terrain_report, MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_terrain_report_send(mavlink_channel_t chan, int32 static inline void mavlink_msg_terrain_report_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int32_t lat, int32_t lon, uint16_t spacing, float terrain_height, float current_height, uint16_t pending, uint16_t loaded) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int32_t(buf, 0, lat); - _mav_put_int32_t(buf, 4, lon); - _mav_put_float(buf, 8, terrain_height); - _mav_put_float(buf, 12, current_height); - _mav_put_uint16_t(buf, 16, spacing); - _mav_put_uint16_t(buf, 18, pending); - _mav_put_uint16_t(buf, 20, loaded); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, buf, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, buf, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); -#endif -#else - mavlink_terrain_report_t *packet = (mavlink_terrain_report_t *)msgbuf; - packet->lat = lat; - packet->lon = lon; - packet->terrain_height = terrain_height; - packet->current_height = current_height; - packet->spacing = spacing; - packet->pending = pending; - packet->loaded = loaded; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); + char *buf = (char *)msgbuf; + _mav_put_int32_t(buf, 0, lat); + _mav_put_int32_t(buf, 4, lon); + _mav_put_float(buf, 8, terrain_height); + _mav_put_float(buf, 12, current_height); + _mav_put_uint16_t(buf, 16, spacing); + _mav_put_uint16_t(buf, 18, pending); + _mav_put_uint16_t(buf, 20, loaded); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, buf, MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); -#endif + mavlink_terrain_report_t *packet = (mavlink_terrain_report_t *)msgbuf; + packet->lat = lat; + packet->lon = lon; + packet->terrain_height = terrain_height; + packet->current_height = current_height; + packet->spacing = spacing; + packet->pending = pending; + packet->loaded = loaded; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REPORT, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN, MAVLINK_MSG_ID_TERRAIN_REPORT_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_terrain_report_send_buf(mavlink_message_t *msgbuf */ static inline int32_t mavlink_msg_terrain_report_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 0); + return _MAV_RETURN_int32_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline int32_t mavlink_msg_terrain_report_get_lat(const mavlink_message_t */ static inline int32_t mavlink_msg_terrain_report_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 4); + return _MAV_RETURN_int32_t(msg, 4); } /** @@ -288,7 +296,7 @@ static inline int32_t mavlink_msg_terrain_report_get_lon(const mavlink_message_t */ static inline uint16_t mavlink_msg_terrain_report_get_spacing(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** @@ -298,7 +306,7 @@ static inline uint16_t mavlink_msg_terrain_report_get_spacing(const mavlink_mess */ static inline float mavlink_msg_terrain_report_get_terrain_height(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_terrain_report_get_terrain_height(const mavlink_ */ static inline float mavlink_msg_terrain_report_get_current_height(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_terrain_report_get_current_height(const mavlink_ */ static inline uint16_t mavlink_msg_terrain_report_get_pending(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -328,7 +336,7 @@ static inline uint16_t mavlink_msg_terrain_report_get_pending(const mavlink_mess */ static inline uint16_t mavlink_msg_terrain_report_get_loaded(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 20); + return _MAV_RETURN_uint16_t(msg, 20); } /** @@ -339,15 +347,17 @@ static inline uint16_t mavlink_msg_terrain_report_get_loaded(const mavlink_messa */ static inline void mavlink_msg_terrain_report_decode(const mavlink_message_t* msg, mavlink_terrain_report_t* terrain_report) { -#if MAVLINK_NEED_BYTE_SWAP - terrain_report->lat = mavlink_msg_terrain_report_get_lat(msg); - terrain_report->lon = mavlink_msg_terrain_report_get_lon(msg); - terrain_report->terrain_height = mavlink_msg_terrain_report_get_terrain_height(msg); - terrain_report->current_height = mavlink_msg_terrain_report_get_current_height(msg); - terrain_report->spacing = mavlink_msg_terrain_report_get_spacing(msg); - terrain_report->pending = mavlink_msg_terrain_report_get_pending(msg); - terrain_report->loaded = mavlink_msg_terrain_report_get_loaded(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + terrain_report->lat = mavlink_msg_terrain_report_get_lat(msg); + terrain_report->lon = mavlink_msg_terrain_report_get_lon(msg); + terrain_report->terrain_height = mavlink_msg_terrain_report_get_terrain_height(msg); + terrain_report->current_height = mavlink_msg_terrain_report_get_current_height(msg); + terrain_report->spacing = mavlink_msg_terrain_report_get_spacing(msg); + terrain_report->pending = mavlink_msg_terrain_report_get_pending(msg); + terrain_report->loaded = mavlink_msg_terrain_report_get_loaded(msg); #else - memcpy(terrain_report, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_TERRAIN_REPORT_LEN? msg->len : MAVLINK_MSG_ID_TERRAIN_REPORT_LEN; + memset(terrain_report, 0, MAVLINK_MSG_ID_TERRAIN_REPORT_LEN); + memcpy(terrain_report, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_terrain_request.h b/vendor/libraries/mavlink/common/mavlink_msg_terrain_request.h index 3a85b8564f..8924ed4f19 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_terrain_request.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_terrain_request.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE TERRAIN_REQUEST PACKING #define MAVLINK_MSG_ID_TERRAIN_REQUEST 133 -typedef struct __mavlink_terrain_request_t -{ - uint64_t mask; ///< Bitmask of requested 4x4 grids (row major 8x7 array of grids, 56 bits) - int32_t lat; ///< Latitude of SW corner of first grid (degrees *10^7) - int32_t lon; ///< Longitude of SW corner of first grid (in degrees *10^7) - uint16_t grid_spacing; ///< Grid spacing in meters -} mavlink_terrain_request_t; +MAVPACKED( +typedef struct __mavlink_terrain_request_t { + uint64_t mask; /*< Bitmask of requested 4x4 grids (row major 8x7 array of grids, 56 bits)*/ + int32_t lat; /*< Latitude of SW corner of first grid (degrees *10^7)*/ + int32_t lon; /*< Longitude of SW corner of first grid (in degrees *10^7)*/ + uint16_t grid_spacing; /*< Grid spacing in meters*/ +}) mavlink_terrain_request_t; #define MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN 18 +#define MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN 18 #define MAVLINK_MSG_ID_133_LEN 18 +#define MAVLINK_MSG_ID_133_MIN_LEN 18 #define MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC 6 #define MAVLINK_MSG_ID_133_CRC 6 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_TERRAIN_REQUEST { \ - "TERRAIN_REQUEST", \ - 4, \ - { { "mask", "0x%07x", MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_terrain_request_t, mask) }, \ + 133, \ + "TERRAIN_REQUEST", \ + 4, \ + { { "mask", "0x%07x", MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_terrain_request_t, mask) }, \ { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_terrain_request_t, lat) }, \ { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_terrain_request_t, lon) }, \ { "grid_spacing", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_terrain_request_t, grid_spacing) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_TERRAIN_REQUEST { \ + "TERRAIN_REQUEST", \ + 4, \ + { { "mask", "0x%07x", MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_terrain_request_t, mask) }, \ + { "lat", NULL, MAVLINK_TYPE_INT32_T, 0, 8, offsetof(mavlink_terrain_request_t, lat) }, \ + { "lon", NULL, MAVLINK_TYPE_INT32_T, 0, 12, offsetof(mavlink_terrain_request_t, lon) }, \ + { "grid_spacing", NULL, MAVLINK_TYPE_UINT16_T, 0, 16, offsetof(mavlink_terrain_request_t, grid_spacing) }, \ + } \ +} +#endif /** * @brief Pack a terrain_request message @@ -42,32 +57,28 @@ typedef struct __mavlink_terrain_request_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_request_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - int32_t lat, int32_t lon, uint16_t grid_spacing, uint64_t mask) + int32_t lat, int32_t lon, uint16_t grid_spacing, uint64_t mask) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN]; - _mav_put_uint64_t(buf, 0, mask); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_uint16_t(buf, 16, grid_spacing); + char buf[MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN]; + _mav_put_uint64_t(buf, 0, mask); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_uint16_t(buf, 16, grid_spacing); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); #else - mavlink_terrain_request_t packet; - packet.mask = mask; - packet.lat = lat; - packet.lon = lon; - packet.grid_spacing = grid_spacing; + mavlink_terrain_request_t packet; + packet.mask = mask; + packet.lat = lat; + packet.lon = lon; + packet.grid_spacing = grid_spacing; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_REQUEST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_REQUEST; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_terrain_request_pack(uint8_t system_id, uint8 * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_terrain_request_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - int32_t lat,int32_t lon,uint16_t grid_spacing,uint64_t mask) + mavlink_message_t* msg, + int32_t lat,int32_t lon,uint16_t grid_spacing,uint64_t mask) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN]; - _mav_put_uint64_t(buf, 0, mask); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_uint16_t(buf, 16, grid_spacing); + char buf[MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN]; + _mav_put_uint64_t(buf, 0, mask); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_uint16_t(buf, 16, grid_spacing); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); #else - mavlink_terrain_request_t packet; - packet.mask = mask; - packet.lat = lat; - packet.lon = lon; - packet.grid_spacing = grid_spacing; + mavlink_terrain_request_t packet; + packet.mask = mask; + packet.lat = lat; + packet.lon = lon; + packet.grid_spacing = grid_spacing; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TERRAIN_REQUEST; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TERRAIN_REQUEST; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_terrain_request_pack_chan(uint8_t system_id, */ static inline uint16_t mavlink_msg_terrain_request_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_terrain_request_t* terrain_request) { - return mavlink_msg_terrain_request_pack(system_id, component_id, msg, terrain_request->lat, terrain_request->lon, terrain_request->grid_spacing, terrain_request->mask); + return mavlink_msg_terrain_request_pack(system_id, component_id, msg, terrain_request->lat, terrain_request->lon, terrain_request->grid_spacing, terrain_request->mask); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_terrain_request_encode(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_terrain_request_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_terrain_request_t* terrain_request) { - return mavlink_msg_terrain_request_pack_chan(system_id, component_id, chan, msg, terrain_request->lat, terrain_request->lon, terrain_request->grid_spacing, terrain_request->mask); + return mavlink_msg_terrain_request_pack_chan(system_id, component_id, chan, msg, terrain_request->lat, terrain_request->lon, terrain_request->grid_spacing, terrain_request->mask); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_terrain_request_encode_chan(uint8_t system_id static inline void mavlink_msg_terrain_request_send(mavlink_channel_t chan, int32_t lat, int32_t lon, uint16_t grid_spacing, uint64_t mask) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN]; - _mav_put_uint64_t(buf, 0, mask); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_uint16_t(buf, 16, grid_spacing); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); + char buf[MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN]; + _mav_put_uint64_t(buf, 0, mask); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_uint16_t(buf, 16, grid_spacing); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); + mavlink_terrain_request_t packet; + packet.mask = mask; + packet.lat = lat; + packet.lon = lon; + packet.grid_spacing = grid_spacing; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); #endif +} + +/** + * @brief Send a terrain_request message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_terrain_request_send_struct(mavlink_channel_t chan, const mavlink_terrain_request_t* terrain_request) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_terrain_request_send(chan, terrain_request->lat, terrain_request->lon, terrain_request->grid_spacing, terrain_request->mask); #else - mavlink_terrain_request_t packet; - packet.mask = mask; - packet.lat = lat; - packet.lon = lon; - packet.grid_spacing = grid_spacing; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, (const char *)&packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, (const char *)terrain_request, MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_terrain_request_send(mavlink_channel_t chan, int3 static inline void mavlink_msg_terrain_request_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int32_t lat, int32_t lon, uint16_t grid_spacing, uint64_t mask) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, mask); - _mav_put_int32_t(buf, 8, lat); - _mav_put_int32_t(buf, 12, lon); - _mav_put_uint16_t(buf, 16, grid_spacing); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); -#endif -#else - mavlink_terrain_request_t *packet = (mavlink_terrain_request_t *)msgbuf; - packet->mask = mask; - packet->lat = lat; - packet->lon = lon; - packet->grid_spacing = grid_spacing; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, mask); + _mav_put_int32_t(buf, 8, lat); + _mav_put_int32_t(buf, 12, lon); + _mav_put_uint16_t(buf, 16, grid_spacing); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, buf, MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); -#endif + mavlink_terrain_request_t *packet = (mavlink_terrain_request_t *)msgbuf; + packet->mask = mask; + packet->lat = lat; + packet->lon = lon; + packet->grid_spacing = grid_spacing; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TERRAIN_REQUEST, (const char *)packet, MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN, MAVLINK_MSG_ID_TERRAIN_REQUEST_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_terrain_request_send_buf(mavlink_message_t *msgbu */ static inline int32_t mavlink_msg_terrain_request_get_lat(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 8); + return _MAV_RETURN_int32_t(msg, 8); } /** @@ -239,7 +244,7 @@ static inline int32_t mavlink_msg_terrain_request_get_lat(const mavlink_message_ */ static inline int32_t mavlink_msg_terrain_request_get_lon(const mavlink_message_t* msg) { - return _MAV_RETURN_int32_t(msg, 12); + return _MAV_RETURN_int32_t(msg, 12); } /** @@ -249,7 +254,7 @@ static inline int32_t mavlink_msg_terrain_request_get_lon(const mavlink_message_ */ static inline uint16_t mavlink_msg_terrain_request_get_grid_spacing(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 16); + return _MAV_RETURN_uint16_t(msg, 16); } /** @@ -259,7 +264,7 @@ static inline uint16_t mavlink_msg_terrain_request_get_grid_spacing(const mavlin */ static inline uint64_t mavlink_msg_terrain_request_get_mask(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -270,12 +275,14 @@ static inline uint64_t mavlink_msg_terrain_request_get_mask(const mavlink_messag */ static inline void mavlink_msg_terrain_request_decode(const mavlink_message_t* msg, mavlink_terrain_request_t* terrain_request) { -#if MAVLINK_NEED_BYTE_SWAP - terrain_request->mask = mavlink_msg_terrain_request_get_mask(msg); - terrain_request->lat = mavlink_msg_terrain_request_get_lat(msg); - terrain_request->lon = mavlink_msg_terrain_request_get_lon(msg); - terrain_request->grid_spacing = mavlink_msg_terrain_request_get_grid_spacing(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + terrain_request->mask = mavlink_msg_terrain_request_get_mask(msg); + terrain_request->lat = mavlink_msg_terrain_request_get_lat(msg); + terrain_request->lon = mavlink_msg_terrain_request_get_lon(msg); + terrain_request->grid_spacing = mavlink_msg_terrain_request_get_grid_spacing(msg); #else - memcpy(terrain_request, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN? msg->len : MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN; + memset(terrain_request, 0, MAVLINK_MSG_ID_TERRAIN_REQUEST_LEN); + memcpy(terrain_request, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_timesync.h b/vendor/libraries/mavlink/common/mavlink_msg_timesync.h index 6f1d5e107b..395211fd8b 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_timesync.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_timesync.h @@ -1,29 +1,42 @@ +#pragma once // MESSAGE TIMESYNC PACKING #define MAVLINK_MSG_ID_TIMESYNC 111 -typedef struct __mavlink_timesync_t -{ - int64_t tc1; ///< Time sync timestamp 1 - int64_t ts1; ///< Time sync timestamp 2 -} mavlink_timesync_t; +MAVPACKED( +typedef struct __mavlink_timesync_t { + int64_t tc1; /*< Time sync timestamp 1*/ + int64_t ts1; /*< Time sync timestamp 2*/ +}) mavlink_timesync_t; #define MAVLINK_MSG_ID_TIMESYNC_LEN 16 +#define MAVLINK_MSG_ID_TIMESYNC_MIN_LEN 16 #define MAVLINK_MSG_ID_111_LEN 16 +#define MAVLINK_MSG_ID_111_MIN_LEN 16 #define MAVLINK_MSG_ID_TIMESYNC_CRC 34 #define MAVLINK_MSG_ID_111_CRC 34 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_TIMESYNC { \ - "TIMESYNC", \ - 2, \ - { { "tc1", NULL, MAVLINK_TYPE_INT64_T, 0, 0, offsetof(mavlink_timesync_t, tc1) }, \ + 111, \ + "TIMESYNC", \ + 2, \ + { { "tc1", NULL, MAVLINK_TYPE_INT64_T, 0, 0, offsetof(mavlink_timesync_t, tc1) }, \ { "ts1", NULL, MAVLINK_TYPE_INT64_T, 0, 8, offsetof(mavlink_timesync_t, ts1) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_TIMESYNC { \ + "TIMESYNC", \ + 2, \ + { { "tc1", NULL, MAVLINK_TYPE_INT64_T, 0, 0, offsetof(mavlink_timesync_t, tc1) }, \ + { "ts1", NULL, MAVLINK_TYPE_INT64_T, 0, 8, offsetof(mavlink_timesync_t, ts1) }, \ + } \ +} +#endif /** * @brief Pack a timesync message @@ -36,28 +49,24 @@ typedef struct __mavlink_timesync_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_timesync_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - int64_t tc1, int64_t ts1) + int64_t tc1, int64_t ts1) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TIMESYNC_LEN]; - _mav_put_int64_t(buf, 0, tc1); - _mav_put_int64_t(buf, 8, ts1); + char buf[MAVLINK_MSG_ID_TIMESYNC_LEN]; + _mav_put_int64_t(buf, 0, tc1); + _mav_put_int64_t(buf, 8, ts1); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TIMESYNC_LEN); #else - mavlink_timesync_t packet; - packet.tc1 = tc1; - packet.ts1 = ts1; + mavlink_timesync_t packet; + packet.tc1 = tc1; + packet.ts1 = ts1; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TIMESYNC_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TIMESYNC; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TIMESYNC_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TIMESYNC; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_TIMESYNC_MIN_LEN, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); } /** @@ -71,29 +80,25 @@ static inline uint16_t mavlink_msg_timesync_pack(uint8_t system_id, uint8_t comp * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_timesync_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - int64_t tc1,int64_t ts1) + mavlink_message_t* msg, + int64_t tc1,int64_t ts1) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TIMESYNC_LEN]; - _mav_put_int64_t(buf, 0, tc1); - _mav_put_int64_t(buf, 8, ts1); + char buf[MAVLINK_MSG_ID_TIMESYNC_LEN]; + _mav_put_int64_t(buf, 0, tc1); + _mav_put_int64_t(buf, 8, ts1); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_TIMESYNC_LEN); #else - mavlink_timesync_t packet; - packet.tc1 = tc1; - packet.ts1 = ts1; + mavlink_timesync_t packet; + packet.tc1 = tc1; + packet.ts1 = ts1; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_TIMESYNC_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_TIMESYNC; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TIMESYNC_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_TIMESYNC; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_TIMESYNC_MIN_LEN, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); } /** @@ -106,7 +111,7 @@ static inline uint16_t mavlink_msg_timesync_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_timesync_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_timesync_t* timesync) { - return mavlink_msg_timesync_pack(system_id, component_id, msg, timesync->tc1, timesync->ts1); + return mavlink_msg_timesync_pack(system_id, component_id, msg, timesync->tc1, timesync->ts1); } /** @@ -120,7 +125,7 @@ static inline uint16_t mavlink_msg_timesync_encode(uint8_t system_id, uint8_t co */ static inline uint16_t mavlink_msg_timesync_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_timesync_t* timesync) { - return mavlink_msg_timesync_pack_chan(system_id, component_id, chan, msg, timesync->tc1, timesync->ts1); + return mavlink_msg_timesync_pack_chan(system_id, component_id, chan, msg, timesync->tc1, timesync->ts1); } /** @@ -135,25 +140,31 @@ static inline uint16_t mavlink_msg_timesync_encode_chan(uint8_t system_id, uint8 static inline void mavlink_msg_timesync_send(mavlink_channel_t chan, int64_t tc1, int64_t ts1) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_TIMESYNC_LEN]; - _mav_put_int64_t(buf, 0, tc1); - _mav_put_int64_t(buf, 8, ts1); + char buf[MAVLINK_MSG_ID_TIMESYNC_LEN]; + _mav_put_int64_t(buf, 0, tc1); + _mav_put_int64_t(buf, 8, ts1); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, buf, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, buf, MAVLINK_MSG_ID_TIMESYNC_MIN_LEN, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, buf, MAVLINK_MSG_ID_TIMESYNC_LEN); + mavlink_timesync_t packet; + packet.tc1 = tc1; + packet.ts1 = ts1; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, (const char *)&packet, MAVLINK_MSG_ID_TIMESYNC_MIN_LEN, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); #endif -#else - mavlink_timesync_t packet; - packet.tc1 = tc1; - packet.ts1 = ts1; +} -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, (const char *)&packet, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); +/** + * @brief Send a timesync message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_timesync_send_struct(mavlink_channel_t chan, const mavlink_timesync_t* timesync) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_timesync_send(chan, timesync->tc1, timesync->ts1); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, (const char *)&packet, MAVLINK_MSG_ID_TIMESYNC_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, (const char *)timesync, MAVLINK_MSG_ID_TIMESYNC_MIN_LEN, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); #endif } @@ -168,25 +179,17 @@ static inline void mavlink_msg_timesync_send(mavlink_channel_t chan, int64_t tc1 static inline void mavlink_msg_timesync_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, int64_t tc1, int64_t ts1) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_int64_t(buf, 0, tc1); - _mav_put_int64_t(buf, 8, ts1); + char *buf = (char *)msgbuf; + _mav_put_int64_t(buf, 0, tc1); + _mav_put_int64_t(buf, 8, ts1); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, buf, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, buf, MAVLINK_MSG_ID_TIMESYNC_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, buf, MAVLINK_MSG_ID_TIMESYNC_MIN_LEN, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); #else - mavlink_timesync_t *packet = (mavlink_timesync_t *)msgbuf; - packet->tc1 = tc1; - packet->ts1 = ts1; + mavlink_timesync_t *packet = (mavlink_timesync_t *)msgbuf; + packet->tc1 = tc1; + packet->ts1 = ts1; -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, (const char *)packet, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, (const char *)packet, MAVLINK_MSG_ID_TIMESYNC_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_TIMESYNC, (const char *)packet, MAVLINK_MSG_ID_TIMESYNC_MIN_LEN, MAVLINK_MSG_ID_TIMESYNC_LEN, MAVLINK_MSG_ID_TIMESYNC_CRC); #endif } #endif @@ -203,7 +206,7 @@ static inline void mavlink_msg_timesync_send_buf(mavlink_message_t *msgbuf, mavl */ static inline int64_t mavlink_msg_timesync_get_tc1(const mavlink_message_t* msg) { - return _MAV_RETURN_int64_t(msg, 0); + return _MAV_RETURN_int64_t(msg, 0); } /** @@ -213,7 +216,7 @@ static inline int64_t mavlink_msg_timesync_get_tc1(const mavlink_message_t* msg) */ static inline int64_t mavlink_msg_timesync_get_ts1(const mavlink_message_t* msg) { - return _MAV_RETURN_int64_t(msg, 8); + return _MAV_RETURN_int64_t(msg, 8); } /** @@ -224,10 +227,12 @@ static inline int64_t mavlink_msg_timesync_get_ts1(const mavlink_message_t* msg) */ static inline void mavlink_msg_timesync_decode(const mavlink_message_t* msg, mavlink_timesync_t* timesync) { -#if MAVLINK_NEED_BYTE_SWAP - timesync->tc1 = mavlink_msg_timesync_get_tc1(msg); - timesync->ts1 = mavlink_msg_timesync_get_ts1(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + timesync->tc1 = mavlink_msg_timesync_get_tc1(msg); + timesync->ts1 = mavlink_msg_timesync_get_ts1(msg); #else - memcpy(timesync, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_TIMESYNC_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_TIMESYNC_LEN? msg->len : MAVLINK_MSG_ID_TIMESYNC_LEN; + memset(timesync, 0, MAVLINK_MSG_ID_TIMESYNC_LEN); + memcpy(timesync, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_v2_extension.h b/vendor/libraries/mavlink/common/mavlink_msg_v2_extension.h index 59a0ba093f..31777f2d9c 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_v2_extension.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_v2_extension.h @@ -1,35 +1,51 @@ +#pragma once // MESSAGE V2_EXTENSION PACKING #define MAVLINK_MSG_ID_V2_EXTENSION 248 -typedef struct __mavlink_v2_extension_t -{ - uint16_t message_type; ///< A code that identifies the software component that understands this message (analogous to usb device classes or mime type strings). If this code is less than 32768, it is considered a 'registered' protocol extension and the corresponding entry should be added to https://github.com/mavlink/mavlink/extension-message-ids.xml. Software creators can register blocks of message IDs as needed (useful for GCS specific metadata, etc...). Message_types greater than 32767 are considered local experiments and should not be checked in to any widely distributed codebase. - uint8_t target_network; ///< Network ID (0 for broadcast) - uint8_t target_system; ///< System ID (0 for broadcast) - uint8_t target_component; ///< Component ID (0 for broadcast) - uint8_t payload[249]; ///< Variable length payload. The length is defined by the remaining message length when subtracting the header and other fields. The entire content of this block is opaque unless you understand any the encoding message_type. The particular encoding used can be extension specific and might not always be documented as part of the mavlink specification. -} mavlink_v2_extension_t; +MAVPACKED( +typedef struct __mavlink_v2_extension_t { + uint16_t message_type; /*< A code that identifies the software component that understands this message (analogous to usb device classes or mime type strings). If this code is less than 32768, it is considered a 'registered' protocol extension and the corresponding entry should be added to https://github.com/mavlink/mavlink/extension-message-ids.xml. Software creators can register blocks of message IDs as needed (useful for GCS specific metadata, etc...). Message_types greater than 32767 are considered local experiments and should not be checked in to any widely distributed codebase.*/ + uint8_t target_network; /*< Network ID (0 for broadcast)*/ + uint8_t target_system; /*< System ID (0 for broadcast)*/ + uint8_t target_component; /*< Component ID (0 for broadcast)*/ + uint8_t payload[249]; /*< Variable length payload. The length is defined by the remaining message length when subtracting the header and other fields. The entire content of this block is opaque unless you understand any the encoding message_type. The particular encoding used can be extension specific and might not always be documented as part of the mavlink specification.*/ +}) mavlink_v2_extension_t; #define MAVLINK_MSG_ID_V2_EXTENSION_LEN 254 +#define MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN 254 #define MAVLINK_MSG_ID_248_LEN 254 +#define MAVLINK_MSG_ID_248_MIN_LEN 254 #define MAVLINK_MSG_ID_V2_EXTENSION_CRC 8 #define MAVLINK_MSG_ID_248_CRC 8 #define MAVLINK_MSG_V2_EXTENSION_FIELD_PAYLOAD_LEN 249 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_V2_EXTENSION { \ - "V2_EXTENSION", \ - 5, \ - { { "message_type", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_v2_extension_t, message_type) }, \ + 248, \ + "V2_EXTENSION", \ + 5, \ + { { "message_type", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_v2_extension_t, message_type) }, \ { "target_network", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_v2_extension_t, target_network) }, \ { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_v2_extension_t, target_system) }, \ { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_v2_extension_t, target_component) }, \ { "payload", NULL, MAVLINK_TYPE_UINT8_T, 249, 5, offsetof(mavlink_v2_extension_t, payload) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_V2_EXTENSION { \ + "V2_EXTENSION", \ + 5, \ + { { "message_type", NULL, MAVLINK_TYPE_UINT16_T, 0, 0, offsetof(mavlink_v2_extension_t, message_type) }, \ + { "target_network", NULL, MAVLINK_TYPE_UINT8_T, 0, 2, offsetof(mavlink_v2_extension_t, target_network) }, \ + { "target_system", NULL, MAVLINK_TYPE_UINT8_T, 0, 3, offsetof(mavlink_v2_extension_t, target_system) }, \ + { "target_component", NULL, MAVLINK_TYPE_UINT8_T, 0, 4, offsetof(mavlink_v2_extension_t, target_component) }, \ + { "payload", NULL, MAVLINK_TYPE_UINT8_T, 249, 5, offsetof(mavlink_v2_extension_t, payload) }, \ + } \ +} +#endif /** * @brief Pack a v2_extension message @@ -45,32 +61,28 @@ typedef struct __mavlink_v2_extension_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_v2_extension_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint8_t target_network, uint8_t target_system, uint8_t target_component, uint16_t message_type, const uint8_t *payload) + uint8_t target_network, uint8_t target_system, uint8_t target_component, uint16_t message_type, const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_V2_EXTENSION_LEN]; - _mav_put_uint16_t(buf, 0, message_type); - _mav_put_uint8_t(buf, 2, target_network); - _mav_put_uint8_t(buf, 3, target_system); - _mav_put_uint8_t(buf, 4, target_component); - _mav_put_uint8_t_array(buf, 5, payload, 249); + char buf[MAVLINK_MSG_ID_V2_EXTENSION_LEN]; + _mav_put_uint16_t(buf, 0, message_type); + _mav_put_uint8_t(buf, 2, target_network); + _mav_put_uint8_t(buf, 3, target_system); + _mav_put_uint8_t(buf, 4, target_component); + _mav_put_uint8_t_array(buf, 5, payload, 249); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_V2_EXTENSION_LEN); #else - mavlink_v2_extension_t packet; - packet.message_type = message_type; - packet.target_network = target_network; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*249); + mavlink_v2_extension_t packet; + packet.message_type = message_type; + packet.target_network = target_network; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*249); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_V2_EXTENSION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_V2_EXTENSION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_V2_EXTENSION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_V2_EXTENSION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); } /** @@ -87,33 +99,29 @@ static inline uint16_t mavlink_msg_v2_extension_pack(uint8_t system_id, uint8_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_v2_extension_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint8_t target_network,uint8_t target_system,uint8_t target_component,uint16_t message_type,const uint8_t *payload) + mavlink_message_t* msg, + uint8_t target_network,uint8_t target_system,uint8_t target_component,uint16_t message_type,const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_V2_EXTENSION_LEN]; - _mav_put_uint16_t(buf, 0, message_type); - _mav_put_uint8_t(buf, 2, target_network); - _mav_put_uint8_t(buf, 3, target_system); - _mav_put_uint8_t(buf, 4, target_component); - _mav_put_uint8_t_array(buf, 5, payload, 249); + char buf[MAVLINK_MSG_ID_V2_EXTENSION_LEN]; + _mav_put_uint16_t(buf, 0, message_type); + _mav_put_uint8_t(buf, 2, target_network); + _mav_put_uint8_t(buf, 3, target_system); + _mav_put_uint8_t(buf, 4, target_component); + _mav_put_uint8_t_array(buf, 5, payload, 249); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_V2_EXTENSION_LEN); #else - mavlink_v2_extension_t packet; - packet.message_type = message_type; - packet.target_network = target_network; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*249); + mavlink_v2_extension_t packet; + packet.message_type = message_type; + packet.target_network = target_network; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*249); memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_V2_EXTENSION_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_V2_EXTENSION; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_V2_EXTENSION_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_V2_EXTENSION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); } /** @@ -126,7 +134,7 @@ static inline uint16_t mavlink_msg_v2_extension_pack_chan(uint8_t system_id, uin */ static inline uint16_t mavlink_msg_v2_extension_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_v2_extension_t* v2_extension) { - return mavlink_msg_v2_extension_pack(system_id, component_id, msg, v2_extension->target_network, v2_extension->target_system, v2_extension->target_component, v2_extension->message_type, v2_extension->payload); + return mavlink_msg_v2_extension_pack(system_id, component_id, msg, v2_extension->target_network, v2_extension->target_system, v2_extension->target_component, v2_extension->message_type, v2_extension->payload); } /** @@ -140,7 +148,7 @@ static inline uint16_t mavlink_msg_v2_extension_encode(uint8_t system_id, uint8_ */ static inline uint16_t mavlink_msg_v2_extension_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_v2_extension_t* v2_extension) { - return mavlink_msg_v2_extension_pack_chan(system_id, component_id, chan, msg, v2_extension->target_network, v2_extension->target_system, v2_extension->target_component, v2_extension->message_type, v2_extension->payload); + return mavlink_msg_v2_extension_pack_chan(system_id, component_id, chan, msg, v2_extension->target_network, v2_extension->target_system, v2_extension->target_component, v2_extension->message_type, v2_extension->payload); } /** @@ -158,29 +166,35 @@ static inline uint16_t mavlink_msg_v2_extension_encode_chan(uint8_t system_id, u static inline void mavlink_msg_v2_extension_send(mavlink_channel_t chan, uint8_t target_network, uint8_t target_system, uint8_t target_component, uint16_t message_type, const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_V2_EXTENSION_LEN]; - _mav_put_uint16_t(buf, 0, message_type); - _mav_put_uint8_t(buf, 2, target_network); - _mav_put_uint8_t(buf, 3, target_system); - _mav_put_uint8_t(buf, 4, target_component); - _mav_put_uint8_t_array(buf, 5, payload, 249); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, buf, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); + char buf[MAVLINK_MSG_ID_V2_EXTENSION_LEN]; + _mav_put_uint16_t(buf, 0, message_type); + _mav_put_uint8_t(buf, 2, target_network); + _mav_put_uint8_t(buf, 3, target_system); + _mav_put_uint8_t(buf, 4, target_component); + _mav_put_uint8_t_array(buf, 5, payload, 249); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, buf, MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, buf, MAVLINK_MSG_ID_V2_EXTENSION_LEN); + mavlink_v2_extension_t packet; + packet.message_type = message_type; + packet.target_network = target_network; + packet.target_system = target_system; + packet.target_component = target_component; + mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*249); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, (const char *)&packet, MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); #endif +} + +/** + * @brief Send a v2_extension message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_v2_extension_send_struct(mavlink_channel_t chan, const mavlink_v2_extension_t* v2_extension) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_v2_extension_send(chan, v2_extension->target_network, v2_extension->target_system, v2_extension->target_component, v2_extension->message_type, v2_extension->payload); #else - mavlink_v2_extension_t packet; - packet.message_type = message_type; - packet.target_network = target_network; - packet.target_system = target_system; - packet.target_component = target_component; - mav_array_memcpy(packet.payload, payload, sizeof(uint8_t)*249); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, (const char *)&packet, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, (const char *)&packet, MAVLINK_MSG_ID_V2_EXTENSION_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, (const char *)v2_extension, MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); #endif } @@ -195,29 +209,21 @@ static inline void mavlink_msg_v2_extension_send(mavlink_channel_t chan, uint8_t static inline void mavlink_msg_v2_extension_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint8_t target_network, uint8_t target_system, uint8_t target_component, uint16_t message_type, const uint8_t *payload) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint16_t(buf, 0, message_type); - _mav_put_uint8_t(buf, 2, target_network); - _mav_put_uint8_t(buf, 3, target_system); - _mav_put_uint8_t(buf, 4, target_component); - _mav_put_uint8_t_array(buf, 5, payload, 249); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, buf, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint16_t(buf, 0, message_type); + _mav_put_uint8_t(buf, 2, target_network); + _mav_put_uint8_t(buf, 3, target_system); + _mav_put_uint8_t(buf, 4, target_component); + _mav_put_uint8_t_array(buf, 5, payload, 249); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, buf, MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, buf, MAVLINK_MSG_ID_V2_EXTENSION_LEN); -#endif -#else - mavlink_v2_extension_t *packet = (mavlink_v2_extension_t *)msgbuf; - packet->message_type = message_type; - packet->target_network = target_network; - packet->target_system = target_system; - packet->target_component = target_component; - mav_array_memcpy(packet->payload, payload, sizeof(uint8_t)*249); -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, (const char *)packet, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, (const char *)packet, MAVLINK_MSG_ID_V2_EXTENSION_LEN); -#endif + mavlink_v2_extension_t *packet = (mavlink_v2_extension_t *)msgbuf; + packet->message_type = message_type; + packet->target_network = target_network; + packet->target_system = target_system; + packet->target_component = target_component; + mav_array_memcpy(packet->payload, payload, sizeof(uint8_t)*249); + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_V2_EXTENSION, (const char *)packet, MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN, MAVLINK_MSG_ID_V2_EXTENSION_LEN, MAVLINK_MSG_ID_V2_EXTENSION_CRC); #endif } #endif @@ -234,7 +240,7 @@ static inline void mavlink_msg_v2_extension_send_buf(mavlink_message_t *msgbuf, */ static inline uint8_t mavlink_msg_v2_extension_get_target_network(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 2); + return _MAV_RETURN_uint8_t(msg, 2); } /** @@ -244,7 +250,7 @@ static inline uint8_t mavlink_msg_v2_extension_get_target_network(const mavlink_ */ static inline uint8_t mavlink_msg_v2_extension_get_target_system(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 3); + return _MAV_RETURN_uint8_t(msg, 3); } /** @@ -254,7 +260,7 @@ static inline uint8_t mavlink_msg_v2_extension_get_target_system(const mavlink_m */ static inline uint8_t mavlink_msg_v2_extension_get_target_component(const mavlink_message_t* msg) { - return _MAV_RETURN_uint8_t(msg, 4); + return _MAV_RETURN_uint8_t(msg, 4); } /** @@ -264,7 +270,7 @@ static inline uint8_t mavlink_msg_v2_extension_get_target_component(const mavlin */ static inline uint16_t mavlink_msg_v2_extension_get_message_type(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 0); + return _MAV_RETURN_uint16_t(msg, 0); } /** @@ -274,7 +280,7 @@ static inline uint16_t mavlink_msg_v2_extension_get_message_type(const mavlink_m */ static inline uint16_t mavlink_msg_v2_extension_get_payload(const mavlink_message_t* msg, uint8_t *payload) { - return _MAV_RETURN_uint8_t_array(msg, payload, 249, 5); + return _MAV_RETURN_uint8_t_array(msg, payload, 249, 5); } /** @@ -285,13 +291,15 @@ static inline uint16_t mavlink_msg_v2_extension_get_payload(const mavlink_messag */ static inline void mavlink_msg_v2_extension_decode(const mavlink_message_t* msg, mavlink_v2_extension_t* v2_extension) { -#if MAVLINK_NEED_BYTE_SWAP - v2_extension->message_type = mavlink_msg_v2_extension_get_message_type(msg); - v2_extension->target_network = mavlink_msg_v2_extension_get_target_network(msg); - v2_extension->target_system = mavlink_msg_v2_extension_get_target_system(msg); - v2_extension->target_component = mavlink_msg_v2_extension_get_target_component(msg); - mavlink_msg_v2_extension_get_payload(msg, v2_extension->payload); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + v2_extension->message_type = mavlink_msg_v2_extension_get_message_type(msg); + v2_extension->target_network = mavlink_msg_v2_extension_get_target_network(msg); + v2_extension->target_system = mavlink_msg_v2_extension_get_target_system(msg); + v2_extension->target_component = mavlink_msg_v2_extension_get_target_component(msg); + mavlink_msg_v2_extension_get_payload(msg, v2_extension->payload); #else - memcpy(v2_extension, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_V2_EXTENSION_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_V2_EXTENSION_LEN? msg->len : MAVLINK_MSG_ID_V2_EXTENSION_LEN; + memset(v2_extension, 0, MAVLINK_MSG_ID_V2_EXTENSION_LEN); + memcpy(v2_extension, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_vfr_hud.h b/vendor/libraries/mavlink/common/mavlink_msg_vfr_hud.h index b130ee50b5..1700dd0aa2 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_vfr_hud.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_vfr_hud.h @@ -1,29 +1,34 @@ +#pragma once // MESSAGE VFR_HUD PACKING #define MAVLINK_MSG_ID_VFR_HUD 74 -typedef struct __mavlink_vfr_hud_t -{ - float airspeed; ///< Current airspeed in m/s - float groundspeed; ///< Current ground speed in m/s - float alt; ///< Current altitude (MSL), in meters - float climb; ///< Current climb rate in meters/second - int16_t heading; ///< Current heading in degrees, in compass units (0..360, 0=north) - uint16_t throttle; ///< Current throttle setting in integer percent, 0 to 100 -} mavlink_vfr_hud_t; +MAVPACKED( +typedef struct __mavlink_vfr_hud_t { + float airspeed; /*< Current airspeed in m/s*/ + float groundspeed; /*< Current ground speed in m/s*/ + float alt; /*< Current altitude (MSL), in meters*/ + float climb; /*< Current climb rate in meters/second*/ + int16_t heading; /*< Current heading in degrees, in compass units (0..360, 0=north)*/ + uint16_t throttle; /*< Current throttle setting in integer percent, 0 to 100*/ +}) mavlink_vfr_hud_t; #define MAVLINK_MSG_ID_VFR_HUD_LEN 20 +#define MAVLINK_MSG_ID_VFR_HUD_MIN_LEN 20 #define MAVLINK_MSG_ID_74_LEN 20 +#define MAVLINK_MSG_ID_74_MIN_LEN 20 #define MAVLINK_MSG_ID_VFR_HUD_CRC 20 #define MAVLINK_MSG_ID_74_CRC 20 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_VFR_HUD { \ - "VFR_HUD", \ - 6, \ - { { "airspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_vfr_hud_t, airspeed) }, \ + 74, \ + "VFR_HUD", \ + 6, \ + { { "airspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_vfr_hud_t, airspeed) }, \ { "groundspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_vfr_hud_t, groundspeed) }, \ { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vfr_hud_t, alt) }, \ { "climb", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vfr_hud_t, climb) }, \ @@ -31,7 +36,19 @@ typedef struct __mavlink_vfr_hud_t { "throttle", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_vfr_hud_t, throttle) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_VFR_HUD { \ + "VFR_HUD", \ + 6, \ + { { "airspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 0, offsetof(mavlink_vfr_hud_t, airspeed) }, \ + { "groundspeed", NULL, MAVLINK_TYPE_FLOAT, 0, 4, offsetof(mavlink_vfr_hud_t, groundspeed) }, \ + { "alt", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vfr_hud_t, alt) }, \ + { "climb", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vfr_hud_t, climb) }, \ + { "heading", NULL, MAVLINK_TYPE_INT16_T, 0, 16, offsetof(mavlink_vfr_hud_t, heading) }, \ + { "throttle", NULL, MAVLINK_TYPE_UINT16_T, 0, 18, offsetof(mavlink_vfr_hud_t, throttle) }, \ + } \ +} +#endif /** * @brief Pack a vfr_hud message @@ -48,36 +65,32 @@ typedef struct __mavlink_vfr_hud_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vfr_hud_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - float airspeed, float groundspeed, int16_t heading, uint16_t throttle, float alt, float climb) + float airspeed, float groundspeed, int16_t heading, uint16_t throttle, float alt, float climb) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VFR_HUD_LEN]; - _mav_put_float(buf, 0, airspeed); - _mav_put_float(buf, 4, groundspeed); - _mav_put_float(buf, 8, alt); - _mav_put_float(buf, 12, climb); - _mav_put_int16_t(buf, 16, heading); - _mav_put_uint16_t(buf, 18, throttle); + char buf[MAVLINK_MSG_ID_VFR_HUD_LEN]; + _mav_put_float(buf, 0, airspeed); + _mav_put_float(buf, 4, groundspeed); + _mav_put_float(buf, 8, alt); + _mav_put_float(buf, 12, climb); + _mav_put_int16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, throttle); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VFR_HUD_LEN); #else - mavlink_vfr_hud_t packet; - packet.airspeed = airspeed; - packet.groundspeed = groundspeed; - packet.alt = alt; - packet.climb = climb; - packet.heading = heading; - packet.throttle = throttle; + mavlink_vfr_hud_t packet; + packet.airspeed = airspeed; + packet.groundspeed = groundspeed; + packet.alt = alt; + packet.climb = climb; + packet.heading = heading; + packet.throttle = throttle; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VFR_HUD_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VFR_HUD; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VFR_HUD_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VFR_HUD; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VFR_HUD_MIN_LEN, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); } /** @@ -95,37 +108,33 @@ static inline uint16_t mavlink_msg_vfr_hud_pack(uint8_t system_id, uint8_t compo * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vfr_hud_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - float airspeed,float groundspeed,int16_t heading,uint16_t throttle,float alt,float climb) + mavlink_message_t* msg, + float airspeed,float groundspeed,int16_t heading,uint16_t throttle,float alt,float climb) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VFR_HUD_LEN]; - _mav_put_float(buf, 0, airspeed); - _mav_put_float(buf, 4, groundspeed); - _mav_put_float(buf, 8, alt); - _mav_put_float(buf, 12, climb); - _mav_put_int16_t(buf, 16, heading); - _mav_put_uint16_t(buf, 18, throttle); + char buf[MAVLINK_MSG_ID_VFR_HUD_LEN]; + _mav_put_float(buf, 0, airspeed); + _mav_put_float(buf, 4, groundspeed); + _mav_put_float(buf, 8, alt); + _mav_put_float(buf, 12, climb); + _mav_put_int16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, throttle); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VFR_HUD_LEN); #else - mavlink_vfr_hud_t packet; - packet.airspeed = airspeed; - packet.groundspeed = groundspeed; - packet.alt = alt; - packet.climb = climb; - packet.heading = heading; - packet.throttle = throttle; + mavlink_vfr_hud_t packet; + packet.airspeed = airspeed; + packet.groundspeed = groundspeed; + packet.alt = alt; + packet.climb = climb; + packet.heading = heading; + packet.throttle = throttle; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VFR_HUD_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VFR_HUD; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VFR_HUD_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VFR_HUD; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VFR_HUD_MIN_LEN, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); } /** @@ -138,7 +147,7 @@ static inline uint16_t mavlink_msg_vfr_hud_pack_chan(uint8_t system_id, uint8_t */ static inline uint16_t mavlink_msg_vfr_hud_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_vfr_hud_t* vfr_hud) { - return mavlink_msg_vfr_hud_pack(system_id, component_id, msg, vfr_hud->airspeed, vfr_hud->groundspeed, vfr_hud->heading, vfr_hud->throttle, vfr_hud->alt, vfr_hud->climb); + return mavlink_msg_vfr_hud_pack(system_id, component_id, msg, vfr_hud->airspeed, vfr_hud->groundspeed, vfr_hud->heading, vfr_hud->throttle, vfr_hud->alt, vfr_hud->climb); } /** @@ -152,7 +161,7 @@ static inline uint16_t mavlink_msg_vfr_hud_encode(uint8_t system_id, uint8_t com */ static inline uint16_t mavlink_msg_vfr_hud_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vfr_hud_t* vfr_hud) { - return mavlink_msg_vfr_hud_pack_chan(system_id, component_id, chan, msg, vfr_hud->airspeed, vfr_hud->groundspeed, vfr_hud->heading, vfr_hud->throttle, vfr_hud->alt, vfr_hud->climb); + return mavlink_msg_vfr_hud_pack_chan(system_id, component_id, chan, msg, vfr_hud->airspeed, vfr_hud->groundspeed, vfr_hud->heading, vfr_hud->throttle, vfr_hud->alt, vfr_hud->climb); } /** @@ -171,33 +180,39 @@ static inline uint16_t mavlink_msg_vfr_hud_encode_chan(uint8_t system_id, uint8_ static inline void mavlink_msg_vfr_hud_send(mavlink_channel_t chan, float airspeed, float groundspeed, int16_t heading, uint16_t throttle, float alt, float climb) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VFR_HUD_LEN]; - _mav_put_float(buf, 0, airspeed); - _mav_put_float(buf, 4, groundspeed); - _mav_put_float(buf, 8, alt); - _mav_put_float(buf, 12, climb); - _mav_put_int16_t(buf, 16, heading); - _mav_put_uint16_t(buf, 18, throttle); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, buf, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); + char buf[MAVLINK_MSG_ID_VFR_HUD_LEN]; + _mav_put_float(buf, 0, airspeed); + _mav_put_float(buf, 4, groundspeed); + _mav_put_float(buf, 8, alt); + _mav_put_float(buf, 12, climb); + _mav_put_int16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, throttle); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, buf, MAVLINK_MSG_ID_VFR_HUD_MIN_LEN, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, buf, MAVLINK_MSG_ID_VFR_HUD_LEN); + mavlink_vfr_hud_t packet; + packet.airspeed = airspeed; + packet.groundspeed = groundspeed; + packet.alt = alt; + packet.climb = climb; + packet.heading = heading; + packet.throttle = throttle; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, (const char *)&packet, MAVLINK_MSG_ID_VFR_HUD_MIN_LEN, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); #endif +} + +/** + * @brief Send a vfr_hud message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_vfr_hud_send_struct(mavlink_channel_t chan, const mavlink_vfr_hud_t* vfr_hud) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_vfr_hud_send(chan, vfr_hud->airspeed, vfr_hud->groundspeed, vfr_hud->heading, vfr_hud->throttle, vfr_hud->alt, vfr_hud->climb); #else - mavlink_vfr_hud_t packet; - packet.airspeed = airspeed; - packet.groundspeed = groundspeed; - packet.alt = alt; - packet.climb = climb; - packet.heading = heading; - packet.throttle = throttle; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, (const char *)&packet, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, (const char *)&packet, MAVLINK_MSG_ID_VFR_HUD_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, (const char *)vfr_hud, MAVLINK_MSG_ID_VFR_HUD_MIN_LEN, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); #endif } @@ -212,33 +227,25 @@ static inline void mavlink_msg_vfr_hud_send(mavlink_channel_t chan, float airspe static inline void mavlink_msg_vfr_hud_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, float airspeed, float groundspeed, int16_t heading, uint16_t throttle, float alt, float climb) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_float(buf, 0, airspeed); - _mav_put_float(buf, 4, groundspeed); - _mav_put_float(buf, 8, alt); - _mav_put_float(buf, 12, climb); - _mav_put_int16_t(buf, 16, heading); - _mav_put_uint16_t(buf, 18, throttle); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, buf, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); + char *buf = (char *)msgbuf; + _mav_put_float(buf, 0, airspeed); + _mav_put_float(buf, 4, groundspeed); + _mav_put_float(buf, 8, alt); + _mav_put_float(buf, 12, climb); + _mav_put_int16_t(buf, 16, heading); + _mav_put_uint16_t(buf, 18, throttle); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, buf, MAVLINK_MSG_ID_VFR_HUD_MIN_LEN, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, buf, MAVLINK_MSG_ID_VFR_HUD_LEN); -#endif -#else - mavlink_vfr_hud_t *packet = (mavlink_vfr_hud_t *)msgbuf; - packet->airspeed = airspeed; - packet->groundspeed = groundspeed; - packet->alt = alt; - packet->climb = climb; - packet->heading = heading; - packet->throttle = throttle; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, (const char *)packet, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, (const char *)packet, MAVLINK_MSG_ID_VFR_HUD_LEN); -#endif + mavlink_vfr_hud_t *packet = (mavlink_vfr_hud_t *)msgbuf; + packet->airspeed = airspeed; + packet->groundspeed = groundspeed; + packet->alt = alt; + packet->climb = climb; + packet->heading = heading; + packet->throttle = throttle; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VFR_HUD, (const char *)packet, MAVLINK_MSG_ID_VFR_HUD_MIN_LEN, MAVLINK_MSG_ID_VFR_HUD_LEN, MAVLINK_MSG_ID_VFR_HUD_CRC); #endif } #endif @@ -255,7 +262,7 @@ static inline void mavlink_msg_vfr_hud_send_buf(mavlink_message_t *msgbuf, mavli */ static inline float mavlink_msg_vfr_hud_get_airspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 0); + return _MAV_RETURN_float(msg, 0); } /** @@ -265,7 +272,7 @@ static inline float mavlink_msg_vfr_hud_get_airspeed(const mavlink_message_t* ms */ static inline float mavlink_msg_vfr_hud_get_groundspeed(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 4); + return _MAV_RETURN_float(msg, 4); } /** @@ -275,7 +282,7 @@ static inline float mavlink_msg_vfr_hud_get_groundspeed(const mavlink_message_t* */ static inline int16_t mavlink_msg_vfr_hud_get_heading(const mavlink_message_t* msg) { - return _MAV_RETURN_int16_t(msg, 16); + return _MAV_RETURN_int16_t(msg, 16); } /** @@ -285,7 +292,7 @@ static inline int16_t mavlink_msg_vfr_hud_get_heading(const mavlink_message_t* m */ static inline uint16_t mavlink_msg_vfr_hud_get_throttle(const mavlink_message_t* msg) { - return _MAV_RETURN_uint16_t(msg, 18); + return _MAV_RETURN_uint16_t(msg, 18); } /** @@ -295,7 +302,7 @@ static inline uint16_t mavlink_msg_vfr_hud_get_throttle(const mavlink_message_t* */ static inline float mavlink_msg_vfr_hud_get_alt(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -305,7 +312,7 @@ static inline float mavlink_msg_vfr_hud_get_alt(const mavlink_message_t* msg) */ static inline float mavlink_msg_vfr_hud_get_climb(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -316,14 +323,16 @@ static inline float mavlink_msg_vfr_hud_get_climb(const mavlink_message_t* msg) */ static inline void mavlink_msg_vfr_hud_decode(const mavlink_message_t* msg, mavlink_vfr_hud_t* vfr_hud) { -#if MAVLINK_NEED_BYTE_SWAP - vfr_hud->airspeed = mavlink_msg_vfr_hud_get_airspeed(msg); - vfr_hud->groundspeed = mavlink_msg_vfr_hud_get_groundspeed(msg); - vfr_hud->alt = mavlink_msg_vfr_hud_get_alt(msg); - vfr_hud->climb = mavlink_msg_vfr_hud_get_climb(msg); - vfr_hud->heading = mavlink_msg_vfr_hud_get_heading(msg); - vfr_hud->throttle = mavlink_msg_vfr_hud_get_throttle(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + vfr_hud->airspeed = mavlink_msg_vfr_hud_get_airspeed(msg); + vfr_hud->groundspeed = mavlink_msg_vfr_hud_get_groundspeed(msg); + vfr_hud->alt = mavlink_msg_vfr_hud_get_alt(msg); + vfr_hud->climb = mavlink_msg_vfr_hud_get_climb(msg); + vfr_hud->heading = mavlink_msg_vfr_hud_get_heading(msg); + vfr_hud->throttle = mavlink_msg_vfr_hud_get_throttle(msg); #else - memcpy(vfr_hud, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_VFR_HUD_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_VFR_HUD_LEN? msg->len : MAVLINK_MSG_ID_VFR_HUD_LEN; + memset(vfr_hud, 0, MAVLINK_MSG_ID_VFR_HUD_LEN); + memcpy(vfr_hud, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_vibration.h b/vendor/libraries/mavlink/common/mavlink_msg_vibration.h new file mode 100644 index 0000000000..a8760f79e5 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_vibration.h @@ -0,0 +1,363 @@ +#pragma once +// MESSAGE VIBRATION PACKING + +#define MAVLINK_MSG_ID_VIBRATION 241 + +MAVPACKED( +typedef struct __mavlink_vibration_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float vibration_x; /*< Vibration levels on X-axis*/ + float vibration_y; /*< Vibration levels on Y-axis*/ + float vibration_z; /*< Vibration levels on Z-axis*/ + uint32_t clipping_0; /*< first accelerometer clipping count*/ + uint32_t clipping_1; /*< second accelerometer clipping count*/ + uint32_t clipping_2; /*< third accelerometer clipping count*/ +}) mavlink_vibration_t; + +#define MAVLINK_MSG_ID_VIBRATION_LEN 32 +#define MAVLINK_MSG_ID_VIBRATION_MIN_LEN 32 +#define MAVLINK_MSG_ID_241_LEN 32 +#define MAVLINK_MSG_ID_241_MIN_LEN 32 + +#define MAVLINK_MSG_ID_VIBRATION_CRC 90 +#define MAVLINK_MSG_ID_241_CRC 90 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_VIBRATION { \ + 241, \ + "VIBRATION", \ + 7, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vibration_t, time_usec) }, \ + { "vibration_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vibration_t, vibration_x) }, \ + { "vibration_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vibration_t, vibration_y) }, \ + { "vibration_z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vibration_t, vibration_z) }, \ + { "clipping_0", NULL, MAVLINK_TYPE_UINT32_T, 0, 20, offsetof(mavlink_vibration_t, clipping_0) }, \ + { "clipping_1", NULL, MAVLINK_TYPE_UINT32_T, 0, 24, offsetof(mavlink_vibration_t, clipping_1) }, \ + { "clipping_2", NULL, MAVLINK_TYPE_UINT32_T, 0, 28, offsetof(mavlink_vibration_t, clipping_2) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_VIBRATION { \ + "VIBRATION", \ + 7, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vibration_t, time_usec) }, \ + { "vibration_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vibration_t, vibration_x) }, \ + { "vibration_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vibration_t, vibration_y) }, \ + { "vibration_z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vibration_t, vibration_z) }, \ + { "clipping_0", NULL, MAVLINK_TYPE_UINT32_T, 0, 20, offsetof(mavlink_vibration_t, clipping_0) }, \ + { "clipping_1", NULL, MAVLINK_TYPE_UINT32_T, 0, 24, offsetof(mavlink_vibration_t, clipping_1) }, \ + { "clipping_2", NULL, MAVLINK_TYPE_UINT32_T, 0, 28, offsetof(mavlink_vibration_t, clipping_2) }, \ + } \ +} +#endif + +/** + * @brief Pack a vibration message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param vibration_x Vibration levels on X-axis + * @param vibration_y Vibration levels on Y-axis + * @param vibration_z Vibration levels on Z-axis + * @param clipping_0 first accelerometer clipping count + * @param clipping_1 second accelerometer clipping count + * @param clipping_2 third accelerometer clipping count + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_vibration_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, float vibration_x, float vibration_y, float vibration_z, uint32_t clipping_0, uint32_t clipping_1, uint32_t clipping_2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_VIBRATION_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vibration_x); + _mav_put_float(buf, 12, vibration_y); + _mav_put_float(buf, 16, vibration_z); + _mav_put_uint32_t(buf, 20, clipping_0); + _mav_put_uint32_t(buf, 24, clipping_1); + _mav_put_uint32_t(buf, 28, clipping_2); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VIBRATION_LEN); +#else + mavlink_vibration_t packet; + packet.time_usec = time_usec; + packet.vibration_x = vibration_x; + packet.vibration_y = vibration_y; + packet.vibration_z = vibration_z; + packet.clipping_0 = clipping_0; + packet.clipping_1 = clipping_1; + packet.clipping_2 = clipping_2; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VIBRATION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_VIBRATION; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VIBRATION_MIN_LEN, MAVLINK_MSG_ID_VIBRATION_LEN, MAVLINK_MSG_ID_VIBRATION_CRC); +} + +/** + * @brief Pack a vibration message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param vibration_x Vibration levels on X-axis + * @param vibration_y Vibration levels on Y-axis + * @param vibration_z Vibration levels on Z-axis + * @param clipping_0 first accelerometer clipping count + * @param clipping_1 second accelerometer clipping count + * @param clipping_2 third accelerometer clipping count + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_vibration_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,float vibration_x,float vibration_y,float vibration_z,uint32_t clipping_0,uint32_t clipping_1,uint32_t clipping_2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_VIBRATION_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vibration_x); + _mav_put_float(buf, 12, vibration_y); + _mav_put_float(buf, 16, vibration_z); + _mav_put_uint32_t(buf, 20, clipping_0); + _mav_put_uint32_t(buf, 24, clipping_1); + _mav_put_uint32_t(buf, 28, clipping_2); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VIBRATION_LEN); +#else + mavlink_vibration_t packet; + packet.time_usec = time_usec; + packet.vibration_x = vibration_x; + packet.vibration_y = vibration_y; + packet.vibration_z = vibration_z; + packet.clipping_0 = clipping_0; + packet.clipping_1 = clipping_1; + packet.clipping_2 = clipping_2; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VIBRATION_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_VIBRATION; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VIBRATION_MIN_LEN, MAVLINK_MSG_ID_VIBRATION_LEN, MAVLINK_MSG_ID_VIBRATION_CRC); +} + +/** + * @brief Encode a vibration struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param vibration C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_vibration_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_vibration_t* vibration) +{ + return mavlink_msg_vibration_pack(system_id, component_id, msg, vibration->time_usec, vibration->vibration_x, vibration->vibration_y, vibration->vibration_z, vibration->clipping_0, vibration->clipping_1, vibration->clipping_2); +} + +/** + * @brief Encode a vibration struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param vibration C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_vibration_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vibration_t* vibration) +{ + return mavlink_msg_vibration_pack_chan(system_id, component_id, chan, msg, vibration->time_usec, vibration->vibration_x, vibration->vibration_y, vibration->vibration_z, vibration->clipping_0, vibration->clipping_1, vibration->clipping_2); +} + +/** + * @brief Send a vibration message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param vibration_x Vibration levels on X-axis + * @param vibration_y Vibration levels on Y-axis + * @param vibration_z Vibration levels on Z-axis + * @param clipping_0 first accelerometer clipping count + * @param clipping_1 second accelerometer clipping count + * @param clipping_2 third accelerometer clipping count + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_vibration_send(mavlink_channel_t chan, uint64_t time_usec, float vibration_x, float vibration_y, float vibration_z, uint32_t clipping_0, uint32_t clipping_1, uint32_t clipping_2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_VIBRATION_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vibration_x); + _mav_put_float(buf, 12, vibration_y); + _mav_put_float(buf, 16, vibration_z); + _mav_put_uint32_t(buf, 20, clipping_0); + _mav_put_uint32_t(buf, 24, clipping_1); + _mav_put_uint32_t(buf, 28, clipping_2); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VIBRATION, buf, MAVLINK_MSG_ID_VIBRATION_MIN_LEN, MAVLINK_MSG_ID_VIBRATION_LEN, MAVLINK_MSG_ID_VIBRATION_CRC); +#else + mavlink_vibration_t packet; + packet.time_usec = time_usec; + packet.vibration_x = vibration_x; + packet.vibration_y = vibration_y; + packet.vibration_z = vibration_z; + packet.clipping_0 = clipping_0; + packet.clipping_1 = clipping_1; + packet.clipping_2 = clipping_2; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VIBRATION, (const char *)&packet, MAVLINK_MSG_ID_VIBRATION_MIN_LEN, MAVLINK_MSG_ID_VIBRATION_LEN, MAVLINK_MSG_ID_VIBRATION_CRC); +#endif +} + +/** + * @brief Send a vibration message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_vibration_send_struct(mavlink_channel_t chan, const mavlink_vibration_t* vibration) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_vibration_send(chan, vibration->time_usec, vibration->vibration_x, vibration->vibration_y, vibration->vibration_z, vibration->clipping_0, vibration->clipping_1, vibration->clipping_2); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VIBRATION, (const char *)vibration, MAVLINK_MSG_ID_VIBRATION_MIN_LEN, MAVLINK_MSG_ID_VIBRATION_LEN, MAVLINK_MSG_ID_VIBRATION_CRC); +#endif +} + +#if MAVLINK_MSG_ID_VIBRATION_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_vibration_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float vibration_x, float vibration_y, float vibration_z, uint32_t clipping_0, uint32_t clipping_1, uint32_t clipping_2) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, vibration_x); + _mav_put_float(buf, 12, vibration_y); + _mav_put_float(buf, 16, vibration_z); + _mav_put_uint32_t(buf, 20, clipping_0); + _mav_put_uint32_t(buf, 24, clipping_1); + _mav_put_uint32_t(buf, 28, clipping_2); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VIBRATION, buf, MAVLINK_MSG_ID_VIBRATION_MIN_LEN, MAVLINK_MSG_ID_VIBRATION_LEN, MAVLINK_MSG_ID_VIBRATION_CRC); +#else + mavlink_vibration_t *packet = (mavlink_vibration_t *)msgbuf; + packet->time_usec = time_usec; + packet->vibration_x = vibration_x; + packet->vibration_y = vibration_y; + packet->vibration_z = vibration_z; + packet->clipping_0 = clipping_0; + packet->clipping_1 = clipping_1; + packet->clipping_2 = clipping_2; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VIBRATION, (const char *)packet, MAVLINK_MSG_ID_VIBRATION_MIN_LEN, MAVLINK_MSG_ID_VIBRATION_LEN, MAVLINK_MSG_ID_VIBRATION_CRC); +#endif +} +#endif + +#endif + +// MESSAGE VIBRATION UNPACKING + + +/** + * @brief Get field time_usec from vibration message + * + * @return Timestamp (micros since boot or Unix epoch) + */ +static inline uint64_t mavlink_msg_vibration_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field vibration_x from vibration message + * + * @return Vibration levels on X-axis + */ +static inline float mavlink_msg_vibration_get_vibration_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field vibration_y from vibration message + * + * @return Vibration levels on Y-axis + */ +static inline float mavlink_msg_vibration_get_vibration_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field vibration_z from vibration message + * + * @return Vibration levels on Z-axis + */ +static inline float mavlink_msg_vibration_get_vibration_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field clipping_0 from vibration message + * + * @return first accelerometer clipping count + */ +static inline uint32_t mavlink_msg_vibration_get_clipping_0(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 20); +} + +/** + * @brief Get field clipping_1 from vibration message + * + * @return second accelerometer clipping count + */ +static inline uint32_t mavlink_msg_vibration_get_clipping_1(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 24); +} + +/** + * @brief Get field clipping_2 from vibration message + * + * @return third accelerometer clipping count + */ +static inline uint32_t mavlink_msg_vibration_get_clipping_2(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint32_t(msg, 28); +} + +/** + * @brief Decode a vibration message into a struct + * + * @param msg The message to decode + * @param vibration C-struct to decode the message contents into + */ +static inline void mavlink_msg_vibration_decode(const mavlink_message_t* msg, mavlink_vibration_t* vibration) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + vibration->time_usec = mavlink_msg_vibration_get_time_usec(msg); + vibration->vibration_x = mavlink_msg_vibration_get_vibration_x(msg); + vibration->vibration_y = mavlink_msg_vibration_get_vibration_y(msg); + vibration->vibration_z = mavlink_msg_vibration_get_vibration_z(msg); + vibration->clipping_0 = mavlink_msg_vibration_get_clipping_0(msg); + vibration->clipping_1 = mavlink_msg_vibration_get_clipping_1(msg); + vibration->clipping_2 = mavlink_msg_vibration_get_clipping_2(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_VIBRATION_LEN? msg->len : MAVLINK_MSG_ID_VIBRATION_LEN; + memset(vibration, 0, MAVLINK_MSG_ID_VIBRATION_LEN); + memcpy(vibration, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/mavlink_msg_vicon_position_estimate.h b/vendor/libraries/mavlink/common/mavlink_msg_vicon_position_estimate.h index b3fa7bc1c1..5813b74a64 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_vicon_position_estimate.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_vicon_position_estimate.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE VICON_POSITION_ESTIMATE PACKING #define MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE 104 -typedef struct __mavlink_vicon_position_estimate_t -{ - uint64_t usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - float x; ///< Global X position - float y; ///< Global Y position - float z; ///< Global Z position - float roll; ///< Roll angle in rad - float pitch; ///< Pitch angle in rad - float yaw; ///< Yaw angle in rad -} mavlink_vicon_position_estimate_t; +MAVPACKED( +typedef struct __mavlink_vicon_position_estimate_t { + uint64_t usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + float x; /*< Global X position*/ + float y; /*< Global Y position*/ + float z; /*< Global Z position*/ + float roll; /*< Roll angle in rad*/ + float pitch; /*< Pitch angle in rad*/ + float yaw; /*< Yaw angle in rad*/ +}) mavlink_vicon_position_estimate_t; #define MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN 32 +#define MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN 32 #define MAVLINK_MSG_ID_104_LEN 32 +#define MAVLINK_MSG_ID_104_MIN_LEN 32 #define MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC 56 #define MAVLINK_MSG_ID_104_CRC 56 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE { \ - "VICON_POSITION_ESTIMATE", \ - 7, \ - { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vicon_position_estimate_t, usec) }, \ + 104, \ + "VICON_POSITION_ESTIMATE", \ + 7, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vicon_position_estimate_t, usec) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vicon_position_estimate_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vicon_position_estimate_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vicon_position_estimate_t, z) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_vicon_position_estimate_t { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_vicon_position_estimate_t, yaw) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_VICON_POSITION_ESTIMATE { \ + "VICON_POSITION_ESTIMATE", \ + 7, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vicon_position_estimate_t, usec) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vicon_position_estimate_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vicon_position_estimate_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vicon_position_estimate_t, z) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_vicon_position_estimate_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_vicon_position_estimate_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_vicon_position_estimate_t, yaw) }, \ + } \ +} +#endif /** * @brief Pack a vicon_position_estimate message @@ -51,38 +69,34 @@ typedef struct __mavlink_vicon_position_estimate_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vicon_position_estimate_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) + uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); + char buf[MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); #else - mavlink_vicon_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_vicon_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_vicon_position_estimate_pack(uint8_t system_i * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vicon_position_estimate_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t usec,float x,float y,float z,float roll,float pitch,float yaw) + mavlink_message_t* msg, + uint64_t usec,float x,float y,float z,float roll,float pitch,float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); + char buf[MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); #else - mavlink_vicon_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_vicon_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_vicon_position_estimate_pack_chan(uint8_t sys */ static inline uint16_t mavlink_msg_vicon_position_estimate_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_vicon_position_estimate_t* vicon_position_estimate) { - return mavlink_msg_vicon_position_estimate_pack(system_id, component_id, msg, vicon_position_estimate->usec, vicon_position_estimate->x, vicon_position_estimate->y, vicon_position_estimate->z, vicon_position_estimate->roll, vicon_position_estimate->pitch, vicon_position_estimate->yaw); + return mavlink_msg_vicon_position_estimate_pack(system_id, component_id, msg, vicon_position_estimate->usec, vicon_position_estimate->x, vicon_position_estimate->y, vicon_position_estimate->z, vicon_position_estimate->roll, vicon_position_estimate->pitch, vicon_position_estimate->yaw); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_vicon_position_estimate_encode(uint8_t system */ static inline uint16_t mavlink_msg_vicon_position_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vicon_position_estimate_t* vicon_position_estimate) { - return mavlink_msg_vicon_position_estimate_pack_chan(system_id, component_id, chan, msg, vicon_position_estimate->usec, vicon_position_estimate->x, vicon_position_estimate->y, vicon_position_estimate->z, vicon_position_estimate->roll, vicon_position_estimate->pitch, vicon_position_estimate->yaw); + return mavlink_msg_vicon_position_estimate_pack_chan(system_id, component_id, chan, msg, vicon_position_estimate->usec, vicon_position_estimate->x, vicon_position_estimate->y, vicon_position_estimate->z, vicon_position_estimate->roll, vicon_position_estimate->pitch, vicon_position_estimate->yaw); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_vicon_position_estimate_encode_chan(uint8_t s static inline void mavlink_msg_vicon_position_estimate_send(mavlink_channel_t chan, uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); + char buf[MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); + mavlink_vicon_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); #endif +} + +/** + * @brief Send a vicon_position_estimate message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_vicon_position_estimate_send_struct(mavlink_channel_t chan, const mavlink_vicon_position_estimate_t* vicon_position_estimate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_vicon_position_estimate_send(chan, vicon_position_estimate->usec, vicon_position_estimate->x, vicon_position_estimate->y, vicon_position_estimate->z, vicon_position_estimate->roll, vicon_position_estimate->pitch, vicon_position_estimate->yaw); #else - mavlink_vicon_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, (const char *)vicon_position_estimate, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_vicon_position_estimate_send(mavlink_channel_t ch static inline void mavlink_msg_vicon_position_estimate_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); -#endif -#else - mavlink_vicon_position_estimate_t *packet = (mavlink_vicon_position_estimate_t *)msgbuf; - packet->usec = usec; - packet->x = x; - packet->y = y; - packet->z = z; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); -#endif + mavlink_vicon_position_estimate_t *packet = (mavlink_vicon_position_estimate_t *)msgbuf; + packet->usec = usec; + packet->x = x; + packet->y = y; + packet->z = z; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_vicon_position_estimate_send_buf(mavlink_message_ */ static inline uint64_t mavlink_msg_vicon_position_estimate_get_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline uint64_t mavlink_msg_vicon_position_estimate_get_usec(const mavlin */ static inline float mavlink_msg_vicon_position_estimate_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_vicon_position_estimate_get_x(const mavlink_mess */ static inline float mavlink_msg_vicon_position_estimate_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_vicon_position_estimate_get_y(const mavlink_mess */ static inline float mavlink_msg_vicon_position_estimate_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_vicon_position_estimate_get_z(const mavlink_mess */ static inline float mavlink_msg_vicon_position_estimate_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_vicon_position_estimate_get_roll(const mavlink_m */ static inline float mavlink_msg_vicon_position_estimate_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_vicon_position_estimate_get_pitch(const mavlink_ */ static inline float mavlink_msg_vicon_position_estimate_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_vicon_position_estimate_get_yaw(const mavlink_me */ static inline void mavlink_msg_vicon_position_estimate_decode(const mavlink_message_t* msg, mavlink_vicon_position_estimate_t* vicon_position_estimate) { -#if MAVLINK_NEED_BYTE_SWAP - vicon_position_estimate->usec = mavlink_msg_vicon_position_estimate_get_usec(msg); - vicon_position_estimate->x = mavlink_msg_vicon_position_estimate_get_x(msg); - vicon_position_estimate->y = mavlink_msg_vicon_position_estimate_get_y(msg); - vicon_position_estimate->z = mavlink_msg_vicon_position_estimate_get_z(msg); - vicon_position_estimate->roll = mavlink_msg_vicon_position_estimate_get_roll(msg); - vicon_position_estimate->pitch = mavlink_msg_vicon_position_estimate_get_pitch(msg); - vicon_position_estimate->yaw = mavlink_msg_vicon_position_estimate_get_yaw(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + vicon_position_estimate->usec = mavlink_msg_vicon_position_estimate_get_usec(msg); + vicon_position_estimate->x = mavlink_msg_vicon_position_estimate_get_x(msg); + vicon_position_estimate->y = mavlink_msg_vicon_position_estimate_get_y(msg); + vicon_position_estimate->z = mavlink_msg_vicon_position_estimate_get_z(msg); + vicon_position_estimate->roll = mavlink_msg_vicon_position_estimate_get_roll(msg); + vicon_position_estimate->pitch = mavlink_msg_vicon_position_estimate_get_pitch(msg); + vicon_position_estimate->yaw = mavlink_msg_vicon_position_estimate_get_yaw(msg); #else - memcpy(vicon_position_estimate, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN? msg->len : MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN; + memset(vicon_position_estimate, 0, MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_LEN); + memcpy(vicon_position_estimate, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_vision_position_estimate.h b/vendor/libraries/mavlink/common/mavlink_msg_vision_position_estimate.h index 8f82fb6824..0c351e0845 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_vision_position_estimate.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_vision_position_estimate.h @@ -1,30 +1,35 @@ +#pragma once // MESSAGE VISION_POSITION_ESTIMATE PACKING #define MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE 102 -typedef struct __mavlink_vision_position_estimate_t -{ - uint64_t usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - float x; ///< Global X position - float y; ///< Global Y position - float z; ///< Global Z position - float roll; ///< Roll angle in rad - float pitch; ///< Pitch angle in rad - float yaw; ///< Yaw angle in rad -} mavlink_vision_position_estimate_t; +MAVPACKED( +typedef struct __mavlink_vision_position_estimate_t { + uint64_t usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + float x; /*< Global X position*/ + float y; /*< Global Y position*/ + float z; /*< Global Z position*/ + float roll; /*< Roll angle in rad*/ + float pitch; /*< Pitch angle in rad*/ + float yaw; /*< Yaw angle in rad*/ +}) mavlink_vision_position_estimate_t; #define MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN 32 +#define MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN 32 #define MAVLINK_MSG_ID_102_LEN 32 +#define MAVLINK_MSG_ID_102_MIN_LEN 32 #define MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC 158 #define MAVLINK_MSG_ID_102_CRC 158 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE { \ - "VISION_POSITION_ESTIMATE", \ - 7, \ - { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vision_position_estimate_t, usec) }, \ + 102, \ + "VISION_POSITION_ESTIMATE", \ + 7, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vision_position_estimate_t, usec) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vision_position_estimate_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vision_position_estimate_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vision_position_estimate_t, z) }, \ @@ -33,7 +38,20 @@ typedef struct __mavlink_vision_position_estimate_t { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_vision_position_estimate_t, yaw) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_VISION_POSITION_ESTIMATE { \ + "VISION_POSITION_ESTIMATE", \ + 7, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vision_position_estimate_t, usec) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vision_position_estimate_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vision_position_estimate_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vision_position_estimate_t, z) }, \ + { "roll", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_vision_position_estimate_t, roll) }, \ + { "pitch", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_vision_position_estimate_t, pitch) }, \ + { "yaw", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_vision_position_estimate_t, yaw) }, \ + } \ +} +#endif /** * @brief Pack a vision_position_estimate message @@ -51,38 +69,34 @@ typedef struct __mavlink_vision_position_estimate_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vision_position_estimate_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) + uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); + char buf[MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); #else - mavlink_vision_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_vision_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); } /** @@ -101,39 +115,35 @@ static inline uint16_t mavlink_msg_vision_position_estimate_pack(uint8_t system_ * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vision_position_estimate_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t usec,float x,float y,float z,float roll,float pitch,float yaw) + mavlink_message_t* msg, + uint64_t usec,float x,float y,float z,float roll,float pitch,float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); + char buf[MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); #else - mavlink_vision_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; + mavlink_vision_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); } /** @@ -146,7 +156,7 @@ static inline uint16_t mavlink_msg_vision_position_estimate_pack_chan(uint8_t sy */ static inline uint16_t mavlink_msg_vision_position_estimate_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_vision_position_estimate_t* vision_position_estimate) { - return mavlink_msg_vision_position_estimate_pack(system_id, component_id, msg, vision_position_estimate->usec, vision_position_estimate->x, vision_position_estimate->y, vision_position_estimate->z, vision_position_estimate->roll, vision_position_estimate->pitch, vision_position_estimate->yaw); + return mavlink_msg_vision_position_estimate_pack(system_id, component_id, msg, vision_position_estimate->usec, vision_position_estimate->x, vision_position_estimate->y, vision_position_estimate->z, vision_position_estimate->roll, vision_position_estimate->pitch, vision_position_estimate->yaw); } /** @@ -160,7 +170,7 @@ static inline uint16_t mavlink_msg_vision_position_estimate_encode(uint8_t syste */ static inline uint16_t mavlink_msg_vision_position_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vision_position_estimate_t* vision_position_estimate) { - return mavlink_msg_vision_position_estimate_pack_chan(system_id, component_id, chan, msg, vision_position_estimate->usec, vision_position_estimate->x, vision_position_estimate->y, vision_position_estimate->z, vision_position_estimate->roll, vision_position_estimate->pitch, vision_position_estimate->yaw); + return mavlink_msg_vision_position_estimate_pack_chan(system_id, component_id, chan, msg, vision_position_estimate->usec, vision_position_estimate->x, vision_position_estimate->y, vision_position_estimate->z, vision_position_estimate->roll, vision_position_estimate->pitch, vision_position_estimate->yaw); } /** @@ -180,35 +190,41 @@ static inline uint16_t mavlink_msg_vision_position_estimate_encode_chan(uint8_t static inline void mavlink_msg_vision_position_estimate_send(mavlink_channel_t chan, uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); + char buf[MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); + mavlink_vision_position_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + packet.roll = roll; + packet.pitch = pitch; + packet.yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); #endif +} + +/** + * @brief Send a vision_position_estimate message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_vision_position_estimate_send_struct(mavlink_channel_t chan, const mavlink_vision_position_estimate_t* vision_position_estimate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_vision_position_estimate_send(chan, vision_position_estimate->usec, vision_position_estimate->x, vision_position_estimate->y, vision_position_estimate->z, vision_position_estimate->roll, vision_position_estimate->pitch, vision_position_estimate->yaw); #else - mavlink_vision_position_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - packet.roll = roll; - packet.pitch = pitch; - packet.yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, (const char *)vision_position_estimate, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); #endif } @@ -223,35 +239,27 @@ static inline void mavlink_msg_vision_position_estimate_send(mavlink_channel_t c static inline void mavlink_msg_vision_position_estimate_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t usec, float x, float y, float z, float roll, float pitch, float yaw) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - _mav_put_float(buf, 20, roll); - _mav_put_float(buf, 24, pitch); - _mav_put_float(buf, 28, yaw); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); -#endif -#else - mavlink_vision_position_estimate_t *packet = (mavlink_vision_position_estimate_t *)msgbuf; - packet->usec = usec; - packet->x = x; - packet->y = y; - packet->z = z; - packet->roll = roll; - packet->pitch = pitch; - packet->yaw = yaw; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + _mav_put_float(buf, 20, roll); + _mav_put_float(buf, 24, pitch); + _mav_put_float(buf, 28, yaw); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); -#endif + mavlink_vision_position_estimate_t *packet = (mavlink_vision_position_estimate_t *)msgbuf; + packet->usec = usec; + packet->x = x; + packet->y = y; + packet->z = z; + packet->roll = roll; + packet->pitch = pitch; + packet->yaw = yaw; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_CRC); #endif } #endif @@ -268,7 +276,7 @@ static inline void mavlink_msg_vision_position_estimate_send_buf(mavlink_message */ static inline uint64_t mavlink_msg_vision_position_estimate_get_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -278,7 +286,7 @@ static inline uint64_t mavlink_msg_vision_position_estimate_get_usec(const mavli */ static inline float mavlink_msg_vision_position_estimate_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -288,7 +296,7 @@ static inline float mavlink_msg_vision_position_estimate_get_x(const mavlink_mes */ static inline float mavlink_msg_vision_position_estimate_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -298,7 +306,7 @@ static inline float mavlink_msg_vision_position_estimate_get_y(const mavlink_mes */ static inline float mavlink_msg_vision_position_estimate_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -308,7 +316,7 @@ static inline float mavlink_msg_vision_position_estimate_get_z(const mavlink_mes */ static inline float mavlink_msg_vision_position_estimate_get_roll(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 20); + return _MAV_RETURN_float(msg, 20); } /** @@ -318,7 +326,7 @@ static inline float mavlink_msg_vision_position_estimate_get_roll(const mavlink_ */ static inline float mavlink_msg_vision_position_estimate_get_pitch(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 24); + return _MAV_RETURN_float(msg, 24); } /** @@ -328,7 +336,7 @@ static inline float mavlink_msg_vision_position_estimate_get_pitch(const mavlink */ static inline float mavlink_msg_vision_position_estimate_get_yaw(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 28); + return _MAV_RETURN_float(msg, 28); } /** @@ -339,15 +347,17 @@ static inline float mavlink_msg_vision_position_estimate_get_yaw(const mavlink_m */ static inline void mavlink_msg_vision_position_estimate_decode(const mavlink_message_t* msg, mavlink_vision_position_estimate_t* vision_position_estimate) { -#if MAVLINK_NEED_BYTE_SWAP - vision_position_estimate->usec = mavlink_msg_vision_position_estimate_get_usec(msg); - vision_position_estimate->x = mavlink_msg_vision_position_estimate_get_x(msg); - vision_position_estimate->y = mavlink_msg_vision_position_estimate_get_y(msg); - vision_position_estimate->z = mavlink_msg_vision_position_estimate_get_z(msg); - vision_position_estimate->roll = mavlink_msg_vision_position_estimate_get_roll(msg); - vision_position_estimate->pitch = mavlink_msg_vision_position_estimate_get_pitch(msg); - vision_position_estimate->yaw = mavlink_msg_vision_position_estimate_get_yaw(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + vision_position_estimate->usec = mavlink_msg_vision_position_estimate_get_usec(msg); + vision_position_estimate->x = mavlink_msg_vision_position_estimate_get_x(msg); + vision_position_estimate->y = mavlink_msg_vision_position_estimate_get_y(msg); + vision_position_estimate->z = mavlink_msg_vision_position_estimate_get_z(msg); + vision_position_estimate->roll = mavlink_msg_vision_position_estimate_get_roll(msg); + vision_position_estimate->pitch = mavlink_msg_vision_position_estimate_get_pitch(msg); + vision_position_estimate->yaw = mavlink_msg_vision_position_estimate_get_yaw(msg); #else - memcpy(vision_position_estimate, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN? msg->len : MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN; + memset(vision_position_estimate, 0, MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_LEN); + memcpy(vision_position_estimate, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_vision_speed_estimate.h b/vendor/libraries/mavlink/common/mavlink_msg_vision_speed_estimate.h index 7528014c76..bca094713a 100644 --- a/vendor/libraries/mavlink/common/mavlink_msg_vision_speed_estimate.h +++ b/vendor/libraries/mavlink/common/mavlink_msg_vision_speed_estimate.h @@ -1,33 +1,48 @@ +#pragma once // MESSAGE VISION_SPEED_ESTIMATE PACKING #define MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE 103 -typedef struct __mavlink_vision_speed_estimate_t -{ - uint64_t usec; ///< Timestamp (microseconds, synced to UNIX time or since system boot) - float x; ///< Global X speed - float y; ///< Global Y speed - float z; ///< Global Z speed -} mavlink_vision_speed_estimate_t; +MAVPACKED( +typedef struct __mavlink_vision_speed_estimate_t { + uint64_t usec; /*< Timestamp (microseconds, synced to UNIX time or since system boot)*/ + float x; /*< Global X speed*/ + float y; /*< Global Y speed*/ + float z; /*< Global Z speed*/ +}) mavlink_vision_speed_estimate_t; #define MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN 20 +#define MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN 20 #define MAVLINK_MSG_ID_103_LEN 20 +#define MAVLINK_MSG_ID_103_MIN_LEN 20 #define MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC 208 #define MAVLINK_MSG_ID_103_CRC 208 +#if MAVLINK_COMMAND_24BIT #define MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE { \ - "VISION_SPEED_ESTIMATE", \ - 4, \ - { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vision_speed_estimate_t, usec) }, \ + 103, \ + "VISION_SPEED_ESTIMATE", \ + 4, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vision_speed_estimate_t, usec) }, \ { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vision_speed_estimate_t, x) }, \ { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vision_speed_estimate_t, y) }, \ { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vision_speed_estimate_t, z) }, \ } \ } - +#else +#define MAVLINK_MESSAGE_INFO_VISION_SPEED_ESTIMATE { \ + "VISION_SPEED_ESTIMATE", \ + 4, \ + { { "usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_vision_speed_estimate_t, usec) }, \ + { "x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_vision_speed_estimate_t, x) }, \ + { "y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_vision_speed_estimate_t, y) }, \ + { "z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_vision_speed_estimate_t, z) }, \ + } \ +} +#endif /** * @brief Pack a vision_speed_estimate message @@ -42,32 +57,28 @@ typedef struct __mavlink_vision_speed_estimate_t * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vision_speed_estimate_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, - uint64_t usec, float x, float y, float z) + uint64_t usec, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); + char buf[MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); #else - mavlink_vision_speed_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; + mavlink_vision_speed_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); -#else - return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); } /** @@ -83,33 +94,29 @@ static inline uint16_t mavlink_msg_vision_speed_estimate_pack(uint8_t system_id, * @return length of the message in bytes (excluding serial stream start sign) */ static inline uint16_t mavlink_msg_vision_speed_estimate_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, - mavlink_message_t* msg, - uint64_t usec,float x,float y,float z) + mavlink_message_t* msg, + uint64_t usec,float x,float y,float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); + char buf[MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); #else - mavlink_vision_speed_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; + mavlink_vision_speed_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); #endif - msg->msgid = MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE; -#if MAVLINK_CRC_EXTRA - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); -#else - return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); -#endif + msg->msgid = MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); } /** @@ -122,7 +129,7 @@ static inline uint16_t mavlink_msg_vision_speed_estimate_pack_chan(uint8_t syste */ static inline uint16_t mavlink_msg_vision_speed_estimate_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_vision_speed_estimate_t* vision_speed_estimate) { - return mavlink_msg_vision_speed_estimate_pack(system_id, component_id, msg, vision_speed_estimate->usec, vision_speed_estimate->x, vision_speed_estimate->y, vision_speed_estimate->z); + return mavlink_msg_vision_speed_estimate_pack(system_id, component_id, msg, vision_speed_estimate->usec, vision_speed_estimate->x, vision_speed_estimate->y, vision_speed_estimate->z); } /** @@ -136,7 +143,7 @@ static inline uint16_t mavlink_msg_vision_speed_estimate_encode(uint8_t system_i */ static inline uint16_t mavlink_msg_vision_speed_estimate_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_vision_speed_estimate_t* vision_speed_estimate) { - return mavlink_msg_vision_speed_estimate_pack_chan(system_id, component_id, chan, msg, vision_speed_estimate->usec, vision_speed_estimate->x, vision_speed_estimate->y, vision_speed_estimate->z); + return mavlink_msg_vision_speed_estimate_pack_chan(system_id, component_id, chan, msg, vision_speed_estimate->usec, vision_speed_estimate->x, vision_speed_estimate->y, vision_speed_estimate->z); } /** @@ -153,29 +160,35 @@ static inline uint16_t mavlink_msg_vision_speed_estimate_encode_chan(uint8_t sys static inline void mavlink_msg_vision_speed_estimate_send(mavlink_channel_t chan, uint64_t usec, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char buf[MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN]; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); + char buf[MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN]; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); + mavlink_vision_speed_estimate_t packet; + packet.usec = usec; + packet.x = x; + packet.y = y; + packet.z = z; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); #endif +} + +/** + * @brief Send a vision_speed_estimate message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_vision_speed_estimate_send_struct(mavlink_channel_t chan, const mavlink_vision_speed_estimate_t* vision_speed_estimate) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_vision_speed_estimate_send(chan, vision_speed_estimate->usec, vision_speed_estimate->x, vision_speed_estimate->y, vision_speed_estimate->z); #else - mavlink_vision_speed_estimate_t packet; - packet.usec = usec; - packet.x = x; - packet.y = y; - packet.z = z; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, (const char *)&packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); -#endif + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, (const char *)vision_speed_estimate, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); #endif } @@ -190,29 +203,21 @@ static inline void mavlink_msg_vision_speed_estimate_send(mavlink_channel_t chan static inline void mavlink_msg_vision_speed_estimate_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t usec, float x, float y, float z) { #if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS - char *buf = (char *)msgbuf; - _mav_put_uint64_t(buf, 0, usec); - _mav_put_float(buf, 8, x); - _mav_put_float(buf, 12, y); - _mav_put_float(buf, 16, z); - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); -#else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); -#endif -#else - mavlink_vision_speed_estimate_t *packet = (mavlink_vision_speed_estimate_t *)msgbuf; - packet->usec = usec; - packet->x = x; - packet->y = y; - packet->z = z; - -#if MAVLINK_CRC_EXTRA - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, usec); + _mav_put_float(buf, 8, x); + _mav_put_float(buf, 12, y); + _mav_put_float(buf, 16, z); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, buf, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); #else - _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); -#endif + mavlink_vision_speed_estimate_t *packet = (mavlink_vision_speed_estimate_t *)msgbuf; + packet->usec = usec; + packet->x = x; + packet->y = y; + packet->z = z; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE, (const char *)packet, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_CRC); #endif } #endif @@ -229,7 +234,7 @@ static inline void mavlink_msg_vision_speed_estimate_send_buf(mavlink_message_t */ static inline uint64_t mavlink_msg_vision_speed_estimate_get_usec(const mavlink_message_t* msg) { - return _MAV_RETURN_uint64_t(msg, 0); + return _MAV_RETURN_uint64_t(msg, 0); } /** @@ -239,7 +244,7 @@ static inline uint64_t mavlink_msg_vision_speed_estimate_get_usec(const mavlink_ */ static inline float mavlink_msg_vision_speed_estimate_get_x(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 8); + return _MAV_RETURN_float(msg, 8); } /** @@ -249,7 +254,7 @@ static inline float mavlink_msg_vision_speed_estimate_get_x(const mavlink_messag */ static inline float mavlink_msg_vision_speed_estimate_get_y(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 12); + return _MAV_RETURN_float(msg, 12); } /** @@ -259,7 +264,7 @@ static inline float mavlink_msg_vision_speed_estimate_get_y(const mavlink_messag */ static inline float mavlink_msg_vision_speed_estimate_get_z(const mavlink_message_t* msg) { - return _MAV_RETURN_float(msg, 16); + return _MAV_RETURN_float(msg, 16); } /** @@ -270,12 +275,14 @@ static inline float mavlink_msg_vision_speed_estimate_get_z(const mavlink_messag */ static inline void mavlink_msg_vision_speed_estimate_decode(const mavlink_message_t* msg, mavlink_vision_speed_estimate_t* vision_speed_estimate) { -#if MAVLINK_NEED_BYTE_SWAP - vision_speed_estimate->usec = mavlink_msg_vision_speed_estimate_get_usec(msg); - vision_speed_estimate->x = mavlink_msg_vision_speed_estimate_get_x(msg); - vision_speed_estimate->y = mavlink_msg_vision_speed_estimate_get_y(msg); - vision_speed_estimate->z = mavlink_msg_vision_speed_estimate_get_z(msg); +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + vision_speed_estimate->usec = mavlink_msg_vision_speed_estimate_get_usec(msg); + vision_speed_estimate->x = mavlink_msg_vision_speed_estimate_get_x(msg); + vision_speed_estimate->y = mavlink_msg_vision_speed_estimate_get_y(msg); + vision_speed_estimate->z = mavlink_msg_vision_speed_estimate_get_z(msg); #else - memcpy(vision_speed_estimate, _MAV_PAYLOAD(msg), MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); + uint8_t len = msg->len < MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN? msg->len : MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN; + memset(vision_speed_estimate, 0, MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_LEN); + memcpy(vision_speed_estimate, _MAV_PAYLOAD(msg), len); #endif } diff --git a/vendor/libraries/mavlink/common/mavlink_msg_wind_cov.h b/vendor/libraries/mavlink/common/mavlink_msg_wind_cov.h new file mode 100644 index 0000000000..0562fb0ea3 --- /dev/null +++ b/vendor/libraries/mavlink/common/mavlink_msg_wind_cov.h @@ -0,0 +1,413 @@ +#pragma once +// MESSAGE WIND_COV PACKING + +#define MAVLINK_MSG_ID_WIND_COV 231 + +MAVPACKED( +typedef struct __mavlink_wind_cov_t { + uint64_t time_usec; /*< Timestamp (micros since boot or Unix epoch)*/ + float wind_x; /*< Wind in X (NED) direction in m/s*/ + float wind_y; /*< Wind in Y (NED) direction in m/s*/ + float wind_z; /*< Wind in Z (NED) direction in m/s*/ + float var_horiz; /*< Variability of the wind in XY. RMS of a 1 Hz lowpassed wind estimate.*/ + float var_vert; /*< Variability of the wind in Z. RMS of a 1 Hz lowpassed wind estimate.*/ + float wind_alt; /*< AMSL altitude (m) this measurement was taken at*/ + float horiz_accuracy; /*< Horizontal speed 1-STD accuracy*/ + float vert_accuracy; /*< Vertical speed 1-STD accuracy*/ +}) mavlink_wind_cov_t; + +#define MAVLINK_MSG_ID_WIND_COV_LEN 40 +#define MAVLINK_MSG_ID_WIND_COV_MIN_LEN 40 +#define MAVLINK_MSG_ID_231_LEN 40 +#define MAVLINK_MSG_ID_231_MIN_LEN 40 + +#define MAVLINK_MSG_ID_WIND_COV_CRC 105 +#define MAVLINK_MSG_ID_231_CRC 105 + + + +#if MAVLINK_COMMAND_24BIT +#define MAVLINK_MESSAGE_INFO_WIND_COV { \ + 231, \ + "WIND_COV", \ + 9, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_wind_cov_t, time_usec) }, \ + { "wind_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_wind_cov_t, wind_x) }, \ + { "wind_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_wind_cov_t, wind_y) }, \ + { "wind_z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_wind_cov_t, wind_z) }, \ + { "var_horiz", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_wind_cov_t, var_horiz) }, \ + { "var_vert", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_wind_cov_t, var_vert) }, \ + { "wind_alt", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_wind_cov_t, wind_alt) }, \ + { "horiz_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_wind_cov_t, horiz_accuracy) }, \ + { "vert_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_wind_cov_t, vert_accuracy) }, \ + } \ +} +#else +#define MAVLINK_MESSAGE_INFO_WIND_COV { \ + "WIND_COV", \ + 9, \ + { { "time_usec", NULL, MAVLINK_TYPE_UINT64_T, 0, 0, offsetof(mavlink_wind_cov_t, time_usec) }, \ + { "wind_x", NULL, MAVLINK_TYPE_FLOAT, 0, 8, offsetof(mavlink_wind_cov_t, wind_x) }, \ + { "wind_y", NULL, MAVLINK_TYPE_FLOAT, 0, 12, offsetof(mavlink_wind_cov_t, wind_y) }, \ + { "wind_z", NULL, MAVLINK_TYPE_FLOAT, 0, 16, offsetof(mavlink_wind_cov_t, wind_z) }, \ + { "var_horiz", NULL, MAVLINK_TYPE_FLOAT, 0, 20, offsetof(mavlink_wind_cov_t, var_horiz) }, \ + { "var_vert", NULL, MAVLINK_TYPE_FLOAT, 0, 24, offsetof(mavlink_wind_cov_t, var_vert) }, \ + { "wind_alt", NULL, MAVLINK_TYPE_FLOAT, 0, 28, offsetof(mavlink_wind_cov_t, wind_alt) }, \ + { "horiz_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 32, offsetof(mavlink_wind_cov_t, horiz_accuracy) }, \ + { "vert_accuracy", NULL, MAVLINK_TYPE_FLOAT, 0, 36, offsetof(mavlink_wind_cov_t, vert_accuracy) }, \ + } \ +} +#endif + +/** + * @brief Pack a wind_cov message + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param wind_x Wind in X (NED) direction in m/s + * @param wind_y Wind in Y (NED) direction in m/s + * @param wind_z Wind in Z (NED) direction in m/s + * @param var_horiz Variability of the wind in XY. RMS of a 1 Hz lowpassed wind estimate. + * @param var_vert Variability of the wind in Z. RMS of a 1 Hz lowpassed wind estimate. + * @param wind_alt AMSL altitude (m) this measurement was taken at + * @param horiz_accuracy Horizontal speed 1-STD accuracy + * @param vert_accuracy Vertical speed 1-STD accuracy + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_wind_cov_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, + uint64_t time_usec, float wind_x, float wind_y, float wind_z, float var_horiz, float var_vert, float wind_alt, float horiz_accuracy, float vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_WIND_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, wind_x); + _mav_put_float(buf, 12, wind_y); + _mav_put_float(buf, 16, wind_z); + _mav_put_float(buf, 20, var_horiz); + _mav_put_float(buf, 24, var_vert); + _mav_put_float(buf, 28, wind_alt); + _mav_put_float(buf, 32, horiz_accuracy); + _mav_put_float(buf, 36, vert_accuracy); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_WIND_COV_LEN); +#else + mavlink_wind_cov_t packet; + packet.time_usec = time_usec; + packet.wind_x = wind_x; + packet.wind_y = wind_y; + packet.wind_z = wind_z; + packet.var_horiz = var_horiz; + packet.var_vert = var_vert; + packet.wind_alt = wind_alt; + packet.horiz_accuracy = horiz_accuracy; + packet.vert_accuracy = vert_accuracy; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_WIND_COV_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_WIND_COV; + return mavlink_finalize_message(msg, system_id, component_id, MAVLINK_MSG_ID_WIND_COV_MIN_LEN, MAVLINK_MSG_ID_WIND_COV_LEN, MAVLINK_MSG_ID_WIND_COV_CRC); +} + +/** + * @brief Pack a wind_cov message on a channel + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param wind_x Wind in X (NED) direction in m/s + * @param wind_y Wind in Y (NED) direction in m/s + * @param wind_z Wind in Z (NED) direction in m/s + * @param var_horiz Variability of the wind in XY. RMS of a 1 Hz lowpassed wind estimate. + * @param var_vert Variability of the wind in Z. RMS of a 1 Hz lowpassed wind estimate. + * @param wind_alt AMSL altitude (m) this measurement was taken at + * @param horiz_accuracy Horizontal speed 1-STD accuracy + * @param vert_accuracy Vertical speed 1-STD accuracy + * @return length of the message in bytes (excluding serial stream start sign) + */ +static inline uint16_t mavlink_msg_wind_cov_pack_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, + mavlink_message_t* msg, + uint64_t time_usec,float wind_x,float wind_y,float wind_z,float var_horiz,float var_vert,float wind_alt,float horiz_accuracy,float vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_WIND_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, wind_x); + _mav_put_float(buf, 12, wind_y); + _mav_put_float(buf, 16, wind_z); + _mav_put_float(buf, 20, var_horiz); + _mav_put_float(buf, 24, var_vert); + _mav_put_float(buf, 28, wind_alt); + _mav_put_float(buf, 32, horiz_accuracy); + _mav_put_float(buf, 36, vert_accuracy); + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), buf, MAVLINK_MSG_ID_WIND_COV_LEN); +#else + mavlink_wind_cov_t packet; + packet.time_usec = time_usec; + packet.wind_x = wind_x; + packet.wind_y = wind_y; + packet.wind_z = wind_z; + packet.var_horiz = var_horiz; + packet.var_vert = var_vert; + packet.wind_alt = wind_alt; + packet.horiz_accuracy = horiz_accuracy; + packet.vert_accuracy = vert_accuracy; + + memcpy(_MAV_PAYLOAD_NON_CONST(msg), &packet, MAVLINK_MSG_ID_WIND_COV_LEN); +#endif + + msg->msgid = MAVLINK_MSG_ID_WIND_COV; + return mavlink_finalize_message_chan(msg, system_id, component_id, chan, MAVLINK_MSG_ID_WIND_COV_MIN_LEN, MAVLINK_MSG_ID_WIND_COV_LEN, MAVLINK_MSG_ID_WIND_COV_CRC); +} + +/** + * @brief Encode a wind_cov struct + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param msg The MAVLink message to compress the data into + * @param wind_cov C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_wind_cov_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const mavlink_wind_cov_t* wind_cov) +{ + return mavlink_msg_wind_cov_pack(system_id, component_id, msg, wind_cov->time_usec, wind_cov->wind_x, wind_cov->wind_y, wind_cov->wind_z, wind_cov->var_horiz, wind_cov->var_vert, wind_cov->wind_alt, wind_cov->horiz_accuracy, wind_cov->vert_accuracy); +} + +/** + * @brief Encode a wind_cov struct on a channel + * + * @param system_id ID of this system + * @param component_id ID of this component (e.g. 200 for IMU) + * @param chan The MAVLink channel this message will be sent over + * @param msg The MAVLink message to compress the data into + * @param wind_cov C-struct to read the message contents from + */ +static inline uint16_t mavlink_msg_wind_cov_encode_chan(uint8_t system_id, uint8_t component_id, uint8_t chan, mavlink_message_t* msg, const mavlink_wind_cov_t* wind_cov) +{ + return mavlink_msg_wind_cov_pack_chan(system_id, component_id, chan, msg, wind_cov->time_usec, wind_cov->wind_x, wind_cov->wind_y, wind_cov->wind_z, wind_cov->var_horiz, wind_cov->var_vert, wind_cov->wind_alt, wind_cov->horiz_accuracy, wind_cov->vert_accuracy); +} + +/** + * @brief Send a wind_cov message + * @param chan MAVLink channel to send the message + * + * @param time_usec Timestamp (micros since boot or Unix epoch) + * @param wind_x Wind in X (NED) direction in m/s + * @param wind_y Wind in Y (NED) direction in m/s + * @param wind_z Wind in Z (NED) direction in m/s + * @param var_horiz Variability of the wind in XY. RMS of a 1 Hz lowpassed wind estimate. + * @param var_vert Variability of the wind in Z. RMS of a 1 Hz lowpassed wind estimate. + * @param wind_alt AMSL altitude (m) this measurement was taken at + * @param horiz_accuracy Horizontal speed 1-STD accuracy + * @param vert_accuracy Vertical speed 1-STD accuracy + */ +#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS + +static inline void mavlink_msg_wind_cov_send(mavlink_channel_t chan, uint64_t time_usec, float wind_x, float wind_y, float wind_z, float var_horiz, float var_vert, float wind_alt, float horiz_accuracy, float vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char buf[MAVLINK_MSG_ID_WIND_COV_LEN]; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, wind_x); + _mav_put_float(buf, 12, wind_y); + _mav_put_float(buf, 16, wind_z); + _mav_put_float(buf, 20, var_horiz); + _mav_put_float(buf, 24, var_vert); + _mav_put_float(buf, 28, wind_alt); + _mav_put_float(buf, 32, horiz_accuracy); + _mav_put_float(buf, 36, vert_accuracy); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND_COV, buf, MAVLINK_MSG_ID_WIND_COV_MIN_LEN, MAVLINK_MSG_ID_WIND_COV_LEN, MAVLINK_MSG_ID_WIND_COV_CRC); +#else + mavlink_wind_cov_t packet; + packet.time_usec = time_usec; + packet.wind_x = wind_x; + packet.wind_y = wind_y; + packet.wind_z = wind_z; + packet.var_horiz = var_horiz; + packet.var_vert = var_vert; + packet.wind_alt = wind_alt; + packet.horiz_accuracy = horiz_accuracy; + packet.vert_accuracy = vert_accuracy; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND_COV, (const char *)&packet, MAVLINK_MSG_ID_WIND_COV_MIN_LEN, MAVLINK_MSG_ID_WIND_COV_LEN, MAVLINK_MSG_ID_WIND_COV_CRC); +#endif +} + +/** + * @brief Send a wind_cov message + * @param chan MAVLink channel to send the message + * @param struct The MAVLink struct to serialize + */ +static inline void mavlink_msg_wind_cov_send_struct(mavlink_channel_t chan, const mavlink_wind_cov_t* wind_cov) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + mavlink_msg_wind_cov_send(chan, wind_cov->time_usec, wind_cov->wind_x, wind_cov->wind_y, wind_cov->wind_z, wind_cov->var_horiz, wind_cov->var_vert, wind_cov->wind_alt, wind_cov->horiz_accuracy, wind_cov->vert_accuracy); +#else + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND_COV, (const char *)wind_cov, MAVLINK_MSG_ID_WIND_COV_MIN_LEN, MAVLINK_MSG_ID_WIND_COV_LEN, MAVLINK_MSG_ID_WIND_COV_CRC); +#endif +} + +#if MAVLINK_MSG_ID_WIND_COV_LEN <= MAVLINK_MAX_PAYLOAD_LEN +/* + This varient of _send() can be used to save stack space by re-using + memory from the receive buffer. The caller provides a + mavlink_message_t which is the size of a full mavlink message. This + is usually the receive buffer for the channel, and allows a reply to an + incoming message with minimum stack space usage. + */ +static inline void mavlink_msg_wind_cov_send_buf(mavlink_message_t *msgbuf, mavlink_channel_t chan, uint64_t time_usec, float wind_x, float wind_y, float wind_z, float var_horiz, float var_vert, float wind_alt, float horiz_accuracy, float vert_accuracy) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + char *buf = (char *)msgbuf; + _mav_put_uint64_t(buf, 0, time_usec); + _mav_put_float(buf, 8, wind_x); + _mav_put_float(buf, 12, wind_y); + _mav_put_float(buf, 16, wind_z); + _mav_put_float(buf, 20, var_horiz); + _mav_put_float(buf, 24, var_vert); + _mav_put_float(buf, 28, wind_alt); + _mav_put_float(buf, 32, horiz_accuracy); + _mav_put_float(buf, 36, vert_accuracy); + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND_COV, buf, MAVLINK_MSG_ID_WIND_COV_MIN_LEN, MAVLINK_MSG_ID_WIND_COV_LEN, MAVLINK_MSG_ID_WIND_COV_CRC); +#else + mavlink_wind_cov_t *packet = (mavlink_wind_cov_t *)msgbuf; + packet->time_usec = time_usec; + packet->wind_x = wind_x; + packet->wind_y = wind_y; + packet->wind_z = wind_z; + packet->var_horiz = var_horiz; + packet->var_vert = var_vert; + packet->wind_alt = wind_alt; + packet->horiz_accuracy = horiz_accuracy; + packet->vert_accuracy = vert_accuracy; + + _mav_finalize_message_chan_send(chan, MAVLINK_MSG_ID_WIND_COV, (const char *)packet, MAVLINK_MSG_ID_WIND_COV_MIN_LEN, MAVLINK_MSG_ID_WIND_COV_LEN, MAVLINK_MSG_ID_WIND_COV_CRC); +#endif +} +#endif + +#endif + +// MESSAGE WIND_COV UNPACKING + + +/** + * @brief Get field time_usec from wind_cov message + * + * @return Timestamp (micros since boot or Unix epoch) + */ +static inline uint64_t mavlink_msg_wind_cov_get_time_usec(const mavlink_message_t* msg) +{ + return _MAV_RETURN_uint64_t(msg, 0); +} + +/** + * @brief Get field wind_x from wind_cov message + * + * @return Wind in X (NED) direction in m/s + */ +static inline float mavlink_msg_wind_cov_get_wind_x(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 8); +} + +/** + * @brief Get field wind_y from wind_cov message + * + * @return Wind in Y (NED) direction in m/s + */ +static inline float mavlink_msg_wind_cov_get_wind_y(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 12); +} + +/** + * @brief Get field wind_z from wind_cov message + * + * @return Wind in Z (NED) direction in m/s + */ +static inline float mavlink_msg_wind_cov_get_wind_z(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 16); +} + +/** + * @brief Get field var_horiz from wind_cov message + * + * @return Variability of the wind in XY. RMS of a 1 Hz lowpassed wind estimate. + */ +static inline float mavlink_msg_wind_cov_get_var_horiz(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 20); +} + +/** + * @brief Get field var_vert from wind_cov message + * + * @return Variability of the wind in Z. RMS of a 1 Hz lowpassed wind estimate. + */ +static inline float mavlink_msg_wind_cov_get_var_vert(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 24); +} + +/** + * @brief Get field wind_alt from wind_cov message + * + * @return AMSL altitude (m) this measurement was taken at + */ +static inline float mavlink_msg_wind_cov_get_wind_alt(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 28); +} + +/** + * @brief Get field horiz_accuracy from wind_cov message + * + * @return Horizontal speed 1-STD accuracy + */ +static inline float mavlink_msg_wind_cov_get_horiz_accuracy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 32); +} + +/** + * @brief Get field vert_accuracy from wind_cov message + * + * @return Vertical speed 1-STD accuracy + */ +static inline float mavlink_msg_wind_cov_get_vert_accuracy(const mavlink_message_t* msg) +{ + return _MAV_RETURN_float(msg, 36); +} + +/** + * @brief Decode a wind_cov message into a struct + * + * @param msg The message to decode + * @param wind_cov C-struct to decode the message contents into + */ +static inline void mavlink_msg_wind_cov_decode(const mavlink_message_t* msg, mavlink_wind_cov_t* wind_cov) +{ +#if MAVLINK_NEED_BYTE_SWAP || !MAVLINK_ALIGNED_FIELDS + wind_cov->time_usec = mavlink_msg_wind_cov_get_time_usec(msg); + wind_cov->wind_x = mavlink_msg_wind_cov_get_wind_x(msg); + wind_cov->wind_y = mavlink_msg_wind_cov_get_wind_y(msg); + wind_cov->wind_z = mavlink_msg_wind_cov_get_wind_z(msg); + wind_cov->var_horiz = mavlink_msg_wind_cov_get_var_horiz(msg); + wind_cov->var_vert = mavlink_msg_wind_cov_get_var_vert(msg); + wind_cov->wind_alt = mavlink_msg_wind_cov_get_wind_alt(msg); + wind_cov->horiz_accuracy = mavlink_msg_wind_cov_get_horiz_accuracy(msg); + wind_cov->vert_accuracy = mavlink_msg_wind_cov_get_vert_accuracy(msg); +#else + uint8_t len = msg->len < MAVLINK_MSG_ID_WIND_COV_LEN? msg->len : MAVLINK_MSG_ID_WIND_COV_LEN; + memset(wind_cov, 0, MAVLINK_MSG_ID_WIND_COV_LEN); + memcpy(wind_cov, _MAV_PAYLOAD(msg), len); +#endif +} diff --git a/vendor/libraries/mavlink/common/testsuite.h b/vendor/libraries/mavlink/common/testsuite.h index b0d4ffb41f..1952d024a3 100644 --- a/vendor/libraries/mavlink/common/testsuite.h +++ b/vendor/libraries/mavlink/common/testsuite.h @@ -1,7 +1,8 @@ /** @file - * @brief MAVLink comm protocol testsuite generated from common.xml - * @see http://qgroundcontrol.org/mavlink/ + * @brief MAVLink comm protocol testsuite generated from common.xml + * @see http://qgroundcontrol.org/mavlink/ */ +#pragma once #ifndef COMMON_TESTSUITE_H #define COMMON_TESTSUITE_H @@ -17,7 +18,7 @@ static void mavlink_test_common(uint8_t, uint8_t, mavlink_message_t *last_msg); static void mavlink_test_all(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg) { - mavlink_test_common(system_id, component_id, last_msg); + mavlink_test_common(system_id, component_id, last_msg); } #endif @@ -26,5727 +27,8357 @@ static void mavlink_test_all(uint8_t system_id, uint8_t component_id, mavlink_me static void mavlink_test_heartbeat(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg) { - mavlink_message_t msg; +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + mavlink_status_t *status = mavlink_get_channel_status(MAVLINK_COMM_0); + if ((status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HEARTBEAT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_heartbeat_t packet_in = { - 963497464,17,84,151,218,3 + mavlink_heartbeat_t packet_in = { + 963497464,17,84,151,218,3 }; - mavlink_heartbeat_t packet1, packet2; + mavlink_heartbeat_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.custom_mode = packet_in.custom_mode; - packet1.type = packet_in.type; - packet1.autopilot = packet_in.autopilot; - packet1.base_mode = packet_in.base_mode; - packet1.system_status = packet_in.system_status; - packet1.mavlink_version = packet_in.mavlink_version; - - - + packet1.custom_mode = packet_in.custom_mode; + packet1.type = packet_in.type; + packet1.autopilot = packet_in.autopilot; + packet1.base_mode = packet_in.base_mode; + packet1.system_status = packet_in.system_status; + packet1.mavlink_version = packet_in.mavlink_version; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HEARTBEAT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_heartbeat_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_heartbeat_decode(&msg, &packet2); + mavlink_msg_heartbeat_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_heartbeat_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_heartbeat_pack(system_id, component_id, &msg , packet1.type , packet1.autopilot , packet1.base_mode , packet1.custom_mode , packet1.system_status ); - mavlink_msg_heartbeat_decode(&msg, &packet2); + mavlink_msg_heartbeat_pack(system_id, component_id, &msg , packet1.type , packet1.autopilot , packet1.base_mode , packet1.custom_mode , packet1.system_status ); + mavlink_msg_heartbeat_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_heartbeat_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.autopilot , packet1.base_mode , packet1.custom_mode , packet1.system_status ); - mavlink_msg_heartbeat_decode(&msg, &packet2); + mavlink_msg_heartbeat_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.autopilot , packet1.base_mode , packet1.custom_mode , packet1.system_status ); + mavlink_msg_heartbeat_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SYS_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_sys_status_t packet_in = { - 963497464,963497672,963497880,17859,17963,18067,18171,18275,18379,18483,18587,18691,223 + mavlink_sys_status_t packet_in = { + 963497464,963497672,963497880,17859,17963,18067,18171,18275,18379,18483,18587,18691,223 }; - mavlink_sys_status_t packet1, packet2; + mavlink_sys_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.onboard_control_sensors_present = packet_in.onboard_control_sensors_present; - packet1.onboard_control_sensors_enabled = packet_in.onboard_control_sensors_enabled; - packet1.onboard_control_sensors_health = packet_in.onboard_control_sensors_health; - packet1.load = packet_in.load; - packet1.voltage_battery = packet_in.voltage_battery; - packet1.current_battery = packet_in.current_battery; - packet1.drop_rate_comm = packet_in.drop_rate_comm; - packet1.errors_comm = packet_in.errors_comm; - packet1.errors_count1 = packet_in.errors_count1; - packet1.errors_count2 = packet_in.errors_count2; - packet1.errors_count3 = packet_in.errors_count3; - packet1.errors_count4 = packet_in.errors_count4; - packet1.battery_remaining = packet_in.battery_remaining; - - - + packet1.onboard_control_sensors_present = packet_in.onboard_control_sensors_present; + packet1.onboard_control_sensors_enabled = packet_in.onboard_control_sensors_enabled; + packet1.onboard_control_sensors_health = packet_in.onboard_control_sensors_health; + packet1.load = packet_in.load; + packet1.voltage_battery = packet_in.voltage_battery; + packet1.current_battery = packet_in.current_battery; + packet1.drop_rate_comm = packet_in.drop_rate_comm; + packet1.errors_comm = packet_in.errors_comm; + packet1.errors_count1 = packet_in.errors_count1; + packet1.errors_count2 = packet_in.errors_count2; + packet1.errors_count3 = packet_in.errors_count3; + packet1.errors_count4 = packet_in.errors_count4; + packet1.battery_remaining = packet_in.battery_remaining; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SYS_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sys_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_sys_status_decode(&msg, &packet2); + mavlink_msg_sys_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_sys_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sys_status_pack(system_id, component_id, &msg , packet1.onboard_control_sensors_present , packet1.onboard_control_sensors_enabled , packet1.onboard_control_sensors_health , packet1.load , packet1.voltage_battery , packet1.current_battery , packet1.battery_remaining , packet1.drop_rate_comm , packet1.errors_comm , packet1.errors_count1 , packet1.errors_count2 , packet1.errors_count3 , packet1.errors_count4 ); - mavlink_msg_sys_status_decode(&msg, &packet2); + mavlink_msg_sys_status_pack(system_id, component_id, &msg , packet1.onboard_control_sensors_present , packet1.onboard_control_sensors_enabled , packet1.onboard_control_sensors_health , packet1.load , packet1.voltage_battery , packet1.current_battery , packet1.battery_remaining , packet1.drop_rate_comm , packet1.errors_comm , packet1.errors_count1 , packet1.errors_count2 , packet1.errors_count3 , packet1.errors_count4 ); + mavlink_msg_sys_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sys_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.onboard_control_sensors_present , packet1.onboard_control_sensors_enabled , packet1.onboard_control_sensors_health , packet1.load , packet1.voltage_battery , packet1.current_battery , packet1.battery_remaining , packet1.drop_rate_comm , packet1.errors_comm , packet1.errors_count1 , packet1.errors_count2 , packet1.errors_count3 , packet1.errors_count4 ); - mavlink_msg_sys_status_decode(&msg, &packet2); + mavlink_msg_sys_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.onboard_control_sensors_present , packet1.onboard_control_sensors_enabled , packet1.onboard_control_sensors_health , packet1.load , packet1.voltage_battery , packet1.current_battery , packet1.battery_remaining , packet1.drop_rate_comm , packet1.errors_comm , packet1.errors_count1 , packet1.errors_count2 , packet1.errors_count3 , packet1.errors_count4 ); + mavlink_msg_sys_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SYSTEM_TIME >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_system_time_t packet_in = { - 93372036854775807ULL,963497880 + mavlink_system_time_t packet_in = { + 93372036854775807ULL,963497880 }; - mavlink_system_time_t packet1, packet2; + mavlink_system_time_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_unix_usec = packet_in.time_unix_usec; - packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.time_unix_usec = packet_in.time_unix_usec; + packet1.time_boot_ms = packet_in.time_boot_ms; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SYSTEM_TIME_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_system_time_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_system_time_decode(&msg, &packet2); + mavlink_msg_system_time_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_system_time_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_system_time_pack(system_id, component_id, &msg , packet1.time_unix_usec , packet1.time_boot_ms ); - mavlink_msg_system_time_decode(&msg, &packet2); + mavlink_msg_system_time_pack(system_id, component_id, &msg , packet1.time_unix_usec , packet1.time_boot_ms ); + mavlink_msg_system_time_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_system_time_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_unix_usec , packet1.time_boot_ms ); - mavlink_msg_system_time_decode(&msg, &packet2); + mavlink_msg_system_time_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_unix_usec , packet1.time_boot_ms ); + mavlink_msg_system_time_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_PING >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_ping_t packet_in = { - 93372036854775807ULL,963497880,41,108 + mavlink_ping_t packet_in = { + 93372036854775807ULL,963497880,41,108 }; - mavlink_ping_t packet1, packet2; + mavlink_ping_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.seq = packet_in.seq; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.time_usec = packet_in.time_usec; + packet1.seq = packet_in.seq; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_PING_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_PING_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ping_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_ping_decode(&msg, &packet2); + mavlink_msg_ping_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_ping_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ping_pack(system_id, component_id, &msg , packet1.time_usec , packet1.seq , packet1.target_system , packet1.target_component ); - mavlink_msg_ping_decode(&msg, &packet2); + mavlink_msg_ping_pack(system_id, component_id, &msg , packet1.time_usec , packet1.seq , packet1.target_system , packet1.target_component ); + mavlink_msg_ping_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_ping_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.seq , packet1.target_system , packet1.target_component ); - mavlink_msg_ping_decode(&msg, &packet2); + mavlink_msg_ping_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.seq , packet1.target_system , packet1.target_component ); + mavlink_msg_ping_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_change_operator_control_t packet_in = { - 5,72,139,"DEFGHIJKLMNOPQRSTUVWXYZA" + mavlink_change_operator_control_t packet_in = { + 5,72,139,"DEFGHIJKLMNOPQRSTUVWXYZA" }; - mavlink_change_operator_control_t packet1, packet2; + mavlink_change_operator_control_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.control_request = packet_in.control_request; - packet1.version = packet_in.version; + packet1.target_system = packet_in.target_system; + packet1.control_request = packet_in.control_request; + packet1.version = packet_in.version; - mav_array_memcpy(packet1.passkey, packet_in.passkey, sizeof(char)*25); + mav_array_memcpy(packet1.passkey, packet_in.passkey, sizeof(char)*25); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_change_operator_control_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_change_operator_control_decode(&msg, &packet2); + mavlink_msg_change_operator_control_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_change_operator_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_change_operator_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.control_request , packet1.version , packet1.passkey ); - mavlink_msg_change_operator_control_decode(&msg, &packet2); + mavlink_msg_change_operator_control_pack(system_id, component_id, &msg , packet1.target_system , packet1.control_request , packet1.version , packet1.passkey ); + mavlink_msg_change_operator_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_change_operator_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.control_request , packet1.version , packet1.passkey ); - mavlink_msg_change_operator_control_decode(&msg, &packet2); + mavlink_msg_change_operator_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.control_request , packet1.version , packet1.passkey ); + mavlink_msg_change_operator_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_change_operator_control_ack_t packet_in = { - 5,72,139 + mavlink_change_operator_control_ack_t packet_in = { + 5,72,139 }; - mavlink_change_operator_control_ack_t packet1, packet2; + mavlink_change_operator_control_ack_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.gcs_system_id = packet_in.gcs_system_id; - packet1.control_request = packet_in.control_request; - packet1.ack = packet_in.ack; + packet1.gcs_system_id = packet_in.gcs_system_id; + packet1.control_request = packet_in.control_request; + packet1.ack = packet_in.ack; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_CHANGE_OPERATOR_CONTROL_ACK_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_change_operator_control_ack_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_change_operator_control_ack_decode(&msg, &packet2); + mavlink_msg_change_operator_control_ack_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_change_operator_control_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_change_operator_control_ack_pack(system_id, component_id, &msg , packet1.gcs_system_id , packet1.control_request , packet1.ack ); - mavlink_msg_change_operator_control_ack_decode(&msg, &packet2); + mavlink_msg_change_operator_control_ack_pack(system_id, component_id, &msg , packet1.gcs_system_id , packet1.control_request , packet1.ack ); + mavlink_msg_change_operator_control_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_change_operator_control_ack_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.gcs_system_id , packet1.control_request , packet1.ack ); - mavlink_msg_change_operator_control_ack_decode(&msg, &packet2); + mavlink_msg_change_operator_control_ack_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.gcs_system_id , packet1.control_request , packet1.ack ); + mavlink_msg_change_operator_control_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AUTH_KEY >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_auth_key_t packet_in = { - "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE" + mavlink_auth_key_t packet_in = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE" }; - mavlink_auth_key_t packet1, packet2; + mavlink_auth_key_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - mav_array_memcpy(packet1.key, packet_in.key, sizeof(char)*32); + mav_array_memcpy(packet1.key, packet_in.key, sizeof(char)*32); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AUTH_KEY_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_auth_key_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_auth_key_decode(&msg, &packet2); + mavlink_msg_auth_key_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_auth_key_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_auth_key_pack(system_id, component_id, &msg , packet1.key ); - mavlink_msg_auth_key_decode(&msg, &packet2); + mavlink_msg_auth_key_pack(system_id, component_id, &msg , packet1.key ); + mavlink_msg_auth_key_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_auth_key_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.key ); - mavlink_msg_auth_key_decode(&msg, &packet2); + mavlink_msg_auth_key_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.key ); + mavlink_msg_auth_key_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_MODE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_set_mode_t packet_in = { - 963497464,17,84 + mavlink_set_mode_t packet_in = { + 963497464,17,84 }; - mavlink_set_mode_t packet1, packet2; + mavlink_set_mode_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.custom_mode = packet_in.custom_mode; - packet1.target_system = packet_in.target_system; - packet1.base_mode = packet_in.base_mode; + packet1.custom_mode = packet_in.custom_mode; + packet1.target_system = packet_in.target_system; + packet1.base_mode = packet_in.base_mode; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_MODE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_MODE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_mode_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_set_mode_decode(&msg, &packet2); + mavlink_msg_set_mode_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_mode_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_mode_pack(system_id, component_id, &msg , packet1.target_system , packet1.base_mode , packet1.custom_mode ); - mavlink_msg_set_mode_decode(&msg, &packet2); + mavlink_msg_set_mode_pack(system_id, component_id, &msg , packet1.target_system , packet1.base_mode , packet1.custom_mode ); + mavlink_msg_set_mode_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_mode_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.base_mode , packet1.custom_mode ); - mavlink_msg_set_mode_decode(&msg, &packet2); + mavlink_msg_set_mode_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.base_mode , packet1.custom_mode ); + mavlink_msg_set_mode_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_PARAM_REQUEST_READ >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_param_request_read_t packet_in = { - 17235,139,206,"EFGHIJKLMNOPQRS" + mavlink_param_request_read_t packet_in = { + 17235,139,206,"EFGHIJKLMNOPQRS" }; - mavlink_param_request_read_t packet1, packet2; + mavlink_param_request_read_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param_index = packet_in.param_index; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.param_index = packet_in.param_index; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); + mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_PARAM_REQUEST_READ_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_request_read_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_param_request_read_decode(&msg, &packet2); + mavlink_msg_param_request_read_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_param_request_read_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_request_read_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index ); - mavlink_msg_param_request_read_decode(&msg, &packet2); + mavlink_msg_param_request_read_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index ); + mavlink_msg_param_request_read_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_request_read_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index ); - mavlink_msg_param_request_read_decode(&msg, &packet2); + mavlink_msg_param_request_read_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index ); + mavlink_msg_param_request_read_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_PARAM_REQUEST_LIST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_param_request_list_t packet_in = { - 5,72 + mavlink_param_request_list_t packet_in = { + 5,72 }; - mavlink_param_request_list_t packet1, packet2; + mavlink_param_request_list_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_PARAM_REQUEST_LIST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_request_list_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_param_request_list_decode(&msg, &packet2); + mavlink_msg_param_request_list_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_param_request_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_request_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_param_request_list_decode(&msg, &packet2); + mavlink_msg_param_request_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_param_request_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_request_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_param_request_list_decode(&msg, &packet2); + mavlink_msg_param_request_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_param_request_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_PARAM_VALUE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_param_value_t packet_in = { - 17.0,17443,17547,"IJKLMNOPQRSTUVW",77 + mavlink_param_value_t packet_in = { + 17.0,17443,17547,"IJKLMNOPQRSTUVW",77 }; - mavlink_param_value_t packet1, packet2; + mavlink_param_value_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param_value = packet_in.param_value; - packet1.param_count = packet_in.param_count; - packet1.param_index = packet_in.param_index; - packet1.param_type = packet_in.param_type; + packet1.param_value = packet_in.param_value; + packet1.param_count = packet_in.param_count; + packet1.param_index = packet_in.param_index; + packet1.param_type = packet_in.param_type; - mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); + mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_PARAM_VALUE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_value_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_param_value_decode(&msg, &packet2); + mavlink_msg_param_value_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_param_value_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_value_pack(system_id, component_id, &msg , packet1.param_id , packet1.param_value , packet1.param_type , packet1.param_count , packet1.param_index ); - mavlink_msg_param_value_decode(&msg, &packet2); + mavlink_msg_param_value_pack(system_id, component_id, &msg , packet1.param_id , packet1.param_value , packet1.param_type , packet1.param_count , packet1.param_index ); + mavlink_msg_param_value_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_value_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.param_id , packet1.param_value , packet1.param_type , packet1.param_count , packet1.param_index ); - mavlink_msg_param_value_decode(&msg, &packet2); + mavlink_msg_param_value_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.param_id , packet1.param_value , packet1.param_type , packet1.param_count , packet1.param_index ); + mavlink_msg_param_value_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_PARAM_SET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_param_set_t packet_in = { - 17.0,17,84,"GHIJKLMNOPQRSTU",199 + mavlink_param_set_t packet_in = { + 17.0,17,84,"GHIJKLMNOPQRSTU",199 }; - mavlink_param_set_t packet1, packet2; + mavlink_param_set_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param_value = packet_in.param_value; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.param_type = packet_in.param_type; + packet1.param_value = packet_in.param_value; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.param_type = packet_in.param_type; - mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); + mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_PARAM_SET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_PARAM_SET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_set_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_param_set_decode(&msg, &packet2); + mavlink_msg_param_set_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_param_set_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_set_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_value , packet1.param_type ); - mavlink_msg_param_set_decode(&msg, &packet2); + mavlink_msg_param_set_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_value , packet1.param_type ); + mavlink_msg_param_set_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_set_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_value , packet1.param_type ); - mavlink_msg_param_set_decode(&msg, &packet2); + mavlink_msg_param_set_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_value , packet1.param_type ); + mavlink_msg_param_set_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS_RAW_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gps_raw_int_t packet_in = { - 93372036854775807ULL,963497880,963498088,963498296,18275,18379,18483,18587,89,156 + mavlink_gps_raw_int_t packet_in = { + 93372036854775807ULL,963497880,963498088,963498296,18275,18379,18483,18587,89,156 }; - mavlink_gps_raw_int_t packet1, packet2; + mavlink_gps_raw_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.eph = packet_in.eph; - packet1.epv = packet_in.epv; - packet1.vel = packet_in.vel; - packet1.cog = packet_in.cog; - packet1.fix_type = packet_in.fix_type; - packet1.satellites_visible = packet_in.satellites_visible; - - - + packet1.time_usec = packet_in.time_usec; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.eph = packet_in.eph; + packet1.epv = packet_in.epv; + packet1.vel = packet_in.vel; + packet1.cog = packet_in.cog; + packet1.fix_type = packet_in.fix_type; + packet1.satellites_visible = packet_in.satellites_visible; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS_RAW_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_raw_int_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gps_raw_int_decode(&msg, &packet2); + mavlink_msg_gps_raw_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps_raw_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_raw_int_pack(system_id, component_id, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible ); - mavlink_msg_gps_raw_int_decode(&msg, &packet2); + mavlink_msg_gps_raw_int_pack(system_id, component_id, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible ); + mavlink_msg_gps_raw_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_raw_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible ); - mavlink_msg_gps_raw_int_decode(&msg, &packet2); + mavlink_msg_gps_raw_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible ); + mavlink_msg_gps_raw_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gps_status_t packet_in = { - 5,{ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91 },{ 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151 },{ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211 },{ 252, 253, 254, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },{ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75 } + mavlink_gps_status_t packet_in = { + 5,{ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91 },{ 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151 },{ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211 },{ 252, 253, 254, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },{ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75 } }; - mavlink_gps_status_t packet1, packet2; + mavlink_gps_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.satellites_visible = packet_in.satellites_visible; - - mav_array_memcpy(packet1.satellite_prn, packet_in.satellite_prn, sizeof(uint8_t)*20); - mav_array_memcpy(packet1.satellite_used, packet_in.satellite_used, sizeof(uint8_t)*20); - mav_array_memcpy(packet1.satellite_elevation, packet_in.satellite_elevation, sizeof(uint8_t)*20); - mav_array_memcpy(packet1.satellite_azimuth, packet_in.satellite_azimuth, sizeof(uint8_t)*20); - mav_array_memcpy(packet1.satellite_snr, packet_in.satellite_snr, sizeof(uint8_t)*20); - - + packet1.satellites_visible = packet_in.satellites_visible; + + mav_array_memcpy(packet1.satellite_prn, packet_in.satellite_prn, sizeof(uint8_t)*20); + mav_array_memcpy(packet1.satellite_used, packet_in.satellite_used, sizeof(uint8_t)*20); + mav_array_memcpy(packet1.satellite_elevation, packet_in.satellite_elevation, sizeof(uint8_t)*20); + mav_array_memcpy(packet1.satellite_azimuth, packet_in.satellite_azimuth, sizeof(uint8_t)*20); + mav_array_memcpy(packet1.satellite_snr, packet_in.satellite_snr, sizeof(uint8_t)*20); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gps_status_decode(&msg, &packet2); + mavlink_msg_gps_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_status_pack(system_id, component_id, &msg , packet1.satellites_visible , packet1.satellite_prn , packet1.satellite_used , packet1.satellite_elevation , packet1.satellite_azimuth , packet1.satellite_snr ); - mavlink_msg_gps_status_decode(&msg, &packet2); + mavlink_msg_gps_status_pack(system_id, component_id, &msg , packet1.satellites_visible , packet1.satellite_prn , packet1.satellite_used , packet1.satellite_elevation , packet1.satellite_azimuth , packet1.satellite_snr ); + mavlink_msg_gps_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.satellites_visible , packet1.satellite_prn , packet1.satellite_used , packet1.satellite_elevation , packet1.satellite_azimuth , packet1.satellite_snr ); - mavlink_msg_gps_status_decode(&msg, &packet2); + mavlink_msg_gps_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.satellites_visible , packet1.satellite_prn , packet1.satellite_used , packet1.satellite_elevation , packet1.satellite_azimuth , packet1.satellite_snr ); + mavlink_msg_gps_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SCALED_IMU >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_scaled_imu_t packet_in = { - 963497464,17443,17547,17651,17755,17859,17963,18067,18171,18275 + mavlink_scaled_imu_t packet_in = { + 963497464,17443,17547,17651,17755,17859,17963,18067,18171,18275 }; - mavlink_scaled_imu_t packet1, packet2; + mavlink_scaled_imu_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - packet1.xgyro = packet_in.xgyro; - packet1.ygyro = packet_in.ygyro; - packet1.zgyro = packet_in.zgyro; - packet1.xmag = packet_in.xmag; - packet1.ymag = packet_in.ymag; - packet1.zmag = packet_in.zmag; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.xmag = packet_in.xmag; + packet1.ymag = packet_in.ymag; + packet1.zmag = packet_in.zmag; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SCALED_IMU_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_imu_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_scaled_imu_decode(&msg, &packet2); + mavlink_msg_scaled_imu_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_scaled_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_imu_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); - mavlink_msg_scaled_imu_decode(&msg, &packet2); + mavlink_msg_scaled_imu_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_scaled_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_imu_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); - mavlink_msg_scaled_imu_decode(&msg, &packet2); + mavlink_msg_scaled_imu_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_scaled_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RAW_IMU >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_raw_imu_t packet_in = { - 93372036854775807ULL,17651,17755,17859,17963,18067,18171,18275,18379,18483 + mavlink_raw_imu_t packet_in = { + 93372036854775807ULL,17651,17755,17859,17963,18067,18171,18275,18379,18483 }; - mavlink_raw_imu_t packet1, packet2; + mavlink_raw_imu_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - packet1.xgyro = packet_in.xgyro; - packet1.ygyro = packet_in.ygyro; - packet1.zgyro = packet_in.zgyro; - packet1.xmag = packet_in.xmag; - packet1.ymag = packet_in.ymag; - packet1.zmag = packet_in.zmag; - - - + packet1.time_usec = packet_in.time_usec; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.xmag = packet_in.xmag; + packet1.ymag = packet_in.ymag; + packet1.zmag = packet_in.zmag; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RAW_IMU_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RAW_IMU_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_raw_imu_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_raw_imu_decode(&msg, &packet2); + mavlink_msg_raw_imu_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_raw_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_raw_imu_pack(system_id, component_id, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); - mavlink_msg_raw_imu_decode(&msg, &packet2); + mavlink_msg_raw_imu_pack(system_id, component_id, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_raw_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_raw_imu_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); - mavlink_msg_raw_imu_decode(&msg, &packet2); + mavlink_msg_raw_imu_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_raw_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RAW_PRESSURE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_raw_pressure_t packet_in = { - 93372036854775807ULL,17651,17755,17859,17963 + mavlink_raw_pressure_t packet_in = { + 93372036854775807ULL,17651,17755,17859,17963 }; - mavlink_raw_pressure_t packet1, packet2; + mavlink_raw_pressure_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.press_abs = packet_in.press_abs; - packet1.press_diff1 = packet_in.press_diff1; - packet1.press_diff2 = packet_in.press_diff2; - packet1.temperature = packet_in.temperature; + packet1.time_usec = packet_in.time_usec; + packet1.press_abs = packet_in.press_abs; + packet1.press_diff1 = packet_in.press_diff1; + packet1.press_diff2 = packet_in.press_diff2; + packet1.temperature = packet_in.temperature; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RAW_PRESSURE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_raw_pressure_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_raw_pressure_decode(&msg, &packet2); + mavlink_msg_raw_pressure_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_raw_pressure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_raw_pressure_pack(system_id, component_id, &msg , packet1.time_usec , packet1.press_abs , packet1.press_diff1 , packet1.press_diff2 , packet1.temperature ); - mavlink_msg_raw_pressure_decode(&msg, &packet2); + mavlink_msg_raw_pressure_pack(system_id, component_id, &msg , packet1.time_usec , packet1.press_abs , packet1.press_diff1 , packet1.press_diff2 , packet1.temperature ); + mavlink_msg_raw_pressure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_raw_pressure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.press_abs , packet1.press_diff1 , packet1.press_diff2 , packet1.temperature ); - mavlink_msg_raw_pressure_decode(&msg, &packet2); + mavlink_msg_raw_pressure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.press_abs , packet1.press_diff1 , packet1.press_diff2 , packet1.temperature ); + mavlink_msg_raw_pressure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SCALED_PRESSURE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_scaled_pressure_t packet_in = { - 963497464,45.0,73.0,17859 + mavlink_scaled_pressure_t packet_in = { + 963497464,45.0,73.0,17859 }; - mavlink_scaled_pressure_t packet1, packet2; + mavlink_scaled_pressure_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.press_abs = packet_in.press_abs; - packet1.press_diff = packet_in.press_diff; - packet1.temperature = packet_in.temperature; + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.press_abs = packet_in.press_abs; + packet1.press_diff = packet_in.press_diff; + packet1.temperature = packet_in.temperature; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SCALED_PRESSURE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_pressure_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_scaled_pressure_decode(&msg, &packet2); + mavlink_msg_scaled_pressure_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_scaled_pressure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_pressure_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); - mavlink_msg_scaled_pressure_decode(&msg, &packet2); + mavlink_msg_scaled_pressure_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); + mavlink_msg_scaled_pressure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_pressure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); - mavlink_msg_scaled_pressure_decode(&msg, &packet2); + mavlink_msg_scaled_pressure_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); + mavlink_msg_scaled_pressure_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ATTITUDE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_attitude_t packet_in = { - 963497464,45.0,73.0,101.0,129.0,157.0,185.0 + mavlink_attitude_t packet_in = { + 963497464,45.0,73.0,101.0,129.0,157.0,185.0 }; - mavlink_attitude_t packet1, packet2; + mavlink_attitude_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.rollspeed = packet_in.rollspeed; - packet1.pitchspeed = packet_in.pitchspeed; - packet1.yawspeed = packet_in.yawspeed; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.rollspeed = packet_in.rollspeed; + packet1.pitchspeed = packet_in.pitchspeed; + packet1.yawspeed = packet_in.yawspeed; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ATTITUDE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ATTITUDE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_attitude_decode(&msg, &packet2); + mavlink_msg_attitude_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_attitude_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); - mavlink_msg_attitude_decode(&msg, &packet2); + mavlink_msg_attitude_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); + mavlink_msg_attitude_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); - mavlink_msg_attitude_decode(&msg, &packet2); + mavlink_msg_attitude_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); + mavlink_msg_attitude_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ATTITUDE_QUATERNION >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_attitude_quaternion_t packet_in = { - 963497464,45.0,73.0,101.0,129.0,157.0,185.0,213.0 + mavlink_attitude_quaternion_t packet_in = { + 963497464,45.0,73.0,101.0,129.0,157.0,185.0,213.0 }; - mavlink_attitude_quaternion_t packet1, packet2; + mavlink_attitude_quaternion_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.q1 = packet_in.q1; - packet1.q2 = packet_in.q2; - packet1.q3 = packet_in.q3; - packet1.q4 = packet_in.q4; - packet1.rollspeed = packet_in.rollspeed; - packet1.pitchspeed = packet_in.pitchspeed; - packet1.yawspeed = packet_in.yawspeed; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.q1 = packet_in.q1; + packet1.q2 = packet_in.q2; + packet1.q3 = packet_in.q3; + packet1.q4 = packet_in.q4; + packet1.rollspeed = packet_in.rollspeed; + packet1.pitchspeed = packet_in.pitchspeed; + packet1.yawspeed = packet_in.yawspeed; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ATTITUDE_QUATERNION_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_quaternion_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_attitude_quaternion_decode(&msg, &packet2); + mavlink_msg_attitude_quaternion_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_attitude_quaternion_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_quaternion_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); - mavlink_msg_attitude_quaternion_decode(&msg, &packet2); + mavlink_msg_attitude_quaternion_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); + mavlink_msg_attitude_quaternion_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_quaternion_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); - mavlink_msg_attitude_quaternion_decode(&msg, &packet2); + mavlink_msg_attitude_quaternion_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed ); + mavlink_msg_attitude_quaternion_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOCAL_POSITION_NED >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_local_position_ned_t packet_in = { - 963497464,45.0,73.0,101.0,129.0,157.0,185.0 + mavlink_local_position_ned_t packet_in = { + 963497464,45.0,73.0,101.0,129.0,157.0,185.0 }; - mavlink_local_position_ned_t packet1, packet2; + mavlink_local_position_ned_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOCAL_POSITION_NED_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_local_position_ned_decode(&msg, &packet2); + mavlink_msg_local_position_ned_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_local_position_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz ); - mavlink_msg_local_position_ned_decode(&msg, &packet2); + mavlink_msg_local_position_ned_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz ); + mavlink_msg_local_position_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz ); - mavlink_msg_local_position_ned_decode(&msg, &packet2); + mavlink_msg_local_position_ned_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz ); + mavlink_msg_local_position_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GLOBAL_POSITION_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_global_position_int_t packet_in = { - 963497464,963497672,963497880,963498088,963498296,18275,18379,18483,18587 + mavlink_global_position_int_t packet_in = { + 963497464,963497672,963497880,963498088,963498296,18275,18379,18483,18587 }; - mavlink_global_position_int_t packet1, packet2; + mavlink_global_position_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.relative_alt = packet_in.relative_alt; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.hdg = packet_in.hdg; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.relative_alt = packet_in.relative_alt; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.hdg = packet_in.hdg; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GLOBAL_POSITION_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_position_int_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_global_position_int_decode(&msg, &packet2); + mavlink_msg_global_position_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_global_position_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_position_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.hdg ); - mavlink_msg_global_position_int_decode(&msg, &packet2); + mavlink_msg_global_position_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.hdg ); + mavlink_msg_global_position_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_position_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.hdg ); - mavlink_msg_global_position_int_decode(&msg, &packet2); + mavlink_msg_global_position_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.hdg ); + mavlink_msg_global_position_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RC_CHANNELS_SCALED >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_rc_channels_scaled_t packet_in = { - 963497464,17443,17547,17651,17755,17859,17963,18067,18171,65,132 + mavlink_rc_channels_scaled_t packet_in = { + 963497464,17443,17547,17651,17755,17859,17963,18067,18171,65,132 }; - mavlink_rc_channels_scaled_t packet1, packet2; + mavlink_rc_channels_scaled_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.chan1_scaled = packet_in.chan1_scaled; - packet1.chan2_scaled = packet_in.chan2_scaled; - packet1.chan3_scaled = packet_in.chan3_scaled; - packet1.chan4_scaled = packet_in.chan4_scaled; - packet1.chan5_scaled = packet_in.chan5_scaled; - packet1.chan6_scaled = packet_in.chan6_scaled; - packet1.chan7_scaled = packet_in.chan7_scaled; - packet1.chan8_scaled = packet_in.chan8_scaled; - packet1.port = packet_in.port; - packet1.rssi = packet_in.rssi; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.chan1_scaled = packet_in.chan1_scaled; + packet1.chan2_scaled = packet_in.chan2_scaled; + packet1.chan3_scaled = packet_in.chan3_scaled; + packet1.chan4_scaled = packet_in.chan4_scaled; + packet1.chan5_scaled = packet_in.chan5_scaled; + packet1.chan6_scaled = packet_in.chan6_scaled; + packet1.chan7_scaled = packet_in.chan7_scaled; + packet1.chan8_scaled = packet_in.chan8_scaled; + packet1.port = packet_in.port; + packet1.rssi = packet_in.rssi; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RC_CHANNELS_SCALED_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_scaled_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_rc_channels_scaled_decode(&msg, &packet2); + mavlink_msg_rc_channels_scaled_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rc_channels_scaled_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_scaled_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_scaled , packet1.chan2_scaled , packet1.chan3_scaled , packet1.chan4_scaled , packet1.chan5_scaled , packet1.chan6_scaled , packet1.chan7_scaled , packet1.chan8_scaled , packet1.rssi ); - mavlink_msg_rc_channels_scaled_decode(&msg, &packet2); + mavlink_msg_rc_channels_scaled_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_scaled , packet1.chan2_scaled , packet1.chan3_scaled , packet1.chan4_scaled , packet1.chan5_scaled , packet1.chan6_scaled , packet1.chan7_scaled , packet1.chan8_scaled , packet1.rssi ); + mavlink_msg_rc_channels_scaled_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_scaled_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_scaled , packet1.chan2_scaled , packet1.chan3_scaled , packet1.chan4_scaled , packet1.chan5_scaled , packet1.chan6_scaled , packet1.chan7_scaled , packet1.chan8_scaled , packet1.rssi ); - mavlink_msg_rc_channels_scaled_decode(&msg, &packet2); + mavlink_msg_rc_channels_scaled_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_scaled , packet1.chan2_scaled , packet1.chan3_scaled , packet1.chan4_scaled , packet1.chan5_scaled , packet1.chan6_scaled , packet1.chan7_scaled , packet1.chan8_scaled , packet1.rssi ); + mavlink_msg_rc_channels_scaled_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RC_CHANNELS_RAW >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_rc_channels_raw_t packet_in = { - 963497464,17443,17547,17651,17755,17859,17963,18067,18171,65,132 + mavlink_rc_channels_raw_t packet_in = { + 963497464,17443,17547,17651,17755,17859,17963,18067,18171,65,132 }; - mavlink_rc_channels_raw_t packet1, packet2; + mavlink_rc_channels_raw_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.chan1_raw = packet_in.chan1_raw; - packet1.chan2_raw = packet_in.chan2_raw; - packet1.chan3_raw = packet_in.chan3_raw; - packet1.chan4_raw = packet_in.chan4_raw; - packet1.chan5_raw = packet_in.chan5_raw; - packet1.chan6_raw = packet_in.chan6_raw; - packet1.chan7_raw = packet_in.chan7_raw; - packet1.chan8_raw = packet_in.chan8_raw; - packet1.port = packet_in.port; - packet1.rssi = packet_in.rssi; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.chan1_raw = packet_in.chan1_raw; + packet1.chan2_raw = packet_in.chan2_raw; + packet1.chan3_raw = packet_in.chan3_raw; + packet1.chan4_raw = packet_in.chan4_raw; + packet1.chan5_raw = packet_in.chan5_raw; + packet1.chan6_raw = packet_in.chan6_raw; + packet1.chan7_raw = packet_in.chan7_raw; + packet1.chan8_raw = packet_in.chan8_raw; + packet1.port = packet_in.port; + packet1.rssi = packet_in.rssi; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RC_CHANNELS_RAW_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_raw_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_rc_channels_raw_decode(&msg, &packet2); + mavlink_msg_rc_channels_raw_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rc_channels_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_raw_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.rssi ); - mavlink_msg_rc_channels_raw_decode(&msg, &packet2); + mavlink_msg_rc_channels_raw_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.rssi ); + mavlink_msg_rc_channels_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.rssi ); - mavlink_msg_rc_channels_raw_decode(&msg, &packet2); + mavlink_msg_rc_channels_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.port , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.rssi ); + mavlink_msg_rc_channels_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SERVO_OUTPUT_RAW >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_servo_output_raw_t packet_in = { - 963497464,17443,17547,17651,17755,17859,17963,18067,18171,65 + mavlink_servo_output_raw_t packet_in = { + 963497464,17443,17547,17651,17755,17859,17963,18067,18171,65 }; - mavlink_servo_output_raw_t packet1, packet2; + mavlink_servo_output_raw_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.servo1_raw = packet_in.servo1_raw; - packet1.servo2_raw = packet_in.servo2_raw; - packet1.servo3_raw = packet_in.servo3_raw; - packet1.servo4_raw = packet_in.servo4_raw; - packet1.servo5_raw = packet_in.servo5_raw; - packet1.servo6_raw = packet_in.servo6_raw; - packet1.servo7_raw = packet_in.servo7_raw; - packet1.servo8_raw = packet_in.servo8_raw; - packet1.port = packet_in.port; - - - + packet1.time_usec = packet_in.time_usec; + packet1.servo1_raw = packet_in.servo1_raw; + packet1.servo2_raw = packet_in.servo2_raw; + packet1.servo3_raw = packet_in.servo3_raw; + packet1.servo4_raw = packet_in.servo4_raw; + packet1.servo5_raw = packet_in.servo5_raw; + packet1.servo6_raw = packet_in.servo6_raw; + packet1.servo7_raw = packet_in.servo7_raw; + packet1.servo8_raw = packet_in.servo8_raw; + packet1.port = packet_in.port; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SERVO_OUTPUT_RAW_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_servo_output_raw_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_servo_output_raw_decode(&msg, &packet2); + mavlink_msg_servo_output_raw_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_servo_output_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_servo_output_raw_pack(system_id, component_id, &msg , packet1.time_usec , packet1.port , packet1.servo1_raw , packet1.servo2_raw , packet1.servo3_raw , packet1.servo4_raw , packet1.servo5_raw , packet1.servo6_raw , packet1.servo7_raw , packet1.servo8_raw ); - mavlink_msg_servo_output_raw_decode(&msg, &packet2); + mavlink_msg_servo_output_raw_pack(system_id, component_id, &msg , packet1.time_usec , packet1.port , packet1.servo1_raw , packet1.servo2_raw , packet1.servo3_raw , packet1.servo4_raw , packet1.servo5_raw , packet1.servo6_raw , packet1.servo7_raw , packet1.servo8_raw ); + mavlink_msg_servo_output_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_servo_output_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.port , packet1.servo1_raw , packet1.servo2_raw , packet1.servo3_raw , packet1.servo4_raw , packet1.servo5_raw , packet1.servo6_raw , packet1.servo7_raw , packet1.servo8_raw ); - mavlink_msg_servo_output_raw_decode(&msg, &packet2); + mavlink_msg_servo_output_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.port , packet1.servo1_raw , packet1.servo2_raw , packet1.servo3_raw , packet1.servo4_raw , packet1.servo5_raw , packet1.servo6_raw , packet1.servo7_raw , packet1.servo8_raw ); + mavlink_msg_servo_output_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_request_partial_list_t packet_in = { - 17235,17339,17,84 + mavlink_mission_request_partial_list_t packet_in = { + 17235,17339,17,84 }; - mavlink_mission_request_partial_list_t packet1, packet2; + mavlink_mission_request_partial_list_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.start_index = packet_in.start_index; - packet1.end_index = packet_in.end_index; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.start_index = packet_in.start_index; + packet1.end_index = packet_in.end_index; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_REQUEST_PARTIAL_LIST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_partial_list_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_request_partial_list_decode(&msg, &packet2); + mavlink_msg_mission_request_partial_list_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_request_partial_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_partial_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); - mavlink_msg_mission_request_partial_list_decode(&msg, &packet2); + mavlink_msg_mission_request_partial_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); + mavlink_msg_mission_request_partial_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_partial_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); - mavlink_msg_mission_request_partial_list_decode(&msg, &packet2); + mavlink_msg_mission_request_partial_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); + mavlink_msg_mission_request_partial_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_write_partial_list_t packet_in = { - 17235,17339,17,84 + mavlink_mission_write_partial_list_t packet_in = { + 17235,17339,17,84 }; - mavlink_mission_write_partial_list_t packet1, packet2; + mavlink_mission_write_partial_list_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.start_index = packet_in.start_index; - packet1.end_index = packet_in.end_index; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.start_index = packet_in.start_index; + packet1.end_index = packet_in.end_index; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_write_partial_list_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_write_partial_list_decode(&msg, &packet2); + mavlink_msg_mission_write_partial_list_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_write_partial_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_write_partial_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); - mavlink_msg_mission_write_partial_list_decode(&msg, &packet2); + mavlink_msg_mission_write_partial_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); + mavlink_msg_mission_write_partial_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_write_partial_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); - mavlink_msg_mission_write_partial_list_decode(&msg, &packet2); + mavlink_msg_mission_write_partial_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.start_index , packet1.end_index ); + mavlink_msg_mission_write_partial_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_ITEM >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_item_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,185.0,18691,18795,101,168,235,46,113 + mavlink_mission_item_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0,18691,18795,101,168,235,46,113 }; - mavlink_mission_item_t packet1, packet2; + mavlink_mission_item_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param1 = packet_in.param1; - packet1.param2 = packet_in.param2; - packet1.param3 = packet_in.param3; - packet1.param4 = packet_in.param4; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.seq = packet_in.seq; - packet1.command = packet_in.command; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.frame = packet_in.frame; - packet1.current = packet_in.current; - packet1.autocontinue = packet_in.autocontinue; - - - + packet1.param1 = packet_in.param1; + packet1.param2 = packet_in.param2; + packet1.param3 = packet_in.param3; + packet1.param4 = packet_in.param4; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.seq = packet_in.seq; + packet1.command = packet_in.command; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.frame = packet_in.frame; + packet1.current = packet_in.current; + packet1.autocontinue = packet_in.autocontinue; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_ITEM_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_item_decode(&msg, &packet2); + mavlink_msg_mission_item_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_item_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); - mavlink_msg_mission_item_decode(&msg, &packet2); + mavlink_msg_mission_item_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); + mavlink_msg_mission_item_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); - mavlink_msg_mission_item_decode(&msg, &packet2); + mavlink_msg_mission_item_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); + mavlink_msg_mission_item_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_REQUEST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_request_t packet_in = { - 17235,139,206 + mavlink_mission_request_t packet_in = { + 17235,139,206 }; - mavlink_mission_request_t packet1, packet2; + mavlink_mission_request_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.seq = packet_in.seq; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.seq = packet_in.seq; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_REQUEST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_request_decode(&msg, &packet2); + mavlink_msg_mission_request_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq ); - mavlink_msg_mission_request_decode(&msg, &packet2); + mavlink_msg_mission_request_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq ); + mavlink_msg_mission_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq ); - mavlink_msg_mission_request_decode(&msg, &packet2); + mavlink_msg_mission_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq ); + mavlink_msg_mission_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_SET_CURRENT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_set_current_t packet_in = { - 17235,139,206 + mavlink_mission_set_current_t packet_in = { + 17235,139,206 }; - mavlink_mission_set_current_t packet1, packet2; + mavlink_mission_set_current_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.seq = packet_in.seq; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.seq = packet_in.seq; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_SET_CURRENT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_set_current_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_set_current_decode(&msg, &packet2); + mavlink_msg_mission_set_current_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_set_current_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_set_current_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq ); - mavlink_msg_mission_set_current_decode(&msg, &packet2); + mavlink_msg_mission_set_current_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq ); + mavlink_msg_mission_set_current_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_set_current_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq ); - mavlink_msg_mission_set_current_decode(&msg, &packet2); + mavlink_msg_mission_set_current_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq ); + mavlink_msg_mission_set_current_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_CURRENT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_current_t packet_in = { - 17235 + mavlink_mission_current_t packet_in = { + 17235 }; - mavlink_mission_current_t packet1, packet2; + mavlink_mission_current_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.seq = packet_in.seq; + packet1.seq = packet_in.seq; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_CURRENT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_current_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_current_decode(&msg, &packet2); + mavlink_msg_mission_current_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_current_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_current_pack(system_id, component_id, &msg , packet1.seq ); - mavlink_msg_mission_current_decode(&msg, &packet2); + mavlink_msg_mission_current_pack(system_id, component_id, &msg , packet1.seq ); + mavlink_msg_mission_current_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_current_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.seq ); - mavlink_msg_mission_current_decode(&msg, &packet2); + mavlink_msg_mission_current_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.seq ); + mavlink_msg_mission_current_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_REQUEST_LIST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_request_list_t packet_in = { - 5,72 + mavlink_mission_request_list_t packet_in = { + 5,72 }; - mavlink_mission_request_list_t packet1, packet2; + mavlink_mission_request_list_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_REQUEST_LIST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_list_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_request_list_decode(&msg, &packet2); + mavlink_msg_mission_request_list_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_request_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_mission_request_list_decode(&msg, &packet2); + mavlink_msg_mission_request_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_mission_request_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_request_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_mission_request_list_decode(&msg, &packet2); + mavlink_msg_mission_request_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_mission_request_list_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_COUNT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_count_t packet_in = { - 17235,139,206 + mavlink_mission_count_t packet_in = { + 17235,139,206 }; - mavlink_mission_count_t packet1, packet2; + mavlink_mission_count_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.count = packet_in.count; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.count = packet_in.count; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_COUNT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_count_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_count_decode(&msg, &packet2); + mavlink_msg_mission_count_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_count_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_count_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.count ); - mavlink_msg_mission_count_decode(&msg, &packet2); + mavlink_msg_mission_count_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.count ); + mavlink_msg_mission_count_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_count_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.count ); - mavlink_msg_mission_count_decode(&msg, &packet2); + mavlink_msg_mission_count_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.count ); + mavlink_msg_mission_count_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_CLEAR_ALL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_clear_all_t packet_in = { - 5,72 + mavlink_mission_clear_all_t packet_in = { + 5,72 }; - mavlink_mission_clear_all_t packet1, packet2; + mavlink_mission_clear_all_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_CLEAR_ALL_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_clear_all_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_clear_all_decode(&msg, &packet2); + mavlink_msg_mission_clear_all_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_clear_all_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_clear_all_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_mission_clear_all_decode(&msg, &packet2); + mavlink_msg_mission_clear_all_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_mission_clear_all_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_clear_all_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_mission_clear_all_decode(&msg, &packet2); + mavlink_msg_mission_clear_all_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_mission_clear_all_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_ITEM_REACHED >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_item_reached_t packet_in = { - 17235 + mavlink_mission_item_reached_t packet_in = { + 17235 }; - mavlink_mission_item_reached_t packet1, packet2; + mavlink_mission_item_reached_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.seq = packet_in.seq; + packet1.seq = packet_in.seq; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_ITEM_REACHED_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_reached_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_item_reached_decode(&msg, &packet2); + mavlink_msg_mission_item_reached_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_item_reached_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_reached_pack(system_id, component_id, &msg , packet1.seq ); - mavlink_msg_mission_item_reached_decode(&msg, &packet2); + mavlink_msg_mission_item_reached_pack(system_id, component_id, &msg , packet1.seq ); + mavlink_msg_mission_item_reached_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_reached_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.seq ); - mavlink_msg_mission_item_reached_decode(&msg, &packet2); + mavlink_msg_mission_item_reached_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.seq ); + mavlink_msg_mission_item_reached_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_ACK >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_ack_t packet_in = { - 5,72,139 + mavlink_mission_ack_t packet_in = { + 5,72,139 }; - mavlink_mission_ack_t packet1, packet2; + mavlink_mission_ack_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.type = packet_in.type; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.type = packet_in.type; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_ACK_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_ack_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_ack_decode(&msg, &packet2); + mavlink_msg_mission_ack_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_ack_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.type ); - mavlink_msg_mission_ack_decode(&msg, &packet2); + mavlink_msg_mission_ack_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.type ); + mavlink_msg_mission_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_ack_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.type ); - mavlink_msg_mission_ack_decode(&msg, &packet2); + mavlink_msg_mission_ack_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.type ); + mavlink_msg_mission_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_set_gps_global_origin_t packet_in = { - 963497464,963497672,963497880,41 + mavlink_set_gps_global_origin_t packet_in = { + 963497464,963497672,963497880,41 }; - mavlink_set_gps_global_origin_t packet1, packet2; + mavlink_set_gps_global_origin_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.latitude = packet_in.latitude; - packet1.longitude = packet_in.longitude; - packet1.altitude = packet_in.altitude; - packet1.target_system = packet_in.target_system; + packet1.latitude = packet_in.latitude; + packet1.longitude = packet_in.longitude; + packet1.altitude = packet_in.altitude; + packet1.target_system = packet_in.target_system; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_GPS_GLOBAL_ORIGIN_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_gps_global_origin_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_set_gps_global_origin_decode(&msg, &packet2); + mavlink_msg_set_gps_global_origin_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_gps_global_origin_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_gps_global_origin_pack(system_id, component_id, &msg , packet1.target_system , packet1.latitude , packet1.longitude , packet1.altitude ); - mavlink_msg_set_gps_global_origin_decode(&msg, &packet2); + mavlink_msg_set_gps_global_origin_pack(system_id, component_id, &msg , packet1.target_system , packet1.latitude , packet1.longitude , packet1.altitude ); + mavlink_msg_set_gps_global_origin_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_gps_global_origin_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.latitude , packet1.longitude , packet1.altitude ); - mavlink_msg_set_gps_global_origin_decode(&msg, &packet2); + mavlink_msg_set_gps_global_origin_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.latitude , packet1.longitude , packet1.altitude ); + mavlink_msg_set_gps_global_origin_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gps_global_origin_t packet_in = { - 963497464,963497672,963497880 + mavlink_gps_global_origin_t packet_in = { + 963497464,963497672,963497880 }; - mavlink_gps_global_origin_t packet1, packet2; + mavlink_gps_global_origin_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.latitude = packet_in.latitude; - packet1.longitude = packet_in.longitude; - packet1.altitude = packet_in.altitude; + packet1.latitude = packet_in.latitude; + packet1.longitude = packet_in.longitude; + packet1.altitude = packet_in.altitude; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS_GLOBAL_ORIGIN_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_global_origin_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gps_global_origin_decode(&msg, &packet2); + mavlink_msg_gps_global_origin_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps_global_origin_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_global_origin_pack(system_id, component_id, &msg , packet1.latitude , packet1.longitude , packet1.altitude ); - mavlink_msg_gps_global_origin_decode(&msg, &packet2); + mavlink_msg_gps_global_origin_pack(system_id, component_id, &msg , packet1.latitude , packet1.longitude , packet1.altitude ); + mavlink_msg_gps_global_origin_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_global_origin_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.latitude , packet1.longitude , packet1.altitude ); - mavlink_msg_gps_global_origin_decode(&msg, &packet2); + mavlink_msg_gps_global_origin_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.latitude , packet1.longitude , packet1.altitude ); + mavlink_msg_gps_global_origin_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_PARAM_MAP_RC >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_param_map_rc_t packet_in = { - 17.0,45.0,73.0,101.0,18067,187,254,"UVWXYZABCDEFGHI",113 + mavlink_param_map_rc_t packet_in = { + 17.0,45.0,73.0,101.0,18067,187,254,"UVWXYZABCDEFGHI",113 }; - mavlink_param_map_rc_t packet1, packet2; + mavlink_param_map_rc_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param_value0 = packet_in.param_value0; - packet1.scale = packet_in.scale; - packet1.param_value_min = packet_in.param_value_min; - packet1.param_value_max = packet_in.param_value_max; - packet1.param_index = packet_in.param_index; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.parameter_rc_channel_index = packet_in.parameter_rc_channel_index; - - mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); - - + packet1.param_value0 = packet_in.param_value0; + packet1.scale = packet_in.scale; + packet1.param_value_min = packet_in.param_value_min; + packet1.param_value_max = packet_in.param_value_max; + packet1.param_index = packet_in.param_index; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.parameter_rc_channel_index = packet_in.parameter_rc_channel_index; + + mav_array_memcpy(packet1.param_id, packet_in.param_id, sizeof(char)*16); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_PARAM_MAP_RC_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_map_rc_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_param_map_rc_decode(&msg, &packet2); + mavlink_msg_param_map_rc_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_param_map_rc_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_map_rc_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index , packet1.parameter_rc_channel_index , packet1.param_value0 , packet1.scale , packet1.param_value_min , packet1.param_value_max ); - mavlink_msg_param_map_rc_decode(&msg, &packet2); + mavlink_msg_param_map_rc_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index , packet1.parameter_rc_channel_index , packet1.param_value0 , packet1.scale , packet1.param_value_min , packet1.param_value_max ); + mavlink_msg_param_map_rc_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_param_map_rc_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index , packet1.parameter_rc_channel_index , packet1.param_value0 , packet1.scale , packet1.param_value_min , packet1.param_value_max ); - mavlink_msg_param_map_rc_decode(&msg, &packet2); + mavlink_msg_param_map_rc_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.param_id , packet1.param_index , packet1.parameter_rc_channel_index , packet1.param_value0 , packet1.scale , packet1.param_value_min , packet1.param_value_max ); + mavlink_msg_param_map_rc_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_REQUEST_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_safety_set_allowed_area_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,77,144,211 + mavlink_mission_request_int_t packet_in = { + 17235,139,206 }; - mavlink_safety_set_allowed_area_t packet1, packet2; + mavlink_mission_request_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.p1x = packet_in.p1x; - packet1.p1y = packet_in.p1y; - packet1.p1z = packet_in.p1z; - packet1.p2x = packet_in.p2x; - packet1.p2y = packet_in.p2y; - packet1.p2z = packet_in.p2z; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.frame = packet_in.frame; + packet1.seq = packet_in.seq; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_REQUEST_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_safety_set_allowed_area_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_safety_set_allowed_area_decode(&msg, &packet2); + mavlink_msg_mission_request_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_request_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_safety_set_allowed_area_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); - mavlink_msg_safety_set_allowed_area_decode(&msg, &packet2); + mavlink_msg_mission_request_int_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq ); + mavlink_msg_mission_request_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_safety_set_allowed_area_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); - mavlink_msg_safety_set_allowed_area_decode(&msg, &packet2); + mavlink_msg_mission_request_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq ); + mavlink_msg_mission_request_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_safety_allowed_area_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,77 + mavlink_safety_set_allowed_area_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,77,144,211 }; - mavlink_safety_allowed_area_t packet1, packet2; + mavlink_safety_set_allowed_area_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.p1x = packet_in.p1x; - packet1.p1y = packet_in.p1y; - packet1.p1z = packet_in.p1z; - packet1.p2x = packet_in.p2x; - packet1.p2y = packet_in.p2y; - packet1.p2z = packet_in.p2z; - packet1.frame = packet_in.frame; - - - + packet1.p1x = packet_in.p1x; + packet1.p1y = packet_in.p1y; + packet1.p1z = packet_in.p1z; + packet1.p2x = packet_in.p2x; + packet1.p2y = packet_in.p2y; + packet1.p2z = packet_in.p2z; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.frame = packet_in.frame; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SAFETY_SET_ALLOWED_AREA_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_safety_allowed_area_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_safety_allowed_area_decode(&msg, &packet2); + mavlink_msg_safety_set_allowed_area_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_safety_set_allowed_area_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_safety_allowed_area_pack(system_id, component_id, &msg , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); - mavlink_msg_safety_allowed_area_decode(&msg, &packet2); + mavlink_msg_safety_set_allowed_area_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); + mavlink_msg_safety_set_allowed_area_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_safety_allowed_area_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); - mavlink_msg_safety_allowed_area_decode(&msg, &packet2); + mavlink_msg_safety_set_allowed_area_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); + mavlink_msg_safety_set_allowed_area_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_attitude_quaternion_cov_t packet_in = { - 963497464,{ 45.0, 46.0, 47.0, 48.0 },157.0,185.0,213.0,{ 241.0, 242.0, 243.0, 244.0, 245.0, 246.0, 247.0, 248.0, 249.0 } + mavlink_safety_allowed_area_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,77 }; - mavlink_attitude_quaternion_cov_t packet1, packet2; + mavlink_safety_allowed_area_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.rollspeed = packet_in.rollspeed; - packet1.pitchspeed = packet_in.pitchspeed; - packet1.yawspeed = packet_in.yawspeed; - - mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); - mav_array_memcpy(packet1.covariance, packet_in.covariance, sizeof(float)*9); - - + packet1.p1x = packet_in.p1x; + packet1.p1y = packet_in.p1y; + packet1.p1z = packet_in.p1z; + packet1.p2x = packet_in.p2x; + packet1.p2y = packet_in.p2y; + packet1.p2z = packet_in.p2z; + packet1.frame = packet_in.frame; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SAFETY_ALLOWED_AREA_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_quaternion_cov_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_attitude_quaternion_cov_decode(&msg, &packet2); + mavlink_msg_safety_allowed_area_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_safety_allowed_area_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_quaternion_cov_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.q , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.covariance ); - mavlink_msg_attitude_quaternion_cov_decode(&msg, &packet2); + mavlink_msg_safety_allowed_area_pack(system_id, component_id, &msg , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); + mavlink_msg_safety_allowed_area_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_quaternion_cov_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.q , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.covariance ); - mavlink_msg_attitude_quaternion_cov_decode(&msg, &packet2); + mavlink_msg_safety_allowed_area_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.frame , packet1.p1x , packet1.p1y , packet1.p1z , packet1.p2x , packet1.p2y , packet1.p2z ); + mavlink_msg_safety_allowed_area_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_nav_controller_output_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,18275,18379,18483 + mavlink_attitude_quaternion_cov_t packet_in = { + 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0 },185.0,213.0,241.0,{ 269.0, 270.0, 271.0, 272.0, 273.0, 274.0, 275.0, 276.0, 277.0 } }; - mavlink_nav_controller_output_t packet1, packet2; + mavlink_attitude_quaternion_cov_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.nav_roll = packet_in.nav_roll; - packet1.nav_pitch = packet_in.nav_pitch; - packet1.alt_error = packet_in.alt_error; - packet1.aspd_error = packet_in.aspd_error; - packet1.xtrack_error = packet_in.xtrack_error; - packet1.nav_bearing = packet_in.nav_bearing; - packet1.target_bearing = packet_in.target_bearing; - packet1.wp_dist = packet_in.wp_dist; - - - + packet1.time_usec = packet_in.time_usec; + packet1.rollspeed = packet_in.rollspeed; + packet1.pitchspeed = packet_in.pitchspeed; + packet1.yawspeed = packet_in.yawspeed; + + mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); + mav_array_memcpy(packet1.covariance, packet_in.covariance, sizeof(float)*9); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ATTITUDE_QUATERNION_COV_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_nav_controller_output_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_nav_controller_output_decode(&msg, &packet2); + mavlink_msg_attitude_quaternion_cov_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_attitude_quaternion_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_nav_controller_output_pack(system_id, component_id, &msg , packet1.nav_roll , packet1.nav_pitch , packet1.nav_bearing , packet1.target_bearing , packet1.wp_dist , packet1.alt_error , packet1.aspd_error , packet1.xtrack_error ); - mavlink_msg_nav_controller_output_decode(&msg, &packet2); + mavlink_msg_attitude_quaternion_cov_pack(system_id, component_id, &msg , packet1.time_usec , packet1.q , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.covariance ); + mavlink_msg_attitude_quaternion_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_nav_controller_output_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.nav_roll , packet1.nav_pitch , packet1.nav_bearing , packet1.target_bearing , packet1.wp_dist , packet1.alt_error , packet1.aspd_error , packet1.xtrack_error ); - mavlink_msg_nav_controller_output_decode(&msg, &packet2); + mavlink_msg_attitude_quaternion_cov_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.q , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.covariance ); + mavlink_msg_attitude_quaternion_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_global_position_int_cov_t packet_in = { - 93372036854775807ULL,963497880,963498088,963498296,963498504,963498712,213.0,241.0,269.0,{ 297.0, 298.0, 299.0, 300.0, 301.0, 302.0, 303.0, 304.0, 305.0, 306.0, 307.0, 308.0, 309.0, 310.0, 311.0, 312.0, 313.0, 314.0, 315.0, 316.0, 317.0, 318.0, 319.0, 320.0, 321.0, 322.0, 323.0, 324.0, 325.0, 326.0, 327.0, 328.0, 329.0, 330.0, 331.0, 332.0 },45 + mavlink_nav_controller_output_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,18275,18379,18483 }; - mavlink_global_position_int_cov_t packet1, packet2; + mavlink_nav_controller_output_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_utc = packet_in.time_utc; - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.relative_alt = packet_in.relative_alt; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.estimator_type = packet_in.estimator_type; - - mav_array_memcpy(packet1.covariance, packet_in.covariance, sizeof(float)*36); + packet1.nav_roll = packet_in.nav_roll; + packet1.nav_pitch = packet_in.nav_pitch; + packet1.alt_error = packet_in.alt_error; + packet1.aspd_error = packet_in.aspd_error; + packet1.xtrack_error = packet_in.xtrack_error; + packet1.nav_bearing = packet_in.nav_bearing; + packet1.target_bearing = packet_in.target_bearing; + packet1.wp_dist = packet_in.wp_dist; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_NAV_CONTROLLER_OUTPUT_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_nav_controller_output_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_nav_controller_output_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_nav_controller_output_pack(system_id, component_id, &msg , packet1.nav_roll , packet1.nav_pitch , packet1.nav_bearing , packet1.target_bearing , packet1.wp_dist , packet1.alt_error , packet1.aspd_error , packet1.xtrack_error ); + mavlink_msg_nav_controller_output_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_nav_controller_output_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.nav_roll , packet1.nav_pitch , packet1.nav_bearing , packet1.target_bearing , packet1.wp_dist , packet1.alt_error , packet1.aspd_error , packet1.xtrack_error ); + mavlink_msg_nav_controller_output_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_global_position_int_cov_t packet_in = { + 93372036854775807ULL,963497880,963498088,963498296,963498504,185.0,213.0,241.0,{ 269.0, 270.0, 271.0, 272.0, 273.0, 274.0, 275.0, 276.0, 277.0, 278.0, 279.0, 280.0, 281.0, 282.0, 283.0, 284.0, 285.0, 286.0, 287.0, 288.0, 289.0, 290.0, 291.0, 292.0, 293.0, 294.0, 295.0, 296.0, 297.0, 298.0, 299.0, 300.0, 301.0, 302.0, 303.0, 304.0 },33 + }; + mavlink_global_position_int_cov_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_usec = packet_in.time_usec; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.relative_alt = packet_in.relative_alt; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.estimator_type = packet_in.estimator_type; + + mav_array_memcpy(packet1.covariance, packet_in.covariance, sizeof(float)*36); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GLOBAL_POSITION_INT_COV_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_position_int_cov_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_global_position_int_cov_decode(&msg, &packet2); + mavlink_msg_global_position_int_cov_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_global_position_int_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_position_int_cov_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.time_utc , packet1.estimator_type , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.covariance ); - mavlink_msg_global_position_int_cov_decode(&msg, &packet2); + mavlink_msg_global_position_int_cov_pack(system_id, component_id, &msg , packet1.time_usec , packet1.estimator_type , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.covariance ); + mavlink_msg_global_position_int_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_position_int_cov_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.time_utc , packet1.estimator_type , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.covariance ); - mavlink_msg_global_position_int_cov_decode(&msg, &packet2); + mavlink_msg_global_position_int_cov_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.estimator_type , packet1.lat , packet1.lon , packet1.alt , packet1.relative_alt , packet1.vx , packet1.vy , packet1.vz , packet1.covariance ); + mavlink_msg_global_position_int_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_local_position_ned_cov_t packet_in = { - 93372036854775807ULL,963497880,101.0,129.0,157.0,185.0,213.0,241.0,{ 269.0, 270.0, 271.0, 272.0, 273.0, 274.0, 275.0, 276.0, 277.0, 278.0, 279.0, 280.0, 281.0, 282.0, 283.0, 284.0, 285.0, 286.0, 287.0, 288.0, 289.0, 290.0, 291.0, 292.0, 293.0, 294.0, 295.0, 296.0, 297.0, 298.0, 299.0, 300.0, 301.0, 302.0, 303.0, 304.0 },33 + mavlink_local_position_ned_cov_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,{ 325.0, 326.0, 327.0, 328.0, 329.0, 330.0, 331.0, 332.0, 333.0, 334.0, 335.0, 336.0, 337.0, 338.0, 339.0, 340.0, 341.0, 342.0, 343.0, 344.0, 345.0, 346.0, 347.0, 348.0, 349.0, 350.0, 351.0, 352.0, 353.0, 354.0, 355.0, 356.0, 357.0, 358.0, 359.0, 360.0, 361.0, 362.0, 363.0, 364.0, 365.0, 366.0, 367.0, 368.0, 369.0 },165 }; - mavlink_local_position_ned_cov_t packet1, packet2; + mavlink_local_position_ned_cov_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_utc = packet_in.time_utc; - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.estimator_type = packet_in.estimator_type; - - mav_array_memcpy(packet1.covariance, packet_in.covariance, sizeof(float)*36); - - + packet1.time_usec = packet_in.time_usec; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.ax = packet_in.ax; + packet1.ay = packet_in.ay; + packet1.az = packet_in.az; + packet1.estimator_type = packet_in.estimator_type; + + mav_array_memcpy(packet1.covariance, packet_in.covariance, sizeof(float)*45); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOCAL_POSITION_NED_COV_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_cov_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_local_position_ned_cov_decode(&msg, &packet2); + mavlink_msg_local_position_ned_cov_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_local_position_ned_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_cov_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.time_utc , packet1.estimator_type , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.covariance ); - mavlink_msg_local_position_ned_cov_decode(&msg, &packet2); + mavlink_msg_local_position_ned_cov_pack(system_id, component_id, &msg , packet1.time_usec , packet1.estimator_type , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.ax , packet1.ay , packet1.az , packet1.covariance ); + mavlink_msg_local_position_ned_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_cov_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.time_utc , packet1.estimator_type , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.covariance ); - mavlink_msg_local_position_ned_cov_decode(&msg, &packet2); + mavlink_msg_local_position_ned_cov_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.estimator_type , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.ax , packet1.ay , packet1.az , packet1.covariance ); + mavlink_msg_local_position_ned_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RC_CHANNELS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_rc_channels_t packet_in = { - 963497464,17443,17547,17651,17755,17859,17963,18067,18171,18275,18379,18483,18587,18691,18795,18899,19003,19107,19211,125,192 + mavlink_rc_channels_t packet_in = { + 963497464,17443,17547,17651,17755,17859,17963,18067,18171,18275,18379,18483,18587,18691,18795,18899,19003,19107,19211,125,192 }; - mavlink_rc_channels_t packet1, packet2; + mavlink_rc_channels_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.chan1_raw = packet_in.chan1_raw; - packet1.chan2_raw = packet_in.chan2_raw; - packet1.chan3_raw = packet_in.chan3_raw; - packet1.chan4_raw = packet_in.chan4_raw; - packet1.chan5_raw = packet_in.chan5_raw; - packet1.chan6_raw = packet_in.chan6_raw; - packet1.chan7_raw = packet_in.chan7_raw; - packet1.chan8_raw = packet_in.chan8_raw; - packet1.chan9_raw = packet_in.chan9_raw; - packet1.chan10_raw = packet_in.chan10_raw; - packet1.chan11_raw = packet_in.chan11_raw; - packet1.chan12_raw = packet_in.chan12_raw; - packet1.chan13_raw = packet_in.chan13_raw; - packet1.chan14_raw = packet_in.chan14_raw; - packet1.chan15_raw = packet_in.chan15_raw; - packet1.chan16_raw = packet_in.chan16_raw; - packet1.chan17_raw = packet_in.chan17_raw; - packet1.chan18_raw = packet_in.chan18_raw; - packet1.chancount = packet_in.chancount; - packet1.rssi = packet_in.rssi; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.chan1_raw = packet_in.chan1_raw; + packet1.chan2_raw = packet_in.chan2_raw; + packet1.chan3_raw = packet_in.chan3_raw; + packet1.chan4_raw = packet_in.chan4_raw; + packet1.chan5_raw = packet_in.chan5_raw; + packet1.chan6_raw = packet_in.chan6_raw; + packet1.chan7_raw = packet_in.chan7_raw; + packet1.chan8_raw = packet_in.chan8_raw; + packet1.chan9_raw = packet_in.chan9_raw; + packet1.chan10_raw = packet_in.chan10_raw; + packet1.chan11_raw = packet_in.chan11_raw; + packet1.chan12_raw = packet_in.chan12_raw; + packet1.chan13_raw = packet_in.chan13_raw; + packet1.chan14_raw = packet_in.chan14_raw; + packet1.chan15_raw = packet_in.chan15_raw; + packet1.chan16_raw = packet_in.chan16_raw; + packet1.chan17_raw = packet_in.chan17_raw; + packet1.chan18_raw = packet_in.chan18_raw; + packet1.chancount = packet_in.chancount; + packet1.rssi = packet_in.rssi; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RC_CHANNELS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_rc_channels_decode(&msg, &packet2); + mavlink_msg_rc_channels_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rc_channels_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.chancount , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.chan13_raw , packet1.chan14_raw , packet1.chan15_raw , packet1.chan16_raw , packet1.chan17_raw , packet1.chan18_raw , packet1.rssi ); - mavlink_msg_rc_channels_decode(&msg, &packet2); + mavlink_msg_rc_channels_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.chancount , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.chan13_raw , packet1.chan14_raw , packet1.chan15_raw , packet1.chan16_raw , packet1.chan17_raw , packet1.chan18_raw , packet1.rssi ); + mavlink_msg_rc_channels_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.chancount , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.chan13_raw , packet1.chan14_raw , packet1.chan15_raw , packet1.chan16_raw , packet1.chan17_raw , packet1.chan18_raw , packet1.rssi ); - mavlink_msg_rc_channels_decode(&msg, &packet2); + mavlink_msg_rc_channels_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.chancount , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.chan13_raw , packet1.chan14_raw , packet1.chan15_raw , packet1.chan16_raw , packet1.chan17_raw , packet1.chan18_raw , packet1.rssi ); + mavlink_msg_rc_channels_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_REQUEST_DATA_STREAM >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_request_data_stream_t packet_in = { - 17235,139,206,17,84 + mavlink_request_data_stream_t packet_in = { + 17235,139,206,17,84 }; - mavlink_request_data_stream_t packet1, packet2; + mavlink_request_data_stream_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.req_message_rate = packet_in.req_message_rate; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.req_stream_id = packet_in.req_stream_id; - packet1.start_stop = packet_in.start_stop; + packet1.req_message_rate = packet_in.req_message_rate; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.req_stream_id = packet_in.req_stream_id; + packet1.start_stop = packet_in.start_stop; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_REQUEST_DATA_STREAM_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_request_data_stream_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_request_data_stream_decode(&msg, &packet2); + mavlink_msg_request_data_stream_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_request_data_stream_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_request_data_stream_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.req_stream_id , packet1.req_message_rate , packet1.start_stop ); - mavlink_msg_request_data_stream_decode(&msg, &packet2); + mavlink_msg_request_data_stream_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.req_stream_id , packet1.req_message_rate , packet1.start_stop ); + mavlink_msg_request_data_stream_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_request_data_stream_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.req_stream_id , packet1.req_message_rate , packet1.start_stop ); - mavlink_msg_request_data_stream_decode(&msg, &packet2); + mavlink_msg_request_data_stream_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.req_stream_id , packet1.req_message_rate , packet1.start_stop ); + mavlink_msg_request_data_stream_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DATA_STREAM >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_data_stream_t packet_in = { - 17235,139,206 + mavlink_data_stream_t packet_in = { + 17235,139,206 }; - mavlink_data_stream_t packet1, packet2; + mavlink_data_stream_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.message_rate = packet_in.message_rate; - packet1.stream_id = packet_in.stream_id; - packet1.on_off = packet_in.on_off; + packet1.message_rate = packet_in.message_rate; + packet1.stream_id = packet_in.stream_id; + packet1.on_off = packet_in.on_off; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DATA_STREAM_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data_stream_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_data_stream_decode(&msg, &packet2); + mavlink_msg_data_stream_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_data_stream_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data_stream_pack(system_id, component_id, &msg , packet1.stream_id , packet1.message_rate , packet1.on_off ); - mavlink_msg_data_stream_decode(&msg, &packet2); + mavlink_msg_data_stream_pack(system_id, component_id, &msg , packet1.stream_id , packet1.message_rate , packet1.on_off ); + mavlink_msg_data_stream_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data_stream_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.stream_id , packet1.message_rate , packet1.on_off ); - mavlink_msg_data_stream_decode(&msg, &packet2); + mavlink_msg_data_stream_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.stream_id , packet1.message_rate , packet1.on_off ); + mavlink_msg_data_stream_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MANUAL_CONTROL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_manual_control_t packet_in = { - 17235,17339,17443,17547,17651,163 + mavlink_manual_control_t packet_in = { + 17235,17339,17443,17547,17651,163 }; - mavlink_manual_control_t packet1, packet2; + mavlink_manual_control_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.r = packet_in.r; - packet1.buttons = packet_in.buttons; - packet1.target = packet_in.target; - - - + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.r = packet_in.r; + packet1.buttons = packet_in.buttons; + packet1.target = packet_in.target; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MANUAL_CONTROL_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_manual_control_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_manual_control_decode(&msg, &packet2); + mavlink_msg_manual_control_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_manual_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_manual_control_pack(system_id, component_id, &msg , packet1.target , packet1.x , packet1.y , packet1.z , packet1.r , packet1.buttons ); - mavlink_msg_manual_control_decode(&msg, &packet2); + mavlink_msg_manual_control_pack(system_id, component_id, &msg , packet1.target , packet1.x , packet1.y , packet1.z , packet1.r , packet1.buttons ); + mavlink_msg_manual_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_manual_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target , packet1.x , packet1.y , packet1.z , packet1.r , packet1.buttons ); - mavlink_msg_manual_control_decode(&msg, &packet2); + mavlink_msg_manual_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target , packet1.x , packet1.y , packet1.z , packet1.r , packet1.buttons ); + mavlink_msg_manual_control_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_rc_channels_override_t packet_in = { - 17235,17339,17443,17547,17651,17755,17859,17963,53,120 + mavlink_rc_channels_override_t packet_in = { + 17235,17339,17443,17547,17651,17755,17859,17963,53,120 }; - mavlink_rc_channels_override_t packet1, packet2; + mavlink_rc_channels_override_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.chan1_raw = packet_in.chan1_raw; - packet1.chan2_raw = packet_in.chan2_raw; - packet1.chan3_raw = packet_in.chan3_raw; - packet1.chan4_raw = packet_in.chan4_raw; - packet1.chan5_raw = packet_in.chan5_raw; - packet1.chan6_raw = packet_in.chan6_raw; - packet1.chan7_raw = packet_in.chan7_raw; - packet1.chan8_raw = packet_in.chan8_raw; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - - - + packet1.chan1_raw = packet_in.chan1_raw; + packet1.chan2_raw = packet_in.chan2_raw; + packet1.chan3_raw = packet_in.chan3_raw; + packet1.chan4_raw = packet_in.chan4_raw; + packet1.chan5_raw = packet_in.chan5_raw; + packet1.chan6_raw = packet_in.chan6_raw; + packet1.chan7_raw = packet_in.chan7_raw; + packet1.chan8_raw = packet_in.chan8_raw; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_override_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_rc_channels_override_decode(&msg, &packet2); + mavlink_msg_rc_channels_override_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_rc_channels_override_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_override_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw ); - mavlink_msg_rc_channels_override_decode(&msg, &packet2); + mavlink_msg_rc_channels_override_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw ); + mavlink_msg_rc_channels_override_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_rc_channels_override_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw ); - mavlink_msg_rc_channels_override_decode(&msg, &packet2); + mavlink_msg_rc_channels_override_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw ); + mavlink_msg_rc_channels_override_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MISSION_ITEM_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_mission_item_int_t packet_in = { - 17.0,45.0,73.0,101.0,963498296,963498504,185.0,18691,18795,101,168,235,46,113 + mavlink_mission_item_int_t packet_in = { + 17.0,45.0,73.0,101.0,963498296,963498504,185.0,18691,18795,101,168,235,46,113 }; - mavlink_mission_item_int_t packet1, packet2; + mavlink_mission_item_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param1 = packet_in.param1; - packet1.param2 = packet_in.param2; - packet1.param3 = packet_in.param3; - packet1.param4 = packet_in.param4; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.seq = packet_in.seq; - packet1.command = packet_in.command; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.frame = packet_in.frame; - packet1.current = packet_in.current; - packet1.autocontinue = packet_in.autocontinue; - - - + packet1.param1 = packet_in.param1; + packet1.param2 = packet_in.param2; + packet1.param3 = packet_in.param3; + packet1.param4 = packet_in.param4; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.seq = packet_in.seq; + packet1.command = packet_in.command; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.frame = packet_in.frame; + packet1.current = packet_in.current; + packet1.autocontinue = packet_in.autocontinue; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MISSION_ITEM_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_int_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_mission_item_int_decode(&msg, &packet2); + mavlink_msg_mission_item_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_mission_item_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_int_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); - mavlink_msg_mission_item_int_decode(&msg, &packet2); + mavlink_msg_mission_item_int_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); + mavlink_msg_mission_item_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_mission_item_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); - mavlink_msg_mission_item_int_decode(&msg, &packet2); + mavlink_msg_mission_item_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.seq , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); + mavlink_msg_mission_item_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_VFR_HUD >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_vfr_hud_t packet_in = { - 17.0,45.0,73.0,101.0,18067,18171 + mavlink_vfr_hud_t packet_in = { + 17.0,45.0,73.0,101.0,18067,18171 }; - mavlink_vfr_hud_t packet1, packet2; + mavlink_vfr_hud_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.airspeed = packet_in.airspeed; - packet1.groundspeed = packet_in.groundspeed; - packet1.alt = packet_in.alt; - packet1.climb = packet_in.climb; - packet1.heading = packet_in.heading; - packet1.throttle = packet_in.throttle; - - - + packet1.airspeed = packet_in.airspeed; + packet1.groundspeed = packet_in.groundspeed; + packet1.alt = packet_in.alt; + packet1.climb = packet_in.climb; + packet1.heading = packet_in.heading; + packet1.throttle = packet_in.throttle; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_VFR_HUD_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_VFR_HUD_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vfr_hud_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_vfr_hud_decode(&msg, &packet2); + mavlink_msg_vfr_hud_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_vfr_hud_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vfr_hud_pack(system_id, component_id, &msg , packet1.airspeed , packet1.groundspeed , packet1.heading , packet1.throttle , packet1.alt , packet1.climb ); - mavlink_msg_vfr_hud_decode(&msg, &packet2); + mavlink_msg_vfr_hud_pack(system_id, component_id, &msg , packet1.airspeed , packet1.groundspeed , packet1.heading , packet1.throttle , packet1.alt , packet1.climb ); + mavlink_msg_vfr_hud_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vfr_hud_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.airspeed , packet1.groundspeed , packet1.heading , packet1.throttle , packet1.alt , packet1.climb ); - mavlink_msg_vfr_hud_decode(&msg, &packet2); + mavlink_msg_vfr_hud_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.airspeed , packet1.groundspeed , packet1.heading , packet1.throttle , packet1.alt , packet1.climb ); + mavlink_msg_vfr_hud_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_COMMAND_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_command_int_t packet_in = { - 17.0,45.0,73.0,101.0,963498296,963498504,185.0,18691,223,34,101,168,235 + mavlink_command_int_t packet_in = { + 17.0,45.0,73.0,101.0,963498296,963498504,185.0,18691,223,34,101,168,235 }; - mavlink_command_int_t packet1, packet2; + mavlink_command_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param1 = packet_in.param1; - packet1.param2 = packet_in.param2; - packet1.param3 = packet_in.param3; - packet1.param4 = packet_in.param4; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.command = packet_in.command; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.frame = packet_in.frame; - packet1.current = packet_in.current; - packet1.autocontinue = packet_in.autocontinue; - - - + packet1.param1 = packet_in.param1; + packet1.param2 = packet_in.param2; + packet1.param3 = packet_in.param3; + packet1.param4 = packet_in.param4; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.command = packet_in.command; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.frame = packet_in.frame; + packet1.current = packet_in.current; + packet1.autocontinue = packet_in.autocontinue; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_COMMAND_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_int_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_command_int_decode(&msg, &packet2); + mavlink_msg_command_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_command_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_int_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); - mavlink_msg_command_int_decode(&msg, &packet2); + mavlink_msg_command_int_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); + mavlink_msg_command_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); - mavlink_msg_command_int_decode(&msg, &packet2); + mavlink_msg_command_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.frame , packet1.command , packet1.current , packet1.autocontinue , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.x , packet1.y , packet1.z ); + mavlink_msg_command_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_COMMAND_LONG >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_command_long_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,185.0,18691,223,34,101 + mavlink_command_long_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0,18691,223,34,101 }; - mavlink_command_long_t packet1, packet2; + mavlink_command_long_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.param1 = packet_in.param1; - packet1.param2 = packet_in.param2; - packet1.param3 = packet_in.param3; - packet1.param4 = packet_in.param4; - packet1.param5 = packet_in.param5; - packet1.param6 = packet_in.param6; - packet1.param7 = packet_in.param7; - packet1.command = packet_in.command; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.confirmation = packet_in.confirmation; - - - + packet1.param1 = packet_in.param1; + packet1.param2 = packet_in.param2; + packet1.param3 = packet_in.param3; + packet1.param4 = packet_in.param4; + packet1.param5 = packet_in.param5; + packet1.param6 = packet_in.param6; + packet1.param7 = packet_in.param7; + packet1.command = packet_in.command; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.confirmation = packet_in.confirmation; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_COMMAND_LONG_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_long_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_command_long_decode(&msg, &packet2); + mavlink_msg_command_long_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_command_long_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_long_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.command , packet1.confirmation , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.param5 , packet1.param6 , packet1.param7 ); - mavlink_msg_command_long_decode(&msg, &packet2); + mavlink_msg_command_long_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.command , packet1.confirmation , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.param5 , packet1.param6 , packet1.param7 ); + mavlink_msg_command_long_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_long_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.command , packet1.confirmation , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.param5 , packet1.param6 , packet1.param7 ); - mavlink_msg_command_long_decode(&msg, &packet2); + mavlink_msg_command_long_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.command , packet1.confirmation , packet1.param1 , packet1.param2 , packet1.param3 , packet1.param4 , packet1.param5 , packet1.param6 , packet1.param7 ); + mavlink_msg_command_long_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_COMMAND_ACK >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_command_ack_t packet_in = { - 17235,139 + mavlink_command_ack_t packet_in = { + 17235,139 }; - mavlink_command_ack_t packet1, packet2; + mavlink_command_ack_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.command = packet_in.command; - packet1.result = packet_in.result; + packet1.command = packet_in.command; + packet1.result = packet_in.result; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_COMMAND_ACK_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_ack_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_command_ack_decode(&msg, &packet2); + mavlink_msg_command_ack_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_command_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_ack_pack(system_id, component_id, &msg , packet1.command , packet1.result ); - mavlink_msg_command_ack_decode(&msg, &packet2); + mavlink_msg_command_ack_pack(system_id, component_id, &msg , packet1.command , packet1.result ); + mavlink_msg_command_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_command_ack_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.command , packet1.result ); - mavlink_msg_command_ack_decode(&msg, &packet2); + mavlink_msg_command_ack_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.command , packet1.result ); + mavlink_msg_command_ack_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MANUAL_SETPOINT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_manual_setpoint_t packet_in = { - 963497464,45.0,73.0,101.0,129.0,65,132 + mavlink_manual_setpoint_t packet_in = { + 963497464,45.0,73.0,101.0,129.0,65,132 }; - mavlink_manual_setpoint_t packet1, packet2; + mavlink_manual_setpoint_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.thrust = packet_in.thrust; - packet1.mode_switch = packet_in.mode_switch; - packet1.manual_override_switch = packet_in.manual_override_switch; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.thrust = packet_in.thrust; + packet1.mode_switch = packet_in.mode_switch; + packet1.manual_override_switch = packet_in.manual_override_switch; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MANUAL_SETPOINT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_manual_setpoint_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_manual_setpoint_decode(&msg, &packet2); + mavlink_msg_manual_setpoint_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_manual_setpoint_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_manual_setpoint_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.thrust , packet1.mode_switch , packet1.manual_override_switch ); - mavlink_msg_manual_setpoint_decode(&msg, &packet2); + mavlink_msg_manual_setpoint_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.thrust , packet1.mode_switch , packet1.manual_override_switch ); + mavlink_msg_manual_setpoint_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_manual_setpoint_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.thrust , packet1.mode_switch , packet1.manual_override_switch ); - mavlink_msg_manual_setpoint_decode(&msg, &packet2); + mavlink_msg_manual_setpoint_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.roll , packet1.pitch , packet1.yaw , packet1.thrust , packet1.mode_switch , packet1.manual_override_switch ); + mavlink_msg_manual_setpoint_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_ATTITUDE_TARGET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_set_attitude_target_t packet_in = { - 963497464,{ 45.0, 46.0, 47.0, 48.0 },157.0,185.0,213.0,241.0,113,180,247 + mavlink_set_attitude_target_t packet_in = { + 963497464,{ 45.0, 46.0, 47.0, 48.0 },157.0,185.0,213.0,241.0,113,180,247 }; - mavlink_set_attitude_target_t packet1, packet2; + mavlink_set_attitude_target_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.body_roll_rate = packet_in.body_roll_rate; - packet1.body_pitch_rate = packet_in.body_pitch_rate; - packet1.body_yaw_rate = packet_in.body_yaw_rate; - packet1.thrust = packet_in.thrust; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.type_mask = packet_in.type_mask; - - mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.body_roll_rate = packet_in.body_roll_rate; + packet1.body_pitch_rate = packet_in.body_pitch_rate; + packet1.body_yaw_rate = packet_in.body_yaw_rate; + packet1.thrust = packet_in.thrust; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.type_mask = packet_in.type_mask; + + mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_ATTITUDE_TARGET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_attitude_target_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_set_attitude_target_decode(&msg, &packet2); + mavlink_msg_set_attitude_target_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_attitude_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_attitude_target_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); - mavlink_msg_set_attitude_target_decode(&msg, &packet2); + mavlink_msg_set_attitude_target_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); + mavlink_msg_set_attitude_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_attitude_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); - mavlink_msg_set_attitude_target_decode(&msg, &packet2); + mavlink_msg_set_attitude_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); + mavlink_msg_set_attitude_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ATTITUDE_TARGET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_attitude_target_t packet_in = { - 963497464,{ 45.0, 46.0, 47.0, 48.0 },157.0,185.0,213.0,241.0,113 + mavlink_attitude_target_t packet_in = { + 963497464,{ 45.0, 46.0, 47.0, 48.0 },157.0,185.0,213.0,241.0,113 }; - mavlink_attitude_target_t packet1, packet2; + mavlink_attitude_target_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.body_roll_rate = packet_in.body_roll_rate; - packet1.body_pitch_rate = packet_in.body_pitch_rate; - packet1.body_yaw_rate = packet_in.body_yaw_rate; - packet1.thrust = packet_in.thrust; - packet1.type_mask = packet_in.type_mask; - - mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.body_roll_rate = packet_in.body_roll_rate; + packet1.body_pitch_rate = packet_in.body_pitch_rate; + packet1.body_yaw_rate = packet_in.body_yaw_rate; + packet1.thrust = packet_in.thrust; + packet1.type_mask = packet_in.type_mask; + + mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ATTITUDE_TARGET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_target_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_attitude_target_decode(&msg, &packet2); + mavlink_msg_attitude_target_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_attitude_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_target_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); - mavlink_msg_attitude_target_decode(&msg, &packet2); + mavlink_msg_attitude_target_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); + mavlink_msg_attitude_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_attitude_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); - mavlink_msg_attitude_target_decode(&msg, &packet2); + mavlink_msg_attitude_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.type_mask , packet1.q , packet1.body_roll_rate , packet1.body_pitch_rate , packet1.body_yaw_rate , packet1.thrust ); + mavlink_msg_attitude_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_set_position_target_local_ned_t packet_in = { - 963497464,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27,94,161 + mavlink_set_position_target_local_ned_t packet_in = { + 963497464,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27,94,161 }; - mavlink_set_position_target_local_ned_t packet1, packet2; + mavlink_set_position_target_local_ned_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.afx = packet_in.afx; - packet1.afy = packet_in.afy; - packet1.afz = packet_in.afz; - packet1.yaw = packet_in.yaw; - packet1.yaw_rate = packet_in.yaw_rate; - packet1.type_mask = packet_in.type_mask; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.coordinate_frame = packet_in.coordinate_frame; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.afx = packet_in.afx; + packet1.afy = packet_in.afy; + packet1.afz = packet_in.afz; + packet1.yaw = packet_in.yaw; + packet1.yaw_rate = packet_in.yaw_rate; + packet1.type_mask = packet_in.type_mask; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.coordinate_frame = packet_in.coordinate_frame; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_POSITION_TARGET_LOCAL_NED_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_position_target_local_ned_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_set_position_target_local_ned_decode(&msg, &packet2); + mavlink_msg_set_position_target_local_ned_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_position_target_local_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_position_target_local_ned_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_set_position_target_local_ned_decode(&msg, &packet2); + mavlink_msg_set_position_target_local_ned_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_set_position_target_local_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_position_target_local_ned_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_set_position_target_local_ned_decode(&msg, &packet2); + mavlink_msg_set_position_target_local_ned_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_set_position_target_local_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_position_target_local_ned_t packet_in = { - 963497464,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27 + mavlink_position_target_local_ned_t packet_in = { + 963497464,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27 }; - mavlink_position_target_local_ned_t packet1, packet2; + mavlink_position_target_local_ned_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.afx = packet_in.afx; - packet1.afy = packet_in.afy; - packet1.afz = packet_in.afz; - packet1.yaw = packet_in.yaw; - packet1.yaw_rate = packet_in.yaw_rate; - packet1.type_mask = packet_in.type_mask; - packet1.coordinate_frame = packet_in.coordinate_frame; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.afx = packet_in.afx; + packet1.afy = packet_in.afy; + packet1.afz = packet_in.afz; + packet1.yaw = packet_in.yaw; + packet1.yaw_rate = packet_in.yaw_rate; + packet1.type_mask = packet_in.type_mask; + packet1.coordinate_frame = packet_in.coordinate_frame; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_POSITION_TARGET_LOCAL_NED_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_position_target_local_ned_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_position_target_local_ned_decode(&msg, &packet2); + mavlink_msg_position_target_local_ned_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_position_target_local_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_position_target_local_ned_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_position_target_local_ned_decode(&msg, &packet2); + mavlink_msg_position_target_local_ned_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_position_target_local_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_position_target_local_ned_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_position_target_local_ned_decode(&msg, &packet2); + mavlink_msg_position_target_local_ned_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.x , packet1.y , packet1.z , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_position_target_local_ned_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_set_position_target_global_int_t packet_in = { - 963497464,963497672,963497880,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27,94,161 + mavlink_set_position_target_global_int_t packet_in = { + 963497464,963497672,963497880,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27,94,161 }; - mavlink_set_position_target_global_int_t packet1, packet2; + mavlink_set_position_target_global_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.lat_int = packet_in.lat_int; - packet1.lon_int = packet_in.lon_int; - packet1.alt = packet_in.alt; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.afx = packet_in.afx; - packet1.afy = packet_in.afy; - packet1.afz = packet_in.afz; - packet1.yaw = packet_in.yaw; - packet1.yaw_rate = packet_in.yaw_rate; - packet1.type_mask = packet_in.type_mask; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.coordinate_frame = packet_in.coordinate_frame; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.lat_int = packet_in.lat_int; + packet1.lon_int = packet_in.lon_int; + packet1.alt = packet_in.alt; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.afx = packet_in.afx; + packet1.afy = packet_in.afy; + packet1.afz = packet_in.afz; + packet1.yaw = packet_in.yaw; + packet1.yaw_rate = packet_in.yaw_rate; + packet1.type_mask = packet_in.type_mask; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.coordinate_frame = packet_in.coordinate_frame; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_POSITION_TARGET_GLOBAL_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_position_target_global_int_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_set_position_target_global_int_decode(&msg, &packet2); + mavlink_msg_set_position_target_global_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_position_target_global_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_position_target_global_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_set_position_target_global_int_decode(&msg, &packet2); + mavlink_msg_set_position_target_global_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_set_position_target_global_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_position_target_global_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_set_position_target_global_int_decode(&msg, &packet2); + mavlink_msg_set_position_target_global_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.target_system , packet1.target_component , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_set_position_target_global_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_position_target_global_int_t packet_in = { - 963497464,963497672,963497880,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27 + mavlink_position_target_global_int_t packet_in = { + 963497464,963497672,963497880,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,19731,27 }; - mavlink_position_target_global_int_t packet1, packet2; + mavlink_position_target_global_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.lat_int = packet_in.lat_int; - packet1.lon_int = packet_in.lon_int; - packet1.alt = packet_in.alt; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.afx = packet_in.afx; - packet1.afy = packet_in.afy; - packet1.afz = packet_in.afz; - packet1.yaw = packet_in.yaw; - packet1.yaw_rate = packet_in.yaw_rate; - packet1.type_mask = packet_in.type_mask; - packet1.coordinate_frame = packet_in.coordinate_frame; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.lat_int = packet_in.lat_int; + packet1.lon_int = packet_in.lon_int; + packet1.alt = packet_in.alt; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.afx = packet_in.afx; + packet1.afy = packet_in.afy; + packet1.afz = packet_in.afz; + packet1.yaw = packet_in.yaw; + packet1.yaw_rate = packet_in.yaw_rate; + packet1.type_mask = packet_in.type_mask; + packet1.coordinate_frame = packet_in.coordinate_frame; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_POSITION_TARGET_GLOBAL_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_position_target_global_int_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_position_target_global_int_decode(&msg, &packet2); + mavlink_msg_position_target_global_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_position_target_global_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_position_target_global_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_position_target_global_int_decode(&msg, &packet2); + mavlink_msg_position_target_global_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_position_target_global_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_position_target_global_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); - mavlink_msg_position_target_global_int_decode(&msg, &packet2); + mavlink_msg_position_target_global_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.coordinate_frame , packet1.type_mask , packet1.lat_int , packet1.lon_int , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.afx , packet1.afy , packet1.afz , packet1.yaw , packet1.yaw_rate ); + mavlink_msg_position_target_global_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_local_position_ned_system_global_offset_t packet_in = { - 963497464,45.0,73.0,101.0,129.0,157.0,185.0 + mavlink_local_position_ned_system_global_offset_t packet_in = { + 963497464,45.0,73.0,101.0,129.0,157.0,185.0 }; - mavlink_local_position_ned_system_global_offset_t packet1, packet2; + mavlink_local_position_ned_system_global_offset_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOCAL_POSITION_NED_SYSTEM_GLOBAL_OFFSET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_system_global_offset_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_local_position_ned_system_global_offset_decode(&msg, &packet2); + mavlink_msg_local_position_ned_system_global_offset_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_local_position_ned_system_global_offset_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_system_global_offset_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_local_position_ned_system_global_offset_decode(&msg, &packet2); + mavlink_msg_local_position_ned_system_global_offset_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_local_position_ned_system_global_offset_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_local_position_ned_system_global_offset_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_local_position_ned_system_global_offset_decode(&msg, &packet2); + mavlink_msg_local_position_ned_system_global_offset_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_local_position_ned_system_global_offset_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_STATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hil_state_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,963499128,963499336,963499544,19523,19627,19731,19835,19939,20043 + mavlink_hil_state_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,963499128,963499336,963499544,19523,19627,19731,19835,19939,20043 }; - mavlink_hil_state_t packet1, packet2; + mavlink_hil_state_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.rollspeed = packet_in.rollspeed; - packet1.pitchspeed = packet_in.pitchspeed; - packet1.yawspeed = packet_in.yawspeed; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - - - + packet1.time_usec = packet_in.time_usec; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.rollspeed = packet_in.rollspeed; + packet1.pitchspeed = packet_in.pitchspeed; + packet1.yawspeed = packet_in.yawspeed; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_STATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_STATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_state_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hil_state_decode(&msg, &packet2); + mavlink_msg_hil_state_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_state_pack(system_id, component_id, &msg , packet1.time_usec , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.xacc , packet1.yacc , packet1.zacc ); - mavlink_msg_hil_state_decode(&msg, &packet2); + mavlink_msg_hil_state_pack(system_id, component_id, &msg , packet1.time_usec , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.xacc , packet1.yacc , packet1.zacc ); + mavlink_msg_hil_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_state_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.xacc , packet1.yacc , packet1.zacc ); - mavlink_msg_hil_state_decode(&msg, &packet2); + mavlink_msg_hil_state_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.roll , packet1.pitch , packet1.yaw , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.xacc , packet1.yacc , packet1.zacc ); + mavlink_msg_hil_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_CONTROLS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hil_controls_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,125,192 + mavlink_hil_controls_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,125,192 }; - mavlink_hil_controls_t packet1, packet2; + mavlink_hil_controls_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.roll_ailerons = packet_in.roll_ailerons; - packet1.pitch_elevator = packet_in.pitch_elevator; - packet1.yaw_rudder = packet_in.yaw_rudder; - packet1.throttle = packet_in.throttle; - packet1.aux1 = packet_in.aux1; - packet1.aux2 = packet_in.aux2; - packet1.aux3 = packet_in.aux3; - packet1.aux4 = packet_in.aux4; - packet1.mode = packet_in.mode; - packet1.nav_mode = packet_in.nav_mode; - - - + packet1.time_usec = packet_in.time_usec; + packet1.roll_ailerons = packet_in.roll_ailerons; + packet1.pitch_elevator = packet_in.pitch_elevator; + packet1.yaw_rudder = packet_in.yaw_rudder; + packet1.throttle = packet_in.throttle; + packet1.aux1 = packet_in.aux1; + packet1.aux2 = packet_in.aux2; + packet1.aux3 = packet_in.aux3; + packet1.aux4 = packet_in.aux4; + packet1.mode = packet_in.mode; + packet1.nav_mode = packet_in.nav_mode; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_CONTROLS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_controls_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hil_controls_decode(&msg, &packet2); + mavlink_msg_hil_controls_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_controls_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_controls_pack(system_id, component_id, &msg , packet1.time_usec , packet1.roll_ailerons , packet1.pitch_elevator , packet1.yaw_rudder , packet1.throttle , packet1.aux1 , packet1.aux2 , packet1.aux3 , packet1.aux4 , packet1.mode , packet1.nav_mode ); - mavlink_msg_hil_controls_decode(&msg, &packet2); + mavlink_msg_hil_controls_pack(system_id, component_id, &msg , packet1.time_usec , packet1.roll_ailerons , packet1.pitch_elevator , packet1.yaw_rudder , packet1.throttle , packet1.aux1 , packet1.aux2 , packet1.aux3 , packet1.aux4 , packet1.mode , packet1.nav_mode ); + mavlink_msg_hil_controls_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_controls_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.roll_ailerons , packet1.pitch_elevator , packet1.yaw_rudder , packet1.throttle , packet1.aux1 , packet1.aux2 , packet1.aux3 , packet1.aux4 , packet1.mode , packet1.nav_mode ); - mavlink_msg_hil_controls_decode(&msg, &packet2); + mavlink_msg_hil_controls_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.roll_ailerons , packet1.pitch_elevator , packet1.yaw_rudder , packet1.throttle , packet1.aux1 , packet1.aux2 , packet1.aux3 , packet1.aux4 , packet1.mode , packet1.nav_mode ); + mavlink_msg_hil_controls_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hil_rc_inputs_raw_t packet_in = { - 93372036854775807ULL,17651,17755,17859,17963,18067,18171,18275,18379,18483,18587,18691,18795,101 + mavlink_hil_rc_inputs_raw_t packet_in = { + 93372036854775807ULL,17651,17755,17859,17963,18067,18171,18275,18379,18483,18587,18691,18795,101 }; - mavlink_hil_rc_inputs_raw_t packet1, packet2; + mavlink_hil_rc_inputs_raw_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.chan1_raw = packet_in.chan1_raw; - packet1.chan2_raw = packet_in.chan2_raw; - packet1.chan3_raw = packet_in.chan3_raw; - packet1.chan4_raw = packet_in.chan4_raw; - packet1.chan5_raw = packet_in.chan5_raw; - packet1.chan6_raw = packet_in.chan6_raw; - packet1.chan7_raw = packet_in.chan7_raw; - packet1.chan8_raw = packet_in.chan8_raw; - packet1.chan9_raw = packet_in.chan9_raw; - packet1.chan10_raw = packet_in.chan10_raw; - packet1.chan11_raw = packet_in.chan11_raw; - packet1.chan12_raw = packet_in.chan12_raw; - packet1.rssi = packet_in.rssi; - - - + packet1.time_usec = packet_in.time_usec; + packet1.chan1_raw = packet_in.chan1_raw; + packet1.chan2_raw = packet_in.chan2_raw; + packet1.chan3_raw = packet_in.chan3_raw; + packet1.chan4_raw = packet_in.chan4_raw; + packet1.chan5_raw = packet_in.chan5_raw; + packet1.chan6_raw = packet_in.chan6_raw; + packet1.chan7_raw = packet_in.chan7_raw; + packet1.chan8_raw = packet_in.chan8_raw; + packet1.chan9_raw = packet_in.chan9_raw; + packet1.chan10_raw = packet_in.chan10_raw; + packet1.chan11_raw = packet_in.chan11_raw; + packet1.chan12_raw = packet_in.chan12_raw; + packet1.rssi = packet_in.rssi; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_RC_INPUTS_RAW_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_rc_inputs_raw_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hil_rc_inputs_raw_decode(&msg, &packet2); + mavlink_msg_hil_rc_inputs_raw_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_rc_inputs_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_rc_inputs_raw_pack(system_id, component_id, &msg , packet1.time_usec , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.rssi ); - mavlink_msg_hil_rc_inputs_raw_decode(&msg, &packet2); + mavlink_msg_hil_rc_inputs_raw_pack(system_id, component_id, &msg , packet1.time_usec , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.rssi ); + mavlink_msg_hil_rc_inputs_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_rc_inputs_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.rssi ); - mavlink_msg_hil_rc_inputs_raw_decode(&msg, &packet2); + mavlink_msg_hil_rc_inputs_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.chan1_raw , packet1.chan2_raw , packet1.chan3_raw , packet1.chan4_raw , packet1.chan5_raw , packet1.chan6_raw , packet1.chan7_raw , packet1.chan8_raw , packet1.chan9_raw , packet1.chan10_raw , packet1.chan11_raw , packet1.chan12_raw , packet1.rssi ); + mavlink_msg_hil_rc_inputs_raw_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_optical_flow_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,18275,18379,77,144 + mavlink_hil_actuator_controls_t packet_in = { + 93372036854775807ULL,93372036854776311ULL,{ 129.0, 130.0, 131.0, 132.0, 133.0, 134.0, 135.0, 136.0, 137.0, 138.0, 139.0, 140.0, 141.0, 142.0, 143.0, 144.0 },245 }; - mavlink_optical_flow_t packet1, packet2; + mavlink_hil_actuator_controls_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.flow_comp_m_x = packet_in.flow_comp_m_x; - packet1.flow_comp_m_y = packet_in.flow_comp_m_y; - packet1.ground_distance = packet_in.ground_distance; - packet1.flow_x = packet_in.flow_x; - packet1.flow_y = packet_in.flow_y; - packet1.sensor_id = packet_in.sensor_id; - packet1.quality = packet_in.quality; + packet1.time_usec = packet_in.time_usec; + packet1.flags = packet_in.flags; + packet1.mode = packet_in.mode; + mav_array_memcpy(packet1.controls, packet_in.controls, sizeof(float)*16); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_ACTUATOR_CONTROLS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_optical_flow_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_optical_flow_decode(&msg, &packet2); + mavlink_msg_hil_actuator_controls_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_actuator_controls_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_optical_flow_pack(system_id, component_id, &msg , packet1.time_usec , packet1.sensor_id , packet1.flow_x , packet1.flow_y , packet1.flow_comp_m_x , packet1.flow_comp_m_y , packet1.quality , packet1.ground_distance ); - mavlink_msg_optical_flow_decode(&msg, &packet2); + mavlink_msg_hil_actuator_controls_pack(system_id, component_id, &msg , packet1.time_usec , packet1.controls , packet1.mode , packet1.flags ); + mavlink_msg_hil_actuator_controls_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_optical_flow_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.sensor_id , packet1.flow_x , packet1.flow_y , packet1.flow_comp_m_x , packet1.flow_comp_m_y , packet1.quality , packet1.ground_distance ); - mavlink_msg_optical_flow_decode(&msg, &packet2); + mavlink_msg_hil_actuator_controls_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.controls , packet1.mode , packet1.flags ); + mavlink_msg_hil_actuator_controls_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_OPTICAL_FLOW >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_global_vision_position_estimate_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0 + mavlink_optical_flow_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,18275,18379,77,144 }; - mavlink_global_vision_position_estimate_t packet1, packet2; + mavlink_optical_flow_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.usec = packet_in.usec; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - - - + packet1.time_usec = packet_in.time_usec; + packet1.flow_comp_m_x = packet_in.flow_comp_m_x; + packet1.flow_comp_m_y = packet_in.flow_comp_m_y; + packet1.ground_distance = packet_in.ground_distance; + packet1.flow_x = packet_in.flow_x; + packet1.flow_y = packet_in.flow_y; + packet1.sensor_id = packet_in.sensor_id; + packet1.quality = packet_in.quality; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_OPTICAL_FLOW_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_vision_position_estimate_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_global_vision_position_estimate_decode(&msg, &packet2); + mavlink_msg_optical_flow_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_optical_flow_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_vision_position_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_global_vision_position_estimate_decode(&msg, &packet2); + mavlink_msg_optical_flow_pack(system_id, component_id, &msg , packet1.time_usec , packet1.sensor_id , packet1.flow_x , packet1.flow_y , packet1.flow_comp_m_x , packet1.flow_comp_m_y , packet1.quality , packet1.ground_distance ); + mavlink_msg_optical_flow_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_global_vision_position_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_global_vision_position_estimate_decode(&msg, &packet2); + mavlink_msg_optical_flow_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.sensor_id , packet1.flow_x , packet1.flow_y , packet1.flow_comp_m_x , packet1.flow_comp_m_y , packet1.quality , packet1.ground_distance ); + mavlink_msg_optical_flow_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_vision_position_estimate_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0 + mavlink_global_vision_position_estimate_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0 }; - mavlink_vision_position_estimate_t packet1, packet2; + mavlink_global_vision_position_estimate_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.usec = packet_in.usec; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - - - + packet1.usec = packet_in.usec; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GLOBAL_VISION_POSITION_ESTIMATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vision_position_estimate_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_vision_position_estimate_decode(&msg, &packet2); + mavlink_msg_global_vision_position_estimate_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_global_vision_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vision_position_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_vision_position_estimate_decode(&msg, &packet2); + mavlink_msg_global_vision_position_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_global_vision_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vision_position_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_vision_position_estimate_decode(&msg, &packet2); + mavlink_msg_global_vision_position_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_global_vision_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_vision_speed_estimate_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0 + mavlink_vision_position_estimate_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0 }; - mavlink_vision_speed_estimate_t packet1, packet2; + mavlink_vision_position_estimate_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.usec = packet_in.usec; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - - - + packet1.usec = packet_in.usec; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_VISION_POSITION_ESTIMATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vision_speed_estimate_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_vision_speed_estimate_decode(&msg, &packet2); + mavlink_msg_vision_position_estimate_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_vision_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vision_speed_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z ); - mavlink_msg_vision_speed_estimate_decode(&msg, &packet2); + mavlink_msg_vision_position_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_vision_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vision_speed_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z ); - mavlink_msg_vision_speed_estimate_decode(&msg, &packet2); + mavlink_msg_vision_position_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_vision_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_vicon_position_estimate_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0 + mavlink_vision_speed_estimate_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0 }; - mavlink_vicon_position_estimate_t packet1, packet2; + mavlink_vision_speed_estimate_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.usec = packet_in.usec; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; + packet1.usec = packet_in.usec; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_VISION_SPEED_ESTIMATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vicon_position_estimate_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_vicon_position_estimate_decode(&msg, &packet2); + mavlink_msg_vision_speed_estimate_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_vision_speed_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vicon_position_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_vicon_position_estimate_decode(&msg, &packet2); + mavlink_msg_vision_speed_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z ); + mavlink_msg_vision_speed_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_vicon_position_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); - mavlink_msg_vicon_position_estimate_decode(&msg, &packet2); + mavlink_msg_vision_speed_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z ); + mavlink_msg_vision_speed_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_highres_imu_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,353.0,381.0,409.0,20355 + mavlink_vicon_position_estimate_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0 }; - mavlink_highres_imu_t packet1, packet2; + mavlink_vicon_position_estimate_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - packet1.xgyro = packet_in.xgyro; - packet1.ygyro = packet_in.ygyro; - packet1.zgyro = packet_in.zgyro; - packet1.xmag = packet_in.xmag; - packet1.ymag = packet_in.ymag; - packet1.zmag = packet_in.zmag; - packet1.abs_pressure = packet_in.abs_pressure; - packet1.diff_pressure = packet_in.diff_pressure; - packet1.pressure_alt = packet_in.pressure_alt; - packet1.temperature = packet_in.temperature; - packet1.fields_updated = packet_in.fields_updated; - - - + packet1.usec = packet_in.usec; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_VICON_POSITION_ESTIMATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_highres_imu_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_highres_imu_decode(&msg, &packet2); + mavlink_msg_vicon_position_estimate_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_vicon_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_highres_imu_pack(system_id, component_id, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); - mavlink_msg_highres_imu_decode(&msg, &packet2); + mavlink_msg_vicon_position_estimate_pack(system_id, component_id, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_vicon_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_highres_imu_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); - mavlink_msg_highres_imu_decode(&msg, &packet2); + mavlink_msg_vicon_position_estimate_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.usec , packet1.x , packet1.y , packet1.z , packet1.roll , packet1.pitch , packet1.yaw ); + mavlink_msg_vicon_position_estimate_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIGHRES_IMU >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_optical_flow_rad_t packet_in = { - 93372036854775807ULL,963497880,101.0,129.0,157.0,185.0,213.0,963499128,269.0,19315,3,70 + mavlink_highres_imu_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,353.0,381.0,409.0,20355 }; - mavlink_optical_flow_rad_t packet1, packet2; + mavlink_highres_imu_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.integration_time_us = packet_in.integration_time_us; - packet1.integrated_x = packet_in.integrated_x; - packet1.integrated_y = packet_in.integrated_y; - packet1.integrated_xgyro = packet_in.integrated_xgyro; - packet1.integrated_ygyro = packet_in.integrated_ygyro; - packet1.integrated_zgyro = packet_in.integrated_zgyro; - packet1.time_delta_distance_us = packet_in.time_delta_distance_us; - packet1.distance = packet_in.distance; - packet1.temperature = packet_in.temperature; - packet1.sensor_id = packet_in.sensor_id; - packet1.quality = packet_in.quality; - - - + packet1.time_usec = packet_in.time_usec; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.xmag = packet_in.xmag; + packet1.ymag = packet_in.ymag; + packet1.zmag = packet_in.zmag; + packet1.abs_pressure = packet_in.abs_pressure; + packet1.diff_pressure = packet_in.diff_pressure; + packet1.pressure_alt = packet_in.pressure_alt; + packet1.temperature = packet_in.temperature; + packet1.fields_updated = packet_in.fields_updated; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIGHRES_IMU_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_optical_flow_rad_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_optical_flow_rad_decode(&msg, &packet2); + mavlink_msg_highres_imu_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_highres_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_optical_flow_rad_pack(system_id, component_id, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); - mavlink_msg_optical_flow_rad_decode(&msg, &packet2); + mavlink_msg_highres_imu_pack(system_id, component_id, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); + mavlink_msg_highres_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_optical_flow_rad_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); - mavlink_msg_optical_flow_rad_decode(&msg, &packet2); + mavlink_msg_highres_imu_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); + mavlink_msg_highres_imu_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_OPTICAL_FLOW_RAD >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hil_sensor_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,353.0,381.0,409.0,963500584 + mavlink_optical_flow_rad_t packet_in = { + 93372036854775807ULL,963497880,101.0,129.0,157.0,185.0,213.0,963499128,269.0,19315,3,70 }; - mavlink_hil_sensor_t packet1, packet2; + mavlink_optical_flow_rad_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - packet1.xgyro = packet_in.xgyro; - packet1.ygyro = packet_in.ygyro; - packet1.zgyro = packet_in.zgyro; - packet1.xmag = packet_in.xmag; - packet1.ymag = packet_in.ymag; - packet1.zmag = packet_in.zmag; - packet1.abs_pressure = packet_in.abs_pressure; - packet1.diff_pressure = packet_in.diff_pressure; - packet1.pressure_alt = packet_in.pressure_alt; - packet1.temperature = packet_in.temperature; - packet1.fields_updated = packet_in.fields_updated; - - - + packet1.time_usec = packet_in.time_usec; + packet1.integration_time_us = packet_in.integration_time_us; + packet1.integrated_x = packet_in.integrated_x; + packet1.integrated_y = packet_in.integrated_y; + packet1.integrated_xgyro = packet_in.integrated_xgyro; + packet1.integrated_ygyro = packet_in.integrated_ygyro; + packet1.integrated_zgyro = packet_in.integrated_zgyro; + packet1.time_delta_distance_us = packet_in.time_delta_distance_us; + packet1.distance = packet_in.distance; + packet1.temperature = packet_in.temperature; + packet1.sensor_id = packet_in.sensor_id; + packet1.quality = packet_in.quality; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_OPTICAL_FLOW_RAD_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_sensor_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hil_sensor_decode(&msg, &packet2); + mavlink_msg_optical_flow_rad_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_optical_flow_rad_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_sensor_pack(system_id, component_id, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); - mavlink_msg_hil_sensor_decode(&msg, &packet2); + mavlink_msg_optical_flow_rad_pack(system_id, component_id, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); + mavlink_msg_optical_flow_rad_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_sensor_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); - mavlink_msg_hil_sensor_decode(&msg, &packet2); + mavlink_msg_optical_flow_rad_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); + mavlink_msg_optical_flow_rad_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_SENSOR >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_sim_state_t packet_in = { - 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,353.0,381.0,409.0,437.0,465.0,493.0,521.0,549.0,577.0 + mavlink_hil_sensor_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,353.0,381.0,409.0,963500584 }; - mavlink_sim_state_t packet1, packet2; + mavlink_hil_sensor_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.q1 = packet_in.q1; - packet1.q2 = packet_in.q2; - packet1.q3 = packet_in.q3; - packet1.q4 = packet_in.q4; - packet1.roll = packet_in.roll; - packet1.pitch = packet_in.pitch; - packet1.yaw = packet_in.yaw; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - packet1.xgyro = packet_in.xgyro; - packet1.ygyro = packet_in.ygyro; - packet1.zgyro = packet_in.zgyro; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.std_dev_horz = packet_in.std_dev_horz; - packet1.std_dev_vert = packet_in.std_dev_vert; - packet1.vn = packet_in.vn; - packet1.ve = packet_in.ve; - packet1.vd = packet_in.vd; - + packet1.time_usec = packet_in.time_usec; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.xmag = packet_in.xmag; + packet1.ymag = packet_in.ymag; + packet1.zmag = packet_in.zmag; + packet1.abs_pressure = packet_in.abs_pressure; + packet1.diff_pressure = packet_in.diff_pressure; + packet1.pressure_alt = packet_in.pressure_alt; + packet1.temperature = packet_in.temperature; + packet1.fields_updated = packet_in.fields_updated; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_SENSOR_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_sensor_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_sensor_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_sensor_pack(system_id, component_id, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); + mavlink_msg_hil_sensor_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_sensor_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag , packet1.abs_pressure , packet1.diff_pressure , packet1.pressure_alt , packet1.temperature , packet1.fields_updated ); + mavlink_msg_hil_sensor_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SIM_STATE >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_sim_state_t packet_in = { + 17.0,45.0,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,353.0,381.0,409.0,437.0,465.0,493.0,521.0,549.0,577.0 + }; + mavlink_sim_state_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.q1 = packet_in.q1; + packet1.q2 = packet_in.q2; + packet1.q3 = packet_in.q3; + packet1.q4 = packet_in.q4; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.yaw = packet_in.yaw; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.std_dev_horz = packet_in.std_dev_horz; + packet1.std_dev_vert = packet_in.std_dev_vert; + packet1.vn = packet_in.vn; + packet1.ve = packet_in.ve; + packet1.vd = packet_in.vd; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SIM_STATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SIM_STATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sim_state_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_sim_state_decode(&msg, &packet2); + mavlink_msg_sim_state_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_sim_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sim_state_pack(system_id, component_id, &msg , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lon , packet1.alt , packet1.std_dev_horz , packet1.std_dev_vert , packet1.vn , packet1.ve , packet1.vd ); - mavlink_msg_sim_state_decode(&msg, &packet2); + mavlink_msg_sim_state_pack(system_id, component_id, &msg , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lon , packet1.alt , packet1.std_dev_horz , packet1.std_dev_vert , packet1.vn , packet1.ve , packet1.vd ); + mavlink_msg_sim_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_sim_state_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lon , packet1.alt , packet1.std_dev_horz , packet1.std_dev_vert , packet1.vn , packet1.ve , packet1.vd ); - mavlink_msg_sim_state_decode(&msg, &packet2); + mavlink_msg_sim_state_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.q1 , packet1.q2 , packet1.q3 , packet1.q4 , packet1.roll , packet1.pitch , packet1.yaw , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.lat , packet1.lon , packet1.alt , packet1.std_dev_horz , packet1.std_dev_vert , packet1.vn , packet1.ve , packet1.vd ); + mavlink_msg_sim_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RADIO_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_radio_status_t packet_in = { + 17235,17339,17,84,151,218,29 + }; + mavlink_radio_status_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.rxerrors = packet_in.rxerrors; + packet1.fixed = packet_in.fixed; + packet1.rssi = packet_in.rssi; + packet1.remrssi = packet_in.remrssi; + packet1.txbuf = packet_in.txbuf; + packet1.noise = packet_in.noise; + packet1.remnoise = packet_in.remnoise; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RADIO_STATUS_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_radio_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_radio_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_radio_status_pack(system_id, component_id, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); + mavlink_msg_radio_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_radio_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); + mavlink_msg_radio_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_radio_status_t packet_in = { - 17235,17339,17,84,151,218,29 + mavlink_file_transfer_protocol_t packet_in = { + 5,72,139,{ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200 } }; - mavlink_radio_status_t packet1, packet2; + mavlink_file_transfer_protocol_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.rxerrors = packet_in.rxerrors; - packet1.fixed = packet_in.fixed; - packet1.rssi = packet_in.rssi; - packet1.remrssi = packet_in.remrssi; - packet1.txbuf = packet_in.txbuf; - packet1.noise = packet_in.noise; - packet1.remnoise = packet_in.remnoise; + packet1.target_network = packet_in.target_network; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + mav_array_memcpy(packet1.payload, packet_in.payload, sizeof(uint8_t)*251); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_file_transfer_protocol_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_file_transfer_protocol_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_file_transfer_protocol_pack(system_id, component_id, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.payload ); + mavlink_msg_file_transfer_protocol_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_file_transfer_protocol_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.payload ); + mavlink_msg_file_transfer_protocol_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_TIMESYNC >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_timesync_t packet_in = { + 93372036854775807LL,93372036854776311LL + }; + mavlink_timesync_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.tc1 = packet_in.tc1; + packet1.ts1 = packet_in.ts1; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_TIMESYNC_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_TIMESYNC_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_radio_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_radio_status_decode(&msg, &packet2); + mavlink_msg_timesync_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_timesync_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_radio_status_pack(system_id, component_id, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); - mavlink_msg_radio_status_decode(&msg, &packet2); + mavlink_msg_timesync_pack(system_id, component_id, &msg , packet1.tc1 , packet1.ts1 ); + mavlink_msg_timesync_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_radio_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.rssi , packet1.remrssi , packet1.txbuf , packet1.noise , packet1.remnoise , packet1.rxerrors , packet1.fixed ); - mavlink_msg_radio_status_decode(&msg, &packet2); + mavlink_msg_timesync_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.tc1 , packet1.ts1 ); + mavlink_msg_timesync_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_CAMERA_TRIGGER >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_file_transfer_protocol_t packet_in = { - 5,72,139,{ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200 } + mavlink_camera_trigger_t packet_in = { + 93372036854775807ULL,963497880 }; - mavlink_file_transfer_protocol_t packet1, packet2; + mavlink_camera_trigger_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_network = packet_in.target_network; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.time_usec = packet_in.time_usec; + packet1.seq = packet_in.seq; + - mav_array_memcpy(packet1.payload, packet_in.payload, sizeof(uint8_t)*251); +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_CAMERA_TRIGGER_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_camera_trigger_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_camera_trigger_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_camera_trigger_pack(system_id, component_id, &msg , packet1.time_usec , packet1.seq ); + mavlink_msg_camera_trigger_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_camera_trigger_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.seq ); + mavlink_msg_camera_trigger_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_GPS >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_hil_gps_t packet_in = { + 93372036854775807ULL,963497880,963498088,963498296,18275,18379,18483,18587,18691,18795,18899,235,46 + }; + mavlink_hil_gps_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_usec = packet_in.time_usec; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.eph = packet_in.eph; + packet1.epv = packet_in.epv; + packet1.vel = packet_in.vel; + packet1.vn = packet_in.vn; + packet1.ve = packet_in.ve; + packet1.vd = packet_in.vd; + packet1.cog = packet_in.cog; + packet1.fix_type = packet_in.fix_type; + packet1.satellites_visible = packet_in.satellites_visible; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_GPS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_GPS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_file_transfer_protocol_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_file_transfer_protocol_decode(&msg, &packet2); + mavlink_msg_hil_gps_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_gps_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_file_transfer_protocol_pack(system_id, component_id, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.payload ); - mavlink_msg_file_transfer_protocol_decode(&msg, &packet2); + mavlink_msg_hil_gps_pack(system_id, component_id, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.vn , packet1.ve , packet1.vd , packet1.cog , packet1.satellites_visible ); + mavlink_msg_hil_gps_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_file_transfer_protocol_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.payload ); - mavlink_msg_file_transfer_protocol_decode(&msg, &packet2); + mavlink_msg_hil_gps_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.vn , packet1.ve , packet1.vd , packet1.cog , packet1.satellites_visible ); + mavlink_msg_hil_gps_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_OPTICAL_FLOW >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_hil_optical_flow_t packet_in = { + 93372036854775807ULL,963497880,101.0,129.0,157.0,185.0,213.0,963499128,269.0,19315,3,70 + }; + mavlink_hil_optical_flow_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_usec = packet_in.time_usec; + packet1.integration_time_us = packet_in.integration_time_us; + packet1.integrated_x = packet_in.integrated_x; + packet1.integrated_y = packet_in.integrated_y; + packet1.integrated_xgyro = packet_in.integrated_xgyro; + packet1.integrated_ygyro = packet_in.integrated_ygyro; + packet1.integrated_zgyro = packet_in.integrated_zgyro; + packet1.time_delta_distance_us = packet_in.time_delta_distance_us; + packet1.distance = packet_in.distance; + packet1.temperature = packet_in.temperature; + packet1.sensor_id = packet_in.sensor_id; + packet1.quality = packet_in.quality; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_OPTICAL_FLOW_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_optical_flow_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_optical_flow_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_optical_flow_pack(system_id, component_id, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); + mavlink_msg_hil_optical_flow_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_optical_flow_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); + mavlink_msg_hil_optical_flow_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIL_STATE_QUATERNION >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_hil_state_quaternion_t packet_in = { + 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0 },185.0,213.0,241.0,963499336,963499544,963499752,19731,19835,19939,20043,20147,20251,20355,20459 + }; + mavlink_hil_state_quaternion_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_usec = packet_in.time_usec; + packet1.rollspeed = packet_in.rollspeed; + packet1.pitchspeed = packet_in.pitchspeed; + packet1.yawspeed = packet_in.yawspeed; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.vx = packet_in.vx; + packet1.vy = packet_in.vy; + packet1.vz = packet_in.vz; + packet1.ind_airspeed = packet_in.ind_airspeed; + packet1.true_airspeed = packet_in.true_airspeed; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + + mav_array_memcpy(packet1.attitude_quaternion, packet_in.attitude_quaternion, sizeof(float)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIL_STATE_QUATERNION_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_state_quaternion_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_hil_state_quaternion_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_state_quaternion_pack(system_id, component_id, &msg , packet1.time_usec , packet1.attitude_quaternion , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.ind_airspeed , packet1.true_airspeed , packet1.xacc , packet1.yacc , packet1.zacc ); + mavlink_msg_hil_state_quaternion_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_hil_state_quaternion_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.attitude_quaternion , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.ind_airspeed , packet1.true_airspeed , packet1.xacc , packet1.yacc , packet1.zacc ); + mavlink_msg_hil_state_quaternion_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SCALED_IMU2 >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_scaled_imu2_t packet_in = { + 963497464,17443,17547,17651,17755,17859,17963,18067,18171,18275 + }; + mavlink_scaled_imu2_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.xmag = packet_in.xmag; + packet1.ymag = packet_in.ymag; + packet1.zmag = packet_in.zmag; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SCALED_IMU2_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_scaled_imu2_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_scaled_imu2_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_scaled_imu2_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_scaled_imu2_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_scaled_imu2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_scaled_imu2_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOG_REQUEST_LIST >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_log_request_list_t packet_in = { + 17235,17339,17,84 + }; + mavlink_log_request_list_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.start = packet_in.start; + packet1.end = packet_in.end; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOG_REQUEST_LIST_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_list_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_log_request_list_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.start , packet1.end ); + mavlink_msg_log_request_list_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.start , packet1.end ); + mavlink_msg_log_request_list_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOG_ENTRY >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_timesync_t packet_in = { - 93372036854775807LL,93372036854776311LL + mavlink_log_entry_t packet_in = { + 963497464,963497672,17651,17755,17859 }; - mavlink_timesync_t packet1, packet2; + mavlink_log_entry_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.tc1 = packet_in.tc1; - packet1.ts1 = packet_in.ts1; + packet1.time_utc = packet_in.time_utc; + packet1.size = packet_in.size; + packet1.id = packet_in.id; + packet1.num_logs = packet_in.num_logs; + packet1.last_log_num = packet_in.last_log_num; +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOG_ENTRY_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_entry_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_log_entry_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_entry_pack(system_id, component_id, &msg , packet1.id , packet1.num_logs , packet1.last_log_num , packet1.time_utc , packet1.size ); + mavlink_msg_log_entry_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_timesync_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_timesync_decode(&msg, &packet2); + mavlink_msg_log_entry_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.id , packet1.num_logs , packet1.last_log_num , packet1.time_utc , packet1.size ); + mavlink_msg_log_entry_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOG_REQUEST_DATA >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_log_request_data_t packet_in = { + 963497464,963497672,17651,163,230 + }; + mavlink_log_request_data_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.ofs = packet_in.ofs; + packet1.count = packet_in.count; + packet1.id = packet_in.id; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOG_REQUEST_DATA_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_data_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_log_request_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_data_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.id , packet1.ofs , packet1.count ); + mavlink_msg_log_request_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.id , packet1.ofs , packet1.count ); + mavlink_msg_log_request_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOG_DATA >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_log_data_t packet_in = { + 963497464,17443,151,{ 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 } + }; + mavlink_log_data_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.ofs = packet_in.ofs; + packet1.id = packet_in.id; + packet1.count = packet_in.count; + + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*90); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOG_DATA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOG_DATA_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_data_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_log_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_data_pack(system_id, component_id, &msg , packet1.id , packet1.ofs , packet1.count , packet1.data ); + mavlink_msg_log_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.id , packet1.ofs , packet1.count , packet1.data ); + mavlink_msg_log_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOG_ERASE >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_log_erase_t packet_in = { + 5,72 + }; + mavlink_log_erase_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOG_ERASE_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_erase_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_log_erase_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_erase_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_log_erase_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_erase_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_log_erase_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LOG_REQUEST_END >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_log_request_end_t packet_in = { + 5,72 + }; + mavlink_log_request_end_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LOG_REQUEST_END_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_end_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_log_request_end_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_end_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_log_request_end_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_log_request_end_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); + mavlink_msg_log_request_end_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS_INJECT_DATA >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gps_inject_data_t packet_in = { + 5,72,139,{ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59 } + }; + mavlink_gps_inject_data_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; + packet1.len = packet_in.len; + + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*110); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS_INJECT_DATA_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps_inject_data_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps_inject_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps_inject_data_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.len , packet1.data ); + mavlink_msg_gps_inject_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps_inject_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.len , packet1.data ); + mavlink_msg_gps_inject_data_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS2_RAW >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gps2_raw_t packet_in = { + 93372036854775807ULL,963497880,963498088,963498296,963498504,18483,18587,18691,18795,101,168,235 + }; + mavlink_gps2_raw_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_usec = packet_in.time_usec; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.dgps_age = packet_in.dgps_age; + packet1.eph = packet_in.eph; + packet1.epv = packet_in.epv; + packet1.vel = packet_in.vel; + packet1.cog = packet_in.cog; + packet1.fix_type = packet_in.fix_type; + packet1.satellites_visible = packet_in.satellites_visible; + packet1.dgps_numch = packet_in.dgps_numch; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS2_RAW_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps2_raw_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps2_raw_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps2_raw_pack(system_id, component_id, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible , packet1.dgps_numch , packet1.dgps_age ); + mavlink_msg_gps2_raw_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps2_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible , packet1.dgps_numch , packet1.dgps_age ); + mavlink_msg_gps2_raw_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_POWER_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_power_status_t packet_in = { + 17235,17339,17443 + }; + mavlink_power_status_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.Vcc = packet_in.Vcc; + packet1.Vservo = packet_in.Vservo; + packet1.flags = packet_in.flags; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_POWER_STATUS_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_power_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_power_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_power_status_pack(system_id, component_id, &msg , packet1.Vcc , packet1.Vservo , packet1.flags ); + mavlink_msg_power_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_power_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.Vcc , packet1.Vservo , packet1.flags ); + mavlink_msg_power_status_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SERIAL_CONTROL >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_serial_control_t packet_in = { + 963497464,17443,151,218,29,{ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165 } + }; + mavlink_serial_control_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.baudrate = packet_in.baudrate; + packet1.timeout = packet_in.timeout; + packet1.device = packet_in.device; + packet1.flags = packet_in.flags; + packet1.count = packet_in.count; + + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*70); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SERIAL_CONTROL_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_serial_control_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_serial_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_serial_control_pack(system_id, component_id, &msg , packet1.device , packet1.flags , packet1.timeout , packet1.baudrate , packet1.count , packet1.data ); + mavlink_msg_serial_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_serial_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.device , packet1.flags , packet1.timeout , packet1.baudrate , packet1.count , packet1.data ); + mavlink_msg_serial_control_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS_RTK >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gps_rtk_t packet_in = { + 963497464,963497672,963497880,963498088,963498296,963498504,963498712,18691,223,34,101,168,235 + }; + mavlink_gps_rtk_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_last_baseline_ms = packet_in.time_last_baseline_ms; + packet1.tow = packet_in.tow; + packet1.baseline_a_mm = packet_in.baseline_a_mm; + packet1.baseline_b_mm = packet_in.baseline_b_mm; + packet1.baseline_c_mm = packet_in.baseline_c_mm; + packet1.accuracy = packet_in.accuracy; + packet1.iar_num_hypotheses = packet_in.iar_num_hypotheses; + packet1.wn = packet_in.wn; + packet1.rtk_receiver_id = packet_in.rtk_receiver_id; + packet1.rtk_health = packet_in.rtk_health; + packet1.rtk_rate = packet_in.rtk_rate; + packet1.nsats = packet_in.nsats; + packet1.baseline_coords_type = packet_in.baseline_coords_type; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS_RTK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS_RTK_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps_rtk_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps_rtk_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps_rtk_pack(system_id, component_id, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); + mavlink_msg_gps_rtk_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps_rtk_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); + mavlink_msg_gps_rtk_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS2_RTK >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_gps2_rtk_t packet_in = { + 963497464,963497672,963497880,963498088,963498296,963498504,963498712,18691,223,34,101,168,235 + }; + mavlink_gps2_rtk_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_last_baseline_ms = packet_in.time_last_baseline_ms; + packet1.tow = packet_in.tow; + packet1.baseline_a_mm = packet_in.baseline_a_mm; + packet1.baseline_b_mm = packet_in.baseline_b_mm; + packet1.baseline_c_mm = packet_in.baseline_c_mm; + packet1.accuracy = packet_in.accuracy; + packet1.iar_num_hypotheses = packet_in.iar_num_hypotheses; + packet1.wn = packet_in.wn; + packet1.rtk_receiver_id = packet_in.rtk_receiver_id; + packet1.rtk_health = packet_in.rtk_health; + packet1.rtk_rate = packet_in.rtk_rate; + packet1.nsats = packet_in.nsats; + packet1.baseline_coords_type = packet_in.baseline_coords_type; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS2_RTK_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps2_rtk_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps2_rtk_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps2_rtk_pack(system_id, component_id, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); + mavlink_msg_gps2_rtk_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_gps2_rtk_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); + mavlink_msg_gps2_rtk_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SCALED_IMU3 >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_scaled_imu3_t packet_in = { + 963497464,17443,17547,17651,17755,17859,17963,18067,18171,18275 + }; + mavlink_scaled_imu3_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.xacc = packet_in.xacc; + packet1.yacc = packet_in.yacc; + packet1.zacc = packet_in.zacc; + packet1.xgyro = packet_in.xgyro; + packet1.ygyro = packet_in.ygyro; + packet1.zgyro = packet_in.zgyro; + packet1.xmag = packet_in.xmag; + packet1.ymag = packet_in.ymag; + packet1.zmag = packet_in.zmag; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SCALED_IMU3_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_scaled_imu3_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_scaled_imu3_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_scaled_imu3_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_scaled_imu3_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_scaled_imu3_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); + mavlink_msg_scaled_imu3_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_data_transmission_handshake_t packet_in = { + 963497464,17443,17547,17651,163,230,41 + }; + mavlink_data_transmission_handshake_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.size = packet_in.size; + packet1.width = packet_in.width; + packet1.height = packet_in.height; + packet1.packets = packet_in.packets; + packet1.type = packet_in.type; + packet1.payload = packet_in.payload; + packet1.jpg_quality = packet_in.jpg_quality; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_data_transmission_handshake_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_data_transmission_handshake_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_data_transmission_handshake_pack(system_id, component_id, &msg , packet1.type , packet1.size , packet1.width , packet1.height , packet1.packets , packet1.payload , packet1.jpg_quality ); + mavlink_msg_data_transmission_handshake_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_data_transmission_handshake_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.size , packet1.width , packet1.height , packet1.packets , packet1.payload , packet1.jpg_quality ); + mavlink_msg_data_transmission_handshake_decode(&msg, &packet2); + MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); + + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_to_send_buffer(buffer, &msg); + for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ENCAPSULATED_DATA >= 256) { + return; + } +#endif + mavlink_message_t msg; + uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; + uint16_t i; + mavlink_encapsulated_data_t packet_in = { + 17235,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135 } + }; + mavlink_encapsulated_data_t packet1, packet2; + memset(&packet1, 0, sizeof(packet1)); + packet1.seqnr = packet_in.seqnr; + + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*253); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ENCAPSULATED_DATA_MIN_LEN); + } +#endif + memset(&packet2, 0, sizeof(packet2)); + mavlink_msg_encapsulated_data_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_encapsulated_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_timesync_pack(system_id, component_id, &msg , packet1.tc1 , packet1.ts1 ); - mavlink_msg_timesync_decode(&msg, &packet2); + mavlink_msg_encapsulated_data_pack(system_id, component_id, &msg , packet1.seqnr , packet1.data ); + mavlink_msg_encapsulated_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_timesync_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.tc1 , packet1.ts1 ); - mavlink_msg_timesync_decode(&msg, &packet2); + mavlink_msg_encapsulated_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.seqnr , packet1.data ); + mavlink_msg_encapsulated_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DISTANCE_SENSOR >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hil_gps_t packet_in = { - 93372036854775807ULL,963497880,963498088,963498296,18275,18379,18483,18587,18691,18795,18899,235,46 + mavlink_distance_sensor_t packet_in = { + 963497464,17443,17547,17651,163,230,41,108 }; - mavlink_hil_gps_t packet1, packet2; + mavlink_distance_sensor_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.eph = packet_in.eph; - packet1.epv = packet_in.epv; - packet1.vel = packet_in.vel; - packet1.vn = packet_in.vn; - packet1.ve = packet_in.ve; - packet1.vd = packet_in.vd; - packet1.cog = packet_in.cog; - packet1.fix_type = packet_in.fix_type; - packet1.satellites_visible = packet_in.satellites_visible; - - - + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.min_distance = packet_in.min_distance; + packet1.max_distance = packet_in.max_distance; + packet1.current_distance = packet_in.current_distance; + packet1.type = packet_in.type; + packet1.id = packet_in.id; + packet1.orientation = packet_in.orientation; + packet1.covariance = packet_in.covariance; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DISTANCE_SENSOR_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_gps_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hil_gps_decode(&msg, &packet2); + mavlink_msg_distance_sensor_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_distance_sensor_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_gps_pack(system_id, component_id, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.vn , packet1.ve , packet1.vd , packet1.cog , packet1.satellites_visible ); - mavlink_msg_hil_gps_decode(&msg, &packet2); + mavlink_msg_distance_sensor_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.min_distance , packet1.max_distance , packet1.current_distance , packet1.type , packet1.id , packet1.orientation , packet1.covariance ); + mavlink_msg_distance_sensor_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_gps_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.vn , packet1.ve , packet1.vd , packet1.cog , packet1.satellites_visible ); - mavlink_msg_hil_gps_decode(&msg, &packet2); + mavlink_msg_distance_sensor_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.min_distance , packet1.max_distance , packet1.current_distance , packet1.type , packet1.id , packet1.orientation , packet1.covariance ); + mavlink_msg_distance_sensor_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_TERRAIN_REQUEST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hil_optical_flow_t packet_in = { - 93372036854775807ULL,963497880,101.0,129.0,157.0,185.0,213.0,963499128,269.0,19315,3,70 + mavlink_terrain_request_t packet_in = { + 93372036854775807ULL,963497880,963498088,18067 }; - mavlink_hil_optical_flow_t packet1, packet2; + mavlink_terrain_request_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.integration_time_us = packet_in.integration_time_us; - packet1.integrated_x = packet_in.integrated_x; - packet1.integrated_y = packet_in.integrated_y; - packet1.integrated_xgyro = packet_in.integrated_xgyro; - packet1.integrated_ygyro = packet_in.integrated_ygyro; - packet1.integrated_zgyro = packet_in.integrated_zgyro; - packet1.time_delta_distance_us = packet_in.time_delta_distance_us; - packet1.distance = packet_in.distance; - packet1.temperature = packet_in.temperature; - packet1.sensor_id = packet_in.sensor_id; - packet1.quality = packet_in.quality; + packet1.mask = packet_in.mask; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.grid_spacing = packet_in.grid_spacing; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_TERRAIN_REQUEST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_optical_flow_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hil_optical_flow_decode(&msg, &packet2); + mavlink_msg_terrain_request_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_terrain_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_optical_flow_pack(system_id, component_id, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); - mavlink_msg_hil_optical_flow_decode(&msg, &packet2); + mavlink_msg_terrain_request_pack(system_id, component_id, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.mask ); + mavlink_msg_terrain_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_optical_flow_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.sensor_id , packet1.integration_time_us , packet1.integrated_x , packet1.integrated_y , packet1.integrated_xgyro , packet1.integrated_ygyro , packet1.integrated_zgyro , packet1.temperature , packet1.quality , packet1.time_delta_distance_us , packet1.distance ); - mavlink_msg_hil_optical_flow_decode(&msg, &packet2); + mavlink_msg_terrain_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.mask ); + mavlink_msg_terrain_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_TERRAIN_DATA >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_hil_state_quaternion_t packet_in = { - 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0 },185.0,213.0,241.0,963499336,963499544,963499752,19731,19835,19939,20043,20147,20251,20355,20459 + mavlink_terrain_data_t packet_in = { + 963497464,963497672,17651,{ 17755, 17756, 17757, 17758, 17759, 17760, 17761, 17762, 17763, 17764, 17765, 17766, 17767, 17768, 17769, 17770 },3 }; - mavlink_hil_state_quaternion_t packet1, packet2; + mavlink_terrain_data_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.rollspeed = packet_in.rollspeed; - packet1.pitchspeed = packet_in.pitchspeed; - packet1.yawspeed = packet_in.yawspeed; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.vx = packet_in.vx; - packet1.vy = packet_in.vy; - packet1.vz = packet_in.vz; - packet1.ind_airspeed = packet_in.ind_airspeed; - packet1.true_airspeed = packet_in.true_airspeed; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.grid_spacing = packet_in.grid_spacing; + packet1.gridbit = packet_in.gridbit; - mav_array_memcpy(packet1.attitude_quaternion, packet_in.attitude_quaternion, sizeof(float)*4); + mav_array_memcpy(packet1.data, packet_in.data, sizeof(int16_t)*16); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_TERRAIN_DATA_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_state_quaternion_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_hil_state_quaternion_decode(&msg, &packet2); + mavlink_msg_terrain_data_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_terrain_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_state_quaternion_pack(system_id, component_id, &msg , packet1.time_usec , packet1.attitude_quaternion , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.ind_airspeed , packet1.true_airspeed , packet1.xacc , packet1.yacc , packet1.zacc ); - mavlink_msg_hil_state_quaternion_decode(&msg, &packet2); + mavlink_msg_terrain_data_pack(system_id, component_id, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.gridbit , packet1.data ); + mavlink_msg_terrain_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_hil_state_quaternion_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.attitude_quaternion , packet1.rollspeed , packet1.pitchspeed , packet1.yawspeed , packet1.lat , packet1.lon , packet1.alt , packet1.vx , packet1.vy , packet1.vz , packet1.ind_airspeed , packet1.true_airspeed , packet1.xacc , packet1.yacc , packet1.zacc ); - mavlink_msg_hil_state_quaternion_decode(&msg, &packet2); + mavlink_msg_terrain_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.gridbit , packet1.data ); + mavlink_msg_terrain_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_TERRAIN_CHECK >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_scaled_imu2_t packet_in = { - 963497464,17443,17547,17651,17755,17859,17963,18067,18171,18275 + mavlink_terrain_check_t packet_in = { + 963497464,963497672 }; - mavlink_scaled_imu2_t packet1, packet2; + mavlink_terrain_check_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.xacc = packet_in.xacc; - packet1.yacc = packet_in.yacc; - packet1.zacc = packet_in.zacc; - packet1.xgyro = packet_in.xgyro; - packet1.ygyro = packet_in.ygyro; - packet1.zgyro = packet_in.zgyro; - packet1.xmag = packet_in.xmag; - packet1.ymag = packet_in.ymag; - packet1.zmag = packet_in.zmag; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_TERRAIN_CHECK_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_imu2_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_scaled_imu2_decode(&msg, &packet2); + mavlink_msg_terrain_check_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_terrain_check_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_imu2_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); - mavlink_msg_scaled_imu2_decode(&msg, &packet2); + mavlink_msg_terrain_check_pack(system_id, component_id, &msg , packet1.lat , packet1.lon ); + mavlink_msg_terrain_check_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_imu2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.xacc , packet1.yacc , packet1.zacc , packet1.xgyro , packet1.ygyro , packet1.zgyro , packet1.xmag , packet1.ymag , packet1.zmag ); - mavlink_msg_scaled_imu2_decode(&msg, &packet2); + mavlink_msg_terrain_check_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon ); + mavlink_msg_terrain_check_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_TERRAIN_REPORT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_log_request_list_t packet_in = { - 17235,17339,17,84 + mavlink_terrain_report_t packet_in = { + 963497464,963497672,73.0,101.0,18067,18171,18275 }; - mavlink_log_request_list_t packet1, packet2; + mavlink_terrain_report_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.start = packet_in.start; - packet1.end = packet_in.end; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - - - + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.terrain_height = packet_in.terrain_height; + packet1.current_height = packet_in.current_height; + packet1.spacing = packet_in.spacing; + packet1.pending = packet_in.pending; + packet1.loaded = packet_in.loaded; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_TERRAIN_REPORT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_list_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_log_request_list_decode(&msg, &packet2); + mavlink_msg_terrain_report_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_terrain_report_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_list_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.start , packet1.end ); - mavlink_msg_log_request_list_decode(&msg, &packet2); + mavlink_msg_terrain_report_pack(system_id, component_id, &msg , packet1.lat , packet1.lon , packet1.spacing , packet1.terrain_height , packet1.current_height , packet1.pending , packet1.loaded ); + mavlink_msg_terrain_report_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_list_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.start , packet1.end ); - mavlink_msg_log_request_list_decode(&msg, &packet2); + mavlink_msg_terrain_report_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon , packet1.spacing , packet1.terrain_height , packet1.current_height , packet1.pending , packet1.loaded ); + mavlink_msg_terrain_report_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SCALED_PRESSURE2 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_log_entry_t packet_in = { - 963497464,963497672,17651,17755,17859 + mavlink_scaled_pressure2_t packet_in = { + 963497464,45.0,73.0,17859 }; - mavlink_log_entry_t packet1, packet2; + mavlink_scaled_pressure2_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_utc = packet_in.time_utc; - packet1.size = packet_in.size; - packet1.id = packet_in.id; - packet1.num_logs = packet_in.num_logs; - packet1.last_log_num = packet_in.last_log_num; + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.press_abs = packet_in.press_abs; + packet1.press_diff = packet_in.press_diff; + packet1.temperature = packet_in.temperature; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SCALED_PRESSURE2_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_entry_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_log_entry_decode(&msg, &packet2); + mavlink_msg_scaled_pressure2_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_scaled_pressure2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_entry_pack(system_id, component_id, &msg , packet1.id , packet1.num_logs , packet1.last_log_num , packet1.time_utc , packet1.size ); - mavlink_msg_log_entry_decode(&msg, &packet2); + mavlink_msg_scaled_pressure2_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); + mavlink_msg_scaled_pressure2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_entry_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.id , packet1.num_logs , packet1.last_log_num , packet1.time_utc , packet1.size ); - mavlink_msg_log_entry_decode(&msg, &packet2); + mavlink_msg_scaled_pressure2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); + mavlink_msg_scaled_pressure2_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ATT_POS_MOCAP >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_log_request_data_t packet_in = { - 963497464,963497672,17651,163,230 + mavlink_att_pos_mocap_t packet_in = { + 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0 },185.0,213.0,241.0 }; - mavlink_log_request_data_t packet1, packet2; + mavlink_att_pos_mocap_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.ofs = packet_in.ofs; - packet1.count = packet_in.count; - packet1.id = packet_in.id; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.time_usec = packet_in.time_usec; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ATT_POS_MOCAP_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_data_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_log_request_data_decode(&msg, &packet2); + mavlink_msg_att_pos_mocap_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_att_pos_mocap_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_data_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.id , packet1.ofs , packet1.count ); - mavlink_msg_log_request_data_decode(&msg, &packet2); + mavlink_msg_att_pos_mocap_pack(system_id, component_id, &msg , packet1.time_usec , packet1.q , packet1.x , packet1.y , packet1.z ); + mavlink_msg_att_pos_mocap_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.id , packet1.ofs , packet1.count ); - mavlink_msg_log_request_data_decode(&msg, &packet2); + mavlink_msg_att_pos_mocap_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.q , packet1.x , packet1.y , packet1.z ); + mavlink_msg_att_pos_mocap_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_log_data_t packet_in = { - 963497464,17443,151,{ 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 } + mavlink_set_actuator_control_target_t packet_in = { + 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0 },125,192,3 }; - mavlink_log_data_t packet1, packet2; + mavlink_set_actuator_control_target_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.ofs = packet_in.ofs; - packet1.id = packet_in.id; - packet1.count = packet_in.count; + packet1.time_usec = packet_in.time_usec; + packet1.group_mlx = packet_in.group_mlx; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*90); + mav_array_memcpy(packet1.controls, packet_in.controls, sizeof(float)*8); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_ACTUATOR_CONTROL_TARGET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_data_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_log_data_decode(&msg, &packet2); + mavlink_msg_set_actuator_control_target_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_actuator_control_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_data_pack(system_id, component_id, &msg , packet1.id , packet1.ofs , packet1.count , packet1.data ); - mavlink_msg_log_data_decode(&msg, &packet2); + mavlink_msg_set_actuator_control_target_pack(system_id, component_id, &msg , packet1.time_usec , packet1.group_mlx , packet1.target_system , packet1.target_component , packet1.controls ); + mavlink_msg_set_actuator_control_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.id , packet1.ofs , packet1.count , packet1.data ); - mavlink_msg_log_data_decode(&msg, &packet2); + mavlink_msg_set_actuator_control_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.group_mlx , packet1.target_system , packet1.target_component , packet1.controls ); + mavlink_msg_set_actuator_control_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_log_erase_t packet_in = { - 5,72 + mavlink_actuator_control_target_t packet_in = { + 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0 },125 }; - mavlink_log_erase_t packet1, packet2; + mavlink_actuator_control_target_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.time_usec = packet_in.time_usec; + packet1.group_mlx = packet_in.group_mlx; + mav_array_memcpy(packet1.controls, packet_in.controls, sizeof(float)*8); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ACTUATOR_CONTROL_TARGET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_erase_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_log_erase_decode(&msg, &packet2); + mavlink_msg_actuator_control_target_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_actuator_control_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_erase_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_log_erase_decode(&msg, &packet2); + mavlink_msg_actuator_control_target_pack(system_id, component_id, &msg , packet1.time_usec , packet1.group_mlx , packet1.controls ); + mavlink_msg_actuator_control_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_erase_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_log_erase_decode(&msg, &packet2); + mavlink_msg_actuator_control_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.group_mlx , packet1.controls ); + mavlink_msg_actuator_control_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ALTITUDE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_log_request_end_t packet_in = { - 5,72 + mavlink_altitude_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0 }; - mavlink_log_request_end_t packet1, packet2; + mavlink_altitude_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - - - + packet1.time_usec = packet_in.time_usec; + packet1.altitude_monotonic = packet_in.altitude_monotonic; + packet1.altitude_amsl = packet_in.altitude_amsl; + packet1.altitude_local = packet_in.altitude_local; + packet1.altitude_relative = packet_in.altitude_relative; + packet1.altitude_terrain = packet_in.altitude_terrain; + packet1.bottom_clearance = packet_in.bottom_clearance; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ALTITUDE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ALTITUDE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_end_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_log_request_end_decode(&msg, &packet2); + mavlink_msg_altitude_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_altitude_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_end_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_log_request_end_decode(&msg, &packet2); + mavlink_msg_altitude_pack(system_id, component_id, &msg , packet1.time_usec , packet1.altitude_monotonic , packet1.altitude_amsl , packet1.altitude_local , packet1.altitude_relative , packet1.altitude_terrain , packet1.bottom_clearance ); + mavlink_msg_altitude_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_log_request_end_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component ); - mavlink_msg_log_request_end_decode(&msg, &packet2); + mavlink_msg_altitude_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.altitude_monotonic , packet1.altitude_amsl , packet1.altitude_local , packet1.altitude_relative , packet1.altitude_terrain , packet1.bottom_clearance ); + mavlink_msg_altitude_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_RESOURCE_REQUEST >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gps_inject_data_t packet_in = { - 5,72,139,{ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59 } + mavlink_resource_request_t packet_in = { + 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 1, 2 },243,{ 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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173 } }; - mavlink_gps_inject_data_t packet1, packet2; + mavlink_resource_request_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; - packet1.len = packet_in.len; + packet1.request_id = packet_in.request_id; + packet1.uri_type = packet_in.uri_type; + packet1.transfer_type = packet_in.transfer_type; - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*110); + mav_array_memcpy(packet1.uri, packet_in.uri, sizeof(uint8_t)*120); + mav_array_memcpy(packet1.storage, packet_in.storage, sizeof(uint8_t)*120); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_RESOURCE_REQUEST_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_inject_data_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gps_inject_data_decode(&msg, &packet2); + mavlink_msg_resource_request_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_resource_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_inject_data_pack(system_id, component_id, &msg , packet1.target_system , packet1.target_component , packet1.len , packet1.data ); - mavlink_msg_gps_inject_data_decode(&msg, &packet2); + mavlink_msg_resource_request_pack(system_id, component_id, &msg , packet1.request_id , packet1.uri_type , packet1.uri , packet1.transfer_type , packet1.storage ); + mavlink_msg_resource_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_inject_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.target_component , packet1.len , packet1.data ); - mavlink_msg_gps_inject_data_decode(&msg, &packet2); + mavlink_msg_resource_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.request_id , packet1.uri_type , packet1.uri , packet1.transfer_type , packet1.storage ); + mavlink_msg_resource_request_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SCALED_PRESSURE3 >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gps2_raw_t packet_in = { - 93372036854775807ULL,963497880,963498088,963498296,963498504,18483,18587,18691,18795,101,168,235 + mavlink_scaled_pressure3_t packet_in = { + 963497464,45.0,73.0,17859 }; - mavlink_gps2_raw_t packet1, packet2; + mavlink_scaled_pressure3_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.alt = packet_in.alt; - packet1.dgps_age = packet_in.dgps_age; - packet1.eph = packet_in.eph; - packet1.epv = packet_in.epv; - packet1.vel = packet_in.vel; - packet1.cog = packet_in.cog; - packet1.fix_type = packet_in.fix_type; - packet1.satellites_visible = packet_in.satellites_visible; - packet1.dgps_numch = packet_in.dgps_numch; + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.press_abs = packet_in.press_abs; + packet1.press_diff = packet_in.press_diff; + packet1.temperature = packet_in.temperature; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SCALED_PRESSURE3_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps2_raw_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gps2_raw_decode(&msg, &packet2); + mavlink_msg_scaled_pressure3_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_scaled_pressure3_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps2_raw_pack(system_id, component_id, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible , packet1.dgps_numch , packet1.dgps_age ); - mavlink_msg_gps2_raw_decode(&msg, &packet2); + mavlink_msg_scaled_pressure3_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); + mavlink_msg_scaled_pressure3_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps2_raw_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.eph , packet1.epv , packet1.vel , packet1.cog , packet1.satellites_visible , packet1.dgps_numch , packet1.dgps_age ); - mavlink_msg_gps2_raw_decode(&msg, &packet2); + mavlink_msg_scaled_pressure3_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); + mavlink_msg_scaled_pressure3_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_FOLLOW_TARGET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_power_status_t packet_in = { - 17235,17339,17443 + mavlink_follow_target_t packet_in = { + 93372036854775807ULL,93372036854776311ULL,963498296,963498504,185.0,{ 213.0, 214.0, 215.0 },{ 297.0, 298.0, 299.0 },{ 381.0, 382.0, 383.0, 384.0 },{ 493.0, 494.0, 495.0 },{ 577.0, 578.0, 579.0 },25 }; - mavlink_power_status_t packet1, packet2; + mavlink_follow_target_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.Vcc = packet_in.Vcc; - packet1.Vservo = packet_in.Vservo; - packet1.flags = packet_in.flags; - - - + packet1.timestamp = packet_in.timestamp; + packet1.custom_state = packet_in.custom_state; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.est_capabilities = packet_in.est_capabilities; + + mav_array_memcpy(packet1.vel, packet_in.vel, sizeof(float)*3); + mav_array_memcpy(packet1.acc, packet_in.acc, sizeof(float)*3); + mav_array_memcpy(packet1.attitude_q, packet_in.attitude_q, sizeof(float)*4); + mav_array_memcpy(packet1.rates, packet_in.rates, sizeof(float)*3); + mav_array_memcpy(packet1.position_cov, packet_in.position_cov, sizeof(float)*3); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_FOLLOW_TARGET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_power_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_power_status_decode(&msg, &packet2); + mavlink_msg_follow_target_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_follow_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_power_status_pack(system_id, component_id, &msg , packet1.Vcc , packet1.Vservo , packet1.flags ); - mavlink_msg_power_status_decode(&msg, &packet2); + mavlink_msg_follow_target_pack(system_id, component_id, &msg , packet1.timestamp , packet1.est_capabilities , packet1.lat , packet1.lon , packet1.alt , packet1.vel , packet1.acc , packet1.attitude_q , packet1.rates , packet1.position_cov , packet1.custom_state ); + mavlink_msg_follow_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_power_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.Vcc , packet1.Vservo , packet1.flags ); - mavlink_msg_power_status_decode(&msg, &packet2); + mavlink_msg_follow_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.timestamp , packet1.est_capabilities , packet1.lat , packet1.lon , packet1.alt , packet1.vel , packet1.acc , packet1.attitude_q , packet1.rates , packet1.position_cov , packet1.custom_state ); + mavlink_msg_follow_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_serial_control_t packet_in = { - 963497464,17443,151,218,29,{ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165 } + mavlink_control_system_state_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,297.0,325.0,{ 353.0, 354.0, 355.0 },{ 437.0, 438.0, 439.0 },{ 521.0, 522.0, 523.0, 524.0 },633.0,661.0,689.0 }; - mavlink_serial_control_t packet1, packet2; + mavlink_control_system_state_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.baudrate = packet_in.baudrate; - packet1.timeout = packet_in.timeout; - packet1.device = packet_in.device; - packet1.flags = packet_in.flags; - packet1.count = packet_in.count; - - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*70); - - + packet1.time_usec = packet_in.time_usec; + packet1.x_acc = packet_in.x_acc; + packet1.y_acc = packet_in.y_acc; + packet1.z_acc = packet_in.z_acc; + packet1.x_vel = packet_in.x_vel; + packet1.y_vel = packet_in.y_vel; + packet1.z_vel = packet_in.z_vel; + packet1.x_pos = packet_in.x_pos; + packet1.y_pos = packet_in.y_pos; + packet1.z_pos = packet_in.z_pos; + packet1.airspeed = packet_in.airspeed; + packet1.roll_rate = packet_in.roll_rate; + packet1.pitch_rate = packet_in.pitch_rate; + packet1.yaw_rate = packet_in.yaw_rate; + + mav_array_memcpy(packet1.vel_variance, packet_in.vel_variance, sizeof(float)*3); + mav_array_memcpy(packet1.pos_variance, packet_in.pos_variance, sizeof(float)*3); + mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_CONTROL_SYSTEM_STATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_serial_control_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_serial_control_decode(&msg, &packet2); + mavlink_msg_control_system_state_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_control_system_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_serial_control_pack(system_id, component_id, &msg , packet1.device , packet1.flags , packet1.timeout , packet1.baudrate , packet1.count , packet1.data ); - mavlink_msg_serial_control_decode(&msg, &packet2); + mavlink_msg_control_system_state_pack(system_id, component_id, &msg , packet1.time_usec , packet1.x_acc , packet1.y_acc , packet1.z_acc , packet1.x_vel , packet1.y_vel , packet1.z_vel , packet1.x_pos , packet1.y_pos , packet1.z_pos , packet1.airspeed , packet1.vel_variance , packet1.pos_variance , packet1.q , packet1.roll_rate , packet1.pitch_rate , packet1.yaw_rate ); + mavlink_msg_control_system_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_serial_control_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.device , packet1.flags , packet1.timeout , packet1.baudrate , packet1.count , packet1.data ); - mavlink_msg_serial_control_decode(&msg, &packet2); + mavlink_msg_control_system_state_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.x_acc , packet1.y_acc , packet1.z_acc , packet1.x_vel , packet1.y_vel , packet1.z_vel , packet1.x_pos , packet1.y_pos , packet1.z_pos , packet1.airspeed , packet1.vel_variance , packet1.pos_variance , packet1.q , packet1.roll_rate , packet1.pitch_rate , packet1.yaw_rate ); + mavlink_msg_control_system_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_BATTERY_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gps_rtk_t packet_in = { - 963497464,963497672,963497880,963498088,963498296,963498504,963498712,18691,223,34,101,168,235 + mavlink_battery_status_t packet_in = { + 963497464,963497672,17651,{ 17755, 17756, 17757, 17758, 17759, 17760, 17761, 17762, 17763, 17764 },18795,101,168,235,46 }; - mavlink_gps_rtk_t packet1, packet2; + mavlink_battery_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_last_baseline_ms = packet_in.time_last_baseline_ms; - packet1.tow = packet_in.tow; - packet1.baseline_a_mm = packet_in.baseline_a_mm; - packet1.baseline_b_mm = packet_in.baseline_b_mm; - packet1.baseline_c_mm = packet_in.baseline_c_mm; - packet1.accuracy = packet_in.accuracy; - packet1.iar_num_hypotheses = packet_in.iar_num_hypotheses; - packet1.wn = packet_in.wn; - packet1.rtk_receiver_id = packet_in.rtk_receiver_id; - packet1.rtk_health = packet_in.rtk_health; - packet1.rtk_rate = packet_in.rtk_rate; - packet1.nsats = packet_in.nsats; - packet1.baseline_coords_type = packet_in.baseline_coords_type; - - - + packet1.current_consumed = packet_in.current_consumed; + packet1.energy_consumed = packet_in.energy_consumed; + packet1.temperature = packet_in.temperature; + packet1.current_battery = packet_in.current_battery; + packet1.id = packet_in.id; + packet1.battery_function = packet_in.battery_function; + packet1.type = packet_in.type; + packet1.battery_remaining = packet_in.battery_remaining; + + mav_array_memcpy(packet1.voltages, packet_in.voltages, sizeof(uint16_t)*10); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_BATTERY_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_rtk_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gps_rtk_decode(&msg, &packet2); + mavlink_msg_battery_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_battery_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_rtk_pack(system_id, component_id, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); - mavlink_msg_gps_rtk_decode(&msg, &packet2); + mavlink_msg_battery_status_pack(system_id, component_id, &msg , packet1.id , packet1.battery_function , packet1.type , packet1.temperature , packet1.voltages , packet1.current_battery , packet1.current_consumed , packet1.energy_consumed , packet1.battery_remaining ); + mavlink_msg_battery_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps_rtk_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); - mavlink_msg_gps_rtk_decode(&msg, &packet2); + mavlink_msg_battery_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.id , packet1.battery_function , packet1.type , packet1.temperature , packet1.voltages , packet1.current_battery , packet1.current_consumed , packet1.energy_consumed , packet1.battery_remaining ); + mavlink_msg_battery_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_AUTOPILOT_VERSION >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_gps2_rtk_t packet_in = { - 963497464,963497672,963497880,963498088,963498296,963498504,963498712,18691,223,34,101,168,235 + mavlink_autopilot_version_t packet_in = { + 93372036854775807ULL,93372036854776311ULL,963498296,963498504,963498712,963498920,18899,19003,{ 113, 114, 115, 116, 117, 118, 119, 120 },{ 137, 138, 139, 140, 141, 142, 143, 144 },{ 161, 162, 163, 164, 165, 166, 167, 168 } }; - mavlink_gps2_rtk_t packet1, packet2; + mavlink_autopilot_version_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_last_baseline_ms = packet_in.time_last_baseline_ms; - packet1.tow = packet_in.tow; - packet1.baseline_a_mm = packet_in.baseline_a_mm; - packet1.baseline_b_mm = packet_in.baseline_b_mm; - packet1.baseline_c_mm = packet_in.baseline_c_mm; - packet1.accuracy = packet_in.accuracy; - packet1.iar_num_hypotheses = packet_in.iar_num_hypotheses; - packet1.wn = packet_in.wn; - packet1.rtk_receiver_id = packet_in.rtk_receiver_id; - packet1.rtk_health = packet_in.rtk_health; - packet1.rtk_rate = packet_in.rtk_rate; - packet1.nsats = packet_in.nsats; - packet1.baseline_coords_type = packet_in.baseline_coords_type; - - - + packet1.capabilities = packet_in.capabilities; + packet1.uid = packet_in.uid; + packet1.flight_sw_version = packet_in.flight_sw_version; + packet1.middleware_sw_version = packet_in.middleware_sw_version; + packet1.os_sw_version = packet_in.os_sw_version; + packet1.board_version = packet_in.board_version; + packet1.vendor_id = packet_in.vendor_id; + packet1.product_id = packet_in.product_id; + + mav_array_memcpy(packet1.flight_custom_version, packet_in.flight_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet1.middleware_custom_version, packet_in.middleware_custom_version, sizeof(uint8_t)*8); + mav_array_memcpy(packet1.os_custom_version, packet_in.os_custom_version, sizeof(uint8_t)*8); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_AUTOPILOT_VERSION_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps2_rtk_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_gps2_rtk_decode(&msg, &packet2); + mavlink_msg_autopilot_version_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_autopilot_version_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps2_rtk_pack(system_id, component_id, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); - mavlink_msg_gps2_rtk_decode(&msg, &packet2); + mavlink_msg_autopilot_version_pack(system_id, component_id, &msg , packet1.capabilities , packet1.flight_sw_version , packet1.middleware_sw_version , packet1.os_sw_version , packet1.board_version , packet1.flight_custom_version , packet1.middleware_custom_version , packet1.os_custom_version , packet1.vendor_id , packet1.product_id , packet1.uid ); + mavlink_msg_autopilot_version_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_gps2_rtk_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_last_baseline_ms , packet1.rtk_receiver_id , packet1.wn , packet1.tow , packet1.rtk_health , packet1.rtk_rate , packet1.nsats , packet1.baseline_coords_type , packet1.baseline_a_mm , packet1.baseline_b_mm , packet1.baseline_c_mm , packet1.accuracy , packet1.iar_num_hypotheses ); - mavlink_msg_gps2_rtk_decode(&msg, &packet2); + mavlink_msg_autopilot_version_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.capabilities , packet1.flight_sw_version , packet1.middleware_sw_version , packet1.os_sw_version , packet1.board_version , packet1.flight_custom_version , packet1.middleware_custom_version , packet1.os_custom_version , packet1.vendor_id , packet1.product_id , packet1.uid ); + mavlink_msg_autopilot_version_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_LANDING_TARGET >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_data_transmission_handshake_t packet_in = { - 963497464,17443,17547,17651,163,230,41 + mavlink_landing_target_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,89,156 }; - mavlink_data_transmission_handshake_t packet1, packet2; + mavlink_landing_target_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.size = packet_in.size; - packet1.width = packet_in.width; - packet1.height = packet_in.height; - packet1.packets = packet_in.packets; - packet1.type = packet_in.type; - packet1.payload = packet_in.payload; - packet1.jpg_quality = packet_in.jpg_quality; - - - + packet1.time_usec = packet_in.time_usec; + packet1.angle_x = packet_in.angle_x; + packet1.angle_y = packet_in.angle_y; + packet1.distance = packet_in.distance; + packet1.size_x = packet_in.size_x; + packet1.size_y = packet_in.size_y; + packet1.target_num = packet_in.target_num; + packet1.frame = packet_in.frame; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_LANDING_TARGET_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data_transmission_handshake_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_data_transmission_handshake_decode(&msg, &packet2); + mavlink_msg_landing_target_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_landing_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data_transmission_handshake_pack(system_id, component_id, &msg , packet1.type , packet1.size , packet1.width , packet1.height , packet1.packets , packet1.payload , packet1.jpg_quality ); - mavlink_msg_data_transmission_handshake_decode(&msg, &packet2); + mavlink_msg_landing_target_pack(system_id, component_id, &msg , packet1.time_usec , packet1.target_num , packet1.frame , packet1.angle_x , packet1.angle_y , packet1.distance , packet1.size_x , packet1.size_y ); + mavlink_msg_landing_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_data_transmission_handshake_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.type , packet1.size , packet1.width , packet1.height , packet1.packets , packet1.payload , packet1.jpg_quality ); - mavlink_msg_data_transmission_handshake_decode(&msg, &packet2); + mavlink_msg_landing_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.target_num , packet1.frame , packet1.angle_x , packet1.angle_y , packet1.distance , packet1.size_x , packet1.size_y ); + mavlink_msg_landing_target_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ESTIMATOR_STATUS >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_encapsulated_data_t packet_in = { - 17235,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135 } + mavlink_estimator_status_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0,19315 }; - mavlink_encapsulated_data_t packet1, packet2; + mavlink_estimator_status_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.seqnr = packet_in.seqnr; - - mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*253); - - + packet1.time_usec = packet_in.time_usec; + packet1.vel_ratio = packet_in.vel_ratio; + packet1.pos_horiz_ratio = packet_in.pos_horiz_ratio; + packet1.pos_vert_ratio = packet_in.pos_vert_ratio; + packet1.mag_ratio = packet_in.mag_ratio; + packet1.hagl_ratio = packet_in.hagl_ratio; + packet1.tas_ratio = packet_in.tas_ratio; + packet1.pos_horiz_accuracy = packet_in.pos_horiz_accuracy; + packet1.pos_vert_accuracy = packet_in.pos_vert_accuracy; + packet1.flags = packet_in.flags; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ESTIMATOR_STATUS_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_encapsulated_data_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_encapsulated_data_decode(&msg, &packet2); + mavlink_msg_estimator_status_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_estimator_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_encapsulated_data_pack(system_id, component_id, &msg , packet1.seqnr , packet1.data ); - mavlink_msg_encapsulated_data_decode(&msg, &packet2); + mavlink_msg_estimator_status_pack(system_id, component_id, &msg , packet1.time_usec , packet1.flags , packet1.vel_ratio , packet1.pos_horiz_ratio , packet1.pos_vert_ratio , packet1.mag_ratio , packet1.hagl_ratio , packet1.tas_ratio , packet1.pos_horiz_accuracy , packet1.pos_vert_accuracy ); + mavlink_msg_estimator_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_encapsulated_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.seqnr , packet1.data ); - mavlink_msg_encapsulated_data_decode(&msg, &packet2); + mavlink_msg_estimator_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.flags , packet1.vel_ratio , packet1.pos_horiz_ratio , packet1.pos_vert_ratio , packet1.mag_ratio , packet1.hagl_ratio , packet1.tas_ratio , packet1.pos_horiz_accuracy , packet1.pos_vert_accuracy ); + mavlink_msg_estimator_status_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_WIND_COV >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_distance_sensor_t packet_in = { - 963497464,17443,17547,17651,163,230,41,108 + mavlink_wind_cov_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,157.0,185.0,213.0,241.0,269.0 }; - mavlink_distance_sensor_t packet1, packet2; + mavlink_wind_cov_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.min_distance = packet_in.min_distance; - packet1.max_distance = packet_in.max_distance; - packet1.current_distance = packet_in.current_distance; - packet1.type = packet_in.type; - packet1.id = packet_in.id; - packet1.orientation = packet_in.orientation; - packet1.covariance = packet_in.covariance; - - - + packet1.time_usec = packet_in.time_usec; + packet1.wind_x = packet_in.wind_x; + packet1.wind_y = packet_in.wind_y; + packet1.wind_z = packet_in.wind_z; + packet1.var_horiz = packet_in.var_horiz; + packet1.var_vert = packet_in.var_vert; + packet1.wind_alt = packet_in.wind_alt; + packet1.horiz_accuracy = packet_in.horiz_accuracy; + packet1.vert_accuracy = packet_in.vert_accuracy; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_WIND_COV_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_WIND_COV_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_distance_sensor_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_distance_sensor_decode(&msg, &packet2); + mavlink_msg_wind_cov_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_wind_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_distance_sensor_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.min_distance , packet1.max_distance , packet1.current_distance , packet1.type , packet1.id , packet1.orientation , packet1.covariance ); - mavlink_msg_distance_sensor_decode(&msg, &packet2); + mavlink_msg_wind_cov_pack(system_id, component_id, &msg , packet1.time_usec , packet1.wind_x , packet1.wind_y , packet1.wind_z , packet1.var_horiz , packet1.var_vert , packet1.wind_alt , packet1.horiz_accuracy , packet1.vert_accuracy ); + mavlink_msg_wind_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_distance_sensor_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.min_distance , packet1.max_distance , packet1.current_distance , packet1.type , packet1.id , packet1.orientation , packet1.covariance ); - mavlink_msg_distance_sensor_decode(&msg, &packet2); + mavlink_msg_wind_cov_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.wind_x , packet1.wind_y , packet1.wind_z , packet1.var_horiz , packet1.var_vert , packet1.wind_alt , packet1.horiz_accuracy , packet1.vert_accuracy ); + mavlink_msg_wind_cov_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS_INPUT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_terrain_request_t packet_in = { - 93372036854775807ULL,963497880,963498088,18067 + mavlink_gps_input_t packet_in = { + 93372036854775807ULL,963497880,963498088,963498296,157.0,185.0,213.0,241.0,269.0,297.0,325.0,353.0,381.0,20147,20251,185,252,63 }; - mavlink_terrain_request_t packet1, packet2; + mavlink_gps_input_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.mask = packet_in.mask; - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.grid_spacing = packet_in.grid_spacing; - - - + packet1.time_usec = packet_in.time_usec; + packet1.time_week_ms = packet_in.time_week_ms; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.alt = packet_in.alt; + packet1.hdop = packet_in.hdop; + packet1.vdop = packet_in.vdop; + packet1.vn = packet_in.vn; + packet1.ve = packet_in.ve; + packet1.vd = packet_in.vd; + packet1.speed_accuracy = packet_in.speed_accuracy; + packet1.horiz_accuracy = packet_in.horiz_accuracy; + packet1.vert_accuracy = packet_in.vert_accuracy; + packet1.ignore_flags = packet_in.ignore_flags; + packet1.time_week = packet_in.time_week; + packet1.gps_id = packet_in.gps_id; + packet1.fix_type = packet_in.fix_type; + packet1.satellites_visible = packet_in.satellites_visible; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS_INPUT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_request_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_terrain_request_decode(&msg, &packet2); + mavlink_msg_gps_input_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps_input_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_request_pack(system_id, component_id, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.mask ); - mavlink_msg_terrain_request_decode(&msg, &packet2); + mavlink_msg_gps_input_pack(system_id, component_id, &msg , packet1.time_usec , packet1.gps_id , packet1.ignore_flags , packet1.time_week_ms , packet1.time_week , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.hdop , packet1.vdop , packet1.vn , packet1.ve , packet1.vd , packet1.speed_accuracy , packet1.horiz_accuracy , packet1.vert_accuracy , packet1.satellites_visible ); + mavlink_msg_gps_input_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_request_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.mask ); - mavlink_msg_terrain_request_decode(&msg, &packet2); + mavlink_msg_gps_input_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.gps_id , packet1.ignore_flags , packet1.time_week_ms , packet1.time_week , packet1.fix_type , packet1.lat , packet1.lon , packet1.alt , packet1.hdop , packet1.vdop , packet1.vn , packet1.ve , packet1.vd , packet1.speed_accuracy , packet1.horiz_accuracy , packet1.vert_accuracy , packet1.satellites_visible ); + mavlink_msg_gps_input_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_GPS_RTCM_DATA >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_terrain_data_t packet_in = { - 963497464,963497672,17651,{ 17755, 17756, 17757, 17758, 17759, 17760, 17761, 17762, 17763, 17764, 17765, 17766, 17767, 17768, 17769, 17770 },3 + mavlink_gps_rtcm_data_t packet_in = { + 5,72,{ 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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 } }; - mavlink_terrain_data_t packet1, packet2; + mavlink_gps_rtcm_data_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.grid_spacing = packet_in.grid_spacing; - packet1.gridbit = packet_in.gridbit; + packet1.flags = packet_in.flags; + packet1.len = packet_in.len; - mav_array_memcpy(packet1.data, packet_in.data, sizeof(int16_t)*16); + mav_array_memcpy(packet1.data, packet_in.data, sizeof(uint8_t)*180); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_GPS_RTCM_DATA_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_data_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_terrain_data_decode(&msg, &packet2); + mavlink_msg_gps_rtcm_data_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_gps_rtcm_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_data_pack(system_id, component_id, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.gridbit , packet1.data ); - mavlink_msg_terrain_data_decode(&msg, &packet2); + mavlink_msg_gps_rtcm_data_pack(system_id, component_id, &msg , packet1.flags , packet1.len , packet1.data ); + mavlink_msg_gps_rtcm_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon , packet1.grid_spacing , packet1.gridbit , packet1.data ); - mavlink_msg_terrain_data_decode(&msg, &packet2); + mavlink_msg_gps_rtcm_data_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.flags , packet1.len , packet1.data ); + mavlink_msg_gps_rtcm_data_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HIGH_LATENCY >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_terrain_check_t packet_in = { - 963497464,963497672 + mavlink_high_latency_t packet_in = { + 963497464,963497672,963497880,17859,17963,18067,18171,18275,18379,18483,211,22,89,156,223,34,101,168,235,46,113,180,247,58 }; - mavlink_terrain_check_t packet1, packet2; + mavlink_high_latency_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - - - + packet1.custom_mode = packet_in.custom_mode; + packet1.latitude = packet_in.latitude; + packet1.longitude = packet_in.longitude; + packet1.roll = packet_in.roll; + packet1.pitch = packet_in.pitch; + packet1.heading = packet_in.heading; + packet1.heading_sp = packet_in.heading_sp; + packet1.altitude_amsl = packet_in.altitude_amsl; + packet1.altitude_sp = packet_in.altitude_sp; + packet1.wp_distance = packet_in.wp_distance; + packet1.base_mode = packet_in.base_mode; + packet1.landed_state = packet_in.landed_state; + packet1.throttle = packet_in.throttle; + packet1.airspeed = packet_in.airspeed; + packet1.airspeed_sp = packet_in.airspeed_sp; + packet1.groundspeed = packet_in.groundspeed; + packet1.climb_rate = packet_in.climb_rate; + packet1.gps_nsat = packet_in.gps_nsat; + packet1.gps_fix_type = packet_in.gps_fix_type; + packet1.battery_remaining = packet_in.battery_remaining; + packet1.temperature = packet_in.temperature; + packet1.temperature_air = packet_in.temperature_air; + packet1.failsafe = packet_in.failsafe; + packet1.wp_num = packet_in.wp_num; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HIGH_LATENCY_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_check_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_terrain_check_decode(&msg, &packet2); + mavlink_msg_high_latency_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_high_latency_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_check_pack(system_id, component_id, &msg , packet1.lat , packet1.lon ); - mavlink_msg_terrain_check_decode(&msg, &packet2); + mavlink_msg_high_latency_pack(system_id, component_id, &msg , packet1.base_mode , packet1.custom_mode , packet1.landed_state , packet1.roll , packet1.pitch , packet1.heading , packet1.throttle , packet1.heading_sp , packet1.latitude , packet1.longitude , packet1.altitude_amsl , packet1.altitude_sp , packet1.airspeed , packet1.airspeed_sp , packet1.groundspeed , packet1.climb_rate , packet1.gps_nsat , packet1.gps_fix_type , packet1.battery_remaining , packet1.temperature , packet1.temperature_air , packet1.failsafe , packet1.wp_num , packet1.wp_distance ); + mavlink_msg_high_latency_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_check_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon ); - mavlink_msg_terrain_check_decode(&msg, &packet2); + mavlink_msg_high_latency_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.base_mode , packet1.custom_mode , packet1.landed_state , packet1.roll , packet1.pitch , packet1.heading , packet1.throttle , packet1.heading_sp , packet1.latitude , packet1.longitude , packet1.altitude_amsl , packet1.altitude_sp , packet1.airspeed , packet1.airspeed_sp , packet1.groundspeed , packet1.climb_rate , packet1.gps_nsat , packet1.gps_fix_type , packet1.battery_remaining , packet1.temperature , packet1.temperature_air , packet1.failsafe , packet1.wp_num , packet1.wp_distance ); + mavlink_msg_high_latency_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_VIBRATION >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_terrain_report_t packet_in = { - 963497464,963497672,73.0,101.0,18067,18171,18275 + mavlink_vibration_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,963498504,963498712,963498920 }; - mavlink_terrain_report_t packet1, packet2; + mavlink_vibration_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.lat = packet_in.lat; - packet1.lon = packet_in.lon; - packet1.terrain_height = packet_in.terrain_height; - packet1.current_height = packet_in.current_height; - packet1.spacing = packet_in.spacing; - packet1.pending = packet_in.pending; - packet1.loaded = packet_in.loaded; - - - + packet1.time_usec = packet_in.time_usec; + packet1.vibration_x = packet_in.vibration_x; + packet1.vibration_y = packet_in.vibration_y; + packet1.vibration_z = packet_in.vibration_z; + packet1.clipping_0 = packet_in.clipping_0; + packet1.clipping_1 = packet_in.clipping_1; + packet1.clipping_2 = packet_in.clipping_2; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_VIBRATION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_VIBRATION_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_report_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_terrain_report_decode(&msg, &packet2); + mavlink_msg_vibration_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_vibration_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_report_pack(system_id, component_id, &msg , packet1.lat , packet1.lon , packet1.spacing , packet1.terrain_height , packet1.current_height , packet1.pending , packet1.loaded ); - mavlink_msg_terrain_report_decode(&msg, &packet2); + mavlink_msg_vibration_pack(system_id, component_id, &msg , packet1.time_usec , packet1.vibration_x , packet1.vibration_y , packet1.vibration_z , packet1.clipping_0 , packet1.clipping_1 , packet1.clipping_2 ); + mavlink_msg_vibration_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_terrain_report_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.lat , packet1.lon , packet1.spacing , packet1.terrain_height , packet1.current_height , packet1.pending , packet1.loaded ); - mavlink_msg_terrain_report_decode(&msg, &packet2); + mavlink_msg_vibration_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.vibration_x , packet1.vibration_y , packet1.vibration_z , packet1.clipping_0 , packet1.clipping_1 , packet1.clipping_2 ); + mavlink_msg_vibration_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_HOME_POSITION >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_scaled_pressure2_t packet_in = { - 963497464,45.0,73.0,17859 + mavlink_home_position_t packet_in = { + 963497464,963497672,963497880,101.0,129.0,157.0,{ 185.0, 186.0, 187.0, 188.0 },297.0,325.0,353.0 }; - mavlink_scaled_pressure2_t packet1, packet2; + mavlink_home_position_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.press_abs = packet_in.press_abs; - packet1.press_diff = packet_in.press_diff; - packet1.temperature = packet_in.temperature; - - - + packet1.latitude = packet_in.latitude; + packet1.longitude = packet_in.longitude; + packet1.altitude = packet_in.altitude; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.approach_x = packet_in.approach_x; + packet1.approach_y = packet_in.approach_y; + packet1.approach_z = packet_in.approach_z; + + mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_HOME_POSITION_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_pressure2_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_scaled_pressure2_decode(&msg, &packet2); + mavlink_msg_home_position_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_home_position_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_pressure2_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); - mavlink_msg_scaled_pressure2_decode(&msg, &packet2); + mavlink_msg_home_position_pack(system_id, component_id, &msg , packet1.latitude , packet1.longitude , packet1.altitude , packet1.x , packet1.y , packet1.z , packet1.q , packet1.approach_x , packet1.approach_y , packet1.approach_z ); + mavlink_msg_home_position_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_scaled_pressure2_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.press_abs , packet1.press_diff , packet1.temperature ); - mavlink_msg_scaled_pressure2_decode(&msg, &packet2); + mavlink_msg_home_position_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.latitude , packet1.longitude , packet1.altitude , packet1.x , packet1.y , packet1.z , packet1.q , packet1.approach_x , packet1.approach_y , packet1.approach_z ); + mavlink_msg_home_position_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_SET_HOME_POSITION >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_att_pos_mocap_t packet_in = { - 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0 },185.0,213.0,241.0 + mavlink_set_home_position_t packet_in = { + 963497464,963497672,963497880,101.0,129.0,157.0,{ 185.0, 186.0, 187.0, 188.0 },297.0,325.0,353.0,161 }; - mavlink_att_pos_mocap_t packet1, packet2; + mavlink_set_home_position_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; - - mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); - - + packet1.latitude = packet_in.latitude; + packet1.longitude = packet_in.longitude; + packet1.altitude = packet_in.altitude; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; + packet1.approach_x = packet_in.approach_x; + packet1.approach_y = packet_in.approach_y; + packet1.approach_z = packet_in.approach_z; + packet1.target_system = packet_in.target_system; + + mav_array_memcpy(packet1.q, packet_in.q, sizeof(float)*4); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_SET_HOME_POSITION_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_att_pos_mocap_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_att_pos_mocap_decode(&msg, &packet2); + mavlink_msg_set_home_position_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_set_home_position_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_att_pos_mocap_pack(system_id, component_id, &msg , packet1.time_usec , packet1.q , packet1.x , packet1.y , packet1.z ); - mavlink_msg_att_pos_mocap_decode(&msg, &packet2); + mavlink_msg_set_home_position_pack(system_id, component_id, &msg , packet1.target_system , packet1.latitude , packet1.longitude , packet1.altitude , packet1.x , packet1.y , packet1.z , packet1.q , packet1.approach_x , packet1.approach_y , packet1.approach_z ); + mavlink_msg_set_home_position_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_att_pos_mocap_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.q , packet1.x , packet1.y , packet1.z ); - mavlink_msg_att_pos_mocap_decode(&msg, &packet2); + mavlink_msg_set_home_position_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_system , packet1.latitude , packet1.longitude , packet1.altitude , packet1.x , packet1.y , packet1.z , packet1.q , packet1.approach_x , packet1.approach_y , packet1.approach_z ); + mavlink_msg_set_home_position_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MESSAGE_INTERVAL >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_set_actuator_control_target_t packet_in = { - 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0 },125,192,3 + mavlink_message_interval_t packet_in = { + 963497464,17443 }; - mavlink_set_actuator_control_target_t packet1, packet2; + mavlink_message_interval_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.group_mlx = packet_in.group_mlx; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.interval_us = packet_in.interval_us; + packet1.message_id = packet_in.message_id; - mav_array_memcpy(packet1.controls, packet_in.controls, sizeof(float)*8); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MESSAGE_INTERVAL_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_actuator_control_target_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_set_actuator_control_target_decode(&msg, &packet2); + mavlink_msg_message_interval_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_message_interval_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_actuator_control_target_pack(system_id, component_id, &msg , packet1.time_usec , packet1.group_mlx , packet1.target_system , packet1.target_component , packet1.controls ); - mavlink_msg_set_actuator_control_target_decode(&msg, &packet2); + mavlink_msg_message_interval_pack(system_id, component_id, &msg , packet1.message_id , packet1.interval_us ); + mavlink_msg_message_interval_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_set_actuator_control_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.group_mlx , packet1.target_system , packet1.target_component , packet1.controls ); - mavlink_msg_set_actuator_control_target_decode(&msg, &packet2); + mavlink_msg_message_interval_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.message_id , packet1.interval_us ); + mavlink_msg_message_interval_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_EXTENDED_SYS_STATE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_actuator_control_target_t packet_in = { - 93372036854775807ULL,{ 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, 80.0 },125 + mavlink_extended_sys_state_t packet_in = { + 5,72 }; - mavlink_actuator_control_target_t packet1, packet2; + mavlink_extended_sys_state_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.group_mlx = packet_in.group_mlx; + packet1.vtol_state = packet_in.vtol_state; + packet1.landed_state = packet_in.landed_state; - mav_array_memcpy(packet1.controls, packet_in.controls, sizeof(float)*8); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_EXTENDED_SYS_STATE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_actuator_control_target_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_actuator_control_target_decode(&msg, &packet2); + mavlink_msg_extended_sys_state_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_extended_sys_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_actuator_control_target_pack(system_id, component_id, &msg , packet1.time_usec , packet1.group_mlx , packet1.controls ); - mavlink_msg_actuator_control_target_decode(&msg, &packet2); + mavlink_msg_extended_sys_state_pack(system_id, component_id, &msg , packet1.vtol_state , packet1.landed_state ); + mavlink_msg_extended_sys_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_actuator_control_target_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_usec , packet1.group_mlx , packet1.controls ); - mavlink_msg_actuator_control_target_decode(&msg, &packet2); + mavlink_msg_extended_sys_state_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.vtol_state , packet1.landed_state ); + mavlink_msg_extended_sys_state_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_ADSB_VEHICLE >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_battery_status_t packet_in = { - 963497464,963497672,17651,{ 17755, 17756, 17757, 17758, 17759, 17760, 17761, 17762, 17763, 17764 },18795,101,168,235,46 + mavlink_adsb_vehicle_t packet_in = { + 963497464,963497672,963497880,963498088,18067,18171,18275,18379,18483,211,"BCDEFGHI",113,180 }; - mavlink_battery_status_t packet1, packet2; + mavlink_adsb_vehicle_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.current_consumed = packet_in.current_consumed; - packet1.energy_consumed = packet_in.energy_consumed; - packet1.temperature = packet_in.temperature; - packet1.current_battery = packet_in.current_battery; - packet1.id = packet_in.id; - packet1.battery_function = packet_in.battery_function; - packet1.type = packet_in.type; - packet1.battery_remaining = packet_in.battery_remaining; - - mav_array_memcpy(packet1.voltages, packet_in.voltages, sizeof(uint16_t)*10); - - + packet1.ICAO_address = packet_in.ICAO_address; + packet1.lat = packet_in.lat; + packet1.lon = packet_in.lon; + packet1.altitude = packet_in.altitude; + packet1.heading = packet_in.heading; + packet1.hor_velocity = packet_in.hor_velocity; + packet1.ver_velocity = packet_in.ver_velocity; + packet1.flags = packet_in.flags; + packet1.squawk = packet_in.squawk; + packet1.altitude_type = packet_in.altitude_type; + packet1.emitter_type = packet_in.emitter_type; + packet1.tslc = packet_in.tslc; + + mav_array_memcpy(packet1.callsign, packet_in.callsign, sizeof(char)*9); + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_ADSB_VEHICLE_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_battery_status_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_battery_status_decode(&msg, &packet2); + mavlink_msg_adsb_vehicle_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_adsb_vehicle_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_battery_status_pack(system_id, component_id, &msg , packet1.id , packet1.battery_function , packet1.type , packet1.temperature , packet1.voltages , packet1.current_battery , packet1.current_consumed , packet1.energy_consumed , packet1.battery_remaining ); - mavlink_msg_battery_status_decode(&msg, &packet2); + mavlink_msg_adsb_vehicle_pack(system_id, component_id, &msg , packet1.ICAO_address , packet1.lat , packet1.lon , packet1.altitude_type , packet1.altitude , packet1.heading , packet1.hor_velocity , packet1.ver_velocity , packet1.callsign , packet1.emitter_type , packet1.tslc , packet1.flags , packet1.squawk ); + mavlink_msg_adsb_vehicle_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_battery_status_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.id , packet1.battery_function , packet1.type , packet1.temperature , packet1.voltages , packet1.current_battery , packet1.current_consumed , packet1.energy_consumed , packet1.battery_remaining ); - mavlink_msg_battery_status_decode(&msg, &packet2); + mavlink_msg_adsb_vehicle_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.ICAO_address , packet1.lat , packet1.lon , packet1.altitude_type , packet1.altitude , packet1.heading , packet1.hor_velocity , packet1.ver_velocity , packet1.callsign , packet1.emitter_type , packet1.tslc , packet1.flags , packet1.squawk ); + mavlink_msg_adsb_vehicle_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_COLLISION >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_autopilot_version_t packet_in = { - 93372036854775807ULL,93372036854776311ULL,963498296,963498504,963498712,963498920,18899,19003,{ 113, 114, 115, 116, 117, 118, 119, 120 },{ 137, 138, 139, 140, 141, 142, 143, 144 },{ 161, 162, 163, 164, 165, 166, 167, 168 } + mavlink_collision_t packet_in = { + 963497464,45.0,73.0,101.0,53,120,187 }; - mavlink_autopilot_version_t packet1, packet2; + mavlink_collision_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.capabilities = packet_in.capabilities; - packet1.uid = packet_in.uid; - packet1.flight_sw_version = packet_in.flight_sw_version; - packet1.middleware_sw_version = packet_in.middleware_sw_version; - packet1.os_sw_version = packet_in.os_sw_version; - packet1.board_version = packet_in.board_version; - packet1.vendor_id = packet_in.vendor_id; - packet1.product_id = packet_in.product_id; - - mav_array_memcpy(packet1.flight_custom_version, packet_in.flight_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet1.middleware_custom_version, packet_in.middleware_custom_version, sizeof(uint8_t)*8); - mav_array_memcpy(packet1.os_custom_version, packet_in.os_custom_version, sizeof(uint8_t)*8); - - + packet1.id = packet_in.id; + packet1.time_to_minimum_delta = packet_in.time_to_minimum_delta; + packet1.altitude_minimum_delta = packet_in.altitude_minimum_delta; + packet1.horizontal_minimum_delta = packet_in.horizontal_minimum_delta; + packet1.src = packet_in.src; + packet1.action = packet_in.action; + packet1.threat_level = packet_in.threat_level; + + +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_COLLISION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_COLLISION_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_autopilot_version_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_autopilot_version_decode(&msg, &packet2); + mavlink_msg_collision_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_collision_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_autopilot_version_pack(system_id, component_id, &msg , packet1.capabilities , packet1.flight_sw_version , packet1.middleware_sw_version , packet1.os_sw_version , packet1.board_version , packet1.flight_custom_version , packet1.middleware_custom_version , packet1.os_custom_version , packet1.vendor_id , packet1.product_id , packet1.uid ); - mavlink_msg_autopilot_version_decode(&msg, &packet2); + mavlink_msg_collision_pack(system_id, component_id, &msg , packet1.src , packet1.id , packet1.action , packet1.threat_level , packet1.time_to_minimum_delta , packet1.altitude_minimum_delta , packet1.horizontal_minimum_delta ); + mavlink_msg_collision_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_autopilot_version_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.capabilities , packet1.flight_sw_version , packet1.middleware_sw_version , packet1.os_sw_version , packet1.board_version , packet1.flight_custom_version , packet1.middleware_custom_version , packet1.os_custom_version , packet1.vendor_id , packet1.product_id , packet1.uid ); - mavlink_msg_autopilot_version_decode(&msg, &packet2); + mavlink_msg_collision_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.src , packet1.id , packet1.action , packet1.threat_level , packet1.time_to_minimum_delta , packet1.altitude_minimum_delta , packet1.horizontal_minimum_delta ); + mavlink_msg_collision_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_V2_EXTENSION >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_v2_extension_t packet_in = { - 17235,139,206,17,{ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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 } + mavlink_v2_extension_t packet_in = { + 17235,139,206,17,{ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 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, 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 } }; - mavlink_v2_extension_t packet1, packet2; + mavlink_v2_extension_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.message_type = packet_in.message_type; - packet1.target_network = packet_in.target_network; - packet1.target_system = packet_in.target_system; - packet1.target_component = packet_in.target_component; + packet1.message_type = packet_in.message_type; + packet1.target_network = packet_in.target_network; + packet1.target_system = packet_in.target_system; + packet1.target_component = packet_in.target_component; - mav_array_memcpy(packet1.payload, packet_in.payload, sizeof(uint8_t)*249); + mav_array_memcpy(packet1.payload, packet_in.payload, sizeof(uint8_t)*249); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_V2_EXTENSION_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_v2_extension_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_v2_extension_decode(&msg, &packet2); + mavlink_msg_v2_extension_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_v2_extension_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_v2_extension_pack(system_id, component_id, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.message_type , packet1.payload ); - mavlink_msg_v2_extension_decode(&msg, &packet2); + mavlink_msg_v2_extension_pack(system_id, component_id, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.message_type , packet1.payload ); + mavlink_msg_v2_extension_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_v2_extension_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.message_type , packet1.payload ); - mavlink_msg_v2_extension_decode(&msg, &packet2); + mavlink_msg_v2_extension_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.target_network , packet1.target_system , packet1.target_component , packet1.message_type , packet1.payload ); + mavlink_msg_v2_extension_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_MEMORY_VECT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_memory_vect_t packet_in = { - 17235,139,206,{ 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 } + mavlink_memory_vect_t packet_in = { + 17235,139,206,{ 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 } }; - mavlink_memory_vect_t packet1, packet2; + mavlink_memory_vect_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.address = packet_in.address; - packet1.ver = packet_in.ver; - packet1.type = packet_in.type; + packet1.address = packet_in.address; + packet1.ver = packet_in.ver; + packet1.type = packet_in.type; - mav_array_memcpy(packet1.value, packet_in.value, sizeof(int8_t)*32); + mav_array_memcpy(packet1.value, packet_in.value, sizeof(int8_t)*32); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_MEMORY_VECT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_memory_vect_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_memory_vect_decode(&msg, &packet2); + mavlink_msg_memory_vect_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_memory_vect_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_memory_vect_pack(system_id, component_id, &msg , packet1.address , packet1.ver , packet1.type , packet1.value ); - mavlink_msg_memory_vect_decode(&msg, &packet2); + mavlink_msg_memory_vect_pack(system_id, component_id, &msg , packet1.address , packet1.ver , packet1.type , packet1.value ); + mavlink_msg_memory_vect_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_memory_vect_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.address , packet1.ver , packet1.type , packet1.value ); - mavlink_msg_memory_vect_decode(&msg, &packet2); + mavlink_msg_memory_vect_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.address , packet1.ver , packet1.type , packet1.value ); + mavlink_msg_memory_vect_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DEBUG_VECT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_debug_vect_t packet_in = { - 93372036854775807ULL,73.0,101.0,129.0,"UVWXYZABC" + mavlink_debug_vect_t packet_in = { + 93372036854775807ULL,73.0,101.0,129.0,"UVWXYZABC" }; - mavlink_debug_vect_t packet1, packet2; + mavlink_debug_vect_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_usec = packet_in.time_usec; - packet1.x = packet_in.x; - packet1.y = packet_in.y; - packet1.z = packet_in.z; + packet1.time_usec = packet_in.time_usec; + packet1.x = packet_in.x; + packet1.y = packet_in.y; + packet1.z = packet_in.z; - mav_array_memcpy(packet1.name, packet_in.name, sizeof(char)*10); + mav_array_memcpy(packet1.name, packet_in.name, sizeof(char)*10); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DEBUG_VECT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_debug_vect_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_debug_vect_decode(&msg, &packet2); + mavlink_msg_debug_vect_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_debug_vect_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_debug_vect_pack(system_id, component_id, &msg , packet1.name , packet1.time_usec , packet1.x , packet1.y , packet1.z ); - mavlink_msg_debug_vect_decode(&msg, &packet2); + mavlink_msg_debug_vect_pack(system_id, component_id, &msg , packet1.name , packet1.time_usec , packet1.x , packet1.y , packet1.z ); + mavlink_msg_debug_vect_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_debug_vect_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.name , packet1.time_usec , packet1.x , packet1.y , packet1.z ); - mavlink_msg_debug_vect_decode(&msg, &packet2); + mavlink_msg_debug_vect_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.name , packet1.time_usec , packet1.x , packet1.y , packet1.z ); + mavlink_msg_debug_vect_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_NAMED_VALUE_FLOAT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_named_value_float_t packet_in = { - 963497464,45.0,"IJKLMNOPQ" + mavlink_named_value_float_t packet_in = { + 963497464,45.0,"IJKLMNOPQ" }; - mavlink_named_value_float_t packet1, packet2; + mavlink_named_value_float_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.value = packet_in.value; + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.value = packet_in.value; - mav_array_memcpy(packet1.name, packet_in.name, sizeof(char)*10); + mav_array_memcpy(packet1.name, packet_in.name, sizeof(char)*10); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_NAMED_VALUE_FLOAT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_named_value_float_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_named_value_float_decode(&msg, &packet2); + mavlink_msg_named_value_float_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_named_value_float_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_named_value_float_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); - mavlink_msg_named_value_float_decode(&msg, &packet2); + mavlink_msg_named_value_float_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); + mavlink_msg_named_value_float_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_named_value_float_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); - mavlink_msg_named_value_float_decode(&msg, &packet2); + mavlink_msg_named_value_float_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); + mavlink_msg_named_value_float_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_NAMED_VALUE_INT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_named_value_int_t packet_in = { - 963497464,963497672,"IJKLMNOPQ" + mavlink_named_value_int_t packet_in = { + 963497464,963497672,"IJKLMNOPQ" }; - mavlink_named_value_int_t packet1, packet2; + mavlink_named_value_int_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.value = packet_in.value; + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.value = packet_in.value; - mav_array_memcpy(packet1.name, packet_in.name, sizeof(char)*10); + mav_array_memcpy(packet1.name, packet_in.name, sizeof(char)*10); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_NAMED_VALUE_INT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_named_value_int_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_named_value_int_decode(&msg, &packet2); + mavlink_msg_named_value_int_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_named_value_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_named_value_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); - mavlink_msg_named_value_int_decode(&msg, &packet2); + mavlink_msg_named_value_int_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); + mavlink_msg_named_value_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_named_value_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); - mavlink_msg_named_value_int_decode(&msg, &packet2); + mavlink_msg_named_value_int_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.name , packet1.value ); + mavlink_msg_named_value_int_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_STATUSTEXT >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_statustext_t packet_in = { - 5,"BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX" + mavlink_statustext_t packet_in = { + 5,"BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWX" }; - mavlink_statustext_t packet1, packet2; + mavlink_statustext_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.severity = packet_in.severity; + packet1.severity = packet_in.severity; - mav_array_memcpy(packet1.text, packet_in.text, sizeof(char)*50); + mav_array_memcpy(packet1.text, packet_in.text, sizeof(char)*50); - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_STATUSTEXT_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_statustext_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_statustext_decode(&msg, &packet2); + mavlink_msg_statustext_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_statustext_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_statustext_pack(system_id, component_id, &msg , packet1.severity , packet1.text ); - mavlink_msg_statustext_decode(&msg, &packet2); + mavlink_msg_statustext_pack(system_id, component_id, &msg , packet1.severity , packet1.text ); + mavlink_msg_statustext_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_statustext_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.severity , packet1.text ); - mavlink_msg_statustext_decode(&msg, &packet2); + mavlink_msg_statustext_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.severity , packet1.text ); + mavlink_msg_statustext_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; iflags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) && MAVLINK_MSG_ID_DEBUG >= 256) { + return; + } +#endif + mavlink_message_t msg; uint8_t buffer[MAVLINK_MAX_PACKET_LEN]; uint16_t i; - mavlink_debug_t packet_in = { - 963497464,45.0,29 + mavlink_debug_t packet_in = { + 963497464,45.0,29 }; - mavlink_debug_t packet1, packet2; + mavlink_debug_t packet1, packet2; memset(&packet1, 0, sizeof(packet1)); - packet1.time_boot_ms = packet_in.time_boot_ms; - packet1.value = packet_in.value; - packet1.ind = packet_in.ind; + packet1.time_boot_ms = packet_in.time_boot_ms; + packet1.value = packet_in.value; + packet1.ind = packet_in.ind; - +#ifdef MAVLINK_STATUS_FLAG_OUT_MAVLINK1 + if (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) { + // cope with extensions + memset(MAVLINK_MSG_ID_DEBUG_MIN_LEN + (char *)&packet1, 0, sizeof(packet1)-MAVLINK_MSG_ID_DEBUG_MIN_LEN); + } +#endif memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_debug_encode(system_id, component_id, &msg, &packet1); - mavlink_msg_debug_decode(&msg, &packet2); + mavlink_msg_debug_encode(system_id, component_id, &msg, &packet1); + mavlink_msg_debug_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_debug_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.ind , packet1.value ); - mavlink_msg_debug_decode(&msg, &packet2); + mavlink_msg_debug_pack(system_id, component_id, &msg , packet1.time_boot_ms , packet1.ind , packet1.value ); + mavlink_msg_debug_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); - mavlink_msg_debug_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.ind , packet1.value ); - mavlink_msg_debug_decode(&msg, &packet2); + mavlink_msg_debug_pack_chan(system_id, component_id, MAVLINK_COMM_0, &msg , packet1.time_boot_ms , packet1.ind , packet1.value ); + mavlink_msg_debug_decode(&msg, &packet2); MAVLINK_ASSERT(memcmp(&packet1, &packet2, sizeof(packet1)) == 0); memset(&packet2, 0, sizeof(packet2)); mavlink_msg_to_send_buffer(buffer, &msg); for (i=0; i */ @@ -135,16 +136,45 @@ MAVLINK_HELPER void mavlink_euler_to_quaternion(float roll, float pitch, float y /** * Converts a rotation matrix to a quaternion + * Reference: + * - Shoemake, Quaternions, + * http://www.cs.ucr.edu/~vbz/resources/quatut.pdf * * @param dcm a 3x3 rotation matrix * @param quaternion a [w, x, y, z] ordered quaternion (null-rotation being 1 0 0 0) */ MAVLINK_HELPER void mavlink_dcm_to_quaternion(const float dcm[3][3], float quaternion[4]) { - quaternion[0] = 0.5f * sqrtf(1 + dcm[0][0] + dcm[1][1] + dcm[2][2]); - quaternion[1] = 0.5f * sqrtf(1 + dcm[0][0] - dcm[1][1] - dcm[2][2]); - quaternion[2] = 0.5f * sqrtf(1 - dcm[0][0] + dcm[1][1] - dcm[2][2]); - quaternion[3] = 0.5f * sqrtf(1 - dcm[0][0] - dcm[1][1] + dcm[2][2]); + float tr = dcm[0][0] + dcm[1][1] + dcm[2][2]; + if (tr > 0.0f) { + float s = sqrtf(tr + 1.0f); + quaternion[0] = s * 0.5f; + s = 0.5f / s; + quaternion[1] = (dcm[2][1] - dcm[1][2]) * s; + quaternion[2] = (dcm[0][2] - dcm[2][0]) * s; + quaternion[3] = (dcm[1][0] - dcm[0][1]) * s; + } else { + /* Find maximum diagonal element in dcm + * store index in dcm_i */ + int dcm_i = 0; + int i; + for (i = 1; i < 3; i++) { + if (dcm[i][i] > dcm[dcm_i][dcm_i]) { + dcm_i = i; + } + } + + int dcm_j = (dcm_i + 1) % 3; + int dcm_k = (dcm_i + 2) % 3; + + float s = sqrtf((dcm[dcm_i][dcm_i] - dcm[dcm_j][dcm_j] - + dcm[dcm_k][dcm_k]) + 1.0f); + quaternion[dcm_i + 1] = s * 0.5f; + s = 0.5f / s; + quaternion[dcm_j + 1] = (dcm[dcm_i][dcm_j] + dcm[dcm_j][dcm_i]) * s; + quaternion[dcm_k + 1] = (dcm[dcm_k][dcm_i] + dcm[dcm_i][dcm_k]) * s; + quaternion[0] = (dcm[dcm_k][dcm_j] - dcm[dcm_j][dcm_k]) * s; + } } diff --git a/vendor/libraries/mavlink/mavlink_helpers.h b/vendor/libraries/mavlink/mavlink_helpers.h index f6f6837fc5..2587cdf328 100644 --- a/vendor/libraries/mavlink/mavlink_helpers.h +++ b/vendor/libraries/mavlink/mavlink_helpers.h @@ -66,18 +66,20 @@ MAVLINK_HELPER void mavlink_reset_channel_status(uint8_t chan) */ #if MAVLINK_CRC_EXTRA MAVLINK_HELPER uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, - uint8_t chan, uint8_t length, uint8_t crc_extra) + uint8_t chan, uint8_t min_length, uint8_t length, uint8_t crc_extra) #else MAVLINK_HELPER uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, uint8_t chan, uint8_t length) #endif { + // This is only used for the v2 protocol and we silence it here + (void)min_length; // This code part is the same for all messages; msg->magic = MAVLINK_STX; msg->len = length; msg->sysid = system_id; msg->compid = component_id; - // One sequence number per component + // One sequence number per channel msg->seq = mavlink_get_channel_status(chan)->current_tx_seq; mavlink_get_channel_status(chan)->current_tx_seq = mavlink_get_channel_status(chan)->current_tx_seq+1; msg->checksum = crc_calculate(((const uint8_t*)(msg)) + 3, MAVLINK_CORE_HEADER_LEN); @@ -97,9 +99,9 @@ MAVLINK_HELPER uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, ui */ #if MAVLINK_CRC_EXTRA MAVLINK_HELPER uint16_t mavlink_finalize_message(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, - uint8_t length, uint8_t crc_extra) + uint8_t min_length, uint8_t length, uint8_t crc_extra) { - return mavlink_finalize_message_chan(msg, system_id, component_id, MAVLINK_COMM_0, length, crc_extra); + return mavlink_finalize_message_chan(msg, system_id, component_id, MAVLINK_COMM_0, min_length, length, crc_extra); } #else MAVLINK_HELPER uint16_t mavlink_finalize_message(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, @@ -117,7 +119,7 @@ MAVLINK_HELPER void _mavlink_send_uart(mavlink_channel_t chan, const char *buf, */ #if MAVLINK_CRC_EXTRA MAVLINK_HELPER void _mav_finalize_message_chan_send(mavlink_channel_t chan, uint8_t msgid, const char *packet, - uint8_t length, uint8_t crc_extra) + uint8_t min_length, uint8_t length, uint8_t crc_extra) #else MAVLINK_HELPER void _mav_finalize_message_chan_send(mavlink_channel_t chan, uint8_t msgid, const char *packet, uint8_t length) #endif @@ -204,24 +206,17 @@ MAVLINK_HELPER void mavlink_update_checksum(mavlink_message_t* msg, uint8_t c) } /** - * This is a convenience function which handles the complete MAVLink parsing. - * the function will parse one byte at a time and return the complete packet once - * it could be successfully decoded. Checksum and other failures will be silently - * ignored. - * - * Messages are parsed into an internal buffer (one for each channel). When a complete - * message is received it is copies into *returnMsg and the channel's status is - * copied into *returnStats. + * This is a varient of mavlink_frame_char() but with caller supplied + * parsing buffers. It is useful when you want to create a MAVLink + * parser in a library that doesn't use any global variables * - * @param chan ID of the current channel. This allows to parse different channels with this function. - * a channel is not a physical message channel like a serial port, but a logic partition of - * the communication streams in this case. COMM_NB is the limit for the number of channels - * on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows + * @param rxmsg parsing message buffer + * @param status parsing starus buffer * @param c The char to parse * * @param returnMsg NULL if no message could be decoded, the message data else * @param returnStats if a message was decoded, this is filled with the channel's stats - * @return 0 if no message could be decoded, 1 else + * @return 0 if no message could be decoded, 1 on good message and CRC, 2 on bad CRC * * A typical use scenario of this function call is: * @@ -235,7 +230,7 @@ MAVLINK_HELPER void mavlink_update_checksum(mavlink_message_t* msg, uint8_t c) * while(serial.bytesAvailable > 0) * { * uint8_t byte = serial.getNextByte(); - * if (mavlink_parse_char(chan, byte, &msg)) + * if (mavlink_frame_char(chan, byte, &msg) != MAVLINK_FRAMING_INCOMPLETE) * { * printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid); * } @@ -244,7 +239,11 @@ MAVLINK_HELPER void mavlink_update_checksum(mavlink_message_t* msg, uint8_t c) * * @endcode */ -MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status) +MAVLINK_HELPER uint8_t mavlink_frame_char_buffer(mavlink_message_t* rxmsg, + mavlink_status_t* status, + uint8_t c, + mavlink_message_t* r_message, + mavlink_status_t* r_mavlink_status) { /* default message crc function. You can override this per-system to @@ -257,12 +256,12 @@ MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_messa #endif #endif -/* Enable this option to check the length of each message. - This allows invalid messages to be caught much sooner. Use if the transmission - medium is prone to missing (or extra) characters (e.g. a radio that fades in - and out). Only use if the channel will only contain messages types listed in - the headers. -*/ + /* Enable this option to check the length of each message. + This allows invalid messages to be caught much sooner. Use if the transmission + medium is prone to missing (or extra) characters (e.g. a radio that fades in + and out). Only use if the channel will only contain messages types listed in + the headers. + */ #ifdef MAVLINK_CHECK_MESSAGE_LENGTH #ifndef MAVLINK_MESSAGE_LENGTH static const uint8_t mavlink_message_lengths[256] = MAVLINK_MESSAGE_LENGTHS; @@ -270,11 +269,9 @@ MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_messa #endif #endif - mavlink_message_t* rxmsg = mavlink_get_channel_buffer(chan); ///< The currently decoded message - mavlink_status_t* status = mavlink_get_channel_status(chan); ///< The current decode status int bufferIndex = 0; - status->msg_received = 0; + status->msg_received = MAVLINK_FRAMING_INCOMPLETE; switch (status->parse_state) { @@ -338,12 +335,7 @@ MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_messa status->parse_error++; status->parse_state = MAVLINK_PARSE_STATE_IDLE; break; - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - mavlink_start_checksum(rxmsg); - } - } + } #endif rxmsg->msgid = c; mavlink_update_checksum(rxmsg, c); @@ -371,51 +363,31 @@ MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_messa mavlink_update_checksum(rxmsg, MAVLINK_MESSAGE_CRC(rxmsg->msgid)); #endif if (c != (rxmsg->checksum & 0xFF)) { - // Check first checksum byte - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - rxmsg->len = 0; - mavlink_start_checksum(rxmsg); - } - } - else - { + status->parse_state = MAVLINK_PARSE_STATE_GOT_BAD_CRC1; + } else { status->parse_state = MAVLINK_PARSE_STATE_GOT_CRC1; - _MAV_PAYLOAD_NON_CONST(rxmsg)[status->packet_idx] = (char)c; } + _MAV_PAYLOAD_NON_CONST(rxmsg)[status->packet_idx] = (char)c; break; case MAVLINK_PARSE_STATE_GOT_CRC1: - if (c != (rxmsg->checksum >> 8)) { - // Check second checksum byte - status->parse_error++; - status->msg_received = 0; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - if (c == MAVLINK_STX) - { - status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; - rxmsg->len = 0; - mavlink_start_checksum(rxmsg); - } - } - else - { + case MAVLINK_PARSE_STATE_GOT_BAD_CRC1: + if (status->parse_state == MAVLINK_PARSE_STATE_GOT_BAD_CRC1 || c != (rxmsg->checksum >> 8)) { + // got a bad CRC message + status->msg_received = MAVLINK_FRAMING_BAD_CRC; + } else { // Successfully got message - status->msg_received = 1; - status->parse_state = MAVLINK_PARSE_STATE_IDLE; - _MAV_PAYLOAD_NON_CONST(rxmsg)[status->packet_idx+1] = (char)c; - memcpy(r_message, rxmsg, sizeof(mavlink_message_t)); - } + status->msg_received = MAVLINK_FRAMING_OK; + } + status->parse_state = MAVLINK_PARSE_STATE_IDLE; + _MAV_PAYLOAD_NON_CONST(rxmsg)[status->packet_idx+1] = (char)c; + memcpy(r_message, rxmsg, sizeof(mavlink_message_t)); break; } bufferIndex++; // If a message has been sucessfully decoded, check index - if (status->msg_received == 1) + if (status->msg_received == MAVLINK_FRAMING_OK) { //while(status->current_seq != rxmsg->seq) //{ @@ -429,13 +401,140 @@ MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_messa status->packet_rx_success_count++; } + r_message->len = rxmsg->len; // Provide visibility on how far we are into current msg + r_mavlink_status->parse_state = status->parse_state; + r_mavlink_status->packet_idx = status->packet_idx; r_mavlink_status->current_rx_seq = status->current_rx_seq+1; r_mavlink_status->packet_rx_success_count = status->packet_rx_success_count; r_mavlink_status->packet_rx_drop_count = status->parse_error; status->parse_error = 0; + + if (status->msg_received == MAVLINK_FRAMING_BAD_CRC) { + /* + the CRC came out wrong. We now need to overwrite the + msg CRC with the one on the wire so that if the + caller decides to forward the message anyway that + mavlink_msg_to_send_buffer() won't overwrite the + checksum + */ + r_message->checksum = _MAV_PAYLOAD(rxmsg)[status->packet_idx] | (_MAV_PAYLOAD(rxmsg)[status->packet_idx+1]<<8); + } + return status->msg_received; } +/** + * This is a convenience function which handles the complete MAVLink parsing. + * the function will parse one byte at a time and return the complete packet once + * it could be successfully decoded. This function will return 0, 1 or + * 2 (MAVLINK_FRAMING_INCOMPLETE, MAVLINK_FRAMING_OK or MAVLINK_FRAMING_BAD_CRC) + * + * Messages are parsed into an internal buffer (one for each channel). When a complete + * message is received it is copies into *returnMsg and the channel's status is + * copied into *returnStats. + * + * @param chan ID of the current channel. This allows to parse different channels with this function. + * a channel is not a physical message channel like a serial port, but a logic partition of + * the communication streams in this case. COMM_NB is the limit for the number of channels + * on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows + * @param c The char to parse + * + * @param returnMsg NULL if no message could be decoded, the message data else + * @param returnStats if a message was decoded, this is filled with the channel's stats + * @return 0 if no message could be decoded, 1 on good message and CRC, 2 on bad CRC + * + * A typical use scenario of this function call is: + * + * @code + * #include + * + * mavlink_message_t msg; + * int chan = 0; + * + * + * while(serial.bytesAvailable > 0) + * { + * uint8_t byte = serial.getNextByte(); + * if (mavlink_frame_char(chan, byte, &msg) != MAVLINK_FRAMING_INCOMPLETE) + * { + * printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid); + * } + * } + * + * + * @endcode + */ +MAVLINK_HELPER uint8_t mavlink_frame_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status) +{ + return mavlink_frame_char_buffer(mavlink_get_channel_buffer(chan), + mavlink_get_channel_status(chan), + c, + r_message, + r_mavlink_status); +} + + +/** + * This is a convenience function which handles the complete MAVLink parsing. + * the function will parse one byte at a time and return the complete packet once + * it could be successfully decoded. This function will return 0 or 1. + * + * Messages are parsed into an internal buffer (one for each channel). When a complete + * message is received it is copies into *returnMsg and the channel's status is + * copied into *returnStats. + * + * @param chan ID of the current channel. This allows to parse different channels with this function. + * a channel is not a physical message channel like a serial port, but a logic partition of + * the communication streams in this case. COMM_NB is the limit for the number of channels + * on MCU (e.g. ARM7), while COMM_NB_HIGH is the limit for the number of channels in Linux/Windows + * @param c The char to parse + * + * @param returnMsg NULL if no message could be decoded, the message data else + * @param returnStats if a message was decoded, this is filled with the channel's stats + * @return 0 if no message could be decoded or bad CRC, 1 on good message and CRC + * + * A typical use scenario of this function call is: + * + * @code + * #include + * + * mavlink_message_t msg; + * int chan = 0; + * + * + * while(serial.bytesAvailable > 0) + * { + * uint8_t byte = serial.getNextByte(); + * if (mavlink_parse_char(chan, byte, &msg)) + * { + * printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid); + * } + * } + * + * + * @endcode + */ +MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status) +{ + uint8_t msg_received = mavlink_frame_char(chan, c, r_message, r_mavlink_status); + if (msg_received == MAVLINK_FRAMING_BAD_CRC) { + // we got a bad CRC. Treat as a parse failure + mavlink_message_t* rxmsg = mavlink_get_channel_buffer(chan); + mavlink_status_t* status = mavlink_get_channel_status(chan); + status->parse_error++; + status->msg_received = MAVLINK_FRAMING_INCOMPLETE; + status->parse_state = MAVLINK_PARSE_STATE_IDLE; + if (c == MAVLINK_STX) + { + status->parse_state = MAVLINK_PARSE_STATE_GOT_STX; + rxmsg->len = 0; + mavlink_start_checksum(rxmsg); + } + return 0; + } + return msg_received; +} + /** * @brief Put a bitfield of length 1-32 bit into the buffer * diff --git a/vendor/libraries/mavlink/mavlink_protobuf_manager.hpp b/vendor/libraries/mavlink/mavlink_protobuf_manager.hpp deleted file mode 100644 index fd3ddd026f..0000000000 --- a/vendor/libraries/mavlink/mavlink_protobuf_manager.hpp +++ /dev/null @@ -1,377 +0,0 @@ -#ifndef MAVLINKPROTOBUFMANAGER_HPP -#define MAVLINKPROTOBUFMANAGER_HPP - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace mavlink -{ - -class ProtobufManager -{ -public: - ProtobufManager() - : mRegisteredTypeCount(0) - , mStreamID(0) - , mVerbose(false) - , kExtendedHeaderSize(MAVLINK_EXTENDED_HEADER_LEN) - , kExtendedPayloadMaxSize(MAVLINK_MAX_EXTENDED_PAYLOAD_LEN) - { - // register GLOverlay - { - std::tr1::shared_ptr msg(new px::GLOverlay); - registerType(msg); - } - - // register ObstacleList - { - std::tr1::shared_ptr msg(new px::ObstacleList); - registerType(msg); - } - - // register ObstacleMap - { - std::tr1::shared_ptr msg(new px::ObstacleMap); - registerType(msg); - } - - // register Path - { - std::tr1::shared_ptr msg(new px::Path); - registerType(msg); - } - - // register PointCloudXYZI - { - std::tr1::shared_ptr msg(new px::PointCloudXYZI); - registerType(msg); - } - - // register PointCloudXYZRGB - { - std::tr1::shared_ptr msg(new px::PointCloudXYZRGB); - registerType(msg); - } - - // register RGBDImage - { - std::tr1::shared_ptr msg(new px::RGBDImage); - registerType(msg); - } - - srand(time(NULL)); - mStreamID = rand() + 1; - } - - bool fragmentMessage(uint8_t system_id, uint8_t component_id, - uint8_t target_system, uint8_t target_component, - const google::protobuf::Message& protobuf_msg, - std::vector& fragments) const - { - TypeMap::const_iterator it = mTypeMap.find(protobuf_msg.GetTypeName()); - if (it == mTypeMap.end()) - { - std::cout << "# WARNING: Protobuf message with type " - << protobuf_msg.GetTypeName() << " is not registered." - << std::endl; - return false; - } - - uint8_t typecode = it->second; - - std::string data = protobuf_msg.SerializeAsString(); - - int fragmentCount = (protobuf_msg.ByteSize() + kExtendedPayloadMaxSize - 1) / kExtendedPayloadMaxSize; - unsigned int offset = 0; - - for (int i = 0; i < fragmentCount; ++i) - { - mavlink_extended_message_t fragment; - - // write extended header data - uint8_t* payload = reinterpret_cast(fragment.base_msg.payload64); - unsigned int length = 0; - uint8_t flags = 0; - - if (i < fragmentCount - 1) - { - length = kExtendedPayloadMaxSize; - flags |= 0x1; - } - else - { - length = protobuf_msg.ByteSize() - kExtendedPayloadMaxSize * (fragmentCount - 1); - } - - memcpy(payload, &target_system, 1); - memcpy(payload + 1, &target_component, 1); - memcpy(payload + 2, &typecode, 1); - memcpy(payload + 3, &length, 4); - memcpy(payload + 7, &mStreamID, 2); - memcpy(payload + 9, &offset, 4); - memcpy(payload + 13, &flags, 1); - - fragment.base_msg.msgid = MAVLINK_MSG_ID_EXTENDED_MESSAGE; - mavlink_finalize_message(&fragment.base_msg, system_id, component_id, kExtendedHeaderSize, 0); - - // write extended payload data - fragment.extended_payload_len = length; - memcpy(fragment.extended_payload, &data[offset], length); - - fragments.push_back(fragment); - offset += length; - } - - if (mVerbose) - { - std::cerr << "# INFO: Split extended message with size " - << protobuf_msg.ByteSize() << " into " - << fragmentCount << " fragments." << std::endl; - } - - return true; - } - - bool cacheFragment(mavlink_extended_message_t& msg) - { - if (!validFragment(msg)) - { - if (mVerbose) - { - std::cerr << "# WARNING: Message is not a valid fragment. " - << "Dropping message..." << std::endl; - } - return false; - } - - // read extended header - uint8_t* payload = reinterpret_cast(msg.base_msg.payload64); - uint8_t typecode = 0; - unsigned int length = 0; - unsigned short streamID = 0; - unsigned int offset = 0; - uint8_t flags = 0; - - memcpy(&typecode, payload + 2, 1); - memcpy(&length, payload + 3, 4); - memcpy(&streamID, payload + 7, 2); - memcpy(&offset, payload + 9, 4); - memcpy(&flags, payload + 13, 1); - - if (typecode >= mTypeMap.size()) - { - std::cout << "# WARNING: Protobuf message with type code " - << static_cast(typecode) << " is not registered." << std::endl; - return false; - } - - bool reassemble = false; - - FragmentQueue::iterator it = mFragmentQueue.find(streamID); - if (it == mFragmentQueue.end()) - { - if (offset == 0) - { - mFragmentQueue[streamID].push_back(msg); - - if ((flags & 0x1) != 0x1) - { - reassemble = true; - } - - if (mVerbose) - { - std::cerr << "# INFO: Added fragment to new queue." - << std::endl; - } - } - else - { - if (mVerbose) - { - std::cerr << "# WARNING: Message is not a valid fragment. " - << "Dropping message..." << std::endl; - } - } - } - else - { - std::deque& queue = it->second; - - if (queue.empty()) - { - if (offset == 0) - { - queue.push_back(msg); - - if ((flags & 0x1) != 0x1) - { - reassemble = true; - } - } - else - { - if (mVerbose) - { - std::cerr << "# WARNING: Message is not a valid fragment. " - << "Dropping message..." << std::endl; - } - } - } - else - { - if (fragmentDataSize(queue.back()) + fragmentOffset(queue.back()) != offset) - { - if (mVerbose) - { - std::cerr << "# WARNING: Previous fragment(s) have been lost. " - << "Dropping message and clearing queue..." << std::endl; - } - queue.clear(); - } - else - { - queue.push_back(msg); - - if ((flags & 0x1) != 0x1) - { - reassemble = true; - } - } - } - } - - if (reassemble) - { - std::deque& queue = mFragmentQueue[streamID]; - - std::string data; - for (size_t i = 0; i < queue.size(); ++i) - { - mavlink_extended_message_t& mavlink_msg = queue.at(i); - - data.append(reinterpret_cast(&mavlink_msg.extended_payload[0]), - static_cast(mavlink_msg.extended_payload_len)); - } - - mMessages.at(typecode)->ParseFromString(data); - - mMessageAvailable.at(typecode) = true; - - queue.clear(); - - if (mVerbose) - { - std::cerr << "# INFO: Reassembled fragments for message with typename " - << mMessages.at(typecode)->GetTypeName() << " and size " - << mMessages.at(typecode)->ByteSize() - << "." << std::endl; - } - } - - return true; - } - - bool getMessage(std::tr1::shared_ptr& msg) - { - for (size_t i = 0; i < mMessageAvailable.size(); ++i) - { - if (mMessageAvailable.at(i)) - { - msg = mMessages.at(i); - mMessageAvailable.at(i) = false; - - return true; - } - } - - return false; - } - -private: - void registerType(const std::tr1::shared_ptr& msg) - { - mTypeMap[msg->GetTypeName()] = mRegisteredTypeCount; - ++mRegisteredTypeCount; - mMessages.push_back(msg); - mMessageAvailable.push_back(false); - } - - bool validFragment(const mavlink_extended_message_t& msg) const - { - if (msg.base_msg.magic != MAVLINK_STX || - msg.base_msg.len != kExtendedHeaderSize || - msg.base_msg.msgid != MAVLINK_MSG_ID_EXTENDED_MESSAGE) - { - return false; - } - - uint16_t checksum; - checksum = crc_calculate(reinterpret_cast(&msg.base_msg.len), MAVLINK_CORE_HEADER_LEN); - crc_accumulate_buffer(&checksum, reinterpret_cast(&msg.base_msg.payload64), kExtendedHeaderSize); -#if MAVLINK_CRC_EXTRA - static const uint8_t mavlink_message_crcs[256] = MAVLINK_MESSAGE_CRCS; - crc_accumulate(mavlink_message_crcs[msg.base_msg.msgid], &checksum); -#endif - - if (mavlink_ck_a(&(msg.base_msg)) != (uint8_t)(checksum & 0xFF) && - mavlink_ck_b(&(msg.base_msg)) != (uint8_t)(checksum >> 8)) - { - return false; - } - - return true; - } - - unsigned int fragmentDataSize(const mavlink_extended_message_t& msg) const - { - const uint8_t* payload = reinterpret_cast(msg.base_msg.payload64); - - return *(reinterpret_cast(payload + 3)); - } - - unsigned int fragmentOffset(const mavlink_extended_message_t& msg) const - { - const uint8_t* payload = reinterpret_cast(msg.base_msg.payload64); - - return *(reinterpret_cast(payload + 9)); - } - - int mRegisteredTypeCount; - unsigned short mStreamID; - bool mVerbose; - - typedef std::map TypeMap; - TypeMap mTypeMap; - std::vector< std::tr1::shared_ptr > mMessages; - std::vector mMessageAvailable; - - typedef std::map > FragmentQueue; - FragmentQueue mFragmentQueue; - - const int kExtendedHeaderSize; - /** - * Extended header structure - * ========================= - * byte 0 - target_system - * byte 1 - target_component - * byte 2 - extended message id (type code) - * bytes 3-6 - extended payload size in bytes - * byte 7-8 - stream ID - * byte 9-12 - fragment offset - * byte 13 - fragment flags (bit 0 - 1=more fragments, 0=last fragment) - */ - - const int kExtendedPayloadMaxSize; -}; - -} - -#endif diff --git a/vendor/libraries/mavlink/mavlink_types.h b/vendor/libraries/mavlink/mavlink_types.h index b56fac8c13..d3cb7a7de4 100644 --- a/vendor/libraries/mavlink/mavlink_types.h +++ b/vendor/libraries/mavlink/mavlink_types.h @@ -86,8 +86,9 @@ typedef struct param_union { * and the bits pulled out using the shifts/masks. */ MAVPACKED( -typedef union { - struct param_union_double{ +typedef struct param_union_extended { + union param_union_ext{ + struct param_struct_ext{ uint8_t is_double:1; uint8_t mavlink_type:7; union { @@ -103,6 +104,7 @@ typedef union { }; }; uint8_t data[8]; + }; }) mavlink_param_union_double_t; /** @@ -204,9 +206,16 @@ typedef enum { MAVLINK_PARSE_STATE_GOT_COMPID, MAVLINK_PARSE_STATE_GOT_MSGID, MAVLINK_PARSE_STATE_GOT_PAYLOAD, - MAVLINK_PARSE_STATE_GOT_CRC1 + MAVLINK_PARSE_STATE_GOT_CRC1, + MAVLINK_PARSE_STATE_GOT_BAD_CRC1 } mavlink_parse_state_t; ///< The state machine for the comm parser +typedef enum { + MAVLINK_FRAMING_INCOMPLETE=0, + MAVLINK_FRAMING_OK=1, + MAVLINK_FRAMING_BAD_CRC=2 +} mavlink_framing_t; + typedef struct __mavlink_status { uint8_t msg_received; ///< Number of received messages uint8_t buffer_overrun; ///< Number of buffer overruns diff --git a/vendor/libraries/mavlink/protocol.h b/vendor/libraries/mavlink/protocol.h index abebfaa659..731bd3a583 100644 --- a/vendor/libraries/mavlink/protocol.h +++ b/vendor/libraries/mavlink/protocol.h @@ -46,18 +46,18 @@ MAVLINK_HELPER void mavlink_reset_channel_status(uint8_t chan); #if MAVLINK_CRC_EXTRA MAVLINK_HELPER uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, - uint8_t chan, uint8_t length, uint8_t crc_extra); + uint8_t chan, uint8_t min_length, uint8_t length, uint8_t crc_extra); MAVLINK_HELPER uint16_t mavlink_finalize_message(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, - uint8_t length, uint8_t crc_extra); + uint8_t min_length, uint8_t length, uint8_t crc_extra); #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS MAVLINK_HELPER void _mav_finalize_message_chan_send(mavlink_channel_t chan, uint8_t msgid, const char *packet, - uint8_t length, uint8_t crc_extra); + uint8_t min_length, uint8_t length, uint8_t crc_extra); #endif #else MAVLINK_HELPER uint16_t mavlink_finalize_message_chan(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, - uint8_t chan, uint8_t length); + uint8_t chan, uint8_t length); MAVLINK_HELPER uint16_t mavlink_finalize_message(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id, - uint8_t length); + uint8_t length); #ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS MAVLINK_HELPER void _mav_finalize_message_chan_send(mavlink_channel_t chan, uint8_t msgid, const char *packet, uint8_t length); #endif @@ -65,6 +65,12 @@ MAVLINK_HELPER uint16_t mavlink_msg_to_send_buffer(uint8_t *buffer, const mavlink_message_t *msg); MAVLINK_HELPER void mavlink_start_checksum(mavlink_message_t* msg); MAVLINK_HELPER void mavlink_update_checksum(mavlink_message_t* msg, uint8_t c); + MAVLINK_HELPER uint8_t mavlink_frame_char_buffer(mavlink_message_t* rxmsg, + mavlink_status_t* status, + uint8_t c, + mavlink_message_t* r_message, + mavlink_status_t* r_mavlink_status); + MAVLINK_HELPER uint8_t mavlink_frame_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status); MAVLINK_HELPER uint8_t mavlink_parse_char(uint8_t chan, uint8_t c, mavlink_message_t* r_message, mavlink_status_t* r_mavlink_status); MAVLINK_HELPER uint8_t put_bitfield_n_by_index(int32_t b, uint8_t bits, uint8_t packet_index, uint8_t bit_index, uint8_t* r_bit_index, uint8_t* buffer); diff --git a/vendor/libraries/mavlink/uAvionix/mavlink.h b/vendor/libraries/mavlink/uAvionix/mavlink.h new file mode 100644 index 0000000000..124ee19cf6 --- /dev/null +++ b/vendor/libraries/mavlink/uAvionix/mavlink.h @@ -0,0 +1,34 @@ +/** @file + * @brief MAVLink comm protocol built from uAvionix.xml + * @see http://mavlink.org + */ +#pragma once +#ifndef MAVLINK_H +#define MAVLINK_H + +#define MAVLINK_PRIMARY_XML_IDX 2 + +#ifndef MAVLINK_STX +#define MAVLINK_STX 254 +#endif + +#ifndef MAVLINK_ENDIAN +#define MAVLINK_ENDIAN MAVLINK_LITTLE_ENDIAN +#endif + +#ifndef MAVLINK_ALIGNED_FIELDS +#define MAVLINK_ALIGNED_FIELDS 1 +#endif + +#ifndef MAVLINK_CRC_EXTRA +#define MAVLINK_CRC_EXTRA 1 +#endif + +#ifndef MAVLINK_COMMAND_24BIT +#define MAVLINK_COMMAND_24BIT 0 +#endif + +#include "version.h" +#include "uAvionix.h" + +#endif // MAVLINK_H diff --git a/vendor/libraries/mavlink/uAvionix/testsuite.h b/vendor/libraries/mavlink/uAvionix/testsuite.h new file mode 100644 index 0000000000..526d7dcbf1 --- /dev/null +++ b/vendor/libraries/mavlink/uAvionix/testsuite.h @@ -0,0 +1,37 @@ +/** @file + * @brief MAVLink comm protocol testsuite generated from uAvionix.xml + * @see http://qgroundcontrol.org/mavlink/ + */ +#pragma once +#ifndef UAVIONIX_TESTSUITE_H +#define UAVIONIX_TESTSUITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MAVLINK_TEST_ALL +#define MAVLINK_TEST_ALL + +static void mavlink_test_uAvionix(uint8_t, uint8_t, mavlink_message_t *last_msg); + +static void mavlink_test_all(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg) +{ + + mavlink_test_uAvionix(system_id, component_id, last_msg); +} +#endif + + + + + +static void mavlink_test_uAvionix(uint8_t system_id, uint8_t component_id, mavlink_message_t *last_msg) +{ + +} + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // UAVIONIX_TESTSUITE_H diff --git a/vendor/libraries/mavlink/uAvionix/uAvionix.h b/vendor/libraries/mavlink/uAvionix/uAvionix.h new file mode 100644 index 0000000000..471416c374 --- /dev/null +++ b/vendor/libraries/mavlink/uAvionix/uAvionix.h @@ -0,0 +1,191 @@ +/** @file + * @brief MAVLink comm protocol generated from uAvionix.xml + * @see http://mavlink.org + */ +#pragma once +#ifndef MAVLINK_UAVIONIX_H +#define MAVLINK_UAVIONIX_H + +#ifndef MAVLINK_H + #error Wrong include order: MAVLINK_UAVIONIX.H MUST NOT BE DIRECTLY USED. Include mavlink.h from the same directory instead or set ALL AND EVERY defines from MAVLINK.H manually accordingly, including the #define MAVLINK_H call. +#endif + +#undef MAVLINK_THIS_XML_IDX +#define MAVLINK_THIS_XML_IDX 2 + +#ifdef __cplusplus +extern "C" { +#endif + +// MESSAGE LENGTHS AND CRCS + +#ifndef MAVLINK_MESSAGE_LENGTHS +#define MAVLINK_MESSAGE_LENGTHS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#endif + +#ifndef MAVLINK_MESSAGE_CRCS +#define MAVLINK_MESSAGE_CRCS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#endif + +#include "../protocol.h" + +#define MAVLINK_ENABLED_UAVIONIX + +// ENUM DEFINITIONS + + +/** @brief State flags for ADS-B transponder dynamic report */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_OUT_DYNAMIC_STATE +#define HAVE_ENUM_UAVIONIX_ADSB_OUT_DYNAMIC_STATE +typedef enum UAVIONIX_ADSB_OUT_DYNAMIC_STATE +{ + UAVIONIX_ADSB_OUT_DYNAMIC_STATE_INTENT_CHANGE=1, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_STATE_AUTOPILOT_ENABLED=2, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_STATE_NICBARO_CROSSCHECKED=4, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_STATE_ON_GROUND=8, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_STATE_IDENT=16, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_STATE_ENUM_END=17 /* | */ +} UAVIONIX_ADSB_OUT_DYNAMIC_STATE; +#endif + +/** @brief Transceiver RF control flags for ADS-B transponder dynamic reports */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_OUT_RF_SELECT +#define HAVE_ENUM_UAVIONIX_ADSB_OUT_RF_SELECT +typedef enum UAVIONIX_ADSB_OUT_RF_SELECT +{ + UAVIONIX_ADSB_OUT_RF_SELECT_STANDBY=0, /* | */ + UAVIONIX_ADSB_OUT_RF_SELECT_RX_ENABLED=1, /* | */ + UAVIONIX_ADSB_OUT_RF_SELECT_TX_ENABLED=2, /* | */ + UAVIONIX_ADSB_OUT_RF_SELECT_ENUM_END=3 /* | */ +} UAVIONIX_ADSB_OUT_RF_SELECT; +#endif + +/** @brief Status for ADS-B transponder dynamic input */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX +#define HAVE_ENUM_UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX +typedef enum UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX +{ + UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX_NONE_0=0, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX_NONE_1=1, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX_2D=2, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX_3D=3, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX_DGPS=4, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX_RTK=5, /* | */ + UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX_ENUM_END=6 /* | */ +} UAVIONIX_ADSB_OUT_DYNAMIC_GPS_FIX; +#endif + +/** @brief Status flags for ADS-B transponder dynamic output */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_RF_HEALTH +#define HAVE_ENUM_UAVIONIX_ADSB_RF_HEALTH +typedef enum UAVIONIX_ADSB_RF_HEALTH +{ + UAVIONIX_ADSB_RF_HEALTH_INITIALIZING=0, /* | */ + UAVIONIX_ADSB_RF_HEALTH_OK=1, /* | */ + UAVIONIX_ADSB_RF_HEALTH_FAIL_TX=2, /* | */ + UAVIONIX_ADSB_RF_HEALTH_FAIL_RX=16, /* | */ + UAVIONIX_ADSB_RF_HEALTH_ENUM_END=17 /* | */ +} UAVIONIX_ADSB_RF_HEALTH; +#endif + +/** @brief Definitions for aircraft size */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE +#define HAVE_ENUM_UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE +typedef enum UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE +{ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_NO_DATA=0, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L15M_W23M=1, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L25M_W28P5M=2, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L25_34M=3, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L35_33M=4, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L35_38M=5, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L45_39P5M=6, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L45_45M=7, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L55_45M=8, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L55_52M=9, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L65_59P5M=10, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L65_67M=11, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L75_W72P5M=12, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L75_W80M=13, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L85_W80M=14, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_L85_W90M=15, /* | */ + UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE_ENUM_END=16 /* | */ +} UAVIONIX_ADSB_OUT_CFG_AIRCRAFT_SIZE; +#endif + +/** @brief GPS lataral offset encoding */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT +#define HAVE_ENUM_UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT +typedef enum UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT +{ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_NO_DATA=0, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_LEFT_2M=1, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_LEFT_4M=2, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_LEFT_6M=3, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_RIGHT_0M=4, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_RIGHT_2M=5, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_RIGHT_4M=6, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_RIGHT_6M=7, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT_ENUM_END=8 /* | */ +} UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LAT; +#endif + +/** @brief GPS longitudinal offset encoding */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LON +#define HAVE_ENUM_UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LON +typedef enum UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LON +{ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LON_NO_DATA=0, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LON_APPLIED_BY_SENSOR=1, /* | */ + UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LON_ENUM_END=2 /* | */ +} UAVIONIX_ADSB_OUT_CFG_GPS_OFFSET_LON; +#endif + +/** @brief Emergency status encoding */ +#ifndef HAVE_ENUM_UAVIONIX_ADSB_EMERGENCY_STATUS +#define HAVE_ENUM_UAVIONIX_ADSB_EMERGENCY_STATUS +typedef enum UAVIONIX_ADSB_EMERGENCY_STATUS +{ + UAVIONIX_ADSB_OUT_NO_EMERGENCY=0, /* | */ + UAVIONIX_ADSB_OUT_GENERAL_EMERGENCY=1, /* | */ + UAVIONIX_ADSB_OUT_LIFEGUARD_EMERGENCY=2, /* | */ + UAVIONIX_ADSB_OUT_MINIMUM_FUEL_EMERGENCY=3, /* | */ + UAVIONIX_ADSB_OUT_NO_COMM_EMERGENCY=4, /* | */ + UAVIONIX_ADSB_OUT_UNLAWFUL_INTERFERANCE_EMERGENCY=5, /* | */ + UAVIONIX_ADSB_OUT_DOWNED_AIRCRAFT_EMERGENCY=6, /* | */ + UAVIONIX_ADSB_OUT_RESERVED=7, /* | */ + UAVIONIX_ADSB_EMERGENCY_STATUS_ENUM_END=8 /* | */ +} UAVIONIX_ADSB_EMERGENCY_STATUS; +#endif + +// MAVLINK VERSION + +#ifndef MAVLINK_VERSION +#define MAVLINK_VERSION 2 +#endif + +#if (MAVLINK_VERSION == 0) +#undef MAVLINK_VERSION +#define MAVLINK_VERSION 2 +#endif + +// MESSAGE DEFINITIONS + + +// base include + + +#undef MAVLINK_THIS_XML_IDX +#define MAVLINK_THIS_XML_IDX 2 + +#if MAVLINK_THIS_XML_IDX == MAVLINK_PRIMARY_XML_IDX +# define MAVLINK_MESSAGE_INFO {{"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}, {"EMPTY",0,{{"","",MAVLINK_TYPE_CHAR,0,0,0}}}} +# if MAVLINK_COMMAND_24BIT +# include "../mavlink_get_info.h" +# endif +#endif + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // MAVLINK_UAVIONIX_H diff --git a/vendor/libraries/mavlink/uAvionix/version.h b/vendor/libraries/mavlink/uAvionix/version.h new file mode 100644 index 0000000000..18bfcee1f1 --- /dev/null +++ b/vendor/libraries/mavlink/uAvionix/version.h @@ -0,0 +1,14 @@ +/** @file + * @brief MAVLink comm protocol built from uAvionix.xml + * @see http://mavlink.org + */ +#pragma once + +#ifndef MAVLINK_VERSION_H +#define MAVLINK_VERSION_H + +#define MAVLINK_BUILD_DATE "Mon May 01 2017" +#define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" +#define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 255 + +#endif // MAVLINK_VERSION_H diff --git a/vendor/libraries/sqlite3/Library.cmake b/vendor/libraries/sqlite3/Library.cmake index fc71574df1..eefcf7658b 100644 --- a/vendor/libraries/sqlite3/Library.cmake +++ b/vendor/libraries/sqlite3/Library.cmake @@ -24,7 +24,22 @@ if(DUNE_OS_DARWIN) set(SQLITE3_C_FLAGS "${SQLITE3_C_FLAGS} -DSQLITE_DISABLE_INTRINSIC") endif(DUNE_OS_DARWIN) +if(CMAKE_COMPILER_IS_GNUCXX) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(SQLITE3_C_FLAGS "${SQLITE3_C_FLAGS} -Wno-cast-function-type") + else() + set(SQLITE3_C_FLAGS "${SQLITE3_C_FLAGS} -Wno-bad-function-cast") + endif() +elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(SQLITE3_C_FLAGS "${SQLITE3_C_FLAGS} -Wno-cast-function-type") +endif() + +check_cxx_compiler_flag(-Wimplicit-fallthrough=0 _has_wimplicit_fallthrough_0) +if(_has_wimplicit_fallthrough_0) + set(_sqlite3_extra_cflags -Wimplicit-fallthrough=0) +endif() + set_source_files_properties(${DUNE_SQLITE3_FILES} - PROPERTIES COMPILE_FLAGS "${DUNE_C_FLAGS} ${SQLITE3_C_FLAGS}") + PROPERTIES COMPILE_FLAGS "${DUNE_C_FLAGS} ${SQLITE3_C_FLAGS} ${_sqlite3_extra_cflags}") list(APPEND DUNE_VENDOR_FILES ${DUNE_SQLITE3_FILES}) diff --git a/vendor/libraries/sqlite3/sqlite3.c b/vendor/libraries/sqlite3/sqlite3.c index dbf4d56381..0b227f0e60 100644 --- a/vendor/libraries/sqlite3/sqlite3.c +++ b/vendor/libraries/sqlite3/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.17.0. By combining all the individual C code files into this +** version 3.38.2. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -60,10 +60,10 @@ ** ** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread ** that would be harmless and undetectable -** if it did occur. +** if it did occur. ** ** In all cases, the special comment must be enclosed in the usual -** slash-asterisk...asterisk-slash comment marks, with no spaces between the +** slash-asterisk...asterisk-slash comment marks, with no spaces between the ** asterisks and the comment text. */ @@ -75,14 +75,6 @@ # define SQLITE_TCLAPI #endif -/* -** Make sure that rand_s() is available on Windows systems with MSVC 2005 -** or higher. -*/ -#if defined(_MSC_VER) && _MSC_VER>=1400 -# define _CRT_RAND_S -#endif - /* ** Include the header file used to customize the compiler options for MSVC. ** This should be done first so that it can successfully prevent spurious @@ -126,6 +118,11 @@ #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ +#if defined(_MSC_VER) && !defined(_WIN64) +#undef SQLITE_4_BYTE_ALIGNED_MALLOC +#define SQLITE_4_BYTE_ALIGNED_MALLOC +#endif /* defined(_MSC_VER) && !defined(_WIN64) */ + #endif /* SQLITE_MSVC_H */ /************** End of msvc.h ************************************************/ @@ -204,29 +201,42 @@ # define _LARGEFILE_SOURCE 1 #endif -/* The GCC_VERSION, CLANG_VERSION, and MSVC_VERSION macros are used to +/* The GCC_VERSION and MSVC_VERSION macros are used to ** conditionally include optimizations for each of these compilers. A ** value of 0 means that compiler is not being used. The ** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific ** optimizations, and hence set all compiler macros to 0 +** +** There was once also a CLANG_VERSION macro. However, we learn that the +** version numbers in clang are for "marketing" only and are inconsistent +** and unreliable. Fortunately, all versions of clang also recognize the +** gcc version numbers and have reasonable settings for gcc version numbers, +** so the GCC_VERSION macro will be set to a correct non-zero value even +** when compiling with clang. */ #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else # define GCC_VERSION 0 #endif -#if defined(__clang__) && !defined(_WIN32) && !defined(SQLITE_DISABLE_INTRINSIC) -# define CLANG_VERSION \ - (__clang_major__*1000000+__clang_minor__*1000+__clang_patchlevel__) -#else -# define CLANG_VERSION 0 -#endif #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif +/* +** Some C99 functions in "math.h" are only present for MSVC when its version +** is associated with Visual Studio 2013 or higher. +*/ +#ifndef SQLITE_HAVE_C99_MATH_FUNCS +# if MSVC_VERSION==0 || MSVC_VERSION>=1800 +# define SQLITE_HAVE_C99_MATH_FUNCS (1) +# else +# define SQLITE_HAVE_C99_MATH_FUNCS (0) +# endif +#endif + /* Needed for various definitions... */ #if defined(__GNUC__) && !defined(_GNU_SOURCE) # define _GNU_SOURCE @@ -236,6 +246,15 @@ # define _BSD_SOURCE #endif +/* +** Macro to disable warnings about missing "break" at the end of a "case". +*/ +#if GCC_VERSION>=7000000 +# define deliberate_fall_through __attribute__((fallthrough)); +#else +# define deliberate_fall_through +#endif + /* ** For MinGW, check to see if we can include the header file containing its ** version information, among other things. Normally, this internal MinGW @@ -268,6 +287,17 @@ # define _USE_32BIT_TIME_T #endif +/* Optionally #include a user-defined header, whereby compilation options +** may be set prior to where they take effect, but after platform setup. +** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include +** file. +*/ +#ifdef SQLITE_CUSTOM_INCLUDE +# define INC_STRINGIFY_(f) #f +# define INC_STRINGIFY(f) INC_STRINGIFY_(f) +# include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE) +#endif + /* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear ** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for ** MinGW. @@ -275,7 +305,7 @@ /************** Include sqlite3.h in the middle of sqliteInt.h ***************/ /************** Begin file sqlite3.h *****************************************/ /* -** 2001 September 15 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -319,7 +349,30 @@ extern "C" { /* -** Provide the ability to override linkage features of the interface. +** Facilitate override of interface linkage and calling conventions. +** Be aware that these macros may not be used within this particular +** translation of the amalgamation and its associated header file. +** +** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the +** compiler that the target identifier should have external linkage. +** +** The SQLITE_CDECL macro is used to set the calling convention for +** public functions that accept a variable number of arguments. +** +** The SQLITE_APICALL macro is used to set the calling convention for +** public functions that accept a fixed number of arguments. +** +** The SQLITE_STDCALL macro is no longer used and is now deprecated. +** +** The SQLITE_CALLBACK macro is used to set the calling convention for +** function pointers. +** +** The SQLITE_SYSAPI macro is used to set the calling convention for +** functions provided by the operating system. +** +** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and +** SQLITE_SYSAPI macros are used only when building for environments +** that require non-default calling conventions. */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern @@ -384,22 +437,24 @@ extern "C" { ** be held constant and Z will be incremented or else Y will be incremented ** and Z will be reset to zero. ** -** Since [version 3.6.18] ([dateof:3.6.18]), +** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the ** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID -** string contains the date and time of the check-in (UTC) and an SHA1 -** hash of the entire source tree. +** string contains the date and time of the check-in (UTC) and a SHA1 +** or SHA3-256 hash of the entire source tree. If the source code has +** been edited in any way since it was last checked in, then the last +** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.17.0" -#define SQLITE_VERSION_NUMBER 3017000 -#define SQLITE_SOURCE_ID "2017-02-13 16:02:40 ada05cfa86ad7f5645450ac7a2a21c9aa6e57d2c" +#define SQLITE_VERSION "3.38.2" +#define SQLITE_VERSION_NUMBER 3038002 +#define SQLITE_SOURCE_ID "2022-03-26 13:51:10 d33c709cc0af66bc5b6dc6216eba9f1f0b40960b9ae83694c986fbf4c1d6f08f" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -415,7 +470,7 @@ extern "C" { ** **
 ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
 ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
 ** 
)^ ** @@ -425,9 +480,11 @@ extern "C" { ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to -** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns -** a pointer to a string constant whose value is the same as the -** [SQLITE_SOURCE_ID] C preprocessor macro. +** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns +** a pointer to a string constant whose value is the same as the +** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built +** using an edited copy of [the amalgamation], then the last four characters +** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ @@ -439,20 +496,20 @@ SQLITE_API int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics ** -** ^The sqlite3_compileoption_used() function returns 0 or 1 -** indicating whether the specified option was defined at -** compile time. ^The SQLITE_ prefix may be omitted from the -** option name passed to sqlite3_compileoption_used(). +** ^The sqlite3_compileoption_used() function returns 0 or 1 +** indicating whether the specified option was defined at +** compile time. ^The SQLITE_ prefix may be omitted from the +** option name passed to sqlite3_compileoption_used(). ** ** ^The sqlite3_compileoption_get() function allows iterating ** over the list of options that were defined at compile time by ** returning the N-th compile time option string. ^If N is out of range, -** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ -** prefix is omitted from any strings returned by +** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ +** prefix is omitted from any strings returned by ** sqlite3_compileoption_get(). ** ** ^Support for the diagnostic functions sqlite3_compileoption_used() -** and sqlite3_compileoption_get() may be omitted by specifying the +** and sqlite3_compileoption_get() may be omitted by specifying the ** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. ** ** See also: SQL functions [sqlite_compileoption_used()] and @@ -461,6 +518,9 @@ SQLITE_API int sqlite3_libversion_number(void); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); +#else +# define sqlite3_compileoption_used(X) 0 +# define sqlite3_compileoption_get(X) ((void*)0) #endif /* @@ -473,7 +533,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N); ** SQLite can be compiled with or without mutexes. When ** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes ** are enabled and SQLite is threadsafe. When the -** [SQLITE_THREADSAFE] macro is 0, +** [SQLITE_THREADSAFE] macro is 0, ** the mutexes are omitted. Without the mutexes, it is not safe ** to use SQLite concurrently from more than one thread. ** @@ -530,14 +590,14 @@ typedef struct sqlite3 sqlite3; ** ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The -** sqlite3_uint64 and sqlite_uint64 types can store integer values +** sqlite3_uint64 and sqlite_uint64 types can store integer values ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; # ifdef SQLITE_UINT64_TYPE typedef SQLITE_UINT64_TYPE sqlite_uint64; -# else +# else typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; # endif #elif defined(_MSC_VER) || defined(__BORLANDC__) @@ -568,26 +628,22 @@ typedef sqlite_uint64 sqlite3_uint64; ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** -** ^If the database connection is associated with unfinalized prepared -** statements or unfinished sqlite3_backup objects then sqlite3_close() -** will leave the database connection open and return [SQLITE_BUSY]. -** ^If sqlite3_close_v2() is called with unfinalized prepared statements -** and/or unfinished sqlite3_backups, then the database connection becomes -** an unusable "zombie" which will automatically be deallocated when the -** last prepared statement is finalized or the last sqlite3_backup is -** finished. The sqlite3_close_v2() interface is intended for use with -** host languages that are garbage collected, and where the order in which -** destructors are called is arbitrary. -** -** Applications should [sqlite3_finalize | finalize] all [prepared statements], -** [sqlite3_blob_close | close] all [BLOB handles], and +** Ideally, applications should [sqlite3_finalize | finalize] all +** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated -** with the [sqlite3] object prior to attempting to close the object. ^If -** sqlite3_close_v2() is called on a [database connection] that still has -** outstanding [prepared statements], [BLOB handles], and/or -** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation -** of resources is deferred until all [prepared statements], [BLOB handles], -** and [sqlite3_backup] objects are also destroyed. +** with the [sqlite3] object prior to attempting to close the object. +** ^If the database connection is associated with unfinalized prepared +** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then +** sqlite3_close() will leave the database connection open and return +** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared +** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups, +** it returns [SQLITE_OK] regardless, but instead of deallocating the database +** connection immediately, it marks the database connection as an unusable +** "zombie" and makes arrangements to automatically deallocate the database +** connection after all prepared statements are finalized, all BLOB handles +** are closed, and all backups have finished. The sqlite3_close_v2() interface +** is intended for use with host languages that are garbage collected, and +** where the order in which destructors are called is arbitrary. ** ** ^If an [sqlite3] object is destroyed while a transaction is open, ** the transaction is automatically rolled back. @@ -617,7 +673,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** The sqlite3_exec() interface is a convenience wrapper around ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], ** that allows an application to run multiple statements of SQL -** without having to use a lot of C code. +** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, ** semicolon-separate SQL statements passed into its 2nd argument, @@ -657,7 +713,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer -** to an empty string, or a pointer that contains only whitespace and/or +** to an empty string, or a pointer that contains only whitespace and/or ** SQL comments, then no SQL statements are evaluated and the database ** is not changed. ** @@ -693,7 +749,7 @@ SQLITE_API int sqlite3_exec( */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_ERROR 1 /* Generic error */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ @@ -708,7 +764,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_EMPTY 16 /* Internal use only */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -716,7 +772,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_FORMAT 24 /* Not used */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ @@ -742,6 +798,9 @@ SQLITE_API int sqlite3_exec( ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ +#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) +#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) +#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) @@ -770,18 +829,31 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) +#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) +#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) +#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) +#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) +#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ +#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) +#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) +#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) +#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) @@ -793,11 +865,14 @@ SQLITE_API int sqlite3_exec( #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) +#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) +#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations @@ -805,6 +880,19 @@ SQLITE_API int sqlite3_exec( ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. +** +** Only those flags marked as "Ok for sqlite3_open_v2()" may be +** used as the third argument to the [sqlite3_open_v2()] interface. +** The other flags have historically been ignored by sqlite3_open_v2(), +** though future versions of SQLite might change so that an error is +** raised if any of the disallowed bits are passed into sqlite3_open_v2(). +** Applications should not depend on the historical behavior. +** +** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into +** [sqlite3_open_v2()] does *not* cause the underlying database file +** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into +** [sqlite3_open_v2()] has historically be a no-op and might become an +** error in future versions of SQLite. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ @@ -820,14 +908,19 @@ SQLITE_API int sqlite3_exec( #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ #define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ -#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ +#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */ #define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ +#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ +/* Legacy compatibility: */ +#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ + /* ** CAPI3REF: Device Characteristics @@ -856,6 +949,11 @@ SQLITE_API int sqlite3_exec( ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on ** read-only media and cannot be changed even by processes with ** elevated privileges. +** +** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying +** filesystem supports doing multiple write operations atomically when those +** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and +** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -871,6 +969,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 +#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels @@ -918,7 +1017,7 @@ SQLITE_API int sqlite3_exec( /* ** CAPI3REF: OS Interface Open File Handle ** -** An [sqlite3_file] object represents an open file in the +** An [sqlite3_file] object represents an open file in the ** [sqlite3_vfs | OS interface layer]. Individual OS interface ** implementations will ** want to subclass this object by appending additional fields @@ -940,7 +1039,7 @@ struct sqlite3_file { ** This object defines the methods used to perform various operations ** against the open file represented by the [sqlite3_file] object. ** -** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method ** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The ** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] @@ -1005,6 +1104,7 @@ struct sqlite3_file { **
  • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] **
  • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
  • [SQLITE_IOCAP_IMMUTABLE] +**
  • [SQLITE_IOCAP_BATCH_ATOMIC] ** ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -1077,10 +1177,19 @@ struct sqlite3_io_methods { ** file space based on this hint in order to help writes to the database ** file run faster. ** +**
  • [[SQLITE_FCNTL_SIZE_LIMIT]] +** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that +** implements [sqlite3_deserialize()] to set an upper bound on the size +** of the in-memory database. The argument is a pointer to a [sqlite3_int64]. +** If the integer pointed to is negative, then it is filled in with the +** current limit. Otherwise the limit is set to the larger of the value +** of the integer pointed to and the current database size. The integer +** pointed to is set to the new limit. +** **
  • [[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified -** by the user. The fourth argument to [sqlite3_file_control()] should +** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and @@ -1103,24 +1212,24 @@ struct sqlite3_io_methods { **
  • [[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and ** sent to the VFS immediately before the xSync method is invoked on a -** database file descriptor. Or, if the xSync method is not invoked -** because the user has configured SQLite with -** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place +** database file descriptor. Or, if the xSync method is not invoked +** because the user has configured SQLite with +** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place ** of the xSync method. In most cases, the pointer argument passed with ** this file-control is NULL. However, if the database file is being synced ** as part of a multi-database commit, the argument points to a nul-terminated -** string containing the transactions master-journal file name. VFSes that -** do not need this signal should silently ignore this opcode. Applications -** should not call [sqlite3_file_control()] with this opcode as doing so may -** disrupt the operation of the specialized VFSes that do require it. +** string containing the transactions super-journal file name. VFSes that +** do not need this signal should silently ignore this opcode. Applications +** should not call [sqlite3_file_control()] with this opcode as doing so may +** disrupt the operation of the specialized VFSes that do require it. ** **
  • [[SQLITE_FCNTL_COMMIT_PHASETWO]] ** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite ** and sent to the VFS after a transaction has been committed immediately ** but before the database is unlocked. VFSes that do not need this signal ** should silently ignore this opcode. Applications should not call -** [sqlite3_file_control()] with this opcode as doing so may disrupt the -** operation of the specialized VFSes that do require it. +** [sqlite3_file_control()] with this opcode as doing so may disrupt the +** operation of the specialized VFSes that do require it. ** **
  • [[SQLITE_FCNTL_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic @@ -1133,7 +1242,7 @@ struct sqlite3_io_methods { ** opcode allows these two values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two -** integers where the first integer i the new retry count and the second +** integers where the first integer is the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be @@ -1142,7 +1251,8 @@ struct sqlite3_io_methods { **
  • [[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary -** write ahead log and shared memory files used for transaction control +** write ahead log ([WAL file]) and shared memory +** files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not @@ -1167,13 +1277,13 @@ struct sqlite3_io_methods { **
  • [[SQLITE_FCNTL_OVERWRITE]] ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** a write transaction to indicate that, unless it is rolled back for some -** reason, the entire database file will be overwritten by the current +** reason, the entire database file will be overwritten by the current ** transaction. This is used by VACUUM operations. ** **
  • [[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of ** all [VFSes] in the VFS stack. The names are of all VFS shims and the -** final bottom-level VFS are written into memory obtained from +** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. ** The caller is responsible for freeing the memory when done. As with @@ -1192,7 +1302,7 @@ struct sqlite3_io_methods { ** upper-most shim only. ** **
  • [[SQLITE_FCNTL_PRAGMA]] -** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] +** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] ** file control is sent to the open [sqlite3_file] object corresponding ** to the database file to which the pragma statement refers. ^The argument ** to the [SQLITE_FCNTL_PRAGMA] file control is an array of @@ -1203,7 +1313,7 @@ struct sqlite3_io_methods { ** of the char** argument point to a string obtained from [sqlite3_mprintf()] ** or the equivalent and that string will become the result of the pragma or ** the error message if the pragma fails. ^If the -** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal +** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] ** file control returns [SQLITE_OK], then the parser assumes that the ** VFS has handled the PRAGMA itself and the parser generates a no-op @@ -1220,16 +1330,16 @@ struct sqlite3_io_methods { ** ^The [SQLITE_FCNTL_BUSYHANDLER] ** file-control may be invoked by SQLite on the database file handle ** shortly after it is opened in order to provide a custom VFS with access -** to the connections busy-handler callback. The argument is of type (void **) +** to the connection's busy-handler callback. The argument is of type (void**) ** - an array of two (void *) values. The first (void *) actually points -** to a function of type (int (*)(void *)). In order to invoke the connections +** to a function of type (int (*)(void *)). In order to invoke the connection's ** busy-handler, this function should be invoked with the second (void *) in ** the array as the only argument. If it returns non-zero, then the operation ** should be retried. If it returns zero, the custom VFS should abandon the ** current operation. ** **
  • [[SQLITE_FCNTL_TEMPFILENAME]] -** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control +** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control ** to have SQLite generate a ** temporary filename using the same algorithm that is followed to generate ** temporary filenames for TEMP tables and other internal uses. The @@ -1243,7 +1353,7 @@ struct sqlite3_io_methods { ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if -** the value originally pointed to is negative, and so the current limit +** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** @@ -1287,7 +1397,97 @@ struct sqlite3_io_methods { **
  • [[SQLITE_FCNTL_RBU]] ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for -** this opcode. +** this opcode. +** +**
  • [[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] +** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then +** the file descriptor is placed in "batch write mode", which +** means all subsequent write operations will be deferred and done +** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems +** that do not support batch atomic writes will return SQLITE_NOTFOUND. +** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to +** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or +** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make +** no VFS interface calls on the same [sqlite3_file] file descriptor +** except for calls to the xWrite method and the xFileControl method +** with [SQLITE_FCNTL_SIZE_HINT]. +** +**
  • [[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. +** This file control returns [SQLITE_OK] if and only if the writes were +** all performed successfully and have been committed to persistent storage. +** ^Regardless of whether or not it is successful, this file control takes +** the file descriptor out of batch write mode so that all subsequent +** write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +**
  • [[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. +** ^This file control takes the file descriptor out of batch write mode +** so that all subsequent write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +**
  • [[SQLITE_FCNTL_LOCK_TIMEOUT]] +** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS +** to block for up to M milliseconds before failing when attempting to +** obtain a file lock using the xLock or xShmLock methods of the VFS. +** The parameter is a pointer to a 32-bit signed integer that contains +** the value that M is to be set to. Before returning, the 32-bit signed +** integer is overwritten with the previous value of M. +** +**
  • [[SQLITE_FCNTL_DATA_VERSION]] +** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to +** a database file. The argument is a pointer to a 32-bit unsigned integer. +** The "data version" for the pager is written into the pointer. The +** "data version" changes whenever any change occurs to the corresponding +** database file, either through SQL statements on the same database +** connection or through transactions committed by separate database +** connections possibly in other processes. The [sqlite3_total_changes()] +** interface can be used to find if any database on the connection has changed, +** but that interface responds to changes on TEMP as well as MAIN and does +** not provide a mechanism to detect changes to MAIN only. Also, the +** [sqlite3_total_changes()] interface responds to internal changes only and +** omits changes made by other database connections. The +** [PRAGMA data_version] command provides a mechanism to detect changes to +** a single attached database that occur due to other database connections, +** but omits changes implemented by the database connection on which it is +** called. This file control is the only mechanism to detect changes that +** happen either internally or externally and that are associated with +** a particular attached database. +** +**
  • [[SQLITE_FCNTL_CKPT_START]] +** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint +** in wal mode before the client starts to copy pages from the wal +** file to the database file. +** +**
  • [[SQLITE_FCNTL_CKPT_DONE]] +** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint +** in wal mode after the client has finished copying pages from the wal +** file to the database file, but before the *-shm file is updated to +** record the fact that the pages have been checkpointed. +** +** +**
  • [[SQLITE_FCNTL_EXTERNAL_READER]] +** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect +** whether or not there is a database client in another process with a wal-mode +** transaction open on the database or not. It is only available on unix.The +** (void*) argument passed with this file-control should be a pointer to a +** value of type (int). The integer value is set to 1 if the database is a wal +** mode database and there exists at least one client in another process that +** currently has an SQL transaction open on the database. It is set to 0 if +** the database is not a wal-mode db, or if there is no such connection in any +** other process. This opcode cannot be used to detect transactions opened +** by clients within the current process, only within other processes. +** +** +**
  • [[SQLITE_FCNTL_CKSM_FILE]] +** Used by the cksmvfs VFS module only. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1319,6 +1519,17 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_JOURNAL_POINTER 28 #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 +#define SQLITE_FCNTL_LOCK_TIMEOUT 34 +#define SQLITE_FCNTL_DATA_VERSION 35 +#define SQLITE_FCNTL_SIZE_LIMIT 36 +#define SQLITE_FCNTL_CKPT_DONE 37 +#define SQLITE_FCNTL_RESERVE_BYTES 38 +#define SQLITE_FCNTL_CKPT_START 39 +#define SQLITE_FCNTL_EXTERNAL_READER 40 +#define SQLITE_FCNTL_CKSM_FILE 41 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1356,12 +1567,18 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. ** -** The value of the iVersion field is initially 1 but may be larger in -** future versions of SQLite. Additional fields may be appended to this -** object when the iVersion value is increased. Note that the structure -** of the sqlite3_vfs object changes in the transaction between -** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not -** modified. +** The VFS interface is sometimes extended by adding new methods onto +** the end. Each time such an extension occurs, the iVersion field +** is incremented. The iVersion value started out as 1 in +** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2 +** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased +** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields +** may be appended to the sqlite3_vfs object and the iVersion value +** may increase again in future versions of SQLite. +** Note that due to an oversight, the structure +** of the sqlite3_vfs object changed in the transition from +** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0] +** and yet the iVersion field was not increased. ** ** The szOsFile field is the size of the subclassed [sqlite3_file] ** structure used by this VFS. mxPathname is the maximum length of @@ -1396,14 +1613,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** the [sqlite3_file] can safely store a pointer to the ** filename if it needs to remember the filename for some reason. ** If the zFilename parameter to xOpen is a NULL pointer then xOpen -** must invent its own temporary name for the file. ^Whenever the +** must invent its own temporary name for the file. ^Whenever the ** xFilename parameter is NULL it will also be the case that the ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. ** ** The flags argument to xOpen() includes all bits set in ** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] ** or [sqlite3_open16()] is used, then flags includes at least -** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. +** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. ** If xOpen() opens a file read-only then it sets *pOutFlags to ** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. ** @@ -1417,7 +1634,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; **
  • [SQLITE_OPEN_TEMP_JOURNAL] **
  • [SQLITE_OPEN_TRANSIENT_DB] **
  • [SQLITE_OPEN_SUBJOURNAL] -**
  • [SQLITE_OPEN_MASTER_JOURNAL] +**
  • [SQLITE_OPEN_SUPER_JOURNAL] **
  • [SQLITE_OPEN_WAL] ** )^ ** @@ -1445,14 +1662,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction ** with the [SQLITE_OPEN_CREATE] flag, which are both directly ** analogous to the O_EXCL and O_CREAT flags of the POSIX open() -** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the +** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the ** SQLITE_OPEN_CREATE, is used to indicate that file should always ** be created, and that it is an error if it already exists. -** It is not used to indicate the file should be opened +** It is not used to indicate the file should be opened ** for exclusive access. ** ** ^At least szOsFile bytes of memory are allocated by SQLite -** to hold the [sqlite3_file] structure passed as the third +** to hold the [sqlite3_file] structure passed as the third ** argument to xOpen. The xOpen method does not have to ** allocate the structure; it should just fill it in. Note that ** the xOpen method must set the sqlite3_file.pMethods to either @@ -1465,8 +1682,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] -** to test whether a file is at least readable. The file can be a -** directory. +** to test whether a file is at least readable. The SQLITE_ACCESS_READ +** flag is never actually used and is not implemented in the built-in +** VFSes of SQLite. The file is named by the second argument and can be a +** directory. The xAccess method returns [SQLITE_OK] on success or some +** non-zero error code if there is an I/O error or if the name of +** the file given in the second argument is illegal. If SQLITE_OK +** is returned, then non-zero or zero is written into *pResOut to indicate +** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer @@ -1486,16 +1709,16 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** method returns a Julian Day Number for the current date and time as ** a floating point value. ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian -** Day Number multiplied by 86400000 (the number of milliseconds in -** a 24-hour day). +** Day Number multiplied by 86400000 (the number of milliseconds in +** a 24-hour day). ** ^SQLite will use the xCurrentTimeInt64() method to get the current -** date and time if that method is available (if iVersion is 2 or +** date and time if that method is available (if iVersion is 2 or ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided -** by some VFSes to facilitate testing of the VFS code. By overriding +** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can ** simulate faults and error conditions that would otherwise be difficult ** or impossible to induce. The set of system calls that can be overridden @@ -1542,7 +1765,7 @@ struct sqlite3_vfs { /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in future versions. The iVersion - ** value will increment whenever this happens. + ** value will increment whenever this happens. */ }; @@ -1586,7 +1809,7 @@ struct sqlite3_vfs { ** ** ** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as -** was given on the corresponding lock. +** was given on the corresponding lock. ** ** The xShmLock method can transition between unlocked and SHARED or ** between unlocked and EXCLUSIVE. It cannot transition between SHARED @@ -1731,7 +1954,7 @@ SQLITE_API int sqlite3_config(int, ...); ** [database connection] (specified in the first argument). ** ** The second argument to sqlite3_db_config(D,V,...) is the -** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code +** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code ** that indicates what aspect of the [database connection] is being configured. ** Subsequent arguments vary depending on the configuration verb. ** @@ -1749,7 +1972,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); ** This object is used in only one place in the SQLite interface. ** A pointer to an instance of this object is the argument to ** [sqlite3_config()] when the configuration option is -** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. +** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. ** By creating an instance of this object ** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) ** during configuration, an application can specify an alternative @@ -1779,17 +2002,17 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] -** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, +** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. For example, -** it might allocate any require mutexes or initialize internal data +** it might allocate any required mutexes or initialize internal data ** structures. The xShutdown method is invoked (indirectly) by ** [sqlite3_shutdown()] and should deallocate any resources acquired ** by xInit. The pAppData pointer is used as the only parameter to ** xInit and xShutdown. ** -** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes +** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes ** the xInit method, so the xInit method need not be threadsafe. The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. For all other methods, SQLite @@ -1837,7 +2060,7 @@ struct sqlite3_mem_methods { ** by a single thread. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to change the [threading mode] from its default -** value of Single-thread and so [sqlite3_config()] will return +** value of Single-thread and so [sqlite3_config()] will return ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD ** configuration option. ** @@ -1872,7 +2095,7 @@ struct sqlite3_mem_methods { ** SQLITE_CONFIG_SERIALIZED configuration option. ** ** [[SQLITE_CONFIG_MALLOC]]
    SQLITE_CONFIG_MALLOC
    -**
    ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is +**
    ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is ** a pointer to an instance of the [sqlite3_mem_methods] structure. ** The argument specifies ** alternative low-level memory allocation routines to be used in place of @@ -1889,12 +2112,23 @@ struct sqlite3_mem_methods { ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
    ** +** [[SQLITE_CONFIG_SMALL_MALLOC]]
    SQLITE_CONFIG_SMALL_MALLOC
    +**
    ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +** type int, interpreted as a boolean, which if true provides a hint to +** SQLite that it should avoid large memory allocations if possible. +** SQLite will run faster if it is free to make large memory allocations, +** but some application might prefer to run slower in exchange for +** guarantees about memory fragmentation that are possible if large +** allocations are avoided. This hint is normally off. +**
    +** ** [[SQLITE_CONFIG_MEMSTATUS]]
    SQLITE_CONFIG_MEMSTATUS
    **
    ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: **
      +**
    • [sqlite3_hard_heap_limit64()] **
    • [sqlite3_memory_used()] **
    • [sqlite3_memory_highwater()] **
    • [sqlite3_soft_heap_limit64()] @@ -1906,32 +2140,14 @@ struct sqlite3_mem_methods { **
    ** ** [[SQLITE_CONFIG_SCRATCH]]
    SQLITE_CONFIG_SCRATCH
    -**
    ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer -** that SQLite can use for scratch memory. ^(There are three arguments -** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte -** aligned memory buffer from which the scratch allocations will be -** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ -** The first argument must be a pointer to an 8-byte aligned buffer -** of at least sz*N bytes of memory. -** ^SQLite will not use more than one scratch buffers per thread. -** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size. -** ^If SQLite needs needs additional -** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.

    -** ^When the application provides any amount of scratch memory using -** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large -** [sqlite3_malloc|heap allocations]. -** This can help [Robson proof|prevent memory allocation failures] due to heap -** fragmentation in low-memory embedded systems. +**

    The SQLITE_CONFIG_SCRATCH option is no longer used. **
    ** ** [[SQLITE_CONFIG_PAGECACHE]]
    SQLITE_CONFIG_PAGECACHE
    **
    ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool ** that SQLite can use for the database page cache with the default page -** cache implementation. -** This configuration option is a no-op if an application-define page +** cache implementation. +** This configuration option is a no-op if an application-defined page ** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]. ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to ** 8-byte aligned memory (pMem), the size of each page cache line (sz), @@ -1958,10 +2174,9 @@ struct sqlite3_mem_methods { ** additional cache line.
    ** ** [[SQLITE_CONFIG_HEAP]]
    SQLITE_CONFIG_HEAP
    -**
    ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer +**
    ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs -** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and -** [SQLITE_CONFIG_PAGECACHE]. +** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. @@ -2014,7 +2229,7 @@ struct sqlite3_mem_methods { ** configuration on individual connections.)^
    ** ** [[SQLITE_CONFIG_PCACHE2]]
    SQLITE_CONFIG_PCACHE2
    -**
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is +**
    ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is ** a pointer to an [sqlite3_pcache_methods2] object. This object specifies ** the interface to a custom page cache implementation.)^ ** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
    @@ -2028,7 +2243,7 @@ struct sqlite3_mem_methods { **
    The SQLITE_CONFIG_LOG option is used to configure the SQLite ** global [error log]. ** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a -** function with a call signature of void(*)(void*,int,const char*), +** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. @@ -2137,7 +2352,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_CONFIG_STMTJRNL_SPILL]] **
    SQLITE_CONFIG_STMTJRNL_SPILL **
    ^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which -** becomes the [statement journal] spill-to-disk threshold. +** becomes the [statement journal] spill-to-disk threshold. ** [Statement journals] are held in memory until their size (in bytes) ** exceeds this threshold, at which point they are written to disk. ** Or if the threshold is -1, statement journals are always held @@ -2147,6 +2362,33 @@ struct sqlite3_mem_methods { ** I/O required to support statement rollback. ** The default value for this setting is controlled by the ** [SQLITE_STMTJRNL_SPILL] compile-time option. +** +** [[SQLITE_CONFIG_SORTERREF_SIZE]] +**
    SQLITE_CONFIG_SORTERREF_SIZE +**
    The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter +** of type (int) - the new value of the sorter-reference size threshold. +** Usually, when SQLite uses an external sort to order records according +** to an ORDER BY clause, all fields required by the caller are present in the +** sorted records. However, if SQLite determines based on the declared type +** of a table column that its values are likely to be very large - larger +** than the configured sorter-reference size threshold - then a reference +** is stored in each sorted record and the required column values loaded +** from the database as records are returned in sorted order. The default +** value for this option is to never use this optimization. Specifying a +** negative value for this option restores the default behaviour. +** This option is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. +** +** [[SQLITE_CONFIG_MEMDB_MAXSIZE]] +**
    SQLITE_CONFIG_MEMDB_MAXSIZE +**
    The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter +** [sqlite3_int64] parameter which is the default maximum size for an in-memory +** database created using [sqlite3_deserialize()]. This default maximum +** size can be adjusted up or down for individual databases using the +** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this +** configuration setting is never used, then the default maximum is determined +** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that +** compile-time option is not set, then the default maximum is 1073741824. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -2154,13 +2396,13 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ -/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ +/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ #define SQLITE_CONFIG_PCACHE 14 /* no-op */ #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ @@ -2175,6 +2417,9 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ +#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ +#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ +#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options @@ -2190,8 +2435,9 @@ struct sqlite3_mem_methods { ** is invoked. ** **
    +** [[SQLITE_DBCONFIG_LOOKASIDE]] **
    SQLITE_DBCONFIG_LOOKASIDE
    -**
    ^This option takes three additional arguments that determine the +**
    ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. ** ^The first argument (the third parameter to [sqlite3_db_config()] is a ** pointer to a memory buffer to use for lookaside memory. @@ -2209,9 +2455,10 @@ struct sqlite3_mem_methods { ** when the "current value" returned by ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside -** memory is in use leaves the configuration unchanged and returns +** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
    ** +** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
    SQLITE_DBCONFIG_ENABLE_FKEY
    **
    ^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. @@ -2222,6 +2469,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]] **
    SQLITE_DBCONFIG_ENABLE_TRIGGER
    **
    ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. @@ -2230,11 +2478,35 @@ struct sqlite3_mem_methods { ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in -** which case the trigger setting is not reported back.
    +** which case the trigger setting is not reported back. ** +**

    Originally this option disabled all triggers. ^(However, since +** SQLite version 3.35.0, TEMP triggers are still allowed even if +** this option is off. So, in other words, this option now only disables +** triggers in the main database schema or in the schemas of ATTACH-ed +** databases.)^

    +** +** [[SQLITE_DBCONFIG_ENABLE_VIEW]] +**
    SQLITE_DBCONFIG_ENABLE_VIEW
    +**
    ^This option is used to enable or disable [CREATE VIEW | views]. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable views, +** positive to enable views or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether views are disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the view setting is not reported back. +** +**

    Originally this option disabled all views. ^(However, since +** SQLite version 3.35.0, TEMP views are still allowed even if +** this option is off. So, in other words, this option now only disables +** views in the main database schema or in the schemas of ATTACH-ed +** databases.)^

    +** +** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
    SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
    -**
    ^This option is used to enable or disable the two-argument -** version of the [fts3_tokenizer()] function which is part of the +**
    ^This option is used to enable or disable the +** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or @@ -2245,6 +2517,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the new setting is not reported back.
    ** +** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
    **
    ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. @@ -2262,7 +2535,7 @@ struct sqlite3_mem_methods { ** be a NULL pointer, in which case the new setting is not reported back. **
    ** -**
    SQLITE_DBCONFIG_MAINDBNAME
    +** [[SQLITE_DBCONFIG_MAINDBNAME]]
    SQLITE_DBCONFIG_MAINDBNAME
    **
    ^This option is used to change the name of the "main" database ** schema. ^The sole argument is a pointer to a constant UTF8 string ** which will become the new schema name in place of "main". ^SQLite @@ -2271,18 +2544,162 @@ struct sqlite3_mem_methods { ** until after the database connection closes. **
    ** +** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
    SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
    -**
    Usually, when a database in wal mode is closed or detached from a -** database handle, SQLite checks if this will mean that there are now no -** connections at all to the database. If so, it performs a checkpoint +**
    Usually, when a database in wal mode is closed or detached from a +** database handle, SQLite checks if this will mean that there are now no +** connections at all to the database. If so, it performs a checkpoint ** operation before closing the connection. This option may be used to ** override this behaviour. The first parameter passed to this operation -** is an integer - non-zero to disable checkpoints-on-close, or zero (the -** default) to enable them. The second parameter is a pointer to an integer +** is an integer - positive to disable checkpoints-on-close, or zero (the +** default) to enable them, and negative to leave the setting unchanged. +** The second parameter is a pointer to an integer ** into which is written 0 or 1 to indicate whether checkpoints-on-close ** have been disabled - 0 if they are not disabled, 1 if they are. **
    ** +** [[SQLITE_DBCONFIG_ENABLE_QPSG]]
    SQLITE_DBCONFIG_ENABLE_QPSG
    +**
    ^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates +** the [query planner stability guarantee] (QPSG). When the QPSG is active, +** a single SQL query statement will always use the same algorithm regardless +** of values of [bound parameters].)^ The QPSG disables some query optimizations +** that look at the values of bound parameters, which can make some queries +** slower. But the QPSG has the advantage of more predictable behavior. With +** the QPSG active, SQLite will always use the same query plan in the field as +** was used during testing in the lab. +** The first argument to this setting is an integer which is 0 to disable +** the QPSG, positive to enable QPSG, or negative to leave the setting +** unchanged. The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether the QPSG is disabled or enabled +** following this call. +**
    +** +** [[SQLITE_DBCONFIG_TRIGGER_EQP]]
    SQLITE_DBCONFIG_TRIGGER_EQP
    +**
    By default, the output of EXPLAIN QUERY PLAN commands does not +** include output for any operations performed by trigger programs. This +** option is used to set or clear (the default) a flag that governs this +** behavior. The first parameter passed to this operation is an integer - +** positive to enable output for trigger programs, or zero to disable it, +** or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which is written +** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if +** it is not disabled, 1 if it is. +**
    +** +** [[SQLITE_DBCONFIG_RESET_DATABASE]]
    SQLITE_DBCONFIG_RESET_DATABASE
    +**
    Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run +** [VACUUM] in order to reset a database back to an empty database +** with no schema and no content. The following process works even for +** a badly corrupted database file: +**
      +**
    1. If the database connection is newly opened, make sure it has read the +** database schema by preparing then discarding some query against the +** database, or calling sqlite3_table_column_metadata(), ignoring any +** errors. This step is only necessary if the application desires to keep +** the database in WAL mode after the reset if it was in WAL mode before +** the reset. +**
    2. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); +**
    3. [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); +**
    4. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); +**
    +** Because resetting a database is destructive and irreversible, the +** process requires the use of this obscure API and multiple steps to help +** ensure that it does not happen by accident. +** +** [[SQLITE_DBCONFIG_DEFENSIVE]]
    SQLITE_DBCONFIG_DEFENSIVE
    +**
    The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the +** "defensive" flag for a database connection. When the defensive +** flag is enabled, language features that allow ordinary SQL to +** deliberately corrupt the database file are disabled. The disabled +** features include but are not limited to the following: +**
      +**
    • The [PRAGMA writable_schema=ON] statement. +**
    • The [PRAGMA journal_mode=OFF] statement. +**
    • Writes to the [sqlite_dbpage] virtual table. +**
    • Direct writes to [shadow tables]. +**
    +**
    +** +** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]]
    SQLITE_DBCONFIG_WRITABLE_SCHEMA
    +**
    The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the +** "writable_schema" flag. This has the same effect and is logically equivalent +** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. +** The first argument to this setting is an integer which is 0 to disable +** the writable_schema, positive to enable writable_schema, or negative to +** leave the setting unchanged. The second parameter is a pointer to an +** integer into which is written 0 or 1 to indicate whether the writable_schema +** is enabled or disabled following this call. +**
    +** +** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] +**
    SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
    +**
    The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates +** the legacy behavior of the [ALTER TABLE RENAME] command such it +** behaves as it did prior to [version 3.24.0] (2018-06-04). See the +** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for +** additional information. This feature can also be turned on and off +** using the [PRAGMA legacy_alter_table] statement. +**
    +** +** [[SQLITE_DBCONFIG_DQS_DML]] +**
    SQLITE_DBCONFIG_DQS_DML +**
    The SQLITE_DBCONFIG_DQS_DML option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DML statements +** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +**
    +** +** [[SQLITE_DBCONFIG_DQS_DDL]] +**
    SQLITE_DBCONFIG_DQS_DDL +**
    The SQLITE_DBCONFIG_DQS option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DDL statements, +** such as CREATE TABLE and CREATE INDEX. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +**
    +** +** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] +**
    SQLITE_DBCONFIG_TRUSTED_SCHEMA +**
    The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to +** assume that database schemas are untainted by malicious content. +** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite +** takes additional defensive steps to protect the application from harm +** including: +**
      +**
    • Prohibit the use of SQL functions inside triggers, views, +** CHECK constraints, DEFAULT clauses, expression indexes, +** partial indexes, or generated columns +** unless those functions are tagged with [SQLITE_INNOCUOUS]. +**
    • Prohibit the use of virtual tables inside of triggers or views +** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS]. +**
    +** This setting defaults to "on" for legacy compatibility, however +** all applications are advised to turn it off if possible. This setting +** can also be controlled using the [PRAGMA trusted_schema] statement. +**
    +** +** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] +**
    SQLITE_DBCONFIG_LEGACY_FILE_FORMAT +**
    The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates +** the legacy file format flag. When activated, this flag causes all newly +** created database file to have a schema format version number (the 4-byte +** integer found at offset 44 into the database header) of 1. This in turn +** means that the resulting database file will be readable and writable by +** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, +** newly created databases are generally not understandable by SQLite versions +** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there +** is now scarcely any need to generated database files that are compatible +** all the way back to version 3.0.0, and so this setting is of little +** practical use, but is provided so that SQLite can continue to claim the +** ability to generate new database files that are compatible with version +** 3.0.0. +**

    Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on, +** the [VACUUM] command will fail with an obscure error when attempting to +** process a table with generated columns and a descending index. This is +** not considered a bug since SQLite versions 3.3.0 and earlier do not support +** either generated columns or decending indexes. +**

    ** */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2292,7 +2709,18 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ - +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ +#define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ +#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ +#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ +#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -2316,20 +2744,30 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** -** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the -** most recent successful [INSERT] into a rowid table or [virtual table] -** on database connection D. -** ^Inserts into [WITHOUT ROWID] tables are not recorded. -** ^If no successful [INSERT]s into rowid tables -** have ever occurred on the database connection D, -** then sqlite3_last_insert_rowid(D) returns zero. -** -** ^(If an [INSERT] occurs within a trigger or within a [virtual table] -** method, then this routine will return the [rowid] of the inserted -** row as long as the trigger or virtual table method is running. -** But once the trigger or virtual table method ends, the value returned -** by this routine reverts to what it was before the trigger or virtual -** table method began.)^ +** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of +** the most recent successful [INSERT] into a rowid table or [virtual table] +** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not +** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred +** on the database connection D, then sqlite3_last_insert_rowid(D) returns +** zero. +** +** As well as being set automatically as rows are inserted into database +** tables, the value returned by this function may be set explicitly by +** [sqlite3_set_last_insert_rowid()] +** +** Some virtual table implementations may INSERT rows into rowid tables as +** part of committing a transaction (e.g. to flush data accumulated in memory +** to disk). In this case subsequent calls to this function return the rowid +** associated with these internal INSERT operations, which leads to +** unintuitive results. Virtual table implementations that do write to rowid +** tables in this way can avoid this problem by restoring the original +** rowid value using [sqlite3_set_last_insert_rowid()] before returning +** control to the user. +** +** ^(If an [INSERT] occurs within a trigger then this routine will +** return the [rowid] of the inserted row as long as the trigger is +** running. Once the trigger program ends, the value returned +** by this routine reverts to what it was before the trigger was fired.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this @@ -2356,82 +2794,119 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); */ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); +/* +** CAPI3REF: Set the Last Insert Rowid value. +** METHOD: sqlite3 +** +** The sqlite3_set_last_insert_rowid(D, R) method allows the application to +** set the value returned by calling sqlite3_last_insert_rowid(D) to R +** without inserting a row into the database. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); + /* ** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** -** ^This function returns the number of rows modified, inserted or +** ^These functions return the number of rows modified, inserted or ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. -** ^Executing any other type of SQL statement does not modify the value -** returned by this function. +** The two functions are identical except for the type of the return value +** and that if the number of rows modified by the most recent INSERT, UPDATE +** or DELETE is greater than the maximum value supported by type "int", then +** the return value of sqlite3_changes() is undefined. ^Executing any other +** type of SQL statement does not modify the value returned by these functions. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are -** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], +** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], ** [foreign key actions] or [REPLACE] constraint resolution are not counted. -** -** Changes to a view that are intercepted by -** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value -** returned by sqlite3_changes() immediately after an INSERT, UPDATE or -** DELETE statement run on a view is always zero. Only changes made to real +** +** Changes to a view that are intercepted by +** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value +** returned by sqlite3_changes() immediately after an INSERT, UPDATE or +** DELETE statement run on a view is always zero. Only changes made to real ** tables are counted. ** ** Things are more complicated if the sqlite3_changes() function is ** executed while a trigger program is running. This may happen if the ** program uses the [changes() SQL function], or if some other callback ** function invokes sqlite3_changes() directly. Essentially: -** +** **
      **
    • ^(Before entering a trigger program the value returned by -** sqlite3_changes() function is saved. After the trigger program +** sqlite3_changes() function is saved. After the trigger program ** has finished, the original value is restored.)^ -** -**
    • ^(Within a trigger program each INSERT, UPDATE and DELETE -** statement sets the value returned by sqlite3_changes() -** upon completion as normal. Of course, this value will not include -** any changes performed by sub-triggers, as the sqlite3_changes() +** +**
    • ^(Within a trigger program each INSERT, UPDATE and DELETE +** statement sets the value returned by sqlite3_changes() +** upon completion as normal. Of course, this value will not include +** any changes performed by sub-triggers, as the sqlite3_changes() ** value will be saved and restored after each sub-trigger has run.)^ **
    -** +** ** ^This means that if the changes() SQL function (or similar) is used -** by the first INSERT, UPDATE or DELETE statement within a trigger, it +** by the first INSERT, UPDATE or DELETE statement within a trigger, it ** returns the value as set when the calling statement began executing. -** ^If it is used by the second or subsequent such statement within a trigger -** program, the value returned reflects the number of rows modified by the +** ^If it is used by the second or subsequent such statement within a trigger +** program, the value returned reflects the number of rows modified by the ** previous INSERT, UPDATE or DELETE statement within the same trigger. ** -** See also the [sqlite3_total_changes()] interface, the -** [count_changes pragma], and the [changes() SQL function]. -** ** If a separate thread makes changes on the same database connection ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. +** +** See also: +**
      +**
    • the [sqlite3_total_changes()] interface +**
    • the [count_changes pragma] +**
    • the [changes() SQL function] +**
    • the [data_version pragma] +**
    */ SQLITE_API int sqlite3_changes(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** -** ^This function returns the total number of rows inserted, modified or +** ^These functions return the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed ** since the database connection was opened, including those executed as -** part of trigger programs. ^Executing any other type of SQL statement -** does not affect the value returned by sqlite3_total_changes(). -** +** part of trigger programs. The two functions are identical except for the +** type of the return value and that if the number of rows modified by the +** connection exceeds the maximum value supported by type "int", then +** the return value of sqlite3_total_changes() is undefined. ^Executing +** any other type of SQL statement does not affect the value returned by +** sqlite3_total_changes(). +** ** ^Changes made as part of [foreign key actions] are included in the ** count, but those made as part of REPLACE constraint resolution are -** not. ^Changes to a view that are intercepted by INSTEAD OF triggers +** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. -** -** See also the [sqlite3_changes()] interface, the -** [count_changes pragma], and the [total_changes() SQL function]. +** +** The [sqlite3_total_changes(D)] interface only reports the number +** of rows that changed due to SQL statement run against database +** connection D. Any changes by other database connections are ignored. +** To detect changes against a database file from other database +** connections use the [PRAGMA data_version] command or the +** [SQLITE_FCNTL_DATA_VERSION] [file control]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. +** +** See also: +**
      +**
    • the [sqlite3_changes()] interface +**
    • the [count_changes pragma] +**
    • the [changes() SQL function] +**
    • the [data_version pragma] +**
    • the [SQLITE_FCNTL_DATA_VERSION] [file control] +**
    */ SQLITE_API int sqlite3_total_changes(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query @@ -2459,17 +2934,14 @@ SQLITE_API int sqlite3_total_changes(sqlite3*); ** ** ^The sqlite3_interrupt(D) call is in effect until all currently running ** SQL statements on [database connection] D complete. ^Any new SQL statements -** that are started after the sqlite3_interrupt() call and before the -** running statements reaches zero are interrupted as if they had been +** that are started after the sqlite3_interrupt() call and before the +** running statement count reaches zero are interrupted as if they had been ** running prior to the sqlite3_interrupt() call. ^New SQL statements ** that are started after the running statement count reaches zero are ** not effected by the sqlite3_interrupt(). ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. -** -** If the database connection closes while [sqlite3_interrupt()] -** is running then bad things will likely happen. */ SQLITE_API void sqlite3_interrupt(sqlite3*); @@ -2494,7 +2966,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3*); ** ^These routines do not parse the SQL statements thus ** will not detect syntactically incorrect SQL. ** -** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior +** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked ** automatically by sqlite3_complete16(). If that initialization fails, ** then the return value from sqlite3_complete16() will be non-zero @@ -2539,7 +3011,7 @@ SQLITE_API int sqlite3_complete16(const void *sql); ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] -** to the application instead of invoking the +** to the application instead of invoking the ** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and @@ -2564,7 +3036,7 @@ SQLITE_API int sqlite3_complete16(const void *sql); ** database connection that invoked the busy handler. In other words, ** the busy handler is not reentrant. Any such actions ** result in undefined behavior. -** +** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ @@ -2631,9 +3103,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); ** Cindy | 21 ** ** -** There are two column (M==2) and three rows (N==3). Thus the +** There are two columns (M==2) and three rows (N==3). Thus the ** result table has 8 entries. Suppose the result table is stored -** in an array names azResult. Then azResult holds this content: +** in an array named azResult. Then azResult holds this content: ** **
     **        azResult[0] = "Name";
    @@ -2681,16 +3153,16 @@ SQLITE_API void sqlite3_free_table(char **result);
     **
     ** These routines are work-alikes of the "printf()" family of functions
     ** from the standard C library.
    -** These routines understand most of the common K&R formatting options,
    -** plus some additional non-standard formats, detailed below.
    -** Note that some of the more obscure formatting options from recent
    -** C-library standards are omitted from this implementation.
    +** These routines understand most of the common formatting options from
    +** the standard library printf()
    +** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]).
    +** See the [built-in printf()] documentation for details.
     **
     ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
    -** results into memory obtained from [sqlite3_malloc()].
    +** results into memory obtained from [sqlite3_malloc64()].
     ** The strings returned by these two routines should be
     ** released by [sqlite3_free()].  ^Both routines return a
    -** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
    +** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough
     ** memory to hold the resulting string.
     **
     ** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
    @@ -2714,71 +3186,7 @@ SQLITE_API void sqlite3_free_table(char **result);
     **
     ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
     **
    -** These routines all implement some additional formatting
    -** options that are useful for constructing SQL statements.
    -** All of the usual printf() formatting options apply.  In addition, there
    -** is are "%q", "%Q", "%w" and "%z" options.
    -**
    -** ^(The %q option works like %s in that it substitutes a nul-terminated
    -** string from the argument list.  But %q also doubles every '\'' character.
    -** %q is designed for use inside a string literal.)^  By doubling each '\''
    -** character it escapes that character and allows it to be inserted into
    -** the string.
    -**
    -** For example, assume the string variable zText contains text as follows:
    -**
    -** 
    -**  char *zText = "It's a happy day!";
    -** 
    -** -** One can use this text in an SQL statement as follows: -** -**
    -**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
    -**  sqlite3_exec(db, zSQL, 0, 0, 0);
    -**  sqlite3_free(zSQL);
    -** 
    -** -** Because the %q format string is used, the '\'' character in zText -** is escaped and the SQL generated is as follows: -** -**
    -**  INSERT INTO table1 VALUES('It''s a happy day!')
    -** 
    -** -** This is correct. Had we used %s instead of %q, the generated SQL -** would have looked like this: -** -**
    -**  INSERT INTO table1 VALUES('It's a happy day!');
    -** 
    -** -** This second example is an SQL syntax error. As a general rule you should -** always use %q instead of %s when inserting text into a string literal. -** -** ^(The %Q option works like %q except it also adds single quotes around -** the outside of the total string. Additionally, if the parameter in the -** argument list is a NULL pointer, %Q substitutes the text "NULL" (without -** single quotes).)^ So, for example, one could say: -** -**
    -**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
    -**  sqlite3_exec(db, zSQL, 0, 0, 0);
    -**  sqlite3_free(zSQL);
    -** 
    -** -** The code above will render a correct SQL statement in the zSQL -** variable even if the zText variable is a NULL pointer. -** -** ^(The "%w" formatting option is like "%q" except that it expects to -** be contained within double-quotes instead of single quotes, and it -** escapes the double-quote character instead of the single-quote -** character.)^ The "%w" formatting option is intended for safely inserting -** table and column names into a constructed SQL statement. -** -** ^(The "%z" formatting option works like "%s" but with the -** addition that after the string has been read and copied into -** the result, [sqlite3_free()] is called on the input string.)^ +** See also: [built-in printf()], [printf() SQL function] */ SQLITE_API char *sqlite3_mprintf(const char*,...); SQLITE_API char *sqlite3_vmprintf(const char*, va_list); @@ -2790,7 +3198,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** ** The SQLite core uses these three routines for all of its own ** internal memory allocation needs. "Core" in the previous sentence -** does not include operating-system specific VFS implementation. The +** does not include operating-system specific [VFS] implementation. The ** Windows VFS uses native malloc() and free() for some operations. ** ** ^The sqlite3_malloc() routine returns a pointer to a block @@ -2851,19 +3259,6 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. ** -** In SQLite version 3.5.0 and 3.5.1, it was possible to define -** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in -** implementation of these routines to be omitted. That capability -** is no longer provided. Only built-in memory allocators can be used. -** -** Prior to SQLite version 3.7.10, the Windows OS interface layer called -** the system malloc() and free() directly when converting -** filenames between the UTF-8 encoding used by SQLite -** and whatever filename encoding is used by the particular Windows -** installation. Memory allocation errors were detected, but -** they were reported back as [SQLITE_CANTOPEN] or -** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. -** ** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] ** must be either NULL or else pointers obtained from a prior ** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have @@ -2912,7 +3307,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for -** the build-in random() and randomblob() SQL functions. This interface allows +** the built-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. @@ -2932,12 +3327,14 @@ SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** METHOD: sqlite3 +** KEYWORDS: {authorizer callback} ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], -** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], +** and [sqlite3_prepare16_v3()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should @@ -2953,14 +3350,16 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** requested is ok. ^When the callback returns [SQLITE_DENY], the ** [sqlite3_prepare_v2()] or equivalent call that triggered the ** authorizer will fail with an error message explaining that -** access is denied. +** access is denied. ** ** ^The first parameter to the authorizer callback is a copy of the third ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter ** to the callback is an integer [SQLITE_COPY | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters -** to the callback are zero-terminated strings that contain additional -** details about the action to be authorized. +** to the callback are either NULL pointers or zero-terminated strings +** that contain additional details about the action to be authorized. +** Applications must always be prepared to encounter a NULL pointer in any +** of the third through the sixth parameters of the authorization callback. ** ** ^If the action code is [SQLITE_READ] ** and the callback returns [SQLITE_IGNORE] then the @@ -2969,6 +3368,10 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] ** return can be used to deny an untrusted user access to individual ** columns of a table. +** ^When a table is referenced by a [SELECT] but no column values are +** extracted from that table (for example in a query like +** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback +** is invoked once for that table with a column name that is an empty string. ** ^If the action code is [SQLITE_DELETE] and the callback returns ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the ** [truncate optimization] is disabled and all rows are deleted individually. @@ -3000,7 +3403,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** database connections for the meaning of "modify" in this paragraph. ** ** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the -** statement might be re-prepared during [sqlite3_step()] due to a +** statement might be re-prepared during [sqlite3_step()] due to a ** schema change. Hence, the application should ensure that the ** correct authorizer callback remains in place during the [sqlite3_step()]. ** @@ -3114,9 +3517,9 @@ SQLITE_API int sqlite3_set_authorizer( ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite -** might provide greater resolution on the profiler callback. The -** sqlite3_profile() function is considered experimental and is -** subject to change in future versions of SQLite. +** might provide greater resolution on the profiler callback. Invoking +** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the +** profile callback. */ SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); @@ -3128,8 +3531,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** KEYWORDS: SQLITE_TRACE ** ** These constants identify classes of events that can be monitored -** using the [sqlite3_trace_v2()] tracing logic. The third argument -** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** using the [sqlite3_trace_v2()] tracing logic. The M argument +** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of ** the following constants. ^The first argument to the trace callback ** is one of the following constants. ** @@ -3148,7 +3551,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** execution of the prepared statement, such as at the start of each ** trigger subprogram. ^The P argument is a pointer to the ** [prepared statement]. ^The X argument is a pointer to a string which -** is the unexpanded SQL text of the prepared statement or an SQL comment +** is the unexpanded SQL text of the prepared statement or an SQL comment ** that indicates the invocation of a trigger. ^The callback can compute ** the same text that would have been returned by the legacy [sqlite3_trace()] ** interface by using the X argument when X begins with "--" and invoking @@ -3164,7 +3567,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** ** [[SQLITE_TRACE_ROW]]
    SQLITE_TRACE_ROW
    **
    ^An SQLITE_TRACE_ROW callback is invoked whenever a prepared -** statement generates a single row of result. +** statement generates a single row of result. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument is unused. ** @@ -3191,10 +3594,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** -** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides ** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). ** -** ^The X callback is invoked whenever any of the events identified by +** ^The X callback is invoked whenever any of the events identified by ** mask M occur. ^The integer return value from the callback is currently ** ignored, though this may change in future releases. Callback ** implementations should return zero to ensure future compatibility. @@ -3226,8 +3629,8 @@ SQLITE_API int sqlite3_trace_v2( ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** -** ^The parameter P is passed through as the only parameter to the -** callback function X. ^The parameter N is the approximate number of +** ^The parameter P is passed through as the only parameter to the +** callback function X. ^The parameter N is the approximate number of ** [virtual machine instructions] that are evaluated between successive ** invocations of the callback X. ^If N is less than one then the progress ** handler is disabled. @@ -3254,7 +3657,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** CAPI3REF: Opening A New Database Connection ** CONSTRUCTOR: sqlite3 ** -** ^These routines open an SQLite database file as specified by the +** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte ** order for sqlite3_open16(). ^(A [database connection] handle is usually @@ -3278,10 +3681,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to -** sqlite3_open_v2() can take one of -** the following three values, optionally combined with the -** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], -** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ +** sqlite3_open_v2() must include, at a minimum, one of the following +** three flag combinations:)^ ** **
    ** ^(
    [SQLITE_OPEN_READONLY]
    @@ -3299,22 +3700,66 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** sqlite3_open() and sqlite3_open16().
    )^ ** ** +** In addition to the required flags, the following optional flags are +** also supported: +** +**
    +** ^(
    [SQLITE_OPEN_URI]
    +**
    The filename can be interpreted as a URI if this flag is set.
    )^ +** +** ^(
    [SQLITE_OPEN_MEMORY]
    +**
    The database will be opened as an in-memory database. The database +** is named by the "filename" argument for the purposes of cache-sharing, +** if shared cache mode is enabled, but the "filename" is otherwise ignored. +**
    )^ +** +** ^(
    [SQLITE_OPEN_NOMUTEX]
    +**
    The new database connection will use the "multi-thread" +** [threading mode].)^ This means that separate threads are allowed +** to use SQLite at the same time, as long as each thread is using +** a different [database connection]. +** +** ^(
    [SQLITE_OPEN_FULLMUTEX]
    +**
    The new database connection will use the "serialized" +** [threading mode].)^ This means the multiple threads can safely +** attempt to use the same database connection at the same time. +** (Mutexes will block any actual concurrency, but in this mode +** there is no harm in trying.) +** +** ^(
    [SQLITE_OPEN_SHAREDCACHE]
    +**
    The database is opened [shared cache] enabled, overriding +** the default shared cache setting provided by +** [sqlite3_enable_shared_cache()].)^ +** +** ^(
    [SQLITE_OPEN_PRIVATECACHE]
    +**
    The database is opened [shared cache] disabled, overriding +** the default shared cache setting provided by +** [sqlite3_enable_shared_cache()].)^ +** +** [[OPEN_EXRESCODE]] ^(
    [SQLITE_OPEN_EXRESCODE]
    +**
    The database connection comes up in "extended result code mode". +** In other words, the database behaves has if +** [sqlite3_extended_result_codes(db,1)] where called on the database +** connection as soon as the connection is created. In addition to setting +** the extended result code mode, this flag also causes [sqlite3_open_v2()] +** to return an extended result code.
    +** +** [[OPEN_NOFOLLOW]] ^(
    [SQLITE_OPEN_NOFOLLOW]
    +**
    The database filename is not allowed to be a symbolic link
    +**
    )^ +** ** If the 3rd parameter to sqlite3_open_v2() is not one of the -** combinations shown above optionally combined with other +** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] -** then the behavior is undefined. -** -** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection -** opens in the multi-thread [threading mode] as long as the single-thread -** mode has not been set at compile-time or start-time. ^If the -** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens -** in the serialized [threading mode] unless single-thread was -** previously selected at compile-time or start-time. -** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be -** eligible to use [shared cache mode], regardless of whether or not shared -** cache is enabled using [sqlite3_enable_shared_cache()]. ^The -** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not -** participate in [shared cache mode] even if it is enabled. +** then the behavior is undefined. Historic versions of SQLite +** have silently ignored surplus bits in the flags parameter to +** sqlite3_open_v2(), however that behavior might not be carried through +** into future versions of SQLite and so applications should not rely +** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op +** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause +** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE +** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not +** by sqlite3_open_v2(). ** ** ^The fourth parameter to sqlite3_open_v2() is the name of the ** [sqlite3_vfs] object that defines the operating system interface that @@ -3338,26 +3783,26 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is -** set in the fourth argument to sqlite3_open_v2(), or if it has +** set in the third argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. -** As of SQLite version 3.7.7, URI filename interpretation is turned off +** URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. ** ** URI filenames are parsed according to RFC 3986. ^If the URI contains an -** authority, then it must be either an empty string or the string -** "localhost". ^If the authority is not an empty string or "localhost", an -** error is returned to the caller. ^The fragment component of a URI, if +** authority, then it must be either an empty string or the string +** "localhost". ^If the authority is not an empty string or "localhost", an +** error is returned to the caller. ^The fragment component of a URI, if ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file -** which contains the database. ^If the path begins with a '/' character, -** then it is interpreted as an absolute path. ^If the path does not begin +** which contains the database. ^If the path begins with a '/' character, +** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) -** then the path is interpreted as a relative path. -** ^(On windows, the first component of an absolute path +** then the path is interpreted as a relative path. +** ^(On windows, the first component of an absolute path ** is a drive specification (e.g. "C:").)^ ** ** [[core URI query parameters]] @@ -3377,13 +3822,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** **
  • mode: ^(The mode parameter may be set to either "ro", "rw", ** "rwc", or "memory". Attempting to set it to any other value is -** an error)^. -** ^If "ro" is specified, then the database is opened for read-only -** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the -** third argument to sqlite3_open_v2(). ^If the mode option is set to -** "rw", then the database is opened for read-write (but not create) -** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had -** been set. ^Value "rwc" is equivalent to setting both +** an error)^. +** ^If "ro" is specified, then the database is opened for read-only +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the +** third argument to sqlite3_open_v2(). ^If the mode option is set to +** "rw", then the database is opened for read-write (but not create) +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had +** been set. ^Value "rwc" is equivalent to setting both ** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is ** set to "memory" then a pure [in-memory database] that never reads ** or writes from disk is used. ^It is an error to specify a value for @@ -3393,7 +3838,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); **
  • cache: ^The cache parameter may be set to either "shared" or ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to -** sqlite3_open_v2(). ^Setting the cache parameter to "private" is +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting @@ -3419,7 +3864,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** property on a database file that does in fact change can result ** in incorrect query results and/or [SQLITE_CORRUPT] errors. ** See also: [SQLITE_IOCAP_IMMUTABLE]. -** +** ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an @@ -3431,36 +3876,37 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ** **
    URI filenames Results -**
    file:data.db +**
    file:data.db ** Open the file "data.db" in the current directory. **
    file:/home/fred/data.db
    -** file:///home/fred/data.db
    -** file://localhost/home/fred/data.db
    +** file:///home/fred/data.db
    +** file://localhost/home/fred/data.db
    ** Open the database file "/home/fred/data.db". -**
    file://darkstar/home/fred/data.db +**
    file://darkstar/home/fred/data.db ** An error. "darkstar" is not a recognized authority. -**
    +**
    ** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db ** Windows only: Open the file "data.db" on fred's desktop on drive -** C:. Note that the %20 escaping in this example is not strictly +** C:. Note that the %20 escaping in this example is not strictly ** necessary - space characters can be used literally ** in URI filenames. -**
    file:data.db?mode=ro&cache=private +**
    file:data.db?mode=ro&cache=private ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. **
    file:/home/fred/data.db?vfs=unix-dotfile ** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" ** that uses dot-files in place of posix advisory locking. -**
    file:data.db?mode=readonly +**
    file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. +** Use "ro" instead: "file:data.db?mode=ro". **
    ** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and ** query components of a URI. A hexadecimal escape sequence consists of a -** percent sign - "%" - followed by exactly two hexadecimal digits +** percent sign - "%" - followed by exactly two hexadecimal digits ** specifying an octet value. ^Before the path or query components of a -** URI filename are interpreted, they are encoded using UTF-8 and all +** URI filename are interpreted, they are encoded using UTF-8 and all ** hexadecimal escape sequences replaced by a single byte containing the ** corresponding octet. If this process generates an invalid UTF-8 encoding, ** the results are undefined. @@ -3495,17 +3941,27 @@ SQLITE_API int sqlite3_open_v2( /* ** CAPI3REF: Obtain Values For URI Parameters ** -** These are utility routines, useful to VFS implementations, that check -** to see if a database file was a URI that contained a specific query +** These are utility routines, useful to [VFS|custom VFS implementations], +** that check if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** -** If F is the database filename pointer passed into the xOpen() method of -** a VFS implementation when the flags parameter to xOpen() has one or -** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and -** P is the name of the query parameter, then +** The first parameter to these interfaces (hereafter referred to +** as F) must be one of: +**
      +**
    • A database filename pointer created by the SQLite core and +** passed into the xOpen() method of a VFS implemention, or +**
    • A filename obtained from [sqlite3_db_filename()], or +**
    • A new filename constructed using [sqlite3_create_filename()]. +**
    +** If the F parameter is not one of the above, then the behavior is +** undefined and probably undesirable. Older versions of SQLite were +** more tolerant of invalid F parameters than newer versions. +** +** If F is a suitable filename (as described in the previous paragraph) +** and if P is the name of the query parameter, then ** sqlite3_uri_parameter(F,P) returns the value of the P -** parameter if it exists or a NULL pointer if P does not appear as a -** query parameter on F. If P is a query parameter of F +** parameter if it exists or a NULL pointer if P does not appear as a +** query parameter on F. If P is a query parameter of F and it ** has no explicit value, then sqlite3_uri_parameter(F,P) returns ** a pointer to an empty string. ** @@ -3513,44 +3969,177 @@ SQLITE_API int sqlite3_open_v2( ** parameter and returns true (1) or false (0) according to the value ** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the ** value of query parameter P is one of "yes", "true", or "on" in any -** case or if the value begins with a non-zero number. The +** case or if the value begins with a non-zero number. The ** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of ** query parameter P is one of "no", "false", or "off" in any case or ** if the value begins with a numeric zero. If P is not a query -** parameter on F or if the value of P is does not match any of the +** parameter on F or if the value of P does not match any of the ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not ** exist. If the value of P is something other than an integer, then ** zero is returned. -** +** +** The sqlite3_uri_key(F,N) returns a pointer to the name (not +** the value) of the N-th query parameter for filename F, or a NULL +** pointer if N is less than zero or greater than the number of query +** parameters minus 1. The N value is zero-based so N should be 0 to obtain +** the name of the first query parameter, 1 for the second parameter, and +** so forth. +** ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and -** is not a database file pathname pointer that SQLite passed into the xOpen -** VFS method, then the behavior of this routine is undefined and probably -** undesirable. +** is not a database file pathname pointer that the SQLite core passed +** into the xOpen VFS method, then the behavior of this routine is undefined +** and probably undesirable. +** +** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F +** parameter can also be the name of a rollback journal file or WAL file +** in addition to the main database file. Prior to version 3.31.0, these +** routines would only work if F was the name of the main database file. +** When the F parameter is the name of the rollback journal or WAL file, +** it has access to all the same query parameters as were found on the +** main database file. +** +** See the [URI filename] documentation for additional information. */ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); +SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N); + +/* +** CAPI3REF: Translate filenames +** +** These routines are available to [VFS|custom VFS implementations] for +** translating filenames between the main database file, the journal file, +** and the WAL file. +** +** If F is the name of an sqlite database file, journal file, or WAL file +** passed by the SQLite core into the VFS, then sqlite3_filename_database(F) +** returns the name of the corresponding database file. +** +** If F is the name of an sqlite database file, journal file, or WAL file +** passed by the SQLite core into the VFS, or if F is a database filename +** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F) +** returns the name of the corresponding rollback journal file. +** +** If F is the name of an sqlite database file, journal file, or WAL file +** that was passed by the SQLite core into the VFS, or if F is a database +** filename obtained from [sqlite3_db_filename()], then +** sqlite3_filename_wal(F) returns the name of the corresponding +** WAL file. +** +** In all of the above, if F is not the name of a database, journal or WAL +** filename passed into the VFS from the SQLite core and F is not the +** return value from [sqlite3_db_filename()], then the result is +** undefined and is likely a memory access violation. +*/ +SQLITE_API const char *sqlite3_filename_database(const char*); +SQLITE_API const char *sqlite3_filename_journal(const char*); +SQLITE_API const char *sqlite3_filename_wal(const char*); +/* +** CAPI3REF: Database File Corresponding To A Journal +** +** ^If X is the name of a rollback or WAL-mode journal file that is +** passed into the xOpen method of [sqlite3_vfs], then +** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file] +** object that represents the main database file. +** +** This routine is intended for use in custom [VFS] implementations +** only. It is not a general-purpose interface. +** The argument sqlite3_file_object(X) must be a filename pointer that +** has been passed into [sqlite3_vfs].xOpen method where the +** flags parameter to xOpen contains one of the bits +** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use +** of this routine results in undefined and probably undesirable +** behavior. +*/ +SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); + +/* +** CAPI3REF: Create and Destroy VFS Filenames +** +** These interfces are provided for use by [VFS shim] implementations and +** are not useful outside of that context. +** +** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of +** database filename D with corresponding journal file J and WAL file W and +** with N URI parameters key/values pairs in the array P. The result from +** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that +** is safe to pass to routines like: +**
      +**
    • [sqlite3_uri_parameter()], +**
    • [sqlite3_uri_boolean()], +**
    • [sqlite3_uri_int64()], +**
    • [sqlite3_uri_key()], +**
    • [sqlite3_filename_database()], +**
    • [sqlite3_filename_journal()], or +**
    • [sqlite3_filename_wal()]. +**
    +** If a memory allocation error occurs, sqlite3_create_filename() might +** return a NULL pointer. The memory obtained from sqlite3_create_filename(X) +** must be released by a corresponding call to sqlite3_free_filename(Y). +** +** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array +** of 2*N pointers to strings. Each pair of pointers in this array corresponds +** to a key and value for a query parameter. The P parameter may be a NULL +** pointer if N is zero. None of the 2*N pointers in the P array may be +** NULL pointers and key pointers should not be empty strings. +** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may +** be NULL pointers, though they can be empty strings. +** +** The sqlite3_free_filename(Y) routine releases a memory allocation +** previously obtained from sqlite3_create_filename(). Invoking +** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op. +** +** If the Y parameter to sqlite3_free_filename(Y) is anything other +** than a NULL pointer or a pointer previously acquired from +** sqlite3_create_filename(), then bad things such as heap +** corruption or segfaults may occur. The value Y should not be +** used again after sqlite3_free_filename(Y) has been called. This means +** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, +** then the corresponding [sqlite3_module.xClose() method should also be +** invoked prior to calling sqlite3_free_filename(Y). +*/ +SQLITE_API char *sqlite3_create_filename( + const char *zDatabase, + const char *zJournal, + const char *zWal, + int nParam, + const char **azParam +); +SQLITE_API void sqlite3_free_filename(char*); /* ** CAPI3REF: Error Codes And Messages ** METHOD: sqlite3 ** -** ^If the most recent sqlite3_* API call associated with +** ^If the most recent sqlite3_* API call associated with ** [database connection] D failed, then the sqlite3_errcode(D) interface ** returns the numeric [result code] or [extended result code] for that ** API call. -** If the most recent API call was successful, -** then the return value from sqlite3_errcode() is undefined. ** ^The sqlite3_extended_errcode() -** interface is the same except that it always returns the +** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. ** +** The values returned by sqlite3_errcode() and/or +** sqlite3_extended_errcode() might change with each API call. +** Except, there are some interfaces that are guaranteed to never +** change the value of the error code. The error-code preserving +** interfaces include the following: +** +**
      +**
    • sqlite3_errcode() +**
    • sqlite3_extended_errcode() +**
    • sqlite3_errmsg() +**
    • sqlite3_errmsg16() +**
    • sqlite3_error_offset() +**
    +** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(Memory to hold the error message string is managed internally. @@ -3563,6 +4152,13 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** +** ^If the most recent error references a specific token in the input +** SQL, the sqlite3_error_offset() interface returns the byte offset +** of the start of that token. ^The byte offset returned by +** sqlite3_error_offset() assumes that the input SQL is UTF8. +** ^If the most recent error does not reference a specific token in the input +** SQL, then the sqlite3_error_offset() function returns -1. +** ** When the serialized [threading mode] is in use, it might be the ** case that a second error occurs on a separate thread in between ** the time of the first error and the call to these interfaces. @@ -3582,6 +4178,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); SQLITE_API const char *sqlite3_errmsg(sqlite3*); SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const char *sqlite3_errstr(int); +SQLITE_API int sqlite3_error_offset(sqlite3 *db); /* ** CAPI3REF: Prepared Statement Object @@ -3591,7 +4188,7 @@ SQLITE_API const char *sqlite3_errstr(int); ** has been compiled into binary form and is ready to be evaluated. ** ** Think of each SQL statement as a separate computer program. The -** original SQL text is source code. A prepared statement object +** original SQL text is source code. A prepared statement object ** is the compiled object code. All SQL must be converted into a ** prepared statement before it can be run. ** @@ -3621,7 +4218,7 @@ typedef struct sqlite3_stmt sqlite3_stmt; ** new limit for that construct.)^ ** ** ^If the new limit is a negative number, the limit is unchanged. -** ^(For each limit category SQLITE_LIMIT_NAME there is a +** ^(For each limit category SQLITE_LIMIT_NAME there is a ** [limits | hard upper bound] ** set at compile-time by a C preprocessor macro called ** [limits | SQLITE_MAX_NAME]. @@ -3629,7 +4226,7 @@ typedef struct sqlite3_stmt sqlite3_stmt; ** ^Attempts to increase a limit above its hard upper bound are ** silently truncated to the hard upper bound. ** -** ^Regardless of whether or not the limit was changed, the +** ^Regardless of whether or not the limit was changed, the ** [sqlite3_limit()] interface returns the prior value of the limit. ** ^Hence, to find the current value of a limit without changing it, ** simply invoke this interface with the third parameter set to -1. @@ -3680,9 +4277,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_VDBE_OP]] ^(
    SQLITE_LIMIT_VDBE_OP
    **
    The maximum number of instructions in a virtual machine program -** used to implement an SQL statement. This limit is not currently -** enforced, though that might be added in some future release of -** SQLite.
    )^ +** used to implement an SQL statement. If [sqlite3_prepare_v2()] or +** the equivalent tries to allocate space for more than this many opcodes +** in a single prepared statement, an SQLITE_NOMEM error is returned.)^ ** ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
    SQLITE_LIMIT_FUNCTION_ARG
    **
    The maximum number of arguments on a function.
    )^ @@ -3720,23 +4317,74 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +/* +** CAPI3REF: Prepare Flags +** +** These constants define various flags that can be passed into +** "prepFlags" parameter of the [sqlite3_prepare_v3()] and +** [sqlite3_prepare16_v3()] interfaces. +** +** New flags may be added in future releases of SQLite. +** +**
    +** [[SQLITE_PREPARE_PERSISTENT]] ^(
    SQLITE_PREPARE_PERSISTENT
    +**
    The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner +** that the prepared statement will be retained for a long time and +** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()] +** and [sqlite3_prepare16_v3()] assume that the prepared statement will +** be used just once or at most a few times and then destroyed using +** [sqlite3_finalize()] relatively soon. The current implementation acts +** on this hint by avoiding the use of [lookaside memory] so as not to +** deplete the limited store of lookaside memory. Future versions of +** SQLite may act on this hint differently. +** +** [[SQLITE_PREPARE_NORMALIZE]]
    SQLITE_PREPARE_NORMALIZE
    +**
    The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used +** to be required for any prepared statement that wanted to use the +** [sqlite3_normalized_sql()] interface. However, the +** [sqlite3_normalized_sql()] interface is now available to all +** prepared statements, regardless of whether or not they use this +** flag. +** +** [[SQLITE_PREPARE_NO_VTAB]]
    SQLITE_PREPARE_NO_VTAB
    +**
    The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler +** to return an error (error code SQLITE_ERROR) if the statement uses +** any virtual tables. +**
    +*/ +#define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 +#define SQLITE_PREPARE_NO_VTAB 0x04 + /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** -** To execute an SQL query, it must first be compiled into a byte-code -** program using one of these routines. +** To execute an SQL statement, it must first be compiled into a byte-code +** program using one of these routines. Or, in other words, these routines +** are constructors for the [prepared statement] object. +** +** The preferred routine to use is [sqlite3_prepare_v2()]. The +** [sqlite3_prepare()] interface is legacy and should be avoided. +** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used +** for special purposes. +** +** The use of the UTF-8 interfaces is preferred, as SQLite currently +** does all parsing using UTF-8. The UTF-16 interfaces are provided +** as a convenience. The UTF-16 interfaces work by converting the +** input text into UTF-8, then invoking the corresponding UTF-8 interface. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded -** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() -** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() -** use UTF-16. +** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), +** and sqlite3_prepare_v3() +** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the ** first zero terminator. ^If nByte is positive, then it is the @@ -3763,10 +4411,11 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** -** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are -** recommended for all new programs. The two older interfaces are retained -** for backwards compatibility, but their use is discouraged. -** ^In the "v2" interfaces, the prepared statement +** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. +** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) +** are retained for backwards compatibility, but their use is discouraged. +** ^In the "vX" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: @@ -3789,17 +4438,23 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
  • ** **
  • -** ^If the specific value bound to [parameter | host parameter] in the +** ^If the specific value bound to a [parameter | host parameter] in the ** WHERE clause might influence the choice of query plan for a statement, -** then the statement will be automatically recompiled, as if there had been -** a schema change, on the first [sqlite3_step()] call following any change -** to the [sqlite3_bind_text | bindings] of that [parameter]. -** ^The specific value of WHERE-clause [parameter] might influence the +** then the statement will be automatically recompiled, as if there had been +** a schema change, on the first [sqlite3_step()] call following any change +** to the [sqlite3_bind_text | bindings] of that [parameter]. +** ^The specific value of a WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column -** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. +** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled. **
  • ** +** +**

    ^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having +** the extra prepFlags parameter, which is a bit array consisting of zero or +** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The +** sqlite3_prepare_v2() interface works exactly the same as +** sqlite3_prepare_v3() with a zero prepFlags parameter. */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ @@ -3815,6 +4470,14 @@ SQLITE_API int sqlite3_prepare_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ @@ -3829,6 +4492,14 @@ SQLITE_API int sqlite3_prepare16_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); /* ** CAPI3REF: Retrieving Statement SQL @@ -3836,10 +4507,16 @@ SQLITE_API int sqlite3_prepare16_v2( ** ** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 ** SQL text used to create [prepared statement] P if P was -** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. +** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 +** string containing the normalized SQL text of prepared statement P. The +** semantics used to normalize a SQL statement are unspecified and subject +** to change. At a minimum, literal values will be replaced with suitable +** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 @@ -3855,14 +4532,21 @@ SQLITE_API int sqlite3_prepare16_v2( ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** -** ^The string returned by sqlite3_sql(P) is managed by SQLite and is -** automatically freed when the prepared statement is finalized. +** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) +** are managed by SQLite and are automatically freed when the prepared +** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, -** is obtained from [sqlite3_malloc()] and must be free by the application +** is obtained from [sqlite3_malloc()] and must be freed by the application ** by passing it to [sqlite3_free()]. +** +** ^The sqlite3_normalized_sql() interface is only available if +** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); +#endif /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -3873,8 +4557,8 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); ** the content of the database file. ** ** Note that [application-defined SQL functions] or -** [virtual tables] might change the database indirectly as a side effect. -** ^(For example, if an application defines a function "eval()" that +** [virtual tables] might change the database indirectly as a side effect. +** ^(For example, if an application defines a function "eval()" that ** calls [sqlite3_exec()], then the following SQL statement would ** change the database file through side-effects: ** @@ -3888,35 +4572,60 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); ** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], ** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, ** since the statements themselves do not actually modify the database but -** rather they control the timing of when other statements modify the +** rather they control the timing of when other statements modify the ** database. ^The [ATTACH] and [DETACH] statements also cause ** sqlite3_stmt_readonly() to return true since, while those statements -** change the configuration of a database connection, they do not make +** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. ** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so ** sqlite3_stmt_readonly() returns false for those commands. +** +** ^This routine returns false if there is any possibility that the +** statement might change the database file. ^A false return does +** not guarantee that the statement will change the database file. +** ^For example, an UPDATE statement might have a WHERE clause that +** makes it a no-op, but the sqlite3_stmt_readonly() result would still +** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a +** read-only no-op if the table already exists, but +** sqlite3_stmt_readonly() still returns false for such a statement. +** +** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN] +** statement, then sqlite3_stmt_readonly(X) returns the same value as +** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted. */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +/* +** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the +** prepared statement S is an EXPLAIN statement, or 2 if the +** statement S is an EXPLAIN QUERY PLAN. +** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is +** an ordinary statement or a NULL pointer. +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); + /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the -** [prepared statement] S has been stepped at least once using +** [prepared statement] S has been stepped at least once using ** [sqlite3_step(S)] but has neither run to completion (returned ** [SQLITE_DONE] from [sqlite3_step(S)]) nor ** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) -** interface returns false if S is a NULL pointer. If S is not a +** interface returns false if S is a NULL pointer. If S is not a ** NULL pointer and is not a pointer to a valid [prepared statement] ** object, then the behavior is undefined and probably undesirable. ** ** This interface can be used in combination [sqlite3_next_stmt()] -** to locate all prepared statements associated with a database +** to locate all prepared statements associated with a database ** connection that are in need of being reset. This can be used, -** for example, in diagnostic routines to search for prepared +** for example, in diagnostic routines to search for prepared ** statements that are holding a transaction open. */ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); @@ -3935,7 +4644,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** will accept either a protected or an unprotected sqlite3_value. ** Every interface that accepts sqlite3_value arguments specifies ** whether or not it requires a protected sqlite3_value. The -** [sqlite3_value_dup()] interface can be used to construct a new +** [sqlite3_value_dup()] interface can be used to construct a new ** protected sqlite3_value from an unprotected sqlite3_value. ** ** The terms "protected" and "unprotected" refer to whether or not @@ -3943,7 +4652,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** sqlite3_value object but no mutex is held for an unprotected ** sqlite3_value object. If SQLite is compiled to be single-threaded ** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) -** or if SQLite is run in one of reduced mutex modes +** or if SQLite is run in one of reduced mutex modes ** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] ** then there is no distinction between protected and unprotected ** sqlite3_value objects and they can be used interchangeably. However, @@ -3953,14 +4662,17 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** ** ^The sqlite3_value objects that are passed as parameters into the ** implementation of [application-defined SQL functions] are protected. +** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()] +** are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. -** Unprotected sqlite3_value objects may only be used with -** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** Unprotected sqlite3_value objects may only be used as arguments +** to [sqlite3_result_value()], [sqlite3_bind_value()], and +** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ -typedef struct Mem sqlite3_value; +typedef struct sqlite3_value sqlite3_value; /* ** CAPI3REF: SQL Function Context Object @@ -4011,12 +4723,30 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_bind_parameter_index()] API if desired. ^The index ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] -** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). +** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766). ** ** ^The third argument is the value to bind to the parameter. ** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter ** is ignored and the end result is the same as sqlite3_bind_null(). +** ^If the third parameter to sqlite3_bind_text() is not NULL, then +** it should be a pointer to well-formed UTF8 text. +** ^If the third parameter to sqlite3_bind_text16() is not NULL, then +** it should be a pointer to well-formed UTF16 text. +** ^If the third parameter to sqlite3_bind_text64() is not NULL, then +** it should be a pointer to a well-formed unicode string that is +** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 +** otherwise. +** +** [[byte-order determination rules]] ^The byte-order of +** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) +** found in first character, which is removed, or in the absence of a BOM +** the byte order is the native byte order of the host +** machine for sqlite3_bind_text16() or the byte order specified in +** the 6th parameter for sqlite3_bind_text64().)^ +** ^If UTF16 input text contains invalid unicode +** characters, then SQLite might change those invalid characters +** into the unicode replacement character: U+FFFD. ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the @@ -4030,21 +4760,27 @@ typedef struct sqlite3_context sqlite3_context; ** or sqlite3_bind_text16() or sqlite3_bind_text64() then ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL -** terminated. If any NUL characters occur at byte offsets less than +** terminated. If any NUL characters occurs at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** -** ^The fifth argument to the BLOB and string binding interfaces -** is a destructor used to dispose of the BLOB or -** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to bind API fails. -** ^If the fifth argument is -** the special value [SQLITE_STATIC], then SQLite assumes that the -** information is in static, unmanaged space and does not need to be freed. -** ^If the fifth argument has the value [SQLITE_TRANSIENT], then -** SQLite makes its own private copy of the data immediately, before -** the sqlite3_bind_*() routine returns. +** ^The fifth argument to the BLOB and string binding interfaces controls +** or indicates the lifetime of the object referenced by the third parameter. +** These three options exist: +** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished +** with it may be passed. ^It is called to dispose of the BLOB or string even +** if the call to the bind API fails, except the destructor is not called if +** the third parameter is a NULL pointer or the fourth parameter is negative. +** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that +** the application remains responsible for disposing of the object. ^In this +** case, the object and the provided pointer to it must remain valid until +** either the prepared statement is finalized or the same SQL parameter is +** bound to something else, whichever occurs sooner. +** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the +** object is to be copied prior to the return from sqlite3_bind_*(). ^The +** object and pointer to it must remain valid until then. ^SQLite will then +** manage the lifetime of its private copy. ** ** ^The sixth argument to sqlite3_bind_text64() must be one of ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] @@ -4062,6 +4798,15 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** +** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in +** [prepared statement] S to have an SQL value of NULL, but to also be +** associated with the pointer P of type T. ^D is either a NULL pointer or +** a pointer to a destructor function for P. ^SQLite will invoke the +** destructor D with a single argument of P when it is finished using +** P. The T parameter should be a static string, preferably a string +** literal. The sqlite3_bind_pointer() routine is part of the +** [pointer passing interface] added for SQLite 3.20.0. +** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], @@ -4095,6 +4840,7 @@ SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*) SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); @@ -4138,8 +4884,8 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was -** originally specified as UTF-16 in [sqlite3_prepare16()] or -** [sqlite3_prepare16_v2()]. +** originally specified as UTF-16 in [sqlite3_prepare16()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -4156,7 +4902,8 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement -** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or +** [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -4179,7 +4926,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); ** METHOD: sqlite3_stmt ** ** ^Return the number of columns in the result set returned by the -** [prepared statement]. ^If this routine returns 0, that means the +** [prepared statement]. ^If this routine returns 0, that means the ** [prepared statement] returns no data (for example an [UPDATE]). ** ^However, just because this routine returns a positive number does not ** mean that one or more rows of data will be returned. ^A SELECT statement @@ -4247,7 +4994,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** ** ^If the Nth column returned by the statement is an expression or ** subquery and is not a column value, then all of these functions return -** NULL. ^These routine might also return NULL if a memory allocation error +** NULL. ^These routines might also return NULL if a memory allocation error ** occurs. ^Otherwise, they return the name of the attached database, table, ** or column that query result column was extracted from. ** @@ -4257,10 +5004,6 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** ^These APIs are only available if the library was compiled with the ** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. ** -** If two or more threads call one or more of these routines against the same -** prepared statement and column at the same time then the results are -** undefined. -** ** If two or more threads call one or more ** [sqlite3_column_database_name | column metadata interfaces] ** for the same [prepared statement] and result column @@ -4310,16 +5053,18 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** CAPI3REF: Evaluate An SQL Statement ** METHOD: sqlite3_stmt ** -** After a [prepared statement] has been prepared using either -** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** After a [prepared statement] has been prepared using any of +** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], +** or [sqlite3_prepare16_v3()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend -** on whether the statement was prepared using the newer "v2" interface -** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy -** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the -** new "v2" interface is recommended for new applications but the legacy +** on whether the statement was prepared using the newer "vX" interfaces +** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], +** [sqlite3_prepare16_v2()] or the older legacy +** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "vX" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], @@ -4363,7 +5108,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of -** sqlite3_step(). Failure to reset the prepared statement using +** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from ** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], ** sqlite3_step() began @@ -4380,10 +5125,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements -** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] +** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly -** by sqlite3_step(). The use of the "v2" interface is recommended. +** by sqlite3_step(). The use of the "vX" interfaces is recommended. */ SQLITE_API int sqlite3_step(sqlite3_stmt*); @@ -4394,7 +5140,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*); ** ^The sqlite3_data_count(P) interface returns the number of columns in the ** current row of the result set of [prepared statement] P. ** ^If prepared statement P does not have results ready to return -** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of +** (via calls to the [sqlite3_column_int | sqlite3_column()] family of ** interfaces) then sqlite3_data_count(P) returns 0. ** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. ** ^The sqlite3_data_count(P) routine returns 0 if the previous call to @@ -4445,6 +5191,28 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** KEYWORDS: {column access functions} ** METHOD: sqlite3_stmt ** +** Summary: +**

    +**
    sqlite3_column_blobBLOB result +**
    sqlite3_column_doubleREAL result +**
    sqlite3_column_int32-bit INTEGER result +**
    sqlite3_column_int6464-bit INTEGER result +**
    sqlite3_column_textUTF-8 TEXT result +**
    sqlite3_column_text16UTF-16 TEXT result +**
    sqlite3_column_valueThe result as an +** [sqlite3_value|unprotected sqlite3_value] object. +**
        +**
    sqlite3_column_bytesSize of a BLOB +** or a UTF-8 TEXT result in bytes +**
    sqlite3_column_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_column_typeDefault +** datatype of the result +**
    +** +** Details: +** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] @@ -4466,16 +5234,29 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** +** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) +** each return the value of a result column in a specific data format. If +** the result column is not initially in the requested format (for example, +** if the query returns an integer but the sqlite3_column_text() interface +** is used to extract the value) then an automatic type conversion is performed. +** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value -** returned by sqlite3_column_type() is only meaningful if no type -** conversions have occurred as described below. After a type conversion, -** the value returned by sqlite3_column_type() is undefined. Future +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. +** The return value of sqlite3_column_type() can be used to decide which +** of the first six interface should be used to extract the column value. +** The value returned by sqlite3_column_type() is only meaningful if no +** automatic type conversions have occurred for the value in question. +** After a type conversion, the result of calling sqlite3_column_type() +** is undefined, though harmless. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** +** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() +** or sqlite3_column_bytes16() interfaces can be used to determine the size +** of that BLOB or string. +** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts @@ -4494,7 +5275,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** the number of bytes in that string. ** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. ** -** ^The values returned by [sqlite3_column_bytes()] and +** ^The values returned by [sqlite3_column_bytes()] and ** [sqlite3_column_bytes16()] do not include the zero terminators at the end ** of the string. ^For clarity: the values returned by ** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of @@ -4504,6 +5285,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** even empty strings, are always zero-terminated. ^The return ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. ** +** ^Strings returned by sqlite3_column_text16() always have the endianness +** which is native to the platform, regardless of the text encoding set +** for the database. +** ** Warning: ^The object returned by [sqlite3_column_value()] is an ** [unprotected sqlite3_value] object. In a multithreaded environment, ** an unprotected sqlite3_value object may only be used safely with @@ -4512,9 +5297,13 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** Hence, the sqlite3_column_value() interface +** is normally only useful within the implementation of +** [application-defined SQL functions] or [virtual tables], not within +** top-level application code. ** -** These routines attempt to convert the value where appropriate. ^For -** example, if the internal representation is FLOAT and a text result +** These routines may attempt to convert the datatype of the result. +** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: @@ -4538,7 +5327,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** TEXT BLOB No change ** BLOB INTEGER [CAST] to INTEGER ** BLOB FLOAT [CAST] to REAL -** BLOB TEXT Add a zero terminator if needed +** BLOB TEXT [CAST] to TEXT, ensure zero terminator ** **
    )^ ** @@ -4586,26 +5375,40 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings -** and BLOBs is freed automatically. Do not pass the pointers returned +** and BLOBs is freed automatically. Do not pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** -** ^(If a memory allocation error occurs during the evaluation of any -** of these routines, a default value is returned. The default value -** is either the integer 0, the floating point number 0.0, or a NULL -** pointer. Subsequent calls to [sqlite3_errcode()] will return -** [SQLITE_NOMEM].)^ +** As long as the input parameters are correct, these routines will only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_column_blob() +**
    • sqlite3_column_text() +**
    • sqlite3_column_text16() +**
    • sqlite3_column_bytes() +**
    • sqlite3_column_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object @@ -4665,17 +5468,17 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} -** KEYWORDS: {application-defined SQL function} -** KEYWORDS: {application-defined SQL functions} ** METHOD: sqlite3 ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior -** of existing SQL functions or aggregates. The only differences between -** these routines are the text encoding expected for -** the second parameter (the name of the function being created) -** and the presence or absence of a destructor callback for -** the application data pointer. +** of existing SQL functions or aggregates. The only differences between +** the three "sqlite3_create_function*" routines are the text encoding +** expected for the second parameter (the name of the function being +** created) and the presence or absence of a destructor callback for +** the application data pointer. Function sqlite3_create_window_function() +** is similar, but allows the user to supply the extra callback functions +** needed by [aggregate window functions]. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database @@ -4685,7 +5488,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ^The second parameter is the name of the SQL function to be created or ** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 ** representation, exclusive of the zero-terminator. ^Note that the name -** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. +** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. ** ^Any attempt to create a function with a longer name ** will result in [SQLITE_MISUSE] being returned. ** @@ -4700,7 +5503,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. The application should set this parameter to -** [SQLITE_UTF16LE] if the function implementation invokes +** [SQLITE_UTF16LE] if the function implementation invokes ** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the ** implementation invokes [sqlite3_value_text16be()] on an input, or ** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] @@ -4718,10 +5521,26 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** +** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY] +** flag, which if present prevents the function from being invoked from +** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions, +** index expressions, or the WHERE clause of partial indexes. +** +** For best security, the [SQLITE_DIRECTONLY] flag is recommended for +** all application-defined SQL functions that do not need to be +** used inside of triggers, view, CHECK constraints, or other elements of +** the database schema. This flags is especially recommended for SQL +** functions that have side effects or reveal internal application state. +** Without this flag, an attacker might be able to modify the schema of +** a database file to include invocations of the function with parameters +** chosen by the attacker, which the application will then execute when +** the database file is opened and read. +** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** -** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are +** ^The sixth, seventh and eighth parameters passed to the three +** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal @@ -4730,15 +5549,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** -** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, -** then it is destructor for the application data pointer. -** The destructor is invoked when the function is deleted, either by being -** overloaded or when the database connection closes.)^ -** ^The destructor is also invoked if the call to -** sqlite3_create_function_v2() fails. -** ^When the destructor callback of the tenth parameter is invoked, it -** is passed a single argument which is a copy of the application data -** pointer which was the fifth parameter to sqlite3_create_function_v2(). +** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue +** and xInverse) passed to sqlite3_create_window_function are pointers to +** C-language callbacks that implement the new function. xStep and xFinal +** must both be non-NULL. xValue and xInverse may either both be NULL, in +** which case a regular aggregate function is created, or must both be +** non-NULL, in which case the new function may be used as either an aggregate +** or aggregate window function. More details regarding the implementation +** of aggregate window functions are +** [user-defined window functions|available here]. +** +** ^(If the final parameter to sqlite3_create_function_v2() or +** sqlite3_create_window_function() is not NULL, then it is destructor for +** the application data pointer. The destructor is invoked when the function +** is deleted, either by being overloaded or when the database connection +** closes.)^ ^The destructor is also invoked if the call to +** sqlite3_create_function_v2() fails. ^When the destructor callback is +** invoked, it is passed a single argument which is a copy of the application +** data pointer which was the fifth parameter to sqlite3_create_function_v2(). ** ** ^It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of @@ -4748,7 +5576,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** nArg parameter is a better match than a function implementation with ** a negative nArg. ^A function where the preferred text encoding ** matches the database encoding is a better -** match than a function where the encoding is different. +** match than a function where the encoding is different. ** ^A function where the encoding difference is between UTF16le and UTF16be ** is a closer match than a function where the encoding difference is ** between UTF8 and UTF16. @@ -4791,6 +5619,18 @@ SQLITE_API int sqlite3_create_function_v2( void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*) ); +SQLITE_API int sqlite3_create_window_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) +); /* ** CAPI3REF: Text Encodings @@ -4808,19 +5648,79 @@ SQLITE_API int sqlite3_create_function_v2( /* ** CAPI3REF: Function Flags ** -** These constants may be ORed together with the +** These constants may be ORed together with the ** [SQLITE_UTF8 | preferred text encoding] as the fourth argument ** to [sqlite3_create_function()], [sqlite3_create_function16()], or ** [sqlite3_create_function_v2()]. +** +**
    +** [[SQLITE_DETERMINISTIC]]
    SQLITE_DETERMINISTIC
    +** The SQLITE_DETERMINISTIC flag means that the new function always gives +** the same output when the input parameters are the same. +** The [abs|abs() function] is deterministic, for example, but +** [randomblob|randomblob()] is not. Functions must +** be deterministic in order to be used in certain contexts such as +** with the WHERE clause of [partial indexes] or in [generated columns]. +** SQLite might also optimize deterministic functions by factoring them +** out of inner loops. +**
    +** +** [[SQLITE_DIRECTONLY]]
    SQLITE_DIRECTONLY
    +** The SQLITE_DIRECTONLY flag means that the function may only be invoked +** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in +** schema structures such as [CHECK constraints], [DEFAULT clauses], +** [expression indexes], [partial indexes], or [generated columns]. +** The SQLITE_DIRECTONLY flags is a security feature which is recommended +** for all [application-defined SQL functions], and especially for functions +** that have side-effects or that could potentially leak sensitive +** information. +**
    +** +** [[SQLITE_INNOCUOUS]]
    SQLITE_INNOCUOUS
    +** The SQLITE_INNOCUOUS flag means that the function is unlikely +** to cause problems even if misused. An innocuous function should have +** no side effects and should not depend on any values other than its +** input parameters. The [abs|abs() function] is an example of an +** innocuous function. +** The [load_extension() SQL function] is not innocuous because of its +** side effects. +**

    SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not +** exactly the same. The [random|random() function] is an example of a +** function that is innocuous but not deterministic. +**

    Some heightened security settings +** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF]) +** disable the use of SQL functions inside views and triggers and in +** schema structures such as [CHECK constraints], [DEFAULT clauses], +** [expression indexes], [partial indexes], and [generated columns] unless +** the function is tagged with SQLITE_INNOCUOUS. Most built-in functions +** are innocuous. Developers are advised to avoid using the +** SQLITE_INNOCUOUS flag for application-defined functions unless the +** function has been carefully audited and found to be free of potentially +** security-adverse side-effects and information-leaks. +**

    +** +** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    +** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call +** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. +** Specifying this flag makes no difference for scalar or aggregate user +** functions. However, if it is not specified for a user-defined window +** function, then any sub-types belonging to arguments passed to the window +** function may be discarded before the window function is called (i.e. +** sqlite3_value_subtype() will always return 0). +**
    +**
    */ -#define SQLITE_DETERMINISTIC 0x800 +#define SQLITE_DETERMINISTIC 0x000000800 +#define SQLITE_DIRECTONLY 0x000080000 +#define SQLITE_SUBTYPE 0x000100000 +#define SQLITE_INNOCUOUS 0x000200000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain -** backwards compatibility with older code, these functions continue +** backwards compatibility with older code, these functions continue ** to be supported. However, new applications should avoid ** the use of these functions. To encourage programmers to avoid ** these functions, we will not explain what they do. @@ -4839,21 +5739,45 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** -** The C-language implementation of SQL functions and aggregates uses -** this set of interface routines to access the parameter values on -** the function or aggregate. -** -** The xFunc (for scalar functions) or xStep (for aggregates) parameters -** to [sqlite3_create_function()] and [sqlite3_create_function16()] -** define callbacks that implement the SQL functions and aggregates. -** The 3rd parameter to these callbacks is an array of pointers to -** [protected sqlite3_value] objects. There is one [sqlite3_value] object for -** each parameter to the SQL function. These routines are used to -** extract values from the [sqlite3_value] objects. +** Summary: +**
    +**
    sqlite3_value_blobBLOB value +**
    sqlite3_value_doubleREAL value +**
    sqlite3_value_int32-bit INTEGER value +**
    sqlite3_value_int6464-bit INTEGER value +**
    sqlite3_value_pointerPointer value +**
    sqlite3_value_textUTF-8 TEXT value +**
    sqlite3_value_text16UTF-16 TEXT value in +** the native byteorder +**
    sqlite3_value_text16beUTF-16be TEXT value +**
    sqlite3_value_text16leUTF-16le TEXT value +**
        +**
    sqlite3_value_bytesSize of a BLOB +** or a UTF-8 TEXT in bytes +**
    sqlite3_value_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_value_typeDefault +** datatype of the value +**
    sqlite3_value_numeric_type   +** →  Best numeric datatype of the value +**
    sqlite3_value_nochange   +** →  True if the column is unchanged in an UPDATE +** against a virtual table. +**
    sqlite3_value_frombind   +** →  True if value originated from a [bound parameter] +**
    +** +** Details: +** +** These routines extract type, size, and content information from +** [protected sqlite3_value] objects. Protected sqlite3_value objects +** are used to pass parameter information into the functions that +** implement [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] -** object results in undefined behavior. +** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object @@ -4864,6 +5788,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** +** ^If [sqlite3_value] object V was initialized +** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] +** and if X and Y are strings that compare equal according to strcmp(X,Y), +** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, +** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** +** ^(The sqlite3_value_type(V) interface returns the +** [SQLITE_INTEGER | datatype code] for the initial datatype of the +** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ +** Other interfaces might change the datatype for an sqlite3_value object. +** For example, if the datatype is initially SQLITE_INTEGER and +** sqlite3_value_text(V) is called to extract a text value for that +** integer, then subsequent calls to sqlite3_value_type(V) might return +** SQLITE_TEXT. Whether or not a persistent internal datatype conversion +** occurs is undefined and may change from one release of SQLite to the next. +** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If @@ -4872,6 +5814,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** +** ^Within the [xUpdate] method of a [virtual table], the +** sqlite3_value_nochange(X) interface returns true if and only if +** the column corresponding to X is unchanged by the UPDATE operation +** that the xUpdate method call was invoked to implement and if +** and the prior [xColumn] method call that was invoked to extracted +** the value for that column returned without setting a result (probably +** because it queried [sqlite3_vtab_nochange()] and found that the column +** was unchanging). ^Within an [xUpdate] method, any value for which +** sqlite3_value_nochange(X) is true will in all other respects appear +** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other +** than within an [xUpdate] method call for an UPDATE statement, then +** the return value is arbitrary and meaningless. +** +** ^The sqlite3_value_frombind(X) interface returns non-zero if the +** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] +** interfaces. ^If X comes from an SQL literal value, or a table column, +** or an expression, then sqlite3_value_frombind(X) returns zero. +** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to @@ -4880,19 +5840,44 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. +** +** As long as the input parameter is correct, these routines can only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_value_blob() +**
    • sqlite3_value_text() +**
    • sqlite3_value_text16() +**
    • sqlite3_value_text16le() +**
    • sqlite3_value_text16be() +**
    • sqlite3_value_bytes() +**
    • sqlite3_value_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); SQLITE_API int sqlite3_value_int(sqlite3_value*); SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); +SQLITE_API int sqlite3_value_nochange(sqlite3_value*); +SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -4903,10 +5888,6 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** SQLite makes no use of subtype itself. It merely passes the subtype -** from the result of one [application-defined SQL function] into the -** input of another. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -4934,9 +5915,9 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*); ** Implementations of aggregate SQL functions use this ** routine to allocate memory for storing their state. ** -** ^The first time the sqlite3_aggregate_context(C,N) routine is called -** for a particular aggregate function, SQLite -** allocates N of memory, zeroes out that memory, and returns a pointer +** ^The first time the sqlite3_aggregate_context(C,N) routine is called +** for a particular aggregate function, SQLite allocates +** N bytes of memory, zeroes out that memory, and returns a pointer ** to the new memory. ^On second and subsequent calls to ** sqlite3_aggregate_context() for the same aggregate function instance, ** the same buffer is returned. Sqlite3_aggregate_context() is normally @@ -4947,19 +5928,19 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*); ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** -** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer +** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory ** allocate error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the -** value of N in subsequent call to sqlite3_aggregate_context() within +** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set -** N=0 in calls to sqlite3_aggregate_context(C,N) so that no +** N=0 in calls to sqlite3_aggregate_context(C,N) so that no ** pointless memory allocations occur. ** -** ^SQLite automatically frees the memory allocated by +** ^SQLite automatically frees the memory allocated by ** sqlite3_aggregate_context() when the aggregate query concludes. ** ** The first parameter must be a copy of the @@ -5009,15 +5990,16 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** some circumstances the associated metadata may be preserved. An example ** of where this might be useful is in a regular-expression matching ** function. The compiled version of the regular expression can be stored as -** metadata associated with the pattern string. +** metadata associated with the pattern string. ** Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata -** associated by the sqlite3_set_auxdata() function with the Nth argument -** value to the application-defined function. ^If there is no metadata -** associated with the function argument, this sqlite3_get_auxdata() interface +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument +** value to the application-defined function. ^N is zero for the left-most +** function argument. ^If there is no metadata +** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th @@ -5034,10 +6016,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** SQL statement)^, or **
  • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or -**
  • ^(during the original sqlite3_set_auxdata() call when a memory +**
  • ^(during the original sqlite3_set_auxdata() call when a memory ** allocation error occurs.)^ ** -** Note the last bullet in particular. The destructor X in +** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the @@ -5048,6 +6030,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** +** The value of the N parameter to these interfaces should be non-negative. +** Future enhancements may make use of negative N values to define new +** kinds of function caching behavior. +** ** These routines must be called from the same thread in which ** the SQL function is running. */ @@ -5105,8 +6091,9 @@ typedef void (*sqlite3_destructor_type)(void*); ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() ** as the text of an error message. ^SQLite interprets the error ** message string from sqlite3_result_error() as UTF-8. ^SQLite -** interprets the string from sqlite3_result_error16() as UTF-16 in native -** byte order. ^If the third parameter to sqlite3_result_error() +** interprets the string from sqlite3_result_error16() as UTF-16 using +** the same [byte-order determination rules] as [sqlite3_bind_text16()]. +** ^If the third parameter to sqlite3_result_error() ** or sqlite3_result_error16() is negative then SQLite takes as the error ** message all text up through the first zero character. ** ^If the third parameter to sqlite3_result_error() or @@ -5171,9 +6158,28 @@ typedef void (*sqlite3_destructor_type)(void*); ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT -** then SQLite makes a copy of the result into space obtained from +** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** +** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and +** sqlite3_result_text16be() routines, and for sqlite3_result_text64() +** when the encoding is not UTF8, if the input UTF16 begins with a +** byte-order mark (BOM, U+FEFF) then the BOM is removed from the +** string and the rest of the string is interpreted according to the +** byte-order specified by the BOM. ^The byte-order specified by +** the BOM at the beginning of the text overrides the byte-order +** specified by the interface procedure. ^So, for example, if +** sqlite3_result_text16le() is invoked with text that begins +** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the +** first two bytes of input are skipped and the remaining input +** is interpreted as UTF16BE text. +** +** ^For UTF16 input text to the sqlite3_result_text16(), +** sqlite3_result_text16be(), sqlite3_result_text16le(), and +** sqlite3_result_text64() routines, if the text contains invalid +** UTF16 characters, the invalid characters might be converted +** into the unicode replacement character, U+FFFD. +** ** ^The sqlite3_result_value() interface sets the result of ** the application-defined function to be a copy of the ** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The @@ -5184,6 +6190,17 @@ typedef void (*sqlite3_destructor_type)(void*); ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** +** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an +** SQL NULL value, just like [sqlite3_result_null(C)], except that it +** also associates the host-language pointer P or type T with that +** NULL value such that the pointer can be retrieved within an +** [application-defined SQL function] using [sqlite3_value_pointer()]. +** ^If the D parameter is not NULL, then it is a pointer to a destructor +** for the P parameter. ^SQLite invokes D with P as its only argument +** when SQLite is finished with P. The T parameter should be a static +** string and preferably a string literal. The sqlite3_result_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. @@ -5207,6 +6224,7 @@ SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(* SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); @@ -5216,8 +6234,8 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** METHOD: sqlite3_context ** ** The sqlite3_result_subtype(C,T) function causes the subtype of -** the result from the [application-defined SQL function] with -** [sqlite3_context] C to be the value T. Only the lower 8 bits +** the result from the [application-defined SQL function] with +** [sqlite3_context] C to be the value T. Only the lower 8 bits ** of the subtype T are preserved in current versions of SQLite; ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase @@ -5247,7 +6265,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); **
  • [SQLITE_UTF16_ALIGNED]. ** )^ ** ^The eTextRep argument determines the encoding of strings passed -** to the collating function callback, xCallback. +** to the collating function callback, xCompare. ** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep ** force strings to be UTF16 with native byte order. ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin @@ -5256,18 +6274,19 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); ** ^The fourth argument, pArg, is an application data pointer that is passed ** through as the first argument to the collating function callback. ** -** ^The fifth argument, xCallback, is a pointer to the collating function. +** ^The fifth argument, xCompare, is a pointer to the collating function. ** ^Multiple collating functions can be registered using the same name but ** with different eTextRep parameters and SQLite will use whichever ** function requires the least amount of data transformation. -** ^If the xCallback argument is NULL then the collating function is +** ^If the xCompare argument is NULL then the collating function is ** deleted. ^When all collating functions having the same name are deleted, ** that collation is no longer usable. ** -** ^The collating function callback is invoked with a copy of the pArg +** ^The collating function callback is invoked with a copy of the pArg ** application data pointer and with two strings in the encoding specified -** by the eTextRep argument. The collating function must return an -** integer that is negative, zero, or positive +** by the eTextRep argument. The two integer parameters to the collating +** function callback are the length of the two strings, in bytes. The collating +** function must return an integer that is negative, zero, or positive ** if the first string is less than, equal to, or greater than the second, ** respectively. A collating function must always return the same answer ** given the same inputs. If two or more collating functions are registered @@ -5284,7 +6303,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); ** ** ** If a collating function fails any of the above constraints and that -** collating function is registered and used, then the behavior of SQLite +** collating function is registered and used, then the behavior of SQLite ** is undefined. ** ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() @@ -5294,36 +6313,36 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); ** calls to the collation creation functions or when the ** [database connection] is closed using [sqlite3_close()]. ** -** ^The xDestroy callback is not called if the +** ^The xDestroy callback is not called if the ** sqlite3_create_collation_v2() function fails. Applications that invoke -** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should +** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should ** check the return code and dispose of the application data pointer ** themselves rather than expecting SQLite to deal with it for them. -** This is different from every other SQLite interface. The inconsistency -** is unfortunate but cannot be changed without breaking backwards +** This is different from every other SQLite interface. The inconsistency +** is unfortunate but cannot be changed without breaking backwards ** compatibility. ** ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. */ SQLITE_API int sqlite3_create_collation( - sqlite3*, - const char *zName, - int eTextRep, + sqlite3*, + const char *zName, + int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); SQLITE_API int sqlite3_create_collation_v2( - sqlite3*, - const char *zName, - int eTextRep, + sqlite3*, + const char *zName, + int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDestroy)(void*) ); SQLITE_API int sqlite3_create_collation16( - sqlite3*, + sqlite3*, const void *zName, - int eTextRep, + int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); @@ -5356,64 +6375,19 @@ SQLITE_API int sqlite3_create_collation16( ** [sqlite3_create_collation_v2()]. */ SQLITE_API int sqlite3_collation_needed( - sqlite3*, - void*, + sqlite3*, + void*, void(*)(void*,sqlite3*,int eTextRep,const char*) ); SQLITE_API int sqlite3_collation_needed16( - sqlite3*, + sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) ); -#ifdef SQLITE_HAS_CODEC -/* -** Specify the key for an encrypted database. This routine should be -** called right after sqlite3_open(). -** -** The code to implement this API is not available in the public release -** of SQLite. -*/ -SQLITE_API int sqlite3_key( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The key */ -); -SQLITE_API int sqlite3_key_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The key */ -); - -/* -** Change the key on an open database. If the current database is not -** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the -** database is decrypted. -** -** The code to implement this API is not available in the public release -** of SQLite. -*/ -SQLITE_API int sqlite3_rekey( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The new key */ -); -SQLITE_API int sqlite3_rekey_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The new key */ -); - -/* -** Specify the activation key for a SEE database. Unless -** activated, none of the SEE routines will work. -*/ -SQLITE_API void sqlite3_activate_see( - const char *zPassPhrase /* Activation phrase */ -); -#endif - #ifdef SQLITE_ENABLE_CEROD /* -** Specify the activation key for a CEROD database. Unless +** Specify the activation key for a CEROD database. Unless ** activated, none of the CEROD routines will work. */ SQLITE_API void sqlite3_activate_cerod( @@ -5469,7 +6443,7 @@ SQLITE_API int sqlite3_sleep(int); ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string -** that this variable points to is held in memory obtained from +** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be @@ -5526,7 +6500,7 @@ SQLITE_API char *sqlite3_temp_directory; ** ^The [data_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [data_store_directory pragma] always assumes that any string -** that this variable points to is held in memory obtained from +** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be @@ -5535,6 +6509,41 @@ SQLITE_API char *sqlite3_temp_directory; */ SQLITE_API char *sqlite3_data_directory; +/* +** CAPI3REF: Win32 Specific Interface +** +** These interfaces are available only on Windows. The +** [sqlite3_win32_set_directory] interface is used to set the value associated +** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to +** zValue, depending on the value of the type parameter. The zValue parameter +** should be NULL to cause the previous value to be freed via [sqlite3_free]; +** a non-NULL value will be copied into memory obtained from [sqlite3_malloc] +** prior to being used. The [sqlite3_win32_set_directory] interface returns +** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported, +** or [SQLITE_NOMEM] if memory could not be allocated. The value of the +** [sqlite3_data_directory] variable is intended to act as a replacement for +** the current directory on the sub-platforms of Win32 where that concept is +** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and +** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the +** sqlite3_win32_set_directory interface except the string parameter must be +** UTF-8 or UTF-16, respectively. +*/ +SQLITE_API int sqlite3_win32_set_directory( + unsigned long type, /* Identifier for directory being set or reset */ + void *zValue /* New value for directory being set or reset */ +); +SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); +SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); + +/* +** CAPI3REF: Win32 Directory Types +** +** These macros are only available on Windows. They define the allowed values +** for the type argument to the [sqlite3_win32_set_directory] interface. +*/ +#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1 +#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2 + /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} @@ -5576,16 +6585,31 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** CAPI3REF: Return The Filename For A Database Connection ** METHOD: sqlite3 ** -** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename -** associated with database N of connection D. ^The main database file -** has the name "main". If there is no attached database N on the database +** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename +** associated with database N of connection D. +** ^If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then -** a NULL pointer is returned. +** this function will return either a NULL pointer or an empty string. +** +** ^The string value returned by this routine is owned and managed by +** the database connection. ^The value will be valid until the database N +** is [DETACH]-ed or until the database connection closes. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. +** +** If the filename pointer returned by this routine is not NULL, then it +** can be used as the filename input parameter to these routines: +**
      +**
    • [sqlite3_uri_parameter()] +**
    • [sqlite3_uri_boolean()] +**
    • [sqlite3_uri_int64()] +**
    • [sqlite3_filename_database()] +**
    • [sqlite3_filename_journal()] +**
    • [sqlite3_filename_wal()] +**
    */ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); @@ -5599,6 +6623,57 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +/* +** CAPI3REF: Determine the transaction state of a database +** METHOD: sqlite3 +** +** ^The sqlite3_txn_state(D,S) interface returns the current +** [transaction state] of schema S in database connection D. ^If S is NULL, +** then the highest transaction state of any schema on database connection D +** is returned. Transaction states are (in order of lowest to highest): +**
      +**
    1. SQLITE_TXN_NONE +**
    2. SQLITE_TXN_READ +**
    3. SQLITE_TXN_WRITE +**
    +** ^If the S argument to sqlite3_txn_state(D,S) is not the name of +** a valid schema, then -1 is returned. +*/ +SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); + +/* +** CAPI3REF: Allowed return values from [sqlite3_txn_state()] +** KEYWORDS: {transaction state} +** +** These constants define the current transaction state of a database file. +** ^The [sqlite3_txn_state(D,S)] interface returns one of these +** constants in order to describe the transaction state of schema S +** in [database connection] D. +** +**
    +** [[SQLITE_TXN_NONE]]
    SQLITE_TXN_NONE
    +**
    The SQLITE_TXN_NONE state means that no transaction is currently +** pending.
    +** +** [[SQLITE_TXN_READ]]
    SQLITE_TXN_READ
    +**
    The SQLITE_TXN_READ state means that the database is currently +** in a read transaction. Content has been read from the database file +** but nothing in the database file has changed. The transaction state +** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** no other conflicting concurrent write transactions. The transaction +** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or +** [COMMIT].
    +** +** [[SQLITE_TXN_WRITE]]
    SQLITE_TXN_WRITE
    +**
    The SQLITE_TXN_WRITE state means that the database is currently +** in a write transaction. Content has been written to the database file +** but has not yet committed. The transaction state will change to +** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
    +*/ +#define SQLITE_TXN_NONE 0 +#define SQLITE_TXN_READ 1 +#define SQLITE_TXN_WRITE 2 + /* ** CAPI3REF: Find the next prepared statement ** METHOD: sqlite3 @@ -5665,6 +6740,72 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); +/* +** CAPI3REF: Autovacuum Compaction Amount Callback +** METHOD: sqlite3 +** +** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback +** function C that is invoked prior to each autovacuum of the database +** file. ^The callback is passed a copy of the generic data pointer (P), +** the schema-name of the attached database that is being autovacuumed, +** the the size of the database file in pages, the number of free pages, +** and the number of bytes per page, respectively. The callback should +** return the number of free pages that should be removed by the +** autovacuum. ^If the callback returns zero, then no autovacuum happens. +** ^If the value returned is greater than or equal to the number of +** free pages, then a complete autovacuum happens. +** +**

    ^If there are multiple ATTACH-ed database files that are being +** modified as part of a transaction commit, then the autovacuum pages +** callback is invoked separately for each file. +** +**

    The callback is not reentrant. The callback function should +** not attempt to invoke any other SQLite interface. If it does, bad +** things may happen, including segmentation faults and corrupt database +** files. The callback function should be a simple function that +** does some arithmetic on its input parameters and returns a result. +** +** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional +** destructor for the P parameter. ^If X is not NULL, then X(P) is +** invoked whenever the database connection closes or when the callback +** is overwritten by another invocation of sqlite3_autovacuum_pages(). +** +**

    ^There is only one autovacuum pages callback per database connection. +** ^Each call to the sqlite3_autovacuum_pages() interface overrides all +** previous invocations for that database connection. ^If the callback +** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, +** then the autovacuum steps callback is cancelled. The return value +** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might +** be some other error code if something goes wrong. The current +** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other +** return codes might be added in future releases. +** +**

    If no autovacuum pages callback is specified (the usual case) or +** a NULL pointer is provided for the callback, +** then the default behavior is to vacuum all free pages. So, in other +** words, the default behavior is the same as if the callback function +** were something like this: +** +**

    +**     unsigned int demonstration_autovac_pages_callback(
    +**       void *pClientData,
    +**       const char *zSchema,
    +**       unsigned int nDbPage,
    +**       unsigned int nFreePage,
    +**       unsigned int nBytePerPage
    +**     ){
    +**       return nFreePage;
    +**     }
    +** 
    +*/ +SQLITE_API int sqlite3_autovacuum_pages( + sqlite3 *db, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, + void(*)(void*) +); + + /* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 @@ -5689,7 +6830,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are -** modified (i.e. sqlite_master and sqlite_sequence).)^ +** modified (i.e. sqlite_sequence).)^ ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook @@ -5715,7 +6856,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** and [sqlite3_preupdate_hook()] interfaces. */ SQLITE_API void *sqlite3_update_hook( - sqlite3*, + sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* ); @@ -5729,25 +6870,29 @@ SQLITE_API void *sqlite3_update_hook( ** and disabled if the argument is false.)^ ** ** ^Cache sharing is enabled and disabled for an entire process. -** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). +** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. -** Existing database connections continue use the sharing mode +** Existing database connections continue to use the sharing mode ** that was in effect at the time they were opened.)^ ** ** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled ** successfully. An [error code] is returned otherwise.)^ ** -** ^Shared cache is disabled by default. But this might change in -** future releases of SQLite. Applications that care about shared -** cache setting should set it explicitly. +** ^Shared cache is disabled by default. It is recommended that it stay +** that way. In other words, do not use this routine. This interface +** continues to be provided for historical compatibility, but its use is +** discouraged. Any use of shared cache is discouraged. If shared cache +** must be used, it is recommended that shared cache only be enabled for +** individual database connections using the [sqlite3_open_v2()] interface +** with the [SQLITE_OPEN_SHAREDCACHE] flag. ** ** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 -** and will always return SQLITE_MISUSE. On those systems, -** shared cache mode should be enabled per-database connection via +** and will always return SQLITE_MISUSE. On those systems, +** shared cache mode should be enabled per-database connection via ** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. ** ** This interface is threadsafe on processors where writing a @@ -5790,6 +6935,9 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size ** +** These interfaces impose limits on the amount of heap memory that will be +** by all database connections within a single process. +** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. ** ^SQLite strives to keep heap memory utilization below the soft heap @@ -5797,23 +6945,44 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** as heap memory usages approaches the limit. ** ^The soft heap limit is "soft" because even though SQLite strives to stay ** below the limit, it will exceed the limit rather than generate -** an [SQLITE_NOMEM] error. In other words, the soft heap limit +** an [SQLITE_NOMEM] error. In other words, the soft heap limit ** is advisory only. ** -** ^The return value from sqlite3_soft_heap_limit64() is the size of -** the soft heap limit prior to the call, or negative in the case of an -** error. ^If the argument N is negative -** then no change is made to the soft heap limit. Hence, the current -** size of the soft heap limit can be determined by invoking -** sqlite3_soft_heap_limit64() with a negative argument. -** -** ^If the argument N is zero then the soft heap limit is disabled. +** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of +** N bytes on the amount of memory that will be allocated. ^The +** sqlite3_hard_heap_limit64(N) interface is similar to +** sqlite3_soft_heap_limit64(N) except that memory allocations will fail +** when the hard heap limit is reached. ** -** ^(The soft heap limit is not enforced in the current implementation +** ^The return value from both sqlite3_soft_heap_limit64() and +** sqlite3_hard_heap_limit64() is the size of +** the heap limit prior to the call, or negative in the case of an +** error. ^If the argument N is negative +** then no change is made to the heap limit. Hence, the current +** size of heap limits can be determined by invoking +** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). +** +** ^Setting the heap limits to zero disables the heap limiter mechanism. +** +** ^The soft heap limit may not be greater than the hard heap limit. +** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) +** is invoked with a value of N that is greater than the hard heap limit, +** the the soft heap limit is set to the value of the hard heap limit. +** ^The soft heap limit is automatically enabled whenever the hard heap +** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and +** the soft heap limit is outside the range of 1..N, then the soft heap +** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the +** hard heap limit is enabled makes the soft heap limit equal to the +** hard heap limit. +** +** The memory allocation limits can also be adjusted using +** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit]. +** +** ^(The heap limits are not enforced in the current implementation ** if one or more of following conditions are true: ** **
      -**
    • The soft heap limit is set to zero. +**
    • The limit value is set to zero. **
    • Memory accounting is disabled using a combination of the ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. @@ -5824,21 +6993,11 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** from the heap. **
    )^ ** -** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), -** the soft heap limit is enforced -** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] -** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], -** the soft heap limit is enforced on every memory allocation. Without -** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced -** when memory is allocated by the page cache. Testing suggests that because -** the page cache is the predominate memory user in SQLite, most -** applications will achieve adequate soft heap limit enforcement without -** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. -** -** The circumstances under which SQLite will enforce the soft heap limit may +** The circumstances under which SQLite will enforce the heap limits may ** changes in future releases of SQLite. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); +SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface @@ -5862,11 +7021,13 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns -** SQLITE_ERROR and if the specified column does not exist. +** SQLITE_ERROR if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a ** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it -** does not. +** does not. If the table name parameter T in a call to +** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is +** undefined behavior. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -5900,7 +7061,7 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** ** ^If the specified table is actually a view, an [error code] is returned. ** -** ^If the specified column is "rowid", "oid" or "_rowid_" and the table +** ^If the specified column is "rowid", "oid" or "_rowid_" and the table ** is not a [WITHOUT ROWID] table and an ** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output ** parameters are set for the explicitly declared column. ^(If there is no @@ -5966,7 +7127,7 @@ SQLITE_API int sqlite3_table_column_metadata( ** prior to calling this API, ** otherwise an error will be returned. ** -** Security warning: It is recommended that the +** Security warning: It is recommended that the ** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this ** interface. The use of the [sqlite3_enable_load_extension()] interface ** should be avoided. This will keep the SQL function [load_extension()] @@ -6002,7 +7163,7 @@ SQLITE_API int sqlite3_load_extension( ** to enable or disable only the C-API.)^ ** ** Security warning: It is recommended that extension loading -** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method +** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method ** rather than this interface, so the [load_extension()] SQL function ** remains disabled. This will prevent SQL injections from giving attackers ** access to extension loading capabilities. @@ -6053,7 +7214,7 @@ SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)); ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the ** initialization routine X that was registered using a prior call to ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] -** routine returns 1 if initialization routine X was successfully +** routine returns 1 if initialization routine X was successfully ** unregistered and it returns 0 if X was not on the list of initialization ** routines. */ @@ -6088,8 +7249,8 @@ typedef struct sqlite3_module sqlite3_module; ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** -** This structure, sometimes called a "virtual table module", -** defines the implementation of a [virtual tables]. +** This structure, sometimes called a "virtual table module", +** defines the implementation of a [virtual table]. ** This structure consists mostly of methods for the module. ** ** ^A virtual table module is created by filling in a persistent @@ -6128,11 +7289,14 @@ struct sqlite3_module { void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); - /* The methods above are in version 1 of the sqlite_module object. Those + /* The methods above are in version 1 of the sqlite_module object. Those ** below are for version 2 and greater. */ int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); }; /* @@ -6175,7 +7339,7 @@ struct sqlite3_module { ** required by SQLite. If the table has at least 64 columns and any column ** to the right of the first 63 is required, then bit 63 of colUsed is also ** set. In other words, column iCol may be required if the expression -** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to +** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to ** non-zero. ** ** The [xBestIndex] method must fill aConstraintUsage[] with information @@ -6183,7 +7347,13 @@ struct sqlite3_module { ** the right-hand side of the corresponding aConstraint[] is evaluated ** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit ** is true, then the constraint is assumed to be fully handled by the -** virtual table and is not checked again by SQLite.)^ +** virtual table and might not be checked again by the byte code.)^ ^(The +** aConstraintUsage[].omit flag is an optimization hint. When the omit flag +** is left in its default setting of false, the constraint will always be +** checked separately in byte code. If the omit flag is change to true, then +** the constraint may or may not be checked in byte code. In other words, +** when the omit flag is true there is no guarantee that the constraint will +** not be checked again using byte code.)^ ** ** ^The idxNum and idxPtr values are recorded and passed into the ** [xFilter] method. @@ -6196,17 +7366,17 @@ struct sqlite3_module { ** ** ^The estimatedCost value is an estimate of the cost of a particular ** strategy. A cost of N indicates that the cost of the strategy is similar -** to a linear scan of an SQLite table with N rows. A cost of log(N) +** to a linear scan of an SQLite table with N rows. A cost of log(N) ** indicates that the expense of the operation is similar to that of a ** binary search on a unique indexed field of an SQLite table with N rows. ** ** ^The estimatedRows value is an estimate of the number of rows that ** will be returned by the strategy. ** -** The xBestIndex method may optionally populate the idxFlags field with a +** The xBestIndex method may optionally populate the idxFlags field with a ** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - ** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite -** assumes that the strategy may visit at most one row. +** assumes that the strategy may visit at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as @@ -6219,14 +7389,14 @@ struct sqlite3_module { ** the xUpdate method are automatically rolled back by SQLite. ** ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info -** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). +** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). ** If a virtual table extension is -** used with an SQLite version earlier than 3.8.2, the results of attempting -** to read or write the estimatedRows field are undefined (but are likely -** to included crashing the application). The estimatedRows field should +** used with an SQLite version earlier than 3.8.2, the results of attempting +** to read or write the estimatedRows field are undefined (but are likely +** to include crashing the application). The estimatedRows field should ** therefore only be used if [sqlite3_libversion_number()] returns a ** value greater than or equal to 3008002. Similarly, the idxFlags field -** was added for [version 3.9.0] ([dateof:3.9.0]). +** was added for [version 3.9.0] ([dateof:3.9.0]). ** It may therefore only be used if ** sqlite3_libversion_number() returns a value greater than or equal to ** 3009000. @@ -6265,26 +7435,68 @@ struct sqlite3_index_info { /* ** CAPI3REF: Virtual Table Scan Flags +** +** Virtual table implementations are allowed to set the +** [sqlite3_index_info].idxFlags field to some combination of +** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** -** These macros defined the allowed values for the +** These macros define the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents -** an operator that is part of a constraint term in the wHERE clause of +** an operator that is part of a constraint term in the WHERE clause of ** a query that uses a [virtual table]. -*/ -#define SQLITE_INDEX_CONSTRAINT_EQ 2 -#define SQLITE_INDEX_CONSTRAINT_GT 4 -#define SQLITE_INDEX_CONSTRAINT_LE 8 -#define SQLITE_INDEX_CONSTRAINT_LT 16 -#define SQLITE_INDEX_CONSTRAINT_GE 32 -#define SQLITE_INDEX_CONSTRAINT_MATCH 64 -#define SQLITE_INDEX_CONSTRAINT_LIKE 65 -#define SQLITE_INDEX_CONSTRAINT_GLOB 66 -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +** +** ^The left-hand operand of the operator is given by the corresponding +** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand +** operand is the rowid. +** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET +** operators have no left-hand operand, and so for those operators the +** corresponding aConstraint[].iColumn is meaningless and should not be +** used. +** +** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through +** value 255 are reserved to represent functions that are overloaded +** by the [xFindFunction|xFindFunction method] of the virtual table +** implementation. +** +** The right-hand operands for each constraint might be accessible using +** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand +** operand is only available if it appears as a single constant literal +** in the input SQL. If the right-hand operand is another column or an +** expression (even a constant expression) or a parameter, then the +** sqlite3_vtab_rhs_value() probably will not be able to extract it. +** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and +** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand +** and hence calls to sqlite3_vtab_rhs_value() for those operators will +** always return SQLITE_NOTFOUND. +** +** The collating sequence to be used for comparison can be found using +** the [sqlite3_vtab_collation()] interface. For most real-world virtual +** tables, the collating sequence of constraints does not matter (for example +** because the constraints are numeric) and so the sqlite3_vtab_collation() +** interface is no commonly needed. +*/ +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 +#define SQLITE_INDEX_CONSTRAINT_LIKE 65 +#define SQLITE_INDEX_CONSTRAINT_GLOB 66 +#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_NE 68 +#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 +#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 +#define SQLITE_INDEX_CONSTRAINT_IS 72 +#define SQLITE_INDEX_CONSTRAINT_LIMIT 73 +#define SQLITE_INDEX_CONSTRAINT_OFFSET 74 +#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation @@ -6296,7 +7508,7 @@ struct sqlite3_index_info { ** preexisting [virtual table] for the module. ** ** ^The module name is registered on the [database connection] specified -** by the first parameter. ^The name of the module is given by the +** by the first parameter. ^The name of the module is given by the ** second parameter. ^The third parameter is a pointer to ** the implementation of the [virtual table module]. ^The fourth ** parameter is an arbitrary client data pointer that is passed through @@ -6311,6 +7523,12 @@ struct sqlite3_index_info { ** ^The sqlite3_create_module() ** interface is equivalent to sqlite3_create_module_v2() with a NULL ** destructor. +** +** ^If the third parameter (the pointer to the sqlite3_module object) is +** NULL then no new module is created and any existing modules with the +** same name are dropped. +** +** See also: [sqlite3_drop_modules()] */ SQLITE_API int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ @@ -6326,6 +7544,23 @@ SQLITE_API int sqlite3_create_module_v2( void(*xDestroy)(void*) /* Module destructor function */ ); +/* +** CAPI3REF: Remove Unnecessary Virtual Table Implementations +** METHOD: sqlite3 +** +** ^The sqlite3_drop_modules(D,L) interface removes all virtual +** table modules from database connection D except those named on list L. +** The L parameter must be either NULL or a pointer to an array of pointers +** to strings where the array is terminated by a single NULL pointer. +** ^If the L parameter is NULL, then all virtual table modules are removed. +** +** See also: [sqlite3_create_module()] +*/ +SQLITE_API int sqlite3_drop_modules( + sqlite3 *db, /* Remove modules from this connection */ + const char **azKeep /* Except, do not remove the ones named here */ +); + /* ** CAPI3REF: Virtual Table Instance Object ** KEYWORDS: sqlite3_vtab @@ -6388,7 +7623,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); ** METHOD: sqlite3 ** ** ^(Virtual tables can provide alternative implementations of functions -** using the [xFindFunction] method of the [virtual table module]. +** using the [xFindFunction] method of the [virtual table module]. ** But global versions of those functions ** must exist in order to be overloaded.)^ ** @@ -6439,7 +7674,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** )^ ** -** ^(Parameter zDb is not the filename that contains the database, but +** ^(Parameter zDb is not the filename that contains the database, but ** rather the symbolic name of the database. For attached databases, this is ** the name that appears after the AS keyword in the [ATTACH] statement. ** For the main database file, the database name is "main". For TEMP @@ -6452,28 +7687,28 @@ typedef struct sqlite3_blob sqlite3_blob; ** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored ** in *ppBlob. Otherwise an [error code] is returned and, unless the error ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided -** the API is not misused, it is always safe to call [sqlite3_blob_close()] +** the API is not misused, it is always safe to call [sqlite3_blob_close()] ** on *ppBlob after this function it returns. ** ** This function fails with SQLITE_ERROR if any of the following are true: **
      -**
    • ^(Database zDb does not exist)^, -**
    • ^(Table zTable does not exist within database zDb)^, -**
    • ^(Table zTable is a WITHOUT ROWID table)^, +**
    • ^(Database zDb does not exist)^, +**
    • ^(Table zTable does not exist within database zDb)^, +**
    • ^(Table zTable is a WITHOUT ROWID table)^, **
    • ^(Column zColumn does not exist)^, **
    • ^(Row iRow is not present in the table)^, **
    • ^(The specified column of row iRow contains a value that is not ** a TEXT or BLOB value)^, -**
    • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE +**
    • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE ** constraint and the blob is being opened for read/write access)^, -**
    • ^([foreign key constraints | Foreign key constraints] are enabled, +**
    • ^([foreign key constraints | Foreign key constraints] are enabled, ** column zColumn is part of a [child key] definition and the blob is ** being opened for read/write access)^. **
    ** -** ^Unless it returns SQLITE_MISUSE, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** ^Unless it returns SQLITE_MISUSE, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** A BLOB referenced by sqlite3_blob_open() may be read using the ** [sqlite3_blob_read()] interface and modified by using @@ -6499,7 +7734,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** blob. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces -** and the built-in [zeroblob] SQL function may be used to create a +** and the built-in [zeroblob] SQL function may be used to create a ** zero-filled blob to read or write using the incremental-blob interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually @@ -6549,7 +7784,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); ** DESTRUCTOR: sqlite3_blob ** ** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed -** unconditionally. Even if this routine returns an error code, the +** unconditionally. Even if this routine returns an error code, the ** handle is still closed.)^ ** ** ^If the blob handle being closed was opened for read-write access, and if @@ -6559,10 +7794,10 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); ** code is returned and the transaction rolled back. ** ** Calling this function with an argument that is not a NULL pointer or an -** open blob handle results in undefined behaviour. ^Calling this routine -** with a null pointer (such as would be returned by a failed call to +** open blob handle results in undefined behaviour. ^Calling this routine +** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function -** is passed a valid open blob handle, the values returned by the +** is passed a valid open blob handle, the values returned by the ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. */ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); @@ -6571,7 +7806,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); ** CAPI3REF: Return The Size Of An Open BLOB ** METHOD: sqlite3_blob ** -** ^Returns the size in bytes of the BLOB accessible via the +** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The ** incremental blob I/O routines can only read or overwriting existing ** blob content; they cannot change the size of a blob. @@ -6622,9 +7857,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); ** ** ^(On success, sqlite3_blob_write() returns SQLITE_OK. ** Otherwise, an [error code] or an [extended error code] is returned.)^ -** ^Unless SQLITE_MISUSE is returned, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** ^Unless SQLITE_MISUSE is returned, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** ^If the [BLOB handle] passed as the first argument was not opened for ** writing (the flags parameter to [sqlite3_blob_open()] was zero), @@ -6633,9 +7868,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); ** This function may only modify the contents of the BLOB; it is ** not possible to increase the size of a BLOB using this API. ** ^If offset iOffset is less than N bytes from the end of the BLOB, -** [SQLITE_ERROR] is returned and no data is written. The size of the -** BLOB (and hence the maximum value of N+iOffset) can be determined -** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less +** [SQLITE_ERROR] is returned and no data is written. The size of the +** BLOB (and hence the maximum value of N+iOffset) can be determined +** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less ** than zero [SQLITE_ERROR] is returned and no data is written. ** ** ^An attempt to write to an expired [BLOB handle] fails with an @@ -6729,7 +7964,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); **
      **
    • SQLITE_MUTEX_FAST **
    • SQLITE_MUTEX_RECURSIVE -**
    • SQLITE_MUTEX_STATIC_MASTER +**
    • SQLITE_MUTEX_STATIC_MAIN **
    • SQLITE_MUTEX_STATIC_MEM **
    • SQLITE_MUTEX_STATIC_OPEN **
    • SQLITE_MUTEX_STATIC_PRNG @@ -6787,7 +8022,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() ** will always return SQLITE_BUSY. The SQLite core only ever uses -** sqlite3_mutex_try() as an optimization so this is acceptable +** sqlite3_mutex_try() as an optimization so this is acceptable ** behavior.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was @@ -6852,7 +8087,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); ** The only difference is that the public sqlite3_XXX functions enumerated ** above silently ignore any invocations that pass a NULL pointer instead ** of a valid mutex handle. The implementations of the methods defined -** by this structure are not required to handle this case, the results +** by this structure are not required to handle this case. The results ** of passing a NULL pointer instead of a valid mutex handle are undefined ** (i.e. it is acceptable to provide an implementation that segfaults if ** it is passed a NULL pointer). @@ -6931,7 +8166,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 -#define SQLITE_MUTEX_STATIC_MASTER 2 +#define SQLITE_MUTEX_STATIC_MAIN 2 #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ @@ -6946,11 +8181,15 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); #define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ #define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ +/* Legacy compatibility: */ +#define SQLITE_MUTEX_STATIC_MASTER 2 + + /* ** CAPI3REF: Retrieve the mutex for a database connection ** METHOD: sqlite3 ** -** ^This interface returns a pointer the [sqlite3_mutex] object that +** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. ** ^If the [threading mode] is Single-thread or Multi-thread then this @@ -6961,6 +8200,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** METHOD: sqlite3 +** KEYWORDS: {file control} ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated @@ -6975,11 +8215,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** -** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes +** A few opcodes for [sqlite3_file_control()] are handled directly +** by the SQLite core and never invoke the +** sqlite3_io_methods.xFileControl method. +** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into -** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER -** case is a short-circuit path which does not actually invoke the -** underlying sqlite3_io_methods.xFileControl method. +** the space pointed to by the 4th parameter. The +** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns +** the [sqlite3_file] object associated with the journal file instead of +** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns +** a pointer to the underlying [sqlite3_vfs] object for the file. +** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter +** from the pager. ** ** ^If the second parameter (zDbName) does not match the name of any ** open database file, then SQLITE_ERROR is returned. ^This error @@ -6989,7 +8236,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); ** an incorrect zDbName and an SQLITE_ERROR return from the underlying ** xFileControl method. ** -** See also: [SQLITE_FCNTL_LOCKSTATE] +** See also: [file control opcodes] */ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); @@ -7026,17 +8273,18 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 -#define SQLITE_TESTCTRL_PRNG_RESET 7 +#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 -#define SQLITE_TESTCTRL_RESERVE 14 +#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 -#define SQLITE_TESTCTRL_ISKEYWORD 16 -#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 +#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ +#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ +#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -7046,7 +8294,198 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 -#define SQLITE_TESTCTRL_LAST 25 +#define SQLITE_TESTCTRL_PARSER_COVERAGE 26 +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_PRNG_SEED 28 +#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 +#define SQLITE_TESTCTRL_SEEK_COUNT 30 +#define SQLITE_TESTCTRL_TRACEFLAGS 31 +#define SQLITE_TESTCTRL_TUNE 32 +#define SQLITE_TESTCTRL_LOGEST 33 +#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */ + +/* +** CAPI3REF: SQL Keyword Checking +** +** These routines provide access to the set of SQL language keywords +** recognized by SQLite. Applications can uses these routines to determine +** whether or not a specific identifier needs to be escaped (for example, +** by enclosing in double-quotes) so as not to confuse the parser. +** +** The sqlite3_keyword_count() interface returns the number of distinct +** keywords understood by SQLite. +** +** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and +** makes *Z point to that keyword expressed as UTF8 and writes the number +** of bytes in the keyword into *L. The string that *Z points to is not +** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns +** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z +** or L are NULL or invalid pointers then calls to +** sqlite3_keyword_name(N,Z,L) result in undefined behavior. +** +** The sqlite3_keyword_check(Z,L) interface checks to see whether or not +** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero +** if it is and zero if not. +** +** The parser used by SQLite is forgiving. It is often possible to use +** a keyword as an identifier as long as such use does not result in a +** parsing ambiguity. For example, the statement +** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and +** creates a new table named "BEGIN" with three columns named +** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid +** using keywords as identifiers. Common techniques used to avoid keyword +** name collisions include: +**
        +**
      • Put all identifier names inside double-quotes. This is the official +** SQL way to escape identifier names. +**
      • Put identifier names inside [...]. This is not standard SQL, +** but it is what SQL Server does and so lots of programmers use this +** technique. +**
      • Begin every identifier with the letter "Z" as no SQL keywords start +** with "Z". +**
      • Include a digit somewhere in every identifier name. +**
      +** +** Note that the number of keywords understood by SQLite can depend on +** compile-time options. For example, "VACUUM" is not a keyword if +** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also, +** new keywords may be added to future releases of SQLite. +*/ +SQLITE_API int sqlite3_keyword_count(void); +SQLITE_API int sqlite3_keyword_name(int,const char**,int*); +SQLITE_API int sqlite3_keyword_check(const char*,int); + +/* +** CAPI3REF: Dynamic String Object +** KEYWORDS: {dynamic string} +** +** An instance of the sqlite3_str object contains a dynamically-sized +** string under construction. +** +** The lifecycle of an sqlite3_str object is as follows: +**
        +**
      1. ^The sqlite3_str object is created using [sqlite3_str_new()]. +**
      2. ^Text is appended to the sqlite3_str object using various +** methods, such as [sqlite3_str_appendf()]. +**
      3. ^The sqlite3_str object is destroyed and the string it created +** is returned using the [sqlite3_str_finish()] interface. +**
      +*/ +typedef struct sqlite3_str sqlite3_str; + +/* +** CAPI3REF: Create A New Dynamic String Object +** CONSTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_new(D)] interface allocates and initializes +** a new [sqlite3_str] object. To avoid memory leaks, the object returned by +** [sqlite3_str_new()] must be freed by a subsequent call to +** [sqlite3_str_finish(X)]. +** +** ^The [sqlite3_str_new(D)] interface always returns a pointer to a +** valid [sqlite3_str] object, though in the event of an out-of-memory +** error the returned object might be a special singleton that will +** silently reject new text, always return SQLITE_NOMEM from +** [sqlite3_str_errcode()], always return 0 for +** [sqlite3_str_length()], and always return NULL from +** [sqlite3_str_finish(X)]. It is always safe to use the value +** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter +** to any of the other [sqlite3_str] methods. +** +** The D parameter to [sqlite3_str_new(D)] may be NULL. If the +** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum +** length of the string contained in the [sqlite3_str] object will be +** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead +** of [SQLITE_MAX_LENGTH]. +*/ +SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); + +/* +** CAPI3REF: Finalize A Dynamic String +** DESTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X +** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()] +** that contains the constructed string. The calling application should +** pass the returned value to [sqlite3_free()] to avoid a memory leak. +** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any +** errors were encountered during construction of the string. ^The +** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** string in [sqlite3_str] object X is zero bytes long. +*/ +SQLITE_API char *sqlite3_str_finish(sqlite3_str*); + +/* +** CAPI3REF: Add Content To A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces add content to an sqlite3_str object previously obtained +** from [sqlite3_str_new()]. +** +** ^The [sqlite3_str_appendf(X,F,...)] and +** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] +** functionality of SQLite to append formatted text onto the end of +** [sqlite3_str] object X. +** +** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S +** onto the end of the [sqlite3_str] object X. N must be non-negative. +** S must contain at least N non-zero bytes of content. To append a +** zero-terminated string in its entirety, use the [sqlite3_str_appendall()] +** method instead. +** +** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of +** zero-terminated string S onto the end of [sqlite3_str] object X. +** +** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the +** single-byte character C onto the end of [sqlite3_str] object X. +** ^This method can be used, for example, to add whitespace indentation. +** +** ^The [sqlite3_str_reset(X)] method resets the string under construction +** inside [sqlite3_str] object X back to zero bytes in length. +** +** These methods do not return a result code. ^If an error occurs, that fact +** is recorded in the [sqlite3_str] object and can be recovered by a +** subsequent call to [sqlite3_str_errcode(X)]. +*/ +SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); +SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list); +SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); +SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); +SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); +SQLITE_API void sqlite3_str_reset(sqlite3_str*); + +/* +** CAPI3REF: Status Of A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces return the current status of an [sqlite3_str] object. +** +** ^If any prior errors have occurred while constructing the dynamic string +** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return +** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns +** [SQLITE_NOMEM] following any out-of-memory error, or +** [SQLITE_TOOBIG] if the size of the dynamic string exceeds +** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors. +** +** ^The [sqlite3_str_length(X)] method returns the current length, in bytes, +** of the dynamic string under construction in [sqlite3_str] object X. +** ^The length returned by [sqlite3_str_length(X)] does not include the +** zero-termination byte. +** +** ^The [sqlite3_str_value(X)] method returns a pointer to the current +** content of the dynamic string under construction in X. The value +** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X +** and might be freed or altered by any subsequent method on the same +** [sqlite3_str] object. Applications must not used the pointer returned +** [sqlite3_str_value(X)] after any subsequent method call on the same +** object. ^Applications may change the content of the string returned +** by [sqlite3_str_value(X)] as long as they do not write into any bytes +** outside the range of 0 to [sqlite3_str_length(X)] and do not read or +** write any byte after any subsequent sqlite3_str method call. +*/ +SQLITE_API int sqlite3_str_errcode(sqlite3_str*); +SQLITE_API int sqlite3_str_length(sqlite3_str*); +SQLITE_API char *sqlite3_str_value(sqlite3_str*); /* ** CAPI3REF: SQLite Runtime Status @@ -7095,8 +8534,7 @@ SQLITE_API int sqlite3_status64( **
      This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application -** and internal memory usage by the SQLite library. Scratch memory -** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** and internal memory usage by the SQLite library. Auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].
      )^ @@ -7105,7 +8543,7 @@ SQLITE_API int sqlite3_status64( **
      This parameter records the largest memory allocation request ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their ** internal equivalents). Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. +** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
      )^ ** ** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
      SQLITE_STATUS_MALLOC_COUNT
      @@ -7114,11 +8552,11 @@ SQLITE_API int sqlite3_status64( ** ** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
      SQLITE_STATUS_PAGECACHE_USED
      **
      This parameter returns the number of pages used out of the -** [pagecache memory allocator] that was configured using +** [pagecache memory allocator] that was configured using ** [SQLITE_CONFIG_PAGECACHE]. The ** value returned is in pages, not in bytes.
      )^ ** -** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] ** ^(
      SQLITE_STATUS_PAGECACHE_OVERFLOW
      **
      This parameter returns the number of bytes of page cache ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] @@ -7130,36 +8568,21 @@ SQLITE_API int sqlite3_status64( ** ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
      SQLITE_STATUS_PAGECACHE_SIZE
      **
      This parameter records the largest memory allocation request -** handed to [pagecache memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. +** handed to the [pagecache memory allocator]. Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
      )^ ** -** [[SQLITE_STATUS_SCRATCH_USED]] ^(
      SQLITE_STATUS_SCRATCH_USED
      -**
      This parameter returns the number of allocations used out of the -** [scratch memory allocator] configured using -** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not -** in bytes. Since a single thread may only have one scratch allocation -** outstanding at time, this parameter also reports the number of threads -** using scratch memory at the same time.
      )^ +** [[SQLITE_STATUS_SCRATCH_USED]]
      SQLITE_STATUS_SCRATCH_USED
      +**
      No longer used.
      ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
      SQLITE_STATUS_SCRATCH_OVERFLOW
      -**
      This parameter returns the number of bytes of scratch memory -** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] -** buffer and where forced to overflow to [sqlite3_malloc()]. The values -** returned include overflows because the requested allocation was too -** larger (that is, because the requested allocation was larger than the -** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer -** slots were available. -**
      )^ +**
      No longer used.
      ** -** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
      SQLITE_STATUS_SCRATCH_SIZE
      -**
      This parameter records the largest memory allocation request -** handed to [scratch memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. -** The value written into the *pCurrent parameter is undefined.
      )^ +** [[SQLITE_STATUS_SCRATCH_SIZE]]
      SQLITE_STATUS_SCRATCH_SIZE
      +**
      No longer used.
      ** ** [[SQLITE_STATUS_PARSER_STACK]] ^(
      SQLITE_STATUS_PARSER_STACK
      -**
      The *pHighwater parameter records the deepest parser stack. +**
      The *pHighwater parameter records the deepest parser stack. ** The *pCurrent value is undefined. The *pHighwater value is only ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
      )^ **
    @@ -7169,24 +8592,24 @@ SQLITE_API int sqlite3_status64( #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 -#define SQLITE_STATUS_SCRATCH_USED 3 -#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 -#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ #define SQLITE_STATUS_MALLOC_COUNT 9 /* ** CAPI3REF: Database Connection Status ** METHOD: sqlite3 ** -** ^This interface is used to retrieve runtime status information +** ^This interface is used to retrieve runtime status information ** about a single [database connection]. ^The first argument is the ** database connection object to be interrogated. ^The second argument ** is an integer constant, taken from the set of ** [SQLITE_DBSTATUS options], that -** determines the parameter to interrogate. The set of +** determines the parameter to interrogate. The set of ** [SQLITE_DBSTATUS options] is likely ** to grow in future releases of SQLite. ** @@ -7221,7 +8644,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** checked out.)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
    SQLITE_DBSTATUS_LOOKASIDE_HIT
    -**
    This parameter returns the number malloc attempts that were +**
    This parameter returns the number of malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; ** the current value is always zero.)^ ** @@ -7246,7 +8669,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** -** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] ** ^(
    SQLITE_DBSTATUS_CACHE_USED_SHARED
    **
    This parameter is similar to DBSTATUS_CACHE_USED, except that if a ** pager cache is shared between two or more connections the bytes of heap @@ -7261,7 +8684,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated -** with the connection - main, temp, and any [ATTACH]-ed databases.)^ +** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. @@ -7276,13 +8699,13 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** ** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(
    SQLITE_DBSTATUS_CACHE_HIT
    **
    This parameter returns the number of pager cache hits that have -** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT ** is always 0. **
    ** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(
    SQLITE_DBSTATUS_CACHE_MISS
    **
    This parameter returns the number of pager cache misses that have -** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. **
    ** @@ -7297,6 +8720,15 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. ** ** +** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(
    SQLITE_DBSTATUS_CACHE_SPILL
    +**
    This parameter returns the number of dirty cache entries that have +** been written to disk in the middle of a transaction due to the page +** cache overflowing. Transactions are more efficient if they are written +** to disk all at once. When pages spill mid-transaction, that introduces +** additional overhead. This parameter can be used help identify +** inefficiencies that can be resolved by increasing the cache size. +**
    +** ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(
    SQLITE_DBSTATUS_DEFERRED_FKS
    **
    This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been @@ -7316,7 +8748,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 -#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_CACHE_SPILL 12 +#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ /* @@ -7330,7 +8763,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** statements. For example, if the number of table steps greatly exceeds ** the number of table searches or result rows, that would tend to indicate ** that the prepared statement is using a full table scan rather than -** an index. +** an index. ** ** ^(This interface is used to retrieve and reset counter values from ** a [prepared statement]. The first argument is the prepared statement @@ -7357,7 +8790,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
    SQLITE_STMTSTATUS_FULLSCAN_STEP
    **
    ^This is the number of times that SQLite has stepped forward in ** a table as part of a full table scan. Large numbers for this counter -** may indicate opportunities for performance improvement through +** may indicate opportunities for performance improvement through ** careful use of indices.
    ** ** [[SQLITE_STMTSTATUS_SORT]]
    SQLITE_STMTSTATUS_SORT
    @@ -7375,10 +8808,38 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** [[SQLITE_STMTSTATUS_VM_STEP]]
    SQLITE_STMTSTATUS_VM_STEP
    **
    ^This is the number of virtual machine operations executed ** by the prepared statement if that number is less than or equal -** to 2147483647. The number of virtual machine operations can be +** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. +** +** [[SQLITE_STMTSTATUS_REPREPARE]]
    SQLITE_STMTSTATUS_REPREPARE
    +**
    ^This is the number of times that the prepare statement has been +** automatically regenerated due to schema changes or changes to +** [bound parameters] that might affect the query plan. +** +** [[SQLITE_STMTSTATUS_RUN]]
    SQLITE_STMTSTATUS_RUN
    +**
    ^This is the number of times that the prepared statement has +** been run. A single "run" for the purposes of this counter is one +** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. +** The counter is incremented on the first [sqlite3_step()] call of each +** cycle. +** +** [[SQLITE_STMTSTATUS_FILTER_MISS]] +** [[SQLITE_STMTSTATUS_FILTER HIT]] +**
    SQLITE_STMTSTATUS_FILTER_HIT
    +** SQLITE_STMTSTATUS_FILTER_MISS
    +**
    ^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join +** step was bypassed because a Bloom filter returned not-found. The +** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of +** times that the Bloom filter returned a find, and thus the join step +** had to be processed as normal. +** +** [[SQLITE_STMTSTATUS_MEMUSED]]
    SQLITE_STMTSTATUS_MEMUSED
    +**
    ^This is the approximate number of bytes of heap memory +** used to store the prepared statement. ^This value is not actually +** a counter, and so the resetFlg parameter to sqlite3_stmt_status() +** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. **
    ** */ @@ -7386,6 +8847,11 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 +#define SQLITE_STMTSTATUS_REPREPARE 5 +#define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_FILTER_MISS 7 +#define SQLITE_STMTSTATUS_FILTER_HIT 8 +#define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object @@ -7421,15 +8887,15 @@ struct sqlite3_pcache_page { ** KEYWORDS: {page cache} ** ** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can -** register an alternative page cache implementation by passing in an +** register an alternative page cache implementation by passing in an ** instance of the sqlite3_pcache_methods2 structure.)^ -** In many applications, most of the heap memory allocated by +** In many applications, most of the heap memory allocated by ** SQLite is used for the page cache. -** By implementing a +** By implementing a ** custom page cache using this API, an application can better control -** the amount of memory consumed by SQLite, the way in which -** that memory is allocated and released, and the policies used to -** determine exactly which parts of a database file are cached and for +** the amount of memory consumed by SQLite, the way in which +** that memory is allocated and released, and the policies used to +** determine exactly which parts of a database file are cached and for ** how long. ** ** The alternative page cache mechanism is an @@ -7442,19 +8908,19 @@ struct sqlite3_pcache_page { ** [sqlite3_config()] returns.)^ ** ** [[the xInit() page cache method]] -** ^(The xInit() method is called once for each effective +** ^(The xInit() method is called once for each effective ** call to [sqlite3_initialize()])^ ** (usually only once during the lifetime of the process). ^(The xInit() ** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^ -** The intent of the xInit() method is to set up global data structures -** required by the custom page cache implementation. -** ^(If the xInit() method is NULL, then the +** The intent of the xInit() method is to set up global data structures +** required by the custom page cache implementation. +** ^(If the xInit() method is NULL, then the ** built-in default page cache is used instead of the application defined ** page cache.)^ ** ** [[the xShutdown() page cache method]] ** ^The xShutdown() method is called by [sqlite3_shutdown()]. -** It can be used to clean up +** It can be used to clean up ** any outstanding resources before process shutdown, if required. ** ^The xShutdown() method may be NULL. ** @@ -7473,7 +8939,7 @@ struct sqlite3_pcache_page { ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must ** be allocated by the cache. ^szPage will always a power of two. ^The -** second parameter szExtra is a number of bytes of extra storage +** second parameter szExtra is a number of bytes of extra storage ** associated with each page cache entry. ^The szExtra parameter will ** a number less than 250. SQLite will use the ** extra szExtra bytes on each page to store metadata about the underlying @@ -7486,7 +8952,7 @@ struct sqlite3_pcache_page { ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to -** false will always have the "discard" flag set to true. +** false will always have the "discard" flag set to true. ** ^Hence, a cache created with bPurgeable false will ** never contain any unpinned pages. ** @@ -7501,12 +8967,12 @@ struct sqlite3_pcache_page { ** [[the xPagecount() page cache methods]] ** The xPagecount() method must return the number of pages currently ** stored in the cache, both pinned and unpinned. -** +** ** [[the xFetch() page cache methods]] -** The xFetch() method locates a page in the cache and returns a pointer to +** The xFetch() method locates a page in the cache and returns a pointer to ** an sqlite3_pcache_page object associated with that page, or a NULL pointer. ** The pBuf element of the returned sqlite3_pcache_page object will be a -** pointer to a buffer of szPage bytes used to store the content of a +** pointer to a buffer of szPage bytes used to store the content of a ** single database page. The pExtra element of sqlite3_pcache_page will be ** a pointer to the szExtra bytes of extra storage that SQLite has requested ** for each entry in the page cache. @@ -7532,7 +8998,7 @@ struct sqlite3_pcache_page { ** ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite ** will only use a createFlag of 2 after a prior call with a createFlag of 1 -** failed.)^ In between the to xFetch() calls, SQLite may +** failed.)^ In between the xFetch() calls, SQLite may ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. ** @@ -7545,8 +9011,8 @@ struct sqlite3_pcache_page { ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** -** The cache must not perform any reference counting. A single -** call to xUnpin() unpins the page regardless of the number of prior calls +** The cache must not perform any reference counting. A single +** call to xUnpin() unpins the page regardless of the number of prior calls ** to xFetch(). ** ** [[the xRekey() page cache methods]] @@ -7586,7 +9052,7 @@ struct sqlite3_pcache_methods2 { int (*xPagecount)(sqlite3_pcache*); sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); - void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, unsigned oldKey, unsigned newKey); void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); void (*xDestroy)(sqlite3_pcache*); @@ -7631,7 +9097,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** ** The backup API copies the content of one database into another. ** It is useful either for creating backups of databases or -** for copying in-memory databases to or from persistent files. +** for copying in-memory databases to or from persistent files. ** ** See Also: [Using the SQLite Online Backup API] ** @@ -7642,36 +9108,36 @@ typedef struct sqlite3_backup sqlite3_backup; ** ^Thus, the backup may be performed on a live source database without ** preventing other database connections from ** reading or writing to the source database while the backup is underway. -** -** ^(To perform a backup operation: +** +** ^(To perform a backup operation: **
      **
    1. sqlite3_backup_init() is called once to initialize the -** backup, -**
    2. sqlite3_backup_step() is called one or more times to transfer +** backup, +**
    3. sqlite3_backup_step() is called one or more times to transfer ** the data between the two databases, and finally -**
    4. sqlite3_backup_finish() is called to release all resources -** associated with the backup operation. +**
    5. sqlite3_backup_finish() is called to release all resources +** associated with the backup operation. **
    )^ ** There should be exactly one call to sqlite3_backup_finish() for each ** successful call to sqlite3_backup_init(). ** ** [[sqlite3_backup_init()]] sqlite3_backup_init() ** -** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the -** [database connection] associated with the destination database +** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the +** [database connection] associated with the destination database ** and the database name, respectively. ** ^The database name is "main" for the main database, "temp" for the ** temporary database, or the name specified after the AS keyword in ** an [ATTACH] statement for an attached database. -** ^The S and M arguments passed to +** ^The S and M arguments passed to ** sqlite3_backup_init(D,N,S,M) identify the [database connection] ** and database name of the source database, respectively. ** ^The source and destination [database connections] (parameters S and D) ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** -** ^A call to sqlite3_backup_init() will fail, returning NULL, if -** there is already a read or read-write transaction open on the +** ^A call to sqlite3_backup_init() will fail, returning NULL, if +** there is already a read or read-write transaction open on the ** destination database. ** ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is @@ -7683,14 +9149,14 @@ typedef struct sqlite3_backup sqlite3_backup; ** ^A successful call to sqlite3_backup_init() returns a pointer to an ** [sqlite3_backup] object. ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and -** sqlite3_backup_finish() functions to perform the specified backup +** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** ** [[sqlite3_backup_step()]] sqlite3_backup_step() ** -** ^Function sqlite3_backup_step(B,N) will copy up to N pages between +** ^Function sqlite3_backup_step(B,N) will copy up to N pages between ** the source and destination databases specified by [sqlite3_backup] object B. -** ^If N is negative, all remaining source pages are copied. +** ^If N is negative, all remaining source pages are copied. ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there ** are still more pages to be copied, then the function returns [SQLITE_OK]. ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages @@ -7712,8 +9178,8 @@ typedef struct sqlite3_backup sqlite3_backup; ** ** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then ** the [sqlite3_busy_handler | busy-handler function] -** is invoked (if one is specified). ^If the -** busy-handler returns non-zero before the lock is available, then +** is invoked (if one is specified). ^If the +** busy-handler returns non-zero before the lock is available, then ** [SQLITE_BUSY] is returned to the caller. ^In this case the call to ** sqlite3_backup_step() can be retried later. ^If the source ** [database connection] @@ -7721,15 +9187,15 @@ typedef struct sqlite3_backup sqlite3_backup; ** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this ** case the call to sqlite3_backup_step() can be retried later on. ^(If ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or -** [SQLITE_READONLY] is returned, then -** there is no point in retrying the call to sqlite3_backup_step(). These -** errors are considered fatal.)^ The application must accept -** that the backup operation has failed and pass the backup operation handle +** [SQLITE_READONLY] is returned, then +** there is no point in retrying the call to sqlite3_backup_step(). These +** errors are considered fatal.)^ The application must accept +** that the backup operation has failed and pass the backup operation handle ** to the sqlite3_backup_finish() to release associated resources. ** ** ^The first call to sqlite3_backup_step() obtains an exclusive lock -** on the destination file. ^The exclusive lock is not released until either -** sqlite3_backup_finish() is called or the backup operation is complete +** on the destination file. ^The exclusive lock is not released until either +** sqlite3_backup_finish() is called or the backup operation is complete ** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to ** sqlite3_backup_step() obtains a [shared lock] on the source database that ** lasts for the duration of the sqlite3_backup_step() call. @@ -7738,18 +9204,18 @@ typedef struct sqlite3_backup sqlite3_backup; ** through the backup process. ^If the source database is modified by an ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically -** restarted by the next call to sqlite3_backup_step(). ^If the source +** restarted by the next call to sqlite3_backup_step(). ^If the source ** database is modified by the using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** ** [[sqlite3_backup_finish()]] sqlite3_backup_finish() ** -** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the +** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the ** application wishes to abandon the backup operation, the application ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). ** ^The sqlite3_backup_finish() interfaces releases all -** resources associated with the [sqlite3_backup] object. +** resources associated with the [sqlite3_backup] object. ** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any ** active write-transaction on the destination database is rolled back. ** The [sqlite3_backup] object is invalid @@ -7789,8 +9255,8 @@ typedef struct sqlite3_backup sqlite3_backup; ** connections, then the source database connection may be used concurrently ** from within other threads. ** -** However, the application must guarantee that the destination -** [database connection] is not passed to any other API (by any thread) after +** However, the application must guarantee that the destination +** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] @@ -7801,11 +9267,11 @@ typedef struct sqlite3_backup sqlite3_backup; ** If running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means -** that the application must guarantee that the disk file being +** that the application must guarantee that the disk file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). ** -** The [sqlite3_backup] object itself is partially threadsafe. Multiple +** The [sqlite3_backup] object itself is partially threadsafe. Multiple ** threads may safely make multiple concurrent calls to sqlite3_backup_step(). ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** APIs are not strictly speaking threadsafe. If they are invoked at the @@ -7830,8 +9296,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ^When running in shared-cache mode, a database operation may fail with ** an [SQLITE_LOCKED] error if the required locks on the shared-cache or ** individual tables within the shared-cache cannot be obtained. See -** [SQLite Shared-Cache Mode] for a description of shared-cache locking. -** ^This API may be used to register a callback that SQLite will invoke +** [SQLite Shared-Cache Mode] for a description of shared-cache locking. +** ^This API may be used to register a callback that SQLite will invoke ** when the connection currently holding the required lock relinquishes it. ** ^This API is only available if the library was compiled with the ** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. @@ -7839,18 +9305,18 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** See Also: [Using the SQLite Unlock Notification Feature]. ** ** ^Shared-cache locks are released when a database connection concludes -** its current transaction, either by committing it or rolling it back. +** its current transaction, either by committing it or rolling it back. ** ** ^When a connection (known as the blocked connection) fails to obtain a ** shared-cache lock and SQLITE_LOCKED is returned to the caller, the ** identity of the database connection (the blocking connection) that -** has locked the required resource is stored internally. ^After an +** has locked the required resource is stored internally. ^After an ** application receives an SQLITE_LOCKED error, it may call the -** sqlite3_unlock_notify() method with the blocked connection handle as +** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked ** when the blocking connections current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] -** call that concludes the blocking connections transaction. +** call that concludes the blocking connection's transaction. ** ** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, ** there is a chance that the blocking connection will have already @@ -7860,15 +9326,15 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ** ^If the blocked connection is attempting to obtain a write-lock on a ** shared-cache table, and more than one other connection currently holds -** a read-lock on the same table, then SQLite arbitrarily selects one of +** a read-lock on the same table, then SQLite arbitrarily selects one of ** the other connections to use as the blocking connection. ** -** ^(There may be at most one unlock-notify callback registered by a +** ^(There may be at most one unlock-notify callback registered by a ** blocked connection. If sqlite3_unlock_notify() is called when the ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback is canceled. ^The blocked connections ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** @@ -7881,25 +9347,25 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ** Callback Invocation Details ** -** When an unlock-notify callback is registered, the application provides a +** When an unlock-notify callback is registered, the application provides a ** single void* pointer that is passed to the callback when it is invoked. ** However, the signature of the callback function allows SQLite to pass ** it an array of void* context pointers. The first argument passed to ** an unlock-notify callback is a pointer to an array of void* pointers, ** and the second is the number of entries in the array. ** -** When a blocking connections transaction is concluded, there may be +** When a blocking connection's transaction is concluded, there may be ** more than one blocked connection that has registered for an unlock-notify ** callback. ^If two or more such blocked connections have specified the ** same callback function, then instead of invoking the callback function ** multiple times, it is invoked once with the set of void* context pointers ** specified by the blocked connections bundled together into an array. -** This gives the application an opportunity to prioritize any actions +** This gives the application an opportunity to prioritize any actions ** related to the set of unblocked database connections. ** ** Deadlock Detection ** -** Assuming that after registering for an unlock-notify callback a +** Assuming that after registering for an unlock-notify callback a ** database waits for the callback to be issued before taking any further ** action (a reasonable assumption), then using this API may cause the ** application to deadlock. For example, if connection X is waiting for @@ -7922,7 +9388,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ** The "DROP TABLE" Exception ** -** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost +** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost ** always appropriate to call sqlite3_unlock_notify(). There is however, ** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, ** SQLite checks if there are any currently executing SELECT statements @@ -7935,7 +9401,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** One way around this problem is to check the extended error code returned ** by an sqlite3_step() call. ^(If there is a blocking connection, then the ** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in -** the special "DROP TABLE/INDEX" case, the extended error code is just +** the special "DROP TABLE/INDEX" case, the extended error code is just ** SQLITE_LOCKED.)^ */ SQLITE_API int sqlite3_unlock_notify( @@ -8026,8 +9492,8 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** ^The [sqlite3_wal_hook()] function is used to register a callback that ** is invoked each time data is committed to a database in wal mode. ** -** ^(The callback is invoked by SQLite after the commit has taken place and -** the associated write-lock on the database released)^, so the implementation +** ^(The callback is invoked by SQLite after the commit has taken place and +** the associated write-lock on the database released)^, so the implementation ** may read, write or [checkpoint] the database as required. ** ** ^The first parameter passed to the callback function when it is invoked @@ -8046,15 +9512,16 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** -** A single database handle may have at most a single write-ahead log callback +** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^Note that the -** [sqlite3_wal_autocheckpoint()] interface and the +** previously registered write-ahead log callback. ^The return value is +** a copy of the third parameter from the previous call, if any, or 0. +** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will ** overwrite any prior [sqlite3_wal_hook()] settings. */ SQLITE_API void *sqlite3_wal_hook( - sqlite3*, + sqlite3*, int(*)(void *,sqlite3*,const char*,int), void* ); @@ -8067,7 +9534,7 @@ SQLITE_API void *sqlite3_wal_hook( ** [sqlite3_wal_hook()] that causes any database on [database connection] D ** to automatically [checkpoint] ** after committing a transaction if there are N or -** more frames in the [write-ahead log] file. ^Passing zero or +** more frames in the [write-ahead log] file. ^Passing zero or ** a negative value as the nFrame parameter disables automatic ** checkpoints entirely. ** @@ -8097,7 +9564,7 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); ** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to ** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ ** -** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the +** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the ** [write-ahead log] for database X on [database connection] D to be ** transferred into the database file and for the write-ahead log to ** be reset. See the [checkpointing] documentation for addition @@ -8123,10 +9590,10 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** **
    **
    SQLITE_CHECKPOINT_PASSIVE
    -** ^Checkpoint as many frames as possible without waiting for any database -** readers or writers to finish, then sync the database file if all frames +** ^Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish, then sync the database file if all frames ** in the log were checkpointed. ^The [busy-handler callback] -** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. +** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. ** ^On the other hand, passive mode might leave the checkpoint unfinished ** if there are concurrent readers or writers. ** @@ -8140,9 +9607,9 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** **
    SQLITE_CHECKPOINT_RESTART
    ** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition -** that after checkpointing the log file it blocks (calls the +** that after checkpointing the log file it blocks (calls the ** [busy-handler callback]) -** until all readers are reading from the database file only. ^This ensures +** until all readers are reading from the database file only. ^This ensures ** that the next writer will restart the log file from the beginning. ** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new ** database writer attempts while it is pending, but does not impede readers. @@ -8164,31 +9631,31 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. ** ** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If -** any other process is running a checkpoint operation at the same time, the -** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a +** any other process is running a checkpoint operation at the same time, the +** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a ** busy-handler configured, it will not be invoked in this case. ** -** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the +** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the ** exclusive "writer" lock on the database file. ^If the writer lock cannot be ** obtained immediately, and a busy-handler is configured, it is invoked and ** the writer lock retried until either the busy-handler returns 0 or the lock ** is successfully obtained. ^The busy-handler is also invoked while waiting for ** database readers as described above. ^If the busy-handler returns 0 before ** the writer lock is obtained or while waiting for database readers, the -** checkpoint operation proceeds from that point in the same way as -** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible +** checkpoint operation proceeds from that point in the same way as +** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible ** without blocking any further. ^SQLITE_BUSY is returned in this case. ** ** ^If parameter zDb is NULL or points to a zero length string, then the -** specified operation is attempted on all WAL databases [attached] to +** specified operation is attempted on all WAL databases [attached] to ** [database connection] db. In this case the -** values written to output parameters *pnLog and *pnCkpt are undefined. ^If -** an SQLITE_BUSY error is encountered when processing one or more of the -** attached WAL databases, the operation is still attempted on any remaining -** attached databases and SQLITE_BUSY is returned at the end. ^If any other -** error occurs while processing an attached database, processing is abandoned -** and the error code is returned to the caller immediately. ^If no error -** (SQLITE_BUSY or otherwise) is encountered while processing the attached +** values written to output parameters *pnLog and *pnCkpt are undefined. ^If +** an SQLITE_BUSY error is encountered when processing one or more of the +** attached WAL databases, the operation is still attempted on any remaining +** attached databases and SQLITE_BUSY is returned at the end. ^If any other +** error occurs while processing an attached database, processing is abandoned +** and the error code is returned to the caller immediately. ^If no error +** (SQLITE_BUSY or otherwise) is encountered while processing the attached ** databases, SQLITE_OK is returned. ** ** ^If database zDb is the name of an attached database that is not in WAL @@ -8236,21 +9703,28 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( ** If this interface is invoked outside the context of an xConnect or ** xCreate virtual table method then the behavior is undefined. ** -** At present, there is only one option that may be configured using -** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options -** may be added in the future. +** In the call sqlite3_vtab_config(D,C,...) the D parameter is the +** [database connection] in which the virtual table is being created and +** which is passed in as the first argument to the [xConnect] or [xCreate] +** method that is invoking sqlite3_vtab_config(). The C parameter is one +** of the [virtual table configuration options]. The presence and meaning +** of parameters after C depend on which [virtual table configuration option] +** is used. */ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options +** KEYWORDS: {virtual table configuration options} +** KEYWORDS: {virtual table configuration option} ** ** These macros define the various options to the ** [sqlite3_vtab_config()] interface that [virtual table] implementations ** can use to customize and optimize their behavior. ** **
    -**
    SQLITE_VTAB_CONSTRAINT_SUPPORT +** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] +**
    SQLITE_VTAB_CONSTRAINT_SUPPORT
    **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, ** where X is an integer. If X is zero, then the [virtual table] whose @@ -8264,24 +9738,46 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** If X is non-zero, then the virtual table implementation guarantees ** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before ** any modifications to internal or persistent data structures have been made. -** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite ** is able to roll back a statement or database transaction, and abandon -** or continue processing the current SQL statement as appropriate. +** or continue processing the current SQL statement as appropriate. ** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns ** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode ** had been ABORT. ** ** Virtual table implementations that are required to handle OR REPLACE -** must do so within the [xUpdate] method. If a call to the -** [sqlite3_vtab_on_conflict()] function indicates that the current ON -** CONFLICT policy is REPLACE, the virtual table implementation should +** must do so within the [xUpdate] method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should ** silently replace the appropriate rows within the xUpdate callback and ** return SQLITE_OK. Or, if this is not possible, it may return -** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT ** constraint handling. +**
    +** +** [[SQLITE_VTAB_DIRECTONLY]]
    SQLITE_VTAB_DIRECTONLY
    +**
    Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation +** prohibits that virtual table from being used from within triggers and +** views. +**
    +** +** [[SQLITE_VTAB_INNOCUOUS]]
    SQLITE_VTAB_INNOCUOUS
    +**
    Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation +** identify that virtual table as being safe to use from within triggers +** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the +** virtual table can do no serious harm even if it is controlled by a +** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS +** flag unless absolutely necessary. +**
    **
    */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 +#define SQLITE_VTAB_INNOCUOUS 2 +#define SQLITE_VTAB_DIRECTONLY 3 /* ** CAPI3REF: Determine The Virtual Table Conflict Policy @@ -8295,6 +9791,297 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); +/* +** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE +** +** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] +** method of a [virtual table], then it might return true if the +** column is being fetched as part of an UPDATE operation during which the +** column value will not change. The virtual table implementation can use +** this hint as permission to substitute a return value that is less +** expensive to compute and that the corresponding +** [xUpdate] method understands as a "no-change" value. +** +** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that +** the column is not changed by the UPDATE statement, then the xColumn +** method can optionally return without setting a result, without calling +** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. +** In that case, [sqlite3_value_nochange(X)] will return true for the +** same column in the [xUpdate] method. +** +** The sqlite3_vtab_nochange() routine is an optimization. Virtual table +** implementations should continue to give a correct answer even if the +** sqlite3_vtab_nochange() interface were to always return false. In the +** current implementation, the sqlite3_vtab_nochange() interface does always +** returns false for the enhanced [UPDATE FROM] statement. +*/ +SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); + +/* +** CAPI3REF: Determine The Collation For a Virtual Table Constraint +** METHOD: sqlite3_index_info +** +** This function may only be called from within a call to the [xBestIndex] +** method of a [virtual table]. This function returns a pointer to a string +** that is the name of the appropriate collation sequence to use for text +** comparisons on the constraint identified by its arguments. +** +** The first argument must be the pointer to the [sqlite3_index_info] object +** that is the first parameter to the xBestIndex() method. The second argument +** must be an index into the aConstraint[] array belonging to the +** sqlite3_index_info structure passed to xBestIndex. +** +** Important: +** The first parameter must be the same pointer that is passed into the +** xBestMethod() method. The first parameter may not be a pointer to a +** different [sqlite3_index_info] object, even an exact copy. +** +** The return value is computed as follows: +** +**
      +**
    1. If the constraint comes from a WHERE clause expression that contains +** a [COLLATE operator], then the name of the collation specified by +** that COLLATE operator is returned. +**

    2. If there is no COLLATE operator, but the column that is the subject +** of the constraint specifies an alternative collating sequence via +** a [COLLATE clause] on the column definition within the CREATE TABLE +** statement that was passed into [sqlite3_declare_vtab()], then the +** name of that alternative collating sequence is returned. +**

    3. Otherwise, "BINARY" is returned. +**

    +*/ +SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); + +/* +** CAPI3REF: Determine if a virtual table query is DISTINCT +** METHOD: sqlite3_index_info +** +** This API may only be used from within an [xBestIndex|xBestIndex method] +** of a [virtual table] implementation. The result of calling this +** interface from outside of xBestIndex() is undefined and probably harmful. +** +** ^The sqlite3_vtab_distinct() interface returns an integer that is +** either 0, 1, or 2. The integer returned by sqlite3_vtab_distinct() +** gives the virtual table additional information about how the query +** planner wants the output to be ordered. As long as the virtual table +** can meet the ordering requirements of the query planner, it may set +** the "orderByConsumed" flag. +** +**
    1. +** ^If the sqlite3_vtab_distinct() interface returns 0, that means +** that the query planner needs the virtual table to return all rows in the +** sort order defined by the "nOrderBy" and "aOrderBy" fields of the +** [sqlite3_index_info] object. This is the default expectation. If the +** virtual table outputs all rows in sorted order, then it is always safe for +** the xBestIndex method to set the "orderByConsumed" flag, regardless of +** the return value from sqlite3_vtab_distinct(). +**

    2. +** ^(If the sqlite3_vtab_distinct() interface returns 1, that means +** that the query planner does not need the rows to be returned in sorted order +** as long as all rows with the same values in all columns identified by the +** "aOrderBy" field are adjacent.)^ This mode is used when the query planner +** is doing a GROUP BY. +**

    3. +** ^(If the sqlite3_vtab_distinct() interface returns 2, that means +** that the query planner does not need the rows returned in any particular +** order, as long as rows with the same values in all "aOrderBy" columns +** are adjacent.)^ ^(Furthermore, only a single row for each particular +** combination of values in the columns identified by the "aOrderBy" field +** needs to be returned.)^ ^It is always ok for two or more rows with the same +** values in all "aOrderBy" columns to be returned, as long as all such rows +** are adjacent. ^The virtual table may, if it chooses, omit extra rows +** that have the same value for all columns identified by "aOrderBy". +** ^However omitting the extra rows is optional. +** This mode is used for a DISTINCT query. +**

    +** +** ^For the purposes of comparing virtual table output values to see if the +** values are same value for sorting purposes, two NULL values are considered +** to be the same. In other words, the comparison operator is "IS" +** (or "IS NOT DISTINCT FROM") and not "==". +** +** If a virtual table implementation is unable to meet the requirements +** specified above, then it must not set the "orderByConsumed" flag in the +** [sqlite3_index_info] object or an incorrect answer may result. +** +** ^A virtual table implementation is always free to return rows in any order +** it wants, as long as the "orderByConsumed" flag is not set. ^When the +** the "orderByConsumed" flag is unset, the query planner will add extra +** [bytecode] to ensure that the final results returned by the SQL query are +** ordered correctly. The use of the "orderByConsumed" flag and the +** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful +** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed" +** flag might help queries against a virtual table to run faster. Being +** overly aggressive and setting the "orderByConsumed" flag when it is not +** valid to do so, on the other hand, might cause SQLite to return incorrect +** results. +*/ +SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*); + +/* +** CAPI3REF: Identify and handle IN constraints in xBestIndex +** +** This interface may only be used from within an +** [xBestIndex|xBestIndex() method] of a [virtual table] implementation. +** The result of invoking this interface from any other context is +** undefined and probably harmful. +** +** ^(A constraint on a virtual table of the form +** "[IN operator|column IN (...)]" is +** communicated to the xBestIndex method as a +** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use +** this constraint, it must set the corresponding +** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under +** the usual mode of handling IN operators, SQLite generates [bytecode] +** that invokes the [xFilter|xFilter() method] once for each value +** on the right-hand side of the IN operator.)^ Thus the virtual table +** only sees a single value from the right-hand side of the IN operator +** at a time. +** +** In some cases, however, it would be advantageous for the virtual +** table to see all values on the right-hand of the IN operator all at +** once. The sqlite3_vtab_in() interfaces facilitates this in two ways: +** +**
      +**
    1. +** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero) +** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint +** is an [IN operator] that can be processed all at once. ^In other words, +** sqlite3_vtab_in() with -1 in the third argument is a mechanism +** by which the virtual table can ask SQLite if all-at-once processing +** of the IN operator is even possible. +** +**

    2. +** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates +** to SQLite that the virtual table does or does not want to process +** the IN operator all-at-once, respectively. ^Thus when the third +** parameter (F) is non-negative, this interface is the mechanism by +** which the virtual table tells SQLite how it wants to process the +** IN operator. +**

    +** +** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times +** within the same xBestIndex method call. ^For any given P,N pair, +** the return value from sqlite3_vtab_in(P,N,F) will always be the same +** within the same xBestIndex call. ^If the interface returns true +** (non-zero), that means that the constraint is an IN operator +** that can be processed all-at-once. ^If the constraint is not an IN +** operator or cannot be processed all-at-once, then the interface returns +** false. +** +** ^(All-at-once processing of the IN operator is selected if both of the +** following conditions are met: +** +**
      +**
    1. The P->aConstraintUsage[N].argvIndex value is set to a positive +** integer. This is how the virtual table tells SQLite that it wants to +** use the N-th constraint. +** +**

    2. The last call to sqlite3_vtab_in(P,N,F) for which F was +** non-negative had F>=1. +**

    )^ +** +** ^If either or both of the conditions above are false, then SQLite uses +** the traditional one-at-a-time processing strategy for the IN constraint. +** ^If both conditions are true, then the argvIndex-th parameter to the +** xFilter method will be an [sqlite3_value] that appears to be NULL, +** but which can be passed to [sqlite3_vtab_in_first()] and +** [sqlite3_vtab_in_next()] to find all values on the right-hand side +** of the IN constraint. +*/ +SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); + +/* +** CAPI3REF: Find all elements on the right-hand side of an IN constraint. +** +** These interfaces are only useful from within the +** [xFilter|xFilter() method] of a [virtual table] implementation. +** The result of invoking these interfaces from any other context +** is undefined and probably harmful. +** +** The X parameter in a call to sqlite3_vtab_in_first(X,P) or +** sqlite3_vtab_in_next(X,P) must be one of the parameters to the +** xFilter method which invokes these routines, and specifically +** a parameter that was previously selected for all-at-once IN constraint +** processing use the [sqlite3_vtab_in()] interface in the +** [xBestIndex|xBestIndex method]. ^(If the X parameter is not +** an xFilter argument that was selected for all-at-once IN constraint +** processing, then these routines return [SQLITE_MISUSE])^ or perhaps +** exhibit some other undefined or harmful behavior. +** +** ^(Use these routines to access all values on the right-hand side +** of the IN constraint using code like the following: +** +**
    +**    for(rc=sqlite3_vtab_in_first(pList, &pVal);
    +**        rc==SQLITE_OK && pVal
    +**        rc=sqlite3_vtab_in_next(pList, &pVal)
    +**    ){
    +**      // do something with pVal
    +**    }
    +**    if( rc!=SQLITE_OK ){
    +**      // an error has occurred
    +**    }
    +** 
    )^ +** +** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P) +** routines return SQLITE_OK and set *P to point to the first or next value +** on the RHS of the IN constraint. ^If there are no more values on the +** right hand side of the IN constraint, then *P is set to NULL and these +** routines return [SQLITE_DONE]. ^The return value might be +** some other value, such as SQLITE_NOMEM, in the event of a malfunction. +** +** The *ppOut values returned by these routines are only valid until the +** next call to either of these routines or until the end of the xFilter +** method from which these routines were called. If the virtual table +** implementation needs to retain the *ppOut values for longer, it must make +** copies. The *ppOut values are [protected sqlite3_value|protected]. +*/ +SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut); +SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); + +/* +** CAPI3REF: Constraint values in xBestIndex() +** METHOD: sqlite3_index_info +** +** This API may only be used from within the [xBestIndex|xBestIndex method] +** of a [virtual table] implementation. The result of calling this interface +** from outside of an xBestIndex method are undefined and probably harmful. +** +** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within +** the [xBestIndex] method of a [virtual table] implementation, with P being +** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and +** J being a 0-based index into P->aConstraint[], then this routine +** attempts to set *V to the value of the right-hand operand of +** that constraint if the right-hand operand is known. ^If the +** right-hand operand is not known, then *V is set to a NULL pointer. +** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if +** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) +** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th +** constraint is not available. ^The sqlite3_vtab_rhs_value() interface +** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if +** something goes wrong. +** +** The sqlite3_vtab_rhs_value() interface is usually only successful if +** the right-hand operand of a constraint is a literal value in the original +** SQL statement. If the right-hand operand is an expression or a reference +** to some other column or a [host parameter], then sqlite3_vtab_rhs_value() +** will probably return [SQLITE_NOTFOUND]. +** +** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and +** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such +** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^ +** +** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value +** and remains valid for the duration of the xBestIndex method call. +** ^When xBestIndex returns, the sqlite3_value object returned by +** sqlite3_vtab_rhs_value() is automatically deallocated. +** +** The "_rhs_" in the name of this routine is an abbreviation for +** "Right-Hand Side". +*/ +SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); + /* ** CAPI3REF: Conflict resolution modes ** KEYWORDS: {conflict resolution mode} @@ -8327,15 +10114,15 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** **
    ** [[SQLITE_SCANSTAT_NLOOP]]
    SQLITE_SCANSTAT_NLOOP
    -**
    ^The [sqlite3_int64] variable pointed to by the T parameter will be +**
    ^The [sqlite3_int64] variable pointed to by the V parameter will be ** set to the total number of times that the X-th loop has run.
    ** ** [[SQLITE_SCANSTAT_NVISIT]]
    SQLITE_SCANSTAT_NVISIT
    -**
    ^The [sqlite3_int64] variable pointed to by the T parameter will be set +**
    ^The [sqlite3_int64] variable pointed to by the V parameter will be set ** to the total number of rows examined by all iterations of the X-th loop.
    ** ** [[SQLITE_SCANSTAT_EST]]
    SQLITE_SCANSTAT_EST
    -**
    ^The "double" variable pointed to by the T parameter will be set to the +**
    ^The "double" variable pointed to by the V parameter will be set to the ** query planner's estimate for the average number of rows output from each ** iteration of the X-th loop. If the query planner's estimates was accurate, ** then this value will approximate the quotient NVISIT/NLOOP and the @@ -8343,17 +10130,17 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** be the NLOOP value for the current loop. ** ** [[SQLITE_SCANSTAT_NAME]]
    SQLITE_SCANSTAT_NAME
    -**
    ^The "const char *" variable pointed to by the T parameter will be set +**
    ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the name of the index or table ** used for the X-th loop. ** ** [[SQLITE_SCANSTAT_EXPLAIN]]
    SQLITE_SCANSTAT_EXPLAIN
    -**
    ^The "const char *" variable pointed to by the T parameter will be set +**
    ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** ** [[SQLITE_SCANSTAT_SELECTID]]
    SQLITE_SCANSTAT_SELECT
    -**
    ^The "int" variable pointed to by the T parameter will be set to the +**
    ^The "int" variable pointed to by the V parameter will be set to the ** "select-id" for the X-th loop. The select-id identifies which query or ** subquery the loop is part of. The main query has a select-id of zero. ** The select-id is the same value as is output in the first column @@ -8403,7 +10190,7 @@ SQLITE_API int sqlite3_stmt_scanstatus( int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ void *pOut /* Result written here */ -); +); /* ** CAPI3REF: Zero Scan-Status Counters @@ -8418,18 +10205,19 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction +** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty -** pages in the pager-cache that are not currently in use are written out +** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database ** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] ** interface flushes caches for all schemas - "main", "temp", and ** any [attached] databases. ** -** ^If this function needs to obtain extra database locks before dirty pages -** can be flushed to disk, it does so. ^If those locks cannot be obtained +** ^If this function needs to obtain extra database locks before dirty pages +** can be flushed to disk, it does so. ^If those locks cannot be obtained ** immediately and there is a busy-handler callback configured, it is invoked ** in the usual manner. ^If the required lock still cannot be obtained, then ** the database is skipped and an attempt made to flush any dirty pages @@ -8450,6 +10238,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. +** METHOD: sqlite3 ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. @@ -8467,7 +10256,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** ** ^The preupdate hook only fires for changes to real database tables; the ** preupdate hook is not invoked for changes to [virtual tables] or to -** system tables like sqlite_master or sqlite_stat1. +** system tables like sqlite_sequence or sqlite_stat1. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. @@ -8476,21 +10265,21 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** kind of update operation that is about to occur. ** ^(The fourth parameter to the preupdate callback is the name of the ** database within the database connection that is being modified. This -** will be "main" for the main database or "temp" for TEMP tables or +** will be "main" for the main database or "temp" for TEMP tables or ** the name given after the AS keyword in the [ATTACH] statement for attached ** databases.)^ ** ^The fifth parameter to the preupdate callback is the name of the ** table that is being modified. ** ** For an UPDATE or DELETE operation on a [rowid table], the sixth -** parameter passed to the preupdate callback is the initial [rowid] of the +** parameter passed to the preupdate callback is the initial [rowid] of the ** row being modified or deleted. For an INSERT operation on a rowid table, -** or any operation on a WITHOUT ROWID table, the value of the sixth +** or any operation on a WITHOUT ROWID table, the value of the sixth ** parameter is undefined. For an INSERT or UPDATE on a rowid table the ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for -** INSERT operations on rowid tables. +** DELETE operations on rowid tables. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces @@ -8524,10 +10313,19 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** ** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate ** callback was invoked as a result of a direct insert, update, or delete -** operation; or 1 for inserts, updates, or deletes invoked by top-level +** operation; or 1 for inserts, updates, or deletes invoked by top-level ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** +** When the [sqlite3_blob_write()] API is used to update a blob column, +** the pre-update hook is invoked with SQLITE_DELETE. This is because the +** in this case the new values are not available. In this case, when a +** callback made with op==SQLITE_DELETE is actuall a write using the +** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns +** the index of the column being written. In other cases, where the +** pre-update hook is being invoked for some other reason, including a +** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. +** ** See also: [sqlite3_update_hook()] */ #if defined(SQLITE_ENABLE_PREUPDATE_HOOK) @@ -8548,24 +10346,25 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); SQLITE_API int sqlite3_preupdate_count(sqlite3 *); SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); +SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *); #endif /* ** CAPI3REF: Low-level system error code +** METHOD: sqlite3 ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. ** The return value is OS-dependent. For example, on unix systems, after ** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be ** called to get back the underlying "errno" that caused the problem, such -** as ENOSPC, EAUTH, EISDIR, and so forth. +** as ENOSPC, EAUTH, EISDIR, and so forth. */ SQLITE_API int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot ** KEYWORDS: {snapshot} {sqlite3_snapshot} -** EXPERIMENTAL ** ** An instance of the snapshot object records the state of a [WAL mode] ** database for some specific point in history. @@ -8582,11 +10381,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*); ** version of the database file so that it is possible to later open a new read ** transaction that sees that historical version of the database rather than ** the most recent version. -** -** The constructor for this object is [sqlite3_snapshot_get()]. The -** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer -** to an historical snapshot (if possible). The destructor for -** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. */ typedef struct sqlite3_snapshot { unsigned char hidden[48]; @@ -8594,7 +10388,7 @@ typedef struct sqlite3_snapshot { /* ** CAPI3REF: Record A Database Snapshot -** EXPERIMENTAL +** CONSTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of @@ -8602,15 +10396,15 @@ typedef struct sqlite3_snapshot { ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. ** If there is not already a read-transaction open on schema S when -** this function is called, one is opened automatically. +** this function is called, one is opened automatically. ** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined -** in this case. +** in this case. ** **
      -**
    • The database handle must be in [autocommit mode]. +**
    • The database handle must not be in [autocommit mode]. ** **
    • Schema S of [database connection] D must be a [WAL mode] database. ** @@ -8619,13 +10413,13 @@ typedef struct sqlite3_snapshot { ** **
    • One or more transactions must have been written to the current wal ** file since it was created on disk (by any connection). This means -** that a snapshot cannot be taken on a wal mode database with no wal +** that a snapshot cannot be taken on a wal mode database with no wal ** file immediately after it is first opened. At least one transaction ** must be written to it first. **
    ** ** This function may also return SQLITE_NOMEM. If it is called with the -** database handle in autocommit mode but fails for some other reason, +** database handle in autocommit mode but fails for some other reason, ** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to @@ -8633,7 +10427,7 @@ typedef struct sqlite3_snapshot { ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, @@ -8643,35 +10437,46 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( /* ** CAPI3REF: Start a read transaction on an historical snapshot -** EXPERIMENTAL +** METHOD: sqlite3_snapshot +** +** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read +** transaction or upgrades an existing one for schema S of +** [database connection] D such that the read transaction refers to +** historical [snapshot] P, rather than the most recent change to the +** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK +** on success or an appropriate [error code] if it fails. +** +** ^In order to succeed, the database connection must not be in +** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there +** is already a read transaction open on schema S, then the database handle +** must have no active statements (SELECT statements that have been passed +** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). +** SQLITE_ERROR is returned if either of these conditions is violated, or +** if schema S does not exist, or if the snapshot object is invalid. +** +** ^A call to sqlite3_snapshot_open() will fail to open if the specified +** snapshot has been overwritten by a [checkpoint]. In this case +** SQLITE_ERROR_SNAPSHOT is returned. +** +** If there is already a read transaction open when this function is +** invoked, then the same read transaction remains open (on the same +** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT +** is returned. If another error code - for example SQLITE_PROTOCOL or an +** SQLITE_IOERR error code - is returned, then the final state of the +** read transaction is undefined. If SQLITE_OK is returned, then the +** read transaction is now open on database snapshot P. ** -** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a -** read transaction for schema S of -** [database connection] D such that the read transaction -** refers to historical [snapshot] P, rather than the most -** recent change to the database. -** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success -** or an appropriate [error code] if it fails. -** -** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be -** the first operation following the [BEGIN] that takes the schema S -** out of [autocommit mode]. -** ^In other words, schema S must not currently be in -** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the -** database connection D must be out of [autocommit mode]. -** ^A [snapshot] will fail to open if it has been overwritten by a -** [checkpoint]. ** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the ** database connection D does not know that the database file for ** schema S is in [WAL mode]. A database connection might not know ** that the database file is in [WAL mode] if there has been no prior -** I/O on that database connection, or if the database entered [WAL mode] +** I/O on that database connection, or if the database entered [WAL mode] ** after the most recent I/O on the database connection.)^ ** (Hint: Run "[PRAGMA application_id]" against a newly opened ** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, @@ -8681,38 +10486,41 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( /* ** CAPI3REF: Destroy a snapshot -** EXPERIMENTAL +** DESTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. ** The application must eventually free every [sqlite3_snapshot] object ** using this routine to avoid a memory leak. ** ** The [sqlite3_snapshot_free()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages -** of two valid snapshot handles. +** of two valid snapshot handles. ** -** If the two snapshot handles are not associated with the same database -** file, the result of the comparison is undefined. +** If the two snapshot handles are not associated with the same database +** file, the result of the comparison is undefined. ** ** Additionally, the result of the comparison is only valid if both of the ** snapshot handles were obtained by calling sqlite3_snapshot_get() since the ** last time the wal file was deleted. The wal file is deleted when the ** database is changed back to rollback mode or when the number of database -** clients drops to zero. If either snapshot handle was obtained before the -** wal file was last deleted, the value returned by this function +** clients drops to zero. If either snapshot handle was obtained before the +** wal file was last deleted, the value returned by this function ** is undefined. ** ** Otherwise, this API returns a negative value if P1 refers to an older ** snapshot than P2, zero if the two handles refer to the same database ** snapshot, and a positive value if P1 is a newer snapshot than P2. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, @@ -8721,26 +10529,155 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( /* ** CAPI3REF: Recover snapshots from a wal file -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** -** If all connections disconnect from a database file but do not perform -** a checkpoint, the existing wal file is opened along with the database -** file the next time the database is opened. At this point it is only -** possible to successfully call sqlite3_snapshot_open() to open the most -** recent snapshot of the database (the one at the head of the wal file), -** even though the wal file may contain other valid snapshots for which -** clients have sqlite3_snapshot handles. +** If a [WAL file] remains on disk after all database connections close +** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] +** or because the last process to have the database opened exited without +** calling [sqlite3_close()]) and a new connection is subsequently opened +** on that database and [WAL file], the [sqlite3_snapshot_open()] interface +** will only be able to open the last transaction added to the WAL file +** even though the WAL file contains other valid transactions. ** -** This function attempts to scan the wal file associated with database zDb +** This function attempts to scan the WAL file associated with database zDb ** of database handle db and make all valid snapshots available to ** sqlite3_snapshot_open(). It is an error if there is already a read -** transaction open on the database, or if the database is not a wal mode +** transaction open on the database, or if the database is not a WAL mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); +/* +** CAPI3REF: Serialize a database +** +** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory +** that is a serialization of the S database on [database connection] D. +** If P is not a NULL pointer, then the size of the database in bytes +** is written into *P. +** +** For an ordinary on-disk database file, the serialization is just a +** copy of the disk file. For an in-memory database or a "TEMP" database, +** the serialization is the same sequence of bytes which would be written +** to disk if that database where backed up to disk. +** +** The usual case is that sqlite3_serialize() copies the serialization of +** the database into memory obtained from [sqlite3_malloc64()] and returns +** a pointer to that memory. The caller is responsible for freeing the +** returned value to avoid a memory leak. However, if the F argument +** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations +** are made, and the sqlite3_serialize() function will return a pointer +** to the contiguous memory representation of the database that SQLite +** is currently using for that database, or NULL if the no such contiguous +** memory representation of the database exists. A contiguous memory +** representation of the database will usually only exist if there has +** been a prior call to [sqlite3_deserialize(D,S,...)] with the same +** values of D and S. +** The size of the database is written into *P even if the +** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy +** of the database exists. +** +** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the +** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory +** allocation error occurs. +** +** This interface is omitted if SQLite is compiled with the +** [SQLITE_OMIT_DESERIALIZE] option. +*/ +SQLITE_API unsigned char *sqlite3_serialize( + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ + sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ + unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3_serialize +** +** Zero or more of the following constants can be OR-ed together for +** the F argument to [sqlite3_serialize(D,S,P,F)]. +** +** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return +** a pointer to contiguous in-memory database that it is currently using, +** without making a copy of the database. If SQLite is not currently using +** a contiguous in-memory database, then this option causes +** [sqlite3_serialize()] to return a NULL pointer. SQLite will only be +** using a contiguous in-memory database if it has been initialized by a +** prior call to [sqlite3_deserialize()]. +*/ +#define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */ + +/* +** CAPI3REF: Deserialize a database +** +** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the +** [database connection] D to disconnect from database S and then +** reopen S as an in-memory database based on the serialization contained +** in P. The serialized database P is N bytes in size. M is the size of +** the buffer P, which might be larger than N. If M is larger than N, and +** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is +** permitted to add content to the in-memory database as long as the total +** size does not exceed M bytes. +** +** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will +** invoke sqlite3_free() on the serialization buffer when the database +** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then +** SQLite will try to increase the buffer size using sqlite3_realloc64() +** if writes on the database cause it to grow larger than M bytes. +** +** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the +** database is currently in a read transaction or is involved in a backup +** operation. +** +** It is not possible to deserialized into the TEMP database. If the +** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the +** function returns SQLITE_ERROR. +** +** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the +** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then +** [sqlite3_free()] is invoked on argument P prior to returning. +** +** This interface is omitted if SQLite is compiled with the +** [SQLITE_OMIT_DESERIALIZE] option. +*/ +SQLITE_API int sqlite3_deserialize( + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which DB to reopen with the deserialization */ + unsigned char *pData, /* The serialized database content */ + sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szBuf, /* Total size of buffer pData[] */ + unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3_deserialize() +** +** The following are allowed values for 6th argument (the F argument) to +** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. +** +** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization +** in the P argument is held in memory obtained from [sqlite3_malloc64()] +** and that SQLite should take ownership of this memory and automatically +** free it when it has finished using it. Without this flag, the caller +** is responsible for freeing any dynamically allocated memory. +** +** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to +** grow the size of the database using calls to [sqlite3_realloc64()]. This +** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. +** Without this flag, the deserialized database cannot increase in size beyond +** the number of bytes specified by the M parameter. +** +** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database +** should be treated as read-only. +*/ +#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */ +#define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ +#define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. @@ -8815,7 +10752,7 @@ struct sqlite3_rtree_geometry { }; /* -** Register a 2nd-generation geometry callback named zScore that can be +** Register a 2nd-generation geometry callback named zScore that can be ** used as part of an R-Tree geometry query as follows: ** ** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) @@ -8830,7 +10767,7 @@ SQLITE_API int sqlite3_rtree_query_callback( /* -** A pointer to a structure of the following type is passed as the +** A pointer to a structure of the following type is passed as the ** argument to scored geometry callback registered using ** sqlite3_rtree_query_callback(). ** @@ -8852,7 +10789,7 @@ struct sqlite3_rtree_query_info { sqlite3_int64 iRowid; /* Rowid for current entry */ sqlite3_rtree_dbl rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ + int eWithin; /* OUT: Visibility */ sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ /* The following fields are only available in 3.8.11 and later */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ @@ -8888,16 +10825,23 @@ extern "C" { /* ** CAPI3REF: Session Object Handle +** +** An instance of this object is a [session] that can be used to +** record changes to a database. */ typedef struct sqlite3_session sqlite3_session; /* ** CAPI3REF: Changeset Iterator Handle +** +** An instance of this object acts as a cursor for iterating +** over the elements of a [changeset] or [patchset]. */ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; /* ** CAPI3REF: Create A New Session Object +** CONSTRUCTOR: sqlite3_session ** ** Create a new session object attached to database handle db. If successful, ** a pointer to the new object is written to *ppSession and SQLITE_OK is @@ -8918,7 +10862,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; ** is not possible for an application to register a pre-update hook on a ** database handle that has one or more session objects attached. Nor is ** it possible to create a session object attached to a database handle for -** which a pre-update hook is already defined. The results of attempting +** which a pre-update hook is already defined. The results of attempting ** either of these things are undefined. ** ** The session object will be used to create changesets for tables in @@ -8934,21 +10878,55 @@ SQLITE_API int sqlite3session_create( /* ** CAPI3REF: Delete A Session Object +** DESTRUCTOR: sqlite3_session ** -** Delete a session object previously allocated using +** Delete a session object previously allocated using ** [sqlite3session_create()]. Once a session object has been deleted, the ** results of attempting to use pSession with any other session module ** function are undefined. ** ** Session objects must be deleted before the database handle to which they -** are attached is closed. Refer to the documentation for +** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); +/* +** CAPIREF: Conigure a Session Object +** METHOD: sqlite3_session +** +** This method is used to configure a session object after it has been +** created. At present the only valid value for the second parameter is +** [SQLITE_SESSION_OBJCONFIG_SIZE]. +** +** Arguments for sqlite3session_object_config() +** +** The following values may passed as the the 4th parameter to +** sqlite3session_object_config(). +** +**
    SQLITE_SESSION_OBJCONFIG_SIZE
    +** This option is used to set, clear or query the flag that enables +** the [sqlite3session_changeset_size()] API. Because it imposes some +** computational overhead, this API is disabled by default. Argument +** pArg must point to a value of type (int). If the value is initially +** 0, then the sqlite3session_changeset_size() API is disabled. If it +** is greater than 0, then the same API is enabled. Or, if the initial +** value is less than zero, no change is made. In all cases the (int) +** variable is set to 1 if the sqlite3session_changeset_size() API is +** enabled following the current call, or 0 otherwise. +** +** It is an error (SQLITE_MISUSE) to attempt to modify this setting after +** the first table has been attached to the session object. +*/ +SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); + +/* +*/ +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object +** METHOD: sqlite3_session ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When @@ -8958,16 +10936,17 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); ** the eventual changesets. ** ** Passing zero to this function disables the session. Passing a value -** greater than zero enables it. Passing a value less than zero is a +** greater than zero enables it. Passing a value less than zero is a ** no-op, and may be used to query the current state of the session. ** -** The return value indicates the final state of the session object: 0 if +** The return value indicates the final state of the session object: 0 if ** the session is disabled, or 1 if it is enabled. */ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Set Or Clear the Indirect Change Flag +** METHOD: sqlite3_session ** ** Each change recorded by a session object is marked as either direct or ** indirect. A change is marked as indirect if either: @@ -8975,7 +10954,7 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); **
      **
    • The session object "indirect" flag is set when the change is ** made, or -**
    • The change is made by an SQL trigger or foreign key action +**
    • The change is made by an SQL trigger or foreign key action ** instead of directly as a result of a users SQL statement. **
    ** @@ -8987,32 +10966,33 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); ** flag. If the second argument passed to this function is zero, then the ** indirect flag is cleared. If it is greater than zero, the indirect flag ** is set. Passing a value less than zero does not modify the current value -** of the indirect flag, and may be used to query the current state of the +** of the indirect flag, and may be used to query the current state of the ** indirect flag for the specified session object. ** -** The return value indicates the final state of the indirect flag: 0 if +** The return value indicates the final state of the indirect flag: 0 if ** it is clear, or 1 if it is set. */ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); /* ** CAPI3REF: Attach A Table To A Session Object +** METHOD: sqlite3_session ** ** If argument zTab is not NULL, then it is the name of a table to attach -** to the session object passed as the first argument. All subsequent changes -** made to the table while the session object is enabled will be recorded. See +** to the session object passed as the first argument. All subsequent changes +** made to the table while the session object is enabled will be recorded. See ** documentation for [sqlite3session_changeset()] for further details. ** ** Or, if argument zTab is NULL, then changes are recorded for all tables -** in the database. If additional tables are added to the database (by -** executing "CREATE TABLE" statements) after this call is made, changes for +** in the database. If additional tables are added to the database (by +** executing "CREATE TABLE" statements) after this call is made, changes for ** the new tables are also recorded. ** ** Changes can only be recorded for tables that have a PRIMARY KEY explicitly -** defined as part of their CREATE TABLE statement. It does not matter if the +** defined as part of their CREATE TABLE statement. It does not matter if the ** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY ** KEY may consist of a single column, or may be a composite key. -** +** ** It is not an error if the named table does not exist in the database. Nor ** is it an error if the named table does not have a PRIMARY KEY. However, ** no changes will be recorded in either of these scenarios. @@ -9020,8 +11000,37 @@ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect) ** Changes are not recorded for individual rows that have NULL values stored ** in one or more of their PRIMARY KEY columns. ** -** SQLITE_OK is returned if the call completes without error. Or, if an error +** SQLITE_OK is returned if the call completes without error. Or, if an error ** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. +** +**

    Special sqlite_stat1 Handling

    +** +** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to +** some of the rules above. In SQLite, the schema of sqlite_stat1 is: +**
    +**        CREATE TABLE sqlite_stat1(tbl,idx,stat)
    +**  
    +** +** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are +** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes +** are recorded for rows for which (idx IS NULL) is true. However, for such +** rows a zero-length blob (SQL value X'') is stored in the changeset or +** patchset instead of a NULL value. This allows such changesets to be +** manipulated by legacy implementations of sqlite3changeset_invert(), +** concat() and similar. +** +** The sqlite3changeset_apply() function automatically converts the +** zero-length blob back to a NULL value when updating the sqlite_stat1 +** table. However, if the application calls sqlite3changeset_new(), +** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset +** iterator directly (including on a changeset iterator passed to a +** conflict-handler callback) then the X'' value is returned. The application +** must translate X'' to NULL itself if required. +** +** Legacy (older than 3.22.0) versions of the sessions module cannot capture +** changes made to the sqlite_stat1 table. Legacy versions of the +** sqlite3changeset_apply() function silently ignore any modifications to the +** sqlite_stat1 table that are part of a changeset or patchset. */ SQLITE_API int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ @@ -9030,11 +11039,12 @@ SQLITE_API int sqlite3session_attach( /* ** CAPI3REF: Set a table filter on a Session Object. +** METHOD: sqlite3_session ** -** The second argument (xFilter) is the "filter callback". For changes to rows +** The second argument (xFilter) is the "filter callback". For changes to rows ** in tables that are not attached to the Session object, the filter is called -** to determine whether changes to the table's rows should be tracked or not. -** If xFilter returns 0, changes is not tracked. Note that once a table is +** to determine whether changes to the table's rows should be tracked or not. +** If xFilter returns 0, changes are not tracked. Note that once a table is ** attached, xFilter will not be called again. */ SQLITE_API void sqlite3session_table_filter( @@ -9048,10 +11058,11 @@ SQLITE_API void sqlite3session_table_filter( /* ** CAPI3REF: Generate A Changeset From A Session Object +** METHOD: sqlite3_session ** -** Obtain a changeset containing changes to the tables attached to the -** session object passed as the first argument. If successful, -** set *ppChangeset to point to a buffer containing the changeset +** Obtain a changeset containing changes to the tables attached to the +** session object passed as the first argument. If successful, +** set *ppChangeset to point to a buffer containing the changeset ** and *pnChangeset to the size of the changeset in bytes before returning ** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to ** zero and return an SQLite error code. @@ -9066,7 +11077,7 @@ SQLITE_API void sqlite3session_table_filter( ** modifies the values of primary key columns. If such a change is made, it ** is represented in a changeset as a DELETE followed by an INSERT. ** -** Changes are not recorded for rows that have NULL values stored in one or +** Changes are not recorded for rows that have NULL values stored in one or ** more of their PRIMARY KEY columns. If such a row is inserted or deleted, ** no corresponding change is present in the changesets returned by this ** function. If an existing row with one or more NULL values stored in @@ -9119,14 +11130,14 @@ SQLITE_API void sqlite3session_table_filter( **
      **
    • For each record generated by an insert, the database is queried ** for a row with a matching primary key. If one is found, an INSERT -** change is added to the changeset. If no such row is found, no change +** change is added to the changeset. If no such row is found, no change ** is added to the changeset. ** -**
    • For each record generated by an update or delete, the database is +**
    • For each record generated by an update or delete, the database is ** queried for a row with a matching primary key. If such a row is ** found and one or more of the non-primary key fields have been -** modified from their original values, an UPDATE change is added to -** the changeset. Or, if no such row is found in the table, a DELETE +** modified from their original values, an UPDATE change is added to +** the changeset. Or, if no such row is found in the table, a DELETE ** change is added to the changeset. If there is a row with a matching ** primary key in the database, but all fields contain their original ** values, no change is added to the changeset. @@ -9134,7 +11145,7 @@ SQLITE_API void sqlite3session_table_filter( ** ** This means, amongst other things, that if a row is inserted and then later ** deleted while a session object is active, neither the insert nor the delete -** will be present in the changeset. Or if a row is deleted and then later a +** will be present in the changeset. Or if a row is deleted and then later a ** row with the same primary key values inserted while a session object is ** active, the resulting changeset will contain an UPDATE change instead of ** a DELETE and an INSERT. @@ -9143,10 +11154,10 @@ SQLITE_API void sqlite3session_table_filter( ** it does not accumulate records when rows are inserted, updated or deleted. ** This may appear to have some counter-intuitive effects if a single row ** is written to more than once during a session. For example, if a row -** is inserted while a session object is enabled, then later deleted while +** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and +** Or, if one field of a row is updated while a session is disabled, and ** another field of the same row is updated while the session is enabled, the ** resulting changeset will contain an UPDATE change that updates both fields. */ @@ -9157,7 +11168,24 @@ SQLITE_API int sqlite3session_changeset( ); /* -** CAPI3REF: Load The Difference Between Tables Into A Session +** CAPI3REF: Return An Upper-limit For The Size Of The Changeset +** METHOD: sqlite3_session +** +** By default, this function always returns 0. For it to return +** a useful result, the sqlite3_session object must have been configured +** to enable this API using sqlite3session_object_config() with the +** SQLITE_SESSION_OBJCONFIG_SIZE verb. +** +** When enabled, this function returns an upper limit, in bytes, for the size +** of the changeset that might be produced if sqlite3session_changeset() were +** called. The final changeset size might be equal to or smaller than the +** size in bytes returned by this function. +*/ +SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession); + +/* +** CAPI3REF: Load The Difference Between Tables Into A Session +** METHOD: sqlite3_session ** ** If it is not already attached to the session object passed as the first ** argument, this function attaches table zTbl in the same manner as the @@ -9166,7 +11194,7 @@ SQLITE_API int sqlite3session_changeset( ** an error). ** ** Argument zFromDb must be the name of a database ("main", "temp" etc.) -** attached to the same database handle as the session object that contains +** attached to the same database handle as the session object that contains ** a table compatible with the table attached to the session by this function. ** A table is considered compatible if it: ** @@ -9182,33 +11210,33 @@ SQLITE_API int sqlite3session_changeset( ** APIs, tables without PRIMARY KEYs are simply ignored. ** ** This function adds a set of changes to the session object that could be -** used to update the table in database zFrom (call this the "from-table") -** so that its content is the same as the table attached to the session +** used to update the table in database zFrom (call this the "from-table") +** so that its content is the same as the table attached to the session ** object (call this the "to-table"). Specifically: ** **
        -**
      • For each row (primary key) that exists in the to-table but not in +**
      • For each row (primary key) that exists in the to-table but not in ** the from-table, an INSERT record is added to the session object. ** -**
      • For each row (primary key) that exists in the to-table but not in +**
      • For each row (primary key) that exists in the to-table but not in ** the from-table, a DELETE record is added to the session object. ** -**
      • For each row (primary key) that exists in both tables, but features +**
      • For each row (primary key) that exists in both tables, but features ** different non-PK values in each, an UPDATE record is added to the -** session. +** session. **
      ** ** To clarify, if this function is called and then a changeset constructed -** using [sqlite3session_changeset()], then after applying that changeset to -** database zFrom the contents of the two compatible tables would be +** using [sqlite3session_changeset()], then after applying that changeset to +** database zFrom the contents of the two compatible tables would be ** identical. ** ** It an error if database zFrom does not exist or does not contain the ** required compatible table. ** -** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite +** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg -** may be set to point to a buffer containing an English language error +** may be set to point to a buffer containing an English language error ** message. It is the responsibility of the caller to free this buffer using ** sqlite3_free(). */ @@ -9222,23 +11250,24 @@ SQLITE_API int sqlite3session_diff( /* ** CAPI3REF: Generate A Patchset From A Session Object +** METHOD: sqlite3_session ** ** The differences between a patchset and a changeset are that: ** **
        -**
      • DELETE records consist of the primary key fields only. The +**
      • DELETE records consist of the primary key fields only. The ** original values of other fields are omitted. -**
      • The original values of any modified fields are omitted from +**
      • The original values of any modified fields are omitted from ** UPDATE records. **
      ** -** A patchset blob may be used with up to date versions of all -** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), +** A patchset blob may be used with up to date versions of all +** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), ** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, ** attempting to use a patchset blob with old versions of the -** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. +** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. ** -** Because the non-primary key "old.*" fields are omitted, no +** Because the non-primary key "old.*" fields are omitted, no ** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset ** is passed to the sqlite3changeset_apply() API. Other conflict types work ** in the same way as for changesets. @@ -9250,36 +11279,45 @@ SQLITE_API int sqlite3session_diff( */ SQLITE_API int sqlite3session_patchset( sqlite3_session *pSession, /* Session object */ - int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ - void **ppPatchset /* OUT: Buffer containing changeset */ + int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void **ppPatchset /* OUT: Buffer containing patchset */ ); /* ** CAPI3REF: Test if a changeset has recorded any changes. ** -** Return non-zero if no changes to attached tables have been recorded by -** the session object passed as the first argument. Otherwise, if one or +** Return non-zero if no changes to attached tables have been recorded by +** the session object passed as the first argument. Otherwise, if one or ** more changes have been recorded, return zero. ** ** Even if this function returns zero, it is possible that calling ** [sqlite3session_changeset()] on the session handle may still return a -** changeset that contains no changes. This can happen when a row in -** an attached table is modified and then later on the original values +** changeset that contains no changes. This can happen when a row in +** an attached table is modified and then later on the original values ** are restored. However, if this function returns non-zero, then it is -** guaranteed that a call to sqlite3session_changeset() will return a +** guaranteed that a call to sqlite3session_changeset() will return a ** changeset containing zero changes. */ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); /* -** CAPI3REF: Create An Iterator To Traverse A Changeset +** CAPI3REF: Query for the amount of heap memory used by a session object. +** +** This API returns the total amount of heap memory in bytes currently +** used by the session object passed as the only argument. +*/ +SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession); + +/* +** CAPI3REF: Create An Iterator To Traverse A Changeset +** CONSTRUCTOR: sqlite3_changeset_iter ** ** Create an iterator used to iterate through the contents of a changeset. ** If successful, *pp is set to point to the iterator handle and SQLITE_OK ** is returned. Otherwise, if an error occurs, *pp is set to zero and an ** SQLite error code is returned. ** -** The following functions can be used to advance and query a changeset +** The following functions can be used to advance and query a changeset ** iterator created by this function: ** **
        @@ -9296,25 +11334,52 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); ** ** Assuming the changeset blob was created by one of the ** [sqlite3session_changeset()], [sqlite3changeset_concat()] or -** [sqlite3changeset_invert()] functions, all changes within the changeset -** that apply to a single table are grouped together. This means that when -** an application iterates through a changeset using an iterator created by -** this function, all changes that relate to a single table are visited -** consecutively. There is no chance that the iterator will visit a change -** the applies to table X, then one for table Y, and then later on visit +** [sqlite3changeset_invert()] functions, all changes within the changeset +** that apply to a single table are grouped together. This means that when +** an application iterates through a changeset using an iterator created by +** this function, all changes that relate to a single table are visited +** consecutively. There is no chance that the iterator will visit a change +** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
        SQLITE_CHANGESETAPPLY_INVERT
        +** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* ** CAPI3REF: Advance A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** -** This function may only be used with iterators created by function +** This function may only be used with iterators created by the function ** [sqlite3changeset_start()]. If it is called on an iterator passed to ** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE ** is returned and the call has no effect. @@ -9325,18 +11390,19 @@ SQLITE_API int sqlite3changeset_start( ** point to the first change in the changeset. Each subsequent call advances ** the iterator to point to the next change in the changeset (if any). If ** no error occurs and the iterator points to a valid change after a call -** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. +** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. ** Otherwise, if all changes in the changeset have already been visited, ** SQLITE_DONE is returned. ** -** If an error occurs, an SQLite error code is returned. Possible error -** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or +** If an error occurs, an SQLite error code is returned. Possible error +** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or ** SQLITE_NOMEM. */ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Obtain The Current Operation From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator @@ -9344,18 +11410,23 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this ** is not the case, this function returns [SQLITE_MISUSE]. ** -** If argument pzTab is not NULL, then *pzTab is set to point to a -** nul-terminated utf-8 encoded string containing the name of the table -** affected by the current change. The buffer remains valid until either -** sqlite3changeset_next() is called on the iterator or until the -** conflict-handler function returns. If pnCol is not NULL, then *pnCol is -** set to the number of columns in the table affected by the change. If -** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change +** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three +** outputs are set through these pointers: +** +** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], +** depending on the type of change that the iterator currently points to; +** +** *pnCol is set to the number of columns in the table affected by the change; and +** +** *pzTab is set to point to a nul-terminated utf-8 encoded string containing +** the name of the table affected by the current change. The buffer remains +** valid until either sqlite3changeset_next() is called on the iterator +** or until the conflict-handler function returns. +** +** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change ** is an indirect change, or false (0) otherwise. See the documentation for ** [sqlite3session_indirect()] for a description of direct and indirect -** changes. Finally, if pOp is not NULL, then *pOp is set to one of -** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the -** type of change that the iterator currently points to. +** changes. ** ** If no error occurs, SQLITE_OK is returned. If an error does occur, an ** SQLite error code is returned. The values of the output variables may not @@ -9371,6 +11442,7 @@ SQLITE_API int sqlite3changeset_op( /* ** CAPI3REF: Obtain The Primary Key Definition Of A Table +** METHOD: sqlite3_changeset_iter ** ** For each modified table, a changeset includes the following: ** @@ -9402,11 +11474,12 @@ SQLITE_API int sqlite3changeset_pk( /* ** CAPI3REF: Obtain old.* Values From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent -** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. @@ -9416,9 +11489,9 @@ SQLITE_API int sqlite3changeset_pk( ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the vector of +** sqlite3_value object containing the iVal'th value from the vector of ** original row values stored as part of the UPDATE or DELETE change and -** returns SQLITE_OK. The name of the function comes from the fact that this +** returns SQLITE_OK. The name of the function comes from the fact that this ** is similar to the "old.*" columns available to update or delete triggers. ** ** If some other error occurs (e.g. an OOM condition), an SQLite error code @@ -9432,11 +11505,12 @@ SQLITE_API int sqlite3changeset_old( /* ** CAPI3REF: Obtain new.* Values From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent -** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. @@ -9446,12 +11520,12 @@ SQLITE_API int sqlite3changeset_old( ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the vector of +** sqlite3_value object containing the iVal'th value from the vector of ** new row values stored as part of the UPDATE or INSERT change and ** returns SQLITE_OK. If the change is an UPDATE and does not include -** a new value for the requested column, *ppValue is set to NULL and -** SQLITE_OK returned. The name of the function comes from the fact that -** this is similar to the "new.*" columns available to update or delete +** a new value for the requested column, *ppValue is set to NULL and +** SQLITE_OK returned. The name of the function comes from the fact that +** this is similar to the "new.*" columns available to update or delete ** triggers. ** ** If some other error occurs (e.g. an OOM condition), an SQLite error code @@ -9465,6 +11539,7 @@ SQLITE_API int sqlite3changeset_new( /* ** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** This function should only be used with iterator objects passed to a ** conflict-handler callback by [sqlite3changeset_apply()] with either @@ -9477,7 +11552,7 @@ SQLITE_API int sqlite3changeset_new( ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the +** sqlite3_value object containing the iVal'th value from the ** "conflicting row" associated with the current conflict-handler callback ** and returns SQLITE_OK. ** @@ -9492,6 +11567,7 @@ SQLITE_API int sqlite3changeset_conflict( /* ** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations +** METHOD: sqlite3_changeset_iter ** ** This function may only be called with an iterator passed to an ** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case @@ -9508,6 +11584,7 @@ SQLITE_API int sqlite3changeset_fk_conflicts( /* ** CAPI3REF: Finalize A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** This function is used to finalize an iterator allocated with ** [sqlite3changeset_start()]. @@ -9519,19 +11596,21 @@ SQLITE_API int sqlite3changeset_fk_conflicts( ** call has no effect. ** ** If an error was encountered within a call to an sqlite3changeset_xxx() -** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an +** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an ** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding ** to that error is returned by this function. Otherwise, SQLITE_OK is ** returned. This is to allow the following pattern (pseudo-code): ** +**
         **   sqlite3changeset_start();
         **   while( SQLITE_ROW==sqlite3changeset_next() ){
         **     // Do something with change.
         **   }
         **   rc = sqlite3changeset_finalize();
         **   if( rc!=SQLITE_OK ){
        -**     // An error has occurred 
        +**     // An error has occurred
         **   }
        +** 
        */ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); @@ -9557,7 +11636,7 @@ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); ** zeroed and an SQLite error code returned. ** ** It is the responsibility of the caller to eventually call sqlite3_free() -** on the *ppOut pointer to free the buffer allocation following a successful +** on the *ppOut pointer to free the buffer allocation following a successful ** call to this function. ** ** WARNING/TODO: This function currently assumes that the input is a valid @@ -9571,14 +11650,15 @@ SQLITE_API int sqlite3changeset_invert( /* ** CAPI3REF: Concatenate Two Changeset Objects ** -** This function is used to concatenate two changesets, A and B, into a +** This function is used to concatenate two changesets, A and B, into a ** single changeset. The result is a changeset equivalent to applying -** changeset A followed by changeset B. +** changeset A followed by changeset B. ** -** This function combines the two input changesets using an +** This function combines the two input changesets using an ** sqlite3_changegroup object. Calling it produces similar results as the ** following code fragment: ** +**
         **   sqlite3_changegroup *pGrp;
         **   rc = sqlite3_changegroup_new(&pGrp);
         **   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
        @@ -9589,6 +11669,7 @@ SQLITE_API int sqlite3changeset_invert(
         **     *ppOut = 0;
         **     *pnOut = 0;
         **   }
        +** 
        ** ** Refer to the sqlite3_changegroup documentation below for details. */ @@ -9604,11 +11685,15 @@ SQLITE_API int sqlite3changeset_concat( /* ** CAPI3REF: Changegroup Handle +** +** A changegroup is an object used to combine two or more +** [changesets] or [patchsets] */ typedef struct sqlite3_changegroup sqlite3_changegroup; /* ** CAPI3REF: Create A New Changegroup Object +** CONSTRUCTOR: sqlite3_changegroup ** ** An sqlite3_changegroup object is used to combine two or more changesets ** (or patchsets) into a single changeset (or patchset). A single changegroup @@ -9617,7 +11702,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; ** ** If successful, this function returns SQLITE_OK and populates (*pp) with ** a pointer to a new sqlite3_changegroup object before returning. The caller -** should eventually free the returned object using a call to +** should eventually free the returned object using a call to ** sqlite3changegroup_delete(). If an error occurs, an SQLite error code ** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. ** @@ -9629,7 +11714,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; **
      • Zero or more changesets (or patchsets) are added to the object ** by calling sqlite3changegroup_add(). ** -**
      • The result of combining all input changesets together is obtained +**
      • The result of combining all input changesets together is obtained ** by the application via a call to sqlite3changegroup_output(). ** **
      • The object is deleted using a call to sqlite3changegroup_delete(). @@ -9638,17 +11723,18 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; ** Any number of calls to add() and output() may be made between the calls to ** new() and delete(), and in any order. ** -** As well as the regular sqlite3changegroup_add() and +** As well as the regular sqlite3changegroup_add() and ** sqlite3changegroup_output() functions, also available are the streaming ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). */ -int sqlite3changegroup_new(sqlite3_changegroup **pp); +SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); /* ** CAPI3REF: Add A Changeset To A Changegroup +** METHOD: sqlite3_changegroup ** ** Add all changes within the changeset (or patchset) in buffer pData (size -** nData bytes) to the changegroup. +** nData bytes) to the changegroup. ** ** If the buffer contains a patchset, then all prior calls to this function ** on the same changegroup object must also have specified patchsets. Or, if @@ -9675,7 +11761,7 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp); ** changeset was recorded immediately after the changesets already ** added to the changegroup. ** INSERT UPDATE -** The INSERT change remains in the changegroup. The values in the +** The INSERT change remains in the changegroup. The values in the ** INSERT change are modified as if the row was inserted by the ** existing change and then updated according to the new change. ** INSERT DELETE @@ -9686,17 +11772,17 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp); ** changeset was recorded immediately after the changesets already ** added to the changegroup. ** UPDATE UPDATE -** The existing UPDATE remains within the changegroup. It is amended -** so that the accompanying values are as if the row was updated once +** The existing UPDATE remains within the changegroup. It is amended +** so that the accompanying values are as if the row was updated once ** by the existing change and then again by the new change. ** UPDATE DELETE ** The existing UPDATE is replaced by the new DELETE within the ** changegroup. ** DELETE INSERT ** If one or more of the column values in the row inserted by the -** new change differ from those in the row deleted by the existing +** new change differ from those in the row deleted by the existing ** change, the existing DELETE is replaced by an UPDATE within the -** changegroup. Otherwise, if the inserted row is exactly the same +** changegroup. Otherwise, if the inserted row is exactly the same ** as the deleted row, the existing DELETE is simply discarded. ** DELETE UPDATE ** The new change is ignored. This case does not occur if the new @@ -9714,15 +11800,16 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp); ** case, this function fails with SQLITE_SCHEMA. If the input changeset ** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is ** returned. Or, if an out-of-memory condition occurs during processing, this -** function returns SQLITE_NOMEM. In all cases, if an error occurs the -** final contents of the changegroup is undefined. +** function returns SQLITE_NOMEM. In all cases, if an error occurs the state +** of the final contents of the changegroup is undefined. ** ** If no error occurs, SQLITE_OK is returned. */ -int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); +SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup +** METHOD: sqlite3_changegroup ** ** Obtain a buffer containing a changeset (or patchset) representing the ** current contents of the changegroup. If the inputs to the changegroup @@ -9740,12 +11827,12 @@ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); ** ** If an error occurs, an SQLite error code is returned and the output ** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK -** is returned and the output variables are set to the size of and a +** is returned and the output variables are set to the size of and a ** pointer to the output buffer, respectively. In this case it is the ** responsibility of the caller to eventually free the buffer using a ** call to sqlite3_free(). */ -int sqlite3changegroup_output( +SQLITE_API int sqlite3changegroup_output( sqlite3_changegroup*, int *pnData, /* OUT: Size of output buffer in bytes */ void **ppData /* OUT: Pointer to output buffer */ @@ -9753,36 +11840,36 @@ int sqlite3changegroup_output( /* ** CAPI3REF: Delete A Changegroup Object +** DESTRUCTOR: sqlite3_changegroup */ -void sqlite3changegroup_delete(sqlite3_changegroup*); +SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); /* ** CAPI3REF: Apply A Changeset To A Database ** -** Apply a changeset to a database. This function attempts to update the -** "main" database attached to handle db with the changes found in the -** changeset passed via the second and third arguments. +** Apply a changeset or patchset to a database. These functions attempt to +** update the "main" database attached to handle db with the changes found in +** the changeset passed via the second and third arguments. ** -** The fourth argument (xFilter) passed to this function is the "filter +** The fourth argument (xFilter) passed to these functions is the "filter ** callback". If it is not NULL, then for each table affected by at least one ** change in the changeset, the filter callback is invoked with ** the table name as the second argument, and a copy of the context pointer -** passed as the sixth argument to this function as the first. If the "filter -** callback" returns zero, then no attempt is made to apply any changes to -** the table. Otherwise, if the return value is non-zero or the xFilter -** argument to this function is NULL, all changes related to the table are -** attempted. -** -** For each table that is not excluded by the filter callback, this function -** tests that the target database contains a compatible table. A table is +** passed as the sixth argument as the first. If the "filter callback" +** returns zero, then no attempt is made to apply any changes to the table. +** Otherwise, if the return value is non-zero or the xFilter argument to +** is NULL, all changes related to the table are attempted. +** +** For each table that is not excluded by the filter callback, this function +** tests that the target database contains a compatible table. A table is ** considered compatible if all of the following are true: ** **
          -**
        • The table has the same name as the name recorded in the +**
        • The table has the same name as the name recorded in the ** changeset, and -**
        • The table has at least as many columns as recorded in the +**
        • The table has at least as many columns as recorded in the ** changeset, and -**
        • The table has primary key columns in the same position as +**
        • The table has primary key columns in the same position as ** recorded in the changeset. **
        ** @@ -9791,11 +11878,11 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most ** one such warning is issued for each table in the changeset. ** -** For each change for which there is a compatible table, an attempt is made -** to modify the table contents according to the UPDATE, INSERT or DELETE -** change. If a change cannot be applied cleanly, the conflict handler -** function passed as the fifth argument to sqlite3changeset_apply() may be -** invoked. A description of exactly when the conflict handler is invoked for +** For each change for which there is a compatible table, an attempt is made +** to modify the table contents according to the UPDATE, INSERT or DELETE +** change. If a change cannot be applied cleanly, the conflict handler +** function passed as the fifth argument to sqlite3changeset_apply() may be +** invoked. A description of exactly when the conflict handler is invoked for ** each type of change is below. ** ** Unlike the xFilter argument, xConflict may not be passed NULL. The results @@ -9803,23 +11890,23 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** argument are undefined. ** ** Each time the conflict handler function is invoked, it must return one -** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or +** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or ** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned ** if the second argument passed to the conflict handler is either ** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler ** returns an illegal value, any changes already made are rolled back and -** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different +** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different ** actions are taken by sqlite3changeset_apply() depending on the value ** returned by each invocation of the conflict-handler function. Refer to -** the documentation for the three +** the documentation for the three ** [SQLITE_CHANGESET_OMIT|available return values] for details. ** **
        **
        DELETE Changes
        -** For each DELETE change, this function checks if the target database -** contains a row with the same primary key value (or values) as the -** original row values stored in the changeset. If it does, and the values -** stored in all non-primary key columns also match the values stored in +** For each DELETE change, the function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all non-primary key columns also match the values stored in ** the changeset the row is deleted from the target database. ** ** If a row with matching primary key values is found, but one or more of @@ -9848,22 +11935,22 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** database table, the trailing fields are populated with their default ** values. ** -** If the attempt to insert the row fails because the database already +** If the attempt to insert the row fails because the database already ** contains a row with the same primary key values, the conflict handler -** function is invoked with the second argument set to +** function is invoked with the second argument set to ** [SQLITE_CHANGESET_CONFLICT]. ** ** If the attempt to insert the row fails because of some other constraint -** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is +** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is ** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. -** This includes the case where the INSERT operation is re-attempted because -** an earlier call to the conflict handler function returned +** This includes the case where the INSERT operation is re-attempted because +** an earlier call to the conflict handler function returned ** [SQLITE_CHANGESET_REPLACE]. ** **
        UPDATE Changes
        -** For each UPDATE change, this function checks if the target database -** contains a row with the same primary key value (or values) as the -** original row values stored in the changeset. If it does, and the values +** For each UPDATE change, the function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values ** stored in all modified non-primary key columns also match the values ** stored in the changeset the row is updated within the target database. ** @@ -9879,24 +11966,41 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] ** passed as the second argument. ** -** If the UPDATE operation is attempted, but SQLite returns -** SQLITE_CONSTRAINT, the conflict-handler function is invoked with +** If the UPDATE operation is attempted, but SQLite returns +** SQLITE_CONSTRAINT, the conflict-handler function is invoked with ** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. -** This includes the case where the UPDATE operation is attempted after +** This includes the case where the UPDATE operation is attempted after ** an earlier call to the conflict handler function returned -** [SQLITE_CHANGESET_REPLACE]. +** [SQLITE_CHANGESET_REPLACE]. **
        ** ** It is safe to execute SQL statements, including those that write to the ** table that the callback related to, from within the xConflict callback. -** This can be used to further customize the applications conflict +** This can be used to further customize the application's conflict ** resolution strategy. ** -** All changes made by this function are enclosed in a savepoint transaction. +** All changes made by these functions are enclosed in a savepoint transaction. ** If any other error (aside from a constraint failure when attempting to ** write to the target database) occurs, then the savepoint transaction is -** rolled back, restoring the target database to its original state, and an +** rolled back, restoring the target database to its original state, and an ** SQLite error code returned. +** +** If the output parameters (ppRebase) and (pnRebase) are non-NULL and +** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() +** may set (*ppRebase) to point to a "rebase" that may be used with the +** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase) +** is set to the size of the buffer in bytes. It is the responsibility of the +** caller to eventually free any such buffer using sqlite3_free(). The buffer +** is only allocated and populated if one or more conflicts were encountered +** while applying the patchset. See comments surrounding the sqlite3_rebaser +** APIs for further details. +** +** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter. +** +** Note that the sqlite3changeset_apply_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_apply( sqlite3 *db, /* Apply change to "main" db of this handle */ @@ -9913,8 +12017,49 @@ SQLITE_API int sqlite3changeset_apply( ), void *pCtx /* First argument passed to xConflict */ ); +SQLITE_API int sqlite3changeset_apply_v2( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, /* OUT: Rebase data */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_apply_v2 +** +** The following flags may passed via the 9th parameter to +** [sqlite3changeset_apply_v2] and [sqlite3changeset_apply_v2_strm]: +** +**
        +**
        SQLITE_CHANGESETAPPLY_NOSAVEPOINT
        +** Usually, the sessions module encloses all operations performed by +** a single call to apply_v2() or apply_v2_strm() in a [SAVEPOINT]. The +** SAVEPOINT is committed if the changeset or patchset is successfully +** applied, or rolled back if an error occurs. Specifying this flag +** causes the sessions module to omit this savepoint. In this case, if the +** caller has an open transaction or savepoint when apply_v2() is called, +** it may revert the partially applied changeset by rolling it back. +** +**
        SQLITE_CHANGESETAPPLY_INVERT
        +** Invert the changeset before applying it. This is equivalent to inverting +** a changeset using sqlite3changeset_invert() before applying it. It is +** an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 -/* +/* ** CAPI3REF: Constants Passed To The Conflict Handler ** ** Values that may be passed as the second argument to a conflict-handler. @@ -9923,32 +12068,32 @@ SQLITE_API int sqlite3changeset_apply( **
        SQLITE_CHANGESET_DATA
        ** The conflict handler is invoked with CHANGESET_DATA as the second argument ** when processing a DELETE or UPDATE change if a row with the required -** PRIMARY KEY fields is present in the database, but one or more other -** (non primary-key) fields modified by the update do not contain the +** PRIMARY KEY fields is present in the database, but one or more other +** (non primary-key) fields modified by the update do not contain the ** expected "before" values. -** +** ** The conflicting row, in this case, is the database row with the matching ** primary key. -** +** **
        SQLITE_CHANGESET_NOTFOUND
        ** The conflict handler is invoked with CHANGESET_NOTFOUND as the second ** argument when processing a DELETE or UPDATE change if a row with the ** required PRIMARY KEY fields is not present in the database. -** +** ** There is no conflicting row in this case. The results of invoking the ** sqlite3changeset_conflict() API are undefined. -** +** **
        SQLITE_CHANGESET_CONFLICT
        ** CHANGESET_CONFLICT is passed as the second argument to the conflict -** handler while processing an INSERT change if the operation would result +** handler while processing an INSERT change if the operation would result ** in duplicate primary key values. -** +** ** The conflicting row in this case is the database row with the matching ** primary key. ** **
        SQLITE_CHANGESET_FOREIGN_KEY
        ** If foreign key handling is enabled, and applying a changeset leaves the -** database in a state containing foreign key violations, the conflict +** database in a state containing foreign key violations, the conflict ** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument ** exactly once before the changeset is committed. If the conflict handler ** returns CHANGESET_OMIT, the changes, including those that caused the @@ -9958,12 +12103,12 @@ SQLITE_API int sqlite3changeset_apply( ** No current or conflicting row information is provided. The only function ** it is possible to call on the supplied sqlite3_changeset_iter handle ** is sqlite3changeset_fk_conflicts(). -** +** **
        SQLITE_CHANGESET_CONSTRAINT
        -** If any other constraint violation occurs while applying a change (i.e. -** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is +** If any other constraint violation occurs while applying a change (i.e. +** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is ** invoked with CHANGESET_CONSTRAINT as the second argument. -** +** ** There is no conflicting row in this case. The results of invoking the ** sqlite3changeset_conflict() API are undefined. ** @@ -9975,7 +12120,7 @@ SQLITE_API int sqlite3changeset_apply( #define SQLITE_CHANGESET_CONSTRAINT 4 #define SQLITE_CHANGESET_FOREIGN_KEY 5 -/* +/* ** CAPI3REF: Constants Returned By The Conflict Handler ** ** A conflict handler callback must return one of the following three values. @@ -9983,13 +12128,13 @@ SQLITE_API int sqlite3changeset_apply( **
        **
        SQLITE_CHANGESET_OMIT
        ** If a conflict handler returns this value no special action is taken. The -** change that caused the conflict is not applied. The session module +** change that caused the conflict is not applied. The session module ** continues to the next change in the changeset. ** **
        SQLITE_CHANGESET_REPLACE
        ** This value may only be returned if the second argument to the conflict ** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this -** is not the case, any changes applied so far are rolled back and the +** is not the case, any changes applied so far are rolled back and the ** call to sqlite3changeset_apply() returns SQLITE_MISUSE. ** ** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict @@ -10002,7 +12147,7 @@ SQLITE_API int sqlite3changeset_apply( ** the original row is restored to the database before continuing. ** **
        SQLITE_CHANGESET_ABORT
        -** If this value is returned, any changes applied so far are rolled back +** If this value is returned, any changes applied so far are rolled back ** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. **
        */ @@ -10010,27 +12155,183 @@ SQLITE_API int sqlite3changeset_apply( #define SQLITE_CHANGESET_REPLACE 1 #define SQLITE_CHANGESET_ABORT 2 +/* +** CAPI3REF: Rebasing changesets +** EXPERIMENTAL +** +** Suppose there is a site hosting a database in state S0. And that +** modifications are made that move that database to state S1 and a +** changeset recorded (the "local" changeset). Then, a changeset based +** on S0 is received from another site (the "remote" changeset) and +** applied to the database. The database is then in state +** (S1+"remote"), where the exact state depends on any conflict +** resolution decisions (OMIT or REPLACE) made while applying "remote". +** Rebasing a changeset is to update it to take those conflict +** resolution decisions into account, so that the same conflicts +** do not have to be resolved elsewhere in the network. +** +** For example, if both the local and remote changesets contain an +** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)": +** +** local: INSERT INTO t1 VALUES(1, 'v1'); +** remote: INSERT INTO t1 VALUES(1, 'v2'); +** +** and the conflict resolution is REPLACE, then the INSERT change is +** removed from the local changeset (it was overridden). Or, if the +** conflict resolution was "OMIT", then the local changeset is modified +** to instead contain: +** +** UPDATE t1 SET b = 'v2' WHERE a=1; +** +** Changes within the local changeset are rebased as follows: +** +**
        +**
        Local INSERT
        +** This may only conflict with a remote INSERT. If the conflict +** resolution was OMIT, then add an UPDATE change to the rebased +** changeset. Or, if the conflict resolution was REPLACE, add +** nothing to the rebased changeset. +** +**
        Local DELETE
        +** This may conflict with a remote UPDATE or DELETE. In both cases the +** only possible resolution is OMIT. If the remote operation was a +** DELETE, then add no change to the rebased changeset. If the remote +** operation was an UPDATE, then the old.* fields of change are updated +** to reflect the new.* values in the UPDATE. +** +**
        Local UPDATE
        +** This may conflict with a remote UPDATE or DELETE. If it conflicts +** with a DELETE, and the conflict resolution was OMIT, then the update +** is changed into an INSERT. Any undefined values in the new.* record +** from the update change are filled in using the old.* values from +** the conflicting DELETE. Or, if the conflict resolution was REPLACE, +** the UPDATE change is simply omitted from the rebased changeset. +** +** If conflict is with a remote UPDATE and the resolution is OMIT, then +** the old.* values are rebased using the new.* values in the remote +** change. Or, if the resolution is REPLACE, then the change is copied +** into the rebased changeset with updates to columns also updated by +** the conflicting remote UPDATE removed. If this means no columns would +** be updated, the change is omitted. +**
        +** +** A local change may be rebased against multiple remote changes +** simultaneously. If a single key is modified by multiple remote +** changesets, they are combined as follows before the local changeset +** is rebased: +** +**
          +**
        • If there has been one or more REPLACE resolutions on a +** key, it is rebased according to a REPLACE. +** +**
        • If there have been no REPLACE resolutions on a key, then +** the local changeset is rebased according to the most recent +** of the OMIT resolutions. +**
        +** +** Note that conflict resolutions from multiple remote changesets are +** combined on a per-field basis, not per-row. This means that in the +** case of multiple remote UPDATE operations, some fields of a single +** local change may be rebased for REPLACE while others are rebased for +** OMIT. +** +** In order to rebase a local changeset, the remote changeset must first +** be applied to the local database using sqlite3changeset_apply_v2() and +** the buffer of rebase information captured. Then: +** +**
          +**
        1. An sqlite3_rebaser object is created by calling +** sqlite3rebaser_create(). +**
        2. The new object is configured with the rebase buffer obtained from +** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure(). +** If the local changeset is to be rebased against multiple remote +** changesets, then sqlite3rebaser_configure() should be called +** multiple times, in the same order that the multiple +** sqlite3changeset_apply_v2() calls were made. +**
        3. Each local changeset is rebased by calling sqlite3rebaser_rebase(). +**
        4. The sqlite3_rebaser object is deleted by calling +** sqlite3rebaser_delete(). +**
        +*/ +typedef struct sqlite3_rebaser sqlite3_rebaser; + +/* +** CAPI3REF: Create a changeset rebaser object. +** EXPERIMENTAL +** +** Allocate a new changeset rebaser object. If successful, set (*ppNew) to +** point to the new object and return SQLITE_OK. Otherwise, if an error +** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew) +** to NULL. +*/ +SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew); + +/* +** CAPI3REF: Configure a changeset rebaser object. +** EXPERIMENTAL +** +** Configure the changeset rebaser object to rebase changesets according +** to the conflict resolutions described by buffer pRebase (size nRebase +** bytes), which must have been obtained from a previous call to +** sqlite3changeset_apply_v2(). +*/ +SQLITE_API int sqlite3rebaser_configure( + sqlite3_rebaser*, + int nRebase, const void *pRebase +); + +/* +** CAPI3REF: Rebase a changeset +** EXPERIMENTAL +** +** Argument pIn must point to a buffer containing a changeset nIn bytes +** in size. This function allocates and populates a buffer with a copy +** of the changeset rebased according to the configuration of the +** rebaser object passed as the first argument. If successful, (*ppOut) +** is set to point to the new buffer containing the rebased changeset and +** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the +** responsibility of the caller to eventually free the new buffer using +** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) +** are set to zero and an SQLite error code returned. +*/ +SQLITE_API int sqlite3rebaser_rebase( + sqlite3_rebaser*, + int nIn, const void *pIn, + int *pnOut, void **ppOut +); + +/* +** CAPI3REF: Delete a changeset rebaser object. +** EXPERIMENTAL +** +** Delete the changeset rebaser object and all associated resources. There +** should be one call to this function for each successful invocation +** of sqlite3rebaser_create(). +*/ +SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p); + /* ** CAPI3REF: Streaming Versions of API functions. ** -** The six streaming API xxx_strm() functions serve similar purposes to the +** The six streaming API xxx_strm() functions serve similar purposes to the ** corresponding non-streaming API functions: ** ** ** -**
        Streaming functionNon-streaming equivalent
        sqlite3changeset_apply_str[sqlite3changeset_apply] -**
        sqlite3changeset_concat_str[sqlite3changeset_concat] -**
        sqlite3changeset_invert_str[sqlite3changeset_invert] -**
        sqlite3changeset_start_str[sqlite3changeset_start] -**
        sqlite3session_changeset_str[sqlite3session_changeset] -**
        sqlite3session_patchset_str[sqlite3session_patchset] +**
        sqlite3changeset_apply_strm[sqlite3changeset_apply] +**
        sqlite3changeset_apply_strm_v2[sqlite3changeset_apply_v2] +**
        sqlite3changeset_concat_strm[sqlite3changeset_concat] +**
        sqlite3changeset_invert_strm[sqlite3changeset_invert] +**
        sqlite3changeset_start_strm[sqlite3changeset_start] +**
        sqlite3session_changeset_strm[sqlite3session_changeset] +**
        sqlite3session_patchset_strm[sqlite3session_patchset] **
        ** ** Non-streaming functions that accept changesets (or patchsets) as input -** require that the entire changeset be stored in a single buffer in memory. -** Similarly, those that return a changeset or patchset do so by returning -** a pointer to a single large buffer allocated using sqlite3_malloc(). -** Normally this is convenient. However, if an application running in a +** require that the entire changeset be stored in a single buffer in memory. +** Similarly, those that return a changeset or patchset do so by returning +** a pointer to a single large buffer allocated using sqlite3_malloc(). +** Normally this is convenient. However, if an application running in a ** low-memory environment is required to handle very large changesets, the ** large contiguous memory allocations required can become onerous. ** @@ -10052,12 +12353,12 @@ SQLITE_API int sqlite3changeset_apply( ** ** ** Each time the xInput callback is invoked by the sessions module, the first -** argument passed is a copy of the supplied pIn context pointer. The second -** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no -** error occurs the xInput method should copy up to (*pnData) bytes of data -** into the buffer and set (*pnData) to the actual number of bytes copied -** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) -** should be set to zero to indicate this. Or, if an error occurs, an SQLite +** argument passed is a copy of the supplied pIn context pointer. The second +** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no +** error occurs the xInput method should copy up to (*pnData) bytes of data +** into the buffer and set (*pnData) to the actual number of bytes copied +** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) +** should be set to zero to indicate this. Or, if an error occurs, an SQLite ** error code should be returned. In all cases, if an xInput callback returns ** an error, all processing is abandoned and the streaming API function ** returns a copy of the error code to the caller. @@ -10065,7 +12366,7 @@ SQLITE_API int sqlite3changeset_apply( ** In the case of sqlite3changeset_start_strm(), the xInput callback may be ** invoked by the sessions module at any point during the lifetime of the ** iterator. If such an xInput callback returns an error, the iterator enters -** an error state, whereby all subsequent calls to iterator functions +** an error state, whereby all subsequent calls to iterator functions ** immediately fail with the same error code as returned by xInput. ** ** Similarly, streaming API functions that return changesets (or patchsets) @@ -10095,7 +12396,7 @@ SQLITE_API int sqlite3changeset_apply( ** is immediately abandoned and the streaming API function returns a copy ** of the xOutput error code to the application. ** -** The sessions module never invokes an xOutput callback with the third +** The sessions module never invokes an xOutput callback with the third ** parameter set to a value less than or equal to zero. Other than this, ** no guarantees are made as to the size of the chunks of data returned. */ @@ -10114,6 +12415,23 @@ SQLITE_API int sqlite3changeset_apply_strm( ), void *pCtx /* First argument passed to xConflict */ ); +SQLITE_API int sqlite3changeset_apply_v2_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +); SQLITE_API int sqlite3changeset_concat_strm( int (*xInputA)(void *pIn, void *pData, int *pnData), void *pInA, @@ -10133,6 +12451,12 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); SQLITE_API int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), @@ -10143,15 +12467,61 @@ SQLITE_API int sqlite3session_patchset_strm( int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); -int sqlite3changegroup_add_strm(sqlite3_changegroup*, +SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); -int sqlite3changegroup_output_strm(sqlite3_changegroup*, - int (*xOutput)(void *pOut, const void *pData, int nData), +SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, + int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); +SQLITE_API int sqlite3rebaser_rebase_strm( + sqlite3_rebaser *pRebaser, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); +/* +** CAPI3REF: Configure global parameters +** +** The sqlite3session_config() interface is used to make global configuration +** changes to the sessions module in order to tune it to the specific needs +** of the application. +** +** The sqlite3session_config() interface is not threadsafe. If it is invoked +** while any other thread is inside any other sessions method then the +** results are undefined. Furthermore, if it is invoked after any sessions +** related objects have been created, the results are also undefined. +** +** The first argument to the sqlite3session_config() function must be one +** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The +** interpretation of the (void*) value passed as the second parameter and +** the effect of calling this function depends on the value of the first +** parameter. +** +**
        +**
        SQLITE_SESSION_CONFIG_STRMSIZE
        +** By default, the sessions module streaming interfaces attempt to input +** and output data in approximately 1 KiB chunks. This operand may be used +** to set and query the value of this configuration setting. The pointer +** passed as the second argument must point to a value of type (int). +** If this value is greater than 0, it is used as the new streaming data +** chunk size for both input and output. Before returning, the (int) value +** pointed to by pArg is set to the final value of the streaming interface +** chunk size. +**
        +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg); + +/* +** CAPI3REF: Values for sqlite3session_config(). +*/ +#define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. @@ -10176,7 +12546,7 @@ int sqlite3changegroup_output_strm(sqlite3_changegroup*, ** ****************************************************************************** ** -** Interfaces to extend FTS5. Using the interfaces defined in this file, +** Interfaces to extend FTS5. Using the interfaces defined in this file, ** FTS5 may be extended with: ** ** * custom tokenizers, and @@ -10220,19 +12590,19 @@ struct Fts5PhraseIter { ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the context pointer the extension function was +** Return a copy of the context pointer the extension function was ** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the FTS5 table. Or, if iCol is ** non-negative but less than the number of columns in the table, return -** the total number of tokens in column iCol, considering all rows in +** the total number of tokens in column iCol, considering all rows in ** the FTS5 table. ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is +** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** xColumnCount(pFts): @@ -10246,7 +12616,7 @@ struct Fts5PhraseIter { ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is +** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** This function may be quite inefficient if used with an FTS5 table @@ -10273,8 +12643,8 @@ struct Fts5PhraseIter { ** an error code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always returns 0. ** ** xInst: @@ -10285,15 +12655,11 @@ struct Fts5PhraseIter { ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. The exception is if the table was created -** with the offsets=0 option specified. In this case *piOff is always -** set to -1. -** -** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) -** if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. +** "detail=none" or "detail=column" option. ** ** xRowid: ** Returns the rowid of the current row. @@ -10309,11 +12675,11 @@ struct Fts5PhraseIter { ** ** with $p set to a phrase equivalent to the phrase iPhrase of the ** current query is executed. Any column filter that applies to -** phrase iPhrase of the current query is included in $p. For each -** row visited, the callback function passed as the fourth argument -** is invoked. The context and API objects passed to the callback +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. -** Invoking Api.xUserData() returns a copy of the pointer passed as +** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the @@ -10328,14 +12694,14 @@ struct Fts5PhraseIter { ** ** xSetAuxdata(pFts5, pAux, xDelete) ** -** Save the pointer passed as the second argument as the extension functions +** Save the pointer passed as the second argument as the extension function's ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for -** each FTS query (MATCH expression). If the extension function is invoked -** more than once for a single FTS query, then all invocations share a +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a ** single auxiliary data context. ** ** If there is already an auxiliary data pointer when this function is @@ -10346,7 +12712,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -10354,7 +12720,7 @@ struct Fts5PhraseIter { ** ** xGetAuxdata(pFts5, bClear) ** -** Returns the current auxiliary data pointer for the fts5 extension +** Returns the current auxiliary data pointer for the fts5 extension ** function. See the xSetAuxdata() method for details. ** ** If the bClear argument is non-zero, then the auxiliary data is cleared @@ -10374,7 +12740,7 @@ struct Fts5PhraseIter { ** method, to iterate through all instances of a single query phrase within ** the current row. This is the same information as is accessible via the ** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient -** to use, this API may be faster under some circumstances. To iterate +** to use, this API may be faster under some circumstances. To iterate ** through instances of phrase iPhrase, use the following code: ** ** Fts5PhraseIter iter; @@ -10392,8 +12758,8 @@ struct Fts5PhraseIter { ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** @@ -10417,16 +12783,16 @@ struct Fts5PhraseIter { ** } ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" option. If the FTS5 table is created with either -** "detail=none" "content=" option (i.e. if it is a contentless table), -** then this API always iterates through an empty set (all calls to +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to ** xPhraseFirstColumn() set iCol to -1). ** ** The information accessed using this API and its companion ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext ** (or xInst/xInstCount). The chief advantage of this API is that it is ** significantly more efficient than those alternatives when used with -** "detail=column" tables. +** "detail=column" tables. ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. @@ -10440,7 +12806,7 @@ struct Fts5ExtensionApi { int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); - int (*xTokenize)(Fts5Context*, + int (*xTokenize)(Fts5Context*, const char *pText, int nText, /* Text to tokenize */ void *pCtx, /* Context passed to xToken() */ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ @@ -10469,15 +12835,15 @@ struct Fts5ExtensionApi { void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; -/* +/* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ /************************************************************************* ** CUSTOM TOKENIZERS ** -** Applications may also register custom tokenizer types. A tokenizer -** is registered by providing fts5 with a populated instance of the +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: @@ -10488,16 +12854,16 @@ struct Fts5ExtensionApi { ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object -** was registered with FTS5 (the third argument to xCreateTokenizer()). +** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used ** to create the FTS5 table. ** -** The final argument is an output variable. If successful, (*ppOut) +** The final argument is an output variable. If successful, (*ppOut) ** should be set to point to the new tokenizer handle and SQLITE_OK ** returned. If an error occurs, some value other than SQLITE_OK should -** be returned. In this case, fts5 assumes that the final value of *ppOut +** be returned. In this case, fts5 assumes that the final value of *ppOut ** is undefined. ** ** xDelete: @@ -10506,7 +12872,7 @@ struct Fts5ExtensionApi { ** be invoked exactly once for each successful call to xCreate(). ** ** xTokenize: -** This function is expected to tokenize the nText byte string indicated +** This function is expected to tokenize the nText byte string indicated ** by argument pText. pText may or may not be nul-terminated. The first ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). @@ -10520,8 +12886,8 @@ struct Fts5ExtensionApi { ** determine the set of tokens to add to (or delete from) the ** FTS index. ** -**
      • FTS5_TOKENIZE_QUERY - A MATCH query is being executed -** against the FTS index. The tokenizer is being called to tokenize +**
      • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize ** a bareword or quoted string specified as part of the query. ** **
      • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as @@ -10529,10 +12895,10 @@ struct Fts5ExtensionApi { ** followed by a "*" character, indicating that the last token ** returned by the tokenizer will be treated as a token prefix. ** -**
      • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +**
      • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to ** satisfy an fts5_api.xTokenize() request made by an auxiliary ** function. Or an fts5_api.xColumnSize() request made by the same -** on a columnsize=0 database. +** on a columnsize=0 database. **
      ** ** For each token in the input string, the supplied callback xToken() must @@ -10544,10 +12910,10 @@ struct Fts5ExtensionApi { ** which the token is derived within the input. ** ** The second argument passed to the xToken() callback ("tflags") should -** normally be set to 0. The exception is if the tokenizer supports +** normally be set to 0. The exception is if the tokenizer supports ** synonyms. In this case see the discussion below for details. ** -** FTS5 assumes the xToken() callback is invoked for each token in the +** FTS5 assumes the xToken() callback is invoked for each token in the ** order that they occur within the input text. ** ** If an xToken() callback returns any value other than SQLITE_OK, then @@ -10561,7 +12927,7 @@ struct Fts5ExtensionApi { ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a -** user wishes to query for a phrase such as "first place". Using the +** user wishes to query for a phrase such as "first place". Using the ** built-in tokenizers, the FTS5 query 'first + place' will match instances ** of "first place" within the document set, but not alternative forms ** such as "1st place". In some applications, it would be better to match @@ -10570,8 +12936,8 @@ struct Fts5ExtensionApi { ** ** There are several ways to approach this in FTS5: ** -**
      1. By mapping all synonyms to a single token. In this case, the -** In the above example, this means that the tokenizer returns the +**
        1. By mapping all synonyms to a single token. In this case, using +** the above example, this means that the tokenizer returns the ** same token for inputs "first" and "1st". Say that token is in ** fact "first", so that when the user inserts the document "I won ** 1st place" entries are added to the index for tokens "i", "won", @@ -10579,37 +12945,37 @@ struct Fts5ExtensionApi { ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** -**
        2. By adding multiple synonyms for a single term to the FTS index. -** In this case, when tokenizing query text, the tokenizer may -** provide multiple synonyms for a single term within the document. -** FTS5 then queries the index for each synonym individually. For -** example, faced with the query: +**
        3. By querying the index for all synonyms of each query term +** separately. In this case, when tokenizing query text, the +** tokenizer may provide multiple synonyms for a single term +** within the document. FTS5 then queries the index for each +** synonym individually. For example, faced with the query: ** ** ** ... MATCH 'first place' ** ** the tokenizer offers both "1st" and "first" as synonyms for the -** first token in the MATCH query and FTS5 effectively runs a query +** first token in the MATCH query and FTS5 effectively runs a query ** similar to: ** ** ** ... MATCH '(first OR 1st) place' ** ** except that, for the purposes of auxiliary functions, the query -** still appears to contain just two phrases - "(first OR 1st)" +** still appears to contain just two phrases - "(first OR 1st)" ** being treated as a single phrase. ** **
        4. By adding multiple synonyms for a single term to the FTS index. ** Using this method, when tokenizing document text, the tokenizer -** provides multiple synonyms for each token. So that when a +** provides multiple synonyms for each token. So that when a ** document such as "I won first place" is tokenized, entries are ** added to the FTS index for "i", "won", "first", "1st" and ** "place". ** ** This way, even if the tokenizer does not provide synonyms -** when tokenizing query text (it should not - to do would be -** inefficient), it doesn't matter if the user queries for -** 'first + place' or '1st + place', as there are entires in the +** when tokenizing query text (it should not - to do so would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. **
        ** @@ -10629,15 +12995,15 @@ struct Fts5ExtensionApi { ** ** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time ** xToken() is called. Multiple synonyms may be specified for a single token -** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. ** There is no limit to the number of synonyms that may be provided for a ** single token. ** -** In many cases, method (1) above is the best approach. It does not add +** In many cases, method (1) above is the best approach. It does not add ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the -** token "first" is subsituted for "1st" by the tokenizer, then the query: +** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** ** ... MATCH '1s*' @@ -10645,18 +13011,18 @@ struct Fts5ExtensionApi { ** will not match documents that contain the token "1st" (as the tokenizer ** will probably not map "1s" to any prefix of "first"). ** -** For full prefix support, method (3) may be preferred. In this case, +** For full prefix support, method (3) may be preferred. In this case, ** because the index contains entries for both "first" and "1st", prefix ** queries such as 'fi*' or '1s*' will match correctly. However, because ** extra entries are added to the FTS index, this method uses more space ** within the database. ** ** Method (2) offers a midpoint between (1) and (3). Using this method, -** a query such as '1s*' will match documents that contain the literal +** a query such as '1s*' will match documents that contain the literal ** token "1st", but not "first" (assuming the tokenizer is not able to ** provide synonyms for prefixes). However, a non-prefix query like '1st' ** will match against "1st" and "first". This method does not require -** extra disk space, as no extra entries are added to the FTS index. +** extra disk space, as no extra entries are added to the FTS index. ** On the other hand, it may require more CPU cycles to run MATCH queries, ** as separate queries of the FTS index are required for each synonym. ** @@ -10670,10 +13036,10 @@ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, + int (*xTokenize)(Fts5Tokenizer*, void *pCtx, int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, + const char *pText, int nText, int (*xToken)( void *pCtx, /* Copy of 2nd argument to xTokenize() */ int tflags, /* Mask of FTS5_TOKEN_* flags */ @@ -10752,8 +13118,9 @@ struct fts5_api { ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ -#ifdef _HAVE_SQLITE_CONFIG_H +#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) #include "config.h" +#define SQLITECONFIG_H 1 #endif /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ @@ -10769,7 +13136,7 @@ struct fts5_api { ** May you share freely, never taking more than you give. ** ************************************************************************* -** +** ** This file defines various limits of what SQLite can process. */ @@ -10817,14 +13184,10 @@ struct fts5_api { #endif /* -** The maximum depth of an expression tree. This is limited to -** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might -** want to place more severe limits on the complexity of an -** expression. -** -** A value of 0 used to mean that the limit was not enforced. -** But that is no longer true. The limit is now strictly enforced -** at all times. +** The maximum depth of an expression tree. This is limited to +** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might +** want to place more severe limits on the complexity of an +** expression. A value of 0 means that there is no limit. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 @@ -10847,7 +13210,7 @@ struct fts5_api { ** Not currently enforced. */ #ifndef SQLITE_MAX_VDBE_OP -# define SQLITE_MAX_VDBE_OP 25000 +# define SQLITE_MAX_VDBE_OP 250000000 #endif /* @@ -10891,9 +13254,12 @@ struct fts5_api { /* ** The maximum value of a ?nnn wildcard that the parser will accept. +** If the value exceeds 32767 then extra space is required for the Expr +** structure. But otherwise, we believe that the number can be as large +** as a signed 32-bit integer can hold. */ #ifndef SQLITE_MAX_VARIABLE_NUMBER -# define SQLITE_MAX_VARIABLE_NUMBER 999 +# define SQLITE_MAX_VARIABLE_NUMBER 32766 #endif /* Maximum page size. The upper bound on this value is 65536. This a limit @@ -10901,10 +13267,10 @@ struct fts5_api { ** ** Earlier versions of SQLite allowed the user to change this value at ** compile time. This is no longer permitted, on the grounds that it creates -** a library that is technically incompatible with an SQLite library -** compiled with a different limit. If a process operating on a database -** with a page-size of 65536 bytes crashes, then an instance of SQLite -** compiled with the default page-size limit will not be able to rollback +** a library that is technically incompatible with an SQLite library +** compiled with a different limit. If a process operating on a database +** with a page-size of 65536 bytes crashes, then an instance of SQLite +** compiled with the default page-size limit will not be able to rollback ** the aborted transaction. This could lead to database corruption. */ #ifdef SQLITE_MAX_PAGE_SIZE @@ -10963,7 +13329,7 @@ struct fts5_api { ** Maximum depth of recursion for triggers. ** ** A value of 1 means that a trigger program will not be able to itself -** fire any triggers. A value of 0 means that no trigger programs at all +** fire any triggers. A value of 0 means that no trigger programs at all ** may be executed. */ #ifndef SQLITE_MAX_TRIGGER_DEPTH @@ -10982,6 +13348,23 @@ struct fts5_api { #pragma warn -spa /* Suspicious pointer arithmetic */ #endif +/* +** WAL mode depends on atomic aligned 32-bit loads and stores in a few +** places. The following macros try to make this explicit. +*/ +#ifndef __has_extension +# define __has_extension(x) 0 /* compatibility with non-clang compilers */ +#endif +#if GCC_VERSION>=4007000 || __has_extension(c_atomic) +# define SQLITE_ATOMIC_INTRINSICS 1 +# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) +# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) +#else +# define SQLITE_ATOMIC_INTRINSICS 0 +# define AtomicLoad(PTR) (*(PTR)) +# define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) +#endif + /* ** Include standard header files as necessary */ @@ -11008,15 +13391,15 @@ struct fts5_api { ** So we have to define the macros in different ways depending on the ** compiler. */ -#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ +#if defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */ +# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X)) +# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X)) +#elif defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ # define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) #elif !defined(__GNUC__) /* Works for compilers other than LLVM */ # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X]) # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) -#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */ -# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X)) -# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X)) #else /* Generates a warning - but it always works */ # define SQLITE_INT_TO_PTR(X) ((void*)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(X)) @@ -11063,6 +13446,11 @@ struct fts5_api { ** ** Older versions of SQLite used an optional THREADSAFE macro. ** We support that for legacy. +** +** To ensure that the correct value of "THREADSAFE" is reported when querying +** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this +** logic is partially replicated in ctime.c. If it is updated here, it should +** also be updated there. */ #if !defined(SQLITE_THREADSAFE) # if defined(THREADSAFE) @@ -11177,11 +13565,12 @@ struct fts5_api { ** is significant and used at least once. On switch statements ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. -** */ -#ifdef SQLITE_COVERAGE_TEST -SQLITE_PRIVATE void sqlite3Coverage(int); -# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); } +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) +# ifndef SQLITE_AMALGAMATION + extern unsigned int sqlite3CoverageCounter; +# endif +# define testcase(X) if( X ){ sqlite3CoverageCounter += (unsigned)__LINE__; } #else # define testcase(X) #endif @@ -11211,6 +13600,14 @@ SQLITE_PRIVATE void sqlite3Coverage(int); # define VVA_ONLY(X) #endif +/* +** Disable ALWAYS() and NEVER() (make them pass-throughs) for coverage +** and mutation testing +*/ +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif + /* ** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such @@ -11226,7 +13623,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int); ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ -#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) @@ -11237,6 +13634,21 @@ SQLITE_PRIVATE void sqlite3Coverage(int); # define NEVER(X) (X) #endif +/* +** Some conditionals are optimizations only. In other words, if the +** conditionals are replaced with a constant 1 (true) or 0 (false) then +** the correct answer is still obtained, though perhaps not as quickly. +** +** The following macros mark these optimizations conditionals. +*/ +#if defined(SQLITE_MUTATION_TEST) +# define OK_IF_ALWAYS_TRUE(X) (1) +# define OK_IF_ALWAYS_FALSE(X) (0) +#else +# define OK_IF_ALWAYS_TRUE(X) (X) +# define OK_IF_ALWAYS_FALSE(X) (X) +#endif + /* ** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is ** defined. We need to defend against those failures when testing with @@ -11285,6 +13697,13 @@ SQLITE_PRIVATE void sqlite3Coverage(int); # undef SQLITE_ENABLE_EXPLAIN_COMMENTS #endif +/* +** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE +*/ +#if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE) +# define SQLITE_OMIT_ALTERTABLE +#endif + /* ** Return true (non-zero) if the input is an integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() @@ -11341,7 +13760,7 @@ typedef struct HashElem HashElem; ** element pointed to plus the next _ht.count-1 elements in the list. ** ** Hash.htsize and Hash.ht may be zero. In that case lookup is done -** by a linear search of the global list. For small tables, the +** by a linear search of the global list. For small tables, the ** Hash.ht table is never allocated because if there are few elements ** in the table, it is faster to do a linear search than to manage ** the hash table. @@ -11351,12 +13770,12 @@ struct Hash { unsigned int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ - int count; /* Number of entries with this hash */ + unsigned int count; /* Number of entries with this hash */ HashElem *chain; /* Pointer to first entry with this hash */ } *ht; }; -/* Each element in the hash table is an instance of the following +/* Each element in the hash table is an instance of the following ** structure. All elements are stored on a single doubly-linked list. ** ** Again, this structure is intended to be opaque, but it can't really @@ -11397,7 +13816,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); /* ** Number of entries in a hash table */ -/* #define sqliteHashCount(H) ((H)->count) // NOT USED */ +#define sqliteHashCount(H) ((H)->count) #endif /* SQLITE_HASH_H */ @@ -11429,152 +13848,166 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_LP 22 #define TK_RP 23 #define TK_AS 24 -#define TK_WITHOUT 25 -#define TK_COMMA 26 -#define TK_OR 27 -#define TK_AND 28 -#define TK_IS 29 -#define TK_MATCH 30 -#define TK_LIKE_KW 31 -#define TK_BETWEEN 32 -#define TK_IN 33 -#define TK_ISNULL 34 -#define TK_NOTNULL 35 -#define TK_NE 36 -#define TK_EQ 37 -#define TK_GT 38 -#define TK_LE 39 -#define TK_LT 40 -#define TK_GE 41 -#define TK_ESCAPE 42 -#define TK_BITAND 43 -#define TK_BITOR 44 -#define TK_LSHIFT 45 -#define TK_RSHIFT 46 -#define TK_PLUS 47 -#define TK_MINUS 48 -#define TK_STAR 49 -#define TK_SLASH 50 -#define TK_REM 51 -#define TK_CONCAT 52 -#define TK_COLLATE 53 -#define TK_BITNOT 54 -#define TK_ID 55 -#define TK_INDEXED 56 -#define TK_ABORT 57 -#define TK_ACTION 58 -#define TK_AFTER 59 -#define TK_ANALYZE 60 -#define TK_ASC 61 -#define TK_ATTACH 62 -#define TK_BEFORE 63 -#define TK_BY 64 -#define TK_CASCADE 65 -#define TK_CAST 66 -#define TK_COLUMNKW 67 -#define TK_CONFLICT 68 -#define TK_DATABASE 69 -#define TK_DESC 70 -#define TK_DETACH 71 -#define TK_EACH 72 -#define TK_FAIL 73 -#define TK_FOR 74 -#define TK_IGNORE 75 -#define TK_INITIALLY 76 -#define TK_INSTEAD 77 -#define TK_NO 78 -#define TK_KEY 79 -#define TK_OF 80 -#define TK_OFFSET 81 -#define TK_PRAGMA 82 -#define TK_RAISE 83 -#define TK_RECURSIVE 84 -#define TK_REPLACE 85 -#define TK_RESTRICT 86 -#define TK_ROW 87 -#define TK_TRIGGER 88 -#define TK_VACUUM 89 -#define TK_VIEW 90 -#define TK_VIRTUAL 91 -#define TK_WITH 92 -#define TK_REINDEX 93 -#define TK_RENAME 94 -#define TK_CTIME_KW 95 -#define TK_ANY 96 -#define TK_STRING 97 -#define TK_JOIN_KW 98 -#define TK_CONSTRAINT 99 -#define TK_DEFAULT 100 -#define TK_NULL 101 -#define TK_PRIMARY 102 -#define TK_UNIQUE 103 -#define TK_CHECK 104 -#define TK_REFERENCES 105 -#define TK_AUTOINCR 106 -#define TK_ON 107 -#define TK_INSERT 108 -#define TK_DELETE 109 -#define TK_UPDATE 110 -#define TK_SET 111 -#define TK_DEFERRABLE 112 -#define TK_FOREIGN 113 -#define TK_DROP 114 -#define TK_UNION 115 -#define TK_ALL 116 -#define TK_EXCEPT 117 -#define TK_INTERSECT 118 -#define TK_SELECT 119 -#define TK_VALUES 120 -#define TK_DISTINCT 121 -#define TK_DOT 122 -#define TK_FROM 123 -#define TK_JOIN 124 -#define TK_USING 125 -#define TK_ORDER 126 -#define TK_GROUP 127 -#define TK_HAVING 128 -#define TK_LIMIT 129 -#define TK_WHERE 130 -#define TK_INTO 131 -#define TK_FLOAT 132 -#define TK_BLOB 133 -#define TK_INTEGER 134 -#define TK_VARIABLE 135 -#define TK_CASE 136 -#define TK_WHEN 137 -#define TK_THEN 138 -#define TK_ELSE 139 -#define TK_INDEX 140 -#define TK_ALTER 141 -#define TK_ADD 142 -#define TK_TO_TEXT 143 -#define TK_TO_BLOB 144 -#define TK_TO_NUMERIC 145 -#define TK_TO_INT 146 -#define TK_TO_REAL 147 -#define TK_ISNOT 148 -#define TK_END_OF_FILE 149 -#define TK_UNCLOSED_STRING 150 -#define TK_FUNCTION 151 -#define TK_COLUMN 152 -#define TK_AGG_FUNCTION 153 -#define TK_AGG_COLUMN 154 -#define TK_UMINUS 155 -#define TK_UPLUS 156 -#define TK_REGISTER 157 -#define TK_VECTOR 158 -#define TK_SELECT_COLUMN 159 -#define TK_ASTERISK 160 -#define TK_SPAN 161 -#define TK_SPACE 162 -#define TK_ILLEGAL 163 - -/* The token codes above must all fit in 8 bits */ -#define TKFLG_MASK 0xff - -/* Flags that can be added to a token code when it is not -** being stored in a u8: */ -#define TKFLG_DONTFOLD 0x100 /* Omit constant folding optimizations */ +#define TK_COMMA 25 +#define TK_WITHOUT 26 +#define TK_ABORT 27 +#define TK_ACTION 28 +#define TK_AFTER 29 +#define TK_ANALYZE 30 +#define TK_ASC 31 +#define TK_ATTACH 32 +#define TK_BEFORE 33 +#define TK_BY 34 +#define TK_CASCADE 35 +#define TK_CAST 36 +#define TK_CONFLICT 37 +#define TK_DATABASE 38 +#define TK_DESC 39 +#define TK_DETACH 40 +#define TK_EACH 41 +#define TK_FAIL 42 +#define TK_OR 43 +#define TK_AND 44 +#define TK_IS 45 +#define TK_MATCH 46 +#define TK_LIKE_KW 47 +#define TK_BETWEEN 48 +#define TK_IN 49 +#define TK_ISNULL 50 +#define TK_NOTNULL 51 +#define TK_NE 52 +#define TK_EQ 53 +#define TK_GT 54 +#define TK_LE 55 +#define TK_LT 56 +#define TK_GE 57 +#define TK_ESCAPE 58 +#define TK_ID 59 +#define TK_COLUMNKW 60 +#define TK_DO 61 +#define TK_FOR 62 +#define TK_IGNORE 63 +#define TK_INITIALLY 64 +#define TK_INSTEAD 65 +#define TK_NO 66 +#define TK_KEY 67 +#define TK_OF 68 +#define TK_OFFSET 69 +#define TK_PRAGMA 70 +#define TK_RAISE 71 +#define TK_RECURSIVE 72 +#define TK_REPLACE 73 +#define TK_RESTRICT 74 +#define TK_ROW 75 +#define TK_ROWS 76 +#define TK_TRIGGER 77 +#define TK_VACUUM 78 +#define TK_VIEW 79 +#define TK_VIRTUAL 80 +#define TK_WITH 81 +#define TK_NULLS 82 +#define TK_FIRST 83 +#define TK_LAST 84 +#define TK_CURRENT 85 +#define TK_FOLLOWING 86 +#define TK_PARTITION 87 +#define TK_PRECEDING 88 +#define TK_RANGE 89 +#define TK_UNBOUNDED 90 +#define TK_EXCLUDE 91 +#define TK_GROUPS 92 +#define TK_OTHERS 93 +#define TK_TIES 94 +#define TK_GENERATED 95 +#define TK_ALWAYS 96 +#define TK_MATERIALIZED 97 +#define TK_REINDEX 98 +#define TK_RENAME 99 +#define TK_CTIME_KW 100 +#define TK_ANY 101 +#define TK_BITAND 102 +#define TK_BITOR 103 +#define TK_LSHIFT 104 +#define TK_RSHIFT 105 +#define TK_PLUS 106 +#define TK_MINUS 107 +#define TK_STAR 108 +#define TK_SLASH 109 +#define TK_REM 110 +#define TK_CONCAT 111 +#define TK_PTR 112 +#define TK_COLLATE 113 +#define TK_BITNOT 114 +#define TK_ON 115 +#define TK_INDEXED 116 +#define TK_STRING 117 +#define TK_JOIN_KW 118 +#define TK_CONSTRAINT 119 +#define TK_DEFAULT 120 +#define TK_NULL 121 +#define TK_PRIMARY 122 +#define TK_UNIQUE 123 +#define TK_CHECK 124 +#define TK_REFERENCES 125 +#define TK_AUTOINCR 126 +#define TK_INSERT 127 +#define TK_DELETE 128 +#define TK_UPDATE 129 +#define TK_SET 130 +#define TK_DEFERRABLE 131 +#define TK_FOREIGN 132 +#define TK_DROP 133 +#define TK_UNION 134 +#define TK_ALL 135 +#define TK_EXCEPT 136 +#define TK_INTERSECT 137 +#define TK_SELECT 138 +#define TK_VALUES 139 +#define TK_DISTINCT 140 +#define TK_DOT 141 +#define TK_FROM 142 +#define TK_JOIN 143 +#define TK_USING 144 +#define TK_ORDER 145 +#define TK_GROUP 146 +#define TK_HAVING 147 +#define TK_LIMIT 148 +#define TK_WHERE 149 +#define TK_RETURNING 150 +#define TK_INTO 151 +#define TK_NOTHING 152 +#define TK_FLOAT 153 +#define TK_BLOB 154 +#define TK_INTEGER 155 +#define TK_VARIABLE 156 +#define TK_CASE 157 +#define TK_WHEN 158 +#define TK_THEN 159 +#define TK_ELSE 160 +#define TK_INDEX 161 +#define TK_ALTER 162 +#define TK_ADD 163 +#define TK_WINDOW 164 +#define TK_OVER 165 +#define TK_FILTER 166 +#define TK_COLUMN 167 +#define TK_AGG_FUNCTION 168 +#define TK_AGG_COLUMN 169 +#define TK_TRUEFALSE 170 +#define TK_ISNOT 171 +#define TK_FUNCTION 172 +#define TK_UMINUS 173 +#define TK_UPLUS 174 +#define TK_TRUTH 175 +#define TK_REGISTER 176 +#define TK_VECTOR 177 +#define TK_SELECT_COLUMN 178 +#define TK_IF_NULL_ROW 179 +#define TK_ASTERISK 180 +#define TK_SPAN 181 +#define TK_ERROR 182 +#define TK_SPACE 183 +#define TK_ILLEGAL 184 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -11652,7 +14085,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 -# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */ #endif /* @@ -11681,13 +14113,29 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); ** number of pages. A negative number N translations means that a buffer ** of -1024*N bytes is allocated and used for as many pages as it will hold. ** -** The default value of "20" was choosen to minimize the run-time of the +** The default value of "20" was chosen to minimize the run-time of the ** speedtest1 test program with options: --shrink-memory --reprepare */ #ifndef SQLITE_DEFAULT_PCACHE_INITSZ # define SQLITE_DEFAULT_PCACHE_INITSZ 20 #endif +/* +** Default value for the SQLITE_CONFIG_SORTERREF_SIZE option. +*/ +#ifndef SQLITE_DEFAULT_SORTERREF_SIZE +# define SQLITE_DEFAULT_SORTERREF_SIZE 0x7fffffff +#endif + +/* +** The compile-time options SQLITE_MMAP_READWRITE and +** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another. +** You must choose one or the other (or neither) but not both. +*/ +#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) +#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE +#endif + /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. @@ -11826,7 +14274,9 @@ typedef INT16_TYPE LogEst; # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(_M_ARM) || defined(__arm__) || defined(__x86) + defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ + (defined(__APPLE__) && defined(__POWERPC__)) || \ + (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 @@ -11864,12 +14314,13 @@ typedef INT16_TYPE LogEst; ** at run-time. */ #ifndef SQLITE_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) +# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) +# elif defined(sparc) || defined(__ppc__) || \ + defined(__ARMEB__) || defined(__AARCH64EB__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 @@ -11900,6 +14351,7 @@ typedef INT16_TYPE LogEst; ** compilers. */ #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) +#define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) /* @@ -11953,7 +14405,6 @@ typedef INT16_TYPE LogEst; # else # define SQLITE_MAX_MMAP_SIZE 0 # endif -# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */ #endif /* @@ -11963,37 +14414,44 @@ typedef INT16_TYPE LogEst; */ #ifndef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE 0 -# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */ #endif #if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE # undef SQLITE_DEFAULT_MMAP_SIZE # define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE #endif -/* -** Only one of SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4 can be defined. -** Priority is given to SQLITE_ENABLE_STAT4. If either are defined, also -** define SQLITE_ENABLE_STAT3_OR_STAT4 -*/ -#ifdef SQLITE_ENABLE_STAT4 -# undef SQLITE_ENABLE_STAT3 -# define SQLITE_ENABLE_STAT3_OR_STAT4 1 -#elif SQLITE_ENABLE_STAT3 -# define SQLITE_ENABLE_STAT3_OR_STAT4 1 -#elif SQLITE_ENABLE_STAT3_OR_STAT4 -# undef SQLITE_ENABLE_STAT3_OR_STAT4 -#endif - /* ** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not ** the Select query generator tracing logic is turned on. */ -#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE) +#if !defined(SQLITE_AMALGAMATION) +SQLITE_PRIVATE u32 sqlite3SelectTrace; +#endif +#if defined(SQLITE_DEBUG) \ + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE)) # define SELECTTRACE_ENABLED 1 +# define SELECTTRACE(K,P,S,X) \ + if(sqlite3SelectTrace&(K)) \ + sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\ + sqlite3DebugPrintf X #else +# define SELECTTRACE(K,P,S,X) # define SELECTTRACE_ENABLED 0 #endif +/* +** Macros for "wheretrace" +*/ +SQLITE_PRIVATE u32 sqlite3WhereTrace; +#if defined(SQLITE_DEBUG) \ + && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) +# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X +# define WHERETRACE_ENABLED 1 +#else +# define WHERETRACE(K,X) +#endif + + /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. @@ -12005,28 +14463,44 @@ typedef INT16_TYPE LogEst; */ typedef struct BusyHandler BusyHandler; struct BusyHandler { - int (*xFunc)(void *,int); /* The busy callback */ - void *pArg; /* First arg to busy callback */ - int nBusy; /* Incremented with each busy call */ + int (*xBusyHandler)(void *,int); /* The busy callback */ + void *pBusyArg; /* First arg to busy callback */ + int nBusy; /* Incremented with each busy call */ }; /* -** Name of the master database table. The master database table -** is a special table that holds the names and attributes of all -** user tables and indices. +** Name of table that holds the database schema. +** +** The PREFERRED names are used whereever possible. But LEGACY is also +** used for backwards compatibility. +** +** 1. Queries can use either the PREFERRED or the LEGACY names +** 2. The sqlite3_set_authorizer() callback uses the LEGACY name +** 3. The PRAGMA table_list statement uses the PREFERRED name +** +** The LEGACY names are stored in the internal symbol hash table +** in support of (2). Names are translated using sqlite3PreferredTableName() +** for (3). The sqlite3FindTable() function takes care of translating +** names for (1). +** +** Note that "sqlite_temp_schema" can also be called "temp.sqlite_schema". */ -#define MASTER_NAME "sqlite_master" -#define TEMP_MASTER_NAME "sqlite_temp_master" +#define LEGACY_SCHEMA_TABLE "sqlite_master" +#define LEGACY_TEMP_SCHEMA_TABLE "sqlite_temp_master" +#define PREFERRED_SCHEMA_TABLE "sqlite_schema" +#define PREFERRED_TEMP_SCHEMA_TABLE "sqlite_temp_schema" + /* -** The root-page of the master database table. +** The root-page of the schema table. */ -#define MASTER_ROOT 1 +#define SCHEMA_ROOT 1 /* -** The name of the schema table. +** The name of the schema table. The name is different for TEMP. */ -#define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME) +#define SCHEMA_TABLE(x) \ + ((!OMIT_TEMPDB)&&(x==1)?LEGACY_TEMP_SCHEMA_TABLE:LEGACY_SCHEMA_TABLE) /* ** A convenience macro that returns the number of elements in @@ -12047,7 +14521,7 @@ struct BusyHandler { ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. */ -#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize) +#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault) /* ** When SQLITE_OMIT_WSD is defined, it means that the target platform does @@ -12103,11 +14577,13 @@ typedef struct AutoincInfo AutoincInfo; typedef struct Bitvec Bitvec; typedef struct CollSeq CollSeq; typedef struct Column Column; +typedef struct Cte Cte; +typedef struct CteUse CteUse; typedef struct Db Db; +typedef struct DbFixer DbFixer; typedef struct Schema Schema; typedef struct Expr Expr; typedef struct ExprList ExprList; -typedef struct ExprSpan ExprSpan; typedef struct FKey FKey; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; @@ -12122,15 +14598,19 @@ typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; +typedef struct ParseCleanup ParseCleanup; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; +typedef struct RenameToken RenameToken; +typedef struct Returning Returning; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; +typedef struct SrcItem SrcItem; typedef struct SrcList SrcList; -typedef struct StrAccum StrAccum; +typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; @@ -12139,12 +14619,42 @@ typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct UnpackedRecord UnpackedRecord; +typedef struct Upsert Upsert; typedef struct VTable VTable; typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WhereInfo WhereInfo; +typedef struct Window Window; typedef struct With With; + +/* +** The bitmask datatype defined below is used for various optimizations. +** +** Changing this from a 64-bit to a 32-bit type limits the number of +** tables in a join to 32 instead of 64. But it also reduces the size +** of the library by 738 bytes on ix86. +*/ +#ifdef SQLITE_BITMASK_TYPE + typedef SQLITE_BITMASK_TYPE Bitmask; +#else + typedef u64 Bitmask; +#endif + +/* +** The number of bits in a Bitmask. "BMS" means "BitMask Size". +*/ +#define BMS ((int)(sizeof(Bitmask)*8)) + +/* +** A bit in a Bitmask +*/ +#define MASKBIT(n) (((Bitmask)1)<<(n)) +#define MASKBIT64(n) (((u64)1)<<(n)) +#define MASKBIT32(n) (((unsigned int)1)<<(n)) +#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0) +#define ALLBITS ((Bitmask)-1) + /* A VList object records a mapping between parameters/variables/wildcards ** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer ** variable number associated with that parameter. See the format description @@ -12158,6 +14668,253 @@ typedef int VList; ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque ** pointer types (i.e. FuncDef) defined above. */ +/************** Include pager.h in the middle of sqliteInt.h *****************/ +/************** Begin file pager.h *******************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface that the sqlite page cache +** subsystem. The page cache subsystem reads and writes a file a page +** at a time and provides a journal for rollback. +*/ + +#ifndef SQLITE_PAGER_H +#define SQLITE_PAGER_H + +/* +** Default maximum size for persistent journal files. A negative +** value means no limit. This value may be overridden using the +** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit". +*/ +#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT + #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1 +#endif + +/* +** The type used to represent a page number. The first page in a file +** is called page 1. 0 is used to represent "not a page". +*/ +typedef u32 Pgno; + +/* +** Each open file is managed by a separate instance of the "Pager" structure. +*/ +typedef struct Pager Pager; + +/* +** Handle type for pages. +*/ +typedef struct PgHdr DbPage; + +/* +** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is +** reserved for working around a windows/posix incompatibility). It is +** used in the journal to signify that the remainder of the journal file +** is devoted to storing a super-journal name - there are no more pages to +** roll back. See comments for function writeSuperJournal() in pager.c +** for details. +*/ +#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) + +/* +** Allowed values for the flags parameter to sqlite3PagerOpen(). +** +** NOTE: These values must match the corresponding BTREE_ values in btree.h. +*/ +#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ +#define PAGER_MEMORY 0x0002 /* In-memory database */ + +/* +** Valid values for the second argument to sqlite3PagerLockingMode(). +*/ +#define PAGER_LOCKINGMODE_QUERY -1 +#define PAGER_LOCKINGMODE_NORMAL 0 +#define PAGER_LOCKINGMODE_EXCLUSIVE 1 + +/* +** Numeric constants that encode the journalmode. +** +** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY) +** are exposed in the API via the "PRAGMA journal_mode" command and +** therefore cannot be changed without a compatibility break. +*/ +#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ +#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ +#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ +#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ +#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ +#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ +#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ + +/* +** Flags that make up the mask passed to sqlite3PagerGet(). +*/ +#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */ +#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */ + +/* +** Flags for sqlite3PagerSetFlags() +** +** Value constraints (enforced via assert()): +** PAGER_FULLFSYNC == SQLITE_FullFSync +** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync +** PAGER_CACHE_SPILL == SQLITE_CacheSpill +*/ +#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */ +#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */ +#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */ +#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */ +#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */ +#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */ +#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */ +#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */ +#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */ + +/* +** The remainder of this file contains the declarations of the functions +** that make up the Pager sub-system API. See source code comments for +** a detailed description of each routine. +*/ + +/* Open and close a Pager connection. */ +SQLITE_PRIVATE int sqlite3PagerOpen( + sqlite3_vfs*, + Pager **ppPager, + const char*, + int, + int, + int, + void(*)(DbPage*) +); +SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*); +SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); + +/* Functions used to configure a Pager object. */ +SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *); +SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); +SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno); +SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); +SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); +SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); +SQLITE_PRIVATE void sqlite3PagerShrink(Pager*); +SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned); +SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int); +SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int); +SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*); +SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*); +SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64); +SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*); +SQLITE_PRIVATE int sqlite3PagerFlush(Pager*); + +/* Functions used to obtain and release page references. */ +SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); +SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); +SQLITE_PRIVATE void sqlite3PagerRef(DbPage*); +SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*); +SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*); +SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*); + +/* Operations on page references. */ +SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); +SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*); +SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int); +SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*); +SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *); +SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *); + +/* Functions used to manage pager transactions and savepoints. */ +SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*); +SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int); +SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int); +SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*); +SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper); +SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*); +SQLITE_PRIVATE int sqlite3PagerRollback(Pager*); +SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n); +SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); +SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); + +#ifndef SQLITE_OMIT_WAL +SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*); +SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); +SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); +# ifdef SQLITE_ENABLE_SNAPSHOT +SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot); +SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager); +SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager); +# endif +#endif + +#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT) +SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int); +SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*); +#else +# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK +# define sqlite3PagerWalDb(x,y) +#endif + +#ifdef SQLITE_DIRECT_OVERFLOW_READ +SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno); +#endif + +#ifdef SQLITE_ENABLE_ZIPVFS +SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager); +#endif + +/* Functions used to query pager state and configuration. */ +SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); +SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); +#endif +SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); +SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int); +SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*); +SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); +SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); +SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); +SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); +SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); +SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); +SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); +SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); + +/* Functions used to truncate the database file. */ +SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); + +SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); + +/* Functions to support testing and debugging. */ +#if !defined(NDEBUG) || defined(SQLITE_TEST) +SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); +SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*); +#endif +#ifdef SQLITE_TEST +SQLITE_PRIVATE int *sqlite3PagerStats(Pager*); +SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); + void disable_simulated_io_errors(void); + void enable_simulated_io_errors(void); +#else +# define disable_simulated_io_errors() +# define enable_simulated_io_errors() +#endif + +#endif /* SQLITE_PAGER_H */ + +/************** End of pager.h ***********************************************/ +/************** Continuing where we left off in sqliteInt.h ******************/ /************** Include btree.h in the middle of sqliteInt.h *****************/ /************** Begin file btree.h *******************************************/ /* @@ -12233,30 +14990,38 @@ SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); -SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); -SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*); +SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno); +SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree*); SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int); -SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*); +SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*); SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p); SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); -SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); -SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int,int*); +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char*); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int); SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); -SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags); -SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); -SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); +SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags); +SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); + SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree); #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); #endif + +/* Savepoints are named, nestable SQL transactions mostly implemented */ +/* in vdbe.c and pager.c See https://sqlite.org/lang_savepoint.html */ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int); +/* "Checkpoint" only refers to WAL. See https://sqlite.org/wal.html#ckpt */ +#ifndef SQLITE_OMIT_WAL +SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); +#endif + SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); @@ -12277,7 +15042,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); -SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); +SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, i64*); SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int); @@ -12288,7 +15053,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); /* ** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta -** should be one of the following values. The integer values are assigned +** should be one of the following values. The integer values are assigned ** to constants so that the offset of the corresponding field in an ** SQLite database header may be found using the following formula: ** @@ -12359,7 +15124,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); #define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */ #define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */ -/* +/* ** Flags passed as the third argument to sqlite3BtreeCursor(). ** ** For read-only cursors the wrFlag argument is always zero. For read-write @@ -12387,11 +15152,12 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p); SQLITE_PRIVATE int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ - int iTable, /* Index of root page */ + Pgno iTable, /* Index of root page */ int wrFlag, /* 1 for writing. 0 for read-only */ struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); +SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void); SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); @@ -12400,13 +15166,17 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...); #endif SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); -SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( +SQLITE_PRIVATE int sqlite3BtreeTableMoveto( BtCursor*, - UnpackedRecord *pUnKey, i64 intKey, int bias, int *pRes ); +SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( + BtCursor*, + UnpackedRecord *pUnKey, + int *pRes +); SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*); SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags); @@ -12415,30 +15185,46 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags); #define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ #define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ #define BTREE_APPEND 0x08 /* Insert is likely an append */ +#define BTREE_PREFORMAT 0x80 /* Inserted data is a preformated cell */ /* An instance of the BtreePayload object describes the content of a single ** entry in either an index or table btree. ** ** Index btrees (used for indexes and also WITHOUT ROWID tables) contain -** an arbitrary key and no data. These btrees have pKey,nKey set to their -** key and pData,nData,nZero set to zero. +** an arbitrary key and no data. These btrees have pKey,nKey set to the +** key and the pData,nData,nZero fields are uninitialized. The aMem,nMem +** fields give an array of Mem objects that are a decomposition of the key. +** The nMem field might be zero, indicating that no decomposition is available. ** ** Table btrees (used for rowid tables) contain an integer rowid used as -** the key and passed in the nKey field. The pKey field is zero. +** the key and passed in the nKey field. The pKey field is zero. ** pData,nData hold the content of the new entry. nZero extra zero bytes ** are appended to the end of the content when constructing the entry. +** The aMem,nMem fields are uninitialized for table btrees. +** +** Field usage summary: +** +** Table BTrees Index Btrees +** +** pKey always NULL encoded key +** nKey the ROWID length of pKey +** pData data not used +** aMem not used decomposed key value +** nMem not used entries in aMem +** nData length of pData not used +** nZero extra zeros after pData not used ** ** This object is used to pass information into sqlite3BtreeInsert(). The ** same information used to be passed as five separate parameters. But placing -** the information into this object helps to keep the interface more +** the information into this object helps to keep the interface more ** organized and understandable, and it also helps the resulting code to ** run a little faster by using fewer registers for parameter passing. */ struct BtreePayload { const void *pKey; /* Key content for indexes. NULL for tables */ sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */ - const void *pData; /* Data for tables. NULL for indexes */ - struct Mem *aMem; /* First of nMem value in the unpacked pKey */ + const void *pData; /* Data for tables. */ + sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */ u16 nMem; /* Number of aMem[] value. Might be zero */ int nData; /* Size of pData. 0 if none. */ int nZero; /* Extra zero data appended after pData,nData */ @@ -12448,16 +15234,23 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes); +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags); SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*); +SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor*); +SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor*); +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC +SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*); +#endif SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*); +SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*); -SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); +SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); +SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*); #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*); @@ -12470,14 +15263,18 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt); SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree*); +#else +# define sqlite3BtreeSeekCount(X) 0 +#endif + #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); #endif SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*); -#ifndef SQLITE_OMIT_BTREECOUNT -SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *); -#endif +SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*); #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int); @@ -12488,6 +15285,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*); SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif +SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64); + /* ** If we are not using shared cache, then there is no need to ** use mutexes to access the BtShared structures. So make the @@ -12500,7 +15299,7 @@ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*); #else -# define sqlite3BtreeEnter(X) +# define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) # define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeEnterCursor(X) @@ -12567,7 +15366,7 @@ typedef struct Vdbe Vdbe; ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ -typedef struct Mem Mem; +typedef struct sqlite3_value Mem; typedef struct SubProgram SubProgram; /* @@ -12594,13 +15393,13 @@ struct VdbeOp { Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ - int *ai; /* Used when p4type is P4_INTARRAY */ + u32 *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Table *pTab; /* Used when p4type is P4_TABLE */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif - int (*xAdvance)(BtCursor *, int *); + int (*xAdvance)(BtCursor *, int); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ @@ -12610,7 +15409,8 @@ struct VdbeOp { u64 cycles; /* Total time spent executing this instruction */ #endif #ifdef SQLITE_VDBE_COVERAGE - int iSrcLine; /* Source-code line that generated this opcode */ + u32 iSrcLine; /* Source-code line that generated this opcode + ** with flags in the upper 8 bits */ #endif }; typedef struct VdbeOp VdbeOp; @@ -12624,6 +15424,7 @@ struct SubProgram { int nOp; /* Elements in aOp[] */ int nMem; /* Number of memory cells required */ int nCsr; /* Number of cursors required */ + u8 *aOnce; /* Array of OP_Once flags */ void *token; /* id that may be used to recursive triggers */ SubProgram *pNext; /* Next sub-program already visited */ }; @@ -12643,24 +15444,27 @@ typedef struct VdbeOpList VdbeOpList; /* ** Allowed values of VdbeOp.p4type */ -#define P4_NOTUSED 0 /* The P4 parameter is not used */ -#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ -#define P4_STATIC (-2) /* Pointer to a static string */ -#define P4_COLLSEQ (-3) /* P4 is a pointer to a CollSeq structure */ -#define P4_FUNCDEF (-4) /* P4 is a pointer to a FuncDef structure */ -#define P4_KEYINFO (-5) /* P4 is a pointer to a KeyInfo structure */ -#define P4_EXPR (-6) /* P4 is a pointer to an Expr tree */ -#define P4_MEM (-7) /* P4 is a pointer to a Mem* structure */ -#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ -#define P4_VTAB (-8) /* P4 is a pointer to an sqlite3_vtab structure */ -#define P4_REAL (-9) /* P4 is a 64-bit floating point value */ -#define P4_INT64 (-10) /* P4 is a 64-bit signed integer */ -#define P4_INT32 (-11) /* P4 is a 32-bit signed integer */ -#define P4_INTARRAY (-12) /* P4 is a vector of 32-bit integers */ -#define P4_SUBPROGRAM (-13) /* P4 is a pointer to a SubProgram structure */ -#define P4_ADVANCE (-14) /* P4 is a pointer to BtreeNext() or BtreePrev() */ -#define P4_TABLE (-15) /* P4 is a pointer to a Table structure */ -#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ +#define P4_NOTUSED 0 /* The P4 parameter is not used */ +#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ +#define P4_STATIC (-1) /* Pointer to a static string */ +#define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */ +#define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ +#define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ +#define P4_ADVANCE (-5) /* P4 is a pointer to BtreeNext() or BtreePrev() */ +#define P4_TABLE (-6) /* P4 is a pointer to a Table structure */ +/* Above do not own any resources. Must free those below */ +#define P4_FREE_IF_LE (-7) +#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */ +#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ +#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ +#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ +#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ +#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ +#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ +#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ +#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ +#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ +#define P4_DYNBLOB (-17) /* Pointer to memory from sqliteMalloc() */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -12669,7 +15473,7 @@ typedef struct VdbeOpList VdbeOpList; #define P5_ConstraintFK 4 /* -** The Vdbe.aColName array contains 5n Mem structures, where n is the +** The Vdbe.aColName array contains 5n Mem structures, where n is the ** number of columns of data returned by the statement. */ #define COLNAME_NAME 0 @@ -12688,12 +15492,11 @@ typedef struct VdbeOpList VdbeOpList; #endif /* -** The following macro converts a relative address in the p2 field -** of a VdbeOp structure into a negative number so that -** sqlite3VdbeAddOpList() knows that the address is relative. Calling -** the macro again restores the address. +** The following macro converts a label returned by sqlite3VdbeMakeLabel() +** into an index into the Parse.aLabel[] array that contains the resolved +** address of that label. */ -#define ADDR(X) (-1-(X)) +#define ADDR(X) (~(X)) /* ** The makefile scans the vdbe.c source file and creates the "opcodes.h" @@ -12706,165 +15509,188 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Savepoint 0 #define OP_AutoCommit 1 #define OP_Transaction 2 -#define OP_SorterNext 3 -#define OP_PrevIfOpen 4 -#define OP_NextIfOpen 5 -#define OP_Prev 6 -#define OP_Next 7 -#define OP_Checkpoint 8 -#define OP_JournalMode 9 -#define OP_Vacuum 10 -#define OP_VFilter 11 /* synopsis: iplan=r[P3] zplan='P4' */ -#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */ -#define OP_Goto 13 -#define OP_Gosub 14 -#define OP_InitCoroutine 15 -#define OP_Yield 16 -#define OP_MustBeInt 17 -#define OP_Jump 18 +#define OP_SorterNext 3 /* jump */ +#define OP_Prev 4 /* jump */ +#define OP_Next 5 /* jump */ +#define OP_Checkpoint 6 +#define OP_JournalMode 7 +#define OP_Vacuum 8 +#define OP_VFilter 9 /* jump, synopsis: iplan=r[P3] zplan='P4' */ +#define OP_VUpdate 10 /* synopsis: data=r[P3@P2] */ +#define OP_Goto 11 /* jump */ +#define OP_Gosub 12 /* jump */ +#define OP_InitCoroutine 13 /* jump */ +#define OP_Yield 14 /* jump */ +#define OP_MustBeInt 15 /* jump */ +#define OP_Jump 16 /* jump */ +#define OP_Once 17 /* jump */ +#define OP_If 18 /* jump */ #define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */ -#define OP_Once 20 -#define OP_If 21 -#define OP_IfNot 22 -#define OP_SeekLT 23 /* synopsis: key=r[P3@P4] */ -#define OP_SeekLE 24 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGE 25 /* synopsis: key=r[P3@P4] */ -#define OP_SeekGT 26 /* synopsis: key=r[P3@P4] */ -#define OP_Or 27 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ -#define OP_And 28 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ -#define OP_NoConflict 29 /* synopsis: key=r[P3@P4] */ -#define OP_NotFound 30 /* synopsis: key=r[P3@P4] */ -#define OP_Found 31 /* synopsis: key=r[P3@P4] */ -#define OP_SeekRowid 32 /* synopsis: intkey=r[P3] */ -#define OP_NotExists 33 /* synopsis: intkey=r[P3] */ -#define OP_IsNull 34 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ -#define OP_NotNull 35 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ -#define OP_Ne 36 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */ -#define OP_Eq 37 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */ -#define OP_Gt 38 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */ -#define OP_Le 39 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */ -#define OP_Lt 40 /* same as TK_LT, synopsis: IF r[P3]=r[P1] */ -#define OP_ElseNotEq 42 /* same as TK_ESCAPE */ -#define OP_BitAnd 43 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ -#define OP_BitOr 44 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ -#define OP_ShiftLeft 45 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ -#define OP_Add 47 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ -#define OP_Subtract 48 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ -#define OP_Multiply 49 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ -#define OP_Divide 50 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ -#define OP_Remainder 51 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ -#define OP_Concat 52 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_Last 53 -#define OP_BitNot 54 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */ -#define OP_SorterSort 55 -#define OP_Sort 56 -#define OP_Rewind 57 -#define OP_IdxLE 58 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGT 59 /* synopsis: key=r[P3@P4] */ -#define OP_IdxLT 60 /* synopsis: key=r[P3@P4] */ -#define OP_IdxGE 61 /* synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 62 /* synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 63 /* synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 64 -#define OP_FkIfZero 65 /* synopsis: if fkctr[P1]==0 goto P2 */ -#define OP_IfPos 66 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_IfNotZero 67 /* synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ -#define OP_DecrJumpZero 68 /* synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 69 -#define OP_VNext 70 -#define OP_Init 71 /* synopsis: Start at P2 */ -#define OP_Return 72 -#define OP_EndCoroutine 73 -#define OP_HaltIfNull 74 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 75 -#define OP_Integer 76 /* synopsis: r[P2]=P1 */ -#define OP_Int64 77 /* synopsis: r[P2]=P4 */ -#define OP_String 78 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 79 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 80 /* synopsis: r[P1]=NULL */ -#define OP_Blob 81 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 82 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 83 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 84 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 85 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 86 /* synopsis: r[P2]=r[P1] */ -#define OP_ResultRow 87 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 88 -#define OP_Function0 89 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_Function 90 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_AddImm 91 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 92 -#define OP_Cast 93 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 94 -#define OP_Compare 95 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_Column 96 /* synopsis: r[P3]=PX */ -#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 100 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 101 -#define OP_SetCookie 102 -#define OP_ReopenIdx 103 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 104 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 105 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenAutoindex 106 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 107 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 108 -#define OP_SequenceTest 109 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ -#define OP_OpenPseudo 110 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 111 -#define OP_ColumnsUsed 112 -#define OP_Sequence 113 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 114 /* synopsis: r[P2]=rowid */ -#define OP_Insert 115 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_InsertInt 116 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 117 -#define OP_ResetCount 118 -#define OP_SorterCompare 119 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 120 /* synopsis: r[P2]=data */ -#define OP_RowData 121 /* synopsis: r[P2]=data */ -#define OP_Rowid 122 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 123 -#define OP_SorterInsert 124 /* synopsis: key=r[P2] */ -#define OP_IdxInsert 125 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 126 /* synopsis: key=r[P2@P3] */ -#define OP_Seek 127 /* synopsis: Move P3 to P1.rowid */ -#define OP_IdxRowid 128 /* synopsis: r[P2]=rowid */ -#define OP_Destroy 129 -#define OP_Clear 130 -#define OP_ResetSorter 131 -#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_CreateIndex 133 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_CreateTable 134 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_ParseSchema 135 -#define OP_LoadAnalysis 136 -#define OP_DropTable 137 -#define OP_DropIndex 138 -#define OP_DropTrigger 139 -#define OP_IntegrityCk 140 -#define OP_RowSetAdd 141 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Param 142 -#define OP_FkCounter 143 /* synopsis: fkctr[P1]+=P2 */ -#define OP_MemMax 144 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 145 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggStep0 146 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep 147 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggFinal 148 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 149 -#define OP_TableLock 150 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 151 -#define OP_VCreate 152 -#define OP_VDestroy 153 -#define OP_VOpen 154 -#define OP_VColumn 155 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 156 -#define OP_Pagecount 157 -#define OP_MaxPgcnt 158 -#define OP_CursorHint 159 -#define OP_Noop 160 -#define OP_Explain 161 +#define OP_IfNot 20 /* jump */ +#define OP_IsNullOrType 21 /* jump, synopsis: if typeof(r[P1]) IN (P3,5) goto P2 */ +#define OP_IfNullRow 22 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */ +#define OP_SeekLT 23 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekLE 24 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGE 25 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekGT 26 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IfNotOpen 27 /* jump, synopsis: if( !csr[P1] ) goto P2 */ +#define OP_IfNoHope 28 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NoConflict 29 /* jump, synopsis: key=r[P3@P4] */ +#define OP_NotFound 30 /* jump, synopsis: key=r[P3@P4] */ +#define OP_Found 31 /* jump, synopsis: key=r[P3@P4] */ +#define OP_SeekRowid 32 /* jump, synopsis: intkey=r[P3] */ +#define OP_NotExists 33 /* jump, synopsis: intkey=r[P3] */ +#define OP_Last 34 /* jump */ +#define OP_IfSmaller 35 /* jump */ +#define OP_SorterSort 36 /* jump */ +#define OP_Sort 37 /* jump */ +#define OP_Rewind 38 /* jump */ +#define OP_IdxLE 39 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGT 40 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxLT 41 /* jump, synopsis: key=r[P3@P4] */ +#define OP_IdxGE 42 /* jump, synopsis: key=r[P3@P4] */ +#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */ +#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ +#define OP_RowSetRead 45 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 46 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 47 /* jump */ +#define OP_FkIfZero 48 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 49 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ +#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ +#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ +#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */ +#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */ +#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */ +#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ +#define OP_ElseEq 58 /* jump, same as TK_ESCAPE */ +#define OP_IfNotZero 59 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_DecrJumpZero 60 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 61 /* jump */ +#define OP_VNext 62 /* jump */ +#define OP_Filter 63 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ +#define OP_Init 64 /* jump, synopsis: Start at P2 */ +#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Return 67 +#define OP_EndCoroutine 68 +#define OP_HaltIfNull 69 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 70 +#define OP_Integer 71 /* synopsis: r[P2]=P1 */ +#define OP_Int64 72 /* synopsis: r[P2]=P4 */ +#define OP_String 73 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_Null 74 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 75 /* synopsis: r[P1]=NULL */ +#define OP_Blob 76 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 77 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 78 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 79 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 80 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 81 /* synopsis: r[P2]=r[P1] */ +#define OP_FkCheck 82 +#define OP_ResultRow 83 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 84 +#define OP_AddImm 85 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 86 +#define OP_Cast 87 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 88 +#define OP_Compare 89 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_IsTrue 90 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ +#define OP_ZeroOrNull 91 /* synopsis: r[P2] = 0 OR NULL */ +#define OP_Offset 92 /* synopsis: r[P3] = sqlite_offset(P1) */ +#define OP_Column 93 /* synopsis: r[P3]=PX */ +#define OP_TypeCheck 94 /* synopsis: typecheck(r[P1@P2]) */ +#define OP_Affinity 95 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 96 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 97 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 98 +#define OP_SetCookie 99 +#define OP_ReopenIdx 100 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 101 /* synopsis: root=P2 iDb=P3 */ +#define OP_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<>r[P1] */ +#define OP_Add 106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_OpenWrite 112 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenDup 113 +#define OP_BitNot 114 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ +#define OP_OpenAutoindex 115 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 116 /* synopsis: nColumn=P2 */ +#define OP_String8 117 /* same as TK_STRING, synopsis: r[P2]='P4' */ +#define OP_SorterOpen 118 +#define OP_SequenceTest 119 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 120 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 121 +#define OP_ColumnsUsed 122 +#define OP_SeekScan 123 /* synopsis: Scan-ahead up to P1 rows */ +#define OP_SeekHit 124 /* synopsis: set P2<=seekHit<=P3 */ +#define OP_Sequence 125 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 126 /* synopsis: r[P2]=rowid */ +#define OP_Insert 127 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_RowCell 128 +#define OP_Delete 129 +#define OP_ResetCount 130 +#define OP_SorterCompare 131 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 132 /* synopsis: r[P2]=data */ +#define OP_RowData 133 /* synopsis: r[P2]=data */ +#define OP_Rowid 134 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 135 +#define OP_SeekEnd 136 +#define OP_IdxInsert 137 /* synopsis: key=r[P2] */ +#define OP_SorterInsert 138 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 139 /* synopsis: key=r[P2@P3] */ +#define OP_DeferredSeek 140 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 141 /* synopsis: r[P2]=rowid */ +#define OP_FinishSeek 142 +#define OP_Destroy 143 +#define OP_Clear 144 +#define OP_ResetSorter 145 +#define OP_CreateBtree 146 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_SqlExec 147 +#define OP_ParseSchema 148 +#define OP_LoadAnalysis 149 +#define OP_DropTable 150 +#define OP_DropIndex 151 +#define OP_DropTrigger 152 +#define OP_Real 153 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ +#define OP_IntegrityCk 154 +#define OP_RowSetAdd 155 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 156 +#define OP_FkCounter 157 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 158 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 159 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 160 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 161 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 162 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 163 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 164 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 165 +#define OP_CursorLock 166 +#define OP_CursorUnlock 167 +#define OP_TableLock 168 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 169 +#define OP_VCreate 170 +#define OP_VDestroy 171 +#define OP_VOpen 172 +#define OP_VInitIn 173 /* synopsis: r[P2]=ValueList(P1,P3) */ +#define OP_VColumn 174 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 175 +#define OP_Pagecount 176 +#define OP_MaxPgcnt 177 +#define OP_FilterAdd 178 /* synopsis: filter(P1) += key(P3@P4) */ +#define OP_Trace 179 +#define OP_CursorHint 180 +#define OP_ReleaseReg 181 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 182 +#define OP_Explain 183 +#define OP_Abortable 184 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -12877,44 +15703,54 @@ typedef struct VdbeOpList VdbeOpList; #define OPFLG_OUT2 0x10 /* out2: P2 is an output */ #define OPFLG_OUT3 0x20 /* out3: P3 is an output */ #define OPFLG_INITIALIZER {\ -/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\ -/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\ -/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x09,\ -/* 24 */ 0x09, 0x09, 0x09, 0x26, 0x26, 0x09, 0x09, 0x09,\ -/* 32 */ 0x09, 0x09, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ -/* 40 */ 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 48 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x01, 0x12, 0x01,\ -/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x0b,\ -/* 64 */ 0x01, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01,\ -/* 72 */ 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10,\ -/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,\ -/* 88 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\ -/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ -/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 112 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00,\ -/* 128 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00,\ -/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00,\ -/* 144 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\ -/* 160 */ 0x00, 0x00,} - -/* The sqlite3P2Values() routine is able to run faster if it knows +/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\ +/* 8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\ +/* 16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x03, 0x01, 0x09,\ +/* 24 */ 0x09, 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09,\ +/* 32 */ 0x09, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ +/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x23, 0x0b, 0x01,\ +/* 48 */ 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x01, 0x01,\ +/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\ +/* 72 */ 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 80 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02,\ +/* 88 */ 0x00, 0x00, 0x12, 0x1e, 0x20, 0x00, 0x00, 0x00,\ +/* 96 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x26, 0x26,\ +/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ +/* 112 */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\ +/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\ +/* 136 */ 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00, 0x10,\ +/* 144 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x10, 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a,\ +/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\ +/* 176 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 184 */ 0x00,} + +/* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum ** JUMP opcode the better, so the mkopcodeh.tcl script that ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ -#define SQLITE_MX_JUMP_OPCODE 71 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 64 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ +/* +** Additional non-public SQLITE_PREPARE_* flags +*/ +#define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ +#define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */ + /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*); +SQLITE_PRIVATE Parse *sqlite3VdbeParser(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); @@ -12925,6 +15761,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); +SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(Parse*,int,int,int,int,const FuncDef*,int); SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int); #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N); @@ -12933,22 +15770,51 @@ SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p); # define sqlite3VdbeVerifyNoMallocRequired(A,B) # define sqlite3VdbeVerifyNoResultRow(A) #endif -SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno); -SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); -SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); -SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); -SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); -SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int); +#else +# define sqlite3VdbeVerifyAbortable(A,B) +#endif +SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); +#ifndef SQLITE_OMIT_EXPLAIN +SQLITE_PRIVATE void sqlite3VdbeExplain(Parse*,u8,const char*,...); +SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse*); +SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*); +# define ExplainQueryPlan(P) sqlite3VdbeExplain P +# define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P) +# define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P) +#else +# define ExplainQueryPlan(P) +# define ExplainQueryPlanPop(P) +# define ExplainQueryPlanParent(P) 0 +# define sqlite3ExplainBreakpoint(A,B) /*no-op*/ +#endif +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN) +SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char*,const char*); +#else +# define sqlite3ExplainBreakpoint(A,B) /*no-op*/ +#endif +SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16); +SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8); +SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1); +SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2); +SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); +SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr); SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int); +#else +# define sqlite3VdbeReleaseRegisters(P,A,N,M,F) +#endif SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); -SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); +SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); @@ -12967,7 +15833,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); +SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*); +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3*,Vdbe*,const char*); +SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(Vdbe*,const char*); +#endif SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); @@ -12976,6 +15847,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); +SQLITE_PRIVATE int sqlite3BlobCompare(const Mem*, const Mem*); SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); @@ -12985,8 +15857,12 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*); typedef int (*RecordCompare)(int,const void*,UnpackedRecord*); SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*); -#ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); +SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe*); + +SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); +#ifdef SQLITE_ENABLE_BYTECODE_VTAB +SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on @@ -13029,23 +15905,52 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); ** ** VdbeCoverageNeverTaken(v) // Previous branch is never taken ** +** VdbeCoverageNeverNull(v) // Previous three-way branch is only +** // taken on the first two ways. The +** // NULL option is not possible +** +** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested +** // in distingishing equal and not-equal. +** ** Every VDBE branch operation must be tagged with one of the macros above. ** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and ** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch() ** routine in vdbe.c, alerting the developer to the missed tag. +** +** During testing, the test application will invoke +** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback +** routine that is invoked as each bytecode branch is taken. The callback +** contains the sqlite3.c source line number ov the VdbeCoverage macro and +** flags to indicate whether or not the branch was taken. The test application +** is responsible for keeping track of this and reporting byte-code branches +** that are never taken. +** +** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the +** vdbe.c source file for additional information. */ #ifdef SQLITE_VDBE_COVERAGE SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int); # define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__) # define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__) -# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2); -# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1); +# define VdbeCoverageAlwaysTaken(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000); +# define VdbeCoverageNeverTaken(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000); +# define VdbeCoverageNeverNull(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); +# define VdbeCoverageNeverNullIf(v,x) \ + if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000); +# define VdbeCoverageEqNe(v) \ + sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000); # define VDBE_OFFSET_LINENO(x) (__LINE__+x) #else # define VdbeCoverage(v) # define VdbeCoverageIf(v,x) # define VdbeCoverageAlwaysTaken(v) # define VdbeCoverageNeverTaken(v) +# define VdbeCoverageNeverNull(v) +# define VdbeCoverageNeverNullIf(v,x) +# define VdbeCoverageEqNe(v) # define VDBE_OFFSET_LINENO(x) 0 #endif @@ -13055,253 +15960,13 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif -#endif /* SQLITE_VDBE_H */ - -/************** End of vdbe.h ************************************************/ -/************** Continuing where we left off in sqliteInt.h ******************/ -/************** Include pager.h in the middle of sqliteInt.h *****************/ -/************** Begin file pager.h *******************************************/ -/* -** 2001 September 15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This header file defines the interface that the sqlite page cache -** subsystem. The page cache subsystem reads and writes a file a page -** at a time and provides a journal for rollback. -*/ - -#ifndef SQLITE_PAGER_H -#define SQLITE_PAGER_H - -/* -** Default maximum size for persistent journal files. A negative -** value means no limit. This value may be overridden using the -** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit". -*/ -#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT - #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1 -#endif - -/* -** The type used to represent a page number. The first page in a file -** is called page 1. 0 is used to represent "not a page". -*/ -typedef u32 Pgno; - -/* -** Each open file is managed by a separate instance of the "Pager" structure. -*/ -typedef struct Pager Pager; - -/* -** Handle type for pages. -*/ -typedef struct PgHdr DbPage; - -/* -** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is -** reserved for working around a windows/posix incompatibility). It is -** used in the journal to signify that the remainder of the journal file -** is devoted to storing a master journal name - there are no more pages to -** roll back. See comments for function writeMasterJournal() in pager.c -** for details. -*/ -#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) - -/* -** Allowed values for the flags parameter to sqlite3PagerOpen(). -** -** NOTE: These values must match the corresponding BTREE_ values in btree.h. -*/ -#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ -#define PAGER_MEMORY 0x0002 /* In-memory database */ - -/* -** Valid values for the second argument to sqlite3PagerLockingMode(). -*/ -#define PAGER_LOCKINGMODE_QUERY -1 -#define PAGER_LOCKINGMODE_NORMAL 0 -#define PAGER_LOCKINGMODE_EXCLUSIVE 1 - -/* -** Numeric constants that encode the journalmode. -** -** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY) -** are exposed in the API via the "PRAGMA journal_mode" command and -** therefore cannot be changed without a compatibility break. -*/ -#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ -#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ -#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ -#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ -#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ -#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ -#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ - -/* -** Flags that make up the mask passed to sqlite3PagerGet(). -*/ -#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */ -#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */ - -/* -** Flags for sqlite3PagerSetFlags() -** -** Value constraints (enforced via assert()): -** PAGER_FULLFSYNC == SQLITE_FullFSync -** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync -** PAGER_CACHE_SPILL == SQLITE_CacheSpill -*/ -#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */ -#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */ -#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */ -#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */ -#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */ -#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */ -#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */ -#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */ -#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */ - -/* -** The remainder of this file contains the declarations of the functions -** that make up the Pager sub-system API. See source code comments for -** a detailed description of each routine. -*/ - -/* Open and close a Pager connection. */ -SQLITE_PRIVATE int sqlite3PagerOpen( - sqlite3_vfs*, - Pager **ppPager, - const char*, - int, - int, - int, - void(*)(DbPage*) -); -SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*); -SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); - -/* Functions used to configure a Pager object. */ -SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); -SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); -#ifdef SQLITE_HAS_CODEC -SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*); -#endif -SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int); -SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); -SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int); -SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); -SQLITE_PRIVATE void sqlite3PagerShrink(Pager*); -SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned); -SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int); -SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int); -SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*); -SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*); -SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64); -SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*); -SQLITE_PRIVATE int sqlite3PagerFlush(Pager*); - -/* Functions used to obtain and release page references. */ -SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); -SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); -SQLITE_PRIVATE void sqlite3PagerRef(DbPage*); -SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*); -SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*); - -/* Operations on page references. */ -SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); -SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*); -SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int); -SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*); -SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *); -SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *); - -/* Functions used to manage pager transactions and savepoints. */ -SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*); -SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int); -SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); -SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*); -SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster); -SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*); -SQLITE_PRIVATE int sqlite3PagerRollback(Pager*); -SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n); -SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); -SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); - -#ifndef SQLITE_OMIT_WAL -SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*); -SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); -SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); -SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); -SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*); -# ifdef SQLITE_DIRECT_OVERFLOW_READ -SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno); -# endif -# ifdef SQLITE_ENABLE_SNAPSHOT -SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot); -SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot); -SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager); -# endif -#else -# define sqlite3PagerUseWal(x,y) 0 -#endif - -#ifdef SQLITE_ENABLE_ZIPVFS -SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager); -#endif - -/* Functions used to query pager state and configuration. */ -SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); -SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*); -#ifdef SQLITE_DEBUG -SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); -#endif -SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); -SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int); -SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*); -SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); -SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*); -SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); -SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); -SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); -SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); -SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*); -SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *); - -/* Functions used to truncate the database file. */ -SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); - -SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16); - -#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) -SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); -#endif - -/* Functions to support testing and debugging. */ -#if !defined(NDEBUG) || defined(SQLITE_TEST) -SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); -SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*); -#endif -#ifdef SQLITE_TEST -SQLITE_PRIVATE int *sqlite3PagerStats(Pager*); -SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); - void disable_simulated_io_errors(void); - void enable_simulated_io_errors(void); -#else -# define disable_simulated_io_errors() -# define enable_simulated_io_errors() +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) +SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); #endif -#endif /* SQLITE_PAGER_H */ +#endif /* SQLITE_VDBE_H */ -/************** End of pager.h ***********************************************/ +/************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pcache.h in the middle of sqliteInt.h ****************/ /************** Begin file pcache.h ******************************************/ @@ -13317,7 +15982,7 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); ** ************************************************************************* ** This header file defines the interface that the sqlite page cache -** subsystem. +** subsystem. */ #ifndef _PCACHE_H_ @@ -13333,6 +15998,7 @@ struct PgHdr { sqlite3_pcache_page *pPage; /* Pcache object page handle */ void *pData; /* Page data */ void *pExtra; /* Extra content */ + PCache *pCache; /* PRIVATE: Cache that owns this page */ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ Pgno pgno; /* Page number for this page */ @@ -13342,14 +16008,15 @@ struct PgHdr { u16 flags; /* PGHDR flags defined below */ /********************************************************************** - ** Elements above are public. All that follows is private to pcache.c - ** and should not be accessed by other modules. + ** Elements above, except pCache, are public. All that follow are + ** private to pcache.c and should not be accessed by other modules. + ** pCache is grouped with the public elements for efficiency. */ i16 nRef; /* Number of users of this page */ - PCache *pCache; /* Cache that owns this page */ - PgHdr *pDirtyNext; /* Next element in list of dirty pages */ PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ + /* NB: pDirtyNext and pDirtyPrev are undefined if the + ** PgHdr object is not dirty */ }; /* Bit values for PgHdr.flags */ @@ -13394,7 +16061,7 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *, int); SQLITE_PRIVATE int sqlite3PcacheSize(void); /* One release per successful fetch. Page is pinned until released. -** Reference counted. +** Reference counted. */ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag); SQLITE_PRIVATE int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**); @@ -13438,7 +16105,7 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*); #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* Iterate through all dirty pages currently stored in the cache. This -** interface is only available if SQLITE_CHECK_PAGES is defined when the +** interface is only available if SQLITE_CHECK_PAGES is defined when the ** library is built. */ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); @@ -13488,6 +16155,10 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void); /* Number of dirty pages as a percentage of the configured cache size */ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); +#ifdef SQLITE_DIRECT_OVERFLOW_READ +SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache); +#endif + #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ @@ -13590,6 +16261,12 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); # define SET_FULLSYNC(x,y) #endif +/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h +*/ +#ifndef SQLITE_MAX_PATHLEN +# define SQLITE_MAX_PATHLEN FILENAME_MAX +#endif + /* ** The default size of a disk sector */ @@ -13609,10 +16286,10 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); ** 2006-10-31: The default prefix used to be "sqlite_". But then ** Mcafee started using SQLite in their anti-virus product and it ** started putting files with the "sqlite" name in the c:/temp folder. -** This annoyed many windows users. Those users would then do a +** This annoyed many windows users. Those users would then do a ** Google search for "sqlite", find the telephone numbers of the ** developers and call to wake them up at night and complain. -** For this reason, the default name prefix is changed to be "sqlite" +** For this reason, the default name prefix is changed to be "sqlite" ** spelled backwards. So the temp files are still identified, but ** anybody smart enough to figure out the code is also likely smart ** enough to know that calling the developer will not help get rid @@ -13653,9 +16330,9 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); ** UnlockFile(). ** ** LockFile() prevents not just writing but also reading by other processes. -** A SHARED_LOCK is obtained by locking a single randomly-chosen -** byte out of a specific range of bytes. The lock byte is obtained at -** random so two separate readers can probably access the file at the +** A SHARED_LOCK is obtained by locking a single randomly-chosen +** byte out of a specific range of bytes. The lock byte is obtained at +** random so two separate readers can probably access the file at the ** same time, unless they are unlucky and choose the same lock byte. ** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range. ** There can only be one writer. A RESERVED_LOCK is obtained by locking @@ -13674,7 +16351,7 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); ** The following #defines specify the range of bytes used for locking. ** SHARED_SIZE is the number of bytes available in the pool from which ** a random byte is selected for a shared lock. The pool of bytes for -** shared locks begins at SHARED_FIRST. +** shared locks begins at SHARED_FIRST. ** ** The same locking strategy and ** byte ranges are used for Unix. This leaves open the possibility of having @@ -13690,7 +16367,7 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); ** that all locks will fit on a single page even at the minimum page size. ** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE ** is set high so that we don't have to allocate an unused page except -** for very large databases. But one should test the page skipping logic +** for very large databases. But one should test the page skipping logic ** by setting PENDING_BYTE low and running the entire regression suite. ** ** Changing the value of PENDING_BYTE results in a subtly incompatible @@ -13714,8 +16391,8 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*); */ SQLITE_PRIVATE int sqlite3OsInit(void); -/* -** Functions for accessing sqlite3_file methods +/* +** Functions for accessing sqlite3_file methods */ SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*); SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); @@ -13731,16 +16408,18 @@ SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*); #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); +#ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int); SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int); +#endif /* SQLITE_OMIT_WAL */ SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *); -/* -** Functions for accessing sqlite3_vfs methods +/* +** Functions for accessing sqlite3_vfs methods */ SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int); @@ -13758,7 +16437,7 @@ SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*); SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); /* -** Convenience functions for opening and closing files using +** Convenience functions for opening and closing files using ** sqlite3_malloc() to obtain space for the file-handle structure. */ SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); @@ -13828,9 +16507,9 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *); */ #define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) #define sqlite3_mutex_free(X) -#define sqlite3_mutex_enter(X) +#define sqlite3_mutex_enter(X) #define sqlite3_mutex_try(X) SQLITE_OK -#define sqlite3_mutex_leave(X) +#define sqlite3_mutex_leave(X) #define sqlite3_mutex_held(X) ((void)(X),1) #define sqlite3_mutex_notheld(X) ((void)(X),1) #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) @@ -13839,6 +16518,7 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *); #define MUTEX_LOGIC(X) #else #define MUTEX_LOGIC(X) X +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); #endif /* defined(SQLITE_MUTEX_OMIT) */ /************** End of mutex.h ***********************************************/ @@ -13869,7 +16549,7 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *); ** and the one-based values are used internally. */ #ifndef SQLITE_DEFAULT_SYNCHRONOUS -# define SQLITE_DEFAULT_SYNCHRONOUS (PAGER_SYNCHRONOUS_FULL-1) +# define SQLITE_DEFAULT_SYNCHRONOUS 2 #endif #ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS # define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS @@ -13942,7 +16622,7 @@ struct Schema { */ #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ -#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ +#define DB_ResetWanted 0x0008 /* Reset the schema when nSchemaLock==0 */ /* ** The number of different kinds of things that can be limited @@ -13969,15 +16649,47 @@ struct Schema { ** is shared by multiple database connections. Therefore, while parsing ** schema information, the Lookaside.bEnabled flag is cleared so that ** lookaside allocations are not used to construct the schema objects. +** +** New lookaside allocations are only allowed if bDisable==0. When +** bDisable is greater than zero, sz is set to zero which effectively +** disables lookaside without adding a new test for the bDisable flag +** in a performance-critical path. sz should be set by to szTrue whenever +** bDisable changes back to zero. +** +** Lookaside buffers are initially held on the pInit list. As they are +** used and freed, they are added back to the pFree list. New allocations +** come off of pFree first, then pInit as a fallback. This dual-list +** allows use to compute a high-water mark - the maximum number of allocations +** outstanding at any point in the past - by subtracting the number of +** allocations on the pInit list from the total number of allocations. +** +** Enhancement on 2019-12-12: Two-size-lookaside +** The default lookaside configuration is 100 slots of 1200 bytes each. +** The larger slot sizes are important for performance, but they waste +** a lot of space, as most lookaside allocations are less than 128 bytes. +** The two-size-lookaside enhancement breaks up the lookaside allocation +** into two pools: One of 128-byte slots and the other of the default size +** (1200-byte) slots. Allocations are filled from the small-pool first, +** failing over to the full-size pool if that does not work. Thus more +** lookaside slots are available while also using less memory. +** This enhancement can be omitted by compiling with +** SQLITE_OMIT_TWOSIZE_LOOKASIDE. */ struct Lookaside { u32 bDisable; /* Only operate the lookaside when zero */ u16 sz; /* Size of each buffer in bytes */ + u16 szTrue; /* True value of sz, even if disabled */ u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */ - int nOut; /* Number of buffers currently checked out */ - int mxOut; /* Highwater mark for nOut */ - int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ + u32 nSlot; /* Number of lookaside slots allocated */ + u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ + LookasideSlot *pInit; /* List of buffers not previously used */ LookasideSlot *pFree; /* List of available buffers */ +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + LookasideSlot *pSmallInit; /* List of small buffers not prediously used */ + LookasideSlot *pSmallFree; /* List of available small buffers */ + void *pMiddle; /* First byte past end of full-size buffers and + ** the first byte of LOOKASIDE_SMALL buffers */ +#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ void *pStart; /* First byte of available memory space */ void *pEnd; /* First byte past end of available space */ }; @@ -13985,17 +16697,30 @@ struct LookasideSlot { LookasideSlot *pNext; /* Next buffer in the list of free buffers */ }; +#define DisableLookaside db->lookaside.bDisable++;db->lookaside.sz=0 +#define EnableLookaside db->lookaside.bDisable--;\ + db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue + +/* Size of the smaller allocations in two-size lookside */ +#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE +# define LOOKASIDE_SMALL 0 +#else +# define LOOKASIDE_SMALL 128 +#endif + /* ** A hash table for built-in function definitions. (Application-defined ** functions use a regular table table from hash.h.) ** ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. -** Collisions are on the FuncDef.u.pHash chain. +** Collisions are on the FuncDef.u.pHash chain. Use the SQLITE_FUNC_HASH() +** macro to compute a hash on the function name. */ #define SQLITE_FUNC_HASH_SZ 23 struct FuncDefHash { FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ }; +#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) #ifdef SQLITE_USER_AUTHENTICATION /* @@ -14039,11 +16764,19 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing ** in the style of sqlite3_trace() */ -#define SQLITE_TRACE_LEGACY 0x80 +#define SQLITE_TRACE_LEGACY 0x40 /* Use the legacy xTrace */ +#define SQLITE_TRACE_XPROFILE 0x80 /* Use the legacy xProfile */ #else -#define SQLITE_TRACE_LEGACY 0 +#define SQLITE_TRACE_LEGACY 0 +#define SQLITE_TRACE_XPROFILE 0 #endif /* SQLITE_OMIT_DEPRECATED */ +#define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */ +/* +** Maximum number of sqlite3.aDb[] entries. This is the number of attached +** databases plus 2 for "main" and "temp". +*/ +#define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2) /* ** Each database connection is an instance of the following structure. @@ -14051,18 +16784,21 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**); struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ struct Vdbe *pVdbe; /* List of active virtual machines */ - CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ + CollSeq *pDfltColl; /* BINARY collseq for the database encoding */ sqlite3_mutex *mutex; /* Connection mutex */ Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ - int flags; /* Miscellaneous flags. See below */ + u32 mDbFlags; /* flags recording internal state */ + u64 flags; /* flags settable by pragmas. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ + u32 nSchemaLock; /* Do not reset the schema when non-zero */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ + int errByteOffset; /* Byte offset of error in SQL statement */ int errMask; /* & result codes with this before returning */ int iSysErrno; /* Errno value from last system error */ - u16 dbOptFlags; /* Flags to enable/disable optimizations */ + u32 dbOptFlags; /* Flags to enable/disable optimizations */ u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ @@ -14074,19 +16810,22 @@ struct sqlite3 { u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ u8 mTrace; /* zero or more SQLITE_TRACE flags */ - u8 skipBtreeMutex; /* True if no shared-cache backends */ + u8 noSharedCache; /* True if no shared-cache backends */ + u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ + u8 eOpenState; /* Current condition of the connection */ int nextPagesize; /* Pagesize after VACUUM if >0 */ - u32 magic; /* Magic number for detect library misuse */ - int nChange; /* Value returned by sqlite3_changes() */ - int nTotalChange; /* Value returned by sqlite3_total_changes() */ + i64 nChange; /* Value returned by sqlite3_changes() */ + i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ - int newTnum; /* Rootpage of table being initialized */ + Pgno newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ - u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ - u8 imposterTable; /* Building an imposter table */ + unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */ + unsigned imposterTable : 1; /* Building an imposter table */ + unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */ + const char **azInit; /* "type", "name", and "tbl_name" columns */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ @@ -14095,16 +16834,25 @@ struct sqlite3 { int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ - int (*xTrace)(u32,void*,void*,void*); /* Trace function */ - void *pTraceArg; /* Argument to the trace function */ + union { + void (*xLegacy)(void*,const char*); /* mTrace==SQLITE_TRACE_LEGACY */ + int (*xV2)(u32,void*,void*,void*); /* All other mTrace values */ + } trace; + void *pTraceArg; /* Argument to the trace function */ +#ifndef SQLITE_OMIT_DEPRECATED void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ +#endif void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ void *pRollbackArg; /* Argument to xRollbackCallback() */ void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); + void *pAutovacPagesArg; /* Client argument to autovac_pages */ + void (*xAutovacDestr)(void*); /* Destructor for pAutovacPAgesArg */ + unsigned int (*xAutovacPages)(void*,const char*,u32,u32,u32); + Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ @@ -14139,13 +16887,14 @@ struct sqlite3 { Hash aModule; /* populated by sqlite3_create_module() */ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ - VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ + VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif Hash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ + int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ @@ -14153,7 +16902,7 @@ struct sqlite3 { i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY - /* The following variables are all protected by the STATIC_MASTER + /* The following variables are all protected by the STATIC_MAIN ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** ** When X.pUnlockConnection==Y, that means that X is waiting for Y to @@ -14180,6 +16929,13 @@ struct sqlite3 { #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) +/* +** A u64 constant where the lower 32 bits are all zeros. Only the +** upper 32 bits are included in the argument. Necessary because some +** C-compilers still do not accept LL integer literals. +*/ +#define HI(X) ((u64)(X)<<32) + /* ** Possible values for the sqlite3.flags. ** @@ -14188,62 +16944,96 @@ struct sqlite3 { ** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC ** SQLITE_CacheSpill == PAGER_CACHE_SPILL */ -#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */ -#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */ +#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_SCHEMA */ +#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */ #define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */ #define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */ #define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */ #define SQLITE_ShortColNames 0x00000040 /* Show short columns names */ -#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */ - /* DELETE, or UPDATE and return */ - /* the count using a callback. */ +#define SQLITE_TrustedSchema 0x00000080 /* Allow unsafe functions and + ** vtabs in the schema definition */ #define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */ /* result set is empty */ -#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ -#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ -#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */ -#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ -#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */ -#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ -#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */ -#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */ -#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */ -#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */ -#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */ -#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */ -#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */ -#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */ -#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */ -#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */ -#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */ -#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */ -#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */ -#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */ -#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */ -#define SQLITE_NoCkptOnClose 0x80000000 /* No checkpoint on close()/DETACH */ +#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */ +#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */ +#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */ +#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */ +#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */ +#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */ +#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */ +#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */ +#define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */ +#define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */ +#define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */ +#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */ +#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */ +#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ +#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/ +#define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ +#define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ +#define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ +#define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ +#define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */ +#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/ +#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/ +#define SQLITE_EnableView 0x80000000 /* Enable the use of views */ +#define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */ + /* DELETE, or UPDATE and return */ + /* the count using a callback. */ +#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */ +/* Flags used only if debugging */ +#ifdef SQLITE_DEBUG +#define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */ +#define SQLITE_VdbeTrace HI(0x0400000) /* True to trace VDBE execution */ +#define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */ +#define SQLITE_VdbeEQP HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_ParserTrace HI(0x2000000) /* PRAGMA parser_trace=ON */ +#endif + +/* +** Allowed values for sqlite3.mDbFlags +*/ +#define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */ +#define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ +#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ +#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */ +#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */ +#define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */ +#define DBFLAG_EncodingFixed 0x0040 /* No longer possible to change enc. */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ -#define SQLITE_QueryFlattener 0x0001 /* Query flattening */ -#define SQLITE_ColumnCache 0x0002 /* Column cache */ -#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ -#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ -/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */ -#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ -#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ -#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ -#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ -#define SQLITE_Transitive 0x0200 /* Transitive constraints */ -#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ -#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ -#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */ -#define SQLITE_AllOpts 0xffff /* All optimizations */ +#define SQLITE_QueryFlattener 0x00000001 /* Query flattening */ +#define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */ +#define SQLITE_GroupByOrder 0x00000004 /* GROUPBY cover of ORDERBY */ +#define SQLITE_FactorOutConst 0x00000008 /* Constant factoring */ +#define SQLITE_DistinctOpt 0x00000010 /* DISTINCT using indexes */ +#define SQLITE_CoverIdxScan 0x00000020 /* Covering index scans */ +#define SQLITE_OrderByIdxJoin 0x00000040 /* ORDER BY of joins via index */ +#define SQLITE_Transitive 0x00000080 /* Transitive constraints */ +#define SQLITE_OmitNoopJoin 0x00000100 /* Omit unused tables in joins */ +#define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */ +#define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */ +#define SQLITE_Stat4 0x00000800 /* Use STAT4 data */ + /* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */ +#define SQLITE_PushDown 0x00001000 /* The push-down optimization */ +#define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */ +#define SQLITE_SkipScan 0x00004000 /* Skip-scans */ +#define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */ +#define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */ +#define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */ +#define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */ + /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */ +#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */ +#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */ +#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */ +#define SQLITE_AllOpts 0xffffffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. @@ -14257,17 +17047,16 @@ struct sqlite3 { */ #define ConstFactorOk(P) ((P)->okConstFactor) -/* -** Possible values for the sqlite.magic field. -** The numbers are obtained at random and have no special meaning, other -** than being distinct from one another. +/* Possible values for the sqlite3.eOpenState field. +** The numbers are randomly selected such that a minimum of three bits must +** change to convert any number to another or to zero */ -#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ -#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ -#define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */ -#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ -#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ -#define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* Close with last statement close */ +#define SQLITE_STATE_OPEN 0x76 /* Database is open */ +#define SQLITE_STATE_CLOSED 0xce /* Database is closed */ +#define SQLITE_STATE_SICK 0xba /* Error and awaiting close */ +#define SQLITE_STATE_BUSY 0x6d /* Database currently in use */ +#define SQLITE_STATE_ERROR 0xd5 /* An SQLITE_MISUSE error occurred */ +#define SQLITE_STATE_ZOMBIE 0xa7 /* Close with last statement close */ /* ** Each SQL function is defined by an instance of the following @@ -14281,16 +17070,18 @@ struct sqlite3 { */ struct FuncDef { i8 nArg; /* Number of arguments. -1 means unlimited */ - u16 funcFlags; /* Some combination of SQLITE_FUNC_* */ + u32 funcFlags; /* Some combination of SQLITE_FUNC_* */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */ void (*xFinalize)(sqlite3_context*); /* Agg finalizer */ + void (*xValue)(sqlite3_context*); /* Current agg value */ + void (*xInverse)(sqlite3_context*,int,sqlite3_value**); /* inverse agg-step */ const char *zName; /* SQL name of the function. */ union { FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ - } u; + } u; /* pHash if SQLITE_FUNC_BUILTIN, pDestructor otherwise */ }; /* @@ -14320,10 +17111,13 @@ struct FuncDestructor { ** are assert() statements in the code to verify this. ** ** Value constraints (enforced via assert()): -** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg -** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG -** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG -** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API +** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg +** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd +** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG +** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG +** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API +** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API +** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS ** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ @@ -14334,13 +17128,31 @@ struct FuncDestructor { #define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */ #define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */ #define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */ -#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */ +/* 0x0200 -- available for reuse */ #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */ #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ #define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a ** single query - might change over time */ -#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */ +#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */ +#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */ +#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ +#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ +#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */ +#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */ +#define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */ +#define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */ +#define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */ +#define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */ + +/* Identifier numbers for each in-line function */ +#define INLINEFUNC_coalesce 0 +#define INLINEFUNC_implies_nonnull_row 1 +#define INLINEFUNC_expr_implies_expr 2 +#define INLINEFUNC_expr_compare 3 +#define INLINEFUNC_affinity 4 +#define INLINEFUNC_iif 5 +#define INLINEFUNC_unlikely 99 /* Default case */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -14356,11 +17168,37 @@ struct FuncDestructor { ** VFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag. ** +** SFUNCTION(zName, nArg, iArg, bNC, xFunc) +** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and +** adds the SQLITE_DIRECTONLY flag. +** +** INLINE_FUNC(zName, nArg, iFuncId, mFlags) +** zName is the name of a function that is implemented by in-line +** byte code rather than by the usual callbacks. The iFuncId +** parameter determines the function id. The mFlags parameter is +** optional SQLITE_FUNC_ flags for this function. +** +** TEST_FUNC(zName, nArg, iFuncId, mFlags) +** zName is the name of a test-only function implemented by in-line +** byte code rather than by the usual callbacks. The iFuncId +** parameter determines the function id. The mFlags parameter is +** optional SQLITE_FUNC_ flags for this function. +** ** DFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and ** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions ** and functions like sqlite_version() that can change, but not during -** a single query. +** a single query. The iArg is ignored. The user-data is always set +** to a NULL pointer. The bNC parameter is not used. +** +** MFUNCTION(zName, nArg, xPtr, xFunc) +** For math-library functions. xPtr is an arbitrary pointer. +** +** PURE_DATE(zName, nArg, iArg, bNC, xFunc) +** Used for "pure" date/time functions, this macro is like DFUNCTION +** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is +** ignored and the user-data for these functions is set to an +** arbitrary non-NULL pointer. The bNC parameter is not used. ** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) ** Used to create an aggregate function definition implemented by @@ -14368,6 +17206,12 @@ struct FuncDestructor { ** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** +** WAGGREGATE(zName, nArg, iArg, xStep, xFinal, xValue, xInverse) +** Used to create an aggregate function definition implemented by +** the C functions xStep and xFinal. The first four parameters +** are interpreted in the same way as the first 4 parameters to +** FUNCTION(). +** ** LIKEFUNC(zName, nArg, pArg, flags) ** Used to create a scalar function definition of a function zName ** that accepts nArg arguments and is implemented by a call to C @@ -14377,29 +17221,57 @@ struct FuncDestructor { ** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } +#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } +#define MFUNCTION(zName, nArg, xPtr, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ + xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } +#define JFUNCTION(zName, nArg, iArg, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } +#define INLINE_FUNC(zName, nArg, iArg, mFlags) \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ + SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } +#define TEST_FUNC(zName, nArg, iArg, mFlags) \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \ + SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ + SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ + 0, 0, xFunc, 0, 0, 0, #zName, {0} } +#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} } #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ - {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} } + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ - pArg, 0, xFunc, 0, #zName, } + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + pArg, 0, xFunc, 0, 0, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ - (void *)arg, 0, likeFunc, 0, #zName, {0} } -#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ - {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} -#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ - {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}} + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ + (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } +#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ + {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \ + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} +#define INTERNAL_FUNCTION(zName, nArg, xFunc) \ + {nArg, SQLITE_FUNC_BUILTIN|\ + SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \ + 0, 0, xFunc, 0, 0, 0, #zName, {0} } + /* ** All current savepoints are stored in a linked list starting at @@ -14431,30 +17303,83 @@ struct Savepoint { struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ + int nRefModule; /* Number of pointers to this object */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ Table *pEpoTab; /* Eponymous table for this module */ }; /* -** information about each column of an SQL table is held in an instance -** of this structure. +** Information about each column of an SQL table is held in an instance +** of the Column structure, in the Table.aCol[] array. +** +** Definitions: +** +** "table column index" This is the index of the column in the +** Table.aCol[] array, and also the index of +** the column in the original CREATE TABLE stmt. +** +** "storage column index" This is the index of the column in the +** record BLOB generated by the OP_MakeRecord +** opcode. The storage column index is less than +** or equal to the table column index. It is +** equal if and only if there are no VIRTUAL +** columns to the left. +** +** Notes on zCnName: +** The zCnName field stores the name of the column, the datatype of the +** column, and the collating sequence for the column, in that order, all in +** a single allocation. Each string is 0x00 terminated. The datatype +** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the +** collating sequence name is only included if the COLFLAG_HASCOLL bit is +** set. */ struct Column { - char *zName; /* Name of this column, \000, then the type */ - Expr *pDflt; /* Default value of this column */ - char *zColl; /* Collating sequence. If NULL, use the default */ - u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ - char affinity; /* One of the SQLITE_AFF_... values */ - u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ - u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */ + char *zCnName; /* Name of this column */ + unsigned notNull :4; /* An OE_ code for handling a NOT NULL constraint */ + unsigned eCType :4; /* One of the standard types */ + char affinity; /* One of the SQLITE_AFF_... values */ + u8 szEst; /* Est size of value in this column. sizeof(INT)==1 */ + u8 hName; /* Column name hash for faster lookup */ + u16 iDflt; /* 1-based index of DEFAULT. 0 means "none" */ + u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ }; -/* Allowed values for Column.colFlags: -*/ -#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ -#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ -#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ +/* Allowed values for Column.eCType. +** +** Values must match entries in the global constant arrays +** sqlite3StdTypeLen[] and sqlite3StdType[]. Each value is one more +** than the offset into these arrays for the corresponding name. +** Adjust the SQLITE_N_STDTYPE value if adding or removing entries. +*/ +#define COLTYPE_CUSTOM 0 /* Type appended to zName */ +#define COLTYPE_ANY 1 +#define COLTYPE_BLOB 2 +#define COLTYPE_INT 3 +#define COLTYPE_INTEGER 4 +#define COLTYPE_REAL 5 +#define COLTYPE_TEXT 6 +#define SQLITE_N_STDTYPE 6 /* Number of standard types */ + +/* Allowed values for Column.colFlags. +** +** Constraints: +** TF_HasVirtual == COLFLAG_VIRTUAL +** TF_HasStored == COLFLAG_STORED +** TF_HasHidden == COLFLAG_HIDDEN +*/ +#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ +#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ +#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ +#define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */ +#define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ +#define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ +#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ +#define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */ +#define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */ +#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */ +#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ +#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ /* ** A "Collating Sequence" is defined by an instance of the following @@ -14494,11 +17419,12 @@ struct CollSeq { ** Note also that the numeric types are grouped together so that testing ** for a numeric type is a single comparison. And the BLOB type is first. */ -#define SQLITE_AFF_BLOB 'A' -#define SQLITE_AFF_TEXT 'B' -#define SQLITE_AFF_NUMERIC 'C' -#define SQLITE_AFF_INTEGER 'D' -#define SQLITE_AFF_REAL 'E' +#define SQLITE_AFF_NONE 0x40 /* '@' */ +#define SQLITE_AFF_BLOB 0x41 /* 'A' */ +#define SQLITE_AFF_TEXT 0x42 /* 'B' */ +#define SQLITE_AFF_NUMERIC 0x43 /* 'C' */ +#define SQLITE_AFF_INTEGER 0x44 /* 'D' */ +#define SQLITE_AFF_REAL 0x45 /* 'E' */ #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) @@ -14517,9 +17443,7 @@ struct CollSeq { ** operator is NULL. It is added to certain comparison operators to ** prove that the operands are always NOT NULL. */ -#define SQLITE_KEEPNULL 0x08 /* Used by vector == or <> */ #define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ -#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ #define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */ @@ -14571,45 +17495,59 @@ struct VTable { sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ + u8 eVtabRisk; /* Riskiness of allowing hacker access */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; +/* Allowed values for VTable.eVtabRisk +*/ +#define SQLITE_VTABRISK_Low 0 +#define SQLITE_VTABRISK_Normal 1 +#define SQLITE_VTABRISK_High 2 + /* -** The schema for each SQL table and view is represented in memory -** by an instance of the following structure. +** The schema for each SQL table, virtual table, and view is represented +** in memory by an instance of the following structure. */ struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ - Select *pSelect; /* NULL for tables. Points to definition if a view. */ - FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ ExprList *pCheck; /* All CHECK constraints */ /* ... also used as column name list in a VIEW */ - int tnum; /* Root BTree page for this table */ + Pgno tnum; /* Root BTree page for this table */ u32 nTabRef; /* Number of pointers to this Table */ + u32 tabFlags; /* Mask of TF_* values */ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ + i16 nNVCol; /* Number of columns that are not VIRTUAL */ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT LogEst costMult; /* Cost multiplier for using this table */ #endif - u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ -#ifndef SQLITE_OMIT_ALTERTABLE - int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ -#endif -#ifndef SQLITE_OMIT_VIRTUALTABLE - int nModuleArg; /* Number of arguments to the module */ - char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */ - VTable *pVTable; /* List of VTable objects. */ -#endif - Trigger *pTrigger; /* List of triggers stored in pSchema */ + u8 eTabType; /* 0: normal, 1: virtual, 2: view */ + union { + struct { /* Used by ordinary tables: */ + int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ + FKey *pFKey; /* Linked list of all foreign keys in this table */ + ExprList *pDfltList; /* DEFAULT clauses on various columns. + ** Or the AS clause for generated columns. */ + } tab; + struct { /* Used by views: */ + Select *pSelect; /* View definition */ + } view; + struct { /* Used by virtual tables only: */ + int nArg; /* Number of arguments to the module */ + char **azArg; /* 0: module 1: schema 2: vtab name 3...: args */ + VTable *p; /* List of VTable objects. */ + } vtab; + } u; + Trigger *pTrigger; /* List of triggers on this object */ Schema *pSchema; /* Schema that contains this table */ - Table *pNextZombie; /* Next on the Parse.pZombieTab list */ }; /* @@ -14619,17 +17557,43 @@ struct Table { ** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING ** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, ** the TF_OOOHidden attribute would apply in this case. Such tables require -** special handling during INSERT processing. +** special handling during INSERT processing. The "OOO" means "Out Of Order". +** +** Constraints: +** +** TF_HasVirtual == COLFLAG_VIRTUAL +** TF_HasStored == COLFLAG_STORED +** TF_HasHidden == COLFLAG_HIDDEN */ -#define TF_Readonly 0x01 /* Read-only system table */ -#define TF_Ephemeral 0x02 /* An ephemeral table */ -#define TF_HasPrimaryKey 0x04 /* Table has a primary key */ -#define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ -#define TF_Virtual 0x10 /* Is a virtual table */ -#define TF_WithoutRowid 0x20 /* No rowid. PRIMARY KEY is the key */ -#define TF_NoVisibleRowid 0x40 /* No user-visible "rowid" column */ -#define TF_OOOHidden 0x80 /* Out-of-Order hidden columns */ +#define TF_Readonly 0x00000001 /* Read-only system table */ +#define TF_HasHidden 0x00000002 /* Has one or more hidden columns */ +#define TF_HasPrimaryKey 0x00000004 /* Table has a primary key */ +#define TF_Autoincrement 0x00000008 /* Integer primary key is autoincrement */ +#define TF_HasStat1 0x00000010 /* nRowLogEst set from sqlite_stat1 */ +#define TF_HasVirtual 0x00000020 /* Has one or more VIRTUAL columns */ +#define TF_HasStored 0x00000040 /* Has one or more STORED columns */ +#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */ +#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */ +#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by + ** Index.aiRowLogEst[] values */ +#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */ +#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */ +#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */ +#define TF_Shadow 0x00001000 /* True for a shadow table */ +#define TF_HasStat4 0x00002000 /* STAT4 info available for this table */ +#define TF_Ephemeral 0x00004000 /* An ephemeral table */ +#define TF_Eponymous 0x00008000 /* An eponymous virtual table */ +#define TF_Strict 0x00010000 /* STRICT mode */ +/* +** Allowed values for Table.eTabType +*/ +#define TABTYP_NORM 0 /* Ordinary table */ +#define TABTYP_VTAB 1 /* Virtual table */ +#define TABTYP_VIEW 2 /* A view */ + +#define IsView(X) ((X)->eTabType==TABTYP_VIEW) +#define IsOrdinaryTable(X) ((X)->eTabType==TABTYP_NORM) /* ** Test to see whether or not a table is a virtual table. This is @@ -14637,9 +17601,12 @@ struct Table { ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE -# define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0) +# define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB) +# define ExprIsVtab(X) \ + ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->eTabType==TABTYP_VTAB) #else # define IsVirtual(X) 0 +# define ExprIsVtab(X) 0 #endif /* @@ -14723,16 +17690,22 @@ struct FKey { ** is returned. REPLACE means that preexisting database rows that caused ** a UNIQUE constraint violation are removed so that the new insert or ** update can proceed. Processing continues and no error is reported. +** UPDATE applies to insert operations only and means that the insert +** is omitted and the DO UPDATE clause of an upsert is run instead. ** -** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys. +** RESTRICT, SETNULL, SETDFLT, and CASCADE actions apply only to foreign keys. ** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the ** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign -** key is set to NULL. CASCADE means that a DELETE or UPDATE of the +** key is set to NULL. SETDFLT means that the foreign key is set +** to its default value. CASCADE means that a DELETE or UPDATE of the ** referenced table row is propagated into the row that holds the ** foreign key. ** +** The OE_Default value is a place holder that means to use whatever +** conflict resolution algorthm is required from context. +** ** The following symbolic values are used to record which type -** of action to take. +** of conflict resolution action to take. */ #define OE_None 0 /* There is no constraint to check */ #define OE_Rollback 1 /* Fail the operation and rollback the transaction */ @@ -14740,13 +17713,12 @@ struct FKey { #define OE_Fail 3 /* Stop the operation but leave all prior changes */ #define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ #define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ - -#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ -#define OE_SetNull 7 /* Set the foreign key value to NULL */ -#define OE_SetDflt 8 /* Set the foreign key value to its default */ -#define OE_Cascade 9 /* Cascade the changes */ - -#define OE_Default 10 /* Do whatever the default action is */ +#define OE_Update 6 /* Process as a DO UPDATE in an upsert */ +#define OE_Restrict 7 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ +#define OE_SetNull 8 /* Set the foreign key value to NULL */ +#define OE_SetDflt 9 /* Set the foreign key value to its default */ +#define OE_Cascade 10 /* Cascade the changes */ +#define OE_Default 11 /* Do whatever the default action is */ /* @@ -14761,13 +17733,19 @@ struct FKey { struct KeyInfo { u32 nRef; /* Number of references to this KeyInfo object */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ - u16 nField; /* Number of key columns in the index */ - u16 nXField; /* Number of columns beyond the key columns */ + u16 nKeyField; /* Number of key columns in the index */ + u16 nAllField; /* Total columns, including key plus others */ sqlite3 *db; /* The database connection */ - u8 *aSortOrder; /* Sort order for each column. */ + u8 *aSortFlags; /* Sort order for each column. */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; +/* +** Allowed bit values for entries in the KeyInfo.aSortFlags[] array. +*/ +#define KEYINFO_ORDER_DESC 0x01 /* DESC sort order */ +#define KEYINFO_ORDER_BIGNULL 0x02 /* NULL is larger than any other value */ + /* ** This object holds a record which has been parsed out into individual ** fields, for the purposes of doing a comparison. @@ -14809,8 +17787,8 @@ struct UnpackedRecord { u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */ - i8 r1; /* Value to return if (lhs > rhs) */ - i8 r2; /* Value to return if (rhs < lhs) */ + i8 r1; /* Value to return if (lhs < rhs) */ + i8 r2; /* Value to return if (lhs > rhs) */ u8 eqSeen; /* True if an equality comparison has been seen */ }; @@ -14842,7 +17820,7 @@ struct UnpackedRecord { ** element. ** ** While parsing a CREATE TABLE or CREATE INDEX statement in order to -** generate VDBE code (as opposed to parsing one read from an sqlite_master +** generate VDBE code (as opposed to parsing one read from an sqlite_schema ** table as part of parsing an existing database schema), transient instances ** of this structure may be created. In this case the Index.tnum variable is ** used to store the address of a VDBE instruction, not a database page @@ -14861,18 +17839,22 @@ struct Index { const char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ ExprList *aColExpr; /* Column expressions */ - int tnum; /* DB Page containing root of this index */ + Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Number of columns stored in the index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ - unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ + unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ + unsigned bNoQuery:1; /* Do not use this index to optimize queries */ + unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ + unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ +#ifdef SQLITE_ENABLE_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */ @@ -14880,6 +17862,7 @@ struct Index { tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */ tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */ #endif + Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */ }; /* @@ -14888,6 +17871,7 @@ struct Index { #define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */ #define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */ #define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */ +#define SQLITE_IDXTYPE_IPK 3 /* INTEGER PRIMARY KEY index */ /* Return true if index X is a PRIMARY KEY index */ #define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) @@ -14902,7 +17886,7 @@ struct Index { #define XN_EXPR (-2) /* Indexed column is an expression */ /* -** Each sample stored in the sqlite_stat3 table is represented in memory +** Each sample stored in the sqlite_stat4 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ @@ -14914,13 +17898,21 @@ struct IndexSample { tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ }; +/* +** Possible values to use within the flags argument to sqlite3GetToken(). +*/ +#define SQLITE_TOKEN_QUOTED 0x1 /* Token is a quoted identifier. */ +#define SQLITE_TOKEN_KEYWORD 0x2 /* Token is a keyword. */ + /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** -** Note if Token.z==0 then Token.dyn and Token.n are undefined and -** may contain random values. Do not make any assumptions about Token.dyn -** and Token.n when Token.z==0. +** The memory that "z" points to is owned by other objects. Take care +** that the owner of the "z" string does not deallocate the string before +** the Token goes out of scope! Very often, the "z" points to some place +** in the middle of the Parse.zSql text. But it might also point to a +** static string. */ struct Token { const char *z; /* Text of the token. Not NULL-terminated! */ @@ -14932,7 +17924,7 @@ struct Token { ** code for a SELECT that contains aggregate functions. ** ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a -** pointer to this structure. The Expr.iColumn field is the index in +** pointer to this structure. The Expr.iAgg field is the index in ** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate ** code for that node. ** @@ -14952,23 +17944,25 @@ struct AggInfo { ExprList *pGroupBy; /* The group by clause */ struct AggInfo_col { /* For each column used in source tables */ Table *pTab; /* Source table */ + Expr *pCExpr; /* The original expression */ int iTable; /* Cursor number of the source table */ - int iColumn; /* Column number within the source table */ - int iSorterColumn; /* Column number in the sorting index */ int iMem; /* Memory location that acts as accumulator */ - Expr *pExpr; /* The original expression */ + i16 iColumn; /* Column number within the source table */ + i16 iSorterColumn; /* Column number in the sorting index */ } *aCol; int nColumn; /* Number of used entries in aCol[] */ int nAccumulator; /* Number of columns that show through to the output. ** Additional columns are used only as parameters to ** aggregate functions */ struct AggInfo_func { /* For each aggregate function */ - Expr *pExpr; /* Expression encoding the function */ + Expr *pFExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iMem; /* Memory location that acts as accumulator */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ + int iDistAddr; /* Address of OP_OpenEphemeral */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ + u32 selId; /* Select to which this AggInfo belongs */ }; /* @@ -14978,10 +17972,10 @@ struct AggInfo { ** it uses less memory in the Expr object, which is a big memory user ** in systems with lots of prepared statements. And few applications ** need more than about 10 or 20 variables. But some extreme users want -** to have prepared statements with over 32767 variables, and for them +** to have prepared statements with over 32766 variables, and for them ** the option is available (at compile-time). */ -#if SQLITE_MAX_VARIABLE_NUMBER<=32767 +#if SQLITE_MAX_VARIABLE_NUMBER<32767 typedef i16 ynVar; #else typedef int ynVar; @@ -14998,10 +17992,10 @@ typedef int ynVar; ** tree. ** ** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, -** or TK_STRING), then Expr.token contains the text of the SQL literal. If -** the expression is a variable (TK_VARIABLE), then Expr.token contains the +** or TK_STRING), then Expr.u.zToken contains the text of the SQL literal. If +** the expression is a variable (TK_VARIABLE), then Expr.u.zToken contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), -** then Expr.token contains the name of the function. +** then Expr.u.zToken contains the name of the function. ** ** Expr.pRight and Expr.pLeft are the left and right subexpressions of a ** binary operator. Either or both may be NULL. @@ -15041,7 +18035,7 @@ typedef int ynVar; ** help reduce memory requirements, sometimes an Expr object will be ** truncated. And to reduce the number of memory allocations, sometimes ** two or more Expr objects will be stored in a single memory allocation, -** together with Expr.zToken strings. +** together with Expr.u.zToken strings. ** ** If the EP_Reduced and EP_TokenOnly flags are set when ** an Expr object is truncated. When EP_Reduced is set, then all @@ -15052,7 +18046,14 @@ typedef int ynVar; */ struct Expr { u8 op; /* Operation performed by this node */ - char affinity; /* The affinity of the column or 0 if not a column */ + char affExpr; /* affinity, or RAISE type */ + u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op + ** TK_COLUMN: the value of p5 for OP_Column + ** TK_AGG_FUNCTION: nesting depth + ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */ +#ifdef SQLITE_DEBUG + u8 vvaFlags; /* Verification flags. */ +#endif u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ @@ -15083,69 +18084,111 @@ struct Expr { ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old ** EP_Unlikely: 134217728 times likelihood + ** TK_IN: ephemerial table holding RHS + ** TK_SELECT_COLUMN: Number of columns on the LHS ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ - i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ - u8 op2; /* TK_REGISTER: original value of Expr.op - ** TK_COLUMN: the value of p5 for OP_Column - ** TK_AGG_FUNCTION: nesting depth */ + union { + int iRightJoinTable; /* If EP_FromJoin, the right table of the join */ + int iOfst; /* else: start of token from start of statement */ + } w; AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ - Table *pTab; /* Table for TK_COLUMN expressions. */ + union { + Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL + ** for a column of an index on an expression */ + Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */ + struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ + int iAddr; /* Subroutine entry address */ + int regReturn; /* Register used to hold return address */ + } sub; + } y; }; -/* -** The following are the meanings of bits in the Expr.flags field. -*/ -#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ -#define EP_Agg 0x000002 /* Contains one or more aggregate functions */ -#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */ -#define EP_Error 0x000008 /* Expression contains one or more errors */ -#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ -#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ -#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ -#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ -#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ -#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ -#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ -#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ -#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ -#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ -#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ -#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */ -#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ -#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ -#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ -#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ -#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ -#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ -#define EP_Alias 0x400000 /* Is an alias for a result set column */ -#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ - -/* -** Combinations of two or more EP_* flags -*/ -#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */ - -/* -** These macros can be used to test, set, or clear bits in the +/* The following are the meanings of bits in the Expr.flags field. +** Value restrictions: +** +** EP_Agg == NC_HasAgg == SF_HasAgg +** EP_Win == NC_HasWin +*/ +#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ +#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */ +#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ +#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ +#define EP_Agg 0x000010 /* Contains one or more aggregate functions */ +#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ +#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ +#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ +#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ +#define EP_Commuted 0x000200 /* Comparison operator has been commuted */ +#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ +#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ +#define EP_Skip 0x001000 /* Operator does not contribute to affinity */ +#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ +#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ +#define EP_Win 0x008000 /* Contains window functions */ +#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ +#define EP_IfNullRow 0x020000 /* The TK_IF_NULL_ROW opcode */ +#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ +#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ +#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ +#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ + /* 0x400000 // Available */ +#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ +#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ +#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */ +#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */ +#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */ +#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ +#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ +#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */ + /* 0x80000000 // Available */ + +/* The EP_Propagate mask is a set of properties that automatically propagate +** upwards into parent nodes. +*/ +#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) + +/* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ #define ExprHasProperty(E,P) (((E)->flags&(P))!=0) #define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) +#define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) +#define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) + +/* Macros used to ensure that the correct members of unions are accessed +** in Expr. +*/ +#define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0) +#define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0) +#define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0) +#define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0) +#define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0) +#define ExprUseYWin(E) (((E)->flags&EP_WinFunc)!=0) +#define ExprUseYSub(E) (((E)->flags&EP_Subrtn)!=0) + +/* Flags for use with Expr.vvaFlags +*/ +#define EP_NoReduce 0x01 /* Cannot EXPRDUP_REDUCE this Expr */ +#define EP_Immutable 0x02 /* Do not change this Expr node */ /* The ExprSetVVAProperty() macro is used for Verification, Validation, ** and Accreditation only. It works like ExprSetProperty() during VVA ** processes but is a no-op for delivery. */ #ifdef SQLITE_DEBUG -# define ExprSetVVAProperty(E,P) (E)->flags|=(P) +# define ExprSetVVAProperty(E,P) (E)->vvaFlags|=(P) +# define ExprHasVVAProperty(E,P) (((E)->vvaFlags&(P))!=0) +# define ExprClearVVAProperties(E) (E)->vvaFlags = 0 #else # define ExprSetVVAProperty(E,P) +# define ExprHasVVAProperty(E,P) 0 +# define ExprClearVVAProperties(E) #endif /* @@ -15163,6 +18206,18 @@ struct Expr { */ #define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */ +/* +** True if the expression passed as an argument was a function with +** an OVER() clause (a window function). +*/ +#ifdef SQLITE_OMIT_WINDOWFUNC +# define IsWindowFunc(p) 0 +#else +# define IsWindowFunc(p) ( \ + ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \ + ) +#endif + /* ** A list of expressions. Each expression may optionally have a ** name. An expr/name combination can be used in several ways, such @@ -15171,44 +18226,49 @@ struct Expr { ** also be used as the argument to a function, in which case the a.zName ** field is not used. ** -** By default the Expr.zSpan field holds a human-readable description of -** the expression that is used in the generation of error messages and -** column labels. In this case, Expr.zSpan is typically the text of a -** column expression as it exists in a SELECT statement. However, if -** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name -** of the result column in the form: DATABASE.TABLE.COLUMN. This later -** form is used for name resolution with nested FROM clauses. +** In order to try to keep memory usage down, the Expr.a.zEName field +** is used for multiple purposes: +** +** eEName Usage +** ---------- ------------------------- +** ENAME_NAME (1) the AS of result set column +** (2) COLUMN= of an UPDATE +** +** ENAME_TAB DB.TABLE.NAME used to resolve names +** of subqueries +** +** ENAME_SPAN Text of the original result set +** expression. */ struct ExprList { int nExpr; /* Number of expressions on the list */ + int nAlloc; /* Number of a[] slots allocated */ struct ExprList_item { /* For each expression in the list */ - Expr *pExpr; /* The list of expressions */ - char *zName; /* Token associated with this expression */ - char *zSpan; /* Original text of the expression */ - u8 sortOrder; /* 1 for DESC or 0 for ASC */ + Expr *pExpr; /* The parse tree for this expression */ + char *zEName; /* Token associated with this expression */ + u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */ + unsigned eEName :2; /* Meaning of zEName */ unsigned done :1; /* A flag to indicate when processing is finished */ - unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */ unsigned reusable :1; /* Constant expression is reusable */ + unsigned bSorterRef :1; /* Defer evaluation until after sorting */ + unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */ union { - struct { + struct { /* Used by any ExprList other than Parse.pConsExpr */ u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iAlias; /* Index into Parse.aAlias[] for zName */ } x; - int iConstExprReg; /* Register in which Expr value is cached */ + int iConstExprReg; /* Register in which Expr value is cached. Used only + ** by Parse.pConstExpr */ } u; - } *a; /* Alloc a power of two greater or equal to nExpr */ + } a[1]; /* One slot for each expression in the list */ }; /* -** An instance of this structure is used by the parser to record both -** the parse tree for an expression and the span of input text for an -** expression. +** Allowed values for Expr.a.eEName */ -struct ExprSpan { - Expr *pExpr; /* The expression parse tree */ - const char *zStart; /* First character of input text */ - const char *zEnd; /* One character past the end of input text */ -}; +#define ENAME_NAME 0 /* The AS clause of a result set */ +#define ENAME_SPAN 1 /* Complete text of the result set expression */ +#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */ /* ** An instance of this structure can hold a simple list of identifiers, @@ -15234,29 +18294,51 @@ struct IdList { }; /* -** The bitmask datatype defined below is used for various optimizations. -** -** Changing this from a 64-bit to a 32-bit type limits the number of -** tables in a join to 32 instead of 64. But it also reduces the size -** of the library by 738 bytes on ix86. -*/ -#ifdef SQLITE_BITMASK_TYPE - typedef SQLITE_BITMASK_TYPE Bitmask; -#else - typedef u64 Bitmask; -#endif - -/* -** The number of bits in a Bitmask. "BMS" means "BitMask Size". -*/ -#define BMS ((int)(sizeof(Bitmask)*8)) - -/* -** A bit in a Bitmask -*/ -#define MASKBIT(n) (((Bitmask)1)<<(n)) -#define MASKBIT32(n) (((unsigned int)1)<<(n)) -#define ALLBITS ((Bitmask)-1) +** The SrcItem object represents a single term in the FROM clause of a query. +** The SrcList object is mostly an array of SrcItems. +** +** Union member validity: +** +** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc +** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy +** u2.pIBIndex fg.isIndexedBy && !fg.isCte +** u2.pCteUse fg.isCte && !fg.isIndexedBy +*/ +struct SrcItem { + Schema *pSchema; /* Schema to which this item is fixed */ + char *zDatabase; /* Name of database holding this table */ + char *zName; /* Name of the table */ + char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ + Table *pTab; /* An SQL table corresponding to zName */ + Select *pSelect; /* A SELECT statement used in place of a table name */ + int addrFillSub; /* Address of subroutine to manifest a subquery */ + int regReturn; /* Register holding return address of addrFillSub */ + int regResult; /* Registers holding results of a co-routine */ + struct { + u8 jointype; /* Type of join between this table and the previous */ + unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ + unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ + unsigned isTabFunc :1; /* True if table-valued-function syntax */ + unsigned isCorrelated :1; /* True if sub-query is correlated */ + unsigned viaCoroutine :1; /* Implemented as a co-routine */ + unsigned isRecursive :1; /* True for recursive reference in WITH */ + unsigned fromDDL :1; /* Comes from sqlite_schema */ + unsigned isCte :1; /* This is a CTE */ + unsigned notCte :1; /* This item may not match a CTE */ + } fg; + int iCursor; /* The VDBE cursor number used to access this table */ + Expr *pOn; /* The ON clause of a join */ + IdList *pUsing; /* The USING clause of a join */ + Bitmask colUsed; /* Bit N (1<" clause */ + ExprList *pFuncArg; /* Arguments to table-valued-function */ + } u1; + union { + Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ + CteUse *pCteUse; /* CTE Usage info info fg.isCte is true */ + } u2; +}; /* ** The following structure describes the FROM clause of a SELECT statement. @@ -15280,38 +18362,7 @@ struct IdList { struct SrcList { int nSrc; /* Number of tables or subqueries in the FROM clause */ u32 nAlloc; /* Number of entries allocated in a[] below */ - struct SrcList_item { - Schema *pSchema; /* Schema to which this item is fixed */ - char *zDatabase; /* Name of database holding this table */ - char *zName; /* Name of the table */ - char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ - Table *pTab; /* An SQL table corresponding to zName */ - Select *pSelect; /* A SELECT statement used in place of a table name */ - int addrFillSub; /* Address of subroutine to manifest a subquery */ - int regReturn; /* Register holding return address of addrFillSub */ - int regResult; /* Registers holding results of a co-routine */ - struct { - u8 jointype; /* Type of join between this table and the previous */ - unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ - unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ - unsigned isTabFunc :1; /* True if table-valued-function syntax */ - unsigned isCorrelated :1; /* True if sub-query is correlated */ - unsigned viaCoroutine :1; /* Implemented as a co-routine */ - unsigned isRecursive :1; /* True for recursive reference in WITH */ - } fg; -#ifndef SQLITE_OMIT_EXPLAIN - u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ -#endif - int iCursor; /* The VDBE cursor number used to access this table */ - Expr *pOn; /* The ON clause of a join */ - IdList *pUsing; /* The USING clause of a join */ - Bitmask colUsed; /* Bit N (1<" clause */ - ExprList *pFuncArg; /* Arguments to table-valued-function */ - } u1; - Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ - } a[1]; /* One entry for each identifier on the list */ + SrcItem a[1]; /* One entry for each identifier on the list */ }; /* @@ -15345,9 +18396,9 @@ struct SrcList { #define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ -#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */ +#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ -#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */ + /* 0x1000 not currently used */ /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */ @@ -15383,40 +18434,93 @@ struct SrcList { struct NameContext { Parse *pParse; /* The parser */ SrcList *pSrcList; /* One or more tables used to resolve names */ - ExprList *pEList; /* Optional list of result-set columns */ - AggInfo *pAggInfo; /* Information about aggregates at this level */ + union { + ExprList *pEList; /* Optional list of result-set columns */ + AggInfo *pAggInfo; /* Information about aggregates at this level */ + Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */ + int iBaseReg; /* For TK_REGISTER when parsing RETURNING */ + } uNC; NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ - int nErr; /* Number of errors encountered while resolving names */ - u16 ncFlags; /* Zero or more NC_* flags defined below */ + int nNcErr; /* Number of errors encountered while resolving names */ + int ncFlags; /* Zero or more NC_* flags defined below */ + Select *pWinSelect; /* SELECT statement for any window functions */ }; /* ** Allowed values for the NameContext, ncFlags field. ** ** Value constraints (all checked via assert()): -** NC_HasAgg == SF_HasAgg -** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX -** -*/ -#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ -#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ -#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ -#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ -#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ -#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ -#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */ -#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ +** NC_HasAgg == SF_HasAgg == EP_Agg +** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** NC_OrderAgg == SF_OrderByReqd == SQLITE_FUNC_ANYORDER +** NC_HasWin == EP_Win +** +*/ +#define NC_AllowAgg 0x000001 /* Aggregate functions are allowed here */ +#define NC_PartIdx 0x000002 /* True if resolving a partial index WHERE */ +#define NC_IsCheck 0x000004 /* True if resolving a CHECK constraint */ +#define NC_GenCol 0x000008 /* True for a GENERATED ALWAYS AS clause */ +#define NC_HasAgg 0x000010 /* One or more aggregate functions seen */ +#define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */ +#define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ +#define NC_VarSelect 0x000040 /* A correlated subquery has been seen */ +#define NC_UEList 0x000080 /* True if uNC.pEList is used */ +#define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */ +#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */ +#define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */ +#define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */ +#define NC_Complex 0x002000 /* True if a function or subquery seen */ +#define NC_AllowWin 0x004000 /* Window functions are allowed here */ +#define NC_HasWin 0x008000 /* One or more window functions seen */ +#define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */ +#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */ +#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */ +#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */ +#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */ + +/* +** An instance of the following object describes a single ON CONFLICT +** clause in an upsert. +** +** The pUpsertTarget field is only set if the ON CONFLICT clause includes +** conflict-target clause. (In "ON CONFLICT(a,b)" the "(a,b)" is the +** conflict-target clause.) The pUpsertTargetWhere is the optional +** WHERE clause used to identify partial unique indexes. +** +** pUpsertSet is the list of column=expr terms of the UPDATE statement. +** The pUpsertSet field is NULL for a ON CONFLICT DO NOTHING. The +** pUpsertWhere is the WHERE clause for the UPDATE and is NULL if the +** WHERE clause is omitted. +*/ +struct Upsert { + ExprList *pUpsertTarget; /* Optional description of conflict target */ + Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */ + ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */ + Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ + Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ + u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */ + /* Above this point is the parse tree for the ON CONFLICT clauses. + ** The next group of fields stores intermediate data. */ + void *pToFree; /* Free memory when deleting the Upsert object */ + /* All fields above are owned by the Upsert object and must be freed + ** when the Upsert is destroyed. The fields below are used to transfer + ** information from the INSERT processing down into the UPDATE processing + ** while generating code. The fields below are owned by the INSERT + ** statement and will be freed by INSERT processing. */ + Index *pUpsertIdx; /* UNIQUE constraint specified by pUpsertTarget */ + SrcList *pUpsertSrc; /* Table to be updated */ + int regData; /* First register holding array of VALUES */ + int iDataCur; /* Index of the data cursor */ + int iIdxCur; /* Index of the first index cursor */ +}; /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. ** -** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. -** If there is a LIMIT clause, the parser sets nLimit to the value of the -** limit and nOffset to the value of the offset (or 0 if there is not -** offset). But later on, nLimit and nOffset become the memory locations -** in the VDBE that record the limit and offset counters. +** See the header comment on the computeLimitRegisters() routine for a +** detailed description of the meaning of the iLimit and iOffset fields. ** ** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. ** These addresses must be stored so that we can go back and fill in @@ -15429,15 +18533,13 @@ struct NameContext { ** sequences for the ORDER BY clause. */ struct Select { - ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ -#if SELECTTRACE_ENABLED - char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ -#endif + u32 selId; /* Unique identifier number for this SELECT */ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ + ExprList *pEList; /* The fields of the result */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ @@ -15446,8 +18548,11 @@ struct Select { Select *pPrior; /* Prior select in a compound select statement */ Select *pNext; /* Next select to the left in a compound */ Expr *pLimit; /* LIMIT expression. NULL means not used. */ - Expr *pOffset; /* OFFSET expression. NULL means not used. */ With *pWith; /* WITH clause attached to this select. Or NULL. */ +#ifndef SQLITE_OMIT_WINDOWFUNC + Window *pWin; /* List of window functions */ + Window *pWinDefn; /* List of named window definitions */ +#endif }; /* @@ -15455,29 +18560,39 @@ struct Select { ** "Select Flag". ** ** Value constraints (all checked via assert()) -** SF_HasAgg == NC_HasAgg -** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX -** SF_FixedLimit == WHERE_USE_LIMIT -*/ -#define SF_Distinct 0x00001 /* Output should be DISTINCT */ -#define SF_All 0x00002 /* Includes the ALL keyword */ -#define SF_Resolved 0x00004 /* Identifiers have been resolved */ -#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */ -#define SF_HasAgg 0x00010 /* Contains aggregate functions */ -#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */ -#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */ -#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */ -#define SF_Compound 0x00100 /* Part of a compound query */ -#define SF_Values 0x00200 /* Synthesized from VALUES clause */ -#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */ -#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */ -#define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */ -#define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */ -#define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */ -#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ -#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ -#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ - +** SF_HasAgg == NC_HasAgg +** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX +** SF_OrderByReqd == NC_OrderAgg == SQLITE_FUNC_ANYORDER +** SF_FixedLimit == WHERE_USE_LIMIT +*/ +#define SF_Distinct 0x0000001 /* Output should be DISTINCT */ +#define SF_All 0x0000002 /* Includes the ALL keyword */ +#define SF_Resolved 0x0000004 /* Identifiers have been resolved */ +#define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */ +#define SF_HasAgg 0x0000010 /* Contains aggregate functions */ +#define SF_UsesEphemeral 0x0000020 /* Uses the OpenEphemeral opcode */ +#define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */ +#define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */ +#define SF_Compound 0x0000100 /* Part of a compound query */ +#define SF_Values 0x0000200 /* Synthesized from VALUES clause */ +#define SF_MultiValue 0x0000400 /* Single VALUES term with multiple rows */ +#define SF_NestedFrom 0x0000800 /* Part of a parenthesized FROM clause */ +#define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */ +#define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */ +#define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */ +#define SF_MaybeConvert 0x0008000 /* Need convertCompoundSelectToSubquery() */ +#define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */ +#define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */ +#define SF_ComplexResult 0x0040000 /* Result contains subquery or function */ +#define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */ +#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ +#define SF_View 0x0200000 /* SELECT statement is a view */ +#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ +#define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ +#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */ +#define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ +#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ +#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ /* ** The results of a SELECT can be distributed in several ways, as defined @@ -15496,9 +18611,6 @@ struct Select { ** statements within triggers whose only purpose is ** the side-effects of functions. ** -** All of the above are free to ignore their ORDER BY clause. Those that -** follow must honor the ORDER BY clause. -** ** SRT_Output Generate a row of output (using the OP_ResultRow ** opcode) for each row in the result set. ** @@ -15542,18 +18654,31 @@ struct Select { ** SRT_DistQueue Store results in priority queue pDest->iSDParm only if ** the same record has never been stored before. The ** index at pDest->iSDParm+1 hold all prior stores. +** +** SRT_Upfrom Store results in the temporary table already opened by +** pDest->iSDParm. If (pDest->iSDParm<0), then the temp +** table is an intkey table - in this case the first +** column returned by the SELECT is used as the integer +** key. If (pDest->iSDParm>0), then the table is an index +** table. (pDest->iSDParm) is the number of key columns in +** each index record in this case. */ #define SRT_Union 1 /* Store result as keys in an index */ #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ -#define SRT_Fifo 5 /* Store result as data with an automatic rowid */ -#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */ +#define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */ +#define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */ + +/* The DISTINCT clause is ignored for all of the above. Not that +** IgnorableDistinct() implies IgnorableOrderby() */ +#define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue) + #define SRT_Queue 7 /* Store result in an queue */ -#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */ +#define SRT_Fifo 8 /* Store result as data with an automatic rowid */ /* The ORDER BY clause is ignored for all of the above */ -#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue) +#define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo) #define SRT_Output 9 /* Output each row of result */ #define SRT_Mem 10 /* Store result in a memory cell */ @@ -15561,17 +18686,19 @@ struct Select { #define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ #define SRT_Coroutine 13 /* Generate a single row of result */ #define SRT_Table 14 /* Store result as data with an automatic rowid */ +#define SRT_Upfrom 15 /* Store result as data with rowid */ /* ** An instance of this object describes where to put of the results of ** a SELECT statement. */ struct SelectDest { - u8 eDest; /* How to dispose of the results. On of SRT_* above. */ - char *zAffSdst; /* Affinity used when eDest==SRT_Set */ + u8 eDest; /* How to dispose of the results. One of SRT_* above. */ int iSDParm; /* A parameter used by the eDest disposal method */ + int iSDParm2; /* A second parameter for the eDest disposal method */ int iSdst; /* Base register where results are written */ int nSdst; /* Number of registers allocated */ + char *zAffSdst; /* Affinity used when eDest==SRT_Set */ ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */ }; @@ -15591,13 +18718,6 @@ struct AutoincInfo { int regCtr; /* Memory register holding the rowid counter */ }; -/* -** Size of the column cache -*/ -#ifndef SQLITE_N_COLCACHE -# define SQLITE_N_COLCACHE 10 -#endif - /* ** At least one instance of the following structure is created for each ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE @@ -15643,6 +18763,17 @@ struct TriggerPrg { # define DbMaskNonZero(M) (M)!=0 #endif +/* +** An instance of the ParseCleanup object specifies an operation that +** should be performed after parsing to deallocation resources obtained +** during the parse and which are no longer needed. +*/ +struct ParseCleanup { + ParseCleanup *pNext; /* Next cleanup task */ + void *pPtr; /* Pointer to object to deallocate */ + void (*xCleanup)(sqlite3*,void*); /* Deallocation routine */ +}; + /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to @@ -15673,19 +18804,20 @@ struct Parse { u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ - u8 nColCache; /* Number of entries in aColCache[] */ + u8 disableVtab; /* Disable all virtual tables for this parse */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) + u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ +#endif int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ - int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ - int ckBase; /* Base register of data during check constraints */ - int iSelfTab; /* Table of an index whose exprs are being coded */ - int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ - int iCacheCnt; /* Counter used to generate aColCache[].lru values */ - int nLabel; /* Number of labels used */ + int iSelfTab; /* Table associated with an index on expr, or negative + ** of the base register during check-constraint eval */ + int nLabel; /* The *negative* of the number of labels used */ + int nLabelAlloc; /* Number of slots in aLabel */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ Token constraintName;/* Name of the constraint currently being parsed */ @@ -15694,10 +18826,7 @@ struct Parse { int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ -#if SELECTTRACE_ENABLED - int nSelect; /* Number of SELECT statements seen */ - int nSelectIndent; /* How far to indent SELECTTRACE() output */ -#endif + int nSelect; /* Number of SELECT stmts. Counter for Select.selId */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ @@ -15705,11 +18834,17 @@ struct Parse { AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ - int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */ + TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ + ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ + union { + int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */ + Returning *pReturning; /* The RETURNING clause */ + } u1; u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ u32 newmask; /* Mask of new.* columns referenced */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ + u8 bReturning; /* Coding a RETURNING trigger */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ @@ -15717,18 +18852,11 @@ struct Parse { ** Fields above must be initialized to zero. The fields that follow, ** down to the beginning of the recursive section, do not need to be ** initialized as they will be set before being used. The boundary is - ** determined by offsetof(Parse,aColCache). + ** determined by offsetof(Parse,aTempReg). **************************************************************************/ - struct yColCache { - int iTable; /* Table cursor number */ - i16 iColumn; /* Table column number */ - u8 tempReg; /* iReg is a temp register that needs to be freed */ - int iLevel; /* Nesting level */ - int iReg; /* Reg with value of this column. 0 means none. */ - int lru; /* Least recently used entry has the smallest value */ - } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ int aTempReg[8]; /* Holding area for temporary registers */ + Parse *pOuterParse; /* Outer Parse object when nested */ Token sNameToken; /* Token with unqualified schema object name */ /************************************************************************ @@ -15742,35 +18870,45 @@ struct Parse { ynVar nVar; /* Number of '?' variables seen in the SQL so far */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ + u8 eParseMode; /* PARSE_MODE_XXX constant */ #ifndef SQLITE_OMIT_VIRTUALTABLE - u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN - int iSelectId; /* ID of current select for EXPLAIN output */ - int iNextSelectId; /* Next available select ID for EXPLAIN output */ + int addrExplain; /* Address of current OP_Explain opcode */ #endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ + Index *pNewIndex; /* An index being constructed by CREATE INDEX. + ** Also used to hold redundant UNIQUE constraints + ** during a RENAME COLUMN */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif - Table *pZombieTab; /* List of Table objects to delete after code gen */ - TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ - With *pWithToFree; /* Free this WITH object at the end of the parse */ +#ifndef SQLITE_OMIT_ALTERTABLE + RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ +#endif }; +/* Allowed values for Parse.eParseMode +*/ +#define PARSE_MODE_NORMAL 0 +#define PARSE_MODE_DECLARE_VTAB 1 +#define PARSE_MODE_RENAME 2 +#define PARSE_MODE_UNMAP 3 + /* ** Sizes and pointers of various parts of the Parse object. */ -#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/ +#define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg)) +#define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/ #define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ #define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ #define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ @@ -15781,7 +18919,19 @@ struct Parse { #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #else - #define IN_DECLARE_VTAB (pParse->declareVtab) + #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB) +#endif + +#if defined(SQLITE_OMIT_ALTERTABLE) + #define IN_RENAME_OBJECT 0 +#else + #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME) +#endif + +#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE) + #define IN_SPECIAL_PARSE 0 +#else + #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL) #endif /* @@ -15807,6 +18957,7 @@ struct AuthContext { */ #define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ /* Also used in P2 (not P5) of OP_Delete */ +#define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ @@ -15822,6 +18973,8 @@ struct AuthContext { #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ #define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ #define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ +#define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */ +#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */ /* * Each trigger present in the database schema is stored as an instance of @@ -15843,6 +18996,7 @@ struct Trigger { char *table; /* The table or view to which the trigger applies */ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ + u8 bReturning; /* This trigger implements a RETURNING clause */ Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */ IdList *pColumns; /* If this is an UPDATE OF trigger, the is stored here */ @@ -15901,49 +19055,48 @@ struct Trigger { * */ struct TriggerStep { - u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */ + u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT, + ** or TK_RETURNING */ u8 orconf; /* OE_Rollback etc. */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ + SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ - ExprList *pExprList; /* SET clause for UPDATE. */ + ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */ IdList *pIdList; /* Column names for INSERT */ + Upsert *pUpsert; /* Upsert clauses on an INSERT */ + char *zSpan; /* Original SQL text of this command */ TriggerStep *pNext; /* Next in the link-list */ TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */ }; /* -** The following structure contains information used by the sqliteFix... -** routines as they walk the parse tree to make database references -** explicit. +** Information about a RETURNING clause */ -typedef struct DbFixer DbFixer; -struct DbFixer { - Parse *pParse; /* The parsing context. Error messages written here */ - Schema *pSchema; /* Fix items to this schema */ - int bVarOnly; /* Check for variable references only */ - const char *zDb; /* Make sure all objects are contained in this database */ - const char *zType; /* Type of the container - used for error messages */ - const Token *pName; /* Name of the container - used for error messages */ +struct Returning { + Parse *pParse; /* The parse that includes the RETURNING clause */ + ExprList *pReturnEL; /* List of expressions to return */ + Trigger retTrig; /* The transient trigger that implements RETURNING */ + TriggerStep retTStep; /* The trigger step */ + int iRetCur; /* Transient table holding RETURNING results */ + int nRetCol; /* Number of in pReturnEL after expansion */ + int iRetReg; /* Register array for holding a row of RETURNING */ }; /* ** An objected used to accumulate the text of a string where we ** do not necessarily know how big the string will be in the end. */ -struct StrAccum { +struct sqlite3_str { sqlite3 *db; /* Optional database for lookaside. Can be NULL */ - char *zBase; /* A base allocation. Not from malloc. */ char *zText; /* The string collected so far */ - u32 nChar; /* Length of the string so far */ u32 nAlloc; /* Amount of space allocated in zText */ u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */ - u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */ + u32 nChar; /* Length of the string so far */ + u8 accError; /* SQLITE_NOMEM or SQLITE_TOOBIG */ u8 printfFlags; /* SQLITE_PRINTF flags below */ }; -#define STRACCUM_NOMEM 1 -#define STRACCUM_TOOBIG 2 #define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */ #define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */ #define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */ @@ -15960,8 +19113,35 @@ typedef struct { char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ + u32 mInitFlags; /* Flags controlling error messages */ + u32 nInitRow; /* Number of rows processed */ + Pgno mxPage; /* Maximum page number. 0 for no limit. */ } InitData; +/* +** Allowed values for mInitFlags +*/ +#define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ +#define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ +#define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ +#define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ + +/* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled +** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning +** parameters are for temporary use during development, to help find +** optimial values for parameters in the query planner. The should not +** be used on trunk check-ins. They are a temporary mechanism available +** for transient development builds only. +** +** Tuning parameters are numbered starting with 1. +*/ +#define SQLITE_NTUNE 6 /* Should be zero for all trunk check-ins */ +#ifdef SQLITE_DEBUG +# define Tuning(X) (sqlite3Config.aTune[(X)-1]) +#else +# define Tuning(X) 0 +#endif + /* ** Structure containing global configuration data for the SQLite library. ** @@ -15969,10 +19149,12 @@ typedef struct { */ struct Sqlite3Config { int bMemstat; /* True to enable memory status */ - int bCoreMutex; /* True to enable core mutexing */ - int bFullMutex; /* True to enable full mutexing */ - int bOpenUri; /* True to interpret filenames as URIs */ - int bUseCis; /* Use covering indices for full-scans */ + u8 bCoreMutex; /* True to enable core mutexing */ + u8 bFullMutex; /* True to enable full mutexing */ + u8 bOpenUri; /* True to interpret filenames as URIs */ + u8 bUseCis; /* Use covering indices for full-scans */ + u8 bSmallMalloc; /* Avoid large memory allocations if true */ + u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */ int mxStrlen; /* Maximum string length */ int neverCorrupt; /* Database is always well-formed */ int szLookaside; /* Default lookaside buffer size */ @@ -15986,9 +19168,6 @@ struct Sqlite3Config { int mnReq, mxReq; /* Min and max heap requests sizes */ sqlite3_int64 szMmap; /* mmap() space per open file */ sqlite3_int64 mxMmap; /* Maximum value for szMmap */ - void *pScratch; /* Scratch memory */ - int szScratch; /* Size of each scratch buffer */ - int nScratch; /* Number of scratch buffers */ void *pPage; /* Page cache memory */ int szPage; /* Size of each page in pPage[] */ int nPage; /* Number of pages in pPage[] */ @@ -16014,14 +19193,24 @@ struct Sqlite3Config { /* The following callback (if not NULL) is invoked on every VDBE branch ** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE. */ - void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */ + void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */ void *pVdbeBranchArg; /* 1st argument */ #endif +#ifndef SQLITE_OMIT_DESERIALIZE + sqlite3_int64 mxMemdbSize; /* Default max memdb size */ +#endif #ifndef SQLITE_UNTESTABLE int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */ #endif int bLocaltimeFault; /* True to fail localtime() calls */ + int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */ int iOnceResetThreshold; /* When to reset OP_Once counters */ + u32 szSorterRef; /* Min size in bytes to use sorter-refs */ + unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ + /* vvvv--- must be last ---vvv */ +#ifdef SQLITE_DEBUG + sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ +#endif }; /* @@ -16051,19 +19240,43 @@ struct Walker { int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */ void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */ int walkerDepth; /* Number of subqueries */ - u8 eCode; /* A small processing code */ + u16 eCode; /* A small processing code */ union { /* Extra data for callback */ - NameContext *pNC; /* Naming context */ - int n; /* A counter */ - int iCur; /* A cursor number */ - SrcList *pSrcList; /* FROM clause */ - struct SrcCount *pSrcCount; /* Counting column references */ - struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ - int *aiCol; /* array of column indexes */ - struct IdxCover *pIdxCover; /* Check for index coverage */ + NameContext *pNC; /* Naming context */ + int n; /* A counter */ + int iCur; /* A cursor number */ + SrcList *pSrcList; /* FROM clause */ + struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ + struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */ + int *aiCol; /* array of column indexes */ + struct IdxCover *pIdxCover; /* Check for index coverage */ + struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */ + ExprList *pGroupBy; /* GROUP BY clause */ + Select *pSelect; /* HAVING to WHERE clause ctx */ + struct WindowRewrite *pRewrite; /* Window rewrite context */ + struct WhereConst *pConst; /* WHERE clause constants */ + struct RenameCtx *pRename; /* RENAME COLUMN context */ + struct Table *pTab; /* Table of generated column */ + SrcItem *pSrcItem; /* A single FROM clause item */ + DbFixer *pFix; } u; }; +/* +** The following structure contains information used by the sqliteFix... +** routines as they walk the parse tree to make database references +** explicit. +*/ +struct DbFixer { + Parse *pParse; /* The parsing context. Error messages written here */ + Walker w; /* Walker object */ + Schema *pSchema; /* Fix items to this schema */ + u8 bTemp; /* True for TEMP schema entries */ + const char *zDb; /* Make sure all objects are contained in this database */ + const char *zType; /* Type of the container - used for error messages */ + const Token *pName; /* Name of the container - used for error messages */ +}; + /* Forward declarations */ SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*); SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*); @@ -16071,6 +19284,21 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*); SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*); SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*); +SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*); +SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*); +SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker*,Select*); +SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker*,Select*); +SQLITE_PRIVATE void sqlite3WalkWinDefnDummyCallback(Walker*,Select*); + +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*); +#endif + +#ifndef SQLITE_OMIT_CTE +SQLITE_PRIVATE void sqlite3SelectPopWith(Walker*, Select*); +#else +# define sqlite3SelectPopWith 0 +#endif /* ** Return code from the parse-tree walking primitives and their @@ -16081,20 +19309,56 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*); #define WRC_Abort 2 /* Abandon the tree walk */ /* -** An instance of this structure represents a set of one or more CTEs -** (common table expressions) created by a single WITH clause. +** A single common table expression +*/ +struct Cte { + char *zName; /* Name of this CTE */ + ExprList *pCols; /* List of explicit column names, or NULL */ + Select *pSelect; /* The definition of this CTE */ + const char *zCteErr; /* Error message for circular references */ + CteUse *pUse; /* Usage information for this CTE */ + u8 eM10d; /* The MATERIALIZED flag */ +}; + +/* +** Allowed values for the materialized flag (eM10d): +*/ +#define M10d_Yes 0 /* AS MATERIALIZED */ +#define M10d_Any 1 /* Not specified. Query planner's choice */ +#define M10d_No 2 /* AS NOT MATERIALIZED */ + +/* +** An instance of the With object represents a WITH clause containing +** one or more CTEs (common table expressions). */ struct With { - int nCte; /* Number of CTEs in the WITH clause */ - With *pOuter; /* Containing WITH clause, or NULL */ - struct Cte { /* For each CTE in the WITH clause.... */ - char *zName; /* Name of this CTE */ - ExprList *pCols; /* List of explicit column names, or NULL */ - Select *pSelect; /* The definition of this CTE */ - const char *zCteErr; /* Error message for circular references */ - } a[1]; + int nCte; /* Number of CTEs in the WITH clause */ + int bView; /* Belongs to the outermost Select of a view */ + With *pOuter; /* Containing WITH clause, or NULL */ + Cte a[1]; /* For each CTE in the WITH clause.... */ +}; + +/* +** The Cte object is not guaranteed to persist for the entire duration +** of code generation. (The query flattener or other parser tree +** edits might delete it.) The following object records information +** about each Common Table Expression that must be preserved for the +** duration of the parse. +** +** The CteUse objects are freed using sqlite3ParserAddCleanup() rather +** than sqlite3SelectDelete(), which is what enables them to persist +** until the end of code generation. +*/ +struct CteUse { + int nUse; /* Number of users of this CTE */ + int addrM9e; /* Start of subroutine to compute materialization */ + int regRtn; /* Return address register for addrM9e subroutine */ + int iCur; /* Ephemeral table holding the materialization */ + LogEst nRowEst; /* Estimated number of rows in the table */ + u8 eM10d; /* The MATERIALIZED flag */ }; + #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of @@ -16106,6 +19370,84 @@ struct TreeView { }; #endif /* SQLITE_DEBUG */ +/* +** This object is used in various ways, most (but not all) related to window +** functions. +** +** (1) A single instance of this structure is attached to the +** the Expr.y.pWin field for each window function in an expression tree. +** This object holds the information contained in the OVER clause, +** plus additional fields used during code generation. +** +** (2) All window functions in a single SELECT form a linked-list +** attached to Select.pWin. The Window.pFunc and Window.pExpr +** fields point back to the expression that is the window function. +** +** (3) The terms of the WINDOW clause of a SELECT are instances of this +** object on a linked list attached to Select.pWinDefn. +** +** (4) For an aggregate function with a FILTER clause, an instance +** of this object is stored in Expr.y.pWin with eFrmType set to +** TK_FILTER. In this case the only field used is Window.pFilter. +** +** The uses (1) and (2) are really the same Window object that just happens +** to be accessible in two different ways. Use case (3) are separate objects. +*/ +struct Window { + char *zName; /* Name of window (may be NULL) */ + char *zBase; /* Name of base window for chaining (may be NULL) */ + ExprList *pPartition; /* PARTITION BY clause */ + ExprList *pOrderBy; /* ORDER BY clause */ + u8 eFrmType; /* TK_RANGE, TK_GROUPS, TK_ROWS, or 0 */ + u8 eStart; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ + u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ + u8 bImplicitFrame; /* True if frame was implicitly specified */ + u8 eExclude; /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */ + Expr *pStart; /* Expression for " PRECEDING" */ + Expr *pEnd; /* Expression for " FOLLOWING" */ + Window **ppThis; /* Pointer to this object in Select.pWin list */ + Window *pNextWin; /* Next window function belonging to this SELECT */ + Expr *pFilter; /* The FILTER expression */ + FuncDef *pFunc; /* The function */ + int iEphCsr; /* Partition buffer or Peer buffer */ + int regAccum; /* Accumulator */ + int regResult; /* Interim result */ + int csrApp; /* Function cursor (used by min/max) */ + int regApp; /* Function register (also used by min/max) */ + int regPart; /* Array of registers for PARTITION BY values */ + Expr *pOwner; /* Expression object this window is attached to */ + int nBufferCol; /* Number of columns in buffer table */ + int iArgCol; /* Offset of first argument for this function */ + int regOne; /* Register containing constant value 1 */ + int regStartRowid; + int regEndRowid; + u8 bExprArgs; /* Defer evaluation of window function arguments + ** due to the SQLITE_SUBTYPE flag */ +}; + +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*); +SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*); +SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p); +SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); +SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*); +SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin); +SQLITE_PRIVATE int sqlite3WindowCompare(const Parse*, const Window*, const Window*, int); +SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*); +SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); +SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*); +SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); +SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); +SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p); +SQLITE_PRIVATE void sqlite3WindowFunctions(void); +SQLITE_PRIVATE void sqlite3WindowChain(Parse*, Window*, Window*); +SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*); +#else +# define sqlite3WindowDelete(a,b) +# define sqlite3WindowFunctions() +# define sqlite3WindowAttach(a,b,c) +#endif + /* ** Assuming zIn points to the first byte of a UTF-8 character, ** advance zIn to point to the first byte of the next UTF-8 character. @@ -16123,6 +19465,7 @@ struct TreeView { ** using sqlite3_log(). The routines also provide a convenient place ** to set a debugger breakpoint. */ +SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); SQLITE_PRIVATE int sqlite3CorruptError(int); SQLITE_PRIVATE int sqlite3MisuseError(int); SQLITE_PRIVATE int sqlite3CantopenError(int); @@ -16138,6 +19481,12 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM #endif +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) +SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) +#else +# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) +#endif /* ** FTS3 and FTS4 both require virtual table support @@ -16189,15 +19538,14 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); # define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') #endif -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_PRIVATE int sqlite3IsIdChar(u8); -#endif /* ** Internal function prototypes */ SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*); SQLITE_PRIVATE int sqlite3Strlen30(const char*); +#define sqlite3Strlen30NN(C) (strlen(C)&0x3fffffff) SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*); #define sqlite3StrNICmp sqlite3_strnicmp @@ -16210,14 +19558,14 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64); SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64); SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*); SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64); +SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*); SQLITE_PRIVATE void *sqlite3Realloc(void*, u64); SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64); SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64); SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*); -SQLITE_PRIVATE int sqlite3MallocSize(void*); -SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*); -SQLITE_PRIVATE void *sqlite3ScratchMalloc(int); -SQLITE_PRIVATE void sqlite3ScratchFree(void*); +SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*); +SQLITE_PRIVATE int sqlite3MallocSize(const void*); +SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*); SQLITE_PRIVATE void *sqlite3PageMalloc(int); SQLITE_PRIVATE void sqlite3PageFree(void*); SQLITE_PRIVATE void sqlite3MemSetDefault(void); @@ -16273,14 +19621,25 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int); SQLITE_PRIVATE void sqlite3StatusUp(int, int); SQLITE_PRIVATE void sqlite3StatusDown(int, int); SQLITE_PRIVATE void sqlite3StatusHighwater(int, int); +SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*); /* Access to mutexes used by sqlite3_status() */ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void); SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void); +#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) +SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*); +#else +# define sqlite3MutexWarnOnContention(x) +#endif + #ifndef SQLITE_OMIT_FLOATING_POINT +# define EXP754 (((u64)0x7ff)<<52) +# define MAN754 ((((u64)1)<<52)-1) +# define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0) SQLITE_PRIVATE int sqlite3IsNaN(double); #else +# define IsNaN(X) 0 # define sqlite3IsNaN(X) 0 #endif @@ -16294,8 +19653,6 @@ struct PrintfArguments { sqlite3_value **apArg; /* The argument values */ }; -SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list); -SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...); SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...); SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list); #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) @@ -16309,17 +19666,25 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*); SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*); SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); +SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*); SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8); SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8); +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView*, const Window*, u8); +SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); +#endif #endif SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); +SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int); SQLITE_PRIVATE void sqlite3Dequote(char*); +SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*); +SQLITE_PRIVATE void sqlite3DequoteToken(Token*); SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int); -SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **); +SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*); SQLITE_PRIVATE void sqlite3FinishCoding(Parse*); SQLITE_PRIVATE int sqlite3GetTempReg(Parse*); SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int); @@ -16334,19 +19699,26 @@ SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); -SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); -SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); +SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int); +SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); +SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); -SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int); -SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); -SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); +SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*); +SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int); +SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); +SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); +SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*); SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); +SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32); SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); #ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); @@ -16355,28 +19727,43 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*); SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int); SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*); SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*); +SQLITE_PRIVATE void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); +SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table*,Column*); +SQLITE_PRIVATE void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); +SQLITE_PRIVATE const char *sqlite3ColumnColl(Column*); SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); +SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); -SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*); -SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*); -SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int); +SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char); +SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); +SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); -SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index*, i16); +SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16); +#ifdef SQLITE_OMIT_GENERATED_COLUMNS +# define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ +# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ +#else +SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table*, i16); +SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table*, i16); +#endif SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); #if SQLITE_ENABLE_HIDDEN_COLUMNS SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*); #else # define sqlite3ColumnPropertiesFromName(T,C) /* no-op */ #endif -SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*); +SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token,Token); SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); -SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); -SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*); +SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*); +SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); -SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); +SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*); +SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*); +SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*); SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); +#define sqlite3CodecQueryParameters(A,B,C) 0 SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE @@ -16396,8 +19783,9 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*); SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*); #endif -SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); -SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*); +SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*); +SQLITE_PRIVATE void sqlite3RowSetDelete(void*); +SQLITE_PRIVATE void sqlite3RowSetClear(void*); SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64); SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64); SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*); @@ -16416,6 +19804,7 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); +SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*); #ifndef SQLITE_OMIT_AUTOINCREMENT SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); @@ -16423,17 +19812,21 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif -SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int); +SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(Parse*, int, Table*); +#endif SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); -SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); +SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); -SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); -SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); +SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); +SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); +SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*); SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); -SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); +SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *); SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*); SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); @@ -16444,22 +19837,26 @@ SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,i SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, - Expr*,ExprList*,u32,Expr*,Expr*); + Expr*,ExprList*,u32,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int); SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) -SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*); -#endif -SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); -SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); -SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); +SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); +#endif +SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe*,int,const char*); +SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); +SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, + Upsert*); +SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*, + ExprList*,Select*,u16,int); SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*); SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*); -SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*); +SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo*); +SQLITE_PRIVATE void sqlite3WhereMinMaxOptEarlyOut(Vdbe*,WhereInfo*); SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*); SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*); @@ -16467,24 +19864,20 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */ #define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */ #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ +SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo*); SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); -SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(Parse*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int); -SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int); -SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*); -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*); -SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int); -SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*); -SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int); SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); +#endif SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); -SQLITE_PRIVATE int sqlite3ExprCodeAtInit(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); -SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ @@ -16497,20 +19890,24 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*); #define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); -SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); +SQLITE_PRIVATE const char *sqlite3PreferredTableName(const char*); +SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *); SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); -SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*); -SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int); -SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); -SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int); -SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int); -SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int); +SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*,Expr*); +SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*); +SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, const Token*); +SQLITE_PRIVATE int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int); +SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*,Expr*,int); +SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList*,const ExprList*, int); +SQLITE_PRIVATE int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int); +SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int); +SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); -SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); +SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse*, Expr*, SrcList*); SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE void sqlite3PrngSaveState(void); @@ -16520,19 +19917,22 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); -SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); -SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); +SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int); SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*); +SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char*); +SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr*); +SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*); SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8); +SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); #endif -SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*); +SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); SQLITE_PRIVATE int sqlite3IsRowid(const char*); @@ -16541,8 +19941,9 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int); +SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int); SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, - u8,u8,int,int*,int*); + u8,u8,int,int*,int*,Upsert*); #ifdef SQLITE_ENABLE_NULL_TRIM SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe*,Table*); #else @@ -16556,27 +19957,29 @@ SQLITE_PRIVATE void sqlite3MayAbort(Parse*); SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8); SQLITE_PRIVATE void sqlite3UniqueConstraint(Parse*, int, Index*); SQLITE_PRIVATE void sqlite3RowidConstraint(Parse*, int, Table*); -SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int); -SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); -SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); -SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*); -SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int); -#if SELECTTRACE_ENABLED -SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*); -#else -# define sqlite3SelectSetName(A,B) -#endif +SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,const Expr*,int); +SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int); +SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int); +SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*); +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); +SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); +SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) +SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*); +#endif SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*); SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*); SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int); +SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p); #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) -SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, int); +SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int); #endif #ifndef SQLITE_OMIT_TRIGGER @@ -16592,14 +19995,19 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, i SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int); void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*, - Select*,u8); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, + const char*,const char*); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, + Select*,u8,Upsert*, + const char*,const char*); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*, + Expr*, u8, const char*,const char*); +SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, + const char*,const char*); SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); +SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else @@ -16613,9 +20021,12 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Tab # define sqlite3ParseToplevel(p) p # define sqlite3IsToplevel(p) 1 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 +# define sqlite3TriggerStepSrc(A,B) 0 #endif SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*); +SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol); +SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr*,int); SQLITE_PRIVATE void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int); SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse*, int); #ifndef SQLITE_OMIT_AUTHORIZATION @@ -16630,30 +20041,29 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(Parse*, const char *, const char *, int) # define sqlite3AuthContextPush(a,b,c) # define sqlite3AuthContextPop(a) ((void)(a)) #endif +SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName); SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*); SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*); SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*); SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); -SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); +SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); +SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); +SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); +#ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); +#endif SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); SQLITE_PRIVATE LogEst sqlite3LogEst(u64); SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); -#ifndef SQLITE_OMIT_VIRTUALTABLE SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); -#endif -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ - defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \ - defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); -#endif SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int); SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int); @@ -16675,6 +20085,8 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v); */ #define getVarint32(A,B) \ (u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B))) +#define getVarint32NR(A,B) \ + B=(u32)*(A);if(B>=0x80)sqlite3GetVarint32((A),(u32*)&(B)) #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ sqlite3PutVarint((A),(B))) @@ -16684,14 +20096,15 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v); SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*); SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int); -SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); -SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); -SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int); -SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); +SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2); +SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); +SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table*,int); +SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*); SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); SQLITE_PRIVATE void sqlite3Error(sqlite3*,int); +SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3*); SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); @@ -16701,17 +20114,27 @@ SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); SQLITE_PRIVATE const char *sqlite3ErrName(int); #endif +#ifndef SQLITE_OMIT_DESERIALIZE +SQLITE_PRIVATE int sqlite3MemdbInit(void); +#endif + SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); +SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); -SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); +SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8); +SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); +SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int); +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*); SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*); SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); -SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *); -SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); +SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*); +SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); +SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, i64); SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); @@ -16729,43 +20152,72 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context*); +#endif SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); +#ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); -SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); +#endif +SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **); SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[]; SQLITE_PRIVATE const char sqlite3StrBINARY[]; +SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[]; +SQLITE_PRIVATE const char sqlite3StdTypeAffinity[]; +SQLITE_PRIVATE const char sqlite3StdTypeMap[]; +SQLITE_PRIVATE const char *sqlite3StdType[]; SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[]; +SQLITE_PRIVATE const unsigned char *sqlite3aLTb; +SQLITE_PRIVATE const unsigned char *sqlite3aEQb; +SQLITE_PRIVATE const unsigned char *sqlite3aGTb; SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[]; -SQLITE_PRIVATE const Token sqlite3IntTokens[]; SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config; SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; #ifndef SQLITE_OMIT_WSD SQLITE_PRIVATE int sqlite3PendingByte; #endif +#endif /* SQLITE_AMALGAMATION */ +#ifdef VDBE_PROFILE +SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt; #endif -SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int); +SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno); SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); SQLITE_PRIVATE void sqlite3AlterFunctions(void); SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); +SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *); SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); -SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*); -SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int); +SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); +SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int); +SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*); SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); +SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, SrcItem*); SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); -SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); +SQLITE_PRIVATE int sqlite3MatchEName( + const struct ExprList_item*, + const char*, + const char*, + const char* +); +SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*); +SQLITE_PRIVATE u8 sqlite3StrIHash(const char*); SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*); SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*); SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); -SQLITE_PRIVATE void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); +SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int); SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); +SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse*, SrcList*, const Token*); +SQLITE_PRIVATE const void *sqlite3RenameTokenMap(Parse*, const void*, const Token*); +SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, const void *pTo, const void *pFrom); +SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*); SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); -SQLITE_PRIVATE char sqlite3AffinityType(const char*, u8*); +SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*); SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*); SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); @@ -16782,27 +20234,36 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo*); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo*); SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); +SQLITE_PRIVATE const char *sqlite3SelectOpName(int); +SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse*, ExprList*); + #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*); #endif SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), - void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*), + void (*)(sqlite3_context*,int,sqlite3_value **), + void (*)(sqlite3_context*), + void (*)(sqlite3_context*), + void (*)(sqlite3_context*,int,sqlite3_value **), FuncDestructor *pDestructor ); -SQLITE_PRIVATE void sqlite3OomFault(sqlite3*); +SQLITE_PRIVATE void sqlite3NoopDestructor(void*); +SQLITE_PRIVATE void *sqlite3OomFault(sqlite3*); SQLITE_PRIVATE void sqlite3OomClear(sqlite3*); SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int); SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *); SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); -SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int); -SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum*,const char*); -SQLITE_PRIVATE void sqlite3AppendChar(StrAccum*,int,char); +SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, int); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); -SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*); +SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8); +SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int); SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); +SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3*,const char*); +SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3*,const Expr*); SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *); SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); @@ -16813,8 +20274,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*); # define sqlite3ExprCheckIN(x,y) SQLITE_OK #endif -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 -SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void); +#ifdef SQLITE_ENABLE_STAT4 SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*); SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); @@ -16827,10 +20287,11 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int); ** The interface to the LEMON-generated parser */ #ifndef SQLITE_AMALGAMATION -SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64)); +SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64), Parse*); SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*)); #endif -SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*); +SQLITE_PRIVATE void sqlite3Parser(void*, int, Token); +SQLITE_PRIVATE int sqlite3ParserFallback(int); #ifdef YYTRACKMAXSTACKDEPTH SQLITE_PRIVATE int sqlite3ParserStackPeak(void*); #endif @@ -16843,7 +20304,7 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3*); #endif #ifndef SQLITE_OMIT_SHARED_CACHE -SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, int, u8, const char *); +SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, Pgno, u8, const char *); #else #define sqlite3TableLock(v,w,x,y,z) #endif @@ -16853,13 +20314,14 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*); #endif #ifdef SQLITE_OMIT_VIRTUALTABLE -# define sqlite3VtabClear(Y) +# define sqlite3VtabClear(D,T) # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) +# define sqlite3VtabModuleUnref(D,X) # define sqlite3VtabUnlockList(X) # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK # define sqlite3GetVTable(X,Y) ((VTable*)0) @@ -16871,6 +20333,7 @@ SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); SQLITE_PRIVATE void sqlite3VtabLock(VTable *); SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); +SQLITE_PRIVATE void sqlite3VtabModuleUnref(sqlite3*,Module*); SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); @@ -16884,6 +20347,16 @@ SQLITE_PRIVATE Module *sqlite3VtabCreateModule( ); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif +SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db); +#ifndef SQLITE_OMIT_VIRTUALTABLE +SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName); +SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); +SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); +#else +# define sqlite3ShadowTableName(A,B) 0 +# define sqlite3IsShadowTableOf(A,B,C) 0 +# define sqlite3MarkAllShadowTablesOf(A,B) +#endif SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*); SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*); SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); @@ -16895,15 +20368,25 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*); SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *); SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *); + SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); -SQLITE_PRIVATE void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) +SQLITE_PRIVATE void sqlite3VtabWriteAll(sqlite3_index_info*); +#endif SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); -SQLITE_PRIVATE void sqlite3ParserReset(Parse*); +SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse*,sqlite3*); +SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse*); +SQLITE_PRIVATE void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*); +#endif SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*); SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); -SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); +SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse*,const Expr*); +SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, const Expr*, const Expr*); SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*); SQLITE_PRIVATE const char *sqlite3JournalModename(int); #ifndef SQLITE_OMIT_WAL @@ -16911,14 +20394,35 @@ SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); #endif #ifndef SQLITE_OMIT_CTE -SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*); +SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8); +SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*); +SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*); SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*); -SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8); +SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8); +#else +# define sqlite3CteNew(P,T,E,S) ((void*)0) +# define sqlite3CteDelete(D,C) +# define sqlite3CteWithAdd(P,W,C) ((void*)0) +# define sqlite3WithDelete(x,y) +# define sqlite3WithPush(x,y,z) ((void*)0) +#endif +#ifndef SQLITE_OMIT_UPSERT +SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*); +SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*); +SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); +SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); +SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); +SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*); +SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*); #else -#define sqlite3WithPush(x,y,z) -#define sqlite3WithDelete(x,y) +#define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0) +#define sqlite3UpsertDelete(x,y) +#define sqlite3UpsertDup(x,y) ((Upsert*)0) +#define sqlite3UpsertOfIndex(x,y) ((Upsert*)0) +#define sqlite3UpsertNextIsIPK(x) 0 #endif + /* Declarations for functions in fkey.c. All of these are replaced by ** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign ** key functionality is available. If OMIT_TRIGGER is defined but @@ -16933,6 +20437,7 @@ SQLITE_PRIVATE void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int SQLITE_PRIVATE int sqlite3FkRequired(Parse*, Table*, int*, int); SQLITE_PRIVATE u32 sqlite3FkOldmask(Parse*, Table*); SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *); +SQLITE_PRIVATE void sqlite3FkClearTriggerCache(sqlite3*,int); #else #define sqlite3FkActions(a,b,c,d,e,f) #define sqlite3FkCheck(a,b,c,d,e,f) @@ -16940,6 +20445,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *); #define sqlite3FkOldmask(a,b) 0 #define sqlite3FkRequired(a,b,c,d) 0 #define sqlite3FkReferences(a) 0 + #define sqlite3FkClearTriggerCache(a,b) #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*); @@ -16983,11 +20489,12 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void); #define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ #define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ #define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ -SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*); +SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*); SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *); -#ifdef SQLITE_ENABLE_ATOMIC_WRITE +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *); #endif @@ -16996,7 +20503,7 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *); SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 -SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *); +SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *); SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int); #else #define sqlite3SelectExprHeight(x) 0 @@ -17019,6 +20526,9 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *); #endif +#if defined(YYCOVERAGE) +SQLITE_PRIVATE int sqlite3ParserCoverage(FILE*); +#endif /* ** If the SQLITE_ENABLE IOTRACE exists then the global variable @@ -17064,8 +20574,8 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...); */ #ifdef SQLITE_MEMDEBUG SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8); -SQLITE_PRIVATE int sqlite3MemdebugHasType(void*,u8); -SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); +SQLITE_PRIVATE int sqlite3MemdebugHasType(const void*,u8); +SQLITE_PRIVATE int sqlite3MemdebugNoType(const void*,u8); #else # define sqlite3MemdebugSetType(X,Y) /* no-op */ # define sqlite3MemdebugHasType(X,Y) 1 @@ -17073,8 +20583,7 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8); #endif #define MEMTYPE_HEAP 0x01 /* General heap allocations */ #define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */ -#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ -#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ +#define MEMTYPE_PCACHE 0x04 /* Page cache allocations */ /* ** Threading interface @@ -17084,22 +20593,29 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*); SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**); #endif +#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST) +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*); +#endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*); #endif -SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr); -SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr); +SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr); SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int); -SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int); +SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt); +#endif + #endif /* SQLITEINT_H */ /************** End of sqliteInt.h *******************************************/ -/************** Begin file global.c ******************************************/ +/************** Begin file os_common.h ***************************************/ /* -** 2008 June 13 +** 2004 May 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -17108,290 +20624,201 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*); ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** -************************************************************************* +****************************************************************************** ** -** This file contains definitions of global variables and constants. +** This file contains macros and a little bit of code that is common to +** all of the platform-specific files (os_*.c) and is #included into those +** files. +** +** This file should be #included by the os_*.c files only. It is not a +** general purpose header file. */ -/* #include "sqliteInt.h" */ +#ifndef _OS_COMMON_H_ +#define _OS_COMMON_H_ -/* An array to map all upper-case characters into their corresponding -** lower-case character. -** -** SQLite only considers US-ASCII (or EBCDIC) characters. We do not -** handle case conversions for the UTF character set since the tables -** involved are nearly as big or bigger than SQLite itself. +/* +** At least two bugs have slipped in because we changed the MEMORY_DEBUG +** macro to SQLITE_DEBUG and some older makefiles have not yet made the +** switch. The following code should catch this problem at compile-time. */ -SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = { -#ifdef SQLITE_ASCII - 0, 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, 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, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, - 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, - 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, - 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, - 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, - 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, - 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, - 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, - 252,253,254,255 -#endif -#ifdef SQLITE_EBCDIC - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */ - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */ - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */ - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */ - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */ - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */ - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */ - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */ - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */ - 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */ - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */ - 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */ - 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */ - 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ +#ifdef MEMORY_DEBUG +# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." #endif -}; /* -** The following 256 byte lookup table is used to support SQLites built-in -** equivalents to the following standard library functions: -** -** isspace() 0x01 -** isalpha() 0x02 -** isdigit() 0x04 -** isalnum() 0x06 -** isxdigit() 0x08 -** toupper() 0x20 -** SQLite identifier character 0x40 -** Quote character 0x80 +** Macros for performance tracing. Normally turned off. Only works +** on i486 hardware. +*/ +#ifdef SQLITE_PERFORMANCE_TRACE + +/* +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. +*/ +/************** Include hwtime.h in the middle of os_common.h ****************/ +/************** Begin file hwtime.h ******************************************/ +/* +** 2008 May 27 ** -** Bit 0x20 is set if the mapped character requires translation to upper -** case. i.e. if the character is a lower-case ASCII character. -** If x is a lower-case ASCII character, then its upper-case equivalent -** is (x - 0x20). Therefore toupper() can be implemented as: +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** (x & ~(map[x]&0x20)) +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. ** -** The equivalent of tolower() is implemented using the sqlite3UpperToLower[] -** array. tolower() is used more often than toupper() by SQLite. +****************************************************************************** ** -** Bit 0x40 is set if the character is non-alphanumeric and can be used in an -** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any -** non-ASCII UTF character. Hence the test for whether or not a character is -** part of an identifier is 0x46. +** This file contains inline asm code for retrieving "high-performance" +** counters for x86 and x86_64 class CPUs. */ -#ifdef SQLITE_ASCII -SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */ - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */ - 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */ - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */ - 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */ +#ifndef SQLITE_HWTIME_H +#define SQLITE_HWTIME_H - 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */ - 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */ - 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */ - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */ - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */ - 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */ +/* +** The following routine only works on pentium-class (or newer) processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +#if !defined(__STRICT_ANSI__) && \ + (defined(__GNUC__) || defined(_MSC_VER)) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */ + #if defined(__GNUC__) - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ -}; -#endif + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned int lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); + return (sqlite_uint64)hi << 32 | lo; + } -/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards -** compatibility for legacy applications, the URI filename capability is -** disabled by default. -** -** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled -** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. -** -** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally -** disabled. The default value may be changed by compiling with the -** SQLITE_USE_URI symbol defined. -*/ -#ifndef SQLITE_USE_URI -# define SQLITE_USE_URI 0 -#endif + #elif defined(_MSC_VER) -/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the -** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if -** that compile-time option is omitted. -*/ -#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN -# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 -#endif + __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ + __asm { + rdtsc + ret ; return value at EDX:EAX + } + } -/* The minimum PMA size is set to this value multiplied by the database -** page size in bytes. -*/ -#ifndef SQLITE_SORTER_PMASZ -# define SQLITE_SORTER_PMASZ 250 -#endif + #endif -/* Statement journals spill to disk when their size exceeds the following -** threshold (in bytes). 0 means that statement journals are created and -** written to disk immediately (the default behavior for SQLite versions -** before 3.12.0). -1 means always keep the entire statement journal in -** memory. (The statement journal is also always held entirely in memory -** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this -** setting.) -*/ -#ifndef SQLITE_STMTJRNL_SPILL -# define SQLITE_STMTJRNL_SPILL (64*1024) -#endif +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) -/* -** The default lookaside-configuration, the format "SZ,N". SZ is the -** number of bytes in each lookaside slot (should be a multiple of 8) -** and N is the number of slots. The lookaside-configuration can be -** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE) -** or at run-time for an individual database connection using -** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE); -*/ -#ifndef SQLITE_DEFAULT_LOOKASIDE -# define SQLITE_DEFAULT_LOOKASIDE 1200,100 -#endif + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long val; + __asm__ __volatile__ ("rdtsc" : "=A" (val)); + return val; + } +#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) -/* -** The following singleton contains the global configuration for -** the SQLite library. -*/ -SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { - SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ - 1, /* bCoreMutex */ - SQLITE_THREADSAFE==1, /* bFullMutex */ - SQLITE_USE_URI, /* bOpenUri */ - SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ - 0x7ffffffe, /* mxStrlen */ - 0, /* neverCorrupt */ - SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ - SQLITE_STMTJRNL_SPILL, /* nStmtSpill */ - {0,0,0,0,0,0,0,0}, /* m */ - {0,0,0,0,0,0,0,0,0}, /* mutex */ - {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */ - (void*)0, /* pHeap */ - 0, /* nHeap */ - 0, 0, /* mnHeap, mxHeap */ - SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */ - SQLITE_MAX_MMAP_SIZE, /* mxMmap */ - (void*)0, /* pScratch */ - 0, /* szScratch */ - 0, /* nScratch */ - (void*)0, /* pPage */ - 0, /* szPage */ - SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */ - 0, /* mxParserStack */ - 0, /* sharedCacheEnabled */ - SQLITE_SORTER_PMASZ, /* szPma */ - /* All the rest should always be initialized to zero */ - 0, /* isInit */ - 0, /* inProgress */ - 0, /* isMutexInit */ - 0, /* isMallocInit */ - 0, /* isPCacheInit */ - 0, /* nRefInitMutex */ - 0, /* pInitMutex */ - 0, /* xLog */ - 0, /* pLogArg */ -#ifdef SQLITE_ENABLE_SQLLOG - 0, /* xSqllog */ - 0, /* pSqllogArg */ -#endif -#ifdef SQLITE_VDBE_COVERAGE - 0, /* xVdbeBranch */ - 0, /* pVbeBranchArg */ -#endif -#ifndef SQLITE_UNTESTABLE - 0, /* xTestCallback */ -#endif - 0, /* bLocaltimeFault */ - 0x7ffffffe /* iOnceResetThreshold */ -}; + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + unsigned long long retval; + unsigned long junk; + __asm__ __volatile__ ("\n\ + 1: mftbu %1\n\ + mftb %L0\n\ + mftbu %0\n\ + cmpw %0,%1\n\ + bne 1b" + : "=r" (retval), "=r" (junk)); + return retval; + } -/* -** Hash table for global functions - functions common to all -** database connections. After initialization, this table is -** read-only. -*/ -SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions; +#else -/* -** Constant tokens for values 0 and 1. -*/ -SQLITE_PRIVATE const Token sqlite3IntTokens[] = { - { "0", 1 }, - { "1", 1 } -}; + /* + ** asm() is needed for hardware timing support. Without asm(), + ** disable the sqlite3Hwtime() routine. + ** + ** sqlite3Hwtime() is only used for some obscure debugging + ** and analysis configurations, not in any deliverable, so this + ** should not be a great loss. + */ +SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } +#endif -/* -** The value of the "pending" byte must be 0x40000000 (1 byte past the -** 1-gibabyte boundary) in a compatible database. SQLite never uses -** the database page that contains the pending byte. It never attempts -** to read or write that page. The pending byte page is set aside -** for use by the VFS layers as space for managing file locks. -** -** During testing, it is often desirable to move the pending byte to -** a different position in the file. This allows code that has to -** deal with the pending byte to run on files that are much smaller -** than 1 GiB. The sqlite3_test_control() interface can be used to -** move the pending byte. -** -** IMPORTANT: Changing the pending byte to any value other than -** 0x40000000 results in an incompatible database file format! -** Changing the pending byte during operation will result in undefined -** and incorrect behavior. -*/ -#ifndef SQLITE_OMIT_WSD -SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000; +#endif /* !defined(SQLITE_HWTIME_H) */ + +/************** End of hwtime.h **********************************************/ +/************** Continuing where we left off in os_common.h ******************/ + +static sqlite_uint64 g_start; +static sqlite_uint64 g_elapsed; +#define TIMER_START g_start=sqlite3Hwtime() +#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start +#define TIMER_ELAPSED g_elapsed +#else +#define TIMER_START +#define TIMER_END +#define TIMER_ELAPSED ((sqlite_uint64)0) #endif -/* #include "opcodes.h" */ /* -** Properties of opcodes. The OPFLG_INITIALIZER macro is -** created by mkopcodeh.awk during compilation. Data is obtained -** from the comments following the "case OP_xxxx:" statements in -** the vdbe.c file. +** If we compile with the SQLITE_TEST macro set, then the following block +** of code will give us the ability to simulate a disk I/O error. This +** is used for testing the I/O recovery logic. */ -SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_io_error_hit; +SQLITE_API extern int sqlite3_io_error_hardhit; +SQLITE_API extern int sqlite3_io_error_pending; +SQLITE_API extern int sqlite3_io_error_persist; +SQLITE_API extern int sqlite3_io_error_benign; +SQLITE_API extern int sqlite3_diskfull_pending; +SQLITE_API extern int sqlite3_diskfull; +#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) +#define SimulateIOError(CODE) \ + if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ + || sqlite3_io_error_pending-- == 1 ) \ + { local_ioerr(); CODE; } +static void local_ioerr(){ + IOTRACE(("IOERR\n")); + sqlite3_io_error_hit++; + if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; +} +#define SimulateDiskfullError(CODE) \ + if( sqlite3_diskfull_pending ){ \ + if( sqlite3_diskfull_pending == 1 ){ \ + local_ioerr(); \ + sqlite3_diskfull = 1; \ + sqlite3_io_error_hit = 1; \ + CODE; \ + }else{ \ + sqlite3_diskfull_pending--; \ + } \ + } +#else +#define SimulateIOErrorBenign(X) +#define SimulateIOError(A) +#define SimulateDiskfullError(A) +#endif /* defined(SQLITE_TEST) */ /* -** Name of the default collating sequence +** When testing, keep a count of the number of open files. */ -SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY"; +#if defined(SQLITE_TEST) +SQLITE_API extern int sqlite3_open_file_count; +#define OpenCounter(X) sqlite3_open_file_count+=(X) +#else +#define OpenCounter(X) +#endif /* defined(SQLITE_TEST) */ -/************** End of global.c **********************************************/ +#endif /* !defined(_OS_COMMON_H_) */ + +/************** End of os_common.h *******************************************/ /************** Begin file ctime.c *******************************************/ +/* DO NOT EDIT! +** This file is automatically generated by the script in the canonical +** SQLite source tree at tool/mkctimec.tcl. +** +** To modify this header, edit any of the various lists in that script +** which specify categories of generated conditionals in this file. +*/ + /* ** 2010 February 23 ** @@ -17407,36 +20834,69 @@ SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY"; ** This file implements routines used to report what compile-time options ** SQLite was built with. */ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +/* +** Include the configuration header output by 'configure' if we're using the +** autoconf-based build +*/ +#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H) +/* #include "config.h" */ +#define SQLITECONFIG_H 1 +#endif + +/* These macros are provided to "stringify" the value of the define +** for those options in which the value is meaningful. */ +#define CTIMEOPT_VAL_(opt) #opt +#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) +/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This +** option requires a separate macro because legal values contain a single +** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ +#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 +#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) /* #include "sqliteInt.h" */ /* -** An array of names of all compile-time options. This array should +** An array of names of all compile-time options. This array should ** be sorted A-Z. ** ** This array looks large, but in a typical installation actually uses ** only a handful of compile-time options, so most times this array is usually ** rather short and uses little memory space. */ -static const char * const azCompileOpt[] = { - -/* These macros are provided to "stringify" the value of the define -** for those options in which the value is meaningful. */ -#define CTIMEOPT_VAL_(opt) #opt -#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) +static const char * const sqlite3azCompileOpt[] = { -#if SQLITE_32BIT_ROWID +#ifdef SQLITE_32BIT_ROWID "32BIT_ROWID", #endif -#if SQLITE_4_BYTE_ALIGNED_MALLOC +#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC "4_BYTE_ALIGNED_MALLOC", #endif -#if SQLITE_CASE_SENSITIVE_LIKE +#ifdef SQLITE_64BIT_STATS + "64BIT_STATS", +#endif +#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN +# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1 + "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN), +# endif +#endif +#ifdef SQLITE_ALLOW_URI_AUTHORITY + "ALLOW_URI_AUTHORITY", +#endif +#ifdef SQLITE_ATOMIC_INTRINSICS + "ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS), +#endif +#ifdef SQLITE_BITMASK_TYPE + "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), +#endif +#ifdef SQLITE_BUG_COMPATIBLE_20160819 + "BUG_COMPATIBLE_20160819", +#endif +#ifdef SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif -#if SQLITE_CHECK_PAGES +#ifdef SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if defined(__clang__) && defined(__clang_major__) @@ -17448,409 +20908,1105 @@ static const char * const azCompileOpt[] = { #elif defined(__GNUC__) && defined(__VERSION__) "COMPILER=gcc-" __VERSION__, #endif -#if SQLITE_COVERAGE_TEST +#ifdef SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG "DEBUG", #endif -#if SQLITE_DEFAULT_LOCKING_MODE +#ifdef SQLITE_DEFAULT_AUTOMATIC_INDEX + "DEFAULT_AUTOMATIC_INDEX", +#endif +#ifdef SQLITE_DEFAULT_AUTOVACUUM + "DEFAULT_AUTOVACUUM", +#endif +#ifdef SQLITE_DEFAULT_CACHE_SIZE + "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), +#endif +#ifdef SQLITE_DEFAULT_CKPTFULLFSYNC + "DEFAULT_CKPTFULLFSYNC", +#endif +#ifdef SQLITE_DEFAULT_FILE_FORMAT + "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT), +#endif +#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS + "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), +#endif +#ifdef SQLITE_DEFAULT_FOREIGN_KEYS + "DEFAULT_FOREIGN_KEYS", +#endif +#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT + "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), +#endif +#ifdef SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif -#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) +#ifdef SQLITE_DEFAULT_LOOKASIDE + "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), +#endif +#ifdef SQLITE_DEFAULT_MEMSTATUS +# if SQLITE_DEFAULT_MEMSTATUS != 1 + "DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS), +# endif +#endif +#ifdef SQLITE_DEFAULT_MMAP_SIZE "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif -#if SQLITE_DIRECT_OVERFLOW_READ +#ifdef SQLITE_DEFAULT_PAGE_SIZE + "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_DEFAULT_PCACHE_INITSZ + "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ), +#endif +#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS + "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), +#endif +#ifdef SQLITE_DEFAULT_RECURSIVE_TRIGGERS + "DEFAULT_RECURSIVE_TRIGGERS", +#endif +#ifdef SQLITE_DEFAULT_ROWEST + "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST), +#endif +#ifdef SQLITE_DEFAULT_SECTOR_SIZE + "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE), +#endif +#ifdef SQLITE_DEFAULT_SYNCHRONOUS + "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT + "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT), +#endif +#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS + "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS), +#endif +#ifdef SQLITE_DEFAULT_WORKER_THREADS + "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), +#endif +#ifdef SQLITE_DIRECT_OVERFLOW_READ "DIRECT_OVERFLOW_READ", #endif -#if SQLITE_DISABLE_DIRSYNC +#ifdef SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif -#if SQLITE_DISABLE_LFS +#ifdef SQLITE_DISABLE_FTS3_UNICODE + "DISABLE_FTS3_UNICODE", +#endif +#ifdef SQLITE_DISABLE_FTS4_DEFERRED + "DISABLE_FTS4_DEFERRED", +#endif +#ifdef SQLITE_DISABLE_INTRINSIC + "DISABLE_INTRINSIC", +#endif +#ifdef SQLITE_DISABLE_LFS "DISABLE_LFS", #endif -#if SQLITE_ENABLE_8_3_NAMES +#ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS + "DISABLE_PAGECACHE_OVERFLOW_STATS", +#endif +#ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + "DISABLE_SKIPAHEAD_DISTINCT", +#endif +#ifdef SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif -#if SQLITE_ENABLE_API_ARMOR +#ifdef SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif -#if SQLITE_ENABLE_ATOMIC_WRITE +#ifdef SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif -#if SQLITE_ENABLE_CEROD - "ENABLE_CEROD", +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + "ENABLE_BATCH_ATOMIC_WRITE", +#endif +#ifdef SQLITE_ENABLE_BYTECODE_VTAB + "ENABLE_BYTECODE_VTAB", #endif -#if SQLITE_ENABLE_COLUMN_METADATA +#ifdef SQLITE_ENABLE_CEROD + "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), +#endif +#ifdef SQLITE_ENABLE_COLUMN_METADATA "ENABLE_COLUMN_METADATA", #endif -#if SQLITE_ENABLE_DBSTAT_VTAB +#ifdef SQLITE_ENABLE_COLUMN_USED_MASK + "ENABLE_COLUMN_USED_MASK", +#endif +#ifdef SQLITE_ENABLE_COSTMULT + "ENABLE_COSTMULT", +#endif +#ifdef SQLITE_ENABLE_CURSOR_HINTS + "ENABLE_CURSOR_HINTS", +#endif +#ifdef SQLITE_ENABLE_DBPAGE_VTAB + "ENABLE_DBPAGE_VTAB", +#endif +#ifdef SQLITE_ENABLE_DBSTAT_VTAB "ENABLE_DBSTAT_VTAB", #endif -#if SQLITE_ENABLE_EXPENSIVE_ASSERT +#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif -#if SQLITE_ENABLE_FTS1 - "ENABLE_FTS1", -#endif -#if SQLITE_ENABLE_FTS2 - "ENABLE_FTS2", +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + "ENABLE_EXPLAIN_COMMENTS", #endif -#if SQLITE_ENABLE_FTS3 +#ifdef SQLITE_ENABLE_FTS3 "ENABLE_FTS3", #endif -#if SQLITE_ENABLE_FTS3_PARENTHESIS +#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif -#if SQLITE_ENABLE_FTS4 +#ifdef SQLITE_ENABLE_FTS3_TOKENIZER + "ENABLE_FTS3_TOKENIZER", +#endif +#ifdef SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif -#if SQLITE_ENABLE_FTS5 +#ifdef SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif -#if SQLITE_ENABLE_ICU +#ifdef SQLITE_ENABLE_GEOPOLY + "ENABLE_GEOPOLY", +#endif +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS + "ENABLE_HIDDEN_COLUMNS", +#endif +#ifdef SQLITE_ENABLE_ICU "ENABLE_ICU", #endif -#if SQLITE_ENABLE_IOTRACE +#ifdef SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif -#if SQLITE_ENABLE_JSON1 - "ENABLE_JSON1", -#endif -#if SQLITE_ENABLE_LOAD_EXTENSION +#ifdef SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif -#if SQLITE_ENABLE_LOCKING_STYLE +#ifdef SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif -#if SQLITE_ENABLE_MEMORY_MANAGEMENT +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS + "ENABLE_MATH_FUNCTIONS", +#endif +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT "ENABLE_MEMORY_MANAGEMENT", #endif -#if SQLITE_ENABLE_MEMSYS3 +#ifdef SQLITE_ENABLE_MEMSYS3 "ENABLE_MEMSYS3", #endif -#if SQLITE_ENABLE_MEMSYS5 +#ifdef SQLITE_ENABLE_MEMSYS5 "ENABLE_MEMSYS5", #endif -#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK +#ifdef SQLITE_ENABLE_MULTIPLEX + "ENABLE_MULTIPLEX", +#endif +#ifdef SQLITE_ENABLE_NORMALIZE + "ENABLE_NORMALIZE", +#endif +#ifdef SQLITE_ENABLE_NULL_TRIM + "ENABLE_NULL_TRIM", +#endif +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + "ENABLE_OFFSET_SQL_FUNC", +#endif +#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif -#if SQLITE_ENABLE_RTREE +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + "ENABLE_PREUPDATE_HOOK", +#endif +#ifdef SQLITE_ENABLE_QPSG + "ENABLE_QPSG", +#endif +#ifdef SQLITE_ENABLE_RBU + "ENABLE_RBU", +#endif +#ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif -#if defined(SQLITE_ENABLE_STAT4) +#ifdef SQLITE_ENABLE_SELECTTRACE + "ENABLE_SELECTTRACE", +#endif +#ifdef SQLITE_ENABLE_SESSION + "ENABLE_SESSION", +#endif +#ifdef SQLITE_ENABLE_SNAPSHOT + "ENABLE_SNAPSHOT", +#endif +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + "ENABLE_SORTER_REFERENCES", +#endif +#ifdef SQLITE_ENABLE_SQLLOG + "ENABLE_SQLLOG", +#endif +#ifdef SQLITE_ENABLE_STAT4 "ENABLE_STAT4", -#elif defined(SQLITE_ENABLE_STAT3) - "ENABLE_STAT3", #endif -#if SQLITE_ENABLE_UNLOCK_NOTIFY +#ifdef SQLITE_ENABLE_STMTVTAB + "ENABLE_STMTVTAB", +#endif +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + "ENABLE_STMT_SCANSTATUS", +#endif +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + "ENABLE_UNKNOWN_SQL_FUNCTION", +#endif +#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", #endif -#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT "ENABLE_UPDATE_DELETE_LIMIT", #endif -#if defined(SQLITE_ENABLE_URI_00_ERROR) +#ifdef SQLITE_ENABLE_URI_00_ERROR "ENABLE_URI_00_ERROR", #endif -#if SQLITE_HAS_CODEC - "HAS_CODEC", +#ifdef SQLITE_ENABLE_VFSTRACE + "ENABLE_VFSTRACE", +#endif +#ifdef SQLITE_ENABLE_WHERETRACE + "ENABLE_WHERETRACE", +#endif +#ifdef SQLITE_ENABLE_ZIPVFS + "ENABLE_ZIPVFS", +#endif +#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS + "EXPLAIN_ESTIMATED_ROWS", +#endif +#ifdef SQLITE_EXTRA_IFNULLROW + "EXTRA_IFNULLROW", +#endif +#ifdef SQLITE_EXTRA_INIT + "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), +#endif +#ifdef SQLITE_EXTRA_SHUTDOWN + "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), +#endif +#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH + "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), +#endif +#ifdef SQLITE_FTS5_ENABLE_TEST_MI + "FTS5_ENABLE_TEST_MI", +#endif +#ifdef SQLITE_FTS5_NO_WITHOUT_ROWID + "FTS5_NO_WITHOUT_ROWID", #endif #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif -#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX - "HOMEGROWN_RECURSIVE_MUTEX", +#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX +# if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1 + "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX), +# endif #endif -#if SQLITE_IGNORE_AFP_LOCK_ERRORS +#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif -#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS +#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS "IGNORE_FLOCK_LOCK_ERRORS", #endif +#ifdef SQLITE_INLINE_MEMCPY + "INLINE_MEMCPY", +#endif #ifdef SQLITE_INT64_TYPE "INT64_TYPE", #endif +#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX + "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), +#endif #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS "LIKE_DOESNT_MATCH_BLOBS", #endif -#if SQLITE_LOCK_TRACE +#ifdef SQLITE_LOCK_TRACE "LOCK_TRACE", #endif -#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc) +#ifdef SQLITE_LOG_CACHE_SPILL + "LOG_CACHE_SPILL", +#endif +#ifdef SQLITE_MALLOC_SOFT_LIMIT + "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT), +#endif +#ifdef SQLITE_MAX_ATTACHED + "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED), +#endif +#ifdef SQLITE_MAX_COLUMN + "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN), +#endif +#ifdef SQLITE_MAX_COMPOUND_SELECT + "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT), +#endif +#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE + "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE), +#endif +#ifdef SQLITE_MAX_EXPR_DEPTH + "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH), +#endif +#ifdef SQLITE_MAX_FUNCTION_ARG + "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG), +#endif +#ifdef SQLITE_MAX_LENGTH + "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH), +#endif +#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH + "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH), +#endif +#ifdef SQLITE_MAX_MEMORY + "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY), +#endif +#ifdef SQLITE_MAX_MMAP_SIZE "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE), #endif +#ifdef SQLITE_MAX_MMAP_SIZE_ + "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_), +#endif +#ifdef SQLITE_MAX_PAGE_COUNT + "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT), +#endif +#ifdef SQLITE_MAX_PAGE_SIZE + "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE), +#endif #ifdef SQLITE_MAX_SCHEMA_RETRY "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY), #endif -#if SQLITE_MEMDEBUG +#ifdef SQLITE_MAX_SQL_LENGTH + "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH), +#endif +#ifdef SQLITE_MAX_TRIGGER_DEPTH + "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH), +#endif +#ifdef SQLITE_MAX_VARIABLE_NUMBER + "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER), +#endif +#ifdef SQLITE_MAX_VDBE_OP + "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP), +#endif +#ifdef SQLITE_MAX_WORKER_THREADS + "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), +#endif +#ifdef SQLITE_MEMDEBUG "MEMDEBUG", #endif -#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT +#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif -#if SQLITE_NO_SYNC +#ifdef SQLITE_MMAP_READWRITE + "MMAP_READWRITE", +#endif +#ifdef SQLITE_MUTEX_NOOP + "MUTEX_NOOP", +#endif +#ifdef SQLITE_MUTEX_OMIT + "MUTEX_OMIT", +#endif +#ifdef SQLITE_MUTEX_PTHREADS + "MUTEX_PTHREADS", +#endif +#ifdef SQLITE_MUTEX_W32 + "MUTEX_W32", +#endif +#ifdef SQLITE_NEED_ERR_NAME + "NEED_ERR_NAME", +#endif +#ifdef SQLITE_NO_SYNC "NO_SYNC", #endif -#if SQLITE_OMIT_ALTERTABLE +#ifdef SQLITE_OMIT_ALTERTABLE "OMIT_ALTERTABLE", #endif -#if SQLITE_OMIT_ANALYZE +#ifdef SQLITE_OMIT_ANALYZE "OMIT_ANALYZE", #endif -#if SQLITE_OMIT_ATTACH +#ifdef SQLITE_OMIT_ATTACH "OMIT_ATTACH", #endif -#if SQLITE_OMIT_AUTHORIZATION +#ifdef SQLITE_OMIT_AUTHORIZATION "OMIT_AUTHORIZATION", #endif -#if SQLITE_OMIT_AUTOINCREMENT +#ifdef SQLITE_OMIT_AUTOINCREMENT "OMIT_AUTOINCREMENT", #endif -#if SQLITE_OMIT_AUTOINIT +#ifdef SQLITE_OMIT_AUTOINIT "OMIT_AUTOINIT", #endif -#if SQLITE_OMIT_AUTOMATIC_INDEX +#ifdef SQLITE_OMIT_AUTOMATIC_INDEX "OMIT_AUTOMATIC_INDEX", #endif -#if SQLITE_OMIT_AUTORESET +#ifdef SQLITE_OMIT_AUTORESET "OMIT_AUTORESET", #endif -#if SQLITE_OMIT_AUTOVACUUM +#ifdef SQLITE_OMIT_AUTOVACUUM "OMIT_AUTOVACUUM", #endif -#if SQLITE_OMIT_BETWEEN_OPTIMIZATION +#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION "OMIT_BETWEEN_OPTIMIZATION", #endif -#if SQLITE_OMIT_BLOB_LITERAL +#ifdef SQLITE_OMIT_BLOB_LITERAL "OMIT_BLOB_LITERAL", #endif -#if SQLITE_OMIT_BTREECOUNT - "OMIT_BTREECOUNT", -#endif -#if SQLITE_OMIT_CAST +#ifdef SQLITE_OMIT_CAST "OMIT_CAST", #endif -#if SQLITE_OMIT_CHECK +#ifdef SQLITE_OMIT_CHECK "OMIT_CHECK", #endif -#if SQLITE_OMIT_COMPLETE +#ifdef SQLITE_OMIT_COMPLETE "OMIT_COMPLETE", #endif -#if SQLITE_OMIT_COMPOUND_SELECT +#ifdef SQLITE_OMIT_COMPOUND_SELECT "OMIT_COMPOUND_SELECT", #endif -#if SQLITE_OMIT_CTE +#ifdef SQLITE_OMIT_CONFLICT_CLAUSE + "OMIT_CONFLICT_CLAUSE", +#endif +#ifdef SQLITE_OMIT_CTE "OMIT_CTE", #endif -#if SQLITE_OMIT_DATETIME_FUNCS +#if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT) "OMIT_DATETIME_FUNCS", #endif -#if SQLITE_OMIT_DECLTYPE +#ifdef SQLITE_OMIT_DECLTYPE "OMIT_DECLTYPE", #endif -#if SQLITE_OMIT_DEPRECATED +#ifdef SQLITE_OMIT_DEPRECATED "OMIT_DEPRECATED", #endif -#if SQLITE_OMIT_DISKIO +#ifdef SQLITE_OMIT_DESERIALIZE + "OMIT_DESERIALIZE", +#endif +#ifdef SQLITE_OMIT_DISKIO "OMIT_DISKIO", #endif -#if SQLITE_OMIT_EXPLAIN +#ifdef SQLITE_OMIT_EXPLAIN "OMIT_EXPLAIN", #endif -#if SQLITE_OMIT_FLAG_PRAGMAS +#ifdef SQLITE_OMIT_FLAG_PRAGMAS "OMIT_FLAG_PRAGMAS", #endif -#if SQLITE_OMIT_FLOATING_POINT +#ifdef SQLITE_OMIT_FLOATING_POINT "OMIT_FLOATING_POINT", #endif -#if SQLITE_OMIT_FOREIGN_KEY +#ifdef SQLITE_OMIT_FOREIGN_KEY "OMIT_FOREIGN_KEY", #endif -#if SQLITE_OMIT_GET_TABLE +#ifdef SQLITE_OMIT_GET_TABLE "OMIT_GET_TABLE", #endif -#if SQLITE_OMIT_INCRBLOB +#ifdef SQLITE_OMIT_HEX_INTEGER + "OMIT_HEX_INTEGER", +#endif +#ifdef SQLITE_OMIT_INCRBLOB "OMIT_INCRBLOB", #endif -#if SQLITE_OMIT_INTEGRITY_CHECK +#ifdef SQLITE_OMIT_INTEGRITY_CHECK "OMIT_INTEGRITY_CHECK", #endif -#if SQLITE_OMIT_LIKE_OPTIMIZATION +#ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS + "OMIT_INTROSPECTION_PRAGMAS", +#endif +#ifdef SQLITE_OMIT_JSON + "OMIT_JSON", +#endif +#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION "OMIT_LIKE_OPTIMIZATION", #endif -#if SQLITE_OMIT_LOAD_EXTENSION +#ifdef SQLITE_OMIT_LOAD_EXTENSION "OMIT_LOAD_EXTENSION", #endif -#if SQLITE_OMIT_LOCALTIME +#ifdef SQLITE_OMIT_LOCALTIME "OMIT_LOCALTIME", #endif -#if SQLITE_OMIT_LOOKASIDE +#ifdef SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif -#if SQLITE_OMIT_MEMORYDB +#ifdef SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif -#if SQLITE_OMIT_OR_OPTIMIZATION +#ifdef SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif -#if SQLITE_OMIT_PAGER_PRAGMAS +#ifdef SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif -#if SQLITE_OMIT_PRAGMA +#ifdef SQLITE_OMIT_PARSER_TRACE + "OMIT_PARSER_TRACE", +#endif +#ifdef SQLITE_OMIT_POPEN + "OMIT_POPEN", +#endif +#ifdef SQLITE_OMIT_PRAGMA "OMIT_PRAGMA", #endif -#if SQLITE_OMIT_PROGRESS_CALLBACK +#ifdef SQLITE_OMIT_PROGRESS_CALLBACK "OMIT_PROGRESS_CALLBACK", #endif -#if SQLITE_OMIT_QUICKBALANCE +#ifdef SQLITE_OMIT_QUICKBALANCE "OMIT_QUICKBALANCE", #endif -#if SQLITE_OMIT_REINDEX +#ifdef SQLITE_OMIT_REINDEX "OMIT_REINDEX", #endif -#if SQLITE_OMIT_SCHEMA_PRAGMAS +#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS "OMIT_SCHEMA_PRAGMAS", #endif -#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS +#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS "OMIT_SCHEMA_VERSION_PRAGMAS", #endif -#if SQLITE_OMIT_SHARED_CACHE +#ifdef SQLITE_OMIT_SHARED_CACHE "OMIT_SHARED_CACHE", #endif -#if SQLITE_OMIT_SUBQUERY +#ifdef SQLITE_OMIT_SHUTDOWN_DIRECTORIES + "OMIT_SHUTDOWN_DIRECTORIES", +#endif +#ifdef SQLITE_OMIT_SUBQUERY "OMIT_SUBQUERY", #endif -#if SQLITE_OMIT_TCL_VARIABLE +#ifdef SQLITE_OMIT_TCL_VARIABLE "OMIT_TCL_VARIABLE", #endif -#if SQLITE_OMIT_TEMPDB +#ifdef SQLITE_OMIT_TEMPDB "OMIT_TEMPDB", #endif -#if SQLITE_OMIT_TRACE - "OMIT_TRACE", +#ifdef SQLITE_OMIT_TEST_CONTROL + "OMIT_TEST_CONTROL", +#endif +#ifdef SQLITE_OMIT_TRACE +# if SQLITE_OMIT_TRACE != 1 + "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE), +# endif #endif -#if SQLITE_OMIT_TRIGGER +#ifdef SQLITE_OMIT_TRIGGER "OMIT_TRIGGER", #endif -#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION +#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION "OMIT_TRUNCATE_OPTIMIZATION", #endif -#if SQLITE_OMIT_UTF16 +#ifdef SQLITE_OMIT_UTF16 "OMIT_UTF16", #endif -#if SQLITE_OMIT_VACUUM +#ifdef SQLITE_OMIT_VACUUM "OMIT_VACUUM", #endif -#if SQLITE_OMIT_VIEW +#ifdef SQLITE_OMIT_VIEW "OMIT_VIEW", #endif -#if SQLITE_OMIT_VIRTUALTABLE +#ifdef SQLITE_OMIT_VIRTUALTABLE "OMIT_VIRTUALTABLE", #endif -#if SQLITE_OMIT_WAL +#ifdef SQLITE_OMIT_WAL "OMIT_WAL", #endif -#if SQLITE_OMIT_WSD +#ifdef SQLITE_OMIT_WSD "OMIT_WSD", #endif -#if SQLITE_OMIT_XFER_OPT +#ifdef SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif -#if SQLITE_PERFORMANCE_TRACE +#ifdef SQLITE_PCACHE_SEPARATE_HEADER + "PCACHE_SEPARATE_HEADER", +#endif +#ifdef SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif -#if SQLITE_PROXY_DEBUG +#ifdef SQLITE_POWERSAFE_OVERWRITE +# if SQLITE_POWERSAFE_OVERWRITE != 1 + "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE), +# endif +#endif +#ifdef SQLITE_PREFER_PROXY_LOCKING + "PREFER_PROXY_LOCKING", +#endif +#ifdef SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif -#if SQLITE_RTREE_INT_ONLY +#ifdef SQLITE_REVERSE_UNORDERED_SELECTS + "REVERSE_UNORDERED_SELECTS", +#endif +#ifdef SQLITE_RTREE_INT_ONLY "RTREE_INT_ONLY", #endif -#if SQLITE_SECURE_DELETE +#ifdef SQLITE_SECURE_DELETE "SECURE_DELETE", #endif -#if SQLITE_SMALL_STACK +#ifdef SQLITE_SMALL_STACK "SMALL_STACK", #endif -#if SQLITE_SOUNDEX +#ifdef SQLITE_SORTER_PMASZ + "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), +#endif +#ifdef SQLITE_SOUNDEX "SOUNDEX", #endif -#if SQLITE_SYSTEM_MALLOC +#ifdef SQLITE_STAT4_SAMPLES + "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES), +#endif +#ifdef SQLITE_STMTJRNL_SPILL + "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), +#endif +#ifdef SQLITE_SUBSTR_COMPATIBILITY + "SUBSTR_COMPATIBILITY", +#endif +#if (!defined(SQLITE_WIN32_MALLOC) \ + && !defined(SQLITE_ZERO_MALLOC) \ + && !defined(SQLITE_MEMDEBUG) \ + ) || defined(SQLITE_SYSTEM_MALLOC) "SYSTEM_MALLOC", #endif -#if SQLITE_TCL +#ifdef SQLITE_TCL "TCL", #endif -#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc) +#ifdef SQLITE_TEMP_STORE "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), #endif -#if SQLITE_TEST +#ifdef SQLITE_TEST "TEST", #endif #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), +#elif defined(THREADSAFE) + "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), +#else + "THREADSAFE=1", #endif -#if SQLITE_UNTESTABLE - "UNTESTABLE" +#ifdef SQLITE_UNLINK_AFTER_CLOSE + "UNLINK_AFTER_CLOSE", #endif -#if SQLITE_USE_ALLOCA - "USE_ALLOCA", +#ifdef SQLITE_UNTESTABLE + "UNTESTABLE", #endif -#if SQLITE_USER_AUTHENTICATION +#ifdef SQLITE_USER_AUTHENTICATION "USER_AUTHENTICATION", #endif -#if SQLITE_WIN32_MALLOC +#ifdef SQLITE_USE_ALLOCA + "USE_ALLOCA", +#endif +#ifdef SQLITE_USE_FCNTL_TRACE + "USE_FCNTL_TRACE", +#endif +#ifdef SQLITE_USE_URI + "USE_URI", +#endif +#ifdef SQLITE_VDBE_COVERAGE + "VDBE_COVERAGE", +#endif +#ifdef SQLITE_WIN32_MALLOC "WIN32_MALLOC", #endif -#if SQLITE_ZERO_MALLOC - "ZERO_MALLOC" +#ifdef SQLITE_ZERO_MALLOC + "ZERO_MALLOC", +#endif + +} ; + +SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ + *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); + return (const char**)sqlite3azCompileOpt; +} + +#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ + +/************** End of ctime.c ***********************************************/ +/************** Begin file global.c ******************************************/ +/* +** 2008 June 13 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file contains definitions of global variables and constants. +*/ +/* #include "sqliteInt.h" */ + +/* An array to map all upper-case characters into their corresponding +** lower-case character. +** +** SQLite only considers US-ASCII (or EBCDIC) characters. We do not +** handle case conversions for the UTF character set since the tables +** involved are nearly as big or bigger than SQLite itself. +*/ +SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = { +#ifdef SQLITE_ASCII + 0, 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, 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, 97, 98, 99,100,101,102,103, + 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, + 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, + 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, + 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, + 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, + 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, + 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, + 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, + 252,253,254,255, +#endif +#ifdef SQLITE_EBCDIC + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */ + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */ + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */ + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */ + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */ + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, /* 6x */ + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, /* 7x */ + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */ + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, /* 9x */ + 160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */ + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */ + 192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */ + 208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */ + 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ #endif +/* All of the upper-to-lower conversion data is above. The following +** 18 integers are completely unrelated. They are appended to the +** sqlite3UpperToLower[] array to avoid UBSAN warnings. Here's what is +** going on: +** +** The SQL comparison operators (<>, =, >, <=, <, and >=) are implemented +** by invoking sqlite3MemCompare(A,B) which compares values A and B and +** returns negative, zero, or positive if A is less then, equal to, or +** greater than B, respectively. Then the true false results is found by +** consulting sqlite3aLTb[opcode], sqlite3aEQb[opcode], or +** sqlite3aGTb[opcode] depending on whether the result of compare(A,B) +** is negative, zero, or positive, where opcode is the specific opcode. +** The only works because the comparison opcodes are consecutive and in +** this order: NE EQ GT LE LT GE. Various assert()s throughout the code +** ensure that is the case. +** +** These elements must be appended to another array. Otherwise the +** index (here shown as [256-OP_Ne]) would be out-of-bounds and thus +** be undefined behavior. That's goofy, but the C-standards people thought +** it was a good idea, so here we are. +*/ +/* NE EQ GT LE LT GE */ + 1, 0, 0, 1, 1, 0, /* aLTb[]: Use when compare(A,B) less than zero */ + 0, 1, 0, 1, 0, 1, /* aEQb[]: Use when compare(A,B) equals zero */ + 1, 0, 1, 0, 0, 1 /* aGTb[]: Use when compare(A,B) greater than zero*/ }; +SQLITE_PRIVATE const unsigned char *sqlite3aLTb = &sqlite3UpperToLower[256-OP_Ne]; +SQLITE_PRIVATE const unsigned char *sqlite3aEQb = &sqlite3UpperToLower[256+6-OP_Ne]; +SQLITE_PRIVATE const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP_Ne]; /* -** Given the name of a compile-time option, return true if that option -** was used and false if not. +** The following 256 byte lookup table is used to support SQLites built-in +** equivalents to the following standard library functions: ** -** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix -** is not required for a match. +** isspace() 0x01 +** isalpha() 0x02 +** isdigit() 0x04 +** isalnum() 0x06 +** isxdigit() 0x08 +** toupper() 0x20 +** SQLite identifier character 0x40 +** Quote character 0x80 +** +** Bit 0x20 is set if the mapped character requires translation to upper +** case. i.e. if the character is a lower-case ASCII character. +** If x is a lower-case ASCII character, then its upper-case equivalent +** is (x - 0x20). Therefore toupper() can be implemented as: +** +** (x & ~(map[x]&0x20)) +** +** The equivalent of tolower() is implemented using the sqlite3UpperToLower[] +** array. tolower() is used more often than toupper() by SQLite. +** +** Bit 0x40 is set if the character is non-alphanumeric and can be used in an +** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any +** non-ASCII UTF character. Hence the test for whether or not a character is +** part of an identifier is 0x46. */ -SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ - int i, n; +SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */ + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */ + 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */ + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */ + 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */ -#if SQLITE_ENABLE_API_ARMOR - if( zOptName==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } + 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */ + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */ + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */ + 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */ + 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */ + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */ + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */ + 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */ + + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */ + + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ +}; + +/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards +** compatibility for legacy applications, the URI filename capability is +** disabled by default. +** +** EVIDENCE-OF: R-38799-08373 URI filenames can be enabled or disabled +** using the SQLITE_USE_URI=1 or SQLITE_USE_URI=0 compile-time options. +** +** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** SQLITE_USE_URI symbol defined. +*/ +#ifndef SQLITE_USE_URI +# define SQLITE_USE_URI 0 #endif - if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; - n = sqlite3Strlen30(zOptName); - /* Since ArraySize(azCompileOpt) is normally in single digits, a - ** linear search is adequate. No need for a binary search. */ - for(i=0; i=0 && NaDb[] (or -1) */ + i8 iDb; /* Index of cursor database in db->aDb[] */ u8 nullRow; /* True if pointing to a row with no data */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ u8 isTable; /* True for rowid tables. False for indexes */ @@ -17957,9 +22114,13 @@ struct VdbeCursor { Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ - Btree *pBtx; /* Separate file holding temporary table */ + Bool hasBeenDuped:1; /* This cursor was source or target of OP_OpenDup */ + u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */ + union { /* pBtx for isEphermeral. pAltMap otherwise */ + Btree *pBtx; /* Separate file holding temporary table */ + u32 *aAltMap; /* Mapping from table to index column numbers */ + } ub; i64 seqCount; /* Sequence counter */ - int *aAltMap; /* Mapping from table to index column numbers */ /* Cached OP_Column parse information is only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of @@ -17968,18 +22129,18 @@ struct VdbeCursor { u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0 ** if there have been no prior seeks on the cursor. */ - /* NB: seekResult does not distinguish between "no seeks have ever occurred - ** on this cursor" and "the most recent seek was an exact match". */ + /* seekResult does not distinguish between "no seeks have ever occurred + ** on this cursor" and "the most recent seek was an exact match". + ** For CURTYPE_PSEUDO, seekResult is the register holding the record */ /* When a new VdbeCursor is allocated, only the fields above are zeroed. ** The fields that follow are uninitialized, and must be individually ** initialized prior to first use. */ VdbeCursor *pAltCursor; /* Associated index cursor from which to read */ union { - BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */ - sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */ - int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */ - VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */ + BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */ + sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */ + VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */ } uc; KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ u32 iHdrOffset; /* Offset to next unparsed byte of the header */ @@ -18011,7 +22172,7 @@ struct VdbeCursor { ** When a sub-program is executed (OP_Program), a structure of this type ** is allocated to store the current value of the program counter, as ** well as the current memory cell array and various other frame specific -** values stored in the Vdbe struct. When the sub-program is finished, +** values stored in the Vdbe struct. When the sub-program is finished, ** these values are copied back to the Vdbe from the VdbeFrame structure, ** restoring the state of the VM to as it was before the sub-program ** began executing. @@ -18036,19 +22197,30 @@ struct VdbeFrame { i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ + u8 *aOnce; /* Bitmask used by OP_Once */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ +#if SQLITE_DEBUG + u32 iFrameMagic; /* magic number for sanity checking */ +#endif int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ - int nChange; /* Statement changes (Vdbe.nChange) */ - int nDbChange; /* Value of db->nChange */ + i64 nChange; /* Statement changes (Vdbe.nChange) */ + i64 nDbChange; /* Value of db->nChange */ }; +/* Magic number for sanity checking on VdbeFrame objects */ +#define SQLITE_FRAME_MAGIC 0x879fb71e + +/* +** Return a pointer to the array of registers allocated for use +** by a VdbeFrame. +*/ #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* @@ -18056,14 +22228,13 @@ struct VdbeFrame { ** structures. Each Mem struct may cache multiple representations (string, ** integer etc.) of the same value. */ -struct Mem { +struct sqlite3_value { union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ - int nZero; /* Used when bit MEM_Zero is set in flags */ + int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ + const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ - RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ - VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ } u; u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ @@ -18078,7 +22249,7 @@ struct Mem { void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ - void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */ + u16 mScopyFlags; /* flags value immediately after the shallow copy */ #endif }; @@ -18092,25 +22263,26 @@ struct Mem { ** representations of the value stored in the Mem struct. ** ** If the MEM_Null flag is set, then the value is an SQL NULL value. -** No other flags may be set in this case. +** For a pointer type created using sqlite3_bind_pointer() or +** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set. ** ** If the MEM_Str flag is set then Mem.z points at a string representation. ** Usually this is encoded in the same unicode encoding as the main ** database (see below for exceptions). If the MEM_Term flag is also -** set, then the string is nul terminated. The MEM_Int and MEM_Real +** set, then the string is nul terminated. The MEM_Int and MEM_Real ** flags may coexist with the MEM_Str flag. */ -#define MEM_Null 0x0001 /* Value is NULL */ +#define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ -#define MEM_AffMask 0x001f /* Mask of affinity bits */ -#define MEM_RowSet 0x0020 /* Value is a RowSet object */ -#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ +#define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */ +#define MEM_AffMask 0x003f /* Mask of affinity bits */ +#define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ -#define MEM_TypeMask 0x81ff /* Mask of type bits */ +#define MEM_TypeMask 0xc1bf /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of @@ -18118,7 +22290,7 @@ struct Mem { ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated */ -#define MEM_Term 0x0200 /* String rep is nul terminated */ +#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */ #define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ #define MEM_Static 0x0800 /* Mem.z points to a static string */ #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ @@ -18134,7 +22306,7 @@ struct Mem { ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ - (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) + (((X)->flags&(MEM_Agg|MEM_Dyn))!=0) /* ** Clear any existing type flags from a Mem and replace them with f @@ -18142,6 +22314,13 @@ struct Mem { #define MemSetTypeFlag(p, f) \ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) +/* +** True if Mem X is a NULL-nochng type. +*/ +#define MemNullNochng(X) \ + (((X)->flags&MEM_TypeMask)==(MEM_Null|MEM_Zero) \ + && (X)->n==0 && (X)->u.nZero==0) + /* ** Return true if a memory cell is not marked as invalid. This macro ** is for use inside assert() statements only. @@ -18151,18 +22330,18 @@ struct Mem { #endif /* -** Each auxiliary data pointer stored by a user defined function +** Each auxiliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance ** of this structure. All such structures associated with a single VM ** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed ** when the VM is halted (if not before). */ struct AuxData { - int iOp; /* Instruction number of OP_Function opcode */ - int iArg; /* Index of function argument. */ + int iAuxOp; /* Instruction number of OP_Function opcode */ + int iAuxArg; /* Index of function argument. */ void *pAux; /* Aux data pointer */ - void (*xDelete)(void *); /* Destructor for the aux data */ - AuxData *pNext; /* Next element in list */ + void (*xDeleteAux)(void*); /* Destructor for the aux data */ + AuxData *pNextAux; /* Next element in list */ }; /* @@ -18186,7 +22365,6 @@ struct sqlite3_context { int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ u8 skipFlag; /* Skip accumulator loading if true */ - u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */ u8 argc; /* Number of arguments */ sqlite3_value *argv[1]; /* Argument set */ }; @@ -18196,6 +22374,9 @@ struct sqlite3_context { */ typedef unsigned bft; /* Bit Field Type */ +/* The ScanStatus object holds a single value for the +** sqlite3_stmt_scanstatus() interface. +*/ typedef struct ScanStatus ScanStatus; struct ScanStatus { int addrExplain; /* OP_Explain for loop */ @@ -18206,6 +22387,19 @@ struct ScanStatus { char *zName; /* Name of table or index */ }; +/* The DblquoteStr object holds the text of a double-quoted +** string for a prepared statement. A linked list of these objects +** is constructed during statement parsing and is held on Vdbe.pDblStr. +** When computing a normalized SQL statement for an SQL statement, that +** list is consulted for each double-quoted identifier to see if the +** identifier should really be a string literal. +*/ +typedef struct DblquoteStr DblquoteStr; +struct DblquoteStr { + DblquoteStr *pNextStr; /* Next string literal in the list */ + char z[8]; /* Dequoted value for the string */ +}; + /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. @@ -18218,54 +22412,60 @@ struct Vdbe { Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ Parse *pParse; /* Parsing context used to create this Vdbe */ ynVar nVar; /* Number of entries in aVar[] */ - u32 magic; /* Magic number for sanity checking */ + u32 iVdbeMagic; /* Magic number defining state of the SQL statement */ int nMem; /* Number of memory locations currently allocated */ int nCursor; /* Number of slots in apCsr[] */ u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ - int nChange; /* Number of db changes made since last reset */ - int iStatement; /* Statement number (or 0 if has not opened stmt) */ + i64 nChange; /* Number of db changes made since last reset */ + int iStatement; /* Statement number (or 0 if has no opened stmt) */ i64 iCurrentTime; /* Value of julianday('now') for this statement */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */ + Mem *aMem; /* The memory locations */ + Mem **apArg; /* Arguments to currently executing user function */ + VdbeCursor **apCsr; /* One element of this array for each open cursor */ + Mem *aVar; /* Values for the OP_Variable opcode. */ /* When allocating a new Vdbe object, all of the fields below should be ** initialized to zero or NULL */ Op *aOp; /* Space to hold the virtual machine's program */ - Mem *aMem; /* The memory locations */ - Mem **apArg; /* Arguments to currently executing user function */ + int nOp; /* Number of instructions in the program */ + int nOpAlloc; /* Slots allocated for aOp[] */ Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ char *zErrMsg; /* Error message written here */ - VdbeCursor **apCsr; /* One element of this array for each open cursor */ - Mem *aVar; /* Values for the OP_Variable opcode. */ VList *pVList; /* Name of variables */ #ifndef SQLITE_OMIT_TRACE i64 startTime; /* Time when query started - used for profiling */ #endif - int nOp; /* Number of instructions in the program */ #ifdef SQLITE_DEBUG int rcApp; /* errcode set by sqlite3_result_error_code() */ + u32 nWrite; /* Number of write operations that have occurred */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ - bft expired:1; /* True if the VM needs to be recompiled */ - bft doingRerun:1; /* True if rerunning after an auto-reprepare */ + u8 prepFlags; /* SQLITE_PREPARE_* flags */ + u8 doingRerun; /* True if rerunning after an auto-reprepare */ + bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* True if EXPLAIN present on SQL command */ bft changeCntOn:1; /* True to update the change-counter */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ - bft isPrepareV2:1; /* True if prepared with prepare_v2() */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ - u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */ + u32 aCounter[9]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ +#ifdef SQLITE_ENABLE_NORMALIZE + char *zNormSql; /* Normalization of the associated SQL statement */ + DblquoteStr *pDblStr; /* List of double-quoted string literals */ +#endif void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ @@ -18290,7 +22490,7 @@ struct Vdbe { #define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */ /* -** Structure used to store the context required by the +** Structure used to store the context required by the ** sqlite3_preupdate_*() API functions. */ struct PreUpdate { @@ -18302,36 +22502,61 @@ struct PreUpdate { UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */ int iNewReg; /* Register for new.* values */ + int iBlobWrite; /* Value returned by preupdate_blobwrite() */ i64 iKey1; /* First key value passed to hook */ i64 iKey2; /* Second key value passed to hook */ Mem *aNew; /* Array of new.* values */ - Table *pTab; /* Schema object being upated */ + Table *pTab; /* Schema object being upated */ Index *pPk; /* PK index if pTab is WITHOUT ROWID */ }; +/* +** An instance of this object is used to pass an vector of values into +** OP_VFilter, the xFilter method of a virtual table. The vector is the +** set of values on the right-hand side of an IN constraint. +** +** The value as passed into xFilter is an sqlite3_value with a "pointer" +** type, such as is generated by sqlite3_result_pointer() and read by +** sqlite3_value_pointer. Such values have MEM_Term|MEM_Subtype|MEM_Null +** and a subtype of 'p'. The sqlite3_vtab_in_first() and _next() interfaces +** know how to use this object to step through all the values in the +** right operand of the IN constraint. +*/ +typedef struct ValueList ValueList; +struct ValueList { + BtCursor *pCsr; /* An ephemeral table holding all values */ + sqlite3_value *pOut; /* Register to hold each decoded output value */ +}; + /* ** Function prototypes */ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...); SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*); void sqliteVdbePopStack(Vdbe*,int); -SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*); +SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*); +SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*); SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*); -#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) -SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*); -#endif SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32); SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8); -SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*); SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32); -SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); +SQLITE_PRIVATE void sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*); SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*); SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*); +#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB) +SQLITE_PRIVATE int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**); +SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3*,Op*); +#endif +#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) +SQLITE_PRIVATE char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*); +#endif +#if !defined(SQLITE_OMIT_EXPLAIN) SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*); +#endif SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int); SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*); @@ -18339,37 +22564,58 @@ SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*); SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*); -SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); +SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); #ifdef SQLITE_OMIT_FLOATING_POINT # define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64 #else SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double); #endif +SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*); +#ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int); -SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*); -SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); -SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); -SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*); +#else +SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int); +#endif +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*); +#endif +SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); +SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); +SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem*); SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); +SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull); SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*); -SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8); +SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem*,u8,u8); SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(BtCursor*,u32,Mem*); SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p); SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*); +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*); +#endif +#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB) SQLITE_PRIVATE const char *sqlite3OpcodeName(int); +#endif SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int); -SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame*); +#endif +SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */ +SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK -SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int); +SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( + Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int); #endif SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); @@ -18377,12 +22623,20 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); -SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *); SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); -#if !defined(SQLITE_OMIT_SHARED_CACHE) +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*); +SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*); +#else +# define sqlite3VdbeIncrWriteCounter(V,C) +# define sqlite3VdbeAssertAbortable(V) +#endif + +#if !defined(SQLITE_OMIT_SHARED_CACHE) SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*); #else # define sqlite3VdbeEnter(X) @@ -18405,12 +22659,14 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int); # define sqlite3VdbeCheckFk(p,i) 0 #endif -SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*); -SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); +SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr); +#endif +#ifndef SQLITE_OMIT_UTF16 +SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8); +SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); #endif -SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem); #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *); @@ -18531,7 +22787,6 @@ SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){ : sqlite3MallocMutex()) ); assert( op==SQLITE_STATUS_MALLOC_SIZE || op==SQLITE_STATUS_PAGECACHE_SIZE - || op==SQLITE_STATUS_SCRATCH_SIZE || op==SQLITE_STATUS_PARSER_STACK ); if( newValue>wsdStat.mxValue[op] ){ wsdStat.mxValue[op] = newValue; @@ -18580,6 +22835,32 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF return rc; } +/* +** Return the number of LookasideSlot elements on the linked list +*/ +static u32 countLookasideSlots(LookasideSlot *p){ + u32 cnt = 0; + while( p ){ + p = p->pNext; + cnt++; + } + return cnt; +} + +/* +** Count the number of slots of lookaside memory that are outstanding +*/ +SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){ + u32 nInit = countLookasideSlots(db->lookaside.pInit); + u32 nFree = countLookasideSlots(db->lookaside.pFree); +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + nInit += countLookasideSlots(db->lookaside.pSmallInit); + nFree += countLookasideSlots(db->lookaside.pSmallFree); +#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ + if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit; + return db->lookaside.nSlot - (nInit+nFree); +} + /* ** Query status information for a single database connection */ @@ -18599,10 +22880,24 @@ SQLITE_API int sqlite3_db_status( sqlite3_mutex_enter(db->mutex); switch( op ){ case SQLITE_DBSTATUS_LOOKASIDE_USED: { - *pCurrent = db->lookaside.nOut; - *pHighwater = db->lookaside.mxOut; + *pCurrent = sqlite3LookasideUsed(db, pHighwater); if( resetFlag ){ - db->lookaside.mxOut = db->lookaside.nOut; + LookasideSlot *p = db->lookaside.pFree; + if( p ){ + while( p->pNext ) p = p->pNext; + p->pNext = db->lookaside.pInit; + db->lookaside.pInit = db->lookaside.pFree; + db->lookaside.pFree = 0; + } +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + p = db->lookaside.pSmallFree; + if( p ){ + while( p->pNext ) p = p->pNext; + p->pNext = db->lookaside.pSmallInit; + db->lookaside.pSmallInit = db->lookaside.pSmallFree; + db->lookaside.pSmallFree = 0; + } +#endif } break; } @@ -18623,7 +22918,7 @@ SQLITE_API int sqlite3_db_status( break; } - /* + /* ** Return an approximation for the amount of memory currently used ** by all pagers associated with the given database connection. The ** highwater mark is meaningless and is returned as zero. @@ -18667,7 +22962,7 @@ SQLITE_API int sqlite3_db_status( HashElem *p; nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( - pSchema->tblHash.count + pSchema->tblHash.count + pSchema->trigHash.count + pSchema->idxHash.count + pSchema->fkeyHash.count @@ -18717,9 +23012,12 @@ SQLITE_API int sqlite3_db_status( /* ** Set *pCurrent to the total cache hits or misses encountered by all - ** pagers the database handle is connected to. *pHighwater is always set + ** pagers the database handle is connected to. *pHighwater is always set ** to zero. */ + case SQLITE_DBSTATUS_CACHE_SPILL: + op = SQLITE_DBSTATUS_CACHE_WRITE+1; + /* no break */ deliberate_fall_through case SQLITE_DBSTATUS_CACHE_HIT: case SQLITE_DBSTATUS_CACHE_MISS: case SQLITE_DBSTATUS_CACHE_WRITE:{ @@ -18773,7 +23071,7 @@ SQLITE_API int sqlite3_db_status( ** ************************************************************************* ** This file contains the C functions that implement date and time -** functions for SQLite. +** functions for SQLite. ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. @@ -18782,7 +23080,7 @@ SQLITE_API int sqlite3_db_status( ** SQLite processes all times and dates as julian day numbers. The ** dates and times are stored as the number of days since noon ** in Greenwich on November 24, 4714 B.C. according to the Gregorian -** calendar system. +** calendar system. ** ** 1970-01-01 00:00:00 is JD 2440587.5 ** 2000-01-01 00:00:00 is JD 2451544.5 @@ -18802,7 +23100,7 @@ SQLITE_API int sqlite3_db_status( ** ** Jean Meeus ** Astronomical Algorithms, 2nd Edition, 1998 -** ISBM 0-943396-61-1 +** ISBN 0-943396-61-1 ** Willmann-Bell, Inc ** Richmond, Virginia (USA) */ @@ -19130,7 +23428,7 @@ static void setRawDateNumber(DateTime *p, double r){ ** The following are acceptable forms for the input string: ** ** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM -** DDDD.DD +** DDDD.DD ** now ** ** In the first form, the +/-HH:MM is always optional. The fractional @@ -19140,8 +23438,8 @@ static void setRawDateNumber(DateTime *p, double r){ ** as there is a year and date. */ static int parseDateOrTime( - sqlite3_context *context, - const char *zDate, + sqlite3_context *context, + const char *zDate, DateTime *p ){ double r; @@ -19149,9 +23447,9 @@ static int parseDateOrTime( return 0; }else if( parseHhMmSs(zDate, p)==0 ){ return 0; - }else if( sqlite3StrICmp(zDate,"now")==0){ + }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); - }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ + }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ setRawDateNumber(p, r); return 0; } @@ -19162,7 +23460,7 @@ static int parseDateOrTime( ** Multiplying this by 86400000 gives 464269060799999 as the maximum value ** for DateTime.iJD. ** -** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with +** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with ** such a large integer literal, so we have to encode it. */ #define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff) @@ -19186,8 +23484,10 @@ static void computeYMD(DateTime *p){ p->Y = 2000; p->M = 1; p->D = 1; + }else if( !validJulianDay(p->iJD) ){ + datetimeError(p); + return; }else{ - assert( validJulianDay(p->iJD) ); Z = (int)((p->iJD + 43200000)/86400000); A = (int)((Z - 1867216.25)/36524.25); A = Z + 1 + A - (A/4); @@ -19242,14 +23542,14 @@ static void clearYMD_HMS_TZ(DateTime *p){ #ifndef SQLITE_OMIT_LOCALTIME /* ** On recent Windows platforms, the localtime_s() function is available -** as part of the "Secure CRT". It is essentially equivalent to -** localtime_r() available under most POSIX platforms, except that the +** as part of the "Secure CRT". It is essentially equivalent to +** localtime_r() available under most POSIX platforms, except that the ** order of the parameters is reversed. ** ** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx. ** ** If the user has not indicated to use localtime_r() or localtime_s() -** already, check for an MSVC build environment that provides +** already, check for an MSVC build environment that provides ** localtime_s(). */ #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \ @@ -19264,8 +23564,10 @@ static void clearYMD_HMS_TZ(DateTime *p){ ** is available. This routine returns 0 on success and ** non-zero on any kind of error. ** -** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this -** routine will always fail. +** If the sqlite3GlobalConfig.bLocaltimeFault variable is non-zero then this +** routine will always fail. If bLocaltimeFault is nonzero and +** sqlite3GlobalConfig.xAltLocaltime is not NULL, then xAltLocaltime() is +** invoked in place of the OS-defined localtime() function. ** ** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C ** library function localtime_r() is used to assist in the calculation of @@ -19276,19 +23578,35 @@ static int osLocaltime(time_t *t, struct tm *pTm){ #if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S struct tm *pX; #if SQLITE_THREADSAFE>0 - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif sqlite3_mutex_enter(mutex); pX = localtime(t); #ifndef SQLITE_UNTESTABLE - if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; + if( sqlite3GlobalConfig.bLocaltimeFault ){ + if( sqlite3GlobalConfig.xAltLocaltime!=0 + && 0==sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm) + ){ + pX = pTm; + }else{ + pX = 0; + } + } #endif if( pX ) *pTm = *pX; +#if SQLITE_THREADSAFE>0 sqlite3_mutex_leave(mutex); +#endif rc = pX==0; #else #ifndef SQLITE_UNTESTABLE - if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; + if( sqlite3GlobalConfig.bLocaltimeFault ){ + if( sqlite3GlobalConfig.xAltLocaltime!=0 ){ + return sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm); + }else{ + return 1; + } + } #endif #if HAVE_LOCALTIME_R rc = localtime_r(t, pTm)==0; @@ -19303,67 +23621,56 @@ static int osLocaltime(time_t *t, struct tm *pTm){ #ifndef SQLITE_OMIT_LOCALTIME /* -** Compute the difference (in milliseconds) between localtime and UTC -** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs, -** return this value and set *pRc to SQLITE_OK. -** -** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value -** is undefined in this case. +** Assuming the input DateTime is UTC, move it to its localtime equivalent. */ -static sqlite3_int64 localtimeOffset( - DateTime *p, /* Date at which to calculate offset */ - sqlite3_context *pCtx, /* Write error here if one occurs */ - int *pRc /* OUT: Error code. SQLITE_OK or ERROR */ +static int toLocaltime( + DateTime *p, /* Date at which to calculate offset */ + sqlite3_context *pCtx /* Write error here if one occurs */ ){ - DateTime x, y; time_t t; struct tm sLocal; + int iYearDiff; /* Initialize the contents of sLocal to avoid a compiler warning. */ memset(&sLocal, 0, sizeof(sLocal)); - x = *p; - computeYMD_HMS(&x); - if( x.Y<1971 || x.Y>=2038 ){ + computeJD(p); + if( p->iJD<2108667600*(i64)100000 /* 1970-01-01 */ + || p->iJD>2130141456*(i64)100000 /* 2038-01-18 */ + ){ /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only ** works for years between 1970 and 2037. For dates outside this range, ** SQLite attempts to map the year into an equivalent year within this ** range, do the calculation, then map the year back. */ - x.Y = 2000; - x.M = 1; - x.D = 1; - x.h = 0; - x.m = 0; - x.s = 0.0; - } else { - int s = (int)(x.s + 0.5); - x.s = s; + DateTime x = *p; + computeYMD_HMS(&x); + iYearDiff = (2000 + x.Y%4) - x.Y; + x.Y += iYearDiff; + x.validJD = 0; + computeJD(&x); + t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); + }else{ + iYearDiff = 0; + t = (time_t)(p->iJD/1000 - 21086676*(i64)10000); } - x.tz = 0; - x.validJD = 0; - computeJD(&x); - t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); if( osLocaltime(&t, &sLocal) ){ sqlite3_result_error(pCtx, "local time unavailable", -1); - *pRc = SQLITE_ERROR; - return 0; + return SQLITE_ERROR; } - y.Y = sLocal.tm_year + 1900; - y.M = sLocal.tm_mon + 1; - y.D = sLocal.tm_mday; - y.h = sLocal.tm_hour; - y.m = sLocal.tm_min; - y.s = sLocal.tm_sec; - y.validYMD = 1; - y.validHMS = 1; - y.validJD = 0; - y.rawS = 0; - y.validTZ = 0; - y.isError = 0; - computeJD(&y); - *pRc = SQLITE_OK; - return y.iJD - x.iJD; + p->Y = sLocal.tm_year + 1900 - iYearDiff; + p->M = sLocal.tm_mon + 1; + p->D = sLocal.tm_mday; + p->h = sLocal.tm_hour; + p->m = sLocal.tm_min; + p->s = sLocal.tm_sec + (p->iJD%1000)*0.001; + p->validYMD = 1; + p->validHMS = 1; + p->validJD = 0; + p->rawS = 0; + p->validTZ = 0; + p->isError = 0; + return SQLITE_OK; } #endif /* SQLITE_OMIT_LOCALTIME */ @@ -19376,18 +23683,17 @@ static sqlite3_int64 localtimeOffset( ** of several units of time. */ static const struct { - u8 eType; /* Transformation type code */ - u8 nName; /* Length of th name */ - char *zName; /* Name of the transformation */ - double rLimit; /* Maximum NNN value for this transform */ - double rXform; /* Constant used for this transform */ + u8 nName; /* Length of the name */ + char zName[7]; /* Name of the transformation */ + float rLimit; /* Maximum NNN value for this transform */ + float rXform; /* Constant used for this transform */ } aXformType[] = { - { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) }, - { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) }, - { 0, 4, "hour", 128963628.0, 86400000.0/24.0 }, - { 0, 3, "day", 5373485.0, 86400000.0 }, - { 1, 5, "month", 176546.0, 30.0*86400000.0 }, - { 2, 4, "year", 14713.0, 365.0*86400000.0 }, + { 6, "second", 4.6427e+14, 1.0 }, + { 6, "minute", 7.7379e+12, 60.0 }, + { 4, "hour", 1.2897e+11, 3600.0 }, + { 3, "day", 5373485.0, 86400.0 }, + { 5, "month", 176546.0, 2592000.0 }, + { 4, "year", 14713.0, 31536000.0 }, }; /* @@ -19418,11 +23724,55 @@ static int parseModifier( sqlite3_context *pCtx, /* Function context */ const char *z, /* The text of the modifier */ int n, /* Length of zMod in bytes */ - DateTime *p /* The date/time value to be modified */ + DateTime *p, /* The date/time value to be modified */ + int idx /* Parameter index of the modifier */ ){ int rc = 1; double r; switch(sqlite3UpperToLower[(u8)z[0]] ){ + case 'a': { + /* + ** auto + ** + ** If rawS is available, then interpret as a julian day number, or + ** a unix timestamp, depending on its magnitude. + */ + if( sqlite3_stricmp(z, "auto")==0 ){ + if( idx>1 ) return 1; /* IMP: R-33611-57934 */ + if( !p->rawS || p->validJD ){ + rc = 0; + p->rawS = 0; + }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */ + && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */ + ){ + r = p->s*1000.0 + 210866760000000.0; + clearYMD_HMS_TZ(p); + p->iJD = (sqlite3_int64)(r + 0.5); + p->validJD = 1; + p->rawS = 0; + rc = 0; + } + } + break; + } + case 'j': { + /* + ** julianday + ** + ** Always interpret the prior number as a julian-day value. If this + ** is not the first modifier, or if the prior argument is not a numeric + ** value in the allowed range of julian day numbers understood by + ** SQLite (0..5373484.5) then the result will be NULL. + */ + if( sqlite3_stricmp(z, "julianday")==0 ){ + if( idx>1 ) return 1; /* IMP: R-31176-64601 */ + if( p->validJD && p->rawS ){ + rc = 0; + p->rawS = 0; + } + } + break; + } #ifndef SQLITE_OMIT_LOCALTIME case 'l': { /* localtime @@ -19430,10 +23780,8 @@ static int parseModifier( ** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** show local time. */ - if( sqlite3_stricmp(z, "localtime")==0 ){ - computeJD(p); - p->iJD += localtimeOffset(p, pCtx, &rc); - clearYMD_HMS_TZ(p); + if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ + rc = toLocaltime(p, pCtx); } break; } @@ -19446,30 +23794,44 @@ static int parseModifier( ** seconds since 1970. Convert to a real julian day number. */ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ + if( idx>1 ) return 1; /* IMP: R-49255-55373 */ r = p->s*1000.0 + 210866760000000.0; if( r>=0.0 && r<464269060800000.0 ){ clearYMD_HMS_TZ(p); - p->iJD = (sqlite3_int64)r; + p->iJD = (sqlite3_int64)(r + 0.5); p->validJD = 1; p->rawS = 0; rc = 0; } } #ifndef SQLITE_OMIT_LOCALTIME - else if( sqlite3_stricmp(z, "utc")==0 ){ + else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ if( p->tzSet==0 ){ - sqlite3_int64 c1; + i64 iOrigJD; /* Original localtime */ + i64 iGuess; /* Guess at the corresponding utc time */ + int cnt = 0; /* Safety to prevent infinite loop */ + int iErr; /* Guess is off by this much */ + computeJD(p); - c1 = localtimeOffset(p, pCtx, &rc); - if( rc==SQLITE_OK ){ - p->iJD -= c1; - clearYMD_HMS_TZ(p); - p->iJD += c1 - localtimeOffset(p, pCtx, &rc); - } + iGuess = iOrigJD = p->iJD; + iErr = 0; + do{ + DateTime new; + memset(&new, 0, sizeof(new)); + iGuess -= iErr; + new.iJD = iGuess; + new.validJD = 1; + rc = toLocaltime(&new, pCtx); + if( rc ) return rc; + computeJD(&new); + iErr = new.iJD - iOrigJD; + }while( iErr && cnt++<3 ); + memset(p, 0, sizeof(*p)); + p->iJD = iGuess; + p->validJD = 1; p->tzSet = 1; - }else{ - rc = SQLITE_OK; } + rc = SQLITE_OK; } #endif break; @@ -19483,7 +23845,7 @@ static int parseModifier( ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 - && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) + && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 && (n=(int)r)==r && n>=0 && r<7 ){ sqlite3_int64 Z; computeYMD_HMS(p); @@ -19506,18 +23868,19 @@ static int parseModifier( ** or month or year. */ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break; + if( !p->validJD && !p->validYMD && !p->validHMS ) break; z += 9; computeYMD(p); p->validHMS = 1; p->h = p->m = 0; p->s = 0.0; + p->rawS = 0; p->validTZ = 0; p->validJD = 0; if( sqlite3_stricmp(z,"month")==0 ){ p->D = 1; rc = 0; }else if( sqlite3_stricmp(z,"year")==0 ){ - computeYMD(p); p->M = 1; p->D = 1; rc = 0; @@ -19541,7 +23904,7 @@ static int parseModifier( double rRounder; int i; for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} - if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ + if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ rc = 1; break; } @@ -19584,9 +23947,10 @@ static int parseModifier( && sqlite3_strnicmp(aXformType[i].zName, z, n)==0 && r>-aXformType[i].rLimit && rM += (int)r; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; @@ -19596,8 +23960,9 @@ static int parseModifier( r -= (int)r; break; } - case 2: { /* Special processing to add years */ + case 5: { /* Special processing to add years */ int y = (int)r; + assert( strcmp(aXformType[i].zName,"year")==0 ); computeYMD_HMS(p); p->Y += y; p->validJD = 0; @@ -19606,7 +23971,7 @@ static int parseModifier( } } computeJD(p); - p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder); + p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder); rc = 0; break; } @@ -19631,9 +23996,9 @@ static int parseModifier( ** then assume a default value of "now" for argv[0]. */ static int isDate( - sqlite3_context *context, - int argc, - sqlite3_value **argv, + sqlite3_context *context, + int argc, + sqlite3_value **argv, DateTime *p ){ int i, n; @@ -19641,6 +24006,7 @@ static int isDate( int eType; memset(p, 0, sizeof(*p)); if( argc==0 ){ + if( !sqlite3NotPureFunc(context) ) return 1; return setDateTimeToCurrent(context, p); } if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT @@ -19655,7 +24021,7 @@ static int isDate( for(i=1; iisError || !validJulianDay(p->iJD) ) return 1; @@ -19685,6 +24051,24 @@ static void juliandayFunc( } } +/* +** unixepoch( TIMESTRING, MOD, MOD, ...) +** +** Return the number of seconds (including fractional seconds) since +** the unix epoch of 1970-01-01 00:00:00 GMT. +*/ +static void unixepochFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + DateTime x; + if( isDate(context, argc, argv, &x)==0 ){ + computeJD(&x); + sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000); + } +} + /* ** datetime( TIMESTRING, MOD, MOD, ...) ** @@ -19697,11 +24081,38 @@ static void datetimeFunc( ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - char zBuf[100]; + int Y, s; + char zBuf[24]; computeYMD_HMS(&x); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", - x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + Y = x.Y; + if( Y<0 ) Y = -Y; + zBuf[1] = '0' + (Y/1000)%10; + zBuf[2] = '0' + (Y/100)%10; + zBuf[3] = '0' + (Y/10)%10; + zBuf[4] = '0' + (Y)%10; + zBuf[5] = '-'; + zBuf[6] = '0' + (x.M/10)%10; + zBuf[7] = '0' + (x.M)%10; + zBuf[8] = '-'; + zBuf[9] = '0' + (x.D/10)%10; + zBuf[10] = '0' + (x.D)%10; + zBuf[11] = ' '; + zBuf[12] = '0' + (x.h/10)%10; + zBuf[13] = '0' + (x.h)%10; + zBuf[14] = ':'; + zBuf[15] = '0' + (x.m/10)%10; + zBuf[16] = '0' + (x.m)%10; + zBuf[17] = ':'; + s = (int)x.s; + zBuf[18] = '0' + (s/10)%10; + zBuf[19] = '0' + (s)%10; + zBuf[20] = 0; + if( x.Y<0 ){ + zBuf[0] = '-'; + sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT); + }else{ + sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT); + } } } @@ -19717,10 +24128,20 @@ static void timeFunc( ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - char zBuf[100]; + int s; + char zBuf[16]; computeHMS(&x); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + zBuf[0] = '0' + (x.h/10)%10; + zBuf[1] = '0' + (x.h)%10; + zBuf[2] = ':'; + zBuf[3] = '0' + (x.m/10)%10; + zBuf[4] = '0' + (x.m)%10; + zBuf[5] = ':'; + s = (int)x.s; + zBuf[6] = '0' + (s/10)%10; + zBuf[7] = '0' + (s)%10; + zBuf[8] = 0; + sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT); } } @@ -19736,10 +24157,28 @@ static void dateFunc( ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ - char zBuf[100]; + int Y; + char zBuf[16]; computeYMD(&x); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); + Y = x.Y; + if( Y<0 ) Y = -Y; + zBuf[1] = '0' + (Y/1000)%10; + zBuf[2] = '0' + (Y/100)%10; + zBuf[3] = '0' + (Y/10)%10; + zBuf[4] = '0' + (Y)%10; + zBuf[5] = '-'; + zBuf[6] = '0' + (x.M/10)%10; + zBuf[7] = '0' + (x.M)%10; + zBuf[8] = '-'; + zBuf[9] = '0' + (x.D/10)%10; + zBuf[10] = '0' + (x.D)%10; + zBuf[11] = 0; + if( x.Y<0 ){ + zBuf[0] = '-'; + sqlite3_result_text(context, zBuf, 11, SQLITE_TRANSIENT); + }else{ + sqlite3_result_text(context, &zBuf[1], 10, SQLITE_TRANSIENT); + } } } @@ -19768,131 +24207,100 @@ static void strftimeFunc( sqlite3_value **argv ){ DateTime x; - u64 n; size_t i,j; - char *z; sqlite3 *db; const char *zFmt; - char zBuf[100]; + sqlite3_str sRes; + + if( argc==0 ) return; zFmt = (const char*)sqlite3_value_text(argv[0]); if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; db = sqlite3_context_db_handle(context); - for(i=0, n=1; zFmt[i]; i++, n++){ - if( zFmt[i]=='%' ){ - switch( zFmt[i+1] ){ - case 'd': - case 'H': - case 'm': - case 'M': - case 'S': - case 'W': - n++; - /* fall thru */ - case 'w': - case '%': - break; - case 'f': - n += 8; - break; - case 'j': - n += 3; - break; - case 'Y': - n += 8; - break; - case 's': - case 'J': - n += 50; - break; - default: - return; /* ERROR. return a NULL */ - } - i++; - } - } - testcase( n==sizeof(zBuf)-1 ); - testcase( n==sizeof(zBuf) ); - testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); - testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ); - if( n(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){ - sqlite3_result_error_toobig(context); - return; - }else{ - z = sqlite3DbMallocRawNN(db, (int)n); - if( z==0 ){ - sqlite3_result_error_nomem(context); - return; - } - } + sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); + computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ - if( zFmt[i]!='%' ){ - z[j++] = zFmt[i]; - }else{ - i++; - switch( zFmt[i] ){ - case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; - case 'f': { - double s = x.s; - if( s>59.999 ) s = 59.999; - sqlite3_snprintf(7, &z[j],"%06.3f", s); - j += sqlite3Strlen30(&z[j]); - break; - } - case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; - case 'W': /* Fall thru */ - case 'j': { - int nDay; /* Number of days since 1st day of year */ - DateTime y = x; - y.validJD = 0; - y.M = 1; - y.D = 1; - computeJD(&y); - nDay = (int)((x.iJD-y.iJD+43200000)/86400000); - if( zFmt[i]=='W' ){ - int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ - wd = (int)(((x.iJD+43200000)/86400000)%7); - sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); - j += 2; - }else{ - sqlite3_snprintf(4, &z[j],"%03d",nDay+1); - j += 3; - } - break; - } - case 'J': { - sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); - j+=sqlite3Strlen30(&z[j]); - break; - } - case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; - case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; - case 's': { - sqlite3_snprintf(30,&z[j],"%lld", - (i64)(x.iJD/1000 - 21086676*(i64)10000)); - j += sqlite3Strlen30(&z[j]); - break; - } - case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; - case 'w': { - z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; - break; - } - case 'Y': { - sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); - break; + if( zFmt[i]!='%' ) continue; + if( j59.999 ) s = 59.999; + sqlite3_str_appendf(&sRes, "%06.3f", s); + break; + } + case 'H': { + sqlite3_str_appendf(&sRes, "%02d", x.h); + break; + } + case 'W': /* Fall thru */ + case 'j': { + int nDay; /* Number of days since 1st day of year */ + DateTime y = x; + y.validJD = 0; + y.M = 1; + y.D = 1; + computeJD(&y); + nDay = (int)((x.iJD-y.iJD+43200000)/86400000); + if( zFmt[i]=='W' ){ + int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ + wd = (int)(((x.iJD+43200000)/86400000)%7); + sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7); + }else{ + sqlite3_str_appendf(&sRes,"%03d",nDay+1); } - default: z[j++] = '%'; break; + break; + } + case 'J': { + sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0); + break; + } + case 'm': { + sqlite3_str_appendf(&sRes,"%02d",x.M); + break; + } + case 'M': { + sqlite3_str_appendf(&sRes,"%02d",x.m); + break; + } + case 's': { + i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); + sqlite3_str_appendf(&sRes,"%lld",iS); + break; + } + case 'S': { + sqlite3_str_appendf(&sRes,"%02d",(int)x.s); + break; + } + case 'w': { + sqlite3_str_appendchar(&sRes, 1, + (char)(((x.iJD+129600000)/86400000) % 7) + '0'); + break; + } + case 'Y': { + sqlite3_str_appendf(&sRes,"%04d",x.Y); + break; + } + case '%': { + sqlite3_str_appendchar(&sRes, 1, '%'); + break; + } + default: { + sqlite3_str_reset(&sRes); + return; } } } - z[j] = 0; - sqlite3_result_text(context, z, -1, - z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC); + if( jpMethods->xSync(id, flags); + return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK; } SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ DO_OS_MALLOC_TEST(id); @@ -20137,8 +24546,13 @@ SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ ** routine has no return value since the return value would be meaningless. */ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ + if( id->pMethods==0 ) return SQLITE_NOTFOUND; #ifdef SQLITE_TEST - if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){ + if( op!=SQLITE_FCNTL_COMMIT_PHASETWO + && op!=SQLITE_FCNTL_LOCK_TIMEOUT + && op!=SQLITE_FCNTL_CKPT_DONE + && op!=SQLITE_FCNTL_CKPT_START + ){ /* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite ** is using a regular VFS, it is called after the corresponding ** transaction has been committed. Injecting a fault at this point @@ -20148,14 +24562,19 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ ** The core must call OsFileControl() though, not OsFileControlHint(), ** as if a custom VFS (e.g. zipvfs) returns an error here, it probably ** means the commit really has failed and an error should be returned - ** to the user. */ + ** to the user. + ** + ** The CKPT_DONE and CKPT_START file-controls are write-only signals + ** to the cksumvfs. Their return code is meaningless and is ignored + ** by the SQLite core, so there is no point in simulating OOMs for them. + */ DO_OS_MALLOC_TEST(id); } #endif return id->pMethods->xFileControl(id, op, pArg); } SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){ - (void)id->pMethods->xFileControl(id, op, pArg); + if( id->pMethods ) (void)id->pMethods->xFileControl(id, op, pArg); } SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){ @@ -20163,8 +24582,10 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){ return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); } SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ + if( NEVER(id->pMethods==0) ) return 0; return id->pMethods->xDeviceCharacteristics(id); } +#ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){ return id->pMethods->xShmLock(id, offset, n, flags); } @@ -20184,6 +24605,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap( DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } +#endif /* SQLITE_OMIT_WAL */ #if SQLITE_MAX_MMAP_SIZE>0 /* The real implementation of xFetch and xUnfetch */ @@ -20222,14 +24644,14 @@ SQLITE_PRIVATE int sqlite3OsOpen( ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before ** reaching the VFS. */ - rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut); + rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut); assert( rc==SQLITE_OK || pFile->pMethods==0 ); return rc; } SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ DO_OS_MALLOC_TEST(0); assert( dirSync==0 || dirSync==1 ); - return pVfs->xDelete(pVfs, zPath, dirSync); + return pVfs->xDelete!=0 ? pVfs->xDelete(pVfs, zPath, dirSync) : SQLITE_OK; } SQLITE_PRIVATE int sqlite3OsAccess( sqlite3_vfs *pVfs, @@ -20252,6 +24674,8 @@ SQLITE_PRIVATE int sqlite3OsFullPathname( } #ifndef SQLITE_OMIT_LOAD_EXTENSION SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ + assert( zPath!=0 ); + assert( strlen(zPath)<=SQLITE_MAX_PATHLEN ); /* tag-20210611-1 */ return pVfs->xDlOpen(pVfs, zPath); } SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ @@ -20265,7 +24689,15 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){ } #endif /* SQLITE_OMIT_LOAD_EXTENSION */ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ - return pVfs->xRandomness(pVfs, nByte, zBufOut); + if( sqlite3Config.iPrngSeed ){ + memset(zBufOut, 0, nByte); + if( ALWAYS(nByte>(signed)sizeof(unsigned)) ) nByte = sizeof(unsigned int); + memcpy(zBufOut, &sqlite3Config.iPrngSeed, nByte); + return SQLITE_OK; + }else{ + return pVfs->xRandomness(pVfs, nByte, zBufOut); + } + } SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){ return pVfs->xSleep(pVfs, nMicro); @@ -20305,12 +24737,15 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc( rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); if( rc!=SQLITE_OK ){ sqlite3_free(pFile); + *ppFile = 0; }else{ *ppFile = pFile; } }else{ + *ppFile = 0; rc = SQLITE_NOMEM_BKPT; } + assert( *ppFile!=0 || rc!=SQLITE_OK ); return rc; } SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){ @@ -20352,7 +24787,7 @@ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ if( rc ) return 0; #endif #if SQLITE_THREADSAFE - mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif sqlite3_mutex_enter(mutex); for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){ @@ -20367,7 +24802,7 @@ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){ ** Unlink a VFS from the linked list */ static void vfsUnlink(sqlite3_vfs *pVfs){ - assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) ); + assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) ); if( pVfs==0 ){ /* No-op */ }else if( vfsList==pVfs ){ @@ -20398,7 +24833,7 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ if( pVfs==0 ) return SQLITE_MISUSE_BKPT; #endif - MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) + MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); if( makeDflt || vfsList==0 ){ @@ -20417,9 +24852,12 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){ ** Unregister a VFS so that it is no longer accessible. */ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ -#if SQLITE_THREADSAFE - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + MUTEX_LOGIC(sqlite3_mutex *mutex;) +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return rc; #endif + MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); sqlite3_mutex_leave(mutex); @@ -20440,17 +24878,17 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){ ** ************************************************************************* ** -** This file contains code to support the concept of "benign" +** This file contains code to support the concept of "benign" ** malloc failures (when the xMalloc() or xRealloc() method of the ** sqlite3_mem_methods structure fails to allocate a block of memory -** and returns 0). +** and returns 0). ** ** Most malloc failures are non-benign. After they occur, SQLite ** abandons the current operation and returns an error code (usually ** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily -** fatal. For example, if a malloc fails while resizing a hash table, this -** is completely recoverable simply by not carrying out the resize. The -** hash table will continue to function normally. So a malloc failure +** fatal. For example, if a malloc fails while resizing a hash table, this +** is completely recoverable simply by not carrying out the resize. The +** hash table will continue to function normally. So a malloc failure ** during a hash table resize is a benign fault. */ @@ -20639,7 +25077,9 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ */ #include #include +#ifdef SQLITE_MIGHT_BE_SINGLE_CORE #include +#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */ static malloc_zone_t* _sqliteZone_; #define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x)) #define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x)); @@ -20650,7 +25090,7 @@ static malloc_zone_t* _sqliteZone_; #else /* if not __APPLE__ */ /* -** Use standard C library malloc and free on non-Apple systems. +** Use standard C library malloc and free on non-Apple systems. ** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined. */ #define SQLITE_MALLOC(x) malloc(x) @@ -20830,21 +25270,12 @@ static int sqlite3MemInit(void *NotUsed){ /* defer MT decisions to system malloc */ _sqliteZone_ = malloc_default_zone(); }else{ - /* only 1 core, use our own zone to contention over global locks, + /* only 1 core, use our own zone to contention over global locks, ** e.g. we have our own dedicated locks */ - bool success; - malloc_zone_t* newzone = malloc_create_zone(4096, 0); - malloc_set_zone_name(newzone, "Sqlite_Heap"); - do{ - success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone, - (void * volatile *)&_sqliteZone_); - }while(!_sqliteZone_); - if( !success ){ - /* somebody registered a zone first */ - malloc_destroy_zone(newzone); - } + _sqliteZone_ = malloc_create_zone(4096, 0); + malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap"); } -#endif +#endif /* defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */ UNUSED_PARAMETER(NotUsed); return SQLITE_OK; } @@ -20963,7 +25394,7 @@ struct MemBlockHdr { ** when this module is combined with other in the amalgamation. */ static struct { - + /* ** Mutex to control access to the memory allocation subsystem. */ @@ -20974,7 +25405,7 @@ static struct { */ struct MemBlockHdr *pFirst; struct MemBlockHdr *pLast; - + /* ** The number of levels of backtrace to save in new allocations. */ @@ -20987,7 +25418,7 @@ static struct { int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ char zTitle[100]; /* The title text */ - /* + /* ** sqlite3MallocDisallow() increments the following counter. ** sqlite3MallocAllow() decrements it. */ @@ -21032,7 +25463,7 @@ static void adjustStats(int iSize, int increment){ ** This routine checks the guards at either end of the allocation and ** if they are incorrect it asserts. */ -static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ +static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){ struct MemBlockHdr *p; int *pInt; u8 *pU8; @@ -21046,7 +25477,7 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ pU8 = (u8*)pAllocation; assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD ); /* This checks any of the "extra" bytes allocated due - ** to rounding up to an 8 byte boundary to ensure + ** to rounding up to an 8 byte boundary to ensure ** they haven't been overwritten. */ while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 ); @@ -21175,7 +25606,7 @@ static void *sqlite3MemMalloc(int nByte){ p = (void*)pInt; } sqlite3_mutex_leave(mem.mutex); - return p; + return p; } /* @@ -21185,7 +25616,7 @@ static void sqlite3MemFree(void *pPrior){ struct MemBlockHdr *pHdr; void **pBt; char *z; - assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0 + assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0 || mem.mutex!=0 ); pHdr = sqlite3MemsysGetHeader(pPrior); pBt = (void**)pHdr; @@ -21211,15 +25642,15 @@ static void sqlite3MemFree(void *pPrior){ randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + (int)pHdr->iSize + sizeof(int) + pHdr->nTitle); free(z); - sqlite3_mutex_leave(mem.mutex); + sqlite3_mutex_leave(mem.mutex); } /* ** Change the size of an existing memory allocation. ** ** For this debugging implementation, we *always* make a copy of the -** allocation into a new place in memory. In this way, if the -** higher level code is using pointer to the old allocation, it is +** allocation into a new place in memory. In this way, if the +** higher level code is using pointer to the old allocation, it is ** much more likely to break and we are much more liking to find ** the error. */ @@ -21262,7 +25693,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){ ** Set the "type" of an allocation. */ SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){ - if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ + if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); @@ -21279,9 +25710,9 @@ SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){ ** ** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); */ -SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ +SQLITE_PRIVATE int sqlite3MemdebugHasType(const void *p, u8 eType){ int rc = 1; - if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ + if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ @@ -21301,9 +25732,9 @@ SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){ ** ** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); */ -SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){ +SQLITE_PRIVATE int sqlite3MemdebugNoType(const void *p, u8 eType){ int rc = 1; - if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ + if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ struct MemBlockHdr *pHdr; pHdr = sqlite3MemsysGetHeader(p); assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ @@ -21353,7 +25784,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSync(){ } /* -** Open the file indicated and write a log of all unfreed memory +** Open the file indicated and write a log of all unfreed memory ** allocations into that log. */ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){ @@ -21370,7 +25801,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){ for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ char *z = (char*)pHdr; z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; - fprintf(out, "**** %lld bytes at %p from %s ****\n", + fprintf(out, "**** %lld bytes at %p from %s ****\n", pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); if( pHdr->nBacktrace ){ fflush(out); @@ -21383,7 +25814,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){ fprintf(out, "COUNTS:\n"); for(i=0; i=nBlock ); - if( nBlock>=mem3.szMaster-1 ){ - /* Use the entire master */ - void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster); - mem3.iMaster = 0; - mem3.szMaster = 0; - mem3.mnMaster = 0; + assert( mem3.szKeyBlk>=nBlock ); + if( nBlock>=mem3.szKeyBlk-1 ){ + /* Use the entire key chunk */ + void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk); + mem3.iKeyBlk = 0; + mem3.szKeyBlk = 0; + mem3.mnKeyBlk = 0; return p; }else{ - /* Split the master block. Return the tail. */ + /* Split the key block. Return the tail. */ u32 newi, x; - newi = mem3.iMaster + mem3.szMaster - nBlock; - assert( newi > mem3.iMaster+1 ); - mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock; - mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2; + newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock; + assert( newi > mem3.iKeyBlk+1 ); + mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock; + mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2; mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; - mem3.szMaster -= nBlock; - mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster; - x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; - mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; - if( mem3.szMaster < mem3.mnMaster ){ - mem3.mnMaster = mem3.szMaster; + mem3.szKeyBlk -= nBlock; + mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk; + x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; + mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; + if( mem3.szKeyBlk < mem3.mnKeyBlk ){ + mem3.mnKeyBlk = mem3.szKeyBlk; } return (void*)&mem3.aPool[newi]; } @@ -21713,18 +26144,18 @@ static void *memsys3FromMaster(u32 nBlock){ /* ** *pRoot is the head of a list of free chunks of the same size ** or same size hash. In other words, *pRoot is an entry in either -** mem3.aiSmall[] or mem3.aiHash[]. +** mem3.aiSmall[] or mem3.aiHash[]. ** ** This routine examines all entries on the given list and tries -** to coalesce each entries with adjacent free chunks. +** to coalesce each entries with adjacent free chunks. ** -** If it sees a chunk that is larger than mem3.iMaster, it replaces -** the current mem3.iMaster with the new larger chunk. In order for -** this mem3.iMaster replacement to work, the master chunk must be +** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces +** the current mem3.iKeyBlk with the new larger chunk. In order for +** this mem3.iKeyBlk replacement to work, the key chunk must be ** linked into the hash tables. That is not the normal state of -** affairs, of course. The calling routine must link the master +** affairs, of course. The calling routine must link the key ** chunk before invoking this routine, then must unlink the (possibly -** changed) master chunk once this routine has finished. +** changed) key chunk once this routine has finished. */ static void memsys3Merge(u32 *pRoot){ u32 iNext, prev, size, i, x; @@ -21751,9 +26182,9 @@ static void memsys3Merge(u32 *pRoot){ }else{ size /= 4; } - if( size>mem3.szMaster ){ - mem3.iMaster = i; - mem3.szMaster = size; + if( size>mem3.szKeyBlk ){ + mem3.iKeyBlk = i; + mem3.szKeyBlk = size; } } } @@ -21802,26 +26233,26 @@ static void *memsys3MallocUnsafe(int nByte){ /* STEP 2: ** Try to satisfy the allocation by carving a piece off of the end - ** of the master chunk. This step usually works if step 1 fails. + ** of the key chunk. This step usually works if step 1 fails. */ - if( mem3.szMaster>=nBlock ){ - return memsys3FromMaster(nBlock); + if( mem3.szKeyBlk>=nBlock ){ + return memsys3FromKeyBlk(nBlock); } - /* STEP 3: + /* STEP 3: ** Loop through the entire memory pool. Coalesce adjacent free - ** chunks. Recompute the master chunk as the largest free chunk. + ** chunks. Recompute the key chunk as the largest free chunk. ** Then try again to satisfy the allocation by carving a piece off - ** of the end of the master chunk. This step happens very + ** of the end of the key chunk. This step happens very ** rarely (we hope!) */ for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){ memsys3OutOfMemory(toFree); - if( mem3.iMaster ){ - memsys3Link(mem3.iMaster); - mem3.iMaster = 0; - mem3.szMaster = 0; + if( mem3.iKeyBlk ){ + memsys3Link(mem3.iKeyBlk); + mem3.iKeyBlk = 0; + mem3.szKeyBlk = 0; } for(i=0; i=nBlock ){ - return memsys3FromMaster(nBlock); + if( mem3.szKeyBlk ){ + memsys3Unlink(mem3.iKeyBlk); + if( mem3.szKeyBlk>=nBlock ){ + return memsys3FromKeyBlk(nBlock); } } } @@ -21862,23 +26293,23 @@ static void memsys3FreeUnsafe(void *pOld){ mem3.aPool[i+size-1].u.hdr.size4x &= ~2; memsys3Link(i); - /* Try to expand the master using the newly freed chunk */ - if( mem3.iMaster ){ - while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){ - size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize; - mem3.iMaster -= size; - mem3.szMaster += size; - memsys3Unlink(mem3.iMaster); - x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; - mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; - mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; + /* Try to expand the key using the newly freed chunk */ + if( mem3.iKeyBlk ){ + while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){ + size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize; + mem3.iKeyBlk -= size; + mem3.szKeyBlk += size; + memsys3Unlink(mem3.iKeyBlk); + x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; + mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; + mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk; } - x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; - while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){ - memsys3Unlink(mem3.iMaster+mem3.szMaster); - mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4; - mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; - mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; + x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2; + while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){ + memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk); + mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4; + mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x; + mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk; } } } @@ -21916,7 +26347,7 @@ static void *memsys3Malloc(int nBytes){ memsys3Enter(); p = memsys3MallocUnsafe(nBytes); memsys3Leave(); - return (void*)p; + return (void*)p; } /* @@ -21974,11 +26405,11 @@ static int memsys3Init(void *NotUsed){ mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap; mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2; - /* Initialize the master block. */ - mem3.szMaster = mem3.nPool; - mem3.mnMaster = mem3.szMaster; - mem3.iMaster = 1; - mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2; + /* Initialize the key block. */ + mem3.szKeyBlk = mem3.nPool; + mem3.mnKeyBlk = mem3.szKeyBlk; + mem3.iKeyBlk = 1; + mem3.aPool[0].u.hdr.size4x = (mem3.szKeyBlk<<2) + 2; mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool; mem3.aPool[mem3.nPool].u.hdr.size4x = 1; @@ -21997,7 +26428,7 @@ static void memsys3Shutdown(void *NotUsed){ /* -** Open the file indicated and write a log of all unfreed memory +** Open the file indicated and write a log of all unfreed memory ** allocations into that log. */ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){ @@ -22038,7 +26469,7 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){ fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8); }else{ fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8, - i==mem3.iMaster ? " **master**" : ""); + i==mem3.iKeyBlk ? " **key**" : ""); } } for(i=0; i= M*(1 + log2(n)/2) - n + 1 @@ -22155,7 +26586,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){ /* #include "sqliteInt.h" */ /* -** This version of the memory allocator is used only when +** This version of the memory allocator is used only when ** SQLITE_ENABLE_MEMSYS5 is defined. */ #ifdef SQLITE_ENABLE_MEMSYS5 @@ -22200,7 +26631,7 @@ static SQLITE_WSD struct Mem5Global { int szAtom; /* Smallest possible allocation in bytes */ int nBlock; /* Number of szAtom sized blocks in zPool */ u8 *zPool; /* Memory available to be allocated */ - + /* ** Mutex to control access to the memory allocation subsystem. */ @@ -22219,7 +26650,7 @@ static SQLITE_WSD struct Mem5Global { u32 maxCount; /* Maximum instantaneous currentCount */ u32 maxRequest; /* Largest allocation (exclusive of internal frag) */ #endif - + /* ** Lists of free blocks. aiFreelist[0] is a list of free blocks of ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2. @@ -22395,7 +26826,7 @@ static void memsys5FreeUnsafe(void *pOld){ u32 size, iLogsize; int iBlock; - /* Set iBlock to the index of the block pointed to by pOld in + /* Set iBlock to the index of the block pointed to by pOld in ** the array of mem5.szAtom byte blocks pointed to by mem5.zPool. */ iBlock = (int)(((u8 *)pOld-mem5.zPool)/mem5.szAtom); @@ -22464,7 +26895,7 @@ static void *memsys5Malloc(int nBytes){ p = memsys5MallocUnsafe(nBytes); memsys5Leave(); } - return (void*)p; + return (void*)p; } /* @@ -22477,14 +26908,14 @@ static void memsys5Free(void *pPrior){ assert( pPrior!=0 ); memsys5Enter(); memsys5FreeUnsafe(pPrior); - memsys5Leave(); + memsys5Leave(); } /* ** Change the size of an existing memory allocation. ** ** The outer layer memory allocator prevents this routine from -** being called with pPrior==0. +** being called with pPrior==0. ** ** nBytes is always a value obtained from a prior call to ** memsys5Round(). Hence nBytes is always a non-negative power @@ -22617,7 +27048,7 @@ static void memsys5Shutdown(void *NotUsed){ #ifdef SQLITE_TEST /* -** Open the file indicated and write a log of all unfreed memory +** Open the file indicated and write a log of all unfreed memory ** allocations into that log. */ SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){ @@ -22659,7 +27090,7 @@ SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){ #endif /* -** This routine is the only routine in this file with external +** This routine is the only routine in this file with external ** linkage. It returns a pointer to a static sqlite3_mem_methods ** struct populated with the memsys5 methods. */ @@ -22709,14 +27140,201 @@ static SQLITE_WSD int mutexIsInit = 0; #ifndef SQLITE_MUTEX_OMIT + +#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +/* +** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains +** the implementation of a wrapper around the system default mutex +** implementation (sqlite3DefaultMutex()). +** +** Most calls are passed directly through to the underlying default +** mutex implementation. Except, if a mutex is configured by calling +** sqlite3MutexWarnOnContention() on it, then if contention is ever +** encountered within xMutexEnter() a warning is emitted via sqlite3_log(). +** +** This type of mutex is used as the database handle mutex when testing +** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. +*/ + +/* +** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS +** is defined. Variable CheckMutex.mutex is a pointer to the real mutex +** allocated by the system mutex implementation. Variable iType is usually set +** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST +** or one of the static mutex identifiers. Or, if this is a recursive mutex +** that has been configured using sqlite3MutexWarnOnContention(), it is +** set to SQLITE_MUTEX_WARNONCONTENTION. +*/ +typedef struct CheckMutex CheckMutex; +struct CheckMutex { + int iType; + sqlite3_mutex *mutex; +}; + +#define SQLITE_MUTEX_WARNONCONTENTION (-1) + +/* +** Pointer to real mutex methods object used by the CheckMutex +** implementation. Set by checkMutexInit(). +*/ +static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods; + +#ifdef SQLITE_DEBUG +static int checkMutexHeld(sqlite3_mutex *p){ + return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex); +} +static int checkMutexNotheld(sqlite3_mutex *p){ + return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex); +} +#endif + +/* +** Initialize and deinitialize the mutex subsystem. +*/ +static int checkMutexInit(void){ + pGlobalMutexMethods = sqlite3DefaultMutex(); + return SQLITE_OK; +} +static int checkMutexEnd(void){ + pGlobalMutexMethods = 0; + return SQLITE_OK; +} + +/* +** Allocate a mutex. +*/ +static sqlite3_mutex *checkMutexAlloc(int iType){ + static CheckMutex staticMutexes[] = { + {2, 0}, {3, 0}, {4, 0}, {5, 0}, + {6, 0}, {7, 0}, {8, 0}, {9, 0}, + {10, 0}, {11, 0}, {12, 0}, {13, 0} + }; + CheckMutex *p = 0; + + assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 ); + if( iType<2 ){ + p = sqlite3MallocZero(sizeof(CheckMutex)); + if( p==0 ) return 0; + p->iType = iType; + }else{ +#ifdef SQLITE_ENABLE_API_ARMOR + if( iType-2>=ArraySize(staticMutexes) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + p = &staticMutexes[iType-2]; + } + + if( p->mutex==0 ){ + p->mutex = pGlobalMutexMethods->xMutexAlloc(iType); + if( p->mutex==0 ){ + if( iType<2 ){ + sqlite3_free(p); + } + p = 0; + } + } + + return (sqlite3_mutex*)p; +} + +/* +** Free a mutex. +*/ +static void checkMutexFree(sqlite3_mutex *p){ + assert( SQLITE_MUTEX_RECURSIVE<2 ); + assert( SQLITE_MUTEX_FAST<2 ); + assert( SQLITE_MUTEX_WARNONCONTENTION<2 ); + +#if SQLITE_ENABLE_API_ARMOR + if( ((CheckMutex*)p)->iType<2 ) +#endif + { + CheckMutex *pCheck = (CheckMutex*)p; + pGlobalMutexMethods->xMutexFree(pCheck->mutex); + sqlite3_free(pCheck); + } +#ifdef SQLITE_ENABLE_API_ARMOR + else{ + (void)SQLITE_MISUSE_BKPT; + } +#endif +} + +/* +** Enter the mutex. +*/ +static void checkMutexEnter(sqlite3_mutex *p){ + CheckMutex *pCheck = (CheckMutex*)p; + if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){ + if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){ + return; + } + sqlite3_log(SQLITE_MISUSE, + "illegal multi-threaded access to database connection" + ); + } + pGlobalMutexMethods->xMutexEnter(pCheck->mutex); +} + +/* +** Enter the mutex (do not block). +*/ +static int checkMutexTry(sqlite3_mutex *p){ + CheckMutex *pCheck = (CheckMutex*)p; + return pGlobalMutexMethods->xMutexTry(pCheck->mutex); +} + +/* +** Leave the mutex. +*/ +static void checkMutexLeave(sqlite3_mutex *p){ + CheckMutex *pCheck = (CheckMutex*)p; + pGlobalMutexMethods->xMutexLeave(pCheck->mutex); +} + +sqlite3_mutex_methods const *multiThreadedCheckMutex(void){ + static const sqlite3_mutex_methods sMutex = { + checkMutexInit, + checkMutexEnd, + checkMutexAlloc, + checkMutexFree, + checkMutexEnter, + checkMutexTry, + checkMutexLeave, +#ifdef SQLITE_DEBUG + checkMutexHeld, + checkMutexNotheld +#else + 0, + 0 +#endif + }; + return &sMutex; +} + +/* +** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as +** one on which there should be no contention. +*/ +SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){ + if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){ + CheckMutex *pCheck = (CheckMutex*)p; + assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE ); + pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION; + } +} +#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */ + /* ** Initialize the mutex system. */ -SQLITE_PRIVATE int sqlite3MutexInit(void){ +SQLITE_PRIVATE int sqlite3MutexInit(void){ int rc = SQLITE_OK; if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){ /* If the xMutexAlloc method has not been set, then the user did not - ** install a mutex implementation via sqlite3_config() prior to + ** install a mutex implementation via sqlite3_config() prior to ** sqlite3_initialize() being called. This block copies pointers to ** the default implementation into the sqlite3GlobalConfig structure. */ @@ -22724,7 +27342,11 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; if( sqlite3GlobalConfig.bCoreMutex ){ +#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS + pFrom = multiThreadedCheckMutex(); +#else pFrom = sqlite3DefaultMutex(); +#endif }else{ pFrom = sqlite3NoopMutex(); } @@ -22746,6 +27368,7 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){ GLOBAL(int, mutexIsInit) = 1; #endif + sqlite3MemoryBarrier(); return rc; } @@ -22823,7 +27446,7 @@ SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){ /* ** The sqlite3_mutex_leave() routine exits a mutex that was previously -** entered by the same thread. The behavior is undefined if the mutex +** entered by the same thread. The behavior is undefined if the mutex ** is not currently entered. If a NULL pointer is passed as an argument ** this function is a no-op. */ @@ -22892,9 +27515,9 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){ */ static int noopMutexInit(void){ return SQLITE_OK; } static int noopMutexEnd(void){ return SQLITE_OK; } -static sqlite3_mutex *noopMutexAlloc(int id){ +static sqlite3_mutex *noopMutexAlloc(int id){ UNUSED_PARAMETER(id); - return (sqlite3_mutex*)8; + return (sqlite3_mutex*)8; } static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; } @@ -22959,7 +27582,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; } /* ** The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. If it returns NULL -** that means that a mutex could not be allocated. +** that means that a mutex could not be allocated. */ static sqlite3_mutex *debugMutexAlloc(int id){ static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1]; @@ -23123,11 +27746,12 @@ struct sqlite3_mutex { #endif }; #if SQLITE_MUTEX_NREF -#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0} +# define SQLITE3_MUTEX_INITIALIZER(id) \ + {PTHREAD_MUTEX_INITIALIZER,id,0,(pthread_t)0,0} #elif defined(SQLITE_ENABLE_API_ARMOR) -#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 } +# define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER, id } #else -#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER } +#define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER } #endif /* @@ -23136,7 +27760,7 @@ struct sqlite3_mutex { ** there might be race conditions that can cause these routines to ** deliver incorrect results. In particular, if pthread_equal() is ** not an atomic operation, then these routines might delivery -** incorrect results. On most platforms, pthread_equal() is a +** incorrect results. On most platforms, pthread_equal() is a ** comparison of two integers and is therefore atomic. But we are ** told that HPUX is not such a platform. If so, then these routines ** will not always work correctly on HPUX. @@ -23184,7 +27808,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; } **
          **
        • SQLITE_MUTEX_FAST **
        • SQLITE_MUTEX_RECURSIVE -**
        • SQLITE_MUTEX_STATIC_MASTER +**
        • SQLITE_MUTEX_STATIC_MAIN **
        • SQLITE_MUTEX_STATIC_MEM **
        • SQLITE_MUTEX_STATIC_OPEN **
        • SQLITE_MUTEX_STATIC_PRNG @@ -23218,24 +27842,24 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; } ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() -** returns a different mutex on every call. But for the static +** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ static sqlite3_mutex *pthreadMutexAlloc(int iType){ static sqlite3_mutex staticMutexes[] = { - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER + SQLITE3_MUTEX_INITIALIZER(2), + SQLITE3_MUTEX_INITIALIZER(3), + SQLITE3_MUTEX_INITIALIZER(4), + SQLITE3_MUTEX_INITIALIZER(5), + SQLITE3_MUTEX_INITIALIZER(6), + SQLITE3_MUTEX_INITIALIZER(7), + SQLITE3_MUTEX_INITIALIZER(8), + SQLITE3_MUTEX_INITIALIZER(9), + SQLITE3_MUTEX_INITIALIZER(10), + SQLITE3_MUTEX_INITIALIZER(11), + SQLITE3_MUTEX_INITIALIZER(12), + SQLITE3_MUTEX_INITIALIZER(13) }; sqlite3_mutex *p; switch( iType ){ @@ -23253,6 +27877,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&p->mutex, &recursiveAttr); pthread_mutexattr_destroy(&recursiveAttr); +#endif +#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) + p->id = SQLITE_MUTEX_RECURSIVE; #endif } break; @@ -23261,6 +27888,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ p = sqlite3MallocZero( sizeof(*p) ); if( p ){ pthread_mutex_init(&p->mutex, 0); +#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) + p->id = SQLITE_MUTEX_FAST; +#endif } break; } @@ -23276,7 +27906,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ } } #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) - if( p ) p->id = iType; + assert( p==0 || p->id==iType ); #endif return p; } @@ -23323,7 +27953,7 @@ static void pthreadMutexEnter(sqlite3_mutex *p){ ** is atomic - that it cannot be deceived into thinking self ** and p->owner are equal if p->owner changes between two values ** that are not equal to self while the comparison is taking place. - ** This implementation also assumes a coherent cache - that + ** This implementation also assumes a coherent cache - that ** separate processes cannot read different values from the same ** address at the same time. If either of these two conditions ** are not met, then the mutexes will fail and problems will result. @@ -23366,7 +27996,7 @@ static int pthreadMutexTry(sqlite3_mutex *p){ ** is atomic - that it cannot be deceived into thinking self ** and p->owner are equal if p->owner changes between two values ** that are not equal to self while the comparison is taking place. - ** This implementation also assumes a coherent cache - that + ** This implementation also assumes a coherent cache - that ** separate processes cannot read different values from the same ** address at the same time. If either of these two conditions ** are not met, then the mutexes will fail and problems will result. @@ -23480,205 +28110,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ /* ** Include code that is common to all os_*.c files */ -/************** Include os_common.h in the middle of mutex_w32.c *************/ -/************** Begin file os_common.h ***************************************/ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains macros and a little bit of code that is common to -** all of the platform-specific files (os_*.c) and is #included into those -** files. -** -** This file should be #included by the os_*.c files only. It is not a -** general purpose header file. -*/ -#ifndef _OS_COMMON_H_ -#define _OS_COMMON_H_ - -/* -** At least two bugs have slipped in because we changed the MEMORY_DEBUG -** macro to SQLITE_DEBUG and some older makefiles have not yet made the -** switch. The following code should catch this problem at compile-time. -*/ -#ifdef MEMORY_DEBUG -# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." -#endif - -/* -** Macros for performance tracing. Normally turned off. Only works -** on i486 hardware. -*/ -#ifdef SQLITE_PERFORMANCE_TRACE - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -/************** Include hwtime.h in the middle of os_common.h ****************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 class CPUs. -*/ -#ifndef SQLITE_HWTIME_H -#define SQLITE_HWTIME_H - -/* -** The following routine only works on pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. -*/ -#if (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long val; - __asm__ __volatile__ ("rdtsc" : "=A" (val)); - return val; - } - -#elif (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - #error Need implementation of sqlite3Hwtime() for your platform. - - /* - ** To compile without implementing sqlite3Hwtime() for your platform, - ** you can remove the above #error and use the following - ** stub function. You will lose timing support for many - ** of the debugging and testing utilities, but it should at - ** least compile and run. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in os_common.h ******************/ - -static sqlite_uint64 g_start; -static sqlite_uint64 g_elapsed; -#define TIMER_START g_start=sqlite3Hwtime() -#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start -#define TIMER_ELAPSED g_elapsed -#else -#define TIMER_START -#define TIMER_END -#define TIMER_ELAPSED ((sqlite_uint64)0) -#endif - -/* -** If we compile with the SQLITE_TEST macro set, then the following block -** of code will give us the ability to simulate a disk I/O error. This -** is used for testing the I/O recovery logic. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_io_error_hit; -SQLITE_API extern int sqlite3_io_error_hardhit; -SQLITE_API extern int sqlite3_io_error_pending; -SQLITE_API extern int sqlite3_io_error_persist; -SQLITE_API extern int sqlite3_io_error_benign; -SQLITE_API extern int sqlite3_diskfull_pending; -SQLITE_API extern int sqlite3_diskfull; -#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) -#define SimulateIOError(CODE) \ - if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ - || sqlite3_io_error_pending-- == 1 ) \ - { local_ioerr(); CODE; } -static void local_ioerr(){ - IOTRACE(("IOERR\n")); - sqlite3_io_error_hit++; - if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; -} -#define SimulateDiskfullError(CODE) \ - if( sqlite3_diskfull_pending ){ \ - if( sqlite3_diskfull_pending == 1 ){ \ - local_ioerr(); \ - sqlite3_diskfull = 1; \ - sqlite3_io_error_hit = 1; \ - CODE; \ - }else{ \ - sqlite3_diskfull_pending--; \ - } \ - } -#else -#define SimulateIOErrorBenign(X) -#define SimulateIOError(A) -#define SimulateDiskfullError(A) -#endif /* defined(SQLITE_TEST) */ - -/* -** When testing, keep a count of the number of open files. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_open_file_count; -#define OpenCounter(X) sqlite3_open_file_count+=(X) -#else -#define OpenCounter(X) -#endif /* defined(SQLITE_TEST) */ - -#endif /* !defined(_OS_COMMON_H_) */ - -/************** End of os_common.h *******************************************/ -/************** Continuing where we left off in mutex_w32.c ******************/ +/* #include "os_common.h" */ /* ** Include the header file for the Windows VFS. @@ -23793,7 +28225,7 @@ struct sqlite3_mutex { #ifdef SQLITE_DEBUG volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ - volatile int trace; /* True to trace changes */ + volatile LONG trace; /* True to trace changes */ #endif }; @@ -23805,10 +28237,10 @@ struct sqlite3_mutex { #define SQLITE_W32_MUTEX_INITIALIZER { 0 } #ifdef SQLITE_DEBUG -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \ +#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \ 0L, (DWORD)0, 0 } #else -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } +#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id } #endif #ifdef SQLITE_DEBUG @@ -23851,18 +28283,18 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){ ** Initialize and deinitialize the mutex subsystem. */ static sqlite3_mutex winMutex_staticMutexes[] = { - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER, - SQLITE3_MUTEX_INITIALIZER + SQLITE3_MUTEX_INITIALIZER(2), + SQLITE3_MUTEX_INITIALIZER(3), + SQLITE3_MUTEX_INITIALIZER(4), + SQLITE3_MUTEX_INITIALIZER(5), + SQLITE3_MUTEX_INITIALIZER(6), + SQLITE3_MUTEX_INITIALIZER(7), + SQLITE3_MUTEX_INITIALIZER(8), + SQLITE3_MUTEX_INITIALIZER(9), + SQLITE3_MUTEX_INITIALIZER(10), + SQLITE3_MUTEX_INITIALIZER(11), + SQLITE3_MUTEX_INITIALIZER(12), + SQLITE3_MUTEX_INITIALIZER(13) }; static int winMutex_isInit = 0; @@ -23924,7 +28356,7 @@ static int winMutexEnd(void){ **
            **
          • SQLITE_MUTEX_FAST **
          • SQLITE_MUTEX_RECURSIVE -**
          • SQLITE_MUTEX_STATIC_MASTER +**
          • SQLITE_MUTEX_STATIC_MAIN **
          • SQLITE_MUTEX_STATIC_MEM **
          • SQLITE_MUTEX_STATIC_OPEN **
          • SQLITE_MUTEX_STATIC_PRNG @@ -23992,15 +28424,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){ } #endif p = &winMutex_staticMutexes[iType-2]; - p->id = iType; #ifdef SQLITE_DEBUG #ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC - p->trace = 1; + InterlockedCompareExchange(&p->trace, 1, 0); #endif #endif break; } } + assert( p==0 || p->id==iType ); return p; } @@ -24051,8 +28483,8 @@ static void winMutexEnter(sqlite3_mutex *p){ p->owner = tid; p->nRef++; if( p->trace ){ - OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", - tid, p, p->trace, p->nRef)); + OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", + tid, p->id, p, p->trace, p->nRef)); } #endif } @@ -24094,8 +28526,8 @@ static int winMutexTry(sqlite3_mutex *p){ #endif #ifdef SQLITE_DEBUG if( p->trace ){ - OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n", - tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); + OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n", + tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); } #endif return rc; @@ -24123,8 +28555,8 @@ static void winMutexLeave(sqlite3_mutex *p){ LeaveCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG if( p->trace ){ - OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", - tid, p, p->trace, p->nRef)); + OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n", + tid, p->id, p, p->trace, p->nRef)); } #endif } @@ -24188,12 +28620,11 @@ SQLITE_API int sqlite3_release_memory(int n){ } /* -** An instance of the following object records the location of -** each unused scratch buffer. +** Default value of the hard heap limit. 0 means "no limit". */ -typedef struct ScratchFreeslot { - struct ScratchFreeslot *pNext; /* Next unused scratch buffer */ -} ScratchFreeslot; +#ifndef SQLITE_MAX_MEMORY +# define SQLITE_MAX_MEMORY 0 +#endif /* ** State information local to the memory allocation subsystem. @@ -24201,23 +28632,14 @@ typedef struct ScratchFreeslot { static SQLITE_WSD struct Mem0Global { sqlite3_mutex *mutex; /* Mutex to serialize access */ sqlite3_int64 alarmThreshold; /* The soft heap limit */ - - /* - ** Pointers to the end of sqlite3GlobalConfig.pScratch memory - ** (so that a range test can be used to determine if an allocation - ** being freed came from pScratch) and a pointer to the list of - ** unused scratch allocations. - */ - void *pScratchEnd; - ScratchFreeslot *pScratchFree; - u32 nScratchFree; + sqlite3_int64 hardLimit; /* The hard upper bound on memory */ /* ** True if heap is nearly "full" where "full" is defined by the ** sqlite3_soft_heap_limit() setting. */ int nearlyFull; -} mem0 = { 0, 0, 0, 0, 0, 0 }; +} mem0 = { 0, SQLITE_MAX_MEMORY, SQLITE_MAX_MEMORY, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) @@ -24247,8 +28669,15 @@ SQLITE_API int sqlite3_memory_alarm( #endif /* -** Set the soft heap-size limit for the library. Passing a zero or -** negative value indicates no limit. +** Set the soft heap-size limit for the library. An argument of +** zero disables the limit. A negative argument is a no-op used to +** obtain the return value. +** +** The return value is the value of the heap limit just before this +** interface was called. +** +** If the hard heap limit is enabled, then the soft heap limit cannot +** be disabled nor raised above the hard heap limit. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ sqlite3_int64 priorLimit; @@ -24264,9 +28693,12 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){ sqlite3_mutex_leave(mem0.mutex); return priorLimit; } + if( mem0.hardLimit>0 && (n>mem0.hardLimit || n==0) ){ + n = mem0.hardLimit; + } mem0.alarmThreshold = n; nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); - mem0.nearlyFull = (n>0 && n<=nUsed); + AtomicStore(&mem0.nearlyFull, n>0 && n<=nUsed); sqlite3_mutex_leave(mem0.mutex); excess = sqlite3_memory_used() - n; if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); @@ -24277,6 +28709,37 @@ SQLITE_API void sqlite3_soft_heap_limit(int n){ sqlite3_soft_heap_limit64(n); } +/* +** Set the hard heap-size limit for the library. An argument of zero +** disables the hard heap limit. A negative argument is a no-op used +** to obtain the return value without affecting the hard heap limit. +** +** The return value is the value of the hard heap limit just prior to +** calling this interface. +** +** Setting the hard heap limit will also activate the soft heap limit +** and constrain the soft heap limit to be no more than the hard heap +** limit. +*/ +SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 n){ + sqlite3_int64 priorLimit; +#ifndef SQLITE_OMIT_AUTOINIT + int rc = sqlite3_initialize(); + if( rc ) return -1; +#endif + sqlite3_mutex_enter(mem0.mutex); + priorLimit = mem0.hardLimit; + if( n>=0 ){ + mem0.hardLimit = n; + if( n=100 - && sqlite3GlobalConfig.nScratch>0 ){ - int i, n, sz; - ScratchFreeslot *pSlot; - sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch); - sqlite3GlobalConfig.szScratch = sz; - pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch; - n = sqlite3GlobalConfig.nScratch; - mem0.pScratchFree = pSlot; - mem0.nScratchFree = n; - for(i=0; ipNext = (ScratchFreeslot*)(sz+(char*)pSlot); - pSlot = pSlot->pNext; - } - pSlot->pNext = 0; - mem0.pScratchEnd = (void*)&pSlot[1]; - }else{ - mem0.pScratchEnd = 0; - sqlite3GlobalConfig.pScratch = 0; - sqlite3GlobalConfig.szScratch = 0; - sqlite3GlobalConfig.nScratch = 0; - } if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512 || sqlite3GlobalConfig.nPage<=0 ){ sqlite3GlobalConfig.pPage = 0; @@ -24325,7 +28765,7 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){ ** sqlite3_soft_heap_limit(). */ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){ - return mem0.nearlyFull; + return AtomicLoad(&mem0.nearlyFull); } /* @@ -24359,7 +28799,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ } /* -** Trigger the alarm +** Trigger the alarm */ static void sqlite3MallocAlarm(int nByte){ if( mem0.alarmThreshold<=0 ) return; @@ -24389,10 +28829,17 @@ static void mallocWithAlarm(int n, void **pp){ if( mem0.alarmThreshold>0 ){ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.alarmThreshold - nFull ){ - mem0.nearlyFull = 1; + AtomicStore(&mem0.nearlyFull, 1); sqlite3MallocAlarm(nFull); + if( mem0.hardLimit ){ + nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); + if( nUsed >= mem0.hardLimit - nFull ){ + *pp = 0; + return; + } + } }else{ - mem0.nearlyFull = 0; + AtomicStore(&mem0.nearlyFull, 0); } } p = sqlite3GlobalConfig.m.xMalloc(nFull); @@ -24452,110 +28899,11 @@ SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){ return sqlite3Malloc(n); } -/* -** Each thread may only have a single outstanding allocation from -** xScratchMalloc(). We verify this constraint in the single-threaded -** case by setting scratchAllocOut to 1 when an allocation -** is outstanding clearing it when the allocation is freed. -*/ -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) -static int scratchAllocOut = 0; -#endif - - -/* -** Allocate memory that is to be used and released right away. -** This routine is similar to alloca() in that it is not intended -** for situations where the memory might be held long-term. This -** routine is intended to get memory to old large transient data -** structures that would not normally fit on the stack of an -** embedded processor. -*/ -SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){ - void *p; - assert( n>0 ); - - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n); - if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){ - p = mem0.pScratchFree; - mem0.pScratchFree = mem0.pScratchFree->pNext; - mem0.nScratchFree--; - sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3_mutex_leave(mem0.mutex); - p = sqlite3Malloc(n); - if( sqlite3GlobalConfig.bMemstat && p ){ - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p)); - sqlite3_mutex_leave(mem0.mutex); - } - sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); - } - assert( sqlite3_mutex_notheld(mem0.mutex) ); - - -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch - ** buffers per thread. - ** - ** This can only be checked in single-threaded mode. - */ - assert( scratchAllocOut==0 ); - if( p ) scratchAllocOut++; -#endif - - return p; -} -SQLITE_PRIVATE void sqlite3ScratchFree(void *p){ - if( p ){ - -#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) - /* Verify that no more than two scratch allocation per thread - ** is outstanding at one time. (This is only checked in the - ** single-threaded case since checking in the multi-threaded case - ** would be much more complicated.) */ - assert( scratchAllocOut>=1 && scratchAllocOut<=2 ); - scratchAllocOut--; -#endif - - if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){ - /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */ - ScratchFreeslot *pSlot; - pSlot = (ScratchFreeslot*)p; - sqlite3_mutex_enter(mem0.mutex); - pSlot->pNext = mem0.pScratchFree; - mem0.pScratchFree = pSlot; - mem0.nScratchFree++; - assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch ); - sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1); - sqlite3_mutex_leave(mem0.mutex); - }else{ - /* Release memory back to the heap */ - assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) ); - assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) ); - sqlite3MemdebugSetType(p, MEMTYPE_HEAP); - if( sqlite3GlobalConfig.bMemstat ){ - int iSize = sqlite3MallocSize(p); - sqlite3_mutex_enter(mem0.mutex); - sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize); - sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize); - sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1); - sqlite3GlobalConfig.m.xFree(p); - sqlite3_mutex_leave(mem0.mutex); - }else{ - sqlite3GlobalConfig.m.xFree(p); - } - } - } -} - /* ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE -static int isLookaside(sqlite3 *db, void *p){ +static int isLookaside(sqlite3 *db, const void *p){ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd); } #else @@ -24566,14 +28914,21 @@ static int isLookaside(sqlite3 *db, void *p){ ** Return the size of a memory allocation previously obtained from ** sqlite3Malloc() or sqlite3_malloc(). */ -SQLITE_PRIVATE int sqlite3MallocSize(void *p){ +SQLITE_PRIVATE int sqlite3MallocSize(const void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); - return sqlite3GlobalConfig.m.xSize(p); + return sqlite3GlobalConfig.m.xSize((void*)p); } -SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ +static int lookasideMallocSize(sqlite3 *db, const void *p){ +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + return plookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL; +#else + return db->lookaside.szTrue; +#endif +} +SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){ assert( p!=0 ); +#ifdef SQLITE_DEBUG if( db==0 || !isLookaside(db,p) ){ -#if SQLITE_DEBUG if( db==0 ){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); @@ -24581,12 +28936,23 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); } + } #endif - return sqlite3GlobalConfig.m.xSize(p); - }else{ - assert( sqlite3_mutex_held(db->mutex) ); - return db->lookaside.sz; + if( db ){ + if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ + assert( sqlite3_mutex_held(db->mutex) ); + return LOOKASIDE_SMALL; + } +#endif + if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ + assert( sqlite3_mutex_held(db->mutex) ); + return db->lookaside.szTrue; + } + } } + return sqlite3GlobalConfig.m.xSize((void*)p); } SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); @@ -24622,26 +28988,38 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){ /* ** Free memory that might be associated with a particular database -** connection. +** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. +** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. */ -SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ +SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); - if( p==0 ) return; + assert( p!=0 ); if( db ){ if( db->pnBytesFreed ){ measureAllocationSize(db, p); return; } - if( isLookaside(db, p) ){ - LookasideSlot *pBuf = (LookasideSlot*)p; -#if SQLITE_DEBUG - /* Trash all content in the buffer being freed */ - memset(p, 0xaa, db->lookaside.sz); + if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ + LookasideSlot *pBuf = (LookasideSlot*)p; +#ifdef SQLITE_DEBUG + memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */ #endif - pBuf->pNext = db->lookaside.pFree; - db->lookaside.pFree = pBuf; - db->lookaside.nOut--; - return; + pBuf->pNext = db->lookaside.pSmallFree; + db->lookaside.pSmallFree = pBuf; + return; + } +#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ + if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ + LookasideSlot *pBuf = (LookasideSlot*)p; +#ifdef SQLITE_DEBUG + memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */ +#endif + pBuf->pNext = db->lookaside.pFree; + db->lookaside.pFree = pBuf; + return; + } } } assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); @@ -24650,6 +29028,10 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } +SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){ + assert( db==0 || sqlite3_mutex_held(db->mutex) ); + if( p ) sqlite3DbFreeNN(db, p); +} /* ** Change the size of an existing memory allocation @@ -24678,18 +29060,25 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ + sqlite3_int64 nUsed; sqlite3_mutex_enter(mem0.mutex); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; - if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= + if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); + if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){ + sqlite3_mutex_leave(mem0.mutex); + return 0; + } } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( pNew==0 && mem0.alarmThreshold>0 ){ sqlite3MallocAlarm((int)nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } +#endif if( pNew ){ nNew = sqlite3MallocSize(pNew); sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld); @@ -24723,7 +29112,7 @@ SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){ /* ** Allocate and zero memory. -*/ +*/ SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){ void *p = sqlite3Malloc(n); if( p ){ @@ -24753,13 +29142,13 @@ static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){ assert( db!=0 ); p = sqlite3Malloc(n); if( !p ) sqlite3OomFault(db); - sqlite3MemdebugSetType(p, + sqlite3MemdebugSetType(p, (db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP); return p; } /* -** Allocate memory, either lookaside (if possible) or heap. +** Allocate memory, either lookaside (if possible) or heap. ** If the allocation fails, set the mallocFailed flag in ** the connection pointer. ** @@ -24793,23 +29182,37 @@ SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){ assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( db->pnBytesFreed==0 ); - if( db->lookaside.bDisable==0 ){ - assert( db->mallocFailed==0 ); - if( n>db->lookaside.sz ){ + if( n>db->lookaside.sz ){ + if( !db->lookaside.bDisable ){ db->lookaside.anStat[1]++; - }else if( (pBuf = db->lookaside.pFree)==0 ){ - db->lookaside.anStat[2]++; - }else{ - db->lookaside.pFree = pBuf->pNext; - db->lookaside.nOut++; + }else if( db->mallocFailed ){ + return 0; + } + return dbMallocRawFinish(db, n); + } +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + if( n<=LOOKASIDE_SMALL ){ + if( (pBuf = db->lookaside.pSmallFree)!=0 ){ + db->lookaside.pSmallFree = pBuf->pNext; + db->lookaside.anStat[0]++; + return (void*)pBuf; + }else if( (pBuf = db->lookaside.pSmallInit)!=0 ){ + db->lookaside.pSmallInit = pBuf->pNext; db->lookaside.anStat[0]++; - if( db->lookaside.nOut>db->lookaside.mxOut ){ - db->lookaside.mxOut = db->lookaside.nOut; - } return (void*)pBuf; } - }else if( db->mallocFailed ){ - return 0; + } +#endif + if( (pBuf = db->lookaside.pFree)!=0 ){ + db->lookaside.pFree = pBuf->pNext; + db->lookaside.anStat[0]++; + return (void*)pBuf; + }else if( (pBuf = db->lookaside.pInit)!=0 ){ + db->lookaside.pInit = pBuf->pNext; + db->lookaside.anStat[0]++; + return (void*)pBuf; + }else{ + db->lookaside.anStat[2]++; } #else assert( db!=0 ); @@ -24833,7 +29236,16 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){ assert( db!=0 ); if( p==0 ) return sqlite3DbMallocRawNN(db, n); assert( sqlite3_mutex_held(db->mutex) ); - if( isLookaside(db,p) && n<=db->lookaside.sz ) return p; + if( ((uptr)p)<(uptr)db->lookaside.pEnd ){ +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + if( ((uptr)p)>=(uptr)db->lookaside.pMiddle ){ + if( n<=LOOKASIDE_SMALL ) return p; + }else +#endif + if( ((uptr)p)>=(uptr)db->lookaside.pStart ){ + if( n<=db->lookaside.szTrue ) return p; + } + } return dbReallocFinish(db, p, n); } static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){ @@ -24844,14 +29256,14 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){ if( isLookaside(db, p) ){ pNew = sqlite3DbMallocRawNN(db, n); if( pNew ){ - memcpy(pNew, p, db->lookaside.sz); + memcpy(pNew, p, lookasideMallocSize(db, p)); sqlite3DbFree(db, p); } }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); - pNew = sqlite3_realloc64(p, n); + pNew = sqlite3Realloc(p, n); if( !pNew ){ sqlite3OomFault(db); } @@ -24876,9 +29288,9 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){ } /* -** Make a copy of a string in memory obtained from sqliteMalloc(). These +** Make a copy of a string in memory obtained from sqliteMalloc(). These ** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This -** is because when memory debugging is turned on, these two functions are +** is because when memory debugging is turned on, these two functions are ** called via macros that record the current file and line number in the ** ThreadData structure. */ @@ -24898,11 +29310,9 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; assert( db!=0 ); - if( z==0 ){ - return 0; - } + assert( z!=0 || n==0 ); assert( (n&0x7fffffff)==n ); - zNew = sqlite3DbMallocRawNN(db, n+1); + zNew = z ? sqlite3DbMallocRawNN(db, n+1) : 0; if( zNew ){ memcpy(zNew, z, (size_t)n); zNew[n] = 0; @@ -24910,6 +29320,19 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ return zNew; } +/* +** The text between zStart and zEnd represents a phrase within a larger +** SQL statement. Make a copy of this phrase in space obtained form +** sqlite3DbMalloc(). Omit leading and trailing whitespace. +*/ +SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){ + int n; + while( sqlite3Isspace(zStart[0]) ) zStart++; + n = (int)(zEnd - zStart); + while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--; + return sqlite3DbStrNDup(db, zStart, n); +} + /* ** Free any prior content in *pz and replace it with a copy of zNew. */ @@ -24923,15 +29346,27 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ ** has happened. This routine will set db->mallocFailed, and also ** temporarily disable the lookaside memory allocator and interrupt ** any running VDBEs. +** +** Always return a NULL pointer so that this routine can be invoked using +** +** return sqlite3OomFault(db); +** +** and thereby avoid unnecessary stack frame allocations for the overwhelmingly +** common case where no OOM occurs. */ -SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ +SQLITE_PRIVATE void *sqlite3OomFault(sqlite3 *db){ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ db->mallocFailed = 1; if( db->nVdbeExec>0 ){ - db->u1.isInterrupted = 1; + AtomicStore(&db->u1.isInterrupted, 1); + } + DisableLookaside; + if( db->pParse ){ + sqlite3ErrorMsg(db->pParse, "out of memory"); + db->pParse->rc = SQLITE_NOMEM_BKPT; } - db->lookaside.bDisable++; } + return 0; } /* @@ -24944,42 +29379,45 @@ SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){ if( db->mallocFailed && db->nVdbeExec==0 ){ db->mallocFailed = 0; - db->u1.isInterrupted = 0; + AtomicStore(&db->u1.isInterrupted, 0); assert( db->lookaside.bDisable>0 ); - db->lookaside.bDisable--; + EnableLookaside; } } /* -** Take actions at the end of an API call to indicate an OOM error +** Take actions at the end of an API call to deal with error codes. */ -static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ - sqlite3OomClear(db); - sqlite3Error(db, SQLITE_NOMEM); - return SQLITE_NOMEM_BKPT; +static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){ + if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomClear(db); + sqlite3Error(db, SQLITE_NOMEM); + return SQLITE_NOMEM_BKPT; + } + return rc & db->errMask; } /* -** This function must be called before exiting any API function (i.e. +** This function must be called before exiting any API function (i.e. ** returning control to the user) that has called sqlite3_malloc or ** sqlite3_realloc. ** ** The returned value is normally a copy of the second argument to this ** function. However, if a malloc() failure has occurred since the previous -** invocation SQLITE_NOMEM is returned instead. +** invocation SQLITE_NOMEM is returned instead. ** ** If an OOM as occurred, then the connection error-code (the value ** returned by sqlite3_errcode()) is set to SQLITE_NOMEM. */ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ /* If the db handle must hold the connection handle mutex here. - ** Otherwise the read (and possible write) of db->mallocFailed + ** Otherwise the read (and possible write) of db->mallocFailed ** is unsafe, as is the call to sqlite3Error(). */ assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); - if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ - return apiOomError(db); + if( db->mallocFailed || rc ){ + return apiHandleError(db, rc); } return rc & db->errMask; } @@ -24988,7 +29426,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ /************** Begin file printf.c ******************************************/ /* ** The "printf" code that follows dates from the 1980's. It is in -** the public domain. +** the public domain. ** ************************************************************************** ** @@ -25003,7 +29441,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ ** Conversion types fall into various categories as defined by the ** following enumeration. */ -#define etRADIX 0 /* Integer types. %d, %x, %o, and so forth */ +#define etRADIX 0 /* non-decimal integer types. %x %o */ #define etFLOAT 1 /* Floating point. %f */ #define etEXP 2 /* Exponentional notation. %e and %E */ #define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */ @@ -25017,12 +29455,13 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ #define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ #define etTOKEN 11 /* a pointer to a Token structure */ -#define etSRCLIST 12 /* a pointer to a SrcList */ +#define etSRCITEM 12 /* a pointer to a SrcItem */ #define etPOINTER 13 /* The %p conversion */ #define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ +#define etDECIMAL 16 /* %d or %u, but not %x, %o */ -#define etINVALID 16 /* Any unrecognized conversion type */ +#define etINVALID 17 /* Any unrecognized conversion type */ /* @@ -25046,8 +29485,8 @@ typedef struct et_info { /* Information about each format field */ /* ** Allowed values for et_info.flags */ -#define FLAG_SIGNED 1 /* True if the value to convert is signed */ -#define FLAG_STRING 4 /* Allow infinity precision */ +#define FLAG_SIGNED 1 /* True if the value to convert is signed */ +#define FLAG_STRING 4 /* Allow infinite precision */ /* @@ -25057,7 +29496,7 @@ typedef struct et_info { /* Information about each format field */ static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; static const char aPrefix[] = "-x0\000X0"; static const et_info fmtinfo[] = { - { 'd', 10, 1, etRADIX, 0, 0 }, + { 'd', 10, 1, etDECIMAL, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 }, { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 4, etDYNSTRING, 0, 0 }, @@ -25066,7 +29505,7 @@ static const et_info fmtinfo[] = { { 'w', 0, 4, etSQLESCAPE3, 0, 0 }, { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, - { 'u', 10, 0, etRADIX, 0, 0 }, + { 'u', 10, 0, etDECIMAL, 0, 0 }, { 'x', 16, 0, etRADIX, 16, 1 }, { 'X', 16, 0, etRADIX, 0, 4 }, #ifndef SQLITE_OMIT_FLOATING_POINT @@ -25075,17 +29514,29 @@ static const et_info fmtinfo[] = { { 'E', 0, 1, etEXP, 14, 0 }, { 'G', 0, 1, etGENERIC, 14, 0 }, #endif - { 'i', 10, 1, etRADIX, 0, 0 }, + { 'i', 10, 1, etDECIMAL, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, /* All the rest are undocumented and are for internal use only */ { 'T', 0, 0, etTOKEN, 0, 0 }, - { 'S', 0, 0, etSRCLIST, 0, 0 }, + { 'S', 0, 0, etSRCITEM, 0, 0 }, { 'r', 10, 1, etORDINAL, 0, 0 }, }; +/* Notes: +** +** %S Takes a pointer to SrcItem. Shows name or database.name +** %!S Like %S but prefer the zName over the zAlias +*/ + +/* Floating point constants used for rounding */ +static const double arRound[] = { + 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05, + 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10, +}; + /* ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** conversions will work. @@ -25120,10 +29571,11 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ /* ** Set the StrAccum object to an error mode. */ -static void setStrAccumError(StrAccum *p, u8 eError){ - assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG ); +SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum *p, u8 eError){ + assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; - p->nAlloc = 0; + if( p->mxAlloc ) sqlite3_str_reset(p); + if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError); } /* @@ -25142,6 +29594,28 @@ static char *getTextArg(PrintfArguments *p){ return (char*)sqlite3_value_text(p->apArg[p->nUsed++]); } +/* +** Allocate memory for a temporary buffer needed for printf rendering. +** +** If the requested size of the temp buffer is larger than the size +** of the output buffer in pAccum, then cause an SQLITE_TOOBIG error. +** Do the size check before the memory allocation to prevent rogue +** SQL from requesting large allocations using the precision or width +** field of the printf() function. +*/ +static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ + char *z; + if( pAccum->accError ) return 0; + if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ + sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG); + return 0; + } + z = sqlite3DbMallocRaw(pAccum->db, n); + if( z==0 ){ + sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM); + } + return z; +} /* ** On machines with a small stack size, you can redefine the @@ -25152,11 +29626,18 @@ static char *getTextArg(PrintfArguments *p){ #endif #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ +/* +** Hard limit on the precision of floating-point conversions. +*/ +#ifndef SQLITE_PRINTF_PRECISION_LIMIT +# define SQLITE_FP_PRECISION_LIMIT 100000000 +#endif + /* ** Render a string given by "fmt" into the StrAccum object. */ -SQLITE_PRIVATE void sqlite3VXPrintf( - StrAccum *pAccum, /* Accumulate results here */ +SQLITE_API void sqlite3_str_vappendf( + sqlite3_str *pAccum, /* Accumulate results here */ const char *fmt, /* Format string */ va_list ap /* arguments */ ){ @@ -25167,14 +29648,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf( int idx; /* A general purpose loop counter */ int width; /* Width of the current field */ etByte flag_leftjustify; /* True if "-" flag is present */ - etByte flag_plussign; /* True if "+" flag is present */ - etByte flag_blanksign; /* True if " " flag is present */ + etByte flag_prefix; /* '+' or ' ' or 0 for prefix */ etByte flag_alternateform; /* True if "#" flag is present */ etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ - etByte flag_long; /* True if "l" flag is present */ - etByte flag_longlong; /* True if the "ll" flag is present */ + etByte flag_long; /* 1 for the "l" flag, 2 for "ll", 0 by default */ etByte done; /* Loop termination flag */ + etByte cThousand; /* Thousands separator for %d and %u */ etByte xtype = etINVALID; /* Conversion paradigm */ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ @@ -25194,6 +29674,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ char buf[etBUFSIZE]; /* Conversion buffer */ + /* pAccum never starts out with an empty buffer that was obtained from + ** malloc(). This precondition is required by the mprintf("%z...") + ** optimization. */ + assert( pAccum->nChar>0 || (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); + bufpt = 0; if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){ pArgList = va_arg(ap, PrintfArguments*); @@ -25209,102 +29694,117 @@ SQLITE_PRIVATE void sqlite3VXPrintf( #else do{ fmt++; }while( *fmt && *fmt != '%' ); #endif - sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt)); + sqlite3_str_append(pAccum, bufpt, (int)(fmt - bufpt)); if( *fmt==0 ) break; } if( (c=(*++fmt))==0 ){ - sqlite3StrAccumAppend(pAccum, "%", 1); + sqlite3_str_append(pAccum, "%", 1); break; } /* Find out what flags are present */ - flag_leftjustify = flag_plussign = flag_blanksign = + flag_leftjustify = flag_prefix = cThousand = flag_alternateform = flag_altform2 = flag_zeropad = 0; done = 0; + width = 0; + flag_long = 0; + precision = -1; do{ switch( c ){ case '-': flag_leftjustify = 1; break; - case '+': flag_plussign = 1; break; - case ' ': flag_blanksign = 1; break; + case '+': flag_prefix = '+'; break; + case ' ': flag_prefix = ' '; break; case '#': flag_alternateform = 1; break; case '!': flag_altform2 = 1; break; case '0': flag_zeropad = 1; break; + case ',': cThousand = ','; break; default: done = 1; break; - } - }while( !done && (c=(*++fmt))!=0 ); - /* Get the field width */ - if( c=='*' ){ - if( bArgList ){ - width = (int)getIntArg(pArgList); - }else{ - width = va_arg(ap,int); - } - if( width<0 ){ - flag_leftjustify = 1; - width = width >= -2147483647 ? -width : 0; - } - c = *++fmt; - }else{ - unsigned wx = 0; - while( c>='0' && c<='9' ){ - wx = wx*10 + c - '0'; - c = *++fmt; - } - testcase( wx>0x7fffffff ); - width = wx & 0x7fffffff; - } - assert( width>=0 ); + case 'l': { + flag_long = 1; + c = *++fmt; + if( c=='l' ){ + c = *++fmt; + flag_long = 2; + } + done = 1; + break; + } + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': { + unsigned wx = c - '0'; + while( (c = *++fmt)>='0' && c<='9' ){ + wx = wx*10 + c - '0'; + } + testcase( wx>0x7fffffff ); + width = wx & 0x7fffffff; #ifdef SQLITE_PRINTF_PRECISION_LIMIT - if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ - width = SQLITE_PRINTF_PRECISION_LIMIT; - } + if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ + width = SQLITE_PRINTF_PRECISION_LIMIT; + } #endif - - /* Get the precision */ - if( c=='.' ){ - c = *++fmt; - if( c=='*' ){ - if( bArgList ){ - precision = (int)getIntArg(pArgList); - }else{ - precision = va_arg(ap,int); + if( c!='.' && c!='l' ){ + done = 1; + }else{ + fmt--; + } + break; } - c = *++fmt; - if( precision<0 ){ - precision = precision >= -2147483647 ? -precision : -1; + case '*': { + if( bArgList ){ + width = (int)getIntArg(pArgList); + }else{ + width = va_arg(ap,int); + } + if( width<0 ){ + flag_leftjustify = 1; + width = width >= -2147483647 ? -width : 0; + } +#ifdef SQLITE_PRINTF_PRECISION_LIMIT + if( width>SQLITE_PRINTF_PRECISION_LIMIT ){ + width = SQLITE_PRINTF_PRECISION_LIMIT; + } +#endif + if( (c = fmt[1])!='.' && c!='l' ){ + c = *++fmt; + done = 1; + } + break; } - }else{ - unsigned px = 0; - while( c>='0' && c<='9' ){ - px = px*10 + c - '0'; + case '.': { c = *++fmt; - } - testcase( px>0x7fffffff ); - precision = px & 0x7fffffff; - } - }else{ - precision = -1; - } - assert( precision>=(-1) ); + if( c=='*' ){ + if( bArgList ){ + precision = (int)getIntArg(pArgList); + }else{ + precision = va_arg(ap,int); + } + if( precision<0 ){ + precision = precision >= -2147483647 ? -precision : -1; + } + c = *++fmt; + }else{ + unsigned px = 0; + while( c>='0' && c<='9' ){ + px = px*10 + c - '0'; + c = *++fmt; + } + testcase( px>0x7fffffff ); + precision = px & 0x7fffffff; + } #ifdef SQLITE_PRINTF_PRECISION_LIMIT - if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ - precision = SQLITE_PRINTF_PRECISION_LIMIT; - } + if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){ + precision = SQLITE_PRINTF_PRECISION_LIMIT; + } #endif - - - /* Get the conversion type modifier */ - if( c=='l' ){ - flag_long = 1; - c = *++fmt; - if( c=='l' ){ - flag_longlong = 1; - c = *++fmt; - }else{ - flag_longlong = 0; + if( c=='l' ){ + --fmt; + }else{ + done = 1; + } + break; + } } - }else{ - flag_long = flag_longlong = 0; - } + }while( !done && (c=(*++fmt))!=0 ); + /* Fetch the info entry for the field */ infop = &fmtinfo[0]; xtype = etINVALID; @@ -25321,15 +29821,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf( ** ** flag_alternateform TRUE if a '#' is present. ** flag_altform2 TRUE if a '!' is present. - ** flag_plussign TRUE if a '+' is present. + ** flag_prefix '+' or ' ' or zero ** flag_leftjustify TRUE if a '-' is present or if the ** field width was negative. ** flag_zeropad TRUE if the width began with 0. - ** flag_long TRUE if the letter 'l' (ell) prefixed - ** the conversion character. - ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed - ** the conversion character. - ** flag_blanksign TRUE if a ' ' is present. + ** flag_long 1 for "l", 2 for "ll" ** width The specified field width. This is ** always non-negative. Zero is the default. ** precision The specified precision. The default @@ -25337,44 +29833,50 @@ SQLITE_PRIVATE void sqlite3VXPrintf( ** xtype The class of the conversion. ** infop Pointer to the appropriate info struct. */ + assert( width>=0 ); + assert( precision>=(-1) ); switch( xtype ){ case etPOINTER: - flag_longlong = sizeof(char*)==sizeof(i64); - flag_long = sizeof(char*)==sizeof(long int); - /* Fall through into the next case */ + flag_long = sizeof(char*)==sizeof(i64) ? 2 : + sizeof(char*)==sizeof(long int) ? 1 : 0; + /* no break */ deliberate_fall_through case etORDINAL: case etRADIX: + cThousand = 0; + /* no break */ deliberate_fall_through + case etDECIMAL: if( infop->flags & FLAG_SIGNED ){ i64 v; if( bArgList ){ v = getIntArg(pArgList); - }else if( flag_longlong ){ - v = va_arg(ap,i64); }else if( flag_long ){ - v = va_arg(ap,long int); + if( flag_long==2 ){ + v = va_arg(ap,i64) ; + }else{ + v = va_arg(ap,long int); + } }else{ v = va_arg(ap,int); } if( v<0 ){ - if( v==SMALLEST_INT64 ){ - longvalue = ((u64)1)<<63; - }else{ - longvalue = -v; - } + testcase( v==SMALLEST_INT64 ); + testcase( v==(-1) ); + longvalue = ~v; + longvalue++; prefix = '-'; }else{ longvalue = v; - if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; + prefix = flag_prefix; } }else{ if( bArgList ){ longvalue = (u64)getIntArg(pArgList); - }else if( flag_longlong ){ - longvalue = va_arg(ap,u64); }else if( flag_long ){ - longvalue = va_arg(ap,unsigned long int); + if( flag_long==2 ){ + longvalue = va_arg(ap,u64); + }else{ + longvalue = va_arg(ap,unsigned long int); + } }else{ longvalue = va_arg(ap,unsigned int); } @@ -25384,16 +29886,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( flag_zeropad && precision0 ); } length = (int)(&zOut[nOut-1]-bufpt); - for(idx=precision-length; idx>0; idx--){ + while( precision>length ){ *(--bufpt) = '0'; /* Zero pad */ + length++; + } + if( cThousand ){ + int nn = (length - 1)/3; /* Number of "," to insert */ + int ix = (length - 1)%3 + 1; + bufpt -= nn; + for(idx=0; nn>0; idx++){ + bufpt[idx] = bufpt[idx+nn]; + ix--; + if( ix==0 ){ + bufpt[++idx] = cThousand; + nn--; + ix = 3; + } + } } if( prefix ) *(--bufpt) = prefix; /* Add sign */ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ @@ -25438,18 +29955,31 @@ SQLITE_PRIVATE void sqlite3VXPrintf( length = 0; #else if( precision<0 ) precision = 6; /* Set default precision */ +#ifdef SQLITE_FP_PRECISION_LIMIT + if( precision>SQLITE_FP_PRECISION_LIMIT ){ + precision = SQLITE_FP_PRECISION_LIMIT; + } +#endif if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ - if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; + prefix = flag_prefix; } if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); - for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} - if( xtype==etFLOAT ) realvalue += rounder; + idx = precision & 0xfff; + rounder = arRound[idx%10]; + while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; } + if( xtype==etFLOAT ){ + double rx = (double)realvalue; + sqlite3_uint64 u; + int ex; + memcpy(&u, &rx, sizeof(u)); + ex = -1023 + (int)((u>>52)&0x7ff); + if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16; + realvalue += rounder; + } /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( sqlite3IsNaN((double)realvalue) ){ @@ -25498,12 +30028,12 @@ SQLITE_PRIVATE void sqlite3VXPrintf( }else{ e2 = exp; } - if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){ - bufpt = zExtra - = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 ); - if( bufpt==0 ){ - setStrAccumError(pAccum, STRACCUM_NOMEM); - return; + { + i64 szBufNeeded; /* Size of a temporary buffer needed */ + szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; + if( szBufNeeded > etBUFSIZE ){ + bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded); + if( bufpt==0 ) return; } } zOut = bufpt; @@ -25598,22 +30128,52 @@ SQLITE_PRIVATE void sqlite3VXPrintf( case etCHARX: if( bArgList ){ bufpt = getTextArg(pArgList); - c = bufpt ? bufpt[0] : 0; + length = 1; + if( bufpt ){ + buf[0] = c = *(bufpt++); + if( (c&0xc0)==0xc0 ){ + while( length<4 && (bufpt[0]&0xc0)==0x80 ){ + buf[length++] = *(bufpt++); + } + } + }else{ + buf[0] = 0; + } }else{ - c = va_arg(ap,int); + unsigned int ch = va_arg(ap,unsigned int); + if( ch<0x00080 ){ + buf[0] = ch & 0xff; + length = 1; + }else if( ch<0x00800 ){ + buf[0] = 0xc0 + (u8)((ch>>6)&0x1f); + buf[1] = 0x80 + (u8)(ch & 0x3f); + length = 2; + }else if( ch<0x10000 ){ + buf[0] = 0xe0 + (u8)((ch>>12)&0x0f); + buf[1] = 0x80 + (u8)((ch>>6) & 0x3f); + buf[2] = 0x80 + (u8)(ch & 0x3f); + length = 3; + }else{ + buf[0] = 0xf0 + (u8)((ch>>18) & 0x07); + buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); + buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); + buf[3] = 0x80 + (u8)(ch & 0x3f); + length = 4; + } } if( precision>1 ){ width -= precision-1; if( width>1 && !flag_leftjustify ){ - sqlite3AppendChar(pAccum, width-1, ' '); + sqlite3_str_appendchar(pAccum, width-1, ' '); width = 0; } - sqlite3AppendChar(pAccum, precision-1, c); + while( precision-- > 1 ){ + sqlite3_str_append(pAccum, buf, length); + } } - length = 1; - buf[0] = c; bufpt = buf; - break; + flag_altform2 = 1; + goto adjust_width_for_utf8; case etSTRING: case etDYNSTRING: if( bArgList ){ @@ -25625,17 +30185,50 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( bufpt==0 ){ bufpt = ""; }else if( xtype==etDYNSTRING ){ + if( pAccum->nChar==0 + && pAccum->mxAlloc + && width==0 + && precision<0 + && pAccum->accError==0 + ){ + /* Special optimization for sqlite3_mprintf("%z..."): + ** Extend an existing memory allocation rather than creating + ** a new one. */ + assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); + pAccum->zText = bufpt; + pAccum->nAlloc = sqlite3DbMallocSize(pAccum->db, bufpt); + pAccum->nChar = 0x7fffffff & (int)strlen(bufpt); + pAccum->printfFlags |= SQLITE_PRINTF_MALLOCED; + length = 0; + break; + } zExtra = bufpt; } if( precision>=0 ){ - for(length=0; length 0 && z[0] ){ + SQLITE_SKIP_UTF8(z); + } + length = (int)(z - (unsigned char*)bufpt); + }else{ + for(length=0; length0 ){ + /* Adjust width to account for extra bytes in UTF-8 characters */ + int ii = length - 1; + while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; - case etSQLESCAPE: /* Escape ' characters */ - case etSQLESCAPE2: /* Escape ' and enclose in '...' */ - case etSQLESCAPE3: { /* Escape " characters */ + case etSQLESCAPE: /* %q: Escape ' characters */ + case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ + case etSQLESCAPE3: { /* %w: Escape " characters */ int i, j, k, n, isnull; int needQuote; char ch; @@ -25649,18 +30242,23 @@ SQLITE_PRIVATE void sqlite3VXPrintf( } isnull = escarg==0; if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); + /* For %q, %Q, and %w, the precision is the number of bytes (or + ** characters if the ! flags is present) to use from the input. + ** Because of the extra quoting characters inserted, the number + ** of output characters may be larger than the precision. + */ k = precision; for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){ if( ch==q ) n++; + if( flag_altform2 && (ch&0xc0)==0xc0 ){ + while( (escarg[i+1]&0xc0)==0x80 ){ i++; } + } } needQuote = !isnull && xtype==etSQLESCAPE2; n += i + 3; if( n>etBUFSIZE ){ - bufpt = zExtra = sqlite3Malloc( n ); - if( bufpt==0 ){ - setStrAccumError(pAccum, STRACCUM_NOMEM); - return; - } + bufpt = zExtra = printfTempBuf(pAccum, n); + if( bufpt==0 ) return; }else{ bufpt = buf; } @@ -25674,37 +30272,47 @@ SQLITE_PRIVATE void sqlite3VXPrintf( if( needQuote ) bufpt[j++] = q; bufpt[j] = 0; length = j; - /* The precision in %q and %Q means how many input characters to - ** consume, not the length of the output... - ** if( precision>=0 && precisionprintfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; - pToken = va_arg(ap, Token*); - assert( bArgList==0 ); - if( pToken && pToken->n ){ - sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n); + if( flag_alternateform ){ + /* %#T means an Expr pointer that uses Expr.u.zToken */ + Expr *pExpr = va_arg(ap,Expr*); + if( ALWAYS(pExpr) && ALWAYS(!ExprHasProperty(pExpr,EP_IntValue)) ){ + sqlite3_str_appendall(pAccum, (const char*)pExpr->u.zToken); + sqlite3RecordErrorOffsetOfExpr(pAccum->db, pExpr); + } + }else{ + /* %T means a Token pointer */ + Token *pToken = va_arg(ap, Token*); + assert( bArgList==0 ); + if( pToken && pToken->n ){ + sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); + sqlite3RecordErrorByteOffset(pAccum->db, pToken->z); + } } length = width = 0; break; } - case etSRCLIST: { - SrcList *pSrc; - int k; - struct SrcList_item *pItem; + case etSRCITEM: { + SrcItem *pItem; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; - pSrc = va_arg(ap, SrcList*); - k = va_arg(ap, int); - pItem = &pSrc->a[k]; + pItem = va_arg(ap, SrcItem*); assert( bArgList==0 ); - assert( k>=0 && knSrc ); - if( pItem->zDatabase ){ - sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase); - sqlite3StrAccumAppend(pAccum, ".", 1); + if( pItem->zAlias && !flag_altform2 ){ + sqlite3_str_appendall(pAccum, pItem->zAlias); + }else if( pItem->zName ){ + if( pItem->zDatabase ){ + sqlite3_str_appendall(pAccum, pItem->zDatabase); + sqlite3_str_append(pAccum, ".", 1); + } + sqlite3_str_appendall(pAccum, pItem->zName); + }else if( pItem->zAlias ){ + sqlite3_str_appendall(pAccum, pItem->zAlias); + }else if( ALWAYS(pItem->pSelect) ){ + sqlite3_str_appendf(pAccum, "SUBQUERY %u", pItem->pSelect->selId); } - sqlite3StrAccumAppendAll(pAccum, pItem->zName); length = width = 0; break; } @@ -25716,15 +30324,18 @@ SQLITE_PRIVATE void sqlite3VXPrintf( /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do - ** the output. + ** the output. Both length and width are in bytes, not characters, + ** at this point. If the "!" flag was present on string conversions + ** indicating that width and precision should be expressed in characters, + ** then the values have been translated prior to reaching this point. */ width -= length; if( width>0 ){ - if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); - sqlite3StrAccumAppend(pAccum, bufpt, length); - if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); + if( !flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); + sqlite3_str_append(pAccum, bufpt, length); + if( flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' '); }else{ - sqlite3StrAccumAppend(pAccum, bufpt, length); + sqlite3_str_append(pAccum, bufpt, length); } if( zExtra ){ @@ -25734,6 +30345,42 @@ SQLITE_PRIVATE void sqlite3VXPrintf( }/* End for loop over the format string */ } /* End of function */ + +/* +** The z string points to the first character of a token that is +** associated with an error. If db does not already have an error +** byte offset recorded, try to compute the error byte offset for +** z and set the error byte offset in db. +*/ +SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){ + const Parse *pParse; + const char *zText; + const char *zEnd; + assert( z!=0 ); + if( NEVER(db==0) ) return; + if( db->errByteOffset!=(-2) ) return; + pParse = db->pParse; + if( NEVER(pParse==0) ) return; + zText =pParse->zTail; + if( NEVER(zText==0) ) return; + zEnd = &zText[strlen(zText)]; + if( SQLITE_WITHIN(z,zText,zEnd) ){ + db->errByteOffset = (int)(z-zText); + } +} + +/* +** If pExpr has a byte offset for the start of a token, record that as +** as the error offset. +*/ +SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){ + while( pExpr && (ExprHasProperty(pExpr,EP_FromJoin) || pExpr->w.iOfst<=0) ){ + pExpr = pExpr->pLeft; + } + if( pExpr==0 ) return; + db->errByteOffset = pExpr->w.iOfst; +} + /* ** Enlarge the memory allocation on a StrAccum object so that it is ** able to accept at least N more bytes of text. @@ -25741,31 +30388,29 @@ SQLITE_PRIVATE void sqlite3VXPrintf( ** Return the number of bytes of text that StrAccum is able to accept ** after the attempted enlargement. The value returned might be zero. */ -static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ +SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zNew; assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ if( p->accError ){ - testcase(p->accError==STRACCUM_TOOBIG); - testcase(p->accError==STRACCUM_NOMEM); + testcase(p->accError==SQLITE_TOOBIG); + testcase(p->accError==SQLITE_NOMEM); return 0; } if( p->mxAlloc==0 ){ - N = p->nAlloc - p->nChar - 1; - setStrAccumError(p, STRACCUM_TOOBIG); - return N; + sqlite3StrAccumSetError(p, SQLITE_TOOBIG); + return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar; - assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); - szNew += N + 1; + szNew += (sqlite3_int64)N + 1; if( szNew+p->nChar<=p->mxAlloc ){ /* Force exponential buffer size growth as long as it does not overflow, ** to avoid having to call this routine too often */ szNew += p->nChar; } if( szNew > p->mxAlloc ){ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_TOOBIG); + sqlite3_str_reset(p); + sqlite3StrAccumSetError(p, SQLITE_TOOBIG); return 0; }else{ p->nAlloc = (int)szNew; @@ -25773,7 +30418,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ if( p->db ){ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); }else{ - zNew = sqlite3_realloc64(zOld, p->nAlloc); + zNew = sqlite3Realloc(zOld, p->nAlloc); } if( zNew ){ assert( p->zText!=0 || p->nChar==0 ); @@ -25782,8 +30427,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ p->nAlloc = sqlite3DbMallocSize(p->db, zNew); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ - sqlite3StrAccumReset(p); - setStrAccumError(p, STRACCUM_NOMEM); + sqlite3_str_reset(p); + sqlite3StrAccumSetError(p, SQLITE_NOMEM); return 0; } } @@ -25793,12 +30438,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ /* ** Append N copies of character c to the given string buffer. */ -SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ +SQLITE_API void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){ testcase( p->nChar + (i64)N > 0x7fffffff ); if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){ return; } - assert( (p->zText==p->zBase)==!isMalloced(p) ); while( (N--)>0 ) p->zText[p->nChar++] = c; } @@ -25806,9 +30450,9 @@ SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){ ** The StrAccum "p" is not large enough to accept N new bytes of z[]. ** So enlarge if first, then do the append. ** -** This is a helper routine to sqlite3StrAccumAppend() that does special-case +** This is a helper routine to sqlite3_str_append() that does special-case ** work (enlarging the buffer) using tail recursion, so that the -** sqlite3StrAccumAppend() routine can use fast calling semantics. +** sqlite3_str_append() routine can use fast calling semantics. */ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ N = sqlite3StrAccumEnlarge(p, N); @@ -25816,18 +30460,17 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){ memcpy(&p->zText[p->nChar], z, N); p->nChar += N; } - assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); } /* ** Append N bytes of text from z to the StrAccum object. Increase the ** size of the memory allocation for StrAccum if necessary. */ -SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ +SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); - assert( p->accError==0 || p->nAlloc==0 ); + assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); }else if( N ){ @@ -25840,8 +30483,8 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ /* ** Append the complete text of zero-terminated string z[] to the p string. */ -SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ - sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z)); +SQLITE_API void sqlite3_str_appendall(sqlite3_str *p, const char *z){ + sqlite3_str_append(p, z, sqlite3Strlen30(z)); } @@ -25851,19 +30494,20 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){ ** pointer if any kind of error was encountered. */ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){ + char *zText; assert( p->mxAlloc>0 && !isMalloced(p) ); - p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); - if( p->zText ){ - memcpy(p->zText, p->zBase, p->nChar+1); + zText = sqlite3DbMallocRaw(p->db, p->nChar+1 ); + if( zText ){ + memcpy(zText, p->zText, p->nChar+1); p->printfFlags |= SQLITE_PRINTF_MALLOCED; }else{ - setStrAccumError(p, STRACCUM_NOMEM); + sqlite3StrAccumSetError(p, SQLITE_NOMEM); } - return p->zText; + p->zText = zText; + return zText; } SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ if( p->zText ){ - assert( (p->zText==p->zBase)==!isMalloced(p) ); p->zText[p->nChar] = 0; if( p->mxAlloc>0 && !isMalloced(p) ){ return strAccumFinishRealloc(p); @@ -25872,15 +30516,72 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){ return p->zText; } +/* +** Use the content of the StrAccum passed as the second argument +** as the result of an SQL function. +*/ +SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){ + if( p->accError ){ + sqlite3_result_error_code(pCtx, p->accError); + sqlite3_str_reset(p); + }else if( isMalloced(p) ){ + sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC); + }else{ + sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); + sqlite3_str_reset(p); + } +} + +/* +** This singleton is an sqlite3_str object that is returned if +** sqlite3_malloc() fails to provide space for a real one. This +** sqlite3_str object accepts no new text and always returns +** an SQLITE_NOMEM error. +*/ +static sqlite3_str sqlite3OomStr = { + 0, 0, 0, 0, 0, SQLITE_NOMEM, 0 +}; + +/* Finalize a string created using sqlite3_str_new(). +*/ +SQLITE_API char *sqlite3_str_finish(sqlite3_str *p){ + char *z; + if( p!=0 && p!=&sqlite3OomStr ){ + z = sqlite3StrAccumFinish(p); + sqlite3_free(p); + }else{ + z = 0; + } + return z; +} + +/* Return any error code associated with p */ +SQLITE_API int sqlite3_str_errcode(sqlite3_str *p){ + return p ? p->accError : SQLITE_NOMEM; +} + +/* Return the current length of p in bytes */ +SQLITE_API int sqlite3_str_length(sqlite3_str *p){ + return p ? p->nChar : 0; +} + +/* Return the current value for p */ +SQLITE_API char *sqlite3_str_value(sqlite3_str *p){ + if( p==0 || p->nChar==0 ) return 0; + p->zText[p->nChar] = 0; + return p->zText; +} + /* ** Reset an StrAccum string. Reclaim all malloced memory. */ -SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ - assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) ); +SQLITE_API void sqlite3_str_reset(StrAccum *p){ if( isMalloced(p) ){ sqlite3DbFree(p->db, p->zText); p->printfFlags &= ~SQLITE_PRINTF_MALLOCED; } + p->nAlloc = 0; + p->nChar = 0; p->zText = 0; } @@ -25899,15 +30600,27 @@ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){ ** allocations will ever occur. */ SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){ - p->zText = p->zBase = zBase; + p->zText = zBase; p->db = db; - p->nChar = 0; p->nAlloc = n; p->mxAlloc = mx; + p->nChar = 0; p->accError = 0; p->printfFlags = 0; } +/* Allocate and initialize a new dynamic string object */ +SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3 *db){ + sqlite3_str *p = sqlite3_malloc64(sizeof(*p)); + if( p ){ + sqlite3StrAccumInit(p, 0, 0, 0, + db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH); + }else{ + p = &sqlite3OomStr; + } + return p; +} + /* ** Print into memory obtained from sqliteMalloc(). Use the internal ** %-conversion extensions. @@ -25920,9 +30633,9 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); acc.printfFlags = SQLITE_PRINTF_INTERNAL; - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); - if( acc.accError==STRACCUM_NOMEM ){ + if( acc.accError==SQLITE_NOMEM ){ sqlite3OomFault(db); } return z; @@ -25950,7 +30663,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ char zBase[SQLITE_PRINT_BUF_SIZE]; StrAccum acc; -#ifdef SQLITE_ENABLE_API_ARMOR +#ifdef SQLITE_ENABLE_API_ARMOR if( zFormat==0 ){ (void)SQLITE_MISUSE_BKPT; return 0; @@ -25960,7 +30673,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){ if( sqlite3_initialize() ) return 0; #endif sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); z = sqlite3StrAccumFinish(&acc); return z; } @@ -26005,7 +30718,7 @@ SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_li } #endif sqlite3StrAccumInit(&acc, 0, zBuf, n, 0); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); zBuf[acc.nChar] = 0; return zBuf; } @@ -26027,7 +30740,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){ ** allocate memory because it might be called while the memory allocator ** mutex is held. ** -** sqlite3VXPrintf() might ask for *temporary* memory allocations for +** sqlite3_str_vappendf() might ask for *temporary* memory allocations for ** certain format characters (%q) or for very large precisions or widths. ** Care must be taken that any sqlite3_log() calls that occur while the ** memory mutex is held do not use these mechanisms. @@ -26037,7 +30750,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, sqlite3StrAccumFinish(&acc)); } @@ -26063,26 +30776,33 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){ va_list ap; StrAccum acc; - char zBuf[500]; + char zBuf[SQLITE_PRINT_BUF_SIZE*10]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); va_start(ap,zFormat); - sqlite3VXPrintf(&acc, zFormat, ap); + sqlite3_str_vappendf(&acc, zFormat, ap); va_end(ap); sqlite3StrAccumFinish(&acc); +#ifdef SQLITE_OS_TRACE_PROC + { + extern void SQLITE_OS_TRACE_PROC(const char *zBuf, int nBuf); + SQLITE_OS_TRACE_PROC(zBuf, sizeof(zBuf)); + } +#else fprintf(stdout,"%s", zBuf); fflush(stdout); +#endif } #endif /* -** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument +** variable-argument wrapper around sqlite3_str_vappendf(). The bFlags argument ** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats. */ -SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){ +SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){ va_list ap; va_start(ap,zFormat); - sqlite3VXPrintf(p, zFormat, ap); + sqlite3_str_vappendf(p, zFormat, ap); va_end(ap); } @@ -26102,7 +30822,7 @@ SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){ ** ** This file contains C code to implement the TreeView debugging routines. ** These routines print a parse tree to standard output for debugging and -** analysis. +** analysis. ** ** The interfaces in this file is only available when compiling ** with SQLITE_DEBUG. @@ -26148,15 +30868,17 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); if( p ){ for(i=0; iiLevel && ibLine)-1; i++){ - sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4); + sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4); } - sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); + sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4); + } + if( zFormat!=0 ){ + va_start(ap, zFormat); + sqlite3_str_vappendf(&acc, zFormat, ap); + va_end(ap); + assert( acc.nChar>0 || acc.accError ); + sqlite3_str_append(&acc, "\n", 1); } - va_start(ap, zFormat); - sqlite3VXPrintf(&acc, zFormat, ap); - va_end(ap); - assert( acc.nChar>0 ); - if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1); sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); fflush(stdout); @@ -26189,17 +30911,20 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m char zLine[1000]; const struct Cte *pCte = &pWith->a[i]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3XPrintf(&x, "%s", pCte->zName); + sqlite3_str_appendf(&x, "%s", pCte->zName); if( pCte->pCols && pCte->pCols->nExpr>0 ){ char cSep = '('; int j; for(j=0; jpCols->nExpr; j++){ - sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName); + sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName); cSep = ','; } - sqlite3XPrintf(&x, ")"); + sqlite3_str_appendf(&x, ")"); + } + if( pCte->pUse ){ + sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse, + pCte->pUse->nUse); } - sqlite3XPrintf(&x, " AS"); sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, inCte-1); sqlite3TreeViewSelect(pView, pCte->pSelect, 0); @@ -26209,6 +30934,44 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m } } +/* +** Generate a human-readable description of a SrcList object. +*/ +SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){ + int i; + for(i=0; inSrc; i++){ + const SrcItem *pItem = &pSrc->a[i]; + StrAccum x; + char zLine[100]; + sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); + x.printfFlags |= SQLITE_PRINTF_INTERNAL; + sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); + if( pItem->pTab ){ + sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx", + pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed); + } + if( pItem->fg.jointype & JT_LEFT ){ + sqlite3_str_appendf(&x, " LEFT-JOIN"); + }else if( pItem->fg.jointype & JT_CROSS ){ + sqlite3_str_appendf(&x, " CROSS-JOIN"); + } + if( pItem->fg.fromDDL ){ + sqlite3_str_appendf(&x, " DDL"); + } + if( pItem->fg.isCte ){ + sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse); + } + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, inSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + if( pItem->fg.isTabFunc ){ + sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); + } + sqlite3TreeViewPop(pView); + } +} /* ** Generate a human-readable description of a Select object. @@ -26216,6 +30979,10 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; int cnt = 0; + if( p==0 ){ + sqlite3TreeViewLine(pView, "nil-SELECT"); + return; + } pView = sqlite3TreeViewPush(pView, moreToFollow); if( p->pWith ){ sqlite3TreeViewWith(pView, p->pWith, 1); @@ -26223,11 +30990,17 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewPush(pView, 1); } do{ - sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", - ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, - (int)p->nSelectRow - ); + if( p->selFlags & SF_WhereBegin ){ + sqlite3TreeViewLine(pView, "sqlite3WhereBegin()"); + }else{ + sqlite3TreeViewLine(pView, + "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d", + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), + p->selId, p, p->selFlags, + (int)p->nSelectRow + ); + } if( cnt++ ) sqlite3TreeViewPop(pView); if( p->pPrior ){ n = 1000; @@ -26239,43 +31012,30 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m if( p->pHaving ) n++; if( p->pOrderBy ) n++; if( p->pLimit ) n++; - if( p->pOffset ) n++; +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ) n++; + if( p->pWinDefn ) n++; +#endif + } + if( p->pEList ){ + sqlite3TreeViewExprList(pView, p->pEList, n>0, "result-set"); + } + n--; +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ){ + Window *pX; + pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewLine(pView, "window-functions"); + for(pX=p->pWin; pX; pX=pX->pNextWin){ + sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0); + } + sqlite3TreeViewPop(pView); } - sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); +#endif if( p->pSrc && p->pSrc->nSrc ){ - int i; pView = sqlite3TreeViewPush(pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); - for(i=0; ipSrc->nSrc; i++){ - struct SrcList_item *pItem = &p->pSrc->a[i]; - StrAccum x; - char zLine[100]; - sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); - sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor); - if( pItem->zDatabase ){ - sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName); - }else if( pItem->zName ){ - sqlite3XPrintf(&x, " %s", pItem->zName); - } - if( pItem->pTab ){ - sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName); - } - if( pItem->zAlias ){ - sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias); - } - if( pItem->fg.jointype & JT_LEFT ){ - sqlite3XPrintf(&x, " LEFT-JOIN"); - } - sqlite3StrAccumFinish(&x); - sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); - if( pItem->pSelect ){ - sqlite3TreeViewSelect(pView, pItem->pSelect, 0); - } - if( pItem->fg.isTabFunc ){ - sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); - } - sqlite3TreeViewPop(pView); - } + sqlite3TreeViewSrcList(pView, p->pSrc); sqlite3TreeViewPop(pView); } if( p->pWhere ){ @@ -26291,17 +31051,27 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewExpr(pView, p->pHaving, 0); sqlite3TreeViewPop(pView); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWinDefn ){ + Window *pX; + sqlite3TreeViewItem(pView, "WINDOW", (n--)>0); + for(pX=p->pWinDefn; pX; pX=pX->pNextWin){ + sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0); + } + sqlite3TreeViewPop(pView); + } +#endif if( p->pOrderBy ){ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } if( p->pLimit ){ sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); - sqlite3TreeViewExpr(pView, p->pLimit, 0); - sqlite3TreeViewPop(pView); - } - if( p->pOffset ){ - sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); - sqlite3TreeViewExpr(pView, p->pOffset, 0); + sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0); + if( p->pLimit->pRight ){ + sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); + sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0); + sqlite3TreeViewPop(pView); + } sqlite3TreeViewPop(pView); } if( p->pPrior ){ @@ -26318,21 +31088,149 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m sqlite3TreeViewPop(pView); } +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Generate a description of starting or stopping bounds +*/ +SQLITE_PRIVATE void sqlite3TreeViewBound( + TreeView *pView, /* View context */ + u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */ + Expr *pExpr, /* Value for PRECEDING or FOLLOWING */ + u8 moreToFollow /* True if more to follow */ +){ + switch( eBound ){ + case TK_UNBOUNDED: { + sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow); + sqlite3TreeViewPop(pView); + break; + } + case TK_CURRENT: { + sqlite3TreeViewItem(pView, "CURRENT", moreToFollow); + sqlite3TreeViewPop(pView); + break; + } + case TK_PRECEDING: { + sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow); + sqlite3TreeViewExpr(pView, pExpr, 0); + sqlite3TreeViewPop(pView); + break; + } + case TK_FOLLOWING: { + sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow); + sqlite3TreeViewExpr(pView, pExpr, 0); + sqlite3TreeViewPop(pView); + break; + } + } +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Generate a human-readable explanation for a Window object +*/ +SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ + int nElement = 0; + if( pWin->pFilter ){ + sqlite3TreeViewItem(pView, "FILTER", 1); + sqlite3TreeViewExpr(pView, pWin->pFilter, 0); + sqlite3TreeViewPop(pView); + } + pView = sqlite3TreeViewPush(pView, more); + if( pWin->zName ){ + sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin); + }else{ + sqlite3TreeViewLine(pView, "OVER (%p)", pWin); + } + if( pWin->zBase ) nElement++; + if( pWin->pOrderBy ) nElement++; + if( pWin->eFrmType ) nElement++; + if( pWin->eExclude ) nElement++; + if( pWin->zBase ){ + sqlite3TreeViewPush(pView, (--nElement)>0); + sqlite3TreeViewLine(pView, "window: %s", pWin->zBase); + sqlite3TreeViewPop(pView); + } + if( pWin->pPartition ){ + sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY"); + } + if( pWin->pOrderBy ){ + sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); + } + if( pWin->eFrmType ){ + char zBuf[30]; + const char *zFrmType = "ROWS"; + if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; + if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS"; + sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s",zFrmType, + pWin->bImplicitFrame ? " (implied)" : ""); + sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); + sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); + sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); + sqlite3TreeViewPop(pView); + } + if( pWin->eExclude ){ + char zBuf[30]; + const char *zExclude; + switch( pWin->eExclude ){ + case TK_NO: zExclude = "NO OTHERS"; break; + case TK_CURRENT: zExclude = "CURRENT ROW"; break; + case TK_GROUP: zExclude = "GROUP"; break; + case TK_TIES: zExclude = "TIES"; break; + default: + sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude); + zExclude = zBuf; + break; + } + sqlite3TreeViewPush(pView, 0); + sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude); + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Generate a human-readable explanation for a Window Function object +*/ +SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ + pView = sqlite3TreeViewPush(pView, more); + sqlite3TreeViewLine(pView, "WINFUNC %s(%d)", + pWin->pFunc->zName, pWin->pFunc->nArg); + sqlite3TreeViewWindow(pView, pWin, 0); + sqlite3TreeViewPop(pView); +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + /* ** Generate a human-readable explanation of an expression tree. */ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ - char zFlgs[30]; + char zFlgs[200]; pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ sqlite3TreeViewLine(pView, "nil"); sqlite3TreeViewPop(pView); return; } - if( pExpr->flags ){ - sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags); + if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){ + StrAccum x; + sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); + sqlite3_str_appendf(&x, " fg.af=%x.%c", + pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + sqlite3_str_appendf(&x, " iRJT=%d", pExpr->w.iRightJoinTable); + } + if( ExprHasProperty(pExpr, EP_FromDDL) ){ + sqlite3_str_appendf(&x, " DDL"); + } + if( ExprHasVVAProperty(pExpr, EP_Immutable) ){ + sqlite3_str_appendf(&x, " IMMUTABLE"); + } + sqlite3StrAccumFinish(&x); }else{ zFlgs[0] = 0; } @@ -26345,10 +31243,22 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ - sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs); + char zOp2[16]; + if( pExpr->op2 ){ + sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2); + }else{ + zOp2[0] = 0; + } + sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s", + pExpr->iColumn, zFlgs, zOp2); }else{ - sqlite3TreeViewLine(pView, "{%d:%d}%s", - pExpr->iTable, pExpr->iColumn, zFlgs); + assert( ExprUseYTab(pExpr) ); + sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s", + pExpr->iTable, pExpr->iColumn, + pExpr->y.pTab, zFlgs); + } + if( ExprHasProperty(pExpr, EP_FixedCol) ){ + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } break; } @@ -26362,11 +31272,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } @@ -26374,13 +31286,20 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewLine(pView,"NULL"); break; } + case TK_TRUEFALSE: { + sqlite3TreeViewLine(pView,"%s%s", + sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE", zFlgs); + break; + } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", pExpr->u.zToken, pExpr->iColumn); break; @@ -26390,12 +31309,14 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m break; } case TK_ID: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; @@ -26422,6 +31343,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; case TK_DOT: zBinOp = "DOT"; break; + case TK_LIMIT: zBinOp = "LIMIT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; @@ -26430,14 +31352,36 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; + case TK_TRUTH: { + int x; + const char *azOp[] = { + "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE" + }; + assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); + assert( pExpr->pRight ); + assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE ); + x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); + zUniOp = azOp[x]; + break; + } + case TK_SPAN: { + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_COLLATE: { - sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); + /* COLLATE operators without the EP_Collate flag are intended to + ** emulate collation associated with a table column. These show + ** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE + ** operators that appear in the original SQL always have the + ** EP_Collate bit set and appear in treeview output as just "COLLATE" */ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s", + !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "", + pExpr->u.zToken, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } @@ -26445,37 +31389,66 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m case TK_AGG_FUNCTION: case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ + Window *pWin; if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; + pWin = 0; }else{ + assert( ExprUseXList(pExpr) ); pFarg = pExpr->x.pList; +#ifndef SQLITE_OMIT_WINDOWFUNC + pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0; +#else + pWin = 0; +#endif } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_AGG_FUNCTION ){ - sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", - pExpr->op2, pExpr->u.zToken); + sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p", + pExpr->op2, pExpr->u.zToken, zFlgs, + pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0, + pExpr->iAgg, pExpr->pAggInfo); + }else if( pExpr->op2!=0 ){ + const char *zOp2; + char zBuf[8]; + sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2); + zOp2 = zBuf; + if( pExpr->op2==NC_IsCheck ) zOp2 = "NC_IsCheck"; + if( pExpr->op2==NC_IdxExpr ) zOp2 = "NC_IdxExpr"; + if( pExpr->op2==NC_PartIdx ) zOp2 = "NC_PartIdx"; + if( pExpr->op2==NC_GenCol ) zOp2 = "NC_GenCol"; + sqlite3TreeViewLine(pView, "FUNCTION %Q%s op2=%s", + pExpr->u.zToken, zFlgs, zOp2); }else{ - sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); + sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs); } if( pFarg ){ - sqlite3TreeViewExprList(pView, pFarg, 0, 0); + sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); + } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pWin ){ + sqlite3TreeViewWindow(pView, pWin, 0); } +#endif break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: { - sqlite3TreeViewLine(pView, "EXISTS-expr"); + assert( ExprUseXSelect(pExpr) ); + sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { - sqlite3TreeViewLine(pView, "SELECT-expr"); + assert( ExprUseXSelect(pExpr) ); + sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_IN: { - sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); }else{ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); @@ -26496,9 +31469,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { - Expr *pX = pExpr->pLeft; - Expr *pY = pExpr->x.pList->a[0].pExpr; - Expr *pZ = pExpr->x.pList->a[1].pExpr; + const Expr *pX, *pY, *pZ; + pX = pExpr->pLeft; + assert( ExprUseXList(pExpr) ); + assert( pExpr->x.pList->nExpr==2 ); + pY = pExpr->x.pList->a[0].pExpr; + pZ = pExpr->x.pList->a[1].pExpr; sqlite3TreeViewLine(pView, "BETWEEN"); sqlite3TreeViewExpr(pView, pX, 1); sqlite3TreeViewExpr(pView, pY, 1); @@ -26513,25 +31489,27 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. */ - sqlite3TreeViewLine(pView, "%s(%d)", + sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { sqlite3TreeViewLine(pView, "CASE"); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + assert( ExprUseXList(pExpr) ); sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { const char *zType = "unk"; - switch( pExpr->affinity ){ + switch( pExpr->affExpr ){ case OE_Rollback: zType = "rollback"; break; case OE_Abort: zType = "abort"; break; case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } @@ -26543,14 +31521,42 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m break; } case TK_VECTOR: { - sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR"); + char *z = sqlite3_mprintf("VECTOR%s",zFlgs); + assert( ExprUseXList(pExpr) ); + sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z); + sqlite3_free(z); break; } case TK_SELECT_COLUMN: { - sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn); + sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s", + pExpr->iColumn, pExpr->iTable-1, + pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : ""); + assert( ExprUseXSelect(pExpr->pLeft) ); sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0); break; } + case TK_IF_NULL_ROW: { + sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + case TK_ERROR: { + Expr tmp; + sqlite3TreeViewLine(pView, "ERROR"); + tmp = *pExpr; + tmp.op = pExpr->op2; + sqlite3TreeViewExpr(pView, &tmp, 0); + break; + } + case TK_ROW: { + if( pExpr->iColumn<=0 ){ + sqlite3TreeViewLine(pView, "First FROM table rowid"); + }else{ + sqlite3TreeViewLine(pView, "First FROM table column %d", + pExpr->iColumn-1); + } + break; + } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; @@ -26562,7 +31568,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m sqlite3TreeViewExpr(pView, pExpr->pRight, 0); }else if( zUniOp ){ sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } sqlite3TreeViewPop(pView); } @@ -26584,12 +31590,26 @@ SQLITE_PRIVATE void sqlite3TreeViewBareExprList( sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inExpr; i++){ int j = pList->a[i].u.x.iOrderByCol; - if( j ){ - sqlite3TreeViewPush(pView, 0); - sqlite3TreeViewLine(pView, "iOrderByCol=%d", j); + char *zName = pList->a[i].zEName; + int moreToFollow = inExpr - 1; + if( pList->a[i].eEName!=ENAME_NAME ) zName = 0; + if( j || zName ){ + sqlite3TreeViewPush(pView, moreToFollow); + moreToFollow = 0; + sqlite3TreeViewLine(pView, 0); + if( zName ){ + fprintf(stdout, "AS %s ", zName); + } + if( j ){ + fprintf(stdout, "iOrderByCol=%d", j); + } + fprintf(stdout, "\n"); + fflush(stdout); + } + sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); + if( j || zName ){ + sqlite3TreeViewPop(pView); } - sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); - if( j ) sqlite3TreeViewPop(pView); } } } @@ -26686,11 +31706,16 @@ SQLITE_API void sqlite3_randomness(int N, void *pBuf){ ** number generator) not as an encryption device. */ if( !wsdPrng.isInit ){ + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); int i; char k[256]; wsdPrng.j = 0; wsdPrng.i = 0; - sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k); + if( NEVER(pVfs==0) ){ + memset(k, 0, sizeof(k)); + }else{ + sqlite3OsRandomness(pVfs, 256, k); + } for(i=0; i<256; i++){ wsdPrng.s[i] = (u8)i; } @@ -26814,13 +31839,13 @@ SQLITE_PRIVATE int sqlite3ThreadCreate( memset(p, 0, sizeof(*p)); p->xTask = xTask; p->pIn = pIn; - /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a + /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a ** function that returns SQLITE_ERROR when passed the argument 200, that - ** forces worker threads to run sequentially and deterministically + ** forces worker threads to run sequentially and deterministically ** for testing purposes. */ if( sqlite3FaultSim(200) ){ rc = 1; - }else{ + }else{ rc = pthread_create(&p->tid, 0, xTask, pIn); } if( rc ){ @@ -26902,9 +31927,9 @@ SQLITE_PRIVATE int sqlite3ThreadCreate( *ppThread = 0; p = sqlite3Malloc(sizeof(*p)); if( p==0 ) return SQLITE_NOMEM_BKPT; - /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a + /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a ** function that returns SQLITE_ERROR when passed the argument 200, that - ** forces worker threads to run sequentially and deterministically + ** forces worker threads to run sequentially and deterministically ** (via the sqlite3FaultSim() term of the conditional) for testing ** purposes. */ if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){ @@ -27033,7 +32058,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains routines used to translate between UTF-8, +** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** ** Notes on UTF-8: @@ -27129,26 +32154,6 @@ static const unsigned char sqlite3Utf8Trans1[] = { } \ } -#define READ_UTF16LE(zIn, TERM, c){ \ - c = (*zIn++); \ - c += ((*zIn++)<<8); \ - if( c>=0xD800 && c<0xE000 && TERM ){ \ - int c2 = (*zIn++); \ - c2 += ((*zIn++)<<8); \ - c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ - } \ -} - -#define READ_UTF16BE(zIn, TERM, c){ \ - c = ((*zIn++)<<8); \ - c += (*zIn++); \ - if( c>=0xD800 && c<0xE000 && TERM ){ \ - int c2 = ((*zIn++)<<8); \ - c2 += (*zIn++); \ - c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ - } \ -} - /* ** Translate a single UTF-8 character. Return the unicode value. ** @@ -27214,7 +32219,7 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read( /* ** If the TRANSLATE_TRACE macro is defined, the value of each Mem is ** printed on stderr on the way into and out of sqlite3VdbeMemTranslate(). -*/ +*/ /* #define TRANSLATE_TRACE 1 */ #ifndef SQLITE_OMIT_UTF16 @@ -27224,11 +32229,11 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read( ** encoding, or if *pMem does not contain a string value. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ - int len; /* Maximum length of output string in bytes */ - unsigned char *zOut; /* Output buffer */ - unsigned char *zIn; /* Input iterator */ - unsigned char *zTerm; /* End of input */ - unsigned char *z; /* Output iterator */ + sqlite3_int64 len; /* Maximum length of output string in bytes */ + unsigned char *zOut; /* Output buffer */ + unsigned char *zIn; /* Input iterator */ + unsigned char *zTerm; /* End of input */ + unsigned char *z; /* Output iterator */ unsigned int c; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -27239,13 +32244,15 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { - char zBuf[100]; - sqlite3VdbeMemPrettyPrint(pMem, zBuf); - fprintf(stderr, "INPUT: %s\n", zBuf); + StrAccum acc; + char zBuf[1000]; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); + sqlite3VdbeMemPrettyPrint(pMem, &acc); + fprintf(stderr, "INPUT: %s\n", sqlite3StrAccumFinish(&acc)); } #endif - /* If the translation is between UTF-16 little and big endian, then + /* If the translation is between UTF-16 little and big endian, then ** all that is required is to swap the byte order. This case is handled ** differently from the others. */ @@ -27277,14 +32284,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired ** nul-terminator. */ pMem->n &= ~1; - len = pMem->n * 2 + 1; + len = 2 * (sqlite3_int64)pMem->n + 1; }else{ /* When converting from UTF-8 to UTF-16 the maximum growth is caused ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 ** character. Two bytes are required in the output buffer for the ** nul-terminator. */ - len = pMem->n * 2 + 2; + len = 2 * (sqlite3_int64)pMem->n + 2; } /* Set zIn to point at the start of the input buffer and zTerm to point 1 @@ -27323,13 +32330,59 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired if( pMem->enc==SQLITE_UTF16LE ){ /* UTF-16 Little-endian -> UTF-8 */ while( zIn=0xd800 && c<0xe000 ){ +#ifdef SQLITE_REPLACE_INVALID_UTF + if( c>=0xdc00 || zIn>=zTerm ){ + c = 0xfffd; + }else{ + int c2 = *(zIn++); + c2 += (*(zIn++))<<8; + if( c2<0xdc00 || c2>=0xe000 ){ + zIn -= 2; + c = 0xfffd; + }else{ + c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000; + } + } +#else + if( zIn UTF-8 */ while( zIn=0xd800 && c<0xe000 ){ +#ifdef SQLITE_REPLACE_INVALID_UTF + if( c>=0xdc00 || zIn>=zTerm ){ + c = 0xfffd; + }else{ + int c2 = (*(zIn++))<<8; + c2 += *(zIn++); + if( c2<0xdc00 || c2>=0xe000 ){ + zIn -= 2; + c = 0xfffd; + }else{ + c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000; + } + } +#else + if( zInn+(desiredEnc==SQLITE_UTF8?1:2))<=len ); - c = pMem->flags; + c = MEM_Str|MEM_Term|(pMem->flags&(MEM_AffMask|MEM_Subtype)); sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype)); + pMem->flags = c; pMem->enc = desiredEnc; pMem->z = (char*)zOut; pMem->zMalloc = pMem->z; @@ -27349,16 +32402,20 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { - char zBuf[100]; - sqlite3VdbeMemPrettyPrint(pMem, zBuf); - fprintf(stderr, "OUTPUT: %s\n", zBuf); + StrAccum acc; + char zBuf[1000]; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); + sqlite3VdbeMemPrettyPrint(pMem, &acc); + fprintf(stderr, "OUTPUT: %s\n", sqlite3StrAccumFinish(&acc)); } #endif return SQLITE_OK; } +#endif /* SQLITE_OMIT_UTF16 */ +#ifndef SQLITE_OMIT_UTF16 /* -** This routine checks for a byte-order mark at the beginning of the +** This routine checks for a byte-order mark at the beginning of the ** UTF-16 string stored in *pMem. If one is present, it is removed and ** the encoding of the Mem adjusted. This routine does not do any ** byte-swapping, it just sets Mem.enc appropriately. @@ -27381,7 +32438,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){ bom = SQLITE_UTF16LE; } } - + if( bom ){ rc = sqlite3VdbeMemMakeWriteable(pMem); if( rc==SQLITE_OK ){ @@ -27401,7 +32458,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){ ** pZ is a UTF-8 encoded unicode string. If nByte is less than zero, ** return the number of unicode characters in pZ up to (but not including) ** the first 0x00 byte. If nByte is not less than zero, return the -** number of unicode characters in the first nByte of pZ (or up to +** number of unicode characters in the first nByte of pZ (or up to ** the first 0x00, whichever comes first). */ SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){ @@ -27421,7 +32478,7 @@ SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){ return r; } -/* This test function is not currently used by the automated test-suite. +/* This test function is not currently used by the automated test-suite. ** Hence it is only available in debug builds. */ #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) @@ -27483,19 +32540,16 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){ int c; unsigned char const *z = zIn; int n = 0; - - if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){ - while( n=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2; + n++; } - return (int)(z-(unsigned char const *)zIn); + return (int)(z-(unsigned char const *)zIn) + - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE); } #if defined(SQLITE_TEST) @@ -27525,30 +32579,6 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){ assert( c==t ); assert( (z-zBuf)==n ); } - for(i=0; i<0x00110000; i++){ - if( i>=0xD800 && i<0xE000 ) continue; - z = zBuf; - WRITE_UTF16LE(z, i); - n = (int)(z-zBuf); - assert( n>0 && n<=4 ); - z[0] = 0; - z = zBuf; - READ_UTF16LE(z, 1, c); - assert( c==i ); - assert( (z-zBuf)==n ); - } - for(i=0; i<0x00110000; i++){ - if( i>=0xD800 && i<0xE000 ) continue; - z = zBuf; - WRITE_UTF16BE(z, i); - n = (int)(z-zBuf); - assert( n>0 && n<=4 ); - z[0] = 0; - z = zBuf; - READ_UTF16BE(z, 1, c); - assert( c==i ); - assert( (z-zBuf)==n ); - } } #endif /* SQLITE_TEST */ #endif /* SQLITE_OMIT_UTF16 */ @@ -27574,30 +32604,28 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){ */ /* #include "sqliteInt.h" */ /* #include */ -#if HAVE_ISNAN || SQLITE_HAVE_ISNAN -# include -#endif - -/* -** Routine needed to support the testcase() macro. -*/ -#ifdef SQLITE_COVERAGE_TEST -SQLITE_PRIVATE void sqlite3Coverage(int x){ - static unsigned dummy = 0; - dummy += (unsigned)x; -} +#ifndef SQLITE_OMIT_FLOATING_POINT +#include #endif /* -** Give a callback to the test harness that can be used to simulate faults -** in places where it is difficult or expensive to do so purely by means -** of inputs. +** Calls to sqlite3FaultSim() are used to simulate a failure during testing, +** or to bypass normal error detection during testing in order to let +** execute proceed futher downstream. ** -** The intent of the integer argument is to let the fault simulator know -** which of multiple sqlite3FaultSim() calls has been hit. +** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The +** sqlite3FaultSim() function only returns non-zero during testing. ** -** Return whatever integer value the test callback returns, or return -** SQLITE_OK if no test callback is installed. +** During testing, if the test harness has set a fault-sim callback using +** a call to sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL), then +** each call to sqlite3FaultSim() is relayed to that application-supplied +** callback and the integer return value form the application-supplied +** callback is returned by sqlite3FaultSim(). +** +** The integer argument to sqlite3FaultSim() is a code to identify which +** sqlite3FaultSim() instance is being invoked. Each call to sqlite3FaultSim() +** should have a unique code. To prevent legacy testing applications from +** breaking, the codes should not be changed or reused. */ #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ @@ -27616,36 +32644,10 @@ SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ SQLITE_PRIVATE int sqlite3IsNaN(double x){ int rc; /* The value return */ #if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN - /* - ** Systems that support the isnan() library function should probably - ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have - ** found that many systems do not have a working isnan() function so - ** this implementation is provided as an alternative. - ** - ** This NaN test sometimes fails if compiled on GCC with -ffast-math. - ** On the other hand, the use of -ffast-math comes with the following - ** warning: - ** - ** This option [-ffast-math] should never be turned on by any - ** -O option since it can result in incorrect output for programs - ** which depend on an exact implementation of IEEE or ISO - ** rules/specifications for math functions. - ** - ** Under MSVC, this NaN test may fail if compiled with a floating- - ** point precision mode other than /fp:precise. From the MSDN - ** documentation: - ** - ** The compiler [with /fp:precise] will properly handle comparisons - ** involving NaN. For example, x != x evaluates to true if x is NaN - ** ... - */ -#ifdef __FAST_MATH__ -# error SQLite will not work correctly with the -ffast-math option of GCC. -#endif - volatile double y = x; - volatile double z = y; - rc = (y!=z); -#else /* if HAVE_ISNAN */ + u64 y; + memcpy(&y,&x,sizeof(y)); + rc = IsNaN(y); +#else rc = isnan(x); #endif /* HAVE_ISNAN */ testcase( rc ); @@ -27667,15 +32669,21 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){ } /* -** Return the declared type of a column. Or return zDflt if the column +** Return the declared type of a column. Or return zDflt if the column ** has no declared type. ** ** The column type is an extra string stored after the zero-terminator on ** the column name if and only if the COLFLAG_HASTYPE flag is set. */ SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){ - if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt; - return pCol->zName + strlen(pCol->zName) + 1; + if( pCol->colFlags & COLFLAG_HASTYPE ){ + return pCol->zCnName + strlen(pCol->zCnName) + 1; + }else if( pCol->eCType ){ + assert( pCol->eCType<=SQLITE_N_STDTYPE ); + return (char*)sqlite3StdType[pCol->eCType-1]; + }else{ + return zDflt; + } } /* @@ -27696,7 +32704,22 @@ static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){ assert( db!=0 ); db->errCode = err_code; - if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code); + if( err_code || db->pErr ){ + sqlite3ErrorFinish(db, err_code); + }else{ + db->errByteOffset = -1; + } +} + +/* +** The equivalent of sqlite3Error(db, SQLITE_OK). Clear the error state +** and error message. +*/ +SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3 *db){ + assert( db!=0 ); + db->errCode = SQLITE_OK; + db->errByteOffset = -1; + if( db->pErr ) sqlite3ValueSetNull(db->pErr); } /* @@ -27716,17 +32739,8 @@ SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){ ** handle "db". The error code is set to "err_code". ** ** If it is not NULL, string zFormat specifies the format of the -** error string in the style of the printf functions: The following -** format characters are allowed: -** -** %s Insert a string -** %z A string that should be freed after use -** %d Insert an integer -** %T Insert a token -** %S Insert the first element of a SrcList -** -** zFormat and any string tokens that follow it are assumed to be -** encoded in UTF-8. +** error string. zFormat and any string tokens that follow it are +** assumed to be encoded in UTF-8. ** ** To clear the most recent error for sqlite handle "db", sqlite3Error ** should be called with err_code set to SQLITE_OK and zFormat set @@ -27750,13 +32764,6 @@ SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *z /* ** Add an error message to pParse->zErrMsg and increment pParse->nErr. -** The following formatting characters are allowed: -** -** %s Insert a string -** %z A string that should be freed after use -** %d Insert an integer -** %T Insert a token -** %S Insert the first element of a SrcList ** ** This function should be used to report any error that occurs while ** compiling an SQL statement (i.e. within sqlite3_prepare()). The @@ -27769,19 +32776,41 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ char *zMsg; va_list ap; sqlite3 *db = pParse->db; + assert( db!=0 ); + assert( db->pParse==pParse ); + db->errByteOffset = -2; va_start(ap, zFormat); zMsg = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); + if( db->errByteOffset<-1 ) db->errByteOffset = -1; if( db->suppressErr ){ sqlite3DbFree(db, zMsg); + if( db->mallocFailed ){ + pParse->nErr++; + pParse->rc = SQLITE_NOMEM; + } }else{ pParse->nErr++; sqlite3DbFree(db, pParse->zErrMsg); pParse->zErrMsg = zMsg; pParse->rc = SQLITE_ERROR; + pParse->pWith = 0; } } +/* +** If database connection db is currently parsing SQL, then transfer +** error code errCode to that parser if the parser has not already +** encountered some other kind of error. +*/ +SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3 *db, int errCode){ + Parse *pParse; + if( db==0 || (pParse = db->pParse)==0 ) return errCode; + pParse->rc = errCode; + pParse->nErr++; + return errCode; +} + /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the @@ -27795,7 +32824,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ ** dequoted string, exclusive of the zero terminator, if dequoting does ** occur. ** -** 2002-Feb-14: This routine is extended to remove MS-Access style +** 2002-02-14: This routine is extended to remove MS-Access style ** brackets from around identifiers. For example: "[a-b-c]" becomes ** "a-b-c". */ @@ -27821,6 +32850,34 @@ SQLITE_PRIVATE void sqlite3Dequote(char *z){ } z[j] = 0; } +SQLITE_PRIVATE void sqlite3DequoteExpr(Expr *p){ + assert( !ExprHasProperty(p, EP_IntValue) ); + assert( sqlite3Isquote(p->u.zToken[0]) ); + p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; + sqlite3Dequote(p->u.zToken); +} + +/* +** If the input token p is quoted, try to adjust the token to remove +** the quotes. This is not always possible: +** +** "abc" -> abc +** "ab""cd" -> (not possible because of the interior "") +** +** Remove the quotes if possible. This is a optimization. The overall +** system should still return the correct answer even if this routine +** is always a no-op. +*/ +SQLITE_PRIVATE void sqlite3DequoteToken(Token *p){ + unsigned int i; + if( p->n<2 ) return; + if( !sqlite3Isquote(p->z[0]) ) return; + for(i=1; in-1; i++){ + if( sqlite3Isquote(p->z[i]) ) return; + } + p->n -= 2; + p->z++; +} /* ** Generate a Token object from a string @@ -27853,12 +32910,18 @@ SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){ } SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; - int c; + int c, x; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; for(;;){ - c = (int)UpperToLower[*a] - (int)UpperToLower[*b]; - if( c || *a==0 ) break; + c = *a; + x = *b; + if( c==x ){ + if( c==0 ) break; + }else{ + c = (int)UpperToLower[c] - (int)UpperToLower[x]; + if( c ) break; + } a++; b++; } @@ -27877,6 +32940,58 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; } +/* +** Compute an 8-bit hash on a string that is insensitive to case differences +*/ +SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){ + u8 h = 0; + if( z==0 ) return 0; + while( z[0] ){ + h += UpperToLower[(unsigned char)z[0]]; + z++; + } + return h; +} + +/* +** Compute 10 to the E-th power. Examples: E==1 results in 10. +** E==2 results in 100. E==50 results in 1.0e50. +** +** This routine only works for values of E between 1 and 341. +*/ +static LONGDOUBLE_TYPE sqlite3Pow10(int E){ +#if defined(_MSC_VER) + static const LONGDOUBLE_TYPE x[] = { + 1.0e+001L, + 1.0e+002L, + 1.0e+004L, + 1.0e+008L, + 1.0e+016L, + 1.0e+032L, + 1.0e+064L, + 1.0e+128L, + 1.0e+256L + }; + LONGDOUBLE_TYPE r = 1.0; + int i; + assert( E>=0 && E<=307 ); + for(i=0; E!=0; i++, E >>=1){ + if( E & 1 ) r *= x[i]; + } + return r; +#else + LONGDOUBLE_TYPE x = 10.0; + LONGDOUBLE_TYPE r = 1.0; + while(1){ + if( E & 1 ) r *= x; + E >>= 1; + if( E==0 ) break; + x *= x; + } + return r; +#endif +} + /* ** The string z[] is an text representation of a real number. ** Convert this string to a double and write it into *pResult. @@ -27885,8 +33000,15 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ ** uses the encoding enc. The string is not necessarily zero-terminated. ** ** Return TRUE if the result is a valid real number (or integer) and FALSE -** if the string is empty or contains extraneous text. Valid numbers -** are in one of these formats: +** if the string is empty or contains extraneous text. More specifically +** return +** 1 => The input string is a pure integer +** 2 or more => The input has a decimal point or eNNN clause +** 0 or less => The input string is not a valid number +** -1 => Not a valid number, but has a valid prefix which +** includes a decimal point and/or an eNNN clause +** +** Valid numbers are in one of these formats: ** ** [+-]digits[E[+-]digits] ** [+-]digits.[digits][E[+-]digits] @@ -27899,10 +33021,13 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ ** returns FALSE but it still converts the prefix and writes the result ** into *pResult. */ +#if defined(_MSC_VER) +#pragma warning(disable : 4756) +#endif SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ #ifndef SQLITE_OMIT_FLOATING_POINT int incr; - const char *zEnd = z + length; + const char *zEnd; /* sign * significand * (10 ^ (esign * exponent)) */ int sign = 1; /* sign of significand */ i64 s = 0; /* significand */ @@ -27911,20 +33036,25 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ double result; - int nDigits = 0; - int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + int nDigit = 0; /* Number of digits processed */ + int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ + if( length==0 ) return 0; if( enc==SQLITE_UTF8 ){ incr = 1; + zEnd = z + length; }else{ int i; incr = 2; + length &= ~1; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + testcase( enc==SQLITE_UTF16LE ); + testcase( enc==SQLITE_UTF16BE ); for(i=3-enc; i=((LARGEST_INT64-9)/10) ){ + /* skip non-significant significand digits + ** (increase exponent by d to shift decimal left) */ + while( z=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ z+=incr; + eType++; /* copy digits from after decimal to significand ** (decrease exponent by d to shift decimal right) */ while( z=zEnd ) goto do_atof_calc; @@ -27971,8 +33104,9 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en if( *z=='e' || *z=='E' ){ z+=incr; eValid = 0; + eType++; - /* This branch is needed to avoid a (harmless) buffer overread. The + /* This branch is needed to avoid a (harmless) buffer overread. The ** special comment alerts the mutation tester that the correct answer ** is obtained even if the branch is omitted */ if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ @@ -28032,11 +33166,10 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/ result = (double)s; }else{ - LONGDOUBLE_TYPE scale = 1.0; /* attempt to handle extremely small/large numbers better */ if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/ if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/ - while( e%308 ) { scale *= 1.0e+1; e -= 1; } + LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308); if( esign<0 ){ result = s / scale; result /= 1.0e+308; @@ -28048,14 +33181,15 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en if( esign<0 ){ result = 0.0*s; }else{ +#ifdef INFINITY + result = INFINITY*s; +#else result = 1e308*1e308*s; /* Infinity */ +#endif } } }else{ - /* 1.0e+22 is the largest power of 10 than can be - ** represented exactly. */ - while( e%22 ) { scale *= 1.0e+1; e -= 1; } - while( e>0 ) { scale *= 1.0e+22; e -= 22; } + LONGDOUBLE_TYPE scale = sqlite3Pow10(e); if( esign<0 ){ result = s / scale; }else{ @@ -28069,11 +33203,44 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en *pResult = result; /* return true if number and no extra non-whitespace chracters after */ - return z==zEnd && nDigits>0 && eValid && nonNum==0; + if( z==zEnd && nDigit>0 && eValid && eType>0 ){ + return eType; + }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ + return -1; + }else{ + return 0; + } #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ } +#if defined(_MSC_VER) +#pragma warning(default : 4756) +#endif + +/* +** Render an signed 64-bit integer as text. Store the result in zOut[]. +** +** The caller must ensure that zOut[] is at least 21 bytes in size. +*/ +SQLITE_PRIVATE void sqlite3Int64ToText(i64 v, char *zOut){ + int i; + u64 x; + char zTemp[22]; + if( v<0 ){ + x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; + }else{ + x = v; + } + i = sizeof(zTemp)-2; + zTemp[sizeof(zTemp)-1] = 0; + do{ + zTemp[i--] = (x%10) + '0'; + x = x/10; + }while( x ); + if( v<0 ) zTemp[i--] = '-'; + memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i); +} /* ** Compare the 19-character string zNum against the text representation @@ -28110,16 +33277,13 @@ static int compare2pow63(const char *zNum, int incr){ ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** -** If the zNum value is representable as a 64-bit twos-complement -** integer, then write that value into *pNum and return 0. -** -** If zNum is exactly 9223372036854775808, return 2. This special -** case is broken out because while 9223372036854775808 cannot be a -** signed 64-bit integer, its negative -9223372036854775808 can be. +** Returns: ** -** If zNum is too big for a 64-bit integer and is not -** 9223372036854775808 or if zNum contains any non-numeric text, -** then return 1. +** -1 Not even a prefix of the input text looks like an integer +** 0 Successful transformation. Fits in a 64-bit signed integer. +** 1 Excess non-space text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is @@ -28132,6 +33296,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc int i; int c = 0; int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + int rc; /* Baseline return code */ const char *zStart; const char *zEnd = zNum + length; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); @@ -28139,6 +33304,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc incr = 1; }else{ incr = 2; + length &= ~1; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i='0' && c<='9'; i+=incr){ u = u*10 + c - '0'; } + testcase( i==18*incr ); + testcase( i==19*incr ); + testcase( i==20*incr ); if( u>LARGEST_INT64 ){ + /* This test and assignment is needed only to suppress UB warnings + ** from clang and -fsanitize=undefined. This test and assignment make + ** the code a little larger and slower, and no harm comes from omitting + ** them, but we must appaise the undefined-behavior pharisees. */ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; }else{ *pNum = (i64)u; } - testcase( i==18 ); - testcase( i==19 ); - testcase( i==20 ); - if( &zNum[i]19*incr /* Too many digits */ - || nonNum /* UTF16 with high-order bytes non-zero */ - ){ - /* zNum is empty or contains non-numeric text or is longer - ** than 19 digits (thus guaranteeing that it is too large) */ - return 1; - }else if( i<19*incr ){ + rc = 0; + if( i==0 && zStart==zNum ){ /* No digits */ + rc = -1; + }else if( nonNum ){ /* UTF16 with high-order bytes non-zero */ + rc = 1; + }else if( &zNum[i]19*incr ? 1 : compare2pow63(zNum, incr); if( c<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); - return 0; - }else if( c>0 ){ - /* zNum is greater than 9223372036854775808 so it overflows */ - return 1; + return rc; }else{ - /* zNum is exactly 9223372036854775808. Fits if negative. The - ** special case 2 overflow if positive */ - assert( u-1==LARGEST_INT64 ); - return neg ? 0 : 2; + *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; + if( c>0 ){ + /* zNum is greater than 9223372036854775808 so it overflows */ + return 2; + }else{ + /* zNum is exactly 9223372036854775808. Fits if negative. The + ** special case 2 overflow if positive */ + assert( u-1==LARGEST_INT64 ); + return neg ? rc : 3; + } } } } @@ -28208,8 +33388,9 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. -** 1 Integer too large for a 64-bit signed integer or is malformed -** 2 Special case of 9223372036854775808 +** 1 Excess text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 */ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ #ifndef SQLITE_OMIT_HEX_INTEGER @@ -28223,7 +33404,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ u = u*16 + sqlite3HexToInt(z[k]); } memcpy(pOut, &u, 8); - return (z[k]==0 && k-i<=16) ? 0 : 1; + return (z[k]==0 && k-i<=16) ? 0 : 2; }else #endif /* SQLITE_OMIT_HEX_INTEGER */ { @@ -28270,6 +33451,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ } } #endif + if( !sqlite3Isdigit(zNum[0]) ) return 0; while( zNum[0]=='0' ) zNum++; for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){ v = v*10 + c; @@ -28301,10 +33483,28 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){ */ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ int x = 0; - if( z ) sqlite3GetInt32(z, &x); + sqlite3GetInt32(z, &x); return x; } +/* +** Try to convert z into an unsigned 32-bit integer. Return true on +** success and false if there is an error. +** +** Only decimal notation is accepted. +*/ +SQLITE_PRIVATE int sqlite3GetUInt32(const char *z, u32 *pI){ + u64 v = 0; + int i; + for(i=0; sqlite3Isdigit(z[i]); i++){ + v = v*10 + z[i] - '0'; + if( v>4294967296LL ){ *pI = 0; return 0; } + } + if( i==0 || z[i]!=0 ){ *pI = 0; return 0; } + *pI = (u32)v; + return 1; +} + /* ** The variable-length integer encoding is as follows: ** @@ -28345,7 +33545,7 @@ static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){ v >>= 7; } return 9; - } + } n = 0; do{ buf[n++] = (u8)((v & 0x7f) | 0x80); @@ -28391,23 +33591,12 @@ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ u32 a,b,s; - a = *p; - /* a: p0 (unmasked) */ - if (!(a&0x80)) - { - *v = a; + if( ((signed char*)p)[0]>=0 ){ + *v = *p; return 1; } - - p++; - b = *p; - /* b: p1 (unmasked) */ - if (!(b&0x80)) - { - a &= 0x7f; - a = a<<7; - a |= b; - *v = a; + if( ((signed char*)p)[1]>=0 ){ + *v = ((u32)(p[0]&0x7f)<<7) | p[1]; return 2; } @@ -28415,8 +33604,9 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); - p++; - a = a<<14; + a = ((u32)p[0])<<14; + b = p[1]; + p += 2; a |= *p; /* a: p0<<14 | p2 (unmasked) */ if (!(a&0x80)) @@ -28555,8 +33745,8 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ ** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned ** integer, then set *v to 0xffffffff. ** -** A MACRO version, getVarint32, is provided which inlines the -** single-byte case. All code should use the MACRO version as +** A MACRO version, getVarint32, is provided which inlines the +** single-byte case. All code should use the MACRO version as ** this function assumes the single-byte case has already been handled. */ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ @@ -28617,8 +33807,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){ u64 v64; u8 n; - p -= 2; - n = sqlite3GetVarint(p, &v64); + n = sqlite3GetVarint(p-2, &v64); assert( n>3 && n<=9 ); if( (v64 & SQLITE_MAX_U32)!=v64 ){ *v = 0xffffffff; @@ -28697,7 +33886,7 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ u32 x; memcpy(&x,p,4); return x; -#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 u32 x; memcpy(&x,p,4); return __builtin_bswap32(x); @@ -28713,7 +33902,7 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){ SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){ #if SQLITE_BYTEORDER==4321 memcpy(p,&v,4); -#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 u32 x = __builtin_bswap32(v); memcpy(p,&x,4); #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 @@ -28745,7 +33934,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ return (u8)(h & 0xf); } -#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) +#if !defined(SQLITE_OMIT_BLOB_LITERAL) /* ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary ** value. Return a pointer to its binary value. Space to hold the @@ -28766,7 +33955,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ } return zBlob; } -#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ +#endif /* !SQLITE_OMIT_BLOB_LITERAL */ /* ** Log an error that is an API call on a connection pointer that should @@ -28774,7 +33963,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ ** argument. The zType is a word like "NULL" or "closed" or "invalid". */ static void logBadConnection(const char *zType){ - sqlite3_log(SQLITE_MISUSE, + sqlite3_log(SQLITE_MISUSE, "API call with %s database connection pointer", zType ); @@ -28795,13 +33984,13 @@ static void logBadConnection(const char *zType){ ** used as an argument to sqlite3_errmsg() or sqlite3_close(). */ SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){ - u32 magic; + u8 eOpenState; if( db==0 ){ logBadConnection("NULL"); return 0; } - magic = db->magic; - if( magic!=SQLITE_MAGIC_OPEN ){ + eOpenState = db->eOpenState; + if( eOpenState!=SQLITE_STATE_OPEN ){ if( sqlite3SafetyCheckSickOrOk(db) ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("unopened"); @@ -28812,11 +34001,11 @@ SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){ } } SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ - u32 magic; - magic = db->magic; - if( magic!=SQLITE_MAGIC_SICK && - magic!=SQLITE_MAGIC_OPEN && - magic!=SQLITE_MAGIC_BUSY ){ + u8 eOpenState; + eOpenState = db->eOpenState; + if( eOpenState!=SQLITE_STATE_SICK && + eOpenState!=SQLITE_STATE_OPEN && + eOpenState!=SQLITE_STATE_BUSY ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("invalid"); return 0; @@ -28832,7 +34021,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ ** overflow, leave *pA unchanged and return 1. */ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ -#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000 +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_add_overflow(*pA, iB, pA); #else i64 iA = *pA; @@ -28848,11 +34037,11 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){ if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1; } *pA += iB; - return 0; + return 0; #endif } SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ -#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000 +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_sub_overflow(*pA, iB, pA); #else testcase( iB==SMALLEST_INT64+1 ); @@ -28867,7 +34056,7 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){ #endif } SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ -#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000 +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) return __builtin_mul_overflow(*pA, iB, pA); #else i64 iA = *pA; @@ -28889,7 +34078,7 @@ SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){ } /* -** Compute the absolute value of a 32-bit signed integer, of possible. Or +** Compute the absolute value of a 32-bit signed integer, of possible. Or ** if the integer has a value of -2147483648, return +2147483647 */ SQLITE_PRIVATE int sqlite3AbsInt32(int x){ @@ -28929,11 +34118,11 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ } #endif -/* +/* ** Find (an approximate) sum of two LogEst values. This computation is ** not a simple "+" operator because LogEst is stored as a logarithmic ** value. -** +** */ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){ static const unsigned char x[] = { @@ -28969,13 +34158,18 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){ if( x<2 ) return 0; while( x<8 ){ y -= 10; x <<= 1; } }else{ +#if GCC_VERSION>=5004000 + int i = 60 - __builtin_clzll(x); + y += i*10; + x >>= i; +#else while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ while( x>15 ){ y += 10; x >>= 1; } +#endif } return a[x&7] + y - 10; } -#ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Convert a double into a LogEst ** In other words, compute an approximation for 10*log2(x). @@ -28990,16 +34184,9 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){ e = (a>>52) - 1022; return e*10; } -#endif /* SQLITE_OMIT_VIRTUALTABLE */ -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ - defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \ - defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) /* ** Convert a LogEst into an integer. -** -** Note that this routine is only used when one or more of various -** non-standard compile-time options is enabled. */ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ u64 n; @@ -29007,17 +34194,9 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; -#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ - defined(SQLITE_EXPLAIN_ESTIMATED_ROWS) if( x>60 ) return (u64)LARGEST_INT64; -#else - /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input - ** possible to this routine is 310, resulting in a maximum x of 31 */ - assert( x<=60 ); -#endif return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); } -#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */ /* ** Add a new name/number pair to a VList. This might require that the @@ -29041,8 +34220,8 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ ** Conceptually: ** ** struct VList { -** int nAlloc; // Number of allocated slots -** int nUsed; // Number of used slots +** int nAlloc; // Number of allocated slots +** int nUsed; // Number of used slots ** struct VListEntry { ** int iValue; // Value for this entry ** int nSlot; // Slots used by this entry @@ -29051,7 +34230,7 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){ ** } ** ** During code generation, pointers to the variable names within the -** VList are taken. When that happens, nAlloc is set to zero as an +** VList are taken. When that happens, nAlloc is set to zero as an ** indication that the VList may never again be enlarged, since the ** accompanying realloc() would invalidate the pointers. */ @@ -29070,7 +34249,7 @@ SQLITE_PRIVATE VList *sqlite3VListAdd( assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ if( pIn==0 || pIn[1]+nInt > pIn[0] ){ /* Enlarge the allocation */ - int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt; + sqlite3_int64 nAlloc = (pIn ? 2*(sqlite3_int64)pIn[0] : 10) + nInt; VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); if( pOut==0 ) return pIn; if( pIn==0 ) pOut[1] = 2; @@ -29242,7 +34421,7 @@ static int rehash(Hash *pH, unsigned int new_size){ /* The inability to allocates space for a larger hash table is ** a performance hit but it is not a fatal error. So mark the - ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of + ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of ** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero() ** only zeroes the requested number of bytes whereas this module will ** use the actual amount of space allocated for the hash table (which @@ -29266,8 +34445,9 @@ static int rehash(Hash *pH, unsigned int new_size){ } /* This function (for internal use only) locates an element in an -** hash table that matches the given key. The hash for this key is -** also computed and returned in the *pH parameter. +** hash table that matches the given key. If no element is found, +** a pointer to a static null element with HashElem.data==0 is returned. +** If pH is not NULL, then the hash for this key is written to *pH. */ static HashElem *findElementWithHash( const Hash *pH, /* The pH to be searched */ @@ -29275,8 +34455,9 @@ static HashElem *findElementWithHash( unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ - int count; /* Number of elements left to test */ + unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ + static HashElem nullElement = { 0, 0, 0, 0 }; if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/ struct _ht *pEntry; @@ -29289,15 +34470,15 @@ static HashElem *findElementWithHash( elem = pH->first; count = pH->count; } - *pHash = h; + if( pHash ) *pHash = h; while( count-- ){ assert( elem!=0 ); - if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ + if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; } - return 0; + return &nullElement; } /* Remove a single entry from the hash table given a pointer to that @@ -29310,7 +34491,7 @@ static void removeElementGivenHash( ){ struct _ht *pEntry; if( elem->prev ){ - elem->prev->next = elem->next; + elem->prev->next = elem->next; }else{ pH->first = elem->next; } @@ -29322,8 +34503,8 @@ static void removeElementGivenHash( if( pEntry->chain==elem ){ pEntry->chain = elem->next; } + assert( pEntry->count>0 ); pEntry->count--; - assert( pEntry->count>=0 ); } sqlite3_free( elem ); pH->count--; @@ -29339,13 +34520,9 @@ static void removeElementGivenHash( ** found, or NULL if there is no match. */ SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){ - HashElem *elem; /* The element that matches key */ - unsigned int h; /* A hash on key */ - assert( pH!=0 ); assert( pKey!=0 ); - elem = findElementWithHash(pH, pKey, &h); - return elem ? elem->data : 0; + return findElementWithHash(pH, pKey, 0)->data; } /* Insert an element into the hash table pH. The key is pKey @@ -29370,7 +34547,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){ assert( pH!=0 ); assert( pKey!=0 ); elem = findElementWithHash(pH,pKey,&h); - if( elem ){ + if( elem->data ){ void *old_data = elem->data; if( data==0 ){ removeElementGivenHash(pH,elem,h); @@ -29414,164 +34591,187 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 1 */ "AutoCommit" OpHelp(""), /* 2 */ "Transaction" OpHelp(""), /* 3 */ "SorterNext" OpHelp(""), - /* 4 */ "PrevIfOpen" OpHelp(""), - /* 5 */ "NextIfOpen" OpHelp(""), - /* 6 */ "Prev" OpHelp(""), - /* 7 */ "Next" OpHelp(""), - /* 8 */ "Checkpoint" OpHelp(""), - /* 9 */ "JournalMode" OpHelp(""), - /* 10 */ "Vacuum" OpHelp(""), - /* 11 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), - /* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"), - /* 13 */ "Goto" OpHelp(""), - /* 14 */ "Gosub" OpHelp(""), - /* 15 */ "InitCoroutine" OpHelp(""), - /* 16 */ "Yield" OpHelp(""), - /* 17 */ "MustBeInt" OpHelp(""), - /* 18 */ "Jump" OpHelp(""), + /* 4 */ "Prev" OpHelp(""), + /* 5 */ "Next" OpHelp(""), + /* 6 */ "Checkpoint" OpHelp(""), + /* 7 */ "JournalMode" OpHelp(""), + /* 8 */ "Vacuum" OpHelp(""), + /* 9 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), + /* 10 */ "VUpdate" OpHelp("data=r[P3@P2]"), + /* 11 */ "Goto" OpHelp(""), + /* 12 */ "Gosub" OpHelp(""), + /* 13 */ "InitCoroutine" OpHelp(""), + /* 14 */ "Yield" OpHelp(""), + /* 15 */ "MustBeInt" OpHelp(""), + /* 16 */ "Jump" OpHelp(""), + /* 17 */ "Once" OpHelp(""), + /* 18 */ "If" OpHelp(""), /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), - /* 20 */ "Once" OpHelp(""), - /* 21 */ "If" OpHelp(""), - /* 22 */ "IfNot" OpHelp(""), + /* 20 */ "IfNot" OpHelp(""), + /* 21 */ "IsNullOrType" OpHelp("if typeof(r[P1]) IN (P3,5) goto P2"), + /* 22 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), /* 23 */ "SeekLT" OpHelp("key=r[P3@P4]"), /* 24 */ "SeekLE" OpHelp("key=r[P3@P4]"), /* 25 */ "SeekGE" OpHelp("key=r[P3@P4]"), /* 26 */ "SeekGT" OpHelp("key=r[P3@P4]"), - /* 27 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), - /* 28 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), + /* 27 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"), + /* 28 */ "IfNoHope" OpHelp("key=r[P3@P4]"), /* 29 */ "NoConflict" OpHelp("key=r[P3@P4]"), /* 30 */ "NotFound" OpHelp("key=r[P3@P4]"), /* 31 */ "Found" OpHelp("key=r[P3@P4]"), /* 32 */ "SeekRowid" OpHelp("intkey=r[P3]"), /* 33 */ "NotExists" OpHelp("intkey=r[P3]"), - /* 34 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), - /* 35 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), - /* 36 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), - /* 37 */ "Eq" OpHelp("IF r[P3]==r[P1]"), - /* 38 */ "Gt" OpHelp("IF r[P3]>r[P1]"), - /* 39 */ "Le" OpHelp("IF r[P3]<=r[P1]"), - /* 40 */ "Lt" OpHelp("IF r[P3]=r[P1]"), - /* 42 */ "ElseNotEq" OpHelp(""), - /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), - /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), - /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), - /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), - /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), - /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), - /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), - /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), - /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 53 */ "Last" OpHelp(""), - /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"), - /* 55 */ "SorterSort" OpHelp(""), - /* 56 */ "Sort" OpHelp(""), - /* 57 */ "Rewind" OpHelp(""), - /* 58 */ "IdxLE" OpHelp("key=r[P3@P4]"), - /* 59 */ "IdxGT" OpHelp("key=r[P3@P4]"), - /* 60 */ "IdxLT" OpHelp("key=r[P3@P4]"), - /* 61 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 62 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 63 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 64 */ "Program" OpHelp(""), - /* 65 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), - /* 66 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 67 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), - /* 68 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 69 */ "IncrVacuum" OpHelp(""), - /* 70 */ "VNext" OpHelp(""), - /* 71 */ "Init" OpHelp("Start at P2"), - /* 72 */ "Return" OpHelp(""), - /* 73 */ "EndCoroutine" OpHelp(""), - /* 74 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 75 */ "Halt" OpHelp(""), - /* 76 */ "Integer" OpHelp("r[P2]=P1"), - /* 77 */ "Int64" OpHelp("r[P2]=P4"), - /* 78 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 79 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 80 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 81 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 82 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 83 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 84 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 85 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 86 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 87 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 88 */ "CollSeq" OpHelp(""), - /* 89 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), - /* 90 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), - /* 91 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 92 */ "RealAffinity" OpHelp(""), - /* 93 */ "Cast" OpHelp("affinity(r[P1])"), - /* 94 */ "Permutation" OpHelp(""), - /* 95 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 96 */ "Column" OpHelp("r[P3]=PX"), - /* 97 */ "String8" OpHelp("r[P2]='P4'"), - /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 100 */ "Count" OpHelp("r[P2]=count()"), - /* 101 */ "ReadCookie" OpHelp(""), - /* 102 */ "SetCookie" OpHelp(""), - /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 106 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 107 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 108 */ "SorterOpen" OpHelp(""), - /* 109 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), - /* 110 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 111 */ "Close" OpHelp(""), - /* 112 */ "ColumnsUsed" OpHelp(""), - /* 113 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 114 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 115 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 116 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 117 */ "Delete" OpHelp(""), - /* 118 */ "ResetCount" OpHelp(""), - /* 119 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 120 */ "SorterData" OpHelp("r[P2]=data"), - /* 121 */ "RowData" OpHelp("r[P2]=data"), - /* 122 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 123 */ "NullRow" OpHelp(""), - /* 124 */ "SorterInsert" OpHelp("key=r[P2]"), - /* 125 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 126 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 127 */ "Seek" OpHelp("Move P3 to P1.rowid"), - /* 128 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 129 */ "Destroy" OpHelp(""), - /* 130 */ "Clear" OpHelp(""), - /* 131 */ "ResetSorter" OpHelp(""), - /* 132 */ "Real" OpHelp("r[P2]=P4"), - /* 133 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), - /* 134 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), - /* 135 */ "ParseSchema" OpHelp(""), - /* 136 */ "LoadAnalysis" OpHelp(""), - /* 137 */ "DropTable" OpHelp(""), - /* 138 */ "DropIndex" OpHelp(""), - /* 139 */ "DropTrigger" OpHelp(""), - /* 140 */ "IntegrityCk" OpHelp(""), - /* 141 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 142 */ "Param" OpHelp(""), - /* 143 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 144 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 145 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 146 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 147 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 148 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 149 */ "Expire" OpHelp(""), - /* 150 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 151 */ "VBegin" OpHelp(""), - /* 152 */ "VCreate" OpHelp(""), - /* 153 */ "VDestroy" OpHelp(""), - /* 154 */ "VOpen" OpHelp(""), - /* 155 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 156 */ "VRename" OpHelp(""), - /* 157 */ "Pagecount" OpHelp(""), - /* 158 */ "MaxPgcnt" OpHelp(""), - /* 159 */ "CursorHint" OpHelp(""), - /* 160 */ "Noop" OpHelp(""), - /* 161 */ "Explain" OpHelp(""), + /* 34 */ "Last" OpHelp(""), + /* 35 */ "IfSmaller" OpHelp(""), + /* 36 */ "SorterSort" OpHelp(""), + /* 37 */ "Sort" OpHelp(""), + /* 38 */ "Rewind" OpHelp(""), + /* 39 */ "IdxLE" OpHelp("key=r[P3@P4]"), + /* 40 */ "IdxGT" OpHelp("key=r[P3@P4]"), + /* 41 */ "IdxLT" OpHelp("key=r[P3@P4]"), + /* 42 */ "IdxGE" OpHelp("key=r[P3@P4]"), + /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), + /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), + /* 45 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 46 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 47 */ "Program" OpHelp(""), + /* 48 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 49 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), + /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), + /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), + /* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"), + /* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"), + /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"), + /* 56 */ "Lt" OpHelp("IF r[P3]=r[P1]"), + /* 58 */ "ElseEq" OpHelp(""), + /* 59 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 60 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 61 */ "IncrVacuum" OpHelp(""), + /* 62 */ "VNext" OpHelp(""), + /* 63 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), + /* 64 */ "Init" OpHelp("Start at P2"), + /* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), + /* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), + /* 67 */ "Return" OpHelp(""), + /* 68 */ "EndCoroutine" OpHelp(""), + /* 69 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 70 */ "Halt" OpHelp(""), + /* 71 */ "Integer" OpHelp("r[P2]=P1"), + /* 72 */ "Int64" OpHelp("r[P2]=P4"), + /* 73 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 74 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 75 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 76 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 77 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 78 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 79 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 80 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 81 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 82 */ "FkCheck" OpHelp(""), + /* 83 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 84 */ "CollSeq" OpHelp(""), + /* 85 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 86 */ "RealAffinity" OpHelp(""), + /* 87 */ "Cast" OpHelp("affinity(r[P1])"), + /* 88 */ "Permutation" OpHelp(""), + /* 89 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 90 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), + /* 91 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), + /* 92 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), + /* 93 */ "Column" OpHelp("r[P3]=PX"), + /* 94 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), + /* 95 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 96 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 97 */ "Count" OpHelp("r[P2]=count()"), + /* 98 */ "ReadCookie" OpHelp(""), + /* 99 */ "SetCookie" OpHelp(""), + /* 100 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 101 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<>r[P1]"), + /* 106 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 107 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 108 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 112 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 113 */ "OpenDup" OpHelp(""), + /* 114 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), + /* 115 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 116 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 117 */ "String8" OpHelp("r[P2]='P4'"), + /* 118 */ "SorterOpen" OpHelp(""), + /* 119 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 120 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 121 */ "Close" OpHelp(""), + /* 122 */ "ColumnsUsed" OpHelp(""), + /* 123 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"), + /* 124 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"), + /* 125 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 126 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 127 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 128 */ "RowCell" OpHelp(""), + /* 129 */ "Delete" OpHelp(""), + /* 130 */ "ResetCount" OpHelp(""), + /* 131 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 132 */ "SorterData" OpHelp("r[P2]=data"), + /* 133 */ "RowData" OpHelp("r[P2]=data"), + /* 134 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 135 */ "NullRow" OpHelp(""), + /* 136 */ "SeekEnd" OpHelp(""), + /* 137 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 138 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 139 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 140 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), + /* 141 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 142 */ "FinishSeek" OpHelp(""), + /* 143 */ "Destroy" OpHelp(""), + /* 144 */ "Clear" OpHelp(""), + /* 145 */ "ResetSorter" OpHelp(""), + /* 146 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), + /* 147 */ "SqlExec" OpHelp(""), + /* 148 */ "ParseSchema" OpHelp(""), + /* 149 */ "LoadAnalysis" OpHelp(""), + /* 150 */ "DropTable" OpHelp(""), + /* 151 */ "DropIndex" OpHelp(""), + /* 152 */ "DropTrigger" OpHelp(""), + /* 153 */ "Real" OpHelp("r[P2]=P4"), + /* 154 */ "IntegrityCk" OpHelp(""), + /* 155 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 156 */ "Param" OpHelp(""), + /* 157 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 158 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 159 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 160 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 161 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 162 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 163 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 164 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 165 */ "Expire" OpHelp(""), + /* 166 */ "CursorLock" OpHelp(""), + /* 167 */ "CursorUnlock" OpHelp(""), + /* 168 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 169 */ "VBegin" OpHelp(""), + /* 170 */ "VCreate" OpHelp(""), + /* 171 */ "VDestroy" OpHelp(""), + /* 172 */ "VOpen" OpHelp(""), + /* 173 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), + /* 174 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 175 */ "VRename" OpHelp(""), + /* 176 */ "Pagecount" OpHelp(""), + /* 177 */ "MaxPgcnt" OpHelp(""), + /* 178 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), + /* 179 */ "Trace" OpHelp(""), + /* 180 */ "CursorHint" OpHelp(""), + /* 181 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 182 */ "Noop" OpHelp(""), + /* 183 */ "Explain" OpHelp(""), + /* 184 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -29642,7 +34842,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ ** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE ** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic ** selection of the appropriate locking style based on the filesystem -** where the database is located. +** where the database is located. */ #if !defined(SQLITE_ENABLE_LOCKING_STYLE) # if defined(__APPLE__) @@ -29671,6 +34871,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #include #include #include +#include #include /* #include */ #include @@ -29680,18 +34881,35 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #endif #if SQLITE_ENABLE_LOCKING_STYLE -# include +/* # include */ # include # include #endif /* SQLITE_ENABLE_LOCKING_STYLE */ -#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ - (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) -# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ - && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0)) -# define HAVE_GETHOSTUUID 1 -# else -# warning "gethostuuid() is disabled." +/* +** Try to determine if gethostuuid() is available based on standard +** macros. This might sometimes compute the wrong value for some +** obscure platforms. For those cases, simply compile with one of +** the following: +** +** -DHAVE_GETHOSTUUID=0 +** -DHAVE_GETHOSTUUID=1 +** +** None if this matters except when building on Apple products with +** -DSQLITE_ENABLE_LOCKING_STYLE. +*/ +#ifndef HAVE_GETHOSTUUID +# define HAVE_GETHOSTUUID 0 +# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ + (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) +# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ + && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))\ + && (!defined(TARGET_OS_MACCATALYST) || (TARGET_OS_MACCATALYST==0)) +# undef HAVE_GETHOSTUUID +# define HAVE_GETHOSTUUID 1 +# else +# warning "gethostuuid() is disabled." +# endif # endif #endif @@ -29716,12 +34934,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* -** If we are to be thread-safe, include the pthreads header and define -** the SQLITE_UNIX_THREADS macro. +** If we are to be thread-safe, include the pthreads header. */ #if SQLITE_THREADSAFE /* # include */ -# define SQLITE_UNIX_THREADS 1 #endif /* @@ -29753,7 +34969,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #define osGetpid(X) (pid_t)getpid() /* -** Only set the lastErrno if the error code is a real error and not +** Only set the lastErrno if the error code is a real error and not ** a normal expected return code of SQLITE_BUSY or SQLITE_OK */ #define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY)) @@ -29790,7 +35006,7 @@ struct unixFile { unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ - UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ + UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ @@ -29801,16 +35017,17 @@ struct unixFile { sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ void *pMapRegion; /* Memory mapped region */ #endif -#ifdef __QNXNTO__ int sectorSize; /* Device sector size */ int deviceCharacteristics; /* Precomputed device characteristics */ -#endif #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) unsigned fsFlags; /* cached details from statfs() */ #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + unsigned iBusyTimeout; /* Wait this many millisec on locks */ +#endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ #endif @@ -29820,7 +35037,7 @@ struct unixFile { ** whenever any part of the database changes. An assertion fault will ** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the - ** one described by ticket #3584. + ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ @@ -29829,7 +35046,7 @@ struct unixFile { #endif #ifdef SQLITE_TEST - /* In test mode, increase the size of this structure a bit so that + /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; @@ -29861,205 +35078,7 @@ static pid_t randomnessPid = 0; /* ** Include code that is common to all os_*.c files */ -/************** Include os_common.h in the middle of os_unix.c ***************/ -/************** Begin file os_common.h ***************************************/ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains macros and a little bit of code that is common to -** all of the platform-specific files (os_*.c) and is #included into those -** files. -** -** This file should be #included by the os_*.c files only. It is not a -** general purpose header file. -*/ -#ifndef _OS_COMMON_H_ -#define _OS_COMMON_H_ - -/* -** At least two bugs have slipped in because we changed the MEMORY_DEBUG -** macro to SQLITE_DEBUG and some older makefiles have not yet made the -** switch. The following code should catch this problem at compile-time. -*/ -#ifdef MEMORY_DEBUG -# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." -#endif - -/* -** Macros for performance tracing. Normally turned off. Only works -** on i486 hardware. -*/ -#ifdef SQLITE_PERFORMANCE_TRACE - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -/************** Include hwtime.h in the middle of os_common.h ****************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 class CPUs. -*/ -#ifndef SQLITE_HWTIME_H -#define SQLITE_HWTIME_H - -/* -** The following routine only works on pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. -*/ -#if (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long val; - __asm__ __volatile__ ("rdtsc" : "=A" (val)); - return val; - } - -#elif (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - #error Need implementation of sqlite3Hwtime() for your platform. - - /* - ** To compile without implementing sqlite3Hwtime() for your platform, - ** you can remove the above #error and use the following - ** stub function. You will lose timing support for many - ** of the debugging and testing utilities, but it should at - ** least compile and run. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in os_common.h ******************/ - -static sqlite_uint64 g_start; -static sqlite_uint64 g_elapsed; -#define TIMER_START g_start=sqlite3Hwtime() -#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start -#define TIMER_ELAPSED g_elapsed -#else -#define TIMER_START -#define TIMER_END -#define TIMER_ELAPSED ((sqlite_uint64)0) -#endif - -/* -** If we compile with the SQLITE_TEST macro set, then the following block -** of code will give us the ability to simulate a disk I/O error. This -** is used for testing the I/O recovery logic. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_io_error_hit; -SQLITE_API extern int sqlite3_io_error_hardhit; -SQLITE_API extern int sqlite3_io_error_pending; -SQLITE_API extern int sqlite3_io_error_persist; -SQLITE_API extern int sqlite3_io_error_benign; -SQLITE_API extern int sqlite3_diskfull_pending; -SQLITE_API extern int sqlite3_diskfull; -#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) -#define SimulateIOError(CODE) \ - if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ - || sqlite3_io_error_pending-- == 1 ) \ - { local_ioerr(); CODE; } -static void local_ioerr(){ - IOTRACE(("IOERR\n")); - sqlite3_io_error_hit++; - if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; -} -#define SimulateDiskfullError(CODE) \ - if( sqlite3_diskfull_pending ){ \ - if( sqlite3_diskfull_pending == 1 ){ \ - local_ioerr(); \ - sqlite3_diskfull = 1; \ - sqlite3_io_error_hit = 1; \ - CODE; \ - }else{ \ - sqlite3_diskfull_pending--; \ - } \ - } -#else -#define SimulateIOErrorBenign(X) -#define SimulateIOError(A) -#define SimulateDiskfullError(A) -#endif /* defined(SQLITE_TEST) */ - -/* -** When testing, keep a count of the number of open files. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_open_file_count; -#define OpenCounter(X) sqlite3_open_file_count+=(X) -#else -#define OpenCounter(X) -#endif /* defined(SQLITE_TEST) */ - -#endif /* !defined(_OS_COMMON_H_) */ - -/************** End of os_common.h *******************************************/ -/************** Continuing where we left off in os_unix.c ********************/ +/* #include "os_common.h" */ /* ** Define various macros that are missing from some systems. @@ -30107,6 +35126,20 @@ SQLITE_API extern int sqlite3_open_file_count; # define lseek lseek64 #endif +#ifdef __linux__ +/* +** Linux-specific IOCTL magic numbers used for controlling F2FS +*/ +#define F2FS_IOCTL_MAGIC 0xf5 +#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) +#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) +#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) +#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) +#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32) +#define F2FS_FEATURE_ATOMIC_WRITE 0x0004 +#endif /* __linux__ */ + + /* ** Different Unix systems declare open() in different ways. Same use ** open(const char*,int,mode_t). Others use open(const char*,int,...). @@ -30158,7 +35191,7 @@ static struct unix_syscall { #ifdef __DJGPP__ { "fstat", 0, 0 }, #define osFstat(a,b,c) 0 -#else +#else { "fstat", (sqlite3_syscall_ptr)fstat, 0 }, #define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent) #endif @@ -30234,7 +35267,11 @@ static struct unix_syscall { #endif #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) +#if defined(HAVE_FCHOWN) { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, +#else + { "geteuid", (sqlite3_syscall_ptr)0, 0 }, +#endif #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 @@ -30249,7 +35286,7 @@ static struct unix_syscall { #else { "munmap", (sqlite3_syscall_ptr)0, 0 }, #endif -#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent) +#define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent) #if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "mremap", (sqlite3_syscall_ptr)mremap, 0 }, @@ -30279,6 +35316,18 @@ static struct unix_syscall { #endif #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) +# ifdef __ANDROID__ + { "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 }, +#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) +# else + { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, +#define osIoctl ((int(*)(int,unsigned long,...))aSyscall[28].pCurrent) +# endif +#else + { "ioctl", (sqlite3_syscall_ptr)0, 0 }, +#endif + }; /* End of the overrideable system calls */ @@ -30380,7 +35429,7 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){ /* ** Do not accept any file descriptor less than this value, in order to avoid -** opening database file using file descriptors that are commonly used for +** opening database file using file descriptors that are commonly used for ** standard input, output, and error. */ #ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR @@ -30419,17 +35468,17 @@ static int robust_open(const char *z, int f, mode_t m){ } if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; osClose(fd); - sqlite3_log(SQLITE_WARNING, + sqlite3_log(SQLITE_WARNING, "attempt to open \"%s\" as file descriptor %d", z, fd); fd = -1; - if( osOpen("/dev/null", f, m)<0 ) break; + if( osOpen("/dev/null", O_RDONLY, m)<0 ) break; } if( fd>=0 ){ if( m!=0 ){ struct stat statbuf; - if( osFstat(fd, &statbuf)==0 + if( osFstat(fd, &statbuf)==0 && statbuf.st_size==0 - && (statbuf.st_mode&0777)!=m + && (statbuf.st_mode&0777)!=m ){ osFchmod(fd, m); } @@ -30444,26 +35493,40 @@ static int robust_open(const char *z, int f, mode_t m){ /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the unixInodeInfo and -** vxworksFileId objects used by this file, all of which may be +** vxworksFileId objects used by this file, all of which may be ** shared by multiple threads. ** -** Function unixMutexHeld() is used to assert() that the global mutex -** is held when required. This function is only used as part of assert() +** Function unixMutexHeld() is used to assert() that the global mutex +** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** unixEnterMutex() ** assert( unixMutexHeld() ); ** unixEnterLeave() +** +** To prevent deadlock, the global unixBigLock must must be acquired +** before the unixInodeInfo.pLockMutex mutex, if both are held. It is +** OK to get the pLockMutex without holding unixBigLock first, but if +** that happens, the unixBigLock mutex must not be acquired until after +** pLockMutex is released. +** +** OK: enter(unixBigLock), enter(pLockInfo) +** OK: enter(unixBigLock) +** OK: enter(pLockInfo) +** ERROR: enter(pLockInfo), enter(unixBigLock) */ +static sqlite3_mutex *unixBigLock = 0; static void unixEnterMutex(void){ - sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); + assert( sqlite3_mutex_notheld(unixBigLock) ); /* Not a recursive mutex */ + sqlite3_mutex_enter(unixBigLock); } static void unixLeaveMutex(void){ - sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); + assert( sqlite3_mutex_held(unixBigLock) ); + sqlite3_mutex_leave(unixBigLock); } #ifdef SQLITE_DEBUG static int unixMutexHeld(void) { - return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); + return sqlite3_mutex_held(unixBigLock); } #endif @@ -30556,7 +35619,7 @@ static int lockTrace(int fd, int op, struct flock *p){ static int robust_ftruncate(int h, sqlite3_int64 sz){ int rc; #ifdef __ANDROID__ - /* On Android, ftruncate() always uses 32-bit offsets, even if + /* On Android, ftruncate() always uses 32-bit offsets, even if ** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to ** truncate a file to any size larger than 2GiB. Silently ignore any ** such attempts. */ @@ -30572,32 +35635,32 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){ ** This routine translates a standard POSIX errno code into something ** useful to the clients of the sqlite3 functions. Specifically, it is ** intended to translate a variety of "try again" errors into SQLITE_BUSY -** and a variety of "please close the file descriptor NOW" errors into +** and a variety of "please close the file descriptor NOW" errors into ** SQLITE_IOERR -** +** ** Errors during initialization of locks, or file system support for locks, ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. */ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { - assert( (sqliteIOErr == SQLITE_IOERR_LOCK) || - (sqliteIOErr == SQLITE_IOERR_UNLOCK) || + assert( (sqliteIOErr == SQLITE_IOERR_LOCK) || + (sqliteIOErr == SQLITE_IOERR_UNLOCK) || (sqliteIOErr == SQLITE_IOERR_RDLOCK) || (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) ); switch (posixError) { - case EACCES: + case EACCES: case EAGAIN: case ETIMEDOUT: case EBUSY: case EINTR: - case ENOLCK: - /* random NFS retry error, unless during file system support + case ENOLCK: + /* random NFS retry error, unless during file system support * introspection, in which it actually means what it says */ return SQLITE_BUSY; - - case EPERM: + + case EPERM: return SQLITE_PERM; - - default: + + default: return sqliteIOErr; } } @@ -30612,7 +35675,7 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { ** ** A pointer to an instance of the following structure can be used as a ** unique file ID in VxWorks. Each instance of this structure contains -** a copy of the canonical filename. There is also a reference count. +** a copy of the canonical filename. There is also a reference count. ** The structure is reclaimed when the number of pointers to it drops to ** zero. ** @@ -30628,7 +35691,7 @@ struct vxworksFileId { }; #if OS_VXWORKS -/* +/* ** All unique filenames are held on a linked list headed by this ** variable: */ @@ -30700,7 +35763,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){ */ unixEnterMutex(); for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){ - if( pCandidate->nName==n + if( pCandidate->nName==n && memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0 ){ sqlite3_free(pNew); @@ -30793,7 +35856,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){ ** cnt>0 means there are cnt shared locks on the file. ** ** Any attempt to lock or unlock a file first checks the locking -** structure. The fcntl() system call is only invoked to set a +** structure. The fcntl() system call is only invoked to set a ** POSIX lock if the internal lock structure transitions between ** a locked and an unlocked state. ** @@ -30826,7 +35889,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){ ** ** SQLite used to support LinuxThreads. But support for LinuxThreads ** was dropped beginning with version 3.7.0. SQLite will still work with -** LinuxThreads provided that (1) there is no more than one connection +** LinuxThreads provided that (1) there is no more than one connection ** per database file in the same process and (2) database connections ** do not move across threads. */ @@ -30843,7 +35906,7 @@ struct unixFileId { /* We are told that some versions of Android contain a bug that ** sizes ino_t at only 32-bits instead of 64-bits. (See ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c) - ** To work around this, always allocate 64-bits for the inode number. + ** To work around this, always allocate 64-bits for the inode number. ** On small machines that only have 32-bit inodes, this wastes 4 bytes, ** but that should not be a big deal. */ /* WAS: ino_t ino; */ @@ -30853,22 +35916,39 @@ struct unixFileId { /* ** An instance of the following structure is allocated for each open -** inode. Or, on LinuxThreads, there is one of these structures for -** each inode opened by each thread. +** inode. ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this ** object keeps a count of the number of unixFile pointing to it. +** +** Mutex rules: +** +** (1) Only the pLockMutex mutex must be held in order to read or write +** any of the locking fields: +** nShared, nLock, eFileLock, bProcessLock, pUnused +** +** (2) When nRef>0, then the following fields are unchanging and can +** be read (but not written) without holding any mutex: +** fileId, pLockMutex +** +** (3) With the exceptions above, all the fields may only be read +** or written while holding the global unixBigLock mutex. +** +** Deadlock prevention: The global unixBigLock mutex may not +** be acquired while holding the pLockMutex mutex. If both unixBigLock +** and pLockMutex are needed, then unixBigLock must be acquired first. */ struct unixInodeInfo { struct unixFileId fileId; /* The lookup key */ - int nShared; /* Number of SHARED locks held */ - unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ - unsigned char bProcessLock; /* An exclusive process lock is held */ + sqlite3_mutex *pLockMutex; /* Hold this mutex for... */ + int nShared; /* Number of SHARED locks held */ + int nLock; /* Number of outstanding file locks */ + unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ + unsigned char bProcessLock; /* An exclusive process lock is held */ + UnixUnusedFd *pUnused; /* Unused file descriptors to close */ int nRef; /* Number of pointers to this structure */ unixShmNode *pShmNode; /* Shared memory associated with this inode */ - int nLock; /* Number of outstanding file locks */ - UnixUnusedFd *pUnused; /* Unused file descriptors to close */ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ unixInodeInfo *pPrev; /* .... doubly linked */ #if SQLITE_ENABLE_LOCKING_STYLE @@ -30882,8 +35962,26 @@ struct unixInodeInfo { /* ** A lists of all unixInodeInfo objects. +** +** Must hold unixBigLock in order to read or write this variable. */ -static unixInodeInfo *inodeList = 0; +static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ + +#ifdef SQLITE_DEBUG +/* +** True if the inode mutex (on the unixFile.pFileMutex field) is held, or not. +** This routine is used only within assert() to help verify correct mutex +** usage. +*/ +int unixFileMutexHeld(unixFile *pFile){ + assert( pFile->pInode ); + return sqlite3_mutex_held(pFile->pInode->pLockMutex); +} +int unixFileMutexNotheld(unixFile *pFile){ + assert( pFile->pInode ); + return sqlite3_mutex_notheld(pFile->pInode->pLockMutex); +} +#endif /* ** @@ -30896,7 +35994,7 @@ static unixInodeInfo *inodeList = 0; ** strerror_r(). ** ** The first argument passed to the macro should be the error code that -** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed (e.g. "unlink", "open") and the associated file-system path, ** if any. @@ -30914,7 +36012,7 @@ static int unixLogErrorAtLine( /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use ** the strerror() function to obtain the human-readable error message ** equivalent to errno. Otherwise, use strerror_r(). - */ + */ #if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R) char aErr[80]; memset(aErr, 0, sizeof(aErr)); @@ -30922,18 +36020,18 @@ static int unixLogErrorAtLine( /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined, ** assume that the system provides the GNU version of strerror_r() that - ** returns a pointer to a buffer containing the error message. That pointer - ** may point to aErr[], or it may point to some static storage somewhere. - ** Otherwise, assume that the system provides the POSIX version of + ** returns a pointer to a buffer containing the error message. That pointer + ** may point to aErr[], or it may point to some static storage somewhere. + ** Otherwise, assume that the system provides the POSIX version of ** strerror_r(), which always writes an error message into aErr[]. ** ** If the code incorrectly assumes that it is the POSIX version that is ** available, the error message will often be an empty string. Not a - ** huge problem. Incorrectly concluding that the GNU version is available + ** huge problem. Incorrectly concluding that the GNU version is available ** could lead to a segfault though. */ #if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU) - zErr = + zErr = # endif strerror_r(iErrno, aErr, sizeof(aErr)-1); @@ -30984,11 +36082,12 @@ static void storeLastErrno(unixFile *pFile, int error){ /* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. -*/ +*/ static void closePendingFds(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p; UnixUnusedFd *pNext; + assert( unixFileMutexHeld(pFile) ); for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; robust_close(pFile, p->fd, __LINE__); @@ -31000,17 +36099,20 @@ static void closePendingFds(unixFile *pFile){ /* ** Release a unixInodeInfo structure previously allocated by findInodeInfo(). ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must be held when this routine is called, but the mutex +** on the inode being deleted must NOT be held. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); + assert( unixFileMutexNotheld(pFile) ); if( ALWAYS(pInode) ){ pInode->nRef--; if( pInode->nRef==0 ){ assert( pInode->pShmNode==0 ); + sqlite3_mutex_enter(pInode->pLockMutex); closePendingFds(pFile); + sqlite3_mutex_leave(pInode->pLockMutex); if( pInode->pPrev ){ assert( pInode->pPrev->pNext==pInode ); pInode->pPrev->pNext = pInode->pNext; @@ -31022,6 +36124,7 @@ static void releaseInodeInfo(unixFile *pFile){ assert( pInode->pNext->pPrev==pInode ); pInode->pNext->pPrev = pInode->pPrev; } + sqlite3_mutex_free(pInode->pLockMutex); sqlite3_free(pInode); } } @@ -31032,8 +36135,7 @@ static void releaseInodeInfo(unixFile *pFile){ ** describes that file descriptor. Create a new one if necessary. The ** return value might be uninitialized if an error occurs. ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must held when calling this routine. ** ** Return an appropriate error code. */ @@ -31094,6 +36196,7 @@ static int findInodeInfo( #else fileId.ino = (u64)statbuf.st_ino; #endif + assert( unixMutexHeld() ); pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; @@ -31105,7 +36208,15 @@ static int findInodeInfo( } memset(pInode, 0, sizeof(*pInode)); memcpy(&pInode->fileId, &fileId, sizeof(fileId)); + if( sqlite3GlobalConfig.bCoreMutex ){ + pInode->pLockMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pInode->pLockMutex==0 ){ + sqlite3_free(pInode); + return SQLITE_NOMEM_BKPT; + } + } pInode->nRef = 1; + assert( unixMutexHeld() ); pInode->pNext = inodeList; pInode->pPrev = 0; if( inodeList ) inodeList->pPrev = pInode; @@ -31126,7 +36237,7 @@ static int fileHasMoved(unixFile *pFile){ #else struct stat buf; return pFile->pInode!=0 && - (osStat(pFile->zPath, &buf)!=0 + (osStat(pFile->zPath, &buf)!=0 || (u64)buf.st_ino!=pFile->pInode->fileId.ino); #endif } @@ -31183,7 +36294,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ assert( pFile ); assert( pFile->eFileLock<=SHARED_LOCK ); - unixEnterMutex(); /* Because pFile->pInode is shared across threads */ + sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ @@ -31207,16 +36318,57 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ } } #endif - - unixLeaveMutex(); + + sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } +/* Forward declaration*/ +static int unixSleep(sqlite3_vfs*,int); + /* -** Attempt to set a system-lock on the file pFile. The lock is +** Set a posix-advisory-lock. +** +** There are two versions of this routine. If compiled with +** SQLITE_ENABLE_SETLK_TIMEOUT then the routine has an extra parameter +** which is a pointer to a unixFile. If the unixFile->iBusyTimeout +** value is set, then it is the number of milliseconds to wait before +** failing the lock. The iBusyTimeout value is always reset back to +** zero on each call. +** +** If SQLITE_ENABLE_SETLK_TIMEOUT is not defined, then do a non-blocking +** attempt to set the lock. +*/ +#ifndef SQLITE_ENABLE_SETLK_TIMEOUT +# define osSetPosixAdvisoryLock(h,x,t) osFcntl(h,F_SETLK,x) +#else +static int osSetPosixAdvisoryLock( + int h, /* The file descriptor on which to take the lock */ + struct flock *pLock, /* The description of the lock */ + unixFile *pFile /* Structure holding timeout value */ +){ + int tm = pFile->iBusyTimeout; + int rc = osFcntl(h,F_SETLK,pLock); + while( rc<0 && tm>0 ){ + /* On systems that support some kind of blocking file lock with a timeout, + ** make appropriate changes here to invoke that blocking file lock. On + ** generic posix, however, there is no such API. So we simply try the + ** lock once every millisecond until either the timeout expires, or until + ** the lock is obtained. */ + unixSleep(0,1000); + rc = osFcntl(h,F_SETLK,pLock); + tm--; + } + return rc; +} +#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ + + +/* +** Attempt to set a system-lock on the file pFile. The lock is ** described by pLock. ** ** If the pFile was opened read/write from unix-excl, then the only lock @@ -31237,8 +36389,8 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ static int unixFileLock(unixFile *pFile, struct flock *pLock){ int rc; unixInodeInfo *pInode = pFile->pInode; - assert( unixMutexHeld() ); assert( pInode!=0 ); + assert( sqlite3_mutex_held(pInode->pLockMutex) ); if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ if( pInode->bProcessLock==0 ){ struct flock lock; @@ -31247,7 +36399,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; lock.l_type = F_WRLCK; - rc = osFcntl(pFile->h, F_SETLK, &lock); + rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile); if( rc<0 ) return rc; pInode->bProcessLock = 1; pInode->nLock++; @@ -31255,7 +36407,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){ rc = 0; } }else{ - rc = osFcntl(pFile->h, F_SETLK, pLock); + rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile); } return rc; } @@ -31308,7 +36460,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** ** A process may only obtain a RESERVED lock after it has a SHARED lock. ** A RESERVED lock is implemented by grabbing a write-lock on the - ** 'reserved byte'. + ** 'reserved byte'. ** ** A process may only obtain a PENDING lock after it has obtained a ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock @@ -31322,7 +36474,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** implemented by obtaining a write-lock on the entire 'shared byte ** range'. Since all other locks require a read-lock on one of the bytes ** within this range, this ensures that no other locks are held on the - ** database. + ** database. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; @@ -31357,13 +36509,13 @@ static int unixLock(sqlite3_file *id, int eFileLock){ /* This mutex is needed because pFile->pInode is shared across threads */ - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ - if( (pFile->eFileLock!=pInode->eFileLock && + if( (pFile->eFileLock!=pInode->eFileLock && (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; @@ -31374,7 +36526,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ ** has a SHARED or RESERVED lock, then increment reference counts and ** return SQLITE_OK. */ - if( eFileLock==SHARED_LOCK && + if( eFileLock==SHARED_LOCK && (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ assert( eFileLock==SHARED_LOCK ); assert( pFile->eFileLock==0 ); @@ -31392,7 +36544,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){ */ lock.l_len = 1L; lock.l_whence = SEEK_SET; - if( eFileLock==SHARED_LOCK + if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLockh, azFileLock(eFileLock), + sqlite3_mutex_leave(pInode->pLockMutex); + OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; } @@ -31513,11 +36665,12 @@ static int unixLock(sqlite3_file *id, int eFileLock){ */ static void setPendingFd(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; - UnixUnusedFd *p = pFile->pUnused; + UnixUnusedFd *p = pFile->pPreallocatedUnused; + assert( unixFileMutexHeld(pFile) ); p->pNext = pInode->pUnused; pInode->pUnused = p; pFile->h = -1; - pFile->pUnused = 0; + pFile->pPreallocatedUnused = 0; } /* @@ -31526,11 +36679,11 @@ static void setPendingFd(unixFile *pFile){ ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. -** +** ** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED ** the byte range is divided into 2 parts and the first part is unlocked then -** set to a read lock, then the other part is simply unlocked. This works -** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to +** set to a read lock, then the other part is simply unlocked. This works +** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to ** remove the write lock on a region when a read lock is set. */ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ @@ -31548,8 +36701,8 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); @@ -31568,7 +36721,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ /* downgrading to a shared lock on NFS involves clearing the write lock ** before establishing the readlock - to avoid a race condition we downgrade - ** the lock in 2 blocks, so that part of the range will be covered by a + ** the lock in 2 blocks, so that part of the range will be covered by a ** write lock until the rest is covered by a read lock: ** 1: [WWWWW] ** 2: [....W] @@ -31584,7 +36737,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ if( handleNFSUnlock ){ int tErrno; /* Error code from system call errors */ off_t divSize = SHARED_SIZE - 1; - + lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; @@ -31626,11 +36779,11 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ lock.l_len = SHARED_SIZE; if( unixFileLock(pFile, &lock) ){ /* In theory, the call to unixFileLock() cannot fail because another - ** process is holding an incompatible lock. If it does, this + ** process is holding an incompatible lock. If it does, this ** indicates that the other process is not following the locking ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning - ** SQLITE_BUSY would confuse the upper layer (in practice it causes - ** an assert to fail). */ + ** SQLITE_BUSY would confuse the upper layer (in practice it causes + ** an assert to fail). */ rc = SQLITE_IOERR_RDLOCK; storeLastErrno(pFile, errno); goto end_unlock; @@ -31675,14 +36828,14 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){ */ pInode->nLock--; assert( pInode->nLock>=0 ); - if( pInode->nLock==0 ){ - closePendingFds(pFile); - } + if( pInode->nLock==0 ) closePendingFds(pFile); } end_unlock: - unixLeaveMutex(); - if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; + sqlite3_mutex_leave(pInode->pLockMutex); + if( rc==SQLITE_OK ){ + pFile->eFileLock = eFileLock; + } return rc; } @@ -31706,7 +36859,7 @@ static void unixUnmapfile(unixFile *pFd); #endif /* -** This function performs the parts of the "close file" operation +** This function performs the parts of the "close file" operation ** common to all locking schemes. It closes the directory and file ** handles, if they are valid, and sets all fields of the unixFile ** structure to 0. @@ -31742,7 +36895,7 @@ static int closeUnixFile(sqlite3_file *id){ #endif OSTRACE(("CLOSE %-3d\n", pFile->h)); OpenCounter(-1); - sqlite3_free(pFile->pUnused); + sqlite3_free(pFile->pPreallocatedUnused); memset(pFile, 0, sizeof(unixFile)); return SQLITE_OK; } @@ -31753,23 +36906,30 @@ static int closeUnixFile(sqlite3_file *id){ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; unixFile *pFile = (unixFile *)id; + unixInodeInfo *pInode = pFile->pInode; + + assert( pInode!=0 ); verifyDbFile(pFile); unixUnlock(id, NO_LOCK); + assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); /* unixFile.pInode is always valid here. Otherwise, a different close ** routine (e.g. nolockClose()) would be called instead. */ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); - if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){ + sqlite3_mutex_enter(pInode->pLockMutex); + if( pInode->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file - ** descriptor to pInode->pUnused list. It will be automatically closed + ** descriptor to pInode->pUnused list. It will be automatically closed ** when the last lock is cleared. */ setPendingFd(pFile); } + sqlite3_mutex_leave(pInode->pLockMutex); releaseInodeInfo(pFile); + assert( pFile->pShm==0 ); rc = closeUnixFile(id); unixLeaveMutex(); return rc; @@ -31863,7 +37023,7 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) { unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); - + assert( pFile ); reserved = osAccess((const char*)pFile->lockingContext, 0)==0; OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved)); @@ -31917,7 +37077,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) { #endif return SQLITE_OK; } - + /* grab an exclusive lock */ rc = osMkdir(zLockFile, 0777); if( rc<0 ){ @@ -31932,8 +37092,8 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) { } } return rc; - } - + } + /* got it, set the type and return ok */ pFile->eFileLock = eFileLock; return rc; @@ -31957,7 +37117,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock, pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); - + /* no-op if possible */ if( pFile->eFileLock==eFileLock ){ return SQLITE_OK; @@ -31970,7 +37130,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { pFile->eFileLock = SHARED_LOCK; return SQLITE_OK; } - + /* To fully unlock the database, delete the lock file */ assert( eFileLock==NO_LOCK ); rc = osRmdir(zLockFile); @@ -31982,7 +37142,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) { rc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, tErrno); } - return rc; + return rc; } pFile->eFileLock = NO_LOCK; return SQLITE_OK; @@ -32029,7 +37189,7 @@ static int robust_flock(int fd, int op){ #else # define robust_flock(a,b) flock(a,b) #endif - + /* ** This routine checks if there is a RESERVED lock held on the specified @@ -32041,16 +37201,16 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; - + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); - + assert( pFile ); - + /* Check if a thread in this process holds such a lock */ if( pFile->eFileLock>SHARED_LOCK ){ reserved = 1; } - + /* Otherwise see if some other process holds it. */ if( !reserved ){ /* attempt to get the lock */ @@ -32061,7 +37221,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ if ( lrc ) { int tErrno = errno; /* unlock failed with an error */ - lrc = SQLITE_IOERR_UNLOCK; + lrc = SQLITE_IOERR_UNLOCK; storeLastErrno(pFile, tErrno); rc = lrc; } @@ -32069,7 +37229,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ int tErrno = errno; reserved = 1; /* someone else might have it reserved */ - lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); + lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(lrc) ){ storeLastErrno(pFile, tErrno); rc = lrc; @@ -32079,7 +37239,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){ OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved)); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ + if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_OK; reserved=1; } @@ -32123,15 +37283,15 @@ static int flockLock(sqlite3_file *id, int eFileLock) { assert( pFile ); - /* if we already have a lock, it is exclusive. + /* if we already have a lock, it is exclusive. ** Just adjust level and punt on outta here. */ if (pFile->eFileLock > NO_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } - + /* grab an exclusive lock */ - + if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) { int tErrno = errno; /* didn't get, must be busy */ @@ -32143,10 +37303,10 @@ static int flockLock(sqlite3_file *id, int eFileLock) { /* got it, set the type and return ok */ pFile->eFileLock = eFileLock; } - OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), + OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS - if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){ + if( (rc & 0xff) == SQLITE_IOERR ){ rc = SQLITE_BUSY; } #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ @@ -32163,23 +37323,23 @@ static int flockLock(sqlite3_file *id, int eFileLock) { */ static int flockUnlock(sqlite3_file *id, int eFileLock) { unixFile *pFile = (unixFile*)id; - + assert( pFile ); OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock, pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); - + /* no-op if possible */ if( pFile->eFileLock==eFileLock ){ return SQLITE_OK; } - + /* shared can just be set because we always have an exclusive */ if (eFileLock==SHARED_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } - + /* no, really, unlock. */ if( robust_flock(pFile->h, LOCK_UN) ){ #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS @@ -32230,14 +37390,14 @@ static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) { unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); - + assert( pFile ); /* Check if a thread in this process holds such a lock */ if( pFile->eFileLock>SHARED_LOCK ){ reserved = 1; } - + /* Otherwise see if some other process holds it. */ if( !reserved ){ sem_t *pSem = pFile->pInode->pSem; @@ -32296,14 +37456,14 @@ static int semXLock(sqlite3_file *id, int eFileLock) { sem_t *pSem = pFile->pInode->pSem; int rc = SQLITE_OK; - /* if we already have a lock, it is exclusive. + /* if we already have a lock, it is exclusive. ** Just adjust level and punt on outta here. */ if (pFile->eFileLock > NO_LOCK) { pFile->eFileLock = eFileLock; rc = SQLITE_OK; goto sem_end_lock; } - + /* lock semaphore now but bail out when already locked. */ if( sem_trywait(pSem)==-1 ){ rc = SQLITE_BUSY; @@ -32333,18 +37493,18 @@ static int semXUnlock(sqlite3_file *id, int eFileLock) { OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock, pFile->eFileLock, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); - + /* no-op if possible */ if( pFile->eFileLock==eFileLock ){ return SQLITE_OK; } - + /* shared can just be set because we always have an exclusive */ if (eFileLock==SHARED_LOCK) { pFile->eFileLock = eFileLock; return SQLITE_OK; } - + /* no, really unlock. */ if ( sem_post(pSem)==-1 ) { int rc, tErrno = errno; @@ -32352,7 +37512,7 @@ static int semXUnlock(sqlite3_file *id, int eFileLock) { if( IS_LOCK_ERROR(rc) ){ storeLastErrno(pFile, tErrno); } - return rc; + return rc; } pFile->eFileLock = NO_LOCK; return SQLITE_OK; @@ -32366,6 +37526,7 @@ static int semXClose(sqlite3_file *id) { unixFile *pFile = (unixFile*)id; semXUnlock(id, NO_LOCK); assert( pFile ); + assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); releaseInodeInfo(pFile); unixLeaveMutex(); @@ -32417,7 +37578,7 @@ struct ByteRangeLockPB2 /* ** This is a utility for setting or clearing a bit-range lock on an ** AFP filesystem. -** +** ** Return SQLITE_OK on success, SQLITE_BUSY on failure. */ static int afpSetLock( @@ -32429,14 +37590,14 @@ static int afpSetLock( ){ struct ByteRangeLockPB2 pb; int err; - + pb.unLockFlag = setLockFlag ? 0 : 1; pb.startEndFlag = 0; pb.offset = offset; - pb.length = length; + pb.length = length; pb.fd = pFile->h; - - OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n", + + OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n", (setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""), offset, length)); err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0); @@ -32471,27 +37632,26 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ int reserved = 0; unixFile *pFile = (unixFile*)id; afpLockingContext *context; - + SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); - + assert( pFile ); context = (afpLockingContext *) pFile->lockingContext; if( context->reserved ){ *pResOut = 1; return SQLITE_OK; } - unixEnterMutex(); /* Because pFile->pInode is shared across threads */ - + sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; } - + /* Otherwise see if some other process holds it. */ if( !reserved ){ /* lock the RESERVED byte */ - int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); + int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1); if( SQLITE_OK==lrc ){ /* if we succeeded in taking the reserved lock, unlock it to restore ** the original state */ @@ -32504,10 +37664,10 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){ rc=lrc; } } - - unixLeaveMutex(); + + sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved)); - + *pResOut = reserved; return rc; } @@ -32541,7 +37701,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){ unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode = pFile->pInode; afpLockingContext *context = (afpLockingContext *) pFile->lockingContext; - + assert( pFile ); OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h, azFileLock(eFileLock), azFileLock(pFile->eFileLock), @@ -32565,27 +37725,27 @@ static int afpLock(sqlite3_file *id, int eFileLock){ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); - + /* This mutex is needed because pFile->pInode is shared across threads */ - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ - if( (pFile->eFileLock!=pInode->eFileLock && + if( (pFile->eFileLock!=pInode->eFileLock && (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ rc = SQLITE_BUSY; goto afp_end_lock; } - + /* If a SHARED lock is requested, and some thread using this PID already ** has a SHARED or RESERVED lock, then increment reference counts and ** return SQLITE_OK. */ - if( eFileLock==SHARED_LOCK && + if( eFileLock==SHARED_LOCK && (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ assert( eFileLock==SHARED_LOCK ); assert( pFile->eFileLock==0 ); @@ -32595,12 +37755,12 @@ static int afpLock(sqlite3_file *id, int eFileLock){ pInode->nLock++; goto afp_end_lock; } - + /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ - if( eFileLock==SHARED_LOCK + if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLocknShared==0 ); assert( pInode->eFileLock==0 ); - + mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff; /* Now get the read-lock SHARED_LOCK */ /* note that the quality of the randomness doesn't matter that much */ - lk = random(); + lk = random(); pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1); - lrc1 = afpSetLock(context->dbPath, pFile, + lrc1 = afpSetLock(context->dbPath, pFile, SHARED_FIRST+pInode->sharedByte, 1, 1); if( IS_LOCK_ERROR(lrc1) ){ lrc1Errno = pFile->lastErrno; } /* Drop the temporary PENDING lock */ lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); - + if( IS_LOCK_ERROR(lrc1) ) { storeLastErrno(pFile, lrc1Errno); rc = lrc1; @@ -32668,34 +37828,34 @@ static int afpLock(sqlite3_file *id, int eFileLock){ } if (!failed && eFileLock == EXCLUSIVE_LOCK) { /* Acquire an EXCLUSIVE lock */ - - /* Remove the shared lock before trying the range. we'll need to + + /* Remove the shared lock before trying the range. we'll need to ** reestablish the shared lock if we can't get the afpUnlock */ if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST + pInode->sharedByte, 1, 0)) ){ int failed2 = SQLITE_OK; /* now attemmpt to get the exclusive lock range */ - failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST, + failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 1); - if( failed && (failed2 = afpSetLock(context->dbPath, pFile, + if( failed && (failed2 = afpSetLock(context->dbPath, pFile, SHARED_FIRST + pInode->sharedByte, 1, 1)) ){ /* Can't reestablish the shared lock. Sqlite can't deal, this is ** a critical I/O error */ - rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 : + rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 : SQLITE_IOERR_LOCK; goto afp_end_lock; - } + } }else{ - rc = failed; + rc = failed; } } if( failed ){ rc = failed; } } - + if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; pInode->eFileLock = eFileLock; @@ -32703,10 +37863,10 @@ static int afpLock(sqlite3_file *id, int eFileLock){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } - + afp_end_lock: - unixLeaveMutex(); - OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), + sqlite3_mutex_leave(pInode->pLockMutex); + OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; } @@ -32737,15 +37897,15 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } - unixEnterMutex(); pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); SimulateIOErrorBenign(1); SimulateIOError( h=(-1) ) SimulateIOErrorBenign(0); - + #ifdef SQLITE_DEBUG /* When reducing a lock such that other processes can start ** reading the database file again, make sure that the @@ -32760,7 +37920,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { || pFile->transCntrChng==1 ); pFile->inNormalWrite = 0; #endif - + if( pFile->eFileLock==EXCLUSIVE_LOCK ){ rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0); if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){ @@ -32773,11 +37933,11 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { } if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){ rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0); - } + } if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){ rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0); - if( !rc ){ - context->reserved = 0; + if( !rc ){ + context->reserved = 0; } } if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){ @@ -32807,33 +37967,39 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) { if( rc==SQLITE_OK ){ pInode->nLock--; assert( pInode->nLock>=0 ); - if( pInode->nLock==0 ){ - closePendingFds(pFile); - } + if( pInode->nLock==0 ) closePendingFds(pFile); } } - - unixLeaveMutex(); - if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock; + + sqlite3_mutex_leave(pInode->pLockMutex); + if( rc==SQLITE_OK ){ + pFile->eFileLock = eFileLock; + } return rc; } /* -** Close a file & cleanup AFP specific locking context +** Close a file & cleanup AFP specific locking context */ static int afpClose(sqlite3_file *id) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; assert( id!=0 ); afpUnlock(id, NO_LOCK); + assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); - if( pFile->pInode && pFile->pInode->nLock ){ - /* If there are outstanding locks, do not actually close the file just - ** yet because that would clear those locks. Instead, add the file - ** descriptor to pInode->aPending. It will be automatically closed when - ** the last lock is cleared. - */ - setPendingFd(pFile); + if( pFile->pInode ){ + unixInodeInfo *pInode = pFile->pInode; + sqlite3_mutex_enter(pInode->pLockMutex); + if( pInode->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pInode->aPending. It will be automatically closed when + ** the last lock is cleared. + */ + setPendingFd(pFile); + } + sqlite3_mutex_leave(pInode->pLockMutex); } releaseInodeInfo(pFile); sqlite3_free(pFile->lockingContext); @@ -32871,7 +38037,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){ /* ** The code above is the NFS lock implementation. The code is specific ** to MacOSX and does not work on other unix platforms. No alternative -** is available. +** is available. ** ********************* End of the NFS lock implementation ********************** ******************************************************************************/ @@ -32879,7 +38045,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){ /****************************************************************************** **************** Non-locking sqlite3_file methods ***************************** ** -** The next division contains implementations for all methods of the +** The next division contains implementations for all methods of the ** sqlite3_file object other than the locking methods. The locking ** methods were defined in divisions above (one locking method per ** division). Those methods that are common to all locking modes @@ -32887,7 +38053,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){ */ /* -** Seek to the offset passed as the second argument, then read cnt +** Seek to the offset passed as the second argument, then read cnt ** bytes into pBuf. Return the number of bytes actually read. ** ** NB: If you define USE_PREAD or USE_PREAD64, then it might also @@ -32949,8 +38115,8 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){ ** wrong. */ static int unixRead( - sqlite3_file *id, - void *pBuf, + sqlite3_file *id, + void *pBuf, int amt, sqlite3_int64 offset ){ @@ -32960,12 +38126,12 @@ static int unixRead( assert( offset>=0 ); assert( amt>0 ); - /* If this is a database file (not a journal, master-journal or temp + /* If this is a database file (not a journal, super-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 - assert( pFile->pUnused==0 + assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 - || offset+amt<=PENDING_BYTE + || offset+amt<=PENDING_BYTE ); #endif @@ -32990,7 +38156,24 @@ static int unixRead( if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ - /* lastErrno set by seekAndRead */ + /* pFile->lastErrno has been set by seekAndRead(). + ** Usually we return SQLITE_IOERR_READ here, though for some + ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The + ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT + ** prior to returning to the application by the sqlite3ApiExit() + ** routine. + */ + switch( pFile->lastErrno ){ + case ERANGE: + case EIO: +#ifdef ENXIO + case ENXIO: +#endif +#ifdef EDEVERR + case EDEVERR: +#endif + return SQLITE_IOERR_CORRUPTFS; + } return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 0); /* not a system error */ @@ -33003,7 +38186,7 @@ static int unixRead( /* ** Attempt to seek the file-descriptor passed as the first argument to ** absolute offset iOff, then attempt to write nBuf bytes of data from -** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise, +** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise, ** return the actual number of bytes written (which may be less than ** nBuf). */ @@ -33063,22 +38246,22 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){ ** or some other error code on failure. */ static int unixWrite( - sqlite3_file *id, - const void *pBuf, + sqlite3_file *id, + const void *pBuf, int amt, - sqlite3_int64 offset + sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); - /* If this is a database file (not a journal, master-journal or temp + /* If this is a database file (not a journal, super-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 - assert( pFile->pUnused==0 + assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 - || offset+amt<=PENDING_BYTE + || offset+amt<=PENDING_BYTE ); #endif @@ -33120,7 +38303,7 @@ static int unixWrite( } } #endif - + while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))0 ){ amt -= wrote; offset += wrote; @@ -33186,8 +38369,8 @@ SQLITE_API int sqlite3_fullsync_count = 0; ** ** SQLite sets the dataOnly flag if the size of the file is unchanged. ** The idea behind dataOnly is that it should only write the file content -** to disk, not the inode. We only set dataOnly if the file size is -** unchanged since the file size is part of the inode. However, +** to disk, not the inode. We only set dataOnly if the file size is +** unchanged since the file size is part of the inode. However, ** Ted Ts'o tells us that fdatasync() will also write the inode if the ** file size has changed. The only real difference between fdatasync() ** and fsync(), Ted tells us, is that fdatasync() will not flush the @@ -33201,7 +38384,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ int rc; /* The following "ifdef/elif/else/" block has the same structure as - ** the one below. It is replicated here solely to avoid cluttering + ** the one below. It is replicated here solely to avoid cluttering ** up the real code with the UNUSED_PARAMETER() macros. */ #ifdef SQLITE_NO_SYNC @@ -33215,7 +38398,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ UNUSED_PARAMETER(dataOnly); #endif - /* Record the number of times that we do a normal fsync() and + /* Record the number of times that we do a normal fsync() and ** FULLSYNC. This is used during testing to verify that this procedure ** gets called with the correct arguments. */ @@ -33241,11 +38424,11 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ rc = 1; } /* If the FULLFSYNC failed, fall back to attempting an fsync(). - ** It shouldn't be possible for fullfsync to fail on the local + ** It shouldn't be possible for fullfsync to fail on the local ** file system (on OSX), so failure indicates that FULLFSYNC - ** isn't supported for this file system. So, attempt an fsync - ** and (for now) ignore the overhead of a superfluous fcntl call. - ** It'd be better to detect fullfsync support once and avoid + ** isn't supported for this file system. So, attempt an fsync + ** and (for now) ignore the overhead of a superfluous fcntl call. + ** It'd be better to detect fullfsync support once and avoid ** the fcntl call every time sync is called. */ if( rc ) rc = fsync(fd); @@ -33255,7 +38438,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){ ** so currently we default to the macro that redefines fdatasync to fsync */ rc = fsync(fd); -#else +#else rc = fdatasync(fd); #if OS_VXWORKS if( rc==-1 && errno==ENOTSUP ){ @@ -33416,7 +38599,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ #if SQLITE_MAX_MMAP_SIZE>0 /* If the file was just truncated to a size smaller than the currently ** mapped region, reduce the effective mapping size as well. SQLite will - ** use read() and write() to access data beyond this point from now on. + ** use read() and write() to access data beyond this point from now on. */ if( nBytemmapSize ){ pFile->mmapSize = nByte; @@ -33462,8 +38645,8 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){ static int proxyFileControl(sqlite3_file*,int,void*); #endif -/* -** This function is called to handle the SQLITE_FCNTL_SIZE_HINT +/* +** This function is called to handle the SQLITE_FCNTL_SIZE_HINT ** file-control operation. Enlarge the database to nBytes in size ** (rounded up to the next chunk-size). If the database is already ** nBytes or larger, this routine is a no-op. @@ -33472,7 +38655,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ if( pFile->szChunk>0 ){ i64 nSize; /* Required file size */ struct stat buf; /* Used to hold return values of fstat() */ - + if( osFstat(pFile->h, &buf) ){ return SQLITE_IOERR_FSTAT; } @@ -33481,16 +38664,16 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ if( nSize>(i64)buf.st_size ){ #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE - /* The code below is handling the return value of osFallocate() - ** correctly. posix_fallocate() is defined to "returns zero on success, + /* The code below is handling the return value of osFallocate() + ** correctly. posix_fallocate() is defined to "returns zero on success, ** or an error number on failure". See the manpage for details. */ int err; do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); - if( err ) return SQLITE_IOERR_WRITE; + if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; #else - /* If the OS does not have posix_fallocate(), fake it. Write a + /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely ** within the extended region. Then, if required, a single byte ** at offset (nSize-1), to set the size of the file correctly. @@ -33549,6 +38732,9 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ /* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); +#ifndef SQLITE_OMIT_WAL + static int unixFcntlExternalReader(unixFile*, int*); +#endif /* ** Information and control of an open file handle. @@ -33556,6 +38742,21 @@ static int unixGetTempname(int nBuf, char *zBuf); static int unixFileControl(sqlite3_file *id, int op, void *pArg){ unixFile *pFile = (unixFile*)id; switch( op ){ +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); + return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); + return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; + } + case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { + int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); + return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; + } +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + case SQLITE_FCNTL_LOCKSTATE: { *(int*)pArg = pFile->eFileLock; return SQLITE_OK; @@ -33599,6 +38800,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ *(int*)pArg = fileHasMoved(pFile); return SQLITE_OK; } +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + case SQLITE_FCNTL_LOCK_TIMEOUT: { + int iOld = pFile->iBusyTimeout; + pFile->iBusyTimeout = *(int*)pArg; + *(int*)pArg = iOld; + return SQLITE_OK; + } +#endif #if SQLITE_MAX_MMAP_SIZE>0 case SQLITE_FCNTL_MMAP_SIZE: { i64 newLimit = *(i64*)pArg; @@ -33606,6 +38815,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } + + /* The value of newLimit may be eventually cast to (size_t) and passed + ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a + ** 64-bit type. */ + if( newLimit>0 && sizeof(size_t)<8 ){ + newLimit = (newLimit & 0x7FFFFFFF); + } + *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; @@ -33634,43 +38851,63 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ return proxyFileControl(id,op,pArg); } #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ + + case SQLITE_FCNTL_EXTERNAL_READER: { +#ifndef SQLITE_OMIT_WAL + return unixFcntlExternalReader((unixFile*)id, (int*)pArg); +#else + *(int*)pArg = 0; + return SQLITE_OK; +#endif + } } return SQLITE_NOTFOUND; } /* -** Return the sector size in bytes of the underlying block device for -** the specified file. This is almost always 512 bytes, but may be -** larger for some devices. +** If pFd->sectorSize is non-zero when this function is called, it is a +** no-op. Otherwise, the values of pFd->sectorSize and +** pFd->deviceCharacteristics are set according to the file-system +** characteristics. ** -** SQLite code assumes this function cannot fail. It also assumes that -** if two files are created in the same file-system directory (i.e. -** a database and its journal file) that the sector size will be the -** same for both. +** There are two versions of this function. One for QNX and one for all +** other systems. */ -#ifndef __QNXNTO__ -static int unixSectorSize(sqlite3_file *NotUsed){ - UNUSED_PARAMETER(NotUsed); - return SQLITE_DEFAULT_SECTOR_SIZE; -} -#endif +#ifndef __QNXNTO__ +static void setDeviceCharacteristics(unixFile *pFd){ + assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 ); + if( pFd->sectorSize==0 ){ +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + int res; + u32 f = 0; -/* -** The following version of unixSectorSize() is optimized for QNX. -*/ -#ifdef __QNXNTO__ + /* Check for support for F2FS atomic batch writes. */ + res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f); + if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){ + pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC; + } +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + + /* Set the POWERSAFE_OVERWRITE flag if requested. */ + if( pFd->ctrlFlags & UNIXFILE_PSOW ){ + pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; + } + + pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; + } +} +#else #include #include -static int unixSectorSize(sqlite3_file *id){ - unixFile *pFile = (unixFile*)id; +static void setDeviceCharacteristics(unixFile *pFile){ if( pFile->sectorSize == 0 ){ struct statvfs fsInfo; - + /* Set defaults for non-supported filesystems */ pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; pFile->deviceCharacteristics = 0; if( fstatvfs(pFile->h, &fsInfo) == -1 ) { - return pFile->sectorSize; + return; } if( !strcmp(fsInfo.f_basetype, "tmp") ) { @@ -33731,9 +38968,24 @@ static int unixSectorSize(sqlite3_file *id){ pFile->deviceCharacteristics = 0; pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE; } - return pFile->sectorSize; } -#endif /* __QNXNTO__ */ +#endif + +/* +** Return the sector size in bytes of the underlying block device for +** the specified file. This is almost always 512 bytes, but may be +** larger for some devices. +** +** SQLite code assumes this function cannot fail. It also assumes that +** if two files are created in the same file-system directory (i.e. +** a database and its journal file) that the sector size will be the +** same for both. +*/ +static int unixSectorSize(sqlite3_file *id){ + unixFile *pFd = (unixFile*)id; + setDeviceCharacteristics(pFd); + return pFd->sectorSize; +} /* ** Return the device characteristics for the file. @@ -33749,16 +39001,9 @@ static int unixSectorSize(sqlite3_file *id){ ** available to turn it off and URI query parameter available to turn it off. */ static int unixDeviceCharacteristics(sqlite3_file *id){ - unixFile *p = (unixFile*)id; - int rc = 0; -#ifdef __QNXNTO__ - if( p->sectorSize==0 ) unixSectorSize(id); - rc = p->deviceCharacteristics; -#endif - if( p->ctrlFlags & UNIXFILE_PSOW ){ - rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE; - } - return rc; + unixFile *pFd = (unixFile*)id; + setDeviceCharacteristics(pFd); + return pFd->deviceCharacteristics; } #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 @@ -33766,7 +39011,7 @@ static int unixDeviceCharacteristics(sqlite3_file *id){ /* ** Return the system page size. ** -** This function should not be called directly by other code in this file. +** This function should not be called directly by other code in this file. ** Instead, it should be called via macro osGetpagesize(). */ static int unixGetpagesize(void){ @@ -33784,7 +39029,7 @@ static int unixGetpagesize(void){ #ifndef SQLITE_OMIT_WAL /* -** Object used to represent an shared memory buffer. +** Object used to represent an shared memory buffer. ** ** When multiple threads all reference the same wal-index, each thread ** has its own unixShm object, but they all point to a single instance @@ -33804,25 +39049,27 @@ static int unixGetpagesize(void){ ** nRef ** ** The following fields are read-only after the object is created: -** -** fid +** +** hShm ** zFilename ** -** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and +** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and ** unixMutexHeld() is true when reading or writing any other field ** in this structure. */ struct unixShmNode { unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ - sqlite3_mutex *mutex; /* Mutex to access this object */ + sqlite3_mutex *pShmMutex; /* Mutex to access this object */ char *zFilename; /* Name of the mmapped file */ - int h; /* Open file descriptor */ + int hShm; /* Open file descriptor */ int szRegion; /* Size of shared-memory regions */ u16 nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ + u8 isUnlocked; /* True if no DMS lock held */ char **apRegion; /* Array of mapped shared-memory regions */ int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ + int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ #ifdef SQLITE_DEBUG u8 exclMask; /* Mask of exclusive locks held */ u8 sharedMask; /* Mask of shared locks held */ @@ -33837,16 +39084,16 @@ struct unixShmNode { ** The following fields are initialized when this object is created and ** are read-only thereafter: ** -** unixShm.pFile +** unixShm.pShmNode ** unixShm.id ** -** All other fields are read/write. The unixShm.pFile->mutex must be held -** while accessing any read/write fields. +** All other fields are read/write. The unixShm.pShmNode->pShmMutex must +** be held while accessing any read/write fields. */ struct unixShm { unixShmNode *pShmNode; /* The underlying unixShmNode object */ unixShm *pNext; /* Next unixShm with the same unixShmNode */ - u8 hasMutex; /* True if holding the unixShmNode mutex */ + u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */ u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ @@ -33858,6 +39105,40 @@ struct unixShm { #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ +/* +** Use F_GETLK to check whether or not there are any readers with open +** wal-mode transactions in other processes on database file pFile. If +** no error occurs, return SQLITE_OK and set (*piOut) to 1 if there are +** such transactions, or 0 otherwise. If an error occurs, return an +** SQLite error code. The final value of *piOut is undefined in this +** case. +*/ +static int unixFcntlExternalReader(unixFile *pFile, int *piOut){ + int rc = SQLITE_OK; + *piOut = 0; + if( pFile->pShm){ + unixShmNode *pShmNode = pFile->pShm->pShmNode; + struct flock f; + + memset(&f, 0, sizeof(f)); + f.l_type = F_WRLCK; + f.l_whence = SEEK_SET; + f.l_start = UNIX_SHM_BASE + 3; + f.l_len = SQLITE_SHM_NLOCK - 3; + + sqlite3_mutex_enter(pShmNode->pShmMutex); + if( osFcntl(pShmNode->hShm, F_GETLK, &f)<0 ){ + rc = SQLITE_IOERR_LOCK; + }else{ + *piOut = (f.l_type!=F_UNLCK); + } + sqlite3_mutex_leave(pShmNode->pShmMutex); + } + + return rc; +} + + /* ** Apply posix advisory locks for all bytes from ofst through ofst+n-1. ** @@ -33876,7 +39157,8 @@ static int unixShmSystemLock( /* Access to the unixShmNode object is serialized by the caller */ pShmNode = pFile->pInode->pShmNode; - assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 ); + assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); + assert( pShmNode->nRef>0 || unixMutexHeld() ); /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); @@ -33884,16 +39166,21 @@ static int unixShmSystemLock( /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ + int res; /* Initialize the locking parameters */ - memset(&f, 0, sizeof(f)); f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; - - rc = osFcntl(pShmNode->h, F_SETLK, &f); - rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; + res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); + if( res==-1 ){ +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY); +#else + rc = SQLITE_BUSY; +#endif + } } /* Update the global lock state and do debug tracing */ @@ -33931,7 +39218,7 @@ static int unixShmSystemLock( } #endif - return rc; + return rc; } /* @@ -33964,18 +39251,18 @@ static void unixShmPurge(unixFile *pFd){ int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); - sqlite3_mutex_free(p->mutex); + sqlite3_mutex_free(p->pShmMutex); for(i=0; inRegion; i+=nShmPerMap){ - if( p->h>=0 ){ + if( p->hShm>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); } } sqlite3_free(p->apRegion); - if( p->h>=0 ){ - robust_close(pFd, p->h, __LINE__); - p->h = -1; + if( p->hShm>=0 ){ + robust_close(pFd, p->hShm, __LINE__); + p->hShm = -1; } p->pInode->pShmNode = 0; sqlite3_free(p); @@ -33983,20 +39270,83 @@ static void unixShmPurge(unixFile *pFd){ } /* -** Open a shared-memory area associated with open database file pDbFd. +** The DMS lock has not yet been taken on shm file pShmNode. Attempt to +** take it now. Return SQLITE_OK if successful, or an SQLite error +** code otherwise. +** +** If the DMS cannot be locked because this is a readonly_shm=1 +** connection and no other process already holds a lock, return +** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1. +*/ +static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ + struct flock lock; + int rc = SQLITE_OK; + + /* Use F_GETLK to determine the locks other processes are holding + ** on the DMS byte. If it indicates that another process is holding + ** a SHARED lock, then this process may also take a SHARED lock + ** and proceed with opening the *-shm file. + ** + ** Or, if no other process is holding any lock, then this process + ** is the first to open it. In this case take an EXCLUSIVE lock on the + ** DMS byte and truncate the *-shm file to zero bytes in size. Then + ** downgrade to a SHARED lock on the DMS byte. + ** + ** If another process is holding an EXCLUSIVE lock on the DMS byte, + ** return SQLITE_BUSY to the caller (it will try again). An earlier + ** version of this code attempted the SHARED lock at this point. But + ** this introduced a subtle race condition: if the process holding + ** EXCLUSIVE failed just before truncating the *-shm file, then this + ** process might open and use the *-shm file without truncating it. + ** And if the *-shm file has been corrupted by a power failure or + ** system crash, the database itself may also become corrupt. */ + lock.l_whence = SEEK_SET; + lock.l_start = UNIX_SHM_DMS; + lock.l_len = 1; + lock.l_type = F_WRLCK; + if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) { + rc = SQLITE_IOERR_LOCK; + }else if( lock.l_type==F_UNLCK ){ + if( pShmNode->isReadonly ){ + pShmNode->isUnlocked = 1; + rc = SQLITE_READONLY_CANTINIT; + }else{ + rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); + /* The first connection to attach must truncate the -shm file. We + ** truncate to 3 bytes (an arbitrary small number, less than the + ** -shm header size) rather than 0 as a system debugging aid, to + ** help detect if a -shm file truncation is legitimate or is the work + ** or a rogue process. */ + if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){ + rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename); + } + } + }else if( lock.l_type==F_WRLCK ){ + rc = SQLITE_BUSY; + } + + if( rc==SQLITE_OK ){ + assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK ); + rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); + } + return rc; +} + +/* +** Open a shared-memory area associated with open database file pDbFd. ** This particular implementation uses mmapped files. ** ** The file used to implement shared-memory is in the same directory ** as the open database file and has the same name as the open database ** file with the "-shm" suffix added. For example, if the database file ** is "/home/user1/config.db" then the file that is created and mmapped -** for shared memory will be called "/home/user1/config.db-shm". +** for shared memory will be called "/home/user1/config.db-shm". ** ** Another approach to is to use files in /dev/shm or /dev/tmp or an ** some other tmpfs mount. But if a file in a different directory ** from the database file is used, then differing access permissions ** or a chroot() might cause two different processes on the same -** database to end up using different files for shared memory - +** database to end up using different files for shared memory - ** meaning that their memory would not really be shared - resulting ** in database corruption. Nevertheless, this tmpfs file usage ** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm" @@ -34020,9 +39370,9 @@ static void unixShmPurge(unixFile *pFd){ static int unixOpenSharedMemory(unixFile *pDbFd){ struct unixShm *p = 0; /* The connection to be opened */ struct unixShmNode *pShmNode; /* The underlying mmapped file */ - int rc; /* Result code */ + int rc = SQLITE_OK; /* Result code */ unixInodeInfo *pInode; /* The inode of fd */ - char *zShmFilename; /* Name of the file used for SHM */ + char *zShm; /* Name of the file used for SHM */ int nShmFilename; /* Size of the SHM filename in bytes */ /* Allocate space for the new unixShm object. */ @@ -34034,6 +39384,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ /* Check to see if a unixShmNode object already exists. Reuse an existing ** one if present. Create a new one if necessary. */ + assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); pInode = pDbFd->pInode; pShmNode = pInode->pShmNode; @@ -34063,57 +39414,49 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ goto shm_open_err; } memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename); - zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1]; + zShm = pShmNode->zFilename = (char*)&pShmNode[1]; #ifdef SQLITE_SHM_DIRECTORY - sqlite3_snprintf(nShmFilename, zShmFilename, + sqlite3_snprintf(nShmFilename, zShm, SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", (u32)sStat.st_ino, (u32)sStat.st_dev); #else - sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath); - sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); + sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath); + sqlite3FileSuffix3(pDbFd->zPath, zShm); #endif - pShmNode->h = -1; + pShmNode->hShm = -1; pDbFd->pInode->pShmNode = pShmNode; pShmNode->pInode = pDbFd->pInode; if( sqlite3GlobalConfig.bCoreMutex ){ - pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ + pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->pShmMutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } } if( pInode->bProcessLock==0 ){ - int openFlags = O_RDWR | O_CREAT; - if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ - openFlags = O_RDONLY; - pShmNode->isReadonly = 1; + if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ + pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW, + (sStat.st_mode&0777)); } - pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777)); - if( pShmNode->h<0 ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename); - goto shm_open_err; + if( pShmNode->hShm<0 ){ + pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW, + (sStat.st_mode&0777)); + if( pShmNode->hShm<0 ){ + rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm); + goto shm_open_err; + } + pShmNode->isReadonly = 1; } /* If this process is running as root, make sure that the SHM file ** is owned by the same user that owns the original database. Otherwise, ** the original owner will not be able to connect. */ - robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); - - /* Check to see if another process is holding the dead-man switch. - ** If not, truncate the file to zero length. - */ - rc = SQLITE_OK; - if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ - if( robust_ftruncate(pShmNode->h, 0) ){ - rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename); - } - } - if( rc==SQLITE_OK ){ - rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); - } - if( rc ) goto shm_open_err; + robustFchown(pShmNode->hShm, sStat.st_uid, sStat.st_gid); + + rc = unixLockSharedMemory(pDbFd, pShmNode); + if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; } } @@ -34130,14 +39473,14 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** the cover of the unixEnterMutex() mutex and the pointer from the ** new (struct unixShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex - ** mutex. + ** at pShmNode->pFirst. This must be done while holding the + ** pShmNode->pShmMutex. */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; - sqlite3_mutex_leave(pShmNode->mutex); - return SQLITE_OK; + sqlite3_mutex_leave(pShmNode->pShmMutex); + return rc; /* Jump here on any error */ shm_open_err: @@ -34148,22 +39491,22 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ } /* -** This function is called to obtain a pointer to region iRegion of the -** shared-memory associated with the database file fd. Shared-memory regions -** are numbered starting from zero. Each shared-memory region is szRegion +** This function is called to obtain a pointer to region iRegion of the +** shared-memory associated with the database file fd. Shared-memory regions +** are numbered starting from zero. Each shared-memory region is szRegion ** bytes in size. ** ** If an error occurs, an error code is returned and *pp is set to NULL. ** ** Otherwise, if the bExtend parameter is 0 and the requested shared-memory ** region has not been allocated (by any client, including one running in a -** separate process), then *pp is set to NULL and SQLITE_OK returned. If -** bExtend is non-zero and the requested shared-memory region has not yet +** separate process), then *pp is set to NULL and SQLITE_OK returned. If +** bExtend is non-zero and the requested shared-memory region has not yet ** been allocated, it is allocated by this function. ** ** If the shared-memory region has already been allocated or is allocated by -** this call as described above, then it is mapped into this processes -** address space (if it is not already), *pp is set to point to the mapped +** this call as described above, then it is mapped into this processes +** address space (if it is not already), *pp is set to point to the mapped ** memory and SQLITE_OK returned. */ static int unixShmMap( @@ -34188,11 +39531,16 @@ static int unixShmMap( p = pDbFd->pShm; pShmNode = p->pShmNode; - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); + if( pShmNode->isUnlocked ){ + rc = unixLockSharedMemory(pDbFd, pShmNode); + if( rc!=SQLITE_OK ) goto shmpage_out; + pShmNode->isUnlocked = 0; + } assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); assert( pShmNode->pInode==pDbFd->pInode ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); /* Minimum number of regions required to be mapped. */ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; @@ -34204,16 +39552,16 @@ static int unixShmMap( pShmNode->szRegion = szRegion; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ /* The requested region is not mapped into this processes address space. ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ - if( osFstat(pShmNode->h, &sStat) ){ + if( osFstat(pShmNode->hShm, &sStat) ){ rc = SQLITE_IOERR_SHMSIZE; goto shmpage_out; } - + if( sStat.st_sizeh, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){ + if( seekAndWriteFd(pShmNode->hShm, iPg*pgsz + pgsz-1,"",1,&x)!=1 ){ const char *zFile = pShmNode->zFilename; rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); goto shmpage_out; @@ -34260,22 +39608,22 @@ static int unixShmMap( int nMap = szRegion*nShmPerMap; int i; void *pMem; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ pMem = osMmap(0, nMap, - pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, - MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion + pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, + MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion ); if( pMem==MAP_FAILED ){ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); goto shmpage_out; } }else{ - pMem = sqlite3_malloc64(szRegion); + pMem = sqlite3_malloc64(nMap); if( pMem==0 ){ rc = SQLITE_NOMEM_BKPT; goto shmpage_out; } - memset(pMem, 0, szRegion); + memset(pMem, 0, nMap); } for(i=0; iisReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } +/* +** Check that the pShmNode->aLock[] array comports with the locking bitmasks +** held by each client. Return true if it does, or false otherwise. This +** is to be used in an assert(). e.g. +** +** assert( assertLockingArrayOk(pShmNode) ); +*/ +#ifdef SQLITE_DEBUG +static int assertLockingArrayOk(unixShmNode *pShmNode){ + unixShm *pX; + int aLock[SQLITE_SHM_NLOCK]; + assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); + + memset(aLock, 0, sizeof(aLock)); + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + int i; + for(i=0; iexclMask & (1<sharedMask & (1<=0 ); + aLock[i]++; + } + } + } + + assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) ); + return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0); +} +#endif + /* ** Change the lock state for a shared-memory segment. ** @@ -34311,11 +39691,17 @@ static int unixShmLock( int flags /* What to do with the lock */ ){ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ - unixShm *p = pDbFd->pShm; /* The shared memory being locked */ - unixShm *pX; /* For looping over all siblings */ - unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ + unixShm *p; /* The shared memory being locked */ + unixShmNode *pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ + int *aLock; + + p = pDbFd->pShm; + if( p==0 ) return SQLITE_IOERR_SHMLOCK; + pShmNode = p->pShmNode; + if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; + aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); @@ -34326,92 +39712,112 @@ static int unixShmLock( || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); + + /* Check that, if this to be a blocking lock, no locks that occur later + ** in the following list than the lock being obtained are already held: + ** + ** 1. Checkpointer lock (ofst==1). + ** 2. Write lock (ofst==0). + ** 3. Read locks (ofst>=3 && ofstiBusyTimeout==0 || ( + (ofst!=2) /* not RECOVER */ + && (ofst!=1 || (p->exclMask|p->sharedMask)==0) + && (ofst!=0 || (p->exclMask|p->sharedMask)<3) + && (ofst<3 || (p->exclMask|p->sharedMask)<(1<1 || mask==(1<mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); + assert( assertLockingArrayOk(pShmNode) ); if( flags & SQLITE_SHM_UNLOCK ){ - u16 allMask = 0; /* Mask of locks held by siblings */ - - /* See if any siblings hold this same lock */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( pX==p ) continue; - assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); - allMask |= pX->sharedMask; - } + if( (p->exclMask|p->sharedMask) & mask ){ + int ii; + int bUnlock = 1; - /* Unlock the system-level locks */ - if( (mask & allMask)==0 ){ - rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); - }else{ - rc = SQLITE_OK; - } + for(ii=ofst; ii((p->sharedMask & (1<exclMask &= ~mask; - p->sharedMask &= ~mask; - } - }else if( flags & SQLITE_SHM_SHARED ){ - u16 allShared = 0; /* Union of locks held by connections other than "p" */ + if( bUnlock ){ + rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); + if( rc==SQLITE_OK ){ + memset(&aLock[ofst], 0, sizeof(int)*n); + } + }else if( ALWAYS(p->sharedMask & (1<1 ); + aLock[ofst]--; + } - /* Find out which shared locks are already held by sibling connections. - ** If any sibling already holds an exclusive lock, go ahead and return - ** SQLITE_BUSY. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 ){ - rc = SQLITE_BUSY; - break; + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; } - allShared |= pX->sharedMask; } - - /* Get shared locks at the system level, if necessary */ - if( rc==SQLITE_OK ){ - if( (allShared & mask)==0 ){ + }else if( flags & SQLITE_SHM_SHARED ){ + assert( n==1 ); + assert( (p->exclMask & (1<sharedMask & mask)==0 ){ + if( aLock[ofst]<0 ){ + rc = SQLITE_BUSY; + }else if( aLock[ofst]==0 ){ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); - }else{ - rc = SQLITE_OK; } - } - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; + /* Get the local shared locks */ + if( rc==SQLITE_OK ){ + p->sharedMask |= mask; + aLock[ofst]++; + } } }else{ /* Make sure no sibling connections hold locks that will block this - ** lock. If any do, return SQLITE_BUSY right away. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ + ** lock. If any do, return SQLITE_BUSY right away. */ + int ii; + for(ii=ofst; iisharedMask & mask)==0 ); + if( ALWAYS((p->exclMask & (1<sharedMask & mask)==0 ); p->exclMask |= mask; + for(ii=ofst; iimutex); + assert( assertLockingArrayOk(pShmNode) ); + sqlite3_mutex_leave(pShmNode->pShmMutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; } /* -** Implement a memory barrier or memory fence on shared memory. +** Implement a memory barrier or memory fence on shared memory. ** ** All loads and stores begun before the barrier must complete before ** any load or store begun after the barrier. @@ -34421,12 +39827,15 @@ static void unixShmBarrier( ){ UNUSED_PARAMETER(fd); sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ + assert( fd->pMethods->xLock==nolockLock + || unixFileMutexNotheld((unixFile*)fd) + ); unixEnterMutex(); /* Also mutex, for redundancy */ unixLeaveMutex(); } /* -** Close a connection to shared-memory. Delete the underlying +** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. ** ** If there is no shared memory associated with the connection then this @@ -34451,22 +39860,23 @@ static int unixShmUnmap( /* Remove connection p from the set of connections associated ** with pShmNode */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} *pp = p->pNext; /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ + assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ - if( deleteFlag && pShmNode->h>=0 ){ + if( deleteFlag && pShmNode->hShm>=0 ){ osUnlink(pShmNode->zFilename); } unixShmPurge(pDbFd); @@ -34499,7 +39909,7 @@ static void unixUnmapfile(unixFile *pFd){ } /* -** Attempt to set the size of the memory mapping maintained by file +** Attempt to set the size of the memory mapping maintained by file ** descriptor pFd to nNew bytes. Any existing mapping is discarded. ** ** If successful, this function sets the following variables: @@ -34591,14 +40001,14 @@ static void unixRemapfile( /* ** Memory map or remap the file opened by file-descriptor pFd (if the file -** is already mapped, the existing mapping is replaced by the new). Or, if -** there already exists a mapping for this file, and there are still +** is already mapped, the existing mapping is replaced by the new). Or, if +** there already exists a mapping for this file, and there are still ** outstanding xFetch() references to it, this function is a no-op. ** -** If parameter nByte is non-negative, then it is the requested size of -** the mapping to create. Otherwise, if nByte is less than zero, then the +** If parameter nByte is non-negative, then it is the requested size of +** the mapping to create. Otherwise, if nByte is less than zero, then the ** requested size is the size of the file on disk. The actual size of the -** created mapping is either the requested size or the value configured +** created mapping is either the requested size or the value configured ** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller. ** ** SQLITE_OK is returned if no error occurs (even if the mapping is not @@ -34639,7 +40049,7 @@ static int unixMapfile(unixFile *pFd, i64 nMap){ ** Finally, if an error does occur, return an SQLite error code. The final ** value of *pp is undefined in this case. ** -** If this function does return a pointer, the caller must eventually +** If this function does return a pointer, the caller must eventually ** release the reference by calling unixUnfetch(). */ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ @@ -34664,13 +40074,13 @@ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ } /* -** If the third argument is non-NULL, then this function releases a +** If the third argument is non-NULL, then this function releases a ** reference obtained by an earlier call to unixFetch(). The second ** argument passed to this function must be the same as the corresponding -** argument that was passed to the unixFetch() invocation. +** argument that was passed to the unixFetch() invocation. ** -** Or, if the third argument is NULL, then this function is being called -** to inform the VFS layer that, according to POSIX, any existing mapping +** Or, if the third argument is NULL, then this function is being called +** to inform the VFS layer that, according to POSIX, any existing mapping ** may now be invalid and should be unmapped. */ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ @@ -34678,7 +40088,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){ unixFile *pFd = (unixFile *)fd; /* The underlying database file */ UNUSED_PARAMETER(iOff); - /* If p==0 (unmap the entire file) then there must be no outstanding + /* If p==0 (unmap the entire file) then there must be no outstanding ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference), ** then there must be at least one outstanding. */ assert( (p==0)==(pFd->nFetchOut==0) ); @@ -34788,7 +40198,7 @@ IOMETHODS( IOMETHODS( nolockIoFinder, /* Finder function name */ nolockIoMethods, /* sqlite3_io_methods object name */ - 3, /* shared memory is disabled */ + 3, /* shared memory and mmap are enabled */ nolockClose, /* xClose method */ nolockLock, /* xLock method */ nolockUnlock, /* xUnlock method */ @@ -34886,8 +40296,8 @@ IOMETHODS( #endif #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE -/* -** This "finder" function attempts to determine the best locking strategy +/* +** This "finder" function attempts to determine the best locking strategy ** for the database file "filePath". It then returns the sqlite3_io_methods ** object that implements that strategy. ** @@ -34929,8 +40339,8 @@ static const sqlite3_io_methods *autolockIoFinderImpl( } /* Default case. Handles, amongst others, "nfs". - ** Test byte-range lock using fcntl(). If the call succeeds, - ** assume that the file-system supports POSIX style locks. + ** Test byte-range lock using fcntl(). If the call succeeds, + ** assume that the file-system supports POSIX style locks. */ lockInfo.l_len = 1; lockInfo.l_start = 0; @@ -34946,7 +40356,7 @@ static const sqlite3_io_methods *autolockIoFinderImpl( return &dotlockIoMethods; } } -static const sqlite3_io_methods +static const sqlite3_io_methods *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ @@ -34982,7 +40392,7 @@ static const sqlite3_io_methods *vxworksIoFinderImpl( return &semIoMethods; } } -static const sqlite3_io_methods +static const sqlite3_io_methods *(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl; #endif /* OS_VXWORKS */ @@ -35016,17 +40426,6 @@ static int fillInUnixFile( assert( pNew->pInode==NULL ); - /* Usually the path zFilename should not be a relative pathname. The - ** exception is when opening the proxy "conch" file in builds that - ** include the special Apple locking styles. - */ -#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE - assert( zFilename==0 || zFilename[0]=='/' - || pVfs->pAppData==(void*)&autolockIoFinder ); -#else - assert( zFilename==0 || zFilename[0]=='/' ); -#endif - /* No locking occurs in temporary files */ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); @@ -35121,14 +40520,14 @@ static int fillInUnixFile( robust_close(pNew, h, __LINE__); h = -1; } - unixLeaveMutex(); + unixLeaveMutex(); } } #endif else if( pLockingStyle == &dotlockIoMethods ){ /* Dotfile locking uses the file path so it needs to be included in - ** the dotlockLockingContext + ** the dotlockLockingContext */ char *zLockFile; int nFilename; @@ -35166,7 +40565,7 @@ static int fillInUnixFile( unixLeaveMutex(); } #endif - + storeLastErrno(pNew, 0); #if OS_VXWORKS if( rc!=SQLITE_OK ){ @@ -35179,32 +40578,42 @@ static int fillInUnixFile( if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ - pNew->pMethod = pLockingStyle; + pId->pMethods = pLockingStyle; OpenCounter(+1); verifyDbFile(pNew); } return rc; } +/* +** Directories to consider for temp files. +*/ +static const char *azTempDirs[] = { + 0, + 0, + "/var/tmp", + "/usr/tmp", + "/tmp", + "." +}; + +/* +** Initialize first two members of azTempDirs[] array. +*/ +static void unixTempFileInit(void){ + azTempDirs[0] = getenv("SQLITE_TMPDIR"); + azTempDirs[1] = getenv("TMPDIR"); +} + /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. */ static const char *unixTempFileDir(void){ - static const char *azDirs[] = { - 0, - 0, - "/var/tmp", - "/usr/tmp", - "/tmp", - "." - }; unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; - if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); - if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); while(1){ if( zDir!=0 && osStat(zDir, &buf)==0 @@ -35213,8 +40622,8 @@ static const char *unixTempFileDir(void){ ){ return zDir; } - if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; - zDir = azDirs[i++]; + if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break; + zDir = azTempDirs[i++]; } return 0; } @@ -35230,7 +40639,7 @@ static int unixGetTempname(int nBuf, char *zBuf){ /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this - ** function failing. + ** function failing. */ zBuf[0] = 0; SimulateIOError( return SQLITE_IOERR ); @@ -35259,8 +40668,8 @@ static int proxyTransformUnixFile(unixFile*, const char*); #endif /* -** Search for an unused file descriptor that was opened on the database -** file (not a journal or master-journal file) identified by pathname +** Search for an unused file descriptor that was opened on the database +** file (not a journal or super-journal file) identified by pathname ** zPath with SQLITE_OPEN_XXX flags matching those passed as the second ** argument to this function. ** @@ -35268,7 +40677,7 @@ static int proxyTransformUnixFile(unixFile*, const char*); ** but the associated file descriptor could not be closed because some ** other file descriptor open on the same file is holding a file-lock. ** Refer to comments in the unixClose() function and the lengthy comment -** describing "Posix Advisory Locking" at the start of this file for +** describing "Posix Advisory Locking" at the start of this file for ** further details. Also, ticket #4018. ** ** If a suitable file descriptor is found, then it is returned. If no @@ -35279,12 +40688,14 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ /* Do not search for an unused file descriptor on vxworks. Not because ** vxworks would not benefit from the change (it might, we're not sure), - ** but because no way to test it is currently available. It is better - ** not to risk breaking vxworks support for the sake of such an obscure + ** but because no way to test it is currently available. It is better + ** not to risk breaking vxworks support for the sake of such an obscure ** feature. */ #if !OS_VXWORKS struct stat sStat; /* Results of stat() call */ + unixEnterMutex(); + /* A stat() call may fail for various reasons. If this happens, it is ** almost certain that an open() call on the same path will also fail. ** For this reason, if an error occurs in the stat() call here, it is @@ -35293,10 +40704,9 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a reusable file descriptor are not dire. */ - if( 0==osStat(zPath, &sStat) ){ + if( inodeList!=0 && 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; - unixEnterMutex(); pInode = inodeList; while( pInode && (pInode->fileId.dev!=sStat.st_dev || pInode->fileId.ino!=(u64)sStat.st_ino) ){ @@ -35304,20 +40714,24 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ } if( pInode ){ UnixUnusedFd **pp; + assert( sqlite3_mutex_notheld(pInode->pLockMutex) ); + sqlite3_mutex_enter(pInode->pLockMutex); + flags &= (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE); for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ *pp = pUnused->pNext; } + sqlite3_mutex_leave(pInode->pLockMutex); } - unixLeaveMutex(); } + unixLeaveMutex(); #endif /* if !OS_VXWORKS */ return pUnused; } /* -** Find the mode, uid and gid of file zFile. +** Find the mode, uid and gid of file zFile. */ static int getFileMode( const char *zFile, /* File name */ @@ -35341,22 +40755,22 @@ static int getFileMode( ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is -** written to *pMode. If an IO error occurs, an SQLite error code is +** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. ** ** In most cases, this routine sets *pMode to 0, which will become ** an indication to robust_open() to create the file using ** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask. -** But if the file being opened is a WAL or regular journal file, then -** this function queries the file-system for the permissions on the -** corresponding database file and sets *pMode to this value. Whenever -** possible, WAL and journal files are created using the same permissions +** But if the file being opened is a WAL or regular journal file, then +** this function queries the file-system for the permissions on the +** corresponding database file and sets *pMode to this value. Whenever +** possible, WAL and journal files are created using the same permissions ** as the associated database file. ** ** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the ** original filename is unavailable. But 8_3_NAMES is only used for ** FAT filesystems and permissions do not matter there, so just use -** the default permissions. +** the default permissions. In 8_3_NAMES mode, leave *pMode set to zero. */ static int findCreateFileMode( const char *zPath, /* Path of file (possibly) being created */ @@ -35382,21 +40796,16 @@ static int findCreateFileMode( ** "-journalNN" ** "-walNN" ** - ** where NN is a decimal number. The NN naming schemes are + ** where NN is a decimal number. The NN naming schemes are ** used by the test_multiplex.c module. */ - nDb = sqlite3Strlen30(zPath) - 1; + nDb = sqlite3Strlen30(zPath) - 1; while( zPath[nDb]!='-' ){ -#ifndef SQLITE_ENABLE_8_3_NAMES - /* In the normal case (8+3 filenames disabled) the journal filename - ** is guaranteed to contain a '-' character. */ - assert( nDb>0 ); - assert( sqlite3Isalnum(zPath[nDb]) ); -#else - /* If 8+3 names are possible, then the journal file might not contain - ** a '-' character. So check for that case and return early. */ + /* In normal operation, the journal file name will always contain + ** a '-' character. However in 8+3 filename mode, or if a corrupt + ** rollback journal specifies a super-journal with a goofy name, then + ** the '-' might be missing. */ if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; -#endif nDb--; } memcpy(zDb, zPath, nDb); @@ -35420,7 +40829,7 @@ static int findCreateFileMode( /* ** Open the file zPath. -** +** ** Previously, the SQLite OS layer used three functions in place of this ** one: ** @@ -35431,13 +40840,13 @@ static int findCreateFileMode( ** These calls correspond to the following combinations of flags: ** ** ReadWrite() -> (READWRITE | CREATE) -** ReadOnly() -> (READONLY) +** ReadOnly() -> (READONLY) ** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) ** ** The old OpenExclusive() accepted a boolean argument - "delFlag". If ** true, the file was configured to be automatically deleted when the -** file handle closed. To achieve the same effect using this new -** interface, add the DELETEONCLOSE flag to those specified above for +** file handle closed. To achieve the same effect using this new +** interface, add the DELETEONCLOSE flag to those specified above for ** OpenExclusive(). */ static int unixOpen( @@ -35450,7 +40859,7 @@ static int unixOpen( unixFile *p = (unixFile *)pFile; int fd = -1; /* File descriptor returned by open() */ int openFlags = 0; /* Flags to pass to open() */ - int eType = flags&0xFFFFFF00; /* Type of file to open */ + int eType = flags&0x0FFF00; /* Type of file to open */ int noLock; /* True to omit locking primitives */ int rc = SQLITE_OK; /* Function Return Code */ int ctrlFlags = 0; /* UNIXFILE_* flags */ @@ -35467,13 +40876,13 @@ static int unixOpen( struct statfs fsInfo; #endif - /* If creating a master or main-file journal, this function will open + /* If creating a super- or main-file journal, this function will open ** a file-descriptor on the directory too. The first time unixSync() ** is called the directory file descriptor will be fsync()ed and close()d. */ - int syncDir = (isCreate && ( - eType==SQLITE_OPEN_MASTER_JOURNAL - || eType==SQLITE_OPEN_MAIN_JOURNAL + int isNewJrnl = (isCreate && ( + eType==SQLITE_OPEN_SUPER_JOURNAL + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); @@ -35483,9 +40892,9 @@ static int unixOpen( char zTmpname[MAX_PATHNAME+2]; const char *zName = zPath; - /* Check the following statements are true: + /* Check the following statements are true: ** - ** (a) Exactly one of the READWRITE and READONLY flags must be set, and + ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and ** (c) if EXCLUSIVE is set, then CREATE must also be set. ** (d) if DELETEONCLOSE is set, then CREATE must also be set. @@ -35495,17 +40904,17 @@ static int unixOpen( assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); - /* The main DB, main journal, WAL file and master journal are never + /* The main DB, main journal, WAL file and super-journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); - assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ - assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB - || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL - || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB + || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); @@ -35518,9 +40927,13 @@ static int unixOpen( randomnessPid = osGetpid(0); sqlite3_randomness(0,0); } - memset(p, 0, sizeof(unixFile)); +#ifdef SQLITE_ASSERT_NO_FILES + /* Applications that never read or write a persistent disk files */ + assert( zName==0 ); +#endif + if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused; pUnused = findReusableFd(zName, flags); @@ -35532,7 +40945,7 @@ static int unixOpen( return SQLITE_NOMEM_BKPT; } } - p->pUnused = pUnused; + p->pPreallocatedUnused = pUnused; /* Database filenames are double-zero terminated if they are not ** URIs with parameters. Hence, they can always be passed into @@ -35541,7 +40954,7 @@ static int unixOpen( }else if( !zName ){ /* If zName is NULL, the upper layer is requesting a temp file. */ - assert(isDelete && !syncDir); + assert(isDelete && !isNewJrnl); rc = unixGetTempname(pVfs->mxPathname, zTmpname); if( rc!=SQLITE_OK ){ return rc; @@ -35555,13 +40968,13 @@ static int unixOpen( /* Determine the value of the flags parameter passed to POSIX function ** open(). These must be calculated even if open() is not called, as - ** they may be stored as part of the file handle and used by the + ** they may be stored as part of the file handle and used by the ** 'conch file' locking functions later on. */ if( isReadonly ) openFlags |= O_RDONLY; if( isReadWrite ) openFlags |= O_RDWR; if( isCreate ) openFlags |= O_CREAT; if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW); - openFlags |= (O_LARGEFILE|O_BINARY); + openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW); if( fd<0 ){ mode_t openMode; /* Permissions to create file with */ @@ -35569,32 +40982,47 @@ static int unixOpen( gid_t gid; /* Groupid for the file */ rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid); if( rc!=SQLITE_OK ){ - assert( !p->pUnused ); + assert( !p->pPreallocatedUnused ); assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); return rc; } fd = robust_open(zName, openFlags, openMode); OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags)); assert( !isExclusive || (openFlags & O_CREAT)!=0 ); - if( fd<0 && errno!=EISDIR && isReadWrite ){ - /* Failed to open the file for read/write access. Try read-only. */ - flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); - openFlags &= ~(O_RDWR|O_CREAT); - flags |= SQLITE_OPEN_READONLY; - openFlags |= O_RDONLY; - isReadonly = 1; - fd = robust_open(zName, openFlags, openMode); + if( fd<0 ){ + if( isNewJrnl && errno==EACCES && osAccess(zName, F_OK) ){ + /* If unable to create a journal because the directory is not + ** writable, change the error code to indicate that. */ + rc = SQLITE_READONLY_DIRECTORY; + }else if( errno!=EISDIR && isReadWrite ){ + /* Failed to open the file for read/write access. Try read-only. */ + flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); + openFlags &= ~(O_RDWR|O_CREAT); + flags |= SQLITE_OPEN_READONLY; + openFlags |= O_RDONLY; + isReadonly = 1; + fd = robust_open(zName, openFlags, openMode); + } } if( fd<0 ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); + int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); + if( rc==SQLITE_OK ) rc = rc2; goto open_finished; } - /* If this process is running as root and if creating a new rollback - ** journal or WAL file, set the ownership of the journal or WAL to be - ** the same as the original database. + /* The owner of the rollback journal or WAL file should always be the + ** same as the owner of the database file. Try to ensure that this is + ** the case. The chown() system call will be a no-op if the current + ** process lacks root privileges, be we should at least try. Without + ** this step, if a root process opens a database file, it can leave + ** behinds a journal/WAL that is owned by root and hence make the + ** database inaccessible to unprivileged processes. + ** + ** If openMode==0, then that means uid and gid are not set correctly + ** (probably because SQLite is configured to use 8+3 filename mode) and + ** in that case we do not want to attempt the chown(). */ - if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ + if( openMode && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){ robustFchown(fd, uid, gid); } } @@ -35603,9 +41031,10 @@ static int unixOpen( *pOutFlags = flags; } - if( p->pUnused ){ - p->pUnused->fd = fd; - p->pUnused->flags = flags; + if( p->pPreallocatedUnused ){ + p->pPreallocatedUnused->fd = fd; + p->pPreallocatedUnused->flags = + flags & (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE); } if( isDelete ){ @@ -35626,7 +41055,7 @@ static int unixOpen( p->openFlags = openFlags; } #endif - + #if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE if( fstatfs(fd, &fsInfo) == -1 ){ storeLastErrno(p, errno); @@ -35646,7 +41075,7 @@ static int unixOpen( if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY; noLock = eType!=SQLITE_OPEN_MAIN_DB; if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK; - if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC; + if( isNewJrnl ) ctrlFlags |= UNIXFILE_DIRSYNC; if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI; #if SQLITE_ENABLE_LOCKING_STYLE @@ -35657,7 +41086,7 @@ static int unixOpen( char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING"); int useProxy = 0; - /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means + /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means ** never use proxy, NULL means use proxy for non-local files only. */ if( envforce!=NULL ){ useProxy = atoi(envforce)>0; @@ -35669,9 +41098,9 @@ static int unixOpen( if( rc==SQLITE_OK ){ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); if( rc!=SQLITE_OK ){ - /* Use unixClose to clean up the resources added in fillInUnixFile - ** and clear all the structure's references. Specifically, - ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op + /* Use unixClose to clean up the resources added in fillInUnixFile + ** and clear all the structure's references. Specifically, + ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op */ unixClose(pFile); return rc; @@ -35681,12 +41110,15 @@ static int unixOpen( } } #endif - + + assert( zPath==0 || zPath[0]=='/' + || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL + ); rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); open_finished: if( rc!=SQLITE_OK ){ - sqlite3_free(p->pUnused); + sqlite3_free(p->pPreallocatedUnused); } return rc; } @@ -35760,7 +41192,8 @@ static int unixAccess( if( flags==SQLITE_ACCESS_EXISTS ){ struct stat buf; - *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0); + *pResOut = 0==osStat(zPath, &buf) && + (!S_ISREG(buf.st_mode) || buf.st_size>0); }else{ *pResOut = osAccess(zPath, W_OK|R_OK)==0; } @@ -35768,7 +41201,27 @@ static int unixAccess( } /* +** If the last component of the pathname in z[0]..z[j-1] is something +** other than ".." then back it out and return true. If the last +** component is empty or if it is ".." then return false. +*/ +static int unixBackupDir(const char *z, int *pJ){ + int j = *pJ; + int i; + if( j<=0 ) return 0; + for(i=j-1; i>0 && z[i-1]!='/'; i--){} + if( i==0 ) return 0; + if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; + *pJ = i-1; + return 1; +} + +/* +** Convert a relative pathname into a full pathname. Also +** simplify the pathname as follows: ** +** Remove all instances of /./ +** Remove all isntances of /X/../ for any X */ static int mkFullPathname( const char *zPath, /* Input path */ @@ -35777,6 +41230,7 @@ static int mkFullPathname( ){ int nPath = sqlite3Strlen30(zPath); int iOff = 0; + int i, j; if( zPath[0]!='/' ){ if( osGetcwd(zOut, nOut-2)==0 ){ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); @@ -35791,15 +41245,50 @@ static int mkFullPathname( return SQLITE_CANTOPEN_BKPT; } sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + + /* Remove duplicate '/' characters. Except, two // at the beginning + ** of a pathname is allowed since this is important on windows. */ + for(i=j=1; zOut[i]; i++){ + zOut[j++] = zOut[i]; + while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; + } + zOut[j] = 0; + + assert( zOut[0]=='/' ); + for(i=j=0; zOut[i]; i++){ + if( zOut[i]=='/' ){ + /* Skip over internal "/." directory components */ + if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ + i += 1; + continue; + } + + /* If this is a "/.." directory component then back out the + ** previous term of the directory if it is something other than "..". + */ + if( zOut[i+1]=='.' + && zOut[i+2]=='.' + && zOut[i+3]=='/' + && unixBackupDir(zOut, &j) + ){ + i += 2; + continue; + } + } + if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; + j++; + } + if( NEVER(j==0) ) zOut[j++] = '/'; + zOut[j] = 0; return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. The relative path ** is stored as a nul-terminated string in the buffer pointed to by -** zPath. +** zPath. ** -** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes +** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes ** (in this case, MAX_PATHNAME bytes). The full-path is written to ** this buffer before returning. */ @@ -35814,7 +41303,7 @@ static int unixFullPathname( #else int rc = SQLITE_OK; int nByte; - int nLink = 1; /* Number of symbolic links followed so far */ + int nLink = 0; /* Number of symbolic links followed so far */ const char *zIn = zPath; /* Input path for each iteration of loop */ char *zDel = 0; @@ -35843,10 +41332,11 @@ static int unixFullPathname( } if( bLink ){ + nLink++; if( zDel==0 ){ zDel = sqlite3_malloc(nOut); if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; - }else if( ++nLink>SQLITE_MAX_SYMLINKS ){ + }else if( nLink>=SQLITE_MAX_SYMLINKS ){ rc = SQLITE_CANTOPEN_BKPT; } @@ -35882,6 +41372,7 @@ static int unixFullPathname( }while( rc==SQLITE_OK ); sqlite3_free(zDel); + if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; return rc; #endif /* HAVE_READLINK && HAVE_LSTAT */ } @@ -35916,7 +41407,7 @@ static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){ unixLeaveMutex(); } static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){ - /* + /* ** GCC with -pedantic-errors says that C90 does not allow a void* to be ** cast into a pointer to a function. And yet the library dlsym() routine ** returns a void* which is really a pointer to a function. So how do we @@ -35926,7 +41417,7 @@ static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){ ** parameters void* and const char* and returning a pointer to a function. ** We initialize x by assigning it a pointer to the dlsym() function. ** (That assignment requires a cast.) Then we call the function that - ** x points to. + ** x points to. ** ** This work-around is unlikely to work correctly on any system where ** you really cannot cast a function pointer into void*. But then, on the @@ -35969,7 +41460,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){ ** tests repeatable. */ memset(zBuf, 0, nBuf); - randomnessPid = osGetpid(0); + randomnessPid = osGetpid(0); #if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) { int fd, got; @@ -36009,7 +41500,8 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ UNUSED_PARAMETER(NotUsed); return microseconds; #elif defined(HAVE_USLEEP) && HAVE_USLEEP - usleep(microseconds); + if( microseconds>=1000000 ) sleep(microseconds/1000000); + if( microseconds%1000000 ) usleep(microseconds%1000000); UNUSED_PARAMETER(NotUsed); return microseconds; #else @@ -36036,7 +41528,7 @@ SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1 ** epoch of noon in Greenwich on November 24, 4714 B.C according to the ** proleptic Gregorian calendar. ** -** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date +** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date ** cannot be found. */ static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){ @@ -36143,7 +41635,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** To address the performance and cache coherency issues, proxy file locking ** changes the way database access is controlled by limiting access to a ** single host at a time and moving file locks off of the database file -** and onto a proxy file on the local file system. +** and onto a proxy file on the local file system. ** ** ** Using proxy locks @@ -36169,19 +41661,19 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** actual proxy file name is generated from the name and path of the ** database file. For example: ** -** For database path "/Users/me/foo.db" +** For database path "/Users/me/foo.db" ** The lock path will be "/sqliteplocks/_Users_me_foo.db:auto:") ** ** Once a lock proxy is configured for a database connection, it can not ** be removed, however it may be switched to a different proxy path via ** the above APIs (assuming the conch file is not being held by another -** connection or process). +** connection or process). ** ** ** How proxy locking works ** ----------------------- ** -** Proxy file locking relies primarily on two new supporting files: +** Proxy file locking relies primarily on two new supporting files: ** ** * conch file to limit access to the database file to a single host ** at a time @@ -36208,11 +41700,11 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** host (the conch ensures that they all use the same local lock file). ** ** Requesting the lock proxy does not immediately take the conch, it is -** only taken when the first request to lock database file is made. +** only taken when the first request to lock database file is made. ** This matches the semantics of the traditional locking behavior, where ** opening a connection to a database file does not take a lock on it. -** The shared lock and an open file descriptor are maintained until -** the connection to the database is closed. +** The shared lock and an open file descriptor are maintained until +** the connection to the database is closed. ** ** The proxy file and the lock file are never deleted so they only need ** to be created the first time they are used. @@ -36226,7 +41718,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** automatically configured for proxy locking, lock files are ** named automatically using the same logic as ** PRAGMA lock_proxy_file=":auto:" -** +** ** SQLITE_PROXY_DEBUG ** ** Enables the logging of error messages during host id file @@ -36241,8 +41733,8 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ ** ** Permissions to use when creating a directory for storing the ** lock proxy files, only used when LOCKPROXYDIR is not set. -** -** +** +** ** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING, ** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will ** force proxy locking to be used for every database file opened, and 0 @@ -36252,12 +41744,12 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){ */ /* -** Proxy locking is only available on MacOSX +** Proxy locking is only available on MacOSX */ #if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE /* -** The proxyLockingContext has the path and file structures for the remote +** The proxyLockingContext has the path and file structures for the remote ** and local proxy files in it */ typedef struct proxyLockingContext proxyLockingContext; @@ -36273,10 +41765,10 @@ struct proxyLockingContext { sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */ }; -/* -** The proxy lock file path for the database at dbPath is written into lPath, +/* +** The proxy lock file path for the database at dbPath is written into lPath, ** which must point to valid, writable memory large enough for a maxLen length -** file path. +** file path. */ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ int len; @@ -36293,7 +41785,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ lPath, errno, osGetpid(0))); return SQLITE_IOERR_LOCK; } - len = strlcat(lPath, "sqliteplocks", maxLen); + len = strlcat(lPath, "sqliteplocks", maxLen); } # else len = strlcpy(lPath, "/tmp/", maxLen); @@ -36303,7 +41795,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ if( lPath[len-1]!='/' ){ len = strlcat(lPath, "/", maxLen); } - + /* transform the db path to a unique cache name */ dbLen = (int)strlen(dbPath); for( i=0; i 0) ){ /* only mkdir if leaf dir != "." or "/" or ".." */ - if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/') + if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/') || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){ buf[i]='\0'; if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){ @@ -36367,7 +41859,7 @@ static int proxyCreateUnixFile( int fd = -1; unixFile *pNew; int rc = SQLITE_OK; - int openFlags = O_RDWR | O_CREAT; + int openFlags = O_RDWR | O_CREAT | O_NOFOLLOW; sqlite3_vfs dummyVfs; int terrno = 0; UnixUnusedFd *pUnused = NULL; @@ -36397,7 +41889,7 @@ static int proxyCreateUnixFile( } } if( fd<0 ){ - openFlags = O_RDONLY; + openFlags = O_RDONLY | O_NOFOLLOW; fd = robust_open(path, openFlags, 0); terrno = errno; } @@ -36408,13 +41900,13 @@ static int proxyCreateUnixFile( switch (terrno) { case EACCES: return SQLITE_PERM; - case EIO: + case EIO: return SQLITE_IOERR_LOCK; /* even though it is the conch */ default: return SQLITE_CANTOPEN_BKPT; } } - + pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew)); if( pNew==NULL ){ rc = SQLITE_NOMEM_BKPT; @@ -36427,14 +41919,14 @@ static int proxyCreateUnixFile( dummyVfs.zName = "dummy"; pUnused->fd = fd; pUnused->flags = openFlags; - pNew->pUnused = pUnused; - + pNew->pPreallocatedUnused = pUnused; + rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0); if( rc==SQLITE_OK ){ *ppFile = pNew; return SQLITE_OK; } -end_create_proxy: +end_create_proxy: robust_close(pNew, fd, __LINE__); sqlite3_free(pNew); sqlite3_free(pUnused); @@ -36448,18 +41940,18 @@ SQLITE_API int sqlite3_hostid_num = 0; #define PROXY_HOSTIDLEN 16 /* conch file host id length */ -#ifdef HAVE_GETHOSTUUID +#if HAVE_GETHOSTUUID /* Not always defined in the headers as it ought to be */ extern int gethostuuid(uuid_t id, const struct timespec *wait); #endif -/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN +/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN ** bytes of writable memory. */ static int proxyGetHostID(unsigned char *pHostID, int *pError){ assert(PROXY_HOSTIDLEN == sizeof(uuid_t)); memset(pHostID, 0, PROXY_HOSTIDLEN); -#ifdef HAVE_GETHOSTUUID +#if HAVE_GETHOSTUUID { struct timespec timeout = {1, 0}; /* 1 sec timeout */ if( gethostuuid(pHostID, &timeout) ){ @@ -36479,7 +41971,7 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF)); } #endif - + return SQLITE_OK; } @@ -36490,14 +41982,14 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){ #define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN) #define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN) -/* -** Takes an open conch file, copies the contents to a new path and then moves +/* +** Takes an open conch file, copies the contents to a new path and then moves ** it back. The newly created file's file descriptor is assigned to the -** conch file structure and finally the original conch file descriptor is +** conch file structure and finally the original conch file descriptor is ** closed. Returns zero if successful. */ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *conchFile = pCtx->conchFile; char tPath[MAXPATHLEN]; char buf[PROXY_MAXCONCHLEN]; @@ -36511,7 +42003,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ /* create a new path by replace the trailing '-conch' with '-break' */ pathLen = strlcpy(tPath, cPath, MAXPATHLEN); - if( pathLen>MAXPATHLEN || pathLen<6 || + if( pathLen>MAXPATHLEN || pathLen<6 || (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){ sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen); goto end_breaklock; @@ -36523,7 +42015,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ goto end_breaklock; } /* write it out to the temporary break file */ - fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0); + fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW), 0); if( fd<0 ){ sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno); goto end_breaklock; @@ -36553,24 +42045,24 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){ return rc; } -/* Take the requested lock on the conch file and break a stale lock if the +/* Take the requested lock on the conch file and break a stale lock if the ** host id matches. */ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; unixFile *conchFile = pCtx->conchFile; int rc = SQLITE_OK; int nTries = 0; struct timespec conchModTime; - + memset(&conchModTime, 0, sizeof(conchModTime)); do { rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType); nTries ++; if( rc==SQLITE_BUSY ){ /* If the lock failed (busy): - * 1st try: get the mod time of the conch, wait 0.5s and try again. - * 2nd try: fail if the mod time changed or host id is different, wait + * 1st try: get the mod time of the conch, wait 0.5s and try again. + * 2nd try: fail if the mod time changed or host id is different, wait * 10 sec and try again * 3rd try: break the lock unless the mod time has changed. */ @@ -36579,20 +42071,20 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } - + if( nTries==1 ){ conchModTime = buf.st_mtimespec; - usleep(500000); /* wait 0.5 sec and try the lock again*/ - continue; + unixSleep(0,500000); /* wait 0.5 sec and try the lock again*/ + continue; } assert( nTries>1 ); - if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || + if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){ return SQLITE_BUSY; } - - if( nTries==2 ){ + + if( nTries==2 ){ char tBuf[PROXY_MAXCONCHLEN]; int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); if( len<0 ){ @@ -36608,10 +42100,10 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ /* don't break the lock on short read or a version mismatch */ return SQLITE_BUSY; } - usleep(10000000); /* wait 10 sec and try the lock again */ - continue; + unixSleep(0,10000000); /* wait 10 sec and try the lock again */ + continue; } - + assert( nTries==3 ); if( 0==proxyBreakConchLock(pFile, myHostID) ){ rc = SQLITE_OK; @@ -36624,19 +42116,19 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ } } } while( rc==SQLITE_BUSY && nTries<3 ); - + return rc; } -/* Takes the conch by taking a shared lock and read the contents conch, if -** lockPath is non-NULL, the host ID and lock file path must match. A NULL -** lockPath means that the lockPath in the conch file will be used if the -** host IDs match, or a new lock path will be generated automatically +/* Takes the conch by taking a shared lock and read the contents conch, if +** lockPath is non-NULL, the host ID and lock file path must match. A NULL +** lockPath means that the lockPath in the conch file will be used if the +** host IDs match, or a new lock path will be generated automatically ** and written to the conch file. */ static int proxyTakeConch(unixFile *pFile){ - proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; - + proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; + if( pCtx->conchHeld!=0 ){ return SQLITE_OK; }else{ @@ -36652,7 +42144,7 @@ static int proxyTakeConch(unixFile *pFile){ int readLen = 0; int tryOldLockPath = 0; int forceNewLockPath = 0; - + OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h, (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), osGetpid(0))); @@ -36673,21 +42165,21 @@ static int proxyTakeConch(unixFile *pFile){ storeLastErrno(pFile, conchFile->lastErrno); rc = SQLITE_IOERR_READ; goto end_takeconch; - }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || + }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || readBuf[0]!=(char)PROXY_CONCHVERSION ){ - /* a short read or version format mismatch means we need to create a new - ** conch file. + /* a short read or version format mismatch means we need to create a new + ** conch file. */ createConch = 1; } /* if the host id matches and the lock path already exists in the conch - ** we'll try to use the path there, if we can't open that path, we'll - ** retry with a new auto-generated path + ** we'll try to use the path there, if we can't open that path, we'll + ** retry with a new auto-generated path */ do { /* in case we need to try again for an :auto: named lock file */ if( !createConch && !forceNewLockPath ){ - hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID, + hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); /* if the conch has data compare the contents */ if( !pCtx->lockProxyPath ){ @@ -36696,7 +42188,7 @@ static int proxyTakeConch(unixFile *pFile){ */ if( hostIdMatch ){ size_t pathLen = (readLen - PROXY_PATHINDEX); - + if( pathLen>=MAXPATHLEN ){ pathLen=MAXPATHLEN-1; } @@ -36712,23 +42204,23 @@ static int proxyTakeConch(unixFile *pFile){ readLen-PROXY_PATHINDEX) ){ /* conch host and lock path match */ - goto end_takeconch; + goto end_takeconch; } } - + /* if the conch isn't writable and doesn't match, we can't take it */ if( (conchFile->openFlags&O_RDWR) == 0 ){ rc = SQLITE_BUSY; goto end_takeconch; } - + /* either the conch didn't match or we need to create a new one */ if( !pCtx->lockProxyPath ){ proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN); tempLockPath = lockPath; /* create a copy of the lock path _only_ if the conch is taken */ } - + /* update conch with host and path (this will fail if other process ** has a shared lock already), if the host id matches, use the big ** stick. @@ -36739,7 +42231,7 @@ static int proxyTakeConch(unixFile *pFile){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ rc = SQLITE_BUSY; - } else { + } else { rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK); } }else{ @@ -36748,7 +42240,7 @@ static int proxyTakeConch(unixFile *pFile){ if( rc==SQLITE_OK ){ char writeBuffer[PROXY_MAXCONCHLEN]; int writeSize = 0; - + writeBuffer[0] = (char)PROXY_CONCHVERSION; memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN); if( pCtx->lockProxyPath!=NULL ){ @@ -36761,8 +42253,8 @@ static int proxyTakeConch(unixFile *pFile){ robust_ftruncate(conchFile->h, writeSize); rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0); full_fsync(conchFile->h,0,0); - /* If we created a new conch file (not just updated the contents of a - ** valid conch file), try to match the permissions of the database + /* If we created a new conch file (not just updated the contents of a + ** valid conch file), try to match the permissions of the database */ if( rc==SQLITE_OK && createConch ){ struct stat buf; @@ -36786,14 +42278,14 @@ static int proxyTakeConch(unixFile *pFile){ } }else{ int code = errno; - fprintf(stderr, "STAT FAILED[%d] with %d %s\n", + fprintf(stderr, "STAT FAILED[%d] with %d %s\n", err, code, strerror(code)); #endif } } } conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK); - + end_takeconch: OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h)); if( rc==SQLITE_OK && pFile->openFlags ){ @@ -36816,7 +42308,7 @@ static int proxyTakeConch(unixFile *pFile){ rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1); if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){ /* we couldn't create the proxy lock file with the old lock file path - ** so try again via auto-naming + ** so try again via auto-naming */ forceNewLockPath = 1; tryOldLockPath = 0; @@ -36836,7 +42328,7 @@ static int proxyTakeConch(unixFile *pFile){ } if( rc==SQLITE_OK ){ pCtx->conchHeld = 1; - + if( pCtx->lockProxy->pMethod == &afpIoMethods ){ afpLockingContext *afpCtx; afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext; @@ -36848,7 +42340,7 @@ static int proxyTakeConch(unixFile *pFile){ OSTRACE(("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed")); return rc; - } while (1); /* in case we need to retry the :auto: lock file - + } while (1); /* in case we need to retry the :auto: lock file - ** we should never get here except via the 'continue' call. */ } } @@ -36864,7 +42356,7 @@ static int proxyReleaseConch(unixFile *pFile){ pCtx = (proxyLockingContext *)pFile->lockingContext; conchFile = pCtx->conchFile; OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h, - (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), + (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), osGetpid(0))); if( pCtx->conchHeld>0 ){ rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK); @@ -36892,13 +42384,13 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ char *conchPath; /* buffer in which to construct conch name */ /* Allocate space for the conch filename and initialize the name to - ** the name of the original database file. */ + ** the name of the original database file. */ *pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8); if( conchPath==0 ){ return SQLITE_NOMEM_BKPT; } memcpy(conchPath, dbPath, len+1); - + /* now insert a "." before the last / character */ for( i=(len-1); i>=0; i-- ){ if( conchPath[i]=='/' ){ @@ -36921,7 +42413,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){ /* Takes a fully configured proxy locking-style unix file and switches -** the local lock file path +** the local lock file path */ static int switchLockProxyPath(unixFile *pFile, const char *path) { proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; @@ -36930,7 +42422,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) { if( pFile->eFileLock!=NO_LOCK ){ return SQLITE_BUSY; - } + } /* nothing to do if the path is NULL, :auto: or matches the existing path */ if( !path || path[0]=='\0' || !strcmp(path, ":auto:") || @@ -36948,7 +42440,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) { sqlite3_free(oldPath); pCtx->lockProxyPath = sqlite3DbStrDup(0, path); } - + return rc; } @@ -36962,7 +42454,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) { static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ #if defined(__APPLE__) if( pFile->pMethod == &afpIoMethods ){ - /* afp style keeps a reference to the db path in the filePath field + /* afp style keeps a reference to the db path in the filePath field ** of the struct */ assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN ); strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, @@ -36983,9 +42475,9 @@ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){ } /* -** Takes an already filled in unix file and alters it so all file locking +** Takes an already filled in unix file and alters it so all file locking ** will be performed on the local proxy lock file. The following fields -** are preserved in the locking context so that they can be restored and +** are preserved in the locking context so that they can be restored and ** the unix structure properly cleaned up at close time: ** ->lockingContext ** ->pMethod @@ -36995,7 +42487,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { char dbPath[MAXPATHLEN+1]; /* Name of the database file */ char *lockPath=NULL; int rc = SQLITE_OK; - + if( pFile->eFileLock!=NO_LOCK ){ return SQLITE_BUSY; } @@ -37005,7 +42497,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { }else{ lockPath=(char *)path; } - + OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h, (lockPath ? lockPath : ":auto:"), osGetpid(0))); @@ -37039,7 +42531,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { rc = SQLITE_OK; } } - } + } if( rc==SQLITE_OK && lockPath ){ pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath); } @@ -37051,7 +42543,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { } } if( rc==SQLITE_OK ){ - /* all memory is allocated, proxys are created and assigned, + /* all memory is allocated, proxys are created and assigned, ** switch the locking context and pMethod then return. */ pCtx->oldLockingContext = pFile->lockingContext; @@ -37059,12 +42551,12 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) { pCtx->pOldMethod = pFile->pMethod; pFile->pMethod = &proxyIoMethods; }else{ - if( pCtx->conchFile ){ + if( pCtx->conchFile ){ pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile); sqlite3_free(pCtx->conchFile); } sqlite3DbFree(0, pCtx->lockProxyPath); - sqlite3_free(pCtx->conchFilePath); + sqlite3_free(pCtx->conchFilePath); sqlite3_free(pCtx); } OSTRACE(("TRANSPROXY %d %s\n", pFile->h, @@ -37102,7 +42594,7 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ if( isProxyStyle ){ /* turn off proxy locking - not supported. If support is added for ** switching proxy locking mode off then it will need to fail if - ** the journal mode is WAL mode. + ** the journal mode is WAL mode. */ rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/; }else{ @@ -37112,9 +42604,9 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ }else{ const char *proxyPath = (const char *)pArg; if( isProxyStyle ){ - proxyLockingContext *pCtx = + proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext; - if( !strcmp(pArg, ":auto:") + if( !strcmp(pArg, ":auto:") || (pCtx->lockProxyPath && !strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN)) ){ @@ -37133,7 +42625,7 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){ assert( 0 ); /* The call assures that only valid opcodes are sent */ } } - /*NOTREACHED*/ + /*NOTREACHED*/ assert(0); return SQLITE_ERROR; } @@ -37239,7 +42731,7 @@ static int proxyClose(sqlite3_file *id) { unixFile *lockProxy = pCtx->lockProxy; unixFile *conchFile = pCtx->conchFile; int rc = SQLITE_OK; - + if( lockProxy ){ rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK); if( rc ) return rc; @@ -37276,7 +42768,7 @@ static int proxyClose(sqlite3_file *id) { ** The proxy locking style is intended for use with AFP filesystems. ** And since AFP is only supported on MacOSX, the proxy locking is also ** restricted to MacOSX. -** +** ** ******************* End of the proxy lock implementation ********************** ******************************************************************************/ @@ -37294,8 +42786,8 @@ static int proxyClose(sqlite3_file *id) { ** necessarily been initialized when this routine is called, and so they ** should not be used. */ -SQLITE_API int sqlite3_os_init(void){ - /* +SQLITE_API int sqlite3_os_init(void){ + /* ** The following macro defines an initializer for an sqlite3_vfs object. ** The name of the VFS is NAME. The pAppData is a pointer to a pointer ** to the "finder" function. (pAppData is a pointer to a pointer because @@ -37311,7 +42803,7 @@ SQLITE_API int sqlite3_os_init(void){ ** ** Most finders simply return a pointer to a fixed sqlite3_io_methods ** object. But the "autolockIoFinder" available on MacOSX does a little - ** more than that; it looks at the filesystem type that hosts the + ** more than that; it looks at the filesystem type that hosts the ** database file and tries to choose an locking method appropriate for ** that filesystem time. */ @@ -37377,13 +42869,36 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==28 ); + assert( ArraySize(aSyscall)==29 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } - return SQLITE_OK; + unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); + +#ifndef SQLITE_OMIT_WAL + /* Validate lock assumptions */ + assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */ + assert( UNIX_SHM_BASE==120 ); /* Start of locking area */ + /* Locks: + ** WRITE UNIX_SHM_BASE 120 + ** CKPT UNIX_SHM_BASE+1 121 + ** RECOVER UNIX_SHM_BASE+2 122 + ** READ-0 UNIX_SHM_BASE+3 123 + ** READ-1 UNIX_SHM_BASE+4 124 + ** READ-2 UNIX_SHM_BASE+5 125 + ** READ-3 UNIX_SHM_BASE+6 126 + ** READ-4 UNIX_SHM_BASE+7 127 + ** DMS UNIX_SHM_BASE+8 128 + */ + assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */ +#endif + + /* Initialize temp file dir array. */ + unixTempFileInit(); + + return SQLITE_OK; } /* @@ -37393,10 +42908,11 @@ SQLITE_API int sqlite3_os_init(void){ ** to release dynamically allocated objects. But not on unix. ** This routine is a no-op for unix. */ -SQLITE_API int sqlite3_os_end(void){ - return SQLITE_OK; +SQLITE_API int sqlite3_os_end(void){ + unixBigLock = 0; + return SQLITE_OK; } - + #endif /* SQLITE_OS_UNIX */ /************** End of os_unix.c *********************************************/ @@ -37421,205 +42937,7 @@ SQLITE_API int sqlite3_os_end(void){ /* ** Include code that is common to all os_*.c files */ -/************** Include os_common.h in the middle of os_win.c ****************/ -/************** Begin file os_common.h ***************************************/ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains macros and a little bit of code that is common to -** all of the platform-specific files (os_*.c) and is #included into those -** files. -** -** This file should be #included by the os_*.c files only. It is not a -** general purpose header file. -*/ -#ifndef _OS_COMMON_H_ -#define _OS_COMMON_H_ - -/* -** At least two bugs have slipped in because we changed the MEMORY_DEBUG -** macro to SQLITE_DEBUG and some older makefiles have not yet made the -** switch. The following code should catch this problem at compile-time. -*/ -#ifdef MEMORY_DEBUG -# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead." -#endif - -/* -** Macros for performance tracing. Normally turned off. Only works -** on i486 hardware. -*/ -#ifdef SQLITE_PERFORMANCE_TRACE - -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -/************** Include hwtime.h in the middle of os_common.h ****************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 class CPUs. -*/ -#ifndef SQLITE_HWTIME_H -#define SQLITE_HWTIME_H - -/* -** The following routine only works on pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. -*/ -#if (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long val; - __asm__ __volatile__ ("rdtsc" : "=A" (val)); - return val; - } - -#elif (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - #error Need implementation of sqlite3Hwtime() for your platform. - - /* - ** To compile without implementing sqlite3Hwtime() for your platform, - ** you can remove the above #error and use the following - ** stub function. You will lose timing support for many - ** of the debugging and testing utilities, but it should at - ** least compile and run. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in os_common.h ******************/ - -static sqlite_uint64 g_start; -static sqlite_uint64 g_elapsed; -#define TIMER_START g_start=sqlite3Hwtime() -#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start -#define TIMER_ELAPSED g_elapsed -#else -#define TIMER_START -#define TIMER_END -#define TIMER_ELAPSED ((sqlite_uint64)0) -#endif - -/* -** If we compile with the SQLITE_TEST macro set, then the following block -** of code will give us the ability to simulate a disk I/O error. This -** is used for testing the I/O recovery logic. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_io_error_hit; -SQLITE_API extern int sqlite3_io_error_hardhit; -SQLITE_API extern int sqlite3_io_error_pending; -SQLITE_API extern int sqlite3_io_error_persist; -SQLITE_API extern int sqlite3_io_error_benign; -SQLITE_API extern int sqlite3_diskfull_pending; -SQLITE_API extern int sqlite3_diskfull; -#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X) -#define SimulateIOError(CODE) \ - if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \ - || sqlite3_io_error_pending-- == 1 ) \ - { local_ioerr(); CODE; } -static void local_ioerr(){ - IOTRACE(("IOERR\n")); - sqlite3_io_error_hit++; - if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++; -} -#define SimulateDiskfullError(CODE) \ - if( sqlite3_diskfull_pending ){ \ - if( sqlite3_diskfull_pending == 1 ){ \ - local_ioerr(); \ - sqlite3_diskfull = 1; \ - sqlite3_io_error_hit = 1; \ - CODE; \ - }else{ \ - sqlite3_diskfull_pending--; \ - } \ - } -#else -#define SimulateIOErrorBenign(X) -#define SimulateIOError(A) -#define SimulateDiskfullError(A) -#endif /* defined(SQLITE_TEST) */ - -/* -** When testing, keep a count of the number of open files. -*/ -#if defined(SQLITE_TEST) -SQLITE_API extern int sqlite3_open_file_count; -#define OpenCounter(X) sqlite3_open_file_count+=(X) -#else -#define OpenCounter(X) -#endif /* defined(SQLITE_TEST) */ - -#endif /* !defined(_OS_COMMON_H_) */ - -/************** End of os_common.h *******************************************/ -/************** Continuing where we left off in os_win.c *********************/ +/* #include "os_common.h" */ /* ** Include the header file for the Windows VFS. @@ -37885,8 +43203,7 @@ struct winFile { int nFetchOut; /* Number of outstanding xFetch references */ HANDLE hMap; /* Handle for accessing memory mapping */ void *pMapRegion; /* Area memory mapped */ - sqlite3_int64 mmapSize; /* Usable size of mapped region */ - sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ + sqlite3_int64 mmapSize; /* Size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; @@ -37916,22 +43233,6 @@ struct winVfsAppData { # define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD))) #endif -/* - * The value used with sqlite3_win32_set_directory() to specify that - * the data directory should be changed. - */ -#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE -# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1) -#endif - -/* - * The value used with sqlite3_win32_set_directory() to specify that - * the temporary directory should be changed. - */ -#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE -# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2) -#endif - /* * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * various Win32 API heap functions instead of our own. @@ -37953,7 +43254,34 @@ struct winVfsAppData { ****************************************************************************** */ #ifndef SQLITE_WIN32_HEAP_CREATE -# define SQLITE_WIN32_HEAP_CREATE (TRUE) +# define SQLITE_WIN32_HEAP_CREATE (TRUE) +#endif + +/* + * This is the maximum possible initial size of the Win32-specific heap, in + * bytes. + */ +#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE +# define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U) +#endif + +/* + * This is the extra space for the initial size of the Win32-specific heap, + * in bytes. This value may be zero. + */ +#ifndef SQLITE_WIN32_HEAP_INIT_EXTRA +# define SQLITE_WIN32_HEAP_INIT_EXTRA (4194304) +#endif + +/* + * Calculate the maximum legal cache size, in pages, based on the maximum + * possible initial heap size and the default page size, setting aside the + * needed extra space. + */ +#ifndef SQLITE_WIN32_MAX_CACHE_SIZE +# define SQLITE_WIN32_MAX_CACHE_SIZE (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \ + (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \ + (SQLITE_DEFAULT_PAGE_SIZE)) #endif /* @@ -37962,25 +43290,36 @@ struct winVfsAppData { */ #ifndef SQLITE_WIN32_CACHE_SIZE # if SQLITE_DEFAULT_CACHE_SIZE>=0 -# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE) +# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE) # else -# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE)) +# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE)) # endif #endif +/* + * Make sure that the calculated cache size, in pages, cannot cause the + * initial size of the Win32-specific heap to exceed the maximum amount + * of memory that can be specified in the call to HeapCreate. + */ +#if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE +# undef SQLITE_WIN32_CACHE_SIZE +# define SQLITE_WIN32_CACHE_SIZE (2000) +#endif + /* * The initial size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_INIT_SIZE -# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \ - (SQLITE_DEFAULT_PAGE_SIZE) + 4194304) +# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \ + (SQLITE_DEFAULT_PAGE_SIZE) + \ + (SQLITE_WIN32_HEAP_INIT_EXTRA)) #endif /* * The maximum size of the Win32-specific heap. This value may be zero. */ #ifndef SQLITE_WIN32_HEAP_MAX_SIZE -# define SQLITE_WIN32_HEAP_MAX_SIZE (0) +# define SQLITE_WIN32_HEAP_MAX_SIZE (0) #endif /* @@ -37988,7 +43327,7 @@ struct winVfsAppData { * zero for the default behavior. */ #ifndef SQLITE_WIN32_HEAP_FLAGS -# define SQLITE_WIN32_HEAP_FLAGS (0) +# define SQLITE_WIN32_HEAP_FLAGS (0) #endif @@ -38870,17 +44209,17 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){ */ SQLITE_API int sqlite3_win32_reset_heap(){ int rc; - MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ + MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */ - MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) + MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); ) - sqlite3_mutex_enter(pMaster); + sqlite3_mutex_enter(pMainMtx); sqlite3_mutex_enter(pMem); winMemAssertMagic(); if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){ /* ** At this point, there should be no outstanding memory allocations on - ** the heap. Also, since both the master and memsys locks are currently + ** the heap. Also, since both the main and memsys locks are currently ** being held by us, no other function (i.e. from another thread) should ** be able to even access the heap. Attempt to destroy and recreate our ** isolated Win32 native heap now. @@ -38903,7 +44242,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){ rc = SQLITE_BUSY; } sqlite3_mutex_leave(pMem); - sqlite3_mutex_leave(pMaster); + sqlite3_mutex_leave(pMainMtx); return rc; } #endif /* SQLITE_WIN32_MALLOC */ @@ -39490,13 +44829,13 @@ SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){ } /* -** This function sets the data directory or the temporary directory based on -** the provided arguments. The type argument must be 1 in order to set the -** data directory or 2 in order to set the temporary directory. The zValue -** argument is the name of the directory to use. The return value will be -** SQLITE_OK if successful. +** This function is the same as sqlite3_win32_set_directory (below); however, +** it accepts a UTF-8 string. */ -SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ +SQLITE_API int sqlite3_win32_set_directory8( + unsigned long type, /* Identifier for directory being set or reset */ + const char *zValue /* New value for directory being set or reset */ +){ char **ppDirectory = 0; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); @@ -39512,20 +44851,53 @@ SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){ ); assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) ); if( ppDirectory ){ - char *zValueUtf8 = 0; + char *zCopy = 0; if( zValue && zValue[0] ){ - zValueUtf8 = winUnicodeToUtf8(zValue); - if ( zValueUtf8==0 ){ + zCopy = sqlite3_mprintf("%s", zValue); + if ( zCopy==0 ){ return SQLITE_NOMEM_BKPT; } } sqlite3_free(*ppDirectory); - *ppDirectory = zValueUtf8; + *ppDirectory = zCopy; return SQLITE_OK; } return SQLITE_ERROR; } +/* +** This function is the same as sqlite3_win32_set_directory (below); however, +** it accepts a UTF-16 string. +*/ +SQLITE_API int sqlite3_win32_set_directory16( + unsigned long type, /* Identifier for directory being set or reset */ + const void *zValue /* New value for directory being set or reset */ +){ + int rc; + char *zUtf8 = 0; + if( zValue ){ + zUtf8 = sqlite3_win32_unicode_to_utf8(zValue); + if( zUtf8==0 ) return SQLITE_NOMEM_BKPT; + } + rc = sqlite3_win32_set_directory8(type, zUtf8); + if( zUtf8 ) sqlite3_free(zUtf8); + return rc; +} + +/* +** This function sets the data directory or the temporary directory based on +** the provided arguments. The type argument must be 1 in order to set the +** data directory or 2 in order to set the temporary directory. The zValue +** argument is the name of the directory to use. The return value will be +** SQLITE_OK if successful. +*/ +SQLITE_API int sqlite3_win32_set_directory( + unsigned long type, /* Identifier for directory being set or reset */ + void *zValue /* New value for directory being set or reset */ +){ + return sqlite3_win32_set_directory16(type, zValue); +} + /* ** The return value of winGetLastErrorMsg ** is zero if the error message fits in the buffer, or non-zero @@ -40450,6 +45822,29 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ winFile *pFile = (winFile*)id; /* File handle object */ int rc = SQLITE_OK; /* Return code for this function */ DWORD lastErrno; +#if SQLITE_MAX_MMAP_SIZE>0 + sqlite3_int64 oldMmapSize; + if( pFile->nFetchOut>0 ){ + /* File truncation is a no-op if there are outstanding memory mapped + ** pages. This is because truncating the file means temporarily unmapping + ** the file, and that might delete memory out from under existing cursors. + ** + ** This can result in incremental vacuum not truncating the file, + ** if there is an active read cursor when the incremental vacuum occurs. + ** No real harm comes of this - the database file is not corrupted, + ** though some folks might complain that the file is bigger than it + ** needs to be. + ** + ** The only feasible work-around is to defer the truncation until after + ** all references to memory-mapped content are closed. That is doable, + ** but involves adding a few branches in the common write code path which + ** could slow down normal operations slightly. Hence, we have decided for + ** now to simply make trancations a no-op if there are pending reads. We + ** can maybe revisit this decision in the future. + */ + return SQLITE_OK; + } +#endif assert( pFile ); SimulateIOError(return SQLITE_IOERR_TRUNCATE); @@ -40465,6 +45860,15 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } +#if SQLITE_MAX_MMAP_SIZE>0 + if( pFile->pMapRegion ){ + oldMmapSize = pFile->mmapSize; + }else{ + oldMmapSize = 0; + } + winUnmapfile(pFile); +#endif + /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ if( winSeekFile(pFile, nByte) ){ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, @@ -40477,12 +45881,12 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ } #if SQLITE_MAX_MMAP_SIZE>0 - /* If the file was truncated to a size smaller than the currently - ** mapped region, reduce the effective mapping size as well. SQLite will - ** use read() and write() to access data beyond this point from now on. - */ - if( pFile->pMapRegion && nBytemmapSize ){ - pFile->mmapSize = nByte; + if( rc==SQLITE_OK && oldMmapSize>0 ){ + if( oldMmapSize>nByte ){ + winMapfile(pFile, -1); + }else{ + winMapfile(pFile, oldMmapSize); + } } #endif @@ -41017,6 +46421,7 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ /* Forward references to VFS helper methods used for temporary files */ static int winGetTempname(sqlite3_vfs *, char **); static int winIsDir(const void *); +static BOOL winIsLongPathPrefix(const char *); static BOOL winIsDriveLetterAndColon(const char *); /* @@ -41122,6 +46527,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ if( newLimit>sqlite3GlobalConfig.mxMmap ){ newLimit = sqlite3GlobalConfig.mxMmap; } + + /* The value of newLimit may be eventually cast to (SIZE_T) and passed + ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at + ** least a 64-bit type. */ + if( newLimit>0 && sizeof(SIZE_T)<8 ){ + newLimit = (newLimit & 0x7FFFFFFF); + } + *(i64*)pArg = pFile->mmapSizeMax; if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){ pFile->mmapSizeMax = newLimit; @@ -41186,15 +46599,16 @@ static SYSTEM_INFO winSysInfo; ** assert( winShmMutexHeld() ); ** winShmLeaveMutex() */ +static sqlite3_mutex *winBigLock = 0; static void winShmEnterMutex(void){ - sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); + sqlite3_mutex_enter(winBigLock); } static void winShmLeaveMutex(void){ - sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); + sqlite3_mutex_leave(winBigLock); } #ifndef NDEBUG static int winShmMutexHeld(void) { - return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1)); + return sqlite3_mutex_held(winBigLock); } #endif @@ -41228,6 +46642,9 @@ struct winShmNode { int szRegion; /* Size of shared-memory regions */ int nRegion; /* Size of array apRegion */ + u8 isReadonly; /* True if read-only */ + u8 isUnlocked; /* True if no DMS lock held */ + struct ShmRegion { HANDLE hMap; /* File handle from CreateFileMapping */ void *pMap; @@ -41294,7 +46711,7 @@ static int winShmSystemLock( int rc = 0; /* Result code form Lock/UnlockFileEx() */ /* Access to the winShmNode object is serialized by the caller */ - assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 ); + assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) ); OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", pFile->hFile.h, lockType, ofst, nByte)); @@ -41375,6 +46792,37 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ } } +/* +** The DMS lock has not yet been taken on shm file pShmNode. Attempt to +** take it now. Return SQLITE_OK if successful, or an SQLite error +** code otherwise. +** +** If the DMS cannot be locked because this is a readonly_shm=1 +** connection and no other process already holds a lock, return +** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1. +*/ +static int winLockSharedMemory(winShmNode *pShmNode){ + int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1); + + if( rc==SQLITE_OK ){ + if( pShmNode->isReadonly ){ + pShmNode->isUnlocked = 1; + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + return SQLITE_READONLY_CANTINIT; + }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){ + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), + "winLockSharedMemory", pShmNode->zFilename); + } + } + + if( rc==SQLITE_OK ){ + winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); + } + + return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); +} + /* ** Open the shared-memory area associated with database file pDbFd. ** @@ -41384,9 +46832,9 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){ */ static int winOpenSharedMemory(winFile *pDbFd){ struct winShm *p; /* The connection to be opened */ - struct winShmNode *pShmNode = 0; /* The underlying mmapped file */ - int rc; /* Result code */ - struct winShmNode *pNew; /* Newly allocated winShmNode */ + winShmNode *pShmNode = 0; /* The underlying mmapped file */ + int rc = SQLITE_OK; /* Result code */ + winShmNode *pNew; /* Newly allocated winShmNode */ int nName; /* Size of zName in bytes */ assert( pDbFd->pShm==0 ); /* Not previously opened */ @@ -41419,6 +46867,9 @@ static int winOpenSharedMemory(winFile *pDbFd){ if( pShmNode ){ sqlite3_free(pNew); }else{ + int inFlags = SQLITE_OPEN_WAL; + int outFlags = 0; + pShmNode = pNew; pNew = 0; ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE; @@ -41433,30 +46884,23 @@ static int winOpenSharedMemory(winFile *pDbFd){ } } - rc = winOpen(pDbFd->pVfs, - pShmNode->zFilename, /* Name of the file (UTF-8) */ - (sqlite3_file*)&pShmNode->hFile, /* File handle here */ - SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, - 0); - if( SQLITE_OK!=rc ){ + if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ + inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + }else{ + inFlags |= SQLITE_OPEN_READONLY; + } + rc = winOpen(pDbFd->pVfs, pShmNode->zFilename, + (sqlite3_file*)&pShmNode->hFile, + inFlags, &outFlags); + if( rc!=SQLITE_OK ){ + rc = winLogError(rc, osGetLastError(), "winOpenShm", + pShmNode->zFilename); goto shm_open_err; } + if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1; - /* Check to see if another process is holding the dead-man switch. - ** If not, truncate the file to zero length. - */ - if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ - rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); - if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), - "winOpenShm", pDbFd->zPath); - } - } - if( rc==SQLITE_OK ){ - winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); - rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); - } - if( rc ) goto shm_open_err; + rc = winLockSharedMemory(pShmNode); + if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; } /* Make the new connection a child of the winShmNode */ @@ -41479,7 +46923,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; sqlite3_mutex_leave(pShmNode->mutex); - return SQLITE_OK; + return rc; /* Jump here on any error */ shm_open_err: @@ -41545,10 +46989,14 @@ static int winShmLock( winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ winShm *pX; /* For looping over all siblings */ - winShmNode *pShmNode = p->pShmNode; + winShmNode *pShmNode; int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ + if( p==0 ) return SQLITE_IOERR_SHMLOCK; + pShmNode = p->pShmNode; + if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; + assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); assert( n>=1 ); assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) @@ -41683,16 +47131,24 @@ static int winShmMap( winFile *pDbFd = (winFile*)fd; winShm *pShm = pDbFd->pShm; winShmNode *pShmNode; + DWORD protect = PAGE_READWRITE; + DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ; int rc = SQLITE_OK; if( !pShm ){ rc = winOpenSharedMemory(pDbFd); if( rc!=SQLITE_OK ) return rc; pShm = pDbFd->pShm; + assert( pShm!=0 ); } pShmNode = pShm->pShmNode; sqlite3_mutex_enter(pShmNode->mutex); + if( pShmNode->isUnlocked ){ + rc = winLockSharedMemory(pShmNode); + if( rc!=SQLITE_OK ) goto shmpage_out; + pShmNode->isUnlocked = 0; + } assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); if( pShmNode->nRegion<=iRegion ){ @@ -41739,21 +47195,26 @@ static int winShmMap( } pShmNode->aRegion = apNew; + if( pShmNode->isReadonly ){ + protect = PAGE_READONLY; + flags = FILE_MAP_READ; + } + while( pShmNode->nRegion<=iRegion ){ HANDLE hMap = NULL; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ #if SQLITE_OS_WINRT hMap = osCreateFileMappingFromApp(pShmNode->hFile.h, - NULL, PAGE_READWRITE, nByte, NULL + NULL, protect, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_WIDE) hMap = osCreateFileMappingW(pShmNode->hFile.h, - NULL, PAGE_READWRITE, 0, nByte, NULL + NULL, protect, 0, nByte, NULL ); #elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA hMap = osCreateFileMappingA(pShmNode->hFile.h, - NULL, PAGE_READWRITE, 0, nByte, NULL + NULL, protect, 0, nByte, NULL ); #endif OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n", @@ -41763,11 +47224,11 @@ static int winShmMap( int iOffset = pShmNode->nRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; #if SQLITE_OS_WINRT - pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ, + pMap = osMapViewOfFileFromApp(hMap, flags, iOffset - iOffsetShift, szRegion + iOffsetShift ); #else - pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ, + pMap = osMapViewOfFile(hMap, flags, 0, iOffset - iOffsetShift, szRegion + iOffsetShift ); #endif @@ -41798,6 +47259,7 @@ static int winShmMap( }else{ *pp = 0; } + if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; sqlite3_mutex_leave(pShmNode->mutex); return rc; } @@ -41816,9 +47278,9 @@ static int winShmMap( static int winUnmapfile(winFile *pFile){ assert( pFile!=0 ); OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, " - "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n", + "mmapSize=%lld, mmapSizeMax=%lld\n", osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion, - pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax)); + pFile->mmapSize, pFile->mmapSizeMax)); if( pFile->pMapRegion ){ if( !osUnmapViewOfFile(pFile->pMapRegion) ){ pFile->lastErrno = osGetLastError(); @@ -41830,7 +47292,6 @@ static int winUnmapfile(winFile *pFile){ } pFile->pMapRegion = 0; pFile->mmapSize = 0; - pFile->mmapSizeActual = 0; } if( pFile->hMap!=NULL ){ if( !osCloseHandle(pFile->hMap) ){ @@ -41941,7 +47402,6 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ } pFd->pMapRegion = pNew; pFd->mmapSize = nMap; - pFd->mmapSizeActual = nMap; } OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n", @@ -41982,6 +47442,7 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ } } if( pFd->mmapSize >= iOff+nAmt ){ + assert( pFd->pMapRegion!=0 ); *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } @@ -42434,6 +47895,14 @@ static int winIsDir(const void *zConverted){ return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); } +/* forward reference */ +static int winAccess( + sqlite3_vfs *pVfs, /* Not used on win32 */ + const char *zFilename, /* Name of file to check */ + int flags, /* Type of test to make on this file */ + int *pResOut /* OUT: Result */ +); + /* ** Open a file. */ @@ -42477,7 +47946,7 @@ static int winOpen( #ifndef NDEBUG int isOpenJournal = (isCreate && ( - eType==SQLITE_OPEN_MASTER_JOURNAL + eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); @@ -42498,17 +47967,17 @@ static int winOpen( assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); - /* The main DB, main journal, WAL file and master journal are never + /* The main DB, main journal, WAL file and super-journal are never ** automatically deleted. Nor are they ever temporary files. */ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL ); - assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL ); + assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL ); assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL ); /* Assert that the upper layer has set one of the "file-type" flags. */ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL - || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL + || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); @@ -42580,7 +48049,11 @@ static int winOpen( dwCreationDisposition = OPEN_EXISTING; } - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + if( 0==sqlite3_uri_boolean(zName, "exclusive", 0) ){ + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + }else{ + dwShareMode = 0; + } if( isDelete ){ #if SQLITE_OS_WINCE @@ -42610,37 +48083,58 @@ static int winOpen( extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; extendedParameters.lpSecurityAttributes = NULL; extendedParameters.hTemplateFile = NULL; - while( (h = osCreateFile2((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, - dwCreationDisposition, - &extendedParameters))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFile2((LPCWSTR)zConverted, + dwDesiredAccess, + dwShareMode, + dwCreationDisposition, + &extendedParameters); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int rc2, isRO = 0; + sqlite3BeginBenignMalloc(); + rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + sqlite3EndBenignMalloc(); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); #else - while( (h = osCreateFileW((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFileW((LPCWSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int rc2, isRO = 0; + sqlite3BeginBenignMalloc(); + rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + sqlite3EndBenignMalloc(); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); #endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ - while( (h = osCreateFileA((LPCSTR)zConverted, - dwDesiredAccess, - dwShareMode, NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL))==INVALID_HANDLE_VALUE && - winRetryIoerr(&cnt, &lastErrno) ){ - /* Noop */ - } + do{ + h = osCreateFileA((LPCSTR)zConverted, + dwDesiredAccess, + dwShareMode, NULL, + dwCreationDisposition, + dwFlagsAndAttributes, + NULL); + if( h!=INVALID_HANDLE_VALUE ) break; + if( isReadWrite ){ + int rc2, isRO = 0; + sqlite3BeginBenignMalloc(); + rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO); + sqlite3EndBenignMalloc(); + if( rc2==SQLITE_OK && isRO ) break; + } + }while( winRetryIoerr(&cnt, &lastErrno) ); } #endif winLogIoerr(cnt, __LINE__); @@ -42649,8 +48143,6 @@ static int winOpen( dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); if( h==INVALID_HANDLE_VALUE ){ - pFile->lastErrno = lastErrno; - winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); sqlite3_free(zConverted); sqlite3_free(zTmpname); if( isReadWrite && !isExclusive ){ @@ -42659,6 +48151,8 @@ static int winOpen( ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); }else{ + pFile->lastErrno = lastErrno; + winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); return SQLITE_CANTOPEN_BKPT; } } @@ -42699,13 +48193,15 @@ static int winOpen( } sqlite3_free(zTmpname); - pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod; + id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ pFile->ctrlFlags |= WINFILE_RDONLY; } - if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ + if( (flags & SQLITE_OPEN_MAIN_DB) + && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) + ){ pFile->ctrlFlags |= WINFILE_PSOW; } pFile->lastErrno = NO_ERROR; @@ -42714,7 +48210,6 @@ static int winOpen( pFile->hMap = NULL; pFile->pMapRegion = 0; pFile->mmapSize = 0; - pFile->mmapSizeActual = 0; pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap; #endif @@ -42916,6 +48411,17 @@ static int winAccess( return SQLITE_OK; } +/* +** Returns non-zero if the specified path name starts with the "long path" +** prefix. +*/ +static BOOL winIsLongPathPrefix( + const char *zPathname +){ + return ( zPathname[0]=='\\' && zPathname[1]=='\\' + && zPathname[2]=='?' && zPathname[3]=='\\' ); +} + /* ** Returns non-zero if the specified path name starts with a drive letter ** followed by a colon character. @@ -42980,10 +48486,11 @@ static int winFullPathname( char *zOut; #endif - /* If this path name begins with "/X:", where "X" is any alphabetic - ** character, discard the initial "/" from the pathname. + /* If this path name begins with "/X:" or "\\?\", where "X" is any + ** alphabetic character, discard the initial "/" from the pathname. */ - if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ + if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1) + || winIsLongPathPrefix(zRelative+1)) ){ zRelative++; } @@ -43251,9 +48758,6 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ EntropyGatherer e; UNUSED_PARAMETER(pVfs); memset(zBuf, 0, nBuf); -#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE - rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */ -#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */ e.a = (unsigned char*)zBuf; e.na = nBuf; e.nXor = 0; @@ -43548,6 +49052,10 @@ SQLITE_API int sqlite3_os_init(void){ sqlite3_vfs_register(&winLongPathNolockVfs, 0); #endif +#ifndef SQLITE_OMIT_WAL + winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +#endif + return SQLITE_OK; } @@ -43558,12 +49066,898 @@ SQLITE_API int sqlite3_os_end(void){ sleepObj = NULL; } #endif + +#ifndef SQLITE_OMIT_WAL + winBigLock = 0; +#endif + return SQLITE_OK; } #endif /* SQLITE_OS_WIN */ /************** End of os_win.c **********************************************/ +/************** Begin file memdb.c *******************************************/ +/* +** 2016-09-07 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file implements an in-memory VFS. A database is held as a contiguous +** block of memory. +** +** This file also implements interface sqlite3_serialize() and +** sqlite3_deserialize(). +*/ +/* #include "sqliteInt.h" */ +#ifndef SQLITE_OMIT_DESERIALIZE + +/* +** Forward declaration of objects used by this utility +*/ +typedef struct sqlite3_vfs MemVfs; +typedef struct MemFile MemFile; +typedef struct MemStore MemStore; + +/* Access to a lower-level VFS that (might) implement dynamic loading, +** access to randomness, etc. +*/ +#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) + +/* Storage for a memdb file. +** +** An memdb object can be shared or separate. Shared memdb objects can be +** used by more than one database connection. Mutexes are used by shared +** memdb objects to coordinate access. Separate memdb objects are only +** connected to a single database connection and do not require additional +** mutexes. +** +** Shared memdb objects have .zFName!=0 and .pMutex!=0. They are created +** using "file:/name?vfs=memdb". The first character of the name must be +** "/" or else the object will be a separate memdb object. All shared +** memdb objects are stored in memdb_g.apMemStore[] in an arbitrary order. +** +** Separate memdb objects are created using a name that does not begin +** with "/" or using sqlite3_deserialize(). +** +** Access rules for shared MemStore objects: +** +** * .zFName is initialized when the object is created and afterwards +** is unchanged until the object is destroyed. So it can be accessed +** at any time as long as we know the object is not being destroyed, +** which means while either the SQLITE_MUTEX_STATIC_VFS1 or +** .pMutex is held or the object is not part of memdb_g.apMemStore[]. +** +** * Can .pMutex can only be changed while holding the +** SQLITE_MUTEX_STATIC_VFS1 mutex or while the object is not part +** of memdb_g.apMemStore[]. +** +** * Other fields can only be changed while holding the .pMutex mutex +** or when the .nRef is less than zero and the object is not part of +** memdb_g.apMemStore[]. +** +** * The .aData pointer has the added requirement that it can can only +** be changed (for resizing) when nMmap is zero. +** +*/ +struct MemStore { + sqlite3_int64 sz; /* Size of the file */ + sqlite3_int64 szAlloc; /* Space allocated to aData */ + sqlite3_int64 szMax; /* Maximum allowed size of the file */ + unsigned char *aData; /* content of the file */ + sqlite3_mutex *pMutex; /* Used by shared stores only */ + int nMmap; /* Number of memory mapped pages */ + unsigned mFlags; /* Flags */ + int nRdLock; /* Number of readers */ + int nWrLock; /* Number of writers. (Always 0 or 1) */ + int nRef; /* Number of users of this MemStore */ + char *zFName; /* The filename for shared stores */ +}; + +/* An open file */ +struct MemFile { + sqlite3_file base; /* IO methods */ + MemStore *pStore; /* The storage */ + int eLock; /* Most recent lock against this file */ +}; + +/* +** File-scope variables for holding the memdb files that are accessible +** to multiple database connections in separate threads. +** +** Must hold SQLITE_MUTEX_STATIC_VFS1 to access any part of this object. +*/ +static struct MemFS { + int nMemStore; /* Number of shared MemStore objects */ + MemStore **apMemStore; /* Array of all shared MemStore objects */ +} memdb_g; + +/* +** Methods for MemFile +*/ +static int memdbClose(sqlite3_file*); +static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); +static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); +static int memdbTruncate(sqlite3_file*, sqlite3_int64 size); +static int memdbSync(sqlite3_file*, int flags); +static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize); +static int memdbLock(sqlite3_file*, int); +/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */ +static int memdbFileControl(sqlite3_file*, int op, void *pArg); +/* static int memdbSectorSize(sqlite3_file*); // not used */ +static int memdbDeviceCharacteristics(sqlite3_file*); +static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); +static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); + +/* +** Methods for MemVfs +*/ +static int memdbOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); +/* static int memdbDelete(sqlite3_vfs*, const char *zName, int syncDir); */ +static int memdbAccess(sqlite3_vfs*, const char *zName, int flags, int *); +static int memdbFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); +static void *memdbDlOpen(sqlite3_vfs*, const char *zFilename); +static void memdbDlError(sqlite3_vfs*, int nByte, char *zErrMsg); +static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); +static void memdbDlClose(sqlite3_vfs*, void*); +static int memdbRandomness(sqlite3_vfs*, int nByte, char *zOut); +static int memdbSleep(sqlite3_vfs*, int microseconds); +/* static int memdbCurrentTime(sqlite3_vfs*, double*); */ +static int memdbGetLastError(sqlite3_vfs*, int, char *); +static int memdbCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); + +static sqlite3_vfs memdb_vfs = { + 2, /* iVersion */ + 0, /* szOsFile (set when registered) */ + 1024, /* mxPathname */ + 0, /* pNext */ + "memdb", /* zName */ + 0, /* pAppData (set when registered) */ + memdbOpen, /* xOpen */ + 0, /* memdbDelete, */ /* xDelete */ + memdbAccess, /* xAccess */ + memdbFullPathname, /* xFullPathname */ + memdbDlOpen, /* xDlOpen */ + memdbDlError, /* xDlError */ + memdbDlSym, /* xDlSym */ + memdbDlClose, /* xDlClose */ + memdbRandomness, /* xRandomness */ + memdbSleep, /* xSleep */ + 0, /* memdbCurrentTime, */ /* xCurrentTime */ + memdbGetLastError, /* xGetLastError */ + memdbCurrentTimeInt64, /* xCurrentTimeInt64 */ + 0, /* xSetSystemCall */ + 0, /* xGetSystemCall */ + 0, /* xNextSystemCall */ +}; + +static const sqlite3_io_methods memdb_io_methods = { + 3, /* iVersion */ + memdbClose, /* xClose */ + memdbRead, /* xRead */ + memdbWrite, /* xWrite */ + memdbTruncate, /* xTruncate */ + memdbSync, /* xSync */ + memdbFileSize, /* xFileSize */ + memdbLock, /* xLock */ + memdbLock, /* xUnlock - same as xLock in this case */ + 0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */ + memdbFileControl, /* xFileControl */ + 0, /* memdbSectorSize,*/ /* xSectorSize */ + memdbDeviceCharacteristics, /* xDeviceCharacteristics */ + 0, /* xShmMap */ + 0, /* xShmLock */ + 0, /* xShmBarrier */ + 0, /* xShmUnmap */ + memdbFetch, /* xFetch */ + memdbUnfetch /* xUnfetch */ +}; + +/* +** Enter/leave the mutex on a MemStore +*/ +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0 +static void memdbEnter(MemStore *p){ + UNUSED_PARAMETER(p); +} +static void memdbLeave(MemStore *p){ + UNUSED_PARAMETER(p); +} +#else +static void memdbEnter(MemStore *p){ + sqlite3_mutex_enter(p->pMutex); +} +static void memdbLeave(MemStore *p){ + sqlite3_mutex_leave(p->pMutex); +} +#endif + + + +/* +** Close an memdb-file. +** Free the underlying MemStore object when its refcount drops to zero +** or less. +*/ +static int memdbClose(sqlite3_file *pFile){ + MemStore *p = ((MemFile*)pFile)->pStore; + if( p->zFName ){ + int i; +#ifndef SQLITE_MUTEX_OMIT + sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +#endif + sqlite3_mutex_enter(pVfsMutex); + for(i=0; ALWAYS(inRef==1 ){ + memdb_g.apMemStore[i] = memdb_g.apMemStore[--memdb_g.nMemStore]; + if( memdb_g.nMemStore==0 ){ + sqlite3_free(memdb_g.apMemStore); + memdb_g.apMemStore = 0; + } + } + break; + } + } + sqlite3_mutex_leave(pVfsMutex); + }else{ + memdbEnter(p); + } + p->nRef--; + if( p->nRef<=0 ){ + if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){ + sqlite3_free(p->aData); + } + memdbLeave(p); + sqlite3_mutex_free(p->pMutex); + sqlite3_free(p); + }else{ + memdbLeave(p); + } + return SQLITE_OK; +} + +/* +** Read data from an memdb-file. +*/ +static int memdbRead( + sqlite3_file *pFile, + void *zBuf, + int iAmt, + sqlite_int64 iOfst +){ + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); + if( iOfst+iAmt>p->sz ){ + memset(zBuf, 0, iAmt); + if( iOfstsz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst); + memdbLeave(p); + return SQLITE_IOERR_SHORT_READ; + } + memcpy(zBuf, p->aData+iOfst, iAmt); + memdbLeave(p); + return SQLITE_OK; +} + +/* +** Try to enlarge the memory allocation to hold at least sz bytes +*/ +static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){ + unsigned char *pNew; + if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){ + return SQLITE_FULL; + } + if( newSz>p->szMax ){ + return SQLITE_FULL; + } + newSz *= 2; + if( newSz>p->szMax ) newSz = p->szMax; + pNew = sqlite3Realloc(p->aData, newSz); + if( pNew==0 ) return SQLITE_IOERR_NOMEM; + p->aData = pNew; + p->szAlloc = newSz; + return SQLITE_OK; +} + +/* +** Write data to an memdb-file. +*/ +static int memdbWrite( + sqlite3_file *pFile, + const void *z, + int iAmt, + sqlite_int64 iOfst +){ + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); + if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ){ + /* Can't happen: memdbLock() will return SQLITE_READONLY before + ** reaching this point */ + memdbLeave(p); + return SQLITE_IOERR_WRITE; + } + if( iOfst+iAmt>p->sz ){ + int rc; + if( iOfst+iAmt>p->szAlloc + && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK + ){ + memdbLeave(p); + return rc; + } + if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz); + p->sz = iOfst+iAmt; + } + memcpy(p->aData+iOfst, z, iAmt); + memdbLeave(p); + return SQLITE_OK; +} + +/* +** Truncate an memdb-file. +** +** In rollback mode (which is always the case for memdb, as it does not +** support WAL mode) the truncate() method is only used to reduce +** the size of a file, never to increase the size. +*/ +static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){ + MemStore *p = ((MemFile*)pFile)->pStore; + int rc = SQLITE_OK; + memdbEnter(p); + if( size>p->sz ){ + /* This can only happen with a corrupt wal mode db */ + rc = SQLITE_CORRUPT; + }else{ + p->sz = size; + } + memdbLeave(p); + return rc; +} + +/* +** Sync an memdb-file. +*/ +static int memdbSync(sqlite3_file *pFile, int flags){ + UNUSED_PARAMETER(pFile); + UNUSED_PARAMETER(flags); + return SQLITE_OK; +} + +/* +** Return the current file-size of an memdb-file. +*/ +static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); + *pSize = p->sz; + memdbLeave(p); + return SQLITE_OK; +} + +/* +** Lock an memdb-file. +*/ +static int memdbLock(sqlite3_file *pFile, int eLock){ + MemFile *pThis = (MemFile*)pFile; + MemStore *p = pThis->pStore; + int rc = SQLITE_OK; + if( eLock==pThis->eLock ) return SQLITE_OK; + memdbEnter(p); + if( eLock>SQLITE_LOCK_SHARED ){ + if( p->mFlags & SQLITE_DESERIALIZE_READONLY ){ + rc = SQLITE_READONLY; + }else if( pThis->eLock<=SQLITE_LOCK_SHARED ){ + if( p->nWrLock ){ + rc = SQLITE_BUSY; + }else{ + p->nWrLock = 1; + } + } + }else if( eLock==SQLITE_LOCK_SHARED ){ + if( pThis->eLock > SQLITE_LOCK_SHARED ){ + assert( p->nWrLock==1 ); + p->nWrLock = 0; + }else if( p->nWrLock ){ + rc = SQLITE_BUSY; + }else{ + p->nRdLock++; + } + }else{ + assert( eLock==SQLITE_LOCK_NONE ); + if( pThis->eLock>SQLITE_LOCK_SHARED ){ + assert( p->nWrLock==1 ); + p->nWrLock = 0; + } + assert( p->nRdLock>0 ); + p->nRdLock--; + } + if( rc==SQLITE_OK ) pThis->eLock = eLock; + memdbLeave(p); + return rc; +} + +#if 0 +/* +** This interface is only used for crash recovery, which does not +** occur on an in-memory database. +*/ +static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){ + *pResOut = 0; + return SQLITE_OK; +} +#endif + + +/* +** File control method. For custom operations on an memdb-file. +*/ +static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){ + MemStore *p = ((MemFile*)pFile)->pStore; + int rc = SQLITE_NOTFOUND; + memdbEnter(p); + if( op==SQLITE_FCNTL_VFSNAME ){ + *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz); + rc = SQLITE_OK; + } + if( op==SQLITE_FCNTL_SIZE_LIMIT ){ + sqlite3_int64 iLimit = *(sqlite3_int64*)pArg; + if( iLimitsz ){ + if( iLimit<0 ){ + iLimit = p->szMax; + }else{ + iLimit = p->sz; + } + } + p->szMax = iLimit; + *(sqlite3_int64*)pArg = iLimit; + rc = SQLITE_OK; + } + memdbLeave(p); + return rc; +} + +#if 0 /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */ +/* +** Return the sector-size in bytes for an memdb-file. +*/ +static int memdbSectorSize(sqlite3_file *pFile){ + return 1024; +} +#endif + +/* +** Return the device characteristic flags supported by an memdb-file. +*/ +static int memdbDeviceCharacteristics(sqlite3_file *pFile){ + UNUSED_PARAMETER(pFile); + return SQLITE_IOCAP_ATOMIC | + SQLITE_IOCAP_POWERSAFE_OVERWRITE | + SQLITE_IOCAP_SAFE_APPEND | + SQLITE_IOCAP_SEQUENTIAL; +} + +/* Fetch a page of a memory-mapped file */ +static int memdbFetch( + sqlite3_file *pFile, + sqlite3_int64 iOfst, + int iAmt, + void **pp +){ + MemStore *p = ((MemFile*)pFile)->pStore; + memdbEnter(p); + if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){ + *pp = 0; + }else{ + p->nMmap++; + *pp = (void*)(p->aData + iOfst); + } + memdbLeave(p); + return SQLITE_OK; +} + +/* Release a memory-mapped page */ +static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ + MemStore *p = ((MemFile*)pFile)->pStore; + UNUSED_PARAMETER(iOfst); + UNUSED_PARAMETER(pPage); + memdbEnter(p); + p->nMmap--; + memdbLeave(p); + return SQLITE_OK; +} + +/* +** Open an mem file handle. +*/ +static int memdbOpen( + sqlite3_vfs *pVfs, + const char *zName, + sqlite3_file *pFd, + int flags, + int *pOutFlags +){ + MemFile *pFile = (MemFile*)pFd; + MemStore *p = 0; + int szName; + UNUSED_PARAMETER(pVfs); + + memset(pFile, 0, sizeof(*pFile)); + szName = sqlite3Strlen30(zName); + if( szName>1 && zName[0]=='/' ){ + int i; +#ifndef SQLITE_MUTEX_OMIT + sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); +#endif + sqlite3_mutex_enter(pVfsMutex); + for(i=0; izFName,zName)==0 ){ + p = memdb_g.apMemStore[i]; + break; + } + } + if( p==0 ){ + MemStore **apNew; + p = sqlite3Malloc( sizeof(*p) + szName + 3 ); + if( p==0 ){ + sqlite3_mutex_leave(pVfsMutex); + return SQLITE_NOMEM; + } + apNew = sqlite3Realloc(memdb_g.apMemStore, + sizeof(apNew[0])*(memdb_g.nMemStore+1) ); + if( apNew==0 ){ + sqlite3_free(p); + sqlite3_mutex_leave(pVfsMutex); + return SQLITE_NOMEM; + } + apNew[memdb_g.nMemStore++] = p; + memdb_g.apMemStore = apNew; + memset(p, 0, sizeof(*p)); + p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE|SQLITE_DESERIALIZE_FREEONCLOSE; + p->szMax = sqlite3GlobalConfig.mxMemdbSize; + p->zFName = (char*)&p[1]; + memcpy(p->zFName, zName, szName+1); + p->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( p->pMutex==0 ){ + memdb_g.nMemStore--; + sqlite3_free(p); + sqlite3_mutex_leave(pVfsMutex); + return SQLITE_NOMEM; + } + p->nRef = 1; + memdbEnter(p); + }else{ + memdbEnter(p); + p->nRef++; + } + sqlite3_mutex_leave(pVfsMutex); + }else{ + p = sqlite3Malloc( sizeof(*p) ); + if( p==0 ){ + return SQLITE_NOMEM; + } + memset(p, 0, sizeof(*p)); + p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE; + p->szMax = sqlite3GlobalConfig.mxMemdbSize; + } + pFile->pStore = p; + if( pOutFlags!=0 ){ + *pOutFlags = flags | SQLITE_OPEN_MEMORY; + } + pFd->pMethods = &memdb_io_methods; + memdbLeave(p); + return SQLITE_OK; +} + +#if 0 /* Only used to delete rollback journals, super-journals, and WAL + ** files, none of which exist in memdb. So this routine is never used */ +/* +** Delete the file located at zPath. If the dirSync argument is true, +** ensure the file-system modifications are synced to disk before +** returning. +*/ +static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + return SQLITE_IOERR_DELETE; +} +#endif + +/* +** Test for access permissions. Return true if the requested permission +** is available, or false otherwise. +** +** With memdb, no files ever exist on disk. So always return false. +*/ +static int memdbAccess( + sqlite3_vfs *pVfs, + const char *zPath, + int flags, + int *pResOut +){ + UNUSED_PARAMETER(pVfs); + UNUSED_PARAMETER(zPath); + UNUSED_PARAMETER(flags); + *pResOut = 0; + return SQLITE_OK; +} + +/* +** Populate buffer zOut with the full canonical pathname corresponding +** to the pathname in zPath. zOut is guaranteed to point to a buffer +** of at least (INST_MAX_PATHNAME+1) bytes. +*/ +static int memdbFullPathname( + sqlite3_vfs *pVfs, + const char *zPath, + int nOut, + char *zOut +){ + UNUSED_PARAMETER(pVfs); + sqlite3_snprintf(nOut, zOut, "%s", zPath); + return SQLITE_OK; +} + +/* +** Open the dynamic library located at zPath and return a handle. +*/ +static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){ + return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); +} + +/* +** Populate the buffer zErrMsg (size nByte bytes) with a human readable +** utf-8 string describing the most recent error encountered associated +** with dynamic libraries. +*/ +static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ + ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); +} + +/* +** Return a pointer to the symbol zSymbol in the dynamic library pHandle. +*/ +static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ + return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); +} + +/* +** Close the dynamic library handle pHandle. +*/ +static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){ + ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); +} + +/* +** Populate the buffer pointed to by zBufOut with nByte bytes of +** random data. +*/ +static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ + return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); +} + +/* +** Sleep for nMicro microseconds. Return the number of microseconds +** actually slept. +*/ +static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){ + return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); +} + +#if 0 /* Never used. Modern cores only call xCurrentTimeInt64() */ +/* +** Return the current time as a Julian Day number in *pTimeOut. +*/ +static int memdbCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ + return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); +} +#endif + +static int memdbGetLastError(sqlite3_vfs *pVfs, int a, char *b){ + return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); +} +static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ + return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p); +} + +/* +** Translate a database connection pointer and schema name into a +** MemFile pointer. +*/ +static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){ + MemFile *p = 0; + MemStore *pStore; + int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); + if( rc ) return 0; + if( p->base.pMethods!=&memdb_io_methods ) return 0; + pStore = p->pStore; + memdbEnter(pStore); + if( pStore->zFName!=0 ) p = 0; + memdbLeave(pStore); + return p; +} + +/* +** Return the serialization of a database +*/ +SQLITE_API unsigned char *sqlite3_serialize( + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which database within the connection */ + sqlite3_int64 *piSize, /* Write size here, if not NULL */ + unsigned int mFlags /* Maybe SQLITE_SERIALIZE_NOCOPY */ +){ + MemFile *p; + int iDb; + Btree *pBt; + sqlite3_int64 sz; + int szPage = 0; + sqlite3_stmt *pStmt = 0; + unsigned char *pOut; + char *zSql; + int rc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + + if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; + p = memdbFromDbSchema(db, zSchema); + iDb = sqlite3FindDbName(db, zSchema); + if( piSize ) *piSize = -1; + if( iDb<0 ) return 0; + if( p ){ + MemStore *pStore = p->pStore; + assert( pStore->pMutex==0 ); + if( piSize ) *piSize = pStore->sz; + if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ + pOut = pStore->aData; + }else{ + pOut = sqlite3_malloc64( pStore->sz ); + if( pOut ) memcpy(pOut, pStore->aData, pStore->sz); + } + return pOut; + } + pBt = db->aDb[iDb].pBt; + if( pBt==0 ) return 0; + szPage = sqlite3BtreeGetPageSize(pBt); + zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema); + rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM; + sqlite3_free(zSql); + if( rc ) return 0; + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_ROW ){ + pOut = 0; + }else{ + sz = sqlite3_column_int64(pStmt, 0)*szPage; + if( piSize ) *piSize = sz; + if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ + pOut = 0; + }else{ + pOut = sqlite3_malloc64( sz ); + if( pOut ){ + int nPage = sqlite3_column_int(pStmt, 0); + Pager *pPager = sqlite3BtreePager(pBt); + int pgno; + for(pgno=1; pgno<=nPage; pgno++){ + DbPage *pPage = 0; + unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1); + rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0); + if( rc==SQLITE_OK ){ + memcpy(pTo, sqlite3PagerGetData(pPage), szPage); + }else{ + memset(pTo, 0, szPage); + } + sqlite3PagerUnref(pPage); + } + } + } + } + sqlite3_finalize(pStmt); + return pOut; +} + +/* Convert zSchema to a MemDB and initialize its content. +*/ +SQLITE_API int sqlite3_deserialize( + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which DB to reopen with the deserialization */ + unsigned char *pData, /* The serialized database content */ + sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szBuf, /* Total size of buffer pData[] */ + unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ +){ + MemFile *p; + char *zSql; + sqlite3_stmt *pStmt = 0; + int rc; + int iDb; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + if( szDb<0 ) return SQLITE_MISUSE_BKPT; + if( szBuf<0 ) return SQLITE_MISUSE_BKPT; +#endif + + sqlite3_mutex_enter(db->mutex); + if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; + iDb = sqlite3FindDbName(db, zSchema); + testcase( iDb==1 ); + if( iDb<2 && iDb!=0 ){ + rc = SQLITE_ERROR; + goto end_deserialize; + } + zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } + if( rc ) goto end_deserialize; + db->init.iDb = (u8)iDb; + db->init.reopenMemdb = 1; + rc = sqlite3_step(pStmt); + db->init.reopenMemdb = 0; + if( rc!=SQLITE_DONE ){ + rc = SQLITE_ERROR; + goto end_deserialize; + } + p = memdbFromDbSchema(db, zSchema); + if( p==0 ){ + rc = SQLITE_ERROR; + }else{ + MemStore *pStore = p->pStore; + pStore->aData = pData; + pData = 0; + pStore->sz = szDb; + pStore->szAlloc = szBuf; + pStore->szMax = szBuf; + if( pStore->szMaxszMax = sqlite3GlobalConfig.mxMemdbSize; + } + pStore->mFlags = mFlags; + rc = SQLITE_OK; + } + +end_deserialize: + sqlite3_finalize(pStmt); + if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){ + sqlite3_free(pData); + } + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** This routine is called when the extension is loaded. +** Register the new VFS. +*/ +SQLITE_PRIVATE int sqlite3MemdbInit(void){ + sqlite3_vfs *pLower = sqlite3_vfs_find(0); + unsigned int sz; + if( NEVER(pLower==0) ) return SQLITE_ERROR; + sz = pLower->szOsFile; + memdb_vfs.pAppData = pLower; + /* The following conditional can only be true when compiled for + ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave + ** it in, to be safe, but it is marked as NO_TEST since there + ** is no way to reach it under most builds. */ + if( szpCache==0 ) return; N = sqlite3PcachePagecount(pCache); @@ -44085,7 +50479,7 @@ struct PCache { ** ** assert( sqlite3PcachePageSanity(pPg) ); */ -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){ PCache *pCache; assert( pPg!=0 ); @@ -44145,12 +50539,12 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); assert( pPage->pDirtyPrev || pPage==p->pDirty ); - + /* Update the PCache1.pSynced variable if necessary. */ if( p->pSynced==pPage ){ p->pSynced = pPage->pDirtyPrev; } - + if( pPage->pDirtyNext ){ pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; }else{ @@ -44160,7 +50554,7 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ if( pPage->pDirtyPrev ){ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; }else{ - /* If there are now no dirty pages in the cache, set eCreate to 2. + /* If there are now no dirty pages in the cache, set eCreate to 2. ** This is an optimization that allows sqlite3PcacheFetch() to skip ** searching for a dirty page to eject from the cache when it might ** otherwise have to. */ @@ -44172,12 +50566,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ p->eCreate = 2; } } - pPage->pDirtyNext = 0; - pPage->pDirtyPrev = 0; } if( addRemove & PCACHE_DIRTYLIST_ADD ){ - assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage ); - + pPage->pDirtyPrev = 0; pPage->pDirtyNext = p->pDirty; if( pPage->pDirtyNext ){ assert( pPage->pDirtyNext->pDirtyPrev==0 ); @@ -44192,11 +50583,11 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ p->pDirty = pPage; /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set - ** pSynced to point to it. Checking the NEED_SYNC flag is an + ** pSynced to point to it. Checking the NEED_SYNC flag is an ** optimization, as if pSynced points to a page with the NEED_SYNC - ** flag set sqlite3PcacheFetchStress() searches through all newer + ** flag set sqlite3PcacheFetchStress() searches through all newer ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */ - if( !p->pSynced + if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ ){ p->pSynced = pPage; @@ -44227,16 +50618,20 @@ static int numberOfCachePages(PCache *p){ ** suggested cache size is set to N. */ return p->szCache; }else{ - /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then - ** the number of cache pages is adjusted to use approximately abs(N*1024) - ** bytes of memory. */ - return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); + i64 n; + /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the + ** number of cache pages is adjusted to be a number of pages that would + ** use approximately abs(N*1024) bytes of memory based on the current + ** page size. */ + n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); + if( n>1000000000 ) n = 1000000000; + return (int)n; } } /*************************************************** General Interfaces ****** ** -** Initialize and shutdown the page cache subsystem. Neither of these +** Initialize and shutdown the page cache subsystem. Neither of these ** functions are threadsafe. */ SQLITE_PRIVATE int sqlite3PcacheInitialize(void){ @@ -44245,6 +50640,7 @@ SQLITE_PRIVATE int sqlite3PcacheInitialize(void){ ** built-in default page cache is used instead of the application defined ** page cache. */ sqlite3PCacheSetDefault(); + assert( sqlite3GlobalConfig.pcache2.xInit!=0 ); } return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg); } @@ -44262,8 +50658,8 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); } /* ** Create a new PCache object. Storage space to hold the object -** has already been allocated and is passed in as the p pointer. -** The caller discovers how much space needs to be allocated by +** has already been allocated and is passed in as the p pointer. +** The caller discovers how much space needs to be allocated by ** calling sqlite3PcacheSize(). ** ** szExtra is some extra space allocated for each page. The first @@ -44375,7 +50771,7 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch( /* ** If the sqlite3PcacheFetch() routine is unable to allocate a new ** page because no clean pages are available for reuse and the cache -** size limit has been reached, then this routine can be invoked to +** size limit has been reached, then this routine can be invoked to ** try harder to allocate a page. This routine might invoke the stress ** callback to spill dirty pages to the journal. It will then try to ** allocate the new page and will only fail to allocate a new page on @@ -44392,17 +50788,17 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress( if( pCache->eCreate==2 ) return 0; if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ - /* Find a dirty page to write-out and recycle. First try to find a + /* Find a dirty page to write-out and recycle. First try to find a ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC - ** cleared), but if that is not possible settle for any other + ** cleared), but if that is not possible settle for any other ** unreferenced dirty page. ** ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC ** flag is currently referenced, then the following may leave pSynced ** set incorrectly (pointing to other than the LRU page with NEED_SYNC ** cleared). This is Ok, as pSynced is just an optimization. */ - for(pPg=pCache->pSynced; - pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); + for(pPg=pCache->pSynced; + pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); pPg=pPg->pDirtyPrev ); pCache->pSynced = pPg; @@ -44412,10 +50808,10 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress( if( pPg ){ int rc; #ifdef SQLITE_LOG_CACHE_SPILL - sqlite3_log(SQLITE_FULL, + sqlite3_log(SQLITE_FULL, "spill page %d making room for %d - cache used: %d/%d", pPg->pgno, pgno, - sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), + sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache), numberOfCachePages(pCache)); #endif pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno)); @@ -44494,11 +50890,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); - }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/ - /* Move the page to the head of the dirty list. If p->pDirtyPrev==0, - ** then page p is already at the head of the dirty list and the - ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE - ** tag above. */ + }else{ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } @@ -44534,7 +50926,8 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){ ** make it so. */ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ - assert( p->nRef>0 ); + assert( p->nRef>0 || p->pCache->bPurgeable==0 ); + testcase( p->nRef==0 ); assert( sqlite3PcachePageSanity(p) ); if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ p->flags &= ~PGHDR_DONT_WRITE; @@ -44554,16 +50947,15 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){ */ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){ assert( sqlite3PcachePageSanity(p) ); - if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){ - assert( (p->flags & PGHDR_CLEAN)==0 ); - pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); - p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); - p->flags |= PGHDR_CLEAN; - pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); - assert( sqlite3PcachePageSanity(p) ); - if( p->nRef==0 ){ - pcacheUnpin(p); - } + assert( (p->flags & PGHDR_DIRTY)!=0 ); + assert( (p->flags & PGHDR_CLEAN)==0 ); + pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); + p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); + p->flags |= PGHDR_CLEAN; + pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); + assert( sqlite3PcachePageSanity(p) ); + if( p->nRef==0 ){ + pcacheUnpin(p); } } @@ -44602,7 +50994,7 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){ } /* -** Change the page number of page p to newPgno. +** Change the page number of page p to newPgno. */ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ PCache *pCache = p->pCache; @@ -44665,7 +51057,7 @@ SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } -/* +/* ** Discard the contents of the cache. */ SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){ @@ -44756,7 +51148,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){ return pcacheSortDirtyList(pCache->pDirty); } -/* +/* ** Return the total number of references to all pages held by the cache. ** ** This is not the total number of pages referenced, but the sum of the @@ -44773,7 +51165,7 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){ return p->nRef; } -/* +/* ** Return the total number of pages in the cache. */ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){ @@ -44815,7 +51207,7 @@ SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){ p->szSpill = mxPage; } res = numberOfCachePages(p); - if( resszSpill ) res = p->szSpill; + if( resszSpill ) res = p->szSpill; return res; } @@ -44845,6 +51237,15 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){ return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0; } +#ifdef SQLITE_DIRECT_OVERFLOW_READ +/* +** Return true if there are one or more dirty pages in the cache. Else false. +*/ +SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache){ + return (pCache->pDirty!=0); +} +#endif + #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified @@ -44926,7 +51327,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd ** ** The third case is a chunk of heap memory (defaulting to 100 pages worth) ** that is allocated when the page cache is created. The size of the local -** bulk allocation can be adjusted using +** bulk allocation can be adjusted using ** ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N). ** @@ -44951,24 +51352,41 @@ typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; /* -** Each cache entry is represented by an instance of the following +** Each cache entry is represented by an instance of the following ** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of -** PgHdr1.pCache->szPage bytes is allocated directly before this structure +** PgHdr1.pCache->szPage bytes is allocated directly before this structure ** in memory. +** +** Note: Variables isBulkLocal and isAnchor were once type "u8". That works, +** but causes a 2-byte gap in the structure for most architectures (since +** pointers must be either 4 or 8-byte aligned). As this structure is located +** in memory directly after the associated page data, if the database is +** corrupt, code at the b-tree layer may overread the page buffer and +** read part of this structure before the corruption is detected. This +** can cause a valgrind error if the unitialized gap is accessed. Using u16 +** ensures there is no such gap, and therefore no bytes of unitialized memory +** in the structure. */ struct PgHdr1 { sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ unsigned int iKey; /* Key value (page number) */ - u8 isPinned; /* Page in use, not on the LRU list */ - u8 isBulkLocal; /* This page from bulk local storage */ - u8 isAnchor; /* This is the PGroup.lru element */ + u16 isBulkLocal; /* This page from bulk local storage */ + u16 isAnchor; /* This is the PGroup.lru element */ PgHdr1 *pNext; /* Next in hash table chain */ PCache1 *pCache; /* Cache that currently owns this page */ PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ + /* NB: pLruPrev is only valid if pLruNext!=0 */ }; -/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set +/* +** A page is pinned if it is not on the LRU list. To be "pinned" means +** that the page is in active use and must not be deallocated. +*/ +#define PAGE_IS_PINNED(p) ((p)->pLruNext==0) +#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0) + +/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set ** of one or more PCaches that are able to recycle each other's unpinned ** pages when they are under memory pressure. A PGroup is an instance of ** the following object. @@ -44995,7 +51413,7 @@ struct PGroup { unsigned int nMaxPage; /* Sum of nMax for purgeable caches */ unsigned int nMinPage; /* Sum of nMin for purgeable caches */ unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */ - unsigned int nCurrentPage; /* Number of purgeable pages allocated */ + unsigned int nPurgeable; /* Number of purgeable pages allocated */ PgHdr1 lru; /* The beginning and end of the LRU list */ }; @@ -45004,16 +51422,18 @@ struct PGroup { ** temporary or transient database) has a single page cache which ** is an instance of this object. ** -** Pointers to structures of this type are cast and returned as +** Pointers to structures of this type are cast and returned as ** opaque sqlite3_pcache* handles. */ struct PCache1 { /* Cache configuration parameters. Page size (szPage) and the purgeable - ** flag (bPurgeable) are set when the cache is created. nMax may be + ** flag (bPurgeable) and the pnPurgeable pointer are all set when the + ** cache is created and are never changed thereafter. nMax may be ** modified at any time by a call to the pcache1Cachesize() method. ** The PGroup mutex must be held when accessing nMax. */ PGroup *pGroup; /* PGroup this cache belongs to */ + unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */ int szPage; /* Size of database content section */ int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */ int szAlloc; /* Total size of one pcache line */ @@ -45022,6 +51442,7 @@ struct PCache1 { unsigned int nMax; /* Configured "cache_size" value */ unsigned int n90pct; /* nMax*9/10 */ unsigned int iMaxKey; /* Largest key seen since xTruncate() */ + unsigned int nPurgeableDummy; /* pnPurgeable points here when not used*/ /* Hash table of all pages. The following variables may only be accessed ** when the accessor is holding the PGroup mutex. @@ -45055,7 +51476,7 @@ static SQLITE_WSD struct PCacheGlobal { */ int isInit; /* True if initialized */ int separateCache; /* Use a new PGroup for each PCache */ - int nInitPage; /* Initial bulk allocation size */ + int nInitPage; /* Initial bulk allocation size */ int szSlot; /* Size of each free slot */ int nSlot; /* The number of pcache slots */ int nReserve; /* Try to keep nFreeSlot above this */ @@ -45096,7 +51517,7 @@ static SQLITE_WSD struct PCacheGlobal { /* -** This function is called during initialization if a static buffer is +** This function is called during initialization if a static buffer is ** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE ** verb to sqlite3_config(). Parameter pBuf points to an allocation large ** enough to contain 'n' buffers of 'sz' bytes each. @@ -45108,6 +51529,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ if( pcache1.isInit ){ PgFreeslot *p; if( pBuf==0 ) sz = n = 0; + if( n==0 ) sz = 0; sz = ROUNDDOWN8(sz); pcache1.szSlot = sz; pcache1.nSlot = pcache1.nFreeSlot = n; @@ -45148,25 +51570,25 @@ static int pcache1InitBulk(PCache1 *pCache){ sqlite3EndBenignMalloc(); if( zBulk ){ int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; - int i; - for(i=0; iszPage]; pX->page.pBuf = zBulk; pX->page.pExtra = &pX[1]; pX->isBulkLocal = 1; pX->isAnchor = 0; pX->pNext = pCache->pFree; + pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ pCache->pFree = pX; zBulk += pCache->szAlloc; - } + }while( --nBulk ); } return pCache->pFree!=0; } /* ** Malloc function used within this file to allocate space from the buffer -** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no -** such buffer exists or there is no space left in it, this function falls +** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no +** such buffer exists or there is no space left in it, this function falls ** back to sqlite3Malloc(). ** ** Multiple threads can run this routine at the same time. Global variables @@ -45266,13 +51688,14 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){ + assert( pCache->pFree!=0 ); p = pCache->pFree; pCache->pFree = p->pNext; p->pNext = 0; }else{ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* The group mutex must be released before pcache1Alloc() is called. This - ** is because it might call sqlite3_release_memory(), which assumes that + ** is because it might call sqlite3_release_memory(), which assumes that ** this mutex is not held. */ assert( pcache1.separateCache==0 ); assert( pCache->pGroup==&pcache1.grp ); @@ -45289,21 +51712,22 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){ } #else pPg = pcache1Alloc(pCache->szAlloc); - p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; #endif if( benignMalloc ){ sqlite3EndBenignMalloc(); } #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT pcache1EnterMutex(pCache->pGroup); #endif if( pPg==0 ) return 0; +#ifndef SQLITE_PCACHE_SEPARATE_HEADER + p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; +#endif p->page.pBuf = pPg; p->page.pExtra = &p[1]; p->isBulkLocal = 0; p->isAnchor = 0; + p->pLruPrev = 0; /* Initializing this saves a valgrind error */ } - if( pCache->bPurgeable ){ - pCache->pGroup->nCurrentPage++; - } + (*pCache->pnPurgeable)++; return p; } @@ -45324,9 +51748,7 @@ static void pcache1FreePage(PgHdr1 *p){ sqlite3_free(p); #endif } - if( pCache->bPurgeable ){ - pCache->pGroup->nCurrentPage--; - } + (*pCache->pnPurgeable)--; } /* @@ -45335,6 +51757,7 @@ static void pcache1FreePage(PgHdr1 *p){ ** exists, this function falls back to sqlite3Malloc(). */ SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){ + assert( sz<=65536+8 ); /* These allocations are never very large */ return pcache1Alloc(sz); } @@ -45414,35 +51837,32 @@ static void pcache1ResizeHash(PCache1 *p){ } /* -** This function is used internally to remove the page pPage from the +** This function is used internally to remove the page pPage from the ** PGroup LRU list, if is part of it. If pPage is not part of the PGroup ** LRU list, then this function is a no-op. ** ** The PGroup mutex must be held when this function is called. */ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){ - PCache1 *pCache; - assert( pPage!=0 ); - assert( pPage->isPinned==0 ); - pCache = pPage->pCache; + assert( PAGE_IS_UNPINNED(pPage) ); assert( pPage->pLruNext ); assert( pPage->pLruPrev ); - assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); + assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) ); pPage->pLruPrev->pLruNext = pPage->pLruNext; pPage->pLruNext->pLruPrev = pPage->pLruPrev; pPage->pLruNext = 0; - pPage->pLruPrev = 0; - pPage->isPinned = 1; + /* pPage->pLruPrev = 0; + ** No need to clear pLruPrev as it is never accessed if pLruNext is 0 */ assert( pPage->isAnchor==0 ); - assert( pCache->pGroup->lru.isAnchor==1 ); - pCache->nRecyclable--; + assert( pPage->pCache->pGroup->lru.isAnchor==1 ); + pPage->pCache->nRecyclable--; return pPage; } /* -** Remove the page supplied as an argument from the hash table +** Remove the page supplied as an argument from the hash table ** (PCache1.apHash structure) that it is currently stored in. ** Also free the page if freePage is true. ** @@ -45470,11 +51890,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){ PGroup *pGroup = pCache->pGroup; PgHdr1 *p; assert( sqlite3_mutex_held(pGroup->mutex) ); - while( pGroup->nCurrentPage>pGroup->nMaxPage + while( pGroup->nPurgeable>pGroup->nMaxPage && (p=pGroup->lru.pLruPrev)->isAnchor==0 ){ assert( p->pCache->pGroup==pGroup ); - assert( p->isPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } @@ -45485,8 +51905,8 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){ } /* -** Discard all pages from cache pCache with a page number (key value) -** greater than or equal to iLimit. Any pinned pages that meet this +** Discard all pages from cache pCache with a page number (key value) +** greater than or equal to iLimit. Any pinned pages that meet this ** criteria are unpinned before they are discarded. ** ** The PCache mutex must be held when this function is called. @@ -45518,12 +51938,12 @@ static void pcache1TruncateUnsafe( PgHdr1 **pp; PgHdr1 *pPage; assert( hnHash ); - pp = &pCache->apHash[h]; + pp = &pCache->apHash[h]; while( (pPage = *pp)!=0 ){ if( pPage->iKey>=iLimit ){ pCache->nPage--; *pp = pPage->pNext; - if( !pPage->isPinned ) pcache1PinPage(pPage); + if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage); pcache1FreePage(pPage); }else{ pp = &pPage->pNext; @@ -45557,7 +51977,7 @@ static int pcache1Init(void *NotUsed){ ** ** * Use a unified cache in single-threaded applications that have ** configured a start-time buffer for use as page-cache memory using - ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL + ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL ** pBuf argument. ** ** * Otherwise use separate caches (mode-1) @@ -45592,7 +52012,7 @@ static int pcache1Init(void *NotUsed){ /* ** Implementation of the sqlite3_pcache.xShutdown method. -** Note that the static mutex allocated in xInit does +** Note that the static mutex allocated in xInit does ** not need to be freed. */ static void pcache1Shutdown(void *NotUsed){ @@ -45626,6 +52046,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ }else{ pGroup = &pcache1.grp; } + pcache1EnterMutex(pGroup); if( pGroup->lru.isAnchor==0 ){ pGroup->lru.isAnchor = 1; pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru; @@ -45635,12 +52056,14 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pCache->szExtra = szExtra; pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1)); pCache->bPurgeable = (bPurgeable ? 1 : 0); - pcache1EnterMutex(pGroup); pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; + pCache->pnPurgeable = &pGroup->nPurgeable; + }else{ + pCache->pnPurgeable = &pCache->nPurgeableDummy; } pcache1LeaveMutex(pGroup); if( pCache->nHash==0 ){ @@ -45652,18 +52075,24 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ } /* -** Implementation of the sqlite3_pcache.xCachesize method. +** Implementation of the sqlite3_pcache.xCachesize method. ** ** Configure the cache_size limit for a cache. */ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ PCache1 *pCache = (PCache1 *)p; + u32 n; + assert( nMax>=0 ); if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; pcache1EnterMutex(pGroup); - pGroup->nMaxPage += (nMax - pCache->nMax); + n = (u32)nMax; + if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){ + n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax; + } + pGroup->nMaxPage += (n - pCache->nMax); pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; - pCache->nMax = nMax; + pCache->nMax = n; pCache->n90pct = pCache->nMax*9/10; pcache1EnforceMaxPage(pCache); pcache1LeaveMutex(pGroup); @@ -45671,7 +52100,7 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ } /* -** Implementation of the sqlite3_pcache.xShrink method. +** Implementation of the sqlite3_pcache.xShrink method. ** ** Free up as much memory as possible. */ @@ -45679,7 +52108,7 @@ static void pcache1Shrink(sqlite3_pcache *p){ PCache1 *pCache = (PCache1*)p; if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; - int savedMaxPage; + unsigned int savedMaxPage; pcache1EnterMutex(pGroup); savedMaxPage = pGroup->nMaxPage; pGroup->nMaxPage = 0; @@ -45690,7 +52119,7 @@ static void pcache1Shrink(sqlite3_pcache *p){ } /* -** Implementation of the sqlite3_pcache.xPagecount method. +** Implementation of the sqlite3_pcache.xPagecount method. */ static int pcache1Pagecount(sqlite3_pcache *p){ int n; @@ -45711,8 +52140,8 @@ static int pcache1Pagecount(sqlite3_pcache *p){ ** for these steps, the main pcache1Fetch() procedure can run faster. */ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( - PCache1 *pCache, - unsigned int iKey, + PCache1 *pCache, + unsigned int iKey, int createFlag ){ unsigned int nPinned; @@ -45742,7 +52171,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ){ PCache1 *pOther; pPage = pGroup->lru.pLruPrev; - assert( pPage->isPinned==0 ); + assert( PAGE_IS_UNPINNED(pPage) ); pcache1RemoveFromHash(pPage, 0); pcache1PinPage(pPage); pOther = pPage->pCache; @@ -45750,12 +52179,12 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( pcache1FreePage(pPage); pPage = 0; }else{ - pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable); + pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable); } } - /* Step 5. If a usable page buffer has still not been found, - ** attempt to allocate a new one. + /* Step 5. If a usable page buffer has still not been found, + ** attempt to allocate a new one. */ if( !pPage ){ pPage = pcache1AllocPage(pCache, createFlag==1); @@ -45767,9 +52196,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( pPage->iKey = iKey; pPage->pNext = pCache->apHash[h]; pPage->pCache = pCache; - pPage->pLruPrev = 0; pPage->pLruNext = 0; - pPage->isPinned = 1; + /* pPage->pLruPrev = 0; + ** No need to clear pLruPrev since it is not accessed when pLruNext==0 */ *(void **)pPage->page.pExtra = 0; pCache->apHash[h] = pPage; if( iKey>pCache->iMaxKey ){ @@ -45780,13 +52209,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( } /* -** Implementation of the sqlite3_pcache.xFetch method. +** Implementation of the sqlite3_pcache.xFetch method. ** ** Fetch a page by key value. ** ** Whether or not a new page may be allocated by this function depends on ** the value of the createFlag argument. 0 means do not allocate a new -** page. 1 means allocate a new page if space is easily available. 2 +** page. 1 means allocate a new page if space is easily available. 2 ** means to try really hard to allocate a new page. ** ** For a non-purgeable cache (a cache used as the storage for an in-memory @@ -45797,7 +52226,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ** There are three different approaches to obtaining space for a page, ** depending on the value of parameter createFlag (which may be 0, 1 or 2). ** -** 1. Regardless of the value of createFlag, the cache is searched for a +** 1. Regardless of the value of createFlag, the cache is searched for a ** copy of the requested page. If one is found, it is returned. ** ** 2. If createFlag==0 and the page is not already in the cache, NULL is @@ -45811,13 +52240,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ** PCache1.nMax, or ** ** (b) the number of pages pinned by the cache is greater than -** the sum of nMax for all purgeable caches, less the sum of +** the sum of nMax for all purgeable caches, less the sum of ** nMin for all other purgeable caches, or ** ** 4. If none of the first three conditions apply and the cache is marked ** as purgeable, and if one of the following is true: ** -** (a) The number of pages allocated for the cache is already +** (a) The number of pages allocated for the cache is already ** PCache1.nMax, or ** ** (b) The number of pages allocated for all purgeable caches is @@ -45829,7 +52258,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ** ** then attempt to recycle a page from the LRU list. If it is the right ** size, return the recycled buffer. Otherwise, free the buffer and -** proceed to step 5. +** proceed to step 5. ** ** 5. Otherwise, allocate and return a new page buffer. ** @@ -45839,8 +52268,8 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2( ** invokes the appropriate routine. */ static PgHdr1 *pcache1FetchNoMutex( - sqlite3_pcache *p, - unsigned int iKey, + sqlite3_pcache *p, + unsigned int iKey, int createFlag ){ PCache1 *pCache = (PCache1 *)p; @@ -45855,7 +52284,7 @@ static PgHdr1 *pcache1FetchNoMutex( ** Otherwise (page not in hash and createFlag!=0) continue with ** subsequent steps to try to create the page. */ if( pPage ){ - if( !pPage->isPinned ){ + if( PAGE_IS_UNPINNED(pPage) ){ return pcache1PinPage(pPage); }else{ return pPage; @@ -45869,8 +52298,8 @@ static PgHdr1 *pcache1FetchNoMutex( } #if PCACHE1_MIGHT_USE_GROUP_MUTEX static PgHdr1 *pcache1FetchWithMutex( - sqlite3_pcache *p, - unsigned int iKey, + sqlite3_pcache *p, + unsigned int iKey, int createFlag ){ PCache1 *pCache = (PCache1 *)p; @@ -45884,8 +52313,8 @@ static PgHdr1 *pcache1FetchWithMutex( } #endif static sqlite3_pcache_page *pcache1Fetch( - sqlite3_pcache *p, - unsigned int iKey, + sqlite3_pcache *p, + unsigned int iKey, int createFlag ){ #if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG) @@ -45915,24 +52344,24 @@ static sqlite3_pcache_page *pcache1Fetch( ** Mark a page as unpinned (eligible for asynchronous recycling). */ static void pcache1Unpin( - sqlite3_pcache *p, - sqlite3_pcache_page *pPg, + sqlite3_pcache *p, + sqlite3_pcache_page *pPg, int reuseUnlikely ){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = (PgHdr1 *)pPg; PGroup *pGroup = pCache->pGroup; - + assert( pPage->pCache==pCache ); pcache1EnterMutex(pGroup); - /* It is an error to call this function if the page is already + /* It is an error to call this function if the page is already ** part of the PGroup LRU list. */ - assert( pPage->pLruPrev==0 && pPage->pLruNext==0 ); - assert( pPage->isPinned==1 ); + assert( pPage->pLruNext==0 ); + assert( PAGE_IS_PINNED(pPage) ); - if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){ + if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){ pcache1RemoveFromHash(pPage, 1); }else{ /* Add the page to the PGroup LRU list. */ @@ -45941,14 +52370,13 @@ static void pcache1Unpin( (pPage->pLruNext = *ppFirst)->pLruPrev = pPage; *ppFirst = pPage; pCache->nRecyclable++; - pPage->isPinned = 0; } pcache1LeaveMutex(pCache->pGroup); } /* -** Implementation of the sqlite3_pcache.xRekey method. +** Implementation of the sqlite3_pcache.xRekey method. */ static void pcache1Rekey( sqlite3_pcache *p, @@ -45959,7 +52387,7 @@ static void pcache1Rekey( PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = (PgHdr1 *)pPg; PgHdr1 **pp; - unsigned int h; + unsigned int h; assert( pPage->iKey==iOld ); assert( pPage->pCache==pCache ); @@ -45984,7 +52412,7 @@ static void pcache1Rekey( } /* -** Implementation of the sqlite3_pcache.xTruncate method. +** Implementation of the sqlite3_pcache.xTruncate method. ** ** Discard all unpinned pages in the cache with a page number equal to ** or greater than parameter iLimit. Any pinned pages with a page number @@ -46001,7 +52429,7 @@ static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){ } /* -** Implementation of the sqlite3_pcache.xDestroy method. +** Implementation of the sqlite3_pcache.xDestroy method. ** ** Destroy a cache allocated using pcache1Create(). */ @@ -46067,14 +52495,14 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){ ** by the current thread may be sqlite3_free()ed. ** ** nReq is the number of bytes of memory required. Once this much has -** been released, the function returns. The return value is the total number +** been released, the function returns. The return value is the total number ** of bytes of memory released. */ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){ int nFree = 0; assert( sqlite3_mutex_notheld(pcache1.grp.mutex) ); assert( sqlite3_mutex_notheld(pcache1.mutex) ); - if( sqlite3GlobalConfig.nPage==0 ){ + if( sqlite3GlobalConfig.pPage==0 ){ PgHdr1 *p; pcache1EnterMutex(&pcache1.grp); while( (nReq<0 || nFreeisPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } @@ -46109,10 +52537,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats( PgHdr1 *p; int nRecyclable = 0; for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){ - assert( p->isPinned==0 ); + assert( PAGE_IS_UNPINNED(p) ); nRecyclable++; } - *pnCurrent = pcache1.grp.nCurrentPage; + *pnCurrent = pcache1.grp.nPurgeable; *pnMax = (int)pcache1.grp.nMaxPage; *pnMin = (int)pcache1.grp.nMinPage; *pnRecyclable = nRecyclable; @@ -46158,7 +52586,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats( ** extracts the least value from the RowSet. ** ** The INSERT primitive might allocate additional memory. Memory is -** allocated in chunks so most INSERTs do no allocation. There is an +** allocated in chunks so most INSERTs do no allocation. There is an ** upper bound on the size of allocated memory. No memory is freed ** until DESTROY. ** @@ -46206,7 +52634,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats( ** in the list, pLeft points to the tree, and v is unused. The ** RowSet.pForest value points to the head of this forest list. */ -struct RowSetEntry { +struct RowSetEntry { i64 v; /* ROWID value for this entry */ struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */ struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */ @@ -46247,30 +52675,23 @@ struct RowSet { #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ /* -** Turn bulk memory into a RowSet object. N bytes of memory -** are available at pSpace. The db pointer is used as a memory context -** for any subsequent allocations that need to occur. -** Return a pointer to the new RowSet object. -** -** It must be the case that N is sufficient to make a Rowset. If not -** an assertion fault occurs. -** -** If N is larger than the minimum, use the surplus as an initial -** allocation of entries available to be filled. +** Allocate a RowSet object. Return NULL if a memory allocation +** error occurs. */ -SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){ - RowSet *p; - assert( N >= ROUND8(sizeof(*p)) ); - p = pSpace; - p->pChunk = 0; - p->db = db; - p->pEntry = 0; - p->pLast = 0; - p->pForest = 0; - p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); - p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); - p->rsFlags = ROWSET_SORTED; - p->iBatch = 0; +SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db){ + RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p)); + if( p ){ + int N = sqlite3DbMallocSize(db, p); + p->pChunk = 0; + p->db = db; + p->pEntry = 0; + p->pLast = 0; + p->pForest = 0; + p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); + p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); + p->rsFlags = ROWSET_SORTED; + p->iBatch = 0; + } return p; } @@ -46279,7 +52700,8 @@ SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int ** the RowSet has allocated over its lifetime. This routine is ** the destructor for the RowSet. */ -SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){ +SQLITE_PRIVATE void sqlite3RowSetClear(void *pArg){ + RowSet *p = (RowSet*)pArg; struct RowSetChunk *pChunk, *pNextChunk; for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ pNextChunk = pChunk->pNextChunk; @@ -46293,10 +52715,20 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){ p->rsFlags = ROWSET_SORTED; } +/* +** Deallocate all chunks from a RowSet. This frees all memory that +** the RowSet has allocated over its lifetime. This routine is +** the destructor for the RowSet. +*/ +SQLITE_PRIVATE void sqlite3RowSetDelete(void *pArg){ + sqlite3RowSetClear(pArg); + sqlite3DbFree(((RowSet*)pArg)->db, pArg); +} + /* ** Allocate a new RowSetEntry object that is associated with the ** given RowSet. Return a pointer to the new and completely uninitialized -** objected. +** object. ** ** In an OOM situation, the RowSet.db->mallocFailed flag is set and this ** routine returns NULL. @@ -46354,7 +52786,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){ /* ** Merge two lists of RowSetEntry objects. Remove duplicates. ** -** The input lists are connected via pRight pointers and are +** The input lists are connected via pRight pointers and are ** assumed to each already be in sorted order. */ static struct RowSetEntry *rowSetEntryMerge( @@ -46391,7 +52823,7 @@ static struct RowSetEntry *rowSetEntryMerge( /* ** Sort all elements on the list of RowSetEntry objects into order of ** increasing v. -*/ +*/ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){ unsigned int i; struct RowSetEntry *pNext, *aBucket[40]; @@ -46464,7 +52896,7 @@ static struct RowSetEntry *rowSetNDeepTree( struct RowSetEntry *pLeft; /* Left subtree */ if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/ /* Prevent unnecessary deep recursion when we run out of entries */ - return 0; + return 0; } if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/ /* This branch causes a *balanced* tree to be generated. A valid tree @@ -46572,7 +53004,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 if( p ){ struct RowSetEntry **ppPrevTree = &pRowSet->pForest; if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/ - /* Only sort the current set of entiries if they need it */ + /* Only sort the current set of entries if they need it */ p = rowSetEntrySort(p); } for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ @@ -46634,7 +53066,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 ** ************************************************************************* ** This is the implementation of the page cache subsystem or "pager". -** +** ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file @@ -46657,8 +53089,8 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 ** May you share freely, never taking more than you give. ** ************************************************************************* -** This header file defines the interface to the write-ahead logging -** system. Refer to the comments below and the header comment attached to +** This header file defines the interface to the write-ahead logging +** system. Refer to the comments below and the header comment attached to ** the implementation of each function in log.c for further details. */ @@ -46667,11 +53099,11 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 /* #include "sqliteInt.h" */ -/* Additional values that can be added to the sync_flags argument of -** sqlite3WalFrames(): +/* Macros for extracting appropriate sync flags for either transaction +** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)): */ -#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */ -#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */ +#define WAL_SYNC_FLAGS(X) ((X)&0x03) +#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03) #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 @@ -46697,8 +53129,8 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 #define WAL_SAVEPOINT_NDATA 4 -/* Connection to a write-ahead log (WAL) file. -** There is one object of this type for each pager. +/* Connection to a write-ahead log (WAL) file. +** There is one object of this type for each pager. */ typedef struct Wal Wal; @@ -46709,7 +53141,7 @@ SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 /* Set the limiting size of a WAL file. */ SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64); -/* Used by readers to open (lock) and close (unlock) a snapshot. A +/* Used by readers to open (lock) and close (unlock) a snapshot. A ** snapshot is like a read-transaction. It is the state of the database ** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and ** preserves the current state even if the other threads or processes @@ -46744,7 +53176,7 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData); /* Write a frame or frames to the log. */ SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int); -/* Copy pages from the log to the database file */ +/* Copy pages from the log to the database file */ SQLITE_PRIVATE int sqlite3WalCheckpoint( Wal *pWal, /* Write-ahead log connection */ sqlite3 *db, /* Check this handle's interrupt flag */ @@ -46772,7 +53204,7 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op); /* Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the -** WAL module is using shared-memory, return false. +** WAL module is using shared-memory, return false. */ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); @@ -46780,6 +53212,8 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal); SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal); +SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot); +SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal); #endif #ifdef SQLITE_ENABLE_ZIPVFS @@ -46792,6 +53226,11 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal); /* Return the sqlite3_file object for the WAL file */ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock); +SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db); +#endif + #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ @@ -46812,60 +53251,60 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal); ** ** Definition: A page of the database file is said to be "overwriteable" if ** one or more of the following are true about the page: -** +** ** (a) The original content of the page as it was at the beginning of ** the transaction has been written into the rollback journal and ** synced. -** +** ** (b) The page was a freelist leaf page at the start of the transaction. -** +** ** (c) The page number is greater than the largest page that existed in ** the database file at the start of the transaction. -** +** ** (1) A page of the database file is never overwritten unless one of the ** following are true: -** +** ** (a) The page and all other pages on the same sector are overwriteable. -** +** ** (b) The atomic page write optimization is enabled, and the entire ** transaction other than the update of the transaction sequence ** number consists of a single page change. -** +** ** (2) The content of a page written into the rollback journal exactly matches ** both the content in the database when the rollback journal was written ** and the content in the database at the beginning of the current ** transaction. -** +** ** (3) Writes to the database file are an integer multiple of the page size ** in length and are aligned on a page boundary. -** +** ** (4) Reads from the database file are either aligned on a page boundary and ** an integer multiple of the page size in length or are taken from the ** first 100 bytes of the database file. -** +** ** (5) All writes to the database file are synced prior to the rollback journal ** being deleted, truncated, or zeroed. -** -** (6) If a master journal file is used, then all writes to the database file -** are synced prior to the master journal being deleted. -** +** +** (6) If a super-journal file is used, then all writes to the database file +** are synced prior to the super-journal being deleted. +** ** Definition: Two databases (or the same database at two points it time) ** are said to be "logically equivalent" if they give the same answer to ** all queries. Note in particular the content of freelist leaf ** pages can be changed arbitrarily without affecting the logical equivalence ** of the database. -** +** ** (7) At any time, if any subset, including the empty set and the total set, -** of the unsynced changes to a rollback journal are removed and the +** of the unsynced changes to a rollback journal are removed and the ** journal is rolled back, the resulting database file will be logically ** equivalent to the database file at the beginning of the transaction. -** +** ** (8) When a transaction is rolled back, the xTruncate method of the VFS ** is called to restore the database file to the same size it was at ** the beginning of the transaction. (In some VFSes, the xTruncate ** method is a no-op, but that does not change the fact the SQLite will ** invoke it.) -** +** ** (9) Whenever the database file is modified, at least one bit in the range ** of bytes from 24 through 39 inclusive will be changed prior to releasing ** the EXCLUSIVE lock, thus signaling other connections on the same @@ -46898,14 +53337,14 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ /* ** The following two macros are used within the PAGERTRACE() macros above -** to print out file-descriptors. +** to print out file-descriptors. ** ** PAGERID() takes a pointer to a Pager struct as its argument. The ** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file ** struct as its argument. */ -#define PAGERID(p) ((int)(p->fd)) -#define FILEHANDLEID(fd) ((int)fd) +#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd)) +#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd)) /* ** The Pager.eState variable stores the current 'state' of a pager. A @@ -46919,7 +53358,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** | | | ** | V | ** |<-------WRITER_LOCKED------> ERROR -** | | ^ +** | | ^ ** | V | ** |<------WRITER_CACHEMOD-------->| ** | | | @@ -46931,7 +53370,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** ** List of state transitions and the C [function] that performs each: -** +** ** OPEN -> READER [sqlite3PagerSharedLock] ** READER -> OPEN [pager_unlock] ** @@ -46943,7 +53382,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** WRITER_*** -> ERROR [pager_error] ** ERROR -> OPEN [pager_unlock] -** +** ** ** OPEN: ** @@ -46957,9 +53396,9 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** READER: ** -** In this state all the requirements for reading the database in +** In this state all the requirements for reading the database in ** rollback (non-WAL) mode are met. Unless the pager is (or recently -** was) in exclusive-locking mode, a user-level read transaction is +** was) in exclusive-locking mode, a user-level read transaction is ** open. The database size is known in this state. ** ** A connection running with locking_mode=normal enters this state when @@ -46969,28 +53408,28 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** this state even after the read-transaction is closed. The only way ** a locking_mode=exclusive connection can transition from READER to OPEN ** is via the ERROR state (see below). -** +** ** * A read transaction may be active (but a write-transaction cannot). ** * A SHARED or greater lock is held on the database file. -** * The dbSize variable may be trusted (even if a user-level read +** * The dbSize variable may be trusted (even if a user-level read ** transaction is not active). The dbOrigSize and dbFileSize variables ** may not be trusted at this point. ** * If the database is a WAL database, then the WAL connection is open. -** * Even if a read-transaction is not open, it is guaranteed that +** * Even if a read-transaction is not open, it is guaranteed that ** there is no hot-journal in the file-system. ** ** WRITER_LOCKED: ** ** The pager moves to this state from READER when a write-transaction -** is first opened on the database. In WRITER_LOCKED state, all locks -** required to start a write-transaction are held, but no actual +** is first opened on the database. In WRITER_LOCKED state, all locks +** required to start a write-transaction are held, but no actual ** modifications to the cache or database have taken place. ** -** In rollback mode, a RESERVED or (if the transaction was opened with +** In rollback mode, a RESERVED or (if the transaction was opened with ** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when -** moving to this state, but the journal file is not written to or opened -** to in this state. If the transaction is committed or rolled back while -** in WRITER_LOCKED state, all that is required is to unlock the database +** moving to this state, but the journal file is not written to or opened +** to in this state. If the transaction is committed or rolled back while +** in WRITER_LOCKED state, all that is required is to unlock the database ** file. ** ** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file. @@ -46998,7 +53437,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** is made to obtain an EXCLUSIVE lock on the database file. ** ** * A write transaction is active. -** * If the connection is open in rollback-mode, a RESERVED or greater +** * If the connection is open in rollback-mode, a RESERVED or greater ** lock is held on the database file. ** * If the connection is open in WAL-mode, a WAL write transaction ** is open (i.e. sqlite3WalBeginWriteTransaction() has been successfully @@ -47017,7 +53456,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** * A write transaction is active. ** * A RESERVED or greater lock is held on the database file. -** * The journal file is open and the first header has been written +** * The journal file is open and the first header has been written ** to it, but the header has not been synced to disk. ** * The contents of the page cache have been modified. ** @@ -47030,7 +53469,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** * A write transaction is active. ** * An EXCLUSIVE or greater lock is held on the database file. -** * The journal file is open and the first header has been written +** * The journal file is open and the first header has been written ** and synced to disk. ** * The contents of the page cache have been modified (and possibly ** written to disk). @@ -47042,8 +53481,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD ** state after the entire transaction has been successfully written into the ** database file. In this state the transaction may be committed simply -** by finalizing the journal file. Once in WRITER_FINISHED state, it is -** not possible to modify the database further. At this point, the upper +** by finalizing the journal file. Once in WRITER_FINISHED state, it is +** not possible to modify the database further. At this point, the upper ** layer must either commit or rollback the transaction. ** ** * A write transaction is active. @@ -47051,19 +53490,19 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** * All writing and syncing of journal and database data has finished. ** If no error occurred, all that remains is to finalize the journal to ** commit the transaction. If an error did occur, the caller will need -** to rollback the transaction. +** to rollback the transaction. ** ** ERROR: ** ** The ERROR state is entered when an IO or disk-full error (including -** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it -** difficult to be sure that the in-memory pager state (cache contents, +** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it +** difficult to be sure that the in-memory pager state (cache contents, ** db size etc.) are consistent with the contents of the file-system. ** ** Temporary pager files may enter the ERROR state, but in-memory pagers ** cannot. ** -** For example, if an IO error occurs while performing a rollback, +** For example, if an IO error occurs while performing a rollback, ** the contents of the page-cache may be left in an inconsistent state. ** At this point it would be dangerous to change back to READER state ** (as usually happens after a rollback). Any subsequent readers might @@ -47073,13 +53512,13 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** instead of READER following such an error. ** ** Once it has entered the ERROR state, any attempt to use the pager -** to read or write data returns an error. Eventually, once all +** to read or write data returns an error. Eventually, once all ** outstanding transactions have been abandoned, the pager is able to -** transition back to OPEN state, discarding the contents of the +** transition back to OPEN state, discarding the contents of the ** page-cache and any other in-memory state at the same time. Everything ** is reloaded from disk (and, if necessary, hot-journal rollback peformed) ** when a read-transaction is next opened on the pager (transitioning -** the pager into READER state). At that point the system has recovered +** the pager into READER state). At that point the system has recovered ** from the error. ** ** Specifically, the pager jumps into the ERROR state if: @@ -47095,21 +53534,21 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** memory. ** ** In other cases, the error is returned to the b-tree layer. The b-tree -** layer then attempts a rollback operation. If the error condition +** layer then attempts a rollback operation. If the error condition ** persists, the pager enters the ERROR state via condition (1) above. ** ** Condition (3) is necessary because it can be triggered by a read-only ** statement executed within a transaction. In this case, if the error ** code were simply returned to the user, the b-tree layer would not ** automatically attempt a rollback, as it assumes that an error in a -** read-only statement cannot leave the pager in an internally inconsistent +** read-only statement cannot leave the pager in an internally inconsistent ** state. ** ** * The Pager.errCode variable is set to something other than SQLITE_OK. ** * There are one or more outstanding references to pages (after the ** last reference is dropped the pager should move back to OPEN state). ** * The pager is not an in-memory pager. -** +** ** ** Notes: ** @@ -47119,7 +53558,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** * Normally, a connection open in exclusive mode is never in PAGER_OPEN ** state. There are two exceptions: immediately after exclusive-mode has -** been turned on (and before any read or write transactions are +** been turned on (and before any read or write transactions are ** executed), and when the pager is leaving the "error state". ** ** * See also: assert_pager_state(). @@ -47133,7 +53572,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ #define PAGER_ERROR 6 /* -** The Pager.eLock variable is almost always set to one of the +** The Pager.eLock variable is almost always set to one of the ** following locking-states, according to the lock currently held on ** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK. ** This variable is kept up to date as locks are taken and released by @@ -47148,20 +53587,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** to a less exclusive (lower) value than the lock that is actually held ** at the system level, but it is never set to a more exclusive value. ** -** This is usually safe. If an xUnlock fails or appears to fail, there may +** This is usually safe. If an xUnlock fails or appears to fail, there may ** be a few redundant xLock() calls or a lock may be held for longer than ** required, but nothing really goes wrong. ** ** The exception is when the database file is unlocked as the pager moves -** from ERROR to OPEN state. At this point there may be a hot-journal file +** from ERROR to OPEN state. At this point there may be a hot-journal file ** in the file-system that needs to be rolled back (as part of an OPEN->SHARED ** transition, by the same pager or any other). If the call to xUnlock() ** fails at this point and the pager is left holding an EXCLUSIVE lock, this ** can confuse the call to xCheckReservedLock() call made later as part ** of hot-journal detection. ** -** xCheckReservedLock() is defined as returning true "if there is a RESERVED -** lock held by this process or any others". So xCheckReservedLock may +** xCheckReservedLock() is defined as returning true "if there is a RESERVED +** lock held by this process or any others". So xCheckReservedLock may ** return true because the caller itself is holding an EXCLUSIVE lock (but ** doesn't know it because of a previous error in xUnlock). If this happens ** a hot-journal may be mistaken for a journal being created by an active @@ -47172,32 +53611,18 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It ** is only changed back to a real locking state after a successful call ** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition -** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK +** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK ** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE ** lock on the database file before attempting to roll it back. See function ** PagerSharedLock() for more detail. ** -** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in +** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in ** PAGER_OPEN state. */ #define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1) /* -** A macro used for invoking the codec if there is one -*/ -#ifdef SQLITE_HAS_CODEC -# define CODEC1(P,D,N,X,E) \ - if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; } -# define CODEC2(P,D,N,X,E,O) \ - if( P->xCodec==0 ){ O=(char*)D; }else \ - if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; } -#else -# define CODEC1(P,D,N,X,E) /* NO-OP */ -# define CODEC2(P,D,N,X,E,O) O=(char*)D -#endif - -/* -** The maximum allowed sector size. 64KiB. If the xSectorsize() method +** The maximum allowed sector size. 64KiB. If the xSectorsize() method ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. ** This could conceivably cause corruption following a power failure on ** such a system. This is currently an undocumented limit. @@ -47213,7 +53638,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */ ** ** When a savepoint is created, the PagerSavepoint.iHdrOffset field is ** set to 0. If a journal-header is written into the main journal while -** the savepoint is active, then iHdrOffset is set to the byte offset +** the savepoint is active, then iHdrOffset is set to the byte offset ** immediately following the last journal record written into the main ** journal before the journal-header. This is required during savepoint ** rollback (see pagerPlaybackSavepoint()). @@ -47225,6 +53650,7 @@ struct PagerSavepoint { Bitvec *pInSavepoint; /* Set of pages in this savepoint */ Pgno nOrig; /* Original number of pages in file */ Pgno iSubRec; /* Index of first record in sub-journal */ + int bTruncateOnRelease; /* If stmt journal may be truncated on RELEASE */ #ifndef SQLITE_OMIT_WAL u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */ #endif @@ -47263,44 +53689,44 @@ struct PagerSavepoint { ** ** changeCountDone ** -** This boolean variable is used to make sure that the change-counter -** (the 4-byte header field at byte offset 24 of the database file) is -** not updated more often than necessary. +** This boolean variable is used to make sure that the change-counter +** (the 4-byte header field at byte offset 24 of the database file) is +** not updated more often than necessary. ** -** It is set to true when the change-counter field is updated, which +** It is set to true when the change-counter field is updated, which ** can only happen if an exclusive lock is held on the database file. -** It is cleared (set to false) whenever an exclusive lock is +** It is cleared (set to false) whenever an exclusive lock is ** relinquished on the database file. Each time a transaction is committed, ** The changeCountDone flag is inspected. If it is true, the work of ** updating the change-counter is omitted for the current transaction. ** -** This mechanism means that when running in exclusive mode, a connection +** This mechanism means that when running in exclusive mode, a connection ** need only update the change-counter once, for the first transaction ** committed. ** -** setMaster +** setSuper ** ** When PagerCommitPhaseOne() is called to commit a transaction, it may -** (or may not) specify a master-journal name to be written into the +** (or may not) specify a super-journal name to be written into the ** journal file before it is synced to disk. ** -** Whether or not a journal file contains a master-journal pointer affects -** the way in which the journal file is finalized after the transaction is +** Whether or not a journal file contains a super-journal pointer affects +** the way in which the journal file is finalized after the transaction is ** committed or rolled back when running in "journal_mode=PERSIST" mode. -** If a journal file does not contain a master-journal pointer, it is +** If a journal file does not contain a super-journal pointer, it is ** finalized by overwriting the first journal header with zeroes. If -** it does contain a master-journal pointer the journal file is finalized -** by truncating it to zero bytes, just as if the connection were +** it does contain a super-journal pointer the journal file is finalized +** by truncating it to zero bytes, just as if the connection were ** running in "journal_mode=truncate" mode. ** -** Journal files that contain master journal pointers cannot be finalized +** Journal files that contain super-journal pointers cannot be finalized ** simply by overwriting the first journal-header with zeroes, as the -** master journal pointer could interfere with hot-journal rollback of any +** super-journal pointer could interfere with hot-journal rollback of any ** subsequently interrupted transaction that reuses the journal file. ** ** The flag is cleared as soon as the journal file is finalized (either ** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the -** journal file from being successfully finalized, the setMaster flag +** journal file from being successfully finalized, the setSuper flag ** is cleared anyway (and the pager will move to ERROR state). ** ** doNotSpill @@ -47316,12 +53742,12 @@ struct PagerSavepoint { ** to allocate a new page to prevent the journal file from being written ** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF ** case is a user preference. -** +** ** If the SPILLFLAG_NOSYNC bit is set, writing to the database from ** pagerStress() is permitted, but syncing the journal file is not. ** This flag is set by sqlite3PagerWrite() when the file-system sector-size ** is larger than the database page-size in order to prevent a journal sync -** from happening in between the journalling of two pages on the same sector. +** from happening in between the journalling of two pages on the same sector. ** ** subjInMemory ** @@ -47329,16 +53755,16 @@ struct PagerSavepoint { ** is opened as an in-memory journal file. If false, then in-memory ** sub-journals are only used for in-memory pager files. ** -** This variable is updated by the upper layer each time a new +** This variable is updated by the upper layer each time a new ** write-transaction is opened. ** ** dbSize, dbOrigSize, dbFileSize ** ** Variable dbSize is set to the number of pages in the database file. ** It is valid in PAGER_READER and higher states (all states except for -** OPEN and ERROR). +** OPEN and ERROR). ** -** dbSize is set based on the size of the database file, which may be +** dbSize is set based on the size of the database file, which may be ** larger than the size of the database (the value stored at offset ** 28 of the database header by the btree). If the size of the file ** is not an integer multiple of the page-size, the value stored in @@ -47349,10 +53775,10 @@ struct PagerSavepoint { ** ** During a write-transaction, if pages with page-numbers greater than ** dbSize are modified in the cache, dbSize is updated accordingly. -** Similarly, if the database is truncated using PagerTruncateImage(), +** Similarly, if the database is truncated using PagerTruncateImage(), ** dbSize is updated. ** -** Variables dbOrigSize and dbFileSize are valid in states +** Variables dbOrigSize and dbFileSize are valid in states ** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize ** variable at the start of the transaction. It is used during rollback, ** and to determine whether or not pages need to be journalled before @@ -47361,12 +53787,12 @@ struct PagerSavepoint { ** Throughout a write-transaction, dbFileSize contains the size of ** the file on disk in pages. It is set to a copy of dbSize when the ** write-transaction is first opened, and updated when VFS calls are made -** to write or truncate the database file on disk. +** to write or truncate the database file on disk. ** -** The only reason the dbFileSize variable is required is to suppress -** unnecessary calls to xTruncate() after committing a transaction. If, -** when a transaction is committed, the dbFileSize variable indicates -** that the database file is larger than the database image (Pager.dbSize), +** The only reason the dbFileSize variable is required is to suppress +** unnecessary calls to xTruncate() after committing a transaction. If, +** when a transaction is committed, the dbFileSize variable indicates +** that the database file is larger than the database image (Pager.dbSize), ** pager_truncate() is called. The pager_truncate() call uses xFilesize() ** to measure the database file on disk, and then truncates it if required. ** dbFileSize is not used when rolling back a transaction. In this case @@ -47377,21 +53803,33 @@ struct PagerSavepoint { ** dbHintSize ** ** The dbHintSize variable is used to limit the number of calls made to -** the VFS xFileControl(FCNTL_SIZE_HINT) method. +** the VFS xFileControl(FCNTL_SIZE_HINT) method. ** ** dbHintSize is set to a copy of the dbSize variable when a ** write-transaction is opened (at the same time as dbFileSize and ** dbOrigSize). If the xFileControl(FCNTL_SIZE_HINT) method is called, ** dbHintSize is increased to the number of pages that correspond to the -** size-hint passed to the method call. See pager_write_pagelist() for +** size-hint passed to the method call. See pager_write_pagelist() for ** details. ** ** errCode ** ** The Pager.errCode variable is only ever used in PAGER_ERROR state. It -** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode -** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX +** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode +** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX ** sub-codes. +** +** syncFlags, walSyncFlags +** +** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03). +** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode +** and contains the flags used to sync the checkpoint operations in the +** lower two bits, and sync flags used for transaction commits in the WAL +** file in bits 0x04 and 0x08. In other words, to get the correct sync flags +** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct +** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note +** that with synchronous=NORMAL in WAL mode, transaction commit is not synced +** meaning that the 0x04 and 0x08 bits are both zero. */ struct Pager { sqlite3_vfs *pVfs; /* OS functions to use for IO */ @@ -47401,13 +53839,13 @@ struct Pager { u8 noSync; /* Do not sync the journal if true */ u8 fullSync; /* Do extra syncs of the journal for robustness */ u8 extraSync; /* sync directory after journal delete */ - u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */ - u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */ u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */ + u8 walSyncFlags; /* See description above */ u8 tempFile; /* zFilename is a temporary or immutable file */ u8 noLock; /* Do not lock (except in WAL mode) */ u8 readOnly; /* True for a read-only database */ u8 memDb; /* True to inhibit all file I/O */ + u8 memVfs; /* VFS-implemented memory database */ /************************************************************************** ** The following block contains those class members that change during @@ -47421,7 +53859,7 @@ struct Pager { u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */ u8 eLock; /* Current lock held on database file */ u8 changeCountDone; /* Set after incrementing the change-counter */ - u8 setMaster; /* True if a m-j name has been written to jrnl */ + u8 setSuper; /* Super-jrnl name is written into jrnl */ u8 doNotSpill; /* Do not spill the cache when non-zero */ u8 subjInMemory; /* True to use in-memory sub-journals */ u8 bUseFetch; /* True to use xFetch() */ @@ -47457,25 +53895,19 @@ struct Pager { i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ u32 sectorSize; /* Assumed sector size during rollback */ - int pageSize; /* Number of bytes in a page */ Pgno mxPgno; /* Maximum allowed size of the database */ + i64 pageSize; /* Number of bytes in a page */ i64 journalSizeLimit; /* Size limit for persistent journal files */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ int (*xBusyHandler)(void*); /* Function to call when busy */ void *pBusyHandlerArg; /* Context argument for xBusyHandler */ - int aStat[3]; /* Total cache hits, misses and writes */ + int aStat[4]; /* Total cache hits, misses, writes, spills */ #ifdef SQLITE_TEST int nRead; /* Database pages read */ #endif void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ -#ifdef SQLITE_HAS_CODEC - void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ - void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ - void (*xCodecFree)(void*); /* Destructor for the codec */ - void *pCodec; /* First argument to xCodec... methods */ -#endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ PCache *pPCache; /* Pointer to page cache object */ #ifndef SQLITE_OMIT_WAL @@ -47486,12 +53918,13 @@ struct Pager { /* ** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains -** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS +** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS ** or CACHE_WRITE to sqlite3_db_status(). */ #define PAGER_STAT_HIT 0 #define PAGER_STAT_MISS 1 #define PAGER_STAT_WRITE 2 +#define PAGER_STAT_SPILL 3 /* ** The following global variables hold counters used for @@ -47543,7 +53976,7 @@ static const unsigned char aJournalMagic[] = { #define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8) /* -** The journal header size for this pager. This is usually the same +** The journal header size for this pager. This is usually the same ** size as a single disk sector. See also setSectorSize(). */ #define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize) @@ -47570,11 +54003,6 @@ static const unsigned char aJournalMagic[] = { # define USEFETCH(x) 0 #endif -/* -** The maximum legal page number is (2^31 - 1). -*/ -#define PAGER_MAX_PGNO 2147483647 - /* ** The argument to this macro is a file descriptor (type sqlite3_file*). ** Return 0 if it is not open, or non-zero (but not 1) if it is. @@ -47589,19 +54017,30 @@ static const unsigned char aJournalMagic[] = { */ #define isOpen(pFd) ((pFd)->pMethods!=0) +#ifdef SQLITE_DIRECT_OVERFLOW_READ /* -** Return true if this pager uses a write-ahead log to read page pgno. -** Return false if the pager reads pgno directly from the database. +** Return true if page pgno can be read directly from the database file +** by the b-tree layer. This is the case if: +** +** * the database file is open, +** * there are no dirty pages in the cache, and +** * the desired page is not currently in the wal file. */ -#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_DIRECT_OVERFLOW_READ) -SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){ - u32 iRead = 0; - int rc; - if( pPager->pWal==0 ) return 0; - rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); - return rc || iRead; +SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ + if( pPager->fd->pMethods==0 ) return 0; + if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; +#ifndef SQLITE_OMIT_WAL + if( pPager->pWal ){ + u32 iRead = 0; + int rc; + rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); + return (rc==SQLITE_OK && iRead==0); + } +#endif + return 1; } #endif + #ifndef SQLITE_OMIT_WAL # define pagerUseWal(x) ((x)->pWal!=0) #else @@ -47612,7 +54051,7 @@ SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){ # define pagerBeginReadTransaction(z) SQLITE_OK #endif -#ifndef NDEBUG +#ifndef NDEBUG /* ** Usage: ** @@ -47641,25 +54080,25 @@ static int assert_pager_state(Pager *p){ assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK ); assert( p->tempFile==0 || pPager->changeCountDone ); - /* If the useJournal flag is clear, the journal-mode must be "OFF". + /* If the useJournal flag is clear, the journal-mode must be "OFF". ** And if the journal-mode is "OFF", the journal file must not be open. */ assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal ); assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) ); - /* Check that MEMDB implies noSync. And an in-memory journal. Since - ** this means an in-memory pager performs no IO at all, it cannot encounter - ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing - ** a journal file. (although the in-memory journal implementation may - ** return SQLITE_IOERR_NOMEM while the journal file is being written). It - ** is therefore not possible for an in-memory pager to enter the ERROR + /* Check that MEMDB implies noSync. And an in-memory journal. Since + ** this means an in-memory pager performs no IO at all, it cannot encounter + ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing + ** a journal file. (although the in-memory journal implementation may + ** return SQLITE_IOERR_NOMEM while the journal file is being written). It + ** is therefore not possible for an in-memory pager to enter the ERROR ** state. */ if( MEMDB ){ assert( !isOpen(p->fd) ); assert( p->noSync ); - assert( p->journalMode==PAGER_JOURNALMODE_OFF - || p->journalMode==PAGER_JOURNALMODE_MEMORY + assert( p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_MEMORY ); assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN ); assert( pagerUseWal(p)==0 ); @@ -47693,7 +54132,7 @@ static int assert_pager_state(Pager *p){ assert( pPager->dbSize==pPager->dbOrigSize ); assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); - assert( pPager->setMaster==0 ); + assert( pPager->setSuper==0 ); break; case PAGER_WRITER_CACHEMOD: @@ -47706,9 +54145,9 @@ static int assert_pager_state(Pager *p){ ** to journal_mode=wal. */ assert( p->eLock>=RESERVED_LOCK ); - assert( isOpen(p->jfd) - || p->journalMode==PAGER_JOURNALMODE_OFF - || p->journalMode==PAGER_JOURNALMODE_WAL + assert( isOpen(p->jfd) + || p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_WAL ); } assert( pPager->dbOrigSize==pPager->dbFileSize ); @@ -47720,9 +54159,10 @@ static int assert_pager_state(Pager *p){ assert( pPager->errCode==SQLITE_OK ); assert( !pagerUseWal(pPager) ); assert( p->eLock>=EXCLUSIVE_LOCK ); - assert( isOpen(p->jfd) - || p->journalMode==PAGER_JOURNALMODE_OFF - || p->journalMode==PAGER_JOURNALMODE_WAL + assert( isOpen(p->jfd) + || p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_WAL + || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); assert( pPager->dbOrigSize<=pPager->dbHintSize ); break; @@ -47731,9 +54171,10 @@ static int assert_pager_state(Pager *p){ assert( p->eLock==EXCLUSIVE_LOCK ); assert( pPager->errCode==SQLITE_OK ); assert( !pagerUseWal(pPager) ); - assert( isOpen(p->jfd) - || p->journalMode==PAGER_JOURNALMODE_OFF - || p->journalMode==PAGER_JOURNALMODE_WAL + assert( isOpen(p->jfd) + || p->journalMode==PAGER_JOURNALMODE_OFF + || p->journalMode==PAGER_JOURNALMODE_WAL + || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC) ); break; @@ -47751,7 +54192,7 @@ static int assert_pager_state(Pager *p){ } #endif /* ifndef NDEBUG */ -#ifdef SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* ** Return a pointer to a human readable string in a static buffer ** containing the state of the Pager object passed as an argument. This @@ -47759,8 +54200,12 @@ static int assert_pager_state(Pager *p){ ** to "print *pPager" in gdb: ** ** (gdb) printf "%s", print_pager_state(pPager) +** +** This routine has external linkage in order to suppress compiler warnings +** about an unused function. It is enclosed within SQLITE_DEBUG and so does +** not appear in normal builds. */ -static char *print_pager_state(Pager *p){ +char *print_pager_state(Pager *p){ static char zRet[1024]; sqlite3_snprintf(1024, zRet, @@ -47817,11 +54262,7 @@ static void setGetterMethod(Pager *pPager){ if( pPager->errCode ){ pPager->xGet = getPageError; #if SQLITE_MAX_MMAP_SIZE>0 - }else if( USEFETCH(pPager) -#ifdef SQLITE_HAS_CODEC - && pPager->xCodec==0 -#endif - ){ + }else if( USEFETCH(pPager) ){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ @@ -47846,6 +54287,9 @@ static int subjRequiresPage(PgHdr *pPg){ for(i=0; inSavepoint; i++){ p = &pPager->aSavepoint[i]; if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){ + for(i=i+1; inSavepoint; i++){ + pPager->aSavepoint[i].bTruncateOnRelease = 0; + } return 1; } } @@ -47899,7 +54343,7 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){ ** succeeds, set the Pager.eLock variable to match the (attempted) new lock. ** ** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is -** called, do not modify it. See the comment above the #define of +** called, do not modify it. See the comment above the #define of ** UNKNOWN_LOCK for an explanation of this. */ static int pagerUnlockDb(Pager *pPager, int eLock){ @@ -47916,17 +54360,18 @@ static int pagerUnlockDb(Pager *pPager, int eLock){ } IOTRACE(("UNLOCK %p %d\n", pPager, eLock)) } + pPager->changeCountDone = pPager->tempFile; /* ticket fb3b3024ea238d5c */ return rc; } /* ** Lock the database file to level eLock, which must be either SHARED_LOCK, ** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the -** Pager.eLock variable to the new locking state. +** Pager.eLock variable to the new locking state. ** -** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is -** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK. -** See the comment above the #define of UNKNOWN_LOCK for an explanation +** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is +** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK. +** See the comment above the #define of UNKNOWN_LOCK for an explanation ** of this. */ static int pagerLockDb(Pager *pPager, int eLock){ @@ -47944,34 +54389,47 @@ static int pagerLockDb(Pager *pPager, int eLock){ } /* -** This function determines whether or not the atomic-write optimization -** can be used with this pager. The optimization can be used if: +** This function determines whether or not the atomic-write or +** atomic-batch-write optimizations can be used with this pager. The +** atomic-write optimization can be used if: ** ** (a) the value returned by OsDeviceCharacteristics() indicates that ** a database page may be written atomically, and ** (b) the value returned by OsSectorSize() is less than or equal ** to the page size. ** -** The optimization is also always enabled for temporary files. It is -** an error to call this function if pPager is opened on an in-memory -** database. +** If it can be used, then the value returned is the size of the journal +** file when it contains rollback data for exactly one page. ** -** If the optimization cannot be used, 0 is returned. If it can be used, -** then the value returned is the size of the journal file when it -** contains rollback data for exactly one page. +** The atomic-batch-write optimization can be used if OsDeviceCharacteristics() +** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is +** returned in this case. +** +** If neither optimization can be used, 0 is returned. */ -#ifdef SQLITE_ENABLE_ATOMIC_WRITE static int jrnlBufferSize(Pager *pPager){ assert( !MEMDB ); - if( !pPager->tempFile ){ - int dc; /* Device characteristics */ - int nSector; /* Sector size */ - int szPage; /* Page size */ - assert( isOpen(pPager->fd) ); - dc = sqlite3OsDeviceCharacteristics(pPager->fd); - nSector = pPager->sectorSize; - szPage = pPager->pageSize; +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) + int dc; /* Device characteristics */ + + assert( isOpen(pPager->fd) ); + dc = sqlite3OsDeviceCharacteristics(pPager->fd); +#else + UNUSED_PARAMETER(pPager); +#endif + +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( pPager->dbSize>0 && (dc&SQLITE_IOCAP_BATCH_ATOMIC) ){ + return -1; + } +#endif + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + { + int nSector = pPager->sectorSize; + int szPage = pPager->pageSize; assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); @@ -47981,11 +54439,11 @@ static int jrnlBufferSize(Pager *pPager){ } return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); -} -#else -# define jrnlBufferSize(x) 0 #endif + return 0; +} + /* ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking ** on the cache using a hash function. This is used for testing @@ -48031,71 +54489,73 @@ static void checkPage(PgHdr *pPg){ /* ** When this is called the journal file for pager pPager must be open. -** This function attempts to read a master journal file name from the -** end of the file and, if successful, copies it into memory supplied -** by the caller. See comments above writeMasterJournal() for the format -** used to store a master journal file name at the end of a journal file. +** This function attempts to read a super-journal file name from the +** end of the file and, if successful, copies it into memory supplied +** by the caller. See comments above writeSuperJournal() for the format +** used to store a super-journal file name at the end of a journal file. ** -** zMaster must point to a buffer of at least nMaster bytes allocated by +** zSuper must point to a buffer of at least nSuper bytes allocated by ** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is -** enough space to write the master journal name). If the master journal -** name in the journal is longer than nMaster bytes (including a -** nul-terminator), then this is handled as if no master journal name +** enough space to write the super-journal name). If the super-journal +** name in the journal is longer than nSuper bytes (including a +** nul-terminator), then this is handled as if no super-journal name ** were present in the journal. ** -** If a master journal file name is present at the end of the journal -** file, then it is copied into the buffer pointed to by zMaster. A -** nul-terminator byte is appended to the buffer following the master -** journal file name. +** If a super-journal file name is present at the end of the journal +** file, then it is copied into the buffer pointed to by zSuper. A +** nul-terminator byte is appended to the buffer following the +** super-journal file name. ** -** If it is determined that no master journal file name is present -** zMaster[0] is set to 0 and SQLITE_OK returned. +** If it is determined that no super-journal file name is present +** zSuper[0] is set to 0 and SQLITE_OK returned. ** ** If an error occurs while reading from the journal file, an SQLite ** error code is returned. */ -static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){ +static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){ int rc; /* Return code */ - u32 len; /* Length in bytes of master journal name */ + u32 len; /* Length in bytes of super-journal name */ i64 szJ; /* Total size in bytes of journal file pJrnl */ u32 cksum; /* MJ checksum value read from journal */ u32 u; /* Unsigned loop counter */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ - zMaster[0] = '\0'; + zSuper[0] = '\0'; if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) - || len>=nMaster - || len==0 + || len>=nSuper + || len>szJ-16 + || len==0 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) || memcmp(aMagic, aJournalMagic, 8) - || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len)) + || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len)) ){ return rc; } - /* See if the checksum matches the master journal name */ + /* See if the checksum matches the super-journal name */ for(u=0; ujournalOff, assuming a sector +** Return the offset of the sector boundary at or immediately +** following the value in pPager->journalOff, assuming a sector ** size of pPager->sectorSize bytes. ** ** i.e for a sector size of 512: @@ -48106,7 +54566,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){ ** 512 512 ** 100 512 ** 2000 2048 -** +** */ static i64 journalHdrOffset(Pager *pPager){ i64 offset = 0; @@ -48128,12 +54588,12 @@ static i64 journalHdrOffset(Pager *pPager){ ** ** If doTruncate is non-zero or the Pager.journalSizeLimit variable is ** set to 0, then truncate the journal file to zero bytes in size. Otherwise, -** zero the 28-byte header at the start of the journal file. In either case, -** if the pager is not in no-sync mode, sync the journal file immediately +** zero the 28-byte header at the start of the journal file. In either case, +** if the pager is not in no-sync mode, sync the journal file immediately ** after writing or truncating it. ** ** If Pager.journalSizeLimit is set to a positive, non-zero value, and -** following the truncation or zeroing described above the size of the +** following the truncation or zeroing described above the size of the ** journal file in bytes is larger than this value, then truncate the ** journal file to Pager.journalSizeLimit bytes. The journal file does ** not need to be synced following this operation. @@ -48159,8 +54619,8 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags); } - /* At this point the transaction is committed but the write lock - ** is still held on the file. If there is a size limit configured for + /* At this point the transaction is committed but the write lock + ** is still held on the file. If there is a size limit configured for ** the persistent journal and the journal file currently consumes more ** space than that limit allows for, truncate it now. There is no need ** to sync the file following this operation. @@ -48188,7 +54648,7 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){ ** - 4 bytes: Initial database page count. ** - 4 bytes: Sector size used by the process that wrote this journal. ** - 4 bytes: Database page size. -** +** ** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space. */ static int writeJournalHdr(Pager *pPager){ @@ -48204,8 +54664,8 @@ static int writeJournalHdr(Pager *pPager){ nHeader = JOURNAL_HDR_SZ(pPager); } - /* If there are active savepoints and any of them were created - ** since the most recent journal header was written, update the + /* If there are active savepoints and any of them were created + ** since the most recent journal header was written, update the ** PagerSavepoint.iHdrOffset fields now. */ for(ii=0; iinSavepoint; ii++){ @@ -48216,10 +54676,10 @@ static int writeJournalHdr(Pager *pPager){ pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager); - /* + /* ** Write the nRec Field - the number of page records that follow this ** journal header. Normally, zero is written to this value at this time. - ** After the records are added to the journal (and the journal synced, + ** After the records are added to the journal (and the journal synced, ** if in full-sync mode), the zero is overwritten with the true number ** of records (see syncJournal()). ** @@ -48238,7 +54698,7 @@ static int writeJournalHdr(Pager *pPager){ */ assert( isOpen(pPager->fd) || pPager->noSync ); if( pPager->noSync || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY) - || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) + || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) ){ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); @@ -48246,7 +54706,7 @@ static int writeJournalHdr(Pager *pPager){ memset(zHeader, 0, sizeof(aJournalMagic)+4); } - /* The random check-hash initializer */ + /* The random check-hash initializer */ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); /* The initial database size */ @@ -48265,23 +54725,23 @@ static int writeJournalHdr(Pager *pPager){ memset(&zHeader[sizeof(aJournalMagic)+20], 0, nHeader-(sizeof(aJournalMagic)+20)); - /* In theory, it is only necessary to write the 28 bytes that the - ** journal header consumes to the journal file here. Then increment the - ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next + /* In theory, it is only necessary to write the 28 bytes that the + ** journal header consumes to the journal file here. Then increment the + ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next ** record is written to the following sector (leaving a gap in the file ** that will be implicitly filled in by the OS). ** - ** However it has been discovered that on some systems this pattern can + ** However it has been discovered that on some systems this pattern can ** be significantly slower than contiguously writing data to the file, - ** even if that means explicitly writing data to the block of + ** even if that means explicitly writing data to the block of ** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what - ** is done. + ** is done. ** - ** The loop is required here in case the sector-size is larger than the + ** The loop is required here in case the sector-size is larger than the ** database page size. Since the zHeader buffer is only Pager.pageSize ** bytes in size, more than one call to sqlite3OsWrite() may be required ** to populate the entire journal header sector. - */ + */ for(nWrite=0; rc==SQLITE_OK&&nWritejournalHdr, nHeader)) rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff); @@ -48379,29 +54839,29 @@ static int readJournalHdr( /* Check that the values read from the page-size and sector-size fields ** are within range. To be 'in range', both values need to be a power - ** of two greater than or equal to 512 or 32, and not greater than their + ** of two greater than or equal to 512 or 32, and not greater than their ** respective compile time maximum limits. */ if( iPageSize<512 || iSectorSize<32 || iPageSize>SQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE - || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0 + || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0 ){ - /* If the either the page-size or sector-size in the journal-header is - ** invalid, then the process that wrote the journal-header must have - ** crashed before the header was synced. In this case stop reading + /* If the either the page-size or sector-size in the journal-header is + ** invalid, then the process that wrote the journal-header must have + ** crashed before the header was synced. In this case stop reading ** the journal file here. */ return SQLITE_DONE; } - /* Update the page-size to match the value read from the journal. - ** Use a testcase() macro to make sure that malloc failure within + /* Update the page-size to match the value read from the journal. + ** Use a testcase() macro to make sure that malloc failure within ** PagerSetPagesize() is tested. */ rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1); testcase( rc!=SQLITE_OK ); - /* Update the assumed sector-size to match the value used by + /* Update the assumed sector-size to match the value used by ** the process that created this journal. If this journal was ** created by a process other than this one, then this routine ** is being called from within pager_playback(). The local value @@ -48416,50 +54876,50 @@ static int readJournalHdr( /* -** Write the supplied master journal name into the journal file for pager -** pPager at the current location. The master journal name must be the last +** Write the supplied super-journal name into the journal file for pager +** pPager at the current location. The super-journal name must be the last ** thing written to a journal file. If the pager is in full-sync mode, the ** journal file descriptor is advanced to the next sector boundary before ** anything is written. The format is: ** ** + 4 bytes: PAGER_MJ_PGNO. -** + N bytes: Master journal filename in utf-8. -** + 4 bytes: N (length of master journal name in bytes, no nul-terminator). -** + 4 bytes: Master journal name checksum. +** + N bytes: super-journal filename in utf-8. +** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator). +** + 4 bytes: super-journal name checksum. ** + 8 bytes: aJournalMagic[]. ** -** The master journal page checksum is the sum of the bytes in the master -** journal name, where each byte is interpreted as a signed 8-bit integer. +** The super-journal page checksum is the sum of the bytes in thesuper-journal +** name, where each byte is interpreted as a signed 8-bit integer. ** -** If zMaster is a NULL pointer (occurs for a single database transaction), +** If zSuper is a NULL pointer (occurs for a single database transaction), ** this call is a no-op. */ -static int writeMasterJournal(Pager *pPager, const char *zMaster){ +static int writeSuperJournal(Pager *pPager, const char *zSuper){ int rc; /* Return code */ - int nMaster; /* Length of string zMaster */ + int nSuper; /* Length of string zSuper */ i64 iHdrOff; /* Offset of header in journal file */ i64 jrnlSize; /* Size of journal file on disk */ - u32 cksum = 0; /* Checksum of string zMaster */ + u32 cksum = 0; /* Checksum of string zSuper */ - assert( pPager->setMaster==0 ); + assert( pPager->setSuper==0 ); assert( !pagerUseWal(pPager) ); - if( !zMaster - || pPager->journalMode==PAGER_JOURNALMODE_MEMORY + if( !zSuper + || pPager->journalMode==PAGER_JOURNALMODE_MEMORY || !isOpen(pPager->jfd) ){ return SQLITE_OK; } - pPager->setMaster = 1; + pPager->setSuper = 1; assert( pPager->journalHdr <= pPager->journalOff ); - /* Calculate the length in bytes and the checksum of zMaster */ - for(nMaster=0; zMaster[nMaster]; nMaster++){ - cksum += zMaster[nMaster]; + /* Calculate the length in bytes and the checksum of zSuper */ + for(nSuper=0; zSuper[nSuper]; nSuper++){ + cksum += zSuper[nSuper]; } /* If in full-sync mode, advance to the next disk sector before writing - ** the master journal name. This is in case the previous page written to + ** the super-journal name. This is in case the previous page written to ** the journal has already been synced. */ if( pPager->fullSync ){ @@ -48467,30 +54927,30 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ } iHdrOff = pPager->journalOff; - /* Write the master journal data to the end of the journal file. If + /* Write the super-journal data to the end of the journal file. If ** an error occurs, return the error code to the caller. */ if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager)))) - || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4))) - || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster))) - || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum))) + || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4))) + || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper))) + || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, - iHdrOff+4+nMaster+8))) + iHdrOff+4+nSuper+8))) ){ return rc; } - pPager->journalOff += (nMaster+20); + pPager->journalOff += (nSuper+20); - /* If the pager is in peristent-journal mode, then the physical - ** journal-file may extend past the end of the master-journal name - ** and 8 bytes of magic data just written to the file. This is + /* If the pager is in peristent-journal mode, then the physical + ** journal-file may extend past the end of the super-journal name + ** and 8 bytes of magic data just written to the file. This is ** dangerous because the code to rollback a hot-journal file - ** will not be able to find the master-journal name to determine - ** whether or not the journal is hot. + ** will not be able to find the super-journal name to determine + ** whether or not the journal is hot. ** - ** Easiest thing to do in this scenario is to truncate the journal + ** Easiest thing to do in this scenario is to truncate the journal ** file to the required size. - */ + */ if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize)) && jrnlSize>pPager->journalOff ){ @@ -48512,7 +54972,6 @@ static void pager_reset(Pager *pPager){ ** Return the pPager->iDataVersion value */ SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){ - assert( pPager->eState>PAGER_OPEN ); return pPager->iDataVersion; } @@ -48536,7 +54995,7 @@ static void releaseAllSavepoints(Pager *pPager){ } /* -** Set the bit number pgno in the PagerSavepoint.pInSavepoint +** Set the bit number pgno in the PagerSavepoint.pInSavepoint ** bitvecs of all open savepoints. Return SQLITE_OK if successful ** or SQLITE_NOMEM if a malloc failure occurs. */ @@ -48565,8 +55024,8 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){ ** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is ** closed (if it is open). ** -** If the pager is in ERROR state when this function is called, the -** contents of the pager cache are discarded before switching back to +** If the pager is in ERROR state when this function is called, the +** contents of the pager cache are discarded before switching back to ** the OPEN state. Regardless of whether the pager is in exclusive-mode ** or not, any journal file left in the file-system will be treated ** as a hot-journal and rolled back the next time a read-transaction @@ -48574,9 +55033,9 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){ */ static void pager_unlock(Pager *pPager){ - assert( pPager->eState==PAGER_READER - || pPager->eState==PAGER_OPEN - || pPager->eState==PAGER_ERROR + assert( pPager->eState==PAGER_READER + || pPager->eState==PAGER_OPEN + || pPager->eState==PAGER_ERROR ); sqlite3BitvecDestroy(pPager->pInJournal); @@ -48623,7 +55082,6 @@ static void pager_unlock(Pager *pPager){ ** code is cleared and the cache reset in the block below. */ assert( pPager->errCode || pPager->eState!=PAGER_ERROR ); - pPager->changeCountDone = 0; pPager->eState = PAGER_OPEN; } @@ -48648,23 +55106,23 @@ static void pager_unlock(Pager *pPager){ pPager->journalOff = 0; pPager->journalHdr = 0; - pPager->setMaster = 0; + pPager->setSuper = 0; } /* ** This function is called whenever an IOERR or FULL error that requires ** the pager to transition into the ERROR state may ahve occurred. -** The first argument is a pointer to the pager structure, the second -** the error-code about to be returned by a pager API function. The -** value returned is a copy of the second argument to this function. +** The first argument is a pointer to the pager structure, the second +** the error-code about to be returned by a pager API function. The +** value returned is a copy of the second argument to this function. ** ** If the second argument is SQLITE_FULL, SQLITE_IOERR or one of the ** IOERR sub-codes, the pager enters the ERROR state and the error code ** is stored in Pager.errCode. While the pager remains in the ERROR state, ** all major API calls on the Pager will immediately return Pager.errCode. ** -** The ERROR state indicates that the contents of the pager-cache -** cannot be trusted. This state can be cleared by completely discarding +** The ERROR state indicates that the contents of the pager-cache +** cannot be trusted. This state can be cleared by completely discarding ** the contents of the pager-cache. If a transaction was active when ** the persistent error occurred, then the rollback journal may need ** to be replayed to restore the contents of the database file (as if @@ -48712,27 +55170,27 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){ } /* -** This routine ends a transaction. A transaction is usually ended by -** either a COMMIT or a ROLLBACK operation. This routine may be called +** This routine ends a transaction. A transaction is usually ended by +** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening ** the journal file or writing the very first journal-header of a ** database transaction. -** +** ** This routine is never called in PAGER_ERROR state. If it is called ** in PAGER_NONE or PAGER_SHARED state and the lock held is less ** exclusive than a RESERVED lock, it is a no-op. ** ** Otherwise, any active savepoints are released. ** -** If the journal file is open, then it is "finalized". Once a journal -** file has been finalized it is not possible to use it to roll back a +** If the journal file is open, then it is "finalized". Once a journal +** file has been finalized it is not possible to use it to roll back a ** transaction. Nor will it be considered to be a hot-journal by this ** or any other database connection. Exactly how a journal is finalized ** depends on whether or not the pager is running in exclusive mode and ** the current journal-mode (Pager.journalMode value), as follows: ** ** journalMode==MEMORY -** Journal file descriptor is simply closed. This destroys an +** Journal file descriptor is simply closed. This destroys an ** in-memory journal. ** ** journalMode==TRUNCATE @@ -48752,19 +55210,19 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){ ** journalMode==PERSIST is used instead. ** ** After the journal is finalized, the pager moves to PAGER_READER state. -** If running in non-exclusive rollback mode, the lock on the file is +** If running in non-exclusive rollback mode, the lock on the file is ** downgraded to a SHARED_LOCK. ** ** SQLITE_OK is returned if no error occurs. If an error occurs during ** any of the IO operations to finalize the journal file or unlock the -** database then the IO error code is returned to the user. If the +** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still ** tries to unlock the database file if not in exclusive mode. If the ** unlock operation fails as well, then the first error code related ** to the first error encountered (the journal finalization one) is ** returned. */ -static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ +static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ int rc = SQLITE_OK; /* Error code from journal finalization operation */ int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ @@ -48776,9 +55234,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ ** 1. After a successful hot-journal rollback, it is called with ** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK. ** - ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE + ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE ** lock switches back to locking_mode=normal and then executes a - ** read-transaction, this function is called with eState==PAGER_READER + ** read-transaction, this function is called with eState==PAGER_READER ** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed. */ assert( assert_pager_state(pPager) ); @@ -48788,7 +55246,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ } releaseAllSavepoints(pPager); - assert( isOpen(pPager->jfd) || pPager->pInJournal==0 ); + assert( isOpen(pPager->jfd) || pPager->pInJournal==0 + || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC) + ); if( isOpen(pPager->jfd) ){ assert( !pagerUseWal(pPager) ); @@ -48814,7 +55274,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ - rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile); + rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile); pPager->journalOff = 0; }else{ /* This branch may be executed with Pager.journalMode==MEMORY if @@ -48824,9 +55284,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ */ int bDelete = !pPager->tempFile; assert( sqlite3JournalIsInMemory(pPager->jfd)==0 ); - assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE - || pPager->journalMode==PAGER_JOURNALMODE_MEMORY - || pPager->journalMode==PAGER_JOURNALMODE_WAL + assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE + || pPager->journalMode==PAGER_JOURNALMODE_MEMORY + || pPager->journalMode==PAGER_JOURNALMODE_WAL ); sqlite3OsClose(pPager->jfd); if( bDelete ){ @@ -48859,8 +55319,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ } if( pagerUseWal(pPager) ){ - /* Drop the WAL write-lock, if any. Also, if the connection was in - ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE + /* Drop the WAL write-lock, if any. Also, if the connection was in + ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE ** lock held on the database file. */ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); @@ -48868,7 +55328,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){ /* This branch is taken when committing a transaction in rollback-journal ** mode if the database file on disk is larger than the database image. - ** At this point the journal has been finalized and the transaction + ** At this point the journal has been finalized and the transaction ** successfully committed, but the EXCLUSIVE lock is still held on the ** file. So it is safe to truncate the database file to its minimum ** required size. */ @@ -48876,37 +55336,36 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ rc = pager_truncate(pPager, pPager->dbSize); } - if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){ + if( rc==SQLITE_OK && bCommit ){ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0); if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } - if( !pPager->exclusiveMode + if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); - pPager->changeCountDone = 0; } pPager->eState = PAGER_READER; - pPager->setMaster = 0; + pPager->setSuper = 0; return (rc==SQLITE_OK?rc2:rc); } /* -** Execute a rollback if a transaction is active and unlock the -** database file. +** Execute a rollback if a transaction is active and unlock the +** database file. ** -** If the pager has already entered the ERROR state, do not attempt +** If the pager has already entered the ERROR state, do not attempt ** the rollback at this time. Instead, pager_unlock() is called. The ** call to pager_unlock() will discard all in-memory pages, unlock -** the database file and move the pager back to OPEN state. If this -** means that there is a hot-journal left in the file-system, the next -** connection to obtain a shared lock on the pager (which may be this one) +** the database file and move the pager back to OPEN state. If this +** means that there is a hot-journal left in the file-system, the next +** connection to obtain a shared lock on the pager (which may be this one) ** will roll it back. ** ** If the pager has not already entered the ERROR state, but an IO or -** malloc error occurs during a rollback, then this will itself cause +** malloc error occurs during a rollback, then this will itself cause ** the pager to enter the ERROR state. Which will be cleared by the ** call to pager_unlock(), as described above. */ @@ -48927,10 +55386,10 @@ static void pagerUnlockAndRollback(Pager *pPager){ /* ** Parameter aData must point to a buffer of pPager->pageSize bytes -** of data. Compute and return a checksum based ont the contents of the +** of data. Compute and return a checksum based ont the contents of the ** page of data and the current value of pPager->cksumInit. ** -** This is not a real checksum. It is really just the sum of the +** This is not a real checksum. It is really just the sum of the ** random initial value (pPager->cksumInit) and every 200th byte ** of the page data, starting with byte offset (pPager->pageSize%200). ** Each byte is interpreted as an 8-bit unsigned integer. @@ -48938,8 +55397,8 @@ static void pagerUnlockAndRollback(Pager *pPager){ ** Changing the formula used to compute this checksum results in an ** incompatible journal file format. ** -** If journal corruption occurs due to a power failure, the most likely -** scenario is that one end or the other of the record will be changed. +** If journal corruption occurs due to a power failure, the most likely +** scenario is that one end or the other of the record will be changed. ** It is much less likely that the two ends of the journal record will be ** correct and the middle be corrupt. Thus, this "checksum" scheme, ** though fast and simple, catches the mostly likely kind of corruption. @@ -48954,42 +55413,13 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){ return cksum; } -/* -** Report the current page size and number of reserved bytes back -** to the codec. -*/ -#ifdef SQLITE_HAS_CODEC -static void pagerReportSize(Pager *pPager){ - if( pPager->xCodecSizeChng ){ - pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize, - (int)pPager->nReserve); - } -} -#else -# define pagerReportSize(X) /* No-op if we do not support a codec */ -#endif - -#ifdef SQLITE_HAS_CODEC -/* -** Make sure the number of reserved bits is the same in the destination -** pager as it is in the source. This comes up when a VACUUM changes the -** number of reserved bits to the "optimal" amount. -*/ -SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ - if( pDest->nReserve!=pSrc->nReserve ){ - pDest->nReserve = pSrc->nReserve; - pagerReportSize(pDest); - } -} -#endif - /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. ** The page begins at offset *pOffset into the file. The *pOffset ** value is increased to the start of the next page in the journal. ** -** The main rollback journal uses checksums - the statement journal does +** The main rollback journal uses checksums - the statement journal does ** not. ** ** If the page number of the page record read from the (sub-)journal file @@ -49009,7 +55439,7 @@ SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ ** is successfully read from the (sub-)journal file but appears to be ** corrupted, SQLITE_DONE is returned. Data is considered corrupted in ** two circumstances: -** +** ** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or ** * If the record is being rolled back from the main journal file ** and the checksum field does not match the record content. @@ -49044,7 +55474,7 @@ static int pager_playback_one_page( assert( aData ); /* Temp storage must have already been allocated */ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) ); - /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction + /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction ** or savepoint rollback done at the request of the caller) or this is ** a hot-journal rollback. If it is a hot-journal rollback, the pager ** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback @@ -49096,7 +55526,6 @@ static int pager_playback_one_page( */ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ pPager->nReserve = ((u8*)aData)[20]; - pagerReportSize(pPager); } /* If the pager is in CACHEMOD state, then there must be a copy of this @@ -49111,7 +55540,7 @@ static int pager_playback_one_page( ** assert()able. ** ** If in WRITER_DBMOD, WRITER_FINISHED or OPEN state, then we update the - ** pager cache if it exists and the main file. The page is then marked + ** pager cache if it exists and the main file. The page is then marked ** not dirty. Since this code is only executed in PAGER_OPEN state for ** a hot-journal rollback, it is guaranteed that the page-cache is empty ** if the pager is in OPEN state. @@ -49157,30 +55586,36 @@ static int pager_playback_one_page( i64 ofst = (pgno-1)*(i64)pPager->pageSize; testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); assert( !pagerUseWal(pPager) ); + + /* Write the data read from the journal back into the database file. + ** This is usually safe even for an encrypted database - as the data + ** was encrypted before it was written to the journal file. The exception + ** is if the data was just read from an in-memory sub-journal. In that + ** case it must be encrypted here before it is copied into the database + ** file. */ rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); + if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ - CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); - CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); } }else if( !isMainJrnl && pPg==0 ){ /* If this is a rollback of a savepoint and data was not written to ** the database and the page is not in-memory, there is a potential - ** problem. When the page is next fetched by the b-tree layer, it - ** will be read from the database file, which may or may not be - ** current. + ** problem. When the page is next fetched by the b-tree layer, it + ** will be read from the database file, which may or may not be + ** current. ** ** There are a couple of different ways this can happen. All are quite - ** obscure. When running in synchronous mode, this can only happen + ** obscure. When running in synchronous mode, this can only happen ** if the page is on the free-list at the start of the transaction, then ** populated, then moved using sqlite3PagerMovepage(). ** ** The solution is to add an in-memory page to the cache containing - ** the data just read from the sub-journal. Mark the page as dirty - ** and if the pager requires a journal-sync, then mark the page as + ** the data just read from the sub-journal. Mark the page as dirty + ** and if the pager requires a journal-sync, then mark the page as ** requiring a journal-sync before it is written. */ assert( isSavepnt ); @@ -49214,162 +55649,167 @@ static int pager_playback_one_page( if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } - - /* Decode the page just read from disk */ - CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); sqlite3PcacheRelease(pPg); } return rc; } /* -** Parameter zMaster is the name of a master journal file. A single journal -** file that referred to the master journal file has just been rolled back. -** This routine checks if it is possible to delete the master journal file, +** Parameter zSuper is the name of a super-journal file. A single journal +** file that referred to the super-journal file has just been rolled back. +** This routine checks if it is possible to delete the super-journal file, ** and does so if it is. ** -** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not +** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not ** available for use within this function. ** -** When a master journal file is created, it is populated with the names -** of all of its child journals, one after another, formatted as utf-8 -** encoded text. The end of each child journal file is marked with a -** nul-terminator byte (0x00). i.e. the entire contents of a master journal +** When a super-journal file is created, it is populated with the names +** of all of its child journals, one after another, formatted as utf-8 +** encoded text. The end of each child journal file is marked with a +** nul-terminator byte (0x00). i.e. the entire contents of a super-journal ** file for a transaction involving two databases might be: ** ** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00" ** -** A master journal file may only be deleted once all of its child +** A super-journal file may only be deleted once all of its child ** journals have been rolled back. ** -** This function reads the contents of the master-journal file into +** This function reads the contents of the super-journal file into ** memory and loops through each of the child journal names. For ** each child journal, it checks if: ** ** * if the child journal exists, and if so -** * if the child journal contains a reference to master journal -** file zMaster +** * if the child journal contains a reference to super-journal +** file zSuper ** ** If a child journal can be found that matches both of the criteria ** above, this function returns without doing anything. Otherwise, if -** no such child journal can be found, file zMaster is deleted from +** no such child journal can be found, file zSuper is deleted from ** the file-system using sqlite3OsDelete(). ** ** If an IO error within this function, an error code is returned. This ** function allocates memory by calling sqlite3Malloc(). If an allocation -** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors +** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors ** occur, SQLITE_OK is returned. ** ** TODO: This function allocates a single block of memory to load -** the entire contents of the master journal file. This could be -** a couple of kilobytes or so - potentially larger than the page +** the entire contents of the super-journal file. This could be +** a couple of kilobytes or so - potentially larger than the page ** size. */ -static int pager_delmaster(Pager *pPager, const char *zMaster){ +static int pager_delsuper(Pager *pPager, const char *zSuper){ sqlite3_vfs *pVfs = pPager->pVfs; int rc; /* Return code */ - sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */ + sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */ sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */ - char *zMasterJournal = 0; /* Contents of master journal file */ - i64 nMasterJournal; /* Size of master journal file */ + char *zSuperJournal = 0; /* Contents of super-journal file */ + i64 nSuperJournal; /* Size of super-journal file */ char *zJournal; /* Pointer to one journal within MJ file */ - char *zMasterPtr; /* Space to hold MJ filename from a journal file */ - int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */ + char *zSuperPtr; /* Space to hold super-journal filename */ + char *zFree = 0; /* Free this buffer */ + int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ - /* Allocate space for both the pJournal and pMaster file descriptors. - ** If successful, open the master journal file for reading. + /* Allocate space for both the pJournal and pSuper file descriptors. + ** If successful, open the super-journal file for reading. */ - pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); - pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile); - if( !pMaster ){ + pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); + if( !pSuper ){ rc = SQLITE_NOMEM_BKPT; + pJournal = 0; }else{ - const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL); - rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0); + const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL); + rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0); + pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile); } - if( rc!=SQLITE_OK ) goto delmaster_out; + if( rc!=SQLITE_OK ) goto delsuper_out; - /* Load the entire master journal file into space obtained from - ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain - ** sufficient space (in zMasterPtr) to hold the names of master - ** journal files extracted from regular rollback-journals. + /* Load the entire super-journal file into space obtained from + ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain + ** sufficient space (in zSuperPtr) to hold the names of super-journal + ** files extracted from regular rollback-journals. */ - rc = sqlite3OsFileSize(pMaster, &nMasterJournal); - if( rc!=SQLITE_OK ) goto delmaster_out; - nMasterPtr = pVfs->mxPathname+1; - zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1); - if( !zMasterJournal ){ + rc = sqlite3OsFileSize(pSuper, &nSuperJournal); + if( rc!=SQLITE_OK ) goto delsuper_out; + nSuperPtr = pVfs->mxPathname+1; + zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); + if( !zFree ){ rc = SQLITE_NOMEM_BKPT; - goto delmaster_out; - } - zMasterPtr = &zMasterJournal[nMasterJournal+1]; - rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0); - if( rc!=SQLITE_OK ) goto delmaster_out; - zMasterJournal[nMasterJournal] = 0; - - zJournal = zMasterJournal; - while( (zJournal-zMasterJournal)pageSize bytes). +** DBMOD or OPEN state, this function is a no-op. Otherwise, the size +** of the file is changed to nPage pages (nPage*pPager->pageSize bytes). ** If the file on disk is currently larger than nPage pages, then use the VFS ** xTruncate() method to truncate it. ** -** Or, it might be the case that the file on disk is smaller than -** nPage pages. Some operating system implementations can get confused if -** you try to truncate a file to some size that is larger than it -** currently is, so detect this case and write a single zero byte to +** Or, it might be the case that the file on disk is smaller than +** nPage pages. Some operating system implementations can get confused if +** you try to truncate a file to some size that is larger than it +** currently is, so detect this case and write a single zero byte to ** the end of the new file instead. ** ** If successful, return SQLITE_OK. If an IO error occurs while modifying @@ -49379,9 +55819,9 @@ static int pager_truncate(Pager *pPager, Pgno nPage){ int rc = SQLITE_OK; assert( pPager->eState!=PAGER_ERROR ); assert( pPager->eState!=PAGER_READER ); - - if( isOpen(pPager->fd) - && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) + + if( isOpen(pPager->fd) + && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ i64 currentSize, newSize; int szPage = pPager->pageSize; @@ -49425,9 +55865,9 @@ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){ /* ** Set the value of the Pager.sectorSize variable for the given ** pager based on the value returned by the xSectorSize method -** of the open database file. The sector size will be used -** to determine the size and alignment of journal header and -** master journal pointers within created journal files. +** of the open database file. The sector size will be used +** to determine the size and alignment of journal header and +** super-journal pointers within created journal files. ** ** For temporary files the effective sector size is always 512 bytes. ** @@ -49449,7 +55889,7 @@ static void setSectorSize(Pager *pPager){ assert( isOpen(pPager->fd) || pPager->tempFile ); if( pPager->tempFile - || (sqlite3OsDeviceCharacteristics(pPager->fd) & + || (sqlite3OsDeviceCharacteristics(pPager->fd) & SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0 ){ /* Sector size doesn't matter for temporary files. Also, the file @@ -49463,15 +55903,15 @@ static void setSectorSize(Pager *pPager){ /* ** Playback the journal and thus restore the database file to -** the state it was in before we started making changes. +** the state it was in before we started making changes. ** -** The journal file format is as follows: +** The journal file format is as follows: ** ** (1) 8 byte prefix. A copy of aJournalMagic[]. ** (2) 4 byte big-endian integer which is the number of valid page records ** in the journal. If this value is 0xffffffff, then compute the ** number of page records from the journal size. -** (3) 4 byte big-endian integer which is the initial value for the +** (3) 4 byte big-endian integer which is the initial value for the ** sanity checksum. ** (4) 4 byte integer which is the number of pages to truncate the ** database to during a rollback. @@ -49500,7 +55940,7 @@ static void setSectorSize(Pager *pPager){ ** from the file size. This value is used when the user selects the ** no-sync option for the journal. A power failure could lead to corruption ** in this case. But for things like temporary table (which will be -** deleted when the power is restored) we don't care. +** deleted when the power is restored) we don't care. ** ** If the file opened as the journal file is not a well-formed ** journal file then all pages up to the first corrupted page are rolled @@ -49512,7 +55952,7 @@ static void setSectorSize(Pager *pPager){ ** and an error code is returned. ** ** The isHot parameter indicates that we are trying to rollback a journal -** that might be a hot journal. Or, it could be that the journal is +** that might be a hot journal. Or, it could be that the journal is ** preserved because of JOURNALMODE_PERSIST or JOURNALMODE_TRUNCATE. ** If the journal really is hot, reset the pager cache prior rolling ** back any content. If the journal is merely persistent, no reset is @@ -49526,9 +55966,10 @@ static int pager_playback(Pager *pPager, int isHot){ Pgno mxPg = 0; /* Size of the original file in pages */ int rc; /* Result code of a subroutine */ int res = 1; /* Value returned by sqlite3OsAccess() */ - char *zMaster = 0; /* Name of master journal file if any */ + char *zSuper = 0; /* Name of super-journal file if any */ int needPagerReset; /* True to reset page prior to first page rollback */ int nPlayback = 0; /* Total number of pages restored from journal */ + u32 savedPageSize = pPager->pageSize; /* Figure out how many records are in the journal. Abort early if ** the journal is empty. @@ -49539,8 +55980,8 @@ static int pager_playback(Pager *pPager, int isHot){ goto end_playback; } - /* Read the master journal name from the journal, if it is present. - ** If a master journal file name is specified, but the file is not + /* Read the super-journal name from the journal, if it is present. + ** If a super-journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. ** @@ -49550,21 +55991,21 @@ static int pager_playback(Pager *pPager, int isHot){ ** mxPathname is 512, which is the same as the minimum allowable value ** for pageSize. */ - zMaster = pPager->pTmpSpace; - rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); - if( rc==SQLITE_OK && zMaster[0] ){ - rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); + zSuper = pPager->pTmpSpace; + rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); + if( rc==SQLITE_OK && zSuper[0] ){ + rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); } - zMaster = 0; + zSuper = 0; if( rc!=SQLITE_OK || !res ){ goto end_playback; } pPager->journalOff = 0; needPagerReset = isHot; - /* This loop terminates either when a readJournalHdr() or - ** pager_playback_one_page() call returns SQLITE_DONE or an IO error - ** occurs. + /* This loop terminates either when a readJournalHdr() or + ** pager_playback_one_page() call returns SQLITE_DONE or an IO error + ** occurs. */ while( 1 ){ /* Read the next journal header from the journal file. If there are @@ -49573,7 +56014,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** This indicates nothing more needs to be rolled back. */ rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg); - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; } @@ -49601,7 +56042,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** chunk of the journal contains zero pages to be rolled back. But ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in ** the journal, it means that the journal might contain additional - ** pages that need to be rolled back and that the number of pages + ** pages that need to be rolled back and that the number of pages ** should be computed based on the journal file size. */ if( nRec==0 && !isHot && @@ -49618,9 +56059,12 @@ static int pager_playback(Pager *pPager, int isHot){ goto end_playback; } pPager->dbSize = mxPg; + if( pPager->mxPgnomxPgno = mxPg; + } } - /* Copy original pages out of the journal and back into the + /* Copy original pages out of the journal and back into the ** database file and/or page cache. */ for(u=0; ufd->pMethods ){ - sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0); - } + sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0); #endif - /* If this playback is happening automatically as a result of an IO or - ** malloc error that occurred after the change-counter was updated but - ** before the transaction was committed, then the change-counter - ** modification may just have been reverted. If this happens in exclusive + /* If this playback is happening automatically as a result of an IO or + ** malloc error that occurred after the change-counter was updated but + ** before the transaction was committed, then the change-counter + ** modification may just have been reverted. If this happens in exclusive ** mode, then subsequent transactions performed by the connection will not ** update the change-counter at all. This may lead to cache inconsistency ** problems for other processes at some point in the future. So, just @@ -49681,8 +56126,12 @@ static int pager_playback(Pager *pPager, int isHot){ pPager->changeCountDone = pPager->tempFile; if( rc==SQLITE_OK ){ - zMaster = pPager->pTmpSpace; - rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); + /* Leave 4 bytes of space before the super-journal filename in memory. + ** This is because it may end up being passed to sqlite3OsOpen(), in + ** which case it requires 4 0x00 bytes in memory immediately before + ** the filename. */ + zSuper = &pPager->pTmpSpace[4]; + rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK @@ -49691,14 +56140,16 @@ static int pager_playback(Pager *pPager, int isHot){ rc = sqlite3PagerSync(pPager, 0); } if( rc==SQLITE_OK ){ - rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0); + rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0); testcase( rc!=SQLITE_OK ); } - if( rc==SQLITE_OK && zMaster[0] && res ){ - /* If there was a master journal and this routine will return success, - ** see if it is possible to delete the master journal. + if( rc==SQLITE_OK && zSuper[0] && res ){ + /* If there was a super-journal and this routine will return success, + ** see if it is possible to delete the super-journal. */ - rc = pager_delmaster(pPager, zMaster); + assert( zSuper==&pPager->pTmpSpace[4] ); + memset(&zSuper[-4], 0, 4); + rc = pager_delsuper(pPager, zSuper); testcase( rc!=SQLITE_OK ); } if( isHot && nPlayback ){ @@ -49716,7 +56167,8 @@ static int pager_playback(Pager *pPager, int isHot){ /* -** Read the content for page pPg out of the database file and into +** Read the content for page pPg out of the database file (or out of +** the WAL if that is where the most recent copy if found) into ** pPg->pData. A shared lock or greater must be held on the database ** file before this function is called. ** @@ -49726,30 +56178,33 @@ static int pager_playback(Pager *pPager, int isHot){ ** If an IO error occurs, then the IO error is returned to the caller. ** Otherwise, SQLITE_OK is returned. */ -static int readDbPage(PgHdr *pPg, u32 iFrame){ +static int readDbPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ - Pgno pgno = pPg->pgno; /* Page number to read */ int rc = SQLITE_OK; /* Return code */ - int pgsz = pPager->pageSize; /* Number of bytes to read */ + +#ifndef SQLITE_OMIT_WAL + u32 iFrame = 0; /* Frame of WAL containing pgno */ assert( pPager->eState>=PAGER_READER && !MEMDB ); assert( isOpen(pPager->fd) ); -#ifndef SQLITE_OMIT_WAL + if( pagerUseWal(pPager) ){ + rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); + if( rc ) return rc; + } if( iFrame ){ - /* Try to pull the page from the write-ahead log. */ - rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); + rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData); }else #endif { - i64 iOffset = (pgno-1)*(i64)pPager->pageSize; - rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); + i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize; + rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } - if( pgno==1 ){ + if( pPg->pgno==1 ){ if( rc ){ /* If the read is unsuccessful, set the dbFileVers[] to something ** that will never be a valid file version. dbFileVers[] is a copy @@ -49769,13 +56224,11 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } - CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT); - PAGER_INCR(sqlite3_pager_readdb_count); PAGER_INCR(pPager->nRead); - IOTRACE(("PGIN %p %d\n", pPager, pgno)); + IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno)); PAGERTRACE(("FETCH %d page %d hash(%08x)\n", - PAGERID(pPager), pgno, pager_pagehash(pPg))); + PAGERID(pPager), pPg->pgno, pager_pagehash(pPg))); return rc; } @@ -49790,6 +56243,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){ */ static void pager_write_changecounter(PgHdr *pPg){ u32 change_counter; + if( NEVER(pPg==0) ) return; /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1; @@ -49804,15 +56258,15 @@ static void pager_write_changecounter(PgHdr *pPg){ #ifndef SQLITE_OMIT_WAL /* -** This function is invoked once for each page that has already been +** This function is invoked once for each page that has already been ** written into the log file when a WAL transaction is rolled back. -** Parameter iPg is the page number of said page. The pCtx argument +** Parameter iPg is the page number of said page. The pCtx argument ** is actually a pointer to the Pager structure. ** ** If page iPg is present in the cache, and has no outstanding references, ** it is discarded. Otherwise, if there are one or more outstanding ** references, the page content is reloaded from the database. If the -** attempt to reload content from the database is required and fails, +** attempt to reload content from the database is required and fails, ** return an SQLite error code. Otherwise, SQLITE_OK. */ static int pagerUndoCallback(void *pCtx, Pgno iPg){ @@ -49826,11 +56280,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){ if( sqlite3PcachePageRefcount(pPg)==1 ){ sqlite3PcacheDrop(pPg); }else{ - u32 iFrame = 0; - rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); - if( rc==SQLITE_OK ){ - rc = readDbPage(pPg, iFrame); - } + rc = readDbPage(pPg); if( rc==SQLITE_OK ){ pPager->xReiniter(pPg); } @@ -49842,7 +56292,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){ ** updated as data is copied out of the rollback journal and into the ** database. This is not generally possible with a WAL database, as ** rollback involves simply truncating the log file. Therefore, if one - ** or more frames have already been written to the log (and therefore + ** or more frames have already been written to the log (and therefore ** also copied into the backup databases) as part of this transaction, ** the backups must be restarted. */ @@ -49859,7 +56309,7 @@ static int pagerRollbackWal(Pager *pPager){ PgHdr *pList; /* List of dirty pages to revert */ /* For all pages in the cache that are currently dirty or have already - ** been written (but not committed) to the log file, do one of the + ** been written (but not committed) to the log file, do one of the ** following: ** ** + Discard the cached page (if refcount==0), or @@ -49881,11 +56331,11 @@ static int pagerRollbackWal(Pager *pPager){ ** This function is a wrapper around sqlite3WalFrames(). As well as logging ** the contents of the list of pages headed by pList (connected by pDirty), ** this function notifies any active backup processes that the pages have -** changed. +** changed. ** ** The list of pages passed into this routine is always sorted by page number. ** Hence, if page 1 appears anywhere on the list, it will be the first page. -*/ +*/ static int pagerWalFrames( Pager *pPager, /* Pager object */ PgHdr *pList, /* List of frames to log */ @@ -49926,7 +56376,7 @@ static int pagerWalFrames( pPager->aStat[PAGER_STAT_WRITE] += nList; if( pList->pgno==1 ) pager_write_changecounter(pList); - rc = sqlite3WalFrames(pPager->pWal, + rc = sqlite3WalFrames(pPager->pWal, pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags ); if( rc==SQLITE_OK && pPager->pBackup ){ @@ -50002,7 +56452,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ nPage = sqlite3WalDbsize(pPager->pWal); /* If the number of pages in the database is not available from the - ** WAL sub-system, determine the page counte based on the size of + ** WAL sub-system, determine the page count based on the size of ** the database file. If the size of the database file is not an ** integer multiple of the page-size, round up the result. */ @@ -50041,9 +56491,9 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){ ** Return SQLITE_OK or an error code. ** ** The caller must hold a SHARED lock on the database file to call this -** function. Because an EXCLUSIVE lock on the db file is required to delete -** a WAL on a none-empty database, this ensures there is no race condition -** between the xAccess() below and an xDelete() being executed by some +** function. Because an EXCLUSIVE lock on the db file is required to delete +** a WAL on a none-empty database, this ensures there is no race condition +** between the xAccess() below and an xDelete() being executed by some ** other connection. */ static int pagerOpenWalIfPresent(Pager *pPager){ @@ -50053,23 +56503,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){ if( !pPager->tempFile ){ int isWal; /* True if WAL file exists */ - Pgno nPage; /* Size of the database file */ - - rc = pagerPagecount(pPager, &nPage); - if( rc ) return rc; - if( nPage==0 ){ - rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); - if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK; - isWal = 0; - }else{ - rc = sqlite3OsAccess( - pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal - ); - } + rc = sqlite3OsAccess( + pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal + ); if( rc==SQLITE_OK ){ if( isWal ){ - testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); - rc = sqlite3PagerOpenWal(pPager, 0); + Pgno nPage; /* Size of the database file */ + + rc = pagerPagecount(pPager, &nPage); + if( rc ) return rc; + if( nPage==0 ){ + rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0); + }else{ + testcase( sqlite3PcachePagecount(pPager->pPCache)==0 ); + rc = sqlite3PagerOpenWal(pPager, 0); + } }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ pPager->journalMode = PAGER_JOURNALMODE_DELETE; } @@ -50081,21 +56529,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){ /* ** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback -** the entire master journal file. The case pSavepoint==NULL occurs when -** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction +** the entire super-journal file. The case pSavepoint==NULL occurs when +** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction ** savepoint. ** -** When pSavepoint is not NULL (meaning a non-transaction savepoint is +** When pSavepoint is not NULL (meaning a non-transaction savepoint is ** being rolled back), then the rollback consists of up to three stages, ** performed in the order specified: ** ** * Pages are played back from the main journal starting at byte -** offset PagerSavepoint.iOffset and continuing to +** offset PagerSavepoint.iOffset and continuing to ** PagerSavepoint.iHdrOffset, or to the end of the main journal ** file if PagerSavepoint.iHdrOffset is zero. ** ** * If PagerSavepoint.iHdrOffset is not zero, then pages are played -** back starting from the journal header immediately following +** back starting from the journal header immediately following ** PagerSavepoint.iHdrOffset to the end of the main journal file. ** ** * Pages are then played back from the sub-journal file, starting @@ -50111,7 +56559,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){ ** journal file. There is no need for a bitvec in this case. ** ** In either case, before playback commences the Pager.dbSize variable -** is reset to the value that it held at the start of the savepoint +** is reset to the value that it held at the start of the savepoint ** (or transaction). No page with a page-number greater than this value ** is played back. If one is encountered it is simply skipped. */ @@ -50132,7 +56580,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ } } - /* Set the database size back to the value it was before the savepoint + /* Set the database size back to the value it was before the savepoint ** being reverted was opened. */ pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize; @@ -50185,7 +56633,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ ** test is related to ticket #2565. See the discussion in the ** pager_playback() function for additional information. */ - if( nJRec==0 + if( nJRec==0 && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager)); @@ -50338,20 +56786,17 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags( } if( pPager->noSync ){ pPager->syncFlags = 0; - pPager->ckptSyncFlags = 0; }else if( pgFlags & PAGER_FULLFSYNC ){ pPager->syncFlags = SQLITE_SYNC_FULL; - pPager->ckptSyncFlags = SQLITE_SYNC_FULL; - }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){ - pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->ckptSyncFlags = SQLITE_SYNC_FULL; }else{ pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; } - pPager->walSyncFlags = pPager->syncFlags; + pPager->walSyncFlags = (pPager->syncFlags<<2); if( pPager->fullSync ){ - pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS; + pPager->walSyncFlags |= pPager->syncFlags; + } + if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){ + pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2); } if( pgFlags & PAGER_CACHESPILL ){ pPager->doNotSpill &= ~SPILLFLAG_OFF; @@ -50364,7 +56809,7 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags( /* ** The following global variable is incremented whenever the library ** attempts to open a temporary file. This information is used for -** testing and analysis only. +** testing and analysis only. */ #ifdef SQLITE_TEST SQLITE_API int sqlite3_opentemp_count = 0; @@ -50373,8 +56818,8 @@ SQLITE_API int sqlite3_opentemp_count = 0; /* ** Open a temporary file. ** -** Write the file descriptor into *pFile. Return SQLITE_OK on success -** or some other error code if we fail. The OS will automatically +** Write the file descriptor into *pFile. Return SQLITE_OK on success +** or some other error code if we fail. The OS will automatically ** delete the temporary file when it is closed. ** ** The flags passed to the VFS layer xOpen() call are those specified @@ -50406,9 +56851,9 @@ static int pagerOpentemp( /* ** Set the busy handler function. ** -** The pager invokes the busy-handler if sqlite3OsLock() returns +** The pager invokes the busy-handler if sqlite3OsLock() returns ** SQLITE_BUSY when trying to upgrade from no-lock to a SHARED lock, -** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE +** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE ** lock. It does *not* invoke the busy handler when upgrading from ** SHARED to RESERVED, or when upgrading from SHARED to EXCLUSIVE ** (which occurs during hot-journal rollback). Summary: @@ -50420,37 +56865,35 @@ static int pagerOpentemp( ** SHARED_LOCK -> EXCLUSIVE_LOCK | No ** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes ** -** If the busy-handler callback returns non-zero, the lock is +** If the busy-handler callback returns non-zero, the lock is ** retried. If it returns zero, then the SQLITE_BUSY error is ** returned to the caller of the pager API function. */ -SQLITE_PRIVATE void sqlite3PagerSetBusyhandler( +SQLITE_PRIVATE void sqlite3PagerSetBusyHandler( Pager *pPager, /* Pager object */ int (*xBusyHandler)(void *), /* Pointer to busy-handler function */ void *pBusyHandlerArg /* Argument to pass to xBusyHandler */ ){ + void **ap; pPager->xBusyHandler = xBusyHandler; pPager->pBusyHandlerArg = pBusyHandlerArg; - - if( isOpen(pPager->fd) ){ - void **ap = (void **)&pPager->xBusyHandler; - assert( ((int(*)(void *))(ap[0]))==xBusyHandler ); - assert( ap[1]==pBusyHandlerArg ); - sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap); - } + ap = (void **)&pPager->xBusyHandler; + assert( ((int(*)(void *))(ap[0]))==xBusyHandler ); + assert( ap[1]==pBusyHandlerArg ); + sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap); } /* -** Change the page size used by the Pager object. The new page size +** Change the page size used by the Pager object. The new page size ** is passed in *pPageSize. ** ** If the pager is in the error state when this function is called, it -** is a no-op. The value returned is the error state error code (i.e. +** is a no-op. The value returned is the error state error code (i.e. ** one of SQLITE_IOERR, an SQLITE_IOERR_xxx sub-code or SQLITE_FULL). ** ** Otherwise, if all of the following are true: ** -** * the new page size (value of *pPageSize) is valid (a power +** * the new page size (value of *pPageSize) is valid (a power ** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and ** ** * there are no outstanding page references, and @@ -50460,14 +56903,14 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler( ** ** then the pager object page size is set to *pPageSize. ** -** If the page size is changed, then this function uses sqlite3PagerMalloc() -** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt -** fails, SQLITE_NOMEM is returned and the page size remains unchanged. +** If the page size is changed, then this function uses sqlite3PagerMalloc() +** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt +** fails, SQLITE_NOMEM is returned and the page size remains unchanged. ** In all other cases, SQLITE_OK is returned. ** ** If the page size is not changed, either because one of the enumerated ** conditions above is not true, the pager was in error state when this -** function was called, or because the memory allocation attempt failed, +** function was called, or because the memory allocation attempt failed, ** then *pPageSize is set to the old, retained page size before returning. */ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){ @@ -50477,7 +56920,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR ** function may be called from within PagerOpen(), before the state ** of the Pager object is internally consistent. ** - ** At one point this function returned an error if the pager was in + ** At one point this function returned an error if the pager was in ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that ** there is at least one outstanding page reference, this function ** is a no-op for that case anyhow. @@ -50486,8 +56929,8 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR u32 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); if( (pPager->memDb==0 || pPager->dbSize==0) - && sqlite3PcacheRefCount(pPager->pPCache)==0 - && pageSize && pageSize!=(u32)pPager->pageSize + && sqlite3PcacheRefCount(pPager->pPCache)==0 + && pageSize && pageSize!=(u32)pPager->pageSize ){ char *pNew = NULL; /* New temp space */ i64 nByte = 0; @@ -50496,8 +56939,14 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR rc = sqlite3OsFileSize(pPager->fd, &nByte); } if( rc==SQLITE_OK ){ - pNew = (char *)sqlite3PageMalloc(pageSize); - if( !pNew ) rc = SQLITE_NOMEM_BKPT; + /* 8 bytes of zeroed overrun space is sufficient so that the b-tree + * cell header parser will never run off the end of the allocation */ + pNew = (char *)sqlite3PageMalloc(pageSize+8); + if( !pNew ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + memset(pNew+pageSize, 0, 8); + } } if( rc==SQLITE_OK ){ @@ -50519,7 +56968,6 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); pPager->nReserve = (i16)nReserve; - pagerReportSize(pPager); pagerFixMaplimit(pPager); } return rc; @@ -50538,18 +56986,21 @@ SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){ } /* -** Attempt to set the maximum database page count if mxPage is positive. +** Attempt to set the maximum database page count if mxPage is positive. ** Make no changes if mxPage is zero or negative. And never reduce the ** maximum page count below the current size of the database. ** ** Regardless of mxPage, return the current maximum page count. */ -SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){ +SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){ if( mxPage>0 ){ pPager->mxPgno = mxPage; } assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */ - assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */ + /* assert( pPager->mxPgno>=pPager->dbSize ); */ + /* OP_MaxPgcnt ensures that the parameter passed to this function is not + ** less than the total number of valid pages in the database. But this + ** may be less than Pager.dbSize, and so the assert() above is not valid */ return pPager->mxPgno; } @@ -50579,11 +57030,11 @@ void enable_simulated_io_errors(void){ /* ** Read the first N bytes from the beginning of the file into memory -** that pDest points to. +** that pDest points to. ** ** If the pager was opened on a transient file (zFilename==""), or ** opened on a file less than N bytes in size, the output buffer is -** zeroed and SQLITE_OK returned. The rationale for this is that this +** zeroed and SQLITE_OK returned. The rationale for this is that this ** function is used to read database headers, and a new transient or ** zero sized database has a header than consists entirely of zeroes. ** @@ -50616,7 +57067,7 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned cha ** This function may only be called when a read-transaction is open on ** the pager. It returns the total number of pages in the database. ** -** However, if the file is between 1 and bytes in size, then +** However, if the file is between 1 and bytes in size, then ** this is considered a 1 page file. */ SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){ @@ -50631,19 +57082,19 @@ SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){ ** a similar or greater lock is already held, this function is a no-op ** (returning SQLITE_OK immediately). ** -** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke -** the busy callback if the lock is currently not available. Repeat -** until the busy callback returns false or until the attempt to +** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke +** the busy callback if the lock is currently not available. Repeat +** until the busy callback returns false or until the attempt to ** obtain the lock succeeds. ** ** Return SQLITE_OK on success and an error code if we cannot obtain -** the lock. If the lock is obtained successfully, set the Pager.state +** the lock. If the lock is obtained successfully, set the Pager.state ** variable to locktype before returning. */ static int pager_wait_on_lock(Pager *pPager, int locktype){ int rc; /* Return code */ - /* Check that this is either a no-op (because the requested lock is + /* Check that this is either a no-op (because the requested lock is ** already held), or one of the transitions that the busy-handler ** may be invoked during, according to the comment above ** sqlite3PagerSetBusyhandler(). @@ -50660,15 +57111,14 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ } /* -** Function assertTruncateConstraint(pPager) checks that one of the +** Function assertTruncateConstraint(pPager) checks that one of the ** following is true for all dirty pages currently in the page-cache: ** -** a) The page number is less than or equal to the size of the +** a) The page number is less than or equal to the size of the ** current database image, in pages, OR ** ** b) if the page content were written at this time, it would not -** be necessary to write the current content out to the sub-journal -** (as determined by function subjRequiresPage()). +** be necessary to write the current content out to the sub-journal. ** ** If the condition asserted by this function were not true, and the ** dirty page were to be discarded from the cache via the pagerStress() @@ -50676,15 +57126,23 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){ ** the database file. If a savepoint transaction were rolled back after ** this happened, the correct behavior would be to restore the current ** content of the page. However, since this content is not present in either -** the database file or the portion of the rollback journal and +** the database file or the portion of the rollback journal and ** sub-journal rolled back the content could not be restored and the -** database image would become corrupt. It is therefore fortunate that +** database image would become corrupt. It is therefore fortunate that ** this circumstance cannot arise. */ #if defined(SQLITE_DEBUG) static void assertTruncateConstraintCb(PgHdr *pPg){ + Pager *pPager = pPg->pPager; assert( pPg->flags&PGHDR_DIRTY ); - assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize ); + if( pPg->pgno>pPager->dbSize ){ /* if (a) is false */ + Pgno pgno = pPg->pgno; + int i; + for(i=0; ipPager->nSavepoint; i++){ + PagerSavepoint *p = &pPager->aSavepoint[i]; + assert( p->nOrigpInSavepoint,pgno) ); + } + } } static void assertTruncateConstraint(Pager *pPager){ sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb); @@ -50694,9 +57152,9 @@ static void assertTruncateConstraint(Pager *pPager){ #endif /* -** Truncate the in-memory database file image to nPage pages. This -** function does not actually modify the database file on disk. It -** just sets the internal state of the pager object so that the +** Truncate the in-memory database file image to nPage pages. This +** function does not actually modify the database file on disk. It +** just sets the internal state of the pager object so that the ** truncation will be done when the current transaction is committed. ** ** This function is only called right before committing a transaction. @@ -50705,17 +57163,17 @@ static void assertTruncateConstraint(Pager *pPager){ ** then continue writing to the database. */ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ - assert( pPager->dbSize>=nPage ); + assert( pPager->dbSize>=nPage || CORRUPT_DB ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage; /* At one point the code here called assertTruncateConstraint() to ** ensure that all pages being truncated away by this operation are, - ** if one or more savepoints are open, present in the savepoint + ** if one or more savepoints are open, present in the savepoint ** journal so that they can be restored if the savepoint is rolled ** back. This is no longer necessary as this function is now only - ** called right before committing a transaction. So although the - ** Pager object may still have open savepoints (Pager.nSavepoint!=0), + ** called right before committing a transaction. So although the + ** Pager object may still have open savepoints (Pager.nSavepoint!=0), ** they cannot be rolled back. So the assertTruncateConstraint() call ** is no longer correct. */ } @@ -50727,12 +57185,12 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ ** size of the journal file so that the pager_playback() routine knows ** that the entire journal file has been synced. ** -** Syncing a hot-journal to disk before attempting to roll it back ensures +** Syncing a hot-journal to disk before attempting to roll it back ensures ** that if a power-failure occurs during the rollback, the process that ** attempts rollback following system recovery sees the same journal ** content as this process. ** -** If everything goes as planned, SQLITE_OK is returned. Otherwise, +** If everything goes as planned, SQLITE_OK is returned. Otherwise, ** an SQLite error code. */ static int pagerSyncHotJournal(Pager *pPager){ @@ -50748,7 +57206,7 @@ static int pagerSyncHotJournal(Pager *pPager){ #if SQLITE_MAX_MMAP_SIZE>0 /* -** Obtain a reference to a memory mapped page object for page number pgno. +** Obtain a reference to a memory mapped page object for page number pgno. ** The new object will use the pointer pData, obtained from xFetch(). ** If successful, set *ppPage to point to the new page reference ** and return SQLITE_OK. Otherwise, return an SQLite error code and set @@ -50764,7 +57222,7 @@ static int pagerAcquireMapPage( PgHdr **ppPage /* OUT: Acquired page object */ ){ PgHdr *p; /* Memory mapped page to return */ - + if( pPager->pMmapFreelist ){ *ppPage = p = pPager->pMmapFreelist; pPager->pMmapFreelist = p->pDirty; @@ -50798,7 +57256,7 @@ static int pagerAcquireMapPage( #endif /* -** Release a reference to page pPg. pPg must have been returned by an +** Release a reference to page pPg. pPg must have been returned by an ** earlier call to pagerAcquireMapPage(). */ static void pagerReleaseMapPage(PgHdr *pPg){ @@ -50823,6 +57281,30 @@ static void pagerFreeMapHdrs(Pager *pPager){ } } +/* Verify that the database file has not be deleted or renamed out from +** under the pager. Return SQLITE_OK if the database is still where it ought +** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error +** code from sqlite3OsAccess()) if the database has gone missing. +*/ +static int databaseIsUnmoved(Pager *pPager){ + int bHasMoved = 0; + int rc; + + if( pPager->tempFile ) return SQLITE_OK; + if( pPager->dbSize==0 ) return SQLITE_OK; + assert( pPager->zFilename && pPager->zFilename[0] ); + rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved); + if( rc==SQLITE_NOTFOUND ){ + /* If the HAS_MOVED file-control is unimplemented, assume that the file + ** has not been moved. That is the historical behavior of SQLite: prior to + ** version 3.8.3, it never checked */ + rc = SQLITE_OK; + }else if( rc==SQLITE_OK && bHasMoved ){ + rc = SQLITE_READONLY_DBMOVED; + } + return rc; +} + /* ** Shutdown the page cache. Free all memory and close all files. @@ -50834,13 +57316,12 @@ static void pagerFreeMapHdrs(Pager *pPager){ ** result in a coredump. ** ** This function always succeeds. If a transaction is active an attempt -** is made to roll it back. If an error occurs during the rollback +** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ - u8 *pTmp = (u8 *)pPager->pTmpSpace; - + u8 *pTmp = (u8*)pPager->pTmpSpace; assert( db || pagerUseWal(pPager)==0 ); assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); @@ -50849,19 +57330,25 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL - assert( db || pPager->pWal==0 ); - sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, pPager->pageSize, - (db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp) - ); - pPager->pWal = 0; + { + u8 *a = 0; + assert( db || pPager->pWal==0 ); + if( db && 0==(db->flags & SQLITE_NoCkptOnClose) + && SQLITE_OK==databaseIsUnmoved(pPager) + ){ + a = pTmp; + } + sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); + pPager->pWal = 0; + } #endif pager_reset(pPager); if( MEMDB ){ pager_unlock(pPager); }else{ /* If it is open, sync the journal file before calling UnlockAndRollback. - ** If this is not done, then an unsynced portion of the open journal - ** file may be played back into the database. If a power failure occurs + ** If this is not done, then an unsynced portion of the open journal + ** file may be played back into the database. If a power failure occurs ** while this is happening, the database could become corrupt. ** ** If an error occurs while trying to sync the journal, shift the pager @@ -50883,11 +57370,6 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3OsClose(pPager->fd); sqlite3PageFree(pTmp); sqlite3PcacheClose(pPager->pPCache); - -#ifdef SQLITE_HAS_CODEC - if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); -#endif - assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); @@ -50917,7 +57399,7 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){ ** disk and can be restored in the event of a hot-journal rollback. ** ** If the Pager.noSync flag is set, then this function is a no-op. -** Otherwise, the actions required depend on the journal-mode and the +** Otherwise, the actions required depend on the journal-mode and the ** device characteristics of the file-system, as follows: ** ** * If the journal file is an in-memory journal file, no action need @@ -50929,7 +57411,7 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){ ** been written following it. If the pager is operating in full-sync ** mode, then the journal file is synced before this field is updated. ** -** * If the device does not support the SEQUENTIAL property, then +** * If the device does not support the SEQUENTIAL property, then ** journal file is synced. ** ** Or, in pseudo-code: @@ -50938,11 +57420,11 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){ ** if( NOT SAFE_APPEND ){ ** if( ) xSync(); ** -** } +** } ** if( NOT SEQUENTIAL ) xSync(); ** } ** -** If successful, this routine clears the PGHDR_NEED_SYNC flag of every +** If successful, this routine clears the PGHDR_NEED_SYNC flag of every ** page currently held in memory before returning SQLITE_OK. If an IO ** error is encountered, then the IO error code is returned to the caller. */ @@ -50970,10 +57452,10 @@ static int syncJournal(Pager *pPager, int newHdr){ ** mode, then the journal file may at this point actually be larger ** than Pager.journalOff bytes. If the next thing in the journal ** file happens to be a journal-header (written as part of the - ** previous connection's transaction), and a crash or power-failure - ** occurs after nRec is updated but before this connection writes - ** anything else to the journal file (or commits/rolls back its - ** transaction), then SQLite may become confused when doing the + ** previous connection's transaction), and a crash or power-failure + ** occurs after nRec is updated but before this connection writes + ** anything else to the journal file (or commits/rolls back its + ** transaction), then SQLite may become confused when doing the ** hot-journal rollback following recovery. It may roll back all ** of this connections data, then proceed to rolling back the old, ** out-of-date data that follows it. Database corruption. @@ -50983,7 +57465,7 @@ static int syncJournal(Pager *pPager, int newHdr){ ** byte to the start of it to prevent it from being recognized. ** ** Variable iNextHdrOffset is set to the offset at which this - ** problematic header will occur, if it exists. aMagic is used + ** problematic header will occur, if it exists. aMagic is used ** as a temporary buffer to inspect the first couple of bytes of ** the potential journal header. */ @@ -51010,7 +57492,7 @@ static int syncJournal(Pager *pPager, int newHdr){ ** it as a candidate for rollback. ** ** This is not required if the persistent media supports the - ** SAFE_APPEND property. Because in this case it is not possible + ** SAFE_APPEND property. Because in this case it is not possible ** for garbage data to be appended to the file, the nRec field ** is populated with 0xFFFFFFFF when the journal header is written ** and never needs to be updated. @@ -51030,7 +57512,7 @@ static int syncJournal(Pager *pPager, int newHdr){ if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){ PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager))); IOTRACE(("JSYNC %p\n", pPager)) - rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags| + rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags| (pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0) ); if( rc!=SQLITE_OK ) return rc; @@ -51047,8 +57529,8 @@ static int syncJournal(Pager *pPager, int newHdr){ } } - /* Unless the pager is in noSync mode, the journal file was just - ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on + /* Unless the pager is in noSync mode, the journal file was just + ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on ** all pages. */ sqlite3PcacheClearSyncFlags(pPager->pPCache); @@ -51068,9 +57550,9 @@ static int syncJournal(Pager *pPager, int newHdr){ ** is called. Before writing anything to the database file, this lock ** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained, ** SQLITE_BUSY is returned and no data is written to the database file. -** +** ** If the pager is a temp-file pager and the actual file-system file -** is not yet open, it is created and opened before any data is +** is not yet open, it is created and opened before any data is ** written out. ** ** Once the lock has been upgraded and, if necessary, the file opened, @@ -51085,7 +57567,7 @@ static int syncJournal(Pager *pPager, int newHdr){ ** in Pager.dbFileVers[] is updated to match the new value stored in ** the database file. ** -** If everything is successful, SQLITE_OK is returned. If an IO error +** If everything is successful, SQLITE_OK is returned. If an IO error ** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot ** be obtained, SQLITE_BUSY is returned. */ @@ -51111,7 +57593,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ ** file size will be. */ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); - if( rc==SQLITE_OK + if( rc==SQLITE_OK && pPager->dbHintSizedbSize && (pList->pDirty || pList->pgno>pPager->dbHintSize) ){ @@ -51133,20 +57615,19 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ */ if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){ i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */ - char *pData; /* Data to write */ + char *pData; /* Data to write */ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); - /* Encode the database */ - CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData); + pData = pList->pData; /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); /* If page 1 was just written, update Pager.dbFileVers to match - ** the value now stored in the database file. If writing this - ** page caused the database file to grow, update dbFileSize. + ** the value now stored in the database file. If writing this + ** page caused the database file to grow, update dbFileSize. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers)); @@ -51174,18 +57655,18 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){ } /* -** Ensure that the sub-journal file is open. If it is already open, this +** Ensure that the sub-journal file is open. If it is already open, this ** function is a no-op. ** -** SQLITE_OK is returned if everything goes according to plan. An -** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen() +** SQLITE_OK is returned if everything goes according to plan. An +** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen() ** fails. */ static int openSubJournal(Pager *pPager){ int rc = SQLITE_OK; if( !isOpen(pPager->sjfd) ){ - const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE - | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE + const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; int nStmtSpill = sqlite3Config.nStmtSpill; if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){ @@ -51197,13 +57678,13 @@ static int openSubJournal(Pager *pPager){ } /* -** Append a record of the current state of page pPg to the sub-journal. +** Append a record of the current state of page pPg to the sub-journal. ** ** If successful, set the bit corresponding to pPg->pgno in the bitvecs ** for all open savepoints before returning. ** ** This function returns SQLITE_OK if everything is successful, an IO -** error code if the attempt to write to the sub-journal fails, or +** error code if the attempt to write to the sub-journal fails, or ** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint ** bitvec. */ @@ -51216,9 +57697,9 @@ static int subjournalPage(PgHdr *pPg){ assert( pPager->useJournal ); assert( isOpen(pPager->jfd) || pagerUseWal(pPager) ); assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 ); - assert( pagerUseWal(pPager) - || pageInJournal(pPager, pPg) - || pPg->pgno>pPager->dbOrigSize + assert( pagerUseWal(pPager) + || pageInJournal(pPager, pPg) + || pPg->pgno>pPager->dbOrigSize ); rc = openSubJournal(pPager); @@ -51228,8 +57709,7 @@ static int subjournalPage(PgHdr *pPg){ void *pData = pPg->pData; i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize); char *pData2; - - CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + pData2 = pData; PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno)); rc = write32bits(pPager->sjfd, offset, pPg->pgno); if( rc==SQLITE_OK ){ @@ -51256,14 +57736,14 @@ static int subjournalPageIfRequired(PgHdr *pPg){ ** This function is called by the pcache layer when it has reached some ** soft memory limit. The first argument is a pointer to a Pager object ** (cast as a void*). The pager is always 'purgeable' (not an in-memory -** database). The second argument is a reference to a page that is +** database). The second argument is a reference to a page that is ** currently dirty but has no outstanding references. The page -** is always associated with the Pager object passed as the first +** is always associated with the Pager object passed as the first ** argument. ** ** The job of this function is to make pPg clean by writing its contents ** out to the database file, if possible. This may involve syncing the -** journal file. +** journal file. ** ** If successful, sqlite3PcacheMakeClean() is called on the page and ** SQLITE_OK returned. If an IO error occurs while trying to make the @@ -51288,7 +57768,7 @@ static int pagerStress(void *p, PgHdr *pPg){ ** a rollback or by user request, respectively. ** ** Spilling is also prohibited when in an error state since that could - ** lead to database corruption. In the current implementation it + ** lead to database corruption. In the current implementation it ** is impossible for sqlite3PcacheFetch() to be called with createFlag==3 ** while in the error state, hence it is impossible for this routine to ** be called in the error state. Nevertheless, we include a NEVER() @@ -51305,22 +57785,30 @@ static int pagerStress(void *p, PgHdr *pPg){ return SQLITE_OK; } + pPager->aStat[PAGER_STAT_SPILL]++; pPg->pDirty = 0; if( pagerUseWal(pPager) ){ /* Write a single frame for this page to the log. */ - rc = subjournalPageIfRequired(pPg); + rc = subjournalPageIfRequired(pPg); if( rc==SQLITE_OK ){ rc = pagerWalFrames(pPager, pPg, 0, 0); } }else{ - + +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( pPager->tempFile==0 ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ) return pager_error(pPager, rc); + } +#endif + /* Sync the journal file if required. */ - if( pPg->flags&PGHDR_NEED_SYNC + if( pPg->flags&PGHDR_NEED_SYNC || pPager->eState==PAGER_WRITER_CACHEMOD ){ rc = syncJournal(pPager, 1); } - + /* Write the contents of the page out to the database file. */ if( rc==SQLITE_OK ){ assert( (pPg->flags&PGHDR_NEED_SYNC)==0 ); @@ -51334,7 +57822,7 @@ static int pagerStress(void *p, PgHdr *pPg){ sqlite3PcacheMakeClean(pPg); } - return pager_error(pPager, rc); + return pager_error(pPager, rc); } /* @@ -51365,8 +57853,8 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){ ** The zFilename argument is the path to the database file to open. ** If zFilename is NULL then a randomly-named temporary file is created ** and used as the file to be cached. Temporary files are be deleted -** automatically when they are closed. If zFilename is ":memory:" then -** all information is held in cache. It is never written to disk. +** automatically when they are closed. If zFilename is ":memory:" then +** all information is held in cache. It is never written to disk. ** This can be used to implement an in-memory database. ** ** The nExtra parameter specifies the number of bytes of space allocated @@ -51380,13 +57868,13 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){ ** of the PAGER_* flags. ** ** The vfsFlags parameter is a bitmask to pass to the flags parameter -** of the xOpen() method of the supplied VFS when opening files. +** of the xOpen() method of the supplied VFS when opening files. ** -** If the pager object is allocated and the specified file opened +** If the pager object is allocated and the specified file opened ** successfully, SQLITE_OK is returned and *ppPager set to point to ** the new pager object. If an error occurs, *ppPager is set to NULL ** and error code returned. This function may return SQLITE_NOMEM -** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or +** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or ** various SQLITE_IO_XXX errors. */ SQLITE_PRIVATE int sqlite3PagerOpen( @@ -51403,6 +57891,11 @@ SQLITE_PRIVATE int sqlite3PagerOpen( int rc = SQLITE_OK; /* Return code */ int tempFile = 0; /* True for temp files (incl. in-memory files) */ int memDb = 0; /* True if this is an in-memory file */ +#ifndef SQLITE_OMIT_DESERIALIZE + int memJM = 0; /* Memory journal mode */ +#else +# define memJM 0 +#endif int readOnly = 0; /* True if this is a read-only file */ int journalFileSize; /* Bytes to allocate for each journal fd */ char *zPathname = 0; /* Full path to database file */ @@ -51411,7 +57904,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen( int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ const char *zUri = 0; /* URI args to copy */ - int nUri = 0; /* Number of bytes of URI args at *zUri */ + int nUriByte = 1; /* Number of bytes of URI args at *zUri */ + int nUri = 0; /* Number of URI parameters */ /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). */ @@ -51445,14 +57939,24 @@ SQLITE_PRIVATE int sqlite3PagerOpen( } zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_OK_SYMLINK ){ + if( vfsFlags & SQLITE_OPEN_NOFOLLOW ){ + rc = SQLITE_CANTOPEN_SYMLINK; + }else{ + rc = SQLITE_OK; + } + } + } nPathname = sqlite3Strlen30(zPathname); z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; while( *z ){ - z += sqlite3Strlen30(z)+1; - z += sqlite3Strlen30(z)+1; + z += strlen(z)+1; + z += strlen(z)+1; + nUri++; } - nUri = (int)(&z[1] - zUri); - assert( nUri>=0 ); + nUriByte = (int)(&z[1] - zUri); + assert( nUriByte>=1 ); if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ /* This branch is taken when the journal path required by ** the database being opened will be more than pVfs->mxPathname @@ -51469,7 +57973,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( } /* Allocate memory for the Pager structure, PCache object, the - ** three file descriptors, the database file name and the journal + ** three file descriptors, the database file name and the journal ** file name. The layout in memory is as follows: ** ** Pager object (sizeof(Pager) bytes) @@ -51477,50 +57981,112 @@ SQLITE_PRIVATE int sqlite3PagerOpen( ** Database file handle (pVfs->szOsFile bytes) ** Sub-journal file handle (journalFileSize bytes) ** Main journal file handle (journalFileSize bytes) + ** Ptr back to the Pager (sizeof(Pager*) bytes) + ** \0\0\0\0 database prefix (4 bytes) ** Database file name (nPathname+1 bytes) - ** Journal file name (nPathname+8+1 bytes) + ** URI query parameters (nUriByte bytes) + ** Journal filename (nPathname+8+1 bytes) + ** WAL filename (nPathname+4+1 bytes) + ** \0\0\0 terminator (3 bytes) + ** + ** Some 3rd-party software, over which we have no control, depends on + ** the specific order of the filenames and the \0 separators between them + ** so that it can (for example) find the database filename given the WAL + ** filename without using the sqlite3_filename_database() API. This is a + ** misuse of SQLite and a bug in the 3rd-party software, but the 3rd-party + ** software is in widespread use, so we try to avoid changing the filename + ** order and formatting if possible. In particular, the details of the + ** filename format expected by 3rd-party software should be as follows: + ** + ** - Main Database Path + ** - \0 + ** - Multiple URI components consisting of: + ** - Key + ** - \0 + ** - Value + ** - \0 + ** - \0 + ** - Journal Path + ** - \0 + ** - WAL Path (zWALName) + ** - \0 + ** + ** The sqlite3_create_filename() interface and the databaseFilename() utility + ** that is used by sqlite3_filename_database() and kin also depend on the + ** specific formatting and order of the various filenames, so if the format + ** changes here, be sure to change it there as well. */ pPtr = (u8 *)sqlite3MallocZero( - ROUND8(sizeof(*pPager)) + /* Pager structure */ - ROUND8(pcacheSize) + /* PCache object */ - ROUND8(pVfs->szOsFile) + /* The main db file */ - journalFileSize * 2 + /* The two journal files */ - nPathname + 1 + nUri + /* zFilename */ - nPathname + 8 + 2 /* zJournal */ + ROUND8(sizeof(*pPager)) + /* Pager structure */ + ROUND8(pcacheSize) + /* PCache object */ + ROUND8(pVfs->szOsFile) + /* The main db file */ + journalFileSize * 2 + /* The two journal files */ + sizeof(pPager) + /* Space to hold a pointer */ + 4 + /* Database prefix */ + nPathname + 1 + /* database filename */ + nUriByte + /* query parameters */ + nPathname + 8 + 1 + /* Journal filename */ #ifndef SQLITE_OMIT_WAL - + nPathname + 4 + 2 /* zWal */ + nPathname + 4 + 1 + /* WAL filename */ #endif + 3 /* Terminator */ ); assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); if( !pPtr ){ sqlite3DbFree(0, zPathname); return SQLITE_NOMEM_BKPT; } - pPager = (Pager*)(pPtr); - pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager))); - pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize)); - pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile)); - pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize); - pPager->zFilename = (char*)(pPtr += journalFileSize); + pPager = (Pager*)pPtr; pPtr += ROUND8(sizeof(*pPager)); + pPager->pPCache = (PCache*)pPtr; pPtr += ROUND8(pcacheSize); + pPager->fd = (sqlite3_file*)pPtr; pPtr += ROUND8(pVfs->szOsFile); + pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; + pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize; assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); + memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager); + + /* Fill in the Pager.zFilename and pPager.zQueryParam fields */ + pPtr += 4; /* Skip zero prefix */ + pPager->zFilename = (char*)pPtr; + if( nPathname>0 ){ + memcpy(pPtr, zPathname, nPathname); pPtr += nPathname + 1; + if( zUri ){ + memcpy(pPtr, zUri, nUriByte); pPtr += nUriByte; + }else{ + pPtr++; + } + } + + + /* Fill in Pager.zJournal */ + if( nPathname>0 ){ + pPager->zJournal = (char*)pPtr; + memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; + memcpy(pPtr, "-journal",8); pPtr += 8 + 1; +#ifdef SQLITE_ENABLE_8_3_NAMES + sqlite3FileSuffix3(zFilename,pPager->zJournal); + pPtr = (u8*)(pPager->zJournal + sqlite3Strlen30(pPager->zJournal)+1); +#endif + }else{ + pPager->zJournal = 0; + } - /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ - if( zPathname ){ - assert( nPathname>0 ); - pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri); - memcpy(pPager->zFilename, zPathname, nPathname); - if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri); - memcpy(pPager->zJournal, zPathname, nPathname); - memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2); - sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal); #ifndef SQLITE_OMIT_WAL - pPager->zWal = &pPager->zJournal[nPathname+8+1]; - memcpy(pPager->zWal, zPathname, nPathname); - memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1); - sqlite3FileSuffix3(pPager->zFilename, pPager->zWal); + /* Fill in Pager.zWal */ + if( nPathname>0 ){ + pPager->zWal = (char*)pPtr; + memcpy(pPtr, zPathname, nPathname); pPtr += nPathname; + memcpy(pPtr, "-wal", 4); pPtr += 4 + 1; +#ifdef SQLITE_ENABLE_8_3_NAMES + sqlite3FileSuffix3(zFilename, pPager->zWal); + pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1); #endif - sqlite3DbFree(0, zPathname); + }else{ + pPager->zWal = 0; } +#endif + (void)pPtr; /* Suppress warning about unused pPtr value */ + + if( nPathname ) sqlite3DbFree(0, zPathname); pPager->pVfs = pVfs; pPager->vfsFlags = vfsFlags; @@ -51530,7 +58096,10 @@ SQLITE_PRIVATE int sqlite3PagerOpen( int fout = 0; /* VFS flags returned by xOpen() */ rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); assert( !memDb ); - readOnly = (fout&SQLITE_OPEN_READONLY); +#ifndef SQLITE_OMIT_DESERIALIZE + pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0; +#endif + readOnly = (fout&SQLITE_OPEN_READONLY)!=0; /* If the file was successfully opened for read/write access, ** choose a default page size in case we have to create the @@ -51566,9 +58135,9 @@ SQLITE_PRIVATE int sqlite3PagerOpen( } #endif } - pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0); + pPager->noLock = sqlite3_uri_boolean(pPager->zFilename, "nolock", 0); if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 - || sqlite3_uri_boolean(zFilename, "immutable", 0) ){ + || sqlite3_uri_boolean(pPager->zFilename, "immutable", 0) ){ vfsFlags |= SQLITE_OPEN_READONLY; goto act_like_temp_file; } @@ -51583,7 +58152,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( ** disk and uses an in-memory rollback journal. ** ** This branch also runs for files marked as immutable. - */ + */ act_like_temp_file: tempFile = 1; pPager->eState = PAGER_READER; /* Pretend we already have a lock */ @@ -51592,7 +58161,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( readOnly = (vfsFlags&SQLITE_OPEN_READONLY); } - /* The following call to PagerSetPagesize() serves to set the value of + /* The following call to PagerSetPagesize() serves to set the value of ** Pager.pageSize and to allocate the Pager.pTmpSpace buffer. */ if( rc==SQLITE_OK ){ @@ -51632,10 +58201,10 @@ SQLITE_PRIVATE int sqlite3PagerOpen( /* pPager->state = PAGER_UNLOCK; */ /* pPager->errMask = 0; */ pPager->tempFile = (u8)tempFile; - assert( tempFile==PAGER_LOCKINGMODE_NORMAL + assert( tempFile==PAGER_LOCKINGMODE_NORMAL || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); - pPager->exclusiveMode = (u8)tempFile; + pPager->exclusiveMode = (u8)tempFile; pPager->changeCountDone = pPager->tempFile; pPager->memDb = (u8)memDb; pPager->readOnly = (u8)readOnly; @@ -51646,13 +58215,11 @@ SQLITE_PRIVATE int sqlite3PagerOpen( assert( pPager->extraSync==0 ); assert( pPager->syncFlags==0 ); assert( pPager->walSyncFlags==0 ); - assert( pPager->ckptSyncFlags==0 ); }else{ pPager->fullSync = 1; pPager->extraSync = 0; pPager->syncFlags = SQLITE_SYNC_NORMAL; - pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS; - pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL; + pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2); } /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ @@ -51663,7 +58230,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen( setSectorSize(pPager); if( !useJournal ){ pPager->journalMode = PAGER_JOURNALMODE_OFF; - }else if( memDb ){ + }else if( memDb || memJM ){ pPager->journalMode = PAGER_JOURNALMODE_MEMORY; } /* pPager->xBusyHandler = 0; */ @@ -51677,36 +58244,25 @@ SQLITE_PRIVATE int sqlite3PagerOpen( return SQLITE_OK; } - -/* Verify that the database file has not be deleted or renamed out from -** under the pager. Return SQLITE_OK if the database is still were it ought -** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error -** code from sqlite3OsAccess()) if the database has gone missing. +/* +** Return the sqlite3_file for the main database given the name +** of the corresonding WAL or Journal name as passed into +** xOpen. */ -static int databaseIsUnmoved(Pager *pPager){ - int bHasMoved = 0; - int rc; - - if( pPager->tempFile ) return SQLITE_OK; - if( pPager->dbSize==0 ) return SQLITE_OK; - assert( pPager->zFilename && pPager->zFilename[0] ); - rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved); - if( rc==SQLITE_NOTFOUND ){ - /* If the HAS_MOVED file-control is unimplemented, assume that the file - ** has not been moved. That is the historical behavior of SQLite: prior to - ** version 3.8.3, it never checked */ - rc = SQLITE_OK; - }else if( rc==SQLITE_OK && bHasMoved ){ - rc = SQLITE_READONLY_DBMOVED; +SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){ + Pager *pPager; + while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ + zName--; } - return rc; + pPager = *(Pager**)(zName - 4 - sizeof(Pager*)); + return pPager->fd; } /* ** This function is called after transitioning from PAGER_UNLOCK to ** PAGER_SHARED state. It tests if there is a hot journal present in -** the file-system for the given pager. A hot journal is one that +** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: ** @@ -51721,14 +58277,14 @@ static int databaseIsUnmoved(Pager *pPager){ ** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK ** is returned. ** -** This routine does not check if there is a master journal filename -** at the end of the file. If there is, and that master journal file +** This routine does not check if there is a super-journal filename +** at the end of the file. If there is, and that super-journal file ** does not exist, then the journal file is not really hot. In this ** case this routine will return a false-positive. The pager_playback() -** routine will discover that the journal file is not really hot and -** will not roll it back. +** routine will discover that the journal file is not really hot and +** will not roll it back. ** -** If a hot-journal file is found to exist, *pExists is set to 1 and +** If a hot-journal file is found to exist, *pExists is set to 1 and ** SQLITE_OK returned. If no hot-journal file is present, *pExists is ** set to 0 and SQLITE_OK returned. If an IO error occurs while trying ** to determine whether or not a hot-journal file exists, the IO error @@ -51756,7 +58312,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ int locked = 0; /* True if some process holds a RESERVED lock */ /* Race condition here: Another process might have been holding the - ** the RESERVED lock and have a journal open at the sqlite3OsAccess() + ** the RESERVED lock and have a journal open at the sqlite3OsAccess() ** call above, but then delete the journal and drop the lock before ** we get to the following sqlite3OsCheckReservedLock() call. If that ** is the case, this routine might think there is a hot journal when @@ -51789,7 +58345,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ /* The journal file exists and no other connection has a reserved ** or greater lock on the database file. Now check that there is ** at least one non-zero bytes at the start of the journal file. - ** If there is, then we consider this journal to be hot. If not, + ** If there is, then we consider this journal to be hot. If not, ** it can be ignored. */ if( !jrnlOpen ){ @@ -51839,7 +58395,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){ ** on the database file), then an attempt is made to obtain a ** SHARED lock on the database file. Immediately after obtaining ** the SHARED lock, the file-system is checked for a hot-journal, -** which is played back if present. Following any hot-journal +** which is played back if present. Following any hot-journal ** rollback, the contents of the cache are validated by checking ** the 'change-counter' field of the database file header and ** discarded if they are found to be invalid. @@ -51850,8 +58406,8 @@ static int hasHotJournal(Pager *pPager, int *pExists){ ** the contents of the page cache and rolling back any open journal ** file. ** -** If everything is successful, SQLITE_OK is returned. If an IO error -** occurs while locking the database, checking for a hot-journal file or +** If everything is successful, SQLITE_OK is returned. If an IO error +** occurs while locking the database, checking for a hot-journal file or ** rolling back a journal file, the IO error code is returned. */ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ @@ -51859,7 +58415,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ /* This routine is only called from b-tree and only when there are no ** outstanding pages. This implies that the pager state should either - ** be OPEN or READER. READER is only possible if the pager is or was in + ** be OPEN or READER. READER is only possible if the pager is or was in ** exclusive access mode. */ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); assert( assert_pager_state(pPager) ); @@ -51897,12 +58453,12 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the ** database file, detect the RESERVED lock, and conclude that the - ** database is safe to read while this process is still rolling the + ** database is safe to read while this process is still rolling the ** hot-journal back. - ** + ** ** Because the intermediate RESERVED lock is not requested, any - ** other process attempting to access the database file will get to - ** this point in the code and fail to obtain its own EXCLUSIVE lock + ** other process attempting to access the database file will get to + ** this point in the code and fail to obtain its own EXCLUSIVE lock ** on the database file. ** ** Unless the pager is in locking_mode=exclusive mode, the lock is @@ -51912,21 +58468,21 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ if( rc!=SQLITE_OK ){ goto failed; } - - /* If it is not already open and the file exists on disk, open the - ** journal for read/write access. Write access is required because - ** in exclusive-access mode the file descriptor will be kept open - ** and possibly used for a transaction later on. Also, write-access - ** is usually required to finalize the journal in journal_mode=persist + + /* If it is not already open and the file exists on disk, open the + ** journal for read/write access. Write access is required because + ** in exclusive-access mode the file descriptor will be kept open + ** and possibly used for a transaction later on. Also, write-access + ** is usually required to finalize the journal in journal_mode=persist ** mode (and also for journal_mode=truncate on some systems). ** - ** If the journal does not exist, it usually means that some - ** other connection managed to get in and roll it back before - ** this connection obtained the exclusive lock above. Or, it + ** If the journal does not exist, it usually means that some + ** other connection managed to get in and roll it back before + ** this connection obtained the exclusive lock above. Or, it ** may mean that the pager was in the error-state when this ** function was called and the journal file does not exist. */ - if( !isOpen(pPager->jfd) ){ + if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ sqlite3_vfs * const pVfs = pPager->pVfs; int bExists; /* True if journal file exists */ rc = sqlite3OsAccess( @@ -51943,7 +58499,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ } } } - + /* Playback and delete the journal. Drop the database write ** lock and reacquire the read lock. Purge the cache before ** playing back the hot-journal so that we don't end up with @@ -51968,8 +58524,8 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** or roll back a hot-journal while holding an EXCLUSIVE lock. The ** pager_unlock() routine will be called before returning to unlock ** the file. If the unlock attempt fails, then Pager.eLock must be - ** set to UNKNOWN_LOCK (see the comment above the #define for - ** UNKNOWN_LOCK above for an explanation). + ** set to UNKNOWN_LOCK (see the comment above the #define for + ** UNKNOWN_LOCK above for an explanation). ** ** In order to get pager_unlock() to do this, set Pager.eState to ** PAGER_ERROR now. This is not actually counted as a transition @@ -51977,7 +58533,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** since we know that the same call to pager_unlock() will very ** shortly transition the pager object to the OPEN state. Calling ** assert_pager_state() would fail now, as it should not be possible - ** to be in ERROR state when there are zero outstanding page + ** to be in ERROR state when there are zero outstanding page ** references. */ pager_error(pPager, rc); @@ -52002,24 +58558,19 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** a 32-bit counter that is incremented with each change. The ** other bytes change randomly with each file change when ** a codec is in use. - ** - ** There is a vanishingly small chance that a change will not be + ** + ** There is a vanishingly small chance that a change will not be ** detected. The chance of an undetected change is so small that ** it can be neglected. */ - Pgno nPage = 0; char dbFileVers[sizeof(pPager->dbFileVers)]; - rc = pagerPagecount(pPager, &nPage); - if( rc ) goto failed; - - if( nPage>0 ){ - IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); - rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); - if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ + IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); + rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); + if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_IOERR_SHORT_READ ){ goto failed; } - }else{ memset(dbFileVers, 0, sizeof(dbFileVers)); } @@ -52075,16 +58626,17 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){ ** Except, in locking_mode=EXCLUSIVE when there is nothing to in ** the rollback journal, the unlock is not performed and there is ** nothing to rollback, so this routine is a no-op. -*/ +*/ static void pagerUnlockIfUnused(Pager *pPager){ - if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ + if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){ + assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */ pagerUnlockAndRollback(pPager); } } /* ** The page getter methods each try to acquire a reference to a -** page with page number pgno. If the requested reference is +** page with page number pgno. If the requested reference is ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned. ** ** There are different implementations of the getter method depending @@ -52094,22 +58646,22 @@ static void pagerUnlockIfUnused(Pager *pPager){ ** getPageError() -- Used if the pager is in an error state ** getPageMmap() -- Used if memory-mapped I/O is enabled ** -** If the requested page is already in the cache, it is returned. +** If the requested page is already in the cache, it is returned. ** Otherwise, a new page object is allocated and populated with data ** read from the database file. In some cases, the pcache module may ** choose not to allocate a new page object and may reuse an existing ** object with no outstanding references. ** -** The extra data appended to a page is always initialized to zeros the -** first time a page is loaded into memory. If the page requested is +** The extra data appended to a page is always initialized to zeros the +** first time a page is loaded into memory. If the page requested is ** already in the cache when this function is called, then the extra ** data is left as it was when the page object was last used. ** -** If the database image is smaller than the requested page or if -** the flags parameter contains the PAGER_GET_NOCONTENT bit and the -** requested page is not already stored in the cache, then no -** actual disk read occurs. In this case the memory image of the -** page is initialized to all zeros. +** If the database image is smaller than the requested page or if +** the flags parameter contains the PAGER_GET_NOCONTENT bit and the +** requested page is not already stored in the cache, then no +** actual disk read occurs. In this case the memory image of the +** page is initialized to all zeros. ** ** If PAGER_GET_NOCONTENT is true, it means that we do not care about ** the contents of the page. This occurs in two scenarios: @@ -52175,18 +58727,18 @@ static int getPageNormal( if( pPg->pPager && !noContent ){ /* In this case the pcache already contains an initialized copy of ** the page. Return without further ado. */ - assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) ); + assert( pgno!=PAGER_MJ_PGNO(pPager) ); pPager->aStat[PAGER_STAT_HIT]++; return SQLITE_OK; }else{ - /* The pager cache has created a new page. Its content needs to + /* The pager cache has created a new page. Its content needs to ** be initialized. But first some error checks: ** - ** (1) The maximum page number is 2^31 + ** (*) obsolete. Was: maximum page number is 2^31 ** (2) Never try to fetch the locking page */ - if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){ + if( pgno==PAGER_MJ_PGNO(pPager) ){ rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; } @@ -52201,9 +58753,9 @@ static int getPageNormal( } if( noContent ){ /* Failure to set the bits in the InJournal bit-vectors is benign. - ** It merely means that we might do some extra work to journal a - ** page that does not need to be journaled. Nevertheless, be sure - ** to test the case where a malloc error occurs while trying to set + ** It merely means that we might do some extra work to journal a + ** page that does not need to be journaled. Nevertheless, be sure + ** to test the case where a malloc error occurs while trying to set ** a bit in a bit vector. */ sqlite3BeginBenignMalloc(); @@ -52218,14 +58770,9 @@ static int getPageNormal( memset(pPg->pData, 0, pPager->pageSize); IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ - u32 iFrame = 0; /* Frame to read from WAL file */ - if( pagerUseWal(pPager) ){ - rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); - if( rc!=SQLITE_OK ) goto pager_acquire_err; - } assert( pPg->pPager==pPager ); pPager->aStat[PAGER_STAT_MISS]++; - rc = readDbPage(pPg, iFrame); + rc = readDbPage(pPg); if( rc!=SQLITE_OK ){ goto pager_acquire_err; } @@ -52258,16 +58805,13 @@ static int getPageMMap( /* It is acceptable to use a read-only (mmap) page for any page except ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY - ** flag was specified by the caller. And so long as the db is not a + ** flag was specified by the caller. And so long as the db is not a ** temporary or in-memory database. */ const int bMmapOk = (pgno>1 && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY)) ); assert( USEFETCH(pPager) ); -#ifdef SQLITE_HAS_CODEC - assert( pPager->xCodec==0 ); -#endif /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here ** allows the compiler optimizer to reuse the results of the "pgno>1" @@ -52290,7 +58834,7 @@ static int getPageMMap( } if( bMmapOk && iFrame==0 ){ void *pData = 0; - rc = sqlite3OsFetch(pPager->fd, + rc = sqlite3OsFetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData ); if( rc==SQLITE_OK && pData ){ @@ -52299,7 +58843,7 @@ static int getPageMMap( } if( pPg==0 ){ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); - }else{ + }else{ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData); } if( pPg ){ @@ -52340,18 +58884,19 @@ SQLITE_PRIVATE int sqlite3PagerGet( DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ + /* printf("PAGE %u\n", pgno); fflush(stdout); */ return pPager->xGet(pPager, pgno, ppPage, flags); } /* ** Acquire a page if it is already in the in-memory cache. Do ** not read the page from disk. Return a pointer to the page, -** or 0 if the page is not in cache. +** or 0 if the page is not in cache. ** ** See also sqlite3PagerGet(). The difference between this routine ** and sqlite3PagerGet() is that _get() will go to the disk and read ** in the page if the page is not already in cache. This routine -** returns NULL if the page is not in cache or if a disk I/O error +** returns NULL if the page is not in cache or if a disk I/O error ** has ever happened. */ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ @@ -52368,46 +58913,60 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ /* ** Release a page reference. ** -** If the number of references to the page drop to zero, then the -** page is added to the LRU list. When all references to all pages -** are released, a rollback occurs and the lock on the database is -** removed. +** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be +** used if we know that the page being released is not the last page. +** The btree layer always holds page1 open until the end, so these first +** to routines can be used to release any page other than BtShared.pPage1. +** +** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine +** checks the total number of outstanding pages and if the number of +** pages reaches zero it drops the database lock. */ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){ - Pager *pPager; + TESTONLY( Pager *pPager = pPg->pPager; ) assert( pPg!=0 ); - pPager = pPg->pPager; if( pPg->flags & PGHDR_MMAP ){ + assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */ pagerReleaseMapPage(pPg); }else{ sqlite3PcacheRelease(pPg); } - pagerUnlockIfUnused(pPager); + /* Do not use this routine to release the last reference to page1 */ + assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); } SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){ if( pPg ) sqlite3PagerUnrefNotNull(pPg); } +SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){ + Pager *pPager; + assert( pPg!=0 ); + assert( pPg->pgno==1 ); + assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */ + pPager = pPg->pPager; + sqlite3PcacheRelease(pPg); + pagerUnlockIfUnused(pPager); +} /* ** This function is called at the start of every write transaction. -** There must already be a RESERVED or EXCLUSIVE lock on the database +** There must already be a RESERVED or EXCLUSIVE lock on the database ** file when this routine is called. ** ** Open the journal file for pager pPager and write a journal header ** to the start of it. If there are active savepoints, open the sub-journal -** as well. This function is only used when the journal file is being -** opened to write a rollback log for a transaction. It is not used +** as well. This function is only used when the journal file is being +** opened to write a rollback log for a transaction. It is not used ** when opening a hot journal file to roll it back. ** ** If the journal file is already open (as it may be in exclusive mode), ** then this function just writes a journal header to the start of the -** already open file. +** already open file. ** ** Whether or not the journal file is opened by this function, the ** Pager.pInJournal bitvec structure is allocated. ** -** Return SQLITE_OK if everything is successful. Otherwise, return -** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or +** Return SQLITE_OK if everything is successful. Otherwise, return +** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or ** an IO error code if opening or writing the journal file fails. */ static int pager_open_journal(Pager *pPager){ @@ -52417,7 +58976,7 @@ static int pager_open_journal(Pager *pPager){ assert( pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); assert( pPager->pInJournal==0 ); - + /* If already in the error state, this function is a no-op. But on ** the other hand, this routine is never called if we are already in ** an error state. */ @@ -52428,7 +58987,7 @@ static int pager_open_journal(Pager *pPager){ if( pPager->pInJournal==0 ){ return SQLITE_NOMEM_BKPT; } - + /* Open the journal file if it is not already open. */ if( !isOpen(pPager->jfd) ){ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){ @@ -52444,7 +59003,7 @@ static int pager_open_journal(Pager *pPager){ flags |= SQLITE_OPEN_MAIN_JOURNAL; nSpill = jrnlBufferSize(pPager); } - + /* Verify that the database still has the same name as it did when ** it was originally opened. */ rc = databaseIsUnmoved(pPager); @@ -52456,16 +59015,16 @@ static int pager_open_journal(Pager *pPager){ } assert( rc!=SQLITE_OK || isOpen(pPager->jfd) ); } - - - /* Write the first journal header to the journal file and open + + + /* Write the first journal header to the journal file and open ** the sub-journal if necessary. */ if( rc==SQLITE_OK ){ /* TODO: Check if all of these are really required. */ pPager->nRec = 0; pPager->journalOff = 0; - pPager->setMaster = 0; + pPager->setSuper = 0; pPager->journalHdr = 0; rc = writeJournalHdr(pPager); } @@ -52483,12 +59042,12 @@ static int pager_open_journal(Pager *pPager){ } /* -** Begin a write-transaction on the specified pager object. If a +** Begin a write-transaction on the specified pager object. If a ** write-transaction has already been opened, this function is a no-op. ** ** If the exFlag argument is false, then acquire at least a RESERVED ** lock on the database file. If exFlag is true, then acquire at least -** an EXCLUSIVE lock. If such a lock is already held, no locking +** an EXCLUSIVE lock. If such a lock is already held, no locking ** functions need be called. ** ** If the subjInMemory argument is non-zero, then any sub-journal opened @@ -52496,7 +59055,7 @@ static int pager_open_journal(Pager *pPager){ ** has no effect if the sub-journal is already opened (as it may be when ** running in exclusive mode) or if the transaction does not require a ** sub-journal. If the subjInMemory argument is zero, then any required -** sub-journal is implemented in-memory if pPager is an in-memory database, +** sub-journal is implemented in-memory if pPager is an in-memory database, ** or using a temporary file otherwise. */ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){ @@ -52506,7 +59065,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory assert( pPager->eState>=PAGER_READER && pPager->eStatesubjInMemory = (u8)subjInMemory; - if( ALWAYS(pPager->eState==PAGER_READER) ){ + if( pPager->eState==PAGER_READER ){ assert( pPager->pInJournal==0 ); if( pagerUseWal(pPager) ){ @@ -52544,9 +59103,9 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory ** ** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD ** when it has an open transaction, but never to DBMOD or FINISHED. - ** This is because in those states the code to roll back savepoint - ** transactions may copy data from the sub-journal into the database - ** file as well as into the page cache. Which would be incorrect in + ** This is because in those states the code to roll back savepoint + ** transactions may copy data from the sub-journal into the database + ** file as well as into the page cache. Which would be incorrect in ** WAL mode. */ pPager->eState = PAGER_WRITER_LOCKED; @@ -52581,7 +59140,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); assert( pPager->journalHdr<=pPager->journalOff ); - CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); + pData2 = pPg->pData; cksum = pager_cksum(pPager, (u8*)pData2); /* Even if an IO or diskfull error occurs while journalling the @@ -52600,11 +59159,11 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum); if( rc!=SQLITE_OK ) return rc; - IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, + IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, pPager->journalOff, pPager->pageSize)); PAGER_INCR(sqlite3_pager_writej_count); PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n", - PAGERID(pPager), pPg->pgno, + PAGERID(pPager), pPg->pgno, ((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg))); pPager->journalOff += 8 + pPager->pageSize; @@ -52619,9 +59178,9 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){ } /* -** Mark a single data page as writeable. The page is written into the +** Mark a single data page as writeable. The page is written into the ** main journal or sub-journal as required. If the page is written into -** one of the journals, the corresponding bit is set in the +** one of the journals, the corresponding bit is set in the ** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs ** of any open savepoints as appropriate. */ @@ -52629,7 +59188,7 @@ static int pager_write(PgHdr *pPg){ Pager *pPager = pPg->pPager; int rc = SQLITE_OK; - /* This routine is not called unless a write-transaction has already + /* This routine is not called unless a write-transaction has already ** been started. The journal file may or may not be open at this point. ** It is never called in the ERROR state. */ @@ -52646,7 +59205,7 @@ static int pager_write(PgHdr *pPg){ ** obtained the necessary locks to begin the write-transaction, but the ** rollback journal might not yet be open. Open it now if this is the case. ** - ** This is done before calling sqlite3PcacheMakeDirty() on the page. + ** This is done before calling sqlite3PcacheMakeDirty() on the page. ** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then ** an error might occur and the pager would end up in WRITER_LOCKED state ** with pages marked as dirty in the cache. @@ -52691,7 +59250,7 @@ static int pager_write(PgHdr *pPg){ ** PGHDR_WRITEABLE bit that indicates that the page can be safely modified. */ pPg->flags |= PGHDR_WRITEABLE; - + /* If the statement journal is open and the page is not in it, ** then write the page into the statement journal. */ @@ -52775,7 +59334,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){ } } - /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages + /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages ** starting at pg1, then it needs to be set for all of them. Because ** writing to any of these nPage pages may damage the others, the ** journal file must contain sync()ed copies of all of them @@ -52798,9 +59357,9 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){ } /* -** Mark a data page as writeable. This routine must be called before -** making changes to a page. The caller must check the return value -** of this function and be careful not to change any page data unless +** Mark a data page as writeable. This routine must be called before +** making changes to a page. The caller must check the return value +** of this function and be careful not to change any page data unless ** this routine returns SQLITE_OK. ** ** The difference between this function and pager_write() is that this @@ -52851,13 +59410,13 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){ ** on the given page is unused. The pager marks the page as clean so ** that it does not get written to disk. ** -** Tests show that this optimization can quadruple the speed of large +** Tests show that this optimization can quadruple the speed of large ** DELETE operations. ** ** This optimization cannot be used with a temp-file, as the page may ** have been dirty at the start of the transaction. In that case, if -** memory pressure forces page pPg out of the cache, the data does need -** to be written out to disk so that it may be read back in if the +** memory pressure forces page pPg out of the cache, the data does need +** to be written out to disk so that it may be read back in if the ** current transaction is rolled back. */ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){ @@ -52873,17 +59432,17 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){ } /* -** This routine is called to increment the value of the database file -** change-counter, stored as a 4-byte big-endian integer starting at +** This routine is called to increment the value of the database file +** change-counter, stored as a 4-byte big-endian integer starting at ** byte offset 24 of the pager file. The secondary change counter at ** 92 is also updated, as is the SQLite version number at offset 96. ** ** But this only happens if the pPager->changeCountDone flag is false. ** To avoid excess churning of page 1, the update only happens once. -** See also the pager_write_changecounter() routine that does an +** See also the pager_write_changecounter() routine that does an ** unconditional update of the change counters. ** -** If the isDirectMode flag is zero, then this is done by calling +** If the isDirectMode flag is zero, then this is done by calling ** sqlite3PagerWrite() on page 1, then modifying the contents of the ** page data. In this case the file will be updated when the current ** transaction is committed. @@ -52891,7 +59450,7 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){ ** The isDirectMode flag may only be non-zero if the library was compiled ** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case, ** if isDirect is non-zero, then the database file is updated directly -** by writing an updated version of page 1 using a call to the +** by writing an updated version of page 1 using a call to the ** sqlite3OsWrite() function. */ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ @@ -52930,7 +59489,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ assert( pPgHdr==0 || rc==SQLITE_OK ); /* If page one was fetched successfully, and this function is not - ** operating in direct-mode, make page 1 writable. When not in + ** operating in direct-mode, make page 1 writable. When not in ** direct mode, page 1 is always held in cache and hence the PagerGet() ** above is always successful - hence the ALWAYS on rc==SQLITE_OK. */ @@ -52946,7 +59505,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ if( DIRECT_MODE ){ const void *zBuf; assert( pPager->dbFileSize>0 ); - CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); + zBuf = pPgHdr->pData; if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; @@ -52977,14 +59536,11 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ ** If successful, or if called on a pager for which it is a no-op, this ** function returns SQLITE_OK. Otherwise, an IO error code is returned. */ -SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){ +SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper){ int rc = SQLITE_OK; - - if( isOpen(pPager->fd) ){ - void *pArg = (void*)zMaster; - rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg); - if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; - } + void *pArg = (void*)zSuper; + rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg); + if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; if( rc==SQLITE_OK && !pPager->noSync ){ assert( !MEMDB ); rc = sqlite3OsSync(pPager->fd, pPager->syncFlags); @@ -52994,22 +59550,22 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){ /* ** This function may only be called while a write-transaction is active in -** rollback. If the connection is in WAL mode, this call is a no-op. -** Otherwise, if the connection does not already have an EXCLUSIVE lock on +** rollback. If the connection is in WAL mode, this call is a no-op. +** Otherwise, if the connection does not already have an EXCLUSIVE lock on ** the database file, an attempt is made to obtain one. ** ** If the EXCLUSIVE lock is already held or the attempt to obtain it is ** successful, or the connection is in WAL mode, SQLITE_OK is returned. -** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is +** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is ** returned. */ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){ int rc = pPager->errCode; assert( assert_pager_state(pPager) ); if( rc==SQLITE_OK ){ - assert( pPager->eState==PAGER_WRITER_CACHEMOD - || pPager->eState==PAGER_WRITER_DBMOD - || pPager->eState==PAGER_WRITER_LOCKED + assert( pPager->eState==PAGER_WRITER_CACHEMOD + || pPager->eState==PAGER_WRITER_DBMOD + || pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( 0==pagerUseWal(pPager) ){ @@ -53020,24 +59576,24 @@ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){ } /* -** Sync the database file for the pager pPager. zMaster points to the name -** of a master journal file that should be written into the individual -** journal file. zMaster may be NULL, which is interpreted as no master -** journal (a single database transaction). +** Sync the database file for the pager pPager. zSuper points to the name +** of a super-journal file that should be written into the individual +** journal file. zSuper may be NULL, which is interpreted as no +** super-journal (a single database transaction). ** ** This routine ensures that: ** ** * The database file change-counter is updated, ** * the journal is synced (unless the atomic-write optimization is used), -** * all dirty pages are written to the database file, +** * all dirty pages are written to the database file, ** * the database file is truncated (if required), and -** * the database file synced. +** * the database file synced. ** -** The only thing that remains to commit the transaction is to finalize -** (delete, truncate or zero the first part of) the journal file (or -** delete the master journal file if specified). +** The only thing that remains to commit the transaction is to finalize +** (delete, truncate or zero the first part of) the journal file (or +** delete the super-journal file if specified). ** -** Note that if zMaster==NULL, this does not overwrite a previous value +** Note that if zSuper==NULL, this does not overwrite a previous value ** passed to an sqlite3PagerCommitPhaseOne() call. ** ** If the final parameter - noSync - is true, then the database file itself @@ -53047,7 +59603,7 @@ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){ */ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( Pager *pPager, /* Pager object */ - const char *zMaster, /* If not NULL, the master journal name */ + const char *zSuper, /* If not NULL, the super-journal name */ int noSync /* True to omit the xSync on the db file */ ){ int rc = SQLITE_OK; /* Return code */ @@ -53065,8 +59621,8 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( /* Provide the ability to easily simulate an I/O error during testing */ if( sqlite3FaultSim(400) ) return SQLITE_IOERR; - PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", - pPager->zFilename, zMaster, pPager->dbSize)); + PAGERTRACE(("DATABASE SYNC: File=%s zSuper=%s nSize=%d\n", + pPager->zFilename, zSuper, pPager->dbSize)); /* If no database changes have been made, return early. */ if( pPager->eStatepBackup); }else{ + PgHdr *pList; if( pagerUseWal(pPager) ){ - PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); PgHdr *pPageOne = 0; + pList = sqlite3PcacheDirtyList(pPager->pPCache); if( pList==0 ){ /* Must have at least one page for the WAL commit flag. ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ @@ -53098,13 +59655,28 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( sqlite3PcacheCleanAll(pPager->pPCache); } }else{ + /* The bBatch boolean is true if the batch-atomic-write commit method + ** should be used. No rollback journal is created if batch-atomic-write + ** is enabled. + */ +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + sqlite3_file *fd = pPager->fd; + int bBatch = zSuper==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ + && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) + && !pPager->noSync + && sqlite3JournalIsInMemory(pPager->jfd); +#else +# define bBatch 0 +#endif + +#ifdef SQLITE_ENABLE_ATOMIC_WRITE /* The following block updates the change-counter. Exactly how it ** does this depends on whether or not the atomic-update optimization - ** was enabled at compile time, and if this transaction meets the - ** runtime criteria to use the operation: + ** was enabled at compile time, and if this transaction meets the + ** runtime criteria to use the operation: ** ** * The file-system supports the atomic-write property for - ** blocks of size page-size, and + ** blocks of size page-size, and ** * This commit is not part of a multi-file transaction, and ** * Exactly one page has been modified and store in the journal file. ** @@ -53114,71 +59686,108 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( ** is not applicable to this transaction, call sqlite3JournalCreate() ** to make sure the journal file has actually been created, then call ** pager_incr_changecounter() to update the change-counter in indirect - ** mode. + ** mode. ** ** Otherwise, if the optimization is both enabled and applicable, ** then call pager_incr_changecounter() to update the change-counter ** in 'direct' mode. In this case the journal file will never be ** created for this transaction. */ - #ifdef SQLITE_ENABLE_ATOMIC_WRITE - PgHdr *pPg; - assert( isOpen(pPager->jfd) - || pPager->journalMode==PAGER_JOURNALMODE_OFF - || pPager->journalMode==PAGER_JOURNALMODE_WAL - ); - if( !zMaster && isOpen(pPager->jfd) - && pPager->journalOff==jrnlBufferSize(pPager) - && pPager->dbSize>=pPager->dbOrigSize - && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) - ){ - /* Update the db file change counter via the direct-write method. The - ** following call will modify the in-memory representation of page 1 - ** to include the updated change counter and then write page 1 - ** directly to the database file. Because of the atomic-write - ** property of the host file-system, this is safe. - */ - rc = pager_incr_changecounter(pPager, 1); - }else{ - rc = sqlite3JournalCreate(pPager->jfd); - if( rc==SQLITE_OK ){ - rc = pager_incr_changecounter(pPager, 0); + if( bBatch==0 ){ + PgHdr *pPg; + assert( isOpen(pPager->jfd) + || pPager->journalMode==PAGER_JOURNALMODE_OFF + || pPager->journalMode==PAGER_JOURNALMODE_WAL + ); + if( !zSuper && isOpen(pPager->jfd) + && pPager->journalOff==jrnlBufferSize(pPager) + && pPager->dbSize>=pPager->dbOrigSize + && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty) + ){ + /* Update the db file change counter via the direct-write method. The + ** following call will modify the in-memory representation of page 1 + ** to include the updated change counter and then write page 1 + ** directly to the database file. Because of the atomic-write + ** property of the host file-system, this is safe. + */ + rc = pager_incr_changecounter(pPager, 1); + }else{ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc==SQLITE_OK ){ + rc = pager_incr_changecounter(pPager, 0); + } } } - #else +#else /* SQLITE_ENABLE_ATOMIC_WRITE */ +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( zSuper ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ) goto commit_phase_one_exit; + assert( bBatch==0 ); + } +#endif rc = pager_incr_changecounter(pPager, 0); - #endif +#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */ if( rc!=SQLITE_OK ) goto commit_phase_one_exit; - - /* Write the master journal name into the journal file. If a master - ** journal file name has already been written to the journal file, - ** or if zMaster is NULL (no master journal), then this call is a no-op. + + /* Write the super-journal name into the journal file. If a + ** super-journal file name has already been written to the journal file, + ** or if zSuper is NULL (no super-journal), then this call is a no-op. */ - rc = writeMasterJournal(pPager, zMaster); + rc = writeSuperJournal(pPager, zSuper); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; - + /* Sync the journal file and write all dirty pages to the database. - ** If the atomic-update optimization is being used, this sync will not + ** If the atomic-update optimization is being used, this sync will not ** create the journal file or perform any real IO. ** ** Because the change-counter page was just modified, unless the ** atomic-update optimization is used it is almost certain that the ** journal requires a sync here. However, in locking_mode=exclusive - ** on a system under memory pressure it is just possible that this is + ** on a system under memory pressure it is just possible that this is ** not the case. In this case it is likely enough that the redundant - ** xSync() call will be changed to a no-op by the OS anyhow. + ** xSync() call will be changed to a no-op by the OS anyhow. */ rc = syncJournal(pPager, 0); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; - - rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache)); + + pList = sqlite3PcacheDirtyList(pPager->pPCache); +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + if( bBatch ){ + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0); + if( rc==SQLITE_OK ){ + rc = pager_write_pagelist(pPager, pList); + if( rc==SQLITE_OK ){ + rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); + } + if( rc!=SQLITE_OK ){ + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0); + } + } + + if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){ + rc = sqlite3JournalCreate(pPager->jfd); + if( rc!=SQLITE_OK ){ + sqlite3OsClose(pPager->jfd); + goto commit_phase_one_exit; + } + bBatch = 0; + }else{ + sqlite3OsClose(pPager->jfd); + } + } +#endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ + + if( bBatch==0 ){ + rc = pager_write_pagelist(pPager, pList); + } if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; } sqlite3PcacheCleanAll(pPager->pPCache); - /* If the file on disk is smaller than the database image, use + /* If the file on disk is smaller than the database image, use ** pager_truncate to grow the file here. This can happen if the database ** image was extended as part of the current transaction and then the ** last page in the db image moved to the free-list. In this case the @@ -53190,10 +59799,10 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( rc = pager_truncate(pPager, nNew); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; } - + /* Finally, sync the database file. */ if( !noSync ){ - rc = sqlite3PagerSync(pPager, zMaster); + rc = sqlite3PagerSync(pPager, zSuper); } IOTRACE(("DBSYNC %p\n", pPager)) } @@ -53210,12 +59819,12 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne( /* ** When this function is called, the database file has been completely ** updated to reflect the changes made by the current transaction and -** synced to disk. The journal file still exists in the file-system +** synced to disk. The journal file still exists in the file-system ** though, and if a failure occurs at this point it will eventually ** be used as a hot-journal and the current transaction rolled back. ** -** This function finalizes the journal file, either by deleting, -** truncating or partially zeroing it, so that it cannot be used +** This function finalizes the journal file, either by deleting, +** truncating or partially zeroing it, so that it cannot be used ** for hot-journal rollback. Once this is done the transaction is ** irrevocably committed. ** @@ -53229,6 +59838,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ ** But if (due to a coding error elsewhere in the system) it does get ** called, just return the same error code without doing anything. */ if( NEVER(pPager->errCode) ) return pPager->errCode; + pPager->iDataVersion++; assert( pPager->eState==PAGER_WRITER_LOCKED || pPager->eState==PAGER_WRITER_FINISHED @@ -53240,15 +59850,15 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ ** this transaction, the pager is running in exclusive-mode and is ** using persistent journals, then this function is a no-op. ** - ** The start of the journal file currently contains a single journal + ** The start of the journal file currently contains a single journal ** header with the nRec field set to 0. If such a journal is used as ** a hot-journal during hot-journal rollback, 0 changes will be made - ** to the database file. So there is no need to zero the journal + ** to the database file. So there is no need to zero the journal ** header. Since the pager is in exclusive mode, there is no need ** to drop any locks either. */ - if( pPager->eState==PAGER_WRITER_LOCKED - && pPager->exclusiveMode + if( pPager->eState==PAGER_WRITER_LOCKED + && pPager->exclusiveMode && pPager->journalMode==PAGER_JOURNALMODE_PERSIST ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); @@ -53257,13 +59867,12 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); - pPager->iDataVersion++; - rc = pager_end_transaction(pPager, pPager->setMaster, 1); + rc = pager_end_transaction(pPager, pPager->setSuper, 1); return pager_error(pPager, rc); } /* -** If a write transaction is open, then all changes made within the +** If a write transaction is open, then all changes made within the ** transaction are reverted and the current write-transaction is closed. ** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR ** state if an error occurs. @@ -53273,14 +59882,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){ ** ** Otherwise, in rollback mode, this function performs two functions: ** -** 1) It rolls back the journal file, restoring all database file and +** 1) It rolls back the journal file, restoring all database file and ** in-memory cache pages to the state they were in when the transaction ** was opened, and ** ** 2) It finalizes the journal file, so that it is not used for hot ** rollback at any point in the future. ** -** Finalization of the journal file (task 2) is only performed if the +** Finalization of the journal file (task 2) is only performed if the ** rollback is successful. ** ** In WAL mode, all cache-entries containing data modified within the @@ -53293,7 +59902,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){ PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager))); /* PagerRollback() is a no-op if called in READER or OPEN state. If - ** the pager is already in the ERROR state, the rollback is not + ** the pager is already in the ERROR state, the rollback is not ** attempted here. Instead, the error code is returned to the caller. */ assert( assert_pager_state(pPager) ); @@ -53303,13 +59912,13 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){ if( pagerUseWal(pPager) ){ int rc2; rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); - rc2 = pager_end_transaction(pPager, pPager->setMaster, 0); + rc2 = pager_end_transaction(pPager, pPager->setSuper, 0); if( rc==SQLITE_OK ) rc = rc2; }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){ int eState = pPager->eState; rc = pager_end_transaction(pPager, 0, 0); if( !MEMDB && eState>PAGER_WRITER_LOCKED ){ - /* This can happen using journal_mode=off. Move the pager to the error + /* This can happen using journal_mode=off. Move the pager to the error ** state to indicate that the contents of the cache may not be trusted. ** Any active readers will get SQLITE_ABORT. */ @@ -53324,7 +59933,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){ assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT - || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR + || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR || rc==SQLITE_CANTOPEN ); @@ -53356,8 +59965,8 @@ SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){ ** used by the pager and its associated cache. */ SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){ - int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr) - + 5*sizeof(void*); + int perPageSize = pPager->pageSize + pPager->nExtra + + (int)(sizeof(PgHdr) + 5*sizeof(void*)); return perPageSize*sqlite3PcachePagecount(pPager->pPCache) + sqlite3MallocSize(pPager) + pPager->pageSize; @@ -53392,10 +60001,14 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){ #endif /* -** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or -** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the -** current cache hit or miss count, according to the value of eStat. If the -** reset parameter is non-zero, the cache hit or miss count is zeroed before +** Parameter eStat must be one of SQLITE_DBSTATUS_CACHE_HIT, _MISS, _WRITE, +** or _WRITE+1. The SQLITE_DBSTATUS_CACHE_WRITE+1 case is a translation +** of SQLITE_DBSTATUS_CACHE_SPILL. The _SPILL case is not contiguous because +** it was added later. +** +** Before returning, *pnVal is incremented by the +** current cache hit or miss count, according to the value of eStat. If the +** reset parameter is non-zero, the cache hit or miss count is zeroed before ** returning. */ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){ @@ -53403,15 +60016,18 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i assert( eStat==SQLITE_DBSTATUS_CACHE_HIT || eStat==SQLITE_DBSTATUS_CACHE_MISS || eStat==SQLITE_DBSTATUS_CACHE_WRITE + || eStat==SQLITE_DBSTATUS_CACHE_WRITE+1 ); assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS ); assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE ); - assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 ); + assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 + && PAGER_STAT_WRITE==2 && PAGER_STAT_SPILL==3 ); - *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT]; + eStat -= SQLITE_DBSTATUS_CACHE_HIT; + *pnVal += pPager->aStat[eStat]; if( reset ){ - pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0; + pPager->aStat[eStat] = 0; } } @@ -53419,7 +60035,7 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i ** Return true if this is an in-memory or temp-file backed pager. */ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){ - return pPager->tempFile; + return pPager->tempFile || pPager->memVfs; } /* @@ -53428,7 +60044,7 @@ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){ ** to make up the difference. If the number of savepoints is already ** equal to nSavepoint, then this function is a no-op. ** -** If a memory allocation fails, SQLITE_NOMEM is returned. If an error +** If a memory allocation fails, SQLITE_NOMEM is returned. If an error ** occurs while opening the sub-journal file, then an IO error code is ** returned. Otherwise, SQLITE_OK. */ @@ -53443,7 +60059,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){ assert( nSavepoint>nCurrent && pPager->useJournal ); /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM - ** if the allocation fails. Otherwise, zero the new portion in case a + ** if the allocation fails. Otherwise, zero the new portion in case a ** malloc failure occurs while populating it in the for(...) loop below. */ aNew = (PagerSavepoint *)sqlite3Realloc( @@ -53465,6 +60081,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){ } aNew[ii].iSubRec = pPager->nSubRec; aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize); + aNew[ii].bTruncateOnRelease = 1; if( !aNew[ii].pInSavepoint ){ return SQLITE_NOMEM_BKPT; } @@ -53491,7 +60108,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){ /* ** This function is called to rollback or release (commit) a savepoint. -** The savepoint to release or rollback need not be the most recently +** The savepoint to release or rollback need not be the most recently ** created savepoint. ** ** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE. @@ -53499,29 +60116,29 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){ ** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes ** that have occurred since the specified savepoint was created. ** -** The savepoint to rollback or release is identified by parameter +** The savepoint to rollback or release is identified by parameter ** iSavepoint. A value of 0 means to operate on the outermost savepoint ** (the first created). A value of (Pager.nSavepoint-1) means operate ** on the most recently created savepoint. If iSavepoint is greater than ** (Pager.nSavepoint-1), then this function is a no-op. ** ** If a negative value is passed to this function, then the current -** transaction is rolled back. This is different to calling +** transaction is rolled back. This is different to calling ** sqlite3PagerRollback() because this function does not terminate -** the transaction or unlock the database, it just restores the -** contents of the database to its original state. +** the transaction or unlock the database, it just restores the +** contents of the database to its original state. ** -** In any case, all savepoints with an index greater than iSavepoint +** In any case, all savepoints with an index greater than iSavepoint ** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE), ** then savepoint iSavepoint is also destroyed. ** ** This function may return SQLITE_NOMEM if a memory allocation fails, -** or an IO error code if an IO error occurs while rolling back a +** or an IO error code if an IO error occurs while rolling back a ** savepoint. If no errors occur, SQLITE_OK is returned. -*/ +*/ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ int rc = pPager->errCode; - + #ifdef SQLITE_ENABLE_ZIPVFS if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK; #endif @@ -53534,7 +60151,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ int nNew; /* Number of remaining savepoints after this op. */ /* Figure out how many savepoints will still be active after this - ** operation. Store this value in nNew. Then free resources associated + ** operation. Store this value in nNew. Then free resources associated ** with any savepoints that are destroyed by this operation. */ nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1); @@ -53543,16 +60160,18 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ } pPager->nSavepoint = nNew; - /* If this is a release of the outermost savepoint, truncate - ** the sub-journal to zero bytes in size. */ + /* Truncate the sub-journal so that it only includes the parts + ** that are still in use. */ if( op==SAVEPOINT_RELEASE ){ - if( nNew==0 && isOpen(pPager->sjfd) ){ + PagerSavepoint *pRel = &pPager->aSavepoint[nNew]; + if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){ /* Only truncate if it is an in-memory sub-journal. */ if( sqlite3JournalIsInMemory(pPager->sjfd) ){ - rc = sqlite3OsTruncate(pPager->sjfd, 0); + i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec; + rc = sqlite3OsTruncate(pPager->sjfd, sz); assert( rc==SQLITE_OK ); } - pPager->nSubRec = 0; + pPager->nSubRec = pRel->iSubRec; } } /* Else this is a rollback operation, playback the specified savepoint. @@ -53565,14 +60184,14 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ rc = pagerPlaybackSavepoint(pPager, pSavepoint); assert(rc!=SQLITE_DONE); } - + #ifdef SQLITE_ENABLE_ZIPVFS - /* If the cache has been modified but the savepoint cannot be rolled + /* If the cache has been modified but the savepoint cannot be rolled ** back journal_mode=off, put the pager in the error state. This way, ** if the VFS used by this pager includes ZipVFS, the entire transaction ** can be rolled back at the ZipVFS level. */ - else if( - pPager->journalMode==PAGER_JOURNALMODE_OFF + else if( + pPager->journalMode==PAGER_JOURNALMODE_OFF && pPager->eState>=PAGER_WRITER_CACHEMOD ){ pPager->errCode = SQLITE_ABORT; @@ -53594,9 +60213,13 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){ ** behavior. But when the Btree needs to know the filename for matching to ** shared cache, it uses nullIfMemDb==0 so that in-memory databases can ** participate in shared-cache. +** +** The return value to this routine is always safe to use with +** sqlite3_uri_parameter() and sqlite3_filename_database() and friends. */ -SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){ - return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename; +SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){ + static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename; } /* @@ -53634,50 +60257,6 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){ return pPager->zJournal; } -#ifdef SQLITE_HAS_CODEC -/* -** Set or retrieve the codec for this pager -*/ -SQLITE_PRIVATE void sqlite3PagerSetCodec( - Pager *pPager, - void *(*xCodec)(void*,void*,Pgno,int), - void (*xCodecSizeChng)(void*,int,int), - void (*xCodecFree)(void*), - void *pCodec -){ - if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); - pPager->xCodec = pPager->memDb ? 0 : xCodec; - pPager->xCodecSizeChng = xCodecSizeChng; - pPager->xCodecFree = xCodecFree; - pPager->pCodec = pCodec; - setGetterMethod(pPager); - pagerReportSize(pPager); -} -SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){ - return pPager->pCodec; -} - -/* -** This function is called by the wal module when writing page content -** into the log file. -** -** This function returns a pointer to a buffer containing the encrypted -** page content. If a malloc fails, this function may return NULL. -*/ -SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){ - void *aData = 0; - CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); - return aData; -} - -/* -** Return the current pager state -*/ -SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){ - return pPager->eState; -} -#endif /* SQLITE_HAS_CODEC */ - #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Move the page pPg to location pgno in the file. @@ -53697,8 +60276,8 @@ SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){ ** transaction is active). ** ** If the fourth argument, isCommit, is non-zero, then this page is being -** moved as part of a database reorganization just before the transaction -** is being committed. In this case, it is guaranteed that the database page +** moved as part of a database reorganization just before the transaction +** is being committed. In this case, it is guaranteed that the database page ** pPg refers to will not be written to again within this transaction. ** ** This function may return SQLITE_NOMEM or an IO error code if an error @@ -53726,7 +60305,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i } /* If the page being moved is dirty and has not been saved by the latest - ** savepoint, then save the current contents of the page into the + ** savepoint, then save the current contents of the page into the ** sub-journal now. This is required to handle the following scenario: ** ** BEGIN; @@ -53749,7 +60328,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i return rc; } - PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n", + PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n", PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno)); IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno)) @@ -53757,7 +60336,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i ** be written to, store pPg->pgno in local variable needSyncPgno. ** ** If the isCommit flag is set, there is no need to remember that - ** the journal needs to be sync()ed before database page pPg->pgno + ** the journal needs to be sync()ed before database page pPg->pgno ** can be written to. The caller has already promised not to write to it. */ if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){ @@ -53768,14 +60347,18 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i } /* If the cache contains a page with page-number pgno, remove it - ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for - ** page pgno before the 'move' operation, it needs to be retained + ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for + ** page pgno before the 'move' operation, it needs to be retained ** for the page moved there. */ pPg->flags &= ~PGHDR_NEED_SYNC; pPgOld = sqlite3PagerLookup(pPager, pgno); - assert( !pPgOld || pPgOld->nRef==1 ); + assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); if( pPgOld ){ + if( NEVER(pPgOld->nRef>1) ){ + sqlite3PagerUnrefNotNull(pPgOld); + return SQLITE_CORRUPT_BKPT; + } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ /* Do not discard pages from an in-memory database since we might @@ -53800,9 +60383,9 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i } if( needSyncPgno ){ - /* If needSyncPgno is non-zero, then the journal file needs to be + /* If needSyncPgno is non-zero, then the journal file needs to be ** sync()ed before any data is written to database file page needSyncPgno. - ** Currently, no such page exists in the page-cache and the + ** Currently, no such page exists in the page-cache and the ** "is journaled" bitvec flag has been set. This needs to be remedied by ** loading the page into the pager-cache and setting the PGHDR_NEED_SYNC ** flag. @@ -53833,9 +60416,9 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i #endif /* -** The page handle passed as the first argument refers to a dirty page -** with a page number other than iNew. This function changes the page's -** page number to iNew and sets the value of the PgHdr.flags field to +** The page handle passed as the first argument refers to a dirty page +** with a page number other than iNew. This function changes the page's +** page number to iNew and sets the value of the PgHdr.flags field to ** the value passed as the third parameter. */ SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){ @@ -53853,7 +60436,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){ } /* -** Return a pointer to the Pager.nExtra bytes of "extra" space +** Return a pointer to the Pager.nExtra bytes of "extra" space ** allocated along with the specified page. */ SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){ @@ -53862,7 +60445,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){ /* ** Get/set the locking-mode for this pager. Parameter eMode must be one -** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or +** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then ** the locking-mode is set to the value specified. ** @@ -53906,20 +60489,13 @@ SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ -#ifdef SQLITE_DEBUG - /* The print_pager_state() routine is intended to be used by the debugger - ** only. We invoke it once here to suppress a compiler warning. */ - print_pager_state(pPager); -#endif - - /* The eMode parameter is always valid */ - assert( eMode==PAGER_JOURNALMODE_DELETE - || eMode==PAGER_JOURNALMODE_TRUNCATE - || eMode==PAGER_JOURNALMODE_PERSIST - || eMode==PAGER_JOURNALMODE_OFF - || eMode==PAGER_JOURNALMODE_WAL - || eMode==PAGER_JOURNALMODE_MEMORY ); + assert( eMode==PAGER_JOURNALMODE_DELETE /* 0 */ + || eMode==PAGER_JOURNALMODE_PERSIST /* 1 */ + || eMode==PAGER_JOURNALMODE_OFF /* 2 */ + || eMode==PAGER_JOURNALMODE_TRUNCATE /* 3 */ + || eMode==PAGER_JOURNALMODE_MEMORY /* 4 */ + || eMode==PAGER_JOURNALMODE_WAL /* 5 */ ); /* This routine is only called from the OP_JournalMode opcode, and ** the logic there will never allow a temporary file to be changed @@ -53956,7 +60532,6 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ assert( isOpen(pPager->fd) || pPager->exclusiveMode ); if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ - /* In this case we would like to delete the journal file. If it is ** not possible, then that is not a problem. Deleting the journal file ** here is an optimization only. @@ -54068,11 +60643,23 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint( int *pnCkpt /* OUT: Final number of checkpointed frames */ ){ int rc = SQLITE_OK; + if( pPager->pWal==0 && pPager->journalMode==PAGER_JOURNALMODE_WAL ){ + /* This only happens when a database file is zero bytes in size opened and + ** then "PRAGMA journal_mode=WAL" is run and then sqlite3_wal_checkpoint() + ** is invoked without any intervening transactions. We need to start + ** a transaction to initialize pWal. The PRAGMA table_list statement is + ** used for this since it starts transactions on every database file, + ** including all ATTACHed databases. This seems expensive for a single + ** sqlite3_wal_checkpoint() call, but it happens very rarely. + ** https://sqlite.org/forum/forumpost/fd0f19d229156939 + */ + sqlite3_exec(db, "PRAGMA table_list",0,0,0); + } if( pPager->pWal ){ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), pPager->pBusyHandlerArg, - pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, + pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); } @@ -54103,7 +60690,7 @@ static int pagerExclusiveLock(Pager *pPager){ assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); rc = pagerLockDb(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ - /* If the attempt to grab the exclusive lock failed, release the + /* If the attempt to grab the exclusive lock failed, release the ** pending lock that may have been obtained instead. */ pagerUnlockDb(pPager, SHARED_LOCK); } @@ -54112,7 +60699,7 @@ static int pagerExclusiveLock(Pager *pPager){ } /* -** Call sqlite3WalOpen() to open the WAL handle. If the pager is in +** Call sqlite3WalOpen() to open the WAL handle. If the pager is in ** exclusive-locking mode when this function is called, take an EXCLUSIVE ** lock on the database file and use heap-memory to store the wal-index ** in. Otherwise, use the normal shared-memory. @@ -54123,8 +60710,8 @@ static int pagerOpenWal(Pager *pPager){ assert( pPager->pWal==0 && pPager->tempFile==0 ); assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK ); - /* If the pager is already in exclusive-mode, the WAL module will use - ** heap-memory for the wal-index instead of the VFS shared-memory + /* If the pager is already in exclusive-mode, the WAL module will use + ** heap-memory for the wal-index instead of the VFS shared-memory ** implementation. Take the exclusive lock now, before opening the WAL ** file, to make sure this is safe. */ @@ -54132,7 +60719,7 @@ static int pagerOpenWal(Pager *pPager){ rc = pagerExclusiveLock(pPager); } - /* Open the connection to the log file. If this operation fails, + /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ @@ -54154,7 +60741,7 @@ static int pagerOpenWal(Pager *pPager){ ** If the pager passed as the first argument is open on a real database ** file (not a temp file or an in-memory database), and the WAL file ** is not already open, make an attempt to open it now. If successful, -** return SQLITE_OK. If an error occurs or the VFS used by the pager does +** return SQLITE_OK. If an error occurs or the VFS used by the pager does ** not support the xShmXXX() methods, return an error code. *pbOpen is ** not modified in either case. ** @@ -54196,7 +60783,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal( ** This function is called to close the connection to the log file prior ** to switching from WAL to rollback mode. ** -** Before closing the log file, this function attempts to take an +** Before closing the log file, this function attempts to take an ** EXCLUSIVE lock on the database file. If this cannot be obtained, an ** error (SQLITE_BUSY) is returned and the log connection is not closed. ** If successful, the EXCLUSIVE lock is not released before returning. @@ -54222,14 +60809,14 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ rc = pagerOpenWal(pPager); } } - + /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on ** the database file, the log and log-summary files will be deleted. */ if( rc==SQLITE_OK && pPager->pWal ){ rc = pagerExclusiveLock(pPager); if( rc==SQLITE_OK ){ - rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, + rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize, (u8*)pPager->pTmpSpace); pPager->pWal = 0; pagerFixMaplimit(pPager); @@ -54239,6 +60826,32 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){ return rc; } +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +/* +** If pager pPager is a wal-mode database not in exclusive locking mode, +** invoke the sqlite3WalWriteLock() function on the associated Wal object +** with the same db and bLock parameters as were passed to this function. +** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. +*/ +SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){ + int rc = SQLITE_OK; + if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){ + rc = sqlite3WalWriteLock(pPager->pWal, bLock); + } + return rc; +} + +/* +** Set the database handle used by the wal layer to determine if +** blocking locks are required. +*/ +SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){ + if( pagerUseWal(pPager) ){ + sqlite3WalDb(pPager->pWal, db); + } +} +#endif + #ifdef SQLITE_ENABLE_SNAPSHOT /* ** If this is a WAL database, obtain a snapshot handle for the snapshot @@ -54254,10 +60867,13 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppS /* ** If this is a WAL database, store a pointer to pSnapshot. Next time a -** read transaction is opened, attempt to read from the snapshot it +** read transaction is opened, attempt to read from the snapshot it ** identifies. If this is not a WAL database, return an error. */ -SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){ +SQLITE_PRIVATE int sqlite3PagerSnapshotOpen( + Pager *pPager, + sqlite3_snapshot *pSnapshot +){ int rc = SQLITE_OK; if( pPager->pWal ){ sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot); @@ -54268,7 +60884,7 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSn } /* -** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this +** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this ** is not a WAL database, return an error. */ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){ @@ -54280,6 +60896,38 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){ } return rc; } + +/* +** The caller currently has a read transaction open on the database. +** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise, +** this function takes a SHARED lock on the CHECKPOINTER slot and then +** checks if the snapshot passed as the second argument is still +** available. If so, SQLITE_OK is returned. +** +** If the snapshot is not available, SQLITE_ERROR is returned. Or, if +** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error +** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER +** lock is released before returning. +*/ +SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){ + int rc; + if( pPager->pWal ){ + rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot); + }else{ + rc = SQLITE_ERROR; + } + return rc; +} + +/* +** Release a lock obtained by an earlier successful call to +** sqlite3PagerSnapshotCheck(). +*/ +SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){ + assert( pPager->pWal ); + sqlite3WalSnapshotUnlock(pPager->pWal); +} + #endif /* SQLITE_ENABLE_SNAPSHOT */ #endif /* !SQLITE_OMIT_WAL */ @@ -54313,7 +60961,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** ************************************************************************* ** -** This file contains the implementation of a write-ahead log (WAL) used in +** This file contains the implementation of a write-ahead log (WAL) used in ** "journal_mode=WAL" mode. ** ** WRITE-AHEAD LOG (WAL) FILE FORMAT @@ -54322,7 +60970,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** Each frame records the revised content of a single page from the ** database file. All changes to the database are recorded by writing ** frames into the WAL. Transactions commit when a frame is written that -** contains a commit marker. A single WAL can and usually does record +** contains a commit marker. A single WAL can and usually does record ** multiple transactions. Periodically, the content of the WAL is ** transferred back into the database file in an operation called a ** "checkpoint". @@ -54348,11 +60996,11 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** ** Immediately following the wal-header are zero or more frames. Each ** frame consists of a 24-byte frame-header followed by a bytes -** of page data. The frame-header is six big-endian 32-bit unsigned +** of page data. The frame-header is six big-endian 32-bit unsigned ** integer values, as follows: ** ** 0: Page number. -** 4: For commit records, the size of the database image in pages +** 4: For commit records, the size of the database image in pages ** after the commit. For all other records, zero. ** 8: Salt-1 (copied from the header) ** 12: Salt-2 (copied from the header) @@ -54378,7 +61026,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** the checksum. The checksum is computed by interpreting the input as ** an even number of unsigned 32-bit integers: x[0] through x[N]. The ** algorithm used for the checksum is as follows: -** +** ** for i from 0 to n-1 step 2: ** s0 += x[i] + s1; ** s1 += x[i+1] + s0; @@ -54386,7 +61034,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** ** Note that s0 and s1 are both weighted checksums using fibonacci weights ** in reverse order (the largest fibonacci weight occurs on the first element -** of the sequence being summed.) The s1 value spans all 32-bit +** of the sequence being summed.) The s1 value spans all 32-bit ** terms of the sequence whereas s0 omits the final term. ** ** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the @@ -54419,22 +61067,26 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** multiple concurrent readers to view different versions of the database ** content simultaneously. ** -** The reader algorithm in the previous paragraphs works correctly, but +** The reader algorithm in the previous paragraphs works correctly, but ** because frames for page P can appear anywhere within the WAL, the ** reader has to scan the entire WAL looking for page P frames. If the ** WAL is large (multiple megabytes is typical) that scan can be slow, ** and read performance suffers. To overcome this problem, a separate ** data structure called the wal-index is maintained to expedite the ** search for frames of a particular page. -** +** ** WAL-INDEX FORMAT ** ** Conceptually, the wal-index is shared memory, though VFS implementations ** might choose to implement the wal-index using a mmapped file. Because -** the wal-index is shared memory, SQLite does not support journal_mode=WAL +** the wal-index is shared memory, SQLite does not support journal_mode=WAL ** on a network filesystem. All users of the database must be able to ** share memory. ** +** In the default unix and windows implementation, the wal-index is a mmapped +** file whose name is the database name with a "-shm" suffix added. For that +** reason, the wal-index is sometimes called the "shm" file. +** ** The wal-index is transient. After a crash, the wal-index can (and should ** be) reconstructed from the original WAL file. In fact, the VFS is required ** to either truncate or zero the header of the wal-index when the last @@ -54445,28 +61097,31 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** byte order of the host computer. ** ** The purpose of the wal-index is to answer this question quickly: Given -** a page number P and a maximum frame index M, return the index of the +** a page number P and a maximum frame index M, return the index of the ** last frame in the wal before frame M for page P in the WAL, or return ** NULL if there are no frames for page P in the WAL prior to M. ** ** The wal-index consists of a header region, followed by an one or -** more index blocks. +** more index blocks. ** ** The wal-index header contains the total number of frames within the WAL ** in the mxFrame field. ** -** Each index block except for the first contains information on +** Each index block except for the first contains information on ** HASHTABLE_NPAGE frames. The first index block contains information on -** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and +** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and ** HASHTABLE_NPAGE are selected so that together the wal-index header and ** first index block are the same size as all other index blocks in the -** wal-index. +** wal-index. The values are: +** +** HASHTABLE_NPAGE 4096 +** HASHTABLE_NPAGE_ONE 4062 ** ** Each index block contains two sections, a page-mapping that contains the -** database page number associated with each wal frame, and a hash-table +** database page number associated with each wal frame, and a hash-table ** that allows readers to query an index block for a specific page number. ** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE -** for the first index block) 32-bit page numbers. The first entry in the +** for the first index block) 32-bit page numbers. The first entry in the ** first index-block contains the database page number corresponding to the ** first frame in the WAL file. The first entry in the second index block ** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in @@ -54487,8 +61142,8 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** ** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers. ** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the -** hash table for each page number in the mapping section, so the hash -** table is never more than half full. The expected number of collisions +** hash table for each page number in the mapping section, so the hash +** table is never more than half full. The expected number of collisions ** prior to finding a match is 1. Each entry of the hash table is an ** 1-based index of an entry in the mapping section of the same ** index block. Let K be the 1-based index of the largest entry in @@ -54507,12 +61162,12 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** reached) until an unused hash slot is found. Let the first unused slot ** be at index iUnused. (iUnused might be less than iKey if there was ** wrap-around.) Because the hash table is never more than half full, -** the search is guaranteed to eventually hit an unused entry. Let +** the search is guaranteed to eventually hit an unused entry. Let ** iMax be the value between iKey and iUnused, closest to iUnused, ** where aHash[iMax]==P. If there is no iMax entry (if there exists ** no hash slot such that aHash[i]==p) then page P is not in the ** current index block. Otherwise the iMax-th mapping entry of the -** current index block corresponds to the last entry that references +** current index block corresponds to the last entry that references ** page P. ** ** A hash search begins with the last index block and moves toward the @@ -54537,7 +61192,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){ ** if no values greater than K0 had ever been inserted into the hash table ** in the first place - which is what reader one wants. Meanwhile, the ** second reader using K1 will see additional values that were inserted -** later, which is exactly what reader two wants. +** later, which is exactly what reader two wants. ** ** When a rollback occurs, the value of K is decreased. Hash table entries ** that correspond to frames greater than the new K value are removed @@ -54565,7 +61220,7 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0; ** values in the wal-header are correct and (b) the version field is not ** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN. ** -** Similarly, if a client successfully reads a wal-index header (i.e. the +** Similarly, if a client successfully reads a wal-index header (i.e. the ** checksum test is successful) and finds that the version field is not ** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite ** returns SQLITE_CANTOPEN. @@ -54574,9 +61229,18 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0; #define WALINDEX_MAX_VERSION 3007000 /* -** Indices of various locking bytes. WAL_NREADER is the number +** Index numbers for various locking bytes. WAL_NREADER is the number ** of available reader locks and should be at least 3. The default ** is SQLITE_SHM_NLOCK==8 and WAL_NREADER==5. +** +** Technically, the various VFSes are free to implement these locks however +** they see fit. However, compatibility is encouraged so that VFSes can +** interoperate. The standard implemention used on both unix and windows +** is for the index number to indicate a byte offset into the +** WalCkptInfo.aLock[] array in the wal-index header. In other words, all +** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which +** should be 120) is the location in the shm file for the first locking +** byte. */ #define WAL_WRITE_LOCK 0 #define WAL_ALL_BUT_WRITE 1 @@ -54603,7 +61267,7 @@ typedef struct WalCkptInfo WalCkptInfo; ** ** The szPage value can be any power of 2 between 512 and 32768, inclusive. ** Or it can be 1 to represent a 65536-byte page. The latter case was -** added in 3.7.1 when support for 64K pages was added. +** added in 3.7.1 when support for 64K pages was added. */ struct WalIndexHdr { u32 iVersion; /* Wal-index version */ @@ -54645,7 +61309,7 @@ struct WalIndexHdr { ** There is one entry in aReadMark[] for each reader lock. If a reader ** holds read-lock K, then the value in aReadMark[K] is no greater than ** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff) -** for any aReadMark[] means that entry is unused. aReadMark[0] is +** for any aReadMark[] means that entry is unused. aReadMark[0] is ** a special case; its value is never used and it exists as a place-holder ** to avoid having to offset aReadMark[] indexs by one. Readers holding ** WAL_READ_LOCK(0) always ignore the entire WAL and read all content @@ -54665,7 +61329,7 @@ struct WalIndexHdr { ** previous sentence is when nBackfill equals mxFrame (meaning that everything ** in the WAL has been backfilled into the database) then new readers ** will choose aReadMark[0] which has value 0 and hence such reader will -** get all their all content directly from the database file and ignore +** get all their all content directly from the database file and ignore ** the WAL. ** ** Writers normally append new frames to the end of the WAL. However, @@ -54687,6 +61351,70 @@ struct WalCkptInfo { }; #define READMARK_NOT_USED 0xffffffff +/* +** This is a schematic view of the complete 136-byte header of the +** wal-index file (also known as the -shm file): +** +** +-----------------------------+ +** 0: | iVersion | \ +** +-----------------------------+ | +** 4: | (unused padding) | | +** +-----------------------------+ | +** 8: | iChange | | +** +-------+-------+-------------+ | +** 12: | bInit | bBig | szPage | | +** +-------+-------+-------------+ | +** 16: | mxFrame | | First copy of the +** +-----------------------------+ | WalIndexHdr object +** 20: | nPage | | +** +-----------------------------+ | +** 24: | aFrameCksum | | +** | | | +** +-----------------------------+ | +** 32: | aSalt | | +** | | | +** +-----------------------------+ | +** 40: | aCksum | | +** | | / +** +-----------------------------+ +** 48: | iVersion | \ +** +-----------------------------+ | +** 52: | (unused padding) | | +** +-----------------------------+ | +** 56: | iChange | | +** +-------+-------+-------------+ | +** 60: | bInit | bBig | szPage | | +** +-------+-------+-------------+ | Second copy of the +** 64: | mxFrame | | WalIndexHdr +** +-----------------------------+ | +** 68: | nPage | | +** +-----------------------------+ | +** 72: | aFrameCksum | | +** | | | +** +-----------------------------+ | +** 80: | aSalt | | +** | | | +** +-----------------------------+ | +** 88: | aCksum | | +** | | / +** +-----------------------------+ +** 96: | nBackfill | +** +-----------------------------+ +** 100: | 5 read marks | +** | | +** | | +** | | +** | | +** +-------+-------+------+------+ +** 120: | Write | Ckpt | Rcvr | Rd0 | \ +** +-------+-------+------+------+ ) 8 lock bytes +** | Read1 | Read2 | Rd3 | Rd4 | / +** +-------+-------+------+------+ +** 128: | nBackfillAttempted | +** +-----------------------------+ +** 132: | (unused padding) | +** +-----------------------------+ +*/ /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems @@ -54700,7 +61428,6 @@ struct WalCkptInfo { #define WAL_FRAME_HDRSIZE 24 /* Size of write ahead log header, including checksum. */ -/* #define WAL_HDRSIZE 24 */ #define WAL_HDRSIZE 32 /* WAL magic value. Either this value, or the same value with the least @@ -54708,14 +61435,14 @@ struct WalCkptInfo { ** big-endian format in the first 4 bytes of a WAL file. ** ** If the LSB is set, then the checksums for each frame within the WAL -** file are calculated by treating all data as an array of 32-bit -** big-endian words. Otherwise, they are calculated by interpreting +** file are calculated by treating all data as an array of 32-bit +** big-endian words. Otherwise, they are calculated by interpreting ** all data as 32-bit little-endian words. */ #define WAL_MAGIC 0x377f0682 /* -** Return the offset of frame iFrame in the write-ahead log file, +** Return the offset of frame iFrame in the write-ahead log file, ** assuming a database page size of szPage bytes. The offset returned ** is to the start of the write-ahead log frame-header. */ @@ -54746,6 +61473,7 @@ struct Wal { u8 truncateOnCommit; /* True to truncate WAL file on commit */ u8 syncHeader; /* Fsync the WAL header if true */ u8 padToSectorBoundary; /* Pad transactions out to the next sector */ + u8 bShmUnreliable; /* SHM content is read-only and unreliable */ WalIndexHdr hdr; /* Wal-index header for current transaction */ u32 minFrame; /* Ignore wal frames before this one */ u32 iReCksum; /* On commit, recalculate checksums from here */ @@ -54757,13 +61485,16 @@ struct Wal { #ifdef SQLITE_ENABLE_SNAPSHOT WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ #endif +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + sqlite3 *db; +#endif }; /* ** Candidate values for Wal.exclusiveMode. */ #define WAL_NORMAL_MODE 0 -#define WAL_EXCLUSIVE_MODE 1 +#define WAL_EXCLUSIVE_MODE 1 #define WAL_HEAPMEMORY_MODE 2 /* @@ -54782,7 +61513,7 @@ typedef u16 ht_slot; /* ** This structure is used to implement an iterator that loops through ** all frames in the WAL in database page order. Where two or more frames -** correspond to the same database page, the iterator visits only the +** correspond to the same database page, the iterator visits only the ** frame most recently written to the WAL (in other words, the frame with ** the largest index). ** @@ -54795,7 +61526,7 @@ typedef u16 ht_slot; ** This functionality is used by the checkpoint code (see walCheckpoint()). */ struct WalIterator { - int iPrior; /* Last result returned from the iterator */ + u32 iPrior; /* Last result returned from the iterator */ int nSegment; /* Number of entries in aSegment[] */ struct WalSegment { int iNext; /* Next slot in aIndex[] not yet returned */ @@ -54818,7 +61549,7 @@ struct WalIterator { #define HASHTABLE_HASH_1 383 /* Should be prime */ #define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */ -/* +/* ** The block of page numbers associated with the first hash-table in a ** wal-index is smaller than usual. This is so that there is a complete ** hash-table on each aligned 32KB page of the wal-index. @@ -54835,18 +61566,31 @@ struct WalIterator { ** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are ** numbered from zero. ** -** If this call is successful, *ppPage is set to point to the wal-index -** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs, -** then an SQLite error code is returned and *ppPage is set to 0. +** If the wal-index is currently smaller the iPage pages then the size +** of the wal-index might be increased, but only if it is safe to do +** so. It is safe to enlarge the wal-index if pWal->writeLock is true +** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. +** +** Three possible result scenarios: +** +** (1) rc==SQLITE_OK and *ppPage==Requested-Wal-Index-Page +** (2) rc>=SQLITE_ERROR and *ppPage==NULL +** (3) rc==SQLITE_OK and *ppPage==NULL // only if iPage==0 +** +** Scenario (3) can only occur when pWal->writeLock is false and iPage==0 */ -static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ +static SQLITE_NOINLINE int walIndexPageRealloc( + Wal *pWal, /* The WAL context */ + int iPage, /* The page we seek */ + volatile u32 **ppPage /* Write the page pointer here */ +){ int rc = SQLITE_OK; /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ - int nByte = sizeof(u32*)*(iPage+1); + sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); volatile u32 **apNew; - apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte); + apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte); if( !apNew ){ *ppPage = 0; return SQLITE_NOMEM_BKPT; @@ -54858,16 +61602,23 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ } /* Request a pointer to the required page from the VFS */ - if( pWal->apWiData[iPage]==0 ){ - if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ - pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); - if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT; - }else{ - rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, - pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] - ); + assert( pWal->apWiData[iPage]==0 ); + if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ + pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); + if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, + pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] + ); + assert( pWal->apWiData[iPage]!=0 + || rc!=SQLITE_OK + || (pWal->writeLock==0 && iPage==0) ); + testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK ); + if( rc==SQLITE_OK ){ + if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM; + }else if( (rc&0xff)==SQLITE_READONLY ){ + pWal->readOnly |= WAL_SHM_RDONLY; if( rc==SQLITE_READONLY ){ - pWal->readOnly |= WAL_SHM_RDONLY; rc = SQLITE_OK; } } @@ -54877,6 +61628,16 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){ assert( iPage==0 || *ppPage || rc!=SQLITE_OK ); return rc; } +static int walIndexPage( + Wal *pWal, /* The WAL context */ + int iPage, /* The page we seek */ + volatile u32 **ppPage /* Write the page pointer here */ +){ + if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){ + return walIndexPageRealloc(pWal, iPage, ppPage); + } + return SQLITE_OK; +} /* ** Return a pointer to the WalCkptInfo structure in the wal-index. @@ -54907,7 +61668,7 @@ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){ ) /* -** Generate or extend an 8 byte checksum based on the data in +** Generate or extend an 8 byte checksum based on the data in ** array aByte[] and the initial values of aIn[0] and aIn[1] (or ** initial values of 0 and 0 if aIn==NULL). ** @@ -54935,6 +61696,7 @@ static void walChecksumBytes( assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); + assert( nByte<=65536 ); if( nativeCksum ){ do { @@ -54953,18 +61715,35 @@ static void walChecksumBytes( aOut[1] = s2; } +/* +** If there is the possibility of concurrent access to the SHM file +** from multiple threads and/or processes, then do a memory barrier. +*/ static void walShmBarrier(Wal *pWal){ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){ sqlite3OsShmBarrier(pWal->pDbFd); } } +/* +** Add the SQLITE_NO_TSAN as part of the return-type of a function +** definition as a hint that the function contains constructs that +** might give false-positive TSAN warnings. +** +** See tag-20200519-1. +*/ +#if defined(__clang__) && !defined(SQLITE_NO_TSAN) +# define SQLITE_NO_TSAN __attribute__((no_sanitize_thread)) +#else +# define SQLITE_NO_TSAN +#endif + /* ** Write the header information in pWal->hdr into the wal-index. ** ** The checksum on pWal->hdr is updated before it is written. */ -static void walIndexWriteHdr(Wal *pWal){ +static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){ volatile WalIndexHdr *aHdr = walIndexHdr(pWal); const int nCksum = offsetof(WalIndexHdr, aCksum); @@ -54972,6 +61751,7 @@ static void walIndexWriteHdr(Wal *pWal){ pWal->hdr.isInit = 1; pWal->hdr.iVersion = WALINDEX_MAX_VERSION; walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum); + /* Possible TSAN false-positive. See tag-20200519-1 */ memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); walShmBarrier(pWal); memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr)); @@ -54979,11 +61759,11 @@ static void walIndexWriteHdr(Wal *pWal){ /* ** This function encodes a single frame header and writes it to a buffer -** supplied by the caller. A frame-header is made up of a series of +** supplied by the caller. A frame-header is made up of a series of ** 4-byte big-endian integers, as follows: ** ** 0: Page number. -** 4: For commit records, the size of the database image in pages +** 4: For commit records, the size of the database image in pages ** after the commit. For all other records, zero. ** 8: Salt-1 (copied from the wal-header) ** 12: Salt-2 (copied from the wal-header) @@ -55034,7 +61814,7 @@ static int walDecodeFrame( assert( WAL_FRAME_HDRSIZE==24 ); /* A frame is only valid if the salt values in the frame-header - ** match the salt values in the wal-header. + ** match the salt values in the wal-header. */ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){ return 0; @@ -55048,15 +61828,15 @@ static int walDecodeFrame( } /* A frame is only valid if a checksum of the WAL header, - ** all prior frams, the first 16 bytes of this frame-header, - ** and the frame-data matches the checksum in the last 8 + ** all prior frams, the first 16 bytes of this frame-header, + ** and the frame-data matches the checksum in the last 8 ** bytes of this frame-header. */ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); - if( aCksum[0]!=sqlite3Get4byte(&aFrame[16]) - || aCksum[1]!=sqlite3Get4byte(&aFrame[20]) + if( aCksum[0]!=sqlite3Get4byte(&aFrame[16]) + || aCksum[1]!=sqlite3Get4byte(&aFrame[20]) ){ /* Checksum failed. */ return 0; @@ -55091,7 +61871,7 @@ static const char *walLockName(int lockIdx){ } } #endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */ - + /* ** Set or release locks on the WAL. Locks are either shared or exclusive. @@ -55107,7 +61887,7 @@ static int walLockShared(Wal *pWal, int lockIdx){ SQLITE_SHM_LOCK | SQLITE_SHM_SHARED); WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal, walLockName(lockIdx), rc ? "failed" : "ok")); - VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); ) + VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); ) return rc; } static void walUnlockShared(Wal *pWal, int lockIdx){ @@ -55123,7 +61903,7 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){ SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE); WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal, walLockName(lockIdx), n, rc ? "failed" : "ok")); - VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); ) + VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); ) return rc; } static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){ @@ -55148,48 +61928,52 @@ static int walNextHash(int iPriorHash){ return (iPriorHash+1)&(HASHTABLE_NSLOT-1); } -/* +/* +** An instance of the WalHashLoc object is used to describe the location +** of a page hash table in the wal-index. This becomes the return value +** from walHashGet(). +*/ +typedef struct WalHashLoc WalHashLoc; +struct WalHashLoc { + volatile ht_slot *aHash; /* Start of the wal-index hash table */ + volatile u32 *aPgno; /* aPgno[1] is the page of first frame indexed */ + u32 iZero; /* One less than the frame number of first indexed*/ +}; + +/* ** Return pointers to the hash table and page number array stored on ** page iHash of the wal-index. The wal-index is broken into 32KB pages ** numbered starting from 0. ** -** Set output variable *paHash to point to the start of the hash table -** in the wal-index file. Set *piZero to one less than the frame +** Set output variable pLoc->aHash to point to the start of the hash table +** in the wal-index file. Set pLoc->iZero to one less than the frame ** number of the first frame indexed by this hash table. If a -** slot in the hash table is set to N, it refers to frame number -** (*piZero+N) in the log. +** slot in the hash table is set to N, it refers to frame number +** (pLoc->iZero+N) in the log. ** -** Finally, set *paPgno so that *paPgno[1] is the page number of the -** first frame indexed by the hash table, frame (*piZero+1). +** Finally, set pLoc->aPgno so that pLoc->aPgno[0] is the page number of the +** first frame indexed by the hash table, frame (pLoc->iZero). */ static int walHashGet( Wal *pWal, /* WAL handle */ int iHash, /* Find the iHash'th table */ - volatile ht_slot **paHash, /* OUT: Pointer to hash index */ - volatile u32 **paPgno, /* OUT: Pointer to page number array */ - u32 *piZero /* OUT: Frame associated with *paPgno[0] */ + WalHashLoc *pLoc /* OUT: Hash table location */ ){ int rc; /* Return code */ - volatile u32 *aPgno; - rc = walIndexPage(pWal, iHash, &aPgno); + rc = walIndexPage(pWal, iHash, &pLoc->aPgno); assert( rc==SQLITE_OK || iHash>0 ); - if( rc==SQLITE_OK ){ - u32 iZero; - volatile ht_slot *aHash; - - aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE]; + if( pLoc->aPgno ){ + pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE]; if( iHash==0 ){ - aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; - iZero = 0; + pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)]; + pLoc->iZero = 0; }else{ - iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; + pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE; } - - *paPgno = &aPgno[-1]; - *paHash = aHash; - *piZero = iZero; + }else if( NEVER(rc==SQLITE_OK) ){ + rc = SQLITE_ERROR; } return rc; } @@ -55197,7 +61981,7 @@ static int walHashGet( /* ** Return the number of the wal-index page that contains the hash-table ** and page-number array that contain entries corresponding to WAL frame -** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages +** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages ** are numbered starting from 0. */ static int walFramePage(u32 iFrame){ @@ -55208,6 +61992,7 @@ static int walFramePage(u32 iFrame){ && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE) && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE)) ); + assert( iHash>=0 ); return iHash; } @@ -55235,9 +62020,7 @@ static u32 walFramePgno(Wal *pWal, u32 iFrame){ ** actually needed. */ static void walCleanupHash(Wal *pWal){ - volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */ - volatile u32 *aPgno = 0; /* Page number array for hash table */ - u32 iZero = 0; /* frame == (aHash[x]+iZero) */ + WalHashLoc sLoc; /* Hash table location */ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ @@ -55249,30 +62032,32 @@ static void walCleanupHash(Wal *pWal){ if( pWal->hdr.mxFrame==0 ) return; - /* Obtain pointers to the hash-table and page-number array containing + /* Obtain pointers to the hash-table and page-number array containing ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed - ** that the page said hash-table and array reside on is already mapped. + ** that the page said hash-table and array reside on is already mapped.(1) */ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) ); assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] ); - walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero); + i = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); + if( NEVER(i) ) return; /* Defense-in-depth, in case (1) above is wrong */ /* Zero all hash-table entries that correspond to frame numbers greater ** than pWal->hdr.mxFrame. */ - iLimit = pWal->hdr.mxFrame - iZero; + iLimit = pWal->hdr.mxFrame - sLoc.iZero; assert( iLimit>0 ); for(i=0; iiLimit ){ - aHash[i] = 0; + if( sLoc.aHash[i]>iLimit ){ + sLoc.aHash[i] = 0; } } - + /* Zero the entries in the aPgno array that correspond to frames with - ** frame numbers greater than pWal->hdr.mxFrame. + ** frame numbers greater than pWal->hdr.mxFrame. */ - nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]); - memset((void *)&aPgno[iLimit+1], 0, nByte); + nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit]); + assert( nByte>=0 ); + memset((void *)&sLoc.aPgno[iLimit], 0, nByte); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the every entry in the mapping region is still reachable @@ -55281,11 +62066,11 @@ static void walCleanupHash(Wal *pWal){ if( iLimit ){ int j; /* Loop counter */ int iKey; /* Hash key */ - for(j=1; j<=iLimit; j++){ - for(iKey=walHash(aPgno[j]); aHash[iKey]; iKey=walNextHash(iKey)){ - if( aHash[iKey]==j ) break; + for(j=0; j=0 ); + memset((void*)sLoc.aPgno, 0, nByte); } /* If the entry in aPgno[] is already set, then the previous writer ** must have exited unexpectedly in the middle of a transaction (after - ** writing one or more dirty pages to the WAL to free up memory). - ** Remove the remnants of that writers uncommitted transaction from + ** writing one or more dirty pages to the WAL to free up memory). + ** Remove the remnants of that writers uncommitted transaction from ** the hash-table before writing any new entries. */ - if( aPgno[idx] ){ + if( sLoc.aPgno[idx-1] ){ walCleanupHash(pWal); - assert( !aPgno[idx] ); + assert( !sLoc.aPgno[idx-1] ); } /* Write the aPgno[] array entry and the hash-table slot. */ nCollide = idx; - for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){ + for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } - aPgno[idx] = iPage; - aHash[iKey] = (ht_slot)idx; + sLoc.aPgno[idx-1] = iPage; + AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* Verify that the number of entries in the hash table exactly equals @@ -55349,7 +62133,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ { int i; /* Loop counter */ int nEntry = 0; /* Number of entries in the hash table */ - for(i=0; iwriteLock ); iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock; - nLock = SQLITE_SHM_NLOCK - iLock; - rc = walLockExclusive(pWal, iLock, nLock); + rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); if( rc ){ return rc; } + WALTRACE(("WAL%p: recovery begin...\n", pWal)); memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); @@ -55419,15 +62203,16 @@ static int walIndexRecover(Wal *pWal){ if( nSize>WAL_HDRSIZE ){ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */ + u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */ int szFrame; /* Number of bytes in buffer aFrame[] */ u8 *aData; /* Pointer to data part of aFrame buffer */ - int iFrame; /* Index of last frame read */ - i64 iOffset; /* Next offset to read from log file */ int szPage; /* Page size according to the log */ u32 magic; /* Magic value read from WAL header */ u32 version; /* Magic value read from WAL header */ int isValid; /* True if this frame is valid */ + u32 iPg; /* Current 32KB wal-index page */ + u32 iLastFrame; /* Last frame in wal, based on nSize alone */ /* Read in the WAL header. */ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0); @@ -55436,16 +62221,16 @@ static int walIndexRecover(Wal *pWal){ } /* If the database page size is not a power of two, or is greater than - ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid + ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid ** data. Similarly, if the 'magic' value is invalid, ignore the whole ** WAL file. */ magic = sqlite3Get4byte(&aBuf[0]); szPage = sqlite3Get4byte(&aBuf[8]); - if( (magic&0xFFFFFFFE)!=WAL_MAGIC - || szPage&(szPage-1) - || szPage>SQLITE_MAX_PAGE_SIZE - || szPage<512 + if( (magic&0xFFFFFFFE)!=WAL_MAGIC + || szPage&(szPage-1) + || szPage>SQLITE_MAX_PAGE_SIZE + || szPage<512 ){ goto finished; } @@ -55455,7 +62240,7 @@ static int walIndexRecover(Wal *pWal){ memcpy(&pWal->hdr.aSalt, &aBuf[16], 8); /* Verify that the WAL header checksum is correct */ - walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN, + walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN, aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum ); if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24]) @@ -55474,38 +62259,83 @@ static int walIndexRecover(Wal *pWal){ /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; - aFrame = (u8 *)sqlite3_malloc64(szFrame); + aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ); if( !aFrame ){ rc = SQLITE_NOMEM_BKPT; goto recovery_error; } aData = &aFrame[WAL_FRAME_HDRSIZE]; + aPrivate = (u32*)&aData[szPage]; /* Read all frames from the log file. */ - iFrame = 0; - for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){ - u32 pgno; /* Database page number for frame */ - u32 nTruncate; /* dbsize field from frame header */ - - /* Read and decode the next log frame. */ - iFrame++; - rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); - if( rc!=SQLITE_OK ) break; - isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame); - if( !isValid ) break; - rc = walIndexAppend(pWal, iFrame, pgno); - if( rc!=SQLITE_OK ) break; - - /* If nTruncate is non-zero, this is a commit record. */ - if( nTruncate ){ - pWal->hdr.mxFrame = iFrame; - pWal->hdr.nPage = nTruncate; - pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); - testcase( szPage<=32768 ); - testcase( szPage>=65536 ); - aFrameCksum[0] = pWal->hdr.aFrameCksum[0]; - aFrameCksum[1] = pWal->hdr.aFrameCksum[1]; + iLastFrame = (nSize - WAL_HDRSIZE) / szFrame; + for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){ + u32 *aShare; + u32 iFrame; /* Index of last frame read */ + u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE); + u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE); + u32 nHdr, nHdr32; + rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare); + assert( aShare!=0 || rc!=SQLITE_OK ); + if( aShare==0 ) break; + pWal->apWiData[iPg] = aPrivate; + + for(iFrame=iFirst; iFrame<=iLast; iFrame++){ + i64 iOffset = walFrameOffset(iFrame, szPage); + u32 pgno; /* Database page number for frame */ + u32 nTruncate; /* dbsize field from frame header */ + + /* Read and decode the next log frame. */ + rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); + if( rc!=SQLITE_OK ) break; + isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame); + if( !isValid ) break; + rc = walIndexAppend(pWal, iFrame, pgno); + if( NEVER(rc!=SQLITE_OK) ) break; + + /* If nTruncate is non-zero, this is a commit record. */ + if( nTruncate ){ + pWal->hdr.mxFrame = iFrame; + pWal->hdr.nPage = nTruncate; + pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16)); + testcase( szPage<=32768 ); + testcase( szPage>=65536 ); + aFrameCksum[0] = pWal->hdr.aFrameCksum[0]; + aFrameCksum[1] = pWal->hdr.aFrameCksum[1]; + } + } + pWal->apWiData[iPg] = aShare; + nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0); + nHdr32 = nHdr / sizeof(u32); +#ifndef SQLITE_SAFER_WALINDEX_RECOVERY + /* Memcpy() should work fine here, on all reasonable implementations. + ** Technically, memcpy() might change the destination to some + ** intermediate value before setting to the final value, and that might + ** cause a concurrent reader to malfunction. Memcpy() is allowed to + ** do that, according to the spec, but no memcpy() implementation that + ** we know of actually does that, which is why we say that memcpy() + ** is safe for this. Memcpy() is certainly a lot faster. + */ + memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr); +#else + /* In the event that some platform is found for which memcpy() + ** changes the destination to some intermediate value before + ** setting the final value, this alternative copy routine is + ** provided. + */ + { + int i; + for(i=nHdr32; ihdr.aFrameCksum[1] = aFrameCksum[1]; walIndexWriteHdr(pWal); - /* Reset the checkpoint-header. This is safe because this thread is - ** currently holding locks that exclude all other readers, writers and - ** checkpointers. + /* Reset the checkpoint-header. This is safe because this thread is + ** currently holding locks that exclude all other writers and + ** checkpointers. Then set the values of read-mark slots 1 through N. */ pInfo = walCkptInfo(pWal); pInfo->nBackfill = 0; pInfo->nBackfillAttempted = pWal->hdr.mxFrame; pInfo->aReadMark[0] = 0; - for(i=1; iaReadMark[i] = READMARK_NOT_USED; - if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame; + for(i=1; ihdr.mxFrame ){ + pInfo->aReadMark[i] = pWal->hdr.mxFrame; + }else{ + pInfo->aReadMark[i] = READMARK_NOT_USED; + } + walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); + }else if( rc!=SQLITE_BUSY ){ + goto recovery_error; + } + } /* If more than one frame was recovered from the log file, report an ** event via sqlite3_log(). This is to help with identifying performance @@ -55545,7 +62386,7 @@ static int walIndexRecover(Wal *pWal){ recovery_error: WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok")); - walUnlockExclusive(pWal, iLock, nLock); + walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock); return rc; } @@ -55553,19 +62394,20 @@ static int walIndexRecover(Wal *pWal){ ** Close an open wal-index. */ static void walIndexClose(Wal *pWal, int isDelete){ - if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ + if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE || pWal->bShmUnreliable ){ int i; for(i=0; inWiData; i++){ sqlite3_free((void *)pWal->apWiData[i]); pWal->apWiData[i] = 0; } - }else{ + } + if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){ sqlite3OsShmUnmap(pWal->pDbFd, isDelete); } } -/* -** Open a connection to the WAL file zWalName. The database file must +/* +** Open a connection to the WAL file zWalName. The database file must ** already be opened on connection pDbFd. The buffer that zWalName points ** to must remain valid for the lifetime of the returned Wal* handle. ** @@ -55575,7 +62417,7 @@ static void walIndexClose(Wal *pWal, int isDelete){ ** were to do this just after this client opened one of these files, the ** system would be badly broken. ** -** If the log file is successfully opened, SQLITE_OK is returned and +** If the log file is successfully opened, SQLITE_OK is returned and ** *ppWal is set to point to a new WAL handle. If an error occurs, ** an SQLite error code is returned and *ppWal is left unmodified. */ @@ -55594,14 +62436,43 @@ SQLITE_PRIVATE int sqlite3WalOpen( assert( zWalName && zWalName[0] ); assert( pDbFd ); + /* Verify the values of various constants. Any changes to the values + ** of these constants would result in an incompatible on-disk format + ** for the -shm file. Any change that causes one of these asserts to + ** fail is a backward compatibility problem, even if the change otherwise + ** works. + ** + ** This table also serves as a helpful cross-reference when trying to + ** interpret hex dumps of the -shm file. + */ + assert( 48 == sizeof(WalIndexHdr) ); + assert( 40 == sizeof(WalCkptInfo) ); + assert( 120 == WALINDEX_LOCK_OFFSET ); + assert( 136 == WALINDEX_HDR_SIZE ); + assert( 4096 == HASHTABLE_NPAGE ); + assert( 4062 == HASHTABLE_NPAGE_ONE ); + assert( 8192 == HASHTABLE_NSLOT ); + assert( 383 == HASHTABLE_HASH_1 ); + assert( 32768 == WALINDEX_PGSZ ); + assert( 8 == SQLITE_SHM_NLOCK ); + assert( 5 == WAL_NREADER ); + assert( 24 == WAL_FRAME_HDRSIZE ); + assert( 32 == WAL_HDRSIZE ); + assert( 120 == WALINDEX_LOCK_OFFSET + WAL_WRITE_LOCK ); + assert( 121 == WALINDEX_LOCK_OFFSET + WAL_CKPT_LOCK ); + assert( 122 == WALINDEX_LOCK_OFFSET + WAL_RECOVER_LOCK ); + assert( 123 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(0) ); + assert( 124 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(1) ); + assert( 125 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(2) ); + assert( 126 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(3) ); + assert( 127 == WALINDEX_LOCK_OFFSET + WAL_READ_LOCK(4) ); + /* In the amalgamation, the os_unix.c and os_win.c source files come before ** this source file. Verify that the #defines of the locking byte offsets ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value. ** For that matter, if the lock offset ever changes from its initial design ** value of 120, we need to know that so there is an assert() to check it. */ - assert( 120==WALINDEX_LOCK_OFFSET ); - assert( 136==WALINDEX_HDR_SIZE ); #ifdef WIN_SHM_BASE assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif @@ -55739,7 +62610,7 @@ static void walMerge( ht_slot logpage; Pgno dbpage; - if( (iLeft=nRight || aContent[aLeft[iLeft]]aSegment[p->nSegment])[iZero]; - iZero++; - + aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero]; + sLoc.iZero++; + for(j=0; jaSegment[i].iZero = iZero; + walMergesort((u32 *)sLoc.aPgno, aTmp, aIndex, &nEntry); + p->aSegment[i].iZero = sLoc.iZero; p->aSegment[i].nEntry = nEntry; p->aSegment[i].aIndex = aIndex; - p->aSegment[i].aPgno = (u32 *)aPgno; + p->aSegment[i].aPgno = (u32 *)sLoc.aPgno; } } sqlite3_free(aTmp); if( rc!=SQLITE_OK ){ walIteratorFree(p); + p = 0; } *pp = p; return rc; } +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT +/* +** Attempt to enable blocking locks. Blocking locks are enabled only if (a) +** they are supported by the VFS, and (b) the database handle is configured +** with a busy-timeout. Return 1 if blocking locks are successfully enabled, +** or 0 otherwise. +*/ +static int walEnableBlocking(Wal *pWal){ + int res = 0; + if( pWal->db ){ + int tmout = pWal->db->busyTimeout; + if( tmout ){ + int rc; + rc = sqlite3OsFileControl( + pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout + ); + res = (rc==SQLITE_OK); + } + } + return res; +} + +/* +** Disable blocking locks. +*/ +static void walDisableBlocking(Wal *pWal){ + int tmout = 0; + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout); +} + +/* +** If parameter bLock is true, attempt to enable blocking locks, take +** the WRITER lock, and then disable blocking locks. If blocking locks +** cannot be enabled, no attempt to obtain the WRITER lock is made. Return +** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not +** an error if blocking locks can not be enabled. +** +** If the bLock parameter is false and the WRITER lock is held, release it. +*/ +SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){ + int rc = SQLITE_OK; + assert( pWal->readLock<0 || bLock==0 ); + if( bLock ){ + assert( pWal->db ); + if( walEnableBlocking(pWal) ){ + rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); + if( rc==SQLITE_OK ){ + pWal->writeLock = 1; + } + walDisableBlocking(pWal); + } + }else if( pWal->writeLock ){ + walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); + pWal->writeLock = 0; + } + return rc; +} + +/* +** Set the database handle used to determine if blocking locks are required. +*/ +SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){ + pWal->db = db; +} + +/* +** Take an exclusive WRITE lock. Blocking if so configured. +*/ +static int walLockWriter(Wal *pWal){ + int rc; + walEnableBlocking(pWal); + rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); + walDisableBlocking(pWal); + return rc; +} +#else +# define walEnableBlocking(x) 0 +# define walDisableBlocking(x) +# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1) +# define sqlite3WalDb(pWal, db) +#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */ + + /* ** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and ** n. If the attempt fails and parameter xBusy is not NULL, then it is a @@ -55949,6 +62902,12 @@ static int walBusyLock( do { rc = walLockExclusive(pWal, lockIdx, n); }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) ); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( rc==SQLITE_BUSY_TIMEOUT ){ + walDisableBlocking(pWal); + rc = SQLITE_BUSY; + } +#endif return rc; } @@ -55973,8 +62932,8 @@ static int walPagesize(Wal *pWal){ ** client to write to the database (which may be this one) does so by ** writing frames into the start of the log file. ** -** The value of parameter salt1 is used as the aSalt[1] value in the -** new wal-index header. It should be passed a pseudo-random value (i.e. +** The value of parameter salt1 is used as the aSalt[1] value in the +** new wal-index header. It should be passed a pseudo-random value (i.e. ** one obtained from sqlite3_randomness()). */ static void walRestartHdr(Wal *pWal, u32 salt1){ @@ -55986,7 +62945,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); memcpy(&pWal->hdr.aSalt[1], &salt1, 4); walIndexWriteHdr(pWal); - pInfo->nBackfill = 0; + AtomicStore(&pInfo->nBackfill, 0); pInfo->nBackfillAttempted = 0; pInfo->aReadMark[1] = 0; for(i=2; iaReadMark[i] = READMARK_NOT_USED; @@ -56002,8 +62961,8 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ ** that a concurrent reader might be using. ** ** All I/O barrier operations (a.k.a fsyncs) occur in this routine when -** SQLite is in WAL-mode in synchronous=NORMAL. That means that if -** checkpoints are always run by a background thread or background +** SQLite is in WAL-mode in synchronous=NORMAL. That means that if +** checkpoints are always run by a background thread or background ** process, foreground threads will never block on a lengthy fsync call. ** ** Fsync is called on the WAL before writing content out of the WAL and @@ -56016,7 +62975,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ ** database file. ** ** This routine uses and updates the nBackfill field of the wal-index header. -** This is the only routine that will increase the value of nBackfill. +** This is the only routine that will increase the value of nBackfill. ** (A WAL reset or recovery will revert nBackfill to zero, but not increase ** its value.) ** @@ -56049,13 +63008,6 @@ static int walCheckpoint( pInfo = walCkptInfo(pWal); if( pInfo->nBackfillhdr.mxFrame ){ - /* Allocate the iterator */ - rc = walIteratorInit(pWal, &pIter); - if( rc!=SQLITE_OK ){ - return rc; - } - assert( pIter ); - /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); @@ -56068,20 +63020,13 @@ static int walCheckpoint( mxSafeFrame = pWal->hdr.mxFrame; mxPage = pWal->hdr.nPage; for(i=1; iaReadMark[i]; + u32 y = AtomicLoad(pInfo->aReadMark+i); if( mxSafeFrame>y ){ assert( y<=pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ - pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED); + u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED); + AtomicStore(pInfo->aReadMark+i, iMark); walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); }else if( rc==SQLITE_BUSY ){ mxSafeFrame = y; @@ -56092,36 +63037,49 @@ static int walCheckpoint( } } - if( pInfo->nBackfillnBackfillnBackfill, &pIter); + assert( rc==SQLITE_OK || pIter==0 ); + } + + if( pIter + && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK ){ - i64 nSize; /* Current size of database file */ u32 nBackfill = pInfo->nBackfill; pInfo->nBackfillAttempted = mxSafeFrame; /* Sync the WAL to disk */ - if( sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags); - } + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); /* If the database may grow as a result of this checkpoint, hint ** about the eventual size of the db file to the VFS layer. */ if( rc==SQLITE_OK ){ i64 nReq = ((i64)mxPage * szPage); + i64 nSize; /* Current size of database file */ + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + if( (nSize+65536+(i64)pWal->hdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); + } } - } + } /* Iterate through the contents of the WAL, copying data to the db file */ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ i64 iOffset; assert( walFramePgno(pWal, iFrame)==iDbpage ); - if( db->u1.isInterrupted ){ + if( AtomicLoad(&db->u1.isInterrupted) ){ rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; break; } @@ -56137,6 +63095,7 @@ static int walCheckpoint( rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); /* If work was actually accomplished... */ if( rc==SQLITE_OK ){ @@ -56144,12 +63103,12 @@ static int walCheckpoint( i64 szDb = pWal->hdr.nPage*(i64)szPage; testcase( IS_BIG_INT(szDb) ); rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK && sync_flags ){ - rc = sqlite3OsSync(pWal->pDbFd, sync_flags); + if( rc==SQLITE_OK ){ + rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); } } if( rc==SQLITE_OK ){ - pInfo->nBackfill = mxSafeFrame; + AtomicStore(&pInfo->nBackfill, mxSafeFrame); } } @@ -56165,8 +63124,8 @@ static int walCheckpoint( } /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the - ** entire wal file has been copied into the database file, then block - ** until all readers have finished using the wal file. This ensures that + ** entire wal file has been copied into the database file, then block + ** until all readers have finished using the wal file. This ensures that ** the next process to write to the database restarts the wal file. */ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ @@ -56190,7 +63149,7 @@ static int walCheckpoint( ** writer clients should see that the entire log file has been ** checkpointed and behave accordingly. This seems unsafe though, ** as it would leave the system in a state where the contents of - ** the wal-index header do not match the contents of the + ** the wal-index header do not match the contents of the ** file-system. To avoid this, update the wal-index header to ** indicate that the log file contains zero valid frames. */ walRestartHdr(pWal, salt1); @@ -56252,7 +63211,7 @@ SQLITE_PRIVATE int sqlite3WalClose( if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } - rc = sqlite3WalCheckpoint(pWal, db, + rc = sqlite3WalCheckpoint(pWal, db, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 ); if( rc==SQLITE_OK ){ @@ -56308,7 +63267,7 @@ SQLITE_PRIVATE int sqlite3WalClose( ** If the checksum cannot be verified return non-zero. If the header ** is read successfully and the checksum verified, return zero. */ -static int walIndexTryHdr(Wal *pWal, int *pChanged){ +static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){ u32 aCksum[2]; /* Checksum on the header content */ WalIndexHdr h1, h2; /* Two copies of the header content */ WalIndexHdr volatile *aHdr; /* Header in shared memory */ @@ -56321,19 +63280,25 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){ ** meaning it is possible that an inconsistent snapshot is read ** from the file. If this happens, return non-zero. ** + ** tag-20200519-1: ** There are two copies of the header at the beginning of the wal-index. ** When reading, read [0] first then [1]. Writes are in the reverse order. ** Memory barriers are used to prevent the compiler or the hardware from - ** reordering the reads and writes. + ** reordering the reads and writes. TSAN and similar tools can sometimes + ** give false-positive warnings about these accesses because the tools do not + ** account for the double-read and the memory barrier. The use of mutexes + ** here would be problematic as the memory being accessed is potentially + ** shared among multiple processes and not all mutex implementions work + ** reliably in that environment. */ aHdr = walIndexHdr(pWal); - memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); + memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */ walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ return 1; /* Dirty read */ - } + } if( h1.isInit==0 ){ return 1; /* Malformed header - probably all zeros */ } @@ -56354,6 +63319,12 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){ return 0; } +/* +** This is the value that walTryBeginRead returns when it needs to +** be retried. +*/ +#define WAL_RETRY (-1) + /* ** Read the wal-index header from the wal-index and into pWal->hdr. ** If the wal-header appears to be corrupt, try to reconstruct the @@ -56363,7 +63334,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){ ** changed by this operation. If pWal->hdr is unchanged, set *pChanged ** to 0. ** -** If the wal-index header is successfully read, return SQLITE_OK. +** If the wal-index header is successfully read, return SQLITE_OK. ** Otherwise an SQLite error code. */ static int walIndexReadHdr(Wal *pWal, int *pChanged){ @@ -56371,19 +63342,39 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ int badHdr; /* True if a header read failed */ volatile u32 *page0; /* Chunk of wal-index containing header */ - /* Ensure that page 0 of the wal-index (the page that contains the + /* Ensure that page 0 of the wal-index (the page that contains the ** wal-index header) is mapped. Return early if an error occurs here. */ assert( pChanged ); rc = walIndexPage(pWal, 0, &page0); if( rc!=SQLITE_OK ){ - return rc; - }; - assert( page0 || pWal->writeLock==0 ); + assert( rc!=SQLITE_READONLY ); /* READONLY changed to OK in walIndexPage */ + if( rc==SQLITE_READONLY_CANTINIT ){ + /* The SQLITE_READONLY_CANTINIT return means that the shared-memory + ** was openable but is not writable, and this thread is unable to + ** confirm that another write-capable connection has the shared-memory + ** open, and hence the content of the shared-memory is unreliable, + ** since the shared-memory might be inconsistent with the WAL file + ** and there is no writer on hand to fix it. */ + assert( page0==0 ); + assert( pWal->writeLock==0 ); + assert( pWal->readOnly & WAL_SHM_RDONLY ); + pWal->bShmUnreliable = 1; + pWal->exclusiveMode = WAL_HEAPMEMORY_MODE; + *pChanged = 1; + }else{ + return rc; /* Any other non-OK return is just an error */ + } + }else{ + /* page0 can be NULL if the SHM is zero bytes in size and pWal->writeLock + ** is zero, which prevents the SHM from growing */ + testcase( page0!=0 ); + } + assert( page0!=0 || pWal->writeLock==0 ); /* If the first page of the wal-index has been mapped, try to read the ** wal-index header immediately, without holding any lock. This usually - ** works, but may fail if the wal-index header is corrupt or currently + ** works, but may fail if the wal-index header is corrupt or currently ** being modified by another thread or process. */ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1); @@ -56391,28 +63382,32 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ /* If the first attempt failed, it might have been due to a race ** with a writer. So get a WRITE lock and try again. */ - assert( badHdr==0 || pWal->writeLock==0 ); if( badHdr ){ - if( pWal->readOnly & WAL_SHM_RDONLY ){ + if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){ if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){ walUnlockShared(pWal, WAL_WRITE_LOCK); rc = SQLITE_READONLY_RECOVERY; } - }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ - pWal->writeLock = 1; - if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ - badHdr = walIndexTryHdr(pWal, pChanged); - if( badHdr ){ - /* If the wal-index header is still malformed even while holding - ** a WRITE lock, it can only mean that the header is corrupted and - ** needs to be reconstructed. So run recovery to do exactly that. - */ - rc = walIndexRecover(pWal); - *pChanged = 1; + }else{ + int bWriteLock = pWal->writeLock; + if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ + pWal->writeLock = 1; + if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ + badHdr = walIndexTryHdr(pWal, pChanged); + if( badHdr ){ + /* If the wal-index header is still malformed even while holding + ** a WRITE lock, it can only mean that the header is corrupted and + ** needs to be reconstructed. So run recovery to do exactly that. + */ + rc = walIndexRecover(pWal); + *pChanged = 1; + } + } + if( bWriteLock==0 ){ + pWal->writeLock = 0; + walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } } - pWal->writeLock = 0; - walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); } } @@ -56423,15 +63418,195 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){ rc = SQLITE_CANTOPEN_BKPT; } + if( pWal->bShmUnreliable ){ + if( rc!=SQLITE_OK ){ + walIndexClose(pWal, 0); + pWal->bShmUnreliable = 0; + assert( pWal->nWiData>0 && pWal->apWiData[0]==0 ); + /* walIndexRecover() might have returned SHORT_READ if a concurrent + ** writer truncated the WAL out from under it. If that happens, it + ** indicates that a writer has fixed the SHM file for us, so retry */ + if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY; + } + pWal->exclusiveMode = WAL_NORMAL_MODE; + } return rc; } /* -** This is the value that walTryBeginRead returns when it needs to -** be retried. +** Open a transaction in a connection where the shared-memory is read-only +** and where we cannot verify that there is a separate write-capable connection +** on hand to keep the shared-memory up-to-date with the WAL file. +** +** This can happen, for example, when the shared-memory is implemented by +** memory-mapping a *-shm file, where a prior writer has shut down and +** left the *-shm file on disk, and now the present connection is trying +** to use that database but lacks write permission on the *-shm file. +** Other scenarios are also possible, depending on the VFS implementation. +** +** Precondition: +** +** The *-wal file has been read and an appropriate wal-index has been +** constructed in pWal->apWiData[] using heap memory instead of shared +** memory. +** +** If this function returns SQLITE_OK, then the read transaction has +** been successfully opened. In this case output variable (*pChanged) +** is set to true before returning if the caller should discard the +** contents of the page cache before proceeding. Or, if it returns +** WAL_RETRY, then the heap memory wal-index has been discarded and +** the caller should retry opening the read transaction from the +** beginning (including attempting to map the *-shm file). +** +** If an error occurs, an SQLite error code is returned. */ -#define WAL_RETRY (-1) +static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ + i64 szWal; /* Size of wal file on disk in bytes */ + i64 iOffset; /* Current offset when reading wal file */ + u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */ + u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */ + int szFrame; /* Number of bytes in buffer aFrame[] */ + u8 *aData; /* Pointer to data part of aFrame buffer */ + volatile void *pDummy; /* Dummy argument for xShmMap */ + int rc; /* Return code */ + u32 aSaveCksum[2]; /* Saved copy of pWal->hdr.aFrameCksum */ + + assert( pWal->bShmUnreliable ); + assert( pWal->readOnly & WAL_SHM_RDONLY ); + assert( pWal->nWiData>0 && pWal->apWiData[0] ); + + /* Take WAL_READ_LOCK(0). This has the effect of preventing any + ** writers from running a checkpoint, but does not stop them + ** from running recovery. */ + rc = walLockShared(pWal, WAL_READ_LOCK(0)); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_BUSY ) rc = WAL_RETRY; + goto begin_unreliable_shm_out; + } + pWal->readLock = 0; + + /* Check to see if a separate writer has attached to the shared-memory area, + ** thus making the shared-memory "reliable" again. Do this by invoking + ** the xShmMap() routine of the VFS and looking to see if the return + ** is SQLITE_READONLY instead of SQLITE_READONLY_CANTINIT. + ** + ** If the shared-memory is now "reliable" return WAL_RETRY, which will + ** cause the heap-memory WAL-index to be discarded and the actual + ** shared memory to be used in its place. + ** + ** This step is important because, even though this connection is holding + ** the WAL_READ_LOCK(0) which prevents a checkpoint, a writer might + ** have already checkpointed the WAL file and, while the current + ** is active, wrap the WAL and start overwriting frames that this + ** process wants to use. + ** + ** Once sqlite3OsShmMap() has been called for an sqlite3_file and has + ** returned any SQLITE_READONLY value, it must return only SQLITE_READONLY + ** or SQLITE_READONLY_CANTINIT or some error for all subsequent invocations, + ** even if some external agent does a "chmod" to make the shared-memory + ** writable by us, until sqlite3OsShmUnmap() has been called. + ** This is a requirement on the VFS implementation. + */ + rc = sqlite3OsShmMap(pWal->pDbFd, 0, WALINDEX_PGSZ, 0, &pDummy); + assert( rc!=SQLITE_OK ); /* SQLITE_OK not possible for read-only connection */ + if( rc!=SQLITE_READONLY_CANTINIT ){ + rc = (rc==SQLITE_READONLY ? WAL_RETRY : rc); + goto begin_unreliable_shm_out; + } + + /* We reach this point only if the real shared-memory is still unreliable. + ** Assume the in-memory WAL-index substitute is correct and load it + ** into pWal->hdr. + */ + memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr)); + + /* Make sure some writer hasn't come in and changed the WAL file out + ** from under us, then disconnected, while we were not looking. + */ + rc = sqlite3OsFileSize(pWal->pWalFd, &szWal); + if( rc!=SQLITE_OK ){ + goto begin_unreliable_shm_out; + } + if( szWalhdr.mxFrame==0 ? SQLITE_OK : WAL_RETRY); + goto begin_unreliable_shm_out; + } + + /* Check the salt keys at the start of the wal file still match. */ + rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0); + if( rc!=SQLITE_OK ){ + goto begin_unreliable_shm_out; + } + if( memcmp(&pWal->hdr.aSalt, &aBuf[16], 8) ){ + /* Some writer has wrapped the WAL file while we were not looking. + ** Return WAL_RETRY which will cause the in-memory WAL-index to be + ** rebuilt. */ + rc = WAL_RETRY; + goto begin_unreliable_shm_out; + } + + /* Allocate a buffer to read frames into */ + assert( (pWal->szPage & (pWal->szPage-1))==0 ); + assert( pWal->szPage>=512 && pWal->szPage<=65536 ); + szFrame = pWal->szPage + WAL_FRAME_HDRSIZE; + aFrame = (u8 *)sqlite3_malloc64(szFrame); + if( aFrame==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto begin_unreliable_shm_out; + } + aData = &aFrame[WAL_FRAME_HDRSIZE]; + + /* Check to see if a complete transaction has been appended to the + ** wal file since the heap-memory wal-index was created. If so, the + ** heap-memory wal-index is discarded and WAL_RETRY returned to + ** the caller. */ + aSaveCksum[0] = pWal->hdr.aFrameCksum[0]; + aSaveCksum[1] = pWal->hdr.aFrameCksum[1]; + for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->szPage); + iOffset+szFrame<=szWal; + iOffset+=szFrame + ){ + u32 pgno; /* Database page number for frame */ + u32 nTruncate; /* dbsize field from frame header */ + + /* Read and decode the next log frame. */ + rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); + if( rc!=SQLITE_OK ) break; + if( !walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame) ) break; + + /* If nTruncate is non-zero, then a complete transaction has been + ** appended to this wal file. Set rc to WAL_RETRY and break out of + ** the loop. */ + if( nTruncate ){ + rc = WAL_RETRY; + break; + } + } + pWal->hdr.aFrameCksum[0] = aSaveCksum[0]; + pWal->hdr.aFrameCksum[1] = aSaveCksum[1]; + + begin_unreliable_shm_out: + sqlite3_free(aFrame); + if( rc!=SQLITE_OK ){ + int i; + for(i=0; inWiData; i++){ + sqlite3_free((void*)pWal->apWiData[i]); + pWal->apWiData[i] = 0; + } + pWal->bShmUnreliable = 0; + sqlite3WalEndReadTransaction(pWal); + *pChanged = 1; + } + return rc; +} /* ** Attempt to start a read transaction. This might fail due to a race or @@ -56444,10 +63619,10 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** ** The useWal parameter is true to force the use of the WAL and disable ** the case where the WAL is bypassed because it has been completely -** checkpointed. If useWal==0 then this routine calls walIndexReadHdr() -** to make a copy of the wal-index header into pWal->hdr. If the -** wal-index header has changed, *pChanged is set to 1 (as an indication -** to the caller that the local paget cache is obsolete and needs to be +** checkpointed. If useWal==0 then this routine calls walIndexReadHdr() +** to make a copy of the wal-index header into pWal->hdr. If the +** wal-index header has changed, *pChanged is set to 1 (as an indication +** to the caller that the local page cache is obsolete and needs to be ** flushed.) When useWal==1, the wal-index header is assumed to already ** be loaded and the pChanged parameter is unused. ** @@ -56462,7 +63637,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** bad luck when there is lots of contention for the wal-index, but that ** possibility is so small that it can be safely neglected, we believe. ** -** On success, this routine obtains a read lock on +** On success, this routine obtains a read lock on ** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is ** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1) ** that means the Wal does not hold any read lock. The reader must not @@ -56493,20 +63668,23 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ assert( pWal->readLock<0 ); /* Not currently locked */ + /* useWal may only be set for read/write connections */ + assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 ); + /* Take steps to avoid spinning forever if there is a protocol error. ** ** Circumstances that cause a RETRY should only last for the briefest ** instances of time. No I/O or other system calls are done while the - ** locks are held, so the locks should not be held for very long. But + ** locks are held, so the locks should not be held for very long. But ** if we are unlucky, another process that is holding a lock might get - ** paged out or take a page-fault that is time-consuming to resolve, + ** paged out or take a page-fault that is time-consuming to resolve, ** during the few nanoseconds that it is holding the lock. In that case, ** it might take longer than normal for the lock to free. ** ** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few ** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this ** is more of a scheduler yield than an actual delay. But on the 10th - ** an subsequent retries, the delays start becoming longer and longer, + ** an subsequent retries, the delays start becoming longer and longer, ** so that on the 100th (and last) RETRY we delay for 323 milliseconds. ** The total delay time before giving up is less than 10 seconds. */ @@ -56521,7 +63699,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ } if( !useWal ){ - rc = walIndexReadHdr(pWal, pChanged); + assert( rc==SQLITE_OK ); + if( pWal->bShmUnreliable==0 ){ + rc = walIndexReadHdr(pWal, pChanged); + } if( rc==SQLITE_BUSY ){ /* If there is not a recovery running in another thread or process ** then convert BUSY errors to WAL_RETRY. If recovery is known to @@ -56534,9 +63715,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ if( pWal->apWiData[0]==0 ){ /* This branch is taken when the xShmMap() method returns SQLITE_BUSY. ** We assume this is a transient condition, so return WAL_RETRY. The - ** xShmMap() implementation used by the default unix and win32 VFS - ** modules may return SQLITE_BUSY due to a race condition in the - ** code that determines whether or not the shared-memory region + ** xShmMap() implementation used by the default unix and win32 VFS + ** modules may return SQLITE_BUSY due to a race condition in the + ** code that determines whether or not the shared-memory region ** must be zeroed before the requested page is returned. */ rc = WAL_RETRY; @@ -56550,13 +63731,17 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ if( rc!=SQLITE_OK ){ return rc; } + else if( pWal->bShmUnreliable ){ + return walBeginShmUnreliable(pWal, pChanged); + } } + assert( pWal->nWiData>0 ); + assert( pWal->apWiData[0]!=0 ); pInfo = walCkptInfo(pWal); - if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame + if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame #ifdef SQLITE_ENABLE_SNAPSHOT - && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0 - || 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr))) + && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0) #endif ){ /* The WAL has been completely backfilled (or it is empty). @@ -56573,7 +63758,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from ** happening, this is usually correct. ** - ** However, if frames have been appended to the log (or if the log + ** However, if frames have been appended to the log (or if the log ** is wrapped and written for that matter) before the READ_LOCK(0) ** is obtained, that is not necessarily true. A checkpointer may ** have started to backfill the appended frames but crashed before @@ -56603,7 +63788,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ } #endif for(i=1; iaReadMark[i]; + u32 thisMark = AtomicLoad(pInfo->aReadMark+i); if( mxReadMark<=thisMark && thisMark<=mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; @@ -56616,7 +63801,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ for(i=1; iaReadMark[i] = mxFrame; + AtomicStore(pInfo->aReadMark+i,mxFrame); + mxReadMark = mxFrame; mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; @@ -56627,7 +63813,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ } if( mxI==0 ){ assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 ); - return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK; + return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT; } rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); @@ -56654,9 +63840,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** to read any frames earlier than minFrame from the wal file - they ** can be safely read directly from the database file. ** - ** Because a ShmBarrier() call is made between taking the copy of + ** Because a ShmBarrier() call is made between taking the copy of ** nBackfill and checking that the wal-header in shared-memory still - ** matches the one cached in pWal->hdr, it is guaranteed that the + ** matches the one cached in pWal->hdr, it is guaranteed that the ** checkpointer that set nBackfill was not working with a wal-index ** header newer than that cached in pWal->hdr. If it were, that could ** cause a problem. The checkpointer could omit to checkpoint @@ -56668,9 +63854,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** we can guarantee that the checkpointer that set nBackfill could not ** see any pages past pWal->hdr.mxFrame, this problem does not come up. */ - pWal->minFrame = pInfo->nBackfill+1; + pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; walShmBarrier(pWal); - if( pInfo->aReadMark[mxI]!=mxReadMark + if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); @@ -56684,15 +63870,15 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ #ifdef SQLITE_ENABLE_SNAPSHOT /* -** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted +** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted ** variable so that older snapshots can be accessed. To do this, loop -** through all wal frames from nBackfillAttempted to (nBackfill+1), +** through all wal frames from nBackfillAttempted to (nBackfill+1), ** comparing their content to the corresponding page with the database ** file, if any. Set nBackfillAttempted to the frame number of the ** first frame for which the wal file content matches the db file. ** -** This is only really safe if the file-system is such that any page -** writes made by earlier checkpointers were atomic operations, which +** This is only really safe if the file-system is such that any page +** writes made by earlier checkpointers were atomic operations, which ** is not always true. It is also possible that nBackfillAttempted ** may be left set to a value larger than expected, if a wal frame ** contains content that duplicate of an earlier version of the same @@ -56720,17 +63906,16 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ rc = SQLITE_NOMEM; }else{ u32 i = pInfo->nBackfillAttempted; - for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){ - volatile ht_slot *dummy; - volatile u32 *aPgno; /* Array of page numbers */ - u32 iZero; /* Frame corresponding to aPgno[0] */ + for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){ + WalHashLoc sLoc; /* Hash table location */ u32 pgno; /* Page number in db file */ i64 iDbOff; /* Offset of db file entry */ i64 iWalOff; /* Offset of wal file entry */ - rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero); + rc = walHashGet(pWal, walFramePage(i), &sLoc); if( rc!=SQLITE_OK ) break; - pgno = aPgno[i-iZero]; + assert( i - sLoc.iZero - 1 >=0 ); + pgno = sLoc.aPgno[i-sLoc.iZero-1]; iDbOff = (i64)(pgno-1) * szPage; if( iDbOff+szPage<=szDb ){ @@ -56771,18 +63956,41 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){ ** ** If the database contents have changes since the previous read ** transaction, then *pChanged is set to 1 before returning. The -** Pager layer will use this to know that is cache is stale and +** Pager layer will use this to know that its cache is stale and ** needs to be flushed. */ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ int cnt = 0; /* Number of TryBeginRead attempts */ - #ifdef SQLITE_ENABLE_SNAPSHOT int bChanged = 0; WalIndexHdr *pSnapshot = pWal->pSnapshot; - if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ - bChanged = 1; +#endif + + assert( pWal->ckptLock==0 ); + +#ifdef SQLITE_ENABLE_SNAPSHOT + if( pSnapshot ){ + if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ + bChanged = 1; + } + + /* It is possible that there is a checkpointer thread running + ** concurrent with this code. If this is the case, it may be that the + ** checkpointer has already determined that it will checkpoint + ** snapshot X, where X is later in the wal file than pSnapshot, but + ** has not yet set the pInfo->nBackfillAttempted variable to indicate + ** its intent. To avoid the race condition this leads to, ensure that + ** there is no checkpointer process by taking a shared CKPT lock + ** before checking pInfo->nBackfillAttempted. */ + (void)walEnableBlocking(pWal); + rc = walLockShared(pWal, WAL_CKPT_LOCK); + walDisableBlocking(pWal); + + if( rc!=SQLITE_OK ){ + return rc; + } + pWal->ckptLock = 1; } #endif @@ -56815,47 +64023,42 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 ); assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame ); - /* It is possible that there is a checkpointer thread running - ** concurrent with this code. If this is the case, it may be that the - ** checkpointer has already determined that it will checkpoint - ** snapshot X, where X is later in the wal file than pSnapshot, but - ** has not yet set the pInfo->nBackfillAttempted variable to indicate - ** its intent. To avoid the race condition this leads to, ensure that - ** there is no checkpointer process by taking a shared CKPT lock - ** before checking pInfo->nBackfillAttempted. - ** - ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing - ** this already? - */ - rc = walLockShared(pWal, WAL_CKPT_LOCK); - - if( rc==SQLITE_OK ){ - /* Check that the wal file has not been wrapped. Assuming that it has - ** not, also check that no checkpointer has attempted to checkpoint any - ** frames beyond pSnapshot->mxFrame. If either of these conditions are - ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr - ** with *pSnapshot and set *pChanged as appropriate for opening the - ** snapshot. */ - if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) - && pSnapshot->mxFrame>=pInfo->nBackfillAttempted - ){ - assert( pWal->readLock>0 ); - memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); - *pChanged = bChanged; - }else{ - rc = SQLITE_BUSY_SNAPSHOT; - } - - /* Release the shared CKPT lock obtained above. */ - walUnlockShared(pWal, WAL_CKPT_LOCK); + /* Check that the wal file has not been wrapped. Assuming that it has + ** not, also check that no checkpointer has attempted to checkpoint any + ** frames beyond pSnapshot->mxFrame. If either of these conditions are + ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr + ** with *pSnapshot and set *pChanged as appropriate for opening the + ** snapshot. */ + if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) + && pSnapshot->mxFrame>=pInfo->nBackfillAttempted + ){ + assert( pWal->readLock>0 ); + memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); + *pChanged = bChanged; + }else{ + rc = SQLITE_ERROR_SNAPSHOT; } + /* A client using a non-current snapshot may not ignore any frames + ** from the start of the wal file. This is because, for a system + ** where (minFrame < iSnapshot < maxFrame), a checkpointer may + ** have omitted to checkpoint a frame earlier than minFrame in + ** the file because there exists a frame after iSnapshot that + ** is the same database page. */ + pWal->minFrame = 1; if( rc!=SQLITE_OK ){ sqlite3WalEndReadTransaction(pWal); } } } + + /* Release the shared CKPT lock obtained above. */ + if( pWal->ckptLock ){ + assert( pSnapshot ); + walUnlockShared(pWal, WAL_CKPT_LOCK); + pWal->ckptLock = 0; + } #endif return rc; } @@ -56895,11 +64098,11 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( /* If the "last page" field of the wal-index header snapshot is 0, then ** no data will be read from the wal under any circumstances. Return early - ** in this case as an optimization. Likewise, if pWal->readLock==0, - ** then the WAL is ignored by the reader so return early, as if the + ** in this case as an optimization. Likewise, if pWal->readLock==0, + ** then the WAL is ignored by the reader so return early, as if the ** WAL were empty. */ - if( iLast==0 || pWal->readLock==0 ){ + if( iLast==0 || (pWal->readLock==0 && pWal->bShmUnreliable==0) ){ *piRead = 0; return SQLITE_OK; } @@ -56909,9 +64112,9 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames). ** ** This code might run concurrently to the code in walIndexAppend() - ** that adds entries to the wal-index (and possibly to this hash - ** table). This means the value just read from the hash - ** slot (aHash[iKey]) may have been added before or after the + ** that adds entries to the wal-index (and possibly to this hash + ** table). This means the value just read from the hash + ** slot (aHash[iKey]) may have been added before or after the ** current read transaction was opened. Values added after the ** read transaction was opened may have been written incorrectly - ** i.e. these slots may contain garbage data. However, we assume @@ -56919,40 +64122,42 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( ** opened remain unmodified. ** ** For the reasons above, the if(...) condition featured in the inner - ** loop of the following block is more stringent that would be required + ** loop of the following block is more stringent that would be required ** if we had exclusive access to the hash-table: ** - ** (aPgno[iFrame]==pgno): + ** (aPgno[iFrame]==pgno): ** This condition filters out normal hash-table collisions. ** - ** (iFrame<=iLast): + ** (iFrame<=iLast): ** This condition filters out entries that were added to the hash ** table after the current read-transaction had started. */ iMinHash = walFramePage(pWal->minFrame); - for(iHash=walFramePage(iLast); iHash>=iMinHash && iRead==0; iHash--){ - volatile ht_slot *aHash; /* Pointer to hash table */ - volatile u32 *aPgno; /* Pointer to array of page numbers */ - u32 iZero; /* Frame number corresponding to aPgno[0] */ + for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){ + WalHashLoc sLoc; /* Hash table location */ int iKey; /* Hash slot index */ int nCollide; /* Number of hash collisions remaining */ int rc; /* Error code */ + u32 iH; - rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero); + rc = walHashGet(pWal, iHash, &sLoc); if( rc!=SQLITE_OK ){ return rc; } nCollide = HASHTABLE_NSLOT; - for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){ - u32 iFrame = aHash[iKey] + iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){ + iKey = walHash(pgno); + while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){ + u32 iFrame = iH + sLoc.iZero; + if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ return SQLITE_CORRUPT_BKPT; } + iKey = walNextHash(iKey); } + if( iRead ) break; } #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT @@ -56962,8 +64167,8 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( { u32 iRead2 = 0; u32 iTest; - assert( pWal->minFrame>0 ); - for(iTest=iLast; iTest>=pWal->minFrame; iTest--){ + assert( pWal->bShmUnreliable || pWal->minFrame>0 ); + for(iTest=iLast; iTest>=pWal->minFrame && iTest>0; iTest--){ if( walFramePgno(pWal, iTest)==pgno ){ iRead2 = iTest; break; @@ -56999,7 +64204,7 @@ SQLITE_PRIVATE int sqlite3WalReadFrame( return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset); } -/* +/* ** Return the size of the database in pages (or zero, if unknown). */ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){ @@ -57010,7 +64215,7 @@ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){ } -/* +/* ** This function starts a write transaction on the WAL. ** ** A read transaction must have already been started by a prior call @@ -57026,6 +64231,16 @@ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){ int rc; +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + /* If the write-lock is already held, then it was obtained before the + ** read-transaction was even opened, making this call a no-op. + ** Return early. */ + if( pWal->writeLock ){ + assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) ); + return SQLITE_OK; + } +#endif + /* Cannot start a write transaction without first holding a read ** transaction. */ assert( pWal->readLock>=0 ); @@ -57088,18 +64303,18 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p if( ALWAYS(pWal->writeLock) ){ Pgno iMax = pWal->hdr.mxFrame; Pgno iFrame; - + /* Restore the clients cache of the wal-index header to the state it - ** was in before the client began writing to the database. + ** was in before the client began writing to the database. */ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr)); - for(iFrame=pWal->hdr.mxFrame+1; - ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; + for(iFrame=pWal->hdr.mxFrame+1; + ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; iFrame++ ){ /* This call cannot fail. Unless the page for which the page number - ** is passed as the second argument is (a) in the cache and + ** is passed as the second argument is (a) in the cache and ** (b) has an outstanding reference, then xUndo is either a no-op ** (if (a) is false) or simply expels the page from the cache (if (b) ** is false). @@ -57117,10 +64332,10 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p return rc; } -/* -** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 -** values. This function populates the array with values required to -** "rollback" the write position of the WAL handle back to the current +/* +** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 +** values. This function populates the array with values required to +** "rollback" the write position of the WAL handle back to the current ** point in the event of a savepoint rollback (via WalSavepointUndo()). */ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){ @@ -57131,7 +64346,7 @@ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){ aWalData[3] = pWal->nCkpt; } -/* +/* ** Move the write position of the WAL back to the point identified by ** the values in the aWalData[] array. aWalData must point to an array ** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated @@ -57251,8 +64466,8 @@ static int walWriteToLog( iOffset += iFirstAmt; iAmt -= iFirstAmt; pContent = (void*)(iFirstAmt + (char*)pContent); - assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) ); - rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK); + assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 ); + rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags)); if( iAmt==0 || rc ) return rc; } rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset); @@ -57271,11 +64486,7 @@ static int walWriteOneFrame( int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ -#if defined(SQLITE_HAS_CODEC) - if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; -#else pData = pPage->pData; -#endif walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame); rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset); if( rc ) return rc; @@ -57337,7 +64548,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){ return rc; } -/* +/* ** Write a set of frames to the log. The caller must hold the write-lock ** on the log file (obtained using sqlite3WalBeginWriteTransaction()). */ @@ -57404,7 +64615,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum); sqlite3Put4byte(&aWalHdr[24], aCksum[0]); sqlite3Put4byte(&aWalHdr[28], aCksum[1]); - + pWal->szPage = szPage; pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN; pWal->hdr.aFrameCksum[0] = aCksum[0]; @@ -57422,10 +64633,10 @@ SQLITE_PRIVATE int sqlite3WalFrames( ** an out-of-order write following a WAL restart could result in ** database corruption. See the ticket: ** - ** http://localhost:591/sqlite/info/ff5be73dee + ** https://sqlite.org/src/info/ff5be73dee */ - if( pWal->syncHeader && sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK); + if( pWal->syncHeader ){ + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); if( rc ) return rc; } } @@ -57446,7 +64657,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( /* Check if this page has already been written into the wal file by ** the current transaction. If so, overwrite the existing frame and - ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that + ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that ** checksums must be recomputed when the transaction is committed. */ if( iFirst && (p->pDirty || isCommit==0) ){ u32 iWrite = 0; @@ -57458,11 +64669,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( if( pWal->iReCksum==0 || iWriteiReCksum ){ pWal->iReCksum = iWrite; } -#if defined(SQLITE_HAS_CODEC) - if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; -#else pData = p->pData; -#endif rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); if( rc ) return rc; p->flags &= ~PGHDR_WAL_APPEND; @@ -57500,7 +64707,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ - if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ + if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){ int bSync = 1; if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); @@ -57512,11 +64719,12 @@ SQLITE_PRIVATE int sqlite3WalFrames( if( rc ) return rc; iOffset += szFrame; nExtra++; + assert( pLast!=0 ); } } if( bSync ){ assert( rc==SQLITE_OK ); - rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK); + rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags)); } } @@ -57533,7 +64741,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( pWal->truncateOnCommit = 0; } - /* Append data to the wal-index. It is not necessary to lock the + /* Append data to the wal-index. It is not necessary to lock the ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index ** guarantees that there are no other writers, and no data that may ** be in use by existing readers is being overwritten. @@ -57544,6 +64752,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( iFrame++; rc = walIndexAppend(pWal, iFrame, p->pgno); } + assert( pLast!=0 || nExtra==0 ); while( rc==SQLITE_OK && nExtra>0 ){ iFrame++; nExtra--; @@ -57571,7 +64780,7 @@ SQLITE_PRIVATE int sqlite3WalFrames( return rc; } -/* +/* ** This routine is called to implement sqlite3_wal_checkpoint() and ** related interfaces. ** @@ -57608,45 +64817,52 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( if( pWal->readOnly ) return SQLITE_READONLY; WALTRACE(("WAL%p: checkpoint begins\n", pWal)); - /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive - ** "checkpoint" lock on the database file. */ - rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); - if( rc ){ - /* EVIDENCE-OF: R-10421-19736 If any other process is running a - ** checkpoint operation at the same time, the lock cannot be obtained and - ** SQLITE_BUSY is returned. - ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, - ** it will not be invoked in this case. - */ - testcase( rc==SQLITE_BUSY ); - testcase( xBusy!=0 ); - return rc; - } - pWal->ckptLock = 1; + /* Enable blocking locks, if possible. If blocking locks are successfully + ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */ + sqlite3WalDb(pWal, db); + (void)walEnableBlocking(pWal); - /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and - ** TRUNCATE modes also obtain the exclusive "writer" lock on the database - ** file. - ** - ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained - ** immediately, and a busy-handler is configured, it is invoked and the - ** writer lock retried until either the busy-handler returns 0 or the - ** lock is successfully obtained. + /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive + ** "checkpoint" lock on the database file. + ** EVIDENCE-OF: R-10421-19736 If any other process is running a + ** checkpoint operation at the same time, the lock cannot be obtained and + ** SQLITE_BUSY is returned. + ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured, + ** it will not be invoked in this case. */ - if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ - rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1); - if( rc==SQLITE_OK ){ - pWal->writeLock = 1; - }else if( rc==SQLITE_BUSY ){ - eMode2 = SQLITE_CHECKPOINT_PASSIVE; - xBusy2 = 0; - rc = SQLITE_OK; + rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); + testcase( rc==SQLITE_BUSY ); + testcase( rc!=SQLITE_OK && xBusy2!=0 ); + if( rc==SQLITE_OK ){ + pWal->ckptLock = 1; + + /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and + ** TRUNCATE modes also obtain the exclusive "writer" lock on the database + ** file. + ** + ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained + ** immediately, and a busy-handler is configured, it is invoked and the + ** writer lock retried until either the busy-handler returns 0 or the + ** lock is successfully obtained. + */ + if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ + rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1); + if( rc==SQLITE_OK ){ + pWal->writeLock = 1; + }else if( rc==SQLITE_BUSY ){ + eMode2 = SQLITE_CHECKPOINT_PASSIVE; + xBusy2 = 0; + rc = SQLITE_OK; + } } } + /* Read the wal-index header. */ if( rc==SQLITE_OK ){ + walDisableBlocking(pWal); rc = walIndexReadHdr(pWal, &isChanged); + (void)walEnableBlocking(pWal); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } @@ -57669,7 +64885,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( } if( isChanged ){ - /* If a new wal-index header was loaded before the checkpoint was + /* If a new wal-index header was loaded before the checkpoint was ** performed, then the pager-cache associated with pWal is now ** out of date. So zero the cached wal-index header to ensure that ** next time the pager opens a snapshot on this database it knows that @@ -57678,11 +64894,19 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); } + walDisableBlocking(pWal); + sqlite3WalDb(pWal, 0); + /* Release the locks. */ sqlite3WalEndWriteTransaction(pWal); - walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); - pWal->ckptLock = 0; + if( pWal->ckptLock ){ + walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); + pWal->ckptLock = 0; + } WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; +#endif return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc); } @@ -57712,7 +64936,7 @@ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){ ** operation must occur while the pager is still holding the exclusive ** lock on the main database file. ** -** If op is one, then change from locking_mode=NORMAL into +** If op is one, then change from locking_mode=NORMAL into ** locking_mode=EXCLUSIVE. This means that the pWal->readLock must ** be released. Return 1 if the transition is made and 0 if the ** WAL is already in exclusive-locking mode - meaning that this @@ -57729,8 +64953,8 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){ assert( pWal->writeLock==0 ); assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 ); - /* pWal->readLock is usually set, but might be -1 if there was a - ** prior error while attempting to acquire are read-lock. This cannot + /* pWal->readLock is usually set, but might be -1 if there was a + ** prior error while attempting to acquire are read-lock. This cannot ** happen if the connection is actually in exclusive mode (as no xShmLock ** locks are taken in this case). Nor should the pager attempt to ** upgrade to exclusive-mode following such an error. @@ -57739,32 +64963,32 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){ assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) ); if( op==0 ){ - if( pWal->exclusiveMode ){ - pWal->exclusiveMode = 0; + if( pWal->exclusiveMode!=WAL_NORMAL_MODE ){ + pWal->exclusiveMode = WAL_NORMAL_MODE; if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){ - pWal->exclusiveMode = 1; + pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } - rc = pWal->exclusiveMode==0; + rc = pWal->exclusiveMode==WAL_NORMAL_MODE; }else{ /* Already in locking_mode=NORMAL */ rc = 0; } }else if( op>0 ){ - assert( pWal->exclusiveMode==0 ); + assert( pWal->exclusiveMode==WAL_NORMAL_MODE ); assert( pWal->readLock>=0 ); walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock)); - pWal->exclusiveMode = 1; + pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; rc = 1; }else{ - rc = pWal->exclusiveMode==0; + rc = pWal->exclusiveMode==WAL_NORMAL_MODE; } return rc; } -/* +/* ** Return true if the argument is non-NULL and the WAL module is using ** heap-memory for the wal-index. Otherwise, if the argument is NULL or the -** WAL module is using shared-memory, return false. +** WAL module is using shared-memory, return false. */ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){ return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ); @@ -57799,11 +65023,14 @@ SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapsho /* Try to open on pSnapshot when the next read-transaction starts */ -SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){ +SQLITE_PRIVATE void sqlite3WalSnapshotOpen( + Wal *pWal, + sqlite3_snapshot *pSnapshot +){ pWal->pSnapshot = (WalIndexHdr*)pSnapshot; } -/* +/* ** Return a +ve value if snapshot p1 is newer than p2. A -ve value if ** p1 is older than p2 and zero if p1 and p2 are the same snapshot. */ @@ -57819,6 +65046,43 @@ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){ if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1; return 0; } + +/* +** The caller currently has a read transaction open on the database. +** This function takes a SHARED lock on the CHECKPOINTER slot and then +** checks if the snapshot passed as the second argument is still +** available. If so, SQLITE_OK is returned. +** +** If the snapshot is not available, SQLITE_ERROR is returned. Or, if +** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error +** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER +** lock is released before returning. +*/ +SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){ + int rc; + rc = walLockShared(pWal, WAL_CKPT_LOCK); + if( rc==SQLITE_OK ){ + WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot; + if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) + || pNew->mxFramenBackfillAttempted + ){ + rc = SQLITE_ERROR_SNAPSHOT; + walUnlockShared(pWal, WAL_CKPT_LOCK); + } + } + return rc; +} + +/* +** Release a lock obtained by an earlier successful call to +** sqlite3WalSnapshotCheck(). +*/ +SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal){ + assert( pWal ); + walUnlockShared(pWal, WAL_CKPT_LOCK); +} + + #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_ZIPVFS @@ -57893,16 +65157,16 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){ ** on Ptr(N) and its subpages have values greater than Key(N-1). And ** so forth. ** -** Finding a particular key requires reading O(log(M)) pages from the +** Finding a particular key requires reading O(log(M)) pages from the ** disk where M is the number of entries in the tree. ** -** In this implementation, a single file can hold one or more separate +** In this implementation, a single file can hold one or more separate ** BTrees. Each BTree is identified by the index of its root page. The ** key and data for any entry are combined to form the "payload". A ** fixed amount of payload can be carried directly on the database ** page. If the payload is larger than the preset amount then surplus ** bytes are stored on overflow pages. The payload for an entry -** and the preceding pointer are combined to form a "Cell". Each +** and the preceding pointer are combined to form a "Cell". Each ** page has a small header which contains the Ptr(N) pointer and other ** information such as the size of key and data. ** @@ -58032,7 +65296,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){ ** contiguous or in order, but cell pointers are contiguous and in order. ** ** Cell content makes use of variable length integers. A variable -** length integer is 1 to 9 bytes where the lower 7 bits of each +** length integer is 1 to 9 bytes where the lower 7 bits of each ** byte are used. The integer consists of all bytes that have bit 8 set and ** the first byte with bit 8 clear. The most significant byte of the integer ** appears first. A variable-length integer may not be more than 9 bytes long. @@ -58105,7 +65369,7 @@ typedef struct CellInfo CellInfo; ** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The ** header must be exactly 16 bytes including the zero-terminator so ** the string itself should be 15 characters long. If you change -** the header, then your custom library will not be able to read +** the header, then your custom library will not be able to read ** databases generated by the standard tools and the standard tools ** will not be able to read databases created by your custom library. */ @@ -58136,7 +65400,6 @@ typedef struct CellInfo CellInfo; */ struct MemPage { u8 isInit; /* True if previously initialized. MUST BE FIRST! */ - u8 bBusy; /* Prevent endless loops on corrupt database files */ u8 intKey; /* True if table b-trees. False for index b-trees */ u8 intKeyLeaf; /* True if the leaf of an intKey table */ Pgno pgno; /* Page number for this page */ @@ -58150,7 +65413,7 @@ struct MemPage { u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ - u16 nFree; /* Number of free bytes on the page */ + int nFree; /* Number of free bytes on the page. -1 for unknown */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th @@ -58158,7 +65421,9 @@ struct MemPage { u8 *apOvfl[4]; /* Pointers to the body of overflow cells */ BtShared *pBt; /* Pointer to BtShared that this page is part of */ u8 *aData; /* Pointer to disk image of the page data */ - u8 *aDataEnd; /* One byte past the end of usable data */ + u8 *aDataEnd; /* One byte past the end of the entire page - not just + ** the usable space, the entire page. Used to prevent + ** corruption-induced of buffer overflow. */ u8 *aCellIdx; /* The cell index area */ u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */ DbPage *pDbPage; /* Pager page handle */ @@ -58168,7 +65433,7 @@ struct MemPage { /* ** A linked list of the following structures is stored at BtShared.pLock. -** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor +** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor ** is opened on the table with root page BtShared.iTable. Locks are removed ** from this list when a transaction is committed or rolled back, or when ** a btree handle is closed. @@ -58192,7 +65457,7 @@ struct BtLock { ** see the internals of this structure and only deals with pointers to ** this structure. ** -** For some database files, the same underlying database cache might be +** For some database files, the same underlying database cache might be ** shared between multiple connections. In that case, each connection ** has it own instance of this object. But each instance of this object ** points to the same BtShared object. The database cache and the @@ -58200,7 +65465,7 @@ struct BtLock { ** the BtShared object. ** ** All fields in this structure are accessed under sqlite3.mutex. -** The pBt pointer itself may not be changed while there exists cursors +** The pBt pointer itself may not be changed while there exists cursors ** in the referenced BtShared that point back to this Btree since those ** cursors have to go through this Btree to find their BtShared and ** they often do so without holding sqlite3.mutex. @@ -58214,9 +65479,12 @@ struct Btree { u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ int nBackup; /* Number of backup operations reading this btree */ - u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */ + u32 iBDataVersion; /* Combines with pBt->pPager->iDataVersion */ Btree *pNext; /* List of other sharable Btrees from the same db */ Btree *pPrev; /* Back pointer of the same list */ +#ifdef SQLITE_DEBUG + u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */ +#endif #ifndef SQLITE_OMIT_SHARED_CACHE BtLock lock; /* Object used to lock page 1 */ #endif @@ -58228,14 +65496,28 @@ struct Btree { ** If the shared-data extension is enabled, there may be multiple users ** of the Btree structure. At most one of these may open a write transaction, ** but any number may have active read transactions. +** +** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and +** SQLITE_TXN_WRITE */ #define TRANS_NONE 0 #define TRANS_READ 1 #define TRANS_WRITE 2 +#if TRANS_NONE!=SQLITE_TXN_NONE +# error wrong numeric code for no-transaction +#endif +#if TRANS_READ!=SQLITE_TXN_READ +# error wrong numeric code for read-transaction +#endif +#if TRANS_WRITE!=SQLITE_TXN_WRITE +# error wrong numeric code for write-transaction +#endif + + /* ** An instance of this object represents a single database file. -** +** ** A single database file can be in use at the same time by two ** or more database connections. When two or more connections are ** sharing the same database file, each connection has it own @@ -58245,7 +65527,7 @@ struct Btree { ** ** Fields in this structure are accessed under the BtShared.mutex ** mutex, except for nRef and pNext which are accessed under the -** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field +** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field ** may not be modified once it is initially set as long as nRef>0. ** The pSchema field may be set once under BtShared.mutex and ** thereafter is unchanged as long as nRef>0. @@ -58281,9 +65563,7 @@ struct BtShared { #endif u8 inTransaction; /* Transaction state */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ -#ifdef SQLITE_HAS_CODEC - u8 optimalReserve; /* Desired amount of reserved space per page */ -#endif + u8 nReserveWanted; /* Desired number of extra bytes per page */ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ @@ -58304,6 +65584,7 @@ struct BtShared { Btree *pWriter; /* Btree with currently open write transaction */ #endif u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ + int nPreformatSize; /* Size of last cell written by TransferRow() */ }; /* @@ -58312,10 +65593,12 @@ struct BtShared { #define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */ #define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */ #define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */ -#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */ -#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */ -#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */ -#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */ +#define BTS_OVERWRITE 0x0008 /* Overwrite deleted content with zeros */ +#define BTS_FAST_SECURE 0x000c /* Combination of the previous two */ +#define BTS_INITIALLY_EMPTY 0x0010 /* Database was empty at trans start */ +#define BTS_NO_WAL 0x0020 /* Do not open write-ahead-log files */ +#define BTS_EXCLUSIVE 0x0040 /* pWriter has an exclusive lock */ +#define BTS_PENDING 0x0080 /* Waiting for read-locks to clear */ /* ** An instance of the following structure is used to hold information @@ -58353,38 +65636,46 @@ struct CellInfo { ** particular database connection identified BtCursor.pBtree.db. ** ** Fields in this structure are accessed under the BtShared.mutex -** found at self->pBt->mutex. +** found at self->pBt->mutex. ** ** skipNext meaning: -** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op. -** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op. -** eState==FAULT: Cursor fault with skipNext as error code. +** The meaning of skipNext depends on the value of eState: +** +** eState Meaning of skipNext +** VALID skipNext is meaningless and is ignored +** INVALID skipNext is meaningless and is ignored +** SKIPNEXT sqlite3BtreeNext() is a no-op if skipNext>0 and +** sqlite3BtreePrevious() is no-op if skipNext<0. +** REQUIRESEEK restoreCursorPosition() restores the cursor to +** eState=SKIPNEXT if skipNext!=0 +** FAULT skipNext holds the cursor fault error code. */ struct BtCursor { - Btree *pBtree; /* The Btree to which this cursor belongs */ - BtShared *pBt; /* The BtShared this cursor points to */ - BtCursor *pNext; /* Forms a linked list of all cursors */ - Pgno *aOverflow; /* Cache of overflow page locations */ - CellInfo info; /* A parse of the cell we are pointing at */ - i64 nKey; /* Size of pKey, or last integer key */ - void *pKey; /* Saved key that was cursor last known position */ - Pgno pgnoRoot; /* The root page of this tree */ - int nOvflAlloc; /* Allocated size of aOverflow[] array */ - int skipNext; /* Prev() is noop if negative. Next() is noop if positive. - ** Error code if eState==CURSOR_FAULT */ + u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ - u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 hints; /* As configured by CursorSetHints() */ + int skipNext; /* Prev() is noop if negative. Next() is noop if positive. + ** Error code if eState==CURSOR_FAULT */ + Btree *pBtree; /* The Btree to which this cursor belongs */ + Pgno *aOverflow; /* Cache of overflow page locations */ + void *pKey; /* Saved key that was cursor last known position */ /* All fields above are zeroed when the cursor is allocated. See ** sqlite3BtreeCursorZero(). Fields that follow must be manually ** initialized. */ +#define BTCURSOR_FIRST_UNINIT pBt /* Name of first uninitialized field */ + BtShared *pBt; /* The BtShared this cursor points to */ + BtCursor *pNext; /* Forms a linked list of all cursors */ + CellInfo info; /* A parse of the cell we are pointing at */ + i64 nKey; /* Size of pKey, or last integer key */ + Pgno pgnoRoot; /* The root page of this tree */ i8 iPage; /* Index of current page in apPage */ u8 curIntKey; /* Value of apPage[0]->intKey */ - struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ - void *padding1; /* Make object size a multiple of 16 */ - u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ - MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ + u16 ix; /* Current index for apPage[iPage] */ + u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */ + struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */ + MemPage *pPage; /* Current page */ + MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */ }; /* @@ -58396,12 +65687,13 @@ struct BtCursor { #define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */ #define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */ #define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */ +#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */ /* ** Potential values for BtCursor.eState. ** ** CURSOR_INVALID: -** Cursor does not point to a valid entry. This can happen (for example) +** Cursor does not point to a valid entry. This can happen (for example) ** because the table is empty or because BtreeCursorFirst() has not been ** called. ** @@ -58414,9 +65706,9 @@ struct BtCursor { ** operation should be a no-op. ** ** CURSOR_REQUIRESEEK: -** The table that this cursor was opened on still exists, but has been +** The table that this cursor was opened on still exists, but has been ** modified since the cursor was last used. The cursor position is saved -** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in +** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in ** this state, restoreCursorPosition() can be called to attempt to ** seek the cursor to the saved position. ** @@ -58427,19 +65719,19 @@ struct BtCursor { ** Do nothing else with this cursor. Any attempt to use the cursor ** should return the error code stored in BtCursor.skipNext */ -#define CURSOR_INVALID 0 -#define CURSOR_VALID 1 +#define CURSOR_VALID 0 +#define CURSOR_INVALID 1 #define CURSOR_SKIPNEXT 2 #define CURSOR_REQUIRESEEK 3 #define CURSOR_FAULT 4 -/* +/* ** The database page the PENDING_BYTE occupies. This page is never used. */ # define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt) /* -** These macros define the location of the pointer-map entry for a +** These macros define the location of the pointer-map entry for a ** database page. The first argument to each is the number of usable ** bytes on each page of the database (often 1024). The second is the ** page number to look up in the pointer map. @@ -58474,10 +65766,10 @@ struct BtCursor { ** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not ** used in this case. ** -** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number +** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number ** is not used in this case. ** -** PTRMAP_OVERFLOW1: The database page is the first page in a list of +** PTRMAP_OVERFLOW1: The database page is the first page in a list of ** overflow pages. The page number identifies the page that ** contains the cell with a pointer to this overflow page. ** @@ -58499,13 +65791,13 @@ struct BtCursor { */ #define btreeIntegrity(p) \ assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ - assert( p->pBt->inTransaction>=p->inTrans ); + assert( p->pBt->inTransaction>=p->inTrans ); /* ** The ISAUTOVACUUM macro is used within balance_nonroot() to determine ** if the database supports auto-vacuum or not. Because it is used -** within an expression that is an argument to another macro +** within an expression that is an argument to another macro ** (sqliteMallocRaw), it is not possible to use conditional compilation. ** So, this macro is defined instead. */ @@ -58522,8 +65814,8 @@ struct BtCursor { ** ** The aRef[] array is allocated so that there is 1 bit for each page in ** the database. As the integrity-check proceeds, for each page used in -** the database the corresponding bit is set. This allows integrity-check to -** detect pages that are used twice and orphaned pages (both of which +** the database the corresponding bit is set. This allows integrity-check to +** detect pages that are used twice and orphaned pages (both of which ** indicate corruption). */ typedef struct IntegrityCk IntegrityCk; @@ -58534,11 +65826,13 @@ struct IntegrityCk { Pgno nPage; /* Number of pages in the database */ int mxErr; /* Stop accumulating errors when this reaches zero */ int nErr; /* Number of messages written to zErrMsg so far */ - int mallocFailed; /* A memory allocation error has occurred */ + int bOomFault; /* A memory allocation error has occurred */ const char *zPfx; /* Error message prefix */ - int v1, v2; /* Values for up to two %d fields in zPfx */ + Pgno v1; /* Value for first %u substitution in zPfx */ + int v2; /* Value for second %d substitution in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ u32 *heap; /* Min-heap used for analyzing cell coverage */ + sqlite3 *db; /* Database connection running the check */ }; /* @@ -58745,10 +66039,10 @@ static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){ skipOk = 0; } } - db->skipBtreeMutex = skipOk; + db->noSharedCache = skipOk; } SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ - if( db->skipBtreeMutex==0 ) btreeEnterAll(db); + if( db->noSharedCache==0 ) btreeEnterAll(db); } static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){ int i; @@ -58760,7 +66054,7 @@ static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){ } } SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){ - if( db->skipBtreeMutex==0 ) btreeLeaveAll(db); + if( db->noSharedCache==0 ) btreeLeaveAll(db); } #ifndef NDEBUG @@ -58839,10 +66133,10 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){ #ifndef SQLITE_OMIT_INCRBLOB /* -** Enter a mutex on a Btree given a cursor owned by that Btree. +** Enter a mutex on a Btree given a cursor owned by that Btree. ** -** These entry points are used by incremental I/O only. Enter() is required -** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not +** These entry points are used by incremental I/O only. Enter() is required +** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not ** the build is threadsafe. Leave() is only required by threadsafe builds. */ SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){ @@ -58912,7 +66206,7 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */ #define BTALLOC_LE 2 /* Allocate any page <= the parameter */ /* -** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not +** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not ** defined, or 0 if it is. For example: ** ** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum); @@ -58927,10 +66221,10 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */ /* ** A list of BtShared objects that are eligible for participation ** in shared cache. This variable has file scope during normal builds, -** but the test harness needs to access it so we make it global for +** but the test harness needs to access it so we make it global for ** test builds. ** -** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER. +** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN. */ #ifdef SQLITE_TEST SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; @@ -58962,7 +66256,7 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){ ** manipulate entries in the BtShared.pLock linked list used to store ** shared-cache table level locks. If the library is compiled with the ** shared-cache feature disabled, then there is only ever one user - ** of each BtShared structure and so this locking is not necessary. + ** of each BtShared structure and so this locking is not necessary. ** So define the lock related functions as no-ops. */ #define querySharedCacheTableLock(a,b,c) SQLITE_OK @@ -58973,21 +66267,60 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){ #define hasReadConflicts(a, b) 0 #endif +#ifdef SQLITE_DEBUG +/* +** Return and reset the seek counter for a Btree object. +*/ +SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ + u64 n = pBt->nSeek; + pBt->nSeek = 0; + return n; +} +#endif + +/* +** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single +** (MemPage*) as an argument. The (MemPage*) must not be NULL. +** +** If SQLITE_DEBUG is not defined, then this macro is equivalent to +** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message +** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented +** with the page number and filename associated with the (MemPage*). +*/ +#ifdef SQLITE_DEBUG +int corruptPageError(int lineno, MemPage *p){ + char *zMsg; + sqlite3BeginBenignMalloc(); + zMsg = sqlite3_mprintf("database corruption page %d of %s", + (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0) + ); + sqlite3EndBenignMalloc(); + if( zMsg ){ + sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); + } + sqlite3_free(zMsg); + return SQLITE_CORRUPT_BKPT; +} +# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) +#else +# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) +#endif + #ifndef SQLITE_OMIT_SHARED_CACHE #ifdef SQLITE_DEBUG /* **** This function is only used as part of an assert() statement. *** ** -** Check to see if pBtree holds the required locks to read or write to the +** Check to see if pBtree holds the required locks to read or write to the ** table with root page iRoot. Return 1 if it does and 0 if not. ** -** For example, when writing to a table with root-page iRoot via +** For example, when writing to a table with root-page iRoot via ** Btree connection pBtree: ** ** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) ); ** -** When writing to an index that resides in a sharable database, the +** When writing to an index that resides in a sharable database, the ** caller should have first obtained a lock specifying the root page of ** the corresponding table. This makes things a bit more complicated, ** as this module treats each table as a separate structure. To determine @@ -59009,11 +66342,11 @@ static int hasSharedCacheTableLock( BtLock *pLock; /* If this database is not shareable, or if the client is reading - ** and has the read-uncommitted flag set, then no lock is required. + ** and has the read-uncommitted flag set, then no lock is required. ** Return true immediately. */ if( (pBtree->sharable==0) - || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) + || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit)) ){ return 1; } @@ -59033,29 +66366,31 @@ static int hasSharedCacheTableLock( ** table. */ if( isIndex ){ HashElem *p; + int bSeen = 0; for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){ Index *pIdx = (Index *)sqliteHashData(p); if( pIdx->tnum==(int)iRoot ){ - if( iTab ){ + if( bSeen ){ /* Two or more indexes share the same root page. There must ** be imposter tables. So just return true. The assert is not ** useful in that case. */ return 1; } iTab = pIdx->pTable->tnum; + bSeen = 1; } } }else{ iTab = iRoot; } - /* Search for the required lock. Either a write-lock on root-page iTab, a + /* Search for the required lock. Either a write-lock on root-page iTab, a ** write-lock on the schema table, or (if the client is reading) a ** read-lock on iTab will suffice. Return 1 if any of these are found. */ for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){ - if( pLock->pBtree==pBtree + if( pLock->pBtree==pBtree && (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1)) - && pLock->eLock>=eLockType + && pLock->eLock>=eLockType ){ return 1; } @@ -59088,9 +66423,9 @@ static int hasSharedCacheTableLock( static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ BtCursor *p; for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - if( p->pgnoRoot==iRoot + if( p->pgnoRoot==iRoot && p->pBtree!=pBtree - && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted) + && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit) ){ return 1; } @@ -59100,7 +66435,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ #endif /* #ifdef SQLITE_DEBUG */ /* -** Query to see if Btree handle p may obtain a lock of type eLock +** Query to see if Btree handle p may obtain a lock of type eLock ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return ** SQLITE_OK if the lock may be obtained (by calling ** setSharedCacheTableLock()), or SQLITE_LOCKED if not. @@ -59112,15 +66447,15 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); - assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 ); - + assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 ); + /* If requesting a write-lock, then the Btree must have an open write - ** transaction on this file. And, obviously, for this to be so there + ** transaction on this file. And, obviously, for this to be so there ** must be an open write transaction on the file itself. */ assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) ); assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE ); - + /* This routine is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; @@ -59135,7 +66470,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ } for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ - /* The condition (pIter->eLock!=eLock) in the following if(...) + /* The condition (pIter->eLock!=eLock) in the following if(...) ** statement is a simplification of: ** ** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK) @@ -59162,7 +66497,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Add a lock on the table with root-page iTable to the shared-btree used -** by Btree handle p. Parameter eLock must be either READ_LOCK or +** by Btree handle p. Parameter eLock must be either READ_LOCK or ** WRITE_LOCK. ** ** This function assumes the following: @@ -59174,7 +66509,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ ** with the requested lock (i.e. querySharedCacheTableLock() has ** already been called and returned SQLITE_OK). ** -** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM +** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM ** is returned if a malloc attempt fails. */ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ @@ -59188,11 +66523,11 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ /* A connection with the read-uncommitted flag set will never try to ** obtain a read-lock using this function. The only read-lock obtained - ** by a connection in read-uncommitted mode is on the sqlite_master + ** by a connection in read-uncommitted mode is on the sqlite_schema ** table, and that lock is obtained in BtreeBeginTrans(). */ - assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK ); + assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK ); - /* This function should only be called on a sharable b-tree after it + /* This function should only be called on a sharable b-tree after it ** has been determined that no other b-tree holds a conflicting lock. */ assert( p->sharable ); assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) ); @@ -59237,7 +66572,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ ** Release all the table locks (locks obtained via calls to ** the setSharedCacheTableLock() procedure) held by Btree object p. ** -** This function assumes that Btree p has an open read or write +** This function assumes that Btree p has an open read or write ** transaction. If it does not, then the BTS_PENDING flag ** may be incorrectly cleared. */ @@ -59269,7 +66604,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){ pBt->pWriter = 0; pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING); }else if( pBt->nTransaction==2 ){ - /* This function is called when Btree p is concluding its + /* This function is called when Btree p is concluding its ** transaction. If there currently exists a writer, and p is not ** that writer, then the number of locks held by connections other ** than the writer must be about to drop to zero. In this case @@ -59300,7 +66635,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){ #endif /* SQLITE_OMIT_SHARED_CACHE */ -static void releasePage(MemPage *pPage); /* Forward reference */ +static void releasePage(MemPage *pPage); /* Forward reference */ +static void releasePageOne(MemPage *pPage); /* Forward reference */ +static void releasePageNotNull(MemPage *pPage); /* Forward reference */ /* ***** This routine is used inside of assert() only **** @@ -59313,7 +66650,7 @@ static int cursorHoldsMutex(BtCursor *p){ } /* Verify that the cursor and the BtShared agree about what is the current -** database connetion. This is important in shared-cache mode. If the database +** database connetion. This is important in shared-cache mode. If the database ** connection pointers get out-of-sync, it is possible for routines like ** btreeInitPage() to reference an stale connection pointer that references a ** a connection that has already closed. This routine is used inside assert() @@ -59360,17 +66697,18 @@ static void invalidateAllOverflowCache(BtShared *pBt){ */ static void invalidateIncrblobCursors( Btree *pBtree, /* The database file to check */ + Pgno pgnoRoot, /* The table that might be changing */ i64 iRow, /* The rowid that might be changing */ int isClearTable /* True if all rows are being deleted */ ){ BtCursor *p; - if( pBtree->hasIncrblobCur==0 ) return; + assert( pBtree->hasIncrblobCur ); assert( sqlite3BtreeHoldsMutex(pBtree) ); pBtree->hasIncrblobCur = 0; for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( (p->curFlags & BTCF_Incrblob)!=0 ){ pBtree->hasIncrblobCur = 1; - if( isClearTable || p->info.nKey==iRow ){ + if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; } } @@ -59379,12 +66717,12 @@ static void invalidateIncrblobCursors( #else /* Stub function when INCRBLOB is omitted */ - #define invalidateIncrblobCursors(x,y,z) + #define invalidateIncrblobCursors(w,x,y,z) #endif /* SQLITE_OMIT_INCRBLOB */ /* -** Set bit pgno of the BtShared.pHasContent bitvec. This is called -** when a page that previously contained data becomes a free-list leaf +** Set bit pgno of the BtShared.pHasContent bitvec. This is called +** when a page that previously contained data becomes a free-list leaf ** page. ** ** The BtShared.pHasContent bitvec exists to work around an obscure @@ -59410,7 +66748,7 @@ static void invalidateIncrblobCursors( ** may be lost. In the event of a rollback, it may not be possible ** to restore the database to its original configuration. ** -** The solution is the BtShared.pHasContent bitvec. Whenever a page is +** The solution is the BtShared.pHasContent bitvec. Whenever a page is ** moved to become a free-list leaf page, the corresponding bit is ** set in the bitvec. Whenever a leaf page is extracted from the free-list, ** optimization 2 above is omitted if the corresponding bit is already @@ -59441,7 +66779,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){ */ static int btreeGetHasContent(BtShared *pBt, Pgno pgno){ Bitvec *p = pBt->pHasContent; - return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno))); + return p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTestNotNull(p, pgno)); } /* @@ -59458,24 +66796,26 @@ static void btreeClearHasContent(BtShared *pBt){ */ static void btreeReleaseAllCursorPages(BtCursor *pCur){ int i; - for(i=0; i<=pCur->iPage; i++){ - releasePage(pCur->apPage[i]); - pCur->apPage[i] = 0; + if( pCur->iPage>=0 ){ + for(i=0; iiPage; i++){ + releasePageNotNull(pCur->apPage[i]); + } + releasePageNotNull(pCur->pPage); + pCur->iPage = -1; } - pCur->iPage = -1; } /* ** The cursor passed as the only argument must point to a valid entry ** when this function is called (i.e. have eState==CURSOR_VALID). This ** function saves the current cursor key in variables pCur->nKey and -** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error +** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error ** code otherwise. ** ** If the cursor is open on an intkey table, then the integer key ** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to -** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is -** set to point to a malloced buffer pCur->nKey bytes in size containing +** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is +** set to point to a malloced buffer pCur->nKey bytes in size containing ** the key. */ static int saveCursorKey(BtCursor *pCur){ @@ -59488,13 +66828,19 @@ static int saveCursorKey(BtCursor *pCur){ /* Only the rowid is required for a table btree */ pCur->nKey = sqlite3BtreeIntegerKey(pCur); }else{ - /* For an index btree, save the complete key content */ + /* For an index btree, save the complete key content. It is possible + ** that the current key is corrupt. In that case, it is possible that + ** the sqlite3VdbeRecordUnpack() function may overread the buffer by + ** up to the size of 1 varint plus 1 8-byte value when the cursor + ** position is restored. Hence the 17 bytes of padding allocated + ** below. */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); - pKey = sqlite3Malloc( pCur->nKey ); + pKey = sqlite3Malloc( pCur->nKey + 9 + 8 ); if( pKey ){ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ + memset(((u8*)pKey)+pCur->nKey, 0, 9+8); pCur->pKey = pKey; }else{ sqlite3_free(pKey); @@ -59508,11 +66854,11 @@ static int saveCursorKey(BtCursor *pCur){ } /* -** Save the current cursor position in the variables BtCursor.nKey +** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. ** ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) -** prior to calling this routine. +** prior to calling this routine. */ static int saveCursorPosition(BtCursor *pCur){ int rc; @@ -59521,6 +66867,9 @@ static int saveCursorPosition(BtCursor *pCur){ assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); + if( pCur->curFlags & BTCF_Pinned ){ + return SQLITE_CONSTRAINT_PINNED; + } if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; }else{ @@ -59548,7 +66897,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*); ** routine is called just before cursor pExcept is used to modify the ** table, for example in BtreeDelete() or BtreeInsert(). ** -** If there are two or more cursors on the same btree, then all such +** If there are two or more cursors on the same btree, then all such ** cursors should have their BTCF_Multiple flag set. The btreeCursor() ** routine enforces that rule. This routine only needs to be called in ** the uncommon case when pExpect has the BTCF_Multiple flag set. @@ -59591,7 +66940,7 @@ static int SQLITE_NOINLINE saveCursorsOnList( return rc; } }else{ - testcase( p->iPage>0 ); + testcase( p->iPage>=0 ); btreeReleaseAllCursorPages(p); } } @@ -59626,47 +66975,50 @@ static int btreeMoveto( UnpackedRecord *pIdxKey; /* Unpacked index key */ if( pKey ){ + KeyInfo *pKeyInfo = pCur->pKeyInfo; assert( nKey==(i64)(int)nKey ); - pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo); + pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; - sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey); - if( pIdxKey->nField==0 ){ + sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); + if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ rc = SQLITE_CORRUPT_BKPT; - goto moveto_done; + }else{ + rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); } + sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); }else{ pIdxKey = 0; - } - rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); -moveto_done: - if( pIdxKey ){ - sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); + rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes); } return rc; } /* ** Restore the cursor to the position it was in (or as close to as possible) -** when saveCursorPosition() was called. Note that this call deletes the +** when saveCursorPosition() was called. Note that this call deletes the ** saved position info stored by saveCursorPosition(), so there can be -** at most one effective restoreCursorPosition() call after each +** at most one effective restoreCursorPosition() call after each ** saveCursorPosition(). */ static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; - int skipNext; + int skipNext = 0; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; } pCur->eState = CURSOR_INVALID; - rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + if( sqlite3FaultSim(410) ){ + rc = SQLITE_IOERR; + }else{ + rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + } if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); - pCur->skipNext |= skipNext; + if( skipNext ) pCur->skipNext = skipNext; if( pCur->skipNext && pCur->eState==CURSOR_VALID ){ pCur->eState = CURSOR_SKIPNEXT; } @@ -59692,13 +67044,28 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){ ** back to where it ought to be if this routine returns true. */ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){ - return pCur->eState!=CURSOR_VALID; + assert( EIGHT_BYTE_ALIGNMENT(pCur) + || pCur==sqlite3BtreeFakeValidCursor() ); + assert( offsetof(BtCursor, eState)==0 ); + assert( sizeof(pCur->eState)==1 ); + return CURSOR_VALID != *(u8*)pCur; +} + +/* +** Return a pointer to a fake BtCursor object that will always answer +** false to the sqlite3BtreeCursorHasMoved() routine above. The fake +** cursor returned must not be used with any other Btree interface. +*/ +SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){ + static u8 fakeCursor = CURSOR_VALID; + assert( offsetof(BtCursor, eState)==0 ); + return (BtCursor*)&fakeCursor; } /* ** This routine restores a cursor back to its original position after it ** has been moved by some outside activity (such as a btree rebalance or -** a row having been deleted out from under the cursor). +** a row having been deleted out from under the cursor). ** ** On success, the *pDifferentRow parameter is false if the cursor is left ** pointing at exactly the same row. *pDifferntRow is the row the cursor @@ -59721,7 +67088,6 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow) if( pCur->eState!=CURSOR_VALID ){ *pDifferentRow = 1; }else{ - assert( pCur->skipNext==0 ); *pDifferentRow = 0; } return SQLITE_OK; @@ -59764,7 +67130,7 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ if( pgno<2 ) return 0; nPagesPerMapPage = (pBt->usableSize/5)+1; iPtrMap = (pgno-2)/nPagesPerMapPage; - ret = (iPtrMap*nPagesPerMapPage) + 2; + ret = (iPtrMap*nPagesPerMapPage) + 2; if( ret==PENDING_BYTE_PAGE(pBt) ){ ret++; } @@ -59791,7 +67157,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ if( *pRC ) return; assert( sqlite3_mutex_held(pBt->mutex) ); - /* The master-journal page number must never be used as a pointer map page */ + /* The super-journal page number must never be used as a pointer map page */ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); assert( pBt->autoVacuum ); @@ -59805,6 +67171,13 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ *pRC = rc; return; } + if( ((char*)sqlite3PagerGetExtra(pDbPage))[0]!=0 ){ + /* The first byte of the extra data is the MemPage.isInit byte. + ** If that byte is set, it means this page is also being used + ** as a btree page. */ + *pRC = SQLITE_CORRUPT_BKPT; + goto ptrmap_exit; + } offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ *pRC = SQLITE_CORRUPT_BKPT; @@ -59860,14 +67233,14 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); sqlite3PagerUnref(pDbPage); - if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; + if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); return SQLITE_OK; } #else /* if defined SQLITE_OMIT_AUTOVACUUM */ #define ptrmapPut(w,x,y,z,rc) #define ptrmapGet(w,x,y,z) SQLITE_OK - #define ptrmapPutOvflPtr(x, y, rc) + #define ptrmapPutOvflPtr(x, y, z, rc) #endif /* @@ -59923,6 +67296,24 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; } +/* +** Given a record with nPayload bytes of payload stored within btree +** page pPage, return the number of bytes of payload stored locally. +*/ +static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){ + int maxLocal; /* Maximum amount of payload held locally */ + maxLocal = pPage->maxLocal; + if( nPayload<=maxLocal ){ + return nPayload; + }else{ + int minLocal; /* Minimum amount of payload held locally */ + int surplus; /* Overflow payload available for local storage */ + minLocal = pPage->minLocal; + surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4); + return ( surplus <= maxLocal ) ? surplus : minLocal; + } +} + /* ** The following routines are implementations of the MemPage.xParseCell() ** method. @@ -59989,18 +67380,32 @@ static void btreeParseCellPtr( ** ** pIter += getVarint(pIter, (u64*)&pInfo->nKey); ** - ** The code is inlined to avoid a function call. + ** The code is inlined and the loop is unrolled for performance. + ** This routine is a high-runner. */ iKey = *pIter; if( iKey>=0x80 ){ - u8 *pEnd = &pIter[7]; - iKey &= 0x7f; - while(1){ - iKey = (iKey<<7) | (*++pIter & 0x7f); - if( (*pIter)<0x80 ) break; - if( pIter>=pEnd ){ - iKey = (iKey<<8) | *++pIter; - break; + u8 x; + iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x =*++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<7) | ((x = *++pIter) & 0x7f); + if( x>=0x80 ){ + iKey = (iKey<<8) | (*++pIter); + } + } + } + } + } } } } @@ -60010,7 +67415,7 @@ static void btreeParseCellPtr( pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); - testcase( nPayload==pPage->maxLocal+1 ); + testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. @@ -60047,7 +67452,7 @@ static void btreeParseCellPtrIndex( pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); - testcase( nPayload==pPage->maxLocal+1 ); + testcase( nPayload==(u32)pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. @@ -60103,14 +67508,14 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ } pIter++; if( pPage->intKey ){ - /* pIter now points at the 64-bit integer key value, a variable length + /* pIter now points at the 64-bit integer key value, a variable length ** integer. The following block moves pIter to point at the first byte ** past the end of the key value. */ pEnd = &pIter[9]; while( (*pIter++)&0x80 && pItermaxLocal ); - testcase( nSize==pPage->maxLocal+1 ); + testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize<=pPage->maxLocal ){ nSize += (u32)(pIter - pCell); if( nSize<4 ) nSize = 4; @@ -60118,7 +67523,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); - testcase( nSize==pPage->maxLocal+1 ); + testcase( nSize==(u32)pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ nSize = minLocal; } @@ -60160,17 +67565,24 @@ static u16 cellSize(MemPage *pPage, int iCell){ #ifndef SQLITE_OMIT_AUTOVACUUM /* -** If the cell pCell, part of page pPage contains a pointer -** to an overflow page, insert an entry into the pointer-map -** for the overflow page. +** The cell pCell is currently part of page pSrc but will ultimately be part +** of pPage. (pSrc and pPager are often the same.) If pCell contains a +** pointer to an overflow page, insert an entry into the pointer-map for +** the overflow page that will be valid after pCell has been moved to pPage. */ -static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ +static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ CellInfo info; if( *pRC ) return; assert( pCell!=0 ); pPage->xParseCell(pPage, pCell, &info); if( info.nLocalaDataEnd, pCell, pCell+info.nLocal) ){ + testcase( pSrc!=pPage ); + *pRC = SQLITE_CORRUPT_BKPT; + return; + } + ovfl = get4byte(&pCell[info.nSize-4]); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); } } @@ -60178,17 +67590,18 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ /* -** Defragment the page given. All Cells are moved to the -** end of the page and all free space is collected into one -** big FreeBlk that occurs in between the header and cell -** pointer array and the cell content area. +** Defragment the page given. This routine reorganizes cells within the +** page so that there are no free-blocks on the free-block list. +** +** Parameter nMaxFrag is the maximum amount of fragmented space that may be +** present in the page after this routine returns. ** ** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a ** b-tree page so that there are no freeblocks or fragment bytes, all ** unused bytes are contained in the unallocated space region, and all ** cells are packed tightly at the end of the page. */ -static int defragmentPage(MemPage *pPage){ +static int defragmentPage(MemPage *pPage, int nMaxFrag){ int i; /* Loop counter */ int pc; /* Address of the i-th cell */ int hdr; /* Offset to the page header */ @@ -60202,7 +67615,7 @@ static int defragmentPage(MemPage *pPage){ unsigned char *src; /* Source of content */ int iCellFirst; /* First allowable cell index */ int iCellLast; /* Last possible cell index */ - + int iCellStart; /* First cell offset in input */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt!=0 ); @@ -60214,11 +67627,56 @@ static int defragmentPage(MemPage *pPage){ hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; - assert( nCell==get2byte(&data[hdr+3]) ); + assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB ); + iCellFirst = cellOffset + 2*nCell; usableSize = pPage->pBt->usableSize; + + /* This block handles pages with two or fewer free blocks and nMaxFrag + ** or fewer fragmented bytes. In this case it is faster to move the + ** two (or one) blocks of cells using memmove() and add the required + ** offsets to each pointer in the cell-pointer array than it is to + ** reconstruct the entire page. */ + if( (int)data[hdr+7]<=nMaxFrag ){ + int iFree = get2byte(&data[hdr+1]); + if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); + if( iFree ){ + int iFree2 = get2byte(&data[iFree]); + if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); + if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ + u8 *pEnd = &data[cellOffset + nCell*2]; + u8 *pAddr; + int sz2 = 0; + int sz = get2byte(&data[iFree+2]); + int top = get2byte(&data[hdr+5]); + if( top>=iFree ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + if( iFree2 ){ + if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); + sz2 = get2byte(&data[iFree2+2]); + if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); + memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); + sz += sz2; + }else if( NEVER(iFree+sz>usableSize) ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + + cbrk = top+sz; + assert( cbrk+(iFree-top) <= usableSize ); + memmove(&data[cbrk], &data[top], iFree-top); + for(pAddr=&data[cellOffset]; pAddriCellLast ){ - return SQLITE_CORRUPT_BKPT; + if( pciCellLast ){ + return SQLITE_CORRUPT_PAGE(pPage); } - assert( pc>=iCellFirst && pc<=iCellLast ); + assert( pc>=iCellStart && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; - if( cbrkusableSize ){ - return SQLITE_CORRUPT_BKPT; + if( cbrkusableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); } - assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); + assert( cbrk+size<=usableSize && cbrk>=iCellStart ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); put2byte(pAddr, cbrk); if( temp==0 ){ - int x; if( cbrk==pc ) continue; temp = sqlite3PagerTempSpace(pPage->pBt->pPager); - x = get2byte(&data[hdr+5]); - memcpy(&temp[x], &data[x], (cbrk+size) - x); + memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart); src = temp; } memcpy(&data[cbrk], &src[pc], size); } + data[hdr+7] = 0; + + defragment_out: + assert( pPage->nFree>=0 ); + if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ + return SQLITE_CORRUPT_PAGE(pPage); + } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); data[hdr+1] = 0; data[hdr+2] = 0; - data[hdr+7] = 0; memset(&data[iCellFirst], 0, cbrk-iCellFirst); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); - if( cbrk-iCellFirst!=pPage->nFree ){ - return SQLITE_CORRUPT_BKPT; - } return SQLITE_OK; } @@ -60279,22 +67738,16 @@ static int defragmentPage(MemPage *pPage){ ** causes the fragmentation count to exceed 60. */ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ - const int hdr = pPg->hdrOffset; - u8 * const aData = pPg->aData; - int iAddr = hdr + 1; - int pc = get2byte(&aData[iAddr]); - int x; - int usableSize = pPg->pBt->usableSize; + const int hdr = pPg->hdrOffset; /* Offset to page header */ + u8 * const aData = pPg->aData; /* Page data */ + int iAddr = hdr + 1; /* Address of ptr to pc */ + int pc = get2byte(&aData[iAddr]); /* Address of a free slot */ + int x; /* Excess size of the slot */ + int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */ + int size; /* Size of the free slot */ assert( pc>0 ); - do{ - int size; /* Size of the free slot */ - /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of - ** increasing offset. */ - if( pc>usableSize-4 || pc=0 ){ testcase( x==4 ); testcase( x==3 ); - if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){ - *pRc = SQLITE_CORRUPT_BKPT; - return 0; - }else if( x<4 ){ + if( x<4 ){ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total ** number of bytes in fragments may not exceed 60. */ if( aData[hdr+7]>57 ) return 0; @@ -60314,17 +67764,31 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ ** fragmented bytes within the page. */ memcpy(&aData[iAddr], &aData[pc], 2); aData[hdr+7] += (u8)x; + }else if( x+pc > maxPC ){ + /* This slot extends off the end of the usable part of the page */ + *pRc = SQLITE_CORRUPT_PAGE(pPg); + return 0; }else{ /* The slot remains on the free-list. Reduce its size to account - ** for the portion used by the new allocation. */ + ** for the portion used by the new allocation. */ put2byte(&aData[pc+2], x); } return &aData[pc + x]; } iAddr = pc; pc = get2byte(&aData[pc]); - }while( pc ); - + if( pc<=iAddr+size ){ + if( pc ){ + /* The next slot in the chain is not past the end of the current slot */ + *pRc = SQLITE_CORRUPT_PAGE(pPg); + } + return 0; + } + } + if( pc>maxPC+nByte-4 ){ + /* The free slot chain extends off the end of the page */ + *pRc = SQLITE_CORRUPT_PAGE(pPg); + } return 0; } @@ -60347,7 +67811,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ int top; /* First byte of cell content area */ int rc = SQLITE_OK; /* Integer return code */ int gap; /* First byte of gap between cell pointers and cell content */ - + assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); @@ -60365,18 +67829,18 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** However, that integer is too large to be stored in a 2-byte unsigned ** integer, so a value of 0 is used in its place. */ top = get2byte(&data[hdr+5]); - assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */ + assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */ if( gap>top ){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; }else{ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PAGE(pPage); } } - /* If there is enough space between gap and top for one more cell pointer - ** array entry offset, and if the freelist is not empty, then search the - ** freelist looking for a free slot big enough to satisfy the request. + /* If there is enough space between gap and top for one more cell pointer, + ** and if the freelist is not empty, then search the + ** freelist looking for a slot big enough to satisfy the request. */ testcase( gap+2==top ); testcase( gap+1==top ); @@ -60384,9 +67848,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){ u8 *pSpace = pageFindSlot(pPage, nByte, &rc); if( pSpace ){ - assert( pSpace>=data && (pSpace - data)<65536 ); - *pIdx = (int)(pSpace - data); - return SQLITE_OK; + int g2; + assert( pSpace+nByte<=data+pPage->pBt->usableSize ); + *pIdx = g2 = (int)(pSpace-data); + if( g2<=gap ){ + return SQLITE_CORRUPT_PAGE(pPage); + }else{ + return SQLITE_OK; + } }else if( rc ){ return rc; } @@ -60398,15 +67867,16 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ assert( pPage->nCell>0 || CORRUPT_DB ); - rc = defragmentPage(pPage); + assert( pPage->nFree>=0 ); + rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); - assert( gap+nByte<=top ); + assert( gap+2+nByte<=top ); } /* Allocate memory from the gap in between the cell pointer array - ** and the cell content area. The btreeInitPage() call has already + ** and the cell content area. The btreeComputeFreeSpace() call has already ** validated the freelist. Given that the freelist is valid, there ** is no way that the allocation can extend off the end of the page. ** The assert() below verifies the previous sentence. @@ -60425,7 +67895,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** ** Adjacent freeblocks are coalesced. ** -** Note that even though the freeblock list was checked by btreeInitPage(), +** Even though the freeblock list was checked by btreeComputeFreeSpace(), ** that routine will not detect overlap between cells or freeblocks. Nor ** does it detect cells or freeblocks that encrouch into the reserved bytes ** at the end of the page. So do additional corruption checks inside this @@ -60437,7 +67907,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ u8 hdr; /* Page header size. 0 or 100 */ u8 nFrag = 0; /* Reduction in fragmentation */ u16 iOrigSize = iSize; /* Original value of iSize */ - u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */ + u16 x; /* Offset to cell content area */ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ @@ -60447,15 +67917,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ - assert( iStart<=iLast ); + assert( iStart<=pPage->pBt->usableSize-4 ); - /* Overwrite deleted information with zeros when the secure_delete - ** option is enabled */ - if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){ - memset(&data[iStart], 0, iSize); - } - - /* The list of freeblocks must be in ascending order. Find the + /* The list of freeblocks must be in ascending order. Find the ** spot on the list where iStart should be inserted. */ hdr = pPage->hdrOffset; @@ -60465,14 +67929,16 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ }else{ while( (iFreeBlk = get2byte(&data[iPtr]))iLast ) return SQLITE_CORRUPT_BKPT; - assert( iFreeBlk>iPtr || iFreeBlk==0 ); - + if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ + return SQLITE_CORRUPT_PAGE(pPage); + } + assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); + /* At this point: ** iFreeBlk: First freeblock after iStart, or zero if none ** iPtr: The address of a pointer to iFreeBlk @@ -60481,13 +67947,15 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ */ if( iFreeBlk && iEnd+3>=iFreeBlk ){ nFrag = iFreeBlk - iEnd; - if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT; + if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); - if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT; + if( iEnd > pPage->pBt->usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); + } iSize = iEnd - iStart; iFreeBlk = get2byte(&data[iFreeBlk]); } - + /* If iPtr is another freeblock (that is, if iPtr is not the freelist ** pointer in the page header) then check to see if iStart should be ** coalesced onto the end of iPtr. @@ -60495,28 +67963,35 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ if( iPtr>hdr+1 ){ int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); if( iPtrEnd+3>=iStart ){ - if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT; + if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); nFrag += iStart - iPtrEnd; iSize = iEnd - iPtr; iStart = iPtr; } } - if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT; + if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); data[hdr+7] -= nFrag; } - if( iStart==get2byte(&data[hdr+5]) ){ + x = get2byte(&data[hdr+5]); + if( iStart<=x ){ /* The new freeblock is at the beginning of the cell content area, ** so just extend the cell content area rather than create another ** freelist entry */ - if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT; + if( iStartpBt->btsFlags & BTS_FAST_SECURE ){ + /* Overwrite deleted information with zeros when the secure_delete + ** option is enabled */ + memset(&data[iStart], 0, iSize); + } + put2byte(&data[iStart], iFreeBlk); + put2byte(&data[iStart+2], iSize); pPage->nFree += iOrigSize; return SQLITE_OK; } @@ -60576,22 +68051,142 @@ static int decodeFlags(MemPage *pPage, int flagByte){ }else{ /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is ** an error. */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PAGE(pPage); } pPage->max1bytePayload = pBt->max1bytePayload; return SQLITE_OK; } +/* +** Compute the amount of freespace on the page. In other words, fill +** in the pPage->nFree field. +*/ +static int btreeComputeFreeSpace(MemPage *pPage){ + int pc; /* Address of a freeblock within pPage->aData[] */ + u8 hdr; /* Offset to beginning of page header */ + u8 *data; /* Equal to pPage->aData */ + int usableSize; /* Amount of usable space on each page */ + int nFree; /* Number of unused bytes on the page */ + int top; /* First byte of the cell content area */ + int iCellFirst; /* First allowable cell or freeblock offset */ + int iCellLast; /* Last possible cell or freeblock offset */ + + assert( pPage->pBt!=0 ); + assert( pPage->pBt->db!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==1 ); + assert( pPage->nFree<0 ); + + usableSize = pPage->pBt->usableSize; + hdr = pPage->hdrOffset; + data = pPage->aData; + /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates + ** the start of the cell content area. A zero value for this integer is + ** interpreted as 65536. */ + top = get2byteNotZero(&data[hdr+5]); + iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell; + iCellLast = usableSize - 4; + + /* Compute the total free space on the page + ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the + ** start of the first freeblock on the page, or is zero if there are no + ** freeblocks. */ + pc = get2byte(&data[hdr+1]); + nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ + if( pc>0 ){ + u32 next, size; + if( pciCellLast ){ + /* Freeblock off the end of the page */ + return SQLITE_CORRUPT_PAGE(pPage); + } + next = get2byte(&data[pc]); + size = get2byte(&data[pc+2]); + nFree = nFree + size; + if( next<=pc+size+3 ) break; + pc = next; + } + if( next>0 ){ + /* Freeblock not in ascending order */ + return SQLITE_CORRUPT_PAGE(pPage); + } + if( pc+size>(unsigned int)usableSize ){ + /* Last freeblock extends past page end */ + return SQLITE_CORRUPT_PAGE(pPage); + } + } + + /* At this point, nFree contains the sum of the offset to the start + ** of the cell-content area plus the number of free bytes within + ** the cell-content area. If this is greater than the usable-size + ** of the page, then the page must be corrupted. This check also + ** serves to verify that the offset to the start of the cell-content + ** area, according to the page header, lies within the page. + */ + if( nFree>usableSize || nFreenFree = (u16)(nFree - iCellFirst); + return SQLITE_OK; +} + +/* +** Do additional sanity check after btreeInitPage() if +** PRAGMA cell_size_check=ON +*/ +static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ + int iCellFirst; /* First allowable cell or freeblock offset */ + int iCellLast; /* Last possible cell or freeblock offset */ + int i; /* Index into the cell pointer array */ + int sz; /* Size of a cell */ + int pc; /* Address of a freeblock within pPage->aData[] */ + u8 *data; /* Equal to pPage->aData */ + int usableSize; /* Maximum usable space on the page */ + int cellOffset; /* Start of cell content area */ + + iCellFirst = pPage->cellOffset + 2*pPage->nCell; + usableSize = pPage->pBt->usableSize; + iCellLast = usableSize - 4; + data = pPage->aData; + cellOffset = pPage->cellOffset; + if( !pPage->leaf ) iCellLast--; + for(i=0; inCell; i++){ + pc = get2byteAligned(&data[cellOffset+i*2]); + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); + if( pciCellLast ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + } + return SQLITE_OK; +} + /* ** Initialize the auxiliary information for a disk block. ** ** Return SQLITE_OK on success. If we see that the page does -** not contain a well-formed database page, then return +** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ static int btreeInitPage(MemPage *pPage){ + u8 *data; /* Equal to pPage->aData */ + BtShared *pBt; /* The main btree structure */ assert( pPage->pBt!=0 ); assert( pPage->pBt->db!=0 ); @@ -60599,126 +68194,41 @@ static int btreeInitPage(MemPage *pPage){ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==0 ); - if( !pPage->isInit ){ - int pc; /* Address of a freeblock within pPage->aData[] */ - u8 hdr; /* Offset to beginning of page header */ - u8 *data; /* Equal to pPage->aData */ - BtShared *pBt; /* The main btree structure */ - int usableSize; /* Amount of usable space on each page */ - u16 cellOffset; /* Offset from start of page to first cell pointer */ - int nFree; /* Number of unused bytes on the page */ - int top; /* First byte of the cell content area */ - int iCellFirst; /* First allowable cell or freeblock offset */ - int iCellLast; /* Last possible cell or freeblock offset */ - - pBt = pPage->pBt; - - hdr = pPage->hdrOffset; - data = pPage->aData; - /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating - ** the b-tree page type. */ - if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; - assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); - pPage->maskPage = (u16)(pBt->pageSize - 1); - pPage->nOverflow = 0; - usableSize = pBt->usableSize; - pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; - pPage->aDataEnd = &data[usableSize]; - pPage->aCellIdx = &data[cellOffset]; - pPage->aDataOfst = &data[pPage->childPtrSize]; - /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates - ** the start of the cell content area. A zero value for this integer is - ** interpreted as 65536. */ - top = get2byteNotZero(&data[hdr+5]); - /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the - ** number of cells on the page. */ - pPage->nCell = get2byte(&data[hdr+3]); - if( pPage->nCell>MX_CELL(pBt) ){ - /* To many cells for a single page. The page must be corrupt */ - return SQLITE_CORRUPT_BKPT; - } - testcase( pPage->nCell==MX_CELL(pBt) ); - /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only - ** possible for a root page of a table that contains no rows) then the - ** offset to the cell content area will equal the page size minus the - ** bytes of reserved space. */ - assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); - - /* A malformed database page might cause us to read past the end - ** of page when parsing a cell. - ** - ** The following block of code checks early to see if a cell extends - ** past the end of a page boundary and causes SQLITE_CORRUPT to be - ** returned if it does. - */ - iCellFirst = cellOffset + 2*pPage->nCell; - iCellLast = usableSize - 4; - if( pBt->db->flags & SQLITE_CellSizeCk ){ - int i; /* Index into the cell pointer array */ - int sz; /* Size of a cell */ - - if( !pPage->leaf ) iCellLast--; - for(i=0; inCell; i++){ - pc = get2byteAligned(&data[cellOffset+i*2]); - testcase( pc==iCellFirst ); - testcase( pc==iCellLast ); - if( pciCellLast ){ - return SQLITE_CORRUPT_BKPT; - } - sz = pPage->xCellSize(pPage, &data[pc]); - testcase( pc+sz==usableSize ); - if( pc+sz>usableSize ){ - return SQLITE_CORRUPT_BKPT; - } - } - if( !pPage->leaf ) iCellLast++; - } - - /* Compute the total free space on the page - ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the - ** start of the first freeblock on the page, or is zero if there are no - ** freeblocks. */ - pc = get2byte(&data[hdr+1]); - nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */ - if( pc>0 ){ - u32 next, size; - if( pciCellLast ){ - return SQLITE_CORRUPT_BKPT; /* Freeblock off the end of the page */ - } - next = get2byte(&data[pc]); - size = get2byte(&data[pc+2]); - nFree = nFree + size; - if( next<=pc+size+3 ) break; - pc = next; - } - if( next>0 ){ - return SQLITE_CORRUPT_BKPT; /* Freeblock not in ascending order */ - } - if( pc+size>(unsigned int)usableSize ){ - return SQLITE_CORRUPT_BKPT; /* Last freeblock extends past page end */ - } - } - - /* At this point, nFree contains the sum of the offset to the start - ** of the cell-content area plus the number of free bytes within - ** the cell-content area. If this is greater than the usable-size - ** of the page, then the page must be corrupted. This check also - ** serves to verify that the offset to the start of the cell-content - ** area, according to the page header, lies within the page. - */ - if( nFree>usableSize ){ - return SQLITE_CORRUPT_BKPT; - } - pPage->nFree = (u16)(nFree - iCellFirst); - pPage->isInit = 1; + pBt = pPage->pBt; + data = pPage->aData + pPage->hdrOffset; + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ + if( decodeFlags(pPage, data[0]) ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nOverflow = 0; + pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; + pPage->aCellIdx = data + pPage->childPtrSize + 8; + pPage->aDataEnd = pPage->aData + pBt->pageSize; + pPage->aDataOfst = pPage->aData + pPage->childPtrSize; + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ + pPage->nCell = get2byte(&data[3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* To many cells for a single page. The page must be corrupt */ + return SQLITE_CORRUPT_PAGE(pPage); + } + testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only + ** possible for a root page of a table that contains no rows) then the + ** offset to the cell content area will equal the page size minus the + ** bytes of reserved space. */ + assert( pPage->nCell>0 + || get2byteNotZero(&data[5])==(int)pBt->usableSize + || CORRUPT_DB ); + pPage->nFree = -1; /* Indicate that this value is yet uncomputed */ + pPage->isInit = 1; + if( pBt->db->flags & SQLITE_CellSizeCk ){ + return btreeCellSizeCheck(pPage); } return SQLITE_OK; } @@ -60733,12 +68243,12 @@ static void zeroPage(MemPage *pPage, int flags){ u8 hdr = pPage->hdrOffset; u16 first; - assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); + assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pBt->mutex) ); - if( pBt->btsFlags & BTS_SECURE_DELETE ){ + if( pBt->btsFlags & BTS_FAST_SECURE ){ memset(&data[hdr], 0, pBt->usableSize - hdr); } data[hdr] = (char)flags; @@ -60749,7 +68259,7 @@ static void zeroPage(MemPage *pPage, int flags){ pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); pPage->cellOffset = first; - pPage->aDataEnd = &data[pBt->usableSize]; + pPage->aDataEnd = &data[pBt->pageSize]; pPage->aCellIdx = &data[first]; pPage->aDataOfst = &data[pPage->childPtrSize]; pPage->nOverflow = 0; @@ -60774,7 +68284,7 @@ static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){ pPage->hdrOffset = pgno==1 ? 100 : 0; } assert( pPage->aData==sqlite3PagerGetData(pDbPage) ); - return pPage; + return pPage; } /* @@ -60827,9 +68337,8 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){ static Pgno btreePagecount(BtShared *pBt){ return pBt->nPage; } -SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){ +SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); - assert( ((p->pBt->nPage)&0x8000000)==0 ); return btreePagecount(p->pBt); } @@ -60856,41 +68365,44 @@ static int getAndInitPage( int rc; DbPage *pDbPage; assert( sqlite3_mutex_held(pBt->mutex) ); - assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] ); + assert( pCur==0 || ppPage==&pCur->pPage ); assert( pCur==0 || bReadOnly==pCur->curPagerFlags ); assert( pCur==0 || pCur->iPage>0 ); if( pgno>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; - goto getAndInitPage_error; + goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); if( rc ){ - goto getAndInitPage_error; + goto getAndInitPage_error1; } *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); if( (*ppPage)->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ - releasePage(*ppPage); - goto getAndInitPage_error; + goto getAndInitPage_error2; } } - assert( (*ppPage)->pgno==pgno ); + assert( (*ppPage)->pgno==pgno || CORRUPT_DB ); assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) ); /* If obtaining a child page for a cursor, we must verify that the page is ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ - rc = SQLITE_CORRUPT_BKPT; - releasePage(*ppPage); - goto getAndInitPage_error; + rc = SQLITE_CORRUPT_PGNO(pgno); + goto getAndInitPage_error2; } return SQLITE_OK; -getAndInitPage_error: - if( pCur ) pCur->iPage--; +getAndInitPage_error2: + releasePage(*ppPage); +getAndInitPage_error1: + if( pCur ){ + pCur->iPage--; + pCur->pPage = pCur->apPage[pCur->iPage]; + } testcase( pgno==0 ); assert( pgno!=0 || rc==SQLITE_CORRUPT ); return rc; @@ -60899,6 +68411,8 @@ static int getAndInitPage( /* ** Release a MemPage. This should be called once for each prior ** call to btreeGetPage. +** +** Page1 is a special case and must be released using releasePageOne(). */ static void releasePageNotNull(MemPage *pPage){ assert( pPage->aData ); @@ -60912,6 +68426,16 @@ static void releasePageNotNull(MemPage *pPage){ static void releasePage(MemPage *pPage){ if( pPage ) releasePageNotNull(pPage); } +static void releasePageOne(MemPage *pPage){ + assert( pPage!=0 ); + assert( pPage->aData ); + assert( pPage->pBt ); + assert( pPage->pDbPage!=0 ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + sqlite3PagerUnrefPageOne(pPage->pDbPage); +} /* ** Get an unused page. @@ -60982,11 +68506,11 @@ static int btreeInvokeBusyHandler(void *pArg){ /* ** Open a database file. -** +** ** zFilename is the name of the database file. If zFilename is NULL ** then an ephemeral database is created. The ephemeral database might ** be exclusively in memory, or it might use a disk-based memory cache. -** Either way, the ephemeral database will be automatically deleted +** Either way, the ephemeral database will be automatically deleted ** when sqlite3BtreeClose() is called. ** ** If zFilename is ":memory:" then an in-memory database is created @@ -61019,7 +68543,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( /* True if opening an ephemeral, temporary database */ const int isTempDb = zFilename==0 || zFilename[0]==0; - /* Set the variable isMemdb to true for an in-memory database, or + /* Set the variable isMemdb to true for an in-memory database, or ** false for a file-based database. */ #ifdef SQLITE_OMIT_MEMORYDB @@ -61081,15 +68605,19 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); if( rc ){ - sqlite3_free(zFullPathname); - sqlite3_free(p); - return rc; + if( rc==SQLITE_OK_SYMLINK ){ + rc = SQLITE_OK; + }else{ + sqlite3_free(zFullPathname); + sqlite3_free(p); + return rc; + } } } #if SQLITE_THREADSAFE mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); sqlite3_mutex_enter(mutexOpen); - mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); sqlite3_mutex_enter(mutexShared); #endif for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){ @@ -61138,7 +68666,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( assert( sizeof(u32)==4 ); assert( sizeof(u16)==2 ); assert( sizeof(Pgno)==4 ); - + pBt = sqlite3MallocZero( sizeof(*pBt) ); if( pBt==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -61155,14 +68683,16 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( } pBt->openFlags = (u8)flags; pBt->db = db; - sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt); + sqlite3PagerSetBusyHandler(pBt->pPager, btreeInvokeBusyHandler, pBt); p->pBt = pBt; - + pBt->pCursor = 0; pBt->pPage1 = 0; if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY; -#ifdef SQLITE_SECURE_DELETE +#if defined(SQLITE_SECURE_DELETE) pBt->btsFlags |= BTS_SECURE_DELETE; +#elif defined(SQLITE_FAST_SECURE_DELETE) + pBt->btsFlags |= BTS_OVERWRITE; #endif /* EVIDENCE-OF: R-51873-39618 The page size for a database file is ** determined by the 2-byte integer located at an offset of 16 bytes from @@ -61199,14 +68729,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( if( rc ) goto btree_open_out; pBt->usableSize = pBt->pageSize - nReserve; assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ - + #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ pBt->nRef = 1; if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) - MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);) + MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ @@ -61271,7 +68801,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( ** do not change the pager-cache size. */ if( sqlite3BtreeSchema(p, 0, 0)==0 ){ - sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE); + sqlite3BtreeSetCacheSize(p, SQLITE_DEFAULT_CACHE_SIZE); } pFile = sqlite3PagerFile(pBt->pPager); @@ -61295,13 +68825,13 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( */ static int removeFromSharingList(BtShared *pBt){ #ifndef SQLITE_OMIT_SHARED_CACHE - MUTEX_LOGIC( sqlite3_mutex *pMaster; ) + MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) BtShared *pList; int removed = 0; assert( sqlite3_mutex_notheld(pBt->mutex) ); - MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) - sqlite3_mutex_enter(pMaster); + MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) + sqlite3_mutex_enter(pMainMtx); pBt->nRef--; if( pBt->nRef<=0 ){ if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){ @@ -61320,7 +68850,7 @@ static int removeFromSharingList(BtShared *pBt){ } removed = 1; } - sqlite3_mutex_leave(pMaster); + sqlite3_mutex_leave(pMainMtx); return removed; #else return 1; @@ -61328,34 +68858,42 @@ static int removeFromSharingList(BtShared *pBt){ } /* -** Make sure pBt->pTmpSpace points to an allocation of +** Make sure pBt->pTmpSpace points to an allocation of ** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child ** pointer. */ -static void allocateTempSpace(BtShared *pBt){ - if( !pBt->pTmpSpace ){ - pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); - - /* One of the uses of pBt->pTmpSpace is to format cells before - ** inserting them into a leaf page (function fillInCell()). If - ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes - ** by the various routines that manipulate binary cells. Which - ** can mean that fillInCell() only initializes the first 2 or 3 - ** bytes of pTmpSpace, but that the first 4 bytes are copied from - ** it into a database page. This is not actually a problem, but it - ** does cause a valgrind error when the 1 or 2 bytes of unitialized - ** data is passed to system call write(). So to avoid this error, - ** zero the first 4 bytes of temp space here. - ** - ** Also: Provide four bytes of initialized space before the - ** beginning of pTmpSpace as an area available to prepend the - ** left-child pointer to the beginning of a cell. - */ - if( pBt->pTmpSpace ){ - memset(pBt->pTmpSpace, 0, 8); - pBt->pTmpSpace += 4; - } +static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){ + assert( pBt!=0 ); + assert( pBt->pTmpSpace==0 ); + /* This routine is called only by btreeCursor() when allocating the + ** first write cursor for the BtShared object */ + assert( pBt->pCursor!=0 && (pBt->pCursor->curFlags & BTCF_WriteFlag)!=0 ); + pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); + if( pBt->pTmpSpace==0 ){ + BtCursor *pCur = pBt->pCursor; + pBt->pCursor = pCur->pNext; /* Unlink the cursor */ + memset(pCur, 0, sizeof(*pCur)); + return SQLITE_NOMEM_BKPT; } + + /* One of the uses of pBt->pTmpSpace is to format cells before + ** inserting them into a leaf page (function fillInCell()). If + ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes + ** by the various routines that manipulate binary cells. Which + ** can mean that fillInCell() only initializes the first 2 or 3 + ** bytes of pTmpSpace, but that the first 4 bytes are copied from + ** it into a database page. This is not actually a problem, but it + ** does cause a valgrind error when the 1 or 2 bytes of unitialized + ** data is passed to system call write(). So to avoid this error, + ** zero the first 4 bytes of temp space here. + ** + ** Also: Provide four bytes of initialized space before the + ** beginning of pTmpSpace as an area available to prepend the + ** left-child pointer to the beginning of a cell. + */ + memset(pBt->pTmpSpace, 0, 8); + pBt->pTmpSpace += 4; + return SQLITE_OK; } /* @@ -61374,19 +68912,23 @@ static void freeTempSpace(BtShared *pBt){ */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; - BtCursor *pCur; /* Close all cursors opened via this handle. */ assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); - pCur = pBt->pCursor; - while( pCur ){ - BtCursor *pTmp = pCur; - pCur = pCur->pNext; - if( pTmp->pBtree==p ){ - sqlite3BtreeCloseCursor(pTmp); + + /* Verify that no other cursors have this Btree open */ +#ifdef SQLITE_DEBUG + { + BtCursor *pCur = pBt->pCursor; + while( pCur ){ + BtCursor *pTmp = pCur; + pCur = pCur->pNext; + assert( pTmp->pBtree!=p ); + } } +#endif /* Rollback any active transaction and free the handle structure. ** The call to sqlite3BtreeRollback() drops any table-locks held by @@ -61396,7 +68938,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){ sqlite3BtreeLeave(p); /* If there are still other outstanding references to the shared-btree - ** structure, return now. The remainder of this procedure cleans + ** structure, return now. The remainder of this procedure cleans ** up the shared-btree. */ assert( p->wantToLock==0 && p->locked==0 ); @@ -61502,7 +69044,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags( /* ** Change the default pages size and the number of reserved bytes per page. -** Or, if the page size has already been fixed, return SQLITE_READONLY +** Or, if the page size has already been fixed, return SQLITE_READONLY ** without changing anything. ** ** The page size must be a power of 2 between 512 and 65536. If the page @@ -61522,24 +69064,23 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags( */ SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){ int rc = SQLITE_OK; + int x; BtShared *pBt = p->pBt; - assert( nReserve>=-1 && nReserve<=255 ); + assert( nReserve>=0 && nReserve<=255 ); sqlite3BtreeEnter(p); -#if SQLITE_HAS_CODEC - if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve; -#endif + pBt->nReserveWanted = nReserve; + x = pBt->pageSize - pBt->usableSize; + if( nReservebtsFlags & BTS_PAGESIZE_FIXED ){ sqlite3BtreeLeave(p); return SQLITE_READONLY; } - if( nReserve<0 ){ - nReserve = pBt->pageSize - pBt->usableSize; - } assert( nReserve>=0 && nReserve<=255 ); if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); assert( !pBt->pCursor ); + if( nReserve>32 && pageSize==512 ) pageSize = 1024; pBt->pageSize = (u32)pageSize; freeTempSpace(pBt); } @@ -61563,7 +69104,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){ ** held. ** ** This is useful in one special case in the backup API code where it is -** known that the shared b-tree mutex is held, but the mutex on the +** known that the shared b-tree mutex is held, but the mutex on the ** database handle that owns *p is not. In this case if sqlite3BtreeEnter() ** were to be called, it might collide with some other operation on the ** database handle that owns *p, causing undefined behavior. @@ -61580,19 +69121,17 @@ SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){ ** are intentually left unused. This is the "reserved" space that is ** sometimes used by extensions. ** -** If SQLITE_HAS_MUTEX is defined then the number returned is the -** greater of the current reserved space and the maximum requested -** reserve space. +** The value returned is the larger of the current reserve size and +** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES. +** The amount of reserve can only grow - never shrink. */ -SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){ - int n; +SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){ + int n1, n2; sqlite3BtreeEnter(p); - n = sqlite3BtreeGetReserveNoMutex(p); -#ifdef SQLITE_HAS_CODEC - if( npBt->optimalReserve ) n = p->pBt->optimalReserve; -#endif + n1 = (int)p->pBt->nReserveWanted; + n2 = sqlite3BtreeGetReserveNoMutex(p); sqlite3BtreeLeave(p); - return n; + return n1>n2 ? n1 : n2; } @@ -61601,8 +69140,8 @@ SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){ ** No changes are made if mxPage is 0 or negative. ** Regardless of the value of mxPage, return the maximum page count. */ -SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ - int n; +SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){ + Pgno n; sqlite3BtreeEnter(p); n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); sqlite3BtreeLeave(p); @@ -61610,19 +69149,34 @@ SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ } /* -** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1. If newFlag is -1, -** then make no changes. Always return the value of the BTS_SECURE_DELETE -** setting after the change. +** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags: +** +** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared +** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared +** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set +** newFlag==(-1) No changes +** +** This routine acts as a query if newFlag is less than zero +** +** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but +** freelist leaf pages are not written back to the database. Thus in-page +** deleted content is cleared, but freelist deleted content is not. +** +** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition +** that freelist leaf pages are written back into the database, increasing +** the amount of disk I/O. */ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ int b; if( p==0 ) return 0; sqlite3BtreeEnter(p); + assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 ); + assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) ); if( newFlag>=0 ){ - p->pBt->btsFlags &= ~BTS_SECURE_DELETE; - if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE; - } - b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0; + p->pBt->btsFlags &= ~BTS_FAST_SECURE; + p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag; + } + b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE; sqlite3BtreeLeave(p); return b; } @@ -61630,7 +69184,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){ /* ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' ** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it -** is disabled. The default value for the auto-vacuum property is +** is disabled. The default value for the auto-vacuum property is ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. */ SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ @@ -61654,7 +69208,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ } /* -** Return the value of the 'auto-vacuum' property. If auto-vacuum is +** Return the value of the 'auto-vacuum' property. If auto-vacuum is ** enabled 1 is returned. Otherwise 0. */ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ @@ -61673,6 +69227,36 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ #endif } +/* +** If the user has not set the safety-level for this database connection +** using "PRAGMA synchronous", and if the safety-level is not already +** set to the value passed to this function as the second parameter, +** set it so. +*/ +#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \ + && !defined(SQLITE_OMIT_WAL) +static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){ + sqlite3 *db; + Db *pDb; + if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){ + while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; } + if( pDb->bSyncSet==0 + && pDb->safety_level!=safety_level + && pDb!=&db->aDb[1] + ){ + pDb->safety_level = safety_level; + sqlite3PagerSetFlags(pBt->pPager, + pDb->safety_level | (db->flags & PAGER_FLAGS_MASK)); + } + } +} +#else +# define setDefaultSyncFlag(pBt,safety_level) +#endif + +/* Forward declaration */ +static int newDatabase(BtShared*); + /* ** Get a reference to pPage1 of the database file. This will @@ -61681,14 +69265,13 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){ ** SQLITE_OK is returned on success. If the file is not a ** well-formed database file, then SQLITE_CORRUPT is returned. ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM -** is returned if we run out of memory. +** is returned if we run out of memory. */ static int lockBtree(BtShared *pBt){ int rc; /* Result code from subfunctions */ MemPage *pPage1; /* Page 1 of the database file */ - int nPage; /* Number of pages in the database */ - int nPageFile = 0; /* Number of pages in the database file */ - int nPageHeader; /* Number of pages in the database according to hdr */ + u32 nPage; /* Number of pages in the database */ + u32 nPageFile = 0; /* Number of pages in the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); @@ -61698,13 +69281,16 @@ static int lockBtree(BtShared *pBt){ if( rc!=SQLITE_OK ) return rc; /* Do some checking to help insure the file we opened really is - ** a valid database file. + ** a valid database file. */ - nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData); - sqlite3PagerPagecount(pBt->pPager, &nPageFile); + nPage = get4byte(28+(u8*)pPage1->aData); + sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile); if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){ nPage = nPageFile; } + if( (pBt->db->flags & SQLITE_ResetDatabase)!=0 ){ + nPage = 0; + } if( nPage>0 ){ u32 pageSize; u32 usableSize; @@ -61732,8 +69318,8 @@ static int lockBtree(BtShared *pBt){ goto page1_init_failed; } - /* If the write version is set to 2, this database should be accessed - ** in WAL mode. If the log is not already open, open it now. Then + /* If the read version is set to 2, this database should be accessed + ** in WAL mode. If the log is not already open, open it now. Then ** return SQLITE_OK and return without populating BtShared.pPage1. ** The caller detects this and calls this function again. This is ** required as the version of page 1 currently in the page1 buffer @@ -61746,26 +69332,15 @@ static int lockBtree(BtShared *pBt){ if( rc!=SQLITE_OK ){ goto page1_init_failed; }else{ -#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS - sqlite3 *db; - Db *pDb; - if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){ - while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; } - if( pDb->bSyncSet==0 - && pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1 - ){ - pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1; - sqlite3PagerSetFlags(pBt->pPager, - pDb->safety_level | (db->flags & PAGER_FLAGS_MASK)); - } - } -#endif + setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1); if( isOpen==0 ){ - releasePage(pPage1); + releasePageOne(pPage1); return SQLITE_OK; } } rc = SQLITE_NOTADB; + }else{ + setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1); } #endif @@ -61785,15 +69360,16 @@ static int lockBtree(BtShared *pBt){ /* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two ** between 512 and 65536 inclusive. */ if( ((pageSize-1)&pageSize)!=0 - || pageSize>SQLITE_MAX_PAGE_SIZE - || pageSize<=256 + || pageSize>SQLITE_MAX_PAGE_SIZE + || pageSize<=256 ){ goto page1_init_failed; } + pBt->btsFlags |= BTS_PAGESIZE_FIXED; assert( (pageSize & 7)==0 ); /* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte ** integer at offset 20 is the number of bytes of space at the end of - ** each page to reserve for extensions. + ** each page to reserve for extensions. ** ** EVIDENCE-OF: R-37497-42412 The size of the reserved region is ** determined by the one-byte unsigned integer found at an offset of 20 @@ -61806,7 +69382,7 @@ static int lockBtree(BtShared *pBt){ ** zero and return SQLITE_OK. The caller will call this function ** again with the correct page-size. */ - releasePage(pPage1); + releasePageOne(pPage1); pBt->usableSize = usableSize; pBt->pageSize = pageSize; freeTempSpace(pBt); @@ -61814,9 +69390,13 @@ static int lockBtree(BtShared *pBt){ pageSize-usableSize); return rc; } - if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){ - rc = SQLITE_CORRUPT_BKPT; - goto page1_init_failed; + if( nPage>nPageFile ){ + if( sqlite3WritableSchema(pBt->db)==0 ){ + rc = SQLITE_CORRUPT_BKPT; + goto page1_init_failed; + }else{ + nPage = nPageFile; + } } /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to ** be less than 480. In other words, if the page size is 512, then the @@ -61860,7 +69440,7 @@ static int lockBtree(BtShared *pBt){ return SQLITE_OK; page1_init_failed: - releasePage(pPage1); + releasePageOne(pPage1); pBt->pPage1 = 0; return rc; } @@ -61883,7 +69463,7 @@ static int countValidCursors(BtShared *pBt, int wrOnly){ int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0) - && pCur->eState!=CURSOR_FAULT ) r++; + && pCur->eState!=CURSOR_FAULT ) r++; } return r; } @@ -61892,7 +69472,7 @@ static int countValidCursors(BtShared *pBt, int wrOnly){ /* ** If there are no outstanding cursors and we are not in the middle ** of a transaction but there is a read lock on the database, then -** this routine unrefs the first page of the database file which +** this routine unrefs the first page of the database file which ** has the effect of releasing the read lock. ** ** If there is a transaction in progress, this routine is a no-op. @@ -61905,7 +69485,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){ assert( pPage1->aData ); assert( sqlite3PagerRefcount(pBt->pPager)==1 ); pBt->pPage1 = 0; - releasePageNotNull(pPage1); + releasePageOne(pPage1); } } @@ -61976,8 +69556,8 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ ** upgraded to exclusive by calling this routine a second time - the ** exclusivity flag only works for a new transaction. ** -** A write-transaction must be started before attempting any -** changes to the database. None of the following routines +** A write-transaction must be started before attempting any +** changes to the database. None of the following routines ** will work unless a transaction is started first: ** ** sqlite3BtreeCreateTable() @@ -61991,7 +69571,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ ** If an initial attempt to acquire the lock fails because of lock contention ** and the database was previously unlocked, then invoke the busy handler ** if there is one. But if there was previously a read-lock, do not -** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is +** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is ** returned when there is already a read-lock in order to avoid a deadlock. ** ** Suppose there are two processes A and B. A has a read lock and B has @@ -62002,8 +69582,9 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){ ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ -SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ +SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){ BtShared *pBt = p->pBt; + Pager *pPager = pBt->pPager; int rc = SQLITE_OK; sqlite3BtreeEnter(p); @@ -62018,6 +69599,12 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 ); + if( (p->db->flags & SQLITE_ResetDatabase) + && sqlite3PagerIsreadonly(pPager)==0 + ){ + pBt->btsFlags &= ~BTS_READ_ONLY; + } + /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; @@ -62027,7 +69614,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ #ifndef SQLITE_OMIT_SHARED_CACHE { sqlite3 *pBlock = 0; - /* If another database handle has already opened a write transaction + /* If another database handle has already opened a write transaction ** on this shared-btree structure and a second write transaction is ** requested, return SQLITE_LOCKED. */ @@ -62052,19 +69639,31 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } #endif - /* Any read-only or read-write transaction implies a read-lock on - ** page 1. So if some other shared-cache client already has a write-lock + /* Any read-only or read-write transaction implies a read-lock on + ** page 1. So if some other shared-cache client already has a write-lock ** on page 1, the transaction cannot be opened. */ - rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK); + rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK); if( SQLITE_OK!=rc ) goto trans_begun; pBt->btsFlags &= ~BTS_INITIALLY_EMPTY; if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY; do { + sqlite3PagerWalDb(pPager, p->db); + +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + /* If transitioning from no transaction directly to a write transaction, + ** block for the WRITER lock first if possible. */ + if( pBt->pPage1==0 && wrflag ){ + assert( pBt->inTransaction==TRANS_NONE ); + rc = sqlite3PagerWalWriteLock(pPager, 1); + if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break; + } +#endif + /* Call lockBtree() until either pBt->pPage1 is populated or ** lockBtree() returns something other than SQLITE_OK. lockBtree() ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after - ** reading page 1 it discovers that the page-size of the database + ** reading page 1 it discovers that the page-size of the database ** file is not pBt->pageSize. In this case lockBtree() will update ** pBt->pageSize to the page-size of the file on disk. */ @@ -62074,18 +69673,28 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){ rc = SQLITE_READONLY; }else{ - rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db)); + rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db)); if( rc==SQLITE_OK ){ rc = newDatabase(pBt); + }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){ + /* if there was no transaction opened when this function was + ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error + ** code to SQLITE_BUSY. */ + rc = SQLITE_BUSY; } } } - + if( rc!=SQLITE_OK ){ + (void)sqlite3PagerWalWriteLock(pPager, 0); unlockBtreeIfUnused(pBt); } }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); + sqlite3PagerWalDb(pPager, 0); +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT + if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; +#endif if( rc==SQLITE_OK ){ if( p->inTrans==TRANS_NONE ){ @@ -62114,7 +69723,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ /* If the db-size header field is incorrect (as it may be if an old ** client has been writing the database file), update it now. Doing - ** this sooner rather than later means the database size can safely + ** this sooner rather than later means the database size can safely ** re-read the database size from page 1 if a savepoint or transaction ** rollback occurs within the transaction. */ @@ -62127,14 +69736,18 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ } } - trans_begun: - if( rc==SQLITE_OK && wrflag ){ - /* This call makes sure that the pager has the correct number of - ** open savepoints. If the second parameter is greater than 0 and - ** the sub-journal is not already open, then it will be opened here. - */ - rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); + if( rc==SQLITE_OK ){ + if( pSchemaVersion ){ + *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]); + } + if( wrflag ){ + /* This call makes sure that the pager has the correct number of + ** open savepoints. If the second parameter is greater than 0 and + ** the sub-journal is not already open, then it will be opened here. + */ + rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); + } } btreeIntegrity(p); @@ -62157,14 +69770,14 @@ static int setChildPtrmaps(MemPage *pPage){ Pgno pgno = pPage->pgno; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - rc = btreeInitPage(pPage); + rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc!=SQLITE_OK ) return rc; nCell = pPage->nCell; for(i=0; ileaf ){ Pgno childPgno = get4byte(pCell); @@ -62185,7 +69798,7 @@ static int setChildPtrmaps(MemPage *pPage){ ** that it points to iTo. Parameter eType describes the type of pointer to ** be modified, as follows: ** -** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child +** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child ** page of pPage. ** ** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow @@ -62200,7 +69813,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ if( eType==PTRMAP_OVERFLOW2 ){ /* The pointer is always the first 4 bytes of the page in this case. */ if( get4byte(pPage->aData)!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PAGE(pPage); } put4byte(pPage->aData, iTo); }else{ @@ -62208,7 +69821,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ int nCell; int rc; - rc = btreeInitPage(pPage); + rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage); if( rc ) return rc; nCell = pPage->nCell; @@ -62219,7 +69832,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ pPage->xParseCell(pPage, pCell, &info); if( info.nLocal pPage->aData+pPage->pBt->usableSize ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PAGE(pPage); } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); @@ -62233,11 +69846,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ } } } - + if( i==nCell ){ - if( eType!=PTRMAP_BTREE || + if( eType!=PTRMAP_BTREE || get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PAGE(pPage); } put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); } @@ -62247,11 +69860,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ /* -** Move the open database page pDbPage to location iFreePage in the +** Move the open database page pDbPage to location iFreePage in the ** database. The pDbPage reference remains valid. ** ** The isCommit flag indicates that there is no need to remember that -** the journal needs to be sync()ed before database page pDbPage->pgno +** the journal needs to be sync()ed before database page pDbPage->pgno ** can be written to. The caller has already promised not to write to that ** page. */ @@ -62268,13 +69881,14 @@ static int relocatePage( Pager *pPager = pBt->pPager; int rc; - assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || + assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( pDbPage->pBt==pBt ); + if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT; /* Move page iDbPage from its current location to page number iFreePage */ - TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", + TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", iDbPage, iFreePage, iPtrPage, eType)); rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit); if( rc!=SQLITE_OK ){ @@ -62333,19 +69947,19 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); /* ** Perform a single step of an incremental-vacuum. If successful, return -** SQLITE_OK. If there is no work to do (and therefore no point in -** calling this function again), return SQLITE_DONE. Or, if an error +** SQLITE_OK. If there is no work to do (and therefore no point in +** calling this function again), return SQLITE_DONE. Or, if an error ** occurs, return some other error code. ** -** More specifically, this function attempts to re-organize the database so +** More specifically, this function attempts to re-organize the database so ** that the last page of the file currently in use is no longer in use. ** ** Parameter nFin is the number of pages that this database would contain ** were this function called until it returns SQLITE_DONE. ** -** If the bCommit parameter is non-zero, this function assumes that the -** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE -** or an error. bCommit is passed true for an auto-vacuum-on-commit +** If the bCommit parameter is non-zero, this function assumes that the +** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE +** or an error. bCommit is passed true for an auto-vacuum-on-commit ** operation, or false for an incremental vacuum. */ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ @@ -62376,7 +69990,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ if( bCommit==0 ){ /* Remove the page from the files free-list. This is not required ** if bCommit is non-zero. In that case, the free-list will be - ** truncated to zero after this function returns, so it doesn't + ** truncated to zero after this function returns, so it doesn't ** matter if it still contains some garbage entries. */ Pgno iFreePg; @@ -62420,7 +70034,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ releasePage(pFreePg); }while( bCommit && iFreePg>nFin ); assert( iFreePgpPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); - if( nOrig=nOrig ){ rc = SQLITE_CORRUPT_BKPT; }else if( nFree>0 ){ rc = saveAllCursors(pBt, 0, 0); @@ -62506,16 +70120,18 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. -** -** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages -** the database file should be truncated to during the commit process. -** i.e. the database has been reorganized so that only the first *pnTrunc -** pages are in use. */ -static int autoVacuumCommit(BtShared *pBt){ +static int autoVacuumCommit(Btree *p){ int rc = SQLITE_OK; - Pager *pPager = pBt->pPager; - VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); ) + Pager *pPager; + BtShared *pBt; + sqlite3 *db; + VVA_ONLY( int nRef ); + + assert( p!=0 ); + pBt = p->pBt; + pPager = pBt->pPager; + VVA_ONLY( nRef = sqlite3PagerRefcount(pPager); ) assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); @@ -62523,6 +70139,7 @@ static int autoVacuumCommit(BtShared *pBt){ if( !pBt->incrVacuum ){ Pgno nFin; /* Number of pages in database after autovacuuming */ Pgno nFree; /* Number of pages on the freelist initially */ + Pgno nVac; /* Number of pages to vacuum */ Pgno iFree; /* The next page to be freed */ Pgno nOrig; /* Database size before freeing */ @@ -62536,18 +70153,42 @@ static int autoVacuumCommit(BtShared *pBt){ } nFree = get4byte(&pBt->pPage1->aData[36]); - nFin = finalDbSize(pBt, nOrig, nFree); + db = p->db; + if( db->xAutovacPages ){ + int iDb; + for(iDb=0; ALWAYS(iDbnDb); iDb++){ + if( db->aDb[iDb].pBt==p ) break; + } + nVac = db->xAutovacPages( + db->pAutovacPagesArg, + db->aDb[iDb].zDbSName, + nOrig, + nFree, + pBt->pageSize + ); + if( nVac>nFree ){ + nVac = nFree; + } + if( nVac==0 ){ + return SQLITE_OK; + } + }else{ + nVac = nFree; + } + nFin = finalDbSize(pBt, nOrig, nVac); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFinnFin && rc==SQLITE_OK; iFree--){ - rc = incrVacuumStep(pBt, nFin, iFree, 1); + rc = incrVacuumStep(pBt, nFin, iFree, nVac==nFree); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); - put4byte(&pBt->pPage1->aData[32], 0); - put4byte(&pBt->pPage1->aData[36], 0); + if( nVac==nFree ){ + put4byte(&pBt->pPage1->aData[32], 0); + put4byte(&pBt->pPage1->aData[36], 0); + } put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; @@ -62580,25 +70221,25 @@ static int autoVacuumCommit(BtShared *pBt){ ** ** This call is a no-op if no write-transaction is currently active on pBt. ** -** Otherwise, sync the database file for the btree pBt. zMaster points to -** the name of a master journal file that should be written into the -** individual journal file, or is NULL, indicating no master journal file +** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to +** the name of a super-journal file that should be written into the +** individual journal file, or is NULL, indicating no super-journal file ** (single database transaction). ** -** When this is called, the master journal should already have been +** When this is called, the super-journal should already have been ** created, populated with this journal pointer and synced to disk. ** ** Once this is routine has returned, the only thing required to commit ** the write-transaction for this database file is to delete the journal. */ -SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ +SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ int rc = SQLITE_OK; if( p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - rc = autoVacuumCommit(pBt); + rc = autoVacuumCommit(p); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; @@ -62608,7 +70249,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } #endif - rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); + rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); sqlite3BtreeLeave(p); } return rc; @@ -62633,8 +70274,8 @@ static void btreeEndTransaction(Btree *p){ downgradeAllSharedCacheTableLocks(p); p->inTrans = TRANS_READ; }else{ - /* If the handle had any kind of transaction open, decrement the - ** transaction count of the shared btree. If the transaction count + /* If the handle had any kind of transaction open, decrement the + ** transaction count of the shared btree. If the transaction count ** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused() ** call below will unlock the pager. */ if( p->inTrans!=TRANS_NONE ){ @@ -62645,7 +70286,7 @@ static void btreeEndTransaction(Btree *p){ } } - /* Set the current transaction state to TRANS_NONE and unlock the + /* Set the current transaction state to TRANS_NONE and unlock the ** pager if this call closed the only read or write transaction. */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); @@ -62666,12 +70307,12 @@ static void btreeEndTransaction(Btree *p){ ** the rollback journal (which causes the transaction to commit) and ** drop locks. ** -** Normally, if an error occurs while the pager layer is attempting to +** Normally, if an error occurs while the pager layer is attempting to ** finalize the underlying journal file, this function returns an error and ** the upper layer will attempt a rollback. However, if the second argument -** is non-zero then this b-tree transaction is part of a multi-file -** transaction. In this case, the transaction has already been committed -** (by deleting a master journal file) and the caller will ignore this +** is non-zero then this b-tree transaction is part of a multi-file +** transaction. In this case, the transaction has already been committed +** (by deleting a super-journal file) and the caller will ignore this ** functions return code. So, even if an error occurs in the pager layer, ** reset the b-tree objects internal state to indicate that the write ** transaction has been closed. This is quite safe, as the pager will have @@ -62686,7 +70327,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ sqlite3BtreeEnter(p); btreeIntegrity(p); - /* If the handle has a write-transaction open, commit the shared-btrees + /* If the handle has a write-transaction open, commit the shared-btrees ** transaction and set the shared state to TRANS_READ. */ if( p->inTrans==TRANS_WRITE ){ @@ -62699,7 +70340,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){ sqlite3BtreeLeave(p); return rc; } - p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */ + p->iBDataVersion--; /* Compensate for pPager->iDataVersion++; */ pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } @@ -62735,15 +70376,15 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){ ** ** This routine gets called when a rollback occurs. If the writeOnly ** flag is true, then only write-cursors need be tripped - read-only -** cursors save their current positions so that they may continue -** following the rollback. Or, if writeOnly is false, all cursors are +** cursors save their current positions so that they may continue +** following the rollback. Or, if writeOnly is false, all cursors are ** tripped. In general, writeOnly is false if the transaction being ** rolled back modified the database schema. In this case b-tree root ** pages may be moved or deleted from the database altogether, making ** it unsafe for read cursors to continue. ** -** If the writeOnly flag is true and an error is encountered while -** saving the current position of a read-only cursor, all cursors, +** If the writeOnly flag is true and an error is encountered while +** saving the current position of a read-only cursor, all cursors, ** including all read-cursors are tripped. ** ** SQLITE_OK is returned if successful, or if an error occurs while @@ -62757,7 +70398,6 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr if( pBtree ){ sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ - int i; if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){ if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){ rc = saveCursorPosition(p); @@ -62771,16 +70411,25 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr p->eState = CURSOR_FAULT; p->skipNext = errCode; } - for(i=0; i<=p->iPage; i++){ - releasePage(p->apPage[i]); - p->apPage[i] = 0; - } + btreeReleaseAllCursorPages(p); } sqlite3BtreeLeave(pBtree); } return rc; } +/* +** Set the pBt->nPage field correctly, according to the current +** state of the database. Assume pBt->pPage1 is valid. +*/ +static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){ + int nPage = get4byte(&pPage1->aData[28]); + testcase( nPage==0 ); + if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); + testcase( pBt->nPage!=(u32)nPage ); + pBt->nPage = nPage; +} + /* ** Rollback the transaction in progress. ** @@ -62826,12 +70475,8 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ ** call btreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ - int nPage = get4byte(28+(u8*)pPage1->aData); - testcase( nPage==0 ); - if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); - testcase( pBt->nPage!=nPage ); - pBt->nPage = nPage; - releasePage(pPage1); + btreeSetNPage(pBt, pPage1); + releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); pBt->inTransaction = TRANS_READ; @@ -62845,8 +70490,8 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ /* ** Start a statement subtransaction. The subtransaction can be rolled -** back independently of the main transaction. You must start a transaction -** before starting a subtransaction. The subtransaction is ended automatically +** back independently of the main transaction. You must start a transaction +** before starting a subtransaction. The subtransaction is ended automatically ** if the main transaction commits or rolls back. ** ** Statement subtransactions are used around individual SQL statements @@ -62883,11 +70528,11 @@ SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){ /* ** The second argument to this function, op, is always SAVEPOINT_ROLLBACK ** or SAVEPOINT_RELEASE. This function either releases or rolls back the -** savepoint identified by parameter iSavepoint, depending on the value +** savepoint identified by parameter iSavepoint, depending on the value ** of op. ** ** Normally, iSavepoint is greater than or equal to zero. However, if op is -** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the +** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the ** contents of the entire transaction are rolled back. This is different ** from a normal transaction rollback, as no locks are released and the ** transaction remains open. @@ -62910,12 +70555,11 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ pBt->nPage = 0; } rc = newDatabase(pBt); - pBt->nPage = get4byte(28 + pBt->pPage1->aData); + btreeSetNPage(pBt, pBt->pPage1); - /* The database size was written into the offset 28 of the header - ** when the transaction started, so we know that the value at offset - ** 28 is nonzero. */ - assert( pBt->nPage>0 ); + /* pBt->nPage might be zero if the database was corrupt when + ** the transaction was started. Otherwise, it must be at least 1. */ + assert( CORRUPT_DB || pBt->nPage>0 ); } sqlite3BtreeLeave(p); } @@ -62951,10 +70595,10 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ ** is set. If FORDELETE is set, that is a hint to the implementation that ** this cursor will only be used to seek to and delete entries of an index ** as part of a larger DELETE statement. The FORDELETE hint is not used by -** this implementation. But in a hypothetical alternative storage engine +** this implementation. But in a hypothetical alternative storage engine ** in which index entries are automatically deleted when corresponding table ** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE -** operations on this cursor can be no-ops and all READ operations can +** operations on this cursor can be no-ops and all READ operations can ** return a null row (2-bytes: 0x01 0x00). ** ** No checking is done to make sure that page iTable really is the @@ -62966,7 +70610,7 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ */ static int btreeCursor( Btree *p, /* The btree */ - int iTable, /* Root page of table to open */ + Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to comparison function */ BtCursor *pCur /* Space for new cursor */ @@ -62975,16 +70619,17 @@ static int btreeCursor( BtCursor *pX; /* Looping over other all cursors */ assert( sqlite3BtreeHoldsMutex(p) ); - assert( wrFlag==0 - || wrFlag==BTREE_WRCSR - || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) + assert( wrFlag==0 + || wrFlag==BTREE_WRCSR + || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) ); - /* The following assert statements verify that if this is a sharable - ** b-tree database, the connection is holding the required table locks, - ** and that no other connection has any open cursor that conflicts with - ** this lock. */ - assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) ); + /* The following assert statements verify that if this is a sharable + ** b-tree database, the connection is holding the required table locks, + ** and that no other connection has any open cursor that conflicts with + ** this lock. The iTable<1 term disables the check for corrupt schemas. */ + assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) + || iTable<1 ); assert( wrFlag==0 || !hasReadConflicts(p, iTable) ); /* Assert that the caller has opened the required transaction. */ @@ -62993,53 +70638,68 @@ static int btreeCursor( assert( pBt->pPage1 && pBt->pPage1->aData ); assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 ); - if( wrFlag ){ - allocateTempSpace(pBt); - if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT; - } - if( iTable==1 && btreePagecount(pBt)==0 ){ - assert( wrFlag==0 ); - iTable = 0; + if( iTable<=1 ){ + if( iTable<1 ){ + return SQLITE_CORRUPT_BKPT; + }else if( btreePagecount(pBt)==0 ){ + assert( wrFlag==0 ); + iTable = 0; + } } /* Now that no other errors can occur, finish filling in the BtCursor ** variables and link the cursor into the BtShared list. */ - pCur->pgnoRoot = (Pgno)iTable; + pCur->pgnoRoot = iTable; pCur->iPage = -1; pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; - pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0; - pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY; + pCur->curFlags = 0; /* If there are two or more cursors on the same btree, then all such ** cursors *must* have the BTCF_Multiple flag set. */ for(pX=pBt->pCursor; pX; pX=pX->pNext){ - if( pX->pgnoRoot==(Pgno)iTable ){ + if( pX->pgnoRoot==iTable ){ pX->curFlags |= BTCF_Multiple; - pCur->curFlags |= BTCF_Multiple; + pCur->curFlags = BTCF_Multiple; } } + pCur->eState = CURSOR_INVALID; pCur->pNext = pBt->pCursor; pBt->pCursor = pCur; - pCur->eState = CURSOR_INVALID; + if( wrFlag ){ + pCur->curFlags |= BTCF_WriteFlag; + pCur->curPagerFlags = 0; + if( pBt->pTmpSpace==0 ) return allocateTempSpace(pBt); + }else{ + pCur->curPagerFlags = PAGER_GET_READONLY; + } return SQLITE_OK; } +static int btreeCursorWithLock( + Btree *p, /* The btree */ + Pgno iTable, /* Root page of table to open */ + int wrFlag, /* 1 to write. 0 read-only */ + struct KeyInfo *pKeyInfo, /* First arg to comparison function */ + BtCursor *pCur /* Space for new cursor */ +){ + int rc; + sqlite3BtreeEnter(p); + rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); + sqlite3BtreeLeave(p); + return rc; +} SQLITE_PRIVATE int sqlite3BtreeCursor( Btree *p, /* The btree */ - int iTable, /* Root page of table to open */ + Pgno iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ struct KeyInfo *pKeyInfo, /* First arg to xCompare() */ BtCursor *pCur /* Write new cursor here */ ){ - int rc; - if( iTable<1 ){ - rc = SQLITE_CORRUPT_BKPT; + if( p->sharable ){ + return btreeCursorWithLock(p, iTable, wrFlag, pKeyInfo, pCur); }else{ - sqlite3BtreeEnter(p); - rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); - sqlite3BtreeLeave(p); + return btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); } - return rc; } /* @@ -63063,7 +70723,7 @@ SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){ ** of run-time by skipping the initialization of those elements. */ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ - memset(p, 0, offsetof(BtCursor, iPage)); + memset(p, 0, offsetof(BtCursor, BTCURSOR_FIRST_UNINIT)); } /* @@ -63073,10 +70733,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ Btree *pBtree = pCur->pBtree; if( pBtree ){ - int i; BtShared *pBt = pCur->pBt; sqlite3BtreeEnter(pBtree); - sqlite3BtreeClearCursor(pCur); assert( pBt->pCursor!=0 ); if( pBt->pCursor==pCur ){ pBt->pCursor = pCur->pNext; @@ -63090,13 +70748,19 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } - for(i=0; i<=pCur->iPage; i++){ - releasePage(pCur->apPage[i]); - } + btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); - /* sqlite3_free(pCur); */ - sqlite3BtreeLeave(pBtree); + sqlite3_free(pCur->pKey); + if( (pBt->openFlags & BTREE_SINGLE) && pBt->pCursor==0 ){ + /* Since the BtShared is not sharable, there is no need to + ** worry about the missing sqlite3BtreeLeave() call here. */ + assert( pBtree->sharable==0 ); + sqlite3BtreeClose(pBtree); + }else{ + sqlite3BtreeLeave(pBtree); + } + pCur->pBtree = 0; } return SQLITE_OK; } @@ -63110,21 +70774,27 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){ ** Using this cache reduces the number of calls to btreeParseCell(). */ #ifndef NDEBUG + static int cellInfoEqual(CellInfo *a, CellInfo *b){ + if( a->nKey!=b->nKey ) return 0; + if( a->pPayload!=b->pPayload ) return 0; + if( a->nPayload!=b->nPayload ) return 0; + if( a->nLocal!=b->nLocal ) return 0; + if( a->nSize!=b->nSize ) return 0; + return 1; + } static void assertCellInfo(BtCursor *pCur){ CellInfo info; - int iPage = pCur->iPage; memset(&info, 0, sizeof(info)); - btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info); - assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 ); + btreeParseCell(pCur->pPage, pCur->ix, &info); + assert( CORRUPT_DB || cellInfoEqual(&info, &pCur->info) ); } #else #define assertCellInfo(x) #endif static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ - int iPage = pCur->iPage; pCur->curFlags |= BTCF_ValidNKey; - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); + btreeParseCell(pCur->pPage,pCur->ix,&pCur->info); }else{ assertCellInfo(pCur); } @@ -63159,6 +70829,32 @@ SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ return pCur->info.nKey; } +/* +** Pin or unpin a cursor. +*/ +SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor *pCur){ + assert( (pCur->curFlags & BTCF_Pinned)==0 ); + pCur->curFlags |= BTCF_Pinned; +} +SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *pCur){ + assert( (pCur->curFlags & BTCF_Pinned)!=0 ); + pCur->curFlags &= ~BTCF_Pinned; +} + +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC +/* +** Return the offset into the database file for the start of the +** payload to which the cursor is pointing. +*/ +SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + getCellInfo(pCur); + return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) + + (i64)(pCur->info.pPayload - pCur->pPage->aData); +} +#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */ + /* ** Return the number of bytes of payload for the entry that pCur is ** currently pointing to. For table btrees, this will be the amount @@ -63175,17 +70871,36 @@ SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){ return pCur->info.nPayload; } +/* +** Return an upper bound on the size of any record for the table +** that the cursor is pointing into. +** +** This is an optimization. Everything will still work if this +** routine always returns 2147483647 (which is the largest record +** that SQLite can handle) or more. But returning a smaller value might +** prevent large memory allocations when trying to interpret a +** corrupt datrabase. +** +** The current implementation merely returns the size of the underlying +** database file. +*/ +SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){ + assert( cursorHoldsMutex(pCur) ); + assert( pCur->eState==CURSOR_VALID ); + return pCur->pBt->pageSize * (sqlite3_int64)pCur->pBt->nPage; +} + /* ** Given the page number of an overflow page in the database (parameter -** ovfl), this function finds the page number of the next page in the +** ovfl), this function finds the page number of the next page in the ** linked list of overflow pages. If possible, it uses the auto-vacuum -** pointer-map data instead of reading the content of page ovfl to do so. +** pointer-map data instead of reading the content of page ovfl to do so. ** ** If an error occurs an SQLite error code is returned. Otherwise: ** -** The page number of the next overflow page in the linked list is -** written to *pPgnoNext. If page ovfl is the last page in its linked -** list, *pPgnoNext is set to zero. +** The page number of the next overflow page in the linked list is +** written to *pPgnoNext. If page ovfl is the last page in its linked +** list, *pPgnoNext is set to zero. ** ** If ppPage is not NULL, and a reference to the MemPage object corresponding ** to page number pOvfl was obtained, then *ppPage is set to point to that @@ -63209,9 +70924,9 @@ static int getOverflowPage( #ifndef SQLITE_OMIT_AUTOVACUUM /* Try to find the next page in the overflow list using the - ** autovacuum pointer-map pages. Guess that the next page in - ** the overflow list is page number (ovfl+1). If that guess turns - ** out to be wrong, fall back to loading the data of page + ** autovacuum pointer-map pages. Guess that the next page in + ** the overflow list is page number (ovfl+1). If that guess turns + ** out to be wrong, fall back to loading the data of page ** number ovfl to determine the next page number. */ if( pBt->autoVacuum ){ @@ -63299,8 +71014,8 @@ static int copyPayload( ** ** If the current cursor entry uses one or more overflow pages ** this function may allocate space for and lazily populate -** the overflow page-list cache array (BtCursor.aOverflow). -** Subsequent calls use this cache to make seeking to the supplied offset +** the overflow page-list cache array (BtCursor.aOverflow). +** Subsequent calls use this cache to make seeking to the supplied offset ** more efficient. ** ** Once an overflow page-list cache has been allocated, it must be @@ -63316,13 +71031,13 @@ static int accessPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 offset, /* Begin reading this far into payload */ u32 amt, /* Read this many bytes */ - unsigned char *pBuf, /* Write the bytes into this buffer */ + unsigned char *pBuf, /* Write the bytes into this buffer */ int eOp /* zero to read. non-zero to write. */ ){ unsigned char *aPayload; int rc = SQLITE_OK; int iIdx = 0; - MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ + MemPage *pPage = pCur->pPage; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ #ifdef SQLITE_DIRECT_OVERFLOW_READ unsigned char * const pBufStart = pBuf; /* Start of original out buffer */ @@ -63331,7 +71046,9 @@ static int accessPayload( assert( pPage ); assert( eOp==0 || eOp==1 ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->aiIdx[pCur->iPage]nCell ); + if( pCur->ix>=pPage->nCell ){ + return SQLITE_CORRUPT_PAGE(pPage); + } assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); @@ -63345,7 +71062,7 @@ static int accessPayload( ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ** but is recast into its current form to avoid integer overflow problems */ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PAGE(pPage); } /* Check if data must be read/written to/from the btree page itself. */ @@ -63378,14 +71095,15 @@ static int accessPayload( */ if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; - if( nOvfl>pCur->nOvflAlloc ){ + if( pCur->aOverflow==0 + || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) + ){ Pgno *aNew = (Pgno*)sqlite3Realloc( pCur->aOverflow, nOvfl*2*sizeof(Pgno) ); if( aNew==0 ){ return SQLITE_NOMEM_BKPT; }else{ - pCur->nOvflAlloc = nOvfl*2; pCur->aOverflow = aNew; } } @@ -63406,6 +71124,7 @@ static int accessPayload( assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ + if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; assert( pCur->aOverflow[iIdx]==0 || pCur->aOverflow[iIdx]==nextPage || CORRUPT_DB ); @@ -63430,9 +71149,6 @@ static int accessPayload( /* Need to read this page properly. It contains some of the ** range of data that is being read (eOp==0) or written (eOp!=0). */ -#ifdef SQLITE_DIRECT_OVERFLOW_READ - sqlite3_file *fd; /* File from which to do direct overflow read */ -#endif int a = amt; if( a + offset > ovflSize ){ a = ovflSize - offset; @@ -63441,12 +71157,12 @@ static int accessPayload( #ifdef SQLITE_DIRECT_OVERFLOW_READ /* If all the following are true: ** - ** 1) this is a read operation, and + ** 1) this is a read operation, and ** 2) data is required from the start of this overflow page, and - ** 3) there is no open write-transaction, and + ** 3) there are no dirty pages in the page-cache ** 4) the database is file-backed, and ** 5) the page is not in the WAL file - ** 6) at least 4 bytes have already been read into the output buffer + ** 6) at least 4 bytes have already been read into the output buffer ** ** then data can be read directly from the database file into the ** output buffer, bypassing the page-cache altogether. This speeds @@ -63454,16 +71170,16 @@ static int accessPayload( */ if( eOp==0 /* (1) */ && offset==0 /* (2) */ - && pBt->inTransaction==TRANS_READ /* (3) */ - && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (4) */ - && 0==sqlite3PagerUseWal(pBt->pPager, nextPage) /* (5) */ + && sqlite3PagerDirectReadOk(pBt->pPager, nextPage) /* (3,4,5) */ && &pBuf[-4]>=pBufStart /* (6) */ ){ + sqlite3_file *fd = sqlite3PagerFile(pBt->pPager); u8 aSave[4]; u8 *aWrite = &pBuf[-4]; assert( aWrite>=pBufStart ); /* due to (6) */ memcpy(aSave, aWrite, 4); rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1)); + if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT; nextPage = get4byte(aWrite); memcpy(aWrite, aSave, 4); }else @@ -63492,7 +71208,8 @@ static int accessPayload( } if( rc==SQLITE_OK && amt>0 ){ - return SQLITE_CORRUPT_BKPT; /* Overflow chain ends prematurely */ + /* Overflow chain ends prematurely */ + return SQLITE_CORRUPT_PAGE(pPage); } return rc; } @@ -63517,8 +71234,7 @@ static int accessPayload( SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->iPage>=0 && pCur->pPage ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } @@ -63553,7 +71269,7 @@ SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 am #endif /* SQLITE_OMIT_INCRBLOB */ /* -** Return a pointer to payload information from the entry that the +** Return a pointer to payload information from the entry that the ** pCur cursor is pointing to. The pointer is to the beginning of ** the key if index btrees (pPage->intKey==0) and is the data for ** table btrees (pPage->intKey==1). The number of bytes of available @@ -63575,18 +71291,23 @@ static const void *fetchPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 *pAmt /* Write the number of available bytes here */ ){ - u32 amt; - assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); + int amt; + assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorOwnsBtShared(pCur) ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->ixpPage->nCell || CORRUPT_DB ); assert( pCur->info.nSize>0 ); - assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); - assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); - amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); - if( pCur->info.nLocalinfo.nLocal; - *pAmt = amt; + assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); + assert( pCur->info.pPayloadpPage->aDataEnd ||CORRUPT_DB); + amt = pCur->info.nLocal; + if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){ + /* There is too little space on the page for the expected amount + ** of local content. Database must be corrupt. */ + assert( CORRUPT_DB ); + amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload)); + } + *pAmt = (u32)amt; return (void*)pCur->info.pPayload; } @@ -63631,15 +71352,16 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ } pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); + pCur->aiIdx[pCur->iPage] = pCur->ix; + pCur->apPage[pCur->iPage] = pCur->pPage; + pCur->ix = 0; pCur->iPage++; - pCur->aiIdx[pCur->iPage] = 0; - return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage], - pCur, pCur->curPagerFlags); + return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags); } -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* -** Page pParent is an internal (non-leaf) tree page. This function +** Page pParent is an internal (non-leaf) tree page. This function ** asserts that page number iChild is the left-child if the iIdx'th ** cell in page pParent. Or, if iIdx is equal to the total number of ** cells in pParent, that page number iChild is the right-child of @@ -63656,7 +71378,7 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ } } #else -# define assertParentIndex(x,y,z) +# define assertParentIndex(x,y,z) #endif /* @@ -63668,19 +71390,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){ ** the largest cell index. */ static void moveToParent(BtCursor *pCur){ + MemPage *pLeaf; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); - assert( pCur->apPage[pCur->iPage] ); + assert( pCur->pPage ); assertParentIndex( - pCur->apPage[pCur->iPage-1], - pCur->aiIdx[pCur->iPage-1], - pCur->apPage[pCur->iPage]->pgno + pCur->apPage[pCur->iPage-1], + pCur->aiIdx[pCur->iPage-1], + pCur->pPage->pgno ); testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); - releasePageNotNull(pCur->apPage[pCur->iPage--]); + pCur->ix = pCur->aiIdx[pCur->iPage-1]; + pLeaf = pCur->pPage; + pCur->pPage = pCur->apPage[--pCur->iPage]; + releasePageNotNull(pLeaf); } /* @@ -63688,19 +71414,19 @@ static void moveToParent(BtCursor *pCur){ ** ** If the table has a virtual root page, then the cursor is moved to point ** to the virtual root page instead of the actual root page. A table has a -** virtual root page when the actual root page contains no cells and a +** virtual root page when the actual root page contains no cells and a ** single child page. This can only happen with the table rooted at page 1. ** -** If the b-tree structure is empty, the cursor state is set to -** CURSOR_INVALID. Otherwise, the cursor is set to point to the first -** cell located on the root (or virtual root) page and the cursor state -** is set to CURSOR_VALID. +** If the b-tree structure is empty, the cursor state is set to +** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise, +** the cursor is set to point to the first cell located on the root +** (or virtual root) page and the cursor state is set to CURSOR_VALID. ** ** If this function returns successfully, it may be assumed that the -** page-header flags indicate that the [virtual] root-page is the expected +** page-header flags indicate that the [virtual] root-page is the expected ** kind of b-tree page (i.e. if when opening the cursor the caller did not ** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D, -** indicating a table b-tree, or if the caller did specify a KeyInfo +** indicating a table b-tree, or if the caller did specify a KeyInfo ** structure the flags byte is set to 0x02 or 0x0A, indicating an index ** b-tree). */ @@ -63712,60 +71438,62 @@ static int moveToRoot(BtCursor *pCur){ assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); - if( pCur->eState>=CURSOR_REQUIRESEEK ){ - if( pCur->eState==CURSOR_FAULT ){ - assert( pCur->skipNext!=SQLITE_OK ); - return pCur->skipNext; - } - sqlite3BtreeClearCursor(pCur); - } + assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 ); + assert( pCur->pgnoRoot>0 || pCur->iPage<0 ); if( pCur->iPage>=0 ){ if( pCur->iPage ){ - do{ - assert( pCur->apPage[pCur->iPage]!=0 ); - releasePageNotNull(pCur->apPage[pCur->iPage--]); - }while( pCur->iPage); + releasePageNotNull(pCur->pPage); + while( --pCur->iPage ){ + releasePageNotNull(pCur->apPage[pCur->iPage]); + } + pRoot = pCur->pPage = pCur->apPage[0]; goto skip_init; } }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; - return SQLITE_OK; + return SQLITE_EMPTY; }else{ assert( pCur->iPage==(-1) ); - rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0], + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + if( pCur->eState==CURSOR_FAULT ){ + assert( pCur->skipNext!=SQLITE_OK ); + return pCur->skipNext; + } + sqlite3BtreeClearCursor(pCur); + } + rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage, 0, pCur->curPagerFlags); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; - return rc; + return rc; } pCur->iPage = 0; - pCur->curIntKey = pCur->apPage[0]->intKey; + pCur->curIntKey = pCur->pPage->intKey; } - pRoot = pCur->apPage[0]; - assert( pRoot->pgno==pCur->pgnoRoot ); + pRoot = pCur->pPage; + assert( pRoot->pgno==pCur->pgnoRoot || CORRUPT_DB ); /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor ** expected to open it on an index b-tree. Otherwise, if pKeyInfo is ** NULL, the caller expects a table b-tree. If this is not the case, - ** return an SQLITE_CORRUPT error. + ** return an SQLITE_CORRUPT error. ** ** Earlier versions of SQLite assumed that this test could not fail ** if the root page was already loaded when this function was called (i.e. - ** if pCur->iPage>=0). But this is not so if the database is corrupted - ** in such a way that page pRoot is linked into a second b-tree table + ** if pCur->iPage>=0). But this is not so if the database is corrupted + ** in such a way that page pRoot is linked into a second b-tree table ** (or the freelist). */ assert( pRoot->intKey==1 || pRoot->intKey==0 ); if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ - return SQLITE_CORRUPT_BKPT; + return SQLITE_CORRUPT_PAGE(pCur->pPage); } -skip_init: - pCur->aiIdx[0] = 0; +skip_init: + pCur->ix = 0; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); - pRoot = pCur->apPage[0]; if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){ @@ -63776,6 +71504,7 @@ static int moveToRoot(BtCursor *pCur){ rc = moveToChild(pCur, subpage); }else{ pCur->eState = CURSOR_INVALID; + rc = SQLITE_EMPTY; } return rc; } @@ -63794,9 +71523,9 @@ static int moveToLeftmost(BtCursor *pCur){ assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ - assert( pCur->aiIdx[pCur->iPage]nCell ); - pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage])); + while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ + assert( pCur->ixnCell ); + pgno = get4byte(findCell(pPage, pCur->ix)); rc = moveToChild(pCur, pgno); } return rc; @@ -63819,13 +71548,13 @@ static int moveToRightmost(BtCursor *pCur){ assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); - pCur->aiIdx[pCur->iPage] = pPage->nCell; + pCur->ix = pPage->nCell; rc = moveToChild(pCur, pgno); if( rc ) return rc; } - pCur->aiIdx[pCur->iPage] = pPage->nCell-1; + pCur->ix = pPage->nCell-1; assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & BTCF_ValidNKey)==0 ); return SQLITE_OK; @@ -63842,14 +71571,13 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ - if( pCur->eState==CURSOR_INVALID ){ - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - *pRes = 1; - }else{ - assert( pCur->apPage[pCur->iPage]->nCell>0 ); - *pRes = 0; - rc = moveToLeftmost(pCur); - } + assert( pCur->pPage->nCell>0 ); + *pRes = 0; + rc = moveToLeftmost(pCur); + }else if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = SQLITE_OK; } return rc; } @@ -63860,51 +71588,48 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ */ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; - + assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor already points to the last entry, this is a no-op. */ if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){ #ifdef SQLITE_DEBUG - /* This block serves to assert() that the cursor really does point + /* This block serves to assert() that the cursor really does point ** to the last entry in the b-tree. */ int ii; for(ii=0; iiiPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } - assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 ); - assert( pCur->apPage[pCur->iPage]->leaf ); + assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB ); + testcase( pCur->ix!=pCur->pPage->nCell-1 ); + /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */ + assert( pCur->pPage->leaf ); #endif + *pRes = 0; return SQLITE_OK; } rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ - if( CURSOR_INVALID==pCur->eState ){ - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - *pRes = 1; + assert( pCur->eState==CURSOR_VALID ); + *pRes = 0; + rc = moveToRightmost(pCur); + if( rc==SQLITE_OK ){ + pCur->curFlags |= BTCF_AtLast; }else{ - assert( pCur->eState==CURSOR_VALID ); - *pRes = 0; - rc = moveToRightmost(pCur); - if( rc==SQLITE_OK ){ - pCur->curFlags |= BTCF_AtLast; - }else{ - pCur->curFlags &= ~BTCF_AtLast; - } - + pCur->curFlags &= ~BTCF_AtLast; } + }else if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = 1; + rc = SQLITE_OK; } return rc; } -/* Move the cursor so that it points to an entry near the key -** specified by pIdxKey or intKey. Return a success code. -** -** For INTKEY tables, the intKey parameter is used. pIdxKey -** must be NULL. For index tables, pIdxKey is used and intKey -** is ignored. +/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY) +** table near the key intKey. Return a success code. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it @@ -63912,44 +71637,37 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ ** before or after the key. ** ** An integer is written into *pRes which is the result of -** comparing the key with the entry to which the cursor is +** comparing the key with the entry to which the cursor is ** pointing. The meaning of the integer written into ** *pRes is as follows: ** ** *pRes<0 The cursor is left pointing at an entry that -** is smaller than intKey/pIdxKey or if the table is empty +** is smaller than intKey or if the table is empty ** and the cursor is therefore left point to nothing. ** ** *pRes==0 The cursor is left pointing at an entry that -** exactly matches intKey/pIdxKey. +** exactly matches intKey. ** ** *pRes>0 The cursor is left pointing at an entry that -** is larger than intKey/pIdxKey. -** -** For index tables, the pIdxKey->eqSeen field is set to 1 if there -** exists an entry in the table that exactly matches pIdxKey. +** is larger than intKey. */ -SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( +SQLITE_PRIVATE int sqlite3BtreeTableMoveto( BtCursor *pCur, /* The cursor to be moved */ - UnpackedRecord *pIdxKey, /* Unpacked index key */ i64 intKey, /* The table key */ int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; - RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); - assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); - assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) ); + assert( pCur->pKeyInfo==0 ); + assert( pCur->eState!=CURSOR_VALID || pCur->curIntKey!=0 ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ - if( pIdxKey==0 - && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 - ){ + if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; @@ -63962,50 +71680,46 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( /* If the requested key is one more than the previous key, then ** try to get there using sqlite3BtreeNext() rather than a full ** binary search. This is an optimization only. The correct answer - ** is still obtained without this ase, only a little more slowely */ - if( pCur->info.nKey+1==intKey && !pCur->skipNext ){ + ** is still obtained without this case, only a little more slowely */ + if( pCur->info.nKey+1==intKey ){ *pRes = 0; - rc = sqlite3BtreeNext(pCur, pRes); - if( rc ) return rc; - if( *pRes==0 ){ + rc = sqlite3BtreeNext(pCur, 0); + if( rc==SQLITE_OK ){ getCellInfo(pCur); if( pCur->info.nKey==intKey ){ return SQLITE_OK; } + }else if( rc!=SQLITE_DONE ){ + return rc; } } } } - if( pIdxKey ){ - xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); - pIdxKey->errCode = 0; - assert( pIdxKey->default_rc==1 - || pIdxKey->default_rc==0 - || pIdxKey->default_rc==-1 - ); - }else{ - xRecordCompare = 0; /* All keys are integers */ - } +#ifdef SQLITE_DEBUG + pCur->pBtree->nSeek++; /* Performance measurement during testing */ +#endif rc = moveToRoot(pCur); if( rc ){ + if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = -1; + return SQLITE_OK; + } return rc; } - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] ); - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit ); - assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 ); - if( pCur->eState==CURSOR_INVALID ){ - *pRes = -1; - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); - return SQLITE_OK; - } - assert( pCur->apPage[0]->intKey==pCur->curIntKey ); - assert( pCur->curIntKey || pIdxKey ); + assert( pCur->pPage ); + assert( pCur->pPage->isInit ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage->nCell > 0 ); + assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); + assert( pCur->curIntKey ); + for(;;){ int lwr, upr, idx, c; Pgno chldPg; - MemPage *pPage = pCur->apPage[pCur->iPage]; + MemPage *pPage = pCur->pPage; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page @@ -64015,150 +71729,256 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); - assert( pPage->intKey==(pIdxKey==0) ); + assert( pPage->intKey ); lwr = 0; upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ - pCur->aiIdx[pCur->iPage] = (u16)idx; - if( xRecordCompare==0 ){ - for(;;){ - i64 nCellKey; - pCell = findCellPastPtr(pPage, idx); - if( pPage->intKeyLeaf ){ - while( 0x80 <= *(pCell++) ){ - if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; + for(;;){ + i64 nCellKey; + pCell = findCellPastPtr(pPage, idx); + if( pPage->intKeyLeaf ){ + while( 0x80 <= *(pCell++) ){ + if( pCell>=pPage->aDataEnd ){ + return SQLITE_CORRUPT_PAGE(pPage); } } - getVarint(pCell, (u64*)&nCellKey); - if( nCellKeyupr ){ c = -1; break; } - }else if( nCellKey>intKey ){ - upr = idx-1; - if( lwr>upr ){ c = +1; break; } + } + getVarint(pCell, (u64*)&nCellKey); + if( nCellKeyupr ){ c = -1; break; } + }else if( nCellKey>intKey ){ + upr = idx-1; + if( lwr>upr ){ c = +1; break; } + }else{ + assert( nCellKey==intKey ); + pCur->ix = (u16)idx; + if( !pPage->leaf ){ + lwr = idx; + goto moveto_table_next_layer; }else{ - assert( nCellKey==intKey ); - pCur->aiIdx[pCur->iPage] = (u16)idx; - if( !pPage->leaf ){ - lwr = idx; - goto moveto_next_layer; - }else{ - pCur->curFlags |= BTCF_ValidNKey; - pCur->info.nKey = nCellKey; - pCur->info.nSize = 0; - *pRes = 0; - return SQLITE_OK; - } + pCur->curFlags |= BTCF_ValidNKey; + pCur->info.nKey = nCellKey; + pCur->info.nSize = 0; + *pRes = 0; + return SQLITE_OK; } - assert( lwr+upr>=0 ); - idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ } + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ + } + assert( lwr==upr+1 || !pPage->leaf ); + assert( pPage->isInit ); + if( pPage->leaf ){ + assert( pCur->ixpPage->nCell ); + pCur->ix = (u16)idx; + *pRes = c; + rc = SQLITE_OK; + goto moveto_table_finish; + } +moveto_table_next_layer: + if( lwr>=pPage->nCell ){ + chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ - for(;;){ - int nCell; /* Size of the pCell cell in bytes */ - pCell = findCellPastPtr(pPage, idx); - - /* The maximum supported page-size is 65536 bytes. This means that - ** the maximum number of record bytes stored on an index B-Tree - ** page is less than 16384 bytes and may be stored as a 2-byte - ** varint. This information is used to attempt to avoid parsing - ** the entire cell by checking for the cases where the record is - ** stored entirely within the b-tree page by inspecting the first - ** 2 bytes of the cell. - */ - nCell = pCell[0]; - if( nCell<=pPage->max1bytePayload ){ - /* This branch runs if the record-size field of the cell is a - ** single byte varint and the record fits entirely on the main - ** b-tree page. */ - testcase( pCell+nCell+1==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); - }else if( !(pCell[1] & 0x80) - && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal - ){ - /* The record-size field is a 2 byte varint and the record - ** fits entirely on the main b-tree page. */ - testcase( pCell+nCell+2==pPage->aDataEnd ); - c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); - }else{ - /* The record flows over onto one or more overflow pages. In - ** this case the whole cell needs to be parsed, a buffer allocated - ** and accessPayload() used to retrieve the record into the - ** buffer before VdbeRecordCompare() can be called. - ** - ** If the record is corrupt, the xRecordCompare routine may read - ** up to two varints past the end of the buffer. An extra 18 - ** bytes of padding is allocated at the end of the buffer in - ** case this happens. */ - void *pCellKey; - u8 * const pCellBody = pCell - pPage->childPtrSize; - pPage->xParseCell(pPage, pCellBody, &pCur->info); - nCell = (int)pCur->info.nKey; - testcase( nCell<0 ); /* True if key size is 2^32 or more */ - testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ - testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ - testcase( nCell==2 ); /* Minimum legal index key size */ - if( nCell<2 ){ - rc = SQLITE_CORRUPT_BKPT; - goto moveto_finish; - } - pCellKey = sqlite3Malloc( nCell+18 ); - if( pCellKey==0 ){ - rc = SQLITE_NOMEM_BKPT; - goto moveto_finish; - } - pCur->aiIdx[pCur->iPage] = (u16)idx; - rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); - pCur->curFlags &= ~BTCF_ValidOvfl; - if( rc ){ - sqlite3_free(pCellKey); - goto moveto_finish; - } - c = xRecordCompare(nCell, pCellKey, pIdxKey); - sqlite3_free(pCellKey); + chldPg = get4byte(findCell(pPage, lwr)); + } + pCur->ix = (u16)lwr; + rc = moveToChild(pCur, chldPg); + if( rc ) break; + } +moveto_table_finish: + pCur->info.nSize = 0; + assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); + return rc; +} + +/* Move the cursor so that it points to an entry in an index table +** near the key pIdxKey. Return a success code. +** +** If an exact match is not found, then the cursor is always +** left pointing at a leaf page which would hold the entry if it +** were present. The cursor might point to an entry that comes +** before or after the key. +** +** An integer is written into *pRes which is the result of +** comparing the key with the entry to which the cursor is +** pointing. The meaning of the integer written into +** *pRes is as follows: +** +** *pRes<0 The cursor is left pointing at an entry that +** is smaller than pIdxKey or if the table is empty +** and the cursor is therefore left point to nothing. +** +** *pRes==0 The cursor is left pointing at an entry that +** exactly matches pIdxKey. +** +** *pRes>0 The cursor is left pointing at an entry that +** is larger than pIdxKey. +** +** The pIdxKey->eqSeen field is set to 1 if there +** exists an entry in the table that exactly matches pIdxKey. +*/ +SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( + BtCursor *pCur, /* The cursor to be moved */ + UnpackedRecord *pIdxKey, /* Unpacked index key */ + int *pRes /* Write search results here */ +){ + int rc; + RecordCompare xRecordCompare; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + assert( pRes ); + assert( pCur->pKeyInfo!=0 ); + +#ifdef SQLITE_DEBUG + pCur->pBtree->nSeek++; /* Performance measurement during testing */ +#endif + + xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); + pIdxKey->errCode = 0; + assert( pIdxKey->default_rc==1 + || pIdxKey->default_rc==0 + || pIdxKey->default_rc==-1 + ); + + rc = moveToRoot(pCur); + if( rc ){ + if( rc==SQLITE_EMPTY ){ + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); + *pRes = -1; + return SQLITE_OK; + } + return rc; + } + assert( pCur->pPage ); + assert( pCur->pPage->isInit ); + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage->nCell > 0 ); + assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey ); + assert( pCur->curIntKey || pIdxKey ); + for(;;){ + int lwr, upr, idx, c; + Pgno chldPg; + MemPage *pPage = pCur->pPage; + u8 *pCell; /* Pointer to current cell in pPage */ + + /* pPage->nCell must be greater than zero. If this is the root-page + ** the cursor would have been INVALID above and this for(;;) loop + ** not run. If this is not the root-page, then the moveToChild() routine + ** would have already detected db corruption. Similarly, pPage must + ** be the right kind (index or table) of b-tree page. Otherwise + ** a moveToChild() or moveToRoot() call would have detected corruption. */ + assert( pPage->nCell>0 ); + assert( pPage->intKey==(pIdxKey==0) ); + lwr = 0; + upr = pPage->nCell-1; + idx = upr>>1; /* idx = (lwr+upr)/2; */ + for(;;){ + int nCell; /* Size of the pCell cell in bytes */ + pCell = findCellPastPtr(pPage, idx); + + /* The maximum supported page-size is 65536 bytes. This means that + ** the maximum number of record bytes stored on an index B-Tree + ** page is less than 16384 bytes and may be stored as a 2-byte + ** varint. This information is used to attempt to avoid parsing + ** the entire cell by checking for the cases where the record is + ** stored entirely within the b-tree page by inspecting the first + ** 2 bytes of the cell. + */ + nCell = pCell[0]; + if( nCell<=pPage->max1bytePayload ){ + /* This branch runs if the record-size field of the cell is a + ** single byte varint and the record fits entirely on the main + ** b-tree page. */ + testcase( pCell+nCell+1==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); + }else if( !(pCell[1] & 0x80) + && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + ){ + /* The record-size field is a 2 byte varint and the record + ** fits entirely on the main b-tree page. */ + testcase( pCell+nCell+2==pPage->aDataEnd ); + c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); + }else{ + /* The record flows over onto one or more overflow pages. In + ** this case the whole cell needs to be parsed, a buffer allocated + ** and accessPayload() used to retrieve the record into the + ** buffer before VdbeRecordCompare() can be called. + ** + ** If the record is corrupt, the xRecordCompare routine may read + ** up to two varints past the end of the buffer. An extra 18 + ** bytes of padding is allocated at the end of the buffer in + ** case this happens. */ + void *pCellKey; + u8 * const pCellBody = pCell - pPage->childPtrSize; + const int nOverrun = 18; /* Size of the overrun padding */ + pPage->xParseCell(pPage, pCellBody, &pCur->info); + nCell = (int)pCur->info.nKey; + testcase( nCell<0 ); /* True if key size is 2^32 or more */ + testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */ + testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ + testcase( nCell==2 ); /* Minimum legal index key size */ + if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ + rc = SQLITE_CORRUPT_PAGE(pPage); + goto moveto_index_finish; + } + pCellKey = sqlite3Malloc( nCell+nOverrun ); + if( pCellKey==0 ){ + rc = SQLITE_NOMEM_BKPT; + goto moveto_index_finish; } - assert( - (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) - && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) - ); - if( c<0 ){ - lwr = idx+1; - }else if( c>0 ){ - upr = idx-1; - }else{ - assert( c==0 ); - *pRes = 0; - rc = SQLITE_OK; - pCur->aiIdx[pCur->iPage] = (u16)idx; - if( pIdxKey->errCode ) rc = SQLITE_CORRUPT; - goto moveto_finish; + pCur->ix = (u16)idx; + rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ + pCur->curFlags &= ~BTCF_ValidOvfl; + if( rc ){ + sqlite3_free(pCellKey); + goto moveto_index_finish; } - if( lwr>upr ) break; - assert( lwr+upr>=0 ); - idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ + c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); + sqlite3_free(pCellKey); } + assert( + (pIdxKey->errCode!=SQLITE_CORRUPT || c==0) + && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed) + ); + if( c<0 ){ + lwr = idx+1; + }else if( c>0 ){ + upr = idx-1; + }else{ + assert( c==0 ); + *pRes = 0; + rc = SQLITE_OK; + pCur->ix = (u16)idx; + if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT; + goto moveto_index_finish; + } + if( lwr>upr ) break; + assert( lwr+upr>=0 ); + idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */ } assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - pCur->aiIdx[pCur->iPage] = (u16)idx; + assert( pCur->ixpPage->nCell ); + pCur->ix = (u16)idx; *pRes = c; rc = SQLITE_OK; - goto moveto_finish; + goto moveto_index_finish; } -moveto_next_layer: if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(findCell(pPage, lwr)); } - pCur->aiIdx[pCur->iPage] = (u16)lwr; + pCur->ix = (u16)lwr; rc = moveToChild(pCur, chldPg); if( rc ) break; } -moveto_finish: +moveto_index_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; @@ -64181,10 +72001,37 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ } /* -** Advance the cursor to the next entry in the database. If -** successful then set *pRes=0. If the cursor -** was already pointing to the last entry in the database before -** this routine was called, then set *pRes=1. +** Return an estimate for the number of rows in the table that pCur is +** pointing to. Return a negative number if no estimate is currently +** available. +*/ +SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){ + i64 n; + u8 i; + + assert( cursorOwnsBtShared(pCur) ); + assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); + + /* Currently this interface is only called by the OP_IfSmaller + ** opcode, and it that case the cursor will always be valid and + ** will always point to a leaf node. */ + if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1; + if( NEVER(pCur->pPage->leaf==0) ) return -1; + + n = pCur->pPage->nCell; + for(i=0; iiPage; i++){ + n *= pCur->apPage[i]->nCell; + } + return n; +} + +/* +** Advance the cursor to the next entry in the database. +** Return value: +** +** SQLITE_OK success +** SQLITE_DONE cursor is already pointing at the last element +** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreeNext(). That routine is optimized ** for the common case of merely incrementing the cell counter BtCursor.aiIdx @@ -64192,23 +72039,18 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){ ** routine is called when it is necessary to move to a different page or ** to restore the cursor. ** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) +** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the +** cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument +** is a hint to the implement. SQLite btree implementation does not use +** this hint, but COMDB2 does. */ -static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ int rc; int idx; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - assert( *pRes==0 ); if( pCur->eState!=CURSOR_VALID ){ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); rc = restoreCursorPosition(pCur); @@ -64216,30 +72058,26 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ return rc; } if( CURSOR_INVALID==pCur->eState ){ - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } - if( pCur->skipNext ){ - assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); + if( pCur->eState==CURSOR_SKIPNEXT ){ pCur->eState = CURSOR_VALID; - if( pCur->skipNext>0 ){ - pCur->skipNext = 0; - return SQLITE_OK; - } - pCur->skipNext = 0; + if( pCur->skipNext>0 ) return SQLITE_OK; } } - pPage = pCur->apPage[pCur->iPage]; - idx = ++pCur->aiIdx[pCur->iPage]; - assert( pPage->isInit ); - - /* If the database file is corrupt, it is possible for the value of idx - ** to be invalid here. This can only occur if a second cursor modifies - ** the page while cursor pCur is holding a reference to it. Which can - ** only happen if the database is corrupt in such a way as to link the - ** page into more than one b-tree structure. */ - testcase( idx>pPage->nCell ); + pPage = pCur->pPage; + idx = ++pCur->ix; + if( !pPage->isInit || sqlite3FaultSim(412) ){ + /* The only known way for this to happen is for there to be a + ** recursive SQL function that does a DELETE operation as part of a + ** SELECT which deletes content out from under an active cursor + ** in a corrupt database file where the table being DELETE-ed from + ** has pages in common with the table being queried. See TH3 + ** module cov1/btree78.test testcase 220 (2018-06-08) for an + ** example. */ + return SQLITE_CORRUPT_BKPT; + } if( idx>=pPage->nCell ){ if( !pPage->leaf ){ @@ -64249,15 +72087,14 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ } do{ if( pCur->iPage==0 ){ - *pRes = 1; pCur->eState = CURSOR_INVALID; - return SQLITE_OK; + return SQLITE_DONE; } moveToParent(pCur); - pPage = pCur->apPage[pCur->iPage]; - }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); + pPage = pCur->pPage; + }while( pCur->ix>=pPage->nCell ); if( pPage->intKey ){ - return sqlite3BtreeNext(pCur, pRes); + return sqlite3BtreeNext(pCur, 0); }else{ return SQLITE_OK; } @@ -64268,20 +72105,18 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){ return moveToLeftmost(pCur); } } -SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ +SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){ MemPage *pPage; + UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ assert( cursorOwnsBtShared(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); + assert( flags==0 || flags==1 ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); - *pRes = 0; - if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); - pPage = pCur->apPage[pCur->iPage]; - if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){ - pCur->aiIdx[pCur->iPage]--; - return btreeNext(pCur, pRes); + if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur); + pPage = pCur->pPage; + if( (++pCur->ix)>=pPage->nCell ){ + pCur->ix--; + return btreeNext(pCur); } if( pPage->leaf ){ return SQLITE_OK; @@ -64291,10 +72126,12 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ } /* -** Step the cursor to the back to the previous entry in the database. If -** successful then set *pRes=0. If the cursor -** was already pointing to the first entry in the database before -** this routine was called, then set *pRes=1. +** Step the cursor to the back to the previous entry in the database. +** Return values: +** +** SQLITE_OK success +** SQLITE_DONE the cursor is already on the first element of the table +** otherwise some kind of error occurred ** ** The main entry point is sqlite3BtreePrevious(). That routine is optimized ** for the common case of merely decrementing the cell counter BtCursor.aiIdx @@ -64302,23 +72139,17 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ ** helper routine is called when it is necessary to move to a different page ** or to restore the cursor. ** -** The calling function will set *pRes to 0 or 1. The initial *pRes value -** will be 1 if the cursor being stepped corresponds to an SQL index and -** if this routine could have been skipped if that SQL index had been -** a unique index. Otherwise the caller will have set *pRes to zero. -** Zero is the common case. The btree implementation is free to use the -** initial *pRes value as a hint to improve performance, but the current -** SQLite btree implementation does not. (Note that the comdb2 btree -** implementation does use this hint, however.) +** If bit 0x01 of the F argument to sqlite3BtreePrevious(C,F) is 1, then +** the cursor corresponds to an SQL index and this routine could have been +** skipped if the SQL index had been a unique index. The F argument is a +** hint to the implement. The native SQLite btree implementation does not +** use this hint, but COMDB2 does. */ -static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ +static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){ int rc; MemPage *pPage; assert( cursorOwnsBtShared(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 ); assert( pCur->info.nSize==0 ); if( pCur->eState!=CURSOR_VALID ){ @@ -64327,64 +72158,55 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){ return rc; } if( CURSOR_INVALID==pCur->eState ){ - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } - if( pCur->skipNext ){ - assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT ); + if( CURSOR_SKIPNEXT==pCur->eState ){ pCur->eState = CURSOR_VALID; - if( pCur->skipNext<0 ){ - pCur->skipNext = 0; - return SQLITE_OK; - } - pCur->skipNext = 0; + if( pCur->skipNext<0 ) return SQLITE_OK; } } - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; assert( pPage->isInit ); if( !pPage->leaf ){ - int idx = pCur->aiIdx[pCur->iPage]; + int idx = pCur->ix; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ - while( pCur->aiIdx[pCur->iPage]==0 ){ + while( pCur->ix==0 ){ if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; - *pRes = 1; - return SQLITE_OK; + return SQLITE_DONE; } moveToParent(pCur); } assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 ); - pCur->aiIdx[pCur->iPage]--; - pPage = pCur->apPage[pCur->iPage]; + pCur->ix--; + pPage = pCur->pPage; if( pPage->intKey && !pPage->leaf ){ - rc = sqlite3BtreePrevious(pCur, pRes); + rc = sqlite3BtreePrevious(pCur, 0); }else{ rc = SQLITE_OK; } } return rc; } -SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ +SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){ assert( cursorOwnsBtShared(pCur) ); - assert( pRes!=0 ); - assert( *pRes==0 || *pRes==1 ); - assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); - *pRes = 0; + assert( flags==0 || flags==1 ); + UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */ pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; if( pCur->eState!=CURSOR_VALID - || pCur->aiIdx[pCur->iPage]==0 - || pCur->apPage[pCur->iPage]->leaf==0 + || pCur->ix==0 + || pCur->pPage->leaf==0 ){ - return btreePrevious(pCur, pRes); + return btreePrevious(pCur); } - pCur->aiIdx[pCur->iPage]--; + pCur->ix--; return SQLITE_OK; } @@ -64399,7 +72221,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ ** SQLITE_OK is returned on success. Any other return value indicates ** an error. *ppPage is set to NULL in the event of an error. ** -** If the "nearby" parameter is not 0, then an effort is made to +** If the "nearby" parameter is not 0, then an effort is made to ** locate a page close to the page number "nearby". This can be used in an ** attempt to keep related pages close to each other in the database file, ** which in turn can make database access faster. @@ -64441,7 +72263,7 @@ static int allocateBtreePage( Pgno iTrunk; u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ u32 nSearch = 0; /* Count of the number of search attempts */ - + /* If eMode==BTALLOC_EXACT and a query of the pointer-map ** shows that the page 'nearby' is somewhere on the free-list, then ** the entire-list will be searched for that page. @@ -64490,7 +72312,7 @@ static int allocateBtreePage( } testcase( iTrunk==mxPage ); if( iTrunk>mxPage || nSearch++ > n ){ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); }else{ rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); } @@ -64504,8 +72326,8 @@ static int allocateBtreePage( ** is the number of leaf page pointers to follow. */ k = get4byte(&pTrunk->aData[4]); if( k==0 && !searchList ){ - /* The trunk has no leaves and the list is not being searched. - ** So extract the trunk page itself and use it as the newly + /* The trunk has no leaves and the list is not being searched. + ** So extract the trunk page itself and use it as the newly ** allocated page */ assert( pPrevTrunk==0 ); rc = sqlite3PagerWrite(pTrunk->pDbPage); @@ -64519,11 +72341,11 @@ static int allocateBtreePage( TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ - rc = SQLITE_CORRUPT_BKPT; + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM - }else if( searchList - && (nearby==iTrunk || (iTrunkaData[0], &pTrunk->aData[0], 4); } }else{ - /* The trunk page is required by the caller but it contains + /* The trunk page is required by the caller but it contains ** pointers to free-list leaves. The first leaf becomes a trunk ** page in this case. */ MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); - if( iNewTrunk>mxPage ){ - rc = SQLITE_CORRUPT_BKPT; + if( iNewTrunk>mxPage ){ + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iNewTrunk==mxPage ); @@ -64617,13 +72439,13 @@ static int allocateBtreePage( iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); - if( iPage>mxPage ){ - rc = SQLITE_CORRUPT_BKPT; + if( iPage>mxPage || iPage<2 ){ + rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iPage==mxPage ); - if( !searchList - || (iPage==nearby || (iPagepPage1; /* Local reference to page 1 */ MemPage *pPage; /* Page being freed. May be NULL. */ int rc; /* Return Code */ - int nFree; /* Initial number of pages on free-list */ + u32 nFree; /* Initial number of pages on free-list */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( CORRUPT_DB || iPage>1 ); assert( !pMemPage || pMemPage->pgno==iPage ); - if( iPage<2 ) return SQLITE_CORRUPT_BKPT; + if( iPage<2 || iPage>pBt->nPage ){ + return SQLITE_CORRUPT_BKPT; + } if( pMemPage ){ pPage = pMemPage; sqlite3PagerRef(pPage->pDbPage); @@ -64789,6 +72613,10 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ u32 nLeaf; /* Initial number of leaf cells on trunk page */ iTrunk = get4byte(&pPage1->aData[32]); + if( iTrunk>btreePagecount(pBt) ){ + rc = SQLITE_CORRUPT_BKPT; + goto freepage_out; + } rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); if( rc!=SQLITE_OK ){ goto freepage_out; @@ -64836,7 +72664,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ /* If control flows to this point, then it was not possible to add the ** the page being freed as a leaf page of the first trunk in the free-list. - ** Possibly because the free-list is empty, or possibly because the + ** Possibly because the free-list is empty, or possibly because the ** first trunk in the free-list is full. Either way, the page being freed ** will become the new first trunk page in the free-list. */ @@ -64867,42 +72695,41 @@ static void freePage(MemPage *pPage, int *pRC){ } /* -** Free any overflow pages associated with the given Cell. Write the -** local Cell size (the number of bytes on the original page, omitting -** overflow) into *pnSize. +** Free the overflow pages associated with the given Cell. */ -static int clearCell( +static SQLITE_NOINLINE int clearCellOverflow( MemPage *pPage, /* The page that contains the Cell */ unsigned char *pCell, /* First byte of the Cell */ CellInfo *pInfo /* Size information about the cell */ ){ - BtShared *pBt = pPage->pBt; + BtShared *pBt; Pgno ovflPgno; int rc; int nOvfl; u32 ovflPageSize; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - pPage->xParseCell(pPage, pCell, pInfo); - if( pInfo->nLocal==pInfo->nPayload ){ - return SQLITE_OK; /* No overflow pages. Return without doing anything */ - } - if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){ - return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */ + assert( pInfo->nLocal!=pInfo->nPayload ); + testcase( pCell + pInfo->nSize == pPage->aDataEnd ); + testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); + if( pCell + pInfo->nSize > pPage->aDataEnd ){ + /* Cell extends past end of page */ + return SQLITE_CORRUPT_PAGE(pPage); } ovflPgno = get4byte(pCell + pInfo->nSize - 4); + pBt = pPage->pBt; assert( pBt->usableSize > 4 ); ovflPageSize = pBt->usableSize - 4; nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize; - assert( nOvfl>0 || + assert( nOvfl>0 || (CORRUPT_DB && (pInfo->nPayload + ovflPageSize)btreePagecount(pBt) ){ - /* 0 is not a legal page number and page 1 cannot be an - ** overflow page. Therefore if ovflPgno<2 or past the end of the + /* 0 is not a legal page number and page 1 cannot be an + ** overflow page. Therefore if ovflPgno<2 or past the end of the ** file the database must be corrupt. */ return SQLITE_CORRUPT_BKPT; } @@ -64914,11 +72741,11 @@ static int clearCell( if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) ) && sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1 ){ - /* There is no reason any cursor should have an outstanding reference + /* There is no reason any cursor should have an outstanding reference ** to an overflow page belonging to a cell that is being deleted/updated. - ** So if there exists more than one reference to this page, then it - ** must not really be an overflow page and the database must be corrupt. - ** It is helpful to detect this before calling freePage2(), as + ** So if there exists more than one reference to this page, then it + ** must not really be an overflow page and the database must be corrupt. + ** It is helpful to detect this before calling freePage2(), as ** freePage2() may zero the page contents if secure-delete mode is ** enabled. If this 'overflow' page happens to be a page that the ** caller is iterating through or using in some other way, this @@ -64938,6 +72765,21 @@ static int clearCell( return SQLITE_OK; } +/* Call xParseCell to compute the size of a cell. If the cell contains +** overflow, then invoke cellClearOverflow to clear out that overflow. +** STore the result code (SQLITE_OK or some error code) in rc. +** +** Implemented as macro to force inlining for performance. +*/ +#define BTREE_CLEAR_CELL(rc, pPage, pCell, sInfo) \ + pPage->xParseCell(pPage, pCell, &sInfo); \ + if( sInfo.nLocal!=sInfo.nPayload ){ \ + rc = clearCellOverflow(pPage, pCell, &sInfo); \ + }else{ \ + rc = SQLITE_OK; \ + } + + /* ** Create the byte sequence used to represent a cell on page pPage ** and write that byte sequence into pCell[]. Overflow pages are @@ -64958,21 +72800,20 @@ static int fillInCell( ){ int nPayload; const u8 *pSrc; - int nSrc, n, rc; + int nSrc, n, rc, mn; int spaceLeft; - MemPage *pOvfl = 0; - MemPage *pToRelease = 0; + MemPage *pToRelease; unsigned char *pPrior; unsigned char *pPayload; - BtShared *pBt = pPage->pBt; - Pgno pgnoOvfl = 0; + BtShared *pBt; + Pgno pgnoOvfl; int nHeader; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); /* pPage is not necessarily writeable since pCell might be auxiliary ** buffer space that is separate from the pPage buffer area */ - assert( pCellaData || pCell>=&pPage->aData[pBt->pageSize] + assert( pCellaData || pCell>=&pPage->aData[pPage->pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ @@ -64990,27 +72831,38 @@ static int fillInCell( pSrc = pX->pKey; nHeader += putVarint32(&pCell[nHeader], nPayload); } - + /* Fill in the payload */ + pPayload = &pCell[nHeader]; if( nPayload<=pPage->maxLocal ){ + /* This is the common case where everything fits on the btree page + ** and no overflow pages are required. */ n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); if( n<4 ) n = 4; *pnSize = n; - spaceLeft = nPayload; - pPrior = pCell; - }else{ - int mn = pPage->minLocal; - n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); - testcase( n==pPage->maxLocal ); - testcase( n==pPage->maxLocal+1 ); - if( n > pPage->maxLocal ) n = mn; - spaceLeft = n; - *pnSize = n + nHeader + 4; - pPrior = &pCell[nHeader+n]; + assert( nSrc<=nPayload ); + testcase( nSrcminLocal; + n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4); + testcase( n==pPage->maxLocal ); + testcase( n==pPage->maxLocal+1 ); + if( n > pPage->maxLocal ) n = mn; + spaceLeft = n; + *pnSize = n + nHeader + 4; + pPrior = &pCell[nHeader+n]; + pToRelease = 0; + pgnoOvfl = 0; + pBt = pPage->pBt; /* At this point variables should be set as follows: ** @@ -65024,7 +72876,7 @@ static int fillInCell( ** Use a call to btreeParseCellPtr() to verify that the values above ** were computed correctly. */ -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG { CellInfo info; pPage->xParseCell(pPage, pCell, &info); @@ -65036,15 +72888,42 @@ static int fillInCell( #endif /* Write the payload into the local Cell and any extra into overflow pages */ - while( nPayload>0 ){ + while( 1 ){ + n = nPayload; + if( n>spaceLeft ) n = spaceLeft; + + /* If pToRelease is not zero than pPayload points into the data area + ** of pToRelease. Make sure pToRelease is still writeable. */ + assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); + + /* If pPayload is part of the data area of pPage, then make sure pPage + ** is still writeable */ + assert( pPayloadaData || pPayload>=&pPage->aData[pBt->pageSize] + || sqlite3PagerIswriteable(pPage->pDbPage) ); + + if( nSrc>=n ){ + memcpy(pPayload, pSrc, n); + }else if( nSrc>0 ){ + n = nSrc; + memcpy(pPayload, pSrc, n); + }else{ + memset(pPayload, 0, n); + } + nPayload -= n; + if( nPayload<=0 ) break; + pPayload += n; + pSrc += n; + nSrc -= n; + spaceLeft -= n; if( spaceLeft==0 ){ + MemPage *pOvfl = 0; #ifndef SQLITE_OMIT_AUTOVACUUM Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */ if( pBt->autoVacuum ){ do{ pgnoOvfl++; - } while( - PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt) + } while( + PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt) ); } #endif @@ -65052,9 +72931,9 @@ static int fillInCell( #ifndef SQLITE_OMIT_AUTOVACUUM /* If the database supports auto-vacuum, and the second or subsequent ** overflow page is being allocated, add an entry to the pointer-map - ** for that page now. + ** for that page now. ** - ** If this is the first overflow page, then write a partial entry + ** If this is the first overflow page, then write a partial entry ** to the pointer-map. If we write nothing to this pointer-map slot, ** then the optimistic overflow chain processing in clearCell() ** may misinterpret the uninitialized values and delete the @@ -65090,30 +72969,6 @@ static int fillInCell( pPayload = &pOvfl->aData[4]; spaceLeft = pBt->usableSize - 4; } - n = nPayload; - if( n>spaceLeft ) n = spaceLeft; - - /* If pToRelease is not zero than pPayload points into the data area - ** of pToRelease. Make sure pToRelease is still writeable. */ - assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) ); - - /* If pPayload is part of the data area of pPage, then make sure pPage - ** is still writeable */ - assert( pPayloadaData || pPayload>=&pPage->aData[pBt->pageSize] - || sqlite3PagerIswriteable(pPage->pDbPage) ); - - if( nSrc>0 ){ - if( n>nSrc ) n = nSrc; - assert( pSrc ); - memcpy(pPayload, pSrc, n); - }else{ - memset(pPayload, 0, n); - } - nPayload -= n; - pPayload += n; - pSrc += n; - nSrc -= n; - spaceLeft -= n; } releasePage(pToRelease); return SQLITE_OK; @@ -65135,17 +72990,26 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; - assert( idx>=0 && idxnCell ); + assert( idx>=0 ); + assert( idxnCell ); assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; + assert( pPage->pBt->usableSize > (u32)(ptr-data) ); pc = get2byte(ptr); hdr = pPage->hdrOffset; - testcase( pc==get2byte(&data[hdr+5]) ); +#if 0 /* Not required. Omit for efficiency */ + if( pcnCell*2 ){ + *pRC = SQLITE_CORRUPT_BKPT; + return; + } +#endif + testcase( pc==(u32)get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); - if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){ + if( pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT; return; } @@ -65176,8 +73040,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either -** in pTemp or the original pCell) and also record its index. -** Allocating a new entry in pPage->aCell[] implies that +** in pTemp or the original pCell) and also record its index. +** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. ** ** *pRC must be SQLITE_OK when this routine is called. @@ -65203,12 +73067,8 @@ static void insertCell( assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); - /* The cell should normally be sized correctly. However, when moving a - ** malformed cell from a leaf page to an interior page, if the cell size - ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size - ** might be less than 8 (leaf-size + pointer) on the interior node. Hence - ** the term after the || in the following assert(). */ - assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) ); + assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB ); + assert( pPage->nFree>=0 ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); @@ -65249,9 +73109,16 @@ static void insertCell( assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); - memcpy(&data[idx], pCell, sz); if( iChild ){ + /* In a corrupt database where an entry in the cell index section of + ** a btree page has a value of 3 or less, the pCell value might point + ** as many as 4 bytes in front of the start of the aData buffer for + ** the source page. Make sure this does not cause problems by not + ** reading the first 4 bytes */ + memcpy(&data[idx+4], pCell+4, sz-4); put4byte(&data[idx], iChild); + }else{ + memcpy(&data[idx], pCell, sz); } pIns = pPage->aCellIdx + i*2; memmove(pIns+2, pIns, 2*(pPage->nCell - i)); @@ -65259,21 +73126,100 @@ static void insertCell( pPage->nCell++; /* increment the cell count */ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; - assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell ); + assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB ); #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ /* The cell may contain a pointer to an overflow page. If so, write ** the entry for the overflow page into the pointer map. */ - ptrmapPutOvflPtr(pPage, pCell, pRC); + ptrmapPutOvflPtr(pPage, pPage, pCell, pRC); } #endif } } +/* +** The following parameters determine how many adjacent pages get involved +** in a balancing operation. NN is the number of neighbors on either side +** of the page that participate in the balancing operation. NB is the +** total number of pages that participate, including the target page and +** NN neighbors on either side. +** +** The minimum value of NN is 1 (of course). Increasing NN above 1 +** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance +** in exchange for a larger degradation in INSERT and UPDATE performance. +** The value of NN appears to give the best results overall. +** +** (Later:) The description above makes it seem as if these values are +** tunable - as if you could change them and recompile and it would all work. +** But that is unlikely. NB has been 3 since the inception of SQLite and +** we have never tested any other value. +*/ +#define NN 1 /* Number of neighbors on either side of pPage */ +#define NB 3 /* (NN*2+1): Total pages involved in the balance */ + /* ** A CellArray object contains a cache of pointers and sizes for a ** consecutive sequence of cells that might be held on multiple pages. +** +** The cells in this array are the divider cell or cells from the pParent +** page plus up to three child pages. There are a total of nCell cells. +** +** pRef is a pointer to one of the pages that contributes cells. This is +** used to access information such as MemPage.intKey and MemPage.pBt->pageSize +** which should be common to all pages that contribute cells to this array. +** +** apCell[] and szCell[] hold, respectively, pointers to the start of each +** cell and the size of each cell. Some of the apCell[] pointers might refer +** to overflow cells. In other words, some apCel[] pointers might not point +** to content area of the pages. +** +** A szCell[] of zero means the size of that cell has not yet been computed. +** +** The cells come from as many as four different pages: +** +** ----------- +** | Parent | +** ----------- +** / | \ +** / | \ +** --------- --------- --------- +** |Child-1| |Child-2| |Child-3| +** --------- --------- --------- +** +** The order of cells is in the array is for an index btree is: +** +** 1. All cells from Child-1 in order +** 2. The first divider cell from Parent +** 3. All cells from Child-2 in order +** 4. The second divider cell from Parent +** 5. All cells from Child-3 in order +** +** For a table-btree (with rowids) the items 2 and 4 are empty because +** content exists only in leaves and there are no divider cells. +** +** For an index btree, the apEnd[] array holds pointer to the end of page +** for Child-1, the Parent, Child-2, the Parent (again), and Child-3, +** respectively. The ixNx[] array holds the number of cells contained in +** each of these 5 stages, and all stages to the left. Hence: +** +** ixNx[0] = Number of cells in Child-1. +** ixNx[1] = Number of cells in Child-1 plus 1 for first divider. +** ixNx[2] = Number of cells in Child-1 and Child-2 + 1 for 1st divider. +** ixNx[3] = Number of cells in Child-1 and Child-2 + both divider cells +** ixNx[4] = Total number of cells. +** +** For a table-btree, the concept is similar, except only apEnd[0]..apEnd[2] +** are used and they point to the leaf pages only, and the ixNx value are: +** +** ixNx[0] = Number of cells in Child-1. +** ixNx[1] = Number of cells in Child-1 and Child-2. +** ixNx[2] = Total number of cells. +** +** Sometimes when deleting, a child page can have zero cells. In those +** cases, ixNx[] entries with higher indexes, and the corresponding apEnd[] +** entries, shift down. The end result is that each ixNx[] entry should +** be larger than the previous */ typedef struct CellArray CellArray; struct CellArray { @@ -65281,6 +73227,8 @@ struct CellArray { MemPage *pRef; /* Reference page */ u8 **apCell; /* All cells begin balanced */ u16 *szCell; /* Local size of all cells in apCell[] */ + u8 *apEnd[NB*2]; /* MemPage.aDataEnd values */ + int ixNx[NB*2]; /* Index of at which we move to the next apEnd[] */ }; /* @@ -65318,49 +73266,71 @@ static u16 cachedCellSize(CellArray *p, int N){ } /* -** Array apCell[] contains pointers to nCell b-tree page cells. The +** Array apCell[] contains pointers to nCell b-tree page cells. The ** szCell[] array contains the size in bytes of each cell. This function ** replaces the current contents of page pPg with the contents of the cell ** array. ** ** Some of the cells in apCell[] may currently be stored in pPg. This -** function works around problems caused by this by making a copy of any +** function works around problems caused by this by making a copy of any ** such cells before overwriting the page data. ** -** The MemPage.nFree field is invalidated by this function. It is the +** The MemPage.nFree field is invalidated by this function. It is the ** responsibility of the caller to set it correctly. */ static int rebuildPage( - MemPage *pPg, /* Edit this page */ + CellArray *pCArray, /* Content to be added to page pPg */ + int iFirst, /* First cell in pCArray to use */ int nCell, /* Final number of cells on page */ - u8 **apCell, /* Array of cells */ - u16 *szCell /* Array of cell sizes */ + MemPage *pPg /* The page to be reconstructed */ ){ const int hdr = pPg->hdrOffset; /* Offset of header on pPg */ u8 * const aData = pPg->aData; /* Pointer to data for pPg */ const int usableSize = pPg->pBt->usableSize; u8 * const pEnd = &aData[usableSize]; - int i; + int i = iFirst; /* Which cell to copy from pCArray*/ + u32 j; /* Start of cell content area */ + int iEnd = i+nCell; /* Loop terminator */ u8 *pCellptr = pPg->aCellIdx; u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager); u8 *pData; + int k; /* Current slot in pCArray->apEnd[] */ + u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */ - i = get2byte(&aData[hdr+5]); - memcpy(&pTmp[i], &aData[i], usableSize - i); + assert( i(u32)usableSize ){ j = 0; } + memcpy(&pTmp[j], &aData[j], usableSize - j); + + for(k=0; pCArray->ixNx[k]<=i && ALWAYS(kapEnd[k]; pData = pEnd; - for(i=0; iapCell[i]; + u16 sz = pCArray->szCell[i]; + assert( sz>0 ); + if( SQLITE_WITHIN(pCell,aData+j,pEnd) ){ + if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT; pCell = &pTmp[pCell - aData]; + }else if( (uptr)(pCell+sz)>(uptr)pSrcEnd + && (uptr)(pCell)<(uptr)pSrcEnd + ){ + return SQLITE_CORRUPT_BKPT; } - pData -= szCell[i]; + + pData -= sz; put2byte(pCellptr, (pData - aData)); pCellptr += 2; if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT; - memcpy(pData, pCell, szCell[i]); - assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); - testcase( szCell[i]!=pPg->xCellSize(pPg,pCell) ); + memmove(pData, pCell, sz); + assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); + i++; + if( i>=iEnd ) break; + if( pCArray->ixNx[k]<=i ){ + k++; + pSrcEnd = pCArray->apEnd[k]; + } } /* The pPg->nFree field is now set incorrectly. The caller will fix it. */ @@ -65375,12 +73345,11 @@ static int rebuildPage( } /* -** Array apCell[] contains nCell pointers to b-tree cells. Array szCell -** contains the size in bytes of each such cell. This function attempts to -** add the cells stored in the array to page pPg. If it cannot (because -** the page needs to be defragmented before the cells will fit), non-zero -** is returned. Otherwise, if the cells are added successfully, zero is -** returned. +** The pCArray objects contains pointers to b-tree cells and the cell sizes. +** This function attempts to add the cells stored in the array to page pPg. +** If it cannot (because the page needs to be defragmented before the cells +** will fit), non-zero is returned. Otherwise, if the cells are added +** successfully, zero is returned. ** ** Argument pCellptr points to the first entry in the cell-pointer array ** (part of page pPg) to populate. After cell apCell[0] is written to the @@ -65388,7 +73357,7 @@ static int rebuildPage( ** cell in the array. It is the responsibility of the caller to ensure ** that it is safe to overwrite this part of the cell-pointer array. ** -** When this function is called, *ppData points to the start of the +** When this function is called, *ppData points to the start of the ** content area on page pPg. If the size of the content area is extended, ** *ppData is updated to point to the new start of the content area ** before returning. @@ -65402,21 +73371,27 @@ static int rebuildPage( static int pageInsertArray( MemPage *pPg, /* Page to add cells to */ u8 *pBegin, /* End of cell-pointer array */ - u8 **ppData, /* IN/OUT: Page content -area pointer */ + u8 **ppData, /* IN/OUT: Page content-area pointer */ u8 *pCellptr, /* Pointer to cell-pointer area */ int iFirst, /* Index of first cell to add */ int nCell, /* Number of cells to add to pPg */ CellArray *pCArray /* Array of cells */ ){ - int i; - u8 *aData = pPg->aData; - u8 *pData = *ppData; - int iEnd = iFirst + nCell; + int i = iFirst; /* Loop counter - cell index to insert */ + u8 *aData = pPg->aData; /* Complete page */ + u8 *pData = *ppData; /* Content area. A subset of aData[] */ + int iEnd = iFirst + nCell; /* End of loop. One past last cell to ins */ + int k; /* Current slot in pCArray->apEnd[] */ + u8 *pEnd; /* Maximum extent of cell data */ assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */ - for(i=iFirst; iixNx[k]<=i && ALWAYS(kapEnd[k]; + while( 1 /*Exit by break*/ ){ int sz, rc; u8 *pSlot; - sz = cachedCellSize(pCArray, i); + assert( pCArray->szCell[i]!=0 ); + sz = pCArray->szCell[i]; if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){ if( (pData - pBegin)apCell[i] || pSlot>=(pCArray->apCell[i]+sz) || CORRUPT_DB ); + if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd + && (uptr)(pCArray->apCell[i])<(uptr)pEnd + ){ + assert( CORRUPT_DB ); + (void)SQLITE_CORRUPT_BKPT; + return 1; + } memmove(pSlot, pCArray->apCell[i], sz); put2byte(pCellptr, (pSlot - aData)); pCellptr += 2; + i++; + if( i>=iEnd ) break; + if( pCArray->ixNx[k]<=i ){ + k++; + pEnd = pCArray->apEnd[k]; + } } *ppData = pData; return 0; } /* -** Array apCell[] contains nCell pointers to b-tree cells. Array szCell -** contains the size in bytes of each such cell. This function adds the -** space associated with each cell in the array that is currently stored -** within the body of pPg to the pPg free-list. The cell-pointers and other -** fields of the page are not updated. +** The pCArray object contains pointers to b-tree cells and their sizes. +** +** This function adds the space associated with each cell in the array +** that is currently stored within the body of pPg to the pPg free-list. +** The cell-pointers and other fields of the page are not updated. ** ** This function returns the total number of cells added to the free-list. */ @@ -65475,7 +73463,9 @@ static int pageFreeArray( } pFree = pCell; szFree = sz; - if( pFree+sz>pEnd ) return 0; + if( pFree+sz>pEnd ){ + return 0; + } }else{ pFree = pCell; szFree += sz; @@ -65491,9 +73481,9 @@ static int pageFreeArray( } /* -** apCell[] and szCell[] contains pointers to and sizes of all cells in the -** pages being balanced. The current page, pPg, has pPg->nCell cells starting -** with apCell[iOld]. After balancing, this page should hold nNew cells +** pCArray contains pointers to and sizes of all cells in the page being +** balanced. The current page, pPg, has pPg->nCell cells starting with +** pCArray->apCell[iOld]. After balancing, this page should hold nNew cells ** starting at apCell[iNew]. ** ** This routine makes the necessary adjustments to pPg so that it contains @@ -65525,22 +73515,28 @@ static int editPage( #endif /* Remove cells from the start and end of the page */ + assert( nCell>=0 ); if( iOldnCell) ) return SQLITE_CORRUPT_BKPT; memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2); nCell -= nShift; } if( iNewEnd < iOldEnd ){ - nCell -= pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); + int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray); + assert( nCell>=nTail ); + nCell -= nTail; } pData = &aData[get2byteNotZero(&aData[hdr+5])]; if( pDatapPg->aDataEnd ) goto editpage_fail; /* Add cells to the start of the page */ if( iNew=0 ); pCellptr = pPg->aCellIdx; memmove(&pCellptr[nAdd*2], pCellptr, nCell*2); if( pageInsertArray( @@ -65555,8 +73551,11 @@ static int editPage( int iCell = (iOld + pPg->aiOvfl[i]) - iNew; if( iCell>=0 && iCellaCellIdx[iCell * 2]; - memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + if( nCell>iCell ){ + memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + } nCell++; + cachedCellSize(pCArray, iCell+iNew); if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iCell+iNew, 1, pCArray @@ -65565,6 +73564,7 @@ static int editPage( } /* Append cells to the end of the page */ + assert( nCell>=0 ); pCellptr = &pPg->aCellIdx[nCell*2]; if( pageInsertArray( pPg, pBegin, &pData, pCellptr, @@ -65593,24 +73593,9 @@ static int editPage( editpage_fail: /* Unable to edit this page. Rebuild it from scratch instead. */ populateCellCache(pCArray, iNew, nNew); - return rebuildPage(pPg, nNew, &pCArray->apCell[iNew], &pCArray->szCell[iNew]); + return rebuildPage(pCArray, iNew, nNew, pPg); } -/* -** The following parameters determine how many adjacent pages get involved -** in a balancing operation. NN is the number of neighbors on either side -** of the page that participate in the balancing operation. NB is the -** total number of pages that participate, including the target page and -** NN neighbors on either side. -** -** The minimum value of NN is 1 (of course). Increasing NN above 1 -** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance -** in exchange for a larger degradation in INSERT and UPDATE performance. -** The value of NN appears to give the best results overall. -*/ -#define NN 1 /* Number of neighbors on either side of pPage */ -#define NB (NN*2+1) /* Total pages involved in the balance */ - #ifndef SQLITE_OMIT_QUICKBALANCE /* @@ -65646,10 +73631,11 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); - /* This error condition is now caught prior to reaching this function */ - if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT; + if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */ + assert( pPage->nFree>=0 ); + assert( pParent->nFree>=0 ); - /* Allocate a new page. This page will become the right-sibling of + /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell ** may be inserted. If both these operations are successful, proceed. */ @@ -65661,16 +73647,26 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ u8 *pCell = pPage->apOvfl[0]; u16 szCell = pPage->xCellSize(pPage, pCell); u8 *pStop; + CellArray b; assert( sqlite3PagerIswriteable(pNew->pDbPage) ); - assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); + assert( CORRUPT_DB || pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) ); zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF); - rc = rebuildPage(pNew, 1, &pCell, &szCell); - if( NEVER(rc) ) return rc; + b.nCell = 1; + b.pRef = pPage; + b.apCell = &pCell; + b.szCell = &szCell; + b.apEnd[0] = pPage->aDataEnd; + b.ixNx[0] = 2; + rc = rebuildPage(&b, 0, 1, pNew); + if( NEVER(rc) ){ + releasePage(pNew); + return rc; + } pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell; /* If this is an auto-vacuum database, update the pointer map - ** with entries for the new page, and any pointer from the + ** with entries for the new page, and any pointer from the ** cell on the page to an overflow page. If either of these ** operations fails, the return code is set, but the contents ** of the parent page are still manipulated by thh code below. @@ -65681,17 +73677,17 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ if( ISAUTOVACUUM ){ ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc); if( szCell>pNew->minLocal ){ - ptrmapPutOvflPtr(pNew, pCell, &rc); + ptrmapPutOvflPtr(pNew, pNew, pCell, &rc); } } - + /* Create a divider cell to insert into pParent. The divider cell ** consists of a 4-byte page number (the page number of pPage) and ** a variable length key value (which must be the same value as the ** largest key on pPage). ** - ** To find the largest key value on pPage, first find the right-most - ** cell on pPage. The first two fields of this cell are the + ** To find the largest key value on pPage, first find the right-most + ** cell on pPage. The first two fields of this cell are the ** record-length (a variable length integer at most 32-bits in size) ** and the key value (a variable length integer, may have any value). ** The first of the while(...) loops below skips over the record-length @@ -65712,7 +73708,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ /* Set the right-child pointer of pParent to point to the new page. */ put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); - + /* Release the reference to the new page. */ releasePage(pNew); } @@ -65724,7 +73720,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ #if 0 /* ** This function does not contribute anything to the operation of SQLite. -** it is sometimes activated temporarily while debugging code responsible +** it is sometimes activated temporarily while debugging code responsible ** for setting pointer-map entries. */ static int ptrmapCheckPages(MemPage **apPage, int nPage){ @@ -65739,7 +73735,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){ for(j=0; jnCell; j++){ CellInfo info; u8 *z; - + z = findCell(pPage, j); pPage->xParseCell(pPage, z, &info); if( info.nLocalpgno==1) ? 100 : 0); int rc; int iData; - - + + assert( pFrom->isInit ); assert( pFrom->nFree>=iToHdr ); assert( get2byte(&aFrom[iFromHdr+5]) <= (int)pBt->usableSize ); - + /* Copy the b-tree node content from page pFrom to page pTo. */ iData = get2byte(&aFrom[iFromHdr+5]); memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData); memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell); - + /* Reinitialize page pTo so that the contents of the MemPage structure ** match the new data. The initialization of pTo can actually fail under - ** fairly obscure circumstances, even though it is a copy of initialized + ** fairly obscure circumstances, even though it is a copy of initialized ** page pFrom. */ pTo->isInit = 0; rc = btreeInitPage(pTo); + if( rc==SQLITE_OK ) rc = btreeComputeFreeSpace(pTo); if( rc!=SQLITE_OK ){ *pRC = rc; return; } - + /* If this is an auto-vacuum database, update the pointer-map entries ** for any b-tree or overflow pages that pTo now contains the pointers to. */ @@ -65826,13 +73823,13 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ ** (hereafter "the page") and up to 2 siblings so that all pages have about the ** same amount of free space. Usually a single sibling on either side of the ** page are used in the balancing, though both siblings might come from one -** side if the page is the first or last child of its parent. If the page +** side if the page is the first or last child of its parent. If the page ** has fewer than 2 siblings (something which can only happen if the page ** is a root page or a child of a root page) then all available siblings ** participate in the balancing. ** -** The number of siblings of the page might be increased or decreased by -** one or two in an effort to keep pages nearly full but not over full. +** The number of siblings of the page might be increased or decreased by +** one or two in an effort to keep pages nearly full but not over full. ** ** Note that when this routine is called, some of the cells on the page ** might not actually be stored in MemPage.aData[]. This can happen @@ -65843,7 +73840,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ ** inserted into or removed from the parent page (pParent). Doing so ** may cause the parent page to become overfull or underfull. If this ** happens, it is the responsibility of the caller to invoke the correct -** balancing routine to fix this problem (see the balance() routine). +** balancing routine to fix this problem (see the balance() routine). ** ** If this routine fails for any reason, it might leave the database ** in a corrupted state. So if this routine fails, the database should @@ -65858,7 +73855,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ ** of the page-size, the aOvflSpace[] buffer is guaranteed to be large ** enough for all overflow cells. ** -** If aOvflSpace is set to a null pointer, this function returns +** If aOvflSpace is set to a null pointer, this function returns ** SQLITE_NOMEM. */ static int balance_nonroot( @@ -65895,21 +73892,16 @@ static int balance_nonroot( Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ - CellArray b; /* Parsed information on cells being balanced */ + CellArray b; /* Parsed information on cells being balanced */ memset(abDone, 0, sizeof(abDone)); - b.nCell = 0; - b.apCell = 0; + memset(&b, 0, sizeof(b)); pBt = pParent->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); -#if 0 - TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); -#endif - /* At this point pParent may have at most one overflow cell. And if - ** this overflow cell is present, it must be the cell with + ** this overflow cell is present, it must be the cell with ** index iParentIdx. This scenario comes about when this function ** is called (indirectly) from sqlite3BtreeDelete(). */ @@ -65919,12 +73911,13 @@ static int balance_nonroot( if( !aOvflSpace ){ return SQLITE_NOMEM_BKPT; } + assert( pParent->nFree>=0 ); - /* Find the sibling pages to balance. Also locate the cells in pParent - ** that divide the siblings. An attempt is made to find NN siblings on - ** either side of pPage. More siblings are taken from one side, however, + /* Find the sibling pages to balance. Also locate the cells in pParent + ** that divide the siblings. An attempt is made to find NN siblings on + ** either side of pPage. More siblings are taken from one side, however, ** if there are fewer than NN siblings on the other side. If pParent - ** has NB or fewer children then all children of pParent are taken. + ** has NB or fewer children then all children of pParent are taken. ** ** This loop also drops the divider cells from the parent page. This ** way, the remainder of the function does not have to deal with any @@ -65936,7 +73929,7 @@ static int balance_nonroot( nxDiv = 0; }else{ assert( bBulk==0 || bBulk==1 ); - if( iParentIdx==0 ){ + if( iParentIdx==0 ){ nxDiv = 0; }else if( iParentIdx==i ){ nxDiv = i-2+bBulk; @@ -65953,12 +73946,21 @@ static int balance_nonroot( } pgno = get4byte(pRight); while( 1 ){ - rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); + if( rc==SQLITE_OK ){ + rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); + } if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } - nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; + if( apOld[i]->nFree<0 ){ + rc = btreeComputeFreeSpace(apOld[i]); + if( rc ){ + memset(apOld, 0, (i)*sizeof(MemPage*)); + goto balance_cleanup; + } + } + nMaxCells += apOld[i]->nCell + ArraySize(pParent->apOvfl); if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ @@ -65976,22 +73978,20 @@ static int balance_nonroot( ** This is safe because dropping a cell only overwrites the first ** four bytes of it, and this function does not need the first ** four bytes of the divider cell. So the pointer is safe to use - ** later on. + ** later on. ** ** But not if we are in secure-delete mode. In secure-delete mode, ** the dropCell() routine will overwrite the entire cell with zeroes. ** In this case, temporarily copy the cell into the aOvflSpace[] ** buffer. It will be copied out again as soon as the aSpace[] buffer ** is allocated. */ - if( pBt->btsFlags & BTS_SECURE_DELETE ){ + if( pBt->btsFlags & BTS_FAST_SECURE ){ int iOff; + /* If the following if() condition is not true, the db is corrupted. + ** The call to dropCell() below will detect this. */ iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData); - if( (iOff+szNew[i])>(int)pBt->usableSize ){ - rc = SQLITE_CORRUPT_BKPT; - memset(apOld, 0, (i+1)*sizeof(MemPage*)); - goto balance_cleanup; - }else{ + if( (iOff+szNew[i])<=(int)pBt->usableSize ){ memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]); apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData]; } @@ -66012,10 +74012,8 @@ static int balance_nonroot( + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ - /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer - ** that is more than 6 times the database page size. */ - assert( szScratch<=6*(int)pBt->pageSize ); - b.apCell = sqlite3ScratchMalloc( szScratch ); + assert( szScratch<=7*(int)pBt->pageSize ); + b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ rc = SQLITE_NOMEM_BKPT; goto balance_cleanup; @@ -66050,6 +74048,7 @@ static int balance_nonroot( u16 maskPage = pOld->maskPage; u8 *piCell = aData + pOld->cellOffset; u8 *piEnd; + VVA_ONLY( int nCellAtStart = b.nCell; ) /* Verify that all sibling pages are of the same "type" (table-leaf, ** table-interior, index-leaf, or index-interior). @@ -66060,7 +74059,7 @@ static int balance_nonroot( } /* Load b.apCell[] with pointers to all cells in pOld. If pOld - ** constains overflow cells, include them in the b.apCell[] array + ** contains overflow cells, include them in the b.apCell[] array ** in the correct spot. ** ** Note that when there are multiple overflow cells, it is always the @@ -66078,6 +74077,10 @@ static int balance_nonroot( */ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ + if( NEVER(limitaiOvfl[0]) ){ + rc = SQLITE_CORRUPT_BKPT; + goto balance_cleanup; + } limit = pOld->aiOvfl[0]; for(j=0; jnCell+pOld->nOverflow) ); cntOld[i] = b.nCell; if( ileaf ){ assert( leafCorrection==0 ); - assert( pOld->hdrOffset==0 ); + assert( pOld->hdrOffset==0 || CORRUPT_DB ); /* The right pointer of the child page pOld becomes the left ** pointer of the divider cell */ memcpy(b.apCell[b.nCell], &pOld->aData[8], 4); @@ -66137,7 +74141,7 @@ static int balance_nonroot( ** Figure out the number of pages needed to hold all b.nCell cells. ** Store this number in "k". Also compute szNew[] which is the total ** size of all cells on the i-th page and cntNew[] which is the index - ** in b.apCell[] of the cell that divides page i from page i+1. + ** in b.apCell[] of the cell that divides page i from page i+1. ** cntNew[k] should equal b.nCell. ** ** Values computed by this block: @@ -66147,11 +74151,22 @@ static int balance_nonroot( ** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to ** the right of the i-th sibling page. ** usableSpace: Number of bytes of space available on each sibling. - ** + ** */ usableSpace = pBt->usableSize - 12 + leafCorrection; - for(i=0; iaDataEnd; + b.ixNx[k] = cntOld[i]; + if( k && b.ixNx[k]==b.ixNx[k-1] ){ + k--; /* Omit b.ixNx[] entry for child pages with no cells */ + } + if( !leafData ){ + k++; + b.apEnd[k] = pParent->aDataEnd; + b.ixNx[k] = cntOld[i]+1; + } + assert( p->nFree>=0 ); szNew[i] = usableSpace - p->nFree; for(j=0; jnOverflow; j++){ szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); @@ -66269,6 +74284,11 @@ static int balance_nonroot( apOld[i] = 0; rc = sqlite3PagerWrite(pNew->pDbPage); nNew++; + if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv)) + && rc==SQLITE_OK + ){ + rc = SQLITE_CORRUPT_BKPT; + } if( rc ) goto balance_cleanup; }else{ assert( i>0 ); @@ -66290,24 +74310,24 @@ static int balance_nonroot( } /* - ** Reassign page numbers so that the new pages are in ascending order. + ** Reassign page numbers so that the new pages are in ascending order. ** This helps to keep entries in the disk file in order so that a scan - ** of the table is closer to a linear scan through the file. That in turn + ** of the table is closer to a linear scan through the file. That in turn ** helps the operating system to deliver pages from the disk more rapidly. ** - ** An O(n^2) insertion sort algorithm is used, but since n is never more + ** An O(n^2) insertion sort algorithm is used, but since n is never more ** than (NB+2) (a small constant), that should not be a problem. ** - ** When NB==3, this one optimization makes the database about 25% faster + ** When NB==3, this one optimization makes the database about 25% faster ** for large insertions and deletions. */ for(i=0; ipgno; aPgFlags[i] = apNew[i]->pDbPage->flags; for(j=0; jpDbPage) ); + assert( nNew>=1 && nNew<=ArraySize(apNew) ); + assert( apNew[nNew-1]!=0 ); put4byte(pRight, apNew[nNew-1]->pgno); /* If the sibling pages are not leaves, ensure that the right-child pointer - ** of the right-most new sibling page is set to the value that was + ** of the right-most new sibling page is set to the value that was ** originally in the same field of the right-most old sibling page. */ if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){ MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1]; memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4); } - /* Make any required updates to pointer map entries associated with + /* Make any required updates to pointer map entries associated with ** cells stored on sibling pages following the balance operation. Pointer ** map entries associated with divider cells are set by the insertCell() ** routine. The associated pointer map entries are: @@ -66369,25 +74391,26 @@ static int balance_nonroot( ** b) if the sibling pages are not leaves, the child page associated ** with the cell. ** - ** If the sibling pages are not leaves, then the pointer map entry - ** associated with the right-child of each sibling may also need to be - ** updated. This happens below, after the sibling pages have been + ** If the sibling pages are not leaves, then the pointer map entry + ** associated with the right-child of each sibling may also need to be + ** updated. This happens below, after the sibling pages have been ** populated, not here. */ if( ISAUTOVACUUM ){ - MemPage *pNew = apNew[0]; - u8 *aOld = pNew->aData; + MemPage *pOld; + MemPage *pNew = pOld = apNew[0]; int cntOldNext = pNew->nCell + pNew->nOverflow; - int usableSize = pBt->usableSize; int iNew = 0; int iOld = 0; for(i=0; i=0 && iOldnCell + pOld->nOverflow + !leafData; - aOld = pOld->aData; } if( i==cntNew[iNew] ){ pNew = apNew[++iNew]; @@ -66395,20 +74418,20 @@ static int balance_nonroot( } /* Cell pCell is destined for new sibling page pNew. Originally, it - ** was either part of sibling page iOld (possibly an overflow cell), + ** was either part of sibling page iOld (possibly an overflow cell), ** or else the divider cell to the left of sibling page iOld. So, ** if sibling page iOld had the same page number as pNew, and if ** pCell really was a part of sibling page iOld (not a divider or ** overflow cell), we can skip updating the pointer map entries. */ if( iOld>=nNew || pNew->pgno!=aPgno[iOld] - || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize]) + || !SQLITE_WITHIN(pCell,pOld->aData,pOld->aDataEnd) ){ if( !leafCorrection ){ ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); } if( cachedCellSize(&b,i)>pNew->minLocal ){ - ptrmapPutOvflPtr(pNew, pCell, &rc); + ptrmapPutOvflPtr(pNew, pOld, pCell, &rc); } if( rc ) goto balance_cleanup; } @@ -66420,6 +74443,7 @@ static int balance_nonroot( u8 *pCell; u8 *pTemp; int sz; + u8 *pSrcEnd; MemPage *pNew = apNew[i]; j = cntNew[i]; @@ -66431,9 +74455,9 @@ static int balance_nonroot( if( !pNew->leaf ){ memcpy(&pNew->aData[8], pCell, 4); }else if( leafData ){ - /* If the tree is a leaf-data tree, and the siblings are leaves, - ** then there is no divider cell in b.apCell[]. Instead, the divider - ** cell consists of the integer key for the right-most cell of + /* If the tree is a leaf-data tree, and the siblings are leaves, + ** then there is no divider cell in b.apCell[]. Instead, the divider + ** cell consists of the integer key for the right-most cell of ** the sibling-page assembled above only. */ CellInfo info; @@ -66446,9 +74470,9 @@ static int balance_nonroot( pCell -= 4; /* Obscure case for non-leaf-data trees: If the cell at pCell was ** previously stored on a leaf node, and its reported size was 4 - ** bytes, then it may actually be smaller than this + ** bytes, then it may actually be smaller than this ** (see btreeParseCellPtr(), 4 bytes is the minimum size of - ** any cell). But it is important to pass the correct size to + ** any cell). But it is important to pass the correct size to ** insertCell(), so reparse the cell now. ** ** This can only happen for b-trees used to evaluate "IN (SELECT ...)" @@ -66463,6 +74487,12 @@ static int balance_nonroot( iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); + for(k=0; b.ixNx[k]<=i && ALWAYS(kpgno, &rc); if( rc!=SQLITE_OK ) goto balance_cleanup; assert( sqlite3PagerIswriteable(pParent->pDbPage) ); @@ -66540,8 +74570,8 @@ static int balance_nonroot( ** b-tree structure by one. This is described as the "balance-shallower" ** sub-algorithm in some documentation. ** - ** If this is an auto-vacuum database, the call to copyNodeContent() - ** sets all pointer-map entries corresponding to database image pages + ** If this is an auto-vacuum database, the call to copyNodeContent() + ** sets all pointer-map entries corresponding to database image pages ** for which the pointer is stored within the content being copied. ** ** It is critical that the child page be defragmented before being @@ -66550,10 +74580,11 @@ static int balance_nonroot( ** free space needs to be up front. */ assert( nNew==1 || CORRUPT_DB ); - rc = defragmentPage(apNew[0]); + rc = defragmentPage(apNew[0], -1); testcase( rc!=SQLITE_OK ); - assert( apNew[0]->nFree == - (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) + assert( apNew[0]->nFree == + (get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset + - apNew[0]->nCell*2) || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); @@ -66581,7 +74612,7 @@ static int balance_nonroot( #if 0 if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){ /* The ptrmapCheckPages() contains assert() statements that verify that - ** all pointer map pages are set correctly. This is helpful while + ** all pointer map pages are set correctly. This is helpful while ** debugging. This is usually disabled because a corrupt database may ** cause an assert() statement to fail. */ ptrmapCheckPages(apNew, nNew); @@ -66593,7 +74624,7 @@ static int balance_nonroot( ** Cleanup before returning. */ balance_cleanup: - sqlite3ScratchFree(b.apCell); + sqlite3StackFree(0, b.apCell); for(i=0; inOverflow>0 ); assert( sqlite3_mutex_held(pBt->mutex) ); - /* Make pRoot, the root page of the b-tree, writable. Allocate a new + /* Make pRoot, the root page of the b-tree, writable. Allocate a new ** page that will become the new right-child of pPage. Copy the contents ** of the node stored on pRoot into the new child page. */ @@ -66652,7 +74683,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ } assert( sqlite3PagerIswriteable(pChild->pDbPage) ); assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); - assert( pChild->nCell==pRoot->nCell ); + assert( pChild->nCell==pRoot->nCell || CORRUPT_DB ); TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno)); @@ -66671,10 +74702,34 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ return SQLITE_OK; } +/* +** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid +** on the same B-tree as pCur. +** +** This can occur if a database is corrupt with two or more SQL tables +** pointing to the same b-tree. If an insert occurs on one SQL table +** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL +** table linked to the same b-tree. If the secondary insert causes a +** rebalance, that can change content out from under the cursor on the +** first SQL table, violating invariants on the first insert. +*/ +static int anotherValidCursor(BtCursor *pCur){ + BtCursor *pOther; + for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){ + if( pOther!=pCur + && pOther->eState==CURSOR_VALID + && pOther->pPage==pCur->pPage + ){ + return SQLITE_CORRUPT_BKPT; + } + } + return SQLITE_OK; +} + /* ** The page that pCur currently points to has just been modified in ** some way. This function figures out if this modification means the -** tree needs to be balanced, and if so calls the appropriate balancing +** tree needs to be balanced, and if so calls the appropriate balancing ** routine. Balancing routines are: ** ** balance_quick() @@ -66691,35 +74746,41 @@ static int balance(BtCursor *pCur){ VVA_ONLY( int balance_deeper_called = 0 ); do { - int iPage = pCur->iPage; - MemPage *pPage = pCur->apPage[iPage]; + int iPage; + MemPage *pPage = pCur->pPage; - if( iPage==0 ){ - if( pPage->nOverflow ){ + if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; + if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ + break; + }else if( (iPage = pCur->iPage)==0 ){ + if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){ /* The root page of the b-tree is overfull. In this case call the ** balance_deeper() function to create a new child for the root-page ** and copy the current contents of the root-page to it. The ** next iteration of the do-loop will balance the child page. - */ + */ assert( balance_deeper_called==0 ); VVA_ONLY( balance_deeper_called++ ); rc = balance_deeper(pPage, &pCur->apPage[1]); if( rc==SQLITE_OK ){ pCur->iPage = 1; + pCur->ix = 0; pCur->aiIdx[0] = 0; - pCur->aiIdx[1] = 0; - assert( pCur->apPage[1]->nOverflow ); + pCur->apPage[0] = pPage; + pCur->pPage = pCur->apPage[1]; + assert( pCur->pPage->nOverflow ); } }else{ break; } - }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ - break; }else{ MemPage * const pParent = pCur->apPage[iPage-1]; int const iIdx = pCur->aiIdx[iPage-1]; rc = sqlite3PagerWrite(pParent->pDbPage); + if( rc==SQLITE_OK && pParent->nFree<0 ){ + rc = btreeComputeFreeSpace(pParent); + } if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE if( pPage->intKeyLeaf @@ -66731,17 +74792,17 @@ static int balance(BtCursor *pCur){ /* Call balance_quick() to create a new sibling of pPage on which ** to store the overflow cell. balance_quick() inserts a new cell ** into pParent, which may cause pParent overflow. If this - ** happens, the next iteration of the do-loop will balance pParent + ** happens, the next iteration of the do-loop will balance pParent ** use either balance_nonroot() or balance_deeper(). Until this ** happens, the overflow cell is stored in the aBalanceQuickSpace[] - ** buffer. + ** buffer. ** ** The purpose of the following assert() is to check that only a ** single call to balance_quick() is made for each call to this ** function. If this were not verified, a subtle bug involving reuse ** of the aBalanceQuickSpace[] might sneak in. */ - assert( balance_quick_called==0 ); + assert( balance_quick_called==0 ); VVA_ONLY( balance_quick_called++ ); rc = balance_quick(pParent, pPage, aBalanceQuickSpace); }else @@ -66752,15 +74813,15 @@ static int balance(BtCursor *pCur){ ** modifying the contents of pParent, which may cause pParent to ** become overfull or underfull. The next iteration of the do-loop ** will balance the parent page to correct this. - ** + ** ** If the parent page becomes overfull, the overflow cell or cells - ** are stored in the pSpace buffer allocated immediately below. + ** are stored in the pSpace buffer allocated immediately below. ** A subsequent iteration of the do-loop will deal with this by ** calling balance_nonroot() (balance_deeper() may be called first, ** but it doesn't deal with overflow cells - just moves them to a - ** different page). Once this subsequent call to balance_nonroot() + ** different page). Once this subsequent call to balance_nonroot() ** has completed, it is safe to release the pSpace buffer used by - ** the previous call, as the overflow cell data will have been + ** the previous call, as the overflow cell data will have been ** copied either into the body of a database page or into the new ** pSpace buffer passed to the latter call to balance_nonroot(). */ @@ -66768,9 +74829,9 @@ static int balance(BtCursor *pCur){ rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1, pCur->hints&BTREE_BULKLOAD); if( pFree ){ - /* If pFree is not NULL, it points to the pSpace buffer used + /* If pFree is not NULL, it points to the pSpace buffer used ** by a previous call to balance_nonroot(). Its contents are - ** now stored either on real database pages or within the + ** now stored either on real database pages or within the ** new pSpace buffer, so it may be safely freed here. */ sqlite3PageFree(pFree); } @@ -66788,6 +74849,7 @@ static int balance(BtCursor *pCur){ releasePage(pPage); pCur->iPage--; assert( pCur->iPage>=0 ); + pCur->pPage = pCur->apPage[pCur->iPage]; } }while( rc==SQLITE_OK ); @@ -66797,6 +74859,100 @@ static int balance(BtCursor *pCur){ return rc; } +/* Overwrite content from pX into pDest. Only do the write if the +** content is different from what is already there. +*/ +static int btreeOverwriteContent( + MemPage *pPage, /* MemPage on which writing will occur */ + u8 *pDest, /* Pointer to the place to start writing */ + const BtreePayload *pX, /* Source of data to write */ + int iOffset, /* Offset of first byte to write */ + int iAmt /* Number of bytes to be written */ +){ + int nData = pX->nData - iOffset; + if( nData<=0 ){ + /* Overwritting with zeros */ + int i; + for(i=0; ipDbPage); + if( rc ) return rc; + memset(pDest + i, 0, iAmt - i); + } + }else{ + if( nDatapData) + iOffset, iAmt)!=0 ){ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + /* In a corrupt database, it is possible for the source and destination + ** buffers to overlap. This is harmless since the database is already + ** corrupt but it does cause valgrind and ASAN warnings. So use + ** memmove(). */ + memmove(pDest, ((u8*)pX->pData) + iOffset, iAmt); + } + } + return SQLITE_OK; +} + +/* +** Overwrite the cell that cursor pCur is pointing to with fresh content +** contained in pX. +*/ +static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ + int iOffset; /* Next byte of pX->pData to write */ + int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */ + int rc; /* Return code */ + MemPage *pPage = pCur->pPage; /* Page being written */ + BtShared *pBt; /* Btree */ + Pgno ovflPgno; /* Next overflow page to write */ + u32 ovflPageSize; /* Size to write on overflow page */ + + if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd + || pCur->info.pPayload < pPage->aData + pPage->cellOffset + ){ + return SQLITE_CORRUPT_BKPT; + } + /* Overwrite the local portion first */ + rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, + 0, pCur->info.nLocal); + if( rc ) return rc; + if( pCur->info.nLocal==nTotal ) return SQLITE_OK; + + /* Now overwrite the overflow pages */ + iOffset = pCur->info.nLocal; + assert( nTotal>=0 ); + assert( iOffset>=0 ); + ovflPgno = get4byte(pCur->info.pPayload + iOffset); + pBt = pPage->pBt; + ovflPageSize = pBt->usableSize - 4; + do{ + rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); + if( rc ) return rc; + if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + if( iOffset+ovflPageSize<(u32)nTotal ){ + ovflPgno = get4byte(pPage->aData); + }else{ + ovflPageSize = nTotal - iOffset; + } + rc = btreeOverwriteContent(pPage, pPage->aData+4, pX, + iOffset, ovflPageSize); + } + sqlite3PagerUnref(pPage->pDbPage); + if( rc ) return rc; + iOffset += ovflPageSize; + }while( iOffseteState==CURSOR_FAULT ){ - assert( pCur->skipNext!=SQLITE_OK ); - return pCur->skipNext; - } - - assert( cursorOwnsBtShared(pCur) ); - assert( (pCur->curFlags & BTCF_WriteFlag)!=0 - && pBt->inTransaction==TRANS_WRITE - && (pBt->btsFlags & BTS_READ_ONLY)==0 ); - assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); - - /* Assert that the caller has been consistent. If this cursor was opened - ** expecting an index b-tree, then the caller should be inserting blob - ** keys with no associated data. If the cursor was opened expecting an - ** intkey table, the caller should be inserting integer keys with a - ** blob of associated data. */ - assert( (pX->pKey==0)==(pCur->pKeyInfo==0) ); + assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags ); + assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 ); /* Save the positions of any other cursors open on this table. ** ** In some cases, the call to btreeMoveto() below is a no-op. For ** example, when inserting data into a table with auto-generated integer - ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the - ** integer key to use. It then calls this function to actually insert the + ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the + ** integer key to use. It then calls this function to actually insert the ** data into the intkey B-Tree. In this case btreeMoveto() recognizes ** that the cursor is already where it needs to be and returns without ** doing any work. To avoid thwarting these optimizations, it is important @@ -66878,53 +75017,135 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; + if( loc && pCur->iPage<0 ){ + /* This can only happen if the schema is corrupt such that there is more + ** than one table or index with the same root page as used by the cursor. + ** Which can only happen if the SQLITE_NoSchemaError flag was set when + ** the schema was loaded. This cannot be asserted though, as a user might + ** set the flag, load the schema, and then unset the flag. */ + return SQLITE_CORRUPT_BKPT; + } } + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + rc = moveToRoot(pCur); + if( rc && rc!=SQLITE_EMPTY ) return rc; + } + + assert( cursorOwnsBtShared(pCur) ); + assert( (pCur->curFlags & BTCF_WriteFlag)!=0 + && pBt->inTransaction==TRANS_WRITE + && (pBt->btsFlags & BTS_READ_ONLY)==0 ); + assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); + + /* Assert that the caller has been consistent. If this cursor was opened + ** expecting an index b-tree, then the caller should be inserting blob + ** keys with no associated data. If the cursor was opened expecting an + ** intkey table, the caller should be inserting integer keys with a + ** blob of associated data. */ + assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) ); + if( pCur->pKeyInfo==0 ){ assert( pX->pKey==0 ); - /* If this is an insert into a table b-tree, invalidate any incrblob + /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced */ - invalidateIncrblobCursors(p, pX->nKey, 0); + if( p->hasIncrblobCur ){ + invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0); + } - /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing - ** to a row with the same key as the new entry being inserted. */ - assert( (flags & BTREE_SAVEPOSITION)==0 || - ((pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey) ); + /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing + ** to a row with the same key as the new entry being inserted. + */ +#ifdef SQLITE_DEBUG + if( flags & BTREE_SAVEPOSITION ){ + assert( pCur->curFlags & BTCF_ValidNKey ); + assert( pX->nKey==pCur->info.nKey ); + assert( loc==0 ); + } +#endif - /* If the cursor is currently on the last row and we are appending a - ** new row onto the end, set the "loc" to avoid an unnecessary - ** btreeMoveto() call */ + /* On the other hand, BTREE_SAVEPOSITION==0 does not imply + ** that the cursor is not pointing to a row to be overwritten. + ** So do a complete check. + */ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){ - loc = 0; - }else if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0 - && pCur->info.nKey==pX->nKey-1 ){ - loc = -1; + /* The cursor is pointing to the entry that is to be + ** overwritten */ + assert( pX->nData>=0 && pX->nZero>=0 ); + if( pCur->info.nSize!=0 + && pCur->info.nPayload==(u32)pX->nData+pX->nZero + ){ + /* New entry is the same size as the old. Do an overwrite */ + return btreeOverwriteCell(pCur, pX); + } + assert( loc==0 ); }else if( loc==0 ){ - rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); + /* The cursor is *not* pointing to the cell to be overwritten, nor + ** to an adjacent cell. Move the cursor so that it is pointing either + ** to the cell to be overwritten or an adjacent cell. + */ + rc = sqlite3BtreeTableMoveto(pCur, pX->nKey, + (flags & BTREE_APPEND)!=0, &loc); if( rc ) return rc; } - }else if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ - if( pX->nMem ){ - UnpackedRecord r; - r.pKeyInfo = pCur->pKeyInfo; - r.aMem = pX->aMem; - r.nField = pX->nMem; - r.default_rc = 0; - r.errCode = 0; - r.r1 = 0; - r.r2 = 0; - r.eqSeen = 0; - rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); - }else{ - rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc); + }else{ + /* This is an index or a WITHOUT ROWID table */ + + /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing + ** to a row with the same key as the new entry being inserted. + */ + assert( (flags & BTREE_SAVEPOSITION)==0 || loc==0 ); + + /* If the cursor is not already pointing either to the cell to be + ** overwritten, or if a new cell is being inserted, if the cursor is + ** not pointing to an immediately adjacent cell, then move the cursor + ** so that it does. + */ + if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){ + if( pX->nMem ){ + UnpackedRecord r; + r.pKeyInfo = pCur->pKeyInfo; + r.aMem = pX->aMem; + r.nField = pX->nMem; + r.default_rc = 0; + r.eqSeen = 0; + rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc); + }else{ + rc = btreeMoveto(pCur, pX->pKey, pX->nKey, + (flags & BTREE_APPEND)!=0, &loc); + } + if( rc ) return rc; + } + + /* If the cursor is currently pointing to an entry to be overwritten + ** and the new content is the same as as the old, then use the + ** overwrite optimization. + */ + if( loc==0 ){ + getCellInfo(pCur); + if( pCur->info.nKey==pX->nKey ){ + BtreePayload x2; + x2.pData = pX->pKey; + x2.nData = pX->nKey; + x2.nZero = 0; + return btreeOverwriteCell(pCur, &x2); + } } - if( rc ) return rc; } - assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); + assert( pCur->eState==CURSOR_VALID + || (pCur->eState==CURSOR_INVALID && loc) ); - pPage = pCur->apPage[pCur->iPage]; - assert( pPage->intKey || pX->nKey>=0 ); + pPage = pCur->pPage; + assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) ); assert( pPage->leaf || !pPage->intKey ); + if( pPage->nFree<0 ){ + if( pCur->eState>CURSOR_INVALID ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + rc = btreeComputeFreeSpace(pPage); + } + if( rc ) return rc; + } TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, @@ -66932,14 +75153,31 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( assert( pPage->isInit ); newCell = pBt->pTmpSpace; assert( newCell!=0 ); - rc = fillInCell(pPage, newCell, pX, &szNew); + if( flags & BTREE_PREFORMAT ){ + rc = SQLITE_OK; + szNew = pBt->nPreformatSize; + if( szNew<4 ) szNew = 4; + if( ISAUTOVACUUM && szNew>pPage->maxLocal ){ + CellInfo info; + pPage->xParseCell(pPage, newCell, &info); + if( info.nPayload!=info.nLocal ){ + Pgno ovfl = get4byte(&newCell[szNew-4]); + ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc); + } + } + }else{ + rc = fillInCell(pPage, newCell, pX, &szNew); + } if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); - idx = pCur->aiIdx[pCur->iPage]; + idx = pCur->ix; if( loc==0 ){ CellInfo info; - assert( idxnCell ); + assert( idx>=0 ); + if( idx>=pPage->nCell ){ + return SQLITE_CORRUPT_BKPT; + } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert; @@ -66948,15 +75186,28 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } - rc = clearCell(pPage, oldCell, &info); - if( info.nSize==szNew && info.nLocal==info.nPayload ){ + BTREE_CLEAR_CELL(rc, pPage, oldCell, info); + testcase( pCur->curFlags & BTCF_ValidOvfl ); + invalidateOverflowCache(pCur); + if( info.nSize==szNew && info.nLocal==info.nPayload + && (!ISAUTOVACUUM || szNewminLocal) + ){ /* Overwrite the old cell with the new if they are the same size. ** We could also try to do this if the old cell is smaller, then add ** the leftover space to the free list. But experiments show that ** doing that is no faster then skipping this optimization and just - ** calling dropCell() and insertCell(). */ + ** calling dropCell() and insertCell(). + ** + ** This optimization cannot be used on an autovacuum database if the + ** new entry uses overflow pages, as the insertCell() call below is + ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */ assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */ - if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; + if( oldCell < pPage->aData+pPage->hdrOffset+10 ){ + return SQLITE_CORRUPT_BKPT; + } + if( oldCell+szNew > pPage->aDataEnd ){ + return SQLITE_CORRUPT_BKPT; + } memcpy(oldCell, newCell, szNew); return SQLITE_OK; } @@ -66964,7 +75215,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); - idx = ++pCur->aiIdx[pCur->iPage]; + idx = ++pCur->ix; + pCur->curFlags &= ~BTCF_ValidNKey; }else{ assert( pPage->leaf ); } @@ -66972,7 +75224,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( assert( pPage->nOverflow==0 || rc==SQLITE_OK ); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); - /* If no error has occurred and pPage has an overflow cell, call balance() + /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey ** variables. @@ -66999,13 +75251,13 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() - ** fails. Internal data structure corruption will result otherwise. + ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() ** from trying to save the current position of the cursor. */ - pCur->apPage[pCur->iPage]->nOverflow = 0; + pCur->pPage->nOverflow = 0; pCur->eState = CURSOR_INVALID; if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){ - rc = moveToRoot(pCur); + btreeReleaseAllCursorPages(pCur); if( pCur->pKeyInfo ){ assert( pCur->pKey==0 ); pCur->pKey = sqlite3Malloc( pX->nKey ); @@ -67019,14 +75271,122 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( pCur->nKey = pX->nKey; } } - assert( pCur->apPage[pCur->iPage]->nOverflow==0 ); + assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); end_insert: return rc; } /* -** Delete the entry that the cursor is pointing to. +** This function is used as part of copying the current row from cursor +** pSrc into cursor pDest. If the cursors are open on intkey tables, then +** parameter iKey is used as the rowid value when the record is copied +** into pDest. Otherwise, the record is copied verbatim. +** +** This function does not actually write the new value to cursor pDest. +** Instead, it creates and populates any required overflow pages and +** writes the data for the new cell into the BtShared.pTmpSpace buffer +** for the destination database. The size of the cell, in bytes, is left +** in BtShared.nPreformatSize. The caller completes the insertion by +** calling sqlite3BtreeInsert() with the BTREE_PREFORMAT flag specified. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +*/ +SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ + int rc = SQLITE_OK; + BtShared *pBt = pDest->pBt; + u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */ + const u8 *aIn; /* Pointer to next input buffer */ + u32 nIn; /* Size of input buffer aIn[] */ + u32 nRem; /* Bytes of data still to copy */ + + getCellInfo(pSrc); + aOut += putVarint32(aOut, pSrc->info.nPayload); + if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey); + nIn = pSrc->info.nLocal; + aIn = pSrc->info.pPayload; + if( aIn+nIn>pSrc->pPage->aDataEnd ){ + return SQLITE_CORRUPT_BKPT; + } + nRem = pSrc->info.nPayload; + if( nIn==nRem && nInpPage->maxLocal ){ + memcpy(aOut, aIn, nIn); + pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace); + }else{ + Pager *pSrcPager = pSrc->pBt->pPager; + u8 *pPgnoOut = 0; + Pgno ovflIn = 0; + DbPage *pPageIn = 0; + MemPage *pPageOut = 0; + u32 nOut; /* Size of output buffer aOut[] */ + + nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); + pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); + if( nOutinfo.nPayload ){ + pPgnoOut = &aOut[nOut]; + pBt->nPreformatSize += 4; + } + + if( nRem>nIn ){ + if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ + return SQLITE_CORRUPT_BKPT; + } + ovflIn = get4byte(&pSrc->info.pPayload[nIn]); + } + + do { + nRem -= nOut; + do{ + assert( nOut>0 ); + if( nIn>0 ){ + int nCopy = MIN(nOut, nIn); + memcpy(aOut, aIn, nCopy); + nOut -= nCopy; + nIn -= nCopy; + aOut += nCopy; + aIn += nCopy; + } + if( nOut>0 ){ + sqlite3PagerUnref(pPageIn); + pPageIn = 0; + rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY); + if( rc==SQLITE_OK ){ + aIn = (const u8*)sqlite3PagerGetData(pPageIn); + ovflIn = get4byte(aIn); + aIn += 4; + nIn = pSrc->pBt->usableSize - 4; + } + } + }while( rc==SQLITE_OK && nOut>0 ); + + if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){ + Pgno pgnoNew; + MemPage *pNew = 0; + rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); + put4byte(pPgnoOut, pgnoNew); + if( ISAUTOVACUUM && pPageOut ){ + ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc); + } + releasePage(pPageOut); + pPageOut = pNew; + if( pPageOut ){ + pPgnoOut = pPageOut->aData; + put4byte(pPgnoOut, 0); + aOut = &pPgnoOut[4]; + nOut = MIN(pBt->usableSize - 4, nRem); + } + } + }while( nRem>0 && rc==SQLITE_OK ); + + releasePage(pPageOut); + sqlite3PagerUnref(pPageIn); + } + + return rc; +} + +/* +** Delete the entry that the cursor is pointing to. ** ** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then ** the cursor is left pointing at an arbitrary location after the delete. @@ -67044,15 +75404,14 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( */ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Btree *p = pCur->pBtree; - BtShared *pBt = p->pBt; - int rc; /* Return code */ - MemPage *pPage; /* Page to delete cell from */ - unsigned char *pCell; /* Pointer to cell to delete */ - int iCellIdx; /* Index of cell to delete */ - int iCellDepth; /* Depth of node containing pCell */ - CellInfo info; /* Size of the cell being deleted */ - int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */ - u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */ + BtShared *pBt = p->pBt; + int rc; /* Return code */ + MemPage *pPage; /* Page to delete cell from */ + unsigned char *pCell; /* Pointer to cell to delete */ + int iCellIdx; /* Index of cell to delete */ + int iCellDepth; /* Depth of node containing pCell */ + CellInfo info; /* Size of the cell being deleted */ + u8 bPreserve; /* Keep cursor valid. 2 for CURSOR_SKIPNEXT */ assert( cursorOwnsBtShared(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); @@ -67060,34 +75419,57 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); - assert( pCur->eState==CURSOR_VALID ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); + if( pCur->eState!=CURSOR_VALID ){ + if( pCur->eState>=CURSOR_REQUIRESEEK ){ + rc = btreeRestoreCursorPosition(pCur); + assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID ); + if( rc || pCur->eState!=CURSOR_VALID ) return rc; + }else{ + return SQLITE_CORRUPT_BKPT; + } + } + assert( pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; - iCellIdx = pCur->aiIdx[iCellDepth]; - pPage = pCur->apPage[iCellDepth]; + iCellIdx = pCur->ix; + pPage = pCur->pPage; + if( pPage->nCell<=iCellIdx ){ + return SQLITE_CORRUPT_BKPT; + } pCell = findCell(pPage, iCellIdx); + if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){ + return SQLITE_CORRUPT_BKPT; + } - /* If the bPreserve flag is set to true, then the cursor position must + /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must ** be preserved following this delete operation. If the current delete ** will cause a b-tree rebalance, then this is done by saving the cursor - ** key and leaving the cursor in CURSOR_REQUIRESEEK state before - ** returning. + ** key and leaving the cursor in CURSOR_REQUIRESEEK state before + ** returning. ** - ** Or, if the current delete will not cause a rebalance, then the cursor + ** If the current delete will not cause a rebalance, then the cursor ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately - ** before or after the deleted entry. In this case set bSkipnext to true. */ + ** before or after the deleted entry. + ** + ** The bPreserve value records which path is required: + ** + ** bPreserve==0 Not necessary to save the cursor position + ** bPreserve==1 Use CURSOR_REQUIRESEEK to save the cursor position + ** bPreserve==2 Cursor won't move. Set CURSOR_SKIPNEXT. + */ + bPreserve = (flags & BTREE_SAVEPOSITION)!=0; if( bPreserve ){ - if( !pPage->leaf + if( !pPage->leaf || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) + || pPage->nCell==1 /* See dbfuzz001.test for a test case */ ){ /* A b-tree rebalance will be required after deleting this entry. ** Save the cursor key. */ rc = saveCursorKey(pCur); if( rc ) return rc; }else{ - bSkipnext = 1; + bPreserve = 2; } } @@ -67099,8 +75481,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** sub-tree headed by the child page of the cell being deleted. This makes ** balancing the tree following the delete operation easier. */ if( !pPage->leaf ){ - int notUsed = 0; - rc = sqlite3BtreePrevious(pCur, ¬Used); + rc = sqlite3BtreePrevious(pCur, 0); + assert( rc!=SQLITE_DONE ); if( rc ) return rc; } @@ -67113,8 +75495,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ /* If this is a delete operation to remove a row from a table b-tree, ** invalidate any incrblob cursors open on the row being deleted. */ - if( pCur->pKeyInfo==0 ){ - invalidateIncrblobCursors(p, pCur->info.nKey, 0); + if( pCur->pKeyInfo==0 && p->hasIncrblobCur ){ + invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0); } /* Make the page containing the entry to be deleted writable. Then free any @@ -67122,7 +75504,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** itself from within the page. */ rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; - rc = clearCell(pPage, pCell, &info); + BTREE_CLEAR_CELL(rc, pPage, pCell, info); dropCell(pPage, iCellIdx, info.nSize, &rc); if( rc ) return rc; @@ -67132,11 +75514,20 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** node. The cell from the leaf node needs to be moved to the internal ** node to replace the deleted cell. */ if( !pPage->leaf ){ - MemPage *pLeaf = pCur->apPage[pCur->iPage]; + MemPage *pLeaf = pCur->pPage; int nCell; - Pgno n = pCur->apPage[iCellDepth+1]->pgno; + Pgno n; unsigned char *pTmp; + if( pLeaf->nFree<0 ){ + rc = btreeComputeFreeSpace(pLeaf); + if( rc ) return rc; + } + if( iCellDepthiPage-1 ){ + n = pCur->apPage[iCellDepth+1]->pgno; + }else{ + n = pCur->pPage->pgno; + } pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); @@ -67164,33 +75555,38 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** on the leaf node first. If the balance proceeds far enough up the ** tree that we can be sure that any problem in the internal node has ** been corrected, so be it. Otherwise, after balancing the leaf node, - ** walk the cursor up the tree to the internal node and balance it as + ** walk the cursor up the tree to the internal node and balance it as ** well. */ rc = balance(pCur); if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ + releasePageNotNull(pCur->pPage); + pCur->iPage--; while( pCur->iPage>iCellDepth ){ releasePage(pCur->apPage[pCur->iPage--]); } + pCur->pPage = pCur->apPage[pCur->iPage]; rc = balance(pCur); } if( rc==SQLITE_OK ){ - if( bSkipnext ){ - assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) ); - assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB ); + if( bPreserve>1 ){ + assert( (pCur->iPage==iCellDepth || CORRUPT_DB) ); + assert( pPage==pCur->pPage || CORRUPT_DB ); assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell ); pCur->eState = CURSOR_SKIPNEXT; if( iCellIdx>=pPage->nCell ){ pCur->skipNext = -1; - pCur->aiIdx[iCellDepth] = pPage->nCell-1; + pCur->ix = pPage->nCell-1; }else{ pCur->skipNext = 1; } }else{ rc = moveToRoot(pCur); if( bPreserve ){ + btreeReleaseAllCursorPages(pCur); pCur->eState = CURSOR_REQUIRESEEK; } + if( rc==SQLITE_EMPTY ) rc = SQLITE_OK; } } return rc; @@ -67207,7 +75603,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys ** BTREE_ZERODATA Used for SQL indices */ -static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ +static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){ BtShared *pBt = p->pBt; MemPage *pRoot; Pgno pgnoRoot; @@ -67240,6 +75636,9 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ ** created so far, so the new root-page is (meta[3]+1). */ sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot); + if( pgnoRoot>btreePagecount(pBt) ){ + return SQLITE_CORRUPT_BKPT; + } pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the @@ -67249,8 +75648,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ pgnoRoot==PENDING_BYTE_PAGE(pBt) ){ pgnoRoot++; } - assert( pgnoRoot>=3 || CORRUPT_DB ); - testcase( pgnoRoot<3 ); + assert( pgnoRoot>=3 ); /* Allocate a page. The page that currently resides at pgnoRoot will ** be moved to the allocated page (unless the allocated page happens @@ -67313,7 +75711,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ } }else{ pRoot = pPageMove; - } + } /* Update the pointer-map and meta-data with the new root-page number. */ ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc); @@ -67347,10 +75745,10 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){ zeroPage(pRoot, ptfFlags); sqlite3PagerUnref(pRoot->pDbPage); assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 ); - *piTable = (int)pgnoRoot; + *piTable = pgnoRoot; return SQLITE_OK; } -SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ +SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){ int rc; sqlite3BtreeEnter(p); rc = btreeCreateTable(p, piTable, flags); @@ -67366,7 +75764,7 @@ static int clearDatabasePage( BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ int freePageFlag, /* Deallocate page if true */ - int *pnChange /* Add number of Cells freed to this counter */ + i64 *pnChange /* Add number of Cells freed to this counter */ ){ MemPage *pPage; int rc; @@ -67381,11 +75779,12 @@ static int clearDatabasePage( } rc = getAndInitPage(pBt, pgno, &pPage, 0, 0); if( rc ) return rc; - if( pPage->bBusy ){ + if( (pBt->openFlags & BTREE_SINGLE)==0 + && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1)) + ){ rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } - pPage->bBusy = 1; hdr = pPage->hdrOffset; for(i=0; inCell; i++){ pCell = findCell(pPage, i); @@ -67393,14 +75792,15 @@ static int clearDatabasePage( rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } - rc = clearCell(pPage, pCell, &info); + BTREE_CLEAR_CELL(rc, pPage, pCell, info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; - }else if( pnChange ){ - assert( pPage->intKey || CORRUPT_DB ); + if( pPage->intKey ) pnChange = 0; + } + if( pnChange ){ testcase( !pPage->intKey ); *pnChange += pPage->nCell; } @@ -67411,7 +75811,6 @@ static int clearDatabasePage( } cleardatabasepage_out: - pPage->bBusy = 0; releasePage(pPage); return rc; } @@ -67425,11 +75824,10 @@ static int clearDatabasePage( ** read cursors on the table. Open write cursors are moved to the ** root of the table. ** -** If pnChange is not NULL, then table iTable must be an intkey table. The -** integer value pointed to by pnChange is incremented by the number of -** entries in the table. +** If pnChange is not NULL, then the integer value pointed to by pnChange +** is incremented by the number of entries in the table. */ -SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ +SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, i64 *pnChange){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); @@ -67441,7 +75839,9 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){ /* Invalidate all incrblob cursors open on table iTable (assuming iTable ** is the root of a table b-tree - if it is not, the following call is ** a no-op). */ - invalidateIncrblobCursors(p, 0, 1); + if( p->hasIncrblobCur ){ + invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); + } rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); } sqlite3BtreeLeave(p); @@ -67466,12 +75866,12 @@ SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){ ** cursors on the table. ** ** If AUTOVACUUM is enabled and the page at iTable is not the last -** root page in the database file, then the last root page +** root page in the database file, then the last root page ** in the database file is moved into the slot formerly occupied by ** iTable and that last slot formerly occupied by the last root page ** is added to the freelist instead of iTable. In this say, all ** root pages are kept at the beginning of the database file, which -** is necessary for AUTOVACUUM to work right. *piMoved is set to the +** is necessary for AUTOVACUUM to work right. *piMoved is set to the ** page number that used to be the last root page in the file before ** the move. If no page gets moved, *piMoved is set to 0. ** The last root page is recorded in meta[3] and the value of @@ -67485,11 +75885,14 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); + if( iTable>btreePagecount(pBt) ){ + return SQLITE_CORRUPT_BKPT; + } - rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); - if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); - if( rc ){ + if( rc ) return rc; + rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); + if( NEVER(rc) ){ releasePage(pPage); return rc; } @@ -67506,7 +75909,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ if( iTable==maxRootPgno ){ /* If the table being dropped is the table with the largest root-page - ** number in the database, put the root page on the free list. + ** number in the database, put the root page on the free list. */ freePage(pPage, &rc); releasePage(pPage); @@ -67515,7 +75918,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ } }else{ /* The table being dropped does not have the largest root-page - ** number in the database. So move the page that does into the + ** number in the database. So move the page that does into the ** gap left by the deleted root-page. */ MemPage *pMove; @@ -67557,7 +75960,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ releasePage(pPage); } #endif - return rc; + return rc; } SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; @@ -67576,7 +75979,7 @@ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ ** is the number of free pages currently in the database. Meta[1] ** through meta[15] are available for use by higher layers. Meta[0] ** is read-only, the others are read/write. -** +** ** The schema layer numbers meta values differently. At the schema ** layer (and the SetCookie and ReadCookie opcodes) the number of ** free pages is not visible. So Cookie[0] is the same as Meta[1]. @@ -67593,12 +75996,12 @@ SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE ); - assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) ); + assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) ); assert( pBt->pPage1 ); assert( idx>=0 && idx<=15 ); if( idx==BTREE_DATA_VERSION ){ - *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion; + *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iBDataVersion; }else{ *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); } @@ -67642,42 +76045,41 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ return rc; } -#ifndef SQLITE_OMIT_BTREECOUNT /* ** The first argument, pCur, is a cursor opened on some b-tree. Count the ** number of entries in the b-tree and write the result to *pnEntry. ** -** SQLITE_OK is returned if the operation is successfully executed. +** SQLITE_OK is returned if the operation is successfully executed. ** Otherwise, if an error is encountered (i.e. an IO error or database ** corruption) an SQLite error code is returned. */ -SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ +SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){ i64 nEntry = 0; /* Value to return in *pnEntry */ int rc; /* Return code */ - if( pCur->pgnoRoot==0 ){ + rc = moveToRoot(pCur); + if( rc==SQLITE_EMPTY ){ *pnEntry = 0; return SQLITE_OK; } - rc = moveToRoot(pCur); /* Unless an error occurs, the following loop runs one iteration for each - ** page in the B-Tree structure (not including overflow pages). + ** page in the B-Tree structure (not including overflow pages). */ - while( rc==SQLITE_OK ){ + while( rc==SQLITE_OK && !AtomicLoad(&db->u1.isInterrupted) ){ int iIdx; /* Index of child node in parent */ MemPage *pPage; /* Current page of the b-tree */ - /* If this is a leaf page or the tree is not an int-key tree, then + /* If this is a leaf page or the tree is not an int-key tree, then ** this page contains countable entries. Increment the entry counter ** accordingly. */ - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; if( pPage->leaf || !pPage->intKey ){ nEntry += pPage->nCell; } - /* pPage is a leaf node. This loop navigates the cursor so that it + /* pPage is a leaf node. This loop navigates the cursor so that it ** points to the first interior cell that it points to the parent of ** the next page in the tree that has not yet been visited. The ** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell @@ -67695,16 +76097,16 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ return moveToRoot(pCur); } moveToParent(pCur); - }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell ); + }while ( pCur->ix>=pCur->pPage->nCell ); - pCur->aiIdx[pCur->iPage]++; - pPage = pCur->apPage[pCur->iPage]; + pCur->ix++; + pPage = pCur->pPage; } - /* Descend to the child node of the cell that the cursor currently + /* Descend to the child node of the cell that the cursor currently ** points at. This is the right-child if (iIdx==pPage->nCell). */ - iIdx = pCur->aiIdx[pCur->iPage]; + iIdx = pCur->ix; if( iIdx==pPage->nCell ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); }else{ @@ -67715,7 +76117,6 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){ /* An error has occurred. Return an error code. */ return rc; } -#endif /* ** Return the pager associated with a BTree. This routine is used for @@ -67740,15 +76141,15 @@ static void checkAppendMsg( pCheck->nErr++; va_start(ap, zFormat); if( pCheck->errMsg.nChar ){ - sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1); + sqlite3_str_append(&pCheck->errMsg, "\n", 1); } if( pCheck->zPfx ){ - sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); + sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2); } - sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap); + sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap); va_end(ap); - if( pCheck->errMsg.accError==STRACCUM_NOMEM ){ - pCheck->mallocFailed = 1; + if( pCheck->errMsg.accError==SQLITE_NOMEM ){ + pCheck->bOomFault = 1; } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -67782,8 +76183,7 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){ ** Also check that the page number is in bounds. */ static int checkRef(IntegrityCk *pCheck, Pgno iPage){ - if( iPage==0 ) return 1; - if( iPage>pCheck->nPage ){ + if( iPage>pCheck->nPage || iPage==0 ){ checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } @@ -67791,13 +76191,14 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage){ checkAppendMsg(pCheck, "2nd reference to page %d", iPage); return 1; } + if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1; setPageReferenced(pCheck, iPage); return 0; } #ifndef SQLITE_OMIT_AUTOVACUUM /* -** Check that the entry in the pointer-map for page iChild maps to +** Check that the entry in the pointer-map for page iChild maps to ** page iParent, pointer type ptrType. If not, append an error message ** to pCheck. */ @@ -67813,14 +76214,14 @@ static void checkPtrmap( rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); if( rc!=SQLITE_OK ){ - if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1; + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1; checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild); return; } if( ePtrmapType!=eType || iPtrmapParent!=iParent ){ checkAppendMsg(pCheck, - "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", + "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", iChild, eType, iParent, ePtrmapType, iPtrmapParent); } } @@ -67833,40 +76234,35 @@ static void checkPtrmap( static void checkList( IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ - int iPage, /* Page number for first page in the list */ - int N /* Expected number of pages in the list */ + Pgno iPage, /* Page number for first page in the list */ + u32 N /* Expected number of pages in the list */ ){ int i; - int expected = N; - int iFirst = iPage; - while( N-- > 0 && pCheck->mxErr ){ + u32 expected = N; + int nErrAtStart = pCheck->nErr; + while( iPage!=0 && pCheck->mxErr ){ DbPage *pOvflPage; unsigned char *pOvflData; - if( iPage<1 ){ - checkAppendMsg(pCheck, - "%d of %d pages missing from overflow list starting at %d", - N+1, expected, iFirst); - break; - } if( checkRef(pCheck, iPage) ) break; + N--; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ checkAppendMsg(pCheck, "failed to get page %d", iPage); break; } pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); if( isFreeList ){ - int n = get4byte(&pOvflData[4]); + u32 n = (u32)get4byte(&pOvflData[4]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pCheck->pBt->autoVacuum ){ checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0); } #endif - if( n>(int)pCheck->pBt->usableSize/4-2 ){ + if( n>pCheck->pBt->usableSize/4-2 ){ checkAppendMsg(pCheck, "freelist leaf count too big on page %d", iPage); N--; }else{ - for(i=0; ipBt->autoVacuum ){ @@ -67892,10 +76288,12 @@ static void checkList( #endif iPage = get4byte(pOvflData); sqlite3PagerUnref(pOvflPage); - - if( isFreeList && N<(iPage!=0) ){ - checkAppendMsg(pCheck, "free-page count in header is too small"); - } + } + if( N && nErrAtStart==pCheck->nErr ){ + checkAppendMsg(pCheck, + "%s is %d but should be %d", + isFreeList ? "size" : "overflow list length", + expected-N, expected); } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ @@ -67918,7 +76316,7 @@ static void checkList( ** property. ** ** This heap is used for cell overlap and coverage testing. Each u32 -** entry represents the span of a cell or freeblock on a btree page. +** entry represents the span of a cell or freeblock on a btree page. ** The upper 16 bits are the index of the first byte of a range and the ** lower 16 bits are the index of the last byte of that range. */ @@ -67948,7 +76346,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){ aHeap[j] = x; i = j; } - return 1; + return 1; } #ifndef SQLITE_OMIT_INTEGRITY_CHECK @@ -67956,7 +76354,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){ ** Do various sanity checks on a single page of a tree. Return ** the tree depth. Root pages return 0. Parents of root pages ** return 1, and so forth. -** +** ** These checks are done: ** ** 1. Make sure that cells and freeblocks do not overlap @@ -67968,7 +76366,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){ */ static int checkTreePage( IntegrityCk *pCheck, /* Context for the sanity check */ - int iPage, /* Page number of the page to check */ + Pgno iPage, /* Page number of the page to check */ i64 *piMinKey, /* Write minimum integer primary key here */ i64 maxKey /* Error if integer primary key greater than this */ ){ @@ -68004,9 +76402,9 @@ static int checkTreePage( usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage) ) return 0; - pCheck->zPfx = "Page %d: "; + pCheck->zPfx = "Page %u: "; pCheck->v1 = iPage; - if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ + if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){ checkAppendMsg(pCheck, "unable to get the page. error code=%d", rc); goto end_of_check; @@ -68022,11 +76420,16 @@ static int checkTreePage( "btreeInitPage() returns error code %d", rc); goto end_of_check; } + if( (rc = btreeComputeFreeSpace(pPage))!=0 ){ + assert( rc==SQLITE_CORRUPT ); + checkAppendMsg(pCheck, "free space corruption", rc); + goto end_of_check; + } data = pPage->aData; hdr = pPage->hdrOffset; /* Set up for cell analysis */ - pCheck->zPfx = "On tree page %d cell %d: "; + pCheck->zPfx = "On tree page %u cell %d: "; contentOffset = get2byteNotZero(&data[hdr+5]); assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ @@ -68046,7 +76449,7 @@ static int checkTreePage( pgno = get4byte(&data[hdr+8]); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ - pCheck->zPfx = "On page %d at right child: "; + pCheck->zPfx = "On page %u at right child: "; checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage); } #endif @@ -68089,11 +76492,12 @@ static int checkTreePage( checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey); } maxKey = info.nKey; + keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */ } /* Check the content overflow list */ if( info.nPayload>info.nLocal ){ - int nPage; /* Number of pages on the overflow chain */ + u32 nPage; /* Number of pages on the overflow chain */ Pgno pgnoOvfl; /* First page of the overflow chain */ assert( pc + info.nSize - 4 <= usableSize ); nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4); @@ -68148,14 +76552,14 @@ static int checkTreePage( ** ** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header ** is the offset of the first freeblock, or zero if there are no - ** freeblocks on the page. + ** freeblocks on the page. */ i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; - assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */ + assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); - assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */ + assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next @@ -68164,17 +76568,17 @@ static int checkTreePage( j = get2byte(&data[i]); /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of ** increasing offset. */ - assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */ - assert( (u32)j<=usableSize-4 ); /* Enforced by btreeInitPage() */ + assert( j==0 || j>i+size ); /* Enforced by btreeComputeFreeSpace() */ + assert( (u32)j<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ i = j; } - /* Analyze the min-heap looking for overlap between cells and/or + /* Analyze the min-heap looking for overlap between cells and/or ** freeblocks, and counting the number of untracked bytes in nFrag. - ** + ** ** Each min-heap entry is of the form: (start_address<<16)|end_address. ** There is an implied first entry the covers the page header, the cell ** pointer index, and the gap between the cell pointer index and the start - ** of cell content. + ** of cell content. ** ** The loop below pulls entries from the min-heap in order and compares ** the start_address against the previous end_address. If there is an @@ -68186,7 +76590,7 @@ static int checkTreePage( while( btreeHeapPull(heap,&x) ){ if( (prev&0xffff)>=(x>>16) ){ checkAppendMsg(pCheck, - "Multiple uses for byte %u of page %d", x>>16, iPage); + "Multiple uses for byte %u of page %u", x>>16, iPage); break; }else{ nFrag += (x>>16) - (prev&0xffff) - 1; @@ -68201,7 +76605,7 @@ static int checkTreePage( */ if( heap[0]==0 && nFrag!=data[hdr+7] ){ checkAppendMsg(pCheck, - "Fragmentation of %d bytes reported as %d on page %d", + "Fragmentation of %d bytes reported as %d on page %u", nFrag, data[hdr+7], iPage); } } @@ -68229,10 +76633,20 @@ static int checkTreePage( ** allocation errors, an error message held in memory obtained from ** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is ** returned. If a memory allocation error occurs, NULL is returned. +** +** If the first entry in aRoot[] is 0, that indicates that the list of +** root pages is incomplete. This is a "partial integrity-check". This +** happens when performing an integrity check on a single table. The +** zero is skipped, of course. But in addition, the freelist checks +** and the checks to make sure every page is referenced are also skipped, +** since obviously it is not possible to know which pages are covered by +** the unverified btrees. Except, if aRoot[1] is 1, then the freelist +** checks are still performed. */ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( + sqlite3 *db, /* Database connection that is running the check */ Btree *p, /* The btree to be checked */ - int *aRoot, /* An array of root pages numbers for individual trees */ + Pgno *aRoot, /* An array of root pages numbers for individual trees */ int nRoot, /* Number of entries in aRoot[] */ int mxErr, /* Stop reporting errors after this many */ int *pnErr /* Write number of errors seen to this variable */ @@ -68240,20 +76654,31 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( Pgno i; IntegrityCk sCheck; BtShared *pBt = p->pBt; - int savedDbFlags = pBt->db->flags; + u64 savedDbFlags = pBt->db->flags; char zErr[100]; + int bPartial = 0; /* True if not checking all btrees */ + int bCkFreelist = 1; /* True to scan the freelist */ VVA_ONLY( int nRef ); + assert( nRoot>0 ); + + /* aRoot[0]==0 means this is a partial check */ + if( aRoot[0]==0 ){ + assert( nRoot>1 ); + bPartial = 1; + if( aRoot[1]!=1 ) bCkFreelist = 0; + } sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) ); assert( nRef>=0 ); + sCheck.db = db; sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nPage = btreePagecount(sCheck.pBt); sCheck.mxErr = mxErr; sCheck.nErr = 0; - sCheck.mallocFailed = 0; + sCheck.bOomFault = 0; sCheck.zPfx = 0; sCheck.v1 = 0; sCheck.v2 = 0; @@ -68267,12 +76692,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1); if( !sCheck.aPgRef ){ - sCheck.mallocFailed = 1; + sCheck.bOomFault = 1; goto integrity_ck_cleanup; } sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); if( sCheck.heap==0 ){ - sCheck.mallocFailed = 1; + sCheck.bOomFault = 1; goto integrity_ck_cleanup; } @@ -68281,20 +76706,42 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( /* Check the integrity of the freelist */ - sCheck.zPfx = "Main freelist: "; - checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), - get4byte(&pBt->pPage1->aData[36])); - sCheck.zPfx = 0; + if( bCkFreelist ){ + sCheck.zPfx = "Main freelist: "; + checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), + get4byte(&pBt->pPage1->aData[36])); + sCheck.zPfx = 0; + } /* Check all the tables. */ +#ifndef SQLITE_OMIT_AUTOVACUUM + if( !bPartial ){ + if( pBt->autoVacuum ){ + Pgno mx = 0; + Pgno mxInHdr; + for(i=0; (int)ipPage1->aData[52]); + if( mx!=mxInHdr ){ + checkAppendMsg(&sCheck, + "max rootpage (%d) disagrees with header (%d)", + mx, mxInHdr + ); + } + }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){ + checkAppendMsg(&sCheck, + "incremental_vacuum enabled with a max rootpage of zero" + ); + } + } +#endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); - pBt->db->flags &= ~SQLITE_CellSizeCk; + pBt->db->flags &= ~(u64)SQLITE_CellSizeCk; for(i=0; (int)iautoVacuum && aRoot[i]>1 ){ + if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } #endif @@ -68304,24 +76751,26 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( /* Make sure every page in the file is referenced */ - for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ + if( !bPartial ){ + for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){ #ifdef SQLITE_OMIT_AUTOVACUUM - if( getPageReferenced(&sCheck, i)==0 ){ - checkAppendMsg(&sCheck, "Page %d is never used", i); - } + if( getPageReferenced(&sCheck, i)==0 ){ + checkAppendMsg(&sCheck, "Page %d is never used", i); + } #else - /* If the database supports auto-vacuum, make sure no tables contain - ** references to pointer-map pages. - */ - if( getPageReferenced(&sCheck, i)==0 && - (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, "Page %d is never used", i); - } - if( getPageReferenced(&sCheck, i)!=0 && - (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ - checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); - } + /* If the database supports auto-vacuum, make sure no tables contain + ** references to pointer-map pages. + */ + if( getPageReferenced(&sCheck, i)==0 && + (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Page %d is never used", i); + } + if( getPageReferenced(&sCheck, i)!=0 && + (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){ + checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i); + } #endif + } } /* Clean up and report errors. @@ -68329,12 +76778,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck( integrity_ck_cleanup: sqlite3PageFree(sCheck.heap); sqlite3_free(sCheck.aPgRef); - if( sCheck.mallocFailed ){ - sqlite3StrAccumReset(&sCheck.errMsg); + if( sCheck.bOomFault ){ + sqlite3_str_reset(&sCheck.errMsg); sCheck.nErr++; } *pnErr = sCheck.nErr; - if( sCheck.nErr==0 ) sqlite3StrAccumReset(&sCheck.errMsg); + if( sCheck.nErr==0 ) sqlite3_str_reset(&sCheck.errMsg); /* Make sure this analysis did not leave any unref() pages. */ assert( nRef==sqlite3PagerRefcount(pBt->pPager) ); sqlite3BtreeLeave(p); @@ -68368,18 +76817,19 @@ SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *p){ } /* -** Return non-zero if a transaction is active. +** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE +** to describe the current transaction state of Btree p. */ -SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){ +SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree *p){ assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); - return (p && (p->inTrans==TRANS_WRITE)); + return p ? p->inTrans : 0; } #ifndef SQLITE_OMIT_WAL /* ** Run a checkpoint on the Btree passed as the first argument. ** -** Return SQLITE_LOCKED if this or any other connection has an open +** Return SQLITE_LOCKED if this or any other connection has an open ** transaction on the shared-cache the argument Btree is connected to. ** ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. @@ -68401,14 +76851,8 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * #endif /* -** Return non-zero if a read (or write) transaction is active. +** Return true if there is currently a backup running on Btree p. */ -SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree *p){ - assert( p ); - assert( sqlite3_mutex_held(p->db->mutex) ); - return p->inTrans!=TRANS_NONE; -} - SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ assert( p ); assert( sqlite3_mutex_held(p->db->mutex) ); @@ -68418,20 +76862,20 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ /* ** This function returns a pointer to a blob of memory associated with ** a single shared-btree. The memory is used by client code for its own -** purposes (for example, to store a high-level schema associated with +** purposes (for example, to store a high-level schema associated with ** the shared-btree). The btree layer manages reference counting issues. ** ** The first time this is called on a shared-btree, nBytes bytes of memory -** are allocated, zeroed, and returned to the caller. For each subsequent +** are allocated, zeroed, and returned to the caller. For each subsequent ** call the nBytes parameter is ignored and a pointer to the same blob -** of memory returned. +** of memory returned. ** ** If the nBytes parameter is 0 and the blob of memory has not yet been ** allocated, a null pointer is returned. If the blob has already been ** allocated, it is returned as normal. ** -** Just before the shared-btree is closed, the function passed as the -** xFree argument when the memory allocation was made is invoked on the +** Just before the shared-btree is closed, the function passed as the +** xFree argument when the memory allocation was made is invoked on the ** blob of allocated memory. The xFree function should not call sqlite3_free() ** on the memory, the btree layer does that. */ @@ -68447,15 +76891,15 @@ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void } /* -** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared -** btree as the argument handle holds an exclusive lock on the -** sqlite_master table. Otherwise SQLITE_OK. +** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared +** btree as the argument handle holds an exclusive lock on the +** sqlite_schema table. Otherwise SQLITE_OK. */ SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){ int rc; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); - rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK); + rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK); assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE ); sqlite3BtreeLeave(p); return rc; @@ -68489,11 +76933,11 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ #ifndef SQLITE_OMIT_INCRBLOB /* -** Argument pCsr must be a cursor opened for writing on an -** INTKEY table currently pointing at a valid table entry. +** Argument pCsr must be a cursor opened for writing on an +** INTKEY table currently pointing at a valid table entry. ** This function modifies the data stored as part of that entry. ** -** Only the data content may only be modified, it is not possible to +** Only the data content may only be modified, it is not possible to ** change the length of the data stored. If this function is called with ** parameters that attempt to write past the end of the existing data, ** no modifications are made and SQLITE_CORRUPT is returned. @@ -68524,7 +76968,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr); assert( rc==SQLITE_OK ); - /* Check some assumptions: + /* Check some assumptions: ** (a) the cursor is open for writing, ** (b) there is a read/write transaction open, ** (c) the connection holds a write-lock on the table (if required), @@ -68538,12 +76982,12 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); - assert( pCsr->apPage[pCsr->iPage]->intKey ); + assert( pCsr->pPage->intKey ); return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); } -/* +/* ** Mark this cursor as an incremental blob cursor. */ SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ @@ -68553,14 +76997,14 @@ SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){ #endif /* -** Set both the "read version" (single byte at byte offset 18) and +** Set both the "read version" (single byte at byte offset 18) and ** "write version" (single byte at byte offset 19) fields in the database ** header to iVersion. */ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ BtShared *pBt = pBtree->pBt; int rc; /* Return code */ - + assert( iVersion==1 || iVersion==2 ); /* If setting the version fields to 1, do not automatically open the @@ -68569,11 +77013,11 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){ pBt->btsFlags &= ~BTS_NO_WAL; if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL; - rc = sqlite3BtreeBeginTrans(pBtree, 0); + rc = sqlite3BtreeBeginTrans(pBtree, 0, 0); if( rc==SQLITE_OK ){ u8 *aData = pBt->pPage1->aData; if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){ - rc = sqlite3BtreeBeginTrans(pBtree, 2); + rc = sqlite3BtreeBeginTrans(pBtree, 2, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc==SQLITE_OK ){ @@ -68618,7 +77062,7 @@ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){ /* ** Return the number of connections to the BtShared object accessed by -** the Btree handle passed as the only argument. For private caches +** the Btree handle passed as the only argument. For private caches ** this is always 1. For shared caches it may be 1 or greater. */ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ @@ -68640,7 +77084,7 @@ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the implementation of the sqlite3_backup_XXX() +** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. */ /* #include "sqliteInt.h" */ @@ -68677,15 +77121,15 @@ struct sqlite3_backup { ** Once it has been created using backup_init(), a single sqlite3_backup ** structure may be accessed via two groups of thread-safe entry points: ** -** * Via the sqlite3_backup_XXX() API function backup_step() and +** * Via the sqlite3_backup_XXX() API function backup_step() and ** backup_finish(). Both these functions obtain the source database -** handle mutex and the mutex associated with the source BtShared +** handle mutex and the mutex associated with the source BtShared ** structure, in that order. ** ** * Via the BackupUpdate() and BackupRestart() functions, which are ** invoked by the pager layer to report various state changes in ** the page cache associated with the source database. The mutex -** associated with the source database BtShared structure will always +** associated with the source database BtShared structure will always ** be held when either of these functions are invoked. ** ** The other sqlite3_backup_XXX() API functions, backup_remaining() and @@ -68706,8 +77150,8 @@ struct sqlite3_backup { ** in connection handle pDb. If such a database cannot be found, return ** a NULL pointer and write an error message to pErrorDb. ** -** If the "temp" database is requested, it may need to be opened by this -** function. If an error occurs while doing so, return 0 and write an +** If the "temp" database is requested, it may need to be opened by this +** function. If an error occurs while doing so, return 0 and write an ** error message to pErrorDb. */ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ @@ -68716,14 +77160,13 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ if( i==1 ){ Parse sParse; int rc = 0; - memset(&sParse, 0, sizeof(sParse)); - sParse.db = pDb; + sqlite3ParseObjectInit(&sParse,pDb); if( sqlite3OpenTempDatabase(&sParse) ){ sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); rc = SQLITE_ERROR; } sqlite3DbFree(pErrorDb, sParse.zErrMsg); - sqlite3ParserReset(&sParse); + sqlite3ParseObjectReset(&sParse); if( rc ){ return 0; } @@ -68743,18 +77186,18 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ */ static int setDestPgsz(sqlite3_backup *p){ int rc; - rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0); + rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0); return rc; } /* ** Check that there is no open read-transaction on the b-tree passed as the ** second argument. If there is not, return SQLITE_OK. Otherwise, if there -** is an open read-transaction, return SQLITE_ERROR and leave an error +** is an open read-transaction, return SQLITE_ERROR and leave an error ** message in database handle db. */ static int checkReadTransaction(sqlite3 *db, Btree *p){ - if( sqlite3BtreeIsInReadTrans(p) ){ + if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); return SQLITE_ERROR; } @@ -68820,13 +77263,13 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init( p->iNext = 1; p->isAttached = 0; - if( 0==p->pSrc || 0==p->pDest - || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK + if( 0==p->pSrc || 0==p->pDest + || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK ){ /* One (or both) of the named databases did not exist or an OOM ** error was hit. Or there is a transaction open on the destination - ** database. The error has already been written into the pDestDb - ** handle. All that is left to do here is free the sqlite3_backup + ** database. The error has already been written into the pDestDb + ** handle. All that is left to do here is free the sqlite3_backup ** structure. */ sqlite3_free(p); p = 0; @@ -68842,7 +77285,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init( } /* -** Argument rc is an SQLite error code. Return true if this error is +** Argument rc is an SQLite error code. Return true if this error is ** considered fatal if encountered during a backup operation. All errors ** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED. */ @@ -68851,8 +77294,8 @@ static int isFatalError(int rc){ } /* -** Parameter zSrcData points to a buffer containing the data for -** page iSrcPg from the source database. Copy this data into the +** Parameter zSrcData points to a buffer containing the data for +** page iSrcPg from the source database. Copy this data into the ** destination database. */ static int backupOnePage( @@ -68866,13 +77309,6 @@ static int backupOnePage( int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; -#ifdef SQLITE_HAS_CODEC - /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is - ** guaranteed that the shared-mutex is held by this thread, handle - ** p->pSrc may not actually be the owner. */ - int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); - int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest); -#endif int rc = SQLITE_OK; i64 iOff; @@ -68883,33 +77319,13 @@ static int backupOnePage( assert( zSrcData ); /* Catch the case where the destination is an in-memory database and the - ** page sizes of the source and destination differ. + ** page sizes of the source and destination differ. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){ rc = SQLITE_READONLY; } -#ifdef SQLITE_HAS_CODEC - /* Backup is not possible if the page size of the destination is changing - ** and a codec is in use. - */ - if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ - rc = SQLITE_READONLY; - } - - /* Backup is not possible if the number of bytes of reserve space differ - ** between source and destination. If there is a difference, try to - ** fix the destination to agree with the source. If that is not possible, - ** then the backup cannot proceed. - */ - if( nSrcReserve!=nDestReserve ){ - u32 newPgsz = nSrcPgsz; - rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); - if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; - } -#endif - - /* This loop runs once for each destination page spanned by the source + /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. */ @@ -68928,7 +77344,7 @@ static int backupOnePage( ** Then clear the Btree layer MemPage.isInit flag. Both this module ** and the pager code use this trick (clearing the first byte ** of the page 'extra' space to invalidate the Btree layers - ** cached parse of the page). MemPage.isInit is marked + ** cached parse of the page). MemPage.isInit is marked ** "MUST BE FIRST" for this purpose. */ memcpy(zOut, zIn, nCopy); @@ -68948,7 +77364,7 @@ static int backupOnePage( ** exactly iSize bytes. If pFile is not larger than iSize bytes, then ** this function is a no-op. ** -** Return SQLITE_OK if everything is successful, or an SQLite error +** Return SQLITE_OK if everything is successful, or an SQLite error ** code if an error occurs. */ static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){ @@ -69012,8 +77428,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ - if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){ - rc = sqlite3BtreeBeginTrans(p->pSrc, 0); + if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){ + rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0); bCloseTrans = 1; } @@ -69029,10 +77445,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 - && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2, + (int*)&p->iDestSchema)) ){ p->bDestLocked = 1; - sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); } /* Do not allow backup if the destination database is in WAL mode @@ -69043,7 +77459,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){ rc = SQLITE_READONLY; } - + /* Now that there is a read-lock on the source database, query the ** source pager for the number of pages in the database. */ @@ -69070,7 +77486,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ attachBackupObject(p); } } - + /* Update the schema version field in the destination database. This ** is to make sure that the schema-version really does change in ** the case where the source and destination databases have the @@ -69096,12 +77512,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int nDestTruncate; /* Set nDestTruncate to the final number of pages in the destination ** database. The complication here is that the destination page - ** size may be different to the source page size. + ** size may be different to the source page size. ** - ** If the source page size is smaller than the destination page size, + ** If the source page size is smaller than the destination page size, ** round up. In this case the call to sqlite3OsTruncate() below will ** fix the size of the file. However it is important to call - ** sqlite3PagerTruncateImage() here so that any pages in the + ** sqlite3PagerTruncateImage() here so that any pages in the ** destination file that lie beyond the nDestTruncate page mark are ** journalled by PagerCommitPhaseOne() before they are destroyed ** by the file truncation. @@ -69125,7 +77541,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** ** * The destination may need to be truncated, and ** - ** * Data stored on the pages immediately following the + ** * Data stored on the pages immediately following the ** pending-byte page in the source database may need to be ** copied into the destination database. */ @@ -69137,7 +77553,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ i64 iEnd; assert( pFile ); - assert( nDestTruncate==0 + assert( nDestTruncate==0 || (i64)nDestTruncate*(i64)pgszDest >= iSize || ( nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest @@ -69147,7 +77563,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** database has been stored in the journal for pDestPager and the ** journal synced to disk. So at this point we may safely modify ** the database file in any way, knowing that if a power failure - ** occurs, the original database will be reconstructed from the + ** occurs, the original database will be reconstructed from the ** journal file. */ sqlite3PagerPagecount(pDestPager, &nDstPage); for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){ @@ -69167,8 +77583,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* Write the extra pages and truncate the database file as required */ iEnd = MIN(PENDING_BYTE + pgszDest, iSize); for( - iOff=PENDING_BYTE+pgszSrc; - rc==SQLITE_OK && iOffpDest, 0)) @@ -69201,7 +77617,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ } } } - + /* If bCloseTrans is true, then this function opened a read transaction ** on the source database. Close the read transaction here. There is ** no need to check the return values of the btree methods here, as @@ -69213,7 +77629,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0); assert( rc2==SQLITE_OK ); } - + if( rc==SQLITE_IOERR_NOMEM ){ rc = SQLITE_NOMEM_BKPT; } @@ -69250,8 +77666,10 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){ } if( p->isAttached ){ pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); + assert( pp!=0 ); while( *pp!=p ){ pp = &(*pp)->pNext; + assert( pp!=0 ); } *pp = p->pNext; } @@ -69293,7 +77711,7 @@ SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){ } /* -** Return the total number of pages in the source database as of the most +** Return the total number of pages in the source database as of the most ** recent call to sqlite3_backup_step(). */ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){ @@ -69308,7 +77726,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){ /* ** This function is called after the contents of page iPage of the -** source database have been modified. If page iPage has already been +** source database have been modified. If page iPage has already been ** copied into the destination database, then the data written to the ** destination is now invalidated. The destination copy of iPage needs ** to be updated with the new data before the backup operation is @@ -69351,7 +77769,7 @@ SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, con ** Restart the backup process. This is called when the pager layer ** detects that the database has been modified by an external database ** connection. In this case there is no way of knowing which of the -** pages that have been copied into the destination database are still +** pages that have been copied into the destination database are still ** valid and which are not, so the entire process needs to be restarted. ** ** It is assumed that the mutex associated with the BtShared object @@ -69371,8 +77789,8 @@ SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *pBackup){ ** Copy the complete content of pBtFrom into pBtTo. A transaction ** must be active for both files. ** -** The size of file pTo may be reduced by this operation. If anything -** goes wrong, the transaction on pTo is rolled back. If successful, the +** The size of file pTo may be reduced by this operation. If anything +** goes wrong, the transaction on pTo is rolled back. If successful, the ** transaction is committed before returning. */ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ @@ -69382,7 +77800,7 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); - assert( sqlite3BtreeIsInTrans(pTo) ); + assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE ); pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); if( pFd->pMethods ){ i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); @@ -69402,15 +77820,11 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ b.pDest = pTo; b.iNext = 1; -#ifdef SQLITE_HAS_CODEC - sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom)); -#endif - /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to - ** sqlite3_backup_step(), we can guarantee that the copy finishes + ** sqlite3_backup_step(), we can guarantee that the copy finishes ** within a single call (unless an error occurs). The assert() statement - ** checks this assumption - (p->rc) should be set to either SQLITE_DONE + ** checks this assumption - (p->rc) should be set to either SQLITE_DONE ** or an error code. */ sqlite3_backup_step(&b, 0x7FFFFFFF); assert( b.rc!=SQLITE_OK ); @@ -69422,7 +77836,7 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } - assert( sqlite3BtreeIsInTrans(pTo)==0 ); + assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE ); copy_finished: sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); @@ -69452,6 +77866,11 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ +/* True if X is a power of two. 0 is considered a power of two here. +** In other words, return true if X has at most one bit set. +*/ +#define ISPOWEROF2(X) (((X)&((X)-1))==0) + #ifdef SQLITE_DEBUG /* ** Check invariants on a Mem object. @@ -69460,8 +77879,8 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ ** this: assert( sqlite3VdbeCheckMemInvariants(pMem) ); */ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ - /* If MEM_Dyn is set then Mem.xDel!=0. - ** Mem.xDel is might not be initialized if MEM_Dyn is clear. + /* If MEM_Dyn is set then Mem.xDel!=0. + ** Mem.xDel might not be initialized if MEM_Dyn is clear. */ assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 ); @@ -69471,12 +77890,42 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ ** That saves a few cycles in inner loops. */ assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); - /* Cannot be both MEM_Int and MEM_Real at the same time */ - assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); + /* Cannot have more than one of MEM_Int, MEM_Real, or MEM_IntReal */ + assert( ISPOWEROF2(p->flags & (MEM_Int|MEM_Real|MEM_IntReal)) ); + + if( p->flags & MEM_Null ){ + /* Cannot be both MEM_Null and some other type */ + assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 ); + + /* If MEM_Null is set, then either the value is a pure NULL (the usual + ** case) or it is a pointer set using sqlite3_bind_pointer() or + ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be + ** set. + */ + if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){ + /* This is a pointer type. There may be a flag to indicate what to + ** do with the pointer. */ + assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + + ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 ); + + /* No other bits set */ + assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype|MEM_FromBind + |MEM_Dyn|MEM_Ephem|MEM_Static))==0 ); + }else{ + /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn, + ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */ + } + }else{ + /* The MEM_Cleared bit is only allowed on NULLs */ + assert( (p->flags & MEM_Cleared)==0 ); + } /* The szMalloc field holds the correct memory allocation size */ assert( p->szMalloc==0 - || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) ); + || (p->flags==MEM_Undefined + && p->szMalloc<=sqlite3DbMallocSize(p->db,p->zMalloc)) + || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc)); /* If p holds a string or blob, the Mem.z must point to exactly ** one of the following: @@ -69487,7 +77936,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ ** (4) A static string or blob */ if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){ - assert( + assert( ((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) + ((p->flags&MEM_Dyn)!=0 ? 1 : 0) + ((p->flags&MEM_Ephem)!=0 ? 1 : 0) + @@ -69498,6 +77947,89 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ } #endif +/* +** Render a Mem object which is one of MEM_Int, MEM_Real, or MEM_IntReal +** into a buffer. +*/ +static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ + StrAccum acc; + assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); + assert( sz>22 ); + if( p->flags & MEM_Int ){ +#if GCC_VERSION>=7000000 + /* Work-around for GCC bug + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */ + i64 x; + assert( (p->flags&MEM_Int)*2==sizeof(x) ); + memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2); + sqlite3Int64ToText(x, zBuf); +#else + sqlite3Int64ToText(p->u.i, zBuf); +#endif + }else{ + sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); + sqlite3_str_appendf(&acc, "%!.15g", + (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r); + assert( acc.zText==zBuf && acc.mxAlloc<=0 ); + zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ + } +} + +#ifdef SQLITE_DEBUG +/* +** Validity checks on pMem. pMem holds a string. +** +** (1) Check that string value of pMem agrees with its integer or real value. +** (2) Check that the string is correctly zero terminated +** +** A single int or real value always converts to the same strings. But +** many different strings can be converted into the same int or real. +** If a table contains a numeric value and an index is based on the +** corresponding string value, then it is important that the string be +** derived from the numeric value, not the other way around, to ensure +** that the index and table are consistent. See ticket +** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for +** an example. +** +** This routine looks at pMem to verify that if it has both a numeric +** representation and a string representation then the string rep has +** been derived from the numeric and not the other way around. It returns +** true if everything is ok and false if there is a problem. +** +** This routine is for use inside of assert() statements only. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){ + char zBuf[100]; + char *z; + int i, j, incr; + if( (p->flags & MEM_Str)==0 ) return 1; + if( p->flags & MEM_Term ){ + /* Insure that the string is properly zero-terminated. Pay particular + ** attention to the case where p->n is odd */ + if( p->szMalloc>0 && p->z==p->zMalloc ){ + assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 ); + assert( p->enc!=SQLITE_UTF8 || p->szMalloc >= p->n+1 ); + } + assert( p->z[p->n]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[(p->n+1)&~1]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); + } + if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; + vdbeMemRenderNum(sizeof(zBuf), zBuf, p); + z = p->z; + i = j = 0; + incr = 1; + if( p->enc!=SQLITE_UTF8 ){ + incr = 2; + if( p->enc==SQLITE_UTF16BE ) z++; + } + while( zBuf[j] ){ + if( zBuf[j++]!=z[i] ) return 0; + i += incr; + } + return 1; +} +#endif /* SQLITE_DEBUG */ /* ** If pMem is an object with a valid string representation, this routine @@ -69516,7 +78048,8 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( pMem!=0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ @@ -69539,8 +78072,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ } /* -** Make sure pMem->z points to a writable allocation of at least -** min(n,32) bytes. +** Make sure pMem->z points to a writable allocation of at least n bytes. ** ** If the bPreserve argument is true, then copy of the content of ** pMem->z into the new allocation. pMem must be either a string or @@ -69549,7 +78081,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); testcase( pMem->db==0 ); /* If the bPreserve flag is set to true, then the memory cell must already @@ -69558,27 +78090,33 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre testcase( bPreserve && pMem->z==0 ); assert( pMem->szMalloc==0 - || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); - if( pMem->szMallocszMalloc>0 && pMem->z==pMem->zMalloc ){ + || (pMem->flags==MEM_Undefined + && pMem->szMalloc<=sqlite3DbMallocSize(pMem->db,pMem->zMalloc)) + || pMem->szMalloc==sqlite3DbMallocSize(pMem->db,pMem->zMalloc)); + if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ + if( pMem->db ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); - bPreserve = 0; - }else{ - if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); - pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); - } - if( pMem->zMalloc==0 ){ - sqlite3VdbeMemSetNull(pMem); - pMem->z = 0; - pMem->szMalloc = 0; - return SQLITE_NOMEM_BKPT; }else{ - pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + pMem->zMalloc = sqlite3Realloc(pMem->z, n); + if( pMem->zMalloc==0 ) sqlite3_free(pMem->z); + pMem->z = pMem->zMalloc; } + bPreserve = 0; + }else{ + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); + pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); + } + if( pMem->zMalloc==0 ){ + sqlite3VdbeMemSetNull(pMem); + pMem->z = 0; + pMem->szMalloc = 0; + return SQLITE_NOMEM_BKPT; + }else{ + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); } - if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){ + if( bPreserve && pMem->z ){ + assert( pMem->z!=pMem->zMalloc ); memcpy(pMem->zMalloc, pMem->z, pMem->n); } if( (pMem->flags&MEM_Dyn)!=0 ){ @@ -69598,21 +78136,41 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre ** ** Any prior string or blob content in the pMem object may be discarded. ** The pMem->xDel destructor is called, if it exists. Though MEM_Str -** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null -** values are preserved. +** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, MEM_IntReal, +** and MEM_Null values are preserved. ** ** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) ** if unable to complete the resizing. */ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ - assert( szNew>0 ); + assert( CORRUPT_DB || szNew>0 ); assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 ); if( pMem->szMallocflags & MEM_Dyn)==0 ); pMem->z = pMem->zMalloc; - pMem->flags &= (MEM_Null|MEM_Int|MEM_Real); + pMem->flags &= (MEM_Null|MEM_Int|MEM_Real|MEM_IntReal); + return SQLITE_OK; +} + +/* +** It is already known that pMem contains an unterminated string. +** Add the zero terminator. +** +** Three bytes of zero are added. In this way, there is guaranteed +** to be a double-zero byte at an even byte boundary in order to +** terminate a UTF16 string, even if the initial size of the buffer +** is an odd number of bytes. +*/ +static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ + if( sqlite3VdbeMemGrow(pMem, pMem->n+3, 1) ){ + return SQLITE_NOMEM_BKPT; + } + pMem->z[pMem->n] = 0; + pMem->z[pMem->n+1] = 0; + pMem->z[pMem->n+2] = 0; + pMem->flags |= MEM_Term; return SQLITE_OK; } @@ -69623,17 +78181,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ - if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ - return SQLITE_NOMEM_BKPT; - } - pMem->z[pMem->n] = 0; - pMem->z[pMem->n+1] = 0; - pMem->flags |= MEM_Term; + int rc = vdbeMemAddTerminator(pMem); + if( rc ) return rc; } } pMem->flags &= ~MEM_Ephem; @@ -69651,19 +78206,24 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ #ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; + assert( pMem!=0 ); assert( pMem->flags & MEM_Zero ); - assert( pMem->flags&MEM_Blob ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) ); + testcase( sqlite3_value_nochange(pMem) ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.nZero; if( nByte<=0 ){ + if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK; nByte = 1; } if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ return SQLITE_NOMEM_BKPT; } + assert( pMem->z!=0 ); + assert( sqlite3DbMallocSize(pMem->db,pMem->z) >= nByte ); memset(&pMem->z[pMem->n], 0, pMem->u.nZero); pMem->n += pMem->u.nZero; @@ -69672,24 +78232,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ } #endif -/* -** It is already known that pMem contains an unterminated string. -** Add the zero terminator. -*/ -static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ - if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ - return SQLITE_NOMEM_BKPT; - } - pMem->z[pMem->n] = 0; - pMem->z[pMem->n+1] = 0; - pMem->flags |= MEM_Term; - return SQLITE_OK; -} - /* ** Make sure the given Mem is \u0000 terminated. */ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) ); testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 ); @@ -69701,12 +78248,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ } /* -** Add MEM_Str to the set of representations for the given Mem. Numbers -** are converted using sqlite3_snprintf(). Converting a BLOB to a string -** is a no-op. +** Add MEM_Str to the set of representations for the given Mem. This +** routine is only called if pMem is a number of some kind, not a NULL +** or a BLOB. ** -** Existing representations MEM_Int and MEM_Real are invalidated if -** bForce is true but are retained if bForce is false. +** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated +** if bForce is true but are retained if bForce is false. ** ** A MEM_Null value will never be passed to this function. This function is ** used for converting values to text for returning to the user (i.e. via @@ -69715,14 +78262,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ ** user and the latter is an internal programming error. */ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ - int fg = pMem->flags; const int nByte = 32; + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( !(fg&MEM_Zero) ); - assert( !(fg&(MEM_Str|MEM_Blob)) ); - assert( fg&(MEM_Int|MEM_Real) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !(pMem->flags&MEM_Zero) ); + assert( !(pMem->flags&(MEM_Str|MEM_Blob)) ); + assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -69731,22 +78278,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ return SQLITE_NOMEM_BKPT; } - /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 - ** string representation of the value. Then, if the required encoding - ** is UTF-16le or UTF-16be do a translation. - ** - ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. - */ - if( fg & MEM_Int ){ - sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); - }else{ - assert( fg & MEM_Real ); - sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); - } - pMem->n = sqlite3Strlen30(pMem->z); + vdbeMemRenderNum(nByte, pMem->z, pMem); + assert( pMem->z!=0 ); + pMem->n = sqlite3Strlen30NN(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; - if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); + if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); sqlite3VdbeChangeEncoding(pMem, enc); return SQLITE_OK; } @@ -69760,28 +78297,52 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ ** otherwise. */ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ - int rc = SQLITE_OK; - if( ALWAYS(pFunc && pFunc->xFinalize) ){ - sqlite3_context ctx; - Mem t; - assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - memset(&ctx, 0, sizeof(ctx)); - memset(&t, 0, sizeof(t)); - t.flags = MEM_Null; - t.db = pMem->db; - ctx.pOut = &t; - ctx.pMem = pMem; - ctx.pFunc = pFunc; - pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ - assert( (pMem->flags & MEM_Dyn)==0 ); - if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc); - memcpy(pMem, &t, sizeof(t)); - rc = ctx.isError; - } - return rc; + sqlite3_context ctx; + Mem t; + assert( pFunc!=0 ); + assert( pMem!=0 ); + assert( pFunc->xFinalize!=0 ); + assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + memset(&ctx, 0, sizeof(ctx)); + memset(&t, 0, sizeof(t)); + t.flags = MEM_Null; + t.db = pMem->db; + ctx.pOut = &t; + ctx.pMem = pMem; + ctx.pFunc = pFunc; + pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ + assert( (pMem->flags & MEM_Dyn)==0 ); + if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); + memcpy(pMem, &t, sizeof(t)); + return ctx.isError; } +/* +** Memory cell pAccum contains the context of an aggregate function. +** This routine calls the xValue method for that function and stores +** the results in memory cell pMem. +** +** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK +** otherwise. +*/ +#ifndef SQLITE_OMIT_WINDOWFUNC +SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){ + sqlite3_context ctx; + assert( pFunc!=0 ); + assert( pFunc->xValue!=0 ); + assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef ); + assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) ); + memset(&ctx, 0, sizeof(ctx)); + sqlite3VdbeMemSetNull(pOut); + ctx.pOut = pOut; + ctx.pMem = pAccum; + ctx.pFunc = pFunc; + pFunc->xValue(&ctx); + return ctx.isError; +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + /* ** If the memory cell contains a value that must be freed by ** invoking the external callback in Mem.xDel, then this routine @@ -69800,15 +78361,8 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ testcase( p->flags & MEM_Dyn ); } if( p->flags&MEM_Dyn ){ - assert( (p->flags&MEM_RowSet)==0 ); assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); p->xDel((void *)p->z); - }else if( p->flags&MEM_RowSet ){ - sqlite3RowSetClear(p->u.pRowSet); - }else if( p->flags&MEM_Frame ){ - VdbeFrame *pFrame = p->u.pFrame; - pFrame->pParent = pFrame->v->pDelFrame; - pFrame->v->pDelFrame = pFrame; } p->flags = MEM_Null; } @@ -69826,7 +78380,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ vdbeMemClearExternAndSetNull(p); } if( p->szMalloc ){ - sqlite3DbFree(p->db, p->zMalloc); + sqlite3DbFreeNN(p->db, p->zMalloc); p->szMalloc = 0; } p->z = 0; @@ -69854,7 +78408,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){ ** If the double is out of range of a 64-bit signed integer then ** return the closest available 64-bit signed integer. */ -static i64 doubleToInt64(double r){ +static SQLITE_NOINLINE i64 doubleToInt64(double r){ #ifdef SQLITE_OMIT_FLOATING_POINT /* When floating-point is omitted, double and int64 are the same thing */ return r; @@ -69890,20 +78444,24 @@ static i64 doubleToInt64(double r){ ** ** If pMem represents a string value, its encoding might be changed. */ -SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ +static SQLITE_NOINLINE i64 memIntValue(const Mem *pMem){ + i64 value = 0; + sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); + return value; +} +SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){ int flags; + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; - if( flags & MEM_Int ){ + if( flags & (MEM_Int|MEM_IntReal) ){ + testcase( flags & MEM_IntReal ); return pMem->u.i; }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); - }else if( flags & (MEM_Str|MEM_Blob) ){ - i64 value = 0; - assert( pMem->z || pMem->n==0 ); - sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); - return value; + }else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){ + return memIntValue(pMem); }else{ return 0; } @@ -69915,32 +78473,49 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ +static SQLITE_NOINLINE double memRealValue(Mem *pMem){ + /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ + double val = (double)0; + sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); + return val; +} SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ return pMem->u.r; - }else if( pMem->flags & MEM_Int ){ + }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - double val = (double)0; - sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); - return val; + return memRealValue(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; } } +/* +** Return 1 if pMem represents true, and return 0 if pMem represents false. +** Return the value ifNull if pMem is NULL. +*/ +SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ + testcase( pMem->flags & MEM_IntReal ); + if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0; + if( pMem->flags & MEM_Null ) return ifNull; + return sqlite3VdbeRealValue(pMem)!=0.0; +} + /* ** The MEM structure is already a MEM_Real. Try to also make it a ** MEM_Int if we can. */ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; + assert( pMem!=0 ); assert( pMem->flags & MEM_Real ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -69966,8 +78541,9 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){ ** Convert pMem to type integer. Invalidate any prior representations. */ SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.i = sqlite3VdbeIntValue(pMem); @@ -69980,6 +78556,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){ ** Invalidate any prior representations. */ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -69988,8 +78565,24 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ return SQLITE_OK; } +/* Compare a floating point value to an integer. Return true if the two +** values are the same within the precision of the floating point value. +** +** This function assumes that i was obtained by assignment from r1. +** +** For some versions of GCC on 32-bit machines, if you do the more obvious +** comparison of "r1==(double)i" you sometimes get an answer of false even +** though the r1 and (double)i values are bit-for-bit the same. +*/ +SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ + double r2 = (double)i; + return r1==0.0 + || (memcmp(&r1, &r2, sizeof(r1))==0 + && i >= -2251799813685248LL && i < 2251799813685248LL); +} + /* -** Convert pMem so that it has types MEM_Real or MEM_Int or both. +** Convert pMem so that it has type MEM_Real or MEM_Int. ** Invalidate any prior representations. ** ** Every effort is made to force the conversion, even if the input @@ -69997,18 +78590,27 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ ** as much of the string as we can and ignore the rest. */ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ - if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ + assert( pMem!=0 ); + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); + testcase( pMem->flags & MEM_Null ); + if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){ + int rc; + sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ + rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) + || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r)) + ){ + pMem->u.i = ix; MemSetTypeFlag(pMem, MEM_Int); }else{ - pMem->u.r = sqlite3VdbeRealValue(pMem); MemSetTypeFlag(pMem, MEM_Real); - sqlite3VdbeIntegerAffinity(pMem); } } - assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))!=0 ); pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero); return SQLITE_OK; } @@ -70020,8 +78622,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ ** affinity even if that results in loss of data. This routine is ** used (for example) to implement the SQL "cast()" operator. */ -SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ - if( pMem->flags & MEM_Null ) return; +SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ + if( pMem->flags & MEM_Null ) return SQLITE_OK; switch( aff ){ case SQLITE_AFF_BLOB: { /* Really a cast to BLOB */ if( (pMem->flags & MEM_Blob)==0 ){ @@ -70051,10 +78653,11 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ pMem->flags |= (pMem->flags&MEM_Blob)>>3; sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); - pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); - break; + pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero); + return sqlite3VdbeChangeEncoding(pMem, encoding); } } + return SQLITE_OK; } /* @@ -70090,13 +78693,14 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){ } } SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){ - sqlite3VdbeMemSetNull((Mem*)p); + sqlite3VdbeMemSetNull((Mem*)p); } /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ +#ifndef SQLITE_OMIT_INCRBLOB SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero; @@ -70106,6 +78710,21 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ pMem->enc = SQLITE_UTF8; pMem->z = 0; } +#else +SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ + int nByte = n>0?n:1; + if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + return SQLITE_NOMEM_BKPT; + } + assert( pMem->z!=0 ); + assert( sqlite3DbMallocSize(pMem->db, pMem->z)>=nByte ); + memset(pMem->z, 0, nByte); + pMem->n = n>0?n:0; + pMem->flags = MEM_Blob; + pMem->enc = SQLITE_UTF8; + return SQLITE_OK; +} +#endif /* ** The pMem is known to contain content that needs to be destroyed prior @@ -70131,6 +78750,28 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ } } +/* A no-op destructor */ +SQLITE_PRIVATE void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); } + +/* +** Set the value stored in *pMem should already be a NULL. +** Also store a pointer to go with it. +*/ +SQLITE_PRIVATE void sqlite3VdbeMemSetPointer( + Mem *pMem, + void *pPtr, + const char *zPType, + void (*xDestructor)(void*) +){ + assert( pMem->flags==MEM_Null ); + vdbeMemClear(pMem); + pMem->u.zPType = zPType ? zPType : ""; + pMem->z = pPtr; + pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term; + pMem->eSubtype = 'p'; + pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor; +} + #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Delete any previous value and set the value stored in *pMem to val, @@ -70145,26 +78786,36 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ } #endif +#ifdef SQLITE_DEBUG +/* +** Return true if the Mem holds a RowSet object. This routine is intended +** for use inside of assert() statements. +*/ +SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem *pMem){ + return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn) + && pMem->xDel==sqlite3RowSetDelete; +} +#endif + /* ** Delete any previous value and set the value of pMem to be an ** empty boolean index. +** +** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation +** error occurs. */ -SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){ +SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem *pMem){ sqlite3 *db = pMem->db; + RowSet *p; assert( db!=0 ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); sqlite3VdbeMemRelease(pMem); - pMem->zMalloc = sqlite3DbMallocRawNN(db, 64); - if( db->mallocFailed ){ - pMem->flags = MEM_Null; - pMem->szMalloc = 0; - }else{ - assert( pMem->zMalloc ); - pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc); - pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc); - assert( pMem->u.pRowSet!=0 ); - pMem->flags = MEM_RowSet; - } + p = sqlite3RowSetInit(db); + if( p==0 ) return SQLITE_NOMEM; + pMem->z = (char*)p; + pMem->flags = MEM_Blob|MEM_Dyn; + pMem->xDel = sqlite3RowSetDelete; + return SQLITE_OK; } /* @@ -70180,7 +78831,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ } return n>p->db->aLimit[SQLITE_LIMIT_LENGTH]; } - return 0; + return 0; } #ifdef SQLITE_DEBUG @@ -70189,15 +78840,31 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){ ** its link to a shallow copy and by marking any current shallow ** copies of this cell as invalid. ** -** This is used for testing and debugging only - to make sure shallow -** copies are not misused. +** This is used for testing and debugging only - to help ensure that shallow +** copies (created by OP_SCopy) are not misused. */ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ int i; Mem *pX; - for(i=0, pX=pVdbe->aMem; inMem; i++, pX++){ + for(i=1, pX=pVdbe->aMem+1; inMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ - pX->flags |= MEM_Undefined; + u16 mFlags; + if( pVdbe->db->flags & SQLITE_VdbeTrace ){ + sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n", + (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem)); + } + /* If pX is marked as a shallow copy of pMem, then try to verify that + ** no significant changes have been made to pX since the OP_SCopy. + ** A significant change would indicated a missed call to this + ** function for pX. Minor changes, such as adding or removing a + ** dual type, are allowed, as long as the underlying value is the + ** same. */ + mFlags = pMem->flags & pX->flags & pX->mScopyFlags; + assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); + + /* pMem is the register that is changing. But also mark pX as + ** undefined so that we can quickly detect the shallow-copy error */ + pX->flags = MEM_Undefined; pX->pScopyFrom = 0; } } @@ -70205,7 +78872,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ } #endif /* SQLITE_DEBUG */ - /* ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are freed. The pFrom->z field is not duplicated. If @@ -70218,7 +78884,7 @@ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){ sqlite3VdbeMemShallowCopy(pTo, pFrom, eType); } SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ - assert( (pFrom->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pFrom) ); assert( pTo->db==pFrom->db ); if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; } memcpy(pTo, pFrom, MEMCELLSIZE); @@ -70236,7 +78902,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; - assert( (pFrom->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pFrom) ); if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; @@ -70271,8 +78937,8 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ ** Change the value of a Mem to be a string or a BLOB. ** ** The memory management strategy depends on the value of the xDel -** parameter. If the value passed is SQLITE_TRANSIENT, then the -** string is copied into a (possibly existing) buffer managed by the +** parameter. If the value passed is SQLITE_TRANSIENT, then the +** string is copied into a (possibly existing) buffer managed by the ** Mem structure. Otherwise, any existing buffer is freed and the ** pointer copied. ** @@ -70285,16 +78951,17 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ const char *z, /* String pointer */ - int n, /* Bytes in string, or negative */ + i64 n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ - int nByte = n; /* New value for pMem->n */ + i64 nByte = n; /* New value for pMem->n */ int iLimit; /* Maximum allowed string or blob size */ u16 flags = 0; /* New value for pMem->flags */ + assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ @@ -70311,8 +78978,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( if( nByte<0 ){ assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ - nByte = sqlite3Strlen30(z); - if( nByte>iLimit ) nByte = iLimit+1; + nByte = strlen(z); }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } @@ -70324,43 +78990,53 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( ** management (one of MEM_Dyn or MEM_Static). */ if( xDel==SQLITE_TRANSIENT ){ - int nAlloc = nByte; + i64 nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); } if( nByte>iLimit ){ - return SQLITE_TOOBIG; + return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } testcase( nAlloc==0 ); testcase( nAlloc==31 ); testcase( nAlloc==32 ); - if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ + if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ return SQLITE_NOMEM_BKPT; } memcpy(pMem->z, z, nAlloc); - }else if( xDel==SQLITE_DYNAMIC ){ - sqlite3VdbeMemRelease(pMem); - pMem->zMalloc = pMem->z = (char *)z; - pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; - pMem->xDel = xDel; - flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + if( xDel==SQLITE_DYNAMIC ){ + pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + }else{ + pMem->xDel = xDel; + flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + } } - pMem->n = nByte; + pMem->n = (int)(nByte & 0x7fffffff); pMem->flags = flags; - pMem->enc = (enc==0 ? SQLITE_UTF8 : enc); + if( enc ){ + pMem->enc = enc; +#ifdef SQLITE_ENABLE_SESSION + }else if( pMem->db==0 ){ + pMem->enc = SQLITE_UTF8; +#endif + }else{ + assert( pMem->db!=0 ); + pMem->enc = ENC(pMem->db); + } #ifndef SQLITE_OMIT_UTF16 - if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ + if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ return SQLITE_NOMEM_BKPT; } #endif if( nByte>iLimit ){ - return SQLITE_TOOBIG; + return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } return SQLITE_OK; @@ -70381,7 +79057,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( ** If this routine fails for any reason (malloc returns NULL or unable ** to read from the disk) then the pMem is left in an inconsistent state. */ -static SQLITE_NOINLINE int vdbeMemFromBtreeResize( +SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ @@ -70389,12 +79065,14 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize( ){ int rc; pMem->flags = MEM_Null; - if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){ + if( sqlite3BtreeMaxRecordSize(pCur)z); if( rc==SQLITE_OK ){ - pMem->z[amt] = 0; - pMem->z[amt+1] = 0; - pMem->flags = MEM_Blob|MEM_Term; + pMem->z[amt] = 0; /* Overrun area used when reading malformed records */ + pMem->flags = MEM_Blob; pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); @@ -70402,31 +79080,28 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize( } return rc; } -SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( +SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset( BtCursor *pCur, /* Cursor pointing at record to retrieve. */ - u32 offset, /* Offset from the start of data to return bytes from. */ u32 amt, /* Number of bytes to return. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ - char *zData; /* Data from the btree layer */ u32 available = 0; /* Number of bytes available on the local btree page */ int rc = SQLITE_OK; /* Return code */ assert( sqlite3BtreeCursorIsValid(pCur) ); assert( !VdbeMemDynamic(pMem) ); - /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() + /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ - assert( (pMem->flags & MEM_RowSet)==0 ); - zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); - assert( zData!=0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); + pMem->z = (char *)sqlite3BtreePayloadFetch(pCur, &available); + assert( pMem->z!=0 ); - if( offset+amt<=available ){ - pMem->z = &zData[offset]; + if( amt<=available ){ pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; }else{ - rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem); + rc = sqlite3VdbeMemFromBtree(pCur, 0, amt, pMem); } return rc; @@ -70441,7 +79116,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); - assert( (pVal->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pVal) ); assert( (pVal->flags & (MEM_Null))==0 ); if( pVal->flags & (MEM_Blob|MEM_Str) ){ if( ExpandBlob(pVal) ) return 0; @@ -70463,6 +79138,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; }else{ return 0; @@ -70483,8 +79159,9 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); - assert( (pVal->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){ @@ -70506,7 +79183,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){ } /* -** Context object passed by sqlite3Stat4ProbeSetValue() through to +** Context object passed by sqlite3Stat4ProbeSetValue() through to ** valueNew(). See comments above valueNew() for details. */ struct ValueNewStat4Ctx { @@ -70521,14 +79198,14 @@ struct ValueNewStat4Ctx { ** the second argument to this function is NULL, the object is allocated ** by calling sqlite3ValueNew(). ** -** Otherwise, if the second argument is non-zero, then this function is +** Otherwise, if the second argument is non-zero, then this function is ** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not -** already been allocated, allocate the UnpackedRecord structure that +** already been allocated, allocate the UnpackedRecord structure that ** that function will return to its caller here. Then return a pointer to ** an sqlite3_value within the UnpackedRecord.a[] array. */ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 if( p ){ UnpackedRecord *pRec = p->ppRec[0]; @@ -70537,13 +79214,13 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ int nByte; /* Bytes of space to allocate */ int i; /* Counter variable */ int nCol = pIdx->nColumn; /* Number of index columns including rowid */ - + nByte = sizeof(Mem) * nCol + ROUND8(sizeof(UnpackedRecord)); pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte); if( pRec ){ pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx); if( pRec->pKeyInfo ){ - assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol ); + assert( pRec->pKeyInfo->nAllField==nCol ); assert( pRec->pKeyInfo->enc==ENC(db) ); pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord))); for(i=0; iaMem[i].db = db; } }else{ - sqlite3DbFree(db, pRec); + sqlite3DbFreeNN(db, pRec); pRec = 0; } } if( pRec==0 ) return 0; p->ppRec[0] = pRec; } - + pRec->nField = p->iVal+1; return &pRec->aMem[p->iVal]; } #else UNUSED_PARAMETER(p); -#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */ +#endif /* defined(SQLITE_ENABLE_STAT4) */ return sqlite3ValueNew(db); } @@ -70577,21 +79254,21 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ ** * the SQLITE_FUNC_NEEDCOLL function flag is not set, ** ** then this routine attempts to invoke the SQL function. Assuming no -** error occurs, output parameter (*ppVal) is set to point to a value +** error occurs, output parameter (*ppVal) is set to point to a value ** object containing the result before returning SQLITE_OK. ** ** Affinity aff is applied to the result of the function before returning. -** If the result is a text value, the sqlite3_value object uses encoding +** If the result is a text value, the sqlite3_value object uses encoding ** enc. ** ** If the conditions above are not met, this function returns SQLITE_OK ** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to ** NULL and an SQLite error code returned. */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 static int valueFromFunction( sqlite3 *db, /* The database connection */ - Expr *p, /* The expression to evaluate */ + const Expr *p, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 aff, /* Affinity to use */ sqlite3_value **ppVal, /* Write the new value here */ @@ -70608,11 +79285,13 @@ static int valueFromFunction( assert( pCtx!=0 ); assert( (p->flags & EP_TokenOnly)==0 ); + assert( ExprUseXList(p) ); pList = p->x.pList; if( pList ) nVal = pList->nExpr; + assert( !ExprHasProperty(p, EP_IntValue) ); pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0); assert( pFunc ); - if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 + if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) ){ return SQLITE_OK; @@ -70663,7 +79342,7 @@ static int valueFromFunction( for(i=0; iop)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft; - if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; + if( op==TK_REGISTER ) op = pExpr->op2; /* Compressed expressions only appear when parsing the DEFAULT clause ** on a table column definition, and hence only when pCtx==0. This @@ -70709,7 +79388,9 @@ static int valueFromExpr( assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 ); if( op==TK_CAST ){ - u8 aff = sqlite3AffinityType(pExpr->u.zToken,0); + u8 aff; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + aff = sqlite3AffinityType(pExpr->u.zToken,0); rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx); testcase( rc!=SQLITE_OK ); if( *ppVal ){ @@ -70745,20 +79426,29 @@ static int valueFromExpr( }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } - if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str; + assert( (pVal->flags & MEM_IntReal)==0 ); + if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){ + testcase( pVal->flags & MEM_Int ); + testcase( pVal->flags & MEM_Real ); + pVal->flags &= ~MEM_Str; + } if( enc!=SQLITE_UTF8 ){ rc = sqlite3VdbeChangeEncoding(pVal, enc); } }else if( op==TK_UMINUS ) { /* This branch happens for multiple negative signs. Ex: -(-5) */ - if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) + if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx) && pVal!=0 ){ sqlite3VdbeMemNumerify(pVal); if( pVal->flags & MEM_Real ){ pVal->u.r = -pVal->u.r; }else if( pVal->u.i==SMALLEST_INT64 ){ +#ifndef SQLITE_OMIT_FLOATING_POINT pVal->u.r = -(double)SMALLEST_INT64; +#else + pVal->u.r = LARGEST_INT64; +#endif MemSetTypeFlag(pVal, MEM_Real); }else{ pVal->u.i = -pVal->u.i; @@ -70768,11 +79458,12 @@ static int valueFromExpr( }else if( op==TK_NULL ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; - sqlite3VdbeMemNumerify(pVal); + sqlite3VdbeMemSetNull(pVal); } #ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ int nVal; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); pVal = valueNew(db, pCtx); @@ -70784,21 +79475,31 @@ static int valueFromExpr( 0, SQLITE_DYNAMIC); } #endif - -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 else if( op==TK_FUNCTION && pCtx!=0 ){ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx); } #endif + else if( op==TK_TRUEFALSE ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pVal = valueNew(db, pCtx); + if( pVal ){ + pVal->flags = MEM_Int; + pVal->u.i = pExpr->u.zToken[4]==0; + } + } *ppVal = pVal; return rc; no_mem: - sqlite3OomFault(db); +#ifdef SQLITE_ENABLE_STAT4 + if( pCtx==0 || NEVER(pCtx->pParse->nErr==0) ) +#endif + sqlite3OomFault(db); sqlite3DbFree(db, zVal); assert( *ppVal==0 ); -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 if( pCtx==0 ) sqlite3ValueFree(pVal); #else assert( pCtx==0 ); sqlite3ValueFree(pVal); @@ -70818,7 +79519,7 @@ static int valueFromExpr( */ SQLITE_PRIVATE int sqlite3ValueFromExpr( sqlite3 *db, /* The database connection */ - Expr *pExpr, /* The expression to evaluate */ + const Expr *pExpr, /* The expression to evaluate */ u8 enc, /* Encoding to use */ u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */ @@ -70826,56 +79527,7 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr( return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0; } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 -/* -** The implementation of the sqlite_record() function. This function accepts -** a single argument of any type. The return value is a formatted database -** record (a blob) containing the argument value. -** -** This is used to convert the value stored in the 'sample' column of the -** sqlite_stat3 table to the record format SQLite uses internally. -*/ -static void recordFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - const int file_format = 1; - u32 iSerial; /* Serial type */ - int nSerial; /* Bytes of space for iSerial as varint */ - u32 nVal; /* Bytes of space required for argv[0] */ - int nRet; - sqlite3 *db; - u8 *aRet; - - UNUSED_PARAMETER( argc ); - iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal); - nSerial = sqlite3VarintLen(iSerial); - db = sqlite3_context_db_handle(context); - - nRet = 1 + nSerial + nVal; - aRet = sqlite3DbMallocRawNN(db, nRet); - if( aRet==0 ){ - sqlite3_result_error_nomem(context); - }else{ - aRet[0] = nSerial+1; - putVarint32(&aRet[1], iSerial); - sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial); - sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT); - sqlite3DbFree(db, aRet); - } -} - -/* -** Register built-in functions used to help read ANALYZE data. -*/ -SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){ - static FuncDef aAnalyzeTableFuncs[] = { - FUNCTION(sqlite_record, 1, 0, 0, recordFunc), - }; - sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs)); -} - +#ifdef SQLITE_ENABLE_STAT4 /* ** Attempt to extract a value from pExpr and use it to construct *ppVal. ** @@ -70908,14 +79560,13 @@ static int stat4ValueFromExpr( /* Skip over any TK_COLLATE nodes */ pExpr = sqlite3ExprSkipCollate(pExpr); + assert( pExpr==0 || pExpr->op!=TK_REGISTER || pExpr->op2!=TK_VARIABLE ); if( !pExpr ){ pVal = valueNew(db, pAlloc); if( pVal ){ sqlite3VdbeMemSetNull((Mem*)pVal); } - }else if( pExpr->op==TK_VARIABLE - || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE) - ){ + }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *v; int iBindVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar); @@ -70923,9 +79574,7 @@ static int stat4ValueFromExpr( pVal = valueNew(db, pAlloc); if( pVal ){ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]); - if( rc==SQLITE_OK ){ - sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); - } + sqlite3ValueApplyAffinity(pVal, affinity, ENC(db)); pVal->db = pParse->db; } } @@ -70939,8 +79588,8 @@ static int stat4ValueFromExpr( } /* -** This function is used to allocate and populate UnpackedRecord -** structures intended to be compared against sample index keys stored +** This function is used to allocate and populate UnpackedRecord +** structures intended to be compared against sample index keys stored ** in the sqlite_stat4 table. ** ** A single call to this function populates zero or more fields of the @@ -70951,14 +79600,14 @@ static int stat4ValueFromExpr( ** ** * The expression is a bound variable, and this is a reprepare, or ** -** * The sqlite3ValueFromExpr() function is able to extract a value +** * The sqlite3ValueFromExpr() function is able to extract a value ** from the expression (i.e. the expression is a literal value). ** ** Or, if pExpr is a TK_VECTOR, one field is populated for each of the ** vector components that match either of the two latter criteria listed ** above. ** -** Before any value is appended to the record, the affinity of the +** Before any value is appended to the record, the affinity of the ** corresponding column within index pIdx is applied to it. Before ** this function returns, output parameter *pnExtract is set to the ** number of values appended to the record. @@ -71009,9 +79658,9 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue( /* ** Attempt to extract a value from expression pExpr using the methods -** as described for sqlite3Stat4ProbeSetValue() above. +** as described for sqlite3Stat4ProbeSetValue() above. ** -** If successful, set *ppVal to point to a new value object and return +** If successful, set *ppVal to point to a new value object and return ** SQLITE_OK. If no value can be extracted, but no other error occurs ** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error ** does occur, return an SQLite error code. The final value of *ppVal @@ -71031,7 +79680,7 @@ SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr( ** the column value into *ppVal. If *ppVal is initially NULL then a new ** sqlite3_value object is allocated. ** -** If *ppVal is initially NULL then the caller is responsible for +** If *ppVal is initially NULL then the caller is responsible for ** ensuring that the value written into *ppVal is eventually freed. */ SQLITE_PRIVATE int sqlite3Stat4Column( @@ -71041,11 +79690,11 @@ SQLITE_PRIVATE int sqlite3Stat4Column( int iCol, /* Column to extract */ sqlite3_value **ppVal /* OUT: Extracted value */ ){ - u32 t; /* a column type code */ + u32 t = 0; /* a column type code */ int nHdr; /* Size of the header in the record */ int iHdr; /* Next unread header byte */ int iField; /* Next unread data byte */ - int szField; /* Size of the current data field */ + int szField = 0; /* Size of the current data field */ int i; /* Column index */ u8 *a = (u8*)pRec; /* Typecast byte array */ Mem *pMem = *ppVal; /* Write result into this Mem object */ @@ -71082,14 +79731,14 @@ SQLITE_PRIVATE int sqlite3Stat4Column( SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){ if( pRec ){ int i; - int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField; + int nCol = pRec->pKeyInfo->nAllField; Mem *aMem = pRec->aMem; sqlite3 *db = aMem[0].db; for(i=0; ipKeyInfo); - sqlite3DbFree(db, pRec); + sqlite3DbFreeNN(db, pRec); } } #endif /* ifdef SQLITE_ENABLE_STAT4 */ @@ -71113,7 +79762,7 @@ SQLITE_PRIVATE void sqlite3ValueSetStr( SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){ if( !v ) return; sqlite3VdbeMemRelease((Mem *)v); - sqlite3DbFree(((Mem*)v)->db, v); + sqlite3DbFreeNN(((Mem*)v)->db, v); } /* @@ -71155,11 +79804,15 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ ** ************************************************************************* ** This file contains code used for creating, destroying, and populating -** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) +** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) */ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ +/* Forward references */ +static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef); +static void vdbeFreeOpArray(sqlite3 *, Op *, int); + /* ** Create a new virtual database engine. */ @@ -71176,15 +79829,24 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){ p->pNext = db->pVdbe; p->pPrev = 0; db->pVdbe = p; - p->magic = VDBE_MAGIC_INIT; + p->iVdbeMagic = VDBE_MAGIC_INIT; p->pParse = pParse; + pParse->pVdbe = p; assert( pParse->aLabel==0 ); assert( pParse->nLabel==0 ); - assert( pParse->nOpAlloc==0 ); + assert( p->nOpAlloc==0 ); assert( pParse->szOpAlloc==0 ); + sqlite3VdbeAddOp2(p, OP_Init, 0, 1); return p; } +/* +** Return the Parse object that owns a Vdbe object. +*/ +SQLITE_PRIVATE Parse *sqlite3VdbeParser(Vdbe *p){ + return p->pParse; +} + /* ** Change the error string stored in Vdbe.zErrMsg */ @@ -71199,17 +79861,53 @@ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){ /* ** Remember the SQL string for a prepared statement. */ -SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ - assert( isPrepareV2==1 || isPrepareV2==0 ); +SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){ if( p==0 ) return; -#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG) - if( !isPrepareV2 ) return; -#endif + p->prepFlags = prepFlags; + if( (prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){ + p->expmask = 0; + } assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); - p->isPrepareV2 = (u8)isPrepareV2; } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Add a new element to the Vdbe->pDblStr list. +*/ +SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3 *db, Vdbe *p, const char *z){ + if( p ){ + int n = sqlite3Strlen30(z); + DblquoteStr *pStr = sqlite3DbMallocRawNN(db, + sizeof(*pStr)+n+1-sizeof(pStr->z)); + if( pStr ){ + pStr->pNextStr = p->pDblStr; + p->pDblStr = pStr; + memcpy(pStr->z, z, n+1); + } + } +} +#endif + +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** zId of length nId is a double-quoted identifier. Check to see if +** that identifier is really used as a string literal. +*/ +SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString( + Vdbe *pVdbe, /* The prepared statement */ + const char *zId /* The double-quoted identifier, already dequoted */ +){ + DblquoteStr *pStr; + assert( zId!=0 ); + if( pVdbe->pDblStr==0 ) return 0; + for(pStr=pVdbe->pDblStr; pStr; pStr=pStr->pNextStr){ + if( strcmp(zId, pStr->z)==0 ) return 1; + } + return 0; +} +#endif + /* ** Swap all content between two VDBE structures. */ @@ -71229,17 +79927,25 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; - pB->isPrepareV2 = pA->isPrepareV2; +#ifdef SQLITE_ENABLE_NORMALIZE + zTmp = pA->zNormSql; + pA->zNormSql = pB->zNormSql; + pB->zNormSql = zTmp; +#endif + pB->expmask = pA->expmask; + pB->prepFlags = pA->prepFlags; + memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); + pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++; } /* -** Resize the Vdbe.aOp array so that it is at least nOp elements larger +** Resize the Vdbe.aOp array so that it is at least nOp elements larger ** than its current size. nOp is guaranteed to be less than or equal ** to 1024/sizeof(Op). ** ** If an out-of-memory error occurs while resizing the array, return -** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain -** unchanged (this is so that any opcodes already allocated can be +** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain +** unchanged (this is so that any opcodes already allocated can be ** correctly deallocated along with the rest of the Vdbe). */ static int growOpArray(Vdbe *v, int nOp){ @@ -71247,25 +79953,33 @@ static int growOpArray(Vdbe *v, int nOp){ Parse *p = v->pParse; /* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force - ** more frequent reallocs and hence provide more opportunities for + ** more frequent reallocs and hence provide more opportunities for ** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used ** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array ** by the minimum* amount required until the size reaches 512. Normal ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current ** size of the op array or add 1KB of space, whichever is smaller. */ #ifdef SQLITE_TEST_REALLOC_STRESS - int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp); + sqlite3_int64 nNew = (v->nOpAlloc>=512 ? 2*(sqlite3_int64)v->nOpAlloc + : (sqlite3_int64)v->nOpAlloc+nOp); #else - int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); + sqlite3_int64 nNew = (v->nOpAlloc ? 2*(sqlite3_int64)v->nOpAlloc + : (sqlite3_int64)(1024/sizeof(Op))); UNUSED_PARAMETER(nOp); #endif + /* Ensure that the size of a VDBE does not grow too large */ + if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){ + sqlite3OomFault(p->db); + return SQLITE_NOMEM; + } + assert( nOp<=(1024/sizeof(Op)) ); - assert( nNew>=(p->nOpAlloc+nOp) ); + assert( nNew>=(v->nOpAlloc+nOp) ); pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); if( pNew ){ p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew); - p->nOpAlloc = p->szOpAlloc/sizeof(Op); + v->nOpAlloc = p->szOpAlloc/sizeof(Op); v->aOp = pNew; } return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT); @@ -71274,9 +79988,16 @@ static int growOpArray(Vdbe *v, int nOp){ #ifdef SQLITE_DEBUG /* This routine is just a convenient place to set a breakpoint that will ** fire after each opcode is inserted and displayed using -** "PRAGMA vdbe_addoptrace=on". +** "PRAGMA vdbe_addoptrace=on". Parameters "pc" (program counter) and +** pOp are available to make the breakpoint conditional. +** +** Other useful labels for breakpoints include: +** test_trace_breakpoint(pc,pOp) +** sqlite3CorruptError(lineno) +** sqlite3MisuseError(lineno) +** sqlite3CantopenError(lineno) */ -static void test_addop_breakpoint(void){ +static void test_addop_breakpoint(int pc, Op *pOp){ static int n = 0; n++; } @@ -71299,9 +80020,9 @@ static void test_addop_breakpoint(void){ ** operand. */ static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){ - assert( p->pParse->nOpAlloc<=p->nOp ); + assert( p->nOpAlloc<=p->nOp ); if( growOpArray(p, 1) ) return 1; - assert( p->pParse->nOpAlloc>p->nOp ); + assert( p->nOpAlloc>p->nOp ); return sqlite3VdbeAddOp3(p, op, p1, p2, p3); } SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ @@ -71309,13 +80030,15 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ VdbeOp *pOp; i = p->nOp; - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); assert( op>=0 && op<0xff ); - if( p->pParse->nOpAlloc<=i ){ + if( p->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } + assert( p->aOp!=0 ); p->nOp++; pOp = &p->aOp[i]; + assert( pOp!=0 ); pOp->opcode = (u8)op; pOp->p5 = 0; pOp->p1 = p1; @@ -71328,16 +80051,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ - int jj, kk; - Parse *pParse = p->pParse; - for(jj=kk=0; jjnColCache; jj++){ - struct yColCache *x = pParse->aColCache + jj; - printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn); - kk++; - } - if( kk ) printf("\n"); sqlite3VdbePrintOp(0, i, &p->aOp[i]); - test_addop_breakpoint(); + test_addop_breakpoint(i, &p->aOp[i]); } #endif #ifdef VDBE_PROFILE @@ -71379,6 +80094,9 @@ SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){ ** "s" character in zTypes[], the register is a string if the argument is ** not NULL, or OP_Null if the value is a null pointer. For each "i" character ** in zTypes[], the register is initialized to an integer. +** +** If the input string does not end with "X" then an OP_ResultRow instruction +** is generated for the values inserted. */ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){ va_list ap; @@ -71388,12 +80106,15 @@ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, for(i=0; (c = zTypes[i])!=0; i++){ if( c=='s' ){ const char *z = va_arg(ap, const char*); - sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0); + sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest+i, 0, z, 0); + }else if( c=='i' ){ + sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest+i); }else{ - assert( c=='i' ); - sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++); + goto skip_op_resultrow; } } + sqlite3VdbeAddOp2(p, OP_ResultRow, iDest, i); +skip_op_resultrow: va_end(ap); } @@ -71414,6 +80135,49 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4( return addr; } +/* +** Add an OP_Function or OP_PureFunc opcode. +** +** The eCallCtx argument is information (typically taken from Expr.op2) +** that describes the calling context of the function. 0 means a general +** function call. NC_IsCheck means called by a check constraint, +** NC_IdxExpr means called as part of an index expression. NC_PartIdx +** means in the WHERE clause of a partial index. NC_GenCol means called +** while computing a generated column value. 0 is the usual case. +*/ +SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall( + Parse *pParse, /* Parsing context */ + int p1, /* Constant argument mask */ + int p2, /* First argument register */ + int p3, /* Register into which results are written */ + int nArg, /* Number of argument */ + const FuncDef *pFunc, /* The function to be invoked */ + int eCallCtx /* Calling context */ +){ + Vdbe *v = pParse->pVdbe; + int nByte; + int addr; + sqlite3_context *pCtx; + assert( v ); + nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*); + pCtx = sqlite3DbMallocRawNN(pParse->db, nByte); + if( pCtx==0 ){ + assert( pParse->db->mallocFailed ); + freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); + return 0; + } + pCtx->pOut = 0; + pCtx->pFunc = (FuncDef*)pFunc; + pCtx->pVdbe = 0; + pCtx->isError = 0; + pCtx->argc = nArg; + pCtx->iOp = sqlite3VdbeCurrentAddr(v); + addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function, + p1, p2, p3, (char*)pCtx, P4_FUNCCTX); + sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef); + return addr; +} + /* ** Add an opcode that includes the p4 value with a P4_INT64 or ** P4_REAL type. @@ -71432,6 +80196,69 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); } +#ifndef SQLITE_OMIT_EXPLAIN +/* +** Return the address of the current EXPLAIN QUERY PLAN baseline. +** 0 means "none". +*/ +SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse *pParse){ + VdbeOp *pOp; + if( pParse->addrExplain==0 ) return 0; + pOp = sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrExplain); + return pOp->p2; +} + +/* +** Set a debugger breakpoint on the following routine in order to +** monitor the EXPLAIN QUERY PLAN code generation. +*/ +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){ + (void)z1; + (void)z2; +} +#endif + +/* +** Add a new OP_Explain opcode. +** +** If the bPush flag is true, then make this opcode the parent for +** subsequent Explains until sqlite3VdbeExplainPop() is called. +*/ +SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ +#ifndef SQLITE_DEBUG + /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined. + ** But omit them (for performance) during production builds */ + if( pParse->explain==2 ) +#endif + { + char *zMsg; + Vdbe *v; + va_list ap; + int iThis; + va_start(ap, zFmt); + zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap); + va_end(ap); + v = pParse->pVdbe; + iThis = v->nOp; + sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, + zMsg, P4_DYNAMIC); + sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z); + if( bPush){ + pParse->addrExplain = iThis; + } + } +} + +/* +** Pop the EXPLAIN QUERY PLAN stack one level. +*/ +SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse *pParse){ + sqlite3ExplainBreakpoint("POP", 0); + pParse->addrExplain = sqlite3VdbeExplainParent(pParse); +} +#endif /* SQLITE_OMIT_EXPLAIN */ + /* ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees @@ -71440,10 +80267,12 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8( ** The zWhere string must have been obtained from sqlite3_malloc(). ** This routine will take ownership of the allocated memory. */ -SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){ +SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){ int j; sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); + sqlite3VdbeChangeP5(p, p5); for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j); + sqlite3MayAbort(p->pParse); } /* @@ -71492,21 +80321,22 @@ SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){ ** The VDBE knows that a P2 value is a label because labels are ** always negative and P2 values are suppose to be non-negative. ** Hence, a negative P2 value is a label that has yet to be resolved. +** (Later:) This is only true for opcodes that have the OPFLG_JUMP +** property. +** +** Variable usage notes: ** -** Zero is returned if a malloc() fails. +** Parse.aLabel[x] Stores the address that the x-th label resolves +** into. For testing (SQLITE_DEBUG), unresolved +** labels stores -1, but that is not required. +** Parse.nLabelAlloc Number of slots allocated to Parse.aLabel[] +** Parse.nLabel The *negative* of the number of labels that have +** been issued. The negative is stored because +** that gives a performance improvement over storing +** the equivalent positive value. */ -SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){ - Parse *p = v->pParse; - int i = p->nLabel++; - assert( v->magic==VDBE_MAGIC_INIT ); - if( (i & (i-1))==0 ){ - p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, - (i*2+1)*sizeof(p->aLabel[0])); - } - if( p->aLabel ){ - p->aLabel[i] = -1; - } - return ADDR(i); +SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse *pParse){ + return --pParse->nLabel; } /* @@ -71514,13 +80344,36 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){ ** be inserted. The parameter "x" must have been obtained from ** a prior call to sqlite3VdbeMakeLabel(). */ +static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){ + int nNewSize = 10 - p->nLabel; + p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, + nNewSize*sizeof(p->aLabel[0])); + if( p->aLabel==0 ){ + p->nLabelAlloc = 0; + }else{ +#ifdef SQLITE_DEBUG + int i; + for(i=p->nLabelAlloc; iaLabel[i] = -1; +#endif + p->nLabelAlloc = nNewSize; + p->aLabel[j] = v->nOp; + } +} SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ Parse *p = v->pParse; int j = ADDR(x); - assert( v->magic==VDBE_MAGIC_INIT ); - assert( jnLabel ); + assert( v->iVdbeMagic==VDBE_MAGIC_INIT ); + assert( j<-p->nLabel ); assert( j>=0 ); - if( p->aLabel ){ +#ifdef SQLITE_DEBUG + if( p->db->flags & SQLITE_VdbeAddopTrace ){ + printf("RESOLVE LABEL %d to %d\n", x, v->nOp); + } +#endif + if( p->nLabelAlloc + p->nLabel < 0 ){ + resizeResolveLabel(p,v,j); + }else{ + assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */ p->aLabel[j] = v->nOp; } } @@ -71543,19 +80396,19 @@ SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){ /* ** The following type and function are used to iterate through all opcodes -** in a Vdbe main program and each of the sub-programs (triggers) it may +** in a Vdbe main program and each of the sub-programs (triggers) it may ** invoke directly or indirectly. It should be used as follows: ** ** Op *pOp; ** VdbeOpIter sIter; ** ** memset(&sIter, 0, sizeof(sIter)); -** sIter.v = v; // v is of type Vdbe* +** sIter.v = v; // v is of type Vdbe* ** while( (pOp = opIterNext(&sIter)) ){ ** // Do something with pOp ** } ** sqlite3DbFree(v->db, sIter.apSub); -** +** */ typedef struct VdbeOpIter VdbeOpIter; struct VdbeOpIter { @@ -71588,7 +80441,7 @@ static Op *opIterNext(VdbeOpIter *p){ p->iSub++; p->iAddr = 0; } - + if( pRet->p4type==P4_SUBPROGRAM ){ int nByte = (p->nSub+1)*sizeof(SubProgram*); int j; @@ -71619,9 +80472,11 @@ static Op *opIterNext(VdbeOpIter *p){ ** * OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort. ** * OP_Destroy ** * OP_VUpdate +** * OP_VCreate ** * OP_VRename ** * OP_FkCounter with P2==0 (immediate foreign key constraint) -** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...) +** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine +** (for CREATE TABLE AS SELECT ...) ** ** Then check that the value of Parse.mayAbort is true if an ** ABORT may be thrown, or false otherwise. Return true if it does @@ -71634,6 +80489,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; int hasFkCounter = 0; int hasCreateTable = 0; + int hasCreateIndex = 0; int hasInitCoroutine = 0; Op *pOp; VdbeOpIter sIter; @@ -71642,14 +80498,25 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; - if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename - || ((opcode==OP_Halt || opcode==OP_HaltIfNull) - && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort)) + if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename + || opcode==OP_VDestroy + || opcode==OP_VCreate + || opcode==OP_ParseSchema + || ((opcode==OP_Halt || opcode==OP_HaltIfNull) + && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } - if( opcode==OP_CreateTable ) hasCreateTable = 1; + if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; + if( mayAbort ){ + /* hasCreateIndex may also be set for some DELETE statements that use + ** OP_Clear. So this routine may end up returning true in the case + ** where a "DELETE FROM tbl" has a statement-journal but does not + ** require one. This is not so bad - it is an inefficiency, not a bug. */ + if( opcode==OP_CreateBtree && pOp->p3==BTREE_BLOBKEY ) hasCreateIndex = 1; + if( opcode==OP_Clear ) hasCreateIndex = 1; + } if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; #ifndef SQLITE_OMIT_FOREIGN_KEY if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ @@ -71665,10 +80532,37 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ ** true for this case to prevent the assert() in the callers frame ** from failing. */ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter - || (hasCreateTable && hasInitCoroutine) ); + || (hasCreateTable && hasInitCoroutine) || hasCreateIndex + ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ +#ifdef SQLITE_DEBUG +/* +** Increment the nWrite counter in the VDBE if the cursor is not an +** ephemeral cursor, or if the cursor argument is NULL. +*/ +SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe *p, VdbeCursor *pC){ + if( pC==0 + || (pC->eCurType!=CURTYPE_SORTER + && pC->eCurType!=CURTYPE_PSEUDO + && !pC->isEphemeral) + ){ + p->nWrite++; + } +} +#endif + +#ifdef SQLITE_DEBUG +/* +** Assert if an Abort at this point in time might result in a corrupt +** database. +*/ +SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){ + assert( p->nWrite==0 || p->usesStmtJournal ); +} +#endif + /* ** This routine is called after all opcodes have been inserted. It loops ** through all the opcodes and fixes up some details. @@ -71712,7 +80606,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ switch( pOp->opcode ){ case OP_Transaction: { if( pOp->p2!=0 ) p->readOnly = 0; - /* fall thru */ + /* no break */ deliberate_fall_through } case OP_AutoCommit: case OP_Savepoint: { @@ -71728,6 +80622,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ p->bIsReader = 1; break; } + case OP_Next: + case OP_SorterNext: { + pOp->p4.xAdvance = sqlite3BtreeNext; + pOp->p4type = P4_ADVANCE; + /* The code generator never codes any of these opcodes as a jump + ** to a label. They are always coded as a jump backwards to a + ** known address */ + assert( pOp->p2>=0 ); + break; + } + case OP_Prev: { + pOp->p4.xAdvance = sqlite3BtreePrevious; + pOp->p4type = P4_ADVANCE; + /* The code generator never codes any of these opcodes as a jump + ** to a label. They are always coded as a jump backwards to a + ** known address */ + assert( pOp->p2>=0 ); + break; + } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; @@ -71739,27 +80652,26 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ assert( pOp[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; - break; + /* Fall through into the default case */ + /* no break */ deliberate_fall_through } #endif - case OP_Next: - case OP_NextIfOpen: - case OP_SorterNext: { - pOp->p4.xAdvance = sqlite3BtreeNext; - pOp->p4type = P4_ADVANCE; - break; - } - case OP_Prev: - case OP_PrevIfOpen: { - pOp->p4.xAdvance = sqlite3BtreePrevious; - pOp->p4type = P4_ADVANCE; + default: { + if( pOp->p2<0 ){ + /* The mkopcodeh.tcl script has so arranged things that the only + ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to + ** have non-negative values for P2. */ + assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ); + assert( ADDR(pOp->p2)<-pParse->nLabel ); + pOp->p2 = aLabel[ADDR(pOp->p2)]; + } break; } } - if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){ - assert( ADDR(pOp->p2)nLabel ); - pOp->p2 = aLabel[ADDR(pOp->p2)]; - } + /* The mkopcodeh.tcl script has so arranged things that the only + ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to + ** have non-negative values for P2. */ + assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0); } if( pOp==p->aOp ) break; pOp--; @@ -71775,7 +80687,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ ** Return the address of the next instruction to be inserted. */ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); return p->nOp; } @@ -71789,7 +80701,7 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){ */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){ - assert( p->nOp + N <= p->pParse->nOpAlloc ); + assert( p->nOp + N <= p->nOpAlloc ); } #endif @@ -71809,15 +80721,26 @@ SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){ } #endif +/* +** Generate code (a single OP_Abortable opcode) that will +** verify that the VDBE program can safely call Abort in the current +** context. +*/ +#if defined(SQLITE_DEBUG) +SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int onError){ + if( onError==OE_Abort ) sqlite3VdbeAddOp0(p, OP_Abortable); +} +#endif + /* ** This function returns a pointer to the array of opcodes associated with ** the Vdbe passed as the first argument. It is the callers responsibility -** to arrange for the returned array to be eventually freed using the +** to arrange for the returned array to be eventually freed using the ** vdbeFreeOpArray() function. ** ** Before returning, *pnOp is set to the number of entries in the returned -** array. Also, *pnMaxArg is set to the larger of its current value and -** the number of entries in the Vdbe.apArg[] array required to execute the +** array. Also, *pnMaxArg is set to the larger of its current value and +** the number of entries in the Vdbe.apArg[] array required to execute the ** returned program. */ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){ @@ -71849,8 +80772,8 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList( int i; VdbeOp *pOut, *pFirst; assert( nOp>0 ); - assert( p->magic==VDBE_MAGIC_INIT ); - if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){ + assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); + if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){ return 0; } pFirst = pOut = &p->aOp[p->nOp]; @@ -71891,12 +80814,12 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList( SQLITE_PRIVATE void sqlite3VdbeScanStatus( Vdbe *p, /* VM to add scanstatus() to */ int addrExplain, /* Address of OP_Explain (or 0) */ - int addrLoop, /* Address of loop counter */ + int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ - int nByte = (p->nScan+1) * sizeof(ScanStatus); + sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ @@ -71916,16 +80839,16 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus( ** Change the value of the opcode, or P1, P2, P3, or P5 operands ** for a specific instruction. */ -SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){ +SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){ sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode; } -SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){ +SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){ sqlite3VdbeGetOp(p,addr)->p1 = val; } -SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){ +SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){ sqlite3VdbeGetOp(p,addr)->p2 = val; } -SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){ +SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){ sqlite3VdbeGetOp(p,addr)->p3 = val; } SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){ @@ -71941,6 +80864,34 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ sqlite3VdbeChangeP2(p, addr, p->nOp); } +/* +** Change the P2 operand of the jump instruction at addr so that +** the jump lands on the next opcode. Or if the jump instruction was +** the previous opcode (and is thus a no-op) then simply back up +** the next instruction counter by one slot so that the jump is +** overwritten by the next inserted opcode. +** +** This routine is an optimization of sqlite3VdbeJumpHere() that +** strives to omit useless byte-code like this: +** +** 7 Once 0 8 0 +** 8 ... +*/ +SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){ + if( addr==p->nOp-1 ){ + assert( p->aOp[addr].opcode==OP_Once + || p->aOp[addr].opcode==OP_If + || p->aOp[addr].opcode==OP_FkIfZero ); + assert( p->aOp[addr].p4type==0 ); +#ifdef SQLITE_VDBE_COVERAGE + sqlite3VdbeGetOp(p,-1)->iSrcLine = 0; /* Erase VdbeCoverage() macros */ +#endif + p->nOp--; + }else{ + sqlite3VdbeChangeP2(p, addr, p->nOp); + } +} + /* ** If the input FuncDef structure is ephemeral, then free it. If @@ -71948,22 +80899,20 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){ */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ - sqlite3DbFree(db, pDef); + sqlite3DbFreeNN(db, pDef); } } -static void vdbeFreeOpArray(sqlite3 *, Op *, int); - /* ** Delete a P4 value if necessary. */ static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ freeEphemeralFunction(db, p->pFunc); - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } static void freeP4(sqlite3 *db, int p4type, void *p4){ assert( db ); @@ -71975,6 +80924,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ case P4_REAL: case P4_INT64: case P4_DYNAMIC: + case P4_DYNBLOB: case P4_INTARRAY: { sqlite3DbFree(db, p4); break; @@ -72010,20 +80960,20 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ /* ** Free the space allocated for aOp and any p4 values allocated for the -** opcodes contained within. If aOp is not NULL it is assumed to contain -** nOp entries. +** opcodes contained within. If aOp is not NULL it is assumed to contain +** nOp entries. */ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ if( aOp ){ Op *pOp; - for(pOp=aOp; pOp<&aOp[nOp]; pOp++){ - if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p); + for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){ + if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS sqlite3DbFree(db, pOp->zComment); -#endif +#endif } + sqlite3DbFreeNN(db, aOp); } - sqlite3DbFree(db, aOp); } /* @@ -72036,6 +80986,13 @@ SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){ pVdbe->pProgram = p; } +/* +** Return true if the given Vdbe has any SubPrograms. +*/ +SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe *pVdbe){ + return pVdbe->pProgram!=0; +} + /* ** Change the opcode at addr into OP_Noop */ @@ -72063,6 +81020,41 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ } } +#ifdef SQLITE_DEBUG +/* +** Generate an OP_ReleaseReg opcode to indicate that a range of +** registers, except any identified by mask, are no longer in use. +*/ +SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters( + Parse *pParse, /* Parsing context */ + int iFirst, /* Index of first register to be released */ + int N, /* Number of registers to release */ + u32 mask, /* Mask of registers to NOT release */ + int bUndefine /* If true, mark registers as undefined */ +){ + if( N==0 ) return; + assert( pParse->pVdbe ); + assert( iFirst>=1 ); + assert( iFirst+N-1<=pParse->nMem ); + if( N<=31 && mask!=0 ){ + while( N>0 && (mask&1)!=0 ){ + mask >>= 1; + iFirst++; + N--; + } + while( N>0 && N<=32 && (mask & MASKBIT32(N-1))!=0 ){ + mask &= ~MASKBIT32(N-1); + N--; + } + } + if( N>0 ){ + sqlite3VdbeAddOp3(pParse->pVdbe, OP_ReleaseReg, iFirst, N, *(int*)&mask); + if( bUndefine ) sqlite3VdbeChangeP5(pParse->pVdbe, 1); + } +} +#endif /* SQLITE_DEBUG */ + + /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a @@ -72073,7 +81065,7 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ ** the string is made into memory obtained from sqlite3_malloc(). ** A value of n==0 means copy bytes of zP4 up to and including the ** first null byte. If n>0 then copy n+1 bytes of zP4. -** +** ** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points ** to a string or structure that is guaranteed to exist for the lifetime of ** the Vdbe. In these cases we can just copy the pointer. @@ -72104,7 +81096,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int sqlite3 *db; assert( p!=0 ); db = p->db; - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); assert( p->aOp!=0 || db->mallocFailed ); if( db->mallocFailed ){ if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4); @@ -72134,7 +81126,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int } /* -** Change the P4 operand of the most recently coded instruction +** Change the P4 operand of the most recently coded instruction ** to the value defined by the arguments. This is a high-speed ** version of sqlite3VdbeChangeP4(). ** @@ -72180,7 +81172,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){ */ static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ assert( p->nOp>0 || p->aOp==0 ); - assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); + assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->pParse->nErr>0 ); if( p->nOp ){ assert( p->aOp ); sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment); @@ -72223,7 +81215,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ ** routine, then a pointer to a dummy VdbeOp will be returned. That opcode ** is readable but not writable, though it is cast to a writable value. ** The return of a dummy opcode allows the call to continue functioning -** after an OOM fault without having to check to see if the return from +** after an OOM fault without having to check to see if the return from ** this routine is a valid pointer. But because the dummy.opcode is 0, ** dummy will never be written to. This is verified by code inspection and ** by running with Valgrind. @@ -72232,7 +81224,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ /* C89 specifies that the constant "dummy" will be initialized to all ** zeros, which is correct. MSVC generates a warning, nevertheless. */ static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */ - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); if( addr<0 ){ addr = p->nOp - 1; } @@ -72270,78 +81262,87 @@ static int translateP(char c, const Op *pOp){ ** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0 ** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x */ -static int displayComment( +SQLITE_PRIVATE char *sqlite3VdbeDisplayComment( + sqlite3 *db, /* Optional - Oom error reporting only */ const Op *pOp, /* The opcode to be commented */ - const char *zP4, /* Previously obtained value for P4 */ - char *zTemp, /* Write result here */ - int nTemp /* Space available in zTemp[] */ + const char *zP4 /* Previously obtained value for P4 */ ){ const char *zOpName; const char *zSynopsis; int nOpName; - int ii, jj; + int ii; char zAlt[50]; + StrAccum x; + + sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH); zOpName = sqlite3OpcodeName(pOp->opcode); nOpName = sqlite3Strlen30(zOpName); if( zOpName[nOpName+1] ){ int seenCom = 0; char c; - zSynopsis = zOpName += nOpName + 1; + zSynopsis = zOpName + nOpName + 1; if( strncmp(zSynopsis,"IF ",3)==0 ){ - if( pOp->p5 & SQLITE_STOREP2 ){ - sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3); - }else{ - sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); - } + sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); zSynopsis = zAlt; } - for(ii=jj=0; jjzComment); + sqlite3_str_appendall(&x, pOp->zComment); seenCom = 1; }else{ int v1 = translateP(c, pOp); int v2; - sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1); if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){ ii += 3; - jj += sqlite3Strlen30(zTemp+jj); v2 = translateP(zSynopsis[ii], pOp); if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){ ii += 2; v2++; } - if( v2>1 ){ - sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1); + if( v2<2 ){ + sqlite3_str_appendf(&x, "%d", v1); + }else{ + sqlite3_str_appendf(&x, "%d..%d", v1, v1+v2-1); + } + }else if( strncmp(zSynopsis+ii+1, "@NP", 3)==0 ){ + sqlite3_context *pCtx = pOp->p4.pCtx; + if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){ + sqlite3_str_appendf(&x, "%d", v1); + }else if( pCtx->argc>1 ){ + sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1); + }else if( x.accError==0 ){ + assert( x.nChar>2 ); + x.nChar -= 2; + ii++; + } + ii += 3; + }else{ + sqlite3_str_appendf(&x, "%d", v1); + if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){ + ii += 4; } - }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){ - ii += 4; } } - jj += sqlite3Strlen30(zTemp+jj); }else{ - zTemp[jj++] = c; + sqlite3_str_appendchar(&x, 1, c); } } - if( !seenCom && jjzComment ){ - sqlite3_snprintf(nTemp-jj, zTemp+jj, "; %s", pOp->zComment); - jj += sqlite3Strlen30(zTemp+jj); + if( !seenCom && pOp->zComment ){ + sqlite3_str_appendf(&x, "; %s", pOp->zComment); } - if( jjzComment ){ - sqlite3_snprintf(nTemp, zTemp, "%s", pOp->zComment); - jj = sqlite3Strlen30(zTemp); - }else{ - zTemp[0] = 0; - jj = 0; + sqlite3_str_appendall(&x, pOp->zComment); + } + if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){ + sqlite3OomFault(db); } - return jj; + return sqlite3StrAccumFinish(&x); } -#endif /* SQLITE_DEBUG */ +#endif /* SQLITE_ENABLE_EXPLAIN_COMMENTS */ #if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) /* @@ -72352,23 +81353,24 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){ const char *zOp = 0; switch( pExpr->op ){ case TK_STRING: - sqlite3XPrintf(p, "%Q", pExpr->u.zToken); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + sqlite3_str_appendf(p, "%Q", pExpr->u.zToken); break; case TK_INTEGER: - sqlite3XPrintf(p, "%d", pExpr->u.iValue); + sqlite3_str_appendf(p, "%d", pExpr->u.iValue); break; case TK_NULL: - sqlite3XPrintf(p, "NULL"); + sqlite3_str_appendf(p, "NULL"); break; case TK_REGISTER: { - sqlite3XPrintf(p, "r[%d]", pExpr->iTable); + sqlite3_str_appendf(p, "r[%d]", pExpr->iTable); break; } case TK_COLUMN: { if( pExpr->iColumn<0 ){ - sqlite3XPrintf(p, "rowid"); + sqlite3_str_appendf(p, "rowid"); }else{ - sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn); + sqlite3_str_appendf(p, "c%d", (int)pExpr->iColumn); } break; } @@ -72400,18 +81402,18 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){ case TK_NOTNULL: zOp = "NOTNULL"; break; default: - sqlite3XPrintf(p, "%s", "expr"); + sqlite3_str_appendf(p, "%s", "expr"); break; } if( zOp ){ - sqlite3XPrintf(p, "%s(", zOp); + sqlite3_str_appendf(p, "%s(", zOp); displayP4Expr(p, pExpr->pLeft); if( pExpr->pRight ){ - sqlite3StrAccumAppend(p, ",", 1); + sqlite3_str_append(p, ",", 1); displayP4Expr(p, pExpr->pRight); } - sqlite3StrAccumAppend(p, ")", 1); + sqlite3_str_append(p, ")", 1); } } #endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */ @@ -72422,24 +81424,27 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){ ** Compute a string that describes the P4 parameter for an opcode. ** Use zTemp for any required temporary buffer space. */ -static char *displayP4(Op *pOp, char *zTemp, int nTemp){ - char *zP4 = zTemp; +SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ + char *zP4 = 0; StrAccum x; - assert( nTemp>=20 ); - sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0); + + sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH); switch( pOp->p4type ){ case P4_KEYINFO: { int j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; - assert( pKeyInfo->aSortOrder!=0 ); - sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField); - for(j=0; jnField; j++){ + assert( pKeyInfo->aSortFlags!=0 ); + sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField); + for(j=0; jnKeyField; j++){ CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : ""; if( strcmp(zColl, "BINARY")==0 ) zColl = "B"; - sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl); + sqlite3_str_appendf(&x, ",%s%s%s", + (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "", + (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "", + zColl); } - sqlite3StrAccumAppend(&x, ")", 1); + sqlite3_str_append(&x, ")", 1); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS @@ -72449,42 +81454,43 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ } #endif case P4_COLLSEQ: { + static const char *const encnames[] = {"?", "8", "16LE", "16BE"}; CollSeq *pColl = pOp->p4.pColl; - sqlite3XPrintf(&x, "(%.20s)", pColl->zName); + assert( pColl->enc<4 ); + sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName, + encnames[pColl->enc]); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; - sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); + sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } -#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) case P4_FUNCCTX: { FuncDef *pDef = pOp->p4.pCtx->pFunc; - sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg); + sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } -#endif case P4_INT64: { - sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64); + sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64); break; } case P4_INT32: { - sqlite3XPrintf(&x, "%d", pOp->p4.i); + sqlite3_str_appendf(&x, "%d", pOp->p4.i); break; } case P4_REAL: { - sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal); + sqlite3_str_appendf(&x, "%.16g", *pOp->p4.pReal); break; } case P4_MEM: { Mem *pMem = pOp->p4.pMem; if( pMem->flags & MEM_Str ){ zP4 = pMem->z; - }else if( pMem->flags & MEM_Int ){ - sqlite3XPrintf(&x, "%lld", pMem->u.i); + }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + sqlite3_str_appendf(&x, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ - sqlite3XPrintf(&x, "%.16g", pMem->u.r); + sqlite3_str_appendf(&x, "%.16g", pMem->u.r); }else if( pMem->flags & MEM_Null ){ zP4 = "NULL"; }else{ @@ -72496,45 +81502,42 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; - sqlite3XPrintf(&x, "vtab:%p", pVtab); + sqlite3_str_appendf(&x, "vtab:%p", pVtab); break; } #endif case P4_INTARRAY: { - int i; - int *ai = pOp->p4.ai; - int n = ai[0]; /* The first element of an INTARRAY is always the + u32 i; + u32 *ai = pOp->p4.ai; + u32 n = ai[0]; /* The first element of an INTARRAY is always the ** count of the number of elements to follow */ - for(i=1; ip4.pTab->zName); + zP4 = pOp->p4.pTab->zName; break; } default: { zP4 = pOp->p4.z; - if( zP4==0 ){ - zP4 = zTemp; - zTemp[0] = 0; - } } } - sqlite3StrAccumFinish(&x); - assert( zP4!=0 ); - return zP4; + if( zP4 ) sqlite3_str_appendall(&x, zP4); + if( (x.accError & SQLITE_NOMEM)!=0 ){ + sqlite3OomFault(db); + } + return sqlite3StrAccumFinish(&x); } #endif /* VDBE_DISPLAY_P4 */ @@ -72565,13 +81568,13 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){ ** ** If SQLite is not threadsafe but does support shared-cache mode, then ** sqlite3BtreeEnter() is invoked to set the BtShared.db variables -** of all of BtShared structures accessible via the database handle +** of all of BtShared structures accessible via the database handle ** associated with the VM. ** ** If SQLite is not threadsafe and does not support shared-cache mode, this ** function is a no-op. ** -** The p->btreeMask field is a bitmask of all btrees that the prepared +** The p->btreeMask field is a bitmask of all btrees that the prepared ** statement p will ever use. Let N be the number of bits in p->btreeMask ** corresponding to btrees that use shared cache. Then the runtime of ** this routine is N*N. But as N is rarely more than 1, this should not @@ -72622,26 +81625,32 @@ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){ /* ** Print a single opcode. This routine is used for debugging only. */ -SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ +SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){ char *zP4; - char zPtr[50]; - char zCom[100]; + char *zCom; + sqlite3 dummyDb; static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n"; if( pOut==0 ) pOut = stdout; - zP4 = displayP4(pOp, zPtr, sizeof(zPtr)); + sqlite3BeginBenignMalloc(); + dummyDb.mallocFailed = 1; + zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS - displayComment(pOp, zP4, zCom, sizeof(zCom)); + zCom = sqlite3VdbeDisplayComment(0, pOp, zP4); #else - zCom[0] = 0; + zCom = 0; #endif /* NB: The sqlite3OpcodeName() function is implemented by code created ** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the ** information from the vdbe.c source text */ - fprintf(pOut, zFormat1, pc, - sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5, - zCom + fprintf(pOut, zFormat1, pc, + sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, + zP4 ? zP4 : "", pOp->p5, + zCom ? zCom : "" ); fflush(pOut); + sqlite3_free(zP4); + sqlite3_free(zCom); + sqlite3EndBenignMalloc(); } #endif @@ -72678,25 +81687,24 @@ static void releaseMemArray(Mem *p, int N){ assert( sqlite3VdbeCheckMemInvariants(p) ); /* This block is really an inlined version of sqlite3VdbeMemRelease() - ** that takes advantage of the fact that the memory cell value is + ** that takes advantage of the fact that the memory cell value is ** being set to NULL after releasing any dynamic resources. ** - ** The justification for duplicating code is that according to - ** callgrind, this causes a certain test case to hit the CPU 4.7 - ** percent less (x86 linux, gcc version 4.1.2, -O6) than if + ** The justification for duplicating code is that according to + ** callgrind, this causes a certain test case to hit the CPU 4.7 + ** percent less (x86 linux, gcc version 4.1.2, -O6) than if ** sqlite3MemRelease() were called from here. With -O2, this jumps - ** to 6.6 percent. The test case is inserting 1000 rows into a table - ** with no indexes using a single prepared INSERT statement, bind() + ** to 6.6 percent. The test case is inserting 1000 rows into a table + ** with no indexes using a single prepared INSERT statement, bind() ** and reset(). Inserts are grouped into a transaction. */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); - testcase( p->flags & MEM_Frame ); - testcase( p->flags & MEM_RowSet ); - if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ + if( p->flags&(MEM_Agg|MEM_Dyn) ){ + testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel ); sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ - sqlite3DbFree(db, p->zMalloc); + sqlite3DbFreeNN(db, p->zMalloc); p->szMalloc = 0; } @@ -72705,6 +81713,150 @@ static void releaseMemArray(Mem *p, int N){ } } +#ifdef SQLITE_DEBUG +/* +** Verify that pFrame is a valid VdbeFrame pointer. Return true if it is +** and false if something is wrong. +** +** This routine is intended for use inside of assert() statements only. +*/ +SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame *pFrame){ + if( pFrame->iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0; + return 1; +} +#endif + + +/* +** This is a destructor on a Mem object (which is really an sqlite3_value) +** that deletes the Frame object that is attached to it as a blob. +** +** This routine does not delete the Frame right away. It merely adds the +** frame to a list of frames to be deleted when the Vdbe halts. +*/ +SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void *pArg){ + VdbeFrame *pFrame = (VdbeFrame*)pArg; + assert( sqlite3VdbeFrameIsValid(pFrame) ); + pFrame->pParent = pFrame->v->pDelFrame; + pFrame->v->pDelFrame = pFrame; +} + +#if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN) +/* +** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN +** QUERY PLAN output. +** +** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no +** more opcodes to be displayed. +*/ +SQLITE_PRIVATE int sqlite3VdbeNextOpcode( + Vdbe *p, /* The statement being explained */ + Mem *pSub, /* Storage for keeping track of subprogram nesting */ + int eMode, /* 0: normal. 1: EQP. 2: TablesUsed */ + int *piPc, /* IN/OUT: Current rowid. Overwritten with next rowid */ + int *piAddr, /* OUT: Write index into (*paOp)[] here */ + Op **paOp /* OUT: Write the opcode array here */ +){ + int nRow; /* Stop when row count reaches this */ + int nSub = 0; /* Number of sub-vdbes seen so far */ + SubProgram **apSub = 0; /* Array of sub-vdbes */ + int i; /* Next instruction address */ + int rc = SQLITE_OK; /* Result code */ + Op *aOp = 0; /* Opcode array */ + int iPc; /* Rowid. Copy of value in *piPc */ + + /* When the number of output rows reaches nRow, that means the + ** listing has finished and sqlite3_step() should return SQLITE_DONE. + ** nRow is the sum of the number of rows in the main program, plus + ** the sum of the number of rows in all trigger subprograms encountered + ** so far. The nRow value will increase as new trigger subprograms are + ** encountered, but p->pc will eventually catch up to nRow. + */ + nRow = p->nOp; + if( pSub!=0 ){ + if( pSub->flags&MEM_Blob ){ + /* pSub is initiallly NULL. It is initialized to a BLOB by + ** the P4_SUBPROGRAM processing logic below */ + nSub = pSub->n/sizeof(Vdbe*); + apSub = (SubProgram **)pSub->z; + } + for(i=0; inOp; + } + } + iPc = *piPc; + while(1){ /* Loop exits via break */ + i = iPc++; + if( i>=nRow ){ + p->rc = SQLITE_OK; + rc = SQLITE_DONE; + break; + } + if( inOp ){ + /* The rowid is small enough that we are still in the + ** main program. */ + aOp = p->aOp; + }else{ + /* We are currently listing subprograms. Figure out which one and + ** pick up the appropriate opcode. */ + int j; + i -= p->nOp; + assert( apSub!=0 ); + assert( nSub>0 ); + for(j=0; i>=apSub[j]->nOp; j++){ + i -= apSub[j]->nOp; + assert( inOp || j+1aOp; + } + + /* When an OP_Program opcode is encounter (the only opcode that has + ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms + ** kept in p->aMem[9].z to hold the new program - assuming this subprogram + ** has not already been seen. + */ + if( pSub!=0 && aOp[i].p4type==P4_SUBPROGRAM ){ + int nByte = (nSub+1)*sizeof(SubProgram*); + int j; + for(j=0; jrc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0); + if( p->rc!=SQLITE_OK ){ + rc = SQLITE_ERROR; + break; + } + apSub = (SubProgram **)pSub->z; + apSub[nSub++] = aOp[i].p4.pProgram; + MemSetTypeFlag(pSub, MEM_Blob); + pSub->n = nSub*sizeof(SubProgram*); + nRow += aOp[i].p4.pProgram->nOp; + } + } + if( eMode==0 ) break; +#ifdef SQLITE_ENABLE_BYTECODE_VTAB + if( eMode==2 ){ + Op *pOp = aOp + i; + if( pOp->opcode==OP_OpenRead ) break; + if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break; + if( pOp->opcode==OP_ReopenIdx ) break; + }else +#endif + { + assert( eMode==1 ); + if( aOp[i].opcode==OP_Explain ) break; + if( aOp[i].opcode==OP_Init && iPc>1 ) break; + } + } + *piPc = iPc; + *piAddr = i; + *paOp = aOp; + return rc; +} +#endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */ + + /* ** Delete a VdbeFrame object and its contents. VdbeFrame objects are ** allocated by the OP_Program opcode in sqlite3VdbeExec(). @@ -72713,6 +81865,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){ int i; Mem *aMem = VdbeFrameMem(p); VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem]; + assert( sqlite3VdbeFrameIsValid(p) ); for(i=0; inChildCsr; i++){ sqlite3VdbeFreeCursor(p->v, apCsr[i]); } @@ -72733,6 +81886,9 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){ ** p->explain==2, only OP_Explain instructions are listed and these ** are shown in a different format. p->explain==2 is used to implement ** EXPLAIN QUERY PLAN. +** 2018-04-24: In p->explain==2 mode, the OP_Init opcodes of triggers +** are also shown, so that the boundaries between the main program and +** each trigger are clear. ** ** When p->explain==1, first the main program is listed, then each of ** the trigger subprograms are listed one by one. @@ -72740,17 +81896,17 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){ SQLITE_PRIVATE int sqlite3VdbeList( Vdbe *p /* The VDBE */ ){ - int nRow; /* Stop when row count reaches this */ - int nSub = 0; /* Number of sub-vdbes seen so far */ - SubProgram **apSub = 0; /* Array of sub-vdbes */ Mem *pSub = 0; /* Memory cell hold array of subprogs */ sqlite3 *db = p->db; /* The database connection */ int i; /* Loop counter */ int rc = SQLITE_OK; /* Return code */ Mem *pMem = &p->aMem[1]; /* First Mem of result set */ + int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0); + Op *aOp; /* Array of opcodes */ + Op *pOp; /* Current opcode */ assert( p->explain ); - assert( p->magic==VDBE_MAGIC_RUN ); + assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM ); /* Even though this opcode does not use dynamic strings for @@ -72760,154 +81916,70 @@ SQLITE_PRIVATE int sqlite3VdbeList( releaseMemArray(pMem, 8); p->pResultSet = 0; - if( p->rc==SQLITE_NOMEM_BKPT ){ + if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ sqlite3OomFault(db); return SQLITE_ERROR; } - /* When the number of output rows reaches nRow, that means the - ** listing has finished and sqlite3_step() should return SQLITE_DONE. - ** nRow is the sum of the number of rows in the main program, plus - ** the sum of the number of rows in all trigger subprograms encountered - ** so far. The nRow value will increase as new trigger subprograms are - ** encountered, but p->pc will eventually catch up to nRow. - */ - nRow = p->nOp; - if( p->explain==1 ){ + if( bListSubprogs ){ /* The first 8 memory cells are used for the result set. So we will ** commandeer the 9th cell to use as storage for an array of pointers ** to trigger subprograms. The VDBE is guaranteed to have at least 9 ** cells. */ assert( p->nMem>9 ); pSub = &p->aMem[9]; - if( pSub->flags&MEM_Blob ){ - /* On the first call to sqlite3_step(), pSub will hold a NULL. It is - ** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */ - nSub = pSub->n/sizeof(Vdbe*); - apSub = (SubProgram **)pSub->z; - } - for(i=0; inOp; - } - } - - do{ - i = p->pc++; - }while( iexplain==2 && p->aOp[i].opcode!=OP_Explain ); - if( i>=nRow ){ - p->rc = SQLITE_OK; - rc = SQLITE_DONE; - }else if( db->u1.isInterrupted ){ - p->rc = SQLITE_INTERRUPT; - rc = SQLITE_ERROR; - sqlite3VdbeError(p, sqlite3ErrStr(p->rc)); }else{ - char *zP4; - Op *pOp; - if( inOp ){ - /* The output line number is small enough that we are still in the - ** main program. */ - pOp = &p->aOp[i]; - }else{ - /* We are currently listing subprograms. Figure out which one and - ** pick up the appropriate opcode. */ - int j; - i -= p->nOp; - for(j=0; i>=apSub[j]->nOp; j++){ - i -= apSub[j]->nOp; - } - pOp = &apSub[j]->aOp[i]; - } - if( p->explain==1 ){ - pMem->flags = MEM_Int; - pMem->u.i = i; /* Program counter */ - pMem++; - - pMem->flags = MEM_Static|MEM_Str|MEM_Term; - pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */ - assert( pMem->z!=0 ); - pMem->n = sqlite3Strlen30(pMem->z); - pMem->enc = SQLITE_UTF8; - pMem++; - - /* When an OP_Program opcode is encounter (the only opcode that has - ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms - ** kept in p->aMem[9].z to hold the new program - assuming this subprogram - ** has not already been seen. - */ - if( pOp->p4type==P4_SUBPROGRAM ){ - int nByte = (nSub+1)*sizeof(SubProgram*); - int j; - for(j=0; jp4.pProgram ) break; - } - if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){ - apSub = (SubProgram **)pSub->z; - apSub[nSub++] = pOp->p4.pProgram; - pSub->flags |= MEM_Blob; - pSub->n = nSub*sizeof(SubProgram*); - } - } - } - - pMem->flags = MEM_Int; - pMem->u.i = pOp->p1; /* P1 */ - pMem++; - - pMem->flags = MEM_Int; - pMem->u.i = pOp->p2; /* P2 */ - pMem++; + pSub = 0; + } - pMem->flags = MEM_Int; - pMem->u.i = pOp->p3; /* P3 */ - pMem++; + /* Figure out which opcode is next to display */ + rc = sqlite3VdbeNextOpcode(p, pSub, p->explain==2, &p->pc, &i, &aOp); - if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */ - assert( p->db->mallocFailed ); - return SQLITE_ERROR; - } - pMem->flags = MEM_Str|MEM_Term; - zP4 = displayP4(pOp, pMem->z, pMem->szMalloc); - if( zP4!=pMem->z ){ - pMem->n = 0; - sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0); - }else{ - assert( pMem->z!=0 ); - pMem->n = sqlite3Strlen30(pMem->z); - pMem->enc = SQLITE_UTF8; - } - pMem++; - - if( p->explain==1 ){ - if( sqlite3VdbeMemClearAndResize(pMem, 4) ){ - assert( p->db->mallocFailed ); - return SQLITE_ERROR; - } - pMem->flags = MEM_Str|MEM_Term; - pMem->n = 2; - sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */ - pMem->enc = SQLITE_UTF8; - pMem++; - + if( rc==SQLITE_OK ){ + pOp = aOp + i; + if( AtomicLoad(&db->u1.isInterrupted) ){ + p->rc = SQLITE_INTERRUPT; + rc = SQLITE_ERROR; + sqlite3VdbeError(p, sqlite3ErrStr(p->rc)); + }else{ + char *zP4 = sqlite3VdbeDisplayP4(db, pOp); + if( p->explain==2 ){ + sqlite3VdbeMemSetInt64(pMem, pOp->p1); + sqlite3VdbeMemSetInt64(pMem+1, pOp->p2); + sqlite3VdbeMemSetInt64(pMem+2, pOp->p3); + sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free); + p->nResColumn = 4; + }else{ + sqlite3VdbeMemSetInt64(pMem+0, i); + sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode), + -1, SQLITE_UTF8, SQLITE_STATIC); + sqlite3VdbeMemSetInt64(pMem+2, pOp->p1); + sqlite3VdbeMemSetInt64(pMem+3, pOp->p2); + sqlite3VdbeMemSetInt64(pMem+4, pOp->p3); + /* pMem+5 for p4 is done last */ + sqlite3VdbeMemSetInt64(pMem+6, pOp->p5); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS - if( sqlite3VdbeMemClearAndResize(pMem, 500) ){ - assert( p->db->mallocFailed ); - return SQLITE_ERROR; - } - pMem->flags = MEM_Str|MEM_Term; - pMem->n = displayComment(pOp, zP4, pMem->z, 500); - pMem->enc = SQLITE_UTF8; + { + char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4); + sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free); + } #else - pMem->flags = MEM_Null; /* Comment */ + sqlite3VdbeMemSetNull(pMem+7); #endif + sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free); + p->nResColumn = 8; + } + p->pResultSet = pMem; + if( db->mallocFailed ){ + p->rc = SQLITE_NOMEM; + rc = SQLITE_ERROR; + }else{ + p->rc = SQLITE_OK; + rc = SQLITE_ROW; + } } - - p->nResColumn = 8 - 4*(p->explain-1); - p->pResultSet = &p->aMem[1]; - p->rc = SQLITE_OK; - rc = SQLITE_ROW; } return rc; } @@ -72967,9 +82039,9 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){ ** of a ReusableSpace object by the allocSpace() routine below. */ struct ReusableSpace { - u8 *pSpace; /* Available memory */ - int nFree; /* Bytes of available memory */ - int nNeeded; /* Total bytes that could not be allocated */ + u8 *pSpace; /* Available memory */ + sqlite3_int64 nFree; /* Bytes of available memory */ + sqlite3_int64 nNeeded; /* Total bytes that could not be allocated */ }; /* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf @@ -72989,7 +82061,7 @@ struct ReusableSpace { static void *allocSpace( struct ReusableSpace *p, /* Bulk memory available for allocation */ void *pBuf, /* Pointer to a prior allocation */ - int nByte /* Bytes of memory needed */ + sqlite3_int64 nByte /* Bytes of memory needed */ ){ assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); if( pBuf==0 ){ @@ -73014,14 +82086,14 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ int i; #endif assert( p!=0 ); - assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET ); + assert( p->iVdbeMagic==VDBE_MAGIC_INIT || p->iVdbeMagic==VDBE_MAGIC_RESET ); /* There should be at least one opcode. */ assert( p->nOp>0 ); /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */ - p->magic = VDBE_MAGIC_RUN; + p->iVdbeMagic = VDBE_MAGIC_RUN; #ifdef SQLITE_DEBUG for(i=0; inMem; i++){ @@ -73049,11 +82121,11 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){ ** creating the virtual machine. This involves things such ** as allocating registers and initializing the program counter. ** After the VDBE has be prepped, it can be executed by one or more -** calls to sqlite3VdbeExec(). +** calls to sqlite3VdbeExec(). ** ** This function may be called exactly once on each virtual machine. ** After this routine is called the VM has been "packaged" and is ready -** to run. After this routine is called, further calls to +** to run. After this routine is called, further calls to ** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects ** the Vdbe from the Parse object that helped generate it so that the ** the Vdbe becomes an independent entity and the Parse object can be @@ -73077,15 +82149,17 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( assert( p!=0 ); assert( p->nOp>0 ); assert( pParse!=0 ); - assert( p->magic==VDBE_MAGIC_INIT ); + assert( p->iVdbeMagic==VDBE_MAGIC_INIT ); assert( pParse==p->pParse ); + p->pVList = pParse->pVList; + pParse->pVList = 0; db = p->db; assert( db->mallocFailed==0 ); nVar = pParse->nVar; nMem = pParse->nMem; nCursor = pParse->nTab; nArg = pParse->nMaxArg; - + /* Each cursor uses a memory cell. The first cursor (cursor 0) can ** use aMem[0] which is not otherwise used by the VDBE program. Allocate ** space at the end of aMem[] for cursors 1 and greater. @@ -73107,38 +82181,62 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( resolveP2Values(p, &nArg); p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); - if( pParse->explain && nMem<10 ){ - nMem = 10; + if( pParse->explain ){ + static const char * const azColName[] = { + "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", + "id", "parent", "notused", "detail" + }; + int iFirst, mx, i; + if( nMem<10 ) nMem = 10; + p->explain = pParse->explain; + if( pParse->explain==2 ){ + sqlite3VdbeSetNumCols(p, 4); + iFirst = 8; + mx = 12; + }else{ + sqlite3VdbeSetNumCols(p, 8); + iFirst = 0; + mx = 8; + } + for(i=iFirst; iexpired = 0; /* Memory for registers, parameters, cursor, etc, is allocated in one or two - ** passes. On the first pass, we try to reuse unused memory at the + ** passes. On the first pass, we try to reuse unused memory at the ** end of the opcode array. If we are unable to satisfy all memory ** requirements by reusing the opcode array tail, then the second - ** pass will fill in the remainder using a fresh memory allocation. + ** pass will fill in the remainder using a fresh memory allocation. ** ** This two-pass approach that reuses as much memory as possible from ** the leftover memory at the end of the opcode array. This can significantly ** reduce the amount of memory held by a prepared statement. */ - do { - x.nNeeded = 0; - p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); - p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); - p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); - p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); + x.nNeeded = 0; + p->aMem = allocSpace(&x, 0, nMem*sizeof(Mem)); + p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem)); + p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*)); + p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*)); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS - p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); + p->anExec = allocSpace(&x, 0, p->nOp*sizeof(i64)); #endif - if( x.nNeeded==0 ) break; + if( x.nNeeded ){ x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded); x.nFree = x.nNeeded; - }while( !db->mallocFailed ); + if( !db->mallocFailed ){ + p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem)); + p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem)); + p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*)); + p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*)); +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS + p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64)); +#endif + } + } - p->pVList = pParse->pVList; - pParse->pVList = 0; - p->explain = pParse->explain; if( db->mallocFailed ){ p->nVar = 0; p->nCursor = 0; @@ -73158,28 +82256,21 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady( } /* -** Close a VDBE cursor and release all the resources that cursor +** Close a VDBE cursor and release all the resources that cursor ** happens to hold. */ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){ if( pCx==0 ){ return; } - assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE ); switch( pCx->eCurType ){ case CURTYPE_SORTER: { sqlite3VdbeSorterClose(p->db, pCx); break; } case CURTYPE_BTREE: { - if( pCx->pBtx ){ - sqlite3BtreeClose(pCx->pBtx); - /* The pCx->pCursor will be close automatically, if it exists, by - ** the call above. */ - }else{ - assert( pCx->uc.pCursor!=0 ); - sqlite3BtreeCloseCursor(pCx->uc.pCursor); - } + assert( pCx->uc.pCursor!=0 ); + sqlite3BtreeCloseCursor(pCx->uc.pCursor); break; } #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -73240,7 +82331,7 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ /* ** Close all cursors. ** -** Also release any dynamic memory held by the VM in the Vdbe.aMem memory +** Also release any dynamic memory held by the VM in the Vdbe.aMem memory ** cell array. This is necessary as the memory cell array may contain ** pointers to VdbeFrame objects, which may in turn contain pointers to ** open cursors. @@ -73269,27 +82360,6 @@ static void closeAllCursors(Vdbe *p){ assert( p->pAuxData==0 ); } -/* -** Clean up the VM after a single run. -*/ -static void Cleanup(Vdbe *p){ - sqlite3 *db = p->db; - -#ifdef SQLITE_DEBUG - /* Execute assert() statements to ensure that the Vdbe.apCsr[] and - ** Vdbe.aMem[] arrays have already been cleaned up. */ - int i; - if( p->apCsr ) for(i=0; inCursor; i++) assert( p->apCsr[i]==0 ); - if( p->aMem ){ - for(i=0; inMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); - } -#endif - - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; - p->pResultSet = 0; -} - /* ** Set the number of result columns that will be returned by this SQL ** statement. This is now set at compile time, rather than during @@ -73297,17 +82367,18 @@ static void Cleanup(Vdbe *p){ ** be called on an SQL statement before sqlite3_step(). */ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ - Mem *pColName; int n; sqlite3 *db = p->db; - releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); - sqlite3DbFree(db, p->aColName); + if( p->nResColumn ){ + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); + sqlite3DbFree(db, p->aColName); + } n = nResColumn*COLNAME_N; p->nResColumn = (u16)nResColumn; - p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); + p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n ); if( p->aColName==0 ) return; - initMemArray(p->aColName, n, p->db, MEM_Null); + initMemArray(p->aColName, n, db, MEM_Null); } /* @@ -73346,43 +82417,43 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName( ** A read or write transaction may or may not be active on database handle ** db. If a transaction is active, commit it. If there is a ** write-transaction spanning more than one database file, this routine -** takes care of the master journal trickery. +** takes care of the super-journal trickery. */ static int vdbeCommit(sqlite3 *db, Vdbe *p){ int i; int nTrans = 0; /* Number of databases with an active write-transaction ** that are candidates for a two-phase commit using a - ** master-journal */ + ** super-journal */ int rc = SQLITE_OK; int needXcommit = 0; #ifdef SQLITE_OMIT_VIRTUALTABLE - /* With this option, sqlite3VtabSync() is defined to be simply - ** SQLITE_OK so p is not used. + /* With this option, sqlite3VtabSync() is defined to be simply + ** SQLITE_OK so p is not used. */ UNUSED_PARAMETER(p); #endif /* Before doing anything else, call the xSync() callback for any ** virtual module tables written in this transaction. This has to - ** be done before determining whether a master journal file is + ** be done before determining whether a super-journal file is ** required, as an xSync() callback may add an attached database ** to the transaction. */ rc = sqlite3VtabSync(db, p); /* This loop determines (a) if the commit hook should be invoked and - ** (b) how many database files have open write transactions, not - ** including the temp database. (b) is important because if more than - ** one database file has an open write transaction, a master journal + ** (b) how many database files have open write transactions, not + ** including the temp database. (b) is important because if more than + ** one database file has an open write transaction, a super-journal ** file is required for an atomic commit. - */ - for(i=0; rc==SQLITE_OK && inDb; i++){ + */ + for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( sqlite3BtreeIsInTrans(pBt) ){ - /* Whether or not a database might need a master journal depends upon + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ + /* Whether or not a database might need a super-journal depends upon ** its journal mode (among other things). This matrix determines which - ** journal modes use a master journal and which do not */ + ** journal modes use a super-journal and which do not */ static const u8 aMJNeeded[] = { /* DELETE */ 1, /* PERSIST */ 1, @@ -73397,7 +82468,8 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ pPager = sqlite3BtreePager(pBt); if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF && aMJNeeded[sqlite3PagerGetJournalMode(pPager)] - ){ + && sqlite3PagerIsMemdb(pPager)==0 + ){ assert( i!=1 ); nTrans++; } @@ -73419,11 +82491,11 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ /* The simple case - no more than one database file (not counting the ** TEMP database) has a transaction active. There is no need for the - ** master-journal. + ** super-journal. ** ** If the return value of sqlite3BtreeGetFilename() is a zero length - ** string, it means the main database is :memory: or a temp file. In - ** that case we do not support atomic multi-file commits, so use the + ** string, it means the main database is :memory: or a temp file. In + ** that case we do not support atomic multi-file commits, so use the ** simple case then too. */ if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt)) @@ -73436,7 +82508,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ } } - /* Do the commit only if all databases successfully complete phase 1. + /* Do the commit only if all databases successfully complete phase 1. ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an ** IO error while deleting or truncating a journal file. It is unlikely, ** but could happen. In this case abandon processing and return the error. @@ -73453,124 +82525,125 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ } /* The complex case - There is a multi-file write-transaction active. - ** This requires a master journal file to ensure the transaction is + ** This requires a super-journal file to ensure the transaction is ** committed atomically. */ #ifndef SQLITE_OMIT_DISKIO else{ sqlite3_vfs *pVfs = db->pVfs; - char *zMaster = 0; /* File-name for the master journal */ + char *zSuper = 0; /* File-name for the super-journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); - sqlite3_file *pMaster = 0; + sqlite3_file *pSuperJrnl = 0; i64 offset = 0; int res; int retryCount = 0; int nMainFile; - /* Select a master journal file name */ + /* Select a super-journal file name */ nMainFile = sqlite3Strlen30(zMainFile); - zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile); - if( zMaster==0 ) return SQLITE_NOMEM_BKPT; + zSuper = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0); + if( zSuper==0 ) return SQLITE_NOMEM_BKPT; + zSuper += 4; do { u32 iRandom; if( retryCount ){ if( retryCount>100 ){ - sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster); - sqlite3OsDelete(pVfs, zMaster, 0); + sqlite3_log(SQLITE_FULL, "MJ delete: %s", zSuper); + sqlite3OsDelete(pVfs, zSuper, 0); break; }else if( retryCount==1 ){ - sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster); + sqlite3_log(SQLITE_FULL, "MJ collide: %s", zSuper); } } retryCount++; sqlite3_randomness(sizeof(iRandom), &iRandom); - sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X", + sqlite3_snprintf(13, &zSuper[nMainFile], "-mj%06X9%02X", (iRandom>>8)&0xffffff, iRandom&0xff); - /* The antipenultimate character of the master journal name must + /* The antipenultimate character of the super-journal name must ** be "9" to avoid name collisions when using 8+3 filenames. */ - assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' ); - sqlite3FileSuffix3(zMainFile, zMaster); - rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); + assert( zSuper[sqlite3Strlen30(zSuper)-3]=='9' ); + sqlite3FileSuffix3(zMainFile, zSuper); + rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); }while( rc==SQLITE_OK && res ); if( rc==SQLITE_OK ){ - /* Open the master journal. */ - rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, + /* Open the super-journal. */ + rc = sqlite3OsOpenMalloc(pVfs, zSuper, &pSuperJrnl, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE| - SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0 + SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_SUPER_JOURNAL, 0 ); } if( rc!=SQLITE_OK ){ - sqlite3DbFree(db, zMaster); + sqlite3DbFree(db, zSuper-4); return rc; } - + /* Write the name of each database file in the transaction into the new - ** master journal file. If an error occurs at this point close - ** and delete the master journal file. All the individual journal files - ** still have 'null' as the master journal pointer, so they will roll + ** super-journal file. If an error occurs at this point close + ** and delete the super-journal file. All the individual journal files + ** still have 'null' as the super-journal pointer, so they will roll ** back independently if a failure occurs. */ for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( sqlite3BtreeIsInTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile==0 ){ continue; /* Ignore TEMP and :memory: databases */ } assert( zFile[0]!=0 ); - rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset); + rc = sqlite3OsWrite(pSuperJrnl, zFile, sqlite3Strlen30(zFile)+1,offset); offset += sqlite3Strlen30(zFile)+1; if( rc!=SQLITE_OK ){ - sqlite3OsCloseFree(pMaster); - sqlite3OsDelete(pVfs, zMaster, 0); - sqlite3DbFree(db, zMaster); + sqlite3OsCloseFree(pSuperJrnl); + sqlite3OsDelete(pVfs, zSuper, 0); + sqlite3DbFree(db, zSuper-4); return rc; } } } - /* Sync the master journal file. If the IOCAP_SEQUENTIAL device + /* Sync the super-journal file. If the IOCAP_SEQUENTIAL device ** flag is set this is not required. */ - if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL) - && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL)) + if( 0==(sqlite3OsDeviceCharacteristics(pSuperJrnl)&SQLITE_IOCAP_SEQUENTIAL) + && SQLITE_OK!=(rc = sqlite3OsSync(pSuperJrnl, SQLITE_SYNC_NORMAL)) ){ - sqlite3OsCloseFree(pMaster); - sqlite3OsDelete(pVfs, zMaster, 0); - sqlite3DbFree(db, zMaster); + sqlite3OsCloseFree(pSuperJrnl); + sqlite3OsDelete(pVfs, zSuper, 0); + sqlite3DbFree(db, zSuper-4); return rc; } /* Sync all the db files involved in the transaction. The same call - ** sets the master journal pointer in each individual journal. If - ** an error occurs here, do not delete the master journal file. + ** sets the super-journal pointer in each individual journal. If + ** an error occurs here, do not delete the super-journal file. ** ** If the error occurs during the first call to ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the - ** master journal file will be orphaned. But we cannot delete it, - ** in case the master journal file name was written into the journal + ** super-journal file will be orphaned. But we cannot delete it, + ** in case the super-journal file name was written into the journal ** file before the failure occurred. */ - for(i=0; rc==SQLITE_OK && inDb; i++){ + for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ - rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster); + rc = sqlite3BtreeCommitPhaseOne(pBt, zSuper); } } - sqlite3OsCloseFree(pMaster); + sqlite3OsCloseFree(pSuperJrnl); assert( rc!=SQLITE_BUSY ); if( rc!=SQLITE_OK ){ - sqlite3DbFree(db, zMaster); + sqlite3DbFree(db, zSuper-4); return rc; } - /* Delete the master journal file. This commits the transaction. After + /* Delete the super-journal file. This commits the transaction. After ** doing this the directory is synced again before any individual ** transaction files are deleted. */ - rc = sqlite3OsDelete(pVfs, zMaster, 1); - sqlite3DbFree(db, zMaster); - zMaster = 0; + rc = sqlite3OsDelete(pVfs, zSuper, 1); + sqlite3DbFree(db, zSuper-4); + zSuper = 0; if( rc ){ return rc; } @@ -73584,7 +82657,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ */ disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); - for(i=0; inDb; i++){ + for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ sqlite3BtreeCommitPhaseTwo(pBt, 1); @@ -73600,7 +82673,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ return rc; } -/* +/* ** This routine checks that the sqlite3.nVdbeActive count variable ** matches the number of vdbe's in the list sqlite3.pVdbe that are ** currently active. An assertion fails if the two counts do not match. @@ -73636,10 +82709,10 @@ static void checkActiveVdbeCnt(sqlite3 *db){ ** If the Vdbe passed as the first argument opened a statement-transaction, ** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or ** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement -** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the +** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the ** statement transaction is committed. ** -** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. +** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. ** Otherwise SQLITE_OK. */ static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){ @@ -73652,7 +82725,7 @@ static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){ assert( db->nStatement>0 ); assert( p->iStatement==(db->nStatement+db->nSavepoint) ); - for(i=0; inDb; i++){ + for(i=0; inDb; i++){ int rc2 = SQLITE_OK; Btree *pBt = db->aDb[i].pBt; if( pBt ){ @@ -73679,8 +82752,8 @@ static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){ } } - /* If the statement transaction is being rolled back, also restore the - ** database handles deferred constraint counter to the value it had when + /* If the statement transaction is being rolled back, also restore the + ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; @@ -73697,20 +82770,20 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ /* -** This function is called when a transaction opened by the database -** handle associated with the VM passed as an argument is about to be +** This function is called when a transaction opened by the database +** handle associated with the VM passed as an argument is about to be ** committed. If there are outstanding deferred foreign key constraint ** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK. ** -** If there are outstanding FK violations and this function returns +** If there are outstanding FK violations and this function returns ** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY ** and write an error message to it. Then return SQLITE_ERROR. */ #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ sqlite3 *db = p->db; - if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) - || (!deferred && p->nFkConstraint>0) + if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) + || (!deferred && p->nFkConstraint>0) ){ p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; p->errorAction = OE_Abort; @@ -73726,9 +82799,9 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ ** has made changes and is in autocommit mode, then commit those ** changes. If a rollback is needed, then do the rollback. ** -** This routine is the only way to move the state of a VM from -** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to -** call this on a VM that is in the SQLITE_MAGIC_HALT state. +** This routine is the only way to move the sqlite3eOpenState of a VM from +** SQLITE_STATE_RUN to SQLITE_STATE_HALT. It is harmless to +** call this on a VM that is in the SQLITE_STATE_HALT state. ** ** Return an error code. If the commit could not complete because of ** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it @@ -73740,7 +82813,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ /* This function contains the logic that determines if a statement or ** transaction will be committed or rolled back as a result of the - ** execution of this virtual machine. + ** execution of this virtual machine. ** ** If any of the following errors occur: ** @@ -73754,13 +82827,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ ** one, or the complete transaction if there is no statement transaction. */ + if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){ + return SQLITE_OK; + } if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; } closeAllCursors(p); - if( p->magic!=VDBE_MAGIC_RUN ){ - return SQLITE_OK; - } checkActiveVdbeCnt(db); /* No commit or rollback needed if the program never started or if the @@ -73774,20 +82847,26 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ sqlite3VdbeEnter(p); /* Check for one of the special errors */ - mrc = p->rc & 0xff; - isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR - || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; + if( p->rc ){ + mrc = p->rc & 0xff; + isSpecialError = mrc==SQLITE_NOMEM + || mrc==SQLITE_IOERR + || mrc==SQLITE_INTERRUPT + || mrc==SQLITE_FULL; + }else{ + mrc = isSpecialError = 0; + } if( isSpecialError ){ - /* If the query was read-only and the error code is SQLITE_INTERRUPT, - ** no rollback is necessary. Otherwise, at least a savepoint - ** transaction must be rolled back to restore the database to a + /* If the query was read-only and the error code is SQLITE_INTERRUPT, + ** no rollback is necessary. Otherwise, at least a savepoint + ** transaction must be rolled back to restore the database to a ** consistent state. ** ** Even if the statement is read-only, it is important to perform - ** a statement or transaction rollback operation. If the error + ** a statement or transaction rollback operation. If the error ** occurred while writing to the journal, sub-journal or database ** file as part of an effort to free up cache space (see function - ** pagerStress() in pager.c), the rollback is required to restore + ** pagerStress() in pager.c), the rollback is required to restore ** the pager to a consistent state. */ if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){ @@ -73806,19 +82885,19 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ } /* Check for immediate foreign key violations. */ - if( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ sqlite3VdbeCheckFk(p, 0); } - - /* If the auto-commit flag is set and this is the only active writer - ** VM, then we do either a commit or rollback of the current transaction. + + /* If the auto-commit flag is set and this is the only active writer + ** VM, then we do either a commit or rollback of the current transaction. ** - ** Note: This block also runs if one of the special errors handled - ** above has occurred. + ** Note: This block also runs if one of the special errors handled + ** above has occurred. */ - if( !sqlite3VtabInSync(db) - && db->autoCommit - && db->nVdbeWrite==(p->readOnly==0) + if( !sqlite3VtabInSync(db) + && db->autoCommit + && db->nVdbeWrite==(p->readOnly==0) ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ rc = sqlite3VdbeCheckFk(p, 1); @@ -73828,10 +82907,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; - }else{ - /* The auto-commit flag is true, the vdbe program was successful + }else if( db->flags & SQLITE_CorruptRdOnly ){ + rc = SQLITE_CORRUPT; + db->flags &= ~SQLITE_CorruptRdOnly; + }else{ + /* The auto-commit flag is true, the vdbe program was successful ** or hit an 'OR FAIL' constraint and there are no deferred foreign - ** key constraints to hold up the transaction. This means a commit + ** key constraints to hold up the transaction. This means a commit ** is required. */ rc = vdbeCommit(db, p); } @@ -73845,7 +82927,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ }else{ db->nDeferredCons = 0; db->nDeferredImmCons = 0; - db->flags &= ~SQLITE_DeferFKs; + db->flags &= ~(u64)SQLITE_DeferFKs; sqlite3CommitInternalChanges(db); } }else{ @@ -73865,7 +82947,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ p->nChange = 0; } } - + /* If eStatementOp is non-zero, then a statement transaction needs to ** be committed or rolled back. Call sqlite3VdbeCloseStatement() to ** do so. If this operation returns an error, and the current statement @@ -73886,9 +82968,9 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ p->nChange = 0; } } - + /* If this was an INSERT, UPDATE or DELETE and no statement transaction - ** has been rolled back, update the database connection change-counter. + ** has been rolled back, update the database connection change-counter. */ if( p->changeCntOn ){ if( eStatementOp!=SAVEPOINT_ROLLBACK ){ @@ -73912,14 +82994,14 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ assert( db->nVdbeRead>=db->nVdbeWrite ); assert( db->nVdbeWrite>=0 ); } - p->magic = VDBE_MAGIC_HALT; + p->iVdbeMagic = VDBE_MAGIC_HALT; checkActiveVdbeCnt(db); if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; } /* If the auto-commit flag is set to true, then any locks that were held - ** by connection db have now been released. Call sqlite3ConnectionUnlocked() + ** by connection db have now been released. Call sqlite3ConnectionUnlocked() ** to invoke any required unlock-notify callbacks. */ if( db->autoCommit ){ @@ -73941,7 +83023,7 @@ SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){ /* ** Copy the error code and error message belonging to the VDBE passed -** as the first argument to its database handle (so that they will be +** as the first argument to its database handle (so that they will be ** returned by calls to sqlite3_errcode() and sqlite3_errmsg()). ** ** This function does not clear the VDBE error code or message, just @@ -73957,16 +83039,17 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){ sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); sqlite3EndBenignMalloc(); db->bBenignMalloc--; - db->errCode = rc; - }else{ - sqlite3Error(db, rc); + }else if( db->pErr ){ + sqlite3ValueSetNull(db->pErr); } + db->errCode = rc; + db->errByteOffset = -1; return rc; } #ifdef SQLITE_ENABLE_SQLLOG /* -** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run, +** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run, ** invoke it. */ static void vdbeInvokeSqllog(Vdbe *v){ @@ -73997,6 +83080,10 @@ static void vdbeInvokeSqllog(Vdbe *v){ ** VDBE_MAGIC_INIT. */ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) + int i; +#endif + sqlite3 *db; db = p->db; @@ -74006,16 +83093,18 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ */ sqlite3VdbeHalt(p); - /* If the VDBE has be run even partially, then transfer the error code + /* If the VDBE has been run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ vdbeInvokeSqllog(p); - sqlite3VdbeTransferError(p); - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; + if( db->pErr || p->zErrMsg ){ + sqlite3VdbeTransferError(p); + }else{ + db->errCode = p->rc; + } if( p->runOnlyOnce ) p->expired = 1; }else if( p->rc && p->expired ){ /* The expired flag was set on the VDBE before the first call @@ -74023,13 +83112,26 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ ** called), set the database error in this case as well. */ sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg); - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = 0; } - /* Reclaim all memory used by the VDBE + /* Reset register contents and reclaim error message memory. */ - Cleanup(p); +#ifdef SQLITE_DEBUG + /* Execute assert() statements to ensure that the Vdbe.apCsr[] and + ** Vdbe.aMem[] arrays have already been cleaned up. */ + if( p->apCsr ) for(i=0; inCursor; i++) assert( p->apCsr[i]==0 ); + if( p->aMem ){ + for(i=0; inMem; i++) assert( p->aMem[i].flags==MEM_Undefined ); + } +#endif + if( p->zErrMsg ){ + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = 0; + } + p->pResultSet = 0; +#ifdef SQLITE_DEBUG + p->nWrite = 0; +#endif /* Save profiling information from this VDBE run. */ @@ -74037,7 +83139,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ { FILE *out = fopen("vdbe_profile.out", "a"); if( out ){ - int i; fprintf(out, "---- "); for(i=0; inOp; i++){ fprintf(out, "%02x", p->aOp[i].opcode); @@ -74067,18 +83168,17 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){ } } #endif - p->iCurrentTime = 0; - p->magic = VDBE_MAGIC_RESET; + p->iVdbeMagic = VDBE_MAGIC_RESET; return p->rc & db->errMask; } - + /* ** Clean up and delete a VDBE after execution. Return an integer which is ** the result code. Write any error message text into *pzErrMsg. */ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){ int rc = SQLITE_OK; - if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){ + if( p->iVdbeMagic==VDBE_MAGIC_RUN || p->iVdbeMagic==VDBE_MAGIC_HALT ){ rc = sqlite3VdbeReset(p); assert( (rc & p->db->errMask)==rc ); } @@ -74092,8 +83192,8 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){ ** the first argument. ** ** Or, if iOp is greater than or equal to zero, then the destructor is -** only invoked for those auxiliary data pointers created by the user -** function invoked by the OP_Function opcode at instruction iOp of +** only invoked for those auxiliary data pointers created by the user +** function invoked by the OP_Function opcode at instruction iOp of ** VM pVdbe, and only then if: ** ** * the associated function parameter is the 32nd or later (counting @@ -74106,16 +83206,18 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, while( *pp ){ AuxData *pAux = *pp; if( (iOp<0) - || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg)))) + || (pAux->iAuxOp==iOp + && pAux->iAuxArg>=0 + && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg)))) ){ - testcase( pAux->iArg==31 ); - if( pAux->xDelete ){ - pAux->xDelete(pAux->pAux); + testcase( pAux->iAuxArg==31 ); + if( pAux->xDeleteAux ){ + pAux->xDeleteAux(pAux->pAux); } - *pp = pAux->pNext; + *pp = pAux->pNextAux; sqlite3DbFree(db, pAux); }else{ - pp= &pAux->pNext; + pp= &pAux->pNextAux; } } } @@ -74137,7 +83239,7 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); sqlite3DbFree(db, pSub); } - if( p->magic!=VDBE_MAGIC_INIT ){ + if( p->iVdbeMagic!=VDBE_MAGIC_INIT ){ releaseMemArray(p->aVar, p->nVar); sqlite3DbFree(db, p->pVList); sqlite3DbFree(db, p->pFree); @@ -74145,6 +83247,16 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3DbFree(db, p->zNormSql); + { + DblquoteStr *pThis, *pNext; + for(pThis=p->pDblStr; pThis; pThis=pNext){ + pNext = pThis->pNextStr; + sqlite3DbFree(db, pThis); + } + } +#endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS { int i; @@ -74162,7 +83274,7 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; - if( NEVER(p==0) ) return; + assert( p!=0 ); db = p->db; assert( sqlite3_mutex_held(db->mutex) ); sqlite3VdbeClearObject(db, p); @@ -74175,9 +83287,9 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ if( p->pNext ){ p->pNext->pPrev = p->pPrev; } - p->magic = VDBE_MAGIC_DEAD; + p->iVdbeMagic = VDBE_MAGIC_DEAD; p->db = 0; - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } /* @@ -74185,7 +83297,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){ ** carried out. Seek the cursor now. If an error occurs, return ** the appropriate error code. */ -static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){ +SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){ int res, rc; #ifdef SQLITE_TEST extern int sqlite3_search_count; @@ -74193,7 +83305,7 @@ static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){ assert( p->deferredMoveto ); assert( p->isTable ); assert( p->eCurType==CURTYPE_BTREE ); - rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res); + rc = sqlite3BtreeTableMoveto(p->uc.pCursor, p->movetoTarget, 0, &res); if( rc ) return rc; if( res!=0 ) return SQLITE_CORRUPT_BKPT; #ifdef SQLITE_TEST @@ -74247,21 +83359,21 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){ ** If the cursor is already pointing to the correct row and that row has ** not been deleted out from under the cursor, then this routine is a no-op. */ -SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ +SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){ VdbeCursor *p = *pp; - if( p->eCurType==CURTYPE_BTREE ){ - if( p->deferredMoveto ){ - int iMap; - if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){ - *pp = p->pAltCursor; - *piCol = iMap - 1; - return SQLITE_OK; - } - return handleDeferredMoveto(p); - } - if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ - return handleMovedCursor(p); + assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO ); + if( p->deferredMoveto ){ + u32 iMap; + assert( !p->isEphemeral ); + if( p->ub.aAltMap && (iMap = p->ub.aAltMap[1+*piCol])>0 && !p->nullRow ){ + *pp = p->pAltCursor; + *piCol = iMap - 1; + return SQLITE_OK; } + return sqlite3VdbeFinishMoveto(p); + } + if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ + return handleMovedCursor(p); } return SQLITE_OK; } @@ -74308,8 +83420,17 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ ** of SQLite will not understand those serial types. */ +#if 0 /* Inlined into the OP_MakeRecord opcode */ /* ** Return the serial-type for the value stored in pMem. +** +** This routine might convert a large MEM_IntReal value into MEM_Real. +** +** 2019-07-11: The primary user of this subroutine was the OP_MakeRecord +** opcode in the byte-code engine. But by moving this routine in-line, we +** can omit some redundant tests and make that opcode a lot faster. So +** this routine is now only used by the STAT3 logic and STAT3 support has +** ended. The code is kept here for historical reference only. */ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ int flags = pMem->flags; @@ -74320,11 +83441,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ *pLen = 0; return 0; } - if( flags&MEM_Int ){ + if( flags&(MEM_Int|MEM_IntReal) ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00008000)<<32)-1) i64 i = pMem->u.i; u64 u; + testcase( flags & MEM_Int ); + testcase( flags & MEM_IntReal ); if( i<0 ){ u = ~i; }else{ @@ -74344,6 +83467,15 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ if( u<=2147483647 ){ *pLen = 4; return 4; } if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } *pLen = 8; + if( flags&MEM_IntReal ){ + /* If the value is IntReal and is going to take up 8 bytes to store + ** as an integer, then we might as well make it an 8-byte floating + ** point value */ + pMem->u.r = (double)pMem->u.i; + pMem->flags &= ~MEM_IntReal; + pMem->flags |= MEM_Real; + return 7; + } return 6; } if( flags&MEM_Real ){ @@ -74359,12 +83491,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ *pLen = n; return ((n*2) + 12 + ((flags&MEM_Str)!=0)); } +#endif /* inlined into OP_MakeRecord */ /* ** The sizes for serial types less than 128 */ static const u8 sqlite3SmallTypeSizes[] = { - /* 0 1 2 3 4 5 6 7 8 9 */ + /* 0 1 2 3 4 5 6 7 8 9 */ /* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, /* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, /* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, @@ -74387,19 +83520,19 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){ if( serial_type>=128 ){ return (serial_type-12)/2; }else{ - assert( serial_type<12 + assert( serial_type<12 || sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 ); return sqlite3SmallTypeSizes[serial_type]; } } SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){ assert( serial_type<128 ); - return sqlite3SmallTypeSizes[serial_type]; + return sqlite3SmallTypeSizes[serial_type]; } /* -** If we are on an architecture with mixed-endian floating -** points (ex: ARM7) then swap the lower 4 bytes with the +** If we are on an architecture with mixed-endian floating +** points (ex: ARM7) then swap the lower 4 bytes with the ** upper 4 bytes. Return the result. ** ** For most architectures, this is a no-op. @@ -74421,7 +83554,7 @@ SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){ ** (2007-08-30) Frank van Vugt has studied this problem closely ** and has send his findings to the SQLite developers. Frank ** writes that some Linux kernels offer floating point hardware -** emulation that uses only 32-bit mantissas instead of a full +** emulation that uses only 32-bit mantissas instead of a full ** 48-bits as required by the IEEE standard. (This is the ** CONFIG_FPE_FASTFPE option.) On such systems, floating point ** byte swapping becomes very complicated. To avoid problems, @@ -74451,7 +83584,7 @@ static u64 floatSwap(u64 in){ #endif /* -** Write the serialized data blob for the value stored in pMem into +** Write the serialized data blob for the value stored in pMem into ** buf. It is assumed that the caller has allocated sufficient space. ** Return the number of bytes written. ** @@ -74462,7 +83595,7 @@ static u64 floatSwap(u64 in){ ** Return the number of bytes actually written into buf[]. The number ** of bytes in the zero-filled tail is included in the return value only ** if those bytes were zeroed in buf[]. -*/ +*/ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ u32 len; @@ -74510,14 +83643,14 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ /* ** Deserialize the data blob pointed to by buf as serial type serial_type -** and store the result in pMem. Return the number of bytes read. +** and store the result in pMem. ** ** This function is implemented as two separate routines for performance. ** The few cases that require local variables are broken out into a separate ** routine so that in most cases the overhead of moving the stack pointer ** is avoided. -*/ -static u32 SQLITE_NOINLINE serialGet( +*/ +static void serialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ @@ -74549,22 +83682,27 @@ static u32 SQLITE_NOINLINE serialGet( assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); - pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real; + pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real; } - return 8; } -SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( +SQLITE_PRIVATE void sqlite3VdbeSerialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ ){ switch( serial_type ){ - case 10: /* Reserved for future use */ + case 10: { /* Internal use only: NULL with virtual table + ** UPDATE no-change flag set */ + pMem->flags = MEM_Null|MEM_Zero; + pMem->n = 0; + pMem->u.nZero = 0; + return; + } case 11: /* Reserved for future use */ case 0: { /* Null */ /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */ pMem->flags = MEM_Null; - break; + return; } case 1: { /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement @@ -74572,7 +83710,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( pMem->u.i = ONE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); - return 1; + return; } case 2: { /* 2-byte signed integer */ /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit @@ -74580,7 +83718,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( pMem->u.i = TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); - return 2; + return; } case 3: { /* 3-byte signed integer */ /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit @@ -74588,19 +83726,19 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( pMem->u.i = THREE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); - return 3; + return; } case 4: { /* 4-byte signed integer */ /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit ** twos-complement integer. */ pMem->u.i = FOUR_BYTE_INT(buf); -#ifdef __HP_cc +#ifdef __HP_cc /* Work around a sign-extension bug in the HP compiler for HP/UX */ if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL; #endif pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); - return 4; + return; } case 5: { /* 6-byte signed integer */ /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit @@ -74608,13 +83746,14 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); - return 6; + return; } case 6: /* 8-byte signed integer */ case 7: { /* IEEE floating point */ /* These use local variables, so do them in a separate routine ** to avoid having to move the frame pointer in the common case */ - return serialGet(buf,serial_type,pMem); + serialGet(buf,serial_type,pMem); + return; } case 8: /* Integer 0 */ case 9: { /* Integer 1 */ @@ -74622,7 +83761,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */ pMem->u.i = serial_type-8; pMem->flags = MEM_Int; - return 0; + return; } default: { /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in @@ -74633,10 +83772,10 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( pMem->z = (char *)buf; pMem->n = (serial_type-12)/2; pMem->flags = aFlag[serial_type&1]; - return pMem->n; + return; } } - return 0; + return; } /* ** This routine is used to allocate sufficient space for an UnpackedRecord @@ -74646,7 +83785,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet( ** The space is either allocated using sqlite3DbMallocRaw() or from within ** the unaligned buffer passed via the second and third arguments (presumably ** stack space). If the former, then *ppFree is set to a pointer that should -** be eventually freed by the caller using sqlite3DbFree(). Or, if the +** be eventually freed by the caller using sqlite3DbFree(). Or, if the ** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL ** before returning. ** @@ -74657,21 +83796,21 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( ){ UnpackedRecord *p; /* Unpacked record to return */ int nByte; /* Number of bytes required for *p */ - nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1); + nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1); p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte); if( !p ) return 0; p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; - assert( pKeyInfo->aSortOrder!=0 ); + assert( pKeyInfo->aSortFlags!=0 ); p->pKeyInfo = pKeyInfo; - p->nField = pKeyInfo->nField + 1; + p->nField = pKeyInfo->nKeyField + 1; return p; } /* -** Given the nKey-byte encoding of a record in pKey[], populate the +** Given the nKey-byte encoding of a record in pKey[], populate the ** UnpackedRecord structure indicated by the fourth argument with the ** contents of the decoded record. -*/ +*/ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( KeyInfo *pKeyInfo, /* Information about the record format */ int nKey, /* Size of the binary record */ @@ -74679,7 +83818,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( UnpackedRecord *p /* Populate this structure before returning. */ ){ const unsigned char *aKey = (const unsigned char *)pKey; - int d; + u32 d; u32 idx; /* Offset in aKey[] to read from */ u16 u; /* Unsigned loop counter */ u32 szHdr; @@ -74690,7 +83829,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack( idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; - while( idxflags = 0; // sqlite3VdbeSerialGet() will set this for us */ pMem->szMalloc = 0; pMem->z = 0; - d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); + sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); + d += sqlite3VdbeSerialTypeLen(serial_type); pMem++; if( (++u)>=p->nField ) break; } - assert( u<=pKeyInfo->nField + 1 ); + if( d>(u32)nKey && u ){ + assert( CORRUPT_DB ); + /* In a corrupt record entry, the last pMem might have been set up using + ** uninitialized memory. Overwrite its value with NULL, to prevent + ** warnings from MSAN. */ + sqlite3VdbeMemSetNull(pMem-1); + } + assert( u<=pKeyInfo->nKeyField + 1 ); p->nField = u; } -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* ** This function compares two index or table record keys in the same way ** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(), @@ -74742,19 +83889,19 @@ static int vdbeRecordCompareDebug( /* Compilers may complain that mem1.u.i is potentially uninitialized. ** We could initialize it, as shown here, to silence those complaints. - ** But in fact, mem1.u.i will never actually be used uninitialized, and doing + ** But in fact, mem1.u.i will never actually be used uninitialized, and doing ** the unnecessary initialization has a measurable negative performance ** impact, since this routine is a very high runner. And so, we choose ** to ignore the compiler warnings and leave this variable uninitialized. */ /* mem1.u.i = 0; // not needed, here to silence compiler warning */ - + idx1 = getVarint32(aKey1, szHdr1); if( szHdr1>98307 ) return SQLITE_CORRUPT; d1 = szHdr1; - assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB ); - assert( pKeyInfo->aSortOrder!=0 ); - assert( pKeyInfo->nField>0 ); + assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); + assert( pKeyInfo->aSortFlags!=0 ); + assert( pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type1; @@ -74768,22 +83915,29 @@ static int vdbeRecordCompareDebug( ** Use that approximation to avoid the more expensive call to ** sqlite3VdbeSerialTypeLen() in the common case. */ - if( d1+serial_type1+2>(u32)nKey1 - && d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 + if( d1+(u64)serial_type1+2>(u64)nKey1 + && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1 ){ break; } /* Extract the values to be compared. */ - d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); + sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1); + d1 += sqlite3VdbeSerialTypeLen(serial_type1); /* Do the comparison */ - rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); + rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], + pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0); if( rc!=0 ){ assert( mem1.szMalloc==0 ); /* See comment below */ - if( pKeyInfo->aSortOrder[i] ){ + if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) + && ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null)) + ){ + rc = -rc; + } + if( pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC ){ rc = -rc; /* Invert the result for DESC sort order. */ } goto debugCompareEnd; @@ -74812,20 +83966,20 @@ static int vdbeRecordCompareDebug( } #endif -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG /* ** Count the number of fields (a.k.a. columns) in the record given by ** pKey,nKey. The verify that this count is less than or equal to the -** limit given by pKeyInfo->nField + pKeyInfo->nXField. +** limit given by pKeyInfo->nAllField. ** ** If this constraint is not satisfied, it means that the high-speed ** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will ** not work correctly. If this assert() ever fires, it probably means -** that the KeyInfo.nField or KeyInfo.nXField values were computed +** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed ** incorrectly. */ static void vdbeAssertFieldCountWithinLimits( - int nKey, const void *pKey, /* The record to verify */ + int nKey, const void *pKey, /* The record to verify */ const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */ ){ int nField = 0; @@ -74842,7 +83996,7 @@ static void vdbeAssertFieldCountWithinLimits( idx += getVarint32(aKey+idx, notUsed); nField++; } - assert( nField <= pKeyInfo->nField+pKeyInfo->nXField ); + assert( nField <= pKeyInfo->nAllField ); } #else # define vdbeAssertFieldCountWithinLimits(A,B,C) @@ -74851,7 +84005,7 @@ static void vdbeAssertFieldCountWithinLimits( /* ** Both *pMem1 and *pMem2 contain string values. Compare the two values ** using the collation sequence pColl. As usual, return a negative , zero -** or positive value if *pMem1 is less than, equal to or greater than +** or positive value if *pMem1 is less than, equal to or greater than ** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);". */ static int vdbeCompareMemString( @@ -74867,7 +84021,6 @@ static int vdbeCompareMemString( }else{ int rc; const void *v1, *v2; - int n1, n2; Mem c1; Mem c2; sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null); @@ -74875,11 +84028,13 @@ static int vdbeCompareMemString( sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem); sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem); v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc); - n1 = v1==0 ? 0 : c1.n; v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); - n2 = v2==0 ? 0 : c2.n; - rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2); - if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT; + if( (v1==0 || v2==0) ){ + if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; + rc = 0; + }else{ + rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); + } sqlite3VdbeMemRelease(&c1); sqlite3VdbeMemRelease(&c2); return rc; @@ -74903,7 +84058,7 @@ static int isAllZero(const char *z, int n){ ** is less than, equal to, or greater than the second, respectively. ** If one blob is a prefix of the other, then the shorter is the lessor. */ -static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ int c; int n1 = pB1->n; int n2 = pB2->n; @@ -74936,23 +84091,23 @@ static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){ ** number. Return negative, zero, or positive if the first (i64) is less than, ** equal to, or greater than the second (double). */ -static int sqlite3IntFloatCompare(i64 i, double r){ +SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){ if( sizeof(LONGDOUBLE_TYPE)>8 ){ LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; + testcase( xr ); + testcase( x==r ); if( xr ) return +1; - return 0; + if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */ + return 0; /*NO_TEST*/ /* work around bugs in gcov */ }else{ i64 y; double s; if( r<-9223372036854775808.0 ) return +1; - if( r>9223372036854775807.0 ) return -1; + if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( iy ){ - if( y==SMALLEST_INT64 && r>0.0 ) return -1; - return +1; - } + if( i>y ) return +1; s = (double)i; if( sr ) return +1; @@ -74976,8 +84131,8 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C f1 = pMem1->flags; f2 = pMem2->flags; combined_flags = f1|f2; - assert( (combined_flags & MEM_RowSet)==0 ); - + assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) ); + /* If one value is NULL, it is less than the other. If both values ** are NULL, return 0. */ @@ -74987,8 +84142,13 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C /* At least one of the two values is a number */ - if( combined_flags&(MEM_Int|MEM_Real) ){ - if( (f1 & f2 & MEM_Int)!=0 ){ + if( combined_flags&(MEM_Int|MEM_Real|MEM_IntReal) ){ + testcase( combined_flags & MEM_Int ); + testcase( combined_flags & MEM_Real ); + testcase( combined_flags & MEM_IntReal ); + if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & f2 & MEM_Int ); + testcase( f1 & f2 & MEM_IntReal ); if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; @@ -74998,15 +84158,23 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C if( pMem1->u.r > pMem2->u.r ) return +1; return 0; } - if( (f1&MEM_Int)!=0 ){ + if( (f1&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & MEM_Int ); + testcase( f1 & MEM_IntReal ); if( (f2&MEM_Real)!=0 ){ return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); + }else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ + if( pMem1->u.i < pMem2->u.i ) return -1; + if( pMem1->u.i > pMem2->u.i ) return +1; + return 0; }else{ return -1; } } if( (f1&MEM_Real)!=0 ){ - if( (f2&MEM_Int)!=0 ){ + if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f2 & MEM_Int ); + testcase( f2 & MEM_IntReal ); return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); }else{ return -1; @@ -75027,7 +84195,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C } assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed ); - assert( pMem1->enc==SQLITE_UTF8 || + assert( pMem1->enc==SQLITE_UTF8 || pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE ); /* The collation sequence must be defined at this point, even if @@ -75042,7 +84210,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C /* If a NULL pointer was passed as the collate function, fall through ** to the blob case and use memcmp(). */ } - + /* Both values must be blobs. Compare using memcmp(). */ return sqlite3BlobCompare(pMem1, pMem2); } @@ -75050,7 +84218,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C /* ** The first argument passed to this function is a serial-type that -** corresponds to an integer - all values between 1 and 9 inclusive +** corresponds to an integer - all values between 1 and 9 inclusive ** except 7. The second points to a buffer containing an integer value ** serialized according to serial_type. This function deserializes ** and returns the value. @@ -75092,7 +84260,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ /* ** This function compares the two table rows or index records ** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero -** or positive integer if key1 is less than, equal to or +** or positive integer if key1 is less than, equal to or ** greater than key2. The {nKey1, pKey1} key must be a blob ** created by the OP_MakeRecord opcode of the VDBE. The pPKey2 ** key must be a parsed key such as obtained from @@ -75101,12 +84269,12 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){ ** If argument bSkip is non-zero, it is assumed that the caller has already ** determined that the first fields of the keys are equal. ** -** Key1 and Key2 do not have to contain the same number of fields. If all -** fields that appear in both keys are equal, then pPKey2->default_rc is +** Key1 and Key2 do not have to contain the same number of fields. If all +** fields that appear in both keys are equal, then pPKey2->default_rc is ** returned. ** -** If database corruption is discovered, set pPKey2->errCode to -** SQLITE_CORRUPT and return 0. If an OOM error is encountered, +** If database corruption is discovered, set pPKey2->errCode to +** SQLITE_CORRUPT and return 0. If an OOM error is encountered, ** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the ** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db). */ @@ -75121,7 +84289,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( u32 idx1; /* Offset of first type in header */ int rc = 0; /* Return value */ Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */ - KeyInfo *pKeyInfo = pPKey2->pKeyInfo; + KeyInfo *pKeyInfo; const unsigned char *aKey1 = (const unsigned char *)pKey1; Mem mem1; @@ -75138,24 +84306,26 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( }else{ idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; - if( d1>(unsigned)nKey1 ){ - pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; - return 0; /* Corruption */ - } i = 0; } + if( d1>(unsigned)nKey1 ){ + pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; + return 0; /* Corruption */ + } VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */ - assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField + assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB ); - assert( pPKey2->pKeyInfo->aSortOrder!=0 ); - assert( pPKey2->pKeyInfo->nField>0 ); + assert( pPKey2->pKeyInfo->aSortFlags!=0 ); + assert( pPKey2->pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type; /* RHS is an integer */ - if( pRhs->flags & MEM_Int ){ + if( pRhs->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pRhs->flags & MEM_Int ); + testcase( pRhs->flags & MEM_IntReal ); serial_type = aKey1[idx1]; testcase( serial_type==12 ); if( serial_type>=10 ){ @@ -75181,7 +84351,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( serial_type = aKey1[idx1]; if( serial_type>=10 ){ /* Serial types 12 or greater are strings and blobs (greater than - ** numbers). Types 10 and 11 are currently "reserved for future + ** numbers). Types 10 and 11 are currently "reserved for future ** use", so it doesn't really matter what the results of comparing ** them to numberic values are. */ rc = +1; @@ -75203,7 +84373,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( /* RHS is a string */ else if( pRhs->flags & MEM_Str ){ - getVarint32(&aKey1[idx1], serial_type); + getVarint32NR(&aKey1[idx1], serial_type); testcase( serial_type==12 ); if( serial_type<12 ){ rc = -1; @@ -75213,7 +84383,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( mem1.n = (serial_type - 12) / 2; testcase( (d1+mem1.n)==(unsigned)nKey1 ); testcase( (d1+mem1.n+1)==(unsigned)nKey1 ); - if( (d1+mem1.n) > (unsigned)nKey1 ){ + if( (d1+mem1.n) > (unsigned)nKey1 + || (pKeyInfo = pPKey2->pKeyInfo)->nAllField<=i + ){ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT; return 0; /* Corruption */ }else if( pKeyInfo->aColl[i] ){ @@ -75227,7 +84399,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( }else{ int nCmp = MIN(mem1.n, pRhs->n); rc = memcmp(&aKey1[d1], pRhs->z, nCmp); - if( rc==0 ) rc = mem1.n - pRhs->n; + if( rc==0 ) rc = mem1.n - pRhs->n; } } } @@ -75235,7 +84407,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( /* RHS is a blob */ else if( pRhs->flags & MEM_Blob ){ assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); - getVarint32(&aKey1[idx1], serial_type); + getVarint32NR(&aKey1[idx1], serial_type); testcase( serial_type==12 ); if( serial_type<12 || (serial_type & 0x01) ){ rc = -1; @@ -75267,8 +84439,14 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( } if( rc!=0 ){ - if( pKeyInfo->aSortOrder[i] ){ - rc = -rc; + int sortFlags = pPKey2->pKeyInfo->aSortFlags[i]; + if( sortFlags ){ + if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0 + || ((sortFlags & KEYINFO_ORDER_DESC) + !=(serial_type==0 || (pRhs->flags&MEM_Null))) + ){ + rc = -rc; + } } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); assert( mem1.szMalloc==0 ); /* See comment below */ @@ -75276,10 +84454,11 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( } i++; + if( i==pPKey2->nField ) break; pRhs++; d1 += sqlite3VdbeSerialTypeLen(serial_type); idx1 += sqlite3VarintLen(serial_type); - }while( idx1<(unsigned)szHdr1 && inField && d1<=(unsigned)nKey1 ); + }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 ); /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a @@ -75289,9 +84468,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( /* rc==0 here means that one or both of the keys ran out of fields and ** all the fields up to that point were equal. Return the default_rc ** value. */ - assert( CORRUPT_DB - || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) - || pKeyInfo->db->mallocFailed + assert( CORRUPT_DB + || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) + || pPKey2->pKeyInfo->db->mallocFailed ); pPKey2->eqSeen = 1; return pPKey2->default_rc; @@ -75305,8 +84484,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( /* -** This function is an optimized version of sqlite3VdbeRecordCompare() -** that (a) the first field of pPKey2 is an integer, and (b) the +** This function is an optimized version of sqlite3VdbeRecordCompare() +** that (a) the first field of pPKey2 is an integer, and (b) the ** size-of-header varint at the start of (pKey1/nKey1) fits in a single ** byte (i.e. is less than 128). ** @@ -75361,7 +84540,7 @@ static int vdbeRecordCompareInt( testcase( lhs<0 ); break; } - case 8: + case 8: lhs = 0; break; case 9: @@ -75369,11 +84548,11 @@ static int vdbeRecordCompareInt( break; /* This case could be removed without changing the results of running - ** this code. Including it causes gcc to generate a faster switch + ** this code. Including it causes gcc to generate a faster switch ** statement (since the range of switch targets now starts at zero and ** is contiguous) but does not cause any duplicate code to be generated - ** (as gcc is clever enough to combine the two like cases). Other - ** compilers might be similar. */ + ** (as gcc is clever enough to combine the two like cases). Other + ** compilers might be similar. */ case 0: case 7: return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); @@ -75387,7 +84566,7 @@ static int vdbeRecordCompareInt( }else if( vr2; }else if( pPKey2->nField>1 ){ - /* The first fields of the two keys are equal. Compare the trailing + /* The first fields of the two keys are equal. Compare the trailing ** fields. */ res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1); }else{ @@ -75402,9 +84581,9 @@ static int vdbeRecordCompareInt( } /* -** This function is an optimized version of sqlite3VdbeRecordCompare() +** This function is an optimized version of sqlite3VdbeRecordCompare() ** that (a) the first field of pPKey2 is a string, that (b) the first field -** uses the collation sequence BINARY and (c) that the size-of-header varint +** uses the collation sequence BINARY and (c) that the size-of-header varint ** at the start of (pKey1/nKey1) fits in a single byte. */ static int vdbeRecordCompareString( @@ -75417,10 +84596,13 @@ static int vdbeRecordCompareString( assert( pPKey2->aMem[0].flags & MEM_Str ); vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); - getVarint32(&aKey1[1], serial_type); + serial_type = (u8)(aKey1[1]); + if( serial_type >= 0x80 ){ + sqlite3GetVarint32(&aKey1[1], (u32*)&serial_type); + } if( serial_type<12 ){ res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */ - }else if( !(serial_type & 0x01) ){ + }else if( !(serial_type & 0x01) ){ res = pPKey2->r2; /* (pKey1/nKey1) is a blob */ }else{ int nCmp; @@ -75435,7 +84617,11 @@ static int vdbeRecordCompareString( nCmp = MIN( pPKey2->aMem[0].n, nStr ); res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp); - if( res==0 ){ + if( res>0 ){ + res = pPKey2->r2; + }else if( res<0 ){ + res = pPKey2->r1; + }else{ res = nStr - pPKey2->aMem[0].n; if( res==0 ){ if( pPKey2->nField>1 ){ @@ -75449,10 +84635,6 @@ static int vdbeRecordCompareString( }else{ res = pPKey2->r1; } - }else if( res>0 ){ - res = pPKey2->r2; - }else{ - res = pPKey2->r1; } } @@ -75472,7 +84654,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ /* varintRecordCompareInt() and varintRecordCompareString() both assume ** that the size-of-header varint that occurs at the start of each record ** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt() - ** also assumes that it is safe to overread a buffer by at least the + ** also assumes that it is safe to overread a buffer by at least the ** maximum possible legal header size plus 8 bytes. Because there is ** guaranteed to be at least 74 (but not 136) bytes of padding following each ** buffer passed to varintRecordCompareInt() this makes it convenient to @@ -75482,9 +84664,12 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ ** The easiest way to enforce this limit is to consider only records with ** 13 fields or less. If the first field is an integer, the maximum legal ** header size is (12*5 + 1 + 1) bytes. */ - if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){ + if( p->pKeyInfo->nAllField<=13 ){ int flags = p->aMem[0].flags; - if( p->pKeyInfo->aSortOrder[0] ){ + if( p->pKeyInfo->aSortFlags[0] ){ + if( p->pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL ){ + return sqlite3VdbeRecordCompare; + } p->r1 = 1; p->r2 = -1; }else{ @@ -75497,7 +84682,9 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ testcase( flags & MEM_Real ); testcase( flags & MEM_Null ); testcase( flags & MEM_Blob ); - if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ + if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0 + && p->pKeyInfo->aColl[0]==0 + ){ assert( flags & MEM_Str ); return vdbeRecordCompareString; } @@ -75525,7 +84712,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so - ** this code can safely assume that nCellKey is 32-bits + ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); @@ -75533,22 +84720,24 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); - rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ){ return rc; } /* The index entry must begin with a header size */ - (void)getVarint32((u8*)m.z, szHdr); + getVarint32NR((u8*)m.z, szHdr); testcase( szHdr==3 ); - testcase( szHdr==m.n ); - if( unlikely(szHdr<3 || (int)szHdr>m.n) ){ + testcase( szHdr==(u32)m.n ); + testcase( szHdr>0x7fffffff ); + assert( m.n>=0 ); + if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){ goto idx_rowid_corruption; } /* The last field of the index should be an integer - the ROWID. ** Verify that the last entry really is an integer. */ - (void)getVarint32((u8*)&m.z[szHdr-1], typeRowid); + getVarint32NR((u8*)&m.z[szHdr-1], typeRowid); testcase( typeRowid==1 ); testcase( typeRowid==2 ); testcase( typeRowid==3 ); @@ -75588,7 +84777,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ ** ** pUnpacked is either created without a rowid or is truncated so that it ** omits the rowid at the end. The rowid at the end of the index entry -** is ignored as well. Hence, this routine only compares the prefixes +** is ignored as well. Hence, this routine only compares the prefixes ** of the keys prior to the final rowid, not the entire key. */ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( @@ -75613,20 +84802,20 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare( return SQLITE_CORRUPT_BKPT; } sqlite3VdbeMemInit(&m, db, 0); - rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); if( rc ){ return rc; } - *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); + *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0); sqlite3VdbeMemRelease(&m); return SQLITE_OK; } /* ** This routine sets the value to be returned by subsequent calls to -** sqlite3_changes() on the database handle 'db'. +** sqlite3_changes() on the database handle 'db'. */ -SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){ +SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, i64 nChange){ assert( sqlite3_mutex_held(db->mutex) ); db->nChange = nChange; db->nTotalChange += nChange; @@ -75649,11 +84838,19 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){ ** programs obsolete. Removing user-defined functions or collating ** sequences, or changing an authorization function are the types of ** things that make prepared statements obsolete. +** +** If iCode is 1, then expiration is advisory. The statement should +** be reprepared before being restarted, but if it is already running +** it is allowed to run to completion. +** +** Internally, this function just sets the Vdbe.expired flag on all +** prepared statements. The flag is set to 1 for an immediate expiration +** and set to 2 for an advisory expiration. */ -SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db){ +SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){ Vdbe *p; for(p = db->pVdbe; p; p=p->pNext){ - p->expired = 1; + p->expired = iCode+1; } } @@ -75664,9 +84861,16 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){ return v->db; } +/* +** Return the SQLITE_PREPARE flags for a Vdbe. +*/ +SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){ + return v->prepFlags; +} + /* ** Return a pointer to an sqlite3_value structure containing the value bound -** parameter iVar of VM v. Except, if the value is an SQL NULL, return +** parameter iVar of VM v. Except, if the value is an SQL NULL, return ** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_* ** constants) to the value before returning it. ** @@ -75676,6 +84880,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ @@ -75695,13 +84900,48 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff */ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ assert( iVar>0 ); - if( iVar>32 ){ - v->expmask = 0xffffffff; + assert( (v->db->flags & SQLITE_EnableQPSG)==0 ); + if( iVar>=32 ){ + v->expmask |= 0x80000000; }else{ v->expmask |= ((u32)1 << (iVar-1)); } } +/* +** Cause a function to throw an error if it was call from OP_PureFunc +** rather than OP_Function. +** +** OP_PureFunc means that the function must be deterministic, and should +** throw an error if it is given inputs that would make it non-deterministic. +** This routine is invoked by date/time functions that use non-deterministic +** features such as 'now'. +*/ +SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){ + const VdbeOp *pOp; +#ifdef SQLITE_ENABLE_STAT4 + if( pCtx->pVdbe==0 ) return 1; +#endif + pOp = pCtx->pVdbe->aOp + pCtx->iOp; + if( pOp->opcode==OP_PureFunc ){ + const char *zContext; + char *zMsg; + if( pOp->p5 & NC_IsCheck ){ + zContext = "a CHECK constraint"; + }else if( pOp->p5 & NC_GenCol ){ + zContext = "a generated column"; + }else{ + zContext = "an index"; + } + zMsg = sqlite3_mprintf("non-deterministic use of %s() in %s", + pCtx->pFunc->zName, zContext); + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); + return 0; + } + return 1; +} + #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored @@ -75722,7 +84962,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* -** If the second argument is not NULL, release any allocations associated +** If the second argument is not NULL, release any allocations associated ** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord ** structure itself, using sqlite3DbFree(). ** @@ -75736,7 +84976,7 @@ static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ Mem *pMem = &p->aMem[i]; if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem); } - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -75755,7 +84995,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( const char *zDb, /* Database name */ Table *pTab, /* Modified table */ i64 iKey1, /* Initial key value */ - int iReg /* Register for new.* record */ + int iReg, /* Register for new.* record */ + int iBlobWrite ){ sqlite3 *db = v->db; i64 iKey2; @@ -75776,7 +85017,9 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( } } - assert( pCsr->nField==pTab->nCol + assert( pCsr!=0 ); + assert( pCsr->eCurType==CURTYPE_BTREE ); + assert( pCsr->nField==pTab->nCol || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1) ); @@ -75786,24 +85029,25 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( preupdate.iNewReg = iReg; preupdate.keyinfo.db = db; preupdate.keyinfo.enc = ENC(db); - preupdate.keyinfo.nField = pTab->nCol; - preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder; + preupdate.keyinfo.nKeyField = pTab->nCol; + preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; + preupdate.iBlobWrite = iBlobWrite; db->pPreUpdate = &preupdate; db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2); db->pPreUpdate = 0; sqlite3DbFree(db, preupdate.aRecord); - vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pUnpacked); - vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pNewUnpacked); + vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked); + vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked); if( preupdate.aNew ){ int i; for(i=0; inField; i++){ sqlite3VdbeMemRelease(&preupdate.aNew[i]); } - sqlite3DbFree(db, preupdate.aNew); + sqlite3DbFreeNN(db, preupdate.aNew); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -75874,16 +85118,18 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; sqlite3_int64 iElapse; assert( p->startTime>0 ); - assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 ); + assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); iElapse = (iNow - p->startTime)*1000000; +#ifndef SQLITE_OMIT_DEPRECATED if( db->xProfile ){ db->xProfile(db->pProfileArg, p->zSql, iElapse); } +#endif if( db->mTrace & SQLITE_TRACE_PROFILE ){ - db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); + db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); } p->startTime = 0; } @@ -75966,7 +85212,8 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ sqlite3VdbeMemRelease(&p->aVar[i]); p->aVar[i].flags = MEM_Null; } - if( p->isPrepareV2 && p->expmask ){ + assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); + if( p->expmask ){ p->expired = 1; } sqlite3_mutex_leave(mutex); @@ -76010,6 +85257,19 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){ Mem *pMem = (Mem*)pVal; return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0); } +SQLITE_API void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){ + Mem *p = (Mem*)pVal; + if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) == + (MEM_Null|MEM_Term|MEM_Subtype) + && zPType!=0 + && p->eSubtype=='p' + && strcmp(p->u.zPType, zPType)==0 + ){ + return (void*)p->z; + }else{ + return 0; + } +} SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); } @@ -76030,42 +85290,99 @@ SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ */ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { - SQLITE_BLOB, /* 0x00 */ - SQLITE_NULL, /* 0x01 */ - SQLITE_TEXT, /* 0x02 */ - SQLITE_NULL, /* 0x03 */ - SQLITE_INTEGER, /* 0x04 */ - SQLITE_NULL, /* 0x05 */ - SQLITE_INTEGER, /* 0x06 */ - SQLITE_NULL, /* 0x07 */ - SQLITE_FLOAT, /* 0x08 */ - SQLITE_NULL, /* 0x09 */ - SQLITE_FLOAT, /* 0x0a */ - SQLITE_NULL, /* 0x0b */ - SQLITE_INTEGER, /* 0x0c */ - SQLITE_NULL, /* 0x0d */ - SQLITE_INTEGER, /* 0x0e */ - SQLITE_NULL, /* 0x0f */ - SQLITE_BLOB, /* 0x10 */ - SQLITE_NULL, /* 0x11 */ - SQLITE_TEXT, /* 0x12 */ - SQLITE_NULL, /* 0x13 */ - SQLITE_INTEGER, /* 0x14 */ - SQLITE_NULL, /* 0x15 */ - SQLITE_INTEGER, /* 0x16 */ - SQLITE_NULL, /* 0x17 */ - SQLITE_FLOAT, /* 0x18 */ - SQLITE_NULL, /* 0x19 */ - SQLITE_FLOAT, /* 0x1a */ - SQLITE_NULL, /* 0x1b */ - SQLITE_INTEGER, /* 0x1c */ - SQLITE_NULL, /* 0x1d */ - SQLITE_INTEGER, /* 0x1e */ - SQLITE_NULL, /* 0x1f */ + SQLITE_BLOB, /* 0x00 (not possible) */ + SQLITE_NULL, /* 0x01 NULL */ + SQLITE_TEXT, /* 0x02 TEXT */ + SQLITE_NULL, /* 0x03 (not possible) */ + SQLITE_INTEGER, /* 0x04 INTEGER */ + SQLITE_NULL, /* 0x05 (not possible) */ + SQLITE_INTEGER, /* 0x06 INTEGER + TEXT */ + SQLITE_NULL, /* 0x07 (not possible) */ + SQLITE_FLOAT, /* 0x08 FLOAT */ + SQLITE_NULL, /* 0x09 (not possible) */ + SQLITE_FLOAT, /* 0x0a FLOAT + TEXT */ + SQLITE_NULL, /* 0x0b (not possible) */ + SQLITE_INTEGER, /* 0x0c (not possible) */ + SQLITE_NULL, /* 0x0d (not possible) */ + SQLITE_INTEGER, /* 0x0e (not possible) */ + SQLITE_NULL, /* 0x0f (not possible) */ + SQLITE_BLOB, /* 0x10 BLOB */ + SQLITE_NULL, /* 0x11 (not possible) */ + SQLITE_TEXT, /* 0x12 (not possible) */ + SQLITE_NULL, /* 0x13 (not possible) */ + SQLITE_INTEGER, /* 0x14 INTEGER + BLOB */ + SQLITE_NULL, /* 0x15 (not possible) */ + SQLITE_INTEGER, /* 0x16 (not possible) */ + SQLITE_NULL, /* 0x17 (not possible) */ + SQLITE_FLOAT, /* 0x18 FLOAT + BLOB */ + SQLITE_NULL, /* 0x19 (not possible) */ + SQLITE_FLOAT, /* 0x1a (not possible) */ + SQLITE_NULL, /* 0x1b (not possible) */ + SQLITE_INTEGER, /* 0x1c (not possible) */ + SQLITE_NULL, /* 0x1d (not possible) */ + SQLITE_INTEGER, /* 0x1e (not possible) */ + SQLITE_NULL, /* 0x1f (not possible) */ + SQLITE_FLOAT, /* 0x20 INTREAL */ + SQLITE_NULL, /* 0x21 (not possible) */ + SQLITE_TEXT, /* 0x22 INTREAL + TEXT */ + SQLITE_NULL, /* 0x23 (not possible) */ + SQLITE_FLOAT, /* 0x24 (not possible) */ + SQLITE_NULL, /* 0x25 (not possible) */ + SQLITE_FLOAT, /* 0x26 (not possible) */ + SQLITE_NULL, /* 0x27 (not possible) */ + SQLITE_FLOAT, /* 0x28 (not possible) */ + SQLITE_NULL, /* 0x29 (not possible) */ + SQLITE_FLOAT, /* 0x2a (not possible) */ + SQLITE_NULL, /* 0x2b (not possible) */ + SQLITE_FLOAT, /* 0x2c (not possible) */ + SQLITE_NULL, /* 0x2d (not possible) */ + SQLITE_FLOAT, /* 0x2e (not possible) */ + SQLITE_NULL, /* 0x2f (not possible) */ + SQLITE_BLOB, /* 0x30 (not possible) */ + SQLITE_NULL, /* 0x31 (not possible) */ + SQLITE_TEXT, /* 0x32 (not possible) */ + SQLITE_NULL, /* 0x33 (not possible) */ + SQLITE_FLOAT, /* 0x34 (not possible) */ + SQLITE_NULL, /* 0x35 (not possible) */ + SQLITE_FLOAT, /* 0x36 (not possible) */ + SQLITE_NULL, /* 0x37 (not possible) */ + SQLITE_FLOAT, /* 0x38 (not possible) */ + SQLITE_NULL, /* 0x39 (not possible) */ + SQLITE_FLOAT, /* 0x3a (not possible) */ + SQLITE_NULL, /* 0x3b (not possible) */ + SQLITE_FLOAT, /* 0x3c (not possible) */ + SQLITE_NULL, /* 0x3d (not possible) */ + SQLITE_FLOAT, /* 0x3e (not possible) */ + SQLITE_NULL, /* 0x3f (not possible) */ }; +#ifdef SQLITE_DEBUG + { + int eType = SQLITE_BLOB; + if( pVal->flags & MEM_Null ){ + eType = SQLITE_NULL; + }else if( pVal->flags & (MEM_Real|MEM_IntReal) ){ + eType = SQLITE_FLOAT; + }else if( pVal->flags & MEM_Int ){ + eType = SQLITE_INTEGER; + }else if( pVal->flags & MEM_Str ){ + eType = SQLITE_TEXT; + } + assert( eType == aType[pVal->flags&MEM_AffMask] ); + } +#endif return aType[pVal->flags&MEM_AffMask]; } +/* Return true if a parameter to xUpdate represents an unchanged column */ +SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){ + return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero); +} + +/* Return true if a parameter value originated from an sqlite3_bind() */ +SQLITE_API int sqlite3_value_frombind(sqlite3_value *pVal){ + return (pVal->flags&MEM_FromBind)!=0; +} + /* Make a copy of an sqlite3_value object */ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ @@ -76094,15 +85411,15 @@ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){ sqlite3ValueFree(pOld); } - + /**************************** sqlite3_result_ ******************************* ** The following routines are used by user-defined functions to specify ** the function result. ** ** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the -** result as a string or blob but if the string or blob is too large, it -** then sets the error code to SQLITE_TOOBIG +** result as a string or blob. Appropriate errors are set if the string/blob +** is too big or if an OOM occurs. ** ** The invokeValueDestructor(P,X) routine invokes destructor function X() ** on value P is not going to be used and need to be destroyed. @@ -76114,8 +85431,16 @@ static void setResultStrOrError( u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ - if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){ - sqlite3_result_error_toobig(pCtx); + int rc = sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel); + if( rc ){ + if( rc==SQLITE_TOOBIG ){ + sqlite3_result_error_toobig(pCtx); + }else{ + /* The only errors possible from sqlite3VdbeMemSetStr are + ** SQLITE_TOOBIG and SQLITE_NOMEM */ + assert( rc==SQLITE_NOMEM ); + sqlite3_result_error_nomem(pCtx); + } } } static int invokeValueDestructor( @@ -76131,13 +85456,13 @@ static int invokeValueDestructor( }else{ xDel((void*)p); } - if( pCtx ) sqlite3_result_error_toobig(pCtx); + sqlite3_result_error_toobig(pCtx); return SQLITE_TOOBIG; } SQLITE_API void sqlite3_result_blob( - sqlite3_context *pCtx, - const void *z, - int n, + sqlite3_context *pCtx, + const void *z, + int n, void (*xDel)(void *) ){ assert( n>=0 ); @@ -76145,8 +85470,8 @@ SQLITE_API void sqlite3_result_blob( setResultStrOrError(pCtx, z, n, 0, xDel); } SQLITE_API void sqlite3_result_blob64( - sqlite3_context *pCtx, - const void *z, + sqlite3_context *pCtx, + const void *z, sqlite3_uint64 n, void (*xDel)(void *) ){ @@ -76165,14 +85490,12 @@ SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; - pCtx->fErrorOrAux = 1; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_ERROR; - pCtx->fErrorOrAux = 1; sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif @@ -76188,6 +85511,18 @@ SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); } +SQLITE_API void sqlite3_result_pointer( + sqlite3_context *pCtx, + void *pPtr, + const char *zPType, + void (*xDestructor)(void*) +){ + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + sqlite3VdbeMemRelease(pOut); + pOut->flags = MEM_Null; + sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor); +} SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pOut->db->mutex) ); @@ -76195,8 +85530,8 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubt pOut->flags |= MEM_Subtype; } SQLITE_API void sqlite3_result_text( - sqlite3_context *pCtx, - const char *z, + sqlite3_context *pCtx, + const char *z, int n, void (*xDel)(void *) ){ @@ -76204,8 +85539,8 @@ SQLITE_API void sqlite3_result_text( setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); } SQLITE_API void sqlite3_result_text64( - sqlite3_context *pCtx, - const char *z, + sqlite3_context *pCtx, + const char *z, sqlite3_uint64 n, void (*xDel)(void *), unsigned char enc @@ -76221,27 +85556,27 @@ SQLITE_API void sqlite3_result_text64( } #ifndef SQLITE_OMIT_UTF16 SQLITE_API void sqlite3_result_text16( - sqlite3_context *pCtx, - const void *z, - int n, + sqlite3_context *pCtx, + const void *z, + int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); } SQLITE_API void sqlite3_result_text16be( - sqlite3_context *pCtx, - const void *z, - int n, + sqlite3_context *pCtx, + const void *z, + int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); } SQLITE_API void sqlite3_result_text16le( - sqlite3_context *pCtx, - const void *z, - int n, + sqlite3_context *pCtx, + const void *z, + int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); @@ -76262,17 +85597,20 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){ if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){ return SQLITE_TOOBIG; } +#ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); return SQLITE_OK; +#else + return sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n); +#endif } SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ - pCtx->isError = errCode; - pCtx->fErrorOrAux = 1; + pCtx->isError = errCode ? errCode : -1; #ifdef SQLITE_DEBUG if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode; #endif if( pCtx->pOut->flags & MEM_Null ){ - sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, + sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, SQLITE_UTF8, SQLITE_STATIC); } } @@ -76281,8 +85619,7 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; - pCtx->fErrorOrAux = 1; - sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, + sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, SQLITE_UTF8, SQLITE_STATIC); } @@ -76291,12 +85628,26 @@ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM_BKPT; - pCtx->fErrorOrAux = 1; sqlite3OomFault(pCtx->pOut->db); } +#ifndef SQLITE_UNTESTABLE +/* Force the INT64 value currently stored as the result to be +** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL +** test-control. +*/ +SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + if( pCtx->pOut->flags & MEM_Int ){ + pCtx->pOut->flags &= ~MEM_Int; + pCtx->pOut->flags |= MEM_IntReal; + } +} +#endif + + /* -** This function is called after a transaction has been committed. It +** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. */ static int doWalCallbacks(sqlite3 *db){ @@ -76310,7 +85661,7 @@ static int doWalCallbacks(sqlite3 *db){ sqlite3BtreeEnter(pBt); nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); - if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){ + if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry); } } @@ -76325,7 +85676,7 @@ static int doWalCallbacks(sqlite3 *db){ ** statement is completely executed or an error occurs. ** ** This routine implements the bulk of the logic behind the sqlite_step() -** API. The only thing omitted is the automatic recompile if a +** API. The only thing omitted is the automatic recompile if a ** schema change has occurred. That detail is handled by the ** outer sqlite3_step() wrapper procedure. */ @@ -76334,20 +85685,20 @@ static int sqlite3Step(Vdbe *p){ int rc; assert(p); - if( p->magic!=VDBE_MAGIC_RUN ){ + if( p->iVdbeMagic!=VDBE_MAGIC_RUN ){ /* We used to require that sqlite3_reset() be called before retrying ** sqlite3_step() after any error or after SQLITE_DONE. But beginning ** with version 3.7.0, we changed this so that sqlite3_reset() would ** be called automatically instead of throwing the SQLITE_MISUSE error. - ** This "automatic-reset" change is not technically an incompatibility, + ** This "automatic-reset" change is not technically an incompatibility, ** since any application that receives an SQLITE_MISUSE is broken by ** definition. ** ** Nevertheless, some published applications that were originally written - ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE + ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE ** returns, and those were broken by the automatic-reset change. As a ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the - ** legacy behavior of returning SQLITE_MISUSE for cases where the + ** legacy behavior of returning SQLITE_MISUSE for cases where the ** previous sqlite3_step() returned something other than a SQLITE_LOCKED ** or SQLITE_BUSY error. */ @@ -76369,9 +85720,16 @@ static int sqlite3Step(Vdbe *p){ return SQLITE_NOMEM_BKPT; } - if( p->pc<=0 && p->expired ){ + if( p->pc<0 && p->expired ){ p->rc = SQLITE_SCHEMA; rc = SQLITE_ERROR; + if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ + /* If this statement was prepared using saved SQL and an + ** error has occurred, then return the error code in p->rc to the + ** caller. Set the error code in the database handle to the same value. + */ + rc = sqlite3VdbeTransferError(p); + } goto end_of_step; } if( p->pc<0 ){ @@ -76380,15 +85738,15 @@ static int sqlite3Step(Vdbe *p){ ** from interrupting a statement that has not yet started. */ if( db->nVdbeActive==0 ){ - db->u1.isInterrupted = 0; + AtomicStore(&db->u1.isInterrupted, 0); } - assert( db->nVdbeWrite>0 || db->autoCommit==0 + assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); #ifndef SQLITE_OMIT_TRACE - if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0) + if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 && !db->init.busy && p->zSql ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); }else{ @@ -76415,42 +85773,39 @@ static int sqlite3Step(Vdbe *p){ db->nVdbeExec--; } + if( rc!=SQLITE_ROW ){ #ifndef SQLITE_OMIT_TRACE - /* If the statement completed successfully, invoke the profile callback */ - if( rc!=SQLITE_ROW ) checkProfileCallback(db, p); + /* If the statement completed successfully, invoke the profile callback */ + checkProfileCallback(db, p); #endif - if( rc==SQLITE_DONE ){ - assert( p->rc==SQLITE_OK ); - p->rc = doWalCallbacks(db); - if( p->rc!=SQLITE_OK ){ - rc = SQLITE_ERROR; + if( rc==SQLITE_DONE && db->autoCommit ){ + assert( p->rc==SQLITE_OK ); + p->rc = doWalCallbacks(db); + if( p->rc!=SQLITE_OK ){ + rc = SQLITE_ERROR; + } + }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){ + /* If this statement was prepared using saved SQL and an + ** error has occurred, then return the error code in p->rc to the + ** caller. Set the error code in the database handle to the same value. + */ + rc = sqlite3VdbeTransferError(p); } } db->errCode = rc; if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){ p->rc = SQLITE_NOMEM_BKPT; + if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ) rc = p->rc; } end_of_step: - /* At this point local variable rc holds the value that should be - ** returned if this statement was compiled using the legacy - ** sqlite3_prepare() interface. According to the docs, this can only - ** be one of the values in the first assert() below. Variable p->rc - ** contains the value that would be returned if sqlite3_finalize() - ** were called on statement p. - */ - assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR + /* There are only a limited number of result codes allowed from the + ** statements prepared using the legacy sqlite3_prepare() interface */ + assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 + || rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); - assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); - if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ - /* If this statement was prepared using sqlite3_prepare_v2(), and an - ** error has occurred, then return the error code in p->rc to the - ** caller. Set the error code in the database handle to the same value. - */ - rc = sqlite3VdbeTransferError(p); - } return (rc&db->errMask); } @@ -76461,7 +85816,6 @@ static int sqlite3Step(Vdbe *p){ */ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; /* Result from sqlite3Step() */ - int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */ Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */ int cnt = 0; /* Counter to prevent infinite loop of reprepares */ sqlite3 *db; /* The database connection */ @@ -76475,32 +85829,31 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; - rc2 = rc = sqlite3Reprepare(v); - if( rc!=SQLITE_OK) break; + rc = sqlite3Reprepare(v); + if( rc!=SQLITE_OK ){ + /* This case occurs after failing to recompile an sql statement. + ** The error message from the SQL compiler has already been loaded + ** into the database handle. This block copies the error message + ** from the database handle into the statement and sets the statement + ** program counter to 0 to ensure that when the statement is + ** finalized or reset the parser error message is available via + ** sqlite3_errmsg() and sqlite3_errcode(). + */ + const char *zErr = (const char *)sqlite3_value_text(db->pErr); + sqlite3DbFree(db, v->zErrMsg); + if( !db->mallocFailed ){ + v->zErrMsg = sqlite3DbStrDup(db, zErr); + v->rc = rc = sqlite3ApiExit(db, rc); + } else { + v->zErrMsg = 0; + v->rc = rc = SQLITE_NOMEM_BKPT; + } + break; + } sqlite3_reset(pStmt); if( savedPc>=0 ) v->doingRerun = 1; assert( v->expired==0 ); } - if( rc2!=SQLITE_OK ){ - /* This case occurs after failing to recompile an sql statement. - ** The error message from the SQL compiler has already been loaded - ** into the database handle. This block copies the error message - ** from the database handle into the statement and sets the statement - ** program counter to 0 to ensure that when the statement is - ** finalized or reset the parser error message is available via - ** sqlite3_errmsg() and sqlite3_errcode(). - */ - const char *zErr = (const char *)sqlite3_value_text(db->pErr); - sqlite3DbFree(db, v->zErrMsg); - if( !db->mallocFailed ){ - v->zErrMsg = sqlite3DbStrDup(db, zErr); - v->rc = rc2; - } else { - v->zErrMsg = 0; - v->rc = rc = SQLITE_NOMEM_BKPT; - } - } - rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } @@ -76530,6 +85883,89 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ return p->pOut->db; } +/* +** If this routine is invoked from within an xColumn method of a virtual +** table, then it returns true if and only if the the call is during an +** UPDATE operation and the value of the column will not be modified +** by the UPDATE. +** +** If this routine is called from any context other than within the +** xColumn method of a virtual table, then the return value is meaningless +** and arbitrary. +** +** Virtual table implements might use this routine to optimize their +** performance by substituting a NULL result, or some other light-weight +** value, as a signal to the xUpdate routine that the column is unchanged. +*/ +SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){ + assert( p ); + return sqlite3_value_nochange(p->pOut); +} + +/* +** Implementation of sqlite3_vtab_in_first() (if bNext==0) and +** sqlite3_vtab_in_next() (if bNext!=0). +*/ +static int valueFromValueList( + sqlite3_value *pVal, /* Pointer to the ValueList object */ + sqlite3_value **ppOut, /* Store the next value from the list here */ + int bNext /* 1 for _next(). 0 for _first() */ +){ + int rc; + ValueList *pRhs; + + *ppOut = 0; + if( pVal==0 ) return SQLITE_MISUSE; + pRhs = (ValueList*)sqlite3_value_pointer(pVal, "ValueList"); + if( pRhs==0 ) return SQLITE_MISUSE; + if( bNext ){ + rc = sqlite3BtreeNext(pRhs->pCsr, 0); + }else{ + int dummy = 0; + rc = sqlite3BtreeFirst(pRhs->pCsr, &dummy); + assert( rc==SQLITE_OK || sqlite3BtreeEof(pRhs->pCsr) ); + if( sqlite3BtreeEof(pRhs->pCsr) ) rc = SQLITE_DONE; + } + if( rc==SQLITE_OK ){ + u32 sz; /* Size of current row in bytes */ + Mem sMem; /* Raw content of current row */ + memset(&sMem, 0, sizeof(sMem)); + sz = sqlite3BtreePayloadSize(pRhs->pCsr); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,(int)sz,&sMem); + if( rc==SQLITE_OK ){ + u8 *zBuf = (u8*)sMem.z; + u32 iSerial; + sqlite3_value *pOut = pRhs->pOut; + int iOff = 1 + getVarint32(&zBuf[1], iSerial); + sqlite3VdbeSerialGet(&zBuf[iOff], iSerial, pOut); + pOut->enc = ENC(pOut->db); + if( (pOut->flags & MEM_Ephem)!=0 && sqlite3VdbeMemMakeWriteable(pOut) ){ + rc = SQLITE_NOMEM; + }else{ + *ppOut = pOut; + } + } + sqlite3VdbeMemRelease(&sMem); + } + return rc; +} + +/* +** Set the iterator value pVal to point to the first value in the set. +** Set (*ppOut) to point to this value before returning. +*/ +SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut){ + return valueFromValueList(pVal, ppOut, 0); +} + +/* +** Set the iterator value pVal to point to the next value in the set. +** Set (*ppOut) to point to this value before returning. +*/ +SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut){ + return valueFromValueList(pVal, ppOut, 1); +} + /* ** Return the current time for a statement. If the current time ** is requested more than once within the same run of a single prepared @@ -76539,7 +85975,7 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ */ SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ int rc; -#ifndef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifndef SQLITE_ENABLE_STAT4 sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime; assert( p->pVdbe!=0 ); #else @@ -76553,28 +85989,6 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ return *piTime; } -/* -** The following is the implementation of an SQL function that always -** fails with an error message stating that the function is used in the -** wrong context. The sqlite3_overload_function() API might construct -** SQL function that use this routine so that the functions will exist -** for name resolution but are actually overloaded by the xFindFunction -** method of virtual tables. -*/ -SQLITE_PRIVATE void sqlite3InvalidFunction( - sqlite3_context *context, /* The function calling context */ - int NotUsed, /* Number of arguments to the function */ - sqlite3_value **NotUsed2 /* Value of each argument */ -){ - const char *zName = context->pFunc->zName; - char *zErr; - UNUSED_PARAMETER2(NotUsed, NotUsed2); - zErr = sqlite3_mprintf( - "unable to use function %s in the requested context", zName); - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); -} - /* ** Create a new aggregate context for p and return a pointer to ** its pMem->z element. @@ -76615,65 +86029,76 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ /* ** Return the auxiliary data pointer, if any, for the iArg'th argument to ** the user-function defined by pCtx. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then access a cache of +** auxiliary data pointers that is available to all functions within a +** single prepared statement. The iArg values must match. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); -#if SQLITE_ENABLE_STAT3_OR_STAT4 +#if SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 0; #else assert( pCtx->pVdbe!=0 ); #endif - for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ - if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + return pAuxData->pAux; + } } - - return (pAuxData ? pAuxData->pAux : 0); + return 0; } /* ** Set the auxiliary data pointer and delete function, for the iArg'th ** argument to the user-function defined by pCtx. Any previous value is ** deleted by calling the delete function specified when it was set. +** +** The left-most argument is 0. +** +** Undocumented behavior: If iArg is negative then make the data available +** to all functions within the current prepared statement using iArg as an +** access code. */ SQLITE_API void sqlite3_set_auxdata( - sqlite3_context *pCtx, - int iArg, - void *pAux, + sqlite3_context *pCtx, + int iArg, + void *pAux, void (*xDelete)(void*) ){ AuxData *pAuxData; Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - if( iArg<0 ) goto failed; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 if( pVdbe==0 ) goto failed; #else assert( pVdbe!=0 ); #endif - for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ - if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){ + if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){ + break; + } } if( pAuxData==0 ){ pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData)); if( !pAuxData ) goto failed; - pAuxData->iOp = pCtx->iOp; - pAuxData->iArg = iArg; - pAuxData->pNext = pVdbe->pAuxData; + pAuxData->iAuxOp = pCtx->iOp; + pAuxData->iAuxArg = iArg; + pAuxData->pNextAux = pVdbe->pAuxData; pVdbe->pAuxData = pAuxData; - if( pCtx->fErrorOrAux==0 ){ - pCtx->isError = 0; - pCtx->fErrorOrAux = 1; - } - }else if( pAuxData->xDelete ){ - pAuxData->xDelete(pAuxData->pAux); + if( pCtx->isError==0 ) pCtx->isError = -1; + }else if( pAuxData->xDeleteAux ){ + pAuxData->xDeleteAux(pAuxData->pAux); } pAuxData->pAux = pAux; - pAuxData->xDelete = xDelete; + pAuxData->xDeleteAux = xDelete; return; failed: @@ -76684,7 +86109,7 @@ SQLITE_API void sqlite3_set_auxdata( #ifndef SQLITE_OMIT_DEPRECATED /* -** Return the number of times the Step function of an aggregate has been +** Return the number of times the Step function of an aggregate has been ** called. ** ** This function is deprecated. Do not use it for new code. It is @@ -76729,9 +86154,9 @@ static const Mem *columnNullValue(void){ ** these assert()s from failing, when building with SQLITE_DEBUG defined ** using gcc, we force nullMem to be 8-byte aligned using the magical ** __attribute__((aligned(8))) macro. */ - static const Mem nullMem + static const Mem nullMem #if defined(SQLITE_DEBUG) && defined(__GNUC__) - __attribute__((aligned(8))) + __attribute__((aligned(8))) #endif = { /* .u = */ {0}, @@ -76747,7 +86172,7 @@ static const Mem *columnNullValue(void){ /* .xDel = */ (void(*)(void*))0, #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, - /* .pFiller = */ (void*)0, + /* .mScopyFlags= */ 0, #endif }; return &nullMem; @@ -76777,9 +86202,9 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){ } /* -** This function is called after invoking an sqlite3_value_XXX function on a +** This function is called after invoking an sqlite3_value_XXX function on a ** column value (i.e. a value returned by evaluating an SQL expression in the -** select list of a SELECT statement) that may cause a malloc() failure. If +** select list of a SELECT statement) that may cause a malloc() failure. If ** malloc() has failed, the threads mallocFailed flag is cleared and the result ** code of statement pStmt set to SQLITE_NOMEM. ** @@ -76818,8 +86243,8 @@ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){ const void *val; val = sqlite3_value_blob( columnMem(pStmt,i) ); /* Even though there is no encoding conversion, value_blob() might - ** need to call malloc() to expand the result of a zeroblob() - ** expression. + ** need to call malloc() to expand the result of a zeroblob() + ** expression. */ columnMallocFailure(pStmt); return val; @@ -76893,10 +86318,10 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ ** or a constant) then useTypes 2, 3, and 4 return NULL. */ static const void *columnName( - sqlite3_stmt *pStmt, - int N, - const void *(*xFunc)(Mem*), - int useType + sqlite3_stmt *pStmt, /* The statement */ + int N, /* Which column to get the name for */ + int useUtf16, /* True to return the name as UTF16 */ + int useType /* What type of name */ ){ const void *ret; Vdbe *p; @@ -76917,8 +86342,15 @@ static const void *columnName( N += useType*n; sqlite3_mutex_enter(db->mutex); assert( db->mallocFailed==0 ); - ret = xFunc(&p->aColName[N]); - /* A malloc may have failed inside of the xFunc() call. If this +#ifndef SQLITE_OMIT_UTF16 + if( useUtf16 ){ + ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); + }else +#endif + { + ret = sqlite3_value_text((sqlite3_value*)&p->aColName[N]); + } + /* A malloc may have failed inside of the _text() call. If this ** is the case, clear the mallocFailed flag and return NULL. */ if( db->mallocFailed ){ @@ -76935,13 +86367,11 @@ static const void *columnName( ** statement pStmt. */ SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME); + return columnName(pStmt, N, 0, COLNAME_NAME); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME); + return columnName(pStmt, N, 1, COLNAME_NAME); } #endif @@ -76960,13 +86390,11 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ ** of the result set of SQL statement pStmt. */ SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE); + return columnName(pStmt, N, 0, COLNAME_DECLTYPE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE); + return columnName(pStmt, N, 1, COLNAME_DECLTYPE); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_DECLTYPE */ @@ -76978,13 +86406,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE); + return columnName(pStmt, N, 0, COLNAME_DATABASE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE); + return columnName(pStmt, N, 1, COLNAME_DATABASE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -76994,13 +86420,11 @@ SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE); + return columnName(pStmt, N, 0, COLNAME_TABLE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE); + return columnName(pStmt, N, 1, COLNAME_TABLE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -77010,24 +86434,22 @@ SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN); + return columnName(pStmt, N, 0, COLNAME_COLUMN); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN); + return columnName(pStmt, N, 1, COLNAME_COLUMN); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_ENABLE_COLUMN_METADATA */ /******************************* sqlite3_bind_ *************************** -** +** ** Routines used to attach values to wildcards in a compiled SQL statement. */ /* -** Unbind the value bound to variable i in virtual machine p. This is the +** Unbind the value bound to variable i in virtual machine p. This is the ** the same as binding a NULL value to the column. If the "i" parameter is ** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK. ** @@ -77043,10 +86465,10 @@ static int vdbeUnbind(Vdbe *p, int i){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(p->db->mutex); - if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){ + if( p->iVdbeMagic!=VDBE_MAGIC_RUN || p->pc>=0 ){ sqlite3Error(p->db, SQLITE_MISUSE); sqlite3_mutex_leave(p->db->mutex); - sqlite3_log(SQLITE_MISUSE, + sqlite3_log(SQLITE_MISUSE, "bind on a busy prepared statement: [%s]", p->zSql); return SQLITE_MISUSE_BKPT; } @@ -77059,20 +86481,19 @@ static int vdbeUnbind(Vdbe *p, int i){ pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; - sqlite3Error(p->db, SQLITE_OK); + p->db->errCode = SQLITE_OK; - /* If the bit corresponding to this variable in Vdbe.expmask is set, then + /* If the bit corresponding to this variable in Vdbe.expmask is set, then ** binding a new value to this variable invalidates the current query plan. ** - ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host + ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host ** parameter in the WHERE clause might influence the choice of query plan ** for a statement, then the statement will be automatically recompiled, ** as if there had been a schema change, on the first sqlite3_step() call ** following any change to the bindings of that parameter. */ - if( p->isPrepareV2 && - ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff) - ){ + assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 ); + if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<expired = 1; } return SQLITE_OK; @@ -77085,7 +86506,7 @@ static int bindText( sqlite3_stmt *pStmt, /* The statement to bind against */ int i, /* Index of the parameter to bind */ const void *zData, /* Pointer to the data to be bound */ - int nData, /* Number of bytes of data to be bound */ + i64 nData, /* Number of bytes of data to be bound */ void (*xDel)(void*), /* Destructor for the data */ u8 encoding /* Encoding for the data */ ){ @@ -77101,8 +86522,10 @@ static int bindText( if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } - sqlite3Error(p->db, rc); - rc = sqlite3ApiExit(p->db, rc); + if( rc ){ + sqlite3Error(p->db, rc); + rc = sqlite3ApiExit(p->db, rc); + } } sqlite3_mutex_leave(p->db->mutex); }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){ @@ -77116,10 +86539,10 @@ static int bindText( ** Bind a blob value to an SQL statement variable. */ SQLITE_API int sqlite3_bind_blob( - sqlite3_stmt *pStmt, - int i, - const void *zData, - int nData, + sqlite3_stmt *pStmt, + int i, + const void *zData, + int nData, void (*xDel)(void*) ){ #ifdef SQLITE_ENABLE_API_ARMOR @@ -77128,18 +86551,14 @@ SQLITE_API int sqlite3_bind_blob( return bindText(pStmt, i, zData, nData, xDel, 0); } SQLITE_API int sqlite3_bind_blob64( - sqlite3_stmt *pStmt, - int i, - const void *zData, - sqlite3_uint64 nData, + sqlite3_stmt *pStmt, + int i, + const void *zData, + sqlite3_uint64 nData, void (*xDel)(void*) ){ assert( xDel!=SQLITE_DYNAMIC ); - if( nData>0x7fffffff ){ - return invokeValueDestructor(zData, xDel, 0); - }else{ - return bindText(pStmt, i, zData, (int)nData, xDel, 0); - } + return bindText(pStmt, i, zData, nData, xDel, 0); } SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int rc; @@ -77173,37 +86592,51 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ } return rc; } -SQLITE_API int sqlite3_bind_text( - sqlite3_stmt *pStmt, - int i, - const char *zData, - int nData, +SQLITE_API int sqlite3_bind_pointer( + sqlite3_stmt *pStmt, + int i, + void *pPtr, + const char *zPTtype, + void (*xDestructor)(void*) +){ + int rc; + Vdbe *p = (Vdbe*)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor); + sqlite3_mutex_leave(p->db->mutex); + }else if( xDestructor ){ + xDestructor(pPtr); + } + return rc; +} +SQLITE_API int sqlite3_bind_text( + sqlite3_stmt *pStmt, + int i, + const char *zData, + int nData, void (*xDel)(void*) ){ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); } -SQLITE_API int sqlite3_bind_text64( - sqlite3_stmt *pStmt, - int i, - const char *zData, - sqlite3_uint64 nData, +SQLITE_API int sqlite3_bind_text64( + sqlite3_stmt *pStmt, + int i, + const char *zData, + sqlite3_uint64 nData, void (*xDel)(void*), unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); - if( nData>0x7fffffff ){ - return invokeValueDestructor(zData, xDel, 0); - }else{ - if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; - return bindText(pStmt, i, zData, (int)nData, xDel, enc); - } + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + return bindText(pStmt, i, zData, nData, xDel, enc); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API int sqlite3_bind_text16( - sqlite3_stmt *pStmt, - int i, - const void *zData, - int nData, + sqlite3_stmt *pStmt, + int i, + const void *zData, + int nData, void (*xDel)(void*) ){ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); @@ -77217,7 +86650,10 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu break; } case SQLITE_FLOAT: { - rc = sqlite3_bind_double(pStmt, i, pValue->u.r); + assert( pValue->flags & (MEM_Real|MEM_IntReal) ); + rc = sqlite3_bind_double(pStmt, i, + (pValue->flags & MEM_Real) ? pValue->u.r : (double)pValue->u.i + ); break; } case SQLITE_BLOB: { @@ -77245,7 +86681,11 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ +#ifndef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); +#else + rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); +#endif sqlite3_mutex_leave(p->db->mutex); } return rc; @@ -77267,7 +86707,7 @@ SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint6 /* ** Return the number of wildcards that can be potentially bound to. -** This routine is added to support DBD::SQLite. +** This routine is added to support DBD::SQLite. */ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; @@ -77335,10 +86775,12 @@ SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt * if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } - if( pTo->isPrepareV2 && pTo->expmask ){ + assert( (pTo->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pTo->expmask==0 ); + if( pTo->expmask ){ pTo->expired = 1; } - if( pFrom->isPrepareV2 && pFrom->expmask ){ + assert( (pFrom->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pFrom->expmask==0 ); + if( pFrom->expmask ){ pFrom->expired = 1; } return sqlite3TransferBindings(pFromStmt, pToStmt); @@ -77363,12 +86805,20 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1; } +/* +** Return 1 if the statement is an EXPLAIN and return 2 if the +** statement is an EXPLAIN QUERY PLAN +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){ + return pStmt ? ((Vdbe*)pStmt)->explain : 0; +} + /* ** Return true if the prepared statement is in need of being reset. */ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; - return v!=0 && v->magic==VDBE_MAGIC_RUN && v->pc>=0; + return v!=0 && v->iVdbeMagic==VDBE_MAGIC_RUN && v->pc>=0; } /* @@ -77402,13 +86852,26 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){ Vdbe *pVdbe = (Vdbe*)pStmt; u32 v; #ifdef SQLITE_ENABLE_API_ARMOR - if( !pStmt ){ + if( !pStmt + || (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter))) + ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - v = pVdbe->aCounter[op]; - if( resetFlag ) pVdbe->aCounter[op] = 0; + if( op==SQLITE_STMTSTATUS_MEMUSED ){ + sqlite3 *db = pVdbe->db; + sqlite3_mutex_enter(db->mutex); + v = 0; + db->pnBytesFreed = (int*)&v; + sqlite3VdbeClearObject(db, pVdbe); + sqlite3DbFree(db, pVdbe); + db->pnBytesFreed = 0; + sqlite3_mutex_leave(db->mutex); + }else{ + v = pVdbe->aCounter[op]; + if( resetFlag ) pVdbe->aCounter[op] = 0; + } return (int)v; } @@ -77445,6 +86908,22 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ #endif } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Return the normalized SQL associated with a prepared statement. +*/ +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + if( p==0 ) return 0; + if( p->zNormSql==0 && ALWAYS(p->zSql!=0) ){ + sqlite3_mutex_enter(p->db->mutex); + p->zNormSql = sqlite3Normalize(p, p->zSql); + sqlite3_mutex_leave(p->db->mutex); + } + return p->zNormSql; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized @@ -77452,15 +86931,15 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ ** if successful, or a NULL pointer if an OOM error is encountered. */ static UnpackedRecord *vdbeUnpackRecord( - KeyInfo *pKeyInfo, - int nKey, + KeyInfo *pKeyInfo, + int nKey, const void *pKey ){ UnpackedRecord *pRet; /* Return value */ pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo); if( pRet ){ - memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1)); + memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1)); sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet); } return pRet; @@ -77482,7 +86961,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa goto preupdate_old_out; } if( p->pPk ){ - iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; @@ -77494,6 +86973,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa u32 nRec; u8 *aRec; + assert( p->pCsr->eCurType==CURTYPE_BTREE ); nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); aRec = sqlite3DbMallocRaw(db, nRec); if( !aRec ) goto preupdate_old_out; @@ -77515,7 +86995,9 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa }else if( iIdx>=p->pUnpacked->nField ){ *ppValue = (sqlite3_value *)columnNullValue(); }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ - if( pMem->flags & MEM_Int ){ + if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pMem); } } @@ -77533,7 +87015,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa */ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ PreUpdate *p = db->pPreUpdate; - return (p ? p->keyinfo.nField : 0); + return (p ? p->keyinfo.nKeyField : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ @@ -77543,7 +87025,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){ ** only. It returns zero if the change that caused the callback was made ** immediately by a user SQL statement. Or, if the change was made by a ** trigger program, it returns the number of trigger programs currently -** on the stack (1 for a top-level trigger, 2 for a trigger fired by a +** on the stack (1 for a top-level trigger, 2 for a trigger fired by a ** top-level trigger etc.). ** ** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL @@ -77555,6 +87037,17 @@ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){ } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** This function is designed to be called from within a pre-update callback +** only. +*/ +SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){ + PreUpdate *p = db->pPreUpdate; + return (p ? p->iBlobWrite : -1); +} +#endif + #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** This function is called from within a pre-update callback to retrieve @@ -77570,7 +87063,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa goto preupdate_new_out; } if( p->pPk && p->op!=SQLITE_UPDATE ){ - iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; @@ -77752,8 +87245,8 @@ static int findNextHostParameter(const char *zSql, int *pnToken){ /* ** This function returns a pointer to a nul-terminated string in memory ** obtained from sqlite3DbMalloc(). If sqlite3.nVdbeExec is 1, then the -** string contains a copy of zRawSql but with host parameters expanded to -** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1, +** string contains a copy of zRawSql but with host parameters expanded to +** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1, ** then the returned string holds a copy of zRawSql with "-- " prepended ** to each line of text. ** @@ -77786,28 +87279,26 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ #ifndef SQLITE_OMIT_UTF16 - Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */ + Mem utf8; /* Used to convert UTF16 into UTF8 for display */ #endif - char zBase[100]; /* Initial working space */ db = p->db; - sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), - db->aLimit[SQLITE_LIMIT_LENGTH]); + sqlite3StrAccumInit(&out, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; while( *(zRawSql++)!='\n' && *zRawSql ); - sqlite3StrAccumAppend(&out, "-- ", 3); + sqlite3_str_append(&out, "-- ", 3); assert( (zRawSql - zStart) > 0 ); - sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart)); + sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart)); } }else if( p->nVar==0 ){ - sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql)); + sqlite3_str_append(&out, zRawSql, sqlite3Strlen30(zRawSql)); }else{ while( zRawSql[0] ){ n = findNextHostParameter(zRawSql, &nToken); assert( n>0 ); - sqlite3StrAccumAppend(&out, zRawSql, n); + sqlite3_str_append(&out, zRawSql, n); zRawSql += n; assert( zRawSql[0] || nToken==0 ); if( nToken==0 ) break; @@ -77829,15 +87320,15 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( assert( idx>0 ); } zRawSql += nToken; - nextIndex = idx + 1; + nextIndex = MAX(idx + 1, nextIndex); assert( idx>0 && idx<=p->nVar ); pVar = &p->aVar[idx-1]; if( pVar->flags & MEM_Null ){ - sqlite3StrAccumAppend(&out, "NULL", 4); - }else if( pVar->flags & MEM_Int ){ - sqlite3XPrintf(&out, "%lld", pVar->u.i); + sqlite3_str_append(&out, "NULL", 4); + }else if( pVar->flags & (MEM_Int|MEM_IntReal) ){ + sqlite3_str_appendf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ - sqlite3XPrintf(&out, "%!.15g", pVar->u.r); + sqlite3_str_appendf(&out, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 @@ -77847,7 +87338,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){ - out.accError = STRACCUM_NOMEM; + out.accError = SQLITE_NOMEM; out.nAlloc = 0; } pVar = &utf8; @@ -77859,39 +87350,39 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( nOut = SQLITE_TRACE_SIZE_LIMIT; while( nOutn && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; } } -#endif - sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z); +#endif + sqlite3_str_appendf(&out, "'%.*q'", nOut, pVar->z); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ - sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); + sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif #ifndef SQLITE_OMIT_UTF16 if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8); #endif }else if( pVar->flags & MEM_Zero ){ - sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero); + sqlite3_str_appendf(&out, "zeroblob(%d)", pVar->u.nZero); }else{ int nOut; /* Number of bytes of the blob to include in output */ assert( pVar->flags & MEM_Blob ); - sqlite3StrAccumAppend(&out, "x'", 2); + sqlite3_str_append(&out, "x'", 2); nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT; #endif for(i=0; iz[i]&0xff); + sqlite3_str_appendf(&out, "%02x", pVar->z[i]&0xff); } - sqlite3StrAccumAppend(&out, "'", 1); + sqlite3_str_append(&out, "'", 1); #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOutn ){ - sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); + sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif } } } - if( out.accError ) sqlite3StrAccumReset(&out); + if( out.accError ) sqlite3_str_reset(&out); return sqlite3StrAccumFinish(&out); } @@ -78018,48 +87509,104 @@ SQLITE_API int sqlite3_found_count = 0; # define UPDATE_MAX_BLOBSIZE(P) #endif +#ifdef SQLITE_DEBUG +/* This routine provides a convenient place to set a breakpoint during +** tracing with PRAGMA vdbe_trace=on. The breakpoint fires right after +** each opcode is printed. Variables "pc" (program counter) and pOp are +** available to add conditionals to the breakpoint. GDB example: +** +** break test_trace_breakpoint if pc=22 +** +** Other useful labels for breakpoints include: +** test_addop_breakpoint(pc,pOp) +** sqlite3CorruptError(lineno) +** sqlite3MisuseError(lineno) +** sqlite3CantopenError(lineno) +*/ +static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){ + static int n = 0; + n++; +} +#endif + /* ** Invoke the VDBE coverage callback, if that callback is defined. This ** feature is used for test suite validation only and does not appear an ** production builds. ** -** M is an integer, 2 or 3, that indices how many different ways the -** branch can go. It is usually 2. "I" is the direction the branch -** goes. 0 means falls through. 1 means branch is taken. 2 means the -** second alternative branch is taken. +** M is the type of branch. I is the direction taken for this instance of +** the branch. +** +** M: 2 - two-way branch (I=0: fall-thru 1: jump ) +** 3 - two-way + NULL (I=0: fall-thru 1: jump 2: NULL ) +** 4 - OP_Jump (I=0: jump p1 1: jump p2 2: jump p3) +** +** In other words, if M is 2, then I is either 0 (for fall-through) or +** 1 (for when the branch is taken). If M is 3, the I is 0 for an +** ordinary fall-through, I is 1 if the branch was taken, and I is 2 +** if the result of comparison is NULL. For M=3, I=2 the jump may or +** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5. +** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2 +** depending on if the operands are less than, equal, or greater than. ** ** iSrcLine is the source code line (from the __LINE__ macro) that -** generated the VDBE instruction. This instrumentation assumes that all -** source code is in a single file (the amalgamation). Special values 1 -** and 2 for the iSrcLine parameter mean that this particular branch is -** always taken or never taken, respectively. +** generated the VDBE instruction combined with flag bits. The source +** code line number is in the lower 24 bits of iSrcLine and the upper +** 8 bytes are flags. The lower three bits of the flags indicate +** values for I that should never occur. For example, if the branch is +** always taken, the flags should be 0x05 since the fall-through and +** alternate branch are never taken. If a branch is never taken then +** flags should be 0x06 since only the fall-through approach is allowed. +** +** Bit 0x08 of the flags indicates an OP_Jump opcode that is only +** interested in equal or not-equal. In other words, I==0 and I==2 +** should be treated as equivalent +** +** Since only a line number is retained, not the filename, this macro +** only works for amalgamation builds. But that is ok, since these macros +** should be no-ops except for special builds used to measure test coverage. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) #else # define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M) - static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){ - if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){ - M = iSrcLine; - /* Assert the truth of VdbeCoverageAlwaysTaken() and - ** VdbeCoverageNeverTaken() */ - assert( (M & I)==I ); - }else{ - if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ - sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, - iSrcLine,I,M); + static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){ + u8 mNever; + assert( I<=2 ); /* 0: fall through, 1: taken, 2: alternate taken */ + assert( M<=4 ); /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */ + assert( I> 24; + assert( (I & mNever)==0 ); + if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ + /* Invoke the branch coverage callback with three arguments: + ** iSrcLine - the line number of the VdbeCoverage() macro, with + ** flags removed. + ** I - Mask of bits 0x07 indicating which cases are are + ** fulfilled by this instance of the jump. 0x01 means + ** fall-thru, 0x02 means taken, 0x04 means NULL. Any + ** impossible cases (ex: if the comparison is never NULL) + ** are filled in automatically so that the coverage + ** measurement logic does not flag those impossible cases + ** as missed coverage. + ** M - Type of jump. Same as M argument above + */ + I |= mNever; + if( M==2 ) I |= 0x04; + if( M==4 ){ + I |= 0x08; + if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/ } + sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, + iSrcLine&0xffffff, I, M); } #endif -/* -** Convert the given register into a string if it isn't one -** already. Return non-zero if a malloc() fails. -*/ -#define Stringify(P, enc) \ - if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ - { goto no_mem; } - /* ** An ephemeral string value (signified by the MEM_Ephem flag) contains ** a pointer to a dynamically allocated string where some other entity @@ -78086,11 +87633,10 @@ static VdbeCursor *allocateCursor( Vdbe *p, /* The virtual machine */ int iCur, /* Index of the new VdbeCursor */ int nField, /* Number of fields in the table or index */ - int iDb, /* Database the cursor belongs to, or -1 */ u8 eCurType /* Type of the new cursor */ ){ /* Find the memory cell that will be used to store the blob of memory - ** required for this VdbeCursor structure. It is convenient to use a + ** required for this VdbeCursor structure. It is convenient to use a ** vdbe memory cell to manage the memory allocation required for a ** VdbeCursor structure for the following reasons: ** @@ -78111,8 +87657,8 @@ static VdbeCursor *allocateCursor( int nByte; VdbeCursor *pCx = 0; - nByte = - ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + + nByte = + ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); assert( iCur>=0 && iCurnCursor ); @@ -78120,22 +87666,54 @@ static VdbeCursor *allocateCursor( sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } - if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ - p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; - memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); - pCx->eCurType = eCurType; - pCx->iDb = iDb; - pCx->nField = nField; - pCx->aOffset = &pCx->aType[nField]; - if( eCurType==CURTYPE_BTREE ){ - pCx->uc.pCursor = (BtCursor*) - &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; - sqlite3BtreeCursorZero(pCx->uc.pCursor); + + /* There used to be a call to sqlite3VdbeMemClearAndResize() to make sure + ** the pMem used to hold space for the cursor has enough storage available + ** in pMem->zMalloc. But for the special case of the aMem[] entries used + ** to hold cursors, it is faster to in-line the logic. */ + assert( pMem->flags==MEM_Undefined ); + assert( (pMem->flags & MEM_Dyn)==0 ); + assert( pMem->szMalloc==0 || pMem->z==pMem->zMalloc ); + if( pMem->szMallocszMalloc>0 ){ + sqlite3DbFreeNN(pMem->db, pMem->zMalloc); } + pMem->z = pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, nByte); + if( pMem->zMalloc==0 ){ + pMem->szMalloc = 0; + return 0; + } + pMem->szMalloc = nByte; + } + + p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc; + memset(pCx, 0, offsetof(VdbeCursor,pAltCursor)); + pCx->eCurType = eCurType; + pCx->nField = nField; + pCx->aOffset = &pCx->aType[nField]; + if( eCurType==CURTYPE_BTREE ){ + pCx->uc.pCursor = (BtCursor*) + &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField]; + sqlite3BtreeCursorZero(pCx->uc.pCursor); } return pCx; } +/* +** The string in pRec is known to look like an integer and to have a +** floating point value of rValue. Return true and set *piValue to the +** integer value if the string is in range to be an integer. Otherwise, +** return false. +*/ +static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ + i64 iValue = (double)rValue; + if( sqlite3RealSameAsInt(rValue,iValue) ){ + *piValue = iValue; + return 1; + } + return 0==sqlite3Atoi64(pRec->z, piValue, pRec->n, pRec->enc); +} + /* ** Try to convert a value into a numeric representation if we can ** do so without loss of information. In other words, if the string @@ -78153,18 +87731,23 @@ static VdbeCursor *allocateCursor( */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; - i64 iValue; u8 enc = pRec->enc; - assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); - if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; - if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ - pRec->u.i = iValue; + int rc; + assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); + rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); + if( rc<=0 ) return; + if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; pRec->flags |= MEM_Real; if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); } + /* TEXT->NUMERIC is many->one. Hence, it is important to invalidate the + ** string representation after computing a numeric equivalent, because the + ** string representation might not be the canonical representation for the + ** numeric value. Ticket [343634942dd54ab57b7024] 2018-01-31. */ + pRec->flags &= ~MEM_Str; } /* @@ -78173,7 +87756,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ ** SQLITE_AFF_INTEGER: ** SQLITE_AFF_REAL: ** SQLITE_AFF_NUMERIC: -** Try to convert pRec to an integer representation or a +** Try to convert pRec to an integer representation or a ** floating-point representation if an integer representation ** is not possible. Note that the integer representation is ** always preferred, even if the affinity is REAL, because @@ -78183,6 +87766,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ ** Convert pRec to a text representation. ** ** SQLITE_AFF_BLOB: +** SQLITE_AFF_NONE: ** No-op. pRec is unchanged. */ static void applyAffinity( @@ -78203,15 +87787,18 @@ static void applyAffinity( }else if( affinity==SQLITE_AFF_TEXT ){ /* Only attempt the conversion to TEXT if there is an integer or real ** representation (blob and NULL do not get converted) but no string - ** representation. It would be harmless to repeat the conversion if + ** representation. It would be harmless to repeat the conversion if ** there is already a string rep, but it is pointless to waste those ** CPU cycles. */ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ - if( (pRec->flags&(MEM_Real|MEM_Int)) ){ + if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){ + testcase( pRec->flags & MEM_Int ); + testcase( pRec->flags & MEM_Real ); + testcase( pRec->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pRec, enc, 1); } } - pRec->flags &= ~(MEM_Real|MEM_Int); + pRec->flags &= ~(MEM_Real|MEM_Int|MEM_IntReal); } } @@ -78232,12 +87819,12 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ } /* -** Exported version of applyAffinity(). This one works on sqlite3_value*, +** Exported version of applyAffinity(). This one works on sqlite3_value*, ** not the internal Mem* type. */ SQLITE_PRIVATE void sqlite3ValueApplyAffinity( - sqlite3_value *pVal, - u8 affinity, + sqlite3_value *pVal, + u8 affinity, u8 enc ){ applyAffinity((Mem *)pVal, affinity, enc); @@ -78250,12 +87837,24 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity( ** accordingly. */ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ - assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); + int rc; + sqlite3_int64 ix; + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ); assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); - if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ - return 0; + if( ExpandBlob(pMem) ){ + pMem->u.i = 0; + return MEM_Int; } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ + rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( rc<=0 ){ + if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ + pMem->u.i = ix; + return MEM_Int; + }else{ + return MEM_Real; + } + }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ + pMem->u.i = ix; return MEM_Int; } return MEM_Real; @@ -78263,16 +87862,21 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ /* ** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or -** none. +** none. ** ** Unlike applyNumericAffinity(), this routine does not modify pMem->flags. ** But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem){ - if( pMem->flags & (MEM_Int|MEM_Real) ){ - return pMem->flags & (MEM_Int|MEM_Real); + if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); + return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal); } if( pMem->flags & (MEM_Str|MEM_Blob) ){ + testcase( pMem->flags & MEM_Str ); + testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); } return 0; @@ -78283,12 +87887,9 @@ static u16 numericType(Mem *pMem){ ** Write a nice string representation of the contents of cell pMem ** into buffer zBuf, length nBuf. */ -SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ - char *zCsr = zBuf; +SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){ int f = pMem->flags; - static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"}; - if( f&MEM_Blob ){ int i; char c; @@ -78304,59 +87905,40 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ }else{ c = 's'; } - - sqlite3_snprintf(100, zCsr, "%c", c); - zCsr += sqlite3Strlen30(zCsr); - sqlite3_snprintf(100, zCsr, "%d[", pMem->n); - zCsr += sqlite3Strlen30(zCsr); - for(i=0; i<16 && in; i++){ - sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF)); - zCsr += sqlite3Strlen30(zCsr); + sqlite3_str_appendf(pStr, "%cx[", c); + for(i=0; i<25 && in; i++){ + sqlite3_str_appendf(pStr, "%02X", ((int)pMem->z[i] & 0xFF)); } - for(i=0; i<16 && in; i++){ + sqlite3_str_appendf(pStr, "|"); + for(i=0; i<25 && in; i++){ char z = pMem->z[i]; - if( z<32 || z>126 ) *zCsr++ = '.'; - else *zCsr++ = z; + sqlite3_str_appendchar(pStr, 1, (z<32||z>126)?'.':z); } - - sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]); - zCsr += sqlite3Strlen30(zCsr); + sqlite3_str_appendf(pStr,"]"); if( f & MEM_Zero ){ - sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero); - zCsr += sqlite3Strlen30(zCsr); + sqlite3_str_appendf(pStr, "+%dz",pMem->u.nZero); } - *zCsr = '\0'; }else if( f & MEM_Str ){ - int j, k; - zBuf[0] = ' '; + int j; + u8 c; if( f & MEM_Dyn ){ - zBuf[1] = 'z'; + c = 'z'; assert( (f & (MEM_Static|MEM_Ephem))==0 ); }else if( f & MEM_Static ){ - zBuf[1] = 't'; + c = 't'; assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); }else if( f & MEM_Ephem ){ - zBuf[1] = 'e'; + c = 'e'; assert( (f & (MEM_Static|MEM_Dyn))==0 ); }else{ - zBuf[1] = 's'; + c = 's'; } - k = 2; - sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n); - k += sqlite3Strlen30(&zBuf[k]); - zBuf[k++] = '['; - for(j=0; j<15 && jn; j++){ - u8 c = pMem->z[j]; - if( c>=0x20 && c<0x7f ){ - zBuf[k++] = c; - }else{ - zBuf[k++] = '.'; - } + sqlite3_str_appendf(pStr, " %c%d[", c, pMem->n); + for(j=0; j<25 && jn; j++){ + c = pMem->z[j]; + sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.'); } - zBuf[k++] = ']'; - sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]); - k += sqlite3Strlen30(&zBuf[k]); - zBuf[k++] = 0; + sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]); } } #endif @@ -78369,31 +87951,56 @@ static void memTracePrint(Mem *p){ if( p->flags & MEM_Undefined ){ printf(" undefined"); }else if( p->flags & MEM_Null ){ - printf(" NULL"); + printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL"); }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ printf(" si:%lld", p->u.i); + }else if( (p->flags & (MEM_IntReal))!=0 ){ + printf(" ir:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ - printf(" r:%g", p->u.r); + printf(" r:%.17g", p->u.r); #endif - }else if( p->flags & MEM_RowSet ){ + }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ - char zBuf[200]; - sqlite3VdbeMemPrettyPrint(p, zBuf); - printf(" %s", zBuf); + StrAccum acc; + char zBuf[1000]; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); + sqlite3VdbeMemPrettyPrint(p, &acc); + printf(" %s", sqlite3StrAccumFinish(&acc)); } if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype); } static void registerTrace(int iReg, Mem *p){ - printf("REG[%d] = ", iReg); + printf("R[%d] = ", iReg); memTracePrint(p); + if( p->pScopyFrom ){ + printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg])); + } printf("\n"); + sqlite3VdbeCheckMemInvariants(p); +} +/**/ void sqlite3PrintMem(Mem *pMem){ + memTracePrint(pMem); + printf("\n"); + fflush(stdout); } #endif +#ifdef SQLITE_DEBUG +/* +** Show the values of all registers in the virtual machine. Used for +** interactive debugging. +*/ +SQLITE_PRIVATE void sqlite3VdbeRegisterDump(Vdbe *v){ + int i; + for(i=1; inMem; i++) registerTrace(i, v->aMem+i); +} +#endif /* SQLITE_DEBUG */ + + #ifdef SQLITE_DEBUG # define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M) #else @@ -78403,100 +88010,11 @@ static void registerTrace(int iReg, Mem *p){ #ifdef VDBE_PROFILE -/* -** hwtime.h contains inline assembler code for implementing -** high-performance timing routines. -*/ -/************** Include hwtime.h in the middle of vdbe.c *********************/ -/************** Begin file hwtime.h ******************************************/ -/* -** 2008 May 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains inline asm code for retrieving "high-performance" -** counters for x86 class CPUs. -*/ -#ifndef SQLITE_HWTIME_H -#define SQLITE_HWTIME_H - /* -** The following routine only works on pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. +** hwtime.h contains inline assembler code for implementing +** high-performance timing routines. */ -#if (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) - - #if defined(__GNUC__) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned int lo, hi; - __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); - return (sqlite_uint64)hi << 32 | lo; - } - - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - -#elif (defined(__GNUC__) && defined(__x86_64__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long val; - __asm__ __volatile__ ("rdtsc" : "=A" (val)); - return val; - } - -#elif (defined(__GNUC__) && defined(__ppc__)) - - __inline__ sqlite_uint64 sqlite3Hwtime(void){ - unsigned long long retval; - unsigned long junk; - __asm__ __volatile__ ("\n\ - 1: mftbu %1\n\ - mftb %L0\n\ - mftbu %0\n\ - cmpw %0,%1\n\ - bne 1b" - : "=r" (retval), "=r" (junk)); - return retval; - } - -#else - - #error Need implementation of sqlite3Hwtime() for your platform. - - /* - ** To compile without implementing sqlite3Hwtime() for your platform, - ** you can remove the above #error and use the following - ** stub function. You will lose timing support for many - ** of the debugging and testing utilities, but it should at - ** least compile and run. - */ -SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } - -#endif - -#endif /* !defined(SQLITE_HWTIME_H) */ - -/************** End of hwtime.h **********************************************/ -/************** Continuing where we left off in vdbe.c ***********************/ +/* #include "hwtime.h" */ #endif @@ -78504,9 +88022,9 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } /* ** This function is only called from within an assert() expression. It ** checks that the sqlite3.nTransaction variable is correctly set to -** the number of non-transaction savepoints currently in the +** the number of non-transaction savepoints currently in the ** linked list starting at sqlite3.pSavepoint. -** +** ** Usage: ** ** assert( checkSavepointCount(db) ); @@ -78543,10 +88061,46 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ } } +/* +** Compute a bloom filter hash using pOp->p4.i registers from aMem[] beginning +** with pOp->p3. Return the hash. +*/ +static u64 filterHash(const Mem *aMem, const Op *pOp){ + int i, mx; + u64 h = 0; + + assert( pOp->p4type==P4_INT32 ); + for(i=pOp->p3, mx=i+pOp->p4.i; iflags & (MEM_Int|MEM_IntReal) ){ + h += p->u.i; + }else if( p->flags & MEM_Real ){ + h += sqlite3VdbeIntValue(p); + }else if( p->flags & (MEM_Str|MEM_Blob) ){ + h += p->n; + if( p->flags & MEM_Zero ) h += p->u.nZero; + } + } + return h; +} + +/* +** Return the symbolic name for the data type of a pMem +*/ +static const char *vdbeMemTypeName(Mem *pMem){ + static const char *azTypes[] = { + /* SQLITE_INTEGER */ "INT", + /* SQLITE_FLOAT */ "REAL", + /* SQLITE_TEXT */ "TEXT", + /* SQLITE_BLOB */ "BLOB", + /* SQLITE_NULL */ "NULL" + }; + return azTypes[sqlite3_value_type(pMem)-1]; +} /* ** Execute as much of a VDBE program as we can. -** This is the core of sqlite3_step(). +** This is the core of sqlite3_step(). */ SQLITE_PRIVATE int sqlite3VdbeExec( Vdbe *p /* The VDBE */ @@ -78564,9 +88118,9 @@ SQLITE_PRIVATE int sqlite3VdbeExec( u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */ u8 encoding = ENC(db); /* The database encoding */ int iCompare = 0; /* Result of last comparison */ - unsigned nVmStep = 0; /* Number of virtual machine steps */ + u64 nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */ + u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */ #endif Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ @@ -78578,28 +88132,32 @@ SQLITE_PRIVATE int sqlite3VdbeExec( #endif /*** INSERT STACK UNION HERE ***/ - assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ + assert( p->iVdbeMagic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ sqlite3VdbeEnter(p); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + if( db->xProgress ){ + u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; + assert( 0 < db->nProgressOps ); + nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); + }else{ + nProgressLimit = LARGEST_UINT64; + } +#endif if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ goto no_mem; } assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY ); + testcase( p->rc!=SQLITE_OK ); + p->rc = SQLITE_OK; assert( p->bIsReader || p->readOnly!=0 ); p->iCurrentTime = 0; assert( p->explain==0 ); p->pResultSet = 0; db->busyHandler.nBusy = 0; - if( db->u1.isInterrupted ) goto abort_due_to_interrupt; + if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt; sqlite3VdbeIOTraceSql(p); -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK - if( db->xProgress ){ - u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; - assert( 0 < db->nProgressOps ); - nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); - } -#endif #ifdef SQLITE_DEBUG sqlite3BeginBenignMalloc(); if( p->pc==0 @@ -78634,7 +88192,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec( assert( pOp>=aOp && pOp<&aOp[p->nOp]); #ifdef VDBE_PROFILE - start = sqlite3Hwtime(); + start = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); #endif nVmStep++; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS @@ -78646,9 +88204,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec( #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp); + test_trace_breakpoint((int)(pOp - aOp),pOp,p); } #endif - + /* Check to see if we need to simulate an interrupt. This only happens ** if we have a special test build. @@ -78702,7 +88261,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec( #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) pOrigOp = pOp; #endif - + switch( pOp->opcode ){ /***************************************************************************** @@ -78743,7 +88302,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec( /* Opcode: Goto * P2 * * * ** ** An unconditional jump to address P2. -** The next instruction executed will be +** The next instruction executed will be ** the one at index P2 from the beginning of ** the program. ** @@ -78753,13 +88312,27 @@ SQLITE_PRIVATE int sqlite3VdbeExec( ** to the current line should be indented for EXPLAIN output. */ case OP_Goto: { /* jump */ + +#ifdef SQLITE_DEBUG + /* In debuggging mode, when the p5 flags is set on an OP_Goto, that + ** means we should really jump back to the preceeding OP_ReleaseReg + ** instruction. */ + if( pOp->p5 ){ + assert( pOp->p2 < (int)(pOp - aOp) ); + assert( pOp->p2 > 1 ); + pOp = &aOp[pOp->p2 - 2]; + assert( pOp[1].opcode==OP_ReleaseReg ); + goto check_for_interrupt; + } +#endif + jump_to_p2_and_check_for_interrupt: pOp = &aOp[pOp->p2 - 1]; /* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev, - ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon + ** OP_VNext, or OP_SorterNext) all jump here upon ** completion. Check to see if sqlite3_interrupt() has been called - ** or if the progress callback needs to be invoked. + ** or if the progress callback needs to be invoked. ** ** This code uses unstructured "goto" statements and does not look clean. ** But that is not due to sloppy coding habits. The code is written this @@ -78767,7 +88340,7 @@ case OP_Goto: { /* jump */ ** checks on every opcode. This helps sqlite3_step() to run about 1.5% ** faster according to "valgrind --tool=cachegrind" */ check_for_interrupt: - if( db->u1.isInterrupted ) goto abort_due_to_interrupt; + if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt; #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* Call the progress callback if it is configured and the required number ** of VDBE ops have been executed (either since this invocation of @@ -78775,16 +88348,17 @@ case OP_Goto: { /* jump */ ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ - if( db->xProgress!=0 && nVmStep>=nProgressLimit ){ + while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ assert( db->nProgressOps!=0 ); - nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); + nProgressLimit += db->nProgressOps; if( db->xProgress(db->pProgressArg) ){ + nProgressLimit = LARGEST_UINT64; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif - + break; } @@ -78901,8 +88475,12 @@ case OP_Yield: { /* in1, jump */ */ case OP_HaltIfNull: { /* in3 */ pIn3 = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } +#endif if( (pIn3->flags & MEM_Null)==0 ) break; /* Fall through into OP_Halt */ + /* no break */ deliberate_fall_through } /* Opcode: Halt P1 P2 * P4 P5 @@ -78916,7 +88494,7 @@ case OP_HaltIfNull: { /* in3 */ ** whether or not to rollback the current transaction. Do not rollback ** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort, ** then back out all changes that have occurred during this execution of the -** VDBE, but do not rollback the transaction. +** VDBE, but do not rollback the transaction. ** ** If P4 is not null then it is an error message string. ** @@ -78940,6 +88518,9 @@ case OP_Halt: { int pcx; pcx = (int)(pOp - aOp); +#ifdef SQLITE_DEBUG + if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } +#endif if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ pFrame = p->pFrame; @@ -78948,7 +88529,7 @@ case OP_Halt: { sqlite3VdbeSetChanges(db, p->nChange); pcx = sqlite3VdbeFrameRestore(pFrame); if( pOp->p2==OE_Ignore ){ - /* Instruction pcx is the OP_Program that invoked the sub-program + /* Instruction pcx is the OP_Program that invoked the sub-program ** currently being halted. If the p2 instruction of this OP_Halt ** instruction is set to OE_Ignore, then the sub-program is throwing ** an IGNORE exception. In this case jump to the address specified @@ -79036,7 +88617,7 @@ case OP_Real: { /* same as TK_FLOAT, out2 */ /* Opcode: String8 * P2 * P4 * ** Synopsis: r[P2]='P4' ** -** P4 points to a nul terminated UTF-8 string. This opcode is transformed +** P4 points to a nul terminated UTF-8 string. This opcode is transformed ** into a String opcode before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. @@ -79044,13 +88625,13 @@ case OP_Real: { /* same as TK_FLOAT, out2 */ case OP_String8: { /* same as TK_STRING, out2 */ assert( pOp->p4.z!=0 ); pOut = out2Prerelease(p, pOp); - pOp->opcode = OP_String; pOp->p1 = sqlite3Strlen30(pOp->p4.z); #ifndef SQLITE_OMIT_UTF16 if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); + if( rc ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); @@ -79063,15 +88644,16 @@ case OP_String8: { /* same as TK_STRING, out2 */ pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } - testcase( rc==SQLITE_TOOBIG ); #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } + pOp->opcode = OP_String; assert( rc==SQLITE_OK ); /* Fall through to the next case, OP_String */ + /* no break */ deliberate_fall_through } - + /* Opcode: String P1 P2 P3 P4 P5 ** Synopsis: r[P2]='P4' (len=P1) ** @@ -79123,6 +88705,9 @@ case OP_Null: { /* out2 */ assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; pOut->n = 0; +#ifdef SQLITE_DEBUG + pOut->uTemp = 0; +#endif while( cnt>0 ){ pOut++; memAboutToChange(p, pOut); @@ -79145,7 +88730,7 @@ case OP_Null: { /* out2 */ case OP_SoftNull: { assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pOut = &aMem[pOp->p1]; - pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined; + pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null; break; } @@ -79153,12 +88738,18 @@ case OP_SoftNull: { ** Synopsis: r[P2]=P4 (len=P1) ** ** P4 points to a blob of data P1 bytes long. Store this -** blob in register P2. +** blob in register P2. If P4 is a NULL pointer, then construct +** a zero-filled blob that is P1 bytes long in P2. */ case OP_Blob: { /* out2 */ assert( pOp->p1 <= SQLITE_MAX_LENGTH ); pOut = out2Prerelease(p, pOp); - sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0); + if( pOp->p4.z==0 ){ + sqlite3VdbeMemSetZeroBlob(pOut, pOp->p1); + if( sqlite3VdbeMemExpandBlob(pOut) ) goto no_mem; + }else{ + sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0); + } pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; @@ -79182,7 +88773,10 @@ case OP_Variable: { /* out2 */ goto too_big; } pOut = &aMem[pOp->p2]; - sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static); + if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); + memcpy(pOut, pVar, MEMCELLSIZE); + pOut->flags &= ~(MEM_Dyn|MEM_Ephem); + pOut->flags |= MEM_Static|MEM_FromBind; UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -79216,8 +88810,13 @@ case OP_Move: { memAboutToChange(p, pOut); sqlite3VdbeMemMove(pOut, pIn1); #ifdef SQLITE_DEBUG - if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrompScopyFrom += pOp->p2 - p1; + pIn1->pScopyFrom = 0; + { int i; + for(i=1; inMem; i++){ + if( aMem[i].pScopyFrom==pIn1 ){ + aMem[i].pScopyFrom = pOut; + } + } } #endif Deephemeralize(pOut); @@ -79244,6 +88843,7 @@ case OP_Copy: { pOut = &aMem[pOp->p2]; assert( pOut!=pIn1 ); while( 1 ){ + memAboutToChange(p, pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); Deephemeralize(pOut); #ifdef SQLITE_DEBUG @@ -79276,7 +88876,8 @@ case OP_SCopy: { /* out2 */ assert( pOut!=pIn1 ); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); #ifdef SQLITE_DEBUG - if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1; + pOut->pScopyFrom = pIn1; + pOut->mScopyFlags = pIn1->flags; #endif break; } @@ -79297,6 +88898,24 @@ case OP_IntCopy: { /* out2 */ break; } +/* Opcode: FkCheck * * * * * +** +** Halt with an SQLITE_CONSTRAINT error if there are any unresolved +** foreign key constraint violations. If there are no foreign key +** constraint violations, this is a no-op. +** +** FK constraint violations are also checked when the prepared statement +** exits. This opcode is used to raise foreign key constraint errors prior +** to returning results such as a row change count or the result of a +** RETURNING clause. +*/ +case OP_FkCheck: { + if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){ + goto abort_due_to_error; + } + break; +} + /* Opcode: ResultRow P1 P2 * * * ** Synopsis: output=r[P1@P2] ** @@ -79310,49 +88929,9 @@ case OP_ResultRow: { Mem *pMem; int i; assert( p->nResColumn==pOp->p2 ); - assert( pOp->p1>0 ); + assert( pOp->p1>0 || CORRUPT_DB ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK - /* Run the progress counter just before returning. - */ - if( db->xProgress!=0 - && nVmStep>=nProgressLimit - && db->xProgress(db->pProgressArg)!=0 - ){ - rc = SQLITE_INTERRUPT; - goto abort_due_to_error; - } -#endif - - /* If this statement has violated immediate foreign key constraints, do - ** not return the number of rows modified. And do not RELEASE the statement - ** transaction. It needs to be rolled back. */ - if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){ - assert( db->flags&SQLITE_CountRows ); - assert( p->usesStmtJournal ); - goto abort_due_to_error; - } - - /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then - ** DML statements invoke this opcode to return the number of rows - ** modified to the user. This is the only way that a VM that - ** opens a statement transaction may invoke this opcode. - ** - ** In case this is such a statement, close any statement transaction - ** opened by this VM before returning control to the user. This is to - ** ensure that statement-transactions are always nested, not overlapping. - ** If the open statement-transaction is not closed here, then the user - ** may step another VM that opens its own statement transaction. This - ** may lead to overlapping statement transactions. - ** - ** The statement transaction is never a top-level transaction. Hence - ** the RELEASE call below can never fail. - */ - assert( p->iStatement==0 || db->flags&SQLITE_CountRows ); - rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE); - assert( rc==SQLITE_OK ); - /* Invalidate all ephemeral cursor row caches */ p->cacheCtr = (p->cacheCtr + 2)|1; @@ -79368,13 +88947,22 @@ case OP_ResultRow: { || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); sqlite3VdbeMemNulTerminate(&pMem[i]); REGISTER_TRACE(pOp->p1+i, &pMem[i]); +#ifdef SQLITE_DEBUG + /* The registers in the result will not be used again when the + ** prepared statement restarts. This is because sqlite3_column() + ** APIs might have caused type conversions of made other changes to + ** the register values. Therefore, we can go ahead and break any + ** OP_SCopy dependencies. */ + pMem[i].pScopyFrom = 0; +#endif } if( db->mallocFailed ) goto no_mem; if( db->mTrace & SQLITE_TRACE_ROW ){ - db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); + db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); } + /* Return SQLITE_ROW */ p->pc = (int)(pOp - aOp) + 1; @@ -79396,33 +88984,56 @@ case OP_ResultRow: { ** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ - i64 nByte; + i64 nByte; /* Total size of the output string or blob */ + u16 flags1; /* Initial flags for P1 */ + u16 flags2; /* Initial flags for P2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; + testcase( pOut==pIn2 ); assert( pIn1!=pOut ); - if( (pIn1->flags | pIn2->flags) & MEM_Null ){ + flags1 = pIn1->flags; + testcase( flags1 & MEM_Null ); + testcase( pIn2->flags & MEM_Null ); + if( (flags1 | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } - if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem; - Stringify(pIn1, encoding); - Stringify(pIn2, encoding); + if( (flags1 & (MEM_Str|MEM_Blob))==0 ){ + if( sqlite3VdbeMemStringify(pIn1,encoding,0) ) goto no_mem; + flags1 = pIn1->flags & ~MEM_Str; + }else if( (flags1 & MEM_Zero)!=0 ){ + if( sqlite3VdbeMemExpandBlob(pIn1) ) goto no_mem; + flags1 = pIn1->flags & ~MEM_Str; + } + flags2 = pIn2->flags; + if( (flags2 & (MEM_Str|MEM_Blob))==0 ){ + if( sqlite3VdbeMemStringify(pIn2,encoding,0) ) goto no_mem; + flags2 = pIn2->flags & ~MEM_Str; + }else if( (flags2 & MEM_Zero)!=0 ){ + if( sqlite3VdbeMemExpandBlob(pIn2) ) goto no_mem; + flags2 = pIn2->flags & ~MEM_Str; + } nByte = pIn1->n + pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ + if( sqlite3VdbeMemGrow(pOut, (int)nByte+3, pOut==pIn2) ){ goto no_mem; } MemSetTypeFlag(pOut, MEM_Str); if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); + assert( (pIn2->flags & MEM_Dyn) == (flags2 & MEM_Dyn) ); + pIn2->flags = flags2; } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); + assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); + pIn1->flags = flags1; pOut->z[nByte]=0; pOut->z[nByte+1] = 0; + pOut->z[nByte+2] = 0; pOut->flags |= MEM_Term; pOut->n = (int)nByte; pOut->enc = encoding; @@ -79456,15 +89067,15 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ ** Synopsis: r[P3]=r[P2]/r[P1] ** ** Divide the value in register P1 by the value in register P2 -** and store the result in register P3 (P3=P2/P1). If the value in -** register P1 is zero, then the result is NULL. If either input is +** and store the result in register P3 (P3=P2/P1). If the value in +** register P1 is zero, then the result is NULL. If either input is ** NULL, the result is NULL. */ /* Opcode: Remainder P1 P2 P3 * * ** Synopsis: r[P3]=r[P2]%r[P1] ** -** Compute the remainder after integer register P2 is divided by -** register P1 and store the result in register P3. +** Compute the remainder after integer register P2 is divided by +** register P1 and store the result in register P3. ** If the value in register P1 is zero the result is NULL. ** If either operand is NULL, the result is NULL. */ @@ -79473,7 +89084,6 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ - char bIntint; /* Started out as two integer operands */ u16 flags; /* Combined MEM_* flags from both inputs */ u16 type1; /* Numeric type of left operand */ u16 type2; /* Numeric type of right operand */ @@ -79488,11 +89098,9 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ type2 = numericType(pIn2); pOut = &aMem[pOp->p3]; flags = pIn1->flags | pIn2->flags; - if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; if( (type1 & type2 & MEM_Int)!=0 ){ iA = pIn1->u.i; iB = pIn2->u.i; - bIntint = 1; switch( pOp->opcode ){ case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; @@ -79512,8 +89120,9 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } pOut->u.i = iB; MemSetTypeFlag(pOut, MEM_Int); + }else if( (flags & MEM_Null)!=0 ){ + goto arithmetic_result_is_null; }else{ - bIntint = 0; fp_math: rA = sqlite3VdbeRealValue(pIn1); rB = sqlite3VdbeRealValue(pIn2); @@ -79528,8 +89137,8 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ break; } default: { - iA = (i64)rA; - iB = (i64)rB; + iA = sqlite3VdbeIntValue(pIn1); + iB = sqlite3VdbeIntValue(pIn2); if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 ) iA = 1; rB = (double)(iB % iA); @@ -79545,9 +89154,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ } pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); - if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ - sqlite3VdbeIntegerAffinity(pOut); - } #endif } break; @@ -79559,7 +89165,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ /* Opcode: CollSeq P1 * * P4 ** -** P4 is a pointer to a CollSeq struct. If the next call to a user function +** P4 is a pointer to a CollSeq object. If the next call to a user function ** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will ** be returned. This is used by the built-in min(), max() and nullif() ** functions. @@ -79580,117 +89186,6 @@ case OP_CollSeq: { break; } -/* Opcode: Function0 P1 P2 P3 P4 P5 -** Synopsis: r[P3]=func(r[P2@P5]) -** -** Invoke a user function (P4 is a pointer to a FuncDef object that -** defines the function) with P5 arguments taken from register P2 and -** successors. The result of the function is stored in register P3. -** Register P3 must not be one of the function inputs. -** -** P1 is a 32-bit bitmask indicating whether or not each argument to the -** function was determined to be constant at compile time. If the first -** argument was constant then bit 0 of P1 is set. This is used to determine -** whether meta data associated with a user function argument using the -** sqlite3_set_auxdata() API may be safely retained until the next -** invocation of this opcode. -** -** See also: Function, AggStep, AggFinal -*/ -/* Opcode: Function P1 P2 P3 P4 P5 -** Synopsis: r[P3]=func(r[P2@P5]) -** -** Invoke a user function (P4 is a pointer to an sqlite3_context object that -** contains a pointer to the function to be run) with P5 arguments taken -** from register P2 and successors. The result of the function is stored -** in register P3. Register P3 must not be one of the function inputs. -** -** P1 is a 32-bit bitmask indicating whether or not each argument to the -** function was determined to be constant at compile time. If the first -** argument was constant then bit 0 of P1 is set. This is used to determine -** whether meta data associated with a user function argument using the -** sqlite3_set_auxdata() API may be safely retained until the next -** invocation of this opcode. -** -** SQL functions are initially coded as OP_Function0 with P4 pointing -** to a FuncDef object. But on first evaluation, the P4 operand is -** automatically converted into an sqlite3_context object and the operation -** changed to this OP_Function opcode. In this way, the initialization of -** the sqlite3_context object occurs only once, rather than once for each -** evaluation of the function. -** -** See also: Function0, AggStep, AggFinal -*/ -case OP_Function0: { - int n; - sqlite3_context *pCtx; - - assert( pOp->p4type==P4_FUNCDEF ); - n = pOp->p5; - assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); - assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); - assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); - pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); - if( pCtx==0 ) goto no_mem; - pCtx->pOut = 0; - pCtx->pFunc = pOp->p4.pFunc; - pCtx->iOp = (int)(pOp - aOp); - pCtx->pVdbe = p; - pCtx->argc = n; - pOp->p4type = P4_FUNCCTX; - pOp->p4.pCtx = pCtx; - pOp->opcode = OP_Function; - /* Fall through into OP_Function */ -} -case OP_Function: { - int i; - sqlite3_context *pCtx; - - assert( pOp->p4type==P4_FUNCCTX ); - pCtx = pOp->p4.pCtx; - - /* If this function is inside of a trigger, the register array in aMem[] - ** might change from one evaluation to the next. The next block of code - ** checks to see if the register array has changed, and if so it - ** reinitializes the relavant parts of the sqlite3_context object */ - pOut = &aMem[pOp->p3]; - if( pCtx->pOut != pOut ){ - pCtx->pOut = pOut; - for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; - } - - memAboutToChange(p, pCtx->pOut); -#ifdef SQLITE_DEBUG - for(i=0; iargc; i++){ - assert( memIsValid(pCtx->argv[i]) ); - REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); - } -#endif - MemSetTypeFlag(pCtx->pOut, MEM_Null); - pCtx->fErrorOrAux = 0; - (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ - - /* If the function returned an error, throw an exception */ - if( pCtx->fErrorOrAux ){ - if( pCtx->isError ){ - sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut)); - rc = pCtx->isError; - } - sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); - if( rc ) goto abort_due_to_error; - } - - /* Copy the result of the function into register P3 */ - if( pOut->flags & (MEM_Str|MEM_Blob) ){ - sqlite3VdbeChangeEncoding(pCtx->pOut, encoding); - if( sqlite3VdbeMemTooBig(pCtx->pOut) ) goto too_big; - } - - REGISTER_TRACE(pOp->p3, pCtx->pOut); - UPDATE_MAX_BLOBSIZE(pCtx->pOut); - break; -} - /* Opcode: BitAnd P1 P2 P3 * * ** Synopsis: r[P3]=r[P1]&r[P2] ** @@ -79775,7 +89270,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ /* Opcode: AddImm P1 P2 * * * ** Synopsis: r[P1]=r[P1]+P2 -** +** ** Add the constant P2 to the value in register P1. ** The result is always an integer. ** @@ -79790,7 +89285,7 @@ case OP_AddImm: { /* in1 */ } /* Opcode: MustBeInt P1 P2 * * * -** +** ** Force the value in register P1 to be an integer. If the value ** in P1 is not an integer and cannot be converted into an integer ** without data loss, then jump immediately to P2, or if P2==0 @@ -79800,8 +89295,8 @@ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); - VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if( (pIn1->flags & MEM_Int)==0 ){ + VdbeBranchTaken(1, 2); if( pOp->p2==0 ){ rc = SQLITE_MISMATCH; goto abort_due_to_error; @@ -79810,6 +89305,7 @@ case OP_MustBeInt: { /* jump, in1 */ } } } + VdbeBranchTaken(0, 2); MemSetTypeFlag(pIn1, MEM_Int); break; } @@ -79826,8 +89322,11 @@ case OP_MustBeInt: { /* jump, in1 */ */ case OP_RealAffinity: { /* in1 */ pIn1 = &aMem[pOp->p1]; - if( pIn1->flags & MEM_Int ){ + if( pIn1->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pIn1->flags & MEM_Int ); + testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pIn1); + REGISTER_TRACE(pOp->p1, pIn1); } break; } @@ -79838,13 +89337,13 @@ case OP_RealAffinity: { /* in1 */ ** Synopsis: affinity(r[P1]) ** ** Force the value in register P1 to be the type defined by P2. -** +** **
              -**
            • TEXT -**
            • BLOB -**
            • NUMERIC -**
            • INTEGER -**
            • REAL +**
            • P2=='A' → BLOB +**
            • P2=='B' → TEXT +**
            • P2=='C' → NUMERIC +**
            • P2=='D' → INTEGER +**
            • P2=='E' → REAL **
            ** ** A NULL value is not changed by this routine. It remains NULL. @@ -79859,9 +89358,11 @@ case OP_Cast: { /* in1 */ pIn1 = &aMem[pOp->p1]; memAboutToChange(p, pIn1); rc = ExpandBlob(pIn1); - sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); - UPDATE_MAX_BLOBSIZE(pIn1); if( rc ) goto abort_due_to_error; + rc = sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); + if( rc ) goto abort_due_to_error; + UPDATE_MAX_BLOBSIZE(pIn1); + REGISTER_TRACE(pOp->p1, pIn1); break; } #endif /* SQLITE_OMIT_CAST */ @@ -79870,18 +89371,17 @@ case OP_Cast: { /* in1 */ ** Synopsis: IF r[P3]==r[P1] ** ** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then -** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, then -** store the result of comparison in register P2. +** jump to address P2. ** ** The SQLITE_AFF_MASK portion of P5 must be an affinity character - -** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made +** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made ** to coerce both inputs according to this affinity before the ** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric ** affinity is used. Note that the affinity conversions are stored ** back into the input registers P1 and P3. So this opcode can cause ** persistent changes to registers P1 and P3. ** -** Once any conversions have taken place, and neither value is NULL, +** Once any conversions have taken place, and neither value is NULL, ** the values are compared. If both values are blobs then memcmp() is ** used to determine the results of the comparison. If both values ** are text, then the appropriate collating function specified in @@ -79897,9 +89397,8 @@ case OP_Cast: { /* in1 */ ** If neither operand is NULL the result is the same as it would be if ** the SQLITE_NULLEQ flag were omitted from P5. ** -** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the -** content of r[P2] is only changed if the new value is NULL or 0 (false). -** In other words, a prior r[P2] value will not be overwritten by 1 (true). +** This opcode saves the result of comparison for use by the new +** OP_Jump opcode. */ /* Opcode: Ne P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]!=r[P1] @@ -79907,31 +89406,26 @@ case OP_Cast: { /* in1 */ ** This works just like the Eq opcode except that the jump is taken if ** the operands in registers P1 and P3 are not equal. See the Eq opcode for ** additional information. -** -** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the -** content of r[P2] is only changed if the new value is NULL or 1 (true). -** In other words, a prior r[P2] value will not be overwritten by 0 (false). */ /* Opcode: Lt P1 P2 P3 P4 P5 ** Synopsis: IF r[P3]p3]; flags1 = pIn1->flags; flags3 = pIn3->flags; + if( (flags1 & flags3 & MEM_Int)!=0 ){ + assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB ); + /* Common case of comparison of two integers */ + if( pIn3->u.i > pIn1->u.i ){ + iCompare = +1; + if( sqlite3aGTb[pOp->opcode] ){ + VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); + goto jump_to_p2; + } + }else if( pIn3->u.i < pIn1->u.i ){ + iCompare = -1; + if( sqlite3aLTb[pOp->opcode] ){ + VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); + goto jump_to_p2; + } + }else{ + iCompare = 0; + if( sqlite3aEQb[pOp->opcode] ){ + VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3); + goto jump_to_p2; + } + } + VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3); + break; + } if( (flags1 | flags3)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ @@ -79984,69 +89506,57 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ - assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); assert( (flags1 & MEM_Cleared)==0 ); - assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 ); + assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 || CORRUPT_DB ); + testcase( (pOp->p5 & SQLITE_JUMPIFNULL)!=0 ); if( (flags1&flags3&MEM_Null)!=0 && (flags3&MEM_Cleared)==0 ){ res = 0; /* Operands are equal */ }else{ - res = 1; /* Operands are not equal */ + res = ((flags3 & MEM_Null) ? -1 : +1); /* Operands are not equal */ } }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, ** then the result is always NULL. ** The jump is taken if the SQLITE_JUMPIFNULL bit is set. */ - if( pOp->p5 & SQLITE_STOREP2 ){ - pOut = &aMem[pOp->p2]; - iCompare = 1; /* Operands are not equal */ - memAboutToChange(p, pOut); - MemSetTypeFlag(pOut, MEM_Null); - REGISTER_TRACE(pOp->p2, pOut); - }else{ - VdbeBranchTaken(2,3); - if( pOp->p5 & SQLITE_JUMPIFNULL ){ - goto jump_to_p2; - } + iCompare = 1; /* Operands are not equal */ + VdbeBranchTaken(2,3); + if( pOp->p5 & SQLITE_JUMPIFNULL ){ + goto jump_to_p2; } break; } }else{ - /* Neither operand is NULL. Do a comparison. */ + /* Neither operand is NULL and we couldn't do the special high-speed + ** integer comparison case. So do a general-case comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ - if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); - testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */ + testcase( flags3==pIn3->flags ); flags3 = pIn3->flags; } - if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } - /* Handle the common case of integer comparison here, as an - ** optimization, to avoid a call to sqlite3MemCompare() */ - if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){ - if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; } - if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; } - res = 0; - goto compare_op; - } }else if( affinity==SQLITE_AFF_TEXT ){ - if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ + if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); + testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); - assert( pIn1!=pIn3 ); + if( pIn1==pIn3 ) flags3 = flags1 | MEM_Str; } - if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ + if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); + testcase( pIn3->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); @@ -80055,69 +89565,63 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } -compare_op: - switch( pOp->opcode ){ - case OP_Eq: res2 = res==0; break; - case OP_Ne: res2 = res; break; - case OP_Lt: res2 = res<0; break; - case OP_Le: res2 = res<=0; break; - case OP_Gt: res2 = res>0; break; - default: res2 = res>=0; break; + + /* At this point, res is negative, zero, or positive if reg[P1] is + ** less than, equal to, or greater than reg[P3], respectively. Compute + ** the answer to this operator in res2, depending on what the comparison + ** operator actually is. The next block of code depends on the fact + ** that the 6 comparison operators are consecutive integers in this + ** order: NE, EQ, GT, LE, LT, GE */ + assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 ); + assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 ); + if( res<0 ){ + res2 = sqlite3aLTb[pOp->opcode]; + }else if( res==0 ){ + res2 = sqlite3aEQb[pOp->opcode]; + }else{ + res2 = sqlite3aGTb[pOp->opcode]; } + iCompare = res; /* Undo any changes made by applyAffinity() to the input registers. */ - assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); - pIn1->flags = flags1; assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); pIn3->flags = flags3; + assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); + pIn1->flags = flags1; - if( pOp->p5 & SQLITE_STOREP2 ){ - pOut = &aMem[pOp->p2]; - iCompare = res; - res2 = res2!=0; /* For this path res2 must be exactly 0 or 1 */ - if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){ - /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1 - ** and prevents OP_Ne from overwriting NULL with 0. This flag - ** is only used in contexts where either: - ** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0) - ** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1) - ** Therefore it is not necessary to check the content of r[P2] for - ** NULL. */ - assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq ); - assert( res2==0 || res2==1 ); - testcase( res2==0 && pOp->opcode==OP_Eq ); - testcase( res2==1 && pOp->opcode==OP_Eq ); - testcase( res2==0 && pOp->opcode==OP_Ne ); - testcase( res2==1 && pOp->opcode==OP_Ne ); - if( (pOp->opcode==OP_Eq)==res2 ) break; - } - memAboutToChange(p, pOut); - MemSetTypeFlag(pOut, MEM_Int); - pOut->u.i = res2; - REGISTER_TRACE(pOp->p2, pOut); - }else{ - VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); - if( res2 ){ - goto jump_to_p2; - } + VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); + if( res2 ){ + goto jump_to_p2; } break; } -/* Opcode: ElseNotEq * P2 * * * +/* Opcode: ElseEq * P2 * * * +** +** This opcode must follow an OP_Lt or OP_Gt comparison operator. There +** can be zero or more OP_ReleaseReg opcodes intervening, but no other +** opcodes are allowed to occur between this instruction and the previous +** OP_Lt or OP_Gt. ** -** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator. -** If result of an OP_Eq comparison on the same two operands -** would have be NULL or false (0), then then jump to P2. -** If the result of an OP_Eq comparison on the two previous operands -** would have been true (1), then fall through. +** If result of an OP_Eq comparison on the same two operands as the +** prior OP_Lt or OP_Gt would have been true, then jump to P2. +** If the result of an OP_Eq comparison on the two previous +** operands would have been false or NULL, then fall through. */ -case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */ - assert( pOp>aOp ); - assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt ); - assert( pOp[-1].p5 & SQLITE_STOREP2 ); - VdbeBranchTaken(iCompare!=0, 2); - if( iCompare!=0 ) goto jump_to_p2; +case OP_ElseEq: { /* same as TK_ESCAPE, jump */ + +#ifdef SQLITE_DEBUG + /* Verify the preconditions of this opcode - that it follows an OP_Lt or + ** OP_Gt with zero or more intervening OP_ReleaseReg opcodes */ + int iAddr; + for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){ + if( aOp[iAddr].opcode==OP_ReleaseReg ) continue; + assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt ); + break; + } +#endif /* SQLITE_DEBUG */ + VdbeBranchTaken(iCompare==0, 2); + if( iCompare==0 ) goto jump_to_p2; break; } @@ -80128,7 +89632,7 @@ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */ ** instruction. The permutation is stored in the P4 operand. ** ** The permutation is only valid until the next OP_Compare that has -** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should +** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should ** occur immediately prior to the OP_Compare. ** ** The first integer in the P4 integer array is the length of the array @@ -80168,10 +89672,10 @@ case OP_Compare: { int p1; int p2; const KeyInfo *pKeyInfo; - int idx; + u32 idx; CollSeq *pColl; /* Collating sequence to use on this term */ int bRev; /* True for DESCENDING sort order */ - int *aPermute; /* The permutation */ + u32 *aPermute; /* The permutation */ if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){ aPermute = 0; @@ -80188,10 +89692,10 @@ case OP_Compare: { assert( pKeyInfo!=0 ); p1 = pOp->p1; p2 = pOp->p2; -#if SQLITE_DEBUG +#ifdef SQLITE_DEBUG if( aPermute ){ int k, mx = 0; - for(k=0; kmx ) mx = aPermute[k]; + for(k=0; k(u32)mx ) mx = aPermute[k]; assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 ); assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 ); }else{ @@ -80200,16 +89704,21 @@ case OP_Compare: { } #endif /* SQLITE_DEBUG */ for(i=0; inField ); + assert( inKeyField ); pColl = pKeyInfo->aColl[i]; - bRev = pKeyInfo->aSortOrder[i]; + bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC); iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); if( iCompare ){ + if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) + && ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null)) + ){ + iCompare = -iCompare; + } if( bRev ) iCompare = -iCompare; break; } @@ -80225,11 +89734,11 @@ case OP_Compare: { */ case OP_Jump: { /* jump */ if( iCompare<0 ){ - VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1]; + VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ - VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1]; + VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1]; }else{ - VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1]; + VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1]; } break; } @@ -80259,18 +89768,8 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ - pIn1 = &aMem[pOp->p1]; - if( pIn1->flags & MEM_Null ){ - v1 = 2; - }else{ - v1 = sqlite3VdbeIntValue(pIn1)!=0; - } - pIn2 = &aMem[pOp->p2]; - if( pIn2->flags & MEM_Null ){ - v2 = 2; - }else{ - v2 = sqlite3VdbeIntValue(pIn2)!=0; - } + v1 = sqlite3VdbeBooleanValue(&aMem[pOp->p1], 2); + v2 = sqlite3VdbeBooleanValue(&aMem[pOp->p2], 2); if( pOp->opcode==OP_And ){ static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; v1 = and_logic[v1*3+v2]; @@ -80288,26 +89787,55 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ break; } +/* Opcode: IsTrue P1 P2 P3 P4 * +** Synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 +** +** This opcode implements the IS TRUE, IS FALSE, IS NOT TRUE, and +** IS NOT FALSE operators. +** +** Interpret the value in register P1 as a boolean value. Store that +** boolean (a 0 or 1) in register P2. Or if the value in register P1 is +** NULL, then the P3 is stored in register P2. Invert the answer if P4 +** is 1. +** +** The logic is summarized like this: +** +**
              +**
            • If P3==0 and P4==0 then r[P2] := r[P1] IS TRUE +**
            • If P3==1 and P4==1 then r[P2] := r[P1] IS FALSE +**
            • If P3==0 and P4==1 then r[P2] := r[P1] IS NOT TRUE +**
            • If P3==1 and P4==0 then r[P2] := r[P1] IS NOT FALSE +**
            +*/ +case OP_IsTrue: { /* in1, out2 */ + assert( pOp->p4type==P4_INT32 ); + assert( pOp->p4.i==0 || pOp->p4.i==1 ); + assert( pOp->p3==0 || pOp->p3==1 ); + sqlite3VdbeMemSetInt64(&aMem[pOp->p2], + sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3) ^ pOp->p4.i); + break; +} + /* Opcode: Not P1 P2 * * * ** Synopsis: r[P2]= !r[P1] ** ** Interpret the value in register P1 as a boolean value. Store the -** boolean complement in register P2. If the value in register P1 is +** boolean complement in register P2. If the value in register P1 is ** NULL, then a NULL is stored in P2. */ case OP_Not: { /* same as TK_NOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; - sqlite3VdbeMemSetNull(pOut); if( (pIn1->flags & MEM_Null)==0 ){ - pOut->flags = MEM_Int; - pOut->u.i = !sqlite3VdbeIntValue(pIn1); + sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeBooleanValue(pIn1,0)); + }else{ + sqlite3VdbeMemSetNull(pOut); } break; } /* Opcode: BitNot P1 P2 * * * -** Synopsis: r[P1]= ~r[P1] +** Synopsis: r[P2]= ~r[P1] ** ** Interpret the content of register P1 as an integer. Store the ** ones-complement of the P1 value into register P2. If P1 holds @@ -80326,19 +89854,39 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */ /* Opcode: Once P1 P2 * * * ** -** If the P1 value is equal to the P1 value on the OP_Init opcode at -** instruction 0, then jump to P2. If the two P1 values differ, then -** set the P1 value on this opcode to equal the P1 value on the OP_Init -** and fall through. +** Fall through to the next instruction the first time this opcode is +** encountered on each invocation of the byte-code program. Jump to P2 +** on the second and all subsequent encounters during the same invocation. +** +** Top-level programs determine first invocation by comparing the P1 +** operand against the P1 operand on the OP_Init opcode at the beginning +** of the program. If the P1 values differ, then fall through and make +** the P1 of this opcode equal to the P1 of OP_Init. If P1 values are +** the same then take the jump. +** +** For subprograms, there is a bitmask in the VdbeFrame that determines +** whether or not the jump should be taken. The bitmask is necessary +** because the self-altering code trick does not work for recursive +** triggers. */ case OP_Once: { /* jump */ + u32 iAddr; /* Address of this instruction */ assert( p->aOp[0].opcode==OP_Init ); - VdbeBranchTaken(p->aOp[0].p1==pOp->p1, 2); - if( p->aOp[0].p1==pOp->p1 ){ - goto jump_to_p2; + if( p->pFrame ){ + iAddr = (int)(pOp - p->aOp); + if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){ + VdbeBranchTaken(1, 2); + goto jump_to_p2; + } + p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7); }else{ - pOp->p1 = p->aOp[0].p1; + if( p->aOp[0].p1==pOp->p1 ){ + VdbeBranchTaken(1, 2); + goto jump_to_p2; + } } + VdbeBranchTaken(0, 2); + pOp->p1 = p->aOp[0].p1; break; } @@ -80348,30 +89896,25 @@ case OP_Once: { /* jump */ ** is considered true if it is numeric and non-zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ +case OP_If: { /* jump, in1 */ + int c; + c = sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3); + VdbeBranchTaken(c!=0, 2); + if( c ) goto jump_to_p2; + break; +} + /* Opcode: IfNot P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is False. The value ** is considered false if it has a numeric value of zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ -case OP_If: /* jump, in1 */ case OP_IfNot: { /* jump, in1 */ int c; - pIn1 = &aMem[pOp->p1]; - if( pIn1->flags & MEM_Null ){ - c = pOp->p3; - }else{ -#ifdef SQLITE_OMIT_FLOATING_POINT - c = sqlite3VdbeIntValue(pIn1)!=0; -#else - c = sqlite3VdbeRealValue(pIn1)!=0.0; -#endif - if( pOp->opcode==OP_IfNot ) c = !c; - } + c = !sqlite3VdbeBooleanValue(&aMem[pOp->p1], !pOp->p3); VdbeBranchTaken(c!=0, 2); - if( c ){ - goto jump_to_p2; - } + if( c ) goto jump_to_p2; break; } @@ -80389,10 +89932,44 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ break; } +/* Opcode: IsNullOrType P1 P2 P3 * * +** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2 +** +** Jump to P2 if the value in register P1 is NULL or has a datatype P3. +** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT, +** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT. +*/ +case OP_IsNullOrType: { /* jump, in1 */ + int doTheJump; + pIn1 = &aMem[pOp->p1]; + doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlite3_value_type(pIn1)==pOp->p3; + VdbeBranchTaken( doTheJump, 2); + if( doTheJump ) goto jump_to_p2; + break; +} + +/* Opcode: ZeroOrNull P1 P2 P3 * * +** Synopsis: r[P2] = 0 OR NULL +** +** If all both registers P1 and P3 are NOT NULL, then store a zero in +** register P2. If either registers P1 or P3 are NULL then put +** a NULL in register P2. +*/ +case OP_ZeroOrNull: { /* in1, in2, out2, in3 */ + if( (aMem[pOp->p1].flags & MEM_Null)!=0 + || (aMem[pOp->p3].flags & MEM_Null)!=0 + ){ + sqlite3VdbeMemSetNull(aMem + pOp->p2); + }else{ + sqlite3VdbeMemSetInt64(aMem + pOp->p2, 0); + } + break; +} + /* Opcode: NotNull P1 P2 * * * ** Synopsis: if r[P1]!=NULL goto P2 ** -** Jump to P2 if the value in register P1 is not NULL. +** Jump to P2 if the value in register P1 is not NULL. */ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ pIn1 = &aMem[pOp->p1]; @@ -80403,33 +89980,84 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ break; } +/* Opcode: IfNullRow P1 P2 P3 * * +** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 +** +** Check the cursor P1 to see if it is currently pointing at a NULL row. +** If it is, then set register P3 to NULL and jump immediately to P2. +** If P1 is not on a NULL row, then fall through without making any +** changes. +*/ +case OP_IfNullRow: { /* jump */ + assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( p->apCsr[pOp->p1]!=0 ); + if( p->apCsr[pOp->p1]->nullRow ){ + sqlite3VdbeMemSetNull(aMem + pOp->p3); + goto jump_to_p2; + } + break; +} + +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC +/* Opcode: Offset P1 P2 P3 * * +** Synopsis: r[P3] = sqlite_offset(P1) +** +** Store in register r[P3] the byte offset into the database file that is the +** start of the payload for the record at which that cursor P1 is currently +** pointing. +** +** P2 is the column number for the argument to the sqlite_offset() function. +** This opcode does not use P2 itself, but the P2 value is used by the +** code generator. The P1, P2, and P3 operands to this opcode are the +** same as for OP_Column. +** +** This opcode is only available if SQLite is compiled with the +** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option. +*/ +case OP_Offset: { /* out3 */ + VdbeCursor *pC; /* The VDBE cursor */ + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + pOut = &p->aMem[pOp->p3]; + if( pC==0 || pC->eCurType!=CURTYPE_BTREE ){ + sqlite3VdbeMemSetNull(pOut); + }else{ + if( pC->deferredMoveto ){ + rc = sqlite3VdbeFinishMoveto(pC); + if( rc ) goto abort_due_to_error; + } + if( sqlite3BtreeEof(pC->uc.pCursor) ){ + sqlite3VdbeMemSetNull(pOut); + }else{ + sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor)); + } + } + break; +} +#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */ + /* Opcode: Column P1 P2 P3 P4 P5 ** Synopsis: r[P3]=PX ** ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional ** information about the format of the data.) Extract the P2-th column -** from this record. If there are less that (P2+1) +** from this record. If there are less that (P2+1) ** values in the record, extract a NULL. ** ** The value extracted is stored in register P3. ** -** If the column contains fewer than P2 fields, then extract a NULL. Or, +** If the record contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as ** the result. ** -** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor, -** then the cache of the cursor is reset prior to extracting the column. -** The first OP_Column against a pseudo-table after the value of the content -** register has changed should have this bit set. -** -** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when +** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { - int p2; /* column number to retrieve */ + u32 p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ @@ -80440,26 +90068,28 @@ case OP_Column: { const u8 *zData; /* Part of the record being decoded */ const u8 *zHdr; /* Next unparsed byte of the header */ const u8 *zEndHdr; /* Pointer to first byte after the header */ - u32 offset; /* Offset into the data */ u64 offset64; /* 64-bit offset */ - u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ Mem *pReg; /* PseudoTable input register */ + assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; - p2 = pOp->p2; + assert( pC!=0 ); + p2 = (u32)pOp->p2; - /* If the cursor cache is stale, bring it up-to-date */ + /* If the cursor cache is stale (meaning it is not currently point at + ** the correct row) then bring it up-to-date by doing the necessary + ** B-Tree seek. */ rc = sqlite3VdbeCursorMoveto(&pC, &p2); if( rc ) goto abort_due_to_error; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); - assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pC!=0 ); - assert( p2nField ); + assert( p2<(u32)pC->nField ); aOffset = pC->aOffset; + assert( aOffset==pC->aType+pC->nField ); assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); @@ -80467,11 +90097,13 @@ case OP_Column: { if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ if( pC->nullRow ){ if( pC->eCurType==CURTYPE_PSEUDO ){ - assert( pC->uc.pseudoTableReg>0 ); - pReg = &aMem[pC->uc.pseudoTableReg]; + /* For the special case of as pseudo-cursor, the seekResult field + ** identifies the register that holds the record */ + assert( pC->seekResult>0 ); + pReg = &aMem[pC->seekResult]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); - pC->payloadSize = pC->szRow = avail = pReg->n; + pC->payloadSize = pC->szRow = pReg->n; pC->aRow = (u8*)pReg->z; }else{ sqlite3VdbeMemSetNull(pDest); @@ -80483,23 +90115,19 @@ case OP_Column: { assert( pCrsr ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); - pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail); - assert( avail<=65536 ); /* Maximum page size is 64KiB */ - if( pC->payloadSize <= (u32)avail ){ - pC->szRow = pC->payloadSize; - }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ + pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow); + assert( pC->szRow<=pC->payloadSize ); + assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */ + if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; - }else{ - pC->szRow = avail; } } pC->cacheStatus = p->cacheCtr; - pC->iHdrOffset = getVarint32(pC->aRow, offset); + pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]); pC->nHdrParsed = 0; - aOffset[0] = offset; - if( availszRowaRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be @@ -80516,17 +90144,26 @@ case OP_Column: { ** 3-byte type for each of the maximum of 32768 columns plus three ** extra bytes for the header length itself. 32768*3 + 3 = 98307. */ - if( offset > 98307 || offset > pC->payloadSize ){ - rc = SQLITE_CORRUPT_BKPT; - goto abort_due_to_error; + if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){ + goto op_column_corrupt; } - }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/ - /* The following goto is an optimization. It can be omitted and - ** everything will still work. But OP_Column is measurably faster - ** by skipping the subsequent conditional, which is always true. + }else{ + /* This is an optimization. By skipping over the first few tests + ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a + ** measurable performance gain. + ** + ** This branch is taken even if aOffset[0]==0. Such a record is never + ** generated by SQLite, and could be considered corruption, but we + ** accept it for historical reasons. When aOffset[0]==0, the code this + ** branch jumps to reads past the end of the record, but never more + ** than a few bytes. Even if the record occurs at the end of the page + ** content area, the "page header" comes after the page content and so + ** this overread is harmless. Similar overreads can occur for a corrupt + ** database file. */ zData = pC->aRow; assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ + testcase( aOffset[0]==0 ); goto op_column_read_header; } } @@ -80536,36 +90173,37 @@ case OP_Column: { */ if( pC->nHdrParsed<=p2 ){ /* If there is more header available for parsing in the record, try - ** to extract additional fields up through the p2+1-th field + ** to extract additional fields up through the p2+1-th field */ if( pC->iHdrOffsetaRow==0 ){ memset(&sMem, 0, sizeof(sMem)); - rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pC->uc.pCursor,aOffset[0],&sMem); if( rc!=SQLITE_OK ) goto abort_due_to_error; zData = (u8*)sMem.z; }else{ zData = pC->aRow; } - + /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ op_column_read_header: i = pC->nHdrParsed; offset64 = aOffset[i]; zHdr = zData + pC->iHdrOffset; zEndHdr = zData + aOffset[0]; + testcase( zHdr>=zEndHdr ); do{ - if( (t = zHdr[0])<0x80 ){ + if( (pC->aType[i] = t = zHdr[0])<0x80 ){ zHdr++; offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); + pC->aType[i] = t; offset64 += sqlite3VdbeSerialTypeLen(t); } - pC->aType[i++] = t; - aOffset[i] = (u32)(offset64 & 0xffffffff); - }while( i<=p2 && zHdr=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize)) || (offset64 > pC->payloadSize) ){ - if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); - rc = SQLITE_CORRUPT_BKPT; - goto abort_due_to_error; + if( aOffset[0]==0 ){ + i = 0; + zHdr = zEndHdr; + }else{ + if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); + goto op_column_corrupt; + } } pC->nHdrParsed = i; @@ -80651,9 +90293,15 @@ case OP_Column: { ** 2. the length(X) function if X is a blob, and ** 3. if the content length is zero. ** So we might as well use bogus content rather than reading - ** content from disk. */ - static u8 aZero[8]; /* This is the bogus content */ - sqlite3VdbeSerialGet(aZero, t, pDest); + ** content from disk. + ** + ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the + ** buffer passed to it, debugging function VdbeMemPrettyPrint() may + ** read more. Use the global constant sqlite3CtypeMap[] as the array, + ** as that array is 256 bytes long (plenty for VdbeMemPrettyPrint()) + ** and it begins with a bunch of zeros. + */ + sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest); }else{ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest); if( rc!=SQLITE_OK ) goto abort_due_to_error; @@ -80666,6 +90314,119 @@ case OP_Column: { UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; + +op_column_corrupt: + if( aOp[0].p3>0 ){ + pOp = &aOp[aOp[0].p3-1]; + break; + }else{ + rc = SQLITE_CORRUPT_BKPT; + goto abort_due_to_error; + } +} + +/* Opcode: TypeCheck P1 P2 P3 P4 * +** Synopsis: typecheck(r[P1@P2]) +** +** Apply affinities to the range of P2 registers beginning with P1. +** Take the affinities from the Table object in P4. If any value +** cannot be coerced into the correct type, then raise an error. +** +** This opcode is similar to OP_Affinity except that this opcode +** forces the register type to the Table column type. This is used +** to implement "strict affinity". +** +** GENERATED ALWAYS AS ... STATIC columns are only checked if P3 +** is zero. When P3 is non-zero, no type checking occurs for +** static generated columns. Virtual columns are computed at query time +** and so they are never checked. +** +** Preconditions: +** +**
              +**
            • P2 should be the number of non-virtual columns in the +** table of P4. +**
            • Table P4 should be a STRICT table. +**
            +** +** If any precondition is false, an assertion fault occurs. +*/ +case OP_TypeCheck: { + Table *pTab; + Column *aCol; + int i; + + assert( pOp->p4type==P4_TABLE ); + pTab = pOp->p4.pTab; + assert( pTab->tabFlags & TF_Strict ); + assert( pTab->nNVCol==pOp->p2 ); + aCol = pTab->aCol; + pIn1 = &aMem[pOp->p1]; + for(i=0; inCol; i++){ + if( aCol[i].colFlags & COLFLAG_GENERATED ){ + if( aCol[i].colFlags & COLFLAG_VIRTUAL ) continue; + if( pOp->p3 ){ pIn1++; continue; } + } + assert( pIn1 < &aMem[pOp->p1+pOp->p2] ); + applyAffinity(pIn1, aCol[i].affinity, encoding); + if( (pIn1->flags & MEM_Null)==0 ){ + switch( aCol[i].eCType ){ + case COLTYPE_BLOB: { + if( (pIn1->flags & MEM_Blob)==0 ) goto vdbe_type_error; + break; + } + case COLTYPE_INTEGER: + case COLTYPE_INT: { + if( (pIn1->flags & MEM_Int)==0 ) goto vdbe_type_error; + break; + } + case COLTYPE_TEXT: { + if( (pIn1->flags & MEM_Str)==0 ) goto vdbe_type_error; + break; + } + case COLTYPE_REAL: { + testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_Real ); + testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_IntReal ); + if( pIn1->flags & MEM_Int ){ + /* When applying REAL affinity, if the result is still an MEM_Int + ** that will fit in 6 bytes, then change the type to MEM_IntReal + ** so that we keep the high-resolution integer value but know that + ** the type really wants to be REAL. */ + testcase( pIn1->u.i==140737488355328LL ); + testcase( pIn1->u.i==140737488355327LL ); + testcase( pIn1->u.i==-140737488355328LL ); + testcase( pIn1->u.i==-140737488355329LL ); + if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL){ + pIn1->flags |= MEM_IntReal; + pIn1->flags &= ~MEM_Int; + }else{ + pIn1->u.r = (double)pIn1->u.i; + pIn1->flags |= MEM_Real; + pIn1->flags &= ~MEM_Int; + } + }else if( (pIn1->flags & (MEM_Real|MEM_IntReal))==0 ){ + goto vdbe_type_error; + } + break; + } + default: { + /* COLTYPE_ANY. Accept anything. */ + break; + } + } + } + REGISTER_TRACE((int)(pIn1-aMem), pIn1); + pIn1++; + } + assert( pIn1 == &aMem[pOp->p1+pOp->p2] ); + break; + +vdbe_type_error: + sqlite3VdbeError(p, "cannot store %s value in %s column %s.%s", + vdbeMemTypeName(pIn1), sqlite3StdType[aCol[i].eCType-1], + pTab->zName, aCol[i].zCnName); + rc = SQLITE_CONSTRAINT_DATATYPE; + goto abort_due_to_error; } /* Opcode: Affinity P1 P2 * P4 * @@ -80673,22 +90434,43 @@ case OP_Column: { ** ** Apply affinities to a range of P2 registers starting with P1. ** -** P4 is a string that is P2 characters long. The nth character of the -** string indicates the column affinity that should be used for the nth +** P4 is a string that is P2 characters long. The N-th character of the +** string indicates the column affinity that should be used for the N-th ** memory cell in the range. */ case OP_Affinity: { const char *zAffinity; /* The affinity to be applied */ - char cAff; /* A single character of affinity */ zAffinity = pOp->p4.z; assert( zAffinity!=0 ); + assert( pOp->p2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; - while( (cAff = *(zAffinity++))!=0 ){ + while( 1 /*exit-by-break*/ ){ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); - assert( memIsValid(pIn1) ); - applyAffinity(pIn1, cAff, encoding); + assert( zAffinity[0]==SQLITE_AFF_NONE || memIsValid(pIn1) ); + applyAffinity(pIn1, zAffinity[0], encoding); + if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){ + /* When applying REAL affinity, if the result is still an MEM_Int + ** that will fit in 6 bytes, then change the type to MEM_IntReal + ** so that we keep the high-resolution integer value but know that + ** the type really wants to be REAL. */ + testcase( pIn1->u.i==140737488355328LL ); + testcase( pIn1->u.i==140737488355327LL ); + testcase( pIn1->u.i==-140737488355328LL ); + testcase( pIn1->u.i==-140737488355329LL ); + if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL ){ + pIn1->flags |= MEM_IntReal; + pIn1->flags &= ~MEM_Int; + }else{ + pIn1->u.r = (double)pIn1->u.i; + pIn1->flags |= MEM_Real; + pIn1->flags &= ~MEM_Int; + } + } + REGISTER_TRACE((int)(pIn1-aMem), pIn1); + zAffinity++; + if( zAffinity[0]==0 ) break; pIn1++; } break; @@ -80701,17 +90483,27 @@ case OP_Affinity: { ** use as a data record in a database table or as a key ** in an index. The OP_Column opcode can decode the record later. ** -** P4 may be a string that is P2 characters long. The nth character of the -** string indicates the column affinity that should be used for the nth +** P4 may be a string that is P2 characters long. The N-th character of the +** string indicates the column affinity that should be used for the N-th ** field of the index key. ** ** The mapping from character to affinity is given by the SQLITE_AFF_ ** macros defined in sqliteInt.h. ** ** If P4 is NULL then all index fields have the affinity BLOB. +** +** The meaning of P5 depends on whether or not the SQLITE_ENABLE_NULL_TRIM +** compile-time option is enabled: +** +** * If SQLITE_ENABLE_NULL_TRIM is enabled, then the P5 is the index +** of the right-most table that can be null-trimmed. +** +** * If SQLITE_ENABLE_NULL_TRIM is omitted, then P5 has the value +** OPFLAG_NOCHNG_MAGIC if the OP_MakeRecord opcode is allowed to +** accept no-change records with serial_type 10. This value is +** only used inside an assert() and does not affect the end result. */ case OP_MakeRecord: { - u8 *zNewRecord; /* A buffer to hold the data for the new record */ Mem *pRec; /* The new record */ u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ @@ -80724,21 +90516,21 @@ case OP_MakeRecord: { int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ - int i; /* Space used in zNewRecord[] header */ - int j; /* Space used in zNewRecord[] content */ u32 len; /* Length of a field */ + u8 *zHdr; /* Where to write next byte of the header */ + u8 *zPayload; /* Where to write next byte of the payload */ /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------------ - ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | + ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | ** ------------------------------------------------------------------------ ** ** Data(0) is taken from register P1. Data(1) comes from register P1+1 ** and so forth. ** - ** Each type field is a varint representing the serial type of the + ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The ** hdr-size field is also a varint which is the offset from the beginning ** of the record to data0. @@ -80765,7 +90557,14 @@ case OP_MakeRecord: { if( zAffinity ){ pRec = pData0; do{ - applyAffinity(pRec++, *(zAffinity++), encoding); + applyAffinity(pRec, zAffinity[0], encoding); + if( zAffinity[0]==SQLITE_AFF_REAL && (pRec->flags & MEM_Int) ){ + pRec->flags |= MEM_IntReal; + pRec->flags &= ~(MEM_Int); + } + REGISTER_TRACE((int)(pRec-aMem), pRec); + zAffinity++; + pRec++; assert( zAffinity[0]==0 || pRec<=pLast ); }while( zAffinity[0] ); } @@ -80785,24 +90584,122 @@ case OP_MakeRecord: { #endif /* Loop through the elements that will make up the record to figure - ** out how much space is required for the new record. + ** out how much space is required for the new record. After this loop, + ** the Mem.uTemp field of each term should hold the serial-type that will + ** be used for that term in the generated record: + ** + ** Mem.uTemp value type + ** --------------- --------------- + ** 0 NULL + ** 1 1-byte signed integer + ** 2 2-byte signed integer + ** 3 3-byte signed integer + ** 4 4-byte signed integer + ** 5 6-byte signed integer + ** 6 8-byte signed integer + ** 7 IEEE float + ** 8 Integer constant 0 + ** 9 Integer constant 1 + ** 10,11 reserved for expansion + ** N>=12 and even BLOB + ** N>=13 and odd text + ** + ** The following additional values are computed: + ** nHdr Number of bytes needed for the record header + ** nData Number of bytes of data space needed for the record + ** nZero Zero bytes at the end of the record */ pRec = pLast; do{ assert( memIsValid(pRec) ); - pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format, &len); - if( pRec->flags & MEM_Zero ){ - if( nData ){ - if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; + if( pRec->flags & MEM_Null ){ + if( pRec->flags & MEM_Zero ){ + /* Values with MEM_Null and MEM_Zero are created by xColumn virtual + ** table methods that never invoke sqlite3_result_xxxxx() while + ** computing an unchanging column value in an UPDATE statement. + ** Give such values a special internal-use-only serial-type of 10 + ** so that they can be passed through to xUpdate and have + ** a true sqlite3_value_nochange(). */ +#ifndef SQLITE_ENABLE_NULL_TRIM + assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB ); +#endif + pRec->uTemp = 10; }else{ - nZero += pRec->u.nZero; - len -= pRec->u.nZero; + pRec->uTemp = 0; + } + nHdr++; + }else if( pRec->flags & (MEM_Int|MEM_IntReal) ){ + /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ + i64 i = pRec->u.i; + u64 uu; + testcase( pRec->flags & MEM_Int ); + testcase( pRec->flags & MEM_IntReal ); + if( i<0 ){ + uu = ~i; + }else{ + uu = i; + } + nHdr++; + testcase( uu==127 ); testcase( uu==128 ); + testcase( uu==32767 ); testcase( uu==32768 ); + testcase( uu==8388607 ); testcase( uu==8388608 ); + testcase( uu==2147483647 ); testcase( uu==2147483648LL ); + testcase( uu==140737488355327LL ); testcase( uu==140737488355328LL ); + if( uu<=127 ){ + if( (i&1)==i && file_format>=4 ){ + pRec->uTemp = 8+(u32)uu; + }else{ + nData++; + pRec->uTemp = 1; + } + }else if( uu<=32767 ){ + nData += 2; + pRec->uTemp = 2; + }else if( uu<=8388607 ){ + nData += 3; + pRec->uTemp = 3; + }else if( uu<=2147483647 ){ + nData += 4; + pRec->uTemp = 4; + }else if( uu<=140737488355327LL ){ + nData += 6; + pRec->uTemp = 5; + }else{ + nData += 8; + if( pRec->flags & MEM_IntReal ){ + /* If the value is IntReal and is going to take up 8 bytes to store + ** as an integer, then we might as well make it an 8-byte floating + ** point value */ + pRec->u.r = (double)pRec->u.i; + pRec->flags &= ~MEM_IntReal; + pRec->flags |= MEM_Real; + pRec->uTemp = 7; + }else{ + pRec->uTemp = 6; + } + } + }else if( pRec->flags & MEM_Real ){ + nHdr++; + nData += 8; + pRec->uTemp = 7; + }else{ + assert( db->mallocFailed || pRec->flags&(MEM_Str|MEM_Blob) ); + assert( pRec->n>=0 ); + len = (u32)pRec->n; + serial_type = (len*2) + 12 + ((pRec->flags & MEM_Str)!=0); + if( pRec->flags & MEM_Zero ){ + serial_type += pRec->u.nZero*2; + if( nData ){ + if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; + len += pRec->u.nZero; + }else{ + nZero += pRec->u.nZero; + } } + nData += len; + nHdr += sqlite3VarintLen(serial_type); + pRec->uTemp = serial_type; } - nData += len; - testcase( serial_type==127 ); - testcase( serial_type==128 ); - nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type); if( pRec==pData0 ) break; pRec--; }while(1); @@ -80823,57 +90720,67 @@ case OP_MakeRecord: { if( nVarintdb->aLimit[SQLITE_LIMIT_LENGTH] ){ - goto too_big; - } - /* Make sure the output register has a buffer large enough to store + /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ - if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ - goto no_mem; + if( nByte+nZero<=pOut->szMalloc ){ + /* The output register is already large enough to hold the record. + ** No error checks or buffer enlargement is required */ + pOut->z = pOut->zMalloc; + }else{ + /* Need to make sure that the output is not too big and then enlarge + ** the output register to hold the full result */ + if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + goto too_big; + } + if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ + goto no_mem; + } + } + pOut->n = (int)nByte; + pOut->flags = MEM_Blob; + if( nZero ){ + pOut->u.nZero = nZero; + pOut->flags |= MEM_Zero; } - zNewRecord = (u8 *)pOut->z; + UPDATE_MAX_BLOBSIZE(pOut); + zHdr = (u8 *)pOut->z; + zPayload = zHdr + nHdr; /* Write the record */ - i = putVarint32(zNewRecord, nHdr); - j = nHdr; + zHdr += putVarint32(zHdr, nHdr); assert( pData0<=pLast ); pRec = pData0; do{ serial_type = pRec->uTemp; /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more ** additional varints, one per column. */ - i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ + zHdr += putVarint32(zHdr, serial_type); /* serial type */ /* EVIDENCE-OF: R-64536-51728 The values for each column in the record ** immediately follow the header. */ - j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ + zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); - assert( i==nHdr ); - assert( j==nByte ); + assert( nHdr==(int)(zHdr - (u8*)pOut->z) ); + assert( nByte==(int)(zPayload - (u8*)pOut->z) ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); - pOut->n = (int)nByte; - pOut->flags = MEM_Blob; - if( nZero ){ - pOut->u.nZero = nZero; - pOut->flags |= MEM_Zero; - } - pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); - UPDATE_MAX_BLOBSIZE(pOut); break; } -/* Opcode: Count P1 P2 * * * +/* Opcode: Count P1 P2 P3 * * ** Synopsis: r[P2]=count() ** -** Store the number of entries (an integer value) in the table or index -** opened by cursor P1 in register P2 +** Store the number of entries (an integer value) in the table or index +** opened by cursor P1 in register P2. +** +** If P3==0, then an exact count is obtained, which involves visiting +** every btree page of the table. But if P3 is non-zero, an estimate +** is returned based on the current cursor position. */ -#ifndef SQLITE_OMIT_BTREECOUNT case OP_Count: { /* out2 */ i64 nEntry; BtCursor *pCrsr; @@ -80881,20 +90788,24 @@ case OP_Count: { /* out2 */ assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE ); pCrsr = p->apCsr[pOp->p1]->uc.pCursor; assert( pCrsr ); - nEntry = 0; /* Not needed. Only used to silence a warning. */ - rc = sqlite3BtreeCount(pCrsr, &nEntry); - if( rc ) goto abort_due_to_error; + if( pOp->p3 ){ + nEntry = sqlite3BtreeRowCountEst(pCrsr); + }else{ + nEntry = 0; /* Not needed. Only used to silence a warning. */ + rc = sqlite3BtreeCount(db, pCrsr, &nEntry); + if( rc ) goto abort_due_to_error; + } pOut = out2Prerelease(p, pOp); pOut->u.i = nEntry; - break; + goto check_for_interrupt; } -#endif /* Opcode: Savepoint P1 * * P4 * ** ** Open, release or rollback the savepoint named by parameter P4, depending -** on the value of P1. To open a new savepoint, P1==0. To release (commit) an -** existing savepoint, P1==1, or to rollback an existing savepoint P1==2. +** on the value of P1. To open a new savepoint set P1==0 (SAVEPOINT_BEGIN). +** To release (commit) an existing savepoint set P1==1 (SAVEPOINT_RELEASE). +** To rollback an existing savepoint set P1==2 (SAVEPOINT_ROLLBACK). */ case OP_Savepoint: { int p1; /* Value of P1 operand */ @@ -80910,7 +90821,7 @@ case OP_Savepoint: { zName = pOp->p4.z; /* Assert that the p1 parameter is valid. Also that if there is no open - ** transaction, then there cannot be any savepoints. + ** transaction, then there cannot be any savepoints. */ assert( db->pSavepoint==0 || db->autoCommit==0 ); assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK ); @@ -80920,7 +90831,7 @@ case OP_Savepoint: { if( p1==SAVEPOINT_BEGIN ){ if( db->nVdbeWrite>0 ){ - /* A new savepoint cannot be created if there are active write + /* A new savepoint cannot be created if there are active write ** statements (i.e. open read/write incremental blob handles). */ sqlite3VdbeError(p, "cannot open savepoint - SQL statements in progress"); @@ -80944,7 +90855,7 @@ case OP_Savepoint: { if( pNew ){ pNew->zName = (char *)&pNew[1]; memcpy(pNew->zName, zName, nName+1); - + /* If there is no open transaction, then mark this as a special ** "transaction savepoint". */ if( db->autoCommit ){ @@ -80962,12 +90873,13 @@ case OP_Savepoint: { } } }else{ + assert( p1==SAVEPOINT_RELEASE || p1==SAVEPOINT_ROLLBACK ); iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an ** an error is returned to the user. */ for( - pSavepoint = db->pSavepoint; + pSavepoint = db->pSavepoint; pSavepoint && sqlite3StrICmp(pSavepoint->zName, zName); pSavepoint = pSavepoint->pNext ){ @@ -80977,7 +90889,7 @@ case OP_Savepoint: { sqlite3VdbeError(p, "no such savepoint: %s", zName); rc = SQLITE_ERROR; }else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){ - /* It is not possible to release (commit) a savepoint if there are + /* It is not possible to release (commit) a savepoint if there are ** active write statements. */ sqlite3VdbeError(p, "cannot release savepoint - " @@ -80986,8 +90898,8 @@ case OP_Savepoint: { }else{ /* Determine whether or not this is a transaction savepoint. If so, - ** and this is a RELEASE command, then the current transaction - ** is committed. + ** and this is a RELEASE command, then the current transaction + ** is committed. */ int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; if( isTransaction && p1==SAVEPOINT_RELEASE ){ @@ -81001,13 +90913,17 @@ case OP_Savepoint: { p->rc = rc = SQLITE_BUSY; goto vdbe_return; } - db->isTransactionSavepoint = 0; rc = p->rc; + if( rc ){ + db->autoCommit = 0; + }else{ + db->isTransactionSavepoint = 0; + } }else{ int isSchemaChange; iSavepoint = db->nSavepoint - iSavepoint - 1; if( p1==SAVEPOINT_ROLLBACK ){ - isSchemaChange = (db->flags & SQLITE_InternChanges)!=0; + isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0; for(ii=0; iinDb; ii++){ rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT_ROLLBACK, @@ -81015,6 +90931,7 @@ case OP_Savepoint: { if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ + assert( p1==SAVEPOINT_RELEASE ); isSchemaChange = 0; } for(ii=0; iinDb; ii++){ @@ -81024,13 +90941,14 @@ case OP_Savepoint: { } } if( isSchemaChange ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); - db->flags = (db->flags | SQLITE_InternChanges); + db->mDbFlags |= DBFLAG_SchemaChange; } } - - /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all + if( rc ) goto abort_due_to_error; + + /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all ** savepoints nested inside of the savepoint being operated on. */ while( db->pSavepoint!=pSavepoint ){ pTmp = db->pSavepoint; @@ -81039,8 +90957,8 @@ case OP_Savepoint: { db->nSavepoint--; } - /* If it is a RELEASE, then destroy the savepoint being operated on - ** too. If it is a ROLLBACK TO, then set the number of deferred + /* If it is a RELEASE, then destroy the savepoint being operated on + ** too. If it is a ROLLBACK TO, then set the number of deferred ** constraint violations present in the database to the value stored ** when the savepoint was created. */ if( p1==SAVEPOINT_RELEASE ){ @@ -81051,6 +90969,7 @@ case OP_Savepoint: { db->nSavepoint--; } }else{ + assert( p1==SAVEPOINT_ROLLBACK ); db->nDeferredCons = pSavepoint->nDeferredCons; db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } @@ -81093,7 +91012,7 @@ case OP_AutoCommit: { db->autoCommit = 1; }else if( desiredAutoCommit && db->nVdbeWrite>0 ){ /* If this instruction implements a COMMIT and other VMs are writing - ** return an error indicating that the other VMs must complete first. + ** return an error indicating that the other VMs must complete first. */ sqlite3VdbeError(p, "cannot commit transaction - " "SQL statements in progress"); @@ -81110,7 +91029,6 @@ case OP_AutoCommit: { p->rc = rc = SQLITE_BUSY; goto vdbe_return; } - assert( db->nStatement==0 ); sqlite3CloseSavepoints(db); if( p->rc==SQLITE_OK ){ rc = SQLITE_DONE; @@ -81123,20 +91041,21 @@ case OP_AutoCommit: { (!desiredAutoCommit)?"cannot start a transaction within a transaction":( (iRollback)?"cannot rollback - no transaction is active": "cannot commit - no transaction is active")); - + rc = SQLITE_ERROR; goto abort_due_to_error; } - break; + /*NOTREACHED*/ assert(0); } /* Opcode: Transaction P1 P2 P3 P4 P5 ** ** Begin a transaction on database P1 if a transaction is not already ** active. -** If P2 is non-zero, then a write-transaction is started, or if a +** If P2 is non-zero, then a write-transaction is started, or if a ** read-transaction is already active, it is upgraded to a write-transaction. -** If P2 is zero, then a read-transaction is started. +** If P2 is zero, then a read-transaction is started. If P2 is 2 or more +** then an exclusive transaction is started. ** ** P1 is the index of the database file on which the transaction is ** started. Index 0 is the main database file and index 1 is the @@ -81166,21 +91085,29 @@ case OP_AutoCommit: { */ case OP_Transaction: { Btree *pBt; - int iMeta; - int iGen; + int iMeta = 0; assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); + assert( pOp->p2>=0 && pOp->p2<=2 ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); - if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ - rc = SQLITE_READONLY; + assert( rc==SQLITE_OK ); + if( pOp->p2 && (db->flags & (SQLITE_QueryOnly|SQLITE_CorruptRdOnly))!=0 ){ + if( db->flags & SQLITE_QueryOnly ){ + /* Writes prohibited by the "PRAGMA query_only=TRUE" statement */ + rc = SQLITE_READONLY; + }else{ + /* Writes prohibited due to a prior SQLITE_CORRUPT in the current + ** transaction */ + rc = SQLITE_CORRUPT; + } goto abort_due_to_error; } pBt = db->aDb[pOp->p1].pBt; if( pBt ){ - rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); + rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta); testcase( rc==SQLITE_BUSY_SNAPSHOT ); testcase( rc==SQLITE_BUSY_RECOVERY ); if( rc!=SQLITE_OK ){ @@ -81192,13 +91119,14 @@ case OP_Transaction: { goto abort_due_to_error; } - if( pOp->p2 && p->usesStmtJournal - && (db->autoCommit==0 || db->nVdbeRead>1) + if( p->usesStmtJournal + && pOp->p2 + && (db->autoCommit==0 || db->nVdbeRead>1) ){ - assert( sqlite3BtreeIsInTrans(pBt) ); + assert( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); - db->nStatement++; + db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } @@ -81213,22 +91141,21 @@ case OP_Transaction: { p->nStmtDefCons = db->nDeferredCons; p->nStmtDefImmCons = db->nDeferredImmCons; } - - /* Gather the schema version number for checking: + } + assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); + if( rc==SQLITE_OK + && pOp->p5 + && (iMeta!=pOp->p3 + || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i) + ){ + /* ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema ** version is checked to ensure that the schema has not changed since the ** SQL statement was prepared. */ - sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); - iGen = db->aDb[pOp->p1].pSchema->iGeneration; - }else{ - iGen = iMeta = 0; - } - assert( pOp->p5==0 || pOp->p4type==P4_INT32 ); - if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); - /* If the schema-cookie from the database file matches the cookie + /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. ** @@ -81238,7 +91165,7 @@ case OP_Transaction: { ** prepared queries. If such a query is out-of-date, we do not want to ** discard the database schema, as the user code implementing the ** v-table would have to be ready for the sqlite3_vtab structure itself - ** to be invalidated whenever sqlite3_step() is called from within + ** to be invalidated whenever sqlite3_step() is called from within ** a v-table method. */ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ @@ -81282,18 +91209,25 @@ case OP_ReadCookie: { /* out2 */ break; } -/* Opcode: SetCookie P1 P2 P3 * * +/* Opcode: SetCookie P1 P2 P3 * P5 ** ** Write the integer value P3 into cookie number P2 of database P1. ** P2==1 is the schema version. P2==2 is the database format. -** P2==3 is the recommended pager cache -** size, and so forth. P1==0 is the main database file and P1==1 is the +** P2==3 is the recommended pager cache +** size, and so forth. P1==0 is the main database file and P1==1 is the ** database file used to store temporary tables. ** ** A transaction must be started before executing this opcode. +** +** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal +** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement +** has P5 set to 1, so that the internal schema version will be different +** from the database schema version, resulting in a schema reset. */ case OP_SetCookie: { Db *pDb; + + sqlite3VdbeIncrWriteCounter(p, 0); assert( pOp->p2p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); @@ -81305,8 +91239,9 @@ case OP_SetCookie: { rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3); if( pOp->p2==BTREE_SCHEMA_VERSION ){ /* When the schema cookie changes, record the new cookie internally */ - pDb->pSchema->schema_cookie = pOp->p3; - db->flags |= SQLITE_InternChanges; + pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5; + db->mDbFlags |= DBFLAG_SchemaChange; + sqlite3FkClearTriggerCache(db, pOp->p1); }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; @@ -81314,7 +91249,7 @@ case OP_SetCookie: { if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, 0); p->expired = 0; } if( rc ) goto abort_due_to_error; @@ -81325,71 +91260,90 @@ case OP_SetCookie: { ** Synopsis: root=P2 iDb=P3 ** ** Open a read-only cursor for the database table whose root page is -** P2 in a database file. The database file is determined by P3. -** P3==0 means the main database, P3==1 means the database used for +** P2 in a database file. The database file is determined by P3. +** P3==0 means the main database, P3==1 means the database used for ** temporary tables, and P3>1 means used the corresponding attached ** database. Give the new cursor an identifier of P1. The P1 ** values need not be contiguous but all P1 values should be small integers. ** It is an error for P1 to be negative. ** -** If P5!=0 then use the content of register P2 as the root page, not -** the value of P2 itself. -** -** There will be a read lock on the database whenever there is an -** open cursor. If the database was unlocked prior to this instruction -** then a read lock is acquired as part of this instruction. A read -** lock allows other processes to read the database but prohibits -** any other process from modifying the database. The read lock is -** released when all cursors are closed. If this instruction attempts -** to get a read lock but fails, the script terminates with an -** SQLITE_BUSY error code. +** Allowed P5 bits: +**
              +**
            • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for +** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT +** of OP_SeekLE/OP_IdxLT) +**
            ** ** The P4 value may be either an integer (P4_INT32) or a pointer to -** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo -** structure, then said structure defines the content and collating -** sequence of the index being opened. Otherwise, if P4 is an integer -** value, it is set to the number of columns in the table. +** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo +** object, then table being opened must be an [index b-tree] where the +** KeyInfo object defines the content and collating +** sequence of that index b-tree. Otherwise, if P4 is an integer +** value, then the table being opened must be a [table b-tree] with a +** number of columns no less than the value of P4. ** ** See also: OpenWrite, ReopenIdx */ /* Opcode: ReopenIdx P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** -** The ReopenIdx opcode works exactly like ReadOpen except that it first -** checks to see if the cursor on P1 is already open with a root page -** number of P2 and if it is this opcode becomes a no-op. In other words, +** The ReopenIdx opcode works like OP_OpenRead except that it first +** checks to see if the cursor on P1 is already open on the same +** b-tree and if it is this opcode becomes a no-op. In other words, ** if the cursor is already open, do not reopen it. ** -** The ReopenIdx opcode may only be used with P5==0 and with P4 being -** a P4_KEYINFO object. Furthermore, the P3 value must be the same as -** every other ReopenIdx or OpenRead for the same cursor number. +** The ReopenIdx opcode may only be used with P5==0 or P5==OPFLAG_SEEKEQ +** and with P4 being a P4_KEYINFO object. Furthermore, the P3 value must +** be the same as every other ReopenIdx or OpenRead for the same cursor +** number. ** -** See the OpenRead opcode documentation for additional information. +** Allowed P5 bits: +**
              +**
            • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for +** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT +** of OP_SeekLE/OP_IdxLT) +**
            +** +** See also: OP_OpenRead, OP_OpenWrite */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** ** Open a read/write cursor named P1 on the table or index whose root -** page is P2. Or if P5!=0 use the content of register P2 to find the -** root page. +** page is P2 (or whose root page is held in register P2 if the +** OPFLAG_P2ISREG bit is set in P5 - see below). ** ** The P4 value may be either an integer (P4_INT32) or a pointer to -** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo -** structure, then said structure defines the content and collating -** sequence of the index being opened. Otherwise, if P4 is an integer -** value, it is set to the number of columns in the table, or to the -** largest index of any column of the table that is actually used. +** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo +** object, then table being opened must be an [index b-tree] where the +** KeyInfo object defines the content and collating +** sequence of that index b-tree. Otherwise, if P4 is an integer +** value, then the table being opened must be a [table b-tree] with a +** number of columns no less than the value of P4. +** +** Allowed P5 bits: +**
              +**
            • 0x02 OPFLAG_SEEKEQ: This cursor will only be used for +** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT +** of OP_SeekLE/OP_IdxLT) +**
            • 0x08 OPFLAG_FORDELETE: This cursor is used only to seek +** and subsequently delete entries in an index btree. This is a +** hint to the storage engine that the storage engine is allowed to +** ignore. The hint is not used by the official SQLite b*tree storage +** engine, but is used by COMDB2. +**
            • 0x10 OPFLAG_P2ISREG: Use the content of register P2 +** as the root page, not the value of P2 itself. +**
            ** -** This instruction works just like OpenRead except that it opens the cursor -** in read/write mode. For a given table, there can be one or more read-only -** cursors or a single read/write cursor but not both. +** This instruction works like OpenRead except that it opens the cursor +** in read/write mode. ** -** See also OpenRead. +** See also: OP_OpenRead, OP_ReopenIdx */ case OP_ReopenIdx: { int nField; KeyInfo *pKeyInfo; - int p2; + u32 p2; int iDb; int wrFlag; Btree *pX; @@ -81401,6 +91355,8 @@ case OP_ReopenIdx: { pCur = p->apCsr[pOp->p1]; if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){ assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */ + assert( pCur->eCurType==CURTYPE_BTREE ); + sqlite3BtreeClearCursor(pCur->uc.pCursor); goto open_cursor_set_hints; } /* If the cursor is not currently open or is open on a different @@ -81413,14 +91369,14 @@ case OP_OpenWrite: assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); - if( p->expired ){ + if( p->expired==1 ){ rc = SQLITE_ABORT_ROLLBACK; goto abort_due_to_error; } nField = 0; pKeyInfo = 0; - p2 = pOp->p2; + p2 = (u32)pOp->p2; iDb = pOp->p3; assert( iDb>=0 && iDbnDb ); assert( DbMaskTest(p->btreeMask, iDb) ); @@ -81439,13 +91395,14 @@ case OP_OpenWrite: } if( pOp->p5 & OPFLAG_P2ISREG ){ assert( p2>0 ); - assert( p2<=(p->nMem+1 - p->nCursor) ); + assert( p2<=(u32)(p->nMem+1 - p->nCursor) ); + assert( pOp->opcode==OP_OpenWrite ); pIn2 = &aMem[p2]; assert( memIsValid(pIn2) ); assert( (pIn2->flags & MEM_Int)!=0 ); sqlite3VdbeMemIntegerify(pIn2); p2 = (int)pIn2->u.i; - /* The p2 value always comes from a prior OP_CreateTable opcode and + /* The p2 value always comes from a prior OP_CreateBtree opcode and ** that opcode will always set the p2 value to 2 or more or else fail. ** If there were a failure, the prepared statement would have halted ** before reaching this instruction. */ @@ -81455,15 +91412,16 @@ case OP_OpenWrite: pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->enc==ENC(db) ); assert( pKeyInfo->db==db ); - nField = pKeyInfo->nField+pKeyInfo->nXField; + nField = pKeyInfo->nAllField; }else if( pOp->p4type==P4_INT32 ){ nField = pOp->p4.i; } assert( pOp->p1>=0 ); assert( nField>=0 ); testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ - pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE); + pCur = allocateCursor(p, pOp->p1, nField, CURTYPE_BTREE); if( pCur==0 ) goto no_mem; + pCur->iDb = iDb; pCur->nullRow = 1; pCur->isOrdered = 1; pCur->pgnoRoot = p2; @@ -81475,30 +91433,68 @@ case OP_OpenWrite: /* Set the VdbeCursor.isTable variable. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has - ** since moved into the btree layer. */ + ** since moved into the btree layer. */ pCur->isTable = pOp->p4type!=P4_KEYINFO; open_cursor_set_hints: assert( OPFLAG_BULKCSR==BTREE_BULKLOAD ); assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ ); testcase( pOp->p5 & OPFLAG_BULKCSR ); -#ifdef SQLITE_ENABLE_CURSOR_HINTS testcase( pOp->p2 & OPFLAG_SEEKEQ ); -#endif sqlite3BtreeCursorHintFlags(pCur->uc.pCursor, (pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ))); if( rc ) goto abort_due_to_error; break; } -/* Opcode: OpenEphemeral P1 P2 * P4 P5 +/* Opcode: OpenDup P1 P2 * * * +** +** Open a new cursor P1 that points to the same ephemeral table as +** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral +** opcode. Only ephemeral cursors may be duplicated. +** +** Duplicate ephemeral cursors are used for self-joins of materialized views. +*/ +case OP_OpenDup: { + VdbeCursor *pOrig; /* The original cursor to be duplicated */ + VdbeCursor *pCx; /* The new cursor */ + + pOrig = p->apCsr[pOp->p2]; + assert( pOrig ); + assert( pOrig->isEphemeral ); /* Only ephemeral cursors can be duplicated */ + + pCx = allocateCursor(p, pOp->p1, pOrig->nField, CURTYPE_BTREE); + if( pCx==0 ) goto no_mem; + pCx->nullRow = 1; + pCx->isEphemeral = 1; + pCx->pKeyInfo = pOrig->pKeyInfo; + pCx->isTable = pOrig->isTable; + pCx->pgnoRoot = pOrig->pgnoRoot; + pCx->isOrdered = pOrig->isOrdered; + pCx->ub.pBtx = pOrig->ub.pBtx; + pCx->hasBeenDuped = 1; + pOrig->hasBeenDuped = 1; + rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR, + pCx->pKeyInfo, pCx->uc.pCursor); + /* The sqlite3BtreeCursor() routine can only fail for the first cursor + ** opened for a database. Since there is already an open cursor when this + ** opcode is run, the sqlite3BtreeCursor() cannot fail */ + assert( rc==SQLITE_OK ); + break; +} + + +/* Opcode: OpenEphemeral P1 P2 P3 P4 P5 ** Synopsis: nColumn=P2 ** ** Open a new cursor P1 to a transient table. -** The cursor is always opened read/write even if +** The cursor is always opened read/write even if ** the main database is read-only. The ephemeral ** table is deleted automatically when the cursor is closed. ** +** If the cursor P1 is already opened on an ephemeral table, the table +** is cleared (all content is erased). +** ** P2 is the number of columns in the ephemeral table. ** The cursor points to a BTree table if P4==0 and to a BTree index ** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure @@ -81508,6 +91504,10 @@ case OP_OpenWrite: ** in btree.h. These flags control aspects of the operation of ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are ** added automatically. +** +** If P3 is positive, then reg[P3] is modified slightly so that it +** can be used as zero-length data for OP_Insert. This is an optimization +** that avoids an extra OP_Blob opcode to initialize that register. */ /* Opcode: OpenAutoindex P1 P2 * P4 * ** Synopsis: nColumn=P2 @@ -81517,12 +91517,12 @@ case OP_OpenWrite: ** by this opcode will be used for automatically created transient ** indices in joins. */ -case OP_OpenAutoindex: +case OP_OpenAutoindex: case OP_OpenEphemeral: { VdbeCursor *pCx; KeyInfo *pKeyInfo; - static const int vfsFlags = + static const int vfsFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | @@ -81530,41 +91530,66 @@ case OP_OpenEphemeral: { SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); - pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE); - if( pCx==0 ) goto no_mem; - pCx->nullRow = 1; - pCx->isEphemeral = 1; - rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, - BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); - if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1); - } - if( rc==SQLITE_OK ){ - /* If a transient index is required, create it by calling - ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before - ** opening it. If a transient table is required, just use the - ** automatically created table with root-page 1 (an BLOB_INTKEY table). - */ - if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ - int pgno; - assert( pOp->p4type==P4_KEYINFO ); - rc = sqlite3BtreeCreateTable(pCx->pBtx, &pgno, BTREE_BLOBKEY | pOp->p5); + if( pOp->p3>0 ){ + /* Make register reg[P3] into a value that can be used as the data + ** form sqlite3BtreeInsert() where the length of the data is zero. */ + assert( pOp->p2==0 ); /* Only used when number of columns is zero */ + assert( pOp->opcode==OP_OpenEphemeral ); + assert( aMem[pOp->p3].flags & MEM_Null ); + aMem[pOp->p3].n = 0; + aMem[pOp->p3].z = ""; + } + pCx = p->apCsr[pOp->p1]; + if( pCx && !pCx->hasBeenDuped && ALWAYS(pOp->p2<=pCx->nField) ){ + /* If the ephermeral table is already open and has no duplicates from + ** OP_OpenDup, then erase all existing content so that the table is + ** empty again, rather than creating a new table. */ + assert( pCx->isEphemeral ); + pCx->seqCount = 0; + pCx->cacheStatus = CACHE_STALE; + rc = sqlite3BtreeClearTable(pCx->ub.pBtx, pCx->pgnoRoot, 0); + }else{ + pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_BTREE); + if( pCx==0 ) goto no_mem; + pCx->isEphemeral = 1; + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->ub.pBtx, + BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, + vfsFlags); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginTrans(pCx->ub.pBtx, 1, 0); if( rc==SQLITE_OK ){ - assert( pgno==MASTER_ROOT+1 ); - assert( pKeyInfo->db==db ); - assert( pKeyInfo->enc==ENC(db) ); - rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR, - pKeyInfo, pCx->uc.pCursor); + /* If a transient index is required, create it by calling + ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before + ** opening it. If a transient table is required, just use the + ** automatically created table with root-page 1 (an BLOB_INTKEY table). + */ + if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){ + assert( pOp->p4type==P4_KEYINFO ); + rc = sqlite3BtreeCreateTable(pCx->ub.pBtx, &pCx->pgnoRoot, + BTREE_BLOBKEY | pOp->p5); + if( rc==SQLITE_OK ){ + assert( pCx->pgnoRoot==SCHEMA_ROOT+1 ); + assert( pKeyInfo->db==db ); + assert( pKeyInfo->enc==ENC(db) ); + rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR, + pKeyInfo, pCx->uc.pCursor); + } + pCx->isTable = 0; + }else{ + pCx->pgnoRoot = SCHEMA_ROOT; + rc = sqlite3BtreeCursor(pCx->ub.pBtx, SCHEMA_ROOT, BTREE_WRCSR, + 0, pCx->uc.pCursor); + pCx->isTable = 1; + } + } + pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); + if( rc ){ + sqlite3BtreeClose(pCx->ub.pBtx); } - pCx->isTable = 0; - }else{ - rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR, - 0, pCx->uc.pCursor); - pCx->isTable = 1; } } if( rc ) goto abort_due_to_error; - pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); + pCx->nullRow = 1; break; } @@ -81583,7 +91608,7 @@ case OP_SorterOpen: { assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); - pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER); + pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_SORTER); if( pCx==0 ) goto no_mem; pCx->pKeyInfo = pOp->p4.pKeyInfo; assert( pCx->pKeyInfo->db==db ); @@ -81616,7 +91641,7 @@ case OP_SequenceTest: { ** ** Open a new cursor that points to a fake table that contains a single ** row of data. The content of that one row is the content of memory -** register P2. In other words, cursor P1 becomes an alias for the +** register P2. In other words, cursor P1 becomes an alias for the ** MEM_Blob content contained in register P2. ** ** A pseudo-table created by this opcode is used to hold a single @@ -81632,11 +91657,16 @@ case OP_OpenPseudo: { assert( pOp->p1>=0 ); assert( pOp->p3>=0 ); - pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO); + pCx = allocateCursor(p, pOp->p1, pOp->p3, CURTYPE_PSEUDO); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; - pCx->uc.pseudoTableReg = pOp->p2; + pCx->seekResult = pOp->p2; pCx->isTable = 1; + /* Give this pseudo-cursor a fake BtCursor pointer so that pCx + ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test + ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto() + ** which is a performance optimization */ + pCx->uc.pCursor = sqlite3BtreeFakeValidCursor(); assert( pOp->p5==0 ); break; } @@ -81676,21 +91706,23 @@ case OP_ColumnsUsed: { /* Opcode: SeekGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), -** use the value in register P3 as the key. If cursor P1 refers -** to an SQL index, then P3 is the first in an array of P4 registers -** that are used as an unpacked index key. +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as the key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. ** -** Reposition cursor P1 so that it points to the smallest entry that -** is greater than or equal to the key value. If there are no records +** Reposition cursor P1 so that it points to the smallest entry that +** is greater than or equal to the key value. If there are no records ** greater than or equal to the key and P2 is not zero, then jump to P2. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this -** opcode will always land on a record that equally equals the key, or -** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this -** opcode must be followed by an IdxLE opcode with the same arguments. -** The IdxLE opcode will be skipped if this opcode succeeds, but the -** IdxLE opcode will be used on subsequent loop iterations. +** opcode will either land on a record that exactly matches the key, or +** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ, +** this opcode must be followed by an IdxLE opcode with the same arguments. +** The IdxGT opcode will be skipped if this opcode succeeds, but the +** IdxGT opcode will be used on subsequent loop iterations. The +** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this +** is an equality search. ** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is @@ -81701,13 +91733,13 @@ case OP_ColumnsUsed: { /* Opcode: SeekGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), -** use the value in register P3 as a key. If cursor P1 refers -** to an SQL index, then P3 is the first in an array of P4 registers -** that are used as an unpacked index key. +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. ** -** Reposition cursor P1 so that it points to the smallest entry that -** is greater than the key value. If there are no records greater than +** Reposition cursor P1 so that it points to the smallest entry that +** is greater than the key value. If there are no records greater than ** the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in forward order, @@ -81716,16 +91748,16 @@ case OP_ColumnsUsed: { ** ** See also: Found, NotFound, SeekLt, SeekGe, SeekLe */ -/* Opcode: SeekLT P1 P2 P3 P4 * +/* Opcode: SeekLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), -** use the value in register P3 as a key. If cursor P1 refers -** to an SQL index, then P3 is the first in an array of P4 registers -** that are used as an unpacked index key. +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. ** -** Reposition cursor P1 so that it points to the largest entry that -** is less than the key value. If there are no records less than +** Reposition cursor P1 so that it points to the largest entry that +** is less than the key value. If there are no records less than ** the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in reverse order, @@ -81737,13 +91769,13 @@ case OP_ColumnsUsed: { /* Opcode: SeekLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), -** use the value in register P3 as a key. If cursor P1 refers -** to an SQL index, then P3 is the first in an array of P4 registers -** that are used as an unpacked index key. +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. ** -** Reposition cursor P1 so that it points to the largest entry that -** is less than or equal to the key value. If there are no records +** Reposition cursor P1 so that it points to the largest entry that +** is less than or equal to the key value. If there are no records ** less than or equal to the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in reverse order, @@ -81751,18 +91783,20 @@ case OP_ColumnsUsed: { ** configured to use Prev, not Next. ** ** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this -** opcode will always land on a record that equally equals the key, or -** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this -** opcode must be followed by an IdxGE opcode with the same arguments. +** opcode will either land on a record that exactly matches the key, or +** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ, +** this opcode must be followed by an IdxLE opcode with the same arguments. ** The IdxGE opcode will be skipped if this opcode succeeds, but the -** IdxGE opcode will be used on subsequent loop iterations. +** IdxGE opcode will be used on subsequent loop iterations. The +** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this +** is an equality search. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ -case OP_SeekLT: /* jump, in3 */ -case OP_SeekLE: /* jump, in3 */ -case OP_SeekGE: /* jump, in3 */ -case OP_SeekGT: { /* jump, in3 */ +case OP_SeekLT: /* jump, in3, group */ +case OP_SeekLE: /* jump, in3, group */ +case OP_SeekGE: /* jump, in3, group */ +case OP_SeekGT: { /* jump, in3, group */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ @@ -81788,8 +91822,11 @@ case OP_SeekGT: { /* jump, in3 */ pC->seekOp = pOp->opcode; #endif + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; if( pC->isTable ){ - /* The BTREE_SEEK_EQ flag is only set on index cursors */ + u16 flags3, newType; + /* The OPFLAG_SEEKEQ/BTREE_SEEK_EQ flag is only set on index cursors */ assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 || CORRUPT_DB ); @@ -81797,20 +91834,29 @@ case OP_SeekGT: { /* jump, in3 */ ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; - if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + flags3 = pIn3->flags; + if( (flags3 & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } - iKey = sqlite3VdbeIntValue(pIn3); + iKey = sqlite3VdbeIntValue(pIn3); /* Get the integer key value */ + newType = pIn3->flags; /* Record the type after applying numeric affinity */ + pIn3->flags = flags3; /* But convert the type back to its original */ /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ - if( (pIn3->flags & MEM_Int)==0 ){ - if( (pIn3->flags & MEM_Real)==0 ){ - /* If the P3 value cannot be converted into any kind of a number, - ** then the seek is not possible, so jump to P2 */ - VdbeBranchTaken(1,2); goto jump_to_p2; - break; + if( (newType & (MEM_Int|MEM_IntReal))==0 ){ + int c; + if( (newType & MEM_Real)==0 ){ + if( (newType & MEM_Null) || oc>=OP_SeekGE ){ + VdbeBranchTaken(1,2); + goto jump_to_p2; + }else{ + rc = sqlite3BtreeLast(pC->uc.pCursor, &res); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + goto seek_not_found; + } } + c = sqlite3IntFloatCompare(iKey, pIn3->u.r); /* If the approximation iKey is larger than the actual real search ** term, substitute >= for > and < for <=. e.g. if the search term @@ -81819,7 +91865,7 @@ case OP_SeekGT: { /* jump, in3 */ ** (x > 4.9) -> (x >= 5) ** (x <= 4.9) -> (x < 5) */ - if( pIn3->u.r<(double)iKey ){ + if( c>0 ){ assert( OP_SeekGE==(OP_SeekGT-1) ); assert( OP_SeekLT==(OP_SeekLE-1) ); assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) ); @@ -81828,27 +91874,30 @@ case OP_SeekGT: { /* jump, in3 */ /* If the approximation iKey is smaller than the actual real search ** term, substitute <= for < and > for >=. */ - else if( pIn3->u.r>(double)iKey ){ + else if( c<0 ){ assert( OP_SeekLE==(OP_SeekLT+1) ); assert( OP_SeekGT==(OP_SeekGE+1) ); assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } - } - rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res); + } + rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } }else{ - /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and - ** OP_SeekLE opcodes are allowed, and these must be immediately followed - ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key. + /* For a cursor with the OPFLAG_SEEKEQ/BTREE_SEEK_EQ hint, only the + ** OP_SeekGE and OP_SeekLE opcodes are allowed, and these must be + ** immediately followed by an OP_IdxGT or OP_IdxLT opcode, respectively, + ** with the same key. */ if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){ eqOnly = 1; assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE ); assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); + assert( pOp->opcode==OP_SeekGE || pOp[1].opcode==OP_IdxLT ); + assert( pOp->opcode==OP_SeekLE || pOp[1].opcode==OP_IdxGT ); assert( pOp[1].p1==pOp[0].p1 ); assert( pOp[1].p2==pOp[0].p2 ); assert( pOp[1].p3==pOp[0].p3 ); @@ -81879,7 +91928,7 @@ case OP_SeekGT: { /* jump, in3 */ { int i; for(i=0; iuc.pCursor, &r, 0, 0, &res); + rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } @@ -81888,16 +91937,21 @@ case OP_SeekGT: { /* jump, in3 */ goto seek_not_found; } } - pC->deferredMoveto = 0; - pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_TEST sqlite3_search_count++; #endif if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT ); if( res<0 || (res==0 && oc==OP_SeekGT) ){ res = 0; - rc = sqlite3BtreeNext(pC->uc.pCursor, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqlite3BtreeNext(pC->uc.pCursor, 0); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + res = 1; + }else{ + goto abort_due_to_error; + } + } }else{ res = 0; } @@ -81905,8 +91959,15 @@ case OP_SeekGT: { /* jump, in3 */ assert( oc==OP_SeekLT || oc==OP_SeekLE ); if( res>0 || (res==0 && oc==OP_SeekLT) ){ res = 0; - rc = sqlite3BtreePrevious(pC->uc.pCursor, &res); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + rc = sqlite3BtreePrevious(pC->uc.pCursor, 0); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + res = 1; + }else{ + goto abort_due_to_error; + } + } }else{ /* res might be negative because the table is empty. Check to ** see if this is the case. @@ -81926,6 +91987,200 @@ case OP_SeekGT: { /* jump, in3 */ break; } + +/* Opcode: SeekScan P1 P2 * * * +** Synopsis: Scan-ahead up to P1 rows +** +** This opcode is a prefix opcode to OP_SeekGE. In other words, this +** opcode must be immediately followed by OP_SeekGE. This constraint is +** checked by assert() statements. +** +** This opcode uses the P1 through P4 operands of the subsequent +** OP_SeekGE. In the text that follows, the operands of the subsequent +** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only +** the P1 and P2 operands of this opcode are also used, and are called +** This.P1 and This.P2. +** +** This opcode helps to optimize IN operators on a multi-column index +** where the IN operator is on the later terms of the index by avoiding +** unnecessary seeks on the btree, substituting steps to the next row +** of the b-tree instead. A correct answer is obtained if this opcode +** is omitted or is a no-op. +** +** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which +** is the desired entry that we want the cursor SeekGE.P1 to be pointing +** to. Call this SeekGE.P4/P5 row the "target". +** +** If the SeekGE.P1 cursor is not currently pointing to a valid row, +** then this opcode is a no-op and control passes through into the OP_SeekGE. +** +** If the SeekGE.P1 cursor is pointing to a valid row, then that row +** might be the target row, or it might be near and slightly before the +** target row. This opcode attempts to position the cursor on the target +** row by, perhaps by invoking sqlite3BtreeStep() on the cursor +** between 0 and This.P1 times. +** +** There are three possible outcomes from this opcode:
              +** +**
            1. If after This.P1 steps, the cursor is still pointing to a place that +** is earlier in the btree than the target row, then fall through +** into the subsquence OP_SeekGE opcode. +** +**
            2. If the cursor is successfully moved to the target row by 0 or more +** sqlite3BtreeNext() calls, then jump to This.P2, which will land just +** past the OP_IdxGT or OP_IdxGE opcode that follows the OP_SeekGE. +** +**
            3. If the cursor ends up past the target row (indicating the the target +** row does not exist in the btree) then jump to SeekOP.P2. +**
            +*/ +case OP_SeekScan: { + VdbeCursor *pC; + int res; + int nStep; + UnpackedRecord r; + + assert( pOp[1].opcode==OP_SeekGE ); + + /* pOp->p2 points to the first instruction past the OP_IdxGT that + ** follows the OP_SeekGE. */ + assert( pOp->p2>=(int)(pOp-aOp)+2 ); + assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE ); + testcase( aOp[pOp->p2-1].opcode==OP_IdxGE ); + assert( pOp[1].p1==aOp[pOp->p2-1].p1 ); + assert( pOp[1].p2==aOp[pOp->p2-1].p2 ); + assert( pOp[1].p3==aOp[pOp->p2-1].p3 ); + + assert( pOp->p1>0 ); + pC = p->apCsr[pOp[1].p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( !pC->isTable ); + if( !sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... cursor not valid - fall through\n"); + } +#endif + break; + } + nStep = pOp->p1; + assert( nStep>=1 ); + r.pKeyInfo = pC->pKeyInfo; + r.nField = (u16)pOp[1].p4.i; + r.default_rc = 0; + r.aMem = &aMem[pOp[1].p3]; +#ifdef SQLITE_DEBUG + { + int i; + for(i=0; i0 ){ + seekscan_search_fail: +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... %d steps and then skip\n", pOp->p1 - nStep); + } +#endif + VdbeBranchTaken(1,3); + pOp++; + goto jump_to_p2; + } + if( res==0 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... %d steps and then success\n", pOp->p1 - nStep); + } +#endif + VdbeBranchTaken(2,3); + goto jump_to_p2; + break; + } + if( nStep<=0 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... fall through after %d steps\n", pOp->p1); + } +#endif + VdbeBranchTaken(0,3); + break; + } + nStep--; + rc = sqlite3BtreeNext(pC->uc.pCursor, 0); + if( rc ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + goto seekscan_search_fail; + }else{ + goto abort_due_to_error; + } + } + } + + break; +} + + +/* Opcode: SeekHit P1 P2 P3 * * +** Synopsis: set P2<=seekHit<=P3 +** +** Increase or decrease the seekHit value for cursor P1, if necessary, +** so that it is no less than P2 and no greater than P3. +** +** The seekHit integer represents the maximum of terms in an index for which +** there is known to be at least one match. If the seekHit value is smaller +** than the total number of equality terms in an index lookup, then the +** OP_IfNoHope opcode might run to see if the IN loop can be abandoned +** early, thus saving work. This is part of the IN-early-out optimization. +** +** P1 must be a valid b-tree cursor. +*/ +case OP_SeekHit: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pOp->p3>=pOp->p2 ); + if( pC->seekHitp2 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p2); + } +#endif + pC->seekHit = pOp->p2; + }else if( pC->seekHit>pOp->p3 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p3); + } +#endif + pC->seekHit = pOp->p3; + } + break; +} + +/* Opcode: IfNotOpen P1 P2 * * * +** Synopsis: if( !csr[P1] ) goto P2 +** +** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through. +*/ +case OP_IfNotOpen: { /* jump */ + assert( pOp->p1>=0 && pOp->p1nCursor ); + VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2); + if( !p->apCsr[pOp->p1] ){ + goto jump_to_p2_and_check_for_interrupt; + } + break; +} + /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** @@ -81949,9 +92204,9 @@ case OP_SeekGT: { /* jump, in3 */ ** If P4==0 then register P3 holds a blob constructed by MakeRecord. If ** P4>0 then register P3 is the first of P4 registers that form an unpacked ** record. -** +** ** Cursor P1 is on an index btree. If the record identified by P3 and P4 -** is not the prefix of any entry in P1 then a jump is made to P2. If P1 +** is not the prefix of any entry in P1 then a jump is made to P2. If P1 ** does contain an entry whose prefix matches the P3/P4 record then control ** falls through to the next instruction and P1 is left pointing at the ** matching entry. @@ -81960,7 +92215,38 @@ case OP_SeekGT: { /* jump, in3 */ ** advanced in either direction. In other words, the Next and Prev ** opcodes do not work after this operation. ** -** See also: Found, NotExists, NoConflict +** See also: Found, NotExists, NoConflict, IfNoHope +*/ +/* Opcode: IfNoHope P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** Register P3 is the first of P4 registers that form an unpacked +** record. Cursor P1 is an index btree. P2 is a jump destination. +** In other words, the operands to this opcode are the same as the +** operands to OP_NotFound and OP_IdxGT. +** +** This opcode is an optimization attempt only. If this opcode always +** falls through, the correct answer is still obtained, but extra works +** is performed. +** +** A value of N in the seekHit flag of cursor P1 means that there exists +** a key P3:N that will match some record in the index. We want to know +** if it is possible for a record P3:P4 to match some record in the +** index. If it is not possible, we can skips some work. So if seekHit +** is less than P4, attempt to find out if a match is possible by running +** OP_NotFound. +** +** This opcode is used in IN clause processing for a multi-column key. +** If an IN clause is attached to an element of the key other than the +** left-most element, and if there are no matches on the most recent +** seek over the whole key, then it might be that one of the key element +** to the left is prohibiting a match, and hence there is "no hope" of +** any match regardless of how many IN clause elements are checked. +** In such a case, we abandon the IN clause search early, using this +** opcode. The opcode name comes from the fact that the +** jump is taken if there is "no hope" of achieving a match. +** +** See also: NotFound, SeekHit */ /* Opcode: NoConflict P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] @@ -81968,7 +92254,7 @@ case OP_SeekGT: { /* jump, in3 */ ** If P4==0 then register P3 holds a blob constructed by MakeRecord. If ** P4>0 then register P3 is the first of P4 registers that form an unpacked ** record. -** +** ** Cursor P1 is on an index btree. If the record identified by P3 and P4 ** contains any NULL value, jump immediately to P2. If all terms of the ** record are not-NULL then a check is done to determine if any row in the @@ -81985,6 +92271,20 @@ case OP_SeekGT: { /* jump, in3 */ ** ** See also: NotFound, Found, NotExists */ +case OP_IfNoHope: { /* jump, in3 */ + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("seekHit is %d\n", pC->seekHit); + } +#endif + if( pC->seekHit>=pOp->p4.i ) break; + /* Fall through into OP_NotFound */ + /* no break */ deliberate_fall_through +} case OP_NoConflict: /* jump, in3 */ case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ @@ -82026,10 +92326,12 @@ case OP_Found: { /* jump, in3 */ pIdxKey = &r; pFree = 0; }else{ + assert( pIn3->flags & MEM_Blob ); + rc = ExpandBlob(pIn3); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc ) goto no_mem; pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo); if( pIdxKey==0 ) goto no_mem; - assert( pIn3->flags & MEM_Blob ); - (void)ExpandBlob(pIn3); sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; @@ -82045,8 +92347,8 @@ case OP_Found: { /* jump, in3 */ } } } - rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res); - if( pFree ) sqlite3DbFree(db, pFree); + rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &res); + if( pFree ) sqlite3DbFreeNN(db, pFree); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } @@ -82061,6 +92363,7 @@ case OP_Found: { /* jump, in3 */ }else{ VdbeBranchTaken(takeJump||alreadyExists==0,2); if( takeJump || !alreadyExists ) goto jump_to_p2; + if( pOp->opcode==OP_IfNoHope ) pC->seekHit = pOp->p4.i; } break; } @@ -82070,9 +92373,9 @@ case OP_Found: { /* jump, in3 */ ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). If register P3 does not contain an integer or if P1 does not -** contain a record with rowid P3 then jump immediately to P2. +** contain a record with rowid P3 then jump immediately to P2. ** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain -** a record with rowid P3 then +** a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** @@ -82095,7 +92398,7 @@ case OP_Found: { /* jump, in3 */ ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). P3 is an integer rowid. If P1 does not contain a record with ** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an -** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then +** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** @@ -82119,27 +92422,41 @@ case OP_SeekRowid: { /* jump, in3 */ u64 iKey; pIn3 = &aMem[pOp->p3]; - if( (pIn3->flags & MEM_Int)==0 ){ - applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); - if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2; + testcase( pIn3->flags & MEM_Int ); + testcase( pIn3->flags & MEM_IntReal ); + testcase( pIn3->flags & MEM_Real ); + testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str ); + if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){ + /* If pIn3->u.i does not contain an integer, compute iKey as the + ** integer value of pIn3. Jump to P2 if pIn3 cannot be converted + ** into an integer without loss of information. Take care to avoid + ** changing the datatype of pIn3, however, as it is used by other + ** parts of the prepared statement. */ + Mem x = pIn3[0]; + applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding); + if( (x.flags & MEM_Int)==0 ) goto jump_to_p2; + iKey = x.u.i; + goto notExistsWithKey; } /* Fall through into OP_NotExists */ + /* no break */ deliberate_fall_through case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; - assert( pIn3->flags & MEM_Int ); + assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid ); assert( pOp->p1>=0 && pOp->p1nCursor ); + iKey = pIn3->u.i; +notExistsWithKey: pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG - pC->seekOp = 0; + if( pOp->opcode==OP_SeekRowid ) pC->seekOp = OP_SeekRowid; #endif assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); res = 0; - iKey = pIn3->u.i; - rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); + rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res); assert( rc==SQLITE_OK || res==0 ); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; @@ -82165,7 +92482,7 @@ case OP_NotExists: /* jump, in3 */ ** Find the next available sequence number for cursor P1. ** Write the sequence number into register P2. ** The sequence number on the cursor is incremented after this -** instruction. +** instruction. */ case OP_Sequence: { /* out2 */ assert( pOp->p1>=0 && pOp->p1nCursor ); @@ -82185,9 +92502,9 @@ case OP_Sequence: { /* out2 */ ** table that cursor P1 points to. The new record number is written ** written to register P2. ** -** If P3>0 then P3 is a register in the root frame of this VDBE that holds +** If P3>0 then P3 is a register in the root frame of this VDBE that holds ** the largest previously generated record number. No new record numbers are -** allowed to be less than this value. When this value reaches its maximum, +** allowed to be less than this value. When this value reaches its maximum, ** an SQLITE_FULL error is generated. The P3 register is updated with the ' ** generated record number. This P3 mechanism is used to help implement the ** AUTOINCREMENT feature. @@ -82197,8 +92514,10 @@ case OP_NewRowid: { /* out2 */ VdbeCursor *pC; /* Cursor of table to get the new rowid */ int res; /* Result of an sqlite3BtreeLast() */ int cnt; /* Counter to limit the number of searches */ +#ifndef SQLITE_OMIT_AUTOINCREMENT Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */ VdbeFrame *pFrame; /* Root frame of VDBE */ +#endif v = 0; res = 0; @@ -82206,6 +92525,7 @@ case OP_NewRowid: { /* out2 */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); + assert( pC->isTable ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); { @@ -82293,7 +92613,7 @@ case OP_NewRowid: { /* out2 */ do{ sqlite3_randomness(sizeof(v), &v); v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */ - }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v, + }while( ((rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)v, 0, &res))==SQLITE_OK) && (res==0) && (++cnt<100)); @@ -82335,8 +92655,8 @@ case OP_NewRowid: { /* out2 */ ** is part of an INSERT operation. The difference is only important to ** the update hook. ** -** Parameter P4 may point to a Table structure, or may be NULL. If it is -** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked +** Parameter P4 may point to a Table structure, or may be NULL. If it is +** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked ** following a successful insert. ** ** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically @@ -82348,78 +92668,63 @@ case OP_NewRowid: { /* out2 */ ** This instruction only works on tables. The equivalent instruction ** for indices is OP_IdxInsert. */ -/* Opcode: InsertInt P1 P2 P3 P4 P5 -** Synopsis: intkey=P3 data=r[P2] -** -** This works exactly like OP_Insert except that the key is the -** integer value P3, not the value of the integer stored in register P3. -*/ -case OP_Insert: -case OP_InsertInt: { +case OP_Insert: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ VdbeCursor *pC; /* Cursor to table into which insert is written */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ Table *pTab; /* Table structure - used by update and pre-update hooks */ - int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ BtreePayload x; /* Payload to be inserted */ - op = 0; pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1nCursor ); assert( memIsValid(pData) ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->deferredMoveto==0 ); assert( pC->uc.pCursor!=0 ); assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable ); assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); REGISTER_TRACE(pOp->p2, pData); + sqlite3VdbeIncrWriteCounter(p, pC); - if( pOp->opcode==OP_Insert ){ - pKey = &aMem[pOp->p3]; - assert( pKey->flags & MEM_Int ); - assert( memIsValid(pKey) ); - REGISTER_TRACE(pOp->p3, pKey); - x.nKey = pKey->u.i; - }else{ - assert( pOp->opcode==OP_InsertInt ); - x.nKey = pOp->p3; - } + pKey = &aMem[pOp->p3]; + assert( pKey->flags & MEM_Int ); + assert( memIsValid(pKey) ); + REGISTER_TRACE(pOp->p3, pKey); + x.nKey = pKey->u.i; if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); zDb = db->aDb[pC->iDb].zDbSName; pTab = pOp->p4.pTab; assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) ); - op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); }else{ - pTab = 0; /* Not needed. Silence a compiler warning. */ - zDb = 0; /* Not needed. Silence a compiler warning. */ + pTab = 0; + zDb = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update hook, if any */ - if( db->xPreUpdateCallback - && pOp->p4type==P4_TABLE - && !(pOp->p5 & OPFLAG_ISUPDATE) - ){ - sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2); + if( pTab ){ + if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){ + sqlite3VdbePreUpdateHook(p,pC,SQLITE_INSERT,zDb,pTab,x.nKey,pOp->p2,-1); + } + if( db->xUpdateCallback==0 || pTab->aCol==0 ){ + /* Prevent post-update hook from running in cases when it should not */ + pTab = 0; + } } if( pOp->p5 & OPFLAG_ISNOOP ) break; #endif if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; - if( pData->flags & MEM_Null ){ - x.pData = 0; - x.nData = 0; - }else{ - assert( pData->flags & (MEM_Blob|MEM_Str) ); - x.pData = pData->z; - x.nData = pData->n; - } + assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 ); + x.pData = pData->z; + x.nData = pData->n; seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ x.nZero = pData->u.nZero; @@ -82428,19 +92733,51 @@ case OP_InsertInt: { } x.pKey = 0; rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, - (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult + (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), + seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc ) goto abort_due_to_error; - if( db->xUpdateCallback && op ){ - db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey); + if( pTab ){ + assert( db->xUpdateCallback!=0 ); + assert( pTab->aCol!=0 ); + db->xUpdateCallback(db->pUpdateArg, + (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT, + zDb, pTab->zName, x.nKey); } break; } +/* Opcode: RowCell P1 P2 P3 * * +** +** P1 and P2 are both open cursors. Both must be opened on the same type +** of table - intkey or index. This opcode is used as part of copying +** the current row from P2 into P1. If the cursors are opened on intkey +** tables, register P3 contains the rowid to use with the new record in +** P1. If they are opened on index tables, P3 is not used. +** +** This opcode must be followed by either an Insert or InsertIdx opcode +** with the OPFLAG_PREFORMAT flag set to complete the insert operation. +*/ +case OP_RowCell: { + VdbeCursor *pDest; /* Cursor to write to */ + VdbeCursor *pSrc; /* Cursor to read from */ + i64 iKey; /* Rowid value to insert with */ + assert( pOp[1].opcode==OP_Insert || pOp[1].opcode==OP_IdxInsert ); + assert( pOp[1].opcode==OP_Insert || pOp->p3==0 ); + assert( pOp[1].opcode==OP_IdxInsert || pOp->p3>0 ); + assert( pOp[1].p5 & OPFLAG_PREFORMAT ); + pDest = p->apCsr[pOp->p1]; + pSrc = p->apCsr[pOp->p2]; + iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0; + rc = sqlite3BtreeTransferRow(pDest->uc.pCursor, pSrc->uc.pCursor, iKey); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + break; +}; + /* Opcode: Delete P1 P2 P3 P4 P5 ** ** Delete the record at which the P1 cursor is currently pointing. @@ -82449,7 +92786,7 @@ case OP_InsertInt: { ** the cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. As a result, in this case -** it is ok to delete a record from within a Next loop. If +** it is ok to delete a record from within a Next loop. If ** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be ** left in an undefined state. ** @@ -82465,11 +92802,11 @@ case OP_InsertInt: { ** P1 must not be pseudo-table. It has to be a real table with ** multiple rows. ** -** If P4 is not NULL then it points to a Table object. In this case either +** If P4 is not NULL then it points to a Table object. In this case either ** the update or pre-update hook, or both, may be invoked. The P1 cursor must -** have been positioned using OP_NotFound prior to invoking this opcode in -** this case. Specifically, if one is configured, the pre-update hook is -** invoked if P4 is not NULL. The update-hook is invoked if one is configured, +** have been positioned using OP_NotFound prior to invoking this opcode in +** this case. Specifically, if one is configured, the pre-update hook is +** invoked if P4 is not NULL. The update-hook is invoked if one is configured, ** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2. ** ** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address @@ -82489,21 +92826,26 @@ case OP_Delete: { assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); + sqlite3VdbeIncrWriteCounter(p, pC); #ifdef SQLITE_DEBUG - if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ + if( pOp->p4type==P4_TABLE + && HasRowid(pOp->p4.pTab) + && pOp->p5==0 + && sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) + ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); - assert( pC->movetoTarget==iKey ); + assert( CORRUPT_DB || pC->movetoTarget==iKey ); } #endif /* If the update-hook or pre-update-hook will be invoked, set zDb to ** the name of the db to pass as to it. Also set local pTab to a copy ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was - ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set + ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set ** VdbeCursor.movetoTarget to the current rowid. */ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); @@ -82514,27 +92856,28 @@ case OP_Delete: { pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ - zDb = 0; /* Not needed. Silence a compiler warning. */ - pTab = 0; /* Not needed. Silence a compiler warning. */ + zDb = 0; + pTab = 0; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update-hook if required. */ - if( db->xPreUpdateCallback && pOp->p4.pTab ){ - assert( !(opflags & OPFLAG_ISUPDATE) - || HasRowid(pTab)==0 - || (aMem[pOp->p3].flags & MEM_Int) + assert( db->xPreUpdateCallback==0 || pTab==pOp->p4.pTab ); + if( db->xPreUpdateCallback && pTab ){ + assert( !(opflags & OPFLAG_ISUPDATE) + || HasRowid(pTab)==0 + || (aMem[pOp->p3].flags & MEM_Int) ); sqlite3VdbePreUpdateHook(p, pC, - (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, + (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE, zDb, pTab, pC->movetoTarget, - pOp->p3 + pOp->p3, -1 ); } if( opflags & OPFLAG_ISNOOP ) break; #endif - - /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ + + /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 ); assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION ); assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE ); @@ -82561,7 +92904,7 @@ case OP_Delete: { /* Invoke the update-hook if required. */ if( opflags & OPFLAG_NCHANGE ){ p->nChange++; - if( db->xUpdateCallback && HasRowid(pTab) ){ + if( db->xUpdateCallback && ALWAYS(pTab!=0) && HasRowid(pTab) ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName, pC->movetoTarget); assert( pC->iDb>=0 ); @@ -82587,7 +92930,7 @@ case OP_ResetCount: { ** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 ** ** P1 is a sorter cursor. This instruction compares a prefix of the -** record blob in register P3 against a prefix of the entry that +** record blob in register P3 against a prefix of the entry that ** the sorter cursor currently points to. Only the first P4 fields ** of r[P3] and the sorter record are compared. ** @@ -82645,10 +92988,10 @@ case OP_SorterData: { /* Opcode: RowData P1 P2 P3 * * ** Synopsis: r[P2]=data ** -** Write into register P2 the complete row content for the row at +** Write into register P2 the complete row content for the row at ** which cursor P1 is currently pointing. -** There is no interpretation of the data. -** It is just copied onto the P2 register exactly as +** There is no interpretation of the data. +** It is just copied onto the P2 register exactly as ** it is found in the database file. ** ** If cursor P1 is an index, then the content is the key of the row. @@ -82657,10 +93000,10 @@ case OP_SorterData: { ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. ** -** If P3!=0 then this opcode is allowed to make an ephermeral pointer +** If P3!=0 then this opcode is allowed to make an ephemeral pointer ** into the database page. That means that the content of the output ** register will be invalidated as soon as the cursor moves - including -** moves caused by other cursors that "save" the the current cursors +** moves caused by other cursors that "save" the current cursors ** position in order that they can write to the same table. If P3==0 ** then a copy of the data is made into memory. P3!=0 is faster, but ** P3==0 is safer. @@ -82696,17 +93039,13 @@ case OP_RowData: { */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); -#if 0 /* Not required due to the previous to assert() statements */ - rc = sqlite3VdbeCursorMoveto(pC); - if( rc!=SQLITE_OK ) goto abort_due_to_error; -#endif n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); - rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pCrsr, n, pOut); if( rc ) goto abort_due_to_error; if( !pOp->p3 ) Deephemeralize(pOut); UPDATE_MAX_BLOBSIZE(pOut); @@ -82770,6 +93109,10 @@ case OP_Rowid: { /* out2 */ ** Move the cursor P1 to a null row. Any OP_Column operations ** that occur while the cursor is on the null row will always ** write a NULL. +** +** Or, if P1 is a Pseudo-Cursor (a cursor opened using OP_OpenPseudo) +** just reset the cache for that cursor. This causes the row of +** content held by the pseudo-cursor to be reparsed. */ case OP_NullRow: { VdbeCursor *pC; @@ -82783,12 +93126,25 @@ case OP_NullRow: { assert( pC->uc.pCursor!=0 ); sqlite3BtreeClearCursor(pC->uc.pCursor); } +#ifdef SQLITE_DEBUG + if( pC->seekOp==0 ) pC->seekOp = OP_NullRow; +#endif break; } -/* Opcode: Last P1 P2 P3 * * +/* Opcode: SeekEnd P1 * * * * +** +** Position cursor P1 at the end of the btree for the purpose of +** appending a new entry onto the btree. ** -** The next use of the Rowid or Column or Prev instruction for P1 +** It is assumed that the cursor is used only for appending and so +** if the cursor is valid, then the cursor must already be pointing +** at the end of the btree and so no changes are made to +** the cursor. +*/ +/* Opcode: Last P1 P2 * * * +** +** The next use of the Rowid or Column or Prev instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through @@ -82797,14 +93153,8 @@ case OP_NullRow: { ** This opcode leaves the cursor configured to move in reverse order, ** from the end toward the beginning. In other words, the cursor is ** configured to use Prev, not Next. -** -** If P3 is -1, then the cursor is positioned at the end of the btree -** for the purpose of appending a new entry onto the btree. In that -** case P2 must be 0. It is assumed that the cursor is used only for -** appending and so if the cursor is valid, then the cursor must already -** be pointing at the end of the btree and so no changes are made to -** the cursor. */ +case OP_SeekEnd: case OP_Last: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; @@ -82817,26 +93167,55 @@ case OP_Last: { /* jump */ pCrsr = pC->uc.pCursor; res = 0; assert( pCrsr!=0 ); - pC->seekResult = pOp->p3; #ifdef SQLITE_DEBUG - pC->seekOp = OP_Last; + pC->seekOp = pOp->opcode; #endif - if( pOp->p3==0 || !sqlite3BtreeCursorIsValidNN(pCrsr) ){ - rc = sqlite3BtreeLast(pCrsr, &res); - pC->nullRow = (u8)res; - pC->deferredMoveto = 0; - pC->cacheStatus = CACHE_STALE; - if( rc ) goto abort_due_to_error; - if( pOp->p2>0 ){ - VdbeBranchTaken(res!=0,2); - if( res ) goto jump_to_p2; - } - }else{ + if( pOp->opcode==OP_SeekEnd ){ assert( pOp->p2==0 ); + pC->seekResult = -1; + if( sqlite3BtreeCursorIsValidNN(pCrsr) ){ + break; + } + } + rc = sqlite3BtreeLast(pCrsr, &res); + pC->nullRow = (u8)res; + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; + if( rc ) goto abort_due_to_error; + if( pOp->p2>0 ){ + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; } break; } +/* Opcode: IfSmaller P1 P2 P3 * * +** +** Estimate the number of rows in the table P1. Jump to P2 if that +** estimate is less than approximately 2**(0.1*P3). +*/ +case OP_IfSmaller: { /* jump */ + VdbeCursor *pC; + BtCursor *pCrsr; + int res; + i64 sz; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + pCrsr = pC->uc.pCursor; + assert( pCrsr ); + rc = sqlite3BtreeFirst(pCrsr, &res); + if( rc ) goto abort_due_to_error; + if( res==0 ){ + sz = sqlite3BtreeRowCountEst(pCrsr); + if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)p3 ) res = 1; + } + VdbeBranchTaken(res!=0,2); + if( res ) goto jump_to_p2; + break; +} + /* Opcode: SorterSort P1 P2 * * * ** @@ -82867,13 +93246,14 @@ case OP_Sort: { /* jump */ #endif p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ + /* no break */ deliberate_fall_through } /* Opcode: Rewind P1 P2 * * * ** -** The next use of the Rowid or Column or Next instruction for P1 +** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. ** If the table or index is empty, jump immediately to P2. -** If the table or index is not empty, fall through to the following +** If the table or index is not empty, fall through to the following ** instruction. ** ** This opcode leaves the cursor configured to move in forward order, @@ -82886,6 +93266,7 @@ case OP_Rewind: { /* jump */ int res; assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( pOp->p5==0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); @@ -82936,12 +93317,7 @@ case OP_Rewind: { /* jump */ ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** -** See also: Prev, NextIfOpen -*/ -/* Opcode: NextIfOpen P1 P2 P3 P4 P5 -** -** This opcode works just like Next except that if cursor P1 is not -** open it behaves a no-op. +** See also: Prev */ /* Opcode: Prev P1 P2 P3 P4 P5 ** @@ -82969,11 +93345,6 @@ case OP_Rewind: { /* jump */ ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ -/* Opcode: PrevIfOpen P1 P2 P3 P4 P5 -** -** This opcode works just like Prev except that if cursor P1 is not -** open it behaves a no-op. -*/ /* Opcode: SorterNext P1 P2 * * P5 ** ** This opcode works just like OP_Next except that P1 must be a @@ -82983,57 +93354,49 @@ case OP_Rewind: { /* jump */ */ case OP_SorterNext: { /* jump */ VdbeCursor *pC; - int res; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); - res = 0; - rc = sqlite3VdbeSorterNext(db, pC, &res); + rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; -case OP_PrevIfOpen: /* jump */ -case OP_NextIfOpen: /* jump */ - if( p->apCsr[pOp->p1]==0 ) break; - /* Fall through */ case OP_Prev: /* jump */ case OP_Next: /* jump */ assert( pOp->p1>=0 && pOp->p1nCursor ); assert( pOp->p5aCounter) ); pC = p->apCsr[pOp->p1]; - res = pOp->p3; assert( pC!=0 ); assert( pC->deferredMoveto==0 ); assert( pC->eCurType==CURTYPE_BTREE ); - assert( res==0 || (res==1 && pC->isTable==0) ); - testcase( res==1 ); assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext ); assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious ); - assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext ); - assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious); - /* The Next opcode is only used after SeekGT, SeekGE, and Rewind. + /* The Next opcode is only used after SeekGT, SeekGE, Rewind, and Found. ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ - assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen + assert( pOp->opcode!=OP_Next || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE - || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found); - assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen + || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found + || pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid + || pC->seekOp==OP_IfNoHope); + assert( pOp->opcode!=OP_Prev || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE - || pC->seekOp==OP_Last ); + || pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope + || pC->seekOp==OP_NullRow); - rc = pOp->p4.xAdvance(pC->uc.pCursor, &res); + rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3); next_tail: pC->cacheStatus = CACHE_STALE; - VdbeBranchTaken(res==0,2); - if( rc ) goto abort_due_to_error; - if( res==0 ){ + VdbeBranchTaken(rc==SQLITE_OK,2); + if( rc==SQLITE_OK ){ pC->nullRow = 0; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif goto jump_to_p2_and_check_for_interrupt; - }else{ - pC->nullRow = 1; } + if( rc!=SQLITE_DONE ) goto abort_due_to_error; + rc = SQLITE_OK; + pC->nullRow = 1; goto check_for_interrupt; } @@ -83060,11 +93423,41 @@ case OP_Next: /* jump */ ** run faster by avoiding an unnecessary seek on cursor P1. However, ** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior ** seeks on the cursor or if the most recent seek used a key equivalent -** to P2. +** to P2. ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ +case OP_IdxInsert: { /* in2 */ + VdbeCursor *pC; + BtreePayload x; + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + sqlite3VdbeIncrWriteCounter(p, pC); + assert( pC!=0 ); + assert( !isSorter(pC) ); + pIn2 = &aMem[pOp->p2]; + assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) ); + if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->isTable==0 ); + rc = ExpandBlob(pIn2); + if( rc ) goto abort_due_to_error; + x.nKey = pIn2->n; + x.pKey = pIn2->z; + x.aMem = aMem + pOp->p3; + x.nMem = (u16)pOp->p4.i; + rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, + (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)), + ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) + ); + assert( pC->deferredMoveto==0 ); + pC->cacheStatus = CACHE_STALE; + if( rc) goto abort_due_to_error; + break; +} + /* Opcode: SorterInsert P1 P2 * * * ** Synopsis: key=r[P2] ** @@ -83072,46 +93465,38 @@ case OP_Next: /* jump */ ** MakeRecord instructions. This opcode writes that key ** into the sorter P1. Data for the entry is nil. */ -case OP_SorterInsert: /* in2 */ -case OP_IdxInsert: { /* in2 */ +case OP_SorterInsert: { /* in2 */ VdbeCursor *pC; - BtreePayload x; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; + sqlite3VdbeIncrWriteCounter(p, pC); assert( pC!=0 ); - assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) ); + assert( isSorter(pC) ); pIn2 = &aMem[pOp->p2]; assert( pIn2->flags & MEM_Blob ); - if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; - assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; - if( pOp->opcode==OP_SorterInsert ){ - rc = sqlite3VdbeSorterWrite(pC, pIn2); - }else{ - x.nKey = pIn2->n; - x.pKey = pIn2->z; - x.aMem = aMem + pOp->p3; - x.nMem = (u16)pOp->p4.i; - rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, - (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), - ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) - ); - assert( pC->deferredMoveto==0 ); - pC->cacheStatus = CACHE_STALE; - } + rc = sqlite3VdbeSorterWrite(pC, pIn2); if( rc) goto abort_due_to_error; break; } -/* Opcode: IdxDelete P1 P2 P3 * * +/* Opcode: IdxDelete P1 P2 P3 * P5 ** Synopsis: key=r[P2@P3] ** ** The content of P3 registers starting at register P2 form -** an unpacked index key. This opcode removes that entry from the +** an unpacked index key. This opcode removes that entry from the ** index opened by cursor P1. +** +** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error +** if no matching index entry is found. This happens when running +** an UPDATE or DELETE statement and the index entry to be updated +** or deleted is not found. For some uses of IdxDelete +** (example: the EXCEPT operator) it does not matter that no matching +** entry is found. For those cases, P5 is zero. Also, do not raise +** this (self-correcting and non-critical) error if in writable_schema mode. */ case OP_IdxDelete: { VdbeCursor *pC; @@ -83125,18 +93510,21 @@ case OP_IdxDelete: { pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3VdbeIncrWriteCounter(p, pC); pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); - assert( pOp->p5==0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; - rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res); + rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); if( rc ) goto abort_due_to_error; + }else if( pOp->p5 && !sqlite3WritableSchema(db) ){ + rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); + goto abort_due_to_error; } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; @@ -83144,8 +93532,8 @@ case OP_IdxDelete: { break; } -/* Opcode: Seek P1 * P3 P4 * -** Synopsis: Move P3 to P1.rowid +/* Opcode: DeferredSeek P1 * P3 P4 * +** Synopsis: Move P3 to P1.rowid if needed ** ** P1 is an open index cursor and P3 is a cursor on the corresponding ** table. This opcode does a deferred seek of the P3 table cursor @@ -83157,8 +93545,8 @@ case OP_IdxDelete: { ** ** P4 may be an array of integers (type P4_INTARRAY) containing ** one entry for each column in the P3 table. If array entry a(i) -** is non-zero, then reading column a(i)-1 from cursor P3 is -** equivalent to performing the deferred seek and then reading column i +** is non-zero, then reading column a(i)-1 from cursor P3 is +** equivalent to performing the deferred seek and then reading column i ** from P1. This information is stored in P3 and used to redirect ** reads against P3 over to P1, thus possibly avoiding the need to ** seek and read cursor P3. @@ -83172,11 +93560,11 @@ case OP_IdxDelete: { ** ** See also: Rowid, MakeRecord. */ -case OP_Seek: -case OP_IdxRowid: { /* out2 */ - VdbeCursor *pC; /* The P1 index cursor */ - VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */ - i64 rowid; /* Rowid that P1 current points to */ +case OP_DeferredSeek: +case OP_IdxRowid: { /* out2 */ + VdbeCursor *pC; /* The P1 index cursor */ + VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */ + i64 rowid; /* Rowid that P1 current points to */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; @@ -83202,7 +93590,7 @@ case OP_IdxRowid: { /* out2 */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - if( pOp->opcode==OP_Seek ){ + if( pOp->opcode==OP_DeferredSeek ){ assert( pOp->p3>=0 && pOp->p3nCursor ); pTabCur = p->apCsr[pOp->p3]; assert( pTabCur!=0 ); @@ -83213,7 +93601,9 @@ case OP_IdxRowid: { /* out2 */ pTabCur->movetoTarget = rowid; pTabCur->deferredMoveto = 1; assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); - pTabCur->aAltMap = pOp->p4.ai; + assert( !pTabCur->isEphemeral ); + pTabCur->ub.aAltMap = pOp->p4.ai; + assert( !pC->isEphemeral ); pTabCur->pAltCursor = pC; }else{ pOut = out2Prerelease(p, pOp); @@ -83226,32 +93616,50 @@ case OP_IdxRowid: { /* out2 */ break; } -/* Opcode: IdxGE P1 P2 P3 P4 P5 +/* Opcode: FinishSeek P1 * * * * +** +** If cursor P1 was previously moved via OP_DeferredSeek, complete that +** seek operation now, without further delay. If the cursor seek has +** already occurred, this instruction is a no-op. +*/ +case OP_FinishSeek: { + VdbeCursor *pC; /* The P1 index cursor */ + + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + if( pC->deferredMoveto ){ + rc = sqlite3VdbeFinishMoveto(pC); + if( rc ) goto abort_due_to_error; + } + break; +} + +/* Opcode: IdxGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** The P4 register values beginning with P3 form an unpacked index -** key that omits the PRIMARY KEY. Compare this key value against the index -** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID +** The P4 register values beginning with P3 form an unpacked index +** key that omits the PRIMARY KEY. Compare this key value against the index +** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID ** fields at the end. ** ** If the P1 index entry is greater than or equal to the key value ** then jump to P2. Otherwise fall through to the next instruction. */ -/* Opcode: IdxGT P1 P2 P3 P4 P5 +/* Opcode: IdxGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** The P4 register values beginning with P3 form an unpacked index -** key that omits the PRIMARY KEY. Compare this key value against the index -** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID +** The P4 register values beginning with P3 form an unpacked index +** key that omits the PRIMARY KEY. Compare this key value against the index +** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID ** fields at the end. ** ** If the P1 index entry is greater than the key value ** then jump to P2. Otherwise fall through to the next instruction. */ -/* Opcode: IdxLT P1 P2 P3 P4 P5 +/* Opcode: IdxLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** The P4 register values beginning with P3 form an unpacked index +** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY or ROWID. Compare this key value against ** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ** ROWID on the P1 index. @@ -83259,10 +93667,10 @@ case OP_IdxRowid: { /* out2 */ ** If the P1 index entry is less than the key value then jump to P2. ** Otherwise fall through to the next instruction. */ -/* Opcode: IdxLE P1 P2 P3 P4 P5 +/* Opcode: IdxLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** -** The P4 register values beginning with P3 form an unpacked index +** The P4 register values beginning with P3 form an unpacked index ** key that omits the PRIMARY KEY or ROWID. Compare this key value against ** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or ** ROWID on the P1 index. @@ -83285,7 +93693,6 @@ case OP_IdxGE: { /* jump */ assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0); assert( pC->deferredMoveto==0 ); - assert( pOp->p5==0 || pOp->p5==1 ); assert( pOp->p4type==P4_INT32 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; @@ -83298,10 +93705,39 @@ case OP_IdxGE: { /* jump */ } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG - { int i; for(i=0; ip3+i, &aMem[pOp->p3+i]); + } + } #endif - res = 0; /* Not needed. Only used to silence a warning. */ - rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res); + + /* Inlined version of sqlite3VdbeIdxKeyCompare() */ + { + i64 nCellKey = 0; + BtCursor *pCur; + Mem m; + + assert( pC->eCurType==CURTYPE_BTREE ); + pCur = pC->uc.pCursor; + assert( sqlite3BtreeCursorIsValid(pCur) ); + nCellKey = sqlite3BtreePayloadSize(pCur); + /* nCellKey will always be between 0 and 0xffffffff because of the way + ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ + if( nCellKey<=0 || nCellKey>0x7fffffff ){ + rc = SQLITE_CORRUPT_BKPT; + goto abort_due_to_error; + } + sqlite3VdbeMemInit(&m, db, 0); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); + if( rc ) goto abort_due_to_error; + res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, &r, 0); + sqlite3VdbeMemRelease(&m); + } + /* End of inlined sqlite3VdbeIdxKeyCompare() */ + assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) ); if( (pOp->opcode&1)==(OP_IdxLT&1) ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); @@ -83311,7 +93747,7 @@ case OP_IdxGE: { /* jump */ res++; } VdbeBranchTaken(res>0,2); - if( rc ) goto abort_due_to_error; + assert( rc==SQLITE_OK ); if( res>0 ) goto jump_to_p2; break; } @@ -83329,10 +93765,17 @@ case OP_IdxGE: { /* jump */ ** might be moved into the newly deleted root page in order to keep all ** root pages contiguous at the beginning of the database. The former ** value of the root page that moved - its value before the move occurred - -** is stored in register P2. If no page -** movement was required (because the table being dropped was already -** the last one in the database) then a zero is stored in register P2. -** If AUTOVACUUM is disabled then a zero is stored in register P2. +** is stored in register P2. If no page movement was required (because the +** table being dropped was already the last one in the database) then a +** zero is stored in register P2. If AUTOVACUUM is disabled then a zero +** is stored in register P2. +** +** This opcode throws an error if there are any active reader VMs when +** it is invoked. This is done to avoid the difficulty associated with +** updating existing cursors when a root page is moved in an AUTOVACUUM +** database. This error is thrown even if the database is not an AUTOVACUUM +** db in order to avoid introducing an incompatibility between autovacuum +** and non-autovacuum modes. ** ** See also: Clear */ @@ -83340,6 +93783,7 @@ case OP_Destroy: { /* out2 */ int iMoved; int iDb; + sqlite3VdbeIncrWriteCounter(p, 0); assert( p->readOnly==0 ); assert( pOp->p1>1 ); pOut = out2Prerelease(p, pOp); @@ -83378,23 +93822,21 @@ case OP_Destroy: { /* out2 */ ** P2==1 then the table to be clear is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** -** If the P3 value is non-zero, then the table referred to must be an -** intkey table (an SQL table, not an index). In this case the row change -** count is incremented by the number of rows in the table being cleared. -** If P3 is greater than zero, then the value stored in register P3 is -** also incremented by the number of rows in the table being cleared. +** If the P3 value is non-zero, then the row change count is incremented +** by the number of rows in the table being cleared. If P3 is greater +** than zero, then the value stored in register P3 is also incremented +** by the number of rows in the table being cleared. ** ** See also: Destroy */ case OP_Clear: { - int nChange; - + i64 nChange; + + sqlite3VdbeIncrWriteCounter(p, 0); nChange = 0; assert( p->readOnly==0 ); assert( DbMaskTest(p->btreeMask, pOp->p2) ); - rc = sqlite3BtreeClearTable( - db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) - ); + rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, (u32)pOp->p1, &nChange); if( pOp->p3 ){ p->nChange += nChange; if( pOp->p3>0 ){ @@ -83417,7 +93859,7 @@ case OP_Clear: { */ case OP_ResetSorter: { VdbeCursor *pC; - + assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -83432,71 +93874,64 @@ case OP_ResetSorter: { break; } -/* Opcode: CreateTable P1 P2 * * * -** Synopsis: r[P2]=root iDb=P1 -** -** Allocate a new table in the main database file if P1==0 or in the -** auxiliary database file if P1==1 or in an attached database if -** P1>1. Write the root page number of the new table into -** register P2 -** -** The difference between a table and an index is this: A table must -** have a 4-byte integer key and can have arbitrary data. An index -** has an arbitrary key but no data. +/* Opcode: CreateBtree P1 P2 P3 * * +** Synopsis: r[P2]=root iDb=P1 flags=P3 ** -** See also: CreateIndex +** Allocate a new b-tree in the main database file if P1==0 or in the +** TEMP database file if P1==1 or in an attached database if +** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table +** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table. +** The root page number of the new b-tree is stored in register P2. */ -/* Opcode: CreateIndex P1 P2 * * * -** Synopsis: r[P2]=root iDb=P1 -** -** Allocate a new index in the main database file if P1==0 or in the -** auxiliary database file if P1==1 or in an attached database if -** P1>1. Write the root page number of the new table into -** register P2. -** -** See documentation on OP_CreateTable for additional information. -*/ -case OP_CreateIndex: /* out2 */ -case OP_CreateTable: { /* out2 */ - int pgno; - int flags; +case OP_CreateBtree: { /* out2 */ + Pgno pgno; Db *pDb; + sqlite3VdbeIncrWriteCounter(p, 0); pOut = out2Prerelease(p, pOp); pgno = 0; + assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); - if( pOp->opcode==OP_CreateTable ){ - /* flags = BTREE_INTKEY; */ - flags = BTREE_INTKEY; - }else{ - flags = BTREE_BLOBKEY; - } - rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags); + rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3); if( rc ) goto abort_due_to_error; pOut->u.i = pgno; break; } +/* Opcode: SqlExec * * * P4 * +** +** Run the SQL statement or statements specified in the P4 string. +*/ +case OP_SqlExec: { + sqlite3VdbeIncrWriteCounter(p, 0); + db->nSqlExec++; + rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0); + db->nSqlExec--; + if( rc ) goto abort_due_to_error; + break; +} + /* Opcode: ParseSchema P1 * * P4 * ** -** Read and parse all entries from the SQLITE_MASTER table of database P1 -** that match the WHERE clause P4. +** Read and parse all entries from the schema table of database P1 +** that match the WHERE clause P4. If P4 is a NULL pointer, then the +** entire schema for P1 is reparsed. ** ** This opcode invokes the parser to create a new virtual machine, ** then runs the new virtual machine. It is thus a re-entrant opcode. */ case OP_ParseSchema: { int iDb; - const char *zMaster; + const char *zSchema; char *zSql; InitData initData; /* Any prepared statement that invokes this opcode will hold mutexes - ** on every btree. This is a prerequisite for invoking + ** on every btree. This is a prerequisite for invoking ** sqlite3InitCallback(). */ #ifdef SQLITE_DEBUG @@ -83507,25 +93942,46 @@ case OP_ParseSchema: { iDb = pOp->p1; assert( iDb>=0 && iDbnDb ); - assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); - /* Used to be a conditional */ { - zMaster = MASTER_NAME; + assert( DbHasProperty(db, iDb, DB_SchemaLoaded) + || db->mallocFailed + || (CORRUPT_DB && (db->flags & SQLITE_NoSchemaError)!=0) ); + +#ifndef SQLITE_OMIT_ALTERTABLE + if( pOp->p4.z==0 ){ + sqlite3SchemaClear(db->aDb[iDb].pSchema); + db->mDbFlags &= ~DBFLAG_SchemaKnownOk; + rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5); + db->mDbFlags |= DBFLAG_SchemaChange; + p->expired = 0; + }else +#endif + { + zSchema = LEGACY_SCHEMA_TABLE; initData.db = db; - initData.iDb = pOp->p1; + initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; + initData.mInitFlags = 0; + initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt); zSql = sqlite3MPrintf(db, - "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", - db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); + "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid", + db->aDb[iDb].zDbSName, zSchema, pOp->p4.z); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); db->init.busy = 1; initData.rc = SQLITE_OK; + initData.nInitRow = 0; assert( !db->mallocFailed ); rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0); if( rc==SQLITE_OK ) rc = initData.rc; - sqlite3DbFree(db, zSql); + if( rc==SQLITE_OK && initData.nInitRow==0 ){ + /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse + ** at least one SQL statement. Any less than that indicates that + ** the sqlite_schema table is corrupt. */ + rc = SQLITE_CORRUPT_BKPT; + } + sqlite3DbFreeNN(db, zSql); db->init.busy = 0; } } @@ -83536,7 +93992,7 @@ case OP_ParseSchema: { } goto abort_due_to_error; } - break; + break; } #if !defined(SQLITE_OMIT_ANALYZE) @@ -83550,7 +94006,7 @@ case OP_LoadAnalysis: { assert( pOp->p1>=0 && pOp->p1nDb ); rc = sqlite3AnalysisLoad(db, pOp->p1); if( rc ) goto abort_due_to_error; - break; + break; } #endif /* !defined(SQLITE_OMIT_ANALYZE) */ @@ -83558,11 +94014,12 @@ case OP_LoadAnalysis: { ** ** Remove the internal (in-memory) data structures that describe ** the table named P4 in database P1. This is called after a table -** is dropped from disk (using the Destroy opcode) in order to keep +** is dropped from disk (using the Destroy opcode) in order to keep ** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTable: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z); break; } @@ -83576,6 +94033,7 @@ case OP_DropTable: { ** schema consistent with what is on disk. */ case OP_DropIndex: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z); break; } @@ -83584,11 +94042,12 @@ case OP_DropIndex: { ** ** Remove the internal (in-memory) data structures that describe ** the trigger named P4 in database P1. This is called after a trigger -** is dropped from disk (using the Destroy opcode) in order to keep +** is dropped from disk (using the Destroy opcode) in order to keep ** the internal representation of the ** schema consistent with what is on disk. */ case OP_DropTrigger: { + sqlite3VdbeIncrWriteCounter(p, 0); sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z); break; } @@ -83601,9 +94060,9 @@ case OP_DropTrigger: { ** register P1 the text of an error message describing any problems. ** If no problems are found, store a NULL in register P1. ** -** The register P3 contains the maximum number of allowed errors. +** The register P3 contains one less than the maximum number of allowed errors. ** At most reg(P3) errors will be reported. -** In other words, the analysis stops as soon as reg(P1) errors are +** In other words, the analysis stops as soon as reg(P1) errors are ** seen. Reg(P1) is updated with the number of errors remaining. ** ** The root page numbers of all tables in the database are integers @@ -83616,7 +94075,7 @@ case OP_DropTrigger: { */ case OP_IntegrityCk: { int nRoot; /* Number of tables to check. (Number of root pages.) */ - int *aRoot; /* Array of rootpage numbers for tables to be checked */ + Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */ int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ @@ -83625,7 +94084,7 @@ case OP_IntegrityCk: { nRoot = pOp->p2; aRoot = pOp->p4.ai; assert( nRoot>0 ); - assert( aRoot[nRoot]==0 ); + assert( aRoot[0]==(Pgno)nRoot ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pnErr = &aMem[pOp->p3]; assert( (pnErr->flags & MEM_Int)!=0 ); @@ -83633,27 +94092,27 @@ case OP_IntegrityCk: { pIn1 = &aMem[pOp->p1]; assert( pOp->p5nDb ); assert( DbMaskTest(p->btreeMask, pOp->p5) ); - z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot, - (int)pnErr->u.i, &nErr); - pnErr->u.i -= nErr; + z = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot, + (int)pnErr->u.i+1, &nErr); sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); }else if( z==0 ){ goto no_mem; }else{ + pnErr->u.i -= nErr-1; sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); } UPDATE_MAX_BLOBSIZE(pIn1); sqlite3VdbeChangeEncoding(pIn1, encoding); - break; + goto check_for_interrupt; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* Opcode: RowSetAdd P1 P2 * * * ** Synopsis: rowset(P1)=r[P2] ** -** Insert the integer value held by register P2 into a boolean index +** Insert the integer value held by register P2 into a RowSet object ** held in register P1. ** ** An assertion fails if P2 is not an integer. @@ -83662,27 +94121,29 @@ case OP_RowSetAdd: { /* in1, in2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Int)!=0 ); - if( (pIn1->flags & MEM_RowSet)==0 ){ - sqlite3VdbeMemSetRowSet(pIn1); - if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + if( (pIn1->flags & MEM_Blob)==0 ){ + if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } - sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i); + assert( sqlite3VdbeMemIsRowSet(pIn1) ); + sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i); break; } /* Opcode: RowSetRead P1 P2 P3 * * ** Synopsis: r[P3]=rowset(P1) ** -** Extract the smallest value from boolean index P1 and put that value into -** register P3. Or, if boolean index P1 is initially empty, leave P3 +** Extract the smallest value from the RowSet object in P1 +** and put that value into register P3. +** Or, if RowSet object P1 is initially empty, leave P3 ** unchanged and jump to instruction P2. */ case OP_RowSetRead: { /* jump, in1, out3 */ i64 val; pIn1 = &aMem[pOp->p1]; - if( (pIn1->flags & MEM_RowSet)==0 - || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 + assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) ); + if( (pIn1->flags & MEM_Blob)==0 + || sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); @@ -83705,15 +94166,14 @@ case OP_RowSetRead: { /* jump, in1, out3 */ ** integer in P3 into the RowSet and continue on to the ** next opcode. ** -** The RowSet object is optimized for the case where successive sets -** of integers, where each set contains no duplicates. Each set -** of values is identified by a unique P4 value. The first set -** must have P4==0, the final set P4=-1. P4 must be either -1 or -** non-negative. For non-negative values of P4 only the lower 4 -** bits are significant. +** The RowSet object is optimized for the case where sets of integers +** are inserted in distinct phases, which each set contains no duplicates. +** Each set is identified by a unique P4 value. The first set +** must have P4==0, the final set must have P4==-1, and for all other sets +** must have P4>0. ** ** This allows optimizations: (a) when P4==0 there is no need to test -** the rowset object for P3, as it is guaranteed not to contain it, +** the RowSet object for P3, as it is guaranteed not to contain it, ** (b) when P4==-1 there is no need to insert the value, as it will ** never be tested for, and (c) when a value that is part of set X is ** inserted, there is no need to search to see if the same value was @@ -83732,20 +94192,19 @@ case OP_RowSetTest: { /* jump, in1, in3 */ /* If there is anything other than a rowset object in memory cell P1, ** delete it now and initialize P1 with an empty rowset */ - if( (pIn1->flags & MEM_RowSet)==0 ){ - sqlite3VdbeMemSetRowSet(pIn1); - if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + if( (pIn1->flags & MEM_Blob)==0 ){ + if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } - + assert( sqlite3VdbeMemIsRowSet(pIn1) ); assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ - exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); + exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); if( exists ) goto jump_to_p2; } if( iSet>=0 ){ - sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); + sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i); } break; } @@ -83755,13 +94214,13 @@ case OP_RowSetTest: { /* jump, in1, in3 */ /* Opcode: Program P1 P2 P3 P4 P5 ** -** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). +** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). ** -** P1 contains the address of the memory cell that contains the first memory -** cell in an array of values used as arguments to the sub-program. P2 -** contains the address to jump to if the sub-program throws an IGNORE -** exception using the RAISE() function. Register P3 contains the address -** of a memory cell in this (the parent) VM that is used to allocate the +** P1 contains the address of the memory cell that contains the first memory +** cell in an array of values used as arguments to the sub-program. P2 +** contains the address to jump to if the sub-program throws an IGNORE +** exception using the RAISE() function. Register P3 contains the address +** of a memory cell in this (the parent) VM that is used to allocate the ** memory required by the sub-vdbe at runtime. ** ** P4 is a pointer to the VM containing the trigger program. @@ -83781,17 +94240,17 @@ case OP_Program: { /* jump */ pProgram = pOp->p4.pProgram; pRt = &aMem[pOp->p3]; assert( pProgram->nOp>0 ); - - /* If the p5 flag is clear, then recursive invocation of triggers is + + /* If the p5 flag is clear, then recursive invocation of triggers is ** disabled for backwards compatibility (p5 is set if this sub-program ** is really a trigger, not a foreign key action, and the flag set ** and cleared by the "PRAGMA recursive_triggers" command is clear). - ** - ** It is recursive invocation of triggers, at the SQL level, that is - ** disabled. In some cases a single trigger may generate more than one - ** SubProgram (if the trigger may be executed with more than one different + ** + ** It is recursive invocation of triggers, at the SQL level, that is + ** disabled. In some cases a single trigger may generate more than one + ** SubProgram (if the trigger may be executed with more than one different ** ON CONFLICT algorithm). SubProgram structures associated with a - ** single trigger all have the same value for the SubProgram.token + ** single trigger all have the same value for the SubProgram.token ** variable. */ if( pOp->p5 ){ t = pProgram->token; @@ -83807,10 +94266,10 @@ case OP_Program: { /* jump */ /* Register pRt is used to store the memory required to save the state ** of the current program, and the memory required at runtime to execute - ** the trigger program. If this trigger has been fired before, then pRt + ** the trigger program. If this trigger has been fired before, then pRt ** is already allocated. Otherwise, it must be initialized. */ - if( (pRt->flags&MEM_Frame)==0 ){ - /* SubProgram.nMem is set to the number of memory cells used by the + if( (pRt->flags&MEM_Blob)==0 ){ + /* SubProgram.nMem is set to the number of memory cells used by the ** program stored in SubProgram.aOp. As well as these, one memory ** cell is required for each cursor used by the program. Set local ** variable nMem (and later, VdbeFrame.nChildMem) to this value. @@ -83820,14 +94279,17 @@ case OP_Program: { /* jump */ if( pProgram->nCsr==0 ) nMem++; nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) - + pProgram->nCsr * sizeof(VdbeCursor *); + + pProgram->nCsr * sizeof(VdbeCursor*) + + (pProgram->nOp + 7)/8; pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; } sqlite3VdbeMemRelease(pRt); - pRt->flags = MEM_Frame; - pRt->u.pFrame = pFrame; + pRt->flags = MEM_Blob|MEM_Dyn; + pRt->z = (char*)pFrame; + pRt->n = nByte; + pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; pFrame->nChildMem = nMem; @@ -83843,6 +94305,9 @@ case OP_Program: { /* jump */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pFrame->anExec = p->anExec; #endif +#ifdef SQLITE_DEBUG + pFrame->iFrameMagic = SQLITE_FRAME_MAGIC; +#endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ @@ -83850,8 +94315,9 @@ case OP_Program: { /* jump */ pMem->db = db; } }else{ - pFrame = pRt->u.pFrame; - assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem + pFrame = (VdbeFrame*)pRt->z; + assert( pRt->xDel==sqlite3VdbeFrameMemDel ); + assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) ); assert( pProgram->nCsr==pFrame->nChildCsr ); assert( (int)(pOp - aOp)==pFrame->pc ); @@ -83871,22 +94337,34 @@ case OP_Program: { /* jump */ p->nMem = pFrame->nChildMem; p->nCursor = (u16)pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&aMem[p->nMem]; + pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr]; + memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8); p->aOp = aOp = pProgram->aOp; p->nOp = pProgram->nOp; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = 0; +#endif +#ifdef SQLITE_DEBUG + /* Verify that second and subsequent executions of the same trigger do not + ** try to reuse register values from the first use. */ + { + int i; + for(i=0; inMem; i++){ + aMem[i].pScopyFrom = 0; /* Prevent false-positive AboutToChange() errs */ + MemSetTypeFlag(&aMem[i], MEM_Undefined); /* Fault if this reg is reused */ + } + } #endif pOp = &aOp[-1]; - - break; + goto check_for_interrupt; } /* Opcode: Param P1 P2 * * * ** -** This opcode is only ever present in sub-programs called via the -** OP_Program instruction. Copy a value currently stored in a memory -** cell of the calling (parent) frame to cell P2 in the current frames -** address space. This is used by trigger programs to access the new.* +** This opcode is only ever present in sub-programs called via the +** OP_Program instruction. Copy a value currently stored in a memory +** cell of the calling (parent) frame to cell P2 in the current frames +** address space. This is used by trigger programs to access the new.* ** and old.* values. ** ** The address of the cell in the parent frame is determined by adding @@ -83898,7 +94376,7 @@ case OP_Param: { /* out2 */ Mem *pIn; pOut = out2Prerelease(p, pOp); pFrame = p->pFrame; - pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; + pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem); break; } @@ -83910,8 +94388,8 @@ case OP_Param: { /* out2 */ ** Synopsis: fkctr[P1]+=P2 ** ** Increment a "constraint counter" by P2 (P2 may be negative or positive). -** If P1 is non-zero, the database constraint counter is incremented -** (deferred foreign key constraints). Otherwise, if P1 is zero, the +** If P1 is non-zero, the database constraint counter is incremented +** (deferred foreign key constraints). Otherwise, if P1 is zero, the ** statement counter is incremented (immediate foreign key constraints). */ case OP_FkCounter: { @@ -83929,7 +94407,7 @@ case OP_FkCounter: { ** Synopsis: if fkctr[P1]==0 goto P2 ** ** This opcode tests if a foreign key constraint-counter is currently zero. -** If so, jump to instruction P2. Otherwise, fall through to the next +** If so, jump to instruction P2. Otherwise, fall through to the next ** instruction. ** ** If P1 is non-zero, then the jump is taken if the database constraint-counter @@ -83955,7 +94433,7 @@ case OP_FkIfZero: { /* jump */ ** ** P1 is a register in the root frame of this VM (the root frame is ** different from the current frame if this instruction is being executed -** within a sub-program). Set the value of register P1 to the maximum of +** within a sub-program). Set the value of register P1 to the maximum of ** its current value and the value in register P2. ** ** This instruction throws an error if the memory cell is not initially @@ -84015,7 +94493,7 @@ case OP_IfPos: { /* jump, in1 */ ** and r[P2] is set to be the value of the LIMIT, r[P1]. ** ** if r[P1] is zero or negative, that means there is no LIMIT -** and r[P2] is set to -1. +** and r[P2] is set to -1. ** ** Otherwise, r[P2] is set to the sum of r[P1] and r[P3]. */ @@ -84047,7 +94525,7 @@ case OP_OffsetLimit: { /* in1, out2, in3 */ ** ** Register P1 must contain an integer. If the content of register P1 is ** initially greater than zero, then decrement the value in register P1. -** If it is non-zero (negative or positive) and then also jump to P2. +** If it is non-zero (negative or positive) and then also jump to P2. ** If register P1 is initially zero, leave it unchanged and fall through. */ case OP_IfNotZero: { /* jump, in1 */ @@ -84077,24 +94555,35 @@ case OP_DecrJumpZero: { /* jump, in1 */ } -/* Opcode: AggStep0 * P2 P3 P4 P5 +/* Opcode: AggStep * P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** -** Execute the step function for an aggregate. The -** function has P5 arguments. P4 is a pointer to the FuncDef -** structure that specifies the function. Register P3 is the +** Execute the xStep function for an aggregate. +** The function has P5 arguments. P4 is a pointer to the +** FuncDef structure that specifies the function. Register P3 is the ** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. */ -/* Opcode: AggStep * P2 P3 P4 P5 +/* Opcode: AggInverse * P2 P3 P4 P5 +** Synopsis: accum=r[P3] inverse(r[P2@P5]) +** +** Execute the xInverse function for an aggregate. +** The function has P5 arguments. P4 is a pointer to the +** FuncDef structure that specifies the function. Register P3 is the +** accumulator. +** +** The P5 arguments are taken from register P2 and its +** successors. +*/ +/* Opcode: AggStep1 P1 P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** -** Execute the step function for an aggregate. The -** function has P5 arguments. P4 is a pointer to an sqlite3_context -** object that is used to run the function. Register P3 is -** as the accumulator. +** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an +** aggregate. The function has P5 arguments. P4 is a pointer to the +** FuncDef structure that specifies the function. Register P3 is the +** accumulator. ** ** The P5 arguments are taken from register P2 and its ** successors. @@ -84105,7 +94594,8 @@ case OP_DecrJumpZero: { /* jump, in1 */ ** sqlite3_context only happens once, instead of on each call to the ** step function. */ -case OP_AggStep0: { +case OP_AggInverse: +case OP_AggStep: { int n; sqlite3_context *pCtx; @@ -84114,28 +94604,48 @@ case OP_AggStep0: { assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); - pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); + pCtx = sqlite3DbMallocRawNN(db, n*sizeof(sqlite3_value*) + + (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(sqlite3_value*))); if( pCtx==0 ) goto no_mem; pCtx->pMem = 0; + pCtx->pOut = (Mem*)&(pCtx->argv[n]); + sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); pCtx->pFunc = pOp->p4.pFunc; pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; + pCtx->skipFlag = 0; + pCtx->isError = 0; pCtx->argc = n; pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; - pOp->opcode = OP_AggStep; + + /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */ + assert( pOp->p1==(pOp->opcode==OP_AggInverse) ); + + pOp->opcode = OP_AggStep1; /* Fall through into OP_AggStep */ + /* no break */ deliberate_fall_through } -case OP_AggStep: { +case OP_AggStep1: { int i; sqlite3_context *pCtx; Mem *pMem; - Mem t; assert( pOp->p4type==P4_FUNCCTX ); pCtx = pOp->p4.pCtx; pMem = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + if( pOp->p1 ){ + /* This is an OP_AggInverse call. Verify that xStep has always + ** been called at least once prior to any xInverse call. */ + assert( pMem->uTemp==0x1122e0e3 ); + }else{ + /* This is an OP_AggStep call. Mark it as such. */ + pMem->uTemp = 0x1122e0e3; + } +#endif + /* If this function is inside of a trigger, the register array in aMem[] ** might change from one evaluation to the next. The next block of code ** checks to see if the register array has changed, and if so it @@ -84153,48 +94663,81 @@ case OP_AggStep: { #endif pMem->n++; - sqlite3VdbeMemInit(&t, db, MEM_Null); - pCtx->pOut = &t; - pCtx->fErrorOrAux = 0; - pCtx->skipFlag = 0; + assert( pCtx->pOut->flags==MEM_Null ); + assert( pCtx->isError==0 ); + assert( pCtx->skipFlag==0 ); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pOp->p1 ){ + (pCtx->pFunc->xInverse)(pCtx,pCtx->argc,pCtx->argv); + }else +#endif (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */ - if( pCtx->fErrorOrAux ){ - if( pCtx->isError ){ - sqlite3VdbeError(p, "%s", sqlite3_value_text(&t)); + + if( pCtx->isError ){ + if( pCtx->isError>0 ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut)); rc = pCtx->isError; } - sqlite3VdbeMemRelease(&t); + if( pCtx->skipFlag ){ + assert( pOp[-1].opcode==OP_CollSeq ); + i = pOp[-1].p1; + if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); + pCtx->skipFlag = 0; + } + sqlite3VdbeMemRelease(pCtx->pOut); + pCtx->pOut->flags = MEM_Null; + pCtx->isError = 0; if( rc ) goto abort_due_to_error; - }else{ - assert( t.flags==MEM_Null ); - } - if( pCtx->skipFlag ){ - assert( pOp[-1].opcode==OP_CollSeq ); - i = pOp[-1].p1; - if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1); } + assert( pCtx->pOut->flags==MEM_Null ); + assert( pCtx->skipFlag==0 ); break; } /* Opcode: AggFinal P1 P2 * P4 * ** Synopsis: accum=r[P1] N=P2 ** -** Execute the finalizer function for an aggregate. P1 is -** the memory location that is the accumulator for the aggregate. +** P1 is the memory location that is the accumulator for an aggregate +** or window function. Execute the finalizer function +** for an aggregate and store the result in P1. +** +** P2 is the number of arguments that the step function takes and +** P4 is a pointer to the FuncDef for this function. The P2 +** argument is not used by this opcode. It is only there to disambiguate +** functions that can take varying numbers of arguments. The +** P4 argument is only needed for the case where +** the step function was not previously called. +*/ +/* Opcode: AggValue * P2 P3 P4 * +** Synopsis: r[P3]=value N=P2 +** +** Invoke the xValue() function and store the result in register P3. ** ** P2 is the number of arguments that the step function takes and ** P4 is a pointer to the FuncDef for this function. The P2 ** argument is not used by this opcode. It is only there to disambiguate ** functions that can take varying numbers of arguments. The -** P4 argument is only needed for the degenerate case where +** P4 argument is only needed for the case where ** the step function was not previously called. */ +case OP_AggValue: case OP_AggFinal: { Mem *pMem; assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + assert( pOp->p3==0 || pOp->opcode==OP_AggValue ); pMem = &aMem[pOp->p1]; assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); - rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pOp->p3 ){ + memAboutToChange(p, &aMem[pOp->p3]); + rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); + pMem = &aMem[pOp->p3]; + }else +#endif + { + rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc); + } + if( rc ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); goto abort_due_to_error; @@ -84240,9 +94783,9 @@ case OP_Checkpoint: { } for(i=0, pMem = &aMem[pOp->p3]; i<3; i++, pMem++){ sqlite3VdbeMemSetInt64(pMem, (i64)aRes[i]); - } + } break; -}; +}; #endif #ifndef SQLITE_OMIT_PRAGMA @@ -84268,9 +94811,9 @@ case OP_JournalMode: { /* out2 */ pOut = out2Prerelease(p, pOp); eNew = pOp->p3; - assert( eNew==PAGER_JOURNALMODE_DELETE - || eNew==PAGER_JOURNALMODE_TRUNCATE - || eNew==PAGER_JOURNALMODE_PERSIST + assert( eNew==PAGER_JOURNALMODE_DELETE + || eNew==PAGER_JOURNALMODE_TRUNCATE + || eNew==PAGER_JOURNALMODE_PERSIST || eNew==PAGER_JOURNALMODE_OFF || eNew==PAGER_JOURNALMODE_MEMORY || eNew==PAGER_JOURNALMODE_WAL @@ -84283,13 +94826,14 @@ case OP_JournalMode: { /* out2 */ pPager = sqlite3BtreePager(pBt); eOld = sqlite3PagerGetJournalMode(pPager); if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld; + assert( sqlite3BtreeHoldsMutex(pBt) ); if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld; #ifndef SQLITE_OMIT_WAL zFilename = sqlite3PagerFilename(pPager, 1); /* Do not allow a transition to journal_mode=WAL for a database - ** in temporary storage or if the VFS does not support shared memory + ** in temporary storage or if the VFS does not support shared memory */ if( eNew==PAGER_JOURNALMODE_WAL && (sqlite3Strlen30(zFilename)==0 /* Temp file */ @@ -84309,12 +94853,12 @@ case OP_JournalMode: { /* out2 */ ); goto abort_due_to_error; }else{ - + if( eOld==PAGER_JOURNALMODE_WAL ){ /* If leaving WAL mode, close the log file. If successful, the call - ** to PagerCloseWal() checkpoints and deletes the write-ahead-log - ** file. An EXCLUSIVE lock may still be held on the database file - ** after a successful return. + ** to PagerCloseWal() checkpoints and deletes the write-ahead-log + ** file. An EXCLUSIVE lock may still be held on the database file + ** after a successful return. */ rc = sqlite3PagerCloseWal(pPager, db); if( rc==SQLITE_OK ){ @@ -84325,11 +94869,11 @@ case OP_JournalMode: { /* out2 */ ** as an intermediate */ sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF); } - + /* Open a transaction on the database file. Regardless of the journal ** mode, this transaction always uses a rollback journal. */ - assert( sqlite3BtreeIsInTrans(pBt)==0 ); + assert( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ); if( rc==SQLITE_OK ){ rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); } @@ -84351,14 +94895,19 @@ case OP_JournalMode: { /* out2 */ #endif /* SQLITE_OMIT_PRAGMA */ #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) -/* Opcode: Vacuum P1 * * * * +/* Opcode: Vacuum P1 P2 * * * ** ** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more ** for an attached database. The "temp" database may not be vacuumed. +** +** If P2 is not zero, then it is a register holding a string which is +** the file into which the result of vacuum should be written. When +** P2 is zero, the vacuum overwrites the original database. */ case OP_Vacuum: { assert( p->readOnly==0 ); - rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1); + rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1, + pOp->p2 ? &aMem[pOp->p2] : 0); if( rc ) goto abort_due_to_error; break; } @@ -84389,31 +94938,68 @@ case OP_IncrVacuum: { /* jump */ } #endif -/* Opcode: Expire P1 * * * * +/* Opcode: Expire P1 P2 * * * ** ** Cause precompiled statements to expire. When an expired statement ** is executed using sqlite3_step() it will either automatically ** reprepare itself (if it was originally created using sqlite3_prepare_v2()) ** or it will fail with SQLITE_SCHEMA. -** +** ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, ** then only the currently executing statement is expired. +** +** If P2 is 0, then SQL statements are expired immediately. If P2 is 1, +** then running SQL statements are allowed to continue to run to completion. +** The P2==1 case occurs when a CREATE INDEX or similar schema change happens +** that might help the statement run faster but which does not affect the +** correctness of operation. */ case OP_Expire: { + assert( pOp->p2==0 || pOp->p2==1 ); if( !pOp->p1 ){ - sqlite3ExpirePreparedStatements(db); + sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ - p->expired = 1; + p->expired = pOp->p2+1; } break; } +/* Opcode: CursorLock P1 * * * * +** +** Lock the btree to which cursor P1 is pointing so that the btree cannot be +** written by an other cursor. +*/ +case OP_CursorLock: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3BtreeCursorPin(pC->uc.pCursor); + break; +} + +/* Opcode: CursorUnlock P1 * * * * +** +** Unlock the btree to which cursor P1 is pointing so that it can be +** written by other cursors. +*/ +case OP_CursorUnlock: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + sqlite3BtreeCursorUnpin(pC->uc.pCursor); + break; +} + #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** Synopsis: iDb=P1 root=P2 write=P3 ** ** Obtain a lock on a particular table. This instruction is only used when -** the shared-cache feature is enabled. +** the shared-cache feature is enabled. ** ** P1 is the index of the database in sqlite3.aDb[] of the database ** on which the lock is acquired. A readlock is obtained if P3==0 or @@ -84426,8 +95012,8 @@ case OP_Expire: { */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; - if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ - int p1 = pOp->p1; + if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){ + int p1 = pOp->p1; assert( p1>=0 && p1nDb ); assert( DbMaskTest(p->btreeMask, p1) ); assert( isWriteLock==0 || isWriteLock==1 ); @@ -84447,7 +95033,7 @@ case OP_TableLock: { #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VBegin * * * P4 * ** -** P4 may be a pointer to an sqlite3_vtab structure. If so, call the +** P4 may be a pointer to an sqlite3_vtab structure. If so, call the ** xBegin method for that table. ** ** Also, whether or not P4 is set, check that this is not being called from @@ -84467,7 +95053,7 @@ case OP_VBegin: { #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VCreate P1 P2 * * * ** -** P2 is a register that holds the name of a virtual table in database +** P2 is a register that holds the name of a virtual table in database ** P1. Call the xCreate method for that table. */ case OP_VCreate: { @@ -84503,6 +95089,7 @@ case OP_VDestroy: { db->nVDestroy++; rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z); db->nVDestroy--; + assert( p->errorAction==OE_Abort && p->usesStmtJournal ); if( rc ) goto abort_due_to_error; break; } @@ -84538,7 +95125,7 @@ case OP_VOpen: { pVCur->pVtab = pVtab; /* Initialize vdbe cursor object */ - pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB); + pCur = allocateCursor(p, pOp->p1, 0, CURTYPE_VTAB); if( pCur ){ pCur->uc.pVCur = pVCur; pVtab->nRef++; @@ -84551,6 +95138,34 @@ case OP_VOpen: { } #endif /* SQLITE_OMIT_VIRTUALTABLE */ +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Opcode: VInitIn P1 P2 P3 * * +** Synopsis: r[P2]=ValueList(P1,P3) +** +** Set register P2 to be a pointer to a ValueList object for cursor P1 +** with cache register P3 and output register P3+1. This ValueList object +** can be used as the first argument to sqlite3_vtab_in_first() and +** sqlite3_vtab_in_next() to extract all of the values stored in the P1 +** cursor. Register P3 is used to hold the values returned by +** sqlite3_vtab_in_first() and sqlite3_vtab_in_next(). +*/ +case OP_VInitIn: { /* out2 */ + VdbeCursor *pC; /* The cursor containing the RHS values */ + ValueList *pRhs; /* New ValueList object to put in reg[P2] */ + + pC = p->apCsr[pOp->p1]; + pRhs = sqlite3_malloc64( sizeof(*pRhs) ); + if( pRhs==0 ) goto no_mem; + pRhs->pCsr = pC->uc.pCursor; + pRhs->pOut = &aMem[pOp->p3]; + pOut = out2Prerelease(p, pOp); + pOut->flags = MEM_Null; + sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3_free); + break; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * ** Synopsis: iplan=r[P3] zplan='P4' @@ -84589,6 +95204,7 @@ case OP_VFilter: { /* jump */ pCur = p->apCsr[pOp->p1]; assert( memIsValid(pQuery) ); REGISTER_TRACE(pOp->p3, pQuery); + assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); pVCur = pCur->uc.pVCur; pVtab = pVCur->pVtab; @@ -84600,7 +95216,6 @@ case OP_VFilter: { /* jump */ iQuery = (int)pQuery->u.i; /* Invoke the xFilter method */ - res = 0; apArg = p->apArg; for(i = 0; iapCsr[pOp->p1]; + assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; @@ -84644,10 +95267,18 @@ case OP_VColumn: { assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; - MemSetTypeFlag(pDest, MEM_Null); + assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 ); + if( pOp->p5 & OPFLAG_NOCHNG ){ + sqlite3VdbeMemSetNull(pDest); + pDest->flags = MEM_Null|MEM_Zero; + pDest->u.nZero = 0; + }else{ + MemSetTypeFlag(pDest, MEM_Null); + } rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); - if( sContext.isError ){ + if( sContext.isError>0 ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(pDest)); rc = sContext.isError; } sqlite3VdbeChangeEncoding(pDest, encoding); @@ -84675,8 +95306,8 @@ case OP_VNext: { /* jump */ int res; VdbeCursor *pCur; - res = 0; pCur = p->apCsr[pOp->p1]; + assert( pCur!=0 ); assert( pCur->eCurType==CURTYPE_VTAB ); if( pCur->nullRow ){ break; @@ -84687,7 +95318,7 @@ case OP_VNext: { /* jump */ /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during - ** xNext(). Instead, if an error occurs, true is returned (indicating that + ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ @@ -84714,7 +95345,10 @@ case OP_VNext: { /* jump */ case OP_VRename: { sqlite3_vtab *pVtab; Mem *pName; + int isLegacy; + isLegacy = (db->flags & SQLITE_LegacyAlter); + db->flags |= SQLITE_LegacyAlter; pVtab = pOp->p4.pVtab->pVtab; pName = &aMem[pOp->p1]; assert( pVtab->pModule->xRename ); @@ -84728,6 +95362,7 @@ case OP_VRename: { rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); if( rc ) goto abort_due_to_error; rc = pVtab->pModule->xRename(pVtab, pName->z); + if( isLegacy==0 ) db->flags &= ~(u64)SQLITE_LegacyAlter; sqlite3VtabImportErrmsg(p, pVtab); p->expired = 0; if( rc ) goto abort_due_to_error; @@ -84741,23 +95376,23 @@ case OP_VRename: { ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** This opcode invokes the corresponding xUpdate method. P2 values -** are contiguous memory cells starting at P3 to pass to the xUpdate -** invocation. The value in register (P3+P2-1) corresponds to the +** are contiguous memory cells starting at P3 to pass to the xUpdate +** invocation. The value in register (P3+P2-1) corresponds to the ** p2th element of the argv array passed to xUpdate. ** ** The xUpdate method will do a DELETE or an INSERT or both. ** The argv[0] element (which corresponds to memory cell P3) -** is the rowid of a row to delete. If argv[0] is NULL then no -** deletion occurs. The argv[1] element is the rowid of the new -** row. This can be NULL to have the virtual table select the new -** rowid for itself. The subsequent elements in the array are +** is the rowid of a row to delete. If argv[0] is NULL then no +** deletion occurs. The argv[1] element is the rowid of the new +** row. This can be NULL to have the virtual table select the new +** rowid for itself. The subsequent elements in the array are ** the values of columns in the new row. ** ** If P2==1 then no insert is performed. argv[0] is the rowid of ** a row to delete. ** ** P1 is a boolean flag. If it is set to true and the xUpdate call -** is successful, then the value returned by sqlite3_last_insert_rowid() +** is successful, then the value returned by sqlite3_last_insert_rowid() ** is set to the value of the rowid for the row just inserted. ** ** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to @@ -84768,14 +95403,16 @@ case OP_VUpdate: { const sqlite3_module *pModule; int nArg; int i; - sqlite_int64 rowid; + sqlite_int64 rowid = 0; Mem **apArg; Mem *pX; - assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback + assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); assert( p->readOnly==0 ); + if( db->mallocFailed ) goto no_mem; + sqlite3VdbeIncrWriteCounter(p, 0); pVtab = pOp->p4.pVtab->pVtab; if( pVtab==0 || NEVER(pVtab->pModule==0) ){ rc = SQLITE_LOCKED; @@ -84855,8 +95492,184 @@ case OP_MaxPgcnt: { /* out2 */ } #endif +/* Opcode: Function P1 P2 P3 P4 * +** Synopsis: r[P3]=func(r[P2@NP]) +** +** Invoke a user function (P4 is a pointer to an sqlite3_context object that +** contains a pointer to the function to be run) with arguments taken +** from register P2 and successors. The number of arguments is in +** the sqlite3_context object that P4 points to. +** The result of the function is stored +** in register P3. Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** See also: AggStep, AggFinal, PureFunc +*/ +/* Opcode: PureFunc P1 P2 P3 P4 * +** Synopsis: r[P3]=func(r[P2@NP]) +** +** Invoke a user function (P4 is a pointer to an sqlite3_context object that +** contains a pointer to the function to be run) with arguments taken +** from register P2 and successors. The number of arguments is in +** the sqlite3_context object that P4 points to. +** The result of the function is stored +** in register P3. Register P3 must not be one of the function inputs. +** +** P1 is a 32-bit bitmask indicating whether or not each argument to the +** function was determined to be constant at compile time. If the first +** argument was constant then bit 0 of P1 is set. This is used to determine +** whether meta data associated with a user function argument using the +** sqlite3_set_auxdata() API may be safely retained until the next +** invocation of this opcode. +** +** This opcode works exactly like OP_Function. The only difference is in +** its name. This opcode is used in places where the function must be +** purely non-deterministic. Some built-in date/time functions can be +** either determinitic of non-deterministic, depending on their arguments. +** When those function are used in a non-deterministic way, they will check +** to see if they were called using OP_PureFunc instead of OP_Function, and +** if they were, they throw an error. +** +** See also: AggStep, AggFinal, Function +*/ +case OP_PureFunc: /* group */ +case OP_Function: { /* group */ + int i; + sqlite3_context *pCtx; + + assert( pOp->p4type==P4_FUNCCTX ); + pCtx = pOp->p4.pCtx; + + /* If this function is inside of a trigger, the register array in aMem[] + ** might change from one evaluation to the next. The next block of code + ** checks to see if the register array has changed, and if so it + ** reinitializes the relavant parts of the sqlite3_context object */ + pOut = &aMem[pOp->p3]; + if( pCtx->pOut != pOut ){ + pCtx->pVdbe = p; + pCtx->pOut = pOut; + for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; + } + assert( pCtx->pVdbe==p ); + + memAboutToChange(p, pOut); +#ifdef SQLITE_DEBUG + for(i=0; iargc; i++){ + assert( memIsValid(pCtx->argv[i]) ); + REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]); + } +#endif + MemSetTypeFlag(pOut, MEM_Null); + assert( pCtx->isError==0 ); + (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */ -/* Opcode: Init P1 P2 * P4 * + /* If the function returned an error, throw an exception */ + if( pCtx->isError ){ + if( pCtx->isError>0 ){ + sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut)); + rc = pCtx->isError; + } + sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); + pCtx->isError = 0; + if( rc ) goto abort_due_to_error; + } + + /* Copy the result of the function into register P3 */ + if( pOut->flags & (MEM_Str|MEM_Blob) ){ + sqlite3VdbeChangeEncoding(pOut, encoding); + if( sqlite3VdbeMemTooBig(pOut) ) goto too_big; + } + + REGISTER_TRACE(pOp->p3, pOut); + UPDATE_MAX_BLOBSIZE(pOut); + break; +} + +/* Opcode: FilterAdd P1 * P3 P4 * +** Synopsis: filter(P1) += key(P3@P4) +** +** Compute a hash on the P4 registers starting with r[P3] and +** add that hash to the bloom filter contained in r[P1]. +*/ +case OP_FilterAdd: { + u64 h; + + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + pIn1 = &aMem[pOp->p1]; + assert( pIn1->flags & MEM_Blob ); + assert( pIn1->n>0 ); + h = filterHash(aMem, pOp); +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + int ii; + for(ii=pOp->p3; iip3+pOp->p4.i; ii++){ + registerTrace(ii, &aMem[ii]); + } + printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n)); + } +#endif + h %= pIn1->n; + pIn1->z[h/8] |= 1<<(h&7); + break; +} + +/* Opcode: Filter P1 P2 P3 P4 * +** Synopsis: if key(P3@P4) not in filter(P1) goto P2 +** +** Compute a hash on the key contained in the P4 registers starting +** with r[P3]. Check to see if that hash is found in the +** bloom filter hosted by register P1. If it is not present then +** maybe jump to P2. Otherwise fall through. +** +** False negatives are harmless. It is always safe to fall through, +** even if the value is in the bloom filter. A false negative causes +** more CPU cycles to be used, but it should still yield the correct +** answer. However, an incorrect answer may well arise from a +** false positive - if the jump is taken when it should fall through. +*/ +case OP_Filter: { /* jump */ + u64 h; + + assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); + pIn1 = &aMem[pOp->p1]; + assert( (pIn1->flags & MEM_Blob)!=0 ); + assert( pIn1->n >= 1 ); + h = filterHash(aMem, pOp); +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + int ii; + for(ii=pOp->p3; iip3+pOp->p4.i; ii++){ + registerTrace(ii, &aMem[ii]); + } + printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n)); + } +#endif + h %= pIn1->n; + if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){ + VdbeBranchTaken(1, 2); + p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++; + goto jump_to_p2; + }else{ + p->aCounter[SQLITE_STMTSTATUS_FILTER_MISS]++; + VdbeBranchTaken(0, 2); + } + break; +} + +/* Opcode: Trace P1 P2 * P4 * +** +** Write P4 on the statement trace output if statement tracing is +** enabled. +** +** Operand P1 must be 0x7fffffff and P2 must positive. +*/ +/* Opcode: Init P1 P2 P3 P4 * ** Synopsis: Start at P2 ** ** Programs contain a single instance of this opcode as the very first @@ -84870,10 +95683,16 @@ case OP_MaxPgcnt: { /* out2 */ ** ** Increment the value of P1 so that OP_Once opcodes will jump the ** first time they are evaluated for this run. +** +** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT +** error is encountered. */ +case OP_Trace: case OP_Init: { /* jump */ - char *zTrace; int i; +#ifndef SQLITE_OMIT_TRACE + char *zTrace; +#endif /* If the P4 argument is not NULL, then it must be an SQL comment string. ** The "--" string is broken up to prevent false-positives with srcck1.c. @@ -84885,7 +95704,9 @@ case OP_Init: { /* jump */ ** sqlite3_expanded_sql(P) otherwise. */ assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); - assert( pOp==p->aOp ); /* Always instruction 0 */ + + /* OP_Init is always instruction 0 */ + assert( pOp==p->aOp || pOp->opcode==OP_Trace ); #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 @@ -84894,14 +95715,17 @@ case OP_Init: { /* jump */ ){ #ifndef SQLITE_OMIT_DEPRECATED if( db->mTrace & SQLITE_TRACE_LEGACY ){ - void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace; char *z = sqlite3VdbeExpandSql(p, zTrace); - x(db->pTraceArg, z); + db->trace.xLegacy(db->pTraceArg, z); sqlite3_free(z); }else #endif - { - (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); + if( db->nVdbeExec>1 ){ + char *z = sqlite3MPrintf(db, "-- %s", zTrace); + (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z); + sqlite3DbFree(db, z); + }else{ + (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); } } #ifdef SQLITE_USE_FCNTL_TRACE @@ -84924,12 +95748,14 @@ case OP_Init: { /* jump */ #endif /* SQLITE_OMIT_TRACE */ assert( pOp->p2>0 ); if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){ + if( pOp->opcode==OP_Trace ) break; for(i=1; inOp; i++){ if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0; } pOp->p1 = 0; } pOp->p1++; + p->aCounter[SQLITE_STMTSTATUS_RUN]++; goto jump_to_p2; } @@ -84956,6 +95782,71 @@ case OP_CursorHint: { } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ +#ifdef SQLITE_DEBUG +/* Opcode: Abortable * * * * * +** +** Verify that an Abort can happen. Assert if an Abort at this point +** might cause database corruption. This opcode only appears in debugging +** builds. +** +** An Abort is safe if either there have been no writes, or if there is +** an active statement journal. +*/ +case OP_Abortable: { + sqlite3VdbeAssertAbortable(p); + break; +} +#endif + +#ifdef SQLITE_DEBUG +/* Opcode: ReleaseReg P1 P2 P3 * P5 +** Synopsis: release r[P1@P2] mask P3 +** +** Release registers from service. Any content that was in the +** the registers is unreliable after this opcode completes. +** +** The registers released will be the P2 registers starting at P1, +** except if bit ii of P3 set, then do not release register P1+ii. +** In other words, P3 is a mask of registers to preserve. +** +** Releasing a register clears the Mem.pScopyFrom pointer. That means +** that if the content of the released register was set using OP_SCopy, +** a change to the value of the source register for the OP_SCopy will no longer +** generate an assertion fault in sqlite3VdbeMemAboutToChange(). +** +** If P5 is set, then all released registers have their type set +** to MEM_Undefined so that any subsequent attempt to read the released +** register (before it is reinitialized) will generate an assertion fault. +** +** P5 ought to be set on every call to this opcode. +** However, there are places in the code generator will release registers +** before their are used, under the (valid) assumption that the registers +** will not be reallocated for some other purpose before they are used and +** hence are safe to release. +** +** This opcode is only available in testing and debugging builds. It is +** not generated for release builds. The purpose of this opcode is to help +** validate the generated bytecode. This opcode does not actually contribute +** to computing an answer. +*/ +case OP_ReleaseReg: { + Mem *pMem; + int i; + u32 constMask; + assert( pOp->p1>0 ); + assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); + pMem = &aMem[pOp->p1]; + constMask = pOp->p3; + for(i=0; ip2; i++, pMem++){ + if( i>=32 || (constMask & MASKBIT32(i))==0 ){ + pMem->pScopyFrom = 0; + if( i<32 && pOp->p5 ) MemSetTypeFlag(pMem, MEM_Undefined); + } + } + break; +} +#endif + /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump @@ -84967,8 +95858,9 @@ case OP_CursorHint: { ** This opcode records information from the optimizer. It is the ** the same as a no-op. This opcodesnever appears in a real VM program. */ -default: { /* This is really OP_Noop and OP_Explain */ +default: { /* This is really OP_Noop, OP_Explain */ assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain ); + break; } @@ -84982,7 +95874,7 @@ default: { /* This is really OP_Noop and OP_Explain */ #ifdef VDBE_PROFILE { - u64 endTime = sqlite3Hwtime(); + u64 endTime = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); if( endTime>start ) pOrigOp->cycles += endTime - start; pOrigOp->cnt++; } @@ -85006,6 +95898,12 @@ default: { /* This is really OP_Noop and OP_Explain */ if( opProperty & OPFLG_OUT3 ){ registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]); } + if( opProperty==0xff ){ + /* Never happens. This code exists to avoid a harmless linkage + ** warning aboud sqlite3VdbeRegisterDump() being defined but not + ** used. */ + sqlite3VdbeRegisterDump(p); + } } #endif /* SQLITE_DEBUG */ #endif /* NDEBUG */ @@ -85015,18 +95913,37 @@ default: { /* This is really OP_Noop and OP_Explain */ ** an error of some kind. */ abort_due_to_error: - if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT; + if( db->mallocFailed ){ + rc = SQLITE_NOMEM_BKPT; + }else if( rc==SQLITE_IOERR_CORRUPTFS ){ + rc = SQLITE_CORRUPT_BKPT; + } assert( rc ); +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_VdbeTrace ){ + const char *zTrace = p->zSql; + if( zTrace==0 ){ + if( aOp[0].opcode==OP_Trace ){ + zTrace = aOp[0].p4.z; + } + if( zTrace==0 ) zTrace = "???"; + } + printf("ABORT-due-to-error (rc=%d): %s\n", rc, zTrace); + } +#endif if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); } p->rc = rc; sqlite3SystemError(db, rc); testcase( sqlite3GlobalConfig.xLog!=0 ); - sqlite3_log(rc, "statement aborts at %d: [%s] %s", + sqlite3_log(rc, "statement aborts at %d: [%s] %s", (int)(pOp - aOp), p->zSql, p->zErrMsg); sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); + if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ + db->flags |= SQLITE_CorruptRdOnly; + } rc = SQLITE_ERROR; if( resetSchemaOnFault>0 ){ sqlite3ResetOneSchema(db, resetSchemaOnFault-1); @@ -85036,11 +95953,20 @@ default: { /* This is really OP_Noop and OP_Explain */ ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: - testcase( nVmStep>0 ); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ + nProgressLimit += db->nProgressOps; + if( db->xProgress(db->pProgressArg) ){ + nProgressLimit = LARGEST_UINT64; + rc = SQLITE_INTERRUPT; + goto abort_due_to_error; + } + } +#endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; sqlite3VdbeLeave(p); - assert( rc!=SQLITE_OK || nExtraDelete==0 - || sqlite3_strlike("DELETE%",p->zSql,0)!=0 + assert( rc!=SQLITE_OK || nExtraDelete==0 + || sqlite3_strlike("DELETE%",p->zSql,0)!=0 ); return rc; @@ -85064,10 +95990,8 @@ default: { /* This is really OP_Noop and OP_Explain */ ** flag. */ abort_due_to_interrupt: - assert( db->u1.isInterrupted ); - rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; - p->rc = rc; - sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); + assert( AtomicLoad(&db->u1.isInterrupted) ); + rc = SQLITE_INTERRUPT; goto abort_due_to_error; } @@ -85124,7 +96048,7 @@ struct Incrblob { ** sqlite3DbFree(). ** ** If an error does occur, then the b-tree cursor is closed. All subsequent -** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will +** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will ** immediately return SQLITE_ABORT. */ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ @@ -85132,25 +96056,29 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){ char *zErr = 0; /* Error message */ Vdbe *v = (Vdbe *)p->pStmt; - /* Set the value of register r[1] in the SQL statement to integer iRow. + /* Set the value of register r[1] in the SQL statement to integer iRow. ** This is done directly as a performance optimization */ v->aMem[1].flags = MEM_Int; v->aMem[1].u.i = iRow; /* If the statement has been run before (and is paused at the OP_ResultRow) - ** then back it up to the point where it does the OP_SeekRowid. This could + ** then back it up to the point where it does the OP_NotExists. This could ** have been down with an extra OP_Goto, but simply setting the program ** counter is faster. */ - if( v->pc>3 ){ - v->pc = 3; + if( v->pc>4 ){ + v->pc = 4; + assert( v->aOp[v->pc].opcode==OP_NotExists ); rc = sqlite3VdbeExec(v); }else{ rc = sqlite3_step(p->pStmt); } if( rc==SQLITE_ROW ){ VdbeCursor *pC = v->apCsr[0]; - u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; + u32 type; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0; testcase( pC->nHdrParsed==p->iCol ); testcase( pC->nHdrParsed==p->iCol+1 ); if( type<12 ){ @@ -85205,8 +96133,8 @@ SQLITE_API int sqlite3_blob_open( int rc = SQLITE_OK; char *zErr = 0; Table *pTab; - Parse *pParse = 0; Incrblob *pBlob = 0; + Parse sParse; #ifdef SQLITE_ENABLE_API_ARMOR if( ppBlob==0 ){ @@ -85224,37 +96152,33 @@ SQLITE_API int sqlite3_blob_open( sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); - if( !pBlob ) goto blob_open_out; - pParse = sqlite3StackAllocRaw(db, sizeof(*pParse)); - if( !pParse ) goto blob_open_out; - - do { - memset(pParse, 0, sizeof(Parse)); - pParse->db = db; + while(1){ + sqlite3ParseObjectInit(&sParse,db); + if( !pBlob ) goto blob_open_out; sqlite3DbFree(db, zErr); zErr = 0; sqlite3BtreeEnterAll(db); - pTab = sqlite3LocateTable(pParse, 0, zTable, zDb); + pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb); if( pTab && IsVirtual(pTab) ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable); } if( pTab && !HasRowid(pTab) ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable); } #ifndef SQLITE_OMIT_VIEW - if( pTab && pTab->pSelect ){ + if( pTab && IsView(pTab) ){ pTab = 0; - sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable); + sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable); } #endif if( !pTab ){ - if( pParse->zErrMsg ){ + if( sParse.zErrMsg ){ sqlite3DbFree(db, zErr); - zErr = pParse->zErrMsg; - pParse->zErrMsg = 0; + zErr = sParse.zErrMsg; + sParse.zErrMsg = 0; } rc = SQLITE_ERROR; sqlite3BtreeLeaveAll(db); @@ -85265,7 +96189,7 @@ SQLITE_API int sqlite3_blob_open( /* Now search pTab for the exact column. */ for(iCol=0; iColnCol; iCol++) { - if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){ + if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){ break; } } @@ -85278,7 +96202,7 @@ SQLITE_API int sqlite3_blob_open( } /* If the value is being opened for writing, check that the - ** column is not indexed, and that it is not part of a foreign key. + ** column is not indexed, and that it is not part of a foreign key. */ if( wrFlag ){ const char *zFault = 0; @@ -85287,10 +96211,11 @@ SQLITE_API int sqlite3_blob_open( if( db->flags&SQLITE_ForeignKeys ){ /* Check that the column is not part of an FK child key definition. It ** is not necessary to check if it is part of a parent key, as parent - ** key columns must be indexed. The check below will pick up this + ** key columns must be indexed. The check below will pick up this ** case. */ FKey *pFKey; - for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + assert( IsOrdinaryTable(pTab) ); + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ int j; for(j=0; jnCol; j++){ if( pFKey->aCol[j].iFrom==iCol ){ @@ -85318,11 +96243,11 @@ SQLITE_API int sqlite3_blob_open( } } - pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse); + pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse); assert( pBlob->pStmt || db->mallocFailed ); if( pBlob->pStmt ){ - - /* This VDBE program seeks a btree cursor to the identified + + /* This VDBE program seeks a btree cursor to the identified ** db/table/row entry. The reason for using a vdbe program instead ** of writing code to use the b-tree layer directly is that the ** vdbe program will take advantage of the various transaction, @@ -85330,11 +96255,11 @@ SQLITE_API int sqlite3_blob_open( ** ** After seeking the cursor, the vdbe executes an OP_ResultRow. ** Code external to the Vdbe then "borrows" the b-tree cursor and - ** uses it to implement the blob_read(), blob_write() and + ** uses it to implement the blob_read(), blob_write() and ** blob_bytes() functions. ** ** The sqlite3_blob_close() function finalizes the vdbe program, - ** which closes the b-tree cursor and (possibly) commits the + ** which closes the b-tree cursor and (possibly) commits the ** transaction. */ static const int iLn = VDBE_OFFSET_LINENO(2); @@ -85351,14 +96276,15 @@ SQLITE_API int sqlite3_blob_open( int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); VdbeOp *aOp; - sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, + sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag, pTab->pSchema->schema_cookie, pTab->pSchema->iGeneration); - sqlite3VdbeChangeP5(v, 1); + sqlite3VdbeChangeP5(v, 1); + assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed ); aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); /* Make sure a mutex is held on the table to be accessed */ - sqlite3VdbeUsesBtree(v, iDb); + sqlite3VdbeUsesBtree(v, iDb); if( db->mallocFailed==0 ){ assert( aOp!=0 ); @@ -85369,35 +96295,35 @@ SQLITE_API int sqlite3_blob_open( aOp[0].p1 = iDb; aOp[0].p2 = pTab->tnum; aOp[0].p3 = wrFlag; - sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); + sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); } if( db->mallocFailed==0 ){ #endif - /* Remove either the OP_OpenWrite or OpenRead. Set the P2 + /* Remove either the OP_OpenWrite or OpenRead. Set the P2 ** parameter of the other to pTab->tnum. */ if( wrFlag ) aOp[1].opcode = OP_OpenWrite; aOp[1].p2 = pTab->tnum; - aOp[1].p3 = iDb; + aOp[1].p3 = iDb; /* Configure the number of columns. Configure the cursor to ** think that the table has one more column than it really ** does. An OP_Column to retrieve this imaginary column will ** always return an SQL NULL. This is useful because it means - ** we can invoke OP_Column to fill in the vdbe cursors type + ** we can invoke OP_Column to fill in the vdbe cursors type ** and offset cache without causing any IO. */ aOp[1].p4type = P4_INT32; aOp[1].p4.i = pTab->nCol+1; aOp[3].p2 = pTab->nCol; - pParse->nVar = 0; - pParse->nMem = 1; - pParse->nTab = 1; - sqlite3VdbeMakeReady(v, pParse); + sParse.nVar = 0; + sParse.nMem = 1; + sParse.nTab = 1; + sqlite3VdbeMakeReady(v, &sParse); } } - + pBlob->iCol = iCol; pBlob->db = db; sqlite3BtreeLeaveAll(db); @@ -85405,7 +96331,9 @@ SQLITE_API int sqlite3_blob_open( goto blob_open_out; } rc = blobSeekToRow(pBlob, iRow, &zErr); - } while( (++nAttempt)=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break; + sqlite3ParseObjectReset(&sParse); + } blob_open_out: if( rc==SQLITE_OK && db->mallocFailed==0 ){ @@ -85416,8 +96344,7 @@ SQLITE_API int sqlite3_blob_open( } sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); - sqlite3ParserReset(pParse); - sqlite3StackFree(db, pParse); + sqlite3ParseObjectReset(&sParse); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; @@ -85433,11 +96360,12 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){ sqlite3 *db; if( p ){ + sqlite3_stmt *pStmt = p->pStmt; db = p->db; sqlite3_mutex_enter(db->mutex); - rc = sqlite3_finalize(p->pStmt); sqlite3DbFree(db, p); sqlite3_mutex_leave(db->mutex); + rc = sqlite3_finalize(pStmt); }else{ rc = SQLITE_OK; } @@ -85448,10 +96376,10 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){ ** Perform a read or write operation on a blob */ static int blobReadWrite( - sqlite3_blob *pBlob, - void *z, - int n, - int iOffset, + sqlite3_blob *pBlob, + void *z, + int n, + int iOffset, int (*xCall)(BtCursor*, u32, u32, void*) ){ int rc; @@ -85481,14 +96409,14 @@ static int blobReadWrite( #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){ - /* If a pre-update hook is registered and this is a write cursor, - ** invoke it here. - ** + /* If a pre-update hook is registered and this is a write cursor, + ** invoke it here. + ** ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this ** operation should really be an SQLITE_UPDATE. This is probably - ** incorrect, but is convenient because at this point the new.* values - ** are not easily obtainable. And for the sessions module, an - ** SQLITE_UPDATE where the PK columns do not change is handled in the + ** incorrect, but is convenient because at this point the new.* values + ** are not easily obtainable. And for the sessions module, an + ** SQLITE_UPDATE where the PK columns do not change is handled in the ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module @@ -85496,8 +96424,10 @@ static int blobReadWrite( */ sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); + assert( v->apCsr[0]!=0 ); + assert( v->apCsr[0]->eCurType==CURTYPE_BTREE ); sqlite3VdbePreUpdateHook( - v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 + v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol ); } #endif @@ -85548,8 +96478,8 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){ ** ** If an error occurs, or if the specified row does not exist or does not ** contain a blob or text value, then an error code is returned and the -** database handle error code and message set. If this happens, then all -** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) +** database handle error code and message set. If this happens, then all +** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) ** immediately return SQLITE_ABORT. */ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ @@ -85568,6 +96498,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ rc = SQLITE_ABORT; }else{ char *zErr; + ((Vdbe*)p->pStmt)->rc = SQLITE_OK; rc = blobSeekToRow(p, iRow, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); @@ -85643,7 +96574,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** is like Close() followed by Init() only ** much faster. ** -** The interfaces above must be called in a particular order. Write() can +** The interfaces above must be called in a particular order. Write() can ** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and ** Compare() can only occur in between Rewind() and Close()/Reset(). i.e. ** @@ -85651,16 +96582,16 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** for each record: Write() ** Rewind() ** Rowkey()/Compare() -** Next() +** Next() ** Close() ** ** Algorithm: ** -** Records passed to the sorter via calls to Write() are initially held +** Records passed to the sorter via calls to Write() are initially held ** unsorted in main memory. Assuming the amount of memory used never exceeds ** a threshold, when Rewind() is called the set of records is sorted using ** an in-memory merge sort. In this case, no temporary files are required -** and subsequent calls to Rowkey(), Next() and Compare() read records +** and subsequent calls to Rowkey(), Next() and Compare() read records ** directly from main memory. ** ** If the amount of space used to store records in main memory exceeds the @@ -85670,10 +96601,10 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** of PMAs may be created by merging existing PMAs together - for example ** merging two or more level-0 PMAs together creates a level-1 PMA. ** -** The threshold for the amount of main memory to use before flushing +** The threshold for the amount of main memory to use before flushing ** records to a PMA is roughly the same as the limit configured for the -** page-cache of the main database. Specifically, the threshold is set to -** the value returned by "PRAGMA main.page_size" multipled by +** page-cache of the main database. Specifically, the threshold is set to +** the value returned by "PRAGMA main.page_size" multipled by ** that returned by "PRAGMA main.cache_size", in bytes. ** ** If the sorter is running in single-threaded mode, then all PMAs generated @@ -85690,7 +96621,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** than zero, and (b) worker threads have been enabled at runtime by calling ** "PRAGMA threads=N" with some value of N greater than 0. ** -** When Rewind() is called, any data remaining in memory is flushed to a +** When Rewind() is called, any data remaining in memory is flushed to a ** final PMA. So at this point the data is stored in some number of sorted ** PMAs within temporary files on disk. ** @@ -85702,16 +96633,16 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ ** ** Or, if running in multi-threaded mode, then a background thread is ** launched to merge the existing PMAs. Once the background thread has -** merged T bytes of data into a single sorted PMA, the main thread +** merged T bytes of data into a single sorted PMA, the main thread ** begins reading keys from that PMA while the background thread proceeds ** with merging the next T bytes of data. And so on. ** -** Parameter T is set to half the value of the memory threshold used +** Parameter T is set to half the value of the memory threshold used ** by Write() above to determine when to create a new PMA. ** -** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when -** Rewind() is called, then a hierarchy of incremental-merges is used. -** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on +** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when +** Rewind() is called, then a hierarchy of incremental-merges is used. +** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on ** disk are merged together. Then T bytes of data from the second set, and ** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT ** PMAs at a time. This done is to improve locality. @@ -85726,7 +96657,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){ /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ -/* +/* ** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various ** messages to stderr that may be helpful in understanding the performance ** characteristics of the sorter in multi-threaded mode. @@ -85755,7 +96686,7 @@ typedef struct SorterList SorterList; /* In-memory list of records */ typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */ /* -** A container for a temp file handle and the current amount of data +** A container for a temp file handle and the current amount of data ** stored in the file. */ struct SorterFile { @@ -85795,17 +96726,17 @@ struct SorterList { ** the MergeEngine.nTree variable. ** ** The final (N/2) elements of aTree[] contain the results of comparing -** pairs of PMA keys together. Element i contains the result of +** pairs of PMA keys together. Element i contains the result of ** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the -** aTree element is set to the index of it. +** aTree element is set to the index of it. ** ** For the purposes of this comparison, EOF is considered greater than any ** other key value. If the keys are equal (only possible with two EOF ** values), it doesn't matter which index is stored. ** -** The (N/4) elements of aTree[] that precede the final (N/2) described +** The (N/4) elements of aTree[] that precede the final (N/2) described ** above contains the index of the smallest of each block of 4 PmaReaders -** And so on. So that aTree[1] contains the index of the PmaReader that +** And so on. So that aTree[1] contains the index of the PmaReader that ** currently points to the smallest key value. aTree[0] is unused. ** ** Example: @@ -85821,7 +96752,7 @@ struct SorterList { ** ** aTree[] = { X, 5 0, 5 0, 3, 5, 6 } ** -** The current element is "Apple" (the value of the key indicated by +** The current element is "Apple" (the value of the key indicated by ** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will ** be advanced to the next key in its segment. Say the next key is ** "Eggplant": @@ -85862,8 +96793,8 @@ struct MergeEngine { ** each thread requries its own UnpackedRecord object to unpack records in ** as part of comparison operations. ** -** Before a background thread is launched, variable bDone is set to 0. Then, -** right before it exits, the thread itself sets bDone to 1. This is used for +** Before a background thread is launched, variable bDone is set to 0. Then, +** right before it exits, the thread itself sets bDone to 1. This is used for ** two purposes: ** ** 1. When flushing the contents of memory to a level-0 PMA on disk, to @@ -85894,7 +96825,7 @@ struct SortSubtask { /* -** Main sorter structure. A single instance of this is allocated for each +** Main sorter structure. A single instance of this is allocated for each ** sorter cursor created by the VDBE. ** ** mxKeysize: @@ -85950,21 +96881,21 @@ struct PmaReader { }; /* -** Normally, a PmaReader object iterates through an existing PMA stored +** Normally, a PmaReader object iterates through an existing PMA stored ** within a temp file. However, if the PmaReader.pIncr variable points to ** an object of the following type, it may be used to iterate/merge through ** multiple PMAs simultaneously. ** -** There are two types of IncrMerger object - single (bUseThread==0) and -** multi-threaded (bUseThread==1). +** There are two types of IncrMerger object - single (bUseThread==0) and +** multi-threaded (bUseThread==1). ** -** A multi-threaded IncrMerger object uses two temporary files - aFile[0] -** and aFile[1]. Neither file is allowed to grow to more than mxSz bytes in -** size. When the IncrMerger is initialized, it reads enough data from -** pMerger to populate aFile[0]. It then sets variables within the -** corresponding PmaReader object to read from that file and kicks off -** a background thread to populate aFile[1] with the next mxSz bytes of -** sorted record data from pMerger. +** A multi-threaded IncrMerger object uses two temporary files - aFile[0] +** and aFile[1]. Neither file is allowed to grow to more than mxSz bytes in +** size. When the IncrMerger is initialized, it reads enough data from +** pMerger to populate aFile[0]. It then sets variables within the +** corresponding PmaReader object to read from that file and kicks off +** a background thread to populate aFile[1] with the next mxSz bytes of +** sorted record data from pMerger. ** ** When the PmaReader reaches the end of aFile[0], it blocks until the ** background thread has finished populating aFile[1]. It then exchanges @@ -85975,7 +96906,7 @@ struct PmaReader { ** ** A single-threaded IncrMerger does not open any temporary files of its ** own. Instead, it has exclusive access to mxSz bytes of space beginning -** at offset iStartOff of file pTask->file2. And instead of using a +** at offset iStartOff of file pTask->file2. And instead of using a ** background thread to prepare data for the PmaReader, with a single ** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with ** keys from pMerger by the calling thread whenever the PmaReader runs out @@ -86087,7 +97018,7 @@ static int vdbePmaReadBlob( assert( p->aBuffer ); - /* If there is no more data to be read from the buffer, read the next + /* If there is no more data to be read from the buffer, read the next ** p->nBuffer bytes of data from the file into it. Or, if there are less ** than p->nBuffer bytes remaining in the PMA, read all remaining data. */ iBuf = p->iReadOff % p->nBuffer; @@ -86108,11 +97039,11 @@ static int vdbePmaReadBlob( assert( rc!=SQLITE_IOERR_SHORT_READ ); if( rc!=SQLITE_OK ) return rc; } - nAvail = p->nBuffer - iBuf; + nAvail = p->nBuffer - iBuf; if( nByte<=nAvail ){ /* The requested data is available in the in-memory buffer. In this - ** case there is no need to make a copy of the data, just return a + ** case there is no need to make a copy of the data, just return a ** pointer into the buffer to the caller. */ *ppOut = &p->aBuffer[iBuf]; p->iReadOff += nByte; @@ -86125,7 +97056,7 @@ static int vdbePmaReadBlob( /* Extend the p->aAlloc[] allocation if required. */ if( p->nAllocnAlloc*2); + sqlite3_int64 nNew = MAX(128, 2*(sqlite3_int64)p->nAlloc); while( nByte>nNew ) nNew = nNew*2; aNew = sqlite3Realloc(p->aAlloc, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; @@ -86191,7 +97122,7 @@ static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){ /* ** Attempt to memory map file pFile. If successful, set *pp to point to the -** new mapping and return SQLITE_OK. If the mapping is not attempted +** new mapping and return SQLITE_OK. If the mapping is not attempted ** (because the file is too large or the VFS layer is configured not to use ** mmap), return SQLITE_OK and set *pp to NULL. ** @@ -86212,7 +97143,7 @@ static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){ /* ** Attach PmaReader pReadr to file pFile (if it is not already attached to -** that file) and seek it to offset iOff within the file. Return SQLITE_OK +** that file) and seek it to offset iOff within the file. Return SQLITE_OK ** if successful, or an SQLite error code if an error occurs. */ static int vdbePmaReaderSeek( @@ -86302,11 +97233,11 @@ static int vdbePmaReaderNext(PmaReader *pReadr){ /* ** Initialize PmaReader pReadr to scan through the PMA stored in file pFile -** starting at offset iStart and ending at offset iEof-1. This function -** leaves the PmaReader pointing to the first key in the PMA (or EOF if the +** starting at offset iStart and ending at offset iEof-1. This function +** leaves the PmaReader pointing to the first key in the PMA (or EOF if the ** PMA is empty). ** -** If the pnByte parameter is NULL, then it is assumed that the file +** If the pnByte parameter is NULL, then it is assumed that the file ** contains a single PMA, and that that PMA omits the initial length varint. */ static int vdbePmaReaderInit( @@ -86339,7 +97270,7 @@ static int vdbePmaReaderInit( /* ** A version of vdbeSorterCompare() that assumes that it has already been -** determined that the first field of key1 is equal to the first field of +** determined that the first field of key1 is equal to the first field of ** key2. */ static int vdbeSorterCompareTail( @@ -86357,7 +97288,7 @@ static int vdbeSorterCompareTail( } /* -** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, +** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, ** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences ** used by the comparison. Return the result of the comparison. ** @@ -86403,21 +97334,22 @@ static int vdbeSorterCompareText( int n2; int res; - getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2; - getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2; - res = memcmp(v1, v2, MIN(n1, n2)); + getVarint32NR(&p1[1], n1); + getVarint32NR(&p2[1], n2); + res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2); if( res==0 ){ res = n1 - n2; } if( res==0 ){ - if( pTask->pSorter->pKeyInfo->nField>1 ){ + if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } }else{ - if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ + assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); + if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ res = res * -1; } } @@ -86446,47 +97378,47 @@ static int vdbeSorterCompareInt( assert( (s1>0 && s1<7) || s1==8 || s1==9 ); assert( (s2>0 && s2<7) || s2==8 || s2==9 ); - if( s1>7 && s2>7 ){ - res = s1 - s2; - }else{ - if( s1==s2 ){ - if( (*v1 ^ *v2) & 0x80 ){ - /* The two values have different signs */ - res = (*v1 & 0x80) ? -1 : +1; - }else{ - /* The two values have the same sign. Compare using memcmp(). */ - static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 }; - int i; - res = 0; - for(i=0; i7 && s2>7 ){ + res = s1 - s2; + }else{ + if( s2>7 ){ + res = +1; + }else if( s1>7 ){ + res = -1; }else{ - if( s2>7 ){ - res = +1; - }else if( s1>7 ){ - res = -1; - }else{ - res = s1 - s2; - } - assert( res!=0 ); + res = s1 - s2; + } + assert( res!=0 ); - if( res>0 ){ - if( *v1 & 0x80 ) res = -1; - }else{ - if( *v2 & 0x80 ) res = +1; - } + if( res>0 ){ + if( *v1 & 0x80 ) res = -1; + }else{ + if( *v2 & 0x80 ) res = +1; } } if( res==0 ){ - if( pTask->pSorter->pKeyInfo->nField>1 ){ + if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } - }else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ + }else if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){ + assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) ); res = res * -1; } @@ -86496,13 +97428,13 @@ static int vdbeSorterCompareInt( /* ** Initialize the temporary index cursor just opened as a sorter cursor. ** -** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) +** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField) ** to determine the number of fields that should be compared from the ** records being sorted. However, if the value passed as argument nField ** is non-zero and the sorter is able to guarantee a stable sort, nField ** is used instead. This is used when sorting records for a CREATE INDEX ** statement. In this case, keys are always delivered to the sorter in -** order of the primary key, which happens to be make up the final part +** order of the primary key, which happens to be make up the final part ** of the records being sorted. So if the sort is stable, there is never ** any reason to compare PK fields and they can be ignored for a small ** performance boost. @@ -86547,9 +97479,10 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( } #endif - assert( pCsr->pKeyInfo && pCsr->pBtx==0 ); + assert( pCsr->pKeyInfo ); + assert( !pCsr->isEphemeral ); assert( pCsr->eCurType==CURTYPE_SORTER ); - szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); + szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); @@ -86557,14 +97490,16 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( if( pSorter==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ + Btree *pBt = db->aDb[0].pBt; pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; if( nField && nWorker==0 ){ - pKeyInfo->nXField += (pKeyInfo->nField - nField); - pKeyInfo->nField = nField; + pKeyInfo->nKeyField = nField; } - pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); + sqlite3BtreeEnter(pBt); + pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt); + sqlite3BtreeLeave(pBt); pSorter->nTask = nWorker + 1; pSorter->iPrev = (u8)(nWorker - 1); pSorter->bUseThreads = (pSorter->nTask>1); @@ -86590,11 +97525,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( mxCache = MIN(mxCache, SQLITE_MAX_PMASZ); pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache); - /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of - ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary - ** large heap allocations. - */ - if( sqlite3GlobalConfig.pScratch==0 ){ + /* Avoid large memory allocations if the application has requested + ** SQLITE_CONFIG_SMALL_MALLOC. */ + if( sqlite3GlobalConfig.bSmallMalloc==0 ){ assert( pSorter->iMemory==0 ); pSorter->nMemory = pgsz; pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); @@ -86602,8 +97535,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( } } - if( (pKeyInfo->nField+pKeyInfo->nXField)<13 + if( pKeyInfo->nAllField<13 && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) + && (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0 ){ pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; } @@ -86626,7 +97560,7 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ } /* -** Free all resources owned by the object indicated by argument pTask. All +** Free all resources owned by the object indicated by argument pTask. All ** fields of *pTask are zeroed before returning. */ static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ @@ -86659,8 +97593,9 @@ static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); } static void vdbeSorterRewindDebug(const char *zEvent){ - i64 t; - sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t); + i64 t = 0; + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); + if( ALWAYS(pVfs) ) sqlite3OsCurrentTimeInt64(pVfs, &t); fprintf(stderr, "%lld:X %s\n", t, zEvent); } static void vdbeSorterPopulateDebug( @@ -86725,7 +97660,7 @@ static int vdbeSorterCreateThread( } /* -** Join all outstanding threads launched by SorterWrite() to create +** Join all outstanding threads launched by SorterWrite() to create ** level-0 PMAs. */ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ @@ -86734,10 +97669,10 @@ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){ /* This function is always called by the main user thread. ** - ** If this function is being called after SorterRewind() has been called, + ** If this function is being called after SorterRewind() has been called, ** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread ** is currently attempt to join one of the other threads. To avoid a race - ** condition where this thread also attempts to join the same object, join + ** condition where this thread also attempts to join the same object, join ** thread pSorter->aTask[pSorter->nTask-1].pThread first. */ for(i=pSorter->nTask-1; i>=0; i--){ SortSubtask *pTask = &pSorter->aTask[i]; @@ -86874,7 +97809,7 @@ static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); sqlite3OsFetch(pFd, 0, (int)nByte, &p); - sqlite3OsUnfetch(pFd, 0, p); + if( p ) sqlite3OsUnfetch(pFd, 0, p); } } #else @@ -86909,15 +97844,15 @@ static int vdbeSorterOpenTempFile( } /* -** If it has not already been allocated, allocate the UnpackedRecord -** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or +** If it has not already been allocated, allocate the UnpackedRecord +** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or ** if no allocation was required), or SQLITE_NOMEM otherwise. */ static int vdbeSortAllocUnpacked(SortSubtask *pTask){ if( pTask->pUnpacked==0 ){ pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo); if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT; - pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField; + pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField; pTask->pUnpacked->errCode = 0; } return SQLITE_OK; @@ -86973,32 +97908,28 @@ static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){ if( p->typeMask==SORTER_TYPE_INTEGER ){ return vdbeSorterCompareInt; }else if( p->typeMask==SORTER_TYPE_TEXT ){ - return vdbeSorterCompareText; + return vdbeSorterCompareText; } return vdbeSorterCompare; } /* -** Sort the linked list of records headed at pTask->pList. Return -** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if +** Sort the linked list of records headed at pTask->pList. Return +** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if ** an error occurs. */ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ int i; - SorterRecord **aSlot; SorterRecord *p; int rc; + SorterRecord *aSlot[64]; rc = vdbeSortAllocUnpacked(pTask); if( rc!=SQLITE_OK ) return rc; p = pList->pList; pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter); - - aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); - if( !aSlot ){ - return SQLITE_NOMEM_BKPT; - } + memset(aSlot, 0, sizeof(aSlot)); while( p ){ SorterRecord *pNext; @@ -87023,15 +97954,14 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ } p = 0; - for(i=0; i<64; i++){ + for(i=0; ipList = p; - sqlite3_free(aSlot); - assert( pTask->pUnpacked->errCode==SQLITE_OK - || pTask->pUnpacked->errCode==SQLITE_NOMEM + assert( pTask->pUnpacked->errCode==SQLITE_OK + || pTask->pUnpacked->errCode==SQLITE_NOMEM ); return pTask->pUnpacked->errCode; } @@ -87072,8 +98002,8 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy); p->iBufEnd += nCopy; if( p->iBufEnd==p->nBuffer ){ - p->eFWErr = sqlite3OsWrite(p->pFd, - &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, + p->eFWErr = sqlite3OsWrite(p->pFd, + &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); p->iBufStart = p->iBufEnd = 0; @@ -87088,7 +98018,7 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ /* ** Flush any buffered data to disk and clean up the PMA-writer object. ** The results of using the PMA-writer after this call are undefined. -** Return SQLITE_OK if flushing the buffered data succeeds or is not +** Return SQLITE_OK if flushing the buffered data succeeds or is not ** required. Otherwise, return an SQLite error code. ** ** Before returning, set *piEof to the offset immediately following the @@ -87097,8 +98027,8 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){ static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){ int rc; if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){ - p->eFWErr = sqlite3OsWrite(p->pFd, - &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, + p->eFWErr = sqlite3OsWrite(p->pFd, + &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart, p->iWriteOff + p->iBufStart ); } @@ -87110,11 +98040,11 @@ static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){ } /* -** Write value iVal encoded as a varint to the PMA. Return +** Write value iVal encoded as a varint to the PMA. Return ** SQLITE_OK if successful, or an SQLite error code if an error occurs. */ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){ - int nByte; + int nByte; u8 aByte[10]; nByte = sqlite3PutVarint(aByte, iVal); vdbePmaWriteBlob(p, aByte, nByte); @@ -87122,7 +98052,7 @@ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){ /* ** Write the current contents of in-memory linked-list pList to a level-0 -** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if +** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if ** successful, or an SQLite error code otherwise. ** ** The format of a PMA is: @@ -87130,8 +98060,8 @@ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){ ** * A varint. This varint contains the total number of bytes of content ** in the PMA (not including the varint itself). ** -** * One or more records packed end-to-end in order of ascending keys. -** Each record consists of a varint followed by a blob of data (the +** * One or more records packed end-to-end in order of ascending keys. +** Each record consists of a varint followed by a blob of data (the ** key). The varint is the number of bytes in the blob of data. */ static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){ @@ -87140,7 +98070,7 @@ static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){ PmaWriter writer; /* Object used to write to the file */ #ifdef SQLITE_DEBUG - /* Set iSz to the expected size of file pTask->file after writing the PMA. + /* Set iSz to the expected size of file pTask->file after writing the PMA. ** This is used by an assert() statement at the end of this function. */ i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof; #endif @@ -87293,7 +98223,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ SortSubtask *pTask = 0; /* Thread context used to create new PMA */ int nWorker = (pSorter->nTask-1); - /* Set the flag to indicate that at least one PMA has been written. + /* Set the flag to indicate that at least one PMA has been written. ** Or will be, anyhow. */ pSorter->bUsePMA = 1; @@ -87303,7 +98233,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ ** the background thread from a sub-tasks previous turn is still running, ** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy, ** fall back to using the final sub-task. The first (pSorter->nTask-1) - ** sub-tasks are prefered as they use background threads - the final + ** sub-tasks are prefered as they use background threads - the final ** sub-task uses the main thread. */ for(i=0; iiPrev + i + 1) % nWorker; @@ -87320,13 +98250,16 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){ rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list); }else{ /* Launch a background thread for this operation */ - u8 *aMem = pTask->list.aMemory; - void *pCtx = (void*)pTask; + u8 *aMem; + void *pCtx; + assert( pTask!=0 ); assert( pTask->pThread==0 && pTask->bDone==0 ); assert( pTask->list.pList==0 ); assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 ); + aMem = pTask->list.aMemory; + pCtx = (void*)pTask; pSorter->iPrev = (u8)(pTask - pSorter->aTask); pTask->list = pSorter->list; pSorter->list.pList = 0; @@ -87364,7 +98297,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( assert( pCsr->eCurType==CURTYPE_SORTER ); pSorter = pCsr->uc.pSorter; - getVarint32((const u8*)&pVal->z[1], t); + getVarint32NR((const u8*)&pVal->z[1], t); if( t>0 && t<10 && t!=7 ){ pSorter->typeMask &= SORTER_TYPE_INTEGER; }else if( t>10 && (t & 0x01) ){ @@ -87381,14 +98314,14 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( ** If using the single large allocation mode (pSorter->aMemory!=0), then ** flush the contents of memory to a new PMA if (a) at least one value is ** already in memory and (b) the new value will not fit in memory. - ** + ** ** Or, if using separate allocations for each record, flush the contents ** of memory to a PMA if either of the following are true: ** - ** * The total memory allocated for the in-memory list is greater + ** * The total memory allocated for the in-memory list is greater ** than (page-size * cache-size), or ** - ** * The total memory allocated for the in-memory list is greater + ** * The total memory allocated for the in-memory list is greater ** than (page-size * 10) and sqlite3HeapNearlyFull() returns true. */ nReq = pVal->n + sizeof(SorterRecord); @@ -87420,15 +98353,19 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( if( nMin>pSorter->nMemory ){ u8 *aNew; - int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; - int nNew = pSorter->nMemory * 2; + sqlite3_int64 nNew = 2 * (sqlite3_int64)pSorter->nMemory; + int iListOff = -1; + if( pSorter->list.pList ){ + iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; + } while( nNew < nMin ) nNew = nNew*2; if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; if( nNew < nMin ) nNew = nMin; - aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; - pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; + if( iListOff>=0 ){ + pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; + } pSorter->list.aMemory = aNew; pSorter->nMemory = nNew; } @@ -87523,11 +98460,11 @@ static int vdbeIncrBgPopulate(IncrMerger *pIncr){ ** aFile[0] such that the PmaReader should start rereading it from the ** beginning. ** -** For single-threaded objects, this is accomplished by literally reading -** keys from pIncr->pMerger and repopulating aFile[0]. +** For single-threaded objects, this is accomplished by literally reading +** keys from pIncr->pMerger and repopulating aFile[0]. ** -** For multi-threaded objects, all that is required is to wait until the -** background thread is finished (if it is not already) and then swap +** For multi-threaded objects, all that is required is to wait until the +** background thread is finished (if it is not already) and then swap ** aFile[0] and aFile[1] in place. If the contents of pMerger have not ** been exhausted, this function also launches a new background thread ** to populate the new aFile[1]. @@ -87590,6 +98527,7 @@ static int vdbeIncrMergerNew( vdbeMergeEngineFree(pMerger); rc = SQLITE_NOMEM_BKPT; } + assert( *ppOut!=0 || rc!=SQLITE_OK ); return rc; } @@ -87667,7 +98605,7 @@ static void vdbeMergeEngineCompare( #define INCRINIT_TASK 1 #define INCRINIT_ROOT 2 -/* +/* ** Forward reference required as the vdbeIncrMergeInit() and ** vdbePmaReaderIncrInit() routines are called mutually recursively when ** building a merge tree. @@ -87676,7 +98614,7 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode); /* ** Initialize the MergeEngine object passed as the second argument. Once this -** function returns, the first key of merged data may be read from the +** function returns, the first key of merged data may be read from the ** MergeEngine object in the usual fashion. ** ** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge @@ -87686,8 +98624,8 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode); ** required is to call vdbePmaReaderNext() on each PmaReader to point it at ** its first key. ** -** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use -** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data +** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use +** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data ** to pMerger. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. @@ -87699,7 +98637,11 @@ static int vdbeMergeEngineInit( ){ int rc = SQLITE_OK; /* Return code */ int i; /* For looping over PmaReader objects */ - int nTree = pMerger->nTree; + int nTree; /* Number of subtrees to merge */ + + /* Failure to allocate the merge would have been detected prior to + ** invoking this routine */ + assert( pMerger!=0 ); /* eMode is always INCRINIT_NORMAL in single-threaded mode */ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); @@ -87708,6 +98650,7 @@ static int vdbeMergeEngineInit( assert( pMerger->pTask==0 ); pMerger->pTask = pTask; + nTree = pMerger->nTree; for(i=0; i0 && eMode==INCRINIT_ROOT ){ /* PmaReaders should be normally initialized in order, as if they are @@ -87737,19 +98680,19 @@ static int vdbeMergeEngineInit( ** object at (pReadr->pIncr). ** ** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders -** in the sub-tree headed by pReadr are also initialized. Data is then -** loaded into the buffers belonging to pReadr and it is set to point to +** in the sub-tree headed by pReadr are also initialized. Data is then +** loaded into the buffers belonging to pReadr and it is set to point to ** the first key in its range. ** ** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed ** to be a multi-threaded PmaReader and this function is being called in a -** background thread. In this case all PmaReaders in the sub-tree are +** background thread. In this case all PmaReaders in the sub-tree are ** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to ** pReadr is populated. However, pReadr itself is not set up to point ** to its first key. A call to vdbePmaReaderNext() is still required to do -** that. +** that. ** -** The reason this function does not call vdbePmaReaderNext() immediately +** The reason this function does not call vdbePmaReaderNext() immediately ** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has ** to block on thread (pTask->thread) before accessing aFile[1]. But, since ** this entire function is being run by thread (pTask->thread), that will @@ -87805,12 +98748,12 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ if( rc==SQLITE_OK && pIncr->bUseThread ){ /* Use the current thread to populate aFile[1], even though this ** PmaReader is multi-threaded. If this is an INCRINIT_TASK object, - ** then this function is already running in background thread - ** pIncr->pTask->thread. + ** then this function is already running in background thread + ** pIncr->pTask->thread. ** - ** If this is the INCRINIT_ROOT object, then it is running in the + ** If this is the INCRINIT_ROOT object, then it is running in the ** main VDBE thread. But that is Ok, as that thread cannot return - ** control to the VDBE or proceed with anything useful until the + ** control to the VDBE or proceed with anything useful until the ** first results are ready from this merger object anyway. */ assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); @@ -87827,7 +98770,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ #if SQLITE_MAX_WORKER_THREADS>0 /* -** The main routine for vdbePmaReaderIncrMergeInit() operations run in +** The main routine for vdbePmaReaderIncrMergeInit() operations run in ** background threads. */ static void *vdbePmaReaderBgIncrInit(void *pCtx){ @@ -87845,8 +98788,8 @@ static void *vdbePmaReaderBgIncrInit(void *pCtx){ ** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes ** the vdbePmaReaderIncrMergeInit() function with the parameters passed to ** this routine to initialize the incremental merge. -** -** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1), +** +** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1), ** then a background thread is launched to call vdbePmaReaderIncrMergeInit(). ** Or, if the IncrMerger is single threaded, the same function is called ** using the current thread. @@ -87876,7 +98819,7 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){ ** to NULL and return an SQLite error code. ** ** When this function is called, *piOffset is set to the offset of the -** first PMA to read from pTask->file. Assuming no error occurs, it is +** first PMA to read from pTask->file. Assuming no error occurs, it is ** set to the offset immediately following the last byte of the last ** PMA before returning. If an error does occur, then the final value of ** *piOffset is undefined. @@ -87986,12 +98929,12 @@ static int vdbeSorterAddToTree( /* ** This function is called as part of a SorterRewind() operation on a sorter ** that has already written two or more level-0 PMAs to one or more temp -** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that +** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that ** can be used to incrementally merge all PMAs on disk. ** ** If successful, SQLITE_OK is returned and *ppOut set to point to the ** MergeEngine object at the root of the tree before returning. Or, if an -** error occurs, an SQLite error code is returned and the final value +** error occurs, an SQLite error code is returned and the final value ** of *ppOut is undefined. */ static int vdbeSorterMergeTreeBuild( @@ -88003,8 +98946,8 @@ static int vdbeSorterMergeTreeBuild( int iTask; #if SQLITE_MAX_WORKER_THREADS>0 - /* If the sorter uses more than one task, then create the top-level - ** MergeEngine here. This MergeEngine will read data from exactly + /* If the sorter uses more than one task, then create the top-level + ** MergeEngine here. This MergeEngine will read data from exactly ** one PmaReader per sub-task. */ assert( pSorter->bUseThreads || pSorter->nTask==1 ); if( pSorter->nTask>1 ){ @@ -88113,7 +99056,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ } for(iTask=0; rc==SQLITE_OK && iTasknTask; iTask++){ /* Check that: - ** + ** ** a) The incremental merge object is configured to use the ** right task, and ** b) If it is using task (nTask-1), it is configured to run @@ -88176,7 +99119,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ return rc; } - /* Write the current in-memory list to a PMA. When the VdbeSorterWrite() + /* Write the current in-memory list to a PMA. When the VdbeSorterWrite() ** function flushes the contents of memory to disk, it immediately always ** creates a new list consisting of a single key immediately afterwards. ** So the list is never empty at this point. */ @@ -88188,7 +99131,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ vdbeSorterRewindDebug("rewind"); - /* Assuming no errors have occurred, set up a merger structure to + /* Assuming no errors have occurred, set up a merger structure to ** incrementally read and merge all remaining PMAs. */ assert( pSorter->pReader==0 ); if( rc==SQLITE_OK ){ @@ -88201,9 +99144,13 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ } /* -** Advance to the next element in the sorter. +** Advance to the next element in the sorter. Return value: +** +** SQLITE_OK success +** SQLITE_DONE end of data +** otherwise some kind of error. */ -SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ +SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){ VdbeSorter *pSorter; int rc; /* Return code */ @@ -88217,27 +99164,28 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in #if SQLITE_MAX_WORKER_THREADS>0 if( pSorter->bUseThreads ){ rc = vdbePmaReaderNext(pSorter->pReader); - *pbEof = (pSorter->pReader->pFd==0); + if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE; }else #endif /*if( !pSorter->bUseThreads )*/ { + int res = 0; assert( pSorter->pMerger!=0 ); assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); - rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); + rc = vdbeMergeEngineStep(pSorter->pMerger, &res); + if( rc==SQLITE_OK && res ) rc = SQLITE_DONE; } }else{ SorterRecord *pFree = pSorter->list.pList; pSorter->list.pList = pFree->u.pNext; pFree->u.pNext = 0; if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); - *pbEof = !pSorter->list.pList; - rc = SQLITE_OK; + rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE; } return rc; } /* -** Return a pointer to a buffer owned by the sorter that contains the +** Return a pointer to a buffer owned by the sorter that contains the ** current key. */ static void *vdbeSorterRowkey( @@ -88337,6 +99285,433 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare( } /************** End of vdbesort.c ********************************************/ +/************** Begin file vdbevtab.c ****************************************/ +/* +** 2020-03-23 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file implements virtual-tables for examining the bytecode content +** of a prepared statement. +*/ +/* #include "sqliteInt.h" */ +#if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE) +/* #include "vdbeInt.h" */ + +/* An instance of the bytecode() table-valued function. +*/ +typedef struct bytecodevtab bytecodevtab; +struct bytecodevtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; /* Database connection */ + int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */ +}; + +/* A cursor for scanning through the bytecode +*/ +typedef struct bytecodevtab_cursor bytecodevtab_cursor; +struct bytecodevtab_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */ + int iRowid; /* The rowid of the output table */ + int iAddr; /* Address */ + int needFinalize; /* Cursors owns pStmt and must finalize it */ + int showSubprograms; /* Provide a listing of subprograms */ + Op *aOp; /* Operand array */ + char *zP4; /* Rendered P4 value */ + const char *zType; /* tables_used.type */ + const char *zSchema; /* tables_used.schema */ + const char *zName; /* tables_used.name */ + Mem sub; /* Subprograms */ +}; + +/* +** Create a new bytecode() table-valued function. +*/ +static int bytecodevtabConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + bytecodevtab *pNew; + int rc; + int isTabUsed = pAux!=0; + const char *azSchema[2] = { + /* bytecode() schema */ + "CREATE TABLE x(" + "addr INT," + "opcode TEXT," + "p1 INT," + "p2 INT," + "p3 INT," + "p4 TEXT," + "p5 INT," + "comment TEXT," + "subprog TEXT," + "stmt HIDDEN" + ");", + + /* Tables_used() schema */ + "CREATE TABLE x(" + "type TEXT," + "schema TEXT," + "name TEXT," + "wr INT," + "subprog TEXT," + "stmt HIDDEN" + ");" + }; + + rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]); + if( rc==SQLITE_OK ){ + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + pNew->db = db; + pNew->bTablesUsed = isTabUsed*2; + } + return rc; +} + +/* +** This method is the destructor for bytecodevtab objects. +*/ +static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){ + bytecodevtab *p = (bytecodevtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Constructor for a new bytecodevtab_cursor object. +*/ +static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + bytecodevtab *pVTab = (bytecodevtab*)p; + bytecodevtab_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1); + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Clear all internal content from a bytecodevtab cursor. +*/ +static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){ + sqlite3_free(pCur->zP4); + pCur->zP4 = 0; + sqlite3VdbeMemRelease(&pCur->sub); + sqlite3VdbeMemSetNull(&pCur->sub); + if( pCur->needFinalize ){ + sqlite3_finalize(pCur->pStmt); + } + pCur->pStmt = 0; + pCur->needFinalize = 0; + pCur->zType = 0; + pCur->zSchema = 0; + pCur->zName = 0; +} + +/* +** Destructor for a bytecodevtab_cursor. +*/ +static int bytecodevtabClose(sqlite3_vtab_cursor *cur){ + bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; + bytecodevtabCursorClear(pCur); + sqlite3_free(pCur); + return SQLITE_OK; +} + + +/* +** Advance a bytecodevtab_cursor to its next row of output. +*/ +static int bytecodevtabNext(sqlite3_vtab_cursor *cur){ + bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; + bytecodevtab *pTab = (bytecodevtab*)cur->pVtab; + int rc; + if( pCur->zP4 ){ + sqlite3_free(pCur->zP4); + pCur->zP4 = 0; + } + if( pCur->zName ){ + pCur->zName = 0; + pCur->zType = 0; + pCur->zSchema = 0; + } + rc = sqlite3VdbeNextOpcode( + (Vdbe*)pCur->pStmt, + pCur->showSubprograms ? &pCur->sub : 0, + pTab->bTablesUsed, + &pCur->iRowid, + &pCur->iAddr, + &pCur->aOp); + if( rc!=SQLITE_OK ){ + sqlite3VdbeMemSetNull(&pCur->sub); + pCur->aOp = 0; + } + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int bytecodevtabEof(sqlite3_vtab_cursor *cur){ + bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; + return pCur->aOp==0; +} + +/* +** Return values of columns for the row at which the bytecodevtab_cursor +** is currently pointing. +*/ +static int bytecodevtabColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; + bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab; + Op *pOp = pCur->aOp + pCur->iAddr; + if( pVTab->bTablesUsed ){ + if( i==4 ){ + i = 8; + }else{ + if( i<=2 && pCur->zType==0 ){ + Schema *pSchema; + HashElem *k; + int iDb = pOp->p3; + Pgno iRoot = (Pgno)pOp->p2; + sqlite3 *db = pVTab->db; + pSchema = db->aDb[iDb].pSchema; + pCur->zSchema = db->aDb[iDb].zDbSName; + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + Table *pTab = (Table*)sqliteHashData(k); + if( !IsVirtual(pTab) && pTab->tnum==iRoot ){ + pCur->zName = pTab->zName; + pCur->zType = "table"; + break; + } + } + if( pCur->zName==0 ){ + for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){ + Index *pIdx = (Index*)sqliteHashData(k); + if( pIdx->tnum==iRoot ){ + pCur->zName = pIdx->zName; + pCur->zType = "index"; + } + } + } + } + i += 10; + } + } + switch( i ){ + case 0: /* addr */ + sqlite3_result_int(ctx, pCur->iAddr); + break; + case 1: /* opcode */ + sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode), + -1, SQLITE_STATIC); + break; + case 2: /* p1 */ + sqlite3_result_int(ctx, pOp->p1); + break; + case 3: /* p2 */ + sqlite3_result_int(ctx, pOp->p2); + break; + case 4: /* p3 */ + sqlite3_result_int(ctx, pOp->p3); + break; + case 5: /* p4 */ + case 7: /* comment */ + if( pCur->zP4==0 ){ + pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp); + } + if( i==5 ){ + sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC); + }else{ +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4); + sqlite3_result_text(ctx, zCom, -1, sqlite3_free); +#endif + } + break; + case 6: /* p5 */ + sqlite3_result_int(ctx, pOp->p5); + break; + case 8: { /* subprog */ + Op *aOp = pCur->aOp; + assert( aOp[0].opcode==OP_Init ); + assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 ); + if( pCur->iRowid==pCur->iAddr+1 ){ + break; /* Result is NULL for the main program */ + }else if( aOp[0].p4.z!=0 ){ + sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC); + }else{ + sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC); + } + break; + } + case 10: /* tables_used.type */ + sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC); + break; + case 11: /* tables_used.schema */ + sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC); + break; + case 12: /* tables_used.name */ + sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC); + break; + case 13: /* tables_used.wr */ + sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite); + break; + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; +} + +/* +** Initialize a cursor. +** +** idxNum==0 means show all subprograms +** idxNum==1 means show only the main bytecode and omit subprograms. +*/ +static int bytecodevtabFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor; + bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab; + int rc = SQLITE_OK; + + bytecodevtabCursorClear(pCur); + pCur->iRowid = 0; + pCur->iAddr = 0; + pCur->showSubprograms = idxNum==0; + assert( argc==1 ); + if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){ + const char *zSql = (const char*)sqlite3_value_text(argv[0]); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0); + pCur->needFinalize = 1; + } + }else{ + pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer"); + } + if( pCur->pStmt==0 ){ + pVTab->base.zErrMsg = sqlite3_mprintf( + "argument to %s() is not a valid SQL statement", + pVTab->bTablesUsed ? "tables_used" : "bytecode" + ); + rc = SQLITE_ERROR; + }else{ + bytecodevtabNext(pVtabCursor); + } + return rc; +} + +/* +** We must have a single stmt=? constraint that will be passed through +** into the xFilter method. If there is no valid stmt=? constraint, +** then return an SQLITE_CONSTRAINT error. +*/ +static int bytecodevtabBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + int i; + int rc = SQLITE_CONSTRAINT; + struct sqlite3_index_constraint *p; + bytecodevtab *pVTab = (bytecodevtab*)tab; + int iBaseCol = pVTab->bTablesUsed ? 4 : 8; + pIdxInfo->estimatedCost = (double)100; + pIdxInfo->estimatedRows = 100; + pIdxInfo->idxNum = 0; + for(i=0, p=pIdxInfo->aConstraint; inConstraint; i++, p++){ + if( p->usable==0 ) continue; + if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){ + rc = SQLITE_OK; + pIdxInfo->aConstraintUsage[i].omit = 1; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + } + if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){ + pIdxInfo->aConstraintUsage[i].omit = 1; + pIdxInfo->idxNum = 1; + } + } + return rc; +} + +/* +** This following structure defines all the methods for the +** virtual table. +*/ +static sqlite3_module bytecodevtabModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ bytecodevtabConnect, + /* xBestIndex */ bytecodevtabBestIndex, + /* xDisconnect */ bytecodevtabDisconnect, + /* xDestroy */ 0, + /* xOpen */ bytecodevtabOpen, + /* xClose */ bytecodevtabClose, + /* xFilter */ bytecodevtabFilter, + /* xNext */ bytecodevtabNext, + /* xEof */ bytecodevtabEof, + /* xColumn */ bytecodevtabColumn, + /* xRowid */ bytecodevtabRowid, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 +}; + + +SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ + int rc; + rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db); + } + return rc; +} +#elif defined(SQLITE_ENABLE_BYTECODE_VTAB) +SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; } +#endif /* SQLITE_ENABLE_BYTECODE_VTAB */ + +/************** End of vdbevtab.c ********************************************/ /************** Begin file memjournal.c **************************************/ /* ** 2008 October 7 @@ -88410,7 +99785,6 @@ struct MemJournal { int nChunkSize; /* In-memory chunk-size */ int nSpill; /* Bytes of data before flushing */ - int nSize; /* Bytes of data currently in memory */ FileChunk *pFirst; /* Head of in-memory chunk-list */ FilePoint endpoint; /* Pointer to the end of the file */ FilePoint readpoint; /* Pointer to the end of the last xRead() */ @@ -88436,17 +99810,13 @@ static int memjrnlRead( int iChunkOffset; FileChunk *pChunk; -#ifdef SQLITE_ENABLE_ATOMIC_WRITE if( (iAmt+iOfst)>p->endpoint.iOffset ){ return SQLITE_IOERR_SHORT_READ; } -#endif - - assert( (iAmt+iOfst)<=p->endpoint.iOffset ); assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 ); if( p->readpoint.iOffset!=iOfst || iOfst==0 ){ sqlite3_int64 iOff = 0; - for(pChunk=p->pFirst; + for(pChunk=p->pFirst; ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst; pChunk=pChunk->pNext ){ @@ -88475,14 +99845,13 @@ static int memjrnlRead( /* ** Free the list of FileChunk structures headed at MemJournal.pFirst. */ -static void memjrnlFreeChunks(MemJournal *p){ +static void memjrnlFreeChunks(FileChunk *pFirst){ FileChunk *pIter; FileChunk *pNext; - for(pIter=p->pFirst; pIter; pIter=pNext){ + for(pIter=pFirst; pIter; pIter=pNext){ pNext = pIter->pNext; sqlite3_free(pIter); - } - p->pFirst = 0; + } } /* @@ -88509,7 +99878,7 @@ static int memjrnlCreateFile(MemJournal *p){ } if( rc==SQLITE_OK ){ /* No error has occurred. Free the in-memory buffers. */ - memjrnlFreeChunks(©); + memjrnlFreeChunks(copy.pFirst); } } if( rc!=SQLITE_OK ){ @@ -88524,6 +99893,9 @@ static int memjrnlCreateFile(MemJournal *p){ } +/* Forward reference */ +static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size); + /* ** Write data to the file. */ @@ -88553,22 +99925,21 @@ static int memjrnlWrite( ** access writes are not required. The only exception to this is when ** the in-memory journal is being used by a connection using the ** atomic-write optimization. In this case the first 28 bytes of the - ** journal file may be written as part of committing the transaction. */ - assert( iOfst==p->endpoint.iOffset || iOfst==0 ); -#ifdef SQLITE_ENABLE_ATOMIC_WRITE + ** journal file may be written as part of committing the transaction. */ + assert( iOfst<=p->endpoint.iOffset ); + if( iOfst>0 && iOfst!=p->endpoint.iOffset ){ + memjrnlTruncate(pJfd, iOfst); + } if( iOfst==0 && p->pFirst ){ assert( p->nChunkSize>iAmt ); memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt); - }else -#else - assert( iOfst>0 || p->pFirst==0 ); -#endif - { + }else{ while( nWrite>0 ){ FileChunk *pChunk = p->endpoint.pChunk; int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize); int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset); + assert( pChunk!=0 || iChunkOffset==0 ); if( iChunkOffset==0 ){ /* New chunk is required to extend the file. */ FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize)); @@ -88583,15 +99954,15 @@ static int memjrnlWrite( assert( !p->pFirst ); p->pFirst = pNew; } - p->endpoint.pChunk = pNew; + pChunk = p->endpoint.pChunk = pNew; } - memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace); + assert( pChunk!=0 ); + memcpy((u8*)pChunk->zChunk + iChunkOffset, zWrite, iSpace); zWrite += iSpace; nWrite -= iSpace; p->endpoint.iOffset += iSpace; } - p->nSize = iAmt + iOfst; } } @@ -88599,19 +99970,29 @@ static int memjrnlWrite( } /* -** Truncate the file. -** -** If the journal file is already on disk, truncate it there. Or, if it -** is still in main memory but is being truncated to zero bytes in size, -** ignore +** Truncate the in-memory file. */ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ MemJournal *p = (MemJournal *)pJfd; - if( ALWAYS(size==0) ){ - memjrnlFreeChunks(p); - p->nSize = 0; - p->endpoint.pChunk = 0; - p->endpoint.iOffset = 0; + assert( p->endpoint.pChunk==0 || p->endpoint.pChunk->pNext==0 ); + if( sizeendpoint.iOffset ){ + FileChunk *pIter = 0; + if( size==0 ){ + memjrnlFreeChunks(p->pFirst); + p->pFirst = 0; + }else{ + i64 iOff = p->nChunkSize; + for(pIter=p->pFirst; ALWAYS(pIter) && iOffpNext){ + iOff += p->nChunkSize; + } + if( ALWAYS(pIter) ){ + memjrnlFreeChunks(pIter->pNext); + pIter->pNext = 0; + } + } + + p->endpoint.pChunk = pIter; + p->endpoint.iOffset = size; p->readpoint.pChunk = 0; p->readpoint.iOffset = 0; } @@ -88623,15 +100004,15 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ */ static int memjrnlClose(sqlite3_file *pJfd){ MemJournal *p = (MemJournal *)pJfd; - memjrnlFreeChunks(p); + memjrnlFreeChunks(p->pFirst); return SQLITE_OK; } /* ** Sync the file. ** -** If the real file has been created, call its xSync method. Otherwise, -** syncing an in-memory journal is a no-op. +** If the real file has been created, call its xSync method. Otherwise, +** syncing an in-memory journal is a no-op. */ static int memjrnlSync(sqlite3_file *pJfd, int flags){ UNUSED_PARAMETER2(pJfd, flags); @@ -88672,11 +100053,11 @@ static const struct sqlite3_io_methods MemJournalMethods = { 0 /* xUnfetch */ }; -/* -** Open a journal file. +/* +** Open a journal file. ** -** The behaviour of the journal file depends on the value of parameter -** nSpill. If nSpill is 0, then the journal file is always create and +** The behaviour of the journal file depends on the value of parameter +** nSpill. If nSpill is 0, then the journal file is always create and ** accessed using the underlying VFS. If nSpill is less than zero, then ** all content is always stored in main-memory. Finally, if nSpill is a ** positive value, then the journal file is initially created in-memory @@ -88709,7 +100090,7 @@ SQLITE_PRIVATE int sqlite3JournalOpen( assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) ); } - p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods; + pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods; p->nSpill = nSpill; p->flags = flags; p->zJournal = zName; @@ -88724,17 +100105,31 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){ sqlite3JournalOpen(0, 0, pJfd, 0, -1); } -#ifdef SQLITE_ENABLE_ATOMIC_WRITE +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) /* -** If the argument p points to a MemJournal structure that is not an +** If the argument p points to a MemJournal structure that is not an ** in-memory-only journal file (i.e. is one that was opened with a +ve -** nSpill parameter), and the underlying file has not yet been created, -** create it now. +** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying +** file has not yet been created, create it now. */ -SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){ +SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){ int rc = SQLITE_OK; - if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){ - rc = memjrnlCreateFile((MemJournal*)p); + MemJournal *p = (MemJournal*)pJfd; + if( pJfd->pMethods==&MemJournalMethods && ( +#ifdef SQLITE_ENABLE_ATOMIC_WRITE + p->nSpill>0 +#else + /* While this appears to not be possible without ATOMIC_WRITE, the + ** paths are complex, so it seems prudent to leave the test in as + ** a NEVER(), in case our analysis is subtly flawed. */ + NEVER(p->nSpill>0) +#endif +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE + || (p->flags & SQLITE_OPEN_MAIN_JOURNAL) +#endif + )){ + rc = memjrnlCreateFile(p); } return rc; } @@ -88749,7 +100144,7 @@ SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){ return p->pMethods==&MemJournalMethods; } -/* +/* ** Return the number of bytes required to store a JournalFile that uses vfs ** pVfs to create the underlying on-disk files. */ @@ -88778,6 +100173,31 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ /* #include */ +#if !defined(SQLITE_OMIT_WINDOWFUNC) +/* +** Walk all expressions linked into the list of Window objects passed +** as the second argument. +*/ +static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){ + Window *pWin; + for(pWin=pList; pWin; pWin=pWin->pNextWin){ + int rc; + rc = sqlite3WalkExprList(pWalker, pWin->pOrderBy); + if( rc ) return WRC_Abort; + rc = sqlite3WalkExprList(pWalker, pWin->pPartition); + if( rc ) return WRC_Abort; + rc = sqlite3WalkExpr(pWalker, pWin->pFilter); + if( rc ) return WRC_Abort; + rc = sqlite3WalkExpr(pWalker, pWin->pStart); + if( rc ) return WRC_Abort; + rc = sqlite3WalkExpr(pWalker, pWin->pEnd); + if( rc ) return WRC_Abort; + if( bOneOnly ) break; + } + return WRC_Continue; +} +#endif + /* ** Walk an expression tree. Invoke the callback once for each node ** of the expression, while descending. (In other words, the callback @@ -88788,11 +100208,11 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){ ** ** WRC_Continue Continue descending down the tree. ** -** WRC_Prune Do not descend into child nodes. But allow +** WRC_Prune Do not descend into child nodes, but allow ** the walk to continue with sibling nodes. ** ** WRC_Abort Do no more callbacks. Unwind the stack and -** return the top-level walk call. +** return from the top-level walk call. ** ** The return value from this routine is WRC_Abort to abandon the tree walk ** and WRC_Continue to continue. @@ -88801,16 +100221,31 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); - rc = pWalker->xExprCallback(pWalker, pExpr); - if( rc || ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ - return rc & WRC_Abort; - } - if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; - if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; - }else if( pExpr->x.pList ){ - if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + while(1){ + rc = pWalker->xExprCallback(pWalker, pExpr); + if( rc ) return rc & WRC_Abort; + if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ + assert( pExpr->x.pList==0 || pExpr->pRight==0 ); + if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; + if( pExpr->pRight ){ + assert( !ExprHasProperty(pExpr, EP_WinFunc) ); + pExpr = pExpr->pRight; + continue; + }else if( ExprUseXSelect(pExpr) ){ + assert( !ExprHasProperty(pExpr, EP_WinFunc) ); + if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; + }else{ + if( pExpr->x.pList ){ + if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; + } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + if( walkWindowList(pWalker, pExpr->y.pWin, 1) ) return WRC_Abort; + } +#endif + } + } + break; } return WRC_Continue; } @@ -88833,6 +100268,16 @@ SQLITE_PRIVATE int sqlite3WalkExprList(Walker *pWalker, ExprList *p){ return WRC_Continue; } +/* +** This is a no-op callback for Walker->xSelectCallback2. If this +** callback is set, then the Select->pWinDefn list is traversed. +*/ +SQLITE_PRIVATE void sqlite3WalkWinDefnDummyCallback(Walker *pWalker, Select *p){ + UNUSED_PARAMETER(pWalker); + UNUSED_PARAMETER(p); + /* No-op */ +} + /* ** Walk all expressions associated with SELECT statement p. Do ** not invoke the SELECT callback on p, but do (of course) invoke @@ -88846,7 +100291,22 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort; - if( sqlite3WalkExpr(pWalker, p->pOffset) ) return WRC_Abort; +#if !defined(SQLITE_OMIT_WINDOWFUNC) + if( p->pWinDefn ){ + Parse *pParse; + if( pWalker->xSelectCallback2==sqlite3WalkWinDefnDummyCallback + || ((pParse = pWalker->pParse)!=0 && IN_RENAME_OBJECT) +#ifndef SQLITE_OMIT_CTE + || pWalker->xSelectCallback2==sqlite3SelectPopWith +#endif + ){ + /* The following may return WRC_Abort if there are unresolvable + ** symbols (e.g. a table that does not exist) in a window definition. */ + int rc = walkWindowList(pWalker, p->pWinDefn, 0); + return rc; + } + } +#endif return WRC_Continue; } @@ -88854,18 +100314,18 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){ ** Walk the parse trees associated with all subqueries in the ** FROM clause of SELECT statement p. Do not invoke the select ** callback on p, but do invoke it on each FROM clause subquery -** and on any subqueries further down in the tree. Return +** and on any subqueries further down in the tree. Return ** WRC_Abort or WRC_Continue; */ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ SrcList *pSrc; int i; - struct SrcList_item *pItem; + SrcItem *pItem; pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){ + if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } if( pItem->fg.isTabFunc @@ -88876,17 +100336,18 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ } } return WRC_Continue; -} +} /* ** Call sqlite3WalkExpr() for every expression in Select statement p. ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and -** on the compound select chain, p->pPrior. +** on the compound select chain, p->pPrior. ** ** If it is not NULL, the xSelectCallback() callback is invoked before ** the walk of the expressions and FROM clause. The xSelectCallback2() -** method, if it is not NULL, is invoked following the walk of the -** expressions and FROM clause. +** method is invoked following the walk of the expressions and FROM clause, +** but only if both xSelectCallback and xSelectCallback2 are both non-NULL +** and if the expressions and FROM clause both return WRC_Continue; ** ** Return WRC_Continue under normal conditions. Return WRC_Abort if ** there is an abort request. @@ -88896,29 +100357,59 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){ */ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ int rc; - if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){ - return WRC_Continue; - } - rc = WRC_Continue; - pWalker->walkerDepth++; - while( p ){ - if( pWalker->xSelectCallback ){ - rc = pWalker->xSelectCallback(pWalker, p); - if( rc ) break; - } + if( p==0 ) return WRC_Continue; + if( pWalker->xSelectCallback==0 ) return WRC_Continue; + do{ + rc = pWalker->xSelectCallback(pWalker, p); + if( rc ) return rc & WRC_Abort; if( sqlite3WalkSelectExpr(pWalker, p) || sqlite3WalkSelectFrom(pWalker, p) ){ - pWalker->walkerDepth--; return WRC_Abort; } if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; - } + }while( p!=0 ); + return WRC_Continue; +} + +/* Increase the walkerDepth when entering a subquery, and +** descrease when leaving the subquery. +*/ +SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pSelect); + pWalker->walkerDepth++; + return WRC_Continue; +} +SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){ + UNUSED_PARAMETER(pSelect); pWalker->walkerDepth--; - return rc & WRC_Abort; +} + + +/* +** No-op routine for the parse-tree walker. +** +** When this routine is the Walker.xExprCallback then expression trees +** are walked without any actions being taken at each node. Presumably, +** when this routine is used for Walker.xExprCallback then +** Walker.xSelectCallback is set to do something useful for every +** subquery in the parser tree. +*/ +SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + return WRC_Continue; +} + +/* +** No-op routine for the parse-tree walker for SELECT statements. +** subquery in the parser tree. +*/ +SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){ + UNUSED_PARAMETER2(NotUsed, NotUsed2); + return WRC_Continue; } /************** End of walker.c **********************************************/ @@ -88941,6 +100432,11 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ */ /* #include "sqliteInt.h" */ +/* +** Magic table number to mean the EXCLUDED table in an UPSERT statement. +*/ +#define EXCLUDED_TABLE_NUMBER 2 + /* ** Walk the expression tree pExpr and increase the aggregate function ** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node. @@ -88949,6 +100445,8 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){ ** ** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..) ** is a helper function - a callback for the tree walker. +** +** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c */ static int incrAggDepth(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n; @@ -88988,7 +100486,6 @@ static void resolveAlias( ExprList *pEList, /* A result set */ int iCol, /* A column in the result set. 0..pEList->nExpr-1 */ Expr *pExpr, /* Transform this into an alias to the result set */ - const char *zType, /* "GROUP" or "ORDER" or "" */ int nSubquery /* Number of subqueries that the label is moving */ ){ Expr *pOrig; /* The iCol-th column of the result set */ @@ -89000,29 +100497,38 @@ static void resolveAlias( assert( pOrig!=0 ); db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); - if( pDup==0 ) return; - if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); - if( pExpr->op==TK_COLLATE ){ - pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); - } - ExprSetProperty(pDup, EP_Alias); + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDup); + pDup = 0; + }else{ + incrAggFunctionDepth(pDup, nSubquery); + if( pExpr->op==TK_COLLATE ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); + } - /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This - ** prevents ExprDelete() from deleting the Expr structure itself, - ** allowing it to be repopulated by the memcpy() on the following line. - ** The pExpr->u.zToken might point into memory that will be freed by the - ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to - ** make a copy of the token before doing the sqlite3DbFree(). - */ - ExprSetProperty(pExpr, EP_Static); - sqlite3ExprDelete(db, pExpr); - memcpy(pExpr, pDup, sizeof(*pExpr)); - if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ - assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); - pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); - pExpr->flags |= EP_MemToken; + /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This + ** prevents ExprDelete() from deleting the Expr structure itself, + ** allowing it to be repopulated by the memcpy() on the following line. + ** The pExpr->u.zToken might point into memory that will be freed by the + ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to + ** make a copy of the token before doing the sqlite3DbFree(). + */ + ExprSetProperty(pExpr, EP_Static); + sqlite3ExprDelete(db, pExpr); + memcpy(pExpr, pDup, sizeof(*pExpr)); + if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ + assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); + pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); + pExpr->flags |= EP_MemToken; + } + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + if( ALWAYS(pExpr->y.pWin!=0) ){ + pExpr->y.pWin->pOwner = pExpr; + } + } + sqlite3DbFree(db, pDup); } - sqlite3DbFree(db, pDup); } @@ -89049,13 +100555,16 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){ ** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will ** match anything. */ -SQLITE_PRIVATE int sqlite3MatchSpanName( - const char *zSpan, +SQLITE_PRIVATE int sqlite3MatchEName( + const struct ExprList_item *pItem, const char *zCol, const char *zTab, const char *zDb ){ int n; + const char *zSpan; + if( pItem->eEName!=ENAME_TAB ) return 0; + zSpan = pItem->zEName; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){ return 0; @@ -89072,9 +100581,52 @@ SQLITE_PRIVATE int sqlite3MatchSpanName( return 1; } +/* +** Return TRUE if the double-quoted string mis-feature should be supported. +*/ +static int areDoubleQuotedStringsEnabled(sqlite3 *db, NameContext *pTopNC){ + if( db->init.busy ) return 1; /* Always support for legacy schemas */ + if( pTopNC->ncFlags & NC_IsDDL ){ + /* Currently parsing a DDL statement */ + if( sqlite3WritableSchema(db) && (db->flags & SQLITE_DqsDML)!=0 ){ + return 1; + } + return (db->flags & SQLITE_DqsDDL)!=0; + }else{ + /* Currently parsing a DML statement */ + return (db->flags & SQLITE_DqsDML)!=0; + } +} + +/* +** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN. +** return the appropriate colUsed mask. +*/ +SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr *pExpr){ + int n; + Table *pExTab; + + n = pExpr->iColumn; + assert( ExprUseYTab(pExpr) ); + pExTab = pExpr->y.pTab; + assert( pExTab!=0 ); + if( (pExTab->tabFlags & TF_HasGenerated)!=0 + && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 + ){ + testcase( pExTab->nCol==BMS-1 ); + testcase( pExTab->nCol==BMS ); + return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1; + }else{ + testcase( n==BMS-1 ); + testcase( n==BMS ); + if( n>=BMS ) n = BMS-1; + return ((Bitmask)1)<iTable Set to the cursor number for the table obtained ** from pSrcList. -** pExpr->pTab Points to the Table structure of X.Y (even if +** pExpr->y.pTab Points to the Table structure of X.Y (even if ** X and/or Y are implied.) ** pExpr->iColumn Set to the column number within the table. ** pExpr->op Set to TK_COLUMN. @@ -89112,11 +100664,11 @@ static int lookupName( int cntTab = 0; /* Number of matching table names */ int nSubquery = 0; /* How many levels of subquery */ sqlite3 *db = pParse->db; /* The database connection */ - struct SrcList_item *pItem; /* Use for looping over pSrcList items */ - struct SrcList_item *pMatch = 0; /* The matching pSrcList item */ + SrcItem *pItem; /* Use for looping over pSrcList items */ + SrcItem *pMatch = 0; /* The matching pSrcList item */ NameContext *pTopNC = pNC; /* First namecontext in the list */ Schema *pSchema = 0; /* Schema of the expression */ - int isTrigger = 0; /* True if resolved to a trigger column */ + int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */ Table *pTab = 0; /* Table hold the row */ Column *pCol; /* A column of pTab */ @@ -89126,7 +100678,6 @@ static int lookupName( /* Initialize the node to no-match */ pExpr->iTable = -1; - pExpr->pTab = 0; ExprSetVVAProperty(pExpr, EP_NoReduce); /* Translate the schema name in zDb into a pointer to the corresponding @@ -89150,24 +100701,32 @@ static int lookupName( break; } } + if( i==db->nDb && sqlite3StrICmp("main", zDb)==0 ){ + /* This branch is taken when the main database has been renamed + ** using SQLITE_DBCONFIG_MAINDBNAME. */ + pSchema = db->aDb[0].pSchema; + zDb = db->aDb[0].zDbSName; + } } } /* Start at the inner-most context and move outward until a match is found */ - while( pNC && cnt==0 ){ + assert( pNC && cnt==0 ); + do{ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ + u8 hCol; pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); - assert( pTab->nCol>0 ); + assert( pTab->nCol>0 || pParse->nErr ); if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ int hit = 0; pEList = pItem->pSelect->pEList; for(j=0; jnExpr; j++){ - if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){ + if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){ cnt++; cntTab = 2; pMatch = pItem; @@ -89177,8 +100736,9 @@ static int lookupName( } if( hit || zTab==0 ) continue; } - if( zDb && pTab->pSchema!=pSchema ){ - continue; + if( zDb ){ + if( pTab->pSchema!=pSchema ) continue; + if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue; } if( zTab ){ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; @@ -89186,14 +100746,18 @@ static int lookupName( if( sqlite3StrICmp(zTabName, zTab)!=0 ){ continue; } + assert( ExprUseYTab(pExpr) ); + if( IN_RENAME_OBJECT && pItem->zAlias ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); + } } - if( 0==(cntTab++) ){ - pMatch = pItem; - } + hCol = sqlite3StrIHash(zCol); for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ - if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ + if( pCol->hName==hCol + && sqlite3StrICmp(pCol->zCnName, zCol)==0 + ){ /* If there has been exactly one prior match and this match - ** is for the right-hand table of a NATURAL JOIN or is in a + ** is for the right-hand table of a NATURAL JOIN or is in a ** USING clause, then skip this match. */ if( cnt==1 ){ @@ -89207,42 +100771,71 @@ static int lookupName( break; } } + if( 0==cnt && VisibleRowid(pTab) ){ + cntTab++; + pMatch = pItem; + } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; - pExpr->pTab = pMatch->pTab; + assert( ExprUseYTab(pExpr) ); + pExpr->y.pTab = pMatch->pTab; /* RIGHT JOIN not (yet) supported */ assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } - pSchema = pExpr->pTab->pSchema; + pSchema = pExpr->y.pTab->pSchema; } } /* if( pSrcList ) */ -#ifndef SQLITE_OMIT_TRIGGER - /* If we have not already resolved the name, then maybe - ** it is a new.* or old.* trigger argument reference +#if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) + /* If we have not already resolved the name, then maybe + ** it is a new.* or old.* trigger argument reference. Or + ** maybe it is an excluded.* from an upsert. Or maybe it is + ** a reference in the RETURNING clause to a table being modified. */ - if( zDb==0 && zTab!=0 && cntTab==0 && pParse->pTriggerTab!=0 ){ - int op = pParse->eTriggerOp; - assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); - if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){ - pExpr->iTable = 1; - pTab = pParse->pTriggerTab; - }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ - pExpr->iTable = 0; - pTab = pParse->pTriggerTab; - }else{ - pTab = 0; + if( cnt==0 && zDb==0 ){ + pTab = 0; +#ifndef SQLITE_OMIT_TRIGGER + if( pParse->pTriggerTab!=0 ){ + int op = pParse->eTriggerOp; + assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT ); + if( pParse->bReturning ){ + if( (pNC->ncFlags & NC_UBaseReg)!=0 + && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0) + ){ + pExpr->iTable = op!=TK_DELETE; + pTab = pParse->pTriggerTab; + } + }else if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){ + pExpr->iTable = 1; + pTab = pParse->pTriggerTab; + }else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){ + pExpr->iTable = 0; + pTab = pParse->pTriggerTab; + } } +#endif /* SQLITE_OMIT_TRIGGER */ +#ifndef SQLITE_OMIT_UPSERT + if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ + Upsert *pUpsert = pNC->uNC.pUpsert; + if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ + pTab = pUpsert->pUpsertSrc->a[0].pTab; + pExpr->iTable = EXCLUDED_TABLE_NUMBER; + } + } +#endif /* SQLITE_OMIT_UPSERT */ - if( pTab ){ + if( pTab ){ int iCol; + u8 hCol = sqlite3StrIHash(zCol); pSchema = pTab->pSchema; cntTab++; for(iCol=0, pCol=pTab->aCol; iColnCol; iCol++, pCol++){ - if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ + if( pCol->hName==hCol + && sqlite3StrICmp(pCol->zCnName, zCol)==0 + ){ if( iCol==pTab->iPKey ){ iCol = -1; } @@ -89255,24 +100848,52 @@ static int lookupName( } if( iColnCol ){ cnt++; - if( iCol<0 ){ - pExpr->affinity = SQLITE_AFF_INTEGER; - }else if( pExpr->iTable==0 ){ - testcase( iCol==31 ); - testcase( iCol==32 ); - pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<iTable==EXCLUDED_TABLE_NUMBER ){ + testcase( iCol==(-1) ); + assert( ExprUseYTab(pExpr) ); + if( IN_RENAME_OBJECT ){ + pExpr->iColumn = iCol; + pExpr->y.pTab = pTab; + eNewExprOp = TK_COLUMN; + }else{ + pExpr->iTable = pNC->uNC.pUpsert->regData + + sqlite3TableColumnToStorage(pTab, iCol); + eNewExprOp = TK_REGISTER; + } + }else +#endif /* SQLITE_OMIT_UPSERT */ + { + assert( ExprUseYTab(pExpr) ); + pExpr->y.pTab = pTab; + if( pParse->bReturning ){ + eNewExprOp = TK_REGISTER; + pExpr->op2 = TK_COLUMN; + pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable + + sqlite3TableColumnToStorage(pTab, iCol) + 1; + }else{ + pExpr->iColumn = (i16)iCol; + eNewExprOp = TK_TRIGGER; +#ifndef SQLITE_OMIT_TRIGGER + if( iCol<0 ){ + pExpr->affExpr = SQLITE_AFF_INTEGER; + }else if( pExpr->iTable==0 ){ + testcase( iCol==31 ); + testcase( iCol==32 ); + pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<iColumn = (i16)iCol; - pExpr->pTab = pTab; - isTrigger = 1; } } } -#endif /* !defined(SQLITE_OMIT_TRIGGER) */ +#endif /* !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) */ /* ** Perhaps the name is a reference to the ROWID @@ -89280,13 +100901,13 @@ static int lookupName( if( cnt==0 && cntTab==1 && pMatch - && (pNC->ncFlags & NC_IdxExpr)==0 + && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) - && VisibleRowid(pMatch->pTab) + && ALWAYS(VisibleRowid(pMatch->pTab)) ){ cnt = 1; pExpr->iColumn = -1; - pExpr->affinity = SQLITE_AFF_INTEGER; + pExpr->affExpr = SQLITE_AFF_INTEGER; } /* @@ -89307,43 +100928,56 @@ static int lookupName( ** is supported for backwards compatibility only. Hence, we issue a warning ** on sqlite3_log() whenever the capability is used. */ - if( (pEList = pNC->pEList)!=0 + if( cnt==0 + && (pNC->ncFlags & NC_UEList)!=0 && zTab==0 - && cnt==0 ){ + pEList = pNC->uNC.pEList; + assert( pEList!=0 ); for(j=0; jnExpr; j++){ - char *zAs = pEList->a[j].zName; - if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ + char *zAs = pEList->a[j].zEName; + if( pEList->a[j].eEName==ENAME_NAME + && sqlite3_stricmp(zAs, zCol)==0 + ){ Expr *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); - assert( pExpr->x.pList==0 ); - assert( pExpr->x.pSelect==0 ); + assert( ExprUseXList(pExpr)==0 || pExpr->x.pList==0 ); + assert( ExprUseXSelect(pExpr)==0 || pExpr->x.pSelect==0 ); pOrig = pEList->a[j].pExpr; if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){ sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); return WRC_Abort; } + if( ExprHasProperty(pOrig, EP_Win) + && ((pNC->ncFlags&NC_AllowWin)==0 || pNC!=pTopNC ) + ){ + sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs); + return WRC_Abort; + } if( sqlite3ExprVectorSize(pOrig)!=1 ){ sqlite3ErrorMsg(pParse, "row value misused"); return WRC_Abort; } - resolveAlias(pParse, pEList, j, pExpr, "", nSubquery); + resolveAlias(pParse, pEList, j, pExpr, nSubquery); cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); + } goto lookupname_end; } - } + } } /* Advance to the next name context. The loop will exit when either ** we have a match (cnt>0) or when we run out of name contexts. */ - if( cnt==0 ){ - pNC = pNC->pNext; - nSubquery++; - } - } + if( cnt ) break; + pNC = pNC->pNext; + nSubquery++; + }while( pNC ); + /* ** If X and Y are NULL (in other words if only the column name Z is @@ -89355,10 +100989,37 @@ static int lookupName( ** Because no reference was made to outer contexts, the pNC->nRef ** fields are not changed in any context. */ - if( cnt==0 && zTab==0 && ExprHasProperty(pExpr,EP_DblQuoted) ){ - pExpr->op = TK_STRING; - pExpr->pTab = 0; - return WRC_Prune; + if( cnt==0 && zTab==0 ){ + assert( pExpr->op==TK_ID ); + if( ExprHasProperty(pExpr,EP_DblQuoted) + && areDoubleQuotedStringsEnabled(db, pTopNC) + ){ + /* If a double-quoted identifier does not match any known column name, + ** then treat it as a string. + ** + ** This hack was added in the early days of SQLite in a misguided attempt + ** to be compatible with MySQL 3.x, which used double-quotes for strings. + ** I now sorely regret putting in this hack. The effect of this hack is + ** that misspelled identifier names are silently converted into strings + ** rather than causing an error, to the frustration of countless + ** programmers. To all those frustrated programmers, my apologies. + ** + ** Someday, I hope to get rid of this hack. Unfortunately there is + ** a huge amount of legacy SQL that uses it. So for now, we just + ** issue a warning. + */ + sqlite3_log(SQLITE_WARNING, + "double-quoted string literal: \"%w\"", zCol); +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol); +#endif + pExpr->op = TK_STRING; + memset(&pExpr->y, 0, sizeof(pExpr->y)); + return WRC_Prune; + } + if( sqlite3ExprIdToTrueFalse(pExpr) ){ + return WRC_Prune; + } } /* @@ -89375,39 +101036,49 @@ static int lookupName( }else{ sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol); } + sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); pParse->checkSchema = 1; - pTopNC->nErr++; + pTopNC->nNcErr++; } /* If a column from a table in pSrcList is referenced, then record ** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes - ** bit 0 to be set. Column 1 sets bit 1. And so forth. If the - ** column number is greater than the number of bits in the bitmask - ** then set the high-order bit of the bitmask. + ** bit 0 to be set. Column 1 sets bit 1. And so forth. Bit 63 is + ** set if the 63rd or any subsequent column is used. + ** + ** The colUsed mask is an optimization used to help determine if an + ** index is a covering index. The correct answer is still obtained + ** if the mask contains extra set bits. However, it is important to + ** avoid setting bits beyond the maximum column number of the table. + ** (See ticket [b92e5e8ec2cdbaa1]). + ** + ** If a generated column is referenced, set bits for every column + ** of the table. */ if( pExpr->iColumn>=0 && pMatch!=0 ){ - int n = pExpr->iColumn; - testcase( n==BMS-1 ); - if( n>=BMS ){ - n = BMS-1; - } - assert( pMatch->iCursor==pExpr->iTable ); - pMatch->colUsed |= ((Bitmask)1)<colUsed |= sqlite3ExprColUsed(pExpr); } /* Clean up and return */ - sqlite3ExprDelete(db, pExpr->pLeft); - pExpr->pLeft = 0; - sqlite3ExprDelete(db, pExpr->pRight); - pExpr->pRight = 0; - pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); + if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){ + sqlite3ExprDelete(db, pExpr->pLeft); + pExpr->pLeft = 0; + sqlite3ExprDelete(db, pExpr->pRight); + pExpr->pRight = 0; + } + pExpr->op = eNewExprOp; + ExprSetProperty(pExpr, EP_Leaf); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); - if( !ExprHasProperty(pExpr, EP_Alias) ){ +#ifndef SQLITE_OMIT_AUTHORIZATION + if( pParse->db->xAuth + && (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER) + ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } +#endif /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ @@ -89429,18 +101100,27 @@ static int lookupName( SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ - struct SrcList_item *pItem = &pSrc->a[iSrc]; - p->pTab = pItem->pTab; + SrcItem *pItem = &pSrc->a[iSrc]; + Table *pTab; + assert( ExprUseYTab(p) ); + pTab = p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; - if( p->pTab->iPKey==iCol ){ + if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; - testcase( iCol==BMS ); - testcase( iCol==BMS-1 ); - pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); + if( (pTab->tabFlags & TF_HasGenerated)!=0 + && (pTab->aCol[iCol].colFlags & COLFLAG_GENERATED)!=0 + ){ + testcase( pTab->nCol==63 ); + testcase( pTab->nCol==64 ); + pItem->colUsed = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1; + }else{ + testcase( iCol==BMS ); + testcase( iCol==BMS-1 ); + pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); + } } - ExprSetProperty(p, EP_Resolved); } return p; } @@ -89448,23 +101128,41 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr /* ** Report an error that an expression is not valid for some set of ** pNC->ncFlags values determined by validMask. -*/ -static void notValid( - Parse *pParse, /* Leave error message here */ - NameContext *pNC, /* The name context */ - const char *zMsg, /* Type of error */ - int validMask /* Set of contexts for which prohibited */ -){ - assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 ); - if( (pNC->ncFlags & validMask)!=0 ){ - const char *zIn = "partial index WHERE clauses"; - if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; +** +** static void notValid( +** Parse *pParse, // Leave error message here +** NameContext *pNC, // The name context +** const char *zMsg, // Type of error +** int validMask, // Set of contexts for which prohibited +** Expr *pExpr // Invalidate this expression on error +** ){...} +** +** As an optimization, since the conditional is almost always false +** (because errors are rare), the conditional is moved outside of the +** function call using a macro. +*/ +static void notValidImpl( + Parse *pParse, /* Leave error message here */ + NameContext *pNC, /* The name context */ + const char *zMsg, /* Type of error */ + Expr *pExpr, /* Invalidate this expression on error */ + Expr *pError /* Associate error with this expression */ +){ + const char *zIn = "partial index WHERE clauses"; + if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; #ifndef SQLITE_OMIT_CHECK - else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; + else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; #endif - sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); - } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns"; +#endif + sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); + if( pExpr ) pExpr->op = TK_NULL; + sqlite3RecordErrorOffsetOfExpr(pParse->db, pError); } +#define sqlite3ResolveNotValid(P,N,M,X,E,R) \ + assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \ + if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E,R); /* ** Expression p should encode a floating point value between 1.0 and 0.0. @@ -89474,6 +101172,7 @@ static void notValid( static int exprProbability(Expr *p){ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; + assert( !ExprHasProperty(p, EP_IntValue) ); sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); assert( r>=0.0 ); if( r>1.0 ) return -1; @@ -89500,8 +101199,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pParse = pNC->pParse; assert( pParse==pWalker->pParse ); - if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune; - ExprSetProperty(pExpr, EP_Resolved); #ifndef NDEBUG if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ SrcList *pSrcList = pNC->pSrcList; @@ -89513,53 +101210,112 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif switch( pExpr->op ){ -#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) /* The special operator TK_ROW means use the rowid for the first ** column in the FROM clause. This is used by the LIMIT and ORDER BY - ** clause processing on UPDATE and DELETE statements. + ** clause processing on UPDATE and DELETE statements, and by + ** UPDATE ... FROM statement processing. */ case TK_ROW: { SrcList *pSrcList = pNC->pSrcList; - struct SrcList_item *pItem; - assert( pSrcList && pSrcList->nSrc==1 ); - pItem = pSrcList->a; + SrcItem *pItem; + assert( pSrcList && pSrcList->nSrc>=1 ); + pItem = pSrcList->a; pExpr->op = TK_COLUMN; - pExpr->pTab = pItem->pTab; + assert( ExprUseYTab(pExpr) ); + pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; - pExpr->iColumn = -1; - pExpr->affinity = SQLITE_AFF_INTEGER; + pExpr->iColumn--; + pExpr->affExpr = SQLITE_AFF_INTEGER; break; } -#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) - && !defined(SQLITE_OMIT_SUBQUERY) */ - /* A lone identifier is the name of a column. + /* An optimization: Attempt to convert + ** + ** "expr IS NOT NULL" --> "TRUE" + ** "expr IS NULL" --> "FALSE" + ** + ** if we can prove that "expr" is never NULL. Call this the + ** "NOT NULL strength reduction optimization". + ** + ** If this optimization occurs, also restore the NameContext ref-counts + ** to the state they where in before the "column" LHS expression was + ** resolved. This prevents "column" from being counted as having been + ** referenced, which might prevent a SELECT from being erroneously + ** marked as correlated. */ - case TK_ID: { - return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr); + case TK_NOTNULL: + case TK_ISNULL: { + int anRef[8]; + NameContext *p; + int i; + for(i=0, p=pNC; p && ipNext, i++){ + anRef[i] = p->nRef; + } + sqlite3WalkExpr(pWalker, pExpr->pLeft); + if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){ + testcase( ExprHasProperty(pExpr, EP_FromJoin) ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + if( pExpr->op==TK_NOTNULL ){ + pExpr->u.zToken = "true"; + ExprSetProperty(pExpr, EP_IsTrue); + }else{ + pExpr->u.zToken = "false"; + ExprSetProperty(pExpr, EP_IsFalse); + } + pExpr->op = TK_TRUEFALSE; + for(i=0, p=pNC; p && ipNext, i++){ + p->nRef = anRef[i]; + } + sqlite3ExprDelete(pParse->db, pExpr->pLeft); + pExpr->pLeft = 0; + } + return WRC_Prune; } - - /* A table name and column name: ID.ID + + /* A column name: ID + ** Or table name and column name: ID.ID ** Or a database, table and column: ID.ID.ID + ** + ** The TK_ID and TK_OUT cases are combined so that there will only + ** be one call to lookupName(). Then the compiler will in-line + ** lookupName() for a size reduction and performance increase. */ + case TK_ID: case TK_DOT: { const char *zColumn; const char *zTable; const char *zDb; Expr *pRight; - /* if( pSrcList==0 ) break; */ - notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); - pRight = pExpr->pRight; - if( pRight->op==TK_ID ){ + if( pExpr->op==TK_ID ){ zDb = 0; - zTable = pExpr->pLeft->u.zToken; - zColumn = pRight->u.zToken; + zTable = 0; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + zColumn = pExpr->u.zToken; }else{ - assert( pRight->op==TK_DOT ); - zDb = pExpr->pLeft->u.zToken; - zTable = pRight->pLeft->u.zToken; - zColumn = pRight->pRight->u.zToken; + Expr *pLeft = pExpr->pLeft; + testcase( pNC->ncFlags & NC_IdxExpr ); + testcase( pNC->ncFlags & NC_GenCol ); + sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator", + NC_IdxExpr|NC_GenCol, 0, pExpr); + pRight = pExpr->pRight; + if( pRight->op==TK_ID ){ + zDb = 0; + }else{ + assert( pRight->op==TK_DOT ); + assert( !ExprHasProperty(pRight, EP_IntValue) ); + zDb = pLeft->u.zToken; + pLeft = pRight->pLeft; + pRight = pRight->pRight; + } + assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) ); + zTable = pLeft->u.zToken; + zColumn = pRight->u.zToken; + assert( ExprUseYTab(pExpr) ); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); + sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); + } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } @@ -89572,14 +101328,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ - int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ u8 enc = ENC(pParse->db); /* The database encoding */ - - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin)); +#ifndef SQLITE_OMIT_WINDOWFUNC + Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0); +#endif + assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) ); zId = pExpr->u.zToken; - nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0); if( pDef==0 ){ pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0); @@ -89591,14 +101348,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ }else{ is_agg = pDef->xFinalize!=0; if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ - ExprSetProperty(pExpr, EP_Unlikely|EP_Skip); + ExprSetProperty(pExpr, EP_Unlikely); if( n==2 ){ pExpr->iTable = exprProbability(pList->a[1].pExpr); if( pExpr->iTable<0 ){ sqlite3ErrorMsg(pParse, - "second argument to likelihood() must be a " - "constant between 0.0 and 1.0"); - pNC->nErr++; + "second argument to %#T() must be a " + "constant between 0.0 and 1.0", pExpr); + pNC->nNcErr++; } }else{ /* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is @@ -89611,16 +101368,16 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ ** to likelihood(X,0.9375). */ /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120; - } + } } #ifndef SQLITE_OMIT_AUTHORIZATION { int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0); if( auth!=SQLITE_OK ){ if( auth==SQLITE_DENY ){ - sqlite3ErrorMsg(pParse, "not authorized to use function: %s", - pDef->zName); - pNC->nErr++; + sqlite3ErrorMsg(pParse, "not authorized to use function: %#T", + pExpr); + pNC->nNcErr++; } pExpr->op = TK_NULL; return WRC_Prune; @@ -89630,54 +101387,160 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered - ** constant because they are constant for the duration of one query */ + ** constant because they are constant for the duration of one query. + ** This allows them to be factored out of inner loops. */ ExprSetProperty(pExpr,EP_ConstFunc); } if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ - /* Date/time functions that use 'now', and other functions like + /* Clearly non-deterministic functions like random(), but also + ** date/time functions that use 'now', and other functions like ** sqlite_version() that might change over time cannot be used - ** in an index. */ - notValid(pParse, pNC, "non-deterministic functions", - NC_IdxExpr|NC_PartIdx); + ** in an index or generated column. Curiously, they can be used + ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all + ** all this. */ + sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", + NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); + }else{ + assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ + pExpr->op2 = pNC->ncFlags & NC_SelfRef; + if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); + } + if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 + && pParse->nested==0 + && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0 + ){ + /* Internal-use-only functions are disallowed unless the + ** SQL is being compiled using sqlite3NestedParse() or + ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be + ** used to activate internal functions for testing purposes */ + no_such_func = 1; + pDef = 0; + }else + if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 + && !IN_RENAME_OBJECT + ){ + sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } } - if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ - sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); - pNC->nErr++; - is_agg = 0; - }else if( no_such_func && pParse->db->init.busy==0 + + if( 0==IN_RENAME_OBJECT ){ +#ifndef SQLITE_OMIT_WINDOWFUNC + assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX) + || (pDef->xValue==0 && pDef->xInverse==0) + || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize) + ); + if( pDef && pDef->xValue==0 && pWin ){ + sqlite3ErrorMsg(pParse, + "%#T() may not be used as a window function", pExpr + ); + pNC->nNcErr++; + }else if( + (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) + || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin) + || (is_agg && pWin && (pNC->ncFlags & NC_AllowWin)==0) + ){ + const char *zType; + if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pWin ){ + zType = "window"; + }else{ + zType = "aggregate"; + } + sqlite3ErrorMsg(pParse, "misuse of %s function %#T()",zType,pExpr); + pNC->nNcErr++; + is_agg = 0; + } +#else + if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ + sqlite3ErrorMsg(pParse,"misuse of aggregate function %#T()",pExpr); + pNC->nNcErr++; + is_agg = 0; + } +#endif + else if( no_such_func && pParse->db->init.busy==0 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION - && pParse->explain==0 + && pParse->explain==0 +#endif + ){ + sqlite3ErrorMsg(pParse, "no such function: %#T", pExpr); + pNC->nNcErr++; + }else if( wrong_num_args ){ + sqlite3ErrorMsg(pParse,"wrong number of arguments to function %#T()", + pExpr); + pNC->nNcErr++; + } +#ifndef SQLITE_OMIT_WINDOWFUNC + else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ + sqlite3ErrorMsg(pParse, + "FILTER may not be used with non-aggregate %#T()", + pExpr + ); + pNC->nNcErr++; + } +#endif + if( is_agg ){ + /* Window functions may not be arguments of aggregate functions. + ** Or arguments of other window functions. But aggregate functions + ** may be arguments for window functions. */ +#ifndef SQLITE_OMIT_WINDOWFUNC + pNC->ncFlags &= ~(NC_AllowWin | (!pWin ? NC_AllowAgg : 0)); +#else + pNC->ncFlags &= ~NC_AllowAgg; +#endif + } + } +#ifndef SQLITE_OMIT_WINDOWFUNC + else if( ExprHasProperty(pExpr, EP_WinFunc) ){ + is_agg = 1; + } #endif - ){ - sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); - pNC->nErr++; - }else if( wrong_num_args ){ - sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", - nId, zId); - pNC->nErr++; - } - if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg; sqlite3WalkExprList(pWalker, pList); if( is_agg ){ - NameContext *pNC2 = pNC; - pExpr->op = TK_AGG_FUNCTION; - pExpr->op2 = 0; - while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ - pExpr->op2++; - pNC2 = pNC2->pNext; - } - assert( pDef!=0 ); - if( pNC2 ){ - assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); - testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); - pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); - +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pWin ){ + Select *pSel = pNC->pWinSelect; + assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) ); + if( IN_RENAME_OBJECT==0 ){ + sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef); + if( pParse->db->mallocFailed ) break; + } + sqlite3WalkExprList(pWalker, pWin->pPartition); + sqlite3WalkExprList(pWalker, pWin->pOrderBy); + sqlite3WalkExpr(pWalker, pWin->pFilter); + sqlite3WindowLink(pSel, pWin); + pNC->ncFlags |= NC_HasWin; + }else +#endif /* SQLITE_OMIT_WINDOWFUNC */ + { + NameContext *pNC2; /* For looping up thru outer contexts */ + pExpr->op = TK_AGG_FUNCTION; + pExpr->op2 = 0; +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); + } +#endif + pNC2 = pNC; + while( pNC2 + && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0 + ){ + pExpr->op2++; + pNC2 = pNC2->pNext; + } + assert( pDef!=0 || IN_RENAME_OBJECT ); + if( pNC2 && pDef ){ + assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); + assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg ); + testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); + testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 ); + pNC2->ncFlags |= NC_HasAgg + | ((pDef->funcFlags^SQLITE_FUNC_ANYORDER) + & (SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER)); + } } - pNC->ncFlags |= NC_AllowAgg; + pNC->ncFlags |= savedAllowFlags; } /* FIX ME: Compute pExpr->affinity based on the expected return - ** type of the function + ** type of the function */ return WRC_Prune; } @@ -89687,10 +101550,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif case TK_IN: { testcase( pExpr->op==TK_IN ); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ int nRef = pNC->nRef; - notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); - sqlite3WalkSelect(pWalker, pExpr->x.pSelect); + testcase( pNC->ncFlags & NC_IsCheck ); + testcase( pNC->ncFlags & NC_PartIdx ); + testcase( pNC->ncFlags & NC_IdxExpr ); + testcase( pNC->ncFlags & NC_GenCol ); + if( pNC->ncFlags & NC_SelfRef ){ + notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr); + }else{ + sqlite3WalkSelect(pWalker, pExpr->x.pSelect); + } assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); @@ -89700,23 +101570,44 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ break; } case TK_VARIABLE: { - notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); + testcase( pNC->ncFlags & NC_IsCheck ); + testcase( pNC->ncFlags & NC_PartIdx ); + testcase( pNC->ncFlags & NC_IdxExpr ); + testcase( pNC->ncFlags & NC_GenCol ); + sqlite3ResolveNotValid(pParse, pNC, "parameters", + NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr, pExpr); break; } + case TK_IS: + case TK_ISNOT: { + Expr *pRight = sqlite3ExprSkipCollateAndLikely(pExpr->pRight); + assert( !ExprHasProperty(pExpr, EP_Reduced) ); + /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", + ** and "x IS NOT FALSE". */ + if( ALWAYS(pRight) && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){ + int rc = resolveExprStep(pWalker, pRight); + if( rc==WRC_Abort ) return WRC_Abort; + if( pRight->op==TK_TRUEFALSE ){ + pExpr->op2 = pExpr->op; + pExpr->op = TK_TRUTH; + return WRC_Continue; + } + } + /* no break */ deliberate_fall_through + } case TK_BETWEEN: case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: - case TK_GE: - case TK_IS: - case TK_ISNOT: { + case TK_GE: { int nLeft, nRight; if( pParse->db->mallocFailed ) break; assert( pExpr->pLeft!=0 ); nLeft = sqlite3ExprVectorSize(pExpr->pLeft); if( pExpr->op==TK_BETWEEN ){ + assert( ExprUseXList(pExpr) ); nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); if( nRight==nLeft ){ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr); @@ -89736,11 +101627,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_ISNOT ); testcase( pExpr->op==TK_BETWEEN ); sqlite3ErrorMsg(pParse, "row value misused"); + sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); } - break; + break; } } - return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; + assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); + return pParse->nErr ? WRC_Abort : WRC_Continue; } /* @@ -89765,10 +101658,13 @@ static int resolveAsName( UNUSED_PARAMETER(pParse); if( pE->op==TK_ID ){ - char *zCol = pE->u.zToken; + const char *zCol; + assert( !ExprHasProperty(pE, EP_IntValue) ); + zCol = pE->u.zToken; for(i=0; inExpr; i++){ - char *zAs = pEList->a[i].zName; - if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ + if( pEList->a[i].eEName==ENAME_NAME + && sqlite3_stricmp(pEList->a[i].zEName, zCol)==0 + ){ return i+1; } } @@ -89814,9 +101710,9 @@ static int resolveOrderByTermToExprList( memset(&nc, 0, sizeof(nc)); nc.pParse = pParse; nc.pSrcList = pSelect->pSrc; - nc.pEList = pEList; - nc.ncFlags = NC_AllowAgg; - nc.nErr = 0; + nc.uNC.pEList = pEList; + nc.ncFlags = NC_AllowAgg|NC_UEList|NC_NoSelect; + nc.nNcErr = 0; db = pParse->db; savedSuppErr = db->suppressErr; db->suppressErr = 1; @@ -89829,7 +101725,7 @@ static int resolveOrderByTermToExprList( ** result-set entry. */ for(i=0; inExpr; i++){ - if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){ + if( sqlite3ExprCompare(0, pEList->a[i].pExpr, pE, -1)<2 ){ return i+1; } } @@ -89845,11 +101741,13 @@ static void resolveOutOfRangeError( Parse *pParse, /* The error context into which to write the error */ const char *zType, /* "ORDER" or "GROUP" */ int i, /* The index (1-based) of the term out of range */ - int mx /* Largest permissible value of i */ + int mx, /* Largest permissible value of i */ + Expr *pError /* Associate the error with the expression */ ){ - sqlite3ErrorMsg(pParse, + sqlite3ErrorMsg(pParse, "%r %s BY term out of range - should be " "between 1 and %d", i, zType, mx); + sqlite3RecordErrorOffsetOfExpr(pParse->db, pError); } /* @@ -89880,12 +101778,10 @@ static int resolveCompoundOrderBy( pOrderBy = pSelect->pOrderBy; if( pOrderBy==0 ) return 0; db = pParse->db; -#if SQLITE_MAX_COLUMN if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); return 1; } -#endif for(i=0; inExpr; i++){ pOrderBy->a[i].done = 0; } @@ -89903,41 +101799,58 @@ static int resolveCompoundOrderBy( int iCol = -1; Expr *pE, *pDup; if( pItem->done ) continue; - pE = sqlite3ExprSkipCollate(pItem->pExpr); + pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr); + if( NEVER(pE==0) ) continue; if( sqlite3ExprIsInteger(pE, &iCol) ){ if( iCol<=0 || iCol>pEList->nExpr ){ - resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr); + resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr, pE); return 1; } }else{ iCol = resolveAsName(pParse, pEList, pE); if( iCol==0 ){ + /* Now test if expression pE matches one of the values returned + ** by pSelect. In the usual case this is done by duplicating the + ** expression, resolving any symbols in it, and then comparing + ** it against each expression returned by the SELECT statement. + ** Once the comparisons are finished, the duplicate expression + ** is deleted. + ** + ** If this is running as part of an ALTER TABLE operation and + ** the symbols resolve successfully, also resolve the symbols in the + ** actual expression. This allows the code in alter.c to modify + ** column references within the ORDER BY expression as required. */ pDup = sqlite3ExprDup(db, pE, 0); if( !db->mallocFailed ){ assert(pDup); iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup); + if( IN_RENAME_OBJECT && iCol>0 ){ + resolveOrderByTermToExprList(pParse, pSelect, pE); + } } sqlite3ExprDelete(db, pDup); } } if( iCol>0 ){ /* Convert the ORDER BY term into an integer column number iCol, - ** taking care to preserve the COLLATE clause if it exists */ - Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); - if( pNew==0 ) return 1; - pNew->flags |= EP_IntValue; - pNew->u.iValue = iCol; - if( pItem->pExpr==pE ){ - pItem->pExpr = pNew; - }else{ - Expr *pParent = pItem->pExpr; - assert( pParent->op==TK_COLLATE ); - while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; - assert( pParent->pLeft==pE ); - pParent->pLeft = pNew; + ** taking care to preserve the COLLATE clause if it exists. */ + if( !IN_RENAME_OBJECT ){ + Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + if( pNew==0 ) return 1; + pNew->flags |= EP_IntValue; + pNew->u.iValue = iCol; + if( pItem->pExpr==pE ){ + pItem->pExpr = pNew; + }else{ + Expr *pParent = pItem->pExpr; + assert( pParent->op==TK_COLLATE ); + while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft; + assert( pParent->pLeft==pE ); + pParent->pLeft = pNew; + } + sqlite3ExprDelete(db, pE); + pItem->u.x.iOrderByCol = (u16)iCol; } - sqlite3ExprDelete(db, pE); - pItem->u.x.iOrderByCol = (u16)iCol; pItem->done = 1; }else{ moreToDo = 1; @@ -89976,28 +101889,55 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy( ExprList *pEList; struct ExprList_item *pItem; - if( pOrderBy==0 || pParse->db->mallocFailed ) return 0; -#if SQLITE_MAX_COLUMN + if( pOrderBy==0 || pParse->db->mallocFailed || IN_RENAME_OBJECT ) return 0; if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType); return 1; } -#endif pEList = pSelect->pEList; assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */ for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ if( pItem->u.x.iOrderByCol ){ if( pItem->u.x.iOrderByCol>pEList->nExpr ){ - resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr); + resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr, 0); return 1; } - resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, - zType,0); + resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,0); } } return 0; } +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Walker callback for windowRemoveExprFromSelect(). +*/ +static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){ + UNUSED_PARAMETER(pWalker); + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + Window *pWin = pExpr->y.pWin; + sqlite3WindowUnlinkFromSelect(pWin); + } + return WRC_Continue; +} + +/* +** Remove any Window objects owned by the expression pExpr from the +** Select.pWin list of Select object pSelect. +*/ +static void windowRemoveExprFromSelect(Select *pSelect, Expr *pExpr){ + if( pSelect->pWin ){ + Walker sWalker; + memset(&sWalker, 0, sizeof(Walker)); + sWalker.xExprCallback = resolveRemoveWindowsCb; + sWalker.u.pSelect = pSelect; + sqlite3WalkExpr(&sWalker, pExpr); + } +} +#else +# define windowRemoveExprFromSelect(a, b) +#endif /* SQLITE_OMIT_WINDOWFUNC */ + /* ** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect. ** The Name context of the SELECT statement is pNC. zType is either @@ -90028,12 +101968,13 @@ static int resolveOrderGroupBy( Parse *pParse; /* Parsing context */ int nResult; /* Number of terms in the result set */ - if( pOrderBy==0 ) return 0; + assert( pOrderBy!=0 ); nResult = pSelect->pEList->nExpr; pParse = pNC->pParse; for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ Expr *pE = pItem->pExpr; - Expr *pE2 = sqlite3ExprSkipCollate(pE); + Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE); + if( NEVER(pE2==0) ) continue; if( zType[0]!='G' ){ iCol = resolveAsName(pParse, pSelect->pEList, pE2); if( iCol>0 ){ @@ -90050,7 +101991,7 @@ static int resolveOrderGroupBy( ** number so that sqlite3ResolveOrderGroupBy() will convert the ** order-by term to a copy of the result-set expression */ if( iCol<1 || iCol>0xffff ){ - resolveOutOfRangeError(pParse, zType, i+1, nResult); + resolveOutOfRangeError(pParse, zType, i+1, nResult, pE2); return 1; } pItem->u.x.iOrderByCol = (u16)iCol; @@ -90063,7 +102004,11 @@ static int resolveOrderGroupBy( return 1; } for(j=0; jpEList->nExpr; j++){ - if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ + if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ + /* Since this expresion is being changed into a reference + ** to an identical expression in the result set, remove all Window + ** objects belonging to the expression from the Select.pWin list. */ + windowRemoveExprFromSelect(pSelect, pE); pItem->u.x.iOrderByCol = j+1; } } @@ -90084,7 +102029,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ExprList *pGroupBy; /* The GROUP BY clause */ Select *pLeftmost; /* Left-most of SELECT of a compound */ sqlite3 *db; /* Database connection */ - + assert( p!=0 ); if( p->selFlags & SF_Resolved ){ @@ -90104,7 +102049,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ */ if( (p->selFlags & SF_Expanded)==0 ){ sqlite3SelectPrep(pParse, p, pOuterNC); - return (pParse->nErr || db->mallocFailed) ? WRC_Abort : WRC_Prune; + return pParse->nErr ? WRC_Abort : WRC_Prune; } isCompound = p->pPrior!=0; @@ -90113,15 +102058,17 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ while( p ){ assert( (p->selFlags & SF_Expanded)!=0 ); assert( (p->selFlags & SF_Resolved)==0 ); + assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */ p->selFlags |= SF_Resolved; + /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; - if( sqlite3ResolveExprNames(&sNC, p->pLimit) || - sqlite3ResolveExprNames(&sNC, p->pOffset) ){ + sNC.pWinSelect = p; + if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){ return WRC_Abort; } @@ -90138,63 +102085,58 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ pSub->pOrderBy = p->pOrderBy; p->pOrderBy = 0; } - - /* Recursively resolve names in all subqueries + + /* Recursively resolve names in all subqueries in the FROM clause */ for(i=0; ipSrc->nSrc; i++){ - struct SrcList_item *pItem = &p->pSrc->a[i]; - if( pItem->pSelect ){ - NameContext *pNC; /* Used to iterate name contexts */ - int nRef = 0; /* Refcount for pOuterNC and outer contexts */ + SrcItem *pItem = &p->pSrc->a[i]; + if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ + int nRef = pOuterNC ? pOuterNC->nRef : 0; const char *zSavedContext = pParse->zAuthContext; - /* Count the total number of references to pOuterNC and all of its - ** parent contexts. After resolving references to expressions in - ** pItem->pSelect, check if this value has changed. If so, then - ** SELECT statement pItem->pSelect must be correlated. Set the - ** pItem->fg.isCorrelated flag if this is the case. */ - for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef; - if( pItem->zName ) pParse->zAuthContext = pItem->zName; sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; - if( pParse->nErr || db->mallocFailed ) return WRC_Abort; + if( pParse->nErr ) return WRC_Abort; + assert( db->mallocFailed==0 ); - for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef; - assert( pItem->fg.isCorrelated==0 && nRef<=0 ); - pItem->fg.isCorrelated = (nRef!=0); + /* If the number of references to the outer context changed when + ** expressions in the sub-select were resolved, the sub-select + ** is correlated. It is not required to check the refcount on any + ** but the innermost outer context object, as lookupName() increments + ** the refcount on all contexts between the current one and the + ** context containing the column when it resolves a name. */ + if( pOuterNC ){ + assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef ); + pItem->fg.isCorrelated = (pOuterNC->nRef>nRef); + } } } - + /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ - sNC.ncFlags = NC_AllowAgg; + sNC.ncFlags = NC_AllowAgg|NC_AllowWin; sNC.pSrcList = p->pSrc; sNC.pNext = pOuterNC; - + /* Resolve names in the result set. */ if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort; - - /* If there are no aggregate functions in the result-set, and no GROUP BY + sNC.ncFlags &= ~NC_AllowWin; + + /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ assert( NC_MinMaxAgg==SF_MinMaxAgg ); - p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg); + assert( NC_OrderAgg==SF_OrderByReqd ); + p->selFlags |= SF_Aggregate | (sNC.ncFlags&(NC_MinMaxAgg|NC_OrderAgg)); }else{ sNC.ncFlags &= ~NC_AllowAgg; } - - /* If a HAVING clause is present, then there must be a GROUP BY clause. - */ - if( p->pHaving && !pGroupBy ){ - sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); - return WRC_Abort; - } - + /* Add the output column list to the name-context before parsing the ** other expressions in the SELECT statement. This is so that ** expressions in the WHERE clause (etc.) can refer to expressions by @@ -90203,27 +102145,48 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** Minor point: If this is the case, then the expression will be ** re-evaluated for each reference to it. */ - sNC.pEList = p->pEList; - if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; + assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert|NC_UBaseReg))==0 ); + sNC.uNC.pEList = p->pEList; + sNC.ncFlags |= NC_UEList; + if( p->pHaving ){ + if( !pGroupBy ){ + sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); + return WRC_Abort; + } + if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; + } if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; /* Resolve names in table-valued-function arguments */ for(i=0; ipSrc->nSrc; i++){ - struct SrcList_item *pItem = &p->pSrc->a[i]; + SrcItem *pItem = &p->pSrc->a[i]; if( pItem->fg.isTabFunc - && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) + && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) ){ return WRC_Abort; } } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( IN_RENAME_OBJECT ){ + Window *pWin; + for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){ + if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy) + || sqlite3ResolveExprListNames(&sNC, pWin->pPartition) + ){ + return WRC_Abort; + } + } + } +#endif + /* The ORDER BY and GROUP BY clauses may not refer to terms in - ** outer queries + ** outer queries */ sNC.pNext = 0; - sNC.ncFlags |= NC_AllowAgg; + sNC.ncFlags |= NC_AllowAgg|NC_AllowWin; - /* If this is a converted compound query, move the ORDER BY clause from + /* If this is a converted compound query, move the ORDER BY clause from ** the sub-query back to the parent query. At this point each term ** within the ORDER BY clause has been transformed to an integer value. ** These integers will be replaced by copies of the corresponding result @@ -90244,7 +102207,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** is not detected until much later, and so we need to go ahead and ** resolve those symbols on the incorrect ORDER BY for consistency. */ - if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ + if( p->pOrderBy!=0 + && isCompound<=nCompound /* Defer right-most ORDER BY of a compound */ && resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER") ){ return WRC_Abort; @@ -90252,13 +102216,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ if( db->mallocFailed ){ return WRC_Abort; } - - /* Resolve the GROUP BY clause. At the same time, make sure + sNC.ncFlags &= ~NC_AllowWin; + + /* Resolve the GROUP BY clause. At the same time, make sure ** the GROUP BY clause does not contain aggregate functions. */ if( pGroupBy ){ struct ExprList_item *pItem; - + if( resolveOrderGroupBy(&sNC, p, pGroupBy, "GROUP") || db->mallocFailed ){ return WRC_Abort; } @@ -90300,7 +102265,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** checking on function usage and set a flag if any aggregate functions ** are seen. ** -** To resolve table columns references we look for nodes (or subtrees) of the +** To resolve table columns references we look for nodes (or subtrees) of the ** form X.Y.Z or Y.Z or just Z where ** ** X: The name of a database. Ex: "main" or "temp" or @@ -90332,7 +102297,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** ** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY a+b; ** -** Function calls are checked to make sure that the function is +** Function calls are checked to make sure that the function is ** defined and that the correct number of arguments are specified. ** If the function is an aggregate function, then the NC_HasAgg flag is ** set and the opcode is changed from TK_FUNCTION to TK_AGG_FUNCTION. @@ -90342,44 +102307,38 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ ** An error message is left in pParse if anything is amiss. The number ** if errors is returned. */ -SQLITE_PRIVATE int sqlite3ResolveExprNames( +SQLITE_PRIVATE int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ - u16 savedHasAgg; + int savedHasAgg; Walker w; - if( pExpr==0 ) return 0; -#if SQLITE_MAX_EXPR_DEPTH>0 - { - Parse *pParse = pNC->pParse; - if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){ - return 1; - } - pParse->nHeight += pExpr->nHeight; - } -#endif - savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); - pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); + if( pExpr==0 ) return SQLITE_OK; + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; - w.xSelectCallback = resolveSelectStep; + w.xSelectCallback = (pNC->ncFlags & NC_NoSelect) ? 0 : resolveSelectStep; w.xSelectCallback2 = 0; - w.walkerDepth = 0; - w.eCode = 0; w.u.pNC = pNC; +#if SQLITE_MAX_EXPR_DEPTH>0 + w.pParse->nHeight += pExpr->nHeight; + if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ + return SQLITE_ERROR; + } +#endif sqlite3WalkExpr(&w, pExpr); #if SQLITE_MAX_EXPR_DEPTH>0 - pNC->pParse->nHeight -= pExpr->nHeight; + w.pParse->nHeight -= pExpr->nHeight; #endif - if( pNC->nErr>0 || w.pParse->nErr>0 ){ - ExprSetProperty(pExpr, EP_Error); - } - if( pNC->ncFlags & NC_HasAgg ){ - ExprSetProperty(pExpr, EP_Agg); - } + assert( EP_Agg==NC_HasAgg ); + assert( EP_Win==NC_HasWin ); + testcase( pNC->ncFlags & NC_HasAgg ); + testcase( pNC->ncFlags & NC_HasWin ); + ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); pNC->ncFlags |= savedHasAgg; - return ExprHasProperty(pExpr, EP_Error); + return pNC->nNcErr>0 || w.pParse->nErr>0; } /* @@ -90387,16 +102346,47 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( ** just like sqlite3ResolveExprNames() except that it works for an expression ** list rather than a single expression. */ -SQLITE_PRIVATE int sqlite3ResolveExprListNames( +SQLITE_PRIVATE int sqlite3ResolveExprListNames( NameContext *pNC, /* Namespace to resolve expressions in. */ ExprList *pList /* The expression list to be analyzed. */ ){ int i; - if( pList ){ - for(i=0; inExpr; i++){ - if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort; + int savedHasAgg = 0; + Walker w; + if( pList==0 ) return WRC_Continue; + w.pParse = pNC->pParse; + w.xExprCallback = resolveExprStep; + w.xSelectCallback = resolveSelectStep; + w.xSelectCallback2 = 0; + w.u.pNC = pNC; + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); + for(i=0; inExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + if( pExpr==0 ) continue; +#if SQLITE_MAX_EXPR_DEPTH>0 + w.pParse->nHeight += pExpr->nHeight; + if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){ + return WRC_Abort; + } +#endif + sqlite3WalkExpr(&w, pExpr); +#if SQLITE_MAX_EXPR_DEPTH>0 + w.pParse->nHeight -= pExpr->nHeight; +#endif + assert( EP_Agg==NC_HasAgg ); + assert( EP_Win==NC_HasWin ); + testcase( pNC->ncFlags & NC_HasAgg ); + testcase( pNC->ncFlags & NC_HasWin ); + if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg) ){ + ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); + savedHasAgg |= pNC->ncFlags & + (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg); } + if( w.pParse->nErr>0 ) return WRC_Abort; } + pNC->ncFlags |= savedHasAgg; return WRC_Continue; } @@ -90420,47 +102410,65 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames( Walker w; assert( p!=0 ); - memset(&w, 0, sizeof(w)); w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; + w.xSelectCallback2 = 0; w.pParse = pParse; w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } /* -** Resolve names in expressions that can only reference a single table: +** Resolve names in expressions that can only reference a single table +** or which cannot reference any tables at all. Examples: ** -** * CHECK constraints -** * WHERE clauses on partial indices +** "type" flag +** ------------ +** (1) CHECK constraints NC_IsCheck +** (2) WHERE clauses on partial indices NC_PartIdx +** (3) Expressions in indexes on expressions NC_IdxExpr +** (4) Expression arguments to VACUUM INTO. 0 +** (5) GENERATED ALWAYS as expressions NC_GenCol ** -** The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression -** is set to -1 and the Expr.iColumn value is set to the column number. +** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN +** nodes of the expression is set to -1 and the Expr.iColumn value is +** set to the column number. In case (4), TK_COLUMN nodes cause an error. ** ** Any errors cause an error message to be set in pParse. */ -SQLITE_PRIVATE void sqlite3ResolveSelfReference( - Parse *pParse, /* Parsing context */ - Table *pTab, /* The table being referenced */ - int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */ - Expr *pExpr, /* Expression to resolve. May be NULL. */ - ExprList *pList /* Expression list to resolve. May be NUL. */ +SQLITE_PRIVATE int sqlite3ResolveSelfReference( + Parse *pParse, /* Parsing context */ + Table *pTab, /* The table being referenced, or NULL */ + int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */ + Expr *pExpr, /* Expression to resolve. May be NULL. */ + ExprList *pList /* Expression list to resolve. May be NULL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ + int rc; - assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr ); + assert( type==0 || pTab!=0 ); + assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr + || type==NC_GenCol || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); - sSrc.nSrc = 1; - sSrc.a[0].zName = pTab->zName; - sSrc.a[0].pTab = pTab; - sSrc.a[0].iCursor = -1; + if( pTab ){ + sSrc.nSrc = 1; + sSrc.a[0].zName = pTab->zName; + sSrc.a[0].pTab = pTab; + sSrc.a[0].iCursor = -1; + if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ + /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP + ** schema elements */ + type |= NC_FromDDL; + } + } sNC.pParse = pParse; sNC.pSrcList = &sSrc; - sNC.ncFlags = type; - if( sqlite3ResolveExprNames(&sNC, pExpr) ) return; - if( pList ) sqlite3ResolveExprListNames(&sNC, pList); + sNC.ncFlags = type | NC_IsDDL; + if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; + if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); + return rc; } /************** End of resolve.c *********************************************/ @@ -90488,16 +102496,16 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree); /* ** Return the affinity character for a single column of a table. */ -SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){ - assert( iColnCol ); - return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER; +SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table *pTab, int iCol){ + if( iCol<0 || NEVER(iCol>=pTab->nCol) ) return SQLITE_AFF_INTEGER; + return pTab->aCol[iCol].affinity; } /* ** Return the 'affinity' of the expression pExpr if any. ** ** If pExpr is a column, a reference to a column via an 'AS' alias, -** or a sub-select with a column as the return value, then the +** or a sub-select with a column as the return value, then the ** affinity of that column is returned. Otherwise, 0x00 is returned, ** indicating no affinity for the expression. ** @@ -90509,32 +102517,49 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){ ** SELECT a AS b FROM t1 WHERE b; ** SELECT * FROM t1 WHERE (select a from t1); */ -SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ +SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){ int op; - pExpr = sqlite3ExprSkipCollate(pExpr); - if( pExpr->flags & EP_Generic ) return 0; + while( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){ + assert( pExpr->op==TK_COLLATE + || pExpr->op==TK_IF_NULL_ROW + || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) ); + pExpr = pExpr->pLeft; + assert( pExpr!=0 ); + } op = pExpr->op; + if( op==TK_REGISTER ) op = pExpr->op2; + if( op==TK_COLUMN || op==TK_AGG_COLUMN ){ + assert( ExprUseYTab(pExpr) ); + if( pExpr->y.pTab ){ + return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); + } + } if( op==TK_SELECT ){ - assert( pExpr->flags&EP_xIsSelect ); + assert( ExprUseXSelect(pExpr) ); + assert( pExpr->x.pSelect!=0 ); + assert( pExpr->x.pSelect->pEList!=0 ); + assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } - if( op==TK_REGISTER ) op = pExpr->op2; #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif - if( op==TK_AGG_COLUMN || op==TK_COLUMN ){ - return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn); - } if( op==TK_SELECT_COLUMN ){ - assert( pExpr->pLeft->flags&EP_xIsSelect ); + assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) ); + assert( pExpr->iColumn < pExpr->iTable ); + assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } - return pExpr->affinity; + if( op==TK_VECTOR ){ + assert( ExprUseXList(pExpr) ); + return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr); + } + return pExpr->affExpr; } /* @@ -90546,7 +102571,7 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ ** and the pExpr parameter is returned unchanged. */ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( - Parse *pParse, /* Parsing context */ + const Parse *pParse, /* Parsing context */ Expr *pExpr, /* Add the "COLLATE" clause to this expression */ const Token *pCollName, /* Name of collating sequence */ int dequote /* True to dequote pCollName */ @@ -90561,7 +102586,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( } return pExpr; } -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString( + const Parse *pParse, /* Parsing context */ + Expr *pExpr, /* Add the "COLLATE" clause to this expression */ + const char *zC /* The collating sequence name */ +){ Token s; assert( zC!=0 ); sqlite3TokenInit(&s, (char*)zC); @@ -90569,13 +102598,25 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con } /* -** Skip over any TK_COLLATE operators and any unlikely() -** or likelihood() function at the root of an expression. +** Skip over any TK_COLLATE operators. */ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ + assert( pExpr->op==TK_COLLATE ); + pExpr = pExpr->pLeft; + } + return pExpr; +} + +/* +** Skip over any TK_COLLATE operators and/or any unlikely() +** or likelihood() or likely() functions at the root of an +** expression. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ + while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprUseXList(pExpr) ); assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; @@ -90583,7 +102624,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } - } + } return pExpr; } @@ -90591,37 +102632,48 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ ** Return the collation sequence for the expression pExpr. If ** there is no defined collating sequence, return NULL. ** +** See also: sqlite3ExprNNCollSeq() +** +** The sqlite3ExprNNCollSeq() works the same exact that it returns the +** default collation if pExpr has no defined collation. +** ** The collating sequence might be determined by a COLLATE operator ** or by the presence of a column with a defined collating sequence. ** COLLATE operators take first precedence. Left operands take ** precedence over right operands. */ -SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ +SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ sqlite3 *db = pParse->db; CollSeq *pColl = 0; - Expr *p = pExpr; + const Expr *p = pExpr; while( p ){ int op = p->op; - if( p->flags & EP_Generic ) break; + if( op==TK_REGISTER ) op = p->op2; + if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){ + assert( ExprUseYTab(p) ); + if( p->y.pTab!=0 ){ + /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally + ** a TK_COLUMN but was previously evaluated and cached in a register */ + int j = p->iColumn; + if( j>=0 ){ + const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]); + pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); + } + break; + } + } if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } - if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){ - pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); - break; + if( op==TK_VECTOR ){ + assert( ExprUseXList(p) ); + p = p->x.pList->a[0].pExpr; + continue; } - if( (op==TK_AGG_COLUMN || op==TK_COLUMN - || op==TK_REGISTER || op==TK_TRIGGER) - && p->pTab!=0 - ){ - /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally - ** a TK_COLUMN but was previously evaluated and cached in a register */ - int j = p->iColumn; - if( j>=0 ){ - const char *zColl = p->pTab->aCol[j].zColl; - pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); - } + if( op==TK_COLLATE ){ + assert( !ExprHasProperty(p, EP_IntValue) ); + pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } if( p->flags & EP_Collate ){ @@ -90630,11 +102682,9 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ }else{ Expr *pNext = p->pRight; /* The Expr.x union is never used at the same time as Expr.pRight */ + assert( ExprUseXList(p) ); assert( p->x.pList==0 || p->pRight==0 ); - /* p->flags holds EP_Collate and p->pLeft->flags does not. And - ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at - ** least one EP_Collate. Thus the following two ALWAYS. */ - if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){ + if( p->x.pList!=0 && !db->mallocFailed ){ int i; for(i=0; ALWAYS(ix.pList->nExpr); i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ @@ -90649,20 +102699,46 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ break; } } - if( sqlite3CheckCollSeq(pParse, pColl) ){ + if( sqlite3CheckCollSeq(pParse, pColl) ){ pColl = 0; } return pColl; } +/* +** Return the collation sequence for the expression pExpr. If +** there is no defined collating sequence, return a pointer to the +** defautl collation sequence. +** +** See also: sqlite3ExprCollSeq() +** +** The sqlite3ExprCollSeq() routine works the same except that it +** returns NULL if there is no defined collation. +*/ +SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){ + CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr); + if( p==0 ) p = pParse->db->pDfltColl; + assert( p!=0 ); + return p; +} + +/* +** Return TRUE if the two expressions have equivalent collating sequences. +*/ +SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){ + CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); + CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); + return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; +} + /* ** pExpr is an operand of a comparison operator. aff2 is the ** type affinity of the other operand. This routine returns the ** type affinity that should be used for the comparison operator. */ -SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){ +SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); - if( aff1 && aff2 ){ + if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){ /* Both sides of the comparison are columns. If one has numeric ** affinity, use that. Otherwise use no affinity. */ @@ -90671,15 +102747,10 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){ }else{ return SQLITE_AFF_BLOB; } - }else if( !aff1 && !aff2 ){ - /* Neither side of the comparison is a column. Compare the - ** results directly. - */ - return SQLITE_AFF_BLOB; }else{ /* One side is a column, the other is not. Use the columns affinity. */ - assert( aff1==0 || aff2==0 ); - return (aff1 + aff2); + assert( aff1<=SQLITE_AFF_NONE || aff2<=SQLITE_AFF_NONE ); + return (aff1<=SQLITE_AFF_NONE ? aff2 : aff1) | SQLITE_AFF_NONE; } } @@ -90687,7 +102758,7 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){ ** pExpr is a comparison operator. Return the type affinity that should ** be applied to both operands prior to doing the comparison. */ -static char comparisonAffinity(Expr *pExpr){ +static char comparisonAffinity(const Expr *pExpr){ char aff; assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT || pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE || @@ -90696,7 +102767,7 @@ static char comparisonAffinity(Expr *pExpr){ aff = sqlite3ExprAffinity(pExpr->pLeft); if( pExpr->pRight ){ aff = sqlite3CompareAffinity(pExpr->pRight, aff); - }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + }else if( ExprUseXSelect(pExpr) ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); }else if( aff==0 ){ aff = SQLITE_AFF_BLOB; @@ -90710,23 +102781,26 @@ static char comparisonAffinity(Expr *pExpr){ ** if the index with affinity idx_affinity may be used to implement ** the comparison in pExpr. */ -SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ +SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); - switch( aff ){ - case SQLITE_AFF_BLOB: - return 1; - case SQLITE_AFF_TEXT: - return idx_affinity==SQLITE_AFF_TEXT; - default: - return sqlite3IsNumericAffinity(idx_affinity); + if( affpRight, p->pLeft); + }else{ + return sqlite3BinaryCompareCollSeq(pParse, p->pLeft, p->pRight); + } +} + /* ** Generate code for a comparison operator. */ @@ -90774,13 +102864,19 @@ static int codeCompare( int opcode, /* The comparison opcode */ int in1, int in2, /* Register holding operands */ int dest, /* Jump here if true. */ - int jumpIfNull /* If true, jump if either operand is NULL */ + int jumpIfNull, /* If true, jump if either operand is NULL */ + int isCommuted /* The comparison has been commuted */ ){ int p5; int addr; CollSeq *p4; - p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight); + if( pParse->nErr ) return 0; + if( isCommuted ){ + p4 = sqlite3BinaryCompareCollSeq(pParse, pRight, pLeft); + }else{ + p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight); + } p5 = binaryCompareP5(pLeft, pRight, jumpIfNull); addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1, (void*)p4, P4_COLLSEQ); @@ -90797,29 +102893,30 @@ static int codeCompare( ** But a TK_SELECT might be either a vector or a scalar. It is only ** considered a vector if it has two or more result columns. */ -SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){ +SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr){ return sqlite3ExprVectorSize(pExpr)>1; } /* -** If the expression passed as the only argument is of type TK_VECTOR +** If the expression passed as the only argument is of type TK_VECTOR ** return the number of expressions in the vector. Or, if the expression ** is a sub-select, return the number of columns in the sub-select. For ** any other type of expression, return 1. */ -SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){ +SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr){ u8 op = pExpr->op; if( op==TK_REGISTER ) op = pExpr->op2; if( op==TK_VECTOR ){ + assert( ExprUseXList(pExpr) ); return pExpr->x.pList->nExpr; }else if( op==TK_SELECT ){ + assert( ExprUseXSelect(pExpr) ); return pExpr->x.pSelect->pEList->nExpr; }else{ return 1; } } -#ifndef SQLITE_OMIT_SUBQUERY /* ** Return a pointer to a subexpression of pVector that is the i-th ** column of the vector (numbered starting with 0). The caller must @@ -90836,26 +102933,26 @@ SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){ ** been positioned. */ SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ - assert( iop==TK_ERROR ); if( sqlite3ExprIsVector(pVector) ){ assert( pVector->op2==0 || pVector->op==TK_REGISTER ); if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){ + assert( ExprUseXSelect(pVector) ); return pVector->x.pSelect->pEList->a[i].pExpr; }else{ + assert( ExprUseXList(pVector) ); return pVector->x.pList->a[i].pExpr; } } return pVector; } -#endif /* !defined(SQLITE_OMIT_SUBQUERY) */ -#ifndef SQLITE_OMIT_SUBQUERY /* ** Compute and return a new Expr object which when passed to ** sqlite3ExprCode() will generate all necessary code to compute ** the iField-th column of the vector expression pVector. ** -** It is ok for pVector to be a scalar (as long as iField==0). +** It is ok for pVector to be a scalar (as long as iField==0). ** In that case, this routine works like sqlite3ExprDup(). ** ** The caller owns the returned Expr object and is responsible for @@ -90874,11 +102971,12 @@ SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( Parse *pParse, /* Parsing context */ Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ - int iField /* Which column of the vector to return */ + int iField, /* Which column of the vector to return */ + int nField /* Total number of columns in the vector */ ){ Expr *pRet; if( pVector->op==TK_SELECT ){ - assert( pVector->flags & EP_xIsSelect ); + assert( ExprUseXSelect(pVector) ); /* The TK_SELECT_COLUMN Expr node: ** ** pLeft: pVector containing TK_SELECT. Not deleted. @@ -90897,21 +102995,30 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField( */ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0); if( pRet ){ + pRet->iTable = nField; pRet->iColumn = iField; pRet->pLeft = pVector; } - assert( pRet==0 || pRet->iTable==0 ); }else{ - if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr; + if( pVector->op==TK_VECTOR ){ + Expr **ppVector; + assert( ExprUseXList(pVector) ); + ppVector = &pVector->x.pList->a[iField].pExpr; + pVector = *ppVector; + if( IN_RENAME_OBJECT ){ + /* This must be a vector UPDATE inside a trigger */ + *ppVector = 0; + return pVector; + } + } pRet = sqlite3ExprDup(pParse->db, pVector, 0); } return pRet; } -#endif /* !define(SQLITE_OMIT_SUBQUERY) */ /* ** If expression pExpr is of type TK_SELECT, generate code to evaluate -** it. Return the register in which the result is stored (or, if the +** it. Return the register in which the result is stored (or, if the ** sub-select returns more than one column, the first in an array ** of registers in which the result is stored). ** @@ -90921,7 +103028,7 @@ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){ int reg = 0; #ifndef SQLITE_OMIT_SUBQUERY if( pExpr->op==TK_SELECT ){ - reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0); + reg = sqlite3CodeSubselect(pParse, pExpr); } #endif return reg; @@ -90933,10 +103040,10 @@ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){ ** the register number of a register that contains the value of ** element iField of the vector. ** -** If pVector is a TK_SELECT expression, then code for it must have +** If pVector is a TK_SELECT expression, then code for it must have ** already been generated using the exprCodeSubselect() routine. In this ** case parameter regSelect should be the first in an array of registers -** containing the results of the sub-select. +** containing the results of the sub-select. ** ** If pVector is of type TK_VECTOR, then code for the requested field ** is generated. In this case (*pRegFree) may be set to the number of @@ -90954,17 +103061,22 @@ static int exprVectorRegister( int *pRegFree /* OUT: Temp register to free */ ){ u8 op = pVector->op; - assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT ); + assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT || op==TK_ERROR ); if( op==TK_REGISTER ){ *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField); return pVector->iTable+iField; } if( op==TK_SELECT ){ + assert( ExprUseXSelect(pVector) ); *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; return regSelect+iField; } - *ppExpr = pVector->x.pList->a[iField].pExpr; - return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); + if( op==TK_VECTOR ){ + assert( ExprUseXList(pVector) ); + *ppExpr = pVector->x.pList->a[iField].pExpr; + return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); + } + return 0; } /* @@ -90993,38 +103105,44 @@ static void codeVectorCompare( int regLeft = 0; int regRight = 0; u8 opx = op; - int addrDone = sqlite3VdbeMakeLabel(v); + int addrCmp = 0; + int addrDone = sqlite3VdbeMakeLabel(pParse); + int isCommuted = ExprHasProperty(pExpr,EP_Commuted); + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); + if( pParse->nErr ) return; if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); return; } - assert( pExpr->op==TK_EQ || pExpr->op==TK_NE - || pExpr->op==TK_IS || pExpr->op==TK_ISNOT - || pExpr->op==TK_LT || pExpr->op==TK_GT - || pExpr->op==TK_LE || pExpr->op==TK_GE + assert( pExpr->op==TK_EQ || pExpr->op==TK_NE + || pExpr->op==TK_IS || pExpr->op==TK_ISNOT + || pExpr->op==TK_LT || pExpr->op==TK_GT + || pExpr->op==TK_LE || pExpr->op==TK_GE ); assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ) || (pExpr->op==TK_ISNOT && op==TK_NE) ); assert( p5==0 || pExpr->op!=op ); assert( p5==SQLITE_NULLEQ || pExpr->op==op ); - p5 |= SQLITE_STOREP2; - if( opx==TK_LE ) opx = TK_LT; - if( opx==TK_GE ) opx = TK_GT; + if( op==TK_LE ) opx = TK_LT; + if( op==TK_GE ) opx = TK_GT; + if( op==TK_NE ) opx = TK_EQ; regLeft = exprCodeSubselect(pParse, pLeft); regRight = exprCodeSubselect(pParse, pRight); + sqlite3VdbeAddOp2(v, OP_Integer, 1, dest); for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; - Expr *pL, *pR; + Expr *pL = 0, *pR = 0; int r1, r2; assert( i>=0 && i0 ) sqlite3ExprCachePush(pParse); + if( addrCmp ) sqlite3VdbeJumpHere(v, addrCmp); r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); - codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5); + addrCmp = sqlite3VdbeCurrentAddr(v); + codeCompare(pParse, pL, pR, opx, r1, r2, addrDone, p5, isCommuted); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); @@ -91033,27 +103151,32 @@ static void codeVectorCompare( testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); - if( i>0 ) sqlite3ExprCachePop(pParse); + if( (opx==TK_LT || opx==TK_GT) && i0 @@ -91066,7 +103189,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){ int rc = SQLITE_OK; int mxHeight = pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH]; if( nHeight>mxHeight ){ - sqlite3ErrorMsg(pParse, + sqlite3ErrorMsg(pParse, "Expression tree is too large (maximum depth %d)", mxHeight ); rc = SQLITE_ERROR; @@ -91083,14 +103206,14 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){ ** to by pnHeight, the second parameter, then set *pnHeight to that ** value. */ -static void heightOfExpr(Expr *p, int *pnHeight){ +static void heightOfExpr(const Expr *p, int *pnHeight){ if( p ){ if( p->nHeight>*pnHeight ){ *pnHeight = p->nHeight; } } } -static void heightOfExprList(ExprList *p, int *pnHeight){ +static void heightOfExprList(const ExprList *p, int *pnHeight){ if( p ){ int i; for(i=0; inExpr; i++){ @@ -91098,34 +103221,32 @@ static void heightOfExprList(ExprList *p, int *pnHeight){ } } } -static void heightOfSelect(Select *p, int *pnHeight){ - if( p ){ +static void heightOfSelect(const Select *pSelect, int *pnHeight){ + const Select *p; + for(p=pSelect; p; p=p->pPrior){ heightOfExpr(p->pWhere, pnHeight); heightOfExpr(p->pHaving, pnHeight); heightOfExpr(p->pLimit, pnHeight); - heightOfExpr(p->pOffset, pnHeight); heightOfExprList(p->pEList, pnHeight); heightOfExprList(p->pGroupBy, pnHeight); heightOfExprList(p->pOrderBy, pnHeight); - heightOfSelect(p->pPrior, pnHeight); } } /* -** Set the Expr.nHeight variable in the structure passed as an -** argument. An expression with no children, Expr.pList or +** Set the Expr.nHeight variable in the structure passed as an +** argument. An expression with no children, Expr.pList or ** Expr.pSelect member has a height of 1. Any other expression -** has a height equal to the maximum height of any other +** has a height equal to the maximum height of any other ** referenced Expr plus one. ** ** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags, ** if appropriate. */ static void exprSetHeight(Expr *p){ - int nHeight = 0; - heightOfExpr(p->pLeft, &nHeight); - heightOfExpr(p->pRight, &nHeight); - if( ExprHasProperty(p, EP_xIsSelect) ){ + int nHeight = p->pLeft ? p->pLeft->nHeight : 0; + if( p->pRight && p->pRight->nHeight>nHeight ) nHeight = p->pRight->nHeight; + if( ExprUseXSelect(p) ){ heightOfSelect(p->x.pSelect, &nHeight); }else if( p->x.pList ){ heightOfExprList(p->x.pList, &nHeight); @@ -91140,7 +103261,7 @@ static void exprSetHeight(Expr *p){ ** leave an error in pParse. ** ** Also propagate all EP_Propagate flags from the Expr.x.pList into -** Expr.flags. +** Expr.flags. */ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ if( pParse->nErr ) return; @@ -91152,7 +103273,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ ** Return the maximum height of any expression tree referenced ** by the select statement passed as an argument. */ -SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){ +SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *p){ int nHeight = 0; heightOfSelect(p, &nHeight); return nHeight; @@ -91160,10 +103281,11 @@ SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){ #else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */ /* ** Propagate all EP_Propagate flags from the Expr.x.pList into -** Expr.flags. +** Expr.flags. */ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ - if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){ + if( pParse->nErr ) return; + if( p && ExprUseXList(p) && p->x.pList ){ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } } @@ -91215,7 +103337,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ - pNew->flags |= EP_IntValue; + pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse); pNew->u.iValue = iValue; }else{ pNew->u.zToken = (char*)&pNew[1]; @@ -91223,14 +103345,13 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); pNew->u.zToken[pToken->n] = 0; if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ - if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted; - sqlite3Dequote(pNew->u.zToken); + sqlite3DequoteExpr(pNew); } } } #if SQLITE_MAX_EXPR_DEPTH>0 pNew->nHeight = 1; -#endif +#endif } return pNew; } @@ -91246,7 +103367,7 @@ SQLITE_PRIVATE Expr *sqlite3Expr( ){ Token x; x.z = zToken; - x.n = zToken ? sqlite3Strlen30(zToken) : 0; + x.n = sqlite3Strlen30(zToken); return sqlite3ExprAlloc(db, op, &x, 0); } @@ -91293,20 +103414,16 @@ SQLITE_PRIVATE Expr *sqlite3PExpr( Expr *pRight /* Right operand */ ){ Expr *p; - if( op==TK_AND && pParse->nErr==0 ){ - /* Take advantage of short-circuit false optimization for AND */ - p = sqlite3ExprAnd(pParse->db, pLeft, pRight); - }else{ - p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); - if( p ){ - memset(p, 0, sizeof(Expr)); - p->op = op & TKFLG_MASK; - p->iAgg = -1; - } + p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = op & 0xff; + p->iAgg = -1; sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); - } - if( p ) { sqlite3ExprCheckHeight(pParse, p->nHeight); + }else{ + sqlite3ExprDelete(pParse->db, pLeft); + sqlite3ExprDelete(pParse->db, pRight); } return p; } @@ -91326,32 +103443,62 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pS } } - /* -** If the expression is always either TRUE or FALSE (respectively), -** then return 1. If one cannot determine the truth value of the -** expression at compile-time return 0. +** Expression list pEList is a list of vector values. This function +** converts the contents of pEList to a VALUES(...) Select statement +** returning 1 row for each element of the list. For example, the +** expression list: +** +** ( (1,2), (3,4) (5,6) ) ** -** This is an optimization. If is OK to return 0 here even if -** the expression really is always false or false (a false negative). -** But it is a bug to return 1 if the expression might have different -** boolean values in different circumstances (a false positive.) +** is translated to the equivalent of: ** -** Note that if the expression is part of conditional for a -** LEFT JOIN, then we cannot determine at compile-time whether or not -** is it true or false, so always return 0. +** VALUES(1,2), (3,4), (5,6) +** +** Each of the vector values in pEList must contain exactly nElem terms. +** If a list element that is not a vector or does not contain nElem terms, +** an error message is left in pParse. +** +** This is used as part of processing IN(...) expressions with a list +** of vectors on the RHS. e.g. "... IN ((1,2), (3,4), (5,6))". */ -static int exprAlwaysTrue(Expr *p){ - int v = 0; - if( ExprHasProperty(p, EP_FromJoin) ) return 0; - if( !sqlite3ExprIsInteger(p, &v) ) return 0; - return v!=0; -} -static int exprAlwaysFalse(Expr *p){ - int v = 0; - if( ExprHasProperty(p, EP_FromJoin) ) return 0; - if( !sqlite3ExprIsInteger(p, &v) ) return 0; - return v==0; +SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprList *pEList){ + int ii; + Select *pRet = 0; + assert( nElem>1 ); + for(ii=0; iinExpr; ii++){ + Select *pSel; + Expr *pExpr = pEList->a[ii].pExpr; + int nExprElem; + if( pExpr->op==TK_VECTOR ){ + assert( ExprUseXList(pExpr) ); + nExprElem = pExpr->x.pList->nExpr; + }else{ + nExprElem = 1; + } + if( nExprElem!=nElem ){ + sqlite3ErrorMsg(pParse, "IN(...) element has %d term%s - expected %d", + nExprElem, nExprElem>1?"s":"", nElem + ); + break; + } + assert( ExprUseXList(pExpr) ); + pSel = sqlite3SelectNew(pParse, pExpr->x.pList, 0, 0, 0, 0, 0, SF_Values,0); + pExpr->x.pList = 0; + if( pSel ){ + if( pRet ){ + pSel->op = TK_ALL; + pSel->pPrior = pRet; + } + pRet = pSel; + } + } + + if( pRet && pRet->pPrior ){ + pRet->selFlags |= SF_MultiValue; + } + sqlite3ExprListDelete(pParse->db, pEList); + return pRet; } /* @@ -91362,19 +103509,20 @@ static int exprAlwaysFalse(Expr *p){ ** of returning an AND expression, just return a constant expression with ** a value of false. */ -SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ - if( pLeft==0 ){ +SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ + sqlite3 *db = pParse->db; + if( pLeft==0 ){ return pRight; }else if( pRight==0 ){ return pLeft; - }else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){ - sqlite3ExprDelete(db, pLeft); - sqlite3ExprDelete(db, pRight); - return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0); + }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight)) + && !IN_RENAME_OBJECT + ){ + sqlite3ExprDeferredDelete(pParse, pLeft); + sqlite3ExprDeferredDelete(pParse, pRight); + return sqlite3Expr(db, TK_INTEGER, "0"); }else{ - Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0); - sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight); - return pNew; + return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } } @@ -91382,7 +103530,12 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ ** Construct a new expression node for a function with multiple ** arguments. */ -SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){ +SQLITE_PRIVATE Expr *sqlite3ExprFunction( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* Argument list */ + const Token *pToken, /* Name of the function */ + int eDistinct /* SF_Distinct or SF_ALL or 0 */ +){ Expr *pNew; sqlite3 *db = pParse->db; assert( pToken ); @@ -91391,15 +103544,58 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token * sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ return 0; } + pNew->w.iOfst = (int)(pToken->z - pParse->zTail); + if( pList + && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] + && !pParse->nested + ){ + sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); + } pNew->x.pList = pList; - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + ExprSetProperty(pNew, EP_HasFunc); + assert( ExprUseXList(pNew) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); + if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; } +/* +** Check to see if a function is usable according to current access +** rules: +** +** SQLITE_FUNC_DIRECT - Only usable from top-level SQL +** +** SQLITE_FUNC_UNSAFE - Usable if TRUSTED_SCHEMA or from +** top-level SQL +** +** If the function is not usable, create an error. +*/ +SQLITE_PRIVATE void sqlite3ExprFunctionUsable( + Parse *pParse, /* Parsing and code generating context */ + const Expr *pExpr, /* The function invocation */ + const FuncDef *pDef /* The function being invoked */ +){ + assert( !IN_RENAME_OBJECT ); + assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 ); + if( ExprHasProperty(pExpr, EP_FromDDL) ){ + if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0 + || (pParse->db->flags & SQLITE_TrustedSchema)==0 + ){ + /* Functions prohibited in triggers and views if: + ** (1) tagged with SQLITE_DIRECTONLY + ** (2) not tagged with SQLITE_INNOCUOUS (which means it + ** is tagged with SQLITE_FUNC_UNSAFE) and + ** SQLITE_DBCONFIG_TRUSTED_SCHEMA is off (meaning + ** that the schema is possibly tainted). + */ + sqlite3ErrorMsg(pParse, "unsafe use of %#T()", pExpr); + } + } +} + /* ** Assign a variable number to an expression that encodes a wildcard -** in the original SQL statement. +** in the original SQL statement. ** ** Wildcards consisting of a single "?" are assigned the next sequential ** variable number. @@ -91423,7 +103619,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n z = pExpr->u.zToken; assert( z!=0 ); assert( z[0]!=0 ); - assert( n==sqlite3Strlen30(z) ); + assert( n==(u32)sqlite3Strlen30(z) ); if( z[1]==0 ){ /* Wildcard of the form "?". Assign the next variable number */ assert( z[0]=='?' ); @@ -91448,6 +103644,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); + sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); return; } x = (ynVar)i; @@ -91475,6 +103672,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n pExpr->iColumn = x; if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "too many SQL variables"); + sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr); } } @@ -91483,41 +103681,83 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); - /* Sanity check: Assert that the IntValue is non-negative if it exists */ - assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); + assert( !ExprUseUValue(p) || p->u.iValue>=0 ); + assert( !ExprUseYWin(p) || !ExprUseYSub(p) ); + assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed ); + assert( p->op!=TK_FUNCTION || !ExprUseYSub(p) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); - assert( p->x.pSelect==0 ); + assert( !ExprUseXSelect(p) || p->x.pSelect==0 ); + assert( !ExprUseXList(p) || p->x.pList==0 ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ - assert( p->x.pList==0 || p->pRight==0 ); + assert( (ExprUseXList(p) && p->x.pList==0) || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); - sqlite3ExprDelete(db, p->pRight); - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( p->pRight ){ + assert( !ExprHasProperty(p, EP_WinFunc) ); + sqlite3ExprDeleteNN(db, p->pRight); + }else if( ExprUseXSelect(p) ){ + assert( !ExprHasProperty(p, EP_WinFunc) ); sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(p, EP_WinFunc) ){ + sqlite3WindowDelete(db, p->y.pWin); + } +#endif } } - if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); + if( ExprHasProperty(p, EP_MemToken) ){ + assert( !ExprHasProperty(p, EP_IntValue) ); + sqlite3DbFree(db, p->u.zToken); + } if( !ExprHasProperty(p, EP_Static) ){ - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } } SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } + +/* +** Arrange to cause pExpr to be deleted when the pParse is deleted. +** This is similar to sqlite3ExprDelete() except that the delete is +** deferred untilthe pParse is deleted. +** +** The pExpr might be deleted immediately on an OOM error. +** +** The deferred delete is (currently) implemented by adding the +** pExpr to the pParse->pConstExpr list with a register number of 0. +*/ +SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ + pParse->pConstExpr = + sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); +} + +/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the +** expression. +*/ +SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){ + if( p ){ + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprUnmap(pParse, p); + } + sqlite3ExprDeleteNN(pParse->db, p); + } +} + /* -** Return the number of bytes allocated for the expression structure +** Return the number of bytes allocated for the expression structure ** passed as the first argument. This is always one of EXPR_FULLSIZE, ** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE. */ -static int exprStructSize(Expr *p){ +static int exprStructSize(const Expr *p){ if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE; if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE; return EXPR_FULLSIZE; @@ -91528,14 +103768,14 @@ static int exprStructSize(Expr *p){ ** to store a copy of an expression or expression tree. They differ in ** how much of the tree is measured. ** -** dupedExprStructSize() Size of only the Expr structure +** dupedExprStructSize() Size of only the Expr structure ** dupedExprNodeSize() Size of Expr + space for token ** dupedExprSize() Expr + token + subtree components ** *************************************************************************** ** -** The dupedExprStructSize() function returns two values OR-ed together: -** (1) the space required for a copy of the Expr structure only and +** The dupedExprStructSize() function returns two values OR-ed together: +** (1) the space required for a copy of the Expr structure only and ** (2) the EP_xxx flags that indicate what the structure size should be. ** The return values is always one of: ** @@ -91550,25 +103790,29 @@ static int exprStructSize(Expr *p){ ** Note that with flags==EXPRDUP_REDUCE, this routines works on full-size ** (unreduced) Expr objects as they or originally constructed by the parser. ** During expression analysis, extra information is computed and moved into -** later parts of teh Expr object and that extra information might get chopped +** later parts of the Expr object and that extra information might get chopped ** off if the expression is reduced. Note also that it does not work to ** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal ** to reduce a pristine expression tree from the parser. The implementation ** of dupedExprStructSize() contain multiple assert() statements that attempt ** to enforce this constraint. */ -static int dupedExprStructSize(Expr *p, int flags){ +static int dupedExprStructSize(const Expr *p, int flags){ int nSize; assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); - if( 0==flags || p->op==TK_SELECT_COLUMN ){ + if( 0==flags || p->op==TK_SELECT_COLUMN +#ifndef SQLITE_OMIT_WINDOWFUNC + || ExprHasProperty(p, EP_WinFunc) +#endif + ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); - assert( !ExprHasProperty(p, EP_FromJoin) ); + assert( !ExprHasProperty(p, EP_FromJoin) ); assert( !ExprHasProperty(p, EP_MemToken) ); - assert( !ExprHasProperty(p, EP_NoReduce) ); + assert( !ExprHasVVAProperty(p, EP_NoReduce) ); if( p->pLeft || p->x.pList ){ nSize = EXPR_REDUCEDSIZE | EP_Reduced; }else{ @@ -91580,32 +103824,32 @@ static int dupedExprStructSize(Expr *p, int flags){ } /* -** This function returns the space in bytes required to store the copy +** This function returns the space in bytes required to store the copy ** of the Expr structure and a copy of the Expr.u.zToken string (if that ** string is defined.) */ -static int dupedExprNodeSize(Expr *p, int flags){ +static int dupedExprNodeSize(const Expr *p, int flags){ int nByte = dupedExprStructSize(p, flags) & 0xfff; if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){ - nByte += sqlite3Strlen30(p->u.zToken)+1; + nByte += sqlite3Strlen30NN(p->u.zToken)+1; } return ROUND8(nByte); } /* -** Return the number of bytes required to create a duplicate of the +** Return the number of bytes required to create a duplicate of the ** expression passed as the first argument. The second argument is a ** mask containing EXPRDUP_XXX flags. ** ** The value returned includes space to create a copy of the Expr struct ** itself and the buffer referred to by Expr.u.zToken, if any. ** -** If the EXPRDUP_REDUCE flag is set, then the return value includes -** space to duplicate all Expr nodes in the tree formed by Expr.pLeft -** and Expr.pRight variables (but not for any structures pointed to or +** If the EXPRDUP_REDUCE flag is set, then the return value includes +** space to duplicate all Expr nodes in the tree formed by Expr.pLeft +** and Expr.pRight variables (but not for any structures pointed to or ** descended from the Expr.x.pList or Expr.x.pSelect variables). */ -static int dupedExprSize(Expr *p, int flags){ +static int dupedExprSize(const Expr *p, int flags){ int nByte = 0; if( p ){ nByte = dupedExprNodeSize(p, flags); @@ -91617,14 +103861,14 @@ static int dupedExprSize(Expr *p, int flags){ } /* -** This function is similar to sqlite3ExprDup(), except that if pzBuffer -** is not NULL then *pzBuffer is assumed to point to a buffer large enough +** This function is similar to sqlite3ExprDup(), except that if pzBuffer +** is not NULL then *pzBuffer is assumed to point to a buffer large enough ** to store the copy of expression p, the copies of p->u.zToken ** (if applicable), and the copies of the p->pLeft and p->pRight expressions, ** if any. Before returning, *pzBuffer is set to the first byte past the ** portion of the buffer copied into by this function. */ -static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ +static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){ Expr *pNew; /* Value to return */ u8 *zAlloc; /* Memory space from which to build Expr object */ u32 staticFlag; /* EP_Static if space not obtained from malloc */ @@ -91638,6 +103882,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ if( pzBuffer ){ zAlloc = *pzBuffer; staticFlag = EP_Static; + assert( zAlloc!=0 ); }else{ zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); staticFlag = 0; @@ -91664,7 +103909,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ }else{ u32 nSize = (u32)exprStructSize(p); memcpy(zAlloc, p, nSize); - if( nSizeflags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); pNew->flags |= staticFlag; + ExprClearVVAProperties(pNew); + if( dupFlags ){ + ExprSetVVAProperty(pNew, EP_Immutable); + } /* Copy the p->u.zToken string, if any. */ if( nToken ){ @@ -91682,7 +103931,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */ - if( ExprHasProperty(p, EP_xIsSelect) ){ + if( ExprUseXSelect(p) ){ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); @@ -91690,7 +103939,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ } /* Fill in pNew->pLeft and pNew->pRight. */ - if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){ + if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){ zAlloc += dupedExprNodeSize(p, dupFlags); if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){ pNew->pLeft = p->pLeft ? @@ -91698,6 +103947,12 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ pNew->pRight = p->pRight ? exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0; } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(p, EP_WinFunc) ){ + pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin); + assert( ExprHasProperty(pNew, EP_WinFunc) ); + } +#endif /* SQLITE_OMIT_WINDOWFUNC */ if( pzBuffer ){ *pzBuffer = zAlloc; } @@ -91705,8 +103960,8 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; - assert( p->iColumn==0 || p->pRight==0 ); - assert( p->pRight==0 || p->pRight==p->pLeft ); + assert( p->pRight==0 || p->pRight==p->pLeft + || ExprHasProperty(p->pLeft, EP_Subquery) ); }else{ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); } @@ -91718,15 +103973,15 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ } /* -** Create and return a deep copy of the object passed as the second +** Create and return a deep copy of the object passed as the second ** argument. If an OOM condition is encountered, NULL is returned ** and the db->mallocFailed flag set. */ #ifndef SQLITE_OMIT_CTE -static With *withDup(sqlite3 *db, With *p){ +SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ - int nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); + sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; @@ -91741,9 +103996,42 @@ static With *withDup(sqlite3 *db, With *p){ return pRet; } #else -# define withDup(x,y) 0 +# define sqlite3WithDup(x,y) 0 #endif +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** The gatherSelectWindows() procedure and its helper routine +** gatherSelectWindowsCallback() are used to scan all the expressions +** an a newly duplicated SELECT statement and gather all of the Window +** objects found there, assembling them onto the linked list at Select->pWin. +*/ +static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){ + Select *pSelect = pWalker->u.pSelect; + Window *pWin = pExpr->y.pWin; + assert( pWin ); + assert( IsWindowFunc(pExpr) ); + assert( pWin->ppThis==0 ); + sqlite3WindowLink(pSelect, pWin); + } + return WRC_Continue; +} +static int gatherSelectWindowsSelectCallback(Walker *pWalker, Select *p){ + return p==pWalker->u.pSelect ? WRC_Continue : WRC_Prune; +} +static void gatherSelectWindows(Select *p){ + Walker w; + w.xExprCallback = gatherSelectWindowsCallback; + w.xSelectCallback = gatherSelectWindowsSelectCallback; + w.xSelectCallback2 = 0; + w.pParse = 0; + w.u.pSelect = p; + sqlite3WalkSelect(&w, p); +} +#endif + + /* ** The following group of routines make deep copies of expressions, ** expression lists, ID lists, and select statements. The copies can @@ -91751,7 +104039,7 @@ static With *withDup(sqlite3 *db, With *p){ ** without effecting the originals. ** ** The expression list, ID, and source lists return by sqlite3ExprListDup(), -** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded +** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded ** by subsequent calls to sqlite*ListAppend() routines. ** ** Any tables that the SrcList might point to are not duplicated. @@ -91761,52 +104049,52 @@ static With *withDup(sqlite3 *db, With *p){ ** truncated version of the usual Expr structure that will be stored as ** part of the in-memory representation of the database schema. */ -SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){ +SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, const Expr *p, int flags){ assert( flags==0 || flags==EXPRDUP_REDUCE ); return p ? exprDup(db, p, flags, 0) : 0; } -SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ +SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){ ExprList *pNew; - struct ExprList_item *pItem, *pOldItem; + struct ExprList_item *pItem; + const struct ExprList_item *pOldItem; int i; - Expr *pPriorSelectCol = 0; + Expr *pPriorSelectColOld = 0; + Expr *pPriorSelectColNew = 0; assert( db!=0 ); if( p==0 ) return 0; - pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) ); + pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); if( pNew==0 ) return 0; - pNew->nExpr = i = p->nExpr; - if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; inExpr; i+=i){} - pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) ); - if( pItem==0 ){ - sqlite3DbFree(db, pNew); - return 0; - } + pNew->nExpr = p->nExpr; + pNew->nAlloc = p->nAlloc; + pItem = pNew->a; pOldItem = p->a; for(i=0; inExpr; i++, pItem++, pOldItem++){ Expr *pOldExpr = pOldItem->pExpr; Expr *pNewExpr; pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags); - if( pOldExpr + if( pOldExpr && pOldExpr->op==TK_SELECT_COLUMN - && (pNewExpr = pItem->pExpr)!=0 + && (pNewExpr = pItem->pExpr)!=0 ){ - assert( pNewExpr->iColumn==0 || i>0 ); - if( pNewExpr->iColumn==0 ){ - assert( pOldExpr->pLeft==pOldExpr->pRight ); - pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight; + if( pNewExpr->pRight ){ + pPriorSelectColOld = pOldExpr->pRight; + pPriorSelectColNew = pNewExpr->pRight; + pNewExpr->pLeft = pNewExpr->pRight; }else{ - assert( i>0 ); - assert( pItem[-1].pExpr!=0 ); - assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 ); - assert( pPriorSelectCol==pItem[-1].pExpr->pLeft ); - pNewExpr->pLeft = pPriorSelectCol; + if( pOldExpr->pLeft!=pPriorSelectColOld ){ + pPriorSelectColOld = pOldExpr->pLeft; + pPriorSelectColNew = sqlite3ExprDup(db, pPriorSelectColOld, flags); + pNewExpr->pRight = pPriorSelectColNew; + } + pNewExpr->pLeft = pPriorSelectColNew; } } - pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); - pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan); - pItem->sortOrder = pOldItem->sortOrder; + pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName); + pItem->sortFlags = pOldItem->sortFlags; + pItem->eEName = pOldItem->eEName; pItem->done = 0; - pItem->bSpanIsTab = pOldItem->bSpanIsTab; + pItem->bNulls = pOldItem->bNulls; + pItem->bSorterRef = pOldItem->bSorterRef; pItem->u = pOldItem->u; } return pNew; @@ -91814,13 +104102,13 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags) /* ** If cursors, triggers, views and subqueries are all omitted from -** the build, then none of the following routines, except for +** the build, then none of the following routines, except for ** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes ** called with a NULL argument. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \ || !defined(SQLITE_OMIT_SUBQUERY) -SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ +SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){ SrcList *pNew; int i; int nByte; @@ -91831,8 +104119,8 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ if( pNew==0 ) return 0; pNew->nSrc = pNew->nAlloc = p->nSrc; for(i=0; inSrc; i++){ - struct SrcList_item *pNewItem = &pNew->a[i]; - struct SrcList_item *pOldItem = &p->a[i]; + SrcItem *pNewItem = &pNew->a[i]; + const SrcItem *pOldItem = &p->a[i]; Table *pTab; pNewItem->pSchema = pOldItem->pSchema; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); @@ -91845,9 +104133,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); } - pNewItem->pIBIndex = pOldItem->pIBIndex; + pNewItem->u2 = pOldItem->u2; + if( pNewItem->fg.isCte ){ + pNewItem->u2.pCteUse->nUse++; + } if( pNewItem->fg.isTabFunc ){ - pNewItem->u1.pFuncArg = + pNewItem->u1.pFuncArg = sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); } pTab = pNewItem->pTab = pOldItem->pTab; @@ -91861,7 +104152,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ } return pNew; } -SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ +SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){ IdList *pNew; int i; assert( db!=0 ); @@ -91871,7 +104162,7 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ pNew->nId = p->nId; pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) ); if( pNew->a==0 ){ - sqlite3DbFree(db, pNew); + sqlite3DbFreeNN(db, pNew); return 0; } /* Note that because the size of the allocation for p->a[] is not @@ -91885,11 +104176,11 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){ } return pNew; } -SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){ Select *pRet = 0; Select *pNext = 0; Select **pp = &pRet; - Select *p; + const Select *p; assert( db!=0 ); for(p=pDup; p; p=p->pPrior){ @@ -91905,15 +104196,27 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ pNew->pNext = pNext; pNew->pPrior = 0; pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); - pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags); pNew->iLimit = 0; pNew->iOffset = 0; pNew->selFlags = p->selFlags & ~SF_UsesEphemeral; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; - pNew->pWith = withDup(db, p->pWith); - sqlite3SelectSetName(pNew, p->zSelName); + pNew->pWith = sqlite3WithDup(db, p->pWith); +#ifndef SQLITE_OMIT_WINDOWFUNC + pNew->pWin = 0; + pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); + if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew); +#endif + pNew->selId = p->selId; + if( db->mallocFailed ){ + /* Any prior OOM might have left the Select object incomplete. + ** Delete the whole thing rather than allow an incomplete Select + ** to be used by the code generator. */ + pNew->pNext = 0; + sqlite3SelectDelete(db, pNew); + break; + } *pp = pNew; pp = &pNew->pPrior; pNext = pNew; @@ -91922,7 +104225,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){ return pRet; } #else -SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ +SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){ assert( p==0 ); return 0; } @@ -91933,47 +104236,75 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ ** Add a new element to the end of an expression list. If pList is ** initially NULL, then create a new expression list. ** +** The pList argument must be either NULL or a pointer to an ExprList +** obtained from a prior call to sqlite3ExprListAppend(). This routine +** may not be used with an ExprList obtained from sqlite3ExprListDup(). +** Reason: This routine assumes that the number of slots in pList->a[] +** is a power of two. That is true for sqlite3ExprListAppend() returns +** but is not necessarily true from the return value of sqlite3ExprListDup(). +** ** If a memory allocation error occurs, the entire list is freed and ** NULL is returned. If non-NULL is returned, then it is guaranteed ** that the new entry was successfully appended. */ +static const struct ExprList_item zeroItem = {0}; +SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew( + sqlite3 *db, /* Database handle. Used for memory allocation */ + Expr *pExpr /* Expression to be appended. Might be NULL */ +){ + struct ExprList_item *pItem; + ExprList *pList; + + pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 ); + if( pList==0 ){ + sqlite3ExprDelete(db, pExpr); + return 0; + } + pList->nAlloc = 4; + pList->nExpr = 1; + pItem = &pList->a[0]; + *pItem = zeroItem; + pItem->pExpr = pExpr; + return pList; +} +SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow( + sqlite3 *db, /* Database handle. Used for memory allocation */ + ExprList *pList, /* List to which to append. Might be NULL */ + Expr *pExpr /* Expression to be appended. Might be NULL */ +){ + struct ExprList_item *pItem; + ExprList *pNew; + pList->nAlloc *= 2; + pNew = sqlite3DbRealloc(db, pList, + sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0])); + if( pNew==0 ){ + sqlite3ExprListDelete(db, pList); + sqlite3ExprDelete(db, pExpr); + return 0; + }else{ + pList = pNew; + } + pItem = &pList->a[pList->nExpr++]; + *pItem = zeroItem; + pItem->pExpr = pExpr; + return pList; +} SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ Expr *pExpr /* Expression to be appended. Might be NULL */ ){ - sqlite3 *db = pParse->db; - assert( db!=0 ); + struct ExprList_item *pItem; if( pList==0 ){ - pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) ); - if( pList==0 ){ - goto no_mem; - } - pList->nExpr = 0; - pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0])); - if( pList->a==0 ) goto no_mem; - }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ - struct ExprList_item *a; - assert( pList->nExpr>0 ); - a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0])); - if( a==0 ){ - goto no_mem; - } - pList->a = a; + return sqlite3ExprListAppendNew(pParse->db,pExpr); } - assert( pList->a!=0 ); - if( 1 ){ - struct ExprList_item *pItem = &pList->a[pList->nExpr++]; - memset(pItem, 0, sizeof(*pItem)); - pItem->pExpr = pExpr; + if( pList->nAllocnExpr+1 ){ + return sqlite3ExprListAppendGrow(pParse->db,pList,pExpr); } + pItem = &pList->a[pList->nExpr++]; + *pItem = zeroItem; + pItem->pExpr = pExpr; return pList; - -no_mem: - /* Avoid leaking memory if malloc has failed. */ - sqlite3ExprDelete(db, pExpr); - sqlite3ExprListDelete(db, pList); - return 0; } /* @@ -92002,8 +104333,8 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( if( NEVER(pColumns==0) ) goto vector_append_error; if( pExpr==0 ) goto vector_append_error; - /* If the RHS is a vector, then we can immediately check to see that - ** the size of the RHS and LHS match. But if the RHS is a SELECT, + /* If the RHS is a vector, then we can immediately check to see that + ** the size of the RHS and LHS match. But if the RHS is a SELECT, ** wildcards ("*") in the result set of the SELECT must be expanded before ** we can do the size check, so defer the size check until code generation. */ @@ -92014,33 +104345,34 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( } for(i=0; inId; i++){ - Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i); + Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i, pColumns->nId); + assert( pSubExpr!=0 || db->mallocFailed ); + if( pSubExpr==0 ) continue; pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); if( pList ){ assert( pList->nExpr==iFirst+i+1 ); - pList->a[pList->nExpr-1].zName = pColumns->a[i].zName; + pList->a[pList->nExpr-1].zEName = pColumns->a[i].zName; pColumns->a[i].zName = 0; } } - if( pExpr->op==TK_SELECT ){ - if( pList && pList->a[iFirst].pExpr ){ - Expr *pFirst = pList->a[iFirst].pExpr; - assert( pFirst->op==TK_SELECT_COLUMN ); - - /* Store the SELECT statement in pRight so it will be deleted when - ** sqlite3ExprListDelete() is called */ - pFirst->pRight = pExpr; - pExpr = 0; + if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){ + Expr *pFirst = pList->a[iFirst].pExpr; + assert( pFirst!=0 ); + assert( pFirst->op==TK_SELECT_COLUMN ); - /* Remember the size of the LHS in iTable so that we can check that - ** the RHS and LHS sizes match during code generation. */ - pFirst->iTable = pColumns->nId; - } + /* Store the SELECT statement in pRight so it will be deleted when + ** sqlite3ExprListDelete() is called */ + pFirst->pRight = pExpr; + pExpr = 0; + + /* Remember the size of the LHS in iTable so that we can check that + ** the RHS and LHS sizes match during code generation. */ + pFirst->iTable = pColumns->nId; } vector_append_error: - sqlite3ExprDelete(db, pExpr); + sqlite3ExprUnmapAndDelete(pParse, pExpr); sqlite3IdListDelete(db, pColumns); return pList; } @@ -92048,19 +104380,38 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( /* ** Set the sort order for the last element on the given ExprList. */ -SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){ +SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){ + struct ExprList_item *pItem; if( p==0 ) return; - assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 ); assert( p->nExpr>0 ); - if( iSortOrder<0 ){ - assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC ); - return; + + assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 ); + assert( iSortOrder==SQLITE_SO_UNDEFINED + || iSortOrder==SQLITE_SO_ASC + || iSortOrder==SQLITE_SO_DESC + ); + assert( eNulls==SQLITE_SO_UNDEFINED + || eNulls==SQLITE_SO_ASC + || eNulls==SQLITE_SO_DESC + ); + + pItem = &p->a[p->nExpr-1]; + assert( pItem->bNulls==0 ); + if( iSortOrder==SQLITE_SO_UNDEFINED ){ + iSortOrder = SQLITE_SO_ASC; + } + pItem->sortFlags = (u8)iSortOrder; + + if( eNulls!=SQLITE_SO_UNDEFINED ){ + pItem->bNulls = 1; + if( iSortOrder!=eNulls ){ + pItem->sortFlags |= KEYINFO_ORDER_BIGNULL; + } } - p->a[p->nExpr-1].sortOrder = (u8)iSortOrder; } /* -** Set the ExprList.a[].zName element of the most recently added item +** Set the ExprList.a[].zEName element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pName should never be @@ -92070,17 +104421,27 @@ SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){ SQLITE_PRIVATE void sqlite3ExprListSetName( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to add the span. */ - Token *pName, /* Name to be added */ + const Token *pName, /* Name to be added */ int dequote /* True to cause the name to be dequoted */ ){ assert( pList!=0 || pParse->db->mallocFailed!=0 ); + assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 ); if( pList ){ struct ExprList_item *pItem; assert( pList->nExpr>0 ); pItem = &pList->a[pList->nExpr-1]; - assert( pItem->zName==0 ); - pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); - if( dequote ) sqlite3Dequote(pItem->zName); + assert( pItem->zEName==0 ); + assert( pItem->eEName==ENAME_NAME ); + pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); + if( dequote ){ + /* If dequote==0, then pName->z does not point to part of a DDL + ** statement handled by the parser. And so no token need be added + ** to the token-map. */ + sqlite3Dequote(pItem->zEName); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (const void*)pItem->zEName, pName); + } + } } } @@ -92095,17 +104456,18 @@ SQLITE_PRIVATE void sqlite3ExprListSetName( SQLITE_PRIVATE void sqlite3ExprListSetSpan( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to add the span. */ - ExprSpan *pSpan /* The span to be added */ + const char *zStart, /* Start of the span */ + const char *zEnd /* End of the span */ ){ sqlite3 *db = pParse->db; assert( pList!=0 || db->mallocFailed!=0 ); if( pList ){ struct ExprList_item *pItem = &pList->a[pList->nExpr-1]; assert( pList->nExpr>0 ); - assert( db->mallocFailed || pItem->pExpr==pSpan->pExpr ); - sqlite3DbFree(db, pItem->zSpan); - pItem->zSpan = sqlite3DbStrNDup(db, (char*)pSpan->zStart, - (int)(pSpan->zEnd - pSpan->zStart)); + if( pItem->zEName==0 ){ + pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd); + pItem->eEName = ENAME_SPAN; + } } } @@ -92130,16 +104492,15 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength( ** Delete an entire expression list. */ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ - int i; - struct ExprList_item *pItem; - assert( pList->a!=0 || pList->nExpr==0 ); - for(pItem=pList->a, i=0; inExpr; i++, pItem++){ + int i = pList->nExpr; + struct ExprList_item *pItem = pList->a; + assert( pList->nExpr>0 ); + do{ sqlite3ExprDelete(db, pItem->pExpr); - sqlite3DbFree(db, pItem->zName); - sqlite3DbFree(db, pItem->zSpan); - } - sqlite3DbFree(db, pList->a); - sqlite3DbFree(db, pList); + sqlite3DbFree(db, pItem->zEName); + pItem++; + }while( --i>0 ); + sqlite3DbFreeNN(db, pList); } SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ if( pList ) exprListDeleteNN(db, pList); @@ -92152,16 +104513,102 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ int i; u32 m = 0; - if( pList ){ - for(i=0; inExpr; i++){ - Expr *pExpr = pList->a[i].pExpr; - assert( pExpr!=0 ); - m |= pExpr->flags; - } + assert( pList!=0 ); + for(i=0; inExpr; i++){ + Expr *pExpr = pList->a[i].pExpr; + assert( pExpr!=0 ); + m |= pExpr->flags; } return m; } +/* +** This is a SELECT-node callback for the expression walker that +** always "fails". By "fail" in this case, we mean set +** pWalker->eCode to zero and abort. +** +** This callback is used by multiple expression walkers. +*/ +SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ + UNUSED_PARAMETER(NotUsed); + pWalker->eCode = 0; + return WRC_Abort; +} + +/* +** Check the input string to see if it is "true" or "false" (in any case). +** +** If the string is.... Return +** "true" EP_IsTrue +** "false" EP_IsFalse +** anything else 0 +*/ +SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char *zIn){ + if( sqlite3StrICmp(zIn, "true")==0 ) return EP_IsTrue; + if( sqlite3StrICmp(zIn, "false")==0 ) return EP_IsFalse; + return 0; +} + + +/* +** If the input expression is an ID with the name "true" or "false" +** then convert it into an TK_TRUEFALSE term. Return non-zero if +** the conversion happened, and zero if the expression is unaltered. +*/ +SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){ + u32 v; + assert( pExpr->op==TK_ID || pExpr->op==TK_STRING ); + if( !ExprHasProperty(pExpr, EP_Quoted|EP_IntValue) + && (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0 + ){ + pExpr->op = TK_TRUEFALSE; + ExprSetProperty(pExpr, v); + return 1; + } + return 0; +} + +/* +** The argument must be a TK_TRUEFALSE Expr node. Return 1 if it is TRUE +** and 0 if it is FALSE. +*/ +SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){ + pExpr = sqlite3ExprSkipCollate((Expr*)pExpr); + assert( pExpr->op==TK_TRUEFALSE ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 + || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); + return pExpr->u.zToken[4]==0; +} + +/* +** If pExpr is an AND or OR expression, try to simplify it by eliminating +** terms that are always true or false. Return the simplified expression. +** Or return the original expression if no simplification is possible. +** +** Examples: +** +** (x<10) AND true => (x<10) +** (x<10) AND false => false +** (x<10) AND (y=22 OR false) => (x<10) AND (y=22) +** (x<10) AND (y=22 OR true) => (x<10) +** (y=22) OR true => true +*/ +SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){ + assert( pExpr!=0 ); + if( pExpr->op==TK_AND || pExpr->op==TK_OR ){ + Expr *pRight = sqlite3ExprSimplifiedAndOr(pExpr->pRight); + Expr *pLeft = sqlite3ExprSimplifiedAndOr(pExpr->pLeft); + if( ExprAlwaysTrue(pLeft) || ExprAlwaysFalse(pRight) ){ + pExpr = pExpr->op==TK_AND ? pRight : pLeft; + }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){ + pExpr = pExpr->op==TK_AND ? pLeft : pRight; + } + } + return pExpr; +} + + /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The @@ -92178,11 +104625,12 @@ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){ ** In all cases, the callbacks set Walker.eCode=0 and abort if the expression ** is found to not be a constant. ** -** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions -** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing -** an existing schema and 4 when processing a new statement. A bound -** parameter raises an error for new statements, but is silently converted -** to NULL for existing schemas. This allows sqlite_master tables that +** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT +** expressions in a CREATE TABLE statement. The Walker.eCode value is 5 +** when parsing an existing schema out of the sqlite_schema table and 4 +** when processing a new CREATE TABLE statement. A bound parameter raises +** an error for new statements, but is silently converted +** to NULL for existing schemas. This allows sqlite_schema tables that ** contain a bound parameter because they were generated by older versions ** of SQLite to be parsed by newer versions of SQLite without raising a ** malformed schema error. @@ -92202,13 +104650,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ ** and either pWalker->eCode==4 or 5 or the function has the ** SQLITE_FUNC_CONST flag. */ case TK_FUNCTION: - if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){ + if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc)) + && !ExprHasProperty(pExpr, EP_WinFunc) + ){ + if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL); return WRC_Continue; }else{ pWalker->eCode = 0; return WRC_Abort; } case TK_ID: + /* Convert "true" or "false" in a DEFAULT clause into the + ** appropriate TK_TRUEFALSE operator */ + if( sqlite3ExprIdToTrueFalse(pExpr) ){ + return WRC_Prune; + } + /* no break */ deliberate_fall_through case TK_COLUMN: case TK_AGG_FUNCTION: case TK_AGG_COLUMN: @@ -92216,17 +104673,26 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); + if( ExprHasProperty(pExpr, EP_FixedCol) && pWalker->eCode!=2 ){ + return WRC_Continue; + } if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ return WRC_Continue; - }else{ - pWalker->eCode = 0; - return WRC_Abort; } + /* no break */ deliberate_fall_through + case TK_IF_NULL_ROW: + case TK_REGISTER: + case TK_DOT: + testcase( pExpr->op==TK_REGISTER ); + testcase( pExpr->op==TK_IF_NULL_ROW ); + testcase( pExpr->op==TK_DOT ); + pWalker->eCode = 0; + return WRC_Abort; case TK_VARIABLE: if( pWalker->eCode==5 ){ /* Silently convert bound parameters that appear inside of CREATE ** statements into a NULL when parsing the CREATE statement text out - ** of the sqlite_master table */ + ** of the sqlite_schema table */ pExpr->op = TK_NULL; }else if( pWalker->eCode==4 ){ /* A bound parameter in a CREATE statement that originates from @@ -92234,24 +104700,21 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ pWalker->eCode = 0; return WRC_Abort; } - /* Fall through */ + /* no break */ deliberate_fall_through default: - testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */ - testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */ + testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */ + testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */ return WRC_Continue; } } -static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){ - UNUSED_PARAMETER(NotUsed); - pWalker->eCode = 0; - return WRC_Abort; -} static int exprIsConst(Expr *p, int initFlag, int iCur){ Walker w; - memset(&w, 0, sizeof(w)); w.eCode = initFlag; w.xExprCallback = exprNodeIsConstant; - w.xSelectCallback = selectNodeIsConstant; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif w.u.iCur = iCur; sqlite3WalkExpr(&w, p); return w.eCode; @@ -92270,10 +104733,17 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){ } /* -** Walk an expression tree. Return non-zero if the expression is constant -** that does no originate from the ON or USING clauses of a join. -** Return 0 if it involves variables or function calls or terms from -** an ON or USING clause. +** Walk an expression tree. Return non-zero if +** +** (1) the expression is constant, and +** (2) the expression does originate in the ON or USING clause +** of a LEFT JOIN, and +** (3) the expression does not contain any EP_FixedCol TK_COLUMN +** operands created by the constant propagation optimization. +** +** When this routine returns true, it indicates that the expression +** can be added to the pParse->pConstExpr list and evaluated once when +** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce(). */ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 2, 0); @@ -92289,10 +104759,81 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){ return exprIsConst(p, 3, iCur); } + /* -** Walk an expression tree. Return non-zero if the expression is constant -** or a function call with constant arguments. Return and 0 if there -** are any variables. +** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy(). +*/ +static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ + ExprList *pGroupBy = pWalker->u.pGroupBy; + int i; + + /* Check if pExpr is identical to any GROUP BY term. If so, consider + ** it constant. */ + for(i=0; inExpr; i++){ + Expr *p = pGroupBy->a[i].pExpr; + if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ + CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p); + if( sqlite3IsBinary(pColl) ){ + return WRC_Prune; + } + } + } + + /* Check if pExpr is a sub-select. If so, consider it variable. */ + if( ExprUseXSelect(pExpr) ){ + pWalker->eCode = 0; + return WRC_Abort; + } + + return exprNodeIsConstant(pWalker, pExpr); +} + +/* +** Walk the expression tree passed as the first argument. Return non-zero +** if the expression consists entirely of constants or copies of terms +** in pGroupBy that sort with the BINARY collation sequence. +** +** This routine is used to determine if a term of the HAVING clause can +** be promoted into the WHERE clause. In order for such a promotion to work, +** the value of the HAVING clause term must be the same for all members of +** a "group". The requirement that the GROUP BY term must be BINARY +** assumes that no other collating sequence will have a finer-grained +** grouping than binary. In other words (A=B COLLATE binary) implies +** A=B in every other collating sequence. The requirement that the +** GROUP BY be BINARY is stricter than necessary. It would also work +** to promote HAVING clauses that use the same alternative collating +** sequence as the GROUP BY term, but that is much harder to check, +** alternative collating sequences are uncommon, and this is only an +** optimization, so we take the easy way out and simply require the +** GROUP BY to use the BINARY collating sequence. +*/ +SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){ + Walker w; + w.eCode = 1; + w.xExprCallback = exprNodeIsConstantOrGroupBy; + w.xSelectCallback = 0; + w.u.pGroupBy = pGroupBy; + w.pParse = pParse; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + +/* +** Walk an expression tree for the DEFAULT field of a column definition +** in a CREATE TABLE statement. Return non-zero if the expression is +** acceptable for use as a DEFAULT. That is to say, return non-zero if +** the expression is constant or a function call with constant arguments. +** Return and 0 if there are any variables. +** +** isInit is true when parsing from sqlite_schema. isInit is false when +** processing a new CREATE TABLE statement. When isInit is true, parameters +** (such as ? or $abc) in the expression are converted into NULL. When +** isInit is false, parameters raise an error. Parameters should not be +** allowed in a CREATE TABLE statement, but some legacy versions of SQLite +** allowed it, so we need to support it when reading sqlite_schema for +** backwards compatibility. +** +** If isInit is true, set EP_FromDDL on every TK_FUNCTION node. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is @@ -92310,10 +104851,12 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ */ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ Walker w; - memset(&w, 0, sizeof(w)); w.eCode = 1; w.xExprCallback = sqlite3ExprWalkNoop; - w.xSelectCallback = selectNodeIsConstant; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif sqlite3WalkExpr(&w, p); return w.eCode==0; } @@ -92325,8 +104868,9 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ ** in *pValue. If the expression is not an integer or if it is too big ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ -SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ +SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue){ int rc = 0; + if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */ /* If an expression is an integer literal that fits in a signed 32-bit ** integer, then the EP_IntValue flag will have already been set */ @@ -92343,9 +104887,9 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ break; } case TK_UMINUS: { - int v; + int v = 0; if( sqlite3ExprIsInteger(p->pLeft, &v) ){ - assert( v!=(-2147483647-1) ); + assert( ((unsigned int)v)!=0x80000000 ); *pValue = -v; rc = 1; } @@ -92360,7 +104904,7 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ ** Return FALSE if there is no chance that the expression can be NULL. ** ** If the expression might be NULL or if the expression is too complex -** to tell return TRUE. +** to tell return TRUE. ** ** This routine is used as an optimization, to skip OP_IsNull opcodes ** when we know that a value cannot be NULL. Hence, a false positive @@ -92372,7 +104916,11 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ */ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ u8 op; - while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } + assert( p!=0 ); + while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ + p = p->pLeft; + assert( p!=0 ); + } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ @@ -92382,9 +104930,12 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ case TK_BLOB: return 0; case TK_COLUMN: - assert( p->pTab!=0 ); + assert( ExprUseYTab(p) ); return ExprHasProperty(p, EP_CanBeNull) || - (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0); + p->y.pTab==0 || /* Reference to column of index on expression */ + (p->iColumn>=0 + && p->y.pTab->aCol!=0 /* Possible due to prior error */ + && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; } @@ -92402,27 +104953,30 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){ */ SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){ u8 op; + int unaryMinus = 0; if( aff==SQLITE_AFF_BLOB ) return 1; - while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } + while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ + if( p->op==TK_UMINUS ) unaryMinus = 1; + p = p->pLeft; + } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ case TK_INTEGER: { - return aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC; + return aff>=SQLITE_AFF_NUMERIC; } case TK_FLOAT: { - return aff==SQLITE_AFF_REAL || aff==SQLITE_AFF_NUMERIC; + return aff>=SQLITE_AFF_NUMERIC; } case TK_STRING: { - return aff==SQLITE_AFF_TEXT; + return !unaryMinus && aff==SQLITE_AFF_TEXT; } case TK_BLOB: { - return 1; + return !unaryMinus; } case TK_COLUMN: { assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */ - return p->iColumn<0 - && (aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC); + return aff>=SQLITE_AFF_NUMERIC && p->iColumn<0; } default: { return 0; @@ -92441,20 +104995,20 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){ } /* -** pX is the RHS of an IN operator. If pX is a SELECT statement +** pX is the RHS of an IN operator. If pX is a SELECT statement ** that can be simplified to a direct table access, then return ** a pointer to the SELECT statement. If pX is not a SELECT statement, ** or if the SELECT statement needs to be manifested into a transient ** table, then return NULL. */ #ifndef SQLITE_OMIT_SUBQUERY -static Select *isCandidateForInOpt(Expr *pX){ +static Select *isCandidateForInOpt(const Expr *pX){ Select *p; SrcList *pSrc; ExprList *pEList; Table *pTab; int i; - if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */ + if( !ExprUseXSelect(pX) ) return 0; /* Not a subquery */ if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */ p = pX->x.pSelect; if( p->pPrior ) return 0; /* Not a compound SELECT */ @@ -92465,7 +105019,6 @@ static Select *isCandidateForInOpt(Expr *pX){ } assert( p->pGroupBy==0 ); /* Has no GROUP BY clause */ if( p->pLimit ) return 0; /* Has no LIMIT clause */ - assert( p->pOffset==0 ); /* No LIMIT means no OFFSET */ if( p->pWhere ) return 0; /* Has no WHERE clause */ pSrc = p->pSrc; assert( pSrc!=0 ); @@ -92473,7 +105026,7 @@ static Select *isCandidateForInOpt(Expr *pX){ if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ pTab = pSrc->a[0].pTab; assert( pTab!=0 ); - assert( pTab->pSelect==0 ); /* FROM clause is not a view */ + assert( !IsView(pTab) ); /* FROM clause is not a view */ if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ pEList = p->pEList; assert( pEList!=0 ); @@ -92508,7 +105061,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ #ifndef SQLITE_OMIT_SUBQUERY /* -** The argument is an IN operator with a list (not a subquery) on the +** The argument is an IN operator with a list (not a subquery) on the ** right-hand side. Return TRUE if that list is constant. */ static int sqlite3InRhsIsConstant(Expr *pIn){ @@ -92555,22 +105108,21 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ ** pX->iTable made to point to the ephemeral table instead of an ** existing table. ** -** The inFlags parameter must contain exactly one of the bits -** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains -** IN_INDEX_MEMBERSHIP, then the generated table will be used for a -** fast membership test. When the IN_INDEX_LOOP bit is set, the -** IN index will be used to loop over all values of the RHS of the -** IN operator. +** The inFlags parameter must contain, at a minimum, one of the bits +** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains +** IN_INDEX_MEMBERSHIP, then the generated table will be used for a fast +** membership test. When the IN_INDEX_LOOP bit is set, the IN index will +** be used to loop over all values of the RHS of the IN operator. ** ** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate ** through the set members) then the b-tree must not contain duplicates. -** An epheremal table must be used unless the selected columns are guaranteed +** An epheremal table will be created unless the selected columns are guaranteed ** to be unique - either because it is an INTEGER PRIMARY KEY or due to ** a UNIQUE constraint or index. ** -** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used -** for fast set membership tests) then an epheremal table must -** be used unless is a single INTEGER PRIMARY KEY column or an +** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used +** for fast set membership tests) then an epheremal table must +** be used unless is a single INTEGER PRIMARY KEY column or an ** index can be found with the specified as its left-most. ** ** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and @@ -92582,7 +105134,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ ** ** When the b-tree is being used for membership tests, the calling function ** might need to know whether or not the RHS side of the IN operator -** contains a NULL. If prRhsHasNull is not a NULL pointer and +** contains a NULL. If prRhsHasNull is not a NULL pointer and ** if there is any chance that the (...) might contain a NULL value at ** runtime, then a register is allocated and the register number written ** to *prRhsHasNull. If there is no chance that the (...) contains a @@ -92607,10 +105159,11 @@ static int sqlite3InRhsIsConstant(Expr *pIn){ #ifndef SQLITE_OMIT_SUBQUERY SQLITE_PRIVATE int sqlite3FindInIndex( Parse *pParse, /* Parsing context */ - Expr *pX, /* The right-hand side (RHS) of the IN operator */ + Expr *pX, /* The IN expression */ u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */ int *prRhsHasNull, /* Register holding NULL status. See notes */ - int *aiMap /* Mapping from Index fields to RHS fields */ + int *aiMap, /* Mapping from Index fields to RHS fields */ + int *piTab /* OUT: index to use */ ){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ @@ -92621,12 +105174,12 @@ SQLITE_PRIVATE int sqlite3FindInIndex( assert( pX->op==TK_IN ); mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; - /* If the RHS of this IN(...) operator is a SELECT, and if it matters + /* If the RHS of this IN(...) operator is a SELECT, and if it matters ** whether or not the SELECT result contains NULL values, check whether - ** or not NULL is actually possible (it may not be, for example, due + ** or not NULL is actually possible (it may not be, for example, due ** to NOT NULL constraints in the schema). If no NULL values are possible, ** set prRhsHasNull to 0 before continuing. */ - if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){ + if( prRhsHasNull && ExprUseXSelect(pX) ){ int i; ExprList *pEList = pX->x.pSelect->pEList; for(i=0; inExpr; i++){ @@ -92638,12 +105191,12 @@ SQLITE_PRIVATE int sqlite3FindInIndex( } /* Check to see if an existing table or index can be used to - ** satisfy the query. This is preferable to generating a new + ** satisfy the query. This is preferable to generating a new ** ephemeral table. */ if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){ sqlite3 *db = pParse->db; /* Database connection */ Table *pTab; /* Table . */ - i16 iDb; /* Database idx for pTab */ + int iDb; /* Database idx for pTab */ ExprList *pEList = p->pEList; int nExpr = pEList->nExpr; @@ -92654,6 +105207,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( /* Code an OP_Transaction and OP_TableLock for
            . */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDb>=0 && iDbtnum, 0, pTab->zName); @@ -92665,14 +105219,15 @@ SQLITE_PRIVATE int sqlite3FindInIndex( sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; - + ExplainQueryPlan((pParse, 0, + "USING ROWID SEARCH ON TABLE %s FOR IN-OPERATOR",pTab->zName)); sqlite3VdbeJumpHere(v, iAddr); }else{ Index *pIdx; /* Iterator variable */ int affinity_ok = 1; int i; - /* Check that the affinity that will be used to perform each + /* Check that the affinity that will be used to perform each ** comparison is the same as the affinity of each column in table ** on the RHS of the IN operator. If it not, it is not possible to ** use any index of the RHS table. */ @@ -92704,6 +105259,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( Bitmask colUsed; /* Columns of the index used */ Bitmask mCol; /* Mask for the current column */ if( pIdx->nColumnpPartIdxWhere!=0 ) continue; /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute ** BITMASK(nExpr) without overflowing */ testcase( pIdx->nColumn==BMS-2 ); @@ -92716,14 +105272,14 @@ SQLITE_PRIVATE int sqlite3FindInIndex( continue; /* This index is not unique over the IN RHS columns */ } } - + colUsed = 0; /* Columns of index used so far */ for(i=0; ipLeft, i); Expr *pRhs = pEList->a[i].pExpr; CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; - + assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; @@ -92739,26 +105295,23 @@ SQLITE_PRIVATE int sqlite3FindInIndex( colUsed |= mCol; if( aiMap ) aiMap[i] = j; } - + assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) ); if( colUsed==(MASKBIT(nExpr)-1) ){ /* If we reach this point, that means the index pIdx is usable */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); -#ifndef SQLITE_OMIT_EXPLAIN - sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0, - sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName), - P4_DYNAMIC); -#endif + ExplainQueryPlan((pParse, 0, + "USING INDEX %s FOR IN-OPERATOR",pIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; - + if( prRhsHasNull ){ #ifdef SQLITE_ENABLE_COLUMN_USED_MASK i64 mask = (1<nMem; @@ -92782,7 +105335,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) - && !ExprHasProperty(pX, EP_xIsSelect) + && ExprUseXList(pX) && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) ){ eType = IN_INDEX_NOOP; @@ -92797,16 +105350,15 @@ SQLITE_PRIVATE int sqlite3FindInIndex( eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; - if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ - eType = IN_INDEX_ROWID; - } }else if( prRhsHasNull ){ *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } - sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); + assert( pX->op==TK_IN ); + sqlite3CodeRhsOfIN(pParse, pX, iTab); + if( rMayHaveNull ){ + sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); + } pParse->nQueryLoop = savedNQueryLoop; - }else{ - pX->iTable = iTab; } if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){ @@ -92814,27 +105366,28 @@ SQLITE_PRIVATE int sqlite3FindInIndex( n = sqlite3ExprVectorSize(pX->pLeft); for(i=0; ipLeft; int nVal = sqlite3ExprVectorSize(pLeft); - Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0; + Select *pSelect = ExprUseXSelect(pExpr) ? pExpr->x.pSelect : 0; char *zRet; assert( pExpr->op==TK_IN ); - zRet = sqlite3DbMallocZero(pParse->db, nVal+1); + zRet = sqlite3DbMallocRaw(pParse->db, nVal+1); if( zRet ){ int i; for(i=0; inErr==0 ){ + const char *zFmt = "sub-select returns %d columns - expected %d"; + sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); + } } #endif /* ** Expression pExpr is a vector that has been used in a context where -** it is not permitted. If pExpr is a sub-select vector, this routine +** it is not permitted. If pExpr is a sub-select vector, this routine ** loads the Parse object with a message of the form: ** ** "sub-select returns N columns - expected 1" @@ -92875,10 +105430,10 @@ SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpec ** Or, if it is a regular scalar vector: ** ** "row value misused" -*/ +*/ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ #ifndef SQLITE_OMIT_SUBQUERY - if( pExpr->flags & EP_xIsSelect ){ + if( ExprUseXSelect(pExpr) ){ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); }else #endif @@ -92887,283 +105442,349 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ } } +#ifndef SQLITE_OMIT_SUBQUERY /* -** Generate code for scalar subqueries used as a subquery expression, EXISTS, -** or IN operators. Examples: +** Generate code that will construct an ephemeral table containing all terms +** in the RHS of an IN operator. The IN operator can be in either of two +** forms: ** -** (SELECT a FROM b) -- subquery -** EXISTS (SELECT a FROM b) -- EXISTS subquery ** x IN (4,5,11) -- IN operator with list on right-hand side ** x IN (SELECT a FROM b) -- IN operator with subquery on the right ** -** The pExpr parameter describes the expression that contains the IN -** operator or subquery. -** -** If parameter isRowid is non-zero, then expression pExpr is guaranteed -** to be of the form " IN (?, ?, ?)", where is a reference -** to some integer key column of a table B-Tree. In this case, use an -** intkey B-Tree to store the set of IN(...) values instead of the usual -** (slower) variable length keys B-Tree. -** -** If rMayHaveNull is non-zero, that means that the operation is an IN -** (not a SELECT or EXISTS) and that the RHS might contains NULLs. -** All this routine does is initialize the register given by rMayHaveNull -** to NULL. Calling routines will take care of changing this register -** value to non-NULL if the RHS is NULL-free. -** -** For a SELECT or EXISTS operator, return the register that holds the -** result. For a multi-column SELECT, the result is stored in a contiguous -** array of registers and the return value is the register of the left-most -** result column. Return 0 for IN operators or if an error occurs. -*/ -#ifndef SQLITE_OMIT_SUBQUERY -SQLITE_PRIVATE int sqlite3CodeSubselect( +** The pExpr parameter is the IN operator. The cursor number for the +** constructed ephermeral table is returned. The first time the ephemeral +** table is computed, the cursor number is also stored in pExpr->iTable, +** however the cursor number returned might not be the same, as it might +** have been duplicated using OP_OpenDup. +** +** If the LHS expression ("x" in the examples) is a column value, or +** the SELECT statement returns a column value, then the affinity of that +** column is used to build the index keys. If both 'x' and the +** SELECT... statement are columns, then numeric affinity is used +** if either column has NUMERIC or INTEGER affinity. If neither +** 'x' nor the SELECT... statement are columns, then numeric affinity +** is used. +*/ +SQLITE_PRIVATE void sqlite3CodeRhsOfIN( Parse *pParse, /* Parsing context */ - Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ - int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ - int isRowid /* If true, LHS of IN operator is a rowid */ + Expr *pExpr, /* The IN operator */ + int iTab /* Use this cursor number */ ){ - int jmpIfDynamic = -1; /* One-time test address */ - int rReg = 0; /* Register storing resulting */ - Vdbe *v = sqlite3GetVdbe(pParse); - if( NEVER(v==0) ) return 0; - sqlite3ExprCachePush(pParse); + int addrOnce = 0; /* Address of the OP_Once instruction at top */ + int addr; /* Address of OP_OpenEphemeral instruction */ + Expr *pLeft; /* the LHS of the IN operator */ + KeyInfo *pKeyInfo = 0; /* Key information */ + int nVal; /* Size of vector pLeft */ + Vdbe *v; /* The prepared statement under construction */ - /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it + v = pParse->pVdbe; + assert( v!=0 ); + + /* The evaluation of the IN must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger ** - ** If all of the above are false, then we can run this code just once - ** save the results, and reuse the same result on subsequent invocations. + ** If all of the above are false, then we can compute the RHS just once + ** and reuse it many names. */ - if( !ExprHasProperty(pExpr, EP_VarSelect) ){ - jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); - } + if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){ + /* Reuse of the RHS is allowed */ + /* If this routine has already been coded, but the previous code + ** might not have been invoked yet, so invoke it now as a subroutine. + */ + if( ExprHasProperty(pExpr, EP_Subrtn) ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + if( ExprUseXSelect(pExpr) ){ + ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", + pExpr->x.pSelect->selId)); + } + assert( ExprUseYSub(pExpr) ); + sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, + pExpr->y.sub.iAddr); + sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); + sqlite3VdbeJumpHere(v, addrOnce); + return; + } -#ifndef SQLITE_OMIT_EXPLAIN - if( pParse->explain==2 ){ - char *zMsg = sqlite3MPrintf(pParse->db, "EXECUTE %s%s SUBQUERY %d", - jmpIfDynamic>=0?"":"CORRELATED ", - pExpr->op==TK_IN?"LIST":"SCALAR", - pParse->iNextSelectId - ); - sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); - } -#endif + /* Begin coding the subroutine */ + assert( !ExprUseYWin(pExpr) ); + ExprSetProperty(pExpr, EP_Subrtn); + assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); + pExpr->y.sub.regReturn = ++pParse->nMem; + pExpr->y.sub.iAddr = + sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1; + VdbeComment((v, "return address")); - switch( pExpr->op ){ - case TK_IN: { - int addr; /* Address of OP_OpenEphemeral instruction */ - Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ - KeyInfo *pKeyInfo = 0; /* Key information */ - int nVal; /* Size of vector pLeft */ - - nVal = sqlite3ExprVectorSize(pLeft); - assert( !isRowid || nVal==1 ); - - /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' - ** expression it is handled the same way. An ephemeral table is - ** filled with index keys representing the results from the - ** SELECT or the . - ** - ** If the 'x' expression is a column value, or the SELECT... - ** statement returns a column value, then the affinity of that - ** column is used to build the index keys. If both 'x' and the - ** SELECT... statement are columns, then numeric affinity is used - ** if either column has NUMERIC or INTEGER affinity. If neither - ** 'x' nor the SELECT... statement are columns, then numeric affinity - ** is used. - */ - pExpr->iTable = pParse->nTab++; - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, - pExpr->iTable, (isRowid?0:nVal)); - pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1); + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - /* Case 1: expr IN (SELECT ...) - ** - ** Generate code to write the results of the select into the temporary - ** table allocated and opened above. - */ - Select *pSelect = pExpr->x.pSelect; - ExprList *pEList = pSelect->pEList; - - assert( !isRowid ); - /* If the LHS and RHS of the IN operator do not match, that - ** error will have been caught long before we reach this point. */ - if( ALWAYS(pEList->nExpr==nVal) ){ - SelectDest dest; - int i; - sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); - dest.zAffSdst = exprINAffinity(pParse, pExpr); - assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); - pSelect->iLimit = 0; - testcase( pSelect->selFlags & SF_Distinct ); - testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ - if( sqlite3Select(pParse, pSelect, &dest) ){ - sqlite3DbFree(pParse->db, dest.zAffSdst); - sqlite3KeyInfoUnref(pKeyInfo); - return 0; - } - sqlite3DbFree(pParse->db, dest.zAffSdst); - assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ - assert( pEList!=0 ); - assert( pEList->nExpr>0 ); - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( - pParse, p, pEList->a[i].pExpr - ); - } - } - }else if( ALWAYS(pExpr->x.pList!=0) ){ - /* Case 2: expr IN (exprlist) - ** - ** For each expression, build an index key from the evaluation and - ** store it in the temporary table. If is a column, then use - ** that columns affinity when building index keys. If is not - ** a column, use numeric affinity. - */ - char affinity; /* Affinity of the LHS of the IN */ - int i; - ExprList *pList = pExpr->x.pList; - struct ExprList_item *pItem; - int r1, r2, r3; + /* Check to see if this is a vector IN operator */ + pLeft = pExpr->pLeft; + nVal = sqlite3ExprVectorSize(pLeft); - affinity = sqlite3ExprAffinity(pLeft); - if( !affinity ){ - affinity = SQLITE_AFF_BLOB; - } - if( pKeyInfo ){ - assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); - pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - } + /* Construct the ephemeral table that will contain the content of + ** RHS of the IN operator. + */ + pExpr->iTable = iTab; + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal); +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS + if( ExprUseXSelect(pExpr) ){ + VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId)); + }else{ + VdbeComment((v, "RHS of IN operator")); + } +#endif + pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); - /* Loop through each expression in . */ - r1 = sqlite3GetTempReg(pParse); - r2 = sqlite3GetTempReg(pParse); - if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2); - for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ - Expr *pE2 = pItem->pExpr; - int iValToIns; - - /* If the expression is not constant then we will need to - ** disable the test that was generated above that makes sure - ** this code only executes once. Because for a non-constant - ** expression we need to rerun this code each time. - */ - if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){ - sqlite3VdbeChangeToNoop(v, jmpIfDynamic); - jmpIfDynamic = -1; - } + if( ExprUseXSelect(pExpr) ){ + /* Case 1: expr IN (SELECT ...) + ** + ** Generate code to write the results of the select into the temporary + ** table allocated and opened above. + */ + Select *pSelect = pExpr->x.pSelect; + ExprList *pEList = pSelect->pEList; - /* Evaluate the expression and insert it into the temp table */ - if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){ - sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns); - }else{ - r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); - if( isRowid ){ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, - sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); - }else{ - sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); - sqlite3ExprCacheAffinityChange(pParse, r3, 1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1); - } - } - } - sqlite3ReleaseTempReg(pParse, r1); - sqlite3ReleaseTempReg(pParse, r2); + ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d", + addrOnce?"":"CORRELATED ", pSelect->selId + )); + /* If the LHS and RHS of the IN operator do not match, that + ** error will have been caught long before we reach this point. */ + if( ALWAYS(pEList->nExpr==nVal) ){ + Select *pCopy; + SelectDest dest; + int i; + int rc; + sqlite3SelectDestInit(&dest, SRT_Set, iTab); + dest.zAffSdst = exprINAffinity(pParse, pExpr); + pSelect->iLimit = 0; + testcase( pSelect->selFlags & SF_Distinct ); + testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ + pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); + rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); + sqlite3SelectDelete(pParse->db, pCopy); + sqlite3DbFree(pParse->db, dest.zAffSdst); + if( rc ){ + sqlite3KeyInfoUnref(pKeyInfo); + return; } - if( pKeyInfo ){ - sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); + assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ + assert( pEList!=0 ); + assert( pEList->nExpr>0 ); + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + for(i=0; iaColl[i] = sqlite3BinaryCompareCollSeq( + pParse, p, pEList->a[i].pExpr + ); } - break; } - - case TK_EXISTS: - case TK_SELECT: - default: { - /* Case 3: (SELECT ... FROM ...) - ** or: EXISTS(SELECT ... FROM ...) - ** - ** For a SELECT, generate code to put the values for all columns of - ** the first row into an array of registers and return the index of - ** the first register. - ** - ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists) - ** into a register and return that register number. - ** - ** In both cases, the query is augmented with "LIMIT 1". Any - ** preexisting limit is discarded in place of the new LIMIT 1. + }else if( ALWAYS(pExpr->x.pList!=0) ){ + /* Case 2: expr IN (exprlist) + ** + ** For each expression, build an index key from the evaluation and + ** store it in the temporary table. If is a column, then use + ** that columns affinity when building index keys. If is not + ** a column, use numeric affinity. + */ + char affinity; /* Affinity of the LHS of the IN */ + int i; + ExprList *pList = pExpr->x.pList; + struct ExprList_item *pItem; + int r1, r2; + affinity = sqlite3ExprAffinity(pLeft); + if( affinity<=SQLITE_AFF_NONE ){ + affinity = SQLITE_AFF_BLOB; + }else if( affinity==SQLITE_AFF_REAL ){ + affinity = SQLITE_AFF_NUMERIC; + } + if( pKeyInfo ){ + assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); + pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + } + + /* Loop through each expression in . */ + r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3GetTempReg(pParse); + for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ + Expr *pE2 = pItem->pExpr; + + /* If the expression is not constant then we will need to + ** disable the test that was generated above that makes sure + ** this code only executes once. Because for a non-constant + ** expression we need to rerun this code each time. */ - Select *pSel; /* SELECT statement to encode */ - SelectDest dest; /* How to deal with SELECT result */ - int nReg; /* Registers to allocate */ - - testcase( pExpr->op==TK_EXISTS ); - testcase( pExpr->op==TK_SELECT ); - assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); - assert( ExprHasProperty(pExpr, EP_xIsSelect) ); - - pSel = pExpr->x.pSelect; - nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; - sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); - pParse->nMem += nReg; - if( pExpr->op==TK_SELECT ){ - dest.eDest = SRT_Mem; - dest.iSdst = dest.iSDParm; - dest.nSdst = nReg; - sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); - VdbeComment((v, "Init subquery result")); - }else{ - dest.eDest = SRT_Exists; - sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm); - VdbeComment((v, "Init EXISTS result")); - } - sqlite3ExprDelete(pParse->db, pSel->pLimit); - pSel->pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER, - &sqlite3IntTokens[1], 0); - pSel->iLimit = 0; - pSel->selFlags &= ~SF_MultiValue; - if( sqlite3Select(pParse, pSel, &dest) ){ - return 0; + if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ + sqlite3VdbeChangeToNoop(v, addrOnce); + ExprClearProperty(pExpr, EP_Subrtn); + addrOnce = 0; } - rReg = dest.iSDParm; - ExprSetVVAProperty(pExpr, EP_NoReduce); - break; + + /* Evaluate the expression and insert it into the temp table */ + sqlite3ExprCode(pParse, pE2, r1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1); } + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempReg(pParse, r2); + } + if( pKeyInfo ){ + sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); } + if( addrOnce ){ + sqlite3VdbeJumpHere(v, addrOnce); + /* Subroutine return */ + assert( ExprUseYSub(pExpr) ); + sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); + sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); + sqlite3ClearTempRegCache(pParse); + } +} +#endif /* SQLITE_OMIT_SUBQUERY */ - if( rHasNullFlag ){ - sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); +/* +** Generate code for scalar subqueries used as a subquery expression +** or EXISTS operator: +** +** (SELECT a FROM b) -- subquery +** EXISTS (SELECT a FROM b) -- EXISTS subquery +** +** The pExpr parameter is the SELECT or EXISTS operator to be coded. +** +** Return the register that holds the result. For a multi-column SELECT, +** the result is stored in a contiguous array of registers and the +** return value is the register of the left-most result column. +** Return 0 if an error occurs. +*/ +#ifndef SQLITE_OMIT_SUBQUERY +SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ + int addrOnce = 0; /* Address of OP_Once at top of subroutine */ + int rReg = 0; /* Register storing resulting */ + Select *pSel; /* SELECT statement to encode */ + SelectDest dest; /* How to deal with SELECT result */ + int nReg; /* Registers to allocate */ + Expr *pLimit; /* New limit expression */ + + Vdbe *v = pParse->pVdbe; + assert( v!=0 ); + if( pParse->nErr ) return 0; + testcase( pExpr->op==TK_EXISTS ); + testcase( pExpr->op==TK_SELECT ); + assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); + assert( ExprUseXSelect(pExpr) ); + pSel = pExpr->x.pSelect; + + /* If this routine has already been coded, then invoke it as a + ** subroutine. */ + if( ExprHasProperty(pExpr, EP_Subrtn) ){ + ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId)); + assert( ExprUseYSub(pExpr) ); + sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, + pExpr->y.sub.iAddr); + return pExpr->iTable; + } + + /* Begin coding the subroutine */ + assert( !ExprUseYWin(pExpr) ); + assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ); + ExprSetProperty(pExpr, EP_Subrtn); + pExpr->y.sub.regReturn = ++pParse->nMem; + pExpr->y.sub.iAddr = + sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1; + VdbeComment((v, "return address")); + + + /* The evaluation of the EXISTS/SELECT must be repeated every time it + ** is encountered if any of the following is true: + ** + ** * The right-hand side is a correlated subquery + ** * The right-hand side is an expression list containing variables + ** * We are inside a trigger + ** + ** If all of the above are false, then we can run this code just once + ** save the results, and reuse the same result on subsequent invocations. + */ + if( !ExprHasProperty(pExpr, EP_VarSelect) ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } - if( jmpIfDynamic>=0 ){ - sqlite3VdbeJumpHere(v, jmpIfDynamic); + /* For a SELECT, generate code to put the values for all columns of + ** the first row into an array of registers and return the index of + ** the first register. + ** + ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists) + ** into a register and return that register number. + ** + ** In both cases, the query is augmented with "LIMIT 1". Any + ** preexisting limit is discarded in place of the new LIMIT 1. + */ + ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d", + addrOnce?"":"CORRELATED ", pSel->selId)); + nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; + sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); + pParse->nMem += nReg; + if( pExpr->op==TK_SELECT ){ + dest.eDest = SRT_Mem; + dest.iSdst = dest.iSDParm; + dest.nSdst = nReg; + sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1); + VdbeComment((v, "Init subquery result")); + }else{ + dest.eDest = SRT_Exists; + sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm); + VdbeComment((v, "Init EXISTS result")); + } + if( pSel->pLimit ){ + /* The subquery already has a limit. If the pre-existing limit is X + ** then make the new limit X<>0 so that the new limit is either 1 or 0 */ + sqlite3 *db = pParse->db; + pLimit = sqlite3Expr(db, TK_INTEGER, "0"); + if( pLimit ){ + pLimit->affExpr = SQLITE_AFF_NUMERIC; + pLimit = sqlite3PExpr(pParse, TK_NE, + sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit); + } + sqlite3ExprDelete(db, pSel->pLimit->pLeft); + pSel->pLimit->pLeft = pLimit; + }else{ + /* If there is no pre-existing limit add a limit of 1 */ + pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1"); + pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); + } + pSel->iLimit = 0; + if( sqlite3Select(pParse, pSel, &dest) ){ + pExpr->op2 = pExpr->op; + pExpr->op = TK_ERROR; + return 0; + } + pExpr->iTable = rReg = dest.iSDParm; + ExprSetVVAProperty(pExpr, EP_NoReduce); + if( addrOnce ){ + sqlite3VdbeJumpHere(v, addrOnce); } - sqlite3ExprCachePop(pParse); + /* Subroutine return */ + assert( ExprUseYSub(pExpr) ); + sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); + sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); + sqlite3ClearTempRegCache(pParse); return rReg; } #endif /* SQLITE_OMIT_SUBQUERY */ #ifndef SQLITE_OMIT_SUBQUERY /* -** Expr pIn is an IN(...) expression. This function checks that the -** sub-select on the RHS of the IN() operator has the same number of -** columns as the vector on the LHS. Or, if the RHS of the IN() is not +** Expr pIn is an IN(...) expression. This function checks that the +** sub-select on the RHS of the IN() operator has the same number of +** columns as the vector on the LHS. Or, if the RHS of the IN() is not ** a sub-query, that the LHS is a vector of size 1. */ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ int nVector = sqlite3ExprVectorSize(pIn->pLeft); - if( (pIn->flags & EP_xIsSelect) ){ + if( ExprUseXSelect(pIn) && !pParse->db->mallocFailed ){ if( nVector!=pIn->x.pSelect->pEList->nExpr ){ sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector); return 1; @@ -93183,18 +105804,18 @@ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){ ** x IN (SELECT ...) ** x IN (value, value, ...) ** -** The left-hand side (LHS) is a scalar or vector expression. The +** The left-hand side (LHS) is a scalar or vector expression. The ** right-hand side (RHS) is an array of zero or more scalar values, or a ** subquery. If the RHS is a subquery, the number of result columns must ** match the number of columns in the vector on the LHS. If the RHS is -** a list of values, the LHS must be a scalar. +** a list of values, the LHS must be a scalar. ** ** The IN operator is true if the LHS value is contained within the RHS. -** The result is false if the LHS is definitely not in the RHS. The -** result is NULL if the presence of the LHS in the RHS cannot be +** The result is false if the LHS is definitely not in the RHS. The +** result is NULL if the presence of the LHS in the RHS cannot be ** determined due to NULLs. ** -** This routine generates code that jumps to destIfFalse if the LHS is not +** This routine generates code that jumps to destIfFalse if the LHS is not ** contained within the RHS. If due to NULLs we cannot determine if the LHS ** is contained in the RHS then jump to destIfNull. If the LHS is contained ** within the RHS then fall through. @@ -93223,8 +105844,11 @@ static void sqlite3ExprCodeIN( int destStep6 = 0; /* Start of code for Step 6 */ int addrTruthOp; /* Address of opcode that determines the IN is true */ int destNotNull; /* Jump here if a comparison is not true in step 6 */ - int addrTop; /* Top of the step-6 loop */ + int addrTop; /* Top of the step-6 loop */ + int iTab = 0; /* Index to use */ + u8 okConstFactor = pParse->okConstFactor; + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); pLeft = pExpr->pLeft; if( sqlite3ExprCheckIN(pParse, pExpr) ) return; zAff = exprINAffinity(pParse, pExpr); @@ -93235,7 +105859,7 @@ static void sqlite3ExprCodeIN( if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; /* Attempt to compute the RHS. After this step, if anything other than - ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable + ** IN_INDEX_NOOP is returned, the table opened with cursor iTab ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned, ** the RHS has not yet been coded. */ v = pParse->pVdbe; @@ -93243,10 +105867,11 @@ static void sqlite3ExprCodeIN( VdbeNoopComment((v, "begin IN expr")); eType = sqlite3FindInIndex(pParse, pExpr, IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, - destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap); + destIfFalse==destIfNull ? 0 : &rRhsHasNull, + aiMap, &iTab); assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH - || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC + || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC ); #ifdef SQLITE_DEBUG /* Confirm that aiMap[] contains nVector integer values between 0 and @@ -93258,17 +105883,22 @@ static void sqlite3ExprCodeIN( } #endif - /* Code the LHS, the from " IN (...)". If the LHS is a - ** vector, then it is stored in an array of nVector registers starting + /* Code the LHS, the from " IN (...)". If the LHS is a + ** vector, then it is stored in an array of nVector registers starting ** at r1. ** ** sqlite3FindInIndex() might have reordered the fields of the LHS vector ** so that the fields are in the same order as an existing index. The ** aiMap[] array contains a mapping from the original LHS field order to ** the field order that matches the RHS index. - */ - sqlite3ExprCachePush(pParse); + ** + ** Avoid factoring the LHS of the IN(...) expression out of the loop, + ** even if it is constant, as OP_Affinity may be used on the register + ** by code generated below. */ + assert( pParse->okConstFactor==okConstFactor ); + pParse->okConstFactor = 0; rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); + pParse->okConstFactor = okConstFactor; for(i=0; ix.pList; - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - int labelOk = sqlite3VdbeMakeLabel(v); + ExprList *pList; + CollSeq *pColl; + int labelOk = sqlite3VdbeMakeLabel(pParse); int r2, regToFree; int regCkNull = 0; int ii; - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + assert( ExprUseXList(pExpr) ); + pList = pExpr->x.pList; + pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); if( destIfNull!=destIfFalse ){ regCkNull = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull); @@ -93304,19 +105936,25 @@ static void sqlite3ExprCodeIN( if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){ sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); } + sqlite3ReleaseTempReg(pParse, regToFree); if( iinExpr-1 || destIfNull!=destIfFalse ){ - sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2, + int op = rLhs!=r2 ? OP_Eq : OP_NotNull; + sqlite3VdbeAddOp4(v, op, rLhs, labelOk, r2, (void*)pColl, P4_COLLSEQ); - VdbeCoverageIf(v, iinExpr-1); - VdbeCoverageIf(v, ii==pList->nExpr-1); + VdbeCoverageIf(v, iinExpr-1 && op==OP_Eq); + VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_Eq); + VdbeCoverageIf(v, iinExpr-1 && op==OP_NotNull); + VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_NotNull); sqlite3VdbeChangeP5(v, zAff[0]); }else{ + int op = rLhs!=r2 ? OP_Ne : OP_IsNull; assert( destIfNull==destIfFalse ); - sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2, - (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); + sqlite3VdbeAddOp4(v, op, rLhs, destIfFalse, r2, + (void*)pColl, P4_COLLSEQ); + VdbeCoverageIf(v, op==OP_Ne); + VdbeCoverageIf(v, op==OP_IsNull); sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL); } - sqlite3ReleaseTempReg(pParse, regToFree); } if( regCkNull ){ sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); @@ -93334,10 +105972,11 @@ static void sqlite3ExprCodeIN( if( destIfNull==destIfFalse ){ destStep2 = destIfFalse; }else{ - destStep2 = destStep6 = sqlite3VdbeMakeLabel(v); + destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse); } for(i=0; ipLeft, i); + if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); VdbeCoverage(v); @@ -93352,19 +105991,19 @@ static void sqlite3ExprCodeIN( /* In this case, the RHS is the ROWID of table b-tree and so we also ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4 ** into a single opcode. */ - sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs); VdbeCoverage(v); addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ }else{ sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ - sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, + sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse, rLhs, nVector); VdbeCoverage(v); goto sqlite3ExprCodeIN_finished; } /* Ordinary Step 3, for the case where FALSE and NULL are distinct */ - addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, + addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, iTab, 0, rLhs, nVector); VdbeCoverage(v); } @@ -93377,7 +106016,7 @@ static void sqlite3ExprCodeIN( } /* Step 5. If we do not care about the difference between NULL and - ** FALSE, then just return false. + ** FALSE, then just return false. */ if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse); @@ -93389,10 +106028,10 @@ static void sqlite3ExprCodeIN( ** of the RHS. */ if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6); - addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse); VdbeCoverage(v); if( nVector>1 ){ - destNotNull = sqlite3VdbeMakeLabel(v); + destNotNull = sqlite3VdbeMakeLabel(pParse); }else{ /* For nVector==1, combine steps 6 and 7 by immediately returning ** FALSE if the first comparison is not NULL */ @@ -93404,7 +106043,7 @@ static void sqlite3ExprCodeIN( int r3 = sqlite3GetTempReg(pParse); p = sqlite3VectorFieldSubexpr(pLeft, i); pColl = sqlite3ExprCollSeq(pParse, p); - sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3); + sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3); sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); @@ -93413,7 +106052,7 @@ static void sqlite3ExprCodeIN( sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); if( nVector>1 ){ sqlite3VdbeResolveLabel(v, destNotNull); - sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1); + sqlite3VdbeAddOp2(v, OP_Next, iTab, addrTop+1); VdbeCoverage(v); /* Step 7: If we reach this point, we know that the result must @@ -93426,7 +106065,6 @@ static void sqlite3ExprCodeIN( sqlite3ExprCodeIN_finished: if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); - sqlite3ExprCachePop(pParse); VdbeComment((v, "end IN expr")); sqlite3ExprCodeIN_oom_error: sqlite3DbFree(pParse->db, aiMap); @@ -93439,7 +106077,7 @@ static void sqlite3ExprCodeIN( ** Generate an instruction that will put the floating point ** value described by z[0..n-1] into register iMem. ** -** The z[] string will probably not be zero-terminated. But the +** The z[] string will probably not be zero-terminated. But the ** z[n] character is guaranteed to be something that does not look ** like the continuation of the number. */ @@ -93474,13 +106112,14 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ const char *z = pExpr->u.zToken; assert( z!=0 ); c = sqlite3DecOrHexToI64(z, &value); - if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){ + if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){ #ifdef SQLITE_OMIT_FLOATING_POINT - sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); + sqlite3ErrorMsg(pParse, "oversized integer: %s%#T", negFlag?"-":"",pExpr); #else #ifndef SQLITE_OMIT_HEX_INTEGER if( sqlite3_strnicmp(z,"0x",2)==0 ){ - sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z); + sqlite3ErrorMsg(pParse, "hex literal too big: %s%#T", + negFlag?"-":"",pExpr); }else #endif { @@ -93488,151 +106127,12 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ } #endif }else{ - if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } + if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); } } } -/* -** Erase column-cache entry number i -*/ -static void cacheEntryClear(Parse *pParse, int i){ - if( pParse->aColCache[i].tempReg ){ - if( pParse->nTempRegaTempReg) ){ - pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; - } - } - pParse->nColCache--; - if( inColCache ){ - pParse->aColCache[i] = pParse->aColCache[pParse->nColCache]; - } -} - - -/* -** Record in the column cache that a particular column from a -** particular table is stored in a particular register. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){ - int i; - int minLru; - int idxLru; - struct yColCache *p; - - /* Unless an error has occurred, register numbers are always positive. */ - assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed ); - assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */ - - /* The SQLITE_ColumnCache flag disables the column cache. This is used - ** for testing only - to verify that SQLite always gets the same answer - ** with and without the column cache. - */ - if( OptimizationDisabled(pParse->db, SQLITE_ColumnCache) ) return; - - /* First replace any existing entry. - ** - ** Actually, the way the column cache is currently used, we are guaranteed - ** that the object will never already be in cache. Verify this guarantee. - */ -#ifndef NDEBUG - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - assert( p->iTable!=iTab || p->iColumn!=iCol ); - } -#endif - - /* If the cache is already full, delete the least recently used entry */ - if( pParse->nColCache>=SQLITE_N_COLCACHE ){ - minLru = 0x7fffffff; - idxLru = -1; - for(i=0, p=pParse->aColCache; ilrulru; - } - } - p = &pParse->aColCache[idxLru]; - }else{ - p = &pParse->aColCache[pParse->nColCache++]; - } - - /* Add the new entry to the end of the cache */ - p->iLevel = pParse->iCacheLevel; - p->iTable = iTab; - p->iColumn = iCol; - p->iReg = iReg; - p->tempReg = 0; - p->lru = pParse->iCacheCnt++; -} - -/* -** Indicate that registers between iReg..iReg+nReg-1 are being overwritten. -** Purge the range of registers from the column cache. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){ - int i = 0; - while( inColCache ){ - struct yColCache *p = &pParse->aColCache[i]; - if( p->iReg >= iReg && p->iReg < iReg+nReg ){ - cacheEntryClear(pParse, i); - }else{ - i++; - } - } -} - -/* -** Remember the current column cache context. Any new entries added -** added to the column cache after this call are removed when the -** corresponding pop occurs. -*/ -SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){ - pParse->iCacheLevel++; -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("PUSH to %d\n", pParse->iCacheLevel); - } -#endif -} - -/* -** Remove from the column cache any entries that were added since the -** the previous sqlite3ExprCachePush operation. In other words, restore -** the cache to the state it was in prior the most recent Push. -*/ -SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){ - int i = 0; - assert( pParse->iCacheLevel>=1 ); - pParse->iCacheLevel--; -#ifdef SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("POP to %d\n", pParse->iCacheLevel); - } -#endif - while( inColCache ){ - if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){ - cacheEntryClear(pParse, i); - }else{ - i++; - } - } -} - -/* -** When a cached column is reused, make sure that its register is -** no longer available as a temp register. ticket #3879: that same -** register might be in the cache in multiple places, so be sure to -** get them all. -*/ -static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){ - int i; - struct yColCache *p; - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - if( p->iReg==iReg ){ - p->tempReg = 0; - } - } -} /* Generate code that will load into register regOut a value that is ** appropriate for the iIdxCol-th column of index pIdx. @@ -93648,47 +106148,100 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn( if( iTabCol==XN_EXPR ){ assert( pIdx->aColExpr ); assert( pIdx->aColExpr->nExpr>iIdxCol ); - pParse->iSelfTab = iTabCur; + pParse->iSelfTab = iTabCur + 1; sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); + pParse->iSelfTab = 0; }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* +** Generate code that will compute the value of generated column pCol +** and store the result in register regOut +*/ +SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn( + Parse *pParse, /* Parsing context */ + Table *pTab, /* Table containing the generated column */ + Column *pCol, /* The generated column */ + int regOut /* Put the result in this register */ +){ + int iAddr; + Vdbe *v = pParse->pVdbe; + assert( v!=0 ); + assert( pParse->iSelfTab!=0 ); + if( pParse->iSelfTab>0 ){ + iAddr = sqlite3VdbeAddOp3(v, OP_IfNullRow, pParse->iSelfTab-1, 0, regOut); + }else{ + iAddr = 0; + } + sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab,pCol), regOut); + if( pCol->affinity>=SQLITE_AFF_TEXT ){ + sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1); + } + if( iAddr ) sqlite3VdbeJumpHere(v, iAddr); +} +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + /* ** Generate code to extract the value of the iCol-th column of a table. */ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable( - Vdbe *v, /* The VDBE under construction */ + Vdbe *v, /* Parsing context */ Table *pTab, /* The table containing the value */ int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */ int iCol, /* Index of the column to extract */ int regOut /* Extract the value into this register */ ){ + Column *pCol; + assert( v!=0 ); + if( pTab==0 ){ + sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut); + return; + } if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ - int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; - int x = iCol; - if( !HasRowid(pTab) && !IsVirtual(pTab) ){ - x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); + int op; + int x; + if( IsVirtual(pTab) ){ + op = OP_VColumn; + x = iCol; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ + Parse *pParse = sqlite3VdbeParser(v); + if( pCol->colFlags & COLFLAG_BUSY ){ + sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", + pCol->zCnName); + }else{ + int savedSelfTab = pParse->iSelfTab; + pCol->colFlags |= COLFLAG_BUSY; + pParse->iSelfTab = iTabCur+1; + sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, regOut); + pParse->iSelfTab = savedSelfTab; + pCol->colFlags &= ~COLFLAG_BUSY; + } + return; +#endif + }else if( !HasRowid(pTab) ){ + testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) ); + x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol); + op = OP_Column; + }else{ + x = sqlite3TableColumnToStorage(pTab,iCol); + testcase( x!=iCol ); + op = OP_Column; } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); - } - if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } } /* ** Generate code that will extract the iColumn-th column from -** table pTab and store the column value in a register. -** -** An effort is made to store the column value in register iReg. This -** is not garanteeed for GetColumn() - the result can be stored in -** any register. But the result is guaranteed to land in register iReg -** for GetColumnToReg(). +** table pTab and store the column value in register iReg. ** ** There must be an open cursor to pTab in iTable when this routine ** is called. If iColumn<0 then code is generated that extracts the rowid. @@ -93701,103 +106254,31 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn( int iReg, /* Store results here */ u8 p5 /* P5 value for OP_Column + FLAGS */ ){ - Vdbe *v = pParse->pVdbe; - int i; - struct yColCache *p; - - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - if( p->iTable==iTable && p->iColumn==iColumn ){ - p->lru = pParse->iCacheCnt++; - sqlite3ExprCachePinRegister(pParse, p->iReg); - return p->iReg; - } - } - assert( v!=0 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg); + assert( pParse->pVdbe!=0 ); + sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg); if( p5 ){ - sqlite3VdbeChangeP5(v, p5); - }else{ - sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg); + VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1); + if( pOp->opcode==OP_Column ) pOp->p5 = p5; } return iReg; } -SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg( - Parse *pParse, /* Parsing and code generating context */ - Table *pTab, /* Description of the table we are reading from */ - int iColumn, /* Index of the table column */ - int iTable, /* The cursor pointing to the table */ - int iReg /* Store results here */ -){ - int r1 = sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0); - if( r1!=iReg ) sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg); -} - - -/* -** Clear all column cache entries. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){ - int i; - -#if SQLITE_DEBUG - if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ - printf("CLEAR\n"); - } -#endif - for(i=0; inColCache; i++){ - if( pParse->aColCache[i].tempReg - && pParse->nTempRegaTempReg) - ){ - pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg; - } - } - pParse->nColCache = 0; -} - -/* -** Record the fact that an affinity change has occurred on iCount -** registers starting with iStart. -*/ -SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){ - sqlite3ExprCacheRemove(pParse, iStart, iCount); -} /* ** Generate code to move content from registers iFrom...iFrom+nReg-1 -** over to iTo..iTo+nReg-1. Keep the column cache up-to-date. +** over to iTo..iTo+nReg-1. */ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ - assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); - sqlite3ExprCacheRemove(pParse, iFrom, nReg); -} - -#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) -/* -** Return true if any register in the range iFrom..iTo (inclusive) -** is used as part of the column cache. -** -** This routine is used within assert() and testcase() macros only -** and does not appear in a normal build. -*/ -static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){ - int i; - struct yColCache *p; - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - int r = p->iReg; - if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/ - } - return 0; } -#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */ - /* ** Convert a scalar expression node to a TK_REGISTER referencing ** register iReg. The caller must ensure that iReg already contains ** the correct value for the expression. */ -static void exprToRegister(Expr *p, int iReg){ +static void exprToRegister(Expr *pExpr, int iReg){ + Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); + if( NEVER(p==0) ) return; p->op2 = p->op; p->op = TK_REGISTER; p->iTable = iReg; @@ -93822,11 +106303,16 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ }else{ *piFreeable = 0; if( p->op==TK_SELECT ){ - iResult = sqlite3CodeSubselect(pParse, p, 0, 0); +#if SQLITE_OMIT_SUBQUERY + iResult = 0; +#else + iResult = sqlite3CodeSubselect(pParse, p); +#endif }else{ int i; iResult = pParse->nMem+1; pParse->nMem += nResult; + assert( ExprUseXList(p) ); for(i=0; ix.pList->a[i].pExpr, i+iResult); } @@ -93835,6 +106321,124 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){ return iResult; } +/* +** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5) +** so that a subsequent copy will not be merged into this one. +*/ +static void setDoNotMergeFlagOnCopy(Vdbe *v){ + if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){ + sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */ + } +} + +/* +** Generate code to implement special SQL functions that are implemented +** in-line rather than by using the usual callbacks. +*/ +static int exprCodeInlineFunction( + Parse *pParse, /* Parsing context */ + ExprList *pFarg, /* List of function arguments */ + int iFuncId, /* Function ID. One of the INTFUNC_... values */ + int target /* Store function result in this register */ +){ + int nFarg; + Vdbe *v = pParse->pVdbe; + assert( v!=0 ); + assert( pFarg!=0 ); + nFarg = pFarg->nExpr; + assert( nFarg>0 ); /* All in-line functions have at least one argument */ + switch( iFuncId ){ + case INLINEFUNC_coalesce: { + /* Attempt a direct implementation of the built-in COALESCE() and + ** IFNULL() functions. This avoids unnecessary evaluation of + ** arguments past the first non-NULL argument. + */ + int endCoalesce = sqlite3VdbeMakeLabel(pParse); + int i; + assert( nFarg>=2 ); + sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); + for(i=1; ia[i].pExpr, target); + } + setDoNotMergeFlagOnCopy(v); + sqlite3VdbeResolveLabel(v, endCoalesce); + break; + } + case INLINEFUNC_iif: { + Expr caseExpr; + memset(&caseExpr, 0, sizeof(caseExpr)); + caseExpr.op = TK_CASE; + caseExpr.x.pList = pFarg; + return sqlite3ExprCodeTarget(pParse, &caseExpr, target); + } + + default: { + /* The UNLIKELY() function is a no-op. The result is the value + ** of the first argument. + */ + assert( nFarg==1 || nFarg==2 ); + target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); + break; + } + + /*********************************************************************** + ** Test-only SQL functions that are only usable if enabled + ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS + */ +#if !defined(SQLITE_UNTESTABLE) + case INLINEFUNC_expr_compare: { + /* Compare two expressions using sqlite3ExprCompare() */ + assert( nFarg==2 ); + sqlite3VdbeAddOp2(v, OP_Integer, + sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1), + target); + break; + } + + case INLINEFUNC_expr_implies_expr: { + /* Compare two expressions using sqlite3ExprImpliesExpr() */ + assert( nFarg==2 ); + sqlite3VdbeAddOp2(v, OP_Integer, + sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1), + target); + break; + } + + case INLINEFUNC_implies_nonnull_row: { + /* REsult of sqlite3ExprImpliesNonNullRow() */ + Expr *pA1; + assert( nFarg==2 ); + pA1 = pFarg->a[1].pExpr; + if( pA1->op==TK_COLUMN ){ + sqlite3VdbeAddOp2(v, OP_Integer, + sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable), + target); + }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, target); + } + break; + } + + case INLINEFUNC_affinity: { + /* The AFFINITY() function evaluates to a string that describes + ** the type affinity of the argument. This is used for testing of + ** the SQLite type logic. + */ + const char *azAff[] = { "blob", "text", "numeric", "integer", "real" }; + char aff; + assert( nFarg==1 ); + aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); + sqlite3VdbeLoadString(v, target, + (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]); + break; + } +#endif /* !defined(SQLITE_UNTESTABLE) */ + } + return target; +} + /* ** Generate code into the current Vdbe to evaluate the given @@ -93858,50 +106462,138 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) int p5 = 0; assert( target>0 && target<=pParse->nMem ); - if( v==0 ){ - assert( pParse->db->mallocFailed ); - return 0; - } + assert( v!=0 ); +expr_code_doover: if( pExpr==0 ){ op = TK_NULL; }else{ + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); op = pExpr->op; } switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; - struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; + struct AggInfo_col *pCol; + assert( pAggInfo!=0 ); + assert( pExpr->iAgg>=0 && pExpr->iAggnColumn ); + pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ assert( pCol->iMem>0 ); return pCol->iMem; }else if( pAggInfo->useSortingIdx ){ + Table *pTab = pCol->pTab; sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); + if( pCol->iColumn<0 ){ + VdbeComment((v,"%s.rowid",pTab->zName)); + }else{ + VdbeComment((v,"%s.%s", + pTab->zName, pTab->aCol[pCol->iColumn].zCnName)); + if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, target); + } + } return target; } /* Otherwise, fall thru into the TK_COLUMN case */ + /* no break */ deliberate_fall_through } case TK_COLUMN: { int iTab = pExpr->iTable; + int iReg; + if( ExprHasProperty(pExpr, EP_FixedCol) ){ + /* This COLUMN expression is really a constant due to WHERE clause + ** constraints, and that constant is coded by the pExpr->pLeft + ** expresssion. However, make sure the constant has the correct + ** datatype by applying the Affinity of the table column to the + ** constant. + */ + int aff; + iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); + assert( ExprUseYTab(pExpr) ); + if( pExpr->y.pTab ){ + aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); + }else{ + aff = pExpr->affExpr; + } + if( aff>SQLITE_AFF_BLOB ){ + static const char zAff[] = "B\000C\000D\000E"; + assert( SQLITE_AFF_BLOB=='A' ); + assert( SQLITE_AFF_TEXT=='B' ); + sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, + &zAff[(aff-'B')*2], P4_STATIC); + } + return iReg; + } if( iTab<0 ){ - if( pParse->ckBase>0 ){ - /* Generating CHECK constraints or inserting into partial index */ - return pExpr->iColumn + pParse->ckBase; + if( pParse->iSelfTab<0 ){ + /* Other columns in the same row for CHECK constraints or + ** generated columns or for inserting into partial index. + ** The row is unpacked into registers beginning at + ** 0-(pParse->iSelfTab). The rowid (if any) is in a register + ** immediately prior to the first column. + */ + Column *pCol; + Table *pTab; + int iSrc; + int iCol = pExpr->iColumn; + assert( ExprUseYTab(pExpr) ); + pTab = pExpr->y.pTab; + assert( pTab!=0 ); + assert( iCol>=XN_ROWID ); + assert( iColnCol ); + if( iCol<0 ){ + return -1-pParse->iSelfTab; + } + pCol = pTab->aCol + iCol; + testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) ); + iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pCol->colFlags & COLFLAG_GENERATED ){ + if( pCol->colFlags & COLFLAG_BUSY ){ + sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", + pCol->zCnName); + return 0; + } + pCol->colFlags |= COLFLAG_BUSY; + if( pCol->colFlags & COLFLAG_NOTAVAIL ){ + sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, iSrc); + } + pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL); + return iSrc; + }else +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + if( pCol->affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target); + sqlite3VdbeAddOp1(v, OP_RealAffinity, target); + return target; + }else{ + return iSrc; + } }else{ /* Coding an expression that is part of an index where column names ** in the index refer to the table to which the index belongs */ - iTab = pParse->iSelfTab; + iTab = pParse->iSelfTab - 1; } } - return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, + assert( ExprUseYTab(pExpr) ); + iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); + if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); + } + return iReg; } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); return target; } + case TK_TRUEFALSE: { + sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target); + return target; + } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); @@ -93914,7 +106606,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } - case TK_NULL: { + default: { + /* Make NULL the default case so that if a bug causes an illegal + ** Expr node to be passed into this function, it will be handled + ** sanely and not crash. But keep the assert() to bring the problem + ** to the attention of the developers. */ + assert( op==TK_NULL || op==TK_ERROR || pParse->db->mallocFailed ); sqlite3VdbeAddOp2(v, OP_Null, 0, target); return target; } @@ -93941,7 +106638,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target); if( pExpr->u.zToken[1]!=0 ){ const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn); - assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 ); + assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) ); pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */ sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC); } @@ -93958,10 +106655,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } + assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); - testcase( usedAsColumnCache(pParse, inReg, inReg) ); - sqlite3ExprCacheAffinityChange(pParse, inReg, 1); return inReg; } #endif /* SQLITE_OMIT_CAST */ @@ -93982,14 +106678,21 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) }else{ r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - codeCompare(pParse, pLeft, pExpr->pRight, op, - r1, r2, inReg, SQLITE_STOREP2 | p5); + sqlite3VdbeAddOp2(v, OP_Integer, 1, inReg); + codeCompare(pParse, pLeft, pExpr->pRight, op, r1, r2, + sqlite3VdbeCurrentAddr(v)+2, p5, + ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); + if( p5==SQLITE_NULLEQ ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, inReg); + }else{ + sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, inReg, r2); + } testcase( regFree1==0 ); testcase( regFree2==0 ); } @@ -94005,7 +106708,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) case TK_BITOR: case TK_SLASH: case TK_LSHIFT: - case TK_RSHIFT: + case TK_RSHIFT: case TK_CONCAT: { assert( TK_AND==OP_And ); testcase( op==TK_AND ); assert( TK_OR==OP_Or ); testcase( op==TK_OR ); @@ -94041,6 +106744,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) tempX.op = TK_INTEGER; tempX.flags = EP_IntValue|EP_TokenOnly; tempX.u.iValue = 0; + ExprClearVVAProperties(&tempX); r1 = sqlite3ExprCodeTemp(pParse, &tempX, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); @@ -94057,6 +106761,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) sqlite3VdbeAddOp2(v, op, r1, inReg); break; } + case TK_TRUTH: { + int isTrue; /* IS TRUE or IS NOT TRUE */ + int bNormal; /* IS TRUE or IS FALSE */ + r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); + testcase( regFree1==0 ); + isTrue = sqlite3ExprTruthValue(pExpr->pRight); + bNormal = pExpr->op2==TK_IS; + testcase( isTrue && bNormal); + testcase( !isTrue && bNormal); + sqlite3VdbeAddOp4Int(v, OP_IsTrue, r1, inReg, !isTrue, isTrue ^ bNormal); + break; + } case TK_ISNULL: case TK_NOTNULL: { int addr; @@ -94074,9 +106790,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; - if( pInfo==0 ){ + if( pInfo==0 + || NEVER(pExpr->iAgg<0) + || NEVER(pExpr->iAgg>=pInfo->nFunc) + ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); - sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken); + sqlite3ErrorMsg(pParse, "misuse of aggregate: %#T()", pExpr); }else{ return pInfo->aFunc[pExpr->iAgg].iMem; } @@ -94093,17 +106812,20 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) u8 enc = ENC(db); /* The text encoding used by this database */ CollSeq *pColl = 0; /* A collating sequence */ - if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ - /* SQL functions can be expensive. So try to move constant functions - ** out of the inner loop, even if that means an extra OP_Copy. */ - return sqlite3ExprCodeAtInit(pParse, pExpr, -1); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + return pExpr->y.pWin->regResult; } - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - if( ExprHasProperty(pExpr, EP_TokenOnly) ){ - pFarg = 0; - }else{ - pFarg = pExpr->x.pList; +#endif + + if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ + /* SQL functions can be expensive. So try to avoid running them + ** multiple times if we know they always give the same result */ + return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); } + assert( !ExprHasProperty(pExpr, EP_TokenOnly) ); + assert( ExprUseXList(pExpr) ); + pFarg = pExpr->x.pList; nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; @@ -94114,54 +106836,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } #endif if( pDef==0 || pDef->xFinalize!=0 ){ - sqlite3ErrorMsg(pParse, "unknown function: %s()", zId); - break; - } - - /* Attempt a direct implementation of the built-in COALESCE() and - ** IFNULL() functions. This avoids unnecessary evaluation of - ** arguments past the first non-NULL argument. - */ - if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ - int endCoalesce = sqlite3VdbeMakeLabel(v); - assert( nFarg>=2 ); - sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); - for(i=1; ia[i].pExpr, target); - sqlite3ExprCachePop(pParse); - } - sqlite3VdbeResolveLabel(v, endCoalesce); + sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr); break; } - - /* The UNLIKELY() function is a no-op. The result is the value - ** of the first argument. - */ - if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ - assert( nFarg>=1 ); - return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); + if( pDef->funcFlags & SQLITE_FUNC_INLINE ){ + assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 ); + assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 ); + return exprCodeInlineFunction(pParse, pFarg, + SQLITE_PTR_TO_INT(pDef->pUserData), target); + }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){ + sqlite3ExprFunctionUsable(pParse, pExpr, pDef); } -#ifdef SQLITE_DEBUG - /* The AFFINITY() function evaluates to a string that describes - ** the type affinity of the argument. This is used for testing of - ** the SQLite type logic. - */ - if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){ - const char *azAff[] = { "blob", "text", "numeric", "integer", "real" }; - char aff; - assert( nFarg==1 ); - aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); - sqlite3VdbeLoadString(v, target, - aff ? azAff[aff-SQLITE_AFF_BLOB] : "none"); - return target; - } -#endif - for(i=0; ia[i].pExpr) ){ testcase( i==31 ); @@ -94193,15 +106879,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG ); assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG ); testcase( pDef->funcFlags & OPFLAG_LENGTHARG ); - pFarg->a[0].pExpr->op2 = + pFarg->a[0].pExpr->op2 = pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); } } - sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); - sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */ }else{ r1 = 0; } @@ -94214,25 +106898,40 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** see if it is a column in a virtual table. This is done because ** the left operand of infix functions (the operand we want to ** control overloading) ends up as the second argument to the - ** function. The expression "A glob B" is equivalent to + ** function. The expression "A glob B" is equivalent to ** "glob(B,A). We want to use the A in "A glob B" to test ** for function overloading. But we use the B term in "glob(B,A)". */ - if( nFarg>=2 && (pExpr->flags & EP_InfixFunc) ){ + if( nFarg>=2 && ExprHasProperty(pExpr, EP_InfixFunc) ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr); }else if( nFarg>0 ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); } #endif if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){ - if( !pColl ) pColl = db->pDfltColl; + if( !pColl ) pColl = db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target, - (char*)pDef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)nFarg); - if( nFarg && constMask==0 ){ - sqlite3ReleaseTempRange(pParse, r1, nFarg); +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + if( (pDef->funcFlags & SQLITE_FUNC_OFFSET)!=0 && ALWAYS(pFarg!=0) ){ + Expr *pArg = pFarg->a[0].pExpr; + if( pArg->op==TK_COLUMN ){ + sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target); + }else{ + sqlite3VdbeAddOp2(v, OP_Null, 0, target); + } + }else +#endif + { + sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg, + pDef, pExpr->op2); + } + if( nFarg ){ + if( constMask==0 ){ + sqlite3ReleaseTempRange(pParse, r1, nFarg); + }else{ + sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask, 1); + } } return target; } @@ -94242,30 +106941,34 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) int nCol; testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); - if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){ + if( pParse->db->mallocFailed ){ + return 0; + }else if( op==TK_SELECT + && ALWAYS( ExprUseXSelect(pExpr) ) + && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 + ){ sqlite3SubselectError(pParse, nCol, 1); }else{ - return sqlite3CodeSubselect(pParse, pExpr, 0, 0); + return sqlite3CodeSubselect(pParse, pExpr); } break; } case TK_SELECT_COLUMN: { int n; if( pExpr->pLeft->iTable==0 ){ - pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0); + pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft); } - assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT ); - if( pExpr->iTable - && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft)) - ){ + assert( pExpr->pLeft->op==TK_SELECT || pExpr->pLeft->op==TK_ERROR ); + n = sqlite3ExprVectorSize(pExpr->pLeft); + if( pExpr->iTable!=n ){ sqlite3ErrorMsg(pParse, "%d columns assigned %d values", pExpr->iTable, n); } return pExpr->pLeft->iTable + pExpr->iColumn; } case TK_IN: { - int destIfFalse = sqlite3VdbeMakeLabel(v); - int destIfNull = sqlite3VdbeMakeLabel(v); + int destIfFalse = sqlite3VdbeMakeLabel(pParse); + int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, target); sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); @@ -94293,9 +106996,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) return target; } case TK_SPAN: - case TK_COLLATE: + case TK_COLLATE: case TK_UPLUS: { - return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + pExpr = pExpr->pLeft; + goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */ } case TK_TRIGGER: { @@ -94308,7 +107012,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** ** The expression is implemented using an OP_Param opcode. The p1 ** parameter is set to 0 for an old.rowid reference, or to (i+1) - ** to reference another column of the old.* pseudo-table, where + ** to reference another column of the old.* pseudo-table, where ** i is the index of the column. For a new.rowid reference, p1 is ** set to (n+1), where n is the number of columns in each pseudo-table. ** For a reference to any other column in the new.* pseudo-table, p1 @@ -94322,21 +107026,27 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** ** p1==0 -> old.rowid p1==3 -> new.rowid ** p1==1 -> old.a p1==4 -> new.a - ** p1==2 -> old.b p1==5 -> new.b + ** p1==2 -> old.b p1==5 -> new.b */ - Table *pTab = pExpr->pTab; - int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; + Table *pTab; + int iCol; + int p1; + + assert( ExprUseYTab(pExpr) ); + pTab = pExpr->y.pTab; + iCol = pExpr->iColumn; + p1 = pExpr->iTable * (pTab->nCol+1) + 1 + + sqlite3TableColumnToStorage(pTab, iCol); assert( pExpr->iTable==0 || pExpr->iTable==1 ); - assert( pExpr->iColumn>=-1 && pExpr->iColumnnCol ); - assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey ); + assert( iCol>=-1 && iColnCol ); + assert( pTab->iPKey<0 || iCol!=pTab->iPKey ); assert( p1>=0 && p1<(pTab->nCol*2+2) ); sqlite3VdbeAddOp2(v, OP_Param, p1, target); - VdbeComment((v, "%s.%s -> $%d", + VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), - (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName), - target + (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zCnName) )); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -94345,9 +107055,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to ** floating point when extracting it from the record. */ - if( pExpr->iColumn>=0 - && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL - ){ + if( iCol>=0 && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } #endif @@ -94359,6 +107067,28 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) break; } + /* TK_IF_NULL_ROW Expr nodes are inserted ahead of expressions + ** that derive from the right-hand table of a LEFT JOIN. The + ** Expr.iTable value is the table number for the right-hand table. + ** The expression is only evaluated if that table is not currently + ** on a LEFT JOIN NULL row. + */ + case TK_IF_NULL_ROW: { + int addrINR; + u8 okConstFactor = pParse->okConstFactor; + addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); + /* Temporarily disable factoring of constant expressions, since + ** even though expressions may appear to be constant, they are not + ** really constant because they originate from the right-hand side + ** of a LEFT JOIN. */ + pParse->okConstFactor = 0; + inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); + pParse->okConstFactor = okConstFactor; + sqlite3VdbeJumpHere(v, addrINR); + sqlite3VdbeChangeP3(v, addrINR, inReg); + break; + } + /* ** Form A: ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END @@ -94380,7 +107110,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) ** or if there is no matching Ei, the ELSE term Y, or if there is ** no ELSE term, NULL. */ - default: assert( op==TK_CASE ); { + case TK_CASE: { int endLabel; /* GOTO label for end of CASE stmt */ int nextCase; /* GOTO label for next WHEN clause */ int nExpr; /* 2x number of WHEN terms */ @@ -94390,22 +107120,27 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) Expr opCompare; /* The X==Ei expression */ Expr *pX; /* The X expression */ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ - VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; ) + Expr *pDel = 0; + sqlite3 *db = pParse->db; - assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); + assert( ExprUseXList(pExpr) && pExpr->x.pList!=0 ); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; nExpr = pEList->nExpr; - endLabel = sqlite3VdbeMakeLabel(v); + endLabel = sqlite3VdbeMakeLabel(pParse); if( (pX = pExpr->pLeft)!=0 ){ - tempX = *pX; + pDel = sqlite3ExprDup(db, pX, 0); + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDel); + break; + } testcase( pX->op==TK_COLUMN ); - exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1)); + exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1)); testcase( regFree1==0 ); memset(&opCompare, 0, sizeof(opCompare)); opCompare.op = TK_EQ; - opCompare.pLeft = &tempX; + opCompare.pLeft = pDel; pTest = &opCompare; /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001: ** The value in regFree1 might get SCopy-ed into the file result. @@ -94414,57 +107149,54 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) regFree1 = 0; } for(i=0; iop==TK_COLUMN ); sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeGoto(v, endLabel); - sqlite3ExprCachePop(pParse); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ - sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); - sqlite3ExprCachePop(pParse); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } - assert( pParse->db->mallocFailed || pParse->nErr>0 - || pParse->iCacheLevel==iCacheLevel ); + sqlite3ExprDelete(db, pDel); + setDoNotMergeFlagOnCopy(v); sqlite3VdbeResolveLabel(v, endLabel); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { - assert( pExpr->affinity==OE_Rollback - || pExpr->affinity==OE_Abort - || pExpr->affinity==OE_Fail - || pExpr->affinity==OE_Ignore + assert( pExpr->affExpr==OE_Rollback + || pExpr->affExpr==OE_Abort + || pExpr->affExpr==OE_Fail + || pExpr->affExpr==OE_Ignore ); - if( !pParse->pTriggerTab ){ + if( !pParse->pTriggerTab && !pParse->nested ){ sqlite3ErrorMsg(pParse, "RAISE() may only be used within a trigger-program"); return 0; } - if( pExpr->affinity==OE_Abort ){ + if( pExpr->affExpr==OE_Abort ){ sqlite3MayAbort(pParse); } assert( !ExprHasProperty(pExpr, EP_IntValue) ); - if( pExpr->affinity==OE_Ignore ){ + if( pExpr->affExpr==OE_Ignore ){ sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); VdbeCoverage(v); }else{ - sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER, - pExpr->affinity, pExpr->u.zToken, 0, 0); + sqlite3HaltConstraint(pParse, + pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR, + pExpr->affExpr, pExpr->u.zToken, 0, 0); } break; @@ -94477,15 +107209,23 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target) } /* -** Factor out the code of the given expression to initialization time. +** Generate code that will evaluate expression pExpr just one time +** per prepared statement execution. +** +** If the expression uses functions (that might throw an exception) then +** guard them with an OP_Once opcode to ensure that the code is only executed +** once. If no functions are involved, then factor the code out and put it at +** the end of the prepared statement in the initialization section. ** ** If regDest>=0 then the result is always stored in that register and the -** result is not reusable. If regDest<0 then this routine is free to -** store the value whereever it wants. The register where the expression -** is stored is returned. When regDest<0, two identical expressions will -** code to the same register. -*/ -SQLITE_PRIVATE int sqlite3ExprCodeAtInit( +** result is not reusable. If regDest<0 then this routine is free to +** store the value whereever it wants. The register where the expression +** is stored is returned. When regDest<0, two identical expressions might +** code to the same register, if they do not contain function calls and hence +** are factored out into the initialization section at the end of the +** prepared statement. +*/ +SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The expression to code when the VDBE initializes */ int regDest /* Store the value in this register */ @@ -94497,20 +107237,35 @@ SQLITE_PRIVATE int sqlite3ExprCodeAtInit( struct ExprList_item *pItem; int i; for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ - if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){ + if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){ return pItem->u.iConstExprReg; } } } pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); - p = sqlite3ExprListAppend(pParse, p, pExpr); - if( p ){ - struct ExprList_item *pItem = &p->a[p->nExpr-1]; - pItem->reusable = regDest<0; - if( regDest<0 ) regDest = ++pParse->nMem; - pItem->u.iConstExprReg = regDest; + if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){ + Vdbe *v = pParse->pVdbe; + int addr; + assert( v ); + addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + pParse->okConstFactor = 0; + if( !pParse->db->mallocFailed ){ + if( regDest<0 ) regDest = ++pParse->nMem; + sqlite3ExprCode(pParse, pExpr, regDest); + } + pParse->okConstFactor = 1; + sqlite3ExprDelete(pParse->db, pExpr); + sqlite3VdbeJumpHere(v, addr); + }else{ + p = sqlite3ExprListAppend(pParse, p, pExpr); + if( p ){ + struct ExprList_item *pItem = &p->a[p->nExpr-1]; + pItem->reusable = regDest<0; + if( regDest<0 ) regDest = ++pParse->nMem; + pItem->u.iConstExprReg = regDest; + } + pParse->pConstExpr = p; } - pParse->pConstExpr = p; return regDest; } @@ -94529,13 +107284,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeAtInit( */ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ int r2; - pExpr = sqlite3ExprSkipCollate(pExpr); + pExpr = sqlite3ExprSkipCollateAndLikely(pExpr); if( ConstFactorOk(pParse) + && ALWAYS(pExpr!=0) && pExpr->op!=TK_REGISTER && sqlite3ExprIsConstantNotJoin(pExpr) ){ *pReg = 0; - r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1); + r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); }else{ int r1 = sqlite3GetTempReg(pParse); r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); @@ -94557,15 +107313,19 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int inReg; + assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) ); assert( target>0 && target<=pParse->nMem ); - if( pExpr && pExpr->op==TK_REGISTER ){ - sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target); - }else{ - inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); - assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); - if( inReg!=target && pParse->pVdbe ){ - sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target); + assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); + if( pParse->pVdbe==0 ) return; + inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); + if( inReg!=target ){ + u8 op; + if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){ + op = OP_Copy; + }else{ + op = OP_SCopy; } + sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target); } } @@ -94588,42 +107348,20 @@ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){ ** might choose to code the expression at initialization time. */ SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ - if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){ - sqlite3ExprCodeAtInit(pParse, pExpr, target); + if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ + sqlite3ExprCodeRunJustOnce(pParse, pExpr, target); }else{ - sqlite3ExprCode(pParse, pExpr, target); + sqlite3ExprCodeCopy(pParse, pExpr, target); } } -/* -** Generate code that evaluates the given expression and puts the result -** in register target. -** -** Also make a copy of the expression results into another "cache" register -** and modify the expression so that the next time it is evaluated, -** the result is a copy of the cache register. -** -** This routine is used for expressions that are used multiple -** times. They are evaluated once and the results of the expression -** are reused. -*/ -SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ - Vdbe *v = pParse->pVdbe; - int iMem; - - assert( target>0 ); - assert( pExpr->op!=TK_REGISTER ); - sqlite3ExprCode(pParse, pExpr, target); - iMem = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); - exprToRegister(pExpr, iMem); -} - /* ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. ** -** Return the number of elements evaluated. +** Return the number of elements evaluated. The number returned will +** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF +** is defined. ** ** The SQLITE_ECEL_DUP flag prevents the arguments from being ** filled using OP_SCopy. OP_Copy must be used instead. @@ -94634,6 +107372,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ ** The SQLITE_ECEL_REF flag means that expressions in the list with ** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored ** in registers at srcReg, and so the value can be copied from there. +** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0 +** are simply omitted rather than being copied from srcReg. */ SQLITE_PRIVATE int sqlite3ExprCodeExprList( Parse *pParse, /* Parsing context */ @@ -94653,6 +107393,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; ipExpr; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( pItem->bSorterRef ){ + i--; + n--; + }else +#endif if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; @@ -94660,8 +107406,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } - }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){ - sqlite3ExprCodeAtInit(pParse, pExpr, target+i); + }else if( (flags & SQLITE_ECEL_FACTOR)!=0 + && sqlite3ExprIsConstantNotJoin(pExpr) + ){ + sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ @@ -94670,6 +107418,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy && pOp->p1+pOp->p3+1==inReg && pOp->p2+pOp->p3+1==target+i + && pOp->p5==0 /* The do-not-merge flag must be clear */ ){ pOp->p3++; }else{ @@ -94686,7 +107435,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList( ** ** x BETWEEN y AND z ** -** The above is equivalent to +** The above is equivalent to ** ** x>=y AND x<=z ** @@ -94708,41 +107457,44 @@ static void exprCodeBetween( void (*xJump)(Parse*,Expr*,int,int), /* Action to take */ int jumpIfNull /* Take the jump if the BETWEEN is NULL */ ){ - Expr exprAnd; /* The AND operator in x>=y AND x<=z */ + Expr exprAnd; /* The AND operator in x>=y AND x<=z */ Expr compLeft; /* The x>=y term */ Expr compRight; /* The x<=z term */ - Expr exprX; /* The x subexpression */ int regFree1 = 0; /* Temporary use register */ - + Expr *pDel = 0; + sqlite3 *db = pParse->db; memset(&compLeft, 0, sizeof(Expr)); memset(&compRight, 0, sizeof(Expr)); memset(&exprAnd, 0, sizeof(Expr)); - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - exprX = *pExpr->pLeft; - exprAnd.op = TK_AND; - exprAnd.pLeft = &compLeft; - exprAnd.pRight = &compRight; - compLeft.op = TK_GE; - compLeft.pLeft = &exprX; - compLeft.pRight = pExpr->x.pList->a[0].pExpr; - compRight.op = TK_LE; - compRight.pLeft = &exprX; - compRight.pRight = pExpr->x.pList->a[1].pExpr; - exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®Free1)); - if( xJump ){ - xJump(pParse, &exprAnd, dest, jumpIfNull); - }else{ - /* Mark the expression is being from the ON or USING clause of a join - ** so that the sqlite3ExprCodeTarget() routine will not attempt to move - ** it into the Parse.pConstExpr list. We should use a new bit for this, - ** for clarity, but we are out of bits in the Expr.flags field so we - ** have to reuse the EP_FromJoin bit. Bummer. */ - exprX.flags |= EP_FromJoin; - sqlite3ExprCodeTarget(pParse, &exprAnd, dest); + assert( ExprUseXList(pExpr) ); + pDel = sqlite3ExprDup(db, pExpr->pLeft, 0); + if( db->mallocFailed==0 ){ + exprAnd.op = TK_AND; + exprAnd.pLeft = &compLeft; + exprAnd.pRight = &compRight; + compLeft.op = TK_GE; + compLeft.pLeft = pDel; + compLeft.pRight = pExpr->x.pList->a[0].pExpr; + compRight.op = TK_LE; + compRight.pLeft = pDel; + compRight.pRight = pExpr->x.pList->a[1].pExpr; + exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1)); + if( xJump ){ + xJump(pParse, &exprAnd, dest, jumpIfNull); + }else{ + /* Mark the expression is being from the ON or USING clause of a join + ** so that the sqlite3ExprCodeTarget() routine will not attempt to move + ** it into the Parse.pConstExpr list. We should use a new bit for this, + ** for clarity, but we are out of bits in the Expr.flags field so we + ** have to reuse the EP_FromJoin bit. Bummer. */ + pDel->flags |= EP_FromJoin; + sqlite3ExprCodeTarget(pParse, &exprAnd, dest); + } + sqlite3ReleaseTempReg(pParse, regFree1); } - sqlite3ReleaseTempReg(pParse, regFree1); + sqlite3ExprDelete(db, pDel); /* Ensure adequate test coverage */ testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 ); @@ -94780,24 +107532,26 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( NEVER(pExpr==0) ) return; /* No way this can happen */ + assert( !ExprHasVVAProperty(pExpr, EP_Immutable) ); op = pExpr->op; switch( op ){ - case TK_AND: { - int d2 = sqlite3VdbeMakeLabel(v); - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprCachePush(pParse); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse); - break; - } + case TK_AND: case TK_OR: { - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprCachePush(pParse); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse); + Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull); + }else if( op==TK_AND ){ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + }else{ + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + } break; } case TK_NOT: { @@ -94805,13 +107559,30 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } + case TK_TRUTH: { + int isNot; /* IS NOT TRUE or IS NOT FALSE */ + int isTrue; /* IS TRUE or IS NOT TRUE */ + testcase( jumpIfNull==0 ); + isNot = pExpr->op2==TK_ISNOT; + isTrue = sqlite3ExprTruthValue(pExpr->pRight); + testcase( isTrue && isNot ); + testcase( !isTrue && isNot ); + if( isTrue ^ isNot ){ + sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, + isNot ? SQLITE_JUMPIFNULL : 0); + }else{ + sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, + isNot ? SQLITE_JUMPIFNULL : 0); + } + break; + } case TK_IS: case TK_ISNOT: testcase( op==TK_IS ); testcase( op==TK_ISNOT ); op = (op==TK_IS) ? TK_EQ : TK_NE; jumpIfNull = SQLITE_NULLEQ; - /* Fall thru */ + /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: @@ -94823,7 +107594,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - r1, r2, dest, jumpIfNull); + r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); @@ -94856,7 +107627,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int } #ifndef SQLITE_OMIT_SUBQUERY case TK_IN: { - int destIfFalse = sqlite3VdbeMakeLabel(v); + int destIfFalse = sqlite3VdbeMakeLabel(pParse); int destIfNull = jumpIfNull ? dest : destIfFalse; sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull); sqlite3VdbeGoto(v, dest); @@ -94866,9 +107637,9 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int #endif default: { default_expr: - if( exprAlwaysTrue(pExpr) ){ + if( ExprAlwaysTrue(pExpr) ){ sqlite3VdbeGoto(v, dest); - }else if( exprAlwaysFalse(pExpr) ){ + }else if( ExprAlwaysFalse(pExpr) ){ /* No-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); @@ -94881,7 +107652,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int } } sqlite3ReleaseTempReg(pParse, regFree1); - sqlite3ReleaseTempReg(pParse, regFree2); + sqlite3ReleaseTempReg(pParse, regFree2); } /* @@ -94903,6 +107674,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( pExpr==0 ) return; + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); /* The value of pExpr->op and op are related as follows: ** @@ -94936,22 +107708,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ - case TK_AND: { - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprCachePush(pParse); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3ExprCachePop(pParse); - break; - } + case TK_AND: case TK_OR: { - int d2 = sqlite3VdbeMakeLabel(v); - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprCachePush(pParse); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); - sqlite3ExprCachePop(pParse); + Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull); + }else if( pExpr->op==TK_AND ){ + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + }else{ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + } break; } case TK_NOT: { @@ -94959,13 +107732,33 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } + case TK_TRUTH: { + int isNot; /* IS NOT TRUE or IS NOT FALSE */ + int isTrue; /* IS TRUE or IS NOT TRUE */ + testcase( jumpIfNull==0 ); + isNot = pExpr->op2==TK_ISNOT; + isTrue = sqlite3ExprTruthValue(pExpr->pRight); + testcase( isTrue && isNot ); + testcase( !isTrue && isNot ); + if( isTrue ^ isNot ){ + /* IS TRUE and IS NOT FALSE */ + sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, + isNot ? 0 : SQLITE_JUMPIFNULL); + + }else{ + /* IS FALSE and IS NOT TRUE */ + sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, + isNot ? 0 : SQLITE_JUMPIFNULL); + } + break; + } case TK_IS: case TK_ISNOT: testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; jumpIfNull = SQLITE_NULLEQ; - /* Fall thru */ + /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: @@ -94977,7 +107770,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, - r1, r2, dest, jumpIfNull); + r1, r2, dest, jumpIfNull,ExprHasProperty(pExpr,EP_Commuted)); assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); @@ -95011,7 +107804,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int if( jumpIfNull ){ sqlite3ExprCodeIN(pParse, pExpr, dest, dest); }else{ - int destIfNull = sqlite3VdbeMakeLabel(v); + int destIfNull = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeIN(pParse, pExpr, dest, destIfNull); sqlite3VdbeResolveLabel(v, destIfNull); } @@ -95019,10 +107812,10 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int } #endif default: { - default_expr: - if( exprAlwaysFalse(pExpr) ){ + default_expr: + if( ExprAlwaysFalse(pExpr) ){ sqlite3VdbeGoto(v, dest); - }else if( exprAlwaysTrue(pExpr) ){ + }else if( ExprAlwaysTrue(pExpr) ){ /* no-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); @@ -95052,6 +107845,45 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i sqlite3ExprDelete(db, pCopy); } +/* +** Expression pVar is guaranteed to be an SQL variable. pExpr may be any +** type of expression. +** +** If pExpr is a simple SQL value - an integer, real, string, blob +** or NULL value - then the VDBE currently being prepared is configured +** to re-prepare each time a new value is bound to variable pVar. +** +** Additionally, if pExpr is a simple SQL value and the value is the +** same as that currently bound to variable pVar, non-zero is returned. +** Otherwise, if the values are not the same or if pExpr is not a simple +** SQL value, zero is returned. +*/ +static int exprCompareVariable( + const Parse *pParse, + const Expr *pVar, + const Expr *pExpr +){ + int res = 0; + int iVar; + sqlite3_value *pL, *pR = 0; + + sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR); + if( pR ){ + iVar = pVar->iColumn; + sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); + pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB); + if( pL ){ + if( sqlite3_value_type(pL)==SQLITE_TEXT ){ + sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */ + } + res = 0==sqlite3MemCompare(pL, pR, 0); + } + sqlite3ValueFree(pR); + sqlite3ValueFree(pL); + } + + return res; +} /* ** Do a deep comparison of two expression trees. Return 0 if the two @@ -95074,12 +107906,27 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. +** +** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in +** pParse->pReprepare can be matched against literals in pB. The +** pParse->pVdbe->expmask bitmask is updated for each variable referenced. +** If pParse is NULL (the normal case) then any TK_VARIABLE term in +** Argument pParse should normally be NULL. If it is not NULL and pA or +** pB causes a return value of 2. */ -SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ +SQLITE_PRIVATE int sqlite3ExprCompare( + const Parse *pParse, + const Expr *pA, + const Expr *pB, + int iTab +){ u32 combinedFlags; if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; } + if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){ + return 0; + } combinedFlags = pA->flags | pB->flags; if( combinedFlags & EP_IntValue ){ if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){ @@ -95087,40 +107934,70 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ } return 2; } - if( pA->op!=pB->op ){ - if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){ + if( pA->op!=pB->op || pA->op==TK_RAISE ){ + if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){ return 1; } - if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){ + if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){ return 1; } return 2; } - if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ - if( pA->op==TK_FUNCTION ){ + assert( !ExprHasProperty(pA, EP_IntValue) ); + assert( !ExprHasProperty(pB, EP_IntValue) ); + if( pA->u.zToken ){ + if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; - }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ - return pA->op==TK_COLLATE ? 1 : 2; +#ifndef SQLITE_OMIT_WINDOWFUNC + assert( pA->op==pB->op ); + if( ExprHasProperty(pA,EP_WinFunc)!=ExprHasProperty(pB,EP_WinFunc) ){ + return 2; + } + if( ExprHasProperty(pA,EP_WinFunc) ){ + if( sqlite3WindowCompare(pParse, pA->y.pWin, pB->y.pWin, 1)!=0 ){ + return 2; + } + } +#endif + }else if( pA->op==TK_NULL ){ + return 0; + }else if( pA->op==TK_COLLATE ){ + if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; + }else + if( pB->u.zToken!=0 + && pA->op!=TK_COLUMN + && pA->op!=TK_AGG_COLUMN + && strcmp(pA->u.zToken,pB->u.zToken)!=0 + ){ + return 2; } } - if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; + if( (pA->flags & (EP_Distinct|EP_Commuted)) + != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; - if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; - if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; + if( (combinedFlags & EP_FixedCol)==0 + && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; + if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; - if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ + if( pA->op!=TK_STRING + && pA->op!=TK_TRUEFALSE + && ALWAYS((combinedFlags & EP_Reduced)==0) + ){ if( pA->iColumn!=pB->iColumn ) return 2; - if( pA->iTable!=pB->iTable - && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; + if( pA->op2!=pB->op2 && pA->op==TK_TRUTH ) return 2; + if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){ + return 2; + } } } return 0; } /* -** Compare two ExprList objects. Return 0 if they are identical and -** non-zero if they differ in any way. +** Compare two ExprList objects. Return 0 if they are identical, 1 +** if they are certainly different, or 2 if it is not possible to +** determine if they are identical or not. ** ** If any subelement of pB has Expr.iTable==(-1) then it is allowed ** to compare equal to an equivalent element in pA with Expr.iTable==iTab. @@ -95133,16 +108010,106 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ ** Two NULL pointers are considered to be the same. But a NULL pointer ** always differs from a non-NULL pointer. */ -SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ +SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){ int i; if( pA==0 && pB==0 ) return 0; if( pA==0 || pB==0 ) return 1; if( pA->nExpr!=pB->nExpr ) return 1; for(i=0; inExpr; i++){ + int res; Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; - if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; - if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1; + if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1; + if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res; + } + return 0; +} + +/* +** Like sqlite3ExprCompare() except COLLATE operators at the top-level +** are ignored. +*/ +SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){ + return sqlite3ExprCompare(0, + sqlite3ExprSkipCollateAndLikely(pA), + sqlite3ExprSkipCollateAndLikely(pB), + iTab); +} + +/* +** Return non-zero if Expr p can only be true if pNN is not NULL. +** +** Or if seenNot is true, return non-zero if Expr p can only be +** non-NULL if pNN is not NULL +*/ +static int exprImpliesNotNull( + const Parse *pParse,/* Parsing context */ + const Expr *p, /* The expression to be checked */ + const Expr *pNN, /* The expression that is NOT NULL */ + int iTab, /* Table being evaluated */ + int seenNot /* Return true only if p can be any non-NULL value */ +){ + assert( p ); + assert( pNN ); + if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){ + return pNN->op!=TK_NULL; + } + switch( p->op ){ + case TK_IN: { + if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0; + assert( ExprUseXSelect(p) || (p->x.pList!=0 && p->x.pList->nExpr>0) ); + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); + } + case TK_BETWEEN: { + ExprList *pList; + assert( ExprUseXList(p) ); + pList = p->x.pList; + assert( pList!=0 ); + assert( pList->nExpr==2 ); + if( seenNot ) return 0; + if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, 1) + || exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, 1) + ){ + return 1; + } + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); + } + case TK_EQ: + case TK_NE: + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_PLUS: + case TK_MINUS: + case TK_BITOR: + case TK_LSHIFT: + case TK_RSHIFT: + case TK_CONCAT: + seenNot = 1; + /* no break */ deliberate_fall_through + case TK_STAR: + case TK_REM: + case TK_BITAND: + case TK_SLASH: { + if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1; + /* no break */ deliberate_fall_through + } + case TK_SPAN: + case TK_COLLATE: + case TK_UPLUS: + case TK_UMINUS: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_TRUTH: { + if( seenNot ) return 0; + if( p->op2!=TK_IS ) return 0; + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); + } + case TK_BITNOT: + case TK_NOT: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); + } } return 0; } @@ -95163,28 +108130,177 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ ** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has ** Expr.iTable<0 then assume a table number given by iTab. ** +** If pParse is not NULL, then the values of bound variables in pE1 are +** compared against literal values in pE2 and pParse->pVdbe->expmask is +** modified to record which bound variables are referenced. If pParse +** is NULL, then false will be returned if pE1 contains any bound variables. +** ** When in doubt, return false. Returning true might give a performance ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ -SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){ - if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){ +SQLITE_PRIVATE int sqlite3ExprImpliesExpr( + const Parse *pParse, + const Expr *pE1, + const Expr *pE2, + int iTab +){ + if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){ return 1; } if( pE2->op==TK_OR - && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab) - || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) ) + && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab) + || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) ) ){ return 1; } - if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){ - Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); - testcase( pX!=pE1->pLeft ); - if( sqlite3ExprCompare(pX, pE2->pLeft, iTab)==0 ) return 1; + if( pE2->op==TK_NOTNULL + && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0) + ){ + return 1; } return 0; } +/* +** This is the Expr node callback for sqlite3ExprImpliesNonNullRow(). +** If the expression node requires that the table at pWalker->iCur +** have one or more non-NULL column, then set pWalker->eCode to 1 and abort. +** +** This routine controls an optimization. False positives (setting +** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives +** (never setting pWalker->eCode) is a harmless missed optimization. +*/ +static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ + testcase( pExpr->op==TK_AGG_COLUMN ); + testcase( pExpr->op==TK_AGG_FUNCTION ); + if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune; + switch( pExpr->op ){ + case TK_ISNOT: + case TK_ISNULL: + case TK_NOTNULL: + case TK_IS: + case TK_OR: + case TK_VECTOR: + case TK_CASE: + case TK_IN: + case TK_FUNCTION: + case TK_TRUTH: + testcase( pExpr->op==TK_ISNOT ); + testcase( pExpr->op==TK_ISNULL ); + testcase( pExpr->op==TK_NOTNULL ); + testcase( pExpr->op==TK_IS ); + testcase( pExpr->op==TK_OR ); + testcase( pExpr->op==TK_VECTOR ); + testcase( pExpr->op==TK_CASE ); + testcase( pExpr->op==TK_IN ); + testcase( pExpr->op==TK_FUNCTION ); + testcase( pExpr->op==TK_TRUTH ); + return WRC_Prune; + case TK_COLUMN: + if( pWalker->u.iCur==pExpr->iTable ){ + pWalker->eCode = 1; + return WRC_Abort; + } + return WRC_Prune; + + case TK_AND: + if( pWalker->eCode==0 ){ + sqlite3WalkExpr(pWalker, pExpr->pLeft); + if( pWalker->eCode ){ + pWalker->eCode = 0; + sqlite3WalkExpr(pWalker, pExpr->pRight); + } + } + return WRC_Prune; + + case TK_BETWEEN: + if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){ + assert( pWalker->eCode ); + return WRC_Abort; + } + return WRC_Prune; + + /* Virtual tables are allowed to use constraints like x=NULL. So + ** a term of the form x=y does not prove that y is not null if x + ** is the column of a virtual table */ + case TK_EQ: + case TK_NE: + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: { + Expr *pLeft = pExpr->pLeft; + Expr *pRight = pExpr->pRight; + testcase( pExpr->op==TK_EQ ); + testcase( pExpr->op==TK_NE ); + testcase( pExpr->op==TK_LT ); + testcase( pExpr->op==TK_LE ); + testcase( pExpr->op==TK_GT ); + testcase( pExpr->op==TK_GE ); + /* The y.pTab=0 assignment in wherecode.c always happens after the + ** impliesNotNullRow() test */ + assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) ); + assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) ); + if( (pLeft->op==TK_COLUMN + && pLeft->y.pTab!=0 + && IsVirtual(pLeft->y.pTab)) + || (pRight->op==TK_COLUMN + && pRight->y.pTab!=0 + && IsVirtual(pRight->y.pTab)) + ){ + return WRC_Prune; + } + /* no break */ deliberate_fall_through + } + default: + return WRC_Continue; + } +} + +/* +** Return true (non-zero) if expression p can only be true if at least +** one column of table iTab is non-null. In other words, return true +** if expression p will always be NULL or false if every column of iTab +** is NULL. +** +** False negatives are acceptable. In other words, it is ok to return +** zero even if expression p will never be true of every column of iTab +** is NULL. A false negative is merely a missed optimization opportunity. +** +** False positives are not allowed, however. A false positive may result +** in an incorrect answer. +** +** Terms of p that are marked with EP_FromJoin (and hence that come from +** the ON or USING clauses of LEFT JOINS) are excluded from the analysis. +** +** This routine is used to check if a LEFT JOIN can be converted into +** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE +** clause requires that some column of the right table of the LEFT JOIN +** be non-NULL, then the LEFT JOIN can be safely converted into an +** ordinary join. +*/ +SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){ + Walker w; + p = sqlite3ExprSkipCollateAndLikely(p); + if( p==0 ) return 0; + if( p->op==TK_NOTNULL ){ + p = p->pLeft; + }else{ + while( p->op==TK_AND ){ + if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1; + p = p->pRight; + } + } + w.xExprCallback = impliesNotNullRow; + w.xSelectCallback = 0; + w.xSelectCallback2 = 0; + w.eCode = 0; + w.u.iCur = iTab; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + /* ** An instance of the following structure is used by the tree walker ** to determine if an expression can be evaluated by reference to the @@ -95198,14 +108314,14 @@ struct IdxCover { }; /* -** Check to see if there are references to columns in table +** Check to see if there are references to columns in table ** pWalker->u.pIdxCover->iCur can be satisfied using the index ** pWalker->u.pIdxCover->pIdx. */ static int exprIdxCover(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iTable==pWalker->u.pIdxCover->iCur - && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 + && sqlite3TableColumnToIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; return WRC_Abort; @@ -95240,62 +108356,181 @@ SQLITE_PRIVATE int sqlite3ExprCoveredByIndex( } -/* -** An instance of the following structure is used by the tree walker -** to count references to table columns in the arguments of an -** aggregate function, in order to implement the -** sqlite3FunctionThisSrc() routine. -*/ -struct SrcCount { - SrcList *pSrc; /* One particular FROM clause in a nested query */ - int nThis; /* Number of references to columns in pSrcList */ - int nOther; /* Number of references to columns in other FROM clauses */ +/* Structure used to pass information throught the Walker in order to +** implement sqlite3ReferencesSrcList(). +*/ +struct RefSrcList { + sqlite3 *db; /* Database connection used for sqlite3DbRealloc() */ + SrcList *pRef; /* Looking for references to these tables */ + i64 nExclude; /* Number of tables to exclude from the search */ + int *aiExclude; /* Cursor IDs for tables to exclude from the search */ }; /* -** Count the number of references to columns. +** Walker SELECT callbacks for sqlite3ReferencesSrcList(). +** +** When entering a new subquery on the pExpr argument, add all FROM clause +** entries for that subquery to the exclude list. +** +** When leaving the subquery, remove those entries from the exclude list. +*/ +static int selectRefEnter(Walker *pWalker, Select *pSelect){ + struct RefSrcList *p = pWalker->u.pRefSrcList; + SrcList *pSrc = pSelect->pSrc; + i64 i, j; + int *piNew; + if( pSrc->nSrc==0 ) return WRC_Continue; + j = p->nExclude; + p->nExclude += pSrc->nSrc; + piNew = sqlite3DbRealloc(p->db, p->aiExclude, p->nExclude*sizeof(int)); + if( piNew==0 ){ + p->nExclude = 0; + return WRC_Abort; + }else{ + p->aiExclude = piNew; + } + for(i=0; inSrc; i++, j++){ + p->aiExclude[j] = pSrc->a[i].iCursor; + } + return WRC_Continue; +} +static void selectRefLeave(Walker *pWalker, Select *pSelect){ + struct RefSrcList *p = pWalker->u.pRefSrcList; + SrcList *pSrc = pSelect->pSrc; + if( p->nExclude ){ + assert( p->nExclude>=pSrc->nSrc ); + p->nExclude -= pSrc->nSrc; + } +} + +/* This is the Walker EXPR callback for sqlite3ReferencesSrcList(). +** +** Set the 0x01 bit of pWalker->eCode if there is a reference to any +** of the tables shown in RefSrcList.pRef. +** +** Set the 0x02 bit of pWalker->eCode if there is a reference to a +** table is in neither RefSrcList.pRef nor RefSrcList.aiExclude. */ -static int exprSrcCount(Walker *pWalker, Expr *pExpr){ - /* The NEVER() on the second term is because sqlite3FunctionUsesThisSrc() - ** is always called before sqlite3ExprAnalyzeAggregates() and so the - ** TK_COLUMNs have not yet been converted into TK_AGG_COLUMN. If - ** sqlite3FunctionUsesThisSrc() is used differently in the future, the - ** NEVER() will need to be removed. */ - if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){ +static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN + || pExpr->op==TK_AGG_COLUMN + ){ int i; - struct SrcCount *p = pWalker->u.pSrcCount; - SrcList *pSrc = p->pSrc; + struct RefSrcList *p = pWalker->u.pRefSrcList; + SrcList *pSrc = p->pRef; int nSrc = pSrc ? pSrc->nSrc : 0; for(i=0; iiTable==pSrc->a[i].iCursor ) break; + if( pExpr->iTable==pSrc->a[i].iCursor ){ + pWalker->eCode |= 1; + return WRC_Continue; + } } - if( inThis++; - }else{ - p->nOther++; + for(i=0; inExclude && p->aiExclude[i]!=pExpr->iTable; i++){} + if( i>=p->nExclude ){ + pWalker->eCode |= 2; } } return WRC_Continue; } /* -** Determine if any of the arguments to the pExpr Function reference -** pSrcList. Return true if they do. Also return true if the function -** has no arguments or has only constant arguments. Return false if pExpr -** references columns but not columns of tables found in pSrcList. +** Check to see if pExpr references any tables in pSrcList. +** Possible return values: +** +** 1 pExpr does references a table in pSrcList. +** +** 0 pExpr references some table that is not defined in either +** pSrcList or in subqueries of pExpr itself. +** +** -1 pExpr only references no tables at all, or it only +** references tables defined in subqueries of pExpr itself. +** +** As currently used, pExpr is always an aggregate function call. That +** fact is exploited for efficiency. */ -SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){ +SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){ Walker w; - struct SrcCount cnt; - assert( pExpr->op==TK_AGG_FUNCTION ); + struct RefSrcList x; memset(&w, 0, sizeof(w)); - w.xExprCallback = exprSrcCount; - w.u.pSrcCount = &cnt; - cnt.pSrc = pSrcList; - cnt.nThis = 0; - cnt.nOther = 0; + memset(&x, 0, sizeof(x)); + w.xExprCallback = exprRefToSrcList; + w.xSelectCallback = selectRefEnter; + w.xSelectCallback2 = selectRefLeave; + w.u.pRefSrcList = &x; + x.db = pParse->db; + x.pRef = pSrcList; + assert( pExpr->op==TK_AGG_FUNCTION ); + assert( ExprUseXList(pExpr) ); sqlite3WalkExprList(&w, pExpr->x.pList); - return cnt.nThis>0 || cnt.nOther==0; +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter); + } +#endif + sqlite3DbFree(pParse->db, x.aiExclude); + if( w.eCode & 0x01 ){ + return 1; + }else if( w.eCode ){ + return 0; + }else{ + return -1; + } +} + +/* +** This is a Walker expression node callback. +** +** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo +** object that is referenced does not refer directly to the Expr. If +** it does, make a copy. This is done because the pExpr argument is +** subject to change. +** +** The copy is stored on pParse->pConstExpr with a register number of 0. +** This will cause the expression to be deleted automatically when the +** Parse object is destroyed, but the zero register number means that it +** will not generate any code in the preamble. +*/ +static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ + if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced)) + && pExpr->pAggInfo!=0 + ){ + AggInfo *pAggInfo = pExpr->pAggInfo; + int iAgg = pExpr->iAgg; + Parse *pParse = pWalker->pParse; + sqlite3 *db = pParse->db; + assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION ); + if( pExpr->op==TK_AGG_COLUMN ){ + assert( iAgg>=0 && iAggnColumn ); + if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){ + pExpr = sqlite3ExprDup(db, pExpr, 0); + if( pExpr ){ + pAggInfo->aCol[iAgg].pCExpr = pExpr; + sqlite3ExprDeferredDelete(pParse, pExpr); + } + } + }else{ + assert( iAgg>=0 && iAggnFunc ); + if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){ + pExpr = sqlite3ExprDup(db, pExpr, 0); + if( pExpr ){ + pAggInfo->aFunc[iAgg].pFExpr = pExpr; + sqlite3ExprDeferredDelete(pParse, pExpr); + } + } + } + } + return WRC_Continue; +} + +/* +** Initialize a Walker object so that will persist AggInfo entries referenced +** by the tree that is walked. +*/ +SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){ + memset(pWalker, 0, sizeof(*pWalker)); + pWalker->pParse = pParse; + pWalker->xExprCallback = agginfoPersistExprCb; + pWalker->xSelectCallback = sqlite3SelectWalkNoop; } /* @@ -95312,7 +108547,7 @@ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ &i ); return i; -} +} /* ** Add a new element to the pAggInfo->aFunc[] array. Return the index of @@ -95321,14 +108556,14 @@ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){ int i; pInfo->aFunc = sqlite3ArrayAllocate( - db, + db, pInfo->aFunc, sizeof(pInfo->aFunc[0]), &pInfo->nFunc, &i ); return i; -} +} /* ** This is the xExprCallback for a tree walker. It is used to @@ -95340,8 +108575,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ NameContext *pNC = pWalker->u.pNC; Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; - AggInfo *pAggInfo = pNC->pAggInfo; + AggInfo *pAggInfo = pNC->uNC.pAggInfo; + assert( pNC->ncFlags & NC_UAggInfo ); switch( pExpr->op ){ case TK_AGG_COLUMN: case TK_COLUMN: { @@ -95350,13 +108586,13 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ /* Check to see if the column is in one of the tables in the FROM ** clause of the aggregate query */ if( ALWAYS(pSrcList!=0) ){ - struct SrcList_item *pItem = pSrcList->a; + SrcItem *pItem = pSrcList->a; for(i=0; inSrc; i++, pItem++){ struct AggInfo_col *pCol; assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); if( pExpr->iTable==pItem->iCursor ){ /* If we reach this point, it means that pExpr refers to a table - ** that is in the FROM clause of the aggregate query. + ** that is in the FROM clause of the aggregate query. ** ** Make an entry for the column in pAggInfo->aCol[] if there ** is not an entry there already. @@ -95370,15 +108606,16 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ } } if( (k>=pAggInfo->nColumn) - && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 + && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; - pCol->pTab = pExpr->pTab; + assert( ExprUseYTab(pExpr) ); + pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; pCol->iMem = ++pParse->nMem; pCol->iSorterColumn = -1; - pCol->pExpr = pExpr; + pCol->pCExpr = pExpr; if( pAggInfo->pGroupBy ){ int j, n; ExprList *pGB = pAggInfo->pGroupBy; @@ -95416,12 +108653,13 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ if( (pNC->ncFlags & NC_InAggFunc)==0 && pWalker->walkerDepth==pExpr->op2 ){ - /* Check to see if pExpr is a duplicate of another aggregate + /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; inFunc; i++, pItem++){ - if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){ + if( pItem->pFExpr==pExpr ) break; + if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){ break; } } @@ -95433,11 +108671,11 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ if( i>=0 ){ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); pItem = &pAggInfo->aFunc[i]; - pItem->pExpr = pExpr; + pItem->pFExpr = pExpr; pItem->iMem = ++pParse->nMem; - assert( !ExprHasProperty(pExpr, EP_IntValue) ); + assert( ExprUseUToken(pExpr) ); pItem->pFunc = sqlite3FindFunction(pParse->db, - pExpr->u.zToken, + pExpr->u.zToken, pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0); if( pExpr->flags & EP_Distinct ){ pItem->iDistinct = pParse->nTab++; @@ -95460,11 +108698,6 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ } return WRC_Continue; } -static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ - UNUSED_PARAMETER(pWalker); - UNUSED_PARAMETER(pSelect); - return WRC_Continue; -} /* ** Analyze the pExpr expression looking for aggregate functions and @@ -95477,10 +108710,12 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ */ SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){ Walker w; - memset(&w, 0, sizeof(w)); w.xExprCallback = analyzeAggregate; - w.xSelectCallback = analyzeAggregatesInSelect; + w.xSelectCallback = sqlite3WalkerDepthIncrease; + w.xSelectCallback2 = sqlite3WalkerDepthDecrease; + w.walkerDepth = 0; w.u.pNC = pNC; + w.pParse = 0; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); } @@ -95514,22 +108749,13 @@ SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){ /* ** Deallocate a register, making available for reuse for some other ** purpose. -** -** If a register is currently being used by the column cache, then -** the deallocation is deferred until the column cache line that uses -** the register becomes stale. */ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ - if( iReg && pParse->nTempRegaTempReg) ){ - int i; - struct yColCache *p; - for(i=0, p=pParse->aColCache; inColCache; i++, p++){ - if( p->iReg==iReg ){ - p->tempReg = 1; - return; - } + if( iReg ){ + sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0); + if( pParse->nTempRegaTempReg) ){ + pParse->aTempReg[pParse->nTempReg++] = iReg; } - pParse->aTempReg[pParse->nTempReg++] = iReg; } } @@ -95542,7 +108768,6 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){ i = pParse->iRangeReg; n = pParse->nRangeReg; if( nReg<=n ){ - assert( !usedAsColumnCache(pParse, i, i+n-1) ); pParse->iRangeReg += nReg; pParse->nRangeReg -= nReg; }else{ @@ -95556,7 +108781,7 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ sqlite3ReleaseTempReg(pParse, iReg); return; } - sqlite3ExprCacheRemove(pParse, iReg, nReg); + sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0, 0); if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; pParse->iRangeReg = iReg; @@ -95565,6 +108790,11 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ /* ** Mark all temporary registers as being unavailable for reuse. +** +** Always invoke this procedure after coding a subroutine or co-routine +** that might be invoked from other parts of the code, to ensure that +** the sub/co-routine does not use registers in common with the code that +** invokes the sub/co-routine. */ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){ pParse->nTempReg = 0; @@ -95580,8 +108810,8 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ int i; if( pParse->nRangeReg>0 - && pParse->iRangeReg+pParse->nRangeRegiRangeReg>=iFirst + && pParse->iRangeReg+pParse->nRangeReg > iFirst + && pParse->iRangeReg <= iLast ){ return 0; } @@ -95618,371 +108848,106 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){ */ #ifndef SQLITE_OMIT_ALTERTABLE - -/* -** This function is used by SQL generated to implement the -** ALTER TABLE command. The first argument is the text of a CREATE TABLE or -** CREATE INDEX command. The second is a table name. The table name in -** the CREATE TABLE or CREATE INDEX statement is replaced with the third -** argument and the result returned. Examples: -** -** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') -** -> 'CREATE TABLE def(a, b, c)' -** -** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') -** -> 'CREATE INDEX i ON def(a, b, c)' -*/ -static void renameTableFunc( - sqlite3_context *context, - int NotUsed, - sqlite3_value **argv -){ - unsigned char const *zSql = sqlite3_value_text(argv[0]); - unsigned char const *zTableName = sqlite3_value_text(argv[1]); - - int token; - Token tname; - unsigned char const *zCsr = zSql; - int len = 0; - char *zRet; - - sqlite3 *db = sqlite3_context_db_handle(context); - - UNUSED_PARAMETER(NotUsed); - - /* The principle used to locate the table name in the CREATE TABLE - ** statement is that the table name is the first non-space token that - ** is immediately followed by a TK_LP or TK_USING token. - */ - if( zSql ){ - do { - if( !*zCsr ){ - /* Ran out of input before finding an opening bracket. Return NULL. */ - return; - } - - /* Store the token that zCsr points to in tname. */ - tname.z = (char*)zCsr; - tname.n = len; - - /* Advance zCsr to the next token. Store that token type in 'token', - ** and its length in 'len' (to be used next iteration of this loop). - */ - do { - zCsr += len; - len = sqlite3GetToken(zCsr, &token); - } while( token==TK_SPACE ); - assert( len>0 ); - } while( token!=TK_LP && token!=TK_USING ); - - zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), - zSql, zTableName, tname.z+tname.n); - sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); - } -} - /* -** This C function implements an SQL user function that is used by SQL code -** generated by the ALTER TABLE ... RENAME command to modify the definition -** of any foreign key constraints that use the table being renamed as the -** parent table. It is passed three arguments: -** -** 1) The complete text of the CREATE TABLE statement being modified, -** 2) The old name of the table being renamed, and -** 3) The new name of the table being renamed. -** -** It returns the new CREATE TABLE statement. For example: +** Parameter zName is the name of a table that is about to be altered +** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). +** If the table is a system table, this function leaves an error message +** in pParse->zErr (system tables may not be altered) and returns non-zero. ** -** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3') -** -> 'CREATE TABLE t1(a REFERENCES t3)' -*/ -#ifndef SQLITE_OMIT_FOREIGN_KEY -static void renameParentFunc( - sqlite3_context *context, - int NotUsed, - sqlite3_value **argv -){ - sqlite3 *db = sqlite3_context_db_handle(context); - char *zOutput = 0; - char *zResult; - unsigned char const *zInput = sqlite3_value_text(argv[0]); - unsigned char const *zOld = sqlite3_value_text(argv[1]); - unsigned char const *zNew = sqlite3_value_text(argv[2]); - - unsigned const char *z; /* Pointer to token */ - int n; /* Length of token z */ - int token; /* Type of token */ - - UNUSED_PARAMETER(NotUsed); - if( zInput==0 || zOld==0 ) return; - for(z=zInput; *z; z=z+n){ - n = sqlite3GetToken(z, &token); - if( token==TK_REFERENCES ){ - char *zParent; - do { - z += n; - n = sqlite3GetToken(z, &token); - }while( token==TK_SPACE ); - - if( token==TK_ILLEGAL ) break; - zParent = sqlite3DbStrNDup(db, (const char *)z, n); - if( zParent==0 ) break; - sqlite3Dequote(zParent); - if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){ - char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"", - (zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew - ); - sqlite3DbFree(db, zOutput); - zOutput = zOut; - zInput = &z[n]; - } - sqlite3DbFree(db, zParent); - } - } - - zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput), - sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC); - sqlite3DbFree(db, zOutput); -} -#endif - -#ifndef SQLITE_OMIT_TRIGGER -/* This function is used by SQL generated to implement the -** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER -** statement. The second is a table name. The table name in the CREATE -** TRIGGER statement is replaced with the third argument and the result -** returned. This is analagous to renameTableFunc() above, except for CREATE -** TRIGGER, not CREATE INDEX and CREATE TABLE. -*/ -static void renameTriggerFunc( - sqlite3_context *context, - int NotUsed, - sqlite3_value **argv -){ - unsigned char const *zSql = sqlite3_value_text(argv[0]); - unsigned char const *zTableName = sqlite3_value_text(argv[1]); - - int token; - Token tname; - int dist = 3; - unsigned char const *zCsr = zSql; - int len = 0; - char *zRet; - sqlite3 *db = sqlite3_context_db_handle(context); - - UNUSED_PARAMETER(NotUsed); - - /* The principle used to locate the table name in the CREATE TRIGGER - ** statement is that the table name is the first token that is immediately - ** preceded by either TK_ON or TK_DOT and immediately followed by one - ** of TK_WHEN, TK_BEGIN or TK_FOR. - */ - if( zSql ){ - do { - - if( !*zCsr ){ - /* Ran out of input before finding the table name. Return NULL. */ - return; - } - - /* Store the token that zCsr points to in tname. */ - tname.z = (char*)zCsr; - tname.n = len; - - /* Advance zCsr to the next token. Store that token type in 'token', - ** and its length in 'len' (to be used next iteration of this loop). - */ - do { - zCsr += len; - len = sqlite3GetToken(zCsr, &token); - }while( token==TK_SPACE ); - assert( len>0 ); - - /* Variable 'dist' stores the number of tokens read since the most - ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN - ** token is read and 'dist' equals 2, the condition stated above - ** to be met. - ** - ** Note that ON cannot be a database, table or column name, so - ** there is no need to worry about syntax like - ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc. - */ - dist++; - if( token==TK_DOT || token==TK_ON ){ - dist = 0; - } - } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) ); - - /* Variable tname now contains the token that is the old table-name - ** in the CREATE TRIGGER statement. - */ - zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql), - zSql, zTableName, tname.z+tname.n); - sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); - } -} -#endif /* !SQLITE_OMIT_TRIGGER */ - -/* -** Register built-in functions used to help implement ALTER TABLE +** Or, if zName is not a system table, zero is returned. */ -SQLITE_PRIVATE void sqlite3AlterFunctions(void){ - static FuncDef aAlterTableFuncs[] = { - FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc), -#ifndef SQLITE_OMIT_TRIGGER - FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc), -#endif -#ifndef SQLITE_OMIT_FOREIGN_KEY - FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc), +static int isAlterableTable(Parse *pParse, Table *pTab){ + if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7) +#ifndef SQLITE_OMIT_VIRTUALTABLE + || (pTab->tabFlags & TF_Eponymous)!=0 + || ( (pTab->tabFlags & TF_Shadow)!=0 + && sqlite3ReadOnlyShadowTables(pParse->db) + ) #endif - }; - sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); -} - -/* -** This function is used to create the text of expressions of the form: -** -** name= OR name= OR ... -** -** If argument zWhere is NULL, then a pointer string containing the text -** "name=" is returned, where is the quoted version -** of the string passed as argument zConstant. The returned buffer is -** allocated using sqlite3DbMalloc(). It is the responsibility of the -** caller to ensure that it is eventually freed. -** -** If argument zWhere is not NULL, then the string returned is -** " OR name=", where is the contents of zWhere. -** In this case zWhere is passed to sqlite3DbFree() before returning. -** -*/ -static char *whereOrName(sqlite3 *db, char *zWhere, char *zConstant){ - char *zNew; - if( !zWhere ){ - zNew = sqlite3MPrintf(db, "name=%Q", zConstant); - }else{ - zNew = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, zConstant); - sqlite3DbFree(db, zWhere); - } - return zNew; -} - -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) -/* -** Generate the text of a WHERE expression which can be used to select all -** tables that have foreign key constraints that refer to table pTab (i.e. -** constraints for which pTab is the parent table) from the sqlite_master -** table. -*/ -static char *whereForeignKeys(Parse *pParse, Table *pTab){ - FKey *p; - char *zWhere = 0; - for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ - zWhere = whereOrName(pParse->db, zWhere, p->pFrom->zName); + ){ + sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName); + return 1; } - return zWhere; + return 0; } -#endif /* -** Generate the text of a WHERE expression which can be used to select all -** temporary triggers on table pTab from the sqlite_temp_master table. If -** table pTab has no temporary triggers, or is itself stored in the -** temporary database, NULL is returned. +** Generate code to verify that the schemas of database zDb and, if +** bTemp is not true, database "temp", can still be parsed. This is +** called at the end of the generation of an ALTER TABLE ... RENAME ... +** statement to ensure that the operation has not rendered any schema +** objects unusable. */ -static char *whereTempTriggers(Parse *pParse, Table *pTab){ - Trigger *pTrig; - char *zWhere = 0; - const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */ +static void renameTestSchema( + Parse *pParse, /* Parse context */ + const char *zDb, /* Name of db to verify schema of */ + int bTemp, /* True if this is the temp db */ + const char *zWhen, /* "when" part of error message */ + int bNoDQS /* Do not allow DQS in the schema */ +){ + pParse->colNamesSet = 1; + sqlite3NestedParse(pParse, + "SELECT 1 " + "FROM \"%w\"." LEGACY_SCHEMA_TABLE " " + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" + " AND sql NOT LIKE 'create virtual%%'" + " AND sqlite_rename_test(%Q, sql, type, name, %d, %Q, %d)=NULL ", + zDb, + zDb, bTemp, zWhen, bNoDQS + ); - /* If the table is not located in the temp-db (in which case NULL is - ** returned, loop through the tables list of triggers. For each trigger - ** that is not part of the temp-db schema, add a clause to the WHERE - ** expression being built up in zWhere. - */ - if( pTab->pSchema!=pTempSchema ){ - sqlite3 *db = pParse->db; - for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ - if( pTrig->pSchema==pTempSchema ){ - zWhere = whereOrName(db, zWhere, pTrig->zName); - } - } - } - if( zWhere ){ - char *zNew = sqlite3MPrintf(pParse->db, "type='trigger' AND (%s)", zWhere); - sqlite3DbFree(pParse->db, zWhere); - zWhere = zNew; + if( bTemp==0 ){ + sqlite3NestedParse(pParse, + "SELECT 1 " + "FROM temp." LEGACY_SCHEMA_TABLE " " + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" + " AND sql NOT LIKE 'create virtual%%'" + " AND sqlite_rename_test(%Q, sql, type, name, 1, %Q, %d)=NULL ", + zDb, zWhen, bNoDQS + ); } - return zWhere; } /* -** Generate code to drop and reload the internal representation of table -** pTab from the database, including triggers and temporary triggers. -** Argument zName is the name of the table in the database schema at -** the time the generated code is executed. This can be different from -** pTab->zName if this function is being called to code part of an -** "ALTER TABLE RENAME TO" statement. +** Generate VM code to replace any double-quoted strings (but not double-quoted +** identifiers) within the "sql" column of the sqlite_schema table in +** database zDb with their single-quoted equivalents. If argument bTemp is +** not true, similarly update all SQL statements in the sqlite_schema table +** of the temp db. */ -static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ - Vdbe *v; - char *zWhere; - int iDb; /* Index of database containing pTab */ -#ifndef SQLITE_OMIT_TRIGGER - Trigger *pTrig; -#endif - - v = sqlite3GetVdbe(pParse); - if( NEVER(v==0) ) return; - assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); - iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - assert( iDb>=0 ); - -#ifndef SQLITE_OMIT_TRIGGER - /* Drop any table triggers from the internal schema. */ - for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ - int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); - assert( iTrigDb==iDb || iTrigDb==1 ); - sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->zName, 0); - } -#endif - - /* Drop the table and index from the internal schema. */ - sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); - - /* Reload the table, index and permanent trigger schemas. */ - zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName); - if( !zWhere ) return; - sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); - -#ifndef SQLITE_OMIT_TRIGGER - /* Now, if the table is not stored in the temp database, reload any temp - ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. - */ - if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ - sqlite3VdbeAddParseSchemaOp(v, 1, zWhere); +static void renameFixQuotes(Parse *pParse, const char *zDb, int bTemp){ + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE + " SET sql = sqlite_rename_quotefix(%Q, sql)" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" + " AND sql NOT LIKE 'create virtual%%'" , zDb, zDb + ); + if( bTemp==0 ){ + sqlite3NestedParse(pParse, + "UPDATE temp." LEGACY_SCHEMA_TABLE + " SET sql = sqlite_rename_quotefix('temp', sql)" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" + " AND sql NOT LIKE 'create virtual%%'" + ); } -#endif } /* -** Parameter zName is the name of a table that is about to be altered -** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). -** If the table is a system table, this function leaves an error message -** in pParse->zErr (system tables may not be altered) and returns non-zero. -** -** Or, if zName is not a system table, zero is returned. +** Generate code to reload the schema for database iDb. And, if iDb!=1, for +** the temp database as well. */ -static int isSystemTable(Parse *pParse, const char *zName){ - if( sqlite3Strlen30(zName)>6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ - sqlite3ErrorMsg(pParse, "table %s may not be altered", zName); - return 1; +static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){ + Vdbe *v = pParse->pVdbe; + if( v ){ + sqlite3ChangeCookie(pParse, iDb); + sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5); + if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5); } - return 0; } /* -** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" -** command. +** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" +** command. */ SQLITE_PRIVATE void sqlite3AlterRenameTable( Parse *pParse, /* Parser context. */ @@ -95992,18 +108957,13 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( int iDb; /* Database that contains the table */ char *zDb; /* Name of database iDb */ Table *pTab; /* Table being renamed */ - char *zName = 0; /* NULL-terminated version of pName */ + char *zName = 0; /* NULL-terminated version of pName */ sqlite3 *db = pParse->db; /* Database connection */ int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; -#ifndef SQLITE_OMIT_TRIGGER - char *zWhere = 0; /* Where clause to locate temp triggers */ -#endif VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ - int savedDbFlags; /* Saved value of db->flags */ - savedDbFlags = db->flags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); @@ -96012,7 +108972,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( if( !pTab ) goto exit_rename_table; iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; - db->flags |= SQLITE_PreferBuiltin; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(db, pName); @@ -96021,8 +108980,11 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( /* Check that a table or index named 'zName' does not already exist ** in database iDb. If so, this is an error. */ - if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){ - sqlite3ErrorMsg(pParse, + if( sqlite3FindTable(db, zName, zDb) + || sqlite3FindIndex(db, zName, zDb) + || sqlite3IsShadowTableOf(db, pTab, zName) + ){ + sqlite3ErrorMsg(pParse, "there is already another table or index with this name: %s", zName); goto exit_rename_table; } @@ -96030,15 +108992,15 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( /* Make sure it is not a system table being altered, or a reserved name ** that the table is being renamed to. */ - if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ + if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_rename_table; } - if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto - exit_rename_table; + if( SQLITE_OK!=sqlite3CheckObjectName(pParse,zName,"table",zName) ){ + goto exit_rename_table; } #ifndef SQLITE_OMIT_VIEW - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); goto exit_rename_table; } @@ -96063,78 +109025,50 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( } #endif - /* Begin a transaction for database iDb. - ** Then modify the schema cookie (since the ALTER TABLE modifies the - ** schema). Open a statement transaction if the table is a virtual - ** table. - */ + /* Begin a transaction for database iDb. Then modify the schema cookie + ** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(), + ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the + ** nested SQL may raise an exception. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } - sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb); - sqlite3ChangeCookie(pParse, iDb); - - /* If this is a virtual table, invoke the xRename() function if - ** one is defined. The xRename() callback will modify the names - ** of any resources used by the v-table implementation (including other - ** SQLite tables) that are identified by the name of the virtual table. - */ -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( pVTab ){ - int i = ++pParse->nMem; - sqlite3VdbeLoadString(v, i, zName); - sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); - sqlite3MayAbort(pParse); - } -#endif + sqlite3MayAbort(pParse); /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - if( db->flags&SQLITE_ForeignKeys ){ - /* If foreign-key support is enabled, rewrite the CREATE TABLE - ** statements corresponding to all child tables of foreign key constraints - ** for which the renamed table is the parent table. */ - if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){ - sqlite3NestedParse(pParse, - "UPDATE \"%w\".%s SET " - "sql = sqlite_rename_parent(sql, %Q, %Q) " - "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere); - sqlite3DbFree(db, zWhere); - } - } -#endif + /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in + ** the schema to use the new table name. */ + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " + "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" + "AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" + , zDb, zDb, zTabName, zName, (iDb==1), zTabName + ); - /* Modify the sqlite_master table to use the new table name. */ + /* Update the tbl_name and name columns of the sqlite_schema table + ** as required. */ sqlite3NestedParse(pParse, - "UPDATE %Q.%s SET " -#ifdef SQLITE_OMIT_TRIGGER - "sql = sqlite_rename_table(sql, %Q), " -#else - "sql = CASE " - "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" - "ELSE sqlite_rename_table(sql, %Q) END, " -#endif + "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET " "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " - "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " + "WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' " + " AND type='index' THEN " "'sqlite_autoindex_' || %Q || substr(name,%d+18) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " - "(type='table' OR type='index' OR type='trigger');", - zDb, MASTER_NAME, zName, zName, zName, -#ifndef SQLITE_OMIT_TRIGGER - zName, -#endif - zName, nTabName, zTabName + "(type='table' OR type='index' OR type='trigger');", + zDb, + zName, zName, zName, + nTabName, zTabName ); #ifndef SQLITE_OMIT_AUTOINCREMENT - /* If the sqlite_sequence table exists in this database, then update + /* If the sqlite_sequence table exists in this database, then update ** it with the new table name. */ if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ @@ -96144,40 +109078,56 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( } #endif -#ifndef SQLITE_OMIT_TRIGGER - /* If there are TEMP triggers on this table, modify the sqlite_temp_master - ** table. Don't do this if the table being ALTERed is itself located in - ** the temp database. - */ - if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ - sqlite3NestedParse(pParse, - "UPDATE sqlite_temp_master SET " - "sql = sqlite_rename_trigger(sql, %Q), " - "tbl_name = %Q " - "WHERE %s;", zName, zName, zWhere); - sqlite3DbFree(db, zWhere); + /* If the table being renamed is not itself part of the temp database, + ** edit view and trigger definitions within the temp database + ** as required. */ + if( iDb!=1 ){ + sqlite3NestedParse(pParse, + "UPDATE sqlite_temp_schema SET " + "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), " + "tbl_name = " + "CASE WHEN tbl_name=%Q COLLATE nocase AND " + " sqlite_rename_test(%Q, sql, type, name, 1, 'after rename', 0) " + "THEN %Q ELSE tbl_name END " + "WHERE type IN ('view', 'trigger')" + , zDb, zTabName, zName, zTabName, zDb, zName); } -#endif -#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) - if( db->flags&SQLITE_ForeignKeys ){ - FKey *p; - for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ - Table *pFrom = p->pFrom; - if( pFrom!=pTab ){ - reloadTableSchema(pParse, p->pFrom, pFrom->zName); - } - } + /* If this is a virtual table, invoke the xRename() function if + ** one is defined. The xRename() callback will modify the names + ** of any resources used by the v-table implementation (including other + ** SQLite tables) that are identified by the name of the virtual table. + */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( pVTab ){ + int i = ++pParse->nMem; + sqlite3VdbeLoadString(v, i, zName); + sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); } #endif - /* Drop and reload the internal table schema. */ - reloadTableSchema(pParse, pTab, zName); + renameReloadSchema(pParse, iDb, INITFLAG_AlterRename); + renameTestSchema(pParse, zDb, iDb==1, "after rename", 0); exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); - db->flags = savedDbFlags; +} + +/* +** Write code that will raise an error if the table described by +** zDb and zTab is not empty. +*/ +static void sqlite3ErrorIfNotEmpty( + Parse *pParse, /* Parsing context */ + const char *zDb, /* Schema holding the table */ + const char *zTab, /* Table to check for empty */ + const char *zErr /* Error message text */ +){ + sqlite3NestedParse(pParse, + "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"", + zErr, zDb, zTab + ); } /* @@ -96198,12 +109148,13 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ - Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ + Vdbe *v; /* The prepared statement under construction */ int r1; /* Temporary registers */ db = pParse->db; - if( pParse->nErr || db->mallocFailed ) return; - assert( v!=0 ); + assert( db->pParse==pParse ); + if( pParse->nErr ) return; + assert( db->mallocFailed==0 ); pNew = pParse->pNewTable; assert( pNew ); @@ -96212,7 +109163,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ pCol = &pNew->aCol[pNew->nCol-1]; - pDflt = pCol->pDflt; + pDflt = sqlite3ColumnExpr(pNew, pCol); pTab = sqlite3FindTable(db, zTab, zDb); assert( pTab ); @@ -96223,14 +109174,6 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ } #endif - /* If the default value for the new column was specified with a - ** literal NULL, then set pDflt to 0. This simplifies checking - ** for an SQL NULL default below. - */ - assert( pDflt==0 || pDflt->op==TK_SPAN ); - if( pDflt && pDflt->pLeft->op==TK_NULL ){ - pDflt = 0; - } /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the @@ -96241,86 +109184,120 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ return; } if( pNew->pIndex ){ - sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); - return; - } - if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ - sqlite3ErrorMsg(pParse, - "Cannot add a REFERENCES column with non-NULL default value"); - return; - } - if( pCol->notNull && !pDflt ){ - sqlite3ErrorMsg(pParse, - "Cannot add a NOT NULL column with default value NULL"); + sqlite3ErrorMsg(pParse, + "Cannot add a UNIQUE column"); return; } - - /* Ensure the default expression is something that sqlite3ValueFromExpr() - ** can handle (i.e. not CURRENT_TIME etc.) - */ - if( pDflt ){ - sqlite3_value *pVal = 0; - int rc; - rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); - assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); - if( rc!=SQLITE_OK ){ - assert( db->mallocFailed == 1 ); - return; + if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){ + /* If the default value for the new column was specified with a + ** literal NULL, then set pDflt to 0. This simplifies checking + ** for an SQL NULL default below. + */ + assert( pDflt==0 || pDflt->op==TK_SPAN ); + if( pDflt && pDflt->pLeft->op==TK_NULL ){ + pDflt = 0; } - if( !pVal ){ - sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); - return; + assert( IsOrdinaryTable(pNew) ); + if( (db->flags&SQLITE_ForeignKeys) && pNew->u.tab.pFKey && pDflt ){ + sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, + "Cannot add a REFERENCES column with non-NULL default value"); + } + if( pCol->notNull && !pDflt ){ + sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, + "Cannot add a NOT NULL column with default value NULL"); + } + + + /* Ensure the default expression is something that sqlite3ValueFromExpr() + ** can handle (i.e. not CURRENT_TIME etc.) + */ + if( pDflt ){ + sqlite3_value *pVal = 0; + int rc; + rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc!=SQLITE_OK ){ + assert( db->mallocFailed == 1 ); + return; + } + if( !pVal ){ + sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, + "Cannot add a column with non-constant default"); + } + sqlite3ValueFree(pVal); } - sqlite3ValueFree(pVal); + }else if( pCol->colFlags & COLFLAG_STORED ){ + sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column"); } + /* Modify the CREATE TABLE statement. */ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; - int savedDbFlags = db->flags; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } - db->flags |= SQLITE_PreferBuiltin; - sqlite3NestedParse(pParse, - "UPDATE \"%w\".%s SET " - "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " - "WHERE type = 'table' AND name = %Q", - zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1, + /* substr() operations on characters, but addColOffset is in bytes. So we + ** have to use printf() to translate between these units: */ + assert( IsOrdinaryTable(pTab) ); + assert( IsOrdinaryTable(pNew) ); + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = printf('%%.%ds, ',sql) || %Q" + " || substr(sql,1+length(printf('%%.%ds',sql))) " + "WHERE type = 'table' AND name = %Q", + zDb, pNew->u.tab.addColOffset, zCol, pNew->u.tab.addColOffset, zTab ); sqlite3DbFree(db, zCol); - db->flags = savedDbFlags; } - /* Make sure the schema version is at least 3. But do not upgrade - ** from less than 3 to 4, as that will corrupt any preexisting DESC - ** index. - */ - r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); - sqlite3VdbeUsesBtree(v, iDb); - sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); - sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); - sqlite3ReleaseTempReg(pParse, r1); + v = sqlite3GetVdbe(pParse); + if( v ){ + /* Make sure the schema version is at least 3. But do not upgrade + ** from less than 3 to 4, as that will corrupt any preexisting DESC + ** index. + */ + r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); + sqlite3VdbeUsesBtree(v, iDb); + sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); + sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); + sqlite3ReleaseTempReg(pParse, r1); + + /* Reload the table definition */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterAdd); - /* Reload the schema of the modified table. */ - reloadTableSchema(pParse, pTab, pTab->zName); + /* Verify that constraints are still satisfied */ + if( pNew->pCheck!=0 + || (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0) + ){ + sqlite3NestedParse(pParse, + "SELECT CASE WHEN quick_check GLOB 'CHECK*'" + " THEN raise(ABORT,'CHECK constraint failed')" + " ELSE raise(ABORT,'NOT NULL constraint failed')" + " END" + " FROM pragma_quick_check(%Q,%Q)" + " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'", + zTab, zDb + ); + } + } } /* ** This function is called by the parser after the table-name in -** an "ALTER TABLE ADD" statement is parsed. Argument +** an "ALTER TABLE ADD" statement is parsed. Argument ** pSrc is the full-name of the table being altered. ** ** This routine makes a (partial) copy of the Table structure ** for the table being altered and sets Parse.pNewTable to point ** to it. Routines called by the parser as the column definition -** is parsed (i.e. sqlite3AddColumn()) add the new Column data to -** the copy. The copy of the Table structure is deleted by tokenize.c +** is parsed (i.e. sqlite3AddColumn()) add the new Column data to +** the copy. The copy of the Table structure is deleted by tokenize.c ** after parsing is finished. ** ** Routine sqlite3AlterFinishAddColumn() will be called to complete @@ -96329,7 +109306,6 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ Table *pNew; Table *pTab; - Vdbe *v; int iDb; int i; int nAlloc; @@ -96350,15 +109326,17 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ #endif /* Make sure this is not an attempt to ALTER a view. */ - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); goto exit_begin_add_column; } - if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){ + if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){ goto exit_begin_add_column; } - assert( pTab->addColOffset>0 ); + sqlite3MayAbort(pParse); + assert( IsOrdinaryTable(pTab) ); + assert( pTab->u.tab.addColOffset>0 ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); /* Put a copy of the Table struct in Parse.pNewTable for the @@ -96385,24 +109363,1728 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol); for(i=0; inCol; i++){ Column *pCol = &pNew->aCol[i]; - pCol->zName = sqlite3DbStrDup(db, pCol->zName); - pCol->zColl = 0; - pCol->pDflt = 0; + pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName); + pCol->hName = sqlite3StrIHash(pCol->zCnName); } + assert( IsOrdinaryTable(pNew) ); + pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0); pNew->pSchema = db->aDb[iDb].pSchema; - pNew->addColOffset = pTab->addColOffset; + pNew->u.tab.addColOffset = pTab->u.tab.addColOffset; pNew->nTabRef = 1; - /* Begin a transaction and increment the schema cookie. */ - sqlite3BeginWriteOperation(pParse, 0, iDb); - v = sqlite3GetVdbe(pParse); - if( !v ) goto exit_begin_add_column; - sqlite3ChangeCookie(pParse, iDb); - exit_begin_add_column: sqlite3SrcListDelete(db, pSrc); return; } + +/* +** Parameter pTab is the subject of an ALTER TABLE ... RENAME COLUMN +** command. This function checks if the table is a view or virtual +** table (columns of views or virtual tables may not be renamed). If so, +** it loads an error message into pParse and returns non-zero. +** +** Or, if pTab is not a view or virtual table, zero is returned. +*/ +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) +static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ + const char *zType = 0; +#ifndef SQLITE_OMIT_VIEW + if( IsView(pTab) ){ + zType = "view"; + } +#endif +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( IsVirtual(pTab) ){ + zType = "virtual table"; + } +#endif + if( zType ){ + sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"", + (bDrop ? "drop column from" : "rename columns of"), + zType, pTab->zName + ); + return 1; + } + return 0; +} +#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ +# define isRealTable(x,y,z) (0) +#endif + +/* +** Handles the following parser reduction: +** +** cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew +*/ +SQLITE_PRIVATE void sqlite3AlterRenameColumn( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* Table being altered. pSrc->nSrc==1 */ + Token *pOld, /* Name of column being changed */ + Token *pNew /* New column name */ +){ + sqlite3 *db = pParse->db; /* Database connection */ + Table *pTab; /* Table being updated */ + int iCol; /* Index of column being renamed */ + char *zOld = 0; /* Old column name */ + char *zNew = 0; /* New column name */ + const char *zDb; /* Name of schema containing the table */ + int iSchema; /* Index of the schema */ + int bQuote; /* True to quote the new name */ + + /* Locate the table to be altered */ + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); + if( !pTab ) goto exit_rename_column; + + /* Cannot alter a system table */ + if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column; + if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column; + + /* Which schema holds the table to be altered */ + iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iSchema>=0 ); + zDb = db->aDb[iSchema].zDbSName; + +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Invoke the authorization callback. */ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ + goto exit_rename_column; + } +#endif + + /* Make sure the old name really is a column name in the table to be + ** altered. Set iCol to be the index of the column being renamed */ + zOld = sqlite3NameFromToken(db, pOld); + if( !zOld ) goto exit_rename_column; + for(iCol=0; iColnCol; iCol++){ + if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break; + } + if( iCol==pTab->nCol ){ + sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld); + goto exit_rename_column; + } + + /* Ensure the schema contains no double-quoted strings */ + renameTestSchema(pParse, zDb, iSchema==1, "", 0); + renameFixQuotes(pParse, zDb, iSchema==1); + + /* Do the rename operation using a recursive UPDATE statement that + ** uses the sqlite_rename_column() SQL function to compute the new + ** CREATE statement text for the sqlite_schema table. + */ + sqlite3MayAbort(pParse); + zNew = sqlite3NameFromToken(db, pNew); + if( !zNew ) goto exit_rename_column; + assert( pNew->n>0 ); + bQuote = sqlite3Isquote(pNew->z[0]); + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' " + " AND (type != 'index' OR tbl_name = %Q)", + zDb, + zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, + pTab->zName + ); + + sqlite3NestedParse(pParse, + "UPDATE temp." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) " + "WHERE type IN ('trigger', 'view')", + zDb, pTab->zName, iCol, zNew, bQuote + ); + + /* Drop and reload the database schema. */ + renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename); + renameTestSchema(pParse, zDb, iSchema==1, "after rename", 1); + + exit_rename_column: + sqlite3SrcListDelete(db, pSrc); + sqlite3DbFree(db, zOld); + sqlite3DbFree(db, zNew); + return; +} + +/* +** Each RenameToken object maps an element of the parse tree into +** the token that generated that element. The parse tree element +** might be one of: +** +** * A pointer to an Expr that represents an ID +** * The name of a table column in Column.zName +** +** A list of RenameToken objects can be constructed during parsing. +** Each new object is created by sqlite3RenameTokenMap(). +** As the parse tree is transformed, the sqlite3RenameTokenRemap() +** routine is used to keep the mapping current. +** +** After the parse finishes, renameTokenFind() routine can be used +** to look up the actual token value that created some element in +** the parse tree. +*/ +struct RenameToken { + const void *p; /* Parse tree element created by token t */ + Token t; /* The token that created parse tree element p */ + RenameToken *pNext; /* Next is a list of all RenameToken objects */ +}; + +/* +** The context of an ALTER TABLE RENAME COLUMN operation that gets passed +** down into the Walker. +*/ +typedef struct RenameCtx RenameCtx; +struct RenameCtx { + RenameToken *pList; /* List of tokens to overwrite */ + int nList; /* Number of tokens in pList */ + int iCol; /* Index of column being renamed */ + Table *pTab; /* Table being ALTERed */ + const char *zOld; /* Old column name */ +}; + +#ifdef SQLITE_DEBUG +/* +** This function is only for debugging. It performs two tasks: +** +** 1. Checks that pointer pPtr does not already appear in the +** rename-token list. +** +** 2. Dereferences each pointer in the rename-token list. +** +** The second is most effective when debugging under valgrind or +** address-sanitizer or similar. If any of these pointers no longer +** point to valid objects, an exception is raised by the memory-checking +** tool. +** +** The point of this is to prevent comparisons of invalid pointer values. +** Even though this always seems to work, it is undefined according to the +** C standard. Example of undefined comparison: +** +** sqlite3_free(x); +** if( x==y ) ... +** +** Technically, as x no longer points into a valid object or to the byte +** following a valid object, it may not be used in comparison operations. +*/ +static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ + assert( pParse==pParse->db->pParse ); + assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); + if( pParse->nErr==0 ){ + const RenameToken *p; + u8 i = 0; + for(p=pParse->pRename; p; p=p->pNext){ + if( p->p ){ + assert( p->p!=pPtr ); + i += *(u8*)(p->p); + } + } + } +} +#else +# define renameTokenCheckAll(x,y) +#endif + +/* +** Remember that the parser tree element pPtr was created using +** the token pToken. +** +** In other words, construct a new RenameToken object and add it +** to the list of RenameToken objects currently being built up +** in pParse->pRename. +** +** The pPtr argument is returned so that this routine can be used +** with tail recursion in tokenExpr() routine, for a small performance +** improvement. +*/ +SQLITE_PRIVATE const void *sqlite3RenameTokenMap( + Parse *pParse, + const void *pPtr, + const Token *pToken +){ + RenameToken *pNew; + assert( pPtr || pParse->db->mallocFailed ); + renameTokenCheckAll(pParse, pPtr); + if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){ + pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken)); + if( pNew ){ + pNew->p = pPtr; + pNew->t = *pToken; + pNew->pNext = pParse->pRename; + pParse->pRename = pNew; + } + } + + return pPtr; +} + +/* +** It is assumed that there is already a RenameToken object associated +** with parse tree element pFrom. This function remaps the associated token +** to parse tree element pTo. +*/ +SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, const void *pTo, const void *pFrom){ + RenameToken *p; + renameTokenCheckAll(pParse, pTo); + for(p=pParse->pRename; p; p=p->pNext){ + if( p->p==pFrom ){ + p->p = pTo; + break; + } + } +} + +/* +** Walker callback used by sqlite3RenameExprUnmap(). +*/ +static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ + Parse *pParse = pWalker->pParse; + sqlite3RenameTokenRemap(pParse, 0, (const void*)pExpr); + if( ExprUseYTab(pExpr) ){ + sqlite3RenameTokenRemap(pParse, 0, (const void*)&pExpr->y.pTab); + } + return WRC_Continue; +} + +/* +** Iterate through the Select objects that are part of WITH clauses attached +** to select statement pSelect. +*/ +static void renameWalkWith(Walker *pWalker, Select *pSelect){ + With *pWith = pSelect->pWith; + if( pWith ){ + Parse *pParse = pWalker->pParse; + int i; + With *pCopy = 0; + assert( pWith->nCte>0 ); + if( (pWith->a[0].pSelect->selFlags & SF_Expanded)==0 ){ + /* Push a copy of the With object onto the with-stack. We use a copy + ** here as the original will be expanded and resolved (flags SF_Expanded + ** and SF_Resolved) below. And the parser code that uses the with-stack + ** fails if the Select objects on it have already been expanded and + ** resolved. */ + pCopy = sqlite3WithDup(pParse->db, pWith); + pCopy = sqlite3WithPush(pParse, pCopy, 1); + } + for(i=0; inCte; i++){ + Select *p = pWith->a[i].pSelect; + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC); + if( sNC.pParse->db->mallocFailed ) return; + sqlite3WalkSelect(pWalker, p); + sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols); + } + if( pCopy && pParse->pWith==pCopy ){ + pParse->pWith = pCopy->pOuter; + } + } +} + +/* +** Unmap all tokens in the IdList object passed as the second argument. +*/ +static void unmapColumnIdlistNames( + Parse *pParse, + const IdList *pIdList +){ + if( pIdList ){ + int ii; + for(ii=0; iinId; ii++){ + sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName); + } + } +} + +/* +** Walker callback used by sqlite3RenameExprUnmap(). +*/ +static int renameUnmapSelectCb(Walker *pWalker, Select *p){ + Parse *pParse = pWalker->pParse; + int i; + if( pParse->nErr ) return WRC_Abort; + testcase( p->selFlags & SF_View ); + testcase( p->selFlags & SF_CopyCte ); + if( p->selFlags & (SF_View|SF_CopyCte) ){ + return WRC_Prune; + } + if( ALWAYS(p->pEList) ){ + ExprList *pList = p->pEList; + for(i=0; inExpr; i++){ + if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName); + } + } + } + if( ALWAYS(p->pSrc) ){ /* Every Select as a SrcList, even if it is empty */ + SrcList *pSrc = p->pSrc; + for(i=0; inSrc; i++){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName); + sqlite3WalkExpr(pWalker, pSrc->a[i].pOn); + unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing); + } + } + + renameWalkWith(pWalker, p); + return WRC_Continue; +} + +/* +** Remove all nodes that are part of expression pExpr from the rename list. +*/ +SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ + u8 eMode = pParse->eParseMode; + Walker sWalker; + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = pParse; + sWalker.xExprCallback = renameUnmapExprCb; + sWalker.xSelectCallback = renameUnmapSelectCb; + pParse->eParseMode = PARSE_MODE_UNMAP; + sqlite3WalkExpr(&sWalker, pExpr); + pParse->eParseMode = eMode; +} + +/* +** Remove all nodes that are part of expression-list pEList from the +** rename list. +*/ +SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){ + if( pEList ){ + int i; + Walker sWalker; + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = pParse; + sWalker.xExprCallback = renameUnmapExprCb; + sqlite3WalkExprList(&sWalker, pEList); + for(i=0; inExpr; i++){ + if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName); + } + } + } +} + +/* +** Free the list of RenameToken objects given in the second argument +*/ +static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ + RenameToken *pNext; + RenameToken *p; + for(p=pToken; p; p=pNext){ + pNext = p->pNext; + sqlite3DbFree(db, p); + } +} + +/* +** Search the Parse object passed as the first argument for a RenameToken +** object associated with parse tree element pPtr. If found, return a pointer +** to it. Otherwise, return NULL. +** +** If the second argument passed to this function is not NULL and a matching +** RenameToken object is found, remove it from the Parse object and add it to +** the list maintained by the RenameCtx object. +*/ +static RenameToken *renameTokenFind( + Parse *pParse, + struct RenameCtx *pCtx, + const void *pPtr +){ + RenameToken **pp; + if( NEVER(pPtr==0) ){ + return 0; + } + for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ + if( (*pp)->p==pPtr ){ + RenameToken *pToken = *pp; + if( pCtx ){ + *pp = pToken->pNext; + pToken->pNext = pCtx->pList; + pCtx->pList = pToken; + pCtx->nList++; + } + return pToken; + } + } + return 0; +} + +/* +** This is a Walker select callback. It does nothing. It is only required +** because without a dummy callback, sqlite3WalkExpr() and similar do not +** descend into sub-select statements. +*/ +static int renameColumnSelectCb(Walker *pWalker, Select *p){ + if( p->selFlags & (SF_View|SF_CopyCte) ){ + testcase( p->selFlags & SF_View ); + testcase( p->selFlags & SF_CopyCte ); + return WRC_Prune; + } + renameWalkWith(pWalker, p); + return WRC_Continue; +} + +/* +** This is a Walker expression callback. +** +** For every TK_COLUMN node in the expression tree, search to see +** if the column being references is the column being renamed by an +** ALTER TABLE statement. If it is, then attach its associated +** RenameToken object to the list of RenameToken objects being +** constructed in RenameCtx object at pWalker->u.pRename. +*/ +static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){ + RenameCtx *p = pWalker->u.pRename; + if( pExpr->op==TK_TRIGGER + && pExpr->iColumn==p->iCol + && pWalker->pParse->pTriggerTab==p->pTab + ){ + renameTokenFind(pWalker->pParse, p, (void*)pExpr); + }else if( pExpr->op==TK_COLUMN + && pExpr->iColumn==p->iCol + && ALWAYS(ExprUseYTab(pExpr)) + && p->pTab==pExpr->y.pTab + ){ + renameTokenFind(pWalker->pParse, p, (void*)pExpr); + } + return WRC_Continue; +} + +/* +** The RenameCtx contains a list of tokens that reference a column that +** is being renamed by an ALTER TABLE statement. Return the "last" +** RenameToken in the RenameCtx and remove that RenameToken from the +** RenameContext. "Last" means the last RenameToken encountered when +** the input SQL is parsed from left to right. Repeated calls to this routine +** return all column name tokens in the order that they are encountered +** in the SQL statement. +*/ +static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){ + RenameToken *pBest = pCtx->pList; + RenameToken *pToken; + RenameToken **pp; + + for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){ + if( pToken->t.z>pBest->t.z ) pBest = pToken; + } + for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext); + *pp = pBest->pNext; + + return pBest; +} + +/* +** An error occured while parsing or otherwise processing a database +** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an +** ALTER TABLE RENAME COLUMN program. The error message emitted by the +** sub-routine is currently stored in pParse->zErrMsg. This function +** adds context to the error message and then stores it in pCtx. +*/ +static void renameColumnParseError( + sqlite3_context *pCtx, + const char *zWhen, + sqlite3_value *pType, + sqlite3_value *pObject, + Parse *pParse +){ + const char *zT = (const char*)sqlite3_value_text(pType); + const char *zN = (const char*)sqlite3_value_text(pObject); + char *zErr; + + zErr = sqlite3MPrintf(pParse->db, "error in %s %s%s%s: %s", + zT, zN, (zWhen[0] ? " " : ""), zWhen, + pParse->zErrMsg + ); + sqlite3_result_error(pCtx, zErr, -1); + sqlite3DbFree(pParse->db, zErr); +} + +/* +** For each name in the the expression-list pEList (i.e. each +** pEList->a[i].zName) that matches the string in zOld, extract the +** corresponding rename-token from Parse object pParse and add it +** to the RenameCtx pCtx. +*/ +static void renameColumnElistNames( + Parse *pParse, + RenameCtx *pCtx, + const ExprList *pEList, + const char *zOld +){ + if( pEList ){ + int i; + for(i=0; inExpr; i++){ + const char *zName = pEList->a[i].zEName; + if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) + && ALWAYS(zName!=0) + && 0==sqlite3_stricmp(zName, zOld) + ){ + renameTokenFind(pParse, pCtx, (const void*)zName); + } + } + } +} + +/* +** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName) +** that matches the string in zOld, extract the corresponding rename-token +** from Parse object pParse and add it to the RenameCtx pCtx. +*/ +static void renameColumnIdlistNames( + Parse *pParse, + RenameCtx *pCtx, + const IdList *pIdList, + const char *zOld +){ + if( pIdList ){ + int i; + for(i=0; inId; i++){ + const char *zName = pIdList->a[i].zName; + if( 0==sqlite3_stricmp(zName, zOld) ){ + renameTokenFind(pParse, pCtx, (const void*)zName); + } + } + } +} + + +/* +** Parse the SQL statement zSql using Parse object (*p). The Parse object +** is initialized by this function before it is used. +*/ +static int renameParseSql( + Parse *p, /* Memory to use for Parse object */ + const char *zDb, /* Name of schema SQL belongs to */ + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL to parse */ + int bTemp /* True if SQL is from temp schema */ +){ + int rc; + + sqlite3ParseObjectInit(p, db); + if( zSql==0 ){ + return SQLITE_NOMEM; + } + if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){ + return SQLITE_CORRUPT_BKPT; + } + db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); + p->eParseMode = PARSE_MODE_RENAME; + p->db = db; + p->nQueryLoop = 1; + rc = sqlite3RunParser(p, zSql); + if( db->mallocFailed ) rc = SQLITE_NOMEM; + if( rc==SQLITE_OK + && NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0) + ){ + rc = SQLITE_CORRUPT_BKPT; + } + +#ifdef SQLITE_DEBUG + /* Ensure that all mappings in the Parse.pRename list really do map to + ** a part of the input string. */ + if( rc==SQLITE_OK ){ + int nSql = sqlite3Strlen30(zSql); + RenameToken *pToken; + for(pToken=p->pRename; pToken; pToken=pToken->pNext){ + assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] ); + } + } +#endif + + db->init.iDb = 0; + return rc; +} + +/* +** This function edits SQL statement zSql, replacing each token identified +** by the linked list pRename with the text of zNew. If argument bQuote is +** true, then zNew is always quoted first. If no error occurs, the result +** is loaded into context object pCtx as the result. +** +** Or, if an error occurs (i.e. an OOM condition), an error is left in +** pCtx and an SQLite error code returned. +*/ +static int renameEditSql( + sqlite3_context *pCtx, /* Return result here */ + RenameCtx *pRename, /* Rename context */ + const char *zSql, /* SQL statement to edit */ + const char *zNew, /* New token text */ + int bQuote /* True to always quote token */ +){ + i64 nNew = sqlite3Strlen30(zNew); + i64 nSql = sqlite3Strlen30(zSql); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + int rc = SQLITE_OK; + char *zQuot = 0; + char *zOut; + i64 nQuot = 0; + char *zBuf1 = 0; + char *zBuf2 = 0; + + if( zNew ){ + /* Set zQuot to point to a buffer containing a quoted copy of the + ** identifier zNew. If the corresponding identifier in the original + ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to + ** point to zQuot so that all substitutions are made using the + ** quoted version of the new column name. */ + zQuot = sqlite3MPrintf(db, "\"%w\" ", zNew); + if( zQuot==0 ){ + return SQLITE_NOMEM; + }else{ + nQuot = sqlite3Strlen30(zQuot)-1; + } + + assert( nQuot>=nNew ); + zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); + }else{ + zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3); + if( zOut ){ + zBuf1 = &zOut[nSql*2+1]; + zBuf2 = &zOut[nSql*4+2]; + } + } + + /* At this point pRename->pList contains a list of RenameToken objects + ** corresponding to all tokens in the input SQL that must be replaced + ** with the new column name, or with single-quoted versions of themselves. + ** All that remains is to construct and return the edited SQL string. */ + if( zOut ){ + int nOut = nSql; + memcpy(zOut, zSql, nSql); + while( pRename->pList ){ + int iOff; /* Offset of token to replace in zOut */ + u32 nReplace; + const char *zReplace; + RenameToken *pBest = renameColumnTokenNext(pRename); + + if( zNew ){ + if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){ + nReplace = nNew; + zReplace = zNew; + }else{ + nReplace = nQuot; + zReplace = zQuot; + if( pBest->t.z[pBest->t.n]=='"' ) nReplace++; + } + }else{ + /* Dequote the double-quoted token. Then requote it again, this time + ** using single quotes. If the character immediately following the + ** original token within the input SQL was a single quote ('), then + ** add another space after the new, single-quoted version of the + ** token. This is so that (SELECT "string"'alias') maps to + ** (SELECT 'string' 'alias'), and not (SELECT 'string''alias'). */ + memcpy(zBuf1, pBest->t.z, pBest->t.n); + zBuf1[pBest->t.n] = 0; + sqlite3Dequote(zBuf1); + sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1, + pBest->t.z[pBest->t.n]=='\'' ? " " : "" + ); + zReplace = zBuf2; + nReplace = sqlite3Strlen30(zReplace); + } + + iOff = pBest->t.z - zSql; + if( pBest->t.n!=nReplace ){ + memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], + nOut - (iOff + pBest->t.n) + ); + nOut += nReplace - pBest->t.n; + zOut[nOut] = '\0'; + } + memcpy(&zOut[iOff], zReplace, nReplace); + sqlite3DbFree(db, pBest); + } + + sqlite3_result_text(pCtx, zOut, -1, SQLITE_TRANSIENT); + sqlite3DbFree(db, zOut); + }else{ + rc = SQLITE_NOMEM; + } + + sqlite3_free(zQuot); + return rc; +} + +/* +** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming +** it was read from the schema of database zDb. Return SQLITE_OK if +** successful. Otherwise, return an SQLite error code and leave an error +** message in the Parse object. +*/ +static int renameResolveTrigger(Parse *pParse){ + sqlite3 *db = pParse->db; + Trigger *pNew = pParse->pNewTrigger; + TriggerStep *pStep; + NameContext sNC; + int rc = SQLITE_OK; + + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + assert( pNew->pTabSchema ); + pParse->pTriggerTab = sqlite3FindTable(db, pNew->table, + db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName + ); + pParse->eTriggerOp = pNew->op; + /* ALWAYS() because if the table of the trigger does not exist, the + ** error would have been hit before this point */ + if( ALWAYS(pParse->pTriggerTab) ){ + rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); + } + + /* Resolve symbols in WHEN clause */ + if( rc==SQLITE_OK && pNew->pWhen ){ + rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen); + } + + for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){ + if( pStep->pSelect ){ + sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); + if( pParse->nErr ) rc = pParse->rc; + } + if( rc==SQLITE_OK && pStep->zTarget ){ + SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep); + if( pSrc ){ + int i; + for(i=0; inSrc && rc==SQLITE_OK; i++){ + SrcItem *p = &pSrc->a[i]; + p->iCursor = pParse->nTab++; + if( p->pSelect ){ + sqlite3SelectPrep(pParse, p->pSelect, 0); + sqlite3ExpandSubquery(pParse, p); + assert( i>0 ); + assert( pStep->pFrom->a[i-1].pSelect ); + sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0); + }else{ + p->pTab = sqlite3LocateTableItem(pParse, 0, p); + if( p->pTab==0 ){ + rc = SQLITE_ERROR; + }else{ + p->pTab->nTabRef++; + rc = sqlite3ViewGetColumnNames(pParse, p->pTab); + } + } + } + if( rc==SQLITE_OK && db->mallocFailed ){ + rc = SQLITE_NOMEM; + } + sNC.pSrcList = pSrc; + if( rc==SQLITE_OK && pStep->pWhere ){ + rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere); + } + if( rc==SQLITE_OK ){ + rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList); + } + assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) ); + if( pStep->pUpsert && rc==SQLITE_OK ){ + Upsert *pUpsert = pStep->pUpsert; + pUpsert->pUpsertSrc = pSrc; + sNC.uNC.pUpsert = pUpsert; + sNC.ncFlags = NC_UUpsert; + rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); + if( rc==SQLITE_OK ){ + ExprList *pUpsertSet = pUpsert->pUpsertSet; + rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet); + } + if( rc==SQLITE_OK ){ + rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere); + } + if( rc==SQLITE_OK ){ + rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); + } + sNC.ncFlags = 0; + } + sNC.pSrcList = 0; + sqlite3SrcListDelete(db, pSrc); + }else{ + rc = SQLITE_NOMEM; + } + } + } + return rc; +} + +/* +** Invoke sqlite3WalkExpr() or sqlite3WalkSelect() on all Select or Expr +** objects that are part of the trigger passed as the second argument. +*/ +static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ + TriggerStep *pStep; + + /* Find tokens to edit in WHEN clause */ + sqlite3WalkExpr(pWalker, pTrigger->pWhen); + + /* Find tokens to edit in trigger steps */ + for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ + sqlite3WalkSelect(pWalker, pStep->pSelect); + sqlite3WalkExpr(pWalker, pStep->pWhere); + sqlite3WalkExprList(pWalker, pStep->pExprList); + if( pStep->pUpsert ){ + Upsert *pUpsert = pStep->pUpsert; + sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget); + sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet); + sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); + sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); + } + if( pStep->pFrom ){ + int i; + for(i=0; ipFrom->nSrc; i++){ + sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); + } + } + } +} + +/* +** Free the contents of Parse object (*pParse). Do not free the memory +** occupied by the Parse object itself. +*/ +static void renameParseCleanup(Parse *pParse){ + sqlite3 *db = pParse->db; + Index *pIdx; + if( pParse->pVdbe ){ + sqlite3VdbeFinalize(pParse->pVdbe); + } + sqlite3DeleteTable(db, pParse->pNewTable); + while( (pIdx = pParse->pNewIndex)!=0 ){ + pParse->pNewIndex = pIdx->pNext; + sqlite3FreeIndex(db, pIdx); + } + sqlite3DeleteTrigger(db, pParse->pNewTrigger); + sqlite3DbFree(db, pParse->zErrMsg); + renameTokenFree(db, pParse->pRename); + sqlite3ParseObjectReset(pParse); +} + +/* +** SQL function: +** +** sqlite_rename_column(SQL,TYPE,OBJ,DB,TABLE,COL,NEWNAME,QUOTE,TEMP) +** +** 0. zSql: SQL statement to rewrite +** 1. type: Type of object ("table", "view" etc.) +** 2. object: Name of object +** 3. Database: Database name (e.g. "main") +** 4. Table: Table name +** 5. iCol: Index of column to rename +** 6. zNew: New column name +** 7. bQuote: Non-zero if the new column name should be quoted. +** 8. bTemp: True if zSql comes from temp schema +** +** Do a column rename operation on the CREATE statement given in zSql. +** The iCol-th column (left-most is 0) of table zTable is renamed from zCol +** into zNew. The name should be quoted if bQuote is true. +** +** This function is used internally by the ALTER TABLE RENAME COLUMN command. +** It is only accessible to SQL created using sqlite3NestedParse(). It is +** not reachable from ordinary SQL passed into sqlite3_prepare() unless the +** SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test setting is enabled. +*/ +static void renameColumnFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + RenameCtx sCtx; + const char *zSql = (const char*)sqlite3_value_text(argv[0]); + const char *zDb = (const char*)sqlite3_value_text(argv[3]); + const char *zTable = (const char*)sqlite3_value_text(argv[4]); + int iCol = sqlite3_value_int(argv[5]); + const char *zNew = (const char*)sqlite3_value_text(argv[6]); + int bQuote = sqlite3_value_int(argv[7]); + int bTemp = sqlite3_value_int(argv[8]); + const char *zOld; + int rc; + Parse sParse; + Walker sWalker; + Index *pIdx; + int i; + Table *pTab; +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; +#endif + + UNUSED_PARAMETER(NotUsed); + if( zSql==0 ) return; + if( zTable==0 ) return; + if( zNew==0 ) return; + if( iCol<0 ) return; + sqlite3BtreeEnterAll(db); + pTab = sqlite3FindTable(db, zTable, zDb); + if( pTab==0 || iCol>=pTab->nCol ){ + sqlite3BtreeLeaveAll(db); + return; + } + zOld = pTab->aCol[iCol].zCnName; + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol); + +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = 0; +#endif + rc = renameParseSql(&sParse, zDb, db, zSql, bTemp); + + /* Find tokens that need to be replaced. */ + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = &sParse; + sWalker.xExprCallback = renameColumnExprCb; + sWalker.xSelectCallback = renameColumnSelectCb; + sWalker.u.pRename = &sCtx; + + sCtx.pTab = pTab; + if( rc!=SQLITE_OK ) goto renameColumnFunc_done; + if( sParse.pNewTable ){ + if( IsView(sParse.pNewTable) ){ + Select *pSelect = sParse.pNewTable->u.view.pSelect; + pSelect->selFlags &= ~SF_View; + sParse.rc = SQLITE_OK; + sqlite3SelectPrep(&sParse, pSelect, 0); + rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); + if( rc==SQLITE_OK ){ + sqlite3WalkSelect(&sWalker, pSelect); + } + if( rc!=SQLITE_OK ) goto renameColumnFunc_done; + }else if( IsOrdinaryTable(sParse.pNewTable) ){ + /* A regular table */ + int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName); + FKey *pFKey; + sCtx.pTab = sParse.pNewTable; + if( bFKOnly==0 ){ + if( iColnCol ){ + renameTokenFind( + &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zCnName + ); + } + if( sCtx.iCol<0 ){ + renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey); + } + sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); + for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){ + sqlite3WalkExprList(&sWalker, pIdx->aColExpr); + } + for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){ + sqlite3WalkExprList(&sWalker, pIdx->aColExpr); + } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + for(i=0; inCol; i++){ + Expr *pExpr = sqlite3ColumnExpr(sParse.pNewTable, + &sParse.pNewTable->aCol[i]); + sqlite3WalkExpr(&sWalker, pExpr); + } +#endif + } + + assert( IsOrdinaryTable(sParse.pNewTable) ); + for(pFKey=sParse.pNewTable->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ + for(i=0; inCol; i++){ + if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){ + renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]); + } + if( 0==sqlite3_stricmp(pFKey->zTo, zTable) + && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld) + ){ + renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol); + } + } + } + } + }else if( sParse.pNewIndex ){ + sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); + sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); + }else{ + /* A trigger */ + TriggerStep *pStep; + rc = renameResolveTrigger(&sParse); + if( rc!=SQLITE_OK ) goto renameColumnFunc_done; + + for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){ + if( pStep->zTarget ){ + Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb); + if( pTarget==pTab ){ + if( pStep->pUpsert ){ + ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet; + renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld); + } + renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld); + renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld); + } + } + } + + + /* Find tokens to edit in UPDATE OF clause */ + if( sParse.pTriggerTab==pTab ){ + renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld); + } + + /* Find tokens to edit in various expressions and selects */ + renameWalkTrigger(&sWalker, sParse.pNewTrigger); + } + + assert( rc==SQLITE_OK ); + rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); + +renameColumnFunc_done: + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_ERROR && sqlite3WritableSchema(db) ){ + sqlite3_result_value(context, argv[0]); + }else if( sParse.zErrMsg ){ + renameColumnParseError(context, "", argv[1], argv[2], &sParse); + }else{ + sqlite3_result_error_code(context, rc); + } + } + + renameParseCleanup(&sParse); + renameTokenFree(db, sCtx.pList); +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + sqlite3BtreeLeaveAll(db); +} + +/* +** Walker expression callback used by "RENAME TABLE". +*/ +static int renameTableExprCb(Walker *pWalker, Expr *pExpr){ + RenameCtx *p = pWalker->u.pRename; + if( pExpr->op==TK_COLUMN + && ALWAYS(ExprUseYTab(pExpr)) + && p->pTab==pExpr->y.pTab + ){ + renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab); + } + return WRC_Continue; +} + +/* +** Walker select callback used by "RENAME TABLE". +*/ +static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ + int i; + RenameCtx *p = pWalker->u.pRename; + SrcList *pSrc = pSelect->pSrc; + if( pSelect->selFlags & (SF_View|SF_CopyCte) ){ + testcase( pSelect->selFlags & SF_View ); + testcase( pSelect->selFlags & SF_CopyCte ); + return WRC_Prune; + } + if( NEVER(pSrc==0) ){ + assert( pWalker->pParse->db->mallocFailed ); + return WRC_Abort; + } + for(i=0; inSrc; i++){ + SrcItem *pItem = &pSrc->a[i]; + if( pItem->pTab==p->pTab ){ + renameTokenFind(pWalker->pParse, p, pItem->zName); + } + } + renameWalkWith(pWalker, pSelect); + + return WRC_Continue; +} + + +/* +** This C function implements an SQL user function that is used by SQL code +** generated by the ALTER TABLE ... RENAME command to modify the definition +** of any foreign key constraints that use the table being renamed as the +** parent table. It is passed three arguments: +** +** 0: The database containing the table being renamed. +** 1. type: Type of object ("table", "view" etc.) +** 2. object: Name of object +** 3: The complete text of the schema statement being modified, +** 4: The old name of the table being renamed, and +** 5: The new name of the table being renamed. +** 6: True if the schema statement comes from the temp db. +** +** It returns the new schema statement. For example: +** +** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0) +** -> 'CREATE TABLE t1(a REFERENCES t3)' +*/ +static void renameTableFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + const char *zDb = (const char*)sqlite3_value_text(argv[0]); + const char *zInput = (const char*)sqlite3_value_text(argv[3]); + const char *zOld = (const char*)sqlite3_value_text(argv[4]); + const char *zNew = (const char*)sqlite3_value_text(argv[5]); + int bTemp = sqlite3_value_int(argv[6]); + UNUSED_PARAMETER(NotUsed); + + if( zInput && zOld && zNew ){ + Parse sParse; + int rc; + int bQuote = 1; + RenameCtx sCtx; + Walker sWalker; + +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; + db->xAuth = 0; +#endif + + sqlite3BtreeEnterAll(db); + + memset(&sCtx, 0, sizeof(RenameCtx)); + sCtx.pTab = sqlite3FindTable(db, zOld, zDb); + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = &sParse; + sWalker.xExprCallback = renameTableExprCb; + sWalker.xSelectCallback = renameTableSelectCb; + sWalker.u.pRename = &sCtx; + + rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); + + if( rc==SQLITE_OK ){ + int isLegacy = (db->flags & SQLITE_LegacyAlter); + if( sParse.pNewTable ){ + Table *pTab = sParse.pNewTable; + + if( IsView(pTab) ){ + if( isLegacy==0 ){ + Select *pSelect = pTab->u.view.pSelect; + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = &sParse; + + assert( pSelect->selFlags & SF_View ); + pSelect->selFlags &= ~SF_View; + sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC); + if( sParse.nErr ){ + rc = sParse.rc; + }else{ + sqlite3WalkSelect(&sWalker, pTab->u.view.pSelect); + } + } + }else{ + /* Modify any FK definitions to point to the new table. */ +#ifndef SQLITE_OMIT_FOREIGN_KEY + if( (isLegacy==0 || (db->flags & SQLITE_ForeignKeys)) + && !IsVirtual(pTab) + ){ + FKey *pFKey; + assert( IsOrdinaryTable(pTab) ); + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ + if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ + renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo); + } + } + } +#endif + + /* If this is the table being altered, fix any table refs in CHECK + ** expressions. Also update the name that appears right after the + ** "CREATE [VIRTUAL] TABLE" bit. */ + if( sqlite3_stricmp(zOld, pTab->zName)==0 ){ + sCtx.pTab = pTab; + if( isLegacy==0 ){ + sqlite3WalkExprList(&sWalker, pTab->pCheck); + } + renameTokenFind(&sParse, &sCtx, pTab->zName); + } + } + } + + else if( sParse.pNewIndex ){ + renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName); + if( isLegacy==0 ){ + sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); + } + } + +#ifndef SQLITE_OMIT_TRIGGER + else{ + Trigger *pTrigger = sParse.pNewTrigger; + TriggerStep *pStep; + if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) + && sCtx.pTab->pSchema==pTrigger->pTabSchema + ){ + renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table); + } + + if( isLegacy==0 ){ + rc = renameResolveTrigger(&sParse); + if( rc==SQLITE_OK ){ + renameWalkTrigger(&sWalker, pTrigger); + for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ + if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ + renameTokenFind(&sParse, &sCtx, pStep->zTarget); + } + } + } + } + } +#endif + } + + if( rc==SQLITE_OK ){ + rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote); + } + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_ERROR && sqlite3WritableSchema(db) ){ + sqlite3_result_value(context, argv[3]); + }else if( sParse.zErrMsg ){ + renameColumnParseError(context, "", argv[1], argv[2], &sParse); + }else{ + sqlite3_result_error_code(context, rc); + } + } + + renameParseCleanup(&sParse); + renameTokenFree(db, sCtx.pList); + sqlite3BtreeLeaveAll(db); +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + } + + return; +} + +static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){ + renameTokenFind(pWalker->pParse, pWalker->u.pRename, (const void*)pExpr); + } + return WRC_Continue; +} + +/* SQL function: sqlite_rename_quotefix(DB,SQL) +** +** Rewrite the DDL statement "SQL" so that any string literals that use +** double-quotes use single quotes instead. +** +** Two arguments must be passed: +** +** 0: Database name ("main", "temp" etc.). +** 1: SQL statement to edit. +** +** The returned value is the modified SQL statement. For example, given +** the database schema: +** +** CREATE TABLE t1(a, b, c); +** +** SELECT sqlite_rename_quotefix('main', +** 'CREATE VIEW v1 AS SELECT "a", "string" FROM t1' +** ); +** +** returns the string: +** +** CREATE VIEW v1 AS SELECT "a", 'string' FROM t1 +** +** If there is a error in the input SQL, then raise an error, except +** if PRAGMA writable_schema=ON, then just return the input string +** unmodified following an error. +*/ +static void renameQuotefixFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + char const *zDb = (const char*)sqlite3_value_text(argv[0]); + char const *zInput = (const char*)sqlite3_value_text(argv[1]); + +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; + db->xAuth = 0; +#endif + + sqlite3BtreeEnterAll(db); + + UNUSED_PARAMETER(NotUsed); + if( zDb && zInput ){ + int rc; + Parse sParse; + rc = renameParseSql(&sParse, zDb, db, zInput, 0); + + if( rc==SQLITE_OK ){ + RenameCtx sCtx; + Walker sWalker; + + /* Walker to find tokens that need to be replaced. */ + memset(&sCtx, 0, sizeof(RenameCtx)); + memset(&sWalker, 0, sizeof(Walker)); + sWalker.pParse = &sParse; + sWalker.xExprCallback = renameQuotefixExprCb; + sWalker.xSelectCallback = renameColumnSelectCb; + sWalker.u.pRename = &sCtx; + + if( sParse.pNewTable ){ + if( IsView(sParse.pNewTable) ){ + Select *pSelect = sParse.pNewTable->u.view.pSelect; + pSelect->selFlags &= ~SF_View; + sParse.rc = SQLITE_OK; + sqlite3SelectPrep(&sParse, pSelect, 0); + rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); + if( rc==SQLITE_OK ){ + sqlite3WalkSelect(&sWalker, pSelect); + } + }else{ + int i; + sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + for(i=0; inCol; i++){ + sqlite3WalkExpr(&sWalker, + sqlite3ColumnExpr(sParse.pNewTable, + &sParse.pNewTable->aCol[i])); + } +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + } + }else if( sParse.pNewIndex ){ + sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); + sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); + }else{ +#ifndef SQLITE_OMIT_TRIGGER + rc = renameResolveTrigger(&sParse); + if( rc==SQLITE_OK ){ + renameWalkTrigger(&sWalker, sParse.pNewTrigger); + } +#endif /* SQLITE_OMIT_TRIGGER */ + } + + if( rc==SQLITE_OK ){ + rc = renameEditSql(context, &sCtx, zInput, 0, 0); + } + renameTokenFree(db, sCtx.pList); + } + if( rc!=SQLITE_OK ){ + if( sqlite3WritableSchema(db) && rc==SQLITE_ERROR ){ + sqlite3_result_value(context, argv[1]); + }else{ + sqlite3_result_error_code(context, rc); + } + } + renameParseCleanup(&sParse); + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + + sqlite3BtreeLeaveAll(db); +} + +/* Function: sqlite_rename_test(DB,SQL,TYPE,NAME,ISTEMP,WHEN,DQS) +** +** An SQL user function that checks that there are no parse or symbol +** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement. +** After an ALTER TABLE .. RENAME operation is performed and the schema +** reloaded, this function is called on each SQL statement in the schema +** to ensure that it is still usable. +** +** 0: Database name ("main", "temp" etc.). +** 1: SQL statement. +** 2: Object type ("view", "table", "trigger" or "index"). +** 3: Object name. +** 4: True if object is from temp schema. +** 5: "when" part of error message. +** 6: True to disable the DQS quirk when parsing SQL. +** +** The return value is computed as follows: +** +** A. If an error is seen and not in PRAGMA writable_schema=ON mode, +** then raise the error. +** B. Else if a trigger is created and the the table that the trigger is +** attached to is in database zDb, then return 1. +** C. Otherwise return NULL. +*/ +static void renameTableTest( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + char const *zDb = (const char*)sqlite3_value_text(argv[0]); + char const *zInput = (const char*)sqlite3_value_text(argv[1]); + int bTemp = sqlite3_value_int(argv[4]); + int isLegacy = (db->flags & SQLITE_LegacyAlter); + char const *zWhen = (const char*)sqlite3_value_text(argv[5]); + int bNoDQS = sqlite3_value_int(argv[6]); + +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; + db->xAuth = 0; +#endif + + UNUSED_PARAMETER(NotUsed); + + if( zDb && zInput ){ + int rc; + Parse sParse; + int flags = db->flags; + if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL); + rc = renameParseSql(&sParse, zDb, db, zInput, bTemp); + db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL)); + if( rc==SQLITE_OK ){ + if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){ + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = &sParse; + sqlite3SelectPrep(&sParse, sParse.pNewTable->u.view.pSelect, &sNC); + if( sParse.nErr ) rc = sParse.rc; + } + + else if( sParse.pNewTrigger ){ + if( isLegacy==0 ){ + rc = renameResolveTrigger(&sParse); + } + if( rc==SQLITE_OK ){ + int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema); + int i2 = sqlite3FindDbName(db, zDb); + if( i1==i2 ){ + /* Handle output case B */ + sqlite3_result_int(context, 1); + } + } + } + } + + if( rc!=SQLITE_OK && zWhen && !sqlite3WritableSchema(db) ){ + /* Output case A */ + renameColumnParseError(context, zWhen, argv[2], argv[3],&sParse); + } + renameParseCleanup(&sParse); + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif +} + +/* +** The implementation of internal UDF sqlite_drop_column(). +** +** Arguments: +** +** argv[0]: An integer - the index of the schema containing the table +** argv[1]: CREATE TABLE statement to modify. +** argv[2]: An integer - the index of the column to remove. +** +** The value returned is a string containing the CREATE TABLE statement +** with column argv[2] removed. +*/ +static void dropColumnFunc( + sqlite3_context *context, + int NotUsed, + sqlite3_value **argv +){ + sqlite3 *db = sqlite3_context_db_handle(context); + int iSchema = sqlite3_value_int(argv[0]); + const char *zSql = (const char*)sqlite3_value_text(argv[1]); + int iCol = sqlite3_value_int(argv[2]); + const char *zDb = db->aDb[iSchema].zDbSName; + int rc; + Parse sParse; + RenameToken *pCol; + Table *pTab; + const char *zEnd; + char *zNew = 0; + +#ifndef SQLITE_OMIT_AUTHORIZATION + sqlite3_xauth xAuth = db->xAuth; + db->xAuth = 0; +#endif + + UNUSED_PARAMETER(NotUsed); + rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1); + if( rc!=SQLITE_OK ) goto drop_column_done; + pTab = sParse.pNewTable; + if( pTab==0 || pTab->nCol==1 || iCol>=pTab->nCol ){ + /* This can happen if the sqlite_schema table is corrupt */ + rc = SQLITE_CORRUPT_BKPT; + goto drop_column_done; + } + + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); + if( iColnCol-1 ){ + RenameToken *pEnd; + pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName); + zEnd = (const char*)pEnd->t.z; + }else{ + assert( IsOrdinaryTable(pTab) ); + zEnd = (const char*)&zSql[pTab->u.tab.addColOffset]; + while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--; + } + + zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd); + sqlite3_result_text(context, zNew, -1, SQLITE_TRANSIENT); + sqlite3_free(zNew); + +drop_column_done: + renameParseCleanup(&sParse); +#ifndef SQLITE_OMIT_AUTHORIZATION + db->xAuth = xAuth; +#endif + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(context, rc); + } +} + +/* +** This function is called by the parser upon parsing an +** +** ALTER TABLE pSrc DROP COLUMN pName +** +** statement. Argument pSrc contains the possibly qualified name of the +** table being edited, and token pName the name of the column to drop. +*/ +SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){ + sqlite3 *db = pParse->db; /* Database handle */ + Table *pTab; /* Table to modify */ + int iDb; /* Index of db containing pTab in aDb[] */ + const char *zDb; /* Database containing pTab ("main" etc.) */ + char *zCol = 0; /* Name of column to drop */ + int iCol; /* Index of column zCol in pTab->aCol[] */ + + /* Look up the table being altered. */ + assert( pParse->pNewTable==0 ); + assert( sqlite3BtreeHoldsAllMutexes(db) ); + if( NEVER(db->mallocFailed) ) goto exit_drop_column; + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); + if( !pTab ) goto exit_drop_column; + + /* Make sure this is not an attempt to ALTER a view, virtual table or + ** system table. */ + if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column; + if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column; + + /* Find the index of the column being dropped. */ + zCol = sqlite3NameFromToken(db, pName); + if( zCol==0 ){ + assert( db->mallocFailed ); + goto exit_drop_column; + } + iCol = sqlite3ColumnIndex(pTab, zCol); + if( iCol<0 ){ + sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pName); + goto exit_drop_column; + } + + /* Do not allow the user to drop a PRIMARY KEY column or a column + ** constrained by a UNIQUE constraint. */ + if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){ + sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"", + (pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE", + zCol + ); + goto exit_drop_column; + } + + /* Do not allow the number of columns to go to zero */ + if( pTab->nCol<=1 ){ + sqlite3ErrorMsg(pParse, "cannot drop column \"%s\": no other columns exist",zCol); + goto exit_drop_column; + } + + /* Edit the sqlite_schema table */ + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDb>=0 ); + zDb = db->aDb[iDb].zDbSName; +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Invoke the authorization callback. */ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){ + goto exit_drop_column; + } +#endif + renameTestSchema(pParse, zDb, iDb==1, "", 0); + renameFixQuotes(pParse, zDb, iDb==1); + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_drop_column(%d, sql, %d) " + "WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)" + , zDb, iDb, iCol, pTab->zName + ); + + /* Drop and reload the database schema. */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop); + renameTestSchema(pParse, zDb, iDb==1, "after drop column", 1); + + /* Edit rows of table on disk */ + if( pParse->nErr==0 && (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){ + int i; + int addr; + int reg; + int regRec; + Index *pPk = 0; + int nField = 0; /* Number of non-virtual columns after drop */ + int iCur; + Vdbe *v = sqlite3GetVdbe(pParse); + iCur = pParse->nTab++; + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); + addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); + reg = ++pParse->nMem; + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg); + pParse->nMem += pTab->nCol; + }else{ + pPk = sqlite3PrimaryKeyIndex(pTab); + pParse->nMem += pPk->nColumn; + for(i=0; inKeyCol; i++){ + sqlite3VdbeAddOp3(v, OP_Column, iCur, i, reg+i+1); + } + nField = pPk->nKeyCol; + } + regRec = ++pParse->nMem; + for(i=0; inCol; i++){ + if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ + int regOut; + if( pPk ){ + int iPos = sqlite3TableColumnToIndex(pPk, i); + int iColPos = sqlite3TableColumnToIndex(pPk, iCol); + if( iPosnKeyCol ) continue; + regOut = reg+1+iPos-(iPos>iColPos); + }else{ + regOut = reg+1+nField; + } + if( i==pTab->iPKey ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regOut); + }else{ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut); + } + nField++; + } + } + if( nField==0 ){ + /* dbsqlfuzz 5f09e7bcc78b4954d06bf9f2400d7715f48d1fef */ + pParse->nMem++; + sqlite3VdbeAddOp2(v, OP_Null, 0, reg+1); + nField = 1; + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec); + if( pPk ){ + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol); + }else{ + sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg); + } + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); + + sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addr); + } + +exit_drop_column: + sqlite3DbFree(db, zCol); + sqlite3SrcListDelete(db, pSrc); +} + +/* +** Register built-in functions used to help implement ALTER TABLE +*/ +SQLITE_PRIVATE void sqlite3AlterFunctions(void){ + static FuncDef aAlterTableFuncs[] = { + INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc), + INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc), + INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest), + INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc), + INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc), + }; + sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); +} #endif /* SQLITE_ALTER_TABLE */ /************** End of alter.c ***********************************************/ @@ -96436,13 +111118,13 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ ** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled ** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated. ** The sqlite_stat2 table is superseded by sqlite_stat3, which is only -** created and used by SQLite versions 3.7.9 and later and with +** created and used by SQLite versions 3.7.9 through 3.29.0 when ** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3 -** is a superset of sqlite_stat2. The sqlite_stat4 is an enhanced -** version of sqlite_stat3 and is only available when compiled with -** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.1 and later. It is -** not possible to enable both STAT3 and STAT4 at the same time. If they -** are both enabled, then STAT4 takes precedence. +** is a superset of sqlite_stat2 and is also now deprecated. The +** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only +** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite +** versions 3.8.1 and later. STAT4 is the only variant that is still +** supported. ** ** For most applications, sqlite_stat1 provides all the statistics required ** for the query planner to make good choices. @@ -96458,7 +111140,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ ** integer is the average number of rows in the index that have the same ** value in the first column of the index. The third integer is the average ** number of rows in the index that have the same value for the first two -** columns. The N-th integer (for N>1) is the average number of rows in +** columns. The N-th integer (for N>1) is the average number of rows in ** the index which have the same value for the first N-1 columns. For ** a K-column index, there will be K+1 integers in the stat column. If ** the index is unique, then the last integer will be 1. @@ -96468,7 +111150,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ ** must be separated from the last integer by a single space. If the ** "unordered" keyword is present, then the query planner assumes that ** the index is unordered and will not use the index for a range query. -** +** ** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat ** column contains a single integer which is the (estimated) number of ** rows in the table identified by sqlite_stat1.tbl. @@ -96526,9 +111208,9 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ ** number of entries that are strictly less than the sample. The first ** integer in nLt contains the number of entries in the index where the ** left-most column is less than the left-most column of the sample. -** The K-th integer in the nLt entry is the number of index entries +** The K-th integer in the nLt entry is the number of index entries ** where the first K columns are less than the first K columns of the -** sample. The nDLt column is like nLt except that it contains the +** sample. The nDLt column is like nLt except that it contains the ** number of distinct entries in the index that are less than the ** sample. ** @@ -96553,17 +111235,11 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ #if defined(SQLITE_ENABLE_STAT4) # define IsStat4 1 -# define IsStat3 0 -#elif defined(SQLITE_ENABLE_STAT3) -# define IsStat4 0 -# define IsStat3 1 #else # define IsStat4 0 -# define IsStat3 0 # undef SQLITE_STAT4_SAMPLES # define SQLITE_STAT4_SAMPLES 1 #endif -#define IsStat34 (IsStat3+IsStat4) /* 1 for STAT3 or STAT4. 0 otherwise */ /* ** This routine generates code that opens the sqlite_statN tables. @@ -96592,21 +111268,22 @@ static void openStatTable( { "sqlite_stat1", "tbl,idx,stat" }, #if defined(SQLITE_ENABLE_STAT4) { "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" }, - { "sqlite_stat3", 0 }, -#elif defined(SQLITE_ENABLE_STAT3) - { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" }, - { "sqlite_stat4", 0 }, #else - { "sqlite_stat3", 0 }, { "sqlite_stat4", 0 }, #endif + { "sqlite_stat3", 0 }, }; int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); - int aRoot[ArraySize(aTable)]; + u32 aRoot[ArraySize(aTable)]; u8 aCreateTbl[ArraySize(aTable)]; +#ifdef SQLITE_ENABLE_STAT4 + const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1; +#else + const int nToOpen = 1; +#endif if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); @@ -96619,41 +111296,45 @@ static void openStatTable( for(i=0; izDbSName))==0 ){ - if( aTable[i].zCols ){ - /* The sqlite_statN table does not exist. Create it. Note that a - ** side-effect of the CREATE TABLE statement is to leave the rootpage - ** of the new table in register pParse->regRoot. This is important + if( iregRoot. This is important ** because the OpenWrite opcode below will be needing it. */ sqlite3NestedParse(pParse, "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols ); - aRoot[i] = pParse->regRoot; + aRoot[i] = (u32)pParse->regRoot; aCreateTbl[i] = OPFLAG_P2ISREG; } }else{ - /* The table already exists. If zWhere is not NULL, delete all entries + /* The table already exists. If zWhere is not NULL, delete all entries ** associated with the table zWhere. If zWhere is NULL, delete the ** entire contents of the table. */ aRoot[i] = pStat->tnum; - aCreateTbl[i] = 0; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", pDb->zDbSName, zTab, zWhereType, zWhere ); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + }else if( db->xPreUpdateCallback ){ + sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab); +#endif }else{ /* The sqlite_stat[134] table already exists. Delete all rows. */ - sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); + sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb); } } } /* Open the sqlite_stat[134] tables for writing. */ - for(i=0; aTable[i].zCols; i++){ + for(i=0; inRowid ){ sqlite3DbFree(db, p->u.aRowid); @@ -96718,8 +111405,8 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){ /* Initialize the BLOB value of a ROWID */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 -static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){ +#ifdef SQLITE_ENABLE_STAT4 +static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){ assert( db!=0 ); if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); p->u.aRowid = sqlite3DbMallocRawNN(db, n); @@ -96734,8 +111421,8 @@ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){ /* Initialize the INTEGER value of a ROWID. */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 -static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){ +#ifdef SQLITE_ENABLE_STAT4 +static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){ assert( db!=0 ); if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid); p->nRowid = 0; @@ -96747,8 +111434,8 @@ static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){ /* ** Copy the contents of object (*pFrom) into (*pTo). */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 -static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){ +#ifdef SQLITE_ENABLE_STAT4 +static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){ pTo->isPSample = pFrom->isPSample; pTo->iCol = pFrom->iCol; pTo->iHash = pFrom->iHash; @@ -96764,40 +111451,41 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){ #endif /* -** Reclaim all memory of a Stat4Accum structure. +** Reclaim all memory of a StatAccum structure. */ -static void stat4Destructor(void *pOld){ - Stat4Accum *p = (Stat4Accum*)pOld; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - int i; - for(i=0; inCol; i++) sampleClear(p->db, p->aBest+i); - for(i=0; imxSample; i++) sampleClear(p->db, p->a+i); - sampleClear(p->db, &p->current); +static void statAccumDestructor(void *pOld){ + StatAccum *p = (StatAccum*)pOld; +#ifdef SQLITE_ENABLE_STAT4 + if( p->mxSample ){ + int i; + for(i=0; inCol; i++) sampleClear(p->db, p->aBest+i); + for(i=0; imxSample; i++) sampleClear(p->db, p->a+i); + sampleClear(p->db, &p->current); + } #endif sqlite3DbFree(p->db, p); } /* -** Implementation of the stat_init(N,K,C) SQL function. The three parameters +** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters ** are: ** N: The number of columns in the index including the rowid/pk (note 1) ** K: The number of columns in the index excluding the rowid/pk. -** C: The number of rows in the index (note 2) +** C: Estimated number of rows in the index +** L: A limit on the number of rows to scan, or 0 for no-limit ** ** Note 1: In the special case of the covering index that implements a ** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the ** total number of columns in the table. ** -** Note 2: C is only used for STAT3 and STAT4. -** ** For indexes on ordinary rowid tables, N==K+1. But for indexes on ** WITHOUT ROWID tables, N=K+P where P is the number of columns in the ** PRIMARY KEY of the table. The covering index that implements the ** original WITHOUT ROWID table as N==K as a special case. ** -** This routine allocates the Stat4Accum object in heap memory. The return -** value is a pointer to the Stat4Accum object. The datatype of the -** return value is BLOB, but it is really just a pointer to the Stat4Accum +** This routine allocates the StatAccum object in heap memory. The return +** value is a pointer to the StatAccum object. The datatype of the +** return value is BLOB, but it is really just a pointer to the StatAccum ** object. */ static void statInit( @@ -96805,14 +111493,15 @@ static void statInit( int argc, sqlite3_value **argv ){ - Stat4Accum *p; + StatAccum *p; int nCol; /* Number of columns in index being sampled */ int nKeyCol; /* Number of key columns */ int nColUp; /* nCol rounded up for alignment */ int n; /* Bytes of space to allocate */ - sqlite3 *db; /* Database connection */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - int mxSample = SQLITE_STAT4_SAMPLES; + sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */ +#ifdef SQLITE_ENABLE_STAT4 + /* Maximum number of samples. 0 if STAT4 data is not collected */ + int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0; #endif /* Decode the three function arguments */ @@ -96824,17 +111513,17 @@ static void statInit( assert( nKeyCol<=nCol ); assert( nKeyCol>0 ); - /* Allocate the space required for the Stat4Accum object */ - n = sizeof(*p) - + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */ - + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */ - + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */ - + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample) + /* Allocate the space required for the StatAccum object */ + n = sizeof(*p) + + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */ + + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */ +#ifdef SQLITE_ENABLE_STAT4 + if( mxSample ){ + n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */ + + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */ + + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample); + } #endif - ; - db = sqlite3_context_db_handle(context); p = sqlite3DbMallocZero(db, n); if( p==0 ){ sqlite3_result_error_nomem(context); @@ -96842,25 +111531,28 @@ static void statInit( } p->db = db; + p->nEst = sqlite3_value_int64(argv[2]); p->nRow = 0; + p->nLimit = sqlite3_value_int64(argv[3]); p->nCol = nCol; p->nKeyCol = nKeyCol; + p->nSkipAhead = 0; p->current.anDLt = (tRowcnt*)&p[1]; p->current.anEq = &p->current.anDLt[nColUp]; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - { +#ifdef SQLITE_ENABLE_STAT4 + p->mxSample = p->nLimit==0 ? mxSample : 0; + if( mxSample ){ u8 *pSpace; /* Allocated space not yet assigned */ int i; /* Used to iterate through p->aSample[] */ p->iGet = -1; - p->mxSample = mxSample; - p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1); + p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1); p->current.anLt = &p->current.anEq[nColUp]; p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]); - - /* Set up the Stat4Accum.a[] and aBest[] arrays */ - p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; + + /* Set up the StatAccum.a[] and aBest[] arrays */ + p->a = (struct StatSample*)&p->current.anLt[nColUp]; p->aBest = &p->a[mxSample]; pSpace = (u8*)(&p->a[mxSample+nCol]); for(i=0; i<(mxSample+nCol); i++){ @@ -96869,7 +111561,7 @@ static void statInit( p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); } assert( (pSpace - (u8*)p)==n ); - + for(i=0; iaBest[i].iCol = i; } @@ -96880,35 +111572,36 @@ static void statInit( ** only the pointer (the 2nd parameter) matters. The size of the object ** (given by the 3rd parameter) is never used and can be any positive ** value. */ - sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor); + sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor); } static const FuncDef statInitFuncdef = { - 2+IsStat34, /* nArg */ + 4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statInit, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "stat_init", /* zName */ {0} }; #ifdef SQLITE_ENABLE_STAT4 /* -** pNew and pOld are both candidate non-periodic samples selected for -** the same column (pNew->iCol==pOld->iCol). Ignoring this column and +** pNew and pOld are both candidate non-periodic samples selected for +** the same column (pNew->iCol==pOld->iCol). Ignoring this column and ** considering only any trailing columns and the sample hash value, this ** function returns true if sample pNew is to be preferred over pOld. ** In other words, if we assume that the cardinalities of the selected ** column for pNew and pOld are equal, is pNew to be preferred over pOld. ** ** This function assumes that for each argument sample, the contents of -** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. +** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. */ static int sampleIsBetterPost( - Stat4Accum *pAccum, - Stat4Sample *pNew, - Stat4Sample *pOld + StatAccum *pAccum, + StatSample *pNew, + StatSample *pOld ){ int nCol = pAccum->nCol; int i; @@ -96922,17 +111615,17 @@ static int sampleIsBetterPost( } #endif -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 /* ** Return true if pNew is to be preferred over pOld. ** ** This function assumes that for each argument sample, the contents of -** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. +** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. */ static int sampleIsBetter( - Stat4Accum *pAccum, - Stat4Sample *pNew, - Stat4Sample *pOld + StatAccum *pAccum, + StatSample *pNew, + StatSample *pOld ){ tRowcnt nEqNew = pNew->anEq[pNew->iCol]; tRowcnt nEqOld = pOld->anEq[pOld->iCol]; @@ -96941,39 +111634,41 @@ static int sampleIsBetter( assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) ); if( (nEqNew>nEqOld) ) return 1; -#ifdef SQLITE_ENABLE_STAT4 if( nEqNew==nEqOld ){ if( pNew->iColiCol ) return 1; return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld)); } return 0; -#else - return (nEqNew==nEqOld && pNew->iHash>pOld->iHash); -#endif } /* ** Copy the contents of sample *pNew into the p->a[] array. If necessary, ** remove the least desirable sample from p->a[] to make room. */ -static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ - Stat4Sample *pSample = 0; +static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){ + StatSample *pSample = 0; int i; assert( IsStat4 || nEqZero==0 ); -#ifdef SQLITE_ENABLE_STAT4 + /* StatAccum.nMaxEqZero is set to the maximum number of leading 0 + ** values in the anEq[] array of any sample in StatAccum.a[]. In + ** other words, if nMaxEqZero is n, then it is guaranteed that there + ** are no samples with StatSample.anEq[m]==0 for (m>=n). */ + if( nEqZero>p->nMaxEqZero ){ + p->nMaxEqZero = nEqZero; + } if( pNew->isPSample==0 ){ - Stat4Sample *pUpgrade = 0; + StatSample *pUpgrade = 0; assert( pNew->anEq[pNew->iCol]>0 ); - /* This sample is being added because the prefix that ends in column + /* This sample is being added because the prefix that ends in column ** iCol occurs many times in the table. However, if we have already ** added a sample that shares this prefix, there is no need to add ** this one. Instead, upgrade the priority of the highest priority ** existing sample that shares this prefix. */ for(i=p->nSample-1; i>=0; i--){ - Stat4Sample *pOld = &p->a[i]; + StatSample *pOld = &p->a[i]; if( pOld->anEq[pNew->iCol]==0 ){ if( pOld->isPSample ) return; assert( pOld->iCol>pNew->iCol ); @@ -96989,11 +111684,10 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ goto find_new_min; } } -#endif /* If necessary, remove sample iMin to make room for the new sample. */ if( p->nSample>=p->mxSample ){ - Stat4Sample *pMin = &p->a[p->iMin]; + StatSample *pMin = &p->a[p->iMin]; tRowcnt *anEq = pMin->anEq; tRowcnt *anLt = pMin->anLt; tRowcnt *anDLt = pMin->anDLt; @@ -97010,10 +111704,8 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ /* The "rows less-than" for the rowid column must be greater than that ** for the last sample in the p->a[] array. Otherwise, the samples would ** be out of order. */ -#ifdef SQLITE_ENABLE_STAT4 - assert( p->nSample==0 + assert( p->nSample==0 || pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] ); -#endif /* Insert the new sample */ pSample = &p->a[p->nSample]; @@ -97023,9 +111715,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ /* Zero the first nEqZero entries in the anEq[] array. */ memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero); -#ifdef SQLITE_ENABLE_STAT4 - find_new_min: -#endif +find_new_min: if( p->nSample>=p->mxSample ){ int iMin = -1; for(i=0; imxSample; i++){ @@ -97038,79 +111728,66 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ p->iMin = iMin; } } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ +#ifdef SQLITE_ENABLE_STAT4 /* ** Field iChng of the index being scanned has changed. So at this point ** p->current contains a sample that reflects the previous row of the ** index. The value of anEq[iChng] and subsequent anEq[] elements are ** correct at this point. */ -static void samplePushPrevious(Stat4Accum *p, int iChng){ -#ifdef SQLITE_ENABLE_STAT4 +static void samplePushPrevious(StatAccum *p, int iChng){ int i; /* Check if any samples from the aBest[] array should be pushed ** into IndexSample.a[] at this point. */ for(i=(p->nCol-2); i>=iChng; i--){ - Stat4Sample *pBest = &p->aBest[i]; + StatSample *pBest = &p->aBest[i]; pBest->anEq[i] = p->current.anEq[i]; if( p->nSamplemxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){ sampleInsert(p, pBest, i); } } - /* Update the anEq[] fields of any samples already collected. */ + /* Check that no sample contains an anEq[] entry with an index of + ** p->nMaxEqZero or greater set to zero. */ for(i=p->nSample-1; i>=0; i--){ int j; - for(j=iChng; jnCol; j++){ - if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; - } + for(j=p->nMaxEqZero; jnCol; j++) assert( p->a[i].anEq[j]>0 ); } -#endif - -#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4) - if( iChng==0 ){ - tRowcnt nLt = p->current.anLt[0]; - tRowcnt nEq = p->current.anEq[0]; - - /* Check if this is to be a periodic sample. If so, add it. */ - if( (nLt/p->nPSample)!=(nLt+nEq)/p->nPSample ){ - p->current.isPSample = 1; - sampleInsert(p, &p->current, 0); - p->current.isPSample = 0; - }else - /* Or if it is a non-periodic sample. Add it in this case too. */ - if( p->nSamplemxSample - || sampleIsBetter(p, &p->current, &p->a[p->iMin]) - ){ - sampleInsert(p, &p->current, 0); + /* Update the anEq[] fields of any samples already collected. */ + if( iChngnMaxEqZero ){ + for(i=p->nSample-1; i>=0; i--){ + int j; + for(j=iChng; jnCol; j++){ + if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j]; + } } + p->nMaxEqZero = iChng; } -#endif - -#ifndef SQLITE_ENABLE_STAT3_OR_STAT4 - UNUSED_PARAMETER( p ); - UNUSED_PARAMETER( iChng ); -#endif } +#endif /* SQLITE_ENABLE_STAT4 */ /* ** Implementation of the stat_push SQL function: stat_push(P,C,R) ** Arguments: ** -** P Pointer to the Stat4Accum object created by stat_init() +** P Pointer to the StatAccum object created by stat_init() ** C Index of left-most column to differ from previous row ** R Rowid for the current row. Might be a key record for ** WITHOUT ROWID tables. ** -** This SQL function always returns NULL. It's purpose it to accumulate -** statistical data and/or samples in the Stat4Accum object about the -** index being analyzed. The stat_get() SQL function will later be used to -** extract relevant information for constructing the sqlite_statN tables. +** The purpose of this routine is to collect statistical data and/or +** samples from the index being analyzed into the StatAccum object. +** The stat_get() SQL function will be used afterwards to +** retrieve the information gathered. +** +** This SQL function usually returns NULL, but might return an integer +** if it wants the byte-code to do special processing. ** -** The R parameter is only used for STAT3 and STAT4 +** The R parameter is only used for STAT4 */ static void statPush( sqlite3_context *context, @@ -97120,7 +111797,7 @@ static void statPush( int i; /* The three function arguments */ - Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]); + StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]); int iChng = sqlite3_value_int(argv[1]); UNUSED_PARAMETER( argc ); @@ -97133,7 +111810,9 @@ static void statPush( for(i=0; inCol; i++) p->current.anEq[i] = 1; }else{ /* Second and subsequent calls get processed here */ - samplePushPrevious(p, iChng); +#ifdef SQLITE_ENABLE_STAT4 + if( p->mxSample ) samplePushPrevious(p, iChng); +#endif /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply ** to the current row of the index. */ @@ -97142,27 +111821,26 @@ static void statPush( } for(i=iChng; inCol; i++){ p->current.anDLt[i]++; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - p->current.anLt[i] += p->current.anEq[i]; +#ifdef SQLITE_ENABLE_STAT4 + if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i]; #endif p->current.anEq[i] = 1; } } - p->nRow++; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){ - sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2])); - }else{ - sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]), - sqlite3_value_blob(argv[2])); - } - p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345; -#endif + p->nRow++; #ifdef SQLITE_ENABLE_STAT4 - { - tRowcnt nLt = p->current.anLt[p->nCol-1]; + if( p->mxSample ){ + tRowcnt nLt; + if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){ + sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2])); + }else{ + sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]), + sqlite3_value_blob(argv[2])); + } + p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345; + nLt = p->current.anLt[p->nCol-1]; /* Check if this is to be a periodic sample. If so, add it. */ if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){ p->current.isPSample = 1; @@ -97178,16 +111856,22 @@ static void statPush( sampleCopy(p, &p->aBest[i], &p->current); } } - } + }else #endif + if( p->nLimit && p->nRow>(tRowcnt)p->nLimit*(p->nSkipAhead+1) ){ + p->nSkipAhead++; + sqlite3_result_int(context, p->current.anDLt[0]>0); + } } + static const FuncDef statPushFuncdef = { - 2+IsStat34, /* nArg */ + 2+IsStat4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statPush, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "stat_push", /* zName */ {0} }; @@ -97201,18 +111885,18 @@ static const FuncDef statPushFuncdef = { /* ** Implementation of the stat_get(P,J) SQL function. This routine is ** used to query statistical information that has been gathered into -** the Stat4Accum object by prior calls to stat_push(). The P parameter -** has type BLOB but it is really just a pointer to the Stat4Accum object. +** the StatAccum object by prior calls to stat_push(). The P parameter +** has type BLOB but it is really just a pointer to the StatAccum object. ** The content to returned is determined by the parameter J ** which is one of the STAT_GET_xxxx values defined above. ** ** The stat_get(P,J) function is not available to generic SQL. It is ** inserted as part of a manually constructed bytecode program. (See ** the callStatGet() routine below.) It is guaranteed that the P -** parameter will always be a poiner to a Stat4Accum object, never a +** parameter will always be a pointer to a StatAccum object, never a ** NULL. ** -** If neither STAT3 nor STAT4 are enabled, then J is always +** If STAT4 is not enabled, then J is always ** STAT_GET_STAT1 and is hence omitted and this routine becomes ** a one-parameter function, stat_get(P), that always returns the ** stat1 table entry information. @@ -97222,15 +111906,16 @@ static void statGet( int argc, sqlite3_value **argv ){ - Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]); -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - /* STAT3 and STAT4 have a parameter on this routine. */ + StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]); +#ifdef SQLITE_ENABLE_STAT4 + /* STAT4 has a parameter on this routine. */ int eCall = sqlite3_value_int(argv[1]); assert( argc==2 ); - assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ + assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ || eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT - || eCall==STAT_GET_NDLT + || eCall==STAT_GET_NDLT ); + assert( eCall==STAT_GET_STAT1 || p->mxSample ); if( eCall==STAT_GET_STAT1 ) #else assert( argc==1 ); @@ -97239,54 +111924,46 @@ static void statGet( /* Return the value to store in the "stat" column of the sqlite_stat1 ** table for this index. ** - ** The value is a string composed of a list of integers describing - ** the index. The first integer in the list is the total number of - ** entries in the index. There is one additional integer in the list + ** The value is a string composed of a list of integers describing + ** the index. The first integer in the list is the total number of + ** entries in the index. There is one additional integer in the list ** for each indexed column. This additional integer is an estimate of - ** the number of rows matched by a stabbing query on the index using + ** the number of rows matched by a equality query on the index using ** a key with the corresponding number of fields. In other words, - ** if the index is on columns (a,b) and the sqlite_stat1 value is + ** if the index is on columns (a,b) and the sqlite_stat1 value is ** "100 10 2", then SQLite estimates that: ** ** * the index contains 100 rows, ** * "WHERE a=?" matches 10 rows, and ** * "WHERE a=? AND b=?" matches 2 rows. ** - ** If D is the count of distinct values and K is the total number of + ** If D is the count of distinct values and K is the total number of ** rows, then each estimate is computed as: ** ** I = (K+D-1)/D */ - char *z; - int i; - - char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 ); - if( zRet==0 ){ - sqlite3_result_error_nomem(context); - return; - } + sqlite3_str sStat; /* Text of the constructed "stat" line */ + int i; /* Loop counter */ - sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow); - z = zRet + sqlite3Strlen30(zRet); + sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100); + sqlite3_str_appendf(&sStat, "%llu", + p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow); for(i=0; inKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; - sqlite3_snprintf(24, z, " %llu", iVal); - z += sqlite3Strlen30(z); + sqlite3_str_appendf(&sStat, " %llu", iVal); assert( p->current.anEq[i] ); } - assert( z[0]=='\0' && z>zRet ); - - sqlite3_result_text(context, zRet, -1, sqlite3_free); + sqlite3ResultStrAccum(context, &sStat); } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 else if( eCall==STAT_GET_ROWID ){ if( p->iGet<0 ){ samplePushPrevious(p, 0); p->iGet = 0; } if( p->iGetnSample ){ - Stat4Sample *pS = p->a + p->iGet; + StatSample *pS = p->a + p->iGet; if( pS->nRowid==0 ){ sqlite3_result_int64(context, pS->u.iRowid); }else{ @@ -97296,66 +111973,79 @@ static void statGet( } }else{ tRowcnt *aCnt = 0; + sqlite3_str sStat; + int i; assert( p->iGetnSample ); switch( eCall ){ case STAT_GET_NEQ: aCnt = p->a[p->iGet].anEq; break; case STAT_GET_NLT: aCnt = p->a[p->iGet].anLt; break; default: { - aCnt = p->a[p->iGet].anDLt; + aCnt = p->a[p->iGet].anDLt; p->iGet++; break; } } - - if( IsStat3 ){ - sqlite3_result_int64(context, (i64)aCnt[0]); - }else{ - char *zRet = sqlite3MallocZero(p->nCol * 25); - if( zRet==0 ){ - sqlite3_result_error_nomem(context); - }else{ - int i; - char *z = zRet; - for(i=0; inCol; i++){ - sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]); - z += sqlite3Strlen30(z); - } - assert( z[0]=='\0' && z>zRet ); - z[-1] = '\0'; - sqlite3_result_text(context, zRet, -1, sqlite3_free); - } + sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100); + for(i=0; inCol; i++){ + sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]); } + if( sStat.nChar ) sStat.nChar--; + sqlite3ResultStrAccum(context, &sStat); } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( argc ); #endif } static const FuncDef statGetFuncdef = { - 1+IsStat34, /* nArg */ + 1+IsStat4, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statGet, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "stat_get", /* zName */ {0} }; -static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){ - assert( regOut!=regStat4 && regOut!=regStat4+1 ); -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1); +static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){ +#ifdef SQLITE_ENABLE_STAT4 + sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1); #elif SQLITE_DEBUG assert( iParam==STAT_GET_STAT1 ); #else UNUSED_PARAMETER( iParam ); #endif - sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut, - (char*)&statGetFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 1 + IsStat34); + assert( regOut!=regStat && regOut!=regStat+1 ); + sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4, + &statGetFuncdef, 0); +} + +#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS +/* Add a comment to the most recent VDBE opcode that is the name +** of the k-th column of the pIdx index. +*/ +static void analyzeVdbeCommentIndexWithColumnName( + Vdbe *v, /* Prepared statement under construction */ + Index *pIdx, /* Index whose column is being loaded */ + int k /* Which column index */ +){ + int i; /* Index of column in the table */ + assert( k>=0 && knColumn ); + i = pIdx->aiColumn[k]; + if( NEVER(i==XN_ROWID) ){ + VdbeComment((v,"%s.rowid",pIdx->zName)); + }else if( i==XN_EXPR ){ + VdbeComment((v,"%s.expr(%d)",pIdx->zName, k)); + }else{ + VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName)); + } } +#else +# define analyzeVdbeCommentIndexWithColumnName(a,b,c) +#endif /* SQLITE_DEBUG */ /* ** Generate code to do an analysis of all indices associated with @@ -97379,27 +112069,29 @@ static void analyzeOneTable( int iDb; /* Index of database containing pTab */ u8 needTableCnt = 1; /* True to count the table */ int regNewRowid = iMem++; /* Rowid for the inserted record */ - int regStat4 = iMem++; /* Register to hold Stat4Accum object */ + int regStat = iMem++; /* Register to hold StatAccum object */ int regChng = iMem++; /* Index of changed index field */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int regRowid = iMem++; /* Rowid argument passed to stat_push() */ -#endif int regTemp = iMem++; /* Temporary use register */ + int regTemp2 = iMem++; /* Second temporary use register */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */ int regPrev = iMem; /* MUST BE LAST (see below) */ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + Table *pStat1 = 0; +#endif pParse->nMem = MAX(pParse->nMem, iMem); v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ return; } - if( pTab->tnum==0 ){ + if( !IsOrdinaryTable(pTab) ){ /* Do not gather statistics on views or virtual tables */ return; } - if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){ + if( sqlite3_strlike("sqlite\\_%", pTab->zName, '\\')==0 ){ /* Do not gather statistics on system tables */ return; } @@ -97414,7 +112106,19 @@ static void analyzeOneTable( } #endif - /* Establish a read-lock on the table at the shared-cache level. +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( db->xPreUpdateCallback ){ + pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13); + if( pStat1==0 ) return; + pStat1->zName = (char*)&pStat1[1]; + memcpy(pStat1->zName, "sqlite_stat1", 13); + pStat1->nCol = 3; + pStat1->iPKey = -1; + sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB); + } +#endif + + /* Establish a read-lock on the table at the shared-cache level. ** Open a read-only cursor on the table. Also allocate a cursor number ** to use for scanning indexes (iIdxCur). No index cursor is opened at ** this time though. */ @@ -97480,9 +112184,9 @@ static void analyzeOneTable( ** end_of_scan: */ - /* Make sure there are enough memory cells allocated to accommodate + /* Make sure there are enough memory cells allocated to accommodate ** the regPrev array and a trailing rowid (the rowid slot is required - ** when building a record to insert into the sample column of + ** when building a record to insert into the sample column of ** the sqlite_stat4 table. */ pParse->nMem = MAX(pParse->nMem, regPrev+nColTest); @@ -97493,23 +112197,31 @@ static void analyzeOneTable( VdbeComment((v, "%s", pIdx->zName)); /* Invoke the stat_init() function. The arguments are: - ** + ** ** (1) the number of columns in the index including the rowid ** (or for a WITHOUT ROWID table, the number of PK columns), ** (2) the number of columns in the key without the rowid/pk - ** (3) the number of rows in the index, - ** - ** - ** The third argument is only used for STAT3 and STAT4 + ** (3) estimated number of rows in the index, */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3); + sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1); + assert( regRowid==regStat+2 ); + sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid); +#ifdef SQLITE_ENABLE_STAT4 + if( OptimizationEnabled(db, SQLITE_Stat4) ){ + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp); + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); + VdbeCoverage(v); + }else #endif - sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); - sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4, - (char*)&statInitFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 2+IsStat34); + { + addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1); + } + assert( regTemp2==regStat+4 ); + sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2); + sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4, + &statInitFuncdef, 0); /* Implementation of the following: ** @@ -97519,13 +112231,11 @@ static void analyzeOneTable( ** goto next_push_0; ** */ - addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); - VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng); addrNextRow = sqlite3VdbeCurrentAddr(v); if( nColTest>0 ){ - int endDistinctTest = sqlite3VdbeMakeLabel(v); + int endDistinctTest = sqlite3VdbeMakeLabel(pParse); int *aGotoChng; /* Array of jump instruction addresses */ aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest); if( aGotoChng==0 ) continue; @@ -97544,7 +112254,7 @@ static void analyzeOneTable( addrNextRow = sqlite3VdbeCurrentAddr(v); if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){ /* For a single-column UNIQUE index, once we have found a non-NULL - ** row, we know that all the rest will be distinct, so skip + ** row, we know that all the rest will be distinct, so skip ** subsequent distinctness tests. */ sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest); VdbeCoverage(v); @@ -97553,15 +112263,16 @@ static void analyzeOneTable( char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]); sqlite3VdbeAddOp2(v, OP_Integer, i, regChng); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp); - aGotoChng[i] = + analyzeVdbeCommentIndexWithColumnName(v,pIdx,i); + aGotoChng[i] = sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng); sqlite3VdbeGoto(v, endDistinctTest); - - + + /* ** chng_addr_0: ** regPrev(0) = idx(0) @@ -97573,53 +112284,72 @@ static void analyzeOneTable( for(i=0; ipTable); - int j, k, regKey; - regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); - for(j=0; jnKeyCol; j++){ - k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); - assert( k>=0 && knCol ); - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); - VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); +#ifdef SQLITE_ENABLE_STAT4 + if( OptimizationEnabled(db, SQLITE_Stat4) ){ + assert( regRowid==(regStat+2) ); + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); + int j, k, regKey; + regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); + for(j=0; jnKeyCol; j++){ + k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); + assert( k>=0 && knColumn ); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); + analyzeVdbeCommentIndexWithColumnName(v,pIdx,k); + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid); + sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol); } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid); - sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol); } #endif - assert( regChng==(regStat4+1) ); - sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp, - (char*)&statPushFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 2+IsStat34); - sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); + assert( regChng==(regStat+1) ); + { + sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4, + &statPushFuncdef, 0); + if( db->nAnalysisLimit ){ + int j1, j2, j3; + j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); VdbeCoverage(v); + j2 = sqlite3VdbeAddOp1(v, OP_If, regTemp); VdbeCoverage(v); + j3 = sqlite3VdbeAddOp4Int(v, OP_SeekGT, iIdxCur, 0, regPrev, 1); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, j1); + sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); + sqlite3VdbeJumpHere(v, j2); + sqlite3VdbeJumpHere(v, j3); + }else{ + sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); + } + } /* Add the entry to the stat1 table. */ - callStatGet(v, regStat4, STAT_GET_STAT1, regStat1); + callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1); assert( "BBB"[0]==SQLITE_AFF_TEXT ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE); +#endif sqlite3VdbeChangeP5(v, OPFLAG_APPEND); - /* Add the entries to the stat3 or stat4 table. */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - { + /* Add the entries to the stat4 table. */ +#ifdef SQLITE_ENABLE_STAT4 + if( OptimizationEnabled(db, SQLITE_Stat4) && db->nAnalysisLimit==0 ){ int regEq = regStat1; int regLt = regStat1+1; int regDLt = regStat1+2; @@ -97633,32 +112363,25 @@ static void analyzeOneTable( pParse->nMem = MAX(pParse->nMem, regCol+nCol); addrNext = sqlite3VdbeCurrentAddr(v); - callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid); + callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid); addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid); VdbeCoverage(v); - callStatGet(v, regStat4, STAT_GET_NEQ, regEq); - callStatGet(v, regStat4, STAT_GET_NLT, regLt); - callStatGet(v, regStat4, STAT_GET_NDLT, regDLt); + callStatGet(pParse, regStat, STAT_GET_NEQ, regEq); + callStatGet(pParse, regStat, STAT_GET_NLT, regLt); + callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); - /* We know that the regSampleRowid row exists because it was read by - ** the previous loop. Thus the not-found jump of seekOp will never - ** be taken */ - VdbeCoverageNeverTaken(v); -#ifdef SQLITE_ENABLE_STAT3 - sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample); -#else + VdbeCoverage(v); for(i=0; in==0 ){ - /* Form 2: Analyze the database or table named */ - iDb = sqlite3FindDb(db, pName1); - if( iDb>=0 ){ - analyzeDatabase(pParse, iDb); - }else{ - z = sqlite3NameFromToken(db, pName1); - if( z ){ - if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){ - analyzeTable(pParse, pIdx->pTable, pIdx); - }else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){ - analyzeTable(pParse, pTab, 0); - } - sqlite3DbFree(db, z); - } - } + }else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){ + /* Analyze the schema named as the argument */ + analyzeDatabase(pParse, iDb); }else{ - /* Form 3: Analyze the fully qualified table name */ + /* Form 3: Analyze the table or index named as an argument */ iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName); if( iDb>=0 ){ - zDb = db->aDb[iDb].zDbSName; + zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; z = sqlite3NameFromToken(db, pTableName); if( z ){ if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){ @@ -97809,10 +112522,11 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){ } sqlite3DbFree(db, z); } - } + } + } + if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){ + sqlite3VdbeAddOp0(v, OP_Expire); } - v = sqlite3GetVdbe(pParse); - if( v ) sqlite3VdbeAddOp0(v, OP_Expire); } /* @@ -97842,7 +112556,7 @@ static void decodeIntArray( int i; tRowcnt v; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 if( z==0 ) z = ""; #else assert( z!=0 ); @@ -97853,7 +112567,7 @@ static void decodeIntArray( v = v*10 + c - '0'; z++; } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 if( aOut ) aOut[i] = v; if( aLog ) aLog[i] = sqlite3LogEst(v); #else @@ -97864,7 +112578,7 @@ static void decodeIntArray( #endif if( *z==' ' ) z++; } -#ifndef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifndef SQLITE_ENABLE_STAT4 assert( pIndex!=0 ); { #else if( pIndex ){ @@ -97875,7 +112589,9 @@ static void decodeIntArray( if( sqlite3_strglob("unordered*", z)==0 ){ pIndex->bUnordered = 1; }else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){ - pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3)); + int sz = sqlite3Atoi(z+3); + if( sz<2 ) sz = 2; + pIndex->szIdxRow = sqlite3LogEst(sz); }else if( sqlite3_strglob("noskipscan*", z)==0 ){ pIndex->noSkipScan = 1; } @@ -97892,7 +112608,7 @@ static void decodeIntArray( /* ** This callback is invoked once for each index when reading the -** sqlite_stat1 table. +** sqlite_stat1 table. ** ** argv[0] = name of the table ** argv[1] = name of the index (might be NULL) @@ -97929,8 +112645,8 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ if( pIndex ){ tRowcnt *aiRowEst = 0; int nCol = pIndex->nKeyCol+1; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - /* Index.aiRowEst may already be set here if there are duplicate +#ifdef SQLITE_ENABLE_STAT4 + /* Index.aiRowEst may already be set here if there are duplicate ** sqlite_stat1 entries for this index. In that case just clobber ** the old data with the new instead of allocating a new array. */ if( pIndex->aiRowEst==0 ){ @@ -97941,7 +112657,11 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ #endif pIndex->bUnordered = 0; decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); - if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + pIndex->hasStat1 = 1; + if( pIndex->pPartIdxWhere==0 ){ + pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + pTable->tabFlags |= TF_HasStat1; + } }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; @@ -97950,6 +112670,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ #endif decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx); pTable->szTabRow = fakeIdx.szIdxRow; + pTable->tabFlags |= TF_HasStat1; } return 0; @@ -97960,7 +112681,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ ** and its contents. */ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 if( pIdx->aSample ){ int j; for(j=0; jnSample; j++){ @@ -97976,13 +112697,13 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ #else UNUSED_PARAMETER(db); UNUSED_PARAMETER(pIdx); -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 /* ** Populate the pIdx->aAvgEq[] array based on the samples currently -** stored in pIdx->aSample[]. +** stored in pIdx->aSample[]. */ static void initAvgEq(Index *pIdx){ if( pIdx ){ @@ -98018,12 +112739,12 @@ static void initAvgEq(Index *pIdx){ pIdx->nRowEst0 = nRow; /* Set nSum to the number of distinct (iCol+1) field prefixes that - ** occur in the stat4 table for this index. Set sumEq to the sum of - ** the nEq values for column iCol for the same set (adding the value + ** occur in the stat4 table for this index. Set sumEq to the sum of + ** the nEq values for column iCol for the same set (adding the value ** only once where there exist duplicate prefixes). */ for(i=0; inSample-1) - || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] + || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){ sumEq += aSample[i].anEq[iCol]; nSum100 += 100; @@ -98057,12 +112778,11 @@ static Index *findIndexOrPrimaryKey( } /* -** Load the content from either the sqlite_stat4 or sqlite_stat3 table +** Load the content from either the sqlite_stat4 ** into the relevant Index.aSample[] arrays. ** ** Arguments zSql1 and zSql2 must point to SQL statements that return -** data equivalent to the following (statements are different for stat3, -** see the caller of this function for details): +** data equivalent to the following: ** ** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx ** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4 @@ -98071,7 +112791,6 @@ static Index *findIndexOrPrimaryKey( */ static int loadStatTbl( sqlite3 *db, /* Database handle */ - int bStat3, /* Assume single column records only */ const char *zSql1, /* SQL statement 1 (see above) */ const char *zSql2, /* SQL statement 2 (see above) */ const char *zDb /* Database name (e.g. "main") */ @@ -98105,17 +112824,13 @@ static int loadStatTbl( if( zIndex==0 ) continue; nSample = sqlite3_column_int(pStmt, 1); pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); - assert( pIdx==0 || bStat3 || pIdx->nSample==0 ); - /* Index.nSample is non-zero at this point if data has already been - ** loaded from the stat4 table. In this case ignore stat3 data. */ - if( pIdx==0 || pIdx->nSample ) continue; - if( bStat3==0 ){ - assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 ); - if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ - nIdxCol = pIdx->nKeyCol; - }else{ - nIdxCol = pIdx->nColumn; - } + assert( pIdx==0 || pIdx->nSample==0 ); + if( pIdx==0 ) continue; + assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 ); + if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){ + nIdxCol = pIdx->nKeyCol; + }else{ + nIdxCol = pIdx->nColumn; } pIdx->nSampleCol = nIdxCol; nByte = sizeof(IndexSample) * nSample; @@ -98129,6 +112844,7 @@ static int loadStatTbl( } pSpace = (tRowcnt*)&pIdx->aSample[nSample]; pIdx->aAvgEq = pSpace; pSpace += nIdxCol; + pIdx->pTable->tabFlags |= TF_HasStat4; for(i=0; iaSample[i].anEq = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol; @@ -98156,10 +112872,9 @@ static int loadStatTbl( if( zIndex==0 ) continue; pIdx = findIndexOrPrimaryKey(db, zIndex, zDb); if( pIdx==0 ) continue; - /* This next condition is true if data has already been loaded from - ** the sqlite_stat4 table. In this case ignore stat3 data. */ + /* This next condition is true if data has already been loaded from + ** the sqlite_stat4 table. */ nCol = pIdx->nSampleCol; - if( bStat3 && nCol>1 ) continue; if( pIdx!=pPrevIdx ){ initAvgEq(pPrevIdx); pPrevIdx = pIdx; @@ -98192,45 +112907,39 @@ static int loadStatTbl( } /* -** Load content from the sqlite_stat4 and sqlite_stat3 tables into +** Load content from the sqlite_stat4 table into ** the Index.aSample[] arrays of all indices. */ static int loadStat4(sqlite3 *db, const char *zDb){ int rc = SQLITE_OK; /* Result codes from subroutines */ + const Table *pStat4; assert( db->lookaside.bDisable ); - if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){ - rc = loadStatTbl(db, 0, - "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", + if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0 + && IsOrdinaryTable(pStat4) + ){ + rc = loadStatTbl(db, + "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", zDb ); } - - if( rc==SQLITE_OK && sqlite3FindTable(db, "sqlite_stat3", zDb) ){ - rc = loadStatTbl(db, 1, - "SELECT idx,count(*) FROM %Q.sqlite_stat3 GROUP BY idx", - "SELECT idx,neq,nlt,ndlt,sqlite_record(sample) FROM %Q.sqlite_stat3", - zDb - ); - } - return rc; } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ /* -** Load the content of the sqlite_stat1 and sqlite_stat3/4 tables. The +** Load the content of the sqlite_stat1 and sqlite_stat4 tables. The ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] -** arrays. The contents of sqlite_stat3/4 are used to populate the +** arrays. The contents of sqlite_stat4 are used to populate the ** Index.aSample[] arrays. ** ** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR -** is returned. In this case, even if SQLITE_ENABLE_STAT3/4 was defined -** during compilation and the sqlite_stat3/4 table is present, no data is +** is returned. In this case, even if SQLITE_ENABLE_STAT4 was defined +** during compilation and the sqlite_stat4 table is present, no data is ** read from it. ** -** If SQLITE_ENABLE_STAT3/4 was defined during compilation and the +** If SQLITE_ENABLE_STAT4 was defined during compilation and the ** sqlite_stat4 table is not present in the database, SQLITE_ERROR is ** returned. However, in this case, data is read from the sqlite_stat1 ** table (if it is present) before returning. @@ -98244,16 +112953,22 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ HashElem *i; char *zSql; int rc = SQLITE_OK; + Schema *pSchema = db->aDb[iDb].pSchema; + const Table *pStat1; assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pBt!=0 ); /* Clear any prior statistics */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){ + Table *pTab = sqliteHashData(i); + pTab->tabFlags &= ~TF_HasStat1; + } + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); - pIdx->aiRowLogEst[0] = 0; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + pIdx->hasStat1 = 0; +#ifdef SQLITE_ENABLE_STAT4 sqlite3DeleteIndexSamples(db, pIdx); pIdx->aSample = 0; #endif @@ -98262,8 +112977,10 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Load new statistics out of the sqlite_stat1 table */ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zDbSName; - if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ - zSql = sqlite3MPrintf(db, + if( (pStat1 = sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)) + && IsOrdinaryTable(pStat1) + ){ + zSql = sqlite3MPrintf(db, "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -98275,19 +112992,19 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); - if( pIdx->aiRowLogEst[0]==0 ) sqlite3DefaultRowEst(pIdx); + if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx); } /* Load the statistics from the sqlite_stat4 table. */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){ - db->lookaside.bDisable++; +#ifdef SQLITE_ENABLE_STAT4 + if( rc==SQLITE_OK ){ + DisableLookaside; rc = loadStat4(db, sInfo.zDatabase); - db->lookaside.bDisable--; + EnableLookaside; } - for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3_free(pIdx->aiRowEst); pIdx->aiRowEst = 0; @@ -98352,6 +113069,17 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr) return rc; } +/* +** Return true if zName points to a name that may be used to refer to +** database iDb attached to handle db. +*/ +SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){ + return ( + sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0 + || (iDb==0 && sqlite3StrICmp("main", zName)==0) + ); +} + /* ** An SQL user-function registered to do the work of an ATTACH statement. The ** three arguments to the function come directly from an attach statement: @@ -98362,6 +113090,10 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr) ** ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the ** third argument. +** +** If the db->init.reopenMemdb flags is set, then instead of attaching a +** new database, close the database on db->init.iDb and reopen it as an +** empty MemDB. */ static void attachFunc( sqlite3_context *context, @@ -98376,150 +113108,138 @@ static void attachFunc( char *zPath = 0; char *zErr = 0; unsigned int flags; - Db *aNew; + Db *aNew; /* New array of Db pointers */ + Db *pNew; /* Db object for the newly attached database */ char *zErrDyn = 0; sqlite3_vfs *pVfs; UNUSED_PARAMETER(NotUsed); - zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; - /* Check for the following errors: - ** - ** * Too many attached databases, - ** * Transaction currently open - ** * Specified database name already being used. - */ - if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ - zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", - db->aLimit[SQLITE_LIMIT_ATTACHED] - ); - goto attach_error; - } - if( !db->autoCommit ){ - zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); - goto attach_error; - } - for(i=0; inDb; i++){ - char *z = db->aDb[i].zDbSName; - assert( z && zName ); - if( sqlite3StrICmp(z, zName)==0 ){ - zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); +#ifndef SQLITE_OMIT_DESERIALIZE +# define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb) +#else +# define REOPEN_AS_MEMDB(db) (0) +#endif + + if( REOPEN_AS_MEMDB(db) ){ + /* This is not a real ATTACH. Instead, this routine is being called + ** from sqlite3_deserialize() to close database db->init.iDb and + ** reopen it as a MemDB */ + pVfs = sqlite3_vfs_find("memdb"); + if( pVfs==0 ) return; + pNew = &db->aDb[db->init.iDb]; + if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt); + pNew->pBt = 0; + pNew->pSchema = 0; + rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); + }else{ + /* This is a real ATTACH + ** + ** Check for the following errors: + ** + ** * Too many attached databases, + ** * Transaction currently open + ** * Specified database name already being used. + */ + if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ + zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", + db->aLimit[SQLITE_LIMIT_ATTACHED] + ); goto attach_error; } - } + for(i=0; inDb; i++){ + assert( zName ); + if( sqlite3DbIsNamed(db, i, zName) ){ + zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); + goto attach_error; + } + } - /* Allocate the new entry in the db->aDb[] array and initialize the schema - ** hash tables. - */ - if( db->aDb==db->aDbStatic ){ - aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 ); - if( aNew==0 ) return; - memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); - }else{ - aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); - if( aNew==0 ) return; - } - db->aDb = aNew; - aNew = &db->aDb[db->nDb]; - memset(aNew, 0, sizeof(*aNew)); + /* Allocate the new entry in the db->aDb[] array and initialize the schema + ** hash tables. + */ + if( db->aDb==db->aDbStatic ){ + aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 ); + if( aNew==0 ) return; + memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); + }else{ + aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); + if( aNew==0 ) return; + } + db->aDb = aNew; + pNew = &db->aDb[db->nDb]; + memset(pNew, 0, sizeof(*pNew)); - /* Open the database file. If the btree is successfully opened, use - ** it to obtain the database schema. At this point the schema may - ** or may not be initialized. - */ - flags = db->openFlags; - rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); - if( rc!=SQLITE_OK ){ - if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); - return; + /* Open the database file. If the btree is successfully opened, use + ** it to obtain the database schema. At this point the schema may + ** or may not be initialized. + */ + flags = db->openFlags; + rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + return; + } + assert( pVfs ); + flags |= SQLITE_OPEN_MAIN_DB; + rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); + db->nDb++; + pNew->zDbSName = sqlite3DbStrDup(db, zName); } - assert( pVfs ); - flags |= SQLITE_OPEN_MAIN_DB; - rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); - sqlite3_free( zPath ); - db->nDb++; - db->skipBtreeMutex = 0; + db->noSharedCache = 0; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; - aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); - if( !aNew->pSchema ){ + pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt); + if( !pNew->pSchema ){ rc = SQLITE_NOMEM_BKPT; - }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ - zErrDyn = sqlite3MPrintf(db, + }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){ + zErrDyn = sqlite3MPrintf(db, "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } - sqlite3BtreeEnter(aNew->pBt); - pPager = sqlite3BtreePager(aNew->pBt); + sqlite3BtreeEnter(pNew->pBt); + pPager = sqlite3BtreePager(pNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); - sqlite3BtreeSecureDelete(aNew->pBt, + sqlite3BtreeSecureDelete(pNew->pBt, sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); #ifndef SQLITE_OMIT_PAGER_PRAGMAS - sqlite3BtreeSetPagerFlags(aNew->pBt, + sqlite3BtreeSetPagerFlags(pNew->pBt, PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif - sqlite3BtreeLeave(aNew->pBt); + sqlite3BtreeLeave(pNew->pBt); } - aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - aNew->zDbSName = sqlite3DbStrDup(db, zName); - if( rc==SQLITE_OK && aNew->zDbSName==0 ){ + pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; + if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } - - -#ifdef SQLITE_HAS_CODEC - if( rc==SQLITE_OK ){ - extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); - extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); - int nKey; - char *zKey; - int t = sqlite3_value_type(argv[2]); - switch( t ){ - case SQLITE_INTEGER: - case SQLITE_FLOAT: - zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); - rc = SQLITE_ERROR; - break; - - case SQLITE_TEXT: - case SQLITE_BLOB: - nKey = sqlite3_value_bytes(argv[2]); - zKey = (char *)sqlite3_value_blob(argv[2]); - rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); - break; - - case SQLITE_NULL: - /* No key specified. Use the key from the main database */ - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ - rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); - } - break; - } - } -#endif + sqlite3_free_filename( zPath ); /* If the file was opened successfully, read the schema for the new database. - ** If this fails, or if opening the file failed, then close the file and - ** remove the entry from the db->aDb[] array. i.e. put everything back the way - ** we found it. + ** If this fails, or if opening the file failed, then close the file and + ** remove the entry from the db->aDb[] array. i.e. put everything back the + ** way we found it. */ if( rc==SQLITE_OK ){ sqlite3BtreeEnterAll(db); - rc = sqlite3Init(db, &zErrDyn); + db->init.iDb = 0; + db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); + if( !REOPEN_AS_MEMDB(db) ){ + rc = sqlite3Init(db, &zErrDyn); + } sqlite3BtreeLeaveAll(db); + assert( zErrDyn==0 || rc!=SQLITE_OK ); } #ifdef SQLITE_USER_AUTHENTICATION - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ u8 newAuth = 0; rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuthauth.authLevel ){ @@ -98528,25 +113248,27 @@ static void attachFunc( } #endif if( rc ){ - int iDb = db->nDb - 1; - assert( iDb>=2 ); - if( db->aDb[iDb].pBt ){ - sqlite3BtreeClose(db->aDb[iDb].pBt); - db->aDb[iDb].pBt = 0; - db->aDb[iDb].pSchema = 0; - } - sqlite3ResetAllSchemasOfConnection(db); - db->nDb = iDb; - if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ - sqlite3OomFault(db); - sqlite3DbFree(db, zErrDyn); - zErrDyn = sqlite3MPrintf(db, "out of memory"); - }else if( zErrDyn==0 ){ - zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile); + if( !REOPEN_AS_MEMDB(db) ){ + int iDb = db->nDb - 1; + assert( iDb>=2 ); + if( db->aDb[iDb].pBt ){ + sqlite3BtreeClose(db->aDb[iDb].pBt); + db->aDb[iDb].pBt = 0; + db->aDb[iDb].pSchema = 0; + } + sqlite3ResetAllSchemasOfConnection(db); + db->nDb = iDb; + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomFault(db); + sqlite3DbFree(db, zErrDyn); + zErrDyn = sqlite3MPrintf(db, "out of memory"); + }else if( zErrDyn==0 ){ + zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile); + } } goto attach_error; } - + return; attach_error: @@ -98575,6 +113297,7 @@ static void detachFunc( sqlite3 *db = sqlite3_context_db_handle(context); int i; Db *pDb = 0; + HashElem *pEntry; char zErr[128]; UNUSED_PARAMETER(NotUsed); @@ -98583,7 +113306,7 @@ static void detachFunc( for(i=0; inDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; - if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break; + if( sqlite3DbIsNamed(db, i, zName) ) break; } if( i>=db->nDb ){ @@ -98594,16 +113317,25 @@ static void detachFunc( sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } - if( !db->autoCommit ){ - sqlite3_snprintf(sizeof(zErr), zErr, - "cannot DETACH database within transaction"); - goto detach_error; - } - if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){ + if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE + || sqlite3BtreeIsInBackup(pDb->pBt) + ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } + /* If any TEMP triggers reference the schema being detached, move those + ** triggers to reference the TEMP schema itself. */ + assert( db->aDb[1].pSchema ); + pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash); + while( pEntry ){ + Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); + if( pTrig->pTabSchema==pDb->pSchema ){ + pTrig->pTabSchema = pTrig->pSchema; + } + pEntry = sqliteHashNext(pEntry); + } + sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; @@ -98637,18 +113369,19 @@ static void codeAttach( memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; - if( - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || - SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) + if( + SQLITE_OK!=resolveAttachExpr(&sName, pFilename) || + SQLITE_OK!=resolveAttachExpr(&sName, pDbname) || + SQLITE_OK!=resolveAttachExpr(&sName, pKey) ){ goto attach_end; } #ifndef SQLITE_OMIT_AUTHORIZATION - if( pAuthArg ){ + if( ALWAYS(pAuthArg) ){ char *zAuthArg; if( pAuthArg->op==TK_STRING ){ + assert( !ExprHasProperty(pAuthArg, EP_IntValue) ); zAuthArg = pAuthArg->u.zToken; }else{ zAuthArg = 0; @@ -98669,18 +113402,15 @@ static void codeAttach( assert( v || db->mallocFailed ); if( v ){ - sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3, - (char *)pFunc, P4_FUNCDEF); - assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg ); - sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg)); - + sqlite3VdbeAddFunctionCall(pParse, 0, regArgs+3-pFunc->nArg, regArgs+3, + pFunc->nArg, pFunc, 0); /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this ** statement only). For DETACH, set it to false (expire all existing ** statements). */ sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH)); } - + attach_end: sqlite3ExprDelete(db, pFilename); sqlite3ExprDelete(db, pDbname); @@ -98700,6 +113430,7 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){ 0, /* pNext */ detachFunc, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "sqlite_detach", /* zName */ {0} }; @@ -98719,6 +113450,7 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p 0, /* pNext */ attachFunc, /* xSFunc */ 0, /* xFinalize */ + 0, 0, /* xValue, xInverse */ "sqlite_attach", /* zName */ {0} }; @@ -98726,6 +113458,65 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p } #endif /* SQLITE_OMIT_ATTACH */ +/* +** Expression callback used by sqlite3FixAAAA() routines. +*/ +static int fixExprCb(Walker *p, Expr *pExpr){ + DbFixer *pFix = p->u.pFix; + if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL); + if( pExpr->op==TK_VARIABLE ){ + if( pFix->pParse->db->init.busy ){ + pExpr->op = TK_NULL; + }else{ + sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType); + return WRC_Abort; + } + } + return WRC_Continue; +} + +/* +** Select callback used by sqlite3FixAAAA() routines. +*/ +static int fixSelectCb(Walker *p, Select *pSelect){ + DbFixer *pFix = p->u.pFix; + int i; + SrcItem *pItem; + sqlite3 *db = pFix->pParse->db; + int iDb = sqlite3FindDbName(db, pFix->zDb); + SrcList *pList = pSelect->pSrc; + + if( NEVER(pList==0) ) return WRC_Continue; + for(i=0, pItem=pList->a; inSrc; i++, pItem++){ + if( pFix->bTemp==0 ){ + if( pItem->zDatabase ){ + if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ + sqlite3ErrorMsg(pFix->pParse, + "%s %T cannot reference objects in database %s", + pFix->zType, pFix->pName, pItem->zDatabase); + return WRC_Abort; + } + sqlite3DbFree(db, pItem->zDatabase); + pItem->zDatabase = 0; + pItem->fg.notCte = 1; + } + pItem->pSchema = pFix->pSchema; + pItem->fg.fromDDL = 1; + } +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) + if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort; +#endif + } + if( pSelect->pWith ){ + for(i=0; ipWith->nCte; i++){ + if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){ + return WRC_Abort; + } + } + } + return WRC_Continue; +} + /* ** Initialize a DbFixer structure. This routine must be called prior ** to passing the structure to one of the sqliteFixAAAA() routines below. @@ -98737,16 +113528,21 @@ SQLITE_PRIVATE void sqlite3FixInit( const char *zType, /* "view", "trigger", or "index" */ const Token *pName /* Name of the view, trigger, or index */ ){ - sqlite3 *db; - - db = pParse->db; + sqlite3 *db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; pFix->zDb = db->aDb[iDb].zDbSName; pFix->pSchema = db->aDb[iDb].pSchema; pFix->zType = zType; pFix->pName = pName; - pFix->bVarOnly = (iDb==1); + pFix->bTemp = (iDb==1); + pFix->w.pParse = pParse; + pFix->w.xExprCallback = fixExprCb; + pFix->w.xSelectCallback = fixSelectCb; + pFix->w.xSelectCallback2 = sqlite3WalkWinDefnDummyCallback; + pFix->w.walkerDepth = 0; + pFix->w.eCode = 0; + pFix->w.u.pFix = pFix; } /* @@ -98767,104 +113563,27 @@ SQLITE_PRIVATE int sqlite3FixSrcList( DbFixer *pFix, /* Context of the fixation */ SrcList *pList /* The Source list to check and modify */ ){ - int i; - const char *zDb; - struct SrcList_item *pItem; - - if( NEVER(pList==0) ) return 0; - zDb = pFix->zDb; - for(i=0, pItem=pList->a; inSrc; i++, pItem++){ - if( pFix->bVarOnly==0 ){ - if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){ - sqlite3ErrorMsg(pFix->pParse, - "%s %T cannot reference objects in database %s", - pFix->zType, pFix->pName, pItem->zDatabase); - return 1; - } - sqlite3DbFree(pFix->pParse->db, pItem->zDatabase); - pItem->zDatabase = 0; - pItem->pSchema = pFix->pSchema; - } -#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) - if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; - if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; -#endif + int res = 0; + if( pList ){ + Select s; + memset(&s, 0, sizeof(s)); + s.pSrc = pList; + res = sqlite3WalkSelect(&pFix->w, &s); } - return 0; + return res; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) SQLITE_PRIVATE int sqlite3FixSelect( DbFixer *pFix, /* Context of the fixation */ Select *pSelect /* The SELECT statement to be fixed to one database */ ){ - while( pSelect ){ - if( sqlite3FixExprList(pFix, pSelect->pEList) ){ - return 1; - } - if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){ - return 1; - } - if( sqlite3FixExpr(pFix, pSelect->pWhere) ){ - return 1; - } - if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){ - return 1; - } - if( sqlite3FixExpr(pFix, pSelect->pHaving) ){ - return 1; - } - if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){ - return 1; - } - if( sqlite3FixExpr(pFix, pSelect->pLimit) ){ - return 1; - } - if( sqlite3FixExpr(pFix, pSelect->pOffset) ){ - return 1; - } - pSelect = pSelect->pPrior; - } - return 0; + return sqlite3WalkSelect(&pFix->w, pSelect); } SQLITE_PRIVATE int sqlite3FixExpr( DbFixer *pFix, /* Context of the fixation */ Expr *pExpr /* The expression to be fixed to one database */ ){ - while( pExpr ){ - if( pExpr->op==TK_VARIABLE ){ - if( pFix->pParse->db->init.busy ){ - pExpr->op = TK_NULL; - }else{ - sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType); - return 1; - } - } - if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; - }else{ - if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1; - } - if( sqlite3FixExpr(pFix, pExpr->pRight) ){ - return 1; - } - pExpr = pExpr->pLeft; - } - return 0; -} -SQLITE_PRIVATE int sqlite3FixExprList( - DbFixer *pFix, /* Context of the fixation */ - ExprList *pList /* The expression to be fixed to one database */ -){ - int i; - struct ExprList_item *pItem; - if( pList==0 ) return 0; - for(i=0, pItem=pList->a; inExpr; i++, pItem++){ - if( sqlite3FixExpr(pFix, pItem->pExpr) ){ - return 1; - } - } - return 0; + return sqlite3WalkExpr(&pFix->w, pExpr); } #endif @@ -98874,17 +113593,30 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep( TriggerStep *pStep /* The trigger step be fixed to one database */ ){ while( pStep ){ - if( sqlite3FixSelect(pFix, pStep->pSelect) ){ - return 1; - } - if( sqlite3FixExpr(pFix, pStep->pWhere) ){ + if( sqlite3WalkSelect(&pFix->w, pStep->pSelect) + || sqlite3WalkExpr(&pFix->w, pStep->pWhere) + || sqlite3WalkExprList(&pFix->w, pStep->pExprList) + || sqlite3FixSrcList(pFix, pStep->pFrom) + ){ return 1; } - if( sqlite3FixExprList(pFix, pStep->pExprList) ){ - return 1; +#ifndef SQLITE_OMIT_UPSERT + { + Upsert *pUp; + for(pUp=pStep->pUpsert; pUp; pUp=pUp->pNextUpsert){ + if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget) + || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere) + || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet) + || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere) + ){ + return 1; + } + } } +#endif pStep = pStep->pNext; } + return 0; } #endif @@ -98971,7 +113703,7 @@ SQLITE_API int sqlite3_set_authorizer( sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; - sqlite3ExpirePreparedStatements(db); + if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -99011,11 +113743,9 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( #endif ); if( rc==SQLITE_DENY ){ - if( db->nDb>2 || iDb!=0 ){ - sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol); - }else{ - sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol); - } + char *z = sqlite3_mprintf("%s.%s", zTab, zCol); + if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z); + sqlite3ErrorMsg(pParse, "access to %z is prohibited", z); pParse->rc = SQLITE_AUTH; }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){ sqliteAuthBadReturnCode(pParse); @@ -99025,10 +113755,10 @@ SQLITE_PRIVATE int sqlite3AuthReadCol( /* ** The pExpr should be a TK_COLUMN expression. The table referred to -** is in pTabList or else it is the NEW or OLD table of a trigger. +** is in pTabList or else it is the NEW or OLD table of a trigger. ** Check to see if it is OK to read this particular column. ** -** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN +** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN ** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, ** then generate an error. */ @@ -99038,14 +113768,15 @@ SQLITE_PRIVATE void sqlite3AuthRead( Schema *pSchema, /* The schema of the expression */ SrcList *pTabList /* All table that pExpr might refer to */ ){ - sqlite3 *db = pParse->db; Table *pTab = 0; /* The table being read */ const char *zCol; /* Name of the column of the table */ int iSrc; /* Index in pTabList->a[] of table being read */ int iDb; /* The index of the database the expression refers to */ int iCol; /* Index of column in table */ - if( db->xAuth==0 ) return; + assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); + assert( !IN_RENAME_OBJECT ); + assert( pParse->db->xAuth!=0 ); iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ /* An attempt to read a column out of a subquery or other @@ -99053,12 +113784,11 @@ SQLITE_PRIVATE void sqlite3AuthRead( return; } - assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); if( pExpr->op==TK_TRIGGER ){ pTab = pParse->pTriggerTab; }else{ assert( pTabList ); - for(iSrc=0; ALWAYS(iSrcnSrc); iSrc++){ + for(iSrc=0; iSrcnSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ pTab = pTabList->a[iSrc].pTab; break; @@ -99066,18 +113796,18 @@ SQLITE_PRIVATE void sqlite3AuthRead( } } iCol = pExpr->iColumn; - if( NEVER(pTab==0) ) return; + if( pTab==0 ) return; if( iCol>=0 ){ assert( iColnCol ); - zCol = pTab->aCol[iCol].zName; + zCol = pTab->aCol[iCol].zCnName; }else if( pTab->iPKey>=0 ){ assert( pTab->iPKeynCol ); - zCol = pTab->aCol[pTab->iPKey].zName; + zCol = pTab->aCol[pTab->iPKey].zCnName; }else{ zCol = "ROWID"; } - assert( iDb>=0 && iDbnDb ); + assert( iDb>=0 && iDbdb->nDb ); if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){ pExpr->op = TK_NULL; } @@ -99102,13 +113832,22 @@ SQLITE_PRIVATE int sqlite3AuthCheck( /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ - if( db->init.busy || IN_DECLARE_VTAB ){ + assert( !IN_RENAME_OBJECT || db->xAuth==0 ); + if( db->xAuth==0 || db->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } - if( db->xAuth==0 ){ - return SQLITE_OK; - } + /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the + ** callback are either NULL pointers or zero-terminated strings that + ** contain additional details about the action to be authorized. + ** + ** The following testcase() macros show that any of the 3rd through 6th + ** parameters can be either NULL or a string. */ + testcase( zArg1==0 ); + testcase( zArg2==0 ); + testcase( zArg3==0 ); + testcase( pParse->zAuthContext==0 ); + rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser @@ -99131,7 +113870,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck( */ SQLITE_PRIVATE void sqlite3AuthContextPush( Parse *pParse, - AuthContext *pContext, + AuthContext *pContext, const char *zContext ){ assert( pParse ); @@ -99188,13 +113927,13 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){ */ struct TableLock { int iDb; /* The database containing the table to be locked */ - int iTab; /* The root page of the table to be locked */ + Pgno iTab; /* The root page of the table to be locked */ u8 isWriteLock; /* True for write lock. False for a read lock */ const char *zLockName; /* Name of the table */ }; /* -** Record the fact that we want to lock a table at run-time. +** Record the fact that we want to lock a table at run-time. ** ** The table to be locked has root page iTab and is found in database iDb. ** A read or a write lock can be taken depending on isWritelock. @@ -99203,21 +113942,20 @@ struct TableLock { ** code to make the lock occur is generated by a later call to ** codeTableLocks() which occurs during sqlite3FinishCoding(). */ -SQLITE_PRIVATE void sqlite3TableLock( +static SQLITE_NOINLINE void lockTable( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ - int iTab, /* Root page number of the table to be locked */ + Pgno iTab, /* Root page number of the table to be locked */ u8 isWriteLock, /* True for a write lock */ const char *zName /* Name of the table to be locked */ ){ - Parse *pToplevel = sqlite3ParseToplevel(pParse); + Parse *pToplevel; int i; int nBytes; TableLock *p; assert( iDb>=0 ); - if( iDb==1 ) return; - if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; + pToplevel = sqlite3ParseToplevel(pParse); for(i=0; inTableLock; i++){ p = &pToplevel->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ @@ -99240,6 +113978,17 @@ SQLITE_PRIVATE void sqlite3TableLock( sqlite3OomFault(pToplevel->db); } } +SQLITE_PRIVATE void sqlite3TableLock( + Parse *pParse, /* Parsing context */ + int iDb, /* Index of the database containing the table to lock */ + Pgno iTab, /* Root page number of the table to be locked */ + u8 isWriteLock, /* True for a write lock */ + const char *zName /* Name of the table to be locked */ +){ + if( iDb==1 ) return; + if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; + lockTable(pParse, iDb, iTab, isWriteLock, zName); +} /* ** Code an OP_TableLock instruction for each table locked by the @@ -99247,10 +113996,8 @@ SQLITE_PRIVATE void sqlite3TableLock( */ static void codeTableLocks(Parse *pParse){ int i; - Vdbe *pVdbe; - - pVdbe = sqlite3GetVdbe(pParse); - assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */ + Vdbe *pVdbe = pParse->pVdbe; + assert( pVdbe!=0 ); for(i=0; inTableLock; i++){ TableLock *p = &pParse->aTableLock[i]; @@ -99292,19 +114039,52 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ assert( pParse->pToplevel==0 ); db = pParse->db; + assert( db->pParse==pParse ); if( pParse->nested ) return; - if( db->mallocFailed || pParse->nErr ){ - if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; + if( pParse->nErr ){ + if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM; return; } + assert( db->mallocFailed==0 ); /* Begin by generating some termination code at the end of the ** vdbe program */ - v = sqlite3GetVdbe(pParse); - assert( !pParse->isMultiWrite + v = pParse->pVdbe; + if( v==0 ){ + if( db->init.busy ){ + pParse->rc = SQLITE_DONE; + return; + } + v = sqlite3GetVdbe(pParse); + if( v==0 ) pParse->rc = SQLITE_ERROR; + } + assert( !pParse->isMultiWrite || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ + if( pParse->bReturning ){ + Returning *pReturning = pParse->u1.pReturning; + int addrRewind; + int i; + int reg; + + if( NEVER(pReturning->nRetCol==0) ){ + assert( CORRUPT_DB ); + }else{ + sqlite3VdbeAddOp0(v, OP_FkCheck); + addrRewind = + sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur); + VdbeCoverage(v); + reg = pReturning->iRetReg; + for(i=0; inRetCol; i++){ + sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i); + } + sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i); + sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrRewind); + } + } sqlite3VdbeAddOp0(v, OP_Halt); #if SQLITE_USER_AUTHENTICATION @@ -99324,7 +114104,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ ** transaction on each used database and to verify the schema cookie ** on each used database. */ - if( db->mallocFailed==0 + if( db->mallocFailed==0 && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr) ){ int iDb, i; @@ -99354,8 +114134,8 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ pParse->nVtabLock = 0; #endif - /* Once all the cookies have been verified and transactions opened, - ** obtain the required table-locks. This is a no-op unless the + /* Once all the cookies have been verified and transactions opened, + ** obtain the required table-locks. This is a no-op unless the ** shared-cache feature is enabled. */ codeTableLocks(pParse); @@ -99364,12 +114144,30 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ */ sqlite3AutoincrementBegin(pParse); - /* Code constant expressions that where factored out of inner loops */ + /* Code constant expressions that where factored out of inner loops. + ** + ** The pConstExpr list might also contain expressions that we simply + ** want to keep around until the Parse object is deleted. Such + ** expressions have iConstExprReg==0. Do not generate code for + ** those expressions, of course. + */ if( pParse->pConstExpr ){ ExprList *pEL = pParse->pConstExpr; pParse->okConstFactor = 0; for(i=0; inExpr; i++){ - sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); + int iReg = pEL->a[i].u.iConstExprReg; + if( iReg>0 ){ + sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg); + } + } + } + + if( pParse->bReturning ){ + Returning *pRet = pParse->u1.pReturning; + if( NEVER(pRet->nRetCol==0) ){ + assert( CORRUPT_DB ); + }else{ + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol); } } @@ -99378,14 +114176,14 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ } } - /* Get the VDBE program ready for execution */ - if( v && pParse->nErr==0 && !db->mallocFailed ){ - assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ + assert( v!=0 || pParse->nErr ); + assert( db->mallocFailed==0 || pParse->nErr ); + if( pParse->nErr==0 ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ - if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; + assert( pParse->pAinc==0 || pParse->nTab>0 ); sqlite3VdbeMakeReady(v, pParse); pParse->rc = SQLITE_DONE; }else{ @@ -99396,20 +114194,21 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){ /* ** Run the parser and code generator recursively in order to generate ** code for the SQL statement given onto the end of the pParse context -** currently under construction. When the parser is run recursively -** this way, the final OP_Halt is not appended and other initialization -** and finalization steps are omitted because those are handling by the -** outermost parser. +** currently under construction. Notes: +** +** * The final OP_Halt is not appended and other initialization +** and finalization steps are omitted because those are handling by the +** outermost parser. ** -** Not everything is nestable. This facility is designed to permit -** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use -** care if you decide to try to use this routine for some other purposes. +** * Built-in SQL functions always take precedence over application-defined +** SQL functions. In other words, it is not possible to override a +** built-in function. */ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ va_list ap; char *zSql; - char *zErrMsg = 0; sqlite3 *db = pParse->db; + u32 savedDbFlags = db->mDbFlags; char saveBuf[PARSE_TAIL_SZ]; if( pParse->nErr ) return; @@ -99418,13 +114217,21 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ zSql = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); if( zSql==0 ){ - return; /* A malloc must have failed */ + /* This can result either from an OOM or because the formatted string + ** exceeds SQLITE_LIMIT_LENGTH. In the latter case, we need to set + ** an error */ + if( !db->mallocFailed ) pParse->rc = SQLITE_TOOBIG; + pParse->nErr++; + return; } pParse->nested++; memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); - sqlite3RunParser(pParse, zSql, &zErrMsg); - sqlite3DbFree(db, zErrMsg); + db->mDbFlags |= DBFLAG_PreferBuiltin; + sqlite3RunParser(pParse, zSql); + sqlite3DbFree(db, pParse->zErrMsg); + pParse->zErrMsg = 0; + db->mDbFlags = savedDbFlags; sqlite3DbFree(db, zSql); memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); pParse->nested--; @@ -99465,22 +114272,59 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha return 0; } #endif - while(1){ - for(i=OMIT_TEMPDB; inDb; i++){ - int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){ - assert( sqlite3SchemaMutexHeld(db, j, 0) ); - p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); - if( p ) return p; + if( zDatabase ){ + for(i=0; inDb; i++){ + if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break; + } + if( i>=db->nDb ){ + /* No match against the official names. But always match "main" + ** to schema 0 as a legacy fallback. */ + if( sqlite3StrICmp(zDatabase,"main")==0 ){ + i = 0; + }else{ + return 0; + } + } + p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); + if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ + if( i==1 ){ + if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 + || sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 + || sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 + ){ + p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, + LEGACY_TEMP_SCHEMA_TABLE); + } + }else{ + if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ + p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, + LEGACY_SCHEMA_TABLE); + } + } + } + }else{ + /* Match against TEMP first */ + p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName); + if( p ) return p; + /* The main database is second */ + p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName); + if( p ) return p; + /* Attached databases are in order of attachment */ + for(i=2; inDb; i++){ + assert( sqlite3SchemaMutexHeld(db, i, 0) ); + p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName); + if( p ) break; + } + if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ + if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){ + p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, LEGACY_SCHEMA_TABLE); + }else if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){ + p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, + LEGACY_TEMP_SCHEMA_TABLE); } } - /* Not found. If the name we were looking for was temp.sqlite_master - ** then change the name to sqlite_temp_master and try again. */ - if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break; - if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break; - zName = TEMP_MASTER_NAME; } - return 0; + return p; } /* @@ -99500,38 +114344,48 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( const char *zDbase /* Name of the database. Might be NULL */ ){ Table *p; + sqlite3 *db = pParse->db; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ - if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ + if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 + && SQLITE_OK!=sqlite3ReadSchema(pParse) + ){ return 0; } - p = sqlite3FindTable(pParse->db, zName, zDbase); + p = sqlite3FindTable(db, zName, zDbase); if( p==0 ){ - const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3FindDbName(pParse->db, zDbase)<1 ){ - /* If zName is the not the name of a table in the schema created using - ** CREATE, then check to see if it is the name of an virtual table that - ** can be an eponymous virtual table. */ - Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); + /* If zName is the not the name of a table in the schema created using + ** CREATE, then check to see if it is the name of an virtual table that + ** can be an eponymous virtual table. */ + if( pParse->disableVtab==0 && db->init.busy==0 ){ + Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName); if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){ - pMod = sqlite3PragmaVtabRegister(pParse->db, zName); + pMod = sqlite3PragmaVtabRegister(db, zName); } if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ + testcase( pMod->pEpoTab==0 ); return pMod->pEpoTab; } } #endif - if( (flags & LOCATE_NOERR)==0 ){ - if( zDbase ){ - sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); - }else{ - sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); - } - pParse->checkSchema = 1; + if( flags & LOCATE_NOERR ) return 0; + pParse->checkSchema = 1; + }else if( IsVirtual(p) && pParse->disableVtab ){ + p = 0; + } + + if( p==0 ){ + const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; + if( zDbase ){ + sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); + }else{ + sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } + }else{ + assert( HasRowid(p) || p->iPKey<0 ); } return p; @@ -99547,9 +114401,9 @@ SQLITE_PRIVATE Table *sqlite3LocateTable( ** sqlite3FixSrcList() for details. */ SQLITE_PRIVATE Table *sqlite3LocateTableItem( - Parse *pParse, + Parse *pParse, u32 flags, - struct SrcList_item *p + SrcItem *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); @@ -99563,7 +114417,23 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem( } /* -** Locate the in-memory structure that describes +** Return the preferred table name for system tables. Translate legacy +** names into the new preferred names, as appropriate. +*/ +SQLITE_PRIVATE const char *sqlite3PreferredTableName(const char *zName){ + if( sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){ + if( sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){ + return PREFERRED_SCHEMA_TABLE; + } + if( sqlite3StrICmp(zName+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){ + return PREFERRED_TEMP_SCHEMA_TABLE; + } + } + return zName; +} + +/* +** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. ** Return NULL if not found. @@ -99583,7 +114453,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ Schema *pSchema = db->aDb[j].pSchema; assert( pSchema ); - if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue; + if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); p = sqlite3HashFind(&pSchema->idxHash, zName); if( p ) break; @@ -99594,7 +114464,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha /* ** Reclaim the memory used by an index */ -static void freeIndex(sqlite3 *db, Index *p){ +SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif @@ -99602,7 +114472,7 @@ static void freeIndex(sqlite3 *db, Index *p){ sqlite3ExprListDelete(db, p->aColExpr); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl); -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 sqlite3_free(p->aiRowEst); #endif sqlite3DbFree(db, p); @@ -99634,9 +114504,9 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char p->pNext = pIndex->pNext; } } - freeIndex(db, pIndex); + sqlite3FreeIndex(db, pIndex); } - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } /* @@ -99671,28 +114541,27 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){ /* ** Reset the schema for the database at index iDb. Also reset the -** TEMP schema. +** TEMP schema. The reset is deferred if db->nSchemaLock is not zero. +** Deferred resets may be run by calling with iDb<0. */ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){ - Db *pDb; + int i; assert( iDbnDb ); - /* Case 1: Reset the single schema identified by iDb */ - pDb = &db->aDb[iDb]; - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); + if( iDb>=0 ){ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + DbSetProperty(db, iDb, DB_ResetWanted); + DbSetProperty(db, 1, DB_ResetWanted); + db->mDbFlags &= ~DBFLAG_SchemaKnownOk; + } - /* If any database other than TEMP is reset, then also reset TEMP - ** since TEMP might be holding triggers that reference tables in the - ** other database. - */ - if( iDb!=1 ){ - pDb = &db->aDb[1]; - assert( pDb->pSchema!=0 ); - sqlite3SchemaClear(pDb->pSchema); + if( db->nSchemaLock==0 ){ + for(i=0; inDb; i++){ + if( DbHasProperty(db, i, DB_ResetWanted) ){ + sqlite3SchemaClear(db->aDb[i].pSchema); + } + } } - return; } /* @@ -99705,20 +114574,104 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){ for(i=0; inDb; i++){ Db *pDb = &db->aDb[i]; if( pDb->pSchema ){ - sqlite3SchemaClear(pDb->pSchema); + if( db->nSchemaLock==0 ){ + sqlite3SchemaClear(pDb->pSchema); + }else{ + DbSetProperty(db, i, DB_ResetWanted); + } } } - db->flags &= ~SQLITE_InternChanges; + db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk); sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); - sqlite3CollapseDatabaseArray(db); + if( db->nSchemaLock==0 ){ + sqlite3CollapseDatabaseArray(db); + } } /* ** This routine is called when a commit occurs. */ SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){ - db->flags &= ~SQLITE_InternChanges; + db->mDbFlags &= ~DBFLAG_SchemaChange; +} + +/* +** Set the expression associated with a column. This is usually +** the DEFAULT value, but might also be the expression that computes +** the value for a generated column. +*/ +SQLITE_PRIVATE void sqlite3ColumnSetExpr( + Parse *pParse, /* Parsing context */ + Table *pTab, /* The table containing the column */ + Column *pCol, /* The column to receive the new DEFAULT expression */ + Expr *pExpr /* The new default expression */ +){ + ExprList *pList; + assert( IsOrdinaryTable(pTab) ); + pList = pTab->u.tab.pDfltList; + if( pCol->iDflt==0 + || NEVER(pList==0) + || NEVER(pList->nExpriDflt) + ){ + pCol->iDflt = pList==0 ? 1 : pList->nExpr+1; + pTab->u.tab.pDfltList = sqlite3ExprListAppend(pParse, pList, pExpr); + }else{ + sqlite3ExprDelete(pParse->db, pList->a[pCol->iDflt-1].pExpr); + pList->a[pCol->iDflt-1].pExpr = pExpr; + } +} + +/* +** Return the expression associated with a column. The expression might be +** the DEFAULT clause or the AS clause of a generated column. +** Return NULL if the column has no associated expression. +*/ +SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ + if( pCol->iDflt==0 ) return 0; + if( NEVER(!IsOrdinaryTable(pTab)) ) return 0; + if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; + if( NEVER(pTab->u.tab.pDfltList->nExpriDflt) ) return 0; + return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; +} + +/* +** Set the collating sequence name for a column. +*/ +SQLITE_PRIVATE void sqlite3ColumnSetColl( + sqlite3 *db, + Column *pCol, + const char *zColl +){ + i64 nColl; + i64 n; + char *zNew; + assert( zColl!=0 ); + n = sqlite3Strlen30(pCol->zCnName) + 1; + if( pCol->colFlags & COLFLAG_HASTYPE ){ + n += sqlite3Strlen30(pCol->zCnName+n) + 1; + } + nColl = sqlite3Strlen30(zColl) + 1; + zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n); + if( zNew ){ + pCol->zCnName = zNew; + memcpy(pCol->zCnName + n, zColl, nColl); + pCol->colFlags |= COLFLAG_HASCOLL; + } +} + +/* +** Return the collating squence name for a column +*/ +SQLITE_PRIVATE const char *sqlite3ColumnColl(Column *pCol){ + const char *z; + if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0; + z = pCol->zCnName; + while( *z ){ z++; } + if( pCol->colFlags & COLFLAG_HASTYPE ){ + do{ z++; }while( *z ); + } + return z+1; } /* @@ -99731,11 +114684,20 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; inCol; i++, pCol++){ - sqlite3DbFree(db, pCol->zName); - sqlite3ExprDelete(db, pCol->pDflt); - sqlite3DbFree(db, pCol->zColl); + assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) ); + sqlite3DbFree(db, pCol->zCnName); } sqlite3DbFree(db, pTable->aCol); + if( IsOrdinaryTable(pTable) ){ + sqlite3ExprListDelete(db, pTable->u.tab.pDfltList); + } + if( db==0 || db->pnBytesFreed==0 ){ + pTable->aCol = 0; + pTable->nCol = 0; + if( IsOrdinaryTable(pTable) ){ + pTable->u.tab.pDfltList = 0; + } + } } } @@ -99745,10 +114707,10 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ ** ** This routine just deletes the data structure. It does not unlink ** the table data structure from the hash table. But it does destroy -** memory structures of the indices and foreign keys associated with +** memory structures of the indices and foreign keys associated with ** the table. ** -** The db parameter is optional. It is needed if the Table object +** The db parameter is optional. It is needed if the Table object ** contains lookaside memory. (Table objects in the schema do not use ** lookaside memory, but some ephemeral Table objects do.) Or the ** db parameter can be used with db->pnBytesFreed to measure the memory @@ -99756,13 +114718,20 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ */ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; - TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */ +#ifdef SQLITE_DEBUG /* Record the number of outstanding lookaside allocations in schema Tables - ** prior to doing any free() operations. Since schema Tables do not use - ** lookaside, this number should not change. */ - TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ? - db->lookaside.nOut : 0 ); + ** prior to doing any free() operations. Since schema Tables do not use + ** lookaside, this number should not change. + ** + ** If malloc has already failed, it may be that it failed while allocating + ** a Table object that was going to be marked ephemeral. So do not check + ** that no lookaside memory is used in this case either. */ + int nLookaside = 0; + if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){ + nLookaside = sqlite3LookasideUsed(db, 0); + } +#endif /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ @@ -99770,33 +114739,39 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ assert( pIndex->pSchema==pTable->pSchema || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){ - char *zName = pIndex->zName; + char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); } - freeIndex(db, pIndex); + sqlite3FreeIndex(db, pIndex); } - /* Delete any foreign keys attached to this table. */ - sqlite3FkDelete(db, pTable); + if( IsOrdinaryTable(pTable) ){ + sqlite3FkDelete(db, pTable); + } +#ifndef SQLITE_OMIT_VIRTUAL_TABLE + else if( IsVirtual(pTable) ){ + sqlite3VtabClear(db, pTable); + } +#endif + else{ + assert( IsView(pTable) ); + sqlite3SelectDelete(db, pTable->u.view.pSelect); + } /* Delete the Table structure itself. */ sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); - sqlite3SelectDelete(db, pTable->pSelect); sqlite3ExprListDelete(db, pTable->pCheck); -#ifndef SQLITE_OMIT_VIRTUALTABLE - sqlite3VtabClear(db, pTable); -#endif sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ - assert( nLookaside==0 || nLookaside==db->lookaside.nOut ); + assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) ); } SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ /* Do not delete the table until the reference count reaches zero. */ @@ -99822,7 +114797,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char pDb = &db->aDb[iDb]; p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0); sqlite3DeleteTable(db, p); - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } /* @@ -99838,10 +114813,10 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char ** are not \000 terminated and are not persistent. The returned string ** is \000 terminated and is persistent. */ -SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ +SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, const Token *pName){ char *zName; if( pName ){ - zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n); + zName = sqlite3DbStrNDup(db, (const char*)pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; @@ -99850,13 +114825,13 @@ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){ } /* -** Open the sqlite_master table stored in database number iDb for +** Open the sqlite_schema table stored in database number iDb for ** writing. The table is opened using cursor 0. */ -SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){ +SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *p, int iDb){ Vdbe *v = sqlite3GetVdbe(p); - sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME); - sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5); + sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, LEGACY_SCHEMA_TABLE); + sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5); if( p->nTab==0 ){ p->nTab = 1; } @@ -99885,7 +114860,7 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){ /* ** The token *pName contains the name of a database (either "main" or ** "temp" or the name of an attached db). This routine returns the -** index of the named database in db->aDb[], or -1 if the named db +** index of the named database in db->aDb[], or -1 if the named db ** does not exist. */ SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){ @@ -99901,7 +114876,7 @@ SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){ ** pName1 and pName2. If the table name was fully qualified, for example: ** ** CREATE TABLE xxx.yyy (...); -** +** ** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if ** the table name is not fully qualified, i.e.: ** @@ -99935,26 +114910,70 @@ SQLITE_PRIVATE int sqlite3TwoPartName( return -1; } }else{ - assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0); + assert( db->init.iDb==0 || db->init.busy || IN_SPECIAL_PARSE + || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } return iDb; } +/* +** True if PRAGMA writable_schema is ON +*/ +SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3 *db){ + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==0 ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + SQLITE_WriteSchema ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + SQLITE_Defensive ); + testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))== + (SQLITE_WriteSchema|SQLITE_Defensive) ); + return (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==SQLITE_WriteSchema; +} + /* ** This routine is used to check if the UTF-8 string zName is a legal ** unqualified name for a new schema object (table, index, view or ** trigger). All names are legal except those that begin with the string ** "sqlite_" (in upper, lower or mixed case). This portion of the namespace ** is reserved for internal use. +** +** When parsing the sqlite_schema table, this routine also checks to +** make sure the "type", "name", and "tbl_name" columns are consistent +** with the SQL. */ -SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){ - if( !pParse->db->init.busy && pParse->nested==0 - && (pParse->db->flags & SQLITE_WriteSchema)==0 - && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ - sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); - return SQLITE_ERROR; +SQLITE_PRIVATE int sqlite3CheckObjectName( + Parse *pParse, /* Parsing context */ + const char *zName, /* Name of the object to check */ + const char *zType, /* Type of this object */ + const char *zTblName /* Parent table name for triggers and indexes */ +){ + sqlite3 *db = pParse->db; + if( sqlite3WritableSchema(db) + || db->init.imposterTable + || !sqlite3Config.bExtraSchemaChecks + ){ + /* Skip these error checks for writable_schema=ON */ + return SQLITE_OK; + } + if( db->init.busy ){ + if( sqlite3_stricmp(zType, db->init.azInit[0]) + || sqlite3_stricmp(zName, db->init.azInit[1]) + || sqlite3_stricmp(zTblName, db->init.azInit[2]) + ){ + sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */ + return SQLITE_ERROR; + } + }else{ + if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7)) + || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName)) + ){ + sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", + zName); + return SQLITE_ERROR; + } + } return SQLITE_OK; } @@ -99969,10 +114988,12 @@ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){ } /* -** Return the column of index pIdx that corresponds to table -** column iCol. Return -1 if not found. +** Convert an table column number into a index column number. That is, +** for the column iCol in the table (as defined by the CREATE TABLE statement) +** find the (first) offset of that column in index pIdx. Or return -1 +** if column iCol is not used in index pIdx. */ -SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ +SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ int i; for(i=0; inColumn; i++){ if( iCol==pIdx->aiColumn[i] ) return i; @@ -99980,6 +115001,101 @@ SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ return -1; } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* Convert a storage column number into a table column number. +** +** The storage column number (0,1,2,....) is the index of the value +** as it appears in the record on disk. The true column number +** is the index (0,1,2,...) of the column in the CREATE TABLE statement. +** +** The storage column number is less than the table column number if +** and only there are VIRTUAL columns to the left. +** +** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. +*/ +SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){ + if( pTab->tabFlags & TF_HasVirtual ){ + int i; + for(i=0; i<=iCol; i++){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++; + } + } + return iCol; +} +#endif + +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* Convert a table column number into a storage column number. +** +** The storage column number (0,1,2,....) is the index of the value +** as it appears in the record on disk. Or, if the input column is +** the N-th virtual column (zero-based) then the storage number is +** the number of non-virtual columns in the table plus N. +** +** The true column number is the index (0,1,2,...) of the column in +** the CREATE TABLE statement. +** +** If the input column is a VIRTUAL column, then it should not appear +** in storage. But the value sometimes is cached in registers that +** follow the range of registers used to construct storage. This +** avoids computing the same VIRTUAL column multiple times, and provides +** values for use by OP_Param opcodes in triggers. Hence, if the +** input column is a VIRTUAL table, put it after all the other columns. +** +** In the following, N means "normal column", S means STORED, and +** V means VIRTUAL. Suppose the CREATE TABLE has columns like this: +** +** CREATE TABLE ex(N,S,V,N,S,V,N,S,V); +** -- 0 1 2 3 4 5 6 7 8 +** +** Then the mapping from this function is as follows: +** +** INPUTS: 0 1 2 3 4 5 6 7 8 +** OUTPUTS: 0 1 6 2 3 7 4 5 8 +** +** So, in other words, this routine shifts all the virtual columns to +** the end. +** +** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and +** this routine is a no-op macro. If the pTab does not have any virtual +** columns, then this routine is no-op that always return iCol. If iCol +** is negative (indicating the ROWID column) then this routine return iCol. +*/ +SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ + int i; + i16 n; + assert( iColnCol ); + if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol; + for(i=0, n=0; iaCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++; + } + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + /* iCol is a virtual column itself */ + return pTab->nNVCol + i - n; + }else{ + /* iCol is a normal or stored column */ + return n; + } +} +#endif + +/* +** Insert a single OP_JournalMode query opcode in order to force the +** prepared statement to return false for sqlite3_stmt_readonly(). This +** is used by CREATE TABLE IF NOT EXISTS and similar if the table already +** exists, so that the prepared statement for CREATE TABLE IF NOT EXISTS +** will return false for sqlite3_stmt_readonly() even if that statement +** is a read-only no-op. +*/ +static void sqlite3ForceNotReadOnly(Parse *pParse){ + int iReg = ++pParse->nMem; + Vdbe *v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp3(v, OP_JournalMode, 0, iReg, PAGER_JOURNALMODE_QUERY); + sqlite3VdbeUsesBtree(v, 0); + } +} + /* ** Begin constructing a new table representation in memory. This is ** the first of several action routines that get called in response @@ -100013,7 +115129,7 @@ SQLITE_PRIVATE void sqlite3StartTable( Token *pName; /* Unqualified name of the table to create */ if( db->init.busy && db->init.newTnum==1 ){ - /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */ + /* Special case: Parsing the sqlite_schema or sqlite_temp_schema schema */ iDb = db->init.iDb; zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb)); pName = pName1; @@ -100022,17 +115138,20 @@ SQLITE_PRIVATE void sqlite3StartTable( iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName); if( iDb<0 ) return; if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){ - /* If creating a temp table, the name may not be qualified. Unless + /* If creating a temp table, the name may not be qualified. Unless ** the database name is "temp" anyway. */ sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); return; } if( !OMIT_TEMPDB && isTemp ) iDb = 1; zName = sqlite3NameFromToken(db, pName); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (void*)zName, pName); + } } pParse->sNameToken = *pName; if( zName==0 ) return; - if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + if( sqlite3CheckObjectName(pParse, zName, isView?"view":"table", zName) ){ goto begin_table_error; } if( db->init.iDb==1 ) isTemp = 1; @@ -100064,7 +115183,7 @@ SQLITE_PRIVATE void sqlite3StartTable( ** and types will be used, so there is no need to test for namespace ** collisions. */ - if( !IN_DECLARE_VTAB ){ + if( !IN_SPECIAL_PARSE ){ char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; @@ -100072,10 +115191,12 @@ SQLITE_PRIVATE void sqlite3StartTable( pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ if( !noErr ){ - sqlite3ErrorMsg(pParse, "table %T already exists", pName); + sqlite3ErrorMsg(pParse, "%s %T already exists", + (IsView(pTable)? "view" : "table"), pName); }else{ assert( !db->init.busy || CORRUPT_DB ); sqlite3CodeVerifySchema(pParse, iDb); + sqlite3ForceNotReadOnly(pParse); } goto begin_table_error; } @@ -100096,26 +115217,19 @@ SQLITE_PRIVATE void sqlite3StartTable( pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nTabRef = 1; +#ifdef SQLITE_DEFAULT_ROWEST + pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); +#else pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); +#endif assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; - /* If this is the magic sqlite_sequence table used by autoincrement, - ** then record a pointer to this table in the main database structure - ** so that INSERT can find the table easily. - */ -#ifndef SQLITE_OMIT_AUTOINCREMENT - if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ - assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - pTable->pSchema->pSeqTab = pTable; - } -#endif - /* Begin generating the code that will insert the table record into - ** the SQLITE_MASTER table. Note in particular that we must go ahead + ** the schema table. Note in particular that we must go ahead ** and allocate the record number for the table entry now. Before any ** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause - ** indices to be created and the table record must come before the + ** indices to be created and the table record must come before the ** indices. Hence, the record number for the table must be allocated ** now. */ @@ -100133,7 +115247,7 @@ SQLITE_PRIVATE void sqlite3StartTable( } #endif - /* If the file format and encoding in the database have not been set, + /* If the file format and encoding in the database have not been set, ** set them now. */ reg1 = pParse->regRowid = ++pParse->nMem; @@ -100148,7 +115262,7 @@ SQLITE_PRIVATE void sqlite3StartTable( sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db)); sqlite3VdbeJumpHere(v, addr1); - /* This just creates a place-holder record in the sqlite_master table. + /* This just creates a place-holder record in the sqlite_schema table. ** The record created does not contain anything yet. It will be replaced ** by the real entry in code generated at sqlite3EndTable(). ** @@ -100163,9 +115277,11 @@ SQLITE_PRIVATE void sqlite3StartTable( }else #endif { - pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2); + assert( !pParse->bReturning ); + pParse->u1.addrCrTab = + sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } - sqlite3OpenMasterTable(pParse, iDb); + sqlite3OpenSchemaTable(pParse, iDb); sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1); sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC); sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1); @@ -100178,6 +115294,7 @@ SQLITE_PRIVATE void sqlite3StartTable( /* If an error occurs, we jump here */ begin_table_error: + pParse->checkSchema = 1; sqlite3DbFree(db, zName); return; } @@ -100187,14 +115304,88 @@ SQLITE_PRIVATE void sqlite3StartTable( */ #if SQLITE_ENABLE_HIDDEN_COLUMNS SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ - if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){ + if( sqlite3_strnicmp(pCol->zCnName, "__hidden__", 10)==0 ){ pCol->colFlags |= COLFLAG_HIDDEN; + if( pTab ) pTab->tabFlags |= TF_HasHidden; }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ pTab->tabFlags |= TF_OOOHidden; } } #endif +/* +** Name of the special TEMP trigger used to implement RETURNING. The +** name begins with "sqlite_" so that it is guaranteed not to collide +** with any application-generated triggers. +*/ +#define RETURNING_TRIGGER_NAME "sqlite_returning" + +/* +** Clean up the data structures associated with the RETURNING clause. +*/ +static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ + Hash *pHash; + pHash = &(db->aDb[1].pSchema->trigHash); + sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0); + sqlite3ExprListDelete(db, pRet->pReturnEL); + sqlite3DbFree(db, pRet); +} + +/* +** Add the RETURNING clause to the parse currently underway. +** +** This routine creates a special TEMP trigger that will fire for each row +** of the DML statement. That TEMP trigger contains a single SELECT +** statement with a result set that is the argument of the RETURNING clause. +** The trigger has the Trigger.bReturning flag and an opcode of +** TK_RETURNING instead of TK_SELECT, so that the trigger code generator +** knows to handle it specially. The TEMP trigger is automatically +** removed at the end of the parse. +** +** When this routine is called, we do not yet know if the RETURNING clause +** is attached to a DELETE, INSERT, or UPDATE, so construct it as a +** RETURNING trigger instead. It will then be converted into the appropriate +** type on the first call to sqlite3TriggersExist(). +*/ +SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){ + Returning *pRet; + Hash *pHash; + sqlite3 *db = pParse->db; + if( pParse->pNewTrigger ){ + sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger"); + }else{ + assert( pParse->bReturning==0 ); + } + pParse->bReturning = 1; + pRet = sqlite3DbMallocZero(db, sizeof(*pRet)); + if( pRet==0 ){ + sqlite3ExprListDelete(db, pList); + return; + } + pParse->u1.pReturning = pRet; + pRet->pParse = pParse; + pRet->pReturnEL = pList; + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); + testcase( pParse->earlyCleanup ); + if( db->mallocFailed ) return; + pRet->retTrig.zName = RETURNING_TRIGGER_NAME; + pRet->retTrig.op = TK_RETURNING; + pRet->retTrig.tr_tm = TRIGGER_AFTER; + pRet->retTrig.bReturning = 1; + pRet->retTrig.pSchema = db->aDb[1].pSchema; + pRet->retTrig.pTabSchema = db->aDb[1].pSchema; + pRet->retTrig.step_list = &pRet->retTStep; + pRet->retTStep.op = TK_RETURNING; + pRet->retTStep.pTrig = &pRet->retTrig; + pRet->retTStep.pExprList = pList; + pHash = &(db->aDb[1].pSchema->trigHash); + assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr ); + if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig) + ==&pRet->retTrig ){ + sqlite3OomFault(db); + } +} /* ** Add a new column to the table currently being constructed. @@ -100204,60 +115395,110 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ ** first to get things going. Then this routine is called for each ** column. */ -SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ +SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){ Table *p; int i; char *z; char *zType; Column *pCol; sqlite3 *db = pParse->db; + u8 hName; + Column *aNew; + u8 eType = COLTYPE_CUSTOM; + u8 szEst = 1; + char affinity = SQLITE_AFF_BLOB; + if( (p = pParse->pNewTable)==0 ) return; -#if SQLITE_MAX_COLUMN if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } -#endif - z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); + if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName); + + /* Because keywords GENERATE ALWAYS can be converted into indentifiers + ** by the parser, we can sometimes end up with a typename that ends + ** with "generated always". Check for this case and omit the surplus + ** text. */ + if( sType.n>=16 + && sqlite3_strnicmp(sType.z+(sType.n-6),"always",6)==0 + ){ + sType.n -= 6; + while( ALWAYS(sType.n>0) && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; + if( sType.n>=9 + && sqlite3_strnicmp(sType.z+(sType.n-9),"generated",9)==0 + ){ + sType.n -= 9; + while( sType.n>0 && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--; + } + } + + /* Check for standard typenames. For standard typenames we will + ** set the Column.eType field rather than storing the typename after + ** the column name, in order to save space. */ + if( sType.n>=3 ){ + sqlite3DequoteToken(&sType); + for(i=0; i0) ); if( z==0 ) return; - memcpy(z, pName->z, pName->n); - z[pName->n] = 0; + if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, &sName); + memcpy(z, sName.z, sName.n); + z[sName.n] = 0; sqlite3Dequote(z); + hName = sqlite3StrIHash(z); for(i=0; inCol; i++){ - if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ + if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); return; } } - if( (p->nCol & 0x7)==0 ){ - Column *aNew; - aNew = sqlite3DbRealloc(db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0])); - if( aNew==0 ){ - sqlite3DbFree(db, z); - return; - } - p->aCol = aNew; + aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0])); + if( aNew==0 ){ + sqlite3DbFree(db, z); + return; } + p->aCol = aNew; pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); - pCol->zName = z; + pCol->zCnName = z; + pCol->hName = hName; sqlite3ColumnPropertiesFromName(p, pCol); - - if( pType->n==0 ){ + + if( sType.n==0 ){ /* If there is no type specified, columns have the default affinity - ** 'BLOB'. */ - pCol->affinity = SQLITE_AFF_BLOB; - pCol->szEst = 1; + ** 'BLOB' with a default size of 4 bytes. */ + pCol->affinity = affinity; + pCol->eCType = eType; + pCol->szEst = szEst; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( affinity==SQLITE_AFF_BLOB ){ + if( 4>=sqlite3GlobalConfig.szSorterRef ){ + pCol->colFlags |= COLFLAG_SORTERREF; + } + } +#endif }else{ zType = z + sqlite3Strlen30(z) + 1; - memcpy(zType, pType->z, pType->n); - zType[pType->n] = 0; + memcpy(zType, sType.z, sType.n); + zType[sType.n] = 0; sqlite3Dequote(zType); - pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst); + pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } p->nCol++; + p->nNVCol++; pParse->constraintName.n = 0; } @@ -100269,20 +115510,35 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ */ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){ Table *p; + Column *pCol; p = pParse->pNewTable; if( p==0 || NEVER(p->nCol<1) ) return; - p->aCol[p->nCol-1].notNull = (u8)onError; + pCol = &p->aCol[p->nCol-1]; + pCol->notNull = (u8)onError; + p->tabFlags |= TF_HasNotNull; + + /* Set the uniqNotNull flag on any UNIQUE or PK indexes already created + ** on this column. */ + if( pCol->colFlags & COLFLAG_UNIQUE ){ + Index *pIdx; + for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ + assert( pIdx->nKeyCol==1 && pIdx->onError!=OE_None ); + if( pIdx->aiColumn[0]==p->nCol-1 ){ + pIdx->uniqNotNull = 1; + } + } + } } /* ** Scan the column type name zType (length nType) and return the ** associated affinity type. ** -** This routine does a case-independent search of zType for the +** This routine does a case-independent search of zType for the ** substrings in the following table. If one of the substrings is ** found, the corresponding affinity is returned. If zType contains -** more than one of the substrings, entries toward the top of -** the table take priority. For example, if zType is 'BLOBINT', +** more than one of the substrings, entries toward the top of +** the table take priority. For example, if zType is 'BLOBINT', ** SQLITE_AFF_INTEGER is returned. ** ** Substring | Affinity @@ -100299,7 +115555,7 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){ ** If none of the substrings in the above table are found, ** SQLITE_AFF_NUMERIC is returned. */ -SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ +SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, Column *pCol){ u32 h = 0; char aff = SQLITE_AFF_NUMERIC; const char *zChar = 0; @@ -100336,27 +115592,32 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ } } - /* If pszEst is not NULL, store an estimate of the field size. The + /* If pCol is not NULL, store an estimate of the field size. The ** estimate is scaled so that the size of an integer is 1. */ - if( pszEst ){ - *pszEst = 1; /* default size is approx 4 bytes */ + if( pCol ){ + int v = 0; /* default size is approx 4 bytes */ if( aff r=(k/4+1) */ sqlite3GetInt32(zChar, &v); - v = v/4 + 1; - if( v>255 ) v = 255; - *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */ break; } zChar++; } }else{ - *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/ + v = 16; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/ } } +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( v>=sqlite3GlobalConfig.szSorterRef ){ + pCol->colFlags |= COLFLAG_SORTERREF; + } +#endif + v = v/4 + 1; + if( v>255 ) v = 255; + pCol->szEst = v; } return aff; } @@ -100371,39 +115632,52 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){ ** This routine is called by the parser while in the middle of ** parsing a CREATE TABLE statement. */ -SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){ +SQLITE_PRIVATE void sqlite3AddDefaultValue( + Parse *pParse, /* Parsing context */ + Expr *pExpr, /* The parsed expression of the default value */ + const char *zStart, /* Start of the default value text */ + const char *zEnd /* First character past end of defaut value text */ +){ Table *p; Column *pCol; sqlite3 *db = pParse->db; p = pParse->pNewTable; if( p!=0 ){ + int isInit = db->init.busy && db->init.iDb!=1; pCol = &(p->aCol[p->nCol-1]); - if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){ + if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", - pCol->zName); + pCol->zCnName); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + }else if( pCol->colFlags & COLFLAG_GENERATED ){ + testcase( pCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pCol->colFlags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column"); +#endif }else{ /* A copy of pExpr is used instead of the original, as pExpr contains - ** tokens that point to volatile memory. The 'span' of the expression - ** is required by pragma table_info. + ** tokens that point to volatile memory. */ - Expr x; - sqlite3ExprDelete(db, pCol->pDflt); + Expr x, *pDfltExpr; memset(&x, 0, sizeof(x)); x.op = TK_SPAN; - x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart, - (int)(pSpan->zEnd - pSpan->zStart)); - x.pLeft = pSpan->pExpr; + x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); + x.pLeft = pExpr; x.flags = EP_Skip; - pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); + pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); + sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr); } } - sqlite3ExprDelete(db, pSpan->pExpr); + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprUnmap(pParse, pExpr); + } + sqlite3ExprDelete(db, pExpr); } /* ** Backwards Compatibility Hack: -** +** ** Historical versions of SQLite accepted strings as column names in ** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example: ** @@ -100414,7 +115688,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){ ** accept it. This routine does the necessary conversion. It converts ** the expression given in its argument from a TK_STRING into a TK_ID ** if the expression is just a TK_STRING with an optional COLLATE clause. -** If the epxression is anything other than TK_STRING, the expression is +** If the expression is anything other than TK_STRING, the expression is ** unchanged. */ static void sqlite3StringToId(Expr *p){ @@ -100426,7 +115700,22 @@ static void sqlite3StringToId(Expr *p){ } /* -** Designate the PRIMARY KEY for the table. pList is a list of names +** Tag the given column as being part of the PRIMARY KEY +*/ +static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){ + pCol->colFlags |= COLFLAG_PRIMKEY; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pCol->colFlags & COLFLAG_GENERATED ){ + testcase( pCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pCol->colFlags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, + "generated columns cannot be part of the PRIMARY KEY"); + } +#endif +} + +/* +** Designate the PRIMARY KEY for the table. pList is a list of names ** of columns that form the primary key. If pList is NULL, then the ** most recently added column of the table is the primary key. ** @@ -100456,7 +115745,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( int nTerm; if( pTab==0 ) goto primary_key_exit; if( pTab->tabFlags & TF_HasPrimaryKey ){ - sqlite3ErrorMsg(pParse, + sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } @@ -100464,7 +115753,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( if( pList==0 ){ iCol = pTab->nCol - 1; pCol = &pTab->aCol[iCol]; - pCol->colFlags |= COLFLAG_PRIMKEY; + makeColumnPartOfPrimaryKey(pParse, pCol); nTerm = 1; }else{ nTerm = pList->nExpr; @@ -100473,11 +115762,13 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( assert( pCExpr!=0 ); sqlite3StringToId(pCExpr); if( pCExpr->op==TK_ID ){ - const char *zCName = pCExpr->u.zToken; + const char *zCName; + assert( !ExprHasProperty(pCExpr, EP_IntValue) ); + zCName = pCExpr->u.zToken; for(iCol=0; iColnCol; iCol++){ - if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ + if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){ pCol = &pTab->aCol[iCol]; - pCol->colFlags |= COLFLAG_PRIMKEY; + makeColumnPartOfPrimaryKey(pParse, pCol); break; } } @@ -100486,14 +115777,19 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( } if( nTerm==1 && pCol - && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 + && pCol->eCType==COLTYPE_INTEGER && sortOrder!=SQLITE_SO_DESC ){ + if( IN_RENAME_OBJECT && pList ){ + Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr); + sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr); + } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); pTab->tabFlags |= autoInc*TF_Autoincrement; - if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; + if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags; + (void)sqlite3HasExplicitNulls(pParse, pList); }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " @@ -100514,8 +115810,10 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( ** Add a new CHECK constraint to the table currently under construction. */ SQLITE_PRIVATE void sqlite3AddCheckConstraint( - Parse *pParse, /* Parsing context */ - Expr *pCheckExpr /* The check expression */ + Parse *pParse, /* Parsing context */ + Expr *pCheckExpr, /* The check expression */ + const char *zStart, /* Opening "(" */ + const char *zEnd /* Closing ")" */ ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; @@ -100526,6 +115824,13 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint( pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); if( pParse->constraintName.n ){ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); + }else{ + Token t; + for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} + while( sqlite3Isspace(zEnd[-1]) ){ zEnd--; } + t.z = zStart; + t.n = (int)(zEnd - t.z); + sqlite3ExprListSetName(pParse, pTab->pCheck, &t, 1); } }else #endif @@ -100544,7 +115849,7 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){ char *zColl; /* Dequoted name of collation sequence */ sqlite3 *db; - if( (p = pParse->pNewTable)==0 ) return; + if( (p = pParse->pNewTable)==0 || IN_RENAME_OBJECT ) return; i = p->nCol-1; db = pParse->db; zColl = sqlite3NameFromToken(db, pToken); @@ -100552,9 +115857,8 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){ if( sqlite3LocateCollSeq(pParse, zColl) ){ Index *pIdx; - sqlite3DbFree(db, p->aCol[i].zColl); - p->aCol[i].zColl = zColl; - + sqlite3ColumnSetColl(db, &p->aCol[i], zColl); + /* If the column is declared as " PRIMARY KEY COLLATE ", ** then an index may have been created on this column before the ** collation type was added. Correct this if it is the case. @@ -100562,49 +115866,65 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nKeyCol==1 ); if( pIdx->aiColumn[0]==i ){ - pIdx->azColl[0] = p->aCol[i].zColl; + pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]); } } - }else{ - sqlite3DbFree(db, zColl); } + sqlite3DbFree(db, zColl); } -/* -** This function returns the collation sequence for database native text -** encoding identified by the string zName, length nName. -** -** If the requested collation sequence is not available, or not available -** in the database native encoding, the collation factory is invoked to -** request it. If the collation factory does not supply such a sequence, -** and the sequence is available in another text encoding, then that is -** returned instead. -** -** If no versions of the requested collations sequence are available, or -** another error occurs, NULL is returned and an error message written into -** pParse. -** -** This routine is a wrapper around sqlite3FindCollSeq(). This routine -** invokes the collation factory if the named collation cannot be found -** and generates an error message. -** -** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq() +/* Change the most recently parsed column to be a GENERATED ALWAYS AS +** column. */ -SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){ - sqlite3 *db = pParse->db; - u8 enc = ENC(db); - u8 initbusy = db->init.busy; - CollSeq *pColl; - - pColl = sqlite3FindCollSeq(db, enc, zName, initbusy); - if( !initbusy && (!pColl || !pColl->xCmp) ){ - pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName); +SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + u8 eType = COLFLAG_VIRTUAL; + Table *pTab = pParse->pNewTable; + Column *pCol; + if( pTab==0 ){ + /* generated column in an CREATE TABLE IF NOT EXISTS that already exists */ + goto generated_done; + } + pCol = &(pTab->aCol[pTab->nCol-1]); + if( IN_DECLARE_VTAB ){ + sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns"); + goto generated_done; + } + if( pCol->iDflt>0 ) goto generated_error; + if( pType ){ + if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){ + /* no-op */ + }else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){ + eType = COLFLAG_STORED; + }else{ + goto generated_error; + } + } + if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--; + pCol->colFlags |= eType; + assert( TF_HasVirtual==COLFLAG_VIRTUAL ); + assert( TF_HasStored==COLFLAG_STORED ); + pTab->tabFlags |= eType; + if( pCol->colFlags & COLFLAG_PRIMKEY ){ + makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */ } + sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr); + pExpr = 0; + goto generated_done; - return pColl; +generated_error: + sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", + pCol->zCnName); +generated_done: + sqlite3ExprDelete(pParse->db, pExpr); +#else + /* Throw and error for the GENERATED ALWAYS AS clause if the + ** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */ + sqlite3ErrorMsg(pParse, "generated columns not supported"); + sqlite3ExprDelete(pParse->db, pExpr); +#endif } - /* ** Generate code that will increment the schema cookie. ** @@ -100628,8 +115948,8 @@ SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){ sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, - db->aDb[iDb].pSchema->schema_cookie+1); + sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION, + (int)(1+(unsigned)db->aDb[iDb].pSchema->schema_cookie)); } /* @@ -100649,13 +115969,13 @@ static int identLength(const char *z){ } /* -** The first parameter is a pointer to an output buffer. The second +** The first parameter is a pointer to an output buffer. The second ** parameter is a pointer to an integer that contains the offset at ** which to write into the output buffer. This function copies the ** nul-terminated string pointed to by the third parameter, zSignedIdent, ** to the specified offset in the buffer and updates *pIdx to refer ** to the first byte after the last byte written before returning. -** +** ** If the string zSignedIdent consists entirely of alpha-numeric ** characters, does not begin with a digit and is not an SQL keyword, ** then it is copied to the output buffer exactly as it is. Otherwise, @@ -100696,10 +116016,10 @@ static char *createTableStmt(sqlite3 *db, Table *p){ Column *pCol; n = 0; for(pCol = p->aCol, i=0; inCol; i++, pCol++){ - n += identLength(pCol->zName) + 5; + n += identLength(pCol->zCnName) + 5; } n += identLength(p->zName); - if( n<50 ){ + if( n<50 ){ zSep = ""; zSep2 = ","; zEnd = ")"; @@ -100732,7 +116052,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){ sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; - identPut(zStmt, &k, pCol->zName); + identPut(zStmt, &k, pCol->zCnName); assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); testcase( pCol->affinity==SQLITE_AFF_BLOB ); @@ -100740,10 +116060,10 @@ static char *createTableStmt(sqlite3 *db, Table *p){ testcase( pCol->affinity==SQLITE_AFF_NUMERIC ); testcase( pCol->affinity==SQLITE_AFF_INTEGER ); testcase( pCol->affinity==SQLITE_AFF_REAL ); - + zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; len = sqlite3Strlen30(zType); - assert( pCol->affinity==SQLITE_AFF_BLOB + assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==sqlite3AffinityType(zType, 0) ); memcpy(&zStmt[k], zType, len); k += len; @@ -100762,12 +116082,15 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ int nByte; if( pIdx->nColumn>=N ) return SQLITE_OK; assert( pIdx->isResized==0 ); - nByte = (sizeof(char*) + sizeof(i16) + 1)*N; + nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N; zExtra = sqlite3DbMallocZero(db, nByte); if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); pIdx->azColl = (const char**)zExtra; zExtra += sizeof(char*)*N; + memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1)); + pIdx->aiRowLogEst = (LogEst*)zExtra; + zExtra += sizeof(LogEst)*N; memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn); pIdx->aiColumn = (i16*)zExtra; zExtra += sizeof(i16)*N; @@ -100807,13 +116130,87 @@ static void estimateIndexWidth(Index *pIdx){ pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } -/* Return true if value x is found any of the first nCol entries of aiCol[] +/* Return true if column number x is any of the first nCol entries of aiCol[]. +** This is used to determine if the column number x appears in any of the +** first nCol entries of an index. */ static int hasColumn(const i16 *aiCol, int nCol, int x){ - while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1; + while( nCol-- > 0 ){ + if( x==*(aiCol++) ){ + return 1; + } + } return 0; } +/* +** Return true if any of the first nKey entries of index pIdx exactly +** match the iCol-th entry of pPk. pPk is always a WITHOUT ROWID +** PRIMARY KEY index. pIdx is an index on the same table. pIdx may +** or may not be the same index as pPk. +** +** The first nKey entries of pIdx are guaranteed to be ordinary columns, +** not a rowid or expression. +** +** This routine differs from hasColumn() in that both the column and the +** collating sequence must match for this routine, but for hasColumn() only +** the column name must match. +*/ +static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){ + int i, j; + assert( nKey<=pIdx->nColumn ); + assert( iColnColumn,pPk->nKeyCol) ); + assert( pPk->idxType==SQLITE_IDXTYPE_PRIMARYKEY ); + assert( pPk->pTable->tabFlags & TF_WithoutRowid ); + assert( pPk->pTable==pIdx->pTable ); + testcase( pPk==pIdx ); + j = pPk->aiColumn[iCol]; + assert( j!=XN_ROWID && j!=XN_EXPR ); + for(i=0; iaiColumn[i]>=0 || j>=0 ); + if( pIdx->aiColumn[i]==j + && sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0 + ){ + return 1; + } + } + return 0; +} + +/* Recompute the colNotIdxed field of the Index. +** +** colNotIdxed is a bitmask that has a 0 bit representing each indexed +** columns that are within the first 63 columns of the table. The +** high-order bit of colNotIdxed is always 1. All unindexed columns +** of the table have a 1. +** +** 2019-10-24: For the purpose of this computation, virtual columns are +** not considered to be covered by the index, even if they are in the +** index, because we do not trust the logic in whereIndexExprTrans() to be +** able to find all instances of a reference to the indexed table column +** and convert them into references to the index. Hence we always want +** the actual table at hand in order to recompute the virtual column, if +** necessary. +** +** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask +** to determine if the index is covering index. +*/ +static void recomputeColumnsNotIndexed(Index *pIdx){ + Bitmask m = 0; + int j; + Table *pTab = pIdx->pTable; + for(j=pIdx->nColumn-1; j>=0; j--){ + int x = pIdx->aiColumn[j]; + if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){ + testcase( x==BMS-1 ); + testcase( x==BMS-2 ); + if( xcolNotIdxed = ~m; + assert( (pIdx->colNotIdxed>>63)==1 ); +} + /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both @@ -100822,17 +116219,16 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){ ** Changes include: ** ** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. -** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is -** no rowid btree for a WITHOUT ROWID. Instead, the canonical -** data storage is a covering index btree. -** (3) Bypass the creation of the sqlite_master table entry +** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY +** into BTREE_BLOBKEY. +** (3) Bypass the creation of the sqlite_schema table entry ** for the PRIMARY KEY as the primary key index is now -** identified by the sqlite_master table entry of the table itself. +** identified by the sqlite_schema table entry of the table itself. ** (4) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus -** columns are part of KeyInfo.nXField and are not used for +** columns are part of KeyInfo.nAllField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. @@ -100843,6 +116239,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Index *pIdx; Index *pPk; int nPk; + int nExtra; int i, j; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; @@ -100851,53 +116248,55 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ */ if( !db->init.imposterTable ){ for(i=0; inCol; i++){ - if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ + if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 + && (pTab->aCol[i].notNull==OE_None) + ){ pTab->aCol[i].notNull = OE_Abort; } } + pTab->tabFlags |= TF_HasNotNull; } - /* The remaining transformations only apply to b-tree tables, not to - ** virtual tables */ - if( IN_DECLARE_VTAB ) return; - - /* Convert the OP_CreateTable opcode that would normally create the - ** root-page for the table into an OP_CreateIndex opcode. The index - ** created will become the PRIMARY KEY index. + /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY + ** into BTREE_BLOBKEY. */ - if( pParse->addrCrTab ){ + assert( !pParse->bReturning ); + if( pParse->u1.addrCrTab ){ assert( v ); - sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex); + sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY); } /* Locate the PRIMARY KEY index. Or, if this table was originally - ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. + ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. */ if( pTab->iPKey>=0 ){ ExprList *pList; Token ipkToken; - sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); - pList = sqlite3ExprListAppend(pParse, 0, + sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zCnName); + pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); - if( pList==0 ) return; - pList->a[0].sortOrder = pParse->iPkSortOrder; + if( pList==0 ){ + pTab->tabFlags &= ~TF_WithoutRowid; + return; + } + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); + } + pList->a[0].sortFlags = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); + pTab->iPKey = -1; sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); - if( db->mallocFailed ) return; + if( pParse->nErr ){ + pTab->tabFlags &= ~TF_WithoutRowid; + return; + } + assert( db->mallocFailed==0 ); pPk = sqlite3PrimaryKeyIndex(pTab); - pTab->iPKey = -1; + assert( pPk->nKeyCol==1 ); }else{ pPk = sqlite3PrimaryKeyIndex(pTab); - - /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master - ** table entry. This is only required if currently generating VDBE - ** code for a CREATE TABLE (not when parsing one as part of reading - ** a database schema). */ - if( v ){ - assert( db->init.busy==0 ); - sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto); - } + assert( pPk!=0 ); /* ** Remove all redundant columns from the PRIMARY KEY. For example, change @@ -100905,9 +116304,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** code assumes the PRIMARY KEY contains no repeated columns. */ for(i=j=1; inKeyCol; i++){ - if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){ + if( isDupColumn(pPk, j, pPk, i) ){ pPk->nColumn--; }else{ + testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ); + pPk->azColl[j] = pPk->azColl[i]; + pPk->aSortOrder[j] = pPk->aSortOrder[i]; pPk->aiColumn[j++] = pPk->aiColumn[i]; } } @@ -100916,7 +116318,16 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ assert( pPk!=0 ); pPk->isCovering = 1; if( !db->init.imposterTable ) pPk->uniqNotNull = 1; - nPk = pPk->nKeyCol; + nPk = pPk->nColumn = pPk->nKeyCol; + + /* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema + ** table entry. This is only required if currently generating VDBE + ** code for a CREATE TABLE (not when parsing one as part of reading + ** a database schema). */ + if( v && pPk->tnum>0 ){ + assert( db->init.busy==0 ); + sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto); + } /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; @@ -100928,7 +116339,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ int n; if( IsPrimaryKeyIndex(pIdx) ) continue; for(i=n=0; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++; + if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ + testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); + n++; + } } if( n==0 ){ /* This index is a superset of the primary key */ @@ -100937,9 +116351,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ } if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; iaiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){ + if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ + testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; + if( pPk->aSortOrder[i] ){ + /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ + pIdx->bAscKeyBug = 1; + } j++; } } @@ -100949,23 +116368,133 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ /* Add all table columns to the PRIMARY KEY index */ - if( nPknCol ){ - if( resizeIndexObject(db, pPk, pTab->nCol) ) return; - for(i=0, j=nPk; inCol; i++){ - if( !hasColumn(pPk->aiColumn, j, i) ){ - assert( jnColumn ); - pPk->aiColumn[j] = i; - pPk->azColl[j] = sqlite3StrBINARY; - j++; - } + nExtra = 0; + for(i=0; inCol; i++){ + if( !hasColumn(pPk->aiColumn, nPk, i) + && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; + } + if( resizeIndexObject(db, pPk, nPk+nExtra) ) return; + for(i=0, j=nPk; inCol; i++){ + if( !hasColumn(pPk->aiColumn, j, i) + && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 + ){ + assert( jnColumn ); + pPk->aiColumn[j] = i; + pPk->azColl[j] = sqlite3StrBINARY; + j++; } - assert( pPk->nColumn==j ); - assert( pTab->nCol==j ); - }else{ - pPk->nColumn = pTab->nCol; } + assert( pPk->nColumn==j ); + assert( pTab->nNVCol<=j ); + recomputeColumnsNotIndexed(pPk); } + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Return true if pTab is a virtual table and zName is a shadow table name +** for that virtual table. +*/ +SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){ + int nName; /* Length of zName */ + Module *pMod; /* Module for the virtual table */ + + if( !IsVirtual(pTab) ) return 0; + nName = sqlite3Strlen30(pTab->zName); + if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0; + if( zName[nName]!='_' ) return 0; + pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); + if( pMod==0 ) return 0; + if( pMod->pModule->iVersion<3 ) return 0; + if( pMod->pModule->xShadowName==0 ) return 0; + return pMod->pModule->xShadowName(zName+nName+1); +} +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Table pTab is a virtual table. If it the virtual table implementation +** exists and has an xShadowName method, then loop over all other ordinary +** tables within the same schema looking for shadow tables of pTab, and mark +** any shadow tables seen using the TF_Shadow flag. +*/ +SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ + int nName; /* Length of pTab->zName */ + Module *pMod; /* Module for the virtual table */ + HashElem *k; /* For looping through the symbol table */ + + assert( IsVirtual(pTab) ); + pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]); + if( pMod==0 ) return; + if( NEVER(pMod->pModule==0) ) return; + if( pMod->pModule->iVersion<3 ) return; + if( pMod->pModule->xShadowName==0 ) return; + assert( pTab->zName!=0 ); + nName = sqlite3Strlen30(pTab->zName); + for(k=sqliteHashFirst(&pTab->pSchema->tblHash); k; k=sqliteHashNext(k)){ + Table *pOther = sqliteHashData(k); + assert( pOther->zName!=0 ); + if( !IsOrdinaryTable(pOther) ) continue; + if( pOther->tabFlags & TF_Shadow ) continue; + if( sqlite3StrNICmp(pOther->zName, pTab->zName, nName)==0 + && pOther->zName[nName]=='_' + && pMod->pModule->xShadowName(pOther->zName+nName+1) + ){ + pOther->tabFlags |= TF_Shadow; + } + } +} +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Return true if zName is a shadow table name in the current database +** connection. +** +** zName is temporarily modified while this routine is running, but is +** restored to its original value prior to this routine returning. +*/ +SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ + char *zTail; /* Pointer to the last "_" in zName */ + Table *pTab; /* Table that zName is a shadow of */ + zTail = strrchr(zName, '_'); + if( zTail==0 ) return 0; + *zTail = 0; + pTab = sqlite3FindTable(db, zName, 0); + *zTail = '_'; + if( pTab==0 ) return 0; + if( !IsVirtual(pTab) ) return 0; + return sqlite3IsShadowTableOf(db, pTab, zName); +} +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ + + +#ifdef SQLITE_DEBUG +/* +** Mark all nodes of an expression as EP_Immutable, indicating that +** they should not be changed. Expressions attached to a table or +** index definition are tagged this way to help ensure that we do +** not pass them into code generator routines by mistake. +*/ +static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){ + ExprSetVVAProperty(pExpr, EP_Immutable); + return WRC_Continue; +} +static void markExprListImmutable(ExprList *pList){ + if( pList ){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = markImmutableExprStep; + w.xSelectCallback = sqlite3SelectWalkNoop; + w.xSelectCallback2 = 0; + sqlite3WalkExprList(&w, pList); + } +} +#else +#define markExprListImmutable(X) /* no-op */ +#endif /* SQLITE_DEBUG */ + + /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. @@ -100974,15 +116503,15 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** is added to the internal hash tables, assuming no errors have ** occurred. ** -** An entry for the table is made in the master table on disk, unless +** An entry for the table is made in the schema table on disk, unless ** this is a temporary table or db->init.busy==1. When db->init.busy==1 -** it means we are reading the sqlite_master table because we just -** connected to the database or because the sqlite_master table has +** it means we are reading the sqlite_schema table because we just +** connected to the database or because the sqlite_schema table has ** recently changed, so the entry for this table already exists in -** the sqlite_master table. We do not want to create it again. +** the sqlite_schema table. We do not want to create it again. ** ** If the pSelect argument is not NULL, it means that this routine -** was called to create a table generated from a +** was called to create a table generated from a ** "CREATE TABLE ... AS SELECT ..." statement. The column names of ** the new table will match the result set of the SELECT. */ @@ -100990,7 +116519,7 @@ SQLITE_PRIVATE void sqlite3EndTable( Parse *pParse, /* Parse context */ Token *pCons, /* The ',' token after the last column defn. */ Token *pEnd, /* The ')' before options in the CREATE TABLE */ - u8 tabOpts, /* Extra table options. Usually 0. */ + u32 tabOpts, /* Extra table options. Usually 0. */ Select *pSelect /* Select from a "CREATE ... AS SELECT" */ ){ Table *p; /* The new table */ @@ -101001,26 +116530,74 @@ SQLITE_PRIVATE void sqlite3EndTable( if( pEnd==0 && pSelect==0 ){ return; } - assert( !db->mallocFailed ); p = pParse->pNewTable; if( p==0 ) return; - assert( !db->init.busy || !pSelect ); + if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){ + p->tabFlags |= TF_Shadow; + } /* If the db->init.busy is 1 it means we are reading the SQL off the - ** "sqlite_master" or "sqlite_temp_master" table on the disk. + ** "sqlite_schema" or "sqlite_temp_schema" table on the disk. ** So do not write to the disk again. Extract the root page number ** for the table from the db->init.newTnum field. (The page number ** should have been put there by the sqliteOpenCb routine.) ** - ** If the root page number is 1, that means this is the sqlite_master + ** If the root page number is 1, that means this is the sqlite_schema ** table itself. So mark it read-only. */ if( db->init.busy ){ + if( pSelect || (!IsOrdinaryTable(p) && db->init.newTnum) ){ + sqlite3ErrorMsg(pParse, ""); + return; + } p->tnum = db->init.newTnum; if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } + /* Special processing for tables that include the STRICT keyword: + ** + ** * Do not allow custom column datatypes. Every column must have + ** a datatype that is one of INT, INTEGER, REAL, TEXT, or BLOB. + ** + ** * If a PRIMARY KEY is defined, other than the INTEGER PRIMARY KEY, + ** then all columns of the PRIMARY KEY must have a NOT NULL + ** constraint. + */ + if( tabOpts & TF_Strict ){ + int ii; + p->tabFlags |= TF_Strict; + for(ii=0; iinCol; ii++){ + Column *pCol = &p->aCol[ii]; + if( pCol->eCType==COLTYPE_CUSTOM ){ + if( pCol->colFlags & COLFLAG_HASTYPE ){ + sqlite3ErrorMsg(pParse, + "unknown datatype for %s.%s: \"%s\"", + p->zName, pCol->zCnName, sqlite3ColumnType(pCol, "") + ); + }else{ + sqlite3ErrorMsg(pParse, "missing datatype for %s.%s", + p->zName, pCol->zCnName); + } + return; + }else if( pCol->eCType==COLTYPE_ANY ){ + pCol->affinity = SQLITE_AFF_BLOB; + } + if( (pCol->colFlags & COLFLAG_PRIMKEY)!=0 + && p->iPKey!=ii + && pCol->notNull == OE_None + ){ + pCol->notNull = OE_Abort; + p->tabFlags |= TF_HasNotNull; + } + } + } + + assert( (p->tabFlags & TF_HasPrimaryKey)==0 + || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); + assert( (p->tabFlags & TF_HasPrimaryKey)!=0 + || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) ); + /* Special processing for WITHOUT ROWID Tables */ if( tabOpts & TF_WithoutRowid ){ if( (p->tabFlags & TF_Autoincrement) ){ @@ -101030,12 +116607,11 @@ SQLITE_PRIVATE void sqlite3EndTable( } if( (p->tabFlags & TF_HasPrimaryKey)==0 ){ sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName); - }else{ - p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; - convertToWithoutRowidTable(pParse, p); + return; } + p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; + convertToWithoutRowidTable(pParse, p); } - iDb = sqlite3SchemaToIndex(db, p->pSchema); #ifndef SQLITE_OMIT_CHECK @@ -101043,8 +116619,47 @@ SQLITE_PRIVATE void sqlite3EndTable( */ if( p->pCheck ){ sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck); + if( pParse->nErr ){ + /* If errors are seen, delete the CHECK constraints now, else they might + ** actually be used if PRAGMA writable_schema=ON is set. */ + sqlite3ExprListDelete(db, p->pCheck); + p->pCheck = 0; + }else{ + markExprListImmutable(p->pCheck); + } } #endif /* !defined(SQLITE_OMIT_CHECK) */ +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( p->tabFlags & TF_HasGenerated ){ + int ii, nNG = 0; + testcase( p->tabFlags & TF_HasVirtual ); + testcase( p->tabFlags & TF_HasStored ); + for(ii=0; iinCol; ii++){ + u32 colFlags = p->aCol[ii].colFlags; + if( (colFlags & COLFLAG_GENERATED)!=0 ){ + Expr *pX = sqlite3ColumnExpr(p, &p->aCol[ii]); + testcase( colFlags & COLFLAG_VIRTUAL ); + testcase( colFlags & COLFLAG_STORED ); + if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){ + /* If there are errors in resolving the expression, change the + ** expression to a NULL. This prevents code generators that operate + ** on the expression from inserting extra parts into the expression + ** tree that have been allocated from lookaside memory, which is + ** illegal in a schema and will lead to errors or heap corruption + ** when the database connection closes. */ + sqlite3ColumnSetExpr(pParse, p, &p->aCol[ii], + sqlite3ExprAlloc(db, TK_NULL, 0, 0)); + } + }else{ + nNG++; + } + } + if( nNG==0 ){ + sqlite3ErrorMsg(pParse, "must have at least one non-generated column"); + return; + } + } +#endif /* Estimate the average row size for the table and for all implied indices */ estimateTableWidth(p); @@ -101053,7 +116668,7 @@ SQLITE_PRIVATE void sqlite3EndTable( } /* If not initializing, then create a record for the new table - ** in the SQLITE_MASTER table of the database. + ** in the schema table of the database. ** ** If this is a TEMPORARY table, write the entry into the auxiliary ** file instead of into the main database file. @@ -101070,10 +116685,10 @@ SQLITE_PRIVATE void sqlite3EndTable( sqlite3VdbeAddOp1(v, OP_Close, 0); - /* + /* ** Initialize zType for the new view or table. */ - if( p->pSelect==0 ){ + if( IsOrdinaryTable(p) ){ /* A regular table */ zType = "table"; zType2 = "TABLE"; @@ -101107,6 +116722,11 @@ SQLITE_PRIVATE void sqlite3EndTable( int addrInsLoop; /* Top of the loop for inserting rows */ Table *pSelTab; /* A table that describes the SELECT results */ + if( IN_SPECIAL_PARSE ){ + pParse->rc = SQLITE_ERROR; + pParse->nErr++; + return; + } regYield = ++pParse->nMem; regRec = ++pParse->nMem; regRowid = ++pParse->nMem; @@ -101117,19 +116737,20 @@ SQLITE_PRIVATE void sqlite3EndTable( pParse->nTab = 2; addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); - sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); - sqlite3Select(pParse, pSelect, &dest); - sqlite3VdbeEndCoroutine(v, regYield); - sqlite3VdbeJumpHere(v, addrTop - 1); if( pParse->nErr ) return; - pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect); + pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB); if( pSelTab==0 ) return; assert( p->aCol==0 ); - p->nCol = pSelTab->nCol; + p->nCol = p->nNVCol = pSelTab->nCol; p->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; sqlite3DeleteTable(db, pSelTab); + sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); + sqlite3Select(pParse, pSelect, &dest); + if( pParse->nErr ) return; + sqlite3VdbeEndCoroutine(v, regYield); + sqlite3VdbeJumpHere(v, addrTop - 1); addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec); @@ -101148,20 +116769,20 @@ SQLITE_PRIVATE void sqlite3EndTable( Token *pEnd2 = tabOpts ? &pParse->sLastToken : pEnd; n = (int)(pEnd2->z - pParse->sNameToken.z); if( pEnd2->z[0]!=';' ) n += pEnd2->n; - zStmt = sqlite3MPrintf(db, + zStmt = sqlite3MPrintf(db, "CREATE %s %.*s", zType2, n, pParse->sNameToken.z ); } - /* A slot for the record has already been allocated in the - ** SQLITE_MASTER table. We just need to update that slot with all + /* A slot for the record has already been allocated in the + ** schema table. We just need to update that slot with all ** the information we've collected. */ sqlite3NestedParse(pParse, - "UPDATE %Q.%s " - "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " - "WHERE rowid=#%d", - db->aDb[iDb].zDbSName, MASTER_NAME, + "UPDATE %Q." LEGACY_SCHEMA_TABLE + " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q" + " WHERE rowid=#%d", + db->aDb[iDb].zDbSName, zType, p->zName, p->zName, @@ -101176,7 +116797,7 @@ SQLITE_PRIVATE void sqlite3EndTable( /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ - if( (p->tabFlags & TF_Autoincrement)!=0 ){ + if( (p->tabFlags & TF_Autoincrement)!=0 && !IN_SPECIAL_PARSE ){ Db *pDb = &db->aDb[iDb]; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->pSeqTab==0 ){ @@ -101190,16 +116811,16 @@ SQLITE_PRIVATE void sqlite3EndTable( /* Reparse everything to update our internal data structures */ sqlite3VdbeAddParseSchemaOp(v, iDb, - sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName)); + sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0); } - /* Add the table to the in-memory representation of the database. */ if( db->init.busy ){ Table *pOld; Schema *pSchema = p->pSchema; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + assert( HasRowid(p) || p->iPKey<0 ); pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ @@ -101207,21 +116828,29 @@ SQLITE_PRIVATE void sqlite3EndTable( return; } pParse->pNewTable = 0; - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; -#ifndef SQLITE_OMIT_ALTERTABLE - if( !p->pSelect ){ - const char *zName = (const char *)pParse->sNameToken.z; - int nName; - assert( !pSelect && pCons && pEnd ); - if( pCons->z==0 ){ - pCons = pEnd; - } - nName = (int)((const char *)pCons->z - zName); - p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName); + /* If this is the magic sqlite_sequence table used by autoincrement, + ** then record a pointer to this table in the main database structure + ** so that INSERT can find the table easily. */ + assert( !pParse->nested ); +#ifndef SQLITE_OMIT_AUTOINCREMENT + if( strcmp(p->zName, "sqlite_sequence")==0 ){ + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + p->pSchema->pSeqTab = p; } #endif } + +#ifndef SQLITE_OMIT_ALTERTABLE + if( !pSelect && IsOrdinaryTable(p) ){ + assert( pCons && pEnd ); + if( pCons->z==0 ){ + pCons = pEnd; + } + p->u.tab.addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z); + } +#endif } #ifndef SQLITE_OMIT_VIEW @@ -101254,6 +116883,16 @@ SQLITE_PRIVATE void sqlite3CreateView( sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; if( p==0 || pParse->nErr ) goto create_view_fail; + + /* Legacy versions of SQLite allowed the use of the magic "rowid" column + ** on a view, even though views do not have rowids. The following flag + ** setting fixes this problem. But the fix can be disabled by compiling + ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that + ** depend upon the old buggy behavior. */ +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW + p->tabFlags |= TF_NoVisibleRowid; +#endif + sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); @@ -101264,15 +116903,22 @@ SQLITE_PRIVATE void sqlite3CreateView( ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ - p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + pSelect->selFlags |= SF_View; + if( IN_RENAME_OBJECT ){ + p->u.view.pSelect = pSelect; + pSelect = 0; + }else{ + p->u.view.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + } p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); + p->eTabType = TABTYP_VIEW; if( db->mallocFailed ) goto create_view_fail; /* Locate the end of the CREATE VIEW statement. Make sEnd point to ** the end. */ sEnd = pParse->sLastToken; - assert( sEnd.z[0]!=0 ); + assert( sEnd.z[0]!=0 || sEnd.n==0 ); if( sEnd.z[0]!=';' ){ sEnd.z += sEnd.n; } @@ -101284,11 +116930,14 @@ SQLITE_PRIVATE void sqlite3CreateView( sEnd.z = &z[n-1]; sEnd.n = 1; - /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ + /* Use sqlite3EndTable() to add the view to the schema table */ sqlite3EndTable(pParse, 0, &sEnd, 0, 0); create_view_fail: sqlite3SelectDelete(db, pSelect); + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprlistUnmap(pParse, pCNames); + } sqlite3ExprListDelete(db, pCNames); return; } @@ -101306,6 +116955,9 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + int rc; +#endif #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Saved xAuth pointer */ #endif @@ -101313,10 +116965,12 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3VtabCallConnect(pParse, pTable) ){ - return SQLITE_ERROR; + if( IsVirtual(pTable) ){ + db->nSchemaLock++; + rc = sqlite3VtabCallConnect(pParse, pTable); + db->nSchemaLock--; + return rc; } - if( IsVirtual(pTable) ) return 0; #endif #ifndef SQLITE_OMIT_VIEW @@ -101335,7 +116989,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ ** Actually, the error above is now caught prior to reaching this point. ** But the following test is still important as it does come up ** in the following: - ** + ** ** CREATE TABLE main.ex1(a); ** CREATE TEMP VIEW ex1 AS SELECT a FROM ex1; ** SELECT * FROM temp.ex1; @@ -101353,60 +117007,69 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ - assert( pTable->pSelect ); - pSel = sqlite3SelectDup(db, pTable->pSelect, 0); + assert( IsView(pTable) ); + pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0); if( pSel ){ + u8 eParseMode = pParse->eParseMode; + pParse->eParseMode = PARSE_MODE_NORMAL; n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; - db->lookaside.bDisable++; + DisableLookaside; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; db->xAuth = 0; - pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); db->xAuth = xAuth; #else - pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); + pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE); #endif pParse->nTab = n; - if( pTable->pCheck ){ + if( pSelTab==0 ){ + pTable->nCol = 0; + nErr++; + }else if( pTable->pCheck ){ /* CREATE VIEW name(arglist) AS ... ** The names of the columns in the table are taken from ** arglist which is stored in pTable->pCheck. The pCheck field ** normally holds CHECK constraints on an ordinary table, but for ** a VIEW it holds the list of column names. */ - sqlite3ColumnsFromExprList(pParse, pTable->pCheck, + sqlite3ColumnsFromExprList(pParse, pTable->pCheck, &pTable->nCol, &pTable->aCol); - if( db->mallocFailed==0 - && pParse->nErr==0 + if( pParse->nErr==0 && pTable->nCol==pSel->pEList->nExpr ){ - sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel); + assert( db->mallocFailed==0 ); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel, + SQLITE_AFF_NONE); } - }else if( pSelTab ){ + }else{ /* CREATE VIEW name AS... without an argument list. Construct ** the column names from the SELECT statement that defines the view. */ assert( pTable->aCol==0 ); pTable->nCol = pSelTab->nCol; pTable->aCol = pSelTab->aCol; + pTable->tabFlags |= (pSelTab->tabFlags & COLFLAG_NOINSERT); pSelTab->nCol = 0; pSelTab->aCol = 0; assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); - }else{ - pTable->nCol = 0; - nErr++; } + pTable->nNVCol = pTable->nCol; sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); - db->lookaside.bDisable--; + EnableLookaside; + pParse->eParseMode = eParseMode; } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; + if( db->mallocFailed ){ + sqlite3DeleteColumnNames(db, pTable); + } #endif /* SQLITE_OMIT_VIEW */ - return nErr; + return nErr; } #endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ @@ -101420,10 +117083,8 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){ if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3DeleteColumnNames(db, pTab); - pTab->aCol = 0; - pTab->nCol = 0; } } DbClearProperty(db, idx, DB_UnresetViews); @@ -101442,7 +117103,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){ ** on tables and/or indices that are the process of being deleted. ** If you are unlucky, one of those deleted indices or tables might ** have the same rootpage number as the real table or index that is -** being moved. So we cannot stop searching after the first match +** being moved. So we cannot stop searching after the first match ** because the first match might be for one of the deleted indices ** or tables and not the table/index that is actually being moved. ** We must continue looping until all tables and indices with @@ -101450,7 +117111,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){ ** in order to be certain that we got the right one. */ #ifndef SQLITE_OMIT_AUTOVACUUM -SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){ +SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){ HashElem *pElem; Hash *pHash; Db *pDb; @@ -101476,51 +117137,44 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT /* ** Write code to erase the table with root-page iTable from database iDb. -** Also write code to modify the sqlite_master table and internal schema +** Also write code to modify the sqlite_schema table and internal schema ** if a root-page of another table is moved by the btree-layer whilst ** erasing iTable (this can happen with an auto-vacuum database). -*/ +*/ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); int r1 = sqlite3GetTempReg(pParse); - assert( iTable>1 ); + if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema"); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM /* OP_Destroy stores an in integer r1. If this integer ** is non-zero, then it is the root page number of a table moved to - ** location iTable. The following code modifies the sqlite_master table to + ** location iTable. The following code modifies the sqlite_schema table to ** reflect this. ** ** The "#NNN" in the SQL is a special constant that means whatever value ** is in register NNN. See grammar rules associated with the TK_REGISTER ** token for additional information. */ - sqlite3NestedParse(pParse, - "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d", - pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1); + sqlite3NestedParse(pParse, + "UPDATE %Q." LEGACY_SCHEMA_TABLE + " SET rootpage=%d WHERE #%d AND rootpage=#%d", + pParse->db->aDb[iDb].zDbSName, iTable, r1, r1); #endif sqlite3ReleaseTempReg(pParse, r1); } /* ** Write VDBE code to erase table pTab and all associated indices on disk. -** Code to update the sqlite_master tables and internal schema definitions +** Code to update the sqlite_schema tables and internal schema definitions ** in case a root-page belonging to another table is moved by the btree layer ** is also added (this can happen with an auto-vacuum database). */ static void destroyTable(Parse *pParse, Table *pTab){ -#ifdef SQLITE_OMIT_AUTOVACUUM - Index *pIdx; - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - destroyRootPage(pParse, pTab->tnum, iDb); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - destroyRootPage(pParse, pIdx->tnum, iDb); - } -#else /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the - ** table and index root-pages in order, starting with the numerically + ** table and index root-pages in order, starting with the numerically ** largest root-page number. This guarantees that none of the root-pages ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the ** following were coded: @@ -101530,22 +117184,22 @@ static void destroyTable(Parse *pParse, Table *pTab){ ** OP_Destroy 5 0 ** ** and root page 5 happened to be the largest root-page number in the - ** database, then root page 5 would be moved to page 4 by the + ** database, then root page 5 would be moved to page 4 by the ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit ** a free-list page. */ - int iTab = pTab->tnum; - int iDestroyed = 0; + Pgno iTab = pTab->tnum; + Pgno iDestroyed = 0; while( 1 ){ Index *pIdx; - int iLargest = 0; + Pgno iLargest = 0; if( iDestroyed==0 || iTabpIndex; pIdx; pIdx=pIdx->pNext){ - int iIdx = pIdx->tnum; + Pgno iIdx = pIdx->tnum; assert( pIdx->pSchema==pTab->pSchema ); if( (iDestroyed==0 || (iIdxiLargest ){ iLargest = iIdx; @@ -101560,7 +117214,6 @@ static void destroyTable(Parse *pParse, Table *pTab){ iDestroyed = iLargest; } } -#endif } /* @@ -101607,12 +117260,12 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in #endif /* Drop all triggers associated with the table being dropped. Code - ** is generated to remove entries from sqlite_master and/or - ** sqlite_temp_master if required. + ** is generated to remove entries from sqlite_schema and/or + ** sqlite_temp_schema if required. */ pTrigger = sqlite3TriggerList(pParse, pTab); while( pTrigger ){ - assert( pTrigger->pSchema==pTab->pSchema || + assert( pTrigger->pSchema==pTab->pSchema || pTrigger->pSchema==db->aDb[1].pSchema ); sqlite3DropTriggerPtr(pParse, pTrigger); pTrigger = pTrigger->pNext; @@ -101632,16 +117285,17 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in } #endif - /* Drop all SQLITE_MASTER table and index entries that refer to the - ** table. The program name loops through the master table and deletes + /* Drop all entries in the schema table that refer to the + ** table. The program name loops through the schema table and deletes ** every row that refers to a table of the same name as the one being ** dropped. Triggers are handled separately because a trigger can be ** created in the temp database that refers to a table in another ** database. */ - sqlite3NestedParse(pParse, - "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", - pDb->zDbSName, MASTER_NAME, pTab->zName); + sqlite3NestedParse(pParse, + "DELETE FROM %Q." LEGACY_SCHEMA_TABLE + " WHERE tbl_name=%Q and type!='trigger'", + pDb->zDbSName, pTab->zName); if( !isView && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } @@ -101651,12 +117305,48 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in */ if( IsVirtual(pTab) ){ sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0); + sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); sqlite3ChangeCookie(pParse, iDb); sqliteViewResetAll(db, iDb); } +/* +** Return TRUE if shadow tables should be read-only in the current +** context. +*/ +SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db){ +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( (db->flags & SQLITE_Defensive)!=0 + && db->pVtabCtx==0 + && db->nVdbeExec==0 + && !sqlite3VtabInSync(db) + ){ + return 1; + } +#endif + return 0; +} + +/* +** Return true if it is not allowed to drop the given table +*/ +static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){ + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ + if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0; + if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0; + return 1; + } + if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){ + return 1; + } + if( pTab->tabFlags & TF_Eponymous ){ + return 1; + } + return 0; +} + /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. @@ -101679,7 +117369,10 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, if( noErr ) db->suppressErr--; if( pTab==0 ){ - if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + if( noErr ){ + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + sqlite3ForceNotReadOnly(pParse); + } goto exit_drop_table; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -101726,8 +117419,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, } } #endif - if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 - && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){ + if( tableMayNotBeDropped(db, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; } @@ -101736,24 +117428,26 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, /* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used ** on a table. */ - if( isView && pTab->pSelect==0 ){ + if( isView && !IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); goto exit_drop_table; } - if( !isView && pTab->pSelect ){ + if( !isView && IsView(pTab) ){ sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); goto exit_drop_table; } #endif - /* Generate code to remove the table from the master table + /* Generate code to remove the table from the schema table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); - sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); - sqlite3FkDropTable(pParse, pName, pTab); + if( !isView ){ + sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); + sqlite3FkDropTable(pParse, pName, pTab); + } sqlite3CodeDropTable(pParse, pTab, iDb, isView); } @@ -101789,7 +117483,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( FKey *pFKey = 0; FKey *pNextTo; Table *p = pParse->pNewTable; - int nByte; + i64 nByte; int i; int nCol; char *z; @@ -101802,7 +117496,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( if( pToCol && pToCol->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "foreign key on %s" " should reference only one column of table %T", - p->aCol[iCol].zName, pTo); + p->aCol[iCol].zCnName, pTo); goto fk_end; } nCol = 1; @@ -101817,7 +117511,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1; if( pToCol ){ for(i=0; inExpr; i++){ - nByte += sqlite3Strlen30(pToCol->a[i].zName) + 1; + nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1; } } pFKey = sqlite3DbMallocZero(db, nByte ); @@ -101825,9 +117519,13 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( goto fk_end; } pFKey->pFrom = p; - pFKey->pNextFrom = p->pFKey; + assert( IsOrdinaryTable(p) ); + pFKey->pNextFrom = p->u.tab.pFKey; z = (char*)&pFKey->aCol[nCol]; pFKey->zTo = z; + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, (void*)z, pTo); + } memcpy(z, pTo->z, pTo->n); z[pTo->n] = 0; sqlite3Dequote(z); @@ -101839,24 +117537,30 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( for(i=0; inCol; j++){ - if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){ + if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){ pFKey->aCol[i].iFrom = j; break; } } if( j>=p->nCol ){ - sqlite3ErrorMsg(pParse, - "unknown column \"%s\" in foreign key definition", - pFromCol->a[i].zName); + sqlite3ErrorMsg(pParse, + "unknown column \"%s\" in foreign key definition", + pFromCol->a[i].zEName); goto fk_end; } + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName); + } } } if( pToCol ){ for(i=0; ia[i].zName); + int n = sqlite3Strlen30(pToCol->a[i].zEName); pFKey->aCol[i].zCol = z; - memcpy(z, pToCol->a[i].zName, n); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName); + } + memcpy(z, pToCol->a[i].zEName, n); z[n] = 0; z += n+1; } @@ -101866,7 +117570,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */ assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); - pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, + pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, pFKey->zTo, (void *)pFKey ); if( pNextTo==pFKey ){ @@ -101881,7 +117585,8 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey( /* Link the foreign key to the table as the last step. */ - p->pFKey = pFKey; + assert( IsOrdinaryTable(p) ); + p->u.tab.pFKey = pFKey; pFKey = 0; fk_end: @@ -101902,7 +117607,9 @@ SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){ #ifndef SQLITE_OMIT_FOREIGN_KEY Table *pTab; FKey *pFKey; - if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return; + if( (pTab = pParse->pNewTable)==0 ) return; + if( NEVER(!IsOrdinaryTable(pTab)) ) return; + if( (pFKey = pTab->u.tab.pFKey)==0 ) return; assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */ pFKey->isDeferred = (u8)isDeferred; #endif @@ -101926,7 +117633,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ int iSorter; /* Cursor opened by OpenSorter (if in use) */ int addr1; /* Address of top of loop */ int addr2; /* Address to jump to for next iteration */ - int tnum; /* Root page of index */ + Pgno tnum; /* Root page of index */ int iPartIdxLabel; /* Jump to this label to skip a row */ Vdbe *v; /* Generate code into this virtual machine */ KeyInfo *pKey; /* KeyInfo for index */ @@ -101947,12 +117654,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ - tnum = memRootPage; + tnum = (Pgno)memRootPage; }else{ tnum = pIndex->tnum; } pKey = sqlite3KeyInfoOfIndex(pParse, pIndex); - assert( pKey!=0 || db->mallocFailed || pParse->nErr ); + assert( pKey!=0 || pParse->nErr ); /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; @@ -101964,6 +117671,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); regRecord = sqlite3GetTempReg(pParse); + sqlite3MultiWrite(pParse); sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); @@ -101971,23 +117679,41 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); - sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, + sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb, (char *)pKey, P4_KEYINFO); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0)); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); if( IsUniqueIndex(pIndex) ){ - int j2 = sqlite3VdbeCurrentAddr(v) + 3; - sqlite3VdbeGoto(v, j2); + int j2 = sqlite3VdbeGoto(v, 1); addr2 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); - }else{ + sqlite3VdbeJumpHere(v, j2); + }else{ + /* Most CREATE INDEX and REINDEX statements that are not UNIQUE can not + ** abort. The exception is if one of the indexed expressions contains a + ** user function that throws an exception when it is evaluated. But the + ** overhead of adding a statement journal to a CREATE INDEX statement is + ** very small (since most of the pages written do not contain content that + ** needs to be restored if the statement aborts), so we call + ** sqlite3MayAbort() for all CREATE INDEX statements. */ + sqlite3MayAbort(pParse); addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); - sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1); + if( !pIndex->bAscKeyBug ){ + /* This OP_SeekEnd opcode makes index insert for a REINDEX go much + ** faster by avoiding unnecessary seeks. But the optimization does + ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables + ** with DESC primary keys, since those indexes have there keys in + ** a different order from the main table. + ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf + */ + sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); + } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); @@ -102035,8 +117761,29 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( } /* -** Create a new index for an SQL table. pName1.pName2 is the name of the index -** and pTblList is the name of the table that is to be indexed. Both will +** If expression list pList contains an expression that was parsed with +** an explicit "NULLS FIRST" or "NULLS LAST" clause, leave an error in +** pParse and return non-zero. Otherwise, return zero. +*/ +SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){ + if( pList ){ + int i; + for(i=0; inExpr; i++){ + if( pList->a[i].bNulls ){ + u8 sf = pList->a[i].sortFlags; + sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s", + (sf==0 || sf==3) ? "FIRST" : "LAST" + ); + return 1; + } + } + } + return 0; +} + +/* +** Create a new index for an SQL table. pName1.pName2 is the name of the index +** and pTblList is the name of the table that is to be indexed. Both will ** be NULL for a primary key or an index that is created to satisfy a ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is @@ -102044,7 +117791,7 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added -** to the table currently under construction. +** to the table currently under construction. */ SQLITE_PRIVATE void sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ @@ -102076,22 +117823,27 @@ SQLITE_PRIVATE void sqlite3CreateIndex( char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ - if( db->mallocFailed || pParse->nErr>0 ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto exit_create_index; } + assert( db->mallocFailed==0 ); if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } + if( sqlite3HasExplicitNulls(pParse, pList) ){ + goto exit_create_index; + } /* ** Find the table that is to be indexed. Return early if not found. */ if( pTblName!=0 ){ - /* Use the two-part index name to determine the database + /* Use the two-part index name to determine the database ** to search for the table. 'Fix' the table name to this db ** before looking up the table. */ @@ -102123,7 +117875,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( assert( db->mallocFailed==0 || pTab==0 ); if( pTab==0 ) goto exit_create_index; if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){ - sqlite3ErrorMsg(pParse, + sqlite3ErrorMsg(pParse, "cannot create a TEMP index on non-TEMP table \"%s\"", pTab->zName); goto exit_create_index; @@ -102139,18 +117891,18 @@ SQLITE_PRIVATE void sqlite3CreateIndex( pDb = &db->aDb[iDb]; assert( pTab!=0 ); - assert( pParse->nErr==0 ); - if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 + if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 + && pTblName!=0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif - && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ + ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW - if( pTab->pSelect ){ + if( IsView(pTab) ){ sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; } @@ -102164,10 +117916,10 @@ SQLITE_PRIVATE void sqlite3CreateIndex( /* ** Find the name of the index. Make sure there is not already another - ** index or table with the same name. + ** index or table with the same name. ** ** Exception: If we are reading the names of permanent indices from the - ** sqlite_master table (because some other process changed the schema) and + ** sqlite_schema table (because some other process changed the schema) and ** one of the index names collides with the name of a temporary table or ** index, then we will continue to process this index. ** @@ -102179,23 +117931,26 @@ SQLITE_PRIVATE void sqlite3CreateIndex( zName = sqlite3NameFromToken(db, pName); if( zName==0 ) goto exit_create_index; assert( pName->z!=0 ); - if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){ goto exit_create_index; } - if( !db->init.busy ){ - if( sqlite3FindTable(db, zName, 0)!=0 ){ - sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); - goto exit_create_index; + if( !IN_RENAME_OBJECT ){ + if( !db->init.busy ){ + if( sqlite3FindTable(db, zName, 0)!=0 ){ + sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); + goto exit_create_index; + } } - } - if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ - if( !ifNotExist ){ - sqlite3ErrorMsg(pParse, "index %s already exists", zName); - }else{ - assert( !db->init.busy ); - sqlite3CodeVerifySchema(pParse, iDb); + if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ + if( !ifNotExist ){ + sqlite3ErrorMsg(pParse, "index %s already exists", zName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); + sqlite3ForceNotReadOnly(pParse); + } + goto exit_create_index; } - goto exit_create_index; } }else{ int n; @@ -102211,13 +117966,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex( ** The following statement converts "sqlite3_autoindex..." into ** "sqlite3_butoindex..." in order to make the names distinct. ** The "vtab_err.test" test demonstrates the need of this statement. */ - if( IN_DECLARE_VTAB ) zName[7]++; + if( IN_SPECIAL_PARSE ) zName[7]++; } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION - { + if( !IN_RENAME_OBJECT ){ const char *zDb = pDb->zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; @@ -102236,14 +117991,17 @@ SQLITE_PRIVATE void sqlite3CreateIndex( */ if( pList==0 ){ Token prevCol; - sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol-1].zName); + Column *pCol = &pTab->aCol[pTab->nCol-1]; + pCol->colFlags |= COLFLAG_UNIQUE; + sqlite3TokenInit(&prevCol, pCol->zCnName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; assert( pList->nExpr==1 ); - sqlite3ExprListSetSortOrder(pList, sortOrder); + sqlite3ExprListSetSortOrder(pList, sortOrder, SQLITE_SO_UNDEFINED); }else{ sqlite3ExprListCheckLength(pParse, pList, "index"); + if( pParse->nErr ) goto exit_create_index; } /* Figure out how many bytes of space are required to store explicitly @@ -102253,15 +118011,17 @@ SQLITE_PRIVATE void sqlite3CreateIndex( Expr *pExpr = pList->a[i].pExpr; assert( pExpr!=0 ); if( pExpr->op==TK_COLLATE ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); } } - /* - ** Allocate the index structure. + /* + ** Allocate the index structure. */ nName = sqlite3Strlen30(zName); nExtraCol = pPk ? pPk->nKeyCol : 1; + assert( pList->nExpr + nExtraCol <= 32767 /* Fits in i16 */ ); pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, nName + nExtra + 1, &zExtra); if( db->mallocFailed ){ @@ -102302,7 +118062,12 @@ SQLITE_PRIVATE void sqlite3CreateIndex( ** TODO: Issue a warning if the table primary key is used as part of the ** index key. */ - for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ + pListItem = pList->a; + if( IN_RENAME_OBJECT ){ + pIndex->aColExpr = pList; + pList = 0; + } + for(i=0; inKeyCol; i++, pListItem++){ Expr *pCExpr; /* The i-th index expression */ int requestedSortOrder; /* ASC or DESC on the i-th expression */ const char *zColl; /* Collation sequence name */ @@ -102318,12 +118083,8 @@ SQLITE_PRIVATE void sqlite3CreateIndex( goto exit_create_index; } if( pIndex->aColExpr==0 ){ - ExprList *pCopy = sqlite3ExprListDup(db, pList, 0); - pIndex->aColExpr = pCopy; - if( !db->mallocFailed ){ - assert( pCopy!=0 ); - pListItem = &pCopy->a[i]; - } + pIndex->aColExpr = pList; + pList = 0; } j = XN_EXPR; pIndex->aiColumn[i] = XN_EXPR; @@ -102333,14 +118094,20 @@ SQLITE_PRIVATE void sqlite3CreateIndex( assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; - }else if( pTab->aCol[j].notNull==0 ){ - pIndex->uniqNotNull = 0; + }else{ + if( pTab->aCol[j].notNull==0 ){ + pIndex->uniqNotNull = 0; + } + if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){ + pIndex->bHasVCol = 1; + } } pIndex->aiColumn[i] = (i16)j; } zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; + assert( !ExprHasProperty(pListItem->pExpr, EP_IntValue) ); zColl = pListItem->pExpr->u.zToken; nColl = sqlite3Strlen30(zColl) + 1; assert( nExtra>=nColl ); @@ -102349,14 +118116,14 @@ SQLITE_PRIVATE void sqlite3CreateIndex( zExtra += nColl; nExtra -= nColl; }else if( j>=0 ){ - zColl = pTab->aCol[j].zColl; + zColl = sqlite3ColumnColl(&pTab->aCol[j]); } if( !zColl ) zColl = sqlite3StrBINARY; if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ goto exit_create_index; } pIndex->azColl[i] = zColl; - requestedSortOrder = pListItem->sortOrder & sortOrderMask; + requestedSortOrder = pListItem->sortFlags & sortOrderMask; pIndex->aSortOrder[i] = (u8)requestedSortOrder; } @@ -102368,9 +118135,10 @@ SQLITE_PRIVATE void sqlite3CreateIndex( for(j=0; jnKeyCol; j++){ int x = pPk->aiColumn[j]; assert( x>=0 ); - if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ - pIndex->nColumn--; + if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){ + pIndex->nColumn--; }else{ + testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) ); pIndex->aiColumn[i] = x; pIndex->azColl[i] = pPk->azColl[j]; pIndex->aSortOrder[i] = pPk->aSortOrder[j]; @@ -102387,13 +118155,14 @@ SQLITE_PRIVATE void sqlite3CreateIndex( /* If this index contains every column of its table, then mark ** it as a covering index */ - assert( HasRowid(pTab) - || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 ); + assert( HasRowid(pTab) + || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 ); + recomputeColumnsNotIndexed(pIndex); if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ pIndex->isCovering = 1; for(j=0; jnCol; j++){ if( j==pTab->iPKey ) continue; - if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue; + if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue; pIndex->isCovering = 0; break; } @@ -102442,13 +118211,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex( if( pIdx->onError!=pIndex->onError ){ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. - ** However the ON CONFLICT clauses are different. If both this + ** However the ON CONFLICT clauses are different. If both this ** constraint and the previous equivalent constraint have explicit ** ON CONFLICT clauses this is an error. Otherwise, use the ** explicitly specified behavior for the index. */ if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){ - sqlite3ErrorMsg(pParse, + sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ @@ -102456,130 +118225,161 @@ SQLITE_PRIVATE void sqlite3CreateIndex( } } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; + if( IN_RENAME_OBJECT ){ + pIndex->pNext = pParse->pNewIndex; + pParse->pNewIndex = pIndex; + pIndex = 0; + } goto exit_create_index; } } } - /* Link the new Index structure to its table and to the other - ** in-memory database structures. - */ - assert( pParse->nErr==0 ); - if( db->init.busy ){ - Index *p; - assert( !IN_DECLARE_VTAB ); - assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); - p = sqlite3HashInsert(&pIndex->pSchema->idxHash, - pIndex->zName, pIndex); - if( p ){ - assert( p==pIndex ); /* Malloc must have failed */ - sqlite3OomFault(db); - goto exit_create_index; - } - db->flags |= SQLITE_InternChanges; - if( pTblName!=0 ){ - pIndex->tnum = db->init.newTnum; - } - } - - /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the - ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then - ** emit code to allocate the index rootpage on disk and make an entry for - ** the index in the sqlite_master table and populate the index with - ** content. But, do not do this if we are simply reading the sqlite_master - ** table to parse the schema, or if this index is the PRIMARY KEY index - ** of a WITHOUT ROWID table. - ** - ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY - ** or UNIQUE index in a CREATE TABLE statement. Since the table - ** has just been created, it contains no data and the index initialization - ** step can be skipped. - */ - else if( HasRowid(pTab) || pTblName!=0 ){ - Vdbe *v; - char *zStmt; - int iMem = ++pParse->nMem; + if( !IN_RENAME_OBJECT ){ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto exit_create_index; - - sqlite3BeginWriteOperation(pParse, 1, iDb); - - /* Create the rootpage for the index using CreateIndex. But before - ** doing so, code a Noop instruction and store its address in - ** Index.tnum. This is required in case this index is actually a - ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In - ** that case the convertToWithoutRowidTable() routine will replace - ** the Noop with a Goto to jump over the VDBE code generated below. */ - pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); - sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem); - - /* Gather the complete text of the CREATE INDEX statement into - ** the zStmt variable + /* Link the new Index structure to its table and to the other + ** in-memory database structures. */ - if( pStart ){ - int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; - if( pName->z[n-1]==';' ) n--; - /* A named index with an explicit CREATE INDEX statement */ - zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", - onError==OE_None ? "" : " UNIQUE", n, pName->z); - }else{ - /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ - /* zStmt = sqlite3MPrintf(""); */ - zStmt = 0; + assert( pParse->nErr==0 ); + if( db->init.busy ){ + Index *p; + assert( !IN_SPECIAL_PARSE ); + assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); + if( pTblName!=0 ){ + pIndex->tnum = db->init.newTnum; + if( sqlite3IndexHasDuplicateRootPage(pIndex) ){ + sqlite3ErrorMsg(pParse, "invalid rootpage"); + pParse->rc = SQLITE_CORRUPT_BKPT; + goto exit_create_index; + } + } + p = sqlite3HashInsert(&pIndex->pSchema->idxHash, + pIndex->zName, pIndex); + if( p ){ + assert( p==pIndex ); /* Malloc must have failed */ + sqlite3OomFault(db); + goto exit_create_index; + } + db->mDbFlags |= DBFLAG_SchemaChange; } - /* Add an entry in sqlite_master for this index - */ - sqlite3NestedParse(pParse, - "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", - db->aDb[iDb].zDbSName, MASTER_NAME, - pIndex->zName, - pTab->zName, - iMem, - zStmt - ); - sqlite3DbFree(db, zStmt); - - /* Fill the index with data and reparse the schema. Code an OP_Expire - ** to invalidate all pre-compiled statements. + /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the + ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then + ** emit code to allocate the index rootpage on disk and make an entry for + ** the index in the sqlite_schema table and populate the index with + ** content. But, do not do this if we are simply reading the sqlite_schema + ** table to parse the schema, or if this index is the PRIMARY KEY index + ** of a WITHOUT ROWID table. + ** + ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY + ** or UNIQUE index in a CREATE TABLE statement. Since the table + ** has just been created, it contains no data and the index initialization + ** step can be skipped. */ - if( pTblName ){ - sqlite3RefillIndex(pParse, pIndex, iMem); - sqlite3ChangeCookie(pParse, iDb); - sqlite3VdbeAddParseSchemaOp(v, iDb, - sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); - sqlite3VdbeAddOp0(v, OP_Expire); - } + else if( HasRowid(pTab) || pTblName!=0 ){ + Vdbe *v; + char *zStmt; + int iMem = ++pParse->nMem; + + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto exit_create_index; + + sqlite3BeginWriteOperation(pParse, 1, iDb); + + /* Create the rootpage for the index using CreateIndex. But before + ** doing so, code a Noop instruction and store its address in + ** Index.tnum. This is required in case this index is actually a + ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In + ** that case the convertToWithoutRowidTable() routine will replace + ** the Noop with a Goto to jump over the VDBE code generated below. */ + pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop); + sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); + + /* Gather the complete text of the CREATE INDEX statement into + ** the zStmt variable + */ + assert( pName!=0 || pStart==0 ); + if( pStart ){ + int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; + if( pName->z[n-1]==';' ) n--; + /* A named index with an explicit CREATE INDEX statement */ + zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", + onError==OE_None ? "" : " UNIQUE", n, pName->z); + }else{ + /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ + /* zStmt = sqlite3MPrintf(""); */ + zStmt = 0; + } - sqlite3VdbeJumpHere(v, pIndex->tnum); - } + /* Add an entry in sqlite_schema for this index + */ + sqlite3NestedParse(pParse, + "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);", + db->aDb[iDb].zDbSName, + pIndex->zName, + pTab->zName, + iMem, + zStmt + ); + sqlite3DbFree(db, zStmt); - /* When adding an index to the list of indices for a table, make - ** sure all indices labeled OE_Replace come after all those labeled - ** OE_Ignore. This is necessary for the correct constraint check - ** processing (in sqlite3GenerateConstraintChecks()) as part of - ** UPDATE and INSERT statements. - */ - if( db->init.busy || pTblName==0 ){ - if( onError!=OE_Replace || pTab->pIndex==0 - || pTab->pIndex->onError==OE_Replace){ - pIndex->pNext = pTab->pIndex; - pTab->pIndex = pIndex; - }else{ - Index *pOther = pTab->pIndex; - while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ - pOther = pOther->pNext; + /* Fill the index with data and reparse the schema. Code an OP_Expire + ** to invalidate all pre-compiled statements. + */ + if( pTblName ){ + sqlite3RefillIndex(pParse, pIndex, iMem); + sqlite3ChangeCookie(pParse, iDb); + sqlite3VdbeAddParseSchemaOp(v, iDb, + sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0); + sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); } - pIndex->pNext = pOther->pNext; - pOther->pNext = pIndex; + + sqlite3VdbeJumpHere(v, (int)pIndex->tnum); } + } + if( db->init.busy || pTblName==0 ){ + pIndex->pNext = pTab->pIndex; + pTab->pIndex = pIndex; + pIndex = 0; + } + else if( IN_RENAME_OBJECT ){ + assert( pParse->pNewIndex==0 ); + pParse->pNewIndex = pIndex; pIndex = 0; } /* Clean up before exiting */ exit_create_index: - if( pIndex ) freeIndex(db, pIndex); + if( pIndex ) sqlite3FreeIndex(db, pIndex); + if( pTab ){ + /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list. + ** The list was already ordered when this routine was entered, so at this + ** point at most a single index (the newly added index) will be out of + ** order. So we have to reorder at most one index. */ + Index **ppFrom; + Index *pThis; + for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){ + Index *pNext; + if( pThis->onError!=OE_Replace ) continue; + while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){ + *ppFrom = pNext; + pThis->pNext = pNext->pNext; + pNext->pNext = pThis; + ppFrom = &pNext->pNext; + } + break; + } +#ifdef SQLITE_DEBUG + /* Verify that all REPLACE indexes really are now at the end + ** of the index list. In other words, no other index type ever + ** comes after a REPLACE index on the list. */ + for(pThis = pTab->pIndex; pThis; pThis=pThis->pNext){ + assert( pThis->onError!=OE_Replace + || pThis->pNext==0 + || pThis->pNext->onError==OE_Replace ); + } +#endif + } sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); @@ -102605,18 +118405,33 @@ SQLITE_PRIVATE void sqlite3CreateIndex( ** are based on typical values found in actual indices. */ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){ - /* 10, 9, 8, 7, 6 */ - LogEst aVal[] = { 33, 32, 30, 28, 26 }; + /* 10, 9, 8, 7, 6 */ + static const LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; + LogEst x; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; - /* Set the first entry (number of rows in the index) to the estimated + /* Indexes with default row estimates should not have stat1 data */ + assert( !pIdx->hasStat1 ); + + /* Set the first entry (number of rows in the index) to the estimated ** number of rows in the table, or half the number of rows in the table - ** for a partial index. But do not let the estimate drop below 10. */ - a[0] = pIdx->pTable->nRowLogEst; - if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) ); - if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); + ** for a partial index. + ** + ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1 + ** table but other parts we are having to guess at, then do not let the + ** estimated number of rows in the table be less than 1000 (LogEst 99). + ** Failure to do this can cause the indexes for which we do not have + ** stat1 data to be ignored by the query planner. + */ + x = pIdx->pTable->nRowLogEst; + assert( 99==sqlite3LogEst(1000) ); + if( x<99 ){ + pIdx->pTable->nRowLogEst = x = 99; + } + if( pIdx->pPartIdxWhere!=0 ){ x -= 10; assert( 10==sqlite3LogEst(2) ); } + a[0] = x; /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is ** 6 and each subsequent value (if any) is 5. */ @@ -102639,10 +118454,10 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists sqlite3 *db = pParse->db; int iDb; - assert( pParse->nErr==0 ); /* Never called with prior errors */ if( db->mallocFailed ){ goto exit_drop_index; } + assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */ assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; @@ -102650,9 +118465,10 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ if( !ifExists ){ - sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); + sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); + sqlite3ForceNotReadOnly(pParse); } pParse->checkSchema = 1; goto exit_drop_index; @@ -102672,20 +118488,20 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } - if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX; + if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX; if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ goto exit_drop_index; } } #endif - /* Generate code to remove the index and from the master table */ + /* Generate code to remove the index and from the schema table */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, - "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", - db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName + "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'", + db->aDb[iDb].zDbSName, pIndex->zName ); sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName); sqlite3ChangeCookie(pParse, iDb); @@ -102722,9 +118538,9 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( int *pIdx /* Write the index of a new slot here */ ){ char *z; - int n = *pnEntry; + sqlite3_int64 n = *pIdx = *pnEntry; if( (n & (n-1))==0 ){ - int sz = (n==0) ? 1 : 2*n; + sqlite3_int64 sz = (n==0) ? 1 : 2*n; void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry); if( pNew==0 ){ *pIdx = -1; @@ -102734,7 +118550,6 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( } z = (char*)pArray; memset(&z[n * szEntry], 0, szEntry); - *pIdx = n; ++*pnEntry; return pArray; } @@ -102745,7 +118560,8 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( ** ** A new IdList is returned, or NULL if malloc() fails. */ -SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){ +SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){ + sqlite3 *db = pParse->db; int i; if( pList==0 ){ pList = sqlite3DbMallocZero(db, sizeof(IdList) ); @@ -102763,6 +118579,9 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pT return 0; } pList->a[i].zName = sqlite3NameFromToken(db, pToken); + if( IN_RENAME_OBJECT && pList->a[i].zName ){ + sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken); + } return pList; } @@ -102776,7 +118595,7 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ sqlite3DbFree(db, pList->a[i].zName); } sqlite3DbFree(db, pList->a); - sqlite3DbFree(db, pList); + sqlite3DbFreeNN(db, pList); } /* @@ -102792,6 +118611,18 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){ return -1; } +/* +** Maximum size of a SrcList object. +** The SrcList object is used to represent the FROM clause of a +** SELECT statement, and the query planner cannot deal with more +** than 64 tables in a join. So any value larger than 64 here +** is sufficient for most uses. Smaller values, like say 10, are +** appropriate for small and memory-limited applications. +*/ +#ifndef SQLITE_MAX_SRCLIST +# define SQLITE_MAX_SRCLIST 200 +#endif + /* ** Expand the space allocated for the given SrcList object by ** creating nExtra new slots beginning at iStart. iStart is zero based. @@ -102808,11 +118639,12 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){ ** the iStart value would be 0. The result then would ** be: nil, nil, nil, A, B. ** -** If a memory allocation fails the SrcList is unchanged. The -** db->mallocFailed flag will be set to true. +** If a memory allocation fails or the SrcList becomes too large, leave +** the original SrcList unchanged, return NULL, and leave an error message +** in pParse. */ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( - sqlite3 *db, /* Database connection to notify of OOM errors */ + Parse *pParse, /* Parsing context into which errors are reported */ SrcList *pSrc, /* The SrcList to be enlarged */ int nExtra, /* Number of new slots to add to pSrc->a[] */ int iStart /* Index in pSrc->a[] of first new slot */ @@ -102828,17 +118660,23 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( /* Allocate additional space if needed */ if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ SrcList *pNew; - int nAlloc = pSrc->nSrc*2+nExtra; - int nGot; + sqlite3_int64 nAlloc = 2*(sqlite3_int64)pSrc->nSrc+nExtra; + sqlite3 *db = pParse->db; + + if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){ + sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d", + SQLITE_MAX_SRCLIST); + return 0; + } + if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST; pNew = sqlite3DbRealloc(db, pSrc, sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) ); if( pNew==0 ){ assert( db->mallocFailed ); - return pSrc; + return 0; } pSrc = pNew; - nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1; - pSrc->nAlloc = nGot; + pSrc->nAlloc = nAlloc; } /* Move existing slots that come after the newly inserted slots @@ -102863,7 +118701,8 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( ** Append a new table name to the given SrcList. Create a new SrcList if ** need be. A new entry is created in the SrcList even if pTable is NULL. ** -** A SrcList is returned, or NULL if there is an OOM error. The returned +** A SrcList is returned, or NULL if there is an OOM error or if the +** SrcList grows to large. The returned ** SrcList might be the same as the SrcList that was input or it might be ** a new one. If an OOM error does occurs, then the prior value of pList ** that is input to this routine is automatically freed. @@ -102872,7 +118711,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( ** database name prefix. Like this: "database.table". The pDatabase ** points to the table name and the pTable points to the database name. ** The SrcList.a[].zName field is filled with the table name which might -** come from pTable (if pDatabase is NULL) or from pDatabase. +** come from pTable (if pDatabase is NULL) or from pDatabase. ** SrcList.a[].zDatabase is filled with the database name from pTable, ** or with NULL if no database is specified. ** @@ -102894,39 +118733,44 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( ** before being added to the SrcList. */ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( - sqlite3 *db, /* Connection to notify of malloc failures */ + Parse *pParse, /* Parsing context, in which errors are reported */ SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */ Token *pTable, /* Table to append */ Token *pDatabase /* Database of the table */ ){ - struct SrcList_item *pItem; + SrcItem *pItem; + sqlite3 *db; assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */ - assert( db!=0 ); + assert( pParse!=0 ); + assert( pParse->db!=0 ); + db = pParse->db; if( pList==0 ){ - pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) ); + pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) ); if( pList==0 ) return 0; pList->nAlloc = 1; pList->nSrc = 1; memset(&pList->a[0], 0, sizeof(pList->a[0])); pList->a[0].iCursor = -1; }else{ - pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc); - } - if( db->mallocFailed ){ - sqlite3SrcListDelete(db, pList); - return 0; + SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc); + if( pNew==0 ){ + sqlite3SrcListDelete(db, pList); + return 0; + }else{ + pList = pNew; + } } pItem = &pList->a[pList->nSrc-1]; if( pDatabase && pDatabase->z==0 ){ pDatabase = 0; } if( pDatabase ){ - Token *pTemp = pDatabase; - pDatabase = pTable; - pTable = pTemp; + pItem->zName = sqlite3NameFromToken(db, pDatabase); + pItem->zDatabase = sqlite3NameFromToken(db, pTable); + }else{ + pItem->zName = sqlite3NameFromToken(db, pTable); + pItem->zDatabase = 0; } - pItem->zName = sqlite3NameFromToken(db, pTable); - pItem->zDatabase = sqlite3NameFromToken(db, pDatabase); return pList; } @@ -102935,11 +118779,11 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend( */ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; - struct SrcList_item *pItem; - assert(pList || pParse->db->mallocFailed ); - if( pList ){ + SrcItem *pItem; + assert( pList || pParse->db->mallocFailed ); + if( ALWAYS(pList) ){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ - if( pItem->iCursor>=0 ) break; + if( pItem->iCursor>=0 ) continue; pItem->iCursor = pParse->nTab++; if( pItem->pSelect ){ sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); @@ -102953,20 +118797,20 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ */ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ int i; - struct SrcList_item *pItem; + SrcItem *pItem; if( pList==0 ) return; for(pItem=pList->a, i=0; inSrc; i++, pItem++){ - sqlite3DbFree(db, pItem->zDatabase); + if( pItem->zDatabase ) sqlite3DbFreeNN(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); - sqlite3DbFree(db, pItem->zAlias); + if( pItem->zAlias ) sqlite3DbFreeNN(db, pItem->zAlias); if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); sqlite3DeleteTable(db, pItem->pTab); - sqlite3SelectDelete(db, pItem->pSelect); - sqlite3ExprDelete(db, pItem->pOn); - sqlite3IdListDelete(db, pItem->pUsing); + if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect); + if( pItem->pOn ) sqlite3ExprDelete(db, pItem->pOn); + if( pItem->pUsing ) sqlite3IdListDelete(db, pItem->pUsing); } - sqlite3DbFree(db, pList); + sqlite3DbFreeNN(db, pList); } /* @@ -102995,19 +118839,26 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( Expr *pOn, /* The ON clause of a join */ IdList *pUsing /* The USING clause of a join */ ){ - struct SrcList_item *pItem; + SrcItem *pItem; sqlite3 *db = pParse->db; if( !p && (pOn || pUsing) ){ - sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", + sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", (pOn ? "ON" : "USING") ); goto append_from_error; } - p = sqlite3SrcListAppend(db, p, pTable, pDatabase); - if( p==0 || NEVER(p->nSrc==0) ){ + p = sqlite3SrcListAppend(pParse, p, pTable, pDatabase); + if( p==0 ){ goto append_from_error; } + assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; + assert( (pTable==0)==(pDatabase==0) ); + assert( pItem->zName==0 || pDatabase!=0 ); + if( IN_RENAME_OBJECT && pItem->zName ){ + Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable; + sqlite3RenameTokenMap(pParse, pItem->zName, pToken); + } assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); @@ -103017,7 +118868,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( pItem->pUsing = pUsing; return p; - append_from_error: +append_from_error: assert( p==0 ); sqlite3ExprDelete(db, pOn); sqlite3IdListDelete(db, pUsing); @@ -103026,25 +118877,48 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm( } /* -** Add an INDEXED BY or NOT INDEXED clause to the most recently added +** Add an INDEXED BY or NOT INDEXED clause to the most recently added ** element of the source-list passed as the second argument. */ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); - if( p && ALWAYS(p->nSrc>0) ){ - struct SrcList_item *pItem = &p->a[p->nSrc-1]; + if( p && pIndexedBy->n>0 ){ + SrcItem *pItem; + assert( p->nSrc>0 ); + pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); if( pIndexedBy->n==1 && !pIndexedBy->z ){ - /* A "NOT INDEXED" clause was supplied. See parse.y + /* A "NOT INDEXED" clause was supplied. See parse.y ** construct "indexed_opt" for details. */ pItem->fg.notIndexed = 1; }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); - pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0); + pItem->fg.isIndexedBy = 1; + assert( pItem->fg.isCte==0 ); /* No collision on union u2 */ + } + } +} + +/* +** Append the contents of SrcList p2 to SrcList p1 and return the resulting +** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2 +** are deleted by this function. +*/ +SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){ + assert( p1 && p1->nSrc==1 ); + if( p2 ){ + SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1); + if( pNew==0 ){ + sqlite3SrcListDelete(pParse->db, p2); + }else{ + p1 = pNew; + memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem)); + sqlite3DbFree(pParse->db, p2); } } + return p1; } /* @@ -103053,7 +118927,7 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI */ SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ if( p ){ - struct SrcList_item *pItem = &p->a[p->nSrc-1]; + SrcItem *pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); @@ -103107,7 +118981,16 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ if( !v ) return; if( type!=TK_DEFERRED ){ for(i=0; inDb; i++){ - sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); + int eTxnType; + Btree *pBt = db->aDb[i].pBt; + if( pBt && sqlite3BtreeIsReadonly(pBt) ){ + eTxnType = 0; /* Read txn */ + }else if( type==TK_EXCLUSIVE ){ + eTxnType = 2; /* Exclusive txn */ + }else{ + eTxnType = 1; /* Write txn */ + } + sqlite3VdbeAddOp2(v, OP_Transaction, i, eTxnType); sqlite3VdbeUsesBtree(v, i); } } @@ -103115,42 +118998,31 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ } /* -** Generate VDBE code for a COMMIT statement. +** Generate VDBE code for a COMMIT or ROLLBACK statement. +** Code for ROLLBACK is generated if eType==TK_ROLLBACK. Otherwise +** code is generated for a COMMIT. */ -SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){ +SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){ Vdbe *v; + int isRollback; assert( pParse!=0 ); assert( pParse->db!=0 ); - if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){ + assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK ); + isRollback = eType==TK_ROLLBACK; + if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, + isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( v ){ - sqlite3VdbeAddOp1(v, OP_AutoCommit, 1); - } -} - -/* -** Generate VDBE code for a ROLLBACK statement. -*/ -SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){ - Vdbe *v; - - assert( pParse!=0 ); - assert( pParse->db!=0 ); - if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){ - return; - } - v = sqlite3GetVdbe(pParse); - if( v ){ - sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1); + sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback); } } /* ** This function is called by the parser when it parses a command to create, -** release or rollback an SQL savepoint. +** release or rollback an SQL savepoint. */ SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){ char *zName = sqlite3NameFromToken(pParse->db, pName); @@ -103177,7 +119049,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ if( db->aDb[1].pBt==0 && !pParse->explain ){ int rc; Btree *pBt; - static const int flags = + static const int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | @@ -103193,7 +119065,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ } db->aDb[1].pBt = pBt; assert( db->aDb[1].pSchema ); - if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){ + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){ sqlite3OomFault(db); return 1; } @@ -103207,13 +119079,11 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ ** will occur at the end of the top-level VDBE and will be generated ** later, by sqlite3FinishCoding(). */ -SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ - Parse *pToplevel = sqlite3ParseToplevel(pParse); - - assert( iDb>=0 && iDbdb->nDb ); - assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 ); - assert( iDbdb, iDb, 0) ); +static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){ + assert( iDb>=0 && iDbdb->nDb ); + assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 ); + assert( iDbdb, iDb, 0) ); if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ DbMaskSet(pToplevel->cookieMask, iDb); if( !OMIT_TEMPDB && iDb==1 ){ @@ -103221,9 +119091,13 @@ SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ } } } +SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ + sqlite3CodeVerifySchemaAtToplevel(sqlite3ParseToplevel(pParse), iDb); +} + /* -** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each +** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each ** attached database. Otherwise, invoke it for the database named zDb only. */ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ @@ -103252,7 +119126,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb) */ SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchemaAtToplevel(pToplevel, iDb); DbMaskSet(pToplevel->writeMask, iDb); pToplevel->isMultiWrite |= setStatement; } @@ -103269,9 +119143,9 @@ SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){ pToplevel->isMultiWrite = 1; } -/* +/* ** The code generator calls this routine if is discovers that it is -** possible to abort a statement prior to completion. In order to +** possible to abort a statement prior to completion. In order to ** perform this abort without corrupting the database, we need to make ** sure that the statement is protected by a statement transaction. ** @@ -103280,7 +119154,7 @@ SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){ ** such that the abort must occur after the multiwrite. This makes ** some statements involving the REPLACE conflict resolution algorithm ** go a little faster. But taking advantage of this time dependency -** makes it more difficult to prove that the code is correct (in +** makes it more difficult to prove that the code is correct (in ** particular, it prevents us from writing an effective ** implementation of sqlite3AssertMayAbort()) and so we have chosen ** to take the safe route and skip the optimization. @@ -103303,8 +119177,10 @@ SQLITE_PRIVATE void sqlite3HaltConstraint( i8 p4type, /* P4_STATIC or P4_TRANSIENT */ u8 p5Errmsg /* P5_ErrMsg type */ ){ - Vdbe *v = sqlite3GetVdbe(pParse); - assert( (errCode&0xff)==SQLITE_CONSTRAINT ); + Vdbe *v; + assert( pParse->pVdbe!=0 ); + v = sqlite3GetVdbe(pParse); + assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested ); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); } @@ -103325,21 +119201,24 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( StrAccum errMsg; Table *pTab = pIdx->pTable; - sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); + sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, + pParse->db->aLimit[SQLITE_LIMIT_LENGTH]); if( pIdx->aColExpr ){ - sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName); + sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName); }else{ for(j=0; jnKeyCol; j++){ char *zCol; assert( pIdx->aiColumn[j]>=0 ); - zCol = pTab->aCol[pIdx->aiColumn[j]].zName; - if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); - sqlite3XPrintf(&errMsg, "%s.%s", pTab->zName, zCol); + zCol = pTab->aCol[pIdx->aiColumn[j]].zCnName; + if( j ) sqlite3_str_append(&errMsg, ", ", 2); + sqlite3_str_appendall(&errMsg, pTab->zName); + sqlite3_str_append(&errMsg, ".", 1); + sqlite3_str_appendall(&errMsg, zCol); } } zErr = sqlite3StrAccumFinish(&errMsg); - sqlite3HaltConstraint(pParse, - IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY + sqlite3HaltConstraint(pParse, + IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY : SQLITE_CONSTRAINT_UNIQUE, onError, zErr, P4_DYNAMIC, P5_ConstraintUnique); } @@ -103351,13 +119230,13 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( SQLITE_PRIVATE void sqlite3RowidConstraint( Parse *pParse, /* Parsing context */ int onError, /* Conflict resolution algorithm */ - Table *pTab /* The table with the non-unique rowid */ + Table *pTab /* The table with the non-unique rowid */ ){ char *zMsg; int rc; if( pTab->iPKey>=0 ){ zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName, - pTab->aCol[pTab->iPKey].zName); + pTab->aCol[pTab->iPKey].zCnName); rc = SQLITE_CONSTRAINT_PRIMARYKEY; }else{ zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName); @@ -103392,13 +119271,15 @@ static int collationMatch(const char *zColl, Index *pIndex){ */ #ifndef SQLITE_OMIT_REINDEX static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ - Index *pIndex; /* An index associated with pTab */ + if( !IsVirtual(pTab) ){ + Index *pIndex; /* An index associated with pTab */ - for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ - if( zColl==0 || collationMatch(zColl, pIndex) ){ - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3RefillIndex(pParse, pIndex, -1); + for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ + if( zColl==0 || collationMatch(zColl, pIndex) ){ + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3RefillIndex(pParse, pIndex, -1); + } } } } @@ -103519,9 +119400,22 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ const char *zColl = pIdx->azColl[i]; pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 : sqlite3LocateCollSeq(pParse, zColl); - pKey->aSortOrder[i] = pIdx->aSortOrder[i]; + pKey->aSortFlags[i] = pIdx->aSortOrder[i]; + assert( 0==(pKey->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) ); } if( pParse->nErr ){ + assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ ); + if( pIdx->bNoQuery==0 ){ + /* Deactivate the index because it contains an unknown collating + ** sequence. The only way to reactive the index is to reload the + ** schema. Adding the missing collating sequence later does not + ** reactive the index. The application had the chance to register + ** the missing index using the collation-needed callback. For + ** simplicity, SQLite will not give the application a second chance. + */ + pIdx->bNoQuery = 1; + pParse->rc = SQLITE_ERROR_RETRY; + } sqlite3KeyInfoUnref(pKey); pKey = 0; } @@ -103530,24 +119424,76 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ } #ifndef SQLITE_OMIT_CTE -/* -** This routine is invoked once per CTE by the parser while parsing a -** WITH clause. +/* +** Create a new CTE object */ -SQLITE_PRIVATE With *sqlite3WithAdd( +SQLITE_PRIVATE Cte *sqlite3CteNew( Parse *pParse, /* Parsing context */ - With *pWith, /* Existing WITH clause, or NULL */ Token *pName, /* Name of the common-table */ ExprList *pArglist, /* Optional column name list for the table */ - Select *pQuery /* Query used to initialize the table */ + Select *pQuery, /* Query used to initialize the table */ + u8 eM10d /* The MATERIALIZED flag */ +){ + Cte *pNew; + sqlite3 *db = pParse->db; + + pNew = sqlite3DbMallocZero(db, sizeof(*pNew)); + assert( pNew!=0 || db->mallocFailed ); + + if( db->mallocFailed ){ + sqlite3ExprListDelete(db, pArglist); + sqlite3SelectDelete(db, pQuery); + }else{ + pNew->pSelect = pQuery; + pNew->pCols = pArglist; + pNew->zName = sqlite3NameFromToken(pParse->db, pName); + pNew->eM10d = eM10d; + } + return pNew; +} + +/* +** Clear information from a Cte object, but do not deallocate storage +** for the object itself. +*/ +static void cteClear(sqlite3 *db, Cte *pCte){ + assert( pCte!=0 ); + sqlite3ExprListDelete(db, pCte->pCols); + sqlite3SelectDelete(db, pCte->pSelect); + sqlite3DbFree(db, pCte->zName); +} + +/* +** Free the contents of the CTE object passed as the second argument. +*/ +SQLITE_PRIVATE void sqlite3CteDelete(sqlite3 *db, Cte *pCte){ + assert( pCte!=0 ); + cteClear(db, pCte); + sqlite3DbFree(db, pCte); +} + +/* +** This routine is invoked once per CTE by the parser while parsing a +** WITH clause. The CTE described by teh third argument is added to +** the WITH clause of the second argument. If the second argument is +** NULL, then a new WITH argument is created. +*/ +SQLITE_PRIVATE With *sqlite3WithAdd( + Parse *pParse, /* Parsing context */ + With *pWith, /* Existing WITH clause, or NULL */ + Cte *pCte /* CTE to add to the WITH clause */ ){ sqlite3 *db = pParse->db; With *pNew; char *zName; + if( pCte==0 ){ + return pWith; + } + /* Check that the CTE name is unique within this WITH clause. If ** not, store an error in the Parse structure. */ - zName = sqlite3NameFromToken(pParse->db, pName); + zName = pCte->zName; if( zName && pWith ){ int i; for(i=0; inCte; i++){ @@ -103558,7 +119504,7 @@ SQLITE_PRIVATE With *sqlite3WithAdd( } if( pWith ){ - int nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); + sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); pNew = sqlite3DbRealloc(db, pWith, nByte); }else{ pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); @@ -103566,16 +119512,11 @@ SQLITE_PRIVATE With *sqlite3WithAdd( assert( (pNew!=0 && zName!=0) || db->mallocFailed ); if( db->mallocFailed ){ - sqlite3ExprListDelete(db, pArglist); - sqlite3SelectDelete(db, pQuery); - sqlite3DbFree(db, zName); + sqlite3CteDelete(db, pCte); pNew = pWith; }else{ - pNew->a[pNew->nCte].pSelect = pQuery; - pNew->a[pNew->nCte].pCols = pArglist; - pNew->a[pNew->nCte].zName = zName; - pNew->a[pNew->nCte].zCteErr = 0; - pNew->nCte++; + pNew->a[pNew->nCte++] = *pCte; + sqlite3DbFree(db, pCte); } return pNew; @@ -103588,10 +119529,7 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){ if( pWith ){ int i; for(i=0; inCte; i++){ - struct Cte *pCte = &pWith->a[i]; - sqlite3ExprListDelete(db, pCte->pCols); - sqlite3SelectDelete(db, pCte->pSelect); - sqlite3DbFree(db, pCte->zName); + cteClear(db, &pWith->a[i]); } sqlite3DbFree(db, pWith); } @@ -103601,7 +119539,7 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){ /************** End of build.c ***********************************************/ /************** Begin file callback.c ****************************************/ /* -** 2005 May 23 +** 2005 May 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -103667,50 +119605,6 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){ return SQLITE_ERROR; } -/* -** This function is responsible for invoking the collation factory callback -** or substituting a collation sequence of a different encoding when the -** requested collation sequence is not available in the desired encoding. -** -** If it is not NULL, then pColl must point to the database native encoding -** collation sequence with name zName, length nName. -** -** The return value is either the collation sequence to be used in database -** db for collation type name zName, length nName, or NULL, if no collation -** sequence can be found. If no collation is found, leave an error message. -** -** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq() -*/ -SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( - Parse *pParse, /* Parsing context */ - u8 enc, /* The desired encoding for the collating sequence */ - CollSeq *pColl, /* Collating sequence with native encoding, or NULL */ - const char *zName /* Collating sequence name */ -){ - CollSeq *p; - sqlite3 *db = pParse->db; - - p = pColl; - if( !p ){ - p = sqlite3FindCollSeq(db, enc, zName, 0); - } - if( !p || !p->xCmp ){ - /* No collation sequence of this type for this encoding is registered. - ** Call the collation factory to see if it can supply us with one. - */ - callCollNeeded(db, enc, zName); - p = sqlite3FindCollSeq(db, enc, zName, 0); - } - if( p && !p->xCmp && synthCollSeq(db, p) ){ - p = 0; - } - assert( !p || p->xCmp ); - if( p==0 ){ - sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); - } - return p; -} - /* ** This routine is called on a collation sequence before it is used to ** check that it is defined. An undefined collation sequence exists when @@ -103718,12 +119612,12 @@ SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( ** that have not been defined by sqlite3_create_collation() etc. ** ** If required, this routine calls the 'collation needed' callback to -** request a definition of the collating sequence. If this doesn't work, +** request a definition of the collating sequence. If this doesn't work, ** an equivalent collating sequence that uses a text encoding different ** from the main database is substituted, if one is available. */ SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ - if( pColl ){ + if( pColl && pColl->xCmp==0 ){ const char *zName = pColl->zName; sqlite3 *db = pParse->db; CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName); @@ -103759,8 +119653,8 @@ static CollSeq *findCollSeqEntry( pColl = sqlite3HashFind(&db->aCollSeq, zName); if( 0==pColl && create ){ - int nName = sqlite3Strlen30(zName); - pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1); + int nName = sqlite3Strlen30(zName) + 1; + pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName); if( pColl ){ CollSeq *pDel = 0; pColl[0].zName = (char*)&pColl[3]; @@ -103770,10 +119664,9 @@ static CollSeq *findCollSeqEntry( pColl[2].zName = (char*)&pColl[3]; pColl[2].enc = SQLITE_UTF16BE; memcpy(pColl[0].zName, zName, nName); - pColl[0].zName[nName] = 0; pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl); - /* If a malloc() failure occurred in sqlite3HashInsert(), it will + /* If a malloc() failure occurred in sqlite3HashInsert(), it will ** return the pColl pointer to be deleted (because it wasn't added ** to the hash table). */ @@ -103804,20 +119697,112 @@ static CollSeq *findCollSeqEntry( ** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq() */ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq( - sqlite3 *db, - u8 enc, - const char *zName, - int create + sqlite3 *db, /* Database connection to search */ + u8 enc, /* Desired text encoding */ + const char *zName, /* Name of the collating sequence. Might be NULL */ + int create /* True to create CollSeq if doesn't already exist */ ){ CollSeq *pColl; + assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); if( zName ){ pColl = findCollSeqEntry(db, zName, create); + if( pColl ) pColl += enc-1; }else{ pColl = db->pDfltColl; } - assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); - assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); - if( pColl ) pColl += enc-1; + return pColl; +} + +/* +** Change the text encoding for a database connection. This means that +** the pDfltColl must change as well. +*/ +SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){ + assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); + db->enc = enc; + /* EVIDENCE-OF: R-08308-17224 The default collating function for all + ** strings is BINARY. + */ + db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0); +} + +/* +** This function is responsible for invoking the collation factory callback +** or substituting a collation sequence of a different encoding when the +** requested collation sequence is not available in the desired encoding. +** +** If it is not NULL, then pColl must point to the database native encoding +** collation sequence with name zName, length nName. +** +** The return value is either the collation sequence to be used in database +** db for collation type name zName, length nName, or NULL, if no collation +** sequence can be found. If no collation is found, leave an error message. +** +** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq() +*/ +SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq( + Parse *pParse, /* Parsing context */ + u8 enc, /* The desired encoding for the collating sequence */ + CollSeq *pColl, /* Collating sequence with native encoding, or NULL */ + const char *zName /* Collating sequence name */ +){ + CollSeq *p; + sqlite3 *db = pParse->db; + + p = pColl; + if( !p ){ + p = sqlite3FindCollSeq(db, enc, zName, 0); + } + if( !p || !p->xCmp ){ + /* No collation sequence of this type for this encoding is registered. + ** Call the collation factory to see if it can supply us with one. + */ + callCollNeeded(db, enc, zName); + p = sqlite3FindCollSeq(db, enc, zName, 0); + } + if( p && !p->xCmp && synthCollSeq(db, p) ){ + p = 0; + } + assert( !p || p->xCmp ); + if( p==0 ){ + sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); + pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ; + } + return p; +} + +/* +** This function returns the collation sequence for database native text +** encoding identified by the string zName. +** +** If the requested collation sequence is not available, or not available +** in the database native encoding, the collation factory is invoked to +** request it. If the collation factory does not supply such a sequence, +** and the sequence is available in another text encoding, then that is +** returned instead. +** +** If no versions of the requested collations sequence are available, or +** another error occurs, NULL is returned and an error message written into +** pParse. +** +** This routine is a wrapper around sqlite3FindCollSeq(). This routine +** invokes the collation factory if the named collation cannot be found +** and generates an error message. +** +** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq() +*/ +SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){ + sqlite3 *db = pParse->db; + u8 enc = ENC(db); + u8 initbusy = db->init.busy; + CollSeq *pColl; + + pColl = sqlite3FindCollSeq(db, enc, zName, initbusy); + if( !initbusy && (!pColl || !pColl->xCmp) ){ + pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName); + } + return pColl; } @@ -103831,7 +119816,7 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq( ** is also -1. In other words, we are searching for a function that ** takes a variable number of arguments. ** -** If nArg is -2 that means that we are searching for any function +** If nArg is -2 that means that we are searching for any function ** regardless of the number of arguments it uses, so return a positive ** match score for any ** @@ -103856,12 +119841,13 @@ static int matchQuality( u8 enc /* Desired text encoding */ ){ int match; - - /* nArg of -2 is a special case */ - if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; + assert( p->nArg>=-1 ); /* Wrong number of arguments means "no match" */ - if( p->nArg!=nArg && p->nArg>=0 ) return 0; + if( p->nArg!=nArg ){ + if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; + if( p->nArg>=0 ) return 0; + } /* Give a better score to a function with a specific number of arguments ** than to function that accepts any number of arguments. */ @@ -103885,12 +119871,13 @@ static int matchQuality( ** Search a FuncDefHash for a function with the given name. Return ** a pointer to the matching FuncDef if found, or 0 if there is no match. */ -static FuncDef *functionSearch( +SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch( int h, /* Hash of the name */ const char *zFunc /* Name of function */ ){ FuncDef *p; for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ + assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); if( sqlite3StrICmp(p->zName, zFunc)==0 ){ return p; } @@ -103910,8 +119897,9 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( FuncDef *pOther; const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); - int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; - pOther = functionSearch(h, zName); + int h = SQLITE_FUNC_HASH(zName[0], nName); + assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN ); + pOther = sqlite3FunctionSearch(h, zName); if( pOther ){ assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); aDef[i].pNext = pOther->pNext; @@ -103923,8 +119911,8 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs( } } } - - + + /* ** Locate a user function given a name, a number of arguments and a flag @@ -103976,7 +119964,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( /* If no match is found, search the built-in functions. ** - ** If the SQLITE_PreferBuiltin flag is set, then search the built-in + ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in ** functions even if a prior app-defined function was found. And give ** priority to built-in functions. ** @@ -103985,11 +119973,11 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( ** have fields overwritten with new information appropriate for the ** new function. But the FuncDefs for built-in functions are read-only. ** So we must not search for built-ins when creating a new function. - */ - if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){ + */ + if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){ bestScore = 0; - h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; - p = functionSearch(h, zName); + h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName); + p = sqlite3FunctionSearch(h, zName); while( p ){ int score = matchQuality(p, nArg, enc); if( score>bestScore ){ @@ -104004,13 +119992,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( ** exact match for the name, number of arguments and encoding, then add a ** new entry to the hash table and return it. */ - if( createFlag && bestScorezName = (const char*)&pBest[1]; pBest->nArg = (u16)nArg; pBest->funcFlags = enc; memcpy((char*)&pBest[1], zName, nName+1); + for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z]; pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest); if( pOther==pBest ){ sqlite3DbFree(db, pBest); @@ -104029,7 +120019,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction( /* ** Free all resources held by the schema structure. The void* argument points -** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the +** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the ** pointer itself, it just cleans up subsidiary resources (i.e. the contents ** of the schema hash tables). ** @@ -104059,8 +120049,8 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){ pSchema->pSeqTab = 0; if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; - pSchema->schemaFlags &= ~DB_SchemaLoaded; } + pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted); } /* @@ -104109,7 +120099,7 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ ** (as in the FROM clause of a SELECT statement) in this case it contains ** the name of a single table, as one might find in an INSERT, DELETE, ** or UPDATE statement. Look up that table in the symbol table and -** return a pointer. Set an error message and return NULL if the table +** return a pointer. Set an error message and return NULL if the table ** name is not found or if any other error occurs. ** ** The following fields are initialized appropriate in pSrc: @@ -104119,49 +120109,72 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ ** */ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ - struct SrcList_item *pItem = pSrc->a; + SrcItem *pItem = pSrc->a; Table *pTab; - assert( pItem && pSrc->nSrc==1 ); + assert( pItem && pSrc->nSrc>=1 ); pTab = sqlite3LocateTableItem(pParse, 0, pItem); sqlite3DeleteTable(pParse->db, pItem->pTab); pItem->pTab = pTab; if( pTab ){ pTab->nTabRef++; - } - if( sqlite3IndexedByLookup(pParse, pItem) ){ - pTab = 0; + if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){ + pTab = 0; + } } return pTab; } +/* Generate byte-code that will report the number of rows modified +** by a DELETE, INSERT, or UPDATE statement. +*/ +SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *zColName){ + sqlite3VdbeAddOp0(v, OP_FkCheck); + sqlite3VdbeAddOp2(v, OP_ResultRow, regCounter, 1); + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zColName, SQLITE_STATIC); +} + +/* Return true if table pTab is read-only. +** +** A table is read-only if any of the following are true: +** +** 1) It is a virtual table and no implementation of the xUpdate method +** has been provided +** +** 2) It is a system table (i.e. sqlite_schema), this call is not +** part of a nested parse and writable_schema pragma has not +** been specified +** +** 3) The table is a shadow table, the database connection is in +** defensive mode, and the current sqlite3_prepare() +** is for a top-level SQL statement. +*/ +static int tabIsReadOnly(Parse *pParse, Table *pTab){ + sqlite3 *db; + if( IsVirtual(pTab) ){ + return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0; + } + if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0; + db = pParse->db; + if( (pTab->tabFlags & TF_Readonly)!=0 ){ + return sqlite3WritableSchema(db)==0 && pParse->nested==0; + } + assert( pTab->tabFlags & TF_Shadow ); + return sqlite3ReadOnlyShadowTables(db); +} + /* ** Check to make sure the given table is writable. If it is not ** writable, generate an error message and return 1. If it is ** writable return 0; */ SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ - /* A table is not writable under the following circumstances: - ** - ** 1) It is a virtual table and no implementation of the xUpdate method - ** has been provided, or - ** 2) It is a system table (i.e. sqlite_master), this call is not - ** part of a nested parse and writable_schema pragma has not - ** been specified. - ** - ** In either case leave an error message in pParse and return non-zero. - */ - if( ( IsVirtual(pTab) - && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ) - || ( (pTab->tabFlags & TF_Readonly)!=0 - && (pParse->db->flags & SQLITE_WriteSchema)==0 - && pParse->nested==0 ) - ){ + if( tabIsReadOnly(pParse, pTab) ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } - #ifndef SQLITE_OMIT_VIEW - if( !viewOk && pTab->pSelect ){ + if( !viewOk && IsView(pTab) ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } @@ -104180,6 +120193,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView( Parse *pParse, /* Parsing context */ Table *pView, /* View definition */ Expr *pWhere, /* Optional WHERE clause to be added */ + ExprList *pOrderBy, /* Optional ORDER BY clause */ + Expr *pLimit, /* Optional LIMIT clause */ int iCur /* Cursor number for ephemeral table */ ){ SelectDest dest; @@ -104188,7 +120203,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView( sqlite3 *db = pParse->db; int iDb = sqlite3SchemaToIndex(db, pView->pSchema); pWhere = sqlite3ExprDup(db, pWhere, 0); - pFrom = sqlite3SrcListAppend(db, 0, 0, 0); + pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); @@ -104196,8 +120211,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView( assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].pUsing==0 ); } - pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, - SF_IncludeHidden, 0, 0); + pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, + SF_IncludeHidden, pLimit); sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pSel, &dest); sqlite3SelectDelete(db, pSel); @@ -104219,71 +120234,89 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( Expr *pWhere, /* The WHERE clause. May be null */ ExprList *pOrderBy, /* The ORDER BY clause. May be null */ Expr *pLimit, /* The LIMIT clause. May be null */ - Expr *pOffset, /* The OFFSET clause. May be null */ char *zStmtType /* Either DELETE or UPDATE. For err msgs. */ ){ - Expr *pWhereRowid = NULL; /* WHERE rowid .. */ + sqlite3 *db = pParse->db; + Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */ Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */ - Expr *pSelectRowid = NULL; /* SELECT rowid ... */ ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */ SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */ Select *pSelect = NULL; /* Complete SELECT tree */ + Table *pTab; /* Check that there isn't an ORDER BY without a LIMIT clause. */ - if( pOrderBy && (pLimit == 0) ) { + if( pOrderBy && pLimit==0 ) { sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType); - goto limit_where_cleanup; + sqlite3ExprDelete(pParse->db, pWhere); + sqlite3ExprListDelete(pParse->db, pOrderBy); + return 0; } /* We only need to generate a select expression if there ** is a limit/offset term to enforce. */ if( pLimit == 0 ) { - /* if pLimit is null, pOffset will always be null as well. */ - assert( pOffset == 0 ); return pWhere; } - /* Generate a select expression tree to enforce the limit/offset + /* Generate a select expression tree to enforce the limit/offset ** term for the DELETE or UPDATE statement. For example: ** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1 ** becomes: - ** DELETE FROM table_a WHERE rowid IN ( + ** DELETE FROM table_a WHERE rowid IN ( ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1 ** ); */ - pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0); - if( pSelectRowid == 0 ) goto limit_where_cleanup; - pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid); - if( pEList == 0 ) goto limit_where_cleanup; + pTab = pSrc->a[0].pTab; + if( HasRowid(pTab) ){ + pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); + pEList = sqlite3ExprListAppend( + pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0) + ); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + if( pPk->nKeyCol==1 ){ + const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName; + pLhs = sqlite3Expr(db, TK_ID, zName); + pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName)); + }else{ + int i; + for(i=0; inKeyCol; i++){ + Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName); + pEList = sqlite3ExprListAppend(pParse, pEList, p); + } + pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( pLhs ){ + pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0); + } + } + } /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree ** and the SELECT subtree. */ - pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0); - if( pSelectSrc == 0 ) { - sqlite3ExprListDelete(pParse->db, pEList); - goto limit_where_cleanup; + pSrc->a[0].pTab = 0; + pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); + pSrc->a[0].pTab = pTab; + if( pSrc->a[0].fg.isIndexedBy ){ + assert( pSrc->a[0].fg.isCte==0 ); + pSrc->a[0].u2.pIBIndex = 0; + pSrc->a[0].fg.isIndexedBy = 0; + sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy); + }else if( pSrc->a[0].fg.isCte ){ + pSrc->a[0].u2.pCteUse->nUse++; } /* generate the SELECT expression tree. */ - pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0, - pOrderBy,0,pLimit,pOffset); - if( pSelect == 0 ) return 0; + pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0, + pOrderBy,0,pLimit + ); /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */ - pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0); - pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0) : 0; + pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0); sqlite3PExprAddSelect(pParse, pInClause, pSelect); return pInClause; - -limit_where_cleanup: - sqlite3ExprDelete(pParse->db, pWhere); - sqlite3ExprListDelete(pParse->db, pOrderBy); - sqlite3ExprDelete(pParse->db, pLimit); - sqlite3ExprDelete(pParse->db, pOffset); - return 0; } #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */ /* && !defined(SQLITE_OMIT_SUBQUERY) */ @@ -104298,7 +120331,9 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere( SQLITE_PRIVATE void sqlite3DeleteFrom( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table from which we should delete things */ - Expr *pWhere /* The WHERE clause. May be null */ + Expr *pWhere, /* The WHERE clause. May be null */ + ExprList *pOrderBy, /* ORDER BY clause. May be null */ + Expr *pLimit /* LIMIT clause. May be null */ ){ Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ @@ -104313,7 +120348,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( AuthContext sContext; /* Authorization context */ NameContext sNC; /* Name context to resolve expressions in */ int iDb; /* Database number */ - int memCnt = -1; /* Memory cell used for change counting */ + int memCnt = 0; /* Memory cell used for change counting */ int rcauth; /* Value returned by authorization callback */ int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */ @@ -104330,7 +120365,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ int bComplex; /* True if there are triggers or FKs or ** subqueries in the WHERE clause */ - + #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ Trigger *pTrigger; /* List of table triggers, if required */ @@ -104338,11 +120373,14 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( memset(&sContext, 0, sizeof(sContext)); db = pParse->db; - if( pParse->nErr || db->mallocFailed ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto delete_from_cleanup; } + assert( db->mallocFailed==0 ); assert( pTabList->nSrc==1 ); + /* Locate the table which we want to delete. This table has to be ** put in an SrcList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect @@ -104356,17 +120394,27 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); - isView = pTab->pSelect!=0; - bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); + isView = IsView(pTab); #else # define pTrigger 0 # define isView 0 #endif + bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + if( !isView ){ + pWhere = sqlite3LimitWhere( + pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE" + ); + pOrderBy = 0; + pLimit = 0; + } +#endif + /* If pTab is really a view, make sure it has been initialized. */ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ @@ -104378,7 +120426,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDbnDb ); - rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, + rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, db->aDb[iDb].zDbSName); assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); if( rcauth==SQLITE_DENY ){ @@ -104407,15 +120455,19 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( goto delete_from_cleanup; } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, 1, iDb); + sqlite3BeginWriteOperation(pParse, bComplex, iDb); /* If we are trying to delete from a view, realize that view into ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ - sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur); + sqlite3MaterializeView(pParse, pTab, + pWhere, pOrderBy, pLimit, iTabCur + ); iDataCur = iIdxCur = iTabCur; + pOrderBy = 0; + pLimit = 0; } #endif @@ -104431,7 +120483,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( /* Initialize the counter of the number of rows deleted, if ** we are counting rows. */ - if( db->flags & SQLITE_CountRows ){ + if( (db->flags & SQLITE_CountRows)!=0 + && !pParse->nested + && !pParse->pTriggerTab + && !pParse->bReturning + ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); } @@ -104439,8 +120495,15 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to erase the whole table. Prior to version 3.6.5, - ** this optimization caused the row change count (the value returned by - ** API function sqlite3_count_changes) to be set incorrectly. */ + ** this optimization caused the row change count (the value returned by + ** API function sqlite3_count_changes) to be set incorrectly. + ** + ** The "rcauth==SQLITE_OK" terms is the + ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and + ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but + ** the truncate optimization is disabled and all rows are deleted + ** individually. + */ if( rcauth==SQLITE_OK && pWhere==0 && !bComplex @@ -104452,17 +120515,20 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( assert( !isView ); sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); if( HasRowid(pTab) ){ - sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt, + sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1, pTab->zName, P4_STATIC); } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ + sqlite3VdbeChangeP3(v, -1, memCnt ? memCnt : -1); + } } }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { - u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE; + u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); if( HasRowid(pTab) ){ @@ -104483,7 +120549,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } - + /* Construct a query to find the rowid or primary key for every row ** to be deleted, based on the WHERE clause. Set variable eOnePass ** to indicate the strategy used to implement this delete: @@ -104492,17 +120558,21 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( ** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,0,wcf,iTabCur+1); if( pWInfo==0 ) goto delete_from_cleanup; eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); - + if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); + if( sqlite3WhereUsesDeferredSeek(pWInfo) ){ + sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur); + } + /* Keep track of the number of rows to be deleted */ - if( db->flags & SQLITE_CountRows ){ + if( memCnt ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } - + /* Extract the rowid or primary key for the current row */ if( pPk ){ for(i=0; inMem + 1; - iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0); - if( iKey>pParse->nMem ) pParse->nMem = iKey; + iKey = ++pParse->nMem; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey); } - + if( eOnePass!=ONEPASS_OFF ){ /* For ONEPASS, no need to store the rowid/primary-key. There is only ** one, so just keep it in its register(s) and fall through to the @@ -104532,6 +120601,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0; if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); + addrBypass = sqlite3VdbeMakeLabel(pParse); }else{ if( pPk ){ /* Add the PK key for this row to the temporary table */ @@ -104542,22 +120612,15 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk); }else{ /* Add the rowid of the row to be deleted to the RowSet */ - nKey = 1; /* OP_Seek always uses a single rowid */ + nKey = 1; /* OP_DeferredSeek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } - } - - /* If this DELETE cannot use the ONEPASS strategy, this is the - ** end of the WHERE loop */ - if( eOnePass!=ONEPASS_OFF ){ - addrBypass = sqlite3VdbeMakeLabel(v); - }else{ sqlite3WhereEnd(pWInfo); } - - /* Unless this is a view, open cursors for the table we are + + /* Unless this is a view, open cursors for the table we are ** deleting from and all its indices. If this is a view, then the - ** only effect this statement has is to fire the INSTEAD OF + ** only effect this statement has is to fire the INSTEAD OF ** triggers. */ if( !isView ){ @@ -104570,41 +120633,50 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( iTabCur, aToOpen, &iDataCur, &iIdxCur); assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); - if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce); + if( eOnePass==ONEPASS_MULTI ){ + sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce); + } } - + /* Set up a loop over the rowids/primary-keys that were found in the ** where-clause loop above. */ if( eOnePass!=ONEPASS_OFF ){ assert( nKey==nPk ); /* OP_Found will use an unpacked key */ if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ - assert( pPk!=0 || pTab->pSelect!=0 ); + assert( pPk!=0 || IsView(pTab) ); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); VdbeCoverage(v); } }else if( pPk ){ addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey); + if( IsVirtual(pTab) ){ + sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey); + }else{ + sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey); + } assert( nKey==0 ); /* OP_Found will use a composite key */ }else{ addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey); VdbeCoverage(v); assert( nKey==1 ); - } - + } + /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); - sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); - sqlite3VdbeChangeP5(v, OE_Abort); assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); sqlite3MayAbort(pParse); - if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){ - pParse->isMultiWrite = 0; + if( eOnePass==ONEPASS_SINGLE ){ + sqlite3VdbeAddOp1(v, OP_Close, iTabCur); + if( sqlite3IsToplevel(pParse) ){ + pParse->isMultiWrite = 0; + } } + sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB); + sqlite3VdbeChangeP5(v, OE_Abort); }else #endif { @@ -104612,7 +120684,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]); } - + /* End of the loop over all rowids/primary-keys. */ if( eOnePass!=ONEPASS_OFF ){ sqlite3VdbeResolveLabel(v, addrBypass); @@ -104623,7 +120695,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( }else{ sqlite3VdbeGoto(v, addrLoop); sqlite3VdbeJumpHere(v, addrLoop); - } + } } /* End non-truncate path */ /* Update the sqlite_sequence table by storing the content of the @@ -104634,20 +120706,22 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( sqlite3AutoincrementEnd(pParse); } - /* Return the number of rows that were deleted. If this routine is + /* Return the number of rows that were deleted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ - if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ - sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1); - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC); + if( memCnt ){ + sqlite3CodeChangeCount(v, memCnt, "rows deleted"); } delete_from_cleanup: sqlite3AuthContextPop(&sContext); sqlite3SrcListDelete(db, pTabList); sqlite3ExprDelete(db, pWhere); +#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) + sqlite3ExprListDelete(db, pOrderBy); + sqlite3ExprDelete(db, pLimit); +#endif sqlite3DbFree(db, aToOpen); return; } @@ -104689,7 +120763,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( ** and nPk before reading from it. ** ** If eMode is ONEPASS_MULTI, then this call is being made as part -** of a ONEPASS delete that affects multiple rows. In this case, if +** of a ONEPASS delete that affects multiple rows. In this case, if ** iIdxNoSeek is a valid cursor number (>=0) and is not the same as ** iDataCur, then its position should be preserved following the delete ** operation. Or, if iIdxNoSeek is not a valid cursor number, the @@ -104725,17 +120799,17 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)", iDataCur, iIdxCur, iPk, (int)nPk)); - /* Seek cursor iCur to the row to delete. If this row no longer exists + /* Seek cursor iCur to the row to delete. If this row no longer exists ** (this can happen if a trigger program has already deleted it), do ** not attempt to delete it or fire any DELETE triggers. */ - iLabel = sqlite3VdbeMakeLabel(v); + iLabel = sqlite3VdbeMakeLabel(pParse); opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound; if( eMode==ONEPASS_OFF ){ sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); VdbeCoverageIf(v, opSeek==OP_NotExists); VdbeCoverageIf(v, opSeek==OP_NotFound); } - + /* If there are any triggers to fire, allocate a range of registers to ** use for the old.* references in the triggers. */ if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){ @@ -104752,24 +120826,25 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( iOld = pParse->nMem+1; pParse->nMem += (1 + pTab->nCol); - /* Populate the OLD.* pseudo-table register array. These values will be + /* Populate the OLD.* pseudo-table register array. These values will be ** used by any BEFORE and AFTER triggers that exist. */ sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld); for(iCol=0; iColnCol; iCol++){ testcase( mask!=0xffffffff && iCol==31 ); testcase( mask!=0xffffffff && iCol==32 ); if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1); + int kk = sqlite3TableColumnToStorage(pTab, iCol); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+kk+1); } } /* Invoke BEFORE DELETE trigger programs. */ addrStart = sqlite3VdbeCurrentAddr(v); - sqlite3CodeRowTrigger(pParse, pTrigger, + sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel ); - /* If any BEFORE triggers were coded, then seek the cursor to the + /* If any BEFORE triggers were coded, then seek the cursor to the ** row to be deleted again. It may be that the BEFORE triggers moved ** the cursor or already deleted the row that the cursor was ** pointing to. @@ -104786,26 +120861,26 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( } /* Do FK processing. This call checks that any FK constraints that - ** refer to this table (i.e. constraints attached to other tables) + ** refer to this table (i.e. constraints attached to other tables) ** are not violated by deleting this row. */ sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0); } /* Delete the index and table entries. Skip this step if pTab is really ** a view (in which case the only effect of the DELETE statement is to - ** fire the INSTEAD OF triggers). + ** fire the INSTEAD OF triggers). ** ** If variable 'count' is non-zero, then this OP_Delete instruction should ** invoke the update-hook. The pre-update-hook, on the other hand should ** be invoked unless table pTab is a system table. The difference is that - ** the update-hook is not invoked for rows removed by REPLACE, but the + ** the update-hook is not invoked for rows removed by REPLACE, but the ** pre-update-hook is. - */ - if( pTab->pSelect==0 ){ + */ + if( !IsView(pTab) ){ u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); - if( pParse->nested==0 ){ + if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){ sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); } if( eMode!=ONEPASS_OFF ){ @@ -104820,16 +120895,16 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete( /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to ** handle rows (possibly in other tables) that refer via a foreign key - ** to the row just deleted. */ + ** to the row just deleted. */ sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0); /* Invoke AFTER DELETE trigger programs. */ - sqlite3CodeRowTrigger(pParse, pTrigger, + sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel ); /* Jump here if the row had already been deleted before any BEFORE - ** trigger programs were invoked. Or if a trigger program throws a + ** trigger programs were invoked. Or if a trigger program throws a ** RAISE(IGNORE) exception. */ sqlite3VdbeResolveLabel(v, iLabel); VdbeModuleComment((v, "END: GenRowDel()")); @@ -104881,6 +120956,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); + sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */ sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } @@ -104913,7 +120989,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( ** its key into the same sequence of registers and if pPrior and pIdx share ** a column in common, then the register corresponding to that column already ** holds the correct value and the loading of that register is skipped. -** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK +** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK ** on a table with multiple indices, and especially with the ROWID or ** PRIMARY KEY columns of the index. */ @@ -104934,11 +121010,13 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ - *piPartIdxLabel = sqlite3VdbeMakeLabel(v); - pParse->iSelfTab = iDataCur; - sqlite3ExprCachePush(pParse); - sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, + *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse); + pParse->iSelfTab = iDataCur + 1; + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); + pParse->iSelfTab = 0; + pPrior = 0; /* Ticket a9efb42811fa41ee 2019-11-02; + ** pPartIdxWhere may have corrupted regPrior registers */ }else{ *piPartIdxLabel = 0; } @@ -104955,20 +121033,18 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( continue; } sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); - /* If the column affinity is REAL but the number is an integer, then it - ** might be stored in the table as an integer (using a compact - ** representation) then converted to REAL by an OP_RealAffinity opcode. - ** But we are getting ready to store this value back into an index, where - ** it should be converted by to INTEGER again. So omit the OP_RealAffinity - ** opcode if it is present */ - sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); + if( pIdx->aiColumn[j]>=0 ){ + /* If the column affinity is REAL but the number is an integer, then it + ** might be stored in the table as an integer (using a compact + ** representation) then converted to REAL by an OP_RealAffinity opcode. + ** But we are getting ready to store this value back into an index, where + ** it should be converted by to INTEGER again. So omit the + ** OP_RealAffinity opcode if it is present */ + sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); + } } if( regOut ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); - if( pIdx->pTable->pSelect ){ - const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx); - sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT); - } } sqlite3ReleaseTempRange(pParse, regBase, nCol); return regBase; @@ -104982,7 +121058,6 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ if( iLabel ){ sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); - sqlite3ExprCachePop(pParse); } } @@ -105006,6 +121081,9 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ /* #include "sqliteInt.h" */ /* #include */ /* #include */ +#ifndef SQLITE_OMIT_FLOATING_POINT +/* #include */ +#endif /* #include "vdbeInt.h" */ /* @@ -105025,6 +121103,8 @@ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ ** iteration of the aggregate loop. */ static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){ + assert( context->isError<=0 ); + context->isError = -1; context->skipFlag = 1; } @@ -105066,18 +121146,34 @@ static void typeofFunc( int NotUsed, sqlite3_value **argv ){ - const char *z = 0; + static const char *azType[] = { "integer", "real", "text", "blob", "null" }; + int i = sqlite3_value_type(argv[0]) - 1; UNUSED_PARAMETER(NotUsed); - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_INTEGER: z = "integer"; break; - case SQLITE_TEXT: z = "text"; break; - case SQLITE_FLOAT: z = "real"; break; - case SQLITE_BLOB: z = "blob"; break; - default: z = "null"; break; - } - sqlite3_result_text(context, z, -1, SQLITE_STATIC); + assert( i>=0 && i=0xc0 ){ + while( (*z & 0xc0)==0x80 ){ z++; z0++; } + } } - sqlite3_result_int(context, len); + sqlite3_result_int(context, (int)(z-z0)); break; } default: { @@ -105120,7 +121218,7 @@ static void lengthFunc( ** Implementation of the abs() function. ** ** IMP: R-23979-26855 The abs(X) function returns the absolute value of -** the numeric argument X. +** the numeric argument X. */ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ assert( argc==1 ); @@ -105137,7 +121235,7 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ return; } iVal = -iVal; - } + } sqlite3_result_int64(context, iVal); break; } @@ -105183,6 +121281,9 @@ static void instrFunc( int typeHaystack, typeNeedle; int N = 1; int isText; + unsigned char firstChar; + sqlite3_value *pC1 = 0; + sqlite3_value *pC2 = 0; UNUSED_PARAMETER(argc); typeHaystack = sqlite3_value_type(argv[0]); @@ -105194,16 +121295,27 @@ static void instrFunc( if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ zHaystack = sqlite3_value_blob(argv[0]); zNeedle = sqlite3_value_blob(argv[1]); - assert( zNeedle!=0 ); - assert( zHaystack!=0 || nHaystack==0 ); isText = 0; - }else{ + }else if( typeHaystack!=SQLITE_BLOB && typeNeedle!=SQLITE_BLOB ){ zHaystack = sqlite3_value_text(argv[0]); zNeedle = sqlite3_value_text(argv[1]); isText = 1; - if( zHaystack==0 || zNeedle==0 ) return; + }else{ + pC1 = sqlite3_value_dup(argv[0]); + zHaystack = sqlite3_value_text(pC1); + if( zHaystack==0 ) goto endInstrOOM; + nHaystack = sqlite3_value_bytes(pC1); + pC2 = sqlite3_value_dup(argv[1]); + zNeedle = sqlite3_value_text(pC2); + if( zNeedle==0 ) goto endInstrOOM; + nNeedle = sqlite3_value_bytes(pC2); + isText = 1; } - while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ + if( zNeedle==0 || (nHaystack && zHaystack==0) ) goto endInstrOOM; + firstChar = zNeedle[0]; + while( nNeedle<=nHaystack + && (zHaystack[0]!=firstChar || memcmp(zHaystack, zNeedle, nNeedle)!=0) + ){ N++; do{ nHaystack--; @@ -105213,10 +121325,17 @@ static void instrFunc( if( nNeedle>nHaystack ) N = 0; } sqlite3_result_int(context, N); +endInstr: + sqlite3_value_free(pC1); + sqlite3_value_free(pC2); + return; +endInstrOOM: + sqlite3_result_error_nomem(context); + goto endInstr; } /* -** Implementation of the printf() function. +** Implementation of the printf() (a.k.a. format()) SQL function. */ static void printfFunc( sqlite3_context *context, @@ -105235,7 +121354,7 @@ static void printfFunc( x.apArg = argv+1; sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); str.printfFlags = SQLITE_PRINTF_SQLFUNC; - sqlite3XPrintf(&str, zFormat, &x); + sqlite3_str_appendf(&str, zFormat, &x); n = str.nChar; sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, SQLITE_DYNAMIC); @@ -105366,10 +121485,10 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ ** handle the rounding directly, ** otherwise use printf. */ - if( n==0 && r>=0 && r+4503599627370496.0 ){ + /* The value has no fractional part so there is nothing to round */ + }else if( n==0 ){ + r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ zBuf = sqlite3_mprintf("%.*f",n,r); if( zBuf==0 ){ @@ -105461,7 +121580,7 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ #define noopFunc versionFunc /* Substitute function - never called */ /* -** Implementation of random(). Return a random integer. +** Implementation of random(). Return a random integer. */ static void randomFunc( sqlite3_context *context, @@ -105472,11 +121591,11 @@ static void randomFunc( UNUSED_PARAMETER2(NotUsed, NotUsed2); sqlite3_randomness(sizeof(r), &r); if( r<0 ){ - /* We need to prevent a random number of 0x8000000000000000 + /* We need to prevent a random number of 0x8000000000000000 ** (or -9223372036854775808) since when you do abs() of that ** number of you get the same value back again. To do this ** in a way that is testable, mask the sign bit off of negative - ** values, resulting in a positive value. Then take the + ** values, resulting in a positive value. Then take the ** 2s complement of that positive value. The end result can ** therefore be no less than -9223372036854775807. */ @@ -105494,11 +121613,11 @@ static void randomBlob( int argc, sqlite3_value **argv ){ - int n; + sqlite3_int64 n; unsigned char *p; assert( argc==1 ); UNUSED_PARAMETER(argc); - n = sqlite3_value_int(argv[0]); + n = sqlite3_value_int64(argv[0]); if( n<1 ){ n = 1; } @@ -105514,8 +121633,8 @@ static void randomBlob( ** value is the same as the sqlite3_last_insert_rowid() API function. */ static void last_insert_rowid( - sqlite3_context *context, - int NotUsed, + sqlite3_context *context, + int NotUsed, sqlite3_value **NotUsed2 ){ sqlite3 *db = sqlite3_context_db_handle(context); @@ -105529,9 +121648,9 @@ static void last_insert_rowid( /* ** Implementation of the changes() SQL function. ** -** IMP: R-62073-11209 The changes() SQL function is a wrapper -** around the sqlite3_changes() C/C++ function and hence follows the same -** rules for counting changes. +** IMP: R-32760-32347 The changes() SQL function is a wrapper +** around the sqlite3_changes64() C/C++ function and hence follows the +** same rules for counting changes. */ static void changes( sqlite3_context *context, @@ -105540,12 +121659,12 @@ static void changes( ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); - sqlite3_result_int(context, sqlite3_changes(db)); + sqlite3_result_int64(context, sqlite3_changes64(db)); } /* ** Implementation of the total_changes() SQL function. The return value is -** the same as the sqlite3_total_changes() API function. +** the same as the sqlite3_total_changes64() API function. */ static void total_changes( sqlite3_context *context, @@ -105554,9 +121673,9 @@ static void total_changes( ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); - /* IMP: R-52756-41993 This function is a wrapper around the - ** sqlite3_total_changes() C/C++ interface. */ - sqlite3_result_int(context, sqlite3_total_changes(db)); + /* IMP: R-11217-42568 This function is a wrapper around the + ** sqlite3_total_changes64() C/C++ interface. */ + sqlite3_result_int64(context, sqlite3_total_changes64(db)); } /* @@ -105623,7 +121742,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; ** it the last character in the list. ** ** Like matching rules: -** +** ** '%' Matches any sequence of zero or more characters ** *** '_' Matches any one character @@ -105646,13 +121765,14 @@ static int patternCompare( u32 matchAll = pInfo->matchAll; /* "*" or "%" */ u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ const u8 *zEscaped = 0; /* One past the last escaped input char */ - + while( (c = Utf8Read(zPattern))!=0 ){ if( c==matchAll ){ /* Match "*" */ /* Skip over multiple "*" characters in the pattern. If there ** are also "?" characters, skip those as well, but consume a ** single character of the input string for each "?" skipped */ - while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){ + while( (c=Utf8Read(zPattern)) == matchAll + || (c == matchOne && matchOne!=0) ){ if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ return SQLITE_NOWILDCARDMATCH; } @@ -105686,16 +121806,20 @@ static int patternCompare( ** c or cx. */ if( c<=0x80 ){ - u32 cx; + char zStop[3]; int bMatch; if( noCase ){ - cx = sqlite3Toupper(c); - c = sqlite3Tolower(c); + zStop[0] = sqlite3Toupper(c); + zStop[1] = sqlite3Tolower(c); + zStop[2] = 0; }else{ - cx = c; + zStop[0] = c; + zStop[1] = 0; } - while( (c2 = *(zString++))!=0 ){ - if( c2!=c && c2!=cx ) continue; + while(1){ + zString += strcspn((const char*)zString, zStop); + if( zString[0]==0 ) break; + zString++; bMatch = patternCompare(zPattern,zString,pInfo,matchOther); if( bMatch!=SQLITE_NOMATCH ) return bMatch; } @@ -105798,8 +121922,8 @@ SQLITE_API int sqlite3_like_count = 0; ** the GLOB operator. */ static void likeFunc( - sqlite3_context *context, - int argc, + sqlite3_context *context, + int argc, sqlite3_value **argv ){ const unsigned char *zA, *zB; @@ -105807,6 +121931,7 @@ static void likeFunc( int nPat; sqlite3 *db = sqlite3_context_db_handle(context); struct compareInfo *pInfo = sqlite3_user_data(context); + struct compareInfo backupInfo; #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( sqlite3_value_type(argv[0])==SQLITE_BLOB @@ -105819,8 +121944,6 @@ static void likeFunc( return; } #endif - zB = sqlite3_value_text(argv[0]); - zA = sqlite3_value_text(argv[1]); /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). @@ -105832,8 +121955,6 @@ static void likeFunc( sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } - assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ - if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. @@ -105841,19 +121962,28 @@ static void likeFunc( const unsigned char *zEsc = sqlite3_value_text(argv[2]); if( zEsc==0 ) return; if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ - sqlite3_result_error(context, + sqlite3_result_error(context, "ESCAPE expression must be a single character", -1); return; } escape = sqlite3Utf8Read(&zEsc); + if( escape==pInfo->matchAll || escape==pInfo->matchOne ){ + memcpy(&backupInfo, pInfo, sizeof(backupInfo)); + pInfo = &backupInfo; + if( escape==pInfo->matchAll ) pInfo->matchAll = 0; + if( escape==pInfo->matchOne ) pInfo->matchOne = 0; + } }else{ escape = pInfo->matchSet; } + zB = sqlite3_value_text(argv[0]); + zA = sqlite3_value_text(argv[1]); if( zA && zB ){ #ifdef SQLITE_TEST sqlite3_like_count++; #endif - sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); + sqlite3_result_int(context, + patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); } } @@ -105945,8 +122075,8 @@ static void compileoptionusedFunc( #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ /* -** Implementation of the sqlite_compileoption_get() function. -** The result is a string that identifies the compiler options +** Implementation of the sqlite_compileoption_get() function. +** The result is a string that identifies the compiler options ** used to build SQLite. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS @@ -105970,43 +122100,46 @@ static void compileoptiongetFunc( ** digits. */ static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /* -** Implementation of the QUOTE() function. This function takes a single -** argument. If the argument is numeric, the return value is the same as -** the argument. If the argument is NULL, the return value is the string -** "NULL". Otherwise, the argument is enclosed in single quotes with -** single-quote escapes. +** Append to pStr text that is the SQL literal representation of the +** value contained in pValue. */ -static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ - assert( argc==1 ); - UNUSED_PARAMETER(argc); - switch( sqlite3_value_type(argv[0]) ){ +SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){ + /* As currently implemented, the string must be initially empty. + ** we might relax this requirement in the future, but that will + ** require enhancements to the implementation. */ + assert( pStr!=0 && pStr->nChar==0 ); + + switch( sqlite3_value_type(pValue) ){ case SQLITE_FLOAT: { double r1, r2; - char zBuf[50]; - r1 = sqlite3_value_double(argv[0]); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1); - sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8); - if( r1!=r2 ){ - sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1); + const char *zVal; + r1 = sqlite3_value_double(pValue); + sqlite3_str_appendf(pStr, "%!.15g", r1); + zVal = sqlite3_str_value(pStr); + if( zVal ){ + sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); + if( r1!=r2 ){ + sqlite3_str_reset(pStr); + sqlite3_str_appendf(pStr, "%!.20e", r1); + } } - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); break; } case SQLITE_INTEGER: { - sqlite3_result_value(context, argv[0]); + sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue)); break; } case SQLITE_BLOB: { - char *zText = 0; - char const *zBlob = sqlite3_value_blob(argv[0]); - int nBlob = sqlite3_value_bytes(argv[0]); - assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ - zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4); - if( zText ){ + char const *zBlob = sqlite3_value_blob(pValue); + int nBlob = sqlite3_value_bytes(pValue); + assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */ + sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4); + if( pStr->accError==0 ){ + char *zText = pStr->zText; int i; for(i=0; i>4)&0x0F]; @@ -106016,45 +122149,51 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ zText[(nBlob*2)+3] = '\0'; zText[0] = 'X'; zText[1] = '\''; - sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); - sqlite3_free(zText); + pStr->nChar = nBlob*2 + 3; } break; } case SQLITE_TEXT: { - int i,j; - u64 n; - const unsigned char *zArg = sqlite3_value_text(argv[0]); - char *z; - - if( zArg==0 ) return; - for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; } - z = contextMalloc(context, ((i64)i)+((i64)n)+3); - if( z ){ - z[0] = '\''; - for(i=0, j=1; zArg[i]; i++){ - z[j++] = zArg[i]; - if( zArg[i]=='\'' ){ - z[j++] = '\''; - } - } - z[j++] = '\''; - z[j] = 0; - sqlite3_result_text(context, z, j, sqlite3_free); - } + const unsigned char *zArg = sqlite3_value_text(pValue); + sqlite3_str_appendf(pStr, "%Q", zArg); break; } default: { - assert( sqlite3_value_type(argv[0])==SQLITE_NULL ); - sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); + assert( sqlite3_value_type(pValue)==SQLITE_NULL ); + sqlite3_str_append(pStr, "NULL", 4); break; } } } +/* +** Implementation of the QUOTE() function. +** +** The quote(X) function returns the text of an SQL literal which is the +** value of its argument suitable for inclusion into an SQL statement. +** Strings are surrounded by single-quotes with escapes on interior quotes +** as needed. BLOBs are encoded as hexadecimal literals. Strings with +** embedded NUL characters cannot be represented as string literals in SQL +** and hence the returned string literal is truncated prior to the first NUL. +*/ +static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + sqlite3_str str; + sqlite3 *db = sqlite3_context_db_handle(context); + assert( argc==1 ); + UNUSED_PARAMETER(argc); + sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); + sqlite3QuoteValue(&str,argv[0]); + sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar, + SQLITE_DYNAMIC); + if( str.accError!=SQLITE_OK ){ + sqlite3_result_null(context); + sqlite3_result_error_code(context, str.accError); + } +} + /* ** The unicode() function. Return the integer unicode code-point value -** for the first character of the input string. +** for the first character of the input string. */ static void unicodeFunc( sqlite3_context *context, @@ -106178,6 +122317,8 @@ static void replaceFunc( i64 nOut; /* Maximum size of zOut */ int loopLimit; /* Last zStr[] that might match zPattern[] */ int i, j; /* Loop counters */ + unsigned cntExpand; /* Number zOut expansions */ + sqlite3 *db = sqlite3_context_db_handle(context); assert( argc==3 ); UNUSED_PARAMETER(argc); @@ -106208,34 +122349,41 @@ static void replaceFunc( if( zOut==0 ){ return; } - loopLimit = nStr - nPattern; + loopLimit = nStr - nPattern; + cntExpand = 0; for(i=j=0; i<=loopLimit; i++){ if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){ zOut[j++] = zStr[i]; }else{ - u8 *zOld; - sqlite3 *db = sqlite3_context_db_handle(context); - nOut += nRep - nPattern; - testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] ); - testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] ); - if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ - sqlite3_result_error_toobig(context); - sqlite3_free(zOut); - return; - } - zOld = zOut; - zOut = sqlite3_realloc64(zOut, (int)nOut); - if( zOut==0 ){ - sqlite3_result_error_nomem(context); - sqlite3_free(zOld); - return; + if( nRep>nPattern ){ + nOut += nRep - nPattern; + testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] ); + testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] ); + if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ + sqlite3_result_error_toobig(context); + sqlite3_free(zOut); + return; + } + cntExpand++; + if( (cntExpand&(cntExpand-1))==0 ){ + /* Grow the size of the output buffer only on substitutions + ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */ + u8 *zOld; + zOld = zOut; + zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1)); + if( zOut==0 ){ + sqlite3_result_error_nomem(context); + sqlite3_free(zOld); + return; + } + } } memcpy(&zOut[j], zRep, nRep); j += nRep; i += nPattern-1; } } - assert( j+nStr-i+1==nOut ); + assert( j+nStr-i+1<=nOut ); memcpy(&zOut[j], &zStr[i], nStr-i); j += nStr - i; assert( j<=nOut ); @@ -106254,10 +122402,10 @@ static void trimFunc( ){ const unsigned char *zIn; /* Input string */ const unsigned char *zCharSet; /* Set of characters to trim */ - int nIn; /* Number of bytes in input */ + unsigned int nIn; /* Number of bytes in input */ int flags; /* 1: trimleft 2: trimright 3: trim */ int i; /* Loop counter */ - unsigned char *aLen = 0; /* Length of each character in zCharSet */ + unsigned int *aLen = 0; /* Length of each character in zCharSet */ unsigned char **azChar = 0; /* Individual characters in zCharSet */ int nChar; /* Number of characters in zCharSet */ @@ -106266,13 +122414,13 @@ static void trimFunc( } zIn = sqlite3_value_text(argv[0]); if( zIn==0 ) return; - nIn = sqlite3_value_bytes(argv[0]); + nIn = (unsigned)sqlite3_value_bytes(argv[0]); assert( zIn==sqlite3_value_text(argv[0]) ); if( argc==1 ){ - static const unsigned char lenOne[] = { 1 }; + static const unsigned lenOne[] = { 1 }; static unsigned char * const azOne[] = { (u8*)" " }; nChar = 1; - aLen = (u8*)lenOne; + aLen = (unsigned*)lenOne; azChar = (unsigned char **)azOne; zCharSet = 0; }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ @@ -106283,15 +122431,16 @@ static void trimFunc( SQLITE_SKIP_UTF8(z); } if( nChar>0 ){ - azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+1)); + azChar = contextMalloc(context, + ((i64)nChar)*(sizeof(char*)+sizeof(unsigned))); if( azChar==0 ){ return; } - aLen = (unsigned char*)&azChar[nChar]; + aLen = (unsigned*)&azChar[nChar]; for(z=zCharSet, nChar=0; *z; nChar++){ azChar[nChar] = (unsigned char *)z; SQLITE_SKIP_UTF8(z); - aLen[nChar] = (u8)(z - azChar[nChar]); + aLen[nChar] = (unsigned)(z - azChar[nChar]); } } } @@ -106299,7 +122448,7 @@ static void trimFunc( flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); if( flags & 1 ){ while( nIn>0 ){ - int len = 0; + unsigned int len = 0; for(i=0; i0 ){ - int len = 0; + unsigned int len = 0; for(i=0; irSum += v; if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){ - p->overflow = 1; + p->approx = p->overflow = 1; } }else{ p->rSum += sqlite3_value_double(argv[0]); @@ -106483,6 +122632,32 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ } } } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){ + SumCtx *p; + int type; + assert( argc==1 ); + UNUSED_PARAMETER(argc); + p = sqlite3_aggregate_context(context, sizeof(*p)); + type = sqlite3_value_numeric_type(argv[0]); + /* p is always non-NULL because sumStep() will have been called first + ** to initialize it */ + if( ALWAYS(p) && type!=SQLITE_NULL ){ + assert( p->cnt>0 ); + p->cnt--; + assert( type==SQLITE_INTEGER || p->approx ); + if( type==SQLITE_INTEGER && p->approx==0 ){ + i64 v = sqlite3_value_int64(argv[0]); + p->rSum -= v; + p->iSum -= v; + }else{ + p->rSum -= sqlite3_value_double(argv[0]); + } + } +} +#else +# define sumInverse 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ static void sumFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); @@ -106517,6 +122692,9 @@ static void totalFinalize(sqlite3_context *context){ typedef struct CountCtx CountCtx; struct CountCtx { i64 n; +#ifdef SQLITE_DEBUG + int bInverse; /* True if xInverse() ever called */ +#endif }; /* @@ -106531,25 +122709,40 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){ #ifndef SQLITE_OMIT_DEPRECATED /* The sqlite3_aggregate_count() function is deprecated. But just to make - ** sure it still operates correctly, verify that its count agrees with our + ** sure it still operates correctly, verify that its count agrees with our ** internal count when using count(*) and when the total count can be ** expressed as a 32-bit integer. */ - assert( argc==1 || p==0 || p->n>0x7fffffff + assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse || p->n==sqlite3_aggregate_count(context) ); #endif -} +} static void countFinalize(sqlite3_context *context){ CountCtx *p; p = sqlite3_aggregate_context(context, 0); sqlite3_result_int64(context, p ? p->n : 0); } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){ + CountCtx *p; + p = sqlite3_aggregate_context(ctx, sizeof(*p)); + /* p is always non-NULL since countStep() will have been called first */ + if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){ + p->n--; +#ifdef SQLITE_DEBUG + p->bInverse = 1; +#endif + } +} +#else +# define countInverse 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** Routines to implement min() and max() aggregate functions. */ static void minmaxStep( - sqlite3_context *context, - int NotUsed, + sqlite3_context *context, + int NotUsed, sqlite3_value **argv ){ Mem *pArg = (Mem *)argv[0]; @@ -106559,7 +122752,7 @@ static void minmaxStep( pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest)); if( !pBest ) return; - if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + if( sqlite3_value_type(pArg)==SQLITE_NULL ){ if( pBest->flags ) sqlite3SkipAccumulatorLoad(context); }else if( pBest->flags ){ int max; @@ -106585,66 +122778,196 @@ static void minmaxStep( sqlite3VdbeMemCopy(pBest, pArg); } } -static void minMaxFinalize(sqlite3_context *context){ +static void minMaxValueFinalize(sqlite3_context *context, int bValue){ sqlite3_value *pRes; pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); if( pRes ){ if( pRes->flags ){ sqlite3_result_value(context, pRes); } - sqlite3VdbeMemRelease(pRes); + if( bValue==0 ) sqlite3VdbeMemRelease(pRes); } } +#ifndef SQLITE_OMIT_WINDOWFUNC +static void minMaxValue(sqlite3_context *context){ + minMaxValueFinalize(context, 1); +} +#else +# define minMaxValue 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ +static void minMaxFinalize(sqlite3_context *context){ + minMaxValueFinalize(context, 0); +} /* ** group_concat(EXPR, ?SEPARATOR?) +** +** The SEPARATOR goes before the EXPR string. This is tragic. The +** groupConcatInverse() implementation would have been easier if the +** SEPARATOR were appended after EXPR. And the order is undocumented, +** so we could change it, in theory. But the old behavior has been +** around for so long that we dare not, for fear of breaking something. */ +typedef struct { + StrAccum str; /* The accumulated concatenation */ +#ifndef SQLITE_OMIT_WINDOWFUNC + int nAccum; /* Number of strings presently concatenated */ + int nFirstSepLength; /* Used to detect separator length change */ + /* If pnSepLengths!=0, refs an array of inter-string separator lengths, + ** stored as actually incorporated into presently accumulated result. + ** (Hence, its slots in use number nAccum-1 between method calls.) + ** If pnSepLengths==0, nFirstSepLength is the length used throughout. + */ + int *pnSepLengths; +#endif +} GroupConcatCtx; + static void groupConcatStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zVal; - StrAccum *pAccum; + GroupConcatCtx *pGCC; const char *zSep; int nVal, nSep; assert( argc==1 || argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); - - if( pAccum ){ + pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); + if( pGCC ){ sqlite3 *db = sqlite3_context_db_handle(context); - int firstTerm = pAccum->mxAlloc==0; - pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; - if( !firstTerm ){ - if( argc==2 ){ - zSep = (char*)sqlite3_value_text(argv[1]); - nSep = sqlite3_value_bytes(argv[1]); - }else{ - zSep = ","; - nSep = 1; + int firstTerm = pGCC->str.mxAlloc==0; + pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; + if( argc==1 ){ + if( !firstTerm ){ + sqlite3_str_appendchar(&pGCC->str, 1, ','); + } +#ifndef SQLITE_OMIT_WINDOWFUNC + else{ + pGCC->nFirstSepLength = 1; + } +#endif + }else if( !firstTerm ){ + zSep = (char*)sqlite3_value_text(argv[1]); + nSep = sqlite3_value_bytes(argv[1]); + if( zSep ){ + sqlite3_str_append(&pGCC->str, zSep, nSep); + } +#ifndef SQLITE_OMIT_WINDOWFUNC + else{ + nSep = 0; + } + if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){ + int *pnsl = pGCC->pnSepLengths; + if( pnsl == 0 ){ + /* First separator length variation seen, start tracking them. */ + pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int)); + if( pnsl!=0 ){ + int i = 0, nA = pGCC->nAccum-1; + while( inFirstSepLength; + } + }else{ + pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int)); + } + if( pnsl!=0 ){ + if( ALWAYS(pGCC->nAccum>0) ){ + pnsl[pGCC->nAccum-1] = nSep; + } + pGCC->pnSepLengths = pnsl; + }else{ + sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM); + } } - if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep); +#endif } +#ifndef SQLITE_OMIT_WINDOWFUNC + else{ + pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]); + } + pGCC->nAccum += 1; +#endif zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); - if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal); + if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal); } } + +#ifndef SQLITE_OMIT_WINDOWFUNC +static void groupConcatInverse( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GroupConcatCtx *pGCC; + assert( argc==1 || argc==2 ); + (void)argc; /* Suppress unused parameter warning */ + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); + /* pGCC is always non-NULL since groupConcatStep() will have always + ** run frist to initialize it */ + if( ALWAYS(pGCC) ){ + int nVS; + /* Must call sqlite3_value_text() to convert the argument into text prior + ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */ + (void)sqlite3_value_text(argv[0]); + nVS = sqlite3_value_bytes(argv[0]); + pGCC->nAccum -= 1; + if( pGCC->pnSepLengths!=0 ){ + assert(pGCC->nAccum >= 0); + if( pGCC->nAccum>0 ){ + nVS += *pGCC->pnSepLengths; + memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1, + (pGCC->nAccum-1)*sizeof(int)); + } + }else{ + /* If removing single accumulated string, harmlessly over-do. */ + nVS += pGCC->nFirstSepLength; + } + if( nVS>=(int)pGCC->str.nChar ){ + pGCC->str.nChar = 0; + }else{ + pGCC->str.nChar -= nVS; + memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar); + } + if( pGCC->str.nChar==0 ){ + pGCC->str.mxAlloc = 0; + sqlite3_free(pGCC->pnSepLengths); + pGCC->pnSepLengths = 0; + } + } +} +#else +# define groupConcatInverse 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ static void groupConcatFinalize(sqlite3_context *context){ - StrAccum *pAccum; - pAccum = sqlite3_aggregate_context(context, 0); - if( pAccum ){ - if( pAccum->accError==STRACCUM_TOOBIG ){ + GroupConcatCtx *pGCC + = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); + if( pGCC ){ + sqlite3ResultStrAccum(context, &pGCC->str); +#ifndef SQLITE_OMIT_WINDOWFUNC + sqlite3_free(pGCC->pnSepLengths); +#endif + } +} +#ifndef SQLITE_OMIT_WINDOWFUNC +static void groupConcatValue(sqlite3_context *context){ + GroupConcatCtx *pGCC + = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); + if( pGCC ){ + StrAccum *pAccum = &pGCC->str; + if( pAccum->accError==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(context); - }else if( pAccum->accError==STRACCUM_NOMEM ){ + }else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); - }else{ - sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1, - sqlite3_free); + }else{ + const char *zText = sqlite3_str_value(pAccum); + sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT); } } } +#else +# define groupConcatValue 0 +#endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** This routine does per-connection function registration. Most @@ -106660,43 +122983,37 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ } /* -** Set the LIKEOPT flag on the 2-argument function with the given name. -*/ -static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ - FuncDef *pDef; - pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0); - if( ALWAYS(pDef) ){ - pDef->funcFlags |= flagVal; - } -} - -/* -** Register the built-in LIKE and GLOB functions. The caseSensitive +** Re-register the built-in LIKE functions. The caseSensitive ** parameter determines whether or not the LIKE operator is case -** sensitive. GLOB is always case sensitive. +** sensitive. */ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ struct compareInfo *pInfo; + int flags; if( caseSensitive ){ pInfo = (struct compareInfo*)&likeInfoAlt; + flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE; }else{ pInfo = (struct compareInfo*)&likeInfoNorm; + flags = SQLITE_FUNC_LIKE; } - sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0); - sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0); - sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, - (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0); - setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); - setLikeOptFlag(db, "like", - caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); + sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); + sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); + sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags; + sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags; } /* ** pExpr points to an expression which implements a function. If ** it is appropriate to apply the LIKE optimization to that function -** then set aWc[0] through aWc[2] to the wildcard characters and -** return TRUE. If the function is not a LIKE-style function then -** return FALSE. +** then set aWc[0] through aWc[2] to the wildcard characters and the +** escape character and then return TRUE. If the function is not a +** LIKE-style function then return FALSE. +** +** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE +** operator if c is a string literal that is exactly one byte in length. +** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is +** no ESCAPE clause. ** ** *pIsNocase is set to true if uppercase and lowercase are equivalent for ** the function (default for LIKE). If the function makes the distinction @@ -106705,14 +123022,19 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive) */ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ FuncDef *pDef; - if( pExpr->op!=TK_FUNCTION - || !pExpr->x.pList - || pExpr->x.pList->nExpr!=2 - ){ + int nExpr; + assert( pExpr!=0 ); + assert( pExpr->op==TK_FUNCTION ); + assert( ExprUseXList(pExpr) ); + if( !pExpr->x.pList ){ return 0; } - assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0); + nExpr = pExpr->x.pList->nExpr; + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); +#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION + if( pDef==0 ) return 0; +#endif if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ return 0; } @@ -106725,10 +123047,220 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); + + if( nExpr<3 ){ + aWc[3] = 0; + }else{ + Expr *pEscape = pExpr->x.pList->a[2].pExpr; + char *zEscape; + if( pEscape->op!=TK_STRING ) return 0; + assert( !ExprHasProperty(pEscape, EP_IntValue) ); + zEscape = pEscape->u.zToken; + if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; + if( zEscape[0]==aWc[0] ) return 0; + if( zEscape[0]==aWc[1] ) return 0; + aWc[3] = zEscape[0]; + } + *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0; return 1; } +/* Mathematical Constants */ +#ifndef M_PI +# define M_PI 3.141592653589793238462643383279502884 +#endif +#ifndef M_LN10 +# define M_LN10 2.302585092994045684017991454684364208 +#endif +#ifndef M_LN2 +# define M_LN2 0.693147180559945309417232121458176568 +#endif + + +/* Extra math functions that require linking with -lm +*/ +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS +/* +** Implementation SQL functions: +** +** ceil(X) +** ceiling(X) +** floor(X) +** +** The sqlite3_user_data() pointer is a pointer to the libm implementation +** of the underlying C function. +*/ +static void ceilingFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + assert( argc==1 ); + switch( sqlite3_value_numeric_type(argv[0]) ){ + case SQLITE_INTEGER: { + sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); + break; + } + case SQLITE_FLOAT: { + double (*x)(double) = (double(*)(double))sqlite3_user_data(context); + sqlite3_result_double(context, x(sqlite3_value_double(argv[0]))); + break; + } + default: { + break; + } + } +} + +/* +** On some systems, ceil() and floor() are intrinsic function. You are +** unable to take a pointer to these functions. Hence, we here wrap them +** in our own actual functions. +*/ +static double xCeil(double x){ return ceil(x); } +static double xFloor(double x){ return floor(x); } + +/* +** Implementation of SQL functions: +** +** ln(X) - natural logarithm +** log(X) - log X base 10 +** log10(X) - log X base 10 +** log(B,X) - log X base B +*/ +static void logFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + double x, b, ans; + assert( argc==1 || argc==2 ); + switch( sqlite3_value_numeric_type(argv[0]) ){ + case SQLITE_INTEGER: + case SQLITE_FLOAT: + x = sqlite3_value_double(argv[0]); + if( x<=0.0 ) return; + break; + default: + return; + } + if( argc==2 ){ + switch( sqlite3_value_numeric_type(argv[0]) ){ + case SQLITE_INTEGER: + case SQLITE_FLOAT: + b = log(x); + if( b<=0.0 ) return; + x = sqlite3_value_double(argv[1]); + if( x<=0.0 ) return; + break; + default: + return; + } + ans = log(x)/b; + }else{ + ans = log(x); + switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){ + case 1: + /* Convert from natural logarithm to log base 10 */ + ans *= 1.0/M_LN10; + break; + case 2: + /* Convert from natural logarithm to log base 2 */ + ans *= 1.0/M_LN2; + break; + default: + break; + } + } + sqlite3_result_double(context, ans); +} + +/* +** Functions to converts degrees to radians and radians to degrees. +*/ +static double degToRad(double x){ return x*(M_PI/180.0); } +static double radToDeg(double x){ return x*(180.0/M_PI); } + +/* +** Implementation of 1-argument SQL math functions: +** +** exp(X) - Compute e to the X-th power +*/ +static void math1Func( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int type0; + double v0, ans; + double (*x)(double); + assert( argc==1 ); + type0 = sqlite3_value_numeric_type(argv[0]); + if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; + v0 = sqlite3_value_double(argv[0]); + x = (double(*)(double))sqlite3_user_data(context); + ans = x(v0); + sqlite3_result_double(context, ans); +} + +/* +** Implementation of 2-argument SQL math functions: +** +** power(X,Y) - Compute X to the Y-th power +*/ +static void math2Func( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int type0, type1; + double v0, v1, ans; + double (*x)(double,double); + assert( argc==2 ); + type0 = sqlite3_value_numeric_type(argv[0]); + if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; + type1 = sqlite3_value_numeric_type(argv[1]); + if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return; + v0 = sqlite3_value_double(argv[0]); + v1 = sqlite3_value_double(argv[1]); + x = (double(*)(double,double))sqlite3_user_data(context); + ans = x(v0, v1); + sqlite3_result_double(context, ans); +} + +/* +** Implementation of 0-argument pi() function. +*/ +static void piFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + assert( argc==0 ); + sqlite3_result_double(context, M_PI); +} + +#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ + +/* +** Implementation of sign(X) function. +*/ +static void signFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int type0; + double x; + UNUSED_PARAMETER(argc); + assert( argc==1 ); + type0 = sqlite3_value_numeric_type(argv[0]); + if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; + x = sqlite3_value_double(argv[0]); + sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0); +} + /* ** All of the FuncDef structures in the aBuiltinFunc[] array above ** to the global function hash table. This occurs at start-time (as @@ -106748,12 +123280,20 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ ** For peak efficiency, put the most frequently used function last. */ static FuncDef aBuiltinFunc[] = { +/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/ +#if !defined(SQLITE_UNTESTABLE) + TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0), + TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0), + TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0), + TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0), +#endif /* !defined(SQLITE_UNTESTABLE) */ +/***** Regular functions *****/ #ifdef SQLITE_SOUNDEX FUNCTION(soundex, 1, 0, 0, soundexFunc ), #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION - VFUNCTION(load_extension, 1, 0, 0, loadExt ), - VFUNCTION(load_extension, 2, 0, 0, loadExt ), + SFUNCTION(load_extension, 1, 0, 0, loadExt ), + SFUNCTION(load_extension, 2, 0, 0, loadExt ), #endif #if SQLITE_USER_AUTHENTICATION FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), @@ -106762,11 +123302,12 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ - FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), - FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), - FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), -#ifdef SQLITE_DEBUG - FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY), + INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), + INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), + INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + {1, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_OFFSET|SQLITE_FUNC_TYPEOF, + 0, 0, noopFunc, 0, 0, 0, "sqlite_offset", {0} }, #endif FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ), @@ -106776,16 +123317,18 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(trim, 2, 3, 0, trimFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, 0, 0, 1, 0 ), - AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize, - SQLITE_FUNC_MINMAX ), + WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, + SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), - AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize, - SQLITE_FUNC_MINMAX ), + WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, + SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), + FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(printf, -1, 0, 0, printfFunc ), + FUNCTION(format, -1, 0, 0, printfFunc ), FUNCTION(unicode, 1, 0, 0, unicodeFunc ), FUNCTION(char, -1, 0, 0, charFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), @@ -106796,7 +123339,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), FUNCTION(hex, 1, 0, 0, hexFunc ), - FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), + INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ), VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), @@ -106811,15 +123354,21 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), - AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), - AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), - AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), - AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, - SQLITE_FUNC_COUNT ), - AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), - AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), - AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), - + FUNCTION(substring, 2, 0, 0, substrFunc ), + FUNCTION(substring, 3, 0, 0, substrFunc ), + WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0), + WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), + WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), + WAGGREGATE(count, 0,0,0, countStep, + countFinalize, countFinalize, countInverse, + SQLITE_FUNC_COUNT|SQLITE_FUNC_ANYORDER ), + WAGGREGATE(count, 1,0,0, countStep, + countFinalize, countFinalize, countInverse, SQLITE_FUNC_ANYORDER ), + WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, + groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), + WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, + groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), + LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), @@ -106833,15 +123382,52 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ #endif FUNCTION(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), - FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS + MFUNCTION(ceil, 1, xCeil, ceilingFunc ), + MFUNCTION(ceiling, 1, xCeil, ceilingFunc ), + MFUNCTION(floor, 1, xFloor, ceilingFunc ), +#if SQLITE_HAVE_C99_MATH_FUNCS + MFUNCTION(trunc, 1, trunc, ceilingFunc ), +#endif + FUNCTION(ln, 1, 0, 0, logFunc ), + FUNCTION(log, 1, 1, 0, logFunc ), + FUNCTION(log10, 1, 1, 0, logFunc ), + FUNCTION(log2, 1, 2, 0, logFunc ), + FUNCTION(log, 2, 0, 0, logFunc ), + MFUNCTION(exp, 1, exp, math1Func ), + MFUNCTION(pow, 2, pow, math2Func ), + MFUNCTION(power, 2, pow, math2Func ), + MFUNCTION(mod, 2, fmod, math2Func ), + MFUNCTION(acos, 1, acos, math1Func ), + MFUNCTION(asin, 1, asin, math1Func ), + MFUNCTION(atan, 1, atan, math1Func ), + MFUNCTION(atan2, 2, atan2, math2Func ), + MFUNCTION(cos, 1, cos, math1Func ), + MFUNCTION(sin, 1, sin, math1Func ), + MFUNCTION(tan, 1, tan, math1Func ), + MFUNCTION(cosh, 1, cosh, math1Func ), + MFUNCTION(sinh, 1, sinh, math1Func ), + MFUNCTION(tanh, 1, tanh, math1Func ), +#if SQLITE_HAVE_C99_MATH_FUNCS + MFUNCTION(acosh, 1, acosh, math1Func ), + MFUNCTION(asinh, 1, asinh, math1Func ), + MFUNCTION(atanh, 1, atanh, math1Func ), +#endif + MFUNCTION(sqrt, 1, sqrt, math1Func ), + MFUNCTION(radians, 1, degToRad, math1Func ), + MFUNCTION(degrees, 1, radToDeg, math1Func ), + FUNCTION(pi, 0, 0, 0, piFunc ), +#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ + FUNCTION(sign, 1, 0, 0, signFunc ), + INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), + INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); #endif -#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4) - sqlite3AnalyzeFunctions(); -#endif + sqlite3WindowFunctions(); sqlite3RegisterDateTimeFunctions(); + sqlite3RegisterJsonFunctions(); sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc)); #if 0 /* Enable to print out how the built-in functions are hashed */ @@ -106853,6 +123439,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){ int n = sqlite3Strlen30(p->zName); int h = p->zName[0] + n; + assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); printf(" %s(%d)", p->zName, h); } printf("\n"); @@ -106888,25 +123475,25 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ ** Foreign keys in SQLite come in two flavours: deferred and immediate. ** If an immediate foreign key constraint is violated, ** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current -** statement transaction rolled back. If a -** deferred foreign key constraint is violated, no action is taken -** immediately. However if the application attempts to commit the +** statement transaction rolled back. If a +** deferred foreign key constraint is violated, no action is taken +** immediately. However if the application attempts to commit the ** transaction before fixing the constraint violation, the attempt fails. ** ** Deferred constraints are implemented using a simple counter associated -** with the database handle. The counter is set to zero each time a -** database transaction is opened. Each time a statement is executed +** with the database handle. The counter is set to zero each time a +** database transaction is opened. Each time a statement is executed ** that causes a foreign key violation, the counter is incremented. Each ** time a statement is executed that removes an existing violation from ** the database, the counter is decremented. When the transaction is ** committed, the commit fails if the current value of the counter is ** greater than zero. This scheme has two big drawbacks: ** -** * When a commit fails due to a deferred foreign key constraint, +** * When a commit fails due to a deferred foreign key constraint, ** there is no way to tell which foreign constraint is not satisfied, ** or which row it is not satisfied for. ** -** * If the database contains foreign key violations when the +** * If the database contains foreign key violations when the ** transaction is opened, this may cause the mechanism to malfunction. ** ** Despite these problems, this approach is adopted as it seems simpler @@ -106918,26 +123505,26 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ ** the parent table for a match. If none is found increment the ** constraint counter. ** -** I.2) For each FK for which the table is the parent table, +** I.2) For each FK for which the table is the parent table, ** search the child table for rows that correspond to the new ** row in the parent table. Decrement the counter for each row ** found (as the constraint is now satisfied). ** ** DELETE operations: ** -** D.1) For each FK for which the table is the child table, -** search the parent table for a row that corresponds to the -** deleted row in the child table. If such a row is not found, +** D.1) For each FK for which the table is the child table, +** search the parent table for a row that corresponds to the +** deleted row in the child table. If such a row is not found, ** decrement the counter. ** -** D.2) For each FK for which the table is the parent table, search -** the child table for rows that correspond to the deleted row +** D.2) For each FK for which the table is the parent table, search +** the child table for rows that correspond to the deleted row ** in the parent table. For each found increment the counter. ** ** UPDATE operations: ** ** An UPDATE command requires that all 4 steps above are taken, but only -** for FK constraints for which the affected columns are actually +** for FK constraints for which the affected columns are actually ** modified (values must be compared at runtime). ** ** Note that I.1 and D.1 are very similar operations, as are I.2 and D.2. @@ -106946,10 +123533,10 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ ** For the purposes of immediate FK constraints, the OR REPLACE conflict ** resolution is considered to delete rows before the new row is inserted. ** If a delete caused by OR REPLACE violates an FK constraint, an exception -** is thrown, even if the FK constraint would be satisfied after the new +** is thrown, even if the FK constraint would be satisfied after the new ** row is inserted. ** -** Immediate constraints are usually handled similarly. The only difference +** Immediate constraints are usually handled similarly. The only difference ** is that the counter used is stored as part of each individual statement ** object (struct Vdbe). If, after the statement has run, its immediate ** constraint counter is greater than zero, @@ -106960,7 +123547,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ ** INSERT violates a foreign key constraint. This is necessary as such ** an INSERT does not open a statement transaction. ** -** TODO: How should dropping a table be handled? How should renaming a +** TODO: How should dropping a table be handled? How should renaming a ** table be handled? ** ** @@ -106971,7 +123558,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ ** for those two operations needs to know whether or not the operation ** requires any FK processing and, if so, which columns of the original ** row are required by the FK processing VDBE code (i.e. if FKs were -** implemented using triggers, which of the old.* columns would be +** implemented using triggers, which of the old.* columns would be ** accessed). No information is required by the code-generator before ** coding an INSERT operation. The functions used by the UPDATE/DELETE ** generation code to query for this information are: @@ -107008,13 +123595,13 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ /* ** A foreign key constraint requires that the key columns in the parent ** table are collectively subject to a UNIQUE or PRIMARY KEY constraint. -** Given that pParent is the parent table for foreign key constraint pFKey, -** search the schema for a unique index on the parent key columns. +** Given that pParent is the parent table for foreign key constraint pFKey, +** search the schema for a unique index on the parent key columns. +** +** If successful, zero is returned. If the parent key is an INTEGER PRIMARY +** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx +** is set to point to the unique index. ** -** If successful, zero is returned. If the parent key is an INTEGER PRIMARY -** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx -** is set to point to the unique index. -** ** If the parent key consists of a single column (the foreign key constraint ** is not a composite foreign key), output variable *paiCol is set to NULL. ** Otherwise, it is set to point to an allocated array of size N, where @@ -107037,8 +123624,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ ** PRIMARY KEY, or ** ** 4) No parent key columns were provided explicitly as part of the -** foreign key definition, and the PRIMARY KEY of the parent table -** consists of a different number of columns to the child key in +** foreign key definition, and the PRIMARY KEY of the parent table +** consists of a different number of columns to the child key in ** the child table. ** ** then non-zero is returned, and a "foreign key mismatch" error loaded @@ -107062,9 +123649,9 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( assert( !paiCol || *paiCol==0 ); assert( pParse ); - /* If this is a non-composite (single column) foreign key, check if it - ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx - ** and *paiCol set to zero and return early. + /* If this is a non-composite (single column) foreign key, check if it + ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx + ** and *paiCol set to zero and return early. ** ** Otherwise, for a composite foreign key (more than one column), allocate ** space for the aiCol array (returned via output parameter *paiCol). @@ -107073,14 +123660,16 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( if( nCol==1 ){ /* The FK maps to the IPK if any of the following are true: ** - ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly + ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly ** mapped to the primary key of table pParent, or ** 2) The FK is explicitly mapped to a column declared as INTEGER ** PRIMARY KEY. */ if( pParent->iPKey>=0 ){ if( !zKey ) return 0; - if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zName, zKey) ) return 0; + if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zCnName, zKey) ){ + return 0; + } } }else if( paiCol ){ assert( nCol>1 ); @@ -107090,14 +123679,14 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( } for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){ + if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){ /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number ** of columns. If each indexed column corresponds to a foreign key ** column of pFKey, then this index is a winner. */ if( zKey==0 ){ - /* If zKey is NULL, then this foreign key is implicitly mapped to - ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be + /* If zKey is NULL, then this foreign key is implicitly mapped to + ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be ** identified by the test. */ if( IsPrimaryKeyIndex(pIdx) ){ if( aiCol ){ @@ -107122,11 +123711,11 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ - zDfltColl = pParent->aCol[iCol].zColl; + zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]); if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; - zIdxCol = pParent->aCol[iCol].zName; + zIdxCol = pParent->aCol[iCol].zCnName; for(j=0; jaCol[j].zCol, zIdxCol)==0 ){ if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom; @@ -107155,15 +123744,15 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( } /* -** This function is called when a row is inserted into or deleted from the -** child table of foreign key constraint pFKey. If an SQL UPDATE is executed +** This function is called when a row is inserted into or deleted from the +** child table of foreign key constraint pFKey. If an SQL UPDATE is executed ** on the child table of pFKey, this function is invoked twice for each row ** affected - once to "delete" the old row, and then again to "insert" the ** new row. ** ** Each time it is called, this function generates VDBE code to locate the -** row in the parent table that corresponds to the row being inserted into -** or deleted from the child table. If the parent row can be found, no +** row in the parent table that corresponds to the row being inserted into +** or deleted from the child table. If the parent row can be found, no ** special action is taken. Otherwise, if the parent row can *not* be ** found in the parent table: ** @@ -107177,7 +123766,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex( ** ** DELETE deferred Decrement the "deferred constraint counter". ** -** These operations are identified in the comment at the top of this file +** These operations are identified in the comment at the top of this file ** (fkey.c) as "I.1" and "D.1". */ static void fkLookupParent( @@ -107194,21 +123783,27 @@ static void fkLookupParent( int i; /* Iterator variable */ Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */ int iCur = pParse->nTab - 1; /* Cursor number to use */ - int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */ + int iOk = sqlite3VdbeMakeLabel(pParse); /* jump here if parent key found */ + + sqlite3VdbeVerifyAbortable(v, + (!pFKey->isDeferred + && !(pParse->db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel + && !pParse->isMultiWrite) ? OE_Abort : OE_Ignore); /* If nIncr is less than zero, then check at runtime if there are any ** outstanding constraints to resolve. If there are not, there is no need ** to check if deleting this row resolves any outstanding violations. ** - ** Check if any of the key columns in the child table row are NULL. If - ** any are, then the constraint is considered satisfied. No need to + ** Check if any of the key columns in the child table row are NULL. If + ** any are, then the constraint is considered satisfied. No need to ** search for a matching row in the parent table. */ if( nIncr<0 ){ sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk); VdbeCoverage(v); } for(i=0; inCol; i++){ - int iReg = aiCol[i] + regData + 1; + int iReg = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + regData + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v); } @@ -107218,16 +123813,17 @@ static void fkLookupParent( ** column of the parent table (table pTab). */ int iMustBeInt; /* Address of MustBeInt instruction */ int regTemp = sqlite3GetTempReg(pParse); - - /* Invoke MustBeInt to coerce the child key value to an integer (i.e. + + /* Invoke MustBeInt to coerce the child key value to an integer (i.e. ** apply the affinity of the parent key). If this fails, then there ** is no matching parent key. Before using MustBeInt, make a copy of ** the value. Otherwise, the value inserted into the child key column ** will have INTEGER affinity applied to it, which may not be correct. */ - sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp); + sqlite3VdbeAddOp2(v, OP_SCopy, + sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp); iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0); VdbeCoverage(v); - + /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not @@ -107236,7 +123832,7 @@ static void fkLookupParent( sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); } - + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v); sqlite3VdbeGoto(v, iOk); @@ -107247,19 +123843,21 @@ static void fkLookupParent( int nCol = pFKey->nCol; int regTemp = sqlite3GetTempRange(pParse, nCol); int regRec = sqlite3GetTempReg(pParse); - + sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); for(i=0; ipFrom, aiCol[i])+1+regData, + regTemp+i); } - + /* If the parent table is the same as the child table, and we are about ** to increment the constraint-counter (i.e. this is an INSERT operation), ** then check if the row being inserted matches itself. If so, do not - ** increment the constraint-counter. + ** increment the constraint-counter. ** - ** If any of the parent-key values are NULL, then the row cannot match + ** If any of the parent-key values are NULL, then the row cannot match ** itself. So set JUMPIFNULL to make sure we do the OP_Found if any ** of the parent-key values are NULL (at this point it is known that ** none of the child key values are). @@ -107267,8 +123865,11 @@ static void fkLookupParent( if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; iaiColumn[i]+1+regData; + int iChild = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + +1+regData; + int iParent = 1+regData; + iParent += sqlite3TableColumnToStorage(pIdx->pTable, + pIdx->aiColumn[i]); assert( pIdx->aiColumn[i]>=0 ); assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ @@ -107280,19 +123881,19 @@ static void fkLookupParent( } sqlite3VdbeGoto(v, iOk); } - + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec, sqlite3IndexAffinityStr(pParse->db,pIdx), nCol); sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v); - + sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempRange(pParse, regTemp, nCol); } } if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs) - && !pParse->pToplevel - && !pParse->isMultiWrite + && !pParse->pToplevel + && !pParse->isMultiWrite ){ /* Special case: If this is an INSERT statement that will insert exactly ** one row into the table, raise a constraint immediately instead of @@ -107336,14 +123937,14 @@ static Expr *exprTableRegister( if( pExpr ){ if( iCol>=0 && iCol!=pTab->iPKey ){ pCol = &pTab->aCol[iCol]; - pExpr->iTable = regBase + iCol + 1; - pExpr->affinity = pCol->affinity; - zColl = pCol->zColl; + pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1; + pExpr->affExpr = pCol->affinity; + zColl = sqlite3ColumnColl(pCol); if( zColl==0 ) zColl = db->pDfltColl->zName; pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); }else{ pExpr->iTable = regBase; - pExpr->affinity = SQLITE_AFF_INTEGER; + pExpr->affExpr = SQLITE_AFF_INTEGER; } } return pExpr; @@ -107361,7 +123962,8 @@ static Expr *exprTableColumn( ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ - pExpr->pTab = pTab; + assert( ExprUseYTab(pExpr) ); + pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; } @@ -107370,7 +123972,7 @@ static Expr *exprTableColumn( /* ** This function is called to generate code executed when a row is deleted -** from the parent table of foreign key constraint pFKey and, if pFKey is +** from the parent table of foreign key constraint pFKey and, if pFKey is ** deferred, when a row is inserted into the same table. When generating ** code for an SQL UPDATE operation, this function may be called twice - ** once to "delete" the old row and once to "insert" the new row. @@ -107397,7 +123999,7 @@ static Expr *exprTableColumn( ** ** INSERT deferred Decrement the "deferred constraint counter". ** -** These operations are identified in the comment at the top of this file +** These operations are identified in the comment at the top of this file ** (fkey.c) as "I.2" and "D.2". */ static void fkScanChildren( @@ -107440,17 +124042,17 @@ static void fkScanChildren( Expr *pLeft; /* Value from parent table row */ Expr *pRight; /* Column ref to child table */ Expr *pEq; /* Expression (pLeft = pRight) */ - i16 iCol; /* Index of column in child table */ + i16 iCol; /* Index of column in child table */ const char *zCol; /* Name of column in child table */ iCol = pIdx ? pIdx->aiColumn[i] : -1; pLeft = exprTableRegister(pParse, pTab, regData, iCol); iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iCol>=0 ); - zCol = pFKey->pFrom->aCol[iCol].zName; + zCol = pFKey->pFrom->aCol[iCol].zCnName; pRight = sqlite3Expr(db, TK_ID, zCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); - pWhere = sqlite3ExprAnd(db, pWhere, pEq); + pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); } /* If the child table is the same as the parent table, then add terms @@ -107461,8 +124063,11 @@ static void fkScanChildren( ** NOT( $current_a==a AND $current_b==b AND ... ) ** ** The first form is used for rowid tables. The second form is used - ** for WITHOUT ROWID tables. In the second form, the primary key is - ** (a,b,...) + ** for WITHOUT ROWID tables. In the second form, the *parent* key is + ** (a,b,...). Either the parent or primary key could be used to + ** uniquely identify the current row, but the parent key is more convenient + ** as the required values have already been loaded into registers + ** by the caller. */ if( pTab==pFKey->pFrom && nIncr>0 ){ Expr *pNe; /* Expression (pLeft != pRight) */ @@ -107474,19 +124079,18 @@ static void fkScanChildren( pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight); }else{ Expr *pEq, *pAll = 0; - Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pIdx!=0 ); - for(i=0; inKeyCol; i++){ + for(i=0; inKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; assert( iCol>=0 ); pLeft = exprTableRegister(pParse, pTab, regData, iCol); - pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol); - pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); - pAll = sqlite3ExprAnd(db, pAll, pEq); + pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zCnName); + pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); + pAll = sqlite3ExprAnd(pParse, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); } - pWhere = sqlite3ExprAnd(db, pWhere, pNe); + pWhere = sqlite3ExprAnd(pParse, pWhere, pNe); } /* Resolve the references in the WHERE clause. */ @@ -107498,16 +124102,18 @@ static void fkScanChildren( /* Create VDBE to loop through the entries in pSrc that match the WHERE ** clause. For each row found, increment either the deferred or immediate ** foreign key constraint counter. */ - pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); - sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); - if( pWInfo ){ - sqlite3WhereEnd(pWInfo); + if( pParse->nErr==0 ){ + pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0, 0); + sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); + if( pWInfo ){ + sqlite3WhereEnd(pWInfo); + } } /* Clean up the WHERE clause constructed above. */ sqlite3ExprDelete(db, pWhere); if( iFkIfZero ){ - sqlite3VdbeJumpHere(v, iFkIfZero); + sqlite3VdbeJumpHereOrPopInst(v, iFkIfZero); } } @@ -107530,7 +124136,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){ } /* -** The second argument is a Trigger structure allocated by the +** The second argument is a Trigger structure allocated by the ** fkActionTrigger() routine. This function deletes the Trigger structure ** and all of its sub-components. ** @@ -107548,6 +124154,25 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ } } +/* +** Clear the apTrigger[] cache of CASCADE triggers for all foreign keys +** in a particular database. This needs to happen when the schema +** changes. +*/ +SQLITE_PRIVATE void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){ + HashElem *k; + Hash *pHash = &db->aDb[iDb].pSchema->tblHash; + for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k)){ + Table *pTab = sqliteHashData(k); + FKey *pFKey; + if( !IsOrdinaryTable(pTab) ) continue; + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ + fkTriggerDelete(db, pFKey->apTrigger[0]); pFKey->apTrigger[0] = 0; + fkTriggerDelete(db, pFKey->apTrigger[1]); pFKey->apTrigger[1] = 0; + } + } +} + /* ** This function is called to generate code that runs when table pTab is ** being dropped from the database. The SrcList passed as the second argument @@ -107558,7 +124183,7 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ ** ** (a) The table is the parent table of a FK constraint, or ** (b) The table is the child table of a deferred FK constraint and it is -** determined at runtime that there are outstanding deferred FK +** determined at runtime that there are outstanding deferred FK ** constraint violations in the database, ** ** then the equivalent of "DELETE FROM " is executed before dropping @@ -107567,40 +124192,42 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ */ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; - if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){ + if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ + assert( IsOrdinaryTable(pTab) ); if( sqlite3FkReferences(pTab)==0 ){ /* Search for a deferred foreign key constraint for which this table - ** is the child table. If one cannot be found, return without + ** is the child table. If one cannot be found, return without ** generating any VDBE code. If one can be found, then jump over ** the entire DELETE if there are no outstanding deferred constraints ** when this statement is run. */ FKey *p; - for(p=pTab->pFKey; p; p=p->pNextFrom){ + for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; } if( !p ) return; - iSkip = sqlite3VdbeMakeLabel(v); + iSkip = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v); } pParse->disableTriggers = 1; - sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0); + sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0); pParse->disableTriggers = 0; - /* If the DELETE has generated immediate foreign key constraint + /* If the DELETE has generated immediate foreign key constraint ** violations, halt the VDBE and return an error at this point, before ** any modifications to the schema are made. This is because statement - ** transactions are not able to rollback schema changes. + ** transactions are not able to rollback schema changes. ** ** If the SQLITE_DeferFKs flag is set, then this is not required, as ** the statement transaction will not be rolled back even if FK ** constraints are violated. */ if( (db->flags & SQLITE_DeferFKs)==0 ){ + sqlite3VdbeVerifyAbortable(v, OE_Abort); sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY, @@ -107617,7 +124244,7 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa /* ** The second argument points to an FKey object representing a foreign key ** for which pTab is the child table. An UPDATE statement against pTab -** is currently being processed. For each column of the table that is +** is currently being processed. For each column of the table that is ** actually updated, the corresponding element in the aChange[] array ** is zero or greater (if a column is unmodified the corresponding element ** is set to -1). If the rowid column is modified by the UPDATE statement @@ -107644,7 +124271,7 @@ static int fkChildIsModified( /* ** The second argument points to an FKey object representing a foreign key ** for which pTab is the parent table. An UPDATE statement against pTab -** is currently being processed. For each column of the table that is +** is currently being processed. For each column of the table that is ** actually updated, the corresponding element in the aChange[] array ** is zero or greater (if a column is unmodified the corresponding element ** is set to -1). If the rowid column is modified by the UPDATE statement @@ -107654,9 +124281,9 @@ static int fkChildIsModified( ** parent key for FK constraint *p are modified. */ static int fkParentIsModified( - Table *pTab, - FKey *p, - int *aChange, + Table *pTab, + FKey *p, + int *aChange, int bChngRowid ){ int i; @@ -107667,7 +124294,7 @@ static int fkParentIsModified( if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){ Column *pCol = &pTab->aCol[iKey]; if( zKey ){ - if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1; + if( 0==sqlite3StrICmp(pCol->zCnName, zKey) ) return 1; }else if( pCol->colFlags & COLFLAG_PRIMKEY ){ return 1; } @@ -107697,7 +124324,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){ /* ** This function is called when inserting, deleting or updating a row of -** table pTab to generate VDBE code to perform foreign key constraint +** table pTab to generate VDBE code to perform foreign key constraint ** processing for the operation. ** ** For a DELETE operation, parameter regOld is passed the index of the @@ -107713,11 +124340,11 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){ ** For an UPDATE operation, this function is called twice. Once before ** the original record is deleted from the table using the calling convention ** described for DELETE. Then again after the original record is deleted -** but before the new record is inserted using the INSERT convention. +** but before the new record is inserted using the INSERT convention. */ SQLITE_PRIVATE void sqlite3FkCheck( Parse *pParse, /* Parse context */ - Table *pTab, /* Row is being deleted from this table */ + Table *pTab, /* Row is being deleted from this table */ int regOld, /* Previous row data is stored here */ int regNew, /* New row data is stored here */ int *aChange, /* Array indicating UPDATEd columns (or 0) */ @@ -107734,13 +124361,14 @@ SQLITE_PRIVATE void sqlite3FkCheck( /* If foreign-keys are disabled, this function is a no-op. */ if( (db->flags&SQLITE_ForeignKeys)==0 ) return; + if( !IsOrdinaryTable(pTab) ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the ** child table (the table that the foreign key definition is part of). */ - for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){ Table *pTo; /* Parent table of foreign key pFKey */ Index *pIdx = 0; /* Index on key columns in pTo */ int *aiFree = 0; @@ -107749,16 +124377,16 @@ SQLITE_PRIVATE void sqlite3FkCheck( int i; int bIgnore = 0; - if( aChange + if( aChange && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0 - && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0 + && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0 ){ continue; } - /* Find the parent table of this foreign key. Also find a unique index - ** on the parent key columns in the parent table. If either of these - ** schema items cannot be located, set an error in pParse and return + /* Find the parent table of this foreign key. Also find a unique index + ** on the parent key columns in the parent table. If either of these + ** schema items cannot be located, set an error in pParse and return ** early. */ if( pParse->disableTriggers ){ pTo = sqlite3FindTable(db, pFKey->zTo, zDb); @@ -107779,7 +124407,9 @@ SQLITE_PRIVATE void sqlite3FkCheck( Vdbe *v = sqlite3GetVdbe(pParse); int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1; for(i=0; inCol; i++){ - int iReg = pFKey->aCol[i].iFrom + regOld + 1; + int iFromCol, iReg; + iFromCol = pFKey->aCol[i].iFrom; + iReg = sqlite3TableColumnToStorage(pFKey->pFrom,iFromCol) + regOld+1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); @@ -107800,36 +124430,36 @@ SQLITE_PRIVATE void sqlite3FkCheck( } assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION - /* Request permission to read the parent key columns. If the + /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; - char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; + char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zCnName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); bIgnore = (rcauth==SQLITE_IGNORE); } #endif } - /* Take a shared-cache advisory read-lock on the parent table. Allocate - ** a cursor to use to search the unique index on the parent key columns + /* Take a shared-cache advisory read-lock on the parent table. Allocate + ** a cursor to use to search the unique index on the parent key columns ** in the parent table. */ sqlite3TableLock(pParse, iDb, pTo->tnum, 0, pTo->zName); pParse->nTab++; if( regOld!=0 ){ /* A row is being removed from the child table. Search for the parent. - ** If the parent does not exist, removing the child row resolves an + ** If the parent does not exist, removing the child row resolves an ** outstanding foreign key constraint violation. */ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore); } if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){ /* A row is being added to the child table. If a parent row cannot - ** be found, adding the child row has violated the FK constraint. + ** be found, adding the child row has violated the FK constraint. ** ** If this operation is being performed as part of a trigger program - ** that is actually a "SET NULL" action belonging to this very + ** that is actually a "SET NULL" action belonging to this very ** foreign key, then omit this scan altogether. As all child key ** values are guaranteed to be NULL, it is not possible for adding ** this row to cause an FK violation. */ @@ -107850,8 +124480,8 @@ SQLITE_PRIVATE void sqlite3FkCheck( continue; } - if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs) - && !pParse->pToplevel && !pParse->isMultiWrite + if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs) + && !pParse->pToplevel && !pParse->isMultiWrite ){ assert( regOld==0 && regNew!=0 ); /* Inserting a single row into a parent table cannot cause (or fix) @@ -107867,14 +124497,14 @@ SQLITE_PRIVATE void sqlite3FkCheck( /* Create a SrcList structure containing the child table. We need the ** child table as a SrcList for sqlite3WhereBegin() */ - pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ - struct SrcList_item *pItem = pSrc->a; + SrcItem *pItem = pSrc->a; pItem->pTab = pFKey->pFrom; pItem->zName = pFKey->pFrom->zName; pItem->pTab->nTabRef++; pItem->iCursor = pParse->nTab++; - + if( regNew!=0 ){ fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); } @@ -107893,10 +124523,10 @@ SQLITE_PRIVATE void sqlite3FkCheck( ** ** Note 2: At first glance it may seem like SQLite could simply omit ** all OP_FkCounter related scans when either CASCADE or SET NULL - ** applies. The trouble starts if the CASCADE or SET NULL action - ** trigger causes other triggers or action rules attached to the + ** applies. The trouble starts if the CASCADE or SET NULL action + ** trigger causes other triggers or action rules attached to the ** child table to fire. In these cases the fk constraint counters - ** might be set incorrectly if any OP_FkCounter related scans are + ** might be set incorrectly if any OP_FkCounter related scans are ** omitted. */ if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){ sqlite3MayAbort(pParse); @@ -107912,7 +124542,7 @@ SQLITE_PRIVATE void sqlite3FkCheck( #define COLUMN_MASK(x) (((x)>31) ? 0xffffffff : ((u32)1<<(x))) /* -** This function is called before generating code to update or delete a +** This function is called before generating code to update or delete a ** row contained in table pTab. */ SQLITE_PRIVATE u32 sqlite3FkOldmask( @@ -107920,10 +124550,10 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask( Table *pTab /* Table being modified */ ){ u32 mask = 0; - if( pParse->db->flags&SQLITE_ForeignKeys ){ + if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ FKey *p; int i; - for(p=pTab->pFKey; p; p=p->pNextFrom){ + for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ for(i=0; inCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ @@ -107942,18 +124572,28 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask( /* -** This function is called before generating code to update or delete a +** This function is called before generating code to update or delete a ** row contained in table pTab. If the operation is a DELETE, then ** parameter aChange is passed a NULL value. For an UPDATE, aChange points ** to an array of size N, where N is the number of columns in table pTab. -** If the i'th column is not modified by the UPDATE, then the corresponding +** If the i'th column is not modified by the UPDATE, then the corresponding ** entry in the aChange[] array is set to -1. If the column is modified, ** the value is 0 or greater. Parameter chngRowid is set to true if the ** UPDATE statement modifies the rowid fields of the table. ** ** If any foreign key processing will be required, this function returns -** true. If there is no foreign key related processing, this function -** returns false. +** non-zero. If there is no foreign key related processing, this function +** returns zero. +** +** For an UPDATE, this function returns 2 if: +** +** * There are any FKs for which pTab is the child and the parent table +** and any FK processing at all is required (even of a different FK), or +** +** * the UPDATE modifies one or more parent keys for which the action is +** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL). +** +** Or, assuming some other foreign key processing is required, 1. */ SQLITE_PRIVATE int sqlite3FkRequired( Parse *pParse, /* Parse context */ @@ -107961,33 +124601,41 @@ SQLITE_PRIVATE int sqlite3FkRequired( int *aChange, /* Non-NULL for UPDATE operations */ int chngRowid /* True for UPDATE that affects rowid */ ){ - if( pParse->db->flags&SQLITE_ForeignKeys ){ + int eRet = 1; /* Value to return if bHaveFK is true */ + int bHaveFK = 0; /* If FK processing is required */ + if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){ if( !aChange ){ - /* A DELETE operation. Foreign key processing is required if the - ** table in question is either the child or parent table for any + /* A DELETE operation. Foreign key processing is required if the + ** table in question is either the child or parent table for any ** foreign key constraint. */ - return (sqlite3FkReferences(pTab) || pTab->pFKey); + bHaveFK = (sqlite3FkReferences(pTab) || pTab->u.tab.pFKey); }else{ /* This is an UPDATE. Foreign key processing is only required if the ** operation modifies one or more child or parent key columns. */ FKey *p; /* Check if any child key columns are being modified. */ - for(p=pTab->pFKey; p; p=p->pNextFrom){ - if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1; + for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){ + if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ + if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2; + bHaveFK = 1; + } } /* Check if any parent key columns are being modified. */ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ - if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1; + if( fkParentIsModified(pTab, p, aChange, chngRowid) ){ + if( p->aAction[1]!=OE_None ) return 2; + bHaveFK = 1; + } } } } - return 0; + return bHaveFK ? eRet : 0; } /* -** This function is called when an UPDATE or DELETE operation is being +** This function is called when an UPDATE or DELETE operation is being ** compiled on table pTab, which is the parent table of foreign-key pFKey. ** If the current operation is an UPDATE, then the pChanges parameter is ** passed a pointer to the list of columns being modified. If it is a @@ -107999,7 +124647,7 @@ SQLITE_PRIVATE int sqlite3FkRequired( ** returned (these actions require no special handling by the triggers ** sub-system, code for them is created by fkScanChildren()). ** -** For example, if pFKey is the foreign key and pTab is table "p" in +** For example, if pFKey is the foreign key and pTab is table "p" in ** the following schema: ** ** CREATE TABLE p(pk PRIMARY KEY); @@ -108012,7 +124660,7 @@ SQLITE_PRIVATE int sqlite3FkRequired( ** END; ** ** The returned pointer is cached as part of the foreign key object. It -** is eventually freed along with the rest of the foreign key object by +** is eventually freed along with the rest of the foreign key object by ** sqlite3FkDelete(). */ static Trigger *fkActionTrigger( @@ -108060,20 +124708,20 @@ static Trigger *fkActionTrigger( assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKeynCol) ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); sqlite3TokenInit(&tToCol, - pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName); - sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName); + pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zCnName); + sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zCnName); /* Create the expression "OLD.zToCol = zFromCol". It is important ** that the "OLD.zToCol" term is on the LHS of the = operator, so ** that the affinity and collation sequence associated with the ** parent table are used for the comparison. */ pEq = sqlite3PExpr(pParse, TK_EQ, - sqlite3PExpr(pParse, TK_DOT, + sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) ); - pWhere = sqlite3ExprAnd(db, pWhere, pEq); + pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); /* For ON UPDATE, construct the next term of the WHEN clause. ** The final WHEN clause will be like this: @@ -108082,24 +124730,32 @@ static Trigger *fkActionTrigger( */ if( pChanges ){ pEq = sqlite3PExpr(pParse, TK_IS, - sqlite3PExpr(pParse, TK_DOT, + sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tOld, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), - sqlite3PExpr(pParse, TK_DOT, + sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)) ); - pWhen = sqlite3ExprAnd(db, pWhen, pEq); + pWhen = sqlite3ExprAnd(pParse, pWhen, pEq); } - + if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){ Expr *pNew; if( action==OE_Cascade ){ - pNew = sqlite3PExpr(pParse, TK_DOT, + pNew = sqlite3PExpr(pParse, TK_DOT, sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)); }else if( action==OE_SetDflt ){ - Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt; + Column *pCol = pFKey->pFrom->aCol + iFromCol; + Expr *pDflt; + if( pCol->colFlags & COLFLAG_GENERATED ){ + testcase( pCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pCol->colFlags & COLFLAG_STORED ); + pDflt = 0; + }else{ + pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol); + } if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); }else{ @@ -108119,27 +124775,27 @@ static Trigger *fkActionTrigger( if( action==OE_Restrict ){ Token tFrom; - Expr *pRaise; + Expr *pRaise; tFrom.z = zFrom; tFrom.n = nFrom; pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); if( pRaise ){ - pRaise->affinity = OE_Abort; + pRaise->affExpr = OE_Abort; } - pSelect = sqlite3SelectNew(pParse, + pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), - sqlite3SrcListAppend(db, 0, &tFrom, 0), + sqlite3SrcListAppend(pParse, 0, &tFrom, 0), pWhere, - 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0 ); pWhere = 0; } /* Disable lookaside memory allocation */ - db->lookaside.bDisable++; + DisableLookaside; - pTrigger = (Trigger *)sqlite3DbMallocZero(db, + pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ sizeof(TriggerStep) + /* Single step in trigger program */ nFrom + 1 /* Space for pStep->zTarget */ @@ -108148,7 +124804,7 @@ static Trigger *fkActionTrigger( pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1]; pStep->zTarget = (char *)&pStep[1]; memcpy((char *)pStep->zTarget, zFrom, nFrom); - + pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); @@ -108159,7 +124815,7 @@ static Trigger *fkActionTrigger( } /* Re-enable the lookaside buffer, if it was disabled earlier. */ - db->lookaside.bDisable--; + EnableLookaside; sqlite3ExprDelete(db, pWhere); sqlite3ExprDelete(db, pWhen); @@ -108170,16 +124826,18 @@ static Trigger *fkActionTrigger( return 0; } assert( pStep!=0 ); + assert( pTrigger!=0 ); switch( action ){ case OE_Restrict: - pStep->op = TK_SELECT; + pStep->op = TK_SELECT; break; - case OE_Cascade: - if( !pChanges ){ - pStep->op = TK_DELETE; - break; + case OE_Cascade: + if( !pChanges ){ + pStep->op = TK_DELETE; + break; } + /* no break */ deliberate_fall_through default: pStep->op = TK_UPDATE; } @@ -108205,9 +124863,9 @@ SQLITE_PRIVATE void sqlite3FkActions( int *aChange, /* Array indicating UPDATEd columns (or 0) */ int bChngRowid /* True if rowid is UPDATEd */ ){ - /* If foreign-key support is enabled, iterate through all FKs that - ** refer to table pTab. If there is an action associated with the FK - ** for this operation (either update or delete), invoke the associated + /* If foreign-key support is enabled, iterate through all FKs that + ** refer to table pTab. If there is an action associated with the FK + ** for this operation (either update or delete), invoke the associated ** trigger sub-program. */ if( pParse->db->flags&SQLITE_ForeignKeys ){ FKey *pFKey; /* Iterator variable */ @@ -108233,9 +124891,9 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ - assert( db==0 || IsVirtual(pTab) - || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); - for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ + assert( IsOrdinaryTable(pTab) ); + for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){ + assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); /* Remove the FK from the fkeyHash hash table. */ if( !db || db->pnBytesFreed==0 ){ @@ -108287,7 +124945,7 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){ /* #include "sqliteInt.h" */ /* -** Generate code that will +** Generate code that will ** ** (1) acquire a lock for table pTab then ** (2) open pTab as cursor iCur. @@ -108304,17 +124962,18 @@ SQLITE_PRIVATE void sqlite3OpenTable( ){ Vdbe *v; assert( !IsVirtual(pTab) ); - v = sqlite3GetVdbe(pParse); + assert( pParse->pVdbe!=0 ); + v = pParse->pVdbe; assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); - sqlite3TableLock(pParse, iDb, pTab->tnum, + sqlite3TableLock(pParse, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); if( HasRowid(pTab) ){ - sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol); + sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol); VdbeComment((v, "%s", pTab->zName)); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk!=0 ); - assert( pPk->tnum==pTab->tnum ); + assert( pPk->tnum==pTab->tnum || CORRUPT_DB ); sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pPk); VdbeComment((v, "%s", pTab->zName)); @@ -108323,7 +124982,7 @@ SQLITE_PRIVATE void sqlite3OpenTable( /* ** Return a pointer to the column affinity string associated with index -** pIdx. A column affinity string has one character for each column in +** pIdx. A column affinity string has one character for each column in ** the table, according to the affinity of the column: ** ** Character Column affinity @@ -108360,48 +125019,89 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ } for(n=0; nnColumn; n++){ i16 x = pIdx->aiColumn[n]; + char aff; if( x>=0 ){ - pIdx->zColAff[n] = pTab->aCol[x].affinity; + aff = pTab->aCol[x].affinity; }else if( x==XN_ROWID ){ - pIdx->zColAff[n] = SQLITE_AFF_INTEGER; + aff = SQLITE_AFF_INTEGER; }else{ - char aff; assert( x==XN_EXPR ); assert( pIdx->aColExpr!=0 ); aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); - if( aff==0 ) aff = SQLITE_AFF_BLOB; - pIdx->zColAff[n] = aff; } + if( affSQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC; + pIdx->zColAff[n] = aff; } pIdx->zColAff[n] = 0; } - + return pIdx->zColAff; } /* +** Make changes to the evolving bytecode to do affinity transformations +** of values that are about to be gathered into a row for table pTab. +** +** For ordinary (legacy, non-strict) tables: +** ----------------------------------------- +** ** Compute the affinity string for table pTab, if it has not already been ** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. ** -** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and -** if iReg>0 then code an OP_Affinity opcode that will set the affinities -** for register iReg and following. Or if affinities exists and iReg==0, +** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries +** which were then optimized out) then this routine becomes a no-op. +** +** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the +** affinities for register iReg and following. Or if iReg==0, ** then just set the P4 operand of the previous opcode (which should be ** an OP_MakeRecord) to the affinity string. ** ** A column affinity string has one character per column: ** -** Character Column affinity -** ------------------------------ -** 'A' BLOB -** 'B' TEXT -** 'C' NUMERIC -** 'D' INTEGER -** 'E' REAL +** Character Column affinity +** --------- --------------- +** 'A' BLOB +** 'B' TEXT +** 'C' NUMERIC +** 'D' INTEGER +** 'E' REAL +** +** For STRICT tables: +** ------------------ +** +** Generate an appropropriate OP_TypeCheck opcode that will verify the +** datatypes against the column definitions in pTab. If iReg==0, that +** means an OP_MakeRecord opcode has already been generated and should be +** the last opcode generated. The new OP_TypeCheck needs to be inserted +** before the OP_MakeRecord. The new OP_TypeCheck should use the same +** register set as the OP_MakeRecord. If iReg>0 then register iReg is +** the first of a series of registers that will form the new record. +** Apply the type checking to that array of registers. */ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ - int i; - char *zColAff = pTab->zColAff; + int i, j; + char *zColAff; + if( pTab->tabFlags & TF_Strict ){ + if( iReg==0 ){ + /* Move the previous opcode (which should be OP_MakeRecord) forward + ** by one slot and insert a new OP_TypeCheck where the current + ** OP_MakeRecord is found */ + VdbeOp *pPrev; + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + pPrev = sqlite3VdbeGetOp(v, -1); + assert( pPrev!=0 ); + assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed ); + pPrev->opcode = OP_TypeCheck; + sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3); + }else{ + /* Insert an isolated OP_Typecheck */ + sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); + } + return; + } + zColAff = pTab->zColAff; if( zColAff==0 ){ sqlite3 *db = sqlite3VdbeDb(v); zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1); @@ -108410,19 +125110,25 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ return; } - for(i=0; inCol; i++){ - zColAff[i] = pTab->aCol[i].affinity; + for(i=j=0; inCol; i++){ + assert( pTab->aCol[i].affinity!=0 || sqlite3VdbeParser(v)->nErr>0 ); + if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ + zColAff[j++] = pTab->aCol[i].affinity; + } } do{ - zColAff[i--] = 0; - }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB ); + zColAff[j--] = 0; + }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB ); pTab->zColAff = zColAff; } - i = sqlite3Strlen30(zColAff); + assert( zColAff!=0 ); + i = sqlite3Strlen30NN(zColAff); if( i ){ if( iReg ){ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); }else{ + assert( sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord + || sqlite3VdbeDb(v)->mallocFailed ); sqlite3VdbeChangeP4(v, -1, zColAff, i); } } @@ -108430,9 +125136,9 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ /* ** Return non-zero if the table pTab in database iDb or any of its indices -** have been opened at any point in the VDBE program. This is used to see if -** a statement of the form "INSERT INTO SELECT ..." can -** run without using a temporary table for the results of the SELECT. +** have been opened at any point in the VDBE program. This is used to see if +** a statement of the form "INSERT INTO SELECT ..." can +** run without using a temporary table for the results of the SELECT. */ static int readsTable(Parse *p, int iDb, Table *pTab){ Vdbe *v = sqlite3GetVdbe(p); @@ -108447,7 +125153,7 @@ static int readsTable(Parse *p, int iDb, Table *pTab){ assert( pOp!=0 ); if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){ Index *pIndex; - int tnum = pOp->p2; + Pgno tnum = pOp->p2; if( tnum==pTab->tnum ){ return 1; } @@ -108468,6 +125174,125 @@ static int readsTable(Parse *p, int iDb, Table *pTab){ return 0; } +/* This walker callback will compute the union of colFlags flags for all +** referenced columns in a CHECK constraint or generated column expression. +*/ +static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 ){ + assert( pExpr->iColumn < pWalker->u.pTab->nCol ); + pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags; + } + return WRC_Continue; +} + +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* +** All regular columns for table pTab have been puts into registers +** starting with iRegStore. The registers that correspond to STORED +** or VIRTUAL columns have not yet been initialized. This routine goes +** back and computes the values for those columns based on the previously +** computed normal columns. +*/ +SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns( + Parse *pParse, /* Parsing context */ + int iRegStore, /* Register holding the first column */ + Table *pTab /* The table */ +){ + int i; + Walker w; + Column *pRedo; + int eProgress; + VdbeOp *pOp; + + assert( pTab->tabFlags & TF_HasGenerated ); + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); + + /* Before computing generated columns, first go through and make sure + ** that appropriate affinity has been applied to the regular columns + */ + sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore); + if( (pTab->tabFlags & TF_HasStored)!=0 ){ + pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1); + if( pOp->opcode==OP_Affinity ){ + /* Change the OP_Affinity argument to '@' (NONE) for all stored + ** columns. '@' is the no-op affinity and those columns have not + ** yet been computed. */ + int ii, jj; + char *zP4 = pOp->p4.z; + assert( zP4!=0 ); + assert( pOp->p4type==P4_DYNAMIC ); + for(ii=jj=0; zP4[jj]; ii++){ + if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){ + continue; + } + if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){ + zP4[jj] = SQLITE_AFF_NONE; + } + jj++; + } + }else if( pOp->opcode==OP_TypeCheck ){ + /* If an OP_TypeCheck was generated because the table is STRICT, + ** then set the P3 operand to indicate that generated columns should + ** not be checked */ + pOp->p3 = 1; + } + } + + /* Because there can be multiple generated columns that refer to one another, + ** this is a two-pass algorithm. On the first pass, mark all generated + ** columns as "not available". + */ + for(i=0; inCol; i++){ + if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); + pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL; + } + } + + w.u.pTab = pTab; + w.xExprCallback = exprColumnFlagUnion; + w.xSelectCallback = 0; + w.xSelectCallback2 = 0; + + /* On the second pass, compute the value of each NOT-AVAILABLE column. + ** Companion code in the TK_COLUMN case of sqlite3ExprCodeTarget() will + ** compute dependencies and mark remove the COLSPAN_NOTAVAIL mark, as + ** they are needed. + */ + pParse->iSelfTab = -iRegStore; + do{ + eProgress = 0; + pRedo = 0; + for(i=0; inCol; i++){ + Column *pCol = pTab->aCol + i; + if( (pCol->colFlags & COLFLAG_NOTAVAIL)!=0 ){ + int x; + pCol->colFlags |= COLFLAG_BUSY; + w.eCode = 0; + sqlite3WalkExpr(&w, sqlite3ColumnExpr(pTab, pCol)); + pCol->colFlags &= ~COLFLAG_BUSY; + if( w.eCode & COLFLAG_NOTAVAIL ){ + pRedo = pCol; + continue; + } + eProgress = 1; + assert( pCol->colFlags & COLFLAG_GENERATED ); + x = sqlite3TableColumnToStorage(pTab, i) + iRegStore; + sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, x); + pCol->colFlags &= ~COLFLAG_NOTAVAIL; + } + } + }while( pRedo && eProgress ); + if( pRedo ){ + sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zCnName); + } + pParse->iSelfTab = 0; +} +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + + #ifndef SQLITE_OMIT_AUTOINCREMENT /* ** Locate or create an AutoincInfo structure associated with table pTab @@ -108482,11 +125307,12 @@ static int readsTable(Parse *p, int iDb, Table *pTab){ ** first use of table pTab. On 2nd and subsequent uses, the original ** AutoincInfo structure is used. ** -** Three memory locations are allocated: +** Four consecutive registers are allocated: ** -** (1) Register to hold the name of the pTab table. -** (2) Register to hold the maximum ROWID of pTab. -** (3) Register to hold the rowid in sqlite_sequence of pTab +** (1) The name of the pTab table. +** (2) The maximum ROWID of pTab. +** (3) The rowid in sqlite_sequence of pTab +** (4) The original value of the max ROWID in pTab, or NULL if none ** ** The 2nd register is the one that is returned. That is all the ** insert routine needs to know about. @@ -108497,24 +125323,41 @@ static int autoIncBegin( Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ + assert( pParse->db->aDb[iDb].pSchema!=0 ); if( (pTab->tabFlags & TF_Autoincrement)!=0 - && (pParse->db->flags & SQLITE_Vacuum)==0 + && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; + Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab; + + /* Verify that the sqlite_sequence table exists and is an ordinary + ** rowid table with exactly two columns. + ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ + if( pSeqTab==0 + || !HasRowid(pSeqTab) + || NEVER(IsVirtual(pSeqTab)) + || pSeqTab->nCol!=2 + ){ + pParse->nErr++; + pParse->rc = SQLITE_CORRUPT_SEQUENCE; + return 0; + } pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); - if( pInfo==0 ) return 0; + sqlite3ParserAddCleanup(pToplevel, sqlite3DbFree, pInfo); + testcase( pParse->earlyCleanup ); + if( pParse->db->mallocFailed ) return 0; pInfo->pNext = pToplevel->pAinc; pToplevel->pAinc = pInfo; pInfo->pTab = pTab; pInfo->iDb = iDb; pToplevel->nMem++; /* Register to hold name of table */ pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */ - pToplevel->nMem++; /* Rowid in sqlite_sequence */ + pToplevel->nMem +=2; /* Rowid in sqlite_sequence + orig max val */ } memId = pInfo->regCtr; } @@ -108523,7 +125366,7 @@ static int autoIncBegin( /* ** This routine generates code that will initialize all of the -** register used by the autoincrement tracker. +** register used by the autoincrement tracker. */ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ AutoincInfo *p; /* Information about an AUTOINCREMENT */ @@ -108542,15 +125385,17 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList autoInc[] = { /* 0 */ {OP_Null, 0, 0, 0}, - /* 1 */ {OP_Rewind, 0, 9, 0}, + /* 1 */ {OP_Rewind, 0, 10, 0}, /* 2 */ {OP_Column, 0, 0, 0}, - /* 3 */ {OP_Ne, 0, 7, 0}, + /* 3 */ {OP_Ne, 0, 9, 0}, /* 4 */ {OP_Rowid, 0, 0, 0}, /* 5 */ {OP_Column, 0, 1, 0}, - /* 6 */ {OP_Goto, 0, 9, 0}, - /* 7 */ {OP_Next, 0, 2, 0}, - /* 8 */ {OP_Integer, 0, 0, 0}, - /* 9 */ {OP_Close, 0, 0, 0} + /* 6 */ {OP_AddImm, 0, 0, 0}, + /* 7 */ {OP_Copy, 0, 0, 0}, + /* 8 */ {OP_Goto, 0, 11, 0}, + /* 9 */ {OP_Next, 0, 2, 0}, + /* 10 */ {OP_Integer, 0, 0, 0}, + /* 11 */ {OP_Close, 0, 0, 0} }; VdbeOp *aOp; pDb = &db->aDb[p->iDb]; @@ -108561,14 +125406,18 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){ aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn); if( aOp==0 ) break; aOp[0].p2 = memId; - aOp[0].p3 = memId+1; + aOp[0].p3 = memId+2; aOp[2].p3 = memId; aOp[3].p1 = memId-1; aOp[3].p3 = memId; aOp[3].p5 = SQLITE_JUMPIFNULL; aOp[4].p2 = memId+1; aOp[5].p3 = memId; - aOp[8].p2 = memId; + aOp[6].p1 = memId; + aOp[7].p2 = memId+2; + aOp[7].p1 = memId; + aOp[10].p2 = memId; + if( pParse->nTab==0 ) pParse->nTab = 1; } } @@ -108615,6 +125464,8 @@ static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){ iRec = sqlite3GetTempReg(pParse); assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); + sqlite3VdbeAddOp3(v, OP_Le, memId+2, sqlite3VdbeCurrentAddr(v)+7, memId); + VdbeCoverage(v); sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn); if( aOp==0 ) break; @@ -108751,12 +125602,12 @@ SQLITE_PRIVATE void sqlite3Insert( Parse *pParse, /* Parser context */ SrcList *pTabList, /* Name of table into which we are inserting */ Select *pSelect, /* A SELECT statement to use as the data source */ - IdList *pColumn, /* Column names corresponding to IDLIST. */ - int onError /* How to handle constraint errors */ + IdList *pColumn, /* Column names corresponding to IDLIST, or NULL. */ + int onError, /* How to handle constraint errors */ + Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */ ){ sqlite3 *db; /* The main database structure */ Table *pTab; /* The table to insert into. aka TABLE */ - char *zTab; /* Name of the table into which we are inserting */ int i, j; /* Loop counters */ Vdbe *v; /* Generate code into this virtual machine */ Index *pIdx; /* For looping over indices of the table */ @@ -108776,6 +125627,7 @@ SQLITE_PRIVATE void sqlite3Insert( u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ + int iRegStore; /* Register in which to store next column */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ @@ -108793,10 +125645,12 @@ SQLITE_PRIVATE void sqlite3Insert( #endif db = pParse->db; - memset(&dest, 0, sizeof(dest)); - if( pParse->nErr || db->mallocFailed ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto insert_cleanup; } + assert( db->mallocFailed==0 ); + dest.iSDParm = 0; /* Suppress a harmless compiler warning */ /* If the Select object is really just a simple VALUES() list with a ** single row (the common case) then keep that one row of values @@ -108812,8 +125666,6 @@ SQLITE_PRIVATE void sqlite3Insert( /* Locate the table into which we will be inserting new information. */ assert( pTabList->nSrc==1 ); - zTab = pTabList->a[0].zName; - if( NEVER(zTab==0) ) goto insert_cleanup; pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; @@ -108831,7 +125683,7 @@ SQLITE_PRIVATE void sqlite3Insert( */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask); - isView = pTab->pSelect!=0; + isView = IsView(pTab); #else # define pTrigger 0 # define tmask 0 @@ -108873,7 +125725,11 @@ SQLITE_PRIVATE void sqlite3Insert( ** ** This is the 2nd template. */ - if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ + if( pColumn==0 + && pSelect!=0 + && pTrigger==0 + && xferOptimization(pParse, pTab, pSelect, onError, iDb) + ){ assert( !pTrigger ); assert( pList==0 ); goto insert_end; @@ -108885,8 +125741,8 @@ SQLITE_PRIVATE void sqlite3Insert( */ regAutoinc = autoIncBegin(pParse, iDb, pTab); - /* Allocate registers for holding the rowid of the new row, - ** the content of the new row, and the assembled row record. + /* Allocate a block registers to hold the rowid and the values + ** for all columns of the new row. */ regRowid = regIns = pParse->nMem+1; pParse->nMem += pTab->nCol + 1; @@ -108897,7 +125753,7 @@ SQLITE_PRIVATE void sqlite3Insert( regData = regRowid+1; /* If the INSERT statement included an IDLIST term, then make sure - ** all elements of the IDLIST really are columns of the table and + ** all elements of the IDLIST really are columns of the table and ** remember the column indices. ** ** If the table has an INTEGER PRIMARY KEY column and that column @@ -108905,21 +125761,37 @@ SQLITE_PRIVATE void sqlite3Insert( ** the index into IDLIST of the primary key column. ipkColumn is ** the index of the primary key as it appears in IDLIST, not as ** is appears in the original table. (The index of the INTEGER - ** PRIMARY KEY in the original table is pTab->iPKey.) + ** PRIMARY KEY in the original table is pTab->iPKey.) After this + ** loop, if ipkColumn==(-1), that means that integer primary key + ** is unspecified, and hence the table is either WITHOUT ROWID or + ** it will automatically generated an integer primary key. + ** + ** bIdListInOrder is true if the columns in IDLIST are in storage + ** order. This enables an optimization that avoids shuffling the + ** columns into storage order. False negatives are harmless, + ** but false positives will cause database corruption. */ - bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0; + bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; if( pColumn ){ for(i=0; inId; i++){ pColumn->a[i].idx = -1; } for(i=0; inId; i++){ for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ + if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){ pColumn->a[i].idx = j; if( i!=j ) bIdListInOrder = 0; if( j==pTab->iPKey ){ ipkColumn = i; assert( !withoutRowid ); } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ + sqlite3ErrorMsg(pParse, + "cannot INSERT into generated column \"%s\"", + pTab->aCol[j].zCnName); + goto insert_cleanup; + } +#endif break; } } @@ -108929,7 +125801,7 @@ SQLITE_PRIVATE void sqlite3Insert( bIdListInOrder = 0; }else{ sqlite3ErrorMsg(pParse, "table %S has no column named %s", - pTabList, 0, pColumn->a[i].zName); + pTabList->a, pColumn->a[i].zName); pParse->checkSchema = 1; goto insert_cleanup; } @@ -108957,7 +125829,9 @@ SQLITE_PRIVATE void sqlite3Insert( dest.nSdst = pTab->nCol; rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; - if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; + assert( db->pParse==pParse ); + if( rc || pParse->nErr ) goto insert_cleanup; + assert( db->mallocFailed==0 ); sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ assert( pSelect->pEList ); @@ -108969,7 +125843,7 @@ SQLITE_PRIVATE void sqlite3Insert( ** the destination table (template 3). ** ** A temp table must be used if the table being updated is also one - ** of the tables being read by the SELECT statement. Also use a + ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ if( pTrigger || readsTable(pParse, iDb, pTab) ){ @@ -109005,7 +125879,7 @@ SQLITE_PRIVATE void sqlite3Insert( sqlite3ReleaseTempReg(pParse, regTempRowid); } }else{ - /* This is the case if the data for the INSERT is coming from a + /* This is the case if the data for the INSERT is coming from a ** single-row VALUES clause */ NameContext sNC; @@ -109024,33 +125898,55 @@ SQLITE_PRIVATE void sqlite3Insert( } /* If there is no IDLIST term but the table has an integer primary - ** key, the set the ipkColumn variable to the integer primary key + ** key, the set the ipkColumn variable to the integer primary key ** column index in the original table definition. */ if( pColumn==0 && nColumn>0 ){ ipkColumn = pTab->iPKey; - } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); + for(i=ipkColumn-1; i>=0; i--){ + if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); + ipkColumn--; + } + } + } +#endif - /* Make sure the number of columns in the source data matches the number - ** of columns to be inserted into the table. - */ - for(i=0; inCol; i++){ - nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0); - } - if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){ - sqlite3ErrorMsg(pParse, - "table %S has %d columns but %d values were supplied", - pTabList, 0, pTab->nCol-nHidden, nColumn); - goto insert_cleanup; + /* Make sure the number of columns in the source data matches the number + ** of columns to be inserted into the table. + */ + assert( TF_HasHidden==COLFLAG_HIDDEN ); + assert( TF_HasGenerated==COLFLAG_GENERATED ); + assert( COLFLAG_NOINSERT==(COLFLAG_GENERATED|COLFLAG_HIDDEN) ); + if( (pTab->tabFlags & (TF_HasGenerated|TF_HasHidden))!=0 ){ + for(i=0; inCol; i++){ + if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++; + } + } + if( nColumn!=(pTab->nCol-nHidden) ){ + sqlite3ErrorMsg(pParse, + "table %S has %d columns but %d values were supplied", + pTabList->a, pTab->nCol-nHidden, nColumn); + goto insert_cleanup; + } } if( pColumn!=0 && nColumn!=pColumn->nId ){ sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId); goto insert_cleanup; } - + /* Initialize the count of rows to be inserted */ - if( db->flags & SQLITE_CountRows ){ + if( (db->flags & SQLITE_CountRows)!=0 + && !pParse->nested + && !pParse->pTriggerTab + && !pParse->bReturning + ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } @@ -109060,7 +125956,7 @@ SQLITE_PRIVATE void sqlite3Insert( int nIdx; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, &iDataCur, &iIdxCur); - aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1)); + aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+2)); if( aRegIdx==0 ){ goto insert_cleanup; } @@ -109069,7 +125965,40 @@ SQLITE_PRIVATE void sqlite3Insert( aRegIdx[i] = ++pParse->nMem; pParse->nMem += pIdx->nColumn; } + aRegIdx[i] = ++pParse->nMem; /* Register to store the table record */ } +#ifndef SQLITE_OMIT_UPSERT + if( pUpsert ){ + Upsert *pNx; + if( IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"", + pTab->zName); + goto insert_cleanup; + } + if( IsView(pTab) ){ + sqlite3ErrorMsg(pParse, "cannot UPSERT a view"); + goto insert_cleanup; + } + if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){ + goto insert_cleanup; + } + pTabList->a[0].iCursor = iDataCur; + pNx = pUpsert; + do{ + pNx->pUpsertSrc = pTabList; + pNx->regData = regData; + pNx->iDataCur = iDataCur; + pNx->iIdxCur = iIdxCur; + if( pNx->pUpsertTarget ){ + if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){ + goto insert_cleanup; + } + } + pNx = pNx->pNextUpsert; + }while( pNx!=0 ); + } +#endif + /* This is the top of the main insertion loop */ if( useTempTable ){ @@ -109093,13 +126022,100 @@ SQLITE_PRIVATE void sqlite3Insert( ** goto C ** D: ... */ + sqlite3VdbeReleaseRegisters(pParse, regData, pTab->nCol, 0, 0); addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); + if( ipkColumn>=0 ){ + /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the + ** SELECT, go ahead and copy the value into the rowid slot now, so that + ** the value does not get overwritten by a NULL at tag-20191021-002. */ + sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); + } + } + + /* Compute data for ordinary columns of the new entry. Values + ** are written in storage order into registers starting with regData. + ** Only ordinary columns are computed in this loop. The rowid + ** (if there is one) is computed later and generated columns are + ** computed after the rowid since they might depend on the value + ** of the rowid. + */ + nHidden = 0; + iRegStore = regData; assert( regData==regRowid+1 ); + for(i=0; inCol; i++, iRegStore++){ + int k; + u32 colFlags; + assert( i>=nHidden ); + if( i==pTab->iPKey ){ + /* tag-20191021-002: References to the INTEGER PRIMARY KEY are filled + ** using the rowid. So put a NULL in the IPK slot of the record to avoid + ** using excess space. The file format definition requires this extra + ** NULL - we cannot optimize further by skipping the column completely */ + sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); + continue; + } + if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){ + nHidden++; + if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ + /* Virtual columns do not participate in OP_MakeRecord. So back up + ** iRegStore by one slot to compensate for the iRegStore++ in the + ** outer for() loop */ + iRegStore--; + continue; + }else if( (colFlags & COLFLAG_STORED)!=0 ){ + /* Stored columns are computed later. But if there are BEFORE + ** triggers, the slots used for stored columns will be OP_Copy-ed + ** to a second block of registers, so the register needs to be + ** initialized to NULL to avoid an uninitialized register read */ + if( tmask & TRIGGER_BEFORE ){ + sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); + } + continue; + }else if( pColumn==0 ){ + /* Hidden columns that are not explicitly named in the INSERT + ** get there default value */ + sqlite3ExprCodeFactorable(pParse, + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + iRegStore); + continue; + } + } + if( pColumn ){ + for(j=0; jnId && pColumn->a[j].idx!=i; j++){} + if( j>=pColumn->nId ){ + /* A column not named in the insert column list gets its + ** default value */ + sqlite3ExprCodeFactorable(pParse, + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + iRegStore); + continue; + } + k = j; + }else if( nColumn==0 ){ + /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ + sqlite3ExprCodeFactorable(pParse, + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + iRegStore); + continue; + }else{ + k = i - nHidden; + } + + if( useTempTable ){ + sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore); + }else if( pSelect ){ + if( regFromSelect!=regData ){ + sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); + } + }else{ + sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore); + } } + /* Run the BEFORE and INSTEAD OF triggers, if there are any */ - endOfLoop = sqlite3VdbeMakeLabel(v); + endOfLoop = sqlite3VdbeMakeLabel(pParse); if( tmask & TRIGGER_BEFORE ){ int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1); @@ -109126,30 +126142,21 @@ SQLITE_PRIVATE void sqlite3Insert( sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); } - /* Cannot have triggers on a virtual table. If it were possible, - ** this block would have to account for hidden column. - */ - assert( !IsVirtual(pTab) ); + /* Copy the new data already generated. */ + assert( pTab->nNVCol>0 ); + sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1); - /* Create the new column data - */ - for(i=j=0; inCol; i++){ - if( pColumn ){ - for(j=0; jnId; j++){ - if( pColumn->a[j].idx==i ) break; - } - } - if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) - || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){ - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1); - }else if( useTempTable ){ - sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); - }else{ - assert( pSelect==0 ); /* Otherwise useTempTable is true */ - sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1); - } - if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Compute the new value for generated columns after all other + ** columns have already been computed. This must be done after + ** computing the ROWID in case one of the generated columns + ** refers to the ROWID. */ + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); + sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab); } +#endif /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. @@ -109161,35 +126168,30 @@ SQLITE_PRIVATE void sqlite3Insert( } /* Fire BEFORE or INSTEAD OF triggers */ - sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, + sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE, pTab, regCols-pTab->nCol-1, onError, endOfLoop); sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1); } - /* Compute the content of the next row to insert into a range of - ** registers beginning at regIns. - */ if( !isView ){ if( IsVirtual(pTab) ){ /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2(v, OP_Null, 0, regIns); } if( ipkColumn>=0 ){ + /* Compute the new rowid */ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid); }else if( pSelect ){ - sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); + /* Rowid already initialized at tag-20191021-001 */ }else{ - VdbeOp *pOp; - sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); - pOp = sqlite3VdbeGetOp(v, -1); - if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){ + Expr *pIpk = pList->a[ipkColumn].pExpr; + if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){ + sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; - pOp->opcode = OP_NewRowid; - pOp->p1 = iDataCur; - pOp->p2 = regRowid; - pOp->p3 = regAutoinc; + }else{ + sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid); } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid @@ -109215,45 +126217,15 @@ SQLITE_PRIVATE void sqlite3Insert( } autoIncStep(pParse, regAutoinc, regRowid); - /* Compute data for all columns of the new entry, beginning - ** with the first column. - */ - nHidden = 0; - for(i=0; inCol; i++){ - int iRegStore = regRowid+1+i; - if( i==pTab->iPKey ){ - /* The value of the INTEGER PRIMARY KEY column is always a NULL. - ** Whenever this column is read, the rowid will be substituted - ** in its place. Hence, fill this column with a NULL to avoid - ** taking up data space with information that will never be used. - ** As there may be shallow copies of this value, make it a soft-NULL */ - sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); - continue; - } - if( pColumn==0 ){ - if( IsHiddenColumn(&pTab->aCol[i]) ){ - j = -1; - nHidden++; - }else{ - j = i - nHidden; - } - }else{ - for(j=0; jnId; j++){ - if( pColumn->a[j].idx==i ) break; - } - } - if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); - }else if( useTempTable ){ - sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); - }else if( pSelect ){ - if( regFromSelect!=regData ){ - sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore); - } - }else{ - sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore); - } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Compute the new value for generated columns after all other + ** columns have already been computed. This must be done after + ** computing the ROWID in case one of the generated columns + ** is derived from the INTEGER PRIMARY KEY. */ + if( pTab->tabFlags & TF_HasGenerated ){ + sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab); } +#endif /* Generate code to check constraints and generate index keys and ** do the insertion. @@ -109268,10 +126240,10 @@ SQLITE_PRIVATE void sqlite3Insert( }else #endif { - int isReplace; /* Set to true if constraints may cause a replace */ + int isReplace = 0;/* Set to true if constraints may cause a replace */ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, - regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0 + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert ); sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); @@ -109279,28 +126251,33 @@ SQLITE_PRIVATE void sqlite3Insert( ** constraints or (b) there are no triggers and this table is not a ** parent table in a foreign key constraint. It is safe to set the ** flag in the second case as if any REPLACE constraint is hit, an - ** OP_Delete or OP_IdxDelete instruction will be executed on each + ** OP_Delete or OP_IdxDelete instruction will be executed on each ** cursor that is disturbed. And these instructions both clear the ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT ** functionality. */ - bUseSeek = (isReplace==0 || (pTrigger==0 && - ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0) - )); + bUseSeek = (isReplace==0 || !sqlite3VdbeHasSubProgram(v)); sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, regIns, aRegIdx, 0, appendFlag, bUseSeek ); } +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + }else if( pParse->bReturning ){ + /* If there is a RETURNING clause, populate the rowid register with + ** constant value -1, in case one or more of the returned expressions + ** refer to the "rowid" of the view. */ + sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid); +#endif } /* Update the count of rows that are inserted */ - if( (db->flags & SQLITE_CountRows)!=0 ){ + if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } if( pTrigger ){ /* Code AFTER triggers */ - sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, + sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, pTab, regData-2-pTab->nCol, onError, endOfLoop); } @@ -109314,10 +126291,21 @@ SQLITE_PRIVATE void sqlite3Insert( sqlite3VdbeAddOp1(v, OP_Close, srcTab); }else if( pSelect ){ sqlite3VdbeGoto(v, addrCont); +#ifdef SQLITE_DEBUG + /* If we are jumping back to an OP_Yield that is preceded by an + ** OP_ReleaseReg, set the p5 flag on the OP_Goto so that the + ** OP_ReleaseReg will be included in the loop. */ + if( sqlite3VdbeGetOp(v, addrCont-1)->opcode==OP_ReleaseReg ){ + assert( sqlite3VdbeGetOp(v, addrCont)->opcode==OP_Yield ); + sqlite3VdbeChangeP5(v, 1); + } +#endif sqlite3VdbeJumpHere(v, addrInsTop); } +#ifndef SQLITE_OMIT_XFER_OPT insert_end: +#endif /* SQLITE_OMIT_XFER_OPT */ /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. @@ -109327,19 +126315,18 @@ SQLITE_PRIVATE void sqlite3Insert( } /* - ** Return the number of rows inserted. If this routine is + ** Return the number of rows inserted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ - if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ - sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC); + if( regRowCount ){ + sqlite3CodeChangeCount(v, regRowCount, "rows inserted"); } insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); + sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); sqlite3DbFree(db, aRegIdx); @@ -109359,14 +126346,15 @@ SQLITE_PRIVATE void sqlite3Insert( #endif /* -** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged() +** Meanings of bits in of pWalker->eCode for +** sqlite3ExprReferencesUpdatedColumn() */ #define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */ #define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */ -/* This is the Walker callback from checkConstraintUnchanged(). Set -** bit 0x01 of pWalker->eCode if -** pWalker->eCode to 0 if this expression node references any of the +/* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn(). +* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this +** expression node references any of the ** columns that are being modifed by an UPDATE statement. */ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ @@ -109388,12 +126376,21 @@ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ ** only columns that are modified by the UPDATE are those for which ** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true. ** -** Return true if CHECK constraint pExpr does not use any of the +** Return true if CHECK constraint pExpr uses any of the ** changing columns (or the rowid if it is changing). In other words, -** return true if this CHECK constraint can be skipped when validating +** return true if this CHECK constraint must be validated for ** the new row in the UPDATE statement. +** +** 2018-09-15: pExpr might also be an expression for an index-on-expressions. +** The operation of this routine is the same - return true if an only if +** the expression uses one or more of columns identified by the second and +** third arguments. */ -static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ +SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn( + Expr *pExpr, /* The expression to be checked */ + int *aiChng, /* aiChng[x]>=0 if column x changed by the UPDATE */ + int chngRowid /* True if UPDATE changes the rowid */ +){ Walker w; memset(&w, 0, sizeof(w)); w.eCode = 0; @@ -109408,7 +126405,71 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ testcase( w.eCode==CKCNSTRNT_COLUMN ); testcase( w.eCode==CKCNSTRNT_ROWID ); testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); - return !w.eCode; + return w.eCode!=0; +} + +/* +** The sqlite3GenerateConstraintChecks() routine usually wants to visit +** the indexes of a table in the order provided in the Table->pIndex list. +** However, sometimes (rarely - when there is an upsert) it wants to visit +** the indexes in a different order. The following data structures accomplish +** this. +** +** The IndexIterator object is used to walk through all of the indexes +** of a table in either Index.pNext order, or in some other order established +** by an array of IndexListTerm objects. +*/ +typedef struct IndexListTerm IndexListTerm; +typedef struct IndexIterator IndexIterator; +struct IndexIterator { + int eType; /* 0 for Index.pNext list. 1 for an array of IndexListTerm */ + int i; /* Index of the current item from the list */ + union { + struct { /* Use this object for eType==0: A Index.pNext list */ + Index *pIdx; /* The current Index */ + } lx; + struct { /* Use this object for eType==1; Array of IndexListTerm */ + int nIdx; /* Size of the array */ + IndexListTerm *aIdx; /* Array of IndexListTerms */ + } ax; + } u; +}; + +/* When IndexIterator.eType==1, then each index is an array of instances +** of the following object +*/ +struct IndexListTerm { + Index *p; /* The index */ + int ix; /* Which entry in the original Table.pIndex list is this index*/ +}; + +/* Return the first index on the list */ +static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){ + assert( pIter->i==0 ); + if( pIter->eType ){ + *pIx = pIter->u.ax.aIdx[0].ix; + return pIter->u.ax.aIdx[0].p; + }else{ + *pIx = 0; + return pIter->u.lx.pIdx; + } +} + +/* Return the next index from the list. Return NULL when out of indexes */ +static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){ + if( pIter->eType ){ + int i = ++pIter->i; + if( i>=pIter->u.ax.nIdx ){ + *pIx = i; + return 0; + } + *pIx = pIter->u.ax.aIdx[i].ix; + return pIter->u.ax.aIdx[i].p; + }else{ + ++(*pIx); + pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext; + return pIter->u.lx.pIdx; + } } /* @@ -109446,6 +126507,14 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){ ** the same as the order of indices on the linked list of indices ** at pTab->pIndex. ** +** (2019-05-07) The generated code also creates a new record for the +** main table, if pTab is a rowid table, and stores that record in the +** register identified by aRegIdx[nIdx] - in other words in the first +** entry of aRegIdx[] past the last index. It is important that the +** record be generated during constraint checks to avoid affinity changes +** to the register content that occur after constraint checks but before +** the new record is inserted. +** ** The caller must have already opened writeable cursors on the main ** table and all applicable indices (that is to say, all indices for which ** aRegIdx[] is not zero). iDataCur is the cursor for the main table when @@ -109506,33 +126575,44 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( u8 overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ - int *aiChng /* column i is unchanged if aiChng[i]<0 */ + int *aiChng, /* column i is unchanged if aiChng[i]<0 */ + Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */ ){ Vdbe *v; /* VDBE under constrution */ Index *pIdx; /* Pointer to one of the indices */ - Index *pPk = 0; /* The PRIMARY KEY index */ + Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */ sqlite3 *db; /* Database connection */ int i; /* loop counter */ int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ - int addr1; /* Address of jump instruction */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ - int ipkTop = 0; /* Top of the rowid change constraint check */ - int ipkBottom = 0; /* Bottom of the rowid change constraint check */ - u8 isUpdate; /* True if this is an UPDATE operation */ + Upsert *pUpsertClause = 0; /* The specific ON CONFLICT clause for pIdx */ + u8 isUpdate; /* True if this is an UPDATE operation */ u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ + int upsertIpkReturn = 0; /* Address of Goto at end of IPK uniqueness check */ + int upsertIpkDelay = 0; /* Address of Goto to bypass initial IPK check */ + int ipkTop = 0; /* Top of the IPK uniqueness check */ + int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */ + /* Variables associated with retesting uniqueness constraints after + ** replace triggers fire have run */ + int regTrigCnt; /* Register used to count replace trigger invocations */ + int addrRecheck = 0; /* Jump here to recheck all uniqueness constraints */ + int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */ + Trigger *pTrigger; /* List of DELETE triggers on the table pTab */ + int nReplaceTrig = 0; /* Number of replace triggers coded */ + IndexIterator sIdxIter; /* Index iterator */ isUpdate = regOldData!=0; db = pParse->db; - v = sqlite3GetVdbe(pParse); + v = pParse->pVdbe; assert( v!=0 ); - assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + assert( !IsView(pTab) ); /* This table is not a VIEW */ nCol = pTab->nCol; - + /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for - ** normal rowid tables. nPkField is the number of key fields in the + ** normal rowid tables. nPkField is the number of key fields in the ** pPk index or 1 for a rowid table. In other words, nPkField is the ** number of fields in the true primary key of the table. */ if( HasRowid(pTab) ){ @@ -109549,90 +126629,287 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Test all NOT NULL constraints. */ - for(i=0; iiPKey ){ - continue; /* ROWID is never NULL */ - } - if( aiChng && aiChng[i]<0 ){ - /* Don't bother checking for NOT NULL on columns that do not change */ - continue; - } - onError = pTab->aCol[i].notNull; - if( onError==OE_None ) continue; /* This column is allowed to be NULL */ - if( overrideError!=OE_Default ){ - onError = overrideError; - }else if( onError==OE_Default ){ - onError = OE_Abort; - } - if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ - onError = OE_Abort; - } - assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail - || onError==OE_Ignore || onError==OE_Replace ); - switch( onError ){ - case OE_Abort: - sqlite3MayAbort(pParse); - /* Fall through */ - case OE_Rollback: - case OE_Fail: { - char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, - pTab->aCol[i].zName); - sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, - regNewData+1+i); - sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); - sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); - VdbeCoverage(v); - break; - } - case OE_Ignore: { - sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); - VdbeCoverage(v); + if( pTab->tabFlags & TF_HasNotNull ){ + int b2ndPass = 0; /* True if currently running 2nd pass */ + int nSeenReplace = 0; /* Number of ON CONFLICT REPLACE operations */ + int nGenerated = 0; /* Number of generated columns with NOT NULL */ + while(1){ /* Make 2 passes over columns. Exit loop via "break" */ + for(i=0; iaCol[i]; /* The column to check for NOT NULL */ + int isGenerated; /* non-zero if column is generated */ + onError = pCol->notNull; + if( onError==OE_None ) continue; /* No NOT NULL on this column */ + if( i==pTab->iPKey ){ + continue; /* ROWID is never NULL */ + } + isGenerated = pCol->colFlags & COLFLAG_GENERATED; + if( isGenerated && !b2ndPass ){ + nGenerated++; + continue; /* Generated columns processed on 2nd pass */ + } + if( aiChng && aiChng[i]<0 && !isGenerated ){ + /* Do not check NOT NULL on columns that do not change */ + continue; + } + if( overrideError!=OE_Default ){ + onError = overrideError; + }else if( onError==OE_Default ){ + onError = OE_Abort; + } + if( onError==OE_Replace ){ + if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */ + || pCol->iDflt==0 /* REPLACE is ABORT if no DEFAULT value */ + ){ + testcase( pCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pCol->colFlags & COLFLAG_STORED ); + testcase( pCol->colFlags & COLFLAG_GENERATED ); + onError = OE_Abort; + }else{ + assert( !isGenerated ); + } + }else if( b2ndPass && !isGenerated ){ + continue; + } + assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail + || onError==OE_Ignore || onError==OE_Replace ); + testcase( i!=sqlite3TableColumnToStorage(pTab, i) ); + iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; + switch( onError ){ + case OE_Replace: { + int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg); + VdbeCoverage(v); + assert( (pCol->colFlags & COLFLAG_GENERATED)==0 ); + nSeenReplace++; + sqlite3ExprCodeCopy(pParse, + sqlite3ColumnExpr(pTab, pCol), iReg); + sqlite3VdbeJumpHere(v, addr1); + break; + } + case OE_Abort: + sqlite3MayAbort(pParse); + /* no break */ deliberate_fall_through + case OE_Rollback: + case OE_Fail: { + char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, + pCol->zCnName); + sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, + onError, iReg); + sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); + sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); + VdbeCoverage(v); + break; + } + default: { + assert( onError==OE_Ignore ); + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest); + VdbeCoverage(v); + break; + } + } /* end switch(onError) */ + } /* end loop i over columns */ + if( nGenerated==0 && nSeenReplace==0 ){ + /* If there are no generated columns with NOT NULL constraints + ** and no NOT NULL ON CONFLICT REPLACE constraints, then a single + ** pass is sufficient */ break; } - default: { - assert( onError==OE_Replace ); - addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); - VdbeCoverage(v); - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); - sqlite3VdbeJumpHere(v, addr1); - break; + if( b2ndPass ) break; /* Never need more than 2 passes */ + b2ndPass = 1; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( nSeenReplace>0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){ + /* If any NOT NULL ON CONFLICT REPLACE constraints fired on the + ** first pass, recomputed values for all generated columns, as + ** those values might depend on columns affected by the REPLACE. + */ + sqlite3ComputeGeneratedColumns(pParse, regNewData+1, pTab); } - } - } +#endif + } /* end of 2-pass loop */ + } /* end if( has-not-null-constraints ) */ /* Test all CHECK constraints */ #ifndef SQLITE_OMIT_CHECK if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = pTab->pCheck; - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; inExpr; i++){ int allOk; + Expr *pCopy; Expr *pExpr = pCheck->a[i].pExpr; - if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue; - allOk = sqlite3VdbeMakeLabel(v); - sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); + if( aiChng + && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng) + ){ + /* The check constraints do not reference any of the columns being + ** updated so there is no point it verifying the check constraint */ + continue; + } + if( bAffinityDone==0 ){ + sqlite3TableAffinity(v, pTab, regNewData+1); + bAffinityDone = 1; + } + allOk = sqlite3VdbeMakeLabel(pParse); + sqlite3VdbeVerifyAbortable(v, onError); + pCopy = sqlite3ExprDup(db, pExpr, 0); + if( !db->mallocFailed ){ + sqlite3ExprIfTrue(pParse, pCopy, allOk, SQLITE_JUMPIFNULL); + } + sqlite3ExprDelete(db, pCopy); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); }else{ - char *zName = pCheck->a[i].zName; - if( zName==0 ) zName = pTab->zName; - if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ + char *zName = pCheck->a[i].zEName; + assert( zName!=0 || pParse->db->mallocFailed ); + if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zName, P4_TRANSIENT, P5_ConstraintCheck); } sqlite3VdbeResolveLabel(v, allOk); } + pParse->iSelfTab = 0; } #endif /* !defined(SQLITE_OMIT_CHECK) */ + /* UNIQUE and PRIMARY KEY constraints should be handled in the following + ** order: + ** + ** (1) OE_Update + ** (2) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore + ** (3) OE_Replace + ** + ** OE_Fail and OE_Ignore must happen before any changes are made. + ** OE_Update guarantees that only a single row will change, so it + ** must happen before OE_Replace. Technically, OE_Abort and OE_Rollback + ** could happen in any order, but they are grouped up front for + ** convenience. + ** + ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43 + ** The order of constraints used to have OE_Update as (2) and OE_Abort + ** and so forth as (1). But apparently PostgreSQL checks the OE_Update + ** constraint before any others, so it had to be moved. + ** + ** Constraint checking code is generated in this order: + ** (A) The rowid constraint + ** (B) Unique index constraints that do not have OE_Replace as their + ** default conflict resolution strategy + ** (C) Unique index that do use OE_Replace by default. + ** + ** The ordering of (2) and (3) is accomplished by making sure the linked + ** list of indexes attached to a table puts all OE_Replace indexes last + ** in the list. See sqlite3CreateIndex() for where that happens. + */ + sIdxIter.eType = 0; + sIdxIter.i = 0; + sIdxIter.u.ax.aIdx = 0; /* Silence harmless compiler warning */ + sIdxIter.u.lx.pIdx = pTab->pIndex; + if( pUpsert ){ + if( pUpsert->pUpsertTarget==0 ){ + /* There is just on ON CONFLICT clause and it has no constraint-target */ + assert( pUpsert->pNextUpsert==0 ); + if( pUpsert->isDoUpdate==0 ){ + /* A single ON CONFLICT DO NOTHING clause, without a constraint-target. + ** Make all unique constraint resolution be OE_Ignore */ + overrideError = OE_Ignore; + pUpsert = 0; + }else{ + /* A single ON CONFLICT DO UPDATE. Make all resolutions OE_Update */ + overrideError = OE_Update; + } + }else if( pTab->pIndex!=0 ){ + /* Otherwise, we'll need to run the IndexListTerm array version of the + ** iterator to ensure that all of the ON CONFLICT conditions are + ** checked first and in order. */ + int nIdx, jj; + u64 nByte; + Upsert *pTerm; + u8 *bUsed; + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ + assert( aRegIdx[nIdx]>0 ); + } + sIdxIter.eType = 1; + sIdxIter.u.ax.nIdx = nIdx; + nByte = (sizeof(IndexListTerm)+1)*nIdx + nIdx; + sIdxIter.u.ax.aIdx = sqlite3DbMallocZero(db, nByte); + if( sIdxIter.u.ax.aIdx==0 ) return; /* OOM */ + bUsed = (u8*)&sIdxIter.u.ax.aIdx[nIdx]; + pUpsert->pToFree = sIdxIter.u.ax.aIdx; + for(i=0, pTerm=pUpsert; pTerm; pTerm=pTerm->pNextUpsert){ + if( pTerm->pUpsertTarget==0 ) break; + if( pTerm->pUpsertIdx==0 ) continue; /* Skip ON CONFLICT for the IPK */ + jj = 0; + pIdx = pTab->pIndex; + while( ALWAYS(pIdx!=0) && pIdx!=pTerm->pUpsertIdx ){ + pIdx = pIdx->pNext; + jj++; + } + if( bUsed[jj] ) continue; /* Duplicate ON CONFLICT clause ignored */ + bUsed[jj] = 1; + sIdxIter.u.ax.aIdx[i].p = pIdx; + sIdxIter.u.ax.aIdx[i].ix = jj; + i++; + } + for(jj=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, jj++){ + if( bUsed[jj] ) continue; + sIdxIter.u.ax.aIdx[i].p = pIdx; + sIdxIter.u.ax.aIdx[i].ix = jj; + i++; + } + assert( i==nIdx ); + } + } + + /* Determine if it is possible that triggers (either explicitly coded + ** triggers or FK resolution actions) might run as a result of deletes + ** that happen when OE_Replace conflict resolution occurs. (Call these + ** "replace triggers".) If any replace triggers run, we will need to + ** recheck all of the uniqueness constraints after they have all run. + ** But on the recheck, the resolution is OE_Abort instead of OE_Replace. + ** + ** If replace triggers are a possibility, then + ** + ** (1) Allocate register regTrigCnt and initialize it to zero. + ** That register will count the number of replace triggers that + ** fire. Constraint recheck only occurs if the number is positive. + ** (2) Initialize pTrigger to the list of all DELETE triggers on pTab. + ** (3) Initialize addrRecheck and lblRecheckOk + ** + ** The uniqueness rechecking code will create a series of tests to run + ** in a second pass. The addrRecheck and lblRecheckOk variables are + ** used to link together these tests which are separated from each other + ** in the generate bytecode. + */ + if( (db->flags & (SQLITE_RecTriggers|SQLITE_ForeignKeys))==0 ){ + /* There are not DELETE triggers nor FK constraints. No constraint + ** rechecks are needed. */ + pTrigger = 0; + regTrigCnt = 0; + }else{ + if( db->flags&SQLITE_RecTriggers ){ + pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); + regTrigCnt = pTrigger!=0 || sqlite3FkRequired(pParse, pTab, 0, 0); + }else{ + pTrigger = 0; + regTrigCnt = sqlite3FkRequired(pParse, pTab, 0, 0); + } + if( regTrigCnt ){ + /* Replace triggers might exist. Allocate the counter and + ** initialize it to zero. */ + regTrigCnt = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regTrigCnt); + VdbeComment((v, "trigger count")); + lblRecheckOk = sqlite3VdbeMakeLabel(pParse); + addrRecheck = lblRecheckOk; + } + } + /* If rowid is changing, make sure the new rowid does not previously ** exist in the table. */ if( pkChng && pPk==0 ){ - int addrRowidOk = sqlite3VdbeMakeLabel(v); + int addrRowidOk = sqlite3VdbeMakeLabel(pParse); /* Figure out what action to take in case of a rowid collision */ onError = pTab->keyConf; @@ -109642,13 +126919,22 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( onError = OE_Abort; } - if( isUpdate ){ - /* pkChng!=0 does not mean that the rowid has changed, only that - ** it might have changed. Skip the conflict logic below if the rowid - ** is unchanged. */ - sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); - VdbeCoverage(v); + /* figure out whether or not upsert applies in this case */ + if( pUpsert ){ + pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0); + if( pUpsertClause!=0 ){ + if( pUpsertClause->isDoUpdate==0 ){ + onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ + }else{ + onError = OE_Update; /* DO UPDATE */ + } + } + if( pUpsertClause!=pUpsert ){ + /* The first ON CONFLICT clause has a conflict target other than + ** the IPK. We have to jump ahead to that first ON CONFLICT clause + ** and then come back here and deal with the IPK afterwards */ + upsertIpkDelay = sqlite3VdbeAddOp0(v, OP_Goto); + } } /* If the response to a rowid conflict is REPLACE but the response @@ -109656,29 +126942,42 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** to defer the running of the rowid conflict checking until after ** the UNIQUE constraints have run. */ - if( onError==OE_Replace && overrideError!=OE_Replace ){ - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->onError==OE_Ignore || pIdx->onError==OE_Fail ){ - ipkTop = sqlite3VdbeAddOp0(v, OP_Goto); - break; - } - } + if( onError==OE_Replace /* IPK rule is REPLACE */ + && onError!=overrideError /* Rules for other constraints are different */ + && pTab->pIndex /* There exist other constraints */ + && !upsertIpkDelay /* IPK check already deferred by UPSERT */ + ){ + ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; + VdbeComment((v, "defer IPK REPLACE until last")); + } + + if( isUpdate ){ + /* pkChng!=0 does not mean that the rowid has changed, only that + ** it might have changed. Skip the conflict logic below if the rowid + ** is unchanged. */ + sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + VdbeCoverage(v); } /* Check to see if the new rowid already exists in the table. Skip ** the following conflict logic if it does not. */ + VdbeNoopComment((v, "uniqueness check for ROWID")); + sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); - /* Generate code that deals with a rowid collision */ switch( onError ){ default: { onError = OE_Abort; - /* Fall thru into the next case */ + /* no break */ deliberate_fall_through } case OE_Rollback: case OE_Abort: case OE_Fail: { + testcase( onError==OE_Rollback ); + testcase( onError==OE_Abort ); + testcase( onError==OE_Fail ); sqlite3RowidConstraint(pParse, onError, pTab); break; } @@ -109689,10 +126988,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** the triggers and remove both the table and index b-tree entries. ** ** Otherwise, if there are no triggers or the recursive-triggers - ** flag is not set, but the table has one or more indexes, call - ** GenerateRowIndexDelete(). This removes the index b-tree entries - ** only. The table b-tree entry will be replaced by the new entry - ** when it is inserted. + ** flag is not set, but the table has one or more indexes, call + ** GenerateRowIndexDelete(). This removes the index b-tree entries + ** only. The table b-tree entry will be replaced by the new entry + ** when it is inserted. ** ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called, ** also invoke MultiWrite() to indicate that this VDBE may require @@ -109705,24 +127004,21 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** to run without a statement journal if there are no indexes on the ** table. */ - Trigger *pTrigger = 0; - if( db->flags&SQLITE_RecTriggers ){ - pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); - } - if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ + if( regTrigCnt ){ sqlite3MultiWrite(pParse); sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regNewData, 1, 0, OE_Replace, 1, -1); + sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ + nReplaceTrig++; }else{ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK - if( HasRowid(pTab) ){ - /* This OP_Delete opcode fires the pre-update-hook only. It does - ** not modify the b-tree. It is more efficient to let the coming - ** OP_Insert replace the existing entry than it is to delete the - ** existing entry and then insert a new one. */ - sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP); - sqlite3VdbeAppendP4(v, pTab, P4_TABLE); - } + assert( HasRowid(pTab) ); + /* This OP_Delete opcode fires the pre-update-hook only. It does + ** not modify the b-tree. It is more efficient to let the coming + ** OP_Insert replace the existing entry than it is to delete the + ** existing entry and then insert a new one. */ + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP); + sqlite3VdbeAppendP4(v, pTab, P4_TABLE); #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ if( pTab->pIndex ){ sqlite3MultiWrite(pParse); @@ -109732,16 +127028,24 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( seenReplace = 1; break; } +#ifndef SQLITE_OMIT_UPSERT + case OE_Update: { + sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur); + /* no break */ deliberate_fall_through + } +#endif case OE_Ignore: { - /*assert( seenReplace==0 );*/ + testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } } sqlite3VdbeResolveLabel(v, addrRowidOk); - if( ipkTop ){ + if( pUpsert && pUpsertClause!=pUpsert ){ + upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto); + }else if( ipkTop ){ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); - sqlite3VdbeJumpHere(v, ipkTop); + sqlite3VdbeJumpHere(v, ipkTop-1); } } @@ -109752,27 +127056,39 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( ** This loop also handles the case of the PRIMARY KEY index for a ** WITHOUT ROWID table. */ - for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){ + for(pIdx = indexIteratorFirst(&sIdxIter, &ix); + pIdx; + pIdx = indexIteratorNext(&sIdxIter, &ix) + ){ int regIdx; /* Range of registers hold conent for pIdx */ int regR; /* Range of registers holding conflicting PK */ int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ + int addrConflictCk; /* First opcode in the conflict check logic */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ + if( pUpsert ){ + pUpsertClause = sqlite3UpsertOfIndex(pUpsert, pIdx); + if( upsertIpkDelay && pUpsertClause==pUpsert ){ + sqlite3VdbeJumpHere(v, upsertIpkDelay); + } + } + addrUniqueOk = sqlite3VdbeMakeLabel(pParse); if( bAffinityDone==0 ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } + VdbeNoopComment((v, "prep index %s", pIdx->zName)); iThisCur = iIdxCur+ix; - addrUniqueOk = sqlite3VdbeMakeLabel(v); + /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk, SQLITE_JUMPIFNULL); - pParse->ckBase = 0; + pParse->iSelfTab = 0; } /* Create a record for this index entry as it should appear after @@ -109783,24 +127099,31 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int iField = pIdx->aiColumn[i]; int x; if( iField==XN_EXPR ){ - pParse->ckBase = regNewData+1; + pParse->iSelfTab = -(regNewData+1); sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); - pParse->ckBase = 0; + pParse->iSelfTab = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); + }else if( iField==XN_ROWID || iField==pTab->iPKey ){ + x = regNewData; + sqlite3VdbeAddOp2(v, OP_IntCopy, x, regIdx+i); + VdbeComment((v, "rowid")); }else{ - if( iField==XN_ROWID || iField==pTab->iPKey ){ - x = regNewData; - }else{ - x = iField + regNewData + 1; - } - sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i); - VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); + testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField ); + x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1; + sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); + VdbeComment((v, "%s", pTab->aCol[iField].zCnName)); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); +#ifdef SQLITE_ENABLE_NULL_TRIM + if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ + sqlite3SetMakeRecordP5(v, pIdx->pTable); + } +#endif + sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0); - /* In an UPDATE operation, if this index is the PRIMARY KEY index + /* In an UPDATE operation, if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table and there has been no change the ** primary key, then no collision is possible. The collision detection ** logic below can all be skipped. */ @@ -109811,7 +127134,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Find out what action to take in case there is a uniqueness conflict */ onError = pIdx->onError; - if( onError==OE_None ){ + if( onError==OE_None ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; /* pIdx is not a UNIQUE index */ } @@ -109821,31 +127144,48 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( onError = OE_Abort; } + /* Figure out if the upsert clause applies to this index */ + if( pUpsertClause ){ + if( pUpsertClause->isDoUpdate==0 ){ + onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ + }else{ + onError = OE_Update; /* DO UPDATE */ + } + } + /* Collision detection may be omitted if all of the following are true: ** (1) The conflict resolution algorithm is REPLACE ** (2) The table is a WITHOUT ROWID table ** (3) There are no secondary indexes on the table ** (4) No delete triggers need to be fired if there is a conflict ** (5) No FK constraint counters need to be updated if a conflict occurs. - */ + ** + ** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row + ** must be explicitly deleted in order to ensure any pre-update hook + ** is invoked. */ + assert( IsOrdinaryTable(pTab) ); +#ifndef SQLITE_ENABLE_PREUPDATE_HOOK if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ && pPk==pIdx /* Condition 2 */ && onError==OE_Replace /* Condition 1 */ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ - (0==pTab->pFKey && 0==sqlite3FkReferences(pTab))) + (0==pTab->u.tab.pFKey && 0==sqlite3FkReferences(pTab))) ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } +#endif /* ifndef SQLITE_ENABLE_PREUPDATE_HOOK */ /* Check to see if the new index entry will be unique */ - sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, - regIdx, pIdx->nKeyCol); VdbeCoverage(v); + sqlite3VdbeVerifyAbortable(v, onError); + addrConflictCk = + sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, + regIdx, pIdx->nKeyCol); VdbeCoverage(v); /* Generate code to handle collisions */ - regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField); + regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField); if( isUpdate || onError==OE_Replace ){ if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); @@ -109863,14 +127203,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( if( pIdx!=pPk ){ for(i=0; inKeyCol; i++){ assert( pPk->aiColumn[i]>=0 ); - x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); + x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, - pTab->aCol[pPk->aiColumn[i]].zName)); + pTab->aCol[pPk->aiColumn[i]].zCnName)); } } if( isUpdate ){ - /* If currently processing the PRIMARY KEY of a WITHOUT ROWID + /* If currently processing the PRIMARY KEY of a WITHOUT ROWID ** table, only conflict if the new PRIMARY KEY values are actually ** different from the old. ** @@ -109880,7 +127220,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); - + for(i=0; inKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; @@ -109889,7 +127229,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( addrJump = addrUniqueOk; op = OP_Eq; } - sqlite3VdbeAddOp4(v, op, + x = sqlite3TableColumnToStorage(pTab, x); + sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); @@ -109902,40 +127243,151 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail - || onError==OE_Ignore || onError==OE_Replace ); + || onError==OE_Ignore || onError==OE_Replace || onError==OE_Update ); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { + testcase( onError==OE_Rollback ); + testcase( onError==OE_Abort ); + testcase( onError==OE_Fail ); sqlite3UniqueConstraint(pParse, onError, pIdx); break; } +#ifndef SQLITE_OMIT_UPSERT + case OE_Update: { + sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix); + /* no break */ deliberate_fall_through + } +#endif case OE_Ignore: { + testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } default: { - Trigger *pTrigger = 0; + int nConflictCk; /* Number of opcodes in conflict check logic */ + assert( onError==OE_Replace ); - sqlite3MultiWrite(pParse); - if( db->flags&SQLITE_RecTriggers ){ - pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); + nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk; + assert( nConflictCk>0 || db->mallocFailed ); + testcase( nConflictCk<=0 ); + testcase( nConflictCk>1 ); + if( regTrigCnt ){ + sqlite3MultiWrite(pParse); + nReplaceTrig++; + } + if( pTrigger && isUpdate ){ + sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur); } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); + if( pTrigger && isUpdate ){ + sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur); + } + if( regTrigCnt ){ + int addrBypass; /* Jump destination to bypass recheck logic */ + + sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */ + addrBypass = sqlite3VdbeAddOp0(v, OP_Goto); /* Bypass recheck */ + VdbeComment((v, "bypass recheck")); + + /* Here we insert code that will be invoked after all constraint + ** checks have run, if and only if one or more replace triggers + ** fired. */ + sqlite3VdbeResolveLabel(v, lblRecheckOk); + lblRecheckOk = sqlite3VdbeMakeLabel(pParse); + if( pIdx->pPartIdxWhere ){ + /* Bypass the recheck if this partial index is not defined + ** for the current row */ + sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk); + VdbeCoverage(v); + } + /* Copy the constraint check code from above, except change + ** the constraint-ok jump destination to be the address of + ** the next retest block */ + while( nConflictCk>0 ){ + VdbeOp x; /* Conflict check opcode to copy */ + /* The sqlite3VdbeAddOp4() call might reallocate the opcode array. + ** Hence, make a complete copy of the opcode, rather than using + ** a pointer to the opcode. */ + x = *sqlite3VdbeGetOp(v, addrConflictCk); + if( x.opcode!=OP_IdxRowid ){ + int p2; /* New P2 value for copied conflict check opcode */ + const char *zP4; + if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){ + p2 = lblRecheckOk; + }else{ + p2 = x.p2; + } + zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z; + sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type); + sqlite3VdbeChangeP5(v, x.p5); + VdbeCoverageIf(v, p2!=x.p2); + } + nConflictCk--; + addrConflictCk++; + } + /* If the retest fails, issue an abort */ + sqlite3UniqueConstraint(pParse, OE_Abort, pIdx); + + sqlite3VdbeJumpHere(v, addrBypass); /* Terminate the recheck bypass */ + } seenReplace = 1; break; } } sqlite3VdbeResolveLabel(v, addrUniqueOk); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); + if( pUpsertClause + && upsertIpkReturn + && sqlite3UpsertNextIsIPK(pUpsertClause) + ){ + sqlite3VdbeGoto(v, upsertIpkDelay+1); + sqlite3VdbeJumpHere(v, upsertIpkReturn); + upsertIpkReturn = 0; + } } + + /* If the IPK constraint is a REPLACE, run it last */ if( ipkTop ){ - sqlite3VdbeGoto(v, ipkTop+1); + sqlite3VdbeGoto(v, ipkTop); + VdbeComment((v, "Do IPK REPLACE")); + assert( ipkBottom>0 ); sqlite3VdbeJumpHere(v, ipkBottom); } - + + /* Recheck all uniqueness constraints after replace triggers have run */ + testcase( regTrigCnt!=0 && nReplaceTrig==0 ); + assert( regTrigCnt!=0 || nReplaceTrig==0 ); + if( nReplaceTrig ){ + sqlite3VdbeAddOp2(v, OP_IfNot, regTrigCnt, lblRecheckOk);VdbeCoverage(v); + if( !pPk ){ + if( isUpdate ){ + sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRecheck, regOldData); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRecheck, regNewData); + VdbeCoverage(v); + sqlite3RowidConstraint(pParse, OE_Abort, pTab); + }else{ + sqlite3VdbeGoto(v, addrRecheck); + } + sqlite3VdbeResolveLabel(v, lblRecheckOk); + } + + /* Generate the table record */ + if( HasRowid(pTab) ){ + int regRec = aRegIdx[ix]; + sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nNVCol, regRec); + sqlite3SetMakeRecordP5(v, pTab); + if( !bAffinityDone ){ + sqlite3TableAffinity(v, pTab, 0); + } + } + *pbMayReplace = seenReplace; VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } @@ -109954,11 +127406,40 @@ SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){ ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */ if( pTab->pSchema->file_format<2 ) return; - for(i=pTab->nCol; i>1 && pTab->aCol[i-1].pDflt==0; i--){} - sqlite3VdbeChangeP5(v, i); + for(i=pTab->nCol-1; i>0; i--){ + if( pTab->aCol[i].iDflt!=0 ) break; + if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; + } + sqlite3VdbeChangeP5(v, i+1); } #endif +/* +** Table pTab is a WITHOUT ROWID table that is being written to. The cursor +** number is iCur, and register regData contains the new record for the +** PK index. This function adds code to invoke the pre-update hook, +** if one is registered. +*/ +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +static void codeWithoutRowidPreupdate( + Parse *pParse, /* Parse context */ + Table *pTab, /* Table being updated */ + int iCur, /* Cursor number for table */ + int regData /* Data containing new record */ +){ + Vdbe *v = pParse->pVdbe; + int r = sqlite3GetTempReg(pParse); + assert( !HasRowid(pTab) ); + assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) || CORRUPT_DB ); + sqlite3VdbeAddOp2(v, OP_Integer, 0, r); + sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE); + sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); + sqlite3ReleaseTempReg(pParse, r); +} +#else +# define codeWithoutRowidPreupdate(a,b,c,d) +#endif + /* ** This routine generates code to finish the INSERT or UPDATE operation ** that was started by a prior call to sqlite3GenerateConstraintChecks. @@ -109982,39 +127463,33 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( Vdbe *v; /* Prepared statements under construction */ Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ - int regData; /* Content registers (after the rowid) */ - int regRec; /* Register holding assembled record for the table */ int i; /* Loop counter */ - u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ assert( update_flags==0 || update_flags==OPFLAG_ISUPDATE || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION) ); - v = sqlite3GetVdbe(pParse); + v = pParse->pVdbe; assert( v!=0 ); - assert( pTab->pSelect==0 ); /* This table is not a VIEW */ + assert( !IsView(pTab) ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ + /* All REPLACE indexes are at the end of the list */ + assert( pIdx->onError!=OE_Replace + || pIdx->pNext==0 + || pIdx->pNext->onError==OE_Replace ); if( aRegIdx[i]==0 ) continue; - bAffinityDone = 1; if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); } pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ - assert( pParse->nested==0 ); pik_flags |= OPFLAG_NCHANGE; pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); -#ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( update_flags==0 ){ - sqlite3VdbeAddOp4(v, OP_InsertInt, - iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE - ); - sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); + codeWithoutRowidPreupdate(pParse, pTab, iIdxCur+i, aRegIdx[i]); } -#endif } sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i], aRegIdx[i]+1, @@ -110022,14 +127497,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( sqlite3VdbeChangeP5(v, pik_flags); } if( !HasRowid(pTab) ) return; - regData = regNewData + 1; - regRec = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); - sqlite3SetMakeRecordP5(v, pTab); - if( !bAffinityDone ){ - sqlite3TableAffinity(v, pTab, 0); - sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); - } if( pParse->nested ){ pik_flags = 0; }else{ @@ -110042,7 +127509,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( if( useSeekResult ){ pik_flags |= OPFLAG_USESEEKRESULT; } - sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData); + sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, aRegIdx[i], regNewData); if( !pParse->nested ){ sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } @@ -110090,12 +127557,13 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( assert( op==OP_OpenWrite || p5==0 ); if( IsVirtual(pTab) ){ /* This routine is a no-op for virtual tables. Leave the output - ** variables *piDataCur and *piIdxCur uninitialized so that valgrind - ** can detect if they are used by mistake in the caller. */ + ** variables *piDataCur and *piIdxCur set to illegal cursor numbers + ** for improved error detection. */ + *piDataCur = *piIdxCur = -999; return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - v = sqlite3GetVdbe(pParse); + v = pParse->pVdbe; assert( v!=0 ); if( iBase<0 ) iBase = pParse->nTab; iDataCur = iBase++; @@ -110152,7 +127620,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ int i; assert( pDest && pSrc ); assert( pDest->pTable!=pSrc->pTable ); - if( pDest->nKeyCol!=pSrc->nKeyCol ){ + if( pDest->nKeyCol!=pSrc->nKeyCol || pDest->nColumn!=pSrc->nColumn ){ return 0; /* Different number of columns */ } if( pDest->onError!=pSrc->onError ){ @@ -110164,7 +127632,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ } if( pSrc->aiColumn[i]==XN_EXPR ){ assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); - if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, + if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr, pDest->aColExpr->a[i].pExpr, -1)!=0 ){ return 0; /* Different expressions in the index */ } @@ -110176,7 +127644,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ return 0; /* Different collating sequences */ } } - if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ + if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){ return 0; /* Different WHERE clauses */ } @@ -110189,7 +127657,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ ** ** INSERT INTO tab1 SELECT * FROM tab2; ** -** The xfer optimization transfers raw records from tab2 over to tab1. +** The xfer optimization transfers raw records from tab2 over to tab1. ** Columns are not decoded and reassembled, which greatly improves ** performance. Raw index records are transferred in the same way. ** @@ -110220,7 +127688,7 @@ static int xferOptimization( ExprList *pEList; /* The result set of the SELECT */ Table *pSrc; /* The table in the FROM clause of SELECT */ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ - struct SrcList_item *pItem; /* An element of pSelect->pSrc */ + SrcItem *pItem; /* An element of pSelect->pSrc */ int i; /* Loop counter */ int iDbSrc; /* The database of pSrc */ int iSrc, iDest; /* Cursors from source and destination */ @@ -110232,20 +127700,15 @@ static int xferOptimization( int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */ int regData, regRowid; /* Registers holding data and rowid */ - if( pSelect==0 ){ - return 0; /* Must be of the form INSERT INTO ... SELECT ... */ - } + assert( pSelect!=0 ); if( pParse->pWith || pSelect->pWith ){ /* Do not attempt to process this query if there are an WITH clauses ** attached to it. Proceeding may generate a false "no such table: xxx" ** error if pSelect reads from a CTE named "xxx". */ return 0; } - if( sqlite3TriggerList(pParse, pDest) ){ - return 0; /* tab1 must not have triggers */ - } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pDest->tabFlags & TF_Virtual ){ + if( IsVirtual(pDest) ){ return 0; /* tab1 must not be a virtual table */ } #endif @@ -110274,7 +127737,6 @@ static int xferOptimization( if( pSelect->pLimit ){ return 0; /* SELECT may not have a LIMIT clause */ } - assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */ if( pSelect->pPrior ){ return 0; /* SELECT may not be a compound query */ } @@ -110300,19 +127762,15 @@ static int xferOptimization( if( pSrc==0 ){ return 0; /* FROM clause does not contain a real table */ } - if( pSrc==pDest ){ + if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){ + testcase( pSrc!=pDest ); /* Possible due to bad sqlite_schema.rootpage */ return 0; /* tab1 and tab2 may not be the same table */ } if( HasRowid(pDest)!=HasRowid(pSrc) ){ return 0; /* source and destination must both be WITHOUT ROWID or not */ } -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( pSrc->tabFlags & TF_Virtual ){ - return 0; /* tab2 must not be a virtual table */ - } -#endif - if( pSrc->pSelect ){ - return 0; /* tab2 may not be a view */ + if( !IsOrdinaryTable(pSrc) ){ + return 0; /* tab2 may not be a view or virtual table */ } if( pDest->nCol!=pSrc->nCol ){ return 0; /* Number of columns must be the same in tab1 and tab2 */ @@ -110320,32 +127778,75 @@ static int xferOptimization( if( pDest->iPKey!=pSrc->iPKey ){ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ } + if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){ + return 0; /* Cannot feed from a non-strict into a strict table */ + } for(i=0; inCol; i++){ Column *pDestCol = &pDest->aCol[i]; Column *pSrcCol = &pSrc->aCol[i]; #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS - if( (db->flags & SQLITE_Vacuum)==0 - && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN + if( (db->mDbFlags & DBFLAG_Vacuum)==0 + && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN ){ return 0; /* Neither table may have __hidden__ columns */ } +#endif +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Even if tables t1 and t2 have identical schemas, if they contain + ** generated columns, then this statement is semantically incorrect: + ** + ** INSERT INTO t2 SELECT * FROM t1; + ** + ** The reason is that generated column values are returned by the + ** the SELECT statement on the right but the INSERT statement on the + ** left wants them to be omitted. + ** + ** Nevertheless, this is a useful notational shorthand to tell SQLite + ** to do a bulk transfer all of the content from t1 over to t2. + ** + ** We could, in theory, disable this (except for internal use by the + ** VACUUM command where it is actually needed). But why do that? It + ** seems harmless enough, and provides a useful service. + */ + if( (pDestCol->colFlags & COLFLAG_GENERATED) != + (pSrcCol->colFlags & COLFLAG_GENERATED) ){ + return 0; /* Both columns have the same generated-column type */ + } + /* But the transfer is only allowed if both the source and destination + ** tables have the exact same expressions for generated columns. + ** This requirement could be relaxed for VIRTUAL columns, I suppose. + */ + if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ + if( sqlite3ExprCompare(0, + sqlite3ColumnExpr(pSrc, pSrcCol), + sqlite3ColumnExpr(pDest, pDestCol), -1)!=0 ){ + testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pDestCol->colFlags & COLFLAG_STORED ); + return 0; /* Different generator expressions */ + } + } #endif if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } - if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){ + if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol), + sqlite3ColumnColl(pSrcCol))!=0 ){ return 0; /* Collating sequence must be the same on all columns */ } if( pDestCol->notNull && !pSrcCol->notNull ){ return 0; /* tab2 must be NOT NULL if tab1 is */ } /* Default values for second and subsequent columns need to match. */ - if( i>0 ){ - assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN ); - assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN ); - if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) - || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken, - pSrcCol->pDflt->u.zToken)!=0) + if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){ + Expr *pDestExpr = sqlite3ColumnExpr(pDest, pDestCol); + Expr *pSrcExpr = sqlite3ColumnExpr(pSrc, pSrcCol); + assert( pDestExpr==0 || pDestExpr->op==TK_SPAN ); + assert( pDestExpr==0 || !ExprHasProperty(pDestExpr, EP_IntValue) ); + assert( pSrcExpr==0 || pSrcExpr->op==TK_SPAN ); + assert( pSrcExpr==0 || !ExprHasProperty(pSrcExpr, EP_IntValue) ); + if( (pDestExpr==0)!=(pSrcExpr==0) + || (pDestExpr!=0 && strcmp(pDestExpr->u.zToken, + pSrcExpr->u.zToken)!=0) ){ return 0; /* Default values must be the same for all columns */ } @@ -110361,6 +127862,13 @@ static int xferOptimization( if( pSrcIdx==0 ){ return 0; /* pDestIdx has no corresponding index in pSrc */ } + if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema + && sqlite3FaultSim(411)==SQLITE_OK ){ + /* The sqlite3FaultSim() call allows this corruption test to be + ** bypassed during testing, in order to exercise other corruption tests + ** further downstream. */ + return 0; /* Corrupt schema - two indexes on the same btree */ + } } #ifndef SQLITE_OMIT_CHECK if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ @@ -110370,12 +127878,13 @@ static int xferOptimization( #ifndef SQLITE_OMIT_FOREIGN_KEY /* Disallow the transfer optimization if the destination table constains ** any foreign key constraints. This is more restrictive than necessary. - ** But the main beneficiary of the transfer optimization is the VACUUM + ** But the main beneficiary of the transfer optimization is the VACUUM ** command, and the VACUUM command disables foreign key constraints. So ** the extra complication to make this rule less restrictive is probably ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] */ - if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ + assert( IsOrdinaryTable(pDest) ); + if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->u.tab.pFKey!=0 ){ return 0; } #endif @@ -110397,18 +127906,19 @@ static int xferOptimization( iDest = pParse->nTab++; regAutoinc = autoIncBegin(pParse, iDbDest, pDest); regData = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Null, 0, regData); regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); - if( (db->flags & SQLITE_Vacuum)==0 && ( + if( (db->mDbFlags & DBFLAG_Vacuum)==0 && ( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ )){ /* In some circumstances, we are able to run the xfer optimization ** only if the destination table is initially empty. Unless the - ** SQLITE_Vacuum flag is set, this block generates code to make - ** that determination. If SQLITE_Vacuum is set, then the destination + ** DBFLAG_Vacuum flag is set, this block generates code to make + ** that determination. If DBFLAG_Vacuum is set, then the destination ** table is always empty. ** ** Conditions under which the destination must be empty: @@ -110417,7 +127927,7 @@ static int xferOptimization( ** (If the destination is not initially empty, the rowid fields ** of index entries might need to change.) ** - ** (2) The destination has a unique index. (The xfer optimization + ** (2) The destination has a unique index. (The xfer optimization ** is unable to test uniqueness.) ** ** (3) onError is something other than OE_Abort and OE_Rollback. @@ -110432,28 +127942,42 @@ static int xferOptimization( emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); - addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); - VdbeCoverage(v); - sqlite3RowidConstraint(pParse, onError, pDest); - sqlite3VdbeJumpHere(v, addr2); + if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ + sqlite3VdbeVerifyAbortable(v, onError); + addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); + VdbeCoverage(v); + sqlite3RowidConstraint(pParse, onError, pDest); + sqlite3VdbeJumpHere(v, addr2); + } autoIncStep(pParse, regAutoinc, regRowid); - }else if( pDest->pIndex==0 ){ + }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); assert( (pDest->tabFlags & TF_Autoincrement)==0 ); } - sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); - if( db->flags & SQLITE_Vacuum ){ - sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); - insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID| - OPFLAG_APPEND|OPFLAG_USESEEKRESULT; + + if( db->mDbFlags & DBFLAG_Vacuum ){ + sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); + insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT; }else{ - insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND; + insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT; + } +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK + if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); + insFlags &= ~OPFLAG_PREFORMAT; + }else +#endif + { + sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid); + } + sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid); + if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){ + sqlite3VdbeChangeP4(v, -1, (char*)pDest, P4_TABLE); } - sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, - (char*)pDest, P4_TABLE); sqlite3VdbeChangeP5(v, insFlags); + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); @@ -110475,36 +127999,42 @@ static int xferOptimization( sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); - if( db->flags & SQLITE_Vacuum ){ + if( db->mDbFlags & DBFLAG_Vacuum ){ /* This INSERT command is part of a VACUUM operation, which guarantees ** that the destination table is empty. If all indexed columns use ** collation sequence BINARY, then it can also be assumed that the - ** index will be populated by inserting keys in strictly sorted + ** index will be populated by inserting keys in strictly sorted ** order. In this case, instead of seeking within the b-tree as part - ** of every OP_IdxInsert opcode, an OP_Last is added before the - ** OP_IdxInsert to seek to the point within the b-tree where each key + ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the + ** OP_IdxInsert to seek to the point within the b-tree where each key ** should be inserted. This is faster. ** ** If any of the indexed columns use a collation sequence other than - ** BINARY, this optimization is disabled. This is because the user + ** BINARY, this optimization is disabled. This is because the user ** might change the definition of a collation sequence and then run ** a VACUUM command. In that case keys may not be written in strictly ** sorted order. */ for(i=0; inColumn; i++){ const char *zColl = pSrcIdx->azColl[i]; - assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0 - || sqlite3StrBINARY==zColl ); if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break; } if( i==pSrcIdx->nColumn ){ - idxInsFlags = OPFLAG_USESEEKRESULT; - sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); + idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT; + sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); + sqlite3VdbeAddOp2(v, OP_RowCell, iDest, iSrc); } - } - if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){ + }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } + if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){ + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); + if( (db->mDbFlags & DBFLAG_Vacuum)==0 + && !HasRowid(pDest) + && IsPrimaryKeyIndex(pDestIdx) + ){ + codeWithoutRowidPreupdate(pParse, pDest, iDest, regData); + } + } sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); @@ -110577,7 +128107,7 @@ SQLITE_API int sqlite3_exec( sqlite3_mutex_enter(db->mutex); sqlite3Error(db, SQLITE_OK); while( rc==SQLITE_OK && zSql[0] ){ - int nCol; + int nCol = 0; char **azVals = 0; pStmt = 0; @@ -110591,20 +128121,19 @@ SQLITE_API int sqlite3_exec( zSql = zLeftover; continue; } - callbackIsInit = 0; - nCol = sqlite3_column_count(pStmt); while( 1 ){ int i; rc = sqlite3_step(pStmt); /* Invoke the callback function if required */ - if( xCallback && (SQLITE_ROW==rc || + if( xCallback && (SQLITE_ROW==rc || (SQLITE_DONE==rc && !callbackIsInit && db->flags&SQLITE_NullCallback)) ){ if( !callbackIsInit ){ - azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1); + nCol = sqlite3_column_count(pStmt); + azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*)); if( azCols==0 ){ goto exec_out; } @@ -110625,6 +128154,7 @@ SQLITE_API int sqlite3_exec( goto exec_out; } } + azVals[i] = 0; } if( xCallback(pArg, nCol, azVals, azCols) ){ /* EVIDENCE-OF: R-38229-40159 If the callback function to @@ -110657,11 +128187,8 @@ SQLITE_API int sqlite3_exec( rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && pzErrMsg ){ - int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); - *pzErrMsg = sqlite3Malloc(nErrMsg); - if( *pzErrMsg ){ - memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); - }else{ + *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db)); + if( *pzErrMsg==0 ){ rc = SQLITE_NOMEM_BKPT; sqlite3Error(db, SQLITE_NOMEM); } @@ -110710,7 +128237,7 @@ SQLITE_API int sqlite3_exec( ** This header file defines the SQLite interface for use by ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded -** as extensions by SQLite should #include this file instead of +** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ #ifndef SQLITE3EXT_H @@ -110832,7 +128359,7 @@ struct sqlite3_api_routines { int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, const char*,const char*),void*); void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*snprintf)(int,char*,const char*,...); + char * (*xsnprintf)(int,char*,const char*,...); int (*step)(sqlite3_stmt*); int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, char const**,char const**,int*,int*,int*); @@ -110944,7 +128471,7 @@ struct sqlite3_api_routines { int (*uri_boolean)(const char*,const char*,int); sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); const char *(*uri_parameter)(const char*,const char*); - char *(*vsnprintf)(int,char*,const char*,va_list); + char *(*xvsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); /* Version 3.8.7 and later */ int (*auto_extension)(void(*)(void)); @@ -110980,6 +128507,75 @@ struct sqlite3_api_routines { /* Version 3.14.0 and later */ int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); char *(*expanded_sql)(sqlite3_stmt*); + /* Version 3.18.0 and later */ + void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); + /* Version 3.20.0 and later */ + int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, + sqlite3_stmt**,const char**); + int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, + sqlite3_stmt**,const void**); + int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); + void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); + void *(*value_pointer)(sqlite3_value*,const char*); + int (*vtab_nochange)(sqlite3_context*); + int (*value_nochange)(sqlite3_value*); + const char *(*vtab_collation)(sqlite3_index_info*,int); + /* Version 3.24.0 and later */ + int (*keyword_count)(void); + int (*keyword_name)(int,const char**,int*); + int (*keyword_check)(const char*,int); + sqlite3_str *(*str_new)(sqlite3*); + char *(*str_finish)(sqlite3_str*); + void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); + void (*str_append)(sqlite3_str*, const char *zIn, int N); + void (*str_appendall)(sqlite3_str*, const char *zIn); + void (*str_appendchar)(sqlite3_str*, int N, char C); + void (*str_reset)(sqlite3_str*); + int (*str_errcode)(sqlite3_str*); + int (*str_length)(sqlite3_str*); + char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ + int (*create_window_function)(sqlite3*,const char*,int,int,void*, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInv)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); + /* Version 3.28.0 and later */ + int (*stmt_isexplain)(sqlite3_stmt*); + int (*value_frombind)(sqlite3_value*); + /* Version 3.30.0 and later */ + int (*drop_modules)(sqlite3*,const char**); + /* Version 3.31.0 and later */ + sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); + const char *(*uri_key)(const char*,int); + const char *(*filename_database)(const char*); + const char *(*filename_journal)(const char*); + const char *(*filename_wal)(const char*); + /* Version 3.32.0 and later */ + char *(*create_filename)(const char*,const char*,const char*, + int,const char**); + void (*free_filename)(char*); + sqlite3_file *(*database_file_object)(const char*); + /* Version 3.34.0 and later */ + int (*txn_state)(sqlite3*,const char*); + /* Version 3.36.1 and later */ + sqlite3_int64 (*changes64)(sqlite3*); + sqlite3_int64 (*total_changes64)(sqlite3*); + /* Version 3.37.0 and later */ + int (*autovacuum_pages)(sqlite3*, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, void(*)(void*)); + /* Version 3.38.0 and later */ + int (*error_offset)(sqlite3*); + int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); + int (*vtab_distinct)(sqlite3_index_info*); + int (*vtab_in)(sqlite3_index_info*,int,int); + int (*vtab_in_first)(sqlite3_value*,sqlite3_value**); + int (*vtab_in_next)(sqlite3_value*,sqlite3_value**); }; /* @@ -111106,7 +128702,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_rollback_hook sqlite3_api->rollback_hook #define sqlite3_set_authorizer sqlite3_api->set_authorizer #define sqlite3_set_auxdata sqlite3_api->set_auxdata -#define sqlite3_snprintf sqlite3_api->snprintf +#define sqlite3_snprintf sqlite3_api->xsnprintf #define sqlite3_step sqlite3_api->step #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup @@ -111130,7 +128726,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf -#define sqlite3_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 @@ -111206,7 +128802,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter -#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf +#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 /* Version 3.8.7 and later */ #define sqlite3_auto_extension sqlite3_api->auto_extension @@ -111238,17 +128834,77 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.14.0 and later */ #define sqlite3_trace_v2 sqlite3_api->trace_v2 #define sqlite3_expanded_sql sqlite3_api->expanded_sql +/* Version 3.18.0 and later */ +#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid +/* Version 3.20.0 and later */ +#define sqlite3_prepare_v3 sqlite3_api->prepare_v3 +#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 +#define sqlite3_bind_pointer sqlite3_api->bind_pointer +#define sqlite3_result_pointer sqlite3_api->result_pointer +#define sqlite3_value_pointer sqlite3_api->value_pointer +/* Version 3.22.0 and later */ +#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange +#define sqlite3_value_nochange sqlite3_api->value_nochange +#define sqlite3_vtab_collation sqlite3_api->vtab_collation +/* Version 3.24.0 and later */ +#define sqlite3_keyword_count sqlite3_api->keyword_count +#define sqlite3_keyword_name sqlite3_api->keyword_name +#define sqlite3_keyword_check sqlite3_api->keyword_check +#define sqlite3_str_new sqlite3_api->str_new +#define sqlite3_str_finish sqlite3_api->str_finish +#define sqlite3_str_appendf sqlite3_api->str_appendf +#define sqlite3_str_vappendf sqlite3_api->str_vappendf +#define sqlite3_str_append sqlite3_api->str_append +#define sqlite3_str_appendall sqlite3_api->str_appendall +#define sqlite3_str_appendchar sqlite3_api->str_appendchar +#define sqlite3_str_reset sqlite3_api->str_reset +#define sqlite3_str_errcode sqlite3_api->str_errcode +#define sqlite3_str_length sqlite3_api->str_length +#define sqlite3_str_value sqlite3_api->str_value +/* Version 3.25.0 and later */ +#define sqlite3_create_window_function sqlite3_api->create_window_function +/* Version 3.26.0 and later */ +#define sqlite3_normalized_sql sqlite3_api->normalized_sql +/* Version 3.28.0 and later */ +#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain +#define sqlite3_value_frombind sqlite3_api->value_frombind +/* Version 3.30.0 and later */ +#define sqlite3_drop_modules sqlite3_api->drop_modules +/* Version 3.31.0 and later */ +#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64 +#define sqlite3_uri_key sqlite3_api->uri_key +#define sqlite3_filename_database sqlite3_api->filename_database +#define sqlite3_filename_journal sqlite3_api->filename_journal +#define sqlite3_filename_wal sqlite3_api->filename_wal +/* Version 3.32.0 and later */ +#define sqlite3_create_filename sqlite3_api->create_filename +#define sqlite3_free_filename sqlite3_api->free_filename +#define sqlite3_database_file_object sqlite3_api->database_file_object +/* Version 3.34.0 and later */ +#define sqlite3_txn_state sqlite3_api->txn_state +/* Version 3.36.1 and later */ +#define sqlite3_changes64 sqlite3_api->changes64 +#define sqlite3_total_changes64 sqlite3_api->total_changes64 +/* Version 3.37.0 and later */ +#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages +/* Version 3.38.0 and later */ +#define sqlite3_error_offset sqlite3_api->error_offset +#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value +#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct +#define sqlite3_vtab_in sqlite3_api->vtab_in +#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first +#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) - /* This case when the file really is being compiled as a loadable + /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; # define SQLITE_EXTENSION_INIT3 \ extern const sqlite3_api_routines *sqlite3_api; #else - /* This case when the file is being statically linked into the + /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ @@ -111293,6 +128949,7 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_open16 0 # define sqlite3_prepare16 0 # define sqlite3_prepare16_v2 0 +# define sqlite3_prepare16_v3 0 # define sqlite3_result_error16 0 # define sqlite3_result_text16 0 # define sqlite3_result_text16be 0 @@ -111325,6 +128982,7 @@ typedef int (*sqlite3_loadext_entry)( # define sqlite3_declare_vtab 0 # define sqlite3_vtab_config 0 # define sqlite3_vtab_on_conflict 0 +# define sqlite3_vtab_collation 0 #endif #ifdef SQLITE_OMIT_SHARED_CACHE @@ -111538,8 +129196,8 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_memory_highwater, sqlite3_memory_used, #ifdef SQLITE_MUTEX_OMIT - 0, - 0, + 0, + 0, 0, 0, 0, @@ -111663,9 +129321,85 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_system_errno, /* Version 3.14.0 and later */ sqlite3_trace_v2, - sqlite3_expanded_sql + sqlite3_expanded_sql, + /* Version 3.18.0 and later */ + sqlite3_set_last_insert_rowid, + /* Version 3.20.0 and later */ + sqlite3_prepare_v3, + sqlite3_prepare16_v3, + sqlite3_bind_pointer, + sqlite3_result_pointer, + sqlite3_value_pointer, + /* Version 3.22.0 and later */ + sqlite3_vtab_nochange, + sqlite3_value_nochange, + sqlite3_vtab_collation, + /* Version 3.24.0 and later */ + sqlite3_keyword_count, + sqlite3_keyword_name, + sqlite3_keyword_check, + sqlite3_str_new, + sqlite3_str_finish, + sqlite3_str_appendf, + sqlite3_str_vappendf, + sqlite3_str_append, + sqlite3_str_appendall, + sqlite3_str_appendchar, + sqlite3_str_reset, + sqlite3_str_errcode, + sqlite3_str_length, + sqlite3_str_value, + /* Version 3.25.0 and later */ + sqlite3_create_window_function, + /* Version 3.26.0 and later */ +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3_normalized_sql, +#else + 0, +#endif + /* Version 3.28.0 and later */ + sqlite3_stmt_isexplain, + sqlite3_value_frombind, + /* Version 3.30.0 and later */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3_drop_modules, +#else + 0, +#endif + /* Version 3.31.0 and later */ + sqlite3_hard_heap_limit64, + sqlite3_uri_key, + sqlite3_filename_database, + sqlite3_filename_journal, + sqlite3_filename_wal, + /* Version 3.32.0 and later */ + sqlite3_create_filename, + sqlite3_free_filename, + sqlite3_database_file_object, + /* Version 3.34.0 and later */ + sqlite3_txn_state, + /* Version 3.36.1 and later */ + sqlite3_changes64, + sqlite3_total_changes64, + /* Version 3.37.0 and later */ + sqlite3_autovacuum_pages, + /* Version 3.38.0 and later */ + sqlite3_error_offset, + sqlite3_vtab_rhs_value, + sqlite3_vtab_distinct, + sqlite3_vtab_in, + sqlite3_vtab_in_first, + sqlite3_vtab_in_next }; +/* True if x is the directory separator character +*/ +#if SQLITE_OS_WIN +# define DirSep(X) ((X)=='/'||(X)=='\\') +#else +# define DirSep(X) ((X)=='/') +#endif + /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a @@ -111674,7 +129408,7 @@ static const sqlite3_api_routines sqlite3Apis = { ** ** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong. ** -** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with +** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with ** error message text. The calling function should free this memory ** by calling sqlite3DbFree(db, ). */ @@ -111691,14 +129425,14 @@ static int sqlite3LoadExtension( const char *zEntry; char *zAltEntry = 0; void **aHandle; - u64 nMsg = 300 + sqlite3Strlen30(zFile); + u64 nMsg = strlen(zFile); int ii; int rc; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN - "dll" + "dll" #elif defined(__APPLE__) "dylib" #else @@ -111725,6 +129459,12 @@ static int sqlite3LoadExtension( zEntry = zProc ? zProc : "sqlite3_extension_init"; + /* tag-20210611-1. Some dlopen() implementations will segfault if given + ** an oversize filename. Most filesystems have a pathname limit of 4K, + ** so limit the extension filename length to about twice that. + ** https://sqlite.org/forum/forumpost/08a0d6d9bf */ + if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found; + handle = sqlite3OsDlOpen(pVfs, zFile); #if SQLITE_OS_UNIX || SQLITE_OS_WIN for(ii=0; ii sqlite3_example_init @@ -111767,7 +129497,7 @@ static int sqlite3LoadExtension( return SQLITE_NOMEM_BKPT; } memcpy(zAltEntry, "sqlite3_", 8); - for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){} + for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){} iFile++; if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ @@ -111781,10 +129511,11 @@ static int sqlite3LoadExtension( } if( xInit==0 ){ if( pzErrMsg ){ - nMsg += sqlite3Strlen30(zEntry); + nMsg += strlen(zEntry) + 300; *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ - sqlite3_snprintf(nMsg, zErrmsg, + assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */ + sqlite3_snprintf((int)nMsg, zErrmsg, "no entry point [%s] in shared library [%s]", zEntry, zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } @@ -111818,6 +129549,19 @@ static int sqlite3LoadExtension( db->aExtension[db->nExtension++] = handle; return SQLITE_OK; + +extension_not_found: + if( pzErrMsg ){ + nMsg += 300; + *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); + if( zErrmsg ){ + assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */ + sqlite3_snprintf((int)nMsg, zErrmsg, + "unable to open shared library [%.*s]", SQLITE_MAX_PATHLEN, zFile); + sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); + } + } + return SQLITE_ERROR; } SQLITE_API int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ @@ -111855,7 +129599,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ if( onoff ){ db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc; }else{ - db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc); + db->flags &= ~(u64)(SQLITE_LoadExtension|SQLITE_LoadExtFunc); } sqlite3_mutex_leave(db->mutex); return SQLITE_OK; @@ -111867,12 +129611,12 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){ ** The following object holds the list of automatically loaded ** extensions. ** -** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER +** This list is shared across threads. The SQLITE_MUTEX_STATIC_MAIN ** mutex must be held while accessing this list. */ typedef struct sqlite3AutoExtList sqlite3AutoExtList; static SQLITE_WSD struct sqlite3AutoExtList { - u32 nExt; /* Number of entries in aExt[] */ + u32 nExt; /* Number of entries in aExt[] */ void (**aExt)(void); /* Pointers to the extension init functions */ } sqlite3Autoext = { 0, 0 }; @@ -111909,7 +129653,7 @@ SQLITE_API int sqlite3_auto_extension( { u32 i; #if SQLITE_THREADSAFE - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); @@ -111947,7 +129691,7 @@ SQLITE_API int sqlite3_cancel_auto_extension( void (*xInit)(void) ){ #if SQLITE_THREADSAFE - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif int i; int n = 0; @@ -111974,7 +129718,7 @@ SQLITE_API void sqlite3_reset_auto_extension(void){ #endif { #if SQLITE_THREADSAFE - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); @@ -112004,7 +129748,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ for(i=0; go; i++){ char *zErrmsg; #if SQLITE_THREADSAFE - sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); + sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); #endif #ifdef SQLITE_OMIT_LOAD_EXTENSION const sqlite3_api_routines *pThunk = 0; @@ -112059,7 +129803,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ ** that includes the PragType_XXXX macro definitions and the aPragmaName[] ** object. This ensures that the aPragmaName[] table is arranged in ** lexicographical order to facility a binary search of the pragma name. -** Do not edit pragma.h directly. Edit and rerun the script in at +** Do not edit pragma.h directly. Edit and rerun the script in at ** ../tool/mkpragmatab.tcl. */ /************** Include pragma.h in the middle of pragma.c *******************/ /************** Begin file pragma.h ******************************************/ @@ -112070,49 +129814,52 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ */ /* The various pragma types */ -#define PragTyp_HEADER_VALUE 0 -#define PragTyp_AUTO_VACUUM 1 -#define PragTyp_FLAG 2 -#define PragTyp_BUSY_TIMEOUT 3 -#define PragTyp_CACHE_SIZE 4 -#define PragTyp_CACHE_SPILL 5 -#define PragTyp_CASE_SENSITIVE_LIKE 6 -#define PragTyp_COLLATION_LIST 7 -#define PragTyp_COMPILE_OPTIONS 8 -#define PragTyp_DATA_STORE_DIRECTORY 9 -#define PragTyp_DATABASE_LIST 10 -#define PragTyp_DEFAULT_CACHE_SIZE 11 -#define PragTyp_ENCODING 12 -#define PragTyp_FOREIGN_KEY_CHECK 13 -#define PragTyp_FOREIGN_KEY_LIST 14 -#define PragTyp_INCREMENTAL_VACUUM 15 -#define PragTyp_INDEX_INFO 16 -#define PragTyp_INDEX_LIST 17 -#define PragTyp_INTEGRITY_CHECK 18 -#define PragTyp_JOURNAL_MODE 19 -#define PragTyp_JOURNAL_SIZE_LIMIT 20 -#define PragTyp_LOCK_PROXY_FILE 21 -#define PragTyp_LOCKING_MODE 22 -#define PragTyp_PAGE_COUNT 23 -#define PragTyp_MMAP_SIZE 24 -#define PragTyp_PAGE_SIZE 25 -#define PragTyp_SECURE_DELETE 26 -#define PragTyp_SHRINK_MEMORY 27 -#define PragTyp_SOFT_HEAP_LIMIT 28 -#define PragTyp_STATS 29 -#define PragTyp_SYNCHRONOUS 30 -#define PragTyp_TABLE_INFO 31 -#define PragTyp_TEMP_STORE 32 -#define PragTyp_TEMP_STORE_DIRECTORY 33 -#define PragTyp_THREADS 34 -#define PragTyp_WAL_AUTOCHECKPOINT 35 -#define PragTyp_WAL_CHECKPOINT 36 -#define PragTyp_ACTIVATE_EXTENSIONS 37 -#define PragTyp_HEXKEY 38 -#define PragTyp_KEY 39 -#define PragTyp_REKEY 40 -#define PragTyp_LOCK_STATUS 41 -#define PragTyp_PARSER_TRACE 42 +#define PragTyp_ACTIVATE_EXTENSIONS 0 +#define PragTyp_ANALYSIS_LIMIT 1 +#define PragTyp_HEADER_VALUE 2 +#define PragTyp_AUTO_VACUUM 3 +#define PragTyp_FLAG 4 +#define PragTyp_BUSY_TIMEOUT 5 +#define PragTyp_CACHE_SIZE 6 +#define PragTyp_CACHE_SPILL 7 +#define PragTyp_CASE_SENSITIVE_LIKE 8 +#define PragTyp_COLLATION_LIST 9 +#define PragTyp_COMPILE_OPTIONS 10 +#define PragTyp_DATA_STORE_DIRECTORY 11 +#define PragTyp_DATABASE_LIST 12 +#define PragTyp_DEFAULT_CACHE_SIZE 13 +#define PragTyp_ENCODING 14 +#define PragTyp_FOREIGN_KEY_CHECK 15 +#define PragTyp_FOREIGN_KEY_LIST 16 +#define PragTyp_FUNCTION_LIST 17 +#define PragTyp_HARD_HEAP_LIMIT 18 +#define PragTyp_INCREMENTAL_VACUUM 19 +#define PragTyp_INDEX_INFO 20 +#define PragTyp_INDEX_LIST 21 +#define PragTyp_INTEGRITY_CHECK 22 +#define PragTyp_JOURNAL_MODE 23 +#define PragTyp_JOURNAL_SIZE_LIMIT 24 +#define PragTyp_LOCK_PROXY_FILE 25 +#define PragTyp_LOCKING_MODE 26 +#define PragTyp_PAGE_COUNT 27 +#define PragTyp_MMAP_SIZE 28 +#define PragTyp_MODULE_LIST 29 +#define PragTyp_OPTIMIZE 30 +#define PragTyp_PAGE_SIZE 31 +#define PragTyp_PRAGMA_LIST 32 +#define PragTyp_SECURE_DELETE 33 +#define PragTyp_SHRINK_MEMORY 34 +#define PragTyp_SOFT_HEAP_LIMIT 35 +#define PragTyp_SYNCHRONOUS 36 +#define PragTyp_TABLE_INFO 37 +#define PragTyp_TABLE_LIST 38 +#define PragTyp_TEMP_STORE 39 +#define PragTyp_TEMP_STORE_DIRECTORY 40 +#define PragTyp_THREADS 41 +#define PragTyp_WAL_AUTOCHECKPOINT 42 +#define PragTyp_WAL_CHECKPOINT 43 +#define PragTyp_LOCK_STATUS 44 +#define PragTyp_STATS 45 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -112129,54 +129876,67 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ ** result column is different from the name of the pragma */ static const char *const pragCName[] = { - /* 0 */ "cache_size", /* Used by: default_cache_size */ - /* 1 */ "cid", /* Used by: table_info */ - /* 2 */ "name", - /* 3 */ "type", - /* 4 */ "notnull", - /* 5 */ "dflt_value", - /* 6 */ "pk", - /* 7 */ "table", /* Used by: stats */ - /* 8 */ "index", - /* 9 */ "width", - /* 10 */ "height", - /* 11 */ "seqno", /* Used by: index_info */ - /* 12 */ "cid", - /* 13 */ "name", - /* 14 */ "seqno", /* Used by: index_xinfo */ - /* 15 */ "cid", - /* 16 */ "name", - /* 17 */ "desc", - /* 18 */ "coll", - /* 19 */ "key", - /* 20 */ "seq", /* Used by: index_list */ - /* 21 */ "name", - /* 22 */ "unique", - /* 23 */ "origin", - /* 24 */ "partial", - /* 25 */ "seq", /* Used by: database_list */ - /* 26 */ "name", - /* 27 */ "file", - /* 28 */ "seq", /* Used by: collation_list */ - /* 29 */ "name", - /* 30 */ "id", /* Used by: foreign_key_list */ - /* 31 */ "seq", - /* 32 */ "table", - /* 33 */ "from", - /* 34 */ "to", - /* 35 */ "on_update", - /* 36 */ "on_delete", - /* 37 */ "match", - /* 38 */ "table", /* Used by: foreign_key_check */ - /* 39 */ "rowid", - /* 40 */ "parent", - /* 41 */ "fkid", - /* 42 */ "busy", /* Used by: wal_checkpoint */ - /* 43 */ "log", - /* 44 */ "checkpointed", - /* 45 */ "timeout", /* Used by: busy_timeout */ - /* 46 */ "database", /* Used by: lock_status */ - /* 47 */ "status", + /* 0 */ "id", /* Used by: foreign_key_list */ + /* 1 */ "seq", + /* 2 */ "table", + /* 3 */ "from", + /* 4 */ "to", + /* 5 */ "on_update", + /* 6 */ "on_delete", + /* 7 */ "match", + /* 8 */ "cid", /* Used by: table_xinfo */ + /* 9 */ "name", + /* 10 */ "type", + /* 11 */ "notnull", + /* 12 */ "dflt_value", + /* 13 */ "pk", + /* 14 */ "hidden", + /* table_info reuses 8 */ + /* 15 */ "schema", /* Used by: table_list */ + /* 16 */ "name", + /* 17 */ "type", + /* 18 */ "ncol", + /* 19 */ "wr", + /* 20 */ "strict", + /* 21 */ "seqno", /* Used by: index_xinfo */ + /* 22 */ "cid", + /* 23 */ "name", + /* 24 */ "desc", + /* 25 */ "coll", + /* 26 */ "key", + /* 27 */ "name", /* Used by: function_list */ + /* 28 */ "builtin", + /* 29 */ "type", + /* 30 */ "enc", + /* 31 */ "narg", + /* 32 */ "flags", + /* 33 */ "tbl", /* Used by: stats */ + /* 34 */ "idx", + /* 35 */ "wdth", + /* 36 */ "hght", + /* 37 */ "flgs", + /* 38 */ "seq", /* Used by: index_list */ + /* 39 */ "name", + /* 40 */ "unique", + /* 41 */ "origin", + /* 42 */ "partial", + /* 43 */ "table", /* Used by: foreign_key_check */ + /* 44 */ "rowid", + /* 45 */ "parent", + /* 46 */ "fkid", + /* index_info reuses 21 */ + /* 47 */ "seq", /* Used by: database_list */ + /* 48 */ "name", + /* 49 */ "file", + /* 50 */ "busy", /* Used by: wal_checkpoint */ + /* 51 */ "log", + /* 52 */ "checkpointed", + /* collation_list reuses 38 */ + /* 53 */ "database", /* Used by: lock_status */ + /* 54 */ "status", + /* 55 */ "cache_size", /* Used by: default_cache_size */ + /* module_list pragma_list reuses 9 */ + /* 56 */ "timeout", /* Used by: busy_timeout */ }; /* Definitions of all built-in pragmas */ @@ -112186,16 +129946,21 @@ typedef struct PragmaName { u8 mPragFlg; /* Zero or more PragFlg_XXX values */ u8 iPragCName; /* Start of column names in pragCName[] */ u8 nPragCName; /* Num of col names. 0 means use pragma name */ - u32 iArg; /* Extra argument */ + u64 iArg; /* Extra argument */ } PragmaName; static const PragmaName aPragmaName[] = { -#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) +#if defined(SQLITE_ENABLE_CEROD) {/* zName: */ "activate_extensions", /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif + {/* zName: */ "analysis_limit", + /* ePragTyp: */ PragTyp_ANALYSIS_LIMIT, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "application_id", /* ePragTyp: */ PragTyp_HEADER_VALUE, @@ -112222,7 +129987,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 45, 1, + /* ColNames: */ 56, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", @@ -112238,11 +130003,13 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif +#if !defined(SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA) {/* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, /* ePragFlg: */ PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#endif {/* zName: */ "cell_size_check", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -112259,7 +130026,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 28, 2, + /* ColNames: */ 38, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -112294,14 +130061,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 25, 3, + /* ColNames: */ 47, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, - /* ColNames: */ 0, 1, + /* ColNames: */ 55, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -112330,15 +130097,15 @@ static const PragmaName aPragmaName[] = { #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 38, 4, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 43, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 30, 8, + /* ColNames: */ 0, 8, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -112369,18 +130136,20 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullFSync }, #endif -#if defined(SQLITE_HAS_CODEC) - {/* zName: */ "hexkey", - /* ePragTyp: */ PragTyp_HEXKEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) +#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) + {/* zName: */ "function_list", + /* ePragTyp: */ PragTyp_FUNCTION_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 27, 6, /* iArg: */ 0 }, - {/* zName: */ "hexrekey", - /* ePragTyp: */ PragTyp_HEXKEY, - /* ePragFlg: */ 0, +#endif +#endif + {/* zName: */ "hard_heap_limit", + /* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT, + /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, -#endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) {/* zName: */ "ignore_check_constraints", @@ -112401,23 +130170,23 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 11, 3, + /* ColNames: */ 21, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 20, 5, + /* ColNames: */ 38, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 14, 6, + /* ColNames: */ 21, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "integrity_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif @@ -112433,19 +130202,12 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif -#if defined(SQLITE_HAS_CODEC) - {/* zName: */ "key", - /* ePragTyp: */ PragTyp_KEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 0 }, -#endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) - {/* zName: */ "legacy_file_format", + {/* zName: */ "legacy_alter_table", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_LegacyFileFmt }, + /* iArg: */ SQLITE_LegacyAlter }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE {/* zName: */ "lock_proxy_file", @@ -112458,7 +130220,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 46, 2, + /* ColNames: */ 53, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -112477,6 +130239,24 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#endif +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) +#if !defined(SQLITE_OMIT_VIRTUALTABLE) +#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) + {/* zName: */ "module_list", + /* ePragTyp: */ PragTyp_MODULE_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 9, 1, + /* iArg: */ 0 }, +#endif +#endif +#endif + {/* zName: */ "optimize", + /* ePragTyp: */ PragTyp_OPTIMIZE, + /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema, + /* ColNames: */ 0, 0, + /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "page_count", /* ePragTyp: */ PragTyp_PAGE_COUNT, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, @@ -112488,11 +130268,20 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif -#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE) +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) +#if defined(SQLITE_DEBUG) {/* zName: */ "parser_trace", - /* ePragTyp: */ PragTyp_PARSER_TRACE, - /* ePragFlg: */ 0, + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_ParserTrace }, +#endif +#endif +#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS) + {/* zName: */ "pragma_list", + /* ePragTyp: */ PragTyp_PRAGMA_LIST, + /* ePragFlg: */ PragFlg_Result0, + /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -112505,7 +130294,7 @@ static const PragmaName aPragmaName[] = { #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "quick_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, - /* ePragFlg: */ PragFlg_NeedSchema, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif @@ -112514,21 +130303,12 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_ReadUncommitted }, + /* iArg: */ SQLITE_ReadUncommit }, {/* zName: */ "recursive_triggers", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_RecTriggers }, -#endif -#if defined(SQLITE_HAS_CODEC) - {/* zName: */ "rekey", - /* ePragTyp: */ PragTyp_REKEY, - /* ePragFlg: */ 0, - /* ColNames: */ 0, 0, - /* iArg: */ 0 }, -#endif -#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "reverse_unordered_selects", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -112575,11 +130355,11 @@ static const PragmaName aPragmaName[] = { /* iArg: */ SQLITE_SqlTrace }, #endif #endif -#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) +#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG) {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 7, 4, + /* ColNames: */ 33, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -112593,8 +130373,18 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "table_info", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 1, 6, + /* ColNames: */ 8, 6, + /* iArg: */ 0 }, + {/* zName: */ "table_list", + /* ePragTyp: */ PragTyp_TABLE_LIST, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, + /* ColNames: */ 15, 6, /* iArg: */ 0 }, + {/* zName: */ "table_xinfo", + /* ePragTyp: */ PragTyp_TABLE_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 8, 7, + /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "temp_store", @@ -112613,6 +130403,13 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) + {/* zName: */ "trusted_schema", + /* ePragTyp: */ PragTyp_FLAG, + /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, + /* ColNames: */ 0, 0, + /* iArg: */ SQLITE_TrustedSchema }, +#endif #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) {/* zName: */ "user_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, @@ -112658,7 +130455,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 42, 3, + /* ColNames: */ 50, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -112666,17 +130463,17 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, + /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; -/* Number of pragmas: 60 on by default, 73 total. */ +/* Number of pragmas: 68 on by default, 78 total. */ /************** End of pragma.h **********************************************/ /************** Continuing where we left off in pragma.c *********************/ /* ** Interpret the given string as a safety level. Return 0 for OFF, -** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or +** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or ** unrecognized string argument. The FULL and EXTRA option is disallowed ** if the omitFull parameter it 1. ** @@ -112735,7 +130532,7 @@ static int getLockingMode(const char *z){ /* ** Interpret the given string as an auto-vacuum mode value. ** -** The following strings, "none", "full" and "incremental" are +** The following strings, "none", "full" and "incremental" are ** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively. */ static int getAutoVacuum(const char *z){ @@ -112775,7 +130572,9 @@ static int getTempStore(const char *z){ static int invalidateTempStorage(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt!=0 ){ - if( !db->autoCommit || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){ + if( !db->autoCommit + || sqlite3BtreeTxnState(db->aDb[1].pBt)!=SQLITE_TXN_NONE + ){ sqlite3ErrorMsg(pParse, "temporary storage cannot be changed " "from within a transaction"); return SQLITE_ERROR; @@ -112887,7 +130686,7 @@ static const char *actionName(u8 action){ case OE_SetDflt: zName = "SET DEFAULT"; break; case OE_Cascade: zName = "CASCADE"; break; case OE_Restrict: zName = "RESTRICT"; break; - default: zName = "NO ACTION"; + default: zName = "NO ACTION"; assert( action==OE_None ); break; } return zName; @@ -112940,7 +130739,72 @@ static const PragmaName *pragmaLocate(const char *zName){ } /* -** Process a pragma statement. +** Create zero or more entries in the output for the SQL functions +** defined by FuncDef p. +*/ +static void pragmaFunclistLine( + Vdbe *v, /* The prepared statement being created */ + FuncDef *p, /* A particular function definition */ + int isBuiltin, /* True if this is a built-in function */ + int showInternFuncs /* True if showing internal functions */ +){ + for(; p; p=p->pNext){ + const char *zType; + static const u32 mask = + SQLITE_DETERMINISTIC | + SQLITE_DIRECTONLY | + SQLITE_SUBTYPE | + SQLITE_INNOCUOUS | + SQLITE_FUNC_INTERNAL + ; + static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" }; + + assert( SQLITE_FUNC_ENCMASK==0x3 ); + assert( strcmp(azEnc[SQLITE_UTF8],"utf8")==0 ); + assert( strcmp(azEnc[SQLITE_UTF16LE],"utf16le")==0 ); + assert( strcmp(azEnc[SQLITE_UTF16BE],"utf16be")==0 ); + + if( p->xSFunc==0 ) continue; + if( (p->funcFlags & SQLITE_FUNC_INTERNAL)!=0 + && showInternFuncs==0 + ){ + continue; + } + if( p->xValue!=0 ){ + zType = "w"; + }else if( p->xFinalize!=0 ){ + zType = "a"; + }else{ + zType = "s"; + } + sqlite3VdbeMultiLoad(v, 1, "sissii", + p->zName, isBuiltin, + zType, azEnc[p->funcFlags&SQLITE_FUNC_ENCMASK], + p->nArg, + (p->funcFlags & mask) ^ SQLITE_INNOCUOUS + ); + } +} + + +/* +** Helper subroutine for PRAGMA integrity_check: +** +** Generate code to output a single-column result row with a value of the +** string held in register 3. Decrement the result count in register 1 +** and halt if the maximum number of result rows have been issued. +*/ +static int integrityCheckResultRow(Vdbe *v){ + int addr; + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); + addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1); + VdbeCoverage(v); + sqlite3VdbeAddOp0(v, OP_Halt); + return addr; +} + +/* +** Process a pragma statement. ** ** Pragmas are of this form: ** @@ -112955,7 +130819,7 @@ static const PragmaName *pragmaLocate(const char *zName){ ** id and pId2 is any empty string. */ SQLITE_PRIVATE void sqlite3Pragma( - Parse *pParse, + Parse *pParse, Token *pId1, /* First part of [schema.]id field */ Token *pId2, /* Second part of [schema.]id field, or NULL */ Token *pValue, /* Token for , or NULL */ @@ -112983,8 +130847,8 @@ SQLITE_PRIVATE void sqlite3Pragma( if( iDb<0 ) return; pDb = &db->aDb[iDb]; - /* If the temp database has been explicitly named as part of the - ** pragma, make sure it is open. + /* If the temp database has been explicitly named as part of the + ** pragma, make sure it is open. */ if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){ return; @@ -113044,7 +130908,11 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); - if( pPragma==0 ) goto pragma_out; + if( pPragma==0 ){ + /* IMP: R-43042-22504 No error messages are generated if an + ** unknown pragma is issued. */ + goto pragma_out; + } /* Make sure the database schema is loaded if the pragma requires that */ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ @@ -113052,7 +130920,7 @@ SQLITE_PRIVATE void sqlite3Pragma( } /* Register the result column names for pragmas that return results */ - if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 + if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0) ){ setPragmaResultColumnNames(v, pPragma); @@ -113060,7 +130928,7 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Jump to the appropriate pragma handler */ switch( pPragma->ePragTyp ){ - + #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) /* ** PRAGMA [schema.]default_cache_size @@ -113134,7 +131002,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ** buffer that the pager module resizes using sqlite3_realloc(). */ db->nextPagesize = sqlite3Atoi(zRight); - if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){ + if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){ sqlite3OomFault(db); } } @@ -113143,18 +131011,22 @@ SQLITE_PRIVATE void sqlite3Pragma( /* ** PRAGMA [schema.]secure_delete - ** PRAGMA [schema.]secure_delete=ON/OFF + ** PRAGMA [schema.]secure_delete=ON/OFF/FAST ** ** The first form reports the current setting for the ** secure_delete flag. The second form changes the secure_delete - ** flag setting and reports thenew value. + ** flag setting and reports the new value. */ case PragTyp_SECURE_DELETE: { Btree *pBt = pDb->pBt; int b = -1; assert( pBt!=0 ); if( zRight ){ - b = sqlite3GetBoolean(zRight, 0); + if( sqlite3_stricmp(zRight, "fast")==0 ){ + b = 2; + }else{ + b = sqlite3GetBoolean(zRight, 0); + } } if( pId2->n==0 && b>=0 ){ int ii; @@ -113172,7 +131044,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ** PRAGMA [schema.]max_page_count=N ** ** The first form reports the current setting for the - ** maximum number of pages in the database file. The + ** maximum number of pages in the database file. The ** second form attempts to change this setting. Both ** forms return the current setting. ** @@ -113186,13 +131058,19 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_PAGE_COUNT: { int iReg; + i64 x = 0; sqlite3CodeVerifySchema(pParse, iDb); iReg = ++pParse->nMem; if( sqlite3Tolower(zLeft[0])=='p' ){ sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg); }else{ - sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, - sqlite3AbsInt32(sqlite3Atoi(zRight))); + if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){ + if( x<0 ) x = 0; + else if( x>0xfffffffe ) x = 0xfffffffe; + }else{ + x = 0; + } + sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x); } sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1); break; @@ -113268,6 +131146,11 @@ SQLITE_PRIVATE void sqlite3Pragma( ** then do a query */ eMode = PAGER_JOURNALMODE_QUERY; } + if( eMode==PAGER_JOURNALMODE_OFF && (db->flags & SQLITE_Defensive)!=0 ){ + /* Do not allow journal-mode "OFF" in defensive since the database + ** can become corrupted using ordinary SQL when the journal is off */ + eMode = PAGER_JOURNALMODE_QUERY; + } } if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){ /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */ @@ -113328,7 +131211,7 @@ SQLITE_PRIVATE void sqlite3Pragma( */ rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto); if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){ - /* When setting the auto_vacuum mode to either "full" or + /* When setting the auto_vacuum mode to either "full" or ** "incremental", write the value of meta[6] in the database ** file. Before writing to meta[6], check that meta[3] indicates ** that this really is an auto-vacuum capable database. @@ -113430,7 +131313,7 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !zRight ){ returnSingleInt(v, - (db->flags & SQLITE_CacheSpill)==0 ? 0 : + (db->flags & SQLITE_CacheSpill)==0 ? 0 : sqlite3BtreeSetSpillSize(pDb->pBt,0)); }else{ int size = 1; @@ -113440,7 +131323,7 @@ SQLITE_PRIVATE void sqlite3Pragma( if( sqlite3GetBoolean(zRight, size!=0) ){ db->flags |= SQLITE_CacheSpill; }else{ - db->flags &= ~SQLITE_CacheSpill; + db->flags &= ~(u64)SQLITE_CacheSpill; } setAllPagerFlags(db); } @@ -113604,7 +131487,7 @@ SQLITE_PRIVATE void sqlite3Pragma( Pager *pPager = sqlite3BtreePager(pDb->pBt); char *proxy_file_path = NULL; sqlite3_file *pFile = sqlite3PagerFile(pPager); - sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, + sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, &proxy_file_path); returnSingleText(v, proxy_file_path); }else{ @@ -113612,10 +131495,10 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3_file *pFile = sqlite3PagerFile(pPager); int res; if( zRight[0] ){ - res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, + res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, zRight); } else { - res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, + res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE, NULL); } if( res!=SQLITE_OK ){ @@ -113625,8 +131508,8 @@ SQLITE_PRIVATE void sqlite3Pragma( } break; } -#endif /* SQLITE_ENABLE_LOCKING_STYLE */ - +#endif /* SQLITE_ENABLE_LOCKING_STYLE */ + /* ** PRAGMA [schema.]synchronous ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA @@ -113641,9 +131524,9 @@ SQLITE_PRIVATE void sqlite3Pragma( returnSingleInt(v, pDb->safety_level-1); }else{ if( !db->autoCommit ){ - sqlite3ErrorMsg(pParse, + sqlite3ErrorMsg(pParse, "Safety level may not be changed inside a transaction"); - }else{ + }else if( iDb!=1 ){ int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK; if( iLevel==0 ) iLevel = 1; pDb->safety_level = iLevel; @@ -113661,7 +131544,7 @@ SQLITE_PRIVATE void sqlite3Pragma( setPragmaResultColumnNames(v, pPragma); returnSingleInt(v, (db->flags & pPragma->iArg)!=0 ); }else{ - int mask = pPragma->iArg; /* Mask of bits to set or clear. */ + u64 mask = pPragma->iArg; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ @@ -113679,9 +131562,17 @@ SQLITE_PRIVATE void sqlite3Pragma( }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; + if( (mask & SQLITE_WriteSchema)!=0 + && sqlite3_stricmp(zRight, "reset")==0 + ){ + /* IMP: R-60817-01178 If the argument is "RESET" then schema + ** writing is disabled (as with "PRAGMA writable_schema=OFF") and, + ** in addition, the schema is reloaded. */ + sqlite3ResetAllSchemasOfConnection(db); + } } - /* Many of the flag-pragmas modify the code generated by the SQL + /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ @@ -113704,22 +131595,34 @@ SQLITE_PRIVATE void sqlite3Pragma( ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. + ** pk: Non-zero for PK fields. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; + sqlite3CodeVerifyNamedSchema(pParse, zDb); pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ int i, k; int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); - pParse->nMem = 6; - sqlite3CodeVerifySchema(pParse, iDb); + pParse->nMem = 7; sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ - if( IsHiddenColumn(pCol) ){ - nHidden++; - continue; + int isHidden = 0; + const Expr *pColExpr; + if( pCol->colFlags & COLFLAG_NOINSERT ){ + if( pPragma->iArg==0 ){ + nHidden++; + continue; + } + if( pCol->colFlags & COLFLAG_VIRTUAL ){ + isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */ + }else if( pCol->colFlags & COLFLAG_STORED ){ + isHidden = 3; /* GENERATED ALWAYS AS ... STORED */ + }else{ assert( pCol->colFlags & COLFLAG_HIDDEN ); + isHidden = 1; /* HIDDEN */ + } } if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ k = 0; @@ -113728,49 +131631,144 @@ SQLITE_PRIVATE void sqlite3Pragma( }else{ for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } - assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN ); - sqlite3VdbeMultiLoad(v, 1, "issisi", + pColExpr = sqlite3ColumnExpr(pTab,pCol); + assert( pColExpr==0 || pColExpr->op==TK_SPAN || isHidden>=2 ); + assert( pColExpr==0 || !ExprHasProperty(pColExpr, EP_IntValue) + || isHidden>=2 ); + sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, - pCol->zName, + pCol->zCnName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, - pCol->pDflt ? pCol->pDflt->u.zToken : 0, - k); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); + (isHidden>=2 || pColExpr==0) ? 0 : pColExpr->u.zToken, + k, + isHidden); } } } break; + /* + ** PRAGMA table_list + ** + ** Return a single row for each table, virtual table, or view in the + ** entire schema. + ** + ** schema: Name of attached database hold this table + ** name: Name of the table itself + ** type: "table", "view", "virtual", "shadow" + ** ncol: Number of columns + ** wr: True for a WITHOUT ROWID table + ** strict: True for a STRICT table + */ + case PragTyp_TABLE_LIST: { + int ii; + pParse->nMem = 6; + sqlite3CodeVerifyNamedSchema(pParse, zDb); + for(ii=0; iinDb; ii++){ + HashElem *k; + Hash *pHash; + int initNCol; + if( zDb && sqlite3_stricmp(zDb, db->aDb[ii].zDbSName)!=0 ) continue; + + /* Ensure that the Table.nCol field is initialized for all views + ** and virtual tables. Each time we initialize a Table.nCol value + ** for a table, that can potentially disrupt the hash table, so restart + ** the initialization scan. + */ + pHash = &db->aDb[ii].pSchema->tblHash; + initNCol = sqliteHashCount(pHash); + while( initNCol-- ){ + for(k=sqliteHashFirst(pHash); 1; k=sqliteHashNext(k) ){ + Table *pTab; + if( k==0 ){ initNCol = 0; break; } + pTab = sqliteHashData(k); + if( pTab->nCol==0 ){ + char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName); + if( zSql ){ + sqlite3_stmt *pDummy = 0; + (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0); + (void)sqlite3_finalize(pDummy); + sqlite3DbFree(db, zSql); + } + if( db->mallocFailed ){ + sqlite3ErrorMsg(db->pParse, "out of memory"); + db->pParse->rc = SQLITE_NOMEM_BKPT; + } + pHash = &db->aDb[ii].pSchema->tblHash; + break; + } + } + } + + for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k) ){ + Table *pTab = sqliteHashData(k); + const char *zType; + if( zRight && sqlite3_stricmp(zRight, pTab->zName)!=0 ) continue; + if( IsView(pTab) ){ + zType = "view"; + }else if( IsVirtual(pTab) ){ + zType = "virtual"; + }else if( pTab->tabFlags & TF_Shadow ){ + zType = "shadow"; + }else{ + zType = "table"; + } + sqlite3VdbeMultiLoad(v, 1, "sssiii", + db->aDb[ii].zDbSName, + sqlite3PreferredTableName(pTab->zName), + zType, + pTab->nCol, + (pTab->tabFlags & TF_WithoutRowid)!=0, + (pTab->tabFlags & TF_Strict)!=0 + ); + } + } + } + break; + +#ifdef SQLITE_DEBUG case PragTyp_STATS: { Index *pIdx; HashElem *i; - pParse->nMem = 4; + pParse->nMem = 5; sqlite3CodeVerifySchema(pParse, iDb); for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); - sqlite3VdbeMultiLoad(v, 1, "ssii", - pTab->zName, + sqlite3VdbeMultiLoad(v, 1, "ssiii", + sqlite3PreferredTableName(pTab->zName), 0, pTab->szTabRow, - pTab->nRowLogEst); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); + pTab->nRowLogEst, + pTab->tabFlags); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - sqlite3VdbeMultiLoad(v, 2, "sii", + sqlite3VdbeMultiLoad(v, 2, "siiiX", pIdx->zName, pIdx->szIdxRow, - pIdx->aiRowLogEst[0]); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4); + pIdx->aiRowLogEst[0], + pIdx->hasStat1); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } break; +#endif case PragTyp_INDEX_INFO: if( zRight ){ Index *pIdx; Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); + if( pIdx==0 ){ + /* If there is no index named zRight, check to see if there is a + ** WITHOUT ROWID table named zRight, and if there is, show the + ** structure of the PRIMARY KEY index for that table. */ + pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); + if( pTab && !HasRowid(pTab) ){ + pIdx = sqlite3PrimaryKeyIndex(pTab); + } + } if( pIdx ){ + int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema); int i; int mx; if( pPragma->iArg ){ @@ -113783,14 +131781,14 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem = 3; } pTab = pIdx->pTable; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iIdxDb); assert( pParse->nMem<=pPragma->nPragCName ); for(i=0; iaiColumn[i]; - sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum, - cnum<0 ? 0 : pTab->aCol[cnum].zName); + sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, + cnum<0 ? 0 : pTab->aCol[cnum].zCnName); if( pPragma->iArg ){ - sqlite3VdbeMultiLoad(v, 4, "isi", + sqlite3VdbeMultiLoad(v, 4, "isiX", pIdx->aSortOrder[i], pIdx->azColl[i], inKeyCol); @@ -113807,8 +131805,9 @@ SQLITE_PRIVATE void sqlite3Pragma( int i; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); pParse->nMem = 5; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iTabDb); for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ const char *azOrigin[] = { "c", "u", "pk" }; sqlite3VdbeMultiLoad(v, 1, "isisi", @@ -113817,7 +131816,6 @@ SQLITE_PRIVATE void sqlite3Pragma( IsUniqueIndex(pIdx), azOrigin[pIdx->idxType], pIdx->pPartIdxWhere!=0); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5); } } } @@ -113833,7 +131831,6 @@ SQLITE_PRIVATE void sqlite3Pragma( i, db->aDb[i].zDbSName, sqlite3BtreeGetFilename(db->aDb[i].pBt)); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } break; @@ -113845,10 +131842,52 @@ SQLITE_PRIVATE void sqlite3Pragma( for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } } break; + +#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS + case PragTyp_FUNCTION_LIST: { + int i; + HashElem *j; + FuncDef *p; + int showInternFunc = (db->mDbFlags & DBFLAG_InternalFunc)!=0; + pParse->nMem = 6; + for(i=0; iu.pHash ){ + assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); + pragmaFunclistLine(v, p, 1, showInternFunc); + } + } + for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ + p = (FuncDef*)sqliteHashData(j); + assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); + pragmaFunclistLine(v, p, 0, showInternFunc); + } + } + break; + +#ifndef SQLITE_OMIT_VIRTUALTABLE + case PragTyp_MODULE_LIST: { + HashElem *j; + pParse->nMem = 1; + for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){ + Module *pMod = (Module*)sqliteHashData(j); + sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName); + } + } + break; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + case PragTyp_PRAGMA_LIST: { + int i; + for(i=0; ipFKey; + if( pTab && IsOrdinaryTable(pTab) ){ + pFK = pTab->u.tab.pFKey; if( pFK ){ - int i = 0; + int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); + int i = 0; pParse->nMem = 8; - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchema(pParse, iTabDb); while(pFK){ int j; for(j=0; jnCol; j++){ @@ -113869,12 +131909,11 @@ SQLITE_PRIVATE void sqlite3Pragma( i, j, pFK->zTo, - pTab->aCol[pFK->aCol[j].iFrom].zName, + pTab->aCol[pFK->aCol[j].iFrom].zCnName, pFK->aCol[j].zCol, actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[0]), /* ON DELETE */ "NONE"); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8); } ++i; pFK = pFK->pNextFrom; @@ -113907,7 +131946,6 @@ SQLITE_PRIVATE void sqlite3Pragma( pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; - sqlite3CodeVerifySchema(pParse, iDb); k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ if( zRight ){ @@ -113917,12 +131955,16 @@ SQLITE_PRIVATE void sqlite3Pragma( pTab = (Table*)sqliteHashData(k); k = sqliteHashNext(k); } - if( pTab==0 || pTab->pFKey==0 ) continue; + if( pTab==0 || !IsOrdinaryTable(pTab) || pTab->u.tab.pFKey==0 ) continue; + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + zDb = db->aDb[iDb].zDbSName; + sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ + assert( IsOrdinaryTable(pTab) ); + for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); if( pParent==0 ) continue; pIdx = 0; @@ -113944,43 +131986,49 @@ SQLITE_PRIVATE void sqlite3Pragma( if( pFK ) break; if( pParse->nTabnTab = i; addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v); - for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ + assert( IsOrdinaryTable(pTab) ); + for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); pIdx = 0; aiCols = 0; if( pParent ){ x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); - assert( x==0 ); - } - addrOk = sqlite3VdbeMakeLabel(v); - if( pParent && pIdx==0 ){ - int iKey = pFK->aCol[0].iFrom; - assert( iKey>=0 && iKeynCol ); - if( iKey!=pTab->iPKey ){ - sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); - sqlite3ColumnDefault(v, pTab, iKey, regRow); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v); - }else{ - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); - } - sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v); + assert( x==0 || db->mallocFailed ); + } + addrOk = sqlite3VdbeMakeLabel(pParse); + + /* Generate code to read the child key values into registers + ** regRow..regRow+n. If any of the child key values are NULL, this + ** row cannot cause an FK violation. Jump directly to addrOk in + ** this case. */ + if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol; + for(j=0; jnCol; j++){ + int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; + sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); + sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); + } + + /* Generate code to query the parent index for a matching parent + ** key. If a match is found, jump to addrOk. */ + if( pIdx ){ + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, + sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); + sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); + VdbeCoverage(v); + }else if( pParent ){ + int jmp = sqlite3VdbeCurrentAddr(v)+2; + sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v); sqlite3VdbeGoto(v, addrOk); - sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); + assert( pFK->nCol==1 || db->mallocFailed ); + } + + /* Generate code to report an FK violation to the caller. */ + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); }else{ - for(j=0; jnCol; j++){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, - aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j); - sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); - } - if( pParent ){ - sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, - sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); - sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); - VdbeCoverage(v); - } + sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1); } - sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); - sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1); + sqlite3VdbeMultiLoad(v, regResult+2, "siX", pFK->zTo, i-1); sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); sqlite3VdbeResolveLabel(v, addrOk); sqlite3DbFree(db, aiCols); @@ -113993,19 +132041,7 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ -#ifndef NDEBUG - case PragTyp_PARSER_TRACE: { - if( zRight ){ - if( sqlite3GetBoolean(zRight, 0) ){ - sqlite3ParserTrace(stdout, "parser: "); - }else{ - sqlite3ParserTrace(0, 0); - } - } - } - break; -#endif - +#ifndef SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA /* Reinstall the LIKE and GLOB functions. The variant of LIKE ** used will be case sensitive or not depending on the RHS. */ @@ -114015,18 +132051,40 @@ SQLITE_PRIVATE void sqlite3Pragma( } } break; +#endif /* SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA */ #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 #endif #ifndef SQLITE_OMIT_INTEGRITY_CHECK - /* Pragma "quick_check" is reduced version of + /* PRAGMA integrity_check + ** PRAGMA integrity_check(N) + ** PRAGMA quick_check + ** PRAGMA quick_check(N) + ** + ** Verify the integrity of the database. + ** + ** The "quick_check" is reduced version of ** integrity_check designed to detect most database corruption - ** without most of the overhead of a full integrity-check. + ** without the overhead of cross-checking indexes. Quick_check + ** is linear time wherease integrity_check is O(NlogN). + ** + ** The maximum nubmer of errors is 100 by default. A different default + ** can be specified using a numeric parameter N. + ** + ** Or, the parameter N can be the name of a table. In that case, only + ** the one table named is verified. The freelist is only verified if + ** the named table is "sqlite_schema" (or one of its aliases). + ** + ** All schemas are checked by default. To check just a single + ** schema, use the form: + ** + ** PRAGMA schema.integrity_check; */ case PragTyp_INTEGRITY_CHECK: { int i, j, addr, mxErr; + Table *pObjTab = 0; /* Check only this one table, if not NULL */ int isQuick = (sqlite3Tolower(zLeft[0])=='q'); @@ -114049,30 +132107,29 @@ SQLITE_PRIVATE void sqlite3Pragma( /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; if( zRight ){ - sqlite3GetInt32(zRight, &mxErr); - if( mxErr<=0 ){ - mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; + if( sqlite3GetInt32(zRight, &mxErr) ){ + if( mxErr<=0 ){ + mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; + } + }else{ + pObjTab = sqlite3LocateTable(pParse, 0, zRight, + iDb>=0 ? db->aDb[iDb].zDbSName : 0); } } - sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */ + sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */ /* Do an integrity check on each database file */ for(i=0; inDb; i++){ - HashElem *x; - Hash *pTbls; - int *aRoot; - int cnt = 0; - int mxIdx = 0; - int nIdx; + HashElem *x; /* For looping over tables in the schema */ + Hash *pTbls; /* Set of all tables in the schema */ + int *aRoot; /* Array of root page numbers of all btrees */ + int cnt = 0; /* Number of entries in aRoot[] */ + int mxIdx = 0; /* Maximum number of indexes for any table */ if( OMIT_TEMPDB && i==1 ) continue; if( iDb>=0 && i!=iDb ) continue; sqlite3CodeVerifySchema(pParse, i); - addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */ - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); - sqlite3VdbeJumpHere(v, addr); /* Do an integrity check of the B-Tree ** @@ -114082,26 +132139,34 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( sqlite3SchemaMutexHeld(db, i, 0) ); pTbls = &db->aDb[i].pSchema->tblHash; for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ - Table *pTab = sqliteHashData(x); - Index *pIdx; + Table *pTab = sqliteHashData(x); /* Current table */ + Index *pIdx; /* An index on pTab */ + int nIdx; /* Number of indexes on pTab */ + if( pObjTab && pObjTab!=pTab ) continue; if( HasRowid(pTab) ) cnt++; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; } if( nIdx>mxIdx ) mxIdx = nIdx; } + if( cnt==0 ) continue; + if( pObjTab ) cnt++; aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1)); if( aRoot==0 ) break; - for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ + cnt = 0; + if( pObjTab ) aRoot[++cnt] = 0; + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; - if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum; + if( pObjTab && pObjTab!=pTab ) continue; + if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - aRoot[cnt++] = pIdx->tnum; + aRoot[++cnt] = pIdx->tnum; } } - aRoot[cnt] = 0; + aRoot[0] = cnt; /* Make sure sufficient number of registers have been allocated */ pParse->nMem = MAX( pParse->nMem, 8+mxIdx ); + sqlite3ClearTempRegCache(pParse); /* Do the b-tree integrity checks */ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY); @@ -114110,30 +132175,29 @@ SQLITE_PRIVATE void sqlite3Pragma( sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName), P4_DYNAMIC); - sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); - sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); + sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3); + integrityCheckResultRow(v); sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. */ - for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){ + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; Index *pPrior = 0; int loopTop; int iDataCur, iIdxCur; int r1 = -1; + int bStrict; - if( pTab->pIndex==0 ) continue; + if( !IsOrdinaryTable(pTab) ) continue; + if( pObjTab && pObjTab!=pTab ) continue; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); - addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */ - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); - sqlite3VdbeJumpHere(v, addr); - sqlite3ExprCacheClear(pParse); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); + /* reg[7] counts the number of entries in the table. + ** reg[8+i] counts the number of entries in the i-th index + */ sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */ @@ -114142,111 +132206,164 @@ SQLITE_PRIVATE void sqlite3Pragma( assert( sqlite3NoTempsInRange(pParse,1,7+j) ); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); - /* Verify that all NOT NULL columns really are NOT NULL */ + if( !isQuick ){ + /* Sanity check on record header decoding */ + sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + VdbeComment((v, "(right-most column)")); + } + /* Verify that all NOT NULL columns really are NOT NULL. At the + ** same time verify the type of the content of STRICT tables */ + bStrict = (pTab->tabFlags & TF_Strict)!=0; for(j=0; jnCol; j++){ char *zErr; - int jmp2, jmp3; + Column *pCol = pTab->aCol + j; + int doError, jmp2; if( j==pTab->iPKey ) continue; - if( pTab->aCol[j].notNull==0 ) continue; + if( pCol->notNull==0 && !bStrict ) continue; + doError = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); - sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); - jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ - zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, - pTab->aCol[j].zName); - sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); - sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); - jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); - sqlite3VdbeAddOp0(v, OP_Halt); - sqlite3VdbeJumpHere(v, jmp2); - sqlite3VdbeJumpHere(v, jmp3); - } - /* Validate index entries for the current row */ - for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - int jmp2, jmp3, jmp4, jmp5; - int ckUniq = sqlite3VdbeMakeLabel(v); - if( pPk==pIdx ) continue; - r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, - pPrior, r1); - pPrior = pIdx; - sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ - /* Verify that an index entry exists for the current table row */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, - pIdx->nColumn); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ - sqlite3VdbeLoadString(v, 3, "row "); - sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeLoadString(v, 4, " missing from index "); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); - jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); - sqlite3VdbeAddOp0(v, OP_Halt); - sqlite3VdbeJumpHere(v, jmp2); - /* For UNIQUE indexes, verify that only one entry exists with the - ** current key. The entry is unique if (1) any column is NULL - ** or (2) the next entry has a different key */ - if( IsUniqueIndex(pIdx) ){ - int uniqOk = sqlite3VdbeMakeLabel(v); - int jmp6; - int kk; - for(kk=0; kknKeyCol; kk++){ - int iCol = pIdx->aiColumn[kk]; - assert( iCol!=XN_ROWID && iColnCol ); - if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; - sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); - VdbeCoverage(v); + if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){ + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + } + if( pCol->notNull ){ + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, + pCol->zCnName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + if( bStrict && pCol->eCType!=COLTYPE_ANY ){ + sqlite3VdbeGoto(v, doError); + }else{ + integrityCheckResultRow(v); } - jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); - sqlite3VdbeGoto(v, uniqOk); - sqlite3VdbeJumpHere(v, jmp6); - sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, - pIdx->nKeyCol); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ - sqlite3VdbeLoadString(v, 3, "non-unique entry in index "); - sqlite3VdbeGoto(v, jmp5); - sqlite3VdbeResolveLabel(v, uniqOk); + sqlite3VdbeJumpHere(v, jmp2); + } + if( (pTab->tabFlags & TF_Strict)!=0 + && pCol->eCType!=COLTYPE_ANY + ){ + jmp2 = sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0, + sqlite3StdTypeMap[pCol->eCType-1]); + VdbeCoverage(v); + zErr = sqlite3MPrintf(db, "non-%s value in %s.%s", + sqlite3StdType[pCol->eCType-1], + pTab->zName, pTab->aCol[j].zCnName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + sqlite3VdbeResolveLabel(v, doError); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, jmp2); + } + } + /* Verify CHECK constraints */ + if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ + ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); + if( db->mallocFailed==0 ){ + int addrCkFault = sqlite3VdbeMakeLabel(pParse); + int addrCkOk = sqlite3VdbeMakeLabel(pParse); + char *zErr; + int k; + pParse->iSelfTab = iDataCur + 1; + for(k=pCheck->nExpr-1; k>0; k--){ + sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); + } + sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, + SQLITE_JUMPIFNULL); + sqlite3VdbeResolveLabel(v, addrCkFault); + pParse->iSelfTab = 0; + zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", + pTab->zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + integrityCheckResultRow(v); + sqlite3VdbeResolveLabel(v, addrCkOk); + } + sqlite3ExprListDelete(db, pCheck); + } + if( !isQuick ){ /* Omit the remaining tests for quick_check */ + /* Validate index entries for the current row */ + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + int jmp2, jmp3, jmp4, jmp5; + int ckUniq = sqlite3VdbeMakeLabel(pParse); + if( pPk==pIdx ) continue; + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, + pPrior, r1); + pPrior = pIdx; + sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */ + /* Verify that an index entry exists for the current table row */ + jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, + pIdx->nColumn); VdbeCoverage(v); + sqlite3VdbeLoadString(v, 3, "row "); + sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); + sqlite3VdbeLoadString(v, 4, " missing from index "); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); + jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); + jmp4 = integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, jmp2); + /* For UNIQUE indexes, verify that only one entry exists with the + ** current key. The entry is unique if (1) any column is NULL + ** or (2) the next entry has a different key */ + if( IsUniqueIndex(pIdx) ){ + int uniqOk = sqlite3VdbeMakeLabel(pParse); + int jmp6; + int kk; + for(kk=0; kknKeyCol; kk++){ + int iCol = pIdx->aiColumn[kk]; + assert( iCol!=XN_ROWID && iColnCol ); + if( iCol>=0 && pTab->aCol[iCol].notNull ) continue; + sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); + VdbeCoverage(v); + } + jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); + sqlite3VdbeGoto(v, uniqOk); + sqlite3VdbeJumpHere(v, jmp6); + sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, + pIdx->nKeyCol); VdbeCoverage(v); + sqlite3VdbeLoadString(v, 3, "non-unique entry in index "); + sqlite3VdbeGoto(v, jmp5); + sqlite3VdbeResolveLabel(v, uniqOk); + } + sqlite3VdbeJumpHere(v, jmp4); + sqlite3ResolvePartIdxLabel(pParse, jmp3); } - sqlite3VdbeJumpHere(v, jmp4); - sqlite3ResolvePartIdxLabel(pParse, jmp3); } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); -#ifndef SQLITE_OMIT_BTREECOUNT - sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); - for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - if( pPk==pIdx ) continue; - addr = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); - sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v); - sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); - sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); - sqlite3VdbeLoadString(v, 3, pIdx->zName); - sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7); - sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1); + if( !isQuick ){ + sqlite3VdbeLoadString(v, 2, "wrong # of entries in index "); + for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( pPk==pIdx ) continue; + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3); + addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); + sqlite3VdbeLoadString(v, 4, pIdx->zName); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3); + integrityCheckResultRow(v); + sqlite3VdbeJumpHere(v, addr); + } } -#endif /* SQLITE_OMIT_BTREECOUNT */ - } + } } { static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { { OP_AddImm, 1, 0, 0}, /* 0 */ - { OP_If, 1, 4, 0}, /* 1 */ + { OP_IfNotZero, 1, 4, 0}, /* 1 */ { OP_String8, 0, 3, 0}, /* 2 */ { OP_ResultRow, 3, 1, 0}, /* 3 */ + { OP_Halt, 0, 0, 0}, /* 4 */ + { OP_String8, 0, 3, 0}, /* 5 */ + { OP_Goto, 0, 3, 0}, /* 6 */ }; VdbeOp *aOp; aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); if( aOp ){ - aOp[0].p2 = -mxErr; + aOp[0].p2 = 1-mxErr; aOp[2].p4type = P4_STATIC; aOp[2].p4.z = "ok"; + aOp[5].p4type = P4_STATIC; + aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT); } + sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2); } } break; @@ -114265,7 +132382,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ** encoding that will be used for the main database file if a new file ** is created. If an existing main database file is opened, then the ** default text encoding for the existing database is used. - ** + ** ** In all cases new databases created using the ATTACH command are ** created to use the same default text encoding as the main database. If ** the main database has not been initialized and/or created when ATTACH @@ -114303,14 +132420,12 @@ SQLITE_PRIVATE void sqlite3Pragma( ** will be overwritten when the schema is next loaded. If it does not ** already exists, it will be created to use the new encoding value. */ - if( - !(DbHasProperty(db, 0, DB_SchemaLoaded)) || - DbHasProperty(db, 0, DB_Empty) - ){ + if( (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ - SCHEMA_ENC(db) = ENC(db) = - pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; + u8 enc = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; + SCHEMA_ENC(db) = enc; + sqlite3SetTextEncoding(db, enc); break; } } @@ -114373,6 +132488,7 @@ SQLITE_PRIVATE void sqlite3Pragma( aOp[1].p1 = iDb; aOp[1].p2 = iCookie; aOp[1].p3 = sqlite3Atoi(zRight); + aOp[1].p5 = 1; }else{ /* Read the specified cookie value */ static const VdbeOpList readCookie[] = { @@ -114420,7 +132536,7 @@ SQLITE_PRIVATE void sqlite3Pragma( ** Checkpoint the database. */ case PragTyp_WAL_CHECKPOINT: { - int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED); + int iBt = (pId2->z?iDb:SQLITE_MAX_DB); int eMode = SQLITE_CHECKPOINT_PASSIVE; if( zRight ){ if( sqlite3StrICmp(zRight, "full")==0 ){ @@ -114449,8 +132565,8 @@ SQLITE_PRIVATE void sqlite3Pragma( if( zRight ){ sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight)); } - returnSingleInt(v, - db->xWalCallback==sqlite3WalDefaultHook ? + returnSingleInt(v, + db->xWalCallback==sqlite3WalDefaultHook ? SQLITE_PTR_TO_INT(db->pWalArg) : 0); } break; @@ -114468,6 +132584,119 @@ SQLITE_PRIVATE void sqlite3Pragma( break; } + /* + ** PRAGMA optimize + ** PRAGMA optimize(MASK) + ** PRAGMA schema.optimize + ** PRAGMA schema.optimize(MASK) + ** + ** Attempt to optimize the database. All schemas are optimized in the first + ** two forms, and only the specified schema is optimized in the latter two. + ** + ** The details of optimizations performed by this pragma are expected + ** to change and improve over time. Applications should anticipate that + ** this pragma will perform new optimizations in future releases. + ** + ** The optional argument is a bitmask of optimizations to perform: + ** + ** 0x0001 Debugging mode. Do not actually perform any optimizations + ** but instead return one line of text for each optimization + ** that would have been done. Off by default. + ** + ** 0x0002 Run ANALYZE on tables that might benefit. On by default. + ** See below for additional information. + ** + ** 0x0004 (Not yet implemented) Record usage and performance + ** information from the current session in the + ** database file so that it will be available to "optimize" + ** pragmas run by future database connections. + ** + ** 0x0008 (Not yet implemented) Create indexes that might have + ** been helpful to recent queries + ** + ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all + ** of the optimizations listed above except Debug Mode, including new + ** optimizations that have not yet been invented. If new optimizations are + ** ever added that should be off by default, those off-by-default + ** optimizations will have bitmasks of 0x10000 or larger. + ** + ** DETERMINATION OF WHEN TO RUN ANALYZE + ** + ** In the current implementation, a table is analyzed if only if all of + ** the following are true: + ** + ** (1) MASK bit 0x02 is set. + ** + ** (2) The query planner used sqlite_stat1-style statistics for one or + ** more indexes of the table at some point during the lifetime of + ** the current connection. + ** + ** (3) One or more indexes of the table are currently unanalyzed OR + ** the number of rows in the table has increased by 25 times or more + ** since the last time ANALYZE was run. + ** + ** The rules for when tables are analyzed are likely to change in + ** future releases. + */ + case PragTyp_OPTIMIZE: { + int iDbLast; /* Loop termination point for the schema loop */ + int iTabCur; /* Cursor for a table whose size needs checking */ + HashElem *k; /* Loop over tables of a schema */ + Schema *pSchema; /* The current schema */ + Table *pTab; /* A table in the schema */ + Index *pIdx; /* An index of the table */ + LogEst szThreshold; /* Size threshold above which reanalysis is needd */ + char *zSubSql; /* SQL statement for the OP_SqlExec opcode */ + u32 opMask; /* Mask of operations to perform */ + + if( zRight ){ + opMask = (u32)sqlite3Atoi(zRight); + if( (opMask & 0x02)==0 ) break; + }else{ + opMask = 0xfffe; + } + iTabCur = pParse->nTab++; + for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){ + if( iDb==1 ) continue; + sqlite3CodeVerifySchema(pParse, iDb); + pSchema = db->aDb[iDb].pSchema; + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + + /* If table pTab has not been used in a way that would benefit from + ** having analysis statistics during the current session, then skip it. + ** This also has the effect of skipping virtual tables and views */ + if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue; + + /* Reanalyze if the table is 25 times larger than the last analysis */ + szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 ); + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( !pIdx->hasStat1 ){ + szThreshold = 0; /* Always analyze if any index lacks statistics */ + break; + } + } + if( szThreshold ){ + sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); + sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, + sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold); + VdbeCoverage(v); + } + zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"", + db->aDb[iDb].zDbSName, pTab->zName); + if( opMask & 0x01 ){ + int r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC); + sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1); + }else{ + sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC); + } + } + } + sqlite3VdbeAddOp0(v, OP_Expire); + break; + } + /* ** PRAGMA busy_timeout ** PRAGMA busy_timeout = N @@ -114506,6 +132735,27 @@ SQLITE_PRIVATE void sqlite3Pragma( break; } + /* + ** PRAGMA hard_heap_limit + ** PRAGMA hard_heap_limit = N + ** + ** Invoke sqlite3_hard_heap_limit64() to query or set the hard heap + ** limit. The hard heap limit can be activated or lowered by this + ** pragma, but not raised or deactivated. Only the + ** sqlite3_hard_heap_limit64() C-language API can raise or deactivate + ** the hard heap limit. This allows an application to set a heap limit + ** constraint that cannot be relaxed by an untrusted SQL script. + */ + case PragTyp_HARD_HEAP_LIMIT: { + sqlite3_int64 N; + if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ + sqlite3_int64 iPrior = sqlite3_hard_heap_limit64(-1); + if( N>0 && (iPrior==0 || iPrior>N) ) sqlite3_hard_heap_limit64(N); + } + returnSingleInt(v, sqlite3_hard_heap_limit64(-1)); + break; + } + /* ** PRAGMA threads ** PRAGMA threads = N @@ -114525,6 +132775,25 @@ SQLITE_PRIVATE void sqlite3Pragma( break; } + /* + ** PRAGMA analysis_limit + ** PRAGMA analysis_limit = N + ** + ** Configure the maximum number of rows that ANALYZE will examine + ** in each index that it looks at. Return the new limit. + */ + case PragTyp_ANALYSIS_LIMIT: { + sqlite3_int64 N; + if( zRight + && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK /* IMP: R-40975-20399 */ + && N>=0 + ){ + db->nAnalysisLimit = (int)(N&0x7fffffff); + } + returnSingleInt(v, db->nAnalysisLimit); /* IMP: R-57594-65522 */ + break; + } + #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Report the current state of file logs for all databases @@ -114543,56 +132812,21 @@ SQLITE_PRIVATE void sqlite3Pragma( pBt = db->aDb[i].pBt; if( pBt==0 || sqlite3BtreePager(pBt)==0 ){ zState = "closed"; - }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, + }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0, SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){ zState = azLockName[j]; } sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); - sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2); } break; } #endif -#ifdef SQLITE_HAS_CODEC - case PragTyp_KEY: { - if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - break; - } - case PragTyp_REKEY: { - if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - break; - } - case PragTyp_HEXKEY: { - if( zRight ){ - u8 iByte; - int i; - char zKey[40]; - for(i=0, iByte=0; imPragFlg & PragFlg_NoColumns1) && zRight ){ sqlite3VdbeVerifyNoResultRow(v); @@ -114633,7 +132867,7 @@ struct PragmaVtabCursor { char *azArg[2]; /* Value of the argument and schema */ }; -/* +/* ** Pragma virtual table module xConnect method. */ static int pragmaVtabConnect( @@ -114654,26 +132888,25 @@ static int pragmaVtabConnect( UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); - sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x"); + sqlite3_str_appendall(&acc, "CREATE TABLE x"); for(i=0, j=pPragma->iPragCName; inPragCName; i++, j++){ - sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]); + sqlite3_str_appendf(&acc, "%c\"%s\"", cSep, pragCName[j]); cSep = ','; } if( i==0 ){ - sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName); - cSep = ','; + sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName); i++; } j = 0; if( pPragma->mPragFlg & PragFlg_Result1 ){ - sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN"); + sqlite3_str_appendall(&acc, ",arg HIDDEN"); j++; } if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){ - sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN"); + sqlite3_str_appendall(&acc, ",schema HIDDEN"); j++; } - sqlite3StrAccumAppend(&acc, ")", 1); + sqlite3_str_append(&acc, ")", 1); sqlite3StrAccumFinish(&acc); assert( strlen(zBuf) < sizeof(zBuf)-1 ); rc = sqlite3_declare_vtab(db, zBuf); @@ -114696,7 +132929,7 @@ static int pragmaVtabConnect( return rc; } -/* +/* ** Pragma virtual table module xDisconnect method. */ static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){ @@ -114794,11 +133027,11 @@ static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){ return rc; } -/* +/* ** Pragma virtual table module xFilter method. */ static int pragmaVtabFilter( - sqlite3_vtab_cursor *pVtabCursor, + sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ @@ -114814,20 +133047,24 @@ static int pragmaVtabFilter( pragmaVtabCursorClear(pCsr); j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1; for(i=0; iazArg) ); - pCsr->azArg[j] = sqlite3_mprintf("%s", sqlite3_value_text(argv[i])); - if( pCsr->azArg[j]==0 ){ - return SQLITE_NOMEM; + assert( pCsr->azArg[j]==0 ); + if( zText ){ + pCsr->azArg[j] = sqlite3_mprintf("%s", zText); + if( pCsr->azArg[j]==0 ){ + return SQLITE_NOMEM; + } } } sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]); - sqlite3StrAccumAppendAll(&acc, "PRAGMA "); + sqlite3_str_appendall(&acc, "PRAGMA "); if( pCsr->azArg[1] ){ - sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]); + sqlite3_str_appendf(&acc, "%Q.", pCsr->azArg[1]); } - sqlite3StrAccumAppendAll(&acc, pTab->pName->zName); + sqlite3_str_appendall(&acc, pTab->pName->zName); if( pCsr->azArg[0] ){ - sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]); + sqlite3_str_appendf(&acc, "=%Q", pCsr->azArg[0]); } zSql = sqlite3StrAccumFinish(&acc); if( zSql==0 ) return SQLITE_NOMEM; @@ -114849,11 +133086,11 @@ static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){ } /* The xColumn method simply returns the corresponding column from -** the PRAGMA. +** the PRAGMA. */ static int pragmaVtabColumn( - sqlite3_vtab_cursor *pVtabCursor, - sqlite3_context *ctx, + sqlite3_vtab_cursor *pVtabCursor, + sqlite3_context *ctx, int i ){ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor; @@ -114866,7 +133103,7 @@ static int pragmaVtabColumn( return SQLITE_OK; } -/* +/* ** Pragma virtual table module xRowid method. */ static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){ @@ -114899,7 +133136,8 @@ static const sqlite3_module pragmaVtabModule = { 0, /* xRename - rename the table */ 0, /* xSavepoint */ 0, /* xRelease */ - 0 /* xRollbackTo */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; /* @@ -114946,21 +133184,63 @@ SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName) */ static void corruptSchema( InitData *pData, /* Initialization context */ - const char *zObj, /* Object being parsed at the point of error */ + char **azObj, /* Type and name of object being parsed */ const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; - if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){ + if( db->mallocFailed ){ + pData->rc = SQLITE_NOMEM_BKPT; + }else if( pData->pzErrMsg[0]!=0 ){ + /* A error message has already been generated. Do not overwrite it */ + }else if( pData->mInitFlags & (INITFLAG_AlterMask) ){ + static const char *azAlterType[] = { + "rename", + "drop column", + "add column" + }; + *pData->pzErrMsg = sqlite3MPrintf(db, + "error in %s %s after %s: %s", azObj[0], azObj[1], + azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1], + zExtra + ); + pData->rc = SQLITE_ERROR; + }else if( db->flags & SQLITE_WriteSchema ){ + pData->rc = SQLITE_CORRUPT_BKPT; + }else{ char *z; - if( zObj==0 ) zObj = "?"; + const char *zObj = azObj[1] ? azObj[1] : "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); - if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); - sqlite3DbFree(db, *pData->pzErrMsg); + if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); *pData->pzErrMsg = z; + pData->rc = SQLITE_CORRUPT_BKPT; } - pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT; } +/* +** Check to see if any sibling index (another index on the same table) +** of pIndex has the same root page number, and if it does, return true. +** This would indicate a corrupt schema. +*/ +SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index *pIndex){ + Index *p; + for(p=pIndex->pTable->pIndex; p; p=p->pNext){ + if( p->tnum==pIndex->tnum && p!=pIndex ) return 1; + } + return 0; +} + +/* forward declaration */ +static int sqlite3Prepare( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ + Vdbe *pReprepare, /* VM being reprepared */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +); + + /* ** This is the callback routine for the code that initializes the ** database. See sqlite3Init() below for additional information. @@ -114968,9 +133248,11 @@ static void corruptSchema( ** ** Each callback contains the following information: ** -** argv[0] = name of thing being created -** argv[1] = root page number for table or index. 0 for trigger or view. -** argv[2] = SQL text for the CREATE statement. +** argv[0] = type of object: "table", "index", "trigger", or "view". +** argv[1] = name of thing being created +** argv[2] = associated table if an index or trigger +** argv[3] = root page number for table or index. 0 for trigger or view. +** argv[4] = SQL text for the CREATE statement. ** */ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ @@ -114978,24 +133260,32 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char sqlite3 *db = pData->db; int iDb = pData->iDb; - assert( argc==3 ); + assert( argc==5 ); UNUSED_PARAMETER2(NotUsed, argc); assert( sqlite3_mutex_held(db->mutex) ); - DbClearProperty(db, iDb, DB_Empty); + db->mDbFlags |= DBFLAG_EncodingFixed; + if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ + pData->nInitRow++; if( db->mallocFailed ){ - corruptSchema(pData, argv[0], 0); + corruptSchema(pData, argv, 0); return 1; } assert( iDb>=0 && iDbnDb ); - if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ - if( argv[1]==0 ){ - corruptSchema(pData, argv[0], 0); - }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){ + if( argv[3]==0 ){ + corruptSchema(pData, argv, 0); + }else if( argv[4] + && 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]] + && 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){ /* Call the parser to process a CREATE TABLE, INDEX or VIEW. ** But because db->init.busy is set to 1, no VDBE code is generated ** or executed. All the parser does is build the internal data ** structures that describe the table, index, or view. + ** + ** No other valid SQL statement, other than the variable CREATE statements, + ** can begin with the letters "C" and "R". Thus, it is not possible run + ** any other kind of statement while parsing the schema, even a corrupt + ** schema. */ int rc; u8 saved_iDb = db->init.iDb; @@ -115004,28 +133294,37 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char assert( db->init.busy ); db->init.iDb = iDb; - db->init.newTnum = sqlite3Atoi(argv[1]); + if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0 + || (db->init.newTnum>pData->mxPage && pData->mxPage>0) + ){ + if( sqlite3Config.bExtraSchemaChecks ){ + corruptSchema(pData, argv, "invalid rootpage"); + } + } db->init.orphanTrigger = 0; - TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); + db->init.azInit = (const char**)argv; + pStmt = 0; + TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; - assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 ); + /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ - pData->rc = rc; + if( rc > pData->rc ) pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ - corruptSchema(pData, argv[0], sqlite3_errmsg(db)); + corruptSchema(pData, argv, sqlite3_errmsg(db)); } } } + db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ sqlite3_finalize(pStmt); - }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){ - corruptSchema(pData, argv[0], 0); + }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ + corruptSchema(pData, argv, 0); }else{ /* If the SQL column is blank it means this is an index that ** was created to be the PRIMARY KEY or to fulfill a UNIQUE @@ -115034,16 +133333,18 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char ** to do here is record the root page number for that index. */ Index *pIndex; - pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName); + pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName); if( pIndex==0 ){ - /* This can occur if there exists an index on a TEMP table which - ** has the same name as another index on a permanent index. Since - ** the permanent table is hidden by the TEMP table, we can also - ** safely ignore the index on the permanent table. - */ - /* Do Nothing */; - }else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){ - corruptSchema(pData, argv[0], "invalid rootpage"); + corruptSchema(pData, argv, "orphan index"); + }else + if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0 + || pIndex->tnum<2 + || pIndex->tnum>pData->mxPage + || sqlite3IndexHasDuplicateRootPage(pIndex) + ){ + if( sqlite3Config.bExtraSchemaChecks ){ + corruptSchema(pData, argv, "invalid rootpage"); + } } } return 0; @@ -115057,39 +133358,49 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ -static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ +SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ int rc; int i; #ifndef SQLITE_OMIT_DEPRECATED int size; #endif Db *pDb; - char const *azArg[4]; + char const *azArg[6]; int meta[5]; InitData initData; - const char *zMasterName; + const char *zSchemaTabName; int openedTransaction = 0; + int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed); + assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ); assert( iDb>=0 && iDbnDb ); assert( db->aDb[iDb].pSchema ); assert( sqlite3_mutex_held(db->mutex) ); assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); - /* Construct the in-memory representation schema tables (sqlite_master or - ** sqlite_temp_master) by invoking the parser directly. The appropriate + db->init.busy = 1; + + /* Construct the in-memory representation schema tables (sqlite_schema or + ** sqlite_temp_schema) by invoking the parser directly. The appropriate ** table name will be inserted automatically by the parser so we can just ** use the abbreviation "x" here. The parser will also automatically tag ** the schema table as read-only. */ - azArg[0] = zMasterName = SCHEMA_TABLE(iDb); - azArg[1] = "1"; - azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text," - "rootpage integer,sql text)"; - azArg[3] = 0; + azArg[0] = "table"; + azArg[1] = zSchemaTabName = SCHEMA_TABLE(iDb); + azArg[2] = azArg[1]; + azArg[3] = "1"; + azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text," + "rootpage int,sql text)"; + azArg[5] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; - sqlite3InitCallback(&initData, 3, (char **)azArg, 0); + initData.mInitFlags = mFlags; + initData.nInitRow = 0; + initData.mxPage = 0; + sqlite3InitCallback(&initData, 5, (char **)azArg, 0); + db->mDbFlags &= mask; if( initData.rc ){ rc = initData.rc; goto error_out; @@ -115099,18 +133410,18 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ */ pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ - if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){ - DbSetProperty(db, 1, DB_SchemaLoaded); - } - return SQLITE_OK; + assert( iDb==1 ); + DbSetProperty(db, 1, DB_SchemaLoaded); + rc = SQLITE_OK; + goto error_out; } /* If there is not already a read-only (or read-write) transaction opened - ** on the b-tree database, open one now. If a transaction is opened, it + ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed before this function returns. */ sqlite3BtreeEnter(pDb->pBt); - if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){ - rc = sqlite3BtreeBeginTrans(pDb->pBt, 0); + if( sqlite3BtreeTxnState(pDb->pBt)==SQLITE_TXN_NONE ){ + rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); goto initone_error_out; @@ -115138,6 +133449,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ for(i=0; ipBt, i+1, (u32 *)&meta[i]); } + if( (db->flags & SQLITE_ResetDatabase)!=0 ){ + memset(meta, 0, sizeof(meta)); + } pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1]; /* If opening a non-empty database, check the text encoding. For the @@ -115146,27 +133460,25 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ ** as sqlite3.enc. */ if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ - if( iDb==0 ){ -#ifndef SQLITE_OMIT_UTF16 + if( iDb==0 && (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){ u8 encoding; +#ifndef SQLITE_OMIT_UTF16 /* If opening the main database, set ENC(db). */ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; - ENC(db) = encoding; #else - ENC(db) = SQLITE_UTF8; + encoding = SQLITE_UTF8; #endif + sqlite3SetTextEncoding(db, encoding); }else{ /* If opening an attached database, the encoding much match ENC(db) */ - if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){ + if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); rc = SQLITE_ERROR; goto initone_error_out; } } - }else{ - DbSetProperty(db, iDb, DB_Empty); } pDb->pSchema->enc = ENC(db); @@ -115203,17 +133515,18 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ ** indices that the user might have created. */ if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){ - db->flags &= ~SQLITE_LegacyFileFmt; + db->flags &= ~(u64)SQLITE_LegacyFileFmt; } /* Read the schema information out of the schema tables */ assert( db->init.busy ); + initData.mxPage = sqlite3BtreeLastPage(pDb->pBt); { char *zSql; - zSql = sqlite3MPrintf(db, - "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid", - db->aDb[iDb].zDbSName, zMasterName); + zSql = sqlite3MPrintf(db, + "SELECT*FROM\"%w\".%s ORDER BY rowid", + db->aDb[iDb].zDbSName, zSchemaTabName); #ifndef SQLITE_OMIT_AUTHORIZATION { sqlite3_xauth xAuth; @@ -115233,18 +133546,22 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ } #endif } + assert( pDb == &(db->aDb[iDb]) ); if( db->mallocFailed ){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); - } - if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){ - /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider - ** the schema loaded, even if errors occurred. In this situation the - ** current sqlite3_prepare() operation will fail, but the following one - ** will attempt to compile the supplied statement against whatever subset - ** of the schema was loaded before the error occurred. The primary - ** purpose of this is to allow access to the sqlite_master table - ** even when its contents have been corrupted. + pDb = &db->aDb[iDb]; + }else + if( rc==SQLITE_OK || ((db->flags&SQLITE_NoSchemaError) && rc!=SQLITE_NOMEM)){ + /* Hack: If the SQLITE_NoSchemaError flag is set, then consider + ** the schema loaded, even if errors (other than OOM) occurred. In + ** this situation the current sqlite3_prepare() operation will fail, + ** but the following one will attempt to compile the supplied statement + ** against whatever subset of the schema was loaded before the error + ** occurred. + ** + ** The primary purpose of this is to allow access to the sqlite_schema + ** table even when its contents have been corrupted. */ DbSetProperty(db, iDb, DB_SchemaLoaded); rc = SQLITE_OK; @@ -115261,9 +133578,13 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ sqlite3BtreeLeave(pDb->pBt); error_out: - if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ - sqlite3OomFault(db); + if( rc ){ + if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomFault(db); + } + sqlite3ResetOneSchema(db, iDb); } + db->init.busy = 0; return rc; } @@ -115274,47 +133595,34 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ ** error occurs, write an error message into *pzErrMsg. ** ** After a database is initialized, the DB_SchemaLoaded bit is set -** bit is set in the flags field of the Db structure. If the database -** file was of zero-length, then the DB_Empty flag is also set. +** bit is set in the flags field of the Db structure. */ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){ int i, rc; - int commit_internal = !(db->flags&SQLITE_InternChanges); - + int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange); + assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); - rc = SQLITE_OK; - db->init.busy = 1; ENC(db) = SCHEMA_ENC(db); - for(i=0; rc==SQLITE_OK && inDb; i++){ - if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue; - rc = sqlite3InitOne(db, i, pzErrMsg); - if( rc ){ - sqlite3ResetOneSchema(db, i); - } + assert( db->nDb>0 ); + /* Do the main schema first */ + if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, 0, pzErrMsg, 0); + if( rc ) return rc; } - - /* Once all the other databases have been initialized, load the schema - ** for the TEMP database. This is loaded last, as the TEMP database - ** schema may contain references to objects in other databases. - */ -#ifndef SQLITE_OMIT_TEMPDB - assert( db->nDb>1 ); - if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){ - rc = sqlite3InitOne(db, 1, pzErrMsg); - if( rc ){ - sqlite3ResetOneSchema(db, 1); + /* All other schemas after the main schema. The "temp" schema must be last */ + for(i=db->nDb-1; i>0; i--){ + assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) ); + if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ + rc = sqlite3InitOne(db, i, pzErrMsg, 0); + if( rc ) return rc; } } -#endif - - db->init.busy = 0; - if( rc==SQLITE_OK && commit_internal ){ + if( commit_internal ){ sqlite3CommitInternalChanges(db); } - - return rc; + return SQLITE_OK; } /* @@ -115327,10 +133635,12 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){ assert( sqlite3_mutex_held(db->mutex) ); if( !db->init.busy ){ rc = sqlite3Init(db, &pParse->zErrMsg); - } - if( rc!=SQLITE_OK ){ - pParse->rc = rc; - pParse->nErr++; + if( rc!=SQLITE_OK ){ + pParse->rc = rc; + pParse->nErr++; + }else if( db->noSharedCache ){ + db->mDbFlags |= DBFLAG_SchemaKnownOk; + } } return rc; } @@ -115355,18 +133665,19 @@ static void schemaIsValid(Parse *pParse){ if( pBt==0 ) continue; /* If there is not already a read-only (or read-write) transaction opened - ** on the b-tree database, open one now. If a transaction is opened, it + ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ - if( !sqlite3BtreeIsInReadTrans(pBt) ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){ + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); + pParse->rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ) return; openedTransaction = 1; } - /* Read the schema cookie from the database. If it does not match the + /* Read the schema cookie from the database. If it does not match the ** value stored as part of the in-memory schema representation, ** set Parse.rc to SQLITE_SCHEMA. */ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); @@ -115391,21 +133702,23 @@ static void schemaIsValid(Parse *pParse){ ** attached database is returned. */ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ - int i = -1000000; + int i = -32768; - /* If pSchema is NULL, then return -1000000. This happens when code in + /* If pSchema is NULL, then return -32768. This happens when code in ** expr.c is trying to resolve a reference to a transient table (i.e. one - ** created by a sub-select). In this case the return value of this + ** created by a sub-select). In this case the return value of this ** function should never be used. ** - ** We return -1000000 instead of the more usual -1 simply because using - ** -1000000 as the incorrect index into db->aDb[] is much + ** We return -32768 instead of the more usual -1 simply because using + ** -32768 as the incorrect index into db->aDb[] is much ** more likely to cause a segfault than -1 (of course there are assert() - ** statements too, but it never hurts to play the odds). + ** statements too, but it never hurts to play the odds) and + ** -32768 will still fit into a 16-bit signed integer. */ assert( sqlite3_mutex_held(db->mutex) ); if( pSchema ){ - for(i=0; ALWAYS(inDb); i++){ + for(i=0; 1; i++){ + assert( inDb ); if( db->aDb[i].pSchema==pSchema ){ break; } @@ -115418,17 +133731,99 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ /* ** Free all memory allocations in the pParse object */ -SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){ - if( pParse ){ - sqlite3 *db = pParse->db; - sqlite3DbFree(db, pParse->aLabel); +SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){ + sqlite3 *db = pParse->db; + assert( db!=0 ); + assert( db->pParse==pParse ); + assert( pParse->nested==0 ); +#ifndef SQLITE_OMIT_SHARED_CACHE + sqlite3DbFree(db, pParse->aTableLock); +#endif + while( pParse->pCleanup ){ + ParseCleanup *pCleanup = pParse->pCleanup; + pParse->pCleanup = pCleanup->pNext; + pCleanup->xCleanup(db, pCleanup->pPtr); + sqlite3DbFreeNN(db, pCleanup); + } + sqlite3DbFree(db, pParse->aLabel); + if( pParse->pConstExpr ){ sqlite3ExprListDelete(db, pParse->pConstExpr); - if( db ){ - assert( db->lookaside.bDisable >= pParse->disableLookaside ); - db->lookaside.bDisable -= pParse->disableLookaside; - } - pParse->disableLookaside = 0; } + assert( db->lookaside.bDisable >= pParse->disableLookaside ); + db->lookaside.bDisable -= pParse->disableLookaside; + db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; + assert( pParse->db->pParse==pParse ); + db->pParse = pParse->pOuterParse; + pParse->db = 0; + pParse->disableLookaside = 0; +} + +/* +** Add a new cleanup operation to a Parser. The cleanup should happen when +** the parser object is destroyed. But, beware: the cleanup might happen +** immediately. +** +** Use this mechanism for uncommon cleanups. There is a higher setup +** cost for this mechansim (an extra malloc), so it should not be used +** for common cleanups that happen on most calls. But for less +** common cleanups, we save a single NULL-pointer comparison in +** sqlite3ParseObjectReset(), which reduces the total CPU cycle count. +** +** If a memory allocation error occurs, then the cleanup happens immediately. +** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the +** pParse->earlyCleanup flag is set in that case. Calling code show verify +** that test cases exist for which this happens, to guard against possible +** use-after-free errors following an OOM. The preferred way to do this is +** to immediately follow the call to this routine with: +** +** testcase( pParse->earlyCleanup ); +** +** This routine returns a copy of its pPtr input (the third parameter) +** except if an early cleanup occurs, in which case it returns NULL. So +** another way to check for early cleanup is to check the return value. +** Or, stop using the pPtr parameter with this call and use only its +** return value thereafter. Something like this: +** +** pObj = sqlite3ParserAddCleanup(pParse, destructor, pObj); +*/ +SQLITE_PRIVATE void *sqlite3ParserAddCleanup( + Parse *pParse, /* Destroy when this Parser finishes */ + void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */ + void *pPtr /* Pointer to object to be cleaned up */ +){ + ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup)); + if( pCleanup ){ + pCleanup->pNext = pParse->pCleanup; + pParse->pCleanup = pCleanup; + pCleanup->pPtr = pPtr; + pCleanup->xCleanup = xCleanup; + }else{ + xCleanup(pParse->db, pPtr); + pPtr = 0; +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) + pParse->earlyCleanup = 1; +#endif + } + return pPtr; +} + +/* +** Turn bulk memory into a valid Parse object and link that Parse object +** into database connection db. +** +** Call sqlite3ParseObjectReset() to undo this operation. +** +** Caution: Do not confuse this routine with sqlite3ParseObjectInit() which +** is generated by Lemon. +*/ +SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){ + memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ); + memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); + assert( db->pParse!=pParse ); + pParse->pOuterParse = db->pParse; + db->pParse = pParse; + pParse->db = db; + if( db->mallocFailed ) sqlite3ErrorMsg(pParse, "out of memory"); } /* @@ -115438,23 +133833,35 @@ static int sqlite3Prepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ - char *zErrMsg = 0; /* Error message */ int rc = SQLITE_OK; /* Result code */ int i; /* Loop counter */ Parse sParse; /* Parsing context */ - memset(&sParse, 0, PARSE_HDR_SZ); + /* sqlite3ParseObjectInit(&sParse, db); // inlined for performance */ + memset(PARSE_HDR(&sParse), 0, PARSE_HDR_SZ); memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); + sParse.pOuterParse = db->pParse; + db->pParse = &sParse; + sParse.db = db; sParse.pReprepare = pReprepare; assert( ppStmt && *ppStmt==0 ); - /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ + if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory"); assert( sqlite3_mutex_held(db->mutex) ); + /* For a long-term use prepared statement avoid the use of + ** lookaside memory. + */ + if( prepFlags & SQLITE_PREPARE_PERSISTENT ){ + sParse.disableLookaside++; + DisableLookaside; + } + sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0; + /* Check to verify that it is possible to get a read lock on all ** database schemas. The inability to get a read lock indicates that ** some other database connection is holding a write-lock, which in @@ -115470,31 +133877,32 @@ static int sqlite3Prepare( ** This thread is currently holding mutexes on all Btrees (because ** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it ** is not possible for another thread to start a new schema change - ** while this routine is running. Hence, we do not need to hold - ** locks on the schema, we just need to make sure nobody else is + ** while this routine is running. Hence, we do not need to hold + ** locks on the schema, we just need to make sure nobody else is ** holding them. ** ** Note that setting READ_UNCOMMITTED overrides most lock detection, ** but it does *not* override schema lock detection, so this all still ** works even if READ_UNCOMMITTED is set. */ - for(i=0; inDb; i++) { - Btree *pBt = db->aDb[i].pBt; - if( pBt ){ - assert( sqlite3BtreeHoldsMutex(pBt) ); - rc = sqlite3BtreeSchemaLocked(pBt); - if( rc ){ - const char *zDb = db->aDb[i].zDbSName; - sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); - testcase( db->flags & SQLITE_ReadUncommitted ); - goto end_prepare; + if( !db->noSharedCache ){ + for(i=0; inDb; i++) { + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + assert( sqlite3BtreeHoldsMutex(pBt) ); + rc = sqlite3BtreeSchemaLocked(pBt); + if( rc ){ + const char *zDb = db->aDb[i].zDbSName; + sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb); + testcase( db->flags & SQLITE_ReadUncommit ); + goto end_prepare; + } } } } sqlite3VtabUnlockList(db); - sParse.db = db; if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -115507,69 +133915,50 @@ static int sqlite3Prepare( } zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); if( zSqlCopy ){ - sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); + sqlite3RunParser(&sParse, zSqlCopy); sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; sqlite3DbFree(db, zSqlCopy); }else{ sParse.zTail = &zSql[nBytes]; } }else{ - sqlite3RunParser(&sParse, zSql, &zErrMsg); + sqlite3RunParser(&sParse, zSql); } assert( 0==sParse.nQueryLoop ); - if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; - if( sParse.checkSchema ){ - schemaIsValid(&sParse); - } - if( db->mallocFailed ){ - sParse.rc = SQLITE_NOMEM_BKPT; - } if( pzTail ){ *pzTail = sParse.zTail; } - rc = sParse.rc; - -#ifndef SQLITE_OMIT_EXPLAIN - if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ - static const char * const azColName[] = { - "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", - "selectid", "order", "from", "detail" - }; - int iFirst, mx; - if( sParse.explain==2 ){ - sqlite3VdbeSetNumCols(sParse.pVdbe, 4); - iFirst = 8; - mx = 12; - }else{ - sqlite3VdbeSetNumCols(sParse.pVdbe, 8); - iFirst = 0; - mx = 8; - } - for(i=iFirst; iinit.busy==0 ){ - Vdbe *pVdbe = sParse.pVdbe; - sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag); + sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags); } - if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ - sqlite3VdbeFinalize(sParse.pVdbe); - assert(!(*ppStmt)); + if( db->mallocFailed ){ + sParse.rc = SQLITE_NOMEM_BKPT; + sParse.checkSchema = 0; + } + if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){ + if( sParse.checkSchema && db->init.busy==0 ){ + schemaIsValid(&sParse); + } + if( sParse.pVdbe ){ + sqlite3VdbeFinalize(sParse.pVdbe); + } + assert( 0==(*ppStmt) ); + rc = sParse.rc; + if( sParse.zErrMsg ){ + sqlite3ErrorWithMsg(db, rc, "%s", sParse.zErrMsg); + sqlite3DbFree(db, sParse.zErrMsg); + }else{ + sqlite3Error(db, rc); + } }else{ + assert( sParse.zErrMsg==0 ); *ppStmt = (sqlite3_stmt*)sParse.pVdbe; + rc = SQLITE_OK; + sqlite3ErrorClear(db); } - if( zErrMsg ){ - sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg); - sqlite3DbFree(db, zErrMsg); - }else{ - sqlite3Error(db, rc); - } /* Delete any TriggerPrg structures allocated while parsing this statement. */ while( sParse.pTriggerPrg ){ @@ -115580,21 +133969,20 @@ static int sqlite3Prepare( end_prepare: - sqlite3ParserReset(&sParse); - rc = sqlite3ApiExit(db, rc); - assert( (rc&db->errMask)==rc ); + sqlite3ParseObjectReset(&sParse); return rc; } static int sqlite3LockAndPrepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; + int cnt = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( ppStmt==0 ) return SQLITE_MISUSE_BKPT; @@ -115605,23 +133993,30 @@ static int sqlite3LockAndPrepare( } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); - rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); - if( rc==SQLITE_SCHEMA ){ - sqlite3_finalize(*ppStmt); - rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); - } + do{ + /* Make multiple attempts to compile the SQL, until it either succeeds + ** or encounters a permanent error. A schema problem after one schema + ** reset is considered a permanent error. */ + rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); + assert( rc==SQLITE_OK || *ppStmt==0 ); + if( rc==SQLITE_OK || db->mallocFailed ) break; + }while( rc==SQLITE_ERROR_RETRY + || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); sqlite3BtreeLeaveAll(db); + rc = sqlite3ApiExit(db, rc); + assert( (rc&db->errMask)==rc ); + db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); - assert( rc==SQLITE_OK || *ppStmt==0 ); return rc; } + /* ** Rerun the compilation of a statement after a schema change. ** ** If the statement is successfully recompiled, return SQLITE_OK. Otherwise, ** if the statement cannot be recompiled because another connection has -** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error +** locked the sqlite3_schema table, return SQLITE_LOCKED. If any other error ** occurs, return SQLITE_SCHEMA. */ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ @@ -115629,13 +134024,15 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){ sqlite3_stmt *pNew; const char *zSql; sqlite3 *db; + u8 prepFlags; assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); zSql = sqlite3_sql((sqlite3_stmt *)p); assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */ db = sqlite3VdbeDb(p); assert( sqlite3_mutex_held(db->mutex) ); - rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0); + prepFlags = sqlite3VdbePrepareFlags(p); + rc = sqlite3LockAndPrepare(db, zSql, -1, prepFlags, p, &pNew, 0); if( rc ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); @@ -115681,8 +134078,36 @@ SQLITE_API int sqlite3_prepare_v2( const char **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail); - assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + /* EVIDENCE-OF: R-37923-12173 The sqlite3_prepare_v2() interface works + ** exactly the same as sqlite3_prepare_v3() with a zero prepFlags + ** parameter. + ** + ** Proof in that the 5th parameter to sqlite3LockAndPrepare is 0 */ + rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0, + ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); + return rc; +} +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle. */ + const char *zSql, /* UTF-8 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const char **pzTail /* OUT: End of parsed string */ +){ + int rc; + /* EVIDENCE-OF: R-56861-42673 sqlite3_prepare_v3() differs from + ** sqlite3_prepare_v2() only in having the extra prepFlags parameter, + ** which is a bit array consisting of zero or more of the + ** SQLITE_PREPARE_* flags. + ** + ** Proof by comparison to the implementation of sqlite3_prepare_v2() + ** directly above. */ + rc = sqlite3LockAndPrepare(db,zSql,nBytes, + SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), + 0,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); return rc; } @@ -115692,10 +134117,10 @@ SQLITE_API int sqlite3_prepare_v2( ** Compile the UTF-16 encoded SQL statement zSql into a statement handle. */ static int sqlite3Prepare16( - sqlite3 *db, /* Database handle. */ + sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ - int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */ + u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ @@ -115723,7 +134148,7 @@ static int sqlite3Prepare16( sqlite3_mutex_enter(db->mutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE); if( zSql8 ){ - rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8); + rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8); } if( zTail8 && pzTail ){ @@ -115735,7 +134160,7 @@ static int sqlite3Prepare16( int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8)); *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed); } - sqlite3DbFree(db, zSql8); + sqlite3DbFree(db, zSql8); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; @@ -115750,7 +134175,7 @@ static int sqlite3Prepare16( ** occurs. */ SQLITE_API int sqlite3_prepare16( - sqlite3 *db, /* Database handle. */ + sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ @@ -115762,14 +134187,29 @@ SQLITE_API int sqlite3_prepare16( return rc; } SQLITE_API int sqlite3_prepare16_v2( - sqlite3 *db, /* Database handle. */ + sqlite3 *db, /* Database handle. */ + const void *zSql, /* UTF-16 encoded SQL statement. */ + int nBytes, /* Length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ + const void **pzTail /* OUT: End of parsed string */ +){ + int rc; + rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail); + assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ + return rc; +} +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle. */ const void *zSql, /* UTF-16 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const void **pzTail /* OUT: End of parsed string */ ){ int rc; - rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail); + rc = sqlite3Prepare16(db,zSql,nBytes, + SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK), + ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } @@ -115794,21 +134234,6 @@ SQLITE_API int sqlite3_prepare16_v2( */ /* #include "sqliteInt.h" */ -/* -** Trace output macros -*/ -#if SELECTTRACE_ENABLED -/***/ int sqlite3SelectTrace = 0; -# define SELECTTRACE(K,P,S,X) \ - if(sqlite3SelectTrace&(K)) \ - sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\ - (S)->zSelName,(S)),\ - sqlite3DebugPrintf X -#else -# define SELECTTRACE(K,P,S,X) -#endif - - /* ** An instance of the following object is used to record information about ** how to process the DISTINCT keyword, to simplify passing that information @@ -115825,6 +134250,20 @@ struct DistinctCtx { /* ** An instance of the following object is used to record information about ** the ORDER BY (or GROUP BY) clause of query is being coded. +** +** The aDefer[] array is used by the sorter-references optimization. For +** example, assuming there is no index that can be used for the ORDER BY, +** for the query: +** +** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10; +** +** it may be more efficient to add just the "a" values to the sorter, and +** retrieve the associated "bigblob" values directly from table t1 as the +** 10 smallest "a" values are extracted from the sorter. +** +** When the sorter-reference optimization is used, there is one entry in the +** aDefer[] array for each database table that may be read as values are +** extracted from the sorter. */ typedef struct SortCtx SortCtx; struct SortCtx { @@ -115835,14 +134274,26 @@ struct SortCtx { int labelBkOut; /* Start label for the block-output subroutine */ int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ + int labelOBLopt; /* Jump here when sorter is full */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ - u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + u8 nDefer; /* Number of valid entries in aDefer[] */ + struct DeferredCsr { + Table *pTab; /* Table definition */ + int iCsr; /* Cursor number for table */ + int nKey; /* Number of PK columns for table pTab (>=1) */ + } aDefer[4]; +#endif + struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure -** itself only if bFree is true. +** itself depending on the value of bFree +** +** If bFree==1, call sqlite3DbFree() on the p object. +** If bFree==0, Leave the first Select object unfreed */ static void clearSelect(sqlite3 *db, Select *p, int bFree){ while( p ){ @@ -115854,9 +134305,17 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ sqlite3ExprDelete(db, p->pHaving); sqlite3ExprListDelete(db, p->pOrderBy); sqlite3ExprDelete(db, p->pLimit); - sqlite3ExprDelete(db, p->pOffset); - if( p->pWith ) sqlite3WithDelete(db, p->pWith); - if( bFree ) sqlite3DbFree(db, p); + if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){ + sqlite3WindowListDelete(db, p->pWinDefn); + } + while( p->pWin ){ + assert( p->pWin->ppThis==&p->pWin ); + sqlite3WindowUnlinkFromSelect(p->pWin); + } +#endif + if( bFree ) sqlite3DbFreeNN(db, p); p = pPrior; bFree = 1; } @@ -115868,6 +134327,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){ pDest->eDest = (u8)eDest; pDest->iSDParm = iParm; + pDest->iSDParm2 = 0; pDest->zAffSdst = 0; pDest->iSdst = 0; pDest->nSdst = 0; @@ -115887,32 +134347,29 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ u32 selFlags, /* Flag parameters, such as SF_Distinct */ - Expr *pLimit, /* LIMIT value. NULL means not used */ - Expr *pOffset /* OFFSET value. NULL means no offset */ + Expr *pLimit /* LIMIT value. NULL means not used */ ){ - Select *pNew; + Select *pNew, *pAllocated; Select standin; - sqlite3 *db = pParse->db; - pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) ); + pAllocated = pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) ); if( pNew==0 ){ - assert( db->mallocFailed ); + assert( pParse->db->mallocFailed ); pNew = &standin; } if( pEList==0 ){ - pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0)); + pEList = sqlite3ExprListAppend(pParse, 0, + sqlite3Expr(pParse->db,TK_ASTERISK,0)); } pNew->pEList = pEList; pNew->op = TK_SELECT; pNew->selFlags = selFlags; pNew->iLimit = 0; pNew->iOffset = 0; -#if SELECTTRACE_ENABLED - pNew->zSelName[0] = 0; -#endif + pNew->selId = ++pParse->nSelect; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; - if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc)); + if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc)); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; @@ -115921,36 +134378,26 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->pPrior = 0; pNew->pNext = 0; pNew->pLimit = pLimit; - pNew->pOffset = pOffset; pNew->pWith = 0; - assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 ); - if( db->mallocFailed ) { - clearSelect(db, pNew, pNew!=&standin); - pNew = 0; +#ifndef SQLITE_OMIT_WINDOWFUNC + pNew->pWin = 0; + pNew->pWinDefn = 0; +#endif + if( pParse->db->mallocFailed ) { + clearSelect(pParse->db, pNew, pNew!=&standin); + pAllocated = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); } - assert( pNew!=&standin ); - return pNew; + return pAllocated; } -#if SELECTTRACE_ENABLED -/* -** Set the name of a Select object -*/ -SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){ - if( p && zName ){ - sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName); - } -} -#endif - /* ** Delete the given Select structure and all of its substructures. */ SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ - if( p ) clearSelect(db, p, 1); + if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } /* @@ -116004,7 +134451,7 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p for(i=0; i<3 && apAll[i]; i++){ p = apAll[i]; for(j=0; jn==aKeyword[j].nChar + if( p->n==aKeyword[j].nChar && sqlite3StrNICmp((char*)p->z, &zKeyText[aKeyword[j].i], p->n)==0 ){ jointype |= aKeyword[j].code; break; @@ -116026,9 +134473,9 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p sqlite3ErrorMsg(pParse, "unknown or unsupported join type: " "%T %T%s%T", pA, pB, zSp, pC); jointype = JT_INNER; - }else if( (jointype & JT_OUTER)!=0 + }else if( (jointype & JT_OUTER)!=0 && (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){ - sqlite3ErrorMsg(pParse, + sqlite3ErrorMsg(pParse, "RIGHT and FULL OUTER JOINs are not currently supported"); jointype = JT_INNER; } @@ -116039,17 +134486,19 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p ** Return the index of a column in a table. Return -1 if the column ** is not contained in the table. */ -static int columnIndex(Table *pTab, const char *zCol){ +SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){ int i; - for(i=0; inCol; i++){ - if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i; + u8 h = sqlite3StrIHash(zCol); + Column *pCol; + for(pCol=pTab->aCol, i=0; inCol; pCol++, i++){ + if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i; } return -1; } /* ** Search the first N tables in pSrc, from left to right, looking for a -** table that has a column named zCol. +** table that has a column named zCol. ** ** When found, set *piTab and *piCol to the table index and column index ** of the matching column and return TRUE. @@ -116061,15 +134510,18 @@ static int tableAndColumnIndex( int N, /* Number of tables in pSrc->a[] to search */ const char *zCol, /* Name of the column we are looking for */ int *piTab, /* Write index of pSrc->a[] here */ - int *piCol /* Write index of pSrc->a[*piTab].pTab->aCol[] here */ + int *piCol, /* Write index of pSrc->a[*piTab].pTab->aCol[] here */ + int bIgnoreHidden /* True to ignore hidden columns */ ){ int i; /* For looping over tables in pSrc */ int iCol; /* Index of column matching zCol */ assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ for(i=0; ia[i].pTab, zCol); - if( iCol>=0 ){ + iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol); + if( iCol>=0 + && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) + ){ if( piTab ){ *piTab = i; *piCol = iCol; @@ -116087,7 +134539,7 @@ static int tableAndColumnIndex( ** ** (tab1.col1 = tab2.col2) ** -** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the +** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the ** (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is ** column iColRight of tab2. */ @@ -116115,18 +134567,21 @@ static void addWhereTerm( pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight); pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2); + assert( pE2!=0 || pEq==0 ); /* Due to db->mallocFailed test + ** in sqlite3DbMallocRawNN() called from + ** sqlite3PExpr(). */ if( pEq && isOuterJoin ){ ExprSetProperty(pEq, EP_FromJoin); assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(pEq, EP_NoReduce); - pEq->iRightJoinTable = (i16)pE2->iTable; + pEq->w.iRightJoinTable = pE2->iTable; } - *ppWhere = sqlite3ExprAnd(db, *ppWhere, pEq); + *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq); } /* ** Set the EP_FromJoin property on all terms of the given expression. -** And set the Expr.iRightJoinTable to iTable for every term in the +** And set the Expr.w.iRightJoinTable to iTable for every term in the ** expression. ** ** The EP_FromJoin property is used on terms of an expression to tell @@ -116136,8 +134591,8 @@ static void addWhereTerm( ** WHERE clause during join processing but we need to remember that they ** originated in the ON or USING clause. ** -** The Expr.iRightJoinTable tells the WHERE clause processing that the -** expression depends on table iRightJoinTable even if that table is not +** The Expr.w.iRightJoinTable tells the WHERE clause processing that the +** expression depends on table w.iRightJoinTable even if that table is not ** explicitly mentioned in the expression. That information is needed ** for cases like this: ** @@ -116150,21 +134605,53 @@ static void addWhereTerm( ** after the t1 loop and rows with t1.x!=5 will never appear in ** the output, which is incorrect. */ -static void setJoinExpr(Expr *p, int iTable){ +SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr *p, int iTable){ while( p ){ ExprSetProperty(p, EP_FromJoin); assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); ExprSetVVAProperty(p, EP_NoReduce); - p->iRightJoinTable = (i16)iTable; - if( p->op==TK_FUNCTION && p->x.pList ){ - int i; - for(i=0; ix.pList->nExpr; i++){ - setJoinExpr(p->x.pList->a[i].pExpr, iTable); + p->w.iRightJoinTable = iTable; + if( p->op==TK_FUNCTION ){ + assert( ExprUseXList(p) ); + if( p->x.pList ){ + int i; + for(i=0; ix.pList->nExpr; i++){ + sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable); + } } } - setJoinExpr(p->pLeft, iTable); + sqlite3SetJoinExpr(p->pLeft, iTable); p = p->pRight; - } + } +} + +/* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every +** term that is marked with EP_FromJoin and w.iRightJoinTable==iTable into +** an ordinary term that omits the EP_FromJoin mark. +** +** This happens when a LEFT JOIN is simplified into an ordinary JOIN. +*/ +static void unsetJoinExpr(Expr *p, int iTable){ + while( p ){ + if( ExprHasProperty(p, EP_FromJoin) + && (iTable<0 || p->w.iRightJoinTable==iTable) ){ + ExprClearProperty(p, EP_FromJoin); + } + if( p->op==TK_COLUMN && p->iTable==iTable ){ + ExprClearProperty(p, EP_CanBeNull); + } + if( p->op==TK_FUNCTION ){ + assert( ExprUseXList(p) ); + if( p->x.pList ){ + int i; + for(i=0; ix.pList->nExpr; i++){ + unsetJoinExpr(p->x.pList->a[i].pExpr, iTable); + } + } + } + unsetJoinExpr(p->pLeft, iTable); + p = p->pRight; + } } /* @@ -116184,18 +134671,17 @@ static void setJoinExpr(Expr *p, int iTable){ static int sqliteProcessJoin(Parse *pParse, Select *p){ SrcList *pSrc; /* All tables in the FROM clause */ int i, j; /* Loop counters */ - struct SrcList_item *pLeft; /* Left table being joined */ - struct SrcList_item *pRight; /* Right table being joined */ + SrcItem *pLeft; /* Left table being joined */ + SrcItem *pRight; /* Right table being joined */ pSrc = p->pSrc; pLeft = &pSrc->a[0]; pRight = &pLeft[1]; for(i=0; inSrc-1; i++, pRight++, pLeft++){ - Table *pLeftTab = pLeft->pTab; Table *pRightTab = pRight->pTab; int isOuter; - if( NEVER(pLeftTab==0 || pRightTab==0) ) continue; + if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; isOuter = (pRight->fg.jointype & JT_OUTER)!=0; /* When the NATURAL keyword is present, add WHERE clause terms for @@ -116212,10 +134698,11 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ int iLeft; /* Matching left table */ int iLeftCol; /* Matching column in the left table */ - zName = pRightTab->aCol[j].zName; - if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){ + if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue; + zName = pRightTab->aCol[j].zCnName; + if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){ addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j, - isOuter, &p->pWhere); + isOuter, &p->pWhere); } } } @@ -116232,13 +134719,13 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ ** an AND operator. */ if( pRight->pOn ){ - if( isOuter ) setJoinExpr(pRight->pOn, pRight->iCursor); - p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn); + if( isOuter ) sqlite3SetJoinExpr(pRight->pOn, pRight->iCursor); + p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn); pRight->pOn = 0; } /* Create extra terms on the WHERE clause for each column named - ** in the USING clause. Example: If the two tables to be joined are + ** in the USING clause. Example: If the two tables to be joined are ** A and B and the USING clause names X, Y, and Z, then add this ** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z ** Report an error if any column mentioned in the USING clause is @@ -116253,9 +134740,9 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ int iRightCol; /* Column number of matching column on the right */ zName = pList->a[j].zName; - iRightCol = columnIndex(pRightTab, zName); + iRightCol = sqlite3ColumnIndex(pRightTab, zName); if( iRightCol<0 - || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) + || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0) ){ sqlite3ErrorMsg(pParse, "cannot join using column %s - column " "not present in both tables", zName); @@ -116269,13 +134756,61 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ return 0; } -/* Forward reference */ -static KeyInfo *keyInfoFromExprList( - Parse *pParse, /* Parsing context */ - ExprList *pList, /* Form the KeyInfo object from this ExprList */ - int iStart, /* Begin with this column of pList */ - int nExtra /* Add this many extra columns to the end */ -); +/* +** An instance of this object holds information (beyond pParse and pSelect) +** needed to load the next result row that is to be added to the sorter. +*/ +typedef struct RowLoadInfo RowLoadInfo; +struct RowLoadInfo { + int regResult; /* Store results in array of registers here */ + u8 ecelFlags; /* Flag argument to ExprCodeExprList() */ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + ExprList *pExtra; /* Extra columns needed by sorter refs */ + int regExtraResult; /* Where to load the extra columns */ +#endif +}; + +/* +** This routine does the work of loading query data into an array of +** registers so that it can be added to the sorter. +*/ +static void innerLoopLoadRow( + Parse *pParse, /* Statement under construction */ + Select *pSelect, /* The query being coded */ + RowLoadInfo *pInfo /* Info needed to complete the row load */ +){ + sqlite3ExprCodeExprList(pParse, pSelect->pEList, pInfo->regResult, + 0, pInfo->ecelFlags); +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( pInfo->pExtra ){ + sqlite3ExprCodeExprList(pParse, pInfo->pExtra, pInfo->regExtraResult, 0, 0); + sqlite3ExprListDelete(pParse->db, pInfo->pExtra); + } +#endif +} + +/* +** Code the OP_MakeRecord instruction that generates the entry to be +** added into the sorter. +** +** Return the register in which the result is stored. +*/ +static int makeSorterRecord( + Parse *pParse, + SortCtx *pSort, + Select *pSelect, + int regBase, + int nBase +){ + int nOBSat = pSort->nOBSat; + Vdbe *v = pParse->pVdbe; + int regOut = ++pParse->nMem; + if( pSort->pDeferredRowLoad ){ + innerLoopLoadRow(pParse, pSelect, pSort->pDeferredRowLoad); + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regOut); + return regOut; +} /* ** Generate code that will push the record in registers regData @@ -116287,7 +134822,7 @@ static void pushOntoSorter( Select *pSelect, /* The whole SELECT statement */ int regData, /* First register holding data to be sorted */ int regOrigData, /* First register holding data before packing */ - int nData, /* Number of elements in the data array */ + int nData, /* Number of elements in the regData data array */ int nPrefixReg /* No. of reg prior to regData available for use */ ){ Vdbe *v = pParse->pVdbe; /* Stmt under construction */ @@ -116295,23 +134830,39 @@ static void pushOntoSorter( int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ int regBase; /* Regs for sorter record */ - int regRecord = ++pParse->nMem; /* Assembled sorter record */ + int regRecord = 0; /* Assembled sorter record */ int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ int op; /* Opcode to add sorter record to sorter */ int iLimit; /* LIMIT counter */ + int iSkip = 0; /* End of the sorter insert loop */ assert( bSeq==0 || bSeq==1 ); + + /* Three cases: + ** (1) The data to be sorted has already been packed into a Record + ** by a prior OP_MakeRecord. In this case nData==1 and regData + ** will be completely unrelated to regOrigData. + ** (2) All output columns are included in the sort record. In that + ** case regData==regOrigData. + ** (3) Some output columns are omitted from the sort record due to + ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the + ** SQLITE_ECEL_OMITREF optimization, or due to the + ** SortCtx.pDeferredRowLoad optimiation. In any of these cases + ** regOrigData is 0 to prevent this routine from trying to copy + ** values that might not yet exist. + */ assert( nData==1 || regData==regOrigData || regOrigData==0 ); + if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); - regBase = regData - nExpr - bSeq; + regBase = regData - nPrefixReg; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; } assert( pSelect->iOffset==0 || pSelect->iLimit!=0 ); iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit; - pSort->labelDone = sqlite3VdbeMakeLabel(v); + pSort->labelDone = sqlite3VdbeMakeLabel(pParse); sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0)); if( bSeq ){ @@ -116320,7 +134871,6 @@ static void pushOntoSorter( if( nPrefixReg==0 && nData>0 ){ sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord); if( nOBSat>0 ){ int regPrevKey; /* The first nOBSat columns of the previous row */ int addrFirst; /* Address of the OP_IfNot opcode */ @@ -116329,11 +134879,12 @@ static void pushOntoSorter( int nKey; /* Number of sorting key columns, including OP_Sequence */ KeyInfo *pKI; /* Original KeyInfo on the sorter table */ + regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase); regPrevKey = pParse->nMem+1; pParse->nMem += pSort->nOBSat; nKey = nExpr - pSort->nOBSat + bSeq; if( bSeq ){ - addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); + addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); }else{ addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor); } @@ -116343,14 +134894,15 @@ static void pushOntoSorter( if( pParse->db->mallocFailed ) return; pOp->p2 = nKey + nData; pKI = pOp->p4.pKeyInfo; - memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */ + memset(pKI->aSortFlags, 0, pKI->nKeyField); /* Makes OP_Jump testable */ sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO); - testcase( pKI->nXField>2 ); - pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, - pKI->nXField-1); + testcase( pKI->nAllField > pKI->nKeyField+2 ); + pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat, + pKI->nAllField-pKI->nKeyField-1); + pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */ addrJmp = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v); - pSort->labelBkOut = sqlite3VdbeMakeLabel(v); + pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse); pSort->regReturn = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor); @@ -116362,6 +134914,34 @@ static void pushOntoSorter( sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat); sqlite3VdbeJumpHere(v, addrJmp); } + if( iLimit ){ + /* At this point the values for the new sorter entry are stored + ** in an array of registers. They need to be composed into a record + ** and inserted into the sorter if either (a) there are currently + ** less than LIMIT+OFFSET items or (b) the new record is smaller than + ** the largest record currently in the sorter. If (b) is true and there + ** are already LIMIT+OFFSET items in the sorter, delete the largest + ** entry before inserting the new one. This way there are never more + ** than LIMIT+OFFSET items in the sorter. + ** + ** If the new record does not need to be inserted into the sorter, + ** jump to the next iteration of the loop. If the pSort->labelOBLopt + ** value is not zero, then it is a label of where to jump. Otherwise, + ** just bypass the row insert logic. See the header comment on the + ** sqlite3WhereOrderByLimitOptLabel() function for additional info. + */ + int iCsr = pSort->iECursor; + sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Last, iCsr, 0); + iSkip = sqlite3VdbeAddOp4Int(v, OP_IdxLE, + iCsr, 0, regBase+nOBSat, nExpr-nOBSat); + VdbeCoverage(v); + sqlite3VdbeAddOp1(v, OP_Delete, iCsr); + } + if( regRecord==0 ){ + regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase); + } if( pSort->sortFlags & SORTFLAG_UseSorter ){ op = OP_SorterInsert; }else{ @@ -116369,33 +134949,9 @@ static void pushOntoSorter( } sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, regBase+nOBSat, nBase-nOBSat); - if( iLimit ){ - int addr; - int r1 = 0; - /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit - ** register is initialized with value of LIMIT+OFFSET.) After the sorter - ** fills up, delete the least entry in the sorter after each insert. - ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */ - addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v); - sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); - if( pSort->bOrderedInnerLoop ){ - r1 = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1); - VdbeComment((v, "seq")); - } - sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); - if( pSort->bOrderedInnerLoop ){ - /* If the inner loop is driven by an index such that values from - ** the same iteration of the inner loop are in sorted order, then - ** immediately jump to the next iteration of an inner loop if the - ** entry from the current iteration does not fit into the top - ** LIMIT+OFFSET entries of the sorter. */ - int iBrk = sqlite3VdbeCurrentAddr(v) + 2; - sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1); - sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); - VdbeCoverage(v); - } - sqlite3VdbeJumpHere(v, addr); + if( iSkip ){ + sqlite3VdbeChangeP2(v, iSkip, + pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v)); } } @@ -116414,47 +134970,258 @@ static void codeOffset( } /* -** Add code that will check to make sure the N registers starting at iMem -** form a distinct entry. iTab is a sorting index that holds previously -** seen combinations of the N values. A new entry is made in iTab -** if the current N values are new. +** Add code that will check to make sure the array of registers starting at +** iMem form a distinct entry. This is used by both "SELECT DISTINCT ..." and +** distinct aggregates ("SELECT count(DISTINCT ) ..."). Three strategies +** are available. Which is used depends on the value of parameter eTnctType, +** as follows: ** -** A jump to addrRepeat is made and the N+1 values are popped from the -** stack if the top N elements are not distinct. -*/ -static void codeDistinct( +** WHERE_DISTINCT_UNORDERED/WHERE_DISTINCT_NOOP: +** Build an ephemeral table that contains all entries seen before and +** skip entries which have been seen before. +** +** Parameter iTab is the cursor number of an ephemeral table that must +** be opened before the VM code generated by this routine is executed. +** The ephemeral cursor table is queried for a record identical to the +** record formed by the current array of registers. If one is found, +** jump to VM address addrRepeat. Otherwise, insert a new record into +** the ephemeral cursor and proceed. +** +** The returned value in this case is a copy of parameter iTab. +** +** WHERE_DISTINCT_ORDERED: +** In this case rows are being delivered sorted order. The ephermal +** table is not required. Instead, the current set of values +** is compared against previous row. If they match, the new row +** is not distinct and control jumps to VM address addrRepeat. Otherwise, +** the VM program proceeds with processing the new row. +** +** The returned value in this case is the register number of the first +** in an array of registers used to store the previous result row so that +** it can be compared to the next. The caller must ensure that this +** register is initialized to NULL. (The fixDistinctOpenEph() routine +** will take care of this initialization.) +** +** WHERE_DISTINCT_UNIQUE: +** In this case it has already been determined that the rows are distinct. +** No special action is required. The return value is zero. +** +** Parameter pEList is the list of expressions used to generated the +** contents of each row. It is used by this routine to determine (a) +** how many elements there are in the array of registers and (b) the +** collation sequences that should be used for the comparisons if +** eTnctType is WHERE_DISTINCT_ORDERED. +*/ +static int codeDistinct( Parse *pParse, /* Parsing and code generating context */ + int eTnctType, /* WHERE_DISTINCT_* value */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ - int N, /* Number of elements */ - int iMem /* First element */ + ExprList *pEList, /* Expression for each element */ + int regElem /* First element */ ){ - Vdbe *v; - int r1; + int iRet = 0; + int nResultCol = pEList->nExpr; + Vdbe *v = pParse->pVdbe; - v = pParse->pVdbe; - r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N); - sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); - sqlite3ReleaseTempReg(pParse, r1); + switch( eTnctType ){ + case WHERE_DISTINCT_ORDERED: { + int i; + int iJump; /* Jump destination */ + int regPrev; /* Previous row content */ + + /* Allocate space for the previous row */ + iRet = regPrev = pParse->nMem+1; + pParse->nMem += nResultCol; + + iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; + for(i=0; ia[i].pExpr); + if( idb->mallocFailed ); + sqlite3VdbeAddOp3(v, OP_Copy, regElem, regPrev, nResultCol-1); + break; + } + + case WHERE_DISTINCT_UNIQUE: { + /* nothing to do */ + break; + } + + default: { + int r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, regElem, nResultCol); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regElem, nResultCol, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, regElem, nResultCol); + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); + sqlite3ReleaseTempReg(pParse, r1); + iRet = iTab; + break; + } + } + + return iRet; } +/* +** This routine runs after codeDistinct(). It makes necessary +** adjustments to the OP_OpenEphemeral opcode that the codeDistinct() +** routine made use of. This processing must be done separately since +** sometimes codeDistinct is called before the OP_OpenEphemeral is actually +** laid down. +** +** WHERE_DISTINCT_NOOP: +** WHERE_DISTINCT_UNORDERED: +** +** No adjustments necessary. This function is a no-op. +** +** WHERE_DISTINCT_UNIQUE: +** +** The ephemeral table is not needed. So change the +** OP_OpenEphemeral opcode into an OP_Noop. +** +** WHERE_DISTINCT_ORDERED: +** +** The ephemeral table is not needed. But we do need register +** iVal to be initialized to NULL. So change the OP_OpenEphemeral +** into an OP_Null on the iVal register. +*/ +static void fixDistinctOpenEph( + Parse *pParse, /* Parsing and code generating context */ + int eTnctType, /* WHERE_DISTINCT_* value */ + int iVal, /* Value returned by codeDistinct() */ + int iOpenEphAddr /* Address of OP_OpenEphemeral instruction for iTab */ +){ + if( pParse->nErr==0 + && (eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED) + ){ + Vdbe *v = pParse->pVdbe; + sqlite3VdbeChangeToNoop(v, iOpenEphAddr); + if( sqlite3VdbeGetOp(v, iOpenEphAddr+1)->opcode==OP_Explain ){ + sqlite3VdbeChangeToNoop(v, iOpenEphAddr+1); + } + if( eTnctType==WHERE_DISTINCT_ORDERED ){ + /* Change the OP_OpenEphemeral to an OP_Null that sets the MEM_Cleared + ** bit on the first register of the previous value. This will cause the + ** OP_Ne added in codeDistinct() to always fail on the first iteration of + ** the loop even if the first row is all NULLs. */ + VdbeOp *pOp = sqlite3VdbeGetOp(v, iOpenEphAddr); + pOp->opcode = OP_Null; + pOp->p1 = 1; + pOp->p2 = iVal; + } + } +} + +#ifdef SQLITE_ENABLE_SORTER_REFERENCES +/* +** This function is called as part of inner-loop generation for a SELECT +** statement with an ORDER BY that is not optimized by an index. It +** determines the expressions, if any, that the sorter-reference +** optimization should be used for. The sorter-reference optimization +** is used for SELECT queries like: +** +** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10 +** +** If the optimization is used for expression "bigblob", then instead of +** storing values read from that column in the sorter records, the PK of +** the row from table t1 is stored instead. Then, as records are extracted from +** the sorter to return to the user, the required value of bigblob is +** retrieved directly from table t1. If the values are very large, this +** can be more efficient than storing them directly in the sorter records. +** +** The ExprList_item.bSorterRef flag is set for each expression in pEList +** for which the sorter-reference optimization should be enabled. +** Additionally, the pSort->aDefer[] array is populated with entries +** for all cursors required to evaluate all selected expressions. Finally. +** output variable (*ppExtra) is set to an expression list containing +** expressions for all extra PK values that should be stored in the +** sorter records. +*/ +static void selectExprDefer( + Parse *pParse, /* Leave any error here */ + SortCtx *pSort, /* Sorter context */ + ExprList *pEList, /* Expressions destined for sorter */ + ExprList **ppExtra /* Expressions to append to sorter record */ +){ + int i; + int nDefer = 0; + ExprList *pExtra = 0; + for(i=0; inExpr; i++){ + struct ExprList_item *pItem = &pEList->a[i]; + if( pItem->u.x.iOrderByCol==0 ){ + Expr *pExpr = pItem->pExpr; + Table *pTab; + if( pExpr->op==TK_COLUMN + && pExpr->iColumn>=0 + && ALWAYS( ExprUseYTab(pExpr) ) + && (pTab = pExpr->y.pTab)!=0 + && IsOrdinaryTable(pTab) + && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)!=0 + ){ + int j; + for(j=0; jaDefer[j].iCsr==pExpr->iTable ) break; + } + if( j==nDefer ){ + if( nDefer==ArraySize(pSort->aDefer) ){ + continue; + }else{ + int nKey = 1; + int k; + Index *pPk = 0; + if( !HasRowid(pTab) ){ + pPk = sqlite3PrimaryKeyIndex(pTab); + nKey = pPk->nKeyCol; + } + for(k=0; kiTable = pExpr->iTable; + assert( ExprUseYTab(pNew) ); + pNew->y.pTab = pExpr->y.pTab; + pNew->iColumn = pPk ? pPk->aiColumn[k] : -1; + pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew); + } + } + pSort->aDefer[nDefer].pTab = pExpr->y.pTab; + pSort->aDefer[nDefer].iCsr = pExpr->iTable; + pSort->aDefer[nDefer].nKey = nKey; + nDefer++; + } + } + pItem->bSorterRef = 1; + } + } + } + pSort->nDefer = (u8)nDefer; + *ppExtra = pExtra; +} +#endif + /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** -** If srcTab is negative, then the pEList expressions +** If srcTab is negative, then the p->pEList expressions ** are evaluated in order to get the data for this row. If srcTab is -** zero or more, then data is pulled from srcTab and pEList is used only +** zero or more, then data is pulled from srcTab and p->pEList is used only ** to get the number of columns and the collation sequence for each column. */ static void selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ - ExprList *pEList, /* List of values being extracted */ - int srcTab, /* Pull data from this table */ + int srcTab, /* Pull data from this table if non-negative */ SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */ DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */ SelectDest *pDest, /* How to dispose of the results */ @@ -116468,6 +135235,7 @@ static void selectInnerLoop( int iParm = pDest->iSDParm; /* First argument to disposal method */ int nResultCol; /* Number of result columns */ int nPrefixReg = 0; /* Number of extra registers before regResult */ + RowLoadInfo sRowLoadInfo; /* Info for deferred row loading */ /* Usually, regResult is the first cell in an array of memory cells ** containing the current result row. In this case regOrig is set to the @@ -116478,7 +135246,7 @@ static void selectInnerLoop( int regOrig; /* Start of memory holding full result (or 0) */ assert( v ); - assert( pEList!=0 ); + assert( p->pEList!=0 ); hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP; if( pSort && pSort->pOrderBy==0 ) pSort = 0; if( pSort==0 && !hasDistinct ){ @@ -116488,7 +135256,7 @@ static void selectInnerLoop( /* Pull the requested columns. */ - nResultCol = pEList->nExpr; + nResultCol = p->pEList->nExpr; if( pDest->iSdst==0 ){ if( pSort ){ @@ -116511,37 +135279,93 @@ static void selectInnerLoop( if( srcTab>=0 ){ for(i=0; ia[i].zName)); + VdbeComment((v, "%s", p->pEList->a[i].zEName)); } }else if( eDest!=SRT_Exists ){ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + ExprList *pExtra = 0; +#endif /* If the destination is an EXISTS(...) expression, the actual ** values returned by the SELECT are not required. */ - u8 ecelFlags; + u8 ecelFlags; /* "ecel" is an abbreviation of "ExprCodeExprList" */ + ExprList *pEList; if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){ ecelFlags = SQLITE_ECEL_DUP; }else{ ecelFlags = 0; } if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){ - /* For each expression in pEList that is a copy of an expression in - ** the ORDER BY clause (pSort->pOrderBy), set the associated - ** iOrderByCol value to one more than the index of the ORDER BY + /* For each expression in p->pEList that is a copy of an expression in + ** the ORDER BY clause (pSort->pOrderBy), set the associated + ** iOrderByCol value to one more than the index of the ORDER BY ** expression within the sort-key that pushOntoSorter() will generate. - ** This allows the pEList field to be omitted from the sorted record, + ** This allows the p->pEList field to be omitted from the sorted record, ** saving space and CPU cycles. */ ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF); + for(i=pSort->nOBSat; ipOrderBy->nExpr; i++){ int j; if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){ - pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; + p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat; + } + } +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + selectExprDefer(pParse, pSort, p->pEList, &pExtra); + if( pExtra && pParse->db->mallocFailed==0 ){ + /* If there are any extra PK columns to add to the sorter records, + ** allocate extra memory cells and adjust the OpenEphemeral + ** instruction to account for the larger records. This is only + ** required if there are one or more WITHOUT ROWID tables with + ** composite primary keys in the SortCtx.aDefer[] array. */ + VdbeOp *pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex); + pOp->p2 += (pExtra->nExpr - pSort->nDefer); + pOp->p4.pKeyInfo->nAllField += (pExtra->nExpr - pSort->nDefer); + pParse->nMem += pExtra->nExpr; + } +#endif + + /* Adjust nResultCol to account for columns that are omitted + ** from the sorter by the optimizations in this branch */ + pEList = p->pEList; + for(i=0; inExpr; i++){ + if( pEList->a[i].u.x.iOrderByCol>0 +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + || pEList->a[i].bSorterRef +#endif + ){ + nResultCol--; + regOrig = 0; } } + + testcase( regOrig ); + testcase( eDest==SRT_Set ); + testcase( eDest==SRT_Mem ); + testcase( eDest==SRT_Coroutine ); + testcase( eDest==SRT_Output ); + assert( eDest==SRT_Set || eDest==SRT_Mem + || eDest==SRT_Coroutine || eDest==SRT_Output + || eDest==SRT_Upfrom ); + } + sRowLoadInfo.regResult = regResult; + sRowLoadInfo.ecelFlags = ecelFlags; +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + sRowLoadInfo.pExtra = pExtra; + sRowLoadInfo.regExtraResult = regResult + nResultCol; + if( pExtra ) nResultCol += pExtra->nExpr; +#endif + if( p->iLimit + && (ecelFlags & SQLITE_ECEL_OMITREF)!=0 + && nPrefixReg>0 + ){ + assert( pSort!=0 ); + assert( hasDistinct==0 ); + pSort->pDeferredRowLoad = &sRowLoadInfo; regOrig = 0; - assert( eDest==SRT_Set || eDest==SRT_Mem - || eDest==SRT_Coroutine || eDest==SRT_Output ); + }else{ + innerLoopLoadRow(pParse, p, &sRowLoadInfo); } - nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags); } /* If the DISTINCT keyword was present on the SELECT statement @@ -116549,58 +135373,11 @@ static void selectInnerLoop( ** part of the result. */ if( hasDistinct ){ - switch( pDistinct->eTnctType ){ - case WHERE_DISTINCT_ORDERED: { - VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ - int iJump; /* Jump destination */ - int regPrev; /* Previous row content */ - - /* Allocate space for the previous row */ - regPrev = pParse->nMem+1; - pParse->nMem += nResultCol; - - /* Change the OP_OpenEphemeral coded earlier to an OP_Null - ** sets the MEM_Cleared bit on the first register of the - ** previous value. This will cause the OP_Ne below to always - ** fail on the first iteration of the loop even if the first - ** row is all NULLs. - */ - sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); - pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct); - pOp->opcode = OP_Null; - pOp->p1 = 1; - pOp->p2 = regPrev; - - iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; - for(i=0; ia[i].pExpr); - if( idb->mallocFailed ); - sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1); - break; - } - - case WHERE_DISTINCT_UNIQUE: { - sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); - break; - } - - default: { - assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED ); - codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, - regResult); - break; - } - } + int eType = pDistinct->eTnctType; + int iTab = pDistinct->tabTnct; + assert( nResultCol==p->pEList->nExpr ); + iTab = codeDistinct(pParse, eType, iTab, iContinue, p->pEList, regResult); + fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct); if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); } @@ -116657,7 +135434,8 @@ static void selectInnerLoop( } #endif if( pSort ){ - pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg); + assert( regResult==regOrig ); + pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, regOrig, 1, nPrefixReg); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); @@ -116669,6 +135447,30 @@ static void selectInnerLoop( break; } + case SRT_Upfrom: { + if( pSort ){ + pushOntoSorter( + pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); + }else{ + int i2 = pDest->iSDParm2; + int r1 = sqlite3GetTempReg(pParse); + + /* If the UPDATE FROM join is an aggregate that matches no rows, it + ** might still be trying to return one row, because that is what + ** aggregates do. Don't record that empty row in the output table. */ + sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v); + + sqlite3VdbeAddOp3(v, OP_MakeRecord, + regResult+(i2<0), nResultCol-(i2<0), r1); + if( i2<0 ){ + sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult); + }else{ + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2); + } + } + break; + } + #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this @@ -116685,15 +135487,15 @@ static void selectInnerLoop( }else{ int r1 = sqlite3GetTempReg(pParse); assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, + sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); - sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } break; } + /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { @@ -116703,7 +135505,7 @@ static void selectInnerLoop( } /* If this is a scalar select that is part of an expression, then - ** store the results in the appropriate memory cell or array of + ** store the results in the appropriate memory cell or array of ** memory cells and break out of the scan loop. */ case SRT_Mem: { @@ -116731,7 +135533,6 @@ static void selectInnerLoop( sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); - sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); } break; } @@ -116759,7 +135560,7 @@ static void selectInnerLoop( /* If the destination is DistQueue, then cursor (iParm+1) is open ** on a second ephemeral index that holds all values every previously ** added to the queue. */ - addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, + addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, regResult, nResultCol); VdbeCoverage(v); } @@ -116812,18 +135613,18 @@ static void selectInnerLoop( ** X extra columns. */ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ - int nExtra = (N+X)*(sizeof(CollSeq*)+1); + int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*); KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra); if( p ){ - p->aSortOrder = (u8*)&p->aColl[N+X]; - p->nField = (u16)N; - p->nXField = (u16)X; + p->aSortFlags = (u8*)&p->aColl[N+X]; + p->nKeyField = (u16)N; + p->nAllField = (u16)(N+X); p->enc = ENC(db); p->db = db; p->nRef = 1; memset(&p[1], 0, nExtra); }else{ - sqlite3OomFault(db); + return (KeyInfo*)sqlite3OomFault(db); } return p; } @@ -116835,7 +135636,7 @@ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; - if( p->nRef==0 ) sqlite3DbFree(p->db, p); + if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p); } } @@ -116874,7 +135675,7 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; } ** function is responsible for seeing that this structure is eventually ** freed. */ -static KeyInfo *keyInfoFromExprList( +SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList( Parse *pParse, /* Parsing context */ ExprList *pList, /* Form the KeyInfo object from this ExprList */ int iStart, /* Begin with this column of pList */ @@ -116891,11 +135692,8 @@ static KeyInfo *keyInfoFromExprList( if( pInfo ){ assert( sqlite3KeyInfoIsWriteable(pInfo) ); for(i=iStart, pItem=pList->a+iStart; ipExpr); - if( !pColl ) pColl = db->pDfltColl; - pInfo->aColl[i-iStart] = pColl; - pInfo->aSortOrder[i-iStart] = pItem->sortOrder; + pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr); + pInfo->aSortFlags[i-iStart] = pItem->sortFlags; } } return pInfo; @@ -116904,7 +135702,7 @@ static KeyInfo *keyInfoFromExprList( /* ** Name of the connection operator, used for error messages. */ -static const char *selectOpName(int id){ +SQLITE_PRIVATE const char *sqlite3SelectOpName(int id){ char *z; switch( id ){ case TK_ALL: z = "UNION ALL"; break; @@ -116927,11 +135725,7 @@ static const char *selectOpName(int id){ ** is determined by the zUsage argument. */ static void explainTempTable(Parse *pParse, const char *zUsage){ - if( pParse->explain==2 ){ - Vdbe *v = pParse->pVdbe; - char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage); - sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); - } + ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s", zUsage)); } /* @@ -116949,42 +135743,6 @@ static void explainTempTable(Parse *pParse, const char *zUsage){ # define explainSetInteger(y,z) #endif -#if !defined(SQLITE_OMIT_EXPLAIN) && !defined(SQLITE_OMIT_COMPOUND_SELECT) -/* -** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function -** is a no-op. Otherwise, it adds a single row of output to the EQP result, -** where the caption is of one of the two forms: -** -** "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)" -** "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)" -** -** where iSub1 and iSub2 are the integers passed as the corresponding -** function parameters, and op is the text representation of the parameter -** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT, -** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is -** false, or the second form if it is true. -*/ -static void explainComposite( - Parse *pParse, /* Parse context */ - int op, /* One of TK_UNION, TK_EXCEPT etc. */ - int iSub1, /* Subquery id 1 */ - int iSub2, /* Subquery id 2 */ - int bUseTmp /* True if a temp table was used */ -){ - assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL ); - if( pParse->explain==2 ){ - Vdbe *v = pParse->pVdbe; - char *zMsg = sqlite3MPrintf( - pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2, - bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op) - ); - sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); - } -} -#else -/* No-op versions of the explainXXX() functions and macros. */ -# define explainComposite(v,w,x,y,z) -#endif /* ** If the inner loop was generated using a non-null pOrderBy argument, @@ -117001,8 +135759,8 @@ static void generateSortTail( ){ Vdbe *v = pParse->pVdbe; /* The prepared statement */ int addrBreak = pSort->labelDone; /* Jump here to exit loop */ - int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */ - int addr; + int addrContinue = sqlite3VdbeMakeLabel(pParse);/* Jump here for next cycle */ + int addr; /* Top of output loop. Jump for Next. */ int addrOnce = 0; int iTab; ExprList *pOrderBy = pSort->pOrderBy; @@ -117011,11 +135769,11 @@ static void generateSortTail( int regRow; int regRowid; int iCol; - int nKey; + int nKey; /* Number of key columns in sorter record */ int iSortTab; /* Sorter cursor to read from */ - int nSortData; /* Trailing values to read from sorter */ int i; int bSeq; /* True if sorter record includes seq. no. */ + int nRefKey = 0; struct ExprList_item *aOutEx = p->pEList->a; assert( addrBreak<0 ); @@ -117024,15 +135782,32 @@ static void generateSortTail( sqlite3VdbeGoto(v, addrBreak); sqlite3VdbeResolveLabel(v, pSort->labelBkOut); } + +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + /* Open any cursors needed for sorter-reference expressions */ + for(i=0; inDefer; i++){ + Table *pTab = pSort->aDefer[i].pTab; + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + sqlite3OpenTable(pParse, pSort->aDefer[i].iCsr, iDb, pTab, OP_OpenRead); + nRefKey = MAX(nRefKey, pSort->aDefer[i].nKey); + } +#endif + iTab = pSort->iECursor; if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){ + if( eDest==SRT_Mem && p->iOffset ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pDest->iSdst); + } regRowid = 0; regRow = pDest->iSdst; - nSortData = nColumn; }else{ regRowid = sqlite3GetTempReg(pParse); - regRow = sqlite3GetTempRange(pParse, nColumn); - nSortData = nColumn; + if( eDest==SRT_EphemTab || eDest==SRT_Table ){ + regRow = sqlite3GetTempReg(pParse); + nColumn = 0; + }else{ + regRow = sqlite3GetTempRange(pParse, nColumn); + } } nKey = pOrderBy->nExpr - pSort->nOBSat; if( pSort->sortFlags & SORTFLAG_UseSorter ){ @@ -117041,7 +135816,8 @@ static void generateSortTail( if( pSort->labelBkOut ){ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } - sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData); + sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, + nKey+1+nColumn+nRefKey); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); @@ -117054,19 +135830,64 @@ static void generateSortTail( iSortTab = iTab; bSeq = 1; } - for(i=0, iCol=nKey+bSeq; inDefer ){ + int iKey = iCol+1; + int regKey = sqlite3GetTempRange(pParse, nRefKey); + + for(i=0; inDefer; i++){ + int iCsr = pSort->aDefer[i].iCsr; + Table *pTab = pSort->aDefer[i].pTab; + int nKey = pSort->aDefer[i].nKey; + + sqlite3VdbeAddOp1(v, OP_NullRow, iCsr); + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iKey++, regKey); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iCsr, + sqlite3VdbeCurrentAddr(v)+1, regKey); + }else{ + int k; + int iJmp; + assert( sqlite3PrimaryKeyIndex(pTab)->nKeyCol==nKey ); + for(k=0; k=0; i--){ +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + if( aOutEx[i].bSorterRef ){ + sqlite3ExprCode(pParse, aOutEx[i].pExpr, regRow+i); + }else +#endif + { + int iRead; + if( aOutEx[i].u.x.iOrderByCol ){ + iRead = aOutEx[i].u.x.iOrderByCol-1; + }else{ + iRead = iCol--; + } + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); + VdbeComment((v, "%s", aOutEx[i].zEName)); } - sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); - VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq, regRow); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); @@ -117077,7 +135898,6 @@ static void generateSortTail( assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, pDest->zAffSdst, nColumn); - sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn); break; } @@ -117086,13 +135906,23 @@ static void generateSortTail( break; } #endif + case SRT_Upfrom: { + int i2 = pDest->iSDParm2; + int r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1); + if( i2<0 ){ + sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regRow); + }else{ + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2); + } + break; + } default: { - assert( eDest==SRT_Output || eDest==SRT_Coroutine ); + assert( eDest==SRT_Output || eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); testcase( eDest==SRT_Coroutine ); if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); - sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn); }else{ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); } @@ -117130,37 +135960,37 @@ static void generateSortTail( ** original CREATE TABLE statement if the expression is a column. The ** declaration type for a ROWID field is INTEGER. Exactly when an expression ** is considered a column can be complex in the presence of subqueries. The -** result-set expression in all of the following SELECT statements is +** result-set expression in all of the following SELECT statements is ** considered a column by this function. ** ** SELECT col FROM tbl; ** SELECT (SELECT col FROM tbl; ** SELECT (SELECT col FROM tbl); ** SELECT abc FROM (SELECT col AS abc FROM tbl); -** +** ** The declaration type for any expression other than a column is NULL. ** ** This routine has either 3 or 6 parameters depending on whether or not ** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used. */ #ifdef SQLITE_ENABLE_COLUMN_METADATA -# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F) +# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E) #else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ -# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F) +# define columnType(A,B,C,D,E) columnTypeImpl(A,B) #endif static const char *columnTypeImpl( - NameContext *pNC, + NameContext *pNC, +#ifndef SQLITE_ENABLE_COLUMN_METADATA + Expr *pExpr +#else Expr *pExpr, -#ifdef SQLITE_ENABLE_COLUMN_METADATA const char **pzOrigDb, const char **pzOrigTab, - const char **pzOrigCol, + const char **pzOrigCol #endif - u8 *pEstWidth ){ char const *zType = 0; int j; - u8 estWidth = 1; #ifdef SQLITE_ENABLE_COLUMN_METADATA char const *zOrigDb = 0; char const *zOrigTab = 0; @@ -117170,7 +136000,6 @@ static const char *columnTypeImpl( assert( pExpr!=0 ); assert( pNC->pSrcList!=0 ); switch( pExpr->op ){ - case TK_AGG_COLUMN: case TK_COLUMN: { /* The expression is a column. Locate the table the column is being ** extracted from in NameContext.pSrcList. This table may be real @@ -117179,8 +136008,6 @@ static const char *columnTypeImpl( Table *pTab = 0; /* Table structure column is extracted from */ Select *pS = 0; /* Select the column is extracted from */ int iCol = pExpr->iColumn; /* Index of column in pTab */ - testcase( pExpr->op==TK_AGG_COLUMN ); - testcase( pExpr->op==TK_COLUMN ); while( pNC && !pTab ){ SrcList *pTabList = pNC->pSrcList; for(j=0;jnSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); @@ -117195,70 +136022,72 @@ static const char *columnTypeImpl( if( pTab==0 ){ /* At one time, code such as "SELECT new.x" within a trigger would ** cause this condition to run. Since then, we have restructured how - ** trigger code is generated and so this condition is no longer + ** trigger code is generated and so this condition is no longer ** possible. However, it can still be true for statements like ** the following: ** ** CREATE TABLE t1(col INTEGER); ** SELECT (SELECT t1.col) FROM FROM t1; ** - ** when columnType() is called on the expression "t1.col" in the + ** when columnType() is called on the expression "t1.col" in the ** sub-select. In this case, set the column type to NULL, even ** though it should really be "INTEGER". ** ** This is not a problem, as the column type of "t1.col" is never - ** used. When columnType() is called on the expression + ** used. When columnType() is called on the expression ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT ** branch below. */ break; } - assert( pTab && pExpr->pTab==pTab ); + assert( pTab && ExprUseYTab(pExpr) && pExpr->y.pTab==pTab ); if( pS ){ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ - if( iCol>=0 && ALWAYS(iColpEList->nExpr) ){ + if( iColpEList->nExpr +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + && iCol>=0 +#else + && ALWAYS(iCol>=0) +#endif + ){ /* If iCol is less than zero, then the expression requests the - ** rowid of the sub-select or view. This expression is legal (see + ** rowid of the sub-select or view. This expression is legal (see ** test case misc2.2.2) - it always evaluates to NULL. - ** - ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been - ** caught already by name resolution. */ NameContext sNC; Expr *p = pS->pEList->a[iCol].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; - zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth); + zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol); } - }else if( pTab->pSchema ){ - /* A real table */ + }else{ + /* A real table or a CTE table */ assert( !pS ); - if( iCol<0 ) iCol = pTab->iPKey; - assert( iCol==-1 || (iCol>=0 && iColnCol) ); #ifdef SQLITE_ENABLE_COLUMN_METADATA + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==XN_ROWID || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zType = "INTEGER"; zOrigCol = "rowid"; }else{ - zOrigCol = pTab->aCol[iCol].zName; + zOrigCol = pTab->aCol[iCol].zCnName; zType = sqlite3ColumnType(&pTab->aCol[iCol],0); - estWidth = pTab->aCol[iCol].szEst; } zOrigTab = pTab->zName; - if( pNC->pParse ){ + if( pNC->pParse && pTab->pSchema ){ int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName; } #else + assert( iCol==XN_ROWID || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zType = "INTEGER"; }else{ zType = sqlite3ColumnType(&pTab->aCol[iCol],0); - estWidth = pTab->aCol[iCol].szEst; } #endif } @@ -117271,19 +136100,21 @@ static const char *columnTypeImpl( ** statement. */ NameContext sNC; - Select *pS = pExpr->x.pSelect; - Expr *p = pS->pEList->a[0].pExpr; - assert( ExprHasProperty(pExpr, EP_xIsSelect) ); + Select *pS; + Expr *p; + assert( ExprUseXSelect(pExpr) ); + pS = pExpr->x.pSelect; + p = pS->pEList->a[0].pExpr; sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; - zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth); + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); break; } #endif } -#ifdef SQLITE_ENABLE_COLUMN_METADATA +#ifdef SQLITE_ENABLE_COLUMN_METADATA if( pzOrigDb ){ assert( pzOrigTab && pzOrigCol ); *pzOrigDb = zOrigDb; @@ -117291,7 +136122,6 @@ static const char *columnTypeImpl( *pzOrigCol = zOrigCol; } #endif - if( pEstWidth ) *pEstWidth = estWidth; return zType; } @@ -117310,6 +136140,7 @@ static void generateColumnTypes( NameContext sNC; sNC.pSrcList = pTabList; sNC.pParse = pParse; + sNC.pNext = 0; for(i=0; inExpr; i++){ Expr *p = pEList->a[i].pExpr; const char *zType; @@ -117317,9 +136148,9 @@ static void generateColumnTypes( const char *zOrigDb = 0; const char *zOrigTab = 0; const char *zOrigCol = 0; - zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0); + zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); - /* The vdbe must make its own copy of the column-type and other + /* The vdbe must make its own copy of the column-type and other ** column specific strings, in case the schema is reset before this ** virtual machine is deleted. */ @@ -117327,27 +136158,56 @@ static void generateColumnTypes( sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT); sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT); #else - zType = columnType(&sNC, p, 0, 0, 0, 0); + zType = columnType(&sNC, p, 0, 0, 0); #endif sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT); } #endif /* !defined(SQLITE_OMIT_DECLTYPE) */ } + /* -** Generate code that will tell the VDBE the names of columns -** in the result set. This information is used to provide the -** azCol[] values in the callback. +** Compute the column names for a SELECT statement. +** +** The only guarantee that SQLite makes about column names is that if the +** column has an AS clause assigning it a name, that will be the name used. +** That is the only documented guarantee. However, countless applications +** developed over the years have made baseless assumptions about column names +** and will break if those assumptions changes. Hence, use extreme caution +** when modifying this routine to avoid breaking legacy. +** +** See Also: sqlite3ColumnsFromExprList() +** +** The PRAGMA short_column_names and PRAGMA full_column_names settings are +** deprecated. The default setting is short=ON, full=OFF. 99.9% of all +** applications should operate this way. Nevertheless, we need to support the +** other modes for legacy: +** +** short=OFF, full=OFF: Column name is the text of the expression has it +** originally appears in the SELECT statement. In +** other words, the zSpan of the result expression. +** +** short=ON, full=OFF: (This is the default setting). If the result +** refers directly to a table column, then the +** result column name is just the table column +** name: COLUMN. Otherwise use zSpan. +** +** full=ON, short=ANY: If the result refers directly to a table column, +** then the result column name with the table name +** prefix, ex: TABLE.COLUMN. Otherwise use zSpan. */ -static void generateColumnNames( +SQLITE_PRIVATE void sqlite3GenerateColumnNames( Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ + Select *pSelect /* Generate column names for this SELECT statement */ ){ Vdbe *v = pParse->pVdbe; - int i, j; + int i; + Table *pTab; + SrcList *pTabList; + ExprList *pEList; sqlite3 *db = pParse->db; - int fullNames, shortNames; + int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */ + int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */ #ifndef SQLITE_OMIT_EXPLAIN /* If this is an EXPLAIN, skip this step */ @@ -117356,40 +136216,42 @@ static void generateColumnNames( } #endif - if( pParse->colNamesSet || db->mallocFailed ) return; + if( pParse->colNamesSet ) return; + /* Column names are determined by the left-most term of a compound select */ + while( pSelect->pPrior ) pSelect = pSelect->pPrior; + SELECTTRACE(1,pParse,pSelect,("generating column names\n")); + pTabList = pSelect->pSrc; + pEList = pSelect->pEList; assert( v!=0 ); assert( pTabList!=0 ); pParse->colNamesSet = 1; - fullNames = (db->flags & SQLITE_FullColNames)!=0; - shortNames = (db->flags & SQLITE_ShortColNames)!=0; + fullName = (db->flags & SQLITE_FullColNames)!=0; + srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; inExpr; i++){ - Expr *p; - p = pEList->a[i].pExpr; - if( NEVER(p==0) ) continue; - if( pEList->a[i].zName ){ - char *zName = pEList->a[i].zName; + Expr *p = pEList->a[i].pExpr; + + assert( p!=0 ); + assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ + assert( p->op!=TK_COLUMN + || (ExprUseYTab(p) && p->y.pTab!=0) ); /* Covering idx not yet coded */ + if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){ + /* An AS clause always takes first priority */ + char *zName = pEList->a[i].zEName; sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); - }else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){ - Table *pTab; + }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; - for(j=0; ALWAYS(jnSrc); j++){ - if( pTabList->a[j].iCursor==p->iTable ) break; - } - assert( jnSrc ); - pTab = pTabList->a[j].pTab; + pTab = p->y.pTab; + assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iColnCol) ); if( iCol<0 ){ zCol = "rowid"; }else{ - zCol = pTab->aCol[iCol].zName; + zCol = pTab->aCol[iCol].zCnName; } - if( !shortNames && !fullNames ){ - sqlite3VdbeSetColName(v, i, COLNAME_NAME, - sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC); - }else if( fullNames ){ + if( fullName ){ char *zName = 0; zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol); sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC); @@ -117397,7 +136259,7 @@ static void generateColumnNames( sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT); } }else{ - const char *z = pEList->a[i].zSpan; + const char *z = pEList->a[i].zEName; z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z); sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC); } @@ -117417,6 +136279,15 @@ static void generateColumnNames( ** ** Return SQLITE_OK on success. If a memory allocation error occurs, ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM. +** +** The only guarantee that SQLite makes about column names is that if the +** column has an AS clause assigning it a name, that will be the name used. +** That is the only documented guarantee. However, countless applications +** developed over the years have made baseless assumptions about column names +** and will break if those assumptions changes. Hence, use extreme caution +** when modifying this routine to avoid breaking legacy. +** +** See Also: sqlite3GenerateColumnNames() */ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( Parse *pParse, /* Parsing context */ @@ -117429,16 +136300,17 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( u32 cnt; /* Index added to make the name unique */ Column *aCol, *pCol; /* For looping over result columns */ int nCol; /* Number of columns in the result set */ - Expr *p; /* Expression for a single result column */ char *zName; /* Column name */ int nName; /* Size of name in zName[] */ Hash ht; /* Hash table of column names */ + Table *pTab; sqlite3HashInit(&ht); if( pEList ){ nCol = pEList->nExpr; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); testcase( aCol==0 ); + if( NEVER(nCol>32767) ) nCol = 32767; }else{ nCol = 0; aCol = 0; @@ -117450,31 +136322,35 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( for(i=0, pCol=aCol; imallocFailed; i++, pCol++){ /* Get an appropriate name for the column */ - p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); - if( (zName = pEList->a[i].zName)!=0 ){ + if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){ /* If the column contains an "AS " phrase, use as the name */ }else{ - Expr *pColExpr = p; /* The expression that is the result column name */ - Table *pTab; /* Table associated with this expression */ - while( pColExpr->op==TK_DOT ){ + Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr); + while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){ pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } - if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){ + if( pColExpr->op==TK_COLUMN + && ALWAYS( ExprUseYTab(pColExpr) ) + && (pTab = pColExpr->y.pTab)!=0 + ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; - pTab = pColExpr->pTab; if( iCol<0 ) iCol = pTab->iPKey; - zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; + zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid"; }else if( pColExpr->op==TK_ID ){ assert( !ExprHasProperty(pColExpr, EP_IntValue) ); zName = pColExpr->u.zToken; }else{ /* Use the original text of the column expression as its name */ - zName = pEList->a[i].zSpan; + zName = pEList->a[i].zEName; } } - zName = sqlite3MPrintf(db, "%s", zName); + if( zName && !sqlite3IsTrueOrFalse(zName) ){ + zName = sqlite3DbStrDup(db, zName); + }else{ + zName = sqlite3MPrintf(db,"column%d",i+1); + } /* Make sure the column name is unique. If the name is not unique, ** append an integer to the name so that it becomes unique. @@ -117489,7 +136365,8 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt); if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt); } - pCol->zName = zName; + pCol->zCnName = zName; + pCol->hName = sqlite3StrIHash(zName); sqlite3ColumnPropertiesFromName(0, pCol); if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){ sqlite3OomFault(db); @@ -117498,7 +136375,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( sqlite3HashClear(&ht); if( db->mallocFailed ){ for(j=0; jdb; NameContext sNC; @@ -117531,7 +136409,6 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation( int i; Expr *p; struct ExprList_item *a; - u64 szAll = 0; assert( pSelect!=0 ); assert( (pSelect->selFlags & SF_Resolved)!=0 ); @@ -117542,56 +136419,59 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation( a = pSelect->pEList->a; for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ const char *zType; - int n, m; + i64 n, m; + pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT); p = a[i].pExpr; - zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst); - szAll += pCol->szEst; + zType = columnType(&sNC, p, 0, 0, 0); + /* pCol->szEst = ... // Column size est for SELECT tables never used */ pCol->affinity = sqlite3ExprAffinity(p); - if( zType && (m = sqlite3Strlen30(zType))>0 ){ - n = sqlite3Strlen30(pCol->zName); - pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2); - if( pCol->zName ){ - memcpy(&pCol->zName[n+1], zType, m+1); + if( zType ){ + m = sqlite3Strlen30(zType); + n = sqlite3Strlen30(pCol->zCnName); + pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2); + if( pCol->zCnName ){ + memcpy(&pCol->zCnName[n+1], zType, m+1); pCol->colFlags |= COLFLAG_HASTYPE; + }else{ + testcase( pCol->colFlags & COLFLAG_HASTYPE ); + pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); } } - if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB; + if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff; pColl = sqlite3ExprCollSeq(pParse, p); - if( pColl && pCol->zColl==0 ){ - pCol->zColl = sqlite3DbStrDup(db, pColl->zName); + if( pColl ){ + assert( pTab->pIndex==0 ); + sqlite3ColumnSetColl(db, pCol, pColl->zName); } } - pTab->szTabRow = sqlite3LogEst(szAll*4); + pTab->szTabRow = 1; /* Any non-zero value works */ } /* ** Given a SELECT statement, generate a Table structure that describes ** the result set of that SELECT. */ -SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ +SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, char aff){ Table *pTab; sqlite3 *db = pParse->db; - int savedFlags; + u64 savedFlags; savedFlags = db->flags; - db->flags &= ~SQLITE_FullColNames; + db->flags &= ~(u64)SQLITE_FullColNames; db->flags |= SQLITE_ShortColNames; sqlite3SelectPrep(pParse, pSelect, 0); + db->flags = savedFlags; if( pParse->nErr ) return 0; while( pSelect->pPrior ) pSelect = pSelect->pPrior; - db->flags = savedFlags; pTab = sqlite3DbMallocZero(db, sizeof(Table) ); if( pTab==0 ){ return 0; } - /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside - ** is disabled */ - assert( db->lookaside.bDisable ); pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); - sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); @@ -117604,41 +136484,38 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ ** Get a VDBE for the given parser context. Create a new one if necessary. ** If an error occurs, return NULL and leave a message in pParse. */ -static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){ - Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse); - if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1); +SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ + if( pParse->pVdbe ){ + return pParse->pVdbe; + } if( pParse->pToplevel==0 && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst) ){ pParse->okConstFactor = 1; } - return v; -} -SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){ - Vdbe *v = pParse->pVdbe; - return v ? v : allocVdbe(pParse); + return sqlite3VdbeCreate(pParse); } /* ** Compute the iLimit and iOffset fields of the SELECT based on the -** pLimit and pOffset expressions. pLimit and pOffset hold the expressions +** pLimit expressions. pLimit->pLeft and pLimit->pRight hold the expressions ** that appear in the original SQL statement after the LIMIT and OFFSET -** keywords. Or NULL if those keywords are omitted. iLimit and iOffset -** are the integer memory register numbers for counters used to compute -** the limit and offset. If there is no limit and/or offset, then +** keywords. Or NULL if those keywords are omitted. iLimit and iOffset +** are the integer memory register numbers for counters used to compute +** the limit and offset. If there is no limit and/or offset, then ** iLimit and iOffset are negative. ** ** This routine changes the values of iLimit and iOffset only if -** a limit or offset is defined by pLimit and pOffset. iLimit and -** iOffset should have been preset to appropriate default values (zero) +** a limit or offset is defined by pLimit->pLeft and pLimit->pRight. iLimit +** and iOffset should have been preset to appropriate default values (zero) ** prior to calling this routine. ** ** The iOffset register (if it exists) is initialized to the value ** of the OFFSET. The iLimit register is initialized to LIMIT. Register ** iOffset+1 is initialized to LIMIT+OFFSET. ** -** Only if pLimit!=0 or pOffset!=0 do the limit registers get +** Only if pLimit->pLeft!=0 do the limit registers get ** redefined. The UNION ALL operator uses this property to force ** the reuse of the same limit and offset registers across multiple ** SELECT statements. @@ -117648,21 +136525,23 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ int iLimit = 0; int iOffset; int n; + Expr *pLimit = p->pLimit; + if( p->iLimit ) return; - /* + /* ** "LIMIT -1" always shows all rows. There is some ** controversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ - sqlite3ExprCacheClear(pParse); - assert( p->pOffset==0 || p->pLimit!=0 ); - if( p->pLimit ){ + if( pLimit ){ + assert( pLimit->op==TK_LIMIT ); + assert( pLimit->pLeft!=0 ); p->iLimit = iLimit = ++pParse->nMem; v = sqlite3GetVdbe(pParse); assert( v!=0 ); - if( sqlite3ExprIsInteger(p->pLimit, &n) ){ + if( sqlite3ExprIsInteger(pLimit->pLeft, &n) ){ sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit); VdbeComment((v, "LIMIT counter")); if( n==0 ){ @@ -117672,15 +136551,15 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ p->selFlags |= SF_FixedLimit; } }else{ - sqlite3ExprCode(pParse, p->pLimit, iLimit); + sqlite3ExprCode(pParse, pLimit->pLeft, iLimit); sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); VdbeComment((v, "LIMIT counter")); sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); } - if( p->pOffset ){ + if( pLimit->pRight ){ p->iOffset = iOffset = ++pParse->nMem; pParse->nMem++; /* Allocate an extra register for limit+offset */ - sqlite3ExprCode(pParse, p->pOffset, iOffset); + sqlite3ExprCode(pParse, pLimit->pRight, iOffset); sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); VdbeComment((v, "OFFSET counter")); sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset); @@ -117726,7 +136605,7 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ */ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ ExprList *pOrderBy = p->pOrderBy; - int nOrderBy = p->pOrderBy->nExpr; + int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0; sqlite3 *db = pParse->db; KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1); if( pRet ){ @@ -117746,7 +136625,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ } assert( sqlite3KeyInfoIsWriteable(pRet) ); pRet->aColl[i] = pColl; - pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder; + pRet->aSortFlags[i] = pOrderBy->a[i].sortFlags; } } @@ -117778,7 +136657,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ ** inserted into the Queue table. The iDistinct table keeps a copy of all rows ** that have ever been inserted into Queue and causes duplicates to be ** discarded. If the operator is UNION ALL, then duplicates are allowed. -** +** ** If the query has an ORDER BY, then entries in the Queue table are kept in ** ORDER BY order and the first entry is extracted for each cycle. Without ** an ORDER BY, the Queue table is just a FIFO. @@ -117798,7 +136677,8 @@ static void generateWithRecursiveQuery( SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */ int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ - Select *pSetup = p->pPrior; /* The setup query */ + Select *pSetup; /* The setup query */ + Select *pFirstRec; /* Left-most recursive term */ int addrTop; /* Top of the loop */ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ int iCurrent = 0; /* The Current table */ @@ -117810,21 +136690,27 @@ static void generateWithRecursiveQuery( int i; /* Loop counter */ int rc; /* Result code */ ExprList *pOrderBy; /* The ORDER BY clause */ - Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */ + Expr *pLimit; /* Saved LIMIT and OFFSET */ int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ){ + sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries"); + return; + } +#endif + /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; /* Process the LIMIT and OFFSET clauses, if they exist */ - addrBreak = sqlite3VdbeMakeLabel(v); + addrBreak = sqlite3VdbeMakeLabel(pParse); p->nSelectRow = 320; /* 4 billion rows */ computeLimitRegisters(pParse, p, addrBreak); pLimit = p->pLimit; - pOffset = p->pOffset; regLimit = p->iLimit; regOffset = p->iOffset; - p->pLimit = p->pOffset = 0; + p->pLimit = 0; p->iLimit = p->iOffset = 0; pOrderBy = p->pOrderBy; @@ -117868,8 +136754,26 @@ static void generateWithRecursiveQuery( /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; + /* Figure out how many elements of the compound SELECT are part of the + ** recursive query. Make sure no recursive elements use aggregate + ** functions. Mark the recursive elements as UNION ALL even if they + ** are really UNION because the distinctness will be enforced by the + ** iDistinct table. pFirstRec is left pointing to the left-most + ** recursive term of the CTE. + */ + for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){ + if( pFirstRec->selFlags & SF_Aggregate ){ + sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); + goto end_of_recursive_query; + } + pFirstRec->op = TK_ALL; + if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break; + } + /* Store the results of the setup-query in Queue. */ + pSetup = pFirstRec->pPrior; pSetup->pNext = 0; + ExplainQueryPlan((pParse, 1, "SETUP")); rc = sqlite3Select(pParse, pSetup, &destQueue); pSetup->pNext = p; if( rc ) goto end_of_recursive_query; @@ -117887,9 +136791,9 @@ static void generateWithRecursiveQuery( sqlite3VdbeAddOp1(v, OP_Delete, iQueue); /* Output the single row in Current */ - addrCont = sqlite3VdbeMakeLabel(v); + addrCont = sqlite3VdbeMakeLabel(pParse); codeOffset(v, regOffset, addrCont); - selectInnerLoop(pParse, p, p->pEList, iCurrent, + selectInnerLoop(pParse, p, iCurrent, 0, 0, pDest, addrCont, addrBreak); if( regLimit ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak); @@ -117900,14 +136804,11 @@ static void generateWithRecursiveQuery( /* Execute the recursive SELECT taking the single row in Current as ** the value for the recursive-table. Store the results in the Queue. */ - if( p->selFlags & SF_Aggregate ){ - sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); - }else{ - p->pPrior = 0; - sqlite3Select(pParse, p, &destQueue); - assert( p->pPrior==0 ); - p->pPrior = pSetup; - } + pFirstRec->pPrior = 0; + ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); + sqlite3Select(pParse, p, &destQueue); + assert( pFirstRec->pPrior==0 ); + pFirstRec->pPrior = pSetup; /* Keep running the loop until the Queue is empty */ sqlite3VdbeGoto(v, addrTop); @@ -117917,7 +136818,6 @@ static void generateWithRecursiveQuery( sqlite3ExprListDelete(pParse->db, p->pOrderBy); p->pOrderBy = pOrderBy; p->pLimit = pLimit; - p->pOffset = pOffset; return; } #endif /* SQLITE_OMIT_CTE */ @@ -117936,42 +136836,57 @@ static int multiSelectOrderBy( ** on a VALUES clause. ** ** Because the Select object originates from a VALUES clause: -** (1) It has no LIMIT or OFFSET +** (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1 ** (2) All terms are UNION ALL ** (3) There is no ORDER BY clause +** +** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES +** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))"). +** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case. +** Since the limit is exactly 1, we only need to evalutes the left-most VALUES. */ static int multiSelectValues( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ - Select *pPrior; int nRow = 1; int rc = 0; + int bShowAll = p->pLimit==0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); - assert( p->pLimit==0 ); - assert( p->pOffset==0 ); assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin ) return -1; +#endif if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); p = p->pPrior; - nRow++; + nRow += bShowAll; }while(1); + ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow, + nRow==1 ? "" : "S")); while( p ){ - pPrior = p->pPrior; - p->pPrior = 0; - rc = sqlite3Select(pParse, p, pDest); - p->pPrior = pPrior; - if( rc ) break; + selectInnerLoop(pParse, p, -1, 0, 0, pDest, 1, 1); + if( !bShowAll ) break; p->nSelectRow = nRow; p = p->pNext; } return rc; } +/* +** Return true if the SELECT statement which is known to be the recursive +** part of a recursive CTE still has its anchor terms attached. If the +** anchor terms have already been removed, then return false. +*/ +static int hasAnchor(Select *p){ + while( p && (p->selFlags & SF_Recursive)!=0 ){ p = p->pPrior; } + return p!=0; +} + /* ** This routine is called to process a compound query form from ** two or more separate queries using UNION, UNION ALL, EXCEPT, or @@ -117979,7 +136894,7 @@ static int multiSelectValues( ** ** "p" points to the right-most of the two queries. the query on the ** left is p->pPrior. The left query could also be a compound query -** in which case this routine will be called recursively. +** in which case this routine will be called recursively. ** ** The results of the total query are to be written into a destination ** of type eDest with parameter iParm. @@ -118014,31 +136929,18 @@ static int multiSelect( SelectDest dest; /* Alternative data destination */ Select *pDelete = 0; /* Chain of simple selects to delete */ sqlite3 *db; /* Database connection */ -#ifndef SQLITE_OMIT_EXPLAIN - int iSub1 = 0; /* EQP id of left-hand query */ - int iSub2 = 0; /* EQP id of right-hand query */ -#endif /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); + assert( p->selFlags & SF_Compound ); db = pParse->db; pPrior = p->pPrior; dest = *pDest; - if( pPrior->pOrderBy ){ - sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before", - selectOpName(p->op)); - rc = 1; - goto multi_select_end; - } - if( pPrior->pLimit ){ - sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before", - selectOpName(p->op)); - rc = 1; - goto multi_select_end; - } + assert( pPrior->pOrderBy==0 ); + assert( pPrior->pLimit==0 ); v = sqlite3GetVdbe(pParse); assert( v!=0 ); /* The VDBE already created by calling function */ @@ -118055,7 +136957,8 @@ static int multiSelect( */ if( p->selFlags & SF_MultiValue ){ rc = multiSelectValues(pParse, p, &dest); - goto multi_select_end; + if( rc>=0 ) goto multi_select_end; + rc = SQLITE_OK; } /* Make sure all SELECTs in the statement have the same number of elements @@ -118065,7 +136968,7 @@ static int multiSelect( assert( p->pEList->nExpr==pPrior->pEList->nExpr ); #ifndef SQLITE_OMIT_CTE - if( p->selFlags & SF_Recursive ){ + if( (p->selFlags & SF_Recursive)!=0 && hasAnchor(p) ){ generateWithRecursiveQuery(pParse, p, &dest); }else #endif @@ -118074,237 +136977,239 @@ static int multiSelect( */ if( p->pOrderBy ){ return multiSelectOrderBy(pParse, p, pDest); - }else + }else{ - /* Generate code for the left and right SELECT statements. - */ - switch( p->op ){ - case TK_ALL: { - int addr = 0; - int nLimit; - assert( !pPrior->pLimit ); - pPrior->iLimit = p->iLimit; - pPrior->iOffset = p->iOffset; - pPrior->pLimit = p->pLimit; - pPrior->pOffset = p->pOffset; - explainSetInteger(iSub1, pParse->iNextSelectId); - rc = sqlite3Select(pParse, pPrior, &dest); - p->pLimit = 0; - p->pOffset = 0; - if( rc ){ - goto multi_select_end; - } - p->pPrior = 0; - p->iLimit = pPrior->iLimit; - p->iOffset = pPrior->iOffset; - if( p->iLimit ){ - addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); - VdbeComment((v, "Jump ahead if LIMIT reached")); - if( p->iOffset ){ - sqlite3VdbeAddOp3(v, OP_OffsetLimit, - p->iLimit, p->iOffset+1, p->iOffset); +#ifndef SQLITE_OMIT_EXPLAIN + if( pPrior->pPrior==0 ){ + ExplainQueryPlan((pParse, 1, "COMPOUND QUERY")); + ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY")); + } +#endif + + /* Generate code for the left and right SELECT statements. + */ + switch( p->op ){ + case TK_ALL: { + int addr = 0; + int nLimit = 0; /* Initialize to suppress harmless compiler warning */ + assert( !pPrior->pLimit ); + pPrior->iLimit = p->iLimit; + pPrior->iOffset = p->iOffset; + pPrior->pLimit = p->pLimit; + SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL left...\n")); + rc = sqlite3Select(pParse, pPrior, &dest); + pPrior->pLimit = 0; + if( rc ){ + goto multi_select_end; + } + p->pPrior = 0; + p->iLimit = pPrior->iLimit; + p->iOffset = pPrior->iOffset; + if( p->iLimit ){ + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); + VdbeComment((v, "Jump ahead if LIMIT reached")); + if( p->iOffset ){ + sqlite3VdbeAddOp3(v, OP_OffsetLimit, + p->iLimit, p->iOffset+1, p->iOffset); + } } + ExplainQueryPlan((pParse, 1, "UNION ALL")); + SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL right...\n")); + rc = sqlite3Select(pParse, p, &dest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + if( p->pLimit + && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit) + && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) + ){ + p->nSelectRow = sqlite3LogEst((u64)nLimit); + } + if( addr ){ + sqlite3VdbeJumpHere(v, addr); + } + break; } - explainSetInteger(iSub2, pParse->iNextSelectId); - rc = sqlite3Select(pParse, p, &dest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - if( pPrior->pLimit - && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit) - && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) - ){ - p->nSelectRow = sqlite3LogEst((u64)nLimit); - } - if( addr ){ - sqlite3VdbeJumpHere(v, addr); - } - break; - } - case TK_EXCEPT: - case TK_UNION: { - int unionTab; /* Cursor number of the temporary table holding result */ - u8 op = 0; /* One of the SRT_ operations to apply to self */ - int priorOp; /* The SRT_ operation to apply to prior selects */ - Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */ - int addr; - SelectDest uniondest; - - testcase( p->op==TK_EXCEPT ); - testcase( p->op==TK_UNION ); - priorOp = SRT_Union; - if( dest.eDest==priorOp ){ - /* We can reuse a temporary table generated by a SELECT to our - ** right. + case TK_EXCEPT: + case TK_UNION: { + int unionTab; /* Cursor number of the temp table holding result */ + u8 op = 0; /* One of the SRT_ operations to apply to self */ + int priorOp; /* The SRT_ operation to apply to prior selects */ + Expr *pLimit; /* Saved values of p->nLimit */ + int addr; + SelectDest uniondest; + + testcase( p->op==TK_EXCEPT ); + testcase( p->op==TK_UNION ); + priorOp = SRT_Union; + if( dest.eDest==priorOp ){ + /* We can reuse a temporary table generated by a SELECT to our + ** right. + */ + assert( p->pLimit==0 ); /* Not allowed on leftward elements */ + unionTab = dest.iSDParm; + }else{ + /* We will need to create our own temporary table to hold the + ** intermediate results. + */ + unionTab = pParse->nTab++; + assert( p->pOrderBy==0 ); + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); + assert( p->addrOpenEphm[0] == -1 ); + p->addrOpenEphm[0] = addr; + findRightmost(p)->selFlags |= SF_UsesEphemeral; + assert( p->pEList ); + } + + + /* Code the SELECT statements to our left */ - assert( p->pLimit==0 ); /* Not allowed on leftward elements */ - assert( p->pOffset==0 ); /* Not allowed on leftward elements */ - unionTab = dest.iSDParm; - }else{ - /* We will need to create our own temporary table to hold the - ** intermediate results. + assert( !pPrior->pOrderBy ); + sqlite3SelectDestInit(&uniondest, priorOp, unionTab); + SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); + rc = sqlite3Select(pParse, pPrior, &uniondest); + if( rc ){ + goto multi_select_end; + } + + /* Code the current SELECT statement */ - unionTab = pParse->nTab++; + if( p->op==TK_EXCEPT ){ + op = SRT_Except; + }else{ + assert( p->op==TK_UNION ); + op = SRT_Union; + } + p->pPrior = 0; + pLimit = p->pLimit; + p->pLimit = 0; + uniondest.eDest = op; + ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", + sqlite3SelectOpName(p->op))); + SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); + rc = sqlite3Select(pParse, p, &uniondest); + testcase( rc!=SQLITE_OK ); assert( p->pOrderBy==0 ); - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->pOrderBy = 0; + if( p->op==TK_UNION ){ + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + } + sqlite3ExprDelete(db, p->pLimit); + p->pLimit = pLimit; + p->iLimit = 0; + p->iOffset = 0; + + /* Convert the data in the temporary table into whatever form + ** it is that we currently need. + */ + assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); + assert( p->pEList || db->mallocFailed ); + if( dest.eDest!=priorOp && db->mallocFailed==0 ){ + int iCont, iBreak, iStart; + iBreak = sqlite3VdbeMakeLabel(pParse); + iCont = sqlite3VdbeMakeLabel(pParse); + computeLimitRegisters(pParse, p, iBreak); + sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); + iStart = sqlite3VdbeCurrentAddr(v); + selectInnerLoop(pParse, p, unionTab, + 0, 0, &dest, iCont, iBreak); + sqlite3VdbeResolveLabel(v, iCont); + sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); + sqlite3VdbeResolveLabel(v, iBreak); + sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); + } + break; + } + default: assert( p->op==TK_INTERSECT ); { + int tab1, tab2; + int iCont, iBreak, iStart; + Expr *pLimit; + int addr; + SelectDest intersectdest; + int r1; + + /* INTERSECT is different from the others since it requires + ** two temporary tables. Hence it has its own case. Begin + ** by allocating the tables we will need. + */ + tab1 = pParse->nTab++; + tab2 = pParse->nTab++; + assert( p->pOrderBy==0 ); + + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); - } - /* Code the SELECT statements to our left - */ - assert( !pPrior->pOrderBy ); - sqlite3SelectDestInit(&uniondest, priorOp, unionTab); - explainSetInteger(iSub1, pParse->iNextSelectId); - rc = sqlite3Select(pParse, pPrior, &uniondest); - if( rc ){ - goto multi_select_end; - } - - /* Code the current SELECT statement - */ - if( p->op==TK_EXCEPT ){ - op = SRT_Except; - }else{ - assert( p->op==TK_UNION ); - op = SRT_Union; - } - p->pPrior = 0; - pLimit = p->pLimit; - p->pLimit = 0; - pOffset = p->pOffset; - p->pOffset = 0; - uniondest.eDest = op; - explainSetInteger(iSub2, pParse->iNextSelectId); - rc = sqlite3Select(pParse, p, &uniondest); - testcase( rc!=SQLITE_OK ); - /* Query flattening in sqlite3Select() might refill p->pOrderBy. - ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ - sqlite3ExprListDelete(db, p->pOrderBy); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->pOrderBy = 0; - if( p->op==TK_UNION ){ - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - } - sqlite3ExprDelete(db, p->pLimit); - p->pLimit = pLimit; - p->pOffset = pOffset; - p->iLimit = 0; - p->iOffset = 0; + /* Code the SELECTs to our left into temporary table "tab1". + */ + sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); + SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT left...\n")); + rc = sqlite3Select(pParse, pPrior, &intersectdest); + if( rc ){ + goto multi_select_end; + } - /* Convert the data in the temporary table into whatever form - ** it is that we currently need. - */ - assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); - if( dest.eDest!=priorOp ){ - int iCont, iBreak, iStart; + /* Code the current SELECT into temporary table "tab2" + */ + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); + assert( p->addrOpenEphm[1] == -1 ); + p->addrOpenEphm[1] = addr; + p->pPrior = 0; + pLimit = p->pLimit; + p->pLimit = 0; + intersectdest.iSDParm = tab2; + ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", + sqlite3SelectOpName(p->op))); + SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT right...\n")); + rc = sqlite3Select(pParse, p, &intersectdest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + if( p->nSelectRow>pPrior->nSelectRow ){ + p->nSelectRow = pPrior->nSelectRow; + } + sqlite3ExprDelete(db, p->pLimit); + p->pLimit = pLimit; + + /* Generate code to take the intersection of the two temporary + ** tables. + */ + if( rc ) break; assert( p->pEList ); - if( dest.eDest==SRT_Output ){ - Select *pFirst = p; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } - iBreak = sqlite3VdbeMakeLabel(v); - iCont = sqlite3VdbeMakeLabel(v); + iBreak = sqlite3VdbeMakeLabel(pParse); + iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); - iStart = sqlite3VdbeCurrentAddr(v); - selectInnerLoop(pParse, p, p->pEList, unionTab, + sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); + r1 = sqlite3GetTempReg(pParse); + iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); + sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, r1); + selectInnerLoop(pParse, p, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); + sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); + sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); + break; } - break; } - default: assert( p->op==TK_INTERSECT ); { - int tab1, tab2; - int iCont, iBreak, iStart; - Expr *pLimit, *pOffset; - int addr; - SelectDest intersectdest; - int r1; - - /* INTERSECT is different from the others since it requires - ** two temporary tables. Hence it has its own case. Begin - ** by allocating the tables we will need. - */ - tab1 = pParse->nTab++; - tab2 = pParse->nTab++; - assert( p->pOrderBy==0 ); - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); - assert( p->addrOpenEphm[0] == -1 ); - p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; - assert( p->pEList ); - - /* Code the SELECTs to our left into temporary table "tab1". - */ - sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); - explainSetInteger(iSub1, pParse->iNextSelectId); - rc = sqlite3Select(pParse, pPrior, &intersectdest); - if( rc ){ - goto multi_select_end; - } - - /* Code the current SELECT into temporary table "tab2" - */ - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); - assert( p->addrOpenEphm[1] == -1 ); - p->addrOpenEphm[1] = addr; - p->pPrior = 0; - pLimit = p->pLimit; - p->pLimit = 0; - pOffset = p->pOffset; - p->pOffset = 0; - intersectdest.iSDParm = tab2; - explainSetInteger(iSub2, pParse->iNextSelectId); - rc = sqlite3Select(pParse, p, &intersectdest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; - sqlite3ExprDelete(db, p->pLimit); - p->pLimit = pLimit; - p->pOffset = pOffset; - - /* Generate code to take the intersection of the two temporary - ** tables. - */ - assert( p->pEList ); - if( dest.eDest==SRT_Output ){ - Select *pFirst = p; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } - iBreak = sqlite3VdbeMakeLabel(v); - iCont = sqlite3VdbeMakeLabel(v); - computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); - r1 = sqlite3GetTempReg(pParse); - iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); - sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); - sqlite3ReleaseTempReg(pParse, r1); - selectInnerLoop(pParse, p, p->pEList, tab1, - 0, 0, &dest, iCont, iBreak); - sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); - sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); - sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); - break; + #ifndef SQLITE_OMIT_EXPLAIN + if( p->pNext==0 ){ + ExplainQueryPlanPop(pParse); } + #endif } + if( pParse->nErr ) goto multi_select_end; - explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL); - - /* Compute collating sequences used by + /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. ** @@ -118321,6 +137226,7 @@ static int multiSelect( int nCol; /* Number of columns in result set */ assert( p->pNext==0 ); + assert( p->pEList!=0 ); nCol = p->pEList->nExpr; pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); if( !pKeyInfo ){ @@ -118355,7 +137261,11 @@ static int multiSelect( multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; - sqlite3SelectDelete(db, pDelete); + if( pDelete ){ + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3SelectDelete, + pDelete); + } return rc; } #endif /* SQLITE_OMIT_COMPOUND_SELECT */ @@ -118369,7 +137279,8 @@ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){ sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms"); }else{ sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s" - " do not have the same number of result columns", selectOpName(p->op)); + " do not have the same number of result columns", + sqlite3SelectOpName(p->op)); } } @@ -118408,9 +137319,9 @@ static int generateOutputSubroutine( int addr; addr = sqlite3VdbeCurrentAddr(v); - iContinue = sqlite3VdbeMakeLabel(v); + iContinue = sqlite3VdbeMakeLabel(pParse); - /* Suppress duplicates for UNION, EXCEPT, and INTERSECT + /* Suppress duplicates for UNION, EXCEPT, and INTERSECT */ if( regPrev ){ int addr1, addr2; @@ -118452,9 +137363,8 @@ static int generateOutputSubroutine( int r1; testcase( pIn->nSdst>1 ); r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, + sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1, pDest->zAffSdst, pIn->nSdst); - sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, pIn->iSdst, pIn->nSdst); sqlite3ReleaseTempReg(pParse, r1); @@ -118463,11 +137373,12 @@ static int generateOutputSubroutine( /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out - ** of the scan loop. + ** of the scan loop. Note that the select might return multiple columns + ** if it is the RHS of a row-value IN operator. */ case SRT_Mem: { - assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 ); - sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1); + testcase( pIn->nSdst>1 ); + sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst); /* The LIMIT clause will jump out of the loop for us */ break; } @@ -118490,14 +137401,13 @@ static int generateOutputSubroutine( ** SRT_Output. This routine is never called with any other ** destination other than the ones handled above or SRT_Output. ** - ** For SRT_Output, results are stored in a sequence of registers. + ** For SRT_Output, results are stored in a sequence of registers. ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to ** return the next row of result. */ default: { assert( pDest->eDest==SRT_Output ); sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst); - sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst); break; } } @@ -118548,7 +137458,7 @@ static int generateOutputSubroutine( ** ** EofB: Called when data is exhausted from selectB. ** -** The implementation of the latter five subroutines depend on which +** The implementation of the latter five subroutines depend on which ** is used: ** ** @@ -118609,6 +137519,8 @@ static int multiSelectOrderBy( ){ int i, j; /* Loop counters */ Select *pPrior; /* Another SELECT immediately to our left */ + Select *pSplit; /* Left-most SELECT in the right-hand group */ + int nSelect; /* Number of SELECT statements in the compound */ Vdbe *v; /* Generate code to this VDBE */ SelectDest destA; /* Destination for coroutine A */ SelectDest destB; /* Destination for coroutine B */ @@ -118640,26 +137552,21 @@ static int multiSelectOrderBy( sqlite3 *db; /* Database connection */ ExprList *pOrderBy; /* The ORDER BY clause */ int nOrderBy; /* Number of terms in the ORDER BY clause */ - int *aPermute; /* Mapping from ORDER BY terms to result set columns */ -#ifndef SQLITE_OMIT_EXPLAIN - int iSub1; /* EQP id of left-hand query */ - int iSub2; /* EQP id of right-hand query */ -#endif + u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */ assert( p->pOrderBy!=0 ); assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */ db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */ - labelEnd = sqlite3VdbeMakeLabel(v); - labelCmpr = sqlite3VdbeMakeLabel(v); + labelEnd = sqlite3VdbeMakeLabel(pParse); + labelCmpr = sqlite3VdbeMakeLabel(pParse); /* Patch up the ORDER BY clause */ - op = p->op; - pPrior = p->pPrior; - assert( pPrior->pOrderBy==0 ); + op = p->op; + assert( p->pPrior->pOrderBy==0 ); pOrderBy = p->pOrderBy; assert( pOrderBy ); nOrderBy = pOrderBy->nExpr; @@ -118672,6 +137579,7 @@ static int multiSelectOrderBy( for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){ struct ExprList_item *pItem; for(j=0, pItem=pOrderBy->a; ju.x.iOrderByCol>0 ); if( pItem->u.x.iOrderByCol==i ) break; } @@ -118680,7 +137588,7 @@ static int multiSelectOrderBy( if( pNew==0 ) return SQLITE_NOMEM_BKPT; pNew->flags |= EP_IntValue; pNew->u.iValue = i; - pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); + p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i; } } @@ -118693,11 +137601,12 @@ static int multiSelectOrderBy( ** to the right and the left are evaluated, they use the correct ** collation. */ - aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1)); + aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1)); if( aPermute ){ struct ExprList_item *pItem; aPermute[0] = nOrderBy; for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ + assert( pItem!=0 ); assert( pItem->u.x.iOrderByCol>0 ); assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; @@ -118707,11 +137616,6 @@ static int multiSelectOrderBy( pKeyMerge = 0; } - /* Reattach the ORDER BY clause to the query. - */ - p->pOrderBy = pOrderBy; - pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0); - /* Allocate a range of temporary registers and the KeyInfo needed ** for the logic that removes duplicate result rows when the ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL). @@ -118729,19 +137633,37 @@ static int multiSelectOrderBy( assert( sqlite3KeyInfoIsWriteable(pKeyDup) ); for(i=0; iaColl[i] = multiSelectCollSeq(pParse, p, i); - pKeyDup->aSortOrder[i] = 0; + pKeyDup->aSortFlags[i] = 0; } } } - + /* Separate the left and the right query from one another */ - p->pPrior = 0; + nSelect = 1; + if( (op==TK_ALL || op==TK_UNION) + && OptimizationEnabled(db, SQLITE_BalancedMerge) + ){ + for(pSplit=p; pSplit->pPrior!=0 && pSplit->op==op; pSplit=pSplit->pPrior){ + nSelect++; + assert( pSplit->pPrior->pNext==pSplit ); + } + } + if( nSelect<=3 ){ + pSplit = p; + }else{ + pSplit = p; + for(i=2; ipPrior; } + } + pPrior = pSplit->pPrior; + assert( pPrior!=0 ); + pSplit->pPrior = 0; pPrior->pNext = 0; + assert( p->pOrderBy == pOrderBy ); + assert( pOrderBy!=0 || db->mallocFailed ); + pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0); sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER"); - if( pPrior->pPrior==0 ){ - sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER"); - } + sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER"); /* Compute the limit registers */ computeLimitRegisters(pParse, p, labelEnd); @@ -118756,8 +137678,6 @@ static int multiSelectOrderBy( } sqlite3ExprDelete(db, p->pLimit); p->pLimit = 0; - sqlite3ExprDelete(db, p->pOffset); - p->pOffset = 0; regAddrA = ++pParse->nMem; regAddrB = ++pParse->nMem; @@ -118766,6 +137686,8 @@ static int multiSelectOrderBy( sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); + ExplainQueryPlan((pParse, 1, "MERGE (%s)", sqlite3SelectOpName(p->op))); + /* Generate a coroutine to evaluate the SELECT statement to the ** left of the compound operator - the "A" select. */ @@ -118773,12 +137695,12 @@ static int multiSelectOrderBy( addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); VdbeComment((v, "left SELECT")); pPrior->iLimit = regLimitA; - explainSetInteger(iSub1, pParse->iNextSelectId); + ExplainQueryPlan((pParse, 1, "LEFT")); sqlite3Select(pParse, pPrior, &destA); sqlite3VdbeEndCoroutine(v, regAddrA); sqlite3VdbeJumpHere(v, addr1); - /* Generate a coroutine to evaluate the SELECT statement on + /* Generate a coroutine to evaluate the SELECT statement on ** the right - the "B" select */ addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; @@ -118787,8 +137709,8 @@ static int multiSelectOrderBy( savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; - p->iOffset = 0; - explainSetInteger(iSub2, pParse->iNextSelectId); + p->iOffset = 0; + ExplainQueryPlan((pParse, 1, "RIGHT")); sqlite3Select(pParse, p, &destB); p->iLimit = savedLimit; p->iOffset = savedOffset; @@ -118801,7 +137723,7 @@ static int multiSelectOrderBy( addrOutA = generateOutputSubroutine(pParse, p, &destA, pDest, regOutA, regPrev, pKeyDup, labelEnd); - + /* Generate a subroutine that outputs the current row of the B ** select as the next output row of the compound select. */ @@ -118818,7 +137740,7 @@ static int multiSelectOrderBy( */ if( op==TK_EXCEPT || op==TK_INTERSECT ){ addrEofA_noB = addrEofA = labelEnd; - }else{ + }else{ VdbeNoopComment((v, "eof-A subroutine")); addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd); @@ -118833,7 +137755,7 @@ static int multiSelectOrderBy( if( op==TK_INTERSECT ){ addrEofB = addrEofA; if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; - }else{ + }else{ VdbeNoopComment((v, "eof-B subroutine")); addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v); @@ -118890,127 +137812,307 @@ static int multiSelectOrderBy( */ sqlite3VdbeResolveLabel(v, labelEnd); - /* Set the number of output columns - */ - if( pDest->eDest==SRT_Output ){ - Select *pFirst = pPrior; - while( pFirst->pPrior ) pFirst = pFirst->pPrior; - generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList); - } - /* Reassembly the compound query so that it will be freed correctly ** by the calling function */ - if( p->pPrior ){ - sqlite3SelectDelete(db, p->pPrior); + if( pSplit->pPrior ){ + sqlite3SelectDelete(db, pSplit->pPrior); } - p->pPrior = pPrior; - pPrior->pNext = p; + pSplit->pPrior = pPrior; + pPrior->pNext = pSplit; + sqlite3ExprListDelete(db, pPrior->pOrderBy); + pPrior->pOrderBy = 0; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ - explainComposite(pParse, p->op, iSub1, iSub2, 0); + ExplainQueryPlanPop(pParse); return pParse->nErr!=0; } #endif #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + +/* An instance of the SubstContext object describes an substitution edit +** to be performed on a parse tree. +** +** All references to columns in table iTable are to be replaced by corresponding +** expressions in pEList. +*/ +typedef struct SubstContext { + Parse *pParse; /* The parsing context */ + int iTable; /* Replace references to this table */ + int iNewTable; /* New table number */ + int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ + ExprList *pEList; /* Replacement expressions */ +} SubstContext; + /* Forward Declarations */ -static void substExprList(Parse*, ExprList*, int, ExprList*); -static void substSelect(Parse*, Select *, int, ExprList*, int); +static void substExprList(SubstContext*, ExprList*); +static void substSelect(SubstContext*, Select*, int); /* ** Scan through the expression pExpr. Replace every reference to ** a column in table number iTable with a copy of the iColumn-th -** entry in pEList. (But leave references to the ROWID column +** entry in pEList. (But leave references to the ROWID column ** unchanged.) ** ** This routine is part of the flattening procedure. A subquery ** whose result set is defined by pEList appears as entry in the ** FROM clause of a SELECT such that the VDBE cursor assigned to that -** FORM clause entry is iTable. This routine make the necessary +** FORM clause entry is iTable. This routine makes the necessary ** changes to pExpr so that it refers directly to the source table ** of the subquery rather the result set of the subquery. */ static Expr *substExpr( - Parse *pParse, /* Report errors here */ - Expr *pExpr, /* Expr in which substitution occurs */ - int iTable, /* Table to be substituted */ - ExprList *pEList /* Substitute expressions */ + SubstContext *pSubst, /* Description of the substitution */ + Expr *pExpr /* Expr in which substitution occurs */ ){ - sqlite3 *db = pParse->db; if( pExpr==0 ) return 0; - if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){ + if( ExprHasProperty(pExpr, EP_FromJoin) + && pExpr->w.iRightJoinTable==pSubst->iTable + ){ + pExpr->w.iRightJoinTable = pSubst->iNewTable; + } + if( pExpr->op==TK_COLUMN + && pExpr->iTable==pSubst->iTable + && !ExprHasProperty(pExpr, EP_FixedCol) + ){ +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; - }else{ + }else +#endif + { Expr *pNew; - Expr *pCopy = pEList->a[pExpr->iColumn].pExpr; - assert( pEList!=0 && pExpr->iColumnnExpr ); - assert( pExpr->pLeft==0 && pExpr->pRight==0 ); + Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; + Expr ifNullRow; + assert( pSubst->pEList!=0 && pExpr->iColumnpEList->nExpr ); + assert( pExpr->pRight==0 ); if( sqlite3ExprIsVector(pCopy) ){ - sqlite3VectorErrorMsg(pParse, pCopy); + sqlite3VectorErrorMsg(pSubst->pParse, pCopy); }else{ + sqlite3 *db = pSubst->pParse->db; + if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){ + memset(&ifNullRow, 0, sizeof(ifNullRow)); + ifNullRow.op = TK_IF_NULL_ROW; + ifNullRow.pLeft = pCopy; + ifNullRow.iTable = pSubst->iNewTable; + ifNullRow.flags = EP_IfNullRow; + pCopy = &ifNullRow; + } + testcase( ExprHasProperty(pCopy, EP_Subquery) ); pNew = sqlite3ExprDup(db, pCopy, 0); - if( pNew && (pExpr->flags & EP_FromJoin) ){ - pNew->iRightJoinTable = pExpr->iRightJoinTable; - pNew->flags |= EP_FromJoin; + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pNew); + return pExpr; + } + if( pSubst->isLeftJoin ){ + ExprSetProperty(pNew, EP_CanBeNull); + } + if( ExprHasProperty(pExpr,EP_FromJoin) ){ + sqlite3SetJoinExpr(pNew, pExpr->w.iRightJoinTable); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; + + /* Ensure that the expression now has an implicit collation sequence, + ** just as it did when it was a column of a view or sub-query. */ + if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){ + CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr); + pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr, + (pColl ? pColl->zName : "BINARY") + ); + } + ExprClearProperty(pExpr, EP_Collate); } } }else{ - pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList); - pExpr->pRight = substExpr(pParse, pExpr->pRight, iTable, pEList); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - substSelect(pParse, pExpr->x.pSelect, iTable, pEList, 1); + if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){ + pExpr->iTable = pSubst->iNewTable; + } + pExpr->pLeft = substExpr(pSubst, pExpr->pLeft); + pExpr->pRight = substExpr(pSubst, pExpr->pRight); + if( ExprUseXSelect(pExpr) ){ + substSelect(pSubst, pExpr->x.pSelect, 1); }else{ - substExprList(pParse, pExpr->x.pList, iTable, pEList); + substExprList(pSubst, pExpr->x.pList); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + Window *pWin = pExpr->y.pWin; + pWin->pFilter = substExpr(pSubst, pWin->pFilter); + substExprList(pSubst, pWin->pPartition); + substExprList(pSubst, pWin->pOrderBy); + } +#endif } return pExpr; } static void substExprList( - Parse *pParse, /* Report errors here */ - ExprList *pList, /* List to scan and in which to make substitutes */ - int iTable, /* Table to be substituted */ - ExprList *pEList /* Substitute values */ + SubstContext *pSubst, /* Description of the substitution */ + ExprList *pList /* List to scan and in which to make substitutes */ ){ int i; if( pList==0 ) return; for(i=0; inExpr; i++){ - pList->a[i].pExpr = substExpr(pParse, pList->a[i].pExpr, iTable, pEList); + pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr); } } static void substSelect( - Parse *pParse, /* Report errors here */ - Select *p, /* SELECT statement in which to make substitutions */ - int iTable, /* Table to be replaced */ - ExprList *pEList, /* Substitute values */ - int doPrior /* Do substitutes on p->pPrior too */ + SubstContext *pSubst, /* Description of the substitution */ + Select *p, /* SELECT statement in which to make substitutions */ + int doPrior /* Do substitutes on p->pPrior too */ ){ SrcList *pSrc; - struct SrcList_item *pItem; + SrcItem *pItem; int i; if( !p ) return; do{ - substExprList(pParse, p->pEList, iTable, pEList); - substExprList(pParse, p->pGroupBy, iTable, pEList); - substExprList(pParse, p->pOrderBy, iTable, pEList); - p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList); - p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList); + substExprList(pSubst, p->pEList); + substExprList(pSubst, p->pGroupBy); + substExprList(pSubst, p->pOrderBy); + p->pHaving = substExpr(pSubst, p->pHaving); + p->pWhere = substExpr(pSubst, p->pWhere); pSrc = p->pSrc; assert( pSrc!=0 ); for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ - substSelect(pParse, pItem->pSelect, iTable, pEList, 1); + substSelect(pSubst, pItem->pSelect, 1); if( pItem->fg.isTabFunc ){ - substExprList(pParse, pItem->u1.pFuncArg, iTable, pEList); + substExprList(pSubst, pItem->u1.pFuncArg); } } }while( doPrior && (p = p->pPrior)!=0 ); } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) +/* +** pSelect is a SELECT statement and pSrcItem is one item in the FROM +** clause of that SELECT. +** +** This routine scans the entire SELECT statement and recomputes the +** pSrcItem->colUsed mask. +*/ +static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){ + SrcItem *pItem; + if( pExpr->op!=TK_COLUMN ) return WRC_Continue; + pItem = pWalker->u.pSrcItem; + if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue; + if( pExpr->iColumn<0 ) return WRC_Continue; + pItem->colUsed |= sqlite3ExprColUsed(pExpr); + return WRC_Continue; +} +static void recomputeColumnsUsed( + Select *pSelect, /* The complete SELECT statement */ + SrcItem *pSrcItem /* Which FROM clause item to recompute */ +){ + Walker w; + if( NEVER(pSrcItem->pTab==0) ) return; + memset(&w, 0, sizeof(w)); + w.xExprCallback = recomputeColumnsUsedExpr; + w.xSelectCallback = sqlite3SelectWalkNoop; + w.u.pSrcItem = pSrcItem; + pSrcItem->colUsed = 0; + sqlite3WalkSelect(&w, pSelect); +} +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) +/* +** Assign new cursor numbers to each of the items in pSrc. For each +** new cursor number assigned, set an entry in the aCsrMap[] array +** to map the old cursor number to the new: +** +** aCsrMap[iOld+1] = iNew; +** +** The array is guaranteed by the caller to be large enough for all +** existing cursor numbers in pSrc. aCsrMap[0] is the array size. +** +** If pSrc contains any sub-selects, call this routine recursively +** on the FROM clause of each such sub-select, with iExcept set to -1. +*/ +static void srclistRenumberCursors( + Parse *pParse, /* Parse context */ + int *aCsrMap, /* Array to store cursor mappings in */ + SrcList *pSrc, /* FROM clause to renumber */ + int iExcept /* FROM clause item to skip */ +){ + int i; + SrcItem *pItem; + for(i=0, pItem=pSrc->a; inSrc; i++, pItem++){ + if( i!=iExcept ){ + Select *p; + assert( pItem->iCursor < aCsrMap[0] ); + if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){ + aCsrMap[pItem->iCursor+1] = pParse->nTab++; + } + pItem->iCursor = aCsrMap[pItem->iCursor+1]; + for(p=pItem->pSelect; p; p=p->pPrior){ + srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); + } + } + } +} + +/* +** *piCursor is a cursor number. Change it if it needs to be mapped. +*/ +static void renumberCursorDoMapping(Walker *pWalker, int *piCursor){ + int *aCsrMap = pWalker->u.aiCol; + int iCsr = *piCursor; + if( iCsr < aCsrMap[0] && aCsrMap[iCsr+1]>0 ){ + *piCursor = aCsrMap[iCsr+1]; + } +} + +/* +** Expression walker callback used by renumberCursors() to update +** Expr objects to match newly assigned cursor numbers. +*/ +static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){ + int op = pExpr->op; + if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){ + renumberCursorDoMapping(pWalker, &pExpr->iTable); + } + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + renumberCursorDoMapping(pWalker, &pExpr->w.iRightJoinTable); + } + return WRC_Continue; +} + +/* +** Assign a new cursor number to each cursor in the FROM clause (Select.pSrc) +** of the SELECT statement passed as the second argument, and to each +** cursor in the FROM clause of any FROM clause sub-selects, recursively. +** Except, do not assign a new cursor number to the iExcept'th element in +** the FROM clause of (*p). Update all expressions and other references +** to refer to the new cursor numbers. +** +** Argument aCsrMap is an array that may be used for temporary working +** space. Two guarantees are made by the caller: +** +** * the array is larger than the largest cursor number used within the +** select statement passed as an argument, and +** +** * the array entries for all cursor numbers that do *not* appear in +** FROM clauses of the select statement as described above are +** initialized to zero. +*/ +static void renumberCursors( + Parse *pParse, /* Parse context */ + Select *p, /* Select to renumber cursors within */ + int iExcept, /* FROM clause item to skip */ + int *aCsrMap /* Working space */ +){ + Walker w; + srclistRenumberCursors(pParse, aCsrMap, p->pSrc, iExcept); + memset(&w, 0, sizeof(w)); + w.u.aiCol = aCsrMap; + w.xExprCallback = renumberCursorsCb; + w.xSelectCallback = sqlite3SelectWalkNoop; + sqlite3WalkSelect(&w, p); +} +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ + #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** This routine attempts to flatten subqueries as a performance optimization. @@ -119034,70 +138136,80 @@ static void substSelect( ** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5 ** ** The code generated for this simplification gives the same result -** but only has to scan the data once. And because indices might +** but only has to scan the data once. And because indices might ** exist on the table t1, a complete scan of the data might be ** avoided. ** -** Flattening is only attempted if all of the following are true: +** Flattening is subject to the following constraints: ** -** (1) The subquery and the outer query do not both use aggregates. +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** The subquery and the outer query cannot both be aggregates. ** -** (2) The subquery is not an aggregate or (2a) the outer query is not a join -** and (2b) the outer query does not use subqueries other than the one -** FROM-clause subquery that is a candidate for flattening. (2b is -** due to ticket [2f7170d73bf9abf80] from 2015-02-09.) +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** (2) If the subquery is an aggregate then +** (2a) the outer query must not be a join and +** (2b) the outer query must not use subqueries +** other than the one FROM-clause subquery that is a candidate +** for flattening. (This is due to ticket [2f7170d73bf9abf80] +** from 2015-02-09.) ** -** (3) The subquery is not the right operand of a left outer join -** (Originally ticket #306. Strengthened by ticket #3300) +** (3) If the subquery is the right operand of a LEFT JOIN then +** (3a) the subquery may not be a join and +** (3b) the FROM clause of the subquery may not contain a virtual +** table and +** (3c) the outer query may not be an aggregate. +** (3d) the outer query may not be DISTINCT. ** -** (4) The subquery is not DISTINCT. +** (4) The subquery can not be DISTINCT. ** ** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT -** sub-queries that were excluded from this optimization. Restriction +** sub-queries that were excluded from this optimization. Restriction ** (4) has since been expanded to exclude all DISTINCT subqueries. ** -** (6) The subquery does not use aggregates or the outer query is not -** DISTINCT. +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** If the subquery is aggregate, the outer query may not be DISTINCT. ** -** (7) The subquery has a FROM clause. TODO: For subqueries without -** A FROM clause, consider adding a FROM close with the special +** (7) The subquery must have a FROM clause. TODO: For subqueries without +** A FROM clause, consider adding a FROM clause with the special ** table sqlite_once that consists of a single row containing a ** single NULL. ** -** (8) The subquery does not use LIMIT or the outer query is not a join. +** (8) If the subquery uses LIMIT then the outer query may not be a join. ** -** (9) The subquery does not use LIMIT or the outer query does not use -** aggregates. +** (9) If the subquery uses LIMIT then the outer query may not be aggregate. ** ** (**) Restriction (10) was removed from the code on 2005-02-05 but we ** accidently carried the comment forward until 2014-09-15. Original -** text: "The subquery does not use aggregates or the outer query -** does not use LIMIT." +** constraint: "If the subquery is aggregate then the outer query +** may not use LIMIT." ** -** (11) The subquery and the outer query do not both have ORDER BY clauses. +** (11) The subquery and the outer query may not both have ORDER BY clauses. ** ** (**) Not implemented. Subsumed into restriction (3). Was previously ** a separate restriction deriving from ticket #350. ** -** (13) The subquery and outer query do not both use LIMIT. +** (13) The subquery and outer query may not both use LIMIT. ** -** (14) The subquery does not use OFFSET. +** (14) The subquery may not use OFFSET. ** -** (15) The outer query is not part of a compound select or the -** subquery does not have a LIMIT clause. +** (15) If the outer query is part of a compound select, then the +** subquery may not use LIMIT. ** (See ticket #2339 and ticket [02a8e81d44]). ** -** (16) The outer query is not an aggregate or the subquery does -** not contain ORDER BY. (Ticket #2942) This used to not matter -** until we introduced the group_concat() function. -** -** (17) The sub-query is not a compound select, or it is a UNION ALL -** compound clause made up entirely of non-aggregate queries, and -** the parent query: -** -** * is not itself part of a compound select, -** * is not an aggregate or DISTINCT query, and -** * is not a join +** (16) If the outer query is aggregate, then the subquery may not +** use ORDER BY. (Ticket #2942) This used to not matter +** until we introduced the group_concat() function. +** +** (17) If the subquery is a compound select, then +** (17a) all compound operators must be a UNION ALL, and +** (17b) no terms within the subquery compound may be aggregate +** or DISTINCT, and +** (17c) every term within the subquery compound must have a FROM clause +** (17d) the outer query may not be +** (17d1) aggregate, or +** (17d2) DISTINCT +** (17e) the subquery may not contain window functions, and +** (17f) the subquery must not be the RHS of a LEFT JOIN. ** ** The parent and sub-query may contain WHERE clauses. Subject to ** rules (11), (13) and (14), they may also contain ORDER BY, @@ -119113,10 +138225,10 @@ static void substSelect( ** syntax error and return a detailed message. ** ** (18) If the sub-query is a compound select, then all terms of the -** ORDER by clause of the parent must be simple references to -** columns of the sub-query. +** ORDER BY clause of the parent must be copies of a term returned +** by the parent query. ** -** (19) The subquery does not use LIMIT or the outer query does not +** (19) If the subquery uses LIMIT then the outer query may not ** have a WHERE clause. ** ** (20) If the sub-query is a compound select, then it must not use @@ -119125,25 +138237,30 @@ static void substSelect( ** appear as unmodified result columns in the outer query. But we ** have other optimizations in mind to deal with that case. ** -** (21) The subquery does not use LIMIT or the outer query is not +** (21) If the subquery uses LIMIT then the outer query may not be ** DISTINCT. (See ticket [752e1646fc]). ** -** (22) The subquery is not a recursive CTE. +** (22) The subquery may not be a recursive CTE. ** -** (23) The parent is not a recursive CTE, or the sub-query is not a -** compound query. This restriction is because transforming the +** (23) If the outer query is a recursive CTE, then the sub-query may not be +** a compound query. This restriction is because transforming the ** parent to a compound query confuses the code that handles ** recursive queries in multiSelect(). ** -** (24) The subquery is not an aggregate that uses the built-in min() or +** (**) We no longer attempt to flatten aggregate subqueries. Was: +** The subquery may not be an aggregate that uses the built-in min() or ** or max() functions. (Without this restriction, a query like: ** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily ** return the value X for which Y was maximal.) ** +** (25) If either the subquery or the parent query contains a window +** function in the select list or ORDER BY clause, flattening +** is not attempted. +** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query -** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. +** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. @@ -119155,8 +138272,7 @@ static int flattenSubquery( Parse *pParse, /* Parsing context */ Select *p, /* The parent or outer SELECT statement */ int iFrom, /* Index in p->pSrc->a[] of the inner subquery */ - int isAgg, /* True if outer SELECT uses aggregate functions */ - int subqueryIsAgg /* True if the subquery uses aggregate functions */ + int isAgg /* True if outer SELECT uses aggregate functions */ ){ const char *zSavedAuthContext = pParse->zAuthContext; Select *pParent; /* Current UNION ALL term of the other query */ @@ -119164,17 +138280,20 @@ static int flattenSubquery( Select *pSub1; /* Pointer to the rightmost select in sub-query */ SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ - ExprList *pList; /* The result set of the outer query */ int iParent; /* VDBE cursor number of the pSub result set temp table */ + int iNewParent = -1;/* Replacement table for iParent */ + int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */ int i; /* Loop counter */ Expr *pWhere; /* The WHERE clause */ - struct SrcList_item *pSubitem; /* The subquery */ + SrcItem *pSubitem; /* The subquery */ sqlite3 *db = pParse->db; + Walker w; /* Walker to persist agginfo data */ + int *aCsrMap = 0; /* Check to see if flattening is permitted. Return 0 if not. */ assert( p!=0 ); - assert( p->pPrior==0 ); /* Unable to flatten compound queries */ + assert( p->pPrior==0 ); if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; pSrc = p->pSrc; assert( pSrc && iFrom>=0 && iFromnSrc ); @@ -119182,17 +138301,11 @@ static int flattenSubquery( iParent = pSubitem->iCursor; pSub = pSubitem->pSelect; assert( pSub!=0 ); - if( subqueryIsAgg ){ - if( isAgg ) return 0; /* Restriction (1) */ - if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */ - if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery)) - || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0 - || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0 - ){ - return 0; /* Restriction (2b) */ - } - } - + +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */ +#endif + pSubSrc = pSub->pSrc; assert( pSubSrc ); /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants, @@ -119201,18 +138314,15 @@ static int flattenSubquery( ** became arbitrary expressions, we were forced to add restrictions (13) ** and (14). */ if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */ - if( pSub->pOffset ) return 0; /* Restriction (14) */ + if( pSub->pLimit && pSub->pLimit->pRight ) return 0; /* Restriction (14) */ if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){ return 0; /* Restriction (15) */ } if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */ - if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */ + if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */ if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){ return 0; /* Restrictions (8)(9) */ } - if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){ - return 0; /* Restriction (6) */ - } if( p->pOrderBy && pSub->pOrderBy ){ return 0; /* Restriction (11) */ } @@ -119221,19 +138331,14 @@ static int flattenSubquery( if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){ return 0; /* Restriction (21) */ } - testcase( pSub->selFlags & SF_Recursive ); - testcase( pSub->selFlags & SF_MinMaxAgg ); - if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){ - return 0; /* Restrictions (22) and (24) */ - } - if( (p->selFlags & SF_Recursive) && pSub->pPrior ){ - return 0; /* Restriction (23) */ + if( pSub->selFlags & (SF_Recursive) ){ + return 0; /* Restrictions (22) */ } - /* OBSOLETE COMMENT 1: - ** Restriction 3: If the subquery is a join, make sure the subquery is - ** not used as the right operand of an outer join. Examples of why this - ** is not allowed: + /* + ** If the subquery is the right operand of a LEFT JOIN, then the + ** subquery may not be a join itself (3a). Example of why this is not + ** allowed: ** ** t1 LEFT OUTER JOIN (t2 JOIN t3) ** @@ -119243,67 +138348,84 @@ static int flattenSubquery( ** ** which is not at all the same thing. ** - ** OBSOLETE COMMENT 2: - ** Restriction 12: If the subquery is the right operand of a left outer - ** join, make sure the subquery has no WHERE clause. - ** An examples of why this is not allowed: - ** - ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0) - ** - ** If we flatten the above, we would get - ** - ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0 - ** - ** But the t2.x>0 test will always fail on a NULL row of t2, which - ** effectively converts the OUTER JOIN into an INNER JOIN. + ** If the subquery is the right operand of a LEFT JOIN, then the outer + ** query cannot be an aggregate. (3c) This is an artifact of the way + ** aggregates are processed - there is no mechanism to determine if + ** the LEFT JOIN table should be all-NULL. ** - ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE: - ** Ticket #3300 shows that flattening the right term of a LEFT JOIN - ** is fraught with danger. Best to avoid the whole thing. If the - ** subquery is the right term of a LEFT JOIN, then do not flatten. + ** See also tickets #306, #350, and #3300. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ - return 0; + isLeftJoin = 1; + if( pSubSrc->nSrc>1 /* (3a) */ + || isAgg /* (3b) */ + || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */ + || (p->selFlags & SF_Distinct)!=0 /* (3d) */ + ){ + return 0; + } } +#ifdef SQLITE_EXTRA_IFNULLROW + else if( iFrom>0 && !isAgg ){ + /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for + ** every reference to any result column from subquery in a join, even + ** though they are not necessary. This will stress-test the OP_IfNullRow + ** opcode. */ + isLeftJoin = -1; + } +#endif - /* Restriction 17: If the sub-query is a compound SELECT, then it must + /* Restriction (17): If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. */ if( pSub->pPrior ){ if( pSub->pOrderBy ){ - return 0; /* Restriction 20 */ + return 0; /* Restriction (20) */ } - if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){ - return 0; + if( isAgg || (p->selFlags & SF_Distinct)!=0 || isLeftJoin>0 ){ + return 0; /* (17d1), (17d2), or (17f) */ } for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){ testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ); testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate ); assert( pSub->pSrc!=0 ); + assert( (pSub->selFlags & SF_Recursive)==0 ); assert( pSub->pEList->nExpr==pSub1->pEList->nExpr ); - if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 - || (pSub1->pPrior && pSub1->op!=TK_ALL) - || pSub1->pSrc->nSrc<1 + if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */ + || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */ + || pSub1->pSrc->nSrc<1 /* (17c) */ +#ifndef SQLITE_OMIT_WINDOWFUNC + || pSub1->pWin /* (17e) */ +#endif ){ return 0; } testcase( pSub1->pSrc->nSrc>1 ); } - /* Restriction 18. */ + /* Restriction (18). */ if( p->pOrderBy ){ int ii; for(ii=0; iipOrderBy->nExpr; ii++){ if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0; } } + + /* Restriction (23) */ + if( (p->selFlags & SF_Recursive) ) return 0; + + if( pSrc->nSrc>1 ){ + if( pParse->nSelect>500 ) return 0; + aCsrMap = sqlite3DbMallocZero(db, ((i64)pParse->nTab+1)*sizeof(int)); + if( aCsrMap ) aCsrMap[0] = pParse->nTab; + } } /***** If we reach this point, flattening is permitted. *****/ - SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n", - pSub->zSelName, pSub, iFrom)); + SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n", + pSub->selId, pSub, iFrom)); /* Authorize the subquery */ pParse->zAuthContext = pSubitem->zName; @@ -119311,14 +138433,25 @@ static int flattenSubquery( testcase( i==SQLITE_DENY ); pParse->zAuthContext = zSavedAuthContext; + /* Delete the transient structures associated with thesubquery */ + pSub1 = pSubitem->pSelect; + sqlite3DbFree(db, pSubitem->zDatabase); + sqlite3DbFree(db, pSubitem->zName); + sqlite3DbFree(db, pSubitem->zAlias); + pSubitem->zDatabase = 0; + pSubitem->zName = 0; + pSubitem->zAlias = 0; + pSubitem->pSelect = 0; + assert( pSubitem->pOn==0 ); + /* If the sub-query is a compound SELECT statement, then (by restrictions - ** 17 and 18 above) it must be a UNION ALL and the parent query must + ** 17 and 18 above) it must be a UNION ALL and the parent query must ** be of the form: ** - ** SELECT FROM () + ** SELECT FROM () ** ** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block - ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or + ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or ** OFFSET clauses and joins them to the left-hand-side of the original ** using UNION ALL operators. In this case N is the number of simple ** select statements in the compound sub-query. @@ -119348,49 +138481,38 @@ static int flattenSubquery( Select *pNew; ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; - Expr *pOffset = p->pOffset; Select *pPrior = p->pPrior; + Table *pItemTab = pSubitem->pTab; + pSubitem->pTab = 0; p->pOrderBy = 0; - p->pSrc = 0; p->pPrior = 0; p->pLimit = 0; - p->pOffset = 0; pNew = sqlite3SelectDup(db, p, 0); - sqlite3SelectSetName(pNew, pSub->zSelName); - p->pOffset = pOffset; p->pLimit = pLimit; p->pOrderBy = pOrderBy; - p->pSrc = pSrc; p->op = TK_ALL; + pSubitem->pTab = pItemTab; if( pNew==0 ){ p->pPrior = pPrior; }else{ + pNew->selId = ++pParse->nSelect; + if( aCsrMap && ALWAYS(db->mallocFailed==0) ){ + renumberCursors(pParse, pNew, iFrom, aCsrMap); + } pNew->pPrior = pPrior; if( pPrior ) pPrior->pNext = pNew; pNew->pNext = p; p->pPrior = pNew; - SELECTTRACE(2,pParse,p, - ("compound-subquery flattener creates %s.%p as peer\n", - pNew->zSelName, pNew)); + SELECTTRACE(2,pParse,p,("compound-subquery flattener" + " creates %u as peer\n",pNew->selId)); } - if( db->mallocFailed ) return 1; + assert( pSubitem->pSelect==0 ); + } + sqlite3DbFree(db, aCsrMap); + if( db->mallocFailed ){ + pSubitem->pSelect = pSub1; + return 1; } - - /* Begin flattening the iFrom-th entry of the FROM clause - ** in the outer query. - */ - pSub = pSub1 = pSubitem->pSelect; - - /* Delete the transient table structure associated with the - ** subquery - */ - sqlite3DbFree(db, pSubitem->zDatabase); - sqlite3DbFree(db, pSubitem->zName); - sqlite3DbFree(db, pSubitem->zAlias); - pSubitem->zDatabase = 0; - pSubitem->zName = 0; - pSubitem->zAlias = 0; - pSubitem->pSelect = 0; /* Defer deleting the Table object associated with the ** subquery until code generation is @@ -119403,8 +138525,10 @@ static int flattenSubquery( Table *pTabToDel = pSubitem->pTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); - pTabToDel->pNextZombie = pToplevel->pZombieTab; - pToplevel->pZombieTab = pTabToDel; + sqlite3ParserAddCleanup(pToplevel, + (void(*)(sqlite3*,void*))sqlite3DeleteTable, + pTabToDel); + testcase( pToplevel->earlyCleanup ); }else{ pTabToDel->nTabRef--; } @@ -119424,23 +138548,17 @@ static int flattenSubquery( ** those references with expressions that resolve to the subquery FROM ** elements we are now copying in. */ + pSub = pSub1; for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ int nSubSrc; u8 jointype = 0; + assert( pSub!=0 ); pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ pSrc = pParent->pSrc; /* FROM clause of the outer query */ - if( pSrc ){ - assert( pParent==p ); /* First time through the loop */ - jointype = pSubitem->fg.jointype; - }else{ - assert( pParent!=p ); /* 2nd and subsequent times through the loop */ - pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); - if( pSrc==0 ){ - assert( db->mallocFailed ); - break; - } + if( pParent==p ){ + jointype = pSubitem->fg.jointype; /* First time through the loop */ } /* The subquery uses a single slot of the FROM clause of the outer @@ -119459,10 +138577,9 @@ static int flattenSubquery( ** for the two elements in the FROM clause of the subquery. */ if( nSubSrc>1 ){ - pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1); - if( db->mallocFailed ){ - break; - } + pSrc = sqlite3SrcListEnlarge(pParse, pSrc, nSubSrc-1,iFrom+1); + if( pSrc==0 ) break; + pParent->pSrc = pSrc; } /* Transfer the FROM clause terms from the subquery into the @@ -119472,13 +138589,14 @@ static int flattenSubquery( sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing); assert( pSrc->a[i+iFrom].fg.isTabFunc==0 ); pSrc->a[i+iFrom] = pSubSrc->a[i]; + iNewParent = pSubSrc->a[i].iCursor; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } pSrc->a[iFrom].fg.jointype = jointype; - - /* Now begin substituting subquery result set expressions for + + /* Now begin substituting subquery result set expressions for ** references to the iParent in the outer query. - ** + ** ** Example: ** ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; @@ -119488,15 +138606,7 @@ static int flattenSubquery( ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ - pList = pParent->pEList; - for(i=0; inExpr; i++){ - if( pList->a[i].zName==0 ){ - char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan); - sqlite3Dequote(zName); - pList->a[i].zName = zName; - } - } - if( pSub->pOrderBy ){ + if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){ /* At this point, any non-zero iOrderByCol values indicate that the ** ORDER BY column expression is identical to the iOrderByCol'th ** expression returned by SELECT statement pSub. Since these values @@ -119512,30 +138622,36 @@ static int flattenSubquery( pOrderBy->a[i].u.x.iOrderByCol = 0; } assert( pParent->pOrderBy==0 ); - assert( pSub->pPrior==0 ); pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } - pWhere = sqlite3ExprDup(db, pSub->pWhere, 0); - if( subqueryIsAgg ){ - assert( pParent->pHaving==0 ); - pParent->pHaving = pParent->pWhere; - pParent->pWhere = pWhere; - pParent->pHaving = sqlite3ExprAnd(db, - sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving - ); - assert( pParent->pGroupBy==0 ); - pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0); - }else{ - pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); + pWhere = pSub->pWhere; + pSub->pWhere = 0; + if( isLeftJoin>0 ){ + sqlite3SetJoinExpr(pWhere, iNewParent); } - substSelect(pParse, pParent, iParent, pSub->pEList, 0); - - /* The flattened query is distinct if either the inner or the - ** outer query is distinct. - */ - pParent->selFlags |= pSub->selFlags & SF_Distinct; - + if( pWhere ){ + if( pParent->pWhere ){ + pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere); + }else{ + pParent->pWhere = pWhere; + } + } + if( db->mallocFailed==0 ){ + SubstContext x; + x.pParse = pParse; + x.iTable = iParent; + x.iNewTable = iNewParent; + x.isLeftJoin = isLeftJoin; + x.pEList = pSub->pEList; + substSelect(&x, pParent, 0); + } + + /* The flattened query is a compound if either the inner or the + ** outer query is a compound. */ + pParent->selFlags |= pSub->selFlags & SF_Compound; + assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */ + /* ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; ** @@ -119546,11 +138662,19 @@ static int flattenSubquery( pParent->pLimit = pSub->pLimit; pSub->pLimit = 0; } + + /* Recompute the SrcList_item.colUsed masks for the flattened + ** tables. */ + for(i=0; ia[i+iFrom]); + } } /* Finially, delete what is left of the subquery and return ** success. */ + sqlite3AggInfoPersistWalkerInit(&w, pParse); + sqlite3WalkSelect(&w,pSub1); sqlite3SelectDelete(db, pSub1); #if SELECTTRACE_ENABLED @@ -119564,7 +138688,286 @@ static int flattenSubquery( } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ +/* +** A structure to keep track of all of the column values that are fixed to +** a known value due to WHERE clause constraints of the form COLUMN=VALUE. +*/ +typedef struct WhereConst WhereConst; +struct WhereConst { + Parse *pParse; /* Parsing context */ + u8 *pOomFault; /* Pointer to pParse->db->mallocFailed */ + int nConst; /* Number for COLUMN=CONSTANT terms */ + int nChng; /* Number of times a constant is propagated */ + int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */ + Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */ +}; + +/* +** Add a new entry to the pConst object. Except, do not add duplicate +** pColumn entires. Also, do not add if doing so would not be appropriate. +** +** The caller guarantees the pColumn is a column and pValue is a constant. +** This routine has to do some additional checks before completing the +** insert. +*/ +static void constInsert( + WhereConst *pConst, /* The WhereConst into which we are inserting */ + Expr *pColumn, /* The COLUMN part of the constraint */ + Expr *pValue, /* The VALUE part of the constraint */ + Expr *pExpr /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */ +){ + int i; + assert( pColumn->op==TK_COLUMN ); + assert( sqlite3ExprIsConstant(pValue) ); + + if( ExprHasProperty(pColumn, EP_FixedCol) ) return; + if( sqlite3ExprAffinity(pValue)!=0 ) return; + if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){ + return; + } + + /* 2018-10-25 ticket [cf5ed20f] + ** Make sure the same pColumn is not inserted more than once */ + for(i=0; inConst; i++){ + const Expr *pE2 = pConst->apExpr[i*2]; + assert( pE2->op==TK_COLUMN ); + if( pE2->iTable==pColumn->iTable + && pE2->iColumn==pColumn->iColumn + ){ + return; /* Already present. Return without doing anything. */ + } + } + if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + pConst->bHasAffBlob = 1; + } + + pConst->nConst++; + pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, + pConst->nConst*2*sizeof(Expr*)); + if( pConst->apExpr==0 ){ + pConst->nConst = 0; + }else{ + pConst->apExpr[pConst->nConst*2-2] = pColumn; + pConst->apExpr[pConst->nConst*2-1] = pValue; + } +} + +/* +** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE +** is a constant expression and where the term must be true because it +** is part of the AND-connected terms of the expression. For each term +** found, add it to the pConst structure. +*/ +static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ + Expr *pRight, *pLeft; + if( NEVER(pExpr==0) ) return; + if( ExprHasProperty(pExpr, EP_FromJoin) ) return; + if( pExpr->op==TK_AND ){ + findConstInWhere(pConst, pExpr->pRight); + findConstInWhere(pConst, pExpr->pLeft); + return; + } + if( pExpr->op!=TK_EQ ) return; + pRight = pExpr->pRight; + pLeft = pExpr->pLeft; + assert( pRight!=0 ); + assert( pLeft!=0 ); + if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){ + constInsert(pConst,pRight,pLeft,pExpr); + } + if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){ + constInsert(pConst,pLeft,pRight,pExpr); + } +} + +/* +** This is a helper function for Walker callback propagateConstantExprRewrite(). +** +** Argument pExpr is a candidate expression to be replaced by a value. If +** pExpr is equivalent to one of the columns named in pWalker->u.pConst, +** then overwrite it with the corresponding value. Except, do not do so +** if argument bIgnoreAffBlob is non-zero and the affinity of pExpr +** is SQLITE_AFF_BLOB. +*/ +static int propagateConstantExprRewriteOne( + WhereConst *pConst, + Expr *pExpr, + int bIgnoreAffBlob +){ + int i; + if( pConst->pOomFault[0] ) return WRC_Prune; + if( pExpr->op!=TK_COLUMN ) return WRC_Continue; + if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){ + testcase( ExprHasProperty(pExpr, EP_FixedCol) ); + testcase( ExprHasProperty(pExpr, EP_FromJoin) ); + return WRC_Continue; + } + for(i=0; inConst; i++){ + Expr *pColumn = pConst->apExpr[i*2]; + if( pColumn==pExpr ) continue; + if( pColumn->iTable!=pExpr->iTable ) continue; + if( pColumn->iColumn!=pExpr->iColumn ) continue; + if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){ + break; + } + /* A match is found. Add the EP_FixedCol property */ + pConst->nChng++; + ExprClearProperty(pExpr, EP_Leaf); + ExprSetProperty(pExpr, EP_FixedCol); + assert( pExpr->pLeft==0 ); + pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0); + if( pConst->pParse->db->mallocFailed ) return WRC_Prune; + break; + } + return WRC_Prune; +} + +/* +** This is a Walker expression callback. pExpr is a node from the WHERE +** clause of a SELECT statement. This function examines pExpr to see if +** any substitutions based on the contents of pWalker->u.pConst should +** be made to pExpr or its immediate children. +** +** A substitution is made if: +** +** + pExpr is a column with an affinity other than BLOB that matches +** one of the columns in pWalker->u.pConst, or +** +** + pExpr is a binary comparison operator (=, <=, >=, <, >) that +** uses an affinity other than TEXT and one of its immediate +** children is a column that matches one of the columns in +** pWalker->u.pConst. +*/ +static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ + WhereConst *pConst = pWalker->u.pConst; + assert( TK_GT==TK_EQ+1 ); + assert( TK_LE==TK_EQ+2 ); + assert( TK_LT==TK_EQ+3 ); + assert( TK_GE==TK_EQ+4 ); + if( pConst->bHasAffBlob ){ + if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE) + || pExpr->op==TK_IS + ){ + propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0); + if( pConst->pOomFault[0] ) return WRC_Prune; + if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){ + propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0); + } + } + } + return propagateConstantExprRewriteOne(pConst, pExpr, pConst->bHasAffBlob); +} + +/* +** The WHERE-clause constant propagation optimization. +** +** If the WHERE clause contains terms of the form COLUMN=CONSTANT or +** CONSTANT=COLUMN that are top-level AND-connected terms that are not +** part of a ON clause from a LEFT JOIN, then throughout the query +** replace all other occurrences of COLUMN with CONSTANT. +** +** For example, the query: +** +** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b +** +** Is transformed into +** +** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=39 AND t3.c=39 +** +** Return true if any transformations where made and false if not. +** +** Implementation note: Constant propagation is tricky due to affinity +** and collating sequence interactions. Consider this example: +** +** CREATE TABLE t1(a INT,b TEXT); +** INSERT INTO t1 VALUES(123,'0123'); +** SELECT * FROM t1 WHERE a=123 AND b=a; +** SELECT * FROM t1 WHERE a=123 AND b=123; +** +** The two SELECT statements above should return different answers. b=a +** is alway true because the comparison uses numeric affinity, but b=123 +** is false because it uses text affinity and '0123' is not the same as '123'. +** To work around this, the expression tree is not actually changed from +** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol +** and the "123" value is hung off of the pLeft pointer. Code generator +** routines know to generate the constant "123" instead of looking up the +** column value. Also, to avoid collation problems, this optimization is +** only attempted if the "a=123" term uses the default BINARY collation. +** +** 2021-05-25 forum post 6a06202608: Another troublesome case is... +** +** CREATE TABLE t1(x); +** INSERT INTO t1 VALUES(10.0); +** SELECT 1 FROM t1 WHERE x=10 AND x LIKE 10; +** +** The query should return no rows, because the t1.x value is '10.0' not '10' +** and '10.0' is not LIKE '10'. But if we are not careful, the first WHERE +** term "x=10" will cause the second WHERE term to become "10 LIKE 10", +** resulting in a false positive. To avoid this, constant propagation for +** columns with BLOB affinity is only allowed if the constant is used with +** operators ==, <=, <, >=, >, or IS in a way that will cause the correct +** type conversions to occur. See logic associated with the bHasAffBlob flag +** for details. +*/ +static int propagateConstants( + Parse *pParse, /* The parsing context */ + Select *p /* The query in which to propagate constants */ +){ + WhereConst x; + Walker w; + int nChng = 0; + x.pParse = pParse; + x.pOomFault = &pParse->db->mallocFailed; + do{ + x.nConst = 0; + x.nChng = 0; + x.apExpr = 0; + x.bHasAffBlob = 0; + findConstInWhere(&x, p->pWhere); + if( x.nConst ){ + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.xExprCallback = propagateConstantExprRewrite; + w.xSelectCallback = sqlite3SelectWalkNoop; + w.xSelectCallback2 = 0; + w.walkerDepth = 0; + w.u.pConst = &x; + sqlite3WalkExpr(&w, p->pWhere); + sqlite3DbFree(x.pParse->db, x.apExpr); + nChng += x.nChng; + } + }while( x.nChng ); + return nChng; +} +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) +# if !defined(SQLITE_OMIT_WINDOWFUNC) +/* +** This function is called to determine whether or not it is safe to +** push WHERE clause expression pExpr down to FROM clause sub-query +** pSubq, which contains at least one window function. Return 1 +** if it is safe and the expression should be pushed down, or 0 +** otherwise. +** +** It is only safe to push the expression down if it consists only +** of constants and copies of expressions that appear in the PARTITION +** BY clause of all window function used by the sub-query. It is safe +** to filter out entire partitions, but not rows within partitions, as +** this may change the results of the window functions. +** +** At the time this function is called it is guaranteed that +** +** * the sub-query uses only one distinct window frame, and +** * that the window frame has a PARTITION BY clase. +*/ +static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){ + assert( pSubq->pWin->pPartition ); + assert( (pSubq->selFlags & SF_MultiPart)==0 ); + assert( pSubq->pPrior==0 ); + return sqlite3ExprIsConstantOrGroupBy(pParse, pExpr, pSubq->pWin->pPartition); +} +# endif /* SQLITE_OMIT_WINDOWFUNC */ +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* @@ -119583,21 +138986,54 @@ static int flattenSubquery( ** ** Do not attempt this optimization if: ** -** (1) The inner query is an aggregate. (In that case, we'd really want -** to copy the outer WHERE-clause terms onto the HAVING clause of the -** inner query. But they probably won't help there so do not bother.) +** (1) (** This restriction was removed on 2017-09-29. We used to +** disallow this optimization for aggregate subqueries, but now +** it is allowed by putting the extra terms on the HAVING clause. +** The added HAVING clause is pointless if the subquery lacks +** a GROUP BY clause. But such a HAVING clause is also harmless +** so there does not appear to be any reason to add extra logic +** to suppress it. **) ** ** (2) The inner query is the recursive part of a common table expression. ** ** (3) The inner query has a LIMIT clause (since the changes to the WHERE -** close would change the meaning of the LIMIT). +** clause would change the meaning of the LIMIT). ** -** (4) The inner query is the right operand of a LEFT JOIN. (The caller -** enforces this restriction since this routine does not have enough -** information to know.) +** (4) The inner query is the right operand of a LEFT JOIN and the +** expression to be pushed down does not come from the ON clause +** on that LEFT JOIN. ** ** (5) The WHERE clause expression originates in the ON or USING clause -** of a LEFT JOIN. +** of a LEFT JOIN where iCursor is not the right-hand table of that +** left join. An example: +** +** SELECT * +** FROM (SELECT 1 AS a1 UNION ALL SELECT 2) AS aa +** JOIN (SELECT 1 AS b2 UNION ALL SELECT 2) AS bb ON (a1=b2) +** LEFT JOIN (SELECT 8 AS c3 UNION ALL SELECT 9) AS cc ON (b2=2); +** +** The correct answer is three rows: (1,1,NULL),(2,2,8),(2,2,9). +** But if the (b2=2) term were to be pushed down into the bb subquery, +** then the (1,1,NULL) row would be suppressed. +** +** (6) Window functions make things tricky as changes to the WHERE clause +** of the inner query could change the window over which window +** functions are calculated. Therefore, do not attempt the optimization +** if: +** +** (6a) The inner query uses multiple incompatible window partitions. +** +** (6b) The inner query is a compound and uses window-functions. +** +** (6c) The WHERE clause does not consist entirely of constants and +** copies of expressions found in the PARTITION BY clause of +** all window-functions used by the sub-query. It is safe to +** filter out entire partitions, as this does not change the +** window over which any window-function is calculated. +** +** (7) The inner query is a Common Table Expression (CTE) that should +** be materialized. (This restriction is implemented in the calling +** routine.) ** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. @@ -119606,34 +139042,83 @@ static int pushDownWhereTerms( Parse *pParse, /* Parse context (for malloc() and error reporting) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ Expr *pWhere, /* The WHERE clause of the outer query */ - int iCursor /* Cursor number of the subquery */ + int iCursor, /* Cursor number of the subquery */ + int isLeftJoin /* True if pSubq is the right term of a LEFT JOIN */ ){ Expr *pNew; int nChng = 0; - Select *pX; /* For looping over compound SELECTs in pSubq */ if( pWhere==0 ) return 0; - for(pX=pSubq; pX; pX=pX->pPrior){ - if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){ - testcase( pX->selFlags & SF_Aggregate ); - testcase( pX->selFlags & SF_Recursive ); - testcase( pX!=pSubq ); - return 0; /* restrictions (1) and (2) */ + if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0; + +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pSubq->pPrior ){ + Select *pSel; + for(pSel=pSubq; pSel; pSel=pSel->pPrior){ + if( pSel->pWin ) return 0; /* restriction (6b) */ + } + }else{ + if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0; + } +#endif + +#ifdef SQLITE_DEBUG + /* Only the first term of a compound can have a WITH clause. But make + ** sure no other terms are marked SF_Recursive in case something changes + ** in the future. + */ + { + Select *pX; + for(pX=pSubq; pX; pX=pX->pPrior){ + assert( (pX->selFlags & (SF_Recursive))==0 ); } } +#endif + if( pSubq->pLimit!=0 ){ return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ - nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor); + nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, + iCursor, isLeftJoin); pWhere = pWhere->pLeft; } - if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */ + if( isLeftJoin + && (ExprHasProperty(pWhere,EP_FromJoin)==0 + || pWhere->w.iRightJoinTable!=iCursor) + ){ + return 0; /* restriction (4) */ + } + if( ExprHasProperty(pWhere,EP_FromJoin) + && pWhere->w.iRightJoinTable!=iCursor + ){ + return 0; /* restriction (5) */ + } if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; + pSubq->selFlags |= SF_PushDown; while( pSubq ){ + SubstContext x; pNew = sqlite3ExprDup(pParse->db, pWhere, 0); - pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList); - pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); + unsetJoinExpr(pNew, -1); + x.pParse = pParse; + x.iTable = iCursor; + x.iNewTable = iCursor; + x.isLeftJoin = 0; + x.pEList = pSubq->pEList; + pNew = substExpr(&x, pNew); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){ + /* Restriction 6c has prevented push-down in this case */ + sqlite3ExprDelete(pParse->db, pNew); + nChng--; + break; + } +#endif + if( pSubq->selFlags & SF_Aggregate ){ + pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew); + }else{ + pSubq->pWhere = sqlite3ExprAnd(pParse, pSubq->pWhere, pNew); + } pSubq = pSubq->pPrior; } } @@ -119642,55 +139127,75 @@ static int pushDownWhereTerms( #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* -** Based on the contents of the AggInfo structure indicated by the first -** argument, this function checks if the following are true: +** The pFunc is the only aggregate function in the query. Check to see +** if the query is a candidate for the min/max optimization. ** -** * the query contains just a single aggregate function, -** * the aggregate function is either min() or max(), and -** * the argument to the aggregate function is a column value. +** If the query is a candidate for the min/max optimization, then set +** *ppMinMax to be an ORDER BY clause to be used for the optimization +** and return either WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX depending on +** whether pFunc is a min() or max() function. ** -** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX -** is returned as appropriate. Also, *ppMinMax is set to point to the -** list of arguments passed to the aggregate before returning. +** If the query is not a candidate for the min/max optimization, return +** WHERE_ORDERBY_NORMAL (which must be zero). ** -** Or, if the conditions above are not met, *ppMinMax is set to 0 and -** WHERE_ORDERBY_NORMAL is returned. +** This routine must be called after aggregate functions have been +** located but before their arguments have been subjected to aggregate +** analysis. */ -static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){ - int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ - - *ppMinMax = 0; - if( pAggInfo->nFunc==1 ){ - Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */ - ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */ - - assert( pExpr->op==TK_AGG_FUNCTION ); - if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){ - const char *zFunc = pExpr->u.zToken; - if( sqlite3StrICmp(zFunc, "min")==0 ){ - eRet = WHERE_ORDERBY_MIN; - *ppMinMax = pEList; - }else if( sqlite3StrICmp(zFunc, "max")==0 ){ - eRet = WHERE_ORDERBY_MAX; - *ppMinMax = pEList; - } +static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){ + int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ + ExprList *pEList; /* Arguments to agg function */ + const char *zFunc; /* Name of aggregate function pFunc */ + ExprList *pOrderBy; + u8 sortFlags = 0; + + assert( *ppMinMax==0 ); + assert( pFunc->op==TK_AGG_FUNCTION ); + assert( !IsWindowFunc(pFunc) ); + assert( ExprUseXList(pFunc) ); + pEList = pFunc->x.pList; + if( pEList==0 + || pEList->nExpr!=1 + || ExprHasProperty(pFunc, EP_WinFunc) + || OptimizationDisabled(db, SQLITE_MinMaxOpt) + ){ + return eRet; + } + assert( !ExprHasProperty(pFunc, EP_IntValue) ); + zFunc = pFunc->u.zToken; + if( sqlite3StrICmp(zFunc, "min")==0 ){ + eRet = WHERE_ORDERBY_MIN; + if( sqlite3ExprCanBeNull(pEList->a[0].pExpr) ){ + sortFlags = KEYINFO_ORDER_BIGNULL; } + }else if( sqlite3StrICmp(zFunc, "max")==0 ){ + eRet = WHERE_ORDERBY_MAX; + sortFlags = KEYINFO_ORDER_DESC; + }else{ + return eRet; } - - assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 ); + *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0); + assert( pOrderBy!=0 || db->mallocFailed ); + if( pOrderBy ) pOrderBy->a[0].sortFlags = sortFlags; return eRet; } /* ** The select statement passed as the first argument is an aggregate query. -** The second argument is the associated aggregate-info object. This +** The second argument is the associated aggregate-info object. This ** function tests if the SELECT is of the form: ** ** SELECT count(*) FROM ** ** where table is a database table, not a sub-select or view. If the query ** does match this pattern, then a pointer to the Table object representing -** is returned. Otherwise, 0 is returned. +** is returned. Otherwise, NULL is returned. +** +** This routine checks to see if it is safe to use the count optimization. +** A correct answer is still obtained (though perhaps more slowly) if +** this routine returns NULL when it could have returned a table pointer. +** But returning the pointer when NULL should have been returned can +** result in incorrect answers and/or crashes. So, when in doubt, return NULL. */ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ Table *pTab; @@ -119698,20 +139203,27 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ assert( !p->pGroupBy ); - if( p->pWhere || p->pEList->nExpr!=1 - || p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect + if( p->pWhere + || p->pEList->nExpr!=1 + || p->pSrc->nSrc!=1 + || p->pSrc->a[0].pSelect + || pAggInfo->nFunc!=1 ){ return 0; } pTab = p->pSrc->a[0].pTab; + assert( pTab!=0 ); + assert( !IsView(pTab) ); + if( !IsOrdinaryTable(pTab) ) return 0; pExpr = p->pEList->a[0].pExpr; - assert( pTab && !pTab->pSelect && pExpr ); - - if( IsVirtual(pTab) ) return 0; + assert( pExpr!=0 ); if( pExpr->op!=TK_AGG_FUNCTION ) return 0; - if( NEVER(pAggInfo->nFunc==0) ) return 0; + if( pExpr->pAggInfo!=pAggInfo ) return 0; if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; - if( pExpr->flags&EP_Distinct ) return 0; + assert( pAggInfo->aFunc[0].pFExpr==pExpr ); + testcase( ExprHasProperty(pExpr, EP_Distinct) ); + testcase( ExprHasProperty(pExpr, EP_WinFunc) ); + if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0; return pTab; } @@ -119719,30 +139231,33 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ /* ** If the source-list item passed as an argument was augmented with an ** INDEXED BY clause, then try to locate the specified index. If there -** was such a clause and the named index cannot be found, return -** SQLITE_ERROR and leave an error in pParse. Otherwise, populate +** was such a clause and the named index cannot be found, return +** SQLITE_ERROR and leave an error in pParse. Otherwise, populate ** pFrom->pIndex and return SQLITE_OK. */ -SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){ - if( pFrom->pTab && pFrom->fg.isIndexedBy ){ - Table *pTab = pFrom->pTab; - char *zIndexedBy = pFrom->u1.zIndexedBy; - Index *pIdx; - for(pIdx=pTab->pIndex; - pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); - pIdx=pIdx->pNext - ); - if( !pIdx ){ - sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0); - pParse->checkSchema = 1; - return SQLITE_ERROR; - } - pFrom->pIBIndex = pIdx; +SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ + Table *pTab = pFrom->pTab; + char *zIndexedBy = pFrom->u1.zIndexedBy; + Index *pIdx; + assert( pTab!=0 ); + assert( pFrom->fg.isIndexedBy!=0 ); + + for(pIdx=pTab->pIndex; + pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); + pIdx=pIdx->pNext + ); + if( !pIdx ){ + sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0); + pParse->checkSchema = 1; + return SQLITE_ERROR; } + assert( pFrom->fg.isCte==0 ); + pFrom->u2.pIBIndex = pIdx; return SQLITE_OK; } + /* -** Detect compound SELECT statements that use an ORDER BY clause with +** Detect compound SELECT statements that use an ORDER BY clause with ** an alternative collating sequence. ** ** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ... @@ -119777,6 +139292,14 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){} if( pX==0 ) return WRC_Continue; a = p->pOrderBy->a; +#ifndef SQLITE_OMIT_WINDOWFUNC + /* If iOrderByCol is already non-zero, then it has already been matched + ** to a result column of the SELECT statement. This occurs when the + ** SELECT is rewritten for window-functions processing and then passed + ** to sqlite3SelectPrep() and similar a second time. The rewriting done + ** by this function is not required in this case. */ + if( a[0].u.x.iOrderByCol ) return WRC_Continue; +#endif for(i=p->pOrderBy->nExpr-1; i>=0; i--){ if( a[i].pExpr->flags & EP_Collate ) break; } @@ -119802,13 +139325,15 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ p->pPrior = 0; p->pNext = 0; p->pWith = 0; +#ifndef SQLITE_OMIT_WINDOWFUNC + p->pWinDefn = 0; +#endif p->selFlags &= ~SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); pNew->pPrior->pNext = pNew; pNew->pLimit = 0; - pNew->pOffset = 0; return WRC_Continue; } @@ -119817,7 +139342,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ ** arguments. If it does, leave an error message in pParse and return ** non-zero, since pFrom is not allowed to be a table-valued function. */ -static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){ +static int cannotBeFunction(Parse *pParse, SrcItem *pFrom){ if( pFrom->fg.isTabFunc ){ sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName); return 1; @@ -119827,9 +139352,9 @@ static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){ #ifndef SQLITE_OMIT_CTE /* -** Argument pWith (which may be NULL) points to a linked list of nested -** WITH contexts, from inner to outermost. If the table identified by -** FROM clause element pItem is really a common-table-expression (CTE) +** Argument pWith (which may be NULL) points to a linked list of nested +** WITH contexts, from inner to outermost. If the table identified by +** FROM clause element pItem is really a common-table-expression (CTE) ** then return a pointer to the CTE definition for that table. Otherwise ** return NULL. ** @@ -119838,21 +139363,22 @@ static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){ */ static struct Cte *searchWith( With *pWith, /* Current innermost WITH clause */ - struct SrcList_item *pItem, /* FROM clause element to resolve */ + SrcItem *pItem, /* FROM clause element to resolve */ With **ppContext /* OUT: WITH clause return value belongs to */ ){ - const char *zName; - if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){ - With *p; - for(p=pWith; p; p=p->pOuter){ - int i; - for(i=0; inCte; i++){ - if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){ - *ppContext = p; - return &p->a[i]; - } + const char *zName = pItem->zName; + With *p; + assert( pItem->zDatabase==0 ); + assert( zName!=0 ); + for(p=pWith; p; p=p->pOuter){ + int i; + for(i=0; inCte; i++){ + if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){ + *ppContext = p; + return &p->a[i]; } } + if( p->bView ) break; } return 0; } @@ -119862,55 +139388,92 @@ static struct Cte *searchWith( ** ** This routine pushes the WITH clause passed as the second argument ** onto the top of the stack. If argument bFree is true, then this -** WITH clause will never be popped from the stack. In this case it -** should be freed along with the Parse object. In other cases, when -** bFree==0, the With object will be freed along with the SELECT +** WITH clause will never be popped from the stack but should instead +** be freed along with the Parse object. In other cases, when +** bFree==0, the With object will be freed along with the SELECT ** statement with which it is associated. +** +** This routine returns a copy of pWith. Or, if bFree is true and +** the pWith object is destroyed immediately due to an OOM condition, +** then this routine return NULL. +** +** If bFree is true, do not continue to use the pWith pointer after +** calling this routine, Instead, use only the return value. */ -SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ - assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) ); +SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ if( pWith ){ - assert( pParse->pWith!=pWith ); - pWith->pOuter = pParse->pWith; - pParse->pWith = pWith; - if( bFree ) pParse->pWithToFree = pWith; + if( bFree ){ + pWith = (With*)sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3WithDelete, + pWith); + if( pWith==0 ) return 0; + } + if( pParse->nErr==0 ){ + assert( pParse->pWith!=pWith ); + pWith->pOuter = pParse->pWith; + pParse->pWith = pWith; + } } + return pWith; } /* -** This function checks if argument pFrom refers to a CTE declared by -** a WITH clause on the stack currently maintained by the parser. And, -** if currently processing a CTE expression, if it is a recursive -** reference to the current CTE. +** This function checks if argument pFrom refers to a CTE declared by +** a WITH clause on the stack currently maintained by the parser (on the +** pParse->pWith linked list). And if currently processing a CTE +** CTE expression, through routine checks to see if the reference is +** a recursive reference to the CTE. ** -** If pFrom falls into either of the two categories above, pFrom->pTab -** and other fields are populated accordingly. The caller should check -** (pFrom->pTab!=0) to determine whether or not a successful match -** was found. +** If pFrom matches a CTE according to either of these two above, pFrom->pTab +** and other fields are populated accordingly. ** -** Whether or not a match is found, SQLITE_OK is returned if no error -** occurs. If an error does occur, an error message is stored in the -** parser and some error code other than SQLITE_OK returned. +** Return 0 if no match is found. +** Return 1 if a match is found. +** Return 2 if an error condition is detected. */ -static int withExpand( - Walker *pWalker, - struct SrcList_item *pFrom +static int resolveFromTermToCte( + Parse *pParse, /* The parsing context */ + Walker *pWalker, /* Current tree walker */ + SrcItem *pFrom /* The FROM clause term to check */ ){ - Parse *pParse = pWalker->pParse; - sqlite3 *db = pParse->db; - struct Cte *pCte; /* Matched CTE (or NULL if no match) */ - With *pWith; /* WITH clause that pCte belongs to */ + Cte *pCte; /* Matched CTE (or NULL if no match) */ + With *pWith; /* The matching WITH */ assert( pFrom->pTab==0 ); - + if( pParse->pWith==0 ){ + /* There are no WITH clauses in the stack. No match is possible */ + return 0; + } + if( pParse->nErr ){ + /* Prior errors might have left pParse->pWith in a goofy state, so + ** go no further. */ + return 0; + } + if( pFrom->zDatabase!=0 ){ + /* The FROM term contains a schema qualifier (ex: main.t1) and so + ** it cannot possibly be a CTE reference. */ + return 0; + } + if( pFrom->fg.notCte ){ + /* The FROM term is specifically excluded from matching a CTE. + ** (1) It is part of a trigger that used to have zDatabase but had + ** zDatabase removed by sqlite3FixTriggerStep(). + ** (2) This is the first term in the FROM clause of an UPDATE. + */ + return 0; + } pCte = searchWith(pParse->pWith, pFrom, &pWith); if( pCte ){ + sqlite3 *db = pParse->db; Table *pTab; ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ + Select *pRecTerm; /* Left-most recursive term */ int bMayRecursive; /* True if compound joined by UNION [ALL] */ With *pSavedWith; /* Initial value of pParse->pWith */ + int iRecTab = -1; /* Cursor for recursive table */ + CteUse *pCteUse; /* If pCte->zCteErr is non-NULL at this point, then this is an illegal ** recursive reference to CTE pCte. Leave an error in pParse and return @@ -119918,62 +139481,98 @@ static int withExpand( ** In this case, proceed. */ if( pCte->zCteErr ){ sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName); - return SQLITE_ERROR; + return 2; } - if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR; + if( cannotBeFunction(pParse, pFrom) ) return 2; assert( pFrom->pTab==0 ); - pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); - if( pTab==0 ) return WRC_Abort; + pTab = sqlite3DbMallocZero(db, sizeof(Table)); + if( pTab==0 ) return 2; + pCteUse = pCte->pUse; + if( pCteUse==0 ){ + pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0])); + if( pCteUse==0 + || sqlite3ParserAddCleanup(pParse,sqlite3DbFree,pCteUse)==0 + ){ + sqlite3DbFree(db, pTab); + return 2; + } + pCteUse->eM10d = pCte->eM10d; + } + pFrom->pTab = pTab; pTab->nTabRef = 1; pTab->zName = sqlite3DbStrDup(db, pCte->zName); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); - if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; + if( db->mallocFailed ) return 2; + pFrom->pSelect->selFlags |= SF_CopyCte; assert( pFrom->pSelect ); + if( pFrom->fg.isIndexedBy ){ + sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); + return 2; + } + pFrom->fg.isCte = 1; + pFrom->u2.pCteUse = pCteUse; + pCteUse->nUse++; + if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){ + pCteUse->eM10d = M10d_Yes; + } /* Check if this is a recursive CTE. */ - pSel = pFrom->pSelect; + pRecTerm = pSel = pFrom->pSelect; bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); - if( bMayRecursive ){ + while( bMayRecursive && pRecTerm->op==pSel->op ){ int i; - SrcList *pSrc = pFrom->pSelect->pSrc; + SrcList *pSrc = pRecTerm->pSrc; + assert( pRecTerm->pPrior!=0 ); for(i=0; inSrc; i++){ - struct SrcList_item *pItem = &pSrc->a[i]; - if( pItem->zDatabase==0 - && pItem->zName!=0 + SrcItem *pItem = &pSrc->a[i]; + if( pItem->zDatabase==0 + && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) - ){ + ){ pItem->pTab = pTab; - pItem->fg.isRecursive = 1; pTab->nTabRef++; - pSel->selFlags |= SF_Recursive; + pItem->fg.isRecursive = 1; + if( pRecTerm->selFlags & SF_Recursive ){ + sqlite3ErrorMsg(pParse, + "multiple references to recursive table: %s", pCte->zName + ); + return 2; + } + pRecTerm->selFlags |= SF_Recursive; + if( iRecTab<0 ) iRecTab = pParse->nTab++; + pItem->iCursor = iRecTab; } } + if( (pRecTerm->selFlags & SF_Recursive)==0 ) break; + pRecTerm = pRecTerm->pPrior; } - /* Only one recursive reference is permitted. */ - if( pTab->nTabRef>2 ){ - sqlite3ErrorMsg( - pParse, "multiple references to recursive table: %s", pCte->zName - ); - return SQLITE_ERROR; - } - assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); - pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; - if( bMayRecursive ){ - Select *pPrior = pSel->pPrior; - assert( pPrior->pWith==0 ); - pPrior->pWith = pSel->pWith; - sqlite3WalkSelect(pWalker, pPrior); - pPrior->pWith = 0; + if( pSel->selFlags & SF_Recursive ){ + int rc; + assert( pRecTerm!=0 ); + assert( (pRecTerm->selFlags & SF_Recursive)==0 ); + assert( pRecTerm->pNext!=0 ); + assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 ); + assert( pRecTerm->pWith==0 ); + pRecTerm->pWith = pSel->pWith; + rc = sqlite3WalkSelect(pWalker, pRecTerm); + pRecTerm->pWith = 0; + if( rc ){ + pParse->pWith = pSavedWith; + return 2; + } }else{ - sqlite3WalkSelect(pWalker, pSel); + if( sqlite3WalkSelect(pWalker, pSel) ){ + pParse->pWith = pSavedWith; + return 2; + } } pParse->pWith = pWith; @@ -119985,7 +139584,7 @@ static int withExpand( pCte->zName, pEList->nExpr, pCte->pCols->nExpr ); pParse->pWith = pSavedWith; - return SQLITE_ERROR; + return 2; } pEList = pCte->pCols; } @@ -120001,35 +139600,68 @@ static int withExpand( } pCte->zCteErr = 0; pParse->pWith = pSavedWith; + return 1; /* Success */ } - - return SQLITE_OK; + return 0; /* No match */ } #endif #ifndef SQLITE_OMIT_CTE /* -** If the SELECT passed as the second argument has an associated WITH +** If the SELECT passed as the second argument has an associated WITH ** clause, pop it from the stack stored as part of the Parse object. ** ** This function is used as the xSelectCallback2() callback by ** sqlite3SelectExpand() when walking a SELECT tree to resolve table -** names and other FROM clause elements. +** names and other FROM clause elements. */ -static void selectPopWith(Walker *pWalker, Select *p){ +SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; - if( pParse->pWith && p->pPrior==0 ){ + if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){ With *pWith = findRightmost(p)->pWith; if( pWith!=0 ){ - assert( pParse->pWith==pWith ); + assert( pParse->pWith==pWith || pParse->nErr ); pParse->pWith = pWith->pOuter; } } } +#endif + +/* +** The SrcList_item structure passed as the second argument represents a +** sub-query in the FROM clause of a SELECT statement. This function +** allocates and populates the SrcList_item.pTab object. If successful, +** SQLITE_OK is returned. Otherwise, if an OOM error is encountered, +** SQLITE_NOMEM. +*/ +SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ + Select *pSel = pFrom->pSelect; + Table *pTab; + + assert( pSel ); + pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); + if( pTab==0 ) return SQLITE_NOMEM; + pTab->nTabRef = 1; + if( pFrom->zAlias ){ + pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias); + }else{ + pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId); + } + while( pSel->pPrior ){ pSel = pSel->pPrior; } + sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); + pTab->iPKey = -1; + pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); +#ifndef SQLITE_ALLOW_ROWID_IN_VIEW + /* The usual case - do not allow ROWID on a subquery */ + pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; #else -#define selectPopWith 0 + pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */ #endif + + return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; +} + /* ** This routine is a Walker callback for "expanding" a SELECT statement. ** "Expanding" means to do the following: @@ -120037,7 +139669,7 @@ static void selectPopWith(Walker *pWalker, Select *p){ ** (1) Make sure VDBE cursor numbers have been assigned to every ** element of the FROM clause. ** -** (2) Fill in the pTabList->a[].pTab fields in the SrcList that +** (2) Fill in the pTabList->a[].pTab fields in the SrcList that ** defines FROM clause. When views appear in the FROM clause, ** fill pTabList->a[].pSelect with a copy of the SELECT statement ** that implements the view. A copy is made of the view's SELECT @@ -120056,26 +139688,39 @@ static void selectPopWith(Walker *pWalker, Select *p){ */ static int selectExpander(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; - int i, j, k; + int i, j, k, rc; SrcList *pTabList; ExprList *pEList; - struct SrcList_item *pFrom; + SrcItem *pFrom; sqlite3 *db = pParse->db; Expr *pE, *pRight, *pExpr; u16 selFlags = p->selFlags; + u32 elistFlags = 0; p->selFlags |= SF_Expanded; if( db->mallocFailed ){ return WRC_Abort; } - if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){ + assert( p->pSrc!=0 ); + if( (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } + if( pWalker->eCode ){ + /* Renumber selId because it has been copied from a view */ + p->selId = ++pParse->nSelect; + } pTabList = p->pSrc; pEList = p->pEList; - if( p->pWith ){ - sqlite3WithPush(pParse, p->pWith, 0); + if( pParse->pWith && (p->selFlags & SF_View) ){ + if( p->pWith==0 ){ + p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With)); + if( p->pWith==0 ){ + return WRC_Abort; + } + } + p->pWith->bView = 1; } + sqlite3WithPush(pParse, p->pWith, 0); /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. @@ -120089,12 +139734,8 @@ static int selectExpander(Walker *pWalker, Select *p){ for(i=0, pFrom=pTabList->a; inSrc; i++, pFrom++){ Table *pTab; assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); - if( pFrom->fg.isRecursive ) continue; - assert( pFrom->pTab==0 ); -#ifndef SQLITE_OMIT_CTE - if( withExpand(pWalker, pFrom) ) return WRC_Abort; - if( pFrom->pTab ) {} else -#endif + if( pFrom->pTab ) continue; + assert( pFrom->fg.isRecursive==0 ); if( pFrom->zName==0 ){ #ifndef SQLITE_OMIT_SUBQUERY Select *pSel = pFrom->pSelect; @@ -120102,15 +139743,13 @@ static int selectExpander(Walker *pWalker, Select *p){ assert( pSel!=0 ); assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; - pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); - if( pTab==0 ) return WRC_Abort; - pTab->nTabRef = 1; - pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab); - while( pSel->pPrior ){ pSel = pSel->pPrior; } - sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); - pTab->iPKey = -1; - pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); - pTab->tabFlags |= TF_Ephemeral; + if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; +#endif +#ifndef SQLITE_OMIT_CTE + }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){ + if( rc>1 ) return WRC_Abort; + pTab = pFrom->pTab; + assert( pTab!=0 ); #endif }else{ /* An ordinary table or view name in the FROM clause */ @@ -120127,30 +139766,52 @@ static int selectExpander(Walker *pWalker, Select *p){ if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){ return WRC_Abort; } -#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) - if( IsVirtual(pTab) || pTab->pSelect ){ +#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) + if( !IsOrdinaryTable(pTab) ){ i16 nCol; + u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); - pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); - sqlite3SelectSetName(pFrom->pSelect, pTab->zName); + if( IsView(pTab) ){ + if( (db->flags & SQLITE_EnableView)==0 + && pTab->pSchema!=db->aDb[1].pSchema + ){ + sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", + pTab->zName); + } + pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); + } +#ifndef SQLITE_OMIT_VIRTUALTABLE + else if( ALWAYS(IsVirtual(pTab)) + && pFrom->fg.fromDDL + && ALWAYS(pTab->u.vtab.p!=0) + && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) + ){ + sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"", + pTab->zName); + } + assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 ); +#endif nCol = pTab->nCol; pTab->nCol = -1; + pWalker->eCode = 1; /* Turn on Select.selId renumbering */ sqlite3WalkSelect(pWalker, pFrom->pSelect); + pWalker->eCode = eCodeOrig; pTab->nCol = nCol; } #endif } /* Locate the index named by the INDEXED BY clause, if any. */ - if( sqlite3IndexedByLookup(pParse, pFrom) ){ + if( pFrom->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pFrom) ){ return WRC_Abort; } } /* Process NATURAL keywords, and ON and USING clauses of joins. */ - if( db->mallocFailed || sqliteProcessJoin(pParse, p) ){ + assert( db->mallocFailed==0 || pParse->nErr!=0 ); + if( pParse->nErr || sqliteProcessJoin(pParse, p) ){ return WRC_Abort; } @@ -120171,6 +139832,7 @@ static int selectExpander(Walker *pWalker, Select *p){ assert( pE->op!=TK_DOT || pE->pRight!=0 ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break; + elistFlags |= pE->flags; } if( knExpr ){ /* @@ -120186,6 +139848,7 @@ static int selectExpander(Walker *pWalker, Select *p){ for(k=0; knExpr; k++){ pE = a[k].pExpr; + elistFlags |= pE->flags; pRight = pE->pRight; assert( pE->op!=TK_DOT || pRight!=0 ); if( pE->op!=TK_ASTERISK @@ -120195,10 +139858,9 @@ static int selectExpander(Walker *pWalker, Select *p){ */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); if( pNew ){ - pNew->a[pNew->nExpr-1].zName = a[k].zName; - pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan; - a[k].zName = 0; - a[k].zSpan = 0; + pNew->a[pNew->nExpr-1].zEName = a[k].zEName; + pNew->a[pNew->nExpr-1].eEName = a[k].eEName; + a[k].zEName = 0; } a[k].pExpr = 0; }else{ @@ -120230,14 +139892,14 @@ static int selectExpander(Walker *pWalker, Select *p){ zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*"; } for(j=0; jnCol; j++){ - char *zName = pTab->aCol[j].zName; + char *zName = pTab->aCol[j].zCnName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ Token sColname; /* Computed column name as a token */ assert( zName ); if( zTName && pSub - && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0 + && sqlite3MatchEName(&pSub->pEList->a[j], 0, zTName, 0)==0 ){ continue; } @@ -120247,7 +139909,7 @@ static int selectExpander(Walker *pWalker, Select *p){ ** bit set. */ if( (p->selFlags & SF_IncludeHidden)==0 - && IsHiddenColumn(&pTab->aCol[j]) + && IsHiddenColumn(&pTab->aCol[j]) ){ continue; } @@ -120255,9 +139917,9 @@ static int selectExpander(Walker *pWalker, Select *p){ if( i>0 && zTName==0 ){ if( (pFrom->fg.jointype & JT_NATURAL)!=0 - && tableAndColumnIndex(pTabList, i, zName, 0, 0) + && tableAndColumnIndex(pTabList, i, zName, 0, 0, 1) ){ - /* In a NATURAL join, omit the join columns from the + /* In a NATURAL join, omit the join columns from the ** table to the right of the join */ continue; } @@ -120288,17 +139950,18 @@ static int selectExpander(Walker *pWalker, Select *p){ pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sqlite3TokenInit(&sColname, zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); - if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){ + if( pNew && (p->selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; + sqlite3DbFree(db, pX->zEName); if( pSub ){ - pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan); - testcase( pX->zSpan==0 ); + pX->zEName = sqlite3DbStrDup(db, pSub->pEList->a[j].zEName); + testcase( pX->zEName==0 ); }else{ - pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s", + pX->zEName = sqlite3MPrintf(db, "%s.%s.%s", zSchemaName, zTabName, zColname); - testcase( pX->zSpan==0 ); + testcase( pX->zEName==0 ); } - pX->bSpanIsTab = 1; + pX->eEName = ENAME_TAB; } sqlite3DbFree(db, zToFree); } @@ -120315,29 +139978,28 @@ static int selectExpander(Walker *pWalker, Select *p){ sqlite3ExprListDelete(db, pEList); p->pEList = pNew; } -#if SQLITE_MAX_COLUMN - if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ - sqlite3ErrorMsg(pParse, "too many columns in result set"); - return WRC_Abort; + if( p->pEList ){ + if( p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ + sqlite3ErrorMsg(pParse, "too many columns in result set"); + return WRC_Abort; + } + if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){ + p->selFlags |= SF_ComplexResult; + } } -#endif return WRC_Continue; } +#if SQLITE_DEBUG /* -** No-op routine for the parse-tree walker. -** -** When this routine is the Walker.xExprCallback then expression trees -** are walked without any actions being taken at each node. Presumably, -** when this routine is used for Walker.xExprCallback then -** Walker.xSelectCallback is set to do something useful for every -** subquery in the parser tree. +** Always assert. This xSelectCallback2 implementation proves that the +** xSelectCallback2 is never invoked. */ -SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ +SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){ UNUSED_PARAMETER2(NotUsed, NotUsed2); - return WRC_Continue; + assert( 0 ); } - +#endif /* ** This routine "expands" a SELECT statement and all of its subqueries. ** For additional information on what it means to "expand" a SELECT @@ -120353,15 +140015,16 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){ */ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ Walker w; - memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; - if( pParse->hasCompound ){ + if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; + w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; - w.xSelectCallback2 = selectPopWith; + w.xSelectCallback2 = sqlite3SelectPopWith; + w.eCode = 0; sqlite3WalkSelect(&w, pSelect); } @@ -120384,10 +140047,10 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Parse *pParse; int i; SrcList *pTabList; - struct SrcList_item *pFrom; + SrcItem *pFrom; assert( p->selFlags & SF_Resolved ); - assert( (p->selFlags & SF_HasTypeInfo)==0 ); + if( p->selFlags & SF_HasTypeInfo ) return; p->selFlags |= SF_HasTypeInfo; pParse = pWalker->pParse; pTabList = p->pSrc; @@ -120399,7 +140062,8 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ Select *pSel = pFrom->pSelect; if( pSel ){ while( pSel->pPrior ) pSel = pSel->pPrior; - sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel); + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel, + SQLITE_AFF_NONE); } } } @@ -120417,7 +140081,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){ #ifndef SQLITE_OMIT_SUBQUERY Walker w; - memset(&w, 0, sizeof(w)); + w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = selectAddSubqueryTypeInfo; w.xExprCallback = sqlite3ExprWalkNoop; w.pParse = pParse; @@ -120443,15 +140107,14 @@ SQLITE_PRIVATE void sqlite3SelectPrep( Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ - sqlite3 *db; - if( NEVER(p==0) ) return; - db = pParse->db; - if( db->mallocFailed ) return; + assert( p!=0 || pParse->db->mallocFailed ); + assert( pParse->db->pParse==pParse ); + if( pParse->db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); - if( pParse->nErr || db->mallocFailed ) return; + if( pParse->nErr ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); - if( pParse->nErr || db->mallocFailed ) return; + if( pParse->nErr ) return; sqlite3SelectAddTypeInfo(pParse, p); } @@ -120468,7 +140131,10 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ int i; struct AggInfo_func *pFunc; int nReg = pAggInfo->nFunc + pAggInfo->nColumn; + assert( pParse->db->pParse==pParse ); + assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); if( nReg==0 ) return; + if( pParse->nErr ) return; #ifdef SQLITE_DEBUG /* Verify that all AggInfo registers are within the range specified by ** AggInfo.mnReg..AggInfo.mxReg */ @@ -120485,16 +140151,18 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg); for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ if( pFunc->iDistinct>=0 ){ - Expr *pE = pFunc->pExpr; - assert( !ExprHasProperty(pE, EP_xIsSelect) ); + Expr *pE = pFunc->pFExpr; + assert( ExprUseXList(pE) ); if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){ sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one " "argument"); pFunc->iDistinct = -1; }else{ - KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0); - sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, - (char*)pKeyInfo, P4_KEYINFO); + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0); + pFunc->iDistAddr = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, + pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); + ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(DISTINCT)", + pFunc->pFunc->zName)); } } } @@ -120509,18 +140177,30 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ int i; struct AggInfo_func *pF; for(i=0, pF=pAggInfo->aFunc; inFunc; i++, pF++){ - ExprList *pList = pF->pExpr->x.pList; - assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + ExprList *pList; + assert( ExprUseXList(pF->pFExpr) ); + pList = pF->pFExpr->x.pList; sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); } } + /* ** Update the accumulator memory cells for an aggregate based on ** the current cursor position. +** +** If regAcc is non-zero and there are no min() or max() aggregates +** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator +** registers if register regAcc contains 0. The caller will take care +** of setting and clearing regAcc. */ -static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ +static void updateAccumulator( + Parse *pParse, + int regAcc, + AggInfo *pAggInfo, + int eDistinctType +){ Vdbe *v = pParse->pVdbe; int i; int regHit = 0; @@ -120533,8 +140213,32 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ int nArg; int addrNext = 0; int regAgg; - ExprList *pList = pF->pExpr->x.pList; - assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); + ExprList *pList; + assert( ExprUseXList(pF->pFExpr) ); + assert( !IsWindowFunc(pF->pFExpr) ); + pList = pF->pFExpr->x.pList; + if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){ + Expr *pFilter = pF->pFExpr->y.pWin->pFilter; + if( pAggInfo->nAccumulator + && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) + && regAcc + ){ + /* If regAcc==0, there there exists some min() or max() function + ** without a FILTER clause that will ensure the magnet registers + ** are populated. */ + if( regHit==0 ) regHit = ++pParse->nMem; + /* If this is the first row of the group (regAcc contains 0), clear the + ** "magnet" register regHit so that the accumulator registers + ** are populated if the FILTER clause jumps over the the + ** invocation of min() or max() altogether. Or, if this is not + ** the first row (regAcc contains 1), set the magnet register so that + ** the accumulators are not populated unless the min()/max() is invoked + ** and indicates that they should be. */ + sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit); + } + addrNext = sqlite3VdbeMakeLabel(pParse); + sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL); + } if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); @@ -120543,11 +140247,12 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ nArg = 0; regAgg = 0; } - if( pF->iDistinct>=0 ){ - addrNext = sqlite3VdbeMakeLabel(v); - testcase( nArg==0 ); /* Error condition */ - testcase( nArg>1 ); /* Also an error */ - codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg); + if( pF->iDistinct>=0 && pList ){ + if( addrNext==0 ){ + addrNext = sqlite3VdbeMakeLabel(pParse); + } + pF->iDistinct = codeDistinct(pParse, eDistinctType, + pF->iDistinct, addrNext, pList, regAgg); } if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl = 0; @@ -120563,38 +140268,27 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } - sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem); + sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); - sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); - sqlite3ExprCacheClear(pParse); } } - - /* Before populating the accumulator registers, clear the column cache. - ** Otherwise, if any of the required column values are already present - ** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value - ** to pC->iMem. But by the time the value is used, the original register - ** may have been used, invalidating the underlying buffer holding the - ** text or blob value. See ticket [883034dcb5]. - ** - ** Another solution would be to change the OP_SCopy used to copy cached - ** values to an OP_Copy. - */ + if( regHit==0 && pAggInfo->nAccumulator ){ + regHit = regAcc; + } if( regHit ){ addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); } - sqlite3ExprCacheClear(pParse); for(i=0, pC=pAggInfo->aCol; inAccumulator; i++, pC++){ - sqlite3ExprCode(pParse, pC->pExpr, pC->iMem); + sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem); } + pAggInfo->directMode = 0; - sqlite3ExprCacheClear(pParse); if( addrHitTest ){ - sqlite3VdbeJumpHere(v, addrHitTest); + sqlite3VdbeJumpHereOrPopInst(v, addrHitTest); } } @@ -120610,14 +140304,11 @@ static void explainSimpleCount( ){ if( pParse->explain==2 ){ int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); - char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", + sqlite3VdbeExplain(pParse, 0, "SCAN %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" ); - sqlite3VdbeAddOp4( - pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC - ); } } #else @@ -120625,7 +140316,212 @@ static void explainSimpleCount( #endif /* -** Generate code for the SELECT statement given in the p argument. +** sqlite3WalkExpr() callback used by havingToWhere(). +** +** If the node passed to the callback is a TK_AND node, return +** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes. +** +** Otherwise, return WRC_Prune. In this case, also check if the +** sub-expression matches the criteria for being moved to the WHERE +** clause. If so, add it to the WHERE clause and replace the sub-expression +** within the HAVING expression with a constant "1". +*/ +static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ + if( pExpr->op!=TK_AND ){ + Select *pS = pWalker->u.pSelect; + /* This routine is called before the HAVING clause of the current + ** SELECT is analyzed for aggregates. So if pExpr->pAggInfo is set + ** here, it indicates that the expression is a correlated reference to a + ** column from an outer aggregate query, or an aggregate function that + ** belongs to an outer query. Do not move the expression to the WHERE + ** clause in this obscure case, as doing so may corrupt the outer Select + ** statements AggInfo structure. */ + if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) + && ExprAlwaysFalse(pExpr)==0 + && pExpr->pAggInfo==0 + ){ + sqlite3 *db = pWalker->pParse->db; + Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1"); + if( pNew ){ + Expr *pWhere = pS->pWhere; + SWAP(Expr, *pNew, *pExpr); + pNew = sqlite3ExprAnd(pWalker->pParse, pWhere, pNew); + pS->pWhere = pNew; + pWalker->eCode = 1; + } + } + return WRC_Prune; + } + return WRC_Continue; +} + +/* +** Transfer eligible terms from the HAVING clause of a query, which is +** processed after grouping, to the WHERE clause, which is processed before +** grouping. For example, the query: +** +** SELECT * FROM WHERE a=? GROUP BY b HAVING b=? AND c=? +** +** can be rewritten as: +** +** SELECT * FROM WHERE a=? AND b=? GROUP BY b HAVING c=? +** +** A term of the HAVING expression is eligible for transfer if it consists +** entirely of constants and expressions that are also GROUP BY terms that +** use the "BINARY" collation sequence. +*/ +static void havingToWhere(Parse *pParse, Select *p){ + Walker sWalker; + memset(&sWalker, 0, sizeof(sWalker)); + sWalker.pParse = pParse; + sWalker.xExprCallback = havingToWhereExprCb; + sWalker.u.pSelect = p; + sqlite3WalkExpr(&sWalker, p->pHaving); +#if SELECTTRACE_ENABLED + if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){ + SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif +} + +/* +** Check to see if the pThis entry of pTabList is a self-join of a prior view. +** If it is, then return the SrcList_item for the prior view. If it is not, +** then return 0. +*/ +static SrcItem *isSelfJoinView( + SrcList *pTabList, /* Search for self-joins in this FROM clause */ + SrcItem *pThis /* Search for prior reference to this subquery */ +){ + SrcItem *pItem; + assert( pThis->pSelect!=0 ); + if( pThis->pSelect->selFlags & SF_PushDown ) return 0; + for(pItem = pTabList->a; pItempSelect==0 ) continue; + if( pItem->fg.viaCoroutine ) continue; + if( pItem->zName==0 ) continue; + assert( pItem->pTab!=0 ); + assert( pThis->pTab!=0 ); + if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; + if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; + pS1 = pItem->pSelect; + if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ + /* The query flattener left two different CTE tables with identical + ** names in the same FROM clause. */ + continue; + } + if( pItem->pSelect->selFlags & SF_PushDown ){ + /* The view was modified by some other optimization such as + ** pushDownWhereTerms() */ + continue; + } + return pItem; + } + return 0; +} + +/* +** Deallocate a single AggInfo object +*/ +static void agginfoFree(sqlite3 *db, AggInfo *p){ + sqlite3DbFree(db, p->aCol); + sqlite3DbFree(db, p->aFunc); + sqlite3DbFreeNN(db, p); +} + +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION +/* +** Attempt to transform a query of the form +** +** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2) +** +** Into this: +** +** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) +** +** The transformation only works if all of the following are true: +** +** * The subquery is a UNION ALL of two or more terms +** * The subquery does not have a LIMIT clause +** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries +** * The outer query is a simple count(*) with no WHERE clause or other +** extraneous syntax. +** +** Return TRUE if the optimization is undertaken. +*/ +static int countOfViewOptimization(Parse *pParse, Select *p){ + Select *pSub, *pPrior; + Expr *pExpr; + Expr *pCount; + sqlite3 *db; + if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ + if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ + if( p->pWhere ) return 0; + if( p->pGroupBy ) return 0; + pExpr = p->pEList->a[0].pExpr; + if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ + assert( ExprUseUToken(pExpr) ); + if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ + assert( ExprUseXList(pExpr) ); + if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ + if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ + pSub = p->pSrc->a[0].pSelect; + if( pSub==0 ) return 0; /* The FROM is a subquery */ + if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */ + do{ + if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ + if( pSub->pWhere ) return 0; /* No WHERE clause */ + if( pSub->pLimit ) return 0; /* No LIMIT clause */ + if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ + pSub = pSub->pPrior; /* Repeat over compound */ + }while( pSub ); + + /* If we reach this point then it is OK to perform the transformation */ + + db = pParse->db; + pCount = pExpr; + pExpr = 0; + pSub = p->pSrc->a[0].pSelect; + p->pSrc->a[0].pSelect = 0; + sqlite3SrcListDelete(db, p->pSrc); + p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); + while( pSub ){ + Expr *pTerm; + pPrior = pSub->pPrior; + pSub->pPrior = 0; + pSub->pNext = 0; + pSub->selFlags |= SF_Aggregate; + pSub->selFlags &= ~SF_Compound; + pSub->nSelectRow = 0; + sqlite3ExprListDelete(db, pSub->pEList); + pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount; + pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm); + pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, pTerm, pSub); + if( pExpr==0 ){ + pExpr = pTerm; + }else{ + pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); + } + pSub = pPrior; + } + p->pEList->a[0].pExpr = pExpr; + p->selFlags &= ~SF_Aggregate; + +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + return 1; +} +#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */ + +/* +** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. @@ -120651,27 +140547,25 @@ SQLITE_PRIVATE int sqlite3Select( Expr *pWhere; /* The WHERE clause. May be NULL */ ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */ Expr *pHaving; /* The HAVING clause. May be NULL */ + AggInfo *pAggInfo = 0; /* Aggregate information */ int rc = 1; /* Value to return from this function */ DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */ SortCtx sSort; /* Info on how to code the ORDER BY clause */ - AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ - -#ifndef SQLITE_OMIT_EXPLAIN - int iRestoreSelectId = pParse->iSelectId; - pParse->iSelectId = pParse->iNextSelectId++; -#endif + ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */ + u8 minMaxFlag; /* Flag for min/max queries */ db = pParse->db; - if( p==0 || db->mallocFailed || pParse->nErr ){ + assert( pParse==db->pParse ); + v = sqlite3GetVdbe(pParse); + if( p==0 || pParse->nErr ){ return 1; } + assert( db->mallocFailed==0 ); if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; - memset(&sAggInfo, 0, sizeof(sAggInfo)); #if SELECTTRACE_ENABLED - pParse->nSelectIndent++; - SELECTTRACE(1,pParse,p, ("begin processing:\n")); + SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain)); if( sqlite3SelectTrace & 0x100 ){ sqlite3TreeViewSelect(0, p, 0); } @@ -120681,41 +140575,118 @@ SQLITE_PRIVATE int sqlite3Select( assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); - if( IgnorableOrderby(pDest) ){ - assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || - pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || - pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo || - pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo); - /* If ORDER BY makes no difference in the output then neither does - ** DISTINCT so it can be removed too. */ - sqlite3ExprListDelete(db, p->pOrderBy); - p->pOrderBy = 0; + if( IgnorableDistinct(pDest) ){ + assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || + pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || + pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo ); + /* All of these destinations are also able to ignore the ORDER BY clause */ + if( p->pOrderBy ){ +#if SELECTTRACE_ENABLED + SELECTTRACE(1,pParse,p, ("dropping superfluous ORDER BY:\n")); + if( sqlite3SelectTrace & 0x100 ){ + sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY"); + } +#endif + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3ExprListDelete, + p->pOrderBy); + testcase( pParse->earlyCleanup ); + p->pOrderBy = 0; + } p->selFlags &= ~SF_Distinct; + p->selFlags |= SF_NoopOrderBy; } sqlite3SelectPrep(pParse, p, 0); - memset(&sSort, 0, sizeof(sSort)); - sSort.pOrderBy = p->pOrderBy; - pTabList = p->pSrc; - if( pParse->nErr || db->mallocFailed ){ + if( pParse->nErr ){ goto select_end; } + assert( db->mallocFailed==0 ); assert( p->pEList!=0 ); - isAgg = (p->selFlags & SF_Aggregate)!=0; #if SELECTTRACE_ENABLED - if( sqlite3SelectTrace & 0x100 ){ - SELECTTRACE(0x100,pParse,p, ("after name resolution:\n")); + if( sqlite3SelectTrace & 0x104 ){ + SELECTTRACE(0x104,pParse,p, ("after name resolution:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + + /* If the SF_UFSrcCheck flag is set, then this function is being called + ** as part of populating the temp table for an UPDATE...FROM statement. + ** In this case, it is an error if the target object (pSrc->a[0]) name + ** or alias is duplicated within FROM clause (pSrc->a[1..n]). + ** + ** Postgres disallows this case too. The reason is that some other + ** systems handle this case differently, and not all the same way, + ** which is just confusing. To avoid this, we follow PG's lead and + ** disallow it altogether. */ + if( p->selFlags & SF_UFSrcCheck ){ + SrcItem *p0 = &p->pSrc->a[0]; + for(i=1; ipSrc->nSrc; i++){ + SrcItem *p1 = &p->pSrc->a[i]; + if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ + sqlite3ErrorMsg(pParse, + "target object/alias may not appear in FROM clause: %s", + p0->zAlias ? p0->zAlias : p0->pTab->zName + ); + goto select_end; + } + } + + /* Clear the SF_UFSrcCheck flag. The check has already been performed, + ** and leaving this flag set can cause errors if a compound sub-query + ** in p->pSrc is flattened into this query and this function called + ** again as part of compound SELECT processing. */ + p->selFlags &= ~SF_UFSrcCheck; + } + + if( pDest->eDest==SRT_Output ){ + sqlite3GenerateColumnNames(pParse, p); + } + +#ifndef SQLITE_OMIT_WINDOWFUNC + if( sqlite3WindowRewrite(pParse, p) ){ + assert( pParse->nErr ); + goto select_end; + } +#if SELECTTRACE_ENABLED + if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){ + SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif +#endif /* SQLITE_OMIT_WINDOWFUNC */ + pTabList = p->pSrc; + isAgg = (p->selFlags & SF_Aggregate)!=0; + memset(&sSort, 0, sizeof(sSort)); + sSort.pOrderBy = p->pOrderBy; - /* Try to flatten subqueries in the FROM clause up into the main query + /* Try to do various optimizations (flattening subqueries, and strength + ** reduction of join operators) in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && inSrc; i++){ - struct SrcList_item *pItem = &pTabList->a[i]; + SrcItem *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; - int isAggSub; Table *pTab = pItem->pTab; + + /* The expander should have already created transient Table objects + ** even for FROM clause elements such as subqueries that do not correspond + ** to a real table */ + assert( pTab!=0 ); + + /* Convert LEFT JOIN into JOIN if there are terms of the right table + ** of the LEFT JOIN used in the WHERE clause. + */ + if( (pItem->fg.jointype & JT_LEFT)!=0 + && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor) + && OptimizationEnabled(db, SQLITE_SimplifyJoin) + ){ + SELECTTRACE(0x100,pParse,p, + ("LEFT-JOIN simplifies to JOIN on term %d\n",i)); + pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER); + unsetJoinExpr(p->pWhere, pItem->iCursor); + } + + /* No futher action if this term of the FROM clause is no a subquery */ if( pSub==0 ) continue; /* Catch mismatch in the declared columns of a view and the number of @@ -120726,13 +140697,79 @@ SQLITE_PRIVATE int sqlite3Select( goto select_end; } - isAggSub = (pSub->selFlags & SF_Aggregate)!=0; - if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ + /* Do not try to flatten an aggregate subquery. + ** + ** Flattening an aggregate subquery is only possible if the outer query + ** is not a join. But if the outer query is not a join, then the subquery + ** will be implemented as a co-routine and there is no advantage to + ** flattening in that case. + */ + if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; + assert( pSub->pGroupBy==0 ); + + /* If a FROM-clause subquery has an ORDER BY clause that is not + ** really doing anything, then delete it now so that it does not + ** interfere with query flattening. See the discussion at + ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a + ** + ** Beware of these cases where the ORDER BY clause may not be safely + ** omitted: + ** + ** (1) There is also a LIMIT clause + ** (2) The subquery was added to help with window-function + ** processing + ** (3) The subquery is in the FROM clause of an UPDATE + ** (4) The outer query uses an aggregate function other than + ** the built-in count(), min(), or max(). + ** (5) The ORDER BY isn't going to accomplish anything because + ** one of: + ** (a) The outer query has a different ORDER BY clause + ** (b) The subquery is part of a join + ** See forum post 062d576715d277c8 + */ + if( pSub->pOrderBy!=0 + && (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */ + && pSub->pLimit==0 /* Condition (1) */ + && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */ + && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ + && OptimizationEnabled(db, SQLITE_OmitOrderBy) + ){ + SELECTTRACE(0x100,pParse,p, + ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); + sqlite3ExprListDelete(db, pSub->pOrderBy); + pSub->pOrderBy = 0; + } + + /* If the outer query contains a "complex" result set (that is, + ** if the result set of the outer query uses functions or subqueries) + ** and if the subquery contains an ORDER BY clause and if + ** it will be implemented as a co-routine, then do not flatten. This + ** restriction allows SQL constructs like this: + ** + ** SELECT expensive_function(x) + ** FROM (SELECT x FROM tab ORDER BY y LIMIT 10); + ** + ** The expensive_function() is only computed on the 10 rows that + ** are output, rather than every row of the table. + ** + ** The requirement that the outer query have a complex result set + ** means that flattening does occur on simpler SQL constraints without + ** the expensive_function() like: + ** + ** SELECT x FROM (SELECT x FROM tab ORDER BY y LIMIT 10); + */ + if( pSub->pOrderBy!=0 + && i==0 + && (p->selFlags & SF_ComplexResult)!=0 + && (pTabList->nSrc==1 + || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) + ){ + continue; + } + + if( flattenSubquery(pParse, p, i, isAgg) ){ + if( pParse->nErr ) goto select_end; /* This subquery can be absorbed into its parent. */ - if( isAggSub ){ - isAgg = 1; - p->selFlags |= SF_Aggregate; - } i = -1; } pTabList = p->pSrc; @@ -120743,48 +140780,95 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* Get a pointer the VDBE under construction, allocating a new VDBE if one - ** does not already exist */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto select_end; - #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() ** procedure. */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); - explainSetInteger(pParse->iSelectId, iRestoreSelectId); #if SELECTTRACE_ENABLED - SELECTTRACE(1,pParse,p,("end compound-select processing\n")); - pParse->nSelectIndent--; + SELECTTRACE(0x1,pParse,p,("end compound-select processing\n")); + if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ + sqlite3TreeViewSelect(0, p, 0); + } #endif + if( p->pNext==0 ) ExplainQueryPlanPop(pParse); return rc; } #endif - /* Generate code for all sub-queries in the FROM clause + /* Do the WHERE-clause constant propagation optimization if this is + ** a join. No need to speed time on this operation for non-join queries + ** as the equivalent optimization will be handled by query planner in + ** sqlite3WhereBegin(). + */ + if( p->pWhere!=0 + && p->pWhere->op==TK_AND + && OptimizationEnabled(db, SQLITE_PropagateConst) + && propagateConstants(pParse, p) + ){ +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After constant propagation:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + }else{ + SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n")); + } + +#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION + if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) + && countOfViewOptimization(pParse, p) + ){ + if( db->mallocFailed ) goto select_end; + pEList = p->pEList; + pTabList = p->pSrc; + } +#endif + + /* For each term in the FROM clause, do two things: + ** (1) Authorized unreferenced tables + ** (2) Generate code for all sub-queries */ -#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; inSrc; i++){ - struct SrcList_item *pItem = &pTabList->a[i]; + SrcItem *pItem = &pTabList->a[i]; + SrcItem *pPrior; SelectDest dest; - Select *pSub = pItem->pSelect; - if( pSub==0 ) continue; + Select *pSub; +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + const char *zSavedAuthContext; +#endif - /* Sometimes the code for a subquery will be generated more than - ** once, if the subquery is part of the WHERE clause in a LEFT JOIN, - ** for example. In that case, do not regenerate the code to manifest - ** a view or the co-routine to implement a view. The first instance - ** is sufficient, though the subroutine to manifest the view does need - ** to be invoked again. */ - if( pItem->addrFillSub ){ - if( pItem->fg.viaCoroutine==0 ){ - sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); - } - continue; + /* Issue SQLITE_READ authorizations with a fake column name for any + ** tables that are referenced but from which no values are extracted. + ** Examples of where these kinds of null SQLITE_READ authorizations + ** would occur: + ** + ** SELECT count(*) FROM t1; -- SQLITE_READ t1."" + ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2."" + ** + ** The fake column name is an empty string. It is possible for a table to + ** have a column named by the empty string, in which case there is no way to + ** distinguish between an unreferenced table and an actual reference to the + ** "" column. The original design was for the fake column name to be a NULL, + ** which would be unambiguous. But legacy authorization callbacks might + ** assume the column name is non-NULL and segfault. The use of an empty + ** string for the fake column name seems safer. + */ + if( pItem->colUsed==0 && pItem->zName!=0 ){ + sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); } +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + /* Generate code for all sub-queries in the FROM clause + */ + pSub = pItem->pSelect; + if( pSub==0 ) continue; + + /* The code for a subquery should only be generated once. */ + assert( pItem->addrFillSub==0 ); + /* Increment Parse.nHeight by the height of the largest expression ** tree referred to by this, the parent select. The child select ** may contain expression trees of at most @@ -120797,47 +140881,53 @@ SQLITE_PRIVATE int sqlite3Select( /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. */ - if( (pItem->fg.jointype & JT_OUTER)==0 - && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor) + if( OptimizationEnabled(db, SQLITE_PushDown) + && (pItem->fg.isCte==0 + || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2)) + && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor, + (pItem->fg.jointype & JT_OUTER)!=0) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ - SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); + SELECTTRACE(0x100,pParse,p, + ("After WHERE-clause push-down into subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif + assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); + }else{ + SELECTTRACE(0x100,pParse,p,("Push-down not possible\n")); } + zSavedAuthContext = pParse->zAuthContext; + pParse->zAuthContext = pItem->zName; + /* Generate code to implement the subquery ** - ** The subquery is implemented as a co-routine if all of these are true: - ** (1) The subquery is guaranteed to be the outer loop (so that it - ** does not need to be computed more than once) - ** (2) The ALL keyword after SELECT is omitted. (Applications are - ** allowed to say "SELECT ALL" instead of just "SELECT" to disable - ** the use of co-routines.) - ** (3) Co-routines are not disabled using sqlite3_test_control() - ** with SQLITE_TESTCTRL_OPTIMIZATIONS. + ** The subquery is implemented as a co-routine if: + ** (1) the subquery is guaranteed to be the outer loop (so that + ** it does not need to be computed more than once), and + ** (2) the subquery is not a CTE that should be materialized ** - ** TODO: Are there other reasons beside (1) to use a co-routine + ** TODO: Are there other reasons beside (1) and (2) to use a co-routine ** implementation? */ if( i==0 && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ - && (p->selFlags & SF_All)==0 /* (2) */ - && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */ + && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */ ){ /* Implement a co-routine that will return a single row of the result ** set on each invocation. */ int addrTop = sqlite3VdbeCurrentAddr(v)+1; + pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); - VdbeComment((v, "%s", pItem->pTab->zName)); + VdbeComment((v, "%!S", pItem)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; @@ -120845,16 +140935,34 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); - }else{ - /* Generate a subroutine that will fill an ephemeral table with - ** the content of this subquery. pItem->addrFillSub will point - ** to the address of the generated subroutine. pItem->regReturn - ** is a register allocated to hold the subroutine return address - */ + }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ + /* This is a CTE for which materialization code has already been + ** generated. Invoke the subroutine to compute the materialization, + ** the make the pItem->iCursor be a copy of the ephemerial table that + ** holds the result of the materialization. */ + CteUse *pCteUse = pItem->u2.pCteUse; + sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); + if( pItem->iCursor!=pCteUse->iCur ){ + sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur); + VdbeComment((v, "%!S", pItem)); + } + pSub->nSelectRow = pCteUse->nRowEst; + }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){ + /* This view has already been materialized by a prior entry in + ** this same FROM clause. Reuse it. */ + if( pPrior->addrFillSub ){ + sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); + } + sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); + pSub->nSelectRow = pPrior->pSelect->nSelectRow; + }else{ + /* Materialize the view. If the view is not correlated, generate a + ** subroutine to do the materialization so that subsequent uses of + ** the same view can reuse the materialization. */ int topAddr; int onceAddr = 0; int retAddr; - assert( pItem->addrFillSub==0 ); + pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); pItem->addrFillSub = topAddr+1; @@ -120863,24 +140971,32 @@ SQLITE_PRIVATE int sqlite3Select( ** a trigger, then we only need to compute the value of the subquery ** once. */ onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); - VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); + VdbeComment((v, "materialize %!S", pItem)); }else{ - VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); + VdbeNoopComment((v, "materialize %!S", pItem)); } sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); - VdbeComment((v, "end %s", pItem->pTab->zName)); + VdbeComment((v, "end %!S", pItem)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); + if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ + CteUse *pCteUse = pItem->u2.pCteUse; + pCteUse->addrM9e = pItem->addrFillSub; + pCteUse->regRtn = pItem->regReturn; + pCteUse->iCur = pItem->iCursor; + pCteUse->nRowEst = pSub->nSelectRow; + } } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); - } + pParse->zAuthContext = zSavedAuthContext; #endif + } /* Various elements of the SELECT copied into local variables for ** convenience */ @@ -120897,7 +141013,7 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and + /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: ** @@ -120907,16 +141023,20 @@ SQLITE_PRIVATE int sqlite3Select( ** ** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz ** - ** The second form is preferred as a single index (or temp-table) may be - ** used for both the ORDER BY and DISTINCT processing. As originally - ** written the query must use a temp-table for at least one of the ORDER + ** The second form is preferred as a single index (or temp-table) may be + ** used for both the ORDER BY and DISTINCT processing. As originally + ** written the query must use a temp-table for at least one of the ORDER ** BY and DISTINCT, and an index or separate temp-table for the other. */ - if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct + if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 +#ifndef SQLITE_OMIT_WINDOWFUNC + && p->pWin==0 +#endif ){ p->selFlags &= ~SF_Distinct; pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); + p->selFlags |= SF_Aggregate; /* Notice that even thought SF_Distinct has been cleared from p->selFlags, ** the sDistinct.isTnct is still set. Hence, isTnct represents the ** original setting of the SF_Distinct flag, not the current setting */ @@ -120940,7 +141060,8 @@ SQLITE_PRIVATE int sqlite3Select( */ if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; - pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr); + pKeyInfo = sqlite3KeyInfoFromExprList( + pParse, sSort.pOrderBy, 0, pEList->nExpr); sSort.iECursor = pParse->nTab++; sSort.addrSortIndex = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, @@ -120959,7 +141080,7 @@ SQLITE_PRIVATE int sqlite3Select( /* Set the limiter. */ - iEnd = sqlite3VdbeMakeLabel(v); + iEnd = sqlite3VdbeMakeLabel(pParse); if( (p->selFlags & SF_FixedLimit)==0 ){ p->nSelectRow = 320; /* 4 billion rows */ } @@ -120974,9 +141095,9 @@ SQLITE_PRIVATE int sqlite3Select( if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - sDistinct.tabTnct, 0, 0, - (char*)keyInfoFromExprList(pParse, p->pEList,0,0), - P4_KEYINFO); + sDistinct.tabTnct, 0, 0, + (char*)sqlite3KeyInfoFromExprList(pParse, p->pEList,0,0), + P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; }else{ @@ -120985,13 +141106,21 @@ SQLITE_PRIVATE int sqlite3Select( if( !isAgg && pGroupBy==0 ){ /* No aggregate functions and no GROUP BY clause */ - u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); + u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) + | (p->selFlags & SF_FixedLimit); +#ifndef SQLITE_OMIT_WINDOWFUNC + Window *pWin = p->pWin; /* Main window object (or NULL) */ + if( pWin ){ + sqlite3WindowCodeInit(pParse, p); + } +#endif assert( WHERE_USE_LIMIT==SF_FixedLimit ); - wctrlFlags |= p->selFlags & SF_FixedLimit; + /* Begin the database scan. */ + SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, - p->pEList, wctrlFlags, p->nSelectRow); + p->pEList, p, wctrlFlags, p->nSelectRow); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); @@ -121001,13 +141130,14 @@ SQLITE_PRIVATE int sqlite3Select( } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); - sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo); + sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } } + SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); - /* If sorting index that was created by a prior OP_OpenEphemeral + /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral ** into an OP_Noop. */ @@ -121015,14 +141145,38 @@ SQLITE_PRIVATE int sqlite3Select( sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex); } - /* Use the standard inner loop. */ - selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest, - sqlite3WhereContinueLabel(pWInfo), - sqlite3WhereBreakLabel(pWInfo)); + assert( p->pEList==pEList ); +#ifndef SQLITE_OMIT_WINDOWFUNC + if( pWin ){ + int addrGosub = sqlite3VdbeMakeLabel(pParse); + int iCont = sqlite3VdbeMakeLabel(pParse); + int iBreak = sqlite3VdbeMakeLabel(pParse); + int regGosub = ++pParse->nMem; - /* End the database scan loop. - */ - sqlite3WhereEnd(pWInfo); + sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); + + sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); + sqlite3VdbeResolveLabel(v, addrGosub); + VdbeNoopComment((v, "inner-loop subroutine")); + sSort.labelOBLopt = 0; + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak); + sqlite3VdbeResolveLabel(v, iCont); + sqlite3VdbeAddOp1(v, OP_Return, regGosub); + VdbeComment((v, "end inner-loop subroutine")); + sqlite3VdbeResolveLabel(v, iBreak); + }else +#endif /* SQLITE_OMIT_WINDOWFUNC */ + { + /* Use the standard inner loop. */ + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, + sqlite3WhereContinueLabel(pWInfo), + sqlite3WhereBreakLabel(pWInfo)); + + /* End the database scan loop. + */ + SELECTTRACE(1,pParse,p,("WhereEnd\n")); + sqlite3WhereEnd(pWInfo); + } }else{ /* This case when there exist aggregate functions or a GROUP BY clause ** or both */ @@ -121054,51 +141208,115 @@ SQLITE_PRIVATE int sqlite3Select( } assert( 66==sqlite3LogEst(100) ); if( p->nSelectRow>66 ) p->nSelectRow = 66; + + /* If there is both a GROUP BY and an ORDER BY clause and they are + ** identical, then it may be possible to disable the ORDER BY clause + ** on the grounds that the GROUP BY will cause elements to come out + ** in the correct order. It also may not - the GROUP BY might use a + ** database index that causes rows to be grouped together as required + ** but not actually sorted. Either way, record the fact that the + ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp + ** variable. */ + if( sSort.pOrderBy && pGroupBy->nExpr==sSort.pOrderBy->nExpr ){ + int ii; + /* The GROUP BY processing doesn't care whether rows are delivered in + ** ASC or DESC order - only that each group is returned contiguously. + ** So set the ASC/DESC flags in the GROUP BY to match those in the + ** ORDER BY to maximize the chances of rows being delivered in an + ** order that makes the ORDER BY redundant. */ + for(ii=0; iinExpr; ii++){ + u8 sortFlags = sSort.pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_DESC; + pGroupBy->a[ii].sortFlags = sortFlags; + } + if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ + orderByGrp = 1; + } + } }else{ assert( 0==sqlite3LogEst(1) ); p->nSelectRow = 0; } - /* If there is both a GROUP BY and an ORDER BY clause and they are - ** identical, then it may be possible to disable the ORDER BY clause - ** on the grounds that the GROUP BY will cause elements to come out - ** in the correct order. It also may not - the GROUP BY might use a - ** database index that causes rows to be grouped together as required - ** but not actually sorted. Either way, record the fact that the - ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp - ** variable. */ - if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ - orderByGrp = 1; - } - /* Create a label to jump to when we want to abort the query */ - addrEnd = sqlite3VdbeMakeLabel(v); + addrEnd = sqlite3VdbeMakeLabel(pParse); /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the ** SELECT statement. */ + pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) ); + if( pAggInfo ){ + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))agginfoFree, pAggInfo); + testcase( pParse->earlyCleanup ); + } + if( db->mallocFailed ){ + goto select_end; + } + pAggInfo->selId = p->selId; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; - sNC.pAggInfo = &sAggInfo; - sAggInfo.mnReg = pParse->nMem+1; - sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; - sAggInfo.pGroupBy = pGroupBy; + sNC.uNC.pAggInfo = pAggInfo; + VVA_ONLY( sNC.ncFlags = NC_UAggInfo; ) + pAggInfo->mnReg = pParse->nMem+1; + pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; + pAggInfo->pGroupBy = pGroupBy; sqlite3ExprAnalyzeAggList(&sNC, pEList); sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); if( pHaving ){ + if( pGroupBy ){ + assert( pWhere==p->pWhere ); + assert( pHaving==p->pHaving ); + assert( pGroupBy==p->pGroupBy ); + havingToWhere(pParse, p); + pWhere = p->pWhere; + } sqlite3ExprAnalyzeAggregates(&sNC, pHaving); } - sAggInfo.nAccumulator = sAggInfo.nColumn; - for(i=0; inAccumulator = pAggInfo->nColumn; + if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){ + minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy); + }else{ + minMaxFlag = WHERE_ORDERBY_NORMAL; + } + for(i=0; inFunc; i++){ + Expr *pExpr = pAggInfo->aFunc[i].pFExpr; + assert( ExprUseXList(pExpr) ); sNC.ncFlags |= NC_InAggFunc; - sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList); + sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList); +#ifndef SQLITE_OMIT_WINDOWFUNC + assert( !IsWindowFunc(pExpr) ); + if( ExprHasProperty(pExpr, EP_WinFunc) ){ + sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter); + } +#endif sNC.ncFlags &= ~NC_InAggFunc; } - sAggInfo.mxReg = pParse->nMem; + pAggInfo->mxReg = pParse->nMem; if( db->mallocFailed ) goto select_end; +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + int ii; + SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo)); + sqlite3TreeViewSelect(0, p, 0); + if( minMaxFlag ){ + sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag); + sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY"); + } + for(ii=0; iinColumn; ii++){ + sqlite3DebugPrintf("agg-column[%d] iMem=%d\n", + ii, pAggInfo->aCol[ii].iMem); + sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0); + } + for(ii=0; iinFunc; ii++){ + sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", + ii, pAggInfo->aFunc[ii].iMem); + sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0); + } + } +#endif + /* Processing for aggregates with GROUP BY is very different and ** much more complex than aggregates without a GROUP BY. @@ -121113,16 +141331,33 @@ SQLITE_PRIVATE int sqlite3Select( int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ int addrReset; /* Subroutine for resetting the accumulator */ int regReset; /* Return address register for reset subroutine */ + ExprList *pDistinct = 0; + u16 distFlag = 0; + int eDist = WHERE_DISTINCT_NOOP; + + if( pAggInfo->nFunc==1 + && pAggInfo->aFunc[0].iDistinct>=0 + && ALWAYS(pAggInfo->aFunc[0].pFExpr!=0) + && ALWAYS(ExprUseXList(pAggInfo->aFunc[0].pFExpr)) + && pAggInfo->aFunc[0].pFExpr->x.pList!=0 + ){ + Expr *pExpr = pAggInfo->aFunc[0].pFExpr->x.pList->a[0].pExpr; + pExpr = sqlite3ExprDup(db, pExpr, 0); + pDistinct = sqlite3ExprListDup(db, pGroupBy, 0); + pDistinct = sqlite3ExprListAppend(pParse, pDistinct, pExpr); + distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; + } /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out ** that we do not need it after all, the OP_SorterOpen instruction - ** will be converted into a Noop. + ** will be converted into a Noop. */ - sAggInfo.sortingIdx = pParse->nTab++; - pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn); - addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, - sAggInfo.sortingIdx, sAggInfo.nSortingColumn, + pAggInfo->sortingIdx = pParse->nTab++; + pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy, + 0, pAggInfo->nColumn); + addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, + pAggInfo->sortingIdx, pAggInfo->nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); /* Initialize memory locations used by GROUP BY aggregate processing @@ -121130,17 +141365,15 @@ SQLITE_PRIVATE int sqlite3Select( iUseFlag = ++pParse->nMem; iAbortFlag = ++pParse->nMem; regOutputRow = ++pParse->nMem; - addrOutputRow = sqlite3VdbeMakeLabel(v); + addrOutputRow = sqlite3VdbeMakeLabel(pParse); regReset = ++pParse->nMem; - addrReset = sqlite3VdbeMakeLabel(v); + addrReset = sqlite3VdbeMakeLabel(pParse); iAMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; iBMem = pParse->nMem + 1; pParse->nMem += pGroupBy->nExpr; sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag); VdbeComment((v, "clear abort flag")); - sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); - VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1); /* Begin a loop that will extract all source rows in GROUP BY order. @@ -121149,10 +141382,16 @@ SQLITE_PRIVATE int sqlite3Select( ** in the right order to begin with. */ sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, - WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 + SELECTTRACE(1,pParse,p,("WhereBegin\n")); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct, + 0, (WHERE_GROUPBY|(orderByGrp ? WHERE_SORTBYGROUP : 0)|distFlag), 0 ); - if( pWInfo==0 ) goto select_end; + if( pWInfo==0 ){ + sqlite3ExprListDelete(db, pDistinct); + goto select_end; + } + eDist = sqlite3WhereIsDistinct(pWInfo); + SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ /* The optimizer is able to deliver rows in group by order so ** we do not have to sort. The OP_OpenEphemeral table will be @@ -121170,7 +141409,7 @@ SQLITE_PRIVATE int sqlite3Select( int nCol; int nGroupBy; - explainTempTable(pParse, + explainTempTable(pParse, (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? "DISTINCT" : "GROUP BY"); @@ -121178,39 +141417,37 @@ SQLITE_PRIVATE int sqlite3Select( nGroupBy = pGroupBy->nExpr; nCol = nGroupBy; j = nGroupBy; - for(i=0; i=j ){ + for(i=0; inColumn; i++){ + if( pAggInfo->aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); - sqlite3ExprCacheClear(pParse); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); j = nGroupBy; - for(i=0; inColumn; i++){ + struct AggInfo_col *pCol = &pAggInfo->aCol[i]; if( pCol->iSorterColumn>=j ){ int r1 = j + regBase; - sqlite3ExprCodeGetColumnToReg(pParse, - pCol->pTab, pCol->iColumn, pCol->iTable, r1); + sqlite3ExprCodeGetColumnOfTable(v, + pCol->pTab, pCol->iTable, pCol->iColumn, r1); j++; } } regRecord = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); - sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord); + sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); + SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); - sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++; + pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++; sortOut = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); - sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd); + sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); - sAggInfo.useSortingIdx = 1; - sqlite3ExprCacheClear(pParse); - + pAggInfo->useSortingIdx = 1; } /* If the index or temporary table used by the GROUP BY sort @@ -121218,9 +141455,9 @@ SQLITE_PRIVATE int sqlite3Select( ** clause, cancel the ephemeral table open coded earlier. ** ** This is an optimization - the correct answer should result regardless. - ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to + ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to ** disable this optimization for testing purposes. */ - if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder) + if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder) && (groupBySort || sqlite3WhereIsSorted(pWInfo)) ){ sSort.pOrderBy = 0; @@ -121233,16 +141470,15 @@ SQLITE_PRIVATE int sqlite3Select( ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); - sqlite3ExprCacheClear(pParse); if( groupBySort ){ - sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, + sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx, sortOut, sortPTab); } for(j=0; jnExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); }else{ - sAggInfo.directMode = 1; + pAggInfo->directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); } } @@ -121272,19 +141508,21 @@ SQLITE_PRIVATE int sqlite3Select( ** the current row */ sqlite3VdbeJumpHere(v, addr1); - updateAccumulator(pParse, &sAggInfo); + updateAccumulator(pParse, iUseFlag, pAggInfo, eDist); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); /* End of the loop */ if( groupBySort ){ - sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop); + sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop); VdbeCoverage(v); }else{ + SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); sqlite3VdbeChangeToNoop(v, addrSortingIdx); } + sqlite3ExprListDelete(db, pDistinct); /* Output the final row of result */ @@ -121312,9 +141550,9 @@ SQLITE_PRIVATE int sqlite3Select( VdbeCoverage(v); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); - finalizeAggFunctions(pParse, &sAggInfo); + finalizeAggFunctions(pParse, pAggInfo); sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, &sSort, + selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addrOutputRow+1, addrSetAbort); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); @@ -121323,15 +141561,19 @@ SQLITE_PRIVATE int sqlite3Select( /* Generate a subroutine that will reset the group-by accumulator */ sqlite3VdbeResolveLabel(v, addrReset); - resetAccumulator(pParse, &sAggInfo); + resetAccumulator(pParse, pAggInfo); + sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); + VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp1(v, OP_Return, regReset); - + + if( eDist!=WHERE_DISTINCT_NOOP ){ + struct AggInfo_func *pF = &pAggInfo->aFunc[0]; + fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); + } } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ else { - ExprList *pDel = 0; -#ifndef SQLITE_OMIT_BTREECOUNT Table *pTab; - if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){ + if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){ /* If isSimpleCount() returns a pointer to a Table structure, then ** the SQL statement is of the form: ** @@ -121350,7 +141592,7 @@ SQLITE_PRIVATE int sqlite3Select( Index *pIdx; /* Iterator variable */ KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */ Index *pBest = 0; /* Best index found so far */ - int iRoot = pTab->tnum; /* Root page of scanned b-tree */ + Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */ sqlite3CodeVerifySchema(pParse, iDb); sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); @@ -121361,17 +141603,19 @@ SQLITE_PRIVATE int sqlite3Select( ** ** (2013-10-03) Do not count the entries in a partial index. ** - ** In practice the KeyInfo structure will not be used. It is only + ** In practice the KeyInfo structure will not be used. It is only ** passed to keep OP_OpenRead happy. */ if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab); - for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->bUnordered==0 - && pIdx->szIdxRowszTabRow - && pIdx->pPartIdxWhere==0 - && (!pBest || pIdx->szIdxRowszIdxRow) - ){ - pBest = pIdx; + if( !p->pSrc->a[0].fg.notIndexed ){ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->bUnordered==0 + && pIdx->szIdxRowszTabRow + && pIdx->pPartIdxWhere==0 + && (!pBest || pIdx->szIdxRowszIdxRow) + ){ + pBest = pIdx; + } } } if( pBest ){ @@ -121380,90 +141624,92 @@ SQLITE_PRIVATE int sqlite3Select( } /* Open a read-only cursor, execute the OP_Count, close the cursor. */ - sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1); + sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1); if( pKeyInfo ){ sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO); } - sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem); + sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem); sqlite3VdbeAddOp1(v, OP_Close, iCsr); explainSimpleCount(pParse, pTab, pBest); - }else -#endif /* SQLITE_OMIT_BTREECOUNT */ - { - /* Check if the query is of one of the following forms: - ** - ** SELECT min(x) FROM ... - ** SELECT max(x) FROM ... - ** - ** If it is, then ask the code in where.c to attempt to sort results - ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause. - ** If where.c is able to produce results sorted in this order, then - ** add vdbe code to break out of the processing loop after the - ** first iteration (since the first iteration of the loop is - ** guaranteed to operate on the row with the minimum or maximum - ** value of x, the only row required). - ** - ** A special flag must be passed to sqlite3WhereBegin() to slightly - ** modify behavior as follows: - ** - ** + If the query is a "SELECT min(x)", then the loop coded by - ** where.c should not iterate over any values with a NULL value - ** for x. - ** - ** + The optimizer code in where.c (the thing that decides which - ** index or indices to use) should place a different priority on - ** satisfying the 'ORDER BY' clause than it does in other cases. - ** Refer to code and comments in where.c for details. - */ - ExprList *pMinMax = 0; - u8 flag = WHERE_ORDERBY_NORMAL; - - assert( p->pGroupBy==0 ); - assert( flag==0 ); - if( p->pHaving==0 ){ - flag = minMaxQuery(&sAggInfo, &pMinMax); - } - assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) ); - - if( flag ){ - pMinMax = sqlite3ExprListDup(db, pMinMax, 0); - pDel = pMinMax; - assert( db->mallocFailed || pMinMax!=0 ); - if( !db->mallocFailed ){ - pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; - pMinMax->a[0].pExpr->op = TK_COLUMN; + }else{ + int regAcc = 0; /* "populate accumulators" flag */ + ExprList *pDistinct = 0; + u16 distFlag = 0; + int eDist; + + /* If there are accumulator registers but no min() or max() functions + ** without FILTER clauses, allocate register regAcc. Register regAcc + ** will contain 0 the first time the inner loop runs, and 1 thereafter. + ** The code generated by updateAccumulator() uses this to ensure + ** that the accumulator registers are (a) updated only once if + ** there are no min() or max functions or (b) always updated for the + ** first row visited by the aggregate, so that they are updated at + ** least once even if the FILTER clause means the min() or max() + ** function visits zero rows. */ + if( pAggInfo->nAccumulator ){ + for(i=0; inFunc; i++){ + if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){ + continue; + } + if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){ + break; + } + } + if( i==pAggInfo->nFunc ){ + regAcc = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc); } + }else if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 ){ + assert( ExprUseXList(pAggInfo->aFunc[0].pFExpr) ); + pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList; + distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0; } - + /* This case runs if the aggregate has no GROUP BY clause. The ** processing is much simpler since there is only a single row ** of output. */ - resetAccumulator(pParse, &sAggInfo); - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax, 0,flag,0); + assert( p->pGroupBy==0 ); + resetAccumulator(pParse, pAggInfo); + + /* If this query is a candidate for the min/max optimization, then + ** minMaxFlag will have been previously set to either + ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will + ** be an appropriate ORDER BY expression for the optimization. + */ + assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 ); + assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 ); + + SELECTTRACE(1,pParse,p,("WhereBegin\n")); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, + pDistinct, 0, minMaxFlag|distFlag, 0); if( pWInfo==0 ){ - sqlite3ExprListDelete(db, pDel); goto select_end; } - updateAccumulator(pParse, &sAggInfo); - assert( pMinMax==0 || pMinMax->nExpr==1 ); - if( sqlite3WhereIsOrdered(pWInfo)>0 ){ - sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo)); - VdbeComment((v, "%s() by index", - (flag==WHERE_ORDERBY_MIN?"min":"max"))); + SELECTTRACE(1,pParse,p,("WhereBegin returns\n")); + eDist = sqlite3WhereIsDistinct(pWInfo); + updateAccumulator(pParse, regAcc, pAggInfo, eDist); + if( eDist!=WHERE_DISTINCT_NOOP ){ + struct AggInfo_func *pF = &pAggInfo->aFunc[0]; + fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); + } + + if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc); + if( minMaxFlag ){ + sqlite3WhereMinMaxOptEarlyOut(v, pWInfo); } + SELECTTRACE(1,pParse,p,("WhereEnd\n")); sqlite3WhereEnd(pWInfo); - finalizeAggFunctions(pParse, &sAggInfo); + finalizeAggFunctions(pParse, pAggInfo); } sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); - selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, + selectInnerLoop(pParse, p, -1, 0, 0, pDest, addrEnd, addrEnd); - sqlite3ExprListDelete(db, pDel); } sqlite3VdbeResolveLabel(v, addrEnd); - + } /* endif aggregate query */ if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){ @@ -121476,6 +141722,7 @@ SQLITE_PRIVATE int sqlite3Select( if( sSort.pOrderBy ){ explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); + assert( p->pEList==pEList ); generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } @@ -121491,20 +141738,33 @@ SQLITE_PRIVATE int sqlite3Select( ** successful coding of the SELECT. */ select_end: - explainSetInteger(pParse->iSelectId, iRestoreSelectId); - - /* Identify column names if results of the SELECT are to be output. - */ - if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){ - generateColumnNames(pParse, pTabList, pEList); + assert( db->mallocFailed==0 || db->mallocFailed==1 ); + assert( db->mallocFailed==0 || pParse->nErr!=0 ); + sqlite3ExprListDelete(db, pMinMaxOrderBy); +#ifdef SQLITE_DEBUG + if( pAggInfo && !db->mallocFailed ){ + for(i=0; inColumn; i++){ + Expr *pExpr = pAggInfo->aCol[i].pCExpr; + assert( pExpr!=0 ); + assert( pExpr->pAggInfo==pAggInfo ); + assert( pExpr->iAgg==i ); + } + for(i=0; inFunc; i++){ + Expr *pExpr = pAggInfo->aFunc[i].pFExpr; + assert( pExpr!=0 ); + assert( pExpr->pAggInfo==pAggInfo ); + assert( pExpr->iAgg==i ); + } } +#endif - sqlite3DbFree(db, sAggInfo.aCol); - sqlite3DbFree(db, sAggInfo.aFunc); #if SELECTTRACE_ENABLED - SELECTTRACE(1,pParse,p,("end processing\n")); - pParse->nSelectIndent--; + SELECTTRACE(0x1,pParse,p,("end processing\n")); + if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ + sqlite3TreeViewSelect(0, p, 0); + } #endif + ExplainQueryPlanPop(pParse); return rc; } @@ -121568,7 +141828,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ if( p->nData + need > p->nAlloc ){ char **azNew; p->nAlloc = p->nAlloc*2 + need; - azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc ); + azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc ); if( azNew==0 ) goto malloc_failed; p->azResult = azNew; } @@ -121621,7 +141881,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ ** at the conclusion of the call. ** ** The result that is written to ***pazResult is held in memory obtained -** from malloc(). But the caller cannot free this memory directly. +** from malloc(). But the caller cannot free this memory directly. ** Instead, the entire table should be passed to sqlite3_free_table() when ** the calling procedure is finished using it. */ @@ -121677,7 +141937,7 @@ SQLITE_API int sqlite3_get_table( } if( res.nAlloc>res.nData ){ char **azNew; - azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData ); + azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData ); if( azNew==0 ){ sqlite3_free_table(&res.azResult[1]); db->errCode = SQLITE_NOMEM; @@ -121738,13 +141998,16 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS sqlite3ExprListDelete(db, pTmp->pExprList); sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); + sqlite3UpsertDelete(db, pTmp->pUpsert); + sqlite3SrcListDelete(db, pTmp->pFrom); + sqlite3DbFree(db, pTmp->zSpan); sqlite3DbFree(db, pTmp); } } /* -** Given table pTab, return a list of all the triggers attached to +** Given table pTab, return a list of all the triggers attached to ** the table. The list is connected by Trigger.pNext pointers. ** ** All of the triggers on pTab that are in the same database as pTab @@ -121758,28 +142021,51 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS ** pTab as well as the triggers lised in pTab->pTrigger. */ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ - Schema * const pTmpSchema = pParse->db->aDb[1].pSchema; - Trigger *pList = 0; /* List of triggers to return */ + Schema *pTmpSchema; /* Schema of the pTab table */ + Trigger *pList; /* List of triggers to return */ + HashElem *p; /* Loop variable for TEMP triggers */ if( pParse->disableTriggers ){ return 0; } - - if( pTmpSchema!=pTab->pSchema ){ - HashElem *p; - assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) ); - for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){ - Trigger *pTrig = (Trigger *)sqliteHashData(p); - if( pTrig->pTabSchema==pTab->pSchema - && 0==sqlite3StrICmp(pTrig->table, pTab->zName) - ){ - pTrig->pNext = (pList ? pList : pTab->pTrigger); - pList = pTrig; - } + pTmpSchema = pParse->db->aDb[1].pSchema; + p = sqliteHashFirst(&pTmpSchema->trigHash); + pList = pTab->pTrigger; + while( p ){ + Trigger *pTrig = (Trigger *)sqliteHashData(p); + if( pTrig->pTabSchema==pTab->pSchema + && pTrig->table + && 0==sqlite3StrICmp(pTrig->table, pTab->zName) + && pTrig->pTabSchema!=pTmpSchema + ){ + pTrig->pNext = pList; + pList = pTrig; + }else if( pTrig->op==TK_RETURNING +#ifndef SQLITE_OMIT_VIRTUALTABLE + && pParse->db->pVtabCtx==0 +#endif + ){ + assert( pParse->bReturning ); + assert( &(pParse->u1.pReturning->retTrig) == pTrig ); + pTrig->table = pTab->zName; + pTrig->pTabSchema = pTab->pSchema; + pTrig->pNext = pList; + pList = pTrig; } + p = sqliteHashNext(p); } - - return (pList ? pList : pTab->pTrigger); +#if 0 + if( pList ){ + Trigger *pX; + printf("Triggers for %s:", pTab->zName); + for(pX=pList; pX; pX=pX->pNext){ + printf(" %s", pX->zName); + } + printf("\n"); + fflush(stdout); + } +#endif + return pList; } /* @@ -121839,7 +142125,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( ** ^^^^^^^^ ** ** To maintain backwards compatibility, ignore the database - ** name on pTableName if we are reparsing out of SQLITE_MASTER. + ** name on pTableName if we are reparsing out of the schema table */ if( db->init.busy && iDb!=1 ){ sqlite3DbFree(db, pTableName->a[0].zDatabase); @@ -121867,39 +142153,34 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ - if( db->init.iDb==1 ){ - /* Ticket #3810. - ** Normally, whenever a table is dropped, all associated triggers are - ** dropped too. But if a TEMP trigger is created on a non-TEMP table - ** and the table is dropped by a different database connection, the - ** trigger is not visible to the database connection that does the - ** drop so the trigger cannot be dropped. This results in an - ** "orphaned trigger" - a trigger whose associated table is missing. - */ - db->init.orphanTrigger = 1; - } - goto trigger_cleanup; + goto trigger_orphan_error; } if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); - goto trigger_cleanup; + goto trigger_orphan_error; } /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ zName = sqlite3NameFromToken(db, pName); - if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + if( zName==0 ){ + assert( db->mallocFailed ); + goto trigger_cleanup; + } + if( sqlite3CheckObjectName(pParse, zName, "trigger", pTab->zName) ){ goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); - if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ - if( !noErr ){ - sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); - }else{ - assert( !db->init.busy ); - sqlite3CodeVerifySchema(pParse, iDb); + if( !IN_RENAME_OBJECT ){ + if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ + if( !noErr ){ + sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); + }else{ + assert( !db->init.busy ); + sqlite3CodeVerifySchema(pParse, iDb); + } + goto trigger_cleanup; } - goto trigger_cleanup; } /* Do not create a trigger on a system table */ @@ -121911,19 +142192,19 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( /* INSTEAD of triggers are only for views and views only support INSTEAD ** of triggers. */ - if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ - sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", - (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); - goto trigger_cleanup; + if( IsView(pTab) && tr_tm!=TK_INSTEAD ){ + sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", + (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName->a); + goto trigger_orphan_error; } - if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ + if( !IsView(pTab) && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" - " trigger on table: %S", pTableName, 0); - goto trigger_cleanup; + " trigger on table: %S", pTableName->a); + goto trigger_orphan_error; } #ifndef SQLITE_OMIT_AUTHORIZATION - { + if( !IN_RENAME_OBJECT ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int code = SQLITE_CREATE_TRIGGER; const char *zDb = db->aDb[iTabDb].zDbSName; @@ -121957,8 +142238,15 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; - pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); - pTrigger->pColumns = sqlite3IdListDup(db, pColumns); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName); + pTrigger->pWhen = pWhen; + pWhen = 0; + }else{ + pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); + } + pTrigger->pColumns = pColumns; + pColumns = 0; assert( pParse->pNewTrigger==0 ); pParse->pNewTrigger = pTrigger; @@ -121972,6 +142260,23 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( }else{ assert( pParse->pNewTrigger==pTrigger ); } + return; + +trigger_orphan_error: + if( db->init.iDb==1 ){ + /* Ticket #3810. + ** Normally, whenever a table is dropped, all associated triggers are + ** dropped too. But if a TEMP trigger is created on a non-TEMP table + ** and the table is dropped by a different database connection, the + ** trigger is not visible to the database connection that does the + ** drop so the trigger cannot be dropped. This results in an + ** "orphaned trigger" - a trigger whose associated table is missing. + ** + ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df + */ + db->init.orphanTrigger = 1; + } + goto trigger_cleanup; } /* @@ -122001,38 +142306,49 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( } sqlite3TokenInit(&nameToken, pTrig->zName); sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); - if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) - || sqlite3FixExpr(&sFix, pTrig->pWhen) + if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) + || sqlite3FixExpr(&sFix, pTrig->pWhen) ){ goto triggerfinish_cleanup; } +#ifndef SQLITE_OMIT_ALTERTABLE + if( IN_RENAME_OBJECT ){ + assert( !db->init.busy ); + pParse->pNewTrigger = pTrig; + pTrig = 0; + }else +#endif + /* if we are not initializing, - ** build the sqlite_master entry + ** build the sqlite_schema entry */ if( !db->init.busy ){ Vdbe *v; char *z; - /* Make an entry in the sqlite_master table */ + /* Make an entry in the sqlite_schema table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n); + testcase( z==0 ); sqlite3NestedParse(pParse, - "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", - db->aDb[iDb].zDbSName, MASTER_NAME, zName, + "INSERT INTO %Q." LEGACY_SCHEMA_TABLE + " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", + db->aDb[iDb].zDbSName, zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, - sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); + sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0); } if( db->init.busy ){ Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + assert( pLink!=0 ); pTrig = sqlite3HashInsert(pHash, zName, pTrig); if( pTrig ){ sqlite3OomFault(db); @@ -122047,18 +142363,34 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( triggerfinish_cleanup: sqlite3DeleteTrigger(db, pTrig); - assert( !pParse->pNewTrigger ); + assert( IN_RENAME_OBJECT || !pParse->pNewTrigger ); sqlite3DeleteTriggerStep(db, pStepList); } +/* +** Duplicate a range of text from an SQL statement, then convert all +** whitespace characters into ordinary space characters. +*/ +static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){ + char *z = sqlite3DbSpanDup(db, zStart, zEnd); + int i; + if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' '; + return z; +} + /* ** Turn a SELECT statement (that the pSelect parameter points to) into ** a trigger step. Return a pointer to a TriggerStep structure. ** ** The parser calls this routine when it finds a SELECT statement in -** body of a TRIGGER. +** body of a TRIGGER. */ -SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){ +SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep( + sqlite3 *db, /* Database connection */ + Select *pSelect, /* The SELECT statement */ + const char *zStart, /* Start of SQL text */ + const char *zEnd /* End of SQL text */ +){ TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); if( pTriggerStep==0 ) { sqlite3SelectDelete(db, pSelect); @@ -122067,6 +142399,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec pTriggerStep->op = TK_SELECT; pTriggerStep->pSelect = pSelect; pTriggerStep->orconf = OE_Default; + pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); return pTriggerStep; } @@ -122077,12 +142410,16 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep *triggerStepAllocate( - sqlite3 *db, /* Database connection */ + Parse *pParse, /* Parser context */ u8 op, /* Trigger opcode */ - Token *pName /* The target name */ + Token *pName, /* The target name */ + const char *zStart, /* Start of SQL text */ + const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; + if( pParse->nErr ) return 0; pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); if( pTriggerStep ){ char *z = (char*)&pTriggerStep[1]; @@ -122090,6 +142427,10 @@ static TriggerStep *triggerStepAllocate( sqlite3Dequote(z); pTriggerStep->zTarget = z; pTriggerStep->op = op; + pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName); + } } return pTriggerStep; } @@ -122102,23 +142443,39 @@ static TriggerStep *triggerStepAllocate( ** body of a trigger. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( - sqlite3 *db, /* The database connection */ + Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table into which we insert */ IdList *pColumn, /* List of columns in pTableName to insert into */ Select *pSelect, /* A SELECT statement that supplies values */ - u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ + u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ + Upsert *pUpsert, /* ON CONFLICT clauses for upsert */ + const char *zStart, /* Start of SQL text */ + const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; assert(pSelect != 0 || db->mallocFailed); - pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName); + pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd); if( pTriggerStep ){ - pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + if( IN_RENAME_OBJECT ){ + pTriggerStep->pSelect = pSelect; + pSelect = 0; + }else{ + pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); + } pTriggerStep->pIdList = pColumn; + pTriggerStep->pUpsert = pUpsert; pTriggerStep->orconf = orconf; + if( pUpsert ){ + sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget); + } }else{ + testcase( pColumn ); sqlite3IdListDelete(db, pColumn); + testcase( pUpsert ); + sqlite3UpsertDelete(db, pUpsert); } sqlite3SelectDelete(db, pSelect); @@ -122131,22 +142488,37 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( - sqlite3 *db, /* The database connection */ + Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table to be updated */ + SrcList *pFrom, ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ - u8 orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ + u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ + const char *zStart, /* Start of SQL text */ + const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName); + pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); if( pTriggerStep ){ - pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); - pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + if( IN_RENAME_OBJECT ){ + pTriggerStep->pExprList = pEList; + pTriggerStep->pWhere = pWhere; + pTriggerStep->pFrom = pFrom; + pEList = 0; + pWhere = 0; + pFrom = 0; + }else{ + pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); + pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE); + } pTriggerStep->orconf = orconf; } sqlite3ExprListDelete(db, pEList); sqlite3ExprDelete(db, pWhere); + sqlite3SrcListDelete(db, pFrom); return pTriggerStep; } @@ -122156,26 +142528,34 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( ** sees a DELETE statement inside the body of a CREATE TRIGGER. */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( - sqlite3 *db, /* Database connection */ + Parse *pParse, /* Parser */ Token *pTableName, /* The table from which rows are deleted */ - Expr *pWhere /* The WHERE clause */ + Expr *pWhere, /* The WHERE clause */ + const char *zStart, /* Start of SQL text */ + const char *zEnd /* End of SQL text */ ){ + sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName); + pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd); if( pTriggerStep ){ - pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + if( IN_RENAME_OBJECT ){ + pTriggerStep->pWhere = pWhere; + pWhere = 0; + }else{ + pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); + } pTriggerStep->orconf = OE_Default; } sqlite3ExprDelete(db, pWhere); return pTriggerStep; } -/* +/* ** Recursively delete a Trigger structure */ SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ - if( pTrigger==0 ) return; + if( pTrigger==0 || pTrigger->bReturning ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); @@ -122185,7 +142565,7 @@ SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ } /* -** This function is called to drop a trigger from the database schema. +** This function is called to drop a trigger from the database schema. ** ** This may be called directly from the parser and therefore identifies ** the trigger by name. The sqlite3DropTriggerPtr() routine does the @@ -122210,14 +142590,14 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr) assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ - if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue; + if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; assert( sqlite3SchemaMutexHeld(db, j, 0) ); pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName); if( pTrigger ) break; } if( !pTrigger ){ if( !noErr ){ - sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); + sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a); }else{ sqlite3CodeVerifyNamedSchema(pParse, zDb); } @@ -122240,7 +142620,7 @@ static Table *tableOfTrigger(Trigger *pTrigger){ /* -** Drop a trigger given a pointer to that trigger. +** Drop a trigger given a pointer to that trigger. */ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ Table *pTable; @@ -122251,10 +142631,9 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDbnDb ); pTable = tableOfTrigger(pTrigger); - assert( pTable ); - assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); + assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION - { + if( pTable ){ int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zDbSName; const char *zTab = SCHEMA_TABLE(iDb); @@ -122268,11 +142647,10 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ /* Generate code to destroy the database record of the trigger. */ - assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, - "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", - db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName + "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'", + db->aDb[iDb].zDbSName, pTrigger->zName ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); @@ -122292,12 +142670,18 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch if( ALWAYS(pTrigger) ){ if( pTrigger->pSchema==pTrigger->pTabSchema ){ Table *pTab = tableOfTrigger(pTrigger); - Trigger **pp; - for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext)); - *pp = (*pp)->pNext; + if( pTab ){ + Trigger **pp; + for(pp=&pTab->pTrigger; *pp; pp=&((*pp)->pNext)){ + if( *pp==pTrigger ){ + *pp = (*pp)->pNext; + break; + } + } + } } sqlite3DeleteTrigger(db, pTrigger); - db->flags |= SQLITE_InternChanges; + db->mDbFlags |= DBFLAG_SchemaChange; } } @@ -122314,14 +142698,14 @@ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){ int e; if( pIdList==0 || NEVER(pEList==0) ) return 1; for(e=0; enExpr; e++){ - if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; + if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1; } - return 0; + return 0; } /* ** Return a list of all triggers on table pTab if there exists at least -** one trigger that must be fired when an operation of type 'op' is +** one trigger that must be fired when an operation of type 'op' is ** performed on the table, and, if that operation is an UPDATE, if at ** least one of the columns in pChanges is being modified. */ @@ -122336,15 +142720,53 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist( Trigger *pList = 0; Trigger *p; - if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){ - pList = sqlite3TriggerList(pParse, pTab); - } - assert( pList==0 || IsVirtual(pTab)==0 ); - for(p=pList; p; p=p->pNext){ - if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ - mask |= p->tr_tm; + pList = sqlite3TriggerList(pParse, pTab); + assert( pList==0 || IsVirtual(pTab)==0 + || (pList->bReturning && pList->pNext==0) ); + if( pList!=0 ){ + p = pList; + if( (pParse->db->flags & SQLITE_EnableTrigger)==0 + && pTab->pTrigger!=0 + ){ + /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that + ** only TEMP triggers are allowed. Truncate the pList so that it + ** includes only TEMP triggers */ + if( pList==pTab->pTrigger ){ + pList = 0; + goto exit_triggers_exist; + } + while( ALWAYS(p->pNext) && p->pNext!=pTab->pTrigger ) p = p->pNext; + p->pNext = 0; + p = pList; } + do{ + if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ + mask |= p->tr_tm; + }else if( p->op==TK_RETURNING ){ + /* The first time a RETURNING trigger is seen, the "op" value tells + ** us what time of trigger it should be. */ + assert( sqlite3IsToplevel(pParse) ); + p->op = op; + if( IsVirtual(pTab) ){ + if( op!=TK_INSERT ){ + sqlite3ErrorMsg(pParse, + "%s RETURNING is not available on virtual tables", + op==TK_DELETE ? "DELETE" : "UPDATE"); + } + p->tr_tm = TRIGGER_BEFORE; + }else{ + p->tr_tm = TRIGGER_AFTER; + } + mask |= p->tr_tm; + }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE + && sqlite3IsToplevel(pParse) ){ + /* Also fire a RETURNING trigger for an UPSERT */ + mask |= p->tr_tm; + } + p = p->pNext; + }while( p ); } +exit_triggers_exist: if( pMask ){ *pMask = mask; } @@ -122361,37 +142783,180 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist( ** trigger is in TEMP in which case it can refer to any other database it ** wants. */ -static SrcList *targetSrcList( +SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc( Parse *pParse, /* The parsing context */ TriggerStep *pStep /* The trigger containing the target token */ ){ sqlite3 *db = pParse->db; - int iDb; /* Index of the database to use */ - SrcList *pSrc; /* SrcList to be returned */ - - pSrc = sqlite3SrcListAppend(db, 0, 0, 0); + SrcList *pSrc; /* SrcList to be returned */ + char *zName = sqlite3DbStrDup(db, pStep->zTarget); + pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); + assert( pSrc==0 || pSrc->nSrc==1 ); + assert( zName || pSrc==0 ); if( pSrc ){ - assert( pSrc->nSrc>0 ); - pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); - iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); - if( iDb==0 || iDb>=2 ){ - const char *zDb; - assert( iDbnDb ); - zDb = db->aDb[iDb].zDbSName; - pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb); + Schema *pSchema = pStep->pTrig->pSchema; + pSrc->a[0].zName = zName; + if( pSchema!=db->aDb[1].pSchema ){ + pSrc->a[0].pSchema = pSchema; + } + if( pStep->pFrom ){ + SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); + pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup); } + }else{ + sqlite3DbFree(db, zName); } return pSrc; } /* -** Generate VDBE code for the statements inside the body of a single +** Return true if the pExpr term from the RETURNING clause argument +** list is of the form "*". Raise an error if the terms if of the +** form "table.*". +*/ +static int isAsteriskTerm( + Parse *pParse, /* Parsing context */ + Expr *pTerm /* A term in the RETURNING clause */ +){ + assert( pTerm!=0 ); + if( pTerm->op==TK_ASTERISK ) return 1; + if( pTerm->op!=TK_DOT ) return 0; + assert( pTerm->pRight!=0 ); + assert( pTerm->pLeft!=0 ); + if( pTerm->pRight->op!=TK_ASTERISK ) return 0; + sqlite3ErrorMsg(pParse, "RETURNING may not use \"TABLE.*\" wildcards"); + return 1; +} + +/* The input list pList is the list of result set terms from a RETURNING +** clause. The table that we are returning from is pTab. +** +** This routine makes a copy of the pList, and at the same time expands +** any "*" wildcards to be the complete set of columns from pTab. +*/ +static ExprList *sqlite3ExpandReturning( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* The arguments to RETURNING */ + Table *pTab /* The table being updated */ +){ + ExprList *pNew = 0; + sqlite3 *db = pParse->db; + int i; + + for(i=0; inExpr; i++){ + Expr *pOldExpr = pList->a[i].pExpr; + if( NEVER(pOldExpr==0) ) continue; + if( isAsteriskTerm(pParse, pOldExpr) ){ + int jj; + for(jj=0; jjnCol; jj++){ + Expr *pNewExpr; + if( IsHiddenColumn(pTab->aCol+jj) ) continue; + pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zCnName); + pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); + if( !db->mallocFailed ){ + struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; + pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName); + pItem->eEName = ENAME_NAME; + } + } + }else{ + Expr *pNewExpr = sqlite3ExprDup(db, pOldExpr, 0); + pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr); + if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){ + struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1]; + pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName); + pItem->eEName = pList->a[i].eEName; + } + } + } + return pNew; +} + +/* +** Generate code for the RETURNING trigger. Unlike other triggers +** that invoke a subprogram in the bytecode, the code for RETURNING +** is generated in-line. +*/ +static void codeReturningTrigger( + Parse *pParse, /* Parse context */ + Trigger *pTrigger, /* The trigger step that defines the RETURNING */ + Table *pTab, /* The table to code triggers from */ + int regIn /* The first in an array of registers */ +){ + Vdbe *v = pParse->pVdbe; + sqlite3 *db = pParse->db; + ExprList *pNew; + Returning *pReturning; + Select sSelect; + SrcList sFrom; + + assert( v!=0 ); + assert( pParse->bReturning ); + assert( db->pParse==pParse ); + pReturning = pParse->u1.pReturning; + assert( pTrigger == &(pReturning->retTrig) ); + memset(&sSelect, 0, sizeof(sSelect)); + memset(&sFrom, 0, sizeof(sFrom)); + sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); + sSelect.pSrc = &sFrom; + sFrom.nSrc = 1; + sFrom.a[0].pTab = pTab; + sFrom.a[0].iCursor = -1; + sqlite3SelectPrep(pParse, &sSelect, 0); + if( pParse->nErr==0 ){ + assert( db->mallocFailed==0 ); + sqlite3GenerateColumnNames(pParse, &sSelect); + } + sqlite3ExprListDelete(db, sSelect.pEList); + pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab); + if( !db->mallocFailed ){ + NameContext sNC; + memset(&sNC, 0, sizeof(sNC)); + if( pReturning->nRetCol==0 ){ + pReturning->nRetCol = pNew->nExpr; + pReturning->iRetCur = pParse->nTab++; + } + sNC.pParse = pParse; + sNC.uNC.iBaseReg = regIn; + sNC.ncFlags = NC_UBaseReg; + pParse->eTriggerOp = pTrigger->op; + pParse->pTriggerTab = pTab; + if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK + && ALWAYS(!db->mallocFailed) + ){ + int i; + int nCol = pNew->nExpr; + int reg = pParse->nMem+1; + pParse->nMem += nCol+2; + pReturning->iRetReg = reg; + for(i=0; ia[i].pExpr; + assert( pCol!=0 ); /* Due to !db->mallocFailed ~9 lines above */ + sqlite3ExprCodeFactorable(pParse, pCol, reg+i); + if( sqlite3ExprAffinity(pCol)==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, reg+i); + } + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i); + sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1); + sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1); + } + } + sqlite3ExprListDelete(db, pNew); + pParse->eTriggerOp = 0; + pParse->pTriggerTab = 0; +} + + + +/* +** Generate VDBE code for the statements inside the body of a single ** trigger. */ static int codeTriggerProgram( Parse *pParse, /* The parser context */ TriggerStep *pStepList, /* List of statements inside the trigger body */ - int orconf /* Conflict algorithm. (OE_Abort, etc) */ + int orconf /* Conflict algorithm. (OE_Abort, etc) */ ){ TriggerStep *pStep; Vdbe *v = pParse->pVdbe; @@ -122417,30 +142982,42 @@ static int codeTriggerProgram( pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf; assert( pParse->okConstFactor==0 ); +#ifndef SQLITE_OMIT_TRACE + if( pStep->zSpan ){ + sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0, + sqlite3MPrintf(db, "-- %s", pStep->zSpan), + P4_DYNAMIC); + } +#endif + switch( pStep->op ){ case TK_UPDATE: { - sqlite3Update(pParse, - targetSrcList(pParse, pStep), - sqlite3ExprListDup(db, pStep->pExprList, 0), - sqlite3ExprDup(db, pStep->pWhere, 0), - pParse->eOrconf + sqlite3Update(pParse, + sqlite3TriggerStepSrc(pParse, pStep), + sqlite3ExprListDup(db, pStep->pExprList, 0), + sqlite3ExprDup(db, pStep->pWhere, 0), + pParse->eOrconf, 0, 0, 0 ); + sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_INSERT: { - sqlite3Insert(pParse, - targetSrcList(pParse, pStep), - sqlite3SelectDup(db, pStep->pSelect, 0), - sqlite3IdListDup(db, pStep->pIdList), - pParse->eOrconf + sqlite3Insert(pParse, + sqlite3TriggerStepSrc(pParse, pStep), + sqlite3SelectDup(db, pStep->pSelect, 0), + sqlite3IdListDup(db, pStep->pIdList), + pParse->eOrconf, + sqlite3UpsertDup(db, pStep->pUpsert) ); + sqlite3VdbeAddOp0(v, OP_ResetCount); break; } case TK_DELETE: { - sqlite3DeleteFrom(pParse, - targetSrcList(pParse, pStep), - sqlite3ExprDup(db, pStep->pWhere, 0) + sqlite3DeleteFrom(pParse, + sqlite3TriggerStepSrc(pParse, pStep), + sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0 ); + sqlite3VdbeAddOp0(v, OP_ResetCount); break; } default: assert( pStep->op==TK_SELECT ); { @@ -122451,9 +143028,6 @@ static int codeTriggerProgram( sqlite3SelectDelete(db, pSelect); break; } - } - if( pStep->op!=TK_SELECT ){ - sqlite3VdbeAddOp0(v, OP_ResetCount); } } @@ -122496,7 +143070,7 @@ static void transferParseError(Parse *pTo, Parse *pFrom){ } /* -** Create and populate a new TriggerPrg object with a sub-program +** Create and populate a new TriggerPrg object with a sub-program ** implementing trigger pTrigger with ON CONFLICT policy orconf. */ static TriggerPrg *codeRowTrigger( @@ -122512,14 +143086,14 @@ static TriggerPrg *codeRowTrigger( Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ - Parse *pSubParse; /* Parse context for sub-vdbe */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ + Parse sSubParse; /* Parse context for sub-vdbe */ assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); assert( pTop->pVdbe ); /* Allocate the TriggerPrg and SubProgram objects. To ensure that they - ** are freed if an error occurs, link them into the Parse.pTriggerPrg + ** are freed if an error occurs, link them into the Parse.pTriggerPrg ** list of the top-level Parse object sooner rather than later. */ pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg)); if( !pPrg ) return 0; @@ -122533,22 +143107,21 @@ static TriggerPrg *codeRowTrigger( pPrg->aColmask[0] = 0xffffffff; pPrg->aColmask[1] = 0xffffffff; - /* Allocate and populate a new Parse context to use for coding the + /* Allocate and populate a new Parse context to use for coding the ** trigger sub-program. */ - pSubParse = sqlite3StackAllocZero(db, sizeof(Parse)); - if( !pSubParse ) return 0; + sqlite3ParseObjectInit(&sSubParse, db); memset(&sNC, 0, sizeof(sNC)); - sNC.pParse = pSubParse; - pSubParse->db = db; - pSubParse->pTriggerTab = pTab; - pSubParse->pToplevel = pTop; - pSubParse->zAuthContext = pTrigger->zName; - pSubParse->eTriggerOp = pTrigger->op; - pSubParse->nQueryLoop = pParse->nQueryLoop; - - v = sqlite3GetVdbe(pSubParse); + sNC.pParse = &sSubParse; + sSubParse.pTriggerTab = pTab; + sSubParse.pToplevel = pTop; + sSubParse.zAuthContext = pTrigger->zName; + sSubParse.eTriggerOp = pTrigger->op; + sSubParse.nQueryLoop = pParse->nQueryLoop; + sSubParse.disableVtab = pParse->disableVtab; + + v = sqlite3GetVdbe(&sSubParse); if( v ){ - VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", + VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", pTrigger->zName, onErrorText(orconf), (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"), (pTrigger->op==TK_UPDATE ? "UPDATE" : ""), @@ -122557,27 +143130,29 @@ static TriggerPrg *codeRowTrigger( pTab->zName )); #ifndef SQLITE_OMIT_TRACE - sqlite3VdbeChangeP4(v, -1, - sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC - ); + if( pTrigger->zName ){ + sqlite3VdbeChangeP4(v, -1, + sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC + ); + } #endif /* If one was specified, code the WHEN clause. If it evaluates to false - ** (or NULL) the sub-vdbe is immediately halted by jumping to the + ** (or NULL) the sub-vdbe is immediately halted by jumping to the ** OP_Halt inserted at the end of the program. */ if( pTrigger->pWhen ){ pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0); - if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) - && db->mallocFailed==0 + if( db->mallocFailed==0 + && SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){ - iEndTrigger = sqlite3VdbeMakeLabel(v); - sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); + iEndTrigger = sqlite3VdbeMakeLabel(&sSubParse); + sqlite3ExprIfFalse(&sSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pWhen); } /* Code the trigger program into the sub-vdbe. */ - codeTriggerProgram(pSubParse, pTrigger->step_list, orconf); + codeTriggerProgram(&sSubParse, pTrigger->step_list, orconf); /* Insert an OP_Halt at the end of the sub-program. */ if( iEndTrigger ){ @@ -122585,27 +143160,27 @@ static TriggerPrg *codeRowTrigger( } sqlite3VdbeAddOp0(v, OP_Halt); VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); + transferParseError(pParse, &sSubParse); - transferParseError(pParse, pSubParse); - if( db->mallocFailed==0 ){ + if( pParse->nErr==0 ){ + assert( db->mallocFailed==0 ); pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } - pProgram->nMem = pSubParse->nMem; - pProgram->nCsr = pSubParse->nTab; + pProgram->nMem = sSubParse.nMem; + pProgram->nCsr = sSubParse.nTab; pProgram->token = (void *)pTrigger; - pPrg->aColmask[0] = pSubParse->oldmask; - pPrg->aColmask[1] = pSubParse->newmask; + pPrg->aColmask[0] = sSubParse.oldmask; + pPrg->aColmask[1] = sSubParse.newmask; sqlite3VdbeDelete(v); + }else{ + transferParseError(pParse, &sSubParse); } - assert( !pSubParse->pAinc && !pSubParse->pZombieTab ); - assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); - sqlite3ParserReset(pSubParse); - sqlite3StackFree(db, pSubParse); - + assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg ); + sqlite3ParseObjectReset(&sSubParse); return pPrg; } - + /* ** Return a pointer to a TriggerPrg object containing the sub-program for ** trigger pTrigger with default ON CONFLICT algorithm orconf. If no such @@ -122627,21 +143202,22 @@ static TriggerPrg *getRowTrigger( ** process of being coded). If this is the case, then an entry with ** a matching TriggerPrg.pTrigger field will be present somewhere ** in the Parse.pTriggerPrg list. Search for such an entry. */ - for(pPrg=pRoot->pTriggerPrg; - pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); + for(pPrg=pRoot->pTriggerPrg; + pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); pPrg=pPrg->pNext ); /* If an existing TriggerPrg could not be located, create a new one. */ if( !pPrg ){ pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf); + pParse->db->errByteOffset = -1; } return pPrg; } /* -** Generate code for the trigger program associated with trigger p on +** Generate code for the trigger program associated with trigger p on ** table pTab. The reg, orconf and ignoreJump parameters passed to this ** function are the same as those described in the header function for ** sqlite3CodeRowTrigger() @@ -122657,9 +143233,9 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect( Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); - assert( pPrg || pParse->nErr || pParse->db->mallocFailed ); + assert( pPrg || pParse->nErr ); - /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program + /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program ** is a pointer to the sub-vdbe containing the trigger program. */ if( pPrg ){ int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); @@ -122688,7 +143264,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect( ** If there are no triggers that fire at the specified time for the specified ** operation on pTab, this function is a no-op. ** -** The reg argument is the address of the first in an array of registers +** The reg argument is the address of the first in an array of registers ** that contain the values substituted for the new.* and old.* references ** in the trigger program. If N is the number of columns in table pTab ** (a copy of pTab->nCol), then registers are populated as follows: @@ -122700,17 +143276,17 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect( ** ... ... ** reg+N OLD.* value of right-most column of pTab ** reg+N+1 NEW.rowid -** reg+N+2 OLD.* value of left-most column of pTab +** reg+N+2 NEW.* value of left-most column of pTab ** ... ... ** reg+N+N+1 NEW.* value of right-most column of pTab ** ** For ON DELETE triggers, the registers containing the NEW.* values will -** never be accessed by the trigger program, so they are not allocated or -** populated by the caller (there is no data to populate them with anyway). +** never be accessed by the trigger program, so they are not allocated or +** populated by the caller (there is no data to populate them with anyway). ** Similarly, for ON INSERT triggers the values stored in the OLD.* registers ** are never accessed, and so are not allocated by the caller. So, for an ** ON INSERT trigger, the value passed to this function as parameter reg -** is not a readable register, although registers (reg+N) through +** is not a readable register, although registers (reg+N) through ** (reg+N+N+1) are. ** ** Parameter orconf is the default conflict resolution algorithm for the @@ -122742,23 +143318,31 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger( ** or else it must be a TEMP trigger. */ assert( p->pSchema!=0 ); assert( p->pTabSchema!=0 ); - assert( p->pSchema==p->pTabSchema + assert( p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema ); - /* Determine whether we should code this trigger */ - if( p->op==op - && p->tr_tm==tr_tm + /* Determine whether we should code this trigger. One of two choices: + ** 1. The trigger is an exact match to the current DML statement + ** 2. This is a RETURNING trigger for INSERT but we are currently + ** doing the UPDATE part of an UPSERT. + */ + if( (p->op==op || (p->bReturning && p->op==TK_INSERT && op==TK_UPDATE)) + && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ - sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); + if( !p->bReturning ){ + sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); + }else if( sqlite3IsToplevel(pParse) ){ + codeReturningTrigger(pParse, p, pTab, reg); + } } } } /* -** Triggers may access values stored in the old.* or new.* pseudo-table. -** This function returns a 32-bit bitmask indicating which columns of the -** old.* or new.* tables actually are used by triggers. This information +** Triggers may access values stored in the old.* or new.* pseudo-table. +** This function returns a 32-bit bitmask indicating which columns of the +** old.* or new.* tables actually are used by triggers. This information ** may be used by the caller, for example, to avoid having to load the entire ** old.* record into memory when executing an UPDATE or DELETE command. ** @@ -122768,7 +143352,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger( ** are more than 32 columns in the table, and at least one of the columns ** with an index greater than 32 may be accessed, 0xffffffff is returned. ** -** It is not possible to determine if the old.rowid or new.rowid column is +** It is not possible to determine if the old.rowid or new.rowid column is ** accessed by triggers. The caller must always assume that it is. ** ** Parameter isNew must be either 1 or 0. If it is 0, then the mask returned @@ -122795,13 +143379,18 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask( assert( isNew==1 || isNew==0 ); for(p=pTrigger; p; p=p->pNext){ - if( p->op==op && (tr_tm&p->tr_tm) + if( p->op==op + && (tr_tm&p->tr_tm) && checkColumnOverlap(p->pColumns,pChanges) ){ - TriggerPrg *pPrg; - pPrg = getRowTrigger(pParse, p, pTab, orconf); - if( pPrg ){ - mask |= pPrg->aColmask[isNew]; + if( p->bReturning ){ + mask = 0xffffffff; + }else{ + TriggerPrg *pPrg; + pPrg = getRowTrigger(pParse, p, pTab, orconf); + if( pPrg ){ + mask |= pPrg->aColmask[isNew]; + } } } } @@ -122845,10 +143434,10 @@ static void updateVirtualTable( /* ** The most recently coded instruction was an OP_Column to retrieve the -** i-th column of table pTab. This routine sets the P4 parameter of the +** i-th column of table pTab. This routine sets the P4 parameter of the ** OP_Column to the default value, if any. ** -** The default value of a column is specified by a DEFAULT clause in the +** The default value of a column is specified by a DEFAULT clause in the ** column definition. This was either supplied by the user when the table ** was created, or added later to the table definition by an ALTER TABLE ** command. If the latter, then the row-records in the table btree on disk @@ -122857,70 +143446,266 @@ static void updateVirtualTable( ** If the former, then all row-records are guaranteed to include a value ** for the column and the P4 value is not required. ** -** Column definitions created by an ALTER TABLE command may only have +** Column definitions created by an ALTER TABLE command may only have ** literal default values specified: a number, null or a string. (If a more -** complicated default expression value was provided, it is evaluated +** complicated default expression value was provided, it is evaluated ** when the ALTER TABLE is executed and one of the literal values written -** into the sqlite_master table.) +** into the sqlite_schema table.) ** ** Therefore, the P4 parameter is only required if the default value for ** the column is a literal number, string or null. The sqlite3ValueFromExpr() ** function is capable of transforming these types of expressions into ** sqlite3_value objects. ** -** If parameter iReg is not negative, code an OP_RealAffinity instruction -** on register iReg. This is used when an equivalent integer value is -** stored in place of an 8-byte floating point value in order to save -** space. +** If column as REAL affinity and the table is an ordinary b-tree table +** (not a virtual table) then the value might have been stored as an +** integer. In that case, add an OP_RealAffinity opcode to make sure +** it has been converted into REAL. */ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ assert( pTab!=0 ); - if( !pTab->pSelect ){ + if( !IsView(pTab) ){ sqlite3_value *pValue = 0; u8 enc = ENC(sqlite3VdbeDb(v)); Column *pCol = &pTab->aCol[i]; - VdbeComment((v, "%s.%s", pTab->zName, pCol->zName)); + VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName)); assert( inCol ); - sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, + sqlite3ValueFromExpr(sqlite3VdbeDb(v), + sqlite3ColumnExpr(pTab,pCol), enc, pCol->affinity, &pValue); if( pValue ){ sqlite3VdbeAppendP4(v, pValue, P4_MEM); } } #ifndef SQLITE_OMIT_FLOATING_POINT - if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ + if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } +/* +** Check to see if column iCol of index pIdx references any of the +** columns defined by aXRef and chngRowid. Return true if it does +** and false if not. This is an optimization. False-positives are a +** performance degradation, but false-negatives can result in a corrupt +** index and incorrect answers. +** +** aXRef[j] will be non-negative if column j of the original table is +** being updated. chngRowid will be true if the rowid of the table is +** being updated. +*/ +static int indexColumnIsBeingUpdated( + Index *pIdx, /* The index to check */ + int iCol, /* Which column of the index to check */ + int *aXRef, /* aXRef[j]>=0 if column j is being updated */ + int chngRowid /* true if the rowid is being updated */ +){ + i16 iIdxCol = pIdx->aiColumn[iCol]; + assert( iIdxCol!=XN_ROWID ); /* Cannot index rowid */ + if( iIdxCol>=0 ){ + return aXRef[iIdxCol]>=0; + } + assert( iIdxCol==XN_EXPR ); + assert( pIdx->aColExpr!=0 ); + assert( pIdx->aColExpr->a[iCol].pExpr!=0 ); + return sqlite3ExprReferencesUpdatedColumn(pIdx->aColExpr->a[iCol].pExpr, + aXRef,chngRowid); +} + +/* +** Check to see if index pIdx is a partial index whose conditional +** expression might change values due to an UPDATE. Return true if +** the index is subject to change and false if the index is guaranteed +** to be unchanged. This is an optimization. False-positives are a +** performance degradation, but false-negatives can result in a corrupt +** index and incorrect answers. +** +** aXRef[j] will be non-negative if column j of the original table is +** being updated. chngRowid will be true if the rowid of the table is +** being updated. +*/ +static int indexWhereClauseMightChange( + Index *pIdx, /* The index to check */ + int *aXRef, /* aXRef[j]>=0 if column j is being updated */ + int chngRowid /* true if the rowid is being updated */ +){ + if( pIdx->pPartIdxWhere==0 ) return 0; + return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, + aXRef, chngRowid); +} + +/* +** Allocate and return a pointer to an expression of type TK_ROW with +** Expr.iColumn set to value (iCol+1). The resolver will modify the +** expression to be a TK_COLUMN reading column iCol of the first +** table in the source-list (pSrc->a[0]). +*/ +static Expr *exprRowColumn(Parse *pParse, int iCol){ + Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0); + if( pRet ) pRet->iColumn = iCol+1; + return pRet; +} + +/* +** Assuming both the pLimit and pOrderBy parameters are NULL, this function +** generates VM code to run the query: +** +** SELECT , pChanges FROM pTabList WHERE pWhere +** +** and write the results to the ephemeral table already opened as cursor +** iEph. None of pChanges, pTabList or pWhere are modified or consumed by +** this function, they must be deleted by the caller. +** +** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view: +** +** SELECT , pChanges FROM pTabList +** WHERE pWhere +** GROUP BY +** ORDER BY pOrderBy LIMIT pLimit +** +** If pTab is a view, the GROUP BY clause is omitted. +** +** Exactly how results are written to table iEph, and exactly what +** the in the query above are is determined by the type +** of table pTabList->a[0].pTab. +** +** If the table is a WITHOUT ROWID table, then argument pPk must be its +** PRIMARY KEY. In this case are the primary key columns +** of the table, in order. The results of the query are written to ephemeral +** table iEph as index keys, using OP_IdxInsert. +** +** If the table is actually a view, then are all columns of +** the view. The results are written to the ephemeral table iEph as records +** with automatically assigned integer keys. +** +** If the table is a virtual or ordinary intkey table, then +** is its rowid. For a virtual table, the results are written to iEph as +** records with automatically assigned integer keys For intkey tables, the +** rowid value in is used as the integer key, and the +** remaining fields make up the table record. +*/ +static void updateFromSelect( + Parse *pParse, /* Parse context */ + int iEph, /* Cursor for open eph. table */ + Index *pPk, /* PK if table 0 is WITHOUT ROWID */ + ExprList *pChanges, /* List of expressions to return */ + SrcList *pTabList, /* List of tables to select from */ + Expr *pWhere, /* WHERE clause for query */ + ExprList *pOrderBy, /* ORDER BY clause */ + Expr *pLimit /* LIMIT clause */ +){ + int i; + SelectDest dest; + Select *pSelect = 0; + ExprList *pList = 0; + ExprList *pGrp = 0; + Expr *pLimit2 = 0; + ExprList *pOrderBy2 = 0; + sqlite3 *db = pParse->db; + Table *pTab = pTabList->a[0].pTab; + SrcList *pSrc; + Expr *pWhere2; + int eDest; + +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + if( pOrderBy && pLimit==0 ) { + sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE"); + return; + } + pOrderBy2 = sqlite3ExprListDup(db, pOrderBy, 0); + pLimit2 = sqlite3ExprDup(db, pLimit, 0); +#else + UNUSED_PARAMETER(pOrderBy); + UNUSED_PARAMETER(pLimit); +#endif + + pSrc = sqlite3SrcListDup(db, pTabList, 0); + pWhere2 = sqlite3ExprDup(db, pWhere, 0); + + assert( pTabList->nSrc>1 ); + if( pSrc ){ + pSrc->a[0].fg.notCte = 1; + pSrc->a[0].iCursor = -1; + pSrc->a[0].pTab->nTabRef--; + pSrc->a[0].pTab = 0; + } + if( pPk ){ + for(i=0; inKeyCol; i++){ + Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]); +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + if( pLimit ){ + pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0)); + } +#endif + pList = sqlite3ExprListAppend(pParse, pList, pNew); + } + eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; + }else if( IsView(pTab) ){ + for(i=0; inCol; i++){ + pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); + } + eDest = SRT_Table; + }else{ + eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; + pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + if( pLimit ){ + pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0)); + } +#endif + } + assert( pChanges!=0 || pParse->db->mallocFailed ); + if( pChanges ){ + for(i=0; inExpr; i++){ + pList = sqlite3ExprListAppend(pParse, pList, + sqlite3ExprDup(db, pChanges->a[i].pExpr, 0) + ); + } + } + pSelect = sqlite3SelectNew(pParse, pList, + pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden, pLimit2 + ); + if( pSelect ) pSelect->selFlags |= SF_OrderByReqd; + sqlite3SelectDestInit(&dest, eDest, iEph); + dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1); + sqlite3Select(pParse, pSelect, &dest); + sqlite3SelectDelete(db, pSelect); +} + /* ** Process an UPDATE statement. ** -** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; -** \_______/ \________/ \______/ \________________/ -* onError pTabList pChanges pWhere +** UPDATE OR IGNORE tbl SET a=b, c=d FROM tbl2... WHERE e<5 AND f NOT NULL; +** \_______/ \_/ \______/ \_____/ \________________/ +** onError | pChanges | pWhere +** \_______________________/ +** pTabList */ SQLITE_PRIVATE void sqlite3Update( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table in which we should change things */ ExprList *pChanges, /* Things to be changed */ Expr *pWhere, /* The WHERE clause. May be null */ - int onError /* How to handle constraint errors */ + int onError, /* How to handle constraint errors */ + ExprList *pOrderBy, /* ORDER BY clause. May be null */ + Expr *pLimit, /* LIMIT clause. May be null */ + Upsert *pUpsert /* ON CONFLICT clause, or null */ ){ - int i, j; /* Loop counters */ + int i, j, k; /* Loop counters */ Table *pTab; /* The table to be updated */ int addrTop = 0; /* VDBE instruction address of the start of the loop */ - WhereInfo *pWInfo; /* Information about the WHERE clause */ + WhereInfo *pWInfo = 0; /* Information about the WHERE clause */ Vdbe *v; /* The virtual database engine */ Index *pIdx; /* For looping over indices */ Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */ int nIdx; /* Number of indices that need updating */ + int nAllIdx; /* Total number of indexes */ int iBaseCur; /* Base cursor number */ int iDataCur; /* Cursor for the canonical data btree */ int iIdxCur; /* Cursor for the first index */ sqlite3 *db; /* The database structure */ - int *aRegIdx = 0; /* First register in array assigned to each index */ + int *aRegIdx = 0; /* Registers for to each index and the main table */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ @@ -122929,6 +143714,7 @@ SQLITE_PRIVATE void sqlite3Update( u8 chngRowid; /* Rowid changed in a normal table */ u8 chngKey; /* Either chngPk or chngRowid */ Expr *pRowidExpr = 0; /* Expression defining the new record number */ + int iRowidExpr = -1; /* Index of "rowid=" (or IPK) assignment in pChanges */ AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ @@ -122951,6 +143737,8 @@ SQLITE_PRIVATE void sqlite3Update( int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */ i16 nPk = 0; /* Number of components of the PRIMARY KEY */ int bReplace = 0; /* True if REPLACE conflict resolution might happen */ + int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */ + int nChangeFrom = 0; /* If there is a FROM, pChanges->nExpr, else 0 */ /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ @@ -122963,12 +143751,13 @@ SQLITE_PRIVATE void sqlite3Update( memset(&sContext, 0, sizeof(sContext)); db = pParse->db; - if( pParse->nErr || db->mallocFailed ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto update_cleanup; } - assert( pTabList->nSrc==1 ); + assert( db->mallocFailed==0 ); - /* Locate the table which we want to update. + /* Locate the table which we want to update. */ pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ) goto update_cleanup; @@ -122979,7 +143768,7 @@ SQLITE_PRIVATE void sqlite3Update( */ #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, &tmask); - isView = pTab->pSelect!=0; + isView = IsView(pTab); assert( pTrigger || tmask==0 ); #else # define pTrigger 0 @@ -122991,6 +143780,23 @@ SQLITE_PRIVATE void sqlite3Update( # define isView 0 #endif + /* If there was a FROM clause, set nChangeFrom to the number of expressions + ** in the change-list. Otherwise, set it to 0. There cannot be a FROM + ** clause if this function is being called to generate code for part of + ** an UPSERT statement. */ + nChangeFrom = (pTabList->nSrc>1) ? pChanges->nExpr : 0; + assert( nChangeFrom==0 || pUpsert==0 ); + +#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + if( !isView && nChangeFrom==0 ){ + pWhere = sqlite3LimitWhere( + pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE" + ); + pOrderBy = 0; + pLimit = 0; + } +#endif + if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto update_cleanup; } @@ -123003,24 +143809,31 @@ SQLITE_PRIVATE void sqlite3Update( ** need to occur right after the database cursor. So go ahead and ** allocate enough space, just in case. */ - pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++; + iBaseCur = iDataCur = pParse->nTab++; iIdxCur = iDataCur+1; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); + testcase( pPk!=0 && pPk!=pTab->pIndex ); for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ - if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){ + if( pPk==pIdx ){ iDataCur = pParse->nTab; - pTabList->a[0].iCursor = iDataCur; } pParse->nTab++; } + if( pUpsert ){ + /* On an UPSERT, reuse the same cursors already opened by INSERT */ + iDataCur = pUpsert->iDataCur; + iIdxCur = pUpsert->iIdxCur; + pParse->nTab = iBaseCur; + } + pTabList->a[0].iCursor = iDataCur; - /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. + /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ - aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 ); + aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx+1) + nIdx+2 ); if( aXRef==0 ) goto update_cleanup; aRegIdx = aXRef+pTab->nCol; - aToOpen = (u8*)(aRegIdx+nIdx); + aToOpen = (u8*)(aRegIdx+nIdx+1); memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; for(i=0; inCol; i++) aXRef[i] = -1; @@ -123029,6 +143842,12 @@ SQLITE_PRIVATE void sqlite3Update( memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; + sNC.uNC.pUpsert = pUpsert; + sNC.ncFlags = NC_UUpsert; + + /* Begin generating code. */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto update_cleanup; /* Resolve the column names in all the expressions of the ** of the UPDATE statement. Also find the column index @@ -123038,28 +143857,45 @@ SQLITE_PRIVATE void sqlite3Update( */ chngRowid = chngPk = 0; for(i=0; inExpr; i++){ - if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ + u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName); + /* If this is an UPDATE with a FROM clause, do not resolve expressions + ** here. The call to sqlite3Select() below will do that. */ + if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ + if( pTab->aCol[j].hName==hCol + && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0 + ){ if( j==pTab->iPKey ){ chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; + iRowidExpr = i; }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ chngPk = 1; } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, + "cannot UPDATE generated column \"%s\"", + pTab->aCol[j].zCnName); + goto update_cleanup; + } +#endif aXRef[j] = i; break; } } if( j>=pTab->nCol ){ - if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){ + if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){ j = -1; chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; + iRowidExpr = i; }else{ - sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); + sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName); pParse->checkSchema = 1; goto update_cleanup; } @@ -123068,7 +143904,7 @@ SQLITE_PRIVATE void sqlite3Update( { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, - j<0 ? "ROWID" : pTab->aCol[j].zName, + j<0 ? "ROWID" : pTab->aCol[j].zCnName, db->aDb[iDb].zDbSName); if( rc==SQLITE_DENY ){ goto update_cleanup; @@ -123083,7 +143919,36 @@ SQLITE_PRIVATE void sqlite3Update( assert( chngPk==0 || chngPk==1 ); chngKey = chngRowid + chngPk; - /* The SET expressions are not actually used inside the WHERE loop. +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Mark generated columns as changing if their generator expressions + ** reference any changing column. The actual aXRef[] value for + ** generated expressions is not used, other than to check to see that it + ** is non-negative, so the value of aXRef[] for generated columns can be + ** set to any non-negative number. We use 99999 so that the value is + ** obvious when looking at aXRef[] in a symbolic debugger. + */ + if( pTab->tabFlags & TF_HasGenerated ){ + int bProgress; + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); + do{ + bProgress = 0; + for(i=0; inCol; i++){ + if( aXRef[i]>=0 ) continue; + if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue; + if( sqlite3ExprReferencesUpdatedColumn( + sqlite3ColumnExpr(pTab, &pTab->aCol[i]), + aXRef, chngRowid) + ){ + aXRef[i] = 99999; + bProgress = 1; + } + } + }while( bProgress ); + } +#endif + + /* The SET expressions are not actually used inside the WHERE loop. ** So reset the colUsed mask. Unless this is a virtual table. In that ** case, set all bits of the colUsed mask (to ensure that the virtual ** table implementation makes all columns available). @@ -123095,48 +143960,50 @@ SQLITE_PRIVATE void sqlite3Update( /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold ** the key for accessing each index. - ** - ** FIXME: Be smarter about omitting indexes that use expressions. */ - for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + if( onError==OE_Replace ) bReplace = 1; + for(nAllIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nAllIdx++){ int reg; - if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){ + if( chngKey || hasFK>1 || pIdx==pPk + || indexWhereClauseMightChange(pIdx,aXRef,chngRowid) + ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; }else{ reg = 0; for(i=0; inKeyCol; i++){ - i16 iIdxCol = pIdx->aiColumn[i]; - if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){ + if( indexColumnIsBeingUpdated(pIdx, i, aXRef, chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; - if( (onError==OE_Replace) - || (onError==OE_Default && pIdx->onError==OE_Replace) - ){ + if( onError==OE_Default && pIdx->onError==OE_Replace ){ bReplace = 1; } break; } } } - if( reg==0 ) aToOpen[j+1] = 0; - aRegIdx[j] = reg; + if( reg==0 ) aToOpen[nAllIdx+1] = 0; + aRegIdx[nAllIdx] = reg; } + aRegIdx[nAllIdx] = ++pParse->nMem; /* Register storing the table record */ if( bReplace ){ - /* If REPLACE conflict resolution might be invoked, open cursors on all + /* If REPLACE conflict resolution might be invoked, open cursors on all ** indexes in case they are needed to delete records. */ memset(aToOpen, 1, nIdx+1); } - /* Begin generating code. */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, 1, iDb); + sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb); /* Allocate required registers. */ if( !IsVirtual(pTab) ){ - regRowSet = ++pParse->nMem; + /* For now, regRowSet and aRegIdx[nAllIdx] share the same register. + ** If regRowSet turns out to be needed, then aRegIdx[nAllIdx] will be + ** reallocated. aRegIdx[nAllIdx] is the register in which the main + ** table record is written. regRowSet holds the RowSet for the + ** two-pass update algorithm. */ + assert( aRegIdx[nAllIdx]==pParse->nMem ); + regRowSet = aRegIdx[nAllIdx]; regOldRowid = regNewRowid = ++pParse->nMem; if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; @@ -123158,15 +144025,19 @@ SQLITE_PRIVATE void sqlite3Update( ** an ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) - if( isView ){ - sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur); + if( nChangeFrom==0 && isView ){ + sqlite3MaterializeView(pParse, pTab, + pWhere, pOrderBy, pLimit, iDataCur + ); + pOrderBy = 0; + pLimit = 0; } #endif /* Resolve the column names in all the expressions in the ** WHERE clause. */ - if( sqlite3ResolveExprNames(&sNC, pWhere) ){ + if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pWhere) ){ goto update_cleanup; } @@ -123179,147 +144050,233 @@ SQLITE_PRIVATE void sqlite3Update( } #endif - /* Initialize the count of updated rows */ - if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){ + /* Jump to labelBreak to abandon further processing of this UPDATE */ + labelContinue = labelBreak = sqlite3VdbeMakeLabel(pParse); + + /* Not an UPSERT. Normal processing. Begin by + ** initialize the count of updated rows */ + if( (db->flags&SQLITE_CountRows)!=0 + && !pParse->pTriggerTab + && !pParse->nested + && !pParse->bReturning + && pUpsert==0 + ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } - if( HasRowid(pTab) ){ + if( nChangeFrom==0 && HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); + iEph = pParse->nTab++; + addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet); }else{ - assert( pPk!=0 ); - nPk = pPk->nKeyCol; + assert( pPk!=0 || HasRowid(pTab) ); + nPk = pPk ? pPk->nKeyCol : 0; iPk = pParse->nMem+1; pParse->nMem += nPk; + pParse->nMem += nChangeFrom; regKey = ++pParse->nMem; - iEph = pParse->nTab++; - - sqlite3VdbeAddOp2(v, OP_Null, 0, iPk); - addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); - sqlite3VdbeSetP4KeyInfo(pParse, pPk); + if( pUpsert==0 ){ + int nEphCol = nPk + nChangeFrom + (isView ? pTab->nCol : 0); + iEph = pParse->nTab++; + if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1); + addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol); + if( pPk ){ + KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk); + if( pKeyInfo ){ + pKeyInfo->nAllField = nEphCol; + sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); + } + } + if( nChangeFrom ){ + updateFromSelect( + pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit + ); +#ifndef SQLITE_OMIT_SUBQUERY + if( isView ) iDataCur = iEph; +#endif + } + } } - /* Begin the database scan. - ** - ** Do not consider a single-pass strategy for a multi-row update if - ** there are any triggers or foreign keys to process, or rows may - ** be deleted as a result of REPLACE conflict handling. Any of these - ** things might disturb a cursor being used to scan through the table - ** or index, causing a single-pass approach to malfunction. */ - flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE; - if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ - flags |= WHERE_ONEPASS_MULTIROW; - } - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur); - if( pWInfo==0 ) goto update_cleanup; - - /* A one-pass strategy that might update more than one row may not - ** be used if any column of the index used for the scan is being - ** updated. Otherwise, if there is an index on "b", statements like - ** the following could create an infinite loop: - ** - ** UPDATE t1 SET b=b+1 WHERE b>? - ** - ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI - ** strategy that uses an index for which one or more columns are being - ** updated. */ - eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); - if( eOnePass==ONEPASS_MULTI ){ - int iCur = aiCurOnePass[1]; - if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ - eOnePass = ONEPASS_OFF; - } - assert( iCur!=iDataCur || !HasRowid(pTab) ); - } - - if( HasRowid(pTab) ){ - /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF - ** mode, write the rowid into the FIFO. In either of the one-pass modes, - ** leave it in register regOldRowid. */ - sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); - if( eOnePass==ONEPASS_OFF ){ - sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); - } - }else{ - /* Read the PK of the current row into an array of registers. In - ** ONEPASS_OFF mode, serialize the array into a record and store it in - ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change - ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table - ** is not required) and leave the PK fields in the array of registers. */ - for(i=0; iaiColumn[i]>=0 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i); + if( nChangeFrom ){ + sqlite3MultiWrite(pParse); + eOnePass = ONEPASS_OFF; + nKey = nPk; + regKey = iPk; + }else{ + if( pUpsert ){ + /* If this is an UPSERT, then all cursors have already been opened by + ** the outer INSERT and the data cursor should be pointing at the row + ** that is to be updated. So bypass the code that searches for the + ** row(s) to be updated. + */ + pWInfo = 0; + eOnePass = ONEPASS_SINGLE; + sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL); + bFinishSeek = 0; + }else{ + /* Begin the database scan. + ** + ** Do not consider a single-pass strategy for a multi-row update if + ** there are any triggers or foreign keys to process, or rows may + ** be deleted as a result of REPLACE conflict handling. Any of these + ** things might disturb a cursor being used to scan through the table + ** or index, causing a single-pass approach to malfunction. */ + flags = WHERE_ONEPASS_DESIRED; + if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ + flags |= WHERE_ONEPASS_MULTIROW; + } + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur); + if( pWInfo==0 ) goto update_cleanup; + + /* A one-pass strategy that might update more than one row may not + ** be used if any column of the index used for the scan is being + ** updated. Otherwise, if there is an index on "b", statements like + ** the following could create an infinite loop: + ** + ** UPDATE t1 SET b=b+1 WHERE b>? + ** + ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI + ** strategy that uses an index for which one or more columns are being + ** updated. */ + eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); + bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo); + if( eOnePass!=ONEPASS_SINGLE ){ + sqlite3MultiWrite(pParse); + if( eOnePass==ONEPASS_MULTI ){ + int iCur = aiCurOnePass[1]; + if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){ + eOnePass = ONEPASS_OFF; + } + assert( iCur!=iDataCur || !HasRowid(pTab) ); + } + } } - if( eOnePass ){ - sqlite3VdbeChangeToNoop(v, addrOpen); - nKey = nPk; - regKey = iPk; + + if( HasRowid(pTab) ){ + /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF + ** mode, write the rowid into the FIFO. In either of the one-pass modes, + ** leave it in register regOldRowid. */ + sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); + if( eOnePass==ONEPASS_OFF ){ + aRegIdx[nAllIdx] = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid); + }else{ + if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen); + } }else{ - sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, - sqlite3IndexAffinityStr(db, pPk), nPk); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk); + /* Read the PK of the current row into an array of registers. In + ** ONEPASS_OFF mode, serialize the array into a record and store it in + ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change + ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table + ** is not required) and leave the PK fields in the array of registers. */ + for(i=0; iaiColumn[i]>=0 ); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, + pPk->aiColumn[i], iPk+i); + } + if( eOnePass ){ + if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen); + nKey = nPk; + regKey = iPk; + }else{ + sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, + sqlite3IndexAffinityStr(db, pPk), nPk); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk); + } } } - if( eOnePass!=ONEPASS_MULTI ){ - sqlite3WhereEnd(pWInfo); - } + if( pUpsert==0 ){ + if( nChangeFrom==0 && eOnePass!=ONEPASS_MULTI ){ + sqlite3WhereEnd(pWInfo); + } - labelBreak = sqlite3VdbeMakeLabel(v); - if( !isView ){ - int addrOnce = 0; + if( !isView ){ + int addrOnce = 0; - /* Open every index that needs updating. */ - if( eOnePass!=ONEPASS_OFF ){ - if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; - if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; - } + /* Open every index that needs updating. */ + if( eOnePass!=ONEPASS_OFF ){ + if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; + if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; + } - if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ - addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){ + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + } + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, + aToOpen, 0, 0); + if( addrOnce ){ + sqlite3VdbeJumpHereOrPopInst(v, addrOnce); + } } - sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen, - 0, 0); - if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); - } - /* Top of the update loop */ - if( eOnePass!=ONEPASS_OFF ){ - if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ - assert( pPk ); - sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey); - VdbeCoverageNeverTaken(v); - } - if( eOnePass==ONEPASS_SINGLE ){ - labelContinue = labelBreak; + /* Top of the update loop */ + if( eOnePass!=ONEPASS_OFF ){ + if( aiCurOnePass[0]!=iDataCur + && aiCurOnePass[1]!=iDataCur +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + && !isView +#endif + ){ + assert( pPk ); + sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey); + VdbeCoverage(v); + } + if( eOnePass!=ONEPASS_SINGLE ){ + labelContinue = sqlite3VdbeMakeLabel(pParse); + } + sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); + VdbeCoverageIf(v, pPk==0); + VdbeCoverageIf(v, pPk!=0); + }else if( pPk || nChangeFrom ){ + labelContinue = sqlite3VdbeMakeLabel(pParse); + sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); + addrTop = sqlite3VdbeCurrentAddr(v); + if( nChangeFrom ){ + if( !isView ){ + if( pPk ){ + for(i=0; i=0 ); + if( nChangeFrom==0 ){ + sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid); + } sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); } @@ -123327,18 +144284,20 @@ SQLITE_PRIVATE void sqlite3Update( ** information is needed */ if( chngPk || hasFK || pTrigger ){ u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); - oldmask |= sqlite3TriggerColmask(pParse, + oldmask |= sqlite3TriggerColmask(pParse, pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError ); for(i=0; inCol; i++){ + u32 colFlags = pTab->aCol[i].colFlags; + k = sqlite3TableColumnToStorage(pTab, i) + regOld; if( oldmask==0xffffffff || (i<32 && (oldmask & MASKBIT32(i))!=0) - || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 + || (colFlags & COLFLAG_PRIMKEY)!=0 ){ testcase( oldmask!=0xffffffff && i==31 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); }else{ - sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); + sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } if( chngRowid==0 && pPk==0 ){ @@ -123354,100 +144313,142 @@ SQLITE_PRIVATE void sqlite3Update( ** If there are one or more BEFORE triggers, then do not populate the ** registers associated with columns that are (a) not modified by ** this UPDATE statement and (b) not accessed by new.* references. The - ** values for registers not modified by the UPDATE must be reloaded from - ** the database after the BEFORE triggers are fired anyway (as the trigger + ** values for registers not modified by the UPDATE must be reloaded from + ** the database after the BEFORE triggers are fired anyway (as the trigger ** may have modified them). So not loading those that are not going to ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); - for(i=0; inCol; i++){ + for(i=0, k=regNew; inCol; i++, k++){ if( i==pTab->iPKey ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); + sqlite3VdbeAddOp2(v, OP_Null, 0, k); + }else if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)!=0 ){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else{ j = aXRef[i]; if( j>=0 ){ - sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); + if( nChangeFrom ){ + int nOff = (isView ? pTab->nCol : nPk); + assert( eOnePass==ONEPASS_OFF ); + sqlite3VdbeAddOp3(v, OP_Column, iEph, nOff+j, k); + }else{ + sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k); + } }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){ - /* This branch loads the value of a column that will not be changed + /* This branch loads the value of a column that will not be changed ** into a register. This is done if there are no BEFORE triggers, or ** if there are one or more BEFORE triggers that use this value via ** a new.* reference in a trigger program. */ testcase( i==31 ); testcase( i==32 ); - sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); + bFinishSeek = 0; }else{ - sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); + sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); + sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); + } +#endif /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( tmask&TRIGGER_BEFORE ){ sqlite3TableAffinity(v, pTab, regNew); - sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, + sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue); - /* The row-trigger may have deleted the row being updated. In this - ** case, jump to the next row. No updates or AFTER triggers are - ** required. This behavior - what happens when the row being updated - ** is deleted or renamed by a BEFORE trigger - is left undefined in the - ** documentation. - */ - if( pPk ){ - sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey); - VdbeCoverage(v); - }else{ - sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); - VdbeCoverage(v); - } + if( !isView ){ + /* The row-trigger may have deleted the row being updated. In this + ** case, jump to the next row. No updates or AFTER triggers are + ** required. This behavior - what happens when the row being updated + ** is deleted or renamed by a BEFORE trigger - is left undefined in the + ** documentation. + */ + if( pPk ){ + sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey); + VdbeCoverage(v); + }else{ + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid); + VdbeCoverage(v); + } - /* If it did not delete it, the row-trigger may still have modified - ** some of the columns of the row being updated. Load the values for - ** all columns not modified by the update statement into their - ** registers in case this has happened. - */ - for(i=0; inCol; i++){ - if( aXRef[i]<0 && i!=pTab->iPKey ){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i); + /* After-BEFORE-trigger-reload-loop: + ** If it did not delete it, the BEFORE trigger may still have modified + ** some of the columns of the row being updated. Load the values for + ** all columns not modified by the update statement into their registers + ** in case this has happened. Only unmodified columns are reloaded. + ** The values computed for modified columns use the values before the + ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26) + ** for an example. + */ + for(i=0, k=regNew; inCol; i++, k++){ + if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; + }else if( aXRef[i]<0 && i!=pTab->iPKey ){ + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); + } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); + sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); + } +#endif } } if( !isView ){ - int addr1 = 0; /* Address of jump instruction */ - /* Do constraint checks. */ assert( regOldRowid>0 ); sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace, - aXRef); + aXRef, 0); - /* Do FK constraint checks. */ - if( hasFK ){ - sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey); - } - - /* Delete the index entries associated with the current record. */ + /* If REPLACE conflict handling may have been used, or if the PK of the + ** row is changing, then the GenerateConstraintChecks() above may have + ** moved cursor iDataCur. Reseek it. */ if( bReplace || chngKey ){ if( pPk ){ - addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey); + sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey); }else{ - addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid); + sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid); } VdbeCoverageNeverTaken(v); } + + /* Do FK constraint checks. */ + if( hasFK ){ + sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey); + } + + /* Delete the index entries associated with the current record. */ sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1); + /* We must run the OP_FinishSeek opcode to resolve a prior + ** OP_DeferredSeek if there is any possibility that there have been + ** no OP_Column opcodes since the OP_DeferredSeek was issued. But + ** we want to avoid the OP_FinishSeek if possible, as running it + ** costs CPU cycles. */ + if( bFinishSeek ){ + sqlite3VdbeAddOp1(v, OP_FinishSeek, iDataCur); + } + /* If changing the rowid value, or if there are foreign key constraints ** to process, delete the old record. Otherwise, add a noop OP_Delete ** to invoke the pre-update hook. ** - ** That (regNew==regnewRowid+1) is true is also important for the + ** That (regNew==regnewRowid+1) is true is also important for the ** pre-update hook. If the caller invokes preupdate_new(), the returned ** value is copied from memory cell (regNewRowid+1+iCol), where iCol ** is the column index supplied by the user. @@ -123455,7 +144456,7 @@ SQLITE_PRIVATE void sqlite3Update( assert( regNew==regNewRowid+1 ); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK sqlite3VdbeAddOp3(v, OP_Delete, iDataCur, - OPFLAG_ISUPDATE | ((hasFK || chngKey) ? 0 : OPFLAG_ISNOOP), + OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP), regNewRowid ); if( eOnePass==ONEPASS_MULTI ){ @@ -123466,40 +144467,37 @@ SQLITE_PRIVATE void sqlite3Update( sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } #else - if( hasFK || chngKey ){ + if( hasFK>1 || chngKey ){ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); } #endif - if( bReplace || chngKey ){ - sqlite3VdbeJumpHere(v, addr1); - } if( hasFK ){ sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey); } - + /* Insert the new index entries and the new record. */ sqlite3CompleteInsertion( - pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx, - OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0), + pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx, + OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0), 0, 0 ); /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to ** handle rows (possibly in other tables) that refer via a foreign key - ** to the row just updated. */ + ** to the row just updated. */ if( hasFK ){ sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey); } } - /* Increment the row counter + /* Increment the row counter */ - if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){ + if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } - sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, + sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue); /* Repeat the above with the next record to be updated, until @@ -123510,11 +144508,9 @@ SQLITE_PRIVATE void sqlite3Update( }else if( eOnePass==ONEPASS_MULTI ){ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3WhereEnd(pWInfo); - }else if( pPk ){ + }else{ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); - }else{ - sqlite3VdbeGoto(v, labelContinue); } sqlite3VdbeResolveLabel(v, labelBreak); @@ -123522,19 +144518,16 @@ SQLITE_PRIVATE void sqlite3Update( ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ - if( pParse->nested==0 && pParse->pTriggerTab==0 ){ + if( pParse->nested==0 && pParse->pTriggerTab==0 && pUpsert==0 ){ sqlite3AutoincrementEnd(pParse); } /* - ** Return the number of rows that were changed. If this routine is - ** generating code because of a call to sqlite3NestedParse(), do not - ** invoke the callback function. + ** Return the number of rows that were changed, if we are tracking + ** that information. */ - if( (db->flags&SQLITE_CountRows) && !pParse->pTriggerTab && !pParse->nested ){ - sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); - sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC); + if( regRowCount ){ + sqlite3CodeChangeCount(v, regRowCount, "rows updated"); } update_cleanup: @@ -123543,6 +144536,10 @@ SQLITE_PRIVATE void sqlite3Update( sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pChanges); sqlite3ExprDelete(db, pWhere); +#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) + sqlite3ExprListDelete(db, pOrderBy); + sqlite3ExprDelete(db, pLimit); +#endif return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise @@ -123559,8 +144556,8 @@ SQLITE_PRIVATE void sqlite3Update( /* ** Generate code for an UPDATE of a virtual table. ** -** There are two possible strategies - the default and the special -** "onepass" strategy. Onepass is only used if the virtual table +** There are two possible strategies - the default and the special +** "onepass" strategy. Onepass is only used if the virtual table ** implementation indicates that pWhere may match at most one row. ** ** The default strategy is to create an ephemeral table that contains @@ -123592,17 +144589,17 @@ static void updateVirtualTable( int i; /* Loop counter */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); - WhereInfo *pWInfo; + WhereInfo *pWInfo = 0; int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ int regArg; /* First register in VUpdate arg array */ int regRec; /* Register in which to assemble record */ int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ - int bOnePass; /* True to use onepass strategy */ + int eOnePass; /* True to use onepass strategy */ int addr; /* Address of OP_OpenEphemeral */ - /* Allocate nArg registers to martial the arguments to VUpdate. Then + /* Allocate nArg registers in which to gather the arguments for VUpdate. Then ** create and open the ephemeral table in which the records created from ** these arguments will be temporarily stored. */ assert( v ); @@ -123610,55 +144607,117 @@ static void updateVirtualTable( addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg); regArg = pParse->nMem + 1; pParse->nMem += nArg; - regRec = ++pParse->nMem; - regRowid = ++pParse->nMem; + if( pSrc->nSrc>1 ){ + Index *pPk = 0; + Expr *pRow; + ExprList *pList; + if( HasRowid(pTab) ){ + if( pRowid ){ + pRow = sqlite3ExprDup(db, pRowid, 0); + }else{ + pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0); + } + }else{ + i16 iPk; /* PRIMARY KEY column */ + pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); + assert( pPk->nKeyCol==1 ); + iPk = pPk->aiColumn[0]; + if( aXRef[iPk]>=0 ){ + pRow = sqlite3ExprDup(db, pChanges->a[aXRef[iPk]].pExpr, 0); + }else{ + pRow = exprRowColumn(pParse, iPk); + } + } + pList = sqlite3ExprListAppend(pParse, 0, pRow); - /* Start scanning the virtual table */ - pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0); - if( pWInfo==0 ) return; + for(i=0; inCol; i++){ + if( aXRef[i]>=0 ){ + pList = sqlite3ExprListAppend(pParse, pList, + sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0) + ); + }else{ + pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); + } + } - /* Populate the argument registers. */ - sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); - if( pRowid ){ - sqlite3ExprCode(pParse, pRowid, regArg+1); + updateFromSelect(pParse, ephemTab, pPk, pList, pSrc, pWhere, 0, 0); + sqlite3ExprListDelete(db, pList); + eOnePass = ONEPASS_OFF; }else{ - sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); - } - for(i=0; inCol; i++){ - if( aXRef[i]>=0 ){ - sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); + regRec = ++pParse->nMem; + regRowid = ++pParse->nMem; + + /* Start scanning the virtual table */ + pWInfo = sqlite3WhereBegin( + pParse, pSrc, pWhere, 0, 0, 0, WHERE_ONEPASS_DESIRED, 0 + ); + if( pWInfo==0 ) return; + + /* Populate the argument registers. */ + for(i=0; inCol; i++){ + assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ); + if( aXRef[i]>=0 ){ + sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); + }else{ + sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); + sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* For sqlite3_vtab_nochange() */ + } + } + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); + if( pRowid ){ + sqlite3ExprCode(pParse, pRowid, regArg+1); + }else{ + sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1); + } }else{ - sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); + Index *pPk; /* PRIMARY KEY index */ + i16 iPk; /* PRIMARY KEY column */ + pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); + assert( pPk->nKeyCol==1 ); + iPk = pPk->aiColumn[0]; + sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg); + sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1); } - } - bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); + eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy); + + /* There is no ONEPASS_MULTI on virtual tables */ + assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE ); - if( bOnePass ){ - /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded - ** above. Also, if this is a top-level parse (not a trigger), clear the - ** multi-write flag so that the VM does not open a statement journal */ - sqlite3VdbeChangeToNoop(v, addr); - if( sqlite3IsToplevel(pParse) ){ - pParse->isMultiWrite = 0; + if( eOnePass ){ + /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded + ** above. */ + sqlite3VdbeChangeToNoop(v, addr); + sqlite3VdbeAddOp1(v, OP_Close, iCsr); + }else{ + /* Create a record from the argument register contents and insert it into + ** the ephemeral table. */ + sqlite3MultiWrite(pParse); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); +#if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM) + /* Signal an assert() within OP_MakeRecord that it is allowed to + ** accept no-change records with serial_type 10 */ + sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); +#endif + sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); } - }else{ - /* Create a record from the argument register contents and insert it into - ** the ephemeral table. */ - sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); - sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); } - if( bOnePass==0 ){ + if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ - sqlite3WhereEnd(pWInfo); + if( pSrc->nSrc==1 ){ + sqlite3WhereEnd(pWInfo); + } /* Begin scannning through the ephemeral table. */ addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); - /* Extract arguments from the current row of the ephemeral table and + /* Extract arguments from the current row of the ephemeral table and ** invoke the VUpdate method. */ for(i=0; ipNextUpsert; + sqlite3ExprListDelete(db, p->pUpsertTarget); + sqlite3ExprDelete(db, p->pUpsertTargetWhere); + sqlite3ExprListDelete(db, p->pUpsertSet); + sqlite3ExprDelete(db, p->pUpsertWhere); + sqlite3DbFree(db, p->pToFree); + sqlite3DbFree(db, p); + p = pNext; + }while( p ); +} +SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){ + if( p ) upsertDelete(db, p); +} + + +/* +** Duplicate an Upsert object. +*/ +SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){ + if( p==0 ) return 0; + return sqlite3UpsertNew(db, + sqlite3ExprListDup(db, p->pUpsertTarget, 0), + sqlite3ExprDup(db, p->pUpsertTargetWhere, 0), + sqlite3ExprListDup(db, p->pUpsertSet, 0), + sqlite3ExprDup(db, p->pUpsertWhere, 0), + sqlite3UpsertDup(db, p->pNextUpsert) + ); +} + +/* +** Create a new Upsert object. +*/ +SQLITE_PRIVATE Upsert *sqlite3UpsertNew( + sqlite3 *db, /* Determines which memory allocator to use */ + ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */ + Expr *pTargetWhere, /* Optional WHERE clause on the target */ + ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */ + Expr *pWhere, /* WHERE clause for the ON CONFLICT UPDATE */ + Upsert *pNext /* Next ON CONFLICT clause in the list */ +){ + Upsert *pNew; + pNew = sqlite3DbMallocZero(db, sizeof(Upsert)); + if( pNew==0 ){ + sqlite3ExprListDelete(db, pTarget); + sqlite3ExprDelete(db, pTargetWhere); + sqlite3ExprListDelete(db, pSet); + sqlite3ExprDelete(db, pWhere); + sqlite3UpsertDelete(db, pNext); + return 0; + }else{ + pNew->pUpsertTarget = pTarget; + pNew->pUpsertTargetWhere = pTargetWhere; + pNew->pUpsertSet = pSet; + pNew->pUpsertWhere = pWhere; + pNew->isDoUpdate = pSet!=0; + pNew->pNextUpsert = pNext; + } + return pNew; +} + +/* +** Analyze the ON CONFLICT clause described by pUpsert. Resolve all +** symbols in the conflict-target. +** +** Return SQLITE_OK if everything works, or an error code is something +** is wrong. +*/ +SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget( + Parse *pParse, /* The parsing context */ + SrcList *pTabList, /* Table into which we are inserting */ + Upsert *pUpsert /* The ON CONFLICT clauses */ +){ + Table *pTab; /* That table into which we are inserting */ + int rc; /* Result code */ + int iCursor; /* Cursor used by pTab */ + Index *pIdx; /* One of the indexes of pTab */ + ExprList *pTarget; /* The conflict-target clause */ + Expr *pTerm; /* One term of the conflict-target clause */ + NameContext sNC; /* Context for resolving symbolic names */ + Expr sCol[2]; /* Index column converted into an Expr */ + int nClause = 0; /* Counter of ON CONFLICT clauses */ + + assert( pTabList->nSrc==1 ); + assert( pTabList->a[0].pTab!=0 ); + assert( pUpsert!=0 ); + assert( pUpsert->pUpsertTarget!=0 ); + + /* Resolve all symbolic names in the conflict-target clause, which + ** includes both the list of columns and the optional partial-index + ** WHERE clause. + */ + memset(&sNC, 0, sizeof(sNC)); + sNC.pParse = pParse; + sNC.pSrcList = pTabList; + for(; pUpsert && pUpsert->pUpsertTarget; + pUpsert=pUpsert->pNextUpsert, nClause++){ + rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); + if( rc ) return rc; + rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); + if( rc ) return rc; + + /* Check to see if the conflict target matches the rowid. */ + pTab = pTabList->a[0].pTab; + pTarget = pUpsert->pUpsertTarget; + iCursor = pTabList->a[0].iCursor; + if( HasRowid(pTab) + && pTarget->nExpr==1 + && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN + && pTerm->iColumn==XN_ROWID + ){ + /* The conflict-target is the rowid of the primary table */ + assert( pUpsert->pUpsertIdx==0 ); + continue; + } + + /* Initialize sCol[0..1] to be an expression parse tree for a + ** single column of an index. The sCol[0] node will be the TK_COLLATE + ** operator and sCol[1] will be the TK_COLUMN operator. Code below + ** will populate the specific collation and column number values + ** prior to comparing against the conflict-target expression. + */ + memset(sCol, 0, sizeof(sCol)); + sCol[0].op = TK_COLLATE; + sCol[0].pLeft = &sCol[1]; + sCol[1].op = TK_COLUMN; + sCol[1].iTable = pTabList->a[0].iCursor; + + /* Check for matches against other indexes */ + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int ii, jj, nn; + if( !IsUniqueIndex(pIdx) ) continue; + if( pTarget->nExpr!=pIdx->nKeyCol ) continue; + if( pIdx->pPartIdxWhere ){ + if( pUpsert->pUpsertTargetWhere==0 ) continue; + if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere, + pIdx->pPartIdxWhere, iCursor)!=0 ){ + continue; + } + } + nn = pIdx->nKeyCol; + for(ii=0; iiazColl[ii]; + if( pIdx->aiColumn[ii]==XN_EXPR ){ + assert( pIdx->aColExpr!=0 ); + assert( pIdx->aColExpr->nExpr>ii ); + pExpr = pIdx->aColExpr->a[ii].pExpr; + if( pExpr->op!=TK_COLLATE ){ + sCol[0].pLeft = pExpr; + pExpr = &sCol[0]; + } + }else{ + sCol[0].pLeft = &sCol[1]; + sCol[1].iColumn = pIdx->aiColumn[ii]; + pExpr = &sCol[0]; + } + for(jj=0; jja[jj].pExpr,pExpr,iCursor)<2 ){ + break; /* Column ii of the index matches column jj of target */ + } + } + if( jj>=nn ){ + /* The target contains no match for column jj of the index */ + break; + } + } + if( iipUpsertIdx = pIdx; + break; + } + if( pUpsert->pUpsertIdx==0 ){ + char zWhich[16]; + if( nClause==0 && pUpsert->pNextUpsert==0 ){ + zWhich[0] = 0; + }else{ + sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1); + } + sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any " + "PRIMARY KEY or UNIQUE constraint", zWhich); + return SQLITE_ERROR; + } + } + return SQLITE_OK; +} + +/* +** Return true if pUpsert is the last ON CONFLICT clause with a +** conflict target, or if pUpsert is followed by another ON CONFLICT +** clause that targets the INTEGER PRIMARY KEY. +*/ +SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){ + Upsert *pNext; + if( NEVER(pUpsert==0) ) return 0; + pNext = pUpsert->pNextUpsert; + if( pNext==0 ) return 1; + if( pNext->pUpsertTarget==0 ) return 1; + if( pNext->pUpsertIdx==0 ) return 1; + return 0; +} + +/* +** Given the list of ON CONFLICT clauses described by pUpsert, and +** a particular index pIdx, return a pointer to the particular ON CONFLICT +** clause that applies to the index. Or, if the index is not subject to +** any ON CONFLICT clause, return NULL. +*/ +SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){ + while( + pUpsert + && pUpsert->pUpsertTarget!=0 + && pUpsert->pUpsertIdx!=pIdx + ){ + pUpsert = pUpsert->pNextUpsert; + } + return pUpsert; +} + +/* +** Generate bytecode that does an UPDATE as part of an upsert. +** +** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK. +** In this case parameter iCur is a cursor open on the table b-tree that +** currently points to the conflicting table row. Otherwise, if pIdx +** is not NULL, then pIdx is the constraint that failed and iCur is a +** cursor points to the conflicting row. +*/ +SQLITE_PRIVATE void sqlite3UpsertDoUpdate( + Parse *pParse, /* The parsing and code-generating context */ + Upsert *pUpsert, /* The ON CONFLICT clause for the upsert */ + Table *pTab, /* The table being updated */ + Index *pIdx, /* The UNIQUE constraint that failed */ + int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */ +){ + Vdbe *v = pParse->pVdbe; + sqlite3 *db = pParse->db; + SrcList *pSrc; /* FROM clause for the UPDATE */ + int iDataCur; + int i; + Upsert *pTop = pUpsert; + + assert( v!=0 ); + assert( pUpsert!=0 ); + iDataCur = pUpsert->iDataCur; + pUpsert = sqlite3UpsertOfIndex(pTop, pIdx); + VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); + if( pIdx && iCur!=iDataCur ){ + if( HasRowid(pTab) ){ + int regRowid = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid); + sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, regRowid); + }else{ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + int nPk = pPk->nKeyCol; + int iPk = pParse->nMem+1; + pParse->nMem += nPk; + for(i=0; iaiColumn[i]>=0 ); + k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); + sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i); + VdbeComment((v, "%s.%s", pIdx->zName, + pTab->aCol[pPk->aiColumn[i]].zCnName)); + } + sqlite3VdbeVerifyAbortable(v, OE_Abort); + i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk); + VdbeCoverage(v); + sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, + "corrupt database", P4_STATIC); + sqlite3MayAbort(pParse); + sqlite3VdbeJumpHere(v, i); + } + } + /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does. + ** So we have to make a copy before passing it down into sqlite3Update() */ + pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0); + /* excluded.* columns of type REAL need to be converted to a hard real */ + for(i=0; inCol; i++){ + if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i); + } + } + sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0), + sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert); + VdbeNoopComment((v, "End DO UPDATE of UPSERT")); +} + +#endif /* SQLITE_OMIT_UPSERT */ + +/************** End of upsert.c **********************************************/ /************** Begin file vacuum.c ******************************************/ /* ** 2003 April 6 @@ -123724,8 +145101,14 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){ while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); - if( zSubSql ){ - assert( zSubSql[0]!='S' ); + /* The secondary SQL must be one of CREATE TABLE, CREATE INDEX, + ** or INSERT. Historically there have been attacks that first + ** corrupt the sqlite_schema.sql field with other kinds of statements + ** then run VACUUM to get those statements to execute at inappropriate + ** times. */ + if( zSubSql + && (strncmp(zSubSql,"CRE",3)==0 || strncmp(zSubSql,"INS",3)==0) + ){ rc = execSql(db, pzErrMsg, zSubSql); if( rc!=SQLITE_OK ) break; } @@ -123781,52 +145164,99 @@ static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){ ** transient would cause the database file to appear to be deleted ** following reboot. */ -SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){ +SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ Vdbe *v = sqlite3GetVdbe(pParse); - int iDb = pNm ? sqlite3TwoPartName(pParse, pNm, pNm, &pNm) : 0; - if( v && (iDb>=2 || iDb==0) ){ - sqlite3VdbeAddOp1(v, OP_Vacuum, iDb); + int iDb = 0; + if( v==0 ) goto build_vacuum_end; + if( pParse->nErr ) goto build_vacuum_end; + if( pNm ){ +#ifndef SQLITE_BUG_COMPATIBLE_20160819 + /* Default behavior: Report an error if the argument to VACUUM is + ** not recognized */ + iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm); + if( iDb<0 ) goto build_vacuum_end; +#else + /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments + ** to VACUUM are silently ignored. This is a back-out of a bug fix that + ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270). + ** The buggy behavior is required for binary compatibility with some + ** legacy applications. */ + iDb = sqlite3FindDb(pParse->db, pNm); + if( iDb<0 ) iDb = 0; +#endif + } + if( iDb!=1 ){ + int iIntoReg = 0; + if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){ + iIntoReg = ++pParse->nMem; + sqlite3ExprCode(pParse, pInto, iIntoReg); + } + sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg); sqlite3VdbeUsesBtree(v, iDb); } +build_vacuum_end: + sqlite3ExprDelete(pParse->db, pInto); return; } /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ -SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( + char **pzErrMsg, /* Write error message here */ + sqlite3 *db, /* Database connection */ + int iDb, /* Which attached DB to vacuum */ + sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */ +){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ - int saved_flags; /* Saved value of the db->flags */ - int saved_nChange; /* Saved value of db->nChange */ - int saved_nTotalChange; /* Saved value of db->nTotalChange */ + u32 saved_mDbFlags; /* Saved value of db->mDbFlags */ + u64 saved_flags; /* Saved value of db->flags */ + i64 saved_nChange; /* Saved value of db->nChange */ + i64 saved_nTotalChange; /* Saved value of db->nTotalChange */ + u32 saved_openFlags; /* Saved value of db->openFlags */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ const char *zDbMain; /* Schema name of database to vacuum */ + const char *zOut; /* Name of output file */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); - return SQLITE_ERROR; + return SQLITE_ERROR; /* IMP: R-12218-18073 */ } if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); - return SQLITE_ERROR; + return SQLITE_ERROR; /* IMP: R-15610-35227 */ + } + saved_openFlags = db->openFlags; + if( pOut ){ + if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ + sqlite3SetString(pzErrMsg, db, "non-text filename"); + return SQLITE_ERROR; + } + zOut = (const char*)sqlite3_value_text(pOut); + db->openFlags &= ~SQLITE_OPEN_READONLY; + db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE; + }else{ + zOut = ""; } - /* Save the current value of the database flags so that it can be + /* Save the current value of the database flags so that it can be ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; + saved_mDbFlags = db->mDbFlags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; - db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks - | SQLITE_PreferBuiltin | SQLITE_Vacuum); - db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows); + db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; + db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum; + db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder + | SQLITE_Defensive | SQLITE_CountRows); db->mTrace = 0; zDbMain = db->aDb[iDb].zDbSName; @@ -123848,31 +145278,24 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ ** to write the journal header file. */ nDb = db->nDb; - rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db"); + rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); + db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,"vacuum_db")==0 ); pTemp = pDb->pBt; - - /* The call to execSql() to attach the temp database has left the file - ** locked (as there was more than one active statement when the transaction - ** to read the schema was concluded. Unlock it here so that this doesn't - ** cause problems for the call to BtreeSetPageSize() below. */ - sqlite3BtreeCommit(pTemp); - - nRes = sqlite3BtreeGetOptimalReserve(pMain); - - /* A VACUUM cannot change the pagesize of an encrypted database. */ -#ifdef SQLITE_HAS_CODEC - if( db->nextPagesize ){ - extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); - int nKey; - char *zKey; - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - if( nKey ) db->nextPagesize = 0; + if( pOut ){ + sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); + i64 sz = 0; + if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ + rc = SQLITE_ERROR; + sqlite3SetString(pzErrMsg, db, "output file already exists"); + goto end_of_vacuum; + } + db->mDbFlags |= DBFLAG_VacuumInto; } -#endif + nRes = sqlite3BtreeGetRequestedReserve(pMain); sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); @@ -123884,12 +145307,14 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ */ rc = execSql(db, pzErrMsg, "BEGIN"); if( rc!=SQLITE_OK ) goto end_of_vacuum; - rc = sqlite3BtreeBeginTrans(pMain, 2); + rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Do not attempt to change the page size for a WAL database */ if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) - ==PAGER_JOURNALMODE_WAL ){ + ==PAGER_JOURNALMODE_WAL + && pOut==0 + ){ db->nextPagesize = 0; } @@ -123911,15 +145336,15 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ */ db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */ rc = execSqlF(db, pzErrMsg, - "SELECT sql FROM \"%w\".sqlite_master" + "SELECT sql FROM \"%w\".sqlite_schema" " WHERE type='table'AND name<>'sqlite_sequence'" " AND coalesce(rootpage,1)>0", zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execSqlF(db, pzErrMsg, - "SELECT sql FROM \"%w\".sqlite_master" - " WHERE type='index' AND length(sql)>10", + "SELECT sql FROM \"%w\".sqlite_schema" + " WHERE type='index'", zDbMain ); if( rc!=SQLITE_OK ) goto end_of_vacuum; @@ -123932,29 +145357,29 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ rc = execSqlF(db, pzErrMsg, "SELECT'INSERT INTO vacuum_db.'||quote(name)" "||' SELECT*FROM\"%w\".'||quote(name)" - "FROM vacuum_db.sqlite_master " + "FROM vacuum_db.sqlite_schema " "WHERE type='table'AND coalesce(rootpage,1)>0", zDbMain ); - assert( (db->flags & SQLITE_Vacuum)!=0 ); - db->flags &= ~SQLITE_Vacuum; + assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 ); + db->mDbFlags &= ~DBFLAG_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy the triggers, views, and virtual tables from the main database ** over to the temporary database. None of these objects has any ** associated storage, so all we have to do is copy their entries - ** from the SQLITE_MASTER table. + ** from the schema table. */ rc = execSqlF(db, pzErrMsg, - "INSERT INTO vacuum_db.sqlite_master" - " SELECT*FROM \"%w\".sqlite_master" + "INSERT INTO vacuum_db.sqlite_schema" + " SELECT*FROM \"%w\".sqlite_schema" " WHERE type IN('view','trigger')" " OR(type='table'AND rootpage=0)", zDbMain ); if( rc ) goto end_of_vacuum; - /* At this point, there is a write transaction open on both the + /* At this point, there is a write transaction open on both the ** vacuum database and the main database. Assuming no error occurs, ** both transactions are closed by this block - the main database ** transaction by sqlite3BtreeCopyFile() and the other by an explicit @@ -123978,8 +145403,8 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; - assert( 1==sqlite3BtreeIsInTrans(pTemp) ); - assert( 1==sqlite3BtreeIsInTrans(pMain) ); + assert( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) ); + assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) ); /* Copy Btree meta values */ for(i=0; iflags */ db->init.iDb = 0; + db->mDbFlags = saved_mDbFlags; db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; db->mTrace = saved_mTrace; - sqlite3BtreeSetPageSize(pMain, -1, -1, 1); + sqlite3BtreeSetPageSize(pMain, -1, 0, 1); /* Currently there is an SQL level transaction open on the vacuum ** database. No locks are held on any other files (since the main file @@ -124027,7 +145459,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ } /* This both clears the schemas and reduces the size of the db->aDb[] - ** array. */ + ** array. */ sqlite3ResetAllSchemasOfConnection(db); return rc; @@ -124056,7 +145488,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){ /* ** Before a virtual table xCreate() or xConnect() method is invoked, the ** sqlite3.pVtabCtx member variable is set to point to an instance of -** this struct allocated on the stack. It is used by the implementation of +** this struct allocated on the stack. It is used by the implementation of ** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which ** are invoked only from within xCreate and xConnect methods. */ @@ -124071,6 +145503,9 @@ struct VtabCtx { ** Construct and install a Module object for a virtual table. When this ** routine is called, it is guaranteed that all appropriate locks are held ** and the module is not already part of the connection. +** +** If there already exists a module with zName, replace it with the new one. +** If pModule==0, then delete the module zName if it exists. */ SQLITE_PRIVATE Module *sqlite3VtabCreateModule( sqlite3 *db, /* Database in which module is registered */ @@ -124080,23 +145515,36 @@ SQLITE_PRIVATE Module *sqlite3VtabCreateModule( void (*xDestroy)(void *) /* Module destructor function */ ){ Module *pMod; - int nName = sqlite3Strlen30(zName); - pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1); - if( pMod ){ - Module *pDel; - char *zCopy = (char *)(&pMod[1]); + Module *pDel; + char *zCopy; + if( pModule==0 ){ + zCopy = (char*)zName; + pMod = 0; + }else{ + int nName = sqlite3Strlen30(zName); + pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); + if( pMod==0 ){ + sqlite3OomFault(db); + return 0; + } + zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; pMod->pEpoTab = 0; - pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); - assert( pDel==0 || pDel==pMod ); - if( pDel ){ + pMod->nRefModule = 1; + } + pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); + if( pDel ){ + if( pDel==pMod ){ sqlite3OomFault(db); sqlite3DbFree(db, pDel); pMod = 0; + }else{ + sqlite3VtabEponymousTableClear(db, pDel); + sqlite3VtabModuleUnref(db, pDel); } } return pMod; @@ -124117,11 +145565,7 @@ static int createModule( int rc = SQLITE_OK; sqlite3_mutex_enter(db->mutex); - if( sqlite3HashFind(&db->aModule, zName) ){ - rc = SQLITE_MISUSE_BKPT; - }else{ - (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); - } + (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy); rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux); sqlite3_mutex_leave(db->mutex); @@ -124160,10 +145604,48 @@ SQLITE_API int sqlite3_create_module_v2( return createModule(db, zName, pModule, pAux, xDestroy); } +/* +** External API to drop all virtual-table modules, except those named +** on the azNames list. +*/ +SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){ + HashElem *pThis, *pNext; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){ + Module *pMod = (Module*)sqliteHashData(pThis); + pNext = sqliteHashNext(pThis); + if( azNames ){ + int ii; + for(ii=0; azNames[ii]!=0 && strcmp(azNames[ii],pMod->zName)!=0; ii++){} + if( azNames[ii]!=0 ) continue; + } + createModule(db, pMod->zName, 0, 0, 0); + } + return SQLITE_OK; +} + +/* +** Decrement the reference count on a Module object. Destroy the +** module when the reference count reaches zero. +*/ +SQLITE_PRIVATE void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){ + assert( pMod->nRefModule>0 ); + pMod->nRefModule--; + if( pMod->nRefModule==0 ){ + if( pMod->xDestroy ){ + pMod->xDestroy(pMod->pAux); + } + assert( pMod->pEpoTab==0 ); + sqlite3DbFree(db, pMod); + } +} + /* ** Lock the virtual table so that it cannot be disconnected. ** Locks nest. Every lock should have a corresponding unlock. -** If an unlock is omitted, resources leaks will occur. +** If an unlock is omitted, resources leaks will occur. ** ** If a disconnect is attempted while a virtual table is locked, ** the disconnect is deferred until all locks have been removed. @@ -124175,13 +145657,13 @@ SQLITE_PRIVATE void sqlite3VtabLock(VTable *pVTab){ /* ** pTab is a pointer to a Table structure representing a virtual-table. -** Return a pointer to the VTable object used by connection db to access +** Return a pointer to the VTable object used by connection db to access ** this virtual-table, if one has been created, or NULL otherwise. */ SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); - for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); + for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); return pVtab; } @@ -124194,11 +145676,13 @@ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){ assert( db ); assert( pVTab->nRef>0 ); - assert( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ZOMBIE ); + assert( db->eOpenState==SQLITE_STATE_OPEN + || db->eOpenState==SQLITE_STATE_ZOMBIE ); pVTab->nRef--; if( pVTab->nRef==0 ){ sqlite3_vtab *p = pVTab->pVtab; + sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod); if( p ){ p->pModule->xDisconnect(p); } @@ -124208,21 +145692,24 @@ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){ /* ** Table p is a virtual table. This function moves all elements in the -** p->pVTable list to the sqlite3.pDisconnect lists of their associated -** database connections to be disconnected at the next opportunity. +** p->u.vtab.p list to the sqlite3.pDisconnect lists of their associated +** database connections to be disconnected at the next opportunity. ** Except, if argument db is not NULL, then the entry associated with -** connection db is left in the p->pVTable list. +** connection db is left in the p->u.vtab.p list. */ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ VTable *pRet = 0; - VTable *pVTable = p->pVTable; - p->pVTable = 0; + VTable *pVTable; + + assert( IsVirtual(p) ); + pVTable = p->u.vtab.p; + p->u.vtab.p = 0; - /* Assert that the mutex (if any) associated with the BtShared database - ** that contains table p is held by the caller. See header comments + /* Assert that the mutex (if any) associated with the BtShared database + ** that contains table p is held by the caller. See header comments ** above function sqlite3VtabUnlockList() for an explanation of why ** this makes it safe to access the sqlite3.pDisconnect list of any - ** database connection that may have an entry in the p->pVTable list. + ** database connection that may have an entry in the p->u.vtab.p list. */ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) ); @@ -124232,7 +145719,7 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ assert( db2 ); if( db2==db ){ pRet = pVTable; - p->pVTable = pRet; + p->u.vtab.p = pRet; pRet->pNext = 0; }else{ pVTable->pNext = db2->pDisconnect; @@ -124260,7 +145747,7 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); - for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){ + for(ppVTab=&p->u.vtab.p; *ppVTab; ppVTab=&(*ppVTab)->pNext){ if( (*ppVTab)->db==db ){ VTable *pVTab = *ppVTab; *ppVTab = pVTab->pNext; @@ -124275,7 +145762,7 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ ** Disconnect all the virtual table objects in the sqlite3.pDisconnect list. ** ** This function may only be called when the mutexes associated with all -** shared b-tree databases opened using connection db are held by the +** shared b-tree databases opened using connection db are held by the ** caller. This is done to protect the sqlite3.pDisconnect list. The ** sqlite3.pDisconnect list is accessed only as follows: ** @@ -124288,18 +145775,18 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ ** or, if the virtual table is stored in a non-sharable database, then ** the database handle mutex is held. ** -** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously +** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously ** by multiple threads. It is thread-safe. */ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){ VTable *p = db->pDisconnect; - db->pDisconnect = 0; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); if( p ){ - sqlite3ExpirePreparedStatements(db); + db->pDisconnect = 0; + sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); @@ -124314,42 +145801,50 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){ ** record. ** ** Since it is a virtual-table, the Table structure contains a pointer -** to the head of a linked list of VTable structures. Each VTable +** to the head of a linked list of VTable structures. Each VTable ** structure is associated with a single sqlite3* user of the schema. -** The reference count of the VTable structure associated with database -** connection db is decremented immediately (which may lead to the +** The reference count of the VTable structure associated with database +** connection db is decremented immediately (which may lead to the ** structure being xDisconnected and free). Any other VTable structures -** in the list are moved to the sqlite3.pDisconnect list of the associated +** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){ + assert( IsVirtual(p) ); if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); - if( p->azModuleArg ){ + if( p->u.vtab.azArg ){ int i; - for(i=0; inModuleArg; i++){ - if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]); + for(i=0; iu.vtab.nArg; i++){ + if( i!=1 ) sqlite3DbFree(db, p->u.vtab.azArg[i]); } - sqlite3DbFree(db, p->azModuleArg); + sqlite3DbFree(db, p->u.vtab.azArg); } } /* -** Add a new module argument to pTable->azModuleArg[]. +** Add a new module argument to pTable->u.vtab.azArg[]. ** The string is not copied - the pointer is stored. The ** string will be freed automatically when the table is ** deleted. */ -static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ - int nBytes = sizeof(char *)*(2+pTable->nModuleArg); +static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){ + sqlite3_int64 nBytes; char **azModuleArg; - azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); + sqlite3 *db = pParse->db; + + assert( IsVirtual(pTable) ); + nBytes = sizeof(char *)*(2+pTable->u.vtab.nArg); + if( pTable->u.vtab.nArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ + sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName); + } + azModuleArg = sqlite3DbRealloc(db, pTable->u.vtab.azArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); }else{ - int i = pTable->nModuleArg++; + int i = pTable->u.vtab.nArg++; azModuleArg[i] = zArg; azModuleArg[i+1] = 0; - pTable->azModuleArg = azModuleArg; + pTable->u.vtab.azArg = azModuleArg; } } @@ -124365,7 +145860,6 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( Token *pModuleName, /* Name of the module for the virtual table */ int ifNotExists /* No error if the table already exists */ ){ - int iDb; /* The database the table is being created in */ Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ @@ -124373,16 +145867,14 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); + pTable->eTabType = TABTYP_VTAB; db = pParse->db; - iDb = sqlite3SchemaToIndex(db, pTable->pSchema); - assert( iDb>=0 ); - pTable->tabFlags |= TF_Virtual; - pTable->nModuleArg = 0; - addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); - addModuleArgument(db, pTable, 0); - addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); + assert( pTable->u.vtab.nArg==0 ); + addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName)); + addModuleArgument(pParse, pTable, 0); + addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName)); assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) || (pParse->sNameToken.z==pName1->z && pName2->z==0) ); @@ -124393,12 +145885,14 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( #ifndef SQLITE_OMIT_AUTHORIZATION /* Creating a virtual table invokes the authorization callback twice. ** The first invocation, to obtain permission to INSERT a row into the - ** sqlite_master table, has already been made by sqlite3StartTable(). + ** sqlite_schema table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ - if( pTable->azModuleArg ){ - sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, - pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); + if( pTable->u.vtab.azArg ){ + int iDb = sqlite3SchemaToIndex(db, pTable->pSchema); + assert( iDb>=0 ); /* The database the table is being created in */ + sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, + pTable->u.vtab.azArg[0], pParse->db->aDb[iDb].zDbSName); } #endif } @@ -124413,7 +145907,7 @@ static void addArgumentToVtab(Parse *pParse){ const char *z = (const char*)pParse->sArg.z; int n = pParse->sArg.n; sqlite3 *db = pParse->db; - addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); + addModuleArgument(pParse, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); } } @@ -124426,15 +145920,16 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ sqlite3 *db = pParse->db; /* The database connection */ if( pTab==0 ) return; + assert( IsVirtual(pTab) ); addArgumentToVtab(pParse); pParse->sArg.z = 0; - if( pTab->nModuleArg<1 ) return; - + if( pTab->u.vtab.nArg<1 ) return; + /* If the CREATE VIRTUAL TABLE statement is being entered for the ** first time (in other words if the virtual table is actually being - ** created now instead of just being read out of sqlite_master) then + ** created now instead of just being read out of sqlite_schema) then ** do additional initialization work and store the statement text - ** in the sqlite_master table. + ** in the sqlite_schema table. */ if( !db->init.busy ){ char *zStmt; @@ -124443,54 +145938,52 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ int iReg; Vdbe *v; + sqlite3MayAbort(pParse); + /* Compute the complete text of the CREATE VIRTUAL TABLE statement */ if( pEnd ){ pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n; } zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken); - /* A slot for the record has already been allocated in the - ** SQLITE_MASTER table. We just need to update that slot with all - ** the information we've collected. + /* A slot for the record has already been allocated in the + ** schema table. We just need to update that slot with all + ** the information we've collected. ** ** The VM register number pParse->regRowid holds the rowid of an - ** entry in the sqlite_master table tht was created for this vtab + ** entry in the sqlite_schema table tht was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, - "UPDATE %Q.%s " + "UPDATE %Q." LEGACY_SCHEMA_TABLE " " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", - db->aDb[iDb].zDbSName, MASTER_NAME, + db->aDb[iDb].zDbSName, pTab->zName, pTab->zName, zStmt, pParse->regRowid ); - sqlite3DbFree(db, zStmt); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); - zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); - sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); + zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt); + sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0); + sqlite3DbFree(db, zStmt); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); - } - - /* If we are rereading the sqlite_master table create the in-memory - ** record of the table. The xConnect() method is not called until - ** the first time the virtual table is used in an SQL statement. This - ** allows a schema that contains virtual tables to be loaded before - ** the required virtual table implementations are registered. */ - else { + }else{ + /* If we are rereading the sqlite_schema table create the in-memory + ** record of the table. */ Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; - assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); + assert( zName!=0 ); + sqlite3MarkAllShadowTablesOf(db, pTab); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ sqlite3OomFault(db); @@ -124532,7 +146025,7 @@ SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){ ** to this procedure. */ static int vtabCallConstructor( - sqlite3 *db, + sqlite3 *db, Table *pTab, Module *pMod, int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), @@ -124541,38 +146034,43 @@ static int vtabCallConstructor( VtabCtx sCtx; VTable *pVTable; int rc; - const char *const*azArg = (const char *const*)pTab->azModuleArg; - int nArg = pTab->nModuleArg; + const char *const*azArg; + int nArg = pTab->u.vtab.nArg; char *zErr = 0; char *zModuleName; int iDb; VtabCtx *pCtx; + assert( IsVirtual(pTab) ); + azArg = (const char *const*)pTab->u.vtab.azArg; + /* Check that the virtual-table is not already being initialized */ for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){ if( pCtx->pTab==pTab ){ - *pzErr = sqlite3MPrintf(db, + *pzErr = sqlite3MPrintf(db, "vtable constructor called recursively: %s", pTab->zName ); return SQLITE_LOCKED; } } - zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); + zModuleName = sqlite3DbStrDup(db, pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM_BKPT; } - pVTable = sqlite3DbMallocZero(db, sizeof(VTable)); + pVTable = sqlite3MallocZero(sizeof(VTable)); if( !pVTable ){ + sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; + pVTable->eVtabRisk = SQLITE_VTABRISK_Normal; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); - pTab->azModuleArg[1] = db->aDb[iDb].zDbSName; + pTab->u.vtab.azArg[1] = db->aDb[iDb].zDbSName; /* Invoke the virtual table constructor */ assert( &db->pVtabCtx ); @@ -124600,6 +146098,7 @@ static int vtabCallConstructor( ** the sqlite3_vtab object if successful. */ memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0])); pVTable->pVtab->pModule = pMod->pModule; + pMod->nRefModule++; pVTable->nRef = 1; if( sCtx.bDeclared==0 ){ const char *zFormat = "vtable constructor did not declare schema: %s"; @@ -124608,14 +146107,14 @@ static int vtabCallConstructor( rc = SQLITE_ERROR; }else{ int iCol; - u8 oooHidden = 0; + u16 oooHidden = 0; /* If everything went according to plan, link the new VTable structure - ** into the linked list headed by pTab->pVTable. Then loop through the + ** into the linked list headed by pTab->u.vtab.p. Then loop through the ** columns of the table to see if any of them contain the token "hidden". ** If so, set the Column COLFLAG_HIDDEN flag and remove the token from ** the type string. */ - pVTable->pNext = pTab->pVTable; - pTab->pVTable = pVTable; + pVTable->pNext = pTab->u.vtab.p; + pTab->u.vtab.p = pVTable; for(iCol=0; iColnCol; iCol++){ char *zType = sqlite3ColumnType(&pTab->aCol[iCol], ""); @@ -124641,6 +146140,7 @@ static int vtabCallConstructor( zType[i-1] = '\0'; } pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN; + pTab->tabFlags |= TF_HasHidden; oooHidden = TF_OOOHidden; }else{ pTab->tabFlags |= oooHidden; @@ -124655,7 +146155,7 @@ static int vtabCallConstructor( /* ** This function is invoked by the parser to call the xConnect() method -** of the virtual table pTab. If an error occurs, an error code is returned +** of the virtual table pTab. If an error occurs, an error code is returned ** and an error left in pParse. ** ** This call is a no-op if table pTab is not a virtual table. @@ -124667,16 +146167,17 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ int rc; assert( pTab ); - if( (pTab->tabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){ + assert( IsVirtual(pTab) ); + if( sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } /* Locate the required virtual table module */ - zMod = pTab->azModuleArg[0]; + zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); if( !pMod ){ - const char *zModule = pTab->azModuleArg[0]; + const char *zModule = pTab->u.vtab.azArg[0]; sqlite3ErrorMsg(pParse, "no such module: %s", zModule); rc = SQLITE_ERROR; }else{ @@ -124684,6 +146185,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "%s", zErr); + pParse->rc = rc; } sqlite3DbFree(db, zErr); } @@ -124700,7 +146202,8 @@ static int growVTrans(sqlite3 *db){ /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ VTable **aVTrans; - int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); + sqlite3_int64 nBytes = sizeof(sqlite3_vtab*)* + ((sqlite3_int64)db->nVTrans + ARRAY_INCR); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM_BKPT; @@ -124724,7 +146227,7 @@ static void addToVTrans(sqlite3 *db, VTable *pVTab){ /* ** This function is invoked by the vdbe to call the xCreate method -** of the virtual table named zTab in database iDb. +** of the virtual table named zTab in database iDb. ** ** If an error occurs, *pzErr is set to point to an English language ** description of the error and an SQLITE_XXX error code is returned. @@ -124737,14 +146240,14 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, const char *zMod; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); - assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable ); + assert( pTab && IsVirtual(pTab) && !pTab->u.vtab.p ); /* Locate the required virtual table module */ - zMod = pTab->azModuleArg[0]; + zMod = pTab->u.vtab.azArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); - /* If the module has been registered and includes a Create method, - ** invoke it now. If the module has not been registered, return an + /* If the module has been registered and includes a Create method, + ** invoke it now. If the module has not been registered, return an ** error. Otherwise, do nothing. */ if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){ @@ -124773,10 +146276,10 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, */ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ VtabCtx *pCtx; - Parse *pParse; int rc = SQLITE_OK; Table *pTab; - char *zErr = 0; + Parse sParse; + int initBusy; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){ @@ -124791,57 +146294,66 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ return SQLITE_MISUSE_BKPT; } pTab = pCtx->pTab; - assert( (pTab->tabFlags & TF_Virtual)!=0 ); + assert( IsVirtual(pTab) ); - pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); - if( pParse==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - pParse->declareVtab = 1; - pParse->db = db; - pParse->nQueryLoop = 1; - - if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) - && pParse->pNewTable - && !db->mallocFailed - && !pParse->pNewTable->pSelect - && (pParse->pNewTable->tabFlags & TF_Virtual)==0 - ){ - if( !pTab->aCol ){ - Table *pNew = pParse->pNewTable; - Index *pIdx; - pTab->aCol = pNew->aCol; - pTab->nCol = pNew->nCol; - pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); - pNew->nCol = 0; - pNew->aCol = 0; - assert( pTab->pIndex==0 ); - if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){ - rc = SQLITE_ERROR; - } - pIdx = pNew->pIndex; - if( pIdx ){ - assert( pIdx->pNext==0 ); - pTab->pIndex = pIdx; - pNew->pIndex = 0; - pIdx->pTable = pTab; - } + sqlite3ParseObjectInit(&sParse, db); + sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; + sParse.disableTriggers = 1; + /* We should never be able to reach this point while loading the + ** schema. Nevertheless, defend against that (turn off db->init.busy) + ** in case a bug arises. */ + assert( db->init.busy==0 ); + initBusy = db->init.busy; + db->init.busy = 0; + sParse.nQueryLoop = 1; + if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable) + && ALWAYS(sParse.pNewTable!=0) + && ALWAYS(!db->mallocFailed) + && IsOrdinaryTable(sParse.pNewTable) + ){ + assert( sParse.zErrMsg==0 ); + if( !pTab->aCol ){ + Table *pNew = sParse.pNewTable; + Index *pIdx; + pTab->aCol = pNew->aCol; + sqlite3ExprListDelete(db, pNew->u.tab.pDfltList); + pTab->nNVCol = pTab->nCol = pNew->nCol; + pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); + pNew->nCol = 0; + pNew->aCol = 0; + assert( pTab->pIndex==0 ); + assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 ); + if( !HasRowid(pNew) + && pCtx->pVTable->pMod->pModule->xUpdate!=0 + && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1 + ){ + /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0) + ** or else must have a single-column PRIMARY KEY */ + rc = SQLITE_ERROR; + } + pIdx = pNew->pIndex; + if( pIdx ){ + assert( pIdx->pNext==0 ); + pTab->pIndex = pIdx; + pNew->pIndex = 0; + pIdx->pTable = pTab; } - pCtx->bDeclared = 1; - }else{ - sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); - sqlite3DbFree(db, zErr); - rc = SQLITE_ERROR; - } - pParse->declareVtab = 0; - - if( pParse->pVdbe ){ - sqlite3VdbeFinalize(pParse->pVdbe); } - sqlite3DeleteTable(db, pParse->pNewTable); - sqlite3ParserReset(pParse); - sqlite3StackFree(db, pParse); + pCtx->bDeclared = 1; + }else{ + sqlite3ErrorWithMsg(db, SQLITE_ERROR, + (sParse.zErrMsg ? "%s" : 0), sParse.zErrMsg); + sqlite3DbFree(db, sParse.zErrMsg); + rc = SQLITE_ERROR; } + sParse.eParseMode = PARSE_MODE_NORMAL; + + if( sParse.pVdbe ){ + sqlite3VdbeFinalize(sParse.pVdbe); + } + sqlite3DeleteTable(db, sParse.pNewTable); + sqlite3ParseObjectReset(&sParse); + db->init.busy = initBusy; assert( (rc&0xff)==rc ); rc = sqlite3ApiExit(db, rc); @@ -124861,10 +146373,13 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName); - if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ + if( ALWAYS(pTab!=0) + && ALWAYS(IsVirtual(pTab)) + && ALWAYS(pTab->u.vtab.p!=0) + ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); - for(p=pTab->pVTable; p; p=p->pNext){ + for(p=pTab->u.vtab.p; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; @@ -124872,15 +146387,18 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab } p = vtabDisconnectAll(db, pTab); xDestroy = p->pMod->pModule->xDestroy; - assert( xDestroy!=0 ); /* Checked before the virtual table is created */ + if( xDestroy==0 ) xDestroy = p->pMod->pModule->xDisconnect; + assert( xDestroy!=0 ); + pTab->nTabRef++; rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ - assert( pTab->pVTable==p && p->pNext==0 ); + assert( pTab->u.vtab.p==p && p->pNext==0 ); p->pVtab = 0; - pTab->pVTable = 0; + pTab->u.vtab.p = 0; sqlite3VtabUnlock(p); } + sqlite3DeleteTable(db, pTab); } return rc; @@ -124892,7 +146410,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab ** called is identified by the second argument, "offset", which is ** the offset of the method to call in the sqlite3_module structure. ** -** The array is cleared after invoking the callbacks. +** The array is cleared after invoking the callbacks. */ static void callFinaliser(sqlite3 *db, int offset){ int i; @@ -124941,7 +146459,7 @@ SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe *p){ } /* -** Invoke the xRollback method of all virtual tables in the +** Invoke the xRollback method of all virtual tables in the ** sqlite3.aVTrans array. Then clear the array itself. */ SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){ @@ -124950,7 +146468,7 @@ SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){ } /* -** Invoke the xCommit method of all virtual tables in the +** Invoke the xCommit method of all virtual tables in the ** sqlite3.aVTrans array. Then clear the array itself. */ SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db){ @@ -124972,7 +146490,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a - ** virtual module xSync() callback. It is illegal to write to + ** virtual module xSync() callback. It is illegal to write to ** virtual module tables in this case, so return SQLITE_LOCKED. */ if( sqlite3VtabInSync(db) ){ @@ -124980,7 +146498,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ } if( !pVTab ){ return SQLITE_OK; - } + } pModule = pVTab->pVtab->pModule; if( pModule->xBegin ){ @@ -124993,7 +146511,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ } } - /* Invoke the xBegin method. If successful, add the vtab to the + /* Invoke the xBegin method. If successful, add the vtab to the ** sqlite3.aVTrans[] array. */ rc = growVTrans(db); if( rc==SQLITE_OK ){ @@ -125017,11 +146535,11 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ ** as the second argument to the virtual table method invoked. ** ** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is -** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is +** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is ** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with ** an open transaction is invoked. ** -** If any virtual table method returns an error code other than SQLITE_OK, +** If any virtual table method returns an error code other than SQLITE_OK, ** processing is abandoned and the error returned to the caller of this ** function immediately. If all calls to virtual table methods are successful, ** SQLITE_OK is returned. @@ -125038,6 +146556,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ const sqlite3_module *pMod = pVTab->pMod->pModule; if( pVTab->pVtab && pMod->iVersion>=2 ){ int (*xMethod)(sqlite3_vtab *, int); + sqlite3VtabLock(pVTab); switch( op ){ case SAVEPOINT_BEGIN: xMethod = pMod->xSavepoint; @@ -125053,6 +146572,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ if( xMethod && pVTab->iSavepoint>iSavepoint ){ rc = xMethod(pVTab->pVtab, iSavepoint); } + sqlite3VtabUnlock(pVTab); } } } @@ -125068,7 +146588,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ ** This routine is used to allow virtual table implementations to ** overload MATCH, LIKE, GLOB, and REGEXP operators. ** -** Return either the pDef argument (indicating no change) or a +** Return either the pDef argument (indicating no change) or a ** new FuncDef structure that is marked as ephemeral using the ** SQLITE_FUNC_EPHEM flag. */ @@ -125085,33 +146605,37 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction( void *pArg = 0; FuncDef *pNew; int rc = 0; - char *zLowerName; - unsigned char *z; - /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; - pTab = pExpr->pTab; - if( NEVER(pTab==0) ) return pDef; - if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef; + assert( ExprUseYTab(pExpr) ); + pTab = pExpr->y.pTab; + if( pTab==0 ) return pDef; + if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction==0 ) return pDef; - + /* Call the xFindFunction method on the virtual table implementation - ** to see if the implementation wants to overload this function + ** to see if the implementation wants to overload this function. + ** + ** Though undocumented, we have historically always invoked xFindFunction + ** with an all lower-case function name. Continue in this tradition to + ** avoid any chance of an incompatibility. */ - zLowerName = sqlite3DbStrDup(db, pDef->zName); - if( zLowerName ){ - for(z=(unsigned char*)zLowerName; *z; z++){ - *z = sqlite3UpperToLower[*z]; +#ifdef SQLITE_DEBUG + { + int i; + for(i=0; pDef->zName[i]; i++){ + unsigned char x = (unsigned char)pDef->zName[i]; + assert( x==sqlite3UpperToLower[x] ); } - rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg); - sqlite3DbFree(db, zLowerName); } +#endif + rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg); if( rc==0 ){ return pDef; } @@ -125148,7 +146672,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ if( pTab==pToplevel->apVtabLock[i] ) return; } n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]); - apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n); + apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n); if( apVtabLock ){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; @@ -125160,8 +146684,9 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ /* ** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already -** exist. Return non-zero if the eponymous virtual table instance exists -** when this routine returns, and return zero if it does not exist. +** exist. Return non-zero if either the eponymous virtual table instance +** exists when this routine returns or if an attempt to create it failed +** and an error message was left in pParse. ** ** An eponymous virtual table instance is one that is named after its ** module, and more importantly, does not require a CREATE VIRTUAL TABLE @@ -125188,19 +146713,19 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ } pMod->pEpoTab = pTab; pTab->nTabRef = 1; + pTab->eTabType = TABTYP_VTAB; pTab->pSchema = db->aDb[0].pSchema; - pTab->tabFlags |= TF_Virtual; - pTab->nModuleArg = 0; + assert( pTab->u.vtab.nArg==0 ); pTab->iPKey = -1; - addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); - addModuleArgument(db, pTab, 0); - addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); + pTab->tabFlags |= TF_Eponymous; + addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); + addModuleArgument(pParse, pTab, 0); + addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); if( rc ){ sqlite3ErrorMsg(pParse, "%s", zErr); sqlite3DbFree(db, zErr); sqlite3VtabEponymousTableClear(db, pMod); - return 0; } return 1; } @@ -125213,7 +146738,7 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ /* Mark the table as Ephemeral prior to deleting it, so that the - ** sqlite3DeleteTable() routine will know that it is not stored in + ** sqlite3DeleteTable() routine will know that it is not stored in ** the schema. */ pTab->tabFlags |= TF_Ephemeral; sqlite3DeleteTable(db, pTab); @@ -125229,8 +146754,8 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ ** within an xUpdate method. */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){ - static const unsigned char aMap[] = { - SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE + static const unsigned char aMap[] = { + SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE }; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; @@ -125242,35 +146767,45 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){ } /* -** Call from within the xCreate() or xConnect() methods to provide +** Call from within the xCreate() or xConnect() methods to provide ** the SQLite core with additional information about the behavior ** of the virtual table being implemented. */ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ va_list ap; int rc = SQLITE_OK; + VtabCtx *p; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); - va_start(ap, op); - switch( op ){ - case SQLITE_VTAB_CONSTRAINT_SUPPORT: { - VtabCtx *p = db->pVtabCtx; - if( !p ){ - rc = SQLITE_MISUSE_BKPT; - }else{ - assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 ); + p = db->pVtabCtx; + if( !p ){ + rc = SQLITE_MISUSE_BKPT; + }else{ + assert( p->pTab==0 || IsVirtual(p->pTab) ); + va_start(ap, op); + switch( op ){ + case SQLITE_VTAB_CONSTRAINT_SUPPORT: { p->pVTable->bConstraint = (u8)va_arg(ap, int); + break; + } + case SQLITE_VTAB_INNOCUOUS: { + p->pVTable->eVtabRisk = SQLITE_VTABRISK_Low; + break; + } + case SQLITE_VTAB_DIRECTONLY: { + p->pVTable->eVtabRisk = SQLITE_VTABRISK_High; + break; + } + default: { + rc = SQLITE_MISUSE_BKPT; + break; } - break; } - default: - rc = SQLITE_MISUSE_BKPT; - break; + va_end(ap); } - va_end(ap); if( rc!=SQLITE_OK ) sqlite3Error(db, rc); sqlite3_mutex_leave(db->mutex); @@ -125319,20 +146854,9 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ ** planner logic in "where.c". These definitions are broken out into ** a separate source file for easier editing. */ +#ifndef SQLITE_WHEREINT_H +#define SQLITE_WHEREINT_H -/* -** Trace output macros -*/ -#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) -/***/ int sqlite3WhereTrace; -#endif -#if defined(SQLITE_DEBUG) \ - && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) -# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X -# define WHERETRACE_ENABLED 1 -#else -# define WHERETRACE(K,X) -#endif /* Forward references */ @@ -125374,23 +146898,28 @@ struct WhereLevel { int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ + int regBignull; /* big-null flag reg. True if a NULL-scan is needed */ + int addrBignull; /* Jump here for next part of big-null scan */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ int addrLikeRep; /* LIKE range processing address */ #endif + int regFilter; /* Bloom filter */ u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ - int p1, p2; /* Operands of the opcode used to ends the loop */ + int p1, p2; /* Operands of the opcode used to end the loop */ union { /* Information that depends on pWLoop->wsFlags */ struct { int nIn; /* Number of entries in aInLoop[] */ struct InLoop { int iCur; /* The VDBE cursor used by this IN operator */ int addrInTop; /* Top of the IN loop */ + int iBase; /* Base register of multi-key index record */ + int nPrefix; /* Number of prior entires in the key */ u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ - Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ + Index *pCoveringIdx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ @@ -125429,14 +146958,17 @@ struct WhereLoop { u16 nEq; /* Number of equality constraints */ u16 nBtm; /* Size of BTM vector */ u16 nTop; /* Size of TOP vector */ + u16 nDistinctCol; /* Index columns used to sort for DISTINCT */ Index *pIndex; /* Index used, or NULL */ } btree; struct { /* Information for virtual tables */ int idxNum; /* Index number */ - u8 needFree; /* True if sqlite3_free(idxStr) is needed */ + u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */ + u32 bOmitOffset : 1; /* True to let virtual table handle offset */ i8 isOrdered; /* True if satisfies ORDER BY */ u16 omitMask; /* Terms that may be omitted */ char *idxStr; /* Index identifier string */ + u32 mHandleIn; /* Terms to handle as IN(...) instead of == */ } vtab; } u; u32 wsFlags; /* WHERE_* flags describing the plan */ @@ -125452,7 +146984,7 @@ struct WhereLoop { /* This object holds the prerequisites and the cost of running a ** subquery on one operand of an OR operator in the WHERE clause. -** See WhereOrSet for additional information +** See WhereOrSet for additional information */ struct WhereOrCost { Bitmask prereq; /* Prerequisites */ @@ -125504,7 +147036,7 @@ struct WherePath { ** clause subexpression is separated from the others by AND operators, ** usually, or sometimes subexpressions separated by OR. ** -** All WhereTerms are collected into a single WhereClause structure. +** All WhereTerms are collected into a single WhereClause structure. ** The following identity holds: ** ** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm @@ -125559,9 +147091,11 @@ struct WhereTerm { u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X " */ - int iField; /* Field in (?,?,?) IN (SELECT...) vector */ union { - int leftColumn; /* Column number of X in "X " */ + struct { + int leftColumn; /* Column number of X in "X " */ + int iField; /* Field in (?,?,?) IN (SELECT...) vector */ + } x; /* Opcode other than OP_OR or OP_AND */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; @@ -125572,22 +147106,26 @@ struct WhereTerm { /* ** Allowed values of WhereTerm.wtFlags */ -#define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(db, pExpr) */ -#define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */ -#define TERM_CODED 0x04 /* This term is already coded */ -#define TERM_COPIED 0x08 /* Has a child */ -#define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */ -#define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */ -#define TERM_OR_OK 0x40 /* Used during OR-clause processing */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 -# define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ +#define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(db, pExpr) */ +#define TERM_VIRTUAL 0x0002 /* Added by the optimizer. Do not code */ +#define TERM_CODED 0x0004 /* This term is already coded */ +#define TERM_COPIED 0x0008 /* Has a child */ +#define TERM_ORINFO 0x0010 /* Need to free the WhereTerm.u.pOrInfo object */ +#define TERM_ANDINFO 0x0020 /* Need to free the WhereTerm.u.pAndInfo obj */ +#define TERM_OK 0x0040 /* Used during OR-clause processing */ +#define TERM_VNULL 0x0080 /* Manufactured x>NULL or x<=NULL term */ +#define TERM_LIKEOPT 0x0100 /* Virtual terms from the LIKE optimization */ +#define TERM_LIKECOND 0x0200 /* Conditionally this LIKE operator term */ +#define TERM_LIKE 0x0400 /* The original LIKE operator */ +#define TERM_IS 0x0800 /* Term.pExpr is an IS operator */ +#define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */ +#define TERM_HEURTRUTH 0x2000 /* Heuristic truthProb used */ +#ifdef SQLITE_ENABLE_STAT4 +# define TERM_HIGHTRUTH 0x4000 /* Term excludes few rows */ #else -# define TERM_VNULL 0x00 /* Disabled if not using stat3 */ +# define TERM_HIGHTRUTH 0 /* Only used with STAT4 */ #endif -#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ -#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ -#define TERM_LIKE 0x400 /* The original LIKE operator */ -#define TERM_IS 0x800 /* Term.pExpr is an IS operator */ +#define TERM_SLICE 0x8000 /* One slice of a row-value/vector comparison */ /* ** An instance of the WhereScan object is used as an iterator for locating @@ -125598,11 +147136,11 @@ struct WhereScan { WhereClause *pWC; /* WhereClause currently being scanned */ const char *zCollName; /* Required collating sequence, if not NULL */ Expr *pIdxExpr; /* Search for this index expression */ - char idxaff; /* Must match this affinity, if zCollName!=NULL */ - unsigned char nEquiv; /* Number of entries in aEquiv[] */ - unsigned char iEquiv; /* Next unused slot in aEquiv[] */ - u32 opMask; /* Acceptable operators */ int k; /* Resume scanning at this->pWC->a[this->k] */ + u32 opMask; /* Acceptable operators */ + char idxaff; /* Must match this affinity, if zCollName!=NULL */ + unsigned char iEquiv; /* Current slot in aiCur[] and aiColumn[] */ + unsigned char nEquiv; /* Number of entries in aiCur[] and aiColumn[] */ int aiCur[11]; /* Cursors in the equivalence class */ i16 aiColumn[11]; /* Corresponding column number in the eq-class */ }; @@ -125623,8 +147161,10 @@ struct WhereClause { WhereInfo *pWInfo; /* WHERE clause processing context */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ + u8 hasOr; /* True if any a[].eOperator is WO_OR */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ + int nBase; /* Number of terms through the last non-Virtual */ WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ #if defined(SQLITE_SMALL_STACK) WhereTerm aStatic[1]; /* Initial static space for a[] */ @@ -125654,8 +147194,8 @@ struct WhereAndInfo { ** An instance of the following structure keeps track of a mapping ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. ** -** The VDBE cursor numbers are small integers contained in -** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE +** The VDBE cursor numbers are small integers contained in +** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE ** clause, the cursor numbers might not begin with 0 and they might ** contain gaps in the numbering sequence. But we want to make maximum ** use of the bits in our bitmasks. This structure provides a mapping @@ -125677,15 +147217,11 @@ struct WhereAndInfo { ** no gaps. */ struct WhereMaskSet { + int bVarSelect; /* Used by sqlite3WhereExprUsage() */ int n; /* Number of assigned cursor values */ int ix[BMS]; /* Cursor assigned to each bit */ }; -/* -** Initialize a WhereMaskSet object -*/ -#define initMaskSet(P) (P)->n=0 - /* ** This object is a convenience wrapper holding all information needed ** to construct WhereLoop objects for a particular query. @@ -125693,13 +147229,55 @@ struct WhereMaskSet { struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ WhereClause *pWC; /* WHERE clause terms */ - ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 UnpackedRecord *pRec; /* Probe for stat4 (if required) */ int nRecValid; /* Number of valid fields currently in pRec */ #endif + unsigned char bldFlags1; /* First set of SQLITE_BLDF_* flags */ + unsigned char bldFlags2; /* Second set of SQLITE_BLDF_* flags */ + unsigned int iPlanLimit; /* Search limiter */ +}; + +/* Allowed values for WhereLoopBuider.bldFlags */ +#define SQLITE_BLDF1_INDEXED 0x0001 /* An index is used */ +#define SQLITE_BLDF1_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ + +#define SQLITE_BLDF2_2NDPASS 0x0004 /* Second builder pass needed */ + +/* The WhereLoopBuilder.iPlanLimit is used to limit the number of +** index+constraint combinations the query planner will consider for a +** particular query. If this parameter is unlimited, then certain +** pathological queries can spend excess time in the sqlite3WhereBegin() +** routine. The limit is high enough that is should not impact real-world +** queries. +** +** SQLITE_QUERY_PLANNER_LIMIT is the baseline limit. The limit is +** increased by SQLITE_QUERY_PLANNER_LIMIT_INCR before each term of the FROM +** clause is processed, so that every table in a join is guaranteed to be +** able to propose a some index+constraint combinations even if the initial +** baseline limit was exhausted by prior tables of the join. +*/ +#ifndef SQLITE_QUERY_PLANNER_LIMIT +# define SQLITE_QUERY_PLANNER_LIMIT 20000 +#endif +#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR +# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 +#endif + +/* +** Each instance of this object records a change to a single node +** in an expression tree to cause that node to point to a column +** of an index rather than an expression or a virtual column. All +** such transformations need to be undone at the end of WHERE clause +** processing. +*/ +typedef struct WhereExprMod WhereExprMod; +struct WhereExprMod { + WhereExprMod *pNext; /* Next translation on a list of them all */ + Expr *pExpr; /* The Expr node that was transformed */ + Expr orig; /* Original value of the Expr node */ }; /* @@ -125716,24 +147294,31 @@ struct WhereInfo { Parse *pParse; /* Parsing and code generating context */ SrcList *pTabList; /* List of tables in the join */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */ - ExprList *pDistinctSet; /* DISTINCT over all these values */ - LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ + ExprList *pResultSet; /* Result set of the query */ + Expr *pWhere; /* The complete WHERE clause */ +#ifndef SQLITE_OMIT_VIRTUALTABLE + Select *pLimit; /* Used to access LIMIT expr/registers for vtabs */ +#endif int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ + LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ u8 nLevel; /* Number of nested loop */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ - u8 sorted; /* True if really sorted (not just grouped) */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ - u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ - u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */ + unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */ + unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */ + unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */ + unsigned sorted :1; /* True if really sorted (not just grouped) */ + LogEst nRowOut; /* Estimated number of output rows */ int iTop; /* The very beginning of the WHERE loop */ + int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ + WhereExprMod *pExprMods; /* Expression modifications */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ - LogEst nRowOut; /* Estimated number of output rows */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ @@ -125747,6 +147332,8 @@ struct WhereInfo { SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC); +SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm); +SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC); #endif SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ @@ -125763,12 +147350,16 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ - int iLevel, /* Value for "level" column of output */ - int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ); +SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( + const Parse *pParse, /* Parse context */ + const WhereInfo *pWInfo, /* WHERE clause */ + const WhereLevel *pLevel /* Bloom filter on this level */ +); #else -# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0 +# define sqlite3WhereExplainOneScan(u,v,w,x) 0 +# define sqlite3WhereExplainBloomFilter(u,v,w) 0 #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS SQLITE_PRIVATE void sqlite3WhereAddScanStatus( @@ -125781,8 +147372,11 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( # define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d) #endif SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( + Parse *pParse, /* Parsing context */ + Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ + WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ); @@ -125790,10 +147384,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( SQLITE_PRIVATE void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause*); SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8); +SQLITE_PRIVATE void sqlite3WhereAddLimit(WhereClause*, Select*); SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); -SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*); +SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*); @@ -125811,7 +147407,6 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC ** WO_LE == SQLITE_INDEX_CONSTRAINT_LE ** WO_GT == SQLITE_INDEX_CONSTRAINT_GT ** WO_GE == SQLITE_INDEX_CONSTRAINT_GE -** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH */ #define WO_IN 0x0001 #define WO_EQ 0x0002 @@ -125819,7 +147414,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) -#define WO_MATCH 0x0040 +#define WO_AUX 0x0040 /* Op useful to virtual tables only */ #define WO_IS 0x0080 #define WO_ISNULL 0x0100 #define WO_OR 0x0200 /* Two or more OR-connected terms */ @@ -125854,6 +147449,15 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */ #define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/ #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ +#define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ +#define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */ +#define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */ +#define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */ +#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */ +#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */ +#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */ + +#endif /* !defined(SQLITE_WHEREINT_H) */ /************** End of whereInt.h ********************************************/ /************** Continuing where we left off in wherecode.c ******************/ @@ -125867,7 +147471,7 @@ static const char *explainIndexColumnName(Index *pIdx, int i){ i = pIdx->aiColumn[i]; if( i==XN_EXPR ) return ""; if( i==XN_ROWID ) return "rowid"; - return pIdx->pTable->aCol[i].zName; + return pIdx->pTable->aCol[i].zCnName; } /* @@ -125889,27 +147493,27 @@ static void explainAppendTerm( int i; assert( nTerm>=1 ); - if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5); + if( bAnd ) sqlite3_str_append(pStr, " AND ", 5); - if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1); for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1); - sqlite3StrAccumAppend(pStr, zOp, 1); + sqlite3_str_append(pStr, zOp, 1); - if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1); for(i=0; i1 ) sqlite3StrAccumAppend(pStr, ")", 1); + if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1); } /* -** Argument pLevel describes a strategy for scanning table pTab. This +** Argument pLevel describes a strategy for scanning table pTab. This ** function appends text to pStr that describes the subset of table ** rows scanned by the strategy in the form of an SQL expression. ** @@ -125929,11 +147533,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ int i, j; if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; - sqlite3StrAccumAppend(pStr, " (", 2); + sqlite3_str_append(pStr, " (", 2); for(i=0; i=nSkip ? "%s=?" : "ANY(%s)", z); + if( i ) sqlite3_str_append(pStr, " AND ", 5); + sqlite3_str_appendf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z); } j = i; @@ -125944,13 +147548,13 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){ if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<"); } - sqlite3StrAccumAppend(pStr, ")", 1); + sqlite3_str_append(pStr, ")", 1); } /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN ** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was -** defined at compile-time. If it is not a no-op, a single OP_Explain opcode +** defined at compile-time. If it is not a no-op, a single OP_Explain opcode ** is added to the output to describe the table scan strategy in pLevel. ** ** If an OP_Explain opcode is added to the VM, its address is returned. @@ -125960,19 +147564,16 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ - int iLevel, /* Value for "level" column of output */ - int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) - if( pParse->explain==2 ) + if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { - struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; + SrcItem *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ - int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ @@ -125989,16 +147590,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); - sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); - if( pItem->pSelect ){ - sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId); - }else{ - sqlite3XPrintf(&str, " TABLE %s", pItem->zName); - } - - if( pItem->zAlias ){ - sqlite3XPrintf(&str, " AS %s", pItem->zAlias); - } + str.printfFlags = SQLITE_PRINTF_INTERNAL; + sqlite3_str_appendf(&str, "%s %S", isSearch ? "SEARCH" : "SCAN", pItem); if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ const char *zFmt = 0; Index *pIdx; @@ -126020,52 +147613,114 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan( zFmt = "INDEX %s"; } if( zFmt ){ - sqlite3StrAccumAppend(&str, " USING ", 7); - sqlite3XPrintf(&str, zFmt, pIdx->zName); + sqlite3_str_append(&str, " USING ", 7); + sqlite3_str_appendf(&str, zFmt, pIdx->zName); explainIndexRange(&str, pLoop); } }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ - const char *zRangeOp; + char cRangeOp; +#if 0 /* Better output, but breaks many tests */ + const Table *pTab = pItem->pTab; + const char *zRowid = pTab->iPKey>=0 ? pTab->aCol[pTab->iPKey].zCnName: + "rowid"; +#else + const char *zRowid = "rowid"; +#endif + sqlite3_str_appendf(&str, " USING INTEGER PRIMARY KEY (%s", zRowid); if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ - zRangeOp = "="; + cRangeOp = '='; }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ - zRangeOp = ">? AND rowid<"; + sqlite3_str_appendf(&str, ">? AND %s", zRowid); + cRangeOp = '<'; }else if( flags&WHERE_BTM_LIMIT ){ - zRangeOp = ">"; + cRangeOp = '>'; }else{ assert( flags&WHERE_TOP_LIMIT); - zRangeOp = "<"; + cRangeOp = '<'; } - sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); + sqlite3_str_appendf(&str, "%c?)", cRangeOp); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ - sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s", + sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ - sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); + sqlite3_str_appendf(&str, " (~%llu rows)", + sqlite3LogEstToInt(pLoop->nOut)); }else{ - sqlite3StrAccumAppend(&str, " (~1 row)", 9); + sqlite3_str_append(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); - ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); + sqlite3ExplainBreakpoint("",zMsg); + ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), + pParse->addrExplain, 0, zMsg,P4_DYNAMIC); } return ret; } + +/* +** Add a single OP_Explain opcode that describes a Bloom filter. +** +** Or if not processing EXPLAIN QUERY PLAN and not in a SQLITE_DEBUG and/or +** SQLITE_ENABLE_STMT_SCANSTATUS build, then OP_Explain opcodes are not +** required and this routine is a no-op. +** +** If an OP_Explain opcode is added to the VM, its address is returned. +** Otherwise, if no OP_Explain is coded, zero is returned. +*/ +SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter( + const Parse *pParse, /* Parse context */ + const WhereInfo *pWInfo, /* WHERE clause */ + const WhereLevel *pLevel /* Bloom filter on this level */ +){ + int ret = 0; + SrcItem *pItem = &pWInfo->pTabList->a[pLevel->iFrom]; + Vdbe *v = pParse->pVdbe; /* VM being constructed */ + sqlite3 *db = pParse->db; /* Database handle */ + char *zMsg; /* Text to add to EQP output */ + int i; /* Loop counter */ + WhereLoop *pLoop; /* The where loop */ + StrAccum str; /* EQP output string */ + char zBuf[100]; /* Initial space for EQP output string */ + + sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + str.printfFlags = SQLITE_PRINTF_INTERNAL; + sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem); + pLoop = pLevel->pWLoop; + if( pLoop->wsFlags & WHERE_IPK ){ + const Table *pTab = pItem->pTab; + if( pTab->iPKey>=0 ){ + sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName); + }else{ + sqlite3_str_appendf(&str, "rowid=?"); + } + }else{ + for(i=pLoop->nSkip; iu.btree.nEq; i++){ + const char *z = explainIndexColumnName(pLoop->u.btree.pIndex, i); + if( i>pLoop->nSkip ) sqlite3_str_append(&str, " AND ", 5); + sqlite3_str_appendf(&str, "%s=?", z); + } + } + sqlite3_str_append(&str, ")", 1); + zMsg = sqlite3StrAccumFinish(&str); + ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), + pParse->addrExplain, 0, zMsg,P4_DYNAMIC); + return ret; +} #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Configure the VM passed as the first argument with an -** sqlite3_stmt_scanstatus() entry corresponding to the scan used to -** implement level pLvl. Argument pSrclist is a pointer to the FROM +** sqlite3_stmt_scanstatus() entry corresponding to the scan used to +** implement level pLvl. Argument pSrclist is a pointer to the FROM ** clause that the scan reads data from. ** -** If argument addrExplain is not 0, it must be the address of an +** If argument addrExplain is not 0, it must be the address of an ** OP_Explain instruction that describes the same loop. */ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( @@ -126121,7 +147776,7 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( ** ** Only the parent term was in the original WHERE clause. The child1 ** and child2 terms were added by the LIKE optimization. If both of -** the virtual child terms are valid, then testing of the parent can be +** the virtual child terms are valid, then testing of the parent can be ** skipped. ** ** Usually the parent term is marked as TERM_CODED. But if the parent @@ -126132,8 +147787,8 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus( */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ int nLoop = 0; - while( ALWAYS(pTerm!=0) - && (pTerm->wtFlags & TERM_CODED)==0 + assert( pTerm!=0 ); + while( (pTerm->wtFlags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) && (pLevel->notReady & pTerm->prereqAll)==0 ){ @@ -126142,8 +147797,15 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ }else{ pTerm->wtFlags |= TERM_CODED; } +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x20000 ){ + sqlite3DebugPrintf("DISABLE-"); + sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a))); + } +#endif if( pTerm->iParent<0 ) break; pTerm = &pTerm->pWC->a[pTerm->iParent]; + assert( pTerm!=0 ); pTerm->nChild--; if( pTerm->nChild!=0 ) break; nLoop++; @@ -126152,11 +147814,11 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ /* ** Code an OP_Affinity opcode to apply the column affinity string zAff -** to the n registers starting at base. +** to the n registers starting at base. ** -** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the -** beginning and end of zAff are ignored. If all entries in zAff are -** SQLITE_AFF_BLOB, then no code gets generated. +** As an optimization, SQLITE_AFF_BLOB and SQLITE_AFF_NONE entries (which +** are no-ops) at the beginning and end of zAff are ignored. If all entries +** in zAff are SQLITE_AFF_BLOB or SQLITE_AFF_NONE, then no code gets generated. ** ** This routine makes its own copy of zAff so that the caller is free ** to modify zAff after this routine returns. @@ -126169,27 +147831,27 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ } assert( v!=0 ); - /* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning - ** and end of the affinity string. + /* Adjust base and n to skip over SQLITE_AFF_BLOB and SQLITE_AFF_NONE + ** entries at the beginning and end of the affinity string. */ - while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){ + assert( SQLITE_AFF_NONE0 && zAff[0]<=SQLITE_AFF_BLOB ){ n--; base++; zAff++; } - while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){ + while( n>1 && zAff[n-1]<=SQLITE_AFF_BLOB ){ n--; } /* Code the OP_Affinity opcode if there is anything left to do. */ if( n>0 ){ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); - sqlite3ExprCacheAffinityChange(pParse, base, n); } } /* -** Expression pRight, which is the RHS of a comparison operation, is +** Expression pRight, which is the RHS of a comparison operation, is ** either a vector of n elements or, if n==1, a scalar expression. ** Before the comparison operation, affinity zAff is to be applied ** to the pRight values. This function modifies characters within the @@ -126214,9 +147876,113 @@ static void updateRangeAffinityStr( } } + +/* +** pX is an expression of the form: (vector) IN (SELECT ...) +** In other words, it is a vector IN operator with a SELECT clause on the +** LHS. But not all terms in the vector are indexable and the terms might +** not be in the correct order for indexing. +** +** This routine makes a copy of the input pX expression and then adjusts +** the vector on the LHS with corresponding changes to the SELECT so that +** the vector contains only index terms and those terms are in the correct +** order. The modified IN expression is returned. The caller is responsible +** for deleting the returned expression. +** +** Example: +** +** CREATE TABLE t1(a,b,c,d,e,f); +** CREATE INDEX t1x1 ON t1(e,c); +** SELECT * FROM t1 WHERE (a,b,c,d,e) IN (SELECT v,w,x,y,z FROM t2) +** \_______________________________________/ +** The pX expression +** +** Since only columns e and c can be used with the index, in that order, +** the modified IN expression that is returned will be: +** +** (e,c) IN (SELECT z,x FROM t2) +** +** The reduced pX is different from the original (obviously) and thus is +** only used for indexing, to improve performance. The original unaltered +** IN expression must also be run on each output row for correctness. +*/ +static Expr *removeUnindexableInClauseTerms( + Parse *pParse, /* The parsing context */ + int iEq, /* Look at loop terms starting here */ + WhereLoop *pLoop, /* The current loop */ + Expr *pX /* The IN expression to be reduced */ +){ + sqlite3 *db = pParse->db; + Expr *pNew; + pNew = sqlite3ExprDup(db, pX, 0); + if( db->mallocFailed==0 ){ + ExprList *pOrigRhs; /* Original unmodified RHS */ + ExprList *pOrigLhs; /* Original unmodified LHS */ + ExprList *pRhs = 0; /* New RHS after modifications */ + ExprList *pLhs = 0; /* New LHS after mods */ + int i; /* Loop counter */ + Select *pSelect; /* Pointer to the SELECT on the RHS */ + + assert( ExprUseXSelect(pNew) ); + pOrigRhs = pNew->x.pSelect->pEList; + assert( pNew->pLeft!=0 ); + assert( ExprUseXList(pNew->pLeft) ); + pOrigLhs = pNew->pLeft->x.pList; + for(i=iEq; inLTerm; i++){ + if( pLoop->aLTerm[i]->pExpr==pX ){ + int iField; + assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 ); + iField = pLoop->aLTerm[i]->u.x.iField - 1; + if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ + pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); + pOrigRhs->a[iField].pExpr = 0; + assert( pOrigLhs->a[iField].pExpr!=0 ); + pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr); + pOrigLhs->a[iField].pExpr = 0; + } + } + sqlite3ExprListDelete(db, pOrigRhs); + sqlite3ExprListDelete(db, pOrigLhs); + pNew->pLeft->x.pList = pLhs; + pNew->x.pSelect->pEList = pRhs; + if( pLhs && pLhs->nExpr==1 ){ + /* Take care here not to generate a TK_VECTOR containing only a + ** single value. Since the parser never creates such a vector, some + ** of the subroutines do not handle this case. */ + Expr *p = pLhs->a[0].pExpr; + pLhs->a[0].pExpr = 0; + sqlite3ExprDelete(db, pNew->pLeft); + pNew->pLeft = p; + } + pSelect = pNew->x.pSelect; + if( pSelect->pOrderBy ){ + /* If the SELECT statement has an ORDER BY clause, zero the + ** iOrderByCol variables. These are set to non-zero when an + ** ORDER BY term exactly matches one of the terms of the + ** result-set. Since the result-set of the SELECT statement may + ** have been modified or reordered, these variables are no longer + ** set correctly. Since setting them is just an optimization, + ** it's easiest just to zero them here. */ + ExprList *pOrderBy = pSelect->pOrderBy; + for(i=0; inExpr; i++){ + pOrderBy->a[i].u.x.iOrderByCol = 0; + } + } + +#if 0 + printf("For indexing, change the IN expr:\n"); + sqlite3TreeViewExpr(0, pX, 0); + printf("Into:\n"); + sqlite3TreeViewExpr(0, pNew, 0); +#endif + } + return pNew; +} + + /* ** Generate code for a single equality term of the WHERE clause. An equality -** term can be either X=expr or X IN (...). pTerm is the term to be +** term can be either X=expr or X IN (...). pTerm is the term to be ** coded. ** ** The current value for the constraint is left in a register, the index @@ -126276,83 +148042,41 @@ static int codeEqualityTerm( } } for(i=iEq;inLTerm; i++){ - if( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++; + assert( pLoop->aLTerm[i]!=0 ); + if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } - if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){ - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0); + iTab = 0; + if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){ + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab); }else{ - Select *pSelect = pX->x.pSelect; sqlite3 *db = pParse->db; - u16 savedDbOptFlags = db->dbOptFlags; - ExprList *pOrigRhs = pSelect->pEList; - ExprList *pOrigLhs = pX->pLeft->x.pList; - ExprList *pRhs = 0; /* New Select.pEList for RHS */ - ExprList *pLhs = 0; /* New pX->pLeft vector */ + pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX); - for(i=iEq;inLTerm; i++){ - if( pLoop->aLTerm[i]->pExpr==pX ){ - int iField = pLoop->aLTerm[i]->iField - 1; - Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0); - Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0); - - pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs); - pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs); - } - } if( !db->mallocFailed ){ - Expr *pLeft = pX->pLeft; - - if( pSelect->pOrderBy ){ - /* If the SELECT statement has an ORDER BY clause, zero the - ** iOrderByCol variables. These are set to non-zero when an - ** ORDER BY term exactly matches one of the terms of the - ** result-set. Since the result-set of the SELECT statement may - ** have been modified or reordered, these variables are no longer - ** set correctly. Since setting them is just an optimization, - ** it's easiest just to zero them here. */ - ExprList *pOrderBy = pSelect->pOrderBy; - for(i=0; inExpr; i++){ - pOrderBy->a[i].u.x.iOrderByCol = 0; - } - } - - /* Take care here not to generate a TK_VECTOR containing only a - ** single value. Since the parser never creates such a vector, some - ** of the subroutines do not handle this case. */ - if( pLhs->nExpr==1 ){ - pX->pLeft = pLhs->a[0].pExpr; - }else{ - pLeft->x.pList = pLhs; - aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq); - testcase( aiMap==0 ); - } - pSelect->pEList = pRhs; - db->dbOptFlags |= SQLITE_QueryFlattener; - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap); - db->dbOptFlags = savedDbOptFlags; - testcase( aiMap!=0 && aiMap[0]!=0 ); - pSelect->pEList = pOrigRhs; - pLeft->x.pList = pOrigLhs; - pX->pLeft = pLeft; + aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq); + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab); + pTerm->pExpr->iTable = iTab; } - sqlite3ExprListDelete(pParse->db, pLhs); - sqlite3ExprListDelete(pParse->db, pRhs); + sqlite3ExprDelete(db, pX); + pX = pTerm->pExpr; } if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; } - iTab = pX->iTable; sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); VdbeCoverageIf(v, bRev); VdbeCoverageIf(v, !bRev); - assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); pLoop->wsFlags |= WHERE_IN_ABLE; if( pLevel->u.in.nIn==0 ){ - pLevel->addrNxt = sqlite3VdbeMakeLabel(v); + pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); + } + if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){ + pLoop->wsFlags |= WHERE_IN_EARLYOUT; } i = pLevel->u.in.nIn; @@ -126368,7 +148092,6 @@ static int codeEqualityTerm( if( pLoop->aLTerm[i]->pExpr==pX ){ int iOut = iReg + i - iEq; if( eType==IN_INDEX_ROWID ){ - testcase( nEq>1 ); /* Happens with a UNIQUE index on ROWID */ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut); }else{ int iCol = aiMap ? aiMap[iMap++] : 0; @@ -126377,20 +148100,49 @@ static int codeEqualityTerm( sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v); if( i==iEq ){ pIn->iCur = iTab; - pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; + pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; + if( iEq>0 ){ + pIn->iBase = iReg - i; + pIn->nPrefix = i; + }else{ + pIn->nPrefix = 0; + } }else{ pIn->eEndLoopOp = OP_Noop; } pIn++; } } + testcase( iEq>0 + && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 + && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ); + if( iEq>0 + && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0 + ){ + sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq); + } }else{ pLevel->u.in.nIn = 0; } sqlite3DbFree(pParse->db, aiMap); #endif } - disableTerm(pLevel, pTerm); + + /* As an optimization, try to disable the WHERE clause term that is + ** driving the index as it will always be true. The correct answer is + ** obtained regardless, but we might get the answer with fewer CPU cycles + ** by omitting the term. + ** + ** But do not disable the term unless we are certain that the term is + ** not a transitive constraint. For an example of where that does not + ** work, see https://sqlite.org/forum/forumpost/eb8613976a (2021-05-04) + */ + if( (pLevel->pWLoop->wsFlags & WHERE_TRANSCONS)==0 + || (pTerm->eOperator & WO_EQUIV)==0 + ){ + disableTerm(pLevel, pTerm); + } + return iReg; } @@ -126401,7 +148153,7 @@ static int codeEqualityTerm( ** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c). ** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10 ** The index has as many as three equality constraints, but in this -** example, the third "c" value is an inequality. So only two +** example, the third "c" value is an inequality. So only two ** constraints are coded. This routine will generate code to evaluate ** a==5 and b IN (1,2,3). The current values for a and b will be stored ** in consecutive registers and the index of the first register is returned. @@ -126476,11 +148228,13 @@ static int codeAllEqualityTerms( if( nSkip ){ int iIdxCur = pLevel->iIdxCur; + sqlite3VdbeAddOp3(v, OP_Null, 0, regBase, regBase+nSkip-1); sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); j = sqlite3VdbeAddOp0(v, OP_Goto); + assert( pLevel->addrSkip==0 ); pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), iIdxCur, 0, regBase, nSkip); VdbeCoverageIf(v, bRev==0); @@ -126491,7 +148245,7 @@ static int codeAllEqualityTerms( testcase( pIdx->aiColumn[j]==XN_EXPR ); VdbeComment((v, "%s", explainIndexColumnName(pIdx, j))); } - } + } /* Evaluate the equality constraints */ @@ -126500,7 +148254,7 @@ static int codeAllEqualityTerms( int r1; pTerm = pLoop->aLTerm[j]; assert( pTerm!=0 ); - /* The following testcase is true for indices with redundant columns. + /* The following testcase is true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); @@ -126510,14 +148264,17 @@ static int codeAllEqualityTerms( sqlite3ReleaseTempReg(pParse, regBase); regBase = r1; }else{ - sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); + sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j); } } + } + for(j=nSkip; jaLTerm[j]; if( pTerm->eOperator & WO_IN ){ if( pTerm->pExpr->flags & EP_xIsSelect ){ /* No affinity ever needs to be (or should be) applied to a value - ** from the RHS of an "? IN (SELECT ...)" expression. The - ** sqlite3FindInIndex() routine has already ensured that the + ** from the RHS of an "? IN (SELECT ...)" expression. The + ** sqlite3FindInIndex() routine has already ensured that the ** affinity of the comparison has been applied to the value. */ if( zAff ) zAff[j] = SQLITE_AFF_BLOB; } @@ -126527,7 +148284,8 @@ static int codeAllEqualityTerms( sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); } - if( zAff ){ + if( pParse->nErr==0 ){ + assert( pParse->db->mallocFailed==0 ); if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ zAff[j] = SQLITE_AFF_BLOB; } @@ -126544,7 +148302,7 @@ static int codeAllEqualityTerms( #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS /* ** If the most recently coded instruction is a constant range constraint -** (a string literal) that originated from the LIKE optimization, then +** (a string literal) that originated from the LIKE optimization, then ** set P3 and P5 on the OP_String opcode so that the string will be cast ** to a BLOB at appropriate times. ** @@ -126569,7 +148327,7 @@ static void whereLikeOptimizationStringFixup( assert( pLevel->iLikeRepCntr>0 ); pOp = sqlite3VdbeGetOp(v, -1); assert( pOp!=0 ); - assert( pOp->opcode==OP_String8 + assert( pOp->opcode==OP_String8 || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ @@ -126602,7 +148360,7 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ assert( pHint->pIdx!=0 ); if( pExpr->op==TK_COLUMN && pExpr->iTable==pHint->iTabCur - && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0 + && sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; } @@ -126612,7 +148370,7 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ /* ** Test whether or not expression pExpr, which was part of a WHERE clause, ** should be included in the cursor-hint for a table that is on the rhs -** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the +** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the ** expression is not suitable. ** ** An expression is unsuitable if it might evaluate to non NULL even if @@ -126625,14 +148383,14 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ ** CASE WHEN col THEN 0 ELSE 1 END */ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ - if( pExpr->op==TK_IS - || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT - || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE + if( pExpr->op==TK_IS + || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT + || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE ){ pWalker->eCode = 1; }else if( pExpr->op==TK_FUNCTION ){ int d1; - char d2[3]; + char d2[4]; if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ pWalker->eCode = 1; } @@ -126648,10 +148406,10 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ ** that accesses any table other than the one identified by ** CCurHint.iTabCur, then do the following: ** -** 1) allocate a register and code an OP_Column instruction to read +** 1) allocate a register and code an OP_Column instruction to read ** the specified column into the new register, and ** -** 2) transform the expression node to a TK_REGISTER node that reads +** 2) transform the expression node to a TK_REGISTER node that reads ** from the newly populated register. ** ** Also, if the node is a TK_COLUMN that does access the table idenified @@ -126664,16 +148422,13 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ struct CCurHint *pHint = pWalker->u.pCCurHint; if( pExpr->op==TK_COLUMN ){ if( pExpr->iTable!=pHint->iTabCur ){ - Vdbe *v = pWalker->pParse->pVdbe; int reg = ++pWalker->pParse->nMem; /* Register for column value */ - sqlite3ExprCodeGetColumnOfTable( - v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg - ); + sqlite3ExprCode(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ pExpr->iTable = pHint->iIdxCur; - pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); + pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn); assert( pExpr->iColumn>=0 ); } }else if( pExpr->op==TK_AGG_FUNCTION ){ @@ -126682,7 +148437,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ ** the parent context. Do not walk the function arguments in this case. ** ** todo: It should be possible to replace this node with a TK_REGISTER - ** expression, as the result of the expression must be stored in a + ** expression, as the result of the expression must be stored in a ** register at this point. The same holds for TK_AGG_COLUMN nodes. */ rc = WRC_Prune; } @@ -126693,7 +148448,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( - struct SrcList_item *pTabItem, /* FROM clause item */ + SrcItem *pTabItem, /* FROM clause item */ WhereInfo *pWInfo, /* The where clause */ WhereLevel *pLevel, /* Which loop to provide hints for */ WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ @@ -126720,23 +148475,23 @@ static void codeCursorHint( sWalker.pParse = pParse; sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; - for(i=0; inTerm; i++){ + for(i=0; inBase; i++){ pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue; - /* Any terms specified as part of the ON(...) clause for any LEFT + /* Any terms specified as part of the ON(...) clause for any LEFT ** JOIN for which the current table is not the rhs are omitted - ** from the cursor-hint. + ** from the cursor-hint. ** - ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms + ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms ** that were specified as part of the WHERE clause must be excluded. ** This is to address the following: ** ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; ** ** Say there is a single row in t2 that matches (t1.a=t2.b), but its - ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is + ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is ** pushed down to the cursor, this row is filtered out, causing ** SQLite to synthesize a row of NULL values. Which does match the ** WHERE clause, and so the query returns a row. Which is incorrect. @@ -126749,8 +148504,8 @@ static void codeCursorHint( */ if( pTabItem->fg.jointype & JT_LEFT ){ Expr *pExpr = pTerm->pExpr; - if( !ExprHasProperty(pExpr, EP_FromJoin) - || pExpr->iRightJoinTable!=pTabItem->iCursor + if( !ExprHasProperty(pExpr, EP_FromJoin) + || pExpr->w.iRightJoinTable!=pTabItem->iCursor ){ sWalker.eCode = 0; sWalker.xExprCallback = codeCursorHintIsOrFunction; @@ -126782,12 +148537,12 @@ static void codeCursorHint( } /* If we survive all prior tests, that means this term is worth hinting */ - pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); + pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sWalker.xExprCallback = codeCursorHintFixExpr; sqlite3WalkExpr(&sWalker, pExpr); - sqlite3VdbeAddOp4(v, OP_CursorHint, + sqlite3VdbeAddOp4(v, OP_CursorHint, (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); } @@ -126799,18 +148554,18 @@ static void codeCursorHint( /* ** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains ** a rowid value just read from cursor iIdxCur, open on index pIdx. This -** function generates code to do a deferred seek of cursor iCur to the +** function generates code to do a deferred seek of cursor iCur to the ** rowid stored in register iRowid. ** ** Normally, this is just: ** -** OP_Seek $iCur $iRowid +** OP_DeferredSeek $iCur $iRowid ** ** However, if the scan currently being coded is a branch of an OR-loop and -** the statement currently being coded is a SELECT, then P3 of the OP_Seek +** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek ** is set to iIdxCur and P4 is set to point to an array of integers -** containing one entry for each column of the table cursor iCur is open -** on. For each table column, if the column is the i'th column of the +** containing one entry for each column of the table cursor iCur is open +** on. For each table column, if the column is the i'th column of the ** index, then the corresponding array entry is set to (i+1). If the column ** does not appear in the index at all, the array entry is set to 0. */ @@ -126825,19 +148580,24 @@ static void codeDeferredSeek( assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); - - sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur); + + pWInfo->bDeferredSeek = 1; + sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur); if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ int i; Table *pTab = pIdx->pTable; - int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1)); + u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1)); if( ai ){ ai[0] = pTab->nCol; for(i=0; inColumn-1; i++){ + int x1, x2; assert( pIdx->aiColumn[i]nCol ); - if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1; + x1 = pIdx->aiColumn[i]; + x2 = sqlite3TableColumnToStorage(pTab, x1); + testcase( x1!=x2 ); + if( x1>=0 ) ai[x2+1] = i+1; } sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); } @@ -126855,68 +148615,308 @@ static void codeDeferredSeek( */ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){ assert( nReg>0 ); - if( sqlite3ExprIsVector(p) ){ + if( p && sqlite3ExprIsVector(p) ){ #ifndef SQLITE_OMIT_SUBQUERY - if( (p->flags & EP_xIsSelect) ){ + if( ExprUseXSelect(p) ){ Vdbe *v = pParse->pVdbe; - int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0); + int iSelect; + assert( p->op==TK_SELECT ); + iSelect = sqlite3CodeSubselect(pParse, p); sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1); }else #endif { int i; - ExprList *pList = p->x.pList; + const ExprList *pList; + assert( ExprUseXList(p) ); + pList = p->x.pList; assert( nReg<=pList->nExpr ); for(i=0; ia[i].pExpr, iReg+i); } } }else{ - assert( nReg==1 ); + assert( nReg==1 || pParse->nErr ); sqlite3ExprCode(pParse, p, iReg); } } +/* An instance of the IdxExprTrans object carries information about a +** mapping from an expression on table columns into a column in an index +** down through the Walker. +*/ +typedef struct IdxExprTrans { + Expr *pIdxExpr; /* The index expression */ + int iTabCur; /* The cursor of the corresponding table */ + int iIdxCur; /* The cursor for the index */ + int iIdxCol; /* The column for the index */ + int iTabCol; /* The column for the table */ + WhereInfo *pWInfo; /* Complete WHERE clause information */ + sqlite3 *db; /* Database connection (for malloc()) */ +} IdxExprTrans; + +/* +** Preserve pExpr on the WhereETrans list of the WhereInfo. +*/ +static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){ + WhereExprMod *pNew; + pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew)); + if( pNew==0 ) return; + pNew->pNext = pTrans->pWInfo->pExprMods; + pTrans->pWInfo->pExprMods = pNew; + pNew->pExpr = pExpr; + memcpy(&pNew->orig, pExpr, sizeof(*pExpr)); +} + +/* The walker node callback used to transform matching expressions into +** a reference to an index column for an index on an expression. +** +** If pExpr matches, then transform it into a reference to the index column +** that contains the value of pExpr. +*/ +static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ + IdxExprTrans *pX = p->u.pIdxTrans; + if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ + preserveExpr(pX, pExpr); + pExpr->affExpr = sqlite3ExprAffinity(pExpr); + pExpr->op = TK_COLUMN; + pExpr->iTable = pX->iIdxCur; + pExpr->iColumn = pX->iIdxCol; + testcase( ExprHasProperty(pExpr, EP_Skip) ); + testcase( ExprHasProperty(pExpr, EP_Unlikely) ); + ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn); + pExpr->y.pTab = 0; + return WRC_Prune; + }else{ + return WRC_Continue; + } +} + +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* A walker node callback that translates a column reference to a table +** into a corresponding column reference of an index. +*/ +static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){ + if( pExpr->op==TK_COLUMN ){ + IdxExprTrans *pX = p->u.pIdxTrans; + if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){ + assert( ExprUseYTab(pExpr) && pExpr->y.pTab!=0 ); + preserveExpr(pX, pExpr); + pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn); + pExpr->iTable = pX->iIdxCur; + pExpr->iColumn = pX->iIdxCol; + pExpr->y.pTab = 0; + } + } + return WRC_Continue; +} +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + +/* +** For an indexes on expression X, locate every instance of expression X +** in pExpr and change that subexpression into a reference to the appropriate +** column of the index. +** +** 2019-10-24: Updated to also translate references to a VIRTUAL column in +** the table into references to the corresponding (stored) column of the +** index. +*/ +static void whereIndexExprTrans( + Index *pIdx, /* The Index */ + int iTabCur, /* Cursor of the table that is being indexed */ + int iIdxCur, /* Cursor of the index itself */ + WhereInfo *pWInfo /* Transform expressions in this WHERE clause */ +){ + int iIdxCol; /* Column number of the index */ + ExprList *aColExpr; /* Expressions that are indexed */ + Table *pTab; + Walker w; + IdxExprTrans x; + aColExpr = pIdx->aColExpr; + if( aColExpr==0 && !pIdx->bHasVCol ){ + /* The index does not reference any expressions or virtual columns + ** so no translations are needed. */ + return; + } + pTab = pIdx->pTable; + memset(&w, 0, sizeof(w)); + w.u.pIdxTrans = &x; + x.iTabCur = iTabCur; + x.iIdxCur = iIdxCur; + x.pWInfo = pWInfo; + x.db = pWInfo->pParse->db; + for(iIdxCol=0; iIdxColnColumn; iIdxCol++){ + i16 iRef = pIdx->aiColumn[iIdxCol]; + if( iRef==XN_EXPR ){ + assert( aColExpr!=0 && aColExpr->a[iIdxCol].pExpr!=0 ); + x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; + if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue; + w.xExprCallback = whereIndexExprTransNode; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + }else if( iRef>=0 + && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0 + && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0 + || sqlite3StrICmp(sqlite3ColumnColl(&pTab->aCol[iRef]), + sqlite3StrBINARY)==0) + ){ + /* Check to see if there are direct references to generated columns + ** that are contained in the index. Pulling the generated column + ** out of the index is an optimization only - the main table is always + ** available if the index cannot be used. To avoid unnecessary + ** complication, omit this optimization if the collating sequence for + ** the column is non-standard */ + x.iTabCol = iRef; + w.xExprCallback = whereIndexExprTransColumn; +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + }else{ + continue; + } + x.iIdxCol = iIdxCol; + sqlite3WalkExpr(&w, pWInfo->pWhere); + sqlite3WalkExprList(&w, pWInfo->pOrderBy); + sqlite3WalkExprList(&w, pWInfo->pResultSet); + } +} + +/* +** The pTruth expression is always true because it is the WHERE clause +** a partial index that is driving a query loop. Look through all of the +** WHERE clause terms on the query, and if any of those terms must be +** true because pTruth is true, then mark those WHERE clause terms as +** coded. +*/ +static void whereApplyPartialIndexConstraints( + Expr *pTruth, + int iTabCur, + WhereClause *pWC +){ + int i; + WhereTerm *pTerm; + while( pTruth->op==TK_AND ){ + whereApplyPartialIndexConstraints(pTruth->pLeft, iTabCur, pWC); + pTruth = pTruth->pRight; + } + for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ + Expr *pExpr; + if( pTerm->wtFlags & TERM_CODED ) continue; + pExpr = pTerm->pExpr; + if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){ + pTerm->wtFlags |= TERM_CODED; + } + } +} + +/* +** This routine is called right after An OP_Filter has been generated and +** before the corresponding index search has been performed. This routine +** checks to see if there are additional Bloom filters in inner loops that +** can be checked prior to doing the index lookup. If there are available +** inner-loop Bloom filters, then evaluate those filters now, before the +** index lookup. The idea is that a Bloom filter check is way faster than +** an index lookup, and the Bloom filter might return false, meaning that +** the index lookup can be skipped. +** +** We know that an inner loop uses a Bloom filter because it has the +** WhereLevel.regFilter set. If an inner-loop Bloom filter is checked, +** then clear the WhereLevel.regFilter value to prevent the Bloom filter +** from being checked a second time when the inner loop is evaluated. +*/ +static SQLITE_NOINLINE void filterPullDown( + Parse *pParse, /* Parsing context */ + WhereInfo *pWInfo, /* Complete information about the WHERE clause */ + int iLevel, /* Which level of pWInfo->a[] should be coded */ + int addrNxt, /* Jump here to bypass inner loops */ + Bitmask notReady /* Loops that are not ready */ +){ + while( ++iLevel < pWInfo->nLevel ){ + WhereLevel *pLevel = &pWInfo->a[iLevel]; + WhereLoop *pLoop = pLevel->pWLoop; + if( pLevel->regFilter==0 ) continue; + if( pLevel->pWLoop->nSkip ) continue; + /* ,--- Because sqlite3ConstructBloomFilter() has will not have set + ** vvvvv--' pLevel->regFilter if this were true. */ + if( NEVER(pLoop->prereq & notReady) ) continue; + if( pLoop->wsFlags & WHERE_IPK ){ + WhereTerm *pTerm = pLoop->aLTerm[0]; + int regRowid; + assert( pTerm!=0 ); + assert( pTerm->pExpr!=0 ); + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + regRowid = sqlite3GetTempReg(pParse); + regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid); + sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, + addrNxt, regRowid, 1); + VdbeCoverage(pParse->pVdbe); + }else{ + u16 nEq = pLoop->u.btree.nEq; + int r1; + char *zStartAff; + + assert( pLoop->wsFlags & WHERE_INDEXED ); + assert( (pLoop->wsFlags & WHERE_COLUMN_IN)==0 ); + r1 = codeAllEqualityTerms(pParse,pLevel,0,0,&zStartAff); + codeApplyAffinity(pParse, r1, nEq, zStartAff); + sqlite3DbFree(pParse->db, zStartAff); + sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter, + addrNxt, r1, nEq); + VdbeCoverage(pParse->pVdbe); + } + pLevel->regFilter = 0; + } +} + /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( + Parse *pParse, /* Parsing context */ + Vdbe *v, /* Prepared statement under construction */ WhereInfo *pWInfo, /* Complete information about the WHERE clause */ int iLevel, /* Which level of pWInfo->a[] should be coded */ + WhereLevel *pLevel, /* The current level pointer */ Bitmask notReady /* Which tables are currently available */ ){ int j, k; /* Loop counters */ int iCur; /* The VDBE cursor for the table */ int addrNxt; /* Where to jump to continue with the next IN case */ - int omitTable; /* True if we use the index only */ int bRev; /* True if we need to scan in reverse order */ - WhereLevel *pLevel; /* The where level to be coded */ WhereLoop *pLoop; /* The WhereLoop object being coded */ WhereClause *pWC; /* Decomposition of the entire WHERE clause */ WhereTerm *pTerm; /* A WHERE clause term */ - Parse *pParse; /* Parsing context */ sqlite3 *db; /* Database connection */ - Vdbe *v; /* The prepared stmt under constructions */ - struct SrcList_item *pTabItem; /* FROM clause term being coded */ + SrcItem *pTabItem; /* FROM clause term being coded */ int addrBrk; /* Jump here to break out of the loop */ + int addrHalt; /* addrBrk for the outermost loop */ int addrCont; /* Jump here to continue with next cycle */ int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ int iReleaseReg = 0; /* Temp register to free before returning */ + Index *pIdx = 0; /* Index used by loop (if any) */ + int iLoop; /* Iteration of constraint generator loop */ - pParse = pWInfo->pParse; - v = pParse->pVdbe; pWC = &pWInfo->sWC; db = pParse->db; - pLevel = &pWInfo->a[iLevel]; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; - omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 - && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); +#if WHERETRACE_ENABLED /* 0x20800 */ + if( sqlite3WhereTrace & 0x800 ){ + sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", + iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom); + sqlite3WhereLoopPrint(pLoop, pWC); + } + if( sqlite3WhereTrace & 0x20000 ){ + if( iLevel==0 ){ + sqlite3DebugPrintf("WHERE clause being coded:\n"); + sqlite3TreeViewExpr(0, pWInfo->pWhere, 0); + } + sqlite3DebugPrintf("All WHERE-clause terms before coding:\n"); + sqlite3WhereClausePrint(pWC); + } +#endif /* Create labels for the "break" and "continue" instructions ** for the current loop. Jump to addrBrk to break out of a loop. @@ -126928,26 +148928,34 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** there are no IN operators in the constraints, the "addrNxt" label ** is the same as "addrBrk". */ - addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v); - addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v); + addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); + addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(pParse); /* If this is the right table of a LEFT OUTER JOIN, allocate and ** initialize a memory cell that records if this table matches any ** row of the left table of the join. */ + assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) + || pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0 + ); if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); VdbeComment((v, "init LEFT JOIN no-match flag")); } + /* Compute a safe address to jump to if we discover that the table for + ** this loop is empty and can never contribute content. */ + for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){} + addrHalt = pWInfo->a[j].addrBrk; + /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); pLevel->op = OP_Goto; }else @@ -126959,9 +148967,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; int nConstraint = pLoop->nLTerm; - int iIn; /* Counter for IN constraints */ - sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; jaLTerm[j]; if( NEVER(pTerm==0) ) continue; if( pTerm->eOperator & WO_IN ){ - codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); - addrNotFound = pLevel->addrNxt; + if( SMASKBIT32(j) & pLoop->u.vtab.mHandleIn ){ + int iTab = pParse->nTab++; + int iCache = ++pParse->nMem; + sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab); + sqlite3VdbeAddOp3(v, OP_VInitIn, iTab, iTarget, iCache); + }else{ + codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); + addrNotFound = pLevel->addrNxt; + } }else{ Expr *pRight = pTerm->pExpr->pRight; codeExprOrVector(pParse, pRight, iTarget, 1); + if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET + && pLoop->u.vtab.bOmitOffset + ){ + assert( pTerm->eOperator==WO_AUX ); + assert( pWInfo->pLimit!=0 ); + assert( pWInfo->pLimit->iOffset>0 ); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pLimit->iOffset); + VdbeComment((v,"Zero OFFSET counter")); + } } } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); @@ -126983,50 +149005,74 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); VdbeCoverage(v); pLoop->u.vtab.needFree = 0; + /* An OOM inside of AddOp4(OP_VFilter) instruction above might have freed + ** the u.vtab.idxStr. NULL it out to prevent a use-after-free */ + if( db->mallocFailed ) pLoop->u.vtab.idxStr = 0; pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); - iIn = pLevel->u.in.nIn; - for(j=nConstraint-1; j>=0; j--){ + assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + + for(j=0; jaLTerm[j]; if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ disableTerm(pLevel, pTerm); - }else if( (pTerm->eOperator & WO_IN)!=0 ){ + continue; + } + if( (pTerm->eOperator & WO_IN)!=0 + && (SMASKBIT32(j) & pLoop->u.vtab.mHandleIn)==0 + && !db->mallocFailed + ){ Expr *pCompare; /* The comparison operator */ Expr *pRight; /* RHS of the comparison */ VdbeOp *pOp; /* Opcode to access the value of the IN constraint */ + int iIn; /* IN loop corresponding to the j-th constraint */ /* Reload the constraint value into reg[iReg+j+2]. The same value ** was loaded into the same register prior to the OP_VFilter, but ** the xFilter implementation might have changed the datatype or - ** encoding of the value in the register, so it *must* be reloaded. */ - assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed ); - if( !db->mallocFailed ){ - assert( iIn>0 ); - pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop); - assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid ); - assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 ); - assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 ); - testcase( pOp->opcode==OP_Rowid ); - sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3); + ** encoding of the value in the register, so it *must* be reloaded. + */ + for(iIn=0; ALWAYS(iInu.in.nIn); iIn++){ + pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop); + if( (pOp->opcode==OP_Column && pOp->p3==iReg+j+2) + || (pOp->opcode==OP_Rowid && pOp->p2==iReg+j+2) + ){ + testcase( pOp->opcode==OP_Rowid ); + sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3); + break; + } } - /* Generate code that will continue to the next row if - ** the IN constraint is not satisfied */ + /* Generate code that will continue to the next row if + ** the IN constraint is not satisfied + */ pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0); - assert( pCompare!=0 || db->mallocFailed ); - if( pCompare ){ - pCompare->pLeft = pTerm->pExpr->pLeft; + if( !db->mallocFailed ){ + int iFld = pTerm->u.x.iField; + Expr *pLeft = pTerm->pExpr->pLeft; + assert( pLeft!=0 ); + if( iFld>0 ){ + assert( pLeft->op==TK_VECTOR ); + assert( ExprUseXList(pLeft) ); + assert( iFld<=pLeft->x.pList->nExpr ); + pCompare->pLeft = pLeft->x.pList->a[iFld-1].pExpr; + }else{ + pCompare->pLeft = pLeft; + } pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0); if( pRight ){ pRight->iTable = iReg+j+2; - sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0); + sqlite3ExprIfFalse( + pParse, pCompare, pLevel->addrCont, SQLITE_JUMPIFNULL + ); } pCompare->pLeft = 0; - sqlite3ExprDelete(db, pCompare); } + sqlite3ExprDelete(db, pCompare); } } + /* These registers need to be preserved in case there is an IN operator ** loop. So we could deallocate the registers here (and potentially ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems @@ -127034,7 +149080,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); */ - sqlite3ExprCachePop(pParse); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -127050,17 +149095,19 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); - assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; + if( pLevel->regFilter ){ + sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt, + iRowidReg, 1); + VdbeCoverage(v); + filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady); + } sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); - sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); - VdbeComment((v, "pk")); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 @@ -127072,7 +149119,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int memEndValue = 0; WhereTerm *pStart, *pEnd; - assert( omitTable==0 ); j = 0; pStart = pEnd = 0; if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; @@ -127089,7 +149135,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int r1, rTemp; /* Registers for holding the start boundary */ int op; /* Cursor seek operation */ - /* The following constant maps TK_xx codes into corresponding + /* The following constant maps TK_xx codes into corresponding ** seek opcodes. It depends on a particular ordering of TK_xx */ const u8 aMoveOp[] = { @@ -127110,7 +149156,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( sqlite3ExprIsVector(pX->pRight) ){ r1 = rTemp = sqlite3GetTempReg(pParse); codeExprOrVector(pParse, pX->pRight, r1, 1); - op = aMoveOp[(pX->op - TK_GT) | 0x0001]; + testcase( pX->op==TK_GT ); + testcase( pX->op==TK_GE ); + testcase( pX->op==TK_LT ); + testcase( pX->op==TK_LE ); + op = aMoveOp[((pX->op - TK_GT - 1) & 0x3) | 0x1]; + assert( pX->op!=TK_GT || op==OP_SeekGE ); + assert( pX->op!=TK_GE || op==OP_SeekGE ); + assert( pX->op!=TK_LT || op==OP_SeekLE ); + assert( pX->op!=TK_LE || op==OP_SeekLE ); }else{ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); disableTerm(pLevel, pStart); @@ -127122,10 +149176,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeCoverageIf(v, pX->op==TK_LE); VdbeCoverageIf(v, pX->op==TK_LT); VdbeCoverageIf(v, pX->op==TK_GE); - sqlite3ExprCacheAffinityChange(pParse, r1, 1); sqlite3ReleaseTempReg(pParse, rTemp); }else{ - sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk); + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); } @@ -127138,8 +149191,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( testcase( pEnd->wtFlags & TERM_VIRTUAL ); memEndValue = ++pParse->nMem; codeExprOrVector(pParse, pX->pRight, memEndValue, 1); - if( 0==sqlite3ExprIsVector(pX->pRight) - && (pX->op==TK_LT || pX->op==TK_GT) + if( 0==sqlite3ExprIsVector(pX->pRight) + && (pX->op==TK_LT || pX->op==TK_GT) ){ testOp = bRev ? OP_Le : OP_Ge; }else{ @@ -127157,7 +149210,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( testOp!=OP_Noop ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); VdbeCoverageIf(v, testOp==OP_Le); VdbeCoverageIf(v, testOp==OP_Lt); @@ -127168,14 +149220,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( }else if( pLoop->wsFlags & WHERE_INDEXED ){ /* Case 4: A scan using an index. ** - ** The WHERE clause may contain zero or more equality + ** The WHERE clause may contain zero or more equality ** terms ("==" or "IN" operators) that refer to the N ** left-most columns of the index. It may also contain ** inequality constraints (>, <, >= or <=) on the indexed - ** column that immediately follows the N equalities. Only + ** column that immediately follows the N equalities. Only ** the right-most column can be an inequality - the rest must - ** use the "==" and "IN" operators. For example, if the - ** index is on (x,y,z), then the following clauses are all + ** use the "==" and "IN" operators. For example, if the + ** index is on (x,y,z), then the following clauses are all ** optimized: ** ** x=5 @@ -127196,7 +149248,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** This case is also used when there are no WHERE clause ** constraints but an index is selected anyway, in order ** to force the output order to conform to an ORDER BY. - */ + */ static const u8 aStartOp[] = { 0, 0, @@ -127223,7 +149275,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int endEq; /* True if range end uses ==, >= or <= */ int start_constraints; /* Start of range is constrained */ int nConstraint; /* Number of constraint terms */ - Index *pIdx; /* The index we will be using */ int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ @@ -127231,40 +149282,23 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( char *zEndAff = 0; /* Affinity for end of range constraint */ u8 bSeekPastNull = 0; /* True to seek past initial nulls */ u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ + int omitTable; /* True if we use the index only */ + int regBignull = 0; /* big-null flag register */ + int addrSeekScan = 0; /* Opcode of the OP_SeekScan, if any */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; assert( nEq>=pLoop->nSkip ); - /* If this loop satisfies a sort order (pOrderBy) request that - ** was passed to this function to implement a "SELECT min(x) ..." - ** query, then the caller will only allow the loop to run for - ** a single iteration. This means that the first row returned - ** should not have a NULL value stored in 'x'. If column 'x' is - ** the first one after the nEq equality constraints in the index, - ** this requires some special handling. - */ - assert( pWInfo->pOrderBy==0 - || pWInfo->pOrderBy->nExpr==1 - || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 ); - if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 - && pWInfo->nOBSat>0 - && (pIdx->nKeyCol>nEq) - ){ - assert( pLoop->nSkip==0 ); - bSeekPastNull = 1; - nExtraReg = 1; - } - - /* Find any inequality constraint terms for the start and end - ** of the range. + /* Find any inequality constraint terms for the start and end + ** of the range. */ j = nEq; if( pLoop->wsFlags & WHERE_BTM_LIMIT ){ pRangeStart = pLoop->aLTerm[j++]; nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm); /* Like optimization range constraints always occur in pairs */ - assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || + assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 || (pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 ); } if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ @@ -127296,18 +149330,44 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); + /* If the WHERE_BIGNULL_SORT flag is set, then index column nEq uses + ** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS + ** FIRST). In both cases separate ordered scans are made of those + ** index entries for which the column is null and for those for which + ** it is not. For an ASC sort, the non-NULL entries are scanned first. + ** For DESC, NULL entries are scanned first. + */ + if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0 + && (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0 + ){ + assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 ); + assert( pRangeEnd==0 && pRangeStart==0 ); + testcase( pLoop->nSkip>0 ); + nExtraReg = 1; + bSeekPastNull = 1; + pLevel->regBignull = regBignull = ++pParse->nMem; + if( pLevel->iLeftJoin ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, regBignull); + } + pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse); + } + /* If we are doing a reverse order scan on an ascending index, or - ** a forward order scan on a descending index, interchange the + ** a forward order scan on a descending index, interchange the ** start and end terms (pRangeStart and pRangeEnd). */ - if( (nEqnKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) - || (bRev && pIdx->nKeyCol==nEq) - ){ + if( (nEqnColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); SWAP(u8, nBtm, nTop); } + if( iLevel>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 ){ + /* In case OP_SeekScan is used, ensure that the index cursor does not + ** point to a valid row for the first iteration of this loop. */ + sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur); + } + /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. @@ -127318,7 +149378,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( zStartAff && nTop ){ zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]); } - addrNxt = pLevel->addrNxt; + addrNxt = (regBignull ? pLevel->addrBignull : pLevel->addrNxt); testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); @@ -127342,7 +149402,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } if( zStartAff ){ updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]); - } + } nConstraint += nBtm; testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); if( sqlite3ExprIsVector(pRight)==0 ){ @@ -127352,10 +149412,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } bSeekPastNull = 0; }else if( bSeekPastNull ){ + startEq = 0; sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); + start_constraints = 1; nConstraint++; - startEq = 0; + }else if( regBignull ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); start_constraints = 1; + nConstraint++; } codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){ @@ -127363,8 +149427,33 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ + if( regBignull ){ + sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull); + VdbeComment((v, "NULL-scan pass ctr")); + } + if( pLevel->regFilter ){ + sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt, + regBase, nEq); + VdbeCoverage(v); + filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady); + } + op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); + if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 && op==OP_SeekGE ){ + assert( regBignull==0 ); + /* TUNING: The OP_SeekScan opcode seeks to reduce the number + ** of expensive seek operations by replacing a single seek with + ** 1 or more step operations. The question is, how many steps + ** should we try before giving up and going with a seek. The cost + ** of a seek is proportional to the logarithm of the of the number + ** of entries in the tree, so basing the number of steps to try + ** on the estimated number of rows in the btree seems like a good + ** guess. */ + addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan, + (pIdx->aiRowLogEst[0]+9)/10); + VdbeCoverage(v); + } sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); VdbeCoverage(v); VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); @@ -127373,15 +149462,42 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); + + assert( bSeekPastNull==0 || bStopAtNull==0 ); + if( regBignull ){ + assert( bSeekPastNull==1 || bStopAtNull==1 ); + assert( bSeekPastNull==!bStopAtNull ); + assert( bStopAtNull==startEq ); + sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2); + op = aStartOp[(nConstraint>1)*4 + 2 + bRev]; + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, + nConstraint-startEq); + VdbeCoverage(v); + VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); + VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); + VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); + VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); + assert( op==OP_Rewind || op==OP_Last || op==OP_SeekGE || op==OP_SeekLE); + } } /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; + assert( pLevel->p2==0 ); if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; - sqlite3ExprCacheRemove(pParse, regBase+nEq, 1); + if( addrSeekScan ){ + /* For a seek-scan that has a range on the lowest term of the index, + ** we have to make the top of the loop be code that sets the end + ** condition of the range. Otherwise, the OP_SeekScan might jump + ** over that initialization, leaving the range-end value set to the + ** range-start value, resulting in a wrong answer. + ** See ticket 5981a8c041a3c2f3 (2021-11-02). + */ + pLevel->p2 = sqlite3VdbeCurrentAddr(v); + } codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 @@ -127405,53 +149521,114 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( endEq = 1; } }else if( bStopAtNull ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); - endEq = 0; + if( regBignull==0 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); + endEq = 0; + } nConstraint++; } sqlite3DbFree(db, zStartAff); sqlite3DbFree(db, zEndAff); /* Top of the loop body */ - pLevel->p2 = sqlite3VdbeCurrentAddr(v); + if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ + if( regBignull ){ + /* Except, skip the end-of-range check while doing the NULL-scan */ + sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3); + VdbeComment((v, "If NULL-scan 2nd pass")); + VdbeCoverage(v); + } op = aEndOp[bRev*2 + endEq]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); + if( addrSeekScan ) sqlite3VdbeJumpHere(v, addrSeekScan); + } + if( regBignull ){ + /* During a NULL-scan, check to see if we have reached the end of + ** the NULLs */ + assert( bSeekPastNull==!bStopAtNull ); + assert( bSeekPastNull+bStopAtNull==1 ); + assert( nConstraint+bSeekPastNull>0 ); + sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2); + VdbeComment((v, "If NULL-scan 1st pass")); + VdbeCoverage(v); + op = aEndOp[bRev*2 + bSeekPastNull]; + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, + nConstraint+bSeekPastNull); + testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); + testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); + testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); + testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); + } + + if( (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0 ){ + sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq); } /* Seek the table cursor, if required */ + omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ - if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || ( - (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) - && (pWInfo->eOnePass==ONEPASS_SINGLE) - )){ - iRowidReg = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); - VdbeCoverage(v); - }else{ - codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); - } + codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ - k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); } sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, iRowidReg, pPk->nKeyCol); VdbeCoverage(v); } + if( pLevel->iLeftJoin==0 ){ + /* If pIdx is an index on one or more expressions, then look through + ** all the expressions in pWInfo and try to transform matching expressions + ** into reference to index columns. Also attempt to translate references + ** to virtual columns in the table into references to (stored) columns + ** of the index. + ** + ** Do not do this for the RHS of a LEFT JOIN. This is because the + ** expression may be evaluated after OP_NullRow has been executed on + ** the cursor. In this case it is important to do the full evaluation, + ** as the result of the expression may not be NULL, even if all table + ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a + ** + ** Also, do not do this when processing one index an a multi-index + ** OR clause, since the transformation will become invalid once we + ** move forward to the next index. + ** https://sqlite.org/src/info/4e8e4857d32d401f + */ + if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ + whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); + } + + /* If a partial index is driving the loop, try to eliminate WHERE clause + ** terms from the query that must be true due to the WHERE clause of + ** the partial index. + ** + ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work + ** for a LEFT JOIN. + */ + if( pIdx->pPartIdxWhere ){ + whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC); + } + }else{ + testcase( pIdx->pPartIdxWhere ); + /* The following assert() is not a requirement, merely an observation: + ** The OR-optimization doesn't work for the right hand table of + ** a LEFT JOIN: */ + assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ); + } + /* Record the instruction used to terminate the loop. */ if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; @@ -127467,6 +149644,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( }else{ assert( pLevel->p5==0 ); } + if( omitTable ) pIdx = 0; }else #ifndef SQLITE_OMIT_OR_OPTIMIZATION @@ -127522,11 +149700,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ int regRowset = 0; /* Register for RowSet object */ int regRowid = 0; /* Register holding rowid */ - int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ + int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */ int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ - u16 wctrlFlags; /* Flags for sub-WHERE clause */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ Table *pTab = pTabItem->pTab; @@ -127544,7 +149721,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( */ if( pWInfo->nLevel>1 ){ int nNotReady; /* The number of notReady tables */ - struct SrcList_item *origSrc; /* Original list of tables */ + SrcItem *origSrc; /* Original list of tables */ nNotReady = pWInfo->nLevel - iLevel - 1; pOrTab = sqlite3StackAllocRaw(db, sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); @@ -127560,15 +149737,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pOrTab = pWInfo->pTabList; } - /* Initialize the rowset register to contain NULL. An SQL NULL is + /* Initialize the rowset register to contain NULL. An SQL NULL is ** equivalent to an empty rowset. Or, create an ephemeral index ** capable of holding primary keys in the case of a WITHOUT ROWID. ** - ** Also initialize regReturn to contain the address of the instruction + ** Also initialize regReturn to contain the address of the instruction ** immediately following the OP_Return at the bottom of the loop. This ** is required in a few obscure LEFT JOIN cases where control jumps - ** over the top of the loop into the body of it. In this case the - ** correct response for the end-of-loop code (the OP_Return) is to + ** over the top of the loop into the body of it. In this case the + ** correct response for the end-of-loop code (the OP_Return) is to ** fall through to the next instruction, just as an OP_Next does if ** called on an uninitialized cursor. */ @@ -127587,35 +149764,56 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y - ** Then for every term xN, evaluate as the subexpression: xN AND z + ** Then for every term xN, evaluate as the subexpression: xN AND y ** That way, terms in y that are factored into the disjunction will ** be picked up by the recursive calls to sqlite3WhereBegin() below. ** ** Actually, each subexpression is converted to "xN AND w" where w is ** the "interesting" terms of z - terms that did not originate in the - ** ON or USING clause of a LEFT JOIN, and terms that are usable as + ** ON or USING clause of a LEFT JOIN, and terms that are usable as ** indices. ** ** This optimization also only applies if the (x1 OR x2 OR ...) term ** is not contained in the ON clause of a LEFT JOIN. ** See ticket http://www.sqlite.org/src/info/f2369304e4 + ** + ** 2022-02-04: Do not push down slices of a row-value comparison. + ** In other words, "w" or "y" may not be a slice of a vector. Otherwise, + ** the initialization of the right-hand operand of the vector comparison + ** might not occur, or might occur only in an OR branch that is not + ** taken. dbsqlfuzz 80a9fade844b4fb43564efc972bcb2c68270f5d1. + ** + ** 2022-03-03: Do not push down expressions that involve subqueries. + ** The subquery might get coded as a subroutine. Any table-references + ** in the subquery might be resolved to index-references for the index on + ** the OR branch in which the subroutine is coded. But if the subroutine + ** is invoked from a different OR branch that uses a different index, such + ** index-references will not work. tag-20220303a + ** https://sqlite.org/forum/forumpost/36937b197273d403 */ if( pWC->nTerm>1 ){ int iTerm; for(iTerm=0; iTermnTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; if( &pWC->a[iTerm] == pTerm ) continue; - if( ExprHasProperty(pExpr, EP_FromJoin) ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL ); testcase( pWC->a[iTerm].wtFlags & TERM_CODED ); - if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue; + testcase( pWC->a[iTerm].wtFlags & TERM_SLICE ); + if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED|TERM_SLICE))!=0 ){ + continue; + } if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; - testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); + if( ExprHasProperty(pExpr, EP_Subquery) ) continue; /* tag-20220303a */ pExpr = sqlite3ExprDup(db, pExpr, 0); - pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); + pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr); } if( pAndExpr ){ - pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr); + /* The extra 0x10000 bit on the opcode is masked off and does not + ** become part of the new Expr.op. However, it does make the + ** op==TK_AND comparison inside of sqlite3PExpr() false, and this + ** prevents sqlite3PExpr() from applying the AND short-circuit + ** optimization, which we do not want here. */ + pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr); } } @@ -127623,26 +149821,36 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ - wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); + ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR")); for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ + Expr *pDelete; /* Local copy of OR clause term */ int jmp1 = 0; /* Address of jump operation */ - if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ + testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0 + && !ExprHasProperty(pOrExpr, EP_FromJoin) + ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */ + pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0); + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDelete); + continue; + } + if( pAndExpr ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ + ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1)); WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); - pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, - wctrlFlags, iCovCur); - assert( pSubWInfo || pParse->nErr || db->mallocFailed ); + pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0, + WHERE_OR_SUBCLAUSE, iCovCur); + assert( pSubWInfo || pParse->nErr ); if( pSubWInfo ){ WhereLoop *pSubLoop; int addrExplain = sqlite3WhereExplainOneScan( - pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 + pParse, pOrTab, &pSubWInfo->a[0], 0 ); sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); @@ -127652,23 +149860,23 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** row will be skipped in subsequent sub-WHERE clauses. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - int r; int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); if( HasRowid(pTab) ){ - r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid); jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, - r,iSet); + regRowid, iSet); VdbeCoverage(v); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); int nPk = pPk->nKeyCol; int iPk; + int r; /* Read the PK into an array of temp registers. */ r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPkaiColumn[iPk]; - sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } /* Check if the temp table already contains this key. If so, @@ -127679,9 +149887,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** ** Use some of the same optimizations as OP_RowSetTest: If iSet ** is zero, assume that the key cannot already be present in - ** the temp table. And if iSet is -1, assume that there is no - ** need to insert the key into the temp table, as it will never - ** be tested for. */ + ** the temp table. And if iSet is -1, assume that there is no + ** need to insert the key into the temp table, as it will never + ** be tested for. */ if( iSet ){ jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk); VdbeCoverage(v); @@ -127720,8 +149928,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** If the call to sqlite3WhereBegin() above resulted in a scan that ** uses an index, and this is either the first OR-connected term ** processed or the index is the same as that used by all previous - ** terms, set pCov to the candidate covering index. Otherwise, set - ** pCov to NULL to indicate that no candidate covering index will + ** terms, set pCov to the candidate covering index. Otherwise, set + ** pCov to NULL to indicate that no candidate covering index will ** be available. */ pSubLoop = pSubWInfo->a[0].pWLoop; @@ -127735,13 +149943,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( }else{ pCov = 0; } + if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){ + pWInfo->bDeferredSeek = 1; + } /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); + ExplainQueryPlanPop(pParse); } + sqlite3ExprDelete(db, pDelete); } } - pLevel->u.pCovidx = pCov; + ExplainQueryPlanPop(pParse); + assert( pLevel->pWLoop==pLoop ); + assert( (pLoop->wsFlags & WHERE_MULTI_OR)!=0 ); + assert( (pLoop->wsFlags & WHERE_IN_ABLE)==0 ); + pLevel->u.pCoveringIdx = pCov; if( pCov ) pLevel->iIdxCur = iCovCur; if( pAndExpr ){ pAndExpr->pLeft = 0; @@ -127751,7 +149968,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeGoto(v, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); - if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab); + if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); } if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ @@ -127771,7 +149988,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( codeCursorHint(pTabItem, pWInfo, pLevel, 0); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; - pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); + pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; @@ -127784,43 +150001,81 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. + ** + ** This loop may run between one and three times, depending on the + ** constraints to be generated. The value of stack variable iLoop + ** determines the constraints coded by each iteration, as follows: + ** + ** iLoop==1: Code only expressions that are entirely covered by pIdx. + ** iLoop==2: Code remaining expressions that do not contain correlated + ** sub-queries. + ** iLoop==3: Code all remaining expressions. + ** + ** An effort is made to skip unnecessary iterations of the loop. */ - for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ - Expr *pE; - int skipLikeAddr = 0; - testcase( pTerm->wtFlags & TERM_VIRTUAL ); - testcase( pTerm->wtFlags & TERM_CODED ); - if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ - testcase( pWInfo->untestedTerms==0 - && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); - pWInfo->untestedTerms = 1; - continue; - } - pE = pTerm->pExpr; - assert( pE!=0 ); - if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ - continue; - } - if( pTerm->wtFlags & TERM_LIKECOND ){ - /* If the TERM_LIKECOND flag is set, that means that the range search - ** is sufficient to guarantee that the LIKE operator is true, so we - ** can skip the call to the like(A,B) function. But this only works - ** for strings. So do not skip the call to the function on the pass - ** that compares BLOBs. */ + iLoop = (pIdx ? 1 : 2); + do{ + int iNext = 0; /* Next value for iLoop */ + for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ + Expr *pE; + int skipLikeAddr = 0; + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + testcase( pTerm->wtFlags & TERM_CODED ); + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ + testcase( pWInfo->untestedTerms==0 + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); + pWInfo->untestedTerms = 1; + continue; + } + pE = pTerm->pExpr; + assert( pE!=0 ); + if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){ + continue; + } + + if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ + iNext = 2; + continue; + } + if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){ + if( iNext==0 ) iNext = 3; + continue; + } + + if( (pTerm->wtFlags & TERM_LIKECOND)!=0 ){ + /* If the TERM_LIKECOND flag is set, that means that the range search + ** is sufficient to guarantee that the LIKE operator is true, so we + ** can skip the call to the like(A,B) function. But this only works + ** for strings. So do not skip the call to the function on the pass + ** that compares BLOBs. */ #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS - continue; + continue; #else - u32 x = pLevel->iLikeRepCntr; - assert( x>0 ); - skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1)); - VdbeCoverage(v); + u32 x = pLevel->iLikeRepCntr; + if( x>0 ){ + skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1)); + VdbeCoverageIf(v, (x&1)==1); + VdbeCoverageIf(v, (x&1)==0); + } +#endif + } +#ifdef WHERETRACE_ENABLED /* 0xffff */ + if( sqlite3WhereTrace ){ + VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d", + pWC->nTerm-j, pTerm, iLoop)); + } + if( sqlite3WhereTrace & 0x800 ){ + sqlite3DebugPrintf("Coding auxiliary constraint:\n"); + sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); + } #endif + sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); + if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); + pTerm->wtFlags |= TERM_CODED; } - sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); - if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); - pTerm->wtFlags |= TERM_CODED; - } + iLoop = iNext; + }while( iLoop>0 ); /* Insert code to test for implied constraints based on transitivity ** of the "==" operator. @@ -127830,21 +150085,34 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** then we cannot use the "t1.a=t2.b" constraint, but we can code ** the implied "t1.a=123" constraint. */ - for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ + for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){ Expr *pE, sEAlt; WhereTerm *pAlt; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; if( pTerm->leftCursor!=iCur ) continue; - if( pLevel->iLeftJoin ) continue; + if( pTabItem->fg.jointype & JT_LEFT ) continue; pE = pTerm->pExpr; +#ifdef WHERETRACE_ENABLED /* 0x800 */ + if( sqlite3WhereTrace & 0x800 ){ + sqlite3DebugPrintf("Coding transitive constraint:\n"); + sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); + } +#endif assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); - pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady, + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady, WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; + if( (pAlt->eOperator & WO_IN) + && ExprUseXSelect(pAlt->pExpr) + && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) + ){ + continue; + } testcase( pAlt->eOperator & WO_EQ ); testcase( pAlt->eOperator & WO_IS ); testcase( pAlt->eOperator & WO_IN ); @@ -127852,17 +150120,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sEAlt = *pAlt->pExpr; sEAlt.pLeft = pE->pLeft; sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); + pAlt->wtFlags |= TERM_CODED; } /* For a LEFT OUTER JOIN, generate code that will record the fact that - ** at least one row of the right table has matched the left table. + ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); - sqlite3ExprCacheClear(pParse); - for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){ + for(pTerm=pWC->a, j=0; jnBase; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; @@ -127876,6 +150144,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( } } +#if WHERETRACE_ENABLED /* 0x20800 */ + if( sqlite3WhereTrace & 0x20000 ){ + sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n", + iLevel); + sqlite3WhereClausePrint(pWC); + } + if( sqlite3WhereTrace & 0x800 ){ + sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n", + iLevel, (u64)pLevel->notReady); + } +#endif return pLevel->notReady; } @@ -127962,12 +150241,13 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; + if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm; if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; }else{ pTerm->truthProb = 1; } - pTerm->pExpr = sqlite3ExprSkipCollate(p); + pTerm->pExpr = sqlite3ExprSkipCollateAndLikely(p); pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; @@ -127992,31 +150272,14 @@ static int allowedOp(int op){ /* ** Commute a comparison operator. Expressions of the form "X op Y" ** are converted into "Y op X". -** -** If left/right precedence rules come into play when determining the -** collating sequence, then COLLATE operators are adjusted to ensure -** that the collating sequence does not change. For example: -** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on -** the left hand side of a comparison overrides any collation sequence -** attached to the right. For the same reason the EP_Collate flag -** is not commuted. -*/ -static void exprCommute(Parse *pParse, Expr *pExpr){ - u16 expRight = (pExpr->pRight->flags & EP_Collate); - u16 expLeft = (pExpr->pLeft->flags & EP_Collate); - assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); - if( expRight==expLeft ){ - /* Either X and Y both have COLLATE operator or neither do */ - if( expRight ){ - /* Both X and Y have COLLATE operators. Make sure X is always - ** used by clearing the EP_Collate flag from Y. */ - pExpr->pRight->flags &= ~EP_Collate; - }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){ - /* Neither X nor Y have COLLATE operators, but X has a non-default - ** collating sequence. So add the EP_Collate marker on X to cause - ** it to be searched first. */ - pExpr->pLeft->flags |= EP_Collate; - } +*/ +static u16 exprCommute(Parse *pParse, Expr *pExpr){ + if( pExpr->pLeft->op==TK_VECTOR + || pExpr->pRight->op==TK_VECTOR + || sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight) != + sqlite3BinaryCompareCollSeq(pParse, pExpr->pRight, pExpr->pLeft) + ){ + pExpr->flags ^= EP_Commuted; } SWAP(Expr*,pExpr->pRight,pExpr->pLeft); if( pExpr->op>=TK_GT ){ @@ -128027,6 +150290,7 @@ static void exprCommute(Parse *pParse, Expr *pExpr){ assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE ); pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; } + return 0; } /* @@ -128077,70 +150341,133 @@ static int isLikeOrGlob( int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */ ){ - const char *z = 0; /* String on RHS of LIKE operator */ + const u8 *z = 0; /* String on RHS of LIKE operator */ Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ ExprList *pList; /* List of operands to the LIKE operator */ - int c; /* One character in z[] */ + u8 c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ - char wc[3]; /* Wildcard characters */ + u8 wc[4]; /* Wildcard characters */ sqlite3 *db = pParse->db; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ int rc; /* Result code to return */ - if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ + if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){ return 0; } #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif + assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; - if( pLeft->op!=TK_COLUMN - || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || IsVirtual(pLeft->pTab) /* Value might be numeric */ - ){ - /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must - ** be the name of an indexed column with TEXT affinity. */ - return 0; - } - assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */ pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); op = pRight->op; - if( op==TK_VARIABLE ){ + if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ - z = (char *)sqlite3_value_text(pVal); + z = sqlite3_value_text(pVal); } sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ - z = pRight->u.zToken; + assert( !ExprHasProperty(pRight, EP_IntValue) ); + z = (u8*)pRight->u.zToken; } if( z ){ + + /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; - } - if( cnt!=0 && 255!=(u8)z[cnt-1] ){ + if( c==wc[3] && z[cnt]!=0 ) cnt++; + } + + /* The optimization is possible only if (1) the pattern does not begin + ** with a wildcard and if (2) the non-wildcard prefix does not end with + ** an (illegal 0xff) character, or (3) the pattern does not consist of + ** a single escape character. The second condition is necessary so + ** that we can increment the prefix key to find an upper bound for the + ** range search. The third is because the caller assumes that the pattern + ** consists of at least one character after all escapes have been + ** removed. */ + if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){ Expr *pPrefix; + + /* A "complete" match if the pattern ends with "*" or "%" */ *pisComplete = c==wc[0] && z[cnt+1]==0; - pPrefix = sqlite3Expr(db, TK_STRING, z); - if( pPrefix ) pPrefix->u.zToken[cnt] = 0; + + /* Get the pattern prefix. Remove all escapes from the prefix. */ + pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); + if( pPrefix ){ + int iFrom, iTo; + char *zNew; + assert( !ExprHasProperty(pPrefix, EP_IntValue) ); + zNew = pPrefix->u.zToken; + zNew[cnt] = 0; + for(iFrom=iTo=0; iFrom0 ); + + /* If the LHS is not an ordinary column with TEXT affinity, then the + ** pattern prefix boundaries (both the start and end boundaries) must + ** not look like a number. Otherwise the pattern might be treated as + ** a number, which will invalidate the LIKE optimization. + ** + ** Getting this right has been a persistent source of bugs in the + ** LIKE optimization. See, for example: + ** 2018-09-10 https://sqlite.org/src/info/c94369cae9b561b1 + ** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28 + ** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07 + ** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975 + ** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a + */ + if( pLeft->op!=TK_COLUMN + || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT + || (ALWAYS( ExprUseYTab(pLeft) ) + && pLeft->y.pTab + && IsVirtual(pLeft->y.pTab)) /* Might be numeric */ + ){ + int isNum; + double rDummy; + isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + if( isNum<=0 ){ + if( iTo==1 && zNew[0]=='-' ){ + isNum = +1; + }else{ + zNew[iTo-1]++; + isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + zNew[iTo-1]--; + } + } + if( isNum>0 ){ + sqlite3ExprDelete(db, pPrefix); + sqlite3ValueFree(pVal); + return 0; + } + } + } *ppPrefix = pPrefix; + + /* If the RHS pattern is a bound parameter, make arrangements to + ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; sqlite3VdbeSetVarmask(v, pRight->iColumn); + assert( !ExprHasProperty(pRight, EP_IntValue) ); if( *pisComplete && pRight->u.zToken[1] ){ /* If the rhs of the LIKE expression is a variable, and the current ** value of the variable means there is no need to invoke the LIKE ** function, then no OP_Variable will be added to the program. ** This causes problems for the sqlite3_bind_parameter_name() ** API. To work around them, add a dummy OP_Variable here. - */ + */ int r1 = sqlite3GetTempReg(pParse); sqlite3ExprCodeTarget(pParse, pRight, r1); sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0); @@ -128161,48 +150488,134 @@ static int isLikeOrGlob( #ifndef SQLITE_OMIT_VIRTUALTABLE /* -** Check to see if the given expression is of the form -** -** column OP expr -** -** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a -** column of a virtual table. -** -** If it is then return TRUE. If not, return FALSE. -*/ -static int isMatchOfColumn( +** Check to see if the pExpr expression is a form that needs to be passed +** to the xBestIndex method of virtual tables. Forms of interest include: +** +** Expression Virtual Table Operator +** ----------------------- --------------------------------- +** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH +** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB +** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE +** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP +** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE +** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE +** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT +** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT +** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL +** +** In every case, "column" must be a column of a virtual table. If there +** is a match, set *ppLeft to the "column" expression, set *ppRight to the +** "expr" expression (even though in forms (6) and (8) the column is on the +** right and the expression is on the left). Also set *peOp2 to the +** appropriate virtual table operator. The return value is 1 or 2 if there +** is a match. The usual return is 1, but if the RHS is also a column +** of virtual table in forms (5) or (7) then return 2. +** +** If the expression matches none of the patterns above, return 0. +*/ +static int isAuxiliaryVtabOperator( + sqlite3 *db, /* Parsing context */ Expr *pExpr, /* Test this expression */ - unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */ -){ - static const struct Op2 { - const char *zOp; - unsigned char eOp2; - } aOp[] = { - { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, - { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, - { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, - { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } - }; - ExprList *pList; - Expr *pCol; /* Column reference */ - int i; + unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ + Expr **ppLeft, /* Column expression to left of MATCH/op2 */ + Expr **ppRight /* Expression to left of MATCH/op2 */ +){ + if( pExpr->op==TK_FUNCTION ){ + static const struct Op2 { + const char *zOp; + unsigned char eOp2; + } aOp[] = { + { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, + { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, + { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, + { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } + }; + ExprList *pList; + Expr *pCol; /* Column reference */ + int i; - if( pExpr->op!=TK_FUNCTION ){ - return 0; - } - pList = pExpr->x.pList; - if( pList==0 || pList->nExpr!=2 ){ - return 0; - } - pCol = pList->a[1].pExpr; - if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){ - return 0; - } - for(i=0; iu.zToken, aOp[i].zOp)==0 ){ - *peOp2 = aOp[i].eOp2; - return 1; + assert( ExprUseXList(pExpr) ); + pList = pExpr->x.pList; + if( pList==0 || pList->nExpr!=2 ){ + return 0; } + + /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a + ** virtual table on their second argument, which is the same as + ** the left-hand side operand in their in-fix form. + ** + ** vtab_column MATCH expression + ** MATCH(expression,vtab_column) + */ + pCol = pList->a[1].pExpr; + assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) ); + testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 ); + if( ExprIsVtab(pCol) ){ + for(i=0; iu.zToken, aOp[i].zOp)==0 ){ + *peOp2 = aOp[i].eOp2; + *ppRight = pList->a[0].pExpr; + *ppLeft = pCol; + return 1; + } + } + } + + /* We can also match against the first column of overloaded + ** functions where xFindFunction returns a value of at least + ** SQLITE_INDEX_CONSTRAINT_FUNCTION. + ** + ** OVERLOADED(vtab_column,expression) + ** + ** Historically, xFindFunction expected to see lower-case function + ** names. But for this use case, xFindFunction is expected to deal + ** with function names in an arbitrary case. + */ + pCol = pList->a[0].pExpr; + assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) ); + testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 ); + if( ExprIsVtab(pCol) ){ + sqlite3_vtab *pVtab; + sqlite3_module *pMod; + void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**); + void *pNotUsed; + pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab; + assert( pVtab!=0 ); + assert( pVtab->pModule!=0 ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pMod = (sqlite3_module *)pVtab->pModule; + if( pMod->xFindFunction!=0 ){ + i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed); + if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ + *peOp2 = i; + *ppRight = pList->a[1].pExpr; + *ppLeft = pCol; + return 1; + } + } + } + }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ + int res = 0; + Expr *pLeft = pExpr->pLeft; + Expr *pRight = pExpr->pRight; + assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) ); + testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 ); + if( ExprIsVtab(pLeft) ){ + res++; + } + assert( pRight==0 || pRight->op!=TK_COLUMN || ExprUseYTab(pRight) ); + testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 ); + if( pRight && ExprIsVtab(pRight) ){ + res++; + SWAP(Expr*, pLeft, pRight); + } + *ppLeft = pLeft; + *ppRight = pRight; + if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE; + if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT; + if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL; + return res; } return 0; } @@ -128215,7 +150628,7 @@ static int isMatchOfColumn( static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ if( pDerived ){ pDerived->flags |= pBase->flags & EP_FromJoin; - pDerived->iRightJoinTable = pBase->iRightJoinTable; + pDerived->w.iRightJoinTable = pBase->w.iRightJoinTable; } } @@ -128261,7 +150674,7 @@ static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){ ** ** The following is NOT generated: ** -** xy --> x!=y +** xy --> x!=y */ static void whereCombineDisjuncts( SrcList *pSrc, /* the FROM clause */ @@ -128275,14 +150688,15 @@ static void whereCombineDisjuncts( int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ + if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return; if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); - if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; - if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return; + if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; + if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return; /* If we reach this point, it means the two subterms can be combined */ if( (eOp & (eOp-1))!=0 ){ if( eOp & (WO_LT|WO_LE) ){ @@ -128358,10 +150772,10 @@ static void whereCombineDisjuncts( ** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T ** ** A subterm is "indexable" if it is of the form -** "T.C " where C is any column of table T and +** "T.C " where C is any column of table T and ** is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN". ** A subterm is also indexable if it is an AND of two or more -** subsubterms at least one of which is indexable. Indexable AND +** subsubterms at least one of which is indexable. Indexable AND ** subterms have their eOperator set to WO_AND and they have ** u.pAndInfo set to a dynamically allocated WhereAndTerm object. ** @@ -128443,6 +150857,7 @@ static void exprAnalyzeOrTerm( pOrTerm->u.pAndInfo = pAndInfo; pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; + pOrTerm->leftCursor = -1; pAndWC = &pAndInfo->wc; memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic)); sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); @@ -128452,8 +150867,8 @@ static void exprAnalyzeOrTerm( if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); - if( allowedOp(pAndTerm->pExpr->op) - || pAndTerm->eOperator==WO_MATCH + if( allowedOp(pAndTerm->pExpr->op) + || pAndTerm->eOperator==WO_AUX ){ b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } @@ -128485,7 +150900,11 @@ static void exprAnalyzeOrTerm( ** empty. */ pOrInfo->indexable = indexable; - pTerm->eOperator = indexable==0 ? 0 : WO_OR; + pTerm->eOperator = WO_OR; + pTerm->leftCursor = -1; + if( indexable ){ + pWC->hasOr = 1; + } /* For a two-way OR, attempt to implementation case 2. */ @@ -128535,10 +150954,11 @@ static void exprAnalyzeOrTerm( ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ + Expr *pLeft = 0; pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); - pOrTerm->wtFlags &= ~TERM_OR_OK; + pOrTerm->wtFlags &= ~TERM_OK; if( pOrTerm->leftCursor==iCursor ){ /* This is the 2-bit case and we are on the second iteration and ** current term is from the first iteration. So skip this term. */ @@ -128549,15 +150969,17 @@ static void exprAnalyzeOrTerm( pOrTerm->leftCursor))==0 ){ /* This term must be of the form t1.a==t2.b where t2 is in the ** chngToIN set but t1 is not. This term will be either preceded - ** or follwed by an inverted copy (t2.b==t1.a). Skip this term + ** or follwed by an inverted copy (t2.b==t1.a). Skip this term ** and use its inversion. */ testcase( pOrTerm->wtFlags & TERM_COPIED ); testcase( pOrTerm->wtFlags & TERM_VIRTUAL ); assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); continue; } - iColumn = pOrTerm->u.leftColumn; + assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); + iColumn = pOrTerm->u.x.leftColumn; iCursor = pOrTerm->leftCursor; + pLeft = pOrTerm->pExpr->pLeft; break; } if( i<0 ){ @@ -128575,9 +150997,12 @@ static void exprAnalyzeOrTerm( okToChngToIN = 1; for(; i>=0 && okToChngToIN; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); + assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); if( pOrTerm->leftCursor!=iCursor ){ - pOrTerm->wtFlags &= ~TERM_OR_OK; - }else if( pOrTerm->u.leftColumn!=iColumn ){ + pOrTerm->wtFlags &= ~TERM_OK; + }else if( pOrTerm->u.x.leftColumn!=iColumn || (iColumn==XN_EXPR + && sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1) + )){ okToChngToIN = 0; }else{ int affLeft, affRight; @@ -128590,14 +151015,14 @@ static void exprAnalyzeOrTerm( if( affRight!=0 && affRight!=affLeft ){ okToChngToIN = 0; }else{ - pOrTerm->wtFlags |= TERM_OR_OK; + pOrTerm->wtFlags |= TERM_OK; } } } } /* At this point, okToChngToIN is true if original pTerm satisfies - ** case 1. In that case, construct a new virtual term that is + ** case 1. In that case, construct a new virtual term that is ** pTerm converted into an IN operator. */ if( okToChngToIN ){ @@ -128607,10 +151032,11 @@ static void exprAnalyzeOrTerm( Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ - if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; + if( (pOrTerm->wtFlags & TERM_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); + assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 ); assert( pOrTerm->leftCursor==iCursor ); - assert( pOrTerm->u.leftColumn==iColumn ); + assert( pOrTerm->u.x.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; @@ -128621,17 +151047,16 @@ static void exprAnalyzeOrTerm( if( pNew ){ int idxNew; transferJoinMarkings(pNew, pExpr); - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + assert( ExprUseXList(pNew) ); pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); - pTerm = &pWC->a[idxTerm]; + /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where reused */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); } - pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */ } } } @@ -128655,7 +151080,6 @@ static void exprAnalyzeOrTerm( static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; - const char *zColl1, *zColl2; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; @@ -128666,13 +151090,9 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ ){ return 0; } - pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); - if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - zColl1 = pColl ? pColl->zName : 0; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); - zColl2 = pColl ? pColl->zName : 0; - return sqlite3_stricmp(zColl1, zColl2)==0; + pColl = sqlite3ExprCompareCollSeq(pParse, pExpr); + if( sqlite3IsBinary(pColl) ) return 1; + return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); } /* @@ -128694,6 +151114,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ for(i=0; inSrc; i++){ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn); + if( pSrc->a[i].fg.isTabFunc ){ + mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg); + } } } pS = pS->pPrior; @@ -128705,8 +151128,8 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ ** Expression pExpr is one operand of a comparison operator that might ** be useful for indexing. This routine checks to see if pExpr appears ** in any index. Return TRUE (1) if pExpr is an indexed term and return -** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor -** number of the table that is indexed and *piColumn to the column number +** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor +** number of the table that is indexed and aiCurCol[1] to the column number ** of the column that is indexed, or XN_EXPR (-2) if an expression is being ** indexed. ** @@ -128714,51 +151137,60 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ ** true even if that particular column is not indexed, because the column ** might be added to an automatic index later. */ -static int exprMightBeIndexed( +static SQLITE_NOINLINE int exprMightBeIndexed2( SrcList *pFrom, /* The FROM clause */ - int op, /* The specific comparison operator */ Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ - Expr *pExpr, /* An operand of a comparison operator */ - int *piCur, /* Write the referenced table cursor number here */ - int *piColumn /* Write the referenced table column number here */ + int *aiCurCol, /* Write the referenced table cursor and column here */ + Expr *pExpr /* An operand of a comparison operator */ ){ Index *pIdx; int i; int iCur; - - /* If this expression is a vector to the left or right of a - ** inequality constraint (>, <, >= or <=), perform the processing + for(i=0; mPrereq>1; i++, mPrereq>>=1){} + iCur = pFrom->a[i].iCursor; + for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->aColExpr==0 ) continue; + for(i=0; inKeyCol; i++){ + if( pIdx->aiColumn[i]!=XN_EXPR ) continue; + if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ + aiCurCol[0] = iCur; + aiCurCol[1] = XN_EXPR; + return 1; + } + } + } + return 0; +} +static int exprMightBeIndexed( + SrcList *pFrom, /* The FROM clause */ + Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ + int *aiCurCol, /* Write the referenced table cursor & column here */ + Expr *pExpr, /* An operand of a comparison operator */ + int op /* The specific comparison operator */ +){ + /* If this expression is a vector to the left or right of a + ** inequality constraint (>, <, >= or <=), perform the processing ** on the first element of the vector. */ assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE ); assert( TK_ISop==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){ + assert( ExprUseXList(pExpr) ); pExpr = pExpr->x.pList->a[0].pExpr; + } if( pExpr->op==TK_COLUMN ){ - *piCur = pExpr->iTable; - *piColumn = pExpr->iColumn; + aiCurCol[0] = pExpr->iTable; + aiCurCol[1] = pExpr->iColumn; return 1; } if( mPrereq==0 ) return 0; /* No table references */ if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ - for(i=0; mPrereq>1; i++, mPrereq>>=1){} - iCur = pFrom->a[i].iCursor; - for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->aColExpr==0 ) continue; - for(i=0; inKeyCol; i++){ - if( pIdx->aiColumn[i]!=XN_EXPR ) continue; - if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ - *piCur = iCur; - *piColumn = XN_EXPR; - return 1; - } - } - } - return 0; + return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr); } + /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the @@ -128795,34 +151227,53 @@ static void exprAnalyze( int op; /* Top-level operator. pExpr->op */ Parse *pParse = pWInfo->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection */ - unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */ + unsigned char eOp2 = 0; /* op2 value for LIKE/REGEXP/GLOB */ int nLeft; /* Number of elements on left side vector */ if( db->mallocFailed ){ return; } + assert( pWC->nTerm > idxTerm ); pTerm = &pWC->a[idxTerm]; pMaskSet = &pWInfo->sMaskSet; pExpr = pTerm->pExpr; + assert( pExpr!=0 ); /* Because malloc() has not failed */ assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); + pMaskSet->bVarSelect = 0; prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( sqlite3ExprCheckIN(pParse, pExpr) ) return; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); }else{ pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); } - }else if( op==TK_ISNULL ){ - pTerm->prereqRight = 0; + prereqAll = prereqLeft | pTerm->prereqRight; }else{ pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); + if( pExpr->pLeft==0 + || ExprHasProperty(pExpr, EP_xIsSelect|EP_IfNullRow) + || pExpr->x.pList!=0 + ){ + prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr); + }else{ + prereqAll = prereqLeft | pTerm->prereqRight; + } } - prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr); + if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT; + +#ifdef SQLITE_DEBUG + if( prereqAll!=sqlite3WhereExprUsageNN(pMaskSet, pExpr) ){ + printf("\n*** Incorrect prereqAll computed for:\n"); + sqlite3TreeViewExpr(0,pExpr,0); + abort(); + } +#endif + if( ExprHasProperty(pExpr, EP_FromJoin) ){ - Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); + Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iRightJoinTable); prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ @@ -128836,30 +151287,33 @@ static void exprAnalyze( pTerm->iParent = -1; pTerm->eOperator = 0; if( allowedOp(op) ){ - int iCur, iColumn; + int aiCurCol[2]; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; - if( pTerm->iField>0 ){ + if( pTerm->u.x.iField>0 ){ assert( op==TK_IN ); assert( pLeft->op==TK_VECTOR ); - pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr; + assert( ExprUseXList(pLeft) ); + pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr; } - if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){ - pTerm->leftCursor = iCur; - pTerm->u.leftColumn = iColumn; + if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ + pTerm->leftCursor = aiCurCol[0]; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + pTerm->u.x.leftColumn = aiCurCol[1]; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; - if( pRight - && exprMightBeIndexed(pSrc, op, pTerm->prereqRight, pRight, &iCur,&iColumn) + if( pRight + && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op) + && !ExprHasProperty(pRight, EP_FixedCol) ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ - assert( pTerm->iField==0 ); + assert( pTerm->u.x.iField==0 ); if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); @@ -128883,13 +151337,25 @@ static void exprAnalyze( pDup = pExpr; pNew = pTerm; } - exprCommute(pParse, pDup); - pNew->leftCursor = iCur; - pNew->u.leftColumn = iColumn; + pNew->wtFlags |= exprCommute(pParse, pDup); + pNew->leftCursor = aiCurCol[0]; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + pNew->u.x.leftColumn = aiCurCol[1]; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; + }else + if( op==TK_ISNULL + && !ExprHasProperty(pExpr,EP_FromJoin) + && 0==sqlite3ExprCanBeNull(pLeft) + ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + pExpr->op = TK_TRUEFALSE; + pExpr->u.zToken = "false"; + ExprSetProperty(pExpr, EP_IsFalse); + pTerm->prereqAll = 0; + pTerm->eOperator = 0; } } @@ -128910,15 +151376,17 @@ static void exprAnalyze( ** BETWEEN term is skipped. */ else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){ - ExprList *pList = pExpr->x.pList; + ExprList *pList; int i; static const u8 ops[] = {TK_GE, TK_LE}; + assert( ExprUseXList(pExpr) ); + pList = pExpr->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); for(i=0; i<2; i++){ Expr *pNewExpr; int idxNew; - pNewExpr = sqlite3PExpr(pParse, ops[i], + pNewExpr = sqlite3PExpr(pParse, ops[i], sqlite3ExprDup(db, pExpr->pLeft, 0), sqlite3ExprDup(db, pList->a[i].pExpr, 0)); transferJoinMarkings(pNewExpr, pExpr); @@ -128941,6 +151409,42 @@ static void exprAnalyze( pTerm = &pWC->a[idxTerm]; } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ + /* The form "x IS NOT NULL" can sometimes be evaluated more efficiently + ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a + ** virtual term of that form. + ** + ** The virtual term must be tagged with TERM_VNULL. + */ + else if( pExpr->op==TK_NOTNULL ){ + if( pExpr->pLeft->op==TK_COLUMN + && pExpr->pLeft->iColumn>=0 + && !ExprHasProperty(pExpr, EP_FromJoin) + ){ + Expr *pNewExpr; + Expr *pLeft = pExpr->pLeft; + int idxNew; + WhereTerm *pNewTerm; + + pNewExpr = sqlite3PExpr(pParse, TK_GT, + sqlite3ExprDup(db, pLeft, 0), + sqlite3ExprAlloc(db, TK_NULL, 0, 0)); + + idxNew = whereClauseInsert(pWC, pNewExpr, + TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); + if( idxNew ){ + pNewTerm = &pWC->a[idxNew]; + pNewTerm->prereqRight = 0; + pNewTerm->leftCursor = pLeft->iTable; + pNewTerm->u.x.leftColumn = pLeft->iColumn; + pNewTerm->eOperator = WO_GT; + markTermAsChild(pWC, idxNew, idxTerm); + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + pNewTerm->prereqAll = pTerm->prereqAll; + } + } + } + #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION /* Add constraints to reduce the search space on a LIKE or GLOB @@ -128956,7 +151460,8 @@ static void exprAnalyze( ** bound is made all lowercase so that the bounds also work when comparing ** BLOBs. */ - if( pWC->op==TK_AND + else if( pExpr->op==TK_FUNCTION + && pWC->op==TK_AND && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase) ){ Expr *pLeft; /* LHS of LIKE/GLOB operator */ @@ -128968,8 +151473,12 @@ static void exprAnalyze( const char *zCollSeqName; /* Name of collating sequence */ const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC; + assert( ExprUseXList(pExpr) ); pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); + assert( pStr1==0 || !ExprHasProperty(pStr1, EP_IntValue) ); + assert( pStr2==0 || !ExprHasProperty(pStr2, EP_IntValue) ); + /* Convert the lower bound to upper-case and the upper bound to ** lower-case (upper-case is less than lower-case in ASCII) so that @@ -128992,7 +151501,7 @@ static void exprAnalyze( if( noCase ){ /* The point is to increment the last character before the first ** wildcard. But if we increment '@', that will push it into the - ** alphabetic range where case conversions will mess up the + ** alphabetic range where case conversions will mess up the ** inequality. To avoid this, make sure to also run the full ** LIKE on all candidate expressions by clearing the isComplete flag */ @@ -129001,7 +151510,7 @@ static void exprAnalyze( } *pC = c + 1; } - zCollSeqName = noCase ? "NOCASE" : "BINARY"; + zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), @@ -129026,133 +151535,114 @@ static void exprAnalyze( } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ -#ifndef SQLITE_OMIT_VIRTUALTABLE - /* Add a WO_MATCH auxiliary term to the constraint set if the - ** current expression is of the form: column MATCH expr. - ** This information is used by the xBestIndex methods of - ** virtual tables. The native query optimizer does not attempt - ** to do anything with MATCH functions. - */ - if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){ - int idxNew; - Expr *pRight, *pLeft; - WhereTerm *pNewTerm; - Bitmask prereqColumn, prereqExpr; - - pRight = pExpr->x.pList->a[0].pExpr; - pLeft = pExpr->x.pList->a[1].pExpr; - prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); - prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); - if( (prereqExpr & prereqColumn)==0 ){ - Expr *pNewExpr; - pNewExpr = sqlite3PExpr(pParse, TK_MATCH, - 0, sqlite3ExprDup(db, pRight, 0)); - idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); - testcase( idxNew==0 ); - pNewTerm = &pWC->a[idxNew]; - pNewTerm->prereqRight = prereqExpr; - pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; - pNewTerm->eOperator = WO_MATCH; - pNewTerm->eMatchOp = eOp2; - markTermAsChild(pWC, idxNew, idxTerm); - pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags |= TERM_COPIED; - pNewTerm->prereqAll = pTerm->prereqAll; - } - } -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create ** new terms for each component comparison - "a = ?" and "b = ?". The ** new terms completely replace the original vector comparison, which is ** no longer used. ** ** This is only required if at least one side of the comparison operation - ** is not a sub-select. */ - if( pWC->op==TK_AND - && (pExpr->op==TK_EQ || pExpr->op==TK_IS) - && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1 - && sqlite3ExprVectorSize(pExpr->pRight)==nLeft - && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 - || (pExpr->pRight->flags & EP_xIsSelect)==0) + ** is not a sub-select. + ** + ** tag-20220128a + */ + if( (pExpr->op==TK_EQ || pExpr->op==TK_IS) + && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1 + && sqlite3ExprVectorSize(pExpr->pRight)==nLeft + && ( (pExpr->pLeft->flags & EP_xIsSelect)==0 + || (pExpr->pRight->flags & EP_xIsSelect)==0) + && pWC->op==TK_AND ){ int i; for(i=0; ipLeft, i); - Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i); + Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i, nLeft); + Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i, nLeft); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); transferJoinMarkings(pNew, pExpr); - idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC); + idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC|TERM_SLICE); exprAnalyze(pSrc, pWC, idxNew); } pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL; /* Disable the original */ + pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */ pTerm->eOperator = 0; } /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create ** a virtual term for each vector component. The expression object - ** used by each such virtual term is pExpr (the full vector IN(...) - ** expression). The WhereTerm.iField variable identifies the index within + ** used by each such virtual term is pExpr (the full vector IN(...) + ** expression). The WhereTerm.u.x.iField variable identifies the index within ** the vector on the LHS that the virtual term represents. ** - ** This only works if the RHS is a simple SELECT, not a compound + ** This only works if the RHS is a simple SELECT (not a compound) that does + ** not use window functions. */ - if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0 + else if( pExpr->op==TK_IN + && pTerm->u.x.iField==0 && pExpr->pLeft->op==TK_VECTOR + && ALWAYS( ExprUseXSelect(pExpr) ) && pExpr->x.pSelect->pPrior==0 +#ifndef SQLITE_OMIT_WINDOWFUNC + && pExpr->x.pSelect->pWin==0 +#endif + && pWC->op==TK_AND ){ int i; for(i=0; ipLeft); i++){ int idxNew; - idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL); - pWC->a[idxNew].iField = i+1; + idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE); + pWC->a[idxNew].u.x.iField = i+1; exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - /* When sqlite_stat3 histogram data is available an operator of the - ** form "x IS NOT NULL" can sometimes be evaluated more efficiently - ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a - ** virtual term of that form. - ** - ** Note that the virtual term must be tagged with TERM_VNULL. +#ifndef SQLITE_OMIT_VIRTUALTABLE + /* Add a WO_AUX auxiliary term to the constraint set if the + ** current expression is of the form "column OP expr" where OP + ** is an operator that gets passed into virtual tables but which is + ** not normally optimized for ordinary tables. In other words, OP + ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. + ** This information is used by the xBestIndex methods of + ** virtual tables. The native query optimizer does not attempt + ** to do anything with MATCH functions. */ - if( pExpr->op==TK_NOTNULL - && pExpr->pLeft->op==TK_COLUMN - && pExpr->pLeft->iColumn>=0 - && OptimizationEnabled(db, SQLITE_Stat34) - ){ - Expr *pNewExpr; - Expr *pLeft = pExpr->pLeft; - int idxNew; - WhereTerm *pNewTerm; - - pNewExpr = sqlite3PExpr(pParse, TK_GT, - sqlite3ExprDup(db, pLeft, 0), - sqlite3ExprAlloc(db, TK_NULL, 0, 0)); - - idxNew = whereClauseInsert(pWC, pNewExpr, - TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); - if( idxNew ){ - pNewTerm = &pWC->a[idxNew]; - pNewTerm->prereqRight = 0; - pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; - pNewTerm->eOperator = WO_GT; - markTermAsChild(pWC, idxNew, idxTerm); - pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags |= TERM_COPIED; - pNewTerm->prereqAll = pTerm->prereqAll; + else if( pWC->op==TK_AND ){ + Expr *pRight = 0, *pLeft = 0; + int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight); + while( res-- > 0 ){ + int idxNew; + WhereTerm *pNewTerm; + Bitmask prereqColumn, prereqExpr; + + prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); + prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); + if( (prereqExpr & prereqColumn)==0 ){ + Expr *pNewExpr; + pNewExpr = sqlite3PExpr(pParse, TK_MATCH, + 0, sqlite3ExprDup(db, pRight, 0)); + if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){ + ExprSetProperty(pNewExpr, EP_FromJoin); + pNewExpr->w.iRightJoinTable = pExpr->w.iRightJoinTable; + } + idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + pNewTerm = &pWC->a[idxNew]; + pNewTerm->prereqRight = prereqExpr; + pNewTerm->leftCursor = pLeft->iTable; + pNewTerm->u.x.leftColumn = pLeft->iColumn; + pNewTerm->eOperator = WO_AUX; + pNewTerm->eMatchOp = eOp2; + markTermAsChild(pWC, idxNew, idxTerm); + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + pNewTerm->prereqAll = pTerm->prereqAll; + } + SWAP(Expr*, pLeft, pRight); } } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_OMIT_VIRTUALTABLE */ /* Prevent ON clause terms of a LEFT JOIN from being used to drive ** an index for tables to the left of the join. @@ -129185,8 +151675,9 @@ static void exprAnalyze( ** all terms of the WHERE clause. */ SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ - Expr *pE2 = sqlite3ExprSkipCollate(pExpr); + Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr); pWC->op = op; + assert( pE2!=0 || pExpr==0 ); if( pE2==0 ) return; if( pE2->op!=op ){ whereClauseInsert(pWC, pExpr, 0); @@ -129196,6 +151687,113 @@ SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ } } +/* +** Add either a LIMIT (if eMatchOp==SQLITE_INDEX_CONSTRAINT_LIMIT) or +** OFFSET (if eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET) term to the +** where-clause passed as the first argument. The value for the term +** is found in register iReg. +** +** In the common case where the value is a simple integer +** (example: "LIMIT 5 OFFSET 10") then the expression codes as a +** TK_INTEGER so that it will be available to sqlite3_vtab_rhs_value(). +** If not, then it codes as a TK_REGISTER expression. +*/ +static void whereAddLimitExpr( + WhereClause *pWC, /* Add the constraint to this WHERE clause */ + int iReg, /* Register that will hold value of the limit/offset */ + Expr *pExpr, /* Expression that defines the limit/offset */ + int iCsr, /* Cursor to which the constraint applies */ + int eMatchOp /* SQLITE_INDEX_CONSTRAINT_LIMIT or _OFFSET */ +){ + Parse *pParse = pWC->pWInfo->pParse; + sqlite3 *db = pParse->db; + Expr *pNew; + int iVal = 0; + + if( sqlite3ExprIsInteger(pExpr, &iVal) && iVal>=0 ){ + Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0); + if( pVal==0 ) return; + ExprSetProperty(pVal, EP_IntValue); + pVal->u.iValue = iVal; + pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); + }else{ + Expr *pVal = sqlite3Expr(db, TK_REGISTER, 0); + if( pVal==0 ) return; + pVal->iTable = iReg; + pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); + } + if( pNew ){ + WhereTerm *pTerm; + int idx; + idx = whereClauseInsert(pWC, pNew, TERM_DYNAMIC|TERM_VIRTUAL); + pTerm = &pWC->a[idx]; + pTerm->leftCursor = iCsr; + pTerm->eOperator = WO_AUX; + pTerm->eMatchOp = eMatchOp; + } +} + +/* +** Possibly add terms corresponding to the LIMIT and OFFSET clauses of the +** SELECT statement passed as the second argument. These terms are only +** added if: +** +** 1. The SELECT statement has a LIMIT clause, and +** 2. The SELECT statement is not an aggregate or DISTINCT query, and +** 3. The SELECT statement has exactly one object in its from clause, and +** that object is a virtual table, and +** 4. There are no terms in the WHERE clause that will not be passed +** to the virtual table xBestIndex method. +** 5. The ORDER BY clause, if any, will be made available to the xBestIndex +** method. +** +** LIMIT and OFFSET terms are ignored by most of the planner code. They +** exist only so that they may be passed to the xBestIndex method of the +** single virtual table in the FROM clause of the SELECT. +*/ +SQLITE_PRIVATE void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){ + assert( p==0 || (p->pGroupBy==0 && (p->selFlags & SF_Aggregate)==0) ); + if( (p && p->pLimit) /* 1 */ + && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */ + && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */ + ){ + ExprList *pOrderBy = p->pOrderBy; + int iCsr = p->pSrc->a[0].iCursor; + int ii; + + /* Check condition (4). Return early if it is not met. */ + for(ii=0; iinTerm; ii++){ + if( pWC->a[ii].wtFlags & TERM_CODED ){ + /* This term is a vector operation that has been decomposed into + ** other, subsequent terms. It can be ignored. See tag-20220128a */ + assert( pWC->a[ii].wtFlags & TERM_VIRTUAL ); + assert( pWC->a[ii].eOperator==0 ); + continue; + } + if( pWC->a[ii].leftCursor!=iCsr ) return; + } + + /* Check condition (5). Return early if it is not met. */ + if( pOrderBy ){ + for(ii=0; iinExpr; ii++){ + Expr *pExpr = pOrderBy->a[ii].pExpr; + if( pExpr->op!=TK_COLUMN ) return; + if( pExpr->iTable!=iCsr ) return; + if( pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_BIGNULL ) return; + } + } + + /* All conditions are met. Add the terms to the where-clause object. */ + assert( p->pLimit->op==TK_LIMIT ); + whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft, + iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT); + if( p->iOffset>0 ){ + whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight, + iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET); + } + } +} + /* ** Initialize a preallocated WhereClause structure. */ @@ -129204,8 +151802,10 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit( WhereInfo *pWInfo /* The WHERE processing context */ ){ pWC->pWInfo = pWInfo; + pWC->hasOr = 0; pWC->pOuter = 0; pWC->nTerm = 0; + pWC->nBase = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; } @@ -129216,17 +151816,34 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit( ** sqlite3WhereClauseInit(). */ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){ - int i; - WhereTerm *a; sqlite3 *db = pWC->pWInfo->pParse->db; - for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){ - if( a->wtFlags & TERM_DYNAMIC ){ - sqlite3ExprDelete(db, a->pExpr); + assert( pWC->nTerm>=pWC->nBase ); + if( pWC->nTerm>0 ){ + WhereTerm *a = pWC->a; + WhereTerm *aLast = &pWC->a[pWC->nTerm-1]; +#ifdef SQLITE_DEBUG + int i; + /* Verify that every term past pWC->nBase is virtual */ + for(i=pWC->nBase; inTerm; i++){ + assert( (pWC->a[i].wtFlags & TERM_VIRTUAL)!=0 ); } - if( a->wtFlags & TERM_ORINFO ){ - whereOrInfoDelete(db, a->u.pOrInfo); - }else if( a->wtFlags & TERM_ANDINFO ){ - whereAndInfoDelete(db, a->u.pAndInfo); +#endif + while(1){ + assert( a->eMatchOp==0 || a->eOperator==WO_AUX ); + if( a->wtFlags & TERM_DYNAMIC ){ + sqlite3ExprDelete(db, a->pExpr); + } + if( a->wtFlags & (TERM_ORINFO|TERM_ANDINFO) ){ + if( a->wtFlags & TERM_ORINFO ){ + assert( (a->wtFlags & TERM_ANDINFO)==0 ); + whereOrInfoDelete(db, a->u.pOrInfo); + }else{ + assert( (a->wtFlags & TERM_ANDINFO)!=0 ); + whereAndInfoDelete(db, a->u.pAndInfo); + } + } + if( a==aLast ) break; + a++; } } if( pWC->a!=pWC->aStatic ){ @@ -129239,24 +151856,71 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){ ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. +** +** sqlite3WhereExprUsage(MaskSet, Expr) -> +** +** Return a Bitmask of all tables referenced by Expr. Expr can be +** be NULL, in which case 0 is returned. +** +** sqlite3WhereExprUsageNN(MaskSet, Expr) -> +** +** Same as sqlite3WhereExprUsage() except that Expr must not be +** NULL. The "NN" suffix on the name stands for "Not Null". +** +** sqlite3WhereExprListUsage(MaskSet, ExprList) -> +** +** Return a Bitmask of all tables referenced by every expression +** in the expression list ExprList. ExprList can be NULL, in which +** case 0 is returned. +** +** sqlite3WhereExprUsageFull(MaskSet, ExprList) -> +** +** Internal use only. Called only by sqlite3WhereExprUsageNN() for +** complex expressions that require pushing register values onto +** the stack. Many calls to sqlite3WhereExprUsageNN() do not need +** the more complex analysis done by this routine. Hence, the +** computations done by this routine are broken out into a separate +** "no-inline" function to avoid the stack push overhead in the +** common case where it is not needed. */ -SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ +static SQLITE_NOINLINE Bitmask sqlite3WhereExprUsageFull( + WhereMaskSet *pMaskSet, + Expr *p +){ Bitmask mask; - if( p==0 ) return 0; - if( p->op==TK_COLUMN ){ - mask = sqlite3WhereGetMask(pMaskSet, p->iTable); - return mask; - } - assert( !ExprHasProperty(p, EP_TokenOnly) ); - mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0; - if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); - if( ExprHasProperty(p, EP_xIsSelect) ){ + mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; + if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft); + if( p->pRight ){ + mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight); + assert( p->x.pList==0 ); + }else if( ExprUseXSelect(p) ){ + if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1; mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && ExprUseYWin(p) ){ + assert( p->y.pWin!=0 ); + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); + mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter); + } +#endif return mask; } +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ + if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ + return sqlite3WhereGetMask(pMaskSet, p->iTable); + }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ + assert( p->op!=TK_IF_NULL_ROW ); + return 0; + } + return sqlite3WhereExprUsageFull(pMaskSet, p); +} +SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ + return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0; +} SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){ int i; Bitmask mask = 0; @@ -129270,7 +151934,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprLis /* -** Call exprAnalyze on all terms in a WHERE clause. +** Call exprAnalyze on all terms in a WHERE clause. ** ** Note that exprAnalyze() might add new virtual terms onto the ** end of the WHERE clause. We do not want to analyze these new @@ -129289,14 +151953,14 @@ SQLITE_PRIVATE void sqlite3WhereExprAnalyze( /* ** For table-valued-functions, transform the function arguments into -** new WHERE clause terms. +** new WHERE clause terms. ** ** Each function argument translates into an equality constraint against ** a HIDDEN column in the table. */ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( Parse *pParse, /* Parsing context */ - struct SrcList_item *pItem, /* The FROM clause term to process */ + SrcItem *pItem, /* The FROM clause term to process */ WhereClause *pWC /* Xfer function arguments to here */ ){ Table *pTab; @@ -129310,6 +151974,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; for(j=k=0; jnExpr; j++){ + Expr *pRhs; while( knCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", @@ -129320,9 +151985,15 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; - pColRef->pTab = pTab; - pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, - sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0)); + assert( ExprUseYTab(pColRef) ); + pColRef->y.pTab = pTab; + pItem->colUsed |= sqlite3ExprColUsed(pColRef); + pRhs = sqlite3PExpr(pParse, TK_UPLUS, + sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); + pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); + if( pItem->fg.jointype & JT_LEFT ){ + sqlite3SetJoinExpr(pTerm, pItem->iCursor); + } whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } @@ -129350,15 +152021,30 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs( /* #include "sqliteInt.h" */ /* #include "whereInt.h" */ +/* +** Extra information appended to the end of sqlite3_index_info but not +** visible to the xBestIndex function, at least not directly. The +** sqlite3_vtab_collation() interface knows how to reach it, however. +** +** This object is not an API and can be changed from one release to the +** next. As long as allocateIndexInfo() and sqlite3_vtab_collation() +** agree on the structure, all will be well. +*/ +typedef struct HiddenIndexInfo HiddenIndexInfo; +struct HiddenIndexInfo { + WhereClause *pWC; /* The Where clause being analyzed */ + Parse *pParse; /* The parsing context */ + int eDistinct; /* Value to return from sqlite3_vtab_distinct() */ + u32 mIn; /* Mask of terms that are IN (...) */ + u32 mHandleIn; /* Terms that vtab will handle as IN (...) */ + sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST + ** because extra space is allocated to hold up + ** to nTerm such values */ +}; + /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); -/* Test variable that can be set to enable WHERE tracing */ -#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) -/***/ int sqlite3WhereTrace = 0; -#endif - - /* ** Return the estimated number of output rows from a WHERE clause */ @@ -129375,23 +152061,76 @@ SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){ } /* -** Return TRUE if the WHERE clause returns rows in ORDER BY order. -** Return FALSE if the output needs to be sorted. +** Return the number of ORDER BY terms that are satisfied by the +** WHERE clause. A return of 0 means that the output must be +** completely sorted. A return equal to the number of ORDER BY +** terms means that no sorting is needed at all. A return that +** is positive but less than the number of ORDER BY terms means that +** block sorting is required. */ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } /* -** Return TRUE if the innermost loop of the WHERE clause implementation -** returns rows in ORDER BY order for complete run of the inner loop. +** In the ORDER BY LIMIT optimization, if the inner-most loop is known +** to emit rows in increasing order, and if the last row emitted by the +** inner-most loop did not fit within the sorter, then we can skip all +** subsequent rows for the current iteration of the inner loop (because they +** will not fit in the sorter either) and continue with the second inner +** loop - the loop immediately outside the inner-most. ** -** Across multiple iterations of outer loops, the output rows need not be -** sorted. As long as rows are sorted for just the innermost loop, this -** routine can return TRUE. +** When a row does not fit in the sorter (because the sorter already +** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the +** label returned by this function. +** +** If the ORDER BY LIMIT optimization applies, the jump destination should +** be the continuation for the second-inner-most loop. If the ORDER BY +** LIMIT optimization does not apply, then the jump destination should +** be the continuation for the inner-most loop. +** +** It is always safe for this routine to return the continuation of the +** inner-most loop, in the sense that a correct answer will result. +** Returning the continuation the second inner loop is an optimization +** that might make the code run a little faster, but should not change +** the final answer. +*/ +SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){ + WhereLevel *pInner; + if( !pWInfo->bOrderedInnerLoop ){ + /* The ORDER BY LIMIT optimization does not apply. Jump to the + ** continuation of the inner-most loop. */ + return pWInfo->iContinue; + } + pInner = &pWInfo->a[pWInfo->nLevel-1]; + assert( pInner->addrNxt!=0 ); + return pInner->addrNxt; +} + +/* +** While generating code for the min/max optimization, after handling +** the aggregate-step call to min() or max(), check to see if any +** additional looping is required. If the output order is such that +** we are certain that the correct answer has already been found, then +** code an OP_Goto to by pass subsequent processing. +** +** Any extra OP_Goto that is coded here is an optimization. The +** correct answer should be obtained regardless. This OP_Goto just +** makes the answer appear faster. */ -SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){ - return pWInfo->bOrderedInnerLoop; +SQLITE_PRIVATE void sqlite3WhereMinMaxOptEarlyOut(Vdbe *v, WhereInfo *pWInfo){ + WhereLevel *pInner; + int i; + if( !pWInfo->bOrderedInnerLoop ) return; + if( pWInfo->nOBSat==0 ) return; + for(i=pWInfo->nLevel-1; i>=0; i--){ + pInner = &pWInfo->a[i]; + if( (pInner->pWLoop->wsFlags & WHERE_COLUMN_IN)!=0 ){ + sqlite3VdbeGoto(v, pInner->addrNxt); + return; + } + } + sqlite3VdbeGoto(v, pWInfo->iBreak); } /* @@ -129413,10 +152152,10 @@ SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ /* ** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to -** operate directly on the rowis returned by a WHERE clause. Return +** operate directly on the rowids returned by a WHERE clause. Return ** ONEPASS_SINGLE (1) if the statement can operation directly because only ** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass -** optimization can be used on multiple +** optimization can be used on multiple ** ** If the ONEPASS optimization is used (if this routine returns true) ** then also write the indices of open cursors used by ONEPASS @@ -129440,6 +152179,14 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){ return pWInfo->eOnePass; } +/* +** Return TRUE if the WHERE loop uses the OP_DeferredSeek opcode to move +** the data cursor to the row selected by the index cursor. +*/ +SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo *pWInfo){ + return pWInfo->bDeferredSeek; +} + /* ** Move the content of pSrc into pDest */ @@ -129495,7 +152242,12 @@ static int whereOrInsert( SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){ int i; assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 ); - for(i=0; in; i++){ + assert( pMaskSet->n>0 || pMaskSet->ix[0]<0 ); + assert( iCursor>=-1 ); + if( pMaskSet->ix[0]==iCursor ){ + return 1; + } + for(i=1; in; i++){ if( pMaskSet->ix[i]==iCursor ){ return MASKBIT(i); } @@ -129516,6 +152268,18 @@ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ pMaskSet->ix[pMaskSet->n++] = iCursor; } +/* +** If the right-hand branch of the expression is a TK_COLUMN, then return +** a pointer to the right-hand branch. Otherwise, return NULL. +*/ +static Expr *whereRightSubexprIsColumn(Expr *p){ + p = sqlite3ExprSkipCollateAndLikely(p->pRight); + if( ALWAYS(p!=0) && p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ + return p; + } + return 0; +} + /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). @@ -129535,17 +152299,20 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ iColumn = pScan->aiColumn[pScan->iEquiv-1]; iCur = pScan->aiCur[pScan->iEquiv-1]; assert( pWC!=0 ); + assert( iCur>=0 ); do{ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 || pTerm->leftCursor<0 ); if( pTerm->leftCursor==iCur - && pTerm->u.leftColumn==iColumn + && pTerm->u.x.leftColumn==iColumn && (iColumn!=XN_EXPR - || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0) + || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft, + pScan->pIdxExpr,iCur)==0) && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaiCur) - && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN + && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0 ){ int j; for(j=0; jnEquiv; j++){ @@ -129570,15 +152337,15 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ continue; } assert(pX->pLeft); - pColl = sqlite3BinaryCompareCollSeq(pParse, - pX->pLeft, pX->pRight); + pColl = sqlite3ExprCompareCollSeq(pParse, pX); if( pColl==0 ) pColl = pParse->db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } } if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 - && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN + && (pX = pTerm->pExpr->pRight, ALWAYS(pX!=0)) + && pX->op==TK_COLUMN && pX->iTable==pScan->aiCur[0] && pX->iColumn==pScan->aiColumn[0] ){ @@ -129587,6 +152354,18 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ } pScan->pWC = pWC; pScan->k = k+1; +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace & 0x20000 ){ + int ii; + sqlite3DebugPrintf("SCAN-TERM %p: nEquiv=%d", + pTerm, pScan->nEquiv); + for(ii=0; iinEquiv; ii++){ + sqlite3DebugPrintf(" {%d:%d}", + pScan->aiCur[ii], pScan->aiColumn[ii]); + } + sqlite3DebugPrintf("\n"); + } +#endif return pTerm; } } @@ -129602,6 +152381,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ return 0; } +/* +** This is whereScanInit() for the case of an index on an expression. +** It is factored out into a separate tail-recursion subroutine so that +** the normal whereScanInit() routine, which is a high-runner, does not +** need to push registers onto the stack as part of its prologue. +*/ +static SQLITE_NOINLINE WhereTerm *whereScanInitIndexExpr(WhereScan *pScan){ + pScan->idxaff = sqlite3ExprAffinity(pScan->pIdxExpr); + return whereScanNext(pScan); +} + /* ** Initialize a WHERE clause scanner object. Return a pointer to the ** first match. Return NULL if there are no matches. @@ -129634,27 +152424,29 @@ static WhereTerm *whereScanInit( pScan->pIdxExpr = 0; pScan->idxaff = 0; pScan->zCollName = 0; + pScan->opMask = opMask; + pScan->k = 0; + pScan->aiCur[0] = iCur; + pScan->nEquiv = 1; + pScan->iEquiv = 1; if( pIdx ){ int j = iColumn; iColumn = pIdx->aiColumn[j]; - if( iColumn==XN_EXPR ){ - pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; - pScan->zCollName = pIdx->azColl[j]; - }else if( iColumn==pIdx->pTable->iPKey ){ + if( iColumn==pIdx->pTable->iPKey ){ iColumn = XN_ROWID; }else if( iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; pScan->zCollName = pIdx->azColl[j]; + }else if( iColumn==XN_EXPR ){ + pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; + pScan->zCollName = pIdx->azColl[j]; + pScan->aiColumn[0] = XN_EXPR; + return whereScanInitIndexExpr(pScan); } }else if( iColumn==XN_EXPR ){ return 0; } - pScan->opMask = opMask; - pScan->k = 0; - pScan->aiCur[0] = iCur; pScan->aiColumn[0] = iColumn; - pScan->nEquiv = 1; - pScan->iEquiv = 1; return whereScanNext(pScan); } @@ -129664,7 +152456,7 @@ static WhereTerm *whereScanInit( ** if pIdx!=0 and is one of the WO_xx operator codes specified by ** the op parameter. Return a pointer to the term. Return 0 if not found. ** -** If pIdx!=0 then it must be one of the indexes of table iCur. +** If pIdx!=0 then it must be one of the indexes of table iCur. ** Search for terms matching the iColumn-th column of pIdx ** rather than the iColumn-th column of table iCur. ** @@ -129728,13 +152520,14 @@ static int findIndexCol( const char *zColl = pIdx->azColl[iCol]; for(i=0; inExpr; i++){ - Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr); - if( p->op==TK_COLUMN + Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr); + if( ALWAYS(p!=0) + && (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN) && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ - CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr); - if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){ + CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr); + if( 0==sqlite3StrICmp(pColl->zName, zColl) ){ return i; } } @@ -129777,23 +152570,25 @@ static int isDistinctRedundant( ){ Table *pTab; Index *pIdx; - int i; + int i; int iBase; /* If there is more than one table or sub-select in the FROM clause of - ** this query, then it will not be possible to show that the DISTINCT + ** this query, then it will not be possible to show that the DISTINCT ** clause is redundant. */ if( pTabList->nSrc!=1 ) return 0; iBase = pTabList->a[0].iCursor; pTab = pTabList->a[0].pTab; - /* If any of the expressions is an IPK column on table iBase, then return + /* If any of the expressions is an IPK column on table iBase, then return ** true. Note: The (p->iTable==iBase) part of this test may be false if the ** current SELECT is a correlated sub-query. */ for(i=0; inExpr; i++){ - Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr); - if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1; + Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr); + if( NEVER(p==0) ) continue; + if( p->op!=TK_COLUMN && p->op!=TK_AGG_COLUMN ) continue; + if( p->iTable==iBase && p->iColumn<0 ) return 1; } /* Loop through all indices on the table, checking each to see if it makes @@ -129811,6 +152606,7 @@ static int isDistinctRedundant( */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( !IsUniqueIndex(pIdx) ) continue; + if( pIdx->pPartIdxWhere ) continue; for(i=0; inKeyCol; i++){ if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){ if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break; @@ -129838,23 +152634,25 @@ static LogEst estLog(LogEst N){ ** Convert OP_Column opcodes to OP_Copy in previously generated code. ** ** This routine runs over generated VDBE code and translates OP_Column -** opcodes into OP_Copy when the table is being accessed via co-routine +** opcodes into OP_Copy when the table is being accessed via co-routine ** instead of via table lookup. ** -** If the bIncrRowid parameter is 0, then any OP_Rowid instructions on -** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero, -** then each OP_Rowid is transformed into an instruction to increment the -** value stored in its output register. +** If the iAutoidxCur is not zero, then any OP_Rowid instructions on +** cursor iTabCur are transformed into OP_Sequence opcode for the +** iAutoidxCur cursor, in order to generate unique rowids for the +** automatic index being generated. */ static void translateColumnToCopy( - Vdbe *v, /* The VDBE containing code to translate */ + Parse *pParse, /* Parsing context */ int iStart, /* Translate from this opcode to the end */ int iTabCur, /* OP_Column/OP_Rowid references to this table */ int iRegister, /* The first column is in this register */ - int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */ + int iAutoidxCur /* If non-zero, cursor of autoindex being generated */ ){ + Vdbe *v = pParse->pVdbe; VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); int iEnd = sqlite3VdbeCurrentAddr(v); + if( pParse->db->mallocFailed ) return; for(; iStartp1!=iTabCur ) continue; if( pOp->opcode==OP_Column ){ @@ -129863,16 +152661,14 @@ static void translateColumnToCopy( pOp->p2 = pOp->p3; pOp->p3 = 0; }else if( pOp->opcode==OP_Rowid ){ - if( bIncrRowid ){ - /* Increment the value stored in the P2 operand of the OP_Rowid. */ - pOp->opcode = OP_AddImm; - pOp->p1 = pOp->p2; - pOp->p2 = 1; - }else{ + pOp->opcode = OP_Sequence; + pOp->p1 = iAutoidxCur; +#ifdef SQLITE_ALLOW_ROWID_IN_VIEW + if( iAutoidxCur==0 ){ pOp->opcode = OP_Null; - pOp->p1 = 0; pOp->p3 = 0; } +#endif } } } @@ -129884,16 +152680,18 @@ static void translateColumnToCopy( ** are no-ops. */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED) -static void TRACE_IDX_INPUTS(sqlite3_index_info *p){ +static void whereTraceIndexInfoInputs(sqlite3_index_info *p){ int i; if( !sqlite3WhereTrace ) return; for(i=0; inConstraint; i++){ - sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n", + sqlite3DebugPrintf( + " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n", i, p->aConstraint[i].iColumn, p->aConstraint[i].iTermOffset, p->aConstraint[i].op, - p->aConstraint[i].usable); + p->aConstraint[i].usable, + sqlite3_vtab_collation(p,i)); } for(i=0; inOrderBy; i++){ sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n", @@ -129902,7 +152700,7 @@ static void TRACE_IDX_INPUTS(sqlite3_index_info *p){ p->aOrderBy[i].desc); } } -static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){ +static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){ int i; if( !sqlite3WhereTrace ) return; for(i=0; inConstraint; i++){ @@ -129918,8 +152716,8 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){ sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows); } #else -#define TRACE_IDX_INPUTS(A) -#define TRACE_IDX_OUTPUTS(A) +#define whereTraceIndexInfoInputs(A) +#define whereTraceIndexInfoOutputs(A) #endif #ifndef SQLITE_OMIT_AUTOMATIC_INDEX @@ -129929,16 +152727,26 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){ ** index existed. */ static int termCanDriveIndex( - WhereTerm *pTerm, /* WHERE clause term to check */ - struct SrcList_item *pSrc, /* Table we are trying to access */ - Bitmask notReady /* Tables in outer loops of the join */ + const WhereTerm *pTerm, /* WHERE clause term to check */ + const SrcItem *pSrc, /* Table we are trying to access */ + const Bitmask notReady /* Tables in outer loops of the join */ ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; + if( (pSrc->fg.jointype & JT_LEFT) + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (pTerm->eOperator & WO_IS) + ){ + /* Cannot use an IS term from the WHERE clause as an index driver for + ** the RHS of a LEFT JOIN. Such a term can only be used if it is from + ** the ON clause. */ + return 0; + } if( (pTerm->prereqRight & notReady)!=0 ) return 0; - if( pTerm->u.leftColumn<0 ) return 0; - aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + if( pTerm->u.x.leftColumn<0 ) return 0; + aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; testcase( pTerm->pExpr->op==TK_IS ); return 1; @@ -129952,11 +152760,11 @@ static int termCanDriveIndex( ** and to set up the WhereLevel object pLevel so that the code generator ** makes use of the automatic index. */ -static void constructAutomaticIndex( +static SQLITE_NOINLINE void constructAutomaticIndex( Parse *pParse, /* The parsing context */ - WhereClause *pWC, /* The WHERE clause */ - struct SrcList_item *pSrc, /* The FROM clause term to get the next index */ - Bitmask notReady, /* Mask of cursors that are not available */ + const WhereClause *pWC, /* The WHERE clause */ + const SrcItem *pSrc, /* The FROM clause term to get the next index */ + const Bitmask notReady, /* Mask of cursors that are not available */ WhereLevel *pLevel /* Write new index here */ ){ int nKeyCol; /* Number of columns in the constructed index */ @@ -129979,7 +152787,7 @@ static void constructAutomaticIndex( u8 sentWarning = 0; /* True if a warnning has been issued */ Expr *pPartial = 0; /* Partial Index Expression */ int iContinue = 0; /* Jump here to skip excluded rows */ - struct SrcList_item *pTabItem; /* FROM clause term being indexed */ + SrcItem *pTabItem; /* FROM clause term being indexed */ int addrCounter = 0; /* Address where integer counter is initialized */ int regBase; /* Array of registers where record is assembled */ @@ -129998,25 +152806,28 @@ static void constructAutomaticIndex( idxCols = 0; for(pTerm=pWC->a; pTermpExpr; - assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */ - || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */ - || pLoop->prereq!=0 ); /* table of a LEFT JOIN */ - if( pLoop->prereq==0 - && (pTerm->wtFlags & TERM_VIRTUAL)==0 - && !ExprHasProperty(pExpr, EP_FromJoin) - && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ - pPartial = sqlite3ExprAnd(pParse->db, pPartial, + /* Make the automatic index a partial index if there are terms in the + ** WHERE clause (or the ON clause of a LEFT join) that constrain which + ** rows of the target table (pSrc) that can be used. */ + if( (pTerm->wtFlags & TERM_VIRTUAL)==0 + && ((pSrc->fg.jointype&JT_LEFT)==0 || ExprHasProperty(pExpr,EP_FromJoin)) + && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) + ){ + pPartial = sqlite3ExprAnd(pParse, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ - int iCol = pTerm->u.leftColumn; - Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); + int iCol; + Bitmask cMask; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + iCol = pTerm->u.x.leftColumn; + cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); if( !sentWarning ){ sqlite3_log(SQLITE_WARNING_AUTOINDEX, "automatic index on %s(%s)", pTable->zName, - pTable->aCol[iCol].zName); + pTable->aCol[iCol].zCnName); sentWarning = 1; } if( (idxCols & cMask)==0 ){ @@ -130028,7 +152839,7 @@ static void constructAutomaticIndex( } } } - assert( nKeyCol>0 ); + assert( nKeyCol>0 || pParse->db->mallocFailed ); pLoop->u.btree.nEq = pLoop->nLTerm = nKeyCol; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED | WHERE_AUTO_INDEX; @@ -130062,15 +152873,19 @@ static void constructAutomaticIndex( idxCols = 0; for(pTerm=pWC->a; pTermu.leftColumn; - Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); + int iCol; + Bitmask cMask; + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + iCol = pTerm->u.x.leftColumn; + cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS-1 ); testcase( iCol==BMS ); if( (idxCols & cMask)==0 ){ Expr *pX = pTerm->pExpr; idxCols |= cMask; - pIdx->aiColumn[n] = pTerm->u.leftColumn; - pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); + pIdx->aiColumn[n] = pTerm->u.x.leftColumn; + pColl = sqlite3ExprCompareCollSeq(pParse, pX); + assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; n++; } @@ -130104,9 +152919,12 @@ static void constructAutomaticIndex( sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); + if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ + pLevel->regFilter = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter); + } /* Fill the automatic index with content */ - sqlite3ExprCachePush(pParse); pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; @@ -130114,12 +152932,12 @@ static void constructAutomaticIndex( sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } if( pPartial ){ - iContinue = sqlite3VdbeMakeLabel(v); + iContinue = sqlite3VdbeMakeLabel(pParse); sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); pLoop->wsFlags |= WHERE_PARTIALIDX; } @@ -130127,22 +152945,28 @@ static void constructAutomaticIndex( regBase = sqlite3GenerateIndexKey( pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0 ); + if( pLevel->regFilter ){ + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, + regBase, pLoop->u.btree.nEq); + } sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pTabItem->fg.viaCoroutine ){ sqlite3VdbeChangeP2(v, addrCounter, regBase+n); - translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1); + testcase( pParse->db->mallocFailed ); + assert( pLevel->iIdxCur>0 ); + translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, + pTabItem->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pTabItem->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); } - sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); - sqlite3ExprCachePop(pParse); - + /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); @@ -130151,33 +152975,172 @@ static void constructAutomaticIndex( } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ +/* +** Generate bytecode that will initialize a Bloom filter that is appropriate +** for pLevel. +** +** If there are inner loops within pLevel that have the WHERE_BLOOMFILTER +** flag set, initialize a Bloomfilter for them as well. Except don't do +** this recursive initialization if the SQLITE_BloomPulldown optimization has +** been turned off. +** +** When the Bloom filter is initialized, the WHERE_BLOOMFILTER flag is cleared +** from the loop, but the regFilter value is set to a register that implements +** the Bloom filter. When regFilter is positive, the +** sqlite3WhereCodeOneLoopStart() will generate code to test the Bloom filter +** and skip the subsequence B-Tree seek if the Bloom filter indicates that +** no matching rows exist. +** +** This routine may only be called if it has previously been determined that +** the loop would benefit from a Bloom filter, and the WHERE_BLOOMFILTER bit +** is set. +*/ +static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( + WhereInfo *pWInfo, /* The WHERE clause */ + int iLevel, /* Index in pWInfo->a[] that is pLevel */ + WhereLevel *pLevel, /* Make a Bloom filter for this FROM term */ + Bitmask notReady /* Loops that are not ready */ +){ + int addrOnce; /* Address of opening OP_Once */ + int addrTop; /* Address of OP_Rewind */ + int addrCont; /* Jump here to skip a row */ + const WhereTerm *pTerm; /* For looping over WHERE clause terms */ + const WhereTerm *pWCEnd; /* Last WHERE clause term */ + Parse *pParse = pWInfo->pParse; /* Parsing context */ + Vdbe *v = pParse->pVdbe; /* VDBE under construction */ + WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */ + int iCur; /* Cursor for table getting the filter */ + + assert( pLoop!=0 ); + assert( v!=0 ); + assert( pLoop->wsFlags & WHERE_BLOOMFILTER ); + + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + do{ + const SrcItem *pItem; + const Table *pTab; + u64 sz; + sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel); + addrCont = sqlite3VdbeMakeLabel(pParse); + iCur = pLevel->iTabCur; + pLevel->regFilter = ++pParse->nMem; + + /* The Bloom filter is a Blob held in a register. Initialize it + ** to zero-filled blob of at least 80K bits, but maybe more if the + ** estimated size of the table is larger. We could actually + ** measure the size of the table at run-time using OP_Count with + ** P3==1 and use that value to initialize the blob. But that makes + ** testing complicated. By basing the blob size on the value in the + ** sqlite_stat1 table, testing is much easier. + */ + pItem = &pWInfo->pTabList->a[pLevel->iFrom]; + assert( pItem!=0 ); + pTab = pItem->pTab; + assert( pTab!=0 ); + sz = sqlite3LogEstToInt(pTab->nRowLogEst); + if( sz<10000 ){ + sz = 10000; + }else if( sz>10000000 ){ + sz = 10000000; + } + sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter); + + addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); + pWCEnd = &pWInfo->sWC.a[pWInfo->sWC.nTerm]; + for(pTerm=pWInfo->sWC.a; pTermpExpr; + if( (pTerm->wtFlags & TERM_VIRTUAL)==0 + && sqlite3ExprIsTableConstant(pExpr, iCur) + ){ + sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); + } + } + if( pLoop->wsFlags & WHERE_IPK ){ + int r1 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1); + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, 1); + sqlite3ReleaseTempReg(pParse, r1); + }else{ + Index *pIdx = pLoop->u.btree.pIndex; + int n = pLoop->u.btree.nEq; + int r1 = sqlite3GetTempRange(pParse, n); + int jj; + for(jj=0; jjaiColumn[jj]; + assert( pIdx->pTable==pItem->pTab ); + sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj); + } + sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); + sqlite3ReleaseTempRange(pParse, r1, n); + } + sqlite3VdbeResolveLabel(v, addrCont); + sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrTop); + pLoop->wsFlags &= ~WHERE_BLOOMFILTER; + if( OptimizationDisabled(pParse->db, SQLITE_BloomPulldown) ) break; + while( ++iLevel < pWInfo->nLevel ){ + const SrcItem *pTabItem; + pLevel = &pWInfo->a[iLevel]; + pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; + if( pTabItem->fg.jointype & JT_LEFT ) continue; + pLoop = pLevel->pWLoop; + if( NEVER(pLoop==0) ) continue; + if( pLoop->prereq & notReady ) continue; + if( (pLoop->wsFlags & (WHERE_BLOOMFILTER|WHERE_COLUMN_IN)) + ==WHERE_BLOOMFILTER + ){ + /* This is a candidate for bloom-filter pull-down (early evaluation). + ** The test that WHERE_COLUMN_IN is omitted is important, as we are + ** not able to do early evaluation of bloom filters that make use of + ** the IN operator */ + break; + } + } + }while( iLevel < pWInfo->nLevel ); + sqlite3VdbeJumpHere(v, addrOnce); +} + + #ifndef SQLITE_OMIT_VIRTUALTABLE /* -** Allocate and populate an sqlite3_index_info structure. It is the +** Allocate and populate an sqlite3_index_info structure. It is the ** responsibility of the caller to eventually release the structure -** by passing the pointer returned by this function to sqlite3_free(). +** by passing the pointer returned by this function to freeIndexInfo(). */ static sqlite3_index_info *allocateIndexInfo( - Parse *pParse, - WhereClause *pWC, + WhereInfo *pWInfo, /* The WHERE clause */ + WhereClause *pWC, /* The WHERE clause being analyzed */ Bitmask mUnusable, /* Ignore terms with these prereqs */ - struct SrcList_item *pSrc, - ExprList *pOrderBy, + SrcItem *pSrc, /* The FROM clause term that is the vtab */ u16 *pmNoOmit /* Mask of terms not to omit */ ){ int i, j; int nTerm; + Parse *pParse = pWInfo->pParse; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; struct sqlite3_index_constraint_usage *pUsage; + struct HiddenIndexInfo *pHidden; WhereTerm *pTerm; int nOrderBy; sqlite3_index_info *pIdxInfo; u16 mNoOmit = 0; + const Table *pTab; + int eDistinct = 0; + ExprList *pOrderBy = pWInfo->pOrderBy; + + assert( pSrc!=0 ); + pTab = pSrc->pTab; + assert( pTab!=0 ); + assert( IsVirtual(pTab) ); - /* Count the number of possible WHERE clause constraints referring - ** to this virtual table */ + /* Find all WHERE clause constraints referring to this virtual table. + ** Mark each term with the TERM_OK flag. Set nTerm to the number of + ** terms found. + */ for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){ + pTerm->wtFlags &= ~TERM_OK; if( pTerm->leftCursor != pSrc->iCursor ) continue; if( pTerm->prereqRight & mUnusable ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); @@ -130185,13 +153148,26 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ALL ); - if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; + if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; - assert( pTerm->u.leftColumn>=(-1) ); + + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); + assert( pTerm->u.x.leftColumn>=XN_ROWID ); + assert( pTerm->u.x.leftColumnnCol ); + + /* tag-20191211-002: WHERE-clause constraints are not useful to the + ** right-hand table of a LEFT JOIN. See tag-20191211-001 for the + ** equivalent restriction for ordinary tables. */ + if( (pSrc->fg.jointype & JT_LEFT)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + ){ + continue; + } nTerm++; + pTerm->wtFlags |= TERM_OK; } - /* If the ORDER BY clause contains only columns in the current + /* If the ORDER BY clause contains only columns in the current ** virtual table then allocate space for the aOrderBy part of ** the sqlite3_index_info structure. */ @@ -130200,10 +153176,47 @@ static sqlite3_index_info *allocateIndexInfo( int n = pOrderBy->nExpr; for(i=0; ia[i].pExpr; - if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break; + Expr *pE2; + + /* Skip over constant terms in the ORDER BY clause */ + if( sqlite3ExprIsConstant(pExpr) ){ + continue; + } + + /* Virtual tables are unable to deal with NULLS FIRST */ + if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break; + + /* First case - a direct column references without a COLLATE operator */ + if( pExpr->op==TK_COLUMN && pExpr->iTable==pSrc->iCursor ){ + assert( pExpr->iColumn>=XN_ROWID && pExpr->iColumnnCol ); + continue; + } + + /* 2nd case - a column reference with a COLLATE operator. Only match + ** of the COLLATE operator matches the collation of the column. */ + if( pExpr->op==TK_COLLATE + && (pE2 = pExpr->pLeft)->op==TK_COLUMN + && pE2->iTable==pSrc->iCursor + ){ + const char *zColl; /* The collating sequence name */ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + assert( pExpr->u.zToken!=0 ); + assert( pE2->iColumn>=XN_ROWID && pE2->iColumnnCol ); + pExpr->iColumn = pE2->iColumn; + if( pE2->iColumn<0 ) continue; /* Collseq does not matter for rowid */ + zColl = sqlite3ColumnColl(&pTab->aCol[pE2->iColumn]); + if( zColl==0 ) zColl = sqlite3StrBINARY; + if( sqlite3_stricmp(pExpr->u.zToken, zColl)==0 ) continue; + } + + /* No matches cause a break out of the loop */ + break; } - if( i==n){ + if( i==n ){ nOrderBy = n; + if( (pWInfo->wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY)) ){ + eDistinct = 1 + ((pWInfo->wctrlFlags & WHERE_DISTINCTBY)!=0); + } } } @@ -130211,87 +153224,114 @@ static sqlite3_index_info *allocateIndexInfo( */ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm - + sizeof(*pIdxOrderBy)*nOrderBy ); + + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) + + sizeof(sqlite3_value*)*nTerm ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; } - - /* Initialize the structure. The sqlite3_index_info structure contains - ** many fields that are declared "const" to prevent xBestIndex from - ** changing them. We have to do some funky casting in order to - ** initialize those fields. - */ - pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1]; + pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1]; + pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm]; pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm]; pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy]; - *(int*)&pIdxInfo->nConstraint = nTerm; - *(int*)&pIdxInfo->nOrderBy = nOrderBy; - *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons; - *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; - *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage = - pUsage; - + pIdxInfo->aConstraint = pIdxCons; + pIdxInfo->aOrderBy = pIdxOrderBy; + pIdxInfo->aConstraintUsage = pUsage; + pHidden->pWC = pWC; + pHidden->pParse = pParse; + pHidden->eDistinct = eDistinct; + pHidden->mIn = 0; for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ - u8 op; - if( pTerm->leftCursor != pSrc->iCursor ) continue; - if( pTerm->prereqRight & mUnusable ) continue; - assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); - testcase( pTerm->eOperator & WO_IN ); - testcase( pTerm->eOperator & WO_IS ); - testcase( pTerm->eOperator & WO_ISNULL ); - testcase( pTerm->eOperator & WO_ALL ); - if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; - if( pTerm->wtFlags & TERM_VNULL ) continue; - assert( pTerm->u.leftColumn>=(-1) ); - pIdxCons[j].iColumn = pTerm->u.leftColumn; + u16 op; + if( (pTerm->wtFlags & TERM_OK)==0 ) continue; + pIdxCons[j].iColumn = pTerm->u.x.leftColumn; pIdxCons[j].iTermOffset = i; - op = (u8)pTerm->eOperator & WO_ALL; - if( op==WO_IN ) op = WO_EQ; - if( op==WO_MATCH ){ - op = pTerm->eMatchOp; - } - pIdxCons[j].op = op; - /* The direct assignment in the previous line is possible only because - ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The - ** following asserts verify this fact. */ - assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); - assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); - assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); - assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); - assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); - assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); - assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); - - if( op & (WO_LT|WO_LE|WO_GT|WO_GE) - && sqlite3ExprIsVector(pTerm->pExpr->pRight) - ){ - if( i<16 ) mNoOmit |= (1 << i); - if( op==WO_LT ) pIdxCons[j].op = WO_LE; - if( op==WO_GT ) pIdxCons[j].op = WO_GE; + op = pTerm->eOperator & WO_ALL; + if( op==WO_IN ){ + if( (pTerm->wtFlags & TERM_SLICE)==0 ){ + pHidden->mIn |= SMASKBIT32(j); + } + op = WO_EQ; + } + if( op==WO_AUX ){ + pIdxCons[j].op = pTerm->eMatchOp; + }else if( op & (WO_ISNULL|WO_IS) ){ + if( op==WO_ISNULL ){ + pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL; + }else{ + pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS; + } + }else{ + pIdxCons[j].op = (u8)op; + /* The direct assignment in the previous line is possible only because + ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The + ** following asserts verify this fact. */ + assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); + assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); + assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); + assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); + assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); + assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) ); + + if( op & (WO_LT|WO_LE|WO_GT|WO_GE) + && sqlite3ExprIsVector(pTerm->pExpr->pRight) + ){ + testcase( j!=i ); + if( j<16 ) mNoOmit |= (1 << j); + if( op==WO_LT ) pIdxCons[j].op = WO_LE; + if( op==WO_GT ) pIdxCons[j].op = WO_GE; + } } j++; } - for(i=0; inConstraint = j; + for(i=j=0; ia[i].pExpr; - pIdxOrderBy[i].iColumn = pExpr->iColumn; - pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder; + if( sqlite3ExprIsConstant(pExpr) ) continue; + assert( pExpr->op==TK_COLUMN + || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN + && pExpr->iColumn==pExpr->pLeft->iColumn) ); + pIdxOrderBy[j].iColumn = pExpr->iColumn; + pIdxOrderBy[j].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC; + j++; } + pIdxInfo->nOrderBy = j; *pmNoOmit = mNoOmit; return pIdxInfo; } +/* +** Free an sqlite3_index_info structure allocated by allocateIndexInfo() +** and possibly modified by xBestIndex methods. +*/ +static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden; + int i; + assert( pIdxInfo!=0 ); + pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + assert( pHidden->pParse!=0 ); + assert( pHidden->pParse->db==db ); + for(i=0; inConstraint; i++){ + sqlite3ValueFree(pHidden->aRhs[i]); /* IMP: R-14553-25174 */ + pHidden->aRhs[i] = 0; + } + sqlite3DbFree(db, pIdxInfo); +} + /* ** The table object reference passed as the second argument to this function ** must represent a virtual table. This function invokes the xBestIndex() ** method of the virtual table with the sqlite3_index_info object that ** comes in as the 3rd argument to this function. ** -** If an error occurs, pParse is populated with an error message and a -** non-zero value is returned. Otherwise, 0 is returned and the output -** part of the sqlite3_index_info structure is left populated. +** If an error occurs, pParse is populated with an error message and an +** appropriate error code is returned. A return of SQLITE_CONSTRAINT from +** xBestIndex is not considered an error. SQLITE_CONSTRAINT indicates that +** the current configuration of "unusable" flags in sqlite3_index_info can +** not result in a valid plan. ** ** Whether or not an error is returned, it is the responsibility of the ** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates @@ -130301,11 +153341,13 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab; int rc; - TRACE_IDX_INPUTS(p); + whereTraceIndexInfoInputs(p); + pParse->db->nSchemaLock++; rc = pVtab->pModule->xBestIndex(pVtab, p); - TRACE_IDX_OUTPUTS(p); + pParse->db->nSchemaLock--; + whereTraceIndexInfoOutputs(p); - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(pParse->db); }else if( !pVtab->zErrMsg ){ @@ -130316,23 +153358,11 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ } sqlite3_free(pVtab->zErrMsg); pVtab->zErrMsg = 0; - -#if 0 - /* This error is now caught by the caller. - ** Search for "xBestIndex malfunction" below */ - for(i=0; inConstraint; i++){ - if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){ - sqlite3ErrorMsg(pParse, - "table %s: xBestIndex returned an invalid plan", pTab->zName); - } - } -#endif - - return pParse->nErr; + return rc; } #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the location of a particular key among all keys in an ** index. Store the results in aStat as follows: @@ -130343,8 +153373,8 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){ ** Return the index of the sample that is the smallest sample that ** is greater than or equal to pRec. Note that this index is not an index ** into the aSample[] array - it is an index into a virtual set of samples -** based on the contents of aSample[] and the number of fields in record -** pRec. +** based on the contents of aSample[] and the number of fields in record +** pRec. */ static int whereKeyStats( Parse *pParse, /* Database connection */ @@ -130380,38 +153410,38 @@ static int whereKeyStats( ** consider prefixes of those samples. For example, if the set of samples ** in aSample is: ** - ** aSample[0] = (a, 5) - ** aSample[1] = (a, 10) - ** aSample[2] = (b, 5) - ** aSample[3] = (c, 100) + ** aSample[0] = (a, 5) + ** aSample[1] = (a, 10) + ** aSample[2] = (b, 5) + ** aSample[3] = (c, 100) ** aSample[4] = (c, 105) ** - ** Then the search space should ideally be the samples above and the - ** unique prefixes [a], [b] and [c]. But since that is hard to organize, + ** Then the search space should ideally be the samples above and the + ** unique prefixes [a], [b] and [c]. But since that is hard to organize, ** the code actually searches this set: ** - ** 0: (a) - ** 1: (a, 5) - ** 2: (a, 10) - ** 3: (a, 10) - ** 4: (b) - ** 5: (b, 5) - ** 6: (c) - ** 7: (c, 100) + ** 0: (a) + ** 1: (a, 5) + ** 2: (a, 10) + ** 3: (a, 10) + ** 4: (b) + ** 5: (b, 5) + ** 6: (c) + ** 7: (c, 100) ** 8: (c, 105) ** 9: (c, 105) ** ** For each sample in the aSample[] array, N samples are present in the - ** effective sample array. In the above, samples 0 and 1 are based on + ** effective sample array. In the above, samples 0 and 1 are based on ** sample aSample[0]. Samples 2 and 3 on aSample[1] etc. ** ** Often, sample i of each block of N effective samples has (i+1) fields. ** Except, each sample may be extended to ensure that it is greater than or - ** equal to the previous sample in the array. For example, in the above, - ** sample 2 is the first sample of a block of N samples, so at first it - ** appears that it should be 1 field in size. However, that would make it - ** smaller than sample 1, so the binary search would not work. As a result, - ** it is extended to two fields. The duplicates that this creates do not + ** equal to the previous sample in the array. For example, in the above, + ** sample 2 is the first sample of a block of N samples, so at first it + ** appears that it should be 1 field in size. However, that would make it + ** smaller than sample 1, so the binary search would not work. As a result, + ** it is extended to two fields. The duplicates that this creates do not ** cause any problems. */ nField = pRec->nField; @@ -130425,7 +153455,7 @@ static int whereKeyStats( iSamp = iTest / nField; if( iSamp>0 ){ /* The proposed effective sample is a prefix of sample aSample[iSamp]. - ** Specifically, the shortest prefix of at least (1 + iTest%nField) + ** Specifically, the shortest prefix of at least (1 + iTest%nField) ** fields that is greater than the previous effective sample. */ for(n=(iTest % nField) + 1; nnSample ); assert( iCol==nField-1 ); pRec->nField = nField; - assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) - || pParse->db->mallocFailed + assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec) + || pParse->db->mallocFailed ); }else{ /* Unless i==pIdx->nSample, indicating that pRec is larger than @@ -130469,7 +153499,7 @@ static int whereKeyStats( ** (iCol+1) field prefix of sample i. */ assert( i<=pIdx->nSample && i>=0 ); pRec->nField = iCol+1; - assert( i==pIdx->nSample + assert( i==pIdx->nSample || sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0 || pParse->db->mallocFailed ); @@ -130497,7 +153527,7 @@ static int whereKeyStats( aStat[0] = aSample[i].anLt[iCol]; aStat[1] = aSample[i].anEq[iCol]; }else{ - /* At this point, the (iCol+1) field prefix of aSample[i] is the first + /* At this point, the (iCol+1) field prefix of aSample[i] is the first ** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec ** is larger than all samples in the array. */ tRowcnt iUpper, iGap; @@ -130518,18 +153548,18 @@ static int whereKeyStats( iGap = iGap/3; } aStat[0] = iLower + iGap; - aStat[1] = pIdx->aAvgEq[iCol]; + aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ pRec->nField = nField; return i; } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ /* ** If it is not NULL, pTerm is a term that provides an upper or lower -** bound on a range scan. Without considering pTerm, it is estimated +** bound on a range scan. Without considering pTerm, it is estimated ** that the scan will visit nNew rows. This function returns the number ** estimated to be visited after taking pTerm into account. ** @@ -130551,7 +153581,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 /* ** Return the affinity for a single column of an index. */ @@ -130560,24 +153590,25 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; } + assert( pIdx->zColAff[iCol]!=0 ); return pIdx->zColAff[iCol]; } #endif -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 -/* +#ifdef SQLITE_ENABLE_STAT4 +/* ** This function is called to estimate the number of rows visited by a ** range-scan on a skip-scan index. For example: ** ** CREATE INDEX i1 ON t1(a, b, c); ** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?; ** -** Value pLoop->nOut is currently set to the estimated number of rows -** visited for scanning (a=? AND b=?). This function reduces that estimate +** Value pLoop->nOut is currently set to the estimated number of rows +** visited for scanning (a=? AND b=?). This function reduces that estimate ** by some factor to account for the (c BETWEEN ? AND ?) expression based -** on the stat4 data for the index. this scan will be peformed multiple -** times (once for each (a,b) combination that matches a=?) is dealt with +** on the stat4 data for the index. this scan will be peformed multiple +** times (once for each (a,b) combination that matches a=?) is dealt with ** by the caller. ** ** It does this by scanning through all stat4 samples, comparing values @@ -130598,7 +153629,7 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo ** estimate of the number of rows delivered remains unchanged), *pbDone ** is left as is. ** -** If an error occurs, an SQLite error code is returned. Otherwise, +** If an error occurs, an SQLite error code is returned. Otherwise, ** SQLITE_OK. */ static int whereRangeSkipScanEst( @@ -130616,7 +153647,7 @@ static int whereRangeSkipScanEst( int rc = SQLITE_OK; u8 aff = sqlite3IndexColumnAffinity(db, p, nEq); CollSeq *pColl; - + sqlite3_value *p1 = 0; /* Value extracted from pLower */ sqlite3_value *p2 = 0; /* Value extracted from pUpper */ sqlite3_value *pVal = 0; /* Value extracted from record */ @@ -130648,7 +153679,7 @@ static int whereRangeSkipScanEst( nDiff = (nUpper - nLower); if( nDiff<=0 ) nDiff = 1; - /* If there is both an upper and lower bound specified, and the + /* If there is both an upper and lower bound specified, and the ** comparisons indicate that they are close together, use the fallback ** method (assume that the scan visits 1/64 of the rows) for estimating ** the number of rows visited. Otherwise, estimate the number of rows @@ -130671,7 +153702,7 @@ static int whereRangeSkipScanEst( return rc; } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ /* ** This function is used to estimate the number of rows that will be visited @@ -130695,7 +153726,7 @@ static int whereRangeSkipScanEst( ** ** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ... ** -** then nEq is set to 1 (as the range restricted column, b, is the second +** then nEq is set to 1 (as the range restricted column, b, is the second ** left-most column of the index). Or, if the query is: ** ** ... FROM t1 WHERE a > ? AND a < ? ... @@ -130703,13 +153734,13 @@ static int whereRangeSkipScanEst( ** then nEq is set to 0. ** ** When this function is called, *pnOut is set to the sqlite3LogEst() of the -** number of rows that the index scan is expected to visit without -** considering the range constraints. If nEq is 0, then *pnOut is the number of +** number of rows that the index scan is expected to visit without +** considering the range constraints. If nEq is 0, then *pnOut is the number of ** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced) ** to account for the range constraints pLower and pUpper. -** +** ** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be -** used, a single range inequality reduces the search space by a factor of 4. +** used, a single range inequality reduces the search space by a factor of 4. ** and a pair of constraints (x>? AND xnOut; LogEst nNew; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; - if( p->nSample>0 && nEqnSampleCol ){ + if( p->nSample>0 && ALWAYS(nEqnSampleCol) + && OptimizationEnabled(pParse->db, SQLITE_Stat4) + ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; int nBtm = pLoop->u.btree.nBtm; int nTop = pLoop->u.btree.nTop; - /* Variable iLower will be set to the estimate of the number of rows in + /* Variable iLower will be set to the estimate of the number of rows in ** the index that are less than the lower bound of the range query. The ** lower bound being the concatenation of $P and $L, where $P is the ** key-prefix formed by the nEq values matched against the nEq left-most @@ -130744,7 +153777,7 @@ static int whereRangeScanEst( ** Or, if pLower is NULL or $L cannot be extracted from it (because it ** is not a simple variable or literal value), the lower bound of the ** range is $P. Due to a quirk in the way whereKeyStats() works, even - ** if $L is available, whereKeyStats() is called for both ($P) and + ** if $L is available, whereKeyStats() is called for both ($P) and ** ($P:$L) and the larger of the two returned values is used. ** ** Similarly, iUpper is to be set to the estimate of the number of rows @@ -130768,7 +153801,7 @@ static int whereRangeScanEst( iLower = 0; iUpper = p->nRowEst0; }else{ - /* Note: this call could be optimized away - since the same values must + /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ whereKeyStats(pParse, p, pRec, 0, a); iLower = a[0]; @@ -130825,7 +153858,7 @@ static int whereRangeScanEst( /* TUNING: If both iUpper and iLower are derived from the same ** sample, then assume they are 4x more selective. This brings ** the estimated selectivity more in line with what it would be - ** if estimated without the use of STAT3/4 tables. */ + ** if estimated without the use of STAT4 tables. */ if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); @@ -130856,7 +153889,7 @@ static int whereRangeScanEst( ** reduced by an additional 75%. This means that, by default, an open-ended ** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the ** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to - ** match 1/64 of the index. */ + ** match 1/64 of the index. */ if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){ nNew -= 20; } @@ -130874,16 +153907,16 @@ static int whereRangeScanEst( return rc; } -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the number of rows that will be returned based on ** an equality constraint x=VALUE and where that VALUE occurs in ** the histogram data. This only works when x is the left-most -** column of an index and sqlite_stat3 histogram data is available +** column of an index and sqlite_stat4 histogram data is available ** for that index. When pExpr==NULL that means the constraint is ** "x IS NULL" instead of "x=VALUE". ** -** Write the estimated row count into *pnRow and return SQLITE_OK. +** Write the estimated row count into *pnRow and return SQLITE_OK. ** If unable to make an estimate, leave *pnRow unchanged and return ** non-zero. ** @@ -130934,12 +153967,12 @@ static int whereEqualScanEst( WHERETRACE(0x10,("equality scan regions %s(%d): %d\n", p->zName, nEq-1, (int)a[1])); *pnRow = a[1]; - + return rc; } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 /* ** Estimate the number of rows that will be returned based on ** an IN constraint where the right-hand side of the IN operator @@ -130947,7 +153980,7 @@ static int whereEqualScanEst( ** ** WHERE x IN (1,2,3,4) ** -** Write the estimated row count into *pnRow and return SQLITE_OK. +** Write the estimated row count into *pnRow and return SQLITE_OK. ** If unable to make an estimate, leave *pnRow unchanged and return ** non-zero. ** @@ -130986,41 +154019,50 @@ static int whereInScanEst( assert( pBuilder->nRecValid==nRecValid ); return rc; } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ +#endif /* SQLITE_ENABLE_STAT4 */ #ifdef WHERETRACE_ENABLED /* ** Print the content of a WhereTerm object */ -static void whereTermPrint(WhereTerm *pTerm, int iTerm){ +SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ - char zType[4]; + char zType[8]; char zLeft[50]; - memcpy(zType, "...", 4); + memcpy(zType, "....", 5); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C'; if( pTerm->eOperator & WO_SINGLE ){ + assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", - pTerm->leftCursor, pTerm->u.leftColumn); + pTerm->leftCursor, pTerm->u.x.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ - sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", + sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%llx", pTerm->u.pOrInfo->indexable); }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); } sqlite3DebugPrintf( - "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x", - iTerm, pTerm, zType, zLeft, pTerm->truthProb, - pTerm->eOperator, pTerm->wtFlags); - if( pTerm->iField ){ - sqlite3DebugPrintf(" iField=%d\n", pTerm->iField); - }else{ - sqlite3DebugPrintf("\n"); + "TERM-%-3d %p %s %-12s op=%03x wtFlags=%04x", + iTerm, pTerm, zType, zLeft, pTerm->eOperator, pTerm->wtFlags); + /* The 0x10000 .wheretrace flag causes extra information to be + ** shown about each Term */ + if( sqlite3WhereTrace & 0x10000 ){ + sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx", + pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight); + } + if( (pTerm->eOperator & (WO_OR|WO_AND))==0 && pTerm->u.x.iField ){ + sqlite3DebugPrintf(" iField=%d", pTerm->u.x.iField); + } + if( pTerm->iParent>=0 ){ + sqlite3DebugPrintf(" iParent=%d", pTerm->iParent); } + sqlite3DebugPrintf("\n"); sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } @@ -131033,7 +154075,7 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ int i; for(i=0; inTerm; i++){ - whereTermPrint(&pWC->a[i], i); + sqlite3WhereTermPrint(&pWC->a[i], i); } } #endif @@ -131042,10 +154084,10 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ /* ** Print a WhereLoop object for debugging purposes */ -static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ +SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){ WhereInfo *pWInfo = pWC->pWInfo; int nb = 1+(pWInfo->pTabList->nSrc+3)/4; - struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab; + SrcItem *pItem = pWInfo->pTabList->a + p->iTab; Table *pTab = pItem->pTab; Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, @@ -131067,7 +154109,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ }else{ char *z; if( p->u.vtab.idxStr ){ - z = sqlite3_mprintf("(%d,\"%s\",%x)", + z = sqlite3_mprintf("(%d,\"%s\",%#x)", p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask); }else{ z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask); @@ -131076,15 +154118,15 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ sqlite3_free(z); } if( p->wsFlags & WHERE_SKIPSCAN ){ - sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); + sqlite3DebugPrintf(" f %06x %d-%d", p->wsFlags, p->nLTerm,p->nSkip); }else{ - sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm); + sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm); } sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut); if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){ int i; for(i=0; inLTerm; i++){ - whereTermPrint(p->aLTerm[i], i); + sqlite3WhereTermPrint(p->aLTerm[i], i); } } } @@ -131112,7 +154154,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ p->u.vtab.idxStr = 0; }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); - sqlite3DbFree(db, p->u.btree.pIndex); + sqlite3DbFreeNN(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } } @@ -131122,7 +154164,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ ** Deallocate internal memory used by a WhereLoop object */ static void whereLoopClear(sqlite3 *db, WhereLoop *p){ - if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); whereLoopClearUnion(db, p); whereLoopInit(p); } @@ -131137,7 +154179,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n); if( paNew==0 ) return SQLITE_NOMEM_BKPT; memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot); - if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm); + if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); p->aLTerm = paNew; p->nLSlot = n; return SQLITE_OK; @@ -131149,7 +154191,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ whereLoopClearUnion(db, pTo); if( whereLoopResize(db, pTo, pFrom->nLTerm) ){ - memset(&pTo->u, 0, sizeof(pTo->u)); + memset(pTo, 0, WHERE_LOOP_XFER_SZ); return SQLITE_NOMEM_BKPT; } memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); @@ -131167,47 +154209,61 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ */ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ whereLoopClear(db, p); - sqlite3DbFree(db, p); + sqlite3DbFreeNN(db, p); } /* ** Free a WhereInfo structure */ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ - if( ALWAYS(pWInfo) ){ - int i; - for(i=0; inLevel; i++){ - WhereLevel *pLevel = &pWInfo->a[i]; - if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){ - sqlite3DbFree(db, pLevel->u.in.aInLoop); - } - } - sqlite3WhereClauseClear(&pWInfo->sWC); - while( pWInfo->pLoops ){ - WhereLoop *p = pWInfo->pLoops; - pWInfo->pLoops = p->pNextLoop; - whereLoopDelete(db, p); + int i; + assert( pWInfo!=0 ); + for(i=0; inLevel; i++){ + WhereLevel *pLevel = &pWInfo->a[i]; + if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE)!=0 ){ + assert( (pLevel->pWLoop->wsFlags & WHERE_MULTI_OR)==0 ); + sqlite3DbFree(db, pLevel->u.in.aInLoop); } - sqlite3DbFree(db, pWInfo); + } + sqlite3WhereClauseClear(&pWInfo->sWC); + while( pWInfo->pLoops ){ + WhereLoop *p = pWInfo->pLoops; + pWInfo->pLoops = p->pNextLoop; + whereLoopDelete(db, p); + } + assert( pWInfo->pExprMods==0 ); + sqlite3DbFreeNN(db, pWInfo); +} + +/* Undo all Expr node modifications +*/ +static void whereUndoExprMods(WhereInfo *pWInfo){ + while( pWInfo->pExprMods ){ + WhereExprMod *p = pWInfo->pExprMods; + pWInfo->pExprMods = p->pNext; + memcpy(p->pExpr, &p->orig, sizeof(p->orig)); + sqlite3DbFree(pWInfo->pParse->db, p); } } /* ** Return TRUE if all of the following are true: ** -** (1) X has the same or lower cost that Y -** (2) X is a proper subset of Y -** (3) X skips at least as many columns as Y -** -** By "proper subset" we mean that X uses fewer WHERE clause terms -** than Y and that every WHERE clause term used by X is also used -** by Y. +** (1) X has the same or lower cost, or returns the same or fewer rows, +** than Y. +** (2) X uses fewer WHERE clause terms than Y +** (3) Every WHERE clause term used by X is also used by Y +** (4) X skips at least as many columns as Y +** (5) If X is a covering index, than Y is too ** +** Conditions (2) and (3) mean that X is a "proper subset" of Y. ** If X is a proper subset of Y then Y is a better choice and ought -** to have a lower cost. This routine returns TRUE when that cost -** relationship is inverted and needs to be adjusted. The third rule +** to have a lower cost. This routine returns TRUE when that cost +** relationship is inverted and needs to be adjusted. Constraint (4) ** was added because if X uses skip-scan less than Y it still might -** deserve a lower cost even if it is a proper subset of Y. +** deserve a lower cost even if it is a proper subset of Y. Constraint (5) +** was added because a covering index probably deserves to have a lower cost +** than a non-covering index even if it is a proper subset. */ static int whereLoopCheaperProperSubset( const WhereLoop *pX, /* First WhereLoop to compare */ @@ -131217,11 +154273,8 @@ static int whereLoopCheaperProperSubset( if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){ return 0; /* X is not a subset of Y */ } + if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; if( pY->nSkip > pX->nSkip ) return 0; - if( pX->rRun >= pY->rRun ){ - if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ - if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ - } for(i=pX->nLTerm-1; i>=0; i--){ if( pX->aLTerm[i]==0 ) continue; for(j=pY->nLTerm-1; j>=0; j--){ @@ -131229,12 +154282,16 @@ static int whereLoopCheaperProperSubset( } if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */ } + if( (pX->wsFlags&WHERE_IDX_ONLY)!=0 + && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){ + return 0; /* Constraint (5) */ + } return 1; /* All conditions meet */ } /* -** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so -** that: +** Try to adjust the cost and number of output rows of WhereLoop pTemplate +** upwards or downwards so that: ** ** (1) pTemplate costs less than any other WhereLoops that are a proper ** subset of pTemplate @@ -131252,35 +154309,40 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){ if( p->iTab!=pTemplate->iTab ) continue; if( (p->wsFlags & WHERE_INDEXED)==0 ) continue; if( whereLoopCheaperProperSubset(p, pTemplate) ){ - /* Adjust pTemplate cost downward so that it is cheaper than its + /* Adjust pTemplate cost downward so that it is cheaper than its ** subset p. */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", - pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1)); - pTemplate->rRun = p->rRun; - pTemplate->nOut = p->nOut - 1; + pTemplate->rRun, pTemplate->nOut, + MIN(p->rRun, pTemplate->rRun), + MIN(p->nOut - 1, pTemplate->nOut))); + pTemplate->rRun = MIN(p->rRun, pTemplate->rRun); + pTemplate->nOut = MIN(p->nOut - 1, pTemplate->nOut); }else if( whereLoopCheaperProperSubset(pTemplate, p) ){ /* Adjust pTemplate cost upward so that it is costlier than p since ** pTemplate is a proper subset of p */ WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n", - pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1)); - pTemplate->rRun = p->rRun; - pTemplate->nOut = p->nOut + 1; + pTemplate->rRun, pTemplate->nOut, + MAX(p->rRun, pTemplate->rRun), + MAX(p->nOut + 1, pTemplate->nOut))); + pTemplate->rRun = MAX(p->rRun, pTemplate->rRun); + pTemplate->nOut = MAX(p->nOut + 1, pTemplate->nOut); } } } /* ** Search the list of WhereLoops in *ppPrev looking for one that can be -** supplanted by pTemplate. +** replaced by pTemplate. ** -** Return NULL if the WhereLoop list contains an entry that can supplant -** pTemplate, in other words if pTemplate does not belong on the list. +** Return NULL if pTemplate does not belong on the WhereLoop list. +** In other words if pTemplate ought to be dropped from further consideration. ** -** If pX is a WhereLoop that pTemplate can supplant, then return the +** If pX is a WhereLoop that pTemplate can replace, then return the ** link that points to pX. ** -** If pTemplate cannot supplant any existing element of the list but needs -** to be added to the list, then return a pointer to the tail of the list. +** If pTemplate cannot replace any existing element of the list but needs +** to be added to the list as a new entry, then return a pointer to the +** tail of the list. */ static WhereLoop **whereLoopFindLesser( WhereLoop **ppPrev, @@ -131297,7 +154359,7 @@ static WhereLoop **whereLoopFindLesser( /* In the current implementation, the rSetup value is either zero ** or the cost of building an automatic index (NlogN) and the NlogN ** is the same for compatible WhereLoops. */ - assert( p->rSetup==0 || pTemplate->rSetup==0 + assert( p->rSetup==0 || pTemplate->rSetup==0 || p->rSetup==pTemplate->rSetup ); /* whereLoopAddBtree() always generates and inserts the automatic index @@ -131362,7 +154424,7 @@ static WhereLoop **whereLoopFindLesser( ** ** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we ** still might overwrite similar loops with the new template if the -** new template is better. Loops may be overwritten if the following +** new template is better. Loops may be overwritten if the following ** conditions are met: ** ** (1) They have the same iTab. @@ -131376,6 +154438,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ sqlite3 *db = pWInfo->pParse->db; int rc; + /* Stop the search once we hit the query planner search limit */ + if( pBuilder->iPlanLimit==0 ){ + WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); + if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; + return SQLITE_DONE; + } + pBuilder->iPlanLimit--; + + whereLoopAdjustCost(pWInfo->pLoops, pTemplate); + /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ @@ -131390,7 +154462,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n); - whereLoopPrint(pTemplate, pBuilder->pWC); + sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif } @@ -131399,7 +154471,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ /* Look for an existing WhereLoop to replace with pTemplate */ - whereLoopAdjustCost(pWInfo->pLoops, pTemplate); ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); if( ppPrev==0 ){ @@ -131408,10 +154479,10 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" skip: "); - whereLoopPrint(pTemplate, pBuilder->pWC); + sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif - return SQLITE_OK; + return SQLITE_OK; }else{ p = *ppPrev; } @@ -131424,10 +154495,12 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ if( sqlite3WhereTrace & 0x8 ){ if( p!=0 ){ sqlite3DebugPrintf("replace: "); - whereLoopPrint(p, pBuilder->pWC); + sqlite3WhereLoopPrint(p, pBuilder->pWC); + sqlite3DebugPrintf(" with: "); + }else{ + sqlite3DebugPrintf(" add: "); } - sqlite3DebugPrintf(" add: "); - whereLoopPrint(pTemplate, pBuilder->pWC); + sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC); } #endif if( p==0 ){ @@ -131451,7 +154524,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" delete: "); - whereLoopPrint(pToDel, pBuilder->pWC); + sqlite3WhereLoopPrint(pToDel, pBuilder->pWC); } #endif whereLoopDelete(db, pToDel); @@ -131460,7 +154533,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ rc = whereLoopXfer(db, p, pTemplate); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ Index *pIndex = p->u.btree.pIndex; - if( pIndex && pIndex->tnum==0 ){ + if( pIndex && pIndex->idxType==SQLITE_IDXTYPE_IPK ){ p->u.btree.pIndex = 0; } } @@ -131503,14 +154576,15 @@ static void whereLoopOutputAdjust( ){ WhereTerm *pTerm, *pX; Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf); - int i, j, k; + int i, j; LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); - for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){ - if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break; - if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; + for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){ + assert( pTerm!=0 ); if( (pTerm->prereqAll & notAllowed)!=0 ) continue; + if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue; + if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) continue; for(j=pLoop->nLTerm-1; j>=0; j--){ pX = pLoop->aLTerm[j]; if( pX==0 ) continue; @@ -131518,6 +154592,22 @@ static void whereLoopOutputAdjust( if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break; } if( j<0 ){ + if( pLoop->maskSelf==pTerm->prereqAll ){ + /* If there are extra terms in the WHERE clause not used by an index + ** that depend only on the table being scanned, and that will tend to + ** cause many rows to be omitted, then mark that table as + ** "self-culling". + ** + ** 2022-03-24: Self-culling only applies if either the extra terms + ** are straight comparison operators that are non-true with NULL + ** operand, or if the loop is not a LEFT JOIN. + */ + if( (pTerm->eOperator & 0x3f)!=0 + || (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 + ){ + pLoop->wsFlags |= WHERE_SELFCULL; + } + } if( pTerm->truthProb<=0 ){ /* If a truth probability is specified using the likelihood() hints, ** then use the probability provided by the application. */ @@ -131526,23 +154616,31 @@ static void whereLoopOutputAdjust( /* In the absence of explicit truth probabilities, use heuristics to ** guess a reasonable truth probability. */ pLoop->nOut--; - if( pTerm->eOperator&(WO_EQ|WO_IS) ){ + if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 + && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */ + ){ Expr *pRight = pTerm->pExpr->pRight; + int k = 0; testcase( pTerm->pExpr->op==TK_IS ); if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){ k = 10; }else{ k = 20; } - if( iReducewtFlags |= TERM_HEURTRUTH; + iReduce = k; + } } } } } - if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce; + if( pLoop->nOut > nRow-iReduce ){ + pLoop->nOut = nRow - iReduce; + } } -/* +/* ** Term pTerm is a vector range comparison operation. The first comparison ** in the vector can be optimized using column nEq of the index. This ** function returns the total number of vector elements that can be used @@ -131571,14 +154669,17 @@ static int whereRangeVectorLen( nCmp = MIN(nCmp, (pIdx->nColumn - nEq)); for(i=1; ipExpr->pLeft->x.pList->a[i].pExpr; - Expr *pRhs = pTerm->pExpr->pRight; - if( pRhs->flags & EP_xIsSelect ){ + Expr *pLhs, *pRhs; + + assert( ExprUseXList(pTerm->pExpr->pLeft) ); + pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr; + pRhs = pTerm->pExpr->pRight; + if( ExprUseXSelect(pRhs) ){ pRhs = pRhs->x.pSelect->pEList->a[i].pExpr; }else{ pRhs = pRhs->x.pList->a[i].pExpr; @@ -131588,9 +154689,9 @@ static int whereRangeVectorLen( ** the right column of the right source table. And that the sort ** order of the index column is the same as the sort order of the ** leftmost index column. */ - if( pLhs->op!=TK_COLUMN - || pLhs->iTable!=iCur - || pLhs->iColumn!=pIdx->aiColumn[i+nEq] + if( pLhs->op!=TK_COLUMN + || pLhs->iTable!=iCur + || pLhs->iColumn!=pIdx->aiColumn[i+nEq] || pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq] ){ break; @@ -131619,20 +154720,20 @@ static int whereRangeVectorLen( #endif /* -** We have so far matched pBuilder->pNew->u.btree.nEq terms of the +** We have so far matched pBuilder->pNew->u.btree.nEq terms of the ** index pIndex. Try to match one more. ** -** When this function is called, pBuilder->pNew->nOut contains the -** number of rows expected to be visited by filtering using the nEq -** terms only. If it is modified, this value is restored before this +** When this function is called, pBuilder->pNew->nOut contains the +** number of rows expected to be visited by filtering using the nEq +** terms only. If it is modified, this value is restored before this ** function returns. ** -** If pProbe->tnum==0, that means pIndex is a fake index used for the -** INTEGER PRIMARY KEY. +** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is +** a fake index used for the INTEGER PRIMARY KEY. */ static int whereLoopAddBtreeIndex( WhereLoopBuilder *pBuilder, /* The WhereLoop factory */ - struct SrcList_item *pSrc, /* FROM clause term being analyzed */ + SrcItem *pSrc, /* FROM clause term being analyzed */ Index *pProbe, /* An index on pSrc */ LogEst nInMul /* log(Number of iterations due to IN) */ ){ @@ -131658,8 +154759,9 @@ static int whereLoopAddBtreeIndex( pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; - WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n", - pProbe->zName, pNew->u.btree.nEq)); + WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n", + pProbe->pTable->zName,pProbe->zName, + pNew->u.btree.nEq, pNew->nSkip, pNew->rRun)); assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); @@ -131672,6 +154774,8 @@ static int whereLoopAddBtreeIndex( if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEqnColumn ); + assert( pNew->u.btree.nEqnKeyCol + || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); saved_nEq = pNew->u.btree.nEq; saved_nBtm = pNew->u.btree.nBtm; @@ -131691,7 +154795,7 @@ static int whereLoopAddBtreeIndex( LogEst rCostIdx; LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */ int nIn = 0; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 int nRecValid = pBuilder->nRecValid; #endif if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) @@ -131705,18 +154809,20 @@ static int whereLoopAddBtreeIndex( ** to mix with a lower range bound from some other source */ if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue; - /* Do not allow IS constraints from the WHERE clause to be used by the - ** right table of a LEFT JOIN. Only constraints in the ON clause are - ** allowed */ + /* tag-20191211-001: Do not allow constraints from the WHERE clause to + ** be used by the right table of a LEFT JOIN. Only constraints in the + ** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */ if( (pSrc->fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) - && (eOp & (WO_IS|WO_ISNULL))!=0 ){ - testcase( eOp & WO_IS ); - testcase( eOp & WO_ISNULL ); continue; } + if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){ + pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE; + }else{ + pBuilder->bldFlags1 |= SQLITE_BLDF1_INDEXED; + } pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->u.btree.nBtm = saved_nBtm; @@ -131727,15 +154833,14 @@ static int whereLoopAddBtreeIndex( pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf; assert( nInMul==0 - || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 - || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 - || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 + || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0 + || (pNew->wsFlags & WHERE_COLUMN_IN)!=0 + || (pNew->wsFlags & WHERE_SKIPSCAN)!=0 ); if( eOp & WO_IN ){ Expr *pExpr = pTerm->pExpr; - pNew->wsFlags |= WHERE_COLUMN_IN; - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + if( ExprUseXSelect(pExpr) ){ /* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */ int i; nIn = 46; assert( 46==sqlite3LogEst(25) ); @@ -131751,22 +154856,69 @@ static int whereLoopAddBtreeIndex( }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){ /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); - assert( nIn>0 ); /* RHS always has 2 or more terms... The parser - ** changes "x IN (?)" into "x=?". */ } + if( pProbe->hasStat1 && rLogSize>=10 ){ + LogEst M, logK, x; + /* Let: + ** N = the total number of rows in the table + ** K = the number of entries on the RHS of the IN operator + ** M = the number of rows in the table that match terms to the + ** to the left in the same index. If the IN operator is on + ** the left-most index column, M==N. + ** + ** Given the definitions above, it is better to omit the IN operator + ** from the index lookup and instead do a scan of the M elements, + ** testing each scanned row against the IN operator separately, if: + ** + ** M*log(K) < K*log(N) + ** + ** Our estimates for M, K, and N might be inaccurate, so we build in + ** a safety margin of 2 (LogEst: 10) that favors using the IN operator + ** with the index, as using an index has better worst-case behavior. + ** If we do not have real sqlite_stat1 data, always prefer to use + ** the index. Do not bother with this optimization on very small + ** tables (less than 2 rows) as it is pointless in that case. + */ + M = pProbe->aiRowLogEst[saved_nEq]; + logK = estLog(nIn); + /* TUNING v----- 10 to bias toward indexed IN */ + x = M + logK + 10 - (nIn + rLogSize); + if( x>=0 ){ + WHERETRACE(0x40, + ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d) " + "prefers indexed lookup\n", + saved_nEq, M, logK, nIn, rLogSize, x)); + }else if( nInMul<2 && OptimizationEnabled(db, SQLITE_SeekScan) ){ + WHERETRACE(0x40, + ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d" + " nInMul=%d) prefers skip-scan\n", + saved_nEq, M, logK, nIn, rLogSize, x, nInMul)); + pNew->wsFlags |= WHERE_IN_SEEKSCAN; + }else{ + WHERETRACE(0x40, + ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d" + " nInMul=%d) prefers normal scan\n", + saved_nEq, M, logK, nIn, rLogSize, x, nInMul)); + continue; + } + } + pNew->wsFlags |= WHERE_COLUMN_IN; }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); - if( iCol==XN_ROWID - || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) + if( iCol==XN_ROWID + || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ - if( iCol>=0 && pProbe->uniqNotNull==0 ){ - pNew->wsFlags |= WHERE_UNQ_WANTED; - }else{ + if( iCol==XN_ROWID || pProbe->uniqNotNull + || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ) + ){ pNew->wsFlags |= WHERE_ONEROW; + }else{ + pNew->wsFlags |= WHERE_UNQ_WANTED; } } + if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS; }else if( eOp & WO_ISNULL ){ pNew->wsFlags |= WHERE_COLUMN_NULL; }else if( eOp & (WO_GT|WO_GE) ){ @@ -131779,7 +154931,7 @@ static int whereLoopAddBtreeIndex( pBtm = pTerm; pTop = 0; if( pTerm->wtFlags & TERM_LIKEOPT ){ - /* Range contraints that come from the LIKE optimization are + /* Range constraints that come from the LIKE optimization are ** always used in pairs. */ pTop = &pTerm[1]; assert( (pTop-(pTerm->pWC->a))pWC->nTerm ); @@ -131805,12 +154957,12 @@ static int whereLoopAddBtreeIndex( /* At this point pNew->nOut is set to the number of rows expected to ** be visited by the index scan before considering term pTerm, or the - ** values of nIn and nInMul. In other words, assuming that all + ** values of nIn and nInMul. In other words, assuming that all ** "x IN(...)" terms are replaced with "x = ?". This block updates ** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */ assert( pNew->nOut==saved_nOut ); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ - /* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4 + /* Adjust nOut using stat4 data. Or, if there is no stat4 ** data, using some other estimate. */ whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew); }else{ @@ -131824,12 +154976,13 @@ static int whereLoopAddBtreeIndex( pNew->nOut += pTerm->truthProb; pNew->nOut -= nIn; }else{ -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 tRowcnt nOut = 0; - if( nInMul==0 - && pProbe->nSample - && pNew->u.btree.nEq<=pProbe->nSampleCol - && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) + if( nInMul==0 + && pProbe->nSample + && ALWAYS(pNew->u.btree.nEq<=pProbe->nSampleCol) + && ((eOp & WO_IN)==0 || ExprUseXList(pTerm->pExpr)) + && OptimizationEnabled(db, SQLITE_Stat4) ){ Expr *pExpr = pTerm->pExpr; if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ @@ -131844,6 +154997,27 @@ static int whereLoopAddBtreeIndex( if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */ if( nOut ){ pNew->nOut = sqlite3LogEst(nOut); + if( nEq==1 + /* TUNING: Mark terms as "low selectivity" if they seem likely + ** to be true for half or more of the rows in the table. + ** See tag-202002240-1 */ + && pNew->nOut+10 > pProbe->aiRowLogEst[0] + ){ +#if WHERETRACE_ENABLED /* 0x01 */ + if( sqlite3WhereTrace & 0x01 ){ + sqlite3DebugPrintf( + "STAT4 determines term has low selectivity:\n"); + sqlite3WhereTermPrint(pTerm, 999); + } +#endif + pTerm->wtFlags |= TERM_HIGHTRUTH; + if( pTerm->wtFlags & TERM_HEURTRUTH ){ + /* If the term has previously been used with an assumption of + ** higher selectivity, then set the flag to rerun the + ** loop computations. */ + pBuilder->bldFlags2 |= SQLITE_BLDF2_2NDPASS; + } + } if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; pNew->nOut -= nIn; } @@ -131853,8 +155027,8 @@ static int whereLoopAddBtreeIndex( { pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]); if( eOp & WO_ISNULL ){ - /* TUNING: If there is no likelihood() value, assume that a - ** "col IS NULL" expression matches twice as many rows + /* TUNING: If there is no likelihood() value, assume that a + ** "col IS NULL" expression matches twice as many rows ** as (col=?). */ pNew->nOut += 10; } @@ -131866,6 +155040,7 @@ static int whereLoopAddBtreeIndex( ** it to pNew->rRun, which is currently set to the cost of the index ** seek only. Then, if this is a non-covering index, add the cost of ** visiting the rows in the main table. */ + assert( pSrc->pTab->szTabRow>0 ); rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx); if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){ @@ -131887,11 +155062,13 @@ static int whereLoopAddBtreeIndex( if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 && pNew->u.btree.nEqnColumn + && (pNew->u.btree.nEqnKeyCol || + pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) ){ whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn); } pNew->nOut = saved_nOut; -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 +#ifdef SQLITE_ENABLE_STAT4 pBuilder->nRecValid = nRecValid; #endif } @@ -131906,18 +155083,21 @@ static int whereLoopAddBtreeIndex( /* Consider using a skip-scan if there are no WHERE clause constraints ** available for the left-most terms of the index, and if the average - ** number of repeats in the left-most terms is at least 18. + ** number of repeats in the left-most terms is at least 18. ** ** The magic number 18 is selected on the basis that scanning 17 rows ** is almost always quicker than an index seek (even though if the index ** contains fewer than 2^17 rows we assume otherwise in other parts of - ** the code). And, even if it is not, it should not be too much slower. + ** the code). And, even if it is not, it should not be too much slower. ** On the other hand, the extra seeks could end up being significantly ** more expensive. */ assert( 42==sqlite3LogEst(18) ); if( saved_nEq==saved_nSkip && saved_nEq+1nKeyCol + && saved_nEq==pNew->nLTerm && pProbe->noSkipScan==0 + && pProbe->hasStat1!=0 + && OptimizationEnabled(db, SQLITE_SkipScan) && pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */ && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK ){ @@ -131938,8 +155118,8 @@ static int whereLoopAddBtreeIndex( pNew->wsFlags = saved_wsFlags; } - WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n", - pProbe->zName, saved_nEq, rc)); + WHERETRACE(0x800, ("END %s.addBtreeIdx(%s), nEq=%d, rc=%d\n", + pProbe->pTable->zName, pProbe->zName, saved_nEq, rc)); return rc; } @@ -131963,7 +155143,8 @@ static int indexMightHelpWithOrderBy( if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; iinExpr; ii++){ - Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); + Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr); + if( NEVER(pExpr==0) ) continue; if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jjnKeyCol; jj++){ @@ -131972,7 +155153,7 @@ static int indexMightHelpWithOrderBy( }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jjnKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; - if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ + if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){ return 1; } } @@ -131981,38 +155162,30 @@ static int indexMightHelpWithOrderBy( return 0; } -/* -** Return a bitmask where 1s indicate that the corresponding column of -** the table is used by an index. Only the first 63 columns are considered. -*/ -static Bitmask columnsInIndex(Index *pIdx){ - Bitmask m = 0; - int j; - for(j=pIdx->nColumn-1; j>=0; j--){ - int x = pIdx->aiColumn[j]; - if( x>=0 ){ - testcase( x==BMS-1 ); - testcase( x==BMS-2 ); - if( xpWInfo->pParse; while( pWhere->op==TK_AND ){ - if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0; + if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0; pWhere = pWhere->pRight; } + if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0; for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ - Expr *pExpr = pTerm->pExpr; - if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) - && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) + Expr *pExpr; + pExpr = pTerm->pExpr; + if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->w.iRightJoinTable==iTab) + && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin)) + && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) + && (pTerm->wtFlags & TERM_VNULL)==0 ){ return 1; } @@ -132034,18 +155207,18 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){ ** cost = nRow * K // scan of covering index ** cost = nRow * (K+3.0) // scan of non-covering index ** -** where K is a value between 1.1 and 3.0 set based on the relative +** where K is a value between 1.1 and 3.0 set based on the relative ** estimated average size of the index and table records. ** ** For an index scan, where nVisit is the number of index rows visited -** by the scan, and nSeek is the number of seek operations required on +** by the scan, and nSeek is the number of seek operations required on ** the index b-tree: ** ** cost = nSeek * (log(nRow) + K * nVisit) // covering index ** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index ** -** Normally, nSeek is 1. nSeek values greater than 1 come about if the -** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when +** Normally, nSeek is 1. nSeek values greater than 1 come about if the +** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when ** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans. ** ** The estimated values (nRow, nVisit, nSeek) often contain a large amount @@ -132066,16 +155239,15 @@ static int whereLoopAddBtree( LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */ i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */ SrcList *pTabList; /* The FROM clause */ - struct SrcList_item *pSrc; /* The FROM clause btree term to add */ + SrcItem *pSrc; /* The FROM clause btree term to add */ WhereLoop *pNew; /* Template WhereLoop object */ int rc = SQLITE_OK; /* Return code */ int iSortIdx = 1; /* Index number */ int b; /* A boolean value */ LogEst rSize; /* number of rows in the table */ - LogEst rLogSize; /* Logarithm of the number of rows in the table */ WhereClause *pWC; /* The parsed WHERE clause */ Table *pTab; /* Table being queried */ - + pNew = pBuilder->pNew; pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; @@ -132084,9 +155256,10 @@ static int whereLoopAddBtree( pWC = pBuilder->pWC; assert( !IsVirtual(pSrc->pTab) ); - if( pSrc->pIBIndex ){ + if( pSrc->fg.isIndexedBy ){ + assert( pSrc->fg.isCte==0 ); /* An INDEXED BY clause specifies a particular index to use */ - pProbe = pSrc->pIBIndex; + pProbe = pSrc->u2.pIBIndex; }else if( !HasRowid(pTab) ){ pProbe = pTab->pIndex; }else{ @@ -132103,6 +155276,7 @@ static int whereLoopAddBtree( sPk.onError = OE_Replace; sPk.pTable = pTab; sPk.szIdxRow = pTab->szTabRow; + sPk.idxType = SQLITE_IDXTYPE_IPK; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; pFirst = pSrc->pTab->pIndex; @@ -132114,22 +155288,23 @@ static int whereLoopAddBtree( pProbe = &sPk; } rSize = pTab->nRowLogEst; - rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 - && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ + && !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ ){ /* Generate auto-index WhereLoops */ + LogEst rLogSize; /* Logarithm of the number of rows in the table */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; + rLogSize = estLog(rSize); for(pTerm=pWC->a; rc==SQLITE_OK && pTermprereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ @@ -132141,14 +155316,16 @@ static int whereLoopAddBtree( /* TUNING: One-time cost for computing the automatic index is ** estimated to be X*N*log2(N) where N is the number of rows in ** the table being indexed and where X is 7 (LogEst=28) for normal - ** tables or 1.375 (LogEst=4) for views and subqueries. The value + ** tables or 0.5 (LogEst=-10) for views and subqueries. The value ** of X is smaller for views and subqueries so that the query planner ** will be more aggressive about generating automatic indexes for ** those objects, since there is no opportunity to add schema ** indexes on subqueries and views. */ - pNew->rSetup = rLogSize + rSize + 4; - if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ - pNew->rSetup += 24; + pNew->rSetup = rLogSize + rSize; + if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){ + pNew->rSetup += 28; + }else{ + pNew->rSetup -= 10; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); if( pNew->rSetup<0 ) pNew->rSetup = 0; @@ -132166,14 +155343,20 @@ static int whereLoopAddBtree( } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ - /* Loop over all indices - */ - for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){ + /* Loop over all indices. If there was an INDEXED BY clause, then only + ** consider index pProbe. */ + for(; rc==SQLITE_OK && pProbe; + pProbe=(pSrc->fg.isIndexedBy ? 0 : pProbe->pNext), iSortIdx++ + ){ + int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0; if( pProbe->pPartIdxWhere!=0 - && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){ + && !whereUsablePartialIndex(pSrc->iCursor, isLeft, pWC, + pProbe->pPartIdxWhere) + ){ testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */ continue; /* Partial index inappropriate for this query */ } + if( pProbe->bNoQuery ) continue; rSize = pProbe->aiRowLogEst[0]; pNew->u.btree.nEq = 0; pNew->u.btree.nBtm = 0; @@ -132186,16 +155369,32 @@ static int whereLoopAddBtree( pNew->nOut = rSize; pNew->u.btree.pIndex = pProbe; b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor); + /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */ assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 ); - if( pProbe->tnum<=0 ){ + if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ /* Integer primary key index */ pNew->wsFlags = WHERE_IPK; /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; - /* TUNING: Cost of full table scan is (N*3.0). */ + /* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an + ** extra cost designed to discourage the use of full table scans, + ** since index lookups have better worst-case performance if our + ** stat guesses are wrong. Reduce the 3.0 penalty slightly + ** (to 2.75) if we have valid STAT4 information for the table. + ** At 2.75, a full table scan is preferred over using an index on + ** a column with just two distinct values where each value has about + ** an equal number of appearances. Without STAT4 data, we still want + ** to use an index in that case, since the constraint might be for + ** the scarcer of the two values, and in that case an index lookup is + ** better. + */ +#ifdef SQLITE_ENABLE_STAT4 + pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0); +#else pNew->rRun = rSize + 16; +#endif ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); @@ -132207,7 +155406,7 @@ static int whereLoopAddBtree( pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; m = 0; }else{ - m = pSrc->colUsed & ~columnsInIndex(pProbe); + m = pSrc->colUsed & pProbe->colNotIdxed; pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } @@ -132215,6 +155414,7 @@ static int whereLoopAddBtree( if( b || !HasRowid(pTab) || pProbe->pPartIdxWhere!=0 + || pSrc->fg.isIndexedBy || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRowszTabRow) @@ -132253,7 +155453,7 @@ static int whereLoopAddBtree( if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19; } } - + pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); @@ -132264,22 +155464,35 @@ static int whereLoopAddBtree( } } + pBuilder->bldFlags1 = 0; rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0); -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){ + /* If a non-unique index is used, or if a prefix of the key for + ** unique index is used (making the index functionally non-unique) + ** then the sqlite_stat1 data becomes important for scoring the + ** plan */ + pTab->tabFlags |= TF_StatsUsed; + } +#ifdef SQLITE_ENABLE_STAT4 sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; #endif - - /* If there was an INDEXED BY clause, then only that one index is - ** considered. */ - if( pSrc->pIBIndex ) break; } return rc; } #ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Return true if pTerm is a virtual table LIMIT or OFFSET term. +*/ +static int isLimitTerm(WhereTerm *pTerm){ + assert( pTerm->eOperator==WO_AUX || pTerm->eMatchOp==0 ); + return pTerm->eMatchOp>=SQLITE_INDEX_CONSTRAINT_LIMIT + && pTerm->eMatchOp<=SQLITE_INDEX_CONSTRAINT_OFFSET; +} + /* ** Argument pIdxInfo is already populated with all constraints that may ** be used by the virtual table identified by pBuilder->pNew->iTab. This @@ -132307,9 +155520,11 @@ static int whereLoopAddVirtualOne( u16 mExclude, /* Exclude terms using these operators */ sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ u16 mNoOmit, /* Do not omit these constraints */ - int *pbIn /* OUT: True if plan uses an IN(...) op */ + int *pbIn, /* OUT: True if plan uses an IN(...) op */ + int *pbRetryLimit /* OUT: Retry without LIMIT/OFFSET */ ){ WhereClause *pWC = pBuilder->pWC; + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage; int i; @@ -132317,21 +155532,22 @@ static int whereLoopAddVirtualOne( int rc = SQLITE_OK; WhereLoop *pNew = pBuilder->pNew; Parse *pParse = pBuilder->pWInfo->pParse; - struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab]; + SrcItem *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab]; int nConstraint = pIdxInfo->nConstraint; assert( (mUsable & mPrereq)==mPrereq ); *pbIn = 0; pNew->prereq = mPrereq; - /* Set the usable flag on the subset of constraints identified by + /* Set the usable flag on the subset of constraints identified by ** arguments mUsable and mExclude. */ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; ia[pIdxCons->iTermOffset]; pIdxCons->usable = 0; - if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight + if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight && (pTerm->eOperator & mExclude)==0 + && (pbRetryLimit || !isLimitTerm(pTerm)) ){ pIdxCons->usable = 1; } @@ -132347,15 +155563,26 @@ static int whereLoopAddVirtualOne( pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; + pHidden->mHandleIn = 0; /* Invoke the virtual table xBestIndex() method */ rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); - if( rc ) return rc; + if( rc ){ + if( rc==SQLITE_CONSTRAINT ){ + /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means + ** that the particular combination of parameters provided is unusable. + ** Make no entries in the loop table. + */ + WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n")); + return SQLITE_OK; + } + return rc; + } mxTerm = -1; assert( pNew->nLSlot>=nConstraint ); - for(i=0; iaLTerm[i] = 0; - pNew->u.vtab.omitMask = 0; + memset(pNew->aLTerm, 0, sizeof(pNew->aLTerm[0])*nConstraint ); + memset(&pNew->u.vtab, 0, sizeof(pNew->u.vtab)); pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; iaLTerm[iTerm]!=0 || pIdxCons->usable==0 ){ - rc = SQLITE_ERROR; sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); - return rc; + testcase( pIdxInfo->needToFreeIdxStr ); + return SQLITE_ERROR; } testcase( iTerm==nConstraint-1 ); testcase( j==0 ); @@ -132382,8 +155609,20 @@ static int whereLoopAddVirtualOne( if( iTerm>mxTerm ) mxTerm = iTerm; testcase( iTerm==15 ); testcase( iTerm==16 ); - if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<eOperator & WO_IN)!=0 ){ + if( pUsage[i].omit ){ + if( i<16 && ((1<u.vtab.omitMask |= 1<eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET ){ + pNew->u.vtab.bOmitOffset = 1; + } + } + if( SMASKBIT32(i) & pHidden->mHandleIn ){ + pNew->u.vtab.mHandleIn |= MASKBIT32(iTerm); + }else if( (pTerm->eOperator & WO_IN)!=0 ){ /* A virtual table that is constrained by an IN clause may not ** consume the ORDER BY clause because (1) the order of IN terms ** is not necessarily related to the order of output terms and @@ -132393,11 +155632,34 @@ static int whereLoopAddVirtualOne( pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; *pbIn = 1; assert( (mExclude & WO_IN)==0 ); } + + if( isLimitTerm(pTerm) && *pbIn ){ + /* If there is an IN(...) term handled as an == (separate call to + ** xFilter for each value on the RHS of the IN) and a LIMIT or + ** OFFSET term handled as well, the plan is unusable. Set output + ** variable *pbRetryLimit to true to tell the caller to retry with + ** LIMIT and OFFSET disabled. */ + if( pIdxInfo->needToFreeIdxStr ){ + sqlite3_free(pIdxInfo->idxStr); + pIdxInfo->idxStr = 0; + pIdxInfo->needToFreeIdxStr = 0; + } + *pbRetryLimit = 1; + return SQLITE_OK; + } } } - pNew->u.vtab.omitMask &= ~mNoOmit; pNew->nLTerm = mxTerm+1; + for(i=0; i<=mxTerm; i++){ + if( pNew->aLTerm[i]==0 ){ + /* The non-zero argvIdx values must be contiguous. Raise an + ** error if they are not */ + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); + testcase( pIdxInfo->needToFreeIdxStr ); + return SQLITE_ERROR; + } + } assert( pNew->nLTerm<=pNew->nLSlot ); pNew->u.vtab.idxNum = pIdxInfo->idxNum; pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; @@ -132428,6 +155690,117 @@ static int whereLoopAddVirtualOne( return rc; } +/* +** Return the collating sequence for a constraint passed into xBestIndex. +** +** pIdxInfo must be an sqlite3_index_info structure passed into xBestIndex. +** This routine depends on there being a HiddenIndexInfo structure immediately +** following the sqlite3_index_info structure. +** +** Return a pointer to the collation name: +** +** 1. If there is an explicit COLLATE operator on the constaint, return it. +** +** 2. Else, if the column has an alternative collation, return that. +** +** 3. Otherwise, return "BINARY". +*/ +SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + const char *zRet = 0; + if( iCons>=0 && iConsnConstraint ){ + CollSeq *pC = 0; + int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset; + Expr *pX = pHidden->pWC->a[iTerm].pExpr; + if( pX->pLeft ){ + pC = sqlite3ExprCompareCollSeq(pHidden->pParse, pX); + } + zRet = (pC ? pC->zName : sqlite3StrBINARY); + } + return zRet; +} + +/* +** Return true if constraint iCons is really an IN(...) constraint, or +** false otherwise. If iCons is an IN(...) constraint, set (if bHandle!=0) +** or clear (if bHandle==0) the flag to handle it using an iterator. +*/ +SQLITE_API int sqlite3_vtab_in(sqlite3_index_info *pIdxInfo, int iCons, int bHandle){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + u32 m = SMASKBIT32(iCons); + if( m & pHidden->mIn ){ + if( bHandle==0 ){ + pHidden->mHandleIn &= ~m; + }else if( bHandle>0 ){ + pHidden->mHandleIn |= m; + } + return 1; + } + return 0; +} + +/* +** This interface is callable from within the xBestIndex callback only. +** +** If possible, set (*ppVal) to point to an object containing the value +** on the right-hand-side of constraint iCons. +*/ +SQLITE_API int sqlite3_vtab_rhs_value( + sqlite3_index_info *pIdxInfo, /* Copy of first argument to xBestIndex */ + int iCons, /* Constraint for which RHS is wanted */ + sqlite3_value **ppVal /* Write value extracted here */ +){ + HiddenIndexInfo *pH = (HiddenIndexInfo*)&pIdxInfo[1]; + sqlite3_value *pVal = 0; + int rc = SQLITE_OK; + if( iCons<0 || iCons>=pIdxInfo->nConstraint ){ + rc = SQLITE_MISUSE; /* EV: R-30545-25046 */ + }else{ + if( pH->aRhs[iCons]==0 ){ + WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset]; + rc = sqlite3ValueFromExpr( + pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db), + SQLITE_AFF_BLOB, &pH->aRhs[iCons] + ); + testcase( rc!=SQLITE_OK ); + } + pVal = pH->aRhs[iCons]; + } + *ppVal = pVal; + + if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-19933-32160 */ + rc = SQLITE_NOTFOUND; /* IMP: R-36424-56542 */ + } + + return rc; +} + +/* +** Return true if ORDER BY clause may be handled as DISTINCT. +*/ +SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + assert( pHidden->eDistinct==0 + || pHidden->eDistinct==1 + || pHidden->eDistinct==2 ); + return pHidden->eDistinct; +} + +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) +/* +** Cause the prepared statement that is associated with a call to +** xBestIndex to open write transactions on all attached schemas. +** This is used by the (built-in) sqlite_dbpage virtual table. +*/ +SQLITE_PRIVATE void sqlite3VtabWriteAll(sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + Parse *pParse = pHidden->pParse; + int nDb = pParse->db->nDb; + int i; + for(i=0; ipWInfo; @@ -132478,8 +155852,7 @@ static int whereLoopAddVirtual( pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; assert( IsVirtual(pSrc->pTab) ); - p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, - &mNoOmit); + p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; @@ -132487,20 +155860,29 @@ static int whereLoopAddVirtual( pNew->u.vtab.needFree = 0; nConstraint = p->nConstraint; if( whereLoopResize(pParse->db, pNew, nConstraint) ){ - sqlite3DbFree(pParse->db, p); + freeIndexInfo(pParse->db, p); return SQLITE_NOMEM_BKPT; } /* First call xBestIndex() with all constraints usable. */ + WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); WHERETRACE(0x40, (" VirtualOne: all usable\n")); - rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry + ); + if( bRetry ){ + assert( rc==SQLITE_OK ); + rc = whereLoopAddVirtualOne( + pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, 0 + ); + } /* If the call to xBestIndex() with all terms enabled produced a plan - ** that does not require any source tables (IOW: a plan with mBest==0), - ** then there is no point in making any further calls to xBestIndex() - ** since they will all return the same result (if the xBestIndex() - ** implementation is sane). */ - if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){ + ** that does not require any source tables (IOW: a plan with mBest==0) + ** and does not use an IN(...) operator, then there is no point in making + ** any further calls to xBestIndex() since they will all return the same + ** result (if the xBestIndex() implementation is sane). */ + if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){ int seenZero = 0; /* True if a plan with no prereqs seen */ int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */ Bitmask mPrev = 0; @@ -132511,7 +155893,7 @@ static int whereLoopAddVirtual( if( bIn ){ WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n")); rc = whereLoopAddVirtualOne( - pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn); + pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0); assert( bIn==0 ); mBestNoIn = pNew->prereq & ~mPrereq; if( mBestNoIn==0 ){ @@ -132520,7 +155902,7 @@ static int whereLoopAddVirtual( } } - /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) + /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq) ** in the set of terms that apply to the current virtual table. */ while( rc==SQLITE_OK ){ int i; @@ -132538,7 +155920,7 @@ static int whereLoopAddVirtual( WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n", (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext)); rc = whereLoopAddVirtualOne( - pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn); + pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn, 0); if( pNew->prereq==mPrereq ){ seenZero = 1; if( bIn==0 ) seenZeroNoIN = 1; @@ -132551,7 +155933,7 @@ static int whereLoopAddVirtual( if( rc==SQLITE_OK && seenZero==0 ){ WHERETRACE(0x40, (" VirtualOne: all disabled\n")); rc = whereLoopAddVirtualOne( - pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn); + pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0); if( bIn==0 ) seenZeroNoIN = 1; } @@ -132561,12 +155943,13 @@ static int whereLoopAddVirtual( if( rc==SQLITE_OK && seenZeroNoIN==0 ){ WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n")); rc = whereLoopAddVirtualOne( - pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn); + pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0); } } if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); - sqlite3DbFree(pParse->db, p); + freeIndexInfo(pParse->db, p); + WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -132576,8 +155959,8 @@ static int whereLoopAddVirtual( ** btrees or virtual tables. */ static int whereLoopAddOr( - WhereLoopBuilder *pBuilder, - Bitmask mPrereq, + WhereLoopBuilder *pBuilder, + Bitmask mPrereq, Bitmask mUnusable ){ WhereInfo *pWInfo = pBuilder->pWInfo; @@ -132589,8 +155972,8 @@ static int whereLoopAddOr( WhereClause tempWC; WhereLoopBuilder sSubBuild; WhereOrSet sSum, sCur; - struct SrcList_item *pItem; - + SrcItem *pItem; + pWC = pBuilder->pWC; pWCEnd = pWC->a + pWC->nTerm; pNew = pBuilder->pNew; @@ -132600,16 +155983,15 @@ static int whereLoopAddOr( for(pTerm=pWC->a; pTermeOperator & WO_OR)!=0 - && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 + && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 ){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; int once = 1; int i, j; - + sSubBuild = *pBuilder; - sSubBuild.pOrderBy = 0; sSubBuild.pOrSet = &sCur; WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); @@ -132621,6 +156003,7 @@ static int whereLoopAddOr( tempWC.pOuter = pWC; tempWC.op = TK_AND; tempWC.nTerm = 1; + tempWC.nBase = 1; tempWC.a = pOrTerm; sSubBuild.pWC = &tempWC; }else{ @@ -132628,7 +156011,7 @@ static int whereLoopAddOr( } sCur.n = 0; #ifdef WHERETRACE_ENABLED - WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", + WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ sqlite3WhereClausePrint(sSubBuild.pWC); @@ -132645,7 +156028,10 @@ static int whereLoopAddOr( if( rc==SQLITE_OK ){ rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } - assert( rc==SQLITE_OK || sCur.n==0 ); + assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 + || rc==SQLITE_NOMEM ); + testcase( rc==SQLITE_NOMEM && sCur.n>0 ); + testcase( rc==SQLITE_DONE ); if( sCur.n==0 ){ sSum.n = 0; break; @@ -132675,8 +156061,8 @@ static int whereLoopAddOr( /* TUNING: Currently sSum.a[i].rRun is set to the sum of the costs ** of all sub-scans required by the OR-scan. However, due to rounding ** errors, it may be that the cost of the OR-scan is equal to its - ** most expensive sub-scan. Add the smallest possible penalty - ** (equivalent to multiplying the cost by 1.07) to ensure that + ** most expensive sub-scan. Add the smallest possible penalty + ** (equivalent to multiplying the cost by 1.07) to ensure that ** this does not happen. Otherwise, for WHERE clauses such as the ** following where there is an index on "y": ** @@ -132696,7 +156082,7 @@ static int whereLoopAddOr( } /* -** Add all WhereLoop objects for all tables +** Add all WhereLoop objects for all tables */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo = pBuilder->pWInfo; @@ -132704,29 +156090,31 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ Bitmask mPrior = 0; int iTab; SrcList *pTabList = pWInfo->pTabList; - struct SrcList_item *pItem; - struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel]; + SrcItem *pItem; + SrcItem *pEnd = &pTabList->a[pWInfo->nLevel]; sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; WhereLoop *pNew; - u8 priorJointype = 0; /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); + pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT; for(iTab=0, pItem=pTabList->a; pItemiTab = iTab; + pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); - if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ + if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ mPrereq = mPrior; + }else{ + mPrereq = 0; } - priorJointype = pItem->fg.jointype; #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ - struct SrcList_item *p; + SrcItem *p; for(p=&pItem[1]; pfg.jointype & (JT_LEFT|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); @@ -132738,11 +156126,19 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ { rc = whereLoopAddBtree(pBuilder, mPrereq); } - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; - if( rc || db->mallocFailed ) break; + if( rc || db->mallocFailed ){ + if( rc==SQLITE_DONE ){ + /* We hit the query planner search limit set by iPlanLimit */ + sqlite3_log(SQLITE_WARNING, "abbreviated query algorithm search"); + rc = SQLITE_OK; + }else{ + break; + } + } } whereLoopClear(db, pNew); @@ -132750,20 +156146,20 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ } /* -** Examine a WherePath (with the addition of the extra WhereLoop of the 5th +** Examine a WherePath (with the addition of the extra WhereLoop of the 6th ** parameters) to see if it outputs rows in the requested ORDER BY ** (or GROUP BY) without requiring a separate sort operation. Return N: -** +** ** N>0: N terms of the ORDER BY clause are satisfied ** N==0: No terms of the ORDER BY clause are satisfied -** N<0: Unknown yet how many terms of ORDER BY might be satisfied. +** N<0: Unknown yet how many terms of ORDER BY might be satisfied. ** ** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as ** strict. With GROUP BY and DISTINCT the only requirement is that ** equivalent rows appear immediately adjacent to one another. GROUP BY ** and DISTINCT do not require rows to appear in any particular order as long ** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT -** the pOrderBy terms can be matched in any order. With ORDER BY, the +** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ static i8 wherePathSatisfiesOrderBy( @@ -132813,7 +156209,7 @@ static i8 wherePathSatisfiesOrderBy( ** row of the WhereLoop. Every one-row WhereLoop is automatically ** order-distinct. A WhereLoop that has no columns in the ORDER BY clause ** is not order-distinct. To be order-distinct is not quite the same as being - ** UNIQUE since a UNIQUE column or index can have multiple rows that + ** UNIQUE since a UNIQUE column or index can have multiple rows that ** are NULL and NULL values are equivalent for the purpose of order-distinct. ** To be order-distinct, the columns must be UNIQUE and NOT NULL. ** @@ -132833,7 +156229,9 @@ static i8 wherePathSatisfiesOrderBy( orderDistinctMask = 0; ready = 0; eqOpMask = WO_EQ | WO_IS | WO_ISNULL; - if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN; + if( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MAX|WHERE_ORDERBY_MIN) ){ + eqOpMask |= WO_IN; + } for(iLoop=0; isOrderDistinct && obSat0 ) ready |= pLoop->maskSelf; if( iLoopwsFlags & WHERE_VIRTUALTABLE ){ - if( pLoop->u.vtab.isOrdered ) obSat = obDone; + if( pLoop->u.vtab.isOrdered && (wctrlFlags & WHERE_DISTINCTBY)==0 ){ + obSat = obDone; + } break; + }else if( wctrlFlags & WHERE_DISTINCTBY ){ + pLoop->u.btree.nDistinctCol = 0; } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; @@ -132855,29 +156257,30 @@ static i8 wherePathSatisfiesOrderBy( */ for(i=0; ia[i].pExpr); - if( pOBExpr->op!=TK_COLUMN ) continue; + pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); + if( NEVER(pOBExpr==0) ) continue; + if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, eqOpMask, 0); if( pTerm==0 ) continue; if( pTerm->eOperator==WO_IN ){ - /* IN terms are only valid for sorting in the ORDER BY LIMIT + /* IN terms are only valid for sorting in the ORDER BY LIMIT ** optimization, and then only if they are actually used ** by the query plan */ - assert( wctrlFlags & WHERE_ORDERBY_LIMIT ); + assert( wctrlFlags & + (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ); for(j=0; jnLTerm && pTerm!=pLoop->aLTerm[j]; j++){} if( j>=pLoop->nLTerm ) continue; } if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ - const char *z1, *z2; - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); - if( !pColl ) pColl = db->pDfltColl; - z1 = pColl->zName; - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr); - if( !pColl ) pColl = db->pDfltColl; - z2 = pColl->zName; - if( sqlite3StrICmp(z1, z2)!=0 ) continue; + Parse *pParse = pWInfo->pParse; + CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[i].pExpr); + CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr); + assert( pColl1 ); + if( pColl2==0 || sqlite3StrICmp(pColl1->zName, pColl2->zName) ){ + continue; + } testcase( pTerm->pExpr->op==TK_IS ); } obSat |= MASKBIT(i); @@ -132896,7 +156299,12 @@ static i8 wherePathSatisfiesOrderBy( assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==XN_ROWID || !HasRowid(pIndex->pTable)); - isOrderDistinct = IsUniqueIndex(pIndex); + /* All relevant terms of the index must also be non-NULL in order + ** for isOrderDistinct to be true. So the isOrderDistint value + ** computed here might be a false positive. Corrections will be + ** made at tag-20210426-1 below */ + isOrderDistinct = IsUniqueIndex(pIndex) + && (pLoop->wsFlags & WHERE_SKIPSCAN)==0; } /* Loop through all columns of the index and deal with the ones @@ -132907,26 +156315,32 @@ static i8 wherePathSatisfiesOrderBy( for(j=0; j=pLoop->u.btree.nEq + assert( j>=pLoop->u.btree.nEq || (pLoop->aLTerm[j]==0)==(jnSkip) ); if( ju.btree.nEq && j>=pLoop->nSkip ){ u16 eOp = pLoop->aLTerm[j]->eOperator; /* Skip over == and IS and ISNULL terms. (Also skip IN terms when - ** doing WHERE_ORDERBY_LIMIT processing). + ** doing WHERE_ORDERBY_LIMIT processing). Except, IS and ISNULL + ** terms imply that the index is not UNIQUE NOT NULL in which case + ** the loop need to be marked as not order-distinct because it can + ** have repeated NULL rows. ** - ** If the current term is a column of an ((?,?) IN (SELECT...)) + ** If the current term is a column of an ((?,?) IN (SELECT...)) ** expression for which the SELECT returns more than one column, ** check that it is the only column used by this loop. Otherwise, ** if it is one of two or more, none of the columns can be - ** considered to match an ORDER BY term. */ + ** considered to match an ORDER BY term. + */ if( (eOp & eqOpMask)!=0 ){ - if( eOp & WO_ISNULL ){ + if( eOp & (WO_ISNULL|WO_IS) ){ + testcase( eOp & WO_ISNULL ); + testcase( eOp & WO_IS ); testcase( isOrderDistinct ); isOrderDistinct = 0; } - continue; + continue; }else if( ALWAYS(eOp & WO_IN) ){ /* ALWAYS() justification: eOp is an equality operator due to the ** ju.btree.nEq constraint above. Any equality other @@ -132948,48 +156362,56 @@ static i8 wherePathSatisfiesOrderBy( */ if( pIndex ){ iColumn = pIndex->aiColumn[j]; - revIdx = pIndex->aSortOrder[j]; - if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; + revIdx = pIndex->aSortOrder[j] & KEYINFO_ORDER_DESC; + if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID; }else{ iColumn = XN_ROWID; revIdx = 0; } /* An unconstrained column that might be NULL means that this - ** WhereLoop is not well-ordered + ** WhereLoop is not well-ordered. tag-20210426-1 */ - if( isOrderDistinct - && iColumn>=0 - && j>=pLoop->u.btree.nEq - && pIndex->pTable->aCol[iColumn].notNull==0 - ){ - isOrderDistinct = 0; + if( isOrderDistinct ){ + if( iColumn>=0 + && j>=pLoop->u.btree.nEq + && pIndex->pTable->aCol[iColumn].notNull==0 + ){ + isOrderDistinct = 0; + } + if( iColumn==XN_EXPR ){ + isOrderDistinct = 0; + } } /* Find the ORDER BY term that corresponds to the j-th column - ** of the index and mark that ORDER BY term off + ** of the index and mark that ORDER BY term off */ isMatch = 0; for(i=0; bOnce && ia[i].pExpr); + pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); + if( NEVER(pOBExpr==0) ) continue; if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; - if( iColumn>=(-1) ){ - if( pOBExpr->op!=TK_COLUMN ) continue; + if( iColumn>=XN_ROWID ){ + if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; if( pOBExpr->iColumn!=iColumn ) continue; }else{ - if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){ + Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr; + if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){ continue; } } - if( iColumn>=0 ){ - pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); - if( !pColl ) pColl = db->pDfltColl; + if( iColumn!=XN_ROWID ){ + pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue; } + if( wctrlFlags & WHERE_DISTINCTBY ){ + pLoop->u.btree.nDistinctCol = j+1; + } isMatch = 1; break; } @@ -132997,13 +156419,22 @@ static i8 wherePathSatisfiesOrderBy( /* Make sure the sort order is compatible in an ORDER BY clause. ** Sort order is irrelevant for a GROUP BY clause. */ if( revSet ){ - if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0; + if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){ + isMatch = 0; + } }else{ - rev = revIdx ^ pOrderBy->a[i].sortOrder; + rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC); if( rev ) *pRevMask |= MASKBIT(iLoop); revSet = 1; } } + if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){ + if( j==pLoop->u.btree.nEq ){ + pLoop->wsFlags |= WHERE_BIGNULL_SORT; + }else{ + isMatch = 0; + } + } if( isMatch ){ if( iColumn==XN_ROWID ){ testcase( distinctColumns==0 ); @@ -133044,7 +156475,7 @@ static i8 wherePathSatisfiesOrderBy( if( obSat==obDone ) return (i8)nOrderBy; if( !isOrderDistinct ){ for(i=nOrderBy-1; i>0; i--){ - Bitmask m = MASKBIT(i) - 1; + Bitmask m = ALWAYS(i0 && 66==sqlite3LogEst(100) ); rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; rSortCost = nRow + rScale + 16; /* Multiple by log(M) where M is the number of output rows. - ** Use the LIMIT for M if it is smaller */ + ** Use the LIMIT for M if it is smaller. Or if this sort is for + ** a DISTINCT operator, M will be the number of distinct output + ** rows, so fudge it downwards a bit. + */ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimitiLimit; + }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){ + /* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT + ** reduces the number of output rows by a factor of 2 */ + if( nRow>10 ){ nRow -= 10; assert( 10==sqlite3LogEst(2) ); } } rSortCost += estLog(nRow); return rSortCost; @@ -133204,7 +156643,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** space for the aSortCost[] array. Each element of the aSortCost array ** is either zero - meaning it has not yet been initialized - or the ** cost of sorting nRowEst rows of data where the first X terms of - ** the ORDER BY clause are already in order, where X is the array + ** the ORDER BY clause are already in order, where X is the array ** index. */ aSortCost = (LogEst*)pX; memset(aSortCost, 0, sizeof(LogEst) * nOrderBy); @@ -133225,7 +156664,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** in this case the query may return a maximum of one row, the results ** are already in the requested order. Set isOrdered to nOrderBy to ** indicate this. Or, if nLoop is greater than zero, set isOrdered to - ** -1, indicating that the result set may or may not be ordered, + ** -1, indicating that the result set may or may not be ordered, ** depending on the loops added to the current plan. */ aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy; } @@ -133246,13 +156685,16 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; - if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){ + if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<3 ){ /* Do not use an automatic index if the this loop is expected - ** to run less than 2 times. */ + ** to run less than 1.25 times. It is tempting to also exclude + ** automatic index usage on an outer loop, but sometimes an automatic + ** index is useful in the outer loop of a correlated subquery. */ assert( 10==sqlite3LogEst(2) ); continue; } - /* At this point, pWLoop is a candidate to be the next loop. + + /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); @@ -133271,14 +156713,19 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo, nRowEst, nOrderBy, isOrdered ); } - rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]); + /* TUNING: Add a small extra penalty (5) to sorting as an + ** extra encouragment to the query planner to select a plan + ** where the rows emerge in the correct order without any sorting + ** required. */ + rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5; WHERETRACE(0x002, ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", - aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy, + aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy, rUnsorted, rCost)); }else{ rCost = rUnsorted; + rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */ } /* Check to see if pWLoop should be added to the set of @@ -133310,8 +156757,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** this candidate as not viable. */ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif @@ -133329,26 +156776,36 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pTo = &aTo[jj]; #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ - sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); } #endif }else{ /* Control reaches here if best-so-far path pTo=aTo[jj] covers the - ** same set of loops and has the sam isOrdered setting as the + ** same set of loops and has the same isOrdered setting as the ** candidate path. Check to see if the candidate should replace - ** pTo or if the candidate should be skipped */ - if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){ + ** pTo or if the candidate should be skipped. + ** + ** The conditional is an expanded vector comparison equivalent to: + ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted) + */ + if( pTo->rCostrCost==rCost + && (pTo->nRownRow==nOut && pTo->rUnsorted<=rUnsorted) + ) + ) + ){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Skip %s cost=%-3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + "Skip %s cost=%-3d,%3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); - sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n", + sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif /* Discard the candidate path from further consideration */ @@ -133361,12 +156818,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ #ifdef WHERETRACE_ENABLED /* 0x4 */ if( sqlite3WhereTrace&0x4 ){ sqlite3DebugPrintf( - "Update %s cost=%-3d,%3d order=%c", - wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, + "Update %s cost=%-3d,%3d,%3d order=%c", + wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted, isOrdered>=0 ? isOrdered+'0' : '?'); - sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n", + sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n", wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow, - pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); + pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?'); } #endif } @@ -133384,8 +156841,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ mxCost = aTo[0].rCost; mxUnsorted = aTo[0].nRow; for(jj=1, pTo=&aTo[1]; jjrCost>mxCost - || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) + if( pTo->rCost>mxCost + || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted) ){ mxCost = pTo->rCost; mxUnsorted = pTo->rUnsorted; @@ -133421,10 +156878,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ if( nFrom==0 ){ sqlite3ErrorMsg(pParse, "no query solution"); - sqlite3DbFree(db, pSpace); + sqlite3DbFreeNN(db, pSpace); return SQLITE_ERROR; } - + /* Find the lowest cost path. pFrom will be left pointing to that path */ pFrom = aFrom; for(ii=1; iipDistinctSet, pFrom, + int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); - if( rc==pWInfo->pDistinctSet->nExpr ){ + if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } + pWInfo->bOrderedInnerLoop = 0; if( pWInfo->pOrderBy ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ @@ -133462,7 +156920,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo->nOBSat = 0; if( nLoop>0 ){ u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags; - if( (wsFlags & WHERE_ONEROW)==0 + if( (wsFlags & WHERE_ONEROW)==0 && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN) ){ Bitmask m = 0; @@ -133476,13 +156934,18 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ } } } + }else if( nLoop + && pWInfo->nOBSat==1 + && (pWInfo->wctrlFlags & (WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX))!=0 + ){ + pWInfo->bOrderedInnerLoop = 1; } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 ){ Bitmask revMask = 0; - int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, + int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask ); assert( pWInfo->sorted==0 ); @@ -133497,7 +156960,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ - sqlite3DbFree(db, pSpace); + sqlite3DbFreeNN(db, pSpace); return SQLITE_OK; } @@ -133509,12 +156972,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ ** times for the common case. ** ** Return non-zero on success, if this query can be handled by this -** no-frills query planner. Return zero if this query needs the +** no-frills query planner. Return zero if this query needs the ** general-purpose query planner. */ static int whereShortCut(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo; - struct SrcList_item *pItem; + SrcItem *pItem; WhereClause *pWC; WhereTerm *pTerm; WhereLoop *pLoop; @@ -133522,6 +156985,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ int j; Table *pTab; Index *pIdx; + WhereScan scan; pWInfo = pBuilder->pWInfo; if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; @@ -133535,7 +156999,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop = pBuilder->pNew; pLoop->wsFlags = 0; pLoop->nSkip = 0; - pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); + pTerm = whereScanInit(&scan, pWC, iCur, -1, WO_EQ|WO_IS, 0); + while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm ){ testcase( pTerm->eOperator & WO_IS ); pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; @@ -133549,19 +157014,20 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ int opMask; assert( pLoop->aLTermSpace==pLoop->aLTerm ); if( !IsUniqueIndex(pIdx) - || pIdx->pPartIdxWhere!=0 - || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) + || pIdx->pPartIdxWhere!=0 + || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; for(j=0; jnKeyCol; j++){ - pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx); + pTerm = whereScanInit(&scan, pWC, iCur, j, opMask, pIdx); + while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan); if( pTerm==0 ) break; testcase( pTerm->eOperator & WO_IS ); pLoop->aLTerm[j] = pTerm; } if( j!=pIdx->nKeyCol ) continue; pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED; - if( pIdx->isCovering || (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){ + if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){ pLoop->wsFlags |= WHERE_IDX_ONLY; } pLoop->nLTerm = j; @@ -133575,21 +157041,220 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ if( pLoop->wsFlags ){ pLoop->nOut = (LogEst)1; pWInfo->a[0].pWLoop = pLoop; - pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); + assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] ); + pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */ pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } + if( scan.iEquiv>1 ) pLoop->wsFlags |= WHERE_TRANSCONS; #ifdef SQLITE_DEBUG pLoop->cId = '0'; +#endif +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace ){ + sqlite3DebugPrintf("whereShortCut() used to compute solution\n"); + } #endif return 1; } return 0; } +/* +** Helper function for exprIsDeterministic(). +*/ +static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){ + pWalker->eCode = 0; + return WRC_Abort; + } + return WRC_Continue; +} + +/* +** Return true if the expression contains no non-deterministic SQL +** functions. Do not consider non-deterministic SQL functions that are +** part of sub-select statements. +*/ +static int exprIsDeterministic(Expr *p){ + Walker w; + memset(&w, 0, sizeof(w)); + w.eCode = 1; + w.xExprCallback = exprNodeIsDeterministic; + w.xSelectCallback = sqlite3SelectWalkFail; + sqlite3WalkExpr(&w, p); + return w.eCode; +} + + +#ifdef WHERETRACE_ENABLED +/* +** Display all WhereLoops in pWInfo +*/ +static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){ + if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */ + WhereLoop *p; + int i; + static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" + "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; + for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ + p->cId = zLabel[i%(sizeof(zLabel)-1)]; + sqlite3WhereLoopPrint(p, pWC); + } + } +} +# define WHERETRACE_ALL_LOOPS(W,C) showAllWhereLoops(W,C) +#else +# define WHERETRACE_ALL_LOOPS(W,C) +#endif + +/* Attempt to omit tables from a join that do not affect the result. +** For a table to not affect the result, the following must be true: +** +** 1) The query must not be an aggregate. +** 2) The table must be the RHS of a LEFT JOIN. +** 3) Either the query must be DISTINCT, or else the ON or USING clause +** must contain a constraint that limits the scan of the table to +** at most a single row. +** 4) The table must not be referenced by any part of the query apart +** from its own USING or ON clause. +** +** For example, given: +** +** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1); +** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2); +** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3); +** +** then table t2 can be omitted from the following: +** +** SELECT v1, v3 FROM t1 +** LEFT JOIN t2 ON (t1.ipk=t2.ipk) +** LEFT JOIN t3 ON (t1.ipk=t3.ipk) +** +** or from: +** +** SELECT DISTINCT v1, v3 FROM t1 +** LEFT JOIN t2 +** LEFT JOIN t3 ON (t1.ipk=t3.ipk) +*/ +static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( + WhereInfo *pWInfo, + Bitmask notReady +){ + int i; + Bitmask tabUsed; + + /* Preconditions checked by the caller */ + assert( pWInfo->nLevel>=2 ); + assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_OmitNoopJoin) ); + + /* These two preconditions checked by the caller combine to guarantee + ** condition (1) of the header comment */ + assert( pWInfo->pResultSet!=0 ); + assert( 0==(pWInfo->wctrlFlags & WHERE_AGG_DISTINCT) ); + + tabUsed = sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pResultSet); + if( pWInfo->pOrderBy ){ + tabUsed |= sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy); + } + for(i=pWInfo->nLevel-1; i>=1; i--){ + WhereTerm *pTerm, *pEnd; + SrcItem *pItem; + WhereLoop *pLoop; + pLoop = pWInfo->a[i].pWLoop; + pItem = &pWInfo->pTabList->a[pLoop->iTab]; + if( (pItem->fg.jointype & JT_LEFT)==0 ) continue; + if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)==0 + && (pLoop->wsFlags & WHERE_ONEROW)==0 + ){ + continue; + } + if( (tabUsed & pLoop->maskSelf)!=0 ) continue; + pEnd = pWInfo->sWC.a + pWInfo->sWC.nTerm; + for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ + if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + || pTerm->pExpr->w.iRightJoinTable!=pItem->iCursor + ){ + break; + } + } + } + if( pTerm drop loop %c not used\n", pLoop->cId)); + notReady &= ~pLoop->maskSelf; + for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ + pTerm->wtFlags |= TERM_CODED; + } + } + if( i!=pWInfo->nLevel-1 ){ + int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel); + memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte); + } + pWInfo->nLevel--; + assert( pWInfo->nLevel>0 ); + } + return notReady; +} + +/* +** Check to see if there are any SEARCH loops that might benefit from +** using a Bloom filter. Consider a Bloom filter if: +** +** (1) The SEARCH happens more than N times where N is the number +** of rows in the table that is being considered for the Bloom +** filter. +** (2) Some searches are expected to find zero rows. (This is determined +** by the WHERE_SELFCULL flag on the term.) +** (3) Bloom-filter processing is not disabled. (Checked by the +** caller.) +** (4) The size of the table being searched is known by ANALYZE. +** +** This block of code merely checks to see if a Bloom filter would be +** appropriate, and if so sets the WHERE_BLOOMFILTER flag on the +** WhereLoop. The implementation of the Bloom filter comes further +** down where the code for each WhereLoop is generated. +*/ +static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful( + const WhereInfo *pWInfo +){ + int i; + LogEst nSearch; + + assert( pWInfo->nLevel>=2 ); + assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) ); + nSearch = pWInfo->a[0].pWLoop->nOut; + for(i=1; inLevel; i++){ + WhereLoop *pLoop = pWInfo->a[i].pWLoop; + const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ); + if( (pLoop->wsFlags & reqFlags)==reqFlags + /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */ + && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0) + ){ + SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; + Table *pTab = pItem->pTab; + pTab->tabFlags |= TF_StatsUsed; + if( nSearch > pTab->nRowLogEst + && (pTab->tabFlags & TF_HasStat1)!=0 + ){ + testcase( pItem->fg.jointype & JT_LEFT ); + pLoop->wsFlags |= WHERE_BLOOMFILTER; + pLoop->wsFlags &= ~WHERE_IDX_ONLY; + WHERETRACE(0xffff, ( + "-> use Bloom-filter on loop %c because there are ~%.1e " + "lookups into %s which has only ~%.1e rows\n", + pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName, + (double)sqlite3LogEstToInt(pTab->nRowLogEst))); + } + } + nSearch += pLoop->nOut; + } +} + /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an opaque structure that contains @@ -133670,7 +157335,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ** if there is one. If there is no ORDER BY clause or if this routine ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. ** -** The iIdxCur parameter is the cursor number of an index. If +** The iIdxCur parameter is the cursor number of an index. If ** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index ** to use for OR clause processing. The WHERE clause should use this ** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is @@ -133683,7 +157348,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ - ExprList *pDistinctSet, /* Try not to output two rows that duplicate these */ + ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */ + Select *pLimit, /* Use this LIMIT/OFFSET clause, if any */ u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number ** If WHERE_USE_LIMIT, then the limit amount */ @@ -133703,8 +157369,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */ assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || ( - (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 - && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 + && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 )); /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */ @@ -133718,16 +157384,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; - sWLB.pOrderBy = pOrderBy; - - /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via - ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ - if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ - wctrlFlags &= ~WHERE_WANT_DISTINCT; - } /* The number of tables in the FROM clause is limited by the number of - ** bits in a Bitmask + ** bits in a Bitmask */ testcase( pTabList->nSrc==BMS ); if( pTabList->nSrc>BMS ){ @@ -133735,7 +157394,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( return 0; } - /* This function normally generates a nested loop for all tables in + /* This function normally generates a nested loop for all tables in ** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should ** only generate code for the first table in pTabList and assume that ** any cursors associated with subsequent tables are uninitialized. @@ -133759,18 +157418,26 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( pWInfo->pParse = pParse; pWInfo->pTabList = pTabList; pWInfo->pOrderBy = pOrderBy; - pWInfo->pDistinctSet = pDistinctSet; + pWInfo->pWhere = pWhere; + pWInfo->pResultSet = pResultSet; pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1; pWInfo->nLevel = nTabList; - pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v); + pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(pParse); pWInfo->wctrlFlags = wctrlFlags; pWInfo->iLimit = iAuxArg; pWInfo->savedNQueryLoop = pParse->nQueryLoop; - memset(&pWInfo->nOBSat, 0, +#ifndef SQLITE_OMIT_VIRTUALTABLE + pWInfo->pLimit = pLimit; +#endif + memset(&pWInfo->nOBSat, 0, offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat)); memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel)); assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */ pMaskSet = &pWInfo->sMaskSet; + pMaskSet->n = 0; + pMaskSet->ix[0] = -99; /* Initialize ix[0] to a value that can never be + ** a valid cursor number, to avoid an initial + ** test for pMaskSet->n==0 in sqlite3WhereGetMask() */ sWLB.pWInfo = pWInfo; sWLB.pWC = &pWInfo->sWC; sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo); @@ -133783,67 +157450,89 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. */ - initMaskSet(pMaskSet); sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo); sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND); - - /* Special case: a WHERE clause that is constant. Evaluate the - ** expression and either jump over all of the code or fall thru. - */ - for(ii=0; iinTerm; ii++){ - if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){ - sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak, - SQLITE_JUMPIFNULL); - sWLB.pWC->a[ii].wtFlags |= TERM_CODED; - } - } /* Special case: No FROM clause */ if( nTabList==0 ){ if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; - if( wctrlFlags & WHERE_WANT_DISTINCT ){ + if( (wctrlFlags & WHERE_WANT_DISTINCT)!=0 + && OptimizationEnabled(db, SQLITE_DistinctOpt) + ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } + ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); + }else{ + /* Assign a bit from the bitmask to every term in the FROM clause. + ** + ** The N-th term of the FROM clause is assigned a bitmask of 1<nSrc tables in + ** pTabList, not just the first nTabList tables. nTabList is normally + ** equal to pTabList->nSrc but might be shortened to 1 if the + ** WHERE_OR_SUBCLAUSE flag is set. + */ + ii = 0; + do{ + createMask(pMaskSet, pTabList->a[ii].iCursor); + sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); + }while( (++ii)nSrc ); + #ifdef SQLITE_DEBUG + { + Bitmask mx = 0; + for(ii=0; iinSrc; ii++){ + Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); + assert( m>=mx ); + mx = m; + } + } + #endif } - /* Assign a bit from the bitmask to every term in the FROM clause. - ** - ** The N-th term of the FROM clause is assigned a bitmask of 1<sWC); + sqlite3WhereAddLimit(&pWInfo->sWC, pLimit); + if( db->mallocFailed ) goto whereBeginError; + + /* Special case: WHERE terms that do not refer to any tables in the join + ** (constant expressions). Evaluate each such term, and jump over all the + ** generated code if the result is not true. ** - ** The rule of the previous sentence ensures thta if X is the bitmask for - ** a table T, then X-1 is the bitmask for all other tables to the left of T. - ** Knowing the bitmask for all tables to the left of a left join is - ** important. Ticket #3015. + ** Do not do this if the expression contains non-deterministic functions + ** that are not within a sub-select. This is not strictly required, but + ** preserves SQLite's legacy behaviour in the following two cases: ** - ** Note that bitmasks are created for all pTabList->nSrc tables in - ** pTabList, not just the first nTabList tables. nTabList is normally - ** equal to pTabList->nSrc but might be shortened to 1 if the - ** WHERE_OR_SUBCLAUSE flag is set. + ** FROM ... WHERE random()>0; -- eval random() once per row + ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ - for(ii=0; iinSrc; ii++){ - createMask(pMaskSet, pTabList->a[ii].iCursor); - sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); - } -#ifdef SQLITE_DEBUG - for(ii=0; iinSrc; ii++){ - Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); - assert( m==MASKBIT(ii) ); + for(ii=0; iinBase; ii++){ + WhereTerm *pT = &sWLB.pWC->a[ii]; + if( pT->wtFlags & TERM_VIRTUAL ) continue; + if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ + sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); + pT->wtFlags |= TERM_CODED; + } } -#endif - - /* Analyze all of the subexpressions. */ - sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); - if( db->mallocFailed ) goto whereBeginError; if( wctrlFlags & WHERE_WANT_DISTINCT ){ - if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pDistinctSet) ){ + if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ + /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via + ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ + wctrlFlags &= ~WHERE_WANT_DISTINCT; + pWInfo->wctrlFlags &= ~WHERE_WANT_DISTINCT; + }else if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; }else if( pOrderBy==0 ){ /* Try to ORDER BY the result set to make distinct processing easier */ pWInfo->wctrlFlags |= WHERE_DISTINCTBY; - pWInfo->pOrderBy = pDistinctSet; + pWInfo->pOrderBy = pResultSet; } } @@ -133855,8 +157544,19 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); + if( sqlite3WhereTrace & 0x100 ){ + Select sSelect; + memset(&sSelect, 0, sizeof(sSelect)); + sSelect.selFlags = SF_WhereBegin; + sSelect.pSrc = pTabList; + sSelect.pWhere = pWhere; + sSelect.pOrderBy = pOrderBy; + sSelect.pEList = pResultSet; + sqlite3TreeViewSelect(0, &sSelect, 0); + } } if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ + sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n"); sqlite3WhereClausePrint(sWLB.pWC); } #endif @@ -133864,20 +157564,29 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; - -#ifdef WHERETRACE_ENABLED - if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */ - WhereLoop *p; - int i; - static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" - "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; - for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ - p->cId = zLabel[i%sizeof(zLabel)]; - whereLoopPrint(p, sWLB.pWC); - } - } -#endif - + +#ifdef SQLITE_ENABLE_STAT4 + /* If one or more WhereTerm.truthProb values were used in estimating + ** loop parameters, but then those truthProb values were subsequently + ** changed based on STAT4 information while computing subsequent loops, + ** then we need to rerun the whole loop building process so that all + ** loops will be built using the revised truthProb values. */ + if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){ + WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC); + WHERETRACE(0xffff, + ("**** Redo all loop computations due to" + " TERM_HIGHTRUTH changes ****\n")); + while( pWInfo->pLoops ){ + WhereLoop *p = pWInfo->pLoops; + pWInfo->pLoops = p->pNextLoop; + whereLoopDelete(db, p); + } + rc = whereLoopAddAll(&sWLB); + if( rc ) goto whereBeginError; + } +#endif + WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC); + wherePathSolver(pWInfo, 0); if( db->mallocFailed ) goto whereBeginError; if( pWInfo->pOrderBy ){ @@ -133888,9 +157597,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ pWInfo->revMask = ALLBITS; } - if( pParse->nErr || NEVER(db->mallocFailed) ){ + if( pParse->nErr ){ goto whereBeginError; } + assert( db->mallocFailed==0 ); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); @@ -133913,57 +157623,79 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } sqlite3DebugPrintf("\n"); for(ii=0; iinLevel; ii++){ - whereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC); + sqlite3WhereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC); } } #endif - /* Attempt to omit tables from the join that do not effect the result */ + + /* Attempt to omit tables from a join that do not affect the result. + ** See the comment on whereOmitNoopJoin() for further information. + ** + ** This query optimization is factored out into a separate "no-inline" + ** procedure to keep the sqlite3WhereBegin() procedure from becoming + ** too large. If sqlite3WhereBegin() becomes too large, that prevents + ** some C-compiler optimizers from in-lining the + ** sqlite3WhereCodeOneLoopStart() procedure, and it is important to + ** in-line sqlite3WhereCodeOneLoopStart() for performance reasons. + */ + notReady = ~(Bitmask)0; if( pWInfo->nLevel>=2 - && pDistinctSet!=0 + && pResultSet!=0 /* these two combine to guarantee */ + && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */ && OptimizationEnabled(db, SQLITE_OmitNoopJoin) ){ - Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pDistinctSet); - if( sWLB.pOrderBy ){ - tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); - } - while( pWInfo->nLevel>=2 ){ - WhereTerm *pTerm, *pEnd; - pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; - if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break; - if( (wctrlFlags & WHERE_WANT_DISTINCT)==0 - && (pLoop->wsFlags & WHERE_ONEROW)==0 - ){ - break; - } - if( (tabUsed & pLoop->maskSelf)!=0 ) break; - pEnd = sWLB.pWC->a + sWLB.pWC->nTerm; - for(pTerm=sWLB.pWC->a; pTermprereqAll & pLoop->maskSelf)!=0 - && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) - ){ - break; - } - } - if( pTerm drop loop %c not used\n", pLoop->cId)); - pWInfo->nLevel--; - nTabList--; - } + notReady = whereOmitNoopJoin(pWInfo, notReady); + nTabList = pWInfo->nLevel; + assert( nTabList>0 ); + } + + /* Check to see if there are any SEARCH loops that might benefit from + ** using a Bloom filter. + */ + if( pWInfo->nLevel>=2 + && OptimizationEnabled(db, SQLITE_BloomFilter) + ){ + whereCheckIfBloomFilterIsUseful(pWInfo); + } + +#if defined(WHERETRACE_ENABLED) + if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ + sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n"); + sqlite3WhereClausePrint(sWLB.pWC); } WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); +#endif pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. + ** + ** A one-pass approach can be used if the caller has requested one + ** and either (a) the scan visits at most one row or (b) each + ** of the following are true: + ** + ** * the caller has indicated that a one-pass approach can be used + ** with multiple rows (by setting WHERE_ONEPASS_MULTIROW), and + ** * the table is not a virtual table, and + ** * either the scan does not use the OR optimization or the caller + ** is a DELETE operation (WHERE_DUPLICATES_OK is only specified + ** for DELETE). + ** + ** The last qualification is because an UPDATE statement uses + ** WhereInfo.aiCurOnePass[1] to determine whether or not it really can + ** use a one-pass approach, and this is not set accurately for scans + ** that use the OR optimization. */ assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ int wsFlags = pWInfo->a[0].pWLoop->wsFlags; int bOnerow = (wsFlags & WHERE_ONEROW)!=0; - if( bOnerow - || ((wctrlFlags & WHERE_ONEPASS_MULTIROW)!=0 - && 0==(wsFlags & WHERE_VIRTUALTABLE)) - ){ + assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); + if( bOnerow || ( + 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) + && !IsVirtual(pTabList->a[0].pTab) + && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) + )){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ @@ -133980,13 +157712,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( for(ii=0, pLevel=pWInfo->a; iia[pLevel->iFrom]; pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; - if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){ + if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ /* Do nothing */ }else #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -134009,7 +157741,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( assert( pTabItem->iCursor==pLevel->iTabCur ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 ); testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS ); - if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nColeOnePass==ONEPASS_OFF + && pTab->nColtabFlags & (TF_HasGenerated|TF_WithoutRowid))==0 + && (pLoop->wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))==0 + ){ + /* If we know that only a prefix of the record will be used, + ** it is advantageous to reduce the "column count" field in + ** the P4 operand of the OP_OpenRead/Write opcode. */ Bitmask b = pTabItem->colUsed; int n = 0; for(; b; b=b>>1, n++){} @@ -134035,7 +157774,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( Index *pIx = pLoop->u.btree.pIndex; int iIndexCur; int op = OP_OpenRead; - /* iAuxArg is always set if to a positive value if ONEPASS is possible */ + /* iAuxArg is always set to a positive value if ONEPASS is possible */ assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 @@ -134068,9 +157807,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( sqlite3VdbeSetP4KeyInfo(pParse, pIx); if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 + && (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0 + && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 + && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED ){ - sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ + sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); } VdbeComment((v, "%s", pIx->zName)); #ifdef SQLITE_ENABLE_COLUMN_USED_MASK @@ -134099,24 +157841,28 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( ** loop below generates code for a single nested loop of the VM ** program. */ - notReady = ~(Bitmask)0; for(ii=0; iinErr ) goto whereBeginError; pLevel = &pWInfo->a[ii]; wsFlags = pLevel->pWLoop->wsFlags; + if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){ + if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){ #ifndef SQLITE_OMIT_AUTOMATIC_INDEX - if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ - constructAutomaticIndex(pParse, &pWInfo->sWC, - &pTabList->a[pLevel->iFrom], notReady, pLevel); + constructAutomaticIndex(pParse, &pWInfo->sWC, + &pTabList->a[pLevel->iFrom], notReady, pLevel); +#endif + }else{ + sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady); + } if( db->mallocFailed ) goto whereBeginError; } -#endif addrExplain = sqlite3WhereExplainOneScan( - pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags + pParse, pTabList, pLevel, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); - notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); + notReady = sqlite3WhereCodeOneLoopStart(pParse,v,pWInfo,ii,pLevel,notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); @@ -134125,11 +157871,14 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); + pWInfo->iEndWhere = sqlite3VdbeCurrentAddr(v); return pWInfo; /* Jump here if malloc fails */ whereBeginError: if( pWInfo ){ + testcase( pWInfo->pExprMods!=0 ); + whereUndoExprMods(pWInfo); pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); } @@ -134137,7 +157886,47 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( } /* -** Generate the end of the WHERE loop. See comments on +** Part of sqlite3WhereEnd() will rewrite opcodes to reference the +** index rather than the main table. In SQLITE_DEBUG mode, we want +** to trace those changes if PRAGMA vdbe_addoptrace=on. This routine +** does that. +*/ +#ifndef SQLITE_DEBUG +# define OpcodeRewriteTrace(D,K,P) /* no-op */ +#else +# define OpcodeRewriteTrace(D,K,P) sqlite3WhereOpcodeRewriteTrace(D,K,P) + static void sqlite3WhereOpcodeRewriteTrace( + sqlite3 *db, + int pc, + VdbeOp *pOp + ){ + if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return; + sqlite3VdbePrintOp(0, pc, pOp); + } +#endif + +#ifdef SQLITE_DEBUG +/* +** Return true if cursor iCur is opened by instruction k of the +** bytecode. Used inside of assert() only. +*/ +static int cursorIsOpen(Vdbe *v, int iCur, int k){ + while( k>=0 ){ + VdbeOp *pOp = sqlite3VdbeGetOp(v,k--); + if( pOp->p1!=iCur ) continue; + if( pOp->opcode==OP_Close ) return 0; + if( pOp->opcode==OP_OpenRead ) return 1; + if( pOp->opcode==OP_OpenWrite ) return 1; + if( pOp->opcode==OP_OpenDup ) return 1; + if( pOp->opcode==OP_OpenAutoindex ) return 1; + if( pOp->opcode==OP_OpenEphemeral ) return 1; + } + return 0; +} +#endif /* SQLITE_DEBUG */ + +/* +** Generate the end of the WHERE loop. See comments on ** sqlite3WhereBegin() for additional information. */ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ @@ -134148,35 +157937,101 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; + int iEnd = sqlite3VdbeCurrentAddr(v); /* Generate loop termination code. */ VdbeModuleComment((v, "End WHERE-core")); - sqlite3ExprCacheClear(pParse); for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; pLoop = pLevel->pWLoop; - sqlite3VdbeResolveLabel(v, pLevel->addrCont); if( pLevel->op!=OP_Noop ){ +#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + int addrSeek = 0; + Index *pIdx; + int n; + if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED + && i==pWInfo->nLevel-1 /* Ticket [ef9318757b152e3] 2017-10-21 */ + && (pLoop->wsFlags & WHERE_INDEXED)!=0 + && (pIdx = pLoop->u.btree.pIndex)->hasStat1 + && (n = pLoop->u.btree.nDistinctCol)>0 + && pIdx->aiRowLogEst[n]>=36 + ){ + int r1 = pParse->nMem+1; + int j, op; + for(j=0; jiIdxCur, j, r1+j); + } + pParse->nMem += n+1; + op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT; + addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n); + VdbeCoverageIf(v, op==OP_SeekLT); + VdbeCoverageIf(v, op==OP_SeekGT); + sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); + } +#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ + /* The common case: Advance to the next row */ + sqlite3VdbeResolveLabel(v, pLevel->addrCont); sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3); sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); + if( pLevel->regBignull ){ + sqlite3VdbeResolveLabel(v, pLevel->addrBignull); + sqlite3VdbeAddOp2(v, OP_DecrJumpZero, pLevel->regBignull, pLevel->p2-1); + VdbeCoverage(v); + } +#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT + if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); +#endif + }else{ + sqlite3VdbeResolveLabel(v, pLevel->addrCont); } - if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ + if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ + assert( sqlite3VdbeGetOp(v, pIn->addrInTop+1)->opcode==OP_IsNull + || pParse->db->mallocFailed ); sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ + if( pIn->nPrefix ){ + int bEarlyOut = + (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 + && (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0; + if( pLevel->iLeftJoin ){ + /* For LEFT JOIN queries, cursor pIn->iCur may not have been + ** opened yet. This occurs for WHERE clauses such as + ** "a = ? AND b IN (...)", where the index is on (a, b). If + ** the RHS of the (a=?) is NULL, then the "b IN (...)" may + ** never have been coded, but the body of the loop run to + ** return the null-row. So, if the cursor is not open yet, + ** jump over the OP_Next or OP_Prev instruction about to + ** be coded. */ + sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur, + sqlite3VdbeCurrentAddr(v) + 2 + bEarlyOut); + VdbeCoverage(v); + } + if( bEarlyOut ){ + sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, + sqlite3VdbeCurrentAddr(v)+2, + pIn->iBase, pIn->nPrefix); + VdbeCoverage(v); + /* Retarget the OP_IsNull against the left operand of IN so + ** it jumps past the OP_IfNoHope. This is because the + ** OP_IsNull also bypasses the OP_Affinity opcode that is + ** required by OP_IfNoHope. */ + sqlite3VdbeJumpHere(v, pIn->addrInTop+1); + } + } sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); VdbeCoverage(v); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen); - VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev); + VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next); } sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } @@ -134200,11 +158055,18 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); if( (ws & WHERE_IDX_ONLY)==0 ){ - sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor); + assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor ); + sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); } - if( (ws & WHERE_INDEXED) - || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx) + if( (ws & WHERE_INDEXED) + || ((ws & WHERE_MULTI_OR) && pLevel->u.pCoveringIdx) ){ + if( ws & WHERE_MULTI_OR ){ + Index *pIx = pLevel->u.pCoveringIdx; + int iDb = sqlite3SchemaToIndex(db, pIx->pSchema); + sqlite3VdbeAddOp3(v, OP_ReopenIdx, pLevel->iIdxCur, pIx->tnum, iDb); + sqlite3VdbeSetP4KeyInfo(pParse, pIx); + } sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } if( pLevel->op==OP_Return ){ @@ -134226,9 +158088,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ int k, last; - VdbeOp *pOp; + VdbeOp *pOp, *pLastOp; Index *pIdx = 0; - struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; + SrcItem *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; assert( pTab!=0 ); pLoop = pLevel->pWLoop; @@ -134237,17 +158099,41 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. */ - if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){ - translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur, + if( pTabItem->fg.viaCoroutine ){ + testcase( pParse->db->mallocFailed ); + translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult, 0); continue; } +#ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE + /* Close all of the cursors that were opened by sqlite3WhereBegin. + ** Except, do not close cursors that will be reused by the OR optimization + ** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors + ** created for the ONEPASS optimization. + */ + if( (pTab->tabFlags & TF_Ephemeral)==0 + && !IsView(pTab) + && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 + ){ + int ws = pLoop->wsFlags; + if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){ + sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); + } + if( (ws & WHERE_INDEXED)!=0 + && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 + && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1] + ){ + sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); + } + } +#endif + /* If this scan uses an index, make VDBE code substitutions to read data ** from the index instead of from the table where possible. In some cases ** this optimization prevents the table from ever being read, which can ** yield a significant performance boost. - ** + ** ** Calls to the code generator in between sqlite3WhereBegin and ** sqlite3WhereEnd will have created code that references the table ** directly. This loop scans all that code looking for opcodes @@ -134257,51 +158143,104 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){ pIdx = pLoop->u.btree.pIndex; }else if( pLoop->wsFlags & WHERE_MULTI_OR ){ - pIdx = pLevel->u.pCovidx; + pIdx = pLevel->u.pCoveringIdx; } if( pIdx - && (pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable)) && !db->mallocFailed ){ - last = sqlite3VdbeCurrentAddr(v); - k = pLevel->addrBody; + if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){ + last = iEnd; + }else{ + last = pWInfo->iEndWhere; + } + k = pLevel->addrBody + 1; +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_VdbeAddopTrace ){ + printf("TRANSLATE opcodes in range %d..%d\n", k, last-1); + } + /* Proof that the "+1" on the k value above is safe */ + pOp = sqlite3VdbeGetOp(v, k - 1); + assert( pOp->opcode!=OP_Column || pOp->p1!=pLevel->iTabCur ); + assert( pOp->opcode!=OP_Rowid || pOp->p1!=pLevel->iTabCur ); + assert( pOp->opcode!=OP_IfNullRow || pOp->p1!=pLevel->iTabCur ); +#endif pOp = sqlite3VdbeGetOp(v, k); - for(; kp1!=pLevel->iTabCur ) continue; - if( pOp->opcode==OP_Column ){ + pLastOp = pOp + (last - k); + assert( pOp<=pLastOp ); + do{ + if( pOp->p1!=pLevel->iTabCur ){ + /* no-op */ + }else if( pOp->opcode==OP_Column +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + || pOp->opcode==OP_Offset +#endif + ){ int x = pOp->p2; assert( pIdx->pTable==pTab ); +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + if( pOp->opcode==OP_Offset ){ + /* Do not need to translate the column number */ + }else +#endif if( !HasRowid(pTab) ){ Index *pPk = sqlite3PrimaryKeyIndex(pTab); x = pPk->aiColumn[x]; assert( x>=0 ); + }else{ + testcase( x!=sqlite3StorageColumnToTable(pTab,x) ); + x = sqlite3StorageColumnToTable(pTab,x); } - x = sqlite3ColumnOfIndex(pIdx, x); + x = sqlite3TableColumnToIndex(pIdx, x); if( x>=0 ){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; + OpcodeRewriteTrace(db, k, pOp); + }else{ + /* Unable to translate the table reference into an index + ** reference. Verify that this is harmless - that the + ** table being referenced really is open. + */ +#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 + || cursorIsOpen(v,pOp->p1,k) + || pOp->opcode==OP_Offset + ); +#else + assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 + || cursorIsOpen(v,pOp->p1,k) + ); +#endif } - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 - || pWInfo->eOnePass ); }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur; pOp->opcode = OP_IdxRowid; + OpcodeRewriteTrace(db, k, pOp); + }else if( pOp->opcode==OP_IfNullRow ){ + pOp->p1 = pLevel->iIdxCur; + OpcodeRewriteTrace(db, k, pOp); } - } +#ifdef SQLITE_DEBUG + k++; +#endif + }while( (++pOp)flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n"); +#endif } } /* Final cleanup */ + if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo); pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); return; } /************** End of where.c ***********************************************/ -/************** Begin file parse.c *******************************************/ +/************** Begin file window.c ******************************************/ /* -** 2000-05-29 +** 2018 May 08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -134311,4986 +158250,3107 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** Driver template for the LEMON parser generator. -** -** The "lemon" program processes an LALR(1) input grammar file, then uses -** this template to construct a parser. The "lemon" program inserts text -** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the -** interstitial "-" characters) contained in this template is changed into -** the value of the %name directive from the grammar. Otherwise, the content -** of this template is copied straight through into the generate parser -** source file. -** -** The following is the concatenation of all %include directives from the -** input grammar file: */ -/* #include */ -/************ Begin %include sections from the grammar ************************/ - /* #include "sqliteInt.h" */ -/* -** Disable all error recovery processing in the parser push-down -** automaton. -*/ -#define YYNOERRORRECOVERY 1 - -/* -** Make yytestcase() the same as testcase() -*/ -#define yytestcase(X) testcase(X) - -/* -** Indicate that sqlite3ParserFree() will never be called with a null -** pointer. -*/ -#define YYPARSEFREENEVERNULL 1 - -/* -** In the amalgamation, the parse.c file generated by lemon and the -** tokenize.c file are concatenated. In that case, sqlite3RunParser() -** has access to the the size of the yyParser object and so the parser -** engine can be allocated from stack. In that case, only the -** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked -** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be -** omitted. -*/ -#ifdef SQLITE_AMALGAMATION -# define sqlite3Parser_ENGINEALWAYSONSTACK 1 -#endif - -/* -** Alternative datatype for the argument to the malloc() routine passed -** into sqlite3ParserAlloc(). The default is size_t. -*/ -#define YYMALLOCARGTYPE u64 - -/* -** An instance of this structure holds information about the -** LIMIT clause of a SELECT statement. -*/ -struct LimitVal { - Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */ - Expr *pOffset; /* The OFFSET expression. NULL if there is none */ -}; +#ifndef SQLITE_OMIT_WINDOWFUNC /* -** An instance of the following structure describes the event of a -** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, -** TK_DELETE, or TK_INSTEAD. If the event is of the form +** SELECT REWRITING ** -** UPDATE ON (a,b,c) +** Any SELECT statement that contains one or more window functions in +** either the select list or ORDER BY clause (the only two places window +** functions may be used) is transformed by function sqlite3WindowRewrite() +** in order to support window function processing. For example, with the +** schema: ** -** Then the "b" IdList records the list "a,b,c". -*/ -struct TrigEvent { int a; IdList * b; }; - -/* -** Disable lookaside memory allocation for objects that might be -** shared across database connections. -*/ -static void disableLookaside(Parse *pParse){ - pParse->disableLookaside++; - pParse->db->lookaside.bDisable++; -} - - - /* - ** For a compound SELECT statement, make sure p->pPrior->pNext==p for - ** all elements in the list. And make sure list length does not exceed - ** SQLITE_LIMIT_COMPOUND_SELECT. - */ - static void parserDoubleLinkSelect(Parse *pParse, Select *p){ - if( p->pPrior ){ - Select *pNext = 0, *pLoop; - int mxSelect, cnt = 0; - for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ - pLoop->pNext = pNext; - pLoop->selFlags |= SF_Compound; - } - if( (p->selFlags & SF_MultiValue)==0 && - (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && - cnt>mxSelect - ){ - sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); - } - } - } - - /* This is a utility routine used to set the ExprSpan.zStart and - ** ExprSpan.zEnd values of pOut so that the span covers the complete - ** range of text beginning with pStart and going to the end of pEnd. - */ - static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){ - pOut->zStart = pStart->z; - pOut->zEnd = &pEnd->z[pEnd->n]; - } - - /* Construct a new Expr object from a single identifier. Use the - ** new Expr to populate pOut. Set the span of pOut to be the identifier - ** that created the expression. - */ - static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){ - Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); - if( p ){ - memset(p, 0, sizeof(Expr)); - p->op = (u8)op; - p->flags = EP_Leaf; - p->iAgg = -1; - p->u.zToken = (char*)&p[1]; - memcpy(p->u.zToken, t.z, t.n); - p->u.zToken[t.n] = 0; - if( sqlite3Isquote(p->u.zToken[0]) ){ - if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted; - sqlite3Dequote(p->u.zToken); - } -#if SQLITE_MAX_EXPR_DEPTH>0 - p->nHeight = 1; -#endif - } - pOut->pExpr = p; - pOut->zStart = t.z; - pOut->zEnd = &t.z[t.n]; - } - - /* This routine constructs a binary expression node out of two ExprSpan - ** objects and uses the result to populate a new ExprSpan object. - */ - static void spanBinaryExpr( - Parse *pParse, /* The parsing context. Errors accumulate here */ - int op, /* The binary operation */ - ExprSpan *pLeft, /* The left operand, and output */ - ExprSpan *pRight /* The right operand */ - ){ - pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr); - pLeft->zEnd = pRight->zEnd; - } - - /* If doNot is true, then add a TK_NOT Expr-node wrapper around the - ** outside of *ppExpr. - */ - static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){ - if( doNot ){ - pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0); - } - } - - /* Construct an expression node for a unary postfix operator - */ - static void spanUnaryPostfix( - Parse *pParse, /* Parsing context to record errors */ - int op, /* The operator */ - ExprSpan *pOperand, /* The operand, and output */ - Token *pPostOp /* The operand token for setting the span */ - ){ - pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); - pOperand->zEnd = &pPostOp->z[pPostOp->n]; - } - - /* A routine to convert a binary TK_IS or TK_ISNOT expression into a - ** unary TK_ISNULL or TK_NOTNULL expression. */ - static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ - sqlite3 *db = pParse->db; - if( pA && pY && pY->op==TK_NULL ){ - pA->op = (u8)op; - sqlite3ExprDelete(db, pA->pRight); - pA->pRight = 0; - } - } - - /* Construct an expression node for a unary prefix operator - */ - static void spanUnaryPrefix( - ExprSpan *pOut, /* Write the new expression node here */ - Parse *pParse, /* Parsing context to record errors */ - int op, /* The operator */ - ExprSpan *pOperand, /* The operand */ - Token *pPreOp /* The operand token for setting the span */ - ){ - pOut->zStart = pPreOp->z; - pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); - pOut->zEnd = pOperand->zEnd; - } - - /* Add a single new term to an ExprList that is used to store a - ** list of identifiers. Report an error if the ID list contains - ** a COLLATE clause or an ASC or DESC keyword, except ignore the - ** error while parsing a legacy schema. - */ - static ExprList *parserAddExprIdListTerm( - Parse *pParse, - ExprList *pPrior, - Token *pIdToken, - int hasCollate, - int sortOrder - ){ - ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); - if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) - && pParse->db->init.busy==0 - ){ - sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", - pIdToken->n, pIdToken->z); - } - sqlite3ExprListSetName(pParse, p, pIdToken, 1); - return p; - } -/**************** End of %include directives **********************************/ -/* These constants specify the various numeric values for terminal symbols -** in a format understandable to "makeheaders". This section is blank unless -** "lemon" is run with the "-m" command-line option. -***************** Begin makeheaders token definitions *************************/ -/**************** End makeheaders token definitions ***************************/ - -/* The next sections is a series of control #defines. -** various aspects of the generated parser. -** YYCODETYPE is the data type used to store the integer codes -** that represent terminal and non-terminal symbols. -** "unsigned char" is used if there are fewer than -** 256 symbols. Larger types otherwise. -** YYNOCODE is a number of type YYCODETYPE that is not used for -** any terminal or nonterminal symbol. -** YYFALLBACK If defined, this indicates that one or more tokens -** (also known as: "terminal symbols") have fall-back -** values which should be used if the original symbol -** would not parse. This permits keywords to sometimes -** be used as identifiers, for example. -** YYACTIONTYPE is the data type used for "action codes" - numbers -** that indicate what to do in response to the next -** token. -** sqlite3ParserTOKENTYPE is the data type used for minor type for terminal -** symbols. Background: A "minor type" is a semantic -** value associated with a terminal or non-terminal -** symbols. For example, for an "ID" terminal symbol, -** the minor type might be the name of the identifier. -** Each non-terminal can have a different minor type. -** Terminal symbols all have the same minor type, though. -** This macros defines the minor type for terminal -** symbols. -** YYMINORTYPE is the data type used for all minor types. -** This is typically a union of many types, one of -** which is sqlite3ParserTOKENTYPE. The entry in the union -** for terminal symbols is called "yy0". -** YYSTACKDEPTH is the maximum depth of the parser's stack. If -** zero the stack is dynamically sized using realloc() -** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument -** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument -** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser -** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser -** YYERRORSYMBOL is the code number of the error symbol. If not -** defined, then do no error processing. -** YYNSTATE the combined number of states. -** YYNRULE the number of rules in the grammar -** YY_MAX_SHIFT Maximum value for shift actions -** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions -** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** YY_MIN_REDUCE Maximum value for reduce actions -** YY_ERROR_ACTION The yy_action[] code for syntax error -** YY_ACCEPT_ACTION The yy_action[] code for accept -** YY_NO_ACTION The yy_action[] code for no-op -*/ -#ifndef INTERFACE -# define INTERFACE 1 -#endif -/************* Begin control #defines *****************************************/ -#define YYCODETYPE unsigned char -#define YYNOCODE 252 -#define YYACTIONTYPE unsigned short int -#define YYWILDCARD 96 -#define sqlite3ParserTOKENTYPE Token -typedef union { - int yyinit; - sqlite3ParserTOKENTYPE yy0; - Expr* yy72; - TriggerStep* yy145; - ExprList* yy148; - SrcList* yy185; - ExprSpan yy190; - int yy194; - Select* yy243; - IdList* yy254; - With* yy285; - struct TrigEvent yy332; - struct LimitVal yy354; - struct {int value; int mask;} yy497; -} YYMINORTYPE; -#ifndef YYSTACKDEPTH -#define YYSTACKDEPTH 100 -#endif -#define sqlite3ParserARG_SDECL Parse *pParse; -#define sqlite3ParserARG_PDECL ,Parse *pParse -#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse -#define sqlite3ParserARG_STORE yypParser->pParse = pParse -#define YYFALLBACK 1 -#define YYNSTATE 456 -#define YYNRULE 332 -#define YY_MAX_SHIFT 455 -#define YY_MIN_SHIFTREDUCE 668 -#define YY_MAX_SHIFTREDUCE 999 -#define YY_MIN_REDUCE 1000 -#define YY_MAX_REDUCE 1331 -#define YY_ERROR_ACTION 1332 -#define YY_ACCEPT_ACTION 1333 -#define YY_NO_ACTION 1334 -/************* End control #defines *******************************************/ - -/* Define the yytestcase() macro to be a no-op if is not already defined -** otherwise. +** CREATE TABLE t1(a, b, c, d, e, f, g); ** -** Applications can choose to define yytestcase() in the %include section -** to a macro that can assist in verifying code coverage. For production -** code the yytestcase() macro should be turned off. But it is useful -** for testing. -*/ -#ifndef yytestcase -# define yytestcase(X) -#endif - - -/* Next are the tables used to determine what action to take based on the -** current state and lookahead token. These tables are used to implement -** functions that take a state number and lookahead value and return an -** action integer. +** the statement: ** -** Suppose the action integer is N. Then the action is determined as -** follows +** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM t1 ORDER BY e; ** -** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead -** token onto the stack and goto state N. +** is transformed to: ** -** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then -** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. +** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM ( +** SELECT a, e, c, d, b FROM t1 ORDER BY c, d +** ) ORDER BY e; ** -** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE -** and YY_MAX_REDUCE +** The flattening optimization is disabled when processing this transformed +** SELECT statement. This allows the implementation of the window function +** (in this case max()) to process rows sorted in order of (c, d), which +** makes things easier for obvious reasons. More generally: ** -** N == YY_ERROR_ACTION A syntax error has occurred. +** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to +** the sub-query. ** -** N == YY_ACCEPT_ACTION The parser accepts its input. +** * ORDER BY, LIMIT and OFFSET remain part of the parent query. ** -** N == YY_NO_ACTION No such action. Denotes unused -** slots in the yy_action[] table. +** * Terminals from each of the expression trees that make up the +** select-list and ORDER BY expressions in the parent query are +** selected by the sub-query. For the purposes of the transformation, +** terminals are column references and aggregate functions. ** -** The action table is constructed as a single large table named yy_action[]. -** Given state S and lookahead X, the action is computed as either: +** If there is more than one window function in the SELECT that uses +** the same window declaration (the OVER bit), then a single scan may +** be used to process more than one window function. For example: ** -** (A) N = yy_action[ yy_shift_ofst[S] + X ] -** (B) N = yy_default[S] +** SELECT max(b) OVER (PARTITION BY c ORDER BY d), +** min(e) OVER (PARTITION BY c ORDER BY d) +** FROM t1; ** -** The (A) formula is preferred. The B formula is used instead if: -** (1) The yy_shift_ofst[S]+X value is out of range, or -** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or -** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. -** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that -** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. -** Hence only tests (1) and (2) need to be evaluated.) +** is transformed in the same way as the example above. However: ** -** The formulas above are for computing the action when the lookahead is -** a terminal symbol. If the lookahead is a non-terminal (as occurs after -** a reduce action) then the yy_reduce_ofst[] array is used in place of -** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of -** YY_SHIFT_USE_DFLT. +** SELECT max(b) OVER (PARTITION BY c ORDER BY d), +** min(e) OVER (PARTITION BY a ORDER BY b) +** FROM t1; ** -** The following are the tables generated in this section: +** Must be transformed to: ** -** yy_action[] A single table containing all actions. -** yy_lookahead[] A table containing the lookahead for each entry in -** yy_action. Used to detect hash collisions. -** yy_shift_ofst[] For each state, the offset into yy_action for -** shifting terminals. -** yy_reduce_ofst[] For each state, the offset into yy_action for -** shifting non-terminals after a reduce. -** yy_default[] Default action for each state. +** SELECT max(b) OVER (PARTITION BY c ORDER BY d) FROM ( +** SELECT e, min(e) OVER (PARTITION BY a ORDER BY b), c, d, b FROM +** SELECT a, e, c, d, b FROM t1 ORDER BY a, b +** ) ORDER BY c, d +** ) ORDER BY e; ** -*********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (1567) -static const YYACTIONTYPE yy_action[] = { - /* 0 */ 325, 832, 351, 825, 5, 203, 203, 819, 99, 100, - /* 10 */ 90, 842, 842, 854, 857, 846, 846, 97, 97, 98, - /* 20 */ 98, 98, 98, 301, 96, 96, 96, 96, 95, 95, - /* 30 */ 94, 94, 94, 93, 351, 325, 977, 977, 824, 824, - /* 40 */ 826, 947, 354, 99, 100, 90, 842, 842, 854, 857, - /* 50 */ 846, 846, 97, 97, 98, 98, 98, 98, 338, 96, - /* 60 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351, - /* 70 */ 95, 95, 94, 94, 94, 93, 351, 791, 977, 977, - /* 80 */ 325, 94, 94, 94, 93, 351, 792, 75, 99, 100, - /* 90 */ 90, 842, 842, 854, 857, 846, 846, 97, 97, 98, - /* 100 */ 98, 98, 98, 450, 96, 96, 96, 96, 95, 95, - /* 110 */ 94, 94, 94, 93, 351, 1333, 155, 155, 2, 325, - /* 120 */ 275, 146, 132, 52, 52, 93, 351, 99, 100, 90, - /* 130 */ 842, 842, 854, 857, 846, 846, 97, 97, 98, 98, - /* 140 */ 98, 98, 101, 96, 96, 96, 96, 95, 95, 94, - /* 150 */ 94, 94, 93, 351, 958, 958, 325, 268, 428, 413, - /* 160 */ 411, 61, 752, 752, 99, 100, 90, 842, 842, 854, - /* 170 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 60, - /* 180 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, - /* 190 */ 351, 325, 270, 329, 273, 277, 959, 960, 250, 99, - /* 200 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97, - /* 210 */ 98, 98, 98, 98, 301, 96, 96, 96, 96, 95, - /* 220 */ 95, 94, 94, 94, 93, 351, 325, 938, 1326, 698, - /* 230 */ 706, 1326, 242, 412, 99, 100, 90, 842, 842, 854, - /* 240 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 347, - /* 250 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, - /* 260 */ 351, 325, 938, 1327, 384, 699, 1327, 381, 379, 99, - /* 270 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97, - /* 280 */ 98, 98, 98, 98, 701, 96, 96, 96, 96, 95, - /* 290 */ 95, 94, 94, 94, 93, 351, 325, 92, 89, 178, - /* 300 */ 833, 936, 373, 700, 99, 100, 90, 842, 842, 854, - /* 310 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 375, - /* 320 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, - /* 330 */ 351, 325, 1276, 947, 354, 818, 936, 739, 739, 99, - /* 340 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97, - /* 350 */ 98, 98, 98, 98, 230, 96, 96, 96, 96, 95, - /* 360 */ 95, 94, 94, 94, 93, 351, 325, 969, 227, 92, - /* 370 */ 89, 178, 373, 300, 99, 100, 90, 842, 842, 854, - /* 380 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 921, - /* 390 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, - /* 400 */ 351, 325, 449, 447, 447, 447, 147, 737, 737, 99, - /* 410 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97, - /* 420 */ 98, 98, 98, 98, 296, 96, 96, 96, 96, 95, - /* 430 */ 95, 94, 94, 94, 93, 351, 325, 419, 231, 958, - /* 440 */ 958, 158, 25, 422, 99, 100, 90, 842, 842, 854, - /* 450 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 450, - /* 460 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, - /* 470 */ 351, 443, 224, 224, 420, 958, 958, 962, 325, 52, - /* 480 */ 52, 959, 960, 176, 415, 78, 99, 100, 90, 842, - /* 490 */ 842, 854, 857, 846, 846, 97, 97, 98, 98, 98, - /* 500 */ 98, 379, 96, 96, 96, 96, 95, 95, 94, 94, - /* 510 */ 94, 93, 351, 325, 428, 418, 298, 959, 960, 962, - /* 520 */ 81, 99, 88, 90, 842, 842, 854, 857, 846, 846, - /* 530 */ 97, 97, 98, 98, 98, 98, 717, 96, 96, 96, - /* 540 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 843, - /* 550 */ 843, 855, 858, 996, 318, 343, 379, 100, 90, 842, - /* 560 */ 842, 854, 857, 846, 846, 97, 97, 98, 98, 98, - /* 570 */ 98, 450, 96, 96, 96, 96, 95, 95, 94, 94, - /* 580 */ 94, 93, 351, 325, 350, 350, 350, 260, 377, 340, - /* 590 */ 929, 52, 52, 90, 842, 842, 854, 857, 846, 846, - /* 600 */ 97, 97, 98, 98, 98, 98, 361, 96, 96, 96, - /* 610 */ 96, 95, 95, 94, 94, 94, 93, 351, 86, 445, - /* 620 */ 847, 3, 1203, 361, 360, 378, 344, 813, 958, 958, - /* 630 */ 1300, 86, 445, 729, 3, 212, 169, 287, 405, 282, - /* 640 */ 404, 199, 232, 450, 300, 760, 83, 84, 280, 245, - /* 650 */ 262, 365, 251, 85, 352, 352, 92, 89, 178, 83, - /* 660 */ 84, 242, 412, 52, 52, 448, 85, 352, 352, 246, - /* 670 */ 959, 960, 194, 455, 670, 402, 399, 398, 448, 243, - /* 680 */ 221, 114, 434, 776, 361, 450, 397, 268, 747, 224, - /* 690 */ 224, 132, 132, 198, 832, 434, 452, 451, 428, 427, - /* 700 */ 819, 415, 734, 713, 132, 52, 52, 832, 268, 452, - /* 710 */ 451, 734, 194, 819, 363, 402, 399, 398, 450, 1271, - /* 720 */ 1271, 23, 958, 958, 86, 445, 397, 3, 228, 429, - /* 730 */ 895, 824, 824, 826, 827, 19, 203, 720, 52, 52, - /* 740 */ 428, 408, 439, 249, 824, 824, 826, 827, 19, 229, - /* 750 */ 403, 153, 83, 84, 761, 177, 241, 450, 721, 85, - /* 760 */ 352, 352, 120, 157, 959, 960, 58, 977, 409, 355, - /* 770 */ 330, 448, 268, 428, 430, 320, 790, 32, 32, 86, - /* 780 */ 445, 776, 3, 341, 98, 98, 98, 98, 434, 96, - /* 790 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351, - /* 800 */ 832, 120, 452, 451, 813, 887, 819, 83, 84, 977, - /* 810 */ 813, 132, 410, 920, 85, 352, 352, 132, 407, 789, - /* 820 */ 958, 958, 92, 89, 178, 917, 448, 262, 370, 261, - /* 830 */ 82, 914, 80, 262, 370, 261, 776, 824, 824, 826, - /* 840 */ 827, 19, 934, 434, 96, 96, 96, 96, 95, 95, - /* 850 */ 94, 94, 94, 93, 351, 832, 74, 452, 451, 958, - /* 860 */ 958, 819, 959, 960, 120, 92, 89, 178, 945, 2, - /* 870 */ 918, 965, 268, 1, 976, 76, 445, 762, 3, 708, - /* 880 */ 901, 901, 387, 958, 958, 757, 919, 371, 740, 778, - /* 890 */ 756, 257, 824, 824, 826, 827, 19, 417, 741, 450, - /* 900 */ 24, 959, 960, 83, 84, 369, 958, 958, 177, 226, - /* 910 */ 85, 352, 352, 885, 315, 314, 313, 215, 311, 10, - /* 920 */ 10, 683, 448, 349, 348, 959, 960, 909, 777, 157, - /* 930 */ 120, 958, 958, 337, 776, 416, 711, 310, 450, 434, - /* 940 */ 450, 321, 450, 791, 103, 200, 175, 450, 959, 960, - /* 950 */ 908, 832, 792, 452, 451, 9, 9, 819, 10, 10, - /* 960 */ 52, 52, 51, 51, 180, 716, 248, 10, 10, 171, - /* 970 */ 170, 167, 339, 959, 960, 247, 984, 702, 702, 450, - /* 980 */ 715, 233, 686, 982, 889, 983, 182, 914, 824, 824, - /* 990 */ 826, 827, 19, 183, 256, 423, 132, 181, 394, 10, - /* 1000 */ 10, 889, 891, 749, 958, 958, 917, 268, 985, 198, - /* 1010 */ 985, 349, 348, 425, 415, 299, 817, 832, 326, 825, - /* 1020 */ 120, 332, 133, 819, 268, 98, 98, 98, 98, 91, - /* 1030 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93, - /* 1040 */ 351, 157, 810, 371, 382, 359, 959, 960, 358, 268, - /* 1050 */ 450, 918, 368, 324, 824, 824, 826, 450, 709, 450, - /* 1060 */ 264, 380, 889, 450, 877, 746, 253, 919, 255, 433, - /* 1070 */ 36, 36, 234, 450, 234, 120, 269, 37, 37, 12, - /* 1080 */ 12, 334, 272, 27, 27, 450, 330, 118, 450, 162, - /* 1090 */ 742, 280, 450, 38, 38, 450, 985, 356, 985, 450, - /* 1100 */ 709, 1210, 450, 132, 450, 39, 39, 450, 40, 40, - /* 1110 */ 450, 362, 41, 41, 450, 42, 42, 450, 254, 28, - /* 1120 */ 28, 450, 29, 29, 31, 31, 450, 43, 43, 450, - /* 1130 */ 44, 44, 450, 714, 45, 45, 450, 11, 11, 767, - /* 1140 */ 450, 46, 46, 450, 268, 450, 105, 105, 450, 47, - /* 1150 */ 47, 450, 48, 48, 450, 237, 33, 33, 450, 172, - /* 1160 */ 49, 49, 450, 50, 50, 34, 34, 274, 122, 122, - /* 1170 */ 450, 123, 123, 450, 124, 124, 450, 898, 56, 56, - /* 1180 */ 450, 897, 35, 35, 450, 267, 450, 817, 450, 817, - /* 1190 */ 106, 106, 450, 53, 53, 385, 107, 107, 450, 817, - /* 1200 */ 108, 108, 817, 450, 104, 104, 121, 121, 119, 119, - /* 1210 */ 450, 117, 112, 112, 450, 276, 450, 225, 111, 111, - /* 1220 */ 450, 730, 450, 109, 109, 450, 673, 674, 675, 912, - /* 1230 */ 110, 110, 317, 998, 55, 55, 57, 57, 692, 331, - /* 1240 */ 54, 54, 26, 26, 696, 30, 30, 317, 937, 197, - /* 1250 */ 196, 195, 335, 281, 336, 446, 331, 745, 689, 436, - /* 1260 */ 440, 444, 120, 72, 386, 223, 175, 345, 757, 933, - /* 1270 */ 20, 286, 319, 756, 815, 372, 374, 202, 202, 202, - /* 1280 */ 263, 395, 285, 74, 208, 21, 696, 719, 718, 884, - /* 1290 */ 120, 120, 120, 120, 120, 754, 278, 828, 77, 74, - /* 1300 */ 726, 727, 785, 783, 880, 202, 999, 208, 894, 893, - /* 1310 */ 894, 893, 694, 816, 763, 116, 774, 1290, 431, 432, - /* 1320 */ 302, 999, 390, 303, 823, 697, 691, 680, 159, 289, - /* 1330 */ 679, 884, 681, 952, 291, 218, 293, 7, 316, 828, - /* 1340 */ 173, 805, 259, 364, 252, 911, 376, 713, 295, 435, - /* 1350 */ 308, 168, 955, 993, 135, 400, 990, 284, 882, 881, - /* 1360 */ 205, 928, 926, 59, 333, 62, 144, 156, 130, 72, - /* 1370 */ 802, 366, 367, 393, 137, 185, 189, 160, 139, 383, - /* 1380 */ 67, 896, 140, 141, 142, 148, 389, 812, 775, 266, - /* 1390 */ 219, 190, 154, 391, 913, 876, 271, 406, 191, 322, - /* 1400 */ 682, 733, 192, 342, 732, 724, 731, 711, 723, 421, - /* 1410 */ 705, 71, 323, 6, 204, 771, 288, 79, 297, 346, - /* 1420 */ 772, 704, 290, 283, 703, 770, 292, 294, 967, 239, - /* 1430 */ 769, 102, 862, 438, 426, 240, 424, 442, 73, 213, - /* 1440 */ 688, 238, 22, 453, 953, 214, 217, 216, 454, 677, - /* 1450 */ 676, 671, 753, 125, 115, 235, 126, 669, 353, 166, - /* 1460 */ 127, 244, 179, 357, 306, 304, 305, 307, 113, 892, - /* 1470 */ 327, 890, 811, 328, 134, 128, 136, 138, 743, 258, - /* 1480 */ 907, 184, 143, 129, 910, 186, 63, 64, 145, 187, - /* 1490 */ 906, 65, 8, 66, 13, 188, 202, 899, 265, 149, - /* 1500 */ 987, 388, 150, 685, 161, 392, 285, 193, 279, 396, - /* 1510 */ 151, 401, 68, 14, 15, 722, 69, 236, 831, 131, - /* 1520 */ 830, 860, 70, 751, 16, 414, 755, 4, 174, 220, - /* 1530 */ 222, 784, 201, 152, 779, 77, 74, 17, 18, 875, - /* 1540 */ 861, 859, 916, 864, 915, 207, 206, 942, 163, 437, - /* 1550 */ 948, 943, 164, 209, 1002, 441, 863, 165, 210, 829, - /* 1560 */ 695, 87, 312, 211, 1292, 1291, 309, -}; -static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 19, 95, 53, 97, 22, 24, 24, 101, 27, 28, - /* 10 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - /* 20 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48, - /* 30 */ 49, 50, 51, 52, 53, 19, 55, 55, 132, 133, - /* 40 */ 134, 1, 2, 27, 28, 29, 30, 31, 32, 33, - /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 187, 43, - /* 60 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 70 */ 47, 48, 49, 50, 51, 52, 53, 61, 97, 97, - /* 80 */ 19, 49, 50, 51, 52, 53, 70, 26, 27, 28, - /* 90 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - /* 100 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48, - /* 110 */ 49, 50, 51, 52, 53, 144, 145, 146, 147, 19, - /* 120 */ 16, 22, 92, 172, 173, 52, 53, 27, 28, 29, - /* 130 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - /* 140 */ 40, 41, 81, 43, 44, 45, 46, 47, 48, 49, - /* 150 */ 50, 51, 52, 53, 55, 56, 19, 152, 207, 208, - /* 160 */ 115, 24, 117, 118, 27, 28, 29, 30, 31, 32, - /* 170 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 79, - /* 180 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 190 */ 53, 19, 88, 157, 90, 23, 97, 98, 193, 27, - /* 200 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - /* 210 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47, - /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 172, - /* 230 */ 23, 26, 119, 120, 27, 28, 29, 30, 31, 32, - /* 240 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187, - /* 250 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 260 */ 53, 19, 22, 23, 228, 23, 26, 231, 152, 27, - /* 270 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - /* 280 */ 38, 39, 40, 41, 172, 43, 44, 45, 46, 47, - /* 290 */ 48, 49, 50, 51, 52, 53, 19, 221, 222, 223, - /* 300 */ 23, 96, 152, 172, 27, 28, 29, 30, 31, 32, - /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152, - /* 320 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 330 */ 53, 19, 0, 1, 2, 23, 96, 190, 191, 27, - /* 340 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - /* 350 */ 38, 39, 40, 41, 238, 43, 44, 45, 46, 47, - /* 360 */ 48, 49, 50, 51, 52, 53, 19, 185, 218, 221, - /* 370 */ 222, 223, 152, 152, 27, 28, 29, 30, 31, 32, - /* 380 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 241, - /* 390 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 400 */ 53, 19, 152, 168, 169, 170, 22, 190, 191, 27, - /* 410 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - /* 420 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47, - /* 430 */ 48, 49, 50, 51, 52, 53, 19, 19, 218, 55, - /* 440 */ 56, 24, 22, 152, 27, 28, 29, 30, 31, 32, - /* 450 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152, - /* 460 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 470 */ 53, 250, 194, 195, 56, 55, 56, 55, 19, 172, - /* 480 */ 173, 97, 98, 152, 206, 138, 27, 28, 29, 30, - /* 490 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - /* 500 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50, - /* 510 */ 51, 52, 53, 19, 207, 208, 152, 97, 98, 97, - /* 520 */ 138, 27, 28, 29, 30, 31, 32, 33, 34, 35, - /* 530 */ 36, 37, 38, 39, 40, 41, 181, 43, 44, 45, - /* 540 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 30, - /* 550 */ 31, 32, 33, 247, 248, 19, 152, 28, 29, 30, - /* 560 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - /* 570 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50, - /* 580 */ 51, 52, 53, 19, 168, 169, 170, 238, 19, 53, - /* 590 */ 152, 172, 173, 29, 30, 31, 32, 33, 34, 35, - /* 600 */ 36, 37, 38, 39, 40, 41, 152, 43, 44, 45, - /* 610 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 20, - /* 620 */ 101, 22, 23, 169, 170, 56, 207, 85, 55, 56, - /* 630 */ 23, 19, 20, 26, 22, 99, 100, 101, 102, 103, - /* 640 */ 104, 105, 238, 152, 152, 210, 47, 48, 112, 152, - /* 650 */ 108, 109, 110, 54, 55, 56, 221, 222, 223, 47, - /* 660 */ 48, 119, 120, 172, 173, 66, 54, 55, 56, 152, - /* 670 */ 97, 98, 99, 148, 149, 102, 103, 104, 66, 154, - /* 680 */ 23, 156, 83, 26, 230, 152, 113, 152, 163, 194, - /* 690 */ 195, 92, 92, 30, 95, 83, 97, 98, 207, 208, - /* 700 */ 101, 206, 179, 180, 92, 172, 173, 95, 152, 97, - /* 710 */ 98, 188, 99, 101, 219, 102, 103, 104, 152, 119, - /* 720 */ 120, 196, 55, 56, 19, 20, 113, 22, 193, 163, - /* 730 */ 11, 132, 133, 134, 135, 136, 24, 65, 172, 173, - /* 740 */ 207, 208, 250, 152, 132, 133, 134, 135, 136, 193, - /* 750 */ 78, 84, 47, 48, 49, 98, 199, 152, 86, 54, - /* 760 */ 55, 56, 196, 152, 97, 98, 209, 55, 163, 244, - /* 770 */ 107, 66, 152, 207, 208, 164, 175, 172, 173, 19, - /* 780 */ 20, 124, 22, 111, 38, 39, 40, 41, 83, 43, - /* 790 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 800 */ 95, 196, 97, 98, 85, 152, 101, 47, 48, 97, - /* 810 */ 85, 92, 207, 193, 54, 55, 56, 92, 49, 175, - /* 820 */ 55, 56, 221, 222, 223, 12, 66, 108, 109, 110, - /* 830 */ 137, 163, 139, 108, 109, 110, 26, 132, 133, 134, - /* 840 */ 135, 136, 152, 83, 43, 44, 45, 46, 47, 48, - /* 850 */ 49, 50, 51, 52, 53, 95, 26, 97, 98, 55, - /* 860 */ 56, 101, 97, 98, 196, 221, 222, 223, 146, 147, - /* 870 */ 57, 171, 152, 22, 26, 19, 20, 49, 22, 179, - /* 880 */ 108, 109, 110, 55, 56, 116, 73, 219, 75, 124, - /* 890 */ 121, 152, 132, 133, 134, 135, 136, 163, 85, 152, - /* 900 */ 232, 97, 98, 47, 48, 237, 55, 56, 98, 5, - /* 910 */ 54, 55, 56, 193, 10, 11, 12, 13, 14, 172, - /* 920 */ 173, 17, 66, 47, 48, 97, 98, 152, 124, 152, - /* 930 */ 196, 55, 56, 186, 124, 152, 106, 160, 152, 83, - /* 940 */ 152, 164, 152, 61, 22, 211, 212, 152, 97, 98, - /* 950 */ 152, 95, 70, 97, 98, 172, 173, 101, 172, 173, - /* 960 */ 172, 173, 172, 173, 60, 181, 62, 172, 173, 47, - /* 970 */ 48, 123, 186, 97, 98, 71, 100, 55, 56, 152, - /* 980 */ 181, 186, 21, 107, 152, 109, 82, 163, 132, 133, - /* 990 */ 134, 135, 136, 89, 16, 207, 92, 93, 19, 172, - /* 1000 */ 173, 169, 170, 195, 55, 56, 12, 152, 132, 30, - /* 1010 */ 134, 47, 48, 186, 206, 225, 152, 95, 114, 97, - /* 1020 */ 196, 245, 246, 101, 152, 38, 39, 40, 41, 42, - /* 1030 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 1040 */ 53, 152, 163, 219, 152, 141, 97, 98, 193, 152, - /* 1050 */ 152, 57, 91, 164, 132, 133, 134, 152, 55, 152, - /* 1060 */ 152, 237, 230, 152, 103, 193, 88, 73, 90, 75, - /* 1070 */ 172, 173, 183, 152, 185, 196, 152, 172, 173, 172, - /* 1080 */ 173, 217, 152, 172, 173, 152, 107, 22, 152, 24, - /* 1090 */ 193, 112, 152, 172, 173, 152, 132, 242, 134, 152, - /* 1100 */ 97, 140, 152, 92, 152, 172, 173, 152, 172, 173, - /* 1110 */ 152, 100, 172, 173, 152, 172, 173, 152, 140, 172, - /* 1120 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152, - /* 1130 */ 172, 173, 152, 152, 172, 173, 152, 172, 173, 213, - /* 1140 */ 152, 172, 173, 152, 152, 152, 172, 173, 152, 172, - /* 1150 */ 173, 152, 172, 173, 152, 210, 172, 173, 152, 26, - /* 1160 */ 172, 173, 152, 172, 173, 172, 173, 152, 172, 173, - /* 1170 */ 152, 172, 173, 152, 172, 173, 152, 59, 172, 173, - /* 1180 */ 152, 63, 172, 173, 152, 193, 152, 152, 152, 152, - /* 1190 */ 172, 173, 152, 172, 173, 77, 172, 173, 152, 152, - /* 1200 */ 172, 173, 152, 152, 172, 173, 172, 173, 172, 173, - /* 1210 */ 152, 22, 172, 173, 152, 152, 152, 22, 172, 173, - /* 1220 */ 152, 152, 152, 172, 173, 152, 7, 8, 9, 163, - /* 1230 */ 172, 173, 22, 23, 172, 173, 172, 173, 166, 167, - /* 1240 */ 172, 173, 172, 173, 55, 172, 173, 22, 23, 108, - /* 1250 */ 109, 110, 217, 152, 217, 166, 167, 163, 163, 163, - /* 1260 */ 163, 163, 196, 130, 217, 211, 212, 217, 116, 23, - /* 1270 */ 22, 101, 26, 121, 23, 23, 23, 26, 26, 26, - /* 1280 */ 23, 23, 112, 26, 26, 37, 97, 100, 101, 55, - /* 1290 */ 196, 196, 196, 196, 196, 23, 23, 55, 26, 26, - /* 1300 */ 7, 8, 23, 152, 23, 26, 96, 26, 132, 132, - /* 1310 */ 134, 134, 23, 152, 152, 26, 152, 122, 152, 191, - /* 1320 */ 152, 96, 234, 152, 152, 152, 152, 152, 197, 210, - /* 1330 */ 152, 97, 152, 152, 210, 233, 210, 198, 150, 97, - /* 1340 */ 184, 201, 239, 214, 214, 201, 239, 180, 214, 227, - /* 1350 */ 200, 198, 155, 67, 243, 176, 69, 175, 175, 175, - /* 1360 */ 122, 159, 159, 240, 159, 240, 22, 220, 27, 130, - /* 1370 */ 201, 18, 159, 18, 189, 158, 158, 220, 192, 159, - /* 1380 */ 137, 236, 192, 192, 192, 189, 74, 189, 159, 235, - /* 1390 */ 159, 158, 22, 177, 201, 201, 159, 107, 158, 177, - /* 1400 */ 159, 174, 158, 76, 174, 182, 174, 106, 182, 125, - /* 1410 */ 174, 107, 177, 22, 159, 216, 215, 137, 159, 53, - /* 1420 */ 216, 176, 215, 174, 174, 216, 215, 215, 174, 229, - /* 1430 */ 216, 129, 224, 177, 126, 229, 127, 177, 128, 25, - /* 1440 */ 162, 226, 26, 161, 13, 153, 6, 153, 151, 151, - /* 1450 */ 151, 151, 205, 165, 178, 178, 165, 4, 3, 22, - /* 1460 */ 165, 142, 15, 94, 202, 204, 203, 201, 16, 23, - /* 1470 */ 249, 23, 120, 249, 246, 111, 131, 123, 20, 16, - /* 1480 */ 1, 125, 123, 111, 56, 64, 37, 37, 131, 122, - /* 1490 */ 1, 37, 5, 37, 22, 107, 26, 80, 140, 80, - /* 1500 */ 87, 72, 107, 20, 24, 19, 112, 105, 23, 79, - /* 1510 */ 22, 79, 22, 22, 22, 58, 22, 79, 23, 68, - /* 1520 */ 23, 23, 26, 116, 22, 26, 23, 22, 122, 23, - /* 1530 */ 23, 56, 64, 22, 124, 26, 26, 64, 64, 23, - /* 1540 */ 23, 23, 23, 11, 23, 22, 26, 23, 22, 24, - /* 1550 */ 1, 23, 22, 26, 251, 24, 23, 22, 122, 23, - /* 1560 */ 23, 22, 15, 122, 122, 122, 23, -}; -#define YY_SHIFT_USE_DFLT (1567) -#define YY_SHIFT_COUNT (455) -#define YY_SHIFT_MIN (-94) -#define YY_SHIFT_MAX (1549) -static const short yy_shift_ofst[] = { - /* 0 */ 40, 599, 904, 612, 760, 760, 760, 760, 725, -19, - /* 10 */ 16, 16, 100, 760, 760, 760, 760, 760, 760, 760, - /* 20 */ 876, 876, 573, 542, 719, 600, 61, 137, 172, 207, - /* 30 */ 242, 277, 312, 347, 382, 417, 459, 459, 459, 459, - /* 40 */ 459, 459, 459, 459, 459, 459, 459, 459, 459, 459, - /* 50 */ 459, 459, 459, 494, 459, 529, 564, 564, 705, 760, - /* 60 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, - /* 70 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, - /* 80 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760, - /* 90 */ 856, 760, 760, 760, 760, 760, 760, 760, 760, 760, - /* 100 */ 760, 760, 760, 760, 987, 746, 746, 746, 746, 746, - /* 110 */ 801, 23, 32, 949, 961, 979, 964, 964, 949, 73, - /* 120 */ 113, -51, 1567, 1567, 1567, 536, 536, 536, 99, 99, - /* 130 */ 813, 813, 667, 205, 240, 949, 949, 949, 949, 949, - /* 140 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, - /* 150 */ 949, 949, 949, 949, 949, 332, 1011, 422, 422, 113, - /* 160 */ 30, 30, 30, 30, 30, 30, 1567, 1567, 1567, 922, - /* 170 */ -94, -94, 384, 613, 828, 420, 765, 804, 851, 949, - /* 180 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949, - /* 190 */ 949, 949, 949, 949, 949, 672, 672, 672, 949, 949, - /* 200 */ 657, 949, 949, 949, -18, 949, 949, 994, 949, 949, - /* 210 */ 949, 949, 949, 949, 949, 949, 949, 949, 772, 1118, - /* 220 */ 712, 712, 712, 810, 45, 769, 1219, 1133, 418, 418, - /* 230 */ 569, 1133, 569, 830, 607, 663, 882, 418, 693, 882, - /* 240 */ 882, 848, 1152, 1065, 1286, 1238, 1238, 1287, 1287, 1238, - /* 250 */ 1344, 1341, 1239, 1353, 1353, 1353, 1353, 1238, 1355, 1239, - /* 260 */ 1344, 1341, 1341, 1239, 1238, 1355, 1243, 1312, 1238, 1238, - /* 270 */ 1355, 1370, 1238, 1355, 1238, 1355, 1370, 1290, 1290, 1290, - /* 280 */ 1327, 1370, 1290, 1301, 1290, 1327, 1290, 1290, 1284, 1304, - /* 290 */ 1284, 1304, 1284, 1304, 1284, 1304, 1238, 1391, 1238, 1280, - /* 300 */ 1370, 1366, 1366, 1370, 1302, 1308, 1310, 1309, 1239, 1414, - /* 310 */ 1416, 1431, 1431, 1440, 1440, 1440, 1440, 1567, 1567, 1567, - /* 320 */ 1567, 1567, 1567, 1567, 1567, 519, 978, 1210, 1225, 104, - /* 330 */ 1141, 1189, 1246, 1248, 1251, 1252, 1253, 1257, 1258, 1273, - /* 340 */ 1003, 1187, 1293, 1170, 1272, 1279, 1234, 1281, 1176, 1177, - /* 350 */ 1289, 1242, 1195, 1453, 1455, 1437, 1319, 1447, 1369, 1452, - /* 360 */ 1446, 1448, 1352, 1345, 1364, 1354, 1458, 1356, 1463, 1479, - /* 370 */ 1359, 1357, 1449, 1450, 1454, 1456, 1372, 1428, 1421, 1367, - /* 380 */ 1489, 1487, 1472, 1388, 1358, 1417, 1470, 1419, 1413, 1429, - /* 390 */ 1395, 1480, 1483, 1486, 1394, 1402, 1488, 1430, 1490, 1491, - /* 400 */ 1485, 1492, 1432, 1457, 1494, 1438, 1451, 1495, 1497, 1498, - /* 410 */ 1496, 1407, 1502, 1503, 1505, 1499, 1406, 1506, 1507, 1475, - /* 420 */ 1468, 1511, 1410, 1509, 1473, 1510, 1474, 1516, 1509, 1517, - /* 430 */ 1518, 1519, 1520, 1521, 1523, 1532, 1524, 1526, 1525, 1527, - /* 440 */ 1528, 1530, 1531, 1527, 1533, 1535, 1536, 1537, 1539, 1436, - /* 450 */ 1441, 1442, 1443, 1543, 1547, 1549, -}; -#define YY_REDUCE_USE_DFLT (-130) -#define YY_REDUCE_COUNT (324) -#define YY_REDUCE_MIN (-129) -#define YY_REDUCE_MAX (1300) -static const short yy_reduce_ofst[] = { - /* 0 */ -29, 566, 525, 605, -49, 307, 491, 533, 668, 435, - /* 10 */ 601, 644, 148, 747, 786, 795, 419, 788, 827, 790, - /* 20 */ 454, 832, 889, 495, 824, 734, 76, 76, 76, 76, - /* 30 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, - /* 40 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, - /* 50 */ 76, 76, 76, 76, 76, 76, 76, 76, 783, 898, - /* 60 */ 905, 907, 911, 921, 933, 936, 940, 943, 947, 950, - /* 70 */ 952, 955, 958, 962, 965, 969, 974, 977, 980, 984, - /* 80 */ 988, 991, 993, 996, 999, 1002, 1006, 1010, 1018, 1021, - /* 90 */ 1024, 1028, 1032, 1034, 1036, 1040, 1046, 1051, 1058, 1062, - /* 100 */ 1064, 1068, 1070, 1073, 76, 76, 76, 76, 76, 76, - /* 110 */ 76, 76, 76, 855, 36, 523, 235, 416, 777, 76, - /* 120 */ 278, 76, 76, 76, 76, 700, 700, 700, 150, 220, - /* 130 */ 147, 217, 221, 306, 306, 611, 5, 535, 556, 620, - /* 140 */ 720, 872, 897, 116, 864, 349, 1035, 1037, 404, 1047, - /* 150 */ 992, -129, 1050, 492, 62, 722, 879, 1072, 1089, 808, - /* 160 */ 1066, 1094, 1095, 1096, 1097, 1098, 776, 1054, 557, 57, - /* 170 */ 112, 131, 167, 182, 250, 272, 291, 331, 364, 438, - /* 180 */ 497, 517, 591, 653, 690, 739, 775, 798, 892, 908, - /* 190 */ 924, 930, 1015, 1063, 1069, 355, 784, 799, 981, 1101, - /* 200 */ 926, 1151, 1161, 1162, 945, 1164, 1166, 1128, 1168, 1171, - /* 210 */ 1172, 250, 1173, 1174, 1175, 1178, 1180, 1181, 1088, 1102, - /* 220 */ 1119, 1124, 1126, 926, 1131, 1139, 1188, 1140, 1129, 1130, - /* 230 */ 1103, 1144, 1107, 1179, 1156, 1167, 1182, 1134, 1122, 1183, - /* 240 */ 1184, 1150, 1153, 1197, 1111, 1202, 1203, 1123, 1125, 1205, - /* 250 */ 1147, 1185, 1169, 1186, 1190, 1191, 1192, 1213, 1217, 1193, - /* 260 */ 1157, 1196, 1198, 1194, 1220, 1218, 1145, 1154, 1229, 1231, - /* 270 */ 1233, 1216, 1237, 1240, 1241, 1244, 1222, 1227, 1230, 1232, - /* 280 */ 1223, 1235, 1236, 1245, 1249, 1226, 1250, 1254, 1199, 1201, - /* 290 */ 1204, 1207, 1209, 1211, 1214, 1212, 1255, 1208, 1259, 1215, - /* 300 */ 1256, 1200, 1206, 1260, 1247, 1261, 1263, 1262, 1266, 1278, - /* 310 */ 1282, 1292, 1294, 1297, 1298, 1299, 1300, 1221, 1224, 1228, - /* 320 */ 1288, 1291, 1276, 1277, 1295, -}; -static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1281, 1271, 1271, 1271, 1203, 1203, 1203, 1203, 1271, 1096, - /* 10 */ 1125, 1125, 1255, 1332, 1332, 1332, 1332, 1332, 1332, 1202, - /* 20 */ 1332, 1332, 1332, 1332, 1271, 1100, 1131, 1332, 1332, 1332, - /* 30 */ 1332, 1204, 1205, 1332, 1332, 1332, 1254, 1256, 1141, 1140, - /* 40 */ 1139, 1138, 1237, 1112, 1136, 1129, 1133, 1204, 1198, 1199, - /* 50 */ 1197, 1201, 1205, 1332, 1132, 1167, 1182, 1166, 1332, 1332, - /* 60 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 70 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 80 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 90 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 100 */ 1332, 1332, 1332, 1332, 1176, 1181, 1188, 1180, 1177, 1169, - /* 110 */ 1168, 1170, 1171, 1332, 1019, 1067, 1332, 1332, 1332, 1172, - /* 120 */ 1332, 1173, 1185, 1184, 1183, 1262, 1289, 1288, 1332, 1332, - /* 130 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 140 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 150 */ 1332, 1332, 1332, 1332, 1332, 1281, 1271, 1025, 1025, 1332, - /* 160 */ 1271, 1271, 1271, 1271, 1271, 1271, 1267, 1100, 1091, 1332, - /* 170 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 180 */ 1259, 1257, 1332, 1218, 1332, 1332, 1332, 1332, 1332, 1332, - /* 190 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 200 */ 1332, 1332, 1332, 1332, 1096, 1332, 1332, 1332, 1332, 1332, - /* 210 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1283, 1332, 1232, - /* 220 */ 1096, 1096, 1096, 1098, 1080, 1090, 1004, 1135, 1114, 1114, - /* 230 */ 1321, 1135, 1321, 1042, 1303, 1039, 1125, 1114, 1200, 1125, - /* 240 */ 1125, 1097, 1090, 1332, 1324, 1105, 1105, 1323, 1323, 1105, - /* 250 */ 1146, 1070, 1135, 1076, 1076, 1076, 1076, 1105, 1016, 1135, - /* 260 */ 1146, 1070, 1070, 1135, 1105, 1016, 1236, 1318, 1105, 1105, - /* 270 */ 1016, 1211, 1105, 1016, 1105, 1016, 1211, 1068, 1068, 1068, - /* 280 */ 1057, 1211, 1068, 1042, 1068, 1057, 1068, 1068, 1118, 1113, - /* 290 */ 1118, 1113, 1118, 1113, 1118, 1113, 1105, 1206, 1105, 1332, - /* 300 */ 1211, 1215, 1215, 1211, 1130, 1119, 1128, 1126, 1135, 1022, - /* 310 */ 1060, 1286, 1286, 1282, 1282, 1282, 1282, 1329, 1329, 1267, - /* 320 */ 1298, 1298, 1044, 1044, 1298, 1332, 1332, 1332, 1332, 1332, - /* 330 */ 1332, 1293, 1332, 1220, 1332, 1332, 1332, 1332, 1332, 1332, - /* 340 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 350 */ 1332, 1332, 1152, 1332, 1000, 1264, 1332, 1332, 1263, 1332, - /* 360 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 370 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1320, - /* 380 */ 1332, 1332, 1332, 1332, 1332, 1332, 1235, 1234, 1332, 1332, - /* 390 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 400 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, - /* 410 */ 1332, 1082, 1332, 1332, 1332, 1307, 1332, 1332, 1332, 1332, - /* 420 */ 1332, 1332, 1332, 1127, 1332, 1120, 1332, 1332, 1311, 1332, - /* 430 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1273, - /* 440 */ 1332, 1332, 1332, 1272, 1332, 1332, 1332, 1332, 1332, 1154, - /* 450 */ 1332, 1153, 1157, 1332, 1010, 1332, -}; -/********** End of lemon-generated parsing tables *****************************/ - -/* The next table maps tokens (terminal symbols) into fallback tokens. -** If a construct like the following: -** -** %fallback ID X Y Z. +** so that both min() and max() may process rows in the order defined by +** their respective window declarations. ** -** appears in the grammar, then ID becomes a fallback token for X, Y, -** and Z. Whenever one of the tokens X, Y, or Z is input to the parser -** but it does not parse, the type of the token is changed to ID and -** the parse is retried before an error is thrown. +** INTERFACE WITH SELECT.C ** -** This feature can be used, for example, to cause some keywords in a language -** to revert to identifiers if they keyword does not apply in the context where -** it appears. -*/ -#ifdef YYFALLBACK -static const YYCODETYPE yyFallback[] = { - 0, /* $ => nothing */ - 0, /* SEMI => nothing */ - 55, /* EXPLAIN => ID */ - 55, /* QUERY => ID */ - 55, /* PLAN => ID */ - 55, /* BEGIN => ID */ - 0, /* TRANSACTION => nothing */ - 55, /* DEFERRED => ID */ - 55, /* IMMEDIATE => ID */ - 55, /* EXCLUSIVE => ID */ - 0, /* COMMIT => nothing */ - 55, /* END => ID */ - 55, /* ROLLBACK => ID */ - 55, /* SAVEPOINT => ID */ - 55, /* RELEASE => ID */ - 0, /* TO => nothing */ - 0, /* TABLE => nothing */ - 0, /* CREATE => nothing */ - 55, /* IF => ID */ - 0, /* NOT => nothing */ - 0, /* EXISTS => nothing */ - 55, /* TEMP => ID */ - 0, /* LP => nothing */ - 0, /* RP => nothing */ - 0, /* AS => nothing */ - 55, /* WITHOUT => ID */ - 0, /* COMMA => nothing */ - 0, /* OR => nothing */ - 0, /* AND => nothing */ - 0, /* IS => nothing */ - 55, /* MATCH => ID */ - 55, /* LIKE_KW => ID */ - 0, /* BETWEEN => nothing */ - 0, /* IN => nothing */ - 0, /* ISNULL => nothing */ - 0, /* NOTNULL => nothing */ - 0, /* NE => nothing */ - 0, /* EQ => nothing */ - 0, /* GT => nothing */ - 0, /* LE => nothing */ - 0, /* LT => nothing */ - 0, /* GE => nothing */ - 0, /* ESCAPE => nothing */ - 0, /* BITAND => nothing */ - 0, /* BITOR => nothing */ - 0, /* LSHIFT => nothing */ - 0, /* RSHIFT => nothing */ - 0, /* PLUS => nothing */ - 0, /* MINUS => nothing */ - 0, /* STAR => nothing */ - 0, /* SLASH => nothing */ - 0, /* REM => nothing */ - 0, /* CONCAT => nothing */ - 0, /* COLLATE => nothing */ - 0, /* BITNOT => nothing */ - 0, /* ID => nothing */ - 0, /* INDEXED => nothing */ - 55, /* ABORT => ID */ - 55, /* ACTION => ID */ - 55, /* AFTER => ID */ - 55, /* ANALYZE => ID */ - 55, /* ASC => ID */ - 55, /* ATTACH => ID */ - 55, /* BEFORE => ID */ - 55, /* BY => ID */ - 55, /* CASCADE => ID */ - 55, /* CAST => ID */ - 55, /* COLUMNKW => ID */ - 55, /* CONFLICT => ID */ - 55, /* DATABASE => ID */ - 55, /* DESC => ID */ - 55, /* DETACH => ID */ - 55, /* EACH => ID */ - 55, /* FAIL => ID */ - 55, /* FOR => ID */ - 55, /* IGNORE => ID */ - 55, /* INITIALLY => ID */ - 55, /* INSTEAD => ID */ - 55, /* NO => ID */ - 55, /* KEY => ID */ - 55, /* OF => ID */ - 55, /* OFFSET => ID */ - 55, /* PRAGMA => ID */ - 55, /* RAISE => ID */ - 55, /* RECURSIVE => ID */ - 55, /* REPLACE => ID */ - 55, /* RESTRICT => ID */ - 55, /* ROW => ID */ - 55, /* TRIGGER => ID */ - 55, /* VACUUM => ID */ - 55, /* VIEW => ID */ - 55, /* VIRTUAL => ID */ - 55, /* WITH => ID */ - 55, /* REINDEX => ID */ - 55, /* RENAME => ID */ - 55, /* CTIME_KW => ID */ -}; -#endif /* YYFALLBACK */ - -/* The following structure represents a single element of the -** parser's stack. Information stored includes: +** When processing the rewritten SELECT statement, code in select.c calls +** sqlite3WhereBegin() to begin iterating through the results of the +** sub-query, which is always implemented as a co-routine. It then calls +** sqlite3WindowCodeStep() to process rows and finish the scan by calling +** sqlite3WhereEnd(). ** -** + The state number for the parser at this level of the stack. +** sqlite3WindowCodeStep() generates VM code so that, for each row returned +** by the sub-query a sub-routine (OP_Gosub) coded by select.c is invoked. +** When the sub-routine is invoked: ** -** + The value of the token stored at this level of the stack. -** (In other words, the "major" token.) +** * The results of all window-functions for the row are stored +** in the associated Window.regResult registers. ** -** + The semantic value stored at this level of the stack. This is -** the information used by the action routines in the grammar. -** It is sometimes called the "minor" token. +** * The required terminal values are stored in the current row of +** temp table Window.iEphCsr. ** -** After the "shift" half of a SHIFTREDUCE action, the stateno field -** actually contains the reduce action for the second half of the -** SHIFTREDUCE. +** In some cases, depending on the window frame and the specific window +** functions invoked, sqlite3WindowCodeStep() caches each entire partition +** in a temp table before returning any rows. In other cases it does not. +** This detail is encapsulated within this file, the code generated by +** select.c is the same in either case. +** +** BUILT-IN WINDOW FUNCTIONS +** +** This implementation features the following built-in window functions: +** +** row_number() +** rank() +** dense_rank() +** percent_rank() +** cume_dist() +** ntile(N) +** lead(expr [, offset [, default]]) +** lag(expr [, offset [, default]]) +** first_value(expr) +** last_value(expr) +** nth_value(expr, N) +** +** These are the same built-in window functions supported by Postgres. +** Although the behaviour of aggregate window functions (functions that +** can be used as either aggregates or window funtions) allows them to +** be implemented using an API, built-in window functions are much more +** esoteric. Additionally, some window functions (e.g. nth_value()) +** may only be implemented by caching the entire partition in memory. +** As such, some built-in window functions use the same API as aggregate +** window functions and some are implemented directly using VDBE +** instructions. Additionally, for those functions that use the API, the +** window frame is sometimes modified before the SELECT statement is +** rewritten. For example, regardless of the specified window frame, the +** row_number() function always uses: +** +** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** +** See sqlite3WindowUpdate() for details. +** +** As well as some of the built-in window functions, aggregate window +** functions min() and max() are implemented using VDBE instructions if +** the start of the window frame is declared as anything other than +** UNBOUNDED PRECEDING. */ -struct yyStackEntry { - YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ - YYCODETYPE major; /* The major token value. This is the code - ** number for the token at this stack level */ - YYMINORTYPE minor; /* The user-supplied minor token value. This - ** is the value of the token */ -}; -typedef struct yyStackEntry yyStackEntry; - -/* The state of the parser is completely contained in an instance of -** the following structure */ -struct yyParser { - yyStackEntry *yytos; /* Pointer to top element of the stack */ -#ifdef YYTRACKMAXSTACKDEPTH - int yyhwm; /* High-water mark of the stack */ -#endif -#ifndef YYNOERRORRECOVERY - int yyerrcnt; /* Shifts left before out of the error */ -#endif - sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ -#if YYSTACKDEPTH<=0 - int yystksz; /* Current side of the stack */ - yyStackEntry *yystack; /* The parser's stack */ - yyStackEntry yystk0; /* First stack entry */ -#else - yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ -#endif -}; -typedef struct yyParser yyParser; - -#ifndef NDEBUG -/* #include */ -static FILE *yyTraceFILE = 0; -static char *yyTracePrompt = 0; -#endif /* NDEBUG */ -#ifndef NDEBUG -/* -** Turn parser tracing on by giving a stream to which to write the trace -** and a prompt to preface each trace message. Tracing is turned off -** by making either argument NULL -** -** Inputs: -**
              -**
            • A FILE* to which trace output should be written. -** If NULL, then tracing is turned off. -**
            • A prefix string written at the beginning of every -** line of trace output. If NULL, then tracing is -** turned off. -**
            +/* +** Implementation of built-in window function row_number(). Assumes that the +** window frame has been coerced to: ** -** Outputs: -** None. +** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ -SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){ - yyTraceFILE = TraceFILE; - yyTracePrompt = zTracePrompt; - if( yyTraceFILE==0 ) yyTracePrompt = 0; - else if( yyTracePrompt==0 ) yyTraceFILE = 0; +static void row_numberStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ) (*p)++; + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void row_numberValueFunc(sqlite3_context *pCtx){ + i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + sqlite3_result_int64(pCtx, (p ? *p : 0)); } -#endif /* NDEBUG */ - -#ifndef NDEBUG -/* For tracing shifts, the names of all terminals and nonterminals -** are required. The following table supplies these names */ -static const char *const yyTokenName[] = { - "$", "SEMI", "EXPLAIN", "QUERY", - "PLAN", "BEGIN", "TRANSACTION", "DEFERRED", - "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END", - "ROLLBACK", "SAVEPOINT", "RELEASE", "TO", - "TABLE", "CREATE", "IF", "NOT", - "EXISTS", "TEMP", "LP", "RP", - "AS", "WITHOUT", "COMMA", "OR", - "AND", "IS", "MATCH", "LIKE_KW", - "BETWEEN", "IN", "ISNULL", "NOTNULL", - "NE", "EQ", "GT", "LE", - "LT", "GE", "ESCAPE", "BITAND", - "BITOR", "LSHIFT", "RSHIFT", "PLUS", - "MINUS", "STAR", "SLASH", "REM", - "CONCAT", "COLLATE", "BITNOT", "ID", - "INDEXED", "ABORT", "ACTION", "AFTER", - "ANALYZE", "ASC", "ATTACH", "BEFORE", - "BY", "CASCADE", "CAST", "COLUMNKW", - "CONFLICT", "DATABASE", "DESC", "DETACH", - "EACH", "FAIL", "FOR", "IGNORE", - "INITIALLY", "INSTEAD", "NO", "KEY", - "OF", "OFFSET", "PRAGMA", "RAISE", - "RECURSIVE", "REPLACE", "RESTRICT", "ROW", - "TRIGGER", "VACUUM", "VIEW", "VIRTUAL", - "WITH", "REINDEX", "RENAME", "CTIME_KW", - "ANY", "STRING", "JOIN_KW", "CONSTRAINT", - "DEFAULT", "NULL", "PRIMARY", "UNIQUE", - "CHECK", "REFERENCES", "AUTOINCR", "ON", - "INSERT", "DELETE", "UPDATE", "SET", - "DEFERRABLE", "FOREIGN", "DROP", "UNION", - "ALL", "EXCEPT", "INTERSECT", "SELECT", - "VALUES", "DISTINCT", "DOT", "FROM", - "JOIN", "USING", "ORDER", "GROUP", - "HAVING", "LIMIT", "WHERE", "INTO", - "FLOAT", "BLOB", "INTEGER", "VARIABLE", - "CASE", "WHEN", "THEN", "ELSE", - "INDEX", "ALTER", "ADD", "error", - "input", "cmdlist", "ecmd", "explain", - "cmdx", "cmd", "transtype", "trans_opt", - "nm", "savepoint_opt", "create_table", "create_table_args", - "createkw", "temp", "ifnotexists", "dbnm", - "columnlist", "conslist_opt", "table_options", "select", - "columnname", "carglist", "typetoken", "typename", - "signed", "plus_num", "minus_num", "ccons", - "term", "expr", "onconf", "sortorder", - "autoinc", "eidlist_opt", "refargs", "defer_subclause", - "refarg", "refact", "init_deferred_pred_opt", "conslist", - "tconscomma", "tcons", "sortlist", "eidlist", - "defer_subclause_opt", "orconf", "resolvetype", "raisetype", - "ifexists", "fullname", "selectnowith", "oneselect", - "with", "multiselect_op", "distinct", "selcollist", - "from", "where_opt", "groupby_opt", "having_opt", - "orderby_opt", "limit_opt", "values", "nexprlist", - "exprlist", "sclp", "as", "seltablist", - "stl_prefix", "joinop", "indexed_opt", "on_opt", - "using_opt", "idlist", "setlist", "insert_cmd", - "idlist_opt", "likeop", "between_op", "in_op", - "paren_exprlist", "case_operand", "case_exprlist", "case_else", - "uniqueflag", "collate", "nmnum", "trigger_decl", - "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause", - "when_clause", "trigger_cmd", "trnm", "tridxby", - "database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt", - "create_vtab", "vtabarglist", "vtabarg", "vtabargtoken", - "lp", "anylist", "wqlist", -}; -#endif /* NDEBUG */ -#ifndef NDEBUG -/* For tracing reduce actions, the names of all rules are required. +/* +** Context object type used by rank(), dense_rank(), percent_rank() and +** cume_dist(). */ -static const char *const yyRuleName[] = { - /* 0 */ "explain ::= EXPLAIN", - /* 1 */ "explain ::= EXPLAIN QUERY PLAN", - /* 2 */ "cmdx ::= cmd", - /* 3 */ "cmd ::= BEGIN transtype trans_opt", - /* 4 */ "transtype ::=", - /* 5 */ "transtype ::= DEFERRED", - /* 6 */ "transtype ::= IMMEDIATE", - /* 7 */ "transtype ::= EXCLUSIVE", - /* 8 */ "cmd ::= COMMIT trans_opt", - /* 9 */ "cmd ::= END trans_opt", - /* 10 */ "cmd ::= ROLLBACK trans_opt", - /* 11 */ "cmd ::= SAVEPOINT nm", - /* 12 */ "cmd ::= RELEASE savepoint_opt nm", - /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", - /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", - /* 15 */ "createkw ::= CREATE", - /* 16 */ "ifnotexists ::=", - /* 17 */ "ifnotexists ::= IF NOT EXISTS", - /* 18 */ "temp ::= TEMP", - /* 19 */ "temp ::=", - /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_options", - /* 21 */ "create_table_args ::= AS select", - /* 22 */ "table_options ::=", - /* 23 */ "table_options ::= WITHOUT nm", - /* 24 */ "columnname ::= nm typetoken", - /* 25 */ "typetoken ::=", - /* 26 */ "typetoken ::= typename LP signed RP", - /* 27 */ "typetoken ::= typename LP signed COMMA signed RP", - /* 28 */ "typename ::= typename ID|STRING", - /* 29 */ "ccons ::= CONSTRAINT nm", - /* 30 */ "ccons ::= DEFAULT term", - /* 31 */ "ccons ::= DEFAULT LP expr RP", - /* 32 */ "ccons ::= DEFAULT PLUS term", - /* 33 */ "ccons ::= DEFAULT MINUS term", - /* 34 */ "ccons ::= DEFAULT ID|INDEXED", - /* 35 */ "ccons ::= NOT NULL onconf", - /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 37 */ "ccons ::= UNIQUE onconf", - /* 38 */ "ccons ::= CHECK LP expr RP", - /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs", - /* 40 */ "ccons ::= defer_subclause", - /* 41 */ "ccons ::= COLLATE ID|STRING", - /* 42 */ "autoinc ::=", - /* 43 */ "autoinc ::= AUTOINCR", - /* 44 */ "refargs ::=", - /* 45 */ "refargs ::= refargs refarg", - /* 46 */ "refarg ::= MATCH nm", - /* 47 */ "refarg ::= ON INSERT refact", - /* 48 */ "refarg ::= ON DELETE refact", - /* 49 */ "refarg ::= ON UPDATE refact", - /* 50 */ "refact ::= SET NULL", - /* 51 */ "refact ::= SET DEFAULT", - /* 52 */ "refact ::= CASCADE", - /* 53 */ "refact ::= RESTRICT", - /* 54 */ "refact ::= NO ACTION", - /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 57 */ "init_deferred_pred_opt ::=", - /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 60 */ "conslist_opt ::=", - /* 61 */ "tconscomma ::= COMMA", - /* 62 */ "tcons ::= CONSTRAINT nm", - /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", - /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf", - /* 65 */ "tcons ::= CHECK LP expr RP onconf", - /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", - /* 67 */ "defer_subclause_opt ::=", - /* 68 */ "onconf ::=", - /* 69 */ "onconf ::= ON CONFLICT resolvetype", - /* 70 */ "orconf ::=", - /* 71 */ "orconf ::= OR resolvetype", - /* 72 */ "resolvetype ::= IGNORE", - /* 73 */ "resolvetype ::= REPLACE", - /* 74 */ "cmd ::= DROP TABLE ifexists fullname", - /* 75 */ "ifexists ::= IF EXISTS", - /* 76 */ "ifexists ::=", - /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", - /* 78 */ "cmd ::= DROP VIEW ifexists fullname", - /* 79 */ "cmd ::= select", - /* 80 */ "select ::= with selectnowith", - /* 81 */ "selectnowith ::= selectnowith multiselect_op oneselect", - /* 82 */ "multiselect_op ::= UNION", - /* 83 */ "multiselect_op ::= UNION ALL", - /* 84 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 86 */ "values ::= VALUES LP nexprlist RP", - /* 87 */ "values ::= values COMMA LP exprlist RP", - /* 88 */ "distinct ::= DISTINCT", - /* 89 */ "distinct ::= ALL", - /* 90 */ "distinct ::=", - /* 91 */ "sclp ::=", - /* 92 */ "selcollist ::= sclp expr as", - /* 93 */ "selcollist ::= sclp STAR", - /* 94 */ "selcollist ::= sclp nm DOT STAR", - /* 95 */ "as ::= AS nm", - /* 96 */ "as ::=", - /* 97 */ "from ::=", - /* 98 */ "from ::= FROM seltablist", - /* 99 */ "stl_prefix ::= seltablist joinop", - /* 100 */ "stl_prefix ::=", - /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", - /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", - /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", - /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", - /* 105 */ "dbnm ::=", - /* 106 */ "dbnm ::= DOT nm", - /* 107 */ "fullname ::= nm dbnm", - /* 108 */ "joinop ::= COMMA|JOIN", - /* 109 */ "joinop ::= JOIN_KW JOIN", - /* 110 */ "joinop ::= JOIN_KW nm JOIN", - /* 111 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 112 */ "on_opt ::= ON expr", - /* 113 */ "on_opt ::=", - /* 114 */ "indexed_opt ::=", - /* 115 */ "indexed_opt ::= INDEXED BY nm", - /* 116 */ "indexed_opt ::= NOT INDEXED", - /* 117 */ "using_opt ::= USING LP idlist RP", - /* 118 */ "using_opt ::=", - /* 119 */ "orderby_opt ::=", - /* 120 */ "orderby_opt ::= ORDER BY sortlist", - /* 121 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 122 */ "sortlist ::= expr sortorder", - /* 123 */ "sortorder ::= ASC", - /* 124 */ "sortorder ::= DESC", - /* 125 */ "sortorder ::=", - /* 126 */ "groupby_opt ::=", - /* 127 */ "groupby_opt ::= GROUP BY nexprlist", - /* 128 */ "having_opt ::=", - /* 129 */ "having_opt ::= HAVING expr", - /* 130 */ "limit_opt ::=", - /* 131 */ "limit_opt ::= LIMIT expr", - /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 133 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt", - /* 135 */ "where_opt ::=", - /* 136 */ "where_opt ::= WHERE expr", - /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt", - /* 138 */ "setlist ::= setlist COMMA nm EQ expr", - /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 140 */ "setlist ::= nm EQ expr", - /* 141 */ "setlist ::= LP idlist RP EQ expr", - /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select", - /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES", - /* 144 */ "insert_cmd ::= INSERT orconf", - /* 145 */ "insert_cmd ::= REPLACE", - /* 146 */ "idlist_opt ::=", - /* 147 */ "idlist_opt ::= LP idlist RP", - /* 148 */ "idlist ::= idlist COMMA nm", - /* 149 */ "idlist ::= nm", - /* 150 */ "expr ::= LP expr RP", - /* 151 */ "term ::= NULL", - /* 152 */ "expr ::= ID|INDEXED", - /* 153 */ "expr ::= JOIN_KW", - /* 154 */ "expr ::= nm DOT nm", - /* 155 */ "expr ::= nm DOT nm DOT nm", - /* 156 */ "term ::= FLOAT|BLOB", - /* 157 */ "term ::= STRING", - /* 158 */ "term ::= INTEGER", - /* 159 */ "expr ::= VARIABLE", - /* 160 */ "expr ::= expr COLLATE ID|STRING", - /* 161 */ "expr ::= CAST LP expr AS typetoken RP", - /* 162 */ "expr ::= ID|INDEXED LP distinct exprlist RP", - /* 163 */ "expr ::= ID|INDEXED LP STAR RP", - /* 164 */ "term ::= CTIME_KW", - /* 165 */ "expr ::= LP nexprlist COMMA expr RP", - /* 166 */ "expr ::= expr AND expr", - /* 167 */ "expr ::= expr OR expr", - /* 168 */ "expr ::= expr LT|GT|GE|LE expr", - /* 169 */ "expr ::= expr EQ|NE expr", - /* 170 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 171 */ "expr ::= expr PLUS|MINUS expr", - /* 172 */ "expr ::= expr STAR|SLASH|REM expr", - /* 173 */ "expr ::= expr CONCAT expr", - /* 174 */ "likeop ::= LIKE_KW|MATCH", - /* 175 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 176 */ "expr ::= expr likeop expr", - /* 177 */ "expr ::= expr likeop expr ESCAPE expr", - /* 178 */ "expr ::= expr ISNULL|NOTNULL", - /* 179 */ "expr ::= expr NOT NULL", - /* 180 */ "expr ::= expr IS expr", - /* 181 */ "expr ::= expr IS NOT expr", - /* 182 */ "expr ::= NOT expr", - /* 183 */ "expr ::= BITNOT expr", - /* 184 */ "expr ::= MINUS expr", - /* 185 */ "expr ::= PLUS expr", - /* 186 */ "between_op ::= BETWEEN", - /* 187 */ "between_op ::= NOT BETWEEN", - /* 188 */ "expr ::= expr between_op expr AND expr", - /* 189 */ "in_op ::= IN", - /* 190 */ "in_op ::= NOT IN", - /* 191 */ "expr ::= expr in_op LP exprlist RP", - /* 192 */ "expr ::= LP select RP", - /* 193 */ "expr ::= expr in_op LP select RP", - /* 194 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 195 */ "expr ::= EXISTS LP select RP", - /* 196 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 197 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 198 */ "case_exprlist ::= WHEN expr THEN expr", - /* 199 */ "case_else ::= ELSE expr", - /* 200 */ "case_else ::=", - /* 201 */ "case_operand ::= expr", - /* 202 */ "case_operand ::=", - /* 203 */ "exprlist ::=", - /* 204 */ "nexprlist ::= nexprlist COMMA expr", - /* 205 */ "nexprlist ::= expr", - /* 206 */ "paren_exprlist ::=", - /* 207 */ "paren_exprlist ::= LP exprlist RP", - /* 208 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 209 */ "uniqueflag ::= UNIQUE", - /* 210 */ "uniqueflag ::=", - /* 211 */ "eidlist_opt ::=", - /* 212 */ "eidlist_opt ::= LP eidlist RP", - /* 213 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 214 */ "eidlist ::= nm collate sortorder", - /* 215 */ "collate ::=", - /* 216 */ "collate ::= COLLATE ID|STRING", - /* 217 */ "cmd ::= DROP INDEX ifexists fullname", - /* 218 */ "cmd ::= VACUUM", - /* 219 */ "cmd ::= VACUUM nm", - /* 220 */ "cmd ::= PRAGMA nm dbnm", - /* 221 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 222 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 223 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 224 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 225 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 226 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 227 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 228 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 229 */ "trigger_time ::= BEFORE", - /* 230 */ "trigger_time ::= AFTER", - /* 231 */ "trigger_time ::= INSTEAD OF", - /* 232 */ "trigger_time ::=", - /* 233 */ "trigger_event ::= DELETE|INSERT", - /* 234 */ "trigger_event ::= UPDATE", - /* 235 */ "trigger_event ::= UPDATE OF idlist", - /* 236 */ "when_clause ::=", - /* 237 */ "when_clause ::= WHEN expr", - /* 238 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 239 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 240 */ "trnm ::= nm DOT nm", - /* 241 */ "tridxby ::= INDEXED BY nm", - /* 242 */ "tridxby ::= NOT INDEXED", - /* 243 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt", - /* 244 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select", - /* 245 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt", - /* 246 */ "trigger_cmd ::= select", - /* 247 */ "expr ::= RAISE LP IGNORE RP", - /* 248 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 249 */ "raisetype ::= ROLLBACK", - /* 250 */ "raisetype ::= ABORT", - /* 251 */ "raisetype ::= FAIL", - /* 252 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 253 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 254 */ "cmd ::= DETACH database_kw_opt expr", - /* 255 */ "key_opt ::=", - /* 256 */ "key_opt ::= KEY expr", - /* 257 */ "cmd ::= REINDEX", - /* 258 */ "cmd ::= REINDEX nm dbnm", - /* 259 */ "cmd ::= ANALYZE", - /* 260 */ "cmd ::= ANALYZE nm dbnm", - /* 261 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 262 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 263 */ "add_column_fullname ::= fullname", - /* 264 */ "cmd ::= create_vtab", - /* 265 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 266 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 267 */ "vtabarg ::=", - /* 268 */ "vtabargtoken ::= ANY", - /* 269 */ "vtabargtoken ::= lp anylist RP", - /* 270 */ "lp ::= LP", - /* 271 */ "with ::=", - /* 272 */ "with ::= WITH wqlist", - /* 273 */ "with ::= WITH RECURSIVE wqlist", - /* 274 */ "wqlist ::= nm eidlist_opt AS LP select RP", - /* 275 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", - /* 276 */ "input ::= cmdlist", - /* 277 */ "cmdlist ::= cmdlist ecmd", - /* 278 */ "cmdlist ::= ecmd", - /* 279 */ "ecmd ::= SEMI", - /* 280 */ "ecmd ::= explain cmdx SEMI", - /* 281 */ "explain ::=", - /* 282 */ "trans_opt ::=", - /* 283 */ "trans_opt ::= TRANSACTION", - /* 284 */ "trans_opt ::= TRANSACTION nm", - /* 285 */ "savepoint_opt ::= SAVEPOINT", - /* 286 */ "savepoint_opt ::=", - /* 287 */ "cmd ::= create_table create_table_args", - /* 288 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 289 */ "columnlist ::= columnname carglist", - /* 290 */ "nm ::= ID|INDEXED", - /* 291 */ "nm ::= STRING", - /* 292 */ "nm ::= JOIN_KW", - /* 293 */ "typetoken ::= typename", - /* 294 */ "typename ::= ID|STRING", - /* 295 */ "signed ::= plus_num", - /* 296 */ "signed ::= minus_num", - /* 297 */ "carglist ::= carglist ccons", - /* 298 */ "carglist ::=", - /* 299 */ "ccons ::= NULL onconf", - /* 300 */ "conslist_opt ::= COMMA conslist", - /* 301 */ "conslist ::= conslist tconscomma tcons", - /* 302 */ "conslist ::= tcons", - /* 303 */ "tconscomma ::=", - /* 304 */ "defer_subclause_opt ::= defer_subclause", - /* 305 */ "resolvetype ::= raisetype", - /* 306 */ "selectnowith ::= oneselect", - /* 307 */ "oneselect ::= values", - /* 308 */ "sclp ::= selcollist COMMA", - /* 309 */ "as ::= ID|STRING", - /* 310 */ "expr ::= term", - /* 311 */ "exprlist ::= nexprlist", - /* 312 */ "nmnum ::= plus_num", - /* 313 */ "nmnum ::= nm", - /* 314 */ "nmnum ::= ON", - /* 315 */ "nmnum ::= DELETE", - /* 316 */ "nmnum ::= DEFAULT", - /* 317 */ "plus_num ::= INTEGER|FLOAT", - /* 318 */ "foreach_clause ::=", - /* 319 */ "foreach_clause ::= FOR EACH ROW", - /* 320 */ "trnm ::= nm", - /* 321 */ "tridxby ::=", - /* 322 */ "database_kw_opt ::= DATABASE", - /* 323 */ "database_kw_opt ::=", - /* 324 */ "kwcolumn_opt ::=", - /* 325 */ "kwcolumn_opt ::= COLUMNKW", - /* 326 */ "vtabarglist ::= vtabarg", - /* 327 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 328 */ "vtabarg ::= vtabarg vtabargtoken", - /* 329 */ "anylist ::=", - /* 330 */ "anylist ::= anylist LP anylist RP", - /* 331 */ "anylist ::= anylist ANY", +struct CallCount { + i64 nValue; + i64 nStep; + i64 nTotal; }; -#endif /* NDEBUG */ - -#if YYSTACKDEPTH<=0 /* -** Try to increase the size of the parser stack. Return the number -** of errors. Return 0 on success. +** Implementation of built-in window function dense_rank(). Assumes that +** the window frame has been set to: +** +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ -static int yyGrowStack(yyParser *p){ - int newSize; - int idx; - yyStackEntry *pNew; - - newSize = p->yystksz*2 + 100; - idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; - if( p->yystack==&p->yystk0 ){ - pNew = malloc(newSize*sizeof(pNew[0])); - if( pNew ) pNew[0] = p->yystk0; - }else{ - pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); - } - if( pNew ){ - p->yystack = pNew; - p->yytos = &p->yystack[idx]; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", - yyTracePrompt, p->yystksz, newSize); +static void dense_rankStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ) p->nStep = 1; + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void dense_rankValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + if( p->nStep ){ + p->nValue++; + p->nStep = 0; } -#endif - p->yystksz = newSize; + sqlite3_result_int64(pCtx, p->nValue); } - return pNew==0; } -#endif -/* Datatype of the argument to the memory allocated passed as the -** second argument to sqlite3ParserAlloc() below. This can be changed by -** putting an appropriate #define in the %include section of the input -** grammar. +/* +** Implementation of built-in window function nth_value(). This +** implementation is used in "slow mode" only - when the EXCLUDE clause +** is not set to the default value "NO OTHERS". */ -#ifndef YYMALLOCARGTYPE -# define YYMALLOCARGTYPE size_t -#endif +struct NthValueCtx { + i64 nStep; + sqlite3_value *pValue; +}; +static void nth_valueStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + i64 iVal; + switch( sqlite3_value_numeric_type(apArg[1]) ){ + case SQLITE_INTEGER: + iVal = sqlite3_value_int64(apArg[1]); + break; + case SQLITE_FLOAT: { + double fVal = sqlite3_value_double(apArg[1]); + if( ((i64)fVal)!=fVal ) goto error_out; + iVal = (i64)fVal; + break; + } + default: + goto error_out; + } + if( iVal<=0 ) goto error_out; -/* Initialize a new parser that has already been allocated. -*/ -SQLITE_PRIVATE void sqlite3ParserInit(void *yypParser){ - yyParser *pParser = (yyParser*)yypParser; -#ifdef YYTRACKMAXSTACKDEPTH - pParser->yyhwm = 0; -#endif -#if YYSTACKDEPTH<=0 - pParser->yytos = NULL; - pParser->yystack = NULL; - pParser->yystksz = 0; - if( yyGrowStack(pParser) ){ - pParser->yystack = &pParser->yystk0; - pParser->yystksz = 1; + p->nStep++; + if( iVal==p->nStep ){ + p->pValue = sqlite3_value_dup(apArg[0]); + if( !p->pValue ){ + sqlite3_result_error_nomem(pCtx); + } + } } -#endif -#ifndef YYNOERRORRECOVERY - pParser->yyerrcnt = -1; -#endif - pParser->yytos = pParser->yystack; - pParser->yystack[0].stateno = 0; - pParser->yystack[0].major = 0; -} + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + return; -#ifndef sqlite3Parser_ENGINEALWAYSONSTACK -/* -** This function allocates a new parser. -** The only argument is a pointer to a function which works like -** malloc. -** -** Inputs: -** A pointer to the function used to allocate memory. -** -** Outputs: -** A pointer to a parser. This pointer is used in subsequent calls -** to sqlite3Parser and sqlite3ParserFree. -*/ -SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ - yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); - if( pParser ) sqlite3ParserInit(pParser); - return pParser; + error_out: + sqlite3_result_error( + pCtx, "second argument to nth_value must be a positive integer", -1 + ); } -#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ - +static void nth_valueFinalizeFunc(sqlite3_context *pCtx){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, 0); + if( p && p->pValue ){ + sqlite3_result_value(pCtx, p->pValue); + sqlite3_value_free(p->pValue); + p->pValue = 0; + } +} +#define nth_valueInvFunc noopStepFunc +#define nth_valueValueFunc noopValueFunc -/* The following function deletes the "minor type" or semantic value -** associated with a symbol. The symbol can be either a terminal -** or nonterminal. "yymajor" is the symbol code, and "yypminor" is -** a pointer to the value to be deleted. The code used to do the -** deletions is derived from the %destructor and/or %token_destructor -** directives of the input grammar. -*/ -static void yy_destructor( - yyParser *yypParser, /* The parser */ - YYCODETYPE yymajor, /* Type code for object to destroy */ - YYMINORTYPE *yypminor /* The object to be destroyed */ +static void first_valueStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg ){ - sqlite3ParserARG_FETCH; - switch( yymajor ){ - /* Here is inserted the actions which take place when a - ** terminal or non-terminal is destroyed. This can happen - ** when the symbol is popped from the stack during a - ** reduce or during error processing or when a parser is - ** being destroyed before it is finished parsing. - ** - ** Note: during a reduce, the only symbols destroyed are those - ** which appear on the RHS of the rule, but which are *not* used - ** inside the C code. - */ -/********* Begin destructor definitions ***************************************/ - case 163: /* select */ - case 194: /* selectnowith */ - case 195: /* oneselect */ - case 206: /* values */ -{ -sqlite3SelectDelete(pParse->db, (yypminor->yy243)); -} - break; - case 172: /* term */ - case 173: /* expr */ -{ -sqlite3ExprDelete(pParse->db, (yypminor->yy190).pExpr); -} - break; - case 177: /* eidlist_opt */ - case 186: /* sortlist */ - case 187: /* eidlist */ - case 199: /* selcollist */ - case 202: /* groupby_opt */ - case 204: /* orderby_opt */ - case 207: /* nexprlist */ - case 208: /* exprlist */ - case 209: /* sclp */ - case 218: /* setlist */ - case 224: /* paren_exprlist */ - case 226: /* case_exprlist */ -{ -sqlite3ExprListDelete(pParse->db, (yypminor->yy148)); -} - break; - case 193: /* fullname */ - case 200: /* from */ - case 211: /* seltablist */ - case 212: /* stl_prefix */ -{ -sqlite3SrcListDelete(pParse->db, (yypminor->yy185)); -} - break; - case 196: /* with */ - case 250: /* wqlist */ -{ -sqlite3WithDelete(pParse->db, (yypminor->yy285)); -} - break; - case 201: /* where_opt */ - case 203: /* having_opt */ - case 215: /* on_opt */ - case 225: /* case_operand */ - case 227: /* case_else */ - case 236: /* when_clause */ - case 241: /* key_opt */ -{ -sqlite3ExprDelete(pParse->db, (yypminor->yy72)); -} - break; - case 216: /* using_opt */ - case 217: /* idlist */ - case 220: /* idlist_opt */ -{ -sqlite3IdListDelete(pParse->db, (yypminor->yy254)); -} - break; - case 232: /* trigger_cmd_list */ - case 237: /* trigger_cmd */ -{ -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy145)); -} - break; - case 234: /* trigger_event */ -{ -sqlite3IdListDelete(pParse->db, (yypminor->yy332).b); + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pValue==0 ){ + p->pValue = sqlite3_value_dup(apArg[0]); + if( !p->pValue ){ + sqlite3_result_error_nomem(pCtx); + } + } + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); } - break; -/********* End destructor definitions *****************************************/ - default: break; /* If no destructor action specified: do nothing */ +static void first_valueFinalizeFunc(sqlite3_context *pCtx){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pValue ){ + sqlite3_result_value(pCtx, p->pValue); + sqlite3_value_free(p->pValue); + p->pValue = 0; } } +#define first_valueInvFunc noopStepFunc +#define first_valueValueFunc noopValueFunc /* -** Pop the parser's stack once. +** Implementation of built-in window function rank(). Assumes that +** the window frame has been set to: ** -** If there is a destructor routine associated with the token which -** is popped from the stack, then call it. +** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW */ -static void yy_pop_parser_stack(yyParser *pParser){ - yyStackEntry *yytos; - assert( pParser->yytos!=0 ); - assert( pParser->yytos > pParser->yystack ); - yytos = pParser->yytos--; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sPopping %s\n", - yyTracePrompt, - yyTokenName[yytos->major]); +static void rankStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + p->nStep++; + if( p->nValue==0 ){ + p->nValue = p->nStep; + } + } + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void rankValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + sqlite3_result_int64(pCtx, p->nValue); + p->nValue = 0; } -#endif - yy_destructor(pParser, yytos->major, &yytos->minor); } /* -** Clear all secondary memory allocations from the parser +** Implementation of built-in window function percent_rank(). Assumes that +** the window frame has been set to: +** +** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING */ -SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ - yyParser *pParser = (yyParser*)p; - while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); -#if YYSTACKDEPTH<=0 - if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); -#endif +static void percent_rankStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + p->nTotal++; + } } +static void percent_rankInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p->nStep++; +} +static void percent_rankValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + p->nValue = p->nStep; + if( p->nTotal>1 ){ + double r = (double)p->nValue / (double)(p->nTotal-1); + sqlite3_result_double(pCtx, r); + }else{ + sqlite3_result_double(pCtx, 0.0); + } + } +} +#define percent_rankFinalizeFunc percent_rankValueFunc -#ifndef sqlite3Parser_ENGINEALWAYSONSTACK -/* -** Deallocate and destroy a parser. Destructors are called for -** all stack elements before shutting the parser down. +/* +** Implementation of built-in window function cume_dist(). Assumes that +** the window frame has been set to: ** -** If the YYPARSEFREENEVERNULL macro exists (for example because it -** is defined in a %include section of the input grammar) then it is -** assumed that the input pointer is never NULL. +** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING */ -SQLITE_PRIVATE void sqlite3ParserFree( - void *p, /* The parser to be deleted */ - void (*freeProc)(void*) /* Function used to reclaim memory */ +static void cume_distStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg ){ -#ifndef YYPARSEFREENEVERNULL - if( p==0 ) return; -#endif - sqlite3ParserFinalize(p); - (*freeProc)(p); + struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + p->nTotal++; + } } -#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ +static void cume_distInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p->nStep++; +} +static void cume_distValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, 0); + if( p ){ + double r = (double)(p->nStep) / (double)(p->nTotal); + sqlite3_result_double(pCtx, r); + } +} +#define cume_distFinalizeFunc cume_distValueFunc /* -** Return the peak depth of the stack for a parser. +** Context object for ntile() window function. */ -#ifdef YYTRACKMAXSTACKDEPTH -SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){ - yyParser *pParser = (yyParser*)p; - return pParser->yyhwm; -} -#endif +struct NtileCtx { + i64 nTotal; /* Total rows in partition */ + i64 nParam; /* Parameter passed to ntile(N) */ + i64 iRow; /* Current row */ +}; /* -** Find the appropriate action for a parser given the terminal -** look-ahead token iLookAhead. +** Implementation of ntile(). This assumes that the window frame has +** been coerced to: +** +** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING */ -static unsigned int yy_find_shift_action( - yyParser *pParser, /* The parser */ - YYCODETYPE iLookAhead /* The look-ahead token */ +static void ntileStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg ){ - int i; - int stateno = pParser->yytos->stateno; - - if( stateno>=YY_MIN_REDUCE ) return stateno; - assert( stateno <= YY_SHIFT_COUNT ); - do{ - i = yy_shift_ofst[stateno]; - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ -#ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ - iLookAhead = iFallback; - continue; - } -#endif -#ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( -#if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && -#endif -#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j0 - ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], - yyTokenName[YYWILDCARD]); - } -#endif /* NDEBUG */ - return yy_action[j]; - } + struct NtileCtx *p; + assert( nArg==1 ); UNUSED_PARAMETER(nArg); + p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + if( p->nTotal==0 ){ + p->nParam = sqlite3_value_int64(apArg[0]); + if( p->nParam<=0 ){ + sqlite3_result_error( + pCtx, "argument of ntile must be a positive integer", -1 + ); } -#endif /* YYWILDCARD */ - return yy_default[stateno]; - }else{ - return yy_action[i]; } - }while(1); + p->nTotal++; + } } - -/* -** Find the appropriate action for a parser given the non-terminal -** look-ahead token iLookAhead. -*/ -static int yy_find_reduce_action( - int stateno, /* Current state number */ - YYCODETYPE iLookAhead /* The look-ahead token */ +static void ntileInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg ){ - int i; -#ifdef YYERRORSYMBOL - if( stateno>YY_REDUCE_COUNT ){ - return yy_default[stateno]; - } -#else - assert( stateno<=YY_REDUCE_COUNT ); -#endif - i = yy_reduce_ofst[stateno]; - assert( i!=YY_REDUCE_USE_DFLT ); - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; -#ifdef YYERRORSYMBOL - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - return yy_default[stateno]; + struct NtileCtx *p; + assert( nArg==1 ); UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p->iRow++; +} +static void ntileValueFunc(sqlite3_context *pCtx){ + struct NtileCtx *p; + p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->nParam>0 ){ + int nSize = (p->nTotal / p->nParam); + if( nSize==0 ){ + sqlite3_result_int64(pCtx, p->iRow+1); + }else{ + i64 nLarge = p->nTotal - p->nParam*nSize; + i64 iSmall = nLarge*(nSize+1); + i64 iRow = p->iRow; + + assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal ); + + if( iRow=0 && iyytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will execute if the parser - ** stack every overflows */ -/******** Begin %stack_overflow code ******************************************/ - - sqlite3ErrorMsg(pParse, "parser stack overflow"); -/******** End %stack_overflow code ********************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ -} +struct LastValueCtx { + sqlite3_value *pVal; + int nVal; +}; /* -** Print tracing information for a SHIFT action +** Implementation of last_value(). */ -#ifndef NDEBUG -static void yyTraceShift(yyParser *yypParser, int yyNewState){ - if( yyTraceFILE ){ - if( yyNewStateyytos->major], - yyNewState); +static void last_valueStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct LastValueCtx *p; + UNUSED_PARAMETER(nArg); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + sqlite3_value_free(p->pVal); + p->pVal = sqlite3_value_dup(apArg[0]); + if( p->pVal==0 ){ + sqlite3_result_error_nomem(pCtx); }else{ - fprintf(yyTraceFILE,"%sShift '%s'\n", - yyTracePrompt,yyTokenName[yypParser->yytos->major]); + p->nVal++; } } } -#else -# define yyTraceShift(X,Y) -#endif - -/* -** Perform a shift action. -*/ -static void yy_shift( - yyParser *yypParser, /* The parser to be shifted */ - int yyNewState, /* The new state to shift in */ - int yyMajor, /* The major token to shift in */ - sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ +static void last_valueInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg ){ - yyStackEntry *yytos; - yypParser->yytos++; -#ifdef YYTRACKMAXSTACKDEPTH - if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ - yypParser->yyhwm++; - assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); + struct LastValueCtx *p; + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( ALWAYS(p) ){ + p->nVal--; + if( p->nVal==0 ){ + sqlite3_value_free(p->pVal); + p->pVal = 0; + } + } +} +static void last_valueValueFunc(sqlite3_context *pCtx){ + struct LastValueCtx *p; + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, 0); + if( p && p->pVal ){ + sqlite3_result_value(pCtx, p->pVal); + } +} +static void last_valueFinalizeFunc(sqlite3_context *pCtx){ + struct LastValueCtx *p; + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pVal ){ + sqlite3_result_value(pCtx, p->pVal); + sqlite3_value_free(p->pVal); + p->pVal = 0; + } +} + +/* +** Static names for the built-in window function names. These static +** names are used, rather than string literals, so that FuncDef objects +** can be associated with a particular window function by direct +** comparison of the zName pointer. Example: +** +** if( pFuncDef->zName==row_valueName ){ ... } +*/ +static const char row_numberName[] = "row_number"; +static const char dense_rankName[] = "dense_rank"; +static const char rankName[] = "rank"; +static const char percent_rankName[] = "percent_rank"; +static const char cume_distName[] = "cume_dist"; +static const char ntileName[] = "ntile"; +static const char last_valueName[] = "last_value"; +static const char nth_valueName[] = "nth_value"; +static const char first_valueName[] = "first_value"; +static const char leadName[] = "lead"; +static const char lagName[] = "lag"; + +/* +** No-op implementations of xStep() and xFinalize(). Used as place-holders +** for built-in window functions that never call those interfaces. +** +** The noopValueFunc() is called but is expected to do nothing. The +** noopStepFunc() is never called, and so it is marked with NO_TEST to +** let the test coverage routine know not to expect this function to be +** invoked. +*/ +static void noopStepFunc( /*NO_TEST*/ + sqlite3_context *p, /*NO_TEST*/ + int n, /*NO_TEST*/ + sqlite3_value **a /*NO_TEST*/ +){ /*NO_TEST*/ + UNUSED_PARAMETER(p); /*NO_TEST*/ + UNUSED_PARAMETER(n); /*NO_TEST*/ + UNUSED_PARAMETER(a); /*NO_TEST*/ + assert(0); /*NO_TEST*/ +} /*NO_TEST*/ +static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ } + +/* Window functions that use all window interfaces: xStep, xFinal, +** xValue, and xInverse */ +#define WINDOWFUNCALL(name,nArg,extra) { \ + nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \ + name ## InvFunc, name ## Name, {0} \ +} + +/* Window functions that are implemented using bytecode and thus have +** no-op routines for their methods */ +#define WINDOWFUNCNOOP(name,nArg,extra) { \ + nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + noopStepFunc, noopValueFunc, noopValueFunc, \ + noopStepFunc, name ## Name, {0} \ +} + +/* Window functions that use all window interfaces: xStep, the +** same routine for xFinalize and xValue and which never call +** xInverse. */ +#define WINDOWFUNCX(name,nArg,extra) { \ + nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \ + name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \ + noopStepFunc, name ## Name, {0} \ +} + + +/* +** Register those built-in window functions that are not also aggregates. +*/ +SQLITE_PRIVATE void sqlite3WindowFunctions(void){ + static FuncDef aWindowFuncs[] = { + WINDOWFUNCX(row_number, 0, 0), + WINDOWFUNCX(dense_rank, 0, 0), + WINDOWFUNCX(rank, 0, 0), + WINDOWFUNCALL(percent_rank, 0, 0), + WINDOWFUNCALL(cume_dist, 0, 0), + WINDOWFUNCALL(ntile, 1, 0), + WINDOWFUNCALL(last_value, 1, 0), + WINDOWFUNCALL(nth_value, 2, 0), + WINDOWFUNCALL(first_value, 1, 0), + WINDOWFUNCNOOP(lead, 1, 0), + WINDOWFUNCNOOP(lead, 2, 0), + WINDOWFUNCNOOP(lead, 3, 0), + WINDOWFUNCNOOP(lag, 1, 0), + WINDOWFUNCNOOP(lag, 2, 0), + WINDOWFUNCNOOP(lag, 3, 0), + }; + sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); +} + +static Window *windowFind(Parse *pParse, Window *pList, const char *zName){ + Window *p; + for(p=pList; p; p=p->pNextWin){ + if( sqlite3StrICmp(p->zName, zName)==0 ) break; } -#endif -#if YYSTACKDEPTH>0 - if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ - yypParser->yytos--; - yyStackOverflow(yypParser); - return; + if( p==0 ){ + sqlite3ErrorMsg(pParse, "no such window: %s", zName); } -#else - if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ - if( yyGrowStack(yypParser) ){ - yypParser->yytos--; - yyStackOverflow(yypParser); - return; + return p; +} + +/* +** This function is called immediately after resolving the function name +** for a window function within a SELECT statement. Argument pList is a +** linked list of WINDOW definitions for the current SELECT statement. +** Argument pFunc is the function definition just resolved and pWin +** is the Window object representing the associated OVER clause. This +** function updates the contents of pWin as follows: +** +** * If the OVER clause refered to a named window (as in "max(x) OVER win"), +** search list pList for a matching WINDOW definition, and update pWin +** accordingly. If no such WINDOW clause can be found, leave an error +** in pParse. +** +** * If the function is a built-in window function that requires the +** window to be coerced (see "BUILT-IN WINDOW FUNCTIONS" at the top +** of this file), pWin is updated here. +*/ +SQLITE_PRIVATE void sqlite3WindowUpdate( + Parse *pParse, + Window *pList, /* List of named windows for this SELECT */ + Window *pWin, /* Window frame to update */ + FuncDef *pFunc /* Window function definition */ +){ + if( pWin->zName && pWin->eFrmType==0 ){ + Window *p = windowFind(pParse, pList, pWin->zName); + if( p==0 ) return; + pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0); + pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0); + pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0); + pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0); + pWin->eStart = p->eStart; + pWin->eEnd = p->eEnd; + pWin->eFrmType = p->eFrmType; + pWin->eExclude = p->eExclude; + }else{ + sqlite3WindowChain(pParse, pWin, pList); + } + if( (pWin->eFrmType==TK_RANGE) + && (pWin->pStart || pWin->pEnd) + && (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1) + ){ + sqlite3ErrorMsg(pParse, + "RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression" + ); + }else + if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){ + sqlite3 *db = pParse->db; + if( pWin->pFilter ){ + sqlite3ErrorMsg(pParse, + "FILTER clause may only be used with aggregate window functions" + ); + }else{ + struct WindowUpdate { + const char *zFunc; + int eFrmType; + int eStart; + int eEnd; + } aUp[] = { + { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, + { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, + { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, + { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED }, + { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED }, + { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED }, + { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED }, + { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, + }; + int i; + for(i=0; izName==aUp[i].zFunc ){ + sqlite3ExprDelete(db, pWin->pStart); + sqlite3ExprDelete(db, pWin->pEnd); + pWin->pEnd = pWin->pStart = 0; + pWin->eFrmType = aUp[i].eFrmType; + pWin->eStart = aUp[i].eStart; + pWin->eEnd = aUp[i].eEnd; + pWin->eExclude = 0; + if( pWin->eStart==TK_FOLLOWING ){ + pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); + } + break; + } + } } } -#endif - if( yyNewState > YY_MAX_SHIFT ){ - yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - } - yytos = yypParser->yytos; - yytos->stateno = (YYACTIONTYPE)yyNewState; - yytos->major = (YYCODETYPE)yyMajor; - yytos->minor.yy0 = yyMinor; - yyTraceShift(yypParser, yyNewState); + pWin->pFunc = pFunc; } -/* The following table contains information about every rule that -** is used during the reduce. +/* +** Context object passed through sqlite3WalkExprList() to +** selectWindowRewriteExprCb() by selectWindowRewriteEList(). */ -static const struct { - YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ -} yyRuleInfo[] = { - { 147, 1 }, - { 147, 3 }, - { 148, 1 }, - { 149, 3 }, - { 150, 0 }, - { 150, 1 }, - { 150, 1 }, - { 150, 1 }, - { 149, 2 }, - { 149, 2 }, - { 149, 2 }, - { 149, 2 }, - { 149, 3 }, - { 149, 5 }, - { 154, 6 }, - { 156, 1 }, - { 158, 0 }, - { 158, 3 }, - { 157, 1 }, - { 157, 0 }, - { 155, 5 }, - { 155, 2 }, - { 162, 0 }, - { 162, 2 }, - { 164, 2 }, - { 166, 0 }, - { 166, 4 }, - { 166, 6 }, - { 167, 2 }, - { 171, 2 }, - { 171, 2 }, - { 171, 4 }, - { 171, 3 }, - { 171, 3 }, - { 171, 2 }, - { 171, 3 }, - { 171, 5 }, - { 171, 2 }, - { 171, 4 }, - { 171, 4 }, - { 171, 1 }, - { 171, 2 }, - { 176, 0 }, - { 176, 1 }, - { 178, 0 }, - { 178, 2 }, - { 180, 2 }, - { 180, 3 }, - { 180, 3 }, - { 180, 3 }, - { 181, 2 }, - { 181, 2 }, - { 181, 1 }, - { 181, 1 }, - { 181, 2 }, - { 179, 3 }, - { 179, 2 }, - { 182, 0 }, - { 182, 2 }, - { 182, 2 }, - { 161, 0 }, - { 184, 1 }, - { 185, 2 }, - { 185, 7 }, - { 185, 5 }, - { 185, 5 }, - { 185, 10 }, - { 188, 0 }, - { 174, 0 }, - { 174, 3 }, - { 189, 0 }, - { 189, 2 }, - { 190, 1 }, - { 190, 1 }, - { 149, 4 }, - { 192, 2 }, - { 192, 0 }, - { 149, 9 }, - { 149, 4 }, - { 149, 1 }, - { 163, 2 }, - { 194, 3 }, - { 197, 1 }, - { 197, 2 }, - { 197, 1 }, - { 195, 9 }, - { 206, 4 }, - { 206, 5 }, - { 198, 1 }, - { 198, 1 }, - { 198, 0 }, - { 209, 0 }, - { 199, 3 }, - { 199, 2 }, - { 199, 4 }, - { 210, 2 }, - { 210, 0 }, - { 200, 0 }, - { 200, 2 }, - { 212, 2 }, - { 212, 0 }, - { 211, 7 }, - { 211, 9 }, - { 211, 7 }, - { 211, 7 }, - { 159, 0 }, - { 159, 2 }, - { 193, 2 }, - { 213, 1 }, - { 213, 2 }, - { 213, 3 }, - { 213, 4 }, - { 215, 2 }, - { 215, 0 }, - { 214, 0 }, - { 214, 3 }, - { 214, 2 }, - { 216, 4 }, - { 216, 0 }, - { 204, 0 }, - { 204, 3 }, - { 186, 4 }, - { 186, 2 }, - { 175, 1 }, - { 175, 1 }, - { 175, 0 }, - { 202, 0 }, - { 202, 3 }, - { 203, 0 }, - { 203, 2 }, - { 205, 0 }, - { 205, 2 }, - { 205, 4 }, - { 205, 4 }, - { 149, 6 }, - { 201, 0 }, - { 201, 2 }, - { 149, 8 }, - { 218, 5 }, - { 218, 7 }, - { 218, 3 }, - { 218, 5 }, - { 149, 6 }, - { 149, 7 }, - { 219, 2 }, - { 219, 1 }, - { 220, 0 }, - { 220, 3 }, - { 217, 3 }, - { 217, 1 }, - { 173, 3 }, - { 172, 1 }, - { 173, 1 }, - { 173, 1 }, - { 173, 3 }, - { 173, 5 }, - { 172, 1 }, - { 172, 1 }, - { 172, 1 }, - { 173, 1 }, - { 173, 3 }, - { 173, 6 }, - { 173, 5 }, - { 173, 4 }, - { 172, 1 }, - { 173, 5 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 173, 3 }, - { 221, 1 }, - { 221, 2 }, - { 173, 3 }, - { 173, 5 }, - { 173, 2 }, - { 173, 3 }, - { 173, 3 }, - { 173, 4 }, - { 173, 2 }, - { 173, 2 }, - { 173, 2 }, - { 173, 2 }, - { 222, 1 }, - { 222, 2 }, - { 173, 5 }, - { 223, 1 }, - { 223, 2 }, - { 173, 5 }, - { 173, 3 }, - { 173, 5 }, - { 173, 5 }, - { 173, 4 }, - { 173, 5 }, - { 226, 5 }, - { 226, 4 }, - { 227, 2 }, - { 227, 0 }, - { 225, 1 }, - { 225, 0 }, - { 208, 0 }, - { 207, 3 }, - { 207, 1 }, - { 224, 0 }, - { 224, 3 }, - { 149, 12 }, - { 228, 1 }, - { 228, 0 }, - { 177, 0 }, - { 177, 3 }, - { 187, 5 }, - { 187, 3 }, - { 229, 0 }, - { 229, 2 }, - { 149, 4 }, - { 149, 1 }, - { 149, 2 }, - { 149, 3 }, - { 149, 5 }, - { 149, 6 }, - { 149, 5 }, - { 149, 6 }, - { 169, 2 }, - { 170, 2 }, - { 149, 5 }, - { 231, 11 }, - { 233, 1 }, - { 233, 1 }, - { 233, 2 }, - { 233, 0 }, - { 234, 1 }, - { 234, 1 }, - { 234, 3 }, - { 236, 0 }, - { 236, 2 }, - { 232, 3 }, - { 232, 2 }, - { 238, 3 }, - { 239, 3 }, - { 239, 2 }, - { 237, 7 }, - { 237, 5 }, - { 237, 5 }, - { 237, 1 }, - { 173, 4 }, - { 173, 6 }, - { 191, 1 }, - { 191, 1 }, - { 191, 1 }, - { 149, 4 }, - { 149, 6 }, - { 149, 3 }, - { 241, 0 }, - { 241, 2 }, - { 149, 1 }, - { 149, 3 }, - { 149, 1 }, - { 149, 3 }, - { 149, 6 }, - { 149, 7 }, - { 242, 1 }, - { 149, 1 }, - { 149, 4 }, - { 244, 8 }, - { 246, 0 }, - { 247, 1 }, - { 247, 3 }, - { 248, 1 }, - { 196, 0 }, - { 196, 2 }, - { 196, 3 }, - { 250, 6 }, - { 250, 8 }, - { 144, 1 }, - { 145, 2 }, - { 145, 1 }, - { 146, 1 }, - { 146, 3 }, - { 147, 0 }, - { 151, 0 }, - { 151, 1 }, - { 151, 2 }, - { 153, 1 }, - { 153, 0 }, - { 149, 2 }, - { 160, 4 }, - { 160, 2 }, - { 152, 1 }, - { 152, 1 }, - { 152, 1 }, - { 166, 1 }, - { 167, 1 }, - { 168, 1 }, - { 168, 1 }, - { 165, 2 }, - { 165, 0 }, - { 171, 2 }, - { 161, 2 }, - { 183, 3 }, - { 183, 1 }, - { 184, 0 }, - { 188, 1 }, - { 190, 1 }, - { 194, 1 }, - { 195, 1 }, - { 209, 2 }, - { 210, 1 }, - { 173, 1 }, - { 208, 1 }, - { 230, 1 }, - { 230, 1 }, - { 230, 1 }, - { 230, 1 }, - { 230, 1 }, - { 169, 1 }, - { 235, 0 }, - { 235, 3 }, - { 238, 1 }, - { 239, 0 }, - { 240, 1 }, - { 240, 0 }, - { 243, 0 }, - { 243, 1 }, - { 245, 1 }, - { 245, 3 }, - { 246, 2 }, - { 249, 0 }, - { 249, 4 }, - { 249, 2 }, +typedef struct WindowRewrite WindowRewrite; +struct WindowRewrite { + Window *pWin; + SrcList *pSrc; + ExprList *pSub; + Table *pTab; + Select *pSubSelect; /* Current sub-select, if any */ }; -static void yy_accept(yyParser*); /* Forward Declaration */ - /* -** Perform a reduce action and the shift that must immediately -** follow the reduce. +** Callback function used by selectWindowRewriteEList(). If necessary, +** this function appends to the output expression-list and updates +** expression (*ppExpr) in place. */ -static void yy_reduce( - yyParser *yypParser, /* The parser */ - unsigned int yyruleno /* Number of the rule by which to reduce */ -){ - int yygoto; /* The next state */ - int yyact; /* The next action */ - yyStackEntry *yymsp; /* The top of the parser's stack */ - int yysize; /* Amount to pop the stack */ - sqlite3ParserARG_FETCH; - yymsp = yypParser->yytos; -#ifndef NDEBUG - if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - yysize = yyRuleInfo[yyruleno].nrhs; - fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, - yyRuleName[yyruleno], yymsp[-yysize].stateno); - } -#endif /* NDEBUG */ - - /* Check that the stack is large enough to grow by a single entry - ** if the RHS of the rule is empty. This ensures that there is room - ** enough on the stack to push the LHS value */ - if( yyRuleInfo[yyruleno].nrhs==0 ){ -#ifdef YYTRACKMAXSTACKDEPTH - if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ - yypParser->yyhwm++; - assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); - } -#endif -#if YYSTACKDEPTH>0 - if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ - yyStackOverflow(yypParser); - return; - } -#else - if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ - if( yyGrowStack(yypParser) ){ - yyStackOverflow(yypParser); - return; +static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ + struct WindowRewrite *p = pWalker->u.pRewrite; + Parse *pParse = pWalker->pParse; + assert( p!=0 ); + assert( p->pWin!=0 ); + + /* If this function is being called from within a scalar sub-select + ** that used by the SELECT statement being processed, only process + ** TK_COLUMN expressions that refer to it (the outer SELECT). Do + ** not process aggregates or window functions at all, as they belong + ** to the scalar sub-select. */ + if( p->pSubSelect ){ + if( pExpr->op!=TK_COLUMN ){ + return WRC_Continue; + }else{ + int nSrc = p->pSrc->nSrc; + int i; + for(i=0; iiTable==p->pSrc->a[i].iCursor ) break; } - yymsp = yypParser->yytos; + if( i==nSrc ) return WRC_Continue; } -#endif } - switch( yyruleno ){ - /* Beginning here are the reduction cases. A typical example - ** follows: - ** case 0: - ** #line - ** { ... } // User supplied code - ** #line - ** break; - */ -/********** Begin reduce actions **********************************************/ - YYMINORTYPE yylhsminor; - case 0: /* explain ::= EXPLAIN */ -{ pParse->explain = 1; } - break; - case 1: /* explain ::= EXPLAIN QUERY PLAN */ -{ pParse->explain = 2; } + switch( pExpr->op ){ + + case TK_FUNCTION: + if( !ExprHasProperty(pExpr, EP_WinFunc) ){ break; - case 2: /* cmdx ::= cmd */ -{ sqlite3FinishCoding(pParse); } - break; - case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy194);} - break; - case 4: /* transtype ::= */ -{yymsp[1].minor.yy194 = TK_DEFERRED;} - break; - case 5: /* transtype ::= DEFERRED */ - case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); - case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); -{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/} - break; - case 8: /* cmd ::= COMMIT trans_opt */ - case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9); -{sqlite3CommitTransaction(pParse);} - break; - case 10: /* cmd ::= ROLLBACK trans_opt */ -{sqlite3RollbackTransaction(pParse);} - break; - case 11: /* cmd ::= SAVEPOINT nm */ -{ - sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); -} - break; - case 12: /* cmd ::= RELEASE savepoint_opt nm */ -{ - sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); -} - break; - case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ -{ - sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); -} - break; - case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ -{ - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194); -} - break; - case 15: /* createkw ::= CREATE */ -{disableLookaside(pParse);} - break; - case 16: /* ifnotexists ::= */ - case 19: /* temp ::= */ yytestcase(yyruleno==19); - case 22: /* table_options ::= */ yytestcase(yyruleno==22); - case 42: /* autoinc ::= */ yytestcase(yyruleno==42); - case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); - case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); - case 76: /* ifexists ::= */ yytestcase(yyruleno==76); - case 90: /* distinct ::= */ yytestcase(yyruleno==90); - case 215: /* collate ::= */ yytestcase(yyruleno==215); -{yymsp[1].minor.yy194 = 0;} - break; - case 17: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy194 = 1;} - break; - case 18: /* temp ::= TEMP */ - case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); -{yymsp[0].minor.yy194 = 1;} - break; - case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ -{ - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0); -} - break; - case 21: /* create_table_args ::= AS select */ -{ - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); -} - break; - case 23: /* table_options ::= WITHOUT nm */ -{ - if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid; - }else{ - yymsp[-1].minor.yy194 = 0; - sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); + }else{ + Window *pWin; + for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ + if( pExpr->y.pWin==pWin ){ + assert( pWin->pOwner==pExpr ); + return WRC_Prune; + } + } + } + /* no break */ deliberate_fall_through + + case TK_AGG_FUNCTION: + case TK_COLUMN: { + int iCol = -1; + if( pParse->db->mallocFailed ) return WRC_Abort; + if( p->pSub ){ + int i; + for(i=0; ipSub->nExpr; i++){ + if( 0==sqlite3ExprCompare(0, p->pSub->a[i].pExpr, pExpr, -1) ){ + iCol = i; + break; + } + } + } + if( iCol<0 ){ + Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0); + if( pDup && pDup->op==TK_AGG_FUNCTION ) pDup->op = TK_FUNCTION; + p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup); + } + if( p->pSub ){ + int f = pExpr->flags & EP_Collate; + assert( ExprHasProperty(pExpr, EP_Static)==0 ); + ExprSetProperty(pExpr, EP_Static); + sqlite3ExprDelete(pParse->db, pExpr); + ExprClearProperty(pExpr, EP_Static); + memset(pExpr, 0, sizeof(Expr)); + + pExpr->op = TK_COLUMN; + pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol); + pExpr->iTable = p->pWin->iEphCsr; + pExpr->y.pTab = p->pTab; + pExpr->flags = f; + } + if( pParse->db->mallocFailed ) return WRC_Abort; + break; + } + + default: /* no-op */ + break; } + + return WRC_Continue; } - break; - case 24: /* columnname ::= nm typetoken */ -{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} - break; - case 25: /* typetoken ::= */ - case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60); - case 96: /* as ::= */ yytestcase(yyruleno==96); -{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} - break; - case 26: /* typetoken ::= typename LP signed RP */ -{ - yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); -} - break; - case 27: /* typetoken ::= typename LP signed COMMA signed RP */ -{ - yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); -} - break; - case 28: /* typename ::= typename ID|STRING */ -{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} - break; - case 29: /* ccons ::= CONSTRAINT nm */ - case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62); -{pParse->constraintName = yymsp[0].minor.yy0;} - break; - case 30: /* ccons ::= DEFAULT term */ - case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32); -{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);} - break; - case 31: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);} - break; - case 33: /* ccons ::= DEFAULT MINUS term */ -{ - ExprSpan v; - v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0); - v.zStart = yymsp[-1].minor.yy0.z; - v.zEnd = yymsp[0].minor.yy190.zEnd; - sqlite3AddDefaultValue(pParse,&v); -} - break; - case 34: /* ccons ::= DEFAULT ID|INDEXED */ -{ - ExprSpan v; - spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0); - sqlite3AddDefaultValue(pParse,&v); -} - break; - case 35: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);} - break; - case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);} - break; - case 37: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0, - SQLITE_IDXTYPE_UNIQUE);} - break; - case 38: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);} - break; - case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);} - break; - case 40: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);} - break; - case 41: /* ccons ::= COLLATE ID|STRING */ -{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} - break; - case 44: /* refargs ::= */ -{ yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */} - break; - case 45: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; } - break; - case 46: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; } - break; - case 47: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; } - break; - case 48: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; } - break; - case 49: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; } - break; - case 50: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */} - break; - case 51: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */} - break; - case 52: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */} - break; - case 53: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */} - break; - case 54: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */} - break; - case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy194 = 0;} - break; - case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); - case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144); -{yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;} - break; - case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ - case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); - case 187: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==187); - case 190: /* in_op ::= NOT IN */ yytestcase(yyruleno==190); - case 216: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==216); -{yymsp[-1].minor.yy194 = 1;} - break; - case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy194 = 0;} - break; - case 61: /* tconscomma ::= COMMA */ -{pParse->constraintName.n = 0;} - break; - case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);} - break; - case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0, - SQLITE_IDXTYPE_UNIQUE);} - break; - case 65: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);} - break; - case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ -{ - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194); -} - break; - case 68: /* onconf ::= */ - case 70: /* orconf ::= */ yytestcase(yyruleno==70); -{yymsp[1].minor.yy194 = OE_Default;} - break; - case 69: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;} - break; - case 72: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy194 = OE_Ignore;} - break; - case 73: /* resolvetype ::= REPLACE */ - case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145); -{yymsp[0].minor.yy194 = OE_Replace;} - break; - case 74: /* cmd ::= DROP TABLE ifexists fullname */ -{ - sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194); -} - break; - case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ -{ - sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194); -} - break; - case 78: /* cmd ::= DROP VIEW ifexists fullname */ -{ - sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194); -} - break; - case 79: /* cmd ::= select */ -{ - SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy243, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243); -} - break; - case 80: /* select ::= with selectnowith */ -{ - Select *p = yymsp[0].minor.yy243; - if( p ){ - p->pWith = yymsp[-1].minor.yy285; - parserDoubleLinkSelect(pParse, p); +static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){ + struct WindowRewrite *p = pWalker->u.pRewrite; + Select *pSave = p->pSubSelect; + if( pSave==pSelect ){ + return WRC_Continue; }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy285); + p->pSubSelect = pSelect; + sqlite3WalkSelect(pWalker, pSelect); + p->pSubSelect = pSave; } - yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/ + return WRC_Prune; } - break; - case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */ -{ - Select *pRhs = yymsp[0].minor.yy243; - Select *pLhs = yymsp[-2].minor.yy243; - if( pRhs && pRhs->pPrior ){ - SrcList *pFrom; - Token x; - x.n = 0; - parserDoubleLinkSelect(pParse, pRhs); - pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); - pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0); - } - if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy194; - pRhs->pPrior = pLhs; - if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; - pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy194!=TK_ALL ) pParse->hasCompound = 1; - }else{ - sqlite3SelectDelete(pParse->db, pLhs); - } - yymsp[-2].minor.yy243 = pRhs; + + +/* +** Iterate through each expression in expression-list pEList. For each: +** +** * TK_COLUMN, +** * aggregate function, or +** * window function with a Window object that is not a member of the +** Window list passed as the second argument (pWin). +** +** Append the node to output expression-list (*ppSub). And replace it +** with a TK_COLUMN that reads the (N-1)th element of table +** pWin->iEphCsr, where N is the number of elements in (*ppSub) after +** appending the new one. +*/ +static void selectWindowRewriteEList( + Parse *pParse, + Window *pWin, + SrcList *pSrc, + ExprList *pEList, /* Rewrite expressions in this list */ + Table *pTab, + ExprList **ppSub /* IN/OUT: Sub-select expression-list */ +){ + Walker sWalker; + WindowRewrite sRewrite; + + assert( pWin!=0 ); + memset(&sWalker, 0, sizeof(Walker)); + memset(&sRewrite, 0, sizeof(WindowRewrite)); + + sRewrite.pSub = *ppSub; + sRewrite.pWin = pWin; + sRewrite.pSrc = pSrc; + sRewrite.pTab = pTab; + + sWalker.pParse = pParse; + sWalker.xExprCallback = selectWindowRewriteExprCb; + sWalker.xSelectCallback = selectWindowRewriteSelectCb; + sWalker.u.pRewrite = &sRewrite; + + (void)sqlite3WalkExprList(&sWalker, pEList); + + *ppSub = sRewrite.pSub; } - break; - case 82: /* multiselect_op ::= UNION */ - case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84); -{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/} - break; - case 83: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy194 = TK_ALL;} - break; - case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ -{ -#if SELECTTRACE_ENABLED - Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/ -#endif - yymsp[-8].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy148,yymsp[-5].minor.yy185,yymsp[-4].minor.yy72,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-1].minor.yy148,yymsp[-7].minor.yy194,yymsp[0].minor.yy354.pLimit,yymsp[0].minor.yy354.pOffset); -#if SELECTTRACE_ENABLED - /* Populate the Select.zSelName[] string that is used to help with - ** query planner debugging, to differentiate between multiple Select - ** objects in a complex query. - ** - ** If the SELECT keyword is immediately followed by a C-style comment - ** then extract the first few alphanumeric characters from within that - ** comment to be the zSelName value. Otherwise, the label is #N where - ** is an integer that is incremented with each SELECT statement seen. - */ - if( yymsp[-8].minor.yy243!=0 ){ - const char *z = s.z+6; + +/* +** Append a copy of each expression in expression-list pAppend to +** expression list pList. Return a pointer to the result list. +*/ +static ExprList *exprListAppendList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to append. Might be NULL */ + ExprList *pAppend, /* List of values to append. Might be NULL */ + int bIntToNull +){ + if( pAppend ){ int i; - sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "#%d", - ++pParse->nSelect); - while( z[0]==' ' ) z++; - if( z[0]=='/' && z[1]=='*' ){ - z += 2; - while( z[0]==' ' ) z++; - for(i=0; sqlite3Isalnum(z[i]); i++){} - sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "%.*s", i, z); + int nInit = pList ? pList->nExpr : 0; + for(i=0; inExpr; i++){ + sqlite3 *db = pParse->db; + Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0); + assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) ); + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDup); + break; + } + if( bIntToNull ){ + int iDummy; + Expr *pSub; + pSub = sqlite3ExprSkipCollateAndLikely(pDup); + if( sqlite3ExprIsInteger(pSub, &iDummy) ){ + pSub->op = TK_NULL; + pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); + pSub->u.zToken = 0; + } + } + pList = sqlite3ExprListAppend(pParse, pList, pDup); + if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags; } } -#endif /* SELECTRACE_ENABLED */ -} - break; - case 86: /* values ::= VALUES LP nexprlist RP */ -{ - yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0); + return pList; } - break; - case 87: /* values ::= values COMMA LP exprlist RP */ -{ - Select *pRight, *pLeft = yymsp[-4].minor.yy243; - pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); - if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; - if( pRight ){ - pRight->op = TK_ALL; - pRight->pPrior = pLeft; - yymsp[-4].minor.yy243 = pRight; - }else{ - yymsp[-4].minor.yy243 = pLeft; + +/* +** When rewriting a query, if the new subquery in the FROM clause +** contains TK_AGG_FUNCTION nodes that refer to an outer query, +** then we have to increase the Expr->op2 values of those nodes +** due to the extra subquery layer that was added. +** +** See also the incrAggDepth() routine in resolve.c +*/ +static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_AGG_FUNCTION + && pExpr->op2>=pWalker->walkerDepth + ){ + pExpr->op2++; } + return WRC_Continue; } - break; - case 88: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy194 = SF_Distinct;} - break; - case 89: /* distinct ::= ALL */ -{yymsp[0].minor.yy194 = SF_All;} - break; - case 91: /* sclp ::= */ - case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119); - case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126); - case 203: /* exprlist ::= */ yytestcase(yyruleno==203); - case 206: /* paren_exprlist ::= */ yytestcase(yyruleno==206); - case 211: /* eidlist_opt ::= */ yytestcase(yyruleno==211); -{yymsp[1].minor.yy148 = 0;} - break; - case 92: /* selcollist ::= sclp expr as */ -{ - yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190); -} - break; - case 93: /* selcollist ::= sclp STAR */ -{ - Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p); -} - break; - case 94: /* selcollist ::= sclp nm DOT STAR */ -{ - Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); - Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); - Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot); -} - break; - case 95: /* as ::= AS nm */ - case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106); - case 225: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==225); - case 226: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==226); -{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} - break; - case 97: /* from ::= */ -{yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));} - break; - case 98: /* from ::= FROM seltablist */ -{ - yymsp[-1].minor.yy185 = yymsp[0].minor.yy185; - sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185); -} - break; - case 99: /* stl_prefix ::= seltablist joinop */ -{ - if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194; -} - break; - case 100: /* stl_prefix ::= */ -{yymsp[1].minor.yy185 = 0;} - break; - case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ -{ - yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); - sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0); -} - break; - case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ -{ - yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); - sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148); -} - break; - case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ -{ - yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + +static int disallowAggregatesInOrderByCb(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_AGG_FUNCTION && pExpr->pAggInfo==0 ){ + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + sqlite3ErrorMsg(pWalker->pParse, + "misuse of aggregate: %s()", pExpr->u.zToken); } - break; - case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ -{ - if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){ - yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185; - }else if( yymsp[-4].minor.yy185->nSrc==1 ){ - yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); - if( yymsp[-6].minor.yy185 ){ - struct SrcList_item *pNew = &yymsp[-6].minor.yy185->a[yymsp[-6].minor.yy185->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy185->a; - pNew->zName = pOld->zName; - pNew->zDatabase = pOld->zDatabase; - pNew->pSelect = pOld->pSelect; - pOld->zName = pOld->zDatabase = 0; - pOld->pSelect = 0; + return WRC_Continue; +} + +/* +** If the SELECT statement passed as the second argument does not invoke +** any SQL window functions, this function is a no-op. Otherwise, it +** rewrites the SELECT statement so that window function xStep functions +** are invoked in the correct order as described under "SELECT REWRITING" +** at the top of this file. +*/ +SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ + int rc = SQLITE_OK; + if( p->pWin + && p->pPrior==0 + && ALWAYS((p->selFlags & SF_WinRewrite)==0) + && ALWAYS(!IN_RENAME_OBJECT) + ){ + Vdbe *v = sqlite3GetVdbe(pParse); + sqlite3 *db = pParse->db; + Select *pSub = 0; /* The subquery */ + SrcList *pSrc = p->pSrc; + Expr *pWhere = p->pWhere; + ExprList *pGroupBy = p->pGroupBy; + Expr *pHaving = p->pHaving; + ExprList *pSort = 0; + + ExprList *pSublist = 0; /* Expression list for sub-query */ + Window *pMWin = p->pWin; /* Main window object */ + Window *pWin; /* Window object iterator */ + Table *pTab; + Walker w; + + u32 selFlags = p->selFlags; + + pTab = sqlite3DbMallocZero(db, sizeof(Table)); + if( pTab==0 ){ + return sqlite3ErrorToParser(db, SQLITE_NOMEM); + } + sqlite3AggInfoPersistWalkerInit(&w, pParse); + sqlite3WalkSelect(&w, p); + if( (p->selFlags & SF_Aggregate)==0 ){ + w.xExprCallback = disallowAggregatesInOrderByCb; + w.xSelectCallback = 0; + sqlite3WalkExprList(&w, p->pOrderBy); + } + + p->pSrc = 0; + p->pWhere = 0; + p->pGroupBy = 0; + p->pHaving = 0; + p->selFlags &= ~SF_Aggregate; + p->selFlags |= SF_WinRewrite; + + /* Create the ORDER BY clause for the sub-select. This is the concatenation + ** of the window PARTITION and ORDER BY clauses. Then, if this makes it + ** redundant, remove the ORDER BY from the parent SELECT. */ + pSort = exprListAppendList(pParse, 0, pMWin->pPartition, 1); + pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1); + if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){ + int nSave = pSort->nExpr; + pSort->nExpr = p->pOrderBy->nExpr; + if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){ + sqlite3ExprListDelete(db, p->pOrderBy); + p->pOrderBy = 0; + } + pSort->nExpr = nSave; + } + + /* Assign a cursor number for the ephemeral table used to buffer rows. + ** The OpenEphemeral instruction is coded later, after it is known how + ** many columns the table will have. */ + pMWin->iEphCsr = pParse->nTab++; + pParse->nTab += 3; + + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, pTab, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist); + pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); + + /* Append the PARTITION BY and ORDER BY expressions to the to the + ** sub-select expression list. They are required to figure out where + ** boundaries for partitions and sets of peer rows lie. */ + pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0); + pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0); + + /* Append the arguments passed to each window function to the + ** sub-select expression list. Also allocate two registers for each + ** window function - one for the accumulator, another for interim + ** results. */ + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + ExprList *pArgs; + assert( ExprUseXList(pWin->pOwner) ); + assert( pWin->pFunc!=0 ); + pArgs = pWin->pOwner->x.pList; + if( pWin->pFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){ + selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); + pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); + pWin->bExprArgs = 1; + }else{ + pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); + pSublist = exprListAppendList(pParse, pSublist, pArgs, 0); } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy185); - }else{ - Select *pSubquery; - sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy185); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy185,0,0,0,0,SF_NestedFrom,0,0); - yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy72,yymsp[0].minor.yy254); + if( pWin->pFilter ){ + Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0); + pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter); + } + pWin->regAccum = ++pParse->nMem; + pWin->regResult = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); } - } - break; - case 105: /* dbnm ::= */ - case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114); -{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} - break; - case 107: /* fullname ::= nm dbnm */ -{yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} - break; - case 108: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy194 = JT_INNER; } - break; - case 109: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} - break; - case 110: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} - break; - case 111: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} - break; - case 112: /* on_opt ::= ON expr */ - case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129); - case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136); - case 199: /* case_else ::= ELSE expr */ yytestcase(yyruleno==199); -{yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;} - break; - case 113: /* on_opt ::= */ - case 128: /* having_opt ::= */ yytestcase(yyruleno==128); - case 135: /* where_opt ::= */ yytestcase(yyruleno==135); - case 200: /* case_else ::= */ yytestcase(yyruleno==200); - case 202: /* case_operand ::= */ yytestcase(yyruleno==202); -{yymsp[1].minor.yy72 = 0;} - break; - case 115: /* indexed_opt ::= INDEXED BY nm */ -{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} - break; - case 116: /* indexed_opt ::= NOT INDEXED */ -{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} - break; - case 117: /* using_opt ::= USING LP idlist RP */ -{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;} - break; - case 118: /* using_opt ::= */ - case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146); -{yymsp[1].minor.yy254 = 0;} - break; - case 120: /* orderby_opt ::= ORDER BY sortlist */ - case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127); -{yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;} - break; - case 121: /* sortlist ::= sortlist COMMA expr sortorder */ -{ - yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr); - sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194); -} - break; - case 122: /* sortlist ::= expr sortorder */ -{ - yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194); -} - break; - case 123: /* sortorder ::= ASC */ -{yymsp[0].minor.yy194 = SQLITE_SO_ASC;} - break; - case 124: /* sortorder ::= DESC */ -{yymsp[0].minor.yy194 = SQLITE_SO_DESC;} - break; - case 125: /* sortorder ::= */ -{yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;} - break; - case 130: /* limit_opt ::= */ -{yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;} - break; - case 131: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;} - break; - case 132: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;} - break; - case 133: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;} - break; - case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ -{ - sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy185, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy185,yymsp[0].minor.yy72); -} - break; - case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ -{ - sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1); - sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy148,"set list"); - sqlite3Update(pParse,yymsp[-4].minor.yy185,yymsp[-1].minor.yy148,yymsp[0].minor.yy72,yymsp[-5].minor.yy194); -} - break; - case 138: /* setlist ::= setlist COMMA nm EQ expr */ -{ - yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1); -} - break; - case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ -{ - yymsp[-6].minor.yy148 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy148, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); -} - break; - case 140: /* setlist ::= nm EQ expr */ -{ - yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr); - sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1); -} - yymsp[-2].minor.yy148 = yylhsminor.yy148; - break; - case 141: /* setlist ::= LP idlist RP EQ expr */ -{ - yymsp[-4].minor.yy148 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr); -} - break; - case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ -{ - sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1); - sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194); -} - break; - case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ -{ - sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1); - sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194); -} - break; - case 147: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} - break; - case 148: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} - break; - case 149: /* idlist ::= nm */ -{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} - break; - case 150: /* expr ::= LP expr RP */ -{spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;} - break; - case 151: /* term ::= NULL */ - case 156: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==156); - case 157: /* term ::= STRING */ yytestcase(yyruleno==157); -{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/} - break; - case 152: /* expr ::= ID|INDEXED */ - case 153: /* expr ::= JOIN_KW */ yytestcase(yyruleno==153); -{spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} - break; - case 154: /* expr ::= nm DOT nm */ -{ - Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); - Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); - spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); -} - break; - case 155: /* expr ::= nm DOT nm DOT nm */ -{ - Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); - Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); - Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); - Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); - spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); -} - break; - case 158: /* term ::= INTEGER */ -{ - yylhsminor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); - yylhsminor.yy190.zStart = yymsp[0].minor.yy0.z; - yylhsminor.yy190.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n; - if( yylhsminor.yy190.pExpr ) yylhsminor.yy190.pExpr->flags |= EP_Leaf; -} - yymsp[0].minor.yy190 = yylhsminor.yy190; - break; - case 159: /* expr ::= VARIABLE */ -{ - if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ - u32 n = yymsp[0].minor.yy0.n; - spanExpr(&yymsp[0].minor.yy190, pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy190.pExpr, n); - }else{ - /* When doing a nested parse, one can include terms in an expression - ** that look like this: #1 #2 ... These terms refer to registers - ** in the virtual machine. #N is the N-th register. */ - Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ - assert( t.n>=2 ); - spanSet(&yymsp[0].minor.yy190, &t, &t); - if( pParse->nested==0 ){ - sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); - yymsp[0].minor.yy190.pExpr = 0; + + /* If there is no ORDER BY or PARTITION BY clause, and the window + ** function accepts zero arguments, and there are no other columns + ** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible + ** that pSublist is still NULL here. Add a constant expression here to + ** keep everything legal in this case. + */ + if( pSublist==0 ){ + pSublist = sqlite3ExprListAppend(pParse, 0, + sqlite3Expr(db, TK_INTEGER, "0") + ); + } + + pSub = sqlite3SelectNew( + pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 + ); + SELECTTRACE(1,pParse,pSub, + ("New window-function subquery in FROM clause of (%u/%p)\n", + p->selId, p)); + p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); + assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside + ** of sqlite3DbMallocRawNN() called from + ** sqlite3SrcListAppend() */ + if( p->pSrc ){ + Table *pTab2; + p->pSrc->a[0].pSelect = pSub; + sqlite3SrcListAssignCursors(pParse, p->pSrc); + pSub->selFlags |= SF_Expanded|SF_OrderByReqd; + pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); + pSub->selFlags |= (selFlags & SF_Aggregate); + if( pTab2==0 ){ + /* Might actually be some other kind of error, but in that case + ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get + ** the correct error message regardless. */ + rc = SQLITE_NOMEM; + }else{ + memcpy(pTab, pTab2, sizeof(Table)); + pTab->tabFlags |= TF_Ephemeral; + p->pSrc->a[0].pTab = pTab; + pTab = pTab2; + memset(&w, 0, sizeof(w)); + w.xExprCallback = sqlite3WindowExtraAggFuncDepth; + w.xSelectCallback = sqlite3WalkerDepthIncrease; + w.xSelectCallback2 = sqlite3WalkerDepthDecrease; + sqlite3WalkSelect(&w, pSub); + } }else{ - yymsp[0].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); - if( yymsp[0].minor.yy190.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy190.pExpr->iTable); + sqlite3SelectDelete(db, pSub); } + if( db->mallocFailed ) rc = SQLITE_NOMEM; + + /* Defer deleting the temporary table pTab because if an error occurred, + ** there could still be references to that table embedded in the + ** result-set or ORDER BY clause of the SELECT statement p. */ + sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pTab); } + + assert( rc==SQLITE_OK || pParse->nErr!=0 ); + return rc; } - break; - case 160: /* expr ::= expr COLLATE ID|STRING */ -{ - yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1); - yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; -} - break; - case 161: /* expr ::= CAST LP expr AS typetoken RP */ -{ - spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); - sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, 0); -} - break; - case 162: /* expr ::= ID|INDEXED LP distinct exprlist RP */ -{ - if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ - sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); - } - yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy148, &yymsp[-4].minor.yy0); - spanSet(&yylhsminor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); - if( yymsp[-2].minor.yy194==SF_Distinct && yylhsminor.yy190.pExpr ){ - yylhsminor.yy190.pExpr->flags |= EP_Distinct; + +/* +** Unlink the Window object from the Select to which it is attached, +** if it is attached. +*/ +SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window *p){ + if( p->ppThis ){ + *p->ppThis = p->pNextWin; + if( p->pNextWin ) p->pNextWin->ppThis = p->ppThis; + p->ppThis = 0; } } - yymsp[-4].minor.yy190 = yylhsminor.yy190; - break; - case 163: /* expr ::= ID|INDEXED LP STAR RP */ -{ - yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); - spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); -} - yymsp[-3].minor.yy190 = yylhsminor.yy190; - break; - case 164: /* term ::= CTIME_KW */ -{ - yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); - spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); -} - yymsp[0].minor.yy190 = yylhsminor.yy190; - break; - case 165: /* expr ::= LP nexprlist COMMA expr RP */ -{ - ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy148, yymsp[-1].minor.yy190.pExpr); - yylhsminor.yy190.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( yylhsminor.yy190.pExpr ){ - yylhsminor.yy190.pExpr->x.pList = pList; - spanSet(&yylhsminor.yy190, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); - }else{ - sqlite3ExprListDelete(pParse->db, pList); + +/* +** Free the Window object passed as the second argument. +*/ +SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3 *db, Window *p){ + if( p ){ + sqlite3WindowUnlinkFromSelect(p); + sqlite3ExprDelete(db, p->pFilter); + sqlite3ExprListDelete(db, p->pPartition); + sqlite3ExprListDelete(db, p->pOrderBy); + sqlite3ExprDelete(db, p->pEnd); + sqlite3ExprDelete(db, p->pStart); + sqlite3DbFree(db, p->zName); + sqlite3DbFree(db, p->zBase); + sqlite3DbFree(db, p); } } - yymsp[-4].minor.yy190 = yylhsminor.yy190; - break; - case 166: /* expr ::= expr AND expr */ - case 167: /* expr ::= expr OR expr */ yytestcase(yyruleno==167); - case 168: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==168); - case 169: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==169); - case 170: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==170); - case 171: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==171); - case 172: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==172); - case 173: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==173); -{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);} - break; - case 174: /* likeop ::= LIKE_KW|MATCH */ -{yymsp[0].minor.yy0=yymsp[0].minor.yy0;/*A-overwrites-X*/} - break; - case 175: /* likeop ::= NOT LIKE_KW|MATCH */ -{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} - break; - case 176: /* expr ::= expr likeop expr */ -{ - ExprList *pList; - int bNot = yymsp[-1].minor.yy0.n & 0x80000000; - yymsp[-1].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy190.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy190.pExpr); - yymsp[-2].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0); - exprNot(pParse, bNot, &yymsp[-2].minor.yy190); - yymsp[-2].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; - if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc; -} - break; - case 177: /* expr ::= expr likeop expr ESCAPE expr */ -{ - ExprList *pList; - int bNot = yymsp[-3].minor.yy0.n & 0x80000000; - yymsp[-3].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy190.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); - yymsp[-4].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0); - exprNot(pParse, bNot, &yymsp[-4].minor.yy190); - yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; - if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc; + +/* +** Free the linked list of Window objects starting at the second argument. +*/ +SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p){ + while( p ){ + Window *pNext = p->pNextWin; + sqlite3WindowDelete(db, p); + p = pNext; + } } - break; - case 178: /* expr ::= expr ISNULL|NOTNULL */ -{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);} - break; - case 179: /* expr ::= expr NOT NULL */ -{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);} - break; - case 180: /* expr ::= expr IS expr */ -{ - spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL); + +/* +** The argument expression is an PRECEDING or FOLLOWING offset. The +** value should be a non-negative integer. If the value is not a +** constant, change it to NULL. The fact that it is then a non-negative +** integer will be caught later. But it is important not to leave +** variable values in the expression tree. +*/ +static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ + if( 0==sqlite3ExprIsConstant(pExpr) ){ + if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr); + sqlite3ExprDelete(pParse->db, pExpr); + pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); + } + return pExpr; } - break; - case 181: /* expr ::= expr IS NOT expr */ -{ - spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL); + +/* +** Allocate and return a new Window object describing a Window Definition. +*/ +SQLITE_PRIVATE Window *sqlite3WindowAlloc( + Parse *pParse, /* Parsing context */ + int eType, /* Frame type. TK_RANGE, TK_ROWS, TK_GROUPS, or 0 */ + int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */ + Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */ + int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */ + Expr *pEnd, /* End window size if TK_FOLLOWING or PRECEDING */ + u8 eExclude /* EXCLUDE clause */ +){ + Window *pWin = 0; + int bImplicitFrame = 0; + + /* Parser assures the following: */ + assert( eType==0 || eType==TK_RANGE || eType==TK_ROWS || eType==TK_GROUPS ); + assert( eStart==TK_CURRENT || eStart==TK_PRECEDING + || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING ); + assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING + || eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING ); + assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) ); + assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) ); + + if( eType==0 ){ + bImplicitFrame = 1; + eType = TK_RANGE; + } + + /* Additionally, the + ** starting boundary type may not occur earlier in the following list than + ** the ending boundary type: + ** + ** UNBOUNDED PRECEDING + ** PRECEDING + ** CURRENT ROW + ** FOLLOWING + ** UNBOUNDED FOLLOWING + ** + ** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending + ** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting + ** frame boundary. + */ + if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING) + || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT)) + ){ + sqlite3ErrorMsg(pParse, "unsupported frame specification"); + goto windowAllocErr; + } + + pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( pWin==0 ) goto windowAllocErr; + pWin->eFrmType = eType; + pWin->eStart = eStart; + pWin->eEnd = eEnd; + if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_WindowFunc) ){ + eExclude = TK_NO; + } + pWin->eExclude = eExclude; + pWin->bImplicitFrame = bImplicitFrame; + pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd); + pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart); + return pWin; + +windowAllocErr: + sqlite3ExprDelete(pParse->db, pEnd); + sqlite3ExprDelete(pParse->db, pStart); + return 0; } - break; - case 182: /* expr ::= NOT expr */ - case 183: /* expr ::= BITNOT expr */ yytestcase(yyruleno==183); -{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} - break; - case 184: /* expr ::= MINUS expr */ -{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} - break; - case 185: /* expr ::= PLUS expr */ -{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} - break; - case 186: /* between_op ::= BETWEEN */ - case 189: /* in_op ::= IN */ yytestcase(yyruleno==189); -{yymsp[0].minor.yy194 = 0;} - break; - case 188: /* expr ::= expr between_op expr AND expr */ -{ - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr); - yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy190.pExpr, 0); - if( yymsp[-4].minor.yy190.pExpr ){ - yymsp[-4].minor.yy190.pExpr->x.pList = pList; + +/* +** Attach PARTITION and ORDER BY clauses pPartition and pOrderBy to window +** pWin. Also, if parameter pBase is not NULL, set pWin->zBase to the +** equivalent nul-terminated string. +*/ +SQLITE_PRIVATE Window *sqlite3WindowAssemble( + Parse *pParse, + Window *pWin, + ExprList *pPartition, + ExprList *pOrderBy, + Token *pBase +){ + if( pWin ){ + pWin->pPartition = pPartition; + pWin->pOrderBy = pOrderBy; + if( pBase ){ + pWin->zBase = sqlite3DbStrNDup(pParse->db, pBase->z, pBase->n); + } }else{ - sqlite3ExprListDelete(pParse->db, pList); - } - exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); - yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd; + sqlite3ExprListDelete(pParse->db, pPartition); + sqlite3ExprListDelete(pParse->db, pOrderBy); + } + return pWin; } - break; - case 191: /* expr ::= expr in_op LP exprlist RP */ -{ - if( yymsp[-1].minor.yy148==0 ){ - /* Expressions of the form - ** - ** expr1 IN () - ** expr1 NOT IN () - ** - ** simplify to constants 0 (false) and 1 (true), respectively, - ** regardless of the value of expr1. - */ - sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy190.pExpr); - yymsp[-4].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy194],1); - }else if( yymsp[-1].minor.yy148->nExpr==1 ){ - /* Expressions of the form: - ** - ** expr1 IN (?1) - ** expr1 NOT IN (?2) - ** - ** with exactly one value on the RHS can be simplified to something - ** like this: - ** - ** expr1 == ?1 - ** expr1 <> ?2 - ** - ** But, the RHS of the == or <> is marked with the EP_Generic flag - ** so that it may not contribute to the computation of comparison - ** affinity or the collating sequence to use for comparison. Otherwise, - ** the semantics would be subtly different from IN or NOT IN. - */ - Expr *pRHS = yymsp[-1].minor.yy148->a[0].pExpr; - yymsp[-1].minor.yy148->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); - /* pRHS cannot be NULL because a malloc error would have been detected - ** before now and control would have never reached this point */ - if( ALWAYS(pRHS) ){ - pRHS->flags &= ~EP_Collate; - pRHS->flags |= EP_Generic; - } - yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy194 ? TK_NE : TK_EQ, yymsp[-4].minor.yy190.pExpr, pRHS); - }else{ - yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); - if( yymsp[-4].minor.yy190.pExpr ){ - yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy148; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); + +/* +** Window *pWin has just been created from a WINDOW clause. Tokne pBase +** is the base window. Earlier windows from the same WINDOW clause are +** stored in the linked list starting at pWin->pNextWin. This function +** either updates *pWin according to the base specification, or else +** leaves an error in pParse. +*/ +SQLITE_PRIVATE void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){ + if( pWin->zBase ){ + sqlite3 *db = pParse->db; + Window *pExist = windowFind(pParse, pList, pWin->zBase); + if( pExist ){ + const char *zErr = 0; + /* Check for errors */ + if( pWin->pPartition ){ + zErr = "PARTITION clause"; + }else if( pExist->pOrderBy && pWin->pOrderBy ){ + zErr = "ORDER BY clause"; + }else if( pExist->bImplicitFrame==0 ){ + zErr = "frame specification"; + } + if( zErr ){ + sqlite3ErrorMsg(pParse, + "cannot override %s of window: %s", zErr, pWin->zBase + ); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148); + pWin->pPartition = sqlite3ExprListDup(db, pExist->pPartition, 0); + if( pExist->pOrderBy ){ + assert( pWin->pOrderBy==0 ); + pWin->pOrderBy = sqlite3ExprListDup(db, pExist->pOrderBy, 0); + } + sqlite3DbFree(db, pWin->zBase); + pWin->zBase = 0; } - exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); } - yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } - break; - case 192: /* expr ::= LP select RP */ -{ - spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ - yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243); +} + +/* +** Attach window object pWin to expression p. +*/ +SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ + if( p ){ + assert( p->op==TK_FUNCTION ); + assert( pWin ); + p->y.pWin = pWin; + ExprSetProperty(p, EP_WinFunc); + pWin->pOwner = p; + if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){ + sqlite3ErrorMsg(pParse, + "DISTINCT is not supported for window functions" + ); + } + }else{ + sqlite3WindowDelete(pParse->db, pWin); } - break; - case 193: /* expr ::= expr in_op LP select RP */ -{ - yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243); - exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); - yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; +} + +/* +** Possibly link window pWin into the list at pSel->pWin (window functions +** to be processed as part of SELECT statement pSel). The window is linked +** in if either (a) there are no other windows already linked to this +** SELECT, or (b) the windows already linked use a compatible window frame. +*/ +SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin){ + if( pSel ){ + if( 0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0) ){ + pWin->pNextWin = pSel->pWin; + if( pSel->pWin ){ + pSel->pWin->ppThis = &pWin->pNextWin; + } + pSel->pWin = pWin; + pWin->ppThis = &pSel->pWin; + }else{ + if( sqlite3ExprListCompare(pWin->pPartition, pSel->pWin->pPartition,-1) ){ + pSel->selFlags |= SF_MultiPart; + } + } } - break; - case 194: /* expr ::= expr in_op nm dbnm paren_exprlist */ -{ - SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); - Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); - if( yymsp[0].minor.yy148 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy148); - yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, pSelect); - exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190); - yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n]; +} + +/* +** Return 0 if the two window objects are identical, 1 if they are +** different, or 2 if it cannot be determined if the objects are identical +** or not. Identical window objects can be processed in a single scan. +*/ +SQLITE_PRIVATE int sqlite3WindowCompare( + const Parse *pParse, + const Window *p1, + const Window *p2, + int bFilter +){ + int res; + if( NEVER(p1==0) || NEVER(p2==0) ) return 1; + if( p1->eFrmType!=p2->eFrmType ) return 1; + if( p1->eStart!=p2->eStart ) return 1; + if( p1->eEnd!=p2->eEnd ) return 1; + if( p1->eExclude!=p2->eExclude ) return 1; + if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1; + if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; + if( (res = sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1)) ){ + return res; } - break; - case 195: /* expr ::= EXISTS LP select RP */ -{ - Expr *p; - spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ - p = yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243); + if( (res = sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1)) ){ + return res; } - break; - case 196: /* expr ::= CASE case_operand case_exprlist case_else END */ -{ - spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ - yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0); - if( yymsp[-4].minor.yy190.pExpr ){ - yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy72 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[-1].minor.yy72) : yymsp[-2].minor.yy148; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr); - }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy148); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy72); + if( bFilter ){ + if( (res = sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1)) ){ + return res; + } } + return 0; } - break; - case 197: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ -{ - yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr); - yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr); -} - break; - case 198: /* case_exprlist ::= WHEN expr THEN expr */ -{ - yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr); - yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr); -} - break; - case 201: /* case_operand ::= expr */ -{yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/} - break; - case 204: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);} - break; - case 205: /* nexprlist ::= expr */ -{yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/} - break; - case 207: /* paren_exprlist ::= LP exprlist RP */ - case 212: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==212); -{yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;} - break; - case 208: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ -{ - sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF); -} - break; - case 209: /* uniqueflag ::= UNIQUE */ - case 250: /* raisetype ::= ABORT */ yytestcase(yyruleno==250); -{yymsp[0].minor.yy194 = OE_Abort;} - break; - case 210: /* uniqueflag ::= */ -{yymsp[1].minor.yy194 = OE_None;} - break; - case 213: /* eidlist ::= eidlist COMMA nm collate sortorder */ -{ - yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); -} - break; - case 214: /* eidlist ::= nm collate sortorder */ -{ - yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/ -} - break; - case 217: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);} - break; - case 218: /* cmd ::= VACUUM */ -{sqlite3Vacuum(pParse,0);} - break; - case 219: /* cmd ::= VACUUM nm */ -{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);} - break; - case 220: /* cmd ::= PRAGMA nm dbnm */ -{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} - break; - case 221: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ -{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} - break; - case 222: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ -{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} - break; - case 223: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ -{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} - break; - case 224: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ -{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} - break; - case 227: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ -{ - Token all; - all.z = yymsp[-3].minor.yy0.z; - all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all); -} - break; - case 228: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ -{ - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194); - yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ -} - break; - case 229: /* trigger_time ::= BEFORE */ -{ yymsp[0].minor.yy194 = TK_BEFORE; } - break; - case 230: /* trigger_time ::= AFTER */ -{ yymsp[0].minor.yy194 = TK_AFTER; } - break; - case 231: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy194 = TK_INSTEAD;} - break; - case 232: /* trigger_time ::= */ -{ yymsp[1].minor.yy194 = TK_BEFORE; } - break; - case 233: /* trigger_event ::= DELETE|INSERT */ - case 234: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==234); -{yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;} - break; - case 235: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;} - break; - case 236: /* when_clause ::= */ - case 255: /* key_opt ::= */ yytestcase(yyruleno==255); -{ yymsp[1].minor.yy72 = 0; } - break; - case 237: /* when_clause ::= WHEN expr */ - case 256: /* key_opt ::= KEY expr */ yytestcase(yyruleno==256); -{ yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; } - break; - case 238: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ -{ - assert( yymsp[-2].minor.yy145!=0 ); - yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145; - yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145; -} - break; - case 239: /* trigger_cmd_list ::= trigger_cmd SEMI */ -{ - assert( yymsp[-1].minor.yy145!=0 ); - yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145; -} - break; - case 240: /* trnm ::= nm DOT nm */ -{ - yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; - sqlite3ErrorMsg(pParse, - "qualified table names are not allowed on INSERT, UPDATE, and DELETE " - "statements within triggers"); -} - break; - case 241: /* tridxby ::= INDEXED BY nm */ -{ - sqlite3ErrorMsg(pParse, - "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " - "within triggers"); -} - break; - case 242: /* tridxby ::= NOT INDEXED */ -{ - sqlite3ErrorMsg(pParse, - "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " - "within triggers"); -} - break; - case 243: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ -{yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);} - break; - case 244: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ -{yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/} - break; - case 245: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ -{yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);} - break; - case 246: /* trigger_cmd ::= select */ -{yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/} - break; - case 247: /* expr ::= RAISE LP IGNORE RP */ -{ - spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0); - if( yymsp[-3].minor.yy190.pExpr ){ - yymsp[-3].minor.yy190.pExpr->affinity = OE_Ignore; + + +/* +** This is called by code in select.c before it calls sqlite3WhereBegin() +** to begin iterating through the sub-query results. It is used to allocate +** and initialize registers and cursors used by sqlite3WindowCodeStep(). +*/ +SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ + int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr; + Window *pMWin = pSelect->pWin; + Window *pWin; + Vdbe *v = sqlite3GetVdbe(pParse); + + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); + + /* Allocate registers to use for PARTITION BY values, if any. Initialize + ** said registers to NULL. */ + if( pMWin->pPartition ){ + int nExpr = pMWin->pPartition->nExpr; + pMWin->regPart = pParse->nMem+1; + pParse->nMem += nExpr; + sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1); + } + + pMWin->regOne = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regOne); + + if( pMWin->eExclude ){ + pMWin->regStartRowid = ++pParse->nMem; + pMWin->regEndRowid = ++pParse->nMem; + pMWin->csrApp = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->csrApp, pMWin->iEphCsr); + return; } -} - break; - case 248: /* expr ::= RAISE LP raisetype COMMA nm RP */ -{ - spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ - yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); - if( yymsp[-5].minor.yy190.pExpr ) { - yymsp[-5].minor.yy190.pExpr->affinity = (char)yymsp[-3].minor.yy194; + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *p = pWin->pFunc; + if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){ + /* The inline versions of min() and max() require a single ephemeral + ** table and 3 registers. The registers are used as follows: + ** + ** regApp+0: slot to copy min()/max() argument to for MakeRecord + ** regApp+1: integer value used to ensure keys are unique + ** regApp+2: output of MakeRecord + */ + ExprList *pList; + KeyInfo *pKeyInfo; + assert( ExprUseXList(pWin->pOwner) ); + pList = pWin->pOwner->x.pList; + pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0); + pWin->csrApp = pParse->nTab++; + pWin->regApp = pParse->nMem+1; + pParse->nMem += 3; + if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){ + assert( pKeyInfo->aSortFlags[0]==0 ); + pKeyInfo->aSortFlags[0] = KEYINFO_ORDER_DESC; + } + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2); + sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } + else if( p->zName==nth_valueName || p->zName==first_valueName ){ + /* Allocate two registers at pWin->regApp. These will be used to + ** store the start and end index of the current frame. */ + pWin->regApp = pParse->nMem+1; + pWin->csrApp = pParse->nTab++; + pParse->nMem += 2; + sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); + } + else if( p->zName==leadName || p->zName==lagName ){ + pWin->csrApp = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); + } } } - break; - case 249: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy194 = OE_Rollback;} - break; - case 251: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy194 = OE_Fail;} - break; - case 252: /* cmd ::= DROP TRIGGER ifexists fullname */ -{ - sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194); -} - break; - case 253: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ -{ - sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72); -} - break; - case 254: /* cmd ::= DETACH database_kw_opt expr */ -{ - sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr); -} - break; - case 257: /* cmd ::= REINDEX */ -{sqlite3Reindex(pParse, 0, 0);} - break; - case 258: /* cmd ::= REINDEX nm dbnm */ -{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} - break; - case 259: /* cmd ::= ANALYZE */ -{sqlite3Analyze(pParse, 0, 0);} - break; - case 260: /* cmd ::= ANALYZE nm dbnm */ -{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} - break; - case 261: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ -{ - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0); -} - break; - case 262: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ -{ - yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; - sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); -} - break; - case 263: /* add_column_fullname ::= fullname */ -{ - disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185); -} - break; - case 264: /* cmd ::= create_vtab */ -{sqlite3VtabFinishParse(pParse,0);} - break; - case 265: /* cmd ::= create_vtab LP vtabarglist RP */ -{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} - break; - case 266: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ -{ - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194); -} - break; - case 267: /* vtabarg ::= */ -{sqlite3VtabArgInit(pParse);} - break; - case 268: /* vtabargtoken ::= ANY */ - case 269: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==269); - case 270: /* lp ::= LP */ yytestcase(yyruleno==270); -{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} - break; - case 271: /* with ::= */ -{yymsp[1].minor.yy285 = 0;} - break; - case 272: /* with ::= WITH wqlist */ -{ yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; } - break; - case 273: /* with ::= WITH RECURSIVE wqlist */ -{ yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; } - break; - case 274: /* wqlist ::= nm eidlist_opt AS LP select RP */ -{ - yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/ -} - break; - case 275: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ -{ - yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); -} - break; - default: - /* (276) input ::= cmdlist */ yytestcase(yyruleno==276); - /* (277) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==277); - /* (278) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=278); - /* (279) ecmd ::= SEMI */ yytestcase(yyruleno==279); - /* (280) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==280); - /* (281) explain ::= */ yytestcase(yyruleno==281); - /* (282) trans_opt ::= */ yytestcase(yyruleno==282); - /* (283) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==283); - /* (284) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==284); - /* (285) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==285); - /* (286) savepoint_opt ::= */ yytestcase(yyruleno==286); - /* (287) cmd ::= create_table create_table_args */ yytestcase(yyruleno==287); - /* (288) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==288); - /* (289) columnlist ::= columnname carglist */ yytestcase(yyruleno==289); - /* (290) nm ::= ID|INDEXED */ yytestcase(yyruleno==290); - /* (291) nm ::= STRING */ yytestcase(yyruleno==291); - /* (292) nm ::= JOIN_KW */ yytestcase(yyruleno==292); - /* (293) typetoken ::= typename */ yytestcase(yyruleno==293); - /* (294) typename ::= ID|STRING */ yytestcase(yyruleno==294); - /* (295) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=295); - /* (296) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=296); - /* (297) carglist ::= carglist ccons */ yytestcase(yyruleno==297); - /* (298) carglist ::= */ yytestcase(yyruleno==298); - /* (299) ccons ::= NULL onconf */ yytestcase(yyruleno==299); - /* (300) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==300); - /* (301) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==301); - /* (302) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=302); - /* (303) tconscomma ::= */ yytestcase(yyruleno==303); - /* (304) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=304); - /* (305) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=305); - /* (306) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=306); - /* (307) oneselect ::= values */ yytestcase(yyruleno==307); - /* (308) sclp ::= selcollist COMMA */ yytestcase(yyruleno==308); - /* (309) as ::= ID|STRING */ yytestcase(yyruleno==309); - /* (310) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=310); - /* (311) exprlist ::= nexprlist */ yytestcase(yyruleno==311); - /* (312) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=312); - /* (313) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=313); - /* (314) nmnum ::= ON */ yytestcase(yyruleno==314); - /* (315) nmnum ::= DELETE */ yytestcase(yyruleno==315); - /* (316) nmnum ::= DEFAULT */ yytestcase(yyruleno==316); - /* (317) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==317); - /* (318) foreach_clause ::= */ yytestcase(yyruleno==318); - /* (319) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==319); - /* (320) trnm ::= nm */ yytestcase(yyruleno==320); - /* (321) tridxby ::= */ yytestcase(yyruleno==321); - /* (322) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==322); - /* (323) database_kw_opt ::= */ yytestcase(yyruleno==323); - /* (324) kwcolumn_opt ::= */ yytestcase(yyruleno==324); - /* (325) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==325); - /* (326) vtabarglist ::= vtabarg */ yytestcase(yyruleno==326); - /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==327); - /* (328) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==328); - /* (329) anylist ::= */ yytestcase(yyruleno==329); - /* (330) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==330); - /* (331) anylist ::= anylist ANY */ yytestcase(yyruleno==331); - break; -/********** End reduce actions ************************************************/ + +#define WINDOW_STARTING_INT 0 +#define WINDOW_ENDING_INT 1 +#define WINDOW_NTH_VALUE_INT 2 +#define WINDOW_STARTING_NUM 3 +#define WINDOW_ENDING_NUM 4 + +/* +** A "PRECEDING " (eCond==0) or "FOLLOWING " (eCond==1) or the +** value of the second argument to nth_value() (eCond==2) has just been +** evaluated and the result left in register reg. This function generates VM +** code to check that the value is a non-negative integer and throws an +** exception if it is not. +*/ +static void windowCheckValue(Parse *pParse, int reg, int eCond){ + static const char *azErr[] = { + "frame starting offset must be a non-negative integer", + "frame ending offset must be a non-negative integer", + "second argument to nth_value must be a positive integer", + "frame starting offset must be a non-negative number", + "frame ending offset must be a non-negative number", }; - assert( yyrulenoYY_MAX_SHIFT ){ - yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - } - yymsp -= yysize-1; - yypParser->yytos = yymsp; - yymsp->stateno = (YYACTIONTYPE)yyact; - yymsp->major = (YYCODETYPE)yygoto; - yyTraceShift(yypParser, yyact); + static int aOp[] = { OP_Ge, OP_Ge, OP_Gt, OP_Ge, OP_Ge }; + Vdbe *v = sqlite3GetVdbe(pParse); + int regZero = sqlite3GetTempReg(pParse); + assert( eCond>=0 && eCond=WINDOW_STARTING_NUM ){ + int regString = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); + sqlite3VdbeAddOp3(v, OP_Ge, regString, sqlite3VdbeCurrentAddr(v)+2, reg); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC|SQLITE_JUMPIFNULL); + VdbeCoverage(v); + assert( eCond==3 || eCond==4 ); + VdbeCoverageIf(v, eCond==3); + VdbeCoverageIf(v, eCond==4); }else{ - assert( yyact == YY_ACCEPT_ACTION ); - yypParser->yytos -= yysize; - yy_accept(yypParser); - } + sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + assert( eCond==0 || eCond==1 || eCond==2 ); + VdbeCoverageIf(v, eCond==0); + VdbeCoverageIf(v, eCond==1); + VdbeCoverageIf(v, eCond==2); + } + sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC); + VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */ + VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */ + VdbeCoverageNeverNullIf(v, eCond==2); + VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */ + VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */ + sqlite3MayAbort(pParse); + sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); + sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC); + sqlite3ReleaseTempReg(pParse, regZero); } /* -** The following code executes when the parse fails +** Return the number of arguments passed to the window-function associated +** with the object passed as the only argument to this function. */ -#ifndef YYNOERRORRECOVERY -static void yy_parse_failed( - yyParser *yypParser /* The parser */ -){ - sqlite3ParserARG_FETCH; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); - } -#endif - while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will be executed whenever the - ** parser fails */ -/************ Begin %parse_failure code ***************************************/ -/************ End %parse_failure code *****************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ +static int windowArgCount(Window *pWin){ + const ExprList *pList; + assert( ExprUseXList(pWin->pOwner) ); + pList = pWin->pOwner->x.pList; + return (pList ? pList->nExpr : 0); } -#endif /* YYNOERRORRECOVERY */ + +typedef struct WindowCodeArg WindowCodeArg; +typedef struct WindowCsrAndReg WindowCsrAndReg; /* -** The following code executes when a syntax error first occurs. +** See comments above struct WindowCodeArg. */ -static void yy_syntax_error( - yyParser *yypParser, /* The parser */ - int yymajor, /* The major type of the error token */ - sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */ -){ - sqlite3ParserARG_FETCH; -#define TOKEN yyminor -/************ Begin %syntax_error code ****************************************/ +struct WindowCsrAndReg { + int csr; /* Cursor number */ + int reg; /* First in array of peer values */ +}; - UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ - assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */ - sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); -/************ End %syntax_error code ******************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ -} +/* +** A single instance of this structure is allocated on the stack by +** sqlite3WindowCodeStep() and a pointer to it passed to the various helper +** routines. This is to reduce the number of arguments required by each +** helper function. +** +** regArg: +** Each window function requires an accumulator register (just as an +** ordinary aggregate function does). This variable is set to the first +** in an array of accumulator registers - one for each window function +** in the WindowCodeArg.pMWin list. +** +** eDelete: +** The window functions implementation sometimes caches the input rows +** that it processes in a temporary table. If it is not zero, this +** variable indicates when rows may be removed from the temp table (in +** order to reduce memory requirements - it would always be safe just +** to leave them there). Possible values for eDelete are: +** +** WINDOW_RETURN_ROW: +** An input row can be discarded after it is returned to the caller. +** +** WINDOW_AGGINVERSE: +** An input row can be discarded after the window functions xInverse() +** callbacks have been invoked in it. +** +** WINDOW_AGGSTEP: +** An input row can be discarded after the window functions xStep() +** callbacks have been invoked in it. +** +** start,current,end +** Consider a window-frame similar to the following: +** +** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING) +** +** The windows functions implmentation caches the input rows in a temp +** table, sorted by "a, b" (it actually populates the cache lazily, and +** aggressively removes rows once they are no longer required, but that's +** a mere detail). It keeps three cursors open on the temp table. One +** (current) that points to the next row to return to the query engine +** once its window function values have been calculated. Another (end) +** points to the next row to call the xStep() method of each window function +** on (so that it is 2 groups ahead of current). And a third (start) that +** points to the next row to call the xInverse() method of each window +** function on. +** +** Each cursor (start, current and end) consists of a VDBE cursor +** (WindowCsrAndReg.csr) and an array of registers (starting at +** WindowCodeArg.reg) that always contains a copy of the peer values +** read from the corresponding cursor. +** +** Depending on the window-frame in question, all three cursors may not +** be required. In this case both WindowCodeArg.csr and reg are set to +** 0. +*/ +struct WindowCodeArg { + Parse *pParse; /* Parse context */ + Window *pMWin; /* First in list of functions being processed */ + Vdbe *pVdbe; /* VDBE object */ + int addrGosub; /* OP_Gosub to this address to return one row */ + int regGosub; /* Register used with OP_Gosub(addrGosub) */ + int regArg; /* First in array of accumulator registers */ + int eDelete; /* See above */ + int regRowid; + + WindowCsrAndReg start; + WindowCsrAndReg current; + WindowCsrAndReg end; +}; /* -** The following is executed when the parser accepts +** Generate VM code to read the window frames peer values from cursor csr into +** an array of registers starting at reg. */ -static void yy_accept( - yyParser *yypParser /* The parser */ +static void windowReadPeerValues( + WindowCodeArg *p, + int csr, + int reg ){ - sqlite3ParserARG_FETCH; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + Window *pMWin = p->pMWin; + ExprList *pOrderBy = pMWin->pOrderBy; + if( pOrderBy ){ + Vdbe *v = sqlite3GetVdbe(p->pParse); + ExprList *pPart = pMWin->pPartition; + int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); + int i; + for(i=0; inExpr; i++){ + sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i); + } } -#endif -#ifndef YYNOERRORRECOVERY - yypParser->yyerrcnt = -1; -#endif - assert( yypParser->yytos==yypParser->yystack ); - /* Here code is inserted which will be executed whenever the - ** parser accepts */ -/*********** Begin %parse_accept code *****************************************/ -/*********** End %parse_accept code *******************************************/ - sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ } -/* The main parser program. -** The first argument is a pointer to a structure obtained from -** "sqlite3ParserAlloc" which describes the current state of the parser. -** The second argument is the major token number. The third is -** the minor token. The fourth optional argument is whatever the -** user wants (and specified in the grammar) and is available for -** use by the action routines. +/* +** Generate VM code to invoke either xStep() (if bInverse is 0) or +** xInverse (if bInverse is non-zero) for each window function in the +** linked list starting at pMWin. Or, for built-in window functions +** that do not use the standard function API, generate the required +** inline VM code. ** -** Inputs: -**
              -**
            • A pointer to the parser (an opaque structure.) -**
            • The major token number. -**
            • The minor token number. -**
            • An option argument of a grammar-specified type. -**
            +** If argument csr is greater than or equal to 0, then argument reg is +** the first register in an array of registers guaranteed to be large +** enough to hold the array of arguments for each function. In this case +** the arguments are extracted from the current row of csr into the +** array of registers before invoking OP_AggStep or OP_AggInverse ** -** Outputs: -** None. +** Or, if csr is less than zero, then the array of registers at reg is +** already populated with all columns from the current row of the sub-query. +** +** If argument regPartSize is non-zero, then it is a register containing the +** number of rows in the current partition. */ -SQLITE_PRIVATE void sqlite3Parser( - void *yyp, /* The parser */ - int yymajor, /* The major token code number */ - sqlite3ParserTOKENTYPE yyminor /* The value for the token */ - sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ +static void windowAggStep( + WindowCodeArg *p, + Window *pMWin, /* Linked list of window functions */ + int csr, /* Read arguments from this cursor */ + int bInverse, /* True to invoke xInverse instead of xStep */ + int reg /* Array of registers */ ){ - YYMINORTYPE yyminorunion; - unsigned int yyact; /* The parser action. */ -#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) - int yyendofinput; /* True if we are at the end of input */ -#endif -#ifdef YYERRORSYMBOL - int yyerrorhit = 0; /* True if yymajor has invoked an error */ -#endif - yyParser *yypParser; /* The parser */ + Parse *pParse = p->pParse; + Vdbe *v = sqlite3GetVdbe(pParse); + Window *pWin; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + int regArg; + int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); + int i; - yypParser = (yyParser*)yyp; - assert( yypParser->yytos!=0 ); -#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) - yyendofinput = (yymajor==0); -#endif - sqlite3ParserARG_STORE; + assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); - } -#endif + /* All OVER clauses in the same window function aggregate step must + ** be the same. */ + assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)!=1 ); - do{ - yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); - if( yyact <= YY_MAX_SHIFTREDUCE ){ - yy_shift(yypParser,yyact,yymajor,yyminor); -#ifndef YYNOERRORRECOVERY - yypParser->yyerrcnt--; -#endif - yymajor = YYNOCODE; - }else if( yyact <= YY_MAX_REDUCE ){ - yy_reduce(yypParser,yyact-YY_MIN_REDUCE); - }else{ - assert( yyact == YY_ERROR_ACTION ); - yyminorunion.yy0 = yyminor; -#ifdef YYERRORSYMBOL - int yymx; -#endif -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + for(i=0; izName!=nth_valueName ){ + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i); } -#endif -#ifdef YYERRORSYMBOL - /* A syntax error has occurred. - ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". - ** - ** This is what we do if the grammar does define ERROR: - ** - ** * Call the %syntax_error function. - ** - ** * Begin popping the stack until we enter a state where - ** it is legal to shift the error symbol, then shift - ** the error symbol. - ** - ** * Set the error count to three. - ** - ** * Begin accepting and shifting new tokens. No new error - ** processing will occur until three tokens have been - ** shifted successfully. - ** - */ - if( yypParser->yyerrcnt<0 ){ - yy_syntax_error(yypParser,yymajor,yyminor); + } + regArg = reg; + + if( pMWin->regStartRowid==0 + && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && (pWin->eStart!=TK_UNBOUNDED) + ){ + int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg); + VdbeCoverage(v); + if( bInverse==0 ){ + sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1); + sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp); + sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2); + sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2); + }else{ + sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp); + sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); } - yymx = yypParser->yytos->major; - if( yymx==YYERRORSYMBOL || yyerrorhit ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sDiscard input token %s\n", - yyTracePrompt,yyTokenName[yymajor]); + sqlite3VdbeJumpHere(v, addrIsNull); + }else if( pWin->regApp ){ + assert( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName + ); + assert( bInverse==0 || bInverse==1 ); + sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); + }else if( pFunc->xSFunc!=noopStepFunc ){ + int addrIf = 0; + if( pWin->pFilter ){ + int regTmp; + assert( ExprUseXList(pWin->pOwner) ); + assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr ); + assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 ); + regTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); + addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); + VdbeCoverage(v); + sqlite3ReleaseTempReg(pParse, regTmp); + } + + if( pWin->bExprArgs ){ + int iOp = sqlite3VdbeCurrentAddr(v); + int iEnd; + + assert( ExprUseXList(pWin->pOwner) ); + nArg = pWin->pOwner->x.pList->nExpr; + regArg = sqlite3GetTempRange(pParse, nArg); + sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0); + + for(iEnd=sqlite3VdbeCurrentAddr(v); iOpopcode==OP_Column && pOp->p1==pWin->iEphCsr ){ + pOp->p1 = csr; + } } -#endif - yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); - yymajor = YYNOCODE; + } + if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ + CollSeq *pColl; + assert( nArg>0 ); + assert( ExprUseXList(pWin->pOwner) ); + pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); + sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ); + } + sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, + bInverse, regArg, pWin->regAccum); + sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)nArg); + if( pWin->bExprArgs ){ + sqlite3ReleaseTempRange(pParse, regArg, nArg); + } + if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); + } + } +} + +/* +** Values that may be passed as the second argument to windowCodeOp(). +*/ +#define WINDOW_RETURN_ROW 1 +#define WINDOW_AGGINVERSE 2 +#define WINDOW_AGGSTEP 3 + +/* +** Generate VM code to invoke either xValue() (bFin==0) or xFinalize() +** (bFin==1) for each window function in the linked list starting at +** pMWin. Or, for built-in window-functions that do not use the standard +** API, generate the equivalent VM code. +*/ +static void windowAggFinal(WindowCodeArg *p, int bFin){ + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; + Vdbe *v = sqlite3GetVdbe(pParse); + Window *pWin; + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + if( pMWin->regStartRowid==0 + && (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && (pWin->eStart!=TK_UNBOUNDED) + ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult); + sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); + }else if( pWin->regApp ){ + assert( pMWin->regStartRowid==0 ); + }else{ + int nArg = windowArgCount(pWin); + if( bFin ){ + sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, nArg); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); }else{ - while( yypParser->yytos >= yypParser->yystack - && yymx != YYERRORSYMBOL - && (yyact = yy_find_reduce_action( - yypParser->yytos->stateno, - YYERRORSYMBOL)) >= YY_MIN_REDUCE - ){ - yy_pop_parser_stack(yypParser); + sqlite3VdbeAddOp3(v, OP_AggValue,pWin->regAccum,nArg,pWin->regResult); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + } + } + } +} + +/* +** Generate code to calculate the current values of all window functions in the +** p->pMWin list by doing a full scan of the current window frame. Store the +** results in the Window.regResult registers, ready to return the upper +** layer. +*/ +static void windowFullScan(WindowCodeArg *p){ + Window *pWin; + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; + Vdbe *v = p->pVdbe; + + int regCRowid = 0; /* Current rowid value */ + int regCPeer = 0; /* Current peer values */ + int regRowid = 0; /* AggStep rowid value */ + int regPeer = 0; /* AggStep peer values */ + + int nPeer; + int lblNext; + int lblBrk; + int addrNext; + int csr; + + VdbeModuleComment((v, "windowFullScan begin")); + + assert( pMWin!=0 ); + csr = pMWin->csrApp; + nPeer = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); + + lblNext = sqlite3VdbeMakeLabel(pParse); + lblBrk = sqlite3VdbeMakeLabel(pParse); + + regCRowid = sqlite3GetTempReg(pParse); + regRowid = sqlite3GetTempReg(pParse); + if( nPeer ){ + regCPeer = sqlite3GetTempRange(pParse, nPeer); + regPeer = sqlite3GetTempRange(pParse, nPeer); + } + + sqlite3VdbeAddOp2(v, OP_Rowid, pMWin->iEphCsr, regCRowid); + windowReadPeerValues(p, pMWin->iEphCsr, regCPeer); + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + } + + sqlite3VdbeAddOp3(v, OP_SeekGE, csr, lblBrk, pMWin->regStartRowid); + VdbeCoverage(v); + addrNext = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Rowid, csr, regRowid); + sqlite3VdbeAddOp3(v, OP_Gt, pMWin->regEndRowid, lblBrk, regRowid); + VdbeCoverageNeverNull(v); + + if( pMWin->eExclude==TK_CURRENT ){ + sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, lblNext, regRowid); + VdbeCoverageNeverNull(v); + }else if( pMWin->eExclude!=TK_NO ){ + int addr; + int addrEq = 0; + KeyInfo *pKeyInfo = 0; + + if( pMWin->pOrderBy ){ + pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pMWin->pOrderBy, 0, 0); + } + if( pMWin->eExclude==TK_TIES ){ + addrEq = sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, 0, regRowid); + VdbeCoverageNeverNull(v); + } + if( pKeyInfo ){ + windowReadPeerValues(p, csr, regPeer); + sqlite3VdbeAddOp3(v, OP_Compare, regPeer, regCPeer, nPeer); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + addr = sqlite3VdbeCurrentAddr(v)+1; + sqlite3VdbeAddOp3(v, OP_Jump, addr, lblNext, addr); + VdbeCoverageEqNe(v); + }else{ + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext); + } + if( addrEq ) sqlite3VdbeJumpHere(v, addrEq); + } + + windowAggStep(p, pMWin, csr, 0, p->regArg); + + sqlite3VdbeResolveLabel(v, lblNext); + sqlite3VdbeAddOp2(v, OP_Next, csr, addrNext); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrNext-1); + sqlite3VdbeJumpHere(v, addrNext+1); + sqlite3ReleaseTempReg(pParse, regRowid); + sqlite3ReleaseTempReg(pParse, regCRowid); + if( nPeer ){ + sqlite3ReleaseTempRange(pParse, regPeer, nPeer); + sqlite3ReleaseTempRange(pParse, regCPeer, nPeer); + } + + windowAggFinal(p, 1); + VdbeModuleComment((v, "windowFullScan end")); +} + +/* +** Invoke the sub-routine at regGosub (generated by code in select.c) to +** return the current row of Window.iEphCsr. If all window functions are +** aggregate window functions that use the standard API, a single +** OP_Gosub instruction is all that this routine generates. Extra VM code +** for per-row processing is only generated for the following built-in window +** functions: +** +** nth_value() +** first_value() +** lag() +** lead() +*/ +static void windowReturnOneRow(WindowCodeArg *p){ + Window *pMWin = p->pMWin; + Vdbe *v = p->pVdbe; + + if( pMWin->regStartRowid ){ + windowFullScan(p); + }else{ + Parse *pParse = p->pParse; + Window *pWin; + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + assert( ExprUseXList(pWin->pOwner) ); + if( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName + ){ + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(pParse); + int tmpReg = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + + if( pFunc->zName==nth_valueName ){ + sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg); + windowCheckValue(pParse, tmpReg, 2); + }else{ + sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); + } + sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); + sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); + VdbeCoverageNeverNull(v); + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); + } + else if( pFunc->zName==leadName || pFunc->zName==lagName ){ + int nArg = pWin->pOwner->x.pList->nExpr; + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(pParse); + int tmpReg = sqlite3GetTempReg(pParse); + int iEph = pMWin->iEphCsr; + + if( nArg<3 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, iEph,pWin->iArgCol+2,pWin->regResult); } - if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - yy_parse_failed(yypParser); -#ifndef YYNOERRORRECOVERY - yypParser->yyerrcnt = -1; -#endif - yymajor = YYNOCODE; - }else if( yymx!=YYERRORSYMBOL ){ - yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); + sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); + if( nArg<2 ){ + int val = (pFunc->zName==leadName ? 1 : -1); + sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); + }else{ + int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); + int tmpReg2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); + sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); + sqlite3ReleaseTempReg(pParse, tmpReg2); } + + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); } - yypParser->yyerrcnt = 3; - yyerrorhit = 1; -#elif defined(YYNOERRORRECOVERY) - /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to - ** do any kind of error recovery. Instead, simply invoke the syntax - ** error routine and continue going as if nothing had happened. - ** - ** Applications can set this macro (for example inside %include) if - ** they intend to abandon the parse upon the first syntax error seen. - */ - yy_syntax_error(yypParser,yymajor, yyminor); - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - yymajor = YYNOCODE; - -#else /* YYERRORSYMBOL is not defined */ - /* This is what we do if the grammar does not define ERROR: - ** - ** * Report an error message, and throw away the input token. - ** - ** * If the input token is $, then fail the parse. - ** - ** As before, subsequent error messages are suppressed until - ** three input tokens have been successfully shifted. - */ - if( yypParser->yyerrcnt<=0 ){ - yy_syntax_error(yypParser,yymajor, yyminor); + } + } + sqlite3VdbeAddOp2(v, OP_Gosub, p->regGosub, p->addrGosub); +} + +/* +** Generate code to set the accumulator register for each window function +** in the linked list passed as the second argument to NULL. And perform +** any equivalent initialization required by any built-in window functions +** in the list. +*/ +static int windowInitAccum(Parse *pParse, Window *pMWin){ + Vdbe *v = sqlite3GetVdbe(pParse); + int regArg; + int nArg = 0; + Window *pWin; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + assert( pWin->regAccum ); + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + nArg = MAX(nArg, windowArgCount(pWin)); + if( pMWin->regStartRowid==0 ){ + if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } - yypParser->yyerrcnt = 3; - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - if( yyendofinput ){ - yy_parse_failed(yypParser); -#ifndef YYNOERRORRECOVERY - yypParser->yyerrcnt = -1; -#endif + + if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ + assert( pWin->eStart!=TK_UNBOUNDED ); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); } - yymajor = YYNOCODE; -#endif } - }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); -#ifndef NDEBUG - if( yyTraceFILE ){ - yyStackEntry *i; - char cDiv = '['; - fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); - for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ - fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); - cDiv = ' '; + } + regArg = pParse->nMem+1; + pParse->nMem += nArg; + return regArg; +} + +/* +** Return true if the current frame should be cached in the ephemeral table, +** even if there are no xInverse() calls required. +*/ +static int windowCacheFrame(Window *pMWin){ + Window *pWin; + if( pMWin->regStartRowid ) return 1; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + if( (pFunc->zName==nth_valueName) + || (pFunc->zName==first_valueName) + || (pFunc->zName==leadName) + || (pFunc->zName==lagName) + ){ + return 1; } - fprintf(yyTraceFILE,"]\n"); } -#endif - return; + return 0; } -/************** End of parse.c ***********************************************/ -/************** Begin file tokenize.c ****************************************/ /* -** 2001 September 15 +** regOld and regNew are each the first register in an array of size +** pOrderBy->nExpr. This function generates code to compare the two +** arrays of registers using the collation sequences and other comparison +** parameters specified by pOrderBy. ** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: +** If the two arrays are not equal, the contents of regNew is copied to +** regOld and control falls through. Otherwise, if the contents of the arrays +** are equal, an OP_Goto is executed. The address of the OP_Goto is returned. +*/ +static void windowIfNewPeer( + Parse *pParse, + ExprList *pOrderBy, + int regNew, /* First in array of new values */ + int regOld, /* First in array of old values */ + int addr /* Jump here */ +){ + Vdbe *v = sqlite3GetVdbe(pParse); + if( pOrderBy ){ + int nVal = pOrderBy->nExpr; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); + sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, + sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1 + ); + VdbeCoverageEqNe(v); + sqlite3VdbeAddOp3(v, OP_Copy, regNew, regOld, nVal-1); + }else{ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); + } +} + +/* +** This function is called as part of generating VM programs for RANGE +** offset PRECEDING/FOLLOWING frame boundaries. Assuming "ASC" order for +** the ORDER BY term in the window, and that argument op is OP_Ge, it generates +** code equivalent to: ** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** if( csr1.peerVal + regVal >= csr2.peerVal ) goto lbl; ** -************************************************************************* -** An tokenizer for SQL +** The value of parameter op may also be OP_Gt or OP_Le. In these cases the +** operator in the above pseudo-code is replaced with ">" or "<=", respectively. ** -** This file contains C code that splits an SQL input string up into -** individual tokens and sends those tokens one-by-one over to the -** parser for analysis. -*/ -/* #include "sqliteInt.h" */ -/* #include */ - -/* Character classes for tokenizing +** If the sort-order for the ORDER BY term in the window is DESC, then the +** comparison is reversed. Instead of adding regVal to csr1.peerVal, it is +** subtracted. And the comparison operator is inverted to - ">=" becomes "<=", +** ">" becomes "<", and so on. So, with DESC sort order, if the argument op +** is OP_Ge, the generated code is equivalent to: ** -** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented -** using a lookup table, whereas a switch() directly on c uses a binary search. -** The lookup table is much faster. To maximize speed, and to ensure that -** a lookup table is used, all of the classes need to be small integers and -** all of them need to be used within the switch. +** if( csr1.peerVal - regVal <= csr2.peerVal ) goto lbl; +** +** A special type of arithmetic is used such that if csr1.peerVal is not +** a numeric type (real or integer), then the result of the addition +** or subtraction is a a copy of csr1.peerVal. */ -#define CC_X 0 /* The letter 'x', or start of BLOB literal */ -#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */ -#define CC_ID 2 /* unicode characters usable in IDs */ -#define CC_DIGIT 3 /* Digits */ -#define CC_DOLLAR 4 /* '$' */ -#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */ -#define CC_VARNUM 6 /* '?'. Numeric SQL variables */ -#define CC_SPACE 7 /* Space characters */ -#define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */ -#define CC_QUOTE2 9 /* '['. [...] style quoted ids */ -#define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */ -#define CC_MINUS 11 /* '-'. Minus or SQL-style comment */ -#define CC_LT 12 /* '<'. Part of < or <= or <> */ -#define CC_GT 13 /* '>'. Part of > or >= */ -#define CC_EQ 14 /* '='. Part of = or == */ -#define CC_BANG 15 /* '!'. Part of != */ -#define CC_SLASH 16 /* '/'. / or c-style comment */ -#define CC_LP 17 /* '(' */ -#define CC_RP 18 /* ')' */ -#define CC_SEMI 19 /* ';' */ -#define CC_PLUS 20 /* '+' */ -#define CC_STAR 21 /* '*' */ -#define CC_PERCENT 22 /* '%' */ -#define CC_COMMA 23 /* ',' */ -#define CC_AND 24 /* '&' */ -#define CC_TILDA 25 /* '~' */ -#define CC_DOT 26 /* '.' */ -#define CC_ILLEGAL 27 /* Illegal character */ +static void windowCodeRangeTest( + WindowCodeArg *p, + int op, /* OP_Ge, OP_Gt, or OP_Le */ + int csr1, /* Cursor number for cursor 1 */ + int regVal, /* Register containing non-negative number */ + int csr2, /* Cursor number for cursor 2 */ + int lbl /* Jump destination if condition is true */ +){ + Parse *pParse = p->pParse; + Vdbe *v = sqlite3GetVdbe(pParse); + ExprList *pOrderBy = p->pMWin->pOrderBy; /* ORDER BY clause for window */ + int reg1 = sqlite3GetTempReg(pParse); /* Reg. for csr1.peerVal+regVal */ + int reg2 = sqlite3GetTempReg(pParse); /* Reg. for csr2.peerVal */ + int regString = ++pParse->nMem; /* Reg. for constant value '' */ + int arith = OP_Add; /* OP_Add or OP_Subtract */ + int addrGe; /* Jump destination */ + int addrDone = sqlite3VdbeMakeLabel(pParse); /* Address past OP_Ge */ + CollSeq *pColl; -static const unsigned char aiClass[] = { -#ifdef SQLITE_ASCII -/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ -/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, -/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, -/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, -/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1, -/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27, -/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 -#endif -#ifdef SQLITE_EBCDIC -/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ -/* 0x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 7, 7, 27, 27, -/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10, -/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27, -/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6, -/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8, -/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, -/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, -/* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, -/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27, -/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, -/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, -/* Ex */ 27, 27, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, -/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 27, 27, 27, 27, 27, -#endif -}; + /* Read the peer-value from each cursor into a register */ + windowReadPeerValues(p, csr1, reg1); + windowReadPeerValues(p, csr2, reg2); -/* -** The charMap() macro maps alphabetic characters (only) into their -** lower-case ASCII equivalent. On ASCII machines, this is just -** an upper-to-lower case map. On EBCDIC machines we also need -** to adjust the encoding. The mapping is only valid for alphabetics -** which are the only characters for which this feature is used. -** -** Used by keywordhash.h -*/ -#ifdef SQLITE_ASCII -# define charMap(X) sqlite3UpperToLower[(unsigned char)X] -#endif -#ifdef SQLITE_EBCDIC -# define charMap(X) ebcdicToAscii[(unsigned char)X] -const unsigned char ebcdicToAscii[] = { -/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ - 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */ - 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */ - 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ - 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */ - 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */ - 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */ -}; -#endif + assert( op==OP_Ge || op==OP_Gt || op==OP_Le ); + assert( pOrderBy && pOrderBy->nExpr==1 ); + if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){ + switch( op ){ + case OP_Ge: op = OP_Le; break; + case OP_Gt: op = OP_Lt; break; + default: assert( op==OP_Le ); op = OP_Ge; break; + } + arith = OP_Subtract; + } -/* -** The sqlite3KeywordCode function looks up an identifier to determine if -** it is a keyword. If it is a keyword, the token code of that keyword is -** returned. If the input is not a keyword, TK_ID is returned. -** -** The implementation of this routine was generated by a program, -** mkkeywordhash.c, located in the tool subdirectory of the distribution. -** The output of the mkkeywordhash.c program is written into a file -** named keywordhash.h and then included into this source file by -** the #include below. -*/ -/************** Include keywordhash.h in the middle of tokenize.c ************/ -/************** Begin file keywordhash.h *************************************/ -/***** This file contains automatically generated code ****** -** -** The code in this file has been automatically generated by -** -** sqlite/tool/mkkeywordhash.c -** -** The code in this file implements a function that determines whether -** or not a given identifier is really an SQL keyword. The same thing -** might be implemented more directly using a hand-written hash table. -** But by using this automatically generated code, the size of the code -** is substantially reduced. This is important for embedded applications -** on platforms with limited memory. -*/ -/* Hash score: 182 */ -static int keywordCode(const char *z, int n, int *pType){ - /* zText[] encodes 834 bytes of keywords in 554 bytes */ - /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ - /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ - /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ - /* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */ - /* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ - /* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */ - /* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */ - /* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */ - /* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */ - /* VACUUMVIEWINITIALLY */ - static const char zText[553] = { - 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', - 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', - 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', - 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', - 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N', - 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I', - 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E', - 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E', - 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T', - 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', - 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', - 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', - 'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E', - 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A', - 'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A', - 'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A', - 'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J', - 'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L', - 'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E', - 'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H', - 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E', - 'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E', - 'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M', - 'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R', - 'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A', - 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', - 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O', - 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T', - 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R', - 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M', - 'V','I','E','W','I','N','I','T','I','A','L','L','Y', - }; - static const unsigned char aHash[127] = { - 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0, - 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0, - 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71, - 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44, - 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25, - 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0, - 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14, - 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113, - 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0, - 29, 0, 86, 63, 64, 0, 20, 61, 0, 56, - }; - static const unsigned char aNext[124] = { - 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, - 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, - 0, 43, 3, 47, 0, 0, 0, 0, 30, 0, 58, 0, 38, - 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0, - 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34, - 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8, - 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37, - 73, 83, 0, 35, 68, 0, 0, - }; - static const unsigned char aLen[124] = { - 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, - 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, - 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, - 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, - 6, 6, 5, 6, 5, 5, 9, 7, 7, 3, 2, 4, 4, - 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4, - 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7, - 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8, - 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8, - 3, 5, 5, 6, 4, 9, 3, - }; - static const unsigned short int aOffset[124] = { - 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, - 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, - 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, - 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, - 199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246, - 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318, - 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380, - 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459, - 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513, - 521, 524, 529, 534, 540, 544, 549, - }; - static const unsigned char aCode[124] = { - TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, - TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, - TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, - TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, - TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, - TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, - TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, - TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, - TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, - TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, - TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, - TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RECURSIVE, TK_BETWEEN, - TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, - TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE, - TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN, - TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, - TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, - TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND, - TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, - TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, - TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS, - TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW, - TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT, - TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING, - TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL, - }; - int i, j; - const char *zKW; - if( n>=2 ){ - i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127; - for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){ - if( aLen[i]!=n ) continue; - j = 0; - zKW = &zText[aOffset[i]]; -#ifdef SQLITE_ASCII - while( j=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2 + )); + + /* If the BIGNULL flag is set for the ORDER BY, then it is required to + ** consider NULL values to be larger than all other values, instead of + ** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this + ** (and adding that capability causes a performance regression), so + ** instead if the BIGNULL flag is set then cases where either reg1 or + ** reg2 are NULL are handled separately in the following block. The code + ** generated is equivalent to: + ** + ** if( reg1 IS NULL ){ + ** if( op==OP_Ge ) goto lbl; + ** if( op==OP_Gt && reg2 IS NOT NULL ) goto lbl; + ** if( op==OP_Le && reg2 IS NULL ) goto lbl; + ** }else if( reg2 IS NULL ){ + ** if( op==OP_Le ) goto lbl; + ** } + ** + ** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is + ** not taken, control jumps over the comparison operator coded below this + ** block. */ + if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){ + /* This block runs if reg1 contains a NULL. */ + int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v); + switch( op ){ + case OP_Ge: + sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl); + break; + case OP_Gt: + sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl); + VdbeCoverage(v); + break; + case OP_Le: + sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); + VdbeCoverage(v); + break; + default: assert( op==OP_Lt ); /* no-op */ break; + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone); + + /* This block runs if reg1 is not NULL, but reg2 is. */ + sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v); + if( op==OP_Gt || op==OP_Ge ){ + sqlite3VdbeChangeP2(v, -1, addrDone); } } - return n; -} -SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){ - int id = TK_ID; - keywordCode((char*)z, n, &id); - return id; -} -#define SQLITE_N_KEYWORD 124 -/************** End of keywordhash.h *****************************************/ -/************** Continuing where we left off in tokenize.c *******************/ + /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1). + ** This block adds (or subtracts for DESC) the numeric value in regVal + ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob), + ** then leave reg1 as it is. In pseudo-code, this is implemented as: + ** + ** if( reg1>='' ) goto addrGe; + ** reg1 = reg1 +/- regVal + ** addrGe: + ** + ** Since all strings and blobs are greater-than-or-equal-to an empty string, + ** the add/subtract is skipped for these, as required. If reg1 is a NULL, + ** then the arithmetic is performed, but since adding or subtracting from + ** NULL is always NULL anyway, this case is handled as required too. */ + sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); + addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); + VdbeCoverage(v); + if( (op==OP_Ge && arith==OP_Add) || (op==OP_Le && arith==OP_Subtract) ){ + sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); + } + sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); + sqlite3VdbeJumpHere(v, addrGe); + + /* Compare registers reg2 and reg1, taking the jump if required. Note that + ** control skips over this test if the BIGNULL flag is set and either + ** reg1 or reg2 contain a NULL value. */ + sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); + pColl = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[0].pExpr); + sqlite3VdbeAppendP4(v, (void*)pColl, P4_COLLSEQ); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + sqlite3VdbeResolveLabel(v, addrDone); + assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le ); + testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge); + testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt); + testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le); + testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt); + sqlite3ReleaseTempReg(pParse, reg1); + sqlite3ReleaseTempReg(pParse, reg2); + + VdbeModuleComment((v, "CodeRangeTest: end")); +} /* -** If X is a character that can be used in an identifier then -** IdChar(X) will be true. Otherwise it is false. -** -** For ASCII, any character with the high-order bit set is -** allowed in an identifier. For 7-bit characters, -** sqlite3IsIdChar[X] must be 1. -** -** For EBCDIC, the rules are more complex but have the same -** end result. -** -** Ticket #1066. the SQL standard does not allow '$' in the -** middle of identifiers. But many SQL implementations do. -** SQLite will allow '$' in identifiers for compatibility. -** But the feature is undocumented. +** Helper function for sqlite3WindowCodeStep(). Each call to this function +** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE +** operation. Refer to the header comment for sqlite3WindowCodeStep() for +** details. */ -#ifdef SQLITE_ASCII -#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) -#endif -#ifdef SQLITE_EBCDIC -SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = { -/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */ - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */ - 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */ - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */ -}; -#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) -#endif +static int windowCodeOp( + WindowCodeArg *p, /* Context object */ + int op, /* WINDOW_RETURN_ROW, AGGSTEP or AGGINVERSE */ + int regCountdown, /* Register for OP_IfPos countdown */ + int jumpOnEof /* Jump here if stepped cursor reaches EOF */ +){ + int csr, reg; + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; + int ret = 0; + Vdbe *v = p->pVdbe; + int addrContinue = 0; + int bPeer = (pMWin->eFrmType!=TK_ROWS); -/* Make the IdChar function accessible from ctime.c */ -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS -SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); } -#endif + int lblDone = sqlite3VdbeMakeLabel(pParse); + int addrNextRange = 0; + /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame + ** starts with UNBOUNDED PRECEDING. */ + if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){ + assert( regCountdown==0 && jumpOnEof==0 ); + return 0; + } -/* -** Return the length (in bytes) of the token that begins at z[0]. -** Store the token type in *tokenType before returning. -*/ -SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ - int i, c; - switch( aiClass[*z] ){ /* Switch on the character-class of the first byte - ** of the token. See the comment on the CC_ defines - ** above. */ - case CC_SPACE: { - testcase( z[0]==' ' ); - testcase( z[0]=='\t' ); - testcase( z[0]=='\n' ); - testcase( z[0]=='\f' ); - testcase( z[0]=='\r' ); - for(i=1; sqlite3Isspace(z[i]); i++){} - *tokenType = TK_SPACE; - return i; - } - case CC_MINUS: { - if( z[1]=='-' ){ - for(i=2; (c=z[i])!=0 && c!='\n'; i++){} - *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ - return i; - } - *tokenType = TK_MINUS; - return 1; - } - case CC_LP: { - *tokenType = TK_LP; - return 1; - } - case CC_RP: { - *tokenType = TK_RP; - return 1; - } - case CC_SEMI: { - *tokenType = TK_SEMI; - return 1; - } - case CC_PLUS: { - *tokenType = TK_PLUS; - return 1; - } - case CC_STAR: { - *tokenType = TK_STAR; - return 1; - } - case CC_SLASH: { - if( z[1]!='*' || z[2]==0 ){ - *tokenType = TK_SLASH; - return 1; - } - for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} - if( c ) i++; - *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ - return i; - } - case CC_PERCENT: { - *tokenType = TK_REM; - return 1; - } - case CC_EQ: { - *tokenType = TK_EQ; - return 1 + (z[1]=='='); - } - case CC_LT: { - if( (c=z[1])=='=' ){ - *tokenType = TK_LE; - return 2; - }else if( c=='>' ){ - *tokenType = TK_NE; - return 2; - }else if( c=='<' ){ - *tokenType = TK_LSHIFT; - return 2; - }else{ - *tokenType = TK_LT; - return 1; - } - } - case CC_GT: { - if( (c=z[1])=='=' ){ - *tokenType = TK_GE; - return 2; - }else if( c=='>' ){ - *tokenType = TK_RSHIFT; - return 2; - }else{ - *tokenType = TK_GT; - return 1; - } - } - case CC_BANG: { - if( z[1]!='=' ){ - *tokenType = TK_ILLEGAL; - return 1; - }else{ - *tokenType = TK_NE; - return 2; - } - } - case CC_PIPE: { - if( z[1]!='|' ){ - *tokenType = TK_BITOR; - return 1; - }else{ - *tokenType = TK_CONCAT; - return 2; - } - } - case CC_COMMA: { - *tokenType = TK_COMMA; - return 1; - } - case CC_AND: { - *tokenType = TK_BITAND; - return 1; - } - case CC_TILDA: { - *tokenType = TK_BITNOT; - return 1; - } - case CC_QUOTE: { - int delim = z[0]; - testcase( delim=='`' ); - testcase( delim=='\'' ); - testcase( delim=='"' ); - for(i=1; (c=z[i])!=0; i++){ - if( c==delim ){ - if( z[i+1]==delim ){ - i++; - }else{ - break; - } - } - } - if( c=='\'' ){ - *tokenType = TK_STRING; - return i+1; - }else if( c!=0 ){ - *tokenType = TK_ID; - return i+1; - }else{ - *tokenType = TK_ILLEGAL; - return i; - } - } - case CC_DOT: { -#ifndef SQLITE_OMIT_FLOATING_POINT - if( !sqlite3Isdigit(z[1]) ) -#endif - { - *tokenType = TK_DOT; - return 1; - } - /* If the next character is a digit, this is a floating point - ** number that begins with ".". Fall thru into the next case */ - } - case CC_DIGIT: { - testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); - testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); - testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); - testcase( z[0]=='9' ); - *tokenType = TK_INTEGER; -#ifndef SQLITE_OMIT_HEX_INTEGER - if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ - for(i=3; sqlite3Isxdigit(z[i]); i++){} - return i; - } -#endif - for(i=0; sqlite3Isdigit(z[i]); i++){} -#ifndef SQLITE_OMIT_FLOATING_POINT - if( z[i]=='.' ){ - i++; - while( sqlite3Isdigit(z[i]) ){ i++; } - *tokenType = TK_FLOAT; - } - if( (z[i]=='e' || z[i]=='E') && - ( sqlite3Isdigit(z[i+1]) - || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) - ) - ){ - i += 2; - while( sqlite3Isdigit(z[i]) ){ i++; } - *tokenType = TK_FLOAT; - } -#endif - while( IdChar(z[i]) ){ - *tokenType = TK_ILLEGAL; - i++; - } - return i; - } - case CC_QUOTE2: { - for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} - *tokenType = c==']' ? TK_ID : TK_ILLEGAL; - return i; - } - case CC_VARNUM: { - *tokenType = TK_VARIABLE; - for(i=1; sqlite3Isdigit(z[i]); i++){} - return i; - } - case CC_DOLLAR: - case CC_VARALPHA: { - int n = 0; - testcase( z[0]=='$' ); testcase( z[0]=='@' ); - testcase( z[0]==':' ); testcase( z[0]=='#' ); - *tokenType = TK_VARIABLE; - for(i=1; (c=z[i])!=0; i++){ - if( IdChar(c) ){ - n++; -#ifndef SQLITE_OMIT_TCL_VARIABLE - }else if( c=='(' && n>0 ){ - do{ - i++; - }while( (c=z[i])!=0 && !sqlite3Isspace(c) && c!=')' ); - if( c==')' ){ - i++; - }else{ - *tokenType = TK_ILLEGAL; - } - break; - }else if( c==':' && z[i+1]==':' ){ - i++; -#endif + if( regCountdown>0 ){ + if( pMWin->eFrmType==TK_RANGE ){ + addrNextRange = sqlite3VdbeCurrentAddr(v); + assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP ); + if( op==WINDOW_AGGINVERSE ){ + if( pMWin->eStart==TK_FOLLOWING ){ + windowCodeRangeTest( + p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone + ); }else{ - break; - } - } - if( n==0 ) *tokenType = TK_ILLEGAL; - return i; - } - case CC_KYWD: { - for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} - if( IdChar(z[i]) ){ - /* This token started out using characters that can appear in keywords, - ** but z[i] is a character not allowed within keywords, so this must - ** be an identifier instead */ - i++; - break; - } - *tokenType = TK_ID; - return keywordCode((char*)z, i, tokenType); - } - case CC_X: { -#ifndef SQLITE_OMIT_BLOB_LITERAL - testcase( z[0]=='x' ); testcase( z[0]=='X' ); - if( z[1]=='\'' ){ - *tokenType = TK_BLOB; - for(i=2; sqlite3Isxdigit(z[i]); i++){} - if( z[i]!='\'' || i%2 ){ - *tokenType = TK_ILLEGAL; - while( z[i] && z[i]!='\'' ){ i++; } + windowCodeRangeTest( + p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone + ); } - if( z[i] ) i++; - return i; + }else{ + windowCodeRangeTest( + p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone + ); } -#endif - /* If it is not a BLOB literal, then it must be an ID, since no - ** SQL keywords start with the letter 'x'. Fall through */ - } - case CC_ID: { - i = 1; - break; - } - default: { - *tokenType = TK_ILLEGAL; - return 1; + }else{ + sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, lblDone, 1); + VdbeCoverage(v); } } - while( IdChar(z[i]) ){ i++; } - *tokenType = TK_ID; - return i; -} - -/* -** Run the parser on the given SQL string. The parser structure is -** passed in. An SQLITE_ status code is returned. If an error occurs -** then an and attempt is made to write an error message into -** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that -** error message. -*/ -SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ - int nErr = 0; /* Number of errors encountered */ - int i; /* Loop counter */ - void *pEngine; /* The LEMON-generated LALR(1) parser */ - int tokenType; /* type of the next token */ - int lastTokenParsed = -1; /* type of the previous token */ - sqlite3 *db = pParse->db; /* The database connection */ - int mxSqlLen; /* Max length of an SQL string */ -#ifdef sqlite3Parser_ENGINEALWAYSONSTACK - unsigned char zSpace[sizeof(yyParser)]; /* Space for parser engine object */ -#endif - assert( zSql!=0 ); - mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; - if( db->nVdbeActive==0 ){ - db->u1.isInterrupted = 0; + if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){ + windowAggFinal(p, 0); } - pParse->rc = SQLITE_OK; - pParse->zTail = zSql; - i = 0; - assert( pzErrMsg!=0 ); - /* sqlite3ParserTrace(stdout, "parser: "); */ -#ifdef sqlite3Parser_ENGINEALWAYSONSTACK - pEngine = zSpace; - sqlite3ParserInit(pEngine); -#else - pEngine = sqlite3ParserAlloc(sqlite3Malloc); - if( pEngine==0 ){ - sqlite3OomFault(db); - return SQLITE_NOMEM_BKPT; + addrContinue = sqlite3VdbeCurrentAddr(v); + + /* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or + ** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the + ** start cursor does not advance past the end cursor within the + ** temporary table. It otherwise might, if (a>b). Also ensure that, + ** if the input cursor is still finding new rows, that the end + ** cursor does not go past it to EOF. */ + if( pMWin->eStart==pMWin->eEnd && regCountdown + && pMWin->eFrmType==TK_RANGE + ){ + int regRowid1 = sqlite3GetTempReg(pParse); + int regRowid2 = sqlite3GetTempReg(pParse); + if( op==WINDOW_AGGINVERSE ){ + sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1); + sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2); + sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1); + VdbeCoverage(v); + }else if( p->regRowid ){ + sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid1); + sqlite3VdbeAddOp3(v, OP_Ge, p->regRowid, lblDone, regRowid1); + VdbeCoverageNeverNull(v); + } + sqlite3ReleaseTempReg(pParse, regRowid1); + sqlite3ReleaseTempReg(pParse, regRowid2); + assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ); } -#endif - assert( pParse->pNewTable==0 ); - assert( pParse->pNewTrigger==0 ); - assert( pParse->nVar==0 ); - assert( pParse->pVList==0 ); - while( 1 ){ - assert( i>=0 ); - if( zSql[i]!=0 ){ - pParse->sLastToken.z = &zSql[i]; - pParse->sLastToken.n = sqlite3GetToken((u8*)&zSql[i],&tokenType); - i += pParse->sLastToken.n; - if( i>mxSqlLen ){ - pParse->rc = SQLITE_TOOBIG; - break; - } - }else{ - /* Upon reaching the end of input, call the parser two more times - ** with tokens TK_SEMI and 0, in that order. */ - if( lastTokenParsed==TK_SEMI ){ - tokenType = 0; - }else if( lastTokenParsed==0 ){ - break; + + switch( op ){ + case WINDOW_RETURN_ROW: + csr = p->current.csr; + reg = p->current.reg; + windowReturnOneRow(p); + break; + + case WINDOW_AGGINVERSE: + csr = p->start.csr; + reg = p->start.reg; + if( pMWin->regStartRowid ){ + assert( pMWin->regEndRowid ); + sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regStartRowid, 1); }else{ - tokenType = TK_SEMI; - } - } - if( tokenType>=TK_SPACE ){ - assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); - if( db->u1.isInterrupted ){ - pParse->rc = SQLITE_INTERRUPT; - break; + windowAggStep(p, pMWin, csr, 1, p->regArg); } - if( tokenType==TK_ILLEGAL ){ - sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", - &pParse->sLastToken); - break; + break; + + default: + assert( op==WINDOW_AGGSTEP ); + csr = p->end.csr; + reg = p->end.reg; + if( pMWin->regStartRowid ){ + assert( pMWin->regEndRowid ); + sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regEndRowid, 1); + }else{ + windowAggStep(p, pMWin, csr, 0, p->regArg); } - }else{ - sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); - lastTokenParsed = tokenType; - if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; - } - } - assert( nErr==0 ); - pParse->zTail = &zSql[i]; -#ifdef YYTRACKMAXSTACKDEPTH - sqlite3_mutex_enter(sqlite3MallocMutex()); - sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, - sqlite3ParserStackPeak(pEngine) - ); - sqlite3_mutex_leave(sqlite3MallocMutex()); -#endif /* YYDEBUG */ -#ifdef sqlite3Parser_ENGINEALWAYSONSTACK - sqlite3ParserFinalize(pEngine); -#else - sqlite3ParserFree(pEngine, sqlite3_free); -#endif - if( db->mallocFailed ){ - pParse->rc = SQLITE_NOMEM_BKPT; - } - if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ - pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); - } - assert( pzErrMsg!=0 ); - if( pParse->zErrMsg ){ - *pzErrMsg = pParse->zErrMsg; - sqlite3_log(pParse->rc, "%s", *pzErrMsg); - pParse->zErrMsg = 0; - nErr++; - } - if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){ - sqlite3VdbeDelete(pParse->pVdbe); - pParse->pVdbe = 0; + break; } -#ifndef SQLITE_OMIT_SHARED_CACHE - if( pParse->nested==0 ){ - sqlite3DbFree(db, pParse->aTableLock); - pParse->aTableLock = 0; - pParse->nTableLock = 0; + + if( op==p->eDelete ){ + sqlite3VdbeAddOp1(v, OP_Delete, csr); + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); } -#endif -#ifndef SQLITE_OMIT_VIRTUALTABLE - sqlite3_free(pParse->apVtabLock); -#endif - if( !IN_DECLARE_VTAB ){ - /* If the pParse->declareVtab flag is set, do not delete any table - ** structure built up in pParse->pNewTable. The calling code (see vtab.c) - ** will take responsibility for freeing the Table structure. - */ - sqlite3DeleteTable(db, pParse->pNewTable); + if( jumpOnEof ){ + sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + ret = sqlite3VdbeAddOp0(v, OP_Goto); + }else{ + sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1+bPeer); + VdbeCoverage(v); + if( bPeer ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblDone); + } } - if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); - sqlite3DeleteTrigger(db, pParse->pNewTrigger); - sqlite3DbFree(db, pParse->pVList); - while( pParse->pAinc ){ - AutoincInfo *p = pParse->pAinc; - pParse->pAinc = p->pNext; - sqlite3DbFree(db, p); + if( bPeer ){ + int nReg = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); + int regTmp = (nReg ? sqlite3GetTempRange(pParse, nReg) : 0); + windowReadPeerValues(p, csr, regTmp); + windowIfNewPeer(pParse, pMWin->pOrderBy, regTmp, reg, addrContinue); + sqlite3ReleaseTempRange(pParse, regTmp, nReg); } - while( pParse->pZombieTab ){ - Table *p = pParse->pZombieTab; - pParse->pZombieTab = p->pNextZombie; - sqlite3DeleteTable(db, p); + + if( addrNextRange ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNextRange); } - assert( nErr==0 || pParse->rc!=SQLITE_OK ); - return nErr; + sqlite3VdbeResolveLabel(v, lblDone); + return ret; } -/************** End of tokenize.c ********************************************/ -/************** Begin file complete.c ****************************************/ + /* -** 2001 September 15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** An tokenizer for SQL -** -** This file contains C code that implements the sqlite3_complete() API. -** This code used to be part of the tokenizer.c source file. But by -** separating it out, the code will be automatically omitted from -** static links that do not use it. +** Allocate and return a duplicate of the Window object indicated by the +** third argument. Set the Window.pOwner field of the new object to +** pOwner. */ -/* #include "sqliteInt.h" */ -#ifndef SQLITE_OMIT_COMPLETE +SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ + Window *pNew = 0; + if( ALWAYS(p) ){ + pNew = sqlite3DbMallocZero(db, sizeof(Window)); + if( pNew ){ + pNew->zName = sqlite3DbStrDup(db, p->zName); + pNew->zBase = sqlite3DbStrDup(db, p->zBase); + pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); + pNew->pFunc = p->pFunc; + pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); + pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); + pNew->eFrmType = p->eFrmType; + pNew->eEnd = p->eEnd; + pNew->eStart = p->eStart; + pNew->eExclude = p->eExclude; + pNew->regResult = p->regResult; + pNew->regAccum = p->regAccum; + pNew->iArgCol = p->iArgCol; + pNew->iEphCsr = p->iEphCsr; + pNew->bExprArgs = p->bExprArgs; + pNew->pStart = sqlite3ExprDup(db, p->pStart, 0); + pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0); + pNew->pOwner = pOwner; + pNew->bImplicitFrame = p->bImplicitFrame; + } + } + return pNew; +} /* -** This is defined in tokenize.c. We just have to import the definition. +** Return a copy of the linked list of Window objects passed as the +** second argument. */ -#ifndef SQLITE_AMALGAMATION -#ifdef SQLITE_ASCII -#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) -#endif -#ifdef SQLITE_EBCDIC -SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; -#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) -#endif -#endif /* SQLITE_AMALGAMATION */ +SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){ + Window *pWin; + Window *pRet = 0; + Window **pp = &pRet; + + for(pWin=p; pWin; pWin=pWin->pNextWin){ + *pp = sqlite3WindowDup(db, 0, pWin); + if( *pp==0 ) break; + pp = &((*pp)->pNextWin); + } + return pRet; +} /* -** Token types used by the sqlite3_complete() routine. See the header -** comments on that procedure for additional information. +** Return true if it can be determined at compile time that expression +** pExpr evaluates to a value that, when cast to an integer, is greater +** than zero. False otherwise. +** +** If an OOM error occurs, this function sets the Parse.db.mallocFailed +** flag and returns zero. */ -#define tkSEMI 0 -#define tkWS 1 -#define tkOTHER 2 -#ifndef SQLITE_OMIT_TRIGGER -#define tkEXPLAIN 3 -#define tkCREATE 4 -#define tkTEMP 5 -#define tkTRIGGER 6 -#define tkEND 7 -#endif +static int windowExprGtZero(Parse *pParse, Expr *pExpr){ + int ret = 0; + sqlite3 *db = pParse->db; + sqlite3_value *pVal = 0; + sqlite3ValueFromExpr(db, pExpr, db->enc, SQLITE_AFF_NUMERIC, &pVal); + if( pVal && sqlite3_value_int(pVal)>0 ){ + ret = 1; + } + sqlite3ValueFree(pVal); + return ret; +} /* -** Return TRUE if the given SQL string ends in a semicolon. +** sqlite3WhereBegin() has already been called for the SELECT statement +** passed as the second argument when this function is invoked. It generates +** code to populate the Window.regResult register for each window function +** and invoke the sub-routine at instruction addrGosub once for each row. +** sqlite3WhereEnd() is always called before returning. ** -** Special handling is require for CREATE TRIGGER statements. -** Whenever the CREATE TRIGGER keywords are seen, the statement -** must end with ";END;". +** This function handles several different types of window frames, which +** require slightly different processing. The following pseudo code is +** used to implement window frames of the form: ** -** This implementation uses a state machine with 8 states: +** ROWS BETWEEN PRECEDING AND FOLLOWING ** -** (0) INVALID We have not yet seen a non-whitespace character. +** Other window frame types use variants of the following: ** -** (1) START At the beginning or end of an SQL statement. This routine -** returns 1 if it ends in the START state and 0 if it ends -** in any other state. +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** +** if( first row of partition ){ +** // Rewind three cursors, all open on the eph table. +** Rewind(csrEnd); +** Rewind(csrStart); +** Rewind(csrCurrent); +** +** regEnd = // FOLLOWING expression +** regStart = // PRECEDING expression +** }else{ +** // First time this branch is taken, the eph table contains two +** // rows. The first row in the partition, which all three cursors +** // currently point to, and the following row. +** AGGSTEP +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** RETURN ROW +** if( csrCurrent is EOF ) break; +** if( (regStart--)<=0 ){ +** AggInverse(csrStart) +** Next(csrStart) +** } +** } ** -** (2) NORMAL We are in the middle of statement which ends with a single -** semicolon. +** The pseudo-code above uses the following shorthand: ** -** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of -** a statement. +** AGGSTEP: invoke the aggregate xStep() function for each window function +** with arguments read from the current row of cursor csrEnd, then +** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()). ** -** (4) CREATE The keyword CREATE has been seen at the beginning of a -** statement, possibly preceded by EXPLAIN and/or followed by -** TEMP or TEMPORARY +** RETURN_ROW: return a row to the caller based on the contents of the +** current row of csrCurrent and the current state of all +** aggregates. Then step cursor csrCurrent forward one row. ** -** (5) TRIGGER We are in the middle of a trigger definition that must be -** ended by a semicolon, the keyword END, and another semicolon. +** AGGINVERSE: invoke the aggregate xInverse() function for each window +** functions with arguments read from the current row of cursor +** csrStart. Then step csrStart forward one row. ** -** (6) SEMI We've seen the first semicolon in the ";END;" that occurs at -** the end of a trigger definition. +** There are two other ROWS window frames that are handled significantly +** differently from the above - "BETWEEN PRECEDING AND PRECEDING" +** and "BETWEEN FOLLOWING AND FOLLOWING". These are special +** cases because they change the order in which the three cursors (csrStart, +** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that +** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these +** three. ** -** (7) END We've seen the ";END" of the ";END;" that occurs at the end -** of a trigger definition. +** ROWS BETWEEN PRECEDING AND PRECEDING ** -** Transitions between states above are determined by tokens extracted -** from the input. The following tokens are significant: +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** if( (regEnd--)<=0 ){ +** AGGSTEP +** } +** RETURN_ROW +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** flush: +** if( (regEnd--)<=0 ){ +** AGGSTEP +** } +** RETURN_ROW ** -** (0) tkSEMI A semicolon. -** (1) tkWS Whitespace. -** (2) tkOTHER Any other SQL token. -** (3) tkEXPLAIN The "explain" keyword. -** (4) tkCREATE The "create" keyword. -** (5) tkTEMP The "temp" or "temporary" keyword. -** (6) tkTRIGGER The "trigger" keyword. -** (7) tkEND The "end" keyword. ** -** Whitespace never causes a state transition and is always ignored. -** This means that a SQL string of all whitespace is invalid. +** ROWS BETWEEN FOLLOWING AND FOLLOWING ** -** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed -** to recognize the end of a trigger can be omitted. All we have to do -** is look for a semicolon that is not part of an string or comment. +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = regEnd - +** }else{ +** AGGSTEP +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** } +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** if( eof ) break; +** } +** if( (regStart--)<=0 ){ +** AGGINVERSE +** if( eof ) break +** } +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** For the most part, the patterns above are adapted to support UNBOUNDED by +** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and +** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING". +** This is optimized of course - branches that will never be taken and +** conditions that are always true are omitted from the VM code. The only +** exceptional case is: +** +** ROWS BETWEEN FOLLOWING AND UNBOUNDED FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regStart = +** }else{ +** AGGSTEP +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** if( (regStart--)<=0 ){ +** AGGINVERSE +** if( eof ) break +** } +** RETURN_ROW +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** Also requiring special handling are the cases: +** +** ROWS BETWEEN PRECEDING AND PRECEDING +** ROWS BETWEEN FOLLOWING AND FOLLOWING +** +** when (expr1 < expr2). This is detected at runtime, not by this function. +** To handle this case, the pseudo-code programs depicted above are modified +** slightly to be: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** if( regEnd < regStart ){ +** RETURN_ROW +** delete eph table contents +** continue +** } +** ... +** +** The new "continue" statement in the above jumps to the next iteration +** of the outer loop - the one started by sqlite3WhereBegin(). +** +** The various GROUPS cases are implemented using the same patterns as +** ROWS. The VM code is modified slightly so that: +** +** 1. The else branch in the main loop is only taken if the row just +** added to the ephemeral table is the start of a new group. In +** other words, it becomes: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else if( new group ){ +** ... +** } +** } +** +** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or +** AGGINVERSE step processes the current row of the relevant cursor and +** all subsequent rows belonging to the same group. +** +** RANGE window frames are a little different again. As for GROUPS, the +** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE +** deal in groups instead of rows. As for ROWS and GROUPS, there are three +** basic cases: +** +** RANGE BETWEEN PRECEDING AND FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** AGGSTEP +** while( (csrCurrent.key + regEnd) < csrEnd.key ){ +** RETURN_ROW +** while( csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** RETURN ROW +** if( csrCurrent is EOF ) break; +** while( csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** } +** } +** +** In the above notation, "csr.key" means the current value of the ORDER BY +** expression (there is only ever 1 for a RANGE that uses an FOLLOWING +** or PRECEDING AND PRECEDING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ +** AGGSTEP +** } +** while( (csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** } +** } +** flush: +** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ +** AGGSTEP +** } +** while( (csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** +** RANGE BETWEEN FOLLOWING AND FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = +** regStart = +** }else{ +** AGGSTEP +** while( (csrCurrent.key + regEnd) < csrEnd.key ){ +** while( (csrCurrent.key + regStart) > csrStart.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** while( (csrCurrent.key + regStart) > csrStart.key ){ +** AGGINVERSE +** if( eof ) break "while( 1 )" loop. +** } +** RETURN_ROW +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** The text above leaves out many details. Refer to the code and comments +** below for a more complete picture. */ -SQLITE_API int sqlite3_complete(const char *zSql){ - u8 state = 0; /* Current state, using numbers defined in header comment */ - u8 token; /* Value of the next token */ - -#ifndef SQLITE_OMIT_TRIGGER - /* A complex statement machine used to detect the end of a CREATE TRIGGER - ** statement. This is the normal case. - */ - static const u8 trans[8][8] = { - /* Token: */ - /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ - /* 0 INVALID: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, - /* 1 START: */ { 1, 1, 2, 3, 4, 2, 2, 2, }, - /* 2 NORMAL: */ { 1, 2, 2, 2, 2, 2, 2, 2, }, - /* 3 EXPLAIN: */ { 1, 3, 3, 2, 4, 2, 2, 2, }, - /* 4 CREATE: */ { 1, 4, 2, 2, 2, 4, 5, 2, }, - /* 5 TRIGGER: */ { 6, 5, 5, 5, 5, 5, 5, 5, }, - /* 6 SEMI: */ { 6, 6, 5, 5, 5, 5, 5, 7, }, - /* 7 END: */ { 1, 7, 5, 5, 5, 5, 5, 5, }, - }; -#else - /* If triggers are not supported by this compile then the statement machine - ** used to detect the end of a statement is much simpler - */ - static const u8 trans[3][3] = { - /* Token: */ - /* State: ** SEMI WS OTHER */ - /* 0 INVALID: */ { 1, 0, 2, }, - /* 1 START: */ { 1, 1, 2, }, - /* 2 NORMAL: */ { 1, 2, 2, }, - }; -#endif /* SQLITE_OMIT_TRIGGER */ - -#ifdef SQLITE_ENABLE_API_ARMOR - if( zSql==0 ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif +SQLITE_PRIVATE void sqlite3WindowCodeStep( + Parse *pParse, /* Parse context */ + Select *p, /* Rewritten SELECT statement */ + WhereInfo *pWInfo, /* Context returned by sqlite3WhereBegin() */ + int regGosub, /* Register for OP_Gosub */ + int addrGosub /* OP_Gosub here to return each row */ +){ + Window *pMWin = p->pWin; + ExprList *pOrderBy = pMWin->pOrderBy; + Vdbe *v = sqlite3GetVdbe(pParse); + int csrWrite; /* Cursor used to write to eph. table */ + int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ + int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ + int iInput; /* To iterate through sub cols */ + int addrNe; /* Address of OP_Ne */ + int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ + int addrInteger = 0; /* Address of OP_Integer */ + int addrEmpty; /* Address of OP_Rewind in flush: */ + int regNew; /* Array of registers holding new input row */ + int regRecord; /* regNew array in record form */ + int regNewPeer = 0; /* Peer values for new row (part of regNew) */ + int regPeer = 0; /* Peer values for current row */ + int regFlushPart = 0; /* Register for "Gosub flush_partition" */ + WindowCodeArg s; /* Context object for sub-routines */ + int lblWhereEnd; /* Label just before sqlite3WhereEnd() code */ + int regStart = 0; /* Value of PRECEDING */ + int regEnd = 0; /* Value of FOLLOWING */ + + assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT + || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED + ); + assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT + || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING + ); + assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT + || pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES + || pMWin->eExclude==TK_NO + ); - while( *zSql ){ - switch( *zSql ){ - case ';': { /* A semicolon */ - token = tkSEMI; - break; - } - case ' ': - case '\r': - case '\t': - case '\n': - case '\f': { /* White space is ignored */ - token = tkWS; - break; - } - case '/': { /* C-style comments */ - if( zSql[1]!='*' ){ - token = tkOTHER; - break; - } - zSql += 2; - while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } - if( zSql[0]==0 ) return 0; - zSql++; - token = tkWS; - break; + lblWhereEnd = sqlite3VdbeMakeLabel(pParse); + + /* Fill in the context object */ + memset(&s, 0, sizeof(WindowCodeArg)); + s.pParse = pParse; + s.pMWin = pMWin; + s.pVdbe = v; + s.regGosub = regGosub; + s.addrGosub = addrGosub; + s.current.csr = pMWin->iEphCsr; + csrWrite = s.current.csr+1; + s.start.csr = s.current.csr+2; + s.end.csr = s.current.csr+3; + + /* Figure out when rows may be deleted from the ephemeral table. There + ** are four options - they may never be deleted (eDelete==0), they may + ** be deleted as soon as they are no longer part of the window frame + ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row + ** has been returned to the caller (WINDOW_RETURN_ROW), or they may + ** be deleted after they enter the frame (WINDOW_AGGSTEP). */ + switch( pMWin->eStart ){ + case TK_FOLLOWING: + if( pMWin->eFrmType!=TK_RANGE + && windowExprGtZero(pParse, pMWin->pStart) + ){ + s.eDelete = WINDOW_RETURN_ROW; } - case '-': { /* SQL-style comments from "--" to end of line */ - if( zSql[1]!='-' ){ - token = tkOTHER; - break; + break; + case TK_UNBOUNDED: + if( windowCacheFrame(pMWin)==0 ){ + if( pMWin->eEnd==TK_PRECEDING ){ + if( pMWin->eFrmType!=TK_RANGE + && windowExprGtZero(pParse, pMWin->pEnd) + ){ + s.eDelete = WINDOW_AGGSTEP; + } + }else{ + s.eDelete = WINDOW_RETURN_ROW; } - while( *zSql && *zSql!='\n' ){ zSql++; } - if( *zSql==0 ) return state==1; - token = tkWS; - break; - } - case '[': { /* Microsoft-style identifiers in [...] */ - zSql++; - while( *zSql && *zSql!=']' ){ zSql++; } - if( *zSql==0 ) return 0; - token = tkOTHER; - break; } - case '`': /* Grave-accent quoted symbols used by MySQL */ - case '"': /* single- and double-quoted strings */ - case '\'': { - int c = *zSql; - zSql++; - while( *zSql && *zSql!=c ){ zSql++; } - if( *zSql==0 ) return 0; - token = tkOTHER; - break; + break; + default: + s.eDelete = WINDOW_AGGINVERSE; + break; + } + + /* Allocate registers for the array of values from the sub-query, the + ** samve values in record form, and the rowid used to insert said record + ** into the ephemeral table. */ + regNew = pParse->nMem+1; + pParse->nMem += nInput; + regRecord = ++pParse->nMem; + s.regRowid = ++pParse->nMem; + + /* If the window frame contains an " PRECEDING" or " FOLLOWING" + ** clause, allocate registers to store the results of evaluating each + ** . */ + if( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ){ + regStart = ++pParse->nMem; + } + if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){ + regEnd = ++pParse->nMem; + } + + /* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of + ** registers to store copies of the ORDER BY expressions (peer values) + ** for the main loop, and for each cursor (start, current and end). */ + if( pMWin->eFrmType!=TK_ROWS ){ + int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); + regNewPeer = regNew + pMWin->nBufferCol; + if( pMWin->pPartition ) regNewPeer += pMWin->pPartition->nExpr; + regPeer = pParse->nMem+1; pParse->nMem += nPeer; + s.start.reg = pParse->nMem+1; pParse->nMem += nPeer; + s.current.reg = pParse->nMem+1; pParse->nMem += nPeer; + s.end.reg = pParse->nMem+1; pParse->nMem += nPeer; + } + + /* Load the column values for the row returned by the sub-select + ** into an array of registers starting at regNew. Assemble them into + ** a record in register regRecord. */ + for(iInput=0; iInputpPartition ){ + int addr; + ExprList *pPart = pMWin->pPartition; + int nPart = pPart->nExpr; + int regNewPart = regNew + pMWin->nBufferCol; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); + + regFlushPart = ++pParse->nMem; + addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart, nPart); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); + VdbeCoverageEqNe(v); + addrGosubFlush = sqlite3VdbeAddOp1(v, OP_Gosub, regFlushPart); + VdbeComment((v, "call flush_partition")); + sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); + } + + /* Insert the new row into the ephemeral table */ + sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, s.regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, s.regRowid); + addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, s.regRowid); + VdbeCoverageNeverNull(v); + + /* This block is run for the first row of each partition */ + s.regArg = windowInitAccum(pParse, pMWin); + + if( regStart ){ + sqlite3ExprCode(pParse, pMWin->pStart, regStart); + windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE?3:0)); + } + if( regEnd ){ + sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); + windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE?3:0)); + } + + if( pMWin->eFrmType!=TK_RANGE && pMWin->eStart==pMWin->eEnd && regStart ){ + int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le); + int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd); + VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound */ + VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */ + windowAggFinal(&s, 0); + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); + windowReturnOneRow(&s); + sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); + sqlite3VdbeJumpHere(v, addrGe); + } + if( pMWin->eStart==TK_FOLLOWING && pMWin->eFrmType!=TK_RANGE && regEnd ){ + assert( pMWin->eEnd==TK_FOLLOWING ); + sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart); + } + + if( pMWin->eStart!=TK_UNBOUNDED ){ + sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1); + VdbeCoverageNeverTaken(v); + } + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1); + VdbeCoverageNeverTaken(v); + if( regPeer && pOrderBy ){ + sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.current.reg, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.end.reg, pOrderBy->nExpr-1); + } + + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); + + sqlite3VdbeJumpHere(v, addrNe); + + /* Beginning of the block executed for the second and subsequent rows. */ + if( regPeer ){ + windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd); + } + if( pMWin->eStart==TK_FOLLOWING ){ + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eEnd!=TK_UNBOUNDED ){ + if( pMWin->eFrmType==TK_RANGE ){ + int lbl = sqlite3VdbeMakeLabel(pParse); + int addrNext = sqlite3VdbeCurrentAddr(v); + windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext); + sqlite3VdbeResolveLabel(v, lbl); + }else{ + windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); } - default: { -#ifdef SQLITE_EBCDIC - unsigned char c; -#endif - if( IdChar((u8)*zSql) ){ - /* Keywords and unquoted identifiers */ - int nId; - for(nId=1; IdChar(zSql[nId]); nId++){} -#ifdef SQLITE_OMIT_TRIGGER - token = tkOTHER; -#else - switch( *zSql ){ - case 'c': case 'C': { - if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){ - token = tkCREATE; - }else{ - token = tkOTHER; - } - break; - } - case 't': case 'T': { - if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){ - token = tkTRIGGER; - }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){ - token = tkTEMP; - }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){ - token = tkTEMP; - }else{ - token = tkOTHER; - } - break; - } - case 'e': case 'E': { - if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){ - token = tkEND; - }else -#ifndef SQLITE_OMIT_EXPLAIN - if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){ - token = tkEXPLAIN; - }else -#endif - { - token = tkOTHER; - } - break; - } - default: { - token = tkOTHER; - break; - } - } -#endif /* SQLITE_OMIT_TRIGGER */ - zSql += nId-1; - }else{ - /* Operators and special symbols */ - token = tkOTHER; + } + }else + if( pMWin->eEnd==TK_PRECEDING ){ + int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); + windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); + if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + if( !bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + }else{ + int addr = 0; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eEnd!=TK_UNBOUNDED ){ + if( pMWin->eFrmType==TK_RANGE ){ + int lbl = 0; + addr = sqlite3VdbeCurrentAddr(v); + if( regEnd ){ + lbl = sqlite3VdbeMakeLabel(pParse); + windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); + } + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + if( regEnd ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); + sqlite3VdbeResolveLabel(v, lbl); } - break; + }else{ + if( regEnd ){ + addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1); + VdbeCoverage(v); + } + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + if( regEnd ) sqlite3VdbeJumpHere(v, addr); } } - state = trans[state][token]; - zSql++; } - return state==1; -} -#ifndef SQLITE_OMIT_UTF16 -/* -** This routine is the same as the sqlite3_complete() routine described -** above, except that the parameter is required to be UTF-16 encoded, not -** UTF-8. -*/ -SQLITE_API int sqlite3_complete16(const void *zSql){ - sqlite3_value *pVal; - char const *zSql8; - int rc; + /* End of the main input loop */ + sqlite3VdbeResolveLabel(v, lblWhereEnd); + sqlite3WhereEnd(pWInfo); -#ifndef SQLITE_OMIT_AUTOINIT - rc = sqlite3_initialize(); - if( rc ) return rc; -#endif - pVal = sqlite3ValueNew(0); - sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); - zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); - if( zSql8 ){ - rc = sqlite3_complete(zSql8); - }else{ - rc = SQLITE_NOMEM_BKPT; + /* Fall through */ + if( pMWin->pPartition ){ + addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart); + sqlite3VdbeJumpHere(v, addrGosubFlush); + } + + s.regRowid = 0; + addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite); + VdbeCoverage(v); + if( pMWin->eEnd==TK_PRECEDING ){ + int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); + windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); + if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + }else if( pMWin->eStart==TK_FOLLOWING ){ + int addrStart; + int addrBreak1; + int addrBreak2; + int addrBreak3; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eFrmType==TK_RANGE ){ + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + }else + if( pMWin->eEnd==TK_UNBOUNDED ){ + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regStart, 1); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, 0, 1); + }else{ + assert( pMWin->eEnd==TK_FOLLOWING ); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 1); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak2); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak3 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak1); + sqlite3VdbeJumpHere(v, addrBreak3); + }else{ + int addrBreak; + int addrStart; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak); + } + sqlite3VdbeJumpHere(v, addrEmpty); + + sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); + if( pMWin->pPartition ){ + if( pMWin->regStartRowid ){ + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); + } + sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); } - sqlite3ValueFree(pVal); - return rc & 0xff; } -#endif /* SQLITE_OMIT_UTF16 */ -#endif /* SQLITE_OMIT_COMPLETE */ -/************** End of complete.c ********************************************/ -/************** Begin file main.c ********************************************/ +#endif /* SQLITE_OMIT_WINDOWFUNC */ + +/************** End of window.c **********************************************/ +/************** Begin file parse.c *******************************************/ +/* This file is automatically generated by Lemon from input grammar +** source file "parse.y". */ /* -** 2001 September 15 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -139300,15164 +161360,28994 @@ SQLITE_API int sqlite3_complete16(const void *zSql){ ** May you share freely, never taking more than you give. ** ************************************************************************* -** Main file for the SQLite library. The routines in this file -** implement the programmer interface to the library. Routines in -** other files are for internal use by SQLite and should not be -** accessed by users of the library. +** This file contains SQLite's SQL parser. +** +** The canonical source code to this file ("parse.y") is a Lemon grammar +** file that specifies the input grammar and actions to take while parsing. +** That input file is processed by Lemon to generate a C-language +** implementation of a parser for the given grammer. You might be reading +** this comment as part of the translated C-code. Edits should be made +** to the original parse.y sources. */ + /* #include "sqliteInt.h" */ -#ifdef SQLITE_ENABLE_FTS3 -/************** Include fts3.h in the middle of main.c ***********************/ -/************** Begin file fts3.h ********************************************/ /* -** 2006 Oct 10 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This header file is used by programs that want to link against the -** FTS3 library. All it does is declare the sqlite3Fts3Init() interface. +** Disable all error recovery processing in the parser push-down +** automaton. */ -/* #include "sqlite3.h" */ - -#if 0 -extern "C" { -#endif /* __cplusplus */ - -SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db); - -#if 0 -} /* extern "C" */ -#endif /* __cplusplus */ +#define YYNOERRORRECOVERY 1 -/************** End of fts3.h ************************************************/ -/************** Continuing where we left off in main.c ***********************/ -#endif -#ifdef SQLITE_ENABLE_RTREE -/************** Include rtree.h in the middle of main.c **********************/ -/************** Begin file rtree.h *******************************************/ /* -** 2008 May 26 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This header file is used by programs that want to link against the -** RTREE library. All it does is declare the sqlite3RtreeInit() interface. +** Make yytestcase() the same as testcase() */ -/* #include "sqlite3.h" */ +#define yytestcase(X) testcase(X) -#if 0 -extern "C" { -#endif /* __cplusplus */ +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define YYPARSEFREENEVERNULL 1 -SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); +/* +** In the amalgamation, the parse.c file generated by lemon and the +** tokenize.c file are concatenated. In that case, sqlite3RunParser() +** has access to the the size of the yyParser object and so the parser +** engine can be allocated from stack. In that case, only the +** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked +** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be +** omitted. +*/ +#ifdef SQLITE_AMALGAMATION +# define sqlite3Parser_ENGINEALWAYSONSTACK 1 +#endif -#if 0 -} /* extern "C" */ -#endif /* __cplusplus */ +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define YYMALLOCARGTYPE u64 -/************** End of rtree.h ***********************************************/ -/************** Continuing where we left off in main.c ***********************/ -#endif -#ifdef SQLITE_ENABLE_ICU -/************** Include sqliteicu.h in the middle of main.c ******************/ -/************** Begin file sqliteicu.h ***************************************/ /* -** 2008 May 26 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** An instance of the following structure describes the event of a +** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, +** TK_DELETE, or TK_INSTEAD. If the event is of the form ** -****************************************************************************** +** UPDATE ON (a,b,c) ** -** This header file is used by programs that want to link against the -** ICU extension. All it does is declare the sqlite3IcuInit() interface. +** Then the "b" IdList records the list "a,b,c". */ -/* #include "sqlite3.h" */ +struct TrigEvent { int a; IdList * b; }; -#if 0 -extern "C" { -#endif /* __cplusplus */ +struct FrameBound { int eType; Expr *pExpr; }; -SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); +/* +** Disable lookaside memory allocation for objects that might be +** shared across database connections. +*/ +static void disableLookaside(Parse *pParse){ + sqlite3 *db = pParse->db; + pParse->disableLookaside++; + DisableLookaside; +} -#if 0 -} /* extern "C" */ -#endif /* __cplusplus */ +#if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \ + && defined(SQLITE_UDL_CAPABLE_PARSER) +/* +** Issue an error message if an ORDER BY or LIMIT clause occurs on an +** UPDATE or DELETE statement. +*/ +static void updateDeleteLimitError( + Parse *pParse, + ExprList *pOrderBy, + Expr *pLimit +){ + if( pOrderBy ){ + sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\""); + }else{ + sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\""); + } + sqlite3ExprListDelete(pParse->db, pOrderBy); + sqlite3ExprDelete(pParse->db, pLimit); +} +#endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */ -/************** End of sqliteicu.h *******************************************/ -/************** Continuing where we left off in main.c ***********************/ -#endif -#ifdef SQLITE_ENABLE_JSON1 -SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*); -#endif -#ifdef SQLITE_ENABLE_FTS5 -SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); -#endif + /* + ** For a compound SELECT statement, make sure p->pPrior->pNext==p for + ** all elements in the list. And make sure list length does not exceed + ** SQLITE_LIMIT_COMPOUND_SELECT. + */ + static void parserDoubleLinkSelect(Parse *pParse, Select *p){ + assert( p!=0 ); + if( p->pPrior ){ + Select *pNext = 0, *pLoop = p; + int mxSelect, cnt = 1; + while(1){ + pLoop->pNext = pNext; + pLoop->selFlags |= SF_Compound; + pNext = pLoop; + pLoop = pLoop->pPrior; + if( pLoop==0 ) break; + cnt++; + if( pLoop->pOrderBy || pLoop->pLimit ){ + sqlite3ErrorMsg(pParse,"%s clause should come after %s not before", + pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT", + sqlite3SelectOpName(pNext->op)); + break; + } + } + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect + ){ + sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); + } + } + } -#ifndef SQLITE_AMALGAMATION -/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant -** contains the text of SQLITE_VERSION macro. -*/ -SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; -#endif + /* Attach a With object describing the WITH clause to a Select + ** object describing the query for which the WITH clause is a prefix. + */ + static Select *attachWithToSelect(Parse *pParse, Select *pSelect, With *pWith){ + if( pSelect ){ + pSelect->pWith = pWith; + parserDoubleLinkSelect(pParse, pSelect); + }else{ + sqlite3WithDelete(pParse->db, pWith); + } + return pSelect; + } -/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns -** a pointer to the to the sqlite3_version[] string constant. -*/ -SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; } -/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a -** pointer to a string constant whose value is the same as the -** SQLITE_SOURCE_ID C preprocessor macro. -*/ -SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } + /* Construct a new Expr object from a single token */ + static Expr *tokenExpr(Parse *pParse, int op, Token t){ + Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); + if( p ){ + /* memset(p, 0, sizeof(Expr)); */ + p->op = (u8)op; + p->affExpr = 0; + p->flags = EP_Leaf; + ExprClearVVAProperties(p); + p->iAgg = -1; + p->pLeft = p->pRight = 0; + p->pAggInfo = 0; + memset(&p->x, 0, sizeof(p->x)); + memset(&p->y, 0, sizeof(p->y)); + p->op2 = 0; + p->iTable = 0; + p->iColumn = 0; + p->u.zToken = (char*)&p[1]; + memcpy(p->u.zToken, t.z, t.n); + p->u.zToken[t.n] = 0; + p->w.iOfst = (int)(t.z - pParse->zTail); + if( sqlite3Isquote(p->u.zToken[0]) ){ + sqlite3DequoteExpr(p); + } +#if SQLITE_MAX_EXPR_DEPTH>0 + p->nHeight = 1; +#endif + if( IN_RENAME_OBJECT ){ + return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t); + } + } + return p; + } -/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function -** returns an integer equal to SQLITE_VERSION_NUMBER. -*/ -SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } -/* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns -** zero if and only if SQLite was compiled with mutexing code omitted due to -** the SQLITE_THREADSAFE compile-time option being set to 0. -*/ -SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } + /* A routine to convert a binary TK_IS or TK_ISNOT expression into a + ** unary TK_ISNULL or TK_NOTNULL expression. */ + static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ + sqlite3 *db = pParse->db; + if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){ + pA->op = (u8)op; + sqlite3ExprDelete(db, pA->pRight); + pA->pRight = 0; + } + } -/* -** When compiling the test fixture or with debugging enabled (on Win32), -** this variable being set to non-zero will cause OSTRACE macros to emit -** extra diagnostic information. -*/ -#ifdef SQLITE_HAVE_OS_TRACE -# ifndef SQLITE_DEBUG_OS_TRACE -# define SQLITE_DEBUG_OS_TRACE 0 -# endif - int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; + /* Add a single new term to an ExprList that is used to store a + ** list of identifiers. Report an error if the ID list contains + ** a COLLATE clause or an ASC or DESC keyword, except ignore the + ** error while parsing a legacy schema. + */ + static ExprList *parserAddExprIdListTerm( + Parse *pParse, + ExprList *pPrior, + Token *pIdToken, + int hasCollate, + int sortOrder + ){ + ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); + if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) + && pParse->db->init.busy==0 + ){ + sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", + pIdToken->n, pIdToken->z); + } + sqlite3ExprListSetName(pParse, p, pIdToken, 1); + return p; + } + +#if TK_SPAN>255 +# error too many tokens in the grammar #endif +/**************** End of %include directives **********************************/ +/* These constants specify the various numeric values for terminal symbols. +***************** Begin token definitions *************************************/ +#ifndef TK_SEMI +#define TK_SEMI 1 +#define TK_EXPLAIN 2 +#define TK_QUERY 3 +#define TK_PLAN 4 +#define TK_BEGIN 5 +#define TK_TRANSACTION 6 +#define TK_DEFERRED 7 +#define TK_IMMEDIATE 8 +#define TK_EXCLUSIVE 9 +#define TK_COMMIT 10 +#define TK_END 11 +#define TK_ROLLBACK 12 +#define TK_SAVEPOINT 13 +#define TK_RELEASE 14 +#define TK_TO 15 +#define TK_TABLE 16 +#define TK_CREATE 17 +#define TK_IF 18 +#define TK_NOT 19 +#define TK_EXISTS 20 +#define TK_TEMP 21 +#define TK_LP 22 +#define TK_RP 23 +#define TK_AS 24 +#define TK_COMMA 25 +#define TK_WITHOUT 26 +#define TK_ABORT 27 +#define TK_ACTION 28 +#define TK_AFTER 29 +#define TK_ANALYZE 30 +#define TK_ASC 31 +#define TK_ATTACH 32 +#define TK_BEFORE 33 +#define TK_BY 34 +#define TK_CASCADE 35 +#define TK_CAST 36 +#define TK_CONFLICT 37 +#define TK_DATABASE 38 +#define TK_DESC 39 +#define TK_DETACH 40 +#define TK_EACH 41 +#define TK_FAIL 42 +#define TK_OR 43 +#define TK_AND 44 +#define TK_IS 45 +#define TK_MATCH 46 +#define TK_LIKE_KW 47 +#define TK_BETWEEN 48 +#define TK_IN 49 +#define TK_ISNULL 50 +#define TK_NOTNULL 51 +#define TK_NE 52 +#define TK_EQ 53 +#define TK_GT 54 +#define TK_LE 55 +#define TK_LT 56 +#define TK_GE 57 +#define TK_ESCAPE 58 +#define TK_ID 59 +#define TK_COLUMNKW 60 +#define TK_DO 61 +#define TK_FOR 62 +#define TK_IGNORE 63 +#define TK_INITIALLY 64 +#define TK_INSTEAD 65 +#define TK_NO 66 +#define TK_KEY 67 +#define TK_OF 68 +#define TK_OFFSET 69 +#define TK_PRAGMA 70 +#define TK_RAISE 71 +#define TK_RECURSIVE 72 +#define TK_REPLACE 73 +#define TK_RESTRICT 74 +#define TK_ROW 75 +#define TK_ROWS 76 +#define TK_TRIGGER 77 +#define TK_VACUUM 78 +#define TK_VIEW 79 +#define TK_VIRTUAL 80 +#define TK_WITH 81 +#define TK_NULLS 82 +#define TK_FIRST 83 +#define TK_LAST 84 +#define TK_CURRENT 85 +#define TK_FOLLOWING 86 +#define TK_PARTITION 87 +#define TK_PRECEDING 88 +#define TK_RANGE 89 +#define TK_UNBOUNDED 90 +#define TK_EXCLUDE 91 +#define TK_GROUPS 92 +#define TK_OTHERS 93 +#define TK_TIES 94 +#define TK_GENERATED 95 +#define TK_ALWAYS 96 +#define TK_MATERIALIZED 97 +#define TK_REINDEX 98 +#define TK_RENAME 99 +#define TK_CTIME_KW 100 +#define TK_ANY 101 +#define TK_BITAND 102 +#define TK_BITOR 103 +#define TK_LSHIFT 104 +#define TK_RSHIFT 105 +#define TK_PLUS 106 +#define TK_MINUS 107 +#define TK_STAR 108 +#define TK_SLASH 109 +#define TK_REM 110 +#define TK_CONCAT 111 +#define TK_PTR 112 +#define TK_COLLATE 113 +#define TK_BITNOT 114 +#define TK_ON 115 +#define TK_INDEXED 116 +#define TK_STRING 117 +#define TK_JOIN_KW 118 +#define TK_CONSTRAINT 119 +#define TK_DEFAULT 120 +#define TK_NULL 121 +#define TK_PRIMARY 122 +#define TK_UNIQUE 123 +#define TK_CHECK 124 +#define TK_REFERENCES 125 +#define TK_AUTOINCR 126 +#define TK_INSERT 127 +#define TK_DELETE 128 +#define TK_UPDATE 129 +#define TK_SET 130 +#define TK_DEFERRABLE 131 +#define TK_FOREIGN 132 +#define TK_DROP 133 +#define TK_UNION 134 +#define TK_ALL 135 +#define TK_EXCEPT 136 +#define TK_INTERSECT 137 +#define TK_SELECT 138 +#define TK_VALUES 139 +#define TK_DISTINCT 140 +#define TK_DOT 141 +#define TK_FROM 142 +#define TK_JOIN 143 +#define TK_USING 144 +#define TK_ORDER 145 +#define TK_GROUP 146 +#define TK_HAVING 147 +#define TK_LIMIT 148 +#define TK_WHERE 149 +#define TK_RETURNING 150 +#define TK_INTO 151 +#define TK_NOTHING 152 +#define TK_FLOAT 153 +#define TK_BLOB 154 +#define TK_INTEGER 155 +#define TK_VARIABLE 156 +#define TK_CASE 157 +#define TK_WHEN 158 +#define TK_THEN 159 +#define TK_ELSE 160 +#define TK_INDEX 161 +#define TK_ALTER 162 +#define TK_ADD 163 +#define TK_WINDOW 164 +#define TK_OVER 165 +#define TK_FILTER 166 +#define TK_COLUMN 167 +#define TK_AGG_FUNCTION 168 +#define TK_AGG_COLUMN 169 +#define TK_TRUEFALSE 170 +#define TK_ISNOT 171 +#define TK_FUNCTION 172 +#define TK_UMINUS 173 +#define TK_UPLUS 174 +#define TK_TRUTH 175 +#define TK_REGISTER 176 +#define TK_VECTOR 177 +#define TK_SELECT_COLUMN 178 +#define TK_IF_NULL_ROW 179 +#define TK_ASTERISK 180 +#define TK_SPAN 181 +#define TK_ERROR 182 +#define TK_SPACE 183 +#define TK_ILLEGAL 184 +#endif +/**************** End token definitions ***************************************/ -#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) -/* -** If the following function pointer is not NULL and if -** SQLITE_ENABLE_IOTRACE is enabled, then messages describing -** I/O active are written using this function. These messages -** are intended for debugging activity only. +/* The next sections is a series of control #defines. +** various aspects of the generated parser. +** YYCODETYPE is the data type used to store the integer codes +** that represent terminal and non-terminal symbols. +** "unsigned char" is used if there are fewer than +** 256 symbols. Larger types otherwise. +** YYNOCODE is a number of type YYCODETYPE that is not used for +** any terminal or nonterminal symbol. +** YYFALLBACK If defined, this indicates that one or more tokens +** (also known as: "terminal symbols") have fall-back +** values which should be used if the original symbol +** would not parse. This permits keywords to sometimes +** be used as identifiers, for example. +** YYACTIONTYPE is the data type used for "action codes" - numbers +** that indicate what to do in response to the next +** token. +** sqlite3ParserTOKENTYPE is the data type used for minor type for terminal +** symbols. Background: A "minor type" is a semantic +** value associated with a terminal or non-terminal +** symbols. For example, for an "ID" terminal symbol, +** the minor type might be the name of the identifier. +** Each non-terminal can have a different minor type. +** Terminal symbols all have the same minor type, though. +** This macros defines the minor type for terminal +** symbols. +** YYMINORTYPE is the data type used for all minor types. +** This is typically a union of many types, one of +** which is sqlite3ParserTOKENTYPE. The entry in the union +** for terminal symbols is called "yy0". +** YYSTACKDEPTH is the maximum depth of the parser's stack. If +** zero the stack is dynamically sized using realloc() +** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument +** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument +** sqlite3ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter +** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser +** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser +** sqlite3ParserCTX_* As sqlite3ParserARG_ except for %extra_context +** YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YYNTOKEN Number of terminal symbols +** YY_MAX_SHIFT Maximum value for shift actions +** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions +** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions +** YY_ERROR_ACTION The yy_action[] code for syntax error +** YY_ACCEPT_ACTION The yy_action[] code for accept +** YY_NO_ACTION The yy_action[] code for no-op +** YY_MIN_REDUCE Minimum value for reduce actions +** YY_MAX_REDUCE Maximum value for reduce actions */ -SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0; +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/************* Begin control #defines *****************************************/ +#define YYCODETYPE unsigned short int +#define YYNOCODE 319 +#define YYACTIONTYPE unsigned short int +#define YYWILDCARD 101 +#define sqlite3ParserTOKENTYPE Token +typedef union { + int yyinit; + sqlite3ParserTOKENTYPE yy0; + TriggerStep* yy33; + Window* yy41; + Select* yy47; + SrcList* yy131; + struct TrigEvent yy180; + struct {int value; int mask;} yy231; + IdList* yy254; + u32 yy285; + ExprList* yy322; + Cte* yy385; + int yy394; + Upsert* yy444; + u8 yy516; + With* yy521; + const char* yy522; + Expr* yy528; + struct FrameBound yy595; +} YYMINORTYPE; +#ifndef YYSTACKDEPTH +#define YYSTACKDEPTH 100 #endif +#define sqlite3ParserARG_SDECL +#define sqlite3ParserARG_PDECL +#define sqlite3ParserARG_PARAM +#define sqlite3ParserARG_FETCH +#define sqlite3ParserARG_STORE +#define sqlite3ParserCTX_SDECL Parse *pParse; +#define sqlite3ParserCTX_PDECL ,Parse *pParse +#define sqlite3ParserCTX_PARAM ,pParse +#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; +#define sqlite3ParserCTX_STORE yypParser->pParse=pParse; +#define YYFALLBACK 1 +#define YYNSTATE 574 +#define YYNRULE 402 +#define YYNRULE_WITH_ACTION 340 +#define YYNTOKEN 185 +#define YY_MAX_SHIFT 573 +#define YY_MIN_SHIFTREDUCE 831 +#define YY_MAX_SHIFTREDUCE 1232 +#define YY_ERROR_ACTION 1233 +#define YY_ACCEPT_ACTION 1234 +#define YY_NO_ACTION 1235 +#define YY_MIN_REDUCE 1236 +#define YY_MAX_REDUCE 1637 +/************* End control #defines *******************************************/ +#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) -/* -** If the following global variable points to a string which is the -** name of a directory, then that directory will be used to store -** temporary files. +/* Define the yytestcase() macro to be a no-op if is not already defined +** otherwise. ** -** See also the "PRAGMA temp_store_directory" SQL command. +** Applications can choose to define yytestcase() in the %include section +** to a macro that can assist in verifying code coverage. For production +** code the yytestcase() macro should be turned off. But it is useful +** for testing. */ -SQLITE_API char *sqlite3_temp_directory = 0; +#ifndef yytestcase +# define yytestcase(X) +#endif -/* -** If the following global variable points to a string which is the -** name of a directory, then that directory will be used to store -** all database files specified with a relative pathname. + +/* Next are the tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. ** -** See also the "PRAGMA data_store_directory" SQL command. -*/ -SQLITE_API char *sqlite3_data_directory = 0; +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead +** token onto the stack and goto state N. +** +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. +** +** N == YY_ERROR_ACTION A syntax error has occurred. +** +** N == YY_ACCEPT_ACTION The parser accepts its input. +** +** N == YY_NO_ACTION No such action. Denotes unused +** slots in the yy_action[] table. +** +** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE +** and YY_MAX_REDUCE +** +** The action table is constructed as a single large table named yy_action[]. +** Given state S and lookahead X, the action is computed as either: +** +** (A) N = yy_action[ yy_shift_ofst[S] + X ] +** (B) N = yy_default[S] +** +** The (A) formula is preferred. The B formula is used instead if +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X. +** +** The formulas above are for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the yy_reduce_ofst[] array is used in place of +** the yy_shift_ofst[] array. +** +** The following are the tables generated in this section: +** +** yy_action[] A single table containing all actions. +** yy_lookahead[] A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** yy_shift_ofst[] For each state, the offset into yy_action for +** shifting terminals. +** yy_reduce_ofst[] For each state, the offset into yy_action for +** shifting non-terminals after a reduce. +** yy_default[] Default action for each state. +** +*********** Begin parsing tables **********************************************/ +#define YY_ACTTAB_COUNT (2070) +static const YYACTIONTYPE yy_action[] = { + /* 0 */ 566, 1307, 566, 1286, 201, 201, 566, 116, 112, 222, + /* 10 */ 566, 1307, 377, 566, 116, 112, 222, 397, 408, 409, + /* 20 */ 1260, 378, 1269, 41, 41, 41, 41, 1412, 1517, 71, + /* 30 */ 71, 967, 1258, 41, 41, 491, 71, 71, 272, 968, + /* 40 */ 298, 476, 298, 123, 124, 114, 1210, 1210, 1044, 1047, + /* 50 */ 1036, 1036, 121, 121, 122, 122, 122, 122, 543, 409, + /* 60 */ 1234, 1, 1, 573, 2, 1238, 548, 116, 112, 222, + /* 70 */ 309, 480, 142, 548, 1272, 524, 116, 112, 222, 1320, + /* 80 */ 417, 523, 547, 123, 124, 114, 1210, 1210, 1044, 1047, + /* 90 */ 1036, 1036, 121, 121, 122, 122, 122, 122, 424, 116, + /* 100 */ 112, 222, 120, 120, 120, 120, 119, 119, 118, 118, + /* 110 */ 118, 117, 113, 444, 277, 277, 277, 277, 560, 560, + /* 120 */ 560, 1558, 376, 1560, 1186, 375, 1157, 563, 1157, 563, + /* 130 */ 409, 1558, 537, 252, 219, 1553, 99, 141, 449, 6, + /* 140 */ 365, 233, 120, 120, 120, 120, 119, 119, 118, 118, + /* 150 */ 118, 117, 113, 444, 123, 124, 114, 1210, 1210, 1044, + /* 160 */ 1047, 1036, 1036, 121, 121, 122, 122, 122, 122, 138, + /* 170 */ 289, 1186, 1546, 448, 118, 118, 118, 117, 113, 444, + /* 180 */ 125, 1186, 1187, 1188, 144, 465, 334, 566, 150, 127, + /* 190 */ 444, 122, 122, 122, 122, 115, 120, 120, 120, 120, + /* 200 */ 119, 119, 118, 118, 118, 117, 113, 444, 454, 419, + /* 210 */ 13, 13, 215, 120, 120, 120, 120, 119, 119, 118, + /* 220 */ 118, 118, 117, 113, 444, 422, 308, 557, 1186, 1187, + /* 230 */ 1188, 441, 440, 409, 1271, 122, 122, 122, 122, 120, + /* 240 */ 120, 120, 120, 119, 119, 118, 118, 118, 117, 113, + /* 250 */ 444, 1543, 98, 1033, 1033, 1045, 1048, 123, 124, 114, + /* 260 */ 1210, 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, + /* 270 */ 122, 122, 566, 406, 405, 1186, 566, 409, 1217, 319, + /* 280 */ 1217, 80, 81, 120, 120, 120, 120, 119, 119, 118, + /* 290 */ 118, 118, 117, 113, 444, 70, 70, 1186, 1604, 71, + /* 300 */ 71, 123, 124, 114, 1210, 1210, 1044, 1047, 1036, 1036, + /* 310 */ 121, 121, 122, 122, 122, 122, 120, 120, 120, 120, + /* 320 */ 119, 119, 118, 118, 118, 117, 113, 444, 1037, 210, + /* 330 */ 1186, 365, 1186, 1187, 1188, 245, 548, 399, 504, 501, + /* 340 */ 500, 108, 558, 138, 4, 516, 933, 433, 499, 217, + /* 350 */ 514, 522, 352, 879, 1186, 1187, 1188, 383, 561, 566, + /* 360 */ 120, 120, 120, 120, 119, 119, 118, 118, 118, 117, + /* 370 */ 113, 444, 277, 277, 16, 16, 1598, 441, 440, 153, + /* 380 */ 409, 445, 13, 13, 1279, 563, 1214, 1186, 1187, 1188, + /* 390 */ 1003, 1216, 264, 555, 1574, 186, 566, 427, 138, 1215, + /* 400 */ 308, 557, 472, 138, 123, 124, 114, 1210, 1210, 1044, + /* 410 */ 1047, 1036, 1036, 121, 121, 122, 122, 122, 122, 55, + /* 420 */ 55, 413, 1023, 507, 1217, 1186, 1217, 474, 106, 106, + /* 430 */ 1312, 1312, 1186, 171, 566, 384, 107, 380, 445, 568, + /* 440 */ 567, 430, 1543, 1013, 332, 549, 565, 263, 280, 360, + /* 450 */ 510, 355, 509, 250, 491, 308, 557, 71, 71, 351, + /* 460 */ 308, 557, 374, 120, 120, 120, 120, 119, 119, 118, + /* 470 */ 118, 118, 117, 113, 444, 1013, 1013, 1015, 1016, 27, + /* 480 */ 277, 277, 1186, 1187, 1188, 1152, 566, 528, 409, 1186, + /* 490 */ 1187, 1188, 348, 563, 548, 1260, 533, 517, 1152, 1516, + /* 500 */ 317, 1152, 285, 550, 485, 569, 566, 569, 482, 51, + /* 510 */ 51, 207, 123, 124, 114, 1210, 1210, 1044, 1047, 1036, + /* 520 */ 1036, 121, 121, 122, 122, 122, 122, 171, 1412, 13, + /* 530 */ 13, 409, 277, 277, 1186, 505, 119, 119, 118, 118, + /* 540 */ 118, 117, 113, 444, 429, 563, 518, 220, 515, 1552, + /* 550 */ 365, 546, 1186, 6, 532, 123, 124, 114, 1210, 1210, + /* 560 */ 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, 122, + /* 570 */ 145, 120, 120, 120, 120, 119, 119, 118, 118, 118, + /* 580 */ 117, 113, 444, 245, 566, 474, 504, 501, 500, 566, + /* 590 */ 1481, 1186, 1187, 1188, 1310, 1310, 499, 1186, 149, 425, + /* 600 */ 1186, 480, 409, 274, 365, 952, 872, 56, 56, 1186, + /* 610 */ 1187, 1188, 71, 71, 120, 120, 120, 120, 119, 119, + /* 620 */ 118, 118, 118, 117, 113, 444, 123, 124, 114, 1210, + /* 630 */ 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, + /* 640 */ 122, 409, 541, 1552, 83, 865, 98, 6, 928, 529, + /* 650 */ 848, 543, 151, 927, 1186, 1187, 1188, 1186, 1187, 1188, + /* 660 */ 290, 1543, 187, 1633, 395, 123, 124, 114, 1210, 1210, + /* 670 */ 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, 122, + /* 680 */ 566, 954, 566, 453, 953, 120, 120, 120, 120, 119, + /* 690 */ 119, 118, 118, 118, 117, 113, 444, 1152, 221, 1186, + /* 700 */ 331, 453, 452, 13, 13, 13, 13, 1003, 365, 463, + /* 710 */ 1152, 193, 409, 1152, 382, 1543, 1170, 32, 297, 474, + /* 720 */ 195, 1527, 5, 952, 120, 120, 120, 120, 119, 119, + /* 730 */ 118, 118, 118, 117, 113, 444, 123, 124, 114, 1210, + /* 740 */ 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, + /* 750 */ 122, 409, 1067, 419, 1186, 1024, 1186, 1187, 1188, 1186, + /* 760 */ 419, 332, 460, 320, 544, 1545, 442, 442, 442, 566, + /* 770 */ 3, 117, 113, 444, 453, 123, 124, 114, 1210, 1210, + /* 780 */ 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, 122, + /* 790 */ 1473, 566, 15, 15, 293, 120, 120, 120, 120, 119, + /* 800 */ 119, 118, 118, 118, 117, 113, 444, 1186, 566, 1486, + /* 810 */ 1412, 1186, 1187, 1188, 13, 13, 1186, 1187, 1188, 1544, + /* 820 */ 271, 271, 409, 286, 308, 557, 1008, 1486, 1488, 196, + /* 830 */ 288, 71, 71, 563, 120, 120, 120, 120, 119, 119, + /* 840 */ 118, 118, 118, 117, 113, 444, 123, 124, 114, 1210, + /* 850 */ 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, + /* 860 */ 122, 409, 201, 1087, 1186, 1187, 1188, 1324, 304, 1529, + /* 870 */ 388, 278, 278, 450, 564, 402, 922, 922, 566, 563, + /* 880 */ 566, 426, 491, 480, 563, 123, 124, 114, 1210, 1210, + /* 890 */ 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, 122, + /* 900 */ 1486, 71, 71, 13, 13, 120, 120, 120, 120, 119, + /* 910 */ 119, 118, 118, 118, 117, 113, 444, 566, 545, 566, + /* 920 */ 1577, 573, 2, 1238, 1092, 1092, 488, 1480, 309, 1525, + /* 930 */ 142, 324, 409, 836, 837, 838, 312, 1320, 305, 363, + /* 940 */ 43, 43, 57, 57, 120, 120, 120, 120, 119, 119, + /* 950 */ 118, 118, 118, 117, 113, 444, 123, 124, 114, 1210, + /* 960 */ 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, + /* 970 */ 122, 12, 277, 277, 566, 1152, 409, 572, 428, 1238, + /* 980 */ 465, 334, 296, 474, 309, 563, 142, 249, 1152, 308, + /* 990 */ 557, 1152, 321, 1320, 323, 491, 455, 71, 71, 233, + /* 1000 */ 283, 101, 114, 1210, 1210, 1044, 1047, 1036, 1036, 121, + /* 1010 */ 121, 122, 122, 122, 122, 120, 120, 120, 120, 119, + /* 1020 */ 119, 118, 118, 118, 117, 113, 444, 1108, 277, 277, + /* 1030 */ 1412, 448, 394, 1230, 439, 277, 277, 248, 247, 246, + /* 1040 */ 1319, 563, 1109, 313, 198, 294, 491, 1318, 563, 464, + /* 1050 */ 566, 1427, 394, 1130, 1023, 233, 414, 1110, 295, 120, + /* 1060 */ 120, 120, 120, 119, 119, 118, 118, 118, 117, 113, + /* 1070 */ 444, 1014, 104, 71, 71, 1013, 322, 496, 908, 566, + /* 1080 */ 277, 277, 277, 277, 1108, 1261, 415, 448, 909, 361, + /* 1090 */ 1571, 1315, 409, 563, 952, 563, 9, 202, 255, 1109, + /* 1100 */ 316, 487, 44, 44, 249, 559, 415, 1013, 1013, 1015, + /* 1110 */ 443, 1231, 409, 1603, 1110, 897, 123, 124, 114, 1210, + /* 1120 */ 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, + /* 1130 */ 122, 1231, 409, 1207, 215, 554, 123, 124, 114, 1210, + /* 1140 */ 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, + /* 1150 */ 122, 1131, 1631, 470, 1631, 255, 123, 111, 114, 1210, + /* 1160 */ 1210, 1044, 1047, 1036, 1036, 121, 121, 122, 122, 122, + /* 1170 */ 122, 1131, 1632, 414, 1632, 120, 120, 120, 120, 119, + /* 1180 */ 119, 118, 118, 118, 117, 113, 444, 221, 209, 351, + /* 1190 */ 1207, 1207, 147, 1426, 491, 120, 120, 120, 120, 119, + /* 1200 */ 119, 118, 118, 118, 117, 113, 444, 1256, 539, 519, + /* 1210 */ 888, 551, 952, 12, 566, 120, 120, 120, 120, 119, + /* 1220 */ 119, 118, 118, 118, 117, 113, 444, 538, 566, 860, + /* 1230 */ 1129, 361, 1571, 346, 1356, 409, 1163, 58, 58, 339, + /* 1240 */ 1355, 508, 277, 277, 277, 277, 277, 277, 1207, 889, + /* 1250 */ 1129, 59, 59, 459, 363, 563, 566, 563, 96, 563, + /* 1260 */ 124, 114, 1210, 1210, 1044, 1047, 1036, 1036, 121, 121, + /* 1270 */ 122, 122, 122, 122, 566, 1412, 566, 281, 1186, 60, + /* 1280 */ 60, 110, 392, 392, 391, 266, 389, 860, 1163, 845, + /* 1290 */ 566, 481, 566, 436, 341, 1152, 344, 61, 61, 62, + /* 1300 */ 62, 967, 227, 1550, 315, 431, 540, 6, 1152, 968, + /* 1310 */ 566, 1152, 314, 45, 45, 46, 46, 512, 120, 120, + /* 1320 */ 120, 120, 119, 119, 118, 118, 118, 117, 113, 444, + /* 1330 */ 416, 173, 1532, 47, 47, 1186, 1187, 1188, 108, 558, + /* 1340 */ 325, 4, 229, 1551, 928, 566, 437, 6, 566, 927, + /* 1350 */ 164, 566, 1290, 137, 1190, 561, 566, 1549, 566, 1089, + /* 1360 */ 566, 6, 566, 1089, 531, 566, 868, 8, 49, 49, + /* 1370 */ 228, 50, 50, 566, 63, 63, 566, 457, 445, 64, + /* 1380 */ 64, 65, 65, 14, 14, 66, 66, 407, 129, 129, + /* 1390 */ 555, 566, 458, 566, 1505, 486, 67, 67, 566, 52, + /* 1400 */ 52, 546, 407, 467, 535, 410, 226, 1023, 566, 534, + /* 1410 */ 308, 557, 1190, 407, 68, 68, 69, 69, 566, 1023, + /* 1420 */ 566, 53, 53, 868, 1014, 106, 106, 525, 1013, 566, + /* 1430 */ 1504, 159, 159, 107, 451, 445, 568, 567, 471, 307, + /* 1440 */ 1013, 160, 160, 76, 76, 566, 1548, 466, 407, 407, + /* 1450 */ 6, 1225, 54, 54, 478, 276, 219, 566, 887, 886, + /* 1460 */ 1013, 1013, 1015, 84, 206, 1206, 230, 282, 72, 72, + /* 1470 */ 329, 483, 1013, 1013, 1015, 1016, 27, 1576, 1174, 447, + /* 1480 */ 130, 130, 281, 148, 105, 38, 103, 392, 392, 391, + /* 1490 */ 266, 389, 566, 1126, 845, 396, 566, 108, 558, 566, + /* 1500 */ 4, 311, 566, 30, 17, 566, 279, 227, 566, 315, + /* 1510 */ 108, 558, 468, 4, 561, 73, 73, 314, 566, 157, + /* 1520 */ 157, 566, 131, 131, 526, 132, 132, 561, 128, 128, + /* 1530 */ 566, 158, 158, 566, 31, 291, 566, 445, 330, 521, + /* 1540 */ 98, 152, 152, 420, 136, 136, 1005, 229, 254, 555, + /* 1550 */ 445, 479, 336, 135, 135, 164, 133, 133, 137, 134, + /* 1560 */ 134, 875, 555, 535, 566, 473, 566, 254, 536, 475, + /* 1570 */ 335, 254, 98, 894, 895, 228, 535, 566, 1023, 566, + /* 1580 */ 1074, 534, 210, 232, 106, 106, 1352, 75, 75, 77, + /* 1590 */ 77, 1023, 107, 340, 445, 568, 567, 106, 106, 1013, + /* 1600 */ 74, 74, 42, 42, 566, 107, 343, 445, 568, 567, + /* 1610 */ 410, 497, 1013, 251, 359, 308, 557, 1135, 349, 875, + /* 1620 */ 98, 1070, 345, 251, 358, 1591, 347, 48, 48, 1017, + /* 1630 */ 1303, 1013, 1013, 1015, 1016, 27, 1289, 1287, 1074, 451, + /* 1640 */ 961, 925, 254, 110, 1013, 1013, 1015, 1016, 27, 1174, + /* 1650 */ 447, 970, 971, 281, 108, 558, 1288, 4, 392, 392, + /* 1660 */ 391, 266, 389, 1343, 1086, 845, 1086, 1085, 858, 1085, + /* 1670 */ 146, 561, 926, 354, 110, 303, 364, 553, 227, 1364, + /* 1680 */ 315, 108, 558, 1411, 4, 1339, 492, 1017, 314, 1350, + /* 1690 */ 1565, 552, 1417, 1268, 445, 204, 1259, 1247, 561, 1246, + /* 1700 */ 1248, 1584, 269, 1336, 367, 369, 555, 371, 11, 212, + /* 1710 */ 393, 225, 1393, 284, 1398, 456, 287, 327, 229, 328, + /* 1720 */ 292, 445, 1386, 216, 333, 1403, 164, 477, 373, 137, + /* 1730 */ 1402, 400, 502, 555, 1286, 1023, 357, 1477, 199, 1587, + /* 1740 */ 211, 106, 106, 932, 1476, 1225, 228, 556, 175, 107, + /* 1750 */ 200, 445, 568, 567, 258, 387, 1013, 1524, 1522, 223, + /* 1760 */ 1222, 418, 1023, 83, 208, 79, 82, 184, 106, 106, + /* 1770 */ 1482, 169, 177, 461, 179, 462, 107, 1399, 445, 568, + /* 1780 */ 567, 410, 180, 1013, 495, 181, 308, 557, 1013, 1013, + /* 1790 */ 1015, 1016, 27, 182, 35, 235, 100, 558, 398, 4, + /* 1800 */ 96, 1405, 1404, 36, 484, 469, 1407, 188, 401, 1471, + /* 1810 */ 451, 89, 1493, 561, 239, 1013, 1013, 1015, 1016, 27, + /* 1820 */ 490, 338, 270, 241, 192, 342, 493, 242, 403, 1249, + /* 1830 */ 243, 511, 432, 1297, 1306, 91, 445, 1305, 1304, 879, + /* 1840 */ 217, 434, 435, 1570, 1276, 1602, 520, 1601, 555, 301, + /* 1850 */ 527, 404, 1275, 302, 356, 1274, 1600, 95, 1347, 366, + /* 1860 */ 1296, 362, 1348, 368, 256, 257, 1556, 1555, 438, 1346, + /* 1870 */ 370, 126, 1345, 10, 1371, 546, 381, 1023, 102, 1457, + /* 1880 */ 97, 530, 34, 106, 106, 570, 1180, 372, 265, 1329, + /* 1890 */ 379, 107, 203, 445, 568, 567, 1328, 385, 1013, 1370, + /* 1900 */ 386, 267, 268, 571, 1244, 161, 1239, 162, 1509, 1510, + /* 1910 */ 1508, 143, 1507, 299, 832, 213, 214, 78, 446, 205, + /* 1920 */ 310, 306, 163, 224, 1084, 140, 1082, 318, 165, 176, + /* 1930 */ 1013, 1013, 1015, 1016, 27, 178, 1206, 231, 911, 234, + /* 1940 */ 326, 1098, 183, 421, 166, 167, 411, 185, 85, 423, + /* 1950 */ 412, 86, 174, 87, 168, 88, 1101, 236, 1097, 237, + /* 1960 */ 154, 18, 238, 254, 337, 1219, 489, 1090, 240, 190, + /* 1970 */ 37, 847, 189, 494, 358, 244, 350, 506, 191, 877, + /* 1980 */ 90, 498, 19, 20, 503, 92, 353, 890, 300, 170, + /* 1990 */ 155, 93, 513, 94, 1168, 156, 1050, 1137, 39, 218, + /* 2000 */ 273, 275, 1136, 960, 194, 955, 110, 1154, 1158, 253, + /* 2010 */ 7, 1162, 1156, 21, 22, 1161, 1142, 23, 24, 25, + /* 2020 */ 33, 542, 26, 260, 197, 98, 1065, 1051, 1049, 1053, + /* 2030 */ 1107, 1054, 1106, 259, 28, 40, 562, 1018, 859, 109, + /* 2040 */ 29, 921, 390, 1176, 172, 139, 1175, 1235, 261, 1235, + /* 2050 */ 1235, 1235, 1235, 1235, 1235, 1235, 1235, 262, 1235, 1235, + /* 2060 */ 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1593, 1592, +}; +static const YYCODETYPE yy_lookahead[] = { + /* 0 */ 193, 223, 193, 225, 193, 193, 193, 274, 275, 276, + /* 10 */ 193, 233, 219, 193, 274, 275, 276, 206, 206, 19, + /* 20 */ 193, 219, 216, 216, 217, 216, 217, 193, 295, 216, + /* 30 */ 217, 31, 205, 216, 217, 193, 216, 217, 213, 39, + /* 40 */ 228, 193, 230, 43, 44, 45, 46, 47, 48, 49, + /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 193, 19, + /* 60 */ 185, 186, 187, 188, 189, 190, 253, 274, 275, 276, + /* 70 */ 195, 193, 197, 253, 216, 262, 274, 275, 276, 204, + /* 80 */ 238, 204, 262, 43, 44, 45, 46, 47, 48, 49, + /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 264, 274, + /* 100 */ 275, 276, 102, 103, 104, 105, 106, 107, 108, 109, + /* 110 */ 110, 111, 112, 113, 239, 240, 239, 240, 210, 211, + /* 120 */ 212, 314, 315, 314, 59, 316, 86, 252, 88, 252, + /* 130 */ 19, 314, 315, 256, 257, 309, 25, 72, 296, 313, + /* 140 */ 193, 266, 102, 103, 104, 105, 106, 107, 108, 109, + /* 150 */ 110, 111, 112, 113, 43, 44, 45, 46, 47, 48, + /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 81, + /* 170 */ 292, 59, 307, 298, 108, 109, 110, 111, 112, 113, + /* 180 */ 69, 116, 117, 118, 72, 128, 129, 193, 241, 22, + /* 190 */ 113, 54, 55, 56, 57, 58, 102, 103, 104, 105, + /* 200 */ 106, 107, 108, 109, 110, 111, 112, 113, 120, 193, + /* 210 */ 216, 217, 25, 102, 103, 104, 105, 106, 107, 108, + /* 220 */ 109, 110, 111, 112, 113, 231, 138, 139, 116, 117, + /* 230 */ 118, 106, 107, 19, 216, 54, 55, 56, 57, 102, + /* 240 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 250 */ 113, 304, 25, 46, 47, 48, 49, 43, 44, 45, + /* 260 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 270 */ 56, 57, 193, 106, 107, 59, 193, 19, 153, 263, + /* 280 */ 155, 67, 24, 102, 103, 104, 105, 106, 107, 108, + /* 290 */ 109, 110, 111, 112, 113, 216, 217, 59, 230, 216, + /* 300 */ 217, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 310 */ 52, 53, 54, 55, 56, 57, 102, 103, 104, 105, + /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 121, 142, + /* 330 */ 59, 193, 116, 117, 118, 119, 253, 204, 122, 123, + /* 340 */ 124, 19, 20, 81, 22, 262, 108, 19, 132, 165, + /* 350 */ 166, 193, 24, 126, 116, 117, 118, 278, 36, 193, + /* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 370 */ 112, 113, 239, 240, 216, 217, 215, 106, 107, 241, + /* 380 */ 19, 59, 216, 217, 223, 252, 115, 116, 117, 118, + /* 390 */ 73, 120, 26, 71, 193, 22, 193, 231, 81, 128, + /* 400 */ 138, 139, 269, 81, 43, 44, 45, 46, 47, 48, + /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 216, + /* 420 */ 217, 198, 100, 95, 153, 59, 155, 193, 106, 107, + /* 430 */ 235, 236, 59, 193, 193, 249, 114, 251, 116, 117, + /* 440 */ 118, 113, 304, 121, 127, 204, 193, 119, 120, 121, + /* 450 */ 122, 123, 124, 125, 193, 138, 139, 216, 217, 131, + /* 460 */ 138, 139, 193, 102, 103, 104, 105, 106, 107, 108, + /* 470 */ 109, 110, 111, 112, 113, 153, 154, 155, 156, 157, + /* 480 */ 239, 240, 116, 117, 118, 76, 193, 193, 19, 116, + /* 490 */ 117, 118, 23, 252, 253, 193, 87, 204, 89, 238, + /* 500 */ 193, 92, 268, 262, 281, 203, 193, 205, 285, 216, + /* 510 */ 217, 150, 43, 44, 45, 46, 47, 48, 49, 50, + /* 520 */ 51, 52, 53, 54, 55, 56, 57, 193, 193, 216, + /* 530 */ 217, 19, 239, 240, 59, 23, 106, 107, 108, 109, + /* 540 */ 110, 111, 112, 113, 231, 252, 253, 193, 308, 309, + /* 550 */ 193, 145, 59, 313, 145, 43, 44, 45, 46, 47, + /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 570 */ 164, 102, 103, 104, 105, 106, 107, 108, 109, 110, + /* 580 */ 111, 112, 113, 119, 193, 193, 122, 123, 124, 193, + /* 590 */ 283, 116, 117, 118, 235, 236, 132, 59, 241, 264, + /* 600 */ 59, 193, 19, 23, 193, 25, 23, 216, 217, 116, + /* 610 */ 117, 118, 216, 217, 102, 103, 104, 105, 106, 107, + /* 620 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, + /* 630 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 640 */ 57, 19, 308, 309, 151, 23, 25, 313, 135, 253, + /* 650 */ 21, 193, 241, 140, 116, 117, 118, 116, 117, 118, + /* 660 */ 268, 304, 22, 301, 302, 43, 44, 45, 46, 47, + /* 670 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 680 */ 193, 143, 193, 193, 143, 102, 103, 104, 105, 106, + /* 690 */ 107, 108, 109, 110, 111, 112, 113, 76, 118, 59, + /* 700 */ 292, 211, 212, 216, 217, 216, 217, 73, 193, 80, + /* 710 */ 89, 25, 19, 92, 193, 304, 23, 22, 231, 193, + /* 720 */ 231, 193, 22, 143, 102, 103, 104, 105, 106, 107, + /* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, + /* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 750 */ 57, 19, 123, 193, 59, 23, 116, 117, 118, 59, + /* 760 */ 193, 127, 128, 129, 306, 307, 210, 211, 212, 193, + /* 770 */ 22, 111, 112, 113, 284, 43, 44, 45, 46, 47, + /* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 790 */ 161, 193, 216, 217, 268, 102, 103, 104, 105, 106, + /* 800 */ 107, 108, 109, 110, 111, 112, 113, 59, 193, 193, + /* 810 */ 193, 116, 117, 118, 216, 217, 116, 117, 118, 304, + /* 820 */ 239, 240, 19, 263, 138, 139, 23, 211, 212, 231, + /* 830 */ 263, 216, 217, 252, 102, 103, 104, 105, 106, 107, + /* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, + /* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 860 */ 57, 19, 193, 11, 116, 117, 118, 240, 253, 193, + /* 870 */ 201, 239, 240, 193, 134, 206, 136, 137, 193, 252, + /* 880 */ 193, 264, 193, 193, 252, 43, 44, 45, 46, 47, + /* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 900 */ 284, 216, 217, 216, 217, 102, 103, 104, 105, 106, + /* 910 */ 107, 108, 109, 110, 111, 112, 113, 193, 231, 193, + /* 920 */ 187, 188, 189, 190, 127, 128, 129, 238, 195, 193, + /* 930 */ 197, 16, 19, 7, 8, 9, 193, 204, 253, 193, + /* 940 */ 216, 217, 216, 217, 102, 103, 104, 105, 106, 107, + /* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46, + /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 970 */ 57, 213, 239, 240, 193, 76, 19, 188, 232, 190, + /* 980 */ 128, 129, 292, 193, 195, 252, 197, 46, 89, 138, + /* 990 */ 139, 92, 77, 204, 79, 193, 269, 216, 217, 266, + /* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52, + /* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106, + /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240, + /* 1030 */ 193, 298, 22, 23, 253, 239, 240, 127, 128, 129, + /* 1040 */ 238, 252, 27, 193, 286, 204, 193, 204, 252, 291, + /* 1050 */ 193, 273, 22, 23, 100, 266, 115, 42, 268, 102, + /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1070 */ 113, 117, 159, 216, 217, 121, 161, 19, 63, 193, + /* 1080 */ 239, 240, 239, 240, 12, 208, 209, 298, 73, 311, + /* 1090 */ 312, 238, 19, 252, 25, 252, 22, 24, 24, 27, + /* 1100 */ 193, 264, 216, 217, 46, 208, 209, 153, 154, 155, + /* 1110 */ 253, 101, 19, 23, 42, 25, 43, 44, 45, 46, + /* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1130 */ 57, 101, 19, 59, 25, 63, 43, 44, 45, 46, + /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1150 */ 57, 22, 23, 115, 25, 24, 43, 44, 45, 46, + /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1170 */ 57, 22, 23, 115, 25, 102, 103, 104, 105, 106, + /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 118, 150, 131, + /* 1190 */ 59, 117, 22, 273, 193, 102, 103, 104, 105, 106, + /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 204, 66, 204, + /* 1210 */ 35, 204, 143, 213, 193, 102, 103, 104, 105, 106, + /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 85, 193, 59, + /* 1230 */ 101, 311, 312, 16, 193, 19, 94, 216, 217, 238, + /* 1240 */ 193, 66, 239, 240, 239, 240, 239, 240, 117, 74, + /* 1250 */ 101, 216, 217, 193, 193, 252, 193, 252, 149, 252, + /* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 1270 */ 54, 55, 56, 57, 193, 193, 193, 5, 59, 216, + /* 1280 */ 217, 25, 10, 11, 12, 13, 14, 117, 146, 17, + /* 1290 */ 193, 291, 193, 232, 77, 76, 79, 216, 217, 216, + /* 1300 */ 217, 31, 30, 309, 32, 130, 87, 313, 89, 39, + /* 1310 */ 193, 92, 40, 216, 217, 216, 217, 108, 102, 103, + /* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + /* 1330 */ 299, 300, 193, 216, 217, 116, 117, 118, 19, 20, + /* 1340 */ 193, 22, 70, 309, 135, 193, 264, 313, 193, 140, + /* 1350 */ 78, 193, 226, 81, 59, 36, 193, 309, 193, 29, + /* 1360 */ 193, 313, 193, 33, 145, 193, 59, 48, 216, 217, + /* 1370 */ 98, 216, 217, 193, 216, 217, 193, 244, 59, 216, + /* 1380 */ 217, 216, 217, 216, 217, 216, 217, 254, 216, 217, + /* 1390 */ 71, 193, 244, 193, 193, 65, 216, 217, 193, 216, + /* 1400 */ 217, 145, 254, 244, 85, 133, 15, 100, 193, 90, + /* 1410 */ 138, 139, 117, 254, 216, 217, 216, 217, 193, 100, + /* 1420 */ 193, 216, 217, 116, 117, 106, 107, 19, 121, 193, + /* 1430 */ 193, 216, 217, 114, 162, 116, 117, 118, 244, 244, + /* 1440 */ 121, 216, 217, 216, 217, 193, 309, 129, 254, 254, + /* 1450 */ 313, 60, 216, 217, 19, 256, 257, 193, 120, 121, + /* 1460 */ 153, 154, 155, 149, 150, 25, 24, 99, 216, 217, + /* 1470 */ 152, 193, 153, 154, 155, 156, 157, 0, 1, 2, + /* 1480 */ 216, 217, 5, 22, 158, 24, 160, 10, 11, 12, + /* 1490 */ 13, 14, 193, 23, 17, 25, 193, 19, 20, 193, + /* 1500 */ 22, 133, 193, 22, 22, 193, 22, 30, 193, 32, + /* 1510 */ 19, 20, 129, 22, 36, 216, 217, 40, 193, 216, + /* 1520 */ 217, 193, 216, 217, 116, 216, 217, 36, 216, 217, + /* 1530 */ 193, 216, 217, 193, 53, 152, 193, 59, 23, 19, + /* 1540 */ 25, 216, 217, 61, 216, 217, 23, 70, 25, 71, + /* 1550 */ 59, 116, 193, 216, 217, 78, 216, 217, 81, 216, + /* 1560 */ 217, 59, 71, 85, 193, 23, 193, 25, 90, 23, + /* 1570 */ 23, 25, 25, 7, 8, 98, 85, 193, 100, 193, + /* 1580 */ 59, 90, 142, 141, 106, 107, 193, 216, 217, 216, + /* 1590 */ 217, 100, 114, 193, 116, 117, 118, 106, 107, 121, + /* 1600 */ 216, 217, 216, 217, 193, 114, 193, 116, 117, 118, + /* 1610 */ 133, 23, 121, 25, 121, 138, 139, 97, 23, 117, + /* 1620 */ 25, 23, 193, 25, 131, 141, 193, 216, 217, 59, + /* 1630 */ 193, 153, 154, 155, 156, 157, 226, 193, 117, 162, + /* 1640 */ 23, 23, 25, 25, 153, 154, 155, 156, 157, 1, + /* 1650 */ 2, 83, 84, 5, 19, 20, 226, 22, 10, 11, + /* 1660 */ 12, 13, 14, 258, 153, 17, 155, 153, 23, 155, + /* 1670 */ 25, 36, 23, 193, 25, 255, 193, 236, 30, 193, + /* 1680 */ 32, 19, 20, 193, 22, 193, 288, 117, 40, 193, + /* 1690 */ 318, 193, 193, 193, 59, 242, 193, 193, 36, 193, + /* 1700 */ 193, 193, 287, 255, 255, 255, 71, 255, 243, 214, + /* 1710 */ 191, 297, 267, 245, 271, 259, 259, 293, 70, 246, + /* 1720 */ 246, 59, 267, 229, 245, 271, 78, 293, 259, 81, + /* 1730 */ 271, 271, 220, 71, 225, 100, 219, 219, 249, 196, + /* 1740 */ 243, 106, 107, 108, 219, 60, 98, 280, 297, 114, + /* 1750 */ 249, 116, 117, 118, 141, 245, 121, 200, 200, 297, + /* 1760 */ 38, 200, 100, 151, 150, 294, 294, 22, 106, 107, + /* 1770 */ 283, 43, 234, 18, 237, 200, 114, 272, 116, 117, + /* 1780 */ 118, 133, 237, 121, 18, 237, 138, 139, 153, 154, + /* 1790 */ 155, 156, 157, 237, 270, 199, 19, 20, 246, 22, + /* 1800 */ 149, 272, 272, 270, 200, 246, 234, 234, 246, 246, + /* 1810 */ 162, 158, 290, 36, 199, 153, 154, 155, 156, 157, + /* 1820 */ 62, 289, 200, 199, 22, 200, 221, 199, 221, 200, + /* 1830 */ 199, 115, 64, 227, 218, 22, 59, 218, 218, 126, + /* 1840 */ 165, 24, 113, 312, 218, 224, 305, 224, 71, 282, + /* 1850 */ 144, 221, 220, 282, 218, 218, 218, 115, 261, 260, + /* 1860 */ 227, 221, 261, 260, 200, 91, 317, 317, 82, 261, + /* 1870 */ 260, 148, 261, 22, 265, 145, 200, 100, 158, 277, + /* 1880 */ 147, 146, 25, 106, 107, 202, 13, 260, 194, 250, + /* 1890 */ 249, 114, 248, 116, 117, 118, 250, 247, 121, 265, + /* 1900 */ 246, 194, 6, 192, 192, 207, 192, 207, 213, 213, + /* 1910 */ 213, 222, 213, 222, 4, 214, 214, 213, 3, 22, + /* 1920 */ 163, 279, 207, 15, 23, 16, 23, 139, 130, 151, + /* 1930 */ 153, 154, 155, 156, 157, 142, 25, 24, 20, 144, + /* 1940 */ 16, 1, 142, 61, 130, 130, 303, 151, 53, 37, + /* 1950 */ 303, 53, 300, 53, 130, 53, 116, 34, 1, 141, + /* 1960 */ 5, 22, 115, 25, 161, 75, 41, 68, 141, 115, + /* 1970 */ 24, 20, 68, 19, 131, 125, 23, 96, 22, 59, + /* 1980 */ 22, 67, 22, 22, 67, 22, 24, 28, 67, 37, + /* 1990 */ 23, 149, 22, 25, 23, 23, 23, 23, 22, 141, + /* 2000 */ 23, 23, 97, 116, 22, 143, 25, 88, 75, 34, + /* 2010 */ 44, 75, 86, 34, 34, 93, 23, 34, 34, 34, + /* 2020 */ 22, 24, 34, 22, 25, 25, 23, 23, 23, 23, + /* 2030 */ 23, 11, 23, 25, 22, 22, 25, 23, 23, 22, + /* 2040 */ 22, 135, 15, 1, 25, 23, 1, 319, 141, 319, + /* 2050 */ 319, 319, 319, 319, 319, 319, 319, 141, 319, 319, + /* 2060 */ 319, 319, 319, 319, 319, 319, 319, 319, 141, 141, + /* 2070 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2080 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2090 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2130 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2140 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2150 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2160 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2170 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2180 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2190 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2200 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2210 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2220 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2230 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2240 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319, + /* 2250 */ 319, 319, 319, 319, 319, +}; +#define YY_SHIFT_COUNT (573) +#define YY_SHIFT_MIN (0) +#define YY_SHIFT_MAX (2045) +static const unsigned short int yy_shift_ofst[] = { + /* 0 */ 1648, 1477, 1272, 322, 322, 262, 1319, 1478, 1491, 1662, + /* 10 */ 1662, 1662, 317, 0, 0, 214, 1093, 1662, 1662, 1662, + /* 20 */ 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, + /* 30 */ 271, 271, 1219, 1219, 216, 88, 262, 262, 262, 262, + /* 40 */ 262, 40, 111, 258, 361, 469, 512, 583, 622, 693, + /* 50 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093, + /* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, + /* 70 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, 1662, + /* 80 */ 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, + /* 90 */ 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, + /* 100 */ 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, + /* 110 */ 1662, 1662, 1662, 1662, 1777, 1662, 1662, 1662, 1662, 1662, + /* 120 */ 1662, 1662, 1662, 1662, 1662, 1662, 1662, 1662, 137, 181, + /* 130 */ 181, 181, 181, 181, 94, 430, 66, 65, 112, 366, + /* 140 */ 475, 475, 629, 1058, 475, 475, 125, 125, 475, 686, + /* 150 */ 686, 686, 660, 686, 57, 184, 184, 77, 77, 2070, + /* 160 */ 2070, 328, 328, 328, 493, 373, 373, 373, 373, 1015, + /* 170 */ 1015, 409, 366, 1129, 1149, 475, 475, 475, 475, 475, + /* 180 */ 475, 475, 475, 475, 475, 475, 475, 475, 475, 475, + /* 190 */ 475, 475, 475, 475, 475, 621, 621, 475, 852, 899, + /* 200 */ 899, 1295, 1295, 406, 851, 2070, 2070, 2070, 2070, 2070, + /* 210 */ 2070, 2070, 1307, 954, 954, 640, 464, 695, 238, 700, + /* 220 */ 538, 541, 748, 475, 475, 475, 475, 475, 475, 475, + /* 230 */ 475, 475, 475, 634, 475, 475, 475, 475, 475, 475, + /* 240 */ 475, 475, 475, 475, 475, 475, 1175, 1175, 1175, 475, + /* 250 */ 475, 475, 580, 475, 475, 475, 1074, 1142, 475, 475, + /* 260 */ 1072, 475, 475, 475, 475, 475, 475, 475, 475, 797, + /* 270 */ 1330, 740, 1131, 1131, 1131, 1131, 1069, 740, 740, 1209, + /* 280 */ 167, 926, 1391, 1038, 1314, 187, 1408, 1314, 1408, 1435, + /* 290 */ 1109, 1038, 1038, 1109, 1038, 187, 1435, 227, 1090, 941, + /* 300 */ 1270, 1270, 1270, 1408, 1256, 1256, 1326, 1440, 513, 1461, + /* 310 */ 1685, 1685, 1613, 1613, 1722, 1722, 1613, 1612, 1614, 1745, + /* 320 */ 1728, 1755, 1755, 1755, 1755, 1613, 1766, 1651, 1614, 1614, + /* 330 */ 1651, 1745, 1728, 1651, 1728, 1651, 1613, 1766, 1653, 1758, + /* 340 */ 1613, 1766, 1802, 1613, 1766, 1613, 1766, 1802, 1716, 1716, + /* 350 */ 1716, 1768, 1813, 1813, 1802, 1716, 1713, 1716, 1768, 1716, + /* 360 */ 1716, 1675, 1817, 1729, 1729, 1802, 1706, 1742, 1706, 1742, + /* 370 */ 1706, 1742, 1706, 1742, 1613, 1774, 1774, 1786, 1786, 1723, + /* 380 */ 1730, 1851, 1613, 1720, 1723, 1733, 1735, 1651, 1857, 1873, + /* 390 */ 1873, 1896, 1896, 1896, 2070, 2070, 2070, 2070, 2070, 2070, + /* 400 */ 2070, 2070, 2070, 2070, 2070, 2070, 2070, 2070, 2070, 207, + /* 410 */ 915, 1010, 1030, 1217, 910, 1170, 1470, 1368, 1481, 1442, + /* 420 */ 1318, 1383, 1515, 1482, 1523, 1542, 1546, 1547, 1588, 1595, + /* 430 */ 1502, 1338, 1566, 1493, 1520, 1521, 1598, 1617, 1568, 1618, + /* 440 */ 1511, 1514, 1645, 1649, 1570, 1484, 1910, 1915, 1897, 1757, + /* 450 */ 1908, 1909, 1901, 1903, 1788, 1778, 1798, 1911, 1911, 1913, + /* 460 */ 1793, 1918, 1795, 1924, 1940, 1800, 1814, 1911, 1815, 1882, + /* 470 */ 1912, 1911, 1796, 1895, 1898, 1900, 1902, 1824, 1840, 1923, + /* 480 */ 1818, 1957, 1955, 1939, 1847, 1803, 1899, 1938, 1904, 1890, + /* 490 */ 1925, 1827, 1854, 1946, 1951, 1954, 1843, 1850, 1956, 1914, + /* 500 */ 1958, 1960, 1953, 1961, 1917, 1920, 1962, 1881, 1959, 1963, + /* 510 */ 1921, 1952, 1967, 1842, 1970, 1971, 1972, 1973, 1968, 1974, + /* 520 */ 1976, 1905, 1858, 1977, 1978, 1887, 1975, 1982, 1862, 1981, + /* 530 */ 1979, 1980, 1983, 1984, 1919, 1933, 1926, 1966, 1936, 1922, + /* 540 */ 1985, 1993, 1998, 1997, 1999, 2000, 1988, 2003, 1981, 2004, + /* 550 */ 2005, 2006, 2007, 2008, 2009, 2001, 2020, 2012, 2013, 2014, + /* 560 */ 2015, 2017, 2018, 2011, 1906, 1907, 1916, 1927, 1928, 2019, + /* 570 */ 2022, 2027, 2042, 2045, +}; +#define YY_REDUCE_COUNT (408) +#define YY_REDUCE_MIN (-267) +#define YY_REDUCE_MAX (1715) +static const short yy_reduce_ofst[] = { + /* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187, + /* 10 */ -180, 83, 133, -207, -198, -267, -175, -6, 166, 313, + /* 20 */ 487, 396, 489, 598, 615, 685, 687, 79, 781, 857, + /* 30 */ 490, 616, 240, 334, -188, 796, 841, 843, 1003, 1005, + /* 40 */ 1007, -260, -260, -260, -260, -260, -260, -260, -260, -260, + /* 50 */ -260, -260, -260, -260, -260, -260, -260, -260, -260, -260, + /* 60 */ -260, -260, -260, -260, -260, -260, -260, -260, -260, -260, + /* 70 */ -260, -260, -260, -260, -260, -260, -260, -260, 158, 203, + /* 80 */ 391, 576, 724, 726, 886, 1021, 1035, 1063, 1081, 1083, + /* 90 */ 1097, 1099, 1117, 1152, 1155, 1158, 1163, 1165, 1167, 1169, + /* 100 */ 1172, 1180, 1183, 1198, 1200, 1205, 1215, 1225, 1227, 1236, + /* 110 */ 1252, 1264, 1299, 1303, 1306, 1309, 1312, 1315, 1325, 1328, + /* 120 */ 1337, 1340, 1343, 1371, 1373, 1384, 1386, 1411, -260, -260, + /* 130 */ -260, -260, -260, -260, -260, -260, -260, -53, 138, 302, + /* 140 */ -158, 357, 223, -222, 411, 458, -92, 556, 669, 581, + /* 150 */ 632, 581, -260, 632, 758, 778, 920, -260, -260, -260, + /* 160 */ -260, 161, 161, 161, 307, 234, 392, 526, 790, 195, + /* 170 */ 359, -174, -173, 362, 362, -189, 16, 560, 567, 261, + /* 180 */ 689, 802, 853, -122, -166, 408, 335, 617, 690, 837, + /* 190 */ 1001, 746, 1061, 515, 1082, 994, 1034, -135, 1000, 1048, + /* 200 */ 1137, 877, 897, 186, 627, 1031, 1133, 1148, 1159, 1194, + /* 210 */ 1199, 1195, -194, -142, 18, -152, 68, 201, 253, 269, + /* 220 */ 294, 354, 521, 528, 676, 680, 736, 743, 850, 907, + /* 230 */ 1041, 1047, 1060, 727, 1139, 1147, 1201, 1237, 1278, 1359, + /* 240 */ 1393, 1400, 1413, 1429, 1433, 1437, 1126, 1410, 1430, 1444, + /* 250 */ 1480, 1483, 1405, 1486, 1490, 1492, 1420, 1372, 1496, 1498, + /* 260 */ 1441, 1499, 253, 1500, 1503, 1504, 1506, 1507, 1508, 1398, + /* 270 */ 1415, 1453, 1448, 1449, 1450, 1452, 1405, 1453, 1453, 1465, + /* 280 */ 1495, 1519, 1414, 1443, 1445, 1468, 1456, 1455, 1457, 1424, + /* 290 */ 1473, 1454, 1459, 1474, 1460, 1479, 1434, 1512, 1494, 1509, + /* 300 */ 1517, 1518, 1525, 1469, 1489, 1501, 1467, 1510, 1497, 1543, + /* 310 */ 1451, 1462, 1557, 1558, 1471, 1472, 1561, 1487, 1505, 1524, + /* 320 */ 1538, 1537, 1545, 1548, 1556, 1575, 1596, 1552, 1529, 1530, + /* 330 */ 1559, 1533, 1572, 1562, 1573, 1563, 1604, 1615, 1522, 1532, + /* 340 */ 1622, 1624, 1605, 1625, 1628, 1629, 1631, 1607, 1616, 1619, + /* 350 */ 1620, 1606, 1621, 1623, 1630, 1626, 1632, 1636, 1633, 1637, + /* 360 */ 1638, 1531, 1541, 1567, 1571, 1640, 1597, 1599, 1601, 1603, + /* 370 */ 1608, 1610, 1611, 1627, 1664, 1549, 1550, 1609, 1634, 1639, + /* 380 */ 1641, 1602, 1676, 1642, 1646, 1644, 1650, 1654, 1683, 1694, + /* 390 */ 1707, 1711, 1712, 1714, 1643, 1647, 1652, 1698, 1695, 1696, + /* 400 */ 1697, 1699, 1700, 1689, 1691, 1701, 1702, 1704, 1715, +}; +static const YYACTIONTYPE yy_default[] = { + /* 0 */ 1637, 1637, 1637, 1466, 1233, 1344, 1233, 1233, 1233, 1466, + /* 10 */ 1466, 1466, 1233, 1374, 1374, 1519, 1266, 1233, 1233, 1233, + /* 20 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1465, 1233, 1233, + /* 30 */ 1233, 1233, 1554, 1554, 1233, 1233, 1233, 1233, 1233, 1233, + /* 40 */ 1233, 1233, 1383, 1233, 1390, 1233, 1233, 1233, 1233, 1233, + /* 50 */ 1467, 1468, 1233, 1233, 1233, 1518, 1520, 1483, 1397, 1396, + /* 60 */ 1395, 1394, 1501, 1361, 1388, 1381, 1385, 1461, 1462, 1460, + /* 70 */ 1464, 1468, 1467, 1233, 1384, 1431, 1445, 1430, 1233, 1233, + /* 80 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 90 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 100 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 110 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 120 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1439, 1444, + /* 130 */ 1451, 1443, 1440, 1433, 1432, 1434, 1435, 1233, 1233, 1257, + /* 140 */ 1233, 1233, 1254, 1308, 1233, 1233, 1233, 1233, 1233, 1538, + /* 150 */ 1537, 1233, 1436, 1233, 1266, 1425, 1424, 1448, 1437, 1447, + /* 160 */ 1446, 1526, 1590, 1589, 1484, 1233, 1233, 1233, 1233, 1233, + /* 170 */ 1233, 1554, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 180 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 190 */ 1233, 1233, 1233, 1233, 1233, 1554, 1554, 1233, 1266, 1554, + /* 200 */ 1554, 1262, 1262, 1368, 1233, 1533, 1335, 1335, 1335, 1335, + /* 210 */ 1344, 1335, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 220 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1523, 1521, 1233, + /* 230 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 240 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 250 */ 1233, 1233, 1233, 1233, 1233, 1233, 1340, 1233, 1233, 1233, + /* 260 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1583, 1233, + /* 270 */ 1496, 1322, 1340, 1340, 1340, 1340, 1342, 1323, 1321, 1334, + /* 280 */ 1267, 1240, 1629, 1400, 1389, 1341, 1363, 1389, 1363, 1626, + /* 290 */ 1387, 1400, 1400, 1387, 1400, 1341, 1626, 1283, 1606, 1278, + /* 300 */ 1374, 1374, 1374, 1363, 1368, 1368, 1463, 1341, 1334, 1233, + /* 310 */ 1629, 1629, 1349, 1349, 1628, 1628, 1349, 1484, 1613, 1409, + /* 320 */ 1311, 1317, 1317, 1317, 1317, 1349, 1251, 1387, 1613, 1613, + /* 330 */ 1387, 1409, 1311, 1387, 1311, 1387, 1349, 1251, 1500, 1623, + /* 340 */ 1349, 1251, 1474, 1349, 1251, 1349, 1251, 1474, 1309, 1309, + /* 350 */ 1309, 1298, 1233, 1233, 1474, 1309, 1283, 1309, 1298, 1309, + /* 360 */ 1309, 1572, 1233, 1478, 1478, 1474, 1367, 1362, 1367, 1362, + /* 370 */ 1367, 1362, 1367, 1362, 1349, 1564, 1564, 1377, 1377, 1382, + /* 380 */ 1368, 1469, 1349, 1233, 1382, 1380, 1378, 1387, 1301, 1586, + /* 390 */ 1586, 1582, 1582, 1582, 1634, 1634, 1533, 1599, 1266, 1266, + /* 400 */ 1266, 1266, 1599, 1285, 1285, 1267, 1267, 1266, 1599, 1233, + /* 410 */ 1233, 1233, 1233, 1233, 1233, 1594, 1233, 1528, 1485, 1353, + /* 420 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 430 */ 1233, 1233, 1233, 1233, 1539, 1233, 1233, 1233, 1233, 1233, + /* 440 */ 1233, 1233, 1233, 1233, 1233, 1414, 1233, 1236, 1530, 1233, + /* 450 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1391, 1392, 1354, + /* 460 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1406, 1233, 1233, + /* 470 */ 1233, 1401, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 480 */ 1625, 1233, 1233, 1233, 1233, 1233, 1233, 1499, 1498, 1233, + /* 490 */ 1233, 1351, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 500 */ 1233, 1233, 1233, 1233, 1233, 1281, 1233, 1233, 1233, 1233, + /* 510 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 520 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1379, + /* 530 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 540 */ 1233, 1233, 1233, 1233, 1569, 1369, 1233, 1233, 1616, 1233, + /* 550 */ 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, 1233, + /* 560 */ 1233, 1233, 1233, 1610, 1325, 1416, 1233, 1415, 1419, 1255, + /* 570 */ 1233, 1245, 1233, 1233, +}; +/********** End of lemon-generated parsing tables *****************************/ -/* -** Initialize SQLite. +/* The next table maps tokens (terminal symbols) into fallback tokens. +** If a construct like the following: ** -** This routine must be called to initialize the memory allocation, -** VFS, and mutex subsystems prior to doing any serious work with -** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT -** this routine will be called automatically by key routines such as -** sqlite3_open(). +** %fallback ID X Y Z. ** -** This routine is a no-op except on its very first call for the process, -** or for the first call after a call to sqlite3_shutdown. +** appears in the grammar, then ID becomes a fallback token for X, Y, +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser +** but it does not parse, the type of the token is changed to ID and +** the parse is retried before an error is thrown. ** -** The first thread to call this routine runs the initialization to -** completion. If subsequent threads call this routine before the first -** thread has finished the initialization process, then the subsequent -** threads must block until the first thread finishes with the initialization. +** This feature can be used, for example, to cause some keywords in a language +** to revert to identifiers if they keyword does not apply in the context where +** it appears. +*/ +#ifdef YYFALLBACK +static const YYCODETYPE yyFallback[] = { + 0, /* $ => nothing */ + 0, /* SEMI => nothing */ + 59, /* EXPLAIN => ID */ + 59, /* QUERY => ID */ + 59, /* PLAN => ID */ + 59, /* BEGIN => ID */ + 0, /* TRANSACTION => nothing */ + 59, /* DEFERRED => ID */ + 59, /* IMMEDIATE => ID */ + 59, /* EXCLUSIVE => ID */ + 0, /* COMMIT => nothing */ + 59, /* END => ID */ + 59, /* ROLLBACK => ID */ + 59, /* SAVEPOINT => ID */ + 59, /* RELEASE => ID */ + 0, /* TO => nothing */ + 0, /* TABLE => nothing */ + 0, /* CREATE => nothing */ + 59, /* IF => ID */ + 0, /* NOT => nothing */ + 0, /* EXISTS => nothing */ + 59, /* TEMP => ID */ + 0, /* LP => nothing */ + 0, /* RP => nothing */ + 0, /* AS => nothing */ + 0, /* COMMA => nothing */ + 59, /* WITHOUT => ID */ + 59, /* ABORT => ID */ + 59, /* ACTION => ID */ + 59, /* AFTER => ID */ + 59, /* ANALYZE => ID */ + 59, /* ASC => ID */ + 59, /* ATTACH => ID */ + 59, /* BEFORE => ID */ + 59, /* BY => ID */ + 59, /* CASCADE => ID */ + 59, /* CAST => ID */ + 59, /* CONFLICT => ID */ + 59, /* DATABASE => ID */ + 59, /* DESC => ID */ + 59, /* DETACH => ID */ + 59, /* EACH => ID */ + 59, /* FAIL => ID */ + 0, /* OR => nothing */ + 0, /* AND => nothing */ + 0, /* IS => nothing */ + 59, /* MATCH => ID */ + 59, /* LIKE_KW => ID */ + 0, /* BETWEEN => nothing */ + 0, /* IN => nothing */ + 0, /* ISNULL => nothing */ + 0, /* NOTNULL => nothing */ + 0, /* NE => nothing */ + 0, /* EQ => nothing */ + 0, /* GT => nothing */ + 0, /* LE => nothing */ + 0, /* LT => nothing */ + 0, /* GE => nothing */ + 0, /* ESCAPE => nothing */ + 0, /* ID => nothing */ + 59, /* COLUMNKW => ID */ + 59, /* DO => ID */ + 59, /* FOR => ID */ + 59, /* IGNORE => ID */ + 59, /* INITIALLY => ID */ + 59, /* INSTEAD => ID */ + 59, /* NO => ID */ + 59, /* KEY => ID */ + 59, /* OF => ID */ + 59, /* OFFSET => ID */ + 59, /* PRAGMA => ID */ + 59, /* RAISE => ID */ + 59, /* RECURSIVE => ID */ + 59, /* REPLACE => ID */ + 59, /* RESTRICT => ID */ + 59, /* ROW => ID */ + 59, /* ROWS => ID */ + 59, /* TRIGGER => ID */ + 59, /* VACUUM => ID */ + 59, /* VIEW => ID */ + 59, /* VIRTUAL => ID */ + 59, /* WITH => ID */ + 59, /* NULLS => ID */ + 59, /* FIRST => ID */ + 59, /* LAST => ID */ + 59, /* CURRENT => ID */ + 59, /* FOLLOWING => ID */ + 59, /* PARTITION => ID */ + 59, /* PRECEDING => ID */ + 59, /* RANGE => ID */ + 59, /* UNBOUNDED => ID */ + 59, /* EXCLUDE => ID */ + 59, /* GROUPS => ID */ + 59, /* OTHERS => ID */ + 59, /* TIES => ID */ + 59, /* GENERATED => ID */ + 59, /* ALWAYS => ID */ + 59, /* MATERIALIZED => ID */ + 59, /* REINDEX => ID */ + 59, /* RENAME => ID */ + 59, /* CTIME_KW => ID */ + 0, /* ANY => nothing */ + 0, /* BITAND => nothing */ + 0, /* BITOR => nothing */ + 0, /* LSHIFT => nothing */ + 0, /* RSHIFT => nothing */ + 0, /* PLUS => nothing */ + 0, /* MINUS => nothing */ + 0, /* STAR => nothing */ + 0, /* SLASH => nothing */ + 0, /* REM => nothing */ + 0, /* CONCAT => nothing */ + 0, /* PTR => nothing */ + 0, /* COLLATE => nothing */ + 0, /* BITNOT => nothing */ + 0, /* ON => nothing */ + 0, /* INDEXED => nothing */ + 0, /* STRING => nothing */ + 0, /* JOIN_KW => nothing */ + 0, /* CONSTRAINT => nothing */ + 0, /* DEFAULT => nothing */ + 0, /* NULL => nothing */ + 0, /* PRIMARY => nothing */ + 0, /* UNIQUE => nothing */ + 0, /* CHECK => nothing */ + 0, /* REFERENCES => nothing */ + 0, /* AUTOINCR => nothing */ + 0, /* INSERT => nothing */ + 0, /* DELETE => nothing */ + 0, /* UPDATE => nothing */ + 0, /* SET => nothing */ + 0, /* DEFERRABLE => nothing */ + 0, /* FOREIGN => nothing */ + 0, /* DROP => nothing */ + 0, /* UNION => nothing */ + 0, /* ALL => nothing */ + 0, /* EXCEPT => nothing */ + 0, /* INTERSECT => nothing */ + 0, /* SELECT => nothing */ + 0, /* VALUES => nothing */ + 0, /* DISTINCT => nothing */ + 0, /* DOT => nothing */ + 0, /* FROM => nothing */ + 0, /* JOIN => nothing */ + 0, /* USING => nothing */ + 0, /* ORDER => nothing */ + 0, /* GROUP => nothing */ + 0, /* HAVING => nothing */ + 0, /* LIMIT => nothing */ + 0, /* WHERE => nothing */ + 0, /* RETURNING => nothing */ + 0, /* INTO => nothing */ + 0, /* NOTHING => nothing */ + 0, /* FLOAT => nothing */ + 0, /* BLOB => nothing */ + 0, /* INTEGER => nothing */ + 0, /* VARIABLE => nothing */ + 0, /* CASE => nothing */ + 0, /* WHEN => nothing */ + 0, /* THEN => nothing */ + 0, /* ELSE => nothing */ + 0, /* INDEX => nothing */ + 0, /* ALTER => nothing */ + 0, /* ADD => nothing */ + 0, /* WINDOW => nothing */ + 0, /* OVER => nothing */ + 0, /* FILTER => nothing */ + 0, /* COLUMN => nothing */ + 0, /* AGG_FUNCTION => nothing */ + 0, /* AGG_COLUMN => nothing */ + 0, /* TRUEFALSE => nothing */ + 0, /* ISNOT => nothing */ + 0, /* FUNCTION => nothing */ + 0, /* UMINUS => nothing */ + 0, /* UPLUS => nothing */ + 0, /* TRUTH => nothing */ + 0, /* REGISTER => nothing */ + 0, /* VECTOR => nothing */ + 0, /* SELECT_COLUMN => nothing */ + 0, /* IF_NULL_ROW => nothing */ + 0, /* ASTERISK => nothing */ + 0, /* SPAN => nothing */ + 0, /* ERROR => nothing */ + 0, /* SPACE => nothing */ + 0, /* ILLEGAL => nothing */ +}; +#endif /* YYFALLBACK */ + +/* The following structure represents a single element of the +** parser's stack. Information stored includes: ** -** The first thread might call this routine recursively. Recursive -** calls to this routine should not block, of course. Otherwise the -** initialization process would never complete. +** + The state number for the parser at this level of the stack. ** -** Let X be the first thread to enter this routine. Let Y be some other -** thread. Then while the initial invocation of this routine by X is -** incomplete, it is required that: +** + The value of the token stored at this level of the stack. +** (In other words, the "major" token.) ** -** * Calls to this routine from Y must block until the outer-most -** call by X completes. +** + The semantic value stored at this level of the stack. This is +** the information used by the action routines in the grammar. +** It is sometimes called the "minor" token. ** -** * Recursive calls to this routine from thread X return immediately -** without blocking. +** After the "shift" half of a SHIFTREDUCE action, the stateno field +** actually contains the reduce action for the second half of the +** SHIFTREDUCE. */ -SQLITE_API int sqlite3_initialize(void){ - MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */ - int rc; /* Result code */ -#ifdef SQLITE_EXTRA_INIT - int bRunExtraInit = 0; /* Extra initialization needed */ -#endif +struct yyStackEntry { + YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ + YYCODETYPE major; /* The major token value. This is the code + ** number for the token at this stack level */ + YYMINORTYPE minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; +typedef struct yyStackEntry yyStackEntry; -#ifdef SQLITE_OMIT_WSD - rc = sqlite3_wsd_init(4096, 24); - if( rc!=SQLITE_OK ){ - return rc; - } +/* The state of the parser is completely contained in an instance of +** the following structure */ +struct yyParser { + yyStackEntry *yytos; /* Pointer to top element of the stack */ +#ifdef YYTRACKMAXSTACKDEPTH + int yyhwm; /* High-water mark of the stack */ +#endif +#ifndef YYNOERRORRECOVERY + int yyerrcnt; /* Shifts left before out of the error */ +#endif + sqlite3ParserARG_SDECL /* A place to hold %extra_argument */ + sqlite3ParserCTX_SDECL /* A place to hold %extra_context */ +#if YYSTACKDEPTH<=0 + int yystksz; /* Current side of the stack */ + yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ +#else + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ + yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif +}; +typedef struct yyParser yyParser; - /* If the following assert() fails on some obscure processor/compiler - ** combination, the work-around is to set the correct pointer - ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */ - assert( SQLITE_PTRSIZE==sizeof(char*) ); +/* #include */ +#ifndef NDEBUG +/* #include */ +static FILE *yyTraceFILE = 0; +static char *yyTracePrompt = 0; +#endif /* NDEBUG */ - /* If SQLite is already completely initialized, then this call - ** to sqlite3_initialize() should be a no-op. But the initialization - ** must be complete. So isInit must not be set until the very end - ** of this routine. - */ - if( sqlite3GlobalConfig.isInit ) return SQLITE_OK; +#ifndef NDEBUG +/* +** Turn parser tracing on by giving a stream to which to write the trace +** and a prompt to preface each trace message. Tracing is turned off +** by making either argument NULL +** +** Inputs: +**
              +**
            • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
            • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
            +** +** Outputs: +** None. +*/ +SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){ + yyTraceFILE = TraceFILE; + yyTracePrompt = zTracePrompt; + if( yyTraceFILE==0 ) yyTracePrompt = 0; + else if( yyTracePrompt==0 ) yyTraceFILE = 0; +} +#endif /* NDEBUG */ - /* Make sure the mutex subsystem is initialized. If unable to - ** initialize the mutex subsystem, return early with the error. - ** If the system is so sick that we are unable to allocate a mutex, - ** there is not much SQLite is going to be able to do. - ** - ** The mutex subsystem must take care of serializing its own - ** initialization. - */ - rc = sqlite3MutexInit(); - if( rc ) return rc; +#if defined(YYCOVERAGE) || !defined(NDEBUG) +/* For tracing shifts, the names of all terminals and nonterminals +** are required. The following table supplies these names */ +static const char *const yyTokenName[] = { + /* 0 */ "$", + /* 1 */ "SEMI", + /* 2 */ "EXPLAIN", + /* 3 */ "QUERY", + /* 4 */ "PLAN", + /* 5 */ "BEGIN", + /* 6 */ "TRANSACTION", + /* 7 */ "DEFERRED", + /* 8 */ "IMMEDIATE", + /* 9 */ "EXCLUSIVE", + /* 10 */ "COMMIT", + /* 11 */ "END", + /* 12 */ "ROLLBACK", + /* 13 */ "SAVEPOINT", + /* 14 */ "RELEASE", + /* 15 */ "TO", + /* 16 */ "TABLE", + /* 17 */ "CREATE", + /* 18 */ "IF", + /* 19 */ "NOT", + /* 20 */ "EXISTS", + /* 21 */ "TEMP", + /* 22 */ "LP", + /* 23 */ "RP", + /* 24 */ "AS", + /* 25 */ "COMMA", + /* 26 */ "WITHOUT", + /* 27 */ "ABORT", + /* 28 */ "ACTION", + /* 29 */ "AFTER", + /* 30 */ "ANALYZE", + /* 31 */ "ASC", + /* 32 */ "ATTACH", + /* 33 */ "BEFORE", + /* 34 */ "BY", + /* 35 */ "CASCADE", + /* 36 */ "CAST", + /* 37 */ "CONFLICT", + /* 38 */ "DATABASE", + /* 39 */ "DESC", + /* 40 */ "DETACH", + /* 41 */ "EACH", + /* 42 */ "FAIL", + /* 43 */ "OR", + /* 44 */ "AND", + /* 45 */ "IS", + /* 46 */ "MATCH", + /* 47 */ "LIKE_KW", + /* 48 */ "BETWEEN", + /* 49 */ "IN", + /* 50 */ "ISNULL", + /* 51 */ "NOTNULL", + /* 52 */ "NE", + /* 53 */ "EQ", + /* 54 */ "GT", + /* 55 */ "LE", + /* 56 */ "LT", + /* 57 */ "GE", + /* 58 */ "ESCAPE", + /* 59 */ "ID", + /* 60 */ "COLUMNKW", + /* 61 */ "DO", + /* 62 */ "FOR", + /* 63 */ "IGNORE", + /* 64 */ "INITIALLY", + /* 65 */ "INSTEAD", + /* 66 */ "NO", + /* 67 */ "KEY", + /* 68 */ "OF", + /* 69 */ "OFFSET", + /* 70 */ "PRAGMA", + /* 71 */ "RAISE", + /* 72 */ "RECURSIVE", + /* 73 */ "REPLACE", + /* 74 */ "RESTRICT", + /* 75 */ "ROW", + /* 76 */ "ROWS", + /* 77 */ "TRIGGER", + /* 78 */ "VACUUM", + /* 79 */ "VIEW", + /* 80 */ "VIRTUAL", + /* 81 */ "WITH", + /* 82 */ "NULLS", + /* 83 */ "FIRST", + /* 84 */ "LAST", + /* 85 */ "CURRENT", + /* 86 */ "FOLLOWING", + /* 87 */ "PARTITION", + /* 88 */ "PRECEDING", + /* 89 */ "RANGE", + /* 90 */ "UNBOUNDED", + /* 91 */ "EXCLUDE", + /* 92 */ "GROUPS", + /* 93 */ "OTHERS", + /* 94 */ "TIES", + /* 95 */ "GENERATED", + /* 96 */ "ALWAYS", + /* 97 */ "MATERIALIZED", + /* 98 */ "REINDEX", + /* 99 */ "RENAME", + /* 100 */ "CTIME_KW", + /* 101 */ "ANY", + /* 102 */ "BITAND", + /* 103 */ "BITOR", + /* 104 */ "LSHIFT", + /* 105 */ "RSHIFT", + /* 106 */ "PLUS", + /* 107 */ "MINUS", + /* 108 */ "STAR", + /* 109 */ "SLASH", + /* 110 */ "REM", + /* 111 */ "CONCAT", + /* 112 */ "PTR", + /* 113 */ "COLLATE", + /* 114 */ "BITNOT", + /* 115 */ "ON", + /* 116 */ "INDEXED", + /* 117 */ "STRING", + /* 118 */ "JOIN_KW", + /* 119 */ "CONSTRAINT", + /* 120 */ "DEFAULT", + /* 121 */ "NULL", + /* 122 */ "PRIMARY", + /* 123 */ "UNIQUE", + /* 124 */ "CHECK", + /* 125 */ "REFERENCES", + /* 126 */ "AUTOINCR", + /* 127 */ "INSERT", + /* 128 */ "DELETE", + /* 129 */ "UPDATE", + /* 130 */ "SET", + /* 131 */ "DEFERRABLE", + /* 132 */ "FOREIGN", + /* 133 */ "DROP", + /* 134 */ "UNION", + /* 135 */ "ALL", + /* 136 */ "EXCEPT", + /* 137 */ "INTERSECT", + /* 138 */ "SELECT", + /* 139 */ "VALUES", + /* 140 */ "DISTINCT", + /* 141 */ "DOT", + /* 142 */ "FROM", + /* 143 */ "JOIN", + /* 144 */ "USING", + /* 145 */ "ORDER", + /* 146 */ "GROUP", + /* 147 */ "HAVING", + /* 148 */ "LIMIT", + /* 149 */ "WHERE", + /* 150 */ "RETURNING", + /* 151 */ "INTO", + /* 152 */ "NOTHING", + /* 153 */ "FLOAT", + /* 154 */ "BLOB", + /* 155 */ "INTEGER", + /* 156 */ "VARIABLE", + /* 157 */ "CASE", + /* 158 */ "WHEN", + /* 159 */ "THEN", + /* 160 */ "ELSE", + /* 161 */ "INDEX", + /* 162 */ "ALTER", + /* 163 */ "ADD", + /* 164 */ "WINDOW", + /* 165 */ "OVER", + /* 166 */ "FILTER", + /* 167 */ "COLUMN", + /* 168 */ "AGG_FUNCTION", + /* 169 */ "AGG_COLUMN", + /* 170 */ "TRUEFALSE", + /* 171 */ "ISNOT", + /* 172 */ "FUNCTION", + /* 173 */ "UMINUS", + /* 174 */ "UPLUS", + /* 175 */ "TRUTH", + /* 176 */ "REGISTER", + /* 177 */ "VECTOR", + /* 178 */ "SELECT_COLUMN", + /* 179 */ "IF_NULL_ROW", + /* 180 */ "ASTERISK", + /* 181 */ "SPAN", + /* 182 */ "ERROR", + /* 183 */ "SPACE", + /* 184 */ "ILLEGAL", + /* 185 */ "input", + /* 186 */ "cmdlist", + /* 187 */ "ecmd", + /* 188 */ "cmdx", + /* 189 */ "explain", + /* 190 */ "cmd", + /* 191 */ "transtype", + /* 192 */ "trans_opt", + /* 193 */ "nm", + /* 194 */ "savepoint_opt", + /* 195 */ "create_table", + /* 196 */ "create_table_args", + /* 197 */ "createkw", + /* 198 */ "temp", + /* 199 */ "ifnotexists", + /* 200 */ "dbnm", + /* 201 */ "columnlist", + /* 202 */ "conslist_opt", + /* 203 */ "table_option_set", + /* 204 */ "select", + /* 205 */ "table_option", + /* 206 */ "columnname", + /* 207 */ "carglist", + /* 208 */ "typetoken", + /* 209 */ "typename", + /* 210 */ "signed", + /* 211 */ "plus_num", + /* 212 */ "minus_num", + /* 213 */ "scanpt", + /* 214 */ "scantok", + /* 215 */ "ccons", + /* 216 */ "term", + /* 217 */ "expr", + /* 218 */ "onconf", + /* 219 */ "sortorder", + /* 220 */ "autoinc", + /* 221 */ "eidlist_opt", + /* 222 */ "refargs", + /* 223 */ "defer_subclause", + /* 224 */ "generated", + /* 225 */ "refarg", + /* 226 */ "refact", + /* 227 */ "init_deferred_pred_opt", + /* 228 */ "conslist", + /* 229 */ "tconscomma", + /* 230 */ "tcons", + /* 231 */ "sortlist", + /* 232 */ "eidlist", + /* 233 */ "defer_subclause_opt", + /* 234 */ "orconf", + /* 235 */ "resolvetype", + /* 236 */ "raisetype", + /* 237 */ "ifexists", + /* 238 */ "fullname", + /* 239 */ "selectnowith", + /* 240 */ "oneselect", + /* 241 */ "wqlist", + /* 242 */ "multiselect_op", + /* 243 */ "distinct", + /* 244 */ "selcollist", + /* 245 */ "from", + /* 246 */ "where_opt", + /* 247 */ "groupby_opt", + /* 248 */ "having_opt", + /* 249 */ "orderby_opt", + /* 250 */ "limit_opt", + /* 251 */ "window_clause", + /* 252 */ "values", + /* 253 */ "nexprlist", + /* 254 */ "sclp", + /* 255 */ "as", + /* 256 */ "seltablist", + /* 257 */ "stl_prefix", + /* 258 */ "joinop", + /* 259 */ "indexed_opt", + /* 260 */ "on_opt", + /* 261 */ "using_opt", + /* 262 */ "exprlist", + /* 263 */ "xfullname", + /* 264 */ "idlist", + /* 265 */ "nulls", + /* 266 */ "with", + /* 267 */ "where_opt_ret", + /* 268 */ "setlist", + /* 269 */ "insert_cmd", + /* 270 */ "idlist_opt", + /* 271 */ "upsert", + /* 272 */ "returning", + /* 273 */ "filter_over", + /* 274 */ "likeop", + /* 275 */ "between_op", + /* 276 */ "in_op", + /* 277 */ "paren_exprlist", + /* 278 */ "case_operand", + /* 279 */ "case_exprlist", + /* 280 */ "case_else", + /* 281 */ "uniqueflag", + /* 282 */ "collate", + /* 283 */ "vinto", + /* 284 */ "nmnum", + /* 285 */ "trigger_decl", + /* 286 */ "trigger_cmd_list", + /* 287 */ "trigger_time", + /* 288 */ "trigger_event", + /* 289 */ "foreach_clause", + /* 290 */ "when_clause", + /* 291 */ "trigger_cmd", + /* 292 */ "trnm", + /* 293 */ "tridxby", + /* 294 */ "database_kw_opt", + /* 295 */ "key_opt", + /* 296 */ "add_column_fullname", + /* 297 */ "kwcolumn_opt", + /* 298 */ "create_vtab", + /* 299 */ "vtabarglist", + /* 300 */ "vtabarg", + /* 301 */ "vtabargtoken", + /* 302 */ "lp", + /* 303 */ "anylist", + /* 304 */ "wqitem", + /* 305 */ "wqas", + /* 306 */ "windowdefn_list", + /* 307 */ "windowdefn", + /* 308 */ "window", + /* 309 */ "frame_opt", + /* 310 */ "part_opt", + /* 311 */ "filter_clause", + /* 312 */ "over_clause", + /* 313 */ "range_or_rows", + /* 314 */ "frame_bound", + /* 315 */ "frame_bound_s", + /* 316 */ "frame_bound_e", + /* 317 */ "frame_exclude_opt", + /* 318 */ "frame_exclude", +}; +#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ - /* Initialize the malloc() system and the recursive pInitMutex mutex. - ** This operation is protected by the STATIC_MASTER mutex. Note that - ** MutexAlloc() is called for a static mutex prior to initializing the - ** malloc subsystem - this implies that the allocation of a static - ** mutex must not require support from the malloc subsystem. - */ - MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) - sqlite3_mutex_enter(pMaster); - sqlite3GlobalConfig.isMutexInit = 1; - if( !sqlite3GlobalConfig.isMallocInit ){ - rc = sqlite3MallocInit(); - } - if( rc==SQLITE_OK ){ - sqlite3GlobalConfig.isMallocInit = 1; - if( !sqlite3GlobalConfig.pInitMutex ){ - sqlite3GlobalConfig.pInitMutex = - sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); - if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){ - rc = SQLITE_NOMEM_BKPT; - } - } - } - if( rc==SQLITE_OK ){ - sqlite3GlobalConfig.nRefInitMutex++; - } - sqlite3_mutex_leave(pMaster); +#ifndef NDEBUG +/* For tracing reduce actions, the names of all rules are required. +*/ +static const char *const yyRuleName[] = { + /* 0 */ "explain ::= EXPLAIN", + /* 1 */ "explain ::= EXPLAIN QUERY PLAN", + /* 2 */ "cmdx ::= cmd", + /* 3 */ "cmd ::= BEGIN transtype trans_opt", + /* 4 */ "transtype ::=", + /* 5 */ "transtype ::= DEFERRED", + /* 6 */ "transtype ::= IMMEDIATE", + /* 7 */ "transtype ::= EXCLUSIVE", + /* 8 */ "cmd ::= COMMIT|END trans_opt", + /* 9 */ "cmd ::= ROLLBACK trans_opt", + /* 10 */ "cmd ::= SAVEPOINT nm", + /* 11 */ "cmd ::= RELEASE savepoint_opt nm", + /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm", + /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm", + /* 14 */ "createkw ::= CREATE", + /* 15 */ "ifnotexists ::=", + /* 16 */ "ifnotexists ::= IF NOT EXISTS", + /* 17 */ "temp ::= TEMP", + /* 18 */ "temp ::=", + /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set", + /* 20 */ "create_table_args ::= AS select", + /* 21 */ "table_option_set ::=", + /* 22 */ "table_option_set ::= table_option_set COMMA table_option", + /* 23 */ "table_option ::= WITHOUT nm", + /* 24 */ "table_option ::= nm", + /* 25 */ "columnname ::= nm typetoken", + /* 26 */ "typetoken ::=", + /* 27 */ "typetoken ::= typename LP signed RP", + /* 28 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 29 */ "typename ::= typename ID|STRING", + /* 30 */ "scanpt ::=", + /* 31 */ "scantok ::=", + /* 32 */ "ccons ::= CONSTRAINT nm", + /* 33 */ "ccons ::= DEFAULT scantok term", + /* 34 */ "ccons ::= DEFAULT LP expr RP", + /* 35 */ "ccons ::= DEFAULT PLUS scantok term", + /* 36 */ "ccons ::= DEFAULT MINUS scantok term", + /* 37 */ "ccons ::= DEFAULT scantok ID|INDEXED", + /* 38 */ "ccons ::= NOT NULL onconf", + /* 39 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 40 */ "ccons ::= UNIQUE onconf", + /* 41 */ "ccons ::= CHECK LP expr RP", + /* 42 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 43 */ "ccons ::= defer_subclause", + /* 44 */ "ccons ::= COLLATE ID|STRING", + /* 45 */ "generated ::= LP expr RP", + /* 46 */ "generated ::= LP expr RP ID", + /* 47 */ "autoinc ::=", + /* 48 */ "autoinc ::= AUTOINCR", + /* 49 */ "refargs ::=", + /* 50 */ "refargs ::= refargs refarg", + /* 51 */ "refarg ::= MATCH nm", + /* 52 */ "refarg ::= ON INSERT refact", + /* 53 */ "refarg ::= ON DELETE refact", + /* 54 */ "refarg ::= ON UPDATE refact", + /* 55 */ "refact ::= SET NULL", + /* 56 */ "refact ::= SET DEFAULT", + /* 57 */ "refact ::= CASCADE", + /* 58 */ "refact ::= RESTRICT", + /* 59 */ "refact ::= NO ACTION", + /* 60 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 61 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 62 */ "init_deferred_pred_opt ::=", + /* 63 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 64 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 65 */ "conslist_opt ::=", + /* 66 */ "tconscomma ::= COMMA", + /* 67 */ "tcons ::= CONSTRAINT nm", + /* 68 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 69 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 70 */ "tcons ::= CHECK LP expr RP onconf", + /* 71 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 72 */ "defer_subclause_opt ::=", + /* 73 */ "onconf ::=", + /* 74 */ "onconf ::= ON CONFLICT resolvetype", + /* 75 */ "orconf ::=", + /* 76 */ "orconf ::= OR resolvetype", + /* 77 */ "resolvetype ::= IGNORE", + /* 78 */ "resolvetype ::= REPLACE", + /* 79 */ "cmd ::= DROP TABLE ifexists fullname", + /* 80 */ "ifexists ::= IF EXISTS", + /* 81 */ "ifexists ::=", + /* 82 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 83 */ "cmd ::= DROP VIEW ifexists fullname", + /* 84 */ "cmd ::= select", + /* 85 */ "select ::= WITH wqlist selectnowith", + /* 86 */ "select ::= WITH RECURSIVE wqlist selectnowith", + /* 87 */ "select ::= selectnowith", + /* 88 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 89 */ "multiselect_op ::= UNION", + /* 90 */ "multiselect_op ::= UNION ALL", + /* 91 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", + /* 94 */ "values ::= VALUES LP nexprlist RP", + /* 95 */ "values ::= values COMMA LP nexprlist RP", + /* 96 */ "distinct ::= DISTINCT", + /* 97 */ "distinct ::= ALL", + /* 98 */ "distinct ::=", + /* 99 */ "sclp ::=", + /* 100 */ "selcollist ::= sclp scanpt expr scanpt as", + /* 101 */ "selcollist ::= sclp scanpt STAR", + /* 102 */ "selcollist ::= sclp scanpt nm DOT STAR", + /* 103 */ "as ::= AS nm", + /* 104 */ "as ::=", + /* 105 */ "from ::=", + /* 106 */ "from ::= FROM seltablist", + /* 107 */ "stl_prefix ::= seltablist joinop", + /* 108 */ "stl_prefix ::=", + /* 109 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 110 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 111 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 112 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 113 */ "dbnm ::=", + /* 114 */ "dbnm ::= DOT nm", + /* 115 */ "fullname ::= nm", + /* 116 */ "fullname ::= nm DOT nm", + /* 117 */ "xfullname ::= nm", + /* 118 */ "xfullname ::= nm DOT nm", + /* 119 */ "xfullname ::= nm DOT nm AS nm", + /* 120 */ "xfullname ::= nm AS nm", + /* 121 */ "joinop ::= COMMA|JOIN", + /* 122 */ "joinop ::= JOIN_KW JOIN", + /* 123 */ "joinop ::= JOIN_KW nm JOIN", + /* 124 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 125 */ "on_opt ::= ON expr", + /* 126 */ "on_opt ::=", + /* 127 */ "indexed_opt ::=", + /* 128 */ "indexed_opt ::= INDEXED BY nm", + /* 129 */ "indexed_opt ::= NOT INDEXED", + /* 130 */ "using_opt ::= USING LP idlist RP", + /* 131 */ "using_opt ::=", + /* 132 */ "orderby_opt ::=", + /* 133 */ "orderby_opt ::= ORDER BY sortlist", + /* 134 */ "sortlist ::= sortlist COMMA expr sortorder nulls", + /* 135 */ "sortlist ::= expr sortorder nulls", + /* 136 */ "sortorder ::= ASC", + /* 137 */ "sortorder ::= DESC", + /* 138 */ "sortorder ::=", + /* 139 */ "nulls ::= NULLS FIRST", + /* 140 */ "nulls ::= NULLS LAST", + /* 141 */ "nulls ::=", + /* 142 */ "groupby_opt ::=", + /* 143 */ "groupby_opt ::= GROUP BY nexprlist", + /* 144 */ "having_opt ::=", + /* 145 */ "having_opt ::= HAVING expr", + /* 146 */ "limit_opt ::=", + /* 147 */ "limit_opt ::= LIMIT expr", + /* 148 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 149 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 150 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret", + /* 151 */ "where_opt ::=", + /* 152 */ "where_opt ::= WHERE expr", + /* 153 */ "where_opt_ret ::=", + /* 154 */ "where_opt_ret ::= WHERE expr", + /* 155 */ "where_opt_ret ::= RETURNING selcollist", + /* 156 */ "where_opt_ret ::= WHERE expr RETURNING selcollist", + /* 157 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret", + /* 158 */ "setlist ::= setlist COMMA nm EQ expr", + /* 159 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 160 */ "setlist ::= nm EQ expr", + /* 161 */ "setlist ::= LP idlist RP EQ expr", + /* 162 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", + /* 163 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning", + /* 164 */ "upsert ::=", + /* 165 */ "upsert ::= RETURNING selcollist", + /* 166 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert", + /* 167 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert", + /* 168 */ "upsert ::= ON CONFLICT DO NOTHING returning", + /* 169 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning", + /* 170 */ "returning ::= RETURNING selcollist", + /* 171 */ "insert_cmd ::= INSERT orconf", + /* 172 */ "insert_cmd ::= REPLACE", + /* 173 */ "idlist_opt ::=", + /* 174 */ "idlist_opt ::= LP idlist RP", + /* 175 */ "idlist ::= idlist COMMA nm", + /* 176 */ "idlist ::= nm", + /* 177 */ "expr ::= LP expr RP", + /* 178 */ "expr ::= ID|INDEXED", + /* 179 */ "expr ::= JOIN_KW", + /* 180 */ "expr ::= nm DOT nm", + /* 181 */ "expr ::= nm DOT nm DOT nm", + /* 182 */ "term ::= NULL|FLOAT|BLOB", + /* 183 */ "term ::= STRING", + /* 184 */ "term ::= INTEGER", + /* 185 */ "expr ::= VARIABLE", + /* 186 */ "expr ::= expr COLLATE ID|STRING", + /* 187 */ "expr ::= CAST LP expr AS typetoken RP", + /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 189 */ "expr ::= ID|INDEXED LP STAR RP", + /* 190 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over", + /* 191 */ "expr ::= ID|INDEXED LP STAR RP filter_over", + /* 192 */ "term ::= CTIME_KW", + /* 193 */ "expr ::= LP nexprlist COMMA expr RP", + /* 194 */ "expr ::= expr AND expr", + /* 195 */ "expr ::= expr OR expr", + /* 196 */ "expr ::= expr LT|GT|GE|LE expr", + /* 197 */ "expr ::= expr EQ|NE expr", + /* 198 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 199 */ "expr ::= expr PLUS|MINUS expr", + /* 200 */ "expr ::= expr STAR|SLASH|REM expr", + /* 201 */ "expr ::= expr CONCAT expr", + /* 202 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 203 */ "expr ::= expr likeop expr", + /* 204 */ "expr ::= expr likeop expr ESCAPE expr", + /* 205 */ "expr ::= expr ISNULL|NOTNULL", + /* 206 */ "expr ::= expr NOT NULL", + /* 207 */ "expr ::= expr IS expr", + /* 208 */ "expr ::= expr IS NOT expr", + /* 209 */ "expr ::= NOT expr", + /* 210 */ "expr ::= BITNOT expr", + /* 211 */ "expr ::= PLUS|MINUS expr", + /* 212 */ "expr ::= expr PTR expr", + /* 213 */ "between_op ::= BETWEEN", + /* 214 */ "between_op ::= NOT BETWEEN", + /* 215 */ "expr ::= expr between_op expr AND expr", + /* 216 */ "in_op ::= IN", + /* 217 */ "in_op ::= NOT IN", + /* 218 */ "expr ::= expr in_op LP exprlist RP", + /* 219 */ "expr ::= LP select RP", + /* 220 */ "expr ::= expr in_op LP select RP", + /* 221 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 222 */ "expr ::= EXISTS LP select RP", + /* 223 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 224 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 225 */ "case_exprlist ::= WHEN expr THEN expr", + /* 226 */ "case_else ::= ELSE expr", + /* 227 */ "case_else ::=", + /* 228 */ "case_operand ::= expr", + /* 229 */ "case_operand ::=", + /* 230 */ "exprlist ::=", + /* 231 */ "nexprlist ::= nexprlist COMMA expr", + /* 232 */ "nexprlist ::= expr", + /* 233 */ "paren_exprlist ::=", + /* 234 */ "paren_exprlist ::= LP exprlist RP", + /* 235 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 236 */ "uniqueflag ::= UNIQUE", + /* 237 */ "uniqueflag ::=", + /* 238 */ "eidlist_opt ::=", + /* 239 */ "eidlist_opt ::= LP eidlist RP", + /* 240 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 241 */ "eidlist ::= nm collate sortorder", + /* 242 */ "collate ::=", + /* 243 */ "collate ::= COLLATE ID|STRING", + /* 244 */ "cmd ::= DROP INDEX ifexists fullname", + /* 245 */ "cmd ::= VACUUM vinto", + /* 246 */ "cmd ::= VACUUM nm vinto", + /* 247 */ "vinto ::= INTO expr", + /* 248 */ "vinto ::=", + /* 249 */ "cmd ::= PRAGMA nm dbnm", + /* 250 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 251 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 252 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 253 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 254 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 255 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 256 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 257 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 258 */ "trigger_time ::= BEFORE|AFTER", + /* 259 */ "trigger_time ::= INSTEAD OF", + /* 260 */ "trigger_time ::=", + /* 261 */ "trigger_event ::= DELETE|INSERT", + /* 262 */ "trigger_event ::= UPDATE", + /* 263 */ "trigger_event ::= UPDATE OF idlist", + /* 264 */ "when_clause ::=", + /* 265 */ "when_clause ::= WHEN expr", + /* 266 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 267 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 268 */ "trnm ::= nm DOT nm", + /* 269 */ "tridxby ::= INDEXED BY nm", + /* 270 */ "tridxby ::= NOT INDEXED", + /* 271 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", + /* 272 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 273 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 274 */ "trigger_cmd ::= scanpt select scanpt", + /* 275 */ "expr ::= RAISE LP IGNORE RP", + /* 276 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 277 */ "raisetype ::= ROLLBACK", + /* 278 */ "raisetype ::= ABORT", + /* 279 */ "raisetype ::= FAIL", + /* 280 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 281 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 282 */ "cmd ::= DETACH database_kw_opt expr", + /* 283 */ "key_opt ::=", + /* 284 */ "key_opt ::= KEY expr", + /* 285 */ "cmd ::= REINDEX", + /* 286 */ "cmd ::= REINDEX nm dbnm", + /* 287 */ "cmd ::= ANALYZE", + /* 288 */ "cmd ::= ANALYZE nm dbnm", + /* 289 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 290 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 291 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", + /* 292 */ "add_column_fullname ::= fullname", + /* 293 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 294 */ "cmd ::= create_vtab", + /* 295 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 296 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 297 */ "vtabarg ::=", + /* 298 */ "vtabargtoken ::= ANY", + /* 299 */ "vtabargtoken ::= lp anylist RP", + /* 300 */ "lp ::= LP", + /* 301 */ "with ::= WITH wqlist", + /* 302 */ "with ::= WITH RECURSIVE wqlist", + /* 303 */ "wqas ::= AS", + /* 304 */ "wqas ::= AS MATERIALIZED", + /* 305 */ "wqas ::= AS NOT MATERIALIZED", + /* 306 */ "wqitem ::= nm eidlist_opt wqas LP select RP", + /* 307 */ "wqlist ::= wqitem", + /* 308 */ "wqlist ::= wqlist COMMA wqitem", + /* 309 */ "windowdefn_list ::= windowdefn", + /* 310 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 311 */ "windowdefn ::= nm AS LP window RP", + /* 312 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 313 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 314 */ "window ::= ORDER BY sortlist frame_opt", + /* 315 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 316 */ "window ::= frame_opt", + /* 317 */ "window ::= nm frame_opt", + /* 318 */ "frame_opt ::=", + /* 319 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 320 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 321 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 322 */ "frame_bound_s ::= frame_bound", + /* 323 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 324 */ "frame_bound_e ::= frame_bound", + /* 325 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 326 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 327 */ "frame_bound ::= CURRENT ROW", + /* 328 */ "frame_exclude_opt ::=", + /* 329 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 330 */ "frame_exclude ::= NO OTHERS", + /* 331 */ "frame_exclude ::= CURRENT ROW", + /* 332 */ "frame_exclude ::= GROUP|TIES", + /* 333 */ "window_clause ::= WINDOW windowdefn_list", + /* 334 */ "filter_over ::= filter_clause over_clause", + /* 335 */ "filter_over ::= over_clause", + /* 336 */ "filter_over ::= filter_clause", + /* 337 */ "over_clause ::= OVER LP window RP", + /* 338 */ "over_clause ::= OVER nm", + /* 339 */ "filter_clause ::= FILTER LP WHERE expr RP", + /* 340 */ "input ::= cmdlist", + /* 341 */ "cmdlist ::= cmdlist ecmd", + /* 342 */ "cmdlist ::= ecmd", + /* 343 */ "ecmd ::= SEMI", + /* 344 */ "ecmd ::= cmdx SEMI", + /* 345 */ "ecmd ::= explain cmdx SEMI", + /* 346 */ "trans_opt ::=", + /* 347 */ "trans_opt ::= TRANSACTION", + /* 348 */ "trans_opt ::= TRANSACTION nm", + /* 349 */ "savepoint_opt ::= SAVEPOINT", + /* 350 */ "savepoint_opt ::=", + /* 351 */ "cmd ::= create_table create_table_args", + /* 352 */ "table_option_set ::= table_option", + /* 353 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 354 */ "columnlist ::= columnname carglist", + /* 355 */ "nm ::= ID|INDEXED", + /* 356 */ "nm ::= STRING", + /* 357 */ "nm ::= JOIN_KW", + /* 358 */ "typetoken ::= typename", + /* 359 */ "typename ::= ID|STRING", + /* 360 */ "signed ::= plus_num", + /* 361 */ "signed ::= minus_num", + /* 362 */ "carglist ::= carglist ccons", + /* 363 */ "carglist ::=", + /* 364 */ "ccons ::= NULL onconf", + /* 365 */ "ccons ::= GENERATED ALWAYS AS generated", + /* 366 */ "ccons ::= AS generated", + /* 367 */ "conslist_opt ::= COMMA conslist", + /* 368 */ "conslist ::= conslist tconscomma tcons", + /* 369 */ "conslist ::= tcons", + /* 370 */ "tconscomma ::=", + /* 371 */ "defer_subclause_opt ::= defer_subclause", + /* 372 */ "resolvetype ::= raisetype", + /* 373 */ "selectnowith ::= oneselect", + /* 374 */ "oneselect ::= values", + /* 375 */ "sclp ::= selcollist COMMA", + /* 376 */ "as ::= ID|STRING", + /* 377 */ "returning ::=", + /* 378 */ "expr ::= term", + /* 379 */ "likeop ::= LIKE_KW|MATCH", + /* 380 */ "exprlist ::= nexprlist", + /* 381 */ "nmnum ::= plus_num", + /* 382 */ "nmnum ::= nm", + /* 383 */ "nmnum ::= ON", + /* 384 */ "nmnum ::= DELETE", + /* 385 */ "nmnum ::= DEFAULT", + /* 386 */ "plus_num ::= INTEGER|FLOAT", + /* 387 */ "foreach_clause ::=", + /* 388 */ "foreach_clause ::= FOR EACH ROW", + /* 389 */ "trnm ::= nm", + /* 390 */ "tridxby ::=", + /* 391 */ "database_kw_opt ::= DATABASE", + /* 392 */ "database_kw_opt ::=", + /* 393 */ "kwcolumn_opt ::=", + /* 394 */ "kwcolumn_opt ::= COLUMNKW", + /* 395 */ "vtabarglist ::= vtabarg", + /* 396 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 397 */ "vtabarg ::= vtabarg vtabargtoken", + /* 398 */ "anylist ::=", + /* 399 */ "anylist ::= anylist LP anylist RP", + /* 400 */ "anylist ::= anylist ANY", + /* 401 */ "with ::=", +}; +#endif /* NDEBUG */ - /* If rc is not SQLITE_OK at this point, then either the malloc - ** subsystem could not be initialized or the system failed to allocate - ** the pInitMutex mutex. Return an error in either case. */ - if( rc!=SQLITE_OK ){ - return rc; - } - /* Do the rest of the initialization under the recursive mutex so - ** that we will be able to handle recursive calls into - ** sqlite3_initialize(). The recursive calls normally come through - ** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other - ** recursive calls might also be possible. - ** - ** IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls - ** to the xInit method, so the xInit method need not be threadsafe. - ** - ** The following mutex is what serializes access to the appdef pcache xInit - ** methods. The sqlite3_pcache_methods.xInit() all is embedded in the - ** call to sqlite3PcacheInitialize(). - */ - sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex); - if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){ - sqlite3GlobalConfig.inProgress = 1; -#ifdef SQLITE_ENABLE_SQLLOG - { - extern void sqlite3_init_sqllog(void); - sqlite3_init_sqllog(); - } -#endif - memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions)); - sqlite3RegisterBuiltinFunctions(); - if( sqlite3GlobalConfig.isPCacheInit==0 ){ - rc = sqlite3PcacheInitialize(); - } - if( rc==SQLITE_OK ){ - sqlite3GlobalConfig.isPCacheInit = 1; - rc = sqlite3OsInit(); - } - if( rc==SQLITE_OK ){ - sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, - sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); - sqlite3GlobalConfig.isInit = 1; -#ifdef SQLITE_EXTRA_INIT - bRunExtraInit = 1; -#endif - } - sqlite3GlobalConfig.inProgress = 0; - } - sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex); +#if YYSTACKDEPTH<=0 +/* +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. +*/ +static int yyGrowStack(yyParser *p){ + int newSize; + int idx; + yyStackEntry *pNew; - /* Go back under the static mutex and clean up the recursive - ** mutex to prevent a resource leak. - */ - sqlite3_mutex_enter(pMaster); - sqlite3GlobalConfig.nRefInitMutex--; - if( sqlite3GlobalConfig.nRefInitMutex<=0 ){ - assert( sqlite3GlobalConfig.nRefInitMutex==0 ); - sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex); - sqlite3GlobalConfig.pInitMutex = 0; + newSize = p->yystksz*2 + 100; + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; + }else{ + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); } - sqlite3_mutex_leave(pMaster); - - /* The following is just a sanity check to make sure SQLite has - ** been compiled correctly. It is important to run this code, but - ** we don't want to run it too often and soak up CPU cycles for no - ** reason. So we run it once during initialization. - */ + if( pNew ){ + p->yystack = pNew; + p->yytos = &p->yystack[idx]; #ifndef NDEBUG -#ifndef SQLITE_OMIT_FLOATING_POINT - /* This section of code's only "output" is via assert() statements. */ - if ( rc==SQLITE_OK ){ - u64 x = (((u64)1)<<63)-1; - double y; - assert(sizeof(x)==8); - assert(sizeof(x)==sizeof(y)); - memcpy(&y, &x, 8); - assert( sqlite3IsNaN(y) ); - } -#endif + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); + } #endif - - /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT - ** compile-time option. - */ -#ifdef SQLITE_EXTRA_INIT - if( bRunExtraInit ){ - int SQLITE_EXTRA_INIT(const char*); - rc = SQLITE_EXTRA_INIT(0); + p->yystksz = newSize; } -#endif - - return rc; + return pNew==0; } +#endif -/* -** Undo the effects of sqlite3_initialize(). Must not be called while -** there are outstanding database connections or memory allocations or -** while any part of SQLite is otherwise in use in any thread. This -** routine is not threadsafe. But it is safe to invoke this routine -** on when SQLite is already shut down. If SQLite is already shut down -** when this routine is invoked, then this routine is a harmless no-op. +/* Datatype of the argument to the memory allocated passed as the +** second argument to sqlite3ParserAlloc() below. This can be changed by +** putting an appropriate #define in the %include section of the input +** grammar. */ -SQLITE_API int sqlite3_shutdown(void){ -#ifdef SQLITE_OMIT_WSD - int rc = sqlite3_wsd_init(4096, 24); - if( rc!=SQLITE_OK ){ - return rc; - } +#ifndef YYMALLOCARGTYPE +# define YYMALLOCARGTYPE size_t #endif - if( sqlite3GlobalConfig.isInit ){ -#ifdef SQLITE_EXTRA_SHUTDOWN - void SQLITE_EXTRA_SHUTDOWN(void); - SQLITE_EXTRA_SHUTDOWN(); +/* Initialize a new parser that has already been allocated. +*/ +SQLITE_PRIVATE void sqlite3ParserInit(void *yypRawParser sqlite3ParserCTX_PDECL){ + yyParser *yypParser = (yyParser*)yypRawParser; + sqlite3ParserCTX_STORE +#ifdef YYTRACKMAXSTACKDEPTH + yypParser->yyhwm = 0; #endif - sqlite3_os_end(); - sqlite3_reset_auto_extension(); - sqlite3GlobalConfig.isInit = 0; - } - if( sqlite3GlobalConfig.isPCacheInit ){ - sqlite3PcacheShutdown(); - sqlite3GlobalConfig.isPCacheInit = 0; +#if YYSTACKDEPTH<=0 + yypParser->yytos = NULL; + yypParser->yystack = NULL; + yypParser->yystksz = 0; + if( yyGrowStack(yypParser) ){ + yypParser->yystack = &yypParser->yystk0; + yypParser->yystksz = 1; } - if( sqlite3GlobalConfig.isMallocInit ){ - sqlite3MallocEnd(); - sqlite3GlobalConfig.isMallocInit = 0; - -#ifndef SQLITE_OMIT_SHUTDOWN_DIRECTORIES - /* The heap subsystem has now been shutdown and these values are supposed - ** to be NULL or point to memory that was obtained from sqlite3_malloc(), - ** which would rely on that heap subsystem; therefore, make sure these - ** values cannot refer to heap memory that was just invalidated when the - ** heap subsystem was shutdown. This is only done if the current call to - ** this function resulted in the heap subsystem actually being shutdown. - */ - sqlite3_data_directory = 0; - sqlite3_temp_directory = 0; #endif - } - if( sqlite3GlobalConfig.isMutexInit ){ - sqlite3MutexEnd(); - sqlite3GlobalConfig.isMutexInit = 0; - } - - return SQLITE_OK; +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + yypParser->yytos = yypParser->yystack; + yypParser->yystack[0].stateno = 0; + yypParser->yystack[0].major = 0; +#if YYSTACKDEPTH>0 + yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; +#endif } +#ifndef sqlite3Parser_ENGINEALWAYSONSTACK /* -** This API allows applications to modify the global configuration of -** the SQLite library at run-time. +** This function allocates a new parser. +** The only argument is a pointer to a function which works like +** malloc. ** -** This routine should only be called when there are no outstanding -** database connections or memory allocations. This routine is not -** threadsafe. Failure to heed these warnings can lead to unpredictable -** behavior. +** Inputs: +** A pointer to the function used to allocate memory. +** +** Outputs: +** A pointer to a parser. This pointer is used in subsequent calls +** to sqlite3Parser and sqlite3ParserFree. */ -SQLITE_API int sqlite3_config(int op, ...){ - va_list ap; - int rc = SQLITE_OK; - - /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while - ** the SQLite library is in use. */ - if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; +SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) sqlite3ParserCTX_PDECL){ + yyParser *yypParser; + yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); + if( yypParser ){ + sqlite3ParserCTX_STORE + sqlite3ParserInit(yypParser sqlite3ParserCTX_PARAM); + } + return (void*)yypParser; +} +#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ - va_start(ap, op); - switch( op ){ - /* Mutex configuration options are only available in a threadsafe - ** compile. +/* The following function deletes the "minor type" or semantic value +** associated with a symbol. The symbol can be either a terminal +** or nonterminal. "yymajor" is the symbol code, and "yypminor" is +** a pointer to the value to be deleted. The code used to do the +** deletions is derived from the %destructor and/or %token_destructor +** directives of the input grammar. +*/ +static void yy_destructor( + yyParser *yypParser, /* The parser */ + YYCODETYPE yymajor, /* Type code for object to destroy */ + YYMINORTYPE *yypminor /* The object to be destroyed */ +){ + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH + switch( yymajor ){ + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are *not* used + ** inside the C code. */ -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ - case SQLITE_CONFIG_SINGLETHREAD: { - /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to - ** Single-thread. */ - sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */ - sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ - break; - } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ - case SQLITE_CONFIG_MULTITHREAD: { - /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to - ** Multi-thread. */ - sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ - sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ - break; - } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ - case SQLITE_CONFIG_SERIALIZED: { - /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to - ** Serialized. */ - sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ - sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */ +/********* Begin destructor definitions ***************************************/ + case 204: /* select */ + case 239: /* selectnowith */ + case 240: /* oneselect */ + case 252: /* values */ +{ +sqlite3SelectDelete(pParse->db, (yypminor->yy47)); +} break; - } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ - case SQLITE_CONFIG_MUTEX: { - /* Specify an alternative mutex implementation */ - sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*); + case 216: /* term */ + case 217: /* expr */ + case 246: /* where_opt */ + case 248: /* having_opt */ + case 260: /* on_opt */ + case 267: /* where_opt_ret */ + case 278: /* case_operand */ + case 280: /* case_else */ + case 283: /* vinto */ + case 290: /* when_clause */ + case 295: /* key_opt */ + case 311: /* filter_clause */ +{ +sqlite3ExprDelete(pParse->db, (yypminor->yy528)); +} break; - } -#endif -#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */ - case SQLITE_CONFIG_GETMUTEX: { - /* Retrieve the current mutex implementation */ - *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex; + case 221: /* eidlist_opt */ + case 231: /* sortlist */ + case 232: /* eidlist */ + case 244: /* selcollist */ + case 247: /* groupby_opt */ + case 249: /* orderby_opt */ + case 253: /* nexprlist */ + case 254: /* sclp */ + case 262: /* exprlist */ + case 268: /* setlist */ + case 277: /* paren_exprlist */ + case 279: /* case_exprlist */ + case 310: /* part_opt */ +{ +sqlite3ExprListDelete(pParse->db, (yypminor->yy322)); +} break; - } -#endif - - case SQLITE_CONFIG_MALLOC: { - /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a - ** single argument which is a pointer to an instance of the - ** sqlite3_mem_methods structure. The argument specifies alternative - ** low-level memory allocation routines to be used in place of the memory - ** allocation routines built into SQLite. */ - sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); + case 238: /* fullname */ + case 245: /* from */ + case 256: /* seltablist */ + case 257: /* stl_prefix */ + case 263: /* xfullname */ +{ +sqlite3SrcListDelete(pParse->db, (yypminor->yy131)); +} break; - } - case SQLITE_CONFIG_GETMALLOC: { - /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a - ** single argument which is a pointer to an instance of the - ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is - ** filled with the currently defined memory allocation routines. */ - if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault(); - *va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m; + case 241: /* wqlist */ +{ +sqlite3WithDelete(pParse->db, (yypminor->yy521)); +} break; - } - case SQLITE_CONFIG_MEMSTATUS: { - /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes - ** single argument of type int, interpreted as a boolean, which enables - ** or disables the collection of memory allocation statistics. */ - sqlite3GlobalConfig.bMemstat = va_arg(ap, int); + case 251: /* window_clause */ + case 306: /* windowdefn_list */ +{ +sqlite3WindowListDelete(pParse->db, (yypminor->yy41)); +} break; - } - case SQLITE_CONFIG_SCRATCH: { - /* EVIDENCE-OF: R-08404-60887 There are three arguments to - ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from - ** which the scratch allocations will be drawn, the size of each scratch - ** allocation (sz), and the maximum number of scratch allocations (N). */ - sqlite3GlobalConfig.pScratch = va_arg(ap, void*); - sqlite3GlobalConfig.szScratch = va_arg(ap, int); - sqlite3GlobalConfig.nScratch = va_arg(ap, int); + case 261: /* using_opt */ + case 264: /* idlist */ + case 270: /* idlist_opt */ +{ +sqlite3IdListDelete(pParse->db, (yypminor->yy254)); +} break; - } - case SQLITE_CONFIG_PAGECACHE: { - /* EVIDENCE-OF: R-18761-36601 There are three arguments to - ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem), - ** the size of each page cache line (sz), and the number of cache lines - ** (N). */ - sqlite3GlobalConfig.pPage = va_arg(ap, void*); - sqlite3GlobalConfig.szPage = va_arg(ap, int); - sqlite3GlobalConfig.nPage = va_arg(ap, int); + case 273: /* filter_over */ + case 307: /* windowdefn */ + case 308: /* window */ + case 309: /* frame_opt */ + case 312: /* over_clause */ +{ +sqlite3WindowDelete(pParse->db, (yypminor->yy41)); +} break; - } - case SQLITE_CONFIG_PCACHE_HDRSZ: { - /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes - ** a single parameter which is a pointer to an integer and writes into - ** that integer the number of extra bytes per page required for each page - ** in SQLITE_CONFIG_PAGECACHE. */ - *va_arg(ap, int*) = - sqlite3HeaderSizeBtree() + - sqlite3HeaderSizePcache() + - sqlite3HeaderSizePcache1(); + case 286: /* trigger_cmd_list */ + case 291: /* trigger_cmd */ +{ +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy33)); +} break; - } - - case SQLITE_CONFIG_PCACHE: { - /* no-op */ + case 288: /* trigger_event */ +{ +sqlite3IdListDelete(pParse->db, (yypminor->yy180).b); +} break; - } - case SQLITE_CONFIG_GETPCACHE: { - /* now an error */ - rc = SQLITE_ERROR; + case 314: /* frame_bound */ + case 315: /* frame_bound_s */ + case 316: /* frame_bound_e */ +{ +sqlite3ExprDelete(pParse->db, (yypminor->yy595).pExpr); +} break; - } +/********* End destructor definitions *****************************************/ + default: break; /* If no destructor action specified: do nothing */ + } +} - case SQLITE_CONFIG_PCACHE2: { - /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a - ** single argument which is a pointer to an sqlite3_pcache_methods2 - ** object. This object specifies the interface to a custom page cache - ** implementation. */ - sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*); - break; - } - case SQLITE_CONFIG_GETPCACHE2: { - /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a - ** single argument which is a pointer to an sqlite3_pcache_methods2 - ** object. SQLite copies of the current page cache implementation into - ** that object. */ - if( sqlite3GlobalConfig.pcache2.xInit==0 ){ - sqlite3PCacheSetDefault(); - } - *va_arg(ap, sqlite3_pcache_methods2*) = sqlite3GlobalConfig.pcache2; - break; - } +/* +** Pop the parser's stack once. +** +** If there is a destructor routine associated with the token which +** is popped from the stack, then call it. +*/ +static void yy_pop_parser_stack(yyParser *pParser){ + yyStackEntry *yytos; + assert( pParser->yytos!=0 ); + assert( pParser->yytos > pParser->yystack ); + yytos = pParser->yytos--; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sPopping %s\n", + yyTracePrompt, + yyTokenName[yytos->major]); + } +#endif + yy_destructor(pParser, yytos->major, &yytos->minor); +} -/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only -** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or -** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ -#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) - case SQLITE_CONFIG_HEAP: { - /* EVIDENCE-OF: R-19854-42126 There are three arguments to - ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the - ** number of bytes in the memory buffer, and the minimum allocation size. - */ - sqlite3GlobalConfig.pHeap = va_arg(ap, void*); - sqlite3GlobalConfig.nHeap = va_arg(ap, int); - sqlite3GlobalConfig.mnReq = va_arg(ap, int); +/* +** Clear all secondary memory allocations from the parser +*/ +SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ + yyParser *pParser = (yyParser*)p; + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); +#if YYSTACKDEPTH<=0 + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); +#endif +} - if( sqlite3GlobalConfig.mnReq<1 ){ - sqlite3GlobalConfig.mnReq = 1; - }else if( sqlite3GlobalConfig.mnReq>(1<<12) ){ - /* cap min request size at 2^12 */ - sqlite3GlobalConfig.mnReq = (1<<12); - } +#ifndef sqlite3Parser_ENGINEALWAYSONSTACK +/* +** Deallocate and destroy a parser. Destructors are called for +** all stack elements before shutting the parser down. +** +** If the YYPARSEFREENEVERNULL macro exists (for example because it +** is defined in a %include section of the input grammar) then it is +** assumed that the input pointer is never NULL. +*/ +SQLITE_PRIVATE void sqlite3ParserFree( + void *p, /* The parser to be deleted */ + void (*freeProc)(void*) /* Function used to reclaim memory */ +){ +#ifndef YYPARSEFREENEVERNULL + if( p==0 ) return; +#endif + sqlite3ParserFinalize(p); + (*freeProc)(p); +} +#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */ - if( sqlite3GlobalConfig.pHeap==0 ){ - /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer) - ** is NULL, then SQLite reverts to using its default memory allocator - ** (the system malloc() implementation), undoing any prior invocation of - ** SQLITE_CONFIG_MALLOC. - ** - ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to - ** revert to its default implementation when sqlite3_initialize() is run - */ - memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m)); - }else{ - /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the - ** alternative memory allocator is engaged to handle all of SQLites - ** memory allocation needs. */ -#ifdef SQLITE_ENABLE_MEMSYS3 - sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3(); +/* +** Return the peak depth of the stack for a parser. +*/ +#ifdef YYTRACKMAXSTACKDEPTH +SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){ + yyParser *pParser = (yyParser*)p; + return pParser->yyhwm; +} #endif -#ifdef SQLITE_ENABLE_MEMSYS5 - sqlite3GlobalConfig.m = *sqlite3MemGetMemsys5(); + +/* This array of booleans keeps track of the parser statement +** coverage. The element yycoverage[X][Y] is set when the parser +** is in state X and has a lookahead token Y. In a well-tested +** systems, every element of this matrix should end up being set. +*/ +#if defined(YYCOVERAGE) +static unsigned char yycoverage[YYNSTATE][YYNTOKEN]; #endif + +/* +** Write into out a description of every state/lookahead combination that +** +** (1) has not been used by the parser, and +** (2) is not a syntax error. +** +** Return the number of missed state/lookahead combinations. +*/ +#if defined(YYCOVERAGE) +SQLITE_PRIVATE int sqlite3ParserCoverage(FILE *out){ + int stateno, iLookAhead, i; + int nMissed = 0; + for(stateno=0; statenoYY_MAX_SHIFT ) return stateno; + assert( stateno <= YY_SHIFT_COUNT ); +#if defined(YYCOVERAGE) + yycoverage[stateno][iLookAhead] = 1; +#endif + do{ + i = yy_shift_ofst[stateno]; + assert( i>=0 ); + assert( i<=YY_ACTTAB_COUNT ); + assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); + assert( iLookAhead!=YYNOCODE ); + assert( iLookAhead < YYNTOKEN ); + i += iLookAhead; + assert( i<(int)YY_NLOOKAHEAD ); + if( yy_lookahead[i]!=iLookAhead ){ +#ifdef YYFALLBACK + YYCODETYPE iFallback; /* Fallback token */ + assert( iLookAhead %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) ); + if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; + } + } +#endif /* YYWILDCARD */ + return yy_default[stateno]; + }else{ + assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) ); + return yy_action[i]; } + }while(1); +} - case SQLITE_CONFIG_COVERING_INDEX_SCAN: { - /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN - ** option takes a single integer argument which is interpreted as a - ** boolean in order to enable or disable the use of covering indices for - ** full table scans in the query optimizer. */ - sqlite3GlobalConfig.bUseCis = va_arg(ap, int); - break; +/* +** Find the appropriate action for a parser given the non-terminal +** look-ahead token iLookAhead. +*/ +static YYACTIONTYPE yy_find_reduce_action( + YYACTIONTYPE stateno, /* Current state number */ + YYCODETYPE iLookAhead /* The look-ahead token */ +){ + int i; +#ifdef YYERRORSYMBOL + if( stateno>YY_REDUCE_COUNT ){ + return yy_default[stateno]; + } +#else + assert( stateno<=YY_REDUCE_COUNT ); +#endif + i = yy_reduce_ofst[stateno]; + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; +#ifdef YYERRORSYMBOL + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + return yy_default[stateno]; + } +#else + assert( i>=0 && iyytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will execute if the parser + ** stack every overflows */ +/******** Begin %stack_overflow code ******************************************/ + + sqlite3ErrorMsg(pParse, "parser stack overflow"); +/******** End %stack_overflow code ********************************************/ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */ + sqlite3ParserCTX_STORE +} + +/* +** Print tracing information for a SHIFT action +*/ +#ifndef NDEBUG +static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){ + if( yyTraceFILE ){ + if( yyNewStateyytos->major], + yyNewState); + }else{ + fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n", + yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major], + yyNewState - YY_MIN_REDUCE); } + } +} +#else +# define yyTraceShift(X,Y,Z) +#endif -#ifdef SQLITE_ENABLE_SQLLOG - case SQLITE_CONFIG_SQLLOG: { - typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); - sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); - sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); - break; +/* +** Perform a shift action. +*/ +static void yy_shift( + yyParser *yypParser, /* The parser to be shifted */ + YYACTIONTYPE yyNewState, /* The new state to shift in */ + YYCODETYPE yyMajor, /* The major token to shift in */ + sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */ +){ + yyStackEntry *yytos; + yypParser->yytos++; +#ifdef YYTRACKMAXSTACKDEPTH + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yytos>yypParser->yystackEnd ){ + yypParser->yytos--; + yyStackOverflow(yypParser); + return; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ + if( yyGrowStack(yypParser) ){ + yypParser->yytos--; + yyStackOverflow(yypParser); + return; } + } #endif + if( yyNewState > YY_MAX_SHIFT ){ + yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yytos = yypParser->yytos; + yytos->stateno = yyNewState; + yytos->major = yyMajor; + yytos->minor.yy0 = yyMinor; + yyTraceShift(yypParser, yyNewState, "Shift"); +} + +/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side +** of that rule */ +static const YYCODETYPE yyRuleInfoLhs[] = { + 189, /* (0) explain ::= EXPLAIN */ + 189, /* (1) explain ::= EXPLAIN QUERY PLAN */ + 188, /* (2) cmdx ::= cmd */ + 190, /* (3) cmd ::= BEGIN transtype trans_opt */ + 191, /* (4) transtype ::= */ + 191, /* (5) transtype ::= DEFERRED */ + 191, /* (6) transtype ::= IMMEDIATE */ + 191, /* (7) transtype ::= EXCLUSIVE */ + 190, /* (8) cmd ::= COMMIT|END trans_opt */ + 190, /* (9) cmd ::= ROLLBACK trans_opt */ + 190, /* (10) cmd ::= SAVEPOINT nm */ + 190, /* (11) cmd ::= RELEASE savepoint_opt nm */ + 190, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + 195, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + 197, /* (14) createkw ::= CREATE */ + 199, /* (15) ifnotexists ::= */ + 199, /* (16) ifnotexists ::= IF NOT EXISTS */ + 198, /* (17) temp ::= TEMP */ + 198, /* (18) temp ::= */ + 196, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + 196, /* (20) create_table_args ::= AS select */ + 203, /* (21) table_option_set ::= */ + 203, /* (22) table_option_set ::= table_option_set COMMA table_option */ + 205, /* (23) table_option ::= WITHOUT nm */ + 205, /* (24) table_option ::= nm */ + 206, /* (25) columnname ::= nm typetoken */ + 208, /* (26) typetoken ::= */ + 208, /* (27) typetoken ::= typename LP signed RP */ + 208, /* (28) typetoken ::= typename LP signed COMMA signed RP */ + 209, /* (29) typename ::= typename ID|STRING */ + 213, /* (30) scanpt ::= */ + 214, /* (31) scantok ::= */ + 215, /* (32) ccons ::= CONSTRAINT nm */ + 215, /* (33) ccons ::= DEFAULT scantok term */ + 215, /* (34) ccons ::= DEFAULT LP expr RP */ + 215, /* (35) ccons ::= DEFAULT PLUS scantok term */ + 215, /* (36) ccons ::= DEFAULT MINUS scantok term */ + 215, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ + 215, /* (38) ccons ::= NOT NULL onconf */ + 215, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + 215, /* (40) ccons ::= UNIQUE onconf */ + 215, /* (41) ccons ::= CHECK LP expr RP */ + 215, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ + 215, /* (43) ccons ::= defer_subclause */ + 215, /* (44) ccons ::= COLLATE ID|STRING */ + 224, /* (45) generated ::= LP expr RP */ + 224, /* (46) generated ::= LP expr RP ID */ + 220, /* (47) autoinc ::= */ + 220, /* (48) autoinc ::= AUTOINCR */ + 222, /* (49) refargs ::= */ + 222, /* (50) refargs ::= refargs refarg */ + 225, /* (51) refarg ::= MATCH nm */ + 225, /* (52) refarg ::= ON INSERT refact */ + 225, /* (53) refarg ::= ON DELETE refact */ + 225, /* (54) refarg ::= ON UPDATE refact */ + 226, /* (55) refact ::= SET NULL */ + 226, /* (56) refact ::= SET DEFAULT */ + 226, /* (57) refact ::= CASCADE */ + 226, /* (58) refact ::= RESTRICT */ + 226, /* (59) refact ::= NO ACTION */ + 223, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + 223, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 227, /* (62) init_deferred_pred_opt ::= */ + 227, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + 227, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 202, /* (65) conslist_opt ::= */ + 229, /* (66) tconscomma ::= COMMA */ + 230, /* (67) tcons ::= CONSTRAINT nm */ + 230, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + 230, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ + 230, /* (70) tcons ::= CHECK LP expr RP onconf */ + 230, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 233, /* (72) defer_subclause_opt ::= */ + 218, /* (73) onconf ::= */ + 218, /* (74) onconf ::= ON CONFLICT resolvetype */ + 234, /* (75) orconf ::= */ + 234, /* (76) orconf ::= OR resolvetype */ + 235, /* (77) resolvetype ::= IGNORE */ + 235, /* (78) resolvetype ::= REPLACE */ + 190, /* (79) cmd ::= DROP TABLE ifexists fullname */ + 237, /* (80) ifexists ::= IF EXISTS */ + 237, /* (81) ifexists ::= */ + 190, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + 190, /* (83) cmd ::= DROP VIEW ifexists fullname */ + 190, /* (84) cmd ::= select */ + 204, /* (85) select ::= WITH wqlist selectnowith */ + 204, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ + 204, /* (87) select ::= selectnowith */ + 239, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ + 242, /* (89) multiselect_op ::= UNION */ + 242, /* (90) multiselect_op ::= UNION ALL */ + 242, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ + 240, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + 240, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + 252, /* (94) values ::= VALUES LP nexprlist RP */ + 252, /* (95) values ::= values COMMA LP nexprlist RP */ + 243, /* (96) distinct ::= DISTINCT */ + 243, /* (97) distinct ::= ALL */ + 243, /* (98) distinct ::= */ + 254, /* (99) sclp ::= */ + 244, /* (100) selcollist ::= sclp scanpt expr scanpt as */ + 244, /* (101) selcollist ::= sclp scanpt STAR */ + 244, /* (102) selcollist ::= sclp scanpt nm DOT STAR */ + 255, /* (103) as ::= AS nm */ + 255, /* (104) as ::= */ + 245, /* (105) from ::= */ + 245, /* (106) from ::= FROM seltablist */ + 257, /* (107) stl_prefix ::= seltablist joinop */ + 257, /* (108) stl_prefix ::= */ + 256, /* (109) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + 256, /* (110) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + 256, /* (111) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + 256, /* (112) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + 200, /* (113) dbnm ::= */ + 200, /* (114) dbnm ::= DOT nm */ + 238, /* (115) fullname ::= nm */ + 238, /* (116) fullname ::= nm DOT nm */ + 263, /* (117) xfullname ::= nm */ + 263, /* (118) xfullname ::= nm DOT nm */ + 263, /* (119) xfullname ::= nm DOT nm AS nm */ + 263, /* (120) xfullname ::= nm AS nm */ + 258, /* (121) joinop ::= COMMA|JOIN */ + 258, /* (122) joinop ::= JOIN_KW JOIN */ + 258, /* (123) joinop ::= JOIN_KW nm JOIN */ + 258, /* (124) joinop ::= JOIN_KW nm nm JOIN */ + 260, /* (125) on_opt ::= ON expr */ + 260, /* (126) on_opt ::= */ + 259, /* (127) indexed_opt ::= */ + 259, /* (128) indexed_opt ::= INDEXED BY nm */ + 259, /* (129) indexed_opt ::= NOT INDEXED */ + 261, /* (130) using_opt ::= USING LP idlist RP */ + 261, /* (131) using_opt ::= */ + 249, /* (132) orderby_opt ::= */ + 249, /* (133) orderby_opt ::= ORDER BY sortlist */ + 231, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */ + 231, /* (135) sortlist ::= expr sortorder nulls */ + 219, /* (136) sortorder ::= ASC */ + 219, /* (137) sortorder ::= DESC */ + 219, /* (138) sortorder ::= */ + 265, /* (139) nulls ::= NULLS FIRST */ + 265, /* (140) nulls ::= NULLS LAST */ + 265, /* (141) nulls ::= */ + 247, /* (142) groupby_opt ::= */ + 247, /* (143) groupby_opt ::= GROUP BY nexprlist */ + 248, /* (144) having_opt ::= */ + 248, /* (145) having_opt ::= HAVING expr */ + 250, /* (146) limit_opt ::= */ + 250, /* (147) limit_opt ::= LIMIT expr */ + 250, /* (148) limit_opt ::= LIMIT expr OFFSET expr */ + 250, /* (149) limit_opt ::= LIMIT expr COMMA expr */ + 190, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ + 246, /* (151) where_opt ::= */ + 246, /* (152) where_opt ::= WHERE expr */ + 267, /* (153) where_opt_ret ::= */ + 267, /* (154) where_opt_ret ::= WHERE expr */ + 267, /* (155) where_opt_ret ::= RETURNING selcollist */ + 267, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */ + 190, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ + 268, /* (158) setlist ::= setlist COMMA nm EQ expr */ + 268, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */ + 268, /* (160) setlist ::= nm EQ expr */ + 268, /* (161) setlist ::= LP idlist RP EQ expr */ + 190, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + 190, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 271, /* (164) upsert ::= */ + 271, /* (165) upsert ::= RETURNING selcollist */ + 271, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + 271, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + 271, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */ + 271, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + 272, /* (170) returning ::= RETURNING selcollist */ + 269, /* (171) insert_cmd ::= INSERT orconf */ + 269, /* (172) insert_cmd ::= REPLACE */ + 270, /* (173) idlist_opt ::= */ + 270, /* (174) idlist_opt ::= LP idlist RP */ + 264, /* (175) idlist ::= idlist COMMA nm */ + 264, /* (176) idlist ::= nm */ + 217, /* (177) expr ::= LP expr RP */ + 217, /* (178) expr ::= ID|INDEXED */ + 217, /* (179) expr ::= JOIN_KW */ + 217, /* (180) expr ::= nm DOT nm */ + 217, /* (181) expr ::= nm DOT nm DOT nm */ + 216, /* (182) term ::= NULL|FLOAT|BLOB */ + 216, /* (183) term ::= STRING */ + 216, /* (184) term ::= INTEGER */ + 217, /* (185) expr ::= VARIABLE */ + 217, /* (186) expr ::= expr COLLATE ID|STRING */ + 217, /* (187) expr ::= CAST LP expr AS typetoken RP */ + 217, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */ + 217, /* (189) expr ::= ID|INDEXED LP STAR RP */ + 217, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */ + 217, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */ + 216, /* (192) term ::= CTIME_KW */ + 217, /* (193) expr ::= LP nexprlist COMMA expr RP */ + 217, /* (194) expr ::= expr AND expr */ + 217, /* (195) expr ::= expr OR expr */ + 217, /* (196) expr ::= expr LT|GT|GE|LE expr */ + 217, /* (197) expr ::= expr EQ|NE expr */ + 217, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 217, /* (199) expr ::= expr PLUS|MINUS expr */ + 217, /* (200) expr ::= expr STAR|SLASH|REM expr */ + 217, /* (201) expr ::= expr CONCAT expr */ + 274, /* (202) likeop ::= NOT LIKE_KW|MATCH */ + 217, /* (203) expr ::= expr likeop expr */ + 217, /* (204) expr ::= expr likeop expr ESCAPE expr */ + 217, /* (205) expr ::= expr ISNULL|NOTNULL */ + 217, /* (206) expr ::= expr NOT NULL */ + 217, /* (207) expr ::= expr IS expr */ + 217, /* (208) expr ::= expr IS NOT expr */ + 217, /* (209) expr ::= NOT expr */ + 217, /* (210) expr ::= BITNOT expr */ + 217, /* (211) expr ::= PLUS|MINUS expr */ + 217, /* (212) expr ::= expr PTR expr */ + 275, /* (213) between_op ::= BETWEEN */ + 275, /* (214) between_op ::= NOT BETWEEN */ + 217, /* (215) expr ::= expr between_op expr AND expr */ + 276, /* (216) in_op ::= IN */ + 276, /* (217) in_op ::= NOT IN */ + 217, /* (218) expr ::= expr in_op LP exprlist RP */ + 217, /* (219) expr ::= LP select RP */ + 217, /* (220) expr ::= expr in_op LP select RP */ + 217, /* (221) expr ::= expr in_op nm dbnm paren_exprlist */ + 217, /* (222) expr ::= EXISTS LP select RP */ + 217, /* (223) expr ::= CASE case_operand case_exprlist case_else END */ + 279, /* (224) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 279, /* (225) case_exprlist ::= WHEN expr THEN expr */ + 280, /* (226) case_else ::= ELSE expr */ + 280, /* (227) case_else ::= */ + 278, /* (228) case_operand ::= expr */ + 278, /* (229) case_operand ::= */ + 262, /* (230) exprlist ::= */ + 253, /* (231) nexprlist ::= nexprlist COMMA expr */ + 253, /* (232) nexprlist ::= expr */ + 277, /* (233) paren_exprlist ::= */ + 277, /* (234) paren_exprlist ::= LP exprlist RP */ + 190, /* (235) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 281, /* (236) uniqueflag ::= UNIQUE */ + 281, /* (237) uniqueflag ::= */ + 221, /* (238) eidlist_opt ::= */ + 221, /* (239) eidlist_opt ::= LP eidlist RP */ + 232, /* (240) eidlist ::= eidlist COMMA nm collate sortorder */ + 232, /* (241) eidlist ::= nm collate sortorder */ + 282, /* (242) collate ::= */ + 282, /* (243) collate ::= COLLATE ID|STRING */ + 190, /* (244) cmd ::= DROP INDEX ifexists fullname */ + 190, /* (245) cmd ::= VACUUM vinto */ + 190, /* (246) cmd ::= VACUUM nm vinto */ + 283, /* (247) vinto ::= INTO expr */ + 283, /* (248) vinto ::= */ + 190, /* (249) cmd ::= PRAGMA nm dbnm */ + 190, /* (250) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 190, /* (251) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 190, /* (252) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 190, /* (253) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 211, /* (254) plus_num ::= PLUS INTEGER|FLOAT */ + 212, /* (255) minus_num ::= MINUS INTEGER|FLOAT */ + 190, /* (256) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 285, /* (257) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 287, /* (258) trigger_time ::= BEFORE|AFTER */ + 287, /* (259) trigger_time ::= INSTEAD OF */ + 287, /* (260) trigger_time ::= */ + 288, /* (261) trigger_event ::= DELETE|INSERT */ + 288, /* (262) trigger_event ::= UPDATE */ + 288, /* (263) trigger_event ::= UPDATE OF idlist */ + 290, /* (264) when_clause ::= */ + 290, /* (265) when_clause ::= WHEN expr */ + 286, /* (266) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 286, /* (267) trigger_cmd_list ::= trigger_cmd SEMI */ + 292, /* (268) trnm ::= nm DOT nm */ + 293, /* (269) tridxby ::= INDEXED BY nm */ + 293, /* (270) tridxby ::= NOT INDEXED */ + 291, /* (271) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + 291, /* (272) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + 291, /* (273) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + 291, /* (274) trigger_cmd ::= scanpt select scanpt */ + 217, /* (275) expr ::= RAISE LP IGNORE RP */ + 217, /* (276) expr ::= RAISE LP raisetype COMMA nm RP */ + 236, /* (277) raisetype ::= ROLLBACK */ + 236, /* (278) raisetype ::= ABORT */ + 236, /* (279) raisetype ::= FAIL */ + 190, /* (280) cmd ::= DROP TRIGGER ifexists fullname */ + 190, /* (281) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 190, /* (282) cmd ::= DETACH database_kw_opt expr */ + 295, /* (283) key_opt ::= */ + 295, /* (284) key_opt ::= KEY expr */ + 190, /* (285) cmd ::= REINDEX */ + 190, /* (286) cmd ::= REINDEX nm dbnm */ + 190, /* (287) cmd ::= ANALYZE */ + 190, /* (288) cmd ::= ANALYZE nm dbnm */ + 190, /* (289) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 190, /* (290) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 190, /* (291) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + 296, /* (292) add_column_fullname ::= fullname */ + 190, /* (293) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 190, /* (294) cmd ::= create_vtab */ + 190, /* (295) cmd ::= create_vtab LP vtabarglist RP */ + 298, /* (296) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 300, /* (297) vtabarg ::= */ + 301, /* (298) vtabargtoken ::= ANY */ + 301, /* (299) vtabargtoken ::= lp anylist RP */ + 302, /* (300) lp ::= LP */ + 266, /* (301) with ::= WITH wqlist */ + 266, /* (302) with ::= WITH RECURSIVE wqlist */ + 305, /* (303) wqas ::= AS */ + 305, /* (304) wqas ::= AS MATERIALIZED */ + 305, /* (305) wqas ::= AS NOT MATERIALIZED */ + 304, /* (306) wqitem ::= nm eidlist_opt wqas LP select RP */ + 241, /* (307) wqlist ::= wqitem */ + 241, /* (308) wqlist ::= wqlist COMMA wqitem */ + 306, /* (309) windowdefn_list ::= windowdefn */ + 306, /* (310) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 307, /* (311) windowdefn ::= nm AS LP window RP */ + 308, /* (312) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 308, /* (313) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 308, /* (314) window ::= ORDER BY sortlist frame_opt */ + 308, /* (315) window ::= nm ORDER BY sortlist frame_opt */ + 308, /* (316) window ::= frame_opt */ + 308, /* (317) window ::= nm frame_opt */ + 309, /* (318) frame_opt ::= */ + 309, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 309, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 313, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ + 315, /* (322) frame_bound_s ::= frame_bound */ + 315, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ + 316, /* (324) frame_bound_e ::= frame_bound */ + 316, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 314, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ + 314, /* (327) frame_bound ::= CURRENT ROW */ + 317, /* (328) frame_exclude_opt ::= */ + 317, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 318, /* (330) frame_exclude ::= NO OTHERS */ + 318, /* (331) frame_exclude ::= CURRENT ROW */ + 318, /* (332) frame_exclude ::= GROUP|TIES */ + 251, /* (333) window_clause ::= WINDOW windowdefn_list */ + 273, /* (334) filter_over ::= filter_clause over_clause */ + 273, /* (335) filter_over ::= over_clause */ + 273, /* (336) filter_over ::= filter_clause */ + 312, /* (337) over_clause ::= OVER LP window RP */ + 312, /* (338) over_clause ::= OVER nm */ + 311, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ + 185, /* (340) input ::= cmdlist */ + 186, /* (341) cmdlist ::= cmdlist ecmd */ + 186, /* (342) cmdlist ::= ecmd */ + 187, /* (343) ecmd ::= SEMI */ + 187, /* (344) ecmd ::= cmdx SEMI */ + 187, /* (345) ecmd ::= explain cmdx SEMI */ + 192, /* (346) trans_opt ::= */ + 192, /* (347) trans_opt ::= TRANSACTION */ + 192, /* (348) trans_opt ::= TRANSACTION nm */ + 194, /* (349) savepoint_opt ::= SAVEPOINT */ + 194, /* (350) savepoint_opt ::= */ + 190, /* (351) cmd ::= create_table create_table_args */ + 203, /* (352) table_option_set ::= table_option */ + 201, /* (353) columnlist ::= columnlist COMMA columnname carglist */ + 201, /* (354) columnlist ::= columnname carglist */ + 193, /* (355) nm ::= ID|INDEXED */ + 193, /* (356) nm ::= STRING */ + 193, /* (357) nm ::= JOIN_KW */ + 208, /* (358) typetoken ::= typename */ + 209, /* (359) typename ::= ID|STRING */ + 210, /* (360) signed ::= plus_num */ + 210, /* (361) signed ::= minus_num */ + 207, /* (362) carglist ::= carglist ccons */ + 207, /* (363) carglist ::= */ + 215, /* (364) ccons ::= NULL onconf */ + 215, /* (365) ccons ::= GENERATED ALWAYS AS generated */ + 215, /* (366) ccons ::= AS generated */ + 202, /* (367) conslist_opt ::= COMMA conslist */ + 228, /* (368) conslist ::= conslist tconscomma tcons */ + 228, /* (369) conslist ::= tcons */ + 229, /* (370) tconscomma ::= */ + 233, /* (371) defer_subclause_opt ::= defer_subclause */ + 235, /* (372) resolvetype ::= raisetype */ + 239, /* (373) selectnowith ::= oneselect */ + 240, /* (374) oneselect ::= values */ + 254, /* (375) sclp ::= selcollist COMMA */ + 255, /* (376) as ::= ID|STRING */ + 272, /* (377) returning ::= */ + 217, /* (378) expr ::= term */ + 274, /* (379) likeop ::= LIKE_KW|MATCH */ + 262, /* (380) exprlist ::= nexprlist */ + 284, /* (381) nmnum ::= plus_num */ + 284, /* (382) nmnum ::= nm */ + 284, /* (383) nmnum ::= ON */ + 284, /* (384) nmnum ::= DELETE */ + 284, /* (385) nmnum ::= DEFAULT */ + 211, /* (386) plus_num ::= INTEGER|FLOAT */ + 289, /* (387) foreach_clause ::= */ + 289, /* (388) foreach_clause ::= FOR EACH ROW */ + 292, /* (389) trnm ::= nm */ + 293, /* (390) tridxby ::= */ + 294, /* (391) database_kw_opt ::= DATABASE */ + 294, /* (392) database_kw_opt ::= */ + 297, /* (393) kwcolumn_opt ::= */ + 297, /* (394) kwcolumn_opt ::= COLUMNKW */ + 299, /* (395) vtabarglist ::= vtabarg */ + 299, /* (396) vtabarglist ::= vtabarglist COMMA vtabarg */ + 300, /* (397) vtabarg ::= vtabarg vtabargtoken */ + 303, /* (398) anylist ::= */ + 303, /* (399) anylist ::= anylist LP anylist RP */ + 303, /* (400) anylist ::= anylist ANY */ + 266, /* (401) with ::= */ +}; - case SQLITE_CONFIG_MMAP_SIZE: { - /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit - ** integer (sqlite3_int64) values that are the default mmap size limit - ** (the default setting for PRAGMA mmap_size) and the maximum allowed - ** mmap size limit. */ - sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); - sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); - /* EVIDENCE-OF: R-53367-43190 If either argument to this option is - ** negative, then that argument is changed to its compile-time default. +/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number +** of symbols on the right-hand side of that rule. */ +static const signed char yyRuleInfoNRhs[] = { + -1, /* (0) explain ::= EXPLAIN */ + -3, /* (1) explain ::= EXPLAIN QUERY PLAN */ + -1, /* (2) cmdx ::= cmd */ + -3, /* (3) cmd ::= BEGIN transtype trans_opt */ + 0, /* (4) transtype ::= */ + -1, /* (5) transtype ::= DEFERRED */ + -1, /* (6) transtype ::= IMMEDIATE */ + -1, /* (7) transtype ::= EXCLUSIVE */ + -2, /* (8) cmd ::= COMMIT|END trans_opt */ + -2, /* (9) cmd ::= ROLLBACK trans_opt */ + -2, /* (10) cmd ::= SAVEPOINT nm */ + -3, /* (11) cmd ::= RELEASE savepoint_opt nm */ + -5, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + -6, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + -1, /* (14) createkw ::= CREATE */ + 0, /* (15) ifnotexists ::= */ + -3, /* (16) ifnotexists ::= IF NOT EXISTS */ + -1, /* (17) temp ::= TEMP */ + 0, /* (18) temp ::= */ + -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */ + -2, /* (20) create_table_args ::= AS select */ + 0, /* (21) table_option_set ::= */ + -3, /* (22) table_option_set ::= table_option_set COMMA table_option */ + -2, /* (23) table_option ::= WITHOUT nm */ + -1, /* (24) table_option ::= nm */ + -2, /* (25) columnname ::= nm typetoken */ + 0, /* (26) typetoken ::= */ + -4, /* (27) typetoken ::= typename LP signed RP */ + -6, /* (28) typetoken ::= typename LP signed COMMA signed RP */ + -2, /* (29) typename ::= typename ID|STRING */ + 0, /* (30) scanpt ::= */ + 0, /* (31) scantok ::= */ + -2, /* (32) ccons ::= CONSTRAINT nm */ + -3, /* (33) ccons ::= DEFAULT scantok term */ + -4, /* (34) ccons ::= DEFAULT LP expr RP */ + -4, /* (35) ccons ::= DEFAULT PLUS scantok term */ + -4, /* (36) ccons ::= DEFAULT MINUS scantok term */ + -3, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */ + -3, /* (38) ccons ::= NOT NULL onconf */ + -5, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + -2, /* (40) ccons ::= UNIQUE onconf */ + -4, /* (41) ccons ::= CHECK LP expr RP */ + -4, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */ + -1, /* (43) ccons ::= defer_subclause */ + -2, /* (44) ccons ::= COLLATE ID|STRING */ + -3, /* (45) generated ::= LP expr RP */ + -4, /* (46) generated ::= LP expr RP ID */ + 0, /* (47) autoinc ::= */ + -1, /* (48) autoinc ::= AUTOINCR */ + 0, /* (49) refargs ::= */ + -2, /* (50) refargs ::= refargs refarg */ + -2, /* (51) refarg ::= MATCH nm */ + -3, /* (52) refarg ::= ON INSERT refact */ + -3, /* (53) refarg ::= ON DELETE refact */ + -3, /* (54) refarg ::= ON UPDATE refact */ + -2, /* (55) refact ::= SET NULL */ + -2, /* (56) refact ::= SET DEFAULT */ + -1, /* (57) refact ::= CASCADE */ + -1, /* (58) refact ::= RESTRICT */ + -2, /* (59) refact ::= NO ACTION */ + -3, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + -2, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 0, /* (62) init_deferred_pred_opt ::= */ + -2, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + -2, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 0, /* (65) conslist_opt ::= */ + -1, /* (66) tconscomma ::= COMMA */ + -2, /* (67) tcons ::= CONSTRAINT nm */ + -7, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + -5, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */ + -5, /* (70) tcons ::= CHECK LP expr RP onconf */ + -10, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 0, /* (72) defer_subclause_opt ::= */ + 0, /* (73) onconf ::= */ + -3, /* (74) onconf ::= ON CONFLICT resolvetype */ + 0, /* (75) orconf ::= */ + -2, /* (76) orconf ::= OR resolvetype */ + -1, /* (77) resolvetype ::= IGNORE */ + -1, /* (78) resolvetype ::= REPLACE */ + -4, /* (79) cmd ::= DROP TABLE ifexists fullname */ + -2, /* (80) ifexists ::= IF EXISTS */ + 0, /* (81) ifexists ::= */ + -9, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + -4, /* (83) cmd ::= DROP VIEW ifexists fullname */ + -1, /* (84) cmd ::= select */ + -3, /* (85) select ::= WITH wqlist selectnowith */ + -4, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */ + -1, /* (87) select ::= selectnowith */ + -3, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */ + -1, /* (89) multiselect_op ::= UNION */ + -2, /* (90) multiselect_op ::= UNION ALL */ + -1, /* (91) multiselect_op ::= EXCEPT|INTERSECT */ + -9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + -10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + -4, /* (94) values ::= VALUES LP nexprlist RP */ + -5, /* (95) values ::= values COMMA LP nexprlist RP */ + -1, /* (96) distinct ::= DISTINCT */ + -1, /* (97) distinct ::= ALL */ + 0, /* (98) distinct ::= */ + 0, /* (99) sclp ::= */ + -5, /* (100) selcollist ::= sclp scanpt expr scanpt as */ + -3, /* (101) selcollist ::= sclp scanpt STAR */ + -5, /* (102) selcollist ::= sclp scanpt nm DOT STAR */ + -2, /* (103) as ::= AS nm */ + 0, /* (104) as ::= */ + 0, /* (105) from ::= */ + -2, /* (106) from ::= FROM seltablist */ + -2, /* (107) stl_prefix ::= seltablist joinop */ + 0, /* (108) stl_prefix ::= */ + -7, /* (109) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + -9, /* (110) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + -7, /* (111) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + -7, /* (112) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + 0, /* (113) dbnm ::= */ + -2, /* (114) dbnm ::= DOT nm */ + -1, /* (115) fullname ::= nm */ + -3, /* (116) fullname ::= nm DOT nm */ + -1, /* (117) xfullname ::= nm */ + -3, /* (118) xfullname ::= nm DOT nm */ + -5, /* (119) xfullname ::= nm DOT nm AS nm */ + -3, /* (120) xfullname ::= nm AS nm */ + -1, /* (121) joinop ::= COMMA|JOIN */ + -2, /* (122) joinop ::= JOIN_KW JOIN */ + -3, /* (123) joinop ::= JOIN_KW nm JOIN */ + -4, /* (124) joinop ::= JOIN_KW nm nm JOIN */ + -2, /* (125) on_opt ::= ON expr */ + 0, /* (126) on_opt ::= */ + 0, /* (127) indexed_opt ::= */ + -3, /* (128) indexed_opt ::= INDEXED BY nm */ + -2, /* (129) indexed_opt ::= NOT INDEXED */ + -4, /* (130) using_opt ::= USING LP idlist RP */ + 0, /* (131) using_opt ::= */ + 0, /* (132) orderby_opt ::= */ + -3, /* (133) orderby_opt ::= ORDER BY sortlist */ + -5, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */ + -3, /* (135) sortlist ::= expr sortorder nulls */ + -1, /* (136) sortorder ::= ASC */ + -1, /* (137) sortorder ::= DESC */ + 0, /* (138) sortorder ::= */ + -2, /* (139) nulls ::= NULLS FIRST */ + -2, /* (140) nulls ::= NULLS LAST */ + 0, /* (141) nulls ::= */ + 0, /* (142) groupby_opt ::= */ + -3, /* (143) groupby_opt ::= GROUP BY nexprlist */ + 0, /* (144) having_opt ::= */ + -2, /* (145) having_opt ::= HAVING expr */ + 0, /* (146) limit_opt ::= */ + -2, /* (147) limit_opt ::= LIMIT expr */ + -4, /* (148) limit_opt ::= LIMIT expr OFFSET expr */ + -4, /* (149) limit_opt ::= LIMIT expr COMMA expr */ + -6, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ + 0, /* (151) where_opt ::= */ + -2, /* (152) where_opt ::= WHERE expr */ + 0, /* (153) where_opt_ret ::= */ + -2, /* (154) where_opt_ret ::= WHERE expr */ + -2, /* (155) where_opt_ret ::= RETURNING selcollist */ + -4, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */ + -9, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ + -5, /* (158) setlist ::= setlist COMMA nm EQ expr */ + -7, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */ + -3, /* (160) setlist ::= nm EQ expr */ + -5, /* (161) setlist ::= LP idlist RP EQ expr */ + -7, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + -8, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ + 0, /* (164) upsert ::= */ + -2, /* (165) upsert ::= RETURNING selcollist */ + -12, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ + -9, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ + -5, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */ + -8, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ + -2, /* (170) returning ::= RETURNING selcollist */ + -2, /* (171) insert_cmd ::= INSERT orconf */ + -1, /* (172) insert_cmd ::= REPLACE */ + 0, /* (173) idlist_opt ::= */ + -3, /* (174) idlist_opt ::= LP idlist RP */ + -3, /* (175) idlist ::= idlist COMMA nm */ + -1, /* (176) idlist ::= nm */ + -3, /* (177) expr ::= LP expr RP */ + -1, /* (178) expr ::= ID|INDEXED */ + -1, /* (179) expr ::= JOIN_KW */ + -3, /* (180) expr ::= nm DOT nm */ + -5, /* (181) expr ::= nm DOT nm DOT nm */ + -1, /* (182) term ::= NULL|FLOAT|BLOB */ + -1, /* (183) term ::= STRING */ + -1, /* (184) term ::= INTEGER */ + -1, /* (185) expr ::= VARIABLE */ + -3, /* (186) expr ::= expr COLLATE ID|STRING */ + -6, /* (187) expr ::= CAST LP expr AS typetoken RP */ + -5, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */ + -4, /* (189) expr ::= ID|INDEXED LP STAR RP */ + -6, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */ + -5, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */ + -1, /* (192) term ::= CTIME_KW */ + -5, /* (193) expr ::= LP nexprlist COMMA expr RP */ + -3, /* (194) expr ::= expr AND expr */ + -3, /* (195) expr ::= expr OR expr */ + -3, /* (196) expr ::= expr LT|GT|GE|LE expr */ + -3, /* (197) expr ::= expr EQ|NE expr */ + -3, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + -3, /* (199) expr ::= expr PLUS|MINUS expr */ + -3, /* (200) expr ::= expr STAR|SLASH|REM expr */ + -3, /* (201) expr ::= expr CONCAT expr */ + -2, /* (202) likeop ::= NOT LIKE_KW|MATCH */ + -3, /* (203) expr ::= expr likeop expr */ + -5, /* (204) expr ::= expr likeop expr ESCAPE expr */ + -2, /* (205) expr ::= expr ISNULL|NOTNULL */ + -3, /* (206) expr ::= expr NOT NULL */ + -3, /* (207) expr ::= expr IS expr */ + -4, /* (208) expr ::= expr IS NOT expr */ + -2, /* (209) expr ::= NOT expr */ + -2, /* (210) expr ::= BITNOT expr */ + -2, /* (211) expr ::= PLUS|MINUS expr */ + -3, /* (212) expr ::= expr PTR expr */ + -1, /* (213) between_op ::= BETWEEN */ + -2, /* (214) between_op ::= NOT BETWEEN */ + -5, /* (215) expr ::= expr between_op expr AND expr */ + -1, /* (216) in_op ::= IN */ + -2, /* (217) in_op ::= NOT IN */ + -5, /* (218) expr ::= expr in_op LP exprlist RP */ + -3, /* (219) expr ::= LP select RP */ + -5, /* (220) expr ::= expr in_op LP select RP */ + -5, /* (221) expr ::= expr in_op nm dbnm paren_exprlist */ + -4, /* (222) expr ::= EXISTS LP select RP */ + -5, /* (223) expr ::= CASE case_operand case_exprlist case_else END */ + -5, /* (224) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + -4, /* (225) case_exprlist ::= WHEN expr THEN expr */ + -2, /* (226) case_else ::= ELSE expr */ + 0, /* (227) case_else ::= */ + -1, /* (228) case_operand ::= expr */ + 0, /* (229) case_operand ::= */ + 0, /* (230) exprlist ::= */ + -3, /* (231) nexprlist ::= nexprlist COMMA expr */ + -1, /* (232) nexprlist ::= expr */ + 0, /* (233) paren_exprlist ::= */ + -3, /* (234) paren_exprlist ::= LP exprlist RP */ + -12, /* (235) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + -1, /* (236) uniqueflag ::= UNIQUE */ + 0, /* (237) uniqueflag ::= */ + 0, /* (238) eidlist_opt ::= */ + -3, /* (239) eidlist_opt ::= LP eidlist RP */ + -5, /* (240) eidlist ::= eidlist COMMA nm collate sortorder */ + -3, /* (241) eidlist ::= nm collate sortorder */ + 0, /* (242) collate ::= */ + -2, /* (243) collate ::= COLLATE ID|STRING */ + -4, /* (244) cmd ::= DROP INDEX ifexists fullname */ + -2, /* (245) cmd ::= VACUUM vinto */ + -3, /* (246) cmd ::= VACUUM nm vinto */ + -2, /* (247) vinto ::= INTO expr */ + 0, /* (248) vinto ::= */ + -3, /* (249) cmd ::= PRAGMA nm dbnm */ + -5, /* (250) cmd ::= PRAGMA nm dbnm EQ nmnum */ + -6, /* (251) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + -5, /* (252) cmd ::= PRAGMA nm dbnm EQ minus_num */ + -6, /* (253) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + -2, /* (254) plus_num ::= PLUS INTEGER|FLOAT */ + -2, /* (255) minus_num ::= MINUS INTEGER|FLOAT */ + -5, /* (256) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + -11, /* (257) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + -1, /* (258) trigger_time ::= BEFORE|AFTER */ + -2, /* (259) trigger_time ::= INSTEAD OF */ + 0, /* (260) trigger_time ::= */ + -1, /* (261) trigger_event ::= DELETE|INSERT */ + -1, /* (262) trigger_event ::= UPDATE */ + -3, /* (263) trigger_event ::= UPDATE OF idlist */ + 0, /* (264) when_clause ::= */ + -2, /* (265) when_clause ::= WHEN expr */ + -3, /* (266) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + -2, /* (267) trigger_cmd_list ::= trigger_cmd SEMI */ + -3, /* (268) trnm ::= nm DOT nm */ + -3, /* (269) tridxby ::= INDEXED BY nm */ + -2, /* (270) tridxby ::= NOT INDEXED */ + -9, /* (271) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ + -8, /* (272) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + -6, /* (273) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + -3, /* (274) trigger_cmd ::= scanpt select scanpt */ + -4, /* (275) expr ::= RAISE LP IGNORE RP */ + -6, /* (276) expr ::= RAISE LP raisetype COMMA nm RP */ + -1, /* (277) raisetype ::= ROLLBACK */ + -1, /* (278) raisetype ::= ABORT */ + -1, /* (279) raisetype ::= FAIL */ + -4, /* (280) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (281) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (282) cmd ::= DETACH database_kw_opt expr */ + 0, /* (283) key_opt ::= */ + -2, /* (284) key_opt ::= KEY expr */ + -1, /* (285) cmd ::= REINDEX */ + -3, /* (286) cmd ::= REINDEX nm dbnm */ + -1, /* (287) cmd ::= ANALYZE */ + -3, /* (288) cmd ::= ANALYZE nm dbnm */ + -6, /* (289) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -7, /* (290) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -6, /* (291) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ + -1, /* (292) add_column_fullname ::= fullname */ + -8, /* (293) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -1, /* (294) cmd ::= create_vtab */ + -4, /* (295) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (296) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (297) vtabarg ::= */ + -1, /* (298) vtabargtoken ::= ANY */ + -3, /* (299) vtabargtoken ::= lp anylist RP */ + -1, /* (300) lp ::= LP */ + -2, /* (301) with ::= WITH wqlist */ + -3, /* (302) with ::= WITH RECURSIVE wqlist */ + -1, /* (303) wqas ::= AS */ + -2, /* (304) wqas ::= AS MATERIALIZED */ + -3, /* (305) wqas ::= AS NOT MATERIALIZED */ + -6, /* (306) wqitem ::= nm eidlist_opt wqas LP select RP */ + -1, /* (307) wqlist ::= wqitem */ + -3, /* (308) wqlist ::= wqlist COMMA wqitem */ + -1, /* (309) windowdefn_list ::= windowdefn */ + -3, /* (310) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (311) windowdefn ::= nm AS LP window RP */ + -5, /* (312) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (313) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (314) window ::= ORDER BY sortlist frame_opt */ + -5, /* (315) window ::= nm ORDER BY sortlist frame_opt */ + -1, /* (316) window ::= frame_opt */ + -2, /* (317) window ::= nm frame_opt */ + 0, /* (318) frame_opt ::= */ + -3, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (322) frame_bound_s ::= frame_bound */ + -2, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (324) frame_bound_e ::= frame_bound */ + -2, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (327) frame_bound ::= CURRENT ROW */ + 0, /* (328) frame_exclude_opt ::= */ + -2, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (330) frame_exclude ::= NO OTHERS */ + -2, /* (331) frame_exclude ::= CURRENT ROW */ + -1, /* (332) frame_exclude ::= GROUP|TIES */ + -2, /* (333) window_clause ::= WINDOW windowdefn_list */ + -2, /* (334) filter_over ::= filter_clause over_clause */ + -1, /* (335) filter_over ::= over_clause */ + -1, /* (336) filter_over ::= filter_clause */ + -4, /* (337) over_clause ::= OVER LP window RP */ + -2, /* (338) over_clause ::= OVER nm */ + -5, /* (339) filter_clause ::= FILTER LP WHERE expr RP */ + -1, /* (340) input ::= cmdlist */ + -2, /* (341) cmdlist ::= cmdlist ecmd */ + -1, /* (342) cmdlist ::= ecmd */ + -1, /* (343) ecmd ::= SEMI */ + -2, /* (344) ecmd ::= cmdx SEMI */ + -3, /* (345) ecmd ::= explain cmdx SEMI */ + 0, /* (346) trans_opt ::= */ + -1, /* (347) trans_opt ::= TRANSACTION */ + -2, /* (348) trans_opt ::= TRANSACTION nm */ + -1, /* (349) savepoint_opt ::= SAVEPOINT */ + 0, /* (350) savepoint_opt ::= */ + -2, /* (351) cmd ::= create_table create_table_args */ + -1, /* (352) table_option_set ::= table_option */ + -4, /* (353) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (354) columnlist ::= columnname carglist */ + -1, /* (355) nm ::= ID|INDEXED */ + -1, /* (356) nm ::= STRING */ + -1, /* (357) nm ::= JOIN_KW */ + -1, /* (358) typetoken ::= typename */ + -1, /* (359) typename ::= ID|STRING */ + -1, /* (360) signed ::= plus_num */ + -1, /* (361) signed ::= minus_num */ + -2, /* (362) carglist ::= carglist ccons */ + 0, /* (363) carglist ::= */ + -2, /* (364) ccons ::= NULL onconf */ + -4, /* (365) ccons ::= GENERATED ALWAYS AS generated */ + -2, /* (366) ccons ::= AS generated */ + -2, /* (367) conslist_opt ::= COMMA conslist */ + -3, /* (368) conslist ::= conslist tconscomma tcons */ + -1, /* (369) conslist ::= tcons */ + 0, /* (370) tconscomma ::= */ + -1, /* (371) defer_subclause_opt ::= defer_subclause */ + -1, /* (372) resolvetype ::= raisetype */ + -1, /* (373) selectnowith ::= oneselect */ + -1, /* (374) oneselect ::= values */ + -2, /* (375) sclp ::= selcollist COMMA */ + -1, /* (376) as ::= ID|STRING */ + 0, /* (377) returning ::= */ + -1, /* (378) expr ::= term */ + -1, /* (379) likeop ::= LIKE_KW|MATCH */ + -1, /* (380) exprlist ::= nexprlist */ + -1, /* (381) nmnum ::= plus_num */ + -1, /* (382) nmnum ::= nm */ + -1, /* (383) nmnum ::= ON */ + -1, /* (384) nmnum ::= DELETE */ + -1, /* (385) nmnum ::= DEFAULT */ + -1, /* (386) plus_num ::= INTEGER|FLOAT */ + 0, /* (387) foreach_clause ::= */ + -3, /* (388) foreach_clause ::= FOR EACH ROW */ + -1, /* (389) trnm ::= nm */ + 0, /* (390) tridxby ::= */ + -1, /* (391) database_kw_opt ::= DATABASE */ + 0, /* (392) database_kw_opt ::= */ + 0, /* (393) kwcolumn_opt ::= */ + -1, /* (394) kwcolumn_opt ::= COLUMNKW */ + -1, /* (395) vtabarglist ::= vtabarg */ + -3, /* (396) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (397) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (398) anylist ::= */ + -4, /* (399) anylist ::= anylist LP anylist RP */ + -2, /* (400) anylist ::= anylist ANY */ + 0, /* (401) with ::= */ +}; + +static void yy_accept(yyParser*); /* Forward Declaration */ + +/* +** Perform a reduce action and the shift that must immediately +** follow the reduce. +** +** The yyLookahead and yyLookaheadToken parameters provide reduce actions +** access to the lookahead token (if any). The yyLookahead will be YYNOCODE +** if the lookahead token has already been consumed. As this procedure is +** only called from one place, optimizing compilers will in-line it, which +** means that the extra parameters have no performance impact. +*/ +static YYACTIONTYPE yy_reduce( + yyParser *yypParser, /* The parser */ + unsigned int yyruleno, /* Number of the rule by which to reduce */ + int yyLookahead, /* Lookahead token, or YYNOCODE if none */ + sqlite3ParserTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ + sqlite3ParserCTX_PDECL /* %extra_context */ +){ + int yygoto; /* The next state */ + YYACTIONTYPE yyact; /* The next action */ + yyStackEntry *yymsp; /* The top of the parser's stack */ + int yysize; /* Amount to pop the stack */ + sqlite3ParserARG_FETCH + (void)yyLookahead; + (void)yyLookaheadToken; + yymsp = yypParser->yytos; + + switch( yyruleno ){ + /* Beginning here are the reduction cases. A typical example + ** follows: + ** case 0: + ** #line + ** { ... } // User supplied code + ** #line + ** break; + */ +/********** Begin reduce actions **********************************************/ + YYMINORTYPE yylhsminor; + case 0: /* explain ::= EXPLAIN */ +{ pParse->explain = 1; } + break; + case 1: /* explain ::= EXPLAIN QUERY PLAN */ +{ pParse->explain = 2; } + break; + case 2: /* cmdx ::= cmd */ +{ sqlite3FinishCoding(pParse); } + break; + case 3: /* cmd ::= BEGIN transtype trans_opt */ +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy394);} + break; + case 4: /* transtype ::= */ +{yymsp[1].minor.yy394 = TK_DEFERRED;} + break; + case 5: /* transtype ::= DEFERRED */ + case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); + case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); + case 321: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==321); +{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/} + break; + case 8: /* cmd ::= COMMIT|END trans_opt */ + case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); +{sqlite3EndTransaction(pParse,yymsp[-1].major);} + break; + case 10: /* cmd ::= SAVEPOINT nm */ +{ + sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0); +} + break; + case 11: /* cmd ::= RELEASE savepoint_opt nm */ +{ + sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0); +} + break; + case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ +{ + sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0); +} + break; + case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ +{ + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy394,0,0,yymsp[-2].minor.yy394); +} + break; + case 14: /* createkw ::= CREATE */ +{disableLookaside(pParse);} + break; + case 15: /* ifnotexists ::= */ + case 18: /* temp ::= */ yytestcase(yyruleno==18); + case 47: /* autoinc ::= */ yytestcase(yyruleno==47); + case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62); + case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72); + case 81: /* ifexists ::= */ yytestcase(yyruleno==81); + case 98: /* distinct ::= */ yytestcase(yyruleno==98); + case 242: /* collate ::= */ yytestcase(yyruleno==242); +{yymsp[1].minor.yy394 = 0;} + break; + case 16: /* ifnotexists ::= IF NOT EXISTS */ +{yymsp[-2].minor.yy394 = 1;} + break; + case 17: /* temp ::= TEMP */ +{yymsp[0].minor.yy394 = pParse->db->init.busy==0;} + break; + case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ +{ + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy285,0); +} + break; + case 20: /* create_table_args ::= AS select */ +{ + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy47); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); +} + break; + case 21: /* table_option_set ::= */ +{yymsp[1].minor.yy285 = 0;} + break; + case 22: /* table_option_set ::= table_option_set COMMA table_option */ +{yylhsminor.yy285 = yymsp[-2].minor.yy285|yymsp[0].minor.yy285;} + yymsp[-2].minor.yy285 = yylhsminor.yy285; + break; + case 23: /* table_option ::= WITHOUT nm */ +{ + if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ + yymsp[-1].minor.yy285 = TF_WithoutRowid | TF_NoVisibleRowid; + }else{ + yymsp[-1].minor.yy285 = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); + } +} + break; + case 24: /* table_option ::= nm */ +{ + if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){ + yylhsminor.yy285 = TF_Strict; + }else{ + yylhsminor.yy285 = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); + } +} + yymsp[0].minor.yy285 = yylhsminor.yy285; + break; + case 25: /* columnname ::= nm typetoken */ +{sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);} + break; + case 26: /* typetoken ::= */ + case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65); + case 104: /* as ::= */ yytestcase(yyruleno==104); +{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} + break; + case 27: /* typetoken ::= typename LP signed RP */ +{ + yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z); +} + break; + case 28: /* typetoken ::= typename LP signed COMMA signed RP */ +{ + yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z); +} + break; + case 29: /* typename ::= typename ID|STRING */ +{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);} + break; + case 30: /* scanpt ::= */ +{ + assert( yyLookahead!=YYNOCODE ); + yymsp[1].minor.yy522 = yyLookaheadToken.z; +} + break; + case 31: /* scantok ::= */ +{ + assert( yyLookahead!=YYNOCODE ); + yymsp[1].minor.yy0 = yyLookaheadToken; +} + break; + case 32: /* ccons ::= CONSTRAINT nm */ + case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67); +{pParse->constraintName = yymsp[0].minor.yy0;} + break; + case 33: /* ccons ::= DEFAULT scantok term */ +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} + break; + case 34: /* ccons ::= DEFAULT LP expr RP */ +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} + break; + case 35: /* ccons ::= DEFAULT PLUS scantok term */ +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} + break; + case 36: /* ccons ::= DEFAULT MINUS scantok term */ +{ + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy528, 0); + sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); +} + break; + case 37: /* ccons ::= DEFAULT scantok ID|INDEXED */ +{ + Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0); + if( p ){ + sqlite3ExprIdToTrueFalse(p); + testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) ); + } + sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); +} + break; + case 38: /* ccons ::= NOT NULL onconf */ +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy394);} + break; + case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy394,yymsp[0].minor.yy394,yymsp[-2].minor.yy394);} + break; + case 40: /* ccons ::= UNIQUE onconf */ +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy394,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} + break; + case 41: /* ccons ::= CHECK LP expr RP */ +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} + break; + case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */ +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy394);} + break; + case 43: /* ccons ::= defer_subclause */ +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy394);} + break; + case 44: /* ccons ::= COLLATE ID|STRING */ +{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} + break; + case 45: /* generated ::= LP expr RP */ +{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy528,0);} + break; + case 46: /* generated ::= LP expr RP ID */ +{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy528,&yymsp[0].minor.yy0);} + break; + case 48: /* autoinc ::= AUTOINCR */ +{yymsp[0].minor.yy394 = 1;} + break; + case 49: /* refargs ::= */ +{ yymsp[1].minor.yy394 = OE_None*0x0101; /* EV: R-19803-45884 */} + break; + case 50: /* refargs ::= refargs refarg */ +{ yymsp[-1].minor.yy394 = (yymsp[-1].minor.yy394 & ~yymsp[0].minor.yy231.mask) | yymsp[0].minor.yy231.value; } + break; + case 51: /* refarg ::= MATCH nm */ +{ yymsp[-1].minor.yy231.value = 0; yymsp[-1].minor.yy231.mask = 0x000000; } + break; + case 52: /* refarg ::= ON INSERT refact */ +{ yymsp[-2].minor.yy231.value = 0; yymsp[-2].minor.yy231.mask = 0x000000; } + break; + case 53: /* refarg ::= ON DELETE refact */ +{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394; yymsp[-2].minor.yy231.mask = 0x0000ff; } + break; + case 54: /* refarg ::= ON UPDATE refact */ +{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394<<8; yymsp[-2].minor.yy231.mask = 0x00ff00; } + break; + case 55: /* refact ::= SET NULL */ +{ yymsp[-1].minor.yy394 = OE_SetNull; /* EV: R-33326-45252 */} + break; + case 56: /* refact ::= SET DEFAULT */ +{ yymsp[-1].minor.yy394 = OE_SetDflt; /* EV: R-33326-45252 */} + break; + case 57: /* refact ::= CASCADE */ +{ yymsp[0].minor.yy394 = OE_Cascade; /* EV: R-33326-45252 */} + break; + case 58: /* refact ::= RESTRICT */ +{ yymsp[0].minor.yy394 = OE_Restrict; /* EV: R-33326-45252 */} + break; + case 59: /* refact ::= NO ACTION */ +{ yymsp[-1].minor.yy394 = OE_None; /* EV: R-33326-45252 */} + break; + case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ +{yymsp[-2].minor.yy394 = 0;} + break; + case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76); + case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171); +{yymsp[-1].minor.yy394 = yymsp[0].minor.yy394;} + break; + case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); + case 214: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==214); + case 217: /* in_op ::= NOT IN */ yytestcase(yyruleno==217); + case 243: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==243); +{yymsp[-1].minor.yy394 = 1;} + break; + case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ +{yymsp[-1].minor.yy394 = 0;} + break; + case 66: /* tconscomma ::= COMMA */ +{pParse->constraintName.n = 0;} + break; + case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy394,yymsp[-2].minor.yy394,0);} + break; + case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */ +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy394,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} + break; + case 70: /* tcons ::= CHECK LP expr RP onconf */ +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy528,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} + break; + case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ +{ + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy394); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy394); +} + break; + case 73: /* onconf ::= */ + case 75: /* orconf ::= */ yytestcase(yyruleno==75); +{yymsp[1].minor.yy394 = OE_Default;} + break; + case 74: /* onconf ::= ON CONFLICT resolvetype */ +{yymsp[-2].minor.yy394 = yymsp[0].minor.yy394;} + break; + case 77: /* resolvetype ::= IGNORE */ +{yymsp[0].minor.yy394 = OE_Ignore;} + break; + case 78: /* resolvetype ::= REPLACE */ + case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172); +{yymsp[0].minor.yy394 = OE_Replace;} + break; + case 79: /* cmd ::= DROP TABLE ifexists fullname */ +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy131, 0, yymsp[-1].minor.yy394); +} + break; + case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ +{ + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy47, yymsp[-7].minor.yy394, yymsp[-5].minor.yy394); +} + break; + case 83: /* cmd ::= DROP VIEW ifexists fullname */ +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy131, 1, yymsp[-1].minor.yy394); +} + break; + case 84: /* cmd ::= select */ +{ + SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; + sqlite3Select(pParse, yymsp[0].minor.yy47, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47); +} + break; + case 85: /* select ::= WITH wqlist selectnowith */ +{yymsp[-2].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} + break; + case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */ +{yymsp[-3].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);} + break; + case 87: /* select ::= selectnowith */ +{ + Select *p = yymsp[0].minor.yy47; + if( p ){ + parserDoubleLinkSelect(pParse, p); + } + yymsp[0].minor.yy47 = p; /*A-overwrites-X*/ +} + break; + case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */ +{ + Select *pRhs = yymsp[0].minor.yy47; + Select *pLhs = yymsp[-2].minor.yy47; + if( pRhs && pRhs->pPrior ){ + SrcList *pFrom; + Token x; + x.n = 0; + parserDoubleLinkSelect(pParse, pRhs); + pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); + pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); + } + if( pRhs ){ + pRhs->op = (u8)yymsp[-1].minor.yy394; + pRhs->pPrior = pLhs; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; + pRhs->selFlags &= ~SF_MultiValue; + if( yymsp[-1].minor.yy394!=TK_ALL ) pParse->hasCompound = 1; + }else{ + sqlite3SelectDelete(pParse->db, pLhs); + } + yymsp[-2].minor.yy47 = pRhs; +} + break; + case 89: /* multiselect_op ::= UNION */ + case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91); +{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-OP*/} + break; + case 90: /* multiselect_op ::= UNION ALL */ +{yymsp[-1].minor.yy394 = TK_ALL;} + break; + case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ +{ + yymsp[-8].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy131,yymsp[-4].minor.yy528,yymsp[-3].minor.yy322,yymsp[-2].minor.yy528,yymsp[-1].minor.yy322,yymsp[-7].minor.yy394,yymsp[0].minor.yy528); +} + break; + case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ +{ + yymsp[-9].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy322,yymsp[-6].minor.yy131,yymsp[-5].minor.yy528,yymsp[-4].minor.yy322,yymsp[-3].minor.yy528,yymsp[-1].minor.yy322,yymsp[-8].minor.yy394,yymsp[0].minor.yy528); + if( yymsp[-9].minor.yy47 ){ + yymsp[-9].minor.yy47->pWinDefn = yymsp[-2].minor.yy41; + }else{ + sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy41); + } +} + break; + case 94: /* values ::= VALUES LP nexprlist RP */ +{ + yymsp[-3].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0); +} + break; + case 95: /* values ::= values COMMA LP nexprlist RP */ +{ + Select *pRight, *pLeft = yymsp[-4].minor.yy47; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0); + if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; + if( pRight ){ + pRight->op = TK_ALL; + pRight->pPrior = pLeft; + yymsp[-4].minor.yy47 = pRight; + }else{ + yymsp[-4].minor.yy47 = pLeft; + } +} + break; + case 96: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy394 = SF_Distinct;} + break; + case 97: /* distinct ::= ALL */ +{yymsp[0].minor.yy394 = SF_All;} + break; + case 99: /* sclp ::= */ + case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132); + case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142); + case 230: /* exprlist ::= */ yytestcase(yyruleno==230); + case 233: /* paren_exprlist ::= */ yytestcase(yyruleno==233); + case 238: /* eidlist_opt ::= */ yytestcase(yyruleno==238); +{yymsp[1].minor.yy322 = 0;} + break; + case 100: /* selcollist ::= sclp scanpt expr scanpt as */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy522,yymsp[-1].minor.yy522); +} + break; + case 101: /* selcollist ::= sclp scanpt STAR */ +{ + Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); + yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p); +} + break; + case 102: /* selcollist ::= sclp scanpt nm DOT STAR */ +{ + Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); + Expr *pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0); + Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot); +} + break; + case 103: /* as ::= AS nm */ + case 114: /* dbnm ::= DOT nm */ yytestcase(yyruleno==114); + case 254: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==254); + case 255: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==255); +{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} + break; + case 105: /* from ::= */ + case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108); +{yymsp[1].minor.yy131 = 0;} + break; + case 106: /* from ::= FROM seltablist */ +{ + yymsp[-1].minor.yy131 = yymsp[0].minor.yy131; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy131); +} + break; + case 107: /* stl_prefix ::= seltablist joinop */ +{ + if( ALWAYS(yymsp[-1].minor.yy131 && yymsp[-1].minor.yy131->nSrc>0) ) yymsp[-1].minor.yy131->a[yymsp[-1].minor.yy131->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy394; +} + break; + case 109: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ +{ + yymsp[-6].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy131,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy528,yymsp[0].minor.yy254); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy131, &yymsp[-2].minor.yy0); +} + break; + case 110: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ +{ + yymsp[-8].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy131,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy528,yymsp[0].minor.yy254); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy131, yymsp[-4].minor.yy322); +} + break; + case 111: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ +{ + yymsp[-6].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy131,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy47,yymsp[-1].minor.yy528,yymsp[0].minor.yy254); + } + break; + case 112: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ +{ + if( yymsp[-6].minor.yy131==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy528==0 && yymsp[0].minor.yy254==0 ){ + yymsp[-6].minor.yy131 = yymsp[-4].minor.yy131; + }else if( yymsp[-4].minor.yy131->nSrc==1 ){ + yymsp[-6].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy131,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy528,yymsp[0].minor.yy254); + if( yymsp[-6].minor.yy131 ){ + SrcItem *pNew = &yymsp[-6].minor.yy131->a[yymsp[-6].minor.yy131->nSrc-1]; + SrcItem *pOld = yymsp[-4].minor.yy131->a; + pNew->zName = pOld->zName; + pNew->zDatabase = pOld->zDatabase; + pNew->pSelect = pOld->pSelect; + if( pOld->fg.isTabFunc ){ + pNew->u1.pFuncArg = pOld->u1.pFuncArg; + pOld->u1.pFuncArg = 0; + pOld->fg.isTabFunc = 0; + pNew->fg.isTabFunc = 1; + } + pOld->zName = pOld->zDatabase = 0; + pOld->pSelect = 0; + } + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy131); + }else{ + Select *pSubquery; + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy131); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy131,0,0,0,0,SF_NestedFrom,0); + yymsp[-6].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy131,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy528,yymsp[0].minor.yy254); + } + } + break; + case 113: /* dbnm ::= */ + case 127: /* indexed_opt ::= */ yytestcase(yyruleno==127); +{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} + break; + case 115: /* fullname ::= nm */ +{ + yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); + if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); +} + yymsp[0].minor.yy131 = yylhsminor.yy131; + break; + case 116: /* fullname ::= nm DOT nm */ +{ + yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0); +} + yymsp[-2].minor.yy131 = yylhsminor.yy131; + break; + case 117: /* xfullname ::= nm */ +{yymsp[0].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} + break; + case 118: /* xfullname ::= nm DOT nm */ +{yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 119: /* xfullname ::= nm DOT nm AS nm */ +{ + yymsp[-4].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ + if( yymsp[-4].minor.yy131 ) yymsp[-4].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); +} + break; + case 120: /* xfullname ::= nm AS nm */ +{ + yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ + if( yymsp[-2].minor.yy131 ) yymsp[-2].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); +} + break; + case 121: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy394 = JT_INNER; } + break; + case 122: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} + break; + case 123: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + break; + case 124: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + break; + case 125: /* on_opt ::= ON expr */ + case 145: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==145); + case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152); + case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154); + case 226: /* case_else ::= ELSE expr */ yytestcase(yyruleno==226); + case 247: /* vinto ::= INTO expr */ yytestcase(yyruleno==247); +{yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;} + break; + case 126: /* on_opt ::= */ + case 144: /* having_opt ::= */ yytestcase(yyruleno==144); + case 146: /* limit_opt ::= */ yytestcase(yyruleno==146); + case 151: /* where_opt ::= */ yytestcase(yyruleno==151); + case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153); + case 227: /* case_else ::= */ yytestcase(yyruleno==227); + case 229: /* case_operand ::= */ yytestcase(yyruleno==229); + case 248: /* vinto ::= */ yytestcase(yyruleno==248); +{yymsp[1].minor.yy528 = 0;} + break; + case 128: /* indexed_opt ::= INDEXED BY nm */ +{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} + break; + case 129: /* indexed_opt ::= NOT INDEXED */ +{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} + break; + case 130: /* using_opt ::= USING LP idlist RP */ +{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;} + break; + case 131: /* using_opt ::= */ + case 173: /* idlist_opt ::= */ yytestcase(yyruleno==173); +{yymsp[1].minor.yy254 = 0;} + break; + case 133: /* orderby_opt ::= ORDER BY sortlist */ + case 143: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==143); +{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;} + break; + case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528); + sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); +} + break; + case 135: /* sortlist ::= expr sortorder nulls */ +{ + yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy528); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394); +} + break; + case 136: /* sortorder ::= ASC */ +{yymsp[0].minor.yy394 = SQLITE_SO_ASC;} + break; + case 137: /* sortorder ::= DESC */ +{yymsp[0].minor.yy394 = SQLITE_SO_DESC;} + break; + case 138: /* sortorder ::= */ + case 141: /* nulls ::= */ yytestcase(yyruleno==141); +{yymsp[1].minor.yy394 = SQLITE_SO_UNDEFINED;} + break; + case 139: /* nulls ::= NULLS FIRST */ +{yymsp[-1].minor.yy394 = SQLITE_SO_ASC;} + break; + case 140: /* nulls ::= NULLS LAST */ +{yymsp[-1].minor.yy394 = SQLITE_SO_DESC;} + break; + case 147: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,0);} + break; + case 148: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} + break; + case 149: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,yymsp[-2].minor.yy528);} + break; + case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ +{ + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy131, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy131,yymsp[0].minor.yy528,0,0); +} + break; + case 155: /* where_opt_ret ::= RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-1].minor.yy528 = 0;} + break; + case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-3].minor.yy528 = yymsp[-2].minor.yy528;} + break; + case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ +{ + sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-4].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy322,"set list"); + yymsp[-5].minor.yy131 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy131, yymsp[-1].minor.yy131); + sqlite3Update(pParse,yymsp[-5].minor.yy131,yymsp[-2].minor.yy322,yymsp[0].minor.yy528,yymsp[-6].minor.yy394,0,0,0); +} + break; + case 158: /* setlist ::= setlist COMMA nm EQ expr */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy528); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1); +} + break; + case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ +{ + yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); +} + break; + case 160: /* setlist ::= nm EQ expr */ +{ + yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy528); + sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1); +} + yymsp[-2].minor.yy322 = yylhsminor.yy322; + break; + case 161: /* setlist ::= LP idlist RP EQ expr */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy528); +} + break; + case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ +{ + sqlite3Insert(pParse, yymsp[-3].minor.yy131, yymsp[-1].minor.yy47, yymsp[-2].minor.yy254, yymsp[-5].minor.yy394, yymsp[0].minor.yy444); +} + break; + case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ +{ + sqlite3Insert(pParse, yymsp[-4].minor.yy131, 0, yymsp[-3].minor.yy254, yymsp[-6].minor.yy394, 0); +} + break; + case 164: /* upsert ::= */ +{ yymsp[1].minor.yy444 = 0; } + break; + case 165: /* upsert ::= RETURNING selcollist */ +{ yymsp[-1].minor.yy444 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy322); } + break; + case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ +{ yymsp[-11].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy322,yymsp[-6].minor.yy528,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,yymsp[0].minor.yy444);} + break; + case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ +{ yymsp[-8].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy322,yymsp[-3].minor.yy528,0,0,yymsp[0].minor.yy444); } + break; + case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */ +{ yymsp[-4].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } + break; + case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ +{ yymsp[-7].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,0);} + break; + case 170: /* returning ::= RETURNING selcollist */ +{sqlite3AddReturning(pParse,yymsp[0].minor.yy322);} + break; + case 174: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;} + break; + case 175: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);} + break; + case 176: /* idlist ::= nm */ +{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + break; + case 177: /* expr ::= LP expr RP */ +{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;} + break; + case 178: /* expr ::= ID|INDEXED */ + case 179: /* expr ::= JOIN_KW */ yytestcase(yyruleno==179); +{yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 180: /* expr ::= nm DOT nm */ +{ + Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); + Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); + yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); +} + yymsp[-2].minor.yy528 = yylhsminor.yy528; + break; + case 181: /* expr ::= nm DOT nm DOT nm */ +{ + Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0); + Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); + Expr *temp3 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); + Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, 0, temp1); + } + yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); +} + yymsp[-4].minor.yy528 = yylhsminor.yy528; + break; + case 182: /* term ::= NULL|FLOAT|BLOB */ + case 183: /* term ::= STRING */ yytestcase(yyruleno==183); +{yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} + break; + case 184: /* term ::= INTEGER */ +{ + yylhsminor.yy528 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); +} + yymsp[0].minor.yy528 = yylhsminor.yy528; + break; + case 185: /* expr ::= VARIABLE */ +{ + if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ + u32 n = yymsp[0].minor.yy0.n; + yymsp[0].minor.yy528 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy528, n); + }else{ + /* When doing a nested parse, one can include terms in an expression + ** that look like this: #1 #2 ... These terms refer to registers + ** in the virtual machine. #N is the N-th register. */ + Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/ + assert( t.n>=2 ); + if( pParse->nested==0 ){ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); + yymsp[0].minor.yy528 = 0; + }else{ + yymsp[0].minor.yy528 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy528 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy528->iTable); + } + } +} + break; + case 186: /* expr ::= expr COLLATE ID|STRING */ +{ + yymsp[-2].minor.yy528 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1); +} + break; + case 187: /* expr ::= CAST LP expr AS typetoken RP */ +{ + yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0); +} + break; + case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394); +} + yymsp[-4].minor.yy528 = yylhsminor.yy528; + break; + case 189: /* expr ::= ID|INDEXED LP STAR RP */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); +} + yymsp[-3].minor.yy528 = yylhsminor.yy528; + break; + case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); +} + yymsp[-5].minor.yy528 = yylhsminor.yy528; + break; + case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); + sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41); +} + yymsp[-4].minor.yy528 = yylhsminor.yy528; + break; + case 192: /* term ::= CTIME_KW */ +{ + yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); +} + yymsp[0].minor.yy528 = yylhsminor.yy528; + break; + case 193: /* expr ::= LP nexprlist COMMA expr RP */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = pList; + if( ALWAYS(pList->nExpr) ){ + yymsp[-4].minor.yy528->flags |= pList->a[0].pExpr->flags & EP_Propagate; + } + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } +} + break; + case 194: /* expr ::= expr AND expr */ +{yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} + break; + case 195: /* expr ::= expr OR expr */ + case 196: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==196); + case 197: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==197); + case 198: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==198); + case 199: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==199); + case 200: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==200); + case 201: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==201); +{yymsp[-2].minor.yy528=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);} + break; + case 202: /* likeop ::= NOT LIKE_KW|MATCH */ +{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} + break; + case 203: /* expr ::= expr likeop expr */ +{ + ExprList *pList; + int bNot = yymsp[-1].minor.yy0.n & 0x80000000; + yymsp[-1].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy528); + yymsp[-2].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + if( bNot ) yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy528, 0); + if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc; +} + break; + case 204: /* expr ::= expr likeop expr ESCAPE expr */ +{ + ExprList *pList; + int bNot = yymsp[-3].minor.yy0.n & 0x80000000; + yymsp[-3].minor.yy0.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); + if( bNot ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc; +} + break; + case 205: /* expr ::= expr ISNULL|NOTNULL */ +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);} + break; + case 206: /* expr ::= expr NOT NULL */ +{yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);} + break; + case 207: /* expr ::= expr IS expr */ +{ + yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL); +} + break; + case 208: /* expr ::= expr IS NOT expr */ +{ + yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL); +} + break; + case 209: /* expr ::= NOT expr */ + case 210: /* expr ::= BITNOT expr */ yytestcase(yyruleno==210); +{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/} + break; + case 211: /* expr ::= PLUS|MINUS expr */ +{ + yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0); + /*A-overwrites-B*/ +} + break; + case 212: /* expr ::= expr PTR expr */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528); + yylhsminor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); +} + yymsp[-2].minor.yy528 = yylhsminor.yy528; + break; + case 213: /* between_op ::= BETWEEN */ + case 216: /* in_op ::= IN */ yytestcase(yyruleno==216); +{yymsp[0].minor.yy394 = 0;} + break; + case 215: /* expr ::= expr between_op expr AND expr */ +{ + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = pList; + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); +} + break; + case 218: /* expr ::= expr in_op LP exprlist RP */ +{ + if( yymsp[-1].minor.yy322==0 ){ + /* Expressions of the form ** - ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be - ** silently truncated if necessary so that it does not exceed the - ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE - ** compile-time option. + ** expr1 IN () + ** expr1 NOT IN () + ** + ** simplify to constants 0 (false) and 1 (true), respectively, + ** regardless of the value of expr1. */ - if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ - mxMmap = SQLITE_MAX_MMAP_SIZE; + sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy528); + yymsp[-4].minor.yy528 = sqlite3Expr(pParse->db, TK_INTEGER, yymsp[-3].minor.yy394 ? "1" : "0"); + }else{ + Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr; + if( yymsp[-1].minor.yy322->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy528->op!=TK_VECTOR ){ + yymsp[-1].minor.yy322->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); + pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS); + }else{ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + if( yymsp[-4].minor.yy528==0 ){ + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322); + }else if( yymsp[-4].minor.yy528->pLeft->op==TK_VECTOR ){ + int nExpr = yymsp[-4].minor.yy528->pLeft->x.pList->nExpr; + Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy322); + if( pSelectRHS ){ + parserDoubleLinkSelect(pParse, pSelectRHS); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelectRHS); + } + }else{ + yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy322; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); + } } - if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; - if( szMmap>mxMmap) szMmap = mxMmap; - sqlite3GlobalConfig.mxMmap = mxMmap; - sqlite3GlobalConfig.szMmap = szMmap; - break; + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + } + } + break; + case 219: /* expr ::= LP select RP */ +{ + yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47); + } + break; + case 220: /* expr ::= expr in_op LP select RP */ +{ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + } + break; + case 221: /* expr ::= expr in_op nm dbnm paren_exprlist */ +{ + SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); + Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); + if( yymsp[0].minor.yy322 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322); + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelect); + if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0); + } + break; + case 222: /* expr ::= EXISTS LP select RP */ +{ + Expr *p; + p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47); + } + break; + case 223: /* expr ::= CASE case_operand case_exprlist case_else END */ +{ + yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0); + if( yymsp[-4].minor.yy528 ){ + yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy528 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528) : yymsp[-2].minor.yy322; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528); + }else{ + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); + } +} + break; + case 224: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ +{ + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528); + yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528); +} + break; + case 225: /* case_exprlist ::= WHEN expr THEN expr */ +{ + yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528); + yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528); +} + break; + case 228: /* case_operand ::= expr */ +{yymsp[0].minor.yy528 = yymsp[0].minor.yy528; /*A-overwrites-X*/} + break; + case 231: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);} + break; + case 232: /* nexprlist ::= expr */ +{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/} + break; + case 234: /* paren_exprlist ::= LP exprlist RP */ + case 239: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==239); +{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;} + break; + case 235: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ +{ + sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, + sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy528, SQLITE_SO_ASC, yymsp[-8].minor.yy394, SQLITE_IDXTYPE_APPDEF); + if( IN_RENAME_OBJECT && pParse->pNewIndex ){ + sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); + } +} + break; + case 236: /* uniqueflag ::= UNIQUE */ + case 278: /* raisetype ::= ABORT */ yytestcase(yyruleno==278); +{yymsp[0].minor.yy394 = OE_Abort;} + break; + case 237: /* uniqueflag ::= */ +{yymsp[1].minor.yy394 = OE_None;} + break; + case 240: /* eidlist ::= eidlist COMMA nm collate sortorder */ +{ + yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); +} + break; + case 241: /* eidlist ::= nm collate sortorder */ +{ + yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/ +} + break; + case 244: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);} + break; + case 245: /* cmd ::= VACUUM vinto */ +{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);} + break; + case 246: /* cmd ::= VACUUM nm vinto */ +{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);} + break; + case 249: /* cmd ::= PRAGMA nm dbnm */ +{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} + break; + case 250: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} + break; + case 251: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} + break; + case 252: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} + break; + case 253: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} + break; + case 256: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ +{ + Token all; + all.z = yymsp[-3].minor.yy0.z; + all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all); +} + break; + case 257: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ +{ + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394); + yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ +} + break; + case 258: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ } + break; + case 259: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy394 = TK_INSTEAD;} + break; + case 260: /* trigger_time ::= */ +{ yymsp[1].minor.yy394 = TK_BEFORE; } + break; + case 261: /* trigger_event ::= DELETE|INSERT */ + case 262: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==262); +{yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;} + break; + case 263: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;} + break; + case 264: /* when_clause ::= */ + case 283: /* key_opt ::= */ yytestcase(yyruleno==283); +{ yymsp[1].minor.yy528 = 0; } + break; + case 265: /* when_clause ::= WHEN expr */ + case 284: /* key_opt ::= KEY expr */ yytestcase(yyruleno==284); +{ yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; } + break; + case 266: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ +{ + assert( yymsp[-2].minor.yy33!=0 ); + yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33; + yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33; +} + break; + case 267: /* trigger_cmd_list ::= trigger_cmd SEMI */ +{ + assert( yymsp[-1].minor.yy33!=0 ); + yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33; +} + break; + case 268: /* trnm ::= nm DOT nm */ +{ + yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; + sqlite3ErrorMsg(pParse, + "qualified table names are not allowed on INSERT, UPDATE, and DELETE " + "statements within triggers"); +} + break; + case 269: /* tridxby ::= INDEXED BY nm */ +{ + sqlite3ErrorMsg(pParse, + "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} + break; + case 270: /* tridxby ::= NOT INDEXED */ +{ + sqlite3ErrorMsg(pParse, + "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} + break; + case 271: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ +{yylhsminor.yy33 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);} + yymsp[-8].minor.yy33 = yylhsminor.yy33; + break; + case 272: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ +{ + yylhsminor.yy33 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/ +} + yymsp[-7].minor.yy33 = yylhsminor.yy33; + break; + case 273: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ +{yylhsminor.yy33 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);} + yymsp[-5].minor.yy33 = yylhsminor.yy33; + break; + case 274: /* trigger_cmd ::= scanpt select scanpt */ +{yylhsminor.yy33 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/} + yymsp[-2].minor.yy33 = yylhsminor.yy33; + break; + case 275: /* expr ::= RAISE LP IGNORE RP */ +{ + yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy528 ){ + yymsp[-3].minor.yy528->affExpr = OE_Ignore; + } +} + break; + case 276: /* expr ::= RAISE LP raisetype COMMA nm RP */ +{ + yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); + if( yymsp[-5].minor.yy528 ) { + yymsp[-5].minor.yy528->affExpr = (char)yymsp[-3].minor.yy394; + } +} + break; + case 277: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy394 = OE_Rollback;} + break; + case 279: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy394 = OE_Fail;} + break; + case 280: /* cmd ::= DROP TRIGGER ifexists fullname */ +{ + sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394); +} + break; + case 281: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ +{ + sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528); +} + break; + case 282: /* cmd ::= DETACH database_kw_opt expr */ +{ + sqlite3Detach(pParse, yymsp[0].minor.yy528); +} + break; + case 285: /* cmd ::= REINDEX */ +{sqlite3Reindex(pParse, 0, 0);} + break; + case 286: /* cmd ::= REINDEX nm dbnm */ +{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} + break; + case 287: /* cmd ::= ANALYZE */ +{sqlite3Analyze(pParse, 0, 0);} + break; + case 288: /* cmd ::= ANALYZE nm dbnm */ +{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} + break; + case 289: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ +{ + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0); +} + break; + case 290: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ +{ + yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; + sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); +} + break; + case 291: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ +{ + sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0); +} + break; + case 292: /* add_column_fullname ::= fullname */ +{ + disableLookaside(pParse); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131); +} + break; + case 293: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ +{ + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); +} + break; + case 294: /* cmd ::= create_vtab */ +{sqlite3VtabFinishParse(pParse,0);} + break; + case 295: /* cmd ::= create_vtab LP vtabarglist RP */ +{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} + break; + case 296: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ +{ + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394); +} + break; + case 297: /* vtabarg ::= */ +{sqlite3VtabArgInit(pParse);} + break; + case 298: /* vtabargtoken ::= ANY */ + case 299: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==299); + case 300: /* lp ::= LP */ yytestcase(yyruleno==300); +{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} + break; + case 301: /* with ::= WITH wqlist */ + case 302: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==302); +{ sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); } + break; + case 303: /* wqas ::= AS */ +{yymsp[0].minor.yy516 = M10d_Any;} + break; + case 304: /* wqas ::= AS MATERIALIZED */ +{yymsp[-1].minor.yy516 = M10d_Yes;} + break; + case 305: /* wqas ::= AS NOT MATERIALIZED */ +{yymsp[-2].minor.yy516 = M10d_No;} + break; + case 306: /* wqitem ::= nm eidlist_opt wqas LP select RP */ +{ + yymsp[-5].minor.yy385 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/ +} + break; + case 307: /* wqlist ::= wqitem */ +{ + yymsp[0].minor.yy521 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/ +} + break; + case 308: /* wqlist ::= wqlist COMMA wqitem */ +{ + yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385); +} + break; + case 309: /* windowdefn_list ::= windowdefn */ +{ yylhsminor.yy41 = yymsp[0].minor.yy41; } + yymsp[0].minor.yy41 = yylhsminor.yy41; + break; + case 310: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ +{ + assert( yymsp[0].minor.yy41!=0 ); + sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41); + yymsp[0].minor.yy41->pNextWin = yymsp[-2].minor.yy41; + yylhsminor.yy41 = yymsp[0].minor.yy41; +} + yymsp[-2].minor.yy41 = yylhsminor.yy41; + break; + case 311: /* windowdefn ::= nm AS LP window RP */ +{ + if( ALWAYS(yymsp[-1].minor.yy41) ){ + yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); + } + yylhsminor.yy41 = yymsp[-1].minor.yy41; +} + yymsp[-4].minor.yy41 = yylhsminor.yy41; + break; + case 312: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ +{ + yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0); +} + break; + case 313: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0); +} + yymsp[-5].minor.yy41 = yylhsminor.yy41; + break; + case 314: /* window ::= ORDER BY sortlist frame_opt */ +{ + yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0); +} + break; + case 315: /* window ::= nm ORDER BY sortlist frame_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0); +} + yymsp[-4].minor.yy41 = yylhsminor.yy41; + break; + case 316: /* window ::= frame_opt */ + case 335: /* filter_over ::= over_clause */ yytestcase(yyruleno==335); +{ + yylhsminor.yy41 = yymsp[0].minor.yy41; +} + yymsp[0].minor.yy41 = yylhsminor.yy41; + break; + case 317: /* window ::= nm frame_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0); +} + yymsp[-1].minor.yy41 = yylhsminor.yy41; + break; + case 318: /* frame_opt ::= */ +{ + yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); +} + break; + case 319: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516); +} + yymsp[-2].minor.yy41 = yylhsminor.yy41; + break; + case 320: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ +{ + yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516); +} + yymsp[-5].minor.yy41 = yylhsminor.yy41; + break; + case 322: /* frame_bound_s ::= frame_bound */ + case 324: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==324); +{yylhsminor.yy595 = yymsp[0].minor.yy595;} + yymsp[0].minor.yy595 = yylhsminor.yy595; + break; + case 323: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 325: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==325); + case 327: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==327); +{yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;} + yymsp[-1].minor.yy595 = yylhsminor.yy595; + break; + case 326: /* frame_bound ::= expr PRECEDING|FOLLOWING */ +{yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;} + yymsp[-1].minor.yy595 = yylhsminor.yy595; + break; + case 328: /* frame_exclude_opt ::= */ +{yymsp[1].minor.yy516 = 0;} + break; + case 329: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ +{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;} + break; + case 330: /* frame_exclude ::= NO OTHERS */ + case 331: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==331); +{yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/} + break; + case 332: /* frame_exclude ::= GROUP|TIES */ +{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/} + break; + case 333: /* window_clause ::= WINDOW windowdefn_list */ +{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; } + break; + case 334: /* filter_over ::= filter_clause over_clause */ +{ + if( yymsp[0].minor.yy41 ){ + yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528; + }else{ + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528); + } + yylhsminor.yy41 = yymsp[0].minor.yy41; +} + yymsp[-1].minor.yy41 = yylhsminor.yy41; + break; + case 336: /* filter_over ::= filter_clause */ +{ + yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yylhsminor.yy41 ){ + yylhsminor.yy41->eFrmType = TK_FILTER; + yylhsminor.yy41->pFilter = yymsp[0].minor.yy528; + }else{ + sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy528); + } +} + yymsp[0].minor.yy41 = yylhsminor.yy41; + break; + case 337: /* over_clause ::= OVER LP window RP */ +{ + yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41; + assert( yymsp[-3].minor.yy41!=0 ); +} + break; + case 338: /* over_clause ::= OVER nm */ +{ + yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yymsp[-1].minor.yy41 ){ + yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); + } +} + break; + case 339: /* filter_clause ::= FILTER LP WHERE expr RP */ +{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; } + break; + default: + /* (340) input ::= cmdlist */ yytestcase(yyruleno==340); + /* (341) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==341); + /* (342) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=342); + /* (343) ecmd ::= SEMI */ yytestcase(yyruleno==343); + /* (344) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==344); + /* (345) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=345); + /* (346) trans_opt ::= */ yytestcase(yyruleno==346); + /* (347) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==347); + /* (348) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==348); + /* (349) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==349); + /* (350) savepoint_opt ::= */ yytestcase(yyruleno==350); + /* (351) cmd ::= create_table create_table_args */ yytestcase(yyruleno==351); + /* (352) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=352); + /* (353) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==353); + /* (354) columnlist ::= columnname carglist */ yytestcase(yyruleno==354); + /* (355) nm ::= ID|INDEXED */ yytestcase(yyruleno==355); + /* (356) nm ::= STRING */ yytestcase(yyruleno==356); + /* (357) nm ::= JOIN_KW */ yytestcase(yyruleno==357); + /* (358) typetoken ::= typename */ yytestcase(yyruleno==358); + /* (359) typename ::= ID|STRING */ yytestcase(yyruleno==359); + /* (360) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=360); + /* (361) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=361); + /* (362) carglist ::= carglist ccons */ yytestcase(yyruleno==362); + /* (363) carglist ::= */ yytestcase(yyruleno==363); + /* (364) ccons ::= NULL onconf */ yytestcase(yyruleno==364); + /* (365) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==365); + /* (366) ccons ::= AS generated */ yytestcase(yyruleno==366); + /* (367) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==367); + /* (368) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==368); + /* (369) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=369); + /* (370) tconscomma ::= */ yytestcase(yyruleno==370); + /* (371) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=371); + /* (372) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=372); + /* (373) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=373); + /* (374) oneselect ::= values */ yytestcase(yyruleno==374); + /* (375) sclp ::= selcollist COMMA */ yytestcase(yyruleno==375); + /* (376) as ::= ID|STRING */ yytestcase(yyruleno==376); + /* (377) returning ::= */ yytestcase(yyruleno==377); + /* (378) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=378); + /* (379) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==379); + /* (380) exprlist ::= nexprlist */ yytestcase(yyruleno==380); + /* (381) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=381); + /* (382) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=382); + /* (383) nmnum ::= ON */ yytestcase(yyruleno==383); + /* (384) nmnum ::= DELETE */ yytestcase(yyruleno==384); + /* (385) nmnum ::= DEFAULT */ yytestcase(yyruleno==385); + /* (386) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==386); + /* (387) foreach_clause ::= */ yytestcase(yyruleno==387); + /* (388) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==388); + /* (389) trnm ::= nm */ yytestcase(yyruleno==389); + /* (390) tridxby ::= */ yytestcase(yyruleno==390); + /* (391) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==391); + /* (392) database_kw_opt ::= */ yytestcase(yyruleno==392); + /* (393) kwcolumn_opt ::= */ yytestcase(yyruleno==393); + /* (394) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==394); + /* (395) vtabarglist ::= vtabarg */ yytestcase(yyruleno==395); + /* (396) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==396); + /* (397) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==397); + /* (398) anylist ::= */ yytestcase(yyruleno==398); + /* (399) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==399); + /* (400) anylist ::= anylist ANY */ yytestcase(yyruleno==400); + /* (401) with ::= */ yytestcase(yyruleno==401); + break; +/********** End reduce actions ************************************************/ + }; + assert( yyrulenoYY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); + + /* It is not possible for a REDUCE to be followed by an error */ + assert( yyact!=YY_ERROR_ACTION ); + + yymsp += yysize+1; + yypParser->yytos = yymsp; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yyTraceShift(yypParser, yyact, "... then shift"); + return yyact; +} + +/* +** The following code executes when the parse fails +*/ +#ifndef YYNOERRORRECOVERY +static void yy_parse_failed( + yyParser *yypParser /* The parser */ +){ + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + } +#endif + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); + /* Here code is inserted which will be executed whenever the + ** parser fails */ +/************ Begin %parse_failure code ***************************************/ +/************ End %parse_failure code *****************************************/ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserCTX_STORE +} +#endif /* YYNOERRORRECOVERY */ + +/* +** The following code executes when a syntax error first occurs. +*/ +static void yy_syntax_error( + yyParser *yypParser, /* The parser */ + int yymajor, /* The major type of the error token */ + sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */ +){ + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH +#define TOKEN yyminor +/************ Begin %syntax_error code ****************************************/ + + UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ + if( TOKEN.z[0] ){ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); + }else{ + sqlite3ErrorMsg(pParse, "incomplete input"); + } +/************ End %syntax_error code ******************************************/ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserCTX_STORE +} + +/* +** The following is executed when the parser accepts +*/ +static void yy_accept( + yyParser *yypParser /* The parser */ +){ + sqlite3ParserARG_FETCH + sqlite3ParserCTX_FETCH +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + } +#endif +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + assert( yypParser->yytos==yypParser->yystack ); + /* Here code is inserted which will be executed whenever the + ** parser accepts */ +/*********** Begin %parse_accept code *****************************************/ +/*********** End %parse_accept code *******************************************/ + sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3ParserCTX_STORE +} + +/* The main parser program. +** The first argument is a pointer to a structure obtained from +** "sqlite3ParserAlloc" which describes the current state of the parser. +** The second argument is the major token number. The third is +** the minor token. The fourth optional argument is whatever the +** user wants (and specified in the grammar) and is available for +** use by the action routines. +** +** Inputs: +**
              +**
            • A pointer to the parser (an opaque structure.) +**
            • The major token number. +**
            • The minor token number. +**
            • An option argument of a grammar-specified type. +**
            +** +** Outputs: +** None. +*/ +SQLITE_PRIVATE void sqlite3Parser( + void *yyp, /* The parser */ + int yymajor, /* The major token code number */ + sqlite3ParserTOKENTYPE yyminor /* The value for the token */ + sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */ +){ + YYMINORTYPE yyminorunion; + YYACTIONTYPE yyact; /* The parser action. */ +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) + int yyendofinput; /* True if we are at the end of input */ +#endif +#ifdef YYERRORSYMBOL + int yyerrorhit = 0; /* True if yymajor has invoked an error */ +#endif + yyParser *yypParser = (yyParser*)yyp; /* The parser */ + sqlite3ParserCTX_FETCH + sqlite3ParserARG_STORE + + assert( yypParser->yytos!=0 ); +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) + yyendofinput = (yymajor==0); +#endif + + yyact = yypParser->yytos->stateno; +#ifndef NDEBUG + if( yyTraceFILE ){ + if( yyact < YY_MIN_REDUCE ){ + fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", + yyTracePrompt,yyTokenName[yymajor],yyact); + }else{ + fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", + yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } + } +#endif + + while(1){ /* Exit by "break" */ + assert( yypParser->yytos>=yypParser->yystack ); + assert( yyact==yypParser->yytos->stateno ); + yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); + if( yyact >= YY_MIN_REDUCE ){ + unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */ +#ifndef NDEBUG + assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ); + if( yyTraceFILE ){ + int yysize = yyRuleInfoNRhs[yyruleno]; + if( yysize ){ + fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n", + yyTracePrompt, + yyruleno, yyRuleName[yyruleno], + yyrulenoyytos[yysize].stateno); + }else{ + fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n", + yyTracePrompt, yyruleno, yyRuleName[yyruleno], + yyrulenoyytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == + (int)(yypParser->yytos - yypParser->yystack)); + } +#endif +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=yypParser->yystackEnd ){ + yyStackOverflow(yypParser); + break; + } +#else + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ + if( yyGrowStack(yypParser) ){ + yyStackOverflow(yypParser); + break; + } + } +#endif + } + yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor sqlite3ParserCTX_PARAM); + }else if( yyact <= YY_MAX_SHIFTREDUCE ){ + yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt--; +#endif + break; + }else if( yyact==YY_ACCEPT_ACTION ){ + yypParser->yytos--; + yy_accept(yypParser); + return; + }else{ + assert( yyact == YY_ERROR_ACTION ); + yyminorunion.yy0 = yyminor; +#ifdef YYERRORSYMBOL + int yymx; +#endif +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + } +#endif +#ifdef YYERRORSYMBOL + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if( yypParser->yyerrcnt<0 ){ + yy_syntax_error(yypParser,yymajor,yyminor); + } + yymx = yypParser->yytos->major; + if( yymx==YYERRORSYMBOL || yyerrorhit ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sDiscard input token %s\n", + yyTracePrompt,yyTokenName[yymajor]); + } +#endif + yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); + yymajor = YYNOCODE; + }else{ + while( yypParser->yytos > yypParser->yystack ){ + yyact = yy_find_reduce_action(yypParser->yytos->stateno, + YYERRORSYMBOL); + if( yyact<=YY_MAX_SHIFTREDUCE ) break; + yy_pop_parser_stack(yypParser); + } + if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){ + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + yymajor = YYNOCODE; + }else if( yymx!=YYERRORSYMBOL ){ + yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); + } + } + yypParser->yyerrcnt = 3; + yyerrorhit = 1; + if( yymajor==YYNOCODE ) break; + yyact = yypParser->yytos->stateno; +#elif defined(YYNOERRORRECOVERY) + /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to + ** do any kind of error recovery. Instead, simply invoke the syntax + ** error routine and continue going as if nothing had happened. + ** + ** Applications can set this macro (for example inside %include) if + ** they intend to abandon the parse upon the first syntax error seen. + */ + yy_syntax_error(yypParser,yymajor, yyminor); + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + break; +#else /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if( yypParser->yyerrcnt<=0 ){ + yy_syntax_error(yypParser,yymajor, yyminor); + } + yypParser->yyerrcnt = 3; + yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); + if( yyendofinput ){ + yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif + } + break; +#endif + } + } +#ifndef NDEBUG + if( yyTraceFILE ){ + yyStackEntry *i; + char cDiv = '['; + fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); + for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ + fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); + cDiv = ' '; + } + fprintf(yyTraceFILE,"]\n"); + } +#endif + return; +} + +/* +** Return the fallback token corresponding to canonical token iToken, or +** 0 if iToken has no fallback. +*/ +SQLITE_PRIVATE int sqlite3ParserFallback(int iToken){ +#ifdef YYFALLBACK + assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); + return yyFallback[iToken]; +#else + (void)iToken; + return 0; +#endif +} + +/************** End of parse.c ***********************************************/ +/************** Begin file tokenize.c ****************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** An tokenizer for SQL +** +** This file contains C code that splits an SQL input string up into +** individual tokens and sends those tokens one-by-one over to the +** parser for analysis. +*/ +/* #include "sqliteInt.h" */ +/* #include */ + +/* Character classes for tokenizing +** +** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented +** using a lookup table, whereas a switch() directly on c uses a binary search. +** The lookup table is much faster. To maximize speed, and to ensure that +** a lookup table is used, all of the classes need to be small integers and +** all of them need to be used within the switch. +*/ +#define CC_X 0 /* The letter 'x', or start of BLOB literal */ +#define CC_KYWD0 1 /* First letter of a keyword */ +#define CC_KYWD 2 /* Alphabetics or '_'. Usable in a keyword */ +#define CC_DIGIT 3 /* Digits */ +#define CC_DOLLAR 4 /* '$' */ +#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */ +#define CC_VARNUM 6 /* '?'. Numeric SQL variables */ +#define CC_SPACE 7 /* Space characters */ +#define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */ +#define CC_QUOTE2 9 /* '['. [...] style quoted ids */ +#define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */ +#define CC_MINUS 11 /* '-'. Minus or SQL-style comment */ +#define CC_LT 12 /* '<'. Part of < or <= or <> */ +#define CC_GT 13 /* '>'. Part of > or >= */ +#define CC_EQ 14 /* '='. Part of = or == */ +#define CC_BANG 15 /* '!'. Part of != */ +#define CC_SLASH 16 /* '/'. / or c-style comment */ +#define CC_LP 17 /* '(' */ +#define CC_RP 18 /* ')' */ +#define CC_SEMI 19 /* ';' */ +#define CC_PLUS 20 /* '+' */ +#define CC_STAR 21 /* '*' */ +#define CC_PERCENT 22 /* '%' */ +#define CC_COMMA 23 /* ',' */ +#define CC_AND 24 /* '&' */ +#define CC_TILDA 25 /* '~' */ +#define CC_DOT 26 /* '.' */ +#define CC_ID 27 /* unicode characters usable in IDs */ +#define CC_ILLEGAL 28 /* Illegal character */ +#define CC_NUL 29 /* 0x00 */ +#define CC_BOM 30 /* First byte of UTF8 BOM: 0xEF 0xBB 0xBF */ + +static const unsigned char aiClass[] = { +#ifdef SQLITE_ASCII +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ +/* 0x */ 29, 28, 28, 28, 28, 28, 28, 28, 28, 7, 7, 28, 7, 7, 28, 28, +/* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, +/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, +/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 9, 28, 28, 28, 2, +/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 28, 10, 28, 25, 28, +/* 8x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* 9x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Ax */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Cx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Dx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +/* Ex */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 30, +/* Fx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27 +#endif +#ifdef SQLITE_EBCDIC +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ +/* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28, +/* 1x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +/* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +/* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +/* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10, +/* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28, +/* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6, +/* 7x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 8, 5, 5, 5, 8, 14, 8, +/* 8x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, +/* 9x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, +/* Ax */ 28, 25, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28, +/* Bx */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 9, 28, 28, 28, 28, 28, +/* Cx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, +/* Dx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28, +/* Ex */ 28, 28, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28, +/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 28, 28, 28, 28, 28, 28, +#endif +}; + +/* +** The charMap() macro maps alphabetic characters (only) into their +** lower-case ASCII equivalent. On ASCII machines, this is just +** an upper-to-lower case map. On EBCDIC machines we also need +** to adjust the encoding. The mapping is only valid for alphabetics +** which are the only characters for which this feature is used. +** +** Used by keywordhash.h +*/ +#ifdef SQLITE_ASCII +# define charMap(X) sqlite3UpperToLower[(unsigned char)X] +#endif +#ifdef SQLITE_EBCDIC +# define charMap(X) ebcdicToAscii[(unsigned char)X] +const unsigned char ebcdicToAscii[] = { +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */ + 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */ + 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + 0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */ + 0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */ + 0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */ +}; +#endif + +/* +** The sqlite3KeywordCode function looks up an identifier to determine if +** it is a keyword. If it is a keyword, the token code of that keyword is +** returned. If the input is not a keyword, TK_ID is returned. +** +** The implementation of this routine was generated by a program, +** mkkeywordhash.c, located in the tool subdirectory of the distribution. +** The output of the mkkeywordhash.c program is written into a file +** named keywordhash.h and then included into this source file by +** the #include below. +*/ +/************** Include keywordhash.h in the middle of tokenize.c ************/ +/************** Begin file keywordhash.h *************************************/ +/***** This file contains automatically generated code ****** +** +** The code in this file has been automatically generated by +** +** sqlite/tool/mkkeywordhash.c +** +** The code in this file implements a function that determines whether +** or not a given identifier is really an SQL keyword. The same thing +** might be implemented more directly using a hand-written hash table. +** But by using this automatically generated code, the size of the code +** is substantially reduced. This is important for embedded applications +** on platforms with limited memory. +*/ +/* Hash score: 231 */ +/* zKWText[] encodes 1007 bytes of keyword text in 667 bytes */ +/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ +/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYISNULLSAVEPOINTERSECT */ +/* IESNOTNULLIKEXCEPTRANSACTIONATURALTERAISEXCLUSIVEXISTS */ +/* CONSTRAINTOFFSETRIGGERANGENERATEDETACHAVINGLOBEGINNEREFERENCES */ +/* UNIQUERYWITHOUTERELEASEATTACHBETWEENOTHINGROUPSCASCADEFAULT */ +/* CASECOLLATECREATECURRENT_DATEIMMEDIATEJOINSERTMATCHPLANALYZE */ +/* PRAGMATERIALIZEDEFERREDISTINCTUPDATEVALUESVIRTUALWAYSWHENWHERE */ +/* CURSIVEABORTAFTERENAMEANDROPARTITIONAUTOINCREMENTCASTCOLUMN */ +/* COMMITCONFLICTCROSSCURRENT_TIMESTAMPRECEDINGFAILASTFILTER */ +/* EPLACEFIRSTFOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVER */ +/* ETURNINGRIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBY */ +/* INITIALLYPRIMARY */ +static const char zKWText[666] = { + 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', + 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', + 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', + 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', + 'E','R','R','A','B','L','E','L','S','E','X','C','L','U','D','E','L','E', + 'T','E','M','P','O','R','A','R','Y','I','S','N','U','L','L','S','A','V', + 'E','P','O','I','N','T','E','R','S','E','C','T','I','E','S','N','O','T', + 'N','U','L','L','I','K','E','X','C','E','P','T','R','A','N','S','A','C', + 'T','I','O','N','A','T','U','R','A','L','T','E','R','A','I','S','E','X', + 'C','L','U','S','I','V','E','X','I','S','T','S','C','O','N','S','T','R', + 'A','I','N','T','O','F','F','S','E','T','R','I','G','G','E','R','A','N', + 'G','E','N','E','R','A','T','E','D','E','T','A','C','H','A','V','I','N', + 'G','L','O','B','E','G','I','N','N','E','R','E','F','E','R','E','N','C', + 'E','S','U','N','I','Q','U','E','R','Y','W','I','T','H','O','U','T','E', + 'R','E','L','E','A','S','E','A','T','T','A','C','H','B','E','T','W','E', + 'E','N','O','T','H','I','N','G','R','O','U','P','S','C','A','S','C','A', + 'D','E','F','A','U','L','T','C','A','S','E','C','O','L','L','A','T','E', + 'C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E', + 'I','M','M','E','D','I','A','T','E','J','O','I','N','S','E','R','T','M', + 'A','T','C','H','P','L','A','N','A','L','Y','Z','E','P','R','A','G','M', + 'A','T','E','R','I','A','L','I','Z','E','D','E','F','E','R','R','E','D', + 'I','S','T','I','N','C','T','U','P','D','A','T','E','V','A','L','U','E', + 'S','V','I','R','T','U','A','L','W','A','Y','S','W','H','E','N','W','H', + 'E','R','E','C','U','R','S','I','V','E','A','B','O','R','T','A','F','T', + 'E','R','E','N','A','M','E','A','N','D','R','O','P','A','R','T','I','T', + 'I','O','N','A','U','T','O','I','N','C','R','E','M','E','N','T','C','A', + 'S','T','C','O','L','U','M','N','C','O','M','M','I','T','C','O','N','F', + 'L','I','C','T','C','R','O','S','S','C','U','R','R','E','N','T','_','T', + 'I','M','E','S','T','A','M','P','R','E','C','E','D','I','N','G','F','A', + 'I','L','A','S','T','F','I','L','T','E','R','E','P','L','A','C','E','F', + 'I','R','S','T','F','O','L','L','O','W','I','N','G','F','R','O','M','F', + 'U','L','L','I','M','I','T','I','F','O','R','D','E','R','E','S','T','R', + 'I','C','T','O','T','H','E','R','S','O','V','E','R','E','T','U','R','N', + 'I','N','G','R','I','G','H','T','R','O','L','L','B','A','C','K','R','O', + 'W','S','U','N','B','O','U','N','D','E','D','U','N','I','O','N','U','S', + 'I','N','G','V','A','C','U','U','M','V','I','E','W','I','N','D','O','W', + 'B','Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R','Y', +}; +/* aKWHash[i] is the hash value for the i-th keyword */ +static const unsigned char aKWHash[127] = { + 84, 92, 134, 82, 105, 29, 0, 0, 94, 0, 85, 72, 0, + 53, 35, 86, 15, 0, 42, 97, 54, 89, 135, 19, 0, 0, + 140, 0, 40, 129, 0, 22, 107, 0, 9, 0, 0, 123, 80, + 0, 78, 6, 0, 65, 103, 147, 0, 136, 115, 0, 0, 48, + 0, 90, 24, 0, 17, 0, 27, 70, 23, 26, 5, 60, 142, + 110, 122, 0, 73, 91, 71, 145, 61, 120, 74, 0, 49, 0, + 11, 41, 0, 113, 0, 0, 0, 109, 10, 111, 116, 125, 14, + 50, 124, 0, 100, 0, 18, 121, 144, 56, 130, 139, 88, 83, + 37, 30, 126, 0, 0, 108, 51, 131, 128, 0, 34, 0, 0, + 132, 0, 98, 38, 39, 0, 20, 45, 117, 93, +}; +/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 +** then the i-th keyword has no more hash collisions. Otherwise, +** the next keyword with the same hash is aKWHash[i]-1. */ +static const unsigned char aKWNext[147] = { + 0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0, + 0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0, + 141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0, + 138, 0, 133, 0, 0, 36, 0, 0, 28, 77, 0, 0, 0, + 0, 59, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 69, 0, 0, 0, 0, 0, 146, 3, 0, 58, 0, 1, + 75, 0, 0, 0, 31, 0, 0, 0, 0, 0, 127, 0, 104, + 0, 64, 66, 63, 0, 0, 0, 0, 0, 46, 0, 16, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 101, 0, + 112, 21, 7, 67, 0, 79, 96, 118, 0, 0, 68, 0, 0, + 99, 44, 0, 55, 0, 76, 0, 95, 32, 33, 57, 25, 0, + 102, 0, 0, 87, +}; +/* aKWLen[i] is the length (in bytes) of the i-th keyword */ +static const unsigned char aKWLen[147] = { + 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, + 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7, + 6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4, + 4, 6, 11, 6, 2, 7, 5, 5, 9, 6, 10, 4, 6, + 2, 3, 7, 5, 9, 6, 6, 4, 5, 5, 10, 6, 5, + 7, 4, 5, 7, 6, 7, 7, 6, 5, 7, 3, 7, 4, + 7, 6, 12, 9, 4, 6, 5, 4, 7, 6, 12, 8, 8, + 2, 6, 6, 7, 6, 4, 5, 9, 5, 5, 6, 3, 4, + 9, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 9, + 4, 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, 6, + 4, 9, 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, 2, + 2, 9, 3, 7, +}; +/* aKWOffset[i] is the index into zKWText[] of the start of +** the text for the i-th keyword. */ +static const unsigned short int aKWOffset[147] = { + 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, + 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, + 86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126, + 129, 132, 137, 142, 146, 147, 152, 156, 160, 168, 174, 181, 184, + 184, 187, 189, 195, 198, 206, 211, 216, 219, 222, 226, 236, 239, + 244, 244, 248, 252, 259, 265, 271, 277, 277, 283, 284, 288, 295, + 299, 306, 312, 324, 333, 335, 341, 346, 348, 355, 359, 370, 377, + 378, 385, 391, 397, 402, 408, 412, 415, 424, 429, 433, 439, 441, + 444, 453, 455, 457, 466, 470, 476, 482, 490, 495, 495, 495, 511, + 520, 523, 527, 532, 539, 544, 553, 557, 560, 565, 567, 571, 579, + 585, 588, 597, 602, 610, 610, 614, 623, 628, 633, 639, 642, 645, + 648, 650, 655, 659, +}; +/* aKWCode[i] is the parser symbol code for the i-th keyword */ +static const unsigned char aKWCode[147] = { + TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, + TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, + TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, + TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, + TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, + TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR, + TK_ISNULL, TK_NULLS, TK_SAVEPOINT, TK_INTERSECT, TK_TIES, + TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW, + TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, + TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT, + TK_INTO, TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER, + TK_RANGE, TK_GENERATED, TK_DETACH, TK_HAVING, TK_LIKE_KW, + TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_UNIQUE, TK_QUERY, + TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH, + TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, TK_CASCADE, + TK_ASC, TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE, + TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH, + TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_MATERIALIZED, TK_DEFERRED, + TK_DISTINCT, TK_IS, TK_UPDATE, TK_VALUES, TK_VIRTUAL, + TK_ALWAYS, TK_WHEN, TK_WHERE, TK_RECURSIVE, TK_ABORT, + TK_AFTER, TK_RENAME, TK_AND, TK_DROP, TK_PARTITION, + TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, TK_COLUMNKW, + TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, + TK_CURRENT, TK_PRECEDING, TK_FAIL, TK_LAST, TK_FILTER, + TK_REPLACE, TK_FIRST, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, + TK_LIMIT, TK_IF, TK_ORDER, TK_RESTRICT, TK_OTHERS, + TK_OVER, TK_RETURNING, TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, + TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, TK_VACUUM, + TK_VIEW, TK_WINDOW, TK_DO, TK_BY, TK_INITIALLY, + TK_ALL, TK_PRIMARY, +}; +/* Hash table decoded: +** 0: INSERT +** 1: IS +** 2: ROLLBACK TRIGGER +** 3: IMMEDIATE +** 4: PARTITION +** 5: TEMP +** 6: +** 7: +** 8: VALUES WITHOUT +** 9: +** 10: MATCH +** 11: NOTHING +** 12: +** 13: OF +** 14: TIES IGNORE +** 15: PLAN +** 16: INSTEAD INDEXED +** 17: +** 18: TRANSACTION RIGHT +** 19: WHEN +** 20: SET HAVING +** 21: MATERIALIZED IF +** 22: ROWS +** 23: SELECT +** 24: +** 25: +** 26: VACUUM SAVEPOINT +** 27: +** 28: LIKE UNION VIRTUAL REFERENCES +** 29: RESTRICT +** 30: +** 31: THEN REGEXP +** 32: TO +** 33: +** 34: BEFORE +** 35: +** 36: +** 37: FOLLOWING COLLATE CASCADE +** 38: CREATE +** 39: +** 40: CASE REINDEX +** 41: EACH +** 42: +** 43: QUERY +** 44: AND ADD +** 45: PRIMARY ANALYZE +** 46: +** 47: ROW ASC DETACH +** 48: CURRENT_TIME CURRENT_DATE +** 49: +** 50: +** 51: EXCLUSIVE TEMPORARY +** 52: +** 53: DEFERRED +** 54: DEFERRABLE +** 55: +** 56: DATABASE +** 57: +** 58: DELETE VIEW GENERATED +** 59: ATTACH +** 60: END +** 61: EXCLUDE +** 62: ESCAPE DESC +** 63: GLOB +** 64: WINDOW ELSE +** 65: COLUMN +** 66: FIRST +** 67: +** 68: GROUPS ALL +** 69: DISTINCT DROP KEY +** 70: BETWEEN +** 71: INITIALLY +** 72: BEGIN +** 73: FILTER CHECK ACTION +** 74: GROUP INDEX +** 75: +** 76: EXISTS DEFAULT +** 77: +** 78: FOR CURRENT_TIMESTAMP +** 79: EXCEPT +** 80: +** 81: CROSS +** 82: +** 83: +** 84: +** 85: CAST +** 86: FOREIGN AUTOINCREMENT +** 87: COMMIT +** 88: CURRENT AFTER ALTER +** 89: FULL FAIL CONFLICT +** 90: EXPLAIN +** 91: CONSTRAINT +** 92: FROM ALWAYS +** 93: +** 94: ABORT +** 95: +** 96: AS DO +** 97: REPLACE WITH RELEASE +** 98: BY RENAME +** 99: RANGE RAISE +** 100: OTHERS +** 101: USING NULLS +** 102: PRAGMA +** 103: JOIN ISNULL OFFSET +** 104: NOT +** 105: OR LAST LEFT +** 106: LIMIT +** 107: +** 108: +** 109: IN +** 110: INTO +** 111: OVER RECURSIVE +** 112: ORDER OUTER +** 113: +** 114: INTERSECT UNBOUNDED +** 115: +** 116: +** 117: RETURNING ON +** 118: +** 119: WHERE +** 120: NO INNER +** 121: NULL +** 122: +** 123: TABLE +** 124: NATURAL NOTNULL +** 125: PRECEDING +** 126: UPDATE UNIQUE +*/ +/* Check to see if z[0..n-1] is a keyword. If it is, write the +** parser symbol code for that keyword into *pType. Always +** return the integer n (the length of the token). */ +static int keywordCode(const char *z, int n, int *pType){ + int i, j; + const char *zKW; + if( n>=2 ){ + i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127; + for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){ + if( aKWLen[i]!=n ) continue; + zKW = &zKWText[aKWOffset[i]]; +#ifdef SQLITE_ASCII + if( (z[0]&~0x20)!=zKW[0] ) continue; + if( (z[1]&~0x20)!=zKW[1] ) continue; + j = 2; + while( j=SQLITE_N_KEYWORD ) return SQLITE_ERROR; + *pzName = zKWText + aKWOffset[i]; + *pnName = aKWLen[i]; + return SQLITE_OK; +} +SQLITE_API int sqlite3_keyword_count(void){ return SQLITE_N_KEYWORD; } +SQLITE_API int sqlite3_keyword_check(const char *zName, int nName){ + return TK_ID!=sqlite3KeywordCode((const u8*)zName, nName); +} + +/************** End of keywordhash.h *****************************************/ +/************** Continuing where we left off in tokenize.c *******************/ + + +/* +** If X is a character that can be used in an identifier then +** IdChar(X) will be true. Otherwise it is false. +** +** For ASCII, any character with the high-order bit set is +** allowed in an identifier. For 7-bit characters, +** sqlite3IsIdChar[X] must be 1. +** +** For EBCDIC, the rules are more complex but have the same +** end result. +** +** Ticket #1066. the SQL standard does not allow '$' in the +** middle of identifiers. But many SQL implementations do. +** SQLite will allow '$' in identifiers for compatibility. +** But the feature is undocumented. +*/ +#ifdef SQLITE_ASCII +#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) +#endif +#ifdef SQLITE_EBCDIC +SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = { +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */ + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */ + 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */ + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */ +}; +#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) +#endif + +/* Make the IdChar function accessible from ctime.c and alter.c */ +SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); } + +#ifndef SQLITE_OMIT_WINDOWFUNC +/* +** Return the id of the next token in string (*pz). Before returning, set +** (*pz) to point to the byte following the parsed token. +*/ +static int getToken(const unsigned char **pz){ + const unsigned char *z = *pz; + int t; /* Token type to return */ + do { + z += sqlite3GetToken(z, &t); + }while( t==TK_SPACE ); + if( t==TK_ID + || t==TK_STRING + || t==TK_JOIN_KW + || t==TK_WINDOW + || t==TK_OVER + || sqlite3ParserFallback(t)==TK_ID + ){ + t = TK_ID; + } + *pz = z; + return t; +} + +/* +** The following three functions are called immediately after the tokenizer +** reads the keywords WINDOW, OVER and FILTER, respectively, to determine +** whether the token should be treated as a keyword or an SQL identifier. +** This cannot be handled by the usual lemon %fallback method, due to +** the ambiguity in some constructions. e.g. +** +** SELECT sum(x) OVER ... +** +** In the above, "OVER" might be a keyword, or it might be an alias for the +** sum(x) expression. If a "%fallback ID OVER" directive were added to +** grammar, then SQLite would always treat "OVER" as an alias, making it +** impossible to call a window-function without a FILTER clause. +** +** WINDOW is treated as a keyword if: +** +** * the following token is an identifier, or a keyword that can fallback +** to being an identifier, and +** * the token after than one is TK_AS. +** +** OVER is a keyword if: +** +** * the previous token was TK_RP, and +** * the next token is either TK_LP or an identifier. +** +** FILTER is a keyword if: +** +** * the previous token was TK_RP, and +** * the next token is TK_LP. +*/ +static int analyzeWindowKeyword(const unsigned char *z){ + int t; + t = getToken(&z); + if( t!=TK_ID ) return TK_ID; + t = getToken(&z); + if( t!=TK_AS ) return TK_ID; + return TK_WINDOW; +} +static int analyzeOverKeyword(const unsigned char *z, int lastToken){ + if( lastToken==TK_RP ){ + int t = getToken(&z); + if( t==TK_LP || t==TK_ID ) return TK_OVER; + } + return TK_ID; +} +static int analyzeFilterKeyword(const unsigned char *z, int lastToken){ + if( lastToken==TK_RP && getToken(&z)==TK_LP ){ + return TK_FILTER; + } + return TK_ID; +} +#endif /* SQLITE_OMIT_WINDOWFUNC */ + +/* +** Return the length (in bytes) of the token that begins at z[0]. +** Store the token type in *tokenType before returning. +*/ +SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){ + int i, c; + switch( aiClass[*z] ){ /* Switch on the character-class of the first byte + ** of the token. See the comment on the CC_ defines + ** above. */ + case CC_SPACE: { + testcase( z[0]==' ' ); + testcase( z[0]=='\t' ); + testcase( z[0]=='\n' ); + testcase( z[0]=='\f' ); + testcase( z[0]=='\r' ); + for(i=1; sqlite3Isspace(z[i]); i++){} + *tokenType = TK_SPACE; + return i; + } + case CC_MINUS: { + if( z[1]=='-' ){ + for(i=2; (c=z[i])!=0 && c!='\n'; i++){} + *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ + return i; + }else if( z[1]=='>' ){ + *tokenType = TK_PTR; + return 2 + (z[2]=='>'); + } + *tokenType = TK_MINUS; + return 1; + } + case CC_LP: { + *tokenType = TK_LP; + return 1; + } + case CC_RP: { + *tokenType = TK_RP; + return 1; + } + case CC_SEMI: { + *tokenType = TK_SEMI; + return 1; + } + case CC_PLUS: { + *tokenType = TK_PLUS; + return 1; + } + case CC_STAR: { + *tokenType = TK_STAR; + return 1; + } + case CC_SLASH: { + if( z[1]!='*' || z[2]==0 ){ + *tokenType = TK_SLASH; + return 1; + } + for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} + if( c ) i++; + *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ + return i; + } + case CC_PERCENT: { + *tokenType = TK_REM; + return 1; + } + case CC_EQ: { + *tokenType = TK_EQ; + return 1 + (z[1]=='='); + } + case CC_LT: { + if( (c=z[1])=='=' ){ + *tokenType = TK_LE; + return 2; + }else if( c=='>' ){ + *tokenType = TK_NE; + return 2; + }else if( c=='<' ){ + *tokenType = TK_LSHIFT; + return 2; + }else{ + *tokenType = TK_LT; + return 1; + } + } + case CC_GT: { + if( (c=z[1])=='=' ){ + *tokenType = TK_GE; + return 2; + }else if( c=='>' ){ + *tokenType = TK_RSHIFT; + return 2; + }else{ + *tokenType = TK_GT; + return 1; + } + } + case CC_BANG: { + if( z[1]!='=' ){ + *tokenType = TK_ILLEGAL; + return 1; + }else{ + *tokenType = TK_NE; + return 2; + } + } + case CC_PIPE: { + if( z[1]!='|' ){ + *tokenType = TK_BITOR; + return 1; + }else{ + *tokenType = TK_CONCAT; + return 2; + } + } + case CC_COMMA: { + *tokenType = TK_COMMA; + return 1; + } + case CC_AND: { + *tokenType = TK_BITAND; + return 1; + } + case CC_TILDA: { + *tokenType = TK_BITNOT; + return 1; + } + case CC_QUOTE: { + int delim = z[0]; + testcase( delim=='`' ); + testcase( delim=='\'' ); + testcase( delim=='"' ); + for(i=1; (c=z[i])!=0; i++){ + if( c==delim ){ + if( z[i+1]==delim ){ + i++; + }else{ + break; + } + } + } + if( c=='\'' ){ + *tokenType = TK_STRING; + return i+1; + }else if( c!=0 ){ + *tokenType = TK_ID; + return i+1; + }else{ + *tokenType = TK_ILLEGAL; + return i; + } + } + case CC_DOT: { +#ifndef SQLITE_OMIT_FLOATING_POINT + if( !sqlite3Isdigit(z[1]) ) +#endif + { + *tokenType = TK_DOT; + return 1; + } + /* If the next character is a digit, this is a floating point + ** number that begins with ".". Fall thru into the next case */ + /* no break */ deliberate_fall_through + } + case CC_DIGIT: { + testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' ); + testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' ); + testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' ); + testcase( z[0]=='9' ); + *tokenType = TK_INTEGER; +#ifndef SQLITE_OMIT_HEX_INTEGER + if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ + for(i=3; sqlite3Isxdigit(z[i]); i++){} + return i; + } +#endif + for(i=0; sqlite3Isdigit(z[i]); i++){} +#ifndef SQLITE_OMIT_FLOATING_POINT + if( z[i]=='.' ){ + i++; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } + if( (z[i]=='e' || z[i]=='E') && + ( sqlite3Isdigit(z[i+1]) + || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) + ) + ){ + i += 2; + while( sqlite3Isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } +#endif + while( IdChar(z[i]) ){ + *tokenType = TK_ILLEGAL; + i++; + } + return i; + } + case CC_QUOTE2: { + for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} + *tokenType = c==']' ? TK_ID : TK_ILLEGAL; + return i; + } + case CC_VARNUM: { + *tokenType = TK_VARIABLE; + for(i=1; sqlite3Isdigit(z[i]); i++){} + return i; + } + case CC_DOLLAR: + case CC_VARALPHA: { + int n = 0; + testcase( z[0]=='$' ); testcase( z[0]=='@' ); + testcase( z[0]==':' ); testcase( z[0]=='#' ); + *tokenType = TK_VARIABLE; + for(i=1; (c=z[i])!=0; i++){ + if( IdChar(c) ){ + n++; +#ifndef SQLITE_OMIT_TCL_VARIABLE + }else if( c=='(' && n>0 ){ + do{ + i++; + }while( (c=z[i])!=0 && !sqlite3Isspace(c) && c!=')' ); + if( c==')' ){ + i++; + }else{ + *tokenType = TK_ILLEGAL; + } + break; + }else if( c==':' && z[i+1]==':' ){ + i++; +#endif + }else{ + break; + } + } + if( n==0 ) *tokenType = TK_ILLEGAL; + return i; + } + case CC_KYWD0: { + for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} + if( IdChar(z[i]) ){ + /* This token started out using characters that can appear in keywords, + ** but z[i] is a character not allowed within keywords, so this must + ** be an identifier instead */ + i++; + break; + } + *tokenType = TK_ID; + return keywordCode((char*)z, i, tokenType); + } + case CC_X: { +#ifndef SQLITE_OMIT_BLOB_LITERAL + testcase( z[0]=='x' ); testcase( z[0]=='X' ); + if( z[1]=='\'' ){ + *tokenType = TK_BLOB; + for(i=2; sqlite3Isxdigit(z[i]); i++){} + if( z[i]!='\'' || i%2 ){ + *tokenType = TK_ILLEGAL; + while( z[i] && z[i]!='\'' ){ i++; } + } + if( z[i] ) i++; + return i; + } +#endif + /* If it is not a BLOB literal, then it must be an ID, since no + ** SQL keywords start with the letter 'x'. Fall through */ + /* no break */ deliberate_fall_through + } + case CC_KYWD: + case CC_ID: { + i = 1; + break; + } + case CC_BOM: { + if( z[1]==0xbb && z[2]==0xbf ){ + *tokenType = TK_SPACE; + return 3; + } + i = 1; + break; + } + case CC_NUL: { + *tokenType = TK_ILLEGAL; + return 0; + } + default: { + *tokenType = TK_ILLEGAL; + return 1; + } + } + while( IdChar(z[i]) ){ i++; } + *tokenType = TK_ID; + return i; +} + +/* +** Run the parser on the given SQL string. +*/ +SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ + int nErr = 0; /* Number of errors encountered */ + void *pEngine; /* The LEMON-generated LALR(1) parser */ + int n = 0; /* Length of the next token token */ + int tokenType; /* type of the next token */ + int lastTokenParsed = -1; /* type of the previous token */ + sqlite3 *db = pParse->db; /* The database connection */ + int mxSqlLen; /* Max length of an SQL string */ + Parse *pParentParse = 0; /* Outer parse context, if any */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ +#endif + VVA_ONLY( u8 startedWithOom = db->mallocFailed ); + + assert( zSql!=0 ); + mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; + if( db->nVdbeActive==0 ){ + AtomicStore(&db->u1.isInterrupted, 0); + } + pParse->rc = SQLITE_OK; + pParse->zTail = zSql; +#ifdef SQLITE_DEBUG + if( db->flags & SQLITE_ParserTrace ){ + printf("parser: [[[%s]]]\n", zSql); + sqlite3ParserTrace(stdout, "parser: "); + }else{ + sqlite3ParserTrace(0, 0); + } +#endif +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + pEngine = &sEngine; + sqlite3ParserInit(pEngine, pParse); +#else + pEngine = sqlite3ParserAlloc(sqlite3Malloc, pParse); + if( pEngine==0 ){ + sqlite3OomFault(db); + return SQLITE_NOMEM_BKPT; + } +#endif + assert( pParse->pNewTable==0 ); + assert( pParse->pNewTrigger==0 ); + assert( pParse->nVar==0 ); + assert( pParse->pVList==0 ); + pParentParse = db->pParse; + db->pParse = pParse; + while( 1 ){ + n = sqlite3GetToken((u8*)zSql, &tokenType); + mxSqlLen -= n; + if( mxSqlLen<0 ){ + pParse->rc = SQLITE_TOOBIG; + break; + } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( tokenType>=TK_WINDOW ){ + assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER + || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW + ); +#else + if( tokenType>=TK_SPACE ){ + assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); +#endif /* SQLITE_OMIT_WINDOWFUNC */ + if( AtomicLoad(&db->u1.isInterrupted) ){ + pParse->rc = SQLITE_INTERRUPT; + pParse->nErr++; + break; + } + if( tokenType==TK_SPACE ){ + zSql += n; + continue; + } + if( zSql[0]==0 ){ + /* Upon reaching the end of input, call the parser two more times + ** with tokens TK_SEMI and 0, in that order. */ + if( lastTokenParsed==TK_SEMI ){ + tokenType = 0; + }else if( lastTokenParsed==0 ){ + break; + }else{ + tokenType = TK_SEMI; + } + n = 0; +#ifndef SQLITE_OMIT_WINDOWFUNC + }else if( tokenType==TK_WINDOW ){ + assert( n==6 ); + tokenType = analyzeWindowKeyword((const u8*)&zSql[6]); + }else if( tokenType==TK_OVER ){ + assert( n==4 ); + tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed); + }else if( tokenType==TK_FILTER ){ + assert( n==6 ); + tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); +#endif /* SQLITE_OMIT_WINDOWFUNC */ + }else{ + Token x; + x.z = zSql; + x.n = n; + sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x); + break; + } + } + pParse->sLastToken.z = zSql; + pParse->sLastToken.n = n; + sqlite3Parser(pEngine, tokenType, pParse->sLastToken); + lastTokenParsed = tokenType; + zSql += n; + assert( db->mallocFailed==0 || pParse->rc!=SQLITE_OK || startedWithOom ); + if( pParse->rc!=SQLITE_OK ) break; + } + assert( nErr==0 ); +#ifdef YYTRACKMAXSTACKDEPTH + sqlite3_mutex_enter(sqlite3MallocMutex()); + sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, + sqlite3ParserStackPeak(pEngine) + ); + sqlite3_mutex_leave(sqlite3MallocMutex()); +#endif /* YYDEBUG */ +#ifdef sqlite3Parser_ENGINEALWAYSONSTACK + sqlite3ParserFinalize(pEngine); +#else + sqlite3ParserFree(pEngine, sqlite3_free); +#endif + if( db->mallocFailed ){ + pParse->rc = SQLITE_NOMEM_BKPT; + } + if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){ + if( pParse->zErrMsg==0 ){ + pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); + } + sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail); + nErr++; + } + pParse->zTail = zSql; +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3_free(pParse->apVtabLock); +#endif + + if( pParse->pNewTable && !IN_SPECIAL_PARSE ){ + /* If the pParse->declareVtab flag is set, do not delete any table + ** structure built up in pParse->pNewTable. The calling code (see vtab.c) + ** will take responsibility for freeing the Table structure. + */ + sqlite3DeleteTable(db, pParse->pNewTable); + } + if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){ + sqlite3DeleteTrigger(db, pParse->pNewTrigger); + } + sqlite3DbFree(db, pParse->pVList); + db->pParse = pParentParse; + assert( nErr==0 || pParse->rc!=SQLITE_OK ); + return nErr; +} + + +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Insert a single space character into pStr if the current string +** ends with an identifier +*/ +static void addSpaceSeparator(sqlite3_str *pStr){ + if( pStr->nChar && sqlite3IsIdChar(pStr->zText[pStr->nChar-1]) ){ + sqlite3_str_append(pStr, " ", 1); + } +} + +/* +** Compute a normalization of the SQL given by zSql[0..nSql-1]. Return +** the normalization in space obtained from sqlite3DbMalloc(). Or return +** NULL if anything goes wrong or if zSql is NULL. +*/ +SQLITE_PRIVATE char *sqlite3Normalize( + Vdbe *pVdbe, /* VM being reprepared */ + const char *zSql /* The original SQL string */ +){ + sqlite3 *db; /* The database connection */ + int i; /* Next unread byte of zSql[] */ + int n; /* length of current token */ + int tokenType; /* type of current token */ + int prevType = 0; /* Previous non-whitespace token */ + int nParen; /* Number of nested levels of parentheses */ + int iStartIN; /* Start of RHS of IN operator in z[] */ + int nParenAtIN; /* Value of nParent at start of RHS of IN operator */ + u32 j; /* Bytes of normalized SQL generated so far */ + sqlite3_str *pStr; /* The normalized SQL string under construction */ + + db = sqlite3VdbeDb(pVdbe); + tokenType = -1; + nParen = iStartIN = nParenAtIN = 0; + pStr = sqlite3_str_new(db); + assert( pStr!=0 ); /* sqlite3_str_new() never returns NULL */ + for(i=0; zSql[i] && pStr->accError==0; i+=n){ + if( tokenType!=TK_SPACE ){ + prevType = tokenType; + } + n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType); + if( NEVER(n<=0) ) break; + switch( tokenType ){ + case TK_SPACE: { + break; + } + case TK_NULL: { + if( prevType==TK_IS || prevType==TK_NOT ){ + sqlite3_str_append(pStr, " NULL", 5); + break; + } + /* Fall through */ + } + case TK_STRING: + case TK_INTEGER: + case TK_FLOAT: + case TK_VARIABLE: + case TK_BLOB: { + sqlite3_str_append(pStr, "?", 1); + break; + } + case TK_LP: { + nParen++; + if( prevType==TK_IN ){ + iStartIN = pStr->nChar; + nParenAtIN = nParen; + } + sqlite3_str_append(pStr, "(", 1); + break; + } + case TK_RP: { + if( iStartIN>0 && nParen==nParenAtIN ){ + assert( pStr->nChar>=(u32)iStartIN ); + pStr->nChar = iStartIN+1; + sqlite3_str_append(pStr, "?,?,?", 5); + iStartIN = 0; + } + nParen--; + sqlite3_str_append(pStr, ")", 1); + break; + } + case TK_ID: { + iStartIN = 0; + j = pStr->nChar; + if( sqlite3Isquote(zSql[i]) ){ + char *zId = sqlite3DbStrNDup(db, zSql+i, n); + int nId; + int eType = 0; + if( zId==0 ) break; + sqlite3Dequote(zId); + if( zSql[i]=='"' && sqlite3VdbeUsesDoubleQuotedString(pVdbe, zId) ){ + sqlite3_str_append(pStr, "?", 1); + sqlite3DbFree(db, zId); + break; + } + nId = sqlite3Strlen30(zId); + if( sqlite3GetToken((u8*)zId, &eType)==nId && eType==TK_ID ){ + addSpaceSeparator(pStr); + sqlite3_str_append(pStr, zId, nId); + }else{ + sqlite3_str_appendf(pStr, "\"%w\"", zId); + } + sqlite3DbFree(db, zId); + }else{ + addSpaceSeparator(pStr); + sqlite3_str_append(pStr, zSql+i, n); + } + while( jnChar ){ + pStr->zText[j] = sqlite3Tolower(pStr->zText[j]); + j++; + } + break; + } + case TK_SELECT: { + iStartIN = 0; + /* fall through */ + } + default: { + if( sqlite3IsIdChar(zSql[i]) ) addSpaceSeparator(pStr); + j = pStr->nChar; + sqlite3_str_append(pStr, zSql+i, n); + while( jnChar ){ + pStr->zText[j] = sqlite3Toupper(pStr->zText[j]); + j++; + } + break; + } + } + } + if( tokenType!=TK_SEMI ) sqlite3_str_append(pStr, ";", 1); + return sqlite3_str_finish(pStr); +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + +/************** End of tokenize.c ********************************************/ +/************** Begin file complete.c ****************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** An tokenizer for SQL +** +** This file contains C code that implements the sqlite3_complete() API. +** This code used to be part of the tokenizer.c source file. But by +** separating it out, the code will be automatically omitted from +** static links that do not use it. +*/ +/* #include "sqliteInt.h" */ +#ifndef SQLITE_OMIT_COMPLETE + +/* +** This is defined in tokenize.c. We just have to import the definition. +*/ +#ifndef SQLITE_AMALGAMATION +#ifdef SQLITE_ASCII +#define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) +#endif +#ifdef SQLITE_EBCDIC +SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[]; +#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) +#endif +#endif /* SQLITE_AMALGAMATION */ + + +/* +** Token types used by the sqlite3_complete() routine. See the header +** comments on that procedure for additional information. +*/ +#define tkSEMI 0 +#define tkWS 1 +#define tkOTHER 2 +#ifndef SQLITE_OMIT_TRIGGER +#define tkEXPLAIN 3 +#define tkCREATE 4 +#define tkTEMP 5 +#define tkTRIGGER 6 +#define tkEND 7 +#endif + +/* +** Return TRUE if the given SQL string ends in a semicolon. +** +** Special handling is require for CREATE TRIGGER statements. +** Whenever the CREATE TRIGGER keywords are seen, the statement +** must end with ";END;". +** +** This implementation uses a state machine with 8 states: +** +** (0) INVALID We have not yet seen a non-whitespace character. +** +** (1) START At the beginning or end of an SQL statement. This routine +** returns 1 if it ends in the START state and 0 if it ends +** in any other state. +** +** (2) NORMAL We are in the middle of statement which ends with a single +** semicolon. +** +** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of +** a statement. +** +** (4) CREATE The keyword CREATE has been seen at the beginning of a +** statement, possibly preceded by EXPLAIN and/or followed by +** TEMP or TEMPORARY +** +** (5) TRIGGER We are in the middle of a trigger definition that must be +** ended by a semicolon, the keyword END, and another semicolon. +** +** (6) SEMI We've seen the first semicolon in the ";END;" that occurs at +** the end of a trigger definition. +** +** (7) END We've seen the ";END" of the ";END;" that occurs at the end +** of a trigger definition. +** +** Transitions between states above are determined by tokens extracted +** from the input. The following tokens are significant: +** +** (0) tkSEMI A semicolon. +** (1) tkWS Whitespace. +** (2) tkOTHER Any other SQL token. +** (3) tkEXPLAIN The "explain" keyword. +** (4) tkCREATE The "create" keyword. +** (5) tkTEMP The "temp" or "temporary" keyword. +** (6) tkTRIGGER The "trigger" keyword. +** (7) tkEND The "end" keyword. +** +** Whitespace never causes a state transition and is always ignored. +** This means that a SQL string of all whitespace is invalid. +** +** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed +** to recognize the end of a trigger can be omitted. All we have to do +** is look for a semicolon that is not part of an string or comment. +*/ +SQLITE_API int sqlite3_complete(const char *zSql){ + u8 state = 0; /* Current state, using numbers defined in header comment */ + u8 token; /* Value of the next token */ + +#ifndef SQLITE_OMIT_TRIGGER + /* A complex statement machine used to detect the end of a CREATE TRIGGER + ** statement. This is the normal case. + */ + static const u8 trans[8][8] = { + /* Token: */ + /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ + /* 0 INVALID: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, + /* 1 START: */ { 1, 1, 2, 3, 4, 2, 2, 2, }, + /* 2 NORMAL: */ { 1, 2, 2, 2, 2, 2, 2, 2, }, + /* 3 EXPLAIN: */ { 1, 3, 3, 2, 4, 2, 2, 2, }, + /* 4 CREATE: */ { 1, 4, 2, 2, 2, 4, 5, 2, }, + /* 5 TRIGGER: */ { 6, 5, 5, 5, 5, 5, 5, 5, }, + /* 6 SEMI: */ { 6, 6, 5, 5, 5, 5, 5, 7, }, + /* 7 END: */ { 1, 7, 5, 5, 5, 5, 5, 5, }, + }; +#else + /* If triggers are not supported by this compile then the statement machine + ** used to detect the end of a statement is much simpler + */ + static const u8 trans[3][3] = { + /* Token: */ + /* State: ** SEMI WS OTHER */ + /* 0 INVALID: */ { 1, 0, 2, }, + /* 1 START: */ { 1, 1, 2, }, + /* 2 NORMAL: */ { 1, 2, 2, }, + }; +#endif /* SQLITE_OMIT_TRIGGER */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( zSql==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + + while( *zSql ){ + switch( *zSql ){ + case ';': { /* A semicolon */ + token = tkSEMI; + break; + } + case ' ': + case '\r': + case '\t': + case '\n': + case '\f': { /* White space is ignored */ + token = tkWS; + break; + } + case '/': { /* C-style comments */ + if( zSql[1]!='*' ){ + token = tkOTHER; + break; + } + zSql += 2; + while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } + if( zSql[0]==0 ) return 0; + zSql++; + token = tkWS; + break; + } + case '-': { /* SQL-style comments from "--" to end of line */ + if( zSql[1]!='-' ){ + token = tkOTHER; + break; + } + while( *zSql && *zSql!='\n' ){ zSql++; } + if( *zSql==0 ) return state==1; + token = tkWS; + break; + } + case '[': { /* Microsoft-style identifiers in [...] */ + zSql++; + while( *zSql && *zSql!=']' ){ zSql++; } + if( *zSql==0 ) return 0; + token = tkOTHER; + break; + } + case '`': /* Grave-accent quoted symbols used by MySQL */ + case '"': /* single- and double-quoted strings */ + case '\'': { + int c = *zSql; + zSql++; + while( *zSql && *zSql!=c ){ zSql++; } + if( *zSql==0 ) return 0; + token = tkOTHER; + break; + } + default: { +#ifdef SQLITE_EBCDIC + unsigned char c; +#endif + if( IdChar((u8)*zSql) ){ + /* Keywords and unquoted identifiers */ + int nId; + for(nId=1; IdChar(zSql[nId]); nId++){} +#ifdef SQLITE_OMIT_TRIGGER + token = tkOTHER; +#else + switch( *zSql ){ + case 'c': case 'C': { + if( nId==6 && sqlite3StrNICmp(zSql, "create", 6)==0 ){ + token = tkCREATE; + }else{ + token = tkOTHER; + } + break; + } + case 't': case 'T': { + if( nId==7 && sqlite3StrNICmp(zSql, "trigger", 7)==0 ){ + token = tkTRIGGER; + }else if( nId==4 && sqlite3StrNICmp(zSql, "temp", 4)==0 ){ + token = tkTEMP; + }else if( nId==9 && sqlite3StrNICmp(zSql, "temporary", 9)==0 ){ + token = tkTEMP; + }else{ + token = tkOTHER; + } + break; + } + case 'e': case 'E': { + if( nId==3 && sqlite3StrNICmp(zSql, "end", 3)==0 ){ + token = tkEND; + }else +#ifndef SQLITE_OMIT_EXPLAIN + if( nId==7 && sqlite3StrNICmp(zSql, "explain", 7)==0 ){ + token = tkEXPLAIN; + }else +#endif + { + token = tkOTHER; + } + break; + } + default: { + token = tkOTHER; + break; + } + } +#endif /* SQLITE_OMIT_TRIGGER */ + zSql += nId-1; + }else{ + /* Operators and special symbols */ + token = tkOTHER; + } + break; + } + } + state = trans[state][token]; + zSql++; + } + return state==1; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** This routine is the same as the sqlite3_complete() routine described +** above, except that the parameter is required to be UTF-16 encoded, not +** UTF-8. +*/ +SQLITE_API int sqlite3_complete16(const void *zSql){ + sqlite3_value *pVal; + char const *zSql8; + int rc; + +#ifndef SQLITE_OMIT_AUTOINIT + rc = sqlite3_initialize(); + if( rc ) return rc; +#endif + pVal = sqlite3ValueNew(0); + sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); + zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); + if( zSql8 ){ + rc = sqlite3_complete(zSql8); + }else{ + rc = SQLITE_NOMEM_BKPT; + } + sqlite3ValueFree(pVal); + return rc & 0xff; +} +#endif /* SQLITE_OMIT_UTF16 */ +#endif /* SQLITE_OMIT_COMPLETE */ + +/************** End of complete.c ********************************************/ +/************** Begin file main.c ********************************************/ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** Main file for the SQLite library. The routines in this file +** implement the programmer interface to the library. Routines in +** other files are for internal use by SQLite and should not be +** accessed by users of the library. +*/ +/* #include "sqliteInt.h" */ + +#ifdef SQLITE_ENABLE_FTS3 +/************** Include fts3.h in the middle of main.c ***********************/ +/************** Begin file fts3.h ********************************************/ +/* +** 2006 Oct 10 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file is used by programs that want to link against the +** FTS3 library. All it does is declare the sqlite3Fts3Init() interface. +*/ +/* #include "sqlite3.h" */ + +#if 0 +extern "C" { +#endif /* __cplusplus */ + +SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db); + +#if 0 +} /* extern "C" */ +#endif /* __cplusplus */ + +/************** End of fts3.h ************************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif +#ifdef SQLITE_ENABLE_RTREE +/************** Include rtree.h in the middle of main.c **********************/ +/************** Begin file rtree.h *******************************************/ +/* +** 2008 May 26 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file is used by programs that want to link against the +** RTREE library. All it does is declare the sqlite3RtreeInit() interface. +*/ +/* #include "sqlite3.h" */ + +#ifdef SQLITE_OMIT_VIRTUALTABLE +# undef SQLITE_ENABLE_RTREE +#endif + +#if 0 +extern "C" { +#endif /* __cplusplus */ + +SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db); + +#if 0 +} /* extern "C" */ +#endif /* __cplusplus */ + +/************** End of rtree.h ***********************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif +#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) +/************** Include sqliteicu.h in the middle of main.c ******************/ +/************** Begin file sqliteicu.h ***************************************/ +/* +** 2008 May 26 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This header file is used by programs that want to link against the +** ICU extension. All it does is declare the sqlite3IcuInit() interface. +*/ +/* #include "sqlite3.h" */ + +#if 0 +extern "C" { +#endif /* __cplusplus */ + +SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db); + +#if 0 +} /* extern "C" */ +#endif /* __cplusplus */ + +/************** End of sqliteicu.h *******************************************/ +/************** Continuing where we left off in main.c ***********************/ +#endif + +/* +** This is an extension initializer that is a no-op and always +** succeeds, except that it fails if the fault-simulation is set +** to 500. +*/ +static int sqlite3TestExtInit(sqlite3 *db){ + (void)db; + return sqlite3FaultSim(500); +} + + +/* +** Forward declarations of external module initializer functions +** for modules that need them. +*/ +#ifdef SQLITE_ENABLE_FTS1 +SQLITE_PRIVATE int sqlite3Fts1Init(sqlite3*); +#endif +#ifdef SQLITE_ENABLE_FTS2 +SQLITE_PRIVATE int sqlite3Fts2Init(sqlite3*); +#endif +#ifdef SQLITE_ENABLE_FTS5 +SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*); +#endif +#ifdef SQLITE_ENABLE_STMTVTAB +SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*); +#endif + +/* +** An array of pointers to extension initializer functions for +** built-in extensions. +*/ +static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = { +#ifdef SQLITE_ENABLE_FTS1 + sqlite3Fts1Init, +#endif +#ifdef SQLITE_ENABLE_FTS2 + sqlite3Fts2Init, +#endif +#ifdef SQLITE_ENABLE_FTS3 + sqlite3Fts3Init, +#endif +#ifdef SQLITE_ENABLE_FTS5 + sqlite3Fts5Init, +#endif +#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) + sqlite3IcuInit, +#endif +#ifdef SQLITE_ENABLE_RTREE + sqlite3RtreeInit, +#endif +#ifdef SQLITE_ENABLE_DBPAGE_VTAB + sqlite3DbpageRegister, +#endif +#ifdef SQLITE_ENABLE_DBSTAT_VTAB + sqlite3DbstatRegister, +#endif + sqlite3TestExtInit, +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) + sqlite3JsonTableFunctions, +#endif +#ifdef SQLITE_ENABLE_STMTVTAB + sqlite3StmtVtabInit, +#endif +#ifdef SQLITE_ENABLE_BYTECODE_VTAB + sqlite3VdbeBytecodeVtabInit, +#endif +}; + +#ifndef SQLITE_AMALGAMATION +/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant +** contains the text of SQLITE_VERSION macro. +*/ +SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; +#endif + +/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns +** a pointer to the to the sqlite3_version[] string constant. +*/ +SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; } + +/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a +** pointer to a string constant whose value is the same as the +** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using +** an edited copy of the amalgamation, then the last four characters of +** the hash might be different from SQLITE_SOURCE_ID. +*/ +/* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */ + +/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function +** returns an integer equal to SQLITE_VERSION_NUMBER. +*/ +SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } + +/* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns +** zero if and only if SQLite was compiled with mutexing code omitted due to +** the SQLITE_THREADSAFE compile-time option being set to 0. +*/ +SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } + +/* +** When compiling the test fixture or with debugging enabled (on Win32), +** this variable being set to non-zero will cause OSTRACE macros to emit +** extra diagnostic information. +*/ +#ifdef SQLITE_HAVE_OS_TRACE +# ifndef SQLITE_DEBUG_OS_TRACE +# define SQLITE_DEBUG_OS_TRACE 0 +# endif + int sqlite3OSTrace = SQLITE_DEBUG_OS_TRACE; +#endif + +#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) +/* +** If the following function pointer is not NULL and if +** SQLITE_ENABLE_IOTRACE is enabled, then messages describing +** I/O active are written using this function. These messages +** are intended for debugging activity only. +*/ +SQLITE_API void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...) = 0; +#endif + +/* +** If the following global variable points to a string which is the +** name of a directory, then that directory will be used to store +** temporary files. +** +** See also the "PRAGMA temp_store_directory" SQL command. +*/ +SQLITE_API char *sqlite3_temp_directory = 0; + +/* +** If the following global variable points to a string which is the +** name of a directory, then that directory will be used to store +** all database files specified with a relative pathname. +** +** See also the "PRAGMA data_store_directory" SQL command. +*/ +SQLITE_API char *sqlite3_data_directory = 0; + +/* +** Initialize SQLite. +** +** This routine must be called to initialize the memory allocation, +** VFS, and mutex subsystems prior to doing any serious work with +** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT +** this routine will be called automatically by key routines such as +** sqlite3_open(). +** +** This routine is a no-op except on its very first call for the process, +** or for the first call after a call to sqlite3_shutdown. +** +** The first thread to call this routine runs the initialization to +** completion. If subsequent threads call this routine before the first +** thread has finished the initialization process, then the subsequent +** threads must block until the first thread finishes with the initialization. +** +** The first thread might call this routine recursively. Recursive +** calls to this routine should not block, of course. Otherwise the +** initialization process would never complete. +** +** Let X be the first thread to enter this routine. Let Y be some other +** thread. Then while the initial invocation of this routine by X is +** incomplete, it is required that: +** +** * Calls to this routine from Y must block until the outer-most +** call by X completes. +** +** * Recursive calls to this routine from thread X return immediately +** without blocking. +*/ +SQLITE_API int sqlite3_initialize(void){ + MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */ + int rc; /* Result code */ +#ifdef SQLITE_EXTRA_INIT + int bRunExtraInit = 0; /* Extra initialization needed */ +#endif + +#ifdef SQLITE_OMIT_WSD + rc = sqlite3_wsd_init(4096, 24); + if( rc!=SQLITE_OK ){ + return rc; + } +#endif + + /* If the following assert() fails on some obscure processor/compiler + ** combination, the work-around is to set the correct pointer + ** size at compile-time using -DSQLITE_PTRSIZE=n compile-time option */ + assert( SQLITE_PTRSIZE==sizeof(char*) ); + + /* If SQLite is already completely initialized, then this call + ** to sqlite3_initialize() should be a no-op. But the initialization + ** must be complete. So isInit must not be set until the very end + ** of this routine. + */ + if( sqlite3GlobalConfig.isInit ){ + sqlite3MemoryBarrier(); + return SQLITE_OK; + } + + /* Make sure the mutex subsystem is initialized. If unable to + ** initialize the mutex subsystem, return early with the error. + ** If the system is so sick that we are unable to allocate a mutex, + ** there is not much SQLite is going to be able to do. + ** + ** The mutex subsystem must take care of serializing its own + ** initialization. + */ + rc = sqlite3MutexInit(); + if( rc ) return rc; + + /* Initialize the malloc() system and the recursive pInitMutex mutex. + ** This operation is protected by the STATIC_MAIN mutex. Note that + ** MutexAlloc() is called for a static mutex prior to initializing the + ** malloc subsystem - this implies that the allocation of a static + ** mutex must not require support from the malloc subsystem. + */ + MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); ) + sqlite3_mutex_enter(pMainMtx); + sqlite3GlobalConfig.isMutexInit = 1; + if( !sqlite3GlobalConfig.isMallocInit ){ + rc = sqlite3MallocInit(); + } + if( rc==SQLITE_OK ){ + sqlite3GlobalConfig.isMallocInit = 1; + if( !sqlite3GlobalConfig.pInitMutex ){ + sqlite3GlobalConfig.pInitMutex = + sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); + if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){ + rc = SQLITE_NOMEM_BKPT; + } + } + } + if( rc==SQLITE_OK ){ + sqlite3GlobalConfig.nRefInitMutex++; + } + sqlite3_mutex_leave(pMainMtx); + + /* If rc is not SQLITE_OK at this point, then either the malloc + ** subsystem could not be initialized or the system failed to allocate + ** the pInitMutex mutex. Return an error in either case. */ + if( rc!=SQLITE_OK ){ + return rc; + } + + /* Do the rest of the initialization under the recursive mutex so + ** that we will be able to handle recursive calls into + ** sqlite3_initialize(). The recursive calls normally come through + ** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other + ** recursive calls might also be possible. + ** + ** IMPLEMENTATION-OF: R-00140-37445 SQLite automatically serializes calls + ** to the xInit method, so the xInit method need not be threadsafe. + ** + ** The following mutex is what serializes access to the appdef pcache xInit + ** methods. The sqlite3_pcache_methods.xInit() all is embedded in the + ** call to sqlite3PcacheInitialize(). + */ + sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex); + if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){ + sqlite3GlobalConfig.inProgress = 1; +#ifdef SQLITE_ENABLE_SQLLOG + { + extern void sqlite3_init_sqllog(void); + sqlite3_init_sqllog(); + } +#endif + memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions)); + sqlite3RegisterBuiltinFunctions(); + if( sqlite3GlobalConfig.isPCacheInit==0 ){ + rc = sqlite3PcacheInitialize(); + } + if( rc==SQLITE_OK ){ + sqlite3GlobalConfig.isPCacheInit = 1; + rc = sqlite3OsInit(); + } +#ifndef SQLITE_OMIT_DESERIALIZE + if( rc==SQLITE_OK ){ + rc = sqlite3MemdbInit(); + } +#endif + if( rc==SQLITE_OK ){ + sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, + sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); + sqlite3MemoryBarrier(); + sqlite3GlobalConfig.isInit = 1; +#ifdef SQLITE_EXTRA_INIT + bRunExtraInit = 1; +#endif + } + sqlite3GlobalConfig.inProgress = 0; + } + sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex); + + /* Go back under the static mutex and clean up the recursive + ** mutex to prevent a resource leak. + */ + sqlite3_mutex_enter(pMainMtx); + sqlite3GlobalConfig.nRefInitMutex--; + if( sqlite3GlobalConfig.nRefInitMutex<=0 ){ + assert( sqlite3GlobalConfig.nRefInitMutex==0 ); + sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex); + sqlite3GlobalConfig.pInitMutex = 0; + } + sqlite3_mutex_leave(pMainMtx); + + /* The following is just a sanity check to make sure SQLite has + ** been compiled correctly. It is important to run this code, but + ** we don't want to run it too often and soak up CPU cycles for no + ** reason. So we run it once during initialization. + */ +#ifndef NDEBUG +#ifndef SQLITE_OMIT_FLOATING_POINT + /* This section of code's only "output" is via assert() statements. */ + if( rc==SQLITE_OK ){ + u64 x = (((u64)1)<<63)-1; + double y; + assert(sizeof(x)==8); + assert(sizeof(x)==sizeof(y)); + memcpy(&y, &x, 8); + assert( sqlite3IsNaN(y) ); + } +#endif +#endif + + /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT + ** compile-time option. + */ +#ifdef SQLITE_EXTRA_INIT + if( bRunExtraInit ){ + int SQLITE_EXTRA_INIT(const char*); + rc = SQLITE_EXTRA_INIT(0); + } +#endif + + return rc; +} + +/* +** Undo the effects of sqlite3_initialize(). Must not be called while +** there are outstanding database connections or memory allocations or +** while any part of SQLite is otherwise in use in any thread. This +** routine is not threadsafe. But it is safe to invoke this routine +** on when SQLite is already shut down. If SQLite is already shut down +** when this routine is invoked, then this routine is a harmless no-op. +*/ +SQLITE_API int sqlite3_shutdown(void){ +#ifdef SQLITE_OMIT_WSD + int rc = sqlite3_wsd_init(4096, 24); + if( rc!=SQLITE_OK ){ + return rc; + } +#endif + + if( sqlite3GlobalConfig.isInit ){ +#ifdef SQLITE_EXTRA_SHUTDOWN + void SQLITE_EXTRA_SHUTDOWN(void); + SQLITE_EXTRA_SHUTDOWN(); +#endif + sqlite3_os_end(); + sqlite3_reset_auto_extension(); + sqlite3GlobalConfig.isInit = 0; + } + if( sqlite3GlobalConfig.isPCacheInit ){ + sqlite3PcacheShutdown(); + sqlite3GlobalConfig.isPCacheInit = 0; + } + if( sqlite3GlobalConfig.isMallocInit ){ + sqlite3MallocEnd(); + sqlite3GlobalConfig.isMallocInit = 0; + +#ifndef SQLITE_OMIT_SHUTDOWN_DIRECTORIES + /* The heap subsystem has now been shutdown and these values are supposed + ** to be NULL or point to memory that was obtained from sqlite3_malloc(), + ** which would rely on that heap subsystem; therefore, make sure these + ** values cannot refer to heap memory that was just invalidated when the + ** heap subsystem was shutdown. This is only done if the current call to + ** this function resulted in the heap subsystem actually being shutdown. + */ + sqlite3_data_directory = 0; + sqlite3_temp_directory = 0; +#endif + } + if( sqlite3GlobalConfig.isMutexInit ){ + sqlite3MutexEnd(); + sqlite3GlobalConfig.isMutexInit = 0; + } + + return SQLITE_OK; +} + +/* +** This API allows applications to modify the global configuration of +** the SQLite library at run-time. +** +** This routine should only be called when there are no outstanding +** database connections or memory allocations. This routine is not +** threadsafe. Failure to heed these warnings can lead to unpredictable +** behavior. +*/ +SQLITE_API int sqlite3_config(int op, ...){ + va_list ap; + int rc = SQLITE_OK; + + /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while + ** the SQLite library is in use. */ + if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT; + + va_start(ap, op); + switch( op ){ + + /* Mutex configuration options are only available in a threadsafe + ** compile. + */ +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-54466-46756 */ + case SQLITE_CONFIG_SINGLETHREAD: { + /* EVIDENCE-OF: R-02748-19096 This option sets the threading mode to + ** Single-thread. */ + sqlite3GlobalConfig.bCoreMutex = 0; /* Disable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-20520-54086 */ + case SQLITE_CONFIG_MULTITHREAD: { + /* EVIDENCE-OF: R-14374-42468 This option sets the threading mode to + ** Multi-thread. */ + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 0; /* Disable mutex on connections */ + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-59593-21810 */ + case SQLITE_CONFIG_SERIALIZED: { + /* EVIDENCE-OF: R-41220-51800 This option sets the threading mode to + ** Serialized. */ + sqlite3GlobalConfig.bCoreMutex = 1; /* Enable mutex on core */ + sqlite3GlobalConfig.bFullMutex = 1; /* Enable mutex on connections */ + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */ + case SQLITE_CONFIG_MUTEX: { + /* Specify an alternative mutex implementation */ + sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*); + break; + } +#endif +#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */ + case SQLITE_CONFIG_GETMUTEX: { + /* Retrieve the current mutex implementation */ + *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex; + break; + } +#endif + + case SQLITE_CONFIG_MALLOC: { + /* EVIDENCE-OF: R-55594-21030 The SQLITE_CONFIG_MALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The argument specifies alternative + ** low-level memory allocation routines to be used in place of the memory + ** allocation routines built into SQLite. */ + sqlite3GlobalConfig.m = *va_arg(ap, sqlite3_mem_methods*); + break; + } + case SQLITE_CONFIG_GETMALLOC: { + /* EVIDENCE-OF: R-51213-46414 The SQLITE_CONFIG_GETMALLOC option takes a + ** single argument which is a pointer to an instance of the + ** sqlite3_mem_methods structure. The sqlite3_mem_methods structure is + ** filled with the currently defined memory allocation routines. */ + if( sqlite3GlobalConfig.m.xMalloc==0 ) sqlite3MemSetDefault(); + *va_arg(ap, sqlite3_mem_methods*) = sqlite3GlobalConfig.m; + break; + } + case SQLITE_CONFIG_MEMSTATUS: { + /* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes + ** single argument of type int, interpreted as a boolean, which enables + ** or disables the collection of memory allocation statistics. */ + sqlite3GlobalConfig.bMemstat = va_arg(ap, int); + break; + } + case SQLITE_CONFIG_SMALL_MALLOC: { + sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int); + break; + } + case SQLITE_CONFIG_PAGECACHE: { + /* EVIDENCE-OF: R-18761-36601 There are three arguments to + ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem), + ** the size of each page cache line (sz), and the number of cache lines + ** (N). */ + sqlite3GlobalConfig.pPage = va_arg(ap, void*); + sqlite3GlobalConfig.szPage = va_arg(ap, int); + sqlite3GlobalConfig.nPage = va_arg(ap, int); + break; + } + case SQLITE_CONFIG_PCACHE_HDRSZ: { + /* EVIDENCE-OF: R-39100-27317 The SQLITE_CONFIG_PCACHE_HDRSZ option takes + ** a single parameter which is a pointer to an integer and writes into + ** that integer the number of extra bytes per page required for each page + ** in SQLITE_CONFIG_PAGECACHE. */ + *va_arg(ap, int*) = + sqlite3HeaderSizeBtree() + + sqlite3HeaderSizePcache() + + sqlite3HeaderSizePcache1(); + break; + } + + case SQLITE_CONFIG_PCACHE: { + /* no-op */ + break; + } + case SQLITE_CONFIG_GETPCACHE: { + /* now an error */ + rc = SQLITE_ERROR; + break; + } + + case SQLITE_CONFIG_PCACHE2: { + /* EVIDENCE-OF: R-63325-48378 The SQLITE_CONFIG_PCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. This object specifies the interface to a custom page cache + ** implementation. */ + sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*); + break; + } + case SQLITE_CONFIG_GETPCACHE2: { + /* EVIDENCE-OF: R-22035-46182 The SQLITE_CONFIG_GETPCACHE2 option takes a + ** single argument which is a pointer to an sqlite3_pcache_methods2 + ** object. SQLite copies of the current page cache implementation into + ** that object. */ + if( sqlite3GlobalConfig.pcache2.xInit==0 ){ + sqlite3PCacheSetDefault(); + } + *va_arg(ap, sqlite3_pcache_methods2*) = sqlite3GlobalConfig.pcache2; + break; + } + +/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only +** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or +** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */ +#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) + case SQLITE_CONFIG_HEAP: { + /* EVIDENCE-OF: R-19854-42126 There are three arguments to + ** SQLITE_CONFIG_HEAP: An 8-byte aligned pointer to the memory, the + ** number of bytes in the memory buffer, and the minimum allocation size. + */ + sqlite3GlobalConfig.pHeap = va_arg(ap, void*); + sqlite3GlobalConfig.nHeap = va_arg(ap, int); + sqlite3GlobalConfig.mnReq = va_arg(ap, int); + + if( sqlite3GlobalConfig.mnReq<1 ){ + sqlite3GlobalConfig.mnReq = 1; + }else if( sqlite3GlobalConfig.mnReq>(1<<12) ){ + /* cap min request size at 2^12 */ + sqlite3GlobalConfig.mnReq = (1<<12); + } + + if( sqlite3GlobalConfig.pHeap==0 ){ + /* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer) + ** is NULL, then SQLite reverts to using its default memory allocator + ** (the system malloc() implementation), undoing any prior invocation of + ** SQLITE_CONFIG_MALLOC. + ** + ** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to + ** revert to its default implementation when sqlite3_initialize() is run + */ + memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m)); + }else{ + /* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the + ** alternative memory allocator is engaged to handle all of SQLites + ** memory allocation needs. */ +#ifdef SQLITE_ENABLE_MEMSYS3 + sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3(); +#endif +#ifdef SQLITE_ENABLE_MEMSYS5 + sqlite3GlobalConfig.m = *sqlite3MemGetMemsys5(); +#endif + } + break; + } +#endif + + case SQLITE_CONFIG_LOOKASIDE: { + sqlite3GlobalConfig.szLookaside = va_arg(ap, int); + sqlite3GlobalConfig.nLookaside = va_arg(ap, int); + break; + } + + /* Record a pointer to the logger function and its first argument. + ** The default is NULL. Logging is disabled if the function pointer is + ** NULL. + */ + case SQLITE_CONFIG_LOG: { + /* MSVC is picky about pulling func ptrs from va lists. + ** http://support.microsoft.com/kb/47961 + ** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*)); + */ + typedef void(*LOGFUNC_t)(void*,int,const char*); + sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); + sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); + break; + } + + /* EVIDENCE-OF: R-55548-33817 The compile-time setting for URI filenames + ** can be changed at start-time using the + ** sqlite3_config(SQLITE_CONFIG_URI,1) or + ** sqlite3_config(SQLITE_CONFIG_URI,0) configuration calls. + */ + case SQLITE_CONFIG_URI: { + /* EVIDENCE-OF: R-25451-61125 The SQLITE_CONFIG_URI option takes a single + ** argument of type int. If non-zero, then URI handling is globally + ** enabled. If the parameter is zero, then URI handling is globally + ** disabled. */ + sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); + break; + } + + case SQLITE_CONFIG_COVERING_INDEX_SCAN: { + /* EVIDENCE-OF: R-36592-02772 The SQLITE_CONFIG_COVERING_INDEX_SCAN + ** option takes a single integer argument which is interpreted as a + ** boolean in order to enable or disable the use of covering indices for + ** full table scans in the query optimizer. */ + sqlite3GlobalConfig.bUseCis = va_arg(ap, int); + break; + } + +#ifdef SQLITE_ENABLE_SQLLOG + case SQLITE_CONFIG_SQLLOG: { + typedef void(*SQLLOGFUNC_t)(void*, sqlite3*, const char*, int); + sqlite3GlobalConfig.xSqllog = va_arg(ap, SQLLOGFUNC_t); + sqlite3GlobalConfig.pSqllogArg = va_arg(ap, void *); + break; + } +#endif + + case SQLITE_CONFIG_MMAP_SIZE: { + /* EVIDENCE-OF: R-58063-38258 SQLITE_CONFIG_MMAP_SIZE takes two 64-bit + ** integer (sqlite3_int64) values that are the default mmap size limit + ** (the default setting for PRAGMA mmap_size) and the maximum allowed + ** mmap size limit. */ + sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64); + sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64); + /* EVIDENCE-OF: R-53367-43190 If either argument to this option is + ** negative, then that argument is changed to its compile-time default. + ** + ** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be + ** silently truncated if necessary so that it does not exceed the + ** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE + ** compile-time option. + */ + if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){ + mxMmap = SQLITE_MAX_MMAP_SIZE; + } + if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE; + if( szMmap>mxMmap) szMmap = mxMmap; + sqlite3GlobalConfig.mxMmap = mxMmap; + sqlite3GlobalConfig.szMmap = szMmap; + break; + } + +#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */ + case SQLITE_CONFIG_WIN32_HEAPSIZE: { + /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit + ** unsigned integer value that specifies the maximum size of the created + ** heap. */ + sqlite3GlobalConfig.nHeap = va_arg(ap, int); + break; + } +#endif + + case SQLITE_CONFIG_PMASZ: { + sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int); + break; + } + + case SQLITE_CONFIG_STMTJRNL_SPILL: { + sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int); + break; + } + +#ifdef SQLITE_ENABLE_SORTER_REFERENCES + case SQLITE_CONFIG_SORTERREF_SIZE: { + int iVal = va_arg(ap, int); + if( iVal<0 ){ + iVal = SQLITE_DEFAULT_SORTERREF_SIZE; + } + sqlite3GlobalConfig.szSorterRef = (u32)iVal; + break; + } +#endif /* SQLITE_ENABLE_SORTER_REFERENCES */ + +#ifndef SQLITE_OMIT_DESERIALIZE + case SQLITE_CONFIG_MEMDB_MAXSIZE: { + sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); + break; + } +#endif /* SQLITE_OMIT_DESERIALIZE */ + + default: { + rc = SQLITE_ERROR; + break; + } + } + va_end(ap); + return rc; +} + +/* +** Set up the lookaside buffers for a database connection. +** Return SQLITE_OK on success. +** If lookaside is already active, return SQLITE_BUSY. +** +** The sz parameter is the number of bytes in each lookaside slot. +** The cnt parameter is the number of slots. If pStart is NULL the +** space for the lookaside memory is obtained from sqlite3_malloc(). +** If pStart is not NULL then it is sz*cnt bytes of memory to use for +** the lookaside memory. +*/ +static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ +#ifndef SQLITE_OMIT_LOOKASIDE + void *pStart; + sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt; + int nBig; /* Number of full-size slots */ + int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */ + + if( sqlite3LookasideUsed(db,0)>0 ){ + return SQLITE_BUSY; + } + /* Free any existing lookaside buffer for this handle before + ** allocating a new one so we don't have to have space for + ** both at the same time. + */ + if( db->lookaside.bMalloced ){ + sqlite3_free(db->lookaside.pStart); + } + /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger + ** than a pointer to be useful. + */ + sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */ + if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; + if( cnt<0 ) cnt = 0; + if( sz==0 || cnt==0 ){ + sz = 0; + pStart = 0; + }else if( pBuf==0 ){ + sqlite3BeginBenignMalloc(); + pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */ + sqlite3EndBenignMalloc(); + if( pStart ) szAlloc = sqlite3MallocSize(pStart); + }else{ + pStart = pBuf; + } +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + if( sz>=LOOKASIDE_SMALL*3 ){ + nBig = szAlloc/(3*LOOKASIDE_SMALL+sz); + nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; + }else if( sz>=LOOKASIDE_SMALL*2 ){ + nBig = szAlloc/(LOOKASIDE_SMALL+sz); + nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; + }else +#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ + if( sz>0 ){ + nBig = szAlloc/sz; + nSm = 0; + }else{ + nBig = nSm = 0; + } + db->lookaside.pStart = pStart; + db->lookaside.pInit = 0; + db->lookaside.pFree = 0; + db->lookaside.sz = (u16)sz; + db->lookaside.szTrue = (u16)sz; + if( pStart ){ + int i; + LookasideSlot *p; + assert( sz > (int)sizeof(LookasideSlot*) ); + p = (LookasideSlot*)pStart; + for(i=0; ipNext = db->lookaside.pInit; + db->lookaside.pInit = p; + p = (LookasideSlot*)&((u8*)p)[sz]; + } +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + db->lookaside.pSmallInit = 0; + db->lookaside.pSmallFree = 0; + db->lookaside.pMiddle = p; + for(i=0; ipNext = db->lookaside.pSmallInit; + db->lookaside.pSmallInit = p; + p = (LookasideSlot*)&((u8*)p)[LOOKASIDE_SMALL]; + } +#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ + assert( ((uptr)p)<=szAlloc + (uptr)pStart ); + db->lookaside.pEnd = p; + db->lookaside.bDisable = 0; + db->lookaside.bMalloced = pBuf==0 ?1:0; + db->lookaside.nSlot = nBig+nSm; + }else{ + db->lookaside.pStart = db; +#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE + db->lookaside.pSmallInit = 0; + db->lookaside.pSmallFree = 0; + db->lookaside.pMiddle = db; +#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ + db->lookaside.pEnd = db; + db->lookaside.bDisable = 1; + db->lookaside.sz = 0; + db->lookaside.bMalloced = 0; + db->lookaside.nSlot = 0; + } + assert( sqlite3LookasideUsed(db,0)==0 ); +#endif /* SQLITE_OMIT_LOOKASIDE */ + return SQLITE_OK; +} + +/* +** Return the mutex associated with a database connection. +*/ +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->mutex; +} + +/* +** Free up as much memory as we can from the given database +** connection. +*/ +SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){ + int i; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ){ + Pager *pPager = sqlite3BtreePager(pBt); + sqlite3PagerShrink(pPager); + } + } + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +/* +** Flush any dirty pages in the pager-cache for any attached database +** to disk. +*/ +SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ + int i; + int rc = SQLITE_OK; + int bSeenBusy = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + for(i=0; rc==SQLITE_OK && inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt && sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ + Pager *pPager = sqlite3BtreePager(pBt); + rc = sqlite3PagerFlush(pPager); + if( rc==SQLITE_BUSY ){ + bSeenBusy = 1; + rc = SQLITE_OK; + } + } + } + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc); +} + +/* +** Configuration settings for an individual database connection +*/ +SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ + va_list ap; + int rc; + va_start(ap, op); + switch( op ){ + case SQLITE_DBCONFIG_MAINDBNAME: { + /* IMP: R-06824-28531 */ + /* IMP: R-36257-52125 */ + db->aDb[0].zDbSName = va_arg(ap,char*); + rc = SQLITE_OK; + break; + } + case SQLITE_DBCONFIG_LOOKASIDE: { + void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ + int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ + int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */ + rc = setupLookaside(db, pBuf, sz, cnt); + break; + } + default: { + static const struct { + int op; /* The opcode */ + u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ + } aFlagOp[] = { + { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, + { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, + { SQLITE_DBCONFIG_ENABLE_VIEW, SQLITE_EnableView }, + { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, + { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, + { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, + { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG }, + { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, + { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, + { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, + { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema| + SQLITE_NoSchemaError }, + { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter }, + { SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL }, + { SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML }, + { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt }, + { SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema }, + }; + unsigned int i; + rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ + for(i=0; iflags; + if( onoff>0 ){ + db->flags |= aFlagOp[i].mask; + }else if( onoff==0 ){ + db->flags &= ~(u64)aFlagOp[i].mask; + } + if( oldFlags!=db->flags ){ + sqlite3ExpirePreparedStatements(db, 0); + } + if( pRes ){ + *pRes = (db->flags & aFlagOp[i].mask)!=0; + } + rc = SQLITE_OK; + break; + } + } + break; + } + } + va_end(ap); + return rc; +} + +/* +** This is the default collating function named "BINARY" which is always +** available. +*/ +static int binCollFunc( + void *NotUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 +){ + int rc, n; + UNUSED_PARAMETER(NotUsed); + n = nKey1xCmp!=binCollFunc || strcmp(p->zName,"BINARY")==0 ); + return p==0 || p->xCmp==binCollFunc; +} + +/* +** Another built-in collating sequence: NOCASE. +** +** This collating sequence is intended to be used for "case independent +** comparison". SQLite's knowledge of upper and lower case equivalents +** extends only to the 26 characters used in the English language. +** +** At the moment there is only a UTF-8 implementation. +*/ +static int nocaseCollatingFunc( + void *NotUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 +){ + int r = sqlite3StrNICmp( + (const char *)pKey1, (const char *)pKey2, (nKey1lastRowid; +} + +/* +** Set the value returned by the sqlite3_last_insert_rowid() API function. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif + sqlite3_mutex_enter(db->mutex); + db->lastRowid = iRowid; + sqlite3_mutex_leave(db->mutex); +} + +/* +** Return the number of changes in the most recent call to sqlite3_exec(). +*/ +SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->nChange; +} +SQLITE_API int sqlite3_changes(sqlite3 *db){ + return (int)sqlite3_changes64(db); +} + +/* +** Return the number of changes since the database handle was opened. +*/ +SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->nTotalChange; +} +SQLITE_API int sqlite3_total_changes(sqlite3 *db){ + return (int)sqlite3_total_changes64(db); +} + +/* +** Close all open savepoints. This function only manipulates fields of the +** database handle object, it does not close any savepoints that may be open +** at the b-tree/pager level. +*/ +SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){ + while( db->pSavepoint ){ + Savepoint *pTmp = db->pSavepoint; + db->pSavepoint = pTmp->pNext; + sqlite3DbFree(db, pTmp); + } + db->nSavepoint = 0; + db->nStatement = 0; + db->isTransactionSavepoint = 0; +} + +/* +** Invoke the destructor function associated with FuncDef p, if any. Except, +** if this is not the last copy of the function, do not invoke it. Multiple +** copies of a single function are created when create_function() is called +** with SQLITE_ANY as the encoding. +*/ +static void functionDestroy(sqlite3 *db, FuncDef *p){ + FuncDestructor *pDestructor; + assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 ); + pDestructor = p->u.pDestructor; + if( pDestructor ){ + pDestructor->nRef--; + if( pDestructor->nRef==0 ){ + pDestructor->xDestroy(pDestructor->pUserData); + sqlite3DbFree(db, pDestructor); + } + } +} + +/* +** Disconnect all sqlite3_vtab objects that belong to database connection +** db. This is called when db is being closed. +*/ +static void disconnectAllVtab(sqlite3 *db){ +#ifndef SQLITE_OMIT_VIRTUALTABLE + int i; + HashElem *p; + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + Schema *pSchema = db->aDb[i].pSchema; + if( pSchema ){ + for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ + Table *pTab = (Table *)sqliteHashData(p); + if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); + } + } + } + for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ + Module *pMod = (Module *)sqliteHashData(p); + if( pMod->pEpoTab ){ + sqlite3VtabDisconnect(db, pMod->pEpoTab); + } + } + sqlite3VtabUnlockList(db); + sqlite3BtreeLeaveAll(db); +#else + UNUSED_PARAMETER(db); +#endif +} + +/* +** Return TRUE if database connection db has unfinalized prepared +** statements or unfinished sqlite3_backup objects. +*/ +static int connectionIsBusy(sqlite3 *db){ + int j; + assert( sqlite3_mutex_held(db->mutex) ); + if( db->pVdbe ) return 1; + for(j=0; jnDb; j++){ + Btree *pBt = db->aDb[j].pBt; + if( pBt && sqlite3BtreeIsInBackup(pBt) ) return 1; + } + return 0; +} + +/* +** Close an existing SQLite database +*/ +static int sqlite3Close(sqlite3 *db, int forceZombie){ + if( !db ){ + /* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or + ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ + return SQLITE_OK; + } + if( !sqlite3SafetyCheckSickOrOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + sqlite3_mutex_enter(db->mutex); + if( db->mTrace & SQLITE_TRACE_CLOSE ){ + db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); + } + + /* Force xDisconnect calls on all virtual tables */ + disconnectAllVtab(db); + + /* If a transaction is open, the disconnectAllVtab() call above + ** will not have called the xDisconnect() method on any virtual + ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() + ** call will do so. We need to do this before the check for active + ** SQL statements below, as the v-table implementation may be storing + ** some prepared statements internally. + */ + sqlite3VtabRollback(db); + + /* Legacy behavior (sqlite3_close() behavior) is to return + ** SQLITE_BUSY if the connection can not be closed immediately. + */ + if( !forceZombie && connectionIsBusy(db) ){ + sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized " + "statements or unfinished backups"); + sqlite3_mutex_leave(db->mutex); + return SQLITE_BUSY; + } + +#ifdef SQLITE_ENABLE_SQLLOG + if( sqlite3GlobalConfig.xSqllog ){ + /* Closing the handle. Fourth parameter is passed the value 2. */ + sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); + } +#endif + + /* Convert the connection into a zombie and then close it. + */ + db->eOpenState = SQLITE_STATE_ZOMBIE; + sqlite3LeaveMutexAndCloseZombie(db); + return SQLITE_OK; +} + +/* +** Return the transaction state for a single databse, or the maximum +** transaction state over all attached databases if zSchema is null. +*/ +SQLITE_API int sqlite3_txn_state(sqlite3 *db, const char *zSchema){ + int iDb, nDb; + int iTxn = -1; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( zSchema ){ + nDb = iDb = sqlite3FindDbName(db, zSchema); + if( iDb<0 ) nDb--; + }else{ + iDb = 0; + nDb = db->nDb-1; + } + for(; iDb<=nDb; iDb++){ + Btree *pBt = db->aDb[iDb].pBt; + int x = pBt!=0 ? sqlite3BtreeTxnState(pBt) : SQLITE_TXN_NONE; + if( x>iTxn ) iTxn = x; + } + sqlite3_mutex_leave(db->mutex); + return iTxn; +} + +/* +** Two variations on the public interface for closing a database +** connection. The sqlite3_close() version returns SQLITE_BUSY and +** leaves the connection open if there are unfinalized prepared +** statements or unfinished sqlite3_backups. The sqlite3_close_v2() +** version forces the connection to become a zombie if there are +** unclosed resources, and arranges for deallocation when the last +** prepare statement or sqlite3_backup closes. +*/ +SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } +SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } + + +/* +** Close the mutex on database connection db. +** +** Furthermore, if database connection db is a zombie (meaning that there +** has been a prior call to sqlite3_close(db) or sqlite3_close_v2(db)) and +** every sqlite3_stmt has now been finalized and every sqlite3_backup has +** finished, then free all resources. +*/ +SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ + HashElem *i; /* Hash table iterator */ + int j; + + /* If there are outstanding sqlite3_stmt or sqlite3_backup objects + ** or if the connection has not yet been closed by sqlite3_close_v2(), + ** then just leave the mutex and return. + */ + if( db->eOpenState!=SQLITE_STATE_ZOMBIE || connectionIsBusy(db) ){ + sqlite3_mutex_leave(db->mutex); + return; + } + + /* If we reach this point, it means that the database connection has + ** closed all sqlite3_stmt and sqlite3_backup objects and has been + ** passed to sqlite3_close (meaning that it is a zombie). Therefore, + ** go ahead and free all resources. + */ + + /* If a transaction is open, roll it back. This also ensures that if + ** any database schemas have been modified by an uncommitted transaction + ** they are reset. And that the required b-tree mutex is held to make + ** the pager rollback and schema reset an atomic operation. */ + sqlite3RollbackAll(db, SQLITE_OK); + + /* Free any outstanding Savepoint structures. */ + sqlite3CloseSavepoints(db); + + /* Close all database connections */ + for(j=0; jnDb; j++){ + struct Db *pDb = &db->aDb[j]; + if( pDb->pBt ){ + sqlite3BtreeClose(pDb->pBt); + pDb->pBt = 0; + if( j!=1 ){ + pDb->pSchema = 0; + } + } + } + /* Clear the TEMP schema separately and last */ + if( db->aDb[1].pSchema ){ + sqlite3SchemaClear(db->aDb[1].pSchema); + } + sqlite3VtabUnlockList(db); + + /* Free up the array of auxiliary databases */ + sqlite3CollapseDatabaseArray(db); + assert( db->nDb<=2 ); + assert( db->aDb==db->aDbStatic ); + + /* Tell the code in notify.c that the connection no longer holds any + ** locks and does not require any further unlock-notify callbacks. + */ + sqlite3ConnectionClosed(db); + + for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ + FuncDef *pNext, *p; + p = sqliteHashData(i); + do{ + functionDestroy(db, p); + pNext = p->pNext; + sqlite3DbFree(db, p); + p = pNext; + }while( p ); + } + sqlite3HashClear(&db->aFunc); + for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ + CollSeq *pColl = (CollSeq *)sqliteHashData(i); + /* Invoke any destructors registered for collation sequence user data. */ + for(j=0; j<3; j++){ + if( pColl[j].xDel ){ + pColl[j].xDel(pColl[j].pUser); + } + } + sqlite3DbFree(db, pColl); + } + sqlite3HashClear(&db->aCollSeq); +#ifndef SQLITE_OMIT_VIRTUALTABLE + for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ + Module *pMod = (Module *)sqliteHashData(i); + sqlite3VtabEponymousTableClear(db, pMod); + sqlite3VtabModuleUnref(db, pMod); + } + sqlite3HashClear(&db->aModule); +#endif + + sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ + sqlite3ValueFree(db->pErr); + sqlite3CloseExtensions(db); +#if SQLITE_USER_AUTHENTICATION + sqlite3_free(db->auth.zAuthUser); + sqlite3_free(db->auth.zAuthPW); +#endif + + db->eOpenState = SQLITE_STATE_ERROR; + + /* The temp-database schema is allocated differently from the other schema + ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). + ** So it needs to be freed here. Todo: Why not roll the temp schema into + ** the same sqliteMalloc() as the one that allocates the database + ** structure? + */ + sqlite3DbFree(db, db->aDb[1].pSchema); + if( db->xAutovacDestr ){ + db->xAutovacDestr(db->pAutovacPagesArg); + } + sqlite3_mutex_leave(db->mutex); + db->eOpenState = SQLITE_STATE_CLOSED; + sqlite3_mutex_free(db->mutex); + assert( sqlite3LookasideUsed(db,0)==0 ); + if( db->lookaside.bMalloced ){ + sqlite3_free(db->lookaside.pStart); + } + sqlite3_free(db); +} + +/* +** Rollback all database files. If tripCode is not SQLITE_OK, then +** any write cursors are invalidated ("tripped" - as in "tripping a circuit +** breaker") and made to return tripCode if there are any further +** attempts to use that cursor. Read cursors remain open and valid +** but are "saved" in case the table pages are moved around. +*/ +SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ + int i; + int inTrans = 0; + int schemaChange; + assert( sqlite3_mutex_held(db->mutex) ); + sqlite3BeginBenignMalloc(); + + /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). + ** This is important in case the transaction being rolled back has + ** modified the database schema. If the b-tree mutexes are not taken + ** here, then another shared-cache connection might sneak in between + ** the database rollback and schema reset, which can cause false + ** corruption reports in some cases. */ + sqlite3BtreeEnterAll(db); + schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0; + + for(i=0; inDb; i++){ + Btree *p = db->aDb[i].pBt; + if( p ){ + if( sqlite3BtreeTxnState(p)==SQLITE_TXN_WRITE ){ + inTrans = 1; + } + sqlite3BtreeRollback(p, tripCode, !schemaChange); + } + } + sqlite3VtabRollback(db); + sqlite3EndBenignMalloc(); + + if( schemaChange ){ + sqlite3ExpirePreparedStatements(db, 0); + sqlite3ResetAllSchemasOfConnection(db); + } + sqlite3BtreeLeaveAll(db); + + /* Any deferred constraint violations have now been resolved. */ + db->nDeferredCons = 0; + db->nDeferredImmCons = 0; + db->flags &= ~(u64)(SQLITE_DeferFKs|SQLITE_CorruptRdOnly); + + /* If one has been configured, invoke the rollback-hook callback */ + if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ + db->xRollbackCallback(db->pRollbackArg); + } +} + +/* +** Return a static string containing the name corresponding to the error code +** specified in the argument. +*/ +#if defined(SQLITE_NEED_ERR_NAME) +SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ + const char *zName = 0; + int i, origRc = rc; + for(i=0; i<2 && zName==0; i++, rc &= 0xff){ + switch( rc ){ + case SQLITE_OK: zName = "SQLITE_OK"; break; + case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; + case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break; + case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; + case SQLITE_PERM: zName = "SQLITE_PERM"; break; + case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; + case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; + case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; + case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; + case SQLITE_BUSY_SNAPSHOT: zName = "SQLITE_BUSY_SNAPSHOT"; break; + case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; + case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; + case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; + case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; + case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; + case SQLITE_READONLY_CANTINIT: zName = "SQLITE_READONLY_CANTINIT"; break; + case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break; + case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break; + case SQLITE_READONLY_DIRECTORY: zName = "SQLITE_READONLY_DIRECTORY";break; + case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; + case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; + case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break; + case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break; + case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break; + case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break; + case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break; + case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break; + case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break; + case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; + case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; + case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; + case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; + case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; + case SQLITE_IOERR_CHECKRESERVEDLOCK: + zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; + case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; + case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break; + case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break; + case SQLITE_IOERR_SHMOPEN: zName = "SQLITE_IOERR_SHMOPEN"; break; + case SQLITE_IOERR_SHMSIZE: zName = "SQLITE_IOERR_SHMSIZE"; break; + case SQLITE_IOERR_SHMLOCK: zName = "SQLITE_IOERR_SHMLOCK"; break; + case SQLITE_IOERR_SHMMAP: zName = "SQLITE_IOERR_SHMMAP"; break; + case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break; + case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break; + case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break; + case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break; + case SQLITE_IOERR_CONVPATH: zName = "SQLITE_IOERR_CONVPATH"; break; + case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; + case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; + case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; + case SQLITE_FULL: zName = "SQLITE_FULL"; break; + case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; + case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break; + case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break; + case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break; + case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break; + case SQLITE_CANTOPEN_SYMLINK: zName = "SQLITE_CANTOPEN_SYMLINK"; break; + case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; + case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; + case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; + case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; + case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; + case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break; + case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break; + case SQLITE_CONSTRAINT_FOREIGNKEY: + zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break; + case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break; + case SQLITE_CONSTRAINT_PRIMARYKEY: + zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break; + case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break; + case SQLITE_CONSTRAINT_COMMITHOOK: + zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break; + case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break; + case SQLITE_CONSTRAINT_FUNCTION: + zName = "SQLITE_CONSTRAINT_FUNCTION"; break; + case SQLITE_CONSTRAINT_ROWID: zName = "SQLITE_CONSTRAINT_ROWID"; break; + case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; + case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; + case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; + case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; + case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; + case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; + case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; + case SQLITE_ROW: zName = "SQLITE_ROW"; break; + case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; + case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; + case SQLITE_NOTICE_RECOVER_ROLLBACK: + zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; + case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; + case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; + case SQLITE_DONE: zName = "SQLITE_DONE"; break; + } + } + if( zName==0 ){ + static char zBuf[50]; + sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc); + zName = zBuf; + } + return zName; +} +#endif + +/* +** Return a static string that describes the kind of error specified in the +** argument. +*/ +SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ + static const char* const aMsg[] = { + /* SQLITE_OK */ "not an error", + /* SQLITE_ERROR */ "SQL logic error", + /* SQLITE_INTERNAL */ 0, + /* SQLITE_PERM */ "access permission denied", + /* SQLITE_ABORT */ "query aborted", + /* SQLITE_BUSY */ "database is locked", + /* SQLITE_LOCKED */ "database table is locked", + /* SQLITE_NOMEM */ "out of memory", + /* SQLITE_READONLY */ "attempt to write a readonly database", + /* SQLITE_INTERRUPT */ "interrupted", + /* SQLITE_IOERR */ "disk I/O error", + /* SQLITE_CORRUPT */ "database disk image is malformed", + /* SQLITE_NOTFOUND */ "unknown operation", + /* SQLITE_FULL */ "database or disk is full", + /* SQLITE_CANTOPEN */ "unable to open database file", + /* SQLITE_PROTOCOL */ "locking protocol", + /* SQLITE_EMPTY */ 0, + /* SQLITE_SCHEMA */ "database schema has changed", + /* SQLITE_TOOBIG */ "string or blob too big", + /* SQLITE_CONSTRAINT */ "constraint failed", + /* SQLITE_MISMATCH */ "datatype mismatch", + /* SQLITE_MISUSE */ "bad parameter or other API misuse", +#ifdef SQLITE_DISABLE_LFS + /* SQLITE_NOLFS */ "large file support is disabled", +#else + /* SQLITE_NOLFS */ 0, +#endif + /* SQLITE_AUTH */ "authorization denied", + /* SQLITE_FORMAT */ 0, + /* SQLITE_RANGE */ "column index out of range", + /* SQLITE_NOTADB */ "file is not a database", + /* SQLITE_NOTICE */ "notification message", + /* SQLITE_WARNING */ "warning message", + }; + const char *zErr = "unknown error"; + switch( rc ){ + case SQLITE_ABORT_ROLLBACK: { + zErr = "abort due to ROLLBACK"; + break; + } + case SQLITE_ROW: { + zErr = "another row available"; + break; + } + case SQLITE_DONE: { + zErr = "no more rows available"; + break; + } + default: { + rc &= 0xff; + if( ALWAYS(rc>=0) && rcbusyTimeout; + int delay, prior; + + assert( count>=0 ); + if( count < NDELAY ){ + delay = delays[count]; + prior = totals[count]; + }else{ + delay = delays[NDELAY-1]; + prior = totals[NDELAY-1] + delay*(count-(NDELAY-1)); + } + if( prior + delay > tmout ){ + delay = tmout - prior; + if( delay<=0 ) return 0; + } + sqlite3OsSleep(db->pVfs, delay*1000); + return 1; +#else + /* This case for unix systems that lack usleep() support. Sleeping + ** must be done in increments of whole seconds */ + sqlite3 *db = (sqlite3 *)ptr; + int tmout = ((sqlite3 *)ptr)->busyTimeout; + if( (count+1)*1000 > tmout ){ + return 0; + } + sqlite3OsSleep(db->pVfs, 1000000); + return 1; +#endif +} + +/* +** Invoke the given busy handler. +** +** This routine is called when an operation failed to acquire a +** lock on VFS file pFile. +** +** If this routine returns non-zero, the lock is retried. If it +** returns 0, the operation aborts with an SQLITE_BUSY error. +*/ +SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){ + int rc; + if( p->xBusyHandler==0 || p->nBusy<0 ) return 0; + rc = p->xBusyHandler(p->pBusyArg, p->nBusy); + if( rc==0 ){ + p->nBusy = -1; + }else{ + p->nBusy++; + } + return rc; +} + +/* +** This routine sets the busy callback for an Sqlite database to the +** given callback function with the given argument. +*/ +SQLITE_API int sqlite3_busy_handler( + sqlite3 *db, + int (*xBusy)(void*,int), + void *pArg +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->busyHandler.xBusyHandler = xBusy; + db->busyHandler.pBusyArg = pArg; + db->busyHandler.nBusy = 0; + db->busyTimeout = 0; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK +/* +** This routine sets the progress callback for an Sqlite database to the +** given callback function with the given argument. The progress callback will +** be invoked every nOps opcodes. +*/ +SQLITE_API void sqlite3_progress_handler( + sqlite3 *db, + int nOps, + int (*xProgress)(void*), + void *pArg +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( nOps>0 ){ + db->xProgress = xProgress; + db->nProgressOps = (unsigned)nOps; + db->pProgressArg = pArg; + }else{ + db->xProgress = 0; + db->nProgressOps = 0; + db->pProgressArg = 0; + } + sqlite3_mutex_leave(db->mutex); +} +#endif + + +/* +** This routine installs a default busy handler that waits for the +** specified number of milliseconds before returning 0. +*/ +SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + if( ms>0 ){ + sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, + (void*)db); + db->busyTimeout = ms; + }else{ + sqlite3_busy_handler(db, 0, 0); + } + return SQLITE_OK; +} + +/* +** Cause any pending operation to stop at its earliest opportunity. +*/ +SQLITE_API void sqlite3_interrupt(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){ + (void)SQLITE_MISUSE_BKPT; + return; + } +#endif + AtomicStore(&db->u1.isInterrupted, 1); +} + + +/* +** This function is exactly the same as sqlite3_create_function(), except +** that it is designed to be called by internal code. The difference is +** that if a malloc() fails in sqlite3_create_function(), an error code +** is returned and the mallocFailed flag cleared. +*/ +SQLITE_PRIVATE int sqlite3CreateFunc( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int enc, + void *pUserData, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value **), + FuncDestructor *pDestructor +){ + FuncDef *p; + int extraFlags; + + assert( sqlite3_mutex_held(db->mutex) ); + assert( xValue==0 || xSFunc==0 ); + if( zFunctionName==0 /* Must have a valid name */ + || (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */ + || ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */ + || ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */ + || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) + || (255funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){ + if( db->nVdbeActive ){ + sqlite3ErrorWithMsg(db, SQLITE_BUSY, + "unable to delete/modify user-function due to active statements"); + assert( !db->mallocFailed ); + return SQLITE_BUSY; + }else{ + sqlite3ExpirePreparedStatements(db, 0); + } + }else if( xSFunc==0 && xFinal==0 ){ + /* Trying to delete a function that does not exist. This is a no-op. + ** https://sqlite.org/forum/forumpost/726219164b */ + return SQLITE_OK; + } + + p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); + assert(p || db->mallocFailed); + if( !p ){ + return SQLITE_NOMEM_BKPT; + } + + /* If an older version of the function with a configured destructor is + ** being replaced invoke the destructor function here. */ + functionDestroy(db, p); + + if( pDestructor ){ + pDestructor->nRef++; + } + p->u.pDestructor = pDestructor; + p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags; + testcase( p->funcFlags & SQLITE_DETERMINISTIC ); + testcase( p->funcFlags & SQLITE_DIRECTONLY ); + p->xSFunc = xSFunc ? xSFunc : xStep; + p->xFinalize = xFinal; + p->xValue = xValue; + p->xInverse = xInverse; + p->pUserData = pUserData; + p->nArg = (u16)nArg; + return SQLITE_OK; +} + +/* +** Worker function used by utf-8 APIs that create new functions: +** +** sqlite3_create_function() +** sqlite3_create_function_v2() +** sqlite3_create_window_function() +*/ +static int createFunctionApi( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) +){ + int rc = SQLITE_ERROR; + FuncDestructor *pArg = 0; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( xDestroy ){ + pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor)); + if( !pArg ){ + sqlite3OomFault(db); + xDestroy(p); + goto out; + } + pArg->nRef = 0; + pArg->xDestroy = xDestroy; + pArg->pUserData = p; + } + rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, + xSFunc, xStep, xFinal, xValue, xInverse, pArg + ); + if( pArg && pArg->nRef==0 ){ + assert( rc!=SQLITE_OK || (xStep==0 && xFinal==0) ); + xDestroy(p); + sqlite3_free(pArg); + } + + out: + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Create new user functions. +*/ +SQLITE_API int sqlite3_create_function( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*) +){ + return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep, + xFinal, 0, 0, 0); +} +SQLITE_API int sqlite3_create_function_v2( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*), + void (*xDestroy)(void *) +){ + return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep, + xFinal, 0, 0, xDestroy); +} +SQLITE_API int sqlite3_create_window_function( + sqlite3 *db, + const char *zFunc, + int nArg, + int enc, + void *p, + void (*xStep)(sqlite3_context*,int,sqlite3_value **), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value **), + void (*xDestroy)(void *) +){ + return createFunctionApi(db, zFunc, nArg, enc, p, 0, xStep, + xFinal, xValue, xInverse, xDestroy); +} + +#ifndef SQLITE_OMIT_UTF16 +SQLITE_API int sqlite3_create_function16( + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *p, + void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +){ + int rc; + char *zFunc8; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); + rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0,0,0); + sqlite3DbFree(db, zFunc8); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} +#endif + + +/* +** The following is the implementation of an SQL function that always +** fails with an error message stating that the function is used in the +** wrong context. The sqlite3_overload_function() API might construct +** SQL function that use this routine so that the functions will exist +** for name resolution but are actually overloaded by the xFindFunction +** method of virtual tables. +*/ +static void sqlite3InvalidFunction( + sqlite3_context *context, /* The function calling context */ + int NotUsed, /* Number of arguments to the function */ + sqlite3_value **NotUsed2 /* Value of each argument */ +){ + const char *zName = (const char*)sqlite3_user_data(context); + char *zErr; + UNUSED_PARAMETER2(NotUsed, NotUsed2); + zErr = sqlite3_mprintf( + "unable to use function %s in the requested context", zName); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); +} + +/* +** Declare that a function has been overloaded by a virtual table. +** +** If the function already exists as a regular global function, then +** this routine is a no-op. If the function does not exist, then create +** a new one that always throws a run-time error. +** +** When virtual tables intend to provide an overloaded function, they +** should call this routine to make sure the global function exists. +** A global function must exist in order for name resolution to work +** properly. +*/ +SQLITE_API int sqlite3_overload_function( + sqlite3 *db, + const char *zName, + int nArg +){ + int rc; + char *zCopy; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; + sqlite3_mutex_leave(db->mutex); + if( rc ) return SQLITE_OK; + zCopy = sqlite3_mprintf(zName); + if( zCopy==0 ) return SQLITE_NOMEM; + return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8, + zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free); +} + +#ifndef SQLITE_OMIT_TRACE +/* +** Register a trace function. The pArg from the previously registered trace +** is returned. +** +** A NULL trace function means that no tracing is executes. A non-NULL +** trace is a pointer to a function that is invoked at the start of each +** SQL statement. +*/ +#ifndef SQLITE_OMIT_DEPRECATED +SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ + void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pOld = db->pTraceArg; + db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; + db->trace.xLegacy = xTrace; + db->pTraceArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pOld; +} +#endif /* SQLITE_OMIT_DEPRECATED */ + +/* Register a trace callback using the version-2 interface. +*/ +SQLITE_API int sqlite3_trace_v2( + sqlite3 *db, /* Trace this connection */ + unsigned mTrace, /* Mask of events to be traced */ + int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ + void *pArg /* Context */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( mTrace==0 ) xTrace = 0; + if( xTrace==0 ) mTrace = 0; + db->mTrace = mTrace; + db->trace.xV2 = xTrace; + db->pTraceArg = pArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** Register a profile function. The pArg from the previously registered +** profile function is returned. +** +** A NULL profile function means that no profiling is executes. A non-NULL +** profile is a pointer to a function that is invoked at the conclusion of +** each SQL statement that is run. +*/ +SQLITE_API void *sqlite3_profile( + sqlite3 *db, + void (*xProfile)(void*,const char*,sqlite_uint64), + void *pArg +){ + void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pOld = db->pProfileArg; + db->xProfile = xProfile; + db->pProfileArg = pArg; + db->mTrace &= SQLITE_TRACE_NONLEGACY_MASK; + if( db->xProfile ) db->mTrace |= SQLITE_TRACE_XPROFILE; + sqlite3_mutex_leave(db->mutex); + return pOld; +} +#endif /* SQLITE_OMIT_DEPRECATED */ +#endif /* SQLITE_OMIT_TRACE */ + +/* +** Register a function to be invoked when a transaction commits. +** If the invoked function returns non-zero, then the commit becomes a +** rollback. +*/ +SQLITE_API void *sqlite3_commit_hook( + sqlite3 *db, /* Attach the hook to this database */ + int (*xCallback)(void*), /* Function to invoke on each commit */ + void *pArg /* Argument to the function */ +){ + void *pOld; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pOld = db->pCommitArg; + db->xCommitCallback = xCallback; + db->pCommitArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pOld; +} + +/* +** Register a callback to be invoked each time a row is updated, +** inserted or deleted using this database connection. +*/ +SQLITE_API void *sqlite3_update_hook( + sqlite3 *db, /* Attach the hook to this database */ + void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), + void *pArg /* Argument to the function */ +){ + void *pRet; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pRet = db->pUpdateArg; + db->xUpdateCallback = xCallback; + db->pUpdateArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} + +/* +** Register a callback to be invoked each time a transaction is rolled +** back by this database connection. +*/ +SQLITE_API void *sqlite3_rollback_hook( + sqlite3 *db, /* Attach the hook to this database */ + void (*xCallback)(void*), /* Callback function */ + void *pArg /* Argument to the function */ +){ + void *pRet; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pRet = db->pRollbackArg; + db->xRollbackCallback = xCallback; + db->pRollbackArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} + +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK +/* +** Register a callback to be invoked each time a row is updated, +** inserted or deleted using this database connection. +*/ +SQLITE_API void *sqlite3_preupdate_hook( + sqlite3 *db, /* Attach the hook to this database */ + void(*xCallback)( /* Callback function */ + void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64), + void *pArg /* First callback argument */ +){ + void *pRet; + sqlite3_mutex_enter(db->mutex); + pRet = db->pPreUpdateArg; + db->xPreUpdateCallback = xCallback; + db->pPreUpdateArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +} +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + +/* +** Register a function to be invoked prior to each autovacuum that +** determines the number of pages to vacuum. +*/ +SQLITE_API int sqlite3_autovacuum_pages( + sqlite3 *db, /* Attach the hook to this database */ + unsigned int (*xCallback)(void*,const char*,u32,u32,u32), + void *pArg, /* Argument to the function */ + void (*xDestructor)(void*) /* Destructor for pArg */ +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + if( xDestructor ) xDestructor(pArg); + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( db->xAutovacDestr ){ + db->xAutovacDestr(db->pAutovacPagesArg); + } + db->xAutovacPages = xCallback; + db->pAutovacPagesArg = pArg; + db->xAutovacDestr = xDestructor; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + + +#ifndef SQLITE_OMIT_WAL +/* +** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). +** Invoke sqlite3_wal_checkpoint if the number of frames in the log file +** is greater than sqlite3.pWalArg cast to an integer (the value configured by +** wal_autocheckpoint()). +*/ +SQLITE_PRIVATE int sqlite3WalDefaultHook( + void *pClientData, /* Argument */ + sqlite3 *db, /* Connection */ + const char *zDb, /* Database */ + int nFrame /* Size of WAL */ +){ + if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){ + sqlite3BeginBenignMalloc(); + sqlite3_wal_checkpoint(db, zDb); + sqlite3EndBenignMalloc(); + } + return SQLITE_OK; +} +#endif /* SQLITE_OMIT_WAL */ + +/* +** Configure an sqlite3_wal_hook() callback to automatically checkpoint +** a database after committing a transaction if there are nFrame or +** more frames in the log file. Passing zero or a negative value as the +** nFrame parameter disables automatic checkpoints entirely. +** +** The callback registered by this function replaces any existing callback +** registered using sqlite3_wal_hook(). Likewise, registering a callback +** using sqlite3_wal_hook() disables the automatic checkpoint mechanism +** configured by this function. +*/ +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ +#ifdef SQLITE_OMIT_WAL + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(nFrame); +#else +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + if( nFrame>0 ){ + sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame)); + }else{ + sqlite3_wal_hook(db, 0, 0); + } +#endif + return SQLITE_OK; +} + +/* +** Register a callback to be invoked each time a transaction is written +** into the write-ahead-log by this database connection. +*/ +SQLITE_API void *sqlite3_wal_hook( + sqlite3 *db, /* Attach the hook to this db handle */ + int(*xCallback)(void *, sqlite3*, const char*, int), + void *pArg /* First argument passed to xCallback() */ +){ +#ifndef SQLITE_OMIT_WAL + void *pRet; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + sqlite3_mutex_enter(db->mutex); + pRet = db->pWalArg; + db->xWalCallback = xCallback; + db->pWalArg = pArg; + sqlite3_mutex_leave(db->mutex); + return pRet; +#else + return 0; +#endif +} + +/* +** Checkpoint database zDb. +*/ +SQLITE_API int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +){ +#ifdef SQLITE_OMIT_WAL + return SQLITE_OK; +#else + int rc; /* Return code */ + int iDb; /* Schema to checkpoint */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + + /* Initialize the output variables to -1 in case an error occurs. */ + if( pnLog ) *pnLog = -1; + if( pnCkpt ) *pnCkpt = -1; + + assert( SQLITE_CHECKPOINT_PASSIVE==0 ); + assert( SQLITE_CHECKPOINT_FULL==1 ); + assert( SQLITE_CHECKPOINT_RESTART==2 ); + assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); + if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ + /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint + ** mode: */ + return SQLITE_MISUSE; + } + + sqlite3_mutex_enter(db->mutex); + if( zDb && zDb[0] ){ + iDb = sqlite3FindDbName(db, zDb); + }else{ + iDb = SQLITE_MAX_DB; /* This means process all schemas */ + } + if( iDb<0 ){ + rc = SQLITE_ERROR; + sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); + }else{ + db->busyHandler.nBusy = 0; + rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); + sqlite3Error(db, rc); + } + rc = sqlite3ApiExit(db, rc); + + /* If there are no active statements, clear the interrupt flag at this + ** point. */ + if( db->nVdbeActive==0 ){ + AtomicStore(&db->u1.isInterrupted, 0); + } + + sqlite3_mutex_leave(db->mutex); + return rc; +#endif +} + + +/* +** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points +** to contains a zero-length string, all attached databases are +** checkpointed. +*/ +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ + /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to + ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */ + return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0); +} + +#ifndef SQLITE_OMIT_WAL +/* +** Run a checkpoint on database iDb. This is a no-op if database iDb is +** not currently open in WAL mode. +** +** If a transaction is open on the database being checkpointed, this +** function returns SQLITE_LOCKED and a checkpoint is not attempted. If +** an error occurs while running the checkpoint, an SQLite error code is +** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK. +** +** The mutex on database handle db should be held by the caller. The mutex +** associated with the specific b-tree being checkpointed is taken by +** this function while the checkpoint is running. +** +** If iDb is passed SQLITE_MAX_DB then all attached databases are +** checkpointed. If an error is encountered it is returned immediately - +** no attempt is made to checkpoint any remaining databases. +** +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART +** or TRUNCATE. +*/ +SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ + int rc = SQLITE_OK; /* Return code */ + int i; /* Used to iterate through attached dbs */ + int bBusy = 0; /* True if SQLITE_BUSY has been encountered */ + + assert( sqlite3_mutex_held(db->mutex) ); + assert( !pnLog || *pnLog==-1 ); + assert( !pnCkpt || *pnCkpt==-1 ); + testcase( iDb==SQLITE_MAX_ATTACHED ); /* See forum post a006d86f72 */ + testcase( iDb==SQLITE_MAX_DB ); + + for(i=0; inDb && rc==SQLITE_OK; i++){ + if( i==iDb || iDb==SQLITE_MAX_DB ){ + rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt); + pnLog = 0; + pnCkpt = 0; + if( rc==SQLITE_BUSY ){ + bBusy = 1; + rc = SQLITE_OK; + } + } + } + + return (rc==SQLITE_OK && bBusy) ? SQLITE_BUSY : rc; +} +#endif /* SQLITE_OMIT_WAL */ + +/* +** This function returns true if main-memory should be used instead of +** a temporary file for transient pager files and statement journals. +** The value returned depends on the value of db->temp_store (runtime +** parameter) and the compile time value of SQLITE_TEMP_STORE. The +** following table describes the relationship between these two values +** and this functions return value. +** +** SQLITE_TEMP_STORE db->temp_store Location of temporary database +** ----------------- -------------- ------------------------------ +** 0 any file (return 0) +** 1 1 file (return 0) +** 1 2 memory (return 1) +** 1 0 file (return 0) +** 2 1 file (return 0) +** 2 2 memory (return 1) +** 2 0 memory (return 1) +** 3 any memory (return 1) +*/ +SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){ +#if SQLITE_TEMP_STORE==1 + return ( db->temp_store==2 ); +#endif +#if SQLITE_TEMP_STORE==2 + return ( db->temp_store!=1 ); +#endif +#if SQLITE_TEMP_STORE==3 + UNUSED_PARAMETER(db); + return 1; +#endif +#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3 + UNUSED_PARAMETER(db); + return 0; +#endif +} + +/* +** Return UTF-8 encoded English language explanation of the most recent +** error. +*/ +SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ + const char *z; + if( !db ){ + return sqlite3ErrStr(SQLITE_NOMEM_BKPT); + } + if( !sqlite3SafetyCheckSickOrOk(db) ){ + return sqlite3ErrStr(SQLITE_MISUSE_BKPT); + } + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + z = sqlite3ErrStr(SQLITE_NOMEM_BKPT); + }else{ + testcase( db->pErr==0 ); + z = db->errCode ? (char*)sqlite3_value_text(db->pErr) : 0; + assert( !db->mallocFailed ); + if( z==0 ){ + z = sqlite3ErrStr(db->errCode); + } + } + sqlite3_mutex_leave(db->mutex); + return z; +} + +/* +** Return the byte offset of the most recent error +*/ +SQLITE_API int sqlite3_error_offset(sqlite3 *db){ + int iOffset = -1; + if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){ + sqlite3_mutex_enter(db->mutex); + iOffset = db->errByteOffset; + sqlite3_mutex_leave(db->mutex); + } + return iOffset; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Return UTF-16 encoded English language explanation of the most recent +** error. +*/ +SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ + static const u16 outOfMem[] = { + 'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0 + }; + static const u16 misuse[] = { + 'b', 'a', 'd', ' ', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', ' ', + 'o', 'r', ' ', 'o', 't', 'h', 'e', 'r', ' ', 'A', 'P', 'I', ' ', + 'm', 'i', 's', 'u', 's', 'e', 0 + }; + + const void *z; + if( !db ){ + return (void *)outOfMem; + } + if( !sqlite3SafetyCheckSickOrOk(db) ){ + return (void *)misuse; + } + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + z = (void *)outOfMem; + }else{ + z = sqlite3_value_text16(db->pErr); + if( z==0 ){ + sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode)); + z = sqlite3_value_text16(db->pErr); + } + /* A malloc() may have failed within the call to sqlite3_value_text16() + ** above. If this is the case, then the db->mallocFailed flag needs to + ** be cleared before returning. Do this directly, instead of via + ** sqlite3ApiExit(), to avoid setting the database handle error message. + */ + sqlite3OomClear(db); + } + sqlite3_mutex_leave(db->mutex); + return z; +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** Return the most recent error code generated by an SQLite routine. If NULL is +** passed to this function, we assume a malloc() failed during sqlite3_open(). +*/ +SQLITE_API int sqlite3_errcode(sqlite3 *db){ + if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + if( !db || db->mallocFailed ){ + return SQLITE_NOMEM_BKPT; + } + return db->errCode & db->errMask; +} +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){ + if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + return SQLITE_MISUSE_BKPT; + } + if( !db || db->mallocFailed ){ + return SQLITE_NOMEM_BKPT; + } + return db->errCode; +} +SQLITE_API int sqlite3_system_errno(sqlite3 *db){ + return db ? db->iSysErrno : 0; +} + +/* +** Return a string that describes the kind of error specified in the +** argument. For now, this simply calls the internal sqlite3ErrStr() +** function. +*/ +SQLITE_API const char *sqlite3_errstr(int rc){ + return sqlite3ErrStr(rc); +} + +/* +** Create a new collating function for database "db". The name is zName +** and the encoding is enc. +*/ +static int createCollation( + sqlite3* db, + const char *zName, + u8 enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDel)(void*) +){ + CollSeq *pColl; + int enc2; + + assert( sqlite3_mutex_held(db->mutex) ); + + /* If SQLITE_UTF16 is specified as the encoding type, transform this + ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the + ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + */ + enc2 = enc; + testcase( enc2==SQLITE_UTF16 ); + testcase( enc2==SQLITE_UTF16_ALIGNED ); + if( enc2==SQLITE_UTF16 || enc2==SQLITE_UTF16_ALIGNED ){ + enc2 = SQLITE_UTF16NATIVE; + } + if( enc2SQLITE_UTF16BE ){ + return SQLITE_MISUSE_BKPT; + } + + /* Check if this call is removing or replacing an existing collation + ** sequence. If so, and there are active VMs, return busy. If there + ** are no active VMs, invalidate any pre-compiled statements. + */ + pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); + if( pColl && pColl->xCmp ){ + if( db->nVdbeActive ){ + sqlite3ErrorWithMsg(db, SQLITE_BUSY, + "unable to delete/modify collation sequence due to active statements"); + return SQLITE_BUSY; + } + sqlite3ExpirePreparedStatements(db, 0); + + /* If collation sequence pColl was created directly by a call to + ** sqlite3_create_collation, and not generated by synthCollSeq(), + ** then any copies made by synthCollSeq() need to be invalidated. + ** Also, collation destructor - CollSeq.xDel() - function may need + ** to be called. + */ + if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){ + CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName); + int j; + for(j=0; j<3; j++){ + CollSeq *p = &aColl[j]; + if( p->enc==pColl->enc ){ + if( p->xDel ){ + p->xDel(p->pUser); + } + p->xCmp = 0; + } + } + } + } + + pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1); + if( pColl==0 ) return SQLITE_NOMEM_BKPT; + pColl->xCmp = xCompare; + pColl->pUser = pCtx; + pColl->xDel = xDel; + pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); + sqlite3Error(db, SQLITE_OK); + return SQLITE_OK; +} + + +/* +** This array defines hard upper bounds on limit values. The +** initializer must be kept in sync with the SQLITE_LIMIT_* +** #defines in sqlite3.h. +*/ +static const int aHardLimit[] = { + SQLITE_MAX_LENGTH, + SQLITE_MAX_SQL_LENGTH, + SQLITE_MAX_COLUMN, + SQLITE_MAX_EXPR_DEPTH, + SQLITE_MAX_COMPOUND_SELECT, + SQLITE_MAX_VDBE_OP, + SQLITE_MAX_FUNCTION_ARG, + SQLITE_MAX_ATTACHED, + SQLITE_MAX_LIKE_PATTERN_LENGTH, + SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ + SQLITE_MAX_TRIGGER_DEPTH, + SQLITE_MAX_WORKER_THREADS, +}; + +/* +** Make sure the hard limits are set to reasonable values +*/ +#if SQLITE_MAX_LENGTH<100 +# error SQLITE_MAX_LENGTH must be at least 100 +#endif +#if SQLITE_MAX_SQL_LENGTH<100 +# error SQLITE_MAX_SQL_LENGTH must be at least 100 +#endif +#if SQLITE_MAX_SQL_LENGTH>SQLITE_MAX_LENGTH +# error SQLITE_MAX_SQL_LENGTH must not be greater than SQLITE_MAX_LENGTH +#endif +#if SQLITE_MAX_COMPOUND_SELECT<2 +# error SQLITE_MAX_COMPOUND_SELECT must be at least 2 +#endif +#if SQLITE_MAX_VDBE_OP<40 +# error SQLITE_MAX_VDBE_OP must be at least 40 +#endif +#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127 +# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127 +#endif +#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 +# error SQLITE_MAX_ATTACHED must be between 0 and 125 +#endif +#if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 +# error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 +#endif +#if SQLITE_MAX_COLUMN>32767 +# error SQLITE_MAX_COLUMN must not exceed 32767 +#endif +#if SQLITE_MAX_TRIGGER_DEPTH<1 +# error SQLITE_MAX_TRIGGER_DEPTH must be at least 1 +#endif +#if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50 +# error SQLITE_MAX_WORKER_THREADS must be between 0 and 50 +#endif + + +/* +** Change the value of a limit. Report the old value. +** If an invalid limit index is supplied, report -1. +** Make no changes but still report the old value if the +** new limit is negative. +** +** A new lower limit does not shrink existing constructs. +** It merely prevents new constructs that exceed the limit +** from forming. +*/ +SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ + int oldLimit; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + + /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME + ** there is a hard upper bound set at compile-time by a C preprocessor + ** macro called SQLITE_MAX_NAME. (The "_LIMIT_" in the name is changed to + ** "_MAX_".) + */ + assert( aHardLimit[SQLITE_LIMIT_LENGTH]==SQLITE_MAX_LENGTH ); + assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH ); + assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN ); + assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH ); + assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT); + assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP ); + assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG ); + assert( aHardLimit[SQLITE_LIMIT_ATTACHED]==SQLITE_MAX_ATTACHED ); + assert( aHardLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]== + SQLITE_MAX_LIKE_PATTERN_LENGTH ); + assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); + assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); + assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); + assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); + + + if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ + return -1; + } + oldLimit = db->aLimit[limitId]; + if( newLimit>=0 ){ /* IMP: R-52476-28732 */ + if( newLimit>aHardLimit[limitId] ){ + newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ + }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){ + newLimit = 1; + } + db->aLimit[limitId] = newLimit; + } + return oldLimit; /* IMP: R-53341-35419 */ +} + +/* +** This function is used to parse both URIs and non-URI filenames passed by the +** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database +** URIs specified as part of ATTACH statements. +** +** The first argument to this function is the name of the VFS to use (or +** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx" +** query parameter. The second argument contains the URI (or non-URI filename) +** itself. When this function is called the *pFlags variable should contain +** the default flags to open the database handle with. The value stored in +** *pFlags may be updated before returning if the URI filename contains +** "cache=xxx" or "mode=xxx" query parameters. +** +** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to +** the VFS that should be used to open the database file. *pzFile is set to +** point to a buffer containing the name of the file to open. The value +** stored in *pzFile is a database name acceptable to sqlite3_uri_parameter() +** and is in the same format as names created using sqlite3_create_filename(). +** The caller must invoke sqlite3_free_filename() (not sqlite3_free()!) on +** the value returned in *pzFile to avoid a memory leak. +** +** If an error occurs, then an SQLite error code is returned and *pzErrMsg +** may be set to point to a buffer containing an English language error +** message. It is the responsibility of the caller to eventually release +** this buffer by calling sqlite3_free(). +*/ +SQLITE_PRIVATE int sqlite3ParseUri( + const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */ + const char *zUri, /* Nul-terminated URI to parse */ + unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */ + sqlite3_vfs **ppVfs, /* OUT: VFS to use */ + char **pzFile, /* OUT: Filename component of URI */ + char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */ +){ + int rc = SQLITE_OK; + unsigned int flags = *pFlags; + const char *zVfs = zDefaultVfs; + char *zFile; + char c; + int nUri = sqlite3Strlen30(zUri); + + assert( *pzErrMsg==0 ); + + if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ + || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ + && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ + ){ + char *zOpt; + int eState; /* Parser state when parsing URI */ + int iIn; /* Input character index */ + int iOut = 0; /* Output character index */ + u64 nByte = nUri+8; /* Bytes of space to allocate */ + + /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen + ** method that there may be extra parameters following the file-name. */ + flags |= SQLITE_OPEN_URI; + + for(iIn=0; iIn=0 && octet<256 ); + if( octet==0 ){ +#ifndef SQLITE_ENABLE_URI_00_ERROR + /* This branch is taken when "%00" appears within the URI. In this + ** case we ignore all text in the remainder of the path, name or + ** value currently being parsed. So ignore the current character + ** and skip to the next "?", "=" or "&", as appropriate. */ + while( (c = zUri[iIn])!=0 && c!='#' + && (eState!=0 || c!='?') + && (eState!=1 || (c!='=' && c!='&')) + && (eState!=2 || c!='&') + ){ + iIn++; + } + continue; +#else + /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */ + *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri"); + rc = SQLITE_ERROR; + goto parse_uri_out; +#endif + } + c = octet; + }else if( eState==1 && (c=='&' || c=='=') ){ + if( zFile[iOut-1]==0 ){ + /* An empty option name. Ignore this option altogether. */ + while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++; + continue; + } + if( c=='&' ){ + zFile[iOut++] = '\0'; + }else{ + eState = 2; + } + c = 0; + }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ + c = 0; + eState = 1; + } + zFile[iOut++] = c; + } + if( eState==1 ) zFile[iOut++] = '\0'; + memset(zFile+iOut, 0, 4); /* end-of-options + empty journal filenames */ + + /* Check if there were any options specified that should be interpreted + ** here. Options that are interpreted here include "vfs" and those that + ** correspond to flags that may be passed to the sqlite3_open_v2() + ** method. */ + zOpt = &zFile[sqlite3Strlen30(zFile)+1]; + while( zOpt[0] ){ + int nOpt = sqlite3Strlen30(zOpt); + char *zVal = &zOpt[nOpt+1]; + int nVal = sqlite3Strlen30(zVal); + + if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ + zVfs = zVal; + }else{ + struct OpenMode { + const char *z; + int mode; + } *aMode = 0; + char *zModeType = 0; + int mask = 0; + int limit = 0; + + if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){ + static struct OpenMode aCacheMode[] = { + { "shared", SQLITE_OPEN_SHAREDCACHE }, + { "private", SQLITE_OPEN_PRIVATECACHE }, + { 0, 0 } + }; + + mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE; + aMode = aCacheMode; + limit = mask; + zModeType = "cache"; + } + if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){ + static struct OpenMode aOpenMode[] = { + { "ro", SQLITE_OPEN_READONLY }, + { "rw", SQLITE_OPEN_READWRITE }, + { "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE }, + { "memory", SQLITE_OPEN_MEMORY }, + { 0, 0 } + }; + + mask = SQLITE_OPEN_READONLY | SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY; + aMode = aOpenMode; + limit = mask & flags; + zModeType = "access"; + } + + if( aMode ){ + int i; + int mode = 0; + for(i=0; aMode[i].z; i++){ + const char *z = aMode[i].z; + if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ + mode = aMode[i].mode; + break; + } + } + if( mode==0 ){ + *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal); + rc = SQLITE_ERROR; + goto parse_uri_out; + } + if( (mode & ~SQLITE_OPEN_MEMORY)>limit ){ + *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s", + zModeType, zVal); + rc = SQLITE_PERM; + goto parse_uri_out; + } + flags = (flags & ~mask) | mode; + } + } + + zOpt = &zVal[nVal+1]; + } + + }else{ + zFile = sqlite3_malloc64(nUri+8); + if( !zFile ) return SQLITE_NOMEM_BKPT; + memset(zFile, 0, 4); + zFile += 4; + if( nUri ){ + memcpy(zFile, zUri, nUri); + } + memset(zFile+nUri, 0, 4); + flags &= ~SQLITE_OPEN_URI; + } + + *ppVfs = sqlite3_vfs_find(zVfs); + if( *ppVfs==0 ){ + *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); + rc = SQLITE_ERROR; + } + parse_uri_out: + if( rc!=SQLITE_OK ){ + sqlite3_free_filename(zFile); + zFile = 0; + } + *pFlags = flags; + *pzFile = zFile; + return rc; +} + +/* +** This routine does the core work of extracting URI parameters from a +** database filename for the sqlite3_uri_parameter() interface. +*/ +static const char *uriParameter(const char *zFilename, const char *zParam){ + zFilename += sqlite3Strlen30(zFilename) + 1; + while( ALWAYS(zFilename!=0) && zFilename[0] ){ + int x = strcmp(zFilename, zParam); + zFilename += sqlite3Strlen30(zFilename) + 1; + if( x==0 ) return zFilename; + zFilename += sqlite3Strlen30(zFilename) + 1; + } + return 0; +} + + + +/* +** This routine does the work of opening a database on behalf of +** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" +** is UTF-8 encoded. +*/ +static int openDatabase( + const char *zFilename, /* Database filename UTF-8 encoded */ + sqlite3 **ppDb, /* OUT: Returned database handle */ + unsigned int flags, /* Operational flags */ + const char *zVfs /* Name of the VFS to use */ +){ + sqlite3 *db; /* Store allocated handle here */ + int rc; /* Return code */ + int isThreadsafe; /* True for threadsafe connections */ + char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ + char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ + int i; /* Loop counter */ + +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppDb==0 ) return SQLITE_MISUSE_BKPT; +#endif + *ppDb = 0; +#ifndef SQLITE_OMIT_AUTOINIT + rc = sqlite3_initialize(); + if( rc ) return rc; +#endif + + if( sqlite3GlobalConfig.bCoreMutex==0 ){ + isThreadsafe = 0; + }else if( flags & SQLITE_OPEN_NOMUTEX ){ + isThreadsafe = 0; + }else if( flags & SQLITE_OPEN_FULLMUTEX ){ + isThreadsafe = 1; + }else{ + isThreadsafe = sqlite3GlobalConfig.bFullMutex; + } + + if( flags & SQLITE_OPEN_PRIVATECACHE ){ + flags &= ~SQLITE_OPEN_SHAREDCACHE; + }else if( sqlite3GlobalConfig.sharedCacheEnabled ){ + flags |= SQLITE_OPEN_SHAREDCACHE; + } + + /* Remove harmful bits from the flags parameter + ** + ** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were + ** dealt with in the previous code block. Besides these, the only + ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, + ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, + ** SQLITE_OPEN_PRIVATECACHE, SQLITE_OPEN_EXRESCODE, and some reserved + ** bits. Silently mask off all other flags. + */ + flags &= ~( SQLITE_OPEN_DELETEONCLOSE | + SQLITE_OPEN_EXCLUSIVE | + SQLITE_OPEN_MAIN_DB | + SQLITE_OPEN_TEMP_DB | + SQLITE_OPEN_TRANSIENT_DB | + SQLITE_OPEN_MAIN_JOURNAL | + SQLITE_OPEN_TEMP_JOURNAL | + SQLITE_OPEN_SUBJOURNAL | + SQLITE_OPEN_SUPER_JOURNAL | + SQLITE_OPEN_NOMUTEX | + SQLITE_OPEN_FULLMUTEX | + SQLITE_OPEN_WAL + ); + + /* Allocate the sqlite data structure */ + db = sqlite3MallocZero( sizeof(sqlite3) ); + if( db==0 ) goto opendb_out; + if( isThreadsafe +#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS + || sqlite3GlobalConfig.bCoreMutex +#endif + ){ + db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); + if( db->mutex==0 ){ + sqlite3_free(db); + db = 0; + goto opendb_out; + } + if( isThreadsafe==0 ){ + sqlite3MutexWarnOnContention(db->mutex); + } + } + sqlite3_mutex_enter(db->mutex); + db->errMask = (flags & SQLITE_OPEN_EXRESCODE)!=0 ? 0xffffffff : 0xff; + db->nDb = 2; + db->eOpenState = SQLITE_STATE_BUSY; + db->aDb = db->aDbStatic; + db->lookaside.bDisable = 1; + db->lookaside.sz = 0; + + assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); + memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); + db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; + db->autoCommit = 1; + db->nextAutovac = -1; + db->szMmap = sqlite3GlobalConfig.szMmap; + db->nextPagesize = 0; + db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ +#ifdef SQLITE_ENABLE_SORTER_MMAP + /* Beginning with version 3.37.0, using the VFS xFetch() API to memory-map + ** the temporary files used to do external sorts (see code in vdbesort.c) + ** is disabled. It can still be used either by defining + ** SQLITE_ENABLE_SORTER_MMAP at compile time or by using the + ** SQLITE_TESTCTRL_SORTER_MMAP test-control at runtime. */ + db->nMaxSorterMmap = 0x7FFFFFFF; +#endif + db->flags |= SQLITE_ShortColNames + | SQLITE_EnableTrigger + | SQLITE_EnableView + | SQLITE_CacheSpill +#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0 + | SQLITE_TrustedSchema +#endif +/* The SQLITE_DQS compile-time option determines the default settings +** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML. +** +** SQLITE_DQS SQLITE_DBCONFIG_DQS_DDL SQLITE_DBCONFIG_DQS_DML +** ---------- ----------------------- ----------------------- +** undefined on on +** 3 on on +** 2 on off +** 1 off on +** 0 off off +** +** Legacy behavior is 3 (double-quoted string literals are allowed anywhere) +** and so that is the default. But developers are encouranged to use +** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible. +*/ +#if !defined(SQLITE_DQS) +# define SQLITE_DQS 3 +#endif +#if (SQLITE_DQS&1)==1 + | SQLITE_DqsDML +#endif +#if (SQLITE_DQS&2)==2 + | SQLITE_DqsDDL +#endif + +#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX + | SQLITE_AutoIndex +#endif +#if SQLITE_DEFAULT_CKPTFULLFSYNC + | SQLITE_CkptFullFSync +#endif +#if SQLITE_DEFAULT_FILE_FORMAT<4 + | SQLITE_LegacyFileFmt +#endif +#ifdef SQLITE_ENABLE_LOAD_EXTENSION + | SQLITE_LoadExtension +#endif +#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS + | SQLITE_RecTriggers +#endif +#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS + | SQLITE_ForeignKeys +#endif +#if defined(SQLITE_REVERSE_UNORDERED_SELECTS) + | SQLITE_ReverseOrder +#endif +#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) + | SQLITE_CellSizeCk +#endif +#if defined(SQLITE_ENABLE_FTS3_TOKENIZER) + | SQLITE_Fts3Tokenizer +#endif +#if defined(SQLITE_ENABLE_QPSG) + | SQLITE_EnableQPSG +#endif +#if defined(SQLITE_DEFAULT_DEFENSIVE) + | SQLITE_Defensive +#endif +#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE) + | SQLITE_LegacyAlter +#endif + ; + sqlite3HashInit(&db->aCollSeq); +#ifndef SQLITE_OMIT_VIRTUALTABLE + sqlite3HashInit(&db->aModule); +#endif + + /* Add the default collation sequence BINARY. BINARY works for both UTF-8 + ** and UTF-16, so add a version for each to avoid any unnecessary + ** conversions. The only error that can occur here is a malloc() failure. + ** + ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating + ** functions: + */ + createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0); + createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); + createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); + createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); + createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0); + if( db->mallocFailed ){ + goto opendb_out; + } + + /* Parse the filename/URI argument + ** + ** Only allow sensible combinations of bits in the flags argument. + ** Throw an error if any non-sense combination is used. If we + ** do not block illegal combinations here, it could trigger + ** assert() statements in deeper layers. Sensible combinations + ** are: + ** + ** 1: SQLITE_OPEN_READONLY + ** 2: SQLITE_OPEN_READWRITE + ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE + */ + db->openFlags = flags; + assert( SQLITE_OPEN_READONLY == 0x01 ); + assert( SQLITE_OPEN_READWRITE == 0x02 ); + assert( SQLITE_OPEN_CREATE == 0x04 ); + testcase( (1<<(flags&7))==0x02 ); /* READONLY */ + testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ + testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ + if( ((1<<(flags&7)) & 0x46)==0 ){ + rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */ + }else{ + rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); + } + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); + sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); + sqlite3_free(zErrMsg); + goto opendb_out; + } + + /* Open the backend database driver */ + rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, + flags | SQLITE_OPEN_MAIN_DB); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_IOERR_NOMEM ){ + rc = SQLITE_NOMEM_BKPT; + } + sqlite3Error(db, rc); + goto opendb_out; + } + sqlite3BtreeEnter(db->aDb[0].pBt); + db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); + if( !db->mallocFailed ){ + sqlite3SetTextEncoding(db, SCHEMA_ENC(db)); + } + sqlite3BtreeLeave(db->aDb[0].pBt); + db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); + + /* The default safety_level for the main database is FULL; for the temp + ** database it is OFF. This matches the pager layer defaults. + */ + db->aDb[0].zDbSName = "main"; + db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; + db->aDb[1].zDbSName = "temp"; + db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; + + db->eOpenState = SQLITE_STATE_OPEN; + if( db->mallocFailed ){ + goto opendb_out; + } + + /* Register all built-in functions, but do not attempt to read the + ** database schema yet. This is delayed until the first time the database + ** is accessed. + */ + sqlite3Error(db, SQLITE_OK); + sqlite3RegisterPerConnectionBuiltinFunctions(db); + rc = sqlite3_errcode(db); + + + /* Load compiled-in extensions */ + for(i=0; rc==SQLITE_OK && imDbFlags |= DBFLAG_InternalFunc; +#endif + + /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking + ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking + ** mode. Doing nothing at all also makes NORMAL the default. + */ +#ifdef SQLITE_DEFAULT_LOCKING_MODE + db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE; + sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt), + SQLITE_DEFAULT_LOCKING_MODE); +#endif + + if( rc ) sqlite3Error(db, rc); + + /* Enable the lookaside-malloc subsystem */ + setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside, + sqlite3GlobalConfig.nLookaside); + + sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); + +opendb_out: + if( db ){ + assert( db->mutex!=0 || isThreadsafe==0 + || sqlite3GlobalConfig.bFullMutex==0 ); + sqlite3_mutex_leave(db->mutex); + } + rc = sqlite3_errcode(db); + assert( db!=0 || (rc&0xff)==SQLITE_NOMEM ); + if( (rc&0xff)==SQLITE_NOMEM ){ + sqlite3_close(db); + db = 0; + }else if( rc!=SQLITE_OK ){ + db->eOpenState = SQLITE_STATE_SICK; + } + *ppDb = db; +#ifdef SQLITE_ENABLE_SQLLOG + if( sqlite3GlobalConfig.xSqllog ){ + /* Opening a db handle. Fourth parameter is passed 0. */ + void *pArg = sqlite3GlobalConfig.pSqllogArg; + sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); + } +#endif + sqlite3_free_filename(zOpen); + return rc; +} + + +/* +** Open a new database handle. +*/ +SQLITE_API int sqlite3_open( + const char *zFilename, + sqlite3 **ppDb +){ + return openDatabase(zFilename, ppDb, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); +} +SQLITE_API int sqlite3_open_v2( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ +){ + return openDatabase(filename, ppDb, (unsigned int)flags, zVfs); +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Open a new database handle. +*/ +SQLITE_API int sqlite3_open16( + const void *zFilename, + sqlite3 **ppDb +){ + char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ + sqlite3_value *pVal; + int rc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( ppDb==0 ) return SQLITE_MISUSE_BKPT; +#endif + *ppDb = 0; +#ifndef SQLITE_OMIT_AUTOINIT + rc = sqlite3_initialize(); + if( rc ) return rc; +#endif + if( zFilename==0 ) zFilename = "\000\000"; + pVal = sqlite3ValueNew(0); + sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); + zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); + if( zFilename8 ){ + rc = openDatabase(zFilename8, ppDb, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); + assert( *ppDb || rc==SQLITE_NOMEM ); + if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){ + SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE; + } + }else{ + rc = SQLITE_NOMEM_BKPT; + } + sqlite3ValueFree(pVal); + + return rc & 0xff; +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** Register a new collation sequence with the database handle db. +*/ +SQLITE_API int sqlite3_create_collation( + sqlite3* db, + const char *zName, + int enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*) +){ + return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0); +} + +/* +** Register a new collation sequence with the database handle db. +*/ +SQLITE_API int sqlite3_create_collation_v2( + sqlite3* db, + const char *zName, + int enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDel)(void*) +){ + int rc; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Register a new collation sequence with the database handle db. +*/ +SQLITE_API int sqlite3_create_collation16( + sqlite3* db, + const void *zName, + int enc, + void* pCtx, + int(*xCompare)(void*,int,const void*,int,const void*) +){ + int rc = SQLITE_OK; + char *zName8; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + assert( !db->mallocFailed ); + zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE); + if( zName8 ){ + rc = createCollation(db, zName8, (u8)enc, pCtx, xCompare, 0); + sqlite3DbFree(db, zName8); + } + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} +#endif /* SQLITE_OMIT_UTF16 */ + +/* +** Register a collation sequence factory callback with the database handle +** db. Replace any previously installed collation sequence factory. +*/ +SQLITE_API int sqlite3_collation_needed( + sqlite3 *db, + void *pCollNeededArg, + void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*) +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->xCollNeeded = xCollNeeded; + db->xCollNeeded16 = 0; + db->pCollNeededArg = pCollNeededArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_UTF16 +/* +** Register a collation sequence factory callback with the database handle +** db. Replace any previously installed collation sequence factory. +*/ +SQLITE_API int sqlite3_collation_needed16( + sqlite3 *db, + void *pCollNeededArg, + void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*) +){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->xCollNeeded = 0; + db->xCollNeeded16 = xCollNeeded16; + db->pCollNeededArg = pCollNeededArg; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} +#endif /* SQLITE_OMIT_UTF16 */ + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** This function is now an anachronism. It used to be used to recover from a +** malloc() failure, but SQLite now does this automatically. +*/ +SQLITE_API int sqlite3_global_recover(void){ + return SQLITE_OK; +} +#endif + +/* +** Test to see whether or not the database connection is in autocommit +** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on +** by default. Autocommit is disabled by a BEGIN statement and reenabled +** by the next COMMIT or ROLLBACK. +*/ +SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + return db->autoCommit; +} + +/* +** The following routines are substitutes for constants SQLITE_CORRUPT, +** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error +** constants. They serve two purposes: +** +** 1. Serve as a convenient place to set a breakpoint in a debugger +** to detect when version error conditions occurs. +** +** 2. Invoke sqlite3_log() to provide the source code location where +** a low-level error is first detected. +*/ +SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ + sqlite3_log(iErr, "%s at line %d of [%.10s]", + zType, lineno, 20+sqlite3_sourceid()); + return iErr; +} +SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption"); +} +SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse"); +} +SQLITE_PRIVATE int sqlite3CantopenError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file"); +} +#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) +SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){ + char zMsg[100]; + sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno); + testcase( sqlite3GlobalConfig.xLog!=0 ); + return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); +} +#endif +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3NomemError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM"); +} +SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error"); +} +#endif + +#ifndef SQLITE_OMIT_DEPRECATED +/* +** This is a convenience routine that makes sure that all thread-specific +** data for this thread has been deallocated. +** +** SQLite no longer uses thread-specific data so this routine is now a +** no-op. It is retained for historical compatibility. +*/ +SQLITE_API void sqlite3_thread_cleanup(void){ +} +#endif + +/* +** Return meta information about a specific column of a database table. +** See comment in sqlite3.h (sqlite.h.in) for details. +*/ +SQLITE_API int sqlite3_table_column_metadata( + sqlite3 *db, /* Connection handle */ + const char *zDbName, /* Database name or NULL */ + const char *zTableName, /* Table name */ + const char *zColumnName, /* Column name */ + char const **pzDataType, /* OUTPUT: Declared data type */ + char const **pzCollSeq, /* OUTPUT: Collation sequence name */ + int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int *pPrimaryKey, /* OUTPUT: True if column part of PK */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ +){ + int rc; + char *zErrMsg = 0; + Table *pTab = 0; + Column *pCol = 0; + int iCol = 0; + char const *zDataType = 0; + char const *zCollSeq = 0; + int notnull = 0; + int primarykey = 0; + int autoinc = 0; + + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){ + return SQLITE_MISUSE_BKPT; + } +#endif + + /* Ensure the database schema has been loaded */ + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + rc = sqlite3Init(db, &zErrMsg); + if( SQLITE_OK!=rc ){ + goto error_out; + } + + /* Locate the table in question */ + pTab = sqlite3FindTable(db, zTableName, zDbName); + if( !pTab || IsView(pTab) ){ + pTab = 0; + goto error_out; + } + + /* Find the column for which info is requested */ + if( zColumnName==0 ){ + /* Query for existance of table only */ + }else{ + for(iCol=0; iColnCol; iCol++){ + pCol = &pTab->aCol[iCol]; + if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){ + break; + } + } + if( iCol==pTab->nCol ){ + if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ + iCol = pTab->iPKey; + pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; + }else{ + pTab = 0; + goto error_out; + } + } + } + + /* The following block stores the meta information that will be returned + ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey + ** and autoinc. At this point there are two possibilities: + ** + ** 1. The specified column name was rowid", "oid" or "_rowid_" + ** and there is no explicitly declared IPK column. + ** + ** 2. The table is not a view and the column name identified an + ** explicitly declared column. Copy meta information from *pCol. + */ + if( pCol ){ + zDataType = sqlite3ColumnType(pCol,0); + zCollSeq = sqlite3ColumnColl(pCol); + notnull = pCol->notNull!=0; + primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; + autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; + }else{ + zDataType = "INTEGER"; + primarykey = 1; + } + if( !zCollSeq ){ + zCollSeq = sqlite3StrBINARY; + } + +error_out: + sqlite3BtreeLeaveAll(db); + + /* Whether the function call succeeded or failed, set the output parameters + ** to whatever their local counterparts contain. If an error did occur, + ** this has the effect of zeroing all output parameters. + */ + if( pzDataType ) *pzDataType = zDataType; + if( pzCollSeq ) *pzCollSeq = zCollSeq; + if( pNotNull ) *pNotNull = notnull; + if( pPrimaryKey ) *pPrimaryKey = primarykey; + if( pAutoinc ) *pAutoinc = autoinc; + + if( SQLITE_OK==rc && !pTab ){ + sqlite3DbFree(db, zErrMsg); + zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName, + zColumnName); + rc = SQLITE_ERROR; + } + sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); + sqlite3DbFree(db, zErrMsg); + rc = sqlite3ApiExit(db, rc); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Sleep for a little while. Return the amount of time slept. +*/ +SQLITE_API int sqlite3_sleep(int ms){ + sqlite3_vfs *pVfs; + int rc; + pVfs = sqlite3_vfs_find(0); + if( pVfs==0 ) return 0; + + /* This function works in milliseconds, but the underlying OsSleep() + ** API uses microseconds. Hence the 1000's. + */ + rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000); + return rc; +} + +/* +** Enable or disable the extended result codes. +*/ +SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + db->errMask = onoff ? 0xffffffff : 0xff; + sqlite3_mutex_leave(db->mutex); + return SQLITE_OK; +} + +/* +** Invoke the xFileControl method on a particular database. +*/ +SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ + int rc = SQLITE_ERROR; + Btree *pBtree; + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +#endif + sqlite3_mutex_enter(db->mutex); + pBtree = sqlite3DbNameToBtree(db, zDbName); + if( pBtree ){ + Pager *pPager; + sqlite3_file *fd; + sqlite3BtreeEnter(pBtree); + pPager = sqlite3BtreePager(pBtree); + assert( pPager!=0 ); + fd = sqlite3PagerFile(pPager); + assert( fd!=0 ); + if( op==SQLITE_FCNTL_FILE_POINTER ){ + *(sqlite3_file**)pArg = fd; + rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_VFS_POINTER ){ + *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); + rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ + *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); + rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_DATA_VERSION ){ + *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); + rc = SQLITE_OK; + }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ + int iNew = *(int*)pArg; + *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); + if( iNew>=0 && iNew<=255 ){ + sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); + } + rc = SQLITE_OK; + }else{ + int nSave = db->busyHandler.nBusy; + rc = sqlite3OsFileControl(fd, op, pArg); + db->busyHandler.nBusy = nSave; + } + sqlite3BtreeLeave(pBtree); + } + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** Interface to the testing logic. +*/ +SQLITE_API int sqlite3_test_control(int op, ...){ + int rc = 0; +#ifdef SQLITE_UNTESTABLE + UNUSED_PARAMETER(op); +#else + va_list ap; + va_start(ap, op); + switch( op ){ + + /* + ** Save the current state of the PRNG. + */ + case SQLITE_TESTCTRL_PRNG_SAVE: { + sqlite3PrngSaveState(); + break; + } + + /* + ** Restore the state of the PRNG to the last state saved using + ** PRNG_SAVE. If PRNG_SAVE has never before been called, then + ** this verb acts like PRNG_RESET. + */ + case SQLITE_TESTCTRL_PRNG_RESTORE: { + sqlite3PrngRestoreState(); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, int x, sqlite3 *db); + ** + ** Control the seed for the pseudo-random number generator (PRNG) that + ** is built into SQLite. Cases: + ** + ** x!=0 && db!=0 Seed the PRNG to the current value of the + ** schema cookie in the main database for db, or + ** x if the schema cookie is zero. This case + ** is convenient to use with database fuzzers + ** as it allows the fuzzer some control over the + ** the PRNG seed. + ** + ** x!=0 && db==0 Seed the PRNG to the value of x. + ** + ** x==0 && db==0 Revert to default behavior of using the + ** xRandomness method on the primary VFS. + ** + ** This test-control also resets the PRNG so that the new seed will + ** be used for the next call to sqlite3_randomness(). + */ +#ifndef SQLITE_OMIT_WSD + case SQLITE_TESTCTRL_PRNG_SEED: { + int x = va_arg(ap, int); + int y; + sqlite3 *db = va_arg(ap, sqlite3*); + assert( db==0 || db->aDb[0].pSchema!=0 ); + if( db && (y = db->aDb[0].pSchema->schema_cookie)!=0 ){ x = y; } + sqlite3Config.iPrngSeed = x; + sqlite3_randomness(0,0); + break; + } +#endif + + /* + ** sqlite3_test_control(BITVEC_TEST, size, program) + ** + ** Run a test against a Bitvec object of size. The program argument + ** is an array of integers that defines the test. Return -1 on a + ** memory allocation error, 0 on success, or non-zero for an error. + ** See the sqlite3BitvecBuiltinTest() for additional information. + */ + case SQLITE_TESTCTRL_BITVEC_TEST: { + int sz = va_arg(ap, int); + int *aProg = va_arg(ap, int*); + rc = sqlite3BitvecBuiltinTest(sz, aProg); + break; + } + + /* + ** sqlite3_test_control(FAULT_INSTALL, xCallback) + ** + ** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called, + ** if xCallback is not NULL. + ** + ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) + ** is called immediately after installing the new callback and the return + ** value from sqlite3FaultSim(0) becomes the return from + ** sqlite3_test_control(). + */ + case SQLITE_TESTCTRL_FAULT_INSTALL: { + /* A bug in MSVC prevents it from understanding pointers to functions + ** types in the second argument to va_arg(). Work around the problem + ** using a typedef. + ** http://support.microsoft.com/kb/47961 <-- dead hyperlink + ** Search at http://web.archive.org/ to find the 2015-03-16 archive + ** of the link above to see the original text. + ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int)); + */ + typedef int(*sqlite3FaultFuncType)(int); + sqlite3GlobalConfig.xTestCallback = va_arg(ap, sqlite3FaultFuncType); + rc = sqlite3FaultSim(0); + break; + } + + /* + ** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd) + ** + ** Register hooks to call to indicate which malloc() failures + ** are benign. + */ + case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: { + typedef void (*void_function)(void); + void_function xBenignBegin; + void_function xBenignEnd; + xBenignBegin = va_arg(ap, void_function); + xBenignEnd = va_arg(ap, void_function); + sqlite3BenignMallocHooks(xBenignBegin, xBenignEnd); + break; + } + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, unsigned int X) + ** + ** Set the PENDING byte to the value in the argument, if X>0. + ** Make no changes if X==0. Return the value of the pending byte + ** as it existing before this routine was called. + ** + ** IMPORTANT: Changing the PENDING byte from 0x40000000 results in + ** an incompatible database file format. Changing the PENDING byte + ** while any database connection is open results in undefined and + ** deleterious behavior. + */ + case SQLITE_TESTCTRL_PENDING_BYTE: { + rc = PENDING_BYTE; +#ifndef SQLITE_OMIT_WSD + { + unsigned int newVal = va_arg(ap, unsigned int); + if( newVal ) sqlite3PendingByte = newVal; + } +#endif + break; + } + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, int X) + ** + ** This action provides a run-time test to see whether or not + ** assert() was enabled at compile-time. If X is true and assert() + ** is enabled, then the return value is true. If X is true and + ** assert() is disabled, then the return value is zero. If X is + ** false and assert() is enabled, then the assertion fires and the + ** process aborts. If X is false and assert() is disabled, then the + ** return value is zero. + */ + case SQLITE_TESTCTRL_ASSERT: { + volatile int x = 0; + assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); + rc = x; + break; + } + + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X) + ** + ** This action provides a run-time test to see how the ALWAYS and + ** NEVER macros were defined at compile-time. + ** + ** The return value is ALWAYS(X) if X is true, or 0 if X is false. + ** + ** The recommended test is X==2. If the return value is 2, that means + ** ALWAYS() and NEVER() are both no-op pass-through macros, which is the + ** default setting. If the return value is 1, then ALWAYS() is either + ** hard-coded to true or else it asserts if its argument is false. + ** The first behavior (hard-coded to true) is the case if + ** SQLITE_TESTCTRL_ASSERT shows that assert() is disabled and the second + ** behavior (assert if the argument to ALWAYS() is false) is the case if + ** SQLITE_TESTCTRL_ASSERT shows that assert() is enabled. + ** + ** The run-time test procedure might look something like this: + ** + ** if( sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, 2)==2 ){ + ** // ALWAYS() and NEVER() are no-op pass-through macros + ** }else if( sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, 1) ){ + ** // ALWAYS(x) asserts that x is true. NEVER(x) asserts x is false. + ** }else{ + ** // ALWAYS(x) is a constant 1. NEVER(x) is a constant 0. + ** } + */ + case SQLITE_TESTCTRL_ALWAYS: { + int x = va_arg(ap,int); + rc = x ? ALWAYS(x) : 0; + break; + } + + /* + ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER); + ** + ** The integer returned reveals the byte-order of the computer on which + ** SQLite is running: + ** + ** 1 big-endian, determined at run-time + ** 10 little-endian, determined at run-time + ** 432101 big-endian, determined at compile-time + ** 123410 little-endian, determined at compile-time + */ + case SQLITE_TESTCTRL_BYTEORDER: { + rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N) + ** + ** Enable or disable various optimizations for testing purposes. The + ** argument N is a bitmask of optimizations to be disabled. For normal + ** operation N should be 0. The idea is that a test program (like the + ** SQL Logic Test or SLT test module) can run the same SQL multiple times + ** with various optimizations disabled to verify that the same answer + ** is obtained in every case. + */ + case SQLITE_TESTCTRL_OPTIMIZATIONS: { + sqlite3 *db = va_arg(ap, sqlite3*); + db->dbOptFlags = va_arg(ap, u32); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt); + ** + ** If parameter onoff is 1, subsequent calls to localtime() fail. + ** If 2, then invoke xAlt() instead of localtime(). If 0, normal + ** processing. + ** + ** xAlt arguments are void pointers, but they really want to be: + ** + ** int xAlt(const time_t*, struct tm*); + ** + ** xAlt should write results in to struct tm object of its 2nd argument + ** and return zero on success, or return non-zero on failure. + */ + case SQLITE_TESTCTRL_LOCALTIME_FAULT: { + sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); + if( sqlite3GlobalConfig.bLocaltimeFault==2 ){ + typedef int(*sqlite3LocaltimeType)(const void*,void*); + sqlite3GlobalConfig.xAltLocaltime = va_arg(ap, sqlite3LocaltimeType); + }else{ + sqlite3GlobalConfig.xAltLocaltime = 0; + } + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*); + ** + ** Toggle the ability to use internal functions on or off for + ** the database connection given in the argument. + */ + case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: { + sqlite3 *db = va_arg(ap, sqlite3*); + db->mDbFlags ^= DBFLAG_InternalFunc; + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); + ** + ** Set or clear a flag that indicates that the database file is always well- + ** formed and never corrupt. This flag is clear by default, indicating that + ** database files might have arbitrary corruption. Setting the flag during + ** testing causes certain assert() statements in the code to be activated + ** that demonstrat invariants on well-formed database files. + */ + case SQLITE_TESTCTRL_NEVER_CORRUPT: { + sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int); + ** + ** Set or clear a flag that causes SQLite to verify that type, name, + ** and tbl_name fields of the sqlite_schema table. This is normally + ** on, but it is sometimes useful to turn it off for testing. + ** + ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the + ** verification of rootpage numbers when parsing the schema. This + ** is useful to make it easier to reach strange internal error states + ** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled + ** in production. + */ + case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: { + sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int); + break; + } + + /* Set the threshold at which OP_Once counters reset back to zero. + ** By default this is 0x7ffffffe (over 2 billion), but that value is + ** too big to test in a reasonable amount of time, so this control is + ** provided to set a small and easily reachable reset value. + */ + case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: { + sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr); + ** + ** Set the VDBE coverage callback function to xCallback with context + ** pointer ptr. + */ + case SQLITE_TESTCTRL_VDBE_COVERAGE: { +#ifdef SQLITE_VDBE_COVERAGE + typedef void (*branch_callback)(void*,unsigned int, + unsigned char,unsigned char); + sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback); + sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*); +#endif + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */ + case SQLITE_TESTCTRL_SORTER_MMAP: { + sqlite3 *db = va_arg(ap, sqlite3*); + db->nMaxSorterMmap = va_arg(ap, int); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); + ** + ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if + ** not. + */ + case SQLITE_TESTCTRL_ISINIT: { + if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); + ** + ** This test control is used to create imposter tables. "db" is a pointer + ** to the database connection. dbName is the database name (ex: "main" or + ** "temp") which will receive the imposter. "onOff" turns imposter mode on + ** or off. "tnum" is the root page of the b-tree to which the imposter + ** table should connect. + ** + ** Enable imposter mode only when the schema has already been parsed. Then + ** run a single CREATE TABLE statement to construct the imposter table in + ** the parsed schema. Then turn imposter mode back off again. + ** + ** If onOff==0 and tnum>0 then reset the schema for all databases, causing + ** the schema to be reparsed the next time it is needed. This has the + ** effect of erasing all imposter tables. + */ + case SQLITE_TESTCTRL_IMPOSTER: { + sqlite3 *db = va_arg(ap, sqlite3*); + int iDb; + sqlite3_mutex_enter(db->mutex); + iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); + if( iDb>=0 ){ + db->init.iDb = iDb; + db->init.busy = db->init.imposterTable = va_arg(ap,int); + db->init.newTnum = va_arg(ap,int); + if( db->init.busy==0 && db->init.newTnum>0 ){ + sqlite3ResetAllSchemasOfConnection(db); + } + } + sqlite3_mutex_leave(db->mutex); + break; + } + +#if defined(YYCOVERAGE) + /* sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out) + ** + ** This test control (only available when SQLite is compiled with + ** -DYYCOVERAGE) writes a report onto "out" that shows all + ** state/lookahead combinations in the parser state machine + ** which are never exercised. If any state is missed, make the + ** return code SQLITE_ERROR. + */ + case SQLITE_TESTCTRL_PARSER_COVERAGE: { + FILE *out = va_arg(ap, FILE*); + if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR; + break; + } +#endif /* defined(YYCOVERAGE) */ + + /* sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, sqlite3_context*); + ** + ** This test-control causes the most recent sqlite3_result_int64() value + ** to be interpreted as a MEM_IntReal instead of as an MEM_Int. Normally, + ** MEM_IntReal values only arise during an INSERT operation of integer + ** values into a REAL column, so they can be challenging to test. This + ** test-control enables us to write an intreal() SQL function that can + ** inject an intreal() value at arbitrary places in an SQL statement, + ** for testing purposes. + */ + case SQLITE_TESTCTRL_RESULT_INTREAL: { + sqlite3_context *pCtx = va_arg(ap, sqlite3_context*); + sqlite3ResultIntReal(pCtx); + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_SEEK_COUNT, + ** sqlite3 *db, // Database connection + ** u64 *pnSeek // Write seek count here + ** ); + ** + ** This test-control queries the seek-counter on the "main" database + ** file. The seek-counter is written into *pnSeek and is then reset. + ** The seek-count is only available if compiled with SQLITE_DEBUG. + */ + case SQLITE_TESTCTRL_SEEK_COUNT: { + sqlite3 *db = va_arg(ap, sqlite3*); + u64 *pn = va_arg(ap, sqlite3_uint64*); + *pn = sqlite3BtreeSeekCount(db->aDb->pBt); + (void)db; /* Silence harmless unused variable warning */ + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, op, ptr) + ** + ** "ptr" is a pointer to a u32. + ** + ** op==0 Store the current sqlite3SelectTrace in *ptr + ** op==1 Set sqlite3SelectTrace to the value *ptr + ** op==3 Store the current sqlite3WhereTrace in *ptr + ** op==3 Set sqlite3WhereTrace to the value *ptr + */ + case SQLITE_TESTCTRL_TRACEFLAGS: { + int opTrace = va_arg(ap, int); + u32 *ptr = va_arg(ap, u32*); + switch( opTrace ){ + case 0: *ptr = sqlite3SelectTrace; break; + case 1: sqlite3SelectTrace = *ptr; break; + case 2: *ptr = sqlite3WhereTrace; break; + case 3: sqlite3WhereTrace = *ptr; break; + } + break; + } + + /* sqlite3_test_control(SQLITE_TESTCTRL_LOGEST, + ** double fIn, // Input value + ** int *pLogEst, // sqlite3LogEstFromDouble(fIn) + ** u64 *pInt, // sqlite3LogEstToInt(*pLogEst) + ** int *pLogEst2 // sqlite3LogEst(*pInt) + ** ); + ** + ** Test access for the LogEst conversion routines. + */ + case SQLITE_TESTCTRL_LOGEST: { + double rIn = va_arg(ap, double); + LogEst rLogEst = sqlite3LogEstFromDouble(rIn); + u64 iInt = sqlite3LogEstToInt(rLogEst); + va_arg(ap, int*)[0] = rLogEst; + va_arg(ap, u64*)[0] = iInt; + va_arg(ap, int*)[0] = sqlite3LogEst(iInt); + break; + } + + +#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) + /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) + ** + ** If "id" is an integer between 1 and SQLITE_NTUNE then set the value + ** of the id-th tuning parameter to *piValue. If "id" is between -1 + ** and -SQLITE_NTUNE, then write the current value of the (-id)-th + ** tuning parameter into *piValue. + ** + ** Tuning parameters are for use during transient development builds, + ** to help find the best values for constants in the query planner. + ** Access tuning parameters using the Tuning(ID) macro. Set the + ** parameters in the CLI using ".testctrl tune ID VALUE". + ** + ** Transient use only. Tuning parameters should not be used in + ** checked-in code. + */ + case SQLITE_TESTCTRL_TUNE: { + int id = va_arg(ap, int); + int *piValue = va_arg(ap, int*); + if( id>0 && id<=SQLITE_NTUNE ){ + Tuning(id) = *piValue; + }else if( id<0 && id>=-SQLITE_NTUNE ){ + *piValue = Tuning(-id); + }else{ + rc = SQLITE_NOTFOUND; + } + break; + } +#endif + } + va_end(ap); +#endif /* SQLITE_UNTESTABLE */ + return rc; +} + +/* +** The Pager stores the Database filename, Journal filename, and WAL filename +** consecutively in memory, in that order. The database filename is prefixed +** by four zero bytes. Locate the start of the database filename by searching +** backwards for the first byte following four consecutive zero bytes. +** +** This only works if the filename passed in was obtained from the Pager. +*/ +static const char *databaseName(const char *zName){ + while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){ + zName--; + } + return zName; +} + +/* +** Append text z[] to the end of p[]. Return a pointer to the first +** character after then zero terminator on the new text in p[]. +*/ +static char *appendText(char *p, const char *z){ + size_t n = strlen(z); + memcpy(p, z, n+1); + return p+n+1; +} + +/* +** Allocate memory to hold names for a database, journal file, WAL file, +** and query parameters. The pointer returned is valid for use by +** sqlite3_filename_database() and sqlite3_uri_parameter() and related +** functions. +** +** Memory layout must be compatible with that generated by the pager +** and expected by sqlite3_uri_parameter() and databaseName(). +*/ +SQLITE_API char *sqlite3_create_filename( + const char *zDatabase, + const char *zJournal, + const char *zWal, + int nParam, + const char **azParam +){ + sqlite3_int64 nByte; + int i; + char *pResult, *p; + nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10; + for(i=0; i0 ){ + zFilename += sqlite3Strlen30(zFilename) + 1; + zFilename += sqlite3Strlen30(zFilename) + 1; + } + return zFilename[0] ? zFilename : 0; +} + +/* +** Return a boolean value for a query parameter. +*/ +SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){ + const char *z = sqlite3_uri_parameter(zFilename, zParam); + bDflt = bDflt!=0; + return z ? sqlite3GetBoolean(z, bDflt) : bDflt; +} + +/* +** Return a 64-bit integer value for a query parameter. +*/ +SQLITE_API sqlite3_int64 sqlite3_uri_int64( + const char *zFilename, /* Filename as passed to xOpen */ + const char *zParam, /* URI parameter sought */ + sqlite3_int64 bDflt /* return if parameter is missing */ +){ + const char *z = sqlite3_uri_parameter(zFilename, zParam); + sqlite3_int64 v; + if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ + bDflt = v; + } + return bDflt; +} + +/* +** Translate a filename that was handed to a VFS routine into the corresponding +** database, journal, or WAL file. +** +** It is an error to pass this routine a filename string that was not +** passed into the VFS from the SQLite core. Doing so is similar to +** passing free() a pointer that was not obtained from malloc() - it is +** an error that we cannot easily detect but that will likely cause memory +** corruption. +*/ +SQLITE_API const char *sqlite3_filename_database(const char *zFilename){ + if( zFilename==0 ) return 0; + return databaseName(zFilename); +} +SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){ + if( zFilename==0 ) return 0; + zFilename = databaseName(zFilename); + zFilename += sqlite3Strlen30(zFilename) + 1; + while( ALWAYS(zFilename) && zFilename[0] ){ + zFilename += sqlite3Strlen30(zFilename) + 1; + zFilename += sqlite3Strlen30(zFilename) + 1; + } + return zFilename + 1; +} +SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){ +#ifdef SQLITE_OMIT_WAL + return 0; +#else + zFilename = sqlite3_filename_journal(zFilename); + if( zFilename ) zFilename += sqlite3Strlen30(zFilename) + 1; + return zFilename; +#endif +} + +/* +** Return the Btree pointer identified by zDbName. Return NULL if not found. +*/ +SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ + int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0; + return iDb<0 ? 0 : db->aDb[iDb].pBt; +} + +/* +** Return the filename of the database associated with a database +** connection. +*/ +SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ + Btree *pBt; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + pBt = sqlite3DbNameToBtree(db, zDbName); + return pBt ? sqlite3BtreeGetFilename(pBt) : 0; +} + +/* +** Return 1 if database is read-only or 0 if read/write. Return -1 if +** no such database exists. +*/ +SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ + Btree *pBt; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + pBt = sqlite3DbNameToBtree(db, zDbName); + return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; +} + +#ifdef SQLITE_ENABLE_SNAPSHOT +/* +** Obtain a snapshot handle for the snapshot of database zDb currently +** being read by handle db. +*/ +SQLITE_API int sqlite3_snapshot_get( + sqlite3 *db, + const char *zDb, + sqlite3_snapshot **ppSnapshot +){ + int rc = SQLITE_ERROR; +#ifndef SQLITE_OMIT_WAL + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + + if( db->autoCommit==0 ){ + int iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){ + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); + } + } + } + } + + sqlite3_mutex_leave(db->mutex); +#endif /* SQLITE_OMIT_WAL */ + return rc; +} + +/* +** Open a read-transaction on the snapshot idendified by pSnapshot. +*/ +SQLITE_API int sqlite3_snapshot_open( + sqlite3 *db, + const char *zDb, + sqlite3_snapshot *pSnapshot +){ + int rc = SQLITE_ERROR; +#ifndef SQLITE_OMIT_WAL + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( db->autoCommit==0 ){ + int iDb; + iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ){ + Pager *pPager = sqlite3BtreePager(pBt); + int bUnlock = 0; + if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_NONE ){ + if( db->nVdbeActive==0 ){ + rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); + if( rc==SQLITE_OK ){ + bUnlock = 1; + rc = sqlite3BtreeCommit(pBt); + } + } + }else{ + rc = SQLITE_OK; + } + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot); + } + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); + sqlite3PagerSnapshotOpen(pPager, 0); + } + if( bUnlock ){ + sqlite3PagerSnapshotUnlock(pPager); + } + } + } + } + + sqlite3_mutex_leave(db->mutex); +#endif /* SQLITE_OMIT_WAL */ + return rc; +} + +/* +** Recover as many snapshots as possible from the wal file associated with +** schema zDb of database db. +*/ +SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ + int rc = SQLITE_ERROR; + int iDb; +#ifndef SQLITE_OMIT_WAL + +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + return SQLITE_MISUSE_BKPT; + } +#endif + + sqlite3_mutex_enter(db->mutex); + iDb = sqlite3FindDbName(db, zDb); + if( iDb==0 || iDb>1 ){ + Btree *pBt = db->aDb[iDb].pBt; + if( SQLITE_TXN_NONE==sqlite3BtreeTxnState(pBt) ){ + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); + sqlite3BtreeCommit(pBt); + } + } + } + sqlite3_mutex_leave(db->mutex); +#endif /* SQLITE_OMIT_WAL */ + return rc; +} + +/* +** Free a snapshot handle obtained from sqlite3_snapshot_get(). +*/ +SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ + sqlite3_free(pSnapshot); +} +#endif /* SQLITE_ENABLE_SNAPSHOT */ + +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +/* +** Given the name of a compile-time option, return true if that option +** was used and false if not. +** +** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix +** is not required for a match. +*/ +SQLITE_API int sqlite3_compileoption_used(const char *zOptName){ + int i, n; + int nOpt; + const char **azCompileOpt; + +#if SQLITE_ENABLE_API_ARMOR + if( zOptName==0 ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + + azCompileOpt = sqlite3CompileOptions(&nOpt); + + if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7; + n = sqlite3Strlen30(zOptName); + + /* Since nOpt is normally in single digits, a linear search is + ** adequate. No need for a binary search. */ + for(i=0; i=0 && NpNextBlocked){ + int seen = 0; + sqlite3 *p2; + + /* Verify property (1) */ + assert( p->pUnlockConnection || p->pBlockingConnection ); + + /* Verify property (2) */ + for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){ + if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1; + assert( p2->xUnlockNotify==p->xUnlockNotify || !seen ); + assert( db==0 || p->pUnlockConnection!=db ); + assert( db==0 || p->pBlockingConnection!=db ); + } + } +} +#else +# define checkListProperties(x) +#endif + +/* +** Remove connection db from the blocked connections list. If connection +** db is not currently a part of the list, this function is a no-op. +*/ +static void removeFromBlockedList(sqlite3 *db){ + sqlite3 **pp; + assertMutexHeld(); + for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){ + if( *pp==db ){ + *pp = (*pp)->pNextBlocked; + break; + } + } +} + +/* +** Add connection db to the blocked connections list. It is assumed +** that it is not already a part of the list. +*/ +static void addToBlockedList(sqlite3 *db){ + sqlite3 **pp; + assertMutexHeld(); + for( + pp=&sqlite3BlockedList; + *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify; + pp=&(*pp)->pNextBlocked + ); + db->pNextBlocked = *pp; + *pp = db; +} + +/* +** Obtain the STATIC_MAIN mutex. +*/ +static void enterMutex(void){ + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); + checkListProperties(0); +} + +/* +** Release the STATIC_MAIN mutex. +*/ +static void leaveMutex(void){ + assertMutexHeld(); + checkListProperties(0); + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)); +} + +/* +** Register an unlock-notify callback. +** +** This is called after connection "db" has attempted some operation +** but has received an SQLITE_LOCKED error because another connection +** (call it pOther) in the same process was busy using the same shared +** cache. pOther is found by looking at db->pBlockingConnection. +** +** If there is no blocking connection, the callback is invoked immediately, +** before this routine returns. +** +** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate +** a deadlock. +** +** Otherwise, make arrangements to invoke xNotify when pOther drops +** its locks. +** +** Each call to this routine overrides any prior callbacks registered +** on the same "db". If xNotify==0 then any prior callbacks are immediately +** cancelled. +*/ +SQLITE_API int sqlite3_unlock_notify( + sqlite3 *db, + void (*xNotify)(void **, int), + void *pArg +){ + int rc = SQLITE_OK; + + sqlite3_mutex_enter(db->mutex); + enterMutex(); + + if( xNotify==0 ){ + removeFromBlockedList(db); + db->pBlockingConnection = 0; + db->pUnlockConnection = 0; + db->xUnlockNotify = 0; + db->pUnlockArg = 0; + }else if( 0==db->pBlockingConnection ){ + /* The blocking transaction has been concluded. Or there never was a + ** blocking transaction. In either case, invoke the notify callback + ** immediately. + */ + xNotify(&pArg, 1); + }else{ + sqlite3 *p; + + for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){} + if( p ){ + rc = SQLITE_LOCKED; /* Deadlock detected. */ + }else{ + db->pUnlockConnection = db->pBlockingConnection; + db->xUnlockNotify = xNotify; + db->pUnlockArg = pArg; + removeFromBlockedList(db); + addToBlockedList(db); + } + } + + leaveMutex(); + assert( !db->mallocFailed ); + sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0)); + sqlite3_mutex_leave(db->mutex); + return rc; +} + +/* +** This function is called while stepping or preparing a statement +** associated with connection db. The operation will return SQLITE_LOCKED +** to the user because it requires a lock that will not be available +** until connection pBlocker concludes its current transaction. +*/ +SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){ + enterMutex(); + if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){ + addToBlockedList(db); + } + db->pBlockingConnection = pBlocker; + leaveMutex(); +} + +/* +** This function is called when +** the transaction opened by database db has just finished. Locks held +** by database connection db have been released. +** +** This function loops through each entry in the blocked connections +** list and does the following: +** +** 1) If the sqlite3.pBlockingConnection member of a list entry is +** set to db, then set pBlockingConnection=0. +** +** 2) If the sqlite3.pUnlockConnection member of a list entry is +** set to db, then invoke the configured unlock-notify callback and +** set pUnlockConnection=0. +** +** 3) If the two steps above mean that pBlockingConnection==0 and +** pUnlockConnection==0, remove the entry from the blocked connections +** list. +*/ +SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){ + void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */ + int nArg = 0; /* Number of entries in aArg[] */ + sqlite3 **pp; /* Iterator variable */ + void **aArg; /* Arguments to the unlock callback */ + void **aDyn = 0; /* Dynamically allocated space for aArg[] */ + void *aStatic[16]; /* Starter space for aArg[]. No malloc required */ + + aArg = aStatic; + enterMutex(); /* Enter STATIC_MAIN mutex */ + + /* This loop runs once for each entry in the blocked-connections list. */ + for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){ + sqlite3 *p = *pp; + + /* Step 1. */ + if( p->pBlockingConnection==db ){ + p->pBlockingConnection = 0; + } + + /* Step 2. */ + if( p->pUnlockConnection==db ){ + assert( p->xUnlockNotify ); + if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){ + xUnlockNotify(aArg, nArg); + nArg = 0; + } + + sqlite3BeginBenignMalloc(); + assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) ); + assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn ); + if( (!aDyn && nArg==(int)ArraySize(aStatic)) + || (aDyn && nArg==(int)(sqlite3MallocSize(aDyn)/sizeof(void*))) + ){ + /* The aArg[] array needs to grow. */ + void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2); + if( pNew ){ + memcpy(pNew, aArg, nArg*sizeof(void *)); + sqlite3_free(aDyn); + aDyn = aArg = pNew; + }else{ + /* This occurs when the array of context pointers that need to + ** be passed to the unlock-notify callback is larger than the + ** aStatic[] array allocated on the stack and the attempt to + ** allocate a larger array from the heap has failed. + ** + ** This is a difficult situation to handle. Returning an error + ** code to the caller is insufficient, as even if an error code + ** is returned the transaction on connection db will still be + ** closed and the unlock-notify callbacks on blocked connections + ** will go unissued. This might cause the application to wait + ** indefinitely for an unlock-notify callback that will never + ** arrive. + ** + ** Instead, invoke the unlock-notify callback with the context + ** array already accumulated. We can then clear the array and + ** begin accumulating any further context pointers without + ** requiring any dynamic allocation. This is sub-optimal because + ** it means that instead of one callback with a large array of + ** context pointers the application will receive two or more + ** callbacks with smaller arrays of context pointers, which will + ** reduce the applications ability to prioritize multiple + ** connections. But it is the best that can be done under the + ** circumstances. + */ + xUnlockNotify(aArg, nArg); + nArg = 0; + } + } + sqlite3EndBenignMalloc(); + + aArg[nArg++] = p->pUnlockArg; + xUnlockNotify = p->xUnlockNotify; + p->pUnlockConnection = 0; + p->xUnlockNotify = 0; + p->pUnlockArg = 0; + } + + /* Step 3. */ + if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){ + /* Remove connection p from the blocked connections list. */ + *pp = p->pNextBlocked; + p->pNextBlocked = 0; + }else{ + pp = &p->pNextBlocked; + } + } + + if( nArg!=0 ){ + xUnlockNotify(aArg, nArg); + } + sqlite3_free(aDyn); + leaveMutex(); /* Leave STATIC_MAIN mutex */ +} + +/* +** This is called when the database connection passed as an argument is +** being closed. The connection is removed from the blocked list. +*/ +SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ + sqlite3ConnectionUnlocked(db); + enterMutex(); + removeFromBlockedList(db); + checkListProperties(db); + leaveMutex(); +} +#endif + +/************** End of notify.c **********************************************/ +/************** Begin file fts3.c ********************************************/ +/* +** 2006 Oct 10 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This is an SQLite module implementing full-text search. +*/ + +/* +** The code in this file is only compiled if: +** +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +*/ + +/* The full-text index is stored in a series of b+tree (-like) +** structures called segments which map terms to doclists. The +** structures are like b+trees in layout, but are constructed from the +** bottom up in optimal fashion and are not updatable. Since trees +** are built from the bottom up, things will be described from the +** bottom up. +** +** +**** Varints **** +** The basic unit of encoding is a variable-length integer called a +** varint. We encode variable-length integers in little-endian order +** using seven bits * per byte as follows: +** +** KEY: +** A = 0xxxxxxx 7 bits of data and one flag bit +** B = 1xxxxxxx 7 bits of data and one flag bit +** +** 7 bits - A +** 14 bits - BA +** 21 bits - BBA +** and so on. +** +** This is similar in concept to how sqlite encodes "varints" but +** the encoding is not the same. SQLite varints are big-endian +** are are limited to 9 bytes in length whereas FTS3 varints are +** little-endian and can be up to 10 bytes in length (in theory). +** +** Example encodings: +** +** 1: 0x01 +** 127: 0x7f +** 128: 0x81 0x00 +** +** +**** Document lists **** +** A doclist (document list) holds a docid-sorted list of hits for a +** given term. Doclists hold docids and associated token positions. +** A docid is the unique integer identifier for a single document. +** A position is the index of a word within the document. The first +** word of the document has a position of 0. +** +** FTS3 used to optionally store character offsets using a compile-time +** option. But that functionality is no longer supported. +** +** A doclist is stored like this: +** +** array { +** varint docid; (delta from previous doclist) +** array { (position list for column 0) +** varint position; (2 more than the delta from previous position) +** } +** array { +** varint POS_COLUMN; (marks start of position list for new column) +** varint column; (index of new column) +** array { +** varint position; (2 more than the delta from previous position) +** } +** } +** varint POS_END; (marks end of positions for this document. +** } +** +** Here, array { X } means zero or more occurrences of X, adjacent in +** memory. A "position" is an index of a token in the token stream +** generated by the tokenizer. Note that POS_END and POS_COLUMN occur +** in the same logical place as the position element, and act as sentinals +** ending a position list array. POS_END is 0. POS_COLUMN is 1. +** The positions numbers are not stored literally but rather as two more +** than the difference from the prior position, or the just the position plus +** 2 for the first position. Example: +** +** label: A B C D E F G H I J K +** value: 123 5 9 1 1 14 35 0 234 72 0 +** +** The 123 value is the first docid. For column zero in this document +** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1 +** at D signals the start of a new column; the 1 at E indicates that the +** new column is column number 1. There are two positions at 12 and 45 +** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The +** 234 at I is the delta to next docid (357). It has one position 70 +** (72-2) and then terminates with the 0 at K. +** +** A "position-list" is the list of positions for multiple columns for +** a single docid. A "column-list" is the set of positions for a single +** column. Hence, a position-list consists of one or more column-lists, +** a document record consists of a docid followed by a position-list and +** a doclist consists of one or more document records. +** +** A bare doclist omits the position information, becoming an +** array of varint-encoded docids. +** +**** Segment leaf nodes **** +** Segment leaf nodes store terms and doclists, ordered by term. Leaf +** nodes are written using LeafWriter, and read using LeafReader (to +** iterate through a single leaf node's data) and LeavesReader (to +** iterate through a segment's entire leaf layer). Leaf nodes have +** the format: +** +** varint iHeight; (height from leaf level, always 0) +** varint nTerm; (length of first term) +** char pTerm[nTerm]; (content of first term) +** varint nDoclist; (length of term's associated doclist) +** char pDoclist[nDoclist]; (content of doclist) +** array { +** (further terms are delta-encoded) +** varint nPrefix; (length of prefix shared with previous term) +** varint nSuffix; (length of unshared suffix) +** char pTermSuffix[nSuffix];(unshared suffix of next term) +** varint nDoclist; (length of term's associated doclist) +** char pDoclist[nDoclist]; (content of doclist) +** } +** +** Here, array { X } means zero or more occurrences of X, adjacent in +** memory. +** +** Leaf nodes are broken into blocks which are stored contiguously in +** the %_segments table in sorted order. This means that when the end +** of a node is reached, the next term is in the node with the next +** greater node id. +** +** New data is spilled to a new leaf node when the current node +** exceeds LEAF_MAX bytes (default 2048). New data which itself is +** larger than STANDALONE_MIN (default 1024) is placed in a standalone +** node (a leaf node with a single term and doclist). The goal of +** these settings is to pack together groups of small doclists while +** making it efficient to directly access large doclists. The +** assumption is that large doclists represent terms which are more +** likely to be query targets. +** +** TODO(shess) It may be useful for blocking decisions to be more +** dynamic. For instance, it may make more sense to have a 2.5k leaf +** node rather than splitting into 2k and .5k nodes. My intuition is +** that this might extend through 2x or 4x the pagesize. +** +** +**** Segment interior nodes **** +** Segment interior nodes store blockids for subtree nodes and terms +** to describe what data is stored by the each subtree. Interior +** nodes are written using InteriorWriter, and read using +** InteriorReader. InteriorWriters are created as needed when +** SegmentWriter creates new leaf nodes, or when an interior node +** itself grows too big and must be split. The format of interior +** nodes: +** +** varint iHeight; (height from leaf level, always >0) +** varint iBlockid; (block id of node's leftmost subtree) +** optional { +** varint nTerm; (length of first term) +** char pTerm[nTerm]; (content of first term) +** array { +** (further terms are delta-encoded) +** varint nPrefix; (length of shared prefix with previous term) +** varint nSuffix; (length of unshared suffix) +** char pTermSuffix[nSuffix]; (unshared suffix of next term) +** } +** } +** +** Here, optional { X } means an optional element, while array { X } +** means zero or more occurrences of X, adjacent in memory. +** +** An interior node encodes n terms separating n+1 subtrees. The +** subtree blocks are contiguous, so only the first subtree's blockid +** is encoded. The subtree at iBlockid will contain all terms less +** than the first term encoded (or all terms if no term is encoded). +** Otherwise, for terms greater than or equal to pTerm[i] but less +** than pTerm[i+1], the subtree for that term will be rooted at +** iBlockid+i. Interior nodes only store enough term data to +** distinguish adjacent children (if the rightmost term of the left +** child is "something", and the leftmost term of the right child is +** "wicked", only "w" is stored). +** +** New data is spilled to a new interior node at the same height when +** the current node exceeds INTERIOR_MAX bytes (default 2048). +** INTERIOR_MIN_TERMS (default 7) keeps large terms from monopolizing +** interior nodes and making the tree too skinny. The interior nodes +** at a given height are naturally tracked by interior nodes at +** height+1, and so on. +** +** +**** Segment directory **** +** The segment directory in table %_segdir stores meta-information for +** merging and deleting segments, and also the root node of the +** segment's tree. +** +** The root node is the top node of the segment's tree after encoding +** the entire segment, restricted to ROOT_MAX bytes (default 1024). +** This could be either a leaf node or an interior node. If the top +** node requires more than ROOT_MAX bytes, it is flushed to %_segments +** and a new root interior node is generated (which should always fit +** within ROOT_MAX because it only needs space for 2 varints, the +** height and the blockid of the previous root). +** +** The meta-information in the segment directory is: +** level - segment level (see below) +** idx - index within level +** - (level,idx uniquely identify a segment) +** start_block - first leaf node +** leaves_end_block - last leaf node +** end_block - last block (including interior nodes) +** root - contents of root node +** +** If the root node is a leaf node, then start_block, +** leaves_end_block, and end_block are all 0. +** +** +**** Segment merging **** +** To amortize update costs, segments are grouped into levels and +** merged in batches. Each increase in level represents exponentially +** more documents. +** +** New documents (actually, document updates) are tokenized and +** written individually (using LeafWriter) to a level 0 segment, with +** incrementing idx. When idx reaches MERGE_COUNT (default 16), all +** level 0 segments are merged into a single level 1 segment. Level 1 +** is populated like level 0, and eventually MERGE_COUNT level 1 +** segments are merged to a single level 2 segment (representing +** MERGE_COUNT^2 updates), and so on. +** +** A segment merge traverses all segments at a given level in +** parallel, performing a straightforward sorted merge. Since segment +** leaf nodes are written in to the %_segments table in order, this +** merge traverses the underlying sqlite disk structures efficiently. +** After the merge, all segment blocks from the merged level are +** deleted. +** +** MERGE_COUNT controls how often we merge segments. 16 seems to be +** somewhat of a sweet spot for insertion performance. 32 and 64 show +** very similar performance numbers to 16 on insertion, though they're +** a tiny bit slower (perhaps due to more overhead in merge-time +** sorting). 8 is about 20% slower than 16, 4 about 50% slower than +** 16, 2 about 66% slower than 16. +** +** At query time, high MERGE_COUNT increases the number of segments +** which need to be scanned and merged. For instance, with 100k docs +** inserted: +** +** MERGE_COUNT segments +** 16 25 +** 8 12 +** 4 10 +** 2 6 +** +** This appears to have only a moderate impact on queries for very +** frequent terms (which are somewhat dominated by segment merge +** costs), and infrequent and non-existent terms still seem to be fast +** even with many segments. +** +** TODO(shess) That said, it would be nice to have a better query-side +** argument for MERGE_COUNT of 16. Also, it is possible/likely that +** optimizations to things like doclist merging will swing the sweet +** spot around. +** +** +** +**** Handling of deletions and updates **** +** Since we're using a segmented structure, with no docid-oriented +** index into the term index, we clearly cannot simply update the term +** index when a document is deleted or updated. For deletions, we +** write an empty doclist (varint(docid) varint(POS_END)), for updates +** we simply write the new doclist. Segment merges overwrite older +** data for a particular docid with newer data, so deletes or updates +** will eventually overtake the earlier data and knock it out. The +** query logic likewise merges doclists so that newer data knocks out +** older data. +*/ + +/************** Include fts3Int.h in the middle of fts3.c ********************/ +/************** Begin file fts3Int.h *****************************************/ +/* +** 2009 Nov 12 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +*/ +#ifndef _FTSINT_H +#define _FTSINT_H + +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif + +/* FTS3/FTS4 require virtual tables */ +#ifdef SQLITE_OMIT_VIRTUALTABLE +# undef SQLITE_ENABLE_FTS3 +# undef SQLITE_ENABLE_FTS4 +#endif + +/* +** FTS4 is really an extension for FTS3. It is enabled using the +** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all +** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3. +*/ +#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) +# define SQLITE_ENABLE_FTS3 +#endif + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* If not building as part of the core, include sqlite3ext.h. */ +#ifndef SQLITE_CORE +/* # include "sqlite3ext.h" */ +SQLITE_EXTENSION_INIT3 +#endif + +/* #include "sqlite3.h" */ +/************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/ +/************** Begin file fts3_tokenizer.h **********************************/ +/* +** 2006 July 10 +** +** The author disclaims copyright to this source code. +** +************************************************************************* +** Defines the interface to tokenizers used by fulltext-search. There +** are three basic components: +** +** sqlite3_tokenizer_module is a singleton defining the tokenizer +** interface functions. This is essentially the class structure for +** tokenizers. +** +** sqlite3_tokenizer is used to define a particular tokenizer, perhaps +** including customization information defined at creation time. +** +** sqlite3_tokenizer_cursor is generated by a tokenizer to generate +** tokens from a particular input. +*/ +#ifndef _FTS3_TOKENIZER_H_ +#define _FTS3_TOKENIZER_H_ + +/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. +** If tokenizers are to be allowed to call sqlite3_*() functions, then +** we will need a way to register the API consistently. +*/ +/* #include "sqlite3.h" */ + +/* +** Structures used by the tokenizer interface. When a new tokenizer +** implementation is registered, the caller provides a pointer to +** an sqlite3_tokenizer_module containing pointers to the callback +** functions that make up an implementation. +** +** When an fts3 table is created, it passes any arguments passed to +** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the +** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer +** implementation. The xCreate() function in turn returns an +** sqlite3_tokenizer structure representing the specific tokenizer to +** be used for the fts3 table (customized by the tokenizer clause arguments). +** +** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() +** method is called. It returns an sqlite3_tokenizer_cursor object +** that may be used to tokenize a specific input buffer based on +** the tokenization rules supplied by a specific sqlite3_tokenizer +** object. +*/ +typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; +typedef struct sqlite3_tokenizer sqlite3_tokenizer; +typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; + +struct sqlite3_tokenizer_module { + + /* + ** Structure version. Should always be set to 0 or 1. + */ + int iVersion; + + /* + ** Create a new tokenizer. The values in the argv[] array are the + ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL + ** TABLE statement that created the fts3 table. For example, if + ** the following SQL is executed: + ** + ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) + ** + ** then argc is set to 2, and the argv[] array contains pointers + ** to the strings "arg1" and "arg2". + ** + ** This method should return either SQLITE_OK (0), or an SQLite error + ** code. If SQLITE_OK is returned, then *ppTokenizer should be set + ** to point at the newly created tokenizer structure. The generic + ** sqlite3_tokenizer.pModule variable should not be initialized by + ** this callback. The caller will do so. + */ + int (*xCreate)( + int argc, /* Size of argv array */ + const char *const*argv, /* Tokenizer argument strings */ + sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ + ); + + /* + ** Destroy an existing tokenizer. The fts3 module calls this method + ** exactly once for each successful call to xCreate(). + */ + int (*xDestroy)(sqlite3_tokenizer *pTokenizer); + + /* + ** Create a tokenizer cursor to tokenize an input buffer. The caller + ** is responsible for ensuring that the input buffer remains valid + ** until the cursor is closed (using the xClose() method). + */ + int (*xOpen)( + sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ + const char *pInput, int nBytes, /* Input buffer */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ + ); + + /* + ** Destroy an existing tokenizer cursor. The fts3 module calls this + ** method exactly once for each successful call to xOpen(). + */ + int (*xClose)(sqlite3_tokenizer_cursor *pCursor); + + /* + ** Retrieve the next token from the tokenizer cursor pCursor. This + ** method should either return SQLITE_OK and set the values of the + ** "OUT" variables identified below, or SQLITE_DONE to indicate that + ** the end of the buffer has been reached, or an SQLite error code. + ** + ** *ppToken should be set to point at a buffer containing the + ** normalized version of the token (i.e. after any case-folding and/or + ** stemming has been performed). *pnBytes should be set to the length + ** of this buffer in bytes. The input text that generated the token is + ** identified by the byte offsets returned in *piStartOffset and + ** *piEndOffset. *piStartOffset should be set to the index of the first + ** byte of the token in the input buffer. *piEndOffset should be set + ** to the index of the first byte just past the end of the token in + ** the input buffer. + ** + ** The buffer *ppToken is set to point at is managed by the tokenizer + ** implementation. It is only required to be valid until the next call + ** to xNext() or xClose(). + */ + /* TODO(shess) current implementation requires pInput to be + ** nul-terminated. This should either be fixed, or pInput/nBytes + ** should be converted to zInput. + */ + int (*xNext)( + sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ + const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ + int *piStartOffset, /* OUT: Byte offset of token in input buffer */ + int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ + int *piPosition /* OUT: Number of tokens returned before this one */ + ); + + /*********************************************************************** + ** Methods below this point are only available if iVersion>=1. + */ + + /* + ** Configure the language id of a tokenizer cursor. + */ + int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); +}; + +struct sqlite3_tokenizer { + const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ + /* Tokenizer implementations will typically add additional fields */ +}; + +struct sqlite3_tokenizer_cursor { + sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ + /* Tokenizer implementations will typically add additional fields */ +}; + +int fts3_global_term_cnt(int iTerm, int iCol); +int fts3_term_cnt(int iTerm, int iCol); + + +#endif /* _FTS3_TOKENIZER_H_ */ + +/************** End of fts3_tokenizer.h **************************************/ +/************** Continuing where we left off in fts3Int.h ********************/ +/************** Include fts3_hash.h in the middle of fts3Int.h ***************/ +/************** Begin file fts3_hash.h ***************************************/ +/* +** 2001 September 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This is the header file for the generic hash-table implementation +** used in SQLite. We've modified it slightly to serve as a standalone +** hash table implementation for the full-text indexing module. +** +*/ +#ifndef _FTS3_HASH_H_ +#define _FTS3_HASH_H_ + +/* Forward declarations of structures. */ +typedef struct Fts3Hash Fts3Hash; +typedef struct Fts3HashElem Fts3HashElem; + +/* A complete hash table is an instance of the following structure. +** The internals of this structure are intended to be opaque -- client +** code should not attempt to access or modify the fields of this structure +** directly. Change this structure only by using the routines below. +** However, many of the "procedures" and "functions" for modifying and +** accessing this structure are really macros, so we can't really make +** this structure opaque. +*/ +struct Fts3Hash { + char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ + char copyKey; /* True if copy of key made on insert */ + int count; /* Number of entries in this table */ + Fts3HashElem *first; /* The first element of the array */ + int htsize; /* Number of buckets in the hash table */ + struct _fts3ht { /* the hash table */ + int count; /* Number of entries with this hash */ + Fts3HashElem *chain; /* Pointer to first entry with this hash */ + } *ht; +}; + +/* Each element in the hash table is an instance of the following +** structure. All elements are stored on a single doubly-linked list. +** +** Again, this structure is intended to be opaque, but it can't really +** be opaque because it is used by macros. +*/ +struct Fts3HashElem { + Fts3HashElem *next, *prev; /* Next and previous elements in the table */ + void *data; /* Data associated with this element */ + void *pKey; int nKey; /* Key associated with this element */ +}; + +/* +** There are 2 different modes of operation for a hash table: +** +** FTS3_HASH_STRING pKey points to a string that is nKey bytes long +** (including the null-terminator, if any). Case +** is respected in comparisons. +** +** FTS3_HASH_BINARY pKey points to binary data nKey bytes long. +** memcmp() is used to compare keys. +** +** A copy of the key is made if the copyKey parameter to fts3HashInit is 1. +*/ +#define FTS3_HASH_STRING 1 +#define FTS3_HASH_BINARY 2 + +/* +** Access routines. To delete, insert a NULL pointer. +*/ +SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey); +SQLITE_PRIVATE void *sqlite3Fts3HashInsert(Fts3Hash*, const void *pKey, int nKey, void *pData); +SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash*, const void *pKey, int nKey); +SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash*); +SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const void *, int); + +/* +** Shorthand for the functions above +*/ +#define fts3HashInit sqlite3Fts3HashInit +#define fts3HashInsert sqlite3Fts3HashInsert +#define fts3HashFind sqlite3Fts3HashFind +#define fts3HashClear sqlite3Fts3HashClear +#define fts3HashFindElem sqlite3Fts3HashFindElem + +/* +** Macros for looping over all elements of a hash table. The idiom is +** like this: +** +** Fts3Hash h; +** Fts3HashElem *p; +** ... +** for(p=fts3HashFirst(&h); p; p=fts3HashNext(p)){ +** SomeStructure *pData = fts3HashData(p); +** // do something with pData +** } +*/ +#define fts3HashFirst(H) ((H)->first) +#define fts3HashNext(E) ((E)->next) +#define fts3HashData(E) ((E)->data) +#define fts3HashKey(E) ((E)->pKey) +#define fts3HashKeysize(E) ((E)->nKey) + +/* +** Number of entries in a hash table +*/ +#define fts3HashCount(H) ((H)->count) + +#endif /* _FTS3_HASH_H_ */ + +/************** End of fts3_hash.h *******************************************/ +/************** Continuing where we left off in fts3Int.h ********************/ + +/* +** This constant determines the maximum depth of an FTS expression tree +** that the library will create and use. FTS uses recursion to perform +** various operations on the query tree, so the disadvantage of a large +** limit is that it may allow very large queries to use large amounts +** of stack space (perhaps causing a stack overflow). +*/ +#ifndef SQLITE_FTS3_MAX_EXPR_DEPTH +# define SQLITE_FTS3_MAX_EXPR_DEPTH 12 +#endif + + +/* +** This constant controls how often segments are merged. Once there are +** FTS3_MERGE_COUNT segments of level N, they are merged into a single +** segment of level N+1. +*/ +#define FTS3_MERGE_COUNT 16 + +/* +** This is the maximum amount of data (in bytes) to store in the +** Fts3Table.pendingTerms hash table. Normally, the hash table is +** populated as documents are inserted/updated/deleted in a transaction +** and used to create a new segment when the transaction is committed. +** However if this limit is reached midway through a transaction, a new +** segment is created and the hash table cleared immediately. +*/ +#define FTS3_MAX_PENDING_DATA (1*1024*1024) + +/* +** Macro to return the number of elements in an array. SQLite has a +** similar macro called ArraySize(). Use a different name to avoid +** a collision when building an amalgamation with built-in FTS3. +*/ +#define SizeofArray(X) ((int)(sizeof(X)/sizeof(X[0]))) + + +#ifndef MIN +# define MIN(x,y) ((x)<(y)?(x):(y)) +#endif +#ifndef MAX +# define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +/* +** Maximum length of a varint encoded integer. The varint format is different +** from that used by SQLite, so the maximum length is 10, not 9. +*/ +#define FTS3_VARINT_MAX 10 + +#define FTS3_BUFFER_PADDING 8 + +/* +** FTS4 virtual tables may maintain multiple indexes - one index of all terms +** in the document set and zero or more prefix indexes. All indexes are stored +** as one or more b+-trees in the %_segments and %_segdir tables. +** +** It is possible to determine which index a b+-tree belongs to based on the +** value stored in the "%_segdir.level" column. Given this value L, the index +** that the b+-tree belongs to is (L<<10). In other words, all b+-trees with +** level values between 0 and 1023 (inclusive) belong to index 0, all levels +** between 1024 and 2047 to index 1, and so on. +** +** It is considered impossible for an index to use more than 1024 levels. In +** theory though this may happen, but only after at least +** (FTS3_MERGE_COUNT^1024) separate flushes of the pending-terms tables. +*/ +#define FTS3_SEGDIR_MAXLEVEL 1024 +#define FTS3_SEGDIR_MAXLEVEL_STR "1024" + +/* +** The testcase() macro is only used by the amalgamation. If undefined, +** make it a no-op. +*/ +#ifndef testcase +# define testcase(X) +#endif + +/* +** Terminator values for position-lists and column-lists. +*/ +#define POS_COLUMN (1) /* Column-list terminator */ +#define POS_END (0) /* Position-list terminator */ + +/* +** The assert_fts3_nc() macro is similar to the assert() macro, except that it +** is used for assert() conditions that are true only if it can be +** guranteed that the database is not corrupt. +*/ +#ifdef SQLITE_DEBUG +SQLITE_API extern int sqlite3_fts3_may_be_corrupt; +# define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x)) +#else +# define assert_fts3_nc(x) assert(x) +#endif + +/* +** This section provides definitions to allow the +** FTS3 extension to be compiled outside of the +** amalgamation. +*/ +#ifndef SQLITE_AMALGAMATION +/* +** Macros indicating that conditional expressions are always true or +** false. +*/ +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +#elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +#else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +#endif + +/* +** Internal types used by SQLite. +*/ +typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */ +typedef short int i16; /* 2-byte (or larger) signed integer */ +typedef unsigned int u32; /* 4-byte unsigned integer */ +typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */ +typedef sqlite3_int64 i64; /* 8-byte signed integer */ + +/* +** Macro used to suppress compiler warnings for unused parameters. +*/ +#define UNUSED_PARAMETER(x) (void)(x) + +/* +** Activate assert() only if SQLITE_TEST is enabled. +*/ +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif + +/* +** The TESTONLY macro is used to enclose variable declarations or +** other bits of code that are needed to support the arguments +** within testcase() and assert() macros. +*/ +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) +# define TESTONLY(X) X +#else +# define TESTONLY(X) +#endif + +#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) +#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) + +#define deliberate_fall_through + +#endif /* SQLITE_AMALGAMATION */ + +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3Fts3Corrupt(void); +# define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() +#else +# define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB +#endif + +typedef struct Fts3Table Fts3Table; +typedef struct Fts3Cursor Fts3Cursor; +typedef struct Fts3Expr Fts3Expr; +typedef struct Fts3Phrase Fts3Phrase; +typedef struct Fts3PhraseToken Fts3PhraseToken; + +typedef struct Fts3Doclist Fts3Doclist; +typedef struct Fts3SegFilter Fts3SegFilter; +typedef struct Fts3DeferredToken Fts3DeferredToken; +typedef struct Fts3SegReader Fts3SegReader; +typedef struct Fts3MultiSegReader Fts3MultiSegReader; + +typedef struct MatchinfoBuffer MatchinfoBuffer; + +/* +** A connection to a fulltext index is an instance of the following +** structure. The xCreate and xConnect methods create an instance +** of this structure and xDestroy and xDisconnect free that instance. +** All other methods receive a pointer to the structure as one of their +** arguments. +*/ +struct Fts3Table { + sqlite3_vtab base; /* Base class used by SQLite core */ + sqlite3 *db; /* The database connection */ + const char *zDb; /* logical database name */ + const char *zName; /* virtual table name */ + int nColumn; /* number of named columns in virtual table */ + char **azColumn; /* column names. malloced */ + u8 *abNotindexed; /* True for 'notindexed' columns */ + sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ + char *zContentTbl; /* content=xxx option, or NULL */ + char *zLanguageid; /* languageid=xxx option, or NULL */ + int nAutoincrmerge; /* Value configured by 'automerge' */ + u32 nLeafAdd; /* Number of leaf blocks added this trans */ + int bLock; /* Used to prevent recursive content= tbls */ + + /* Precompiled statements used by the implementation. Each of these + ** statements is run and reset within a single virtual table API call. + */ + sqlite3_stmt *aStmt[40]; + sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */ + + char *zReadExprlist; + char *zWriteExprlist; + + int nNodeSize; /* Soft limit for node size */ + u8 bFts4; /* True for FTS4, false for FTS3 */ + u8 bHasStat; /* True if %_stat table exists (2==unknown) */ + u8 bHasDocsize; /* True if %_docsize table exists */ + u8 bDescIdx; /* True if doclists are in reverse order */ + u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ + int nPgsz; /* Page size for host database */ + char *zSegmentsTbl; /* Name of %_segments table */ + sqlite3_blob *pSegments; /* Blob handle open on %_segments table */ + + /* + ** The following array of hash tables is used to buffer pending index + ** updates during transactions. All pending updates buffered at any one + ** time must share a common language-id (see the FTS4 langid= feature). + ** The current language id is stored in variable iPrevLangid. + ** + ** A single FTS4 table may have multiple full-text indexes. For each index + ** there is an entry in the aIndex[] array. Index 0 is an index of all the + ** terms that appear in the document set. Each subsequent index in aIndex[] + ** is an index of prefixes of a specific length. + ** + ** Variable nPendingData contains an estimate the memory consumed by the + ** pending data structures, including hash table overhead, but not including + ** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash + ** tables are flushed to disk. Variable iPrevDocid is the docid of the most + ** recently inserted record. + */ + int nIndex; /* Size of aIndex[] */ + struct Fts3Index { + int nPrefix; /* Prefix length (0 for main terms index) */ + Fts3Hash hPending; /* Pending terms table for this index */ + } *aIndex; + int nMaxPendingData; /* Max pending data before flush to disk */ + int nPendingData; /* Current bytes of pending data */ + sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ + int iPrevLangid; /* Langid of recently inserted document */ + int bPrevDelete; /* True if last operation was a delete */ + +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) + /* State variables used for validating that the transaction control + ** methods of the virtual table are called at appropriate times. These + ** values do not contribute to FTS functionality; they are used for + ** verifying the operation of the SQLite core. + */ + int inTransaction; /* True after xBegin but before xCommit/xRollback */ + int mxSavepoint; /* Largest valid xSavepoint integer */ +#endif + +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + /* True to disable the incremental doclist optimization. This is controled + ** by special insert command 'test-no-incr-doclist'. */ + int bNoIncrDoclist; + + /* Number of segments in a level */ + int nMergeCount; +#endif +}; + +/* Macro to find the number of segments to merge */ +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) +# define MergeCount(P) ((P)->nMergeCount) +#else +# define MergeCount(P) FTS3_MERGE_COUNT +#endif + +/* +** When the core wants to read from the virtual table, it creates a +** virtual table cursor (an instance of the following structure) using +** the xOpen method. Cursors are destroyed using the xClose method. +*/ +struct Fts3Cursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + i16 eSearch; /* Search strategy (see below) */ + u8 isEof; /* True if at End Of Results */ + u8 isRequireSeek; /* True if must seek pStmt to %_content row */ + u8 bSeekStmt; /* True if pStmt is a seek */ + sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */ + Fts3Expr *pExpr; /* Parsed MATCH query string */ + int iLangid; /* Language being queried for */ + int nPhrase; /* Number of matchable phrases in query */ + Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */ + sqlite3_int64 iPrevId; /* Previous id read from aDoclist */ + char *pNextId; /* Pointer into the body of aDoclist */ + char *aDoclist; /* List of docids for full-text queries */ + int nDoclist; /* Size of buffer at aDoclist */ + u8 bDesc; /* True to sort in descending order */ + int eEvalmode; /* An FTS3_EVAL_XX constant */ + int nRowAvg; /* Average size of database rows, in pages */ + sqlite3_int64 nDoc; /* Documents in table */ + i64 iMinDocid; /* Minimum docid to return */ + i64 iMaxDocid; /* Maximum docid to return */ + int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ + MatchinfoBuffer *pMIBuffer; /* Buffer for matchinfo data */ +}; + +#define FTS3_EVAL_FILTER 0 +#define FTS3_EVAL_NEXT 1 +#define FTS3_EVAL_MATCHINFO 2 + +/* +** The Fts3Cursor.eSearch member is always set to one of the following. +** Actualy, Fts3Cursor.eSearch can be greater than or equal to +** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index +** of the column to be searched. For example, in +** +** CREATE VIRTUAL TABLE ex1 USING fts3(a,b,c,d); +** SELECT docid FROM ex1 WHERE b MATCH 'one two three'; +** +** Because the LHS of the MATCH operator is 2nd column "b", +** Fts3Cursor.eSearch will be set to FTS3_FULLTEXT_SEARCH+1. (+0 for a, +** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1" +** indicating that all columns should be searched, +** then eSearch would be set to FTS3_FULLTEXT_SEARCH+4. +*/ +#define FTS3_FULLSCAN_SEARCH 0 /* Linear scan of %_content table */ +#define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */ +#define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */ + +/* +** The lower 16-bits of the sqlite3_index_info.idxNum value set by +** the xBestIndex() method contains the Fts3Cursor.eSearch value described +** above. The upper 16-bits contain a combination of the following +** bits, used to describe extra constraints on full-text searches. +*/ +#define FTS3_HAVE_LANGID 0x00010000 /* languageid=? */ +#define FTS3_HAVE_DOCID_GE 0x00020000 /* docid>=? */ +#define FTS3_HAVE_DOCID_LE 0x00040000 /* docid<=? */ + +struct Fts3Doclist { + char *aAll; /* Array containing doclist (or NULL) */ + int nAll; /* Size of a[] in bytes */ + char *pNextDocid; /* Pointer to next docid */ + + sqlite3_int64 iDocid; /* Current docid (if pList!=0) */ + int bFreeList; /* True if pList should be sqlite3_free()d */ + char *pList; /* Pointer to position list following iDocid */ + int nList; /* Length of position list */ +}; + +/* +** A "phrase" is a sequence of one or more tokens that must match in +** sequence. A single token is the base case and the most common case. +** For a sequence of tokens contained in double-quotes (i.e. "one two three") +** nToken will be the number of tokens in the string. +*/ +struct Fts3PhraseToken { + char *z; /* Text of the token */ + int n; /* Number of bytes in buffer z */ + int isPrefix; /* True if token ends with a "*" character */ + int bFirst; /* True if token must appear at position 0 */ + + /* Variables above this point are populated when the expression is + ** parsed (by code in fts3_expr.c). Below this point the variables are + ** used when evaluating the expression. */ + Fts3DeferredToken *pDeferred; /* Deferred token object for this token */ + Fts3MultiSegReader *pSegcsr; /* Segment-reader for this token */ +}; + +struct Fts3Phrase { + /* Cache of doclist for this phrase. */ + Fts3Doclist doclist; + int bIncr; /* True if doclist is loaded incrementally */ + int iDoclistToken; + + /* Used by sqlite3Fts3EvalPhrasePoslist() if this is a descendent of an + ** OR condition. */ + char *pOrPoslist; + i64 iOrDocid; + + /* Variables below this point are populated by fts3_expr.c when parsing + ** a MATCH expression. Everything above is part of the evaluation phase. + */ + int nToken; /* Number of tokens in the phrase */ + int iColumn; /* Index of column this phrase must match */ + Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */ +}; + +/* +** A tree of these objects forms the RHS of a MATCH operator. +** +** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist +** points to a malloced buffer, size nDoclist bytes, containing the results +** of this phrase query in FTS3 doclist format. As usual, the initial +** "Length" field found in doclists stored on disk is omitted from this +** buffer. +** +** Variable aMI is used only for FTSQUERY_NEAR nodes to store the global +** matchinfo data. If it is not NULL, it points to an array of size nCol*3, +** where nCol is the number of columns in the queried FTS table. The array +** is populated as follows: +** +** aMI[iCol*3 + 0] = Undefined +** aMI[iCol*3 + 1] = Number of occurrences +** aMI[iCol*3 + 2] = Number of rows containing at least one instance +** +** The aMI array is allocated using sqlite3_malloc(). It should be freed +** when the expression node is. +*/ +struct Fts3Expr { + int eType; /* One of the FTSQUERY_XXX values defined below */ + int nNear; /* Valid if eType==FTSQUERY_NEAR */ + Fts3Expr *pParent; /* pParent->pLeft==this or pParent->pRight==this */ + Fts3Expr *pLeft; /* Left operand */ + Fts3Expr *pRight; /* Right operand */ + Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */ + + /* The following are used by the fts3_eval.c module. */ + sqlite3_int64 iDocid; /* Current docid */ + u8 bEof; /* True this expression is at EOF already */ + u8 bStart; /* True if iDocid is valid */ + u8 bDeferred; /* True if this expression is entirely deferred */ + + /* The following are used by the fts3_snippet.c module. */ + int iPhrase; /* Index of this phrase in matchinfo() results */ + u32 *aMI; /* See above */ +}; + +/* +** Candidate values for Fts3Query.eType. Note that the order of the first +** four values is in order of precedence when parsing expressions. For +** example, the following: +** +** "a OR b AND c NOT d NEAR e" +** +** is equivalent to: +** +** "a OR (b AND (c NOT (d NEAR e)))" +*/ +#define FTSQUERY_NEAR 1 +#define FTSQUERY_NOT 2 +#define FTSQUERY_AND 3 +#define FTSQUERY_OR 4 +#define FTSQUERY_PHRASE 5 + + +/* fts3_write.c */ +SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); +SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *); +SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *); +SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *); +SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64, + sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**); +SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( + Fts3Table*,int,const char*,int,int,Fts3SegReader**); +SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *); +SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, int, sqlite3_stmt **); +SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*); + +SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **); +SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **); + +#ifndef SQLITE_DISABLE_FTS4_DEFERRED +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *); +SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int); +SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *); +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *); +SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *); +#else +# define sqlite3Fts3FreeDeferredTokens(x) +# define sqlite3Fts3DeferToken(x,y,z) SQLITE_OK +# define sqlite3Fts3CacheDeferredDoclists(x) SQLITE_OK +# define sqlite3Fts3FreeDeferredDoclists(x) +# define sqlite3Fts3DeferredTokenList(x,y,z) SQLITE_OK +#endif + +SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *); +SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *, int *); + +/* Special values interpreted by sqlite3SegReaderCursor() */ +#define FTS3_SEGCURSOR_PENDING -1 +#define FTS3_SEGCURSOR_ALL -2 + +SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Fts3SegFilter*); +SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *); +SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *); + +SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *, + int, int, int, const char *, int, int, int, Fts3MultiSegReader *); + +/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */ +#define FTS3_SEGMENT_REQUIRE_POS 0x00000001 +#define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002 +#define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 +#define FTS3_SEGMENT_PREFIX 0x00000008 +#define FTS3_SEGMENT_SCAN 0x00000010 +#define FTS3_SEGMENT_FIRST 0x00000020 + +/* Type passed as 4th argument to SegmentReaderIterate() */ +struct Fts3SegFilter { + const char *zTerm; + int nTerm; + int iCol; + int flags; +}; + +struct Fts3MultiSegReader { + /* Used internally by sqlite3Fts3SegReaderXXX() calls */ + Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */ + int nSegment; /* Size of apSegment array */ + int nAdvance; /* How many seg-readers to advance */ + Fts3SegFilter *pFilter; /* Pointer to filter object */ + char *aBuffer; /* Buffer to merge doclists in */ + int nBuffer; /* Allocated size of aBuffer[] in bytes */ + + int iColFilter; /* If >=0, filter for this column */ + int bRestart; + + /* Used by fts3.c only. */ + int nCost; /* Cost of running iterator */ + int bLookup; /* True if a lookup of a single entry. */ + + /* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */ + char *zTerm; /* Pointer to term buffer */ + int nTerm; /* Size of zTerm in bytes */ + char *aDoclist; /* Pointer to doclist buffer */ + int nDoclist; /* Size of aDoclist[] in bytes */ +}; + +SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int); + +#define fts3GetVarint32(p, piVal) ( \ + (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ +) + +/* fts3.c */ +SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...); +SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64); +SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); +SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *); +SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*); +SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); +SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); +SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); +SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); +SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); +SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); +SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*); +SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc); +SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut); + +/* fts3_tokenizer.c */ +SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *); +SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); +SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, + sqlite3_tokenizer **, char ** +); +SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char); + +/* fts3_snippet.c */ +SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*); +SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, + const char *, const char *, int, int +); +SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); +SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p); + +/* fts3_expr.c */ +SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, + char **, int, int, int, const char *, int, Fts3Expr **, char ** +); +SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); +#ifdef SQLITE_TEST +SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*); +SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); +#endif +SQLITE_PRIVATE void *sqlite3Fts3MallocZero(i64 nByte); + +SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, + sqlite3_tokenizer_cursor ** +); + +/* fts3_aux.c */ +SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); + +SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); + +SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( + Fts3Table*, Fts3MultiSegReader*, int, const char*, int); +SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( + Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); +SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); +SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); +SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); + +/* fts3_tokenize_vtab.c */ +SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*)); + +/* fts3_unicode2.c (functions generated by parsing unicode text files) */ +#ifndef SQLITE_DISABLE_FTS3_UNICODE +SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int); +SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); +SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); +#endif + +#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ +#endif /* _FTSINT_H */ + +/************** End of fts3Int.h *********************************************/ +/************** Continuing where we left off in fts3.c ***********************/ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +#if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE) +# define SQLITE_CORE 1 +#endif + +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +/* #include "fts3.h" */ +#ifndef SQLITE_CORE +/* # include "sqlite3ext.h" */ + SQLITE_EXTENSION_INIT1 +#endif + +typedef struct Fts3HashWrapper Fts3HashWrapper; +struct Fts3HashWrapper { + Fts3Hash hash; /* Hash table */ + int nRef; /* Number of pointers to this object */ +}; + +static int fts3EvalNext(Fts3Cursor *pCsr); +static int fts3EvalStart(Fts3Cursor *pCsr); +static int fts3TermSegReaderCursor( + Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); + +/* +** This variable is set to false when running tests for which the on disk +** structures should not be corrupt. Otherwise, true. If it is false, extra +** assert() conditions in the fts3 code are activated - conditions that are +** only true if it is guaranteed that the fts3 database is not corrupt. +*/ +#ifdef SQLITE_DEBUG +SQLITE_API int sqlite3_fts3_may_be_corrupt = 1; +#endif + +/* +** Write a 64-bit variable-length integer to memory starting at p[0]. +** The length of data written will be between 1 and FTS3_VARINT_MAX bytes. +** The number of bytes written is returned. +*/ +SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){ + unsigned char *q = (unsigned char *) p; + sqlite_uint64 vu = v; + do{ + *q++ = (unsigned char) ((vu & 0x7f) | 0x80); + vu >>= 7; + }while( vu!=0 ); + q[-1] &= 0x7f; /* turn off high bit in final byte */ + assert( q - (unsigned char *)p <= FTS3_VARINT_MAX ); + return (int) (q - (unsigned char *)p); +} + +#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \ + v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift ); \ + if( (v & mask2)==0 ){ var = v; return ret; } +#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \ + v = (*ptr++); \ + if( (v & mask2)==0 ){ var = v; return ret; } + +SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){ + const unsigned char *p = (const unsigned char*)pBuf; + const unsigned char *pStart = p; + u32 a; + u64 b; + int shift; + + GETVARINT_INIT(a, p, 0, 0x00, 0x80, *v, 1); + GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *v, 2); + GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *v, 3); + GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4); + b = (a & 0x0FFFFFFF ); + + for(shift=28; shift<=63; shift+=7){ + u64 c = *p++; + b += (c&0x7F) << shift; + if( (c & 0x80)==0 ) break; + } + *v = b; + return (int)(p - pStart); +} + +/* +** Read a 64-bit variable-length integer from memory starting at p[0]. +** Return the number of bytes read, or 0 on error. +** The value is stored in *v. +*/ +SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){ + return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v); +} + +/* +** Read a 64-bit variable-length integer from memory starting at p[0] and +** not extending past pEnd[-1]. +** Return the number of bytes read, or 0 on error. +** The value is stored in *v. +*/ +SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded( + const char *pBuf, + const char *pEnd, + sqlite_int64 *v +){ + const unsigned char *p = (const unsigned char*)pBuf; + const unsigned char *pStart = p; + const unsigned char *pX = (const unsigned char*)pEnd; + u64 b = 0; + int shift; + for(shift=0; shift<=63; shift+=7){ + u64 c = p=0 ); + return 5; +} + +/* +** Return the number of bytes required to encode v as a varint +*/ +SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64 v){ + int i = 0; + do{ + i++; + v >>= 7; + }while( v!=0 ); + return i; +} + +/* +** Convert an SQL-style quoted string into a normal string by removing +** the quote characters. The conversion is done in-place. If the +** input does not begin with a quote character, then this routine +** is a no-op. +** +** Examples: +** +** "abc" becomes abc +** 'xyz' becomes xyz +** [pqr] becomes pqr +** `mno` becomes mno +** +*/ +SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){ + char quote; /* Quote character (if any ) */ + + quote = z[0]; + if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ + int iIn = 1; /* Index of next byte to read from input */ + int iOut = 0; /* Index of next byte to write to output */ + + /* If the first byte was a '[', then the close-quote character is a ']' */ + if( quote=='[' ) quote = ']'; + + while( z[iIn] ){ + if( z[iIn]==quote ){ + if( z[iIn+1]!=quote ) break; + z[iOut++] = quote; + iIn += 2; + }else{ + z[iOut++] = z[iIn++]; + } + } + z[iOut] = '\0'; + } +} + +/* +** Read a single varint from the doclist at *pp and advance *pp to point +** to the first byte past the end of the varint. Add the value of the varint +** to *pVal. +*/ +static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ + sqlite3_int64 iVal; + *pp += sqlite3Fts3GetVarint(*pp, &iVal); + *pVal += iVal; +} -#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC) /* IMP: R-04780-55815 */ - case SQLITE_CONFIG_WIN32_HEAPSIZE: { - /* EVIDENCE-OF: R-34926-03360 SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit - ** unsigned integer value that specifies the maximum size of the created - ** heap. */ - sqlite3GlobalConfig.nHeap = va_arg(ap, int); - break; - } -#endif +/* +** When this function is called, *pp points to the first byte following a +** varint that is part of a doclist (or position-list, or any other list +** of varints). This function moves *pp to point to the start of that varint, +** and sets *pVal by the varint value. +** +** Argument pStart points to the first byte of the doclist that the +** varint is part of. +*/ +static void fts3GetReverseVarint( + char **pp, + char *pStart, + sqlite3_int64 *pVal +){ + sqlite3_int64 iVal; + char *p; - case SQLITE_CONFIG_PMASZ: { - sqlite3GlobalConfig.szPma = va_arg(ap, unsigned int); - break; - } + /* Pointer p now points at the first byte past the varint we are + ** interested in. So, unless the doclist is corrupt, the 0x80 bit is + ** clear on character p[-1]. */ + for(p = (*pp)-2; p>=pStart && *p&0x80; p--); + p++; + *pp = p; - case SQLITE_CONFIG_STMTJRNL_SPILL: { - sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int); - break; - } + sqlite3Fts3GetVarint(p, &iVal); + *pVal = iVal; +} - default: { - rc = SQLITE_ERROR; - break; - } +/* +** The xDisconnect() virtual table method. +*/ +static int fts3DisconnectMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table *)pVtab; + int i; + + assert( p->nPendingData==0 ); + assert( p->pSegments==0 ); + + /* Free any prepared statements held */ + sqlite3_finalize(p->pSeekStmt); + for(i=0; iaStmt); i++){ + sqlite3_finalize(p->aStmt[i]); } + sqlite3_free(p->zSegmentsTbl); + sqlite3_free(p->zReadExprlist); + sqlite3_free(p->zWriteExprlist); + sqlite3_free(p->zContentTbl); + sqlite3_free(p->zLanguageid); + + /* Invoke the tokenizer destructor to free the tokenizer. */ + p->pTokenizer->pModule->xDestroy(p->pTokenizer); + + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Write an error message into *pzErr +*/ +SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char **pzErr, const char *zFormat, ...){ + va_list ap; + sqlite3_free(*pzErr); + va_start(ap, zFormat); + *pzErr = sqlite3_vmprintf(zFormat, ap); va_end(ap); - return rc; } /* -** Set up the lookaside buffers for a database connection. -** Return SQLITE_OK on success. -** If lookaside is already active, return SQLITE_BUSY. +** Construct one or more SQL statements from the format string given +** and then evaluate those statements. The success code is written +** into *pRc. ** -** The sz parameter is the number of bytes in each lookaside slot. -** The cnt parameter is the number of slots. If pStart is NULL the -** space for the lookaside memory is obtained from sqlite3_malloc(). -** If pStart is not NULL then it is sz*cnt bytes of memory to use for -** the lookaside memory. +** If *pRc is initially non-zero then this routine is a no-op. */ -static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ -#ifndef SQLITE_OMIT_LOOKASIDE - void *pStart; - if( db->lookaside.nOut ){ - return SQLITE_BUSY; - } - /* Free any existing lookaside buffer for this handle before - ** allocating a new one so we don't have to have space for - ** both at the same time. - */ - if( db->lookaside.bMalloced ){ - sqlite3_free(db->lookaside.pStart); - } - /* The size of a lookaside slot after ROUNDDOWN8 needs to be larger - ** than a pointer to be useful. - */ - sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */ - if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0; - if( cnt<0 ) cnt = 0; - if( sz==0 || cnt==0 ){ - sz = 0; - pStart = 0; - }else if( pBuf==0 ){ - sqlite3BeginBenignMalloc(); - pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */ - sqlite3EndBenignMalloc(); - if( pStart ) cnt = sqlite3MallocSize(pStart)/sz; +static void fts3DbExec( + int *pRc, /* Success code */ + sqlite3 *db, /* Database in which to run SQL */ + const char *zFormat, /* Format string for SQL */ + ... /* Arguments to the format string */ +){ + va_list ap; + char *zSql; + if( *pRc ) return; + va_start(ap, zFormat); + zSql = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( zSql==0 ){ + *pRc = SQLITE_NOMEM; }else{ - pStart = pBuf; + *pRc = sqlite3_exec(db, zSql, 0, 0, 0); + sqlite3_free(zSql); } - db->lookaside.pStart = pStart; - db->lookaside.pFree = 0; - db->lookaside.sz = (u16)sz; - if( pStart ){ - int i; - LookasideSlot *p; - assert( sz > (int)sizeof(LookasideSlot*) ); - p = (LookasideSlot*)pStart; - for(i=cnt-1; i>=0; i--){ - p->pNext = db->lookaside.pFree; - db->lookaside.pFree = p; - p = (LookasideSlot*)&((u8*)p)[sz]; +} + +/* +** The xDestroy() virtual table method. +*/ +static int fts3DestroyMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table *)pVtab; + int rc = SQLITE_OK; /* Return code */ + const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ + sqlite3 *db = p->db; /* Database handle */ + + /* Drop the shadow tables */ + fts3DbExec(&rc, db, + "DROP TABLE IF EXISTS %Q.'%q_segments';" + "DROP TABLE IF EXISTS %Q.'%q_segdir';" + "DROP TABLE IF EXISTS %Q.'%q_docsize';" + "DROP TABLE IF EXISTS %Q.'%q_stat';" + "%s DROP TABLE IF EXISTS %Q.'%q_content';", + zDb, p->zName, + zDb, p->zName, + zDb, p->zName, + zDb, p->zName, + (p->zContentTbl ? "--" : ""), zDb,p->zName + ); + + /* If everything has worked, invoke fts3DisconnectMethod() to free the + ** memory associated with the Fts3Table structure and return SQLITE_OK. + ** Otherwise, return an SQLite error code. + */ + return (rc==SQLITE_OK ? fts3DisconnectMethod(pVtab) : rc); +} + + +/* +** Invoke sqlite3_declare_vtab() to declare the schema for the FTS3 table +** passed as the first argument. This is done as part of the xConnect() +** and xCreate() methods. +** +** If *pRc is non-zero when this function is called, it is a no-op. +** Otherwise, if an error occurs, an SQLite error code is stored in *pRc +** before returning. +*/ +static void fts3DeclareVtab(int *pRc, Fts3Table *p){ + if( *pRc==SQLITE_OK ){ + int i; /* Iterator variable */ + int rc; /* Return code */ + char *zSql; /* SQL statement passed to declare_vtab() */ + char *zCols; /* List of user defined columns */ + const char *zLanguageid; + + zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid"); + sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + + /* Create a list of user columns for the virtual table */ + zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); + for(i=1; zCols && inColumn; i++){ + zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]); } - db->lookaside.pEnd = p; - db->lookaside.bDisable = 0; - db->lookaside.bMalloced = pBuf==0 ?1:0; - }else{ - db->lookaside.pStart = db; - db->lookaside.pEnd = db; - db->lookaside.bDisable = 1; - db->lookaside.bMalloced = 0; + + /* Create the whole "CREATE TABLE" statement to pass to SQLite */ + zSql = sqlite3_mprintf( + "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)", + zCols, p->zName, zLanguageid + ); + if( !zCols || !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_declare_vtab(p->db, zSql); + } + + sqlite3_free(zSql); + sqlite3_free(zCols); + *pRc = rc; } -#endif /* SQLITE_OMIT_LOOKASIDE */ - return SQLITE_OK; } /* -** Return the mutex associated with a database connection. +** Create the %_stat table if it does not already exist. */ -SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; - } -#endif - return db->mutex; +SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){ + fts3DbExec(pRc, p->db, + "CREATE TABLE IF NOT EXISTS %Q.'%q_stat'" + "(id INTEGER PRIMARY KEY, value BLOB);", + p->zDb, p->zName + ); + if( (*pRc)==SQLITE_OK ) p->bHasStat = 1; } /* -** Free up as much memory as we can from the given database -** connection. +** Create the backing store tables (%_content, %_segments and %_segdir) +** required by the FTS3 table passed as the only argument. This is done +** as part of the vtab xCreate() method. +** +** If the p->bHasDocsize boolean is true (indicating that this is an +** FTS4 table, not an FTS3 table) then also create the %_docsize and +** %_stat tables required by FTS4. */ -SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){ - int i; +static int fts3CreateTables(Fts3Table *p){ + int rc = SQLITE_OK; /* Return code */ + int i; /* Iterator variable */ + sqlite3 *db = p->db; /* The database connection */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - sqlite3BtreeEnterAll(db); - for(i=0; inDb; i++){ - Btree *pBt = db->aDb[i].pBt; - if( pBt ){ - Pager *pPager = sqlite3BtreePager(pBt); - sqlite3PagerShrink(pPager); + if( p->zContentTbl==0 ){ + const char *zLanguageid = p->zLanguageid; + char *zContentCols; /* Columns of %_content table */ + + /* Create a list of user columns for the content table */ + zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); + for(i=0; zContentCols && inColumn; i++){ + char *z = p->azColumn[i]; + zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); } + if( zLanguageid && zContentCols ){ + zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid); + } + if( zContentCols==0 ) rc = SQLITE_NOMEM; + + /* Create the content table */ + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_content'(%s)", + p->zDb, p->zName, zContentCols + ); + sqlite3_free(zContentCols); } - sqlite3BtreeLeaveAll(db); - sqlite3_mutex_leave(db->mutex); - return SQLITE_OK; + + /* Create other tables */ + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", + p->zDb, p->zName + ); + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_segdir'(" + "level INTEGER," + "idx INTEGER," + "start_block INTEGER," + "leaves_end_block INTEGER," + "end_block INTEGER," + "root BLOB," + "PRIMARY KEY(level, idx)" + ");", + p->zDb, p->zName + ); + if( p->bHasDocsize ){ + fts3DbExec(&rc, db, + "CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);", + p->zDb, p->zName + ); + } + assert( p->bHasStat==p->bFts4 ); + if( p->bHasStat ){ + sqlite3Fts3CreateStatTable(&rc, p); + } + return rc; } /* -** Flush any dirty pages in the pager-cache for any attached database -** to disk. +** Store the current database page-size in bytes in p->nPgsz. +** +** If *pRc is non-zero when this function is called, it is a no-op. +** Otherwise, if an error occurs, an SQLite error code is stored in *pRc +** before returning. */ -SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ - int i; - int rc = SQLITE_OK; - int bSeenBusy = 0; +static void fts3DatabasePageSize(int *pRc, Fts3Table *p){ + if( *pRc==SQLITE_OK ){ + int rc; /* Return code */ + char *zSql; /* SQL text "PRAGMA %Q.page_size" */ + sqlite3_stmt *pStmt; /* Compiled "PRAGMA %Q.page_size" statement */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - sqlite3BtreeEnterAll(db); - for(i=0; rc==SQLITE_OK && inDb; i++){ - Btree *pBt = db->aDb[i].pBt; - if( pBt && sqlite3BtreeIsInTrans(pBt) ){ - Pager *pPager = sqlite3BtreePager(pBt); - rc = sqlite3PagerFlush(pPager); - if( rc==SQLITE_BUSY ){ - bSeenBusy = 1; + zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_step(pStmt); + p->nPgsz = sqlite3_column_int(pStmt, 0); + rc = sqlite3_finalize(pStmt); + }else if( rc==SQLITE_AUTH ){ + p->nPgsz = 1024; rc = SQLITE_OK; } } + assert( p->nPgsz>0 || rc!=SQLITE_OK ); + sqlite3_free(zSql); + *pRc = rc; } - sqlite3BtreeLeaveAll(db); - sqlite3_mutex_leave(db->mutex); - return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc); } /* -** Configuration settings for an individual database connection +** "Special" FTS4 arguments are column specifications of the following form: +** +** = +** +** There may not be whitespace surrounding the "=" character. The +** term may be quoted, but the may not. */ -SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ - va_list ap; - int rc; - va_start(ap, op); - switch( op ){ - case SQLITE_DBCONFIG_MAINDBNAME: { - db->aDb[0].zDbSName = va_arg(ap,char*); - rc = SQLITE_OK; - break; - } - case SQLITE_DBCONFIG_LOOKASIDE: { - void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */ - int sz = va_arg(ap, int); /* IMP: R-47871-25994 */ - int cnt = va_arg(ap, int); /* IMP: R-04460-53386 */ - rc = setupLookaside(db, pBuf, sz, cnt); - break; - } - default: { - static const struct { - int op; /* The opcode */ - u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */ - } aFlagOp[] = { - { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys }, - { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger }, - { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer }, - { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension }, - { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose }, - }; - unsigned int i; - rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ - for(i=0; iflags; - if( onoff>0 ){ - db->flags |= aFlagOp[i].mask; - }else if( onoff==0 ){ - db->flags &= ~aFlagOp[i].mask; - } - if( oldFlags!=db->flags ){ - sqlite3ExpirePreparedStatements(db); - } - if( pRes ){ - *pRes = (db->flags & aFlagOp[i].mask)!=0; - } - rc = SQLITE_OK; - break; - } - } - break; - } +static int fts3IsSpecialColumn( + const char *z, + int *pnKey, + char **pzValue +){ + char *zValue; + const char *zCsr = z; + + while( *zCsr!='=' ){ + if( *zCsr=='\0' ) return 0; + zCsr++; } - va_end(ap); - return rc; + + *pnKey = (int)(zCsr-z); + zValue = sqlite3_mprintf("%s", &zCsr[1]); + if( zValue ){ + sqlite3Fts3Dequote(zValue); + } + *pzValue = zValue; + return 1; } +/* +** Append the output of a printf() style formatting to an existing string. +*/ +static void fts3Appendf( + int *pRc, /* IN/OUT: Error code */ + char **pz, /* IN/OUT: Pointer to string buffer */ + const char *zFormat, /* Printf format string to append */ + ... /* Arguments for printf format string */ +){ + if( *pRc==SQLITE_OK ){ + va_list ap; + char *z; + va_start(ap, zFormat); + z = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( z && *pz ){ + char *z2 = sqlite3_mprintf("%s%s", *pz, z); + sqlite3_free(z); + z = z2; + } + if( z==0 ) *pRc = SQLITE_NOMEM; + sqlite3_free(*pz); + *pz = z; + } +} /* -** Return true if the buffer z[0..n-1] contains all spaces. +** Return a copy of input string zInput enclosed in double-quotes (") and +** with all double quote characters escaped. For example: +** +** fts3QuoteId("un \"zip\"") -> "un \"\"zip\"\"" +** +** The pointer returned points to memory obtained from sqlite3_malloc(). It +** is the callers responsibility to call sqlite3_free() to release this +** memory. */ -static int allSpaces(const char *z, int n){ - while( n>0 && z[n-1]==' ' ){ n--; } - return n==0; +static char *fts3QuoteId(char const *zInput){ + sqlite3_int64 nRet; + char *zRet; + nRet = 2 + (int)strlen(zInput)*2 + 1; + zRet = sqlite3_malloc64(nRet); + if( zRet ){ + int i; + char *z = zRet; + *(z++) = '"'; + for(i=0; zInput[i]; i++){ + if( zInput[i]=='"' ) *(z++) = '"'; + *(z++) = zInput[i]; + } + *(z++) = '"'; + *(z++) = '\0'; + } + return zRet; } /* -** This is the default collating function named "BINARY" which is always -** available. +** Return a list of comma separated SQL expressions and a FROM clause that +** could be used in a SELECT statement such as the following: +** +** SELECT FROM %_content AS x ... +** +** to return the docid, followed by each column of text data in order +** from left to write. If parameter zFunc is not NULL, then instead of +** being returned directly each column of text data is passed to an SQL +** function named zFunc first. For example, if zFunc is "unzip" and the +** table has the three user-defined columns "a", "b", and "c", the following +** string is returned: +** +** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x" ** -** If the padFlag argument is not NULL then space padding at the end -** of strings is ignored. This implements the RTRIM collation. +** The pointer returned points to a buffer allocated by sqlite3_malloc(). It +** is the responsibility of the caller to eventually free it. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and +** a NULL pointer is returned). Otherwise, if an OOM error is encountered +** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If +** no error occurs, *pRc is left unmodified. */ -static int binCollFunc( - void *padFlag, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 -){ - int rc, n; - n = nKey1zContentTbl==0 ){ + if( !zFunc ){ + zFunction = ""; }else{ - rc = nKey1 - nKey2; + zFree = zFunction = fts3QuoteId(zFunc); + } + fts3Appendf(pRc, &zRet, "docid"); + for(i=0; inColumn; i++){ + fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); + } + if( p->zLanguageid ){ + fts3Appendf(pRc, &zRet, ", x.%Q", "langid"); + } + sqlite3_free(zFree); + }else{ + fts3Appendf(pRc, &zRet, "rowid"); + for(i=0; inColumn; i++){ + fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]); + } + if( p->zLanguageid ){ + fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid); } } - return rc; + fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x", + p->zDb, + (p->zContentTbl ? p->zContentTbl : p->zName), + (p->zContentTbl ? "" : "_content") + ); + return zRet; } /* -** Another built-in collating sequence: NOCASE. +** Return a list of N comma separated question marks, where N is the number +** of columns in the %_content table (one for the docid plus one for each +** user-defined text column). ** -** This collating sequence is intended to be used for "case independent -** comparison". SQLite's knowledge of upper and lower case equivalents -** extends only to the 26 characters used in the English language. +** If argument zFunc is not NULL, then all but the first question mark +** is preceded by zFunc and an open bracket, and followed by a closed +** bracket. For example, if zFunc is "zip" and the FTS3 table has three +** user-defined text columns, the following string is returned: ** -** At the moment there is only a UTF-8 implementation. +** "?, zip(?), zip(?), zip(?)" +** +** The pointer returned points to a buffer allocated by sqlite3_malloc(). It +** is the responsibility of the caller to eventually free it. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and +** a NULL pointer is returned). Otherwise, if an OOM error is encountered +** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If +** no error occurs, *pRc is left unmodified. */ -static int nocaseCollatingFunc( - void *NotUsed, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 -){ - int r = sqlite3StrNICmp( - (const char *)pKey1, (const char *)pKey2, (nKey1nColumn; i++){ + fts3Appendf(pRc, &zRet, ",%s(?)", zFunction); + } + if( p->zLanguageid ){ + fts3Appendf(pRc, &zRet, ", ?"); + } + sqlite3_free(zFree); + return zRet; } /* -** Return the ROWID of the most recent insert +** Buffer z contains a positive integer value encoded as utf-8 text. +** Decode this value and store it in *pnOut, returning the number of bytes +** consumed. If an overflow error occurs return a negative value. */ -SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; +SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut){ + u64 iVal = 0; + int i; + for(i=0; z[i]>='0' && z[i]<='9'; i++){ + iVal = iVal*10 + (z[i] - '0'); + if( iVal>0x7FFFFFFF ) return -1; } -#endif - return db->lastRowid; + *pnOut = (int)iVal; + return i; } /* -** Return the number of changes in the most recent call to sqlite3_exec(). +** This function interprets the string at (*pp) as a non-negative integer +** value. It reads the integer and sets *pnOut to the value read, then +** sets *pp to point to the byte immediately following the last byte of +** the integer value. +** +** Only decimal digits ('0'..'9') may be part of an integer value. +** +** If *pp does not being with a decimal digit SQLITE_ERROR is returned and +** the output value undefined. Otherwise SQLITE_OK is returned. +** +** This function is used when parsing the "prefix=" FTS4 parameter. */ -SQLITE_API int sqlite3_changes(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; +static int fts3GobbleInt(const char **pp, int *pnOut){ + const int MAX_NPREFIX = 10000000; + int nInt = 0; /* Output value */ + int nByte; + nByte = sqlite3Fts3ReadInt(*pp, &nInt); + if( nInt>MAX_NPREFIX ){ + nInt = 0; } -#endif - return db->nChange; + if( nByte==0 ){ + return SQLITE_ERROR; + } + *pnOut = nInt; + *pp += nByte; + return SQLITE_OK; } /* -** Return the number of changes since the database handle was opened. +** This function is called to allocate an array of Fts3Index structures +** representing the indexes maintained by the current FTS table. FTS tables +** always maintain the main "terms" index, but may also maintain one or +** more "prefix" indexes, depending on the value of the "prefix=" parameter +** (if any) specified as part of the CREATE VIRTUAL TABLE statement. +** +** Argument zParam is passed the value of the "prefix=" option if one was +** specified, or NULL otherwise. +** +** If no error occurs, SQLITE_OK is returned and *apIndex set to point to +** the allocated array. *pnIndex is set to the number of elements in the +** array. If an error does occur, an SQLite error code is returned. +** +** Regardless of whether or not an error is returned, it is the responsibility +** of the caller to call sqlite3_free() on the output array to free it. */ -SQLITE_API int sqlite3_total_changes(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; +static int fts3PrefixParameter( + const char *zParam, /* ABC in prefix=ABC parameter to parse */ + int *pnIndex, /* OUT: size of *apIndex[] array */ + struct Fts3Index **apIndex /* OUT: Array of indexes for this table */ +){ + struct Fts3Index *aIndex; /* Allocated array */ + int nIndex = 1; /* Number of entries in array */ + + if( zParam && zParam[0] ){ + const char *p; + nIndex++; + for(p=zParam; *p; p++){ + if( *p==',' ) nIndex++; + } } -#endif - return db->nTotalChange; + + aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex); + *apIndex = aIndex; + if( !aIndex ){ + return SQLITE_NOMEM; + } + + memset(aIndex, 0, sizeof(struct Fts3Index) * nIndex); + if( zParam ){ + const char *p = zParam; + int i; + for(i=1; i=0 ); + if( nPrefix==0 ){ + nIndex--; + i--; + }else{ + aIndex[i].nPrefix = nPrefix; + } + p++; + } + } + + *pnIndex = nIndex; + return SQLITE_OK; } /* -** Close all open savepoints. This function only manipulates fields of the -** database handle object, it does not close any savepoints that may be open -** at the b-tree/pager level. +** This function is called when initializing an FTS4 table that uses the +** content=xxx option. It determines the number of and names of the columns +** of the new FTS4 table. +** +** The third argument passed to this function is the value passed to the +** config=xxx option (i.e. "xxx"). This function queries the database for +** a table of that name. If found, the output variables are populated +** as follows: +** +** *pnCol: Set to the number of columns table xxx has, +** +** *pnStr: Set to the total amount of space required to store a copy +** of each columns name, including the nul-terminator. +** +** *pazCol: Set to point to an array of *pnCol strings. Each string is +** the name of the corresponding column in table xxx. The array +** and its contents are allocated using a single allocation. It +** is the responsibility of the caller to free this allocation +** by eventually passing the *pazCol value to sqlite3_free(). +** +** If the table cannot be found, an error code is returned and the output +** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is +** returned (and the output variables are undefined). */ -SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){ - while( db->pSavepoint ){ - Savepoint *pTmp = db->pSavepoint; - db->pSavepoint = pTmp->pNext; - sqlite3DbFree(db, pTmp); +static int fts3ContentColumns( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */ + const char *zTbl, /* Name of content table */ + const char ***pazCol, /* OUT: Malloc'd array of column names */ + int *pnCol, /* OUT: Size of array *pazCol */ + int *pnStr, /* OUT: Bytes of string content */ + char **pzErr /* OUT: error message */ +){ + int rc = SQLITE_OK; /* Return code */ + char *zSql; /* "SELECT *" statement on zTbl */ + sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */ + + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db)); + } } - db->nSavepoint = 0; - db->nStatement = 0; - db->isTransactionSavepoint = 0; + sqlite3_free(zSql); + + if( rc==SQLITE_OK ){ + const char **azCol; /* Output array */ + sqlite3_int64 nStr = 0; /* Size of all column names (incl. 0x00) */ + int nCol; /* Number of table columns */ + int i; /* Used to iterate through columns */ + + /* Loop through the returned columns. Set nStr to the number of bytes of + ** space required to store a copy of each column name, including the + ** nul-terminator byte. */ + nCol = sqlite3_column_count(pStmt); + for(i=0; iu.pDestructor; - if( pDestructor ){ - pDestructor->nRef--; - if( pDestructor->nRef==0 ){ - pDestructor->xDestroy(pDestructor->pUserData); - sqlite3DbFree(db, pDestructor); +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the FTS3 virtual table. +** +** The argv[] array contains the following: +** +** argv[0] -> module name ("fts3" or "fts4") +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> "column name" and other module argument fields. +*/ +static int fts3InitVtab( + int isCreate, /* True for xCreate, false for xConnect */ + sqlite3 *db, /* The SQLite database connection */ + void *pAux, /* Hash table containing tokenizers */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ + char **pzErr /* Write any error message here */ +){ + Fts3Hash *pHash = &((Fts3HashWrapper*)pAux)->hash; + Fts3Table *p = 0; /* Pointer to allocated vtab */ + int rc = SQLITE_OK; /* Return code */ + int i; /* Iterator variable */ + sqlite3_int64 nByte; /* Size of allocation used for *p */ + int iCol; /* Column index */ + int nString = 0; /* Bytes required to hold all column names */ + int nCol = 0; /* Number of columns in the FTS table */ + char *zCsr; /* Space for holding column names */ + int nDb; /* Bytes required to hold database name */ + int nName; /* Bytes required to hold table name */ + int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */ + const char **aCol; /* Array of column names */ + sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */ + + int nIndex = 0; /* Size of aIndex[] array */ + struct Fts3Index *aIndex = 0; /* Array of indexes for this table */ + + /* The results of parsing supported FTS4 key=value options: */ + int bNoDocsize = 0; /* True to omit %_docsize table */ + int bDescIdx = 0; /* True to store descending indexes */ + char *zPrefix = 0; /* Prefix parameter value (or NULL) */ + char *zCompress = 0; /* compress=? parameter (or NULL) */ + char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ + char *zContent = 0; /* content=? parameter (or NULL) */ + char *zLanguageid = 0; /* languageid=? parameter (or NULL) */ + char **azNotindexed = 0; /* The set of notindexed= columns */ + int nNotindexed = 0; /* Size of azNotindexed[] array */ + + assert( strlen(argv[0])==4 ); + assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) + || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) + ); + + nDb = (int)strlen(argv[1]) + 1; + nName = (int)strlen(argv[2]) + 1; + + nByte = sizeof(const char *) * (argc-2); + aCol = (const char **)sqlite3_malloc64(nByte); + if( aCol ){ + memset((void*)aCol, 0, nByte); + azNotindexed = (char **)sqlite3_malloc64(nByte); + } + if( azNotindexed ){ + memset(azNotindexed, 0, nByte); + } + if( !aCol || !azNotindexed ){ + rc = SQLITE_NOMEM; + goto fts3_init_out; + } + + /* Loop through all of the arguments passed by the user to the FTS3/4 + ** module (i.e. all the column names and special arguments). This loop + ** does the following: + ** + ** + Figures out the number of columns the FTSX table will have, and + ** the number of bytes of space that must be allocated to store copies + ** of the column names. + ** + ** + If there is a tokenizer specification included in the arguments, + ** initializes the tokenizer pTokenizer. + */ + for(i=3; rc==SQLITE_OK && i8 + && 0==sqlite3_strnicmp(z, "tokenize", 8) + && 0==sqlite3Fts3IsIdChar(z[8]) + ){ + rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr); + } + + /* Check if it is an FTS4 special argument. */ + else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){ + struct Fts4Option { + const char *zOpt; + int nOpt; + } aFts4Opt[] = { + { "matchinfo", 9 }, /* 0 -> MATCHINFO */ + { "prefix", 6 }, /* 1 -> PREFIX */ + { "compress", 8 }, /* 2 -> COMPRESS */ + { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ + { "order", 5 }, /* 4 -> ORDER */ + { "content", 7 }, /* 5 -> CONTENT */ + { "languageid", 10 }, /* 6 -> LANGUAGEID */ + { "notindexed", 10 } /* 7 -> NOTINDEXED */ + }; + + int iOpt; + if( !zVal ){ + rc = SQLITE_NOMEM; + }else{ + for(iOpt=0; iOptnOpt && !sqlite3_strnicmp(z, pOp->zOpt, pOp->nOpt) ){ + break; + } + } + switch( iOpt ){ + case 0: /* MATCHINFO */ + if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){ + sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal); + rc = SQLITE_ERROR; + } + bNoDocsize = 1; + break; + + case 1: /* PREFIX */ + sqlite3_free(zPrefix); + zPrefix = zVal; + zVal = 0; + break; + + case 2: /* COMPRESS */ + sqlite3_free(zCompress); + zCompress = zVal; + zVal = 0; + break; + + case 3: /* UNCOMPRESS */ + sqlite3_free(zUncompress); + zUncompress = zVal; + zVal = 0; + break; + + case 4: /* ORDER */ + if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) + && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) + ){ + sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal); + rc = SQLITE_ERROR; + } + bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); + break; + + case 5: /* CONTENT */ + sqlite3_free(zContent); + zContent = zVal; + zVal = 0; + break; + + case 6: /* LANGUAGEID */ + assert( iOpt==6 ); + sqlite3_free(zLanguageid); + zLanguageid = zVal; + zVal = 0; + break; + + case 7: /* NOTINDEXED */ + azNotindexed[nNotindexed++] = zVal; + zVal = 0; + break; + + default: + assert( iOpt==SizeofArray(aFts4Opt) ); + sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z); + rc = SQLITE_ERROR; + break; + } + sqlite3_free(zVal); + } + } + + /* Otherwise, the argument is a column name. */ + else { + nString += (int)(strlen(z) + 1); + aCol[nCol++] = z; + } + } + + /* If a content=xxx option was specified, the following: + ** + ** 1. Ignore any compress= and uncompress= options. + ** + ** 2. If no column names were specified as part of the CREATE VIRTUAL + ** TABLE statement, use all columns from the content table. + */ + if( rc==SQLITE_OK && zContent ){ + sqlite3_free(zCompress); + sqlite3_free(zUncompress); + zCompress = 0; + zUncompress = 0; + if( nCol==0 ){ + sqlite3_free((void*)aCol); + aCol = 0; + rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr); + + /* If a languageid= option was specified, remove the language id + ** column from the aCol[] array. */ + if( rc==SQLITE_OK && zLanguageid ){ + int j; + for(j=0; jdb = db; + p->nColumn = nCol; + p->nPendingData = 0; + p->azColumn = (char **)&p[1]; + p->pTokenizer = pTokenizer; + p->nMaxPendingData = FTS3_MAX_PENDING_DATA; + p->bHasDocsize = (isFts4 && bNoDocsize==0); + p->bHasStat = (u8)isFts4; + p->bFts4 = (u8)isFts4; + p->bDescIdx = (u8)bDescIdx; + p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ + p->zContentTbl = zContent; + p->zLanguageid = zLanguageid; + zContent = 0; + zLanguageid = 0; + TESTONLY( p->inTransaction = -1 ); + TESTONLY( p->mxSavepoint = -1 ); + + p->aIndex = (struct Fts3Index *)&p->azColumn[nCol]; + memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex); + p->nIndex = nIndex; + for(i=0; iaIndex[i].hPending, FTS3_HASH_STRING, 1); + } + p->abNotindexed = (u8 *)&p->aIndex[nIndex]; + + /* Fill in the zName and zDb fields of the vtab structure. */ + zCsr = (char *)&p->abNotindexed[nCol]; + p->zName = zCsr; + memcpy(zCsr, argv[2], nName); + zCsr += nName; + p->zDb = zCsr; + memcpy(zCsr, argv[1], nDb); + zCsr += nDb; + + /* Fill in the azColumn array */ + for(iCol=0; iCol0 ){ + memcpy(zCsr, z, n); } + zCsr[n] = '\0'; + sqlite3Fts3Dequote(zCsr); + p->azColumn[iCol] = zCsr; + zCsr += n+1; + assert( zCsr <= &((char *)p)[nByte] ); } -} -/* -** Disconnect all sqlite3_vtab objects that belong to database connection -** db. This is called when db is being closed. -*/ -static void disconnectAllVtab(sqlite3 *db){ -#ifndef SQLITE_OMIT_VIRTUALTABLE - int i; - HashElem *p; - sqlite3BtreeEnterAll(db); - for(i=0; inDb; i++){ - Schema *pSchema = db->aDb[i].pSchema; - if( db->aDb[i].pSchema ){ - for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ - Table *pTab = (Table *)sqliteHashData(p); - if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); + /* Fill in the abNotindexed array */ + for(iCol=0; iColazColumn[iCol]); + for(i=0; iazColumn[iCol], zNot, n) + ){ + p->abNotindexed[iCol] = 1; + sqlite3_free(zNot); + azNotindexed[i] = 0; } } } - for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ - Module *pMod = (Module *)sqliteHashData(p); - if( pMod->pEpoTab ){ - sqlite3VtabDisconnect(db, pMod->pEpoTab); + for(i=0; imutex) ); - if( db->pVdbe ) return 1; - for(j=0; jnDb; j++){ - Btree *pBt = db->aDb[j].pBt; - if( pBt && sqlite3BtreeIsInBackup(pBt) ) return 1; - } - return 0; -} -/* -** Close an existing SQLite database -*/ -static int sqlite3Close(sqlite3 *db, int forceZombie){ - if( !db ){ - /* EVIDENCE-OF: R-63257-11740 Calling sqlite3_close() or - ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ - return SQLITE_OK; - } - if( !sqlite3SafetyCheckSickOrOk(db) ){ - return SQLITE_MISUSE_BKPT; - } - sqlite3_mutex_enter(db->mutex); - if( db->mTrace & SQLITE_TRACE_CLOSE ){ - db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); + if( rc==SQLITE_OK && (zCompress==0)!=(zUncompress==0) ){ + char const *zMiss = (zCompress==0 ? "compress" : "uncompress"); + rc = SQLITE_ERROR; + sqlite3Fts3ErrMsg(pzErr, "missing %s parameter in fts4 constructor", zMiss); } + p->zReadExprlist = fts3ReadExprList(p, zUncompress, &rc); + p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc); + if( rc!=SQLITE_OK ) goto fts3_init_out; - /* Force xDisconnect calls on all virtual tables */ - disconnectAllVtab(db); - - /* If a transaction is open, the disconnectAllVtab() call above - ** will not have called the xDisconnect() method on any virtual - ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() - ** call will do so. We need to do this before the check for active - ** SQL statements below, as the v-table implementation may be storing - ** some prepared statements internally. + /* If this is an xCreate call, create the underlying tables in the + ** database. TODO: For xConnect(), it could verify that said tables exist. */ - sqlite3VtabRollback(db); + if( isCreate ){ + rc = fts3CreateTables(p); + } - /* Legacy behavior (sqlite3_close() behavior) is to return - ** SQLITE_BUSY if the connection can not be closed immediately. + /* Check to see if a legacy fts3 table has been "upgraded" by the + ** addition of a %_stat table so that it can use incremental merge. */ - if( !forceZombie && connectionIsBusy(db) ){ - sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to close due to unfinalized " - "statements or unfinished backups"); - sqlite3_mutex_leave(db->mutex); - return SQLITE_BUSY; + if( !isFts4 && !isCreate ){ + p->bHasStat = 2; } -#ifdef SQLITE_ENABLE_SQLLOG - if( sqlite3GlobalConfig.xSqllog ){ - /* Closing the handle. Fourth parameter is passed the value 2. */ - sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2); - } + /* Figure out the page-size for the database. This is required in order to + ** estimate the cost of loading large doclists from the database. */ + fts3DatabasePageSize(&rc, p); + p->nNodeSize = p->nPgsz-35; + +#if defined(SQLITE_DEBUG)||defined(SQLITE_TEST) + p->nMergeCount = FTS3_MERGE_COUNT; #endif - /* Convert the connection into a zombie and then close it. - */ - db->magic = SQLITE_MAGIC_ZOMBIE; - sqlite3LeaveMutexAndCloseZombie(db); - return SQLITE_OK; + /* Declare the table schema to SQLite. */ + fts3DeclareVtab(&rc, p); + +fts3_init_out: + sqlite3_free(zPrefix); + sqlite3_free(aIndex); + sqlite3_free(zCompress); + sqlite3_free(zUncompress); + sqlite3_free(zContent); + sqlite3_free(zLanguageid); + for(i=0; ipModule->xDestroy(pTokenizer); + } + }else{ + assert( p->pSegments==0 ); + *ppVTab = &p->base; + } + return rc; } /* -** Two variations on the public interface for closing a database -** connection. The sqlite3_close() version returns SQLITE_BUSY and -** leaves the connection option if there are unfinalized prepared -** statements or unfinished sqlite3_backups. The sqlite3_close_v2() -** version forces the connection to become a zombie if there are -** unclosed resources, and arranges for deallocation when the last -** prepare statement or sqlite3_backup closes. +** The xConnect() and xCreate() methods for the virtual table. All the +** work is done in function fts3InitVtab(). */ -SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } -SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } - +static int fts3ConnectMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts3InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr); +} +static int fts3CreateMethod( + sqlite3 *db, /* Database connection */ + void *pAux, /* Pointer to tokenizer hash table */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ +){ + return fts3InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); +} /* -** Close the mutex on database connection db. -** -** Furthermore, if database connection db is a zombie (meaning that there -** has been a prior call to sqlite3_close(db) or sqlite3_close_v2(db)) and -** every sqlite3_stmt has now been finalized and every sqlite3_backup has -** finished, then free all resources. +** Set the pIdxInfo->estimatedRows variable to nRow. Unless this +** extension is currently being used by a version of SQLite too old to +** support estimatedRows. In that case this function is a no-op. */ -SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){ - HashElem *i; /* Hash table iterator */ - int j; - - /* If there are outstanding sqlite3_stmt or sqlite3_backup objects - ** or if the connection has not yet been closed by sqlite3_close_v2(), - ** then just leave the mutex and return. - */ - if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){ - sqlite3_mutex_leave(db->mutex); - return; +static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ +#if SQLITE_VERSION_NUMBER>=3008002 + if( sqlite3_libversion_number()>=3008002 ){ + pIdxInfo->estimatedRows = nRow; } +#endif +} - /* If we reach this point, it means that the database connection has - ** closed all sqlite3_stmt and sqlite3_backup objects and has been - ** passed to sqlite3_close (meaning that it is a zombie). Therefore, - ** go ahead and free all resources. - */ +/* +** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this +** extension is currently being used by a version of SQLite too old to +** support index-info flags. In that case this function is a no-op. +*/ +static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){ +#if SQLITE_VERSION_NUMBER>=3008012 + if( sqlite3_libversion_number()>=3008012 ){ + pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; + } +#endif +} - /* If a transaction is open, roll it back. This also ensures that if - ** any database schemas have been modified by an uncommitted transaction - ** they are reset. And that the required b-tree mutex is held to make - ** the pager rollback and schema reset an atomic operation. */ - sqlite3RollbackAll(db, SQLITE_OK); +/* +** Implementation of the xBestIndex method for FTS3 tables. There +** are three possible strategies, in order of preference: +** +** 1. Direct lookup by rowid or docid. +** 2. Full-text search using a MATCH operator on a non-docid column. +** 3. Linear scan of %_content table. +*/ +static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ + Fts3Table *p = (Fts3Table *)pVTab; + int i; /* Iterator variable */ + int iCons = -1; /* Index of constraint to use */ - /* Free any outstanding Savepoint structures. */ - sqlite3CloseSavepoints(db); + int iLangidCons = -1; /* Index of langid=x constraint, if present */ + int iDocidGe = -1; /* Index of docid>=x constraint, if present */ + int iDocidLe = -1; /* Index of docid<=x constraint, if present */ + int iIdx; - /* Close all database connections */ - for(j=0; jnDb; j++){ - struct Db *pDb = &db->aDb[j]; - if( pDb->pBt ){ - sqlite3BtreeClose(pDb->pBt); - pDb->pBt = 0; - if( j!=1 ){ - pDb->pSchema = 0; - } - } - } - /* Clear the TEMP schema separately and last */ - if( db->aDb[1].pSchema ){ - sqlite3SchemaClear(db->aDb[1].pSchema); + if( p->bLock ){ + return SQLITE_ERROR; } - sqlite3VtabUnlockList(db); - - /* Free up the array of auxiliary databases */ - sqlite3CollapseDatabaseArray(db); - assert( db->nDb<=2 ); - assert( db->aDb==db->aDbStatic ); - /* Tell the code in notify.c that the connection no longer holds any - ** locks and does not require any further unlock-notify callbacks. + /* By default use a full table scan. This is an expensive option, + ** so search through the constraints to see if a more efficient + ** strategy is possible. */ - sqlite3ConnectionClosed(db); - - for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ - FuncDef *pNext, *p; - p = sqliteHashData(i); - do{ - functionDestroy(db, p); - pNext = p->pNext; - sqlite3DbFree(db, p); - p = pNext; - }while( p ); - } - sqlite3HashClear(&db->aFunc); - for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ - CollSeq *pColl = (CollSeq *)sqliteHashData(i); - /* Invoke any destructors registered for collation sequence user data. */ - for(j=0; j<3; j++){ - if( pColl[j].xDel ){ - pColl[j].xDel(pColl[j].pUser); + pInfo->idxNum = FTS3_FULLSCAN_SEARCH; + pInfo->estimatedCost = 5000000; + for(i=0; inConstraint; i++){ + int bDocid; /* True if this constraint is on docid */ + struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; + if( pCons->usable==0 ){ + if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ + /* There exists an unusable MATCH constraint. This means that if + ** the planner does elect to use the results of this call as part + ** of the overall query plan the user will see an "unable to use + ** function MATCH in the requested context" error. To discourage + ** this, return a very high cost here. */ + pInfo->idxNum = FTS3_FULLSCAN_SEARCH; + pInfo->estimatedCost = 1e50; + fts3SetEstimatedRows(pInfo, ((sqlite3_int64)1) << 50); + return SQLITE_OK; } + continue; } - sqlite3DbFree(db, pColl); - } - sqlite3HashClear(&db->aCollSeq); -#ifndef SQLITE_OMIT_VIRTUALTABLE - for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ - Module *pMod = (Module *)sqliteHashData(i); - if( pMod->xDestroy ){ - pMod->xDestroy(pMod->pAux); - } - sqlite3VtabEponymousTableClear(db, pMod); - sqlite3DbFree(db, pMod); - } - sqlite3HashClear(&db->aModule); -#endif - sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ - sqlite3ValueFree(db->pErr); - sqlite3CloseExtensions(db); -#if SQLITE_USER_AUTHENTICATION - sqlite3_free(db->auth.zAuthUser); - sqlite3_free(db->auth.zAuthPW); -#endif + bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1); - db->magic = SQLITE_MAGIC_ERROR; + /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */ + if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){ + pInfo->idxNum = FTS3_DOCID_SEARCH; + pInfo->estimatedCost = 1.0; + iCons = i; + } - /* The temp-database schema is allocated differently from the other schema - ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). - ** So it needs to be freed here. Todo: Why not roll the temp schema into - ** the same sqliteMalloc() as the one that allocates the database - ** structure? - */ - sqlite3DbFree(db, db->aDb[1].pSchema); - sqlite3_mutex_leave(db->mutex); - db->magic = SQLITE_MAGIC_CLOSED; - sqlite3_mutex_free(db->mutex); - assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */ - if( db->lookaside.bMalloced ){ - sqlite3_free(db->lookaside.pStart); - } - sqlite3_free(db); -} + /* A MATCH constraint. Use a full-text search. + ** + ** If there is more than one MATCH constraint available, use the first + ** one encountered. If there is both a MATCH constraint and a direct + ** rowid/docid lookup, prefer the MATCH strategy. This is done even + ** though the rowid/docid lookup is faster than a MATCH query, selecting + ** it would lead to an "unable to use function MATCH in the requested + ** context" error. + */ + if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH + && pCons->iColumn>=0 && pCons->iColumn<=p->nColumn + ){ + pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn; + pInfo->estimatedCost = 2.0; + iCons = i; + } -/* -** Rollback all database files. If tripCode is not SQLITE_OK, then -** any write cursors are invalidated ("tripped" - as in "tripping a circuit -** breaker") and made to return tripCode if there are any further -** attempts to use that cursor. Read cursors remain open and valid -** but are "saved" in case the table pages are moved around. -*/ -SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ - int i; - int inTrans = 0; - int schemaChange; - assert( sqlite3_mutex_held(db->mutex) ); - sqlite3BeginBenignMalloc(); + /* Equality constraint on the langid column */ + if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ + && pCons->iColumn==p->nColumn + 2 + ){ + iLangidCons = i; + } - /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). - ** This is important in case the transaction being rolled back has - ** modified the database schema. If the b-tree mutexes are not taken - ** here, then another shared-cache connection might sneak in between - ** the database rollback and schema reset, which can cause false - ** corruption reports in some cases. */ - sqlite3BtreeEnterAll(db); - schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0; + if( bDocid ){ + switch( pCons->op ){ + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_GT: + iDocidGe = i; + break; - for(i=0; inDb; i++){ - Btree *p = db->aDb[i].pBt; - if( p ){ - if( sqlite3BtreeIsInTrans(p) ){ - inTrans = 1; + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + iDocidLe = i; + break; } - sqlite3BtreeRollback(p, tripCode, !schemaChange); } } - sqlite3VtabRollback(db); - sqlite3EndBenignMalloc(); - - if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ - sqlite3ExpirePreparedStatements(db); - sqlite3ResetAllSchemasOfConnection(db); - } - sqlite3BtreeLeaveAll(db); - /* Any deferred constraint violations have now been resolved. */ - db->nDeferredCons = 0; - db->nDeferredImmCons = 0; - db->flags &= ~SQLITE_DeferFKs; + /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */ + if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo); - /* If one has been configured, invoke the rollback-hook callback */ - if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ - db->xRollbackCallback(db->pRollbackArg); + iIdx = 1; + if( iCons>=0 ){ + pInfo->aConstraintUsage[iCons].argvIndex = iIdx++; + pInfo->aConstraintUsage[iCons].omit = 1; } -} - -/* -** Return a static string containing the name corresponding to the error code -** specified in the argument. -*/ -#if defined(SQLITE_NEED_ERR_NAME) -SQLITE_PRIVATE const char *sqlite3ErrName(int rc){ - const char *zName = 0; - int i, origRc = rc; - for(i=0; i<2 && zName==0; i++, rc &= 0xff){ - switch( rc ){ - case SQLITE_OK: zName = "SQLITE_OK"; break; - case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; - case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; - case SQLITE_PERM: zName = "SQLITE_PERM"; break; - case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; - case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; - case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; - case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; - case SQLITE_BUSY_SNAPSHOT: zName = "SQLITE_BUSY_SNAPSHOT"; break; - case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; - case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; - case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; - case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; - case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; - case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break; - case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break; - case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break; - case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; - case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; - case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break; - case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break; - case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break; - case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break; - case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break; - case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break; - case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break; - case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; - case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; - case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; - case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; - case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; - case SQLITE_IOERR_CHECKRESERVEDLOCK: - zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; - case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; - case SQLITE_IOERR_CLOSE: zName = "SQLITE_IOERR_CLOSE"; break; - case SQLITE_IOERR_DIR_CLOSE: zName = "SQLITE_IOERR_DIR_CLOSE"; break; - case SQLITE_IOERR_SHMOPEN: zName = "SQLITE_IOERR_SHMOPEN"; break; - case SQLITE_IOERR_SHMSIZE: zName = "SQLITE_IOERR_SHMSIZE"; break; - case SQLITE_IOERR_SHMLOCK: zName = "SQLITE_IOERR_SHMLOCK"; break; - case SQLITE_IOERR_SHMMAP: zName = "SQLITE_IOERR_SHMMAP"; break; - case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break; - case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break; - case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break; - case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break; - case SQLITE_IOERR_CONVPATH: zName = "SQLITE_IOERR_CONVPATH"; break; - case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; - case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; - case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; - case SQLITE_FULL: zName = "SQLITE_FULL"; break; - case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; - case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break; - case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break; - case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break; - case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break; - case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; - case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; - case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; - case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; - case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; - case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break; - case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break; - case SQLITE_CONSTRAINT_FOREIGNKEY: - zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break; - case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break; - case SQLITE_CONSTRAINT_PRIMARYKEY: - zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break; - case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break; - case SQLITE_CONSTRAINT_COMMITHOOK: - zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break; - case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break; - case SQLITE_CONSTRAINT_FUNCTION: - zName = "SQLITE_CONSTRAINT_FUNCTION"; break; - case SQLITE_CONSTRAINT_ROWID: zName = "SQLITE_CONSTRAINT_ROWID"; break; - case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; - case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; - case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; - case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; - case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; - case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; - case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; - case SQLITE_ROW: zName = "SQLITE_ROW"; break; - case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; - case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; - case SQLITE_NOTICE_RECOVER_ROLLBACK: - zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; - case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; - case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; - case SQLITE_DONE: zName = "SQLITE_DONE"; break; - } + if( iLangidCons>=0 ){ + pInfo->idxNum |= FTS3_HAVE_LANGID; + pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++; } - if( zName==0 ){ - static char zBuf[50]; - sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc); - zName = zBuf; + if( iDocidGe>=0 ){ + pInfo->idxNum |= FTS3_HAVE_DOCID_GE; + pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++; + } + if( iDocidLe>=0 ){ + pInfo->idxNum |= FTS3_HAVE_DOCID_LE; + pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++; } - return zName; -} -#endif -/* -** Return a static string that describes the kind of error specified in the -** argument. -*/ -SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ - static const char* const aMsg[] = { - /* SQLITE_OK */ "not an error", - /* SQLITE_ERROR */ "SQL logic error or missing database", - /* SQLITE_INTERNAL */ 0, - /* SQLITE_PERM */ "access permission denied", - /* SQLITE_ABORT */ "callback requested query abort", - /* SQLITE_BUSY */ "database is locked", - /* SQLITE_LOCKED */ "database table is locked", - /* SQLITE_NOMEM */ "out of memory", - /* SQLITE_READONLY */ "attempt to write a readonly database", - /* SQLITE_INTERRUPT */ "interrupted", - /* SQLITE_IOERR */ "disk I/O error", - /* SQLITE_CORRUPT */ "database disk image is malformed", - /* SQLITE_NOTFOUND */ "unknown operation", - /* SQLITE_FULL */ "database or disk is full", - /* SQLITE_CANTOPEN */ "unable to open database file", - /* SQLITE_PROTOCOL */ "locking protocol", - /* SQLITE_EMPTY */ "table contains no data", - /* SQLITE_SCHEMA */ "database schema has changed", - /* SQLITE_TOOBIG */ "string or blob too big", - /* SQLITE_CONSTRAINT */ "constraint failed", - /* SQLITE_MISMATCH */ "datatype mismatch", - /* SQLITE_MISUSE */ "library routine called out of sequence", - /* SQLITE_NOLFS */ "large file support is disabled", - /* SQLITE_AUTH */ "authorization denied", - /* SQLITE_FORMAT */ "auxiliary database format error", - /* SQLITE_RANGE */ "bind or column index out of range", - /* SQLITE_NOTADB */ "file is encrypted or is not a database", - }; - const char *zErr = "unknown error"; - switch( rc ){ - case SQLITE_ABORT_ROLLBACK: { - zErr = "abort due to ROLLBACK"; - break; - } - default: { - rc &= 0xff; - if( ALWAYS(rc>=0) && rcnOrderBy==1 ){ + struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0]; + if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){ + if( pOrder->desc ){ + pInfo->idxStr = "DESC"; + }else{ + pInfo->idxStr = "ASC"; } - break; + pInfo->orderByConsumed = 1; } } - return zErr; + + assert( p->pSegments==0 ); + return SQLITE_OK; } /* -** This routine implements a busy callback that sleeps and tries -** again until a timeout value is reached. The timeout value is -** an integer number of milliseconds passed in as the first -** argument. +** Implementation of xOpen method. */ -static int sqliteDefaultBusyCallback( - void *ptr, /* Database connection */ - int count /* Number of times table has been busy */ -){ -#if SQLITE_OS_WIN || HAVE_USLEEP - static const u8 delays[] = - { 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 }; - static const u8 totals[] = - { 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 }; -# define NDELAY ArraySize(delays) - sqlite3 *db = (sqlite3 *)ptr; - int timeout = db->busyTimeout; - int delay, prior; +static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + sqlite3_vtab_cursor *pCsr; /* Allocated cursor */ - assert( count>=0 ); - if( count < NDELAY ){ - delay = delays[count]; - prior = totals[count]; - }else{ - delay = delays[NDELAY-1]; - prior = totals[NDELAY-1] + delay*(count-(NDELAY-1)); - } - if( prior + delay > timeout ){ - delay = timeout - prior; - if( delay<=0 ) return 0; - } - sqlite3OsSleep(db->pVfs, delay*1000); - return 1; -#else - sqlite3 *db = (sqlite3 *)ptr; - int timeout = ((sqlite3 *)ptr)->busyTimeout; - if( (count+1)*1000 > timeout ){ - return 0; + UNUSED_PARAMETER(pVTab); + + /* Allocate a buffer large enough for an Fts3Cursor structure. If the + ** allocation succeeds, zero it and return SQLITE_OK. Otherwise, + ** if the allocation fails, return SQLITE_NOMEM. + */ + *ppCsr = pCsr = (sqlite3_vtab_cursor *)sqlite3_malloc(sizeof(Fts3Cursor)); + if( !pCsr ){ + return SQLITE_NOMEM; } - sqlite3OsSleep(db->pVfs, 1000000); - return 1; -#endif + memset(pCsr, 0, sizeof(Fts3Cursor)); + return SQLITE_OK; } /* -** Invoke the given busy handler. +** Finalize the statement handle at pCsr->pStmt. ** -** This routine is called when an operation failed with a lock. -** If this routine returns non-zero, the lock is retried. If it -** returns 0, the operation aborts with an SQLITE_BUSY error. +** Or, if that statement handle is one created by fts3CursorSeekStmt(), +** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement +** pointer there instead of finalizing it. */ -SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){ - int rc; - if( NEVER(p==0) || p->xFunc==0 || p->nBusy<0 ) return 0; - rc = p->xFunc(p->pArg, p->nBusy); - if( rc==0 ){ - p->nBusy = -1; - }else{ - p->nBusy++; +static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){ + if( pCsr->bSeekStmt ){ + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + if( p->pSeekStmt==0 ){ + p->pSeekStmt = pCsr->pStmt; + sqlite3_reset(pCsr->pStmt); + pCsr->pStmt = 0; + } + pCsr->bSeekStmt = 0; } - return rc; + sqlite3_finalize(pCsr->pStmt); } /* -** This routine sets the busy callback for an Sqlite database to the -** given callback function with the given argument. +** Free all resources currently held by the cursor passed as the only +** argument. */ -SQLITE_API int sqlite3_busy_handler( - sqlite3 *db, - int (*xBusy)(void*,int), - void *pArg -){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - db->busyHandler.xFunc = xBusy; - db->busyHandler.pArg = pArg; - db->busyHandler.nBusy = 0; - db->busyTimeout = 0; - sqlite3_mutex_leave(db->mutex); - return SQLITE_OK; +static void fts3ClearCursor(Fts3Cursor *pCsr){ + fts3CursorFinalizeStmt(pCsr); + sqlite3Fts3FreeDeferredTokens(pCsr); + sqlite3_free(pCsr->aDoclist); + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + sqlite3Fts3ExprFree(pCsr->pExpr); + memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); } -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* -** This routine sets the progress callback for an Sqlite database to the -** given callback function with the given argument. The progress callback will -** be invoked every nOps opcodes. +** Close the cursor. For additional information see the documentation +** on the xClose method of the virtual table interface. */ -SQLITE_API void sqlite3_progress_handler( - sqlite3 *db, - int nOps, - int (*xProgress)(void*), - void *pArg -){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return; - } -#endif - sqlite3_mutex_enter(db->mutex); - if( nOps>0 ){ - db->xProgress = xProgress; - db->nProgressOps = (unsigned)nOps; - db->pProgressArg = pArg; - }else{ - db->xProgress = 0; - db->nProgressOps = 0; - db->pProgressArg = 0; - } - sqlite3_mutex_leave(db->mutex); +static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + fts3ClearCursor(pCsr); + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + sqlite3_free(pCsr); + return SQLITE_OK; } -#endif - /* -** This routine installs a default busy handler that waits for the -** specified number of milliseconds before returning 0. +** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then +** compose and prepare an SQL statement of the form: +** +** "SELECT FROM %_content WHERE rowid = ?" +** +** (or the equivalent for a content=xxx table) and set pCsr->pStmt to +** it. If an error occurs, return an SQLite error code. */ -SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - if( ms>0 ){ - sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db); - db->busyTimeout = ms; - }else{ - sqlite3_busy_handler(db, 0, 0); +static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ + int rc = SQLITE_OK; + if( pCsr->pStmt==0 ){ + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + char *zSql; + if( p->pSeekStmt ){ + pCsr->pStmt = p->pSeekStmt; + p->pSeekStmt = 0; + }else{ + zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); + if( !zSql ) return SQLITE_NOMEM; + p->bLock++; + rc = sqlite3_prepare_v3( + p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 + ); + p->bLock--; + sqlite3_free(zSql); + } + if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1; } - return SQLITE_OK; + return rc; } /* -** Cause any pending operation to stop at its earliest opportunity. +** Position the pCsr->pStmt statement so that it is on the row +** of the %_content table that contains the last match. Return +** SQLITE_OK on success. */ -SQLITE_API void sqlite3_interrupt(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){ - (void)SQLITE_MISUSE_BKPT; - return; +static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ + int rc = SQLITE_OK; + if( pCsr->isRequireSeek ){ + rc = fts3CursorSeekStmt(pCsr); + if( rc==SQLITE_OK ){ + Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab; + pTab->bLock++; + sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); + pCsr->isRequireSeek = 0; + if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ + pTab->bLock--; + return SQLITE_OK; + }else{ + pTab->bLock--; + rc = sqlite3_reset(pCsr->pStmt); + if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ + /* If no row was found and no error has occurred, then the %_content + ** table is missing a row that is present in the full-text index. + ** The data structures are corrupt. */ + rc = FTS_CORRUPT_VTAB; + pCsr->isEof = 1; + } + } + } } -#endif - db->u1.isInterrupted = 1; -} + if( rc!=SQLITE_OK && pContext ){ + sqlite3_result_error_code(pContext, rc); + } + return rc; +} /* -** This function is exactly the same as sqlite3_create_function(), except -** that it is designed to be called by internal code. The difference is -** that if a malloc() fails in sqlite3_create_function(), an error code -** is returned and the mallocFailed flag cleared. +** This function is used to process a single interior node when searching +** a b-tree for a term or term prefix. The node data is passed to this +** function via the zNode/nNode parameters. The term to search for is +** passed in zTerm/nTerm. +** +** If piFirst is not NULL, then this function sets *piFirst to the blockid +** of the child node that heads the sub-tree that may contain the term. +** +** If piLast is not NULL, then *piLast is set to the right-most child node +** that heads a sub-tree that may contain a term for which zTerm/nTerm is +** a prefix. +** +** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK. */ -SQLITE_PRIVATE int sqlite3CreateFunc( - sqlite3 *db, - const char *zFunctionName, - int nArg, - int enc, - void *pUserData, - void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), - void (*xStep)(sqlite3_context*,int,sqlite3_value **), - void (*xFinal)(sqlite3_context*), - FuncDestructor *pDestructor +static int fts3ScanInteriorNode( + const char *zTerm, /* Term to select leaves for */ + int nTerm, /* Size of term zTerm in bytes */ + const char *zNode, /* Buffer containing segment interior node */ + int nNode, /* Size of buffer at zNode */ + sqlite3_int64 *piFirst, /* OUT: Selected child node */ + sqlite3_int64 *piLast /* OUT: Selected child node */ ){ - FuncDef *p; - int nName; - int extraFlags; - - assert( sqlite3_mutex_held(db->mutex) ); - if( zFunctionName==0 || - (xSFunc && (xFinal || xStep)) || - (!xSFunc && (xFinal && !xStep)) || - (!xSFunc && (!xFinal && xStep)) || - (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || - (255<(nName = sqlite3Strlen30( zFunctionName))) ){ - return SQLITE_MISUSE_BKPT; - } + int rc = SQLITE_OK; /* Return code */ + const char *zCsr = zNode; /* Cursor to iterate through node */ + const char *zEnd = &zCsr[nNode];/* End of interior node buffer */ + char *zBuffer = 0; /* Buffer to load terms into */ + i64 nAlloc = 0; /* Size of allocated buffer */ + int isFirstTerm = 1; /* True when processing first term on page */ + u64 iChild; /* Block id of child node to descend to */ + int nBuffer = 0; /* Total term size */ - assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); - extraFlags = enc & SQLITE_DETERMINISTIC; - enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); - -#ifndef SQLITE_OMIT_UTF16 - /* If SQLITE_UTF16 is specified as the encoding type, transform this - ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the - ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + /* Skip over the 'height' varint that occurs at the start of every + ** interior node. Then load the blockid of the left-child of the b-tree + ** node into variable iChild. ** - ** If SQLITE_ANY is specified, add three versions of the function - ** to the hash table. + ** Even if the data structure on disk is corrupted, this (reading two + ** varints from the buffer) does not risk an overread. If zNode is a + ** root node, then the buffer comes from a SELECT statement. SQLite does + ** not make this guarantee explicitly, but in practice there are always + ** either more than 20 bytes of allocated space following the nNode bytes of + ** contents, or two zero bytes. Or, if the node is read from the %_segments + ** table, then there are always 20 bytes of zeroed padding following the + ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). */ - if( enc==SQLITE_UTF16 ){ - enc = SQLITE_UTF16NATIVE; - }else if( enc==SQLITE_ANY ){ - int rc; - rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags, - pUserData, xSFunc, xStep, xFinal, pDestructor); - if( rc==SQLITE_OK ){ - rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags, - pUserData, xSFunc, xStep, xFinal, pDestructor); + zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); + zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); + if( zCsr>zEnd ){ + return FTS_CORRUPT_VTAB; + } + + while( zCsrnBuffer ){ + rc = FTS_CORRUPT_VTAB; + goto finish_scan; + } } - if( rc!=SQLITE_OK ){ - return rc; + isFirstTerm = 0; + zCsr += fts3GetVarint32(zCsr, &nSuffix); + + assert( nPrefix>=0 && nSuffix>=0 ); + if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){ + rc = FTS_CORRUPT_VTAB; + goto finish_scan; } - enc = SQLITE_UTF16BE; - } -#else - enc = SQLITE_UTF8; -#endif - - /* Check if an existing function is being overridden or deleted. If so, - ** and there are active VMs, then return SQLITE_BUSY. If a function - ** is being overridden/deleted but there are no active VMs, allow the - ** operation to continue but invalidate all precompiled statements. - */ - p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0); - if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){ - if( db->nVdbeActive ){ - sqlite3ErrorWithMsg(db, SQLITE_BUSY, - "unable to delete/modify user-function due to active statements"); - assert( !db->mallocFailed ); - return SQLITE_BUSY; - }else{ - sqlite3ExpirePreparedStatements(db); + if( (i64)nPrefix+nSuffix>nAlloc ){ + char *zNew; + nAlloc = ((i64)nPrefix+nSuffix) * 2; + zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc); + if( !zNew ){ + rc = SQLITE_NOMEM; + goto finish_scan; + } + zBuffer = zNew; } - } + assert( zBuffer ); + memcpy(&zBuffer[nPrefix], zCsr, nSuffix); + nBuffer = nPrefix + nSuffix; + zCsr += nSuffix; - p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); - assert(p || db->mallocFailed); - if( !p ){ - return SQLITE_NOMEM_BKPT; - } + /* Compare the term we are searching for with the term just loaded from + ** the interior node. If the specified term is greater than or equal + ** to the term from the interior node, then all terms on the sub-tree + ** headed by node iChild are smaller than zTerm. No need to search + ** iChild. + ** + ** If the interior node term is larger than the specified term, then + ** the tree headed by iChild may contain the specified term. + */ + cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); + if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ + *piFirst = (i64)iChild; + piFirst = 0; + } - /* If an older version of the function with a configured destructor is - ** being replaced invoke the destructor function here. */ - functionDestroy(db, p); + if( piLast && cmp<0 ){ + *piLast = (i64)iChild; + piLast = 0; + } - if( pDestructor ){ - pDestructor->nRef++; - } - p->u.pDestructor = pDestructor; - p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags; - testcase( p->funcFlags & SQLITE_DETERMINISTIC ); - p->xSFunc = xSFunc ? xSFunc : xStep; - p->xFinalize = xFinal; - p->pUserData = pUserData; - p->nArg = (u16)nArg; - return SQLITE_OK; + iChild++; + }; + + if( piFirst ) *piFirst = (i64)iChild; + if( piLast ) *piLast = (i64)iChild; + + finish_scan: + sqlite3_free(zBuffer); + return rc; } + /* -** Create new user functions. +** The buffer pointed to by argument zNode (size nNode bytes) contains an +** interior node of a b-tree segment. The zTerm buffer (size nTerm bytes) +** contains a term. This function searches the sub-tree headed by the zNode +** node for the range of leaf nodes that may contain the specified term +** or terms for which the specified term is a prefix. +** +** If piLeaf is not NULL, then *piLeaf is set to the blockid of the +** left-most leaf node in the tree that may contain the specified term. +** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the +** right-most leaf node that may contain a term for which the specified +** term is a prefix. +** +** It is possible that the range of returned leaf nodes does not contain +** the specified term or any terms for which it is a prefix. However, if the +** segment does contain any such terms, they are stored within the identified +** range. Because this function only inspects interior segment nodes (and +** never loads leaf nodes into memory), it is not possible to be sure. +** +** If an error occurs, an error code other than SQLITE_OK is returned. */ -SQLITE_API int sqlite3_create_function( - sqlite3 *db, - const char *zFunc, - int nArg, - int enc, - void *p, - void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), - void (*xStep)(sqlite3_context*,int,sqlite3_value **), - void (*xFinal)(sqlite3_context*) +static int fts3SelectLeaf( + Fts3Table *p, /* Virtual table handle */ + const char *zTerm, /* Term to select leaves for */ + int nTerm, /* Size of term zTerm in bytes */ + const char *zNode, /* Buffer containing segment interior node */ + int nNode, /* Size of buffer at zNode */ + sqlite3_int64 *piLeaf, /* Selected leaf node */ + sqlite3_int64 *piLeaf2 /* Selected leaf node */ ){ - return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep, - xFinal, 0); -} + int rc = SQLITE_OK; /* Return code */ + int iHeight; /* Height of this node in tree */ -SQLITE_API int sqlite3_create_function_v2( - sqlite3 *db, - const char *zFunc, - int nArg, - int enc, - void *p, - void (*xSFunc)(sqlite3_context*,int,sqlite3_value **), - void (*xStep)(sqlite3_context*,int,sqlite3_value **), - void (*xFinal)(sqlite3_context*), - void (*xDestroy)(void *) -){ - int rc = SQLITE_ERROR; - FuncDestructor *pArg = 0; + assert( piLeaf || piLeaf2 ); -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - return SQLITE_MISUSE_BKPT; - } -#endif - sqlite3_mutex_enter(db->mutex); - if( xDestroy ){ - pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor)); - if( !pArg ){ - xDestroy(p); - goto out; + fts3GetVarint32(zNode, &iHeight); + rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); + assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) ); + + if( rc==SQLITE_OK && iHeight>1 ){ + char *zBlob = 0; /* Blob read from %_segments table */ + int nBlob = 0; /* Size of zBlob in bytes */ + + if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){ + rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0); + if( rc==SQLITE_OK ){ + rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0); + } + sqlite3_free(zBlob); + piLeaf = 0; + zBlob = 0; + } + + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0); + } + if( rc==SQLITE_OK ){ + int iNewHeight = 0; + fts3GetVarint32(zBlob, &iNewHeight); + if( iNewHeight>=iHeight ){ + rc = FTS_CORRUPT_VTAB; + }else{ + rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2); + } } - pArg->xDestroy = xDestroy; - pArg->pUserData = p; - } - rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg); - if( pArg && pArg->nRef==0 ){ - assert( rc!=SQLITE_OK ); - xDestroy(p); - sqlite3DbFree(db, pArg); + sqlite3_free(zBlob); } - out: - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); return rc; } -#ifndef SQLITE_OMIT_UTF16 -SQLITE_API int sqlite3_create_function16( - sqlite3 *db, - const void *zFunctionName, - int nArg, - int eTextRep, - void *p, - void (*xSFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*) +/* +** This function is used to create delta-encoded serialized lists of FTS3 +** varints. Each call to this function appends a single varint to a list. +*/ +static void fts3PutDeltaVarint( + char **pp, /* IN/OUT: Output pointer */ + sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ + sqlite3_int64 iVal /* Write this value to the list */ ){ - int rc; - char *zFunc8; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zFunctionName==0 ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - assert( !db->mallocFailed ); - zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE); - rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0); - sqlite3DbFree(db, zFunc8); - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); - return rc; + assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); + *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); + *piPrev = iVal; } -#endif - /* -** Declare that a function has been overloaded by a virtual table. +** When this function is called, *ppPoslist is assumed to point to the +** start of a position-list. After it returns, *ppPoslist points to the +** first byte after the position-list. ** -** If the function already exists as a regular global function, then -** this routine is a no-op. If the function does not exist, then create -** a new one that always throws a run-time error. +** A position list is list of positions (delta encoded) and columns for +** a single document record of a doclist. So, in other words, this +** routine advances *ppPoslist so that it points to the next docid in +** the doclist, or to the first byte past the end of the doclist. ** -** When virtual tables intend to provide an overloaded function, they -** should call this routine to make sure the global function exists. -** A global function must exist in order for name resolution to work -** properly. +** If pp is not NULL, then the contents of the position list are copied +** to *pp. *pp is set to point to the first byte past the last byte copied +** before this function returns. */ -SQLITE_API int sqlite3_overload_function( - sqlite3 *db, - const char *zName, - int nArg -){ - int rc = SQLITE_OK; +static void fts3PoslistCopy(char **pp, char **ppPoslist){ + char *pEnd = *ppPoslist; + char c = 0; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){ - return SQLITE_MISUSE_BKPT; + /* The end of a position list is marked by a zero encoded as an FTS3 + ** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by + ** a byte with the 0x80 bit set, then it is not a varint 0, but the tail + ** of some other, multi-byte, value. + ** + ** The following while-loop moves pEnd to point to the first byte that is not + ** immediately preceded by a byte with the 0x80 bit set. Then increments + ** pEnd once more so that it points to the byte immediately following the + ** last byte in the position-list. + */ + while( *pEnd | c ){ + c = *pEnd++ & 0x80; + testcase( c!=0 && (*pEnd)==0 ); } -#endif - sqlite3_mutex_enter(db->mutex); - if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){ - rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8, - 0, sqlite3InvalidFunction, 0, 0, 0); + pEnd++; /* Advance past the POS_END terminator byte */ + + if( pp ){ + int n = (int)(pEnd - *ppPoslist); + char *p = *pp; + memcpy(p, *ppPoslist, n); + p += n; + *pp = p; } - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); - return rc; + *ppPoslist = pEnd; } -#ifndef SQLITE_OMIT_TRACE /* -** Register a trace function. The pArg from the previously registered trace -** is returned. +** When this function is called, *ppPoslist is assumed to point to the +** start of a column-list. After it returns, *ppPoslist points to the +** to the terminator (POS_COLUMN or POS_END) byte of the column-list. ** -** A NULL trace function means that no tracing is executes. A non-NULL -** trace is a pointer to a function that is invoked at the start of each -** SQL statement. +** A column-list is list of delta-encoded positions for a single column +** within a single document within a doclist. +** +** The column-list is terminated either by a POS_COLUMN varint (1) or +** a POS_END varint (0). This routine leaves *ppPoslist pointing to +** the POS_COLUMN or POS_END that terminates the column-list. +** +** If pp is not NULL, then the contents of the column-list are copied +** to *pp. *pp is set to point to the first byte past the last byte copied +** before this function returns. The POS_COLUMN or POS_END terminator +** is not copied into *pp. */ -#ifndef SQLITE_OMIT_DEPRECATED -SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ - void *pOld; +static void fts3ColumnlistCopy(char **pp, char **ppPoslist){ + char *pEnd = *ppPoslist; + char c = 0; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; + /* A column-list is terminated by either a 0x01 or 0x00 byte that is + ** not part of a multi-byte varint. + */ + while( 0xFE & (*pEnd | c) ){ + c = *pEnd++ & 0x80; + testcase( c!=0 && ((*pEnd)&0xfe)==0 ); } -#endif - sqlite3_mutex_enter(db->mutex); - pOld = db->pTraceArg; - db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; - db->xTrace = (int(*)(u32,void*,void*,void*))xTrace; - db->pTraceArg = pArg; - sqlite3_mutex_leave(db->mutex); - return pOld; + if( pp ){ + int n = (int)(pEnd - *ppPoslist); + char *p = *pp; + memcpy(p, *ppPoslist, n); + p += n; + *pp = p; + } + *ppPoslist = pEnd; } -#endif /* SQLITE_OMIT_DEPRECATED */ -/* Register a trace callback using the version-2 interface. +/* +** Value used to signify the end of an position-list. This must be +** as large or larger than any value that might appear on the +** position-list, even a position list that has been corrupted. */ -SQLITE_API int sqlite3_trace_v2( - sqlite3 *db, /* Trace this connection */ - unsigned mTrace, /* Mask of events to be traced */ - int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ - void *pArg /* Context */ -){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - return SQLITE_MISUSE_BKPT; - } -#endif - sqlite3_mutex_enter(db->mutex); - if( mTrace==0 ) xTrace = 0; - if( xTrace==0 ) mTrace = 0; - db->mTrace = mTrace; - db->xTrace = xTrace; - db->pTraceArg = pArg; - sqlite3_mutex_leave(db->mutex); - return SQLITE_OK; -} +#define POSITION_LIST_END LARGEST_INT64 -#ifndef SQLITE_OMIT_DEPRECATED /* -** Register a profile function. The pArg from the previously registered -** profile function is returned. +** This function is used to help parse position-lists. When this function is +** called, *pp may point to the start of the next varint in the position-list +** being parsed, or it may point to 1 byte past the end of the position-list +** (in which case **pp will be a terminator bytes POS_END (0) or +** (1)). ** -** A NULL profile function means that no profiling is executes. A non-NULL -** profile is a pointer to a function that is invoked at the conclusion of -** each SQL statement that is run. +** If *pp points past the end of the current position-list, set *pi to +** POSITION_LIST_END and return. Otherwise, read the next varint from *pp, +** increment the current value of *pi by the value read, and set *pp to +** point to the next value before returning. +** +** Before calling this routine *pi must be initialized to the value of +** the previous position, or zero if we are reading the first position +** in the position-list. Because positions are delta-encoded, the value +** of the previous position is needed in order to compute the value of +** the next position. */ -SQLITE_API void *sqlite3_profile( - sqlite3 *db, - void (*xProfile)(void*,const char*,sqlite_uint64), - void *pArg +static void fts3ReadNextPos( + char **pp, /* IN/OUT: Pointer into position-list buffer */ + sqlite3_int64 *pi /* IN/OUT: Value read from position-list */ ){ - void *pOld; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; + if( (**pp)&0xFE ){ + int iVal; + *pp += fts3GetVarint32((*pp), &iVal); + *pi += iVal; + *pi -= 2; + }else{ + *pi = POSITION_LIST_END; } -#endif - sqlite3_mutex_enter(db->mutex); - pOld = db->pProfileArg; - db->xProfile = xProfile; - db->pProfileArg = pArg; - sqlite3_mutex_leave(db->mutex); - return pOld; } -#endif /* SQLITE_OMIT_DEPRECATED */ -#endif /* SQLITE_OMIT_TRACE */ /* -** Register a function to be invoked when a transaction commits. -** If the invoked function returns non-zero, then the commit becomes a -** rollback. +** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by +** the value of iCol encoded as a varint to *pp. This will start a new +** column list. +** +** Set *pp to point to the byte just after the last byte written before +** returning (do not modify it if iCol==0). Return the total number of bytes +** written (0 if iCol==0). */ -SQLITE_API void *sqlite3_commit_hook( - sqlite3 *db, /* Attach the hook to this database */ - int (*xCallback)(void*), /* Function to invoke on each commit */ - void *pArg /* Argument to the function */ -){ - void *pOld; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; +static int fts3PutColNumber(char **pp, int iCol){ + int n = 0; /* Number of bytes written */ + if( iCol ){ + char *p = *pp; /* Output pointer */ + n = 1 + sqlite3Fts3PutVarint(&p[1], iCol); + *p = 0x01; + *pp = &p[n]; } -#endif - sqlite3_mutex_enter(db->mutex); - pOld = db->pCommitArg; - db->xCommitCallback = xCallback; - db->pCommitArg = pArg; - sqlite3_mutex_leave(db->mutex); - return pOld; + return n; } /* -** Register a callback to be invoked each time a row is updated, -** inserted or deleted using this database connection. +** Compute the union of two position lists. The output written +** into *pp contains all positions of both *pp1 and *pp2 in sorted +** order and with any duplicates removed. All pointers are +** updated appropriately. The caller is responsible for insuring +** that there is enough space in *pp to hold the complete output. */ -SQLITE_API void *sqlite3_update_hook( - sqlite3 *db, /* Attach the hook to this database */ - void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), - void *pArg /* Argument to the function */ +static int fts3PoslistMerge( + char **pp, /* Output buffer */ + char **pp1, /* Left input list */ + char **pp2 /* Right input list */ ){ - void *pRet; + char *p = *pp; + char *p1 = *pp1; + char *p2 = *pp2; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; + while( *p1 || *p2 ){ + int iCol1; /* The current column index in pp1 */ + int iCol2; /* The current column index in pp2 */ + + if( *p1==POS_COLUMN ){ + fts3GetVarint32(&p1[1], &iCol1); + if( iCol1==0 ) return FTS_CORRUPT_VTAB; + } + else if( *p1==POS_END ) iCol1 = 0x7fffffff; + else iCol1 = 0; + + if( *p2==POS_COLUMN ){ + fts3GetVarint32(&p2[1], &iCol2); + if( iCol2==0 ) return FTS_CORRUPT_VTAB; + } + else if( *p2==POS_END ) iCol2 = 0x7fffffff; + else iCol2 = 0; + + if( iCol1==iCol2 ){ + sqlite3_int64 i1 = 0; /* Last position from pp1 */ + sqlite3_int64 i2 = 0; /* Last position from pp2 */ + sqlite3_int64 iPrev = 0; + int n = fts3PutColNumber(&p, iCol1); + p1 += n; + p2 += n; + + /* At this point, both p1 and p2 point to the start of column-lists + ** for the same column (the column with index iCol1 and iCol2). + ** A column-list is a list of non-negative delta-encoded varints, each + ** incremented by 2 before being stored. Each list is terminated by a + ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists + ** and writes the results to buffer p. p is left pointing to the byte + ** after the list written. No terminator (POS_END or POS_COLUMN) is + ** written to the output. + */ + fts3GetDeltaVarint(&p1, &i1); + fts3GetDeltaVarint(&p2, &i2); + if( i1<2 || i2<2 ){ + break; + } + do { + fts3PutDeltaVarint(&p, &iPrev, (i1mutex); - pRet = db->pUpdateArg; - db->xUpdateCallback = xCallback; - db->pUpdateArg = pArg; - sqlite3_mutex_leave(db->mutex); - return pRet; + + *p++ = POS_END; + *pp = p; + *pp1 = p1 + 1; + *pp2 = p2 + 1; + return SQLITE_OK; } /* -** Register a callback to be invoked each time a transaction is rolled -** back by this database connection. +** This function is used to merge two position lists into one. When it is +** called, *pp1 and *pp2 must both point to position lists. A position-list is +** the part of a doclist that follows each document id. For example, if a row +** contains: +** +** 'a b c'|'x y z'|'a b b a' +** +** Then the position list for this row for token 'b' would consist of: +** +** 0x02 0x01 0x02 0x03 0x03 0x00 +** +** When this function returns, both *pp1 and *pp2 are left pointing to the +** byte following the 0x00 terminator of their respective position lists. +** +** If isSaveLeft is 0, an entry is added to the output position list for +** each position in *pp2 for which there exists one or more positions in +** *pp1 so that (pos(*pp2)>pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e. +** when the *pp1 token appears before the *pp2 token, but not more than nToken +** slots before it. +** +** e.g. nToken==1 searches for adjacent positions. */ -SQLITE_API void *sqlite3_rollback_hook( - sqlite3 *db, /* Attach the hook to this database */ - void (*xCallback)(void*), /* Callback function */ - void *pArg /* Argument to the function */ +static int fts3PoslistPhraseMerge( + char **pp, /* IN/OUT: Preallocated output buffer */ + int nToken, /* Maximum difference in token positions */ + int isSaveLeft, /* Save the left position */ + int isExact, /* If *pp1 is exactly nTokens before *pp2 */ + char **pp1, /* IN/OUT: Left input list */ + char **pp2 /* IN/OUT: Right input list */ ){ - void *pRet; + char *p = *pp; + char *p1 = *pp1; + char *p2 = *pp2; + int iCol1 = 0; + int iCol2 = 0; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; + /* Never set both isSaveLeft and isExact for the same invocation. */ + assert( isSaveLeft==0 || isExact==0 ); + + assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 ); + if( *p1==POS_COLUMN ){ + p1++; + p1 += fts3GetVarint32(p1, &iCol1); + } + if( *p2==POS_COLUMN ){ + p2++; + p2 += fts3GetVarint32(p2, &iCol2); + } + + while( 1 ){ + if( iCol1==iCol2 ){ + char *pSave = p; + sqlite3_int64 iPrev = 0; + sqlite3_int64 iPos1 = 0; + sqlite3_int64 iPos2 = 0; + + if( iCol1 ){ + *p++ = POS_COLUMN; + p += sqlite3Fts3PutVarint(p, iCol1); + } + + fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; + fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; + if( iPos1<0 || iPos2<0 ) break; + + while( 1 ){ + if( iPos2==iPos1+nToken + || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) + ){ + sqlite3_int64 iSave; + iSave = isSaveLeft ? iPos1 : iPos2; + fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; + pSave = 0; + assert( p ); + } + if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ + if( (*p2&0xFE)==0 ) break; + fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; + }else{ + if( (*p1&0xFE)==0 ) break; + fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; + } + } + + if( pSave ){ + assert( pp && p ); + p = pSave; + } + + fts3ColumnlistCopy(0, &p1); + fts3ColumnlistCopy(0, &p2); + assert( (*p1&0xFE)==0 && (*p2&0xFE)==0 ); + if( 0==*p1 || 0==*p2 ) break; + + p1++; + p1 += fts3GetVarint32(p1, &iCol1); + p2++; + p2 += fts3GetVarint32(p2, &iCol2); + } + + /* Advance pointer p1 or p2 (whichever corresponds to the smaller of + ** iCol1 and iCol2) so that it points to either the 0x00 that marks the + ** end of the position list, or the 0x01 that precedes the next + ** column-number in the position list. + */ + else if( iCol1mutex); - pRet = db->pRollbackArg; - db->xRollbackCallback = xCallback; - db->pRollbackArg = pArg; - sqlite3_mutex_leave(db->mutex); - return pRet; + *p++ = 0x00; + *pp = p; + return 1; } -#ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* -** Register a callback to be invoked each time a row is updated, -** inserted or deleted using this database connection. +** Merge two position-lists as required by the NEAR operator. The argument +** position lists correspond to the left and right phrases of an expression +** like: +** +** "phrase 1" NEAR "phrase number 2" +** +** Position list *pp1 corresponds to the left-hand side of the NEAR +** expression and *pp2 to the right. As usual, the indexes in the position +** lists are the offsets of the last token in each phrase (tokens "1" and "2" +** in the example above). +** +** The output position list - written to *pp - is a copy of *pp2 with those +** entries that are not sufficiently NEAR entries in *pp1 removed. */ -SQLITE_API void *sqlite3_preupdate_hook( - sqlite3 *db, /* Attach the hook to this database */ - void(*xCallback)( /* Callback function */ - void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64), - void *pArg /* First callback argument */ +static int fts3PoslistNearMerge( + char **pp, /* Output buffer */ + char *aTmp, /* Temporary buffer space */ + int nRight, /* Maximum difference in token positions */ + int nLeft, /* Maximum difference in token positions */ + char **pp1, /* IN/OUT: Left input list */ + char **pp2 /* IN/OUT: Right input list */ ){ - void *pRet; - sqlite3_mutex_enter(db->mutex); - pRet = db->pPreUpdateArg; - db->xPreUpdateCallback = xCallback; - db->pPreUpdateArg = pArg; - sqlite3_mutex_leave(db->mutex); - return pRet; -} -#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ + char *p1 = *pp1; + char *p2 = *pp2; -#ifndef SQLITE_OMIT_WAL -/* -** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). -** Invoke sqlite3_wal_checkpoint if the number of frames in the log file -** is greater than sqlite3.pWalArg cast to an integer (the value configured by -** wal_autocheckpoint()). -*/ -SQLITE_PRIVATE int sqlite3WalDefaultHook( - void *pClientData, /* Argument */ - sqlite3 *db, /* Connection */ - const char *zDb, /* Database */ - int nFrame /* Size of WAL */ -){ - if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){ - sqlite3BeginBenignMalloc(); - sqlite3_wal_checkpoint(db, zDb); - sqlite3EndBenignMalloc(); + char *pTmp1 = aTmp; + char *pTmp2; + char *aTmp2; + int res = 1; + + fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2); + aTmp2 = pTmp2 = pTmp1; + *pp1 = p1; + *pp2 = p2; + fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1); + if( pTmp1!=aTmp && pTmp2!=aTmp2 ){ + fts3PoslistMerge(pp, &aTmp, &aTmp2); + }else if( pTmp1!=aTmp ){ + fts3PoslistCopy(pp, &aTmp); + }else if( pTmp2!=aTmp2 ){ + fts3PoslistCopy(pp, &aTmp2); + }else{ + res = 0; } - return SQLITE_OK; + + return res; } -#endif /* SQLITE_OMIT_WAL */ /* -** Configure an sqlite3_wal_hook() callback to automatically checkpoint -** a database after committing a transaction if there are nFrame or -** more frames in the log file. Passing zero or a negative value as the -** nFrame parameter disables automatic checkpoints entirely. -** -** The callback registered by this function replaces any existing callback -** registered using sqlite3_wal_hook(). Likewise, registering a callback -** using sqlite3_wal_hook() disables the automatic checkpoint mechanism -** configured by this function. +** An instance of this function is used to merge together the (potentially +** large number of) doclists for each term that matches a prefix query. +** See function fts3TermSelectMerge() for details. */ -SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){ -#ifdef SQLITE_OMIT_WAL - UNUSED_PARAMETER(db); - UNUSED_PARAMETER(nFrame); -#else -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - if( nFrame>0 ){ - sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame)); - }else{ - sqlite3_wal_hook(db, 0, 0); - } -#endif - return SQLITE_OK; -} +typedef struct TermSelect TermSelect; +struct TermSelect { + char *aaOutput[16]; /* Malloc'd output buffers */ + int anOutput[16]; /* Size each output buffer in bytes */ +}; /* -** Register a callback to be invoked each time a transaction is written -** into the write-ahead-log by this database connection. +** This function is used to read a single varint from a buffer. Parameter +** pEnd points 1 byte past the end of the buffer. When this function is +** called, if *pp points to pEnd or greater, then the end of the buffer +** has been reached. In this case *pp is set to 0 and the function returns. +** +** If *pp does not point to or past pEnd, then a single varint is read +** from *pp. *pp is then set to point 1 byte past the end of the read varint. +** +** If bDescIdx is false, the value read is added to *pVal before returning. +** If it is true, the value read is subtracted from *pVal before this +** function returns. */ -SQLITE_API void *sqlite3_wal_hook( - sqlite3 *db, /* Attach the hook to this db handle */ - int(*xCallback)(void *, sqlite3*, const char*, int), - void *pArg /* First argument passed to xCallback() */ +static void fts3GetDeltaVarint3( + char **pp, /* IN/OUT: Point to read varint from */ + char *pEnd, /* End of buffer */ + int bDescIdx, /* True if docids are descending */ + sqlite3_int64 *pVal /* IN/OUT: Integer value */ ){ -#ifndef SQLITE_OMIT_WAL - void *pRet; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; + if( *pp>=pEnd ){ + *pp = 0; + }else{ + u64 iVal; + *pp += sqlite3Fts3GetVarintU(*pp, &iVal); + if( bDescIdx ){ + *pVal = (i64)((u64)*pVal - iVal); + }else{ + *pVal = (i64)((u64)*pVal + iVal); + } } -#endif - sqlite3_mutex_enter(db->mutex); - pRet = db->pWalArg; - db->xWalCallback = xCallback; - db->pWalArg = pArg; - sqlite3_mutex_leave(db->mutex); - return pRet; -#else - return 0; -#endif } /* -** Checkpoint database zDb. +** This function is used to write a single varint to a buffer. The varint +** is written to *pp. Before returning, *pp is set to point 1 byte past the +** end of the value written. +** +** If *pbFirst is zero when this function is called, the value written to +** the buffer is that of parameter iVal. +** +** If *pbFirst is non-zero when this function is called, then the value +** written is either (iVal-*piPrev) (if bDescIdx is zero) or (*piPrev-iVal) +** (if bDescIdx is non-zero). +** +** Before returning, this function always sets *pbFirst to 1 and *piPrev +** to the value of parameter iVal. */ -SQLITE_API int sqlite3_wal_checkpoint_v2( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Name of attached database (or NULL) */ - int eMode, /* SQLITE_CHECKPOINT_* value */ - int *pnLog, /* OUT: Size of WAL log in frames */ - int *pnCkpt /* OUT: Total number of frames checkpointed */ +static void fts3PutDeltaVarint3( + char **pp, /* IN/OUT: Output pointer */ + int bDescIdx, /* True for descending docids */ + sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ + int *pbFirst, /* IN/OUT: True after first int written */ + sqlite3_int64 iVal /* Write this value to the list */ ){ -#ifdef SQLITE_OMIT_WAL - return SQLITE_OK; -#else - int rc; /* Return code */ - int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */ - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - - /* Initialize the output variables to -1 in case an error occurs. */ - if( pnLog ) *pnLog = -1; - if( pnCkpt ) *pnCkpt = -1; - - assert( SQLITE_CHECKPOINT_PASSIVE==0 ); - assert( SQLITE_CHECKPOINT_FULL==1 ); - assert( SQLITE_CHECKPOINT_RESTART==2 ); - assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); - if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ - /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint - ** mode: */ - return SQLITE_MISUSE; - } - - sqlite3_mutex_enter(db->mutex); - if( zDb && zDb[0] ){ - iDb = sqlite3FindDbName(db, zDb); - } - if( iDb<0 ){ - rc = SQLITE_ERROR; - sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb); + sqlite3_uint64 iWrite; + if( bDescIdx==0 || *pbFirst==0 ){ + assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev ); + iWrite = (u64)iVal - (u64)*piPrev; }else{ - db->busyHandler.nBusy = 0; - rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); - sqlite3Error(db, rc); - } - rc = sqlite3ApiExit(db, rc); - - /* If there are no active statements, clear the interrupt flag at this - ** point. */ - if( db->nVdbeActive==0 ){ - db->u1.isInterrupted = 0; + assert_fts3_nc( *piPrev>=iVal ); + iWrite = (u64)*piPrev - (u64)iVal; } - - sqlite3_mutex_leave(db->mutex); - return rc; -#endif + assert( *pbFirst || *piPrev==0 ); + assert_fts3_nc( *pbFirst==0 || iWrite>0 ); + *pp += sqlite3Fts3PutVarint(*pp, iWrite); + *piPrev = iVal; + *pbFirst = 1; } /* -** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points -** to contains a zero-length string, all attached databases are -** checkpointed. +** This macro is used by various functions that merge doclists. The two +** arguments are 64-bit docid values. If the value of the stack variable +** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). +** Otherwise, (i2-i1). +** +** Using this makes it easier to write code that can merge doclists that are +** sorted in either ascending or descending order. */ -SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ - /* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to - ** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */ - return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0); -} +/* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */ +#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1))) -#ifndef SQLITE_OMIT_WAL /* -** Run a checkpoint on database iDb. This is a no-op if database iDb is -** not currently open in WAL mode. -** -** If a transaction is open on the database being checkpointed, this -** function returns SQLITE_LOCKED and a checkpoint is not attempted. If -** an error occurs while running the checkpoint, an SQLite error code is -** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK. -** -** The mutex on database handle db should be held by the caller. The mutex -** associated with the specific b-tree being checkpointed is taken by -** this function while the checkpoint is running. +** This function does an "OR" merge of two doclists (output contains all +** positions contained in either argument doclist). If the docids in the +** input doclists are sorted in ascending order, parameter bDescDoclist +** should be false. If they are sorted in ascending order, it should be +** passed a non-zero value. ** -** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are -** checkpointed. If an error is encountered it is returned immediately - -** no attempt is made to checkpoint any remaining databases. +** If no error occurs, *paOut is set to point at an sqlite3_malloc'd buffer +** containing the output doclist and SQLITE_OK is returned. In this case +** *pnOut is set to the number of bytes in the output doclist. ** -** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. +** If an error occurs, an SQLite error code is returned. The output values +** are undefined in this case. */ -SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ - int rc = SQLITE_OK; /* Return code */ - int i; /* Used to iterate through attached dbs */ - int bBusy = 0; /* True if SQLITE_BUSY has been encountered */ +static int fts3DoclistOrMerge( + int bDescDoclist, /* True if arguments are desc */ + char *a1, int n1, /* First doclist */ + char *a2, int n2, /* Second doclist */ + char **paOut, int *pnOut /* OUT: Malloc'd doclist */ +){ + int rc = SQLITE_OK; + sqlite3_int64 i1 = 0; + sqlite3_int64 i2 = 0; + sqlite3_int64 iPrev = 0; + char *pEnd1 = &a1[n1]; + char *pEnd2 = &a2[n2]; + char *p1 = a1; + char *p2 = a2; + char *p; + char *aOut; + int bFirstOut = 0; - assert( sqlite3_mutex_held(db->mutex) ); - assert( !pnLog || *pnLog==-1 ); - assert( !pnCkpt || *pnCkpt==-1 ); + *paOut = 0; + *pnOut = 0; - for(i=0; inDb && rc==SQLITE_OK; i++){ - if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){ - rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt); - pnLog = 0; - pnCkpt = 0; - if( rc==SQLITE_BUSY ){ - bBusy = 1; - rc = SQLITE_OK; - } + /* Allocate space for the output. Both the input and output doclists + ** are delta encoded. If they are in ascending order (bDescDoclist==0), + ** then the first docid in each list is simply encoded as a varint. For + ** each subsequent docid, the varint stored is the difference between the + ** current and previous docid (a positive number - since the list is in + ** ascending order). + ** + ** The first docid written to the output is therefore encoded using the + ** same number of bytes as it is in whichever of the input lists it is + ** read from. And each subsequent docid read from the same input list + ** consumes either the same or less bytes as it did in the input (since + ** the difference between it and the previous value in the output must + ** be a positive value less than or equal to the delta value read from + ** the input list). The same argument applies to all but the first docid + ** read from the 'other' list. And to the contents of all position lists + ** that will be copied and merged from the input to the output. + ** + ** However, if the first docid copied to the output is a negative number, + ** then the encoding of the first docid from the 'other' input list may + ** be larger in the output than it was in the input (since the delta value + ** may be a larger positive integer than the actual docid). + ** + ** The space required to store the output is therefore the sum of the + ** sizes of the two inputs, plus enough space for exactly one of the input + ** docids to grow. + ** + ** A symetric argument may be made if the doclists are in descending + ** order. + */ + aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); + if( !aOut ) return SQLITE_NOMEM; + + p = aOut; + fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); + while( p1 || p2 ){ + sqlite3_int64 iDiff = DOCID_CMP(i1, i2); + + if( p2 && p1 && iDiff==0 ){ + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); + rc = fts3PoslistMerge(&p, &p1, &p2); + if( rc ) break; + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); + }else if( !p2 || (p1 && iDiff<0) ){ + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); + fts3PoslistCopy(&p, &p1); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + }else{ + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2); + fts3PoslistCopy(&p, &p2); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); } + + assert( (p-aOut)<=((p1?(p1-a1):n1)+(p2?(p2-a2):n2)+FTS3_VARINT_MAX-1) ); } - return (rc==SQLITE_OK && bBusy) ? SQLITE_BUSY : rc; + if( rc!=SQLITE_OK ){ + sqlite3_free(aOut); + p = aOut = 0; + }else{ + assert( (p-aOut)<=n1+n2+FTS3_VARINT_MAX-1 ); + memset(&aOut[(p-aOut)], 0, FTS3_BUFFER_PADDING); + } + *paOut = aOut; + *pnOut = (int)(p-aOut); + return rc; } -#endif /* SQLITE_OMIT_WAL */ /* -** This function returns true if main-memory should be used instead of -** a temporary file for transient pager files and statement journals. -** The value returned depends on the value of db->temp_store (runtime -** parameter) and the compile time value of SQLITE_TEMP_STORE. The -** following table describes the relationship between these two values -** and this functions return value. +** This function does a "phrase" merge of two doclists. In a phrase merge, +** the output contains a copy of each position from the right-hand input +** doclist for which there is a position in the left-hand input doclist +** exactly nDist tokens before it. ** -** SQLITE_TEMP_STORE db->temp_store Location of temporary database -** ----------------- -------------- ------------------------------ -** 0 any file (return 0) -** 1 1 file (return 0) -** 1 2 memory (return 1) -** 1 0 file (return 0) -** 2 1 file (return 0) -** 2 2 memory (return 1) -** 2 0 memory (return 1) -** 3 any memory (return 1) +** If the docids in the input doclists are sorted in ascending order, +** parameter bDescDoclist should be false. If they are sorted in ascending +** order, it should be passed a non-zero value. +** +** The right-hand input doclist is overwritten by this function. */ -SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){ -#if SQLITE_TEMP_STORE==1 - return ( db->temp_store==2 ); -#endif -#if SQLITE_TEMP_STORE==2 - return ( db->temp_store!=1 ); -#endif -#if SQLITE_TEMP_STORE==3 - UNUSED_PARAMETER(db); - return 1; -#endif -#if SQLITE_TEMP_STORE<1 || SQLITE_TEMP_STORE>3 - UNUSED_PARAMETER(db); - return 0; -#endif -} +static int fts3DoclistPhraseMerge( + int bDescDoclist, /* True if arguments are desc */ + int nDist, /* Distance from left to right (1=adjacent) */ + char *aLeft, int nLeft, /* Left doclist */ + char **paRight, int *pnRight /* IN/OUT: Right/output doclist */ +){ + sqlite3_int64 i1 = 0; + sqlite3_int64 i2 = 0; + sqlite3_int64 iPrev = 0; + char *aRight = *paRight; + char *pEnd1 = &aLeft[nLeft]; + char *pEnd2 = &aRight[*pnRight]; + char *p1 = aLeft; + char *p2 = aRight; + char *p; + int bFirstOut = 0; + char *aOut; -/* -** Return UTF-8 encoded English language explanation of the most recent -** error. -*/ -SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){ - const char *z; - if( !db ){ - return sqlite3ErrStr(SQLITE_NOMEM_BKPT); - } - if( !sqlite3SafetyCheckSickOrOk(db) ){ - return sqlite3ErrStr(SQLITE_MISUSE_BKPT); - } - sqlite3_mutex_enter(db->mutex); - if( db->mallocFailed ){ - z = sqlite3ErrStr(SQLITE_NOMEM_BKPT); + assert( nDist>0 ); + if( bDescDoclist ){ + aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX); + if( aOut==0 ) return SQLITE_NOMEM; }else{ - testcase( db->pErr==0 ); - z = (char*)sqlite3_value_text(db->pErr); - assert( !db->mallocFailed ); - if( z==0 ){ - z = sqlite3ErrStr(db->errCode); - } + aOut = aRight; } - sqlite3_mutex_leave(db->mutex); - return z; -} + p = aOut; -#ifndef SQLITE_OMIT_UTF16 -/* -** Return UTF-16 encoded English language explanation of the most recent -** error. -*/ -SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ - static const u16 outOfMem[] = { - 'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0 - }; - static const u16 misuse[] = { - 'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ', - 'r', 'o', 'u', 't', 'i', 'n', 'e', ' ', - 'c', 'a', 'l', 'l', 'e', 'd', ' ', - 'o', 'u', 't', ' ', - 'o', 'f', ' ', - 's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0 - }; + fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); - const void *z; - if( !db ){ - return (void *)outOfMem; - } - if( !sqlite3SafetyCheckSickOrOk(db) ){ - return (void *)misuse; - } - sqlite3_mutex_enter(db->mutex); - if( db->mallocFailed ){ - z = (void *)outOfMem; - }else{ - z = sqlite3_value_text16(db->pErr); - if( z==0 ){ - sqlite3ErrorWithMsg(db, db->errCode, sqlite3ErrStr(db->errCode)); - z = sqlite3_value_text16(db->pErr); + while( p1 && p2 ){ + sqlite3_int64 iDiff = DOCID_CMP(i1, i2); + if( iDiff==0 ){ + char *pSave = p; + sqlite3_int64 iPrevSave = iPrev; + int bFirstOutSave = bFirstOut; + + fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); + if( 0==fts3PoslistPhraseMerge(&p, nDist, 0, 1, &p1, &p2) ){ + p = pSave; + iPrev = iPrevSave; + bFirstOut = bFirstOutSave; + } + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); + }else if( iDiff<0 ){ + fts3PoslistCopy(0, &p1); + fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); + }else{ + fts3PoslistCopy(0, &p2); + fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); } - /* A malloc() may have failed within the call to sqlite3_value_text16() - ** above. If this is the case, then the db->mallocFailed flag needs to - ** be cleared before returning. Do this directly, instead of via - ** sqlite3ApiExit(), to avoid setting the database handle error message. - */ - sqlite3OomClear(db); } - sqlite3_mutex_leave(db->mutex); - return z; -} -#endif /* SQLITE_OMIT_UTF16 */ -/* -** Return the most recent error code generated by an SQLite routine. If NULL is -** passed to this function, we assume a malloc() failed during sqlite3_open(). -*/ -SQLITE_API int sqlite3_errcode(sqlite3 *db){ - if( db && !sqlite3SafetyCheckSickOrOk(db) ){ - return SQLITE_MISUSE_BKPT; - } - if( !db || db->mallocFailed ){ - return SQLITE_NOMEM_BKPT; - } - return db->errCode & db->errMask; -} -SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){ - if( db && !sqlite3SafetyCheckSickOrOk(db) ){ - return SQLITE_MISUSE_BKPT; - } - if( !db || db->mallocFailed ){ - return SQLITE_NOMEM_BKPT; + *pnRight = (int)(p - aOut); + if( bDescDoclist ){ + sqlite3_free(aRight); + *paRight = aOut; } - return db->errCode; -} -SQLITE_API int sqlite3_system_errno(sqlite3 *db){ - return db ? db->iSysErrno : 0; -} -/* -** Return a string that describes the kind of error specified in the -** argument. For now, this simply calls the internal sqlite3ErrStr() -** function. -*/ -SQLITE_API const char *sqlite3_errstr(int rc){ - return sqlite3ErrStr(rc); + return SQLITE_OK; } /* -** Create a new collating function for database "db". The name is zName -** and the encoding is enc. +** Argument pList points to a position list nList bytes in size. This +** function checks to see if the position list contains any entries for +** a token in position 0 (of any column). If so, it writes argument iDelta +** to the output buffer pOut, followed by a position list consisting only +** of the entries from pList at position 0, and terminated by an 0x00 byte. +** The value returned is the number of bytes written to pOut (if any). */ -static int createCollation( - sqlite3* db, - const char *zName, - u8 enc, - void* pCtx, - int(*xCompare)(void*,int,const void*,int,const void*), - void(*xDel)(void*) +SQLITE_PRIVATE int sqlite3Fts3FirstFilter( + sqlite3_int64 iDelta, /* Varint that may be written to pOut */ + char *pList, /* Position list (no 0x00 term) */ + int nList, /* Size of pList in bytes */ + char *pOut /* Write output here */ ){ - CollSeq *pColl; - int enc2; - - assert( sqlite3_mutex_held(db->mutex) ); - - /* If SQLITE_UTF16 is specified as the encoding type, transform this - ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the - ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. - */ - enc2 = enc; - testcase( enc2==SQLITE_UTF16 ); - testcase( enc2==SQLITE_UTF16_ALIGNED ); - if( enc2==SQLITE_UTF16 || enc2==SQLITE_UTF16_ALIGNED ){ - enc2 = SQLITE_UTF16NATIVE; - } - if( enc2SQLITE_UTF16BE ){ - return SQLITE_MISUSE_BKPT; - } + int nOut = 0; + int bWritten = 0; /* True once iDelta has been written */ + char *p = pList; + char *pEnd = &pList[nList]; - /* Check if this call is removing or replacing an existing collation - ** sequence. If so, and there are active VMs, return busy. If there - ** are no active VMs, invalidate any pre-compiled statements. - */ - pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); - if( pColl && pColl->xCmp ){ - if( db->nVdbeActive ){ - sqlite3ErrorWithMsg(db, SQLITE_BUSY, - "unable to delete/modify collation sequence due to active statements"); - return SQLITE_BUSY; + if( *p!=0x01 ){ + if( *p==0x02 ){ + nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); + pOut[nOut++] = 0x02; + bWritten = 1; } - sqlite3ExpirePreparedStatements(db); + fts3ColumnlistCopy(0, &p); + } - /* If collation sequence pColl was created directly by a call to - ** sqlite3_create_collation, and not generated by synthCollSeq(), - ** then any copies made by synthCollSeq() need to be invalidated. - ** Also, collation destructor - CollSeq.xDel() - function may need - ** to be called. - */ - if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){ - CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName); - int j; - for(j=0; j<3; j++){ - CollSeq *p = &aColl[j]; - if( p->enc==pColl->enc ){ - if( p->xDel ){ - p->xDel(p->pUser); - } - p->xCmp = 0; - } + while( pxCmp = xCompare; - pColl->pUser = pCtx; - pColl->xDel = xDel; - pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); - sqlite3Error(db, SQLITE_OK); - return SQLITE_OK; + return nOut; } /* -** This array defines hard upper bounds on limit values. The -** initializer must be kept in sync with the SQLITE_LIMIT_* -** #defines in sqlite3.h. +** Merge all doclists in the TermSelect.aaOutput[] array into a single +** doclist stored in TermSelect.aaOutput[0]. If successful, delete all +** other doclists (except the aaOutput[0] one) and return SQLITE_OK. +** +** If an OOM error occurs, return SQLITE_NOMEM. In this case it is +** the responsibility of the caller to free any doclists left in the +** TermSelect.aaOutput[] array. */ -static const int aHardLimit[] = { - SQLITE_MAX_LENGTH, - SQLITE_MAX_SQL_LENGTH, - SQLITE_MAX_COLUMN, - SQLITE_MAX_EXPR_DEPTH, - SQLITE_MAX_COMPOUND_SELECT, - SQLITE_MAX_VDBE_OP, - SQLITE_MAX_FUNCTION_ARG, - SQLITE_MAX_ATTACHED, - SQLITE_MAX_LIKE_PATTERN_LENGTH, - SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ - SQLITE_MAX_TRIGGER_DEPTH, - SQLITE_MAX_WORKER_THREADS, -}; +static int fts3TermSelectFinishMerge(Fts3Table *p, TermSelect *pTS){ + char *aOut = 0; + int nOut = 0; + int i; -/* -** Make sure the hard limits are set to reasonable values -*/ -#if SQLITE_MAX_LENGTH<100 -# error SQLITE_MAX_LENGTH must be at least 100 -#endif -#if SQLITE_MAX_SQL_LENGTH<100 -# error SQLITE_MAX_SQL_LENGTH must be at least 100 -#endif -#if SQLITE_MAX_SQL_LENGTH>SQLITE_MAX_LENGTH -# error SQLITE_MAX_SQL_LENGTH must not be greater than SQLITE_MAX_LENGTH -#endif -#if SQLITE_MAX_COMPOUND_SELECT<2 -# error SQLITE_MAX_COMPOUND_SELECT must be at least 2 -#endif -#if SQLITE_MAX_VDBE_OP<40 -# error SQLITE_MAX_VDBE_OP must be at least 40 -#endif -#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127 -# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127 -#endif -#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125 -# error SQLITE_MAX_ATTACHED must be between 0 and 125 -#endif -#if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 -# error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 -#endif -#if SQLITE_MAX_COLUMN>32767 -# error SQLITE_MAX_COLUMN must not exceed 32767 -#endif -#if SQLITE_MAX_TRIGGER_DEPTH<1 -# error SQLITE_MAX_TRIGGER_DEPTH must be at least 1 -#endif -#if SQLITE_MAX_WORKER_THREADS<0 || SQLITE_MAX_WORKER_THREADS>50 -# error SQLITE_MAX_WORKER_THREADS must be between 0 and 50 -#endif + /* Loop through the doclists in the aaOutput[] array. Merge them all + ** into a single doclist. + */ + for(i=0; iaaOutput); i++){ + if( pTS->aaOutput[i] ){ + if( !aOut ){ + aOut = pTS->aaOutput[i]; + nOut = pTS->anOutput[i]; + pTS->aaOutput[i] = 0; + }else{ + int nNew; + char *aNew; + + int rc = fts3DoclistOrMerge(p->bDescIdx, + pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, &aNew, &nNew + ); + if( rc!=SQLITE_OK ){ + sqlite3_free(aOut); + return rc; + } + + sqlite3_free(pTS->aaOutput[i]); + sqlite3_free(aOut); + pTS->aaOutput[i] = 0; + aOut = aNew; + nOut = nNew; + } + } + } + pTS->aaOutput[0] = aOut; + pTS->anOutput[0] = nOut; + return SQLITE_OK; +} /* -** Change the value of a limit. Report the old value. -** If an invalid limit index is supplied, report -1. -** Make no changes but still report the old value if the -** new limit is negative. +** Merge the doclist aDoclist/nDoclist into the TermSelect object passed +** as the first argument. The merge is an "OR" merge (see function +** fts3DoclistOrMerge() for details). ** -** A new lower limit does not shrink existing constructs. -** It merely prevents new constructs that exceed the limit -** from forming. +** This function is called with the doclist for each term that matches +** a queried prefix. It merges all these doclists into one, the doclist +** for the specified prefix. Since there can be a very large number of +** doclists to merge, the merging is done pair-wise using the TermSelect +** object. +** +** This function returns SQLITE_OK if the merge is successful, or an +** SQLite error code (SQLITE_NOMEM) if an error occurs. */ -SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ - int oldLimit; +static int fts3TermSelectMerge( + Fts3Table *p, /* FTS table handle */ + TermSelect *pTS, /* TermSelect object to merge into */ + char *aDoclist, /* Pointer to doclist */ + int nDoclist /* Size of aDoclist in bytes */ +){ + if( pTS->aaOutput[0]==0 ){ + /* If this is the first term selected, copy the doclist to the output + ** buffer using memcpy(). + ** + ** Add FTS3_VARINT_MAX bytes of unused space to the end of the + ** allocation. This is so as to ensure that the buffer is big enough + ** to hold the current doclist AND'd with any other doclist. If the + ** doclists are stored in order=ASC order, this padding would not be + ** required (since the size of [doclistA AND doclistB] is always less + ** than or equal to the size of [doclistA] in that case). But this is + ** not true for order=DESC. For example, a doclist containing (1, -1) + ** may be smaller than (-1), as in the first example the -1 may be stored + ** as a single-byte delta, whereas in the second it must be stored as a + ** FTS3_VARINT_MAX byte varint. + ** + ** Similar padding is added in the fts3DoclistOrMerge() function. + */ + pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); + pTS->anOutput[0] = nDoclist; + if( pTS->aaOutput[0] ){ + memcpy(pTS->aaOutput[0], aDoclist, nDoclist); + memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX); + }else{ + return SQLITE_NOMEM; + } + }else{ + char *aMerge = aDoclist; + int nMerge = nDoclist; + int iOut; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return -1; - } -#endif + for(iOut=0; iOutaaOutput); iOut++){ + if( pTS->aaOutput[iOut]==0 ){ + assert( iOut>0 ); + pTS->aaOutput[iOut] = aMerge; + pTS->anOutput[iOut] = nMerge; + break; + }else{ + char *aNew; + int nNew; - /* EVIDENCE-OF: R-30189-54097 For each limit category SQLITE_LIMIT_NAME - ** there is a hard upper bound set at compile-time by a C preprocessor - ** macro called SQLITE_MAX_NAME. (The "_LIMIT_" in the name is changed to - ** "_MAX_".) - */ - assert( aHardLimit[SQLITE_LIMIT_LENGTH]==SQLITE_MAX_LENGTH ); - assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH ); - assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN ); - assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH ); - assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT); - assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP ); - assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG ); - assert( aHardLimit[SQLITE_LIMIT_ATTACHED]==SQLITE_MAX_ATTACHED ); - assert( aHardLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]== - SQLITE_MAX_LIKE_PATTERN_LENGTH ); - assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); - assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); - assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); - assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); + int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge, + pTS->aaOutput[iOut], pTS->anOutput[iOut], &aNew, &nNew + ); + if( rc!=SQLITE_OK ){ + if( aMerge!=aDoclist ) sqlite3_free(aMerge); + return rc; + } + if( aMerge!=aDoclist ) sqlite3_free(aMerge); + sqlite3_free(pTS->aaOutput[iOut]); + pTS->aaOutput[iOut] = 0; - if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ - return -1; + aMerge = aNew; + nMerge = nNew; + if( (iOut+1)==SizeofArray(pTS->aaOutput) ){ + pTS->aaOutput[iOut] = aMerge; + pTS->anOutput[iOut] = nMerge; + } + } + } } - oldLimit = db->aLimit[limitId]; - if( newLimit>=0 ){ /* IMP: R-52476-28732 */ - if( newLimit>aHardLimit[limitId] ){ - newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ + return SQLITE_OK; +} + +/* +** Append SegReader object pNew to the end of the pCsr->apSegment[] array. +*/ +static int fts3SegReaderCursorAppend( + Fts3MultiSegReader *pCsr, + Fts3SegReader *pNew +){ + if( (pCsr->nSegment%16)==0 ){ + Fts3SegReader **apNew; + sqlite3_int64 nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*); + apNew = (Fts3SegReader **)sqlite3_realloc64(pCsr->apSegment, nByte); + if( !apNew ){ + sqlite3Fts3SegReaderFree(pNew); + return SQLITE_NOMEM; } - db->aLimit[limitId] = newLimit; + pCsr->apSegment = apNew; } - return oldLimit; /* IMP: R-53341-35419 */ + pCsr->apSegment[pCsr->nSegment++] = pNew; + return SQLITE_OK; } /* -** This function is used to parse both URIs and non-URI filenames passed by the -** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database -** URIs specified as part of ATTACH statements. -** -** The first argument to this function is the name of the VFS to use (or -** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx" -** query parameter. The second argument contains the URI (or non-URI filename) -** itself. When this function is called the *pFlags variable should contain -** the default flags to open the database handle with. The value stored in -** *pFlags may be updated before returning if the URI filename contains -** "cache=xxx" or "mode=xxx" query parameters. -** -** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to -** the VFS that should be used to open the database file. *pzFile is set to -** point to a buffer containing the name of the file to open. It is the -** responsibility of the caller to eventually call sqlite3_free() to release -** this buffer. +** Add seg-reader objects to the Fts3MultiSegReader object passed as the +** 8th argument. ** -** If an error occurs, then an SQLite error code is returned and *pzErrMsg -** may be set to point to a buffer containing an English language error -** message. It is the responsibility of the caller to eventually release -** this buffer by calling sqlite3_free(). +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. */ -SQLITE_PRIVATE int sqlite3ParseUri( - const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */ - const char *zUri, /* Nul-terminated URI to parse */ - unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */ - sqlite3_vfs **ppVfs, /* OUT: VFS to use */ - char **pzFile, /* OUT: Filename component of URI */ - char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */ +static int fts3SegReaderCursor( + Fts3Table *p, /* FTS3 table handle */ + int iLangid, /* Language id */ + int iIndex, /* Index to search (from 0 to p->nIndex-1) */ + int iLevel, /* Level of segments to scan */ + const char *zTerm, /* Term to query for */ + int nTerm, /* Size of zTerm in bytes */ + int isPrefix, /* True for a prefix search */ + int isScan, /* True to scan from zTerm to EOF */ + Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ - int rc = SQLITE_OK; - unsigned int flags = *pFlags; - const char *zVfs = zDefaultVfs; - char *zFile; - char c; - int nUri = sqlite3Strlen30(zUri); + int rc = SQLITE_OK; /* Error code */ + sqlite3_stmt *pStmt = 0; /* Statement to iterate through segments */ + int rc2; /* Result of sqlite3_reset() */ - assert( *pzErrMsg==0 ); + /* If iLevel is less than 0 and this is not a scan, include a seg-reader + ** for the pending-terms. If this is a scan, then this call must be being + ** made by an fts4aux module, not an FTS table. In this case calling + ** Fts3SegReaderPending might segfault, as the data structures used by + ** fts4aux are not completely populated. So it's easiest to filter these + ** calls out here. */ + if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){ + Fts3SegReader *pSeg = 0; + rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg); + if( rc==SQLITE_OK && pSeg ){ + rc = fts3SegReaderCursorAppend(pCsr, pSeg); + } + } - if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */ - || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */ - && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */ - ){ - char *zOpt; - int eState; /* Parser state when parsing URI */ - int iIn; /* Input character index */ - int iOut = 0; /* Output character index */ - u64 nByte = nUri+2; /* Bytes of space to allocate */ + if( iLevel!=FTS3_SEGCURSOR_PENDING ){ + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3AllSegdirs(p, iLangid, iIndex, iLevel, &pStmt); + } - /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen - ** method that there may be extra parameters following the file-name. */ - flags |= SQLITE_OPEN_URI; + while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ + Fts3SegReader *pSeg = 0; - for(iIn=0; iInnSegment+1, + (isPrefix==0 && isScan==0), + iStartBlock, iLeavesEndBlock, + iEndBlock, zRoot, nRoot, &pSeg + ); + if( rc!=SQLITE_OK ) goto finished; + rc = fts3SegReaderCursorAppend(pCsr, pSeg); } -#endif + } - /* Copy the filename and any query parameters into the zFile buffer. - ** Decode %HH escape codes along the way. - ** - ** Within this loop, variable eState may be set to 0, 1 or 2, depending - ** on the parsing context. As follows: - ** - ** 0: Parsing file-name. - ** 1: Parsing name section of a name=value query parameter. - ** 2: Parsing value section of a name=value query parameter. - */ - eState = 0; - while( (c = zUri[iIn])!=0 && c!='#' ){ - iIn++; - if( c=='%' - && sqlite3Isxdigit(zUri[iIn]) - && sqlite3Isxdigit(zUri[iIn+1]) - ){ - int octet = (sqlite3HexToInt(zUri[iIn++]) << 4); - octet += sqlite3HexToInt(zUri[iIn++]); + finished: + rc2 = sqlite3_reset(pStmt); + if( rc==SQLITE_DONE ) rc = rc2; - assert( octet>=0 && octet<256 ); - if( octet==0 ){ -#ifndef SQLITE_ENABLE_URI_00_ERROR - /* This branch is taken when "%00" appears within the URI. In this - ** case we ignore all text in the remainder of the path, name or - ** value currently being parsed. So ignore the current character - ** and skip to the next "?", "=" or "&", as appropriate. */ - while( (c = zUri[iIn])!=0 && c!='#' - && (eState!=0 || c!='?') - && (eState!=1 || (c!='=' && c!='&')) - && (eState!=2 || c!='&') - ){ - iIn++; - } - continue; -#else - /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */ - *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri"); - rc = SQLITE_ERROR; - goto parse_uri_out; -#endif - } - c = octet; - }else if( eState==1 && (c=='&' || c=='=') ){ - if( zFile[iOut-1]==0 ){ - /* An empty option name. Ignore this option altogether. */ - while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++; - continue; - } - if( c=='&' ){ - zFile[iOut++] = '\0'; - }else{ - eState = 2; - } - c = 0; - }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ - c = 0; - eState = 1; - } - zFile[iOut++] = c; - } - if( eState==1 ) zFile[iOut++] = '\0'; - zFile[iOut++] = '\0'; - zFile[iOut++] = '\0'; + return rc; +} - /* Check if there were any options specified that should be interpreted - ** here. Options that are interpreted here include "vfs" and those that - ** correspond to flags that may be passed to the sqlite3_open_v2() - ** method. */ - zOpt = &zFile[sqlite3Strlen30(zFile)+1]; - while( zOpt[0] ){ - int nOpt = sqlite3Strlen30(zOpt); - char *zVal = &zOpt[nOpt+1]; - int nVal = sqlite3Strlen30(zVal); +/* +** Set up a cursor object for iterating through a full-text index or a +** single level therein. +*/ +SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor( + Fts3Table *p, /* FTS3 table handle */ + int iLangid, /* Language-id to search */ + int iIndex, /* Index to search (from 0 to p->nIndex-1) */ + int iLevel, /* Level of segments to scan */ + const char *zTerm, /* Term to query for */ + int nTerm, /* Size of zTerm in bytes */ + int isPrefix, /* True for a prefix search */ + int isScan, /* True to scan from zTerm to EOF */ + Fts3MultiSegReader *pCsr /* Cursor object to populate */ +){ + assert( iIndex>=0 && iIndexnIndex ); + assert( iLevel==FTS3_SEGCURSOR_ALL + || iLevel==FTS3_SEGCURSOR_PENDING + || iLevel>=0 + ); + assert( iLevelbase.pVtab; + + if( isPrefix ){ + for(i=1; bFound==0 && inIndex; i++){ + if( p->aIndex[i].nPrefix==nTerm ){ + bFound = 1; + rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, + i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr + ); + pSegcsr->bLookup = 1; } + } - if( aMode ){ - int i; - int mode = 0; - for(i=0; aMode[i].z; i++){ - const char *z = aMode[i].z; - if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ - mode = aMode[i].mode; - break; - } - } - if( mode==0 ){ - *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal); - rc = SQLITE_ERROR; - goto parse_uri_out; - } - if( (mode & ~SQLITE_OPEN_MEMORY)>limit ){ - *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s", - zModeType, zVal); - rc = SQLITE_PERM; - goto parse_uri_out; + for(i=1; bFound==0 && inIndex; i++){ + if( p->aIndex[i].nPrefix==nTerm+1 ){ + bFound = 1; + rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, + i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr + ); + if( rc==SQLITE_OK ){ + rc = fts3SegReaderCursorAddZero( + p, pCsr->iLangid, zTerm, nTerm, pSegcsr + ); } - flags = (flags & ~mask) | mode; } } - - zOpt = &zVal[nVal+1]; } - }else{ - zFile = sqlite3_malloc64(nUri+2); - if( !zFile ) return SQLITE_NOMEM_BKPT; - if( nUri ){ - memcpy(zFile, zUri, nUri); + if( bFound==0 ){ + rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, + 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr + ); + pSegcsr->bLookup = !isPrefix; } - zFile[nUri] = '\0'; - zFile[nUri+1] = '\0'; - flags &= ~SQLITE_OPEN_URI; } - *ppVfs = sqlite3_vfs_find(zVfs); - if( *ppVfs==0 ){ - *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); - rc = SQLITE_ERROR; - } - parse_uri_out: - if( rc!=SQLITE_OK ){ - sqlite3_free(zFile); - zFile = 0; - } - *pFlags = flags; - *pzFile = zFile; + *ppSegcsr = pSegcsr; return rc; } +/* +** Free an Fts3MultiSegReader allocated by fts3TermSegReaderCursor(). +*/ +static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ + sqlite3Fts3SegReaderFinish(pSegcsr); + sqlite3_free(pSegcsr); +} /* -** This routine does the work of opening a database on behalf of -** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" -** is UTF-8 encoded. +** This function retrieves the doclist for the specified term (or term +** prefix) from the database. */ -static int openDatabase( - const char *zFilename, /* Database filename UTF-8 encoded */ - sqlite3 **ppDb, /* OUT: Returned database handle */ - unsigned int flags, /* Operational flags */ - const char *zVfs /* Name of the VFS to use */ +static int fts3TermSelect( + Fts3Table *p, /* Virtual table handle */ + Fts3PhraseToken *pTok, /* Token to query for */ + int iColumn, /* Column to query (or -ve for all columns) */ + int *pnOut, /* OUT: Size of buffer at *ppOut */ + char **ppOut /* OUT: Malloced result buffer */ ){ - sqlite3 *db; /* Store allocated handle here */ int rc; /* Return code */ - int isThreadsafe; /* True for threadsafe connections */ - char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ - char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ - -#ifdef SQLITE_ENABLE_API_ARMOR - if( ppDb==0 ) return SQLITE_MISUSE_BKPT; -#endif - *ppDb = 0; -#ifndef SQLITE_OMIT_AUTOINIT - rc = sqlite3_initialize(); - if( rc ) return rc; -#endif - - /* Only allow sensible combinations of bits in the flags argument. - ** Throw an error if any non-sense combination is used. If we - ** do not block illegal combinations here, it could trigger - ** assert() statements in deeper layers. Sensible combinations - ** are: - ** - ** 1: SQLITE_OPEN_READONLY - ** 2: SQLITE_OPEN_READWRITE - ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE - */ - assert( SQLITE_OPEN_READONLY == 0x01 ); - assert( SQLITE_OPEN_READWRITE == 0x02 ); - assert( SQLITE_OPEN_CREATE == 0x04 ); - testcase( (1<<(flags&7))==0x02 ); /* READONLY */ - testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ - testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ - if( ((1<<(flags&7)) & 0x46)==0 ){ - return SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ - } - - if( sqlite3GlobalConfig.bCoreMutex==0 ){ - isThreadsafe = 0; - }else if( flags & SQLITE_OPEN_NOMUTEX ){ - isThreadsafe = 0; - }else if( flags & SQLITE_OPEN_FULLMUTEX ){ - isThreadsafe = 1; - }else{ - isThreadsafe = sqlite3GlobalConfig.bFullMutex; - } - if( flags & SQLITE_OPEN_PRIVATECACHE ){ - flags &= ~SQLITE_OPEN_SHAREDCACHE; - }else if( sqlite3GlobalConfig.sharedCacheEnabled ){ - flags |= SQLITE_OPEN_SHAREDCACHE; - } - - /* Remove harmful bits from the flags parameter - ** - ** The SQLITE_OPEN_NOMUTEX and SQLITE_OPEN_FULLMUTEX flags were - ** dealt with in the previous code block. Besides these, the only - ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, - ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, - ** SQLITE_OPEN_PRIVATECACHE, and some reserved bits. Silently mask - ** off all other flags. - */ - flags &= ~( SQLITE_OPEN_DELETEONCLOSE | - SQLITE_OPEN_EXCLUSIVE | - SQLITE_OPEN_MAIN_DB | - SQLITE_OPEN_TEMP_DB | - SQLITE_OPEN_TRANSIENT_DB | - SQLITE_OPEN_MAIN_JOURNAL | - SQLITE_OPEN_TEMP_JOURNAL | - SQLITE_OPEN_SUBJOURNAL | - SQLITE_OPEN_MASTER_JOURNAL | - SQLITE_OPEN_NOMUTEX | - SQLITE_OPEN_FULLMUTEX | - SQLITE_OPEN_WAL - ); + Fts3MultiSegReader *pSegcsr; /* Seg-reader cursor for this term */ + TermSelect tsc; /* Object for pair-wise doclist merging */ + Fts3SegFilter filter; /* Segment term filter configuration */ - /* Allocate the sqlite data structure */ - db = sqlite3MallocZero( sizeof(sqlite3) ); - if( db==0 ) goto opendb_out; - if( isThreadsafe ){ - db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); - if( db->mutex==0 ){ - sqlite3_free(db); - db = 0; - goto opendb_out; - } - } - sqlite3_mutex_enter(db->mutex); - db->errMask = 0xff; - db->nDb = 2; - db->magic = SQLITE_MAGIC_BUSY; - db->aDb = db->aDbStatic; + pSegcsr = pTok->pSegcsr; + memset(&tsc, 0, sizeof(TermSelect)); - assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); - memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); - db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; - db->autoCommit = 1; - db->nextAutovac = -1; - db->szMmap = sqlite3GlobalConfig.szMmap; - db->nextPagesize = 0; - db->nMaxSorterMmap = 0x7FFFFFFF; - db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill -#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX - | SQLITE_AutoIndex -#endif -#if SQLITE_DEFAULT_CKPTFULLFSYNC - | SQLITE_CkptFullFSync -#endif -#if SQLITE_DEFAULT_FILE_FORMAT<4 - | SQLITE_LegacyFileFmt -#endif -#ifdef SQLITE_ENABLE_LOAD_EXTENSION - | SQLITE_LoadExtension -#endif -#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS - | SQLITE_RecTriggers -#endif -#if defined(SQLITE_DEFAULT_FOREIGN_KEYS) && SQLITE_DEFAULT_FOREIGN_KEYS - | SQLITE_ForeignKeys -#endif -#if defined(SQLITE_REVERSE_UNORDERED_SELECTS) - | SQLITE_ReverseOrder -#endif -#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) - | SQLITE_CellSizeCk -#endif -#if defined(SQLITE_ENABLE_FTS3_TOKENIZER) - | SQLITE_Fts3Tokenizer -#endif - ; - sqlite3HashInit(&db->aCollSeq); -#ifndef SQLITE_OMIT_VIRTUALTABLE - sqlite3HashInit(&db->aModule); -#endif + filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS + | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) + | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0) + | (iColumnnColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); + filter.iCol = iColumn; + filter.zTerm = pTok->z; + filter.nTerm = pTok->n; - /* Add the default collation sequence BINARY. BINARY works for both UTF-8 - ** and UTF-16, so add a version for each to avoid any unnecessary - ** conversions. The only error that can occur here is a malloc() failure. - ** - ** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating - ** functions: - */ - createCollation(db, sqlite3StrBINARY, SQLITE_UTF8, 0, binCollFunc, 0); - createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); - createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); - createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); - createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0); - if( db->mallocFailed ){ - goto opendb_out; + rc = sqlite3Fts3SegReaderStart(p, pSegcsr, &filter); + while( SQLITE_OK==rc + && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr)) + ){ + rc = fts3TermSelectMerge(p, &tsc, pSegcsr->aDoclist, pSegcsr->nDoclist); } - /* EVIDENCE-OF: R-08308-17224 The default collating function for all - ** strings is BINARY. - */ - db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0); - assert( db->pDfltColl!=0 ); - /* Parse the filename/URI argument. */ - db->openFlags = flags; - rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); - if( rc!=SQLITE_OK ){ - if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); - sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); - sqlite3_free(zErrMsg); - goto opendb_out; + if( rc==SQLITE_OK ){ + rc = fts3TermSelectFinishMerge(p, &tsc); } - - /* Open the backend database driver */ - rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, - flags | SQLITE_OPEN_MAIN_DB); - if( rc!=SQLITE_OK ){ - if( rc==SQLITE_IOERR_NOMEM ){ - rc = SQLITE_NOMEM_BKPT; + if( rc==SQLITE_OK ){ + *ppOut = tsc.aaOutput[0]; + *pnOut = tsc.anOutput[0]; + }else{ + int i; + for(i=0; iaDb[0].pBt); - db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt); - if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db); - sqlite3BtreeLeave(db->aDb[0].pBt); - db->aDb[1].pSchema = sqlite3SchemaGet(db, 0); - /* The default safety_level for the main database is FULL; for the temp - ** database it is OFF. This matches the pager layer defaults. - */ - db->aDb[0].zDbSName = "main"; - db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; - db->aDb[1].zDbSName = "temp"; - db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; + fts3SegReaderCursorFree(pSegcsr); + pTok->pSegcsr = 0; + return rc; +} - db->magic = SQLITE_MAGIC_OPEN; - if( db->mallocFailed ){ - goto opendb_out; +/* +** This function counts the total number of docids in the doclist stored +** in buffer aList[], size nList bytes. +** +** If the isPoslist argument is true, then it is assumed that the doclist +** contains a position-list following each docid. Otherwise, it is assumed +** that the doclist is simply a list of docids stored as delta encoded +** varints. +*/ +static int fts3DoclistCountDocids(char *aList, int nList){ + int nDoc = 0; /* Return value */ + if( aList ){ + char *aEnd = &aList[nList]; /* Pointer to one byte after EOF */ + char *p = aList; /* Cursor */ + while( pmallocFailed && rc==SQLITE_OK ){ - rc = sqlite3Fts5Init(db); - } -#endif + return nDoc; +} - /* Load automatic extensions - extensions that have been registered - ** using the sqlite3_automatic_extension() API. - */ - if( rc==SQLITE_OK ){ - sqlite3AutoLoadExtensions(db); - rc = sqlite3_errcode(db); - if( rc!=SQLITE_OK ){ - goto opendb_out; +/* +** Advance the cursor to the next row in the %_content table that +** matches the search criteria. For a MATCH search, this will be +** the next row that matches. For a full-table scan, this will be +** simply the next row in the %_content table. For a docid lookup, +** this routine simply sets the EOF flag. +** +** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned +** even if we reach end-of-file. The fts3EofMethod() will be called +** subsequently to determine whether or not an EOF was hit. +*/ +static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){ + int rc; + Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; + if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){ + Fts3Table *pTab = (Fts3Table*)pCursor->pVtab; + pTab->bLock++; + if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){ + pCsr->isEof = 1; + rc = sqlite3_reset(pCsr->pStmt); + }else{ + pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); + rc = SQLITE_OK; } + pTab->bLock--; + }else{ + rc = fts3EvalNext((Fts3Cursor *)pCursor); } + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + return rc; +} -#ifdef SQLITE_ENABLE_FTS1 - if( !db->mallocFailed ){ - extern int sqlite3Fts1Init(sqlite3*); - rc = sqlite3Fts1Init(db); +/* +** If the numeric type of argument pVal is "integer", then return it +** converted to a 64-bit signed integer. Otherwise, return a copy of +** the second parameter, iDefault. +*/ +static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){ + if( pVal ){ + int eType = sqlite3_value_numeric_type(pVal); + if( eType==SQLITE_INTEGER ){ + return sqlite3_value_int64(pVal); + } } -#endif + return iDefault; +} -#ifdef SQLITE_ENABLE_FTS2 - if( !db->mallocFailed && rc==SQLITE_OK ){ - extern int sqlite3Fts2Init(sqlite3*); - rc = sqlite3Fts2Init(db); - } -#endif +/* +** This is the xFilter interface for the virtual table. See +** the virtual table xFilter method documentation for additional +** information. +** +** If idxNum==FTS3_FULLSCAN_SEARCH then do a full table scan against +** the %_content table. +** +** If idxNum==FTS3_DOCID_SEARCH then do a docid lookup for a single entry +** in the %_content table. +** +** If idxNum>=FTS3_FULLTEXT_SEARCH then use the full text index. The +** column on the left-hand side of the MATCH operator is column +** number idxNum-FTS3_FULLTEXT_SEARCH, 0 indexed. argv[0] is the right-hand +** side of the MATCH operator. +*/ +static int fts3FilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *idxStr, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + int rc = SQLITE_OK; + char *zSql; /* SQL statement used to access %_content */ + int eSearch; + Fts3Table *p = (Fts3Table *)pCursor->pVtab; + Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; -#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */ - if( !db->mallocFailed && rc==SQLITE_OK ){ - rc = sqlite3Fts3Init(db); - } -#endif + sqlite3_value *pCons = 0; /* The MATCH or rowid constraint, if any */ + sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */ + sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */ + sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */ + int iIdx; -#ifdef SQLITE_ENABLE_ICU - if( !db->mallocFailed && rc==SQLITE_OK ){ - rc = sqlite3IcuInit(db); - } -#endif + UNUSED_PARAMETER(idxStr); + UNUSED_PARAMETER(nVal); -#ifdef SQLITE_ENABLE_RTREE - if( !db->mallocFailed && rc==SQLITE_OK){ - rc = sqlite3RtreeInit(db); + if( p->bLock ){ + return SQLITE_ERROR; } -#endif -#ifdef SQLITE_ENABLE_DBSTAT_VTAB - if( !db->mallocFailed && rc==SQLITE_OK){ - rc = sqlite3DbstatRegister(db); - } -#endif + eSearch = (idxNum & 0x0000FFFF); + assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); + assert( p->pSegments==0 ); -#ifdef SQLITE_ENABLE_JSON1 - if( !db->mallocFailed && rc==SQLITE_OK){ - rc = sqlite3Json1Init(db); - } -#endif + /* Collect arguments into local variables */ + iIdx = 0; + if( eSearch!=FTS3_FULLSCAN_SEARCH ) pCons = apVal[iIdx++]; + if( idxNum & FTS3_HAVE_LANGID ) pLangid = apVal[iIdx++]; + if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++]; + if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++]; + assert( iIdx==nVal ); - /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking - ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking - ** mode. Doing nothing at all also makes NORMAL the default. - */ -#ifdef SQLITE_DEFAULT_LOCKING_MODE - db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE; - sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt), - SQLITE_DEFAULT_LOCKING_MODE); -#endif + /* In case the cursor has been used before, clear it now. */ + fts3ClearCursor(pCsr); - if( rc ) sqlite3Error(db, rc); + /* Set the lower and upper bounds on docids to return */ + pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); + pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64); - /* Enable the lookaside-malloc subsystem */ - setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside, - sqlite3GlobalConfig.nLookaside); + if( idxStr ){ + pCsr->bDesc = (idxStr[0]=='D'); + }else{ + pCsr->bDesc = p->bDescIdx; + } + pCsr->eSearch = (i16)eSearch; - sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); + if( eSearch!=FTS3_DOCID_SEARCH && eSearch!=FTS3_FULLSCAN_SEARCH ){ + int iCol = eSearch-FTS3_FULLTEXT_SEARCH; + const char *zQuery = (const char *)sqlite3_value_text(pCons); -opendb_out: - if( db ){ - assert( db->mutex!=0 || isThreadsafe==0 - || sqlite3GlobalConfig.bFullMutex==0 ); - sqlite3_mutex_leave(db->mutex); - } - rc = sqlite3_errcode(db); - assert( db!=0 || rc==SQLITE_NOMEM ); - if( rc==SQLITE_NOMEM ){ - sqlite3_close(db); - db = 0; - }else if( rc!=SQLITE_OK ){ - db->magic = SQLITE_MAGIC_SICK; - } - *ppDb = db; -#ifdef SQLITE_ENABLE_SQLLOG - if( sqlite3GlobalConfig.xSqllog ){ - /* Opening a db handle. Fourth parameter is passed 0. */ - void *pArg = sqlite3GlobalConfig.pSqllogArg; - sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0); + if( zQuery==0 && sqlite3_value_type(pCons)!=SQLITE_NULL ){ + return SQLITE_NOMEM; + } + + pCsr->iLangid = 0; + if( pLangid ) pCsr->iLangid = sqlite3_value_int(pLangid); + + assert( p->base.zErrMsg==0 ); + rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, + p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, + &p->base.zErrMsg + ); + if( rc!=SQLITE_OK ){ + return rc; + } + + rc = fts3EvalStart(pCsr); + sqlite3Fts3SegmentsClose(p); + if( rc!=SQLITE_OK ) return rc; + pCsr->pNextId = pCsr->aDoclist; + pCsr->iPrevId = 0; } -#endif -#if defined(SQLITE_HAS_CODEC) - if( rc==SQLITE_OK ){ - const char *zHexKey = sqlite3_uri_parameter(zOpen, "hexkey"); - if( zHexKey && zHexKey[0] ){ - u8 iByte; - int i; - char zKey[40]; - for(i=0, iByte=0; izReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid, + (pCsr->bDesc ? "DESC" : "ASC") + ); + }else{ + zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", + p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") + ); + } + if( zSql ){ + p->bLock++; + rc = sqlite3_prepare_v3( + p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 + ); + p->bLock--; + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + }else if( eSearch==FTS3_DOCID_SEARCH ){ + rc = fts3CursorSeekStmt(pCsr); + if( rc==SQLITE_OK ){ + rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons); } } -#endif - sqlite3_free(zOpen); - return rc & 0xff; + if( rc!=SQLITE_OK ) return rc; + + return fts3NextMethod(pCursor); } /* -** Open a new database handle. +** This is the xEof method of the virtual table. SQLite calls this +** routine to find out if it has reached the end of a result set. */ -SQLITE_API int sqlite3_open( - const char *zFilename, - sqlite3 **ppDb -){ - return openDatabase(zFilename, ppDb, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); +static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){ + Fts3Cursor *pCsr = (Fts3Cursor*)pCursor; + if( pCsr->isEof ){ + fts3ClearCursor(pCsr); + pCsr->isEof = 1; + } + return pCsr->isEof; } -SQLITE_API int sqlite3_open_v2( - const char *filename, /* Database filename (UTF-8) */ - sqlite3 **ppDb, /* OUT: SQLite db handle */ - int flags, /* Flags */ - const char *zVfs /* Name of VFS module to use */ -){ - return openDatabase(filename, ppDb, (unsigned int)flags, zVfs); + +/* +** This is the xRowid method. The SQLite core calls this routine to +** retrieve the rowid for the current row of the result set. fts3 +** exposes %_content.docid as the rowid for the virtual table. The +** rowid should be written to *pRowid. +*/ +static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; + *pRowid = pCsr->iPrevId; + return SQLITE_OK; } -#ifndef SQLITE_OMIT_UTF16 /* -** Open a new database handle. +** This is the xColumn method, called by SQLite to request a value from +** the row that the supplied cursor currently points to. +** +** If: +** +** (iCol < p->nColumn) -> The value of the iCol'th user column. +** (iCol == p->nColumn) -> Magic column with the same name as the table. +** (iCol == p->nColumn+1) -> Docid column +** (iCol == p->nColumn+2) -> Langid column */ -SQLITE_API int sqlite3_open16( - const void *zFilename, - sqlite3 **ppDb +static int fts3ColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ ){ - char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ - sqlite3_value *pVal; - int rc; + int rc = SQLITE_OK; /* Return Code */ + Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; + Fts3Table *p = (Fts3Table *)pCursor->pVtab; -#ifdef SQLITE_ENABLE_API_ARMOR - if( ppDb==0 ) return SQLITE_MISUSE_BKPT; -#endif - *ppDb = 0; -#ifndef SQLITE_OMIT_AUTOINIT - rc = sqlite3_initialize(); - if( rc ) return rc; -#endif - if( zFilename==0 ) zFilename = "\000\000"; - pVal = sqlite3ValueNew(0); - sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); - zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); - if( zFilename8 ){ - rc = openDatabase(zFilename8, ppDb, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); - assert( *ppDb || rc==SQLITE_NOMEM ); - if( rc==SQLITE_OK && !DbHasProperty(*ppDb, 0, DB_SchemaLoaded) ){ - SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE; - } - }else{ - rc = SQLITE_NOMEM_BKPT; + /* The column value supplied by SQLite must be in range. */ + assert( iCol>=0 && iCol<=p->nColumn+2 ); + + switch( iCol-p->nColumn ){ + case 0: + /* The special 'table-name' column */ + sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0); + break; + + case 1: + /* The docid column */ + sqlite3_result_int64(pCtx, pCsr->iPrevId); + break; + + case 2: + if( pCsr->pExpr ){ + sqlite3_result_int64(pCtx, pCsr->iLangid); + break; + }else if( p->zLanguageid==0 ){ + sqlite3_result_int(pCtx, 0); + break; + }else{ + iCol = p->nColumn; + /* no break */ deliberate_fall_through + } + + default: + /* A user column. Or, if this is a full-table scan, possibly the + ** language-id column. Seek the cursor. */ + rc = fts3CursorSeek(0, pCsr); + if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){ + sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); + } + break; } - sqlite3ValueFree(pVal); - return rc & 0xff; + assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); + return rc; } -#endif /* SQLITE_OMIT_UTF16 */ /* -** Register a new collation sequence with the database handle db. +** This function is the implementation of the xUpdate callback used by +** FTS3 virtual tables. It is invoked by SQLite each time a row is to be +** inserted, updated or deleted. */ -SQLITE_API int sqlite3_create_collation( - sqlite3* db, - const char *zName, - int enc, - void* pCtx, - int(*xCompare)(void*,int,const void*,int,const void*) +static int fts3UpdateMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nArg, /* Size of argument array */ + sqlite3_value **apVal, /* Array of arguments */ + sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ - return sqlite3_create_collation_v2(db, zName, enc, pCtx, xCompare, 0); + return sqlite3Fts3UpdateMethod(pVtab, nArg, apVal, pRowid); } /* -** Register a new collation sequence with the database handle db. +** Implementation of xSync() method. Flush the contents of the pending-terms +** hash-table to the database. */ -SQLITE_API int sqlite3_create_collation_v2( - sqlite3* db, - const char *zName, - int enc, - void* pCtx, - int(*xCompare)(void*,int,const void*,int,const void*), - void(*xDel)(void*) -){ +static int fts3SyncMethod(sqlite3_vtab *pVtab){ + + /* Following an incremental-merge operation, assuming that the input + ** segments are not completely consumed (the usual case), they are updated + ** in place to remove the entries that have already been merged. This + ** involves updating the leaf block that contains the smallest unmerged + ** entry and each block (if any) between the leaf and the root node. So + ** if the height of the input segment b-trees is N, and input segments + ** are merged eight at a time, updating the input segments at the end + ** of an incremental-merge requires writing (8*(1+N)) blocks. N is usually + ** small - often between 0 and 2. So the overhead of the incremental + ** merge is somewhere between 8 and 24 blocks. To avoid this overhead + ** dwarfing the actual productive work accomplished, the incremental merge + ** is only attempted if it will write at least 64 leaf blocks. Hence + ** nMinMerge. + ** + ** Of course, updating the input segments also involves deleting a bunch + ** of blocks from the segments table. But this is not considered overhead + ** as it would also be required by a crisis-merge that used the same input + ** segments. + */ + const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */ + + Fts3Table *p = (Fts3Table*)pVtab; int rc; + i64 iLastRowid = sqlite3_last_insert_rowid(p->db); -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - assert( !db->mallocFailed ); - rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel); - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); + rc = sqlite3Fts3PendingTermsFlush(p); + if( rc==SQLITE_OK + && p->nLeafAdd>(nMinMerge/16) + && p->nAutoincrmerge && p->nAutoincrmerge!=0xff + ){ + int mxLevel = 0; /* Maximum relative level value in db */ + int A; /* Incr-merge parameter A */ + + rc = sqlite3Fts3MaxLevel(p, &mxLevel); + assert( rc==SQLITE_OK || mxLevel==0 ); + A = p->nLeafAdd * mxLevel; + A += (A/2); + if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); + } + sqlite3Fts3SegmentsClose(p); + sqlite3_set_last_insert_rowid(p->db, iLastRowid); return rc; } -#ifndef SQLITE_OMIT_UTF16 /* -** Register a new collation sequence with the database handle db. +** If it is currently unknown whether or not the FTS table has an %_stat +** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat +** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code +** if an error occurs. */ -SQLITE_API int sqlite3_create_collation16( - sqlite3* db, - const void *zName, - int enc, - void* pCtx, - int(*xCompare)(void*,int,const void*,int,const void*) -){ +static int fts3SetHasStat(Fts3Table *p){ int rc = SQLITE_OK; - char *zName8; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - assert( !db->mallocFailed ); - zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE); - if( zName8 ){ - rc = createCollation(db, zName8, (u8)enc, pCtx, xCompare, 0); - sqlite3DbFree(db, zName8); + if( p->bHasStat==2 ){ + char *zTbl = sqlite3_mprintf("%s_stat", p->zName); + if( zTbl ){ + int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0); + sqlite3_free(zTbl); + p->bHasStat = (res==SQLITE_OK); + }else{ + rc = SQLITE_NOMEM; + } } - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); return rc; } -#endif /* SQLITE_OMIT_UTF16 */ /* -** Register a collation sequence factory callback with the database handle -** db. Replace any previously installed collation sequence factory. +** Implementation of xBegin() method. */ -SQLITE_API int sqlite3_collation_needed( - sqlite3 *db, - void *pCollNeededArg, - void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*) -){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; +static int fts3BeginMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table*)pVtab; + int rc; + UNUSED_PARAMETER(pVtab); + assert( p->pSegments==0 ); + assert( p->nPendingData==0 ); + assert( p->inTransaction!=1 ); + p->nLeafAdd = 0; + rc = fts3SetHasStat(p); +#ifdef SQLITE_DEBUG + if( rc==SQLITE_OK ){ + p->inTransaction = 1; + p->mxSavepoint = -1; + } #endif - sqlite3_mutex_enter(db->mutex); - db->xCollNeeded = xCollNeeded; - db->xCollNeeded16 = 0; - db->pCollNeededArg = pCollNeededArg; - sqlite3_mutex_leave(db->mutex); - return SQLITE_OK; + return rc; } -#ifndef SQLITE_OMIT_UTF16 /* -** Register a collation sequence factory callback with the database handle -** db. Replace any previously installed collation sequence factory. +** Implementation of xCommit() method. This is a no-op. The contents of +** the pending-terms hash-table have already been flushed into the database +** by fts3SyncMethod(). */ -SQLITE_API int sqlite3_collation_needed16( - sqlite3 *db, - void *pCollNeededArg, - void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*) -){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - db->xCollNeeded = 0; - db->xCollNeeded16 = xCollNeeded16; - db->pCollNeededArg = pCollNeededArg; - sqlite3_mutex_leave(db->mutex); +static int fts3CommitMethod(sqlite3_vtab *pVtab){ + TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); + UNUSED_PARAMETER(pVtab); + assert( p->nPendingData==0 ); + assert( p->inTransaction!=0 ); + assert( p->pSegments==0 ); + TESTONLY( p->inTransaction = 0 ); + TESTONLY( p->mxSavepoint = -1; ); return SQLITE_OK; } -#endif /* SQLITE_OMIT_UTF16 */ -#ifndef SQLITE_OMIT_DEPRECATED /* -** This function is now an anachronism. It used to be used to recover from a -** malloc() failure, but SQLite now does this automatically. +** Implementation of xRollback(). Discard the contents of the pending-terms +** hash-table. Any changes made to the database are reverted by SQLite. */ -SQLITE_API int sqlite3_global_recover(void){ +static int fts3RollbackMethod(sqlite3_vtab *pVtab){ + Fts3Table *p = (Fts3Table*)pVtab; + sqlite3Fts3PendingTermsClear(p); + assert( p->inTransaction!=0 ); + TESTONLY( p->inTransaction = 0 ); + TESTONLY( p->mxSavepoint = -1; ); return SQLITE_OK; } -#endif /* -** Test to see whether or not the database connection is in autocommit -** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on -** by default. Autocommit is disabled by a BEGIN statement and reenabled -** by the next COMMIT or ROLLBACK. +** When called, *ppPoslist must point to the byte immediately following the +** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function +** moves *ppPoslist so that it instead points to the first byte of the +** same position list. */ -SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; +static void fts3ReversePoslist(char *pStart, char **ppPoslist){ + char *p = &(*ppPoslist)[-2]; + char c = 0; + + /* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */ + while( p>pStart && (c=*p--)==0 ); + + /* Search backwards for a varint with value zero (the end of the previous + ** poslist). This is an 0x00 byte preceded by some byte that does not + ** have the 0x80 bit set. */ + while( p>pStart && (*p & 0x80) | c ){ + c = *p--; } -#endif - return db->autoCommit; + assert( p==pStart || c==0 ); + + /* At this point p points to that preceding byte without the 0x80 bit + ** set. So to find the start of the poslist, skip forward 2 bytes then + ** over a varint. + ** + ** Normally. The other case is that p==pStart and the poslist to return + ** is the first in the doclist. In this case do not skip forward 2 bytes. + ** The second part of the if condition (c==0 && *ppPoslist>&p[2]) + ** is required for cases where the first byte of a doclist and the + ** doclist is empty. For example, if the first docid is 10, a doclist + ** that begins with: + ** + ** 0x0A 0x00 + */ + if( p>pStart || (c==0 && *ppPoslist>&p[2]) ){ p = &p[2]; } + while( *p++&0x80 ); + *ppPoslist = p; } /* -** The following routines are substitutes for constants SQLITE_CORRUPT, -** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error -** constants. They serve two purposes: -** -** 1. Serve as a convenient place to set a breakpoint in a debugger -** to detect when version error conditions occurs. +** Helper function used by the implementation of the overloaded snippet(), +** offsets() and optimize() SQL functions. ** -** 2. Invoke sqlite3_log() to provide the source code location where -** a low-level error is first detected. +** If the value passed as the third argument is a blob of size +** sizeof(Fts3Cursor*), then the blob contents are copied to the +** output variable *ppCsr and SQLITE_OK is returned. Otherwise, an error +** message is written to context pContext and SQLITE_ERROR returned. The +** string passed via zFunc is used as part of the error message. */ -static int reportError(int iErr, int lineno, const char *zType){ - sqlite3_log(iErr, "%s at line %d of [%.10s]", - zType, lineno, 20+sqlite3_sourceid()); - return iErr; -} -SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ - testcase( sqlite3GlobalConfig.xLog!=0 ); - return reportError(SQLITE_CORRUPT, lineno, "database corruption"); -} -SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ - testcase( sqlite3GlobalConfig.xLog!=0 ); - return reportError(SQLITE_MISUSE, lineno, "misuse"); -} -SQLITE_PRIVATE int sqlite3CantopenError(int lineno){ - testcase( sqlite3GlobalConfig.xLog!=0 ); - return reportError(SQLITE_CANTOPEN, lineno, "cannot open file"); -} -#ifdef SQLITE_DEBUG -SQLITE_PRIVATE int sqlite3NomemError(int lineno){ - testcase( sqlite3GlobalConfig.xLog!=0 ); - return reportError(SQLITE_NOMEM, lineno, "OOM"); -} -SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){ - testcase( sqlite3GlobalConfig.xLog!=0 ); - return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error"); +static int fts3FunctionArg( + sqlite3_context *pContext, /* SQL function call context */ + const char *zFunc, /* Function name */ + sqlite3_value *pVal, /* argv[0] passed to function */ + Fts3Cursor **ppCsr /* OUT: Store cursor handle here */ +){ + int rc; + *ppCsr = (Fts3Cursor*)sqlite3_value_pointer(pVal, "fts3cursor"); + if( (*ppCsr)!=0 ){ + rc = SQLITE_OK; + }else{ + char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc); + sqlite3_result_error(pContext, zErr, -1); + sqlite3_free(zErr); + rc = SQLITE_ERROR; + } + return rc; } -#endif -#ifndef SQLITE_OMIT_DEPRECATED /* -** This is a convenience routine that makes sure that all thread-specific -** data for this thread has been deallocated. -** -** SQLite no longer uses thread-specific data so this routine is now a -** no-op. It is retained for historical compatibility. +** Implementation of the snippet() function for FTS3 */ -SQLITE_API void sqlite3_thread_cleanup(void){ +static void fts3SnippetFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of apVal[] array */ + sqlite3_value **apVal /* Array of arguments */ +){ + Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ + const char *zStart = ""; + const char *zEnd = ""; + const char *zEllipsis = "..."; + int iCol = -1; + int nToken = 15; /* Default number of tokens in snippet */ + + /* There must be at least one argument passed to this function (otherwise + ** the non-overloaded version would have been called instead of this one). + */ + assert( nVal>=1 ); + + if( nVal>6 ){ + sqlite3_result_error(pContext, + "wrong number of arguments to function snippet()", -1); + return; + } + if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return; + + switch( nVal ){ + case 6: nToken = sqlite3_value_int(apVal[5]); + /* no break */ deliberate_fall_through + case 5: iCol = sqlite3_value_int(apVal[4]); + /* no break */ deliberate_fall_through + case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); + /* no break */ deliberate_fall_through + case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]); + /* no break */ deliberate_fall_through + case 2: zStart = (const char*)sqlite3_value_text(apVal[1]); + } + if( !zEllipsis || !zEnd || !zStart ){ + sqlite3_result_error_nomem(pContext); + }else if( nToken==0 ){ + sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); + }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ + sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken); + } } -#endif /* -** Return meta information about a specific column of a database table. -** See comment in sqlite3.h (sqlite.h.in) for details. +** Implementation of the offsets() function for FTS3 */ -SQLITE_API int sqlite3_table_column_metadata( - sqlite3 *db, /* Connection handle */ - const char *zDbName, /* Database name or NULL */ - const char *zTableName, /* Table name */ - const char *zColumnName, /* Column name */ - char const **pzDataType, /* OUTPUT: Declared data type */ - char const **pzCollSeq, /* OUTPUT: Collation sequence name */ - int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ - int *pPrimaryKey, /* OUTPUT: True if column part of PK */ - int *pAutoinc /* OUTPUT: True if column is auto-increment */ +static void fts3OffsetsFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of argument array */ + sqlite3_value **apVal /* Array of arguments */ ){ - int rc; - char *zErrMsg = 0; - Table *pTab = 0; - Column *pCol = 0; - int iCol = 0; - char const *zDataType = 0; - char const *zCollSeq = 0; - int notnull = 0; - int primarykey = 0; - int autoinc = 0; + Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ + UNUSED_PARAMETER(nVal); -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) || zTableName==0 ){ - return SQLITE_MISUSE_BKPT; + assert( nVal==1 ); + if( fts3FunctionArg(pContext, "offsets", apVal[0], &pCsr) ) return; + assert( pCsr ); + if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ + sqlite3Fts3Offsets(pContext, pCsr); } -#endif +} - /* Ensure the database schema has been loaded */ - sqlite3_mutex_enter(db->mutex); - sqlite3BtreeEnterAll(db); - rc = sqlite3Init(db, &zErrMsg); - if( SQLITE_OK!=rc ){ - goto error_out; - } +/* +** Implementation of the special optimize() function for FTS3. This +** function merges all segments in the database to a single segment. +** Example usage is: +** +** SELECT optimize(t) FROM t LIMIT 1; +** +** where 't' is the name of an FTS3 table. +*/ +static void fts3OptimizeFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of argument array */ + sqlite3_value **apVal /* Array of arguments */ +){ + int rc; /* Return code */ + Fts3Table *p; /* Virtual table handle */ + Fts3Cursor *pCursor; /* Cursor handle passed through apVal[0] */ - /* Locate the table in question */ - pTab = sqlite3FindTable(db, zTableName, zDbName); - if( !pTab || pTab->pSelect ){ - pTab = 0; - goto error_out; + UNUSED_PARAMETER(nVal); + + assert( nVal==1 ); + if( fts3FunctionArg(pContext, "optimize", apVal[0], &pCursor) ) return; + p = (Fts3Table *)pCursor->base.pVtab; + assert( p ); + + rc = sqlite3Fts3Optimize(p); + + switch( rc ){ + case SQLITE_OK: + sqlite3_result_text(pContext, "Index optimized", -1, SQLITE_STATIC); + break; + case SQLITE_DONE: + sqlite3_result_text(pContext, "Index already optimal", -1, SQLITE_STATIC); + break; + default: + sqlite3_result_error_code(pContext, rc); + break; } +} - /* Find the column for which info is requested */ - if( zColumnName==0 ){ - /* Query for existance of table only */ - }else{ - for(iCol=0; iColnCol; iCol++){ - pCol = &pTab->aCol[iCol]; - if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){ - break; - } - } - if( iCol==pTab->nCol ){ - if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ - iCol = pTab->iPKey; - pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; - }else{ - pTab = 0; - goto error_out; - } +/* +** Implementation of the matchinfo() function for FTS3 +*/ +static void fts3MatchinfoFunc( + sqlite3_context *pContext, /* SQLite function call context */ + int nVal, /* Size of argument array */ + sqlite3_value **apVal /* Array of arguments */ +){ + Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ + assert( nVal==1 || nVal==2 ); + if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){ + const char *zArg = 0; + if( nVal>1 ){ + zArg = (const char *)sqlite3_value_text(apVal[1]); } + sqlite3Fts3Matchinfo(pContext, pCsr, zArg); } +} - /* The following block stores the meta information that will be returned - ** to the caller in local variables zDataType, zCollSeq, notnull, primarykey - ** and autoinc. At this point there are two possibilities: - ** - ** 1. The specified column name was rowid", "oid" or "_rowid_" - ** and there is no explicitly declared IPK column. - ** - ** 2. The table is not a view and the column name identified an - ** explicitly declared column. Copy meta information from *pCol. - */ - if( pCol ){ - zDataType = sqlite3ColumnType(pCol,0); - zCollSeq = pCol->zColl; - notnull = pCol->notNull!=0; - primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; - autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; - }else{ - zDataType = "INTEGER"; - primarykey = 1; - } - if( !zCollSeq ){ - zCollSeq = sqlite3StrBINARY; +/* +** This routine implements the xFindFunction method for the FTS3 +** virtual table. +*/ +static int fts3FindFunctionMethod( + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nArg, /* Number of SQL function arguments */ + const char *zName, /* Name of SQL function */ + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ + void **ppArg /* Unused */ +){ + struct Overloaded { + const char *zName; + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + } aOverload[] = { + { "snippet", fts3SnippetFunc }, + { "offsets", fts3OffsetsFunc }, + { "optimize", fts3OptimizeFunc }, + { "matchinfo", fts3MatchinfoFunc }, + }; + int i; /* Iterator variable */ + + UNUSED_PARAMETER(pVtab); + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(ppArg); + + for(i=0; idb; /* Database connection */ + int rc; /* Return Code */ + + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + rc = fts3SetHasStat(p); + + /* As it happens, the pending terms table is always empty here. This is + ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction + ** always opens a savepoint transaction. And the xSavepoint() method + ** flushes the pending terms table. But leave the (no-op) call to + ** PendingTermsFlush() in in case that changes. */ - if( pzDataType ) *pzDataType = zDataType; - if( pzCollSeq ) *pzCollSeq = zCollSeq; - if( pNotNull ) *pNotNull = notnull; - if( pPrimaryKey ) *pPrimaryKey = primarykey; - if( pAutoinc ) *pAutoinc = autoinc; + assert( p->nPendingData==0 ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3PendingTermsFlush(p); + } - if( SQLITE_OK==rc && !pTab ){ - sqlite3DbFree(db, zErrMsg); - zErrMsg = sqlite3MPrintf(db, "no such table column: %s.%s", zTableName, - zColumnName); - rc = SQLITE_ERROR; + if( p->zContentTbl==0 ){ + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", + p->zDb, p->zName, zName + ); } - sqlite3ErrorWithMsg(db, rc, (zErrMsg?"%s":0), zErrMsg); - sqlite3DbFree(db, zErrMsg); - rc = sqlite3ApiExit(db, rc); - sqlite3_mutex_leave(db->mutex); + + if( p->bHasDocsize ){ + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", + p->zDb, p->zName, zName + ); + } + if( p->bHasStat ){ + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_stat' RENAME TO '%q_stat';", + p->zDb, p->zName, zName + ); + } + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';", + p->zDb, p->zName, zName + ); + fts3DbExec(&rc, db, + "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", + p->zDb, p->zName, zName + ); return rc; } /* -** Sleep for a little while. Return the amount of time slept. +** The xSavepoint() method. +** +** Flush the contents of the pending-terms table to disk. */ -SQLITE_API int sqlite3_sleep(int ms){ - sqlite3_vfs *pVfs; - int rc; - pVfs = sqlite3_vfs_find(0); - if( pVfs==0 ) return 0; - - /* This function works in milliseconds, but the underlying OsSleep() - ** API uses microseconds. Hence the 1000's. - */ - rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000); +static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ + int rc = SQLITE_OK; + UNUSED_PARAMETER(iSavepoint); + assert( ((Fts3Table *)pVtab)->inTransaction ); + assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint ); + TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint ); + if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){ + rc = fts3SyncMethod(pVtab); + } return rc; } /* -** Enable or disable the extended result codes. +** The xRelease() method. +** +** This is a no-op. */ -SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - db->errMask = onoff ? 0xffffffff : 0xff; - sqlite3_mutex_leave(db->mutex); +static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ + TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); + UNUSED_PARAMETER(iSavepoint); + UNUSED_PARAMETER(pVtab); + assert( p->inTransaction ); + assert( p->mxSavepoint >= iSavepoint ); + TESTONLY( p->mxSavepoint = iSavepoint-1 ); return SQLITE_OK; } /* -** Invoke the xFileControl method on a particular database. +** The xRollbackTo() method. +** +** Discard the contents of the pending terms table. */ -SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){ - int rc = SQLITE_ERROR; - Btree *pBtree; - -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; -#endif - sqlite3_mutex_enter(db->mutex); - pBtree = sqlite3DbNameToBtree(db, zDbName); - if( pBtree ){ - Pager *pPager; - sqlite3_file *fd; - sqlite3BtreeEnter(pBtree); - pPager = sqlite3BtreePager(pBtree); - assert( pPager!=0 ); - fd = sqlite3PagerFile(pPager); - assert( fd!=0 ); - if( op==SQLITE_FCNTL_FILE_POINTER ){ - *(sqlite3_file**)pArg = fd; - rc = SQLITE_OK; - }else if( op==SQLITE_FCNTL_VFS_POINTER ){ - *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); - rc = SQLITE_OK; - }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ - *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); - rc = SQLITE_OK; - }else if( fd->pMethods ){ - rc = sqlite3OsFileControl(fd, op, pArg); - }else{ - rc = SQLITE_NOTFOUND; - } - sqlite3BtreeLeave(pBtree); - } - sqlite3_mutex_leave(db->mutex); - return rc; +static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ + Fts3Table *p = (Fts3Table*)pVtab; + UNUSED_PARAMETER(iSavepoint); + assert( p->inTransaction ); + TESTONLY( p->mxSavepoint = iSavepoint ); + sqlite3Fts3PendingTermsClear(p); + return SQLITE_OK; } /* -** Interface to the testing logic. +** Return true if zName is the extension on one of the shadow tables used +** by this module. */ -SQLITE_API int sqlite3_test_control(int op, ...){ - int rc = 0; -#ifdef SQLITE_UNTESTABLE - UNUSED_PARAMETER(op); -#else - va_list ap; - va_start(ap, op); - switch( op ){ - - /* - ** Save the current state of the PRNG. - */ - case SQLITE_TESTCTRL_PRNG_SAVE: { - sqlite3PrngSaveState(); - break; - } - - /* - ** Restore the state of the PRNG to the last state saved using - ** PRNG_SAVE. If PRNG_SAVE has never before been called, then - ** this verb acts like PRNG_RESET. - */ - case SQLITE_TESTCTRL_PRNG_RESTORE: { - sqlite3PrngRestoreState(); - break; - } - - /* - ** Reset the PRNG back to its uninitialized state. The next call - ** to sqlite3_randomness() will reseed the PRNG using a single call - ** to the xRandomness method of the default VFS. - */ - case SQLITE_TESTCTRL_PRNG_RESET: { - sqlite3_randomness(0,0); - break; - } - - /* - ** sqlite3_test_control(BITVEC_TEST, size, program) - ** - ** Run a test against a Bitvec object of size. The program argument - ** is an array of integers that defines the test. Return -1 on a - ** memory allocation error, 0 on success, or non-zero for an error. - ** See the sqlite3BitvecBuiltinTest() for additional information. - */ - case SQLITE_TESTCTRL_BITVEC_TEST: { - int sz = va_arg(ap, int); - int *aProg = va_arg(ap, int*); - rc = sqlite3BitvecBuiltinTest(sz, aProg); - break; - } +static int fts3ShadowName(const char *zName){ + static const char *azName[] = { + "content", "docsize", "segdir", "segments", "stat", + }; + unsigned int i; + for(i=0; inRef--; + if( pHash->nRef<=0 ){ + sqlite3Fts3HashClear(&pHash->hash); + sqlite3_free(pHash); + } +} - /* - ** sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, unsigned int X) - ** - ** Set the PENDING byte to the value in the argument, if X>0. - ** Make no changes if X==0. Return the value of the pending byte - ** as it existing before this routine was called. - ** - ** IMPORTANT: Changing the PENDING byte from 0x40000000 results in - ** an incompatible database file format. Changing the PENDING byte - ** while any database connection is open results in undefined and - ** deleterious behavior. - */ - case SQLITE_TESTCTRL_PENDING_BYTE: { - rc = PENDING_BYTE; -#ifndef SQLITE_OMIT_WSD - { - unsigned int newVal = va_arg(ap, unsigned int); - if( newVal ) sqlite3PendingByte = newVal; - } +/* +** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are +** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c +** respectively. The following three forward declarations are for functions +** declared in these files used to retrieve the respective implementations. +** +** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed +** to by the argument to point to the "simple" tokenizer implementation. +** And so on. +*/ +SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); +SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); +#ifndef SQLITE_DISABLE_FTS3_UNICODE +SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); +#endif +#ifdef SQLITE_ENABLE_ICU +SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); #endif - break; - } - - /* - ** sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, int X) - ** - ** This action provides a run-time test to see whether or not - ** assert() was enabled at compile-time. If X is true and assert() - ** is enabled, then the return value is true. If X is true and - ** assert() is disabled, then the return value is zero. If X is - ** false and assert() is enabled, then the assertion fires and the - ** process aborts. If X is false and assert() is disabled, then the - ** return value is zero. - */ - case SQLITE_TESTCTRL_ASSERT: { - volatile int x = 0; - assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); - rc = x; - break; - } - - - /* - ** sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X) - ** - ** This action provides a run-time test to see how the ALWAYS and - ** NEVER macros were defined at compile-time. - ** - ** The return value is ALWAYS(X). - ** - ** The recommended test is X==2. If the return value is 2, that means - ** ALWAYS() and NEVER() are both no-op pass-through macros, which is the - ** default setting. If the return value is 1, then ALWAYS() is either - ** hard-coded to true or else it asserts if its argument is false. - ** The first behavior (hard-coded to true) is the case if - ** SQLITE_TESTCTRL_ASSERT shows that assert() is disabled and the second - ** behavior (assert if the argument to ALWAYS() is false) is the case if - ** SQLITE_TESTCTRL_ASSERT shows that assert() is enabled. - ** - ** The run-time test procedure might look something like this: - ** - ** if( sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, 2)==2 ){ - ** // ALWAYS() and NEVER() are no-op pass-through macros - ** }else if( sqlite3_test_control(SQLITE_TESTCTRL_ASSERT, 1) ){ - ** // ALWAYS(x) asserts that x is true. NEVER(x) asserts x is false. - ** }else{ - ** // ALWAYS(x) is a constant 1. NEVER(x) is a constant 0. - ** } - */ - case SQLITE_TESTCTRL_ALWAYS: { - int x = va_arg(ap,int); - rc = ALWAYS(x); - break; - } - /* - ** sqlite3_test_control(SQLITE_TESTCTRL_BYTEORDER); - ** - ** The integer returned reveals the byte-order of the computer on which - ** SQLite is running: - ** - ** 1 big-endian, determined at run-time - ** 10 little-endian, determined at run-time - ** 432101 big-endian, determined at compile-time - ** 123410 little-endian, determined at compile-time - */ - case SQLITE_TESTCTRL_BYTEORDER: { - rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN; - break; - } +/* +** Initialize the fts3 extension. If this extension is built as part +** of the sqlite library, then this function is called directly by +** SQLite. If fts3 is built as a dynamically loadable extension, this +** function is called by the sqlite3_extension_init() entry point. +*/ +SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ + int rc = SQLITE_OK; + Fts3HashWrapper *pHash = 0; + const sqlite3_tokenizer_module *pSimple = 0; + const sqlite3_tokenizer_module *pPorter = 0; +#ifndef SQLITE_DISABLE_FTS3_UNICODE + const sqlite3_tokenizer_module *pUnicode = 0; +#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N) - ** - ** Set the nReserve size to N for the main database on the database - ** connection db. - */ - case SQLITE_TESTCTRL_RESERVE: { - sqlite3 *db = va_arg(ap, sqlite3*); - int x = va_arg(ap,int); - sqlite3_mutex_enter(db->mutex); - sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0); - sqlite3_mutex_leave(db->mutex); - break; - } +#ifdef SQLITE_ENABLE_ICU + const sqlite3_tokenizer_module *pIcu = 0; + sqlite3Fts3IcuTokenizerModule(&pIcu); +#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N) - ** - ** Enable or disable various optimizations for testing purposes. The - ** argument N is a bitmask of optimizations to be disabled. For normal - ** operation N should be 0. The idea is that a test program (like the - ** SQL Logic Test or SLT test module) can run the same SQL multiple times - ** with various optimizations disabled to verify that the same answer - ** is obtained in every case. - */ - case SQLITE_TESTCTRL_OPTIMIZATIONS: { - sqlite3 *db = va_arg(ap, sqlite3*); - db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff); - break; - } +#ifndef SQLITE_DISABLE_FTS3_UNICODE + sqlite3Fts3UnicodeTokenizer(&pUnicode); +#endif -#ifdef SQLITE_N_KEYWORD - /* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord) - ** - ** If zWord is a keyword recognized by the parser, then return the - ** number of keywords. Or if zWord is not a keyword, return 0. - ** - ** This test feature is only available in the amalgamation since - ** the SQLITE_N_KEYWORD macro is not defined in this file if SQLite - ** is built using separate source files. - */ - case SQLITE_TESTCTRL_ISKEYWORD: { - const char *zWord = va_arg(ap, const char*); - int n = sqlite3Strlen30(zWord); - rc = (sqlite3KeywordCode((u8*)zWord, n)!=TK_ID) ? SQLITE_N_KEYWORD : 0; - break; - } -#endif +#ifdef SQLITE_TEST + rc = sqlite3Fts3InitTerm(db); + if( rc!=SQLITE_OK ) return rc; +#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree); - ** - ** Pass pFree into sqlite3ScratchFree(). - ** If sz>0 then allocate a scratch buffer into pNew. - */ - case SQLITE_TESTCTRL_SCRATCHMALLOC: { - void *pFree, **ppNew; - int sz; - sz = va_arg(ap, int); - ppNew = va_arg(ap, void**); - pFree = va_arg(ap, void*); - if( sz ) *ppNew = sqlite3ScratchMalloc(sz); - sqlite3ScratchFree(pFree); - break; - } + rc = sqlite3Fts3InitAux(db); + if( rc!=SQLITE_OK ) return rc; - /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff); - ** - ** If parameter onoff is non-zero, configure the wrappers so that all - ** subsequent calls to localtime() and variants fail. If onoff is zero, - ** undo this setting. - */ - case SQLITE_TESTCTRL_LOCALTIME_FAULT: { - sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); - break; - } + sqlite3Fts3SimpleTokenizerModule(&pSimple); + sqlite3Fts3PorterTokenizerModule(&pPorter); - /* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int); - ** - ** Set or clear a flag that indicates that the database file is always well- - ** formed and never corrupt. This flag is clear by default, indicating that - ** database files might have arbitrary corruption. Setting the flag during - ** testing causes certain assert() statements in the code to be activated - ** that demonstrat invariants on well-formed database files. - */ - case SQLITE_TESTCTRL_NEVER_CORRUPT: { - sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int); - break; - } + /* Allocate and initialize the hash-table used to store tokenizers. */ + pHash = sqlite3_malloc(sizeof(Fts3HashWrapper)); + if( !pHash ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3Fts3HashInit(&pHash->hash, FTS3_HASH_STRING, 1); + pHash->nRef = 0; + } - /* Set the threshold at which OP_Once counters reset back to zero. - ** By default this is 0x7ffffffe (over 2 billion), but that value is - ** too big to test in a reasonable amount of time, so this control is - ** provided to set a small and easily reachable reset value. - */ - case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: { - sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int); - break; - } + /* Load the built-in tokenizers into the hash table */ + if( rc==SQLITE_OK ){ + if( sqlite3Fts3HashInsert(&pHash->hash, "simple", 7, (void *)pSimple) + || sqlite3Fts3HashInsert(&pHash->hash, "porter", 7, (void *)pPorter) - /* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr); - ** - ** Set the VDBE coverage callback function to xCallback with context - ** pointer ptr. - */ - case SQLITE_TESTCTRL_VDBE_COVERAGE: { -#ifdef SQLITE_VDBE_COVERAGE - typedef void (*branch_callback)(void*,int,u8,u8); - sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback); - sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*); +#ifndef SQLITE_DISABLE_FTS3_UNICODE + || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode) #endif - break; +#ifdef SQLITE_ENABLE_ICU + || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu)) +#endif + ){ + rc = SQLITE_NOMEM; } + } - /* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */ - case SQLITE_TESTCTRL_SORTER_MMAP: { - sqlite3 *db = va_arg(ap, sqlite3*); - db->nMaxSorterMmap = va_arg(ap, int); - break; - } +#ifdef SQLITE_TEST + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3ExprInitTestInterface(db, &pHash->hash); + } +#endif - /* sqlite3_test_control(SQLITE_TESTCTRL_ISINIT); - ** - ** Return SQLITE_OK if SQLite has been initialized and SQLITE_ERROR if - ** not. - */ - case SQLITE_TESTCTRL_ISINIT: { - if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR; - break; + /* Create the virtual table wrapper around the hash-table and overload + ** the four scalar functions. If this is successful, register the + ** module with sqlite. + */ + if( SQLITE_OK==rc + && SQLITE_OK==(rc=sqlite3Fts3InitHashTable(db,&pHash->hash,"fts3_tokenizer")) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2)) + && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1)) + ){ + pHash->nRef++; + rc = sqlite3_create_module_v2( + db, "fts3", &fts3Module, (void *)pHash, hashDestroy + ); + if( rc==SQLITE_OK ){ + pHash->nRef++; + rc = sqlite3_create_module_v2( + db, "fts4", &fts3Module, (void *)pHash, hashDestroy + ); } - - /* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum); - ** - ** This test control is used to create imposter tables. "db" is a pointer - ** to the database connection. dbName is the database name (ex: "main" or - ** "temp") which will receive the imposter. "onOff" turns imposter mode on - ** or off. "tnum" is the root page of the b-tree to which the imposter - ** table should connect. - ** - ** Enable imposter mode only when the schema has already been parsed. Then - ** run a single CREATE TABLE statement to construct the imposter table in - ** the parsed schema. Then turn imposter mode back off again. - ** - ** If onOff==0 and tnum>0 then reset the schema for all databases, causing - ** the schema to be reparsed the next time it is needed. This has the - ** effect of erasing all imposter tables. - */ - case SQLITE_TESTCTRL_IMPOSTER: { - sqlite3 *db = va_arg(ap, sqlite3*); - sqlite3_mutex_enter(db->mutex); - db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); - db->init.busy = db->init.imposterTable = va_arg(ap,int); - db->init.newTnum = va_arg(ap,int); - if( db->init.busy==0 && db->init.newTnum>0 ){ - sqlite3ResetAllSchemasOfConnection(db); - } - sqlite3_mutex_leave(db->mutex); - break; + if( rc==SQLITE_OK ){ + pHash->nRef++; + rc = sqlite3Fts3InitTok(db, (void *)pHash, hashDestroy); } + return rc; + } + + + /* An error has occurred. Delete the hash table and return the error code. */ + assert( rc!=SQLITE_OK ); + if( pHash ){ + sqlite3Fts3HashClear(&pHash->hash); + sqlite3_free(pHash); } - va_end(ap); -#endif /* SQLITE_UNTESTABLE */ return rc; } /* -** This is a utility routine, useful to VFS implementations, that checks -** to see if a database file was a URI that contained a specific query -** parameter, and if so obtains the value of the query parameter. +** Allocate an Fts3MultiSegReader for each token in the expression headed +** by pExpr. ** -** The zFilename argument is the filename pointer passed into the xOpen() -** method of a VFS implementation. The zParam argument is the name of the -** query parameter we seek. This routine returns the value of the zParam -** parameter if it exists. If the parameter does not exist, this routine -** returns a NULL pointer. +** An Fts3SegReader object is a cursor that can seek or scan a range of +** entries within a single segment b-tree. An Fts3MultiSegReader uses multiple +** Fts3SegReader objects internally to provide an interface to seek or scan +** within the union of all segments of a b-tree. Hence the name. +** +** If the allocated Fts3MultiSegReader just seeks to a single entry in a +** segment b-tree (if the term is not a prefix or it is a prefix for which +** there exists prefix b-tree of the right length) then it may be traversed +** and merged incrementally. Otherwise, it has to be merged into an in-memory +** doclist and then traversed. */ -SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ - if( zFilename==0 || zParam==0 ) return 0; - zFilename += sqlite3Strlen30(zFilename) + 1; - while( zFilename[0] ){ - int x = strcmp(zFilename, zParam); - zFilename += sqlite3Strlen30(zFilename) + 1; - if( x==0 ) return zFilename; - zFilename += sqlite3Strlen30(zFilename) + 1; +static void fts3EvalAllocateReaders( + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Allocate readers for this expression */ + int *pnToken, /* OUT: Total number of tokens in phrase. */ + int *pnOr, /* OUT: Total number of OR nodes in expr. */ + int *pRc /* IN/OUT: Error code */ +){ + if( pExpr && SQLITE_OK==*pRc ){ + if( pExpr->eType==FTSQUERY_PHRASE ){ + int i; + int nToken = pExpr->pPhrase->nToken; + *pnToken += nToken; + for(i=0; ipPhrase->aToken[i]; + int rc = fts3TermSegReaderCursor(pCsr, + pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr + ); + if( rc!=SQLITE_OK ){ + *pRc = rc; + return; + } + } + assert( pExpr->pPhrase->iDoclistToken==0 ); + pExpr->pPhrase->iDoclistToken = -1; + }else{ + *pnOr += (pExpr->eType==FTSQUERY_OR); + fts3EvalAllocateReaders(pCsr, pExpr->pLeft, pnToken, pnOr, pRc); + fts3EvalAllocateReaders(pCsr, pExpr->pRight, pnToken, pnOr, pRc); + } } - return 0; } /* -** Return a boolean value for a query parameter. +** Arguments pList/nList contain the doclist for token iToken of phrase p. +** It is merged into the main doclist stored in p->doclist.aAll/nAll. +** +** This function assumes that pList points to a buffer allocated using +** sqlite3_malloc(). This function takes responsibility for eventually +** freeing the buffer. +** +** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs. */ -SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){ - const char *z = sqlite3_uri_parameter(zFilename, zParam); - bDflt = bDflt!=0; - return z ? sqlite3GetBoolean(z, bDflt) : bDflt; +static int fts3EvalPhraseMergeToken( + Fts3Table *pTab, /* FTS Table pointer */ + Fts3Phrase *p, /* Phrase to merge pList/nList into */ + int iToken, /* Token pList/nList corresponds to */ + char *pList, /* Pointer to doclist */ + int nList /* Number of bytes in pList */ +){ + int rc = SQLITE_OK; + assert( iToken!=p->iDoclistToken ); + + if( pList==0 ){ + sqlite3_free(p->doclist.aAll); + p->doclist.aAll = 0; + p->doclist.nAll = 0; + } + + else if( p->iDoclistToken<0 ){ + p->doclist.aAll = pList; + p->doclist.nAll = nList; + } + + else if( p->doclist.aAll==0 ){ + sqlite3_free(pList); + } + + else { + char *pLeft; + char *pRight; + int nLeft; + int nRight; + int nDiff; + + if( p->iDoclistTokendoclist.aAll; + nLeft = p->doclist.nAll; + pRight = pList; + nRight = nList; + nDiff = iToken - p->iDoclistToken; + }else{ + pRight = p->doclist.aAll; + nRight = p->doclist.nAll; + pLeft = pList; + nLeft = nList; + nDiff = p->iDoclistToken - iToken; + } + + rc = fts3DoclistPhraseMerge( + pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight + ); + sqlite3_free(pLeft); + p->doclist.aAll = pRight; + p->doclist.nAll = nRight; + } + + if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken; + return rc; } /* -** Return a 64-bit integer value for a query parameter. +** Load the doclist for phrase p into p->doclist.aAll/nAll. The loaded doclist +** does not take deferred tokens into account. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ -SQLITE_API sqlite3_int64 sqlite3_uri_int64( - const char *zFilename, /* Filename as passed to xOpen */ - const char *zParam, /* URI parameter sought */ - sqlite3_int64 bDflt /* return if parameter is missing */ +static int fts3EvalPhraseLoad( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p /* Phrase object */ ){ - const char *z = sqlite3_uri_parameter(zFilename, zParam); - sqlite3_int64 v; - if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ - bDflt = v; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int iToken; + int rc = SQLITE_OK; + + for(iToken=0; rc==SQLITE_OK && iTokennToken; iToken++){ + Fts3PhraseToken *pToken = &p->aToken[iToken]; + assert( pToken->pDeferred==0 || pToken->pSegcsr==0 ); + + if( pToken->pSegcsr ){ + int nThis = 0; + char *pThis = 0; + rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis); + if( rc==SQLITE_OK ){ + rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis); + } + } + assert( pToken->pSegcsr==0 ); } - return bDflt; -} -/* -** Return the Btree pointer identified by zDbName. Return NULL if not found. -*/ -SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ - int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0; - return iDb<0 ? 0 : db->aDb[iDb].pBt; + return rc; } +#ifndef SQLITE_DISABLE_FTS4_DEFERRED /* -** Return the filename of the database associated with a database -** connection. +** This function is called on each phrase after the position lists for +** any deferred tokens have been loaded into memory. It updates the phrases +** current position list to include only those positions that are really +** instances of the phrase (after considering deferred tokens). If this +** means that the phrase does not appear in the current row, doclist.pList +** and doclist.nList are both zeroed. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ -SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ - Btree *pBt; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return 0; +static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ + int iToken; /* Used to iterate through phrase tokens */ + char *aPoslist = 0; /* Position list for deferred tokens */ + int nPoslist = 0; /* Number of bytes in aPoslist */ + int iPrev = -1; /* Token number of previous deferred token */ + + assert( pPhrase->doclist.bFreeList==0 ); + + for(iToken=0; iTokennToken; iToken++){ + Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; + Fts3DeferredToken *pDeferred = pToken->pDeferred; + + if( pDeferred ){ + char *pList; + int nList; + int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); + if( rc!=SQLITE_OK ) return rc; + + if( pList==0 ){ + sqlite3_free(aPoslist); + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + return SQLITE_OK; + + }else if( aPoslist==0 ){ + aPoslist = pList; + nPoslist = nList; + + }else{ + char *aOut = pList; + char *p1 = aPoslist; + char *p2 = aOut; + + assert( iPrev>=0 ); + fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2); + sqlite3_free(aPoslist); + aPoslist = pList; + nPoslist = (int)(aOut - aPoslist); + if( nPoslist==0 ){ + sqlite3_free(aPoslist); + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + return SQLITE_OK; + } + } + iPrev = iToken; + } } -#endif - pBt = sqlite3DbNameToBtree(db, zDbName); - return pBt ? sqlite3BtreeGetFilename(pBt) : 0; + + if( iPrev>=0 ){ + int nMaxUndeferred = pPhrase->iDoclistToken; + if( nMaxUndeferred<0 ){ + pPhrase->doclist.pList = aPoslist; + pPhrase->doclist.nList = nPoslist; + pPhrase->doclist.iDocid = pCsr->iPrevId; + pPhrase->doclist.bFreeList = 1; + }else{ + int nDistance; + char *p1; + char *p2; + char *aOut; + + if( nMaxUndeferred>iPrev ){ + p1 = aPoslist; + p2 = pPhrase->doclist.pList; + nDistance = nMaxUndeferred - iPrev; + }else{ + p1 = pPhrase->doclist.pList; + p2 = aPoslist; + nDistance = iPrev - nMaxUndeferred; + } + + aOut = (char *)sqlite3_malloc(nPoslist+8); + if( !aOut ){ + sqlite3_free(aPoslist); + return SQLITE_NOMEM; + } + + pPhrase->doclist.pList = aOut; + if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){ + pPhrase->doclist.bFreeList = 1; + pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList); + }else{ + sqlite3_free(aOut); + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + } + sqlite3_free(aPoslist); + } + } + + return SQLITE_OK; } +#endif /* SQLITE_DISABLE_FTS4_DEFERRED */ /* -** Return 1 if database is read-only or 0 if read/write. Return -1 if -** no such database exists. +** Maximum number of tokens a phrase may have to be considered for the +** incremental doclists strategy. */ -SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){ - Btree *pBt; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - (void)SQLITE_MISUSE_BKPT; - return -1; - } -#endif - pBt = sqlite3DbNameToBtree(db, zDbName); - return pBt ? sqlite3BtreeIsReadonly(pBt) : -1; -} +#define MAX_INCR_PHRASE_TOKENS 4 -#ifdef SQLITE_ENABLE_SNAPSHOT /* -** Obtain a snapshot handle for the snapshot of database zDb currently -** being read by handle db. +** This function is called for each Fts3Phrase in a full-text query +** expression to initialize the mechanism for returning rows. Once this +** function has been called successfully on an Fts3Phrase, it may be +** used with fts3EvalPhraseNext() to iterate through the matching docids. +** +** If parameter bOptOk is true, then the phrase may (or may not) use the +** incremental loading strategy. Otherwise, the entire doclist is loaded into +** memory within this call. +** +** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ -SQLITE_API int sqlite3_snapshot_get( - sqlite3 *db, - const char *zDb, - sqlite3_snapshot **ppSnapshot -){ - int rc = SQLITE_ERROR; -#ifndef SQLITE_OMIT_WAL +static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; /* Error code */ + int i; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - return SQLITE_MISUSE_BKPT; - } + /* Determine if doclists may be loaded from disk incrementally. This is + ** possible if the bOptOk argument is true, the FTS doclists will be + ** scanned in forward order, and the phrase consists of + ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first" + ** tokens or prefix tokens that cannot use a prefix-index. */ + int bHaveIncr = 0; + int bIncrOk = (bOptOk + && pCsr->bDesc==pTab->bDescIdx + && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + && pTab->bNoIncrDoclist==0 #endif - sqlite3_mutex_enter(db->mutex); + ); + for(i=0; bIncrOk==1 && inToken; i++){ + Fts3PhraseToken *pToken = &p->aToken[i]; + if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){ + bIncrOk = 0; + } + if( pToken->pSegcsr ) bHaveIncr = 1; + } - if( db->autoCommit==0 ){ - int iDb = sqlite3FindDbName(db, zDb); - if( iDb==0 || iDb>1 ){ - Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInTrans(pBt) ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); - } + if( bIncrOk && bHaveIncr ){ + /* Use the incremental approach. */ + int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); + for(i=0; rc==SQLITE_OK && inToken; i++){ + Fts3PhraseToken *pToken = &p->aToken[i]; + Fts3MultiSegReader *pSegcsr = pToken->pSegcsr; + if( pSegcsr ){ + rc = sqlite3Fts3MsrIncrStart(pTab, pSegcsr, iCol, pToken->z, pToken->n); } } + p->bIncr = 1; + }else{ + /* Load the full doclist for the phrase into memory. */ + rc = fts3EvalPhraseLoad(pCsr, p); + p->bIncr = 0; } - sqlite3_mutex_leave(db->mutex); -#endif /* SQLITE_OMIT_WAL */ + assert( rc!=SQLITE_OK || p->nToken<1 || p->aToken[0].pSegcsr==0 || p->bIncr ); return rc; } /* -** Open a read-transaction on the snapshot idendified by pSnapshot. +** This function is used to iterate backwards (from the end to start) +** through doclists. It is used by this module to iterate through phrase +** doclists in reverse and by the fts3_write.c module to iterate through +** pending-terms lists when writing to databases with "order=desc". +** +** The doclist may be sorted in ascending (parameter bDescIdx==0) or +** descending (parameter bDescIdx==1) order of docid. Regardless, this +** function iterates from the end of the doclist to the beginning. */ -SQLITE_API int sqlite3_snapshot_open( - sqlite3 *db, - const char *zDb, - sqlite3_snapshot *pSnapshot +SQLITE_PRIVATE void sqlite3Fts3DoclistPrev( + int bDescIdx, /* True if the doclist is desc */ + char *aDoclist, /* Pointer to entire doclist */ + int nDoclist, /* Length of aDoclist in bytes */ + char **ppIter, /* IN/OUT: Iterator pointer */ + sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ + int *pnList, /* OUT: List length pointer */ + u8 *pbEof /* OUT: End-of-file flag */ ){ - int rc = SQLITE_ERROR; -#ifndef SQLITE_OMIT_WAL + char *p = *ppIter; -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - return SQLITE_MISUSE_BKPT; + assert( nDoclist>0 ); + assert( *pbEof==0 ); + assert_fts3_nc( p || *piDocid==0 ); + assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) ); + + if( p==0 ){ + sqlite3_int64 iDocid = 0; + char *pNext = 0; + char *pDocid = aDoclist; + char *pEnd = &aDoclist[nDoclist]; + int iMul = 1; + + while( pDocidmutex); - if( db->autoCommit==0 ){ - int iDb; - iDb = sqlite3FindDbName(db, zDb); - if( iDb==0 || iDb>1 ){ - Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ - rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot); - if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); - sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0); - } - } +} + +/* +** Iterate forwards through a doclist. +*/ +SQLITE_PRIVATE void sqlite3Fts3DoclistNext( + int bDescIdx, /* True if the doclist is desc */ + char *aDoclist, /* Pointer to entire doclist */ + int nDoclist, /* Length of aDoclist in bytes */ + char **ppIter, /* IN/OUT: Iterator pointer */ + sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ + u8 *pbEof /* OUT: End-of-file flag */ +){ + char *p = *ppIter; + + assert( nDoclist>0 ); + assert( *pbEof==0 ); + assert_fts3_nc( p || *piDocid==0 ); + assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) ); + + if( p==0 ){ + p = aDoclist; + p += sqlite3Fts3GetVarint(p, piDocid); + }else{ + fts3PoslistCopy(0, &p); + while( p<&aDoclist[nDoclist] && *p==0 ) p++; + if( p>=&aDoclist[nDoclist] ){ + *pbEof = 1; + }else{ + sqlite3_int64 iVar; + p += sqlite3Fts3GetVarint(p, &iVar); + *piDocid += ((bDescIdx ? -1 : 1) * iVar); } } - sqlite3_mutex_leave(db->mutex); -#endif /* SQLITE_OMIT_WAL */ - return rc; + *ppIter = p; } /* -** Recover as many snapshots as possible from the wal file associated with -** schema zDb of database db. +** Advance the iterator pDL to the next entry in pDL->aAll/nAll. Set *pbEof +** to true if EOF is reached. */ -SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ - int rc = SQLITE_ERROR; - int iDb; -#ifndef SQLITE_OMIT_WAL +static void fts3EvalDlPhraseNext( + Fts3Table *pTab, + Fts3Doclist *pDL, + u8 *pbEof +){ + char *pIter; /* Used to iterate through aAll */ + char *pEnd; /* 1 byte past end of aAll */ -#ifdef SQLITE_ENABLE_API_ARMOR - if( !sqlite3SafetyCheckOk(db) ){ - return SQLITE_MISUSE_BKPT; + if( pDL->pNextDocid ){ + pIter = pDL->pNextDocid; + assert( pDL->aAll!=0 || pIter==0 ); + }else{ + pIter = pDL->aAll; } -#endif - sqlite3_mutex_enter(db->mutex); - iDb = sqlite3FindDbName(db, zDb); - if( iDb==0 || iDb>1 ){ - Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); - sqlite3BtreeCommit(pBt); - } + if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){ + /* We have already reached the end of this doclist. EOF. */ + *pbEof = 1; + }else{ + sqlite3_int64 iDelta; + pIter += sqlite3Fts3GetVarint(pIter, &iDelta); + if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){ + pDL->iDocid += iDelta; + }else{ + pDL->iDocid -= iDelta; } + pDL->pList = pIter; + fts3PoslistCopy(0, &pIter); + pDL->nList = (int)(pIter - pDL->pList); + + /* pIter now points just past the 0x00 that terminates the position- + ** list for document pDL->iDocid. However, if this position-list was + ** edited in place by fts3EvalNearTrim(), then pIter may not actually + ** point to the start of the next docid value. The following line deals + ** with this case by advancing pIter past the zero-padding added by + ** fts3EvalNearTrim(). */ + while( pIterpNextDocid = pIter; + assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter ); + *pbEof = 0; } - sqlite3_mutex_leave(db->mutex); -#endif /* SQLITE_OMIT_WAL */ - return rc; } /* -** Free a snapshot handle obtained from sqlite3_snapshot_get(). +** Helper type used by fts3EvalIncrPhraseNext() and incrPhraseTokenNext(). */ -SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){ - sqlite3_free(pSnapshot); +typedef struct TokenDoclist TokenDoclist; +struct TokenDoclist { + int bIgnore; + sqlite3_int64 iDocid; + char *pList; + int nList; +}; + +/* +** Token pToken is an incrementally loaded token that is part of a +** multi-token phrase. Advance it to the next matching document in the +** database and populate output variable *p with the details of the new +** entry. Or, if the iterator has reached EOF, set *pbEof to true. +** +** If an error occurs, return an SQLite error code. Otherwise, return +** SQLITE_OK. +*/ +static int incrPhraseTokenNext( + Fts3Table *pTab, /* Virtual table handle */ + Fts3Phrase *pPhrase, /* Phrase to advance token of */ + int iToken, /* Specific token to advance */ + TokenDoclist *p, /* OUT: Docid and doclist for new entry */ + u8 *pbEof /* OUT: True if iterator is at EOF */ +){ + int rc = SQLITE_OK; + + if( pPhrase->iDoclistToken==iToken ){ + assert( p->bIgnore==0 ); + assert( pPhrase->aToken[iToken].pSegcsr==0 ); + fts3EvalDlPhraseNext(pTab, &pPhrase->doclist, pbEof); + p->pList = pPhrase->doclist.pList; + p->nList = pPhrase->doclist.nList; + p->iDocid = pPhrase->doclist.iDocid; + }else{ + Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; + assert( pToken->pDeferred==0 ); + assert( pToken->pSegcsr || pPhrase->iDoclistToken>=0 ); + if( pToken->pSegcsr ){ + assert( p->bIgnore==0 ); + rc = sqlite3Fts3MsrIncrNext( + pTab, pToken->pSegcsr, &p->iDocid, &p->pList, &p->nList + ); + if( p->pList==0 ) *pbEof = 1; + }else{ + p->bIgnore = 1; + } + } + + return rc; } -#endif /* SQLITE_ENABLE_SNAPSHOT */ -/************** End of main.c ************************************************/ -/************** Begin file notify.c ******************************************/ + /* -** 2009 March 3 +** The phrase iterator passed as the second argument: ** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: +** * features at least one token that uses an incremental doclist, and ** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** * does not contain any deferred tokens. ** -************************************************************************* +** Advance it to the next matching documnent in the database and populate +** the Fts3Doclist.pList and nList fields. ** -** This file contains the implementation of the sqlite3_unlock_notify() -** API method and its associated functionality. +** If there is no "next" entry and no error occurs, then *pbEof is set to +** 1 before returning. Otherwise, if no error occurs and the iterator is +** successfully advanced, *pbEof is set to 0. +** +** If an error occurs, return an SQLite error code. Otherwise, return +** SQLITE_OK. */ -/* #include "sqliteInt.h" */ -/* #include "btreeInt.h" */ +static int fts3EvalIncrPhraseNext( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p, /* Phrase object to advance to next docid */ + u8 *pbEof /* OUT: Set to 1 if EOF */ +){ + int rc = SQLITE_OK; + Fts3Doclist *pDL = &p->doclist; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + u8 bEof = 0; -/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */ -#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY + /* This is only called if it is guaranteed that the phrase has at least + ** one incremental token. In which case the bIncr flag is set. */ + assert( p->bIncr==1 ); + + if( p->nToken==1 ){ + rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, + &pDL->iDocid, &pDL->pList, &pDL->nList + ); + if( pDL->pList==0 ) bEof = 1; + }else{ + int bDescDoclist = pCsr->bDesc; + struct TokenDoclist a[MAX_INCR_PHRASE_TOKENS]; + + memset(a, 0, sizeof(a)); + assert( p->nToken<=MAX_INCR_PHRASE_TOKENS ); + assert( p->iDoclistTokennToken && bEof==0; i++){ + rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); + if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){ + iMax = a[i].iDocid; + bMaxSet = 1; + } + } + assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) ); + assert( rc!=SQLITE_OK || bMaxSet ); + + /* Keep advancing iterators until they all point to the same document */ + for(i=0; inToken; i++){ + while( rc==SQLITE_OK && bEof==0 + && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0 + ){ + rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); + if( DOCID_CMP(a[i].iDocid, iMax)>0 ){ + iMax = a[i].iDocid; + i = 0; + } + } + } + + /* Check if the current entries really are a phrase match */ + if( bEof==0 ){ + int nList = 0; + int nByte = a[p->nToken-1].nList; + char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING); + if( !aDoclist ) return SQLITE_NOMEM; + memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); + memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); + + for(i=0; i<(p->nToken-1); i++){ + if( a[i].bIgnore==0 ){ + char *pL = a[i].pList; + char *pR = aDoclist; + char *pOut = aDoclist; + int nDist = p->nToken-1-i; + int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR); + if( res==0 ) break; + nList = (int)(pOut - aDoclist); + } + } + if( i==(p->nToken-1) ){ + pDL->iDocid = iMax; + pDL->pList = aDoclist; + pDL->nList = nList; + pDL->bFreeList = 1; + break; + } + sqlite3_free(aDoclist); + } + } + } + + *pbEof = bEof; + return rc; +} /* -** Public interfaces: +** Attempt to move the phrase iterator to point to the next matching docid. +** If an error occurs, return an SQLite error code. Otherwise, return +** SQLITE_OK. ** -** sqlite3ConnectionBlocked() -** sqlite3ConnectionUnlocked() -** sqlite3ConnectionClosed() -** sqlite3_unlock_notify() +** If there is no "next" entry and no error occurs, then *pbEof is set to +** 1 before returning. Otherwise, if no error occurs and the iterator is +** successfully advanced, *pbEof is set to 0. */ +static int fts3EvalPhraseNext( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Phrase *p, /* Phrase object to advance to next docid */ + u8 *pbEof /* OUT: Set to 1 if EOF */ +){ + int rc = SQLITE_OK; + Fts3Doclist *pDL = &p->doclist; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; -#define assertMutexHeld() \ - assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) ) + if( p->bIncr ){ + rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof); + }else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){ + sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll, + &pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof + ); + pDL->pList = pDL->pNextDocid; + }else{ + fts3EvalDlPhraseNext(pTab, pDL, pbEof); + } -/* -** Head of a linked list of all sqlite3 objects created by this process -** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection -** is not NULL. This variable may only accessed while the STATIC_MASTER -** mutex is held. -*/ -static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0; + return rc; +} -#ifndef NDEBUG /* -** This function is a complex assert() that verifies the following -** properties of the blocked connections list: ** -** 1) Each entry in the list has a non-NULL value for either -** pUnlockConnection or pBlockingConnection, or both. +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, fts3EvalPhraseStart() is called on all phrases within the +** expression. Also the Fts3Expr.bDeferred variable is set to true for any +** expressions for which all descendent tokens are deferred. ** -** 2) All entries in the list that share a common value for -** xUnlockNotify are grouped together. +** If parameter bOptOk is zero, then it is guaranteed that the +** Fts3Phrase.doclist.aAll/nAll variables contain the entire doclist for +** each phrase in the expression (subject to deferred token processing). +** Or, if bOptOk is non-zero, then one or more tokens within the expression +** may be loaded incrementally, meaning doclist.aAll/nAll is not available. ** -** 3) If the argument db is not NULL, then none of the entries in the -** blocked connections list have pUnlockConnection or pBlockingConnection -** set to db. This is used when closing connection db. +** If an error occurs within this function, *pRc is set to an SQLite error +** code before returning. */ -static void checkListProperties(sqlite3 *db){ - sqlite3 *p; - for(p=sqlite3BlockedList; p; p=p->pNextBlocked){ - int seen = 0; - sqlite3 *p2; - - /* Verify property (1) */ - assert( p->pUnlockConnection || p->pBlockingConnection ); - - /* Verify property (2) */ - for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){ - if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1; - assert( p2->xUnlockNotify==p->xUnlockNotify || !seen ); - assert( db==0 || p->pUnlockConnection!=db ); - assert( db==0 || p->pBlockingConnection!=db ); +static void fts3EvalStartReaders( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pExpr, /* Expression to initialize phrases in */ + int *pRc /* IN/OUT: Error code */ +){ + if( pExpr && SQLITE_OK==*pRc ){ + if( pExpr->eType==FTSQUERY_PHRASE ){ + int nToken = pExpr->pPhrase->nToken; + if( nToken ){ + int i; + for(i=0; ipPhrase->aToken[i].pDeferred==0 ) break; + } + pExpr->bDeferred = (i==nToken); + } + *pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase); + }else{ + fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc); + fts3EvalStartReaders(pCsr, pExpr->pRight, pRc); + pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred); } } } -#else -# define checkListProperties(x) -#endif /* -** Remove connection db from the blocked connections list. If connection -** db is not currently a part of the list, this function is a no-op. +** An array of the following structures is assembled as part of the process +** of selecting tokens to defer before the query starts executing (as part +** of the xFilter() method). There is one element in the array for each +** token in the FTS expression. +** +** Tokens are divided into AND/NEAR clusters. All tokens in a cluster belong +** to phrases that are connected only by AND and NEAR operators (not OR or +** NOT). When determining tokens to defer, each AND/NEAR cluster is considered +** separately. The root of a tokens AND/NEAR cluster is stored in +** Fts3TokenAndCost.pRoot. */ -static void removeFromBlockedList(sqlite3 *db){ - sqlite3 **pp; - assertMutexHeld(); - for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){ - if( *pp==db ){ - *pp = (*pp)->pNextBlocked; - break; +typedef struct Fts3TokenAndCost Fts3TokenAndCost; +struct Fts3TokenAndCost { + Fts3Phrase *pPhrase; /* The phrase the token belongs to */ + int iToken; /* Position of token in phrase */ + Fts3PhraseToken *pToken; /* The token itself */ + Fts3Expr *pRoot; /* Root of NEAR/AND cluster */ + int nOvfl; /* Number of overflow pages to load doclist */ + int iCol; /* The column the token must match */ +}; + +/* +** This function is used to populate an allocated Fts3TokenAndCost array. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, if an error occurs during execution, *pRc is set to an +** SQLite error code. +*/ +static void fts3EvalTokenCosts( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pRoot, /* Root of current AND/NEAR cluster */ + Fts3Expr *pExpr, /* Expression to consider */ + Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ + Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ + int *pRc /* IN/OUT: Error code */ +){ + if( *pRc==SQLITE_OK ){ + if( pExpr->eType==FTSQUERY_PHRASE ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + int i; + for(i=0; *pRc==SQLITE_OK && inToken; i++){ + Fts3TokenAndCost *pTC = (*ppTC)++; + pTC->pPhrase = pPhrase; + pTC->iToken = i; + pTC->pRoot = pRoot; + pTC->pToken = &pPhrase->aToken[i]; + pTC->iCol = pPhrase->iColumn; + *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); + } + }else if( pExpr->eType!=FTSQUERY_NOT ){ + assert( pExpr->eType==FTSQUERY_OR + || pExpr->eType==FTSQUERY_AND + || pExpr->eType==FTSQUERY_NEAR + ); + assert( pExpr->pLeft && pExpr->pRight ); + if( pExpr->eType==FTSQUERY_OR ){ + pRoot = pExpr->pLeft; + **ppOr = pRoot; + (*ppOr)++; + } + fts3EvalTokenCosts(pCsr, pRoot, pExpr->pLeft, ppTC, ppOr, pRc); + if( pExpr->eType==FTSQUERY_OR ){ + pRoot = pExpr->pRight; + **ppOr = pRoot; + (*ppOr)++; + } + fts3EvalTokenCosts(pCsr, pRoot, pExpr->pRight, ppTC, ppOr, pRc); } } } /* -** Add connection db to the blocked connections list. It is assumed -** that it is not already a part of the list. +** Determine the average document (row) size in pages. If successful, +** write this value to *pnPage and return SQLITE_OK. Otherwise, return +** an SQLite error code. +** +** The average document size in pages is calculated by first calculating +** determining the average size in bytes, B. If B is less than the amount +** of data that will fit on a single leaf page of an intkey table in +** this database, then the average docsize is 1. Otherwise, it is 1 plus +** the number of overflow pages consumed by a record B bytes in size. */ -static void addToBlockedList(sqlite3 *db){ - sqlite3 **pp; - assertMutexHeld(); - for( - pp=&sqlite3BlockedList; - *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify; - pp=&(*pp)->pNextBlocked - ); - db->pNextBlocked = *pp; - *pp = db; -} +static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ + int rc = SQLITE_OK; + if( pCsr->nRowAvg==0 ){ + /* The average document size, which is required to calculate the cost + ** of each doclist, has not yet been determined. Read the required + ** data from the %_stat table to calculate it. + ** + ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 + ** varints, where nCol is the number of columns in the FTS3 table. + ** The first varint is the number of documents currently stored in + ** the table. The following nCol varints contain the total amount of + ** data stored in all rows of each column of the table, from left + ** to right. + */ + Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; + sqlite3_stmt *pStmt; + sqlite3_int64 nDoc = 0; + sqlite3_int64 nByte = 0; + const char *pEnd; + const char *a; + + rc = sqlite3Fts3SelectDoctotal(p, &pStmt); + if( rc!=SQLITE_OK ) return rc; + a = sqlite3_column_blob(pStmt, 0); + testcase( a==0 ); /* If %_stat.value set to X'' */ + if( a ){ + pEnd = &a[sqlite3_column_bytes(pStmt, 0)]; + a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc); + while( anDoc = nDoc; + pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz); + assert( pCsr->nRowAvg>0 ); + rc = sqlite3_reset(pStmt); + } -/* -** Release the STATIC_MASTER mutex. -*/ -static void leaveMutex(void){ - assertMutexHeld(); - checkListProperties(0); - sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); + *pnPage = pCsr->nRowAvg; + return rc; } /* -** Register an unlock-notify callback. -** -** This is called after connection "db" has attempted some operation -** but has received an SQLITE_LOCKED error because another connection -** (call it pOther) in the same process was busy using the same shared -** cache. pOther is found by looking at db->pBlockingConnection. -** -** If there is no blocking connection, the callback is invoked immediately, -** before this routine returns. -** -** If pOther is already blocked on db, then report SQLITE_LOCKED, to indicate -** a deadlock. +** This function is called to select the tokens (if any) that will be +** deferred. The array aTC[] has already been populated when this is +** called. ** -** Otherwise, make arrangements to invoke xNotify when pOther drops -** its locks. +** This function is called once for each AND/NEAR cluster in the +** expression. Each invocation determines which tokens to defer within +** the cluster with root node pRoot. See comments above the definition +** of struct Fts3TokenAndCost for more details. ** -** Each call to this routine overrides any prior callbacks registered -** on the same "db". If xNotify==0 then any prior callbacks are immediately -** cancelled. +** If no error occurs, SQLITE_OK is returned and sqlite3Fts3DeferToken() +** called on each token to defer. Otherwise, an SQLite error code is +** returned. */ -SQLITE_API int sqlite3_unlock_notify( - sqlite3 *db, - void (*xNotify)(void **, int), - void *pArg +static int fts3EvalSelectDeferred( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pRoot, /* Consider tokens with this root node */ + Fts3TokenAndCost *aTC, /* Array of expression tokens and costs */ + int nTC /* Number of entries in aTC[] */ ){ - int rc = SQLITE_OK; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int nDocSize = 0; /* Number of pages per doc loaded */ + int rc = SQLITE_OK; /* Return code */ + int ii; /* Iterator variable for various purposes */ + int nOvfl = 0; /* Total overflow pages used by doclists */ + int nToken = 0; /* Total number of tokens in cluster */ - sqlite3_mutex_enter(db->mutex); - enterMutex(); + int nMinEst = 0; /* The minimum count for any phrase so far. */ + int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ - if( xNotify==0 ){ - removeFromBlockedList(db); - db->pBlockingConnection = 0; - db->pUnlockConnection = 0; - db->xUnlockNotify = 0; - db->pUnlockArg = 0; - }else if( 0==db->pBlockingConnection ){ - /* The blocking transaction has been concluded. Or there never was a - ** blocking transaction. In either case, invoke the notify callback - ** immediately. - */ - xNotify(&pArg, 1); - }else{ - sqlite3 *p; + /* Tokens are never deferred for FTS tables created using the content=xxx + ** option. The reason being that it is not guaranteed that the content + ** table actually contains the same data as the index. To prevent this from + ** causing any problems, the deferred token optimization is completely + ** disabled for content=xxx tables. */ + if( pTab->zContentTbl ){ + return SQLITE_OK; + } - for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection){} - if( p ){ - rc = SQLITE_LOCKED; /* Deadlock detected. */ - }else{ - db->pUnlockConnection = db->pBlockingConnection; - db->xUnlockNotify = xNotify; - db->pUnlockArg = pArg; - removeFromBlockedList(db); - addToBlockedList(db); + /* Count the tokens in this AND/NEAR cluster. If none of the doclists + ** associated with the tokens spill onto overflow pages, or if there is + ** only 1 token, exit early. No tokens to defer in this case. */ + for(ii=0; iimallocFailed ); - sqlite3ErrorWithMsg(db, rc, (rc?"database is deadlocked":0)); - sqlite3_mutex_leave(db->mutex); - return rc; -} + /* Obtain the average docsize (in pages). */ + rc = fts3EvalAverageDocsize(pCsr, &nDocSize); + assert( rc!=SQLITE_OK || nDocSize>0 ); -/* -** This function is called while stepping or preparing a statement -** associated with connection db. The operation will return SQLITE_LOCKED -** to the user because it requires a lock that will not be available -** until connection pBlocker concludes its current transaction. -*/ -SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){ - enterMutex(); - if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){ - addToBlockedList(db); + + /* Iterate through all tokens in this AND/NEAR cluster, in ascending order + ** of the number of overflow pages that will be loaded by the pager layer + ** to retrieve the entire doclist for the token from the full-text index. + ** Load the doclists for tokens that are either: + ** + ** a. The cheapest token in the entire query (i.e. the one visited by the + ** first iteration of this loop), or + ** + ** b. Part of a multi-token phrase. + ** + ** After each token doclist is loaded, merge it with the others from the + ** same phrase and count the number of documents that the merged doclist + ** contains. Set variable "nMinEst" to the smallest number of documents in + ** any phrase doclist for which 1 or more token doclists have been loaded. + ** Let nOther be the number of other phrases for which it is certain that + ** one or more tokens will not be deferred. + ** + ** Then, for each token, defer it if loading the doclist would result in + ** loading N or more overflow pages into memory, where N is computed as: + ** + ** (nMinEst + 4^nOther - 1) / (4^nOther) + */ + for(ii=0; iinOvfl) + ){ + pTC = &aTC[iTC]; + } + } + assert( pTC ); + + if( ii && pTC->nOvfl>=((nMinEst+(nLoad4/4)-1)/(nLoad4/4))*nDocSize ){ + /* The number of overflow pages to load for this (and therefore all + ** subsequent) tokens is greater than the estimated number of pages + ** that will be loaded if all subsequent tokens are deferred. + */ + Fts3PhraseToken *pToken = pTC->pToken; + rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); + fts3SegReaderCursorFree(pToken->pSegcsr); + pToken->pSegcsr = 0; + }else{ + /* Set nLoad4 to the value of (4^nOther) for the next iteration of the + ** for-loop. Except, limit the value to 2^24 to prevent it from + ** overflowing the 32-bit integer it is stored in. */ + if( ii<12 ) nLoad4 = nLoad4*4; + + if( ii==0 || (pTC->pPhrase->nToken>1 && ii!=nToken-1) ){ + /* Either this is the cheapest token in the entire query, or it is + ** part of a multi-token phrase. Either way, the entire doclist will + ** (eventually) be loaded into memory. It may as well be now. */ + Fts3PhraseToken *pToken = pTC->pToken; + int nList = 0; + char *pList = 0; + rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList); + assert( rc==SQLITE_OK || pList==0 ); + if( rc==SQLITE_OK ){ + rc = fts3EvalPhraseMergeToken( + pTab, pTC->pPhrase, pTC->iToken,pList,nList + ); + } + if( rc==SQLITE_OK ){ + int nCount; + nCount = fts3DoclistCountDocids( + pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll + ); + if( ii==0 || nCountpToken = 0; } - db->pBlockingConnection = pBlocker; - leaveMutex(); + + return rc; } /* -** This function is called when -** the transaction opened by database db has just finished. Locks held -** by database connection db have been released. -** -** This function loops through each entry in the blocked connections -** list and does the following: -** -** 1) If the sqlite3.pBlockingConnection member of a list entry is -** set to db, then set pBlockingConnection=0. -** -** 2) If the sqlite3.pUnlockConnection member of a list entry is -** set to db, then invoke the configured unlock-notify callback and -** set pUnlockConnection=0. +** This function is called from within the xFilter method. It initializes +** the full-text query currently stored in pCsr->pExpr. To iterate through +** the results of a query, the caller does: ** -** 3) If the two steps above mean that pBlockingConnection==0 and -** pUnlockConnection==0, remove the entry from the blocked connections -** list. +** fts3EvalStart(pCsr); +** while( 1 ){ +** fts3EvalNext(pCsr); +** if( pCsr->bEof ) break; +** ... return row pCsr->iPrevId to the caller ... +** } */ -SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){ - void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */ - int nArg = 0; /* Number of entries in aArg[] */ - sqlite3 **pp; /* Iterator variable */ - void **aArg; /* Arguments to the unlock callback */ - void **aDyn = 0; /* Dynamically allocated space for aArg[] */ - void *aStatic[16]; /* Starter space for aArg[]. No malloc required */ +static int fts3EvalStart(Fts3Cursor *pCsr){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int nToken = 0; + int nOr = 0; - aArg = aStatic; - enterMutex(); /* Enter STATIC_MASTER mutex */ + /* Allocate a MultiSegReader for each token in the expression. */ + fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); - /* This loop runs once for each entry in the blocked-connections list. */ - for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){ - sqlite3 *p = *pp; + /* Determine which, if any, tokens in the expression should be deferred. */ +#ifndef SQLITE_DISABLE_FTS4_DEFERRED + if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ + Fts3TokenAndCost *aTC; + aTC = (Fts3TokenAndCost *)sqlite3_malloc64( + sizeof(Fts3TokenAndCost) * nToken + + sizeof(Fts3Expr *) * nOr * 2 + ); - /* Step 1. */ - if( p->pBlockingConnection==db ){ - p->pBlockingConnection = 0; - } + if( !aTC ){ + rc = SQLITE_NOMEM; + }else{ + Fts3Expr **apOr = (Fts3Expr **)&aTC[nToken]; + int ii; + Fts3TokenAndCost *pTC = aTC; + Fts3Expr **ppOr = apOr; - /* Step 2. */ - if( p->pUnlockConnection==db ){ - assert( p->xUnlockNotify ); - if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){ - xUnlockNotify(aArg, nArg); - nArg = 0; - } + fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc); + nToken = (int)(pTC-aTC); + nOr = (int)(ppOr-apOr); - sqlite3BeginBenignMalloc(); - assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) ); - assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn ); - if( (!aDyn && nArg==(int)ArraySize(aStatic)) - || (aDyn && nArg==(int)(sqlite3MallocSize(aDyn)/sizeof(void*))) - ){ - /* The aArg[] array needs to grow. */ - void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2); - if( pNew ){ - memcpy(pNew, aArg, nArg*sizeof(void *)); - sqlite3_free(aDyn); - aDyn = aArg = pNew; - }else{ - /* This occurs when the array of context pointers that need to - ** be passed to the unlock-notify callback is larger than the - ** aStatic[] array allocated on the stack and the attempt to - ** allocate a larger array from the heap has failed. - ** - ** This is a difficult situation to handle. Returning an error - ** code to the caller is insufficient, as even if an error code - ** is returned the transaction on connection db will still be - ** closed and the unlock-notify callbacks on blocked connections - ** will go unissued. This might cause the application to wait - ** indefinitely for an unlock-notify callback that will never - ** arrive. - ** - ** Instead, invoke the unlock-notify callback with the context - ** array already accumulated. We can then clear the array and - ** begin accumulating any further context pointers without - ** requiring any dynamic allocation. This is sub-optimal because - ** it means that instead of one callback with a large array of - ** context pointers the application will receive two or more - ** callbacks with smaller arrays of context pointers, which will - ** reduce the applications ability to prioritize multiple - ** connections. But it is the best that can be done under the - ** circumstances. - */ - xUnlockNotify(aArg, nArg); - nArg = 0; + if( rc==SQLITE_OK ){ + rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken); + for(ii=0; rc==SQLITE_OK && iipUnlockArg; - xUnlockNotify = p->xUnlockNotify; - p->pUnlockConnection = 0; - p->xUnlockNotify = 0; - p->pUnlockArg = 0; - } - /* Step 3. */ - if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){ - /* Remove connection p from the blocked connections list. */ - *pp = p->pNextBlocked; - p->pNextBlocked = 0; - }else{ - pp = &p->pNextBlocked; + sqlite3_free(aTC); } } +#endif - if( nArg!=0 ){ - xUnlockNotify(aArg, nArg); - } - sqlite3_free(aDyn); - leaveMutex(); /* Leave STATIC_MASTER mutex */ + fts3EvalStartReaders(pCsr, pCsr->pExpr, &rc); + return rc; } /* -** This is called when the database connection passed as an argument is -** being closed. The connection is removed from the blocked list. +** Invalidate the current position list for phrase pPhrase. */ -SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){ - sqlite3ConnectionUnlocked(db); - enterMutex(); - removeFromBlockedList(db); - checkListProperties(db); - leaveMutex(); +static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){ + if( pPhrase->doclist.bFreeList ){ + sqlite3_free(pPhrase->doclist.pList); + } + pPhrase->doclist.pList = 0; + pPhrase->doclist.nList = 0; + pPhrase->doclist.bFreeList = 0; } -#endif -/************** End of notify.c **********************************************/ -/************** Begin file fts3.c ********************************************/ /* -** 2006 Oct 10 +** This function is called to edit the position list associated with +** the phrase object passed as the fifth argument according to a NEAR +** condition. For example: ** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: +** abc NEAR/5 "def ghi" ** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** Parameter nNear is passed the NEAR distance of the expression (5 in +** the example above). When this function is called, *paPoslist points to +** the position list, and *pnToken is the number of phrase tokens in the +** phrase on the other side of the NEAR operator to pPhrase. For example, +** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to +** the position list associated with phrase "abc". ** -****************************************************************************** +** All positions in the pPhrase position list that are not sufficiently +** close to a position in the *paPoslist position list are removed. If this +** leaves 0 positions, zero is returned. Otherwise, non-zero. ** -** This is an SQLite module implementing full-text search. +** Before returning, *paPoslist is set to point to the position lsit +** associated with pPhrase. And *pnToken is set to the number of tokens in +** pPhrase. */ +static int fts3EvalNearTrim( + int nNear, /* NEAR distance. As in "NEAR/nNear". */ + char *aTmp, /* Temporary space to use */ + char **paPoslist, /* IN/OUT: Position list */ + int *pnToken, /* IN/OUT: Tokens in phrase of *paPoslist */ + Fts3Phrase *pPhrase /* The phrase object to trim the doclist of */ +){ + int nParam1 = nNear + pPhrase->nToken; + int nParam2 = nNear + *pnToken; + int nNew; + char *p2; + char *pOut; + int res; -/* -** The code in this file is only compiled if: -** -** * The FTS3 module is being built as an extension -** (in which case SQLITE_CORE is not defined), or -** -** * The FTS3 module is being built into the core of -** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). -*/ + assert( pPhrase->doclist.pList ); -/* The full-text index is stored in a series of b+tree (-like) -** structures called segments which map terms to doclists. The -** structures are like b+trees in layout, but are constructed from the -** bottom up in optimal fashion and are not updatable. Since trees -** are built from the bottom up, things will be described from the -** bottom up. -** -** -**** Varints **** -** The basic unit of encoding is a variable-length integer called a -** varint. We encode variable-length integers in little-endian order -** using seven bits * per byte as follows: -** -** KEY: -** A = 0xxxxxxx 7 bits of data and one flag bit -** B = 1xxxxxxx 7 bits of data and one flag bit -** -** 7 bits - A -** 14 bits - BA -** 21 bits - BBA -** and so on. -** -** This is similar in concept to how sqlite encodes "varints" but -** the encoding is not the same. SQLite varints are big-endian -** are are limited to 9 bytes in length whereas FTS3 varints are -** little-endian and can be up to 10 bytes in length (in theory). -** -** Example encodings: -** -** 1: 0x01 -** 127: 0x7f -** 128: 0x81 0x00 -** -** -**** Document lists **** -** A doclist (document list) holds a docid-sorted list of hits for a -** given term. Doclists hold docids and associated token positions. -** A docid is the unique integer identifier for a single document. -** A position is the index of a word within the document. The first -** word of the document has a position of 0. -** -** FTS3 used to optionally store character offsets using a compile-time -** option. But that functionality is no longer supported. -** -** A doclist is stored like this: -** -** array { -** varint docid; (delta from previous doclist) -** array { (position list for column 0) -** varint position; (2 more than the delta from previous position) -** } -** array { -** varint POS_COLUMN; (marks start of position list for new column) -** varint column; (index of new column) -** array { -** varint position; (2 more than the delta from previous position) -** } -** } -** varint POS_END; (marks end of positions for this document. -** } -** -** Here, array { X } means zero or more occurrences of X, adjacent in -** memory. A "position" is an index of a token in the token stream -** generated by the tokenizer. Note that POS_END and POS_COLUMN occur -** in the same logical place as the position element, and act as sentinals -** ending a position list array. POS_END is 0. POS_COLUMN is 1. -** The positions numbers are not stored literally but rather as two more -** than the difference from the prior position, or the just the position plus -** 2 for the first position. Example: -** -** label: A B C D E F G H I J K -** value: 123 5 9 1 1 14 35 0 234 72 0 -** -** The 123 value is the first docid. For column zero in this document -** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1 -** at D signals the start of a new column; the 1 at E indicates that the -** new column is column number 1. There are two positions at 12 and 45 -** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The -** 234 at I is the delta to next docid (357). It has one position 70 -** (72-2) and then terminates with the 0 at K. -** -** A "position-list" is the list of positions for multiple columns for -** a single docid. A "column-list" is the set of positions for a single -** column. Hence, a position-list consists of one or more column-lists, -** a document record consists of a docid followed by a position-list and -** a doclist consists of one or more document records. -** -** A bare doclist omits the position information, becoming an -** array of varint-encoded docids. -** -**** Segment leaf nodes **** -** Segment leaf nodes store terms and doclists, ordered by term. Leaf -** nodes are written using LeafWriter, and read using LeafReader (to -** iterate through a single leaf node's data) and LeavesReader (to -** iterate through a segment's entire leaf layer). Leaf nodes have -** the format: -** -** varint iHeight; (height from leaf level, always 0) -** varint nTerm; (length of first term) -** char pTerm[nTerm]; (content of first term) -** varint nDoclist; (length of term's associated doclist) -** char pDoclist[nDoclist]; (content of doclist) -** array { -** (further terms are delta-encoded) -** varint nPrefix; (length of prefix shared with previous term) -** varint nSuffix; (length of unshared suffix) -** char pTermSuffix[nSuffix];(unshared suffix of next term) -** varint nDoclist; (length of term's associated doclist) -** char pDoclist[nDoclist]; (content of doclist) -** } -** -** Here, array { X } means zero or more occurrences of X, adjacent in -** memory. -** -** Leaf nodes are broken into blocks which are stored contiguously in -** the %_segments table in sorted order. This means that when the end -** of a node is reached, the next term is in the node with the next -** greater node id. -** -** New data is spilled to a new leaf node when the current node -** exceeds LEAF_MAX bytes (default 2048). New data which itself is -** larger than STANDALONE_MIN (default 1024) is placed in a standalone -** node (a leaf node with a single term and doclist). The goal of -** these settings is to pack together groups of small doclists while -** making it efficient to directly access large doclists. The -** assumption is that large doclists represent terms which are more -** likely to be query targets. -** -** TODO(shess) It may be useful for blocking decisions to be more -** dynamic. For instance, it may make more sense to have a 2.5k leaf -** node rather than splitting into 2k and .5k nodes. My intuition is -** that this might extend through 2x or 4x the pagesize. -** -** -**** Segment interior nodes **** -** Segment interior nodes store blockids for subtree nodes and terms -** to describe what data is stored by the each subtree. Interior -** nodes are written using InteriorWriter, and read using -** InteriorReader. InteriorWriters are created as needed when -** SegmentWriter creates new leaf nodes, or when an interior node -** itself grows too big and must be split. The format of interior -** nodes: -** -** varint iHeight; (height from leaf level, always >0) -** varint iBlockid; (block id of node's leftmost subtree) -** optional { -** varint nTerm; (length of first term) -** char pTerm[nTerm]; (content of first term) -** array { -** (further terms are delta-encoded) -** varint nPrefix; (length of shared prefix with previous term) -** varint nSuffix; (length of unshared suffix) -** char pTermSuffix[nSuffix]; (unshared suffix of next term) -** } -** } -** -** Here, optional { X } means an optional element, while array { X } -** means zero or more occurrences of X, adjacent in memory. -** -** An interior node encodes n terms separating n+1 subtrees. The -** subtree blocks are contiguous, so only the first subtree's blockid -** is encoded. The subtree at iBlockid will contain all terms less -** than the first term encoded (or all terms if no term is encoded). -** Otherwise, for terms greater than or equal to pTerm[i] but less -** than pTerm[i+1], the subtree for that term will be rooted at -** iBlockid+i. Interior nodes only store enough term data to -** distinguish adjacent children (if the rightmost term of the left -** child is "something", and the leftmost term of the right child is -** "wicked", only "w" is stored). -** -** New data is spilled to a new interior node at the same height when -** the current node exceeds INTERIOR_MAX bytes (default 2048). -** INTERIOR_MIN_TERMS (default 7) keeps large terms from monopolizing -** interior nodes and making the tree too skinny. The interior nodes -** at a given height are naturally tracked by interior nodes at -** height+1, and so on. -** -** -**** Segment directory **** -** The segment directory in table %_segdir stores meta-information for -** merging and deleting segments, and also the root node of the -** segment's tree. -** -** The root node is the top node of the segment's tree after encoding -** the entire segment, restricted to ROOT_MAX bytes (default 1024). -** This could be either a leaf node or an interior node. If the top -** node requires more than ROOT_MAX bytes, it is flushed to %_segments -** and a new root interior node is generated (which should always fit -** within ROOT_MAX because it only needs space for 2 varints, the -** height and the blockid of the previous root). -** -** The meta-information in the segment directory is: -** level - segment level (see below) -** idx - index within level -** - (level,idx uniquely identify a segment) -** start_block - first leaf node -** leaves_end_block - last leaf node -** end_block - last block (including interior nodes) -** root - contents of root node -** -** If the root node is a leaf node, then start_block, -** leaves_end_block, and end_block are all 0. -** -** -**** Segment merging **** -** To amortize update costs, segments are grouped into levels and -** merged in batches. Each increase in level represents exponentially -** more documents. -** -** New documents (actually, document updates) are tokenized and -** written individually (using LeafWriter) to a level 0 segment, with -** incrementing idx. When idx reaches MERGE_COUNT (default 16), all -** level 0 segments are merged into a single level 1 segment. Level 1 -** is populated like level 0, and eventually MERGE_COUNT level 1 -** segments are merged to a single level 2 segment (representing -** MERGE_COUNT^2 updates), and so on. -** -** A segment merge traverses all segments at a given level in -** parallel, performing a straightforward sorted merge. Since segment -** leaf nodes are written in to the %_segments table in order, this -** merge traverses the underlying sqlite disk structures efficiently. -** After the merge, all segment blocks from the merged level are -** deleted. -** -** MERGE_COUNT controls how often we merge segments. 16 seems to be -** somewhat of a sweet spot for insertion performance. 32 and 64 show -** very similar performance numbers to 16 on insertion, though they're -** a tiny bit slower (perhaps due to more overhead in merge-time -** sorting). 8 is about 20% slower than 16, 4 about 50% slower than -** 16, 2 about 66% slower than 16. -** -** At query time, high MERGE_COUNT increases the number of segments -** which need to be scanned and merged. For instance, with 100k docs -** inserted: -** -** MERGE_COUNT segments -** 16 25 -** 8 12 -** 4 10 -** 2 6 -** -** This appears to have only a moderate impact on queries for very -** frequent terms (which are somewhat dominated by segment merge -** costs), and infrequent and non-existent terms still seem to be fast -** even with many segments. -** -** TODO(shess) That said, it would be nice to have a better query-side -** argument for MERGE_COUNT of 16. Also, it is possible/likely that -** optimizations to things like doclist merging will swing the sweet -** spot around. -** -** -** -**** Handling of deletions and updates **** -** Since we're using a segmented structure, with no docid-oriented -** index into the term index, we clearly cannot simply update the term -** index when a document is deleted or updated. For deletions, we -** write an empty doclist (varint(docid) varint(POS_END)), for updates -** we simply write the new doclist. Segment merges overwrite older -** data for a particular docid with newer data, so deletes or updates -** will eventually overtake the earlier data and knock it out. The -** query logic likewise merges doclists so that newer data knocks out -** older data. -*/ + p2 = pOut = pPhrase->doclist.pList; + res = fts3PoslistNearMerge( + &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 + ); + if( res ){ + nNew = (int)(pOut - pPhrase->doclist.pList) - 1; + assert_fts3_nc( nNew<=pPhrase->doclist.nList && nNew>0 ); + if( nNew>=0 && nNew<=pPhrase->doclist.nList ){ + assert( pPhrase->doclist.pList[nNew]=='\0' ); + memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew); + pPhrase->doclist.nList = nNew; + } + *paPoslist = pPhrase->doclist.pList; + *pnToken = pPhrase->nToken; + } + + return res; +} -/************** Include fts3Int.h in the middle of fts3.c ********************/ -/************** Begin file fts3Int.h *****************************************/ /* -** 2009 Nov 12 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** This function is a no-op if *pRc is other than SQLITE_OK when it is called. +** Otherwise, it advances the expression passed as the second argument to +** point to the next matching row in the database. Expressions iterate through +** matching rows in docid order. Ascending order if Fts3Cursor.bDesc is zero, +** or descending if it is non-zero. ** -****************************************************************************** +** If an error occurs, *pRc is set to an SQLite error code. Otherwise, if +** successful, the following variables in pExpr are set: ** -*/ -#ifndef _FTSINT_H -#define _FTSINT_H - -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) -# define NDEBUG 1 -#endif - -/* FTS3/FTS4 require virtual tables */ -#ifdef SQLITE_OMIT_VIRTUALTABLE -# undef SQLITE_ENABLE_FTS3 -# undef SQLITE_ENABLE_FTS4 -#endif - -/* -** FTS4 is really an extension for FTS3. It is enabled using the -** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all -** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3. -*/ -#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3) -# define SQLITE_ENABLE_FTS3 -#endif - -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -/* If not building as part of the core, include sqlite3ext.h. */ -#ifndef SQLITE_CORE -/* # include "sqlite3ext.h" */ -SQLITE_EXTENSION_INIT3 -#endif - -/* #include "sqlite3.h" */ -/************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/ -/************** Begin file fts3_tokenizer.h **********************************/ -/* -** 2006 July 10 +** Fts3Expr.bEof (non-zero if EOF - there is no next row) +** Fts3Expr.iDocid (valid if bEof==0. The docid of the next row) ** -** The author disclaims copyright to this source code. +** If the expression is of type FTSQUERY_PHRASE, and the expression is not +** at EOF, then the following variables are populated with the position list +** for the phrase for the visited row: ** -************************************************************************* -** Defines the interface to tokenizers used by fulltext-search. There -** are three basic components: +** FTs3Expr.pPhrase->doclist.nList (length of pList in bytes) +** FTs3Expr.pPhrase->doclist.pList (pointer to position list) ** -** sqlite3_tokenizer_module is a singleton defining the tokenizer -** interface functions. This is essentially the class structure for -** tokenizers. +** It says above that this function advances the expression to the next +** matching row. This is usually true, but there are the following exceptions: ** -** sqlite3_tokenizer is used to define a particular tokenizer, perhaps -** including customization information defined at creation time. +** 1. Deferred tokens are not taken into account. If a phrase consists +** entirely of deferred tokens, it is assumed to match every row in +** the db. In this case the position-list is not populated at all. ** -** sqlite3_tokenizer_cursor is generated by a tokenizer to generate -** tokens from a particular input. -*/ -#ifndef _FTS3_TOKENIZER_H_ -#define _FTS3_TOKENIZER_H_ - -/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. -** If tokenizers are to be allowed to call sqlite3_*() functions, then -** we will need a way to register the API consistently. -*/ -/* #include "sqlite3.h" */ - -/* -** Structures used by the tokenizer interface. When a new tokenizer -** implementation is registered, the caller provides a pointer to -** an sqlite3_tokenizer_module containing pointers to the callback -** functions that make up an implementation. +** Or, if a phrase contains one or more deferred tokens and one or +** more non-deferred tokens, then the expression is advanced to the +** next possible match, considering only non-deferred tokens. In other +** words, if the phrase is "A B C", and "B" is deferred, the expression +** is advanced to the next row that contains an instance of "A * C", +** where "*" may match any single token. The position list in this case +** is populated as for "A * C" before returning. ** -** When an fts3 table is created, it passes any arguments passed to -** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the -** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer -** implementation. The xCreate() function in turn returns an -** sqlite3_tokenizer structure representing the specific tokenizer to -** be used for the fts3 table (customized by the tokenizer clause arguments). +** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is +** advanced to point to the next row that matches "x AND y". ** -** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() -** method is called. It returns an sqlite3_tokenizer_cursor object -** that may be used to tokenize a specific input buffer based on -** the tokenization rules supplied by a specific sqlite3_tokenizer -** object. +** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is +** really a match, taking into account deferred tokens and NEAR operators. */ -typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; -typedef struct sqlite3_tokenizer sqlite3_tokenizer; -typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; - -struct sqlite3_tokenizer_module { - - /* - ** Structure version. Should always be set to 0 or 1. - */ - int iVersion; - - /* - ** Create a new tokenizer. The values in the argv[] array are the - ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL - ** TABLE statement that created the fts3 table. For example, if - ** the following SQL is executed: - ** - ** CREATE .. USING fts3( ... , tokenizer arg1 arg2) - ** - ** then argc is set to 2, and the argv[] array contains pointers - ** to the strings "arg1" and "arg2". - ** - ** This method should return either SQLITE_OK (0), or an SQLite error - ** code. If SQLITE_OK is returned, then *ppTokenizer should be set - ** to point at the newly created tokenizer structure. The generic - ** sqlite3_tokenizer.pModule variable should not be initialized by - ** this callback. The caller will do so. - */ - int (*xCreate)( - int argc, /* Size of argv array */ - const char *const*argv, /* Tokenizer argument strings */ - sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ - ); - - /* - ** Destroy an existing tokenizer. The fts3 module calls this method - ** exactly once for each successful call to xCreate(). - */ - int (*xDestroy)(sqlite3_tokenizer *pTokenizer); - - /* - ** Create a tokenizer cursor to tokenize an input buffer. The caller - ** is responsible for ensuring that the input buffer remains valid - ** until the cursor is closed (using the xClose() method). - */ - int (*xOpen)( - sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ - const char *pInput, int nBytes, /* Input buffer */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ - ); - - /* - ** Destroy an existing tokenizer cursor. The fts3 module calls this - ** method exactly once for each successful call to xOpen(). - */ - int (*xClose)(sqlite3_tokenizer_cursor *pCursor); - - /* - ** Retrieve the next token from the tokenizer cursor pCursor. This - ** method should either return SQLITE_OK and set the values of the - ** "OUT" variables identified below, or SQLITE_DONE to indicate that - ** the end of the buffer has been reached, or an SQLite error code. - ** - ** *ppToken should be set to point at a buffer containing the - ** normalized version of the token (i.e. after any case-folding and/or - ** stemming has been performed). *pnBytes should be set to the length - ** of this buffer in bytes. The input text that generated the token is - ** identified by the byte offsets returned in *piStartOffset and - ** *piEndOffset. *piStartOffset should be set to the index of the first - ** byte of the token in the input buffer. *piEndOffset should be set - ** to the index of the first byte just past the end of the token in - ** the input buffer. - ** - ** The buffer *ppToken is set to point at is managed by the tokenizer - ** implementation. It is only required to be valid until the next call - ** to xNext() or xClose(). - */ - /* TODO(shess) current implementation requires pInput to be - ** nul-terminated. This should either be fixed, or pInput/nBytes - ** should be converted to zInput. - */ - int (*xNext)( - sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ - const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ - int *piStartOffset, /* OUT: Byte offset of token in input buffer */ - int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ - int *piPosition /* OUT: Number of tokens returned before this one */ - ); +static void fts3EvalNextRow( + Fts3Cursor *pCsr, /* FTS Cursor handle */ + Fts3Expr *pExpr, /* Expr. to advance to next matching row */ + int *pRc /* IN/OUT: Error code */ +){ + if( *pRc==SQLITE_OK ){ + int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */ + assert( pExpr->bEof==0 ); + pExpr->bStart = 1; - /*********************************************************************** - ** Methods below this point are only available if iVersion>=1. - */ + switch( pExpr->eType ){ + case FTSQUERY_NEAR: + case FTSQUERY_AND: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + assert( !pLeft->bDeferred || !pRight->bDeferred ); - /* - ** Configure the language id of a tokenizer cursor. - */ - int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid); -}; + if( pLeft->bDeferred ){ + /* LHS is entirely deferred. So we assume it matches every row. + ** Advance the RHS iterator to find the next row visited. */ + fts3EvalNextRow(pCsr, pRight, pRc); + pExpr->iDocid = pRight->iDocid; + pExpr->bEof = pRight->bEof; + }else if( pRight->bDeferred ){ + /* RHS is entirely deferred. So we assume it matches every row. + ** Advance the LHS iterator to find the next row visited. */ + fts3EvalNextRow(pCsr, pLeft, pRc); + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = pLeft->bEof; + }else{ + /* Neither the RHS or LHS are deferred. */ + fts3EvalNextRow(pCsr, pLeft, pRc); + fts3EvalNextRow(pCsr, pRight, pRc); + while( !pLeft->bEof && !pRight->bEof && *pRc==SQLITE_OK ){ + sqlite3_int64 iDiff = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + if( iDiff==0 ) break; + if( iDiff<0 ){ + fts3EvalNextRow(pCsr, pLeft, pRc); + }else{ + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = (pLeft->bEof || pRight->bEof); + if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){ + assert( pRight->eType==FTSQUERY_PHRASE ); + if( pRight->pPhrase->doclist.aAll ){ + Fts3Doclist *pDl = &pRight->pPhrase->doclist; + while( *pRc==SQLITE_OK && pRight->bEof==0 ){ + memset(pDl->pList, 0, pDl->nList); + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){ + Fts3Doclist *pDl = &pLeft->pPhrase->doclist; + while( *pRc==SQLITE_OK && pLeft->bEof==0 ){ + memset(pDl->pList, 0, pDl->nList); + fts3EvalNextRow(pCsr, pLeft, pRc); + } + } + pRight->bEof = pLeft->bEof = 1; + } + } + break; + } -struct sqlite3_tokenizer { - const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ - /* Tokenizer implementations will typically add additional fields */ -}; + case FTSQUERY_OR: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; + sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); -struct sqlite3_tokenizer_cursor { - sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ - /* Tokenizer implementations will typically add additional fields */ -}; + assert_fts3_nc( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); + assert_fts3_nc( pRight->bStart || pLeft->iDocid==pRight->iDocid ); -int fts3_global_term_cnt(int iTerm, int iCol); -int fts3_term_cnt(int iTerm, int iCol); + if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ + fts3EvalNextRow(pCsr, pLeft, pRc); + }else if( pLeft->bEof || iCmp>0 ){ + fts3EvalNextRow(pCsr, pRight, pRc); + }else{ + fts3EvalNextRow(pCsr, pLeft, pRc); + fts3EvalNextRow(pCsr, pRight, pRc); + } + pExpr->bEof = (pLeft->bEof && pRight->bEof); + iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); + if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ + pExpr->iDocid = pLeft->iDocid; + }else{ + pExpr->iDocid = pRight->iDocid; + } -#endif /* _FTS3_TOKENIZER_H_ */ + break; + } -/************** End of fts3_tokenizer.h **************************************/ -/************** Continuing where we left off in fts3Int.h ********************/ -/************** Include fts3_hash.h in the middle of fts3Int.h ***************/ -/************** Begin file fts3_hash.h ***************************************/ -/* -** 2001 September 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This is the header file for the generic hash-table implementation -** used in SQLite. We've modified it slightly to serve as a standalone -** hash table implementation for the full-text indexing module. -** -*/ -#ifndef _FTS3_HASH_H_ -#define _FTS3_HASH_H_ + case FTSQUERY_NOT: { + Fts3Expr *pLeft = pExpr->pLeft; + Fts3Expr *pRight = pExpr->pRight; -/* Forward declarations of structures. */ -typedef struct Fts3Hash Fts3Hash; -typedef struct Fts3HashElem Fts3HashElem; + if( pRight->bStart==0 ){ + fts3EvalNextRow(pCsr, pRight, pRc); + assert( *pRc!=SQLITE_OK || pRight->bStart ); + } -/* A complete hash table is an instance of the following structure. -** The internals of this structure are intended to be opaque -- client -** code should not attempt to access or modify the fields of this structure -** directly. Change this structure only by using the routines below. -** However, many of the "procedures" and "functions" for modifying and -** accessing this structure are really macros, so we can't really make -** this structure opaque. -*/ -struct Fts3Hash { - char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ - char copyKey; /* True if copy of key made on insert */ - int count; /* Number of entries in this table */ - Fts3HashElem *first; /* The first element of the array */ - int htsize; /* Number of buckets in the hash table */ - struct _fts3ht { /* the hash table */ - int count; /* Number of entries with this hash */ - Fts3HashElem *chain; /* Pointer to first entry with this hash */ - } *ht; -}; + fts3EvalNextRow(pCsr, pLeft, pRc); + if( pLeft->bEof==0 ){ + while( !*pRc + && !pRight->bEof + && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0 + ){ + fts3EvalNextRow(pCsr, pRight, pRc); + } + } + pExpr->iDocid = pLeft->iDocid; + pExpr->bEof = pLeft->bEof; + break; + } -/* Each element in the hash table is an instance of the following -** structure. All elements are stored on a single doubly-linked list. -** -** Again, this structure is intended to be opaque, but it can't really -** be opaque because it is used by macros. -*/ -struct Fts3HashElem { - Fts3HashElem *next, *prev; /* Next and previous elements in the table */ - void *data; /* Data associated with this element */ - void *pKey; int nKey; /* Key associated with this element */ -}; + default: { + Fts3Phrase *pPhrase = pExpr->pPhrase; + fts3EvalInvalidatePoslist(pPhrase); + *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof); + pExpr->iDocid = pPhrase->doclist.iDocid; + break; + } + } + } +} /* -** There are 2 different modes of operation for a hash table: -** -** FTS3_HASH_STRING pKey points to a string that is nKey bytes long -** (including the null-terminator, if any). Case -** is respected in comparisons. +** If *pRc is not SQLITE_OK, or if pExpr is not the root node of a NEAR +** cluster, then this function returns 1 immediately. ** -** FTS3_HASH_BINARY pKey points to binary data nKey bytes long. -** memcmp() is used to compare keys. +** Otherwise, it checks if the current row really does match the NEAR +** expression, using the data currently stored in the position lists +** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression. ** -** A copy of the key is made if the copyKey parameter to fts3HashInit is 1. +** If the current row is a match, the position list associated with each +** phrase in the NEAR expression is edited in place to contain only those +** phrase instances sufficiently close to their peers to satisfy all NEAR +** constraints. In this case it returns 1. If the NEAR expression does not +** match the current row, 0 is returned. The position lists may or may not +** be edited if 0 is returned. */ -#define FTS3_HASH_STRING 1 -#define FTS3_HASH_BINARY 2 +static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ + int res = 1; -/* -** Access routines. To delete, insert a NULL pointer. -*/ -SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey); -SQLITE_PRIVATE void *sqlite3Fts3HashInsert(Fts3Hash*, const void *pKey, int nKey, void *pData); -SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash*, const void *pKey, int nKey); -SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash*); -SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const void *, int); + /* The following block runs if pExpr is the root of a NEAR query. + ** For example, the query: + ** + ** "w" NEAR "x" NEAR "y" NEAR "z" + ** + ** which is represented in tree form as: + ** + ** | + ** +--NEAR--+ <-- root of NEAR query + ** | | + ** +--NEAR--+ "z" + ** | | + ** +--NEAR--+ "y" + ** | | + ** "w" "x" + ** + ** The right-hand child of a NEAR node is always a phrase. The + ** left-hand child may be either a phrase or a NEAR node. There are + ** no exceptions to this - it's the way the parser in fts3_expr.c works. + */ + if( *pRc==SQLITE_OK + && pExpr->eType==FTSQUERY_NEAR + && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) + ){ + Fts3Expr *p; + sqlite3_int64 nTmp = 0; /* Bytes of temp space */ + char *aTmp; /* Temp space for PoslistNearMerge() */ -/* -** Shorthand for the functions above -*/ -#define fts3HashInit sqlite3Fts3HashInit -#define fts3HashInsert sqlite3Fts3HashInsert -#define fts3HashFind sqlite3Fts3HashFind -#define fts3HashClear sqlite3Fts3HashClear -#define fts3HashFindElem sqlite3Fts3HashFindElem + /* Allocate temporary working space. */ + for(p=pExpr; p->pLeft; p=p->pLeft){ + assert( p->pRight->pPhrase->doclist.nList>0 ); + nTmp += p->pRight->pPhrase->doclist.nList; + } + nTmp += p->pPhrase->doclist.nList; + aTmp = sqlite3_malloc64(nTmp*2); + if( !aTmp ){ + *pRc = SQLITE_NOMEM; + res = 0; + }else{ + char *aPoslist = p->pPhrase->doclist.pList; + int nToken = p->pPhrase->nToken; -/* -** Macros for looping over all elements of a hash table. The idiom is -** like this: -** -** Fts3Hash h; -** Fts3HashElem *p; -** ... -** for(p=fts3HashFirst(&h); p; p=fts3HashNext(p)){ -** SomeStructure *pData = fts3HashData(p); -** // do something with pData -** } -*/ -#define fts3HashFirst(H) ((H)->first) -#define fts3HashNext(E) ((E)->next) -#define fts3HashData(E) ((E)->data) -#define fts3HashKey(E) ((E)->pKey) -#define fts3HashKeysize(E) ((E)->nKey) + for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ + Fts3Phrase *pPhrase = p->pRight->pPhrase; + int nNear = p->nNear; + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); + } -/* -** Number of entries in a hash table -*/ -#define fts3HashCount(H) ((H)->count) + aPoslist = pExpr->pRight->pPhrase->doclist.pList; + nToken = pExpr->pRight->pPhrase->nToken; + for(p=pExpr->pLeft; p && res; p=p->pLeft){ + int nNear; + Fts3Phrase *pPhrase; + assert( p->pParent && p->pParent->pLeft==p ); + nNear = p->pParent->nNear; + pPhrase = ( + p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase + ); + res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); + } + } -#endif /* _FTS3_HASH_H_ */ + sqlite3_free(aTmp); + } -/************** End of fts3_hash.h *******************************************/ -/************** Continuing where we left off in fts3Int.h ********************/ + return res; +} /* -** This constant determines the maximum depth of an FTS expression tree -** that the library will create and use. FTS uses recursion to perform -** various operations on the query tree, so the disadvantage of a large -** limit is that it may allow very large queries to use large amounts -** of stack space (perhaps causing a stack overflow). +** This function is a helper function for sqlite3Fts3EvalTestDeferred(). +** Assuming no error occurs or has occurred, It returns non-zero if the +** expression passed as the second argument matches the row that pCsr +** currently points to, or zero if it does not. +** +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** If an error occurs during execution of this function, *pRc is set to +** the appropriate SQLite error code. In this case the returned value is +** undefined. */ -#ifndef SQLITE_FTS3_MAX_EXPR_DEPTH -# define SQLITE_FTS3_MAX_EXPR_DEPTH 12 -#endif - +static int fts3EvalTestExpr( + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Expr to test. May or may not be root. */ + int *pRc /* IN/OUT: Error code */ +){ + int bHit = 1; /* Return value */ + if( *pRc==SQLITE_OK ){ + switch( pExpr->eType ){ + case FTSQUERY_NEAR: + case FTSQUERY_AND: + bHit = ( + fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) + && fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) + && fts3EvalNearTest(pExpr, pRc) + ); -/* -** This constant controls how often segments are merged. Once there are -** FTS3_MERGE_COUNT segments of level N, they are merged into a single -** segment of level N+1. -*/ -#define FTS3_MERGE_COUNT 16 + /* If the NEAR expression does not match any rows, zero the doclist for + ** all phrases involved in the NEAR. This is because the snippet(), + ** offsets() and matchinfo() functions are not supposed to recognize + ** any instances of phrases that are part of unmatched NEAR queries. + ** For example if this expression: + ** + ** ... MATCH 'a OR (b NEAR c)' + ** + ** is matched against a row containing: + ** + ** 'a b d e' + ** + ** then any snippet() should ony highlight the "a" term, not the "b" + ** (as "b" is part of a non-matching NEAR clause). + */ + if( bHit==0 + && pExpr->eType==FTSQUERY_NEAR + && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) + ){ + Fts3Expr *p; + for(p=pExpr; p->pPhrase==0; p=p->pLeft){ + if( p->pRight->iDocid==pCsr->iPrevId ){ + fts3EvalInvalidatePoslist(p->pRight->pPhrase); + } + } + if( p->iDocid==pCsr->iPrevId ){ + fts3EvalInvalidatePoslist(p->pPhrase); + } + } -/* -** This is the maximum amount of data (in bytes) to store in the -** Fts3Table.pendingTerms hash table. Normally, the hash table is -** populated as documents are inserted/updated/deleted in a transaction -** and used to create a new segment when the transaction is committed. -** However if this limit is reached midway through a transaction, a new -** segment is created and the hash table cleared immediately. -*/ -#define FTS3_MAX_PENDING_DATA (1*1024*1024) + break; -/* -** Macro to return the number of elements in an array. SQLite has a -** similar macro called ArraySize(). Use a different name to avoid -** a collision when building an amalgamation with built-in FTS3. -*/ -#define SizeofArray(X) ((int)(sizeof(X)/sizeof(X[0]))) + case FTSQUERY_OR: { + int bHit1 = fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc); + int bHit2 = fts3EvalTestExpr(pCsr, pExpr->pRight, pRc); + bHit = bHit1 || bHit2; + break; + } + case FTSQUERY_NOT: + bHit = ( + fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) + && !fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) + ); + break; -#ifndef MIN -# define MIN(x,y) ((x)<(y)?(x):(y)) -#endif -#ifndef MAX -# define MAX(x,y) ((x)>(y)?(x):(y)) + default: { +#ifndef SQLITE_DISABLE_FTS4_DEFERRED + if( pCsr->pDeferred + && (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred) + ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 ); + if( pExpr->bDeferred ){ + fts3EvalInvalidatePoslist(pPhrase); + } + *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); + bHit = (pPhrase->doclist.pList!=0); + pExpr->iDocid = pCsr->iPrevId; + }else #endif + { + bHit = ( + pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId + && pExpr->pPhrase->doclist.nList>0 + ); + } + break; + } + } + } + return bHit; +} /* -** Maximum length of a varint encoded integer. The varint format is different -** from that used by SQLite, so the maximum length is 10, not 9. -*/ -#define FTS3_VARINT_MAX 10 - -/* -** FTS4 virtual tables may maintain multiple indexes - one index of all terms -** in the document set and zero or more prefix indexes. All indexes are stored -** as one or more b+-trees in the %_segments and %_segdir tables. +** This function is called as the second part of each xNext operation when +** iterating through the results of a full-text query. At this point the +** cursor points to a row that matches the query expression, with the +** following caveats: ** -** It is possible to determine which index a b+-tree belongs to based on the -** value stored in the "%_segdir.level" column. Given this value L, the index -** that the b+-tree belongs to is (L<<10). In other words, all b+-trees with -** level values between 0 and 1023 (inclusive) belong to index 0, all levels -** between 1024 and 2047 to index 1, and so on. +** * Up until this point, "NEAR" operators in the expression have been +** treated as "AND". ** -** It is considered impossible for an index to use more than 1024 levels. In -** theory though this may happen, but only after at least -** (FTS3_MERGE_COUNT^1024) separate flushes of the pending-terms tables. -*/ -#define FTS3_SEGDIR_MAXLEVEL 1024 -#define FTS3_SEGDIR_MAXLEVEL_STR "1024" - -/* -** The testcase() macro is only used by the amalgamation. If undefined, -** make it a no-op. +** * Deferred tokens have not yet been considered. +** +** If *pRc is not SQLITE_OK when this function is called, it immediately +** returns 0. Otherwise, it tests whether or not after considering NEAR +** operators and deferred tokens the current row is still a match for the +** expression. It returns 1 if both of the following are true: +** +** 1. *pRc is SQLITE_OK when this function returns, and +** +** 2. After scanning the current FTS table row for the deferred tokens, +** it is determined that the row does *not* match the query. +** +** Or, if no error occurs and it seems the current row does match the FTS +** query, return 0. */ -#ifndef testcase -# define testcase(X) -#endif +SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){ + int rc = *pRc; + int bMiss = 0; + if( rc==SQLITE_OK ){ -/* -** Terminator values for position-lists and column-lists. -*/ -#define POS_COLUMN (1) /* Column-list terminator */ -#define POS_END (0) /* Position-list terminator */ + /* If there are one or more deferred tokens, load the current row into + ** memory and scan it to determine the position list for each deferred + ** token. Then, see if this row is really a match, considering deferred + ** tokens and NEAR operators (neither of which were taken into account + ** earlier, by fts3EvalNextRow()). + */ + if( pCsr->pDeferred ){ + rc = fts3CursorSeek(0, pCsr); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3CacheDeferredDoclists(pCsr); + } + } + bMiss = (0==fts3EvalTestExpr(pCsr, pCsr->pExpr, &rc)); -/* -** This section provides definitions to allow the -** FTS3 extension to be compiled outside of the -** amalgamation. -*/ -#ifndef SQLITE_AMALGAMATION -/* -** Macros indicating that conditional expressions are always true or -** false. -*/ -#ifdef SQLITE_COVERAGE_TEST -# define ALWAYS(x) (1) -# define NEVER(X) (0) -#elif defined(SQLITE_DEBUG) -# define ALWAYS(x) sqlite3Fts3Always((x)!=0) -# define NEVER(x) sqlite3Fts3Never((x)!=0) -SQLITE_PRIVATE int sqlite3Fts3Always(int b); -SQLITE_PRIVATE int sqlite3Fts3Never(int b); -#else -# define ALWAYS(x) (x) -# define NEVER(x) (x) -#endif + /* Free the position-lists accumulated for each deferred token above. */ + sqlite3Fts3FreeDeferredDoclists(pCsr); + *pRc = rc; + } + return (rc==SQLITE_OK && bMiss); +} /* -** Internal types used by SQLite. +** Advance to the next document that matches the FTS expression in +** Fts3Cursor.pExpr. */ -typedef unsigned char u8; /* 1-byte (or larger) unsigned integer */ -typedef short int i16; /* 2-byte (or larger) signed integer */ -typedef unsigned int u32; /* 4-byte unsigned integer */ -typedef sqlite3_uint64 u64; /* 8-byte unsigned integer */ -typedef sqlite3_int64 i64; /* 8-byte signed integer */ +static int fts3EvalNext(Fts3Cursor *pCsr){ + int rc = SQLITE_OK; /* Return Code */ + Fts3Expr *pExpr = pCsr->pExpr; + assert( pCsr->isEof==0 ); + if( pExpr==0 ){ + pCsr->isEof = 1; + }else{ + do { + if( pCsr->isRequireSeek==0 ){ + sqlite3_reset(pCsr->pStmt); + } + assert( sqlite3_data_count(pCsr->pStmt)==0 ); + fts3EvalNextRow(pCsr, pExpr, &rc); + pCsr->isEof = pExpr->bEof; + pCsr->isRequireSeek = 1; + pCsr->isMatchinfoNeeded = 1; + pCsr->iPrevId = pExpr->iDocid; + }while( pCsr->isEof==0 && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); + } -/* -** Macro used to suppress compiler warnings for unused parameters. -*/ -#define UNUSED_PARAMETER(x) (void)(x) + /* Check if the cursor is past the end of the docid range specified + ** by Fts3Cursor.iMinDocid/iMaxDocid. If so, set the EOF flag. */ + if( rc==SQLITE_OK && ( + (pCsr->bDesc==0 && pCsr->iPrevId>pCsr->iMaxDocid) + || (pCsr->bDesc!=0 && pCsr->iPrevIdiMinDocid) + )){ + pCsr->isEof = 1; + } -/* -** Activate assert() only if SQLITE_TEST is enabled. -*/ -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) -# define NDEBUG 1 -#endif + return rc; +} /* -** The TESTONLY macro is used to enclose variable declarations or -** other bits of code that are needed to support the arguments -** within testcase() and assert() macros. +** Restart interation for expression pExpr so that the next call to +** fts3EvalNext() visits the first row. Do not allow incremental +** loading or merging of phrase doclists for this iteration. +** +** If *pRc is other than SQLITE_OK when this function is called, it is +** a no-op. If an error occurs within this function, *pRc is set to an +** SQLite error code before returning. */ -#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) -# define TESTONLY(X) X -#else -# define TESTONLY(X) -#endif - -#endif /* SQLITE_AMALGAMATION */ - -#ifdef SQLITE_DEBUG -SQLITE_PRIVATE int sqlite3Fts3Corrupt(void); -# define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() -#else -# define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB -#endif +static void fts3EvalRestart( + Fts3Cursor *pCsr, + Fts3Expr *pExpr, + int *pRc +){ + if( pExpr && *pRc==SQLITE_OK ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; -typedef struct Fts3Table Fts3Table; -typedef struct Fts3Cursor Fts3Cursor; -typedef struct Fts3Expr Fts3Expr; -typedef struct Fts3Phrase Fts3Phrase; -typedef struct Fts3PhraseToken Fts3PhraseToken; + if( pPhrase ){ + fts3EvalInvalidatePoslist(pPhrase); + if( pPhrase->bIncr ){ + int i; + for(i=0; inToken; i++){ + Fts3PhraseToken *pToken = &pPhrase->aToken[i]; + assert( pToken->pDeferred==0 ); + if( pToken->pSegcsr ){ + sqlite3Fts3MsrIncrRestart(pToken->pSegcsr); + } + } + *pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase); + } + pPhrase->doclist.pNextDocid = 0; + pPhrase->doclist.iDocid = 0; + pPhrase->pOrPoslist = 0; + } -typedef struct Fts3Doclist Fts3Doclist; -typedef struct Fts3SegFilter Fts3SegFilter; -typedef struct Fts3DeferredToken Fts3DeferredToken; -typedef struct Fts3SegReader Fts3SegReader; -typedef struct Fts3MultiSegReader Fts3MultiSegReader; + pExpr->iDocid = 0; + pExpr->bEof = 0; + pExpr->bStart = 0; -typedef struct MatchinfoBuffer MatchinfoBuffer; + fts3EvalRestart(pCsr, pExpr->pLeft, pRc); + fts3EvalRestart(pCsr, pExpr->pRight, pRc); + } +} /* -** A connection to a fulltext index is an instance of the following -** structure. The xCreate and xConnect methods create an instance -** of this structure and xDestroy and xDisconnect free that instance. -** All other methods receive a pointer to the structure as one of their -** arguments. +** After allocating the Fts3Expr.aMI[] array for each phrase in the +** expression rooted at pExpr, the cursor iterates through all rows matched +** by pExpr, calling this function for each row. This function increments +** the values in Fts3Expr.aMI[] according to the position-list currently +** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase +** expression nodes. */ -struct Fts3Table { - sqlite3_vtab base; /* Base class used by SQLite core */ - sqlite3 *db; /* The database connection */ - const char *zDb; /* logical database name */ - const char *zName; /* virtual table name */ - int nColumn; /* number of named columns in virtual table */ - char **azColumn; /* column names. malloced */ - u8 *abNotindexed; /* True for 'notindexed' columns */ - sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ - char *zContentTbl; /* content=xxx option, or NULL */ - char *zLanguageid; /* languageid=xxx option, or NULL */ - int nAutoincrmerge; /* Value configured by 'automerge' */ - u32 nLeafAdd; /* Number of leaf blocks added this trans */ - - /* Precompiled statements used by the implementation. Each of these - ** statements is run and reset within a single virtual table API call. - */ - sqlite3_stmt *aStmt[40]; - sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */ - - char *zReadExprlist; - char *zWriteExprlist; - - int nNodeSize; /* Soft limit for node size */ - u8 bFts4; /* True for FTS4, false for FTS3 */ - u8 bHasStat; /* True if %_stat table exists (2==unknown) */ - u8 bHasDocsize; /* True if %_docsize table exists */ - u8 bDescIdx; /* True if doclists are in reverse order */ - u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */ - int nPgsz; /* Page size for host database */ - char *zSegmentsTbl; /* Name of %_segments table */ - sqlite3_blob *pSegments; /* Blob handle open on %_segments table */ +static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){ + if( pExpr ){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + if( pPhrase && pPhrase->doclist.pList ){ + int iCol = 0; + char *p = pPhrase->doclist.pList; - /* - ** The following array of hash tables is used to buffer pending index - ** updates during transactions. All pending updates buffered at any one - ** time must share a common language-id (see the FTS4 langid= feature). - ** The current language id is stored in variable iPrevLangid. - ** - ** A single FTS4 table may have multiple full-text indexes. For each index - ** there is an entry in the aIndex[] array. Index 0 is an index of all the - ** terms that appear in the document set. Each subsequent index in aIndex[] - ** is an index of prefixes of a specific length. - ** - ** Variable nPendingData contains an estimate the memory consumed by the - ** pending data structures, including hash table overhead, but not including - ** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash - ** tables are flushed to disk. Variable iPrevDocid is the docid of the most - ** recently inserted record. - */ - int nIndex; /* Size of aIndex[] */ - struct Fts3Index { - int nPrefix; /* Prefix length (0 for main terms index) */ - Fts3Hash hPending; /* Pending terms table for this index */ - } *aIndex; - int nMaxPendingData; /* Max pending data before flush to disk */ - int nPendingData; /* Current bytes of pending data */ - sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ - int iPrevLangid; /* Langid of recently inserted document */ - int bPrevDelete; /* True if last operation was a delete */ + do{ + u8 c = 0; + int iCnt = 0; + while( 0xFE & (*p | c) ){ + if( (c&0x80)==0 ) iCnt++; + c = *p++ & 0x80; + } -#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) - /* State variables used for validating that the transaction control - ** methods of the virtual table are called at appropriate times. These - ** values do not contribute to FTS functionality; they are used for - ** verifying the operation of the SQLite core. - */ - int inTransaction; /* True after xBegin but before xCommit/xRollback */ - int mxSavepoint; /* Largest valid xSavepoint integer */ -#endif + /* aMI[iCol*3 + 1] = Number of occurrences + ** aMI[iCol*3 + 2] = Number of rows containing at least one instance + */ + pExpr->aMI[iCol*3 + 1] += iCnt; + pExpr->aMI[iCol*3 + 2] += (iCnt>0); + if( *p==0x00 ) break; + p++; + p += fts3GetVarint32(p, &iCol); + }while( iColpLeft, nCol); + fts3EvalUpdateCounts(pExpr->pRight, nCol); + } +} /* -** When the core wants to read from the virtual table, it creates a -** virtual table cursor (an instance of the following structure) using -** the xOpen method. Cursors are destroyed using the xClose method. +** Expression pExpr must be of type FTSQUERY_PHRASE. +** +** If it is not already allocated and populated, this function allocates and +** populates the Fts3Expr.aMI[] array for expression pExpr. If pExpr is part +** of a NEAR expression, then it also allocates and populates the same array +** for all other phrases that are part of the NEAR expression. +** +** SQLITE_OK is returned if the aMI[] array is successfully allocated and +** populated. Otherwise, if an error occurs, an SQLite error code is returned. */ -struct Fts3Cursor { - sqlite3_vtab_cursor base; /* Base class used by SQLite core */ - i16 eSearch; /* Search strategy (see below) */ - u8 isEof; /* True if at End Of Results */ - u8 isRequireSeek; /* True if must seek pStmt to %_content row */ - u8 bSeekStmt; /* True if pStmt is a seek */ - sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */ - Fts3Expr *pExpr; /* Parsed MATCH query string */ - int iLangid; /* Language being queried for */ - int nPhrase; /* Number of matchable phrases in query */ - Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */ - sqlite3_int64 iPrevId; /* Previous id read from aDoclist */ - char *pNextId; /* Pointer into the body of aDoclist */ - char *aDoclist; /* List of docids for full-text queries */ - int nDoclist; /* Size of buffer at aDoclist */ - u8 bDesc; /* True to sort in descending order */ - int eEvalmode; /* An FTS3_EVAL_XX constant */ - int nRowAvg; /* Average size of database rows, in pages */ - sqlite3_int64 nDoc; /* Documents in table */ - i64 iMinDocid; /* Minimum docid to return */ - i64 iMaxDocid; /* Maximum docid to return */ - int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ - MatchinfoBuffer *pMIBuffer; /* Buffer for matchinfo data */ -}; +static int fts3EvalGatherStats( + Fts3Cursor *pCsr, /* Cursor object */ + Fts3Expr *pExpr /* FTSQUERY_PHRASE expression */ +){ + int rc = SQLITE_OK; /* Return code */ -#define FTS3_EVAL_FILTER 0 -#define FTS3_EVAL_NEXT 1 -#define FTS3_EVAL_MATCHINFO 2 + assert( pExpr->eType==FTSQUERY_PHRASE ); + if( pExpr->aMI==0 ){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + Fts3Expr *pRoot; /* Root of NEAR expression */ + Fts3Expr *p; /* Iterator used for several purposes */ -/* -** The Fts3Cursor.eSearch member is always set to one of the following. -** Actualy, Fts3Cursor.eSearch can be greater than or equal to -** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index -** of the column to be searched. For example, in -** -** CREATE VIRTUAL TABLE ex1 USING fts3(a,b,c,d); -** SELECT docid FROM ex1 WHERE b MATCH 'one two three'; -** -** Because the LHS of the MATCH operator is 2nd column "b", -** Fts3Cursor.eSearch will be set to FTS3_FULLTEXT_SEARCH+1. (+0 for a, -** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1" -** indicating that all columns should be searched, -** then eSearch would be set to FTS3_FULLTEXT_SEARCH+4. -*/ -#define FTS3_FULLSCAN_SEARCH 0 /* Linear scan of %_content table */ -#define FTS3_DOCID_SEARCH 1 /* Lookup by rowid on %_content table */ -#define FTS3_FULLTEXT_SEARCH 2 /* Full-text index search */ + sqlite3_int64 iPrevId = pCsr->iPrevId; + sqlite3_int64 iDocid; + u8 bEof; -/* -** The lower 16-bits of the sqlite3_index_info.idxNum value set by -** the xBestIndex() method contains the Fts3Cursor.eSearch value described -** above. The upper 16-bits contain a combination of the following -** bits, used to describe extra constraints on full-text searches. -*/ -#define FTS3_HAVE_LANGID 0x00010000 /* languageid=? */ -#define FTS3_HAVE_DOCID_GE 0x00020000 /* docid>=? */ -#define FTS3_HAVE_DOCID_LE 0x00040000 /* docid<=? */ + /* Find the root of the NEAR expression */ + pRoot = pExpr; + while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){ + pRoot = pRoot->pParent; + } + iDocid = pRoot->iDocid; + bEof = pRoot->bEof; + assert( pRoot->bStart ); -struct Fts3Doclist { - char *aAll; /* Array containing doclist (or NULL) */ - int nAll; /* Size of a[] in bytes */ - char *pNextDocid; /* Pointer to next docid */ + /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */ + for(p=pRoot; p; p=p->pLeft){ + Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight); + assert( pE->aMI==0 ); + pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32)); + if( !pE->aMI ) return SQLITE_NOMEM; + memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32)); + } - sqlite3_int64 iDocid; /* Current docid (if pList!=0) */ - int bFreeList; /* True if pList should be sqlite3_free()d */ - char *pList; /* Pointer to position list following iDocid */ - int nList; /* Length of position list */ -}; + fts3EvalRestart(pCsr, pRoot, &rc); -/* -** A "phrase" is a sequence of one or more tokens that must match in -** sequence. A single token is the base case and the most common case. -** For a sequence of tokens contained in double-quotes (i.e. "one two three") -** nToken will be the number of tokens in the string. -*/ -struct Fts3PhraseToken { - char *z; /* Text of the token */ - int n; /* Number of bytes in buffer z */ - int isPrefix; /* True if token ends with a "*" character */ - int bFirst; /* True if token must appear at position 0 */ + while( pCsr->isEof==0 && rc==SQLITE_OK ){ - /* Variables above this point are populated when the expression is - ** parsed (by code in fts3_expr.c). Below this point the variables are - ** used when evaluating the expression. */ - Fts3DeferredToken *pDeferred; /* Deferred token object for this token */ - Fts3MultiSegReader *pSegcsr; /* Segment-reader for this token */ -}; + do { + /* Ensure the %_content statement is reset. */ + if( pCsr->isRequireSeek==0 ) sqlite3_reset(pCsr->pStmt); + assert( sqlite3_data_count(pCsr->pStmt)==0 ); -struct Fts3Phrase { - /* Cache of doclist for this phrase. */ - Fts3Doclist doclist; - int bIncr; /* True if doclist is loaded incrementally */ - int iDoclistToken; + /* Advance to the next document */ + fts3EvalNextRow(pCsr, pRoot, &rc); + pCsr->isEof = pRoot->bEof; + pCsr->isRequireSeek = 1; + pCsr->isMatchinfoNeeded = 1; + pCsr->iPrevId = pRoot->iDocid; + }while( pCsr->isEof==0 + && pRoot->eType==FTSQUERY_NEAR + && sqlite3Fts3EvalTestDeferred(pCsr, &rc) + ); - /* Used by sqlite3Fts3EvalPhrasePoslist() if this is a descendent of an - ** OR condition. */ - char *pOrPoslist; - i64 iOrDocid; + if( rc==SQLITE_OK && pCsr->isEof==0 ){ + fts3EvalUpdateCounts(pRoot, pTab->nColumn); + } + } - /* Variables below this point are populated by fts3_expr.c when parsing - ** a MATCH expression. Everything above is part of the evaluation phase. - */ - int nToken; /* Number of tokens in the phrase */ - int iColumn; /* Index of column this phrase must match */ - Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */ -}; + pCsr->isEof = 0; + pCsr->iPrevId = iPrevId; + + if( bEof ){ + pRoot->bEof = bEof; + }else{ + /* Caution: pRoot may iterate through docids in ascending or descending + ** order. For this reason, even though it seems more defensive, the + ** do loop can not be written: + ** + ** do {...} while( pRoot->iDocidbEof==0 ); + if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB; + }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); + } + } + return rc; +} /* -** A tree of these objects forms the RHS of a MATCH operator. +** This function is used by the matchinfo() module to query a phrase +** expression node for the following information: ** -** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist -** points to a malloced buffer, size nDoclist bytes, containing the results -** of this phrase query in FTS3 doclist format. As usual, the initial -** "Length" field found in doclists stored on disk is omitted from this -** buffer. +** 1. The total number of occurrences of the phrase in each column of +** the FTS table (considering all rows), and ** -** Variable aMI is used only for FTSQUERY_NEAR nodes to store the global -** matchinfo data. If it is not NULL, it points to an array of size nCol*3, -** where nCol is the number of columns in the queried FTS table. The array -** is populated as follows: +** 2. For each column, the number of rows in the table for which the +** column contains at least one instance of the phrase. ** -** aMI[iCol*3 + 0] = Undefined -** aMI[iCol*3 + 1] = Number of occurrences -** aMI[iCol*3 + 2] = Number of rows containing at least one instance +** If no error occurs, SQLITE_OK is returned and the values for each column +** written into the array aiOut as follows: ** -** The aMI array is allocated using sqlite3_malloc(). It should be freed -** when the expression node is. +** aiOut[iCol*3 + 1] = Number of occurrences +** aiOut[iCol*3 + 2] = Number of rows containing at least one instance +** +** Caveats: +** +** * If a phrase consists entirely of deferred tokens, then all output +** values are set to the number of documents in the table. In other +** words we assume that very common tokens occur exactly once in each +** column of each row of the table. +** +** * If a phrase contains some deferred tokens (and some non-deferred +** tokens), count the potential occurrence identified by considering +** the non-deferred tokens instead of actual phrase occurrences. +** +** * If the phrase is part of a NEAR expression, then only phrase instances +** that meet the NEAR constraint are included in the counts. */ -struct Fts3Expr { - int eType; /* One of the FTSQUERY_XXX values defined below */ - int nNear; /* Valid if eType==FTSQUERY_NEAR */ - Fts3Expr *pParent; /* pParent->pLeft==this or pParent->pRight==this */ - Fts3Expr *pLeft; /* Left operand */ - Fts3Expr *pRight; /* Right operand */ - Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */ +SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats( + Fts3Cursor *pCsr, /* FTS cursor handle */ + Fts3Expr *pExpr, /* Phrase expression */ + u32 *aiOut /* Array to write results into (see above) */ +){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int iCol; - /* The following are used by the fts3_eval.c module. */ - sqlite3_int64 iDocid; /* Current docid */ - u8 bEof; /* True this expression is at EOF already */ - u8 bStart; /* True if iDocid is valid */ - u8 bDeferred; /* True if this expression is entirely deferred */ + if( pExpr->bDeferred && pExpr->pParent->eType!=FTSQUERY_NEAR ){ + assert( pCsr->nDoc>0 ); + for(iCol=0; iColnColumn; iCol++){ + aiOut[iCol*3 + 1] = (u32)pCsr->nDoc; + aiOut[iCol*3 + 2] = (u32)pCsr->nDoc; + } + }else{ + rc = fts3EvalGatherStats(pCsr, pExpr); + if( rc==SQLITE_OK ){ + assert( pExpr->aMI ); + for(iCol=0; iColnColumn; iCol++){ + aiOut[iCol*3 + 1] = pExpr->aMI[iCol*3 + 1]; + aiOut[iCol*3 + 2] = pExpr->aMI[iCol*3 + 2]; + } + } + } - /* The following are used by the fts3_snippet.c module. */ - int iPhrase; /* Index of this phrase in matchinfo() results */ - u32 *aMI; /* See above */ -}; + return rc; +} /* -** Candidate values for Fts3Query.eType. Note that the order of the first -** four values is in order of precedence when parsing expressions. For -** example, the following: +** The expression pExpr passed as the second argument to this function +** must be of type FTSQUERY_PHRASE. ** -** "a OR b AND c NOT d NEAR e" +** The returned value is either NULL or a pointer to a buffer containing +** a position-list indicating the occurrences of the phrase in column iCol +** of the current row. ** -** is equivalent to: +** More specifically, the returned buffer contains 1 varint for each +** occurrence of the phrase in the column, stored using the normal (delta+2) +** compression and is terminated by either an 0x01 or 0x00 byte. For example, +** if the requested column contains "a b X c d X X" and the position-list +** for 'X' is requested, the buffer returned may contain: ** -** "a OR (b AND (c NOT (d NEAR e)))" +** 0x04 0x05 0x03 0x01 or 0x04 0x05 0x03 0x00 +** +** This function works regardless of whether or not the phrase is deferred, +** incremental, or neither. */ -#define FTSQUERY_NEAR 1 -#define FTSQUERY_NOT 2 -#define FTSQUERY_AND 3 -#define FTSQUERY_OR 4 -#define FTSQUERY_PHRASE 5 - - -/* fts3_write.c */ -SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); -SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *); -SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *); -SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *); -SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64, - sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**); -SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( - Fts3Table*,int,const char*,int,int,Fts3SegReader**); -SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *); -SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, int, sqlite3_stmt **); -SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*); - -SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **); -SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **); - -#ifndef SQLITE_DISABLE_FTS4_DEFERRED -SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *); -SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int); -SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *); -SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *); -SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *); -#else -# define sqlite3Fts3FreeDeferredTokens(x) -# define sqlite3Fts3DeferToken(x,y,z) SQLITE_OK -# define sqlite3Fts3CacheDeferredDoclists(x) SQLITE_OK -# define sqlite3Fts3FreeDeferredDoclists(x) -# define sqlite3Fts3DeferredTokenList(x,y,z) SQLITE_OK -#endif - -SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *); -SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *, int *); - -/* Special values interpreted by sqlite3SegReaderCursor() */ -#define FTS3_SEGCURSOR_PENDING -1 -#define FTS3_SEGCURSOR_ALL -2 - -SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Fts3SegFilter*); -SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *); -SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *); - -SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *, - int, int, int, const char *, int, int, int, Fts3MultiSegReader *); - -/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */ -#define FTS3_SEGMENT_REQUIRE_POS 0x00000001 -#define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002 -#define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 -#define FTS3_SEGMENT_PREFIX 0x00000008 -#define FTS3_SEGMENT_SCAN 0x00000010 -#define FTS3_SEGMENT_FIRST 0x00000020 - -/* Type passed as 4th argument to SegmentReaderIterate() */ -struct Fts3SegFilter { - const char *zTerm; - int nTerm; - int iCol; - int flags; -}; - -struct Fts3MultiSegReader { - /* Used internally by sqlite3Fts3SegReaderXXX() calls */ - Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */ - int nSegment; /* Size of apSegment array */ - int nAdvance; /* How many seg-readers to advance */ - Fts3SegFilter *pFilter; /* Pointer to filter object */ - char *aBuffer; /* Buffer to merge doclists in */ - int nBuffer; /* Allocated size of aBuffer[] in bytes */ - - int iColFilter; /* If >=0, filter for this column */ - int bRestart; - - /* Used by fts3.c only. */ - int nCost; /* Cost of running iterator */ - int bLookup; /* True if a lookup of a single entry. */ - - /* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */ - char *zTerm; /* Pointer to term buffer */ - int nTerm; /* Size of zTerm in bytes */ - char *aDoclist; /* Pointer to doclist buffer */ - int nDoclist; /* Size of aDoclist[] in bytes */ -}; - -SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int); - -#define fts3GetVarint32(p, piVal) ( \ - (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ -) - -/* fts3.c */ -SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...); -SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64); -SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); -SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); -SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); -SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); -SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); -SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); -SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); -SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*); -SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc); - -/* fts3_tokenizer.c */ -SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *); -SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); -SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, - sqlite3_tokenizer **, char ** -); -SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char); - -/* fts3_snippet.c */ -SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*); -SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *, - const char *, const char *, int, int -); -SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); -SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p); - -/* fts3_expr.c */ -SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int, - char **, int, int, int, const char *, int, Fts3Expr **, char ** -); -SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); -#ifdef SQLITE_TEST -SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); -SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); -#endif - -SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, - sqlite3_tokenizer_cursor ** -); - -/* fts3_aux.c */ -SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); - -SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); - -SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( - Fts3Table*, Fts3MultiSegReader*, int, const char*, int); -SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( - Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); -SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); -SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); -SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); - -/* fts3_tokenize_vtab.c */ -SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); - -/* fts3_unicode2.c (functions generated by parsing unicode text files) */ -#ifndef SQLITE_DISABLE_FTS3_UNICODE -SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int); -SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int); -SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int); -#endif - -#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ -#endif /* _FTSINT_H */ - -/************** End of fts3Int.h *********************************************/ -/************** Continuing where we left off in fts3.c ***********************/ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -#if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE) -# define SQLITE_CORE 1 -#endif - -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ -/* #include */ +SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist( + Fts3Cursor *pCsr, /* FTS3 cursor object */ + Fts3Expr *pExpr, /* Phrase to return doclist for */ + int iCol, /* Column to return position list for */ + char **ppOut /* OUT: Pointer to position list */ +){ + Fts3Phrase *pPhrase = pExpr->pPhrase; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + char *pIter; + int iThis; + sqlite3_int64 iDocid; -/* #include "fts3.h" */ -#ifndef SQLITE_CORE -/* # include "sqlite3ext.h" */ - SQLITE_EXTENSION_INIT1 -#endif + /* If this phrase is applies specifically to some column other than + ** column iCol, return a NULL pointer. */ + *ppOut = 0; + assert( iCol>=0 && iColnColumn ); + if( (pPhrase->iColumnnColumn && pPhrase->iColumn!=iCol) ){ + return SQLITE_OK; + } -static int fts3EvalNext(Fts3Cursor *pCsr); -static int fts3EvalStart(Fts3Cursor *pCsr); -static int fts3TermSegReaderCursor( - Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); + iDocid = pExpr->iDocid; + pIter = pPhrase->doclist.pList; + if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ + int rc = SQLITE_OK; + int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ + int bOr = 0; + u8 bTreeEof = 0; + Fts3Expr *p; /* Used to iterate from pExpr to root */ + Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */ + int bMatch; -#ifndef SQLITE_AMALGAMATION -# if defined(SQLITE_DEBUG) -SQLITE_PRIVATE int sqlite3Fts3Always(int b) { assert( b ); return b; } -SQLITE_PRIVATE int sqlite3Fts3Never(int b) { assert( !b ); return b; } -# endif -#endif + /* Check if this phrase descends from an OR expression node. If not, + ** return NULL. Otherwise, the entry that corresponds to docid + ** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the + ** tree that the node is part of has been marked as EOF, but the node + ** itself is not EOF, then it may point to an earlier entry. */ + pNear = pExpr; + for(p=pExpr->pParent; p; p=p->pParent){ + if( p->eType==FTSQUERY_OR ) bOr = 1; + if( p->eType==FTSQUERY_NEAR ) pNear = p; + if( p->bEof ) bTreeEof = 1; + } + if( bOr==0 ) return SQLITE_OK; -/* -** Write a 64-bit variable-length integer to memory starting at p[0]. -** The length of data written will be between 1 and FTS3_VARINT_MAX bytes. -** The number of bytes written is returned. -*/ -SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){ - unsigned char *q = (unsigned char *) p; - sqlite_uint64 vu = v; - do{ - *q++ = (unsigned char) ((vu & 0x7f) | 0x80); - vu >>= 7; - }while( vu!=0 ); - q[-1] &= 0x7f; /* turn off high bit in final byte */ - assert( q - (unsigned char *)p <= FTS3_VARINT_MAX ); - return (int) (q - (unsigned char *)p); -} + /* This is the descendent of an OR node. In this case we cannot use + ** an incremental phrase. Load the entire doclist for the phrase + ** into memory in this case. */ + if( pPhrase->bIncr ){ + int bEofSave = pNear->bEof; + fts3EvalRestart(pCsr, pNear, &rc); + while( rc==SQLITE_OK && !pNear->bEof ){ + fts3EvalNextRow(pCsr, pNear, &rc); + if( bEofSave==0 && pNear->iDocid==iDocid ) break; + } + assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); + if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){ + rc = FTS_CORRUPT_VTAB; + } + } + if( bTreeEof ){ + while( rc==SQLITE_OK && !pNear->bEof ){ + fts3EvalNextRow(pCsr, pNear, &rc); + } + } + if( rc!=SQLITE_OK ) return rc; -#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \ - v = (v & mask1) | ( (*ptr++) << shift ); \ - if( (v & mask2)==0 ){ var = v; return ret; } -#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \ - v = (*ptr++); \ - if( (v & mask2)==0 ){ var = v; return ret; } + bMatch = 1; + for(p=pNear; p; p=p->pLeft){ + u8 bEof = 0; + Fts3Expr *pTest = p; + Fts3Phrase *pPh; + assert( pTest->eType==FTSQUERY_NEAR || pTest->eType==FTSQUERY_PHRASE ); + if( pTest->eType==FTSQUERY_NEAR ) pTest = pTest->pRight; + assert( pTest->eType==FTSQUERY_PHRASE ); + pPh = pTest->pPhrase; -/* -** Read a 64-bit variable-length integer from memory starting at p[0]. -** Return the number of bytes read, or 0 on error. -** The value is stored in *v. -*/ -SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){ - const char *pStart = p; - u32 a; - u64 b; - int shift; + pIter = pPh->pOrPoslist; + iDocid = pPh->iOrDocid; + if( pCsr->bDesc==bDescDoclist ){ + bEof = !pPh->doclist.nAll || + (pIter >= (pPh->doclist.aAll + pPh->doclist.nAll)); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ + sqlite3Fts3DoclistNext( + bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, + &pIter, &iDocid, &bEof + ); + } + }else{ + bEof = !pPh->doclist.nAll || (pIter && pIter<=pPh->doclist.aAll); + while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ + int dummy; + sqlite3Fts3DoclistPrev( + bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, + &pIter, &iDocid, &dummy, &bEof + ); + } + } + pPh->pOrPoslist = pIter; + pPh->iOrDocid = iDocid; + if( bEof || iDocid!=pCsr->iPrevId ) bMatch = 0; + } - GETVARINT_INIT(a, p, 0, 0x00, 0x80, *v, 1); - GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *v, 2); - GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *v, 3); - GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4); - b = (a & 0x0FFFFFFF ); + if( bMatch ){ + pIter = pPhrase->pOrPoslist; + }else{ + pIter = 0; + } + } + if( pIter==0 ) return SQLITE_OK; - for(shift=28; shift<=63; shift+=7){ - u64 c = *p++; - b += (c&0x7F) << shift; - if( (c & 0x80)==0 ) break; + if( *pIter==0x01 ){ + pIter++; + pIter += fts3GetVarint32(pIter, &iThis); + }else{ + iThis = 0; } - *v = b; - return (int)(p - pStart); + while( iThisdoclist, and +** * any Fts3MultiSegReader objects held by phrase tokens. */ -SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){ - u32 a; +SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){ + if( pPhrase ){ + int i; + sqlite3_free(pPhrase->doclist.aAll); + fts3EvalInvalidatePoslist(pPhrase); + memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist)); + for(i=0; inToken; i++){ + fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr); + pPhrase->aToken[i].pSegcsr = 0; + } + } +} -#ifndef fts3GetVarint32 - GETVARINT_INIT(a, p, 0, 0x00, 0x80, *pi, 1); -#else - a = (*p++); - assert( a & 0x80 ); -#endif - GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *pi, 2); - GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *pi, 3); - GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4); - a = (a & 0x0FFFFFFF ); - *pi = (int)(a | ((u32)(*p & 0x0F) << 28)); - return 5; +/* +** Return SQLITE_CORRUPT_VTAB. +*/ +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ + return SQLITE_CORRUPT_VTAB; } +#endif +#if !SQLITE_CORE /* -** Return the number of bytes required to encode v as a varint +** Initialize API pointer table, if required. */ -SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64 v){ - int i = 0; - do{ - i++; - v >>= 7; - }while( v!=0 ); - return i; +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_fts3_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi) + return sqlite3Fts3Init(db); } +#endif +#endif + +/************** End of fts3.c ************************************************/ +/************** Begin file fts3_aux.c ****************************************/ /* -** Convert an SQL-style quoted string into a normal string by removing -** the quote characters. The conversion is done in-place. If the -** input does not begin with a quote character, then this routine -** is a no-op. +** 2011 Jan 27 ** -** Examples: +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** "abc" becomes abc -** 'xyz' becomes xyz -** [pqr] becomes pqr -** `mno` becomes mno +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** ** */ -SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){ - char quote; /* Quote character (if any ) */ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - quote = z[0]; - if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ - int iIn = 1; /* Index of next byte to read from input */ - int iOut = 0; /* Index of next byte to write to output */ +/* #include */ +/* #include */ - /* If the first byte was a '[', then the close-quote character is a ']' */ - if( quote=='[' ) quote = ']'; +typedef struct Fts3auxTable Fts3auxTable; +typedef struct Fts3auxCursor Fts3auxCursor; - while( z[iIn] ){ - if( z[iIn]==quote ){ - if( z[iIn+1]!=quote ) break; - z[iOut++] = quote; - iIn += 2; - }else{ - z[iOut++] = z[iIn++]; - } - } - z[iOut] = '\0'; - } -} +struct Fts3auxTable { + sqlite3_vtab base; /* Base class used by SQLite core */ + Fts3Table *pFts3Tab; +}; + +struct Fts3auxCursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + Fts3MultiSegReader csr; /* Must be right after "base" */ + Fts3SegFilter filter; + char *zStop; + int nStop; /* Byte-length of string zStop */ + int iLangid; /* Language id to query */ + int isEof; /* True if cursor is at EOF */ + sqlite3_int64 iRowid; /* Current rowid */ + + int iCol; /* Current value of 'col' column */ + int nStat; /* Size of aStat[] array */ + struct Fts3auxColstats { + sqlite3_int64 nDoc; /* 'documents' values for current csr row */ + sqlite3_int64 nOcc; /* 'occurrences' values for current csr row */ + } *aStat; +}; /* -** Read a single varint from the doclist at *pp and advance *pp to point -** to the first byte past the end of the varint. Add the value of the varint -** to *pVal. +** Schema of the terms table. */ -static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ - sqlite3_int64 iVal; - *pp += sqlite3Fts3GetVarint(*pp, &iVal); - *pVal += iVal; -} +#define FTS3_AUX_SCHEMA \ + "CREATE TABLE x(term, col, documents, occurrences, languageid HIDDEN)" /* -** When this function is called, *pp points to the first byte following a -** varint that is part of a doclist (or position-list, or any other list -** of varints). This function moves *pp to point to the start of that varint, -** and sets *pVal by the varint value. -** -** Argument pStart points to the first byte of the doclist that the -** varint is part of. +** This function does all the work for both the xConnect and xCreate methods. +** These tables have no persistent representation of their own, so xConnect +** and xCreate are identical operations. */ -static void fts3GetReverseVarint( - char **pp, - char *pStart, - sqlite3_int64 *pVal +static int fts3auxConnectMethod( + sqlite3 *db, /* Database connection */ + void *pUnused, /* Unused */ + int argc, /* Number of elements in argv array */ + const char * const *argv, /* xCreate/xConnect argument array */ + sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ + char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ - sqlite3_int64 iVal; - char *p; + char const *zDb; /* Name of database (e.g. "main") */ + char const *zFts3; /* Name of fts3 table */ + int nDb; /* Result of strlen(zDb) */ + int nFts3; /* Result of strlen(zFts3) */ + sqlite3_int64 nByte; /* Bytes of space to allocate here */ + int rc; /* value returned by declare_vtab() */ + Fts3auxTable *p; /* Virtual table object to return */ - /* Pointer p now points at the first byte past the varint we are - ** interested in. So, unless the doclist is corrupt, the 0x80 bit is - ** clear on character p[-1]. */ - for(p = (*pp)-2; p>=pStart && *p&0x80; p--); - p++; - *pp = p; + UNUSED_PARAMETER(pUnused); - sqlite3Fts3GetVarint(p, &iVal); - *pVal = iVal; + /* The user should invoke this in one of two forms: + ** + ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table); + ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table); + */ + if( argc!=4 && argc!=5 ) goto bad_args; + + zDb = argv[1]; + nDb = (int)strlen(zDb); + if( argc==5 ){ + if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){ + zDb = argv[3]; + nDb = (int)strlen(zDb); + zFts3 = argv[4]; + }else{ + goto bad_args; + } + }else{ + zFts3 = argv[3]; + } + nFts3 = (int)strlen(zFts3); + + rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA); + if( rc!=SQLITE_OK ) return rc; + + nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; + p = (Fts3auxTable *)sqlite3_malloc64(nByte); + if( !p ) return SQLITE_NOMEM; + memset(p, 0, nByte); + + p->pFts3Tab = (Fts3Table *)&p[1]; + p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; + p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; + p->pFts3Tab->db = db; + p->pFts3Tab->nIndex = 1; + + memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); + memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); + sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); + + *ppVtab = (sqlite3_vtab *)p; + return SQLITE_OK; + + bad_args: + sqlite3Fts3ErrMsg(pzErr, "invalid arguments to fts4aux constructor"); + return SQLITE_ERROR; } /* -** The xDisconnect() virtual table method. +** This function does the work for both the xDisconnect and xDestroy methods. +** These tables have no persistent representation of their own, so xDisconnect +** and xDestroy are identical operations. */ -static int fts3DisconnectMethod(sqlite3_vtab *pVtab){ - Fts3Table *p = (Fts3Table *)pVtab; +static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){ + Fts3auxTable *p = (Fts3auxTable *)pVtab; + Fts3Table *pFts3 = p->pFts3Tab; int i; - assert( p->nPendingData==0 ); - assert( p->pSegments==0 ); - /* Free any prepared statements held */ - sqlite3_finalize(p->pSeekStmt); - for(i=0; iaStmt); i++){ - sqlite3_finalize(p->aStmt[i]); + for(i=0; iaStmt); i++){ + sqlite3_finalize(pFts3->aStmt[i]); } - sqlite3_free(p->zSegmentsTbl); - sqlite3_free(p->zReadExprlist); - sqlite3_free(p->zWriteExprlist); - sqlite3_free(p->zContentTbl); - sqlite3_free(p->zLanguageid); - - /* Invoke the tokenizer destructor to free the tokenizer. */ - p->pTokenizer->pModule->xDestroy(p->pTokenizer); - + sqlite3_free(pFts3->zSegmentsTbl); sqlite3_free(p); return SQLITE_OK; } -/* -** Write an error message into *pzErr -*/ -SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char **pzErr, const char *zFormat, ...){ - va_list ap; - sqlite3_free(*pzErr); - va_start(ap, zFormat); - *pzErr = sqlite3_vmprintf(zFormat, ap); - va_end(ap); -} +#define FTS4AUX_EQ_CONSTRAINT 1 +#define FTS4AUX_GE_CONSTRAINT 2 +#define FTS4AUX_LE_CONSTRAINT 4 /* -** Construct one or more SQL statements from the format string given -** and then evaluate those statements. The success code is written -** into *pRc. -** -** If *pRc is initially non-zero then this routine is a no-op. +** xBestIndex - Analyze a WHERE and ORDER BY clause. */ -static void fts3DbExec( - int *pRc, /* Success code */ - sqlite3 *db, /* Database in which to run SQL */ - const char *zFormat, /* Format string for SQL */ - ... /* Arguments to the format string */ +static int fts3auxBestIndexMethod( + sqlite3_vtab *pVTab, + sqlite3_index_info *pInfo ){ - va_list ap; - char *zSql; - if( *pRc ) return; - va_start(ap, zFormat); - zSql = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - if( zSql==0 ){ - *pRc = SQLITE_NOMEM; + int i; + int iEq = -1; + int iGe = -1; + int iLe = -1; + int iLangid = -1; + int iNext = 1; /* Next free argvIndex value */ + + UNUSED_PARAMETER(pVTab); + + /* This vtab delivers always results in "ORDER BY term ASC" order. */ + if( pInfo->nOrderBy==1 + && pInfo->aOrderBy[0].iColumn==0 + && pInfo->aOrderBy[0].desc==0 + ){ + pInfo->orderByConsumed = 1; + } + + /* Search for equality and range constraints on the "term" column. + ** And equality constraints on the hidden "languageid" column. */ + for(i=0; inConstraint; i++){ + if( pInfo->aConstraint[i].usable ){ + int op = pInfo->aConstraint[i].op; + int iCol = pInfo->aConstraint[i].iColumn; + + if( iCol==0 ){ + if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i; + if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i; + if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i; + if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i; + if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i; + } + if( iCol==4 ){ + if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iLangid = i; + } + } + } + + if( iEq>=0 ){ + pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT; + pInfo->aConstraintUsage[iEq].argvIndex = iNext++; + pInfo->estimatedCost = 5; }else{ - *pRc = sqlite3_exec(db, zSql, 0, 0, 0); - sqlite3_free(zSql); + pInfo->idxNum = 0; + pInfo->estimatedCost = 20000; + if( iGe>=0 ){ + pInfo->idxNum += FTS4AUX_GE_CONSTRAINT; + pInfo->aConstraintUsage[iGe].argvIndex = iNext++; + pInfo->estimatedCost /= 2; + } + if( iLe>=0 ){ + pInfo->idxNum += FTS4AUX_LE_CONSTRAINT; + pInfo->aConstraintUsage[iLe].argvIndex = iNext++; + pInfo->estimatedCost /= 2; + } + } + if( iLangid>=0 ){ + pInfo->aConstraintUsage[iLangid].argvIndex = iNext++; + pInfo->estimatedCost--; } + + return SQLITE_OK; } /* -** The xDestroy() virtual table method. +** xOpen - Open a cursor. */ -static int fts3DestroyMethod(sqlite3_vtab *pVtab){ - Fts3Table *p = (Fts3Table *)pVtab; - int rc = SQLITE_OK; /* Return code */ - const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ - sqlite3 *db = p->db; /* Database handle */ +static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts3auxCursor *pCsr; /* Pointer to cursor object to return */ - /* Drop the shadow tables */ - if( p->zContentTbl==0 ){ - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName); - } - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName); - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName); + UNUSED_PARAMETER(pVTab); - /* If everything has worked, invoke fts3DisconnectMethod() to free the - ** memory associated with the Fts3Table structure and return SQLITE_OK. - ** Otherwise, return an SQLite error code. - */ - return (rc==SQLITE_OK ? fts3DisconnectMethod(pVtab) : rc); + pCsr = (Fts3auxCursor *)sqlite3_malloc(sizeof(Fts3auxCursor)); + if( !pCsr ) return SQLITE_NOMEM; + memset(pCsr, 0, sizeof(Fts3auxCursor)); + + *ppCsr = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** xClose - Close a cursor. +*/ +static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + + sqlite3Fts3SegmentsClose(pFts3); + sqlite3Fts3SegReaderFinish(&pCsr->csr); + sqlite3_free((void *)pCsr->filter.zTerm); + sqlite3_free(pCsr->zStop); + sqlite3_free(pCsr->aStat); + sqlite3_free(pCsr); + return SQLITE_OK; } +static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){ + if( nSize>pCsr->nStat ){ + struct Fts3auxColstats *aNew; + aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat, + sizeof(struct Fts3auxColstats) * nSize + ); + if( aNew==0 ) return SQLITE_NOMEM; + memset(&aNew[pCsr->nStat], 0, + sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat) + ); + pCsr->aStat = aNew; + pCsr->nStat = nSize; + } + return SQLITE_OK; +} /* -** Invoke sqlite3_declare_vtab() to declare the schema for the FTS3 table -** passed as the first argument. This is done as part of the xConnect() -** and xCreate() methods. -** -** If *pRc is non-zero when this function is called, it is a no-op. -** Otherwise, if an error occurs, an SQLite error code is stored in *pRc -** before returning. +** xNext - Advance the cursor to the next row, if any. */ -static void fts3DeclareVtab(int *pRc, Fts3Table *p){ - if( *pRc==SQLITE_OK ){ - int i; /* Iterator variable */ - int rc; /* Return code */ - char *zSql; /* SQL statement passed to declare_vtab() */ - char *zCols; /* List of user defined columns */ - const char *zLanguageid; +static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; + int rc; - zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid"); - sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + /* Increment our pretend rowid value. */ + pCsr->iRowid++; - /* Create a list of user columns for the virtual table */ - zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); - for(i=1; zCols && inColumn; i++){ - zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]); + for(pCsr->iCol++; pCsr->iColnStat; pCsr->iCol++){ + if( pCsr->aStat[pCsr->iCol].nDoc>0 ) return SQLITE_OK; + } + + rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr); + if( rc==SQLITE_ROW ){ + int i = 0; + int nDoclist = pCsr->csr.nDoclist; + char *aDoclist = pCsr->csr.aDoclist; + int iCol; + + int eState = 0; + + if( pCsr->zStop ){ + int n = (pCsr->nStopcsr.nTerm) ? pCsr->nStop : pCsr->csr.nTerm; + int mc = memcmp(pCsr->zStop, pCsr->csr.zTerm, n); + if( mc<0 || (mc==0 && pCsr->csr.nTerm>pCsr->nStop) ){ + pCsr->isEof = 1; + return SQLITE_OK; + } } - /* Create the whole "CREATE TABLE" statement to pass to SQLite */ - zSql = sqlite3_mprintf( - "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)", - zCols, p->zName, zLanguageid - ); - if( !zCols || !zSql ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_declare_vtab(p->db, zSql); + if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; + memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); + iCol = 0; + rc = SQLITE_OK; + + while( iaStat[0].nDoc++; + eState = 1; + iCol = 0; + break; + + /* State 1. In this state we are expecting either a 1, indicating + ** that the following integer will be a column number, or the + ** start of a position list for column 0. + ** + ** The only difference between state 1 and state 2 is that if the + ** integer encountered in state 1 is not 0 or 1, then we need to + ** increment the column 0 "nDoc" count for this term. + */ + case 1: + assert( iCol==0 ); + if( v>1 ){ + pCsr->aStat[1].nDoc++; + } + eState = 2; + /* fall through */ + + case 2: + if( v==0 ){ /* 0x00. Next integer will be a docid. */ + eState = 0; + }else if( v==1 ){ /* 0x01. Next integer will be a column number. */ + eState = 3; + }else{ /* 2 or greater. A position. */ + pCsr->aStat[iCol+1].nOcc++; + pCsr->aStat[0].nOcc++; + } + break; + + /* State 3. The integer just read is a column number. */ + default: assert( eState==3 ); + iCol = (int)v; + if( iCol<1 ){ + rc = SQLITE_CORRUPT_VTAB; + break; + } + if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; + pCsr->aStat[iCol+1].nDoc++; + eState = 2; + break; + } } - sqlite3_free(zSql); - sqlite3_free(zCols); - *pRc = rc; + pCsr->iCol = 0; + }else{ + pCsr->isEof = 1; } + return rc; } /* -** Create the %_stat table if it does not already exist. +** xFilter - Initialize a cursor to point at the start of its data. */ -SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){ - fts3DbExec(pRc, p->db, - "CREATE TABLE IF NOT EXISTS %Q.'%q_stat'" - "(id INTEGER PRIMARY KEY, value BLOB);", - p->zDb, p->zName - ); - if( (*pRc)==SQLITE_OK ) p->bHasStat = 1; -} +static int fts3auxFilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *idxStr, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ +){ + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; + int rc; + int isScan = 0; + int iLangVal = 0; /* Language id to query */ -/* -** Create the backing store tables (%_content, %_segments and %_segdir) -** required by the FTS3 table passed as the only argument. This is done -** as part of the vtab xCreate() method. -** -** If the p->bHasDocsize boolean is true (indicating that this is an -** FTS4 table, not an FTS3 table) then also create the %_docsize and -** %_stat tables required by FTS4. -*/ -static int fts3CreateTables(Fts3Table *p){ - int rc = SQLITE_OK; /* Return code */ - int i; /* Iterator variable */ - sqlite3 *db = p->db; /* The database connection */ + int iEq = -1; /* Index of term=? value in apVal */ + int iGe = -1; /* Index of term>=? value in apVal */ + int iLe = -1; /* Index of term<=? value in apVal */ + int iLangid = -1; /* Index of languageid=? value in apVal */ + int iNext = 0; - if( p->zContentTbl==0 ){ - const char *zLanguageid = p->zLanguageid; - char *zContentCols; /* Columns of %_content table */ + UNUSED_PARAMETER(nVal); + UNUSED_PARAMETER(idxStr); - /* Create a list of user columns for the content table */ - zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); - for(i=0; zContentCols && inColumn; i++){ - char *z = p->azColumn[i]; - zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); + assert( idxStr==0 ); + assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0 + || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT + || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) + ); + + if( idxNum==FTS4AUX_EQ_CONSTRAINT ){ + iEq = iNext++; + }else{ + isScan = 1; + if( idxNum & FTS4AUX_GE_CONSTRAINT ){ + iGe = iNext++; } - if( zLanguageid && zContentCols ){ - zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid); + if( idxNum & FTS4AUX_LE_CONSTRAINT ){ + iLe = iNext++; } - if( zContentCols==0 ) rc = SQLITE_NOMEM; - - /* Create the content table */ - fts3DbExec(&rc, db, - "CREATE TABLE %Q.'%q_content'(%s)", - p->zDb, p->zName, zContentCols - ); - sqlite3_free(zContentCols); + } + if( iNextzDb, p->zName - ); - fts3DbExec(&rc, db, - "CREATE TABLE %Q.'%q_segdir'(" - "level INTEGER," - "idx INTEGER," - "start_block INTEGER," - "leaves_end_block INTEGER," - "end_block INTEGER," - "root BLOB," - "PRIMARY KEY(level, idx)" - ");", - p->zDb, p->zName - ); - if( p->bHasDocsize ){ - fts3DbExec(&rc, db, - "CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);", - p->zDb, p->zName - ); + /* In case this cursor is being reused, close and zero it. */ + testcase(pCsr->filter.zTerm); + sqlite3Fts3SegReaderFinish(&pCsr->csr); + sqlite3_free((void *)pCsr->filter.zTerm); + sqlite3_free(pCsr->aStat); + sqlite3_free(pCsr->zStop); + memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); + + pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; + if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; + + if( iEq>=0 || iGe>=0 ){ + const unsigned char *zStr = sqlite3_value_text(apVal[0]); + assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); + if( zStr ){ + pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); + if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; + pCsr->filter.nTerm = (int)strlen(pCsr->filter.zTerm); + } } - assert( p->bHasStat==p->bFts4 ); - if( p->bHasStat ){ - sqlite3Fts3CreateStatTable(&rc, p); + + if( iLe>=0 ){ + pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); + if( pCsr->zStop==0 ) return SQLITE_NOMEM; + pCsr->nStop = (int)strlen(pCsr->zStop); + } + + if( iLangid>=0 ){ + iLangVal = sqlite3_value_int(apVal[iLangid]); + + /* If the user specified a negative value for the languageid, use zero + ** instead. This works, as the "languageid=?" constraint will also + ** be tested by the VDBE layer. The test will always be false (since + ** this module will not return a row with a negative languageid), and + ** so the overall query will return zero rows. */ + if( iLangVal<0 ) iLangVal = 0; + } + pCsr->iLangid = iLangVal; + + rc = sqlite3Fts3SegReaderCursor(pFts3, iLangVal, 0, FTS3_SEGCURSOR_ALL, + pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr + ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); } + + if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor); return rc; } /* -** Store the current database page-size in bytes in p->nPgsz. -** -** If *pRc is non-zero when this function is called, it is a no-op. -** Otherwise, if an error occurs, an SQLite error code is stored in *pRc -** before returning. +** xEof - Return true if the cursor is at EOF, or false otherwise. */ -static void fts3DatabasePageSize(int *pRc, Fts3Table *p){ - if( *pRc==SQLITE_OK ){ - int rc; /* Return code */ - char *zSql; /* SQL text "PRAGMA %Q.page_size" */ - sqlite3_stmt *pStmt; /* Compiled "PRAGMA %Q.page_size" statement */ - - zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb); - if( !zSql ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_step(pStmt); - p->nPgsz = sqlite3_column_int(pStmt, 0); - rc = sqlite3_finalize(pStmt); - }else if( rc==SQLITE_AUTH ){ - p->nPgsz = 1024; - rc = SQLITE_OK; - } - } - assert( p->nPgsz>0 || rc!=SQLITE_OK ); - sqlite3_free(zSql); - *pRc = rc; - } +static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + return pCsr->isEof; } /* -** "Special" FTS4 arguments are column specifications of the following form: -** -** = -** -** There may not be whitespace surrounding the "=" character. The -** term may be quoted, but the may not. +** xColumn - Return a column value. */ -static int fts3IsSpecialColumn( - const char *z, - int *pnKey, - char **pzValue +static int fts3auxColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ ){ - char *zValue; - const char *zCsr = z; + Fts3auxCursor *p = (Fts3auxCursor *)pCursor; - while( *zCsr!='=' ){ - if( *zCsr=='\0' ) return 0; - zCsr++; - } + assert( p->isEof==0 ); + switch( iCol ){ + case 0: /* term */ + sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); + break; - *pnKey = (int)(zCsr-z); - zValue = sqlite3_mprintf("%s", &zCsr[1]); - if( zValue ){ - sqlite3Fts3Dequote(zValue); + case 1: /* col */ + if( p->iCol ){ + sqlite3_result_int(pCtx, p->iCol-1); + }else{ + sqlite3_result_text(pCtx, "*", -1, SQLITE_STATIC); + } + break; + + case 2: /* documents */ + sqlite3_result_int64(pCtx, p->aStat[p->iCol].nDoc); + break; + + case 3: /* occurrences */ + sqlite3_result_int64(pCtx, p->aStat[p->iCol].nOcc); + break; + + default: /* languageid */ + assert( iCol==4 ); + sqlite3_result_int(pCtx, p->iLangid); + break; } - *pzValue = zValue; - return 1; + + return SQLITE_OK; } /* -** Append the output of a printf() style formatting to an existing string. +** xRowid - Return the current rowid for the cursor. */ -static void fts3Appendf( - int *pRc, /* IN/OUT: Error code */ - char **pz, /* IN/OUT: Pointer to string buffer */ - const char *zFormat, /* Printf format string to append */ - ... /* Arguments for printf format string */ +static int fts3auxRowidMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite_int64 *pRowid /* OUT: Rowid value */ ){ - if( *pRc==SQLITE_OK ){ - va_list ap; - char *z; - va_start(ap, zFormat); - z = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - if( z && *pz ){ - char *z2 = sqlite3_mprintf("%s%s", *pz, z); - sqlite3_free(z); - z = z2; - } - if( z==0 ) *pRc = SQLITE_NOMEM; - sqlite3_free(*pz); - *pz = z; - } + Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; + *pRowid = pCsr->iRowid; + return SQLITE_OK; } /* -** Return a copy of input string zInput enclosed in double-quotes (") and -** with all double quote characters escaped. For example: -** -** fts3QuoteId("un \"zip\"") -> "un \"\"zip\"\"" -** -** The pointer returned points to memory obtained from sqlite3_malloc(). It -** is the callers responsibility to call sqlite3_free() to release this -** memory. +** Register the fts3aux module with database connection db. Return SQLITE_OK +** if successful or an error code if sqlite3_create_module() fails. */ -static char *fts3QuoteId(char const *zInput){ - int nRet; - char *zRet; - nRet = 2 + (int)strlen(zInput)*2 + 1; - zRet = sqlite3_malloc(nRet); - if( zRet ){ - int i; - char *z = zRet; - *(z++) = '"'; - for(i=0; zInput[i]; i++){ - if( zInput[i]=='"' ) *(z++) = '"'; - *(z++) = zInput[i]; - } - *(z++) = '"'; - *(z++) = '\0'; - } - return zRet; +SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){ + static const sqlite3_module fts3aux_module = { + 0, /* iVersion */ + fts3auxConnectMethod, /* xCreate */ + fts3auxConnectMethod, /* xConnect */ + fts3auxBestIndexMethod, /* xBestIndex */ + fts3auxDisconnectMethod, /* xDisconnect */ + fts3auxDisconnectMethod, /* xDestroy */ + fts3auxOpenMethod, /* xOpen */ + fts3auxCloseMethod, /* xClose */ + fts3auxFilterMethod, /* xFilter */ + fts3auxNextMethod, /* xNext */ + fts3auxEofMethod, /* xEof */ + fts3auxColumnMethod, /* xColumn */ + fts3auxRowidMethod, /* xRowid */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindFunction */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ + }; + int rc; /* Return code */ + + rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0); + return rc; } +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_aux.c ********************************************/ +/************** Begin file fts3_expr.c ***************************************/ /* -** Return a list of comma separated SQL expressions and a FROM clause that -** could be used in a SELECT statement such as the following: -** -** SELECT FROM %_content AS x ... +** 2008 Nov 28 ** -** to return the docid, followed by each column of text data in order -** from left to write. If parameter zFunc is not NULL, then instead of -** being returned directly each column of text data is passed to an SQL -** function named zFunc first. For example, if zFunc is "unzip" and the -** table has the three user-defined columns "a", "b", and "c", the following -** string is returned: +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x" +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. ** -** The pointer returned points to a buffer allocated by sqlite3_malloc(). It -** is the responsibility of the caller to eventually free it. +****************************************************************************** ** -** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and -** a NULL pointer is returned). Otherwise, if an OOM error is encountered -** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If -** no error occurs, *pRc is left unmodified. +** This module contains code that implements a parser for fts3 query strings +** (the right-hand argument to the MATCH operator). Because the supported +** syntax is relatively simple, the whole tokenizer/parser system is +** hand-coded. */ -static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){ - char *zRet = 0; - char *zFree = 0; - char *zFunction; - int i; - - if( p->zContentTbl==0 ){ - if( !zFunc ){ - zFunction = ""; - }else{ - zFree = zFunction = fts3QuoteId(zFunc); - } - fts3Appendf(pRc, &zRet, "docid"); - for(i=0; inColumn; i++){ - fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); - } - if( p->zLanguageid ){ - fts3Appendf(pRc, &zRet, ", x.%Q", "langid"); - } - sqlite3_free(zFree); - }else{ - fts3Appendf(pRc, &zRet, "rowid"); - for(i=0; inColumn; i++){ - fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]); - } - if( p->zLanguageid ){ - fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid); - } - } - fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x", - p->zDb, - (p->zContentTbl ? p->zContentTbl : p->zName), - (p->zContentTbl ? "" : "_content") - ); - return zRet; -} +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) /* -** Return a list of N comma separated question marks, where N is the number -** of columns in the %_content table (one for the docid plus one for each -** user-defined text column). +** By default, this module parses the legacy syntax that has been +** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS +** is defined, then it uses the new syntax. The differences between +** the new and the old syntaxes are: ** -** If argument zFunc is not NULL, then all but the first question mark -** is preceded by zFunc and an open bracket, and followed by a closed -** bracket. For example, if zFunc is "zip" and the FTS3 table has three -** user-defined text columns, the following string is returned: +** a) The new syntax supports parenthesis. The old does not. ** -** "?, zip(?), zip(?), zip(?)" +** b) The new syntax supports the AND and NOT operators. The old does not. ** -** The pointer returned points to a buffer allocated by sqlite3_malloc(). It -** is the responsibility of the caller to eventually free it. +** c) The old syntax supports the "-" token qualifier. This is not +** supported by the new syntax (it is replaced by the NOT operator). ** -** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and -** a NULL pointer is returned). Otherwise, if an OOM error is encountered -** by this function, NULL is returned and *pRc is set to SQLITE_NOMEM. If -** no error occurs, *pRc is left unmodified. +** d) When using the old syntax, the OR operator has a greater precedence +** than an implicit AND. When using the new, both implicity and explicit +** AND operators have a higher precedence than OR. +** +** If compiled with SQLITE_TEST defined, then this module exports the +** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable +** to zero causes the module to use the old syntax. If it is set to +** non-zero the new syntax is activated. This is so both syntaxes can +** be tested using a single build of testfixture. +** +** The following describes the syntax supported by the fts3 MATCH +** operator in a similar format to that used by the lemon parser +** generator. This module does not use actually lemon, it uses a +** custom parser. +** +** query ::= andexpr (OR andexpr)*. +** +** andexpr ::= notexpr (AND? notexpr)*. +** +** notexpr ::= nearexpr (NOT nearexpr|-TOKEN)*. +** notexpr ::= LP query RP. +** +** nearexpr ::= phrase (NEAR distance_opt nearexpr)*. +** +** distance_opt ::= . +** distance_opt ::= / INTEGER. +** +** phrase ::= TOKEN. +** phrase ::= COLUMN:TOKEN. +** phrase ::= "TOKEN TOKEN TOKEN...". */ -static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){ - char *zRet = 0; - char *zFree = 0; - char *zFunction; - int i; - if( !zFunc ){ - zFunction = ""; - }else{ - zFree = zFunction = fts3QuoteId(zFunc); - } - fts3Appendf(pRc, &zRet, "?"); - for(i=0; inColumn; i++){ - fts3Appendf(pRc, &zRet, ",%s(?)", zFunction); - } - if( p->zLanguageid ){ - fts3Appendf(pRc, &zRet, ", ?"); - } - sqlite3_free(zFree); - return zRet; +#ifdef SQLITE_TEST +SQLITE_API int sqlite3_fts3_enable_parentheses = 0; +#else +# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS +# define sqlite3_fts3_enable_parentheses 1 +# else +# define sqlite3_fts3_enable_parentheses 0 +# endif +#endif + +/* +** Default span for NEAR operators. +*/ +#define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 + +/* #include */ +/* #include */ + +/* +** isNot: +** This variable is used by function getNextNode(). When getNextNode() is +** called, it sets ParseContext.isNot to true if the 'next node' is a +** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the +** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to +** zero. +*/ +typedef struct ParseContext ParseContext; +struct ParseContext { + sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ + int iLangid; /* Language id used with tokenizer */ + const char **azCol; /* Array of column names for fts3 table */ + int bFts4; /* True to allow FTS4-only syntax */ + int nCol; /* Number of entries in azCol[] */ + int iDefaultCol; /* Default column to query */ + int isNot; /* True if getNextNode() sees a unary - */ + sqlite3_context *pCtx; /* Write error message here */ + int nNest; /* Number of nested brackets */ +}; + +/* +** This function is equivalent to the standard isspace() function. +** +** The standard isspace() can be awkward to use safely, because although it +** is defined to accept an argument of type int, its behavior when passed +** an integer that falls outside of the range of the unsigned char type +** is undefined (and sometimes, "undefined" means segfault). This wrapper +** is defined to accept an argument of type char, and always returns 0 for +** any values that fall outside of the range of the unsigned char type (i.e. +** negative values). +*/ +static int fts3isspace(char c){ + return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } /* -** This function interprets the string at (*pp) as a non-negative integer -** value. It reads the integer and sets *pnOut to the value read, then -** sets *pp to point to the byte immediately following the last byte of -** the integer value. -** -** Only decimal digits ('0'..'9') may be part of an integer value. -** -** If *pp does not being with a decimal digit SQLITE_ERROR is returned and -** the output value undefined. Otherwise SQLITE_OK is returned. -** -** This function is used when parsing the "prefix=" FTS4 parameter. +** Allocate nByte bytes of memory using sqlite3_malloc(). If successful, +** zero the memory before returning a pointer to it. If unsuccessful, +** return NULL. */ -static int fts3GobbleInt(const char **pp, int *pnOut){ - const int MAX_NPREFIX = 10000000; - const char *p; /* Iterator pointer */ - int nInt = 0; /* Output value */ +SQLITE_PRIVATE void *sqlite3Fts3MallocZero(sqlite3_int64 nByte){ + void *pRet = sqlite3_malloc64(nByte); + if( pRet ) memset(pRet, 0, nByte); + return pRet; +} - for(p=*pp; p[0]>='0' && p[0]<='9'; p++){ - nInt = nInt * 10 + (p[0] - '0'); - if( nInt>MAX_NPREFIX ){ - nInt = 0; - break; +SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer( + sqlite3_tokenizer *pTokenizer, + int iLangid, + const char *z, + int n, + sqlite3_tokenizer_cursor **ppCsr +){ + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + sqlite3_tokenizer_cursor *pCsr = 0; + int rc; + + rc = pModule->xOpen(pTokenizer, z, n, &pCsr); + assert( rc==SQLITE_OK || pCsr==0 ); + if( rc==SQLITE_OK ){ + pCsr->pTokenizer = pTokenizer; + if( pModule->iVersion>=1 ){ + rc = pModule->xLanguageid(pCsr, iLangid); + if( rc!=SQLITE_OK ){ + pModule->xClose(pCsr); + pCsr = 0; + } } } - if( p==*pp ) return SQLITE_ERROR; - *pnOut = nInt; - *pp = p; - return SQLITE_OK; + *ppCsr = pCsr; + return rc; } /* -** This function is called to allocate an array of Fts3Index structures -** representing the indexes maintained by the current FTS table. FTS tables -** always maintain the main "terms" index, but may also maintain one or -** more "prefix" indexes, depending on the value of the "prefix=" parameter -** (if any) specified as part of the CREATE VIRTUAL TABLE statement. -** -** Argument zParam is passed the value of the "prefix=" option if one was -** specified, or NULL otherwise. -** -** If no error occurs, SQLITE_OK is returned and *apIndex set to point to -** the allocated array. *pnIndex is set to the number of elements in the -** array. If an error does occur, an SQLite error code is returned. +** Function getNextNode(), which is called by fts3ExprParse(), may itself +** call fts3ExprParse(). So this forward declaration is required. +*/ +static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); + +/* +** Extract the next token from buffer z (length n) using the tokenizer +** and other information (column names etc.) in pParse. Create an Fts3Expr +** structure of type FTSQUERY_PHRASE containing a phrase consisting of this +** single token and set *ppExpr to point to it. If the end of the buffer is +** reached before a token is found, set *ppExpr to zero. It is the +** responsibility of the caller to eventually deallocate the allocated +** Fts3Expr structure (if any) by passing it to sqlite3_free(). ** -** Regardless of whether or not an error is returned, it is the responsibility -** of the caller to call sqlite3_free() on the output array to free it. +** Return SQLITE_OK if successful, or SQLITE_NOMEM if a memory allocation +** fails. */ -static int fts3PrefixParameter( - const char *zParam, /* ABC in prefix=ABC parameter to parse */ - int *pnIndex, /* OUT: size of *apIndex[] array */ - struct Fts3Index **apIndex /* OUT: Array of indexes for this table */ +static int getNextToken( + ParseContext *pParse, /* fts3 query parse context */ + int iCol, /* Value for Fts3Phrase.iColumn */ + const char *z, int n, /* Input string */ + Fts3Expr **ppExpr, /* OUT: expression */ + int *pnConsumed /* OUT: Number of bytes consumed */ ){ - struct Fts3Index *aIndex; /* Allocated array */ - int nIndex = 1; /* Number of entries in array */ + sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + int rc; + sqlite3_tokenizer_cursor *pCursor; + Fts3Expr *pRet = 0; + int i = 0; - if( zParam && zParam[0] ){ - const char *p; - nIndex++; - for(p=zParam; *p; p++){ - if( *p==',' ) nIndex++; - } + /* Set variable i to the maximum number of bytes of input to tokenize. */ + for(i=0; iiLangid, z, i, &pCursor); + if( rc==SQLITE_OK ){ + const char *zToken; + int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; + sqlite3_int64 nByte; /* total space to allocate */ - memset(aIndex, 0, sizeof(struct Fts3Index) * nIndex); - if( zParam ){ - const char *p = zParam; - int i; - for(i=1; i=0 ); - if( nPrefix==0 ){ - nIndex--; - i--; + rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); + if( rc==SQLITE_OK ){ + nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; + pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte); + if( !pRet ){ + rc = SQLITE_NOMEM; }else{ - aIndex[i].nPrefix = nPrefix; + pRet->eType = FTSQUERY_PHRASE; + pRet->pPhrase = (Fts3Phrase *)&pRet[1]; + pRet->pPhrase->nToken = 1; + pRet->pPhrase->iColumn = iCol; + pRet->pPhrase->aToken[0].n = nToken; + pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1]; + memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken); + + if( iEndpPhrase->aToken[0].isPrefix = 1; + iEnd++; + } + + while( 1 ){ + if( !sqlite3_fts3_enable_parentheses + && iStart>0 && z[iStart-1]=='-' + ){ + pParse->isNot = 1; + iStart--; + }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){ + pRet->pPhrase->aToken[0].bFirst = 1; + iStart--; + }else{ + break; + } + } + } - p++; + *pnConsumed = iEnd; + }else if( i && rc==SQLITE_DONE ){ + rc = SQLITE_OK; } + + pModule->xClose(pCursor); } - *pnIndex = nIndex; - return SQLITE_OK; + *ppExpr = pRet; + return rc; } + /* -** This function is called when initializing an FTS4 table that uses the -** content=xxx option. It determines the number of and names of the columns -** of the new FTS4 table. -** -** The third argument passed to this function is the value passed to the -** config=xxx option (i.e. "xxx"). This function queries the database for -** a table of that name. If found, the output variables are populated -** as follows: -** -** *pnCol: Set to the number of columns table xxx has, -** -** *pnStr: Set to the total amount of space required to store a copy -** of each columns name, including the nul-terminator. -** -** *pazCol: Set to point to an array of *pnCol strings. Each string is -** the name of the corresponding column in table xxx. The array -** and its contents are allocated using a single allocation. It -** is the responsibility of the caller to free this allocation -** by eventually passing the *pazCol value to sqlite3_free(). +** Enlarge a memory allocation. If an out-of-memory allocation occurs, +** then free the old allocation. +*/ +static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){ + void *pRet = sqlite3_realloc64(pOrig, nNew); + if( !pRet ){ + sqlite3_free(pOrig); + } + return pRet; +} + +/* +** Buffer zInput, length nInput, contains the contents of a quoted string +** that appeared as part of an fts3 query expression. Neither quote character +** is included in the buffer. This function attempts to tokenize the entire +** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE +** containing the results. ** -** If the table cannot be found, an error code is returned and the output -** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is -** returned (and the output variables are undefined). +** If successful, SQLITE_OK is returned and *ppExpr set to point at the +** allocated Fts3Expr structure. Otherwise, either SQLITE_NOMEM (out of memory +** error) or SQLITE_ERROR (tokenization error) is returned and *ppExpr set +** to 0. */ -static int fts3ContentColumns( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */ - const char *zTbl, /* Name of content table */ - const char ***pazCol, /* OUT: Malloc'd array of column names */ - int *pnCol, /* OUT: Size of array *pazCol */ - int *pnStr, /* OUT: Bytes of string content */ - char **pzErr /* OUT: error message */ +static int getNextString( + ParseContext *pParse, /* fts3 query parse context */ + const char *zInput, int nInput, /* Input string */ + Fts3Expr **ppExpr /* OUT: expression */ ){ - int rc = SQLITE_OK; /* Return code */ - char *zSql; /* "SELECT *" statement on zTbl */ - sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */ + sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + int rc; + Fts3Expr *p = 0; + sqlite3_tokenizer_cursor *pCursor = 0; + char *zTemp = 0; + int nTemp = 0; - zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl); - if( !zSql ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ){ - sqlite3Fts3ErrMsg(pzErr, "%s", sqlite3_errmsg(db)); - } - } - sqlite3_free(zSql); + const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase); + int nToken = 0; + /* The final Fts3Expr data structure, including the Fts3Phrase, + ** Fts3PhraseToken structures token buffers are all stored as a single + ** allocation so that the expression can be freed with a single call to + ** sqlite3_free(). Setting this up requires a two pass approach. + ** + ** The first pass, in the block below, uses a tokenizer cursor to iterate + ** through the tokens in the expression. This pass uses fts3ReallocOrFree() + ** to assemble data in two dynamic buffers: + ** + ** Buffer p: Points to the Fts3Expr structure, followed by the Fts3Phrase + ** structure, followed by the array of Fts3PhraseToken + ** structures. This pass only populates the Fts3PhraseToken array. + ** + ** Buffer zTemp: Contains copies of all tokens. + ** + ** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below, + ** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase + ** structures. + */ + rc = sqlite3Fts3OpenTokenizer( + pTokenizer, pParse->iLangid, zInput, nInput, &pCursor); if( rc==SQLITE_OK ){ - const char **azCol; /* Output array */ - int nStr = 0; /* Size of all column names (incl. 0x00) */ - int nCol; /* Number of table columns */ - int i; /* Used to iterate through columns */ + int ii; + for(ii=0; rc==SQLITE_OK; ii++){ + const char *zByte; + int nByte = 0, iBegin = 0, iEnd = 0, iPos = 0; + rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos); + if( rc==SQLITE_OK ){ + Fts3PhraseToken *pToken; - /* Loop through the returned columns. Set nStr to the number of bytes of - ** space required to store a copy of each column name, including the - ** nul-terminator byte. */ - nCol = sqlite3_column_count(pStmt); - for(i=0; iaToken[ii]; + memset(pToken, 0, sizeof(Fts3PhraseToken)); + + memcpy(&zTemp[nTemp], zByte, nByte); + nTemp += nByte; + + pToken->n = nByte; + pToken->isPrefix = (iEndbFirst = (iBegin>0 && zInput[iBegin-1]=='^'); + nToken = ii+1; + } } - /* Allocate and populate the array to return. */ - azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr); - if( azCol==0 ){ - rc = SQLITE_NOMEM; + pModule->xClose(pCursor); + pCursor = 0; + } + + if( rc==SQLITE_DONE ){ + int jj; + char *zBuf = 0; + + p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp); + if( !p ) goto no_mem; + memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p); + p->eType = FTSQUERY_PHRASE; + p->pPhrase = (Fts3Phrase *)&p[1]; + p->pPhrase->iColumn = pParse->iDefaultCol; + p->pPhrase->nToken = nToken; + + zBuf = (char *)&p->pPhrase->aToken[nToken]; + if( zTemp ){ + memcpy(zBuf, zTemp, nTemp); + sqlite3_free(zTemp); }else{ - char *p = (char *)&azCol[nCol]; - for(i=0; ipPhrase->nToken; jj++){ + p->pPhrase->aToken[jj].z = zBuf; + zBuf += p->pPhrase->aToken[jj].n; + } + rc = SQLITE_OK; } + *ppExpr = p; return rc; +no_mem: + + if( pCursor ){ + pModule->xClose(pCursor); + } + sqlite3_free(zTemp); + sqlite3_free(p); + *ppExpr = 0; + return SQLITE_NOMEM; } /* -** This function is the implementation of both the xConnect and xCreate -** methods of the FTS3 virtual table. -** -** The argv[] array contains the following: +** The output variable *ppExpr is populated with an allocated Fts3Expr +** structure, or set to 0 if the end of the input buffer is reached. ** -** argv[0] -> module name ("fts3" or "fts4") -** argv[1] -> database name -** argv[2] -> table name -** argv[...] -> "column name" and other module argument fields. +** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM +** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered. +** If SQLITE_ERROR is returned, pContext is populated with an error message. */ -static int fts3InitVtab( - int isCreate, /* True for xCreate, false for xConnect */ - sqlite3 *db, /* The SQLite database connection */ - void *pAux, /* Hash table containing tokenizers */ - int argc, /* Number of elements in argv array */ - const char * const *argv, /* xCreate/xConnect argument array */ - sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ - char **pzErr /* Write any error message here */ +static int getNextNode( + ParseContext *pParse, /* fts3 query parse context */ + const char *z, int n, /* Input string */ + Fts3Expr **ppExpr, /* OUT: expression */ + int *pnConsumed /* OUT: Number of bytes consumed */ ){ - Fts3Hash *pHash = (Fts3Hash *)pAux; - Fts3Table *p = 0; /* Pointer to allocated vtab */ - int rc = SQLITE_OK; /* Return code */ - int i; /* Iterator variable */ - int nByte; /* Size of allocation used for *p */ - int iCol; /* Column index */ - int nString = 0; /* Bytes required to hold all column names */ - int nCol = 0; /* Number of columns in the FTS table */ - char *zCsr; /* Space for holding column names */ - int nDb; /* Bytes required to hold database name */ - int nName; /* Bytes required to hold table name */ - int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */ - const char **aCol; /* Array of column names */ - sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */ - - int nIndex = 0; /* Size of aIndex[] array */ - struct Fts3Index *aIndex = 0; /* Array of indexes for this table */ - - /* The results of parsing supported FTS4 key=value options: */ - int bNoDocsize = 0; /* True to omit %_docsize table */ - int bDescIdx = 0; /* True to store descending indexes */ - char *zPrefix = 0; /* Prefix parameter value (or NULL) */ - char *zCompress = 0; /* compress=? parameter (or NULL) */ - char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ - char *zContent = 0; /* content=? parameter (or NULL) */ - char *zLanguageid = 0; /* languageid=? parameter (or NULL) */ - char **azNotindexed = 0; /* The set of notindexed= columns */ - int nNotindexed = 0; /* Size of azNotindexed[] array */ + static const struct Fts3Keyword { + char *z; /* Keyword text */ + unsigned char n; /* Length of the keyword */ + unsigned char parenOnly; /* Only valid in paren mode */ + unsigned char eType; /* Keyword code */ + } aKeyword[] = { + { "OR" , 2, 0, FTSQUERY_OR }, + { "AND", 3, 1, FTSQUERY_AND }, + { "NOT", 3, 1, FTSQUERY_NOT }, + { "NEAR", 4, 0, FTSQUERY_NEAR } + }; + int ii; + int iCol; + int iColLen; + int rc; + Fts3Expr *pRet = 0; - assert( strlen(argv[0])==4 ); - assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) - || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) - ); + const char *zInput = z; + int nInput = n; - nDb = (int)strlen(argv[1]) + 1; - nName = (int)strlen(argv[2]) + 1; + pParse->isNot = 0; - nByte = sizeof(const char *) * (argc-2); - aCol = (const char **)sqlite3_malloc(nByte); - if( aCol ){ - memset((void*)aCol, 0, nByte); - azNotindexed = (char **)sqlite3_malloc(nByte); - } - if( azNotindexed ){ - memset(azNotindexed, 0, nByte); + /* Skip over any whitespace before checking for a keyword, an open or + ** close bracket, or a quoted string. + */ + while( nInput>0 && fts3isspace(*zInput) ){ + nInput--; + zInput++; } - if( !aCol || !azNotindexed ){ - rc = SQLITE_NOMEM; - goto fts3_init_out; + if( nInput==0 ){ + return SQLITE_DONE; } - /* Loop through all of the arguments passed by the user to the FTS3/4 - ** module (i.e. all the column names and special arguments). This loop - ** does the following: - ** - ** + Figures out the number of columns the FTSX table will have, and - ** the number of bytes of space that must be allocated to store copies - ** of the column names. - ** - ** + If there is a tokenizer specification included in the arguments, - ** initializes the tokenizer pTokenizer. - */ - for(i=3; rc==SQLITE_OK && i8 - && 0==sqlite3_strnicmp(z, "tokenize", 8) - && 0==sqlite3Fts3IsIdChar(z[8]) - ){ - rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr); + if( (pKey->parenOnly & ~sqlite3_fts3_enable_parentheses)!=0 ){ + continue; } - /* Check if it is an FTS4 special argument. */ - else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){ - struct Fts4Option { - const char *zOpt; - int nOpt; - } aFts4Opt[] = { - { "matchinfo", 9 }, /* 0 -> MATCHINFO */ - { "prefix", 6 }, /* 1 -> PREFIX */ - { "compress", 8 }, /* 2 -> COMPRESS */ - { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ - { "order", 5 }, /* 4 -> ORDER */ - { "content", 7 }, /* 5 -> CONTENT */ - { "languageid", 10 }, /* 6 -> LANGUAGEID */ - { "notindexed", 10 } /* 7 -> NOTINDEXED */ - }; + if( nInput>=pKey->n && 0==memcmp(zInput, pKey->z, pKey->n) ){ + int nNear = SQLITE_FTS3_DEFAULT_NEAR_PARAM; + int nKey = pKey->n; + char cNext; - int iOpt; - if( !zVal ){ - rc = SQLITE_NOMEM; - }else{ - for(iOpt=0; iOptnOpt && !sqlite3_strnicmp(z, pOp->zOpt, pOp->nOpt) ){ - break; - } + /* If this is a "NEAR" keyword, check for an explicit nearness. */ + if( pKey->eType==FTSQUERY_NEAR ){ + assert( nKey==4 ); + if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ + nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear); } - if( iOpt==SizeofArray(aFts4Opt) ){ - sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z); - rc = SQLITE_ERROR; - }else{ - switch( iOpt ){ - case 0: /* MATCHINFO */ - if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){ - sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal); - rc = SQLITE_ERROR; - } - bNoDocsize = 1; - break; - - case 1: /* PREFIX */ - sqlite3_free(zPrefix); - zPrefix = zVal; - zVal = 0; - break; - - case 2: /* COMPRESS */ - sqlite3_free(zCompress); - zCompress = zVal; - zVal = 0; - break; - - case 3: /* UNCOMPRESS */ - sqlite3_free(zUncompress); - zUncompress = zVal; - zVal = 0; - break; - - case 4: /* ORDER */ - if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) - && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) - ){ - sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal); - rc = SQLITE_ERROR; - } - bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); - break; - - case 5: /* CONTENT */ - sqlite3_free(zContent); - zContent = zVal; - zVal = 0; - break; - - case 6: /* LANGUAGEID */ - assert( iOpt==6 ); - sqlite3_free(zLanguageid); - zLanguageid = zVal; - zVal = 0; - break; + } - case 7: /* NOTINDEXED */ - azNotindexed[nNotindexed++] = zVal; - zVal = 0; - break; - } + /* At this point this is probably a keyword. But for that to be true, + ** the next byte must contain either whitespace, an open or close + ** parenthesis, a quote character, or EOF. + */ + cNext = zInput[nKey]; + if( fts3isspace(cNext) + || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 + ){ + pRet = (Fts3Expr *)sqlite3Fts3MallocZero(sizeof(Fts3Expr)); + if( !pRet ){ + return SQLITE_NOMEM; } - sqlite3_free(zVal); + pRet->eType = pKey->eType; + pRet->nNear = nNear; + *ppExpr = pRet; + *pnConsumed = (int)((zInput - z) + nKey); + return SQLITE_OK; } - } - /* Otherwise, the argument is a column name. */ - else { - nString += (int)(strlen(z) + 1); - aCol[nCol++] = z; + /* Turns out that wasn't a keyword after all. This happens if the + ** user has supplied a token such as "ORacle". Continue. + */ } } - /* If a content=xxx option was specified, the following: - ** - ** 1. Ignore any compress= and uncompress= options. - ** - ** 2. If no column names were specified as part of the CREATE VIRTUAL - ** TABLE statement, use all columns from the content table. + /* See if we are dealing with a quoted phrase. If this is the case, then + ** search for the closing quote and pass the whole string to getNextString() + ** for processing. This is easy to do, as fts3 has no syntax for escaping + ** a quote character embedded in a string. */ - if( rc==SQLITE_OK && zContent ){ - sqlite3_free(zCompress); - sqlite3_free(zUncompress); - zCompress = 0; - zUncompress = 0; - if( nCol==0 ){ - sqlite3_free((void*)aCol); - aCol = 0; - rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr); - - /* If a languageid= option was specified, remove the language id - ** column from the aCol[] array. */ - if( rc==SQLITE_OK && zLanguageid ){ - int j; - for(j=0; jnNest++; +#if !defined(SQLITE_MAX_EXPR_DEPTH) + if( pParse->nNest>1000 ) return SQLITE_ERROR; +#elif SQLITE_MAX_EXPR_DEPTH>0 + if( pParse->nNest>SQLITE_MAX_EXPR_DEPTH ) return SQLITE_ERROR; +#endif + rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); + *pnConsumed = (int)(zInput - z) + 1 + nConsumed; + return rc; + }else if( *zInput==')' ){ + pParse->nNest--; + *pnConsumed = (int)((zInput - z) + 1); + *ppExpr = 0; + return SQLITE_DONE; + } } - if( pTokenizer==0 ){ - rc = sqlite3Fts3InitTokenizer(pHash, "simple", &pTokenizer, pzErr); - if( rc!=SQLITE_OK ) goto fts3_init_out; + /* If control flows to this point, this must be a regular token, or + ** the end of the input. Read a regular token using the sqlite3_tokenizer + ** interface. Before doing so, figure out if there is an explicit + ** column specifier for the token. + ** + ** TODO: Strangely, it is not possible to associate a column specifier + ** with a quoted phrase, only with a single token. Not sure if this was + ** an implementation artifact or an intentional decision when fts3 was + ** first implemented. Whichever it was, this module duplicates the + ** limitation. + */ + iCol = pParse->iDefaultCol; + iColLen = 0; + for(ii=0; iinCol; ii++){ + const char *zStr = pParse->azCol[ii]; + int nStr = (int)strlen(zStr); + if( nInput>nStr && zInput[nStr]==':' + && sqlite3_strnicmp(zStr, zInput, nStr)==0 + ){ + iCol = ii; + iColLen = (int)((zInput - z) + nStr + 1); + break; + } } - assert( pTokenizer ); + rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed); + *pnConsumed += iColLen; + return rc; +} - rc = fts3PrefixParameter(zPrefix, &nIndex, &aIndex); - if( rc==SQLITE_ERROR ){ - assert( zPrefix ); - sqlite3Fts3ErrMsg(pzErr, "error parsing prefix parameter: %s", zPrefix); +/* +** The argument is an Fts3Expr structure for a binary operator (any type +** except an FTSQUERY_PHRASE). Return an integer value representing the +** precedence of the operator. Lower values have a higher precedence (i.e. +** group more tightly). For example, in the C language, the == operator +** groups more tightly than ||, and would therefore have a higher precedence. +** +** When using the new fts3 query syntax (when SQLITE_ENABLE_FTS3_PARENTHESIS +** is defined), the order of the operators in precedence from highest to +** lowest is: +** +** NEAR +** NOT +** AND (including implicit ANDs) +** OR +** +** Note that when using the old query syntax, the OR operator has a higher +** precedence than the AND operator. +*/ +static int opPrecedence(Fts3Expr *p){ + assert( p->eType!=FTSQUERY_PHRASE ); + if( sqlite3_fts3_enable_parentheses ){ + return p->eType; + }else if( p->eType==FTSQUERY_NEAR ){ + return 1; + }else if( p->eType==FTSQUERY_OR ){ + return 2; } - if( rc!=SQLITE_OK ) goto fts3_init_out; + assert( p->eType==FTSQUERY_AND ); + return 3; +} - /* Allocate and populate the Fts3Table structure. */ - nByte = sizeof(Fts3Table) + /* Fts3Table */ - nCol * sizeof(char *) + /* azColumn */ - nIndex * sizeof(struct Fts3Index) + /* aIndex */ - nCol * sizeof(u8) + /* abNotindexed */ - nName + /* zName */ - nDb + /* zDb */ - nString; /* Space for azColumn strings */ - p = (Fts3Table*)sqlite3_malloc(nByte); - if( p==0 ){ - rc = SQLITE_NOMEM; - goto fts3_init_out; +/* +** Argument ppHead contains a pointer to the current head of a query +** expression tree being parsed. pPrev is the expression node most recently +** inserted into the tree. This function adds pNew, which is always a binary +** operator node, into the expression tree based on the relative precedence +** of pNew and the existing nodes of the tree. This may result in the head +** of the tree changing, in which case *ppHead is set to the new root node. +*/ +static void insertBinaryOperator( + Fts3Expr **ppHead, /* Pointer to the root node of a tree */ + Fts3Expr *pPrev, /* Node most recently inserted into the tree */ + Fts3Expr *pNew /* New binary node to insert into expression tree */ +){ + Fts3Expr *pSplit = pPrev; + while( pSplit->pParent && opPrecedence(pSplit->pParent)<=opPrecedence(pNew) ){ + pSplit = pSplit->pParent; } - memset(p, 0, nByte); - p->db = db; - p->nColumn = nCol; - p->nPendingData = 0; - p->azColumn = (char **)&p[1]; - p->pTokenizer = pTokenizer; - p->nMaxPendingData = FTS3_MAX_PENDING_DATA; - p->bHasDocsize = (isFts4 && bNoDocsize==0); - p->bHasStat = (u8)isFts4; - p->bFts4 = (u8)isFts4; - p->bDescIdx = (u8)bDescIdx; - p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */ - p->zContentTbl = zContent; - p->zLanguageid = zLanguageid; - zContent = 0; - zLanguageid = 0; - TESTONLY( p->inTransaction = -1 ); - TESTONLY( p->mxSavepoint = -1 ); - p->aIndex = (struct Fts3Index *)&p->azColumn[nCol]; - memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex); - p->nIndex = nIndex; - for(i=0; iaIndex[i].hPending, FTS3_HASH_STRING, 1); + if( pSplit->pParent ){ + assert( pSplit->pParent->pRight==pSplit ); + pSplit->pParent->pRight = pNew; + pNew->pParent = pSplit->pParent; + }else{ + *ppHead = pNew; } - p->abNotindexed = (u8 *)&p->aIndex[nIndex]; + pNew->pLeft = pSplit; + pSplit->pParent = pNew; +} - /* Fill in the zName and zDb fields of the vtab structure. */ - zCsr = (char *)&p->abNotindexed[nCol]; - p->zName = zCsr; - memcpy(zCsr, argv[2], nName); - zCsr += nName; - p->zDb = zCsr; - memcpy(zCsr, argv[1], nDb); - zCsr += nDb; +/* +** Parse the fts3 query expression found in buffer z, length n. This function +** returns either when the end of the buffer is reached or an unmatched +** closing bracket - ')' - is encountered. +** +** If successful, SQLITE_OK is returned, *ppExpr is set to point to the +** parsed form of the expression and *pnConsumed is set to the number of +** bytes read from buffer z. Otherwise, *ppExpr is set to 0 and SQLITE_NOMEM +** (out of memory error) or SQLITE_ERROR (parse error) is returned. +*/ +static int fts3ExprParse( + ParseContext *pParse, /* fts3 query parse context */ + const char *z, int n, /* Text of MATCH query */ + Fts3Expr **ppExpr, /* OUT: Parsed query structure */ + int *pnConsumed /* OUT: Number of bytes consumed */ +){ + Fts3Expr *pRet = 0; + Fts3Expr *pPrev = 0; + Fts3Expr *pNotBranch = 0; /* Only used in legacy parse mode */ + int nIn = n; + const char *zIn = z; + int rc = SQLITE_OK; + int isRequirePhrase = 1; - /* Fill in the azColumn array */ - for(iCol=0; iColazColumn[iCol] = zCsr; - zCsr += n+1; - assert( zCsr <= &((char *)p)[nByte] ); - } + while( rc==SQLITE_OK ){ + Fts3Expr *p = 0; + int nByte = 0; - /* Fill in the abNotindexed array */ - for(iCol=0; iColazColumn[iCol]); - for(i=0; iazColumn[iCol], zNot, n) - ){ - p->abNotindexed[iCol] = 1; - sqlite3_free(zNot); - azNotindexed[i] = 0; + rc = getNextNode(pParse, zIn, nIn, &p, &nByte); + assert( nByte>0 || (rc!=SQLITE_OK && p==0) ); + if( rc==SQLITE_OK ){ + if( p ){ + int isPhrase; + + if( !sqlite3_fts3_enable_parentheses + && p->eType==FTSQUERY_PHRASE && pParse->isNot + ){ + /* Create an implicit NOT operator. */ + Fts3Expr *pNot = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); + if( !pNot ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_NOMEM; + goto exprparse_out; + } + pNot->eType = FTSQUERY_NOT; + pNot->pRight = p; + p->pParent = pNot; + if( pNotBranch ){ + pNot->pLeft = pNotBranch; + pNotBranch->pParent = pNot; + } + pNotBranch = pNot; + p = pPrev; + }else{ + int eType = p->eType; + isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); + + /* The isRequirePhrase variable is set to true if a phrase or + ** an expression contained in parenthesis is required. If a + ** binary operator (AND, OR, NOT or NEAR) is encounted when + ** isRequirePhrase is set, this is a syntax error. + */ + if( !isPhrase && isRequirePhrase ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase && !isRequirePhrase ){ + /* Insert an implicit AND operator. */ + Fts3Expr *pAnd; + assert( pRet && pPrev ); + pAnd = sqlite3Fts3MallocZero(sizeof(Fts3Expr)); + if( !pAnd ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_NOMEM; + goto exprparse_out; + } + pAnd->eType = FTSQUERY_AND; + insertBinaryOperator(&pRet, pPrev, pAnd); + pPrev = pAnd; + } + + /* This test catches attempts to make either operand of a NEAR + ** operator something other than a phrase. For example, either of + ** the following: + ** + ** (bracketed expression) NEAR phrase + ** phrase NEAR (bracketed expression) + ** + ** Return an error in either case. + */ + if( pPrev && ( + (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) + || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) + )){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_ERROR; + goto exprparse_out; + } + + if( isPhrase ){ + if( pRet ){ + assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); + pPrev->pRight = p; + p->pParent = pPrev; + }else{ + pRet = p; + } + }else{ + insertBinaryOperator(&pRet, pPrev, p); + } + isRequirePhrase = !isPhrase; + } + pPrev = p; } + assert( nByte>0 ); } - } - for(i=0; i0 && nByte<=nIn) ); + nIn -= nByte; + zIn += nByte; } - if( rc==SQLITE_OK && (zCompress==0)!=(zUncompress==0) ){ - char const *zMiss = (zCompress==0 ? "compress" : "uncompress"); + if( rc==SQLITE_DONE && pRet && isRequirePhrase ){ rc = SQLITE_ERROR; - sqlite3Fts3ErrMsg(pzErr, "missing %s parameter in fts4 constructor", zMiss); - } - p->zReadExprlist = fts3ReadExprList(p, zUncompress, &rc); - p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc); - if( rc!=SQLITE_OK ) goto fts3_init_out; - - /* If this is an xCreate call, create the underlying tables in the - ** database. TODO: For xConnect(), it could verify that said tables exist. - */ - if( isCreate ){ - rc = fts3CreateTables(p); } - /* Check to see if a legacy fts3 table has been "upgraded" by the - ** addition of a %_stat table so that it can use incremental merge. - */ - if( !isFts4 && !isCreate ){ - p->bHasStat = 2; + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + if( !sqlite3_fts3_enable_parentheses && pNotBranch ){ + if( !pRet ){ + rc = SQLITE_ERROR; + }else{ + Fts3Expr *pIter = pNotBranch; + while( pIter->pLeft ){ + pIter = pIter->pLeft; + } + pIter->pLeft = pRet; + pRet->pParent = pIter; + pRet = pNotBranch; + } + } } + *pnConsumed = n - nIn; - /* Figure out the page-size for the database. This is required in order to - ** estimate the cost of loading large doclists from the database. */ - fts3DatabasePageSize(&rc, p); - p->nNodeSize = p->nPgsz-35; - - /* Declare the table schema to SQLite. */ - fts3DeclareVtab(&rc, p); - -fts3_init_out: - sqlite3_free(zPrefix); - sqlite3_free(aIndex); - sqlite3_free(zCompress); - sqlite3_free(zUncompress); - sqlite3_free(zContent); - sqlite3_free(zLanguageid); - for(i=0; ipModule->xDestroy(pTokenizer); - } - }else{ - assert( p->pSegments==0 ); - *ppVTab = &p->base; + sqlite3Fts3ExprFree(pRet); + sqlite3Fts3ExprFree(pNotBranch); + pRet = 0; } + *ppExpr = pRet; return rc; } /* -** The xConnect() and xCreate() methods for the virtual table. All the -** work is done in function fts3InitVtab(). +** Return SQLITE_ERROR if the maximum depth of the expression tree passed +** as the only argument is more than nMaxDepth. */ -static int fts3ConnectMethod( - sqlite3 *db, /* Database connection */ - void *pAux, /* Pointer to tokenizer hash table */ - int argc, /* Number of elements in argv array */ - const char * const *argv, /* xCreate/xConnect argument array */ - sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ - char **pzErr /* OUT: sqlite3_malloc'd error message */ -){ - return fts3InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr); -} -static int fts3CreateMethod( - sqlite3 *db, /* Database connection */ - void *pAux, /* Pointer to tokenizer hash table */ - int argc, /* Number of elements in argv array */ - const char * const *argv, /* xCreate/xConnect argument array */ - sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ - char **pzErr /* OUT: sqlite3_malloc'd error message */ -){ - return fts3InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); +static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){ + int rc = SQLITE_OK; + if( p ){ + if( nMaxDepth<0 ){ + rc = SQLITE_TOOBIG; + }else{ + rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1); + if( rc==SQLITE_OK ){ + rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1); + } + } + } + return rc; } /* -** Set the pIdxInfo->estimatedRows variable to nRow. Unless this -** extension is currently being used by a version of SQLite too old to -** support estimatedRows. In that case this function is a no-op. +** This function attempts to transform the expression tree at (*pp) to +** an equivalent but more balanced form. The tree is modified in place. +** If successful, SQLITE_OK is returned and (*pp) set to point to the +** new root expression node. +** +** nMaxDepth is the maximum allowable depth of the balanced sub-tree. +** +** Otherwise, if an error occurs, an SQLite error code is returned and +** expression (*pp) freed. */ -static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ -#if SQLITE_VERSION_NUMBER>=3008002 - if( sqlite3_libversion_number()>=3008002 ){ - pIdxInfo->estimatedRows = nRow; +static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ + int rc = SQLITE_OK; /* Return code */ + Fts3Expr *pRoot = *pp; /* Initial root node */ + Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */ + int eType = pRoot->eType; /* Type of node in this tree */ + + if( nMaxDepth==0 ){ + rc = SQLITE_ERROR; } -#endif -} -/* -** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this -** extension is currently being used by a version of SQLite too old to -** support index-info flags. In that case this function is a no-op. -*/ -static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){ -#if SQLITE_VERSION_NUMBER>=3008012 - if( sqlite3_libversion_number()>=3008012 ){ - pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; - } -#endif -} + if( rc==SQLITE_OK ){ + if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ + Fts3Expr **apLeaf; + apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth); + if( 0==apLeaf ){ + rc = SQLITE_NOMEM; + }else{ + memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); + } + + if( rc==SQLITE_OK ){ + int i; + Fts3Expr *p; + + /* Set $p to point to the left-most leaf in the tree of eType nodes. */ + for(p=pRoot; p->eType==eType; p=p->pLeft){ + assert( p->pParent==0 || p->pParent->pLeft==p ); + assert( p->pLeft && p->pRight ); + } + + /* This loop runs once for each leaf in the tree of eType nodes. */ + while( 1 ){ + int iLvl; + Fts3Expr *pParent = p->pParent; /* Current parent of p */ + + assert( pParent==0 || pParent->pLeft==p ); + p->pParent = 0; + if( pParent ){ + pParent->pLeft = 0; + }else{ + pRoot = 0; + } + rc = fts3ExprBalance(&p, nMaxDepth-1); + if( rc!=SQLITE_OK ) break; -/* -** Implementation of the xBestIndex method for FTS3 tables. There -** are three possible strategies, in order of preference: -** -** 1. Direct lookup by rowid or docid. -** 2. Full-text search using a MATCH operator on a non-docid column. -** 3. Linear scan of %_content table. -*/ -static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ - Fts3Table *p = (Fts3Table *)pVTab; - int i; /* Iterator variable */ - int iCons = -1; /* Index of constraint to use */ + for(iLvl=0; p && iLvlpLeft = apLeaf[iLvl]; + pFree->pRight = p; + pFree->pLeft->pParent = pFree; + pFree->pRight->pParent = pFree; - int iLangidCons = -1; /* Index of langid=x constraint, if present */ - int iDocidGe = -1; /* Index of docid>=x constraint, if present */ - int iDocidLe = -1; /* Index of docid<=x constraint, if present */ - int iIdx; + p = pFree; + pFree = pFree->pParent; + p->pParent = 0; + apLeaf[iLvl] = 0; + } + } + if( p ){ + sqlite3Fts3ExprFree(p); + rc = SQLITE_TOOBIG; + break; + } - /* By default use a full table scan. This is an expensive option, - ** so search through the constraints to see if a more efficient - ** strategy is possible. - */ - pInfo->idxNum = FTS3_FULLSCAN_SEARCH; - pInfo->estimatedCost = 5000000; - for(i=0; inConstraint; i++){ - int bDocid; /* True if this constraint is on docid */ - struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; - if( pCons->usable==0 ){ - if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ - /* There exists an unusable MATCH constraint. This means that if - ** the planner does elect to use the results of this call as part - ** of the overall query plan the user will see an "unable to use - ** function MATCH in the requested context" error. To discourage - ** this, return a very high cost here. */ - pInfo->idxNum = FTS3_FULLSCAN_SEARCH; - pInfo->estimatedCost = 1e50; - fts3SetEstimatedRows(pInfo, ((sqlite3_int64)1) << 50); - return SQLITE_OK; - } - continue; - } + /* If that was the last leaf node, break out of the loop */ + if( pParent==0 ) break; - bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1); + /* Set $p to point to the next leaf in the tree of eType nodes */ + for(p=pParent->pRight; p->eType==eType; p=p->pLeft); - /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */ - if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){ - pInfo->idxNum = FTS3_DOCID_SEARCH; - pInfo->estimatedCost = 1.0; - iCons = i; - } + /* Remove pParent from the original tree. */ + assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); + pParent->pRight->pParent = pParent->pParent; + if( pParent->pParent ){ + pParent->pParent->pLeft = pParent->pRight; + }else{ + assert( pParent==pRoot ); + pRoot = pParent->pRight; + } - /* A MATCH constraint. Use a full-text search. - ** - ** If there is more than one MATCH constraint available, use the first - ** one encountered. If there is both a MATCH constraint and a direct - ** rowid/docid lookup, prefer the MATCH strategy. This is done even - ** though the rowid/docid lookup is faster than a MATCH query, selecting - ** it would lead to an "unable to use function MATCH in the requested - ** context" error. - */ - if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH - && pCons->iColumn>=0 && pCons->iColumn<=p->nColumn - ){ - pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn; - pInfo->estimatedCost = 2.0; - iCons = i; - } + /* Link pParent into the free node list. It will be used as an + ** internal node of the new tree. */ + pParent->pParent = pFree; + pFree = pParent; + } - /* Equality constraint on the langid column */ - if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ - && pCons->iColumn==p->nColumn + 2 - ){ - iLangidCons = i; - } + if( rc==SQLITE_OK ){ + p = 0; + for(i=0; ipParent = 0; + }else{ + assert( pFree!=0 ); + pFree->pRight = p; + pFree->pLeft = apLeaf[i]; + pFree->pLeft->pParent = pFree; + pFree->pRight->pParent = pFree; - if( bDocid ){ - switch( pCons->op ){ - case SQLITE_INDEX_CONSTRAINT_GE: - case SQLITE_INDEX_CONSTRAINT_GT: - iDocidGe = i; - break; + p = pFree; + pFree = pFree->pParent; + p->pParent = 0; + } + } + } + pRoot = p; + }else{ + /* An error occurred. Delete the contents of the apLeaf[] array + ** and pFree list. Everything else is cleaned up by the call to + ** sqlite3Fts3ExprFree(pRoot) below. */ + Fts3Expr *pDel; + for(i=0; ipParent; + sqlite3_free(pDel); + } + } - case SQLITE_INDEX_CONSTRAINT_LE: - case SQLITE_INDEX_CONSTRAINT_LT: - iDocidLe = i; - break; + assert( pFree==0 ); + sqlite3_free( apLeaf ); } - } - } + }else if( eType==FTSQUERY_NOT ){ + Fts3Expr *pLeft = pRoot->pLeft; + Fts3Expr *pRight = pRoot->pRight; - /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */ - if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo); + pRoot->pLeft = 0; + pRoot->pRight = 0; + pLeft->pParent = 0; + pRight->pParent = 0; - iIdx = 1; - if( iCons>=0 ){ - pInfo->aConstraintUsage[iCons].argvIndex = iIdx++; - pInfo->aConstraintUsage[iCons].omit = 1; - } - if( iLangidCons>=0 ){ - pInfo->idxNum |= FTS3_HAVE_LANGID; - pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++; - } - if( iDocidGe>=0 ){ - pInfo->idxNum |= FTS3_HAVE_DOCID_GE; - pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++; - } - if( iDocidLe>=0 ){ - pInfo->idxNum |= FTS3_HAVE_DOCID_LE; - pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++; - } + rc = fts3ExprBalance(&pLeft, nMaxDepth-1); + if( rc==SQLITE_OK ){ + rc = fts3ExprBalance(&pRight, nMaxDepth-1); + } - /* Regardless of the strategy selected, FTS can deliver rows in rowid (or - ** docid) order. Both ascending and descending are possible. - */ - if( pInfo->nOrderBy==1 ){ - struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0]; - if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){ - if( pOrder->desc ){ - pInfo->idxStr = "DESC"; + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(pRight); + sqlite3Fts3ExprFree(pLeft); }else{ - pInfo->idxStr = "ASC"; + assert( pLeft && pRight ); + pRoot->pLeft = pLeft; + pLeft->pParent = pRoot; + pRoot->pRight = pRight; + pRight->pParent = pRoot; } - pInfo->orderByConsumed = 1; } } - assert( p->pSegments==0 ); - return SQLITE_OK; + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(pRoot); + pRoot = 0; + } + *pp = pRoot; + return rc; } /* -** Implementation of xOpen method. +** This function is similar to sqlite3Fts3ExprParse(), with the following +** differences: +** +** 1. It does not do expression rebalancing. +** 2. It does not check that the expression does not exceed the +** maximum allowable depth. +** 3. Even if it fails, *ppExpr may still be set to point to an +** expression tree. It should be deleted using sqlite3Fts3ExprFree() +** in this case. */ -static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ - sqlite3_vtab_cursor *pCsr; /* Allocated cursor */ +static int fts3ExprParseUnbalanced( + sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ + int iLangid, /* Language id for tokenizer */ + char **azCol, /* Array of column names for fts3 table */ + int bFts4, /* True to allow FTS4-only syntax */ + int nCol, /* Number of entries in azCol[] */ + int iDefaultCol, /* Default column to query */ + const char *z, int n, /* Text of MATCH query */ + Fts3Expr **ppExpr /* OUT: Parsed query structure */ +){ + int nParsed; + int rc; + ParseContext sParse; - UNUSED_PARAMETER(pVTab); + memset(&sParse, 0, sizeof(ParseContext)); + sParse.pTokenizer = pTokenizer; + sParse.iLangid = iLangid; + sParse.azCol = (const char **)azCol; + sParse.nCol = nCol; + sParse.iDefaultCol = iDefaultCol; + sParse.bFts4 = bFts4; + if( z==0 ){ + *ppExpr = 0; + return SQLITE_OK; + } + if( n<0 ){ + n = (int)strlen(z); + } + rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); + assert( rc==SQLITE_OK || *ppExpr==0 ); - /* Allocate a buffer large enough for an Fts3Cursor structure. If the - ** allocation succeeds, zero it and return SQLITE_OK. Otherwise, - ** if the allocation fails, return SQLITE_NOMEM. - */ - *ppCsr = pCsr = (sqlite3_vtab_cursor *)sqlite3_malloc(sizeof(Fts3Cursor)); - if( !pCsr ){ - return SQLITE_NOMEM; + /* Check for mismatched parenthesis */ + if( rc==SQLITE_OK && sParse.nNest ){ + rc = SQLITE_ERROR; } - memset(pCsr, 0, sizeof(Fts3Cursor)); - return SQLITE_OK; + + return rc; } /* -** Finalize the statement handle at pCsr->pStmt. +** Parameters z and n contain a pointer to and length of a buffer containing +** an fts3 query expression, respectively. This function attempts to parse the +** query expression and create a tree of Fts3Expr structures representing the +** parsed expression. If successful, *ppExpr is set to point to the head +** of the parsed expression tree and SQLITE_OK is returned. If an error +** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse +** error) is returned and *ppExpr is set to 0. ** -** Or, if that statement handle is one created by fts3CursorSeekStmt(), -** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement -** pointer there instead of finalizing it. +** If parameter n is a negative number, then z is assumed to point to a +** nul-terminated string and the length is determined using strlen(). +** +** The first parameter, pTokenizer, is passed the fts3 tokenizer module to +** use to normalize query tokens while parsing the expression. The azCol[] +** array, which is assumed to contain nCol entries, should contain the names +** of each column in the target fts3 table, in order from left to right. +** Column names must be nul-terminated strings. +** +** The iDefaultCol parameter should be passed the index of the table column +** that appears on the left-hand-side of the MATCH operator (the default +** column to match against for tokens for which a column name is not explicitly +** specified as part of the query string), or -1 if tokens may by default +** match any table column. */ -static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){ - if( pCsr->bSeekStmt ){ - Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; - if( p->pSeekStmt==0 ){ - p->pSeekStmt = pCsr->pStmt; - sqlite3_reset(pCsr->pStmt); - pCsr->pStmt = 0; +SQLITE_PRIVATE int sqlite3Fts3ExprParse( + sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ + int iLangid, /* Language id for tokenizer */ + char **azCol, /* Array of column names for fts3 table */ + int bFts4, /* True to allow FTS4-only syntax */ + int nCol, /* Number of entries in azCol[] */ + int iDefaultCol, /* Default column to query */ + const char *z, int n, /* Text of MATCH query */ + Fts3Expr **ppExpr, /* OUT: Parsed query structure */ + char **pzErr /* OUT: Error message (sqlite3_malloc) */ +){ + int rc = fts3ExprParseUnbalanced( + pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr + ); + + /* Rebalance the expression. And check that its depth does not exceed + ** SQLITE_FTS3_MAX_EXPR_DEPTH. */ + if( rc==SQLITE_OK && *ppExpr ){ + rc = fts3ExprBalance(ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); + if( rc==SQLITE_OK ){ + rc = fts3ExprCheckDepth(*ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); } - pCsr->bSeekStmt = 0; } - sqlite3_finalize(pCsr->pStmt); + + if( rc!=SQLITE_OK ){ + sqlite3Fts3ExprFree(*ppExpr); + *ppExpr = 0; + if( rc==SQLITE_TOOBIG ){ + sqlite3Fts3ErrMsg(pzErr, + "FTS expression tree is too large (maximum depth %d)", + SQLITE_FTS3_MAX_EXPR_DEPTH + ); + rc = SQLITE_ERROR; + }else if( rc==SQLITE_ERROR ){ + sqlite3Fts3ErrMsg(pzErr, "malformed MATCH expression: [%s]", z); + } + } + + return rc; } /* -** Close the cursor. For additional information see the documentation -** on the xClose method of the virtual table interface. +** Free a single node of an expression tree. */ -static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ - Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; - assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); - fts3CursorFinalizeStmt(pCsr); - sqlite3Fts3ExprFree(pCsr->pExpr); - sqlite3Fts3FreeDeferredTokens(pCsr); - sqlite3_free(pCsr->aDoclist); - sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); - assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); - sqlite3_free(pCsr); - return SQLITE_OK; +static void fts3FreeExprNode(Fts3Expr *p){ + assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); + sqlite3Fts3EvalPhraseCleanup(p->pPhrase); + sqlite3_free(p->aMI); + sqlite3_free(p); } /* -** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then -** compose and prepare an SQL statement of the form: -** -** "SELECT FROM %_content WHERE rowid = ?" +** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). ** -** (or the equivalent for a content=xxx table) and set pCsr->pStmt to -** it. If an error occurs, return an SQLite error code. +** This function would be simpler if it recursively called itself. But +** that would mean passing a sufficiently large expression to ExprParse() +** could cause a stack overflow. */ -static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ - int rc = SQLITE_OK; - if( pCsr->pStmt==0 ){ - Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; - char *zSql; - if( p->pSeekStmt ){ - pCsr->pStmt = p->pSeekStmt; - p->pSeekStmt = 0; +SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){ + Fts3Expr *p; + assert( pDel==0 || pDel->pParent==0 ); + for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){ + assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft ); + } + while( p ){ + Fts3Expr *pParent = p->pParent; + fts3FreeExprNode(p); + if( pParent && p==pParent->pLeft && pParent->pRight ){ + p = pParent->pRight; + while( p && (p->pLeft || p->pRight) ){ + assert( p==p->pParent->pRight || p==p->pParent->pLeft ); + p = (p->pLeft ? p->pLeft : p->pRight); + } }else{ - zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); - if( !zSql ) return SQLITE_NOMEM; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); - sqlite3_free(zSql); + p = pParent; } - if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1; } - return rc; } +/**************************************************************************** +***************************************************************************** +** Everything after this point is just test code. +*/ + +#ifdef SQLITE_TEST + +/* #include */ + /* -** Position the pCsr->pStmt statement so that it is on the row -** of the %_content table that contains the last match. Return -** SQLITE_OK on success. +** Return a pointer to a buffer containing a text representation of the +** expression passed as the first argument. The buffer is obtained from +** sqlite3_malloc(). It is the responsibility of the caller to use +** sqlite3_free() to release the memory. If an OOM condition is encountered, +** NULL is returned. +** +** If the second argument is not NULL, then its contents are prepended to +** the returned expression text and then freed using sqlite3_free(). */ -static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ - int rc = SQLITE_OK; - if( pCsr->isRequireSeek ){ - rc = fts3CursorSeekStmt(pCsr); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); - pCsr->isRequireSeek = 0; - if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ - return SQLITE_OK; - }else{ - rc = sqlite3_reset(pCsr->pStmt); - if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ - /* If no row was found and no error has occurred, then the %_content - ** table is missing a row that is present in the full-text index. - ** The data structures are corrupt. */ - rc = FTS_CORRUPT_VTAB; - pCsr->isEof = 1; - } +static char *exprToString(Fts3Expr *pExpr, char *zBuf){ + if( pExpr==0 ){ + return sqlite3_mprintf(""); + } + switch( pExpr->eType ){ + case FTSQUERY_PHRASE: { + Fts3Phrase *pPhrase = pExpr->pPhrase; + int i; + zBuf = sqlite3_mprintf( + "%zPHRASE %d 0", zBuf, pPhrase->iColumn); + for(i=0; zBuf && inToken; i++){ + zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, + pPhrase->aToken[i].n, pPhrase->aToken[i].z, + (pPhrase->aToken[i].isPrefix?"+":"") + ); } + return zBuf; } - } - if( rc!=SQLITE_OK && pContext ){ - sqlite3_result_error_code(pContext, rc); + case FTSQUERY_NEAR: + zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear); + break; + case FTSQUERY_NOT: + zBuf = sqlite3_mprintf("%zNOT ", zBuf); + break; + case FTSQUERY_AND: + zBuf = sqlite3_mprintf("%zAND ", zBuf); + break; + case FTSQUERY_OR: + zBuf = sqlite3_mprintf("%zOR ", zBuf); + break; } - return rc; + + if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf); + if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf); + if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf); + + if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf); + if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf); + + return zBuf; } /* -** This function is used to process a single interior node when searching -** a b-tree for a term or term prefix. The node data is passed to this -** function via the zNode/nNode parameters. The term to search for is -** passed in zTerm/nTerm. +** This is the implementation of a scalar SQL function used to test the +** expression parser. It should be called as follows: ** -** If piFirst is not NULL, then this function sets *piFirst to the blockid -** of the child node that heads the sub-tree that may contain the term. +** fts3_exprtest(, , , ...); ** -** If piLast is not NULL, then *piLast is set to the right-most child node -** that heads a sub-tree that may contain a term for which zTerm/nTerm is -** a prefix. +** The first argument, , is the name of the fts3 tokenizer used +** to parse the query expression (see README.tokenizers). The second argument +** is the query expression to parse. Each subsequent argument is the name +** of a column of the fts3 table that the query expression may refer to. +** For example: ** -** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK. +** SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2'); */ -static int fts3ScanInteriorNode( - const char *zTerm, /* Term to select leaves for */ - int nTerm, /* Size of term zTerm in bytes */ - const char *zNode, /* Buffer containing segment interior node */ - int nNode, /* Size of buffer at zNode */ - sqlite3_int64 *piFirst, /* OUT: Selected child node */ - sqlite3_int64 *piLast /* OUT: Selected child node */ +static void fts3ExprTestCommon( + int bRebalance, + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - int rc = SQLITE_OK; /* Return code */ - const char *zCsr = zNode; /* Cursor to iterate through node */ - const char *zEnd = &zCsr[nNode];/* End of interior node buffer */ - char *zBuffer = 0; /* Buffer to load terms into */ - int nAlloc = 0; /* Size of allocated buffer */ - int isFirstTerm = 1; /* True when processing first term on page */ - sqlite3_int64 iChild; /* Block id of child node to descend to */ + sqlite3_tokenizer *pTokenizer = 0; + int rc; + char **azCol = 0; + const char *zExpr; + int nExpr; + int nCol; + int ii; + Fts3Expr *pExpr; + char *zBuf = 0; + Fts3Hash *pHash = (Fts3Hash*)sqlite3_user_data(context); + const char *zTokenizer = 0; + char *zErr = 0; - /* Skip over the 'height' varint that occurs at the start of every - ** interior node. Then load the blockid of the left-child of the b-tree - ** node into variable iChild. - ** - ** Even if the data structure on disk is corrupted, this (reading two - ** varints from the buffer) does not risk an overread. If zNode is a - ** root node, then the buffer comes from a SELECT statement. SQLite does - ** not make this guarantee explicitly, but in practice there are always - ** either more than 20 bytes of allocated space following the nNode bytes of - ** contents, or two zero bytes. Or, if the node is read from the %_segments - ** table, then there are always 20 bytes of zeroed padding following the - ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). - */ - zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); - zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); - if( zCsr>zEnd ){ - return FTS_CORRUPT_VTAB; + if( argc<3 ){ + sqlite3_result_error(context, + "Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1 + ); + return; } - - while( zCsrzEnd ){ - rc = FTS_CORRUPT_VTAB; - goto finish_scan; - } - if( nPrefix+nSuffix>nAlloc ){ - char *zNew; - nAlloc = (nPrefix+nSuffix) * 2; - zNew = (char *)sqlite3_realloc(zBuffer, nAlloc); - if( !zNew ){ - rc = SQLITE_NOMEM; - goto finish_scan; - } - zBuffer = zNew; - } - assert( zBuffer ); - memcpy(&zBuffer[nPrefix], zCsr, nSuffix); - nBuffer = nPrefix + nSuffix; - zCsr += nSuffix; - /* Compare the term we are searching for with the term just loaded from - ** the interior node. If the specified term is greater than or equal - ** to the term from the interior node, then all terms on the sub-tree - ** headed by node iChild are smaller than zTerm. No need to search - ** iChild. - ** - ** If the interior node term is larger than the specified term, then - ** the tree headed by iChild may contain the specified term. - */ - cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); - if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ - *piFirst = iChild; - piFirst = 0; + zTokenizer = (const char*)sqlite3_value_text(argv[0]); + rc = sqlite3Fts3InitTokenizer(pHash, zTokenizer, &pTokenizer, &zErr); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_error(context, zErr, -1); } + sqlite3_free(zErr); + return; + } - if( piLast && cmp<0 ){ - *piLast = iChild; - piLast = 0; - } + zExpr = (const char *)sqlite3_value_text(argv[1]); + nExpr = sqlite3_value_bytes(argv[1]); + nCol = argc-2; + azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *)); + if( !azCol ){ + sqlite3_result_error_nomem(context); + goto exprtest_out; + } + for(ii=0; iipModule->xDestroy(pTokenizer); + } + sqlite3_free(azCol); +} + +static void fts3ExprTest( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + fts3ExprTestCommon(0, context, argc, argv); +} +static void fts3ExprTestRebalance( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + fts3ExprTestCommon(1, context, argc, argv); +} + +/* +** Register the query expression parser test function fts3_exprtest() +** with database connection db. +*/ +SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash *pHash){ + int rc = sqlite3_create_function( + db, "fts3_exprtest", -1, SQLITE_UTF8, (void*)pHash, fts3ExprTest, 0, 0 + ); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "fts3_exprtest_rebalance", + -1, SQLITE_UTF8, (void*)pHash, fts3ExprTestRebalance, 0, 0 + ); + } return rc; } +#endif +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ +/************** End of fts3_expr.c *******************************************/ +/************** Begin file fts3_hash.c ***************************************/ /* -** The buffer pointed to by argument zNode (size nNode bytes) contains an -** interior node of a b-tree segment. The zTerm buffer (size nTerm bytes) -** contains a term. This function searches the sub-tree headed by the zNode -** node for the range of leaf nodes that may contain the specified term -** or terms for which the specified term is a prefix. +** 2001 September 22 ** -** If piLeaf is not NULL, then *piLeaf is set to the blockid of the -** left-most leaf node in the tree that may contain the specified term. -** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the -** right-most leaf node that may contain a term for which the specified -** term is a prefix. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** It is possible that the range of returned leaf nodes does not contain -** the specified term or any terms for which it is a prefix. However, if the -** segment does contain any such terms, they are stored within the identified -** range. Because this function only inspects interior segment nodes (and -** never loads leaf nodes into memory), it is not possible to be sure. +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. ** -** If an error occurs, an error code other than SQLITE_OK is returned. -*/ -static int fts3SelectLeaf( - Fts3Table *p, /* Virtual table handle */ - const char *zTerm, /* Term to select leaves for */ - int nTerm, /* Size of term zTerm in bytes */ - const char *zNode, /* Buffer containing segment interior node */ - int nNode, /* Size of buffer at zNode */ - sqlite3_int64 *piLeaf, /* Selected leaf node */ - sqlite3_int64 *piLeaf2 /* Selected leaf node */ -){ - int rc = SQLITE_OK; /* Return code */ - int iHeight; /* Height of this node in tree */ - - assert( piLeaf || piLeaf2 ); +************************************************************************* +** This is the implementation of generic hash-tables used in SQLite. +** We've modified it slightly to serve as a standalone hash table +** implementation for the full-text indexing module. +*/ - fts3GetVarint32(zNode, &iHeight); - rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2); - assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) ); +/* +** The code in this file is only compiled if: +** +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +*/ +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - if( rc==SQLITE_OK && iHeight>1 ){ - char *zBlob = 0; /* Blob read from %_segments table */ - int nBlob = 0; /* Size of zBlob in bytes */ +/* #include */ +/* #include */ +/* #include */ - if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){ - rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0); - if( rc==SQLITE_OK ){ - rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0); - } - sqlite3_free(zBlob); - piLeaf = 0; - zBlob = 0; - } +/* #include "fts3_hash.h" */ - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0); - } - if( rc==SQLITE_OK ){ - rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2); - } - sqlite3_free(zBlob); +/* +** Malloc and Free functions +*/ +static void *fts3HashMalloc(sqlite3_int64 n){ + void *p = sqlite3_malloc64(n); + if( p ){ + memset(p, 0, n); } + return p; +} +static void fts3HashFree(void *p){ + sqlite3_free(p); +} - return rc; +/* Turn bulk memory into a hash table object by initializing the +** fields of the Hash structure. +** +** "pNew" is a pointer to the hash table that is to be initialized. +** keyClass is one of the constants +** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass +** determines what kind of key the hash table will use. "copyKey" is +** true if the hash table should make its own private copy of keys and +** false if it should just use the supplied pointer. +*/ +SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey){ + assert( pNew!=0 ); + assert( keyClass>=FTS3_HASH_STRING && keyClass<=FTS3_HASH_BINARY ); + pNew->keyClass = keyClass; + pNew->copyKey = copyKey; + pNew->first = 0; + pNew->count = 0; + pNew->htsize = 0; + pNew->ht = 0; } -/* -** This function is used to create delta-encoded serialized lists of FTS3 -** varints. Each call to this function appends a single varint to a list. +/* Remove all entries from a hash table. Reclaim all memory. +** Call this routine to delete a hash table or to reset a hash table +** to the empty state. */ -static void fts3PutDeltaVarint( - char **pp, /* IN/OUT: Output pointer */ - sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ - sqlite3_int64 iVal /* Write this value to the list */ -){ - assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); - *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); - *piPrev = iVal; +SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash *pH){ + Fts3HashElem *elem; /* For looping over all elements of the table */ + + assert( pH!=0 ); + elem = pH->first; + pH->first = 0; + fts3HashFree(pH->ht); + pH->ht = 0; + pH->htsize = 0; + while( elem ){ + Fts3HashElem *next_elem = elem->next; + if( pH->copyKey && elem->pKey ){ + fts3HashFree(elem->pKey); + } + fts3HashFree(elem); + elem = next_elem; + } + pH->count = 0; } /* -** When this function is called, *ppPoslist is assumed to point to the -** start of a position-list. After it returns, *ppPoslist points to the -** first byte after the position-list. -** -** A position list is list of positions (delta encoded) and columns for -** a single document record of a doclist. So, in other words, this -** routine advances *ppPoslist so that it points to the next docid in -** the doclist, or to the first byte past the end of the doclist. -** -** If pp is not NULL, then the contents of the position list are copied -** to *pp. *pp is set to point to the first byte past the last byte copied -** before this function returns. +** Hash and comparison functions when the mode is FTS3_HASH_STRING */ -static void fts3PoslistCopy(char **pp, char **ppPoslist){ - char *pEnd = *ppPoslist; - char c = 0; - - /* The end of a position list is marked by a zero encoded as an FTS3 - ** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by - ** a byte with the 0x80 bit set, then it is not a varint 0, but the tail - ** of some other, multi-byte, value. - ** - ** The following while-loop moves pEnd to point to the first byte that is not - ** immediately preceded by a byte with the 0x80 bit set. Then increments - ** pEnd once more so that it points to the byte immediately following the - ** last byte in the position-list. - */ - while( *pEnd | c ){ - c = *pEnd++ & 0x80; - testcase( c!=0 && (*pEnd)==0 ); +static int fts3StrHash(const void *pKey, int nKey){ + const char *z = (const char *)pKey; + unsigned h = 0; + if( nKey<=0 ) nKey = (int) strlen(z); + while( nKey > 0 ){ + h = (h<<3) ^ h ^ *z++; + nKey--; } - pEnd++; /* Advance past the POS_END terminator byte */ + return (int)(h & 0x7fffffff); +} +static int fts3StrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ + if( n1!=n2 ) return 1; + return strncmp((const char*)pKey1,(const char*)pKey2,n1); +} - if( pp ){ - int n = (int)(pEnd - *ppPoslist); - char *p = *pp; - memcpy(p, *ppPoslist, n); - p += n; - *pp = p; +/* +** Hash and comparison functions when the mode is FTS3_HASH_BINARY +*/ +static int fts3BinHash(const void *pKey, int nKey){ + int h = 0; + const char *z = (const char *)pKey; + while( nKey-- > 0 ){ + h = (h<<3) ^ h ^ *(z++); } - *ppPoslist = pEnd; + return h & 0x7fffffff; +} +static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){ + if( n1!=n2 ) return 1; + return memcmp(pKey1,pKey2,n1); } /* -** When this function is called, *ppPoslist is assumed to point to the -** start of a column-list. After it returns, *ppPoslist points to the -** to the terminator (POS_COLUMN or POS_END) byte of the column-list. -** -** A column-list is list of delta-encoded positions for a single column -** within a single document within a doclist. +** Return a pointer to the appropriate hash function given the key class. ** -** The column-list is terminated either by a POS_COLUMN varint (1) or -** a POS_END varint (0). This routine leaves *ppPoslist pointing to -** the POS_COLUMN or POS_END that terminates the column-list. +** The C syntax in this function definition may be unfamilar to some +** programmers, so we provide the following additional explanation: ** -** If pp is not NULL, then the contents of the column-list are copied -** to *pp. *pp is set to point to the first byte past the last byte copied -** before this function returns. The POS_COLUMN or POS_END terminator -** is not copied into *pp. +** The name of the function is "ftsHashFunction". The function takes a +** single parameter "keyClass". The return value of ftsHashFunction() +** is a pointer to another function. Specifically, the return value +** of ftsHashFunction() is a pointer to a function that takes two parameters +** with types "const void*" and "int" and returns an "int". */ -static void fts3ColumnlistCopy(char **pp, char **ppPoslist){ - char *pEnd = *ppPoslist; - char c = 0; - - /* A column-list is terminated by either a 0x01 or 0x00 byte that is - ** not part of a multi-byte varint. - */ - while( 0xFE & (*pEnd | c) ){ - c = *pEnd++ & 0x80; - testcase( c!=0 && ((*pEnd)&0xfe)==0 ); - } - if( pp ){ - int n = (int)(pEnd - *ppPoslist); - char *p = *pp; - memcpy(p, *ppPoslist, n); - p += n; - *pp = p; +static int (*ftsHashFunction(int keyClass))(const void*,int){ + if( keyClass==FTS3_HASH_STRING ){ + return &fts3StrHash; + }else{ + assert( keyClass==FTS3_HASH_BINARY ); + return &fts3BinHash; } - *ppPoslist = pEnd; } /* -** Value used to signify the end of an position-list. This is safe because -** it is not possible to have a document with 2^31 terms. +** Return a pointer to the appropriate hash function given the key class. +** +** For help in interpreted the obscure C code in the function definition, +** see the header comment on the previous function. */ -#define POSITION_LIST_END 0x7fffffff +static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){ + if( keyClass==FTS3_HASH_STRING ){ + return &fts3StrCompare; + }else{ + assert( keyClass==FTS3_HASH_BINARY ); + return &fts3BinCompare; + } +} -/* -** This function is used to help parse position-lists. When this function is -** called, *pp may point to the start of the next varint in the position-list -** being parsed, or it may point to 1 byte past the end of the position-list -** (in which case **pp will be a terminator bytes POS_END (0) or -** (1)). -** -** If *pp points past the end of the current position-list, set *pi to -** POSITION_LIST_END and return. Otherwise, read the next varint from *pp, -** increment the current value of *pi by the value read, and set *pp to -** point to the next value before returning. -** -** Before calling this routine *pi must be initialized to the value of -** the previous position, or zero if we are reading the first position -** in the position-list. Because positions are delta-encoded, the value -** of the previous position is needed in order to compute the value of -** the next position. +/* Link an element into the hash table */ -static void fts3ReadNextPos( - char **pp, /* IN/OUT: Pointer into position-list buffer */ - sqlite3_int64 *pi /* IN/OUT: Value read from position-list */ +static void fts3HashInsertElement( + Fts3Hash *pH, /* The complete hash table */ + struct _fts3ht *pEntry, /* The entry into which pNew is inserted */ + Fts3HashElem *pNew /* The element to be inserted */ ){ - if( (**pp)&0xFE ){ - fts3GetDeltaVarint(pp, pi); - *pi -= 2; + Fts3HashElem *pHead; /* First element already in pEntry */ + pHead = pEntry->chain; + if( pHead ){ + pNew->next = pHead; + pNew->prev = pHead->prev; + if( pHead->prev ){ pHead->prev->next = pNew; } + else { pH->first = pNew; } + pHead->prev = pNew; }else{ - *pi = POSITION_LIST_END; + pNew->next = pH->first; + if( pH->first ){ pH->first->prev = pNew; } + pNew->prev = 0; + pH->first = pNew; } + pEntry->count++; + pEntry->chain = pNew; } -/* -** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by -** the value of iCol encoded as a varint to *pp. This will start a new -** column list. + +/* Resize the hash table so that it cantains "new_size" buckets. +** "new_size" must be a power of 2. The hash table might fail +** to resize if sqliteMalloc() fails. ** -** Set *pp to point to the byte just after the last byte written before -** returning (do not modify it if iCol==0). Return the total number of bytes -** written (0 if iCol==0). +** Return non-zero if a memory allocation error occurs. */ -static int fts3PutColNumber(char **pp, int iCol){ - int n = 0; /* Number of bytes written */ - if( iCol ){ - char *p = *pp; /* Output pointer */ - n = 1 + sqlite3Fts3PutVarint(&p[1], iCol); - *p = 0x01; - *pp = &p[n]; +static int fts3Rehash(Fts3Hash *pH, int new_size){ + struct _fts3ht *new_ht; /* The new hash table */ + Fts3HashElem *elem, *next_elem; /* For looping over existing elements */ + int (*xHash)(const void*,int); /* The hash function */ + + assert( (new_size & (new_size-1))==0 ); + new_ht = (struct _fts3ht *)fts3HashMalloc( new_size*sizeof(struct _fts3ht) ); + if( new_ht==0 ) return 1; + fts3HashFree(pH->ht); + pH->ht = new_ht; + pH->htsize = new_size; + xHash = ftsHashFunction(pH->keyClass); + for(elem=pH->first, pH->first=0; elem; elem = next_elem){ + int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); + next_elem = elem->next; + fts3HashInsertElement(pH, &new_ht[h], elem); + } + return 0; +} + +/* This function (for internal use only) locates an element in an +** hash table that matches the given key. The hash for this key has +** already been computed and is passed as the 4th parameter. +*/ +static Fts3HashElem *fts3FindElementByHash( + const Fts3Hash *pH, /* The pH to be searched */ + const void *pKey, /* The key we are searching for */ + int nKey, + int h /* The hash for this key. */ +){ + Fts3HashElem *elem; /* Used to loop thru the element list */ + int count; /* Number of elements left to test */ + int (*xCompare)(const void*,int,const void*,int); /* comparison function */ + + if( pH->ht ){ + struct _fts3ht *pEntry = &pH->ht[h]; + elem = pEntry->chain; + count = pEntry->count; + xCompare = ftsCompareFunction(pH->keyClass); + while( count-- && elem ){ + if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ + return elem; + } + elem = elem->next; + } + } + return 0; +} + +/* Remove a single entry from the hash table given a pointer to that +** element and a hash on the element's key. +*/ +static void fts3RemoveElementByHash( + Fts3Hash *pH, /* The pH containing "elem" */ + Fts3HashElem* elem, /* The element to be removed from the pH */ + int h /* Hash value for the element */ +){ + struct _fts3ht *pEntry; + if( elem->prev ){ + elem->prev->next = elem->next; + }else{ + pH->first = elem->next; + } + if( elem->next ){ + elem->next->prev = elem->prev; + } + pEntry = &pH->ht[h]; + if( pEntry->chain==elem ){ + pEntry->chain = elem->next; + } + pEntry->count--; + if( pEntry->count<=0 ){ + pEntry->chain = 0; + } + if( pH->copyKey && elem->pKey ){ + fts3HashFree(elem->pKey); + } + fts3HashFree( elem ); + pH->count--; + if( pH->count<=0 ){ + assert( pH->first==0 ); + assert( pH->count==0 ); + fts3HashClear(pH); } - return n; } -/* -** Compute the union of two position lists. The output written -** into *pp contains all positions of both *pp1 and *pp2 in sorted -** order and with any duplicates removed. All pointers are -** updated appropriately. The caller is responsible for insuring -** that there is enough space in *pp to hold the complete output. -*/ -static void fts3PoslistMerge( - char **pp, /* Output buffer */ - char **pp1, /* Left input list */ - char **pp2 /* Right input list */ +SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem( + const Fts3Hash *pH, + const void *pKey, + int nKey ){ - char *p = *pp; - char *p1 = *pp1; - char *p2 = *pp2; + int h; /* A hash on key */ + int (*xHash)(const void*,int); /* The hash function */ - while( *p1 || *p2 ){ - int iCol1; /* The current column index in pp1 */ - int iCol2; /* The current column index in pp2 */ + if( pH==0 || pH->ht==0 ) return 0; + xHash = ftsHashFunction(pH->keyClass); + assert( xHash!=0 ); + h = (*xHash)(pKey,nKey); + assert( (pH->htsize & (pH->htsize-1))==0 ); + return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1)); +} - if( *p1==POS_COLUMN ) fts3GetVarint32(&p1[1], &iCol1); - else if( *p1==POS_END ) iCol1 = POSITION_LIST_END; - else iCol1 = 0; +/* +** Attempt to locate an element of the hash table pH with a key +** that matches pKey,nKey. Return the data for this element if it is +** found, or NULL if there is no match. +*/ +SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){ + Fts3HashElem *pElem; /* The element that matches key (if any) */ - if( *p2==POS_COLUMN ) fts3GetVarint32(&p2[1], &iCol2); - else if( *p2==POS_END ) iCol2 = POSITION_LIST_END; - else iCol2 = 0; + pElem = sqlite3Fts3HashFindElem(pH, pKey, nKey); + return pElem ? pElem->data : 0; +} - if( iCol1==iCol2 ){ - sqlite3_int64 i1 = 0; /* Last position from pp1 */ - sqlite3_int64 i2 = 0; /* Last position from pp2 */ - sqlite3_int64 iPrev = 0; - int n = fts3PutColNumber(&p, iCol1); - p1 += n; - p2 += n; +/* Insert an element into the hash table pH. The key is pKey,nKey +** and the data is "data". +** +** If no element exists with a matching key, then a new +** element is created. A copy of the key is made if the copyKey +** flag is set. NULL is returned. +** +** If another element already exists with the same key, then the +** new data replaces the old data and the old data is returned. +** The key is not copied in this instance. If a malloc fails, then +** the new data is returned and the hash table is unchanged. +** +** If the "data" parameter to this function is NULL, then the +** element corresponding to "key" is removed from the hash table. +*/ +SQLITE_PRIVATE void *sqlite3Fts3HashInsert( + Fts3Hash *pH, /* The hash table to insert into */ + const void *pKey, /* The key */ + int nKey, /* Number of bytes in the key */ + void *data /* The data */ +){ + int hraw; /* Raw hash value of the key */ + int h; /* the hash of the key modulo hash table size */ + Fts3HashElem *elem; /* Used to loop thru the element list */ + Fts3HashElem *new_elem; /* New element added to the pH */ + int (*xHash)(const void*,int); /* The hash function */ - /* At this point, both p1 and p2 point to the start of column-lists - ** for the same column (the column with index iCol1 and iCol2). - ** A column-list is a list of non-negative delta-encoded varints, each - ** incremented by 2 before being stored. Each list is terminated by a - ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists - ** and writes the results to buffer p. p is left pointing to the byte - ** after the list written. No terminator (POS_END or POS_COLUMN) is - ** written to the output. - */ - fts3GetDeltaVarint(&p1, &i1); - fts3GetDeltaVarint(&p2, &i2); - do { - fts3PutDeltaVarint(&p, &iPrev, (i1keyClass); + assert( xHash!=0 ); + hraw = (*xHash)(pKey, nKey); + assert( (pH->htsize & (pH->htsize-1))==0 ); + h = hraw & (pH->htsize-1); + elem = fts3FindElementByHash(pH,pKey,nKey,h); + if( elem ){ + void *old_data = elem->data; + if( data==0 ){ + fts3RemoveElementByHash(pH,elem,h); }else{ - p2 += fts3PutColNumber(&p, iCol2); - fts3ColumnlistCopy(&p, &p2); + elem->data = data; } + return old_data; } - - *p++ = POS_END; - *pp = p; - *pp1 = p1 + 1; - *pp2 = p2 + 1; + if( data==0 ) return 0; + if( (pH->htsize==0 && fts3Rehash(pH,8)) + || (pH->count>=pH->htsize && fts3Rehash(pH, pH->htsize*2)) + ){ + pH->count = 0; + return data; + } + assert( pH->htsize>0 ); + new_elem = (Fts3HashElem*)fts3HashMalloc( sizeof(Fts3HashElem) ); + if( new_elem==0 ) return data; + if( pH->copyKey && pKey!=0 ){ + new_elem->pKey = fts3HashMalloc( nKey ); + if( new_elem->pKey==0 ){ + fts3HashFree(new_elem); + return data; + } + memcpy((void*)new_elem->pKey, pKey, nKey); + }else{ + new_elem->pKey = (void*)pKey; + } + new_elem->nKey = nKey; + pH->count++; + assert( pH->htsize>0 ); + assert( (pH->htsize & (pH->htsize-1))==0 ); + h = hraw & (pH->htsize-1); + fts3HashInsertElement(pH, &pH->ht[h], new_elem); + new_elem->data = data; + return 0; } +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_hash.c *******************************************/ +/************** Begin file fts3_porter.c *************************************/ /* -** This function is used to merge two position lists into one. When it is -** called, *pp1 and *pp2 must both point to position lists. A position-list is -** the part of a doclist that follows each document id. For example, if a row -** contains: -** -** 'a b c'|'x y z'|'a b b a' +** 2006 September 30 ** -** Then the position list for this row for token 'b' would consist of: +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** 0x02 0x01 0x02 0x03 0x03 0x00 +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. ** -** When this function returns, both *pp1 and *pp2 are left pointing to the -** byte following the 0x00 terminator of their respective position lists. +************************************************************************* +** Implementation of the full-text-search tokenizer that implements +** a Porter stemmer. +*/ + +/* +** The code in this file is only compiled if: ** -** If isSaveLeft is 0, an entry is added to the output position list for -** each position in *pp2 for which there exists one or more positions in -** *pp1 so that (pos(*pp2)>pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e. -** when the *pp1 token appears before the *pp2 token, but not more than nToken -** slots before it. +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or ** -** e.g. nToken==1 searches for adjacent positions. +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ -static int fts3PoslistPhraseMerge( - char **pp, /* IN/OUT: Preallocated output buffer */ - int nToken, /* Maximum difference in token positions */ - int isSaveLeft, /* Save the left position */ - int isExact, /* If *pp1 is exactly nTokens before *pp2 */ - char **pp1, /* IN/OUT: Left input list */ - char **pp2 /* IN/OUT: Right input list */ -){ - char *p = *pp; - char *p1 = *pp1; - char *p2 = *pp2; - int iCol1 = 0; - int iCol2 = 0; - - /* Never set both isSaveLeft and isExact for the same invocation. */ - assert( isSaveLeft==0 || isExact==0 ); - - assert( p!=0 && *p1!=0 && *p2!=0 ); - if( *p1==POS_COLUMN ){ - p1++; - p1 += fts3GetVarint32(p1, &iCol1); - } - if( *p2==POS_COLUMN ){ - p2++; - p2 += fts3GetVarint32(p2, &iCol2); - } +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - while( 1 ){ - if( iCol1==iCol2 ){ - char *pSave = p; - sqlite3_int64 iPrev = 0; - sqlite3_int64 iPos1 = 0; - sqlite3_int64 iPos2 = 0; +/* #include */ +/* #include */ +/* #include */ +/* #include */ - if( iCol1 ){ - *p++ = POS_COLUMN; - p += sqlite3Fts3PutVarint(p, iCol1); - } +/* #include "fts3_tokenizer.h" */ - assert( *p1!=POS_END && *p1!=POS_COLUMN ); - assert( *p2!=POS_END && *p2!=POS_COLUMN ); - fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; - fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; +/* +** Class derived from sqlite3_tokenizer +*/ +typedef struct porter_tokenizer { + sqlite3_tokenizer base; /* Base class */ +} porter_tokenizer; - while( 1 ){ - if( iPos2==iPos1+nToken - || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) - ){ - sqlite3_int64 iSave; - iSave = isSaveLeft ? iPos1 : iPos2; - fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; - pSave = 0; - assert( p ); - } - if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ - if( (*p2&0xFE)==0 ) break; - fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; - }else{ - if( (*p1&0xFE)==0 ) break; - fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2; - } - } +/* +** Class derived from sqlite3_tokenizer_cursor +*/ +typedef struct porter_tokenizer_cursor { + sqlite3_tokenizer_cursor base; + const char *zInput; /* input we are tokenizing */ + int nInput; /* size of the input */ + int iOffset; /* current position in zInput */ + int iToken; /* index of next token to be returned */ + char *zToken; /* storage for current token */ + int nAllocated; /* space allocated to zToken buffer */ +} porter_tokenizer_cursor; - if( pSave ){ - assert( pp && p ); - p = pSave; - } - fts3ColumnlistCopy(0, &p1); - fts3ColumnlistCopy(0, &p2); - assert( (*p1&0xFE)==0 && (*p2&0xFE)==0 ); - if( 0==*p1 || 0==*p2 ) break; +/* +** Create a new tokenizer instance. +*/ +static int porterCreate( + int argc, const char * const *argv, + sqlite3_tokenizer **ppTokenizer +){ + porter_tokenizer *t; - p1++; - p1 += fts3GetVarint32(p1, &iCol1); - p2++; - p2 += fts3GetVarint32(p2, &iCol2); - } + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); - /* Advance pointer p1 or p2 (whichever corresponds to the smaller of - ** iCol1 and iCol2) so that it points to either the 0x00 that marks the - ** end of the position list, or the 0x01 that precedes the next - ** column-number in the position list. - */ - else if( iCol1base; + return SQLITE_OK; +} - fts3PoslistCopy(0, &p2); - fts3PoslistCopy(0, &p1); - *pp1 = p1; - *pp2 = p2; - if( *pp==p ){ - return 0; - } - *p++ = 0x00; - *pp = p; - return 1; +/* +** Destroy a tokenizer +*/ +static int porterDestroy(sqlite3_tokenizer *pTokenizer){ + sqlite3_free(pTokenizer); + return SQLITE_OK; } /* -** Merge two position-lists as required by the NEAR operator. The argument -** position lists correspond to the left and right phrases of an expression -** like: -** -** "phrase 1" NEAR "phrase number 2" -** -** Position list *pp1 corresponds to the left-hand side of the NEAR -** expression and *pp2 to the right. As usual, the indexes in the position -** lists are the offsets of the last token in each phrase (tokens "1" and "2" -** in the example above). -** -** The output position list - written to *pp - is a copy of *pp2 with those -** entries that are not sufficiently NEAR entries in *pp1 removed. +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is zInput[0..nInput-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. */ -static int fts3PoslistNearMerge( - char **pp, /* Output buffer */ - char *aTmp, /* Temporary buffer space */ - int nRight, /* Maximum difference in token positions */ - int nLeft, /* Maximum difference in token positions */ - char **pp1, /* IN/OUT: Left input list */ - char **pp2 /* IN/OUT: Right input list */ +static int porterOpen( + sqlite3_tokenizer *pTokenizer, /* The tokenizer */ + const char *zInput, int nInput, /* String to be tokenized */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ - char *p1 = *pp1; - char *p2 = *pp2; + porter_tokenizer_cursor *c; - char *pTmp1 = aTmp; - char *pTmp2; - char *aTmp2; - int res = 1; + UNUSED_PARAMETER(pTokenizer); - fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2); - aTmp2 = pTmp2 = pTmp1; - *pp1 = p1; - *pp2 = p2; - fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1); - if( pTmp1!=aTmp && pTmp2!=aTmp2 ){ - fts3PoslistMerge(pp, &aTmp, &aTmp2); - }else if( pTmp1!=aTmp ){ - fts3PoslistCopy(pp, &aTmp); - }else if( pTmp2!=aTmp2 ){ - fts3PoslistCopy(pp, &aTmp2); + c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); + if( c==NULL ) return SQLITE_NOMEM; + + c->zInput = zInput; + if( zInput==0 ){ + c->nInput = 0; + }else if( nInput<0 ){ + c->nInput = (int)strlen(zInput); }else{ - res = 0; + c->nInput = nInput; } + c->iOffset = 0; /* start tokenizing at the beginning */ + c->iToken = 0; + c->zToken = NULL; /* no space allocated, yet. */ + c->nAllocated = 0; - return res; + *ppCursor = &c->base; + return SQLITE_OK; } -/* -** An instance of this function is used to merge together the (potentially -** large number of) doclists for each term that matches a prefix query. -** See function fts3TermSelectMerge() for details. +/* +** Close a tokenization cursor previously opened by a call to +** porterOpen() above. */ -typedef struct TermSelect TermSelect; -struct TermSelect { - char *aaOutput[16]; /* Malloc'd output buffers */ - int anOutput[16]; /* Size each output buffer in bytes */ +static int porterClose(sqlite3_tokenizer_cursor *pCursor){ + porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; + sqlite3_free(c->zToken); + sqlite3_free(c); + return SQLITE_OK; +} +/* +** Vowel or consonant +*/ +static const char cType[] = { + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 2, 1 }; /* -** This function is used to read a single varint from a buffer. Parameter -** pEnd points 1 byte past the end of the buffer. When this function is -** called, if *pp points to pEnd or greater, then the end of the buffer -** has been reached. In this case *pp is set to 0 and the function returns. +** isConsonant() and isVowel() determine if their first character in +** the string they point to is a consonant or a vowel, according +** to Porter ruls. ** -** If *pp does not point to or past pEnd, then a single varint is read -** from *pp. *pp is then set to point 1 byte past the end of the read varint. +** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'. +** 'Y' is a consonant unless it follows another consonant, +** in which case it is a vowel. ** -** If bDescIdx is false, the value read is added to *pVal before returning. -** If it is true, the value read is subtracted from *pVal before this -** function returns. +** In these routine, the letters are in reverse order. So the 'y' rule +** is that 'y' is a consonant unless it is followed by another +** consonent. */ -static void fts3GetDeltaVarint3( - char **pp, /* IN/OUT: Point to read varint from */ - char *pEnd, /* End of buffer */ - int bDescIdx, /* True if docids are descending */ - sqlite3_int64 *pVal /* IN/OUT: Integer value */ -){ - if( *pp>=pEnd ){ - *pp = 0; - }else{ - sqlite3_int64 iVal; - *pp += sqlite3Fts3GetVarint(*pp, &iVal); - if( bDescIdx ){ - *pVal -= iVal; - }else{ - *pVal += iVal; - } - } +static int isVowel(const char*); +static int isConsonant(const char *z){ + int j; + char x = *z; + if( x==0 ) return 0; + assert( x>='a' && x<='z' ); + j = cType[x-'a']; + if( j<2 ) return j; + return z[1]==0 || isVowel(z + 1); +} +static int isVowel(const char *z){ + int j; + char x = *z; + if( x==0 ) return 0; + assert( x>='a' && x<='z' ); + j = cType[x-'a']; + if( j<2 ) return 1-j; + return isConsonant(z + 1); } /* -** This function is used to write a single varint to a buffer. The varint -** is written to *pp. Before returning, *pp is set to point 1 byte past the -** end of the value written. +** Let any sequence of one or more vowels be represented by V and let +** C be sequence of one or more consonants. Then every word can be +** represented as: ** -** If *pbFirst is zero when this function is called, the value written to -** the buffer is that of parameter iVal. +** [C] (VC){m} [V] ** -** If *pbFirst is non-zero when this function is called, then the value -** written is either (iVal-*piPrev) (if bDescIdx is zero) or (*piPrev-iVal) -** (if bDescIdx is non-zero). +** In prose: A word is an optional consonant followed by zero or +** vowel-consonant pairs followed by an optional vowel. "m" is the +** number of vowel consonant pairs. This routine computes the value +** of m for the first i bytes of a word. ** -** Before returning, this function always sets *pbFirst to 1 and *piPrev -** to the value of parameter iVal. +** Return true if the m-value for z is 1 or more. In other words, +** return true if z contains at least one vowel that is followed +** by a consonant. +** +** In this routine z[] is in reverse order. So we are really looking +** for an instance of a consonant followed by a vowel. */ -static void fts3PutDeltaVarint3( - char **pp, /* IN/OUT: Output pointer */ - int bDescIdx, /* True for descending docids */ - sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */ - int *pbFirst, /* IN/OUT: True after first int written */ - sqlite3_int64 iVal /* Write this value to the list */ -){ - sqlite3_int64 iWrite; - if( bDescIdx==0 || *pbFirst==0 ){ - iWrite = iVal - *piPrev; - }else{ - iWrite = *piPrev - iVal; - } - assert( *pbFirst || *piPrev==0 ); - assert( *pbFirst==0 || iWrite>0 ); - *pp += sqlite3Fts3PutVarint(*pp, iWrite); - *piPrev = iVal; - *pbFirst = 1; +static int m_gt_0(const char *z){ + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + return *z!=0; +} + +/* Like mgt0 above except we are looking for a value of m which is +** exactly 1 +*/ +static int m_eq_1(const char *z){ + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + if( *z==0 ) return 0; + while( isVowel(z) ){ z++; } + if( *z==0 ) return 1; + while( isConsonant(z) ){ z++; } + return *z==0; +} + +/* Like mgt0 above except we are looking for a value of m>1 instead +** or m>0 +*/ +static int m_gt_1(const char *z){ + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + if( *z==0 ) return 0; + while( isVowel(z) ){ z++; } + if( *z==0 ) return 0; + while( isConsonant(z) ){ z++; } + return *z!=0; } +/* +** Return TRUE if there is a vowel anywhere within z[0..n-1] +*/ +static int hasVowel(const char *z){ + while( isConsonant(z) ){ z++; } + return *z!=0; +} /* -** This macro is used by various functions that merge doclists. The two -** arguments are 64-bit docid values. If the value of the stack variable -** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2). -** Otherwise, (i2-i1). +** Return TRUE if the word ends in a double consonant. ** -** Using this makes it easier to write code that can merge doclists that are -** sorted in either ascending or descending order. +** The text is reversed here. So we are really looking at +** the first two characters of z[]. */ -#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2)) +static int doubleConsonant(const char *z){ + return isConsonant(z) && z[0]==z[1]; +} /* -** This function does an "OR" merge of two doclists (output contains all -** positions contained in either argument doclist). If the docids in the -** input doclists are sorted in ascending order, parameter bDescDoclist -** should be false. If they are sorted in ascending order, it should be -** passed a non-zero value. -** -** If no error occurs, *paOut is set to point at an sqlite3_malloc'd buffer -** containing the output doclist and SQLITE_OK is returned. In this case -** *pnOut is set to the number of bytes in the output doclist. +** Return TRUE if the word ends with three letters which +** are consonant-vowel-consonent and where the final consonant +** is not 'w', 'x', or 'y'. ** -** If an error occurs, an SQLite error code is returned. The output values -** are undefined in this case. +** The word is reversed here. So we are really checking the +** first three letters and the first one cannot be in [wxy]. */ -static int fts3DoclistOrMerge( - int bDescDoclist, /* True if arguments are desc */ - char *a1, int n1, /* First doclist */ - char *a2, int n2, /* Second doclist */ - char **paOut, int *pnOut /* OUT: Malloc'd doclist */ -){ - sqlite3_int64 i1 = 0; - sqlite3_int64 i2 = 0; - sqlite3_int64 iPrev = 0; - char *pEnd1 = &a1[n1]; - char *pEnd2 = &a2[n2]; - char *p1 = a1; - char *p2 = a2; - char *p; - char *aOut; - int bFirstOut = 0; - - *paOut = 0; - *pnOut = 0; - - /* Allocate space for the output. Both the input and output doclists - ** are delta encoded. If they are in ascending order (bDescDoclist==0), - ** then the first docid in each list is simply encoded as a varint. For - ** each subsequent docid, the varint stored is the difference between the - ** current and previous docid (a positive number - since the list is in - ** ascending order). - ** - ** The first docid written to the output is therefore encoded using the - ** same number of bytes as it is in whichever of the input lists it is - ** read from. And each subsequent docid read from the same input list - ** consumes either the same or less bytes as it did in the input (since - ** the difference between it and the previous value in the output must - ** be a positive value less than or equal to the delta value read from - ** the input list). The same argument applies to all but the first docid - ** read from the 'other' list. And to the contents of all position lists - ** that will be copied and merged from the input to the output. - ** - ** However, if the first docid copied to the output is a negative number, - ** then the encoding of the first docid from the 'other' input list may - ** be larger in the output than it was in the input (since the delta value - ** may be a larger positive integer than the actual docid). - ** - ** The space required to store the output is therefore the sum of the - ** sizes of the two inputs, plus enough space for exactly one of the input - ** docids to grow. - ** - ** A symetric argument may be made if the doclists are in descending - ** order. - */ - aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1); - if( !aOut ) return SQLITE_NOMEM; - - p = aOut; - fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); - fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); - while( p1 || p2 ){ - sqlite3_int64 iDiff = DOCID_CMP(i1, i2); - - if( p2 && p1 && iDiff==0 ){ - fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); - fts3PoslistMerge(&p, &p1, &p2); - fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); - fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); - }else if( !p2 || (p1 && iDiff<0) ){ - fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); - fts3PoslistCopy(&p, &p1); - fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); - }else{ - fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i2); - fts3PoslistCopy(&p, &p2); - fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); - } - } - - *paOut = aOut; - *pnOut = (int)(p-aOut); - assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 ); - return SQLITE_OK; +static int star_oh(const char *z){ + return + isConsonant(z) && + z[0]!='w' && z[0]!='x' && z[0]!='y' && + isVowel(z+1) && + isConsonant(z+2); } /* -** This function does a "phrase" merge of two doclists. In a phrase merge, -** the output contains a copy of each position from the right-hand input -** doclist for which there is a position in the left-hand input doclist -** exactly nDist tokens before it. +** If the word ends with zFrom and xCond() is true for the stem +** of the word that preceeds the zFrom ending, then change the +** ending to zTo. ** -** If the docids in the input doclists are sorted in ascending order, -** parameter bDescDoclist should be false. If they are sorted in ascending -** order, it should be passed a non-zero value. +** The input word *pz and zFrom are both in reverse order. zTo +** is in normal order. ** -** The right-hand input doclist is overwritten by this function. +** Return TRUE if zFrom matches. Return FALSE if zFrom does not +** match. Not that TRUE is returned even if xCond() fails and +** no substitution occurs. */ -static int fts3DoclistPhraseMerge( - int bDescDoclist, /* True if arguments are desc */ - int nDist, /* Distance from left to right (1=adjacent) */ - char *aLeft, int nLeft, /* Left doclist */ - char **paRight, int *pnRight /* IN/OUT: Right/output doclist */ +static int stem( + char **pz, /* The word being stemmed (Reversed) */ + const char *zFrom, /* If the ending matches this... (Reversed) */ + const char *zTo, /* ... change the ending to this (not reversed) */ + int (*xCond)(const char*) /* Condition that must be true */ ){ - sqlite3_int64 i1 = 0; - sqlite3_int64 i2 = 0; - sqlite3_int64 iPrev = 0; - char *aRight = *paRight; - char *pEnd1 = &aLeft[nLeft]; - char *pEnd2 = &aRight[*pnRight]; - char *p1 = aLeft; - char *p2 = aRight; - char *p; - int bFirstOut = 0; - char *aOut; - - assert( nDist>0 ); - if( bDescDoclist ){ - aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX); - if( aOut==0 ) return SQLITE_NOMEM; - }else{ - aOut = aRight; - } - p = aOut; - - fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); - fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2); - - while( p1 && p2 ){ - sqlite3_int64 iDiff = DOCID_CMP(i1, i2); - if( iDiff==0 ){ - char *pSave = p; - sqlite3_int64 iPrevSave = iPrev; - int bFirstOutSave = bFirstOut; - - fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1); - if( 0==fts3PoslistPhraseMerge(&p, nDist, 0, 1, &p1, &p2) ){ - p = pSave; - iPrev = iPrevSave; - bFirstOut = bFirstOutSave; - } - fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); - fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); - }else if( iDiff<0 ){ - fts3PoslistCopy(0, &p1); - fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1); - }else{ - fts3PoslistCopy(0, &p2); - fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2); - } - } - - *pnRight = (int)(p - aOut); - if( bDescDoclist ){ - sqlite3_free(aRight); - *paRight = aOut; + char *z = *pz; + while( *zFrom && *zFrom==*z ){ z++; zFrom++; } + if( *zFrom!=0 ) return 0; + if( xCond && !xCond(z) ) return 1; + while( *zTo ){ + *(--z) = *(zTo++); } - - return SQLITE_OK; + *pz = z; + return 1; } /* -** Argument pList points to a position list nList bytes in size. This -** function checks to see if the position list contains any entries for -** a token in position 0 (of any column). If so, it writes argument iDelta -** to the output buffer pOut, followed by a position list consisting only -** of the entries from pList at position 0, and terminated by an 0x00 byte. -** The value returned is the number of bytes written to pOut (if any). +** This is the fallback stemmer used when the porter stemmer is +** inappropriate. The input word is copied into the output with +** US-ASCII case folding. If the input word is too long (more +** than 20 bytes if it contains no digits or more than 6 bytes if +** it contains digits) then word is truncated to 20 or 6 bytes +** by taking 10 or 3 bytes from the beginning and end. */ -SQLITE_PRIVATE int sqlite3Fts3FirstFilter( - sqlite3_int64 iDelta, /* Varint that may be written to pOut */ - char *pList, /* Position list (no 0x00 term) */ - int nList, /* Size of pList in bytes */ - char *pOut /* Write output here */ -){ - int nOut = 0; - int bWritten = 0; /* True once iDelta has been written */ - char *p = pList; - char *pEnd = &pList[nList]; - - if( *p!=0x01 ){ - if( *p==0x02 ){ - nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); - pOut[nOut++] = 0x02; - bWritten = 1; +static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ + int i, mx, j; + int hasDigit = 0; + for(i=0; i='A' && c<='Z' ){ + zOut[i] = c - 'A' + 'a'; + }else{ + if( c>='0' && c<='9' ) hasDigit = 1; + zOut[i] = c; } - fts3ColumnlistCopy(0, &p); } - - while( pmx*2 ){ + for(j=mx, i=nIn-mx; iaaOutput); i++){ - if( pTS->aaOutput[i] ){ - if( !aOut ){ - aOut = pTS->aaOutput[i]; - nOut = pTS->anOutput[i]; - pTS->aaOutput[i] = 0; - }else{ - int nNew; - char *aNew; - - int rc = fts3DoclistOrMerge(p->bDescIdx, - pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, &aNew, &nNew - ); - if( rc!=SQLITE_OK ){ - sqlite3_free(aOut); - return rc; - } - - sqlite3_free(pTS->aaOutput[i]); - sqlite3_free(aOut); - pTS->aaOutput[i] = 0; - aOut = aNew; - nOut = nNew; - } - } - } - - pTS->aaOutput[0] = aOut; - pTS->anOutput[0] = nOut; - return SQLITE_OK; -} - -/* -** Merge the doclist aDoclist/nDoclist into the TermSelect object passed -** as the first argument. The merge is an "OR" merge (see function -** fts3DoclistOrMerge() for details). +** Any upper-case characters in the US-ASCII character set ([A-Z]) +** are converted to lower case. Upper-case UTF characters are +** unchanged. ** -** This function is called with the doclist for each term that matches -** a queried prefix. It merges all these doclists into one, the doclist -** for the specified prefix. Since there can be a very large number of -** doclists to merge, the merging is done pair-wise using the TermSelect -** object. +** Words that are longer than about 20 bytes are stemmed by retaining +** a few bytes from the beginning and the end of the word. If the +** word contains digits, 3 bytes are taken from the beginning and +** 3 bytes from the end. For long words without digits, 10 bytes +** are taken from each end. US-ASCII case folding still applies. ** -** This function returns SQLITE_OK if the merge is successful, or an -** SQLite error code (SQLITE_NOMEM) if an error occurs. +** If the input word contains not digits but does characters not +** in [a-zA-Z] then no stemming is attempted and this routine just +** copies the input into the input into the output with US-ASCII +** case folding. +** +** Stemming never increases the length of the word. So there is +** no chance of overflowing the zOut buffer. */ -static int fts3TermSelectMerge( - Fts3Table *p, /* FTS table handle */ - TermSelect *pTS, /* TermSelect object to merge into */ - char *aDoclist, /* Pointer to doclist */ - int nDoclist /* Size of aDoclist in bytes */ -){ - if( pTS->aaOutput[0]==0 ){ - /* If this is the first term selected, copy the doclist to the output - ** buffer using memcpy(). - ** - ** Add FTS3_VARINT_MAX bytes of unused space to the end of the - ** allocation. This is so as to ensure that the buffer is big enough - ** to hold the current doclist AND'd with any other doclist. If the - ** doclists are stored in order=ASC order, this padding would not be - ** required (since the size of [doclistA AND doclistB] is always less - ** than or equal to the size of [doclistA] in that case). But this is - ** not true for order=DESC. For example, a doclist containing (1, -1) - ** may be smaller than (-1), as in the first example the -1 may be stored - ** as a single-byte delta, whereas in the second it must be stored as a - ** FTS3_VARINT_MAX byte varint. - ** - ** Similar padding is added in the fts3DoclistOrMerge() function. - */ - pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); - pTS->anOutput[0] = nDoclist; - if( pTS->aaOutput[0] ){ - memcpy(pTS->aaOutput[0], aDoclist, nDoclist); +static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ + int i, j; + char zReverse[28]; + char *z, *z2; + if( nIn<3 || nIn>=(int)sizeof(zReverse)-7 ){ + /* The word is too big or too small for the porter stemmer. + ** Fallback to the copy stemmer */ + copy_stemmer(zIn, nIn, zOut, pnOut); + return; + } + for(i=0, j=sizeof(zReverse)-6; i='A' && c<='Z' ){ + zReverse[j] = c + 'a' - 'A'; + }else if( c>='a' && c<='z' ){ + zReverse[j] = c; }else{ - return SQLITE_NOMEM; + /* The use of a character not in [a-zA-Z] means that we fallback + ** to the copy stemmer */ + copy_stemmer(zIn, nIn, zOut, pnOut); + return; } - }else{ - char *aMerge = aDoclist; - int nMerge = nDoclist; - int iOut; - - for(iOut=0; iOutaaOutput); iOut++){ - if( pTS->aaOutput[iOut]==0 ){ - assert( iOut>0 ); - pTS->aaOutput[iOut] = aMerge; - pTS->anOutput[iOut] = nMerge; - break; - }else{ - char *aNew; - int nNew; + } + memset(&zReverse[sizeof(zReverse)-5], 0, 5); + z = &zReverse[j+1]; - int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge, - pTS->aaOutput[iOut], pTS->anOutput[iOut], &aNew, &nNew - ); - if( rc!=SQLITE_OK ){ - if( aMerge!=aDoclist ) sqlite3_free(aMerge); - return rc; - } - if( aMerge!=aDoclist ) sqlite3_free(aMerge); - sqlite3_free(pTS->aaOutput[iOut]); - pTS->aaOutput[iOut] = 0; - - aMerge = aNew; - nMerge = nNew; - if( (iOut+1)==SizeofArray(pTS->aaOutput) ){ - pTS->aaOutput[iOut] = aMerge; - pTS->anOutput[iOut] = nMerge; - } - } + /* Step 1a */ + if( z[0]=='s' ){ + if( + !stem(&z, "sess", "ss", 0) && + !stem(&z, "sei", "i", 0) && + !stem(&z, "ss", "ss", 0) + ){ + z++; } } - return SQLITE_OK; -} -/* -** Append SegReader object pNew to the end of the pCsr->apSegment[] array. -*/ -static int fts3SegReaderCursorAppend( - Fts3MultiSegReader *pCsr, - Fts3SegReader *pNew -){ - if( (pCsr->nSegment%16)==0 ){ - Fts3SegReader **apNew; - int nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*); - apNew = (Fts3SegReader **)sqlite3_realloc(pCsr->apSegment, nByte); - if( !apNew ){ - sqlite3Fts3SegReaderFree(pNew); - return SQLITE_NOMEM; - } - pCsr->apSegment = apNew; + /* Step 1b */ + z2 = z; + if( stem(&z, "dee", "ee", m_gt_0) ){ + /* Do nothing. The work was all in the test */ + }else if( + (stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel)) + && z!=z2 + ){ + if( stem(&z, "ta", "ate", 0) || + stem(&z, "lb", "ble", 0) || + stem(&z, "zi", "ize", 0) ){ + /* Do nothing. The work was all in the test */ + }else if( doubleConsonant(z) && (*z!='l' && *z!='s' && *z!='z') ){ + z++; + }else if( m_eq_1(z) && star_oh(z) ){ + *(--z) = 'e'; + } } - pCsr->apSegment[pCsr->nSegment++] = pNew; - return SQLITE_OK; -} -/* -** Add seg-reader objects to the Fts3MultiSegReader object passed as the -** 8th argument. -** -** This function returns SQLITE_OK if successful, or an SQLite error code -** otherwise. -*/ -static int fts3SegReaderCursor( - Fts3Table *p, /* FTS3 table handle */ - int iLangid, /* Language id */ - int iIndex, /* Index to search (from 0 to p->nIndex-1) */ - int iLevel, /* Level of segments to scan */ - const char *zTerm, /* Term to query for */ - int nTerm, /* Size of zTerm in bytes */ - int isPrefix, /* True for a prefix search */ - int isScan, /* True to scan from zTerm to EOF */ - Fts3MultiSegReader *pCsr /* Cursor object to populate */ -){ - int rc = SQLITE_OK; /* Error code */ - sqlite3_stmt *pStmt = 0; /* Statement to iterate through segments */ - int rc2; /* Result of sqlite3_reset() */ + /* Step 1c */ + if( z[0]=='y' && hasVowel(z+1) ){ + z[0] = 'i'; + } - /* If iLevel is less than 0 and this is not a scan, include a seg-reader - ** for the pending-terms. If this is a scan, then this call must be being - ** made by an fts4aux module, not an FTS table. In this case calling - ** Fts3SegReaderPending might segfault, as the data structures used by - ** fts4aux are not completely populated. So it's easiest to filter these - ** calls out here. */ - if( iLevel<0 && p->aIndex ){ - Fts3SegReader *pSeg = 0; - rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg); - if( rc==SQLITE_OK && pSeg ){ - rc = fts3SegReaderCursorAppend(pCsr, pSeg); - } + /* Step 2 */ + switch( z[1] ){ + case 'a': + if( !stem(&z, "lanoita", "ate", m_gt_0) ){ + stem(&z, "lanoit", "tion", m_gt_0); + } + break; + case 'c': + if( !stem(&z, "icne", "ence", m_gt_0) ){ + stem(&z, "icna", "ance", m_gt_0); + } + break; + case 'e': + stem(&z, "rezi", "ize", m_gt_0); + break; + case 'g': + stem(&z, "igol", "log", m_gt_0); + break; + case 'l': + if( !stem(&z, "ilb", "ble", m_gt_0) + && !stem(&z, "illa", "al", m_gt_0) + && !stem(&z, "iltne", "ent", m_gt_0) + && !stem(&z, "ile", "e", m_gt_0) + ){ + stem(&z, "ilsuo", "ous", m_gt_0); + } + break; + case 'o': + if( !stem(&z, "noitazi", "ize", m_gt_0) + && !stem(&z, "noita", "ate", m_gt_0) + ){ + stem(&z, "rota", "ate", m_gt_0); + } + break; + case 's': + if( !stem(&z, "msila", "al", m_gt_0) + && !stem(&z, "ssenevi", "ive", m_gt_0) + && !stem(&z, "ssenluf", "ful", m_gt_0) + ){ + stem(&z, "ssensuo", "ous", m_gt_0); + } + break; + case 't': + if( !stem(&z, "itila", "al", m_gt_0) + && !stem(&z, "itivi", "ive", m_gt_0) + ){ + stem(&z, "itilib", "ble", m_gt_0); + } + break; } - if( iLevel!=FTS3_SEGCURSOR_PENDING ){ - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3AllSegdirs(p, iLangid, iIndex, iLevel, &pStmt); - } - - while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ - Fts3SegReader *pSeg = 0; + /* Step 3 */ + switch( z[0] ){ + case 'e': + if( !stem(&z, "etaci", "ic", m_gt_0) + && !stem(&z, "evita", "", m_gt_0) + ){ + stem(&z, "ezila", "al", m_gt_0); + } + break; + case 'i': + stem(&z, "itici", "ic", m_gt_0); + break; + case 'l': + if( !stem(&z, "laci", "ic", m_gt_0) ){ + stem(&z, "luf", "", m_gt_0); + } + break; + case 's': + stem(&z, "ssen", "", m_gt_0); + break; + } - /* Read the values returned by the SELECT into local variables. */ - sqlite3_int64 iStartBlock = sqlite3_column_int64(pStmt, 1); - sqlite3_int64 iLeavesEndBlock = sqlite3_column_int64(pStmt, 2); - sqlite3_int64 iEndBlock = sqlite3_column_int64(pStmt, 3); - int nRoot = sqlite3_column_bytes(pStmt, 4); - char const *zRoot = sqlite3_column_blob(pStmt, 4); + /* Step 4 */ + switch( z[1] ){ + case 'a': + if( z[0]=='l' && m_gt_1(z+2) ){ + z += 2; + } + break; + case 'c': + if( z[0]=='e' && z[2]=='n' && (z[3]=='a' || z[3]=='e') && m_gt_1(z+4) ){ + z += 4; + } + break; + case 'e': + if( z[0]=='r' && m_gt_1(z+2) ){ + z += 2; + } + break; + case 'i': + if( z[0]=='c' && m_gt_1(z+2) ){ + z += 2; + } + break; + case 'l': + if( z[0]=='e' && z[2]=='b' && (z[3]=='a' || z[3]=='i') && m_gt_1(z+4) ){ + z += 4; + } + break; + case 'n': + if( z[0]=='t' ){ + if( z[2]=='a' ){ + if( m_gt_1(z+3) ){ + z += 3; + } + }else if( z[2]=='e' ){ + if( !stem(&z, "tneme", "", m_gt_1) + && !stem(&z, "tnem", "", m_gt_1) + ){ + stem(&z, "tne", "", m_gt_1); + } + } + } + break; + case 'o': + if( z[0]=='u' ){ + if( m_gt_1(z+2) ){ + z += 2; + } + }else if( z[3]=='s' || z[3]=='t' ){ + stem(&z, "noi", "", m_gt_1); + } + break; + case 's': + if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){ + z += 3; + } + break; + case 't': + if( !stem(&z, "eta", "", m_gt_1) ){ + stem(&z, "iti", "", m_gt_1); + } + break; + case 'u': + if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){ + z += 3; + } + break; + case 'v': + case 'z': + if( z[0]=='e' && z[2]=='i' && m_gt_1(z+3) ){ + z += 3; + } + break; + } - /* If zTerm is not NULL, and this segment is not stored entirely on its - ** root node, the range of leaves scanned can be reduced. Do this. */ - if( iStartBlock && zTerm ){ - sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0); - rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi); - if( rc!=SQLITE_OK ) goto finished; - if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock; - } - - rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1, - (isPrefix==0 && isScan==0), - iStartBlock, iLeavesEndBlock, - iEndBlock, zRoot, nRoot, &pSeg - ); - if( rc!=SQLITE_OK ) goto finished; - rc = fts3SegReaderCursorAppend(pCsr, pSeg); + /* Step 5a */ + if( z[0]=='e' ){ + if( m_gt_1(z+1) ){ + z++; + }else if( m_eq_1(z+1) && !star_oh(z+1) ){ + z++; } } - finished: - rc2 = sqlite3_reset(pStmt); - if( rc==SQLITE_DONE ) rc = rc2; - - return rc; -} - -/* -** Set up a cursor object for iterating through a full-text index or a -** single level therein. -*/ -SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor( - Fts3Table *p, /* FTS3 table handle */ - int iLangid, /* Language-id to search */ - int iIndex, /* Index to search (from 0 to p->nIndex-1) */ - int iLevel, /* Level of segments to scan */ - const char *zTerm, /* Term to query for */ - int nTerm, /* Size of zTerm in bytes */ - int isPrefix, /* True for a prefix search */ - int isScan, /* True to scan from zTerm to EOF */ - Fts3MultiSegReader *pCsr /* Cursor object to populate */ -){ - assert( iIndex>=0 && iIndexnIndex ); - assert( iLevel==FTS3_SEGCURSOR_ALL - || iLevel==FTS3_SEGCURSOR_PENDING - || iLevel>=0 - ); - assert( iLevelzInput; - pSegcsr = sqlite3_malloc(sizeof(Fts3MultiSegReader)); - if( pSegcsr ){ - int i; - int bFound = 0; /* True once an index has been found */ - Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + while( c->iOffsetnInput ){ + int iStartOffset, ch; - if( isPrefix ){ - for(i=1; bFound==0 && inIndex; i++){ - if( p->aIndex[i].nPrefix==nTerm ){ - bFound = 1; - rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, - i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr - ); - pSegcsr->bLookup = 1; - } - } + /* Scan past delimiter characters */ + while( c->iOffsetnInput && isDelim(z[c->iOffset]) ){ + c->iOffset++; + } - for(i=1; bFound==0 && inIndex; i++){ - if( p->aIndex[i].nPrefix==nTerm+1 ){ - bFound = 1; - rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, - i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr - ); - if( rc==SQLITE_OK ){ - rc = fts3SegReaderCursorAddZero( - p, pCsr->iLangid, zTerm, nTerm, pSegcsr - ); - } - } - } + /* Count non-delimiter characters. */ + iStartOffset = c->iOffset; + while( c->iOffsetnInput && !isDelim(z[c->iOffset]) ){ + c->iOffset++; } - if( bFound==0 ){ - rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid, - 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr - ); - pSegcsr->bLookup = !isPrefix; + if( c->iOffset>iStartOffset ){ + int n = c->iOffset-iStartOffset; + if( n>c->nAllocated ){ + char *pNew; + c->nAllocated = n+20; + pNew = sqlite3_realloc(c->zToken, c->nAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->zToken = pNew; + } + porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); + *pzToken = c->zToken; + *piStartOffset = iStartOffset; + *piEndOffset = c->iOffset; + *piPosition = c->iToken++; + return SQLITE_OK; } } - - *ppSegcsr = pSegcsr; - return rc; + return SQLITE_DONE; } /* -** Free an Fts3MultiSegReader allocated by fts3TermSegReaderCursor(). +** The set of routines that implement the porter-stemmer tokenizer */ -static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){ - sqlite3Fts3SegReaderFinish(pSegcsr); - sqlite3_free(pSegcsr); -} +static const sqlite3_tokenizer_module porterTokenizerModule = { + 0, + porterCreate, + porterDestroy, + porterOpen, + porterClose, + porterNext, + 0 +}; /* -** This function retrieves the doclist for the specified term (or term -** prefix) from the database. +** Allocate a new porter tokenizer. Return a pointer to the new +** tokenizer in *ppModule */ -static int fts3TermSelect( - Fts3Table *p, /* Virtual table handle */ - Fts3PhraseToken *pTok, /* Token to query for */ - int iColumn, /* Column to query (or -ve for all columns) */ - int *pnOut, /* OUT: Size of buffer at *ppOut */ - char **ppOut /* OUT: Malloced result buffer */ +SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule( + sqlite3_tokenizer_module const**ppModule ){ - int rc; /* Return code */ - Fts3MultiSegReader *pSegcsr; /* Seg-reader cursor for this term */ - TermSelect tsc; /* Object for pair-wise doclist merging */ - Fts3SegFilter filter; /* Segment term filter configuration */ - - pSegcsr = pTok->pSegcsr; - memset(&tsc, 0, sizeof(TermSelect)); - - filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS - | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) - | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0) - | (iColumnnColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); - filter.iCol = iColumn; - filter.zTerm = pTok->z; - filter.nTerm = pTok->n; - - rc = sqlite3Fts3SegReaderStart(p, pSegcsr, &filter); - while( SQLITE_OK==rc - && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr)) - ){ - rc = fts3TermSelectMerge(p, &tsc, pSegcsr->aDoclist, pSegcsr->nDoclist); - } - - if( rc==SQLITE_OK ){ - rc = fts3TermSelectFinishMerge(p, &tsc); - } - if( rc==SQLITE_OK ){ - *ppOut = tsc.aaOutput[0]; - *pnOut = tsc.anOutput[0]; - }else{ - int i; - for(i=0; ipSegcsr = 0; - return rc; + *ppModule = &porterTokenizerModule; } -/* -** This function counts the total number of docids in the doclist stored -** in buffer aList[], size nList bytes. -** -** If the isPoslist argument is true, then it is assumed that the doclist -** contains a position-list following each docid. Otherwise, it is assumed -** that the doclist is simply a list of docids stored as delta encoded -** varints. -*/ -static int fts3DoclistCountDocids(char *aList, int nList){ - int nDoc = 0; /* Return value */ - if( aList ){ - char *aEnd = &aList[nList]; /* Pointer to one byte after EOF */ - char *p = aList; /* Cursor */ - while( peSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){ - if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){ - pCsr->isEof = 1; - rc = sqlite3_reset(pCsr->pStmt); - }else{ - pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); - rc = SQLITE_OK; - } - }else{ - rc = fts3EvalNext((Fts3Cursor *)pCursor); - } - assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); - return rc; -} /* -** The following are copied from sqliteInt.h. +** The code in this file is only compiled if: ** -** Constants for the largest and smallest possible 64-bit signed integers. -** These macros are designed to work correctly on both 32-bit and 64-bit -** compilers. +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or +** +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ -#ifndef SQLITE_AMALGAMATION -# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) -# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) -#endif +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ /* -** If the numeric type of argument pVal is "integer", then return it -** converted to a 64-bit signed integer. Otherwise, return a copy of -** the second parameter, iDefault. +** Return true if the two-argument version of fts3_tokenizer() +** has been activated via a prior call to sqlite3_db_config(db, +** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0); */ -static sqlite3_int64 fts3DocidRange(sqlite3_value *pVal, i64 iDefault){ - if( pVal ){ - int eType = sqlite3_value_numeric_type(pVal); - if( eType==SQLITE_INTEGER ){ - return sqlite3_value_int64(pVal); - } - } - return iDefault; +static int fts3TokenizerEnabled(sqlite3_context *context){ + sqlite3 *db = sqlite3_context_db_handle(context); + int isEnabled = 0; + sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled); + return isEnabled; } /* -** This is the xFilter interface for the virtual table. See -** the virtual table xFilter method documentation for additional -** information. +** Implementation of the SQL scalar function for accessing the underlying +** hash table. This function may be called as follows: ** -** If idxNum==FTS3_FULLSCAN_SEARCH then do a full table scan against -** the %_content table. +** SELECT (); +** SELECT (, ); ** -** If idxNum==FTS3_DOCID_SEARCH then do a docid lookup for a single entry -** in the %_content table. +** where is the name passed as the second argument +** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer'). ** -** If idxNum>=FTS3_FULLTEXT_SEARCH then use the full text index. The -** column on the left-hand side of the MATCH operator is column -** number idxNum-FTS3_FULLTEXT_SEARCH, 0 indexed. argv[0] is the right-hand -** side of the MATCH operator. +** If the argument is specified, it must be a blob value +** containing a pointer to be stored as the hash data corresponding +** to the string . If is not specified, then +** the string must already exist in the has table. Otherwise, +** an error is returned. +** +** Whether or not the argument is specified, the value returned +** is a blob containing the pointer stored as the hash data corresponding +** to string (after the hash-table is updated, if applicable). */ -static int fts3FilterMethod( - sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ - int idxNum, /* Strategy index */ - const char *idxStr, /* Unused */ - int nVal, /* Number of elements in apVal */ - sqlite3_value **apVal /* Arguments for the indexing scheme */ +static void fts3TokenizerFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - int rc = SQLITE_OK; - char *zSql; /* SQL statement used to access %_content */ - int eSearch; - Fts3Table *p = (Fts3Table *)pCursor->pVtab; - Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; - - sqlite3_value *pCons = 0; /* The MATCH or rowid constraint, if any */ - sqlite3_value *pLangid = 0; /* The "langid = ?" constraint, if any */ - sqlite3_value *pDocidGe = 0; /* The "docid >= ?" constraint, if any */ - sqlite3_value *pDocidLe = 0; /* The "docid <= ?" constraint, if any */ - int iIdx; - - UNUSED_PARAMETER(idxStr); - UNUSED_PARAMETER(nVal); - - eSearch = (idxNum & 0x0000FFFF); - assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) ); - assert( p->pSegments==0 ); - - /* Collect arguments into local variables */ - iIdx = 0; - if( eSearch!=FTS3_FULLSCAN_SEARCH ) pCons = apVal[iIdx++]; - if( idxNum & FTS3_HAVE_LANGID ) pLangid = apVal[iIdx++]; - if( idxNum & FTS3_HAVE_DOCID_GE ) pDocidGe = apVal[iIdx++]; - if( idxNum & FTS3_HAVE_DOCID_LE ) pDocidLe = apVal[iIdx++]; - assert( iIdx==nVal ); - - /* In case the cursor has been used before, clear it now. */ - fts3CursorFinalizeStmt(pCsr); - sqlite3_free(pCsr->aDoclist); - sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); - sqlite3Fts3ExprFree(pCsr->pExpr); - memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor)); - - /* Set the lower and upper bounds on docids to return */ - pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64); - pCsr->iMaxDocid = fts3DocidRange(pDocidLe, LARGEST_INT64); - - if( idxStr ){ - pCsr->bDesc = (idxStr[0]=='D'); - }else{ - pCsr->bDesc = p->bDescIdx; - } - pCsr->eSearch = (i16)eSearch; - - if( eSearch!=FTS3_DOCID_SEARCH && eSearch!=FTS3_FULLSCAN_SEARCH ){ - int iCol = eSearch-FTS3_FULLTEXT_SEARCH; - const char *zQuery = (const char *)sqlite3_value_text(pCons); - - if( zQuery==0 && sqlite3_value_type(pCons)!=SQLITE_NULL ){ - return SQLITE_NOMEM; - } + Fts3Hash *pHash; + void *pPtr = 0; + const unsigned char *zName; + int nName; - pCsr->iLangid = 0; - if( pLangid ) pCsr->iLangid = sqlite3_value_int(pLangid); + assert( argc==1 || argc==2 ); - assert( p->base.zErrMsg==0 ); - rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid, - p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, - &p->base.zErrMsg - ); - if( rc!=SQLITE_OK ){ - return rc; - } + pHash = (Fts3Hash *)sqlite3_user_data(context); - rc = fts3EvalStart(pCsr); - sqlite3Fts3SegmentsClose(p); - if( rc!=SQLITE_OK ) return rc; - pCsr->pNextId = pCsr->aDoclist; - pCsr->iPrevId = 0; - } + zName = sqlite3_value_text(argv[0]); + nName = sqlite3_value_bytes(argv[0])+1; - /* Compile a SELECT statement for this cursor. For a full-table-scan, the - ** statement loops through all rows of the %_content table. For a - ** full-text query or docid lookup, the statement retrieves a single - ** row by docid. - */ - if( eSearch==FTS3_FULLSCAN_SEARCH ){ - if( pDocidGe || pDocidLe ){ - zSql = sqlite3_mprintf( - "SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s", - p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid, - (pCsr->bDesc ? "DESC" : "ASC") - ); + if( argc==2 ){ + if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[1]) ){ + void *pOld; + int n = sqlite3_value_bytes(argv[1]); + if( zName==0 || n!=sizeof(pPtr) ){ + sqlite3_result_error(context, "argument type mismatch", -1); + return; + } + pPtr = *(void **)sqlite3_value_blob(argv[1]); + pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); + if( pOld==pPtr ){ + sqlite3_result_error(context, "out of memory", -1); + } }else{ - zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s", - p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") - ); + sqlite3_result_error(context, "fts3tokenize disabled", -1); + return; } - if( zSql ){ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); - sqlite3_free(zSql); - }else{ - rc = SQLITE_NOMEM; + }else{ + if( zName ){ + pPtr = sqlite3Fts3HashFind(pHash, zName, nName); } - }else if( eSearch==FTS3_DOCID_SEARCH ){ - rc = fts3CursorSeekStmt(pCsr); - if( rc==SQLITE_OK ){ - rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons); + if( !pPtr ){ + char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + return; } } - if( rc!=SQLITE_OK ) return rc; - - return fts3NextMethod(pCursor); -} - -/* -** This is the xEof method of the virtual table. SQLite calls this -** routine to find out if it has reached the end of a result set. -*/ -static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){ - return ((Fts3Cursor *)pCursor)->isEof; + if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[0]) ){ + sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); + } } -/* -** This is the xRowid method. The SQLite core calls this routine to -** retrieve the rowid for the current row of the result set. fts3 -** exposes %_content.docid as the rowid for the virtual table. The -** rowid should be written to *pRowid. -*/ -static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ - Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; - *pRowid = pCsr->iPrevId; - return SQLITE_OK; +SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){ + static const char isFtsIdChar[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ + }; + return (c&0x80 || isFtsIdChar[(int)(c)]); } -/* -** This is the xColumn method, called by SQLite to request a value from -** the row that the supplied cursor currently points to. -** -** If: -** -** (iCol < p->nColumn) -> The value of the iCol'th user column. -** (iCol == p->nColumn) -> Magic column with the same name as the table. -** (iCol == p->nColumn+1) -> Docid column -** (iCol == p->nColumn+2) -> Langid column -*/ -static int fts3ColumnMethod( - sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ - sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ - int iCol /* Index of column to read value from */ -){ - int rc = SQLITE_OK; /* Return Code */ - Fts3Cursor *pCsr = (Fts3Cursor *) pCursor; - Fts3Table *p = (Fts3Table *)pCursor->pVtab; - - /* The column value supplied by SQLite must be in range. */ - assert( iCol>=0 && iCol<=p->nColumn+2 ); +SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){ + const char *z1; + const char *z2 = 0; - if( iCol==p->nColumn+1 ){ - /* This call is a request for the "docid" column. Since "docid" is an - ** alias for "rowid", use the xRowid() method to obtain the value. - */ - sqlite3_result_int64(pCtx, pCsr->iPrevId); - }else if( iCol==p->nColumn ){ - /* The extra column whose name is the same as the table. - ** Return a blob which is a pointer to the cursor. */ - sqlite3_result_blob(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT); - }else if( iCol==p->nColumn+2 && pCsr->pExpr ){ - sqlite3_result_int64(pCtx, pCsr->iLangid); - }else{ - /* The requested column is either a user column (one that contains - ** indexed data), or the language-id column. */ - rc = fts3CursorSeek(0, pCsr); + /* Find the start of the next token. */ + z1 = zStr; + while( z2==0 ){ + char c = *z1; + switch( c ){ + case '\0': return 0; /* No more tokens here */ + case '\'': + case '"': + case '`': { + z2 = z1; + while( *++z2 && (*z2!=c || *++z2==c) ); + break; + } + case '[': + z2 = &z1[1]; + while( *z2 && z2[0]!=']' ) z2++; + if( *z2 ) z2++; + break; - if( rc==SQLITE_OK ){ - if( iCol==p->nColumn+2 ){ - int iLangid = 0; - if( p->zLanguageid ){ - iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1); + default: + if( sqlite3Fts3IsIdChar(*z1) ){ + z2 = &z1[1]; + while( sqlite3Fts3IsIdChar(*z2) ) z2++; + }else{ + z1++; } - sqlite3_result_int(pCtx, iLangid); - }else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){ - sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); - } } } - assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); - return rc; + *pn = (int)(z2-z1); + return z1; } -/* -** This function is the implementation of the xUpdate callback used by -** FTS3 virtual tables. It is invoked by SQLite each time a row is to be -** inserted, updated or deleted. -*/ -static int fts3UpdateMethod( - sqlite3_vtab *pVtab, /* Virtual table handle */ - int nArg, /* Size of argument array */ - sqlite3_value **apVal, /* Array of arguments */ - sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ +SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( + Fts3Hash *pHash, /* Tokenizer hash table */ + const char *zArg, /* Tokenizer name */ + sqlite3_tokenizer **ppTok, /* OUT: Tokenizer (if applicable) */ + char **pzErr /* OUT: Set to malloced error message */ ){ - return sqlite3Fts3UpdateMethod(pVtab, nArg, apVal, pRowid); -} - -/* -** Implementation of xSync() method. Flush the contents of the pending-terms -** hash-table to the database. -*/ -static int fts3SyncMethod(sqlite3_vtab *pVtab){ - - /* Following an incremental-merge operation, assuming that the input - ** segments are not completely consumed (the usual case), they are updated - ** in place to remove the entries that have already been merged. This - ** involves updating the leaf block that contains the smallest unmerged - ** entry and each block (if any) between the leaf and the root node. So - ** if the height of the input segment b-trees is N, and input segments - ** are merged eight at a time, updating the input segments at the end - ** of an incremental-merge requires writing (8*(1+N)) blocks. N is usually - ** small - often between 0 and 2. So the overhead of the incremental - ** merge is somewhere between 8 and 24 blocks. To avoid this overhead - ** dwarfing the actual productive work accomplished, the incremental merge - ** is only attempted if it will write at least 64 leaf blocks. Hence - ** nMinMerge. - ** - ** Of course, updating the input segments also involves deleting a bunch - ** of blocks from the segments table. But this is not considered overhead - ** as it would also be required by a crisis-merge that used the same input - ** segments. - */ - const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */ - - Fts3Table *p = (Fts3Table*)pVtab; - int rc = sqlite3Fts3PendingTermsFlush(p); + int rc; + char *z = (char *)zArg; + int n = 0; + char *zCopy; + char *zEnd; /* Pointer to nul-term of zCopy */ + sqlite3_tokenizer_module *m; - if( rc==SQLITE_OK - && p->nLeafAdd>(nMinMerge/16) - && p->nAutoincrmerge && p->nAutoincrmerge!=0xff - ){ - int mxLevel = 0; /* Maximum relative level value in db */ - int A; /* Incr-merge parameter A */ + zCopy = sqlite3_mprintf("%s", zArg); + if( !zCopy ) return SQLITE_NOMEM; + zEnd = &zCopy[strlen(zCopy)]; - rc = sqlite3Fts3MaxLevel(p, &mxLevel); - assert( rc==SQLITE_OK || mxLevel==0 ); - A = p->nLeafAdd * mxLevel; - A += (A/2); - if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge); + z = (char *)sqlite3Fts3NextToken(zCopy, &n); + if( z==0 ){ + assert( n==0 ); + z = zCopy; } - sqlite3Fts3SegmentsClose(p); - return rc; -} + z[n] = '\0'; + sqlite3Fts3Dequote(z); -/* -** If it is currently unknown whether or not the FTS table has an %_stat -** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat -** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code -** if an error occurs. -*/ -static int fts3SetHasStat(Fts3Table *p){ - int rc = SQLITE_OK; - if( p->bHasStat==2 ){ - const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'"; - char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName); - if( zSql ){ - sqlite3_stmt *pStmt = 0; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - if( rc==SQLITE_OK ){ - int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW); - rc = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ) p->bHasStat = (u8)bHasStat; + m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1); + if( !m ){ + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z); + rc = SQLITE_ERROR; + }else{ + char const **aArg = 0; + int iArg = 0; + z = &z[n+1]; + while( zxCreate(iArg, aArg, ppTok); + assert( rc!=SQLITE_OK || *ppTok ); + if( rc!=SQLITE_OK ){ + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer"); }else{ - rc = SQLITE_NOMEM; + (*ppTok)->pModule = m; } + sqlite3_free((void *)aArg); } + + sqlite3_free(zCopy); return rc; } -/* -** Implementation of xBegin() method. -*/ -static int fts3BeginMethod(sqlite3_vtab *pVtab){ - Fts3Table *p = (Fts3Table*)pVtab; - UNUSED_PARAMETER(pVtab); - assert( p->pSegments==0 ); - assert( p->nPendingData==0 ); - assert( p->inTransaction!=1 ); - TESTONLY( p->inTransaction = 1 ); - TESTONLY( p->mxSavepoint = -1; ); - p->nLeafAdd = 0; - return fts3SetHasStat(p); -} -/* -** Implementation of xCommit() method. This is a no-op. The contents of -** the pending-terms hash-table have already been flushed into the database -** by fts3SyncMethod(). -*/ -static int fts3CommitMethod(sqlite3_vtab *pVtab){ - TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); - UNUSED_PARAMETER(pVtab); - assert( p->nPendingData==0 ); - assert( p->inTransaction!=0 ); - assert( p->pSegments==0 ); - TESTONLY( p->inTransaction = 0 ); - TESTONLY( p->mxSavepoint = -1; ); - return SQLITE_OK; -} +#ifdef SQLITE_TEST -/* -** Implementation of xRollback(). Discard the contents of the pending-terms -** hash-table. Any changes made to the database are reverted by SQLite. -*/ -static int fts3RollbackMethod(sqlite3_vtab *pVtab){ - Fts3Table *p = (Fts3Table*)pVtab; - sqlite3Fts3PendingTermsClear(p); - assert( p->inTransaction!=0 ); - TESTONLY( p->inTransaction = 0 ); - TESTONLY( p->mxSavepoint = -1; ); - return SQLITE_OK; -} +#if defined(INCLUDE_SQLITE_TCL_H) +# include "sqlite_tcl.h" +#else +# include "tcl.h" +#endif +/* #include */ /* -** When called, *ppPoslist must point to the byte immediately following the -** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function -** moves *ppPoslist so that it instead points to the first byte of the -** same position list. +** Implementation of a special SQL scalar function for testing tokenizers +** designed to be used in concert with the Tcl testing framework. This +** function must be called with two or more arguments: +** +** SELECT (, ..., ); +** +** where is the name passed as the second argument +** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer') +** concatenated with the string '_test' (e.g. 'fts3_tokenizer_test'). +** +** The return value is a string that may be interpreted as a Tcl +** list. For each token in the , three elements are +** added to the returned list. The first is the token position, the +** second is the token text (folded, stemmed, etc.) and the third is the +** substring of associated with the token. For example, +** using the built-in "simple" tokenizer: +** +** SELECT fts_tokenizer_test('simple', 'I don't see how'); +** +** will return the string: +** +** "{0 i I 1 dont don't 2 see see 3 how how}" +** */ -static void fts3ReversePoslist(char *pStart, char **ppPoslist){ - char *p = &(*ppPoslist)[-2]; - char c = 0; - - /* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */ - while( p>pStart && (c=*p--)==0 ); +static void testFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Fts3Hash *pHash; + sqlite3_tokenizer_module *p; + sqlite3_tokenizer *pTokenizer = 0; + sqlite3_tokenizer_cursor *pCsr = 0; - /* Search backwards for a varint with value zero (the end of the previous - ** poslist). This is an 0x00 byte preceded by some byte that does not - ** have the 0x80 bit set. */ - while( p>pStart && (*p & 0x80) | c ){ - c = *p--; - } - assert( p==pStart || c==0 ); + const char *zErr = 0; - /* At this point p points to that preceding byte without the 0x80 bit - ** set. So to find the start of the poslist, skip forward 2 bytes then - ** over a varint. - ** - ** Normally. The other case is that p==pStart and the poslist to return - ** is the first in the doclist. In this case do not skip forward 2 bytes. - ** The second part of the if condition (c==0 && *ppPoslist>&p[2]) - ** is required for cases where the first byte of a doclist and the - ** doclist is empty. For example, if the first docid is 10, a doclist - ** that begins with: - ** - ** 0x0A 0x00 - */ - if( p>pStart || (c==0 && *ppPoslist>&p[2]) ){ p = &p[2]; } - while( *p++&0x80 ); - *ppPoslist = p; -} + const char *zName; + int nName; + const char *zInput; + int nInput; -/* -** Helper function used by the implementation of the overloaded snippet(), -** offsets() and optimize() SQL functions. -** -** If the value passed as the third argument is a blob of size -** sizeof(Fts3Cursor*), then the blob contents are copied to the -** output variable *ppCsr and SQLITE_OK is returned. Otherwise, an error -** message is written to context pContext and SQLITE_ERROR returned. The -** string passed via zFunc is used as part of the error message. -*/ -static int fts3FunctionArg( - sqlite3_context *pContext, /* SQL function call context */ - const char *zFunc, /* Function name */ - sqlite3_value *pVal, /* argv[0] passed to function */ - Fts3Cursor **ppCsr /* OUT: Store cursor handle here */ -){ - Fts3Cursor *pRet; - if( sqlite3_value_type(pVal)!=SQLITE_BLOB - || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *) - ){ - char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc); - sqlite3_result_error(pContext, zErr, -1); - sqlite3_free(zErr); - return SQLITE_ERROR; - } - memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *)); - *ppCsr = pRet; - return SQLITE_OK; -} + const char *azArg[64]; -/* -** Implementation of the snippet() function for FTS3 -*/ -static void fts3SnippetFunc( - sqlite3_context *pContext, /* SQLite function call context */ - int nVal, /* Size of apVal[] array */ - sqlite3_value **apVal /* Array of arguments */ -){ - Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ - const char *zStart = ""; - const char *zEnd = ""; - const char *zEllipsis = "..."; - int iCol = -1; - int nToken = 15; /* Default number of tokens in snippet */ + const char *zToken; + int nToken = 0; + int iStart = 0; + int iEnd = 0; + int iPos = 0; + int i; - /* There must be at least one argument passed to this function (otherwise - ** the non-overloaded version would have been called instead of this one). - */ - assert( nVal>=1 ); + Tcl_Obj *pRet; - if( nVal>6 ){ - sqlite3_result_error(pContext, - "wrong number of arguments to function snippet()", -1); + if( argc<2 ){ + sqlite3_result_error(context, "insufficient arguments", -1); return; } - if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return; - - switch( nVal ){ - case 6: nToken = sqlite3_value_int(apVal[5]); - case 5: iCol = sqlite3_value_int(apVal[4]); - case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]); - case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]); - case 2: zStart = (const char*)sqlite3_value_text(apVal[1]); - } - if( !zEllipsis || !zEnd || !zStart ){ - sqlite3_result_error_nomem(pContext); - }else if( nToken==0 ){ - sqlite3_result_text(pContext, "", -1, SQLITE_STATIC); - }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ - sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken); - } -} - -/* -** Implementation of the offsets() function for FTS3 -*/ -static void fts3OffsetsFunc( - sqlite3_context *pContext, /* SQLite function call context */ - int nVal, /* Size of argument array */ - sqlite3_value **apVal /* Array of arguments */ -){ - Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ - UNUSED_PARAMETER(nVal); + nName = sqlite3_value_bytes(argv[0]); + zName = (const char *)sqlite3_value_text(argv[0]); + nInput = sqlite3_value_bytes(argv[argc-1]); + zInput = (const char *)sqlite3_value_text(argv[argc-1]); - assert( nVal==1 ); - if( fts3FunctionArg(pContext, "offsets", apVal[0], &pCsr) ) return; - assert( pCsr ); - if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){ - sqlite3Fts3Offsets(pContext, pCsr); + pHash = (Fts3Hash *)sqlite3_user_data(context); + p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); + + if( !p ){ + char *zErr2 = sqlite3_mprintf("unknown tokenizer: %s", zName); + sqlite3_result_error(context, zErr2, -1); + sqlite3_free(zErr2); + return; } -} -/* -** Implementation of the special optimize() function for FTS3. This -** function merges all segments in the database to a single segment. -** Example usage is: -** -** SELECT optimize(t) FROM t LIMIT 1; -** -** where 't' is the name of an FTS3 table. -*/ -static void fts3OptimizeFunc( - sqlite3_context *pContext, /* SQLite function call context */ - int nVal, /* Size of argument array */ - sqlite3_value **apVal /* Array of arguments */ -){ - int rc; /* Return code */ - Fts3Table *p; /* Virtual table handle */ - Fts3Cursor *pCursor; /* Cursor handle passed through apVal[0] */ + pRet = Tcl_NewObj(); + Tcl_IncrRefCount(pRet); - UNUSED_PARAMETER(nVal); + for(i=1; ibase.pVtab; - assert( p ); + if( SQLITE_OK!=p->xCreate(argc-2, azArg, &pTokenizer) ){ + zErr = "error in xCreate()"; + goto finish; + } + pTokenizer->pModule = p; + if( sqlite3Fts3OpenTokenizer(pTokenizer, 0, zInput, nInput, &pCsr) ){ + zErr = "error in xOpen()"; + goto finish; + } - rc = sqlite3Fts3Optimize(p); + while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){ + Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); + zToken = &zInput[iStart]; + nToken = iEnd-iStart; + Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); + } - switch( rc ){ - case SQLITE_OK: - sqlite3_result_text(pContext, "Index optimized", -1, SQLITE_STATIC); - break; - case SQLITE_DONE: - sqlite3_result_text(pContext, "Index already optimal", -1, SQLITE_STATIC); - break; - default: - sqlite3_result_error_code(pContext, rc); - break; + if( SQLITE_OK!=p->xClose(pCsr) ){ + zErr = "error in xClose()"; + goto finish; + } + if( SQLITE_OK!=p->xDestroy(pTokenizer) ){ + zErr = "error in xDestroy()"; + goto finish; } -} -/* -** Implementation of the matchinfo() function for FTS3 -*/ -static void fts3MatchinfoFunc( - sqlite3_context *pContext, /* SQLite function call context */ - int nVal, /* Size of argument array */ - sqlite3_value **apVal /* Array of arguments */ -){ - Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */ - assert( nVal==1 || nVal==2 ); - if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){ - const char *zArg = 0; - if( nVal>1 ){ - zArg = (const char *)sqlite3_value_text(apVal[1]); - } - sqlite3Fts3Matchinfo(pContext, pCsr, zArg); +finish: + if( zErr ){ + sqlite3_result_error(context, zErr, -1); + }else{ + sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT); } + Tcl_DecrRefCount(pRet); } -/* -** This routine implements the xFindFunction method for the FTS3 -** virtual table. -*/ -static int fts3FindFunctionMethod( - sqlite3_vtab *pVtab, /* Virtual table handle */ - int nArg, /* Number of SQL function arguments */ - const char *zName, /* Name of SQL function */ - void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ - void **ppArg /* Unused */ +static +int registerTokenizer( + sqlite3 *db, + char *zName, + const sqlite3_tokenizer_module *p ){ - struct Overloaded { - const char *zName; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aOverload[] = { - { "snippet", fts3SnippetFunc }, - { "offsets", fts3OffsetsFunc }, - { "optimize", fts3OptimizeFunc }, - { "matchinfo", fts3MatchinfoFunc }, - }; - int i; /* Iterator variable */ - - UNUSED_PARAMETER(pVtab); - UNUSED_PARAMETER(nArg); - UNUSED_PARAMETER(ppArg); + int rc; + sqlite3_stmt *pStmt; + const char zSql[] = "SELECT fts3_tokenizer(?, ?)"; - for(i=0; idb; /* Database connection */ - int rc; /* Return Code */ + int rc; + sqlite3_stmt *pStmt; + const char zSql[] = "SELECT fts3_tokenizer(?)"; - /* At this point it must be known if the %_stat table exists or not. - ** So bHasStat may not be 2. */ - rc = fts3SetHasStat(p); - - /* As it happens, the pending terms table is always empty here. This is - ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction - ** always opens a savepoint transaction. And the xSavepoint() method - ** flushes the pending terms table. But leave the (no-op) call to - ** PendingTermsFlush() in in case that changes. - */ - assert( p->nPendingData==0 ); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3PendingTermsFlush(p); + *pp = 0; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc!=SQLITE_OK ){ + return rc; } - if( p->zContentTbl==0 ){ - fts3DbExec(&rc, db, - "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", - p->zDb, p->zName, zName - ); + sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB + && sqlite3_column_bytes(pStmt, 0)==sizeof(*pp) + ){ + memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); + } } - if( p->bHasDocsize ){ - fts3DbExec(&rc, db, - "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", - p->zDb, p->zName, zName - ); - } - if( p->bHasStat ){ - fts3DbExec(&rc, db, - "ALTER TABLE %Q.'%q_stat' RENAME TO '%q_stat';", - p->zDb, p->zName, zName - ); - } - fts3DbExec(&rc, db, - "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';", - p->zDb, p->zName, zName - ); - fts3DbExec(&rc, db, - "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", - p->zDb, p->zName, zName - ); - return rc; + return sqlite3_finalize(pStmt); } -/* -** The xSavepoint() method. -** -** Flush the contents of the pending-terms table to disk. -*/ -static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ - int rc = SQLITE_OK; - UNUSED_PARAMETER(iSavepoint); - assert( ((Fts3Table *)pVtab)->inTransaction ); - assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint ); - TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint ); - if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){ - rc = fts3SyncMethod(pVtab); - } - return rc; -} +SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); /* -** The xRelease() method. +** Implementation of the scalar function fts3_tokenizer_internal_test(). +** This function is used for testing only, it is not included in the +** build unless SQLITE_TEST is defined. ** -** This is a no-op. -*/ -static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ - TESTONLY( Fts3Table *p = (Fts3Table*)pVtab ); - UNUSED_PARAMETER(iSavepoint); - UNUSED_PARAMETER(pVtab); - assert( p->inTransaction ); - assert( p->mxSavepoint >= iSavepoint ); - TESTONLY( p->mxSavepoint = iSavepoint-1 ); - return SQLITE_OK; -} - -/* -** The xRollbackTo() method. +** The purpose of this is to test that the fts3_tokenizer() function +** can be used as designed by the C-code in the queryTokenizer and +** registerTokenizer() functions above. These two functions are repeated +** in the README.tokenizer file as an example, so it is important to +** test them. +** +** To run the tests, evaluate the fts3_tokenizer_internal_test() scalar +** function with no arguments. An assert() will fail if a problem is +** detected. i.e.: +** +** SELECT fts3_tokenizer_internal_test(); ** -** Discard the contents of the pending terms table. */ -static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts3Table *p = (Fts3Table*)pVtab; - UNUSED_PARAMETER(iSavepoint); - assert( p->inTransaction ); - assert( p->mxSavepoint >= iSavepoint ); - TESTONLY( p->mxSavepoint = iSavepoint ); - sqlite3Fts3PendingTermsClear(p); - return SQLITE_OK; -} +static void intTestFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int rc; + const sqlite3_tokenizer_module *p1; + const sqlite3_tokenizer_module *p2; + sqlite3 *db = (sqlite3 *)sqlite3_user_data(context); -static const sqlite3_module fts3Module = { - /* iVersion */ 2, - /* xCreate */ fts3CreateMethod, - /* xConnect */ fts3ConnectMethod, - /* xBestIndex */ fts3BestIndexMethod, - /* xDisconnect */ fts3DisconnectMethod, - /* xDestroy */ fts3DestroyMethod, - /* xOpen */ fts3OpenMethod, - /* xClose */ fts3CloseMethod, - /* xFilter */ fts3FilterMethod, - /* xNext */ fts3NextMethod, - /* xEof */ fts3EofMethod, - /* xColumn */ fts3ColumnMethod, - /* xRowid */ fts3RowidMethod, - /* xUpdate */ fts3UpdateMethod, - /* xBegin */ fts3BeginMethod, - /* xSync */ fts3SyncMethod, - /* xCommit */ fts3CommitMethod, - /* xRollback */ fts3RollbackMethod, - /* xFindFunction */ fts3FindFunctionMethod, - /* xRename */ fts3RenameMethod, - /* xSavepoint */ fts3SavepointMethod, - /* xRelease */ fts3ReleaseMethod, - /* xRollbackTo */ fts3RollbackToMethod, -}; + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); -/* -** This function is registered as the module destructor (called when an -** FTS3 enabled database connection is closed). It frees the memory -** allocated for the tokenizer hash table. -*/ -static void hashDestroy(void *p){ - Fts3Hash *pHash = (Fts3Hash *)p; - sqlite3Fts3HashClear(pHash); - sqlite3_free(pHash); + /* Test the query function */ + sqlite3Fts3SimpleTokenizerModule(&p1); + rc = queryTokenizer(db, "simple", &p2); + assert( rc==SQLITE_OK ); + assert( p1==p2 ); + rc = queryTokenizer(db, "nosuchtokenizer", &p2); + assert( rc==SQLITE_ERROR ); + assert( p2==0 ); + assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); + + /* Test the storage function */ + if( fts3TokenizerEnabled(context) ){ + rc = registerTokenizer(db, "nosuchtokenizer", p1); + assert( rc==SQLITE_OK ); + rc = queryTokenizer(db, "nosuchtokenizer", &p2); + assert( rc==SQLITE_OK ); + assert( p2==p1 ); + } + + sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); } -/* -** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are -** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c -** respectively. The following three forward declarations are for functions -** declared in these files used to retrieve the respective implementations. -** -** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed -** to by the argument to point to the "simple" tokenizer implementation. -** And so on. -*/ -SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); -SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); -#ifndef SQLITE_DISABLE_FTS3_UNICODE -SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const**ppModule); -#endif -#ifdef SQLITE_ENABLE_ICU -SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); #endif /* -** Initialize the fts3 extension. If this extension is built as part -** of the sqlite library, then this function is called directly by -** SQLite. If fts3 is built as a dynamically loadable extension, this -** function is called by the sqlite3_extension_init() entry point. +** Set up SQL objects in database db used to access the contents of +** the hash table pointed to by argument pHash. The hash table must +** been initialized to use string keys, and to take a private copy +** of the key when a value is inserted. i.e. by a call similar to: +** +** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); +** +** This function adds a scalar function (see header comment above +** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is +** defined at compilation time, a temporary virtual table (see header +** comment above struct HashTableVtab) to the database schema. Both +** provide read/write access to the contents of *pHash. +** +** The third argument to this function, zName, is used as the name +** of both the scalar and, if created, the virtual table. */ -SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){ +SQLITE_PRIVATE int sqlite3Fts3InitHashTable( + sqlite3 *db, + Fts3Hash *pHash, + const char *zName +){ int rc = SQLITE_OK; - Fts3Hash *pHash = 0; - const sqlite3_tokenizer_module *pSimple = 0; - const sqlite3_tokenizer_module *pPorter = 0; -#ifndef SQLITE_DISABLE_FTS3_UNICODE - const sqlite3_tokenizer_module *pUnicode = 0; -#endif - -#ifdef SQLITE_ENABLE_ICU - const sqlite3_tokenizer_module *pIcu = 0; - sqlite3Fts3IcuTokenizerModule(&pIcu); -#endif - -#ifndef SQLITE_DISABLE_FTS3_UNICODE - sqlite3Fts3UnicodeTokenizer(&pUnicode); -#endif + void *p = (void *)pHash; + const int any = SQLITE_UTF8|SQLITE_DIRECTONLY; #ifdef SQLITE_TEST - rc = sqlite3Fts3InitTerm(db); - if( rc!=SQLITE_OK ) return rc; -#endif - - rc = sqlite3Fts3InitAux(db); - if( rc!=SQLITE_OK ) return rc; - - sqlite3Fts3SimpleTokenizerModule(&pSimple); - sqlite3Fts3PorterTokenizerModule(&pPorter); - - /* Allocate and initialize the hash-table used to store tokenizers. */ - pHash = sqlite3_malloc(sizeof(Fts3Hash)); - if( !pHash ){ + char *zTest = 0; + char *zTest2 = 0; + void *pdb = (void *)db; + zTest = sqlite3_mprintf("%s_test", zName); + zTest2 = sqlite3_mprintf("%s_internal_test", zName); + if( !zTest || !zTest2 ){ rc = SQLITE_NOMEM; - }else{ - sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); } - - /* Load the built-in tokenizers into the hash table */ - if( rc==SQLITE_OK ){ - if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple) - || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter) - -#ifndef SQLITE_DISABLE_FTS3_UNICODE - || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode) -#endif -#ifdef SQLITE_ENABLE_ICU - || (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu)) #endif - ){ - rc = SQLITE_NOMEM; - } - } + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0); + } + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0); + } #ifdef SQLITE_TEST - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3ExprInitTestInterface(db); + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zTest, -1, any, p, testFunc, 0, 0); } -#endif - - /* Create the virtual table wrapper around the hash-table and overload - ** the two scalar functions. If this is successful, register the - ** module with sqlite. - */ - if( SQLITE_OK==rc - && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer")) - && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) - && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1)) - && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1)) - && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2)) - && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1)) - ){ - rc = sqlite3_create_module_v2( - db, "fts3", &fts3Module, (void *)pHash, hashDestroy - ); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_module_v2( - db, "fts4", &fts3Module, (void *)pHash, 0 - ); - } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3InitTok(db, (void *)pHash); - } - return rc; + if( SQLITE_OK==rc ){ + rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0); } +#endif +#ifdef SQLITE_TEST + sqlite3_free(zTest); + sqlite3_free(zTest2); +#endif - /* An error has occurred. Delete the hash table and return the error code. */ - assert( rc!=SQLITE_OK ); - if( pHash ){ - sqlite3Fts3HashClear(pHash); - sqlite3_free(pHash); - } return rc; } +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_tokenizer.c **************************************/ +/************** Begin file fts3_tokenizer1.c *********************************/ /* -** Allocate an Fts3MultiSegReader for each token in the expression headed -** by pExpr. +** 2006 Oct 10 ** -** An Fts3SegReader object is a cursor that can seek or scan a range of -** entries within a single segment b-tree. An Fts3MultiSegReader uses multiple -** Fts3SegReader objects internally to provide an interface to seek or scan -** within the union of all segments of a b-tree. Hence the name. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** If the allocated Fts3MultiSegReader just seeks to a single entry in a -** segment b-tree (if the term is not a prefix or it is a prefix for which -** there exists prefix b-tree of the right length) then it may be traversed -** and merged incrementally. Otherwise, it has to be merged into an in-memory -** doclist and then traversed. +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** Implementation of the "simple" full-text-search tokenizer. */ -static void fts3EvalAllocateReaders( - Fts3Cursor *pCsr, /* FTS cursor handle */ - Fts3Expr *pExpr, /* Allocate readers for this expression */ - int *pnToken, /* OUT: Total number of tokens in phrase. */ - int *pnOr, /* OUT: Total number of OR nodes in expr. */ - int *pRc /* IN/OUT: Error code */ -){ - if( pExpr && SQLITE_OK==*pRc ){ - if( pExpr->eType==FTSQUERY_PHRASE ){ - int i; - int nToken = pExpr->pPhrase->nToken; - *pnToken += nToken; - for(i=0; ipPhrase->aToken[i]; - int rc = fts3TermSegReaderCursor(pCsr, - pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr - ); - if( rc!=SQLITE_OK ){ - *pRc = rc; - return; - } - } - assert( pExpr->pPhrase->iDoclistToken==0 ); - pExpr->pPhrase->iDoclistToken = -1; - }else{ - *pnOr += (pExpr->eType==FTSQUERY_OR); - fts3EvalAllocateReaders(pCsr, pExpr->pLeft, pnToken, pnOr, pRc); - fts3EvalAllocateReaders(pCsr, pExpr->pRight, pnToken, pnOr, pRc); - } - } -} /* -** Arguments pList/nList contain the doclist for token iToken of phrase p. -** It is merged into the main doclist stored in p->doclist.aAll/nAll. +** The code in this file is only compiled if: ** -** This function assumes that pList points to a buffer allocated using -** sqlite3_malloc(). This function takes responsibility for eventually -** freeing the buffer. +** * The FTS3 module is being built as an extension +** (in which case SQLITE_CORE is not defined), or ** -** SQLITE_OK is returned if successful, or SQLITE_NOMEM if an error occurs. +** * The FTS3 module is being built into the core of +** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). */ -static int fts3EvalPhraseMergeToken( - Fts3Table *pTab, /* FTS Table pointer */ - Fts3Phrase *p, /* Phrase to merge pList/nList into */ - int iToken, /* Token pList/nList corresponds to */ - char *pList, /* Pointer to doclist */ - int nList /* Number of bytes in pList */ -){ - int rc = SQLITE_OK; - assert( iToken!=p->iDoclistToken ); - - if( pList==0 ){ - sqlite3_free(p->doclist.aAll); - p->doclist.aAll = 0; - p->doclist.nAll = 0; - } +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - else if( p->iDoclistToken<0 ){ - p->doclist.aAll = pList; - p->doclist.nAll = nList; - } +/* #include */ +/* #include */ +/* #include */ +/* #include */ - else if( p->doclist.aAll==0 ){ - sqlite3_free(pList); - } +/* #include "fts3_tokenizer.h" */ - else { - char *pLeft; - char *pRight; - int nLeft; - int nRight; - int nDiff; +typedef struct simple_tokenizer { + sqlite3_tokenizer base; + char delim[128]; /* flag ASCII delimiters */ +} simple_tokenizer; - if( p->iDoclistTokendoclist.aAll; - nLeft = p->doclist.nAll; - pRight = pList; - nRight = nList; - nDiff = iToken - p->iDoclistToken; - }else{ - pRight = p->doclist.aAll; - nRight = p->doclist.nAll; - pLeft = pList; - nLeft = nList; - nDiff = p->iDoclistToken - iToken; - } +typedef struct simple_tokenizer_cursor { + sqlite3_tokenizer_cursor base; + const char *pInput; /* input we are tokenizing */ + int nBytes; /* size of the input */ + int iOffset; /* current position in pInput */ + int iToken; /* index of next token to be returned */ + char *pToken; /* storage for current token */ + int nTokenAllocated; /* space allocated to zToken buffer */ +} simple_tokenizer_cursor; - rc = fts3DoclistPhraseMerge( - pTab->bDescIdx, nDiff, pLeft, nLeft, &pRight, &nRight - ); - sqlite3_free(pLeft); - p->doclist.aAll = pRight; - p->doclist.nAll = nRight; - } - if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken; - return rc; +static int simpleDelim(simple_tokenizer *t, unsigned char c){ + return c<0x80 && t->delim[c]; +} +static int fts3_isalnum(int x){ + return (x>='0' && x<='9') || (x>='A' && x<='Z') || (x>='a' && x<='z'); } /* -** Load the doclist for phrase p into p->doclist.aAll/nAll. The loaded doclist -** does not take deferred tokens into account. -** -** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +** Create a new tokenizer instance. */ -static int fts3EvalPhraseLoad( - Fts3Cursor *pCsr, /* FTS Cursor handle */ - Fts3Phrase *p /* Phrase object */ +static int simpleCreate( + int argc, const char * const *argv, + sqlite3_tokenizer **ppTokenizer ){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int iToken; - int rc = SQLITE_OK; + simple_tokenizer *t; - for(iToken=0; rc==SQLITE_OK && iTokennToken; iToken++){ - Fts3PhraseToken *pToken = &p->aToken[iToken]; - assert( pToken->pDeferred==0 || pToken->pSegcsr==0 ); + t = (simple_tokenizer *) sqlite3_malloc(sizeof(*t)); + if( t==NULL ) return SQLITE_NOMEM; + memset(t, 0, sizeof(*t)); - if( pToken->pSegcsr ){ - int nThis = 0; - char *pThis = 0; - rc = fts3TermSelect(pTab, pToken, p->iColumn, &nThis, &pThis); - if( rc==SQLITE_OK ){ - rc = fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis); + /* TODO(shess) Delimiters need to remain the same from run to run, + ** else we need to reindex. One solution would be a meta-table to + ** track such information in the database, then we'd only want this + ** information on the initial create. + */ + if( argc>1 ){ + int i, n = (int)strlen(argv[1]); + for(i=0; i=0x80 ){ + sqlite3_free(t); + return SQLITE_ERROR; } + t->delim[ch] = 1; + } + } else { + /* Mark non-alphanumeric ASCII characters as delimiters */ + int i; + for(i=1; i<0x80; i++){ + t->delim[i] = !fts3_isalnum(i) ? -1 : 0; } - assert( pToken->pSegcsr==0 ); } - return rc; + *ppTokenizer = &t->base; + return SQLITE_OK; } /* -** This function is called on each phrase after the position lists for -** any deferred tokens have been loaded into memory. It updates the phrases -** current position list to include only those positions that are really -** instances of the phrase (after considering deferred tokens). If this -** means that the phrase does not appear in the current row, doclist.pList -** and doclist.nList are both zeroed. -** -** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. +** Destroy a tokenizer */ -static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ - int iToken; /* Used to iterate through phrase tokens */ - char *aPoslist = 0; /* Position list for deferred tokens */ - int nPoslist = 0; /* Number of bytes in aPoslist */ - int iPrev = -1; /* Token number of previous deferred token */ +static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ + sqlite3_free(pTokenizer); + return SQLITE_OK; +} - assert( pPhrase->doclist.bFreeList==0 ); +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is pInput[0..nBytes-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int simpleOpen( + sqlite3_tokenizer *pTokenizer, /* The tokenizer */ + const char *pInput, int nBytes, /* String to be tokenized */ + sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +){ + simple_tokenizer_cursor *c; - for(iToken=0; iTokennToken; iToken++){ - Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; - Fts3DeferredToken *pDeferred = pToken->pDeferred; + UNUSED_PARAMETER(pTokenizer); - if( pDeferred ){ - char *pList; - int nList; - int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); - if( rc!=SQLITE_OK ) return rc; + c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); + if( c==NULL ) return SQLITE_NOMEM; - if( pList==0 ){ - sqlite3_free(aPoslist); - pPhrase->doclist.pList = 0; - pPhrase->doclist.nList = 0; - return SQLITE_OK; + c->pInput = pInput; + if( pInput==0 ){ + c->nBytes = 0; + }else if( nBytes<0 ){ + c->nBytes = (int)strlen(pInput); + }else{ + c->nBytes = nBytes; + } + c->iOffset = 0; /* start tokenizing at the beginning */ + c->iToken = 0; + c->pToken = NULL; /* no space allocated, yet. */ + c->nTokenAllocated = 0; - }else if( aPoslist==0 ){ - aPoslist = pList; - nPoslist = nList; + *ppCursor = &c->base; + return SQLITE_OK; +} - }else{ - char *aOut = pList; - char *p1 = aPoslist; - char *p2 = aOut; +/* +** Close a tokenization cursor previously opened by a call to +** simpleOpen() above. +*/ +static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ + simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; + sqlite3_free(c->pToken); + sqlite3_free(c); + return SQLITE_OK; +} - assert( iPrev>=0 ); - fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2); - sqlite3_free(aPoslist); - aPoslist = pList; - nPoslist = (int)(aOut - aPoslist); - if( nPoslist==0 ){ - sqlite3_free(aPoslist); - pPhrase->doclist.pList = 0; - pPhrase->doclist.nList = 0; - return SQLITE_OK; - } - } - iPrev = iToken; - } - } +/* +** Extract the next token from a tokenization cursor. The cursor must +** have been opened by a prior call to simpleOpen(). +*/ +static int simpleNext( + sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ + const char **ppToken, /* OUT: *ppToken is the token text */ + int *pnBytes, /* OUT: Number of bytes in token */ + int *piStartOffset, /* OUT: Starting offset of token */ + int *piEndOffset, /* OUT: Ending offset of token */ + int *piPosition /* OUT: Position integer of token */ +){ + simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; + simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; + unsigned char *p = (unsigned char *)c->pInput; - if( iPrev>=0 ){ - int nMaxUndeferred = pPhrase->iDoclistToken; - if( nMaxUndeferred<0 ){ - pPhrase->doclist.pList = aPoslist; - pPhrase->doclist.nList = nPoslist; - pPhrase->doclist.iDocid = pCsr->iPrevId; - pPhrase->doclist.bFreeList = 1; - }else{ - int nDistance; - char *p1; - char *p2; - char *aOut; + while( c->iOffsetnBytes ){ + int iStartOffset; - if( nMaxUndeferred>iPrev ){ - p1 = aPoslist; - p2 = pPhrase->doclist.pList; - nDistance = nMaxUndeferred - iPrev; - }else{ - p1 = pPhrase->doclist.pList; - p2 = aPoslist; - nDistance = iPrev - nMaxUndeferred; - } + /* Scan past delimiter characters */ + while( c->iOffsetnBytes && simpleDelim(t, p[c->iOffset]) ){ + c->iOffset++; + } - aOut = (char *)sqlite3_malloc(nPoslist+8); - if( !aOut ){ - sqlite3_free(aPoslist); - return SQLITE_NOMEM; + /* Count non-delimiter characters. */ + iStartOffset = c->iOffset; + while( c->iOffsetnBytes && !simpleDelim(t, p[c->iOffset]) ){ + c->iOffset++; + } + + if( c->iOffset>iStartOffset ){ + int i, n = c->iOffset-iStartOffset; + if( n>c->nTokenAllocated ){ + char *pNew; + c->nTokenAllocated = n+20; + pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->pToken = pNew; } - - pPhrase->doclist.pList = aOut; - if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){ - pPhrase->doclist.bFreeList = 1; - pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList); - }else{ - sqlite3_free(aOut); - pPhrase->doclist.pList = 0; - pPhrase->doclist.nList = 0; + for(i=0; ipToken[i] = (char)((ch>='A' && ch<='Z') ? ch-'A'+'a' : ch); } - sqlite3_free(aPoslist); + *ppToken = c->pToken; + *pnBytes = n; + *piStartOffset = iStartOffset; + *piEndOffset = c->iOffset; + *piPosition = c->iToken++; + + return SQLITE_OK; } } - - return SQLITE_OK; + return SQLITE_DONE; } /* -** Maximum number of tokens a phrase may have to be considered for the -** incremental doclists strategy. +** The set of routines that implement the simple tokenizer */ -#define MAX_INCR_PHRASE_TOKENS 4 +static const sqlite3_tokenizer_module simpleTokenizerModule = { + 0, + simpleCreate, + simpleDestroy, + simpleOpen, + simpleClose, + simpleNext, + 0, +}; /* -** This function is called for each Fts3Phrase in a full-text query -** expression to initialize the mechanism for returning rows. Once this -** function has been called successfully on an Fts3Phrase, it may be -** used with fts3EvalPhraseNext() to iterate through the matching docids. +** Allocate a new simple tokenizer. Return a pointer to the new +** tokenizer in *ppModule +*/ +SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule( + sqlite3_tokenizer_module const**ppModule +){ + *ppModule = &simpleTokenizerModule; +} + +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_tokenizer1.c *************************************/ +/************** Begin file fts3_tokenize_vtab.c ******************************/ +/* +** 2013 Apr 22 ** -** If parameter bOptOk is true, then the phrase may (or may not) use the -** incremental loading strategy. Otherwise, the entire doclist is loaded into -** memory within this call. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code for the "fts3tokenize" virtual table module. +** An fts3tokenize virtual table is created as follows: +** +** CREATE VIRTUAL TABLE USING fts3tokenize( +** , , ... +** ); +** +** The table created has the following schema: +** +** CREATE TABLE (input, token, start, end, position) +** +** When queried, the query must include a WHERE clause of type: +** +** input = +** +** The virtual table module tokenizes this , using the FTS3 +** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE +** statement and returns one row for each token in the result. With +** fields set as follows: +** +** input: Always set to a copy of +** token: A token from the input. +** start: Byte offset of the token within the input . +** end: Byte offset of the byte immediately following the end of the +** token within the input string. +** pos: Token offset of token within input. ** -** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ -static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int rc = SQLITE_OK; /* Error code */ - int i; +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - /* Determine if doclists may be loaded from disk incrementally. This is - ** possible if the bOptOk argument is true, the FTS doclists will be - ** scanned in forward order, and the phrase consists of - ** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first" - ** tokens or prefix tokens that cannot use a prefix-index. */ - int bHaveIncr = 0; - int bIncrOk = (bOptOk - && pCsr->bDesc==pTab->bDescIdx - && p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0 -#ifdef SQLITE_TEST - && pTab->bNoIncrDoclist==0 -#endif - ); - for(i=0; bIncrOk==1 && inToken; i++){ - Fts3PhraseToken *pToken = &p->aToken[i]; - if( pToken->bFirst || (pToken->pSegcsr!=0 && !pToken->pSegcsr->bLookup) ){ - bIncrOk = 0; - } - if( pToken->pSegcsr ) bHaveIncr = 1; - } +/* #include */ +/* #include */ - if( bIncrOk && bHaveIncr ){ - /* Use the incremental approach. */ - int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); - for(i=0; rc==SQLITE_OK && inToken; i++){ - Fts3PhraseToken *pToken = &p->aToken[i]; - Fts3MultiSegReader *pSegcsr = pToken->pSegcsr; - if( pSegcsr ){ - rc = sqlite3Fts3MsrIncrStart(pTab, pSegcsr, iCol, pToken->z, pToken->n); - } - } - p->bIncr = 1; - }else{ - /* Load the full doclist for the phrase into memory. */ - rc = fts3EvalPhraseLoad(pCsr, p); - p->bIncr = 0; - } +typedef struct Fts3tokTable Fts3tokTable; +typedef struct Fts3tokCursor Fts3tokCursor; - assert( rc!=SQLITE_OK || p->nToken<1 || p->aToken[0].pSegcsr==0 || p->bIncr ); - return rc; -} +/* +** Virtual table structure. +*/ +struct Fts3tokTable { + sqlite3_vtab base; /* Base class used by SQLite core */ + const sqlite3_tokenizer_module *pMod; + sqlite3_tokenizer *pTok; +}; /* -** This function is used to iterate backwards (from the end to start) -** through doclists. It is used by this module to iterate through phrase -** doclists in reverse and by the fts3_write.c module to iterate through -** pending-terms lists when writing to databases with "order=desc". -** -** The doclist may be sorted in ascending (parameter bDescIdx==0) or -** descending (parameter bDescIdx==1) order of docid. Regardless, this -** function iterates from the end of the doclist to the beginning. +** Virtual table cursor structure. */ -SQLITE_PRIVATE void sqlite3Fts3DoclistPrev( - int bDescIdx, /* True if the doclist is desc */ - char *aDoclist, /* Pointer to entire doclist */ - int nDoclist, /* Length of aDoclist in bytes */ - char **ppIter, /* IN/OUT: Iterator pointer */ - sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ - int *pnList, /* OUT: List length pointer */ - u8 *pbEof /* OUT: End-of-file flag */ -){ - char *p = *ppIter; +struct Fts3tokCursor { + sqlite3_vtab_cursor base; /* Base class used by SQLite core */ + char *zInput; /* Input string */ + sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */ + int iRowid; /* Current 'rowid' value */ + const char *zToken; /* Current 'token' value */ + int nToken; /* Size of zToken in bytes */ + int iStart; /* Current 'start' value */ + int iEnd; /* Current 'end' value */ + int iPos; /* Current 'pos' value */ +}; - assert( nDoclist>0 ); - assert( *pbEof==0 ); - assert( p || *piDocid==0 ); - assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) ); +/* +** Query FTS for the tokenizer implementation named zName. +*/ +static int fts3tokQueryTokenizer( + Fts3Hash *pHash, + const char *zName, + const sqlite3_tokenizer_module **pp, + char **pzErr +){ + sqlite3_tokenizer_module *p; + int nName = (int)strlen(zName); - if( p==0 ){ - sqlite3_int64 iDocid = 0; - char *pNext = 0; - char *pDocid = aDoclist; - char *pEnd = &aDoclist[nDoclist]; - int iMul = 1; + p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); + if( !p ){ + sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", zName); + return SQLITE_ERROR; + } - while( pDocid0 ); - assert( *pbEof==0 ); - assert( p || *piDocid==0 ); - assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) ); + rc = sqlite3_declare_vtab(db, FTS3_TOK_SCHEMA); + if( rc!=SQLITE_OK ) return rc; - if( p==0 ){ - p = aDoclist; - p += sqlite3Fts3GetVarint(p, piDocid); - }else{ - fts3PoslistCopy(0, &p); - while( p<&aDoclist[nDoclist] && *p==0 ) p++; - if( p>=&aDoclist[nDoclist] ){ - *pbEof = 1; + nDequote = argc-3; + rc = fts3tokDequoteArray(nDequote, &argv[3], &azDequote); + + if( rc==SQLITE_OK ){ + const char *zModule; + if( nDequote<1 ){ + zModule = "simple"; }else{ - sqlite3_int64 iVar; - p += sqlite3Fts3GetVarint(p, &iVar); - *piDocid += ((bDescIdx ? -1 : 1) * iVar); + zModule = azDequote[0]; } + rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr); } - *ppIter = p; -} + assert( (rc==SQLITE_OK)==(pMod!=0) ); + if( rc==SQLITE_OK ){ + const char * const *azArg = 0; + if( nDequote>1 ) azArg = (const char * const *)&azDequote[1]; + rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok); + } -/* -** Advance the iterator pDL to the next entry in pDL->aAll/nAll. Set *pbEof -** to true if EOF is reached. -*/ -static void fts3EvalDlPhraseNext( - Fts3Table *pTab, - Fts3Doclist *pDL, - u8 *pbEof -){ - char *pIter; /* Used to iterate through aAll */ - char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */ - - if( pDL->pNextDocid ){ - pIter = pDL->pNextDocid; - }else{ - pIter = pDL->aAll; + if( rc==SQLITE_OK ){ + pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable)); + if( pTab==0 ){ + rc = SQLITE_NOMEM; + } } - if( pIter>=pEnd ){ - /* We have already reached the end of this doclist. EOF. */ - *pbEof = 1; + if( rc==SQLITE_OK ){ + memset(pTab, 0, sizeof(Fts3tokTable)); + pTab->pMod = pMod; + pTab->pTok = pTok; + *ppVtab = &pTab->base; }else{ - sqlite3_int64 iDelta; - pIter += sqlite3Fts3GetVarint(pIter, &iDelta); - if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){ - pDL->iDocid += iDelta; - }else{ - pDL->iDocid -= iDelta; + if( pTok ){ + pMod->xDestroy(pTok); } - pDL->pList = pIter; - fts3PoslistCopy(0, &pIter); - pDL->nList = (int)(pIter - pDL->pList); - - /* pIter now points just past the 0x00 that terminates the position- - ** list for document pDL->iDocid. However, if this position-list was - ** edited in place by fts3EvalNearTrim(), then pIter may not actually - ** point to the start of the next docid value. The following line deals - ** with this case by advancing pIter past the zero-padding added by - ** fts3EvalNearTrim(). */ - while( pIterpNextDocid = pIter; - assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter ); - *pbEof = 0; } + + sqlite3_free(azDequote); + return rc; } /* -** Helper type used by fts3EvalIncrPhraseNext() and incrPhraseTokenNext(). +** This function does the work for both the xDisconnect and xDestroy methods. +** These tables have no persistent representation of their own, so xDisconnect +** and xDestroy are identical operations. */ -typedef struct TokenDoclist TokenDoclist; -struct TokenDoclist { - int bIgnore; - sqlite3_int64 iDocid; - char *pList; - int nList; -}; +static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){ + Fts3tokTable *pTab = (Fts3tokTable *)pVtab; + + pTab->pMod->xDestroy(pTab->pTok); + sqlite3_free(pTab); + return SQLITE_OK; +} /* -** Token pToken is an incrementally loaded token that is part of a -** multi-token phrase. Advance it to the next matching document in the -** database and populate output variable *p with the details of the new -** entry. Or, if the iterator has reached EOF, set *pbEof to true. -** -** If an error occurs, return an SQLite error code. Otherwise, return -** SQLITE_OK. +** xBestIndex - Analyze a WHERE and ORDER BY clause. */ -static int incrPhraseTokenNext( - Fts3Table *pTab, /* Virtual table handle */ - Fts3Phrase *pPhrase, /* Phrase to advance token of */ - int iToken, /* Specific token to advance */ - TokenDoclist *p, /* OUT: Docid and doclist for new entry */ - u8 *pbEof /* OUT: True if iterator is at EOF */ +static int fts3tokBestIndexMethod( + sqlite3_vtab *pVTab, + sqlite3_index_info *pInfo ){ - int rc = SQLITE_OK; + int i; + UNUSED_PARAMETER(pVTab); - if( pPhrase->iDoclistToken==iToken ){ - assert( p->bIgnore==0 ); - assert( pPhrase->aToken[iToken].pSegcsr==0 ); - fts3EvalDlPhraseNext(pTab, &pPhrase->doclist, pbEof); - p->pList = pPhrase->doclist.pList; - p->nList = pPhrase->doclist.nList; - p->iDocid = pPhrase->doclist.iDocid; - }else{ - Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; - assert( pToken->pDeferred==0 ); - assert( pToken->pSegcsr || pPhrase->iDoclistToken>=0 ); - if( pToken->pSegcsr ){ - assert( p->bIgnore==0 ); - rc = sqlite3Fts3MsrIncrNext( - pTab, pToken->pSegcsr, &p->iDocid, &p->pList, &p->nList - ); - if( p->pList==0 ) *pbEof = 1; - }else{ - p->bIgnore = 1; + for(i=0; inConstraint; i++){ + if( pInfo->aConstraint[i].usable + && pInfo->aConstraint[i].iColumn==0 + && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + pInfo->idxNum = 1; + pInfo->aConstraintUsage[i].argvIndex = 1; + pInfo->aConstraintUsage[i].omit = 1; + pInfo->estimatedCost = 1; + return SQLITE_OK; } } - return rc; -} + pInfo->idxNum = 0; + assert( pInfo->estimatedCost>1000000.0 ); + return SQLITE_OK; +} /* -** The phrase iterator passed as the second argument: -** -** * features at least one token that uses an incremental doclist, and -** -** * does not contain any deferred tokens. -** -** Advance it to the next matching documnent in the database and populate -** the Fts3Doclist.pList and nList fields. -** -** If there is no "next" entry and no error occurs, then *pbEof is set to -** 1 before returning. Otherwise, if no error occurs and the iterator is -** successfully advanced, *pbEof is set to 0. -** -** If an error occurs, return an SQLite error code. Otherwise, return -** SQLITE_OK. +** xOpen - Open a cursor. */ -static int fts3EvalIncrPhraseNext( - Fts3Cursor *pCsr, /* FTS Cursor handle */ - Fts3Phrase *p, /* Phrase object to advance to next docid */ - u8 *pbEof /* OUT: Set to 1 if EOF */ -){ - int rc = SQLITE_OK; - Fts3Doclist *pDL = &p->doclist; - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - u8 bEof = 0; +static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ + Fts3tokCursor *pCsr; + UNUSED_PARAMETER(pVTab); - /* This is only called if it is guaranteed that the phrase has at least - ** one incremental token. In which case the bIncr flag is set. */ - assert( p->bIncr==1 ); + pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(Fts3tokCursor)); - if( p->nToken==1 && p->bIncr ){ - rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, - &pDL->iDocid, &pDL->pList, &pDL->nList - ); - if( pDL->pList==0 ) bEof = 1; - }else{ - int bDescDoclist = pCsr->bDesc; - struct TokenDoclist a[MAX_INCR_PHRASE_TOKENS]; + *ppCsr = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} - memset(a, 0, sizeof(a)); - assert( p->nToken<=MAX_INCR_PHRASE_TOKENS ); - assert( p->iDoclistTokenpCsr ){ + Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab); + pTab->pMod->xClose(pCsr->pCsr); + pCsr->pCsr = 0; + } + sqlite3_free(pCsr->zInput); + pCsr->zInput = 0; + pCsr->zToken = 0; + pCsr->nToken = 0; + pCsr->iStart = 0; + pCsr->iEnd = 0; + pCsr->iPos = 0; + pCsr->iRowid = 0; +} - while( bEof==0 ){ - int bMaxSet = 0; - sqlite3_int64 iMax = 0; /* Largest docid for all iterators */ - int i; /* Used to iterate through tokens */ +/* +** xClose - Close a cursor. +*/ +static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - /* Advance the iterator for each token in the phrase once. */ - for(i=0; rc==SQLITE_OK && inToken && bEof==0; i++){ - rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); - if( a[i].bIgnore==0 && (bMaxSet==0 || DOCID_CMP(iMax, a[i].iDocid)<0) ){ - iMax = a[i].iDocid; - bMaxSet = 1; - } - } - assert( rc!=SQLITE_OK || (p->nToken>=1 && a[p->nToken-1].bIgnore==0) ); - assert( rc!=SQLITE_OK || bMaxSet ); + fts3tokResetCursor(pCsr); + sqlite3_free(pCsr); + return SQLITE_OK; +} - /* Keep advancing iterators until they all point to the same document */ - for(i=0; inToken; i++){ - while( rc==SQLITE_OK && bEof==0 - && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0 - ){ - rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof); - if( DOCID_CMP(a[i].iDocid, iMax)>0 ){ - iMax = a[i].iDocid; - i = 0; - } - } - } +/* +** xNext - Advance the cursor to the next row, if any. +*/ +static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); + int rc; /* Return code */ - /* Check if the current entries really are a phrase match */ - if( bEof==0 ){ - int nList = 0; - int nByte = a[p->nToken-1].nList; - char *aDoclist = sqlite3_malloc(nByte+1); - if( !aDoclist ) return SQLITE_NOMEM; - memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); + pCsr->iRowid++; + rc = pTab->pMod->xNext(pCsr->pCsr, + &pCsr->zToken, &pCsr->nToken, + &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos + ); - for(i=0; i<(p->nToken-1); i++){ - if( a[i].bIgnore==0 ){ - char *pL = a[i].pList; - char *pR = aDoclist; - char *pOut = aDoclist; - int nDist = p->nToken-1-i; - int res = fts3PoslistPhraseMerge(&pOut, nDist, 0, 1, &pL, &pR); - if( res==0 ) break; - nList = (int)(pOut - aDoclist); - } - } - if( i==(p->nToken-1) ){ - pDL->iDocid = iMax; - pDL->pList = aDoclist; - pDL->nList = nList; - pDL->bFreeList = 1; - break; - } - sqlite3_free(aDoclist); - } - } + if( rc!=SQLITE_OK ){ + fts3tokResetCursor(pCsr); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; } - *pbEof = bEof; return rc; } /* -** Attempt to move the phrase iterator to point to the next matching docid. -** If an error occurs, return an SQLite error code. Otherwise, return -** SQLITE_OK. -** -** If there is no "next" entry and no error occurs, then *pbEof is set to -** 1 before returning. Otherwise, if no error occurs and the iterator is -** successfully advanced, *pbEof is set to 0. +** xFilter - Initialize a cursor to point at the start of its data. */ -static int fts3EvalPhraseNext( - Fts3Cursor *pCsr, /* FTS Cursor handle */ - Fts3Phrase *p, /* Phrase object to advance to next docid */ - u8 *pbEof /* OUT: Set to 1 if EOF */ +static int fts3tokFilterMethod( + sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ + int idxNum, /* Strategy index */ + const char *idxStr, /* Unused */ + int nVal, /* Number of elements in apVal */ + sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ - int rc = SQLITE_OK; - Fts3Doclist *pDL = &p->doclist; - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_ERROR; + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); + UNUSED_PARAMETER(idxStr); + UNUSED_PARAMETER(nVal); - if( p->bIncr ){ - rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof); - }else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){ - sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll, - &pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof - ); - pDL->pList = pDL->pNextDocid; - }else{ - fts3EvalDlPhraseNext(pTab, pDL, pbEof); + fts3tokResetCursor(pCsr); + if( idxNum==1 ){ + const char *zByte = (const char *)sqlite3_value_text(apVal[0]); + int nByte = sqlite3_value_bytes(apVal[0]); + pCsr->zInput = sqlite3_malloc64(nByte+1); + if( pCsr->zInput==0 ){ + rc = SQLITE_NOMEM; + }else{ + if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte); + pCsr->zInput[nByte] = 0; + rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr); + if( rc==SQLITE_OK ){ + pCsr->pCsr->pTokenizer = pTab->pTok; + } + } } - return rc; + if( rc!=SQLITE_OK ) return rc; + return fts3tokNextMethod(pCursor); } /* -** -** If *pRc is not SQLITE_OK when this function is called, it is a no-op. -** Otherwise, fts3EvalPhraseStart() is called on all phrases within the -** expression. Also the Fts3Expr.bDeferred variable is set to true for any -** expressions for which all descendent tokens are deferred. -** -** If parameter bOptOk is zero, then it is guaranteed that the -** Fts3Phrase.doclist.aAll/nAll variables contain the entire doclist for -** each phrase in the expression (subject to deferred token processing). -** Or, if bOptOk is non-zero, then one or more tokens within the expression -** may be loaded incrementally, meaning doclist.aAll/nAll is not available. -** -** If an error occurs within this function, *pRc is set to an SQLite error -** code before returning. +** xEof - Return true if the cursor is at EOF, or false otherwise. */ -static void fts3EvalStartReaders( - Fts3Cursor *pCsr, /* FTS Cursor handle */ - Fts3Expr *pExpr, /* Expression to initialize phrases in */ - int *pRc /* IN/OUT: Error code */ +static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + return (pCsr->zToken==0); +} + +/* +** xColumn - Return a column value. +*/ +static int fts3tokColumnMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ + int iCol /* Index of column to read value from */ ){ - if( pExpr && SQLITE_OK==*pRc ){ - if( pExpr->eType==FTSQUERY_PHRASE ){ - int nToken = pExpr->pPhrase->nToken; - if( nToken ){ - int i; - for(i=0; ipPhrase->aToken[i].pDeferred==0 ) break; - } - pExpr->bDeferred = (i==nToken); - } - *pRc = fts3EvalPhraseStart(pCsr, 1, pExpr->pPhrase); - }else{ - fts3EvalStartReaders(pCsr, pExpr->pLeft, pRc); - fts3EvalStartReaders(pCsr, pExpr->pRight, pRc); - pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred); - } + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + + /* CREATE TABLE x(input, token, start, end, position) */ + switch( iCol ){ + case 0: + sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT); + break; + case 1: + sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT); + break; + case 2: + sqlite3_result_int(pCtx, pCsr->iStart); + break; + case 3: + sqlite3_result_int(pCtx, pCsr->iEnd); + break; + default: + assert( iCol==4 ); + sqlite3_result_int(pCtx, pCsr->iPos); + break; } + return SQLITE_OK; } /* -** An array of the following structures is assembled as part of the process -** of selecting tokens to defer before the query starts executing (as part -** of the xFilter() method). There is one element in the array for each -** token in the FTS expression. -** -** Tokens are divided into AND/NEAR clusters. All tokens in a cluster belong -** to phrases that are connected only by AND and NEAR operators (not OR or -** NOT). When determining tokens to defer, each AND/NEAR cluster is considered -** separately. The root of a tokens AND/NEAR cluster is stored in -** Fts3TokenAndCost.pRoot. +** xRowid - Return the current rowid for the cursor. */ -typedef struct Fts3TokenAndCost Fts3TokenAndCost; -struct Fts3TokenAndCost { - Fts3Phrase *pPhrase; /* The phrase the token belongs to */ - int iToken; /* Position of token in phrase */ - Fts3PhraseToken *pToken; /* The token itself */ - Fts3Expr *pRoot; /* Root of NEAR/AND cluster */ - int nOvfl; /* Number of overflow pages to load doclist */ - int iCol; /* The column the token must match */ -}; +static int fts3tokRowidMethod( + sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ + sqlite_int64 *pRowid /* OUT: Rowid value */ +){ + Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + *pRowid = (sqlite3_int64)pCsr->iRowid; + return SQLITE_OK; +} /* -** This function is used to populate an allocated Fts3TokenAndCost array. -** -** If *pRc is not SQLITE_OK when this function is called, it is a no-op. -** Otherwise, if an error occurs during execution, *pRc is set to an -** SQLite error code. +** Register the fts3tok module with database connection db. Return SQLITE_OK +** if successful or an error code if sqlite3_create_module() fails. */ -static void fts3EvalTokenCosts( - Fts3Cursor *pCsr, /* FTS Cursor handle */ - Fts3Expr *pRoot, /* Root of current AND/NEAR cluster */ - Fts3Expr *pExpr, /* Expression to consider */ - Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ - Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ - int *pRc /* IN/OUT: Error code */ -){ - if( *pRc==SQLITE_OK ){ - if( pExpr->eType==FTSQUERY_PHRASE ){ - Fts3Phrase *pPhrase = pExpr->pPhrase; - int i; - for(i=0; *pRc==SQLITE_OK && inToken; i++){ - Fts3TokenAndCost *pTC = (*ppTC)++; - pTC->pPhrase = pPhrase; - pTC->iToken = i; - pTC->pRoot = pRoot; - pTC->pToken = &pPhrase->aToken[i]; - pTC->iCol = pPhrase->iColumn; - *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); - } - }else if( pExpr->eType!=FTSQUERY_NOT ){ - assert( pExpr->eType==FTSQUERY_OR - || pExpr->eType==FTSQUERY_AND - || pExpr->eType==FTSQUERY_NEAR - ); - assert( pExpr->pLeft && pExpr->pRight ); - if( pExpr->eType==FTSQUERY_OR ){ - pRoot = pExpr->pLeft; - **ppOr = pRoot; - (*ppOr)++; - } - fts3EvalTokenCosts(pCsr, pRoot, pExpr->pLeft, ppTC, ppOr, pRc); - if( pExpr->eType==FTSQUERY_OR ){ - pRoot = pExpr->pRight; - **ppOr = pRoot; - (*ppOr)++; - } - fts3EvalTokenCosts(pCsr, pRoot, pExpr->pRight, ppTC, ppOr, pRc); - } - } +SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestroy)(void*)){ + static const sqlite3_module fts3tok_module = { + 0, /* iVersion */ + fts3tokConnectMethod, /* xCreate */ + fts3tokConnectMethod, /* xConnect */ + fts3tokBestIndexMethod, /* xBestIndex */ + fts3tokDisconnectMethod, /* xDisconnect */ + fts3tokDisconnectMethod, /* xDestroy */ + fts3tokOpenMethod, /* xOpen */ + fts3tokCloseMethod, /* xClose */ + fts3tokFilterMethod, /* xFilter */ + fts3tokNextMethod, /* xNext */ + fts3tokEofMethod, /* xEof */ + fts3tokColumnMethod, /* xColumn */ + fts3tokRowidMethod, /* xRowid */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindFunction */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ + }; + int rc; /* Return code */ + + rc = sqlite3_create_module_v2( + db, "fts3tokenize", &fts3tok_module, (void*)pHash, xDestroy + ); + return rc; } +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + +/************** End of fts3_tokenize_vtab.c **********************************/ +/************** Begin file fts3_write.c **************************************/ /* -** Determine the average document (row) size in pages. If successful, -** write this value to *pnPage and return SQLITE_OK. Otherwise, return -** an SQLite error code. +** 2009 Oct 23 ** -** The average document size in pages is calculated by first calculating -** determining the average size in bytes, B. If B is less than the amount -** of data that will fit on a single leaf page of an intkey table in -** this database, then the average docsize is 1. Otherwise, it is 1 plus -** the number of overflow pages consumed by a record B bytes in size. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file is part of the SQLite FTS3 extension module. Specifically, +** this file contains code to insert, update and delete rows from FTS3 +** tables. It also contains code to merge FTS3 b-tree segments. Some +** of the sub-routines used to merge segments are also used by the query +** code in fts3.c. */ -static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){ - if( pCsr->nRowAvg==0 ){ - /* The average document size, which is required to calculate the cost - ** of each doclist, has not yet been determined. Read the required - ** data from the %_stat table to calculate it. - ** - ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 - ** varints, where nCol is the number of columns in the FTS3 table. - ** The first varint is the number of documents currently stored in - ** the table. The following nCol varints contain the total amount of - ** data stored in all rows of each column of the table, from left - ** to right. - */ - int rc; - Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; - sqlite3_stmt *pStmt; - sqlite3_int64 nDoc = 0; - sqlite3_int64 nByte = 0; - const char *pEnd; - const char *a; - rc = sqlite3Fts3SelectDoctotal(p, &pStmt); - if( rc!=SQLITE_OK ) return rc; - a = sqlite3_column_blob(pStmt, 0); - assert( a ); +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - pEnd = &a[sqlite3_column_bytes(pStmt, 0)]; - a += sqlite3Fts3GetVarint(a, &nDoc); - while( a */ +/* #include */ +/* #include */ +/* #include */ - pCsr->nDoc = nDoc; - pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz); - assert( pCsr->nRowAvg>0 ); - rc = sqlite3_reset(pStmt); - if( rc!=SQLITE_OK ) return rc; - } +#define FTS_MAX_APPENDABLE_HEIGHT 16 - *pnPage = pCsr->nRowAvg; - return SQLITE_OK; -} +/* +** When full-text index nodes are loaded from disk, the buffer that they +** are loaded into has the following number of bytes of padding at the end +** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer +** of 920 bytes is allocated for it. +** +** This means that if we have a pointer into a buffer containing node data, +** it is always safe to read up to two varints from it without risking an +** overread, even if the node data is corrupted. +*/ +#define FTS3_NODE_PADDING (FTS3_VARINT_MAX*2) /* -** This function is called to select the tokens (if any) that will be -** deferred. The array aTC[] has already been populated when this is -** called. +** Under certain circumstances, b-tree nodes (doclists) can be loaded into +** memory incrementally instead of all at once. This can be a big performance +** win (reduced IO and CPU) if SQLite stops calling the virtual table xNext() +** method before retrieving all query results (as may happen, for example, +** if a query has a LIMIT clause). ** -** This function is called once for each AND/NEAR cluster in the -** expression. Each invocation determines which tokens to defer within -** the cluster with root node pRoot. See comments above the definition -** of struct Fts3TokenAndCost for more details. +** Incremental loading is used for b-tree nodes FTS3_NODE_CHUNK_THRESHOLD +** bytes and larger. Nodes are loaded in chunks of FTS3_NODE_CHUNKSIZE bytes. +** The code is written so that the hard lower-limit for each of these values +** is 1. Clearly such small values would be inefficient, but can be useful +** for testing purposes. ** -** If no error occurs, SQLITE_OK is returned and sqlite3Fts3DeferToken() -** called on each token to defer. Otherwise, an SQLite error code is -** returned. +** If this module is built with SQLITE_TEST defined, these constants may +** be overridden at runtime for testing purposes. File fts3_test.c contains +** a Tcl interface to read and write the values. */ -static int fts3EvalSelectDeferred( - Fts3Cursor *pCsr, /* FTS Cursor handle */ - Fts3Expr *pRoot, /* Consider tokens with this root node */ - Fts3TokenAndCost *aTC, /* Array of expression tokens and costs */ - int nTC /* Number of entries in aTC[] */ -){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int nDocSize = 0; /* Number of pages per doc loaded */ - int rc = SQLITE_OK; /* Return code */ - int ii; /* Iterator variable for various purposes */ - int nOvfl = 0; /* Total overflow pages used by doclists */ - int nToken = 0; /* Total number of tokens in cluster */ - - int nMinEst = 0; /* The minimum count for any phrase so far. */ - int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ - - /* Tokens are never deferred for FTS tables created using the content=xxx - ** option. The reason being that it is not guaranteed that the content - ** table actually contains the same data as the index. To prevent this from - ** causing any problems, the deferred token optimization is completely - ** disabled for content=xxx tables. */ - if( pTab->zContentTbl ){ - return SQLITE_OK; - } - - /* Count the tokens in this AND/NEAR cluster. If none of the doclists - ** associated with the tokens spill onto overflow pages, or if there is - ** only 1 token, exit early. No tokens to defer in this case. */ - for(ii=0; ii0 ); +/* +** The values that may be meaningfully bound to the :1 parameter in +** statements SQL_REPLACE_STAT and SQL_SELECT_STAT. +*/ +#define FTS_STAT_DOCTOTAL 0 +#define FTS_STAT_INCRMERGEHINT 1 +#define FTS_STAT_AUTOINCRMERGE 2 +/* +** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic +** and incremental merge operation that takes place. This is used for +** debugging FTS only, it should not usually be turned on in production +** systems. +*/ +#ifdef FTS3_LOG_MERGES +static void fts3LogMerge(int nMerge, sqlite3_int64 iAbsLevel){ + sqlite3_log(SQLITE_OK, "%d-way merge from level %d", nMerge, (int)iAbsLevel); +} +#else +#define fts3LogMerge(x, y) +#endif - /* Iterate through all tokens in this AND/NEAR cluster, in ascending order - ** of the number of overflow pages that will be loaded by the pager layer - ** to retrieve the entire doclist for the token from the full-text index. - ** Load the doclists for tokens that are either: - ** - ** a. The cheapest token in the entire query (i.e. the one visited by the - ** first iteration of this loop), or - ** - ** b. Part of a multi-token phrase. - ** - ** After each token doclist is loaded, merge it with the others from the - ** same phrase and count the number of documents that the merged doclist - ** contains. Set variable "nMinEst" to the smallest number of documents in - ** any phrase doclist for which 1 or more token doclists have been loaded. - ** Let nOther be the number of other phrases for which it is certain that - ** one or more tokens will not be deferred. - ** - ** Then, for each token, defer it if loading the doclist would result in - ** loading N or more overflow pages into memory, where N is computed as: - ** - ** (nMinEst + 4^nOther - 1) / (4^nOther) - */ - for(ii=0; iinOvfl) - ){ - pTC = &aTC[iTC]; - } - } - assert( pTC ); +typedef struct PendingList PendingList; +typedef struct SegmentNode SegmentNode; +typedef struct SegmentWriter SegmentWriter; - if( ii && pTC->nOvfl>=((nMinEst+(nLoad4/4)-1)/(nLoad4/4))*nDocSize ){ - /* The number of overflow pages to load for this (and therefore all - ** subsequent) tokens is greater than the estimated number of pages - ** that will be loaded if all subsequent tokens are deferred. - */ - Fts3PhraseToken *pToken = pTC->pToken; - rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); - fts3SegReaderCursorFree(pToken->pSegcsr); - pToken->pSegcsr = 0; - }else{ - /* Set nLoad4 to the value of (4^nOther) for the next iteration of the - ** for-loop. Except, limit the value to 2^24 to prevent it from - ** overflowing the 32-bit integer it is stored in. */ - if( ii<12 ) nLoad4 = nLoad4*4; +/* +** An instance of the following data structure is used to build doclists +** incrementally. See function fts3PendingListAppend() for details. +*/ +struct PendingList { + int nData; + char *aData; + int nSpace; + sqlite3_int64 iLastDocid; + sqlite3_int64 iLastCol; + sqlite3_int64 iLastPos; +}; - if( ii==0 || (pTC->pPhrase->nToken>1 && ii!=nToken-1) ){ - /* Either this is the cheapest token in the entire query, or it is - ** part of a multi-token phrase. Either way, the entire doclist will - ** (eventually) be loaded into memory. It may as well be now. */ - Fts3PhraseToken *pToken = pTC->pToken; - int nList = 0; - char *pList = 0; - rc = fts3TermSelect(pTab, pToken, pTC->iCol, &nList, &pList); - assert( rc==SQLITE_OK || pList==0 ); - if( rc==SQLITE_OK ){ - rc = fts3EvalPhraseMergeToken( - pTab, pTC->pPhrase, pTC->iToken,pList,nList - ); - } - if( rc==SQLITE_OK ){ - int nCount; - nCount = fts3DoclistCountDocids( - pTC->pPhrase->doclist.aAll, pTC->pPhrase->doclist.nAll - ); - if( ii==0 || nCountpToken = 0; - } - return rc; -} +/* +** Each cursor has a (possibly empty) linked list of the following objects. +*/ +struct Fts3DeferredToken { + Fts3PhraseToken *pToken; /* Pointer to corresponding expr token */ + int iCol; /* Column token must occur in */ + Fts3DeferredToken *pNext; /* Next in list of deferred tokens */ + PendingList *pList; /* Doclist is assembled here */ +}; /* -** This function is called from within the xFilter method. It initializes -** the full-text query currently stored in pCsr->pExpr. To iterate through -** the results of a query, the caller does: +** An instance of this structure is used to iterate through the terms on +** a contiguous set of segment b-tree leaf nodes. Although the details of +** this structure are only manipulated by code in this file, opaque handles +** of type Fts3SegReader* are also used by code in fts3.c to iterate through +** terms when querying the full-text index. See functions: ** -** fts3EvalStart(pCsr); -** while( 1 ){ -** fts3EvalNext(pCsr); -** if( pCsr->bEof ) break; -** ... return row pCsr->iPrevId to the caller ... -** } +** sqlite3Fts3SegReaderNew() +** sqlite3Fts3SegReaderFree() +** sqlite3Fts3SegReaderIterate() +** +** Methods used to manipulate Fts3SegReader structures: +** +** fts3SegReaderNext() +** fts3SegReaderFirstDocid() +** fts3SegReaderNextDocid() */ -static int fts3EvalStart(Fts3Cursor *pCsr){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int rc = SQLITE_OK; - int nToken = 0; - int nOr = 0; - - /* Allocate a MultiSegReader for each token in the expression. */ - fts3EvalAllocateReaders(pCsr, pCsr->pExpr, &nToken, &nOr, &rc); +struct Fts3SegReader { + int iIdx; /* Index within level, or 0x7FFFFFFF for PT */ + u8 bLookup; /* True for a lookup only */ + u8 rootOnly; /* True for a root-only reader */ - /* Determine which, if any, tokens in the expression should be deferred. */ -#ifndef SQLITE_DISABLE_FTS4_DEFERRED - if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ - Fts3TokenAndCost *aTC; - Fts3Expr **apOr; - aTC = (Fts3TokenAndCost *)sqlite3_malloc( - sizeof(Fts3TokenAndCost) * nToken - + sizeof(Fts3Expr *) * nOr * 2 - ); - apOr = (Fts3Expr **)&aTC[nToken]; + sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */ + sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */ + sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */ + sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */ - if( !aTC ){ - rc = SQLITE_NOMEM; - }else{ - int ii; - Fts3TokenAndCost *pTC = aTC; - Fts3Expr **ppOr = apOr; + char *aNode; /* Pointer to node data (or NULL) */ + int nNode; /* Size of buffer at aNode (or 0) */ + int nPopulate; /* If >0, bytes of buffer aNode[] loaded */ + sqlite3_blob *pBlob; /* If not NULL, blob handle to read node */ - fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc); - nToken = (int)(pTC-aTC); - nOr = (int)(ppOr-apOr); + Fts3HashElem **ppNextElem; - if( rc==SQLITE_OK ){ - rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken); - for(ii=0; rc==SQLITE_OK && iipExpr, &rc); - return rc; -} +#define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0) +#define fts3SegReaderIsRootOnly(p) ((p)->rootOnly!=0) /* -** Invalidate the current position list for phrase pPhrase. +** An instance of this structure is used to create a segment b-tree in the +** database. The internal details of this type are only accessed by the +** following functions: +** +** fts3SegWriterAdd() +** fts3SegWriterFlush() +** fts3SegWriterFree() */ -static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){ - if( pPhrase->doclist.bFreeList ){ - sqlite3_free(pPhrase->doclist.pList); - } - pPhrase->doclist.pList = 0; - pPhrase->doclist.nList = 0; - pPhrase->doclist.bFreeList = 0; -} +struct SegmentWriter { + SegmentNode *pTree; /* Pointer to interior tree structure */ + sqlite3_int64 iFirst; /* First slot in %_segments written */ + sqlite3_int64 iFree; /* Next free slot in %_segments */ + char *zTerm; /* Pointer to previous term buffer */ + int nTerm; /* Number of bytes in zTerm */ + int nMalloc; /* Size of malloc'd buffer at zMalloc */ + char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ + int nSize; /* Size of allocation at aData */ + int nData; /* Bytes of data in aData */ + char *aData; /* Pointer to block from malloc() */ + i64 nLeafData; /* Number of bytes of leaf data written */ +}; /* -** This function is called to edit the position list associated with -** the phrase object passed as the fifth argument according to a NEAR -** condition. For example: -** -** abc NEAR/5 "def ghi" -** -** Parameter nNear is passed the NEAR distance of the expression (5 in -** the example above). When this function is called, *paPoslist points to -** the position list, and *pnToken is the number of phrase tokens in, the -** phrase on the other side of the NEAR operator to pPhrase. For example, -** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to -** the position list associated with phrase "abc". +** Type SegmentNode is used by the following three functions to create +** the interior part of the segment b+-tree structures (everything except +** the leaf nodes). These functions and type are only ever used by code +** within the fts3SegWriterXXX() family of functions described above. ** -** All positions in the pPhrase position list that are not sufficiently -** close to a position in the *paPoslist position list are removed. If this -** leaves 0 positions, zero is returned. Otherwise, non-zero. +** fts3NodeAddTerm() +** fts3NodeWrite() +** fts3NodeFree() ** -** Before returning, *paPoslist is set to point to the position lsit -** associated with pPhrase. And *pnToken is set to the number of tokens in -** pPhrase. +** When a b+tree is written to the database (either as a result of a merge +** or the pending-terms table being flushed), leaves are written into the +** database file as soon as they are completely populated. The interior of +** the tree is assembled in memory and written out only once all leaves have +** been populated and stored. This is Ok, as the b+-tree fanout is usually +** very large, meaning that the interior of the tree consumes relatively +** little memory. */ -static int fts3EvalNearTrim( - int nNear, /* NEAR distance. As in "NEAR/nNear". */ - char *aTmp, /* Temporary space to use */ - char **paPoslist, /* IN/OUT: Position list */ - int *pnToken, /* IN/OUT: Tokens in phrase of *paPoslist */ - Fts3Phrase *pPhrase /* The phrase object to trim the doclist of */ -){ - int nParam1 = nNear + pPhrase->nToken; - int nParam2 = nNear + *pnToken; - int nNew; - char *p2; - char *pOut; - int res; +struct SegmentNode { + SegmentNode *pParent; /* Parent node (or NULL for root node) */ + SegmentNode *pRight; /* Pointer to right-sibling */ + SegmentNode *pLeftmost; /* Pointer to left-most node of this depth */ + int nEntry; /* Number of terms written to node so far */ + char *zTerm; /* Pointer to previous term buffer */ + int nTerm; /* Number of bytes in zTerm */ + int nMalloc; /* Size of malloc'd buffer at zMalloc */ + char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ + int nData; /* Bytes of valid data so far */ + char *aData; /* Node data */ +}; - assert( pPhrase->doclist.pList ); +/* +** Valid values for the second argument to fts3SqlStmt(). +*/ +#define SQL_DELETE_CONTENT 0 +#define SQL_IS_EMPTY 1 +#define SQL_DELETE_ALL_CONTENT 2 +#define SQL_DELETE_ALL_SEGMENTS 3 +#define SQL_DELETE_ALL_SEGDIR 4 +#define SQL_DELETE_ALL_DOCSIZE 5 +#define SQL_DELETE_ALL_STAT 6 +#define SQL_SELECT_CONTENT_BY_ROWID 7 +#define SQL_NEXT_SEGMENT_INDEX 8 +#define SQL_INSERT_SEGMENTS 9 +#define SQL_NEXT_SEGMENTS_ID 10 +#define SQL_INSERT_SEGDIR 11 +#define SQL_SELECT_LEVEL 12 +#define SQL_SELECT_LEVEL_RANGE 13 +#define SQL_SELECT_LEVEL_COUNT 14 +#define SQL_SELECT_SEGDIR_MAX_LEVEL 15 +#define SQL_DELETE_SEGDIR_LEVEL 16 +#define SQL_DELETE_SEGMENTS_RANGE 17 +#define SQL_CONTENT_INSERT 18 +#define SQL_DELETE_DOCSIZE 19 +#define SQL_REPLACE_DOCSIZE 20 +#define SQL_SELECT_DOCSIZE 21 +#define SQL_SELECT_STAT 22 +#define SQL_REPLACE_STAT 23 - p2 = pOut = pPhrase->doclist.pList; - res = fts3PoslistNearMerge( - &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 - ); - if( res ){ - nNew = (int)(pOut - pPhrase->doclist.pList) - 1; - assert( pPhrase->doclist.pList[nNew]=='\0' ); - assert( nNew<=pPhrase->doclist.nList && nNew>0 ); - memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew); - pPhrase->doclist.nList = nNew; - *paPoslist = pPhrase->doclist.pList; - *pnToken = pPhrase->nToken; - } +#define SQL_SELECT_ALL_PREFIX_LEVEL 24 +#define SQL_DELETE_ALL_TERMS_SEGDIR 25 +#define SQL_DELETE_SEGDIR_RANGE 26 +#define SQL_SELECT_ALL_LANGID 27 +#define SQL_FIND_MERGE_LEVEL 28 +#define SQL_MAX_LEAF_NODE_ESTIMATE 29 +#define SQL_DELETE_SEGDIR_ENTRY 30 +#define SQL_SHIFT_SEGDIR_ENTRY 31 +#define SQL_SELECT_SEGDIR 32 +#define SQL_CHOMP_SEGDIR 33 +#define SQL_SEGMENT_IS_APPENDABLE 34 +#define SQL_SELECT_INDEXES 35 +#define SQL_SELECT_MXLEVEL 36 - return res; -} +#define SQL_SELECT_LEVEL_RANGE2 37 +#define SQL_UPDATE_LEVEL_IDX 38 +#define SQL_UPDATE_LEVEL 39 /* -** This function is a no-op if *pRc is other than SQLITE_OK when it is called. -** Otherwise, it advances the expression passed as the second argument to -** point to the next matching row in the database. Expressions iterate through -** matching rows in docid order. Ascending order if Fts3Cursor.bDesc is zero, -** or descending if it is non-zero. -** -** If an error occurs, *pRc is set to an SQLite error code. Otherwise, if -** successful, the following variables in pExpr are set: -** -** Fts3Expr.bEof (non-zero if EOF - there is no next row) -** Fts3Expr.iDocid (valid if bEof==0. The docid of the next row) -** -** If the expression is of type FTSQUERY_PHRASE, and the expression is not -** at EOF, then the following variables are populated with the position list -** for the phrase for the visited row: -** -** FTs3Expr.pPhrase->doclist.nList (length of pList in bytes) -** FTs3Expr.pPhrase->doclist.pList (pointer to position list) -** -** It says above that this function advances the expression to the next -** matching row. This is usually true, but there are the following exceptions: -** -** 1. Deferred tokens are not taken into account. If a phrase consists -** entirely of deferred tokens, it is assumed to match every row in -** the db. In this case the position-list is not populated at all. -** -** Or, if a phrase contains one or more deferred tokens and one or -** more non-deferred tokens, then the expression is advanced to the -** next possible match, considering only non-deferred tokens. In other -** words, if the phrase is "A B C", and "B" is deferred, the expression -** is advanced to the next row that contains an instance of "A * C", -** where "*" may match any single token. The position list in this case -** is populated as for "A * C" before returning. +** This function is used to obtain an SQLite prepared statement handle +** for the statement identified by the second argument. If successful, +** *pp is set to the requested statement handle and SQLITE_OK returned. +** Otherwise, an SQLite error code is returned and *pp is set to 0. ** -** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is -** advanced to point to the next row that matches "x AND y". -** -** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is -** really a match, taking into account deferred tokens and NEAR operators. +** If argument apVal is not NULL, then it must point to an array with +** at least as many entries as the requested statement has bound +** parameters. The values are bound to the statements parameters before +** returning. */ -static void fts3EvalNextRow( - Fts3Cursor *pCsr, /* FTS Cursor handle */ - Fts3Expr *pExpr, /* Expr. to advance to next matching row */ - int *pRc /* IN/OUT: Error code */ +static int fts3SqlStmt( + Fts3Table *p, /* Virtual table handle */ + int eStmt, /* One of the SQL_XXX constants above */ + sqlite3_stmt **pp, /* OUT: Statement handle */ + sqlite3_value **apVal /* Values to bind to statement */ ){ - if( *pRc==SQLITE_OK ){ - int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */ - assert( pExpr->bEof==0 ); - pExpr->bStart = 1; + const char *azSql[] = { +/* 0 */ "DELETE FROM %Q.'%q_content' WHERE rowid = ?", +/* 1 */ "SELECT NOT EXISTS(SELECT docid FROM %Q.'%q_content' WHERE rowid!=?)", +/* 2 */ "DELETE FROM %Q.'%q_content'", +/* 3 */ "DELETE FROM %Q.'%q_segments'", +/* 4 */ "DELETE FROM %Q.'%q_segdir'", +/* 5 */ "DELETE FROM %Q.'%q_docsize'", +/* 6 */ "DELETE FROM %Q.'%q_stat'", +/* 7 */ "SELECT %s WHERE rowid=?", +/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", +/* 9 */ "REPLACE INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", +/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", +/* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)", - switch( pExpr->eType ){ - case FTSQUERY_NEAR: - case FTSQUERY_AND: { - Fts3Expr *pLeft = pExpr->pLeft; - Fts3Expr *pRight = pExpr->pRight; - assert( !pLeft->bDeferred || !pRight->bDeferred ); + /* Return segments in order from oldest to newest.*/ +/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root " + "FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC", +/* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root " + "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?" + "ORDER BY level DESC, idx ASC", - if( pLeft->bDeferred ){ - /* LHS is entirely deferred. So we assume it matches every row. - ** Advance the RHS iterator to find the next row visited. */ - fts3EvalNextRow(pCsr, pRight, pRc); - pExpr->iDocid = pRight->iDocid; - pExpr->bEof = pRight->bEof; - }else if( pRight->bDeferred ){ - /* RHS is entirely deferred. So we assume it matches every row. - ** Advance the LHS iterator to find the next row visited. */ - fts3EvalNextRow(pCsr, pLeft, pRc); - pExpr->iDocid = pLeft->iDocid; - pExpr->bEof = pLeft->bEof; - }else{ - /* Neither the RHS or LHS are deferred. */ - fts3EvalNextRow(pCsr, pLeft, pRc); - fts3EvalNextRow(pCsr, pRight, pRc); - while( !pLeft->bEof && !pRight->bEof && *pRc==SQLITE_OK ){ - sqlite3_int64 iDiff = DOCID_CMP(pLeft->iDocid, pRight->iDocid); - if( iDiff==0 ) break; - if( iDiff<0 ){ - fts3EvalNextRow(pCsr, pLeft, pRc); - }else{ - fts3EvalNextRow(pCsr, pRight, pRc); - } - } - pExpr->iDocid = pLeft->iDocid; - pExpr->bEof = (pLeft->bEof || pRight->bEof); - if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){ - if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){ - Fts3Doclist *pDl = &pRight->pPhrase->doclist; - while( *pRc==SQLITE_OK && pRight->bEof==0 ){ - memset(pDl->pList, 0, pDl->nList); - fts3EvalNextRow(pCsr, pRight, pRc); - } - } - if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){ - Fts3Doclist *pDl = &pLeft->pPhrase->doclist; - while( *pRc==SQLITE_OK && pLeft->bEof==0 ){ - memset(pDl->pList, 0, pDl->nList); - fts3EvalNextRow(pCsr, pLeft, pRc); - } - } - } - } - break; - } - - case FTSQUERY_OR: { - Fts3Expr *pLeft = pExpr->pLeft; - Fts3Expr *pRight = pExpr->pRight; - sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); +/* 14 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?", +/* 15 */ "SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", - assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); - assert( pRight->bStart || pLeft->iDocid==pRight->iDocid ); +/* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?", +/* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?", +/* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%s)", +/* 19 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?", +/* 20 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", +/* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?", +/* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=?", +/* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(?,?)", +/* 24 */ "", +/* 25 */ "", - if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ - fts3EvalNextRow(pCsr, pLeft, pRc); - }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){ - fts3EvalNextRow(pCsr, pRight, pRc); - }else{ - fts3EvalNextRow(pCsr, pLeft, pRc); - fts3EvalNextRow(pCsr, pRight, pRc); - } +/* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", +/* 27 */ "SELECT ? UNION SELECT level / (1024 * ?) FROM %Q.'%q_segdir'", - pExpr->bEof = (pLeft->bEof && pRight->bEof); - iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); - if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ - pExpr->iDocid = pLeft->iDocid; - }else{ - pExpr->iDocid = pRight->iDocid; - } +/* This statement is used to determine which level to read the input from +** when performing an incremental merge. It returns the absolute level number +** of the oldest level in the db that contains at least ? segments. Or, +** if no level in the FTS index contains more than ? segments, the statement +** returns zero rows. */ +/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' " + " GROUP BY level HAVING cnt>=?" + " ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1", - break; - } +/* Estimate the upper limit on the number of leaf nodes in a new segment +** created by merging the oldest :2 segments from absolute level :1. See +** function sqlite3Fts3Incrmerge() for details. */ +/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) " + " FROM (SELECT * FROM %Q.'%q_segdir' " + " WHERE level = ? ORDER BY idx ASC LIMIT ?" + " )", - case FTSQUERY_NOT: { - Fts3Expr *pLeft = pExpr->pLeft; - Fts3Expr *pRight = pExpr->pRight; +/* SQL_DELETE_SEGDIR_ENTRY +** Delete the %_segdir entry on absolute level :1 with index :2. */ +/* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", - if( pRight->bStart==0 ){ - fts3EvalNextRow(pCsr, pRight, pRc); - assert( *pRc!=SQLITE_OK || pRight->bStart ); - } +/* SQL_SHIFT_SEGDIR_ENTRY +** Modify the idx value for the segment with idx=:3 on absolute level :2 +** to :1. */ +/* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?", - fts3EvalNextRow(pCsr, pLeft, pRc); - if( pLeft->bEof==0 ){ - while( !*pRc - && !pRight->bEof - && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0 - ){ - fts3EvalNextRow(pCsr, pRight, pRc); - } - } - pExpr->iDocid = pLeft->iDocid; - pExpr->bEof = pLeft->bEof; - break; - } +/* SQL_SELECT_SEGDIR +** Read a single entry from the %_segdir table. The entry from absolute +** level :1 with index value :2. */ +/* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root " + "FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", - default: { - Fts3Phrase *pPhrase = pExpr->pPhrase; - fts3EvalInvalidatePoslist(pPhrase); - *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof); - pExpr->iDocid = pPhrase->doclist.iDocid; - break; - } - } - } -} +/* SQL_CHOMP_SEGDIR +** Update the start_block (:1) and root (:2) fields of the %_segdir +** entry located on absolute level :3 with index :4. */ +/* 33 */ "UPDATE %Q.'%q_segdir' SET start_block = ?, root = ?" + "WHERE level = ? AND idx = ?", -/* -** If *pRc is not SQLITE_OK, or if pExpr is not the root node of a NEAR -** cluster, then this function returns 1 immediately. -** -** Otherwise, it checks if the current row really does match the NEAR -** expression, using the data currently stored in the position lists -** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression. -** -** If the current row is a match, the position list associated with each -** phrase in the NEAR expression is edited in place to contain only those -** phrase instances sufficiently close to their peers to satisfy all NEAR -** constraints. In this case it returns 1. If the NEAR expression does not -** match the current row, 0 is returned. The position lists may or may not -** be edited if 0 is returned. -*/ -static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){ - int res = 1; +/* SQL_SEGMENT_IS_APPENDABLE +** Return a single row if the segment with end_block=? is appendable. Or +** no rows otherwise. */ +/* 34 */ "SELECT 1 FROM %Q.'%q_segments' WHERE blockid=? AND block IS NULL", - /* The following block runs if pExpr is the root of a NEAR query. - ** For example, the query: - ** - ** "w" NEAR "x" NEAR "y" NEAR "z" - ** - ** which is represented in tree form as: - ** - ** | - ** +--NEAR--+ <-- root of NEAR query - ** | | - ** +--NEAR--+ "z" - ** | | - ** +--NEAR--+ "y" - ** | | - ** "w" "x" - ** - ** The right-hand child of a NEAR node is always a phrase. The - ** left-hand child may be either a phrase or a NEAR node. There are - ** no exceptions to this - it's the way the parser in fts3_expr.c works. - */ - if( *pRc==SQLITE_OK - && pExpr->eType==FTSQUERY_NEAR - && pExpr->bEof==0 - && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) - ){ - Fts3Expr *p; - int nTmp = 0; /* Bytes of temp space */ - char *aTmp; /* Temp space for PoslistNearMerge() */ +/* SQL_SELECT_INDEXES +** Return the list of valid segment indexes for absolute level ? */ +/* 35 */ "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC", - /* Allocate temporary working space. */ - for(p=pExpr; p->pLeft; p=p->pLeft){ - nTmp += p->pRight->pPhrase->doclist.nList; +/* SQL_SELECT_MXLEVEL +** Return the largest relative level in the FTS index or indexes. */ +/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'", + + /* Return segments in order from oldest to newest.*/ +/* 37 */ "SELECT level, idx, end_block " + "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? " + "ORDER BY level DESC, idx ASC", + + /* Update statements used while promoting segments */ +/* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? " + "WHERE level=? AND idx=?", +/* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1" + + }; + int rc = SQLITE_OK; + sqlite3_stmt *pStmt; + + assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); + assert( eStmt=0 ); + + pStmt = p->aStmt[eStmt]; + if( !pStmt ){ + int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; + char *zSql; + if( eStmt==SQL_CONTENT_INSERT ){ + zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); + }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ + f &= ~SQLITE_PREPARE_NO_VTAB; + zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); + }else{ + zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); } - nTmp += p->pPhrase->doclist.nList; - if( nTmp==0 ){ - res = 0; + if( !zSql ){ + rc = SQLITE_NOMEM; }else{ - aTmp = sqlite3_malloc(nTmp*2); - if( !aTmp ){ - *pRc = SQLITE_NOMEM; - res = 0; - }else{ - char *aPoslist = p->pPhrase->doclist.pList; - int nToken = p->pPhrase->nToken; - - for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){ - Fts3Phrase *pPhrase = p->pRight->pPhrase; - int nNear = p->nNear; - res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); - } - - aPoslist = pExpr->pRight->pPhrase->doclist.pList; - nToken = pExpr->pRight->pPhrase->nToken; - for(p=pExpr->pLeft; p && res; p=p->pLeft){ - int nNear; - Fts3Phrase *pPhrase; - assert( p->pParent && p->pParent->pLeft==p ); - nNear = p->pParent->nNear; - pPhrase = ( - p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase - ); - res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase); - } - } - - sqlite3_free(aTmp); + rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL); + sqlite3_free(zSql); + assert( rc==SQLITE_OK || pStmt==0 ); + p->aStmt[eStmt] = pStmt; } } - - return res; + if( apVal ){ + int i; + int nParam = sqlite3_bind_parameter_count(pStmt); + for(i=0; rc==SQLITE_OK && ieType ){ - case FTSQUERY_NEAR: - case FTSQUERY_AND: - bHit = ( - fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) - && fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) - && fts3EvalNearTest(pExpr, pRc) - ); - - /* If the NEAR expression does not match any rows, zero the doclist for - ** all phrases involved in the NEAR. This is because the snippet(), - ** offsets() and matchinfo() functions are not supposed to recognize - ** any instances of phrases that are part of unmatched NEAR queries. - ** For example if this expression: - ** - ** ... MATCH 'a OR (b NEAR c)' - ** - ** is matched against a row containing: - ** - ** 'a b d e' - ** - ** then any snippet() should ony highlight the "a" term, not the "b" - ** (as "b" is part of a non-matching NEAR clause). - */ - if( bHit==0 - && pExpr->eType==FTSQUERY_NEAR - && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR) - ){ - Fts3Expr *p; - for(p=pExpr; p->pPhrase==0; p=p->pLeft){ - if( p->pRight->iDocid==pCsr->iPrevId ){ - fts3EvalInvalidatePoslist(p->pRight->pPhrase); - } - } - if( p->iDocid==pCsr->iPrevId ){ - fts3EvalInvalidatePoslist(p->pPhrase); - } - } - break; +static int fts3SelectDocsize( + Fts3Table *pTab, /* FTS3 table handle */ + sqlite3_int64 iDocid, /* Docid to bind for SQL_SELECT_DOCSIZE */ + sqlite3_stmt **ppStmt /* OUT: Statement handle */ +){ + sqlite3_stmt *pStmt = 0; /* Statement requested from fts3SqlStmt() */ + int rc; /* Return code */ - case FTSQUERY_OR: { - int bHit1 = fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc); - int bHit2 = fts3EvalTestExpr(pCsr, pExpr->pRight, pRc); - bHit = bHit1 || bHit2; - break; - } + rc = fts3SqlStmt(pTab, SQL_SELECT_DOCSIZE, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iDocid); + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){ + rc = sqlite3_reset(pStmt); + if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB; + pStmt = 0; + }else{ + rc = SQLITE_OK; + } + } - case FTSQUERY_NOT: - bHit = ( - fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) - && !fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) - ); - break; + *ppStmt = pStmt; + return rc; +} - default: { -#ifndef SQLITE_DISABLE_FTS4_DEFERRED - if( pCsr->pDeferred - && (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred) - ){ - Fts3Phrase *pPhrase = pExpr->pPhrase; - assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 ); - if( pExpr->bDeferred ){ - fts3EvalInvalidatePoslist(pPhrase); - } - *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); - bHit = (pPhrase->doclist.pList!=0); - pExpr->iDocid = pCsr->iPrevId; - }else -#endif - { - bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId); - } - break; - } +SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal( + Fts3Table *pTab, /* Fts3 table handle */ + sqlite3_stmt **ppStmt /* OUT: Statement handle */ +){ + sqlite3_stmt *pStmt = 0; + int rc; + rc = fts3SqlStmt(pTab, SQL_SELECT_STAT, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); + if( sqlite3_step(pStmt)!=SQLITE_ROW + || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB + ){ + rc = sqlite3_reset(pStmt); + if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB; + pStmt = 0; } } - return bHit; + *ppStmt = pStmt; + return rc; +} + +SQLITE_PRIVATE int sqlite3Fts3SelectDocsize( + Fts3Table *pTab, /* Fts3 table handle */ + sqlite3_int64 iDocid, /* Docid to read size data for */ + sqlite3_stmt **ppStmt /* OUT: Statement handle */ +){ + return fts3SelectDocsize(pTab, iDocid, ppStmt); } /* -** This function is called as the second part of each xNext operation when -** iterating through the results of a full-text query. At this point the -** cursor points to a row that matches the query expression, with the -** following caveats: -** -** * Up until this point, "NEAR" operators in the expression have been -** treated as "AND". -** -** * Deferred tokens have not yet been considered. -** -** If *pRc is not SQLITE_OK when this function is called, it immediately -** returns 0. Otherwise, it tests whether or not after considering NEAR -** operators and deferred tokens the current row is still a match for the -** expression. It returns 1 if both of the following are true: -** -** 1. *pRc is SQLITE_OK when this function returns, and -** -** 2. After scanning the current FTS table row for the deferred tokens, -** it is determined that the row does *not* match the query. +** Similar to fts3SqlStmt(). Except, after binding the parameters in +** array apVal[] to the SQL statement identified by eStmt, the statement +** is executed. ** -** Or, if no error occurs and it seems the current row does match the FTS -** query, return 0. +** Returns SQLITE_OK if the statement is successfully executed, or an +** SQLite error code otherwise. */ -SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){ - int rc = *pRc; - int bMiss = 0; +static void fts3SqlExec( + int *pRC, /* Result code */ + Fts3Table *p, /* The FTS3 table */ + int eStmt, /* Index of statement to evaluate */ + sqlite3_value **apVal /* Parameters to bind */ +){ + sqlite3_stmt *pStmt; + int rc; + if( *pRC ) return; + rc = fts3SqlStmt(p, eStmt, &pStmt, apVal); if( rc==SQLITE_OK ){ - - /* If there are one or more deferred tokens, load the current row into - ** memory and scan it to determine the position list for each deferred - ** token. Then, see if this row is really a match, considering deferred - ** tokens and NEAR operators (neither of which were taken into account - ** earlier, by fts3EvalNextRow()). - */ - if( pCsr->pDeferred ){ - rc = fts3CursorSeek(0, pCsr); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3CacheDeferredDoclists(pCsr); - } - } - bMiss = (0==fts3EvalTestExpr(pCsr, pCsr->pExpr, &rc)); - - /* Free the position-lists accumulated for each deferred token above. */ - sqlite3Fts3FreeDeferredDoclists(pCsr); - *pRc = rc; + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); } - return (rc==SQLITE_OK && bMiss); + *pRC = rc; } + /* -** Advance to the next document that matches the FTS expression in -** Fts3Cursor.pExpr. +** This function ensures that the caller has obtained an exclusive +** shared-cache table-lock on the %_segdir table. This is required before +** writing data to the fts3 table. If this lock is not acquired first, then +** the caller may end up attempting to take this lock as part of committing +** a transaction, causing SQLite to return SQLITE_LOCKED or +** LOCKED_SHAREDCACHEto a COMMIT command. +** +** It is best to avoid this because if FTS3 returns any error when +** committing a transaction, the whole transaction will be rolled back. +** And this is not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. +** It can still happen if the user locks the underlying tables directly +** instead of accessing them via FTS. */ -static int fts3EvalNext(Fts3Cursor *pCsr){ - int rc = SQLITE_OK; /* Return Code */ - Fts3Expr *pExpr = pCsr->pExpr; - assert( pCsr->isEof==0 ); - if( pExpr==0 ){ - pCsr->isEof = 1; - }else{ - do { - if( pCsr->isRequireSeek==0 ){ - sqlite3_reset(pCsr->pStmt); - } - assert( sqlite3_data_count(pCsr->pStmt)==0 ); - fts3EvalNextRow(pCsr, pExpr, &rc); - pCsr->isEof = pExpr->bEof; - pCsr->isRequireSeek = 1; - pCsr->isMatchinfoNeeded = 1; - pCsr->iPrevId = pExpr->iDocid; - }while( pCsr->isEof==0 && sqlite3Fts3EvalTestDeferred(pCsr, &rc) ); - } +static int fts3Writelock(Fts3Table *p){ + int rc = SQLITE_OK; - /* Check if the cursor is past the end of the docid range specified - ** by Fts3Cursor.iMinDocid/iMaxDocid. If so, set the EOF flag. */ - if( rc==SQLITE_OK && ( - (pCsr->bDesc==0 && pCsr->iPrevId>pCsr->iMaxDocid) - || (pCsr->bDesc!=0 && pCsr->iPrevIdiMinDocid) - )){ - pCsr->isEof = 1; + if( p->nPendingData==0 ){ + sqlite3_stmt *pStmt; + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_null(pStmt, 1); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } } return rc; } /* -** Restart interation for expression pExpr so that the next call to -** fts3EvalNext() visits the first row. Do not allow incremental -** loading or merging of phrase doclists for this iteration. +** FTS maintains a separate indexes for each language-id (a 32-bit integer). +** Within each language id, a separate index is maintained to store the +** document terms, and each configured prefix size (configured the FTS +** "prefix=" option). And each index consists of multiple levels ("relative +** levels"). ** -** If *pRc is other than SQLITE_OK when this function is called, it is -** a no-op. If an error occurs within this function, *pRc is set to an -** SQLite error code before returning. +** All three of these values (the language id, the specific index and the +** level within the index) are encoded in 64-bit integer values stored +** in the %_segdir table on disk. This function is used to convert three +** separate component values into the single 64-bit integer value that +** can be used to query the %_segdir table. +** +** Specifically, each language-id/index combination is allocated 1024 +** 64-bit integer level values ("absolute levels"). The main terms index +** for language-id 0 is allocate values 0-1023. The first prefix index +** (if any) for language-id 0 is allocated values 1024-2047. And so on. +** Language 1 indexes are allocated immediately following language 0. +** +** So, for a system with nPrefix prefix indexes configured, the block of +** absolute levels that corresponds to language-id iLangid and index +** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024). */ -static void fts3EvalRestart( - Fts3Cursor *pCsr, - Fts3Expr *pExpr, - int *pRc +static sqlite3_int64 getAbsoluteLevel( + Fts3Table *p, /* FTS3 table handle */ + int iLangid, /* Language id */ + int iIndex, /* Index in p->aIndex[] */ + int iLevel /* Level of segments */ ){ - if( pExpr && *pRc==SQLITE_OK ){ - Fts3Phrase *pPhrase = pExpr->pPhrase; - - if( pPhrase ){ - fts3EvalInvalidatePoslist(pPhrase); - if( pPhrase->bIncr ){ - int i; - for(i=0; inToken; i++){ - Fts3PhraseToken *pToken = &pPhrase->aToken[i]; - assert( pToken->pDeferred==0 ); - if( pToken->pSegcsr ){ - sqlite3Fts3MsrIncrRestart(pToken->pSegcsr); - } - } - *pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase); - } - pPhrase->doclist.pNextDocid = 0; - pPhrase->doclist.iDocid = 0; - pPhrase->pOrPoslist = 0; - } - - pExpr->iDocid = 0; - pExpr->bEof = 0; - pExpr->bStart = 0; - - fts3EvalRestart(pCsr, pExpr->pLeft, pRc); - fts3EvalRestart(pCsr, pExpr->pRight, pRc); - } -} - -/* -** After allocating the Fts3Expr.aMI[] array for each phrase in the -** expression rooted at pExpr, the cursor iterates through all rows matched -** by pExpr, calling this function for each row. This function increments -** the values in Fts3Expr.aMI[] according to the position-list currently -** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase -** expression nodes. -*/ -static void fts3EvalUpdateCounts(Fts3Expr *pExpr){ - if( pExpr ){ - Fts3Phrase *pPhrase = pExpr->pPhrase; - if( pPhrase && pPhrase->doclist.pList ){ - int iCol = 0; - char *p = pPhrase->doclist.pList; - - assert( *p ); - while( 1 ){ - u8 c = 0; - int iCnt = 0; - while( 0xFE & (*p | c) ){ - if( (c&0x80)==0 ) iCnt++; - c = *p++ & 0x80; - } - - /* aMI[iCol*3 + 1] = Number of occurrences - ** aMI[iCol*3 + 2] = Number of rows containing at least one instance - */ - pExpr->aMI[iCol*3 + 1] += iCnt; - pExpr->aMI[iCol*3 + 2] += (iCnt>0); - if( *p==0x00 ) break; - p++; - p += fts3GetVarint32(p, &iCol); - } - } + sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */ + assert_fts3_nc( iLangid>=0 ); + assert( p->nIndex>0 ); + assert( iIndex>=0 && iIndexnIndex ); - fts3EvalUpdateCounts(pExpr->pLeft); - fts3EvalUpdateCounts(pExpr->pRight); - } + iBase = ((sqlite3_int64)iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL; + return iBase + iLevel; } /* -** Expression pExpr must be of type FTSQUERY_PHRASE. +** Set *ppStmt to a statement handle that may be used to iterate through +** all rows in the %_segdir table, from oldest to newest. If successful, +** return SQLITE_OK. If an error occurs while preparing the statement, +** return an SQLite error code. ** -** If it is not already allocated and populated, this function allocates and -** populates the Fts3Expr.aMI[] array for expression pExpr. If pExpr is part -** of a NEAR expression, then it also allocates and populates the same array -** for all other phrases that are part of the NEAR expression. +** There is only ever one instance of this SQL statement compiled for +** each FTS3 table. ** -** SQLITE_OK is returned if the aMI[] array is successfully allocated and -** populated. Otherwise, if an error occurs, an SQLite error code is returned. +** The statement returns the following columns from the %_segdir table: +** +** 0: idx +** 1: start_block +** 2: leaves_end_block +** 3: end_block +** 4: root */ -static int fts3EvalGatherStats( - Fts3Cursor *pCsr, /* Cursor object */ - Fts3Expr *pExpr /* FTSQUERY_PHRASE expression */ +SQLITE_PRIVATE int sqlite3Fts3AllSegdirs( + Fts3Table *p, /* FTS3 table */ + int iLangid, /* Language being queried */ + int iIndex, /* Index for p->aIndex[] */ + int iLevel, /* Level to select (relative level) */ + sqlite3_stmt **ppStmt /* OUT: Compiled statement */ ){ - int rc = SQLITE_OK; /* Return code */ - - assert( pExpr->eType==FTSQUERY_PHRASE ); - if( pExpr->aMI==0 ){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - Fts3Expr *pRoot; /* Root of NEAR expression */ - Fts3Expr *p; /* Iterator used for several purposes */ - - sqlite3_int64 iPrevId = pCsr->iPrevId; - sqlite3_int64 iDocid; - u8 bEof; - - /* Find the root of the NEAR expression */ - pRoot = pExpr; - while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){ - pRoot = pRoot->pParent; - } - iDocid = pRoot->iDocid; - bEof = pRoot->bEof; - assert( pRoot->bStart ); - - /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */ - for(p=pRoot; p; p=p->pLeft){ - Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight); - assert( pE->aMI==0 ); - pE->aMI = (u32 *)sqlite3_malloc(pTab->nColumn * 3 * sizeof(u32)); - if( !pE->aMI ) return SQLITE_NOMEM; - memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32)); - } - - fts3EvalRestart(pCsr, pRoot, &rc); - - while( pCsr->isEof==0 && rc==SQLITE_OK ){ + int rc; + sqlite3_stmt *pStmt = 0; - do { - /* Ensure the %_content statement is reset. */ - if( pCsr->isRequireSeek==0 ) sqlite3_reset(pCsr->pStmt); - assert( sqlite3_data_count(pCsr->pStmt)==0 ); + assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel>=0 ); + assert( iLevel=0 && iIndexnIndex ); - /* Advance to the next document */ - fts3EvalNextRow(pCsr, pRoot, &rc); - pCsr->isEof = pRoot->bEof; - pCsr->isRequireSeek = 1; - pCsr->isMatchinfoNeeded = 1; - pCsr->iPrevId = pRoot->iDocid; - }while( pCsr->isEof==0 - && pRoot->eType==FTSQUERY_NEAR - && sqlite3Fts3EvalTestDeferred(pCsr, &rc) + if( iLevel<0 ){ + /* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */ + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); + sqlite3_bind_int64(pStmt, 2, + getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) ); - - if( rc==SQLITE_OK && pCsr->isEof==0 ){ - fts3EvalUpdateCounts(pRoot); - } } - - pCsr->isEof = 0; - pCsr->iPrevId = iPrevId; - - if( bEof ){ - pRoot->bEof = bEof; - }else{ - /* Caution: pRoot may iterate through docids in ascending or descending - ** order. For this reason, even though it seems more defensive, the - ** do loop can not be written: - ** - ** do {...} while( pRoot->iDocidbEof==0 ); - }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); + }else{ + /* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */ + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel)); } } + *ppStmt = pStmt; return rc; } + /* -** This function is used by the matchinfo() module to query a phrase -** expression node for the following information: -** -** 1. The total number of occurrences of the phrase in each column of -** the FTS table (considering all rows), and -** -** 2. For each column, the number of rows in the table for which the -** column contains at least one instance of the phrase. -** -** If no error occurs, SQLITE_OK is returned and the values for each column -** written into the array aiOut as follows: -** -** aiOut[iCol*3 + 1] = Number of occurrences -** aiOut[iCol*3 + 2] = Number of rows containing at least one instance -** -** Caveats: -** -** * If a phrase consists entirely of deferred tokens, then all output -** values are set to the number of documents in the table. In other -** words we assume that very common tokens occur exactly once in each -** column of each row of the table. +** Append a single varint to a PendingList buffer. SQLITE_OK is returned +** if successful, or an SQLite error code otherwise. ** -** * If a phrase contains some deferred tokens (and some non-deferred -** tokens), count the potential occurrence identified by considering -** the non-deferred tokens instead of actual phrase occurrences. +** This function also serves to allocate the PendingList structure itself. +** For example, to create a new PendingList structure containing two +** varints: ** -** * If the phrase is part of a NEAR expression, then only phrase instances -** that meet the NEAR constraint are included in the counts. +** PendingList *p = 0; +** fts3PendingListAppendVarint(&p, 1); +** fts3PendingListAppendVarint(&p, 2); */ -SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats( - Fts3Cursor *pCsr, /* FTS cursor handle */ - Fts3Expr *pExpr, /* Phrase expression */ - u32 *aiOut /* Array to write results into (see above) */ +static int fts3PendingListAppendVarint( + PendingList **pp, /* IN/OUT: Pointer to PendingList struct */ + sqlite3_int64 i /* Value to append to data */ ){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int rc = SQLITE_OK; - int iCol; + PendingList *p = *pp; - if( pExpr->bDeferred && pExpr->pParent->eType!=FTSQUERY_NEAR ){ - assert( pCsr->nDoc>0 ); - for(iCol=0; iColnColumn; iCol++){ - aiOut[iCol*3 + 1] = (u32)pCsr->nDoc; - aiOut[iCol*3 + 2] = (u32)pCsr->nDoc; + /* Allocate or grow the PendingList as required. */ + if( !p ){ + p = sqlite3_malloc(sizeof(*p) + 100); + if( !p ){ + return SQLITE_NOMEM; } - }else{ - rc = fts3EvalGatherStats(pCsr, pExpr); - if( rc==SQLITE_OK ){ - assert( pExpr->aMI ); - for(iCol=0; iColnColumn; iCol++){ - aiOut[iCol*3 + 1] = pExpr->aMI[iCol*3 + 1]; - aiOut[iCol*3 + 2] = pExpr->aMI[iCol*3 + 2]; - } + p->nSpace = 100; + p->aData = (char *)&p[1]; + p->nData = 0; + } + else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ + int nNew = p->nSpace * 2; + p = sqlite3_realloc(p, sizeof(*p) + nNew); + if( !p ){ + sqlite3_free(*pp); + *pp = 0; + return SQLITE_NOMEM; } + p->nSpace = nNew; + p->aData = (char *)&p[1]; } - return rc; + /* Append the new serialized varint to the end of the list. */ + p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i); + p->aData[p->nData] = '\0'; + *pp = p; + return SQLITE_OK; } /* -** The expression pExpr passed as the second argument to this function -** must be of type FTSQUERY_PHRASE. -** -** The returned value is either NULL or a pointer to a buffer containing -** a position-list indicating the occurrences of the phrase in column iCol -** of the current row. -** -** More specifically, the returned buffer contains 1 varint for each -** occurrence of the phrase in the column, stored using the normal (delta+2) -** compression and is terminated by either an 0x01 or 0x00 byte. For example, -** if the requested column contains "a b X c d X X" and the position-list -** for 'X' is requested, the buffer returned may contain: -** -** 0x04 0x05 0x03 0x01 or 0x04 0x05 0x03 0x00 +** Add a docid/column/position entry to a PendingList structure. Non-zero +** is returned if the structure is sqlite3_realloced as part of adding +** the entry. Otherwise, zero. ** -** This function works regardless of whether or not the phrase is deferred, -** incremental, or neither. +** If an OOM error occurs, *pRc is set to SQLITE_NOMEM before returning. +** Zero is always returned in this case. Otherwise, if no OOM error occurs, +** it is set to SQLITE_OK. */ -SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist( - Fts3Cursor *pCsr, /* FTS3 cursor object */ - Fts3Expr *pExpr, /* Phrase to return doclist for */ - int iCol, /* Column to return position list for */ - char **ppOut /* OUT: Pointer to position list */ +static int fts3PendingListAppend( + PendingList **pp, /* IN/OUT: PendingList structure */ + sqlite3_int64 iDocid, /* Docid for entry to add */ + sqlite3_int64 iCol, /* Column for entry to add */ + sqlite3_int64 iPos, /* Position of term for entry to add */ + int *pRc /* OUT: Return code */ ){ - Fts3Phrase *pPhrase = pExpr->pPhrase; - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - char *pIter; - int iThis; - sqlite3_int64 iDocid; - - /* If this phrase is applies specifically to some column other than - ** column iCol, return a NULL pointer. */ - *ppOut = 0; - assert( iCol>=0 && iColnColumn ); - if( (pPhrase->iColumnnColumn && pPhrase->iColumn!=iCol) ){ - return SQLITE_OK; - } + PendingList *p = *pp; + int rc = SQLITE_OK; - iDocid = pExpr->iDocid; - pIter = pPhrase->doclist.pList; - if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ - int rc = SQLITE_OK; - int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ - int bOr = 0; - u8 bTreeEof = 0; - Fts3Expr *p; /* Used to iterate from pExpr to root */ - Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */ - int bMatch; + assert( !p || p->iLastDocid<=iDocid ); - /* Check if this phrase descends from an OR expression node. If not, - ** return NULL. Otherwise, the entry that corresponds to docid - ** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the - ** tree that the node is part of has been marked as EOF, but the node - ** itself is not EOF, then it may point to an earlier entry. */ - pNear = pExpr; - for(p=pExpr->pParent; p; p=p->pParent){ - if( p->eType==FTSQUERY_OR ) bOr = 1; - if( p->eType==FTSQUERY_NEAR ) pNear = p; - if( p->bEof ) bTreeEof = 1; + if( !p || p->iLastDocid!=iDocid ){ + u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0); + if( p ){ + assert( p->nDatanSpace ); + assert( p->aData[p->nData]==0 ); + p->nData++; } - if( bOr==0 ) return SQLITE_OK; - - /* This is the descendent of an OR node. In this case we cannot use - ** an incremental phrase. Load the entire doclist for the phrase - ** into memory in this case. */ - if( pPhrase->bIncr ){ - int bEofSave = pNear->bEof; - fts3EvalRestart(pCsr, pNear, &rc); - while( rc==SQLITE_OK && !pNear->bEof ){ - fts3EvalNextRow(pCsr, pNear, &rc); - if( bEofSave==0 && pNear->iDocid==iDocid ) break; - } - assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); + if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iDelta)) ){ + goto pendinglistappend_out; } - if( bTreeEof ){ - while( rc==SQLITE_OK && !pNear->bEof ){ - fts3EvalNextRow(pCsr, pNear, &rc); - } + p->iLastCol = -1; + p->iLastPos = 0; + p->iLastDocid = iDocid; + } + if( iCol>0 && p->iLastCol!=iCol ){ + if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, 1)) + || SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iCol)) + ){ + goto pendinglistappend_out; } - if( rc!=SQLITE_OK ) return rc; - - bMatch = 1; - for(p=pNear; p; p=p->pLeft){ - u8 bEof = 0; - Fts3Expr *pTest = p; - Fts3Phrase *pPh; - assert( pTest->eType==FTSQUERY_NEAR || pTest->eType==FTSQUERY_PHRASE ); - if( pTest->eType==FTSQUERY_NEAR ) pTest = pTest->pRight; - assert( pTest->eType==FTSQUERY_PHRASE ); - pPh = pTest->pPhrase; - - pIter = pPh->pOrPoslist; - iDocid = pPh->iOrDocid; - if( pCsr->bDesc==bDescDoclist ){ - bEof = !pPh->doclist.nAll || - (pIter >= (pPh->doclist.aAll + pPh->doclist.nAll)); - while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){ - sqlite3Fts3DoclistNext( - bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, - &pIter, &iDocid, &bEof - ); - } - }else{ - bEof = !pPh->doclist.nAll || (pIter && pIter<=pPh->doclist.aAll); - while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){ - int dummy; - sqlite3Fts3DoclistPrev( - bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll, - &pIter, &iDocid, &dummy, &bEof - ); - } - } - pPh->pOrPoslist = pIter; - pPh->iOrDocid = iDocid; - if( bEof || iDocid!=pCsr->iPrevId ) bMatch = 0; + p->iLastCol = iCol; + p->iLastPos = 0; + } + if( iCol>=0 ){ + assert( iPos>p->iLastPos || (iPos==0 && p->iLastPos==0) ); + rc = fts3PendingListAppendVarint(&p, 2+iPos-p->iLastPos); + if( rc==SQLITE_OK ){ + p->iLastPos = iPos; } + } - if( bMatch ){ - pIter = pPhrase->pOrPoslist; - }else{ - pIter = 0; - } + pendinglistappend_out: + *pRc = rc; + if( p!=*pp ){ + *pp = p; + return 1; } - if( pIter==0 ) return SQLITE_OK; + return 0; +} - if( *pIter==0x01 ){ - pIter++; - pIter += fts3GetVarint32(pIter, &iThis); - }else{ - iThis = 0; +/* +** Free a PendingList object allocated by fts3PendingListAppend(). +*/ +static void fts3PendingListDelete(PendingList *pList){ + sqlite3_free(pList); +} + +/* +** Add an entry to one of the pending-terms hash tables. +*/ +static int fts3PendingTermsAddOne( + Fts3Table *p, + int iCol, + int iPos, + Fts3Hash *pHash, /* Pending terms hash table to add entry to */ + const char *zToken, + int nToken +){ + PendingList *pList; + int rc = SQLITE_OK; + + pList = (PendingList *)fts3HashFind(pHash, zToken, nToken); + if( pList ){ + p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem)); } - while( iThisiPrevDocid, iCol, iPos, &rc) ){ + if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){ + /* Malloc failed while inserting the new entry. This can only + ** happen if there was no previous entry for this token. + */ + assert( 0==fts3HashFind(pHash, zToken, nToken) ); + sqlite3_free(pList); + rc = SQLITE_NOMEM; + } } - if( *pIter==0x00 ){ - pIter = 0; + if( rc==SQLITE_OK ){ + p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem)); } - - *ppOut = ((iCol==iThis)?pIter:0); - return SQLITE_OK; + return rc; } /* -** Free all components of the Fts3Phrase structure that were allocated by -** the eval module. Specifically, this means to free: +** Tokenize the nul-terminated string zText and add all tokens to the +** pending-terms hash-table. The docid used is that currently stored in +** p->iPrevDocid, and the column is specified by argument iCol. ** -** * the contents of pPhrase->doclist, and -** * any Fts3MultiSegReader objects held by phrase tokens. +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. */ -SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){ - if( pPhrase ){ +static int fts3PendingTermsAdd( + Fts3Table *p, /* Table into which text will be inserted */ + int iLangid, /* Language id to use */ + const char *zText, /* Text of document to be inserted */ + int iCol, /* Column into which text is being inserted */ + u32 *pnWord /* IN/OUT: Incr. by number tokens inserted */ +){ + int rc; + int iStart = 0; + int iEnd = 0; + int iPos = 0; + int nWord = 0; + + char const *zToken; + int nToken = 0; + + sqlite3_tokenizer *pTokenizer = p->pTokenizer; + sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + sqlite3_tokenizer_cursor *pCsr; + int (*xNext)(sqlite3_tokenizer_cursor *pCursor, + const char**,int*,int*,int*,int*); + + assert( pTokenizer && pModule ); + + /* If the user has inserted a NULL value, this function may be called with + ** zText==0. In this case, add zero token entries to the hash table and + ** return early. */ + if( zText==0 ){ + *pnWord = 0; + return SQLITE_OK; + } + + rc = sqlite3Fts3OpenTokenizer(pTokenizer, iLangid, zText, -1, &pCsr); + if( rc!=SQLITE_OK ){ + return rc; + } + + xNext = pModule->xNext; + while( SQLITE_OK==rc + && SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos)) + ){ int i; - sqlite3_free(pPhrase->doclist.aAll); - fts3EvalInvalidatePoslist(pPhrase); - memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist)); - for(i=0; inToken; i++){ - fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr); - pPhrase->aToken[i].pSegcsr = 0; + if( iPos>=nWord ) nWord = iPos+1; + + /* Positions cannot be negative; we use -1 as a terminator internally. + ** Tokens must have a non-zero length. + */ + if( iPos<0 || !zToken || nToken<=0 ){ + rc = SQLITE_ERROR; + break; } - } -} + /* Add the term to the terms index */ + rc = fts3PendingTermsAddOne( + p, iCol, iPos, &p->aIndex[0].hPending, zToken, nToken + ); -/* -** Return SQLITE_CORRUPT_VTAB. -*/ -#ifdef SQLITE_DEBUG -SQLITE_PRIVATE int sqlite3Fts3Corrupt(){ - return SQLITE_CORRUPT_VTAB; + /* Add the term to each of the prefix indexes that it is not too + ** short for. */ + for(i=1; rc==SQLITE_OK && inIndex; i++){ + struct Fts3Index *pIndex = &p->aIndex[i]; + if( nTokennPrefix ) continue; + rc = fts3PendingTermsAddOne( + p, iCol, iPos, &pIndex->hPending, zToken, pIndex->nPrefix + ); + } + } + + pModule->xClose(pCsr); + *pnWord += nWord; + return (rc==SQLITE_DONE ? SQLITE_OK : rc); } -#endif -#if !SQLITE_CORE /* -** Initialize API pointer table, if required. +** Calling this function indicates that subsequent calls to +** fts3PendingTermsAdd() are to add term/position-list pairs for the +** contents of the document with docid iDocid. */ -#ifdef _WIN32 -__declspec(dllexport) -#endif -SQLITE_API int sqlite3_fts3_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi +static int fts3PendingTermsDocid( + Fts3Table *p, /* Full-text table handle */ + int bDelete, /* True if this op is a delete */ + int iLangid, /* Language id of row being written */ + sqlite_int64 iDocid /* Docid of row being written */ ){ - SQLITE_EXTENSION_INIT2(pApi) - return sqlite3Fts3Init(db); -} -#endif + assert( iLangid>=0 ); + assert( bDelete==1 || bDelete==0 ); -#endif + /* TODO(shess) Explore whether partially flushing the buffer on + ** forced-flush would provide better performance. I suspect that if + ** we ordered the doclists by size and flushed the largest until the + ** buffer was half empty, that would let the less frequent terms + ** generate longer doclists. + */ + if( iDocidiPrevDocid + || (iDocid==p->iPrevDocid && p->bPrevDelete==0) + || p->iPrevLangid!=iLangid + || p->nPendingData>p->nMaxPendingData + ){ + int rc = sqlite3Fts3PendingTermsFlush(p); + if( rc!=SQLITE_OK ) return rc; + } + p->iPrevDocid = iDocid; + p->iPrevLangid = iLangid; + p->bPrevDelete = bDelete; + return SQLITE_OK; +} -/************** End of fts3.c ************************************************/ -/************** Begin file fts3_aux.c ****************************************/ /* -** 2011 Jan 27 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** +** Discard the contents of the pending-terms hash tables. */ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -/* #include */ -/* #include */ - -typedef struct Fts3auxTable Fts3auxTable; -typedef struct Fts3auxCursor Fts3auxCursor; - -struct Fts3auxTable { - sqlite3_vtab base; /* Base class used by SQLite core */ - Fts3Table *pFts3Tab; -}; - -struct Fts3auxCursor { - sqlite3_vtab_cursor base; /* Base class used by SQLite core */ - Fts3MultiSegReader csr; /* Must be right after "base" */ - Fts3SegFilter filter; - char *zStop; - int nStop; /* Byte-length of string zStop */ - int iLangid; /* Language id to query */ - int isEof; /* True if cursor is at EOF */ - sqlite3_int64 iRowid; /* Current rowid */ - - int iCol; /* Current value of 'col' column */ - int nStat; /* Size of aStat[] array */ - struct Fts3auxColstats { - sqlite3_int64 nDoc; /* 'documents' values for current csr row */ - sqlite3_int64 nOcc; /* 'occurrences' values for current csr row */ - } *aStat; -}; +SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){ + int i; + for(i=0; inIndex; i++){ + Fts3HashElem *pElem; + Fts3Hash *pHash = &p->aIndex[i].hPending; + for(pElem=fts3HashFirst(pHash); pElem; pElem=fts3HashNext(pElem)){ + PendingList *pList = (PendingList *)fts3HashData(pElem); + fts3PendingListDelete(pList); + } + fts3HashClear(pHash); + } + p->nPendingData = 0; +} /* -** Schema of the terms table. +** This function is called by the xUpdate() method as part of an INSERT +** operation. It adds entries for each term in the new record to the +** pendingTerms hash table. +** +** Argument apVal is the same as the similarly named argument passed to +** fts3InsertData(). Parameter iDocid is the docid of the new row. */ -#define FTS3_AUX_SCHEMA \ - "CREATE TABLE x(term, col, documents, occurrences, languageid HIDDEN)" +static int fts3InsertTerms( + Fts3Table *p, + int iLangid, + sqlite3_value **apVal, + u32 *aSz +){ + int i; /* Iterator variable */ + for(i=2; inColumn+2; i++){ + int iCol = i-2; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_value_text(apVal[i]); + int rc = fts3PendingTermsAdd(p, iLangid, zText, iCol, &aSz[iCol]); + if( rc!=SQLITE_OK ){ + return rc; + } + aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); + } + } + return SQLITE_OK; +} /* -** This function does all the work for both the xConnect and xCreate methods. -** These tables have no persistent representation of their own, so xConnect -** and xCreate are identical operations. +** This function is called by the xUpdate() method for an INSERT operation. +** The apVal parameter is passed a copy of the apVal argument passed by +** SQLite to the xUpdate() method. i.e: +** +** apVal[0] Not used for INSERT. +** apVal[1] rowid +** apVal[2] Left-most user-defined column +** ... +** apVal[p->nColumn+1] Right-most user-defined column +** apVal[p->nColumn+2] Hidden column with same name as table +** apVal[p->nColumn+3] Hidden "docid" column (alias for rowid) +** apVal[p->nColumn+4] Hidden languageid column */ -static int fts3auxConnectMethod( - sqlite3 *db, /* Database connection */ - void *pUnused, /* Unused */ - int argc, /* Number of elements in argv array */ - const char * const *argv, /* xCreate/xConnect argument array */ - sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ - char **pzErr /* OUT: sqlite3_malloc'd error message */ +static int fts3InsertData( + Fts3Table *p, /* Full-text table */ + sqlite3_value **apVal, /* Array of values to insert */ + sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ ){ - char const *zDb; /* Name of database (e.g. "main") */ - char const *zFts3; /* Name of fts3 table */ - int nDb; /* Result of strlen(zDb) */ - int nFts3; /* Result of strlen(zFts3) */ - int nByte; /* Bytes of space to allocate here */ - int rc; /* value returned by declare_vtab() */ - Fts3auxTable *p; /* Virtual table object to return */ + int rc; /* Return code */ + sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ - UNUSED_PARAMETER(pUnused); + if( p->zContentTbl ){ + sqlite3_value *pRowid = apVal[p->nColumn+3]; + if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ + pRowid = apVal[1]; + } + if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ + return SQLITE_CONSTRAINT; + } + *piDocid = sqlite3_value_int64(pRowid); + return SQLITE_OK; + } - /* The user should invoke this in one of two forms: + /* Locate the statement handle used to insert data into the %_content + ** table. The SQL for this statement is: ** - ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table); - ** CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table); + ** INSERT INTO %_content VALUES(?, ?, ?, ...) + ** + ** The statement features N '?' variables, where N is the number of user + ** defined columns in the FTS3 table, plus one for the docid field. */ - if( argc!=4 && argc!=5 ) goto bad_args; + rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); + if( rc==SQLITE_OK && p->zLanguageid ){ + rc = sqlite3_bind_int( + pContentInsert, p->nColumn+2, + sqlite3_value_int(apVal[p->nColumn+4]) + ); + } + if( rc!=SQLITE_OK ) return rc; - zDb = argv[1]; - nDb = (int)strlen(zDb); - if( argc==5 ){ - if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){ - zDb = argv[3]; - nDb = (int)strlen(zDb); - zFts3 = argv[4]; - }else{ - goto bad_args; + /* There is a quirk here. The users INSERT statement may have specified + ** a value for the "rowid" field, for the "docid" field, or for both. + ** Which is a problem, since "rowid" and "docid" are aliases for the + ** same value. For example: + ** + ** INSERT INTO fts3tbl(rowid, docid) VALUES(1, 2); + ** + ** In FTS3, this is an error. It is an error to specify non-NULL values + ** for both docid and some other rowid alias. + */ + if( SQLITE_NULL!=sqlite3_value_type(apVal[3+p->nColumn]) ){ + if( SQLITE_NULL==sqlite3_value_type(apVal[0]) + && SQLITE_NULL!=sqlite3_value_type(apVal[1]) + ){ + /* A rowid/docid conflict. */ + return SQLITE_ERROR; } - }else{ - zFts3 = argv[3]; + rc = sqlite3_bind_value(pContentInsert, 1, apVal[3+p->nColumn]); + if( rc!=SQLITE_OK ) return rc; } - nFts3 = (int)strlen(zFts3); - rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA); - if( rc!=SQLITE_OK ) return rc; + /* Execute the statement to insert the record. Set *piDocid to the + ** new docid value. + */ + sqlite3_step(pContentInsert); + rc = sqlite3_reset(pContentInsert); - nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; - p = (Fts3auxTable *)sqlite3_malloc(nByte); - if( !p ) return SQLITE_NOMEM; - memset(p, 0, nByte); + *piDocid = sqlite3_last_insert_rowid(p->db); + return rc; +} - p->pFts3Tab = (Fts3Table *)&p[1]; - p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; - p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; - p->pFts3Tab->db = db; - p->pFts3Tab->nIndex = 1; - memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); - memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); - sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); - *ppVtab = (sqlite3_vtab *)p; - return SQLITE_OK; +/* +** Remove all data from the FTS3 table. Clear the hash table containing +** pending terms. +*/ +static int fts3DeleteAll(Fts3Table *p, int bContent){ + int rc = SQLITE_OK; /* Return code */ - bad_args: - sqlite3Fts3ErrMsg(pzErr, "invalid arguments to fts4aux constructor"); - return SQLITE_ERROR; + /* Discard the contents of the pending-terms hash table. */ + sqlite3Fts3PendingTermsClear(p); + + /* Delete everything from the shadow tables. Except, leave %_content as + ** is if bContent is false. */ + assert( p->zContentTbl==0 || bContent==0 ); + if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); + fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); + fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); + if( p->bHasDocsize ){ + fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0); + } + if( p->bHasStat ){ + fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0); + } + return rc; } /* -** This function does the work for both the xDisconnect and xDestroy methods. -** These tables have no persistent representation of their own, so xDisconnect -** and xDestroy are identical operations. +** */ -static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){ - Fts3auxTable *p = (Fts3auxTable *)pVtab; - Fts3Table *pFts3 = p->pFts3Tab; - int i; +static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){ + int iLangid = 0; + if( p->zLanguageid ) iLangid = sqlite3_column_int(pSelect, p->nColumn+1); + return iLangid; +} - /* Free any prepared statements held */ - for(i=0; iaStmt); i++){ - sqlite3_finalize(pFts3->aStmt[i]); +/* +** The first element in the apVal[] array is assumed to contain the docid +** (an integer) of a row about to be deleted. Remove all terms from the +** full-text index. +*/ +static void fts3DeleteTerms( + int *pRC, /* Result code */ + Fts3Table *p, /* The FTS table to delete from */ + sqlite3_value *pRowid, /* The docid to be deleted */ + u32 *aSz, /* Sizes of deleted document written here */ + int *pbFound /* OUT: Set to true if row really does exist */ +){ + int rc; + sqlite3_stmt *pSelect; + + assert( *pbFound==0 ); + if( *pRC ) return; + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pSelect) ){ + int i; + int iLangid = langidFromSelect(p, pSelect); + i64 iDocid = sqlite3_column_int64(pSelect, 0); + rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid); + for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){ + int iCol = i-1; + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pSelect, i); + rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[iCol]); + aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i); + } + } + if( rc!=SQLITE_OK ){ + sqlite3_reset(pSelect); + *pRC = rc; + return; + } + *pbFound = 1; + } + rc = sqlite3_reset(pSelect); + }else{ + sqlite3_reset(pSelect); } - sqlite3_free(pFts3->zSegmentsTbl); - sqlite3_free(p); - return SQLITE_OK; + *pRC = rc; } -#define FTS4AUX_EQ_CONSTRAINT 1 -#define FTS4AUX_GE_CONSTRAINT 2 -#define FTS4AUX_LE_CONSTRAINT 4 +/* +** Forward declaration to account for the circular dependency between +** functions fts3SegmentMerge() and fts3AllocateSegdirIdx(). +*/ +static int fts3SegmentMerge(Fts3Table *, int, int, int); /* -** xBestIndex - Analyze a WHERE and ORDER BY clause. +** This function allocates a new level iLevel index in the segdir table. +** Usually, indexes are allocated within a level sequentially starting +** with 0, so the allocated index is one greater than the value returned +** by: +** +** SELECT max(idx) FROM %_segdir WHERE level = :iLevel +** +** However, if there are already FTS3_MERGE_COUNT indexes at the requested +** level, they are merged into a single level (iLevel+1) segment and the +** allocated index is 0. +** +** If successful, *piIdx is set to the allocated index slot and SQLITE_OK +** returned. Otherwise, an SQLite error code is returned. */ -static int fts3auxBestIndexMethod( - sqlite3_vtab *pVTab, - sqlite3_index_info *pInfo +static int fts3AllocateSegdirIdx( + Fts3Table *p, + int iLangid, /* Language id */ + int iIndex, /* Index for p->aIndex */ + int iLevel, + int *piIdx ){ - int i; - int iEq = -1; - int iGe = -1; - int iLe = -1; - int iLangid = -1; - int iNext = 1; /* Next free argvIndex value */ - - UNUSED_PARAMETER(pVTab); - - /* This vtab delivers always results in "ORDER BY term ASC" order. */ - if( pInfo->nOrderBy==1 - && pInfo->aOrderBy[0].iColumn==0 - && pInfo->aOrderBy[0].desc==0 - ){ - pInfo->orderByConsumed = 1; - } + int rc; /* Return Code */ + sqlite3_stmt *pNextIdx; /* Query for next idx at level iLevel */ + int iNext = 0; /* Result of query pNextIdx */ - /* Search for equality and range constraints on the "term" column. - ** And equality constraints on the hidden "languageid" column. */ - for(i=0; inConstraint; i++){ - if( pInfo->aConstraint[i].usable ){ - int op = pInfo->aConstraint[i].op; - int iCol = pInfo->aConstraint[i].iColumn; + assert( iLangid>=0 ); + assert( p->nIndex>=1 ); - if( iCol==0 ){ - if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i; - if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i; - if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i; - if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i; - if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i; - } - if( iCol==4 ){ - if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iLangid = i; - } + /* Set variable iNext to the next available segdir index at level iLevel. */ + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pNextIdx, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64( + pNextIdx, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) + ); + if( SQLITE_ROW==sqlite3_step(pNextIdx) ){ + iNext = sqlite3_column_int(pNextIdx, 0); } + rc = sqlite3_reset(pNextIdx); } - if( iEq>=0 ){ - pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT; - pInfo->aConstraintUsage[iEq].argvIndex = iNext++; - pInfo->estimatedCost = 5; - }else{ - pInfo->idxNum = 0; - pInfo->estimatedCost = 20000; - if( iGe>=0 ){ - pInfo->idxNum += FTS4AUX_GE_CONSTRAINT; - pInfo->aConstraintUsage[iGe].argvIndex = iNext++; - pInfo->estimatedCost /= 2; - } - if( iLe>=0 ){ - pInfo->idxNum += FTS4AUX_LE_CONSTRAINT; - pInfo->aConstraintUsage[iLe].argvIndex = iNext++; - pInfo->estimatedCost /= 2; + if( rc==SQLITE_OK ){ + /* If iNext is FTS3_MERGE_COUNT, indicating that level iLevel is already + ** full, merge all segments in level iLevel into a single iLevel+1 + ** segment and allocate (newly freed) index 0 at level iLevel. Otherwise, + ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext. + */ + if( iNext>=MergeCount(p) ){ + fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel)); + rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel); + *piIdx = 0; + }else{ + *piIdx = iNext; } } - if( iLangid>=0 ){ - pInfo->aConstraintUsage[iLangid].argvIndex = iNext++; - pInfo->estimatedCost--; - } - return SQLITE_OK; + return rc; } /* -** xOpen - Open a cursor. +** The %_segments table is declared as follows: +** +** CREATE TABLE %_segments(blockid INTEGER PRIMARY KEY, block BLOB) +** +** This function reads data from a single row of the %_segments table. The +** specific row is identified by the iBlockid parameter. If paBlob is not +** NULL, then a buffer is allocated using sqlite3_malloc() and populated +** with the contents of the blob stored in the "block" column of the +** identified table row is. Whether or not paBlob is NULL, *pnBlob is set +** to the size of the blob in bytes before returning. +** +** If an error occurs, or the table does not contain the specified row, +** an SQLite error code is returned. Otherwise, SQLITE_OK is returned. If +** paBlob is non-NULL, then it is the responsibility of the caller to +** eventually free the returned buffer. +** +** This function may leave an open sqlite3_blob* handle in the +** Fts3Table.pSegments variable. This handle is reused by subsequent calls +** to this function. The handle may be closed by calling the +** sqlite3Fts3SegmentsClose() function. Reusing a blob handle is a handy +** performance improvement, but the blob handle should always be closed +** before control is returned to the user (to prevent a lock being held +** on the database file for longer than necessary). Thus, any virtual table +** method (xFilter etc.) that may directly or indirectly call this function +** must call sqlite3Fts3SegmentsClose() before returning. */ -static int fts3auxOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ - Fts3auxCursor *pCsr; /* Pointer to cursor object to return */ +SQLITE_PRIVATE int sqlite3Fts3ReadBlock( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iBlockid, /* Access the row with blockid=$iBlockid */ + char **paBlob, /* OUT: Blob data in malloc'd buffer */ + int *pnBlob, /* OUT: Size of blob data */ + int *pnLoad /* OUT: Bytes actually loaded */ +){ + int rc; /* Return code */ - UNUSED_PARAMETER(pVTab); + /* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */ + assert( pnBlob ); - pCsr = (Fts3auxCursor *)sqlite3_malloc(sizeof(Fts3auxCursor)); - if( !pCsr ) return SQLITE_NOMEM; - memset(pCsr, 0, sizeof(Fts3auxCursor)); + if( p->pSegments ){ + rc = sqlite3_blob_reopen(p->pSegments, iBlockid); + }else{ + if( 0==p->zSegmentsTbl ){ + p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName); + if( 0==p->zSegmentsTbl ) return SQLITE_NOMEM; + } + rc = sqlite3_blob_open( + p->db, p->zDb, p->zSegmentsTbl, "block", iBlockid, 0, &p->pSegments + ); + } - *ppCsr = (sqlite3_vtab_cursor *)pCsr; - return SQLITE_OK; + if( rc==SQLITE_OK ){ + int nByte = sqlite3_blob_bytes(p->pSegments); + *pnBlob = nByte; + if( paBlob ){ + char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); + if( !aByte ){ + rc = SQLITE_NOMEM; + }else{ + if( pnLoad && nByte>(FTS3_NODE_CHUNK_THRESHOLD) ){ + nByte = FTS3_NODE_CHUNKSIZE; + *pnLoad = nByte; + } + rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0); + memset(&aByte[nByte], 0, FTS3_NODE_PADDING); + if( rc!=SQLITE_OK ){ + sqlite3_free(aByte); + aByte = 0; + } + } + *paBlob = aByte; + } + }else if( rc==SQLITE_ERROR ){ + rc = FTS_CORRUPT_VTAB; + } + + return rc; } /* -** xClose - Close a cursor. +** Close the blob handle at p->pSegments, if it is open. See comments above +** the sqlite3Fts3ReadBlock() function for details. */ -static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){ - Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; - Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; +SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){ + sqlite3_blob_close(p->pSegments); + p->pSegments = 0; +} - sqlite3Fts3SegmentsClose(pFts3); - sqlite3Fts3SegReaderFinish(&pCsr->csr); - sqlite3_free((void *)pCsr->filter.zTerm); - sqlite3_free(pCsr->zStop); - sqlite3_free(pCsr->aStat); - sqlite3_free(pCsr); - return SQLITE_OK; +static int fts3SegReaderIncrRead(Fts3SegReader *pReader){ + int nRead; /* Number of bytes to read */ + int rc; /* Return code */ + + nRead = MIN(pReader->nNode - pReader->nPopulate, FTS3_NODE_CHUNKSIZE); + rc = sqlite3_blob_read( + pReader->pBlob, + &pReader->aNode[pReader->nPopulate], + nRead, + pReader->nPopulate + ); + + if( rc==SQLITE_OK ){ + pReader->nPopulate += nRead; + memset(&pReader->aNode[pReader->nPopulate], 0, FTS3_NODE_PADDING); + if( pReader->nPopulate==pReader->nNode ){ + sqlite3_blob_close(pReader->pBlob); + pReader->pBlob = 0; + pReader->nPopulate = 0; + } + } + return rc; } -static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){ - if( nSize>pCsr->nStat ){ - struct Fts3auxColstats *aNew; - aNew = (struct Fts3auxColstats *)sqlite3_realloc(pCsr->aStat, - sizeof(struct Fts3auxColstats) * nSize - ); - if( aNew==0 ) return SQLITE_NOMEM; - memset(&aNew[pCsr->nStat], 0, - sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat) - ); - pCsr->aStat = aNew; - pCsr->nStat = nSize; +static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){ + int rc = SQLITE_OK; + assert( !pReader->pBlob + || (pFrom>=pReader->aNode && pFrom<&pReader->aNode[pReader->nNode]) + ); + while( pReader->pBlob && rc==SQLITE_OK + && (pFrom - pReader->aNode + nByte)>pReader->nPopulate + ){ + rc = fts3SegReaderIncrRead(pReader); } - return SQLITE_OK; + return rc; } /* -** xNext - Advance the cursor to the next row, if any. +** Set an Fts3SegReader cursor to point at EOF. */ -static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ - Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; - Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; - int rc; +static void fts3SegReaderSetEof(Fts3SegReader *pSeg){ + if( !fts3SegReaderIsRootOnly(pSeg) ){ + sqlite3_free(pSeg->aNode); + sqlite3_blob_close(pSeg->pBlob); + pSeg->pBlob = 0; + } + pSeg->aNode = 0; +} - /* Increment our pretend rowid value. */ - pCsr->iRowid++; +/* +** Move the iterator passed as the first argument to the next term in the +** segment. If successful, SQLITE_OK is returned. If there is no next term, +** SQLITE_DONE. Otherwise, an SQLite error code. +*/ +static int fts3SegReaderNext( + Fts3Table *p, + Fts3SegReader *pReader, + int bIncr +){ + int rc; /* Return code of various sub-routines */ + char *pNext; /* Cursor variable */ + int nPrefix; /* Number of bytes in term prefix */ + int nSuffix; /* Number of bytes in term suffix */ - for(pCsr->iCol++; pCsr->iColnStat; pCsr->iCol++){ - if( pCsr->aStat[pCsr->iCol].nDoc>0 ) return SQLITE_OK; + if( !pReader->aDoclist ){ + pNext = pReader->aNode; + }else{ + pNext = &pReader->aDoclist[pReader->nDoclist]; } - rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr); - if( rc==SQLITE_ROW ){ - int i = 0; - int nDoclist = pCsr->csr.nDoclist; - char *aDoclist = pCsr->csr.aDoclist; - int iCol; + if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){ - int eState = 0; + if( fts3SegReaderIsPending(pReader) ){ + Fts3HashElem *pElem = *(pReader->ppNextElem); + sqlite3_free(pReader->aNode); + pReader->aNode = 0; + if( pElem ){ + char *aCopy; + PendingList *pList = (PendingList *)fts3HashData(pElem); + int nCopy = pList->nData+1; - if( pCsr->zStop ){ - int n = (pCsr->nStopcsr.nTerm) ? pCsr->nStop : pCsr->csr.nTerm; - int mc = memcmp(pCsr->zStop, pCsr->csr.zTerm, n); - if( mc<0 || (mc==0 && pCsr->csr.nTerm>pCsr->nStop) ){ - pCsr->isEof = 1; - return SQLITE_OK; + int nTerm = fts3HashKeysize(pElem); + if( (nTerm+1)>pReader->nTermAlloc ){ + sqlite3_free(pReader->zTerm); + pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2); + if( !pReader->zTerm ) return SQLITE_NOMEM; + pReader->nTermAlloc = (nTerm+1)*2; + } + memcpy(pReader->zTerm, fts3HashKey(pElem), nTerm); + pReader->zTerm[nTerm] = '\0'; + pReader->nTerm = nTerm; + + aCopy = (char*)sqlite3_malloc(nCopy); + if( !aCopy ) return SQLITE_NOMEM; + memcpy(aCopy, pList->aData, nCopy); + pReader->nNode = pReader->nDoclist = nCopy; + pReader->aNode = pReader->aDoclist = aCopy; + pReader->ppNextElem++; + assert( pReader->aNode ); } + return SQLITE_OK; } - if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; - memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); - iCol = 0; + fts3SegReaderSetEof(pReader); - while( i=iLeafEndBlock, this is an EOF condition. All leaf + ** blocks have already been traversed. */ +#ifdef CORRUPT_DB + assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB ); +#endif + if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){ + return SQLITE_OK; + } - i += sqlite3Fts3GetVarint(&aDoclist[i], &v); - switch( eState ){ - /* State 0. In this state the integer just read was a docid. */ - case 0: - pCsr->aStat[0].nDoc++; - eState = 1; - iCol = 0; - break; + rc = sqlite3Fts3ReadBlock( + p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode, + (bIncr ? &pReader->nPopulate : 0) + ); + if( rc!=SQLITE_OK ) return rc; + assert( pReader->pBlob==0 ); + if( bIncr && pReader->nPopulatenNode ){ + pReader->pBlob = p->pSegments; + p->pSegments = 0; + } + pNext = pReader->aNode; + } - /* State 1. In this state we are expecting either a 1, indicating - ** that the following integer will be a column number, or the - ** start of a position list for column 0. - ** - ** The only difference between state 1 and state 2 is that if the - ** integer encountered in state 1 is not 0 or 1, then we need to - ** increment the column 0 "nDoc" count for this term. - */ - case 1: - assert( iCol==0 ); - if( v>1 ){ - pCsr->aStat[1].nDoc++; - } - eState = 2; - /* fall through */ + assert( !fts3SegReaderIsPending(pReader) ); - case 2: - if( v==0 ){ /* 0x00. Next integer will be a docid. */ - eState = 0; - }else if( v==1 ){ /* 0x01. Next integer will be a column number. */ - eState = 3; - }else{ /* 2 or greater. A position. */ - pCsr->aStat[iCol+1].nOcc++; - pCsr->aStat[0].nOcc++; - } - break; + rc = fts3SegReaderRequire(pReader, pNext, FTS3_VARINT_MAX*2); + if( rc!=SQLITE_OK ) return rc; - /* State 3. The integer just read is a column number. */ - default: assert( eState==3 ); - iCol = (int)v; - if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; - pCsr->aStat[iCol+1].nDoc++; - eState = 2; - break; - } + /* Because of the FTS3_NODE_PADDING bytes of padding, the following is + ** safe (no risk of overread) even if the node data is corrupted. */ + pNext += fts3GetVarint32(pNext, &nPrefix); + pNext += fts3GetVarint32(pNext, &nSuffix); + if( nSuffix<=0 + || (&pReader->aNode[pReader->nNode] - pNext)pReader->nTerm + ){ + return FTS_CORRUPT_VTAB; + } + + /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are + ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer + ** overflow - hence the (i64) casts. */ + if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){ + i64 nNew = ((i64)nPrefix+nSuffix)*2; + char *zNew = sqlite3_realloc64(pReader->zTerm, nNew); + if( !zNew ){ + return SQLITE_NOMEM; } + pReader->zTerm = zNew; + pReader->nTermAlloc = nNew; + } - pCsr->iCol = 0; - rc = SQLITE_OK; + rc = fts3SegReaderRequire(pReader, pNext, nSuffix+FTS3_VARINT_MAX); + if( rc!=SQLITE_OK ) return rc; + + memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix); + pReader->nTerm = nPrefix+nSuffix; + pNext += nSuffix; + pNext += fts3GetVarint32(pNext, &pReader->nDoclist); + pReader->aDoclist = pNext; + pReader->pOffsetList = 0; + + /* Check that the doclist does not appear to extend past the end of the + ** b-tree node. And that the final byte of the doclist is 0x00. If either + ** of these statements is untrue, then the data structure is corrupt. + */ + if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode) + || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) + || pReader->nDoclist==0 + ){ + return FTS_CORRUPT_VTAB; + } + return SQLITE_OK; +} + +/* +** Set the SegReader to point to the first docid in the doclist associated +** with the current term. +*/ +static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){ + int rc = SQLITE_OK; + assert( pReader->aDoclist ); + assert( !pReader->pOffsetList ); + if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ + u8 bEof = 0; + pReader->iDocid = 0; + pReader->nOffsetList = 0; + sqlite3Fts3DoclistPrev(0, + pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList, + &pReader->iDocid, &pReader->nOffsetList, &bEof + ); }else{ - pCsr->isEof = 1; + rc = fts3SegReaderRequire(pReader, pReader->aDoclist, FTS3_VARINT_MAX); + if( rc==SQLITE_OK ){ + int n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid); + pReader->pOffsetList = &pReader->aDoclist[n]; + } } return rc; } /* -** xFilter - Initialize a cursor to point at the start of its data. +** Advance the SegReader to point to the next docid in the doclist +** associated with the current term. +** +** If arguments ppOffsetList and pnOffsetList are not NULL, then +** *ppOffsetList is set to point to the first column-offset list +** in the doclist entry (i.e. immediately past the docid varint). +** *pnOffsetList is set to the length of the set of column-offset +** lists, not including the nul-terminator byte. For example: */ -static int fts3auxFilterMethod( - sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ - int idxNum, /* Strategy index */ - const char *idxStr, /* Unused */ - int nVal, /* Number of elements in apVal */ - sqlite3_value **apVal /* Arguments for the indexing scheme */ +static int fts3SegReaderNextDocid( + Fts3Table *pTab, + Fts3SegReader *pReader, /* Reader to advance to next docid */ + char **ppOffsetList, /* OUT: Pointer to current position-list */ + int *pnOffsetList /* OUT: Length of *ppOffsetList in bytes */ ){ - Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; - Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab; - int rc; - int isScan = 0; - int iLangVal = 0; /* Language id to query */ + int rc = SQLITE_OK; + char *p = pReader->pOffsetList; + char c = 0; - int iEq = -1; /* Index of term=? value in apVal */ - int iGe = -1; /* Index of term>=? value in apVal */ - int iLe = -1; /* Index of term<=? value in apVal */ - int iLangid = -1; /* Index of languageid=? value in apVal */ - int iNext = 0; + assert( p ); - UNUSED_PARAMETER(nVal); - UNUSED_PARAMETER(idxStr); + if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ + /* A pending-terms seg-reader for an FTS4 table that uses order=desc. + ** Pending-terms doclists are always built up in ascending order, so + ** we have to iterate through them backwards here. */ + u8 bEof = 0; + if( ppOffsetList ){ + *ppOffsetList = pReader->pOffsetList; + *pnOffsetList = pReader->nOffsetList - 1; + } + sqlite3Fts3DoclistPrev(0, + pReader->aDoclist, pReader->nDoclist, &p, &pReader->iDocid, + &pReader->nOffsetList, &bEof + ); + if( bEof ){ + pReader->pOffsetList = 0; + }else{ + pReader->pOffsetList = p; + } + }else{ + char *pEnd = &pReader->aDoclist[pReader->nDoclist]; - assert( idxStr==0 ); - assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0 - || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT - || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) - ); + /* Pointer p currently points at the first byte of an offset list. The + ** following block advances it to point one byte past the end of + ** the same offset list. */ + while( 1 ){ - if( idxNum==FTS4AUX_EQ_CONSTRAINT ){ - iEq = iNext++; - }else{ - isScan = 1; - if( idxNum & FTS4AUX_GE_CONSTRAINT ){ - iGe = iNext++; - } - if( idxNum & FTS4AUX_LE_CONSTRAINT ){ - iLe = iNext++; + /* The following line of code (and the "p++" below the while() loop) is + ** normally all that is required to move pointer p to the desired + ** position. The exception is if this node is being loaded from disk + ** incrementally and pointer "p" now points to the first byte past + ** the populated part of pReader->aNode[]. + */ + while( *p | c ) c = *p++ & 0x80; + assert( *p==0 ); + + if( pReader->pBlob==0 || p<&pReader->aNode[pReader->nPopulate] ) break; + rc = fts3SegReaderIncrRead(pReader); + if( rc!=SQLITE_OK ) return rc; } - } - if( iNextfilter.zTerm); - sqlite3Fts3SegReaderFinish(&pCsr->csr); - sqlite3_free((void *)pCsr->filter.zTerm); - sqlite3_free(pCsr->aStat); - memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); + /* If required, populate the output variables with a pointer to and the + ** size of the previous offset-list. + */ + if( ppOffsetList ){ + *ppOffsetList = pReader->pOffsetList; + *pnOffsetList = (int)(p - pReader->pOffsetList - 1); + } - pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; - if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN; + /* List may have been edited in place by fts3EvalNearTrim() */ + while( p=0 || iGe>=0 ){ - const unsigned char *zStr = sqlite3_value_text(apVal[0]); - assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) ); - if( zStr ){ - pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr); - pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]); - if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM; + /* If there are no more entries in the doclist, set pOffsetList to + ** NULL. Otherwise, set Fts3SegReader.iDocid to the next docid and + ** Fts3SegReader.pOffsetList to point to the next offset list before + ** returning. + */ + if( p>=pEnd ){ + pReader->pOffsetList = 0; + }else{ + rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX); + if( rc==SQLITE_OK ){ + u64 iDelta; + pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta); + if( pTab->bDescIdx ){ + pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta); + }else{ + pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta); + } + } } } - if( iLe>=0 ){ - pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe])); - pCsr->nStop = sqlite3_value_bytes(apVal[iLe]); - if( pCsr->zStop==0 ) return SQLITE_NOMEM; - } - - if( iLangid>=0 ){ - iLangVal = sqlite3_value_int(apVal[iLangid]); + return rc; +} - /* If the user specified a negative value for the languageid, use zero - ** instead. This works, as the "languageid=?" constraint will also - ** be tested by the VDBE layer. The test will always be false (since - ** this module will not return a row with a negative languageid), and - ** so the overall query will return zero rows. */ - if( iLangVal<0 ) iLangVal = 0; - } - pCsr->iLangid = iLangVal; - rc = sqlite3Fts3SegReaderCursor(pFts3, iLangVal, 0, FTS3_SEGCURSOR_ALL, - pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr - ); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); - } +SQLITE_PRIVATE int sqlite3Fts3MsrOvfl( + Fts3Cursor *pCsr, + Fts3MultiSegReader *pMsr, + int *pnOvfl +){ + Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; + int nOvfl = 0; + int ii; + int rc = SQLITE_OK; + int pgsz = p->nPgsz; - if( rc==SQLITE_OK ) rc = fts3auxNextMethod(pCursor); + assert( p->bFts4 ); + assert( pgsz>0 ); + + for(ii=0; rc==SQLITE_OK && iinSegment; ii++){ + Fts3SegReader *pReader = pMsr->apSegment[ii]; + if( !fts3SegReaderIsPending(pReader) + && !fts3SegReaderIsRootOnly(pReader) + ){ + sqlite3_int64 jj; + for(jj=pReader->iStartBlock; jj<=pReader->iLeafEndBlock; jj++){ + int nBlob; + rc = sqlite3Fts3ReadBlock(p, jj, 0, &nBlob, 0); + if( rc!=SQLITE_OK ) break; + if( (nBlob+35)>pgsz ){ + nOvfl += (nBlob + 34)/pgsz; + } + } + } + } + *pnOvfl = nOvfl; return rc; } /* -** xEof - Return true if the cursor is at EOF, or false otherwise. +** Free all allocations associated with the iterator passed as the +** second argument. */ -static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){ - Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; - return pCsr->isEof; +SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ + if( pReader ){ + sqlite3_free(pReader->zTerm); + if( !fts3SegReaderIsRootOnly(pReader) ){ + sqlite3_free(pReader->aNode); + } + sqlite3_blob_close(pReader->pBlob); + } + sqlite3_free(pReader); } /* -** xColumn - Return a column value. +** Allocate a new SegReader object. */ -static int fts3auxColumnMethod( - sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ - sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ - int iCol /* Index of column to read value from */ +SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( + int iAge, /* Segment "age". */ + int bLookup, /* True for a lookup only */ + sqlite3_int64 iStartLeaf, /* First leaf to traverse */ + sqlite3_int64 iEndLeaf, /* Final leaf to traverse */ + sqlite3_int64 iEndBlock, /* Final block of segment */ + const char *zRoot, /* Buffer containing root node */ + int nRoot, /* Size of buffer containing root node */ + Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */ ){ - Fts3auxCursor *p = (Fts3auxCursor *)pCursor; - - assert( p->isEof==0 ); - switch( iCol ){ - case 0: /* term */ - sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); - break; - - case 1: /* col */ - if( p->iCol ){ - sqlite3_result_int(pCtx, p->iCol-1); - }else{ - sqlite3_result_text(pCtx, "*", -1, SQLITE_STATIC); - } - break; + Fts3SegReader *pReader; /* Newly allocated SegReader object */ + int nExtra = 0; /* Bytes to allocate segment root node */ - case 2: /* documents */ - sqlite3_result_int64(pCtx, p->aStat[p->iCol].nDoc); - break; + assert( zRoot!=0 || nRoot==0 ); +#ifdef CORRUPT_DB + assert( zRoot!=0 || CORRUPT_DB ); +#endif - case 3: /* occurrences */ - sqlite3_result_int64(pCtx, p->aStat[p->iCol].nOcc); - break; + if( iStartLeaf==0 ){ + if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB; + nExtra = nRoot + FTS3_NODE_PADDING; + } - default: /* languageid */ - assert( iCol==4 ); - sqlite3_result_int(pCtx, p->iLangid); - break; + pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); + if( !pReader ){ + return SQLITE_NOMEM; } + memset(pReader, 0, sizeof(Fts3SegReader)); + pReader->iIdx = iAge; + pReader->bLookup = bLookup!=0; + pReader->iStartBlock = iStartLeaf; + pReader->iLeafEndBlock = iEndLeaf; + pReader->iEndBlock = iEndBlock; + if( nExtra ){ + /* The entire segment is stored in the root node. */ + pReader->aNode = (char *)&pReader[1]; + pReader->rootOnly = 1; + pReader->nNode = nRoot; + if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot); + memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING); + }else{ + pReader->iCurrentBlock = iStartLeaf-1; + } + *ppReader = pReader; return SQLITE_OK; } /* -** xRowid - Return the current rowid for the cursor. +** This is a comparison function used as a qsort() callback when sorting +** an array of pending terms by term. This occurs as part of flushing +** the contents of the pending-terms hash table to the database. */ -static int fts3auxRowidMethod( - sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ - sqlite_int64 *pRowid /* OUT: Rowid value */ +static int SQLITE_CDECL fts3CompareElemByTerm( + const void *lhs, + const void *rhs ){ - Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor; - *pRowid = pCsr->iRowid; - return SQLITE_OK; + char *z1 = fts3HashKey(*(Fts3HashElem **)lhs); + char *z2 = fts3HashKey(*(Fts3HashElem **)rhs); + int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs); + int n2 = fts3HashKeysize(*(Fts3HashElem **)rhs); + + int n = (n1aIndex */ + const char *zTerm, /* Term to search for */ + int nTerm, /* Size of buffer zTerm */ + int bPrefix, /* True for a prefix iterator */ + Fts3SegReader **ppReader /* OUT: SegReader for pending-terms */ +){ + Fts3SegReader *pReader = 0; /* Fts3SegReader object to return */ + Fts3HashElem *pE; /* Iterator variable */ + Fts3HashElem **aElem = 0; /* Array of term hash entries to scan */ + int nElem = 0; /* Size of array at aElem */ + int rc = SQLITE_OK; /* Return Code */ + Fts3Hash *pHash; - rc = sqlite3_create_module(db, "fts4aux", &fts3aux_module, 0); + pHash = &p->aIndex[iIndex].hPending; + if( bPrefix ){ + int nAlloc = 0; /* Size of allocated array at aElem */ + + for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){ + char *zKey = (char *)fts3HashKey(pE); + int nKey = fts3HashKeysize(pE); + if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){ + if( nElem==nAlloc ){ + Fts3HashElem **aElem2; + nAlloc += 16; + aElem2 = (Fts3HashElem **)sqlite3_realloc( + aElem, nAlloc*sizeof(Fts3HashElem *) + ); + if( !aElem2 ){ + rc = SQLITE_NOMEM; + nElem = 0; + break; + } + aElem = aElem2; + } + + aElem[nElem++] = pE; + } + } + + /* If more than one term matches the prefix, sort the Fts3HashElem + ** objects in term order using qsort(). This uses the same comparison + ** callback as is used when flushing terms to disk. + */ + if( nElem>1 ){ + qsort(aElem, nElem, sizeof(Fts3HashElem *), fts3CompareElemByTerm); + } + + }else{ + /* The query is a simple term lookup that matches at most one term in + ** the index. All that is required is a straight hash-lookup. + ** + ** Because the stack address of pE may be accessed via the aElem pointer + ** below, the "Fts3HashElem *pE" must be declared so that it is valid + ** within this entire function, not just this "else{...}" block. + */ + pE = fts3HashFindElem(pHash, zTerm, nTerm); + if( pE ){ + aElem = &pE; + nElem = 1; + } + } + + if( nElem>0 ){ + sqlite3_int64 nByte; + nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); + pReader = (Fts3SegReader *)sqlite3_malloc64(nByte); + if( !pReader ){ + rc = SQLITE_NOMEM; + }else{ + memset(pReader, 0, nByte); + pReader->iIdx = 0x7FFFFFFF; + pReader->ppNextElem = (Fts3HashElem **)&pReader[1]; + memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *)); + } + } + + if( bPrefix ){ + sqlite3_free(aElem); + } + *ppReader = pReader; return rc; } -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ - -/************** End of fts3_aux.c ********************************************/ -/************** Begin file fts3_expr.c ***************************************/ /* -** 2008 Nov 28 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: +** Compare the entries pointed to by two Fts3SegReader structures. +** Comparison is as follows: ** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** 1) EOF is greater than not EOF. ** -****************************************************************************** +** 2) The current terms (if any) are compared using memcmp(). If one +** term is a prefix of another, the longer term is considered the +** larger. ** -** This module contains code that implements a parser for fts3 query strings -** (the right-hand argument to the MATCH operator). Because the supported -** syntax is relatively simple, the whole tokenizer/parser system is -** hand-coded. +** 3) By segment age. An older segment is considered larger. */ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) +static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ + int rc; + if( pLhs->aNode && pRhs->aNode ){ + int rc2 = pLhs->nTerm - pRhs->nTerm; + if( rc2<0 ){ + rc = memcmp(pLhs->zTerm, pRhs->zTerm, pLhs->nTerm); + }else{ + rc = memcmp(pLhs->zTerm, pRhs->zTerm, pRhs->nTerm); + } + if( rc==0 ){ + rc = rc2; + } + }else{ + rc = (pLhs->aNode==0) - (pRhs->aNode==0); + } + if( rc==0 ){ + rc = pRhs->iIdx - pLhs->iIdx; + } + assert_fts3_nc( rc!=0 ); + return rc; +} /* -** By default, this module parses the legacy syntax that has been -** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS -** is defined, then it uses the new syntax. The differences between -** the new and the old syntaxes are: -** -** a) The new syntax supports parenthesis. The old does not. -** -** b) The new syntax supports the AND and NOT operators. The old does not. -** -** c) The old syntax supports the "-" token qualifier. This is not -** supported by the new syntax (it is replaced by the NOT operator). -** -** d) When using the old syntax, the OR operator has a greater precedence -** than an implicit AND. When using the new, both implicity and explicit -** AND operators have a higher precedence than OR. -** -** If compiled with SQLITE_TEST defined, then this module exports the -** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable -** to zero causes the module to use the old syntax. If it is set to -** non-zero the new syntax is activated. This is so both syntaxes can -** be tested using a single build of testfixture. -** -** The following describes the syntax supported by the fts3 MATCH -** operator in a similar format to that used by the lemon parser -** generator. This module does not use actually lemon, it uses a -** custom parser. -** -** query ::= andexpr (OR andexpr)*. -** -** andexpr ::= notexpr (AND? notexpr)*. -** -** notexpr ::= nearexpr (NOT nearexpr|-TOKEN)*. -** notexpr ::= LP query RP. +** A different comparison function for SegReader structures. In this +** version, it is assumed that each SegReader points to an entry in +** a doclist for identical terms. Comparison is made as follows: ** -** nearexpr ::= phrase (NEAR distance_opt nearexpr)*. +** 1) EOF (end of doclist in this case) is greater than not EOF. ** -** distance_opt ::= . -** distance_opt ::= / INTEGER. +** 2) By current docid. ** -** phrase ::= TOKEN. -** phrase ::= COLUMN:TOKEN. -** phrase ::= "TOKEN TOKEN TOKEN...". +** 3) By segment age. An older segment is considered larger. */ - -#ifdef SQLITE_TEST -SQLITE_API int sqlite3_fts3_enable_parentheses = 0; -#else -# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS -# define sqlite3_fts3_enable_parentheses 1 -# else -# define sqlite3_fts3_enable_parentheses 0 -# endif -#endif +static int fts3SegReaderDoclistCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ + int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); + if( rc==0 ){ + if( pLhs->iDocid==pRhs->iDocid ){ + rc = pRhs->iIdx - pLhs->iIdx; + }else{ + rc = (pLhs->iDocid > pRhs->iDocid) ? 1 : -1; + } + } + assert( pLhs->aNode && pRhs->aNode ); + return rc; +} +static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ + int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); + if( rc==0 ){ + if( pLhs->iDocid==pRhs->iDocid ){ + rc = pRhs->iIdx - pLhs->iIdx; + }else{ + rc = (pLhs->iDocid < pRhs->iDocid) ? 1 : -1; + } + } + assert( pLhs->aNode && pRhs->aNode ); + return rc; +} /* -** Default span for NEAR operators. +** Compare the term that the Fts3SegReader object passed as the first argument +** points to with the term specified by arguments zTerm and nTerm. +** +** If the pSeg iterator is already at EOF, return 0. Otherwise, return +** -ve if the pSeg term is less than zTerm/nTerm, 0 if the two terms are +** equal, or +ve if the pSeg term is greater than zTerm/nTerm. */ -#define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10 - -/* #include */ -/* #include */ +static int fts3SegReaderTermCmp( + Fts3SegReader *pSeg, /* Segment reader object */ + const char *zTerm, /* Term to compare to */ + int nTerm /* Size of term zTerm in bytes */ +){ + int res = 0; + if( pSeg->aNode ){ + if( pSeg->nTerm>nTerm ){ + res = memcmp(pSeg->zTerm, zTerm, nTerm); + }else{ + res = memcmp(pSeg->zTerm, zTerm, pSeg->nTerm); + } + if( res==0 ){ + res = pSeg->nTerm-nTerm; + } + } + return res; +} /* -** isNot: -** This variable is used by function getNextNode(). When getNextNode() is -** called, it sets ParseContext.isNot to true if the 'next node' is a -** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the -** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to -** zero. +** Argument apSegment is an array of nSegment elements. It is known that +** the final (nSegment-nSuspect) members are already in sorted order +** (according to the comparison function provided). This function shuffles +** the array around until all entries are in sorted order. */ -typedef struct ParseContext ParseContext; -struct ParseContext { - sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ - int iLangid; /* Language id used with tokenizer */ - const char **azCol; /* Array of column names for fts3 table */ - int bFts4; /* True to allow FTS4-only syntax */ - int nCol; /* Number of entries in azCol[] */ - int iDefaultCol; /* Default column to query */ - int isNot; /* True if getNextNode() sees a unary - */ - sqlite3_context *pCtx; /* Write error message here */ - int nNest; /* Number of nested brackets */ -}; +static void fts3SegReaderSort( + Fts3SegReader **apSegment, /* Array to sort entries of */ + int nSegment, /* Size of apSegment array */ + int nSuspect, /* Unsorted entry count */ + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) /* Comparison function */ +){ + int i; /* Iterator variable */ -/* -** This function is equivalent to the standard isspace() function. -** -** The standard isspace() can be awkward to use safely, because although it -** is defined to accept an argument of type int, its behavior when passed -** an integer that falls outside of the range of the unsigned char type -** is undefined (and sometimes, "undefined" means segfault). This wrapper -** is defined to accept an argument of type char, and always returns 0 for -** any values that fall outside of the range of the unsigned char type (i.e. -** negative values). -*/ -static int fts3isspace(char c){ - return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; + assert( nSuspect<=nSegment ); + + if( nSuspect==nSegment ) nSuspect--; + for(i=nSuspect-1; i>=0; i--){ + int j; + for(j=i; j<(nSegment-1); j++){ + Fts3SegReader *pTmp; + if( xCmp(apSegment[j], apSegment[j+1])<0 ) break; + pTmp = apSegment[j+1]; + apSegment[j+1] = apSegment[j]; + apSegment[j] = pTmp; + } + } + +#ifndef NDEBUG + /* Check that the list really is sorted now. */ + for(i=0; i<(nSuspect-1); i++){ + assert( xCmp(apSegment[i], apSegment[i+1])<0 ); + } +#endif } /* -** Allocate nByte bytes of memory using sqlite3_malloc(). If successful, -** zero the memory before returning a pointer to it. If unsuccessful, -** return NULL. +** Insert a record into the %_segments table. */ -static void *fts3MallocZero(int nByte){ - void *pRet = sqlite3_malloc(nByte); - if( pRet ) memset(pRet, 0, nByte); - return pRet; +static int fts3WriteSegment( + Fts3Table *p, /* Virtual table handle */ + sqlite3_int64 iBlock, /* Block id for new block */ + char *z, /* Pointer to buffer containing block data */ + int n /* Size of buffer z in bytes */ +){ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, SQL_INSERT_SEGMENTS, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iBlock); + sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + sqlite3_bind_null(pStmt, 2); + } + return rc; } -SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer( - sqlite3_tokenizer *pTokenizer, - int iLangid, - const char *z, - int n, - sqlite3_tokenizer_cursor **ppCsr -){ - sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; - sqlite3_tokenizer_cursor *pCsr = 0; +/* +** Find the largest relative level number in the table. If successful, set +** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs, +** set *pnMax to zero and return an SQLite error code. +*/ +SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){ int rc; + int mxLevel = 0; + sqlite3_stmt *pStmt = 0; - rc = pModule->xOpen(pTokenizer, z, n, &pCsr); - assert( rc==SQLITE_OK || pCsr==0 ); + rc = fts3SqlStmt(p, SQL_SELECT_MXLEVEL, &pStmt, 0); if( rc==SQLITE_OK ){ - pCsr->pTokenizer = pTokenizer; - if( pModule->iVersion>=1 ){ - rc = pModule->xLanguageid(pCsr, iLangid); - if( rc!=SQLITE_OK ){ - pModule->xClose(pCsr); - pCsr = 0; - } + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + mxLevel = sqlite3_column_int(pStmt, 0); } + rc = sqlite3_reset(pStmt); } - *ppCsr = pCsr; + *pnMax = mxLevel; return rc; } /* -** Function getNextNode(), which is called by fts3ExprParse(), may itself -** call fts3ExprParse(). So this forward declaration is required. +** Insert a record into the %_segdir table. */ -static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); +static int fts3WriteSegdir( + Fts3Table *p, /* Virtual table handle */ + sqlite3_int64 iLevel, /* Value for "level" field (absolute level) */ + int iIdx, /* Value for "idx" field */ + sqlite3_int64 iStartBlock, /* Value for "start_block" field */ + sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */ + sqlite3_int64 iEndBlock, /* Value for "end_block" field */ + sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */ + char *zRoot, /* Blob value for "root" field */ + int nRoot /* Number of bytes in buffer zRoot */ +){ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iLevel); + sqlite3_bind_int(pStmt, 2, iIdx); + sqlite3_bind_int64(pStmt, 3, iStartBlock); + sqlite3_bind_int64(pStmt, 4, iLeafEndBlock); + if( nLeafData==0 ){ + sqlite3_bind_int64(pStmt, 5, iEndBlock); + }else{ + char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); + if( !zEnd ) return SQLITE_NOMEM; + sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); + } + sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + sqlite3_bind_null(pStmt, 6); + } + return rc; +} /* -** Extract the next token from buffer z (length n) using the tokenizer -** and other information (column names etc.) in pParse. Create an Fts3Expr -** structure of type FTSQUERY_PHRASE containing a phrase consisting of this -** single token and set *ppExpr to point to it. If the end of the buffer is -** reached before a token is found, set *ppExpr to zero. It is the -** responsibility of the caller to eventually deallocate the allocated -** Fts3Expr structure (if any) by passing it to sqlite3_free(). +** Return the size of the common prefix (if any) shared by zPrev and +** zNext, in bytes. For example, ** -** Return SQLITE_OK if successful, or SQLITE_NOMEM if a memory allocation -** fails. +** fts3PrefixCompress("abc", 3, "abcdef", 6) // returns 3 +** fts3PrefixCompress("abX", 3, "abcdef", 6) // returns 2 +** fts3PrefixCompress("abX", 3, "Xbcdef", 6) // returns 0 */ -static int getNextToken( - ParseContext *pParse, /* fts3 query parse context */ - int iCol, /* Value for Fts3Phrase.iColumn */ - const char *z, int n, /* Input string */ - Fts3Expr **ppExpr, /* OUT: expression */ - int *pnConsumed /* OUT: Number of bytes consumed */ +static int fts3PrefixCompress( + const char *zPrev, /* Buffer containing previous term */ + int nPrev, /* Size of buffer zPrev in bytes */ + const char *zNext, /* Buffer containing next term */ + int nNext /* Size of buffer zNext in bytes */ ){ - sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; - sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; + int n; + for(n=0; nnData; /* Current size of node in bytes */ + int nReq = nData; /* Required space after adding zTerm */ + int nPrefix; /* Number of bytes of prefix compression */ + int nSuffix; /* Suffix length */ - *pnConsumed = i; - rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, i, &pCursor); - if( rc==SQLITE_OK ){ - const char *zToken; - int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0; - int nByte; /* total space to allocate */ + nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm); + nSuffix = nTerm-nPrefix; - rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); - if( rc==SQLITE_OK ){ - nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; - pRet = (Fts3Expr *)fts3MallocZero(nByte); - if( !pRet ){ - rc = SQLITE_NOMEM; - }else{ - pRet->eType = FTSQUERY_PHRASE; - pRet->pPhrase = (Fts3Phrase *)&pRet[1]; - pRet->pPhrase->nToken = 1; - pRet->pPhrase->iColumn = iCol; - pRet->pPhrase->aToken[0].n = nToken; - pRet->pPhrase->aToken[0].z = (char *)&pRet->pPhrase[1]; - memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken); + /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of + ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when + ** compared with BINARY collation. This indicates corruption. */ + if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; - if( iEndpPhrase->aToken[0].isPrefix = 1; - iEnd++; + nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix; + if( nReq<=p->nNodeSize || !pTree->zTerm ){ + + if( nReq>p->nNodeSize ){ + /* An unusual case: this is the first term to be added to the node + ** and the static node buffer (p->nNodeSize bytes) is not large + ** enough. Use a separately malloced buffer instead This wastes + ** p->nNodeSize bytes, but since this scenario only comes about when + ** the database contain two terms that share a prefix of almost 2KB, + ** this is not expected to be a serious problem. + */ + assert( pTree->aData==(char *)&pTree[1] ); + pTree->aData = (char *)sqlite3_malloc(nReq); + if( !pTree->aData ){ + return SQLITE_NOMEM; } + } - while( 1 ){ - if( !sqlite3_fts3_enable_parentheses - && iStart>0 && z[iStart-1]=='-' - ){ - pParse->isNot = 1; - iStart--; - }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){ - pRet->pPhrase->aToken[0].bFirst = 1; - iStart--; - }else{ - break; + if( pTree->zTerm ){ + /* There is no prefix-length field for first term in a node */ + nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nPrefix); + } + + nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nSuffix); + memcpy(&pTree->aData[nData], &zTerm[nPrefix], nSuffix); + pTree->nData = nData + nSuffix; + pTree->nEntry++; + + if( isCopyTerm ){ + if( pTree->nMalloczMalloc, nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; } + pTree->nMalloc = nTerm*2; + pTree->zMalloc = zNew; } - + pTree->zTerm = pTree->zMalloc; + memcpy(pTree->zTerm, zTerm, nTerm); + pTree->nTerm = nTerm; + }else{ + pTree->zTerm = (char *)zTerm; + pTree->nTerm = nTerm; } - *pnConsumed = iEnd; - }else if( i && rc==SQLITE_DONE ){ - rc = SQLITE_OK; + return SQLITE_OK; } + } - pModule->xClose(pCursor); + /* If control flows to here, it was not possible to append zTerm to the + ** current node. Create a new node (a right-sibling of the current node). + ** If this is the first node in the tree, the term is added to it. + ** + ** Otherwise, the term is not added to the new node, it is left empty for + ** now. Instead, the term is inserted into the parent of pTree. If pTree + ** has no parent, one is created here. + */ + pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); + if( !pNew ){ + return SQLITE_NOMEM; } - - *ppExpr = pRet; + memset(pNew, 0, sizeof(SegmentNode)); + pNew->nData = 1 + FTS3_VARINT_MAX; + pNew->aData = (char *)&pNew[1]; + + if( pTree ){ + SegmentNode *pParent = pTree->pParent; + rc = fts3NodeAddTerm(p, &pParent, isCopyTerm, zTerm, nTerm); + if( pTree->pParent==0 ){ + pTree->pParent = pParent; + } + pTree->pRight = pNew; + pNew->pLeftmost = pTree->pLeftmost; + pNew->pParent = pParent; + pNew->zMalloc = pTree->zMalloc; + pNew->nMalloc = pTree->nMalloc; + pTree->zMalloc = 0; + }else{ + pNew->pLeftmost = pNew; + rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm); + } + + *ppTree = pNew; return rc; } +/* +** Helper function for fts3NodeWrite(). +*/ +static int fts3TreeFinishNode( + SegmentNode *pTree, + int iHeight, + sqlite3_int64 iLeftChild +){ + int nStart; + assert( iHeight>=1 && iHeight<128 ); + nStart = FTS3_VARINT_MAX - sqlite3Fts3VarintLen(iLeftChild); + pTree->aData[nStart] = (char)iHeight; + sqlite3Fts3PutVarint(&pTree->aData[nStart+1], iLeftChild); + return nStart; +} /* -** Enlarge a memory allocation. If an out-of-memory allocation occurs, -** then free the old allocation. +** Write the buffer for the segment node pTree and all of its peers to the +** database. Then call this function recursively to write the parent of +** pTree and its peers to the database. +** +** Except, if pTree is a root node, do not write it to the database. Instead, +** set output variables *paRoot and *pnRoot to contain the root node. +** +** If successful, SQLITE_OK is returned and output variable *piLast is +** set to the largest blockid written to the database (or zero if no +** blocks were written to the db). Otherwise, an SQLite error code is +** returned. */ -static void *fts3ReallocOrFree(void *pOrig, int nNew){ - void *pRet = sqlite3_realloc(pOrig, nNew); - if( !pRet ){ - sqlite3_free(pOrig); +static int fts3NodeWrite( + Fts3Table *p, /* Virtual table handle */ + SegmentNode *pTree, /* SegmentNode handle */ + int iHeight, /* Height of this node in tree */ + sqlite3_int64 iLeaf, /* Block id of first leaf node */ + sqlite3_int64 iFree, /* Block id of next free slot in %_segments */ + sqlite3_int64 *piLast, /* OUT: Block id of last entry written */ + char **paRoot, /* OUT: Data for root node */ + int *pnRoot /* OUT: Size of root node in bytes */ +){ + int rc = SQLITE_OK; + + if( !pTree->pParent ){ + /* Root node of the tree. */ + int nStart = fts3TreeFinishNode(pTree, iHeight, iLeaf); + *piLast = iFree-1; + *pnRoot = pTree->nData - nStart; + *paRoot = &pTree->aData[nStart]; + }else{ + SegmentNode *pIter; + sqlite3_int64 iNextFree = iFree; + sqlite3_int64 iNextLeaf = iLeaf; + for(pIter=pTree->pLeftmost; pIter && rc==SQLITE_OK; pIter=pIter->pRight){ + int nStart = fts3TreeFinishNode(pIter, iHeight, iNextLeaf); + int nWrite = pIter->nData - nStart; + + rc = fts3WriteSegment(p, iNextFree, &pIter->aData[nStart], nWrite); + iNextFree++; + iNextLeaf += (pIter->nEntry+1); + } + if( rc==SQLITE_OK ){ + assert( iNextLeaf==iFree ); + rc = fts3NodeWrite( + p, pTree->pParent, iHeight+1, iFree, iNextFree, piLast, paRoot, pnRoot + ); + } } - return pRet; + + return rc; } /* -** Buffer zInput, length nInput, contains the contents of a quoted string -** that appeared as part of an fts3 query expression. Neither quote character -** is included in the buffer. This function attempts to tokenize the entire -** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE -** containing the results. +** Free all memory allocations associated with the tree pTree. +*/ +static void fts3NodeFree(SegmentNode *pTree){ + if( pTree ){ + SegmentNode *p = pTree->pLeftmost; + fts3NodeFree(p->pParent); + while( p ){ + SegmentNode *pRight = p->pRight; + if( p->aData!=(char *)&p[1] ){ + sqlite3_free(p->aData); + } + assert( pRight==0 || p->zMalloc==0 ); + sqlite3_free(p->zMalloc); + sqlite3_free(p); + p = pRight; + } + } +} + +/* +** Add a term to the segment being constructed by the SegmentWriter object +** *ppWriter. When adding the first term to a segment, *ppWriter should +** be passed NULL. This function will allocate a new SegmentWriter object +** and return it via the input/output variable *ppWriter in this case. ** -** If successful, SQLITE_OK is returned and *ppExpr set to point at the -** allocated Fts3Expr structure. Otherwise, either SQLITE_NOMEM (out of memory -** error) or SQLITE_ERROR (tokenization error) is returned and *ppExpr set -** to 0. +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. */ -static int getNextString( - ParseContext *pParse, /* fts3 query parse context */ - const char *zInput, int nInput, /* Input string */ - Fts3Expr **ppExpr /* OUT: expression */ +static int fts3SegWriterAdd( + Fts3Table *p, /* Virtual table handle */ + SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */ + int isCopyTerm, /* True if buffer zTerm must be copied */ + const char *zTerm, /* Pointer to buffer containing term */ + int nTerm, /* Size of term in bytes */ + const char *aDoclist, /* Pointer to buffer containing doclist */ + int nDoclist /* Size of doclist in bytes */ ){ - sqlite3_tokenizer *pTokenizer = pParse->pTokenizer; - sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; - int rc; - Fts3Expr *p = 0; - sqlite3_tokenizer_cursor *pCursor = 0; - char *zTemp = 0; - int nTemp = 0; + int nPrefix; /* Size of term prefix in bytes */ + int nSuffix; /* Size of term suffix in bytes */ + int nReq; /* Number of bytes required on leaf page */ + int nData; + SegmentWriter *pWriter = *ppWriter; - const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase); - int nToken = 0; + if( !pWriter ){ + int rc; + sqlite3_stmt *pStmt; - /* The final Fts3Expr data structure, including the Fts3Phrase, - ** Fts3PhraseToken structures token buffers are all stored as a single - ** allocation so that the expression can be freed with a single call to - ** sqlite3_free(). Setting this up requires a two pass approach. - ** - ** The first pass, in the block below, uses a tokenizer cursor to iterate - ** through the tokens in the expression. This pass uses fts3ReallocOrFree() - ** to assemble data in two dynamic buffers: - ** - ** Buffer p: Points to the Fts3Expr structure, followed by the Fts3Phrase - ** structure, followed by the array of Fts3PhraseToken - ** structures. This pass only populates the Fts3PhraseToken array. - ** - ** Buffer zTemp: Contains copies of all tokens. - ** - ** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below, - ** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase - ** structures. - */ - rc = sqlite3Fts3OpenTokenizer( - pTokenizer, pParse->iLangid, zInput, nInput, &pCursor); - if( rc==SQLITE_OK ){ - int ii; - for(ii=0; rc==SQLITE_OK; ii++){ - const char *zByte; - int nByte = 0, iBegin = 0, iEnd = 0, iPos = 0; - rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos); - if( rc==SQLITE_OK ){ - Fts3PhraseToken *pToken; + /* Allocate the SegmentWriter structure */ + pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); + if( !pWriter ) return SQLITE_NOMEM; + memset(pWriter, 0, sizeof(SegmentWriter)); + *ppWriter = pWriter; - p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken)); - if( !p ) goto no_mem; + /* Allocate a buffer in which to accumulate data */ + pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); + if( !pWriter->aData ) return SQLITE_NOMEM; + pWriter->nSize = p->nNodeSize; - zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte); - if( !zTemp ) goto no_mem; + /* Find the next free blockid in the %_segments table */ + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + pWriter->iFree = sqlite3_column_int64(pStmt, 0); + pWriter->iFirst = pWriter->iFree; + } + rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ) return rc; + } + nData = pWriter->nData; - assert( nToken==ii ); - pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii]; - memset(pToken, 0, sizeof(Fts3PhraseToken)); + nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); + nSuffix = nTerm-nPrefix; - memcpy(&zTemp[nTemp], zByte, nByte); - nTemp += nByte; + /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of + ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when + ** compared with BINARY collation. This indicates corruption. */ + if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; - pToken->n = nByte; - pToken->isPrefix = (iEndbFirst = (iBegin>0 && zInput[iBegin-1]=='^'); - nToken = ii+1; - } - } + /* Figure out how many bytes are required by this new entry */ + nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */ + sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */ + nSuffix + /* Term suffix */ + sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ + nDoclist; /* Doclist data */ - pModule->xClose(pCursor); - pCursor = 0; + if( nData>0 && nData+nReq>p->nNodeSize ){ + int rc; + + /* The current leaf node is full. Write it out to the database. */ + if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB; + rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData); + if( rc!=SQLITE_OK ) return rc; + p->nLeafAdd++; + + /* Add the current term to the interior node tree. The term added to + ** the interior tree must: + ** + ** a) be greater than the largest term on the leaf node just written + ** to the database (still available in pWriter->zTerm), and + ** + ** b) be less than or equal to the term about to be added to the new + ** leaf node (zTerm/nTerm). + ** + ** In other words, it must be the prefix of zTerm 1 byte longer than + ** the common prefix (if any) of zTerm and pWriter->zTerm. + */ + assert( nPrefixpTree, isCopyTerm, zTerm, nPrefix+1); + if( rc!=SQLITE_OK ) return rc; + + nData = 0; + pWriter->nTerm = 0; + + nPrefix = 0; + nSuffix = nTerm; + nReq = 1 + /* varint containing prefix size */ + sqlite3Fts3VarintLen(nTerm) + /* varint containing suffix size */ + nTerm + /* Term suffix */ + sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ + nDoclist; /* Doclist data */ } - if( rc==SQLITE_DONE ){ - int jj; - char *zBuf = 0; + /* Increase the total number of bytes written to account for the new entry. */ + pWriter->nLeafData += nReq; - p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp); - if( !p ) goto no_mem; - memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p); - p->eType = FTSQUERY_PHRASE; - p->pPhrase = (Fts3Phrase *)&p[1]; - p->pPhrase->iColumn = pParse->iDefaultCol; - p->pPhrase->nToken = nToken; + /* If the buffer currently allocated is too small for this entry, realloc + ** the buffer to make it large enough. + */ + if( nReq>pWriter->nSize ){ + char *aNew = sqlite3_realloc(pWriter->aData, nReq); + if( !aNew ) return SQLITE_NOMEM; + pWriter->aData = aNew; + pWriter->nSize = nReq; + } + assert( nData+nReq<=pWriter->nSize ); - zBuf = (char *)&p->pPhrase->aToken[nToken]; - if( zTemp ){ - memcpy(zBuf, zTemp, nTemp); - sqlite3_free(zTemp); - }else{ - assert( nTemp==0 ); + /* Append the prefix-compressed term and doclist to the buffer. */ + nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix); + nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix); + assert( nSuffix>0 ); + memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix); + nData += nSuffix; + nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist); + assert( nDoclist>0 ); + memcpy(&pWriter->aData[nData], aDoclist, nDoclist); + pWriter->nData = nData + nDoclist; + + /* Save the current term so that it can be used to prefix-compress the next. + ** If the isCopyTerm parameter is true, then the buffer pointed to by + ** zTerm is transient, so take a copy of the term data. Otherwise, just + ** store a copy of the pointer. + */ + if( isCopyTerm ){ + if( nTerm>pWriter->nMalloc ){ + char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } + pWriter->nMalloc = nTerm*2; + pWriter->zMalloc = zNew; + pWriter->zTerm = zNew; } + assert( pWriter->zTerm==pWriter->zMalloc ); + assert( nTerm>0 ); + memcpy(pWriter->zTerm, zTerm, nTerm); + }else{ + pWriter->zTerm = (char *)zTerm; + } + pWriter->nTerm = nTerm; - for(jj=0; jjpPhrase->nToken; jj++){ - p->pPhrase->aToken[jj].z = zBuf; - zBuf += p->pPhrase->aToken[jj].n; + return SQLITE_OK; +} + +/* +** Flush all data associated with the SegmentWriter object pWriter to the +** database. This function must be called after all terms have been added +** to the segment using fts3SegWriterAdd(). If successful, SQLITE_OK is +** returned. Otherwise, an SQLite error code. +*/ +static int fts3SegWriterFlush( + Fts3Table *p, /* Virtual table handle */ + SegmentWriter *pWriter, /* SegmentWriter to flush to the db */ + sqlite3_int64 iLevel, /* Value for 'level' column of %_segdir */ + int iIdx /* Value for 'idx' column of %_segdir */ +){ + int rc; /* Return code */ + if( pWriter->pTree ){ + sqlite3_int64 iLast = 0; /* Largest block id written to database */ + sqlite3_int64 iLastLeaf; /* Largest leaf block id written to db */ + char *zRoot = NULL; /* Pointer to buffer containing root node */ + int nRoot = 0; /* Size of buffer zRoot */ + + iLastLeaf = pWriter->iFree; + rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, pWriter->nData); + if( rc==SQLITE_OK ){ + rc = fts3NodeWrite(p, pWriter->pTree, 1, + pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot); } + if( rc==SQLITE_OK ){ + rc = fts3WriteSegdir(p, iLevel, iIdx, + pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot); + } + }else{ + /* The entire tree fits on the root node. Write it to the segdir table. */ + rc = fts3WriteSegdir(p, iLevel, iIdx, + 0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData); + } + p->nLeafAdd++; + return rc; +} + +/* +** Release all memory held by the SegmentWriter object passed as the +** first argument. +*/ +static void fts3SegWriterFree(SegmentWriter *pWriter){ + if( pWriter ){ + sqlite3_free(pWriter->aData); + sqlite3_free(pWriter->zMalloc); + fts3NodeFree(pWriter->pTree); + sqlite3_free(pWriter); + } +} + +/* +** The first value in the apVal[] array is assumed to contain an integer. +** This function tests if there exist any documents with docid values that +** are different from that integer. i.e. if deleting the document with docid +** pRowid would mean the FTS3 table were empty. +** +** If successful, *pisEmpty is set to true if the table is empty except for +** document pRowid, or false otherwise, and SQLITE_OK is returned. If an +** error occurs, an SQLite error code is returned. +*/ +static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ + sqlite3_stmt *pStmt; + int rc; + if( p->zContentTbl ){ + /* If using the content=xxx option, assume the table is never empty */ + *pisEmpty = 0; rc = SQLITE_OK; + }else{ + rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pisEmpty = sqlite3_column_int(pStmt, 0); + } + rc = sqlite3_reset(pStmt); + } } - - *ppExpr = p; return rc; -no_mem: - - if( pCursor ){ - pModule->xClose(pCursor); - } - sqlite3_free(zTemp); - sqlite3_free(p); - *ppExpr = 0; - return SQLITE_NOMEM; } /* -** The output variable *ppExpr is populated with an allocated Fts3Expr -** structure, or set to 0 if the end of the input buffer is reached. +** Set *pnMax to the largest segment level in the database for the index +** iIndex. ** -** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM -** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered. -** If SQLITE_ERROR is returned, pContext is populated with an error message. +** Segment levels are stored in the 'level' column of the %_segdir table. +** +** Return SQLITE_OK if successful, or an SQLite error code if not. */ -static int getNextNode( - ParseContext *pParse, /* fts3 query parse context */ - const char *z, int n, /* Input string */ - Fts3Expr **ppExpr, /* OUT: expression */ - int *pnConsumed /* OUT: Number of bytes consumed */ +static int fts3SegmentMaxLevel( + Fts3Table *p, + int iLangid, + int iIndex, + sqlite3_int64 *pnMax ){ - static const struct Fts3Keyword { - char *z; /* Keyword text */ - unsigned char n; /* Length of the keyword */ - unsigned char parenOnly; /* Only valid in paren mode */ - unsigned char eType; /* Keyword code */ - } aKeyword[] = { - { "OR" , 2, 0, FTSQUERY_OR }, - { "AND", 3, 1, FTSQUERY_AND }, - { "NOT", 3, 1, FTSQUERY_NOT }, - { "NEAR", 4, 0, FTSQUERY_NEAR } - }; - int ii; - int iCol; - int iColLen; + sqlite3_stmt *pStmt; int rc; - Fts3Expr *pRet = 0; - - const char *zInput = z; - int nInput = n; - - pParse->isNot = 0; + assert( iIndex>=0 && iIndexnIndex ); - /* Skip over any whitespace before checking for a keyword, an open or - ** close bracket, or a quoted string. + /* Set pStmt to the compiled version of: + ** + ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? + ** + ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). */ - while( nInput>0 && fts3isspace(*zInput) ){ - nInput--; - zInput++; - } - if( nInput==0 ){ - return SQLITE_DONE; + rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); + if( rc!=SQLITE_OK ) return rc; + sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); + sqlite3_bind_int64(pStmt, 2, + getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) + ); + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pnMax = sqlite3_column_int64(pStmt, 0); } + return sqlite3_reset(pStmt); +} - /* See if we are dealing with a keyword. */ - for(ii=0; ii<(int)(sizeof(aKeyword)/sizeof(struct Fts3Keyword)); ii++){ - const struct Fts3Keyword *pKey = &aKeyword[ii]; - - if( (pKey->parenOnly & ~sqlite3_fts3_enable_parentheses)!=0 ){ - continue; - } - - if( nInput>=pKey->n && 0==memcmp(zInput, pKey->z, pKey->n) ){ - int nNear = SQLITE_FTS3_DEFAULT_NEAR_PARAM; - int nKey = pKey->n; - char cNext; - - /* If this is a "NEAR" keyword, check for an explicit nearness. */ - if( pKey->eType==FTSQUERY_NEAR ){ - assert( nKey==4 ); - if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){ - nNear = 0; - for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){ - nNear = nNear * 10 + (zInput[nKey] - '0'); - } - } - } - - /* At this point this is probably a keyword. But for that to be true, - ** the next byte must contain either whitespace, an open or close - ** parenthesis, a quote character, or EOF. - */ - cNext = zInput[nKey]; - if( fts3isspace(cNext) - || cNext=='"' || cNext=='(' || cNext==')' || cNext==0 - ){ - pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr)); - if( !pRet ){ - return SQLITE_NOMEM; - } - pRet->eType = pKey->eType; - pRet->nNear = nNear; - *ppExpr = pRet; - *pnConsumed = (int)((zInput - z) + nKey); - return SQLITE_OK; - } - - /* Turns out that wasn't a keyword after all. This happens if the - ** user has supplied a token such as "ORacle". Continue. - */ - } - } +/* +** iAbsLevel is an absolute level that may be assumed to exist within +** the database. This function checks if it is the largest level number +** within its index. Assuming no error occurs, *pbMax is set to 1 if +** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK +** is returned. If an error occurs, an error code is returned and the +** final value of *pbMax is undefined. +*/ +static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){ - /* See if we are dealing with a quoted phrase. If this is the case, then - ** search for the closing quote and pass the whole string to getNextString() - ** for processing. This is easy to do, as fts3 has no syntax for escaping - ** a quote character embedded in a string. + /* Set pStmt to the compiled version of: + ** + ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? + ** + ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). */ - if( *zInput=='"' ){ - for(ii=1; iinNest++; - rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed); - if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; } - *pnConsumed = (int)(zInput - z) + 1 + nConsumed; - return rc; - }else if( *zInput==')' ){ - pParse->nNest--; - *pnConsumed = (int)((zInput - z) + 1); - *ppExpr = 0; - return SQLITE_DONE; - } + *pbMax = 0; + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; } + return sqlite3_reset(pStmt); +} - /* If control flows to this point, this must be a regular token, or - ** the end of the input. Read a regular token using the sqlite3_tokenizer - ** interface. Before doing so, figure out if there is an explicit - ** column specifier for the token. - ** - ** TODO: Strangely, it is not possible to associate a column specifier - ** with a quoted phrase, only with a single token. Not sure if this was - ** an implementation artifact or an intentional decision when fts3 was - ** first implemented. Whichever it was, this module duplicates the - ** limitation. - */ - iCol = pParse->iDefaultCol; - iColLen = 0; - for(ii=0; iinCol; ii++){ - const char *zStr = pParse->azCol[ii]; - int nStr = (int)strlen(zStr); - if( nInput>nStr && zInput[nStr]==':' - && sqlite3_strnicmp(zStr, zInput, nStr)==0 - ){ - iCol = ii; - iColLen = (int)((zInput - z) + nStr + 1); - break; +/* +** Delete all entries in the %_segments table associated with the segment +** opened with seg-reader pSeg. This function does not affect the contents +** of the %_segdir table. +*/ +static int fts3DeleteSegment( + Fts3Table *p, /* FTS table handle */ + Fts3SegReader *pSeg /* Segment to delete */ +){ + int rc = SQLITE_OK; /* Return code */ + if( pSeg->iStartBlock ){ + sqlite3_stmt *pDelete; /* SQL statement to delete rows */ + rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDelete, 1, pSeg->iStartBlock); + sqlite3_bind_int64(pDelete, 2, pSeg->iEndBlock); + sqlite3_step(pDelete); + rc = sqlite3_reset(pDelete); } } - rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed); - *pnConsumed += iColLen; return rc; } /* -** The argument is an Fts3Expr structure for a binary operator (any type -** except an FTSQUERY_PHRASE). Return an integer value representing the -** precedence of the operator. Lower values have a higher precedence (i.e. -** group more tightly). For example, in the C language, the == operator -** groups more tightly than ||, and would therefore have a higher precedence. +** This function is used after merging multiple segments into a single large +** segment to delete the old, now redundant, segment b-trees. Specifically, +** it: ** -** When using the new fts3 query syntax (when SQLITE_ENABLE_FTS3_PARENTHESIS -** is defined), the order of the operators in precedence from highest to -** lowest is: +** 1) Deletes all %_segments entries for the segments associated with +** each of the SegReader objects in the array passed as the third +** argument, and ** -** NEAR -** NOT -** AND (including implicit ANDs) -** OR +** 2) deletes all %_segdir entries with level iLevel, or all %_segdir +** entries regardless of level if (iLevel<0). ** -** Note that when using the old query syntax, the OR operator has a higher -** precedence than the AND operator. +** SQLITE_OK is returned if successful, otherwise an SQLite error code. */ -static int opPrecedence(Fts3Expr *p){ - assert( p->eType!=FTSQUERY_PHRASE ); - if( sqlite3_fts3_enable_parentheses ){ - return p->eType; - }else if( p->eType==FTSQUERY_NEAR ){ - return 1; - }else if( p->eType==FTSQUERY_OR ){ - return 2; +static int fts3DeleteSegdir( + Fts3Table *p, /* Virtual table handle */ + int iLangid, /* Language id */ + int iIndex, /* Index for p->aIndex */ + int iLevel, /* Level of %_segdir entries to delete */ + Fts3SegReader **apSegment, /* Array of SegReader objects */ + int nReader /* Size of array apSegment */ +){ + int rc = SQLITE_OK; /* Return Code */ + int i; /* Iterator variable */ + sqlite3_stmt *pDelete = 0; /* SQL statement to delete rows */ + + for(i=0; rc==SQLITE_OK && ieType==FTSQUERY_AND ); - return 3; + if( rc!=SQLITE_OK ){ + return rc; + } + + assert( iLevel>=0 || iLevel==FTS3_SEGCURSOR_ALL ); + if( iLevel==FTS3_SEGCURSOR_ALL ){ + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); + sqlite3_bind_int64(pDelete, 2, + getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) + ); + } + }else{ + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64( + pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) + ); + } + } + + if( rc==SQLITE_OK ){ + sqlite3_step(pDelete); + rc = sqlite3_reset(pDelete); + } + + return rc; } /* -** Argument ppHead contains a pointer to the current head of a query -** expression tree being parsed. pPrev is the expression node most recently -** inserted into the tree. This function adds pNew, which is always a binary -** operator node, into the expression tree based on the relative precedence -** of pNew and the existing nodes of the tree. This may result in the head -** of the tree changing, in which case *ppHead is set to the new root node. +** When this function is called, buffer *ppList (size *pnList bytes) contains +** a position list that may (or may not) feature multiple columns. This +** function adjusts the pointer *ppList and the length *pnList so that they +** identify the subset of the position list that corresponds to column iCol. +** +** If there are no entries in the input position list for column iCol, then +** *pnList is set to zero before returning. +** +** If parameter bZero is non-zero, then any part of the input list following +** the end of the output list is zeroed before returning. */ -static void insertBinaryOperator( - Fts3Expr **ppHead, /* Pointer to the root node of a tree */ - Fts3Expr *pPrev, /* Node most recently inserted into the tree */ - Fts3Expr *pNew /* New binary node to insert into expression tree */ +static void fts3ColumnFilter( + int iCol, /* Column to filter on */ + int bZero, /* Zero out anything following *ppList */ + char **ppList, /* IN/OUT: Pointer to position list */ + int *pnList /* IN/OUT: Size of buffer *ppList in bytes */ ){ - Fts3Expr *pSplit = pPrev; - while( pSplit->pParent && opPrecedence(pSplit->pParent)<=opPrecedence(pNew) ){ - pSplit = pSplit->pParent; + char *pList = *ppList; + int nList = *pnList; + char *pEnd = &pList[nList]; + int iCurrent = 0; + char *p = pList; + + assert( iCol>=0 ); + while( 1 ){ + char c = 0; + while( ppParent ){ - assert( pSplit->pParent->pRight==pSplit ); - pSplit->pParent->pRight = pNew; - pNew->pParent = pSplit->pParent; - }else{ - *ppHead = pNew; + if( bZero && (pEnd - &pList[nList])>0){ + memset(&pList[nList], 0, pEnd - &pList[nList]); } - pNew->pLeft = pSplit; - pSplit->pParent = pNew; + *ppList = pList; + *pnList = nList; } /* -** Parse the fts3 query expression found in buffer z, length n. This function -** returns either when the end of the buffer is reached or an unmatched -** closing bracket - ')' - is encountered. +** Cache data in the Fts3MultiSegReader.aBuffer[] buffer (overwriting any +** existing data). Grow the buffer if required. ** -** If successful, SQLITE_OK is returned, *ppExpr is set to point to the -** parsed form of the expression and *pnConsumed is set to the number of -** bytes read from buffer z. Otherwise, *ppExpr is set to 0 and SQLITE_NOMEM -** (out of memory error) or SQLITE_ERROR (parse error) is returned. +** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered +** trying to resize the buffer, return SQLITE_NOMEM. */ -static int fts3ExprParse( - ParseContext *pParse, /* fts3 query parse context */ - const char *z, int n, /* Text of MATCH query */ - Fts3Expr **ppExpr, /* OUT: Parsed query structure */ - int *pnConsumed /* OUT: Number of bytes consumed */ +static int fts3MsrBufferData( + Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ + char *pList, + int nList ){ - Fts3Expr *pRet = 0; - Fts3Expr *pPrev = 0; - Fts3Expr *pNotBranch = 0; /* Only used in legacy parse mode */ - int nIn = n; - const char *zIn = z; - int rc = SQLITE_OK; - int isRequirePhrase = 1; + if( nList>pMsr->nBuffer ){ + char *pNew; + pMsr->nBuffer = nList*2; + pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); + if( !pNew ) return SQLITE_NOMEM; + pMsr->aBuffer = pNew; + } - while( rc==SQLITE_OK ){ - Fts3Expr *p = 0; - int nByte = 0; + assert( nList>0 ); + memcpy(pMsr->aBuffer, pList, nList); + return SQLITE_OK; +} - rc = getNextNode(pParse, zIn, nIn, &p, &nByte); - assert( nByte>0 || (rc!=SQLITE_OK && p==0) ); - if( rc==SQLITE_OK ){ - if( p ){ - int isPhrase; +SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ + sqlite3_int64 *piDocid, /* OUT: Docid value */ + char **paPoslist, /* OUT: Pointer to position list */ + int *pnPoslist /* OUT: Size of position list in bytes */ +){ + int nMerge = pMsr->nAdvance; + Fts3SegReader **apSegment = pMsr->apSegment; + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( + p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp + ); - if( !sqlite3_fts3_enable_parentheses - && p->eType==FTSQUERY_PHRASE && pParse->isNot - ){ - /* Create an implicit NOT operator. */ - Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); - if( !pNot ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_NOMEM; - goto exprparse_out; - } - pNot->eType = FTSQUERY_NOT; - pNot->pRight = p; - p->pParent = pNot; - if( pNotBranch ){ - pNot->pLeft = pNotBranch; - pNotBranch->pParent = pNot; - } - pNotBranch = pNot; - p = pPrev; - }else{ - int eType = p->eType; - isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); + if( nMerge==0 ){ + *paPoslist = 0; + return SQLITE_OK; + } - /* The isRequirePhrase variable is set to true if a phrase or - ** an expression contained in parenthesis is required. If a - ** binary operator (AND, OR, NOT or NEAR) is encounted when - ** isRequirePhrase is set, this is a syntax error. - */ - if( !isPhrase && isRequirePhrase ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } + while( 1 ){ + Fts3SegReader *pSeg; + pSeg = pMsr->apSegment[0]; - if( isPhrase && !isRequirePhrase ){ - /* Insert an implicit AND operator. */ - Fts3Expr *pAnd; - assert( pRet && pPrev ); - pAnd = fts3MallocZero(sizeof(Fts3Expr)); - if( !pAnd ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_NOMEM; - goto exprparse_out; - } - pAnd->eType = FTSQUERY_AND; - insertBinaryOperator(&pRet, pPrev, pAnd); - pPrev = pAnd; - } + if( pSeg->pOffsetList==0 ){ + *paPoslist = 0; + break; + }else{ + int rc; + char *pList; + int nList; + int j; + sqlite3_int64 iDocid = apSegment[0]->iDocid; - /* This test catches attempts to make either operand of a NEAR - ** operator something other than a phrase. For example, either of - ** the following: - ** - ** (bracketed expression) NEAR phrase - ** phrase NEAR (bracketed expression) - ** - ** Return an error in either case. - */ - if( pPrev && ( - (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE) - || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR) - )){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_ERROR; - goto exprparse_out; - } + rc = fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); + j = 1; + while( rc==SQLITE_OK + && jpOffsetList + && apSegment[j]->iDocid==iDocid + ){ + rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); + j++; + } + if( rc!=SQLITE_OK ) return rc; + fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); - if( isPhrase ){ - if( pRet ){ - assert( pPrev && pPrev->pLeft && pPrev->pRight==0 ); - pPrev->pRight = p; - p->pParent = pPrev; - }else{ - pRet = p; - } - }else{ - insertBinaryOperator(&pRet, pPrev, p); - } - isRequirePhrase = !isPhrase; - } - pPrev = p; + if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ + rc = fts3MsrBufferData(pMsr, pList, nList+1); + if( rc!=SQLITE_OK ) return rc; + assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); + pList = pMsr->aBuffer; } - assert( nByte>0 ); - } - assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) ); - nIn -= nByte; - zIn += nByte; - } - if( rc==SQLITE_DONE && pRet && isRequirePhrase ){ - rc = SQLITE_ERROR; - } + if( pMsr->iColFilter>=0 ){ + fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList); + } - if( rc==SQLITE_DONE ){ - rc = SQLITE_OK; - if( !sqlite3_fts3_enable_parentheses && pNotBranch ){ - if( !pRet ){ - rc = SQLITE_ERROR; - }else{ - Fts3Expr *pIter = pNotBranch; - while( pIter->pLeft ){ - pIter = pIter->pLeft; - } - pIter->pLeft = pRet; - pRet->pParent = pIter; - pRet = pNotBranch; + if( nList>0 ){ + *paPoslist = pList; + *piDocid = iDocid; + *pnPoslist = nList; + break; } } } - *pnConsumed = n - nIn; -exprparse_out: - if( rc!=SQLITE_OK ){ - sqlite3Fts3ExprFree(pRet); - sqlite3Fts3ExprFree(pNotBranch); - pRet = 0; + return SQLITE_OK; +} + +static int fts3SegReaderStart( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr, /* Cursor object */ + const char *zTerm, /* Term searched for (or NULL) */ + int nTerm /* Length of zTerm in bytes */ +){ + int i; + int nSeg = pCsr->nSegment; + + /* If the Fts3SegFilter defines a specific term (or term prefix) to search + ** for, then advance each segment iterator until it points to a term of + ** equal or greater value than the specified term. This prevents many + ** unnecessary merge/sort operations for the case where single segment + ** b-tree leaf nodes contain more than one term. + */ + for(i=0; pCsr->bRestart==0 && inSegment; i++){ + int res = 0; + Fts3SegReader *pSeg = pCsr->apSegment[i]; + do { + int rc = fts3SegReaderNext(p, pSeg, 0); + if( rc!=SQLITE_OK ) return rc; + }while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 ); + + if( pSeg->bLookup && res!=0 ){ + fts3SegReaderSetEof(pSeg); + } } - *ppExpr = pRet; - return rc; + fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp); + + return SQLITE_OK; } -/* -** Return SQLITE_ERROR if the maximum depth of the expression tree passed -** as the only argument is more than nMaxDepth. -*/ -static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){ - int rc = SQLITE_OK; - if( p ){ - if( nMaxDepth<0 ){ - rc = SQLITE_TOOBIG; - }else{ - rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1); - if( rc==SQLITE_OK ){ - rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1); - } +SQLITE_PRIVATE int sqlite3Fts3SegReaderStart( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr, /* Cursor object */ + Fts3SegFilter *pFilter /* Restrictions on range of iteration */ +){ + pCsr->pFilter = pFilter; + return fts3SegReaderStart(p, pCsr, pFilter->zTerm, pFilter->nTerm); +} + +SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr, /* Cursor object */ + int iCol, /* Column to match on. */ + const char *zTerm, /* Term to iterate through a doclist for */ + int nTerm /* Number of bytes in zTerm */ +){ + int i; + int rc; + int nSegment = pCsr->nSegment; + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( + p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp + ); + + assert( pCsr->pFilter==0 ); + assert( zTerm && nTerm>0 ); + + /* Advance each segment iterator until it points to the term zTerm/nTerm. */ + rc = fts3SegReaderStart(p, pCsr, zTerm, nTerm); + if( rc!=SQLITE_OK ) return rc; + + /* Determine how many of the segments actually point to zTerm/nTerm. */ + for(i=0; iapSegment[i]; + if( !pSeg->aNode || fts3SegReaderTermCmp(pSeg, zTerm, nTerm) ){ + break; } } - return rc; + pCsr->nAdvance = i; + + /* Advance each of the segments to point to the first docid. */ + for(i=0; inAdvance; i++){ + rc = fts3SegReaderFirstDocid(p, pCsr->apSegment[i]); + if( rc!=SQLITE_OK ) return rc; + } + fts3SegReaderSort(pCsr->apSegment, i, i, xCmp); + + assert( iCol<0 || iColnColumn ); + pCsr->iColFilter = iCol; + + return SQLITE_OK; } /* -** This function attempts to transform the expression tree at (*pp) to -** an equivalent but more balanced form. The tree is modified in place. -** If successful, SQLITE_OK is returned and (*pp) set to point to the -** new root expression node. +** This function is called on a MultiSegReader that has been started using +** sqlite3Fts3MsrIncrStart(). One or more calls to MsrIncrNext() may also +** have been made. Calling this function puts the MultiSegReader in such +** a state that if the next two calls are: ** -** nMaxDepth is the maximum allowable depth of the balanced sub-tree. +** sqlite3Fts3SegReaderStart() +** sqlite3Fts3SegReaderStep() ** -** Otherwise, if an error occurs, an SQLite error code is returned and -** expression (*pp) freed. +** then the entire doclist for the term is available in +** MultiSegReader.aDoclist/nDoclist. */ -static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){ - int rc = SQLITE_OK; /* Return code */ - Fts3Expr *pRoot = *pp; /* Initial root node */ - Fts3Expr *pFree = 0; /* List of free nodes. Linked by pParent. */ - int eType = pRoot->eType; /* Type of node in this tree */ - - if( nMaxDepth==0 ){ - rc = SQLITE_ERROR; - } +SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){ + int i; /* Used to iterate through segment-readers */ - if( rc==SQLITE_OK ){ - if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){ - Fts3Expr **apLeaf; - apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth); - if( 0==apLeaf ){ - rc = SQLITE_NOMEM; - }else{ - memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth); - } + assert( pCsr->zTerm==0 ); + assert( pCsr->nTerm==0 ); + assert( pCsr->aDoclist==0 ); + assert( pCsr->nDoclist==0 ); - if( rc==SQLITE_OK ){ - int i; - Fts3Expr *p; + pCsr->nAdvance = 0; + pCsr->bRestart = 1; + for(i=0; inSegment; i++){ + pCsr->apSegment[i]->pOffsetList = 0; + pCsr->apSegment[i]->nOffsetList = 0; + pCsr->apSegment[i]->iDocid = 0; + } - /* Set $p to point to the left-most leaf in the tree of eType nodes. */ - for(p=pRoot; p->eType==eType; p=p->pLeft){ - assert( p->pParent==0 || p->pParent->pLeft==p ); - assert( p->pLeft && p->pRight ); - } + return SQLITE_OK; +} - /* This loop runs once for each leaf in the tree of eType nodes. */ - while( 1 ){ - int iLvl; - Fts3Expr *pParent = p->pParent; /* Current parent of p */ +static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){ + if( nReq>pCsr->nBuffer ){ + char *aNew; + pCsr->nBuffer = nReq*2; + aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); + if( !aNew ){ + return SQLITE_NOMEM; + } + pCsr->aBuffer = aNew; + } + return SQLITE_OK; +} - assert( pParent==0 || pParent->pLeft==p ); - p->pParent = 0; - if( pParent ){ - pParent->pLeft = 0; - }else{ - pRoot = 0; - } - rc = fts3ExprBalance(&p, nMaxDepth-1); - if( rc!=SQLITE_OK ) break; - for(iLvl=0; p && iLvlpLeft = apLeaf[iLvl]; - pFree->pRight = p; - pFree->pLeft->pParent = pFree; - pFree->pRight->pParent = pFree; +SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + Fts3Table *p, /* Virtual table handle */ + Fts3MultiSegReader *pCsr /* Cursor object */ +){ + int rc = SQLITE_OK; - p = pFree; - pFree = pFree->pParent; - p->pParent = 0; - apLeaf[iLvl] = 0; - } - } - if( p ){ - sqlite3Fts3ExprFree(p); - rc = SQLITE_TOOBIG; - break; - } + int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY); + int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS); + int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); + int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); + int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); + int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST); - /* If that was the last leaf node, break out of the loop */ - if( pParent==0 ) break; + Fts3SegReader **apSegment = pCsr->apSegment; + int nSegment = pCsr->nSegment; + Fts3SegFilter *pFilter = pCsr->pFilter; + int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( + p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp + ); - /* Set $p to point to the next leaf in the tree of eType nodes */ - for(p=pParent->pRight; p->eType==eType; p=p->pLeft); + if( pCsr->nSegment==0 ) return SQLITE_OK; - /* Remove pParent from the original tree. */ - assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent ); - pParent->pRight->pParent = pParent->pParent; - if( pParent->pParent ){ - pParent->pParent->pLeft = pParent->pRight; - }else{ - assert( pParent==pRoot ); - pRoot = pParent->pRight; - } + do { + int nMerge; + int i; - /* Link pParent into the free node list. It will be used as an - ** internal node of the new tree. */ - pParent->pParent = pFree; - pFree = pParent; - } + /* Advance the first pCsr->nAdvance entries in the apSegment[] array + ** forward. Then sort the list in order of current term again. + */ + for(i=0; inAdvance; i++){ + Fts3SegReader *pSeg = apSegment[i]; + if( pSeg->bLookup ){ + fts3SegReaderSetEof(pSeg); + }else{ + rc = fts3SegReaderNext(p, pSeg, 0); + } + if( rc!=SQLITE_OK ) return rc; + } + fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp); + pCsr->nAdvance = 0; - if( rc==SQLITE_OK ){ - p = 0; - for(i=0; ipParent = 0; - }else{ - assert( pFree!=0 ); - pFree->pRight = p; - pFree->pLeft = apLeaf[i]; - pFree->pLeft->pParent = pFree; - pFree->pRight->pParent = pFree; + /* If all the seg-readers are at EOF, we're finished. return SQLITE_OK. */ + assert( rc==SQLITE_OK ); + if( apSegment[0]->aNode==0 ) break; - p = pFree; - pFree = pFree->pParent; - p->pParent = 0; - } - } - } - pRoot = p; - }else{ - /* An error occurred. Delete the contents of the apLeaf[] array - ** and pFree list. Everything else is cleaned up by the call to - ** sqlite3Fts3ExprFree(pRoot) below. */ - Fts3Expr *pDel; - for(i=0; ipParent; - sqlite3_free(pDel); - } - } + pCsr->nTerm = apSegment[0]->nTerm; + pCsr->zTerm = apSegment[0]->zTerm; - assert( pFree==0 ); - sqlite3_free( apLeaf ); + /* If this is a prefix-search, and if the term that apSegment[0] points + ** to does not share a suffix with pFilter->zTerm/nTerm, then all + ** required callbacks have been made. In this case exit early. + ** + ** Similarly, if this is a search for an exact match, and the first term + ** of segment apSegment[0] is not a match, exit early. + */ + if( pFilter->zTerm && !isScan ){ + if( pCsr->nTermnTerm + || (!isPrefix && pCsr->nTerm>pFilter->nTerm) + || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm) + ){ + break; } - }else if( eType==FTSQUERY_NOT ){ - Fts3Expr *pLeft = pRoot->pLeft; - Fts3Expr *pRight = pRoot->pRight; + } - pRoot->pLeft = 0; - pRoot->pRight = 0; - pLeft->pParent = 0; - pRight->pParent = 0; + nMerge = 1; + while( nMergeaNode + && apSegment[nMerge]->nTerm==pCsr->nTerm + && 0==memcmp(pCsr->zTerm, apSegment[nMerge]->zTerm, pCsr->nTerm) + ){ + nMerge++; + } - rc = fts3ExprBalance(&pLeft, nMaxDepth-1); - if( rc==SQLITE_OK ){ - rc = fts3ExprBalance(&pRight, nMaxDepth-1); + assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); + if( nMerge==1 + && !isIgnoreEmpty + && !isFirst + && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) + ){ + pCsr->nDoclist = apSegment[0]->nDoclist; + if( fts3SegReaderIsPending(apSegment[0]) ){ + rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); + pCsr->aDoclist = pCsr->aBuffer; + }else{ + pCsr->aDoclist = apSegment[0]->aDoclist; } + if( rc==SQLITE_OK ) rc = SQLITE_ROW; + }else{ + int nDoclist = 0; /* Size of doclist */ + sqlite3_int64 iPrev = 0; /* Previous docid stored in doclist */ - if( rc!=SQLITE_OK ){ - sqlite3Fts3ExprFree(pRight); - sqlite3Fts3ExprFree(pLeft); - }else{ - assert( pLeft && pRight ); - pRoot->pLeft = pLeft; - pLeft->pParent = pRoot; - pRoot->pRight = pRight; - pRight->pParent = pRoot; + /* The current term of the first nMerge entries in the array + ** of Fts3SegReader objects is the same. The doclists must be merged + ** and a single term returned with the merged doclist. + */ + for(i=0; ipOffsetList ){ + int j; /* Number of segments that share a docid */ + char *pList = 0; + int nList = 0; + int nByte; + sqlite3_int64 iDocid = apSegment[0]->iDocid; + fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); + j = 1; + while( jpOffsetList + && apSegment[j]->iDocid==iDocid + ){ + fts3SegReaderNextDocid(p, apSegment[j], 0, 0); + j++; + } -/* -** This function is similar to sqlite3Fts3ExprParse(), with the following -** differences: -** -** 1. It does not do expression rebalancing. -** 2. It does not check that the expression does not exceed the -** maximum allowable depth. -** 3. Even if it fails, *ppExpr may still be set to point to an -** expression tree. It should be deleted using sqlite3Fts3ExprFree() -** in this case. -*/ -static int fts3ExprParseUnbalanced( - sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ - int iLangid, /* Language id for tokenizer */ - char **azCol, /* Array of column names for fts3 table */ - int bFts4, /* True to allow FTS4-only syntax */ - int nCol, /* Number of entries in azCol[] */ - int iDefaultCol, /* Default column to query */ - const char *z, int n, /* Text of MATCH query */ - Fts3Expr **ppExpr /* OUT: Parsed query structure */ -){ - int nParsed; - int rc; - ParseContext sParse; + if( isColFilter ){ + fts3ColumnFilter(pFilter->iCol, 0, &pList, &nList); + } - memset(&sParse, 0, sizeof(ParseContext)); - sParse.pTokenizer = pTokenizer; - sParse.iLangid = iLangid; - sParse.azCol = (const char **)azCol; - sParse.nCol = nCol; - sParse.iDefaultCol = iDefaultCol; - sParse.bFts4 = bFts4; - if( z==0 ){ - *ppExpr = 0; - return SQLITE_OK; - } - if( n<0 ){ - n = (int)strlen(z); - } - rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed); - assert( rc==SQLITE_OK || *ppExpr==0 ); + if( !isIgnoreEmpty || nList>0 ){ - /* Check for mismatched parenthesis */ - if( rc==SQLITE_OK && sParse.nNest ){ - rc = SQLITE_ERROR; - } - - return rc; -} + /* Calculate the 'docid' delta value to write into the merged + ** doclist. */ + sqlite3_int64 iDelta; + if( p->bDescIdx && nDoclist>0 ){ + if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB; + iDelta = (i64)((u64)iPrev - (u64)iDocid); + }else{ + if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB; + iDelta = (i64)((u64)iDocid - (u64)iPrev); + } -/* -** Parameters z and n contain a pointer to and length of a buffer containing -** an fts3 query expression, respectively. This function attempts to parse the -** query expression and create a tree of Fts3Expr structures representing the -** parsed expression. If successful, *ppExpr is set to point to the head -** of the parsed expression tree and SQLITE_OK is returned. If an error -** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse -** error) is returned and *ppExpr is set to 0. -** -** If parameter n is a negative number, then z is assumed to point to a -** nul-terminated string and the length is determined using strlen(). -** -** The first parameter, pTokenizer, is passed the fts3 tokenizer module to -** use to normalize query tokens while parsing the expression. The azCol[] -** array, which is assumed to contain nCol entries, should contain the names -** of each column in the target fts3 table, in order from left to right. -** Column names must be nul-terminated strings. -** -** The iDefaultCol parameter should be passed the index of the table column -** that appears on the left-hand-side of the MATCH operator (the default -** column to match against for tokens for which a column name is not explicitly -** specified as part of the query string), or -1 if tokens may by default -** match any table column. -*/ -SQLITE_PRIVATE int sqlite3Fts3ExprParse( - sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ - int iLangid, /* Language id for tokenizer */ - char **azCol, /* Array of column names for fts3 table */ - int bFts4, /* True to allow FTS4-only syntax */ - int nCol, /* Number of entries in azCol[] */ - int iDefaultCol, /* Default column to query */ - const char *z, int n, /* Text of MATCH query */ - Fts3Expr **ppExpr, /* OUT: Parsed query structure */ - char **pzErr /* OUT: Error message (sqlite3_malloc) */ -){ - int rc = fts3ExprParseUnbalanced( - pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr - ); - - /* Rebalance the expression. And check that its depth does not exceed - ** SQLITE_FTS3_MAX_EXPR_DEPTH. */ - if( rc==SQLITE_OK && *ppExpr ){ - rc = fts3ExprBalance(ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); - if( rc==SQLITE_OK ){ - rc = fts3ExprCheckDepth(*ppExpr, SQLITE_FTS3_MAX_EXPR_DEPTH); - } - } + nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); + + rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + + if( isFirst ){ + char *a = &pCsr->aBuffer[nDoclist]; + int nWrite; + + nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); + if( nWrite ){ + iPrev = iDocid; + nDoclist += nWrite; + } + }else{ + nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); + iPrev = iDocid; + if( isRequirePos ){ + memcpy(&pCsr->aBuffer[nDoclist], pList, nList); + nDoclist += nList; + pCsr->aBuffer[nDoclist++] = '\0'; + } + } + } - if( rc!=SQLITE_OK ){ - sqlite3Fts3ExprFree(*ppExpr); - *ppExpr = 0; - if( rc==SQLITE_TOOBIG ){ - sqlite3Fts3ErrMsg(pzErr, - "FTS expression tree is too large (maximum depth %d)", - SQLITE_FTS3_MAX_EXPR_DEPTH - ); - rc = SQLITE_ERROR; - }else if( rc==SQLITE_ERROR ){ - sqlite3Fts3ErrMsg(pzErr, "malformed MATCH expression: [%s]", z); + fts3SegReaderSort(apSegment, nMerge, j, xCmp); + } + if( nDoclist>0 ){ + rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING); + pCsr->aDoclist = pCsr->aBuffer; + pCsr->nDoclist = nDoclist; + rc = SQLITE_ROW; + } } - } + pCsr->nAdvance = nMerge; + }while( rc==SQLITE_OK ); return rc; } -/* -** Free a single node of an expression tree. -*/ -static void fts3FreeExprNode(Fts3Expr *p){ - assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 ); - sqlite3Fts3EvalPhraseCleanup(p->pPhrase); - sqlite3_free(p->aMI); - sqlite3_free(p); + +SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish( + Fts3MultiSegReader *pCsr /* Cursor object */ +){ + if( pCsr ){ + int i; + for(i=0; inSegment; i++){ + sqlite3Fts3SegReaderFree(pCsr->apSegment[i]); + } + sqlite3_free(pCsr->apSegment); + sqlite3_free(pCsr->aBuffer); + + pCsr->nSegment = 0; + pCsr->apSegment = 0; + pCsr->aBuffer = 0; + } } /* -** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse(). +** Decode the "end_block" field, selected by column iCol of the SELECT +** statement passed as the first argument. ** -** This function would be simpler if it recursively called itself. But -** that would mean passing a sufficiently large expression to ExprParse() -** could cause a stack overflow. +** The "end_block" field may contain either an integer, or a text field +** containing the text representation of two non-negative integers separated +** by one or more space (0x20) characters. In the first case, set *piEndBlock +** to the integer value and *pnByte to zero before returning. In the second, +** set *piEndBlock to the first value and *pnByte to the second. */ -SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){ - Fts3Expr *p; - assert( pDel==0 || pDel->pParent==0 ); - for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){ - assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft ); - } - while( p ){ - Fts3Expr *pParent = p->pParent; - fts3FreeExprNode(p); - if( pParent && p==pParent->pLeft && pParent->pRight ){ - p = pParent->pRight; - while( p && (p->pLeft || p->pRight) ){ - assert( p==p->pParent->pRight || p==p->pParent->pLeft ); - p = (p->pLeft ? p->pLeft : p->pRight); - } - }else{ - p = pParent; +static void fts3ReadEndBlockField( + sqlite3_stmt *pStmt, + int iCol, + i64 *piEndBlock, + i64 *pnByte +){ + const unsigned char *zText = sqlite3_column_text(pStmt, iCol); + if( zText ){ + int i; + int iMul = 1; + u64 iVal = 0; + for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); + } + *piEndBlock = (i64)iVal; + while( zText[i]==' ' ) i++; + iVal = 0; + if( zText[i]=='-' ){ + i++; + iMul = -1; + } + for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ + iVal = iVal*10 + (zText[i] - '0'); } + *pnByte = ((i64)iVal * (i64)iMul); } } -/**************************************************************************** -***************************************************************************** -** Everything after this point is just test code. -*/ - -#ifdef SQLITE_TEST - -/* #include */ /* -** Function to query the hash-table of tokenizers (see README.tokenizers). +** A segment of size nByte bytes has just been written to absolute level +** iAbsLevel. Promote any segments that should be promoted as a result. */ -static int queryTestTokenizer( - sqlite3 *db, - const char *zName, - const sqlite3_tokenizer_module **pp +static int fts3PromoteSegments( + Fts3Table *p, /* FTS table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level just updated */ + sqlite3_int64 nByte /* Size of new segment at iAbsLevel */ ){ - int rc; - sqlite3_stmt *pStmt; - const char zSql[] = "SELECT fts3_tokenizer(?)"; + int rc = SQLITE_OK; + sqlite3_stmt *pRange; - *pp = 0; - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ){ - return rc; - } + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0); - sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){ - memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); + if( rc==SQLITE_OK ){ + int bOk = 0; + i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1; + i64 nLimit = (nByte*3)/2; + + /* Loop through all entries in the %_segdir table corresponding to + ** segments in this index on levels greater than iAbsLevel. If there is + ** at least one such segment, and it is possible to determine that all + ** such segments are smaller than nLimit bytes in size, they will be + ** promoted to level iAbsLevel. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel+1); + sqlite3_bind_int64(pRange, 2, iLast); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + i64 nSize = 0, dummy; + fts3ReadEndBlockField(pRange, 2, &dummy, &nSize); + if( nSize<=0 || nSize>nLimit ){ + /* If nSize==0, then the %_segdir.end_block field does not not + ** contain a size value. This happens if it was written by an + ** old version of FTS. In this case it is not possible to determine + ** the size of the segment, and so segment promotion does not + ** take place. */ + bOk = 0; + break; + } + bOk = 1; } - } + rc = sqlite3_reset(pRange); - return sqlite3_finalize(pStmt); -} + if( bOk ){ + int iIdx = 0; + sqlite3_stmt *pUpdate1 = 0; + sqlite3_stmt *pUpdate2 = 0; -/* -** Return a pointer to a buffer containing a text representation of the -** expression passed as the first argument. The buffer is obtained from -** sqlite3_malloc(). It is the responsibility of the caller to use -** sqlite3_free() to release the memory. If an OOM condition is encountered, -** NULL is returned. -** -** If the second argument is not NULL, then its contents are prepended to -** the returned expression text and then freed using sqlite3_free(). -*/ -static char *exprToString(Fts3Expr *pExpr, char *zBuf){ - if( pExpr==0 ){ - return sqlite3_mprintf(""); - } - switch( pExpr->eType ){ - case FTSQUERY_PHRASE: { - Fts3Phrase *pPhrase = pExpr->pPhrase; - int i; - zBuf = sqlite3_mprintf( - "%zPHRASE %d 0", zBuf, pPhrase->iColumn); - for(i=0; zBuf && inToken; i++){ - zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, - pPhrase->aToken[i].n, pPhrase->aToken[i].z, - (pPhrase->aToken[i].isPrefix?"+":"") - ); + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); + } + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0); } - return zBuf; - } - case FTSQUERY_NEAR: - zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear); - break; - case FTSQUERY_NOT: - zBuf = sqlite3_mprintf("%zNOT ", zBuf); - break; - case FTSQUERY_AND: - zBuf = sqlite3_mprintf("%zAND ", zBuf); - break; - case FTSQUERY_OR: - zBuf = sqlite3_mprintf("%zOR ", zBuf); - break; - } + if( rc==SQLITE_OK ){ - if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf); - if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf); - if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf); + /* Loop through all %_segdir entries for segments in this index with + ** levels equal to or greater than iAbsLevel. As each entry is visited, + ** updated it to set (level = -1) and (idx = N), where N is 0 for the + ** oldest segment in the range, 1 for the next oldest, and so on. + ** + ** In other words, move all segments being promoted to level -1, + ** setting the "idx" fields as appropriate to keep them in the same + ** order. The contents of level -1 (which is never used, except + ** transiently here), will be moved back to level iAbsLevel below. */ + sqlite3_bind_int64(pRange, 1, iAbsLevel); + while( SQLITE_ROW==sqlite3_step(pRange) ){ + sqlite3_bind_int(pUpdate1, 1, iIdx++); + sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0)); + sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1)); + sqlite3_step(pUpdate1); + rc = sqlite3_reset(pUpdate1); + if( rc!=SQLITE_OK ){ + sqlite3_reset(pRange); + break; + } + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3_reset(pRange); + } - if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf); - if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf); + /* Move level -1 to level iAbsLevel */ + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pUpdate2, 1, iAbsLevel); + sqlite3_step(pUpdate2); + rc = sqlite3_reset(pUpdate2); + } + } + } - return zBuf; + + return rc; } /* -** This is the implementation of a scalar SQL function used to test the -** expression parser. It should be called as follows: -** -** fts3_exprtest(, , , ...); -** -** The first argument, , is the name of the fts3 tokenizer used -** to parse the query expression (see README.tokenizers). The second argument -** is the query expression to parse. Each subsequent argument is the name -** of a column of the fts3 table that the query expression may refer to. -** For example: +** Merge all level iLevel segments in the database into a single +** iLevel+1 segment. Or, if iLevel<0, merge all segments into a +** single segment with a level equal to the numerically largest level +** currently present in the database. ** -** SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2'); +** If this function is called with iLevel<0, but there is only one +** segment in the database, SQLITE_DONE is returned immediately. +** Otherwise, if successful, SQLITE_OK is returned. If an error occurs, +** an SQLite error code is returned. */ -static void fts3ExprTest( - sqlite3_context *context, - int argc, - sqlite3_value **argv +static int fts3SegmentMerge( + Fts3Table *p, + int iLangid, /* Language id to merge */ + int iIndex, /* Index in p->aIndex[] to merge */ + int iLevel /* Level to merge */ ){ - sqlite3_tokenizer_module const *pModule = 0; - sqlite3_tokenizer *pTokenizer = 0; - int rc; - char **azCol = 0; - const char *zExpr; - int nExpr; - int nCol; - int ii; - Fts3Expr *pExpr; - char *zBuf = 0; - sqlite3 *db = sqlite3_context_db_handle(context); + int rc; /* Return code */ + int iIdx = 0; /* Index of new segment */ + sqlite3_int64 iNewLevel = 0; /* Level/index to create new segment at */ + SegmentWriter *pWriter = 0; /* Used to write the new, merged, segment */ + Fts3SegFilter filter; /* Segment term filter condition */ + Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */ + int bIgnoreEmpty = 0; /* True to ignore empty segments */ + i64 iMaxLevel = 0; /* Max level number for this index/langid */ - if( argc<3 ){ - sqlite3_result_error(context, - "Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1 - ); - return; - } + assert( iLevel==FTS3_SEGCURSOR_ALL + || iLevel==FTS3_SEGCURSOR_PENDING + || iLevel>=0 + ); + assert( iLevel=0 && iIndexnIndex ); - rc = queryTestTokenizer(db, - (const char *)sqlite3_value_text(argv[0]), &pModule); - if( rc==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(context); - goto exprtest_out; - }else if( !pModule ){ - sqlite3_result_error(context, "No such tokenizer module", -1); - goto exprtest_out; - } + rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr); + if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished; - rc = pModule->xCreate(0, 0, &pTokenizer); - assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); - if( rc==SQLITE_NOMEM ){ - sqlite3_result_error_nomem(context); - goto exprtest_out; + if( iLevel!=FTS3_SEGCURSOR_PENDING ){ + rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel); + if( rc!=SQLITE_OK ) goto finished; } - pTokenizer->pModule = pModule; - zExpr = (const char *)sqlite3_value_text(argv[1]); - nExpr = sqlite3_value_bytes(argv[1]); - nCol = argc-2; - azCol = (char **)sqlite3_malloc(nCol*sizeof(char *)); - if( !azCol ){ - sqlite3_result_error_nomem(context); - goto exprtest_out; - } - for(ii=0; iiiMaxLevel); } + if( rc!=SQLITE_OK ) goto finished; - if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ - sqlite3Fts3ExprFree(pExpr); - sqlite3_result_error(context, "Error parsing expression", -1); - }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ - sqlite3_result_error_nomem(context); - }else{ - sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); - sqlite3_free(zBuf); - } + assert( csr.nSegment>0 ); + assert_fts3_nc( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); + assert_fts3_nc( + iNewLevelxDestroy(pTokenizer); + rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); + while( SQLITE_OK==rc ){ + rc = sqlite3Fts3SegReaderStep(p, &csr); + if( rc!=SQLITE_ROW ) break; + rc = fts3SegWriterAdd(p, &pWriter, 1, + csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist); } - sqlite3_free(azCol); -} + if( rc!=SQLITE_OK ) goto finished; + assert_fts3_nc( pWriter || bIgnoreEmpty ); -/* -** Register the query expression parser test function fts3_exprtest() -** with database connection db. -*/ -SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){ - int rc = sqlite3_create_function( - db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0 - ); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "fts3_exprtest_rebalance", - -1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0 + if( iLevel!=FTS3_SEGCURSOR_PENDING ){ + rc = fts3DeleteSegdir( + p, iLangid, iIndex, iLevel, csr.apSegment, csr.nSegment ); + if( rc!=SQLITE_OK ) goto finished; + } + if( pWriter ){ + rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx); + if( rc==SQLITE_OK ){ + if( iLevel==FTS3_SEGCURSOR_PENDING || iNewLevelnLeafData); + } + } } + + finished: + fts3SegWriterFree(pWriter); + sqlite3Fts3SegReaderFinish(&csr); return rc; } -#endif -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ - -/************** End of fts3_expr.c *******************************************/ -/************** Begin file fts3_hash.c ***************************************/ -/* -** 2001 September 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This is the implementation of generic hash-tables used in SQLite. -** We've modified it slightly to serve as a standalone hash table -** implementation for the full-text indexing module. -*/ /* -** The code in this file is only compiled if: -** -** * The FTS3 module is being built as an extension -** (in which case SQLITE_CORE is not defined), or -** -** * The FTS3 module is being built into the core of -** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +** Flush the contents of pendingTerms to level 0 segments. */ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -/* #include */ -/* #include */ -/* #include */ - -/* #include "fts3_hash.h" */ +SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ + int rc = SQLITE_OK; + int i; -/* -** Malloc and Free functions -*/ -static void *fts3HashMalloc(int n){ - void *p = sqlite3_malloc(n); - if( p ){ - memset(p, 0, n); + for(i=0; rc==SQLITE_OK && inIndex; i++){ + rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; } - return p; -} -static void fts3HashFree(void *p){ - sqlite3_free(p); -} - -/* Turn bulk memory into a hash table object by initializing the -** fields of the Hash structure. -** -** "pNew" is a pointer to the hash table that is to be initialized. -** keyClass is one of the constants -** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass -** determines what kind of key the hash table will use. "copyKey" is -** true if the hash table should make its own private copy of keys and -** false if it should just use the supplied pointer. -*/ -SQLITE_PRIVATE void sqlite3Fts3HashInit(Fts3Hash *pNew, char keyClass, char copyKey){ - assert( pNew!=0 ); - assert( keyClass>=FTS3_HASH_STRING && keyClass<=FTS3_HASH_BINARY ); - pNew->keyClass = keyClass; - pNew->copyKey = copyKey; - pNew->first = 0; - pNew->count = 0; - pNew->htsize = 0; - pNew->ht = 0; -} - -/* Remove all entries from a hash table. Reclaim all memory. -** Call this routine to delete a hash table or to reset a hash table -** to the empty state. -*/ -SQLITE_PRIVATE void sqlite3Fts3HashClear(Fts3Hash *pH){ - Fts3HashElem *elem; /* For looping over all elements of the table */ + sqlite3Fts3PendingTermsClear(p); - assert( pH!=0 ); - elem = pH->first; - pH->first = 0; - fts3HashFree(pH->ht); - pH->ht = 0; - pH->htsize = 0; - while( elem ){ - Fts3HashElem *next_elem = elem->next; - if( pH->copyKey && elem->pKey ){ - fts3HashFree(elem->pKey); + /* Determine the auto-incr-merge setting if unknown. If enabled, + ** estimate the number of leaf blocks of content to be written + */ + if( rc==SQLITE_OK && p->bHasStat + && p->nAutoincrmerge==0xff && p->nLeafAdd>0 + ){ + sqlite3_stmt *pStmt = 0; + rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); + rc = sqlite3_step(pStmt); + if( rc==SQLITE_ROW ){ + p->nAutoincrmerge = sqlite3_column_int(pStmt, 0); + if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8; + }else if( rc==SQLITE_DONE ){ + p->nAutoincrmerge = 0; + } + rc = sqlite3_reset(pStmt); } - fts3HashFree(elem); - elem = next_elem; } - pH->count = 0; + return rc; } /* -** Hash and comparison functions when the mode is FTS3_HASH_STRING +** Encode N integers as varints into a blob. */ -static int fts3StrHash(const void *pKey, int nKey){ - const char *z = (const char *)pKey; - unsigned h = 0; - if( nKey<=0 ) nKey = (int) strlen(z); - while( nKey > 0 ){ - h = (h<<3) ^ h ^ *z++; - nKey--; +static void fts3EncodeIntArray( + int N, /* The number of integers to encode */ + u32 *a, /* The integer values */ + char *zBuf, /* Write the BLOB here */ + int *pNBuf /* Write number of bytes if zBuf[] used here */ +){ + int i, j; + for(i=j=0; i 0 ){ - h = (h<<3) ^ h ^ *(z++); +static void fts3DecodeIntArray( + int N, /* The number of integers to decode */ + u32 *a, /* Write the integer values */ + const char *zBuf, /* The BLOB containing the varints */ + int nBuf /* size of the BLOB */ +){ + int i = 0; + if( nBuf && (zBuf[nBuf-1]&0x80)==0 ){ + int j; + for(i=j=0; iiPrevDocid. The sizes are encoded as +** a blob of varints. */ -static int (*ftsHashFunction(int keyClass))(const void*,int){ - if( keyClass==FTS3_HASH_STRING ){ - return &fts3StrHash; - }else{ - assert( keyClass==FTS3_HASH_BINARY ); - return &fts3BinHash; +static void fts3InsertDocsize( + int *pRC, /* Result code */ + Fts3Table *p, /* Table into which to insert */ + u32 *aSz /* Sizes of each column, in tokens */ +){ + char *pBlob; /* The BLOB encoding of the document size */ + int nBlob; /* Number of bytes in the BLOB */ + sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ + int rc; /* Result code from subfunctions */ + + if( *pRC ) return; + pBlob = sqlite3_malloc64( 10*(sqlite3_int64)p->nColumn ); + if( pBlob==0 ){ + *pRC = SQLITE_NOMEM; + return; + } + fts3EncodeIntArray(p->nColumn, aSz, pBlob, &nBlob); + rc = fts3SqlStmt(p, SQL_REPLACE_DOCSIZE, &pStmt, 0); + if( rc ){ + sqlite3_free(pBlob); + *pRC = rc; + return; } + sqlite3_bind_int64(pStmt, 1, p->iPrevDocid); + sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, sqlite3_free); + sqlite3_step(pStmt); + *pRC = sqlite3_reset(pStmt); } /* -** Return a pointer to the appropriate hash function given the key class. +** Record 0 of the %_stat table contains a blob consisting of N varints, +** where N is the number of user defined columns in the fts3 table plus +** two. If nCol is the number of user defined columns, then values of the +** varints are set as follows: +** +** Varint 0: Total number of rows in the table. +** +** Varint 1..nCol: For each column, the total number of tokens stored in +** the column for all rows of the table. +** +** Varint 1+nCol: The total size, in bytes, of all text values in all +** columns of all rows of the table. ** -** For help in interpreted the obscure C code in the function definition, -** see the header comment on the previous function. -*/ -static int (*ftsCompareFunction(int keyClass))(const void*,int,const void*,int){ - if( keyClass==FTS3_HASH_STRING ){ - return &fts3StrCompare; - }else{ - assert( keyClass==FTS3_HASH_BINARY ); - return &fts3BinCompare; - } -} - -/* Link an element into the hash table */ -static void fts3HashInsertElement( - Fts3Hash *pH, /* The complete hash table */ - struct _fts3ht *pEntry, /* The entry into which pNew is inserted */ - Fts3HashElem *pNew /* The element to be inserted */ +static void fts3UpdateDocTotals( + int *pRC, /* The result code */ + Fts3Table *p, /* Table being updated */ + u32 *aSzIns, /* Size increases */ + u32 *aSzDel, /* Size decreases */ + int nChng /* Change in the number of documents */ ){ - Fts3HashElem *pHead; /* First element already in pEntry */ - pHead = pEntry->chain; - if( pHead ){ - pNew->next = pHead; - pNew->prev = pHead->prev; - if( pHead->prev ){ pHead->prev->next = pNew; } - else { pH->first = pNew; } - pHead->prev = pNew; - }else{ - pNew->next = pH->first; - if( pH->first ){ pH->first->prev = pNew; } - pNew->prev = 0; - pH->first = pNew; - } - pEntry->count++; - pEntry->chain = pNew; -} - + char *pBlob; /* Storage for BLOB written into %_stat */ + int nBlob; /* Size of BLOB written into %_stat */ + u32 *a; /* Array of integers that becomes the BLOB */ + sqlite3_stmt *pStmt; /* Statement for reading and writing */ + int i; /* Loop counter */ + int rc; /* Result code from subfunctions */ -/* Resize the hash table so that it cantains "new_size" buckets. -** "new_size" must be a power of 2. The hash table might fail -** to resize if sqliteMalloc() fails. -** -** Return non-zero if a memory allocation error occurs. -*/ -static int fts3Rehash(Fts3Hash *pH, int new_size){ - struct _fts3ht *new_ht; /* The new hash table */ - Fts3HashElem *elem, *next_elem; /* For looping over existing elements */ - int (*xHash)(const void*,int); /* The hash function */ + const int nStat = p->nColumn+2; - assert( (new_size & (new_size-1))==0 ); - new_ht = (struct _fts3ht *)fts3HashMalloc( new_size*sizeof(struct _fts3ht) ); - if( new_ht==0 ) return 1; - fts3HashFree(pH->ht); - pH->ht = new_ht; - pH->htsize = new_size; - xHash = ftsHashFunction(pH->keyClass); - for(elem=pH->first, pH->first=0; elem; elem = next_elem){ - int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); - next_elem = elem->next; - fts3HashInsertElement(pH, &new_ht[h], elem); + if( *pRC ) return; + a = sqlite3_malloc64( (sizeof(u32)+10)*(sqlite3_int64)nStat ); + if( a==0 ){ + *pRC = SQLITE_NOMEM; + return; } - return 0; -} - -/* This function (for internal use only) locates an element in an -** hash table that matches the given key. The hash for this key has -** already been computed and is passed as the 4th parameter. -*/ -static Fts3HashElem *fts3FindElementByHash( - const Fts3Hash *pH, /* The pH to be searched */ - const void *pKey, /* The key we are searching for */ - int nKey, - int h /* The hash for this key. */ -){ - Fts3HashElem *elem; /* Used to loop thru the element list */ - int count; /* Number of elements left to test */ - int (*xCompare)(const void*,int,const void*,int); /* comparison function */ - - if( pH->ht ){ - struct _fts3ht *pEntry = &pH->ht[h]; - elem = pEntry->chain; - count = pEntry->count; - xCompare = ftsCompareFunction(pH->keyClass); - while( count-- && elem ){ - if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ - return elem; - } - elem = elem->next; - } + pBlob = (char*)&a[nStat]; + rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); + if( rc ){ + sqlite3_free(a); + *pRC = rc; + return; } - return 0; -} - -/* Remove a single entry from the hash table given a pointer to that -** element and a hash on the element's key. -*/ -static void fts3RemoveElementByHash( - Fts3Hash *pH, /* The pH containing "elem" */ - Fts3HashElem* elem, /* The element to be removed from the pH */ - int h /* Hash value for the element */ -){ - struct _fts3ht *pEntry; - if( elem->prev ){ - elem->prev->next = elem->next; + sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + fts3DecodeIntArray(nStat, a, + sqlite3_column_blob(pStmt, 0), + sqlite3_column_bytes(pStmt, 0)); }else{ - pH->first = elem->next; - } - if( elem->next ){ - elem->next->prev = elem->prev; + memset(a, 0, sizeof(u32)*(nStat) ); } - pEntry = &pH->ht[h]; - if( pEntry->chain==elem ){ - pEntry->chain = elem->next; + rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ){ + sqlite3_free(a); + *pRC = rc; + return; } - pEntry->count--; - if( pEntry->count<=0 ){ - pEntry->chain = 0; + if( nChng<0 && a[0]<(u32)(-nChng) ){ + a[0] = 0; + }else{ + a[0] += nChng; } - if( pH->copyKey && elem->pKey ){ - fts3HashFree(elem->pKey); + for(i=0; inColumn+1; i++){ + u32 x = a[i+1]; + if( x+aSzIns[i] < aSzDel[i] ){ + x = 0; + }else{ + x = x + aSzIns[i] - aSzDel[i]; + } + a[i+1] = x; } - fts3HashFree( elem ); - pH->count--; - if( pH->count<=0 ){ - assert( pH->first==0 ); - assert( pH->count==0 ); - fts3HashClear(pH); + fts3EncodeIntArray(nStat, a, pBlob, &nBlob); + rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); + if( rc ){ + sqlite3_free(a); + *pRC = rc; + return; } + sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); + sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC); + sqlite3_step(pStmt); + *pRC = sqlite3_reset(pStmt); + sqlite3_bind_null(pStmt, 2); + sqlite3_free(a); } -SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem( - const Fts3Hash *pH, - const void *pKey, - int nKey -){ - int h; /* A hash on key */ - int (*xHash)(const void*,int); /* The hash function */ - - if( pH==0 || pH->ht==0 ) return 0; - xHash = ftsHashFunction(pH->keyClass); - assert( xHash!=0 ); - h = (*xHash)(pKey,nKey); - assert( (pH->htsize & (pH->htsize-1))==0 ); - return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1)); -} - -/* -** Attempt to locate an element of the hash table pH with a key -** that matches pKey,nKey. Return the data for this element if it is -** found, or NULL if there is no match. -*/ -SQLITE_PRIVATE void *sqlite3Fts3HashFind(const Fts3Hash *pH, const void *pKey, int nKey){ - Fts3HashElem *pElem; /* The element that matches key (if any) */ - - pElem = sqlite3Fts3HashFindElem(pH, pKey, nKey); - return pElem ? pElem->data : 0; -} - -/* Insert an element into the hash table pH. The key is pKey,nKey -** and the data is "data". -** -** If no element exists with a matching key, then a new -** element is created. A copy of the key is made if the copyKey -** flag is set. NULL is returned. -** -** If another element already exists with the same key, then the -** new data replaces the old data and the old data is returned. -** The key is not copied in this instance. If a malloc fails, then -** the new data is returned and the hash table is unchanged. -** -** If the "data" parameter to this function is NULL, then the -** element corresponding to "key" is removed from the hash table. +/* +** Merge the entire database so that there is one segment for each +** iIndex/iLangid combination. */ -SQLITE_PRIVATE void *sqlite3Fts3HashInsert( - Fts3Hash *pH, /* The hash table to insert into */ - const void *pKey, /* The key */ - int nKey, /* Number of bytes in the key */ - void *data /* The data */ -){ - int hraw; /* Raw hash value of the key */ - int h; /* the hash of the key modulo hash table size */ - Fts3HashElem *elem; /* Used to loop thru the element list */ - Fts3HashElem *new_elem; /* New element added to the pH */ - int (*xHash)(const void*,int); /* The hash function */ +static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ + int bSeenDone = 0; + int rc; + sqlite3_stmt *pAllLangid = 0; - assert( pH!=0 ); - xHash = ftsHashFunction(pH->keyClass); - assert( xHash!=0 ); - hraw = (*xHash)(pKey, nKey); - assert( (pH->htsize & (pH->htsize-1))==0 ); - h = hraw & (pH->htsize-1); - elem = fts3FindElementByHash(pH,pKey,nKey,h); - if( elem ){ - void *old_data = elem->data; - if( data==0 ){ - fts3RemoveElementByHash(pH,elem,h); - }else{ - elem->data = data; - } - return old_data; - } - if( data==0 ) return 0; - if( (pH->htsize==0 && fts3Rehash(pH,8)) - || (pH->count>=pH->htsize && fts3Rehash(pH, pH->htsize*2)) - ){ - pH->count = 0; - return data; + rc = sqlite3Fts3PendingTermsFlush(p); + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); } - assert( pH->htsize>0 ); - new_elem = (Fts3HashElem*)fts3HashMalloc( sizeof(Fts3HashElem) ); - if( new_elem==0 ) return data; - if( pH->copyKey && pKey!=0 ){ - new_elem->pKey = fts3HashMalloc( nKey ); - if( new_elem->pKey==0 ){ - fts3HashFree(new_elem); - return data; + if( rc==SQLITE_OK ){ + int rc2; + sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); + sqlite3_bind_int(pAllLangid, 2, p->nIndex); + while( sqlite3_step(pAllLangid)==SQLITE_ROW ){ + int i; + int iLangid = sqlite3_column_int(pAllLangid, 0); + for(i=0; rc==SQLITE_OK && inIndex; i++){ + rc = fts3SegmentMerge(p, iLangid, i, FTS3_SEGCURSOR_ALL); + if( rc==SQLITE_DONE ){ + bSeenDone = 1; + rc = SQLITE_OK; + } + } } - memcpy((void*)new_elem->pKey, pKey, nKey); - }else{ - new_elem->pKey = (void*)pKey; + rc2 = sqlite3_reset(pAllLangid); + if( rc==SQLITE_OK ) rc = rc2; } - new_elem->nKey = nKey; - pH->count++; - assert( pH->htsize>0 ); - assert( (pH->htsize & (pH->htsize-1))==0 ); - h = hraw & (pH->htsize-1); - fts3HashInsertElement(pH, &pH->ht[h], new_elem); - new_elem->data = data; - return 0; -} -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + sqlite3Fts3SegmentsClose(p); -/************** End of fts3_hash.c *******************************************/ -/************** Begin file fts3_porter.c *************************************/ -/* -** 2006 September 30 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** Implementation of the full-text-search tokenizer that implements -** a Porter stemmer. -*/ + return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; +} /* -** The code in this file is only compiled if: +** This function is called when the user executes the following statement: ** -** * The FTS3 module is being built as an extension -** (in which case SQLITE_CORE is not defined), or +** INSERT INTO () VALUES('rebuild'); ** -** * The FTS3 module is being built into the core of -** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +** The entire FTS index is discarded and rebuilt. If the table is one +** created using the content=xxx option, then the new index is based on +** the current contents of the xxx table. Otherwise, it is rebuilt based +** on the contents of the %_content table. */ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -/* #include */ -/* #include */ -/* #include */ -/* #include */ - -/* #include "fts3_tokenizer.h" */ +static int fts3DoRebuild(Fts3Table *p){ + int rc; /* Return Code */ -/* -** Class derived from sqlite3_tokenizer -*/ -typedef struct porter_tokenizer { - sqlite3_tokenizer base; /* Base class */ -} porter_tokenizer; + rc = fts3DeleteAll(p, 0); + if( rc==SQLITE_OK ){ + u32 *aSz = 0; + u32 *aSzIns = 0; + u32 *aSzDel = 0; + sqlite3_stmt *pStmt = 0; + int nEntry = 0; -/* -** Class derived from sqlite3_tokenizer_cursor -*/ -typedef struct porter_tokenizer_cursor { - sqlite3_tokenizer_cursor base; - const char *zInput; /* input we are tokenizing */ - int nInput; /* size of the input */ - int iOffset; /* current position in zInput */ - int iToken; /* index of next token to be returned */ - char *zToken; /* storage for current token */ - int nAllocated; /* space allocated to zToken buffer */ -} porter_tokenizer_cursor; + /* Compose and prepare an SQL statement to loop through the content table */ + char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } + if( rc==SQLITE_OK ){ + sqlite3_int64 nByte = sizeof(u32) * ((sqlite3_int64)p->nColumn+1)*3; + aSz = (u32 *)sqlite3_malloc64(nByte); + if( aSz==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(aSz, 0, nByte); + aSzIns = &aSz[p->nColumn+1]; + aSzDel = &aSzIns[p->nColumn+1]; + } + } -/* -** Create a new tokenizer instance. -*/ -static int porterCreate( - int argc, const char * const *argv, - sqlite3_tokenizer **ppTokenizer -){ - porter_tokenizer *t; + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + int iCol; + int iLangid = langidFromSelect(p, pStmt); + rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0)); + memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); + for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ + if( p->abNotindexed[iCol]==0 ){ + const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); + rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); + aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); + } + } + if( p->bHasDocsize ){ + fts3InsertDocsize(&rc, p, aSz); + } + if( rc!=SQLITE_OK ){ + sqlite3_finalize(pStmt); + pStmt = 0; + }else{ + nEntry++; + for(iCol=0; iCol<=p->nColumn; iCol++){ + aSzIns[iCol] += aSz[iCol]; + } + } + } + if( p->bFts4 ){ + fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry); + } + sqlite3_free(aSz); - UNUSED_PARAMETER(argc); - UNUSED_PARAMETER(argv); + if( pStmt ){ + int rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } - t = (porter_tokenizer *) sqlite3_malloc(sizeof(*t)); - if( t==NULL ) return SQLITE_NOMEM; - memset(t, 0, sizeof(*t)); - *ppTokenizer = &t->base; - return SQLITE_OK; + return rc; } -/* -** Destroy a tokenizer -*/ -static int porterDestroy(sqlite3_tokenizer *pTokenizer){ - sqlite3_free(pTokenizer); - return SQLITE_OK; -} -/* -** Prepare to begin tokenizing a particular string. The input -** string to be tokenized is zInput[0..nInput-1]. A cursor -** used to incrementally tokenize this string is returned in -** *ppCursor. +/* +** This function opens a cursor used to read the input data for an +** incremental merge operation. Specifically, it opens a cursor to scan +** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute +** level iAbsLevel. */ -static int porterOpen( - sqlite3_tokenizer *pTokenizer, /* The tokenizer */ - const char *zInput, int nInput, /* String to be tokenized */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +static int fts3IncrmergeCsr( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level to open */ + int nSeg, /* Number of segments to merge */ + Fts3MultiSegReader *pCsr /* Cursor object to populate */ ){ - porter_tokenizer_cursor *c; - - UNUSED_PARAMETER(pTokenizer); + int rc; /* Return Code */ + sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ + sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */ - c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); - if( c==NULL ) return SQLITE_NOMEM; + /* Allocate space for the Fts3MultiSegReader.aCsr[] array */ + memset(pCsr, 0, sizeof(*pCsr)); + nByte = sizeof(Fts3SegReader *) * nSeg; + pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc64(nByte); - c->zInput = zInput; - if( zInput==0 ){ - c->nInput = 0; - }else if( nInput<0 ){ - c->nInput = (int)strlen(zInput); + if( pCsr->apSegment==0 ){ + rc = SQLITE_NOMEM; }else{ - c->nInput = nInput; + memset(pCsr->apSegment, 0, nByte); + rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); + } + if( rc==SQLITE_OK ){ + int i; + int rc2; + sqlite3_bind_int64(pStmt, 1, iAbsLevel); + assert( pCsr->nSegment==0 ); + for(i=0; rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW && iapSegment[i] + ); + pCsr->nSegment++; + } + rc2 = sqlite3_reset(pStmt); + if( rc==SQLITE_OK ) rc = rc2; } - c->iOffset = 0; /* start tokenizing at the beginning */ - c->iToken = 0; - c->zToken = NULL; /* no space allocated, yet. */ - c->nAllocated = 0; - *ppCursor = &c->base; - return SQLITE_OK; + return rc; } +typedef struct IncrmergeWriter IncrmergeWriter; +typedef struct NodeWriter NodeWriter; +typedef struct Blob Blob; +typedef struct NodeReader NodeReader; + /* -** Close a tokenization cursor previously opened by a call to -** porterOpen() above. +** An instance of the following structure is used as a dynamic buffer +** to build up nodes or other blobs of data in. +** +** The function blobGrowBuffer() is used to extend the allocation. */ -static int porterClose(sqlite3_tokenizer_cursor *pCursor){ - porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; - sqlite3_free(c->zToken); - sqlite3_free(c); - return SQLITE_OK; -} +struct Blob { + char *a; /* Pointer to allocation */ + int n; /* Number of valid bytes of data in a[] */ + int nAlloc; /* Allocated size of a[] (nAlloc>=n) */ +}; + /* -** Vowel or consonant +** This structure is used to build up buffers containing segment b-tree +** nodes (blocks). */ -static const char cType[] = { - 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, - 1, 1, 1, 2, 1 +struct NodeWriter { + sqlite3_int64 iBlock; /* Current block id */ + Blob key; /* Last key written to the current block */ + Blob block; /* Current block image */ }; /* -** isConsonant() and isVowel() determine if their first character in -** the string they point to is a consonant or a vowel, according -** to Porter ruls. -** -** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'. -** 'Y' is a consonant unless it follows another consonant, -** in which case it is a vowel. -** -** In these routine, the letters are in reverse order. So the 'y' rule -** is that 'y' is a consonant unless it is followed by another -** consonent. +** An object of this type contains the state required to create or append +** to an appendable b-tree segment. */ -static int isVowel(const char*); -static int isConsonant(const char *z){ - int j; - char x = *z; - if( x==0 ) return 0; - assert( x>='a' && x<='z' ); - j = cType[x-'a']; - if( j<2 ) return j; - return z[1]==0 || isVowel(z + 1); -} -static int isVowel(const char *z){ - int j; - char x = *z; - if( x==0 ) return 0; - assert( x>='a' && x<='z' ); - j = cType[x-'a']; - if( j<2 ) return 1-j; - return isConsonant(z + 1); -} +struct IncrmergeWriter { + int nLeafEst; /* Space allocated for leaf blocks */ + int nWork; /* Number of leaf pages flushed */ + sqlite3_int64 iAbsLevel; /* Absolute level of input segments */ + int iIdx; /* Index of *output* segment in iAbsLevel+1 */ + sqlite3_int64 iStart; /* Block number of first allocated block */ + sqlite3_int64 iEnd; /* Block number of last allocated block */ + sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */ + u8 bNoLeafData; /* If true, store 0 for segment size */ + NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT]; +}; /* -** Let any sequence of one or more vowels be represented by V and let -** C be sequence of one or more consonants. Then every word can be -** represented as: -** -** [C] (VC){m} [V] -** -** In prose: A word is an optional consonant followed by zero or -** vowel-consonant pairs followed by an optional vowel. "m" is the -** number of vowel consonant pairs. This routine computes the value -** of m for the first i bytes of a word. -** -** Return true if the m-value for z is 1 or more. In other words, -** return true if z contains at least one vowel that is followed -** by a consonant. +** An object of the following type is used to read data from a single +** FTS segment node. See the following functions: ** -** In this routine z[] is in reverse order. So we are really looking -** for an instance of a consonant followed by a vowel. +** nodeReaderInit() +** nodeReaderNext() +** nodeReaderRelease() */ -static int m_gt_0(const char *z){ - while( isVowel(z) ){ z++; } - if( *z==0 ) return 0; - while( isConsonant(z) ){ z++; } - return *z!=0; -} +struct NodeReader { + const char *aNode; + int nNode; + int iOff; /* Current offset within aNode[] */ -/* Like mgt0 above except we are looking for a value of m which is -** exactly 1 + /* Output variables. Containing the current node entry. */ + sqlite3_int64 iChild; /* Pointer to child node */ + Blob term; /* Current term */ + const char *aDoclist; /* Pointer to doclist */ + int nDoclist; /* Size of doclist in bytes */ +}; + +/* +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, if the allocation at pBlob->a is not already at least nMin +** bytes in size, extend (realloc) it to be so. +** +** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a +** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc +** to reflect the new size of the pBlob->a[] buffer. */ -static int m_eq_1(const char *z){ - while( isVowel(z) ){ z++; } - if( *z==0 ) return 0; - while( isConsonant(z) ){ z++; } - if( *z==0 ) return 0; - while( isVowel(z) ){ z++; } - if( *z==0 ) return 1; - while( isConsonant(z) ){ z++; } - return *z==0; +static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ + if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ + int nAlloc = nMin; + char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); + if( a ){ + pBlob->nAlloc = nAlloc; + pBlob->a = a; + }else{ + *pRc = SQLITE_NOMEM; + } + } } -/* Like mgt0 above except we are looking for a value of m>1 instead -** or m>0 +/* +** Attempt to advance the node-reader object passed as the first argument to +** the next entry on the node. +** +** Return an error code if an error occurs (SQLITE_NOMEM is possible). +** Otherwise return SQLITE_OK. If there is no next entry on the node +** (e.g. because the current entry is the last) set NodeReader->aNode to +** NULL to indicate EOF. Otherwise, populate the NodeReader structure output +** variables for the new entry. */ -static int m_gt_1(const char *z){ - while( isVowel(z) ){ z++; } - if( *z==0 ) return 0; - while( isConsonant(z) ){ z++; } - if( *z==0 ) return 0; - while( isVowel(z) ){ z++; } - if( *z==0 ) return 0; - while( isConsonant(z) ){ z++; } - return *z!=0; +static int nodeReaderNext(NodeReader *p){ + int bFirst = (p->term.n==0); /* True for first term on the node */ + int nPrefix = 0; /* Bytes to copy from previous term */ + int nSuffix = 0; /* Bytes to append to the prefix */ + int rc = SQLITE_OK; /* Return code */ + + assert( p->aNode ); + if( p->iChild && bFirst==0 ) p->iChild++; + if( p->iOff>=p->nNode ){ + /* EOF */ + p->aNode = 0; + }else{ + if( bFirst==0 ){ + p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nPrefix); + } + p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); + + if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){ + return FTS_CORRUPT_VTAB; + } + blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); + if( rc==SQLITE_OK && ALWAYS(p->term.a!=0) ){ + memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); + p->term.n = nPrefix+nSuffix; + p->iOff += nSuffix; + if( p->iChild==0 ){ + p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist); + if( (p->nNode-p->iOff)nDoclist ){ + return FTS_CORRUPT_VTAB; + } + p->aDoclist = &p->aNode[p->iOff]; + p->iOff += p->nDoclist; + } + } + } + + assert_fts3_nc( p->iOff<=p->nNode ); + return rc; } /* -** Return TRUE if there is a vowel anywhere within z[0..n-1] +** Release all dynamic resources held by node-reader object *p. */ -static int hasVowel(const char *z){ - while( isConsonant(z) ){ z++; } - return *z!=0; +static void nodeReaderRelease(NodeReader *p){ + sqlite3_free(p->term.a); } /* -** Return TRUE if the word ends in a double consonant. +** Initialize a node-reader object to read the node in buffer aNode/nNode. ** -** The text is reversed here. So we are really looking at -** the first two characters of z[]. +** If successful, SQLITE_OK is returned and the NodeReader object set to +** point to the first entry on the node (if any). Otherwise, an SQLite +** error code is returned. */ -static int doubleConsonant(const char *z){ - return isConsonant(z) && z[0]==z[1]; +static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){ + memset(p, 0, sizeof(NodeReader)); + p->aNode = aNode; + p->nNode = nNode; + + /* Figure out if this is a leaf or an internal node. */ + if( aNode && aNode[0] ){ + /* An internal node. */ + p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild); + }else{ + p->iOff = 1; + } + + return aNode ? nodeReaderNext(p) : SQLITE_OK; } /* -** Return TRUE if the word ends with three letters which -** are consonant-vowel-consonent and where the final consonant -** is not 'w', 'x', or 'y'. +** This function is called while writing an FTS segment each time a leaf o +** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed +** to be greater than the largest key on the node just written, but smaller +** than or equal to the first key that will be written to the next leaf +** node. ** -** The word is reversed here. So we are really checking the -** first three letters and the first one cannot be in [wxy]. +** The block id of the leaf node just written to disk may be found in +** (pWriter->aNodeWriter[0].iBlock) when this function is called. */ -static int star_oh(const char *z){ - return - isConsonant(z) && - z[0]!='w' && z[0]!='x' && z[0]!='y' && - isVowel(z+1) && - isConsonant(z+2); +static int fts3IncrmergePush( + Fts3Table *p, /* Fts3 table handle */ + IncrmergeWriter *pWriter, /* Writer object */ + const char *zTerm, /* Term to write to internal node */ + int nTerm /* Bytes at zTerm */ +){ + sqlite3_int64 iPtr = pWriter->aNodeWriter[0].iBlock; + int iLayer; + + assert( nTerm>0 ); + for(iLayer=1; ALWAYS(iLayeraNodeWriter[iLayer]; + int rc = SQLITE_OK; + int nPrefix; + int nSuffix; + int nSpace; + + /* Figure out how much space the key will consume if it is written to + ** the current node of layer iLayer. Due to the prefix compression, + ** the space required changes depending on which node the key is to + ** be added to. */ + nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm); + nSuffix = nTerm - nPrefix; + if(nSuffix<=0 ) return FTS_CORRUPT_VTAB; + nSpace = sqlite3Fts3VarintLen(nPrefix); + nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; + + if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){ + /* If the current node of layer iLayer contains zero keys, or if adding + ** the key to it will not cause it to grow to larger than nNodeSize + ** bytes in size, write the key here. */ + + Blob *pBlk = &pNode->block; + if( pBlk->n==0 ){ + blobGrowBuffer(pBlk, p->nNodeSize, &rc); + if( rc==SQLITE_OK ){ + pBlk->a[0] = (char)iLayer; + pBlk->n = 1 + sqlite3Fts3PutVarint(&pBlk->a[1], iPtr); + } + } + blobGrowBuffer(pBlk, pBlk->n + nSpace, &rc); + blobGrowBuffer(&pNode->key, nTerm, &rc); + + if( rc==SQLITE_OK ){ + if( pNode->key.n ){ + pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix); + } + pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix); + memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix); + pBlk->n += nSuffix; + + memcpy(pNode->key.a, zTerm, nTerm); + pNode->key.n = nTerm; + } + }else{ + /* Otherwise, flush the current node of layer iLayer to disk. + ** Then allocate a new, empty sibling node. The key will be written + ** into the parent of this node. */ + rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); + + assert( pNode->block.nAlloc>=p->nNodeSize ); + pNode->block.a[0] = (char)iLayer; + pNode->block.n = 1 + sqlite3Fts3PutVarint(&pNode->block.a[1], iPtr+1); + + iNextPtr = pNode->iBlock; + pNode->iBlock++; + pNode->key.n = 0; + } + + if( rc!=SQLITE_OK || iNextPtr==0 ) return rc; + iPtr = iNextPtr; + } + + assert( 0 ); + return 0; } /* -** If the word ends with zFrom and xCond() is true for the stem -** of the word that preceeds the zFrom ending, then change the -** ending to zTo. +** Append a term and (optionally) doclist to the FTS segment node currently +** stored in blob *pNode. The node need not contain any terms, but the +** header must be written before this function is called. ** -** The input word *pz and zFrom are both in reverse order. zTo -** is in normal order. +** A node header is a single 0x00 byte for a leaf node, or a height varint +** followed by the left-hand-child varint for an internal node. ** -** Return TRUE if zFrom matches. Return FALSE if zFrom does not -** match. Not that TRUE is returned even if xCond() fails and -** no substitution occurs. +** The term to be appended is passed via arguments zTerm/nTerm. For a +** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal +** node, both aDoclist and nDoclist must be passed 0. +** +** If the size of the value in blob pPrev is zero, then this is the first +** term written to the node. Otherwise, pPrev contains a copy of the +** previous term. Before this function returns, it is updated to contain a +** copy of zTerm/nTerm. +** +** It is assumed that the buffer associated with pNode is already large +** enough to accommodate the new entry. The buffer associated with pPrev +** is extended by this function if requrired. +** +** If an error (i.e. OOM condition) occurs, an SQLite error code is +** returned. Otherwise, SQLITE_OK. */ -static int stem( - char **pz, /* The word being stemmed (Reversed) */ - const char *zFrom, /* If the ending matches this... (Reversed) */ - const char *zTo, /* ... change the ending to this (not reversed) */ - int (*xCond)(const char*) /* Condition that must be true */ +static int fts3AppendToNode( + Blob *pNode, /* Current node image to append to */ + Blob *pPrev, /* Buffer containing previous term written */ + const char *zTerm, /* New term to write */ + int nTerm, /* Size of zTerm in bytes */ + const char *aDoclist, /* Doclist (or NULL) to write */ + int nDoclist /* Size of aDoclist in bytes */ ){ - char *z = *pz; - while( *zFrom && *zFrom==*z ){ z++; zFrom++; } - if( *zFrom!=0 ) return 0; - if( xCond && !xCond(z) ) return 1; - while( *zTo ){ - *(--z) = *(zTo++); + int rc = SQLITE_OK; /* Return code */ + int bFirst = (pPrev->n==0); /* True if this is the first term written */ + int nPrefix; /* Size of term prefix in bytes */ + int nSuffix; /* Size of term suffix in bytes */ + + /* Node must have already been started. There must be a doclist for a + ** leaf node, and there must not be a doclist for an internal node. */ + assert( pNode->n>0 ); + assert_fts3_nc( (pNode->a[0]=='\0')==(aDoclist!=0) ); + + blobGrowBuffer(pPrev, nTerm, &rc); + if( rc!=SQLITE_OK ) return rc; + + nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm); + nSuffix = nTerm - nPrefix; + if( nSuffix<=0 ) return FTS_CORRUPT_VTAB; + memcpy(pPrev->a, zTerm, nTerm); + pPrev->n = nTerm; + + if( bFirst==0 ){ + pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nPrefix); } - *pz = z; - return 1; + pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nSuffix); + memcpy(&pNode->a[pNode->n], &zTerm[nPrefix], nSuffix); + pNode->n += nSuffix; + + if( aDoclist ){ + pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nDoclist); + memcpy(&pNode->a[pNode->n], aDoclist, nDoclist); + pNode->n += nDoclist; + } + + assert( pNode->n<=pNode->nAlloc ); + + return SQLITE_OK; } /* -** This is the fallback stemmer used when the porter stemmer is -** inappropriate. The input word is copied into the output with -** US-ASCII case folding. If the input word is too long (more -** than 20 bytes if it contains no digits or more than 6 bytes if -** it contains digits) then word is truncated to 20 or 6 bytes -** by taking 10 or 3 bytes from the beginning and end. +** Append the current term and doclist pointed to by cursor pCsr to the +** appendable b-tree segment opened for writing by pWriter. +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. */ -static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ - int i, mx, j; - int hasDigit = 0; - for(i=0; i='A' && c<='Z' ){ - zOut[i] = c - 'A' + 'a'; - }else{ - if( c>='0' && c<='9' ) hasDigit = 1; - zOut[i] = c; +static int fts3IncrmergeAppend( + Fts3Table *p, /* Fts3 table handle */ + IncrmergeWriter *pWriter, /* Writer object */ + Fts3MultiSegReader *pCsr /* Cursor containing term and doclist */ +){ + const char *zTerm = pCsr->zTerm; + int nTerm = pCsr->nTerm; + const char *aDoclist = pCsr->aDoclist; + int nDoclist = pCsr->nDoclist; + int rc = SQLITE_OK; /* Return code */ + int nSpace; /* Total space in bytes required on leaf */ + int nPrefix; /* Size of prefix shared with previous term */ + int nSuffix; /* Size of suffix (nTerm - nPrefix) */ + NodeWriter *pLeaf; /* Object used to write leaf nodes */ + + pLeaf = &pWriter->aNodeWriter[0]; + nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm); + nSuffix = nTerm - nPrefix; + + nSpace = sqlite3Fts3VarintLen(nPrefix); + nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; + nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; + + /* If the current block is not empty, and if adding this term/doclist + ** to the current block would make it larger than Fts3Table.nNodeSize + ** bytes, write this block out to the database. */ + if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){ + rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n); + pWriter->nWork++; + + /* Add the current term to the parent node. The term added to the + ** parent must: + ** + ** a) be greater than the largest term on the leaf node just written + ** to the database (still available in pLeaf->key), and + ** + ** b) be less than or equal to the term about to be added to the new + ** leaf node (zTerm/nTerm). + ** + ** In other words, it must be the prefix of zTerm 1 byte longer than + ** the common prefix (if any) of zTerm and pWriter->zTerm. + */ + if( rc==SQLITE_OK ){ + rc = fts3IncrmergePush(p, pWriter, zTerm, nPrefix+1); } + + /* Advance to the next output block */ + pLeaf->iBlock++; + pLeaf->key.n = 0; + pLeaf->block.n = 0; + + nSuffix = nTerm; + nSpace = 1; + nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; + nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; } - mx = hasDigit ? 3 : 10; - if( nIn>mx*2 ){ - for(j=mx, i=nIn-mx; inLeafData += nSpace; + blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc); + if( rc==SQLITE_OK ){ + if( pLeaf->block.n==0 ){ + pLeaf->block.n = 1; + pLeaf->block.a[0] = '\0'; } - i = j; + rc = fts3AppendToNode( + &pLeaf->block, &pLeaf->key, zTerm, nTerm, aDoclist, nDoclist + ); } - zOut[i] = 0; - *pnOut = i; -} + return rc; +} /* -** Stem the input word zIn[0..nIn-1]. Store the output in zOut. -** zOut is at least big enough to hold nIn bytes. Write the actual -** size of the output word (exclusive of the '\0' terminator) into *pnOut. -** -** Any upper-case characters in the US-ASCII character set ([A-Z]) -** are converted to lower case. Upper-case UTF characters are -** unchanged. +** This function is called to release all dynamic resources held by the +** merge-writer object pWriter, and if no error has occurred, to flush +** all outstanding node buffers held by pWriter to disk. ** -** Words that are longer than about 20 bytes are stemmed by retaining -** a few bytes from the beginning and the end of the word. If the -** word contains digits, 3 bytes are taken from the beginning and -** 3 bytes from the end. For long words without digits, 10 bytes -** are taken from each end. US-ASCII case folding still applies. -** -** If the input word contains not digits but does characters not -** in [a-zA-Z] then no stemming is attempted and this routine just -** copies the input into the input into the output with US-ASCII -** case folding. +** If *pRc is not SQLITE_OK when this function is called, then no attempt +** is made to write any data to disk. Instead, this function serves only +** to release outstanding resources. ** -** Stemming never increases the length of the word. So there is -** no chance of overflowing the zOut buffer. +** Otherwise, if *pRc is initially SQLITE_OK and an error occurs while +** flushing buffers to disk, *pRc is set to an SQLite error code before +** returning. */ -static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ - int i, j; - char zReverse[28]; - char *z, *z2; - if( nIn<3 || nIn>=(int)sizeof(zReverse)-7 ){ - /* The word is too big or too small for the porter stemmer. - ** Fallback to the copy stemmer */ - copy_stemmer(zIn, nIn, zOut, pnOut); - return; - } - for(i=0, j=sizeof(zReverse)-6; i='A' && c<='Z' ){ - zReverse[j] = c + 'a' - 'A'; - }else if( c>='a' && c<='z' ){ - zReverse[j] = c; - }else{ - /* The use of a character not in [a-zA-Z] means that we fallback - ** to the copy stemmer */ - copy_stemmer(zIn, nIn, zOut, pnOut); - return; - } - } - memset(&zReverse[sizeof(zReverse)-5], 0, 5); - z = &zReverse[j+1]; - +static void fts3IncrmergeRelease( + Fts3Table *p, /* FTS3 table handle */ + IncrmergeWriter *pWriter, /* Merge-writer object */ + int *pRc /* IN/OUT: Error code */ +){ + int i; /* Used to iterate through non-root layers */ + int iRoot; /* Index of root in pWriter->aNodeWriter */ + NodeWriter *pRoot; /* NodeWriter for root node */ + int rc = *pRc; /* Error code */ - /* Step 1a */ - if( z[0]=='s' ){ - if( - !stem(&z, "sess", "ss", 0) && - !stem(&z, "sei", "i", 0) && - !stem(&z, "ss", "ss", 0) - ){ - z++; - } + /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment + ** root node. If the segment fits entirely on a single leaf node, iRoot + ** will be set to 0. If the root node is the parent of the leaves, iRoot + ** will be 1. And so on. */ + for(iRoot=FTS_MAX_APPENDABLE_HEIGHT-1; iRoot>=0; iRoot--){ + NodeWriter *pNode = &pWriter->aNodeWriter[iRoot]; + if( pNode->block.n>0 ) break; + assert( *pRc || pNode->block.nAlloc==0 ); + assert( *pRc || pNode->key.nAlloc==0 ); + sqlite3_free(pNode->block.a); + sqlite3_free(pNode->key.a); } - /* Step 1b */ - z2 = z; - if( stem(&z, "dee", "ee", m_gt_0) ){ - /* Do nothing. The work was all in the test */ - }else if( - (stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel)) - && z!=z2 - ){ - if( stem(&z, "ta", "ate", 0) || - stem(&z, "lb", "ble", 0) || - stem(&z, "zi", "ize", 0) ){ - /* Do nothing. The work was all in the test */ - }else if( doubleConsonant(z) && (*z!='l' && *z!='s' && *z!='z') ){ - z++; - }else if( m_eq_1(z) && star_oh(z) ){ - *(--z) = 'e'; - } - } + /* Empty output segment. This is a no-op. */ + if( iRoot<0 ) return; - /* Step 1c */ - if( z[0]=='y' && hasVowel(z+1) ){ - z[0] = 'i'; + /* The entire output segment fits on a single node. Normally, this means + ** the node would be stored as a blob in the "root" column of the %_segdir + ** table. However, this is not permitted in this case. The problem is that + ** space has already been reserved in the %_segments table, and so the + ** start_block and end_block fields of the %_segdir table must be populated. + ** And, by design or by accident, released versions of FTS cannot handle + ** segments that fit entirely on the root node with start_block!=0. + ** + ** Instead, create a synthetic root node that contains nothing but a + ** pointer to the single content node. So that the segment consists of a + ** single leaf and a single interior (root) node. + ** + ** Todo: Better might be to defer allocating space in the %_segments + ** table until we are sure it is needed. + */ + if( iRoot==0 ){ + Blob *pBlock = &pWriter->aNodeWriter[1].block; + blobGrowBuffer(pBlock, 1 + FTS3_VARINT_MAX, &rc); + if( rc==SQLITE_OK ){ + pBlock->a[0] = 0x01; + pBlock->n = 1 + sqlite3Fts3PutVarint( + &pBlock->a[1], pWriter->aNodeWriter[0].iBlock + ); + } + iRoot = 1; } + pRoot = &pWriter->aNodeWriter[iRoot]; - /* Step 2 */ - switch( z[1] ){ - case 'a': - if( !stem(&z, "lanoita", "ate", m_gt_0) ){ - stem(&z, "lanoit", "tion", m_gt_0); - } - break; - case 'c': - if( !stem(&z, "icne", "ence", m_gt_0) ){ - stem(&z, "icna", "ance", m_gt_0); - } - break; - case 'e': - stem(&z, "rezi", "ize", m_gt_0); - break; - case 'g': - stem(&z, "igol", "log", m_gt_0); - break; - case 'l': - if( !stem(&z, "ilb", "ble", m_gt_0) - && !stem(&z, "illa", "al", m_gt_0) - && !stem(&z, "iltne", "ent", m_gt_0) - && !stem(&z, "ile", "e", m_gt_0) - ){ - stem(&z, "ilsuo", "ous", m_gt_0); - } - break; - case 'o': - if( !stem(&z, "noitazi", "ize", m_gt_0) - && !stem(&z, "noita", "ate", m_gt_0) - ){ - stem(&z, "rota", "ate", m_gt_0); - } - break; - case 's': - if( !stem(&z, "msila", "al", m_gt_0) - && !stem(&z, "ssenevi", "ive", m_gt_0) - && !stem(&z, "ssenluf", "ful", m_gt_0) - ){ - stem(&z, "ssensuo", "ous", m_gt_0); - } - break; - case 't': - if( !stem(&z, "itila", "al", m_gt_0) - && !stem(&z, "itivi", "ive", m_gt_0) - ){ - stem(&z, "itilib", "ble", m_gt_0); - } - break; + /* Flush all currently outstanding nodes to disk. */ + for(i=0; iaNodeWriter[i]; + if( pNode->block.n>0 && rc==SQLITE_OK ){ + rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); + } + sqlite3_free(pNode->block.a); + sqlite3_free(pNode->key.a); } - /* Step 3 */ - switch( z[0] ){ - case 'e': - if( !stem(&z, "etaci", "ic", m_gt_0) - && !stem(&z, "evita", "", m_gt_0) - ){ - stem(&z, "ezila", "al", m_gt_0); - } - break; - case 'i': - stem(&z, "itici", "ic", m_gt_0); - break; - case 'l': - if( !stem(&z, "laci", "ic", m_gt_0) ){ - stem(&z, "luf", "", m_gt_0); - } - break; - case 's': - stem(&z, "ssen", "", m_gt_0); - break; + /* Write the %_segdir record. */ + if( rc==SQLITE_OK ){ + rc = fts3WriteSegdir(p, + pWriter->iAbsLevel+1, /* level */ + pWriter->iIdx, /* idx */ + pWriter->iStart, /* start_block */ + pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */ + pWriter->iEnd, /* end_block */ + (pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */ + pRoot->block.a, pRoot->block.n /* root */ + ); } + sqlite3_free(pRoot->block.a); + sqlite3_free(pRoot->key.a); - /* Step 4 */ - switch( z[1] ){ - case 'a': - if( z[0]=='l' && m_gt_1(z+2) ){ - z += 2; - } - break; - case 'c': - if( z[0]=='e' && z[2]=='n' && (z[3]=='a' || z[3]=='e') && m_gt_1(z+4) ){ - z += 4; - } - break; - case 'e': - if( z[0]=='r' && m_gt_1(z+2) ){ - z += 2; - } - break; - case 'i': - if( z[0]=='c' && m_gt_1(z+2) ){ - z += 2; - } - break; - case 'l': - if( z[0]=='e' && z[2]=='b' && (z[3]=='a' || z[3]=='i') && m_gt_1(z+4) ){ - z += 4; - } - break; - case 'n': - if( z[0]=='t' ){ - if( z[2]=='a' ){ - if( m_gt_1(z+3) ){ - z += 3; - } - }else if( z[2]=='e' ){ - if( !stem(&z, "tneme", "", m_gt_1) - && !stem(&z, "tnem", "", m_gt_1) - ){ - stem(&z, "tne", "", m_gt_1); - } - } - } - break; - case 'o': - if( z[0]=='u' ){ - if( m_gt_1(z+2) ){ - z += 2; - } - }else if( z[3]=='s' || z[3]=='t' ){ - stem(&z, "noi", "", m_gt_1); - } - break; - case 's': - if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){ - z += 3; - } - break; - case 't': - if( !stem(&z, "eta", "", m_gt_1) ){ - stem(&z, "iti", "", m_gt_1); - } - break; - case 'u': - if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){ - z += 3; - } - break; - case 'v': - case 'z': - if( z[0]=='e' && z[2]=='i' && m_gt_1(z+3) ){ - z += 3; - } - break; - } + *pRc = rc; +} - /* Step 5a */ - if( z[0]=='e' ){ - if( m_gt_1(z+1) ){ - z++; - }else if( m_eq_1(z+1) && !star_oh(z+1) ){ - z++; - } - } +/* +** Compare the term in buffer zLhs (size in bytes nLhs) with that in +** zRhs (size in bytes nRhs) using memcmp. If one term is a prefix of +** the other, it is considered to be smaller than the other. +** +** Return -ve if zLhs is smaller than zRhs, 0 if it is equal, or +ve +** if it is greater. +*/ +static int fts3TermCmp( + const char *zLhs, int nLhs, /* LHS of comparison */ + const char *zRhs, int nRhs /* RHS of comparison */ +){ + int nCmp = MIN(nLhs, nRhs); + int res; - /* Step 5b */ - if( m_gt_1(z) && z[0]=='l' && z[1]=='l' ){ - z++; + if( nCmp && ALWAYS(zLhs) && ALWAYS(zRhs) ){ + res = memcmp(zLhs, zRhs, nCmp); + }else{ + res = 0; } + if( res==0 ) res = nLhs - nRhs; - /* z[] is now the stemmed word in reverse order. Flip it back - ** around into forward order and return. - */ - *pnOut = i = (int)strlen(z); - zOut[i] = 0; - while( *z ){ - zOut[--i] = *(z++); - } + return res; } + /* -** Characters that can be part of a token. We assume any character -** whose value is greater than 0x80 (any UTF character) can be -** part of a token. In other words, delimiters all must have -** values of 0x7f or lower. +** Query to see if the entry in the %_segments table with blockid iEnd is +** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before +** returning. Otherwise, set *pbRes to 0. +** +** Or, if an error occurs while querying the database, return an SQLite +** error code. The final value of *pbRes is undefined in this case. +** +** This is used to test if a segment is an "appendable" segment. If it +** is, then a NULL entry has been inserted into the %_segments table +** with blockid %_segdir.end_block. */ -static const char porterIdChar[] = { -/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ -}; -#define isDelim(C) (((ch=C)&0x80)==0 && (ch<0x30 || !porterIdChar[ch-0x30])) +static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){ + int bRes = 0; /* Result to set *pbRes to */ + sqlite3_stmt *pCheck = 0; /* Statement to query database with */ + int rc; /* Return code */ + + rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pCheck, 1, iEnd); + if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1; + rc = sqlite3_reset(pCheck); + } + + *pbRes = bRes; + return rc; +} /* -** Extract the next token from a tokenization cursor. The cursor must -** have been opened by a prior call to porterOpen(). +** This function is called when initializing an incremental-merge operation. +** It checks if the existing segment with index value iIdx at absolute level +** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the +** merge-writer object *pWriter is initialized to write to it. +** +** An existing segment can be appended to by an incremental merge if: +** +** * It was initially created as an appendable segment (with all required +** space pre-allocated), and +** +** * The first key read from the input (arguments zKey and nKey) is +** greater than the largest key currently stored in the potential +** output segment. */ -static int porterNext( - sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by porterOpen */ - const char **pzToken, /* OUT: *pzToken is the token text */ - int *pnBytes, /* OUT: Number of bytes in token */ - int *piStartOffset, /* OUT: Starting offset of token */ - int *piEndOffset, /* OUT: Ending offset of token */ - int *piPosition /* OUT: Position integer of token */ +static int fts3IncrmergeLoad( + Fts3Table *p, /* Fts3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ + int iIdx, /* Index of candidate output segment */ + const char *zKey, /* First key to write */ + int nKey, /* Number of bytes in nKey */ + IncrmergeWriter *pWriter /* Populate this object */ ){ - porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; - const char *z = c->zInput; + int rc; /* Return code */ + sqlite3_stmt *pSelect = 0; /* SELECT to read %_segdir entry */ - while( c->iOffsetnInput ){ - int iStartOffset, ch; + rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pSelect, 0); + if( rc==SQLITE_OK ){ + sqlite3_int64 iStart = 0; /* Value of %_segdir.start_block */ + sqlite3_int64 iLeafEnd = 0; /* Value of %_segdir.leaves_end_block */ + sqlite3_int64 iEnd = 0; /* Value of %_segdir.end_block */ + const char *aRoot = 0; /* Pointer to %_segdir.root buffer */ + int nRoot = 0; /* Size of aRoot[] in bytes */ + int rc2; /* Return code from sqlite3_reset() */ + int bAppendable = 0; /* Set to true if segment is appendable */ - /* Scan past delimiter characters */ - while( c->iOffsetnInput && isDelim(z[c->iOffset]) ){ - c->iOffset++; + /* Read the %_segdir entry for index iIdx absolute level (iAbsLevel+1) */ + sqlite3_bind_int64(pSelect, 1, iAbsLevel+1); + sqlite3_bind_int(pSelect, 2, iIdx); + if( sqlite3_step(pSelect)==SQLITE_ROW ){ + iStart = sqlite3_column_int64(pSelect, 1); + iLeafEnd = sqlite3_column_int64(pSelect, 2); + fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); + if( pWriter->nLeafData<0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } + pWriter->bNoLeafData = (pWriter->nLeafData==0); + nRoot = sqlite3_column_bytes(pSelect, 4); + aRoot = sqlite3_column_blob(pSelect, 4); + if( aRoot==0 ){ + sqlite3_reset(pSelect); + return nRoot ? SQLITE_NOMEM : FTS_CORRUPT_VTAB; + } + }else{ + return sqlite3_reset(pSelect); } - /* Count non-delimiter characters. */ - iStartOffset = c->iOffset; - while( c->iOffsetnInput && !isDelim(z[c->iOffset]) ){ - c->iOffset++; + /* Check for the zero-length marker in the %_segments table */ + rc = fts3IsAppendable(p, iEnd, &bAppendable); + + /* Check that zKey/nKey is larger than the largest key the candidate */ + if( rc==SQLITE_OK && bAppendable ){ + char *aLeaf = 0; + int nLeaf = 0; + + rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0); + if( rc==SQLITE_OK ){ + NodeReader reader; + for(rc = nodeReaderInit(&reader, aLeaf, nLeaf); + rc==SQLITE_OK && reader.aNode; + rc = nodeReaderNext(&reader) + ){ + assert( reader.aNode ); + } + if( fts3TermCmp(zKey, nKey, reader.term.a, reader.term.n)<=0 ){ + bAppendable = 0; + } + nodeReaderRelease(&reader); + } + sqlite3_free(aLeaf); } - if( c->iOffset>iStartOffset ){ - int n = c->iOffset-iStartOffset; - if( n>c->nAllocated ){ - char *pNew; - c->nAllocated = n+20; - pNew = sqlite3_realloc(c->zToken, c->nAllocated); - if( !pNew ) return SQLITE_NOMEM; - c->zToken = pNew; + if( rc==SQLITE_OK && bAppendable ){ + /* It is possible to append to this segment. Set up the IncrmergeWriter + ** object to do so. */ + int i; + int nHeight = (int)aRoot[0]; + NodeWriter *pNode; + if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){ + sqlite3_reset(pSelect); + return FTS_CORRUPT_VTAB; + } + + pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; + pWriter->iStart = iStart; + pWriter->iEnd = iEnd; + pWriter->iAbsLevel = iAbsLevel; + pWriter->iIdx = iIdx; + + for(i=nHeight+1; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; + } + + pNode = &pWriter->aNodeWriter[nHeight]; + pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; + blobGrowBuffer(&pNode->block, + MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc + ); + if( rc==SQLITE_OK ){ + memcpy(pNode->block.a, aRoot, nRoot); + pNode->block.n = nRoot; + memset(&pNode->block.a[nRoot], 0, FTS3_NODE_PADDING); + } + + for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ + NodeReader reader; + pNode = &pWriter->aNodeWriter[i]; + + if( pNode->block.a){ + rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); + while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); + blobGrowBuffer(&pNode->key, reader.term.n, &rc); + if( rc==SQLITE_OK ){ + assert_fts3_nc( reader.term.n>0 || reader.aNode==0 ); + if( reader.term.n>0 ){ + memcpy(pNode->key.a, reader.term.a, reader.term.n); + } + pNode->key.n = reader.term.n; + if( i>0 ){ + char *aBlock = 0; + int nBlock = 0; + pNode = &pWriter->aNodeWriter[i-1]; + pNode->iBlock = reader.iChild; + rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0); + blobGrowBuffer(&pNode->block, + MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc + ); + if( rc==SQLITE_OK ){ + memcpy(pNode->block.a, aBlock, nBlock); + pNode->block.n = nBlock; + memset(&pNode->block.a[nBlock], 0, FTS3_NODE_PADDING); + } + sqlite3_free(aBlock); + } + } + } + nodeReaderRelease(&reader); } - porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); - *pzToken = c->zToken; - *piStartOffset = iStartOffset; - *piEndOffset = c->iOffset; - *piPosition = c->iToken++; - return SQLITE_OK; } + + rc2 = sqlite3_reset(pSelect); + if( rc==SQLITE_OK ) rc = rc2; } - return SQLITE_DONE; -} -/* -** The set of routines that implement the porter-stemmer tokenizer -*/ -static const sqlite3_tokenizer_module porterTokenizerModule = { - 0, - porterCreate, - porterDestroy, - porterOpen, - porterClose, - porterNext, - 0 -}; + return rc; +} /* -** Allocate a new porter tokenizer. Return a pointer to the new -** tokenizer in *ppModule +** Determine the largest segment index value that exists within absolute +** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus +** one before returning SQLITE_OK. Or, if there are no segments at all +** within level iAbsLevel, set *piIdx to zero. +** +** If an error occurs, return an SQLite error code. The final value of +** *piIdx is undefined in this case. */ -SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule( - sqlite3_tokenizer_module const**ppModule +static int fts3IncrmergeOutputIdx( + Fts3Table *p, /* FTS Table handle */ + sqlite3_int64 iAbsLevel, /* Absolute index of input segments */ + int *piIdx /* OUT: Next free index at iAbsLevel+1 */ ){ - *ppModule = &porterTokenizerModule; -} + int rc; + sqlite3_stmt *pOutputIdx = 0; /* SQL used to find output index */ -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pOutputIdx, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pOutputIdx, 1, iAbsLevel+1); + sqlite3_step(pOutputIdx); + *piIdx = sqlite3_column_int(pOutputIdx, 0); + rc = sqlite3_reset(pOutputIdx); + } + + return rc; +} -/************** End of fts3_porter.c *****************************************/ -/************** Begin file fts3_tokenizer.c **********************************/ /* -** 2007 June 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: +** Allocate an appendable output segment on absolute level iAbsLevel+1 +** with idx value iIdx. ** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** In the %_segdir table, a segment is defined by the values in three +** columns: ** -****************************************************************************** +** start_block +** leaves_end_block +** end_block ** -** This is part of an SQLite module implementing full-text search. -** This particular file implements the generic tokenizer interface. -*/ - -/* -** The code in this file is only compiled if: +** When an appendable segment is allocated, it is estimated that the +** maximum number of leaf blocks that may be required is the sum of the +** number of leaf blocks consumed by the input segments, plus the number +** of input segments, multiplied by two. This value is stored in stack +** variable nLeafEst. ** -** * The FTS3 module is being built as an extension -** (in which case SQLITE_CORE is not defined), or +** A total of 16*nLeafEst blocks are allocated when an appendable segment +** is created ((1 + end_block - start_block)==16*nLeafEst). The contiguous +** array of leaf nodes starts at the first block allocated. The array +** of interior nodes that are parents of the leaf nodes start at block +** (start_block + (1 + end_block - start_block) / 16). And so on. ** -** * The FTS3 module is being built into the core of -** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). +** In the actual code below, the value "16" is replaced with the +** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT. */ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) +static int fts3IncrmergeWriter( + Fts3Table *p, /* Fts3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ + int iIdx, /* Index of new output segment */ + Fts3MultiSegReader *pCsr, /* Cursor that data will be read from */ + IncrmergeWriter *pWriter /* Populate this object */ +){ + int rc; /* Return Code */ + int i; /* Iterator variable */ + int nLeafEst = 0; /* Blocks allocated for leaf nodes */ + sqlite3_stmt *pLeafEst = 0; /* SQL used to determine nLeafEst */ + sqlite3_stmt *pFirstBlock = 0; /* SQL used to determine first block */ -/* #include */ -/* #include */ + /* Calculate nLeafEst. */ + rc = fts3SqlStmt(p, SQL_MAX_LEAF_NODE_ESTIMATE, &pLeafEst, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pLeafEst, 1, iAbsLevel); + sqlite3_bind_int64(pLeafEst, 2, pCsr->nSegment); + if( SQLITE_ROW==sqlite3_step(pLeafEst) ){ + nLeafEst = sqlite3_column_int(pLeafEst, 0); + } + rc = sqlite3_reset(pLeafEst); + } + if( rc!=SQLITE_OK ) return rc; -/* -** Return true if the two-argument version of fts3_tokenizer() -** has been activated via a prior call to sqlite3_db_config(db, -** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0); -*/ -static int fts3TokenizerEnabled(sqlite3_context *context){ - sqlite3 *db = sqlite3_context_db_handle(context); - int isEnabled = 0; - sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled); - return isEnabled; + /* Calculate the first block to use in the output segment */ + rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pFirstBlock, 0); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pFirstBlock) ){ + pWriter->iStart = sqlite3_column_int64(pFirstBlock, 0); + pWriter->iEnd = pWriter->iStart - 1; + pWriter->iEnd += nLeafEst * FTS_MAX_APPENDABLE_HEIGHT; + } + rc = sqlite3_reset(pFirstBlock); + } + if( rc!=SQLITE_OK ) return rc; + + /* Insert the marker in the %_segments table to make sure nobody tries + ** to steal the space just allocated. This is also used to identify + ** appendable segments. */ + rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0); + if( rc!=SQLITE_OK ) return rc; + + pWriter->iAbsLevel = iAbsLevel; + pWriter->nLeafEst = nLeafEst; + pWriter->iIdx = iIdx; + + /* Set up the array of NodeWriter objects */ + for(i=0; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; + } + return SQLITE_OK; } /* -** Implementation of the SQL scalar function for accessing the underlying -** hash table. This function may be called as follows: -** -** SELECT (); -** SELECT (, ); -** -** where is the name passed as the second argument -** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer'). +** Remove an entry from the %_segdir table. This involves running the +** following two statements: ** -** If the argument is specified, it must be a blob value -** containing a pointer to be stored as the hash data corresponding -** to the string . If is not specified, then -** the string must already exist in the has table. Otherwise, -** an error is returned. +** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx +** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx ** -** Whether or not the argument is specified, the value returned -** is a blob containing the pointer stored as the hash data corresponding -** to string (after the hash-table is updated, if applicable). +** The DELETE statement removes the specific %_segdir level. The UPDATE +** statement ensures that the remaining segments have contiguously allocated +** idx values. */ -static void fts3TokenizerFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv +static int fts3RemoveSegdirEntry( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level to delete from */ + int iIdx /* Index of %_segdir entry to delete */ ){ - Fts3Hash *pHash; - void *pPtr = 0; - const unsigned char *zName; - int nName; - - assert( argc==1 || argc==2 ); - - pHash = (Fts3Hash *)sqlite3_user_data(context); - - zName = sqlite3_value_text(argv[0]); - nName = sqlite3_value_bytes(argv[0])+1; + int rc; /* Return code */ + sqlite3_stmt *pDelete = 0; /* DELETE statement */ - if( argc==2 ){ - if( fts3TokenizerEnabled(context) ){ - void *pOld; - int n = sqlite3_value_bytes(argv[1]); - if( zName==0 || n!=sizeof(pPtr) ){ - sqlite3_result_error(context, "argument type mismatch", -1); - return; - } - pPtr = *(void **)sqlite3_value_blob(argv[1]); - pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr); - if( pOld==pPtr ){ - sqlite3_result_error(context, "out of memory", -1); - } - }else{ - sqlite3_result_error(context, "fts3tokenize disabled", -1); - return; - } - }else{ - if( zName ){ - pPtr = sqlite3Fts3HashFind(pHash, zName, nName); - } - if( !pPtr ){ - char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); - sqlite3_result_error(context, zErr, -1); - sqlite3_free(zErr); - return; - } + rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_ENTRY, &pDelete, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDelete, 1, iAbsLevel); + sqlite3_bind_int(pDelete, 2, iIdx); + sqlite3_step(pDelete); + rc = sqlite3_reset(pDelete); } - sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); -} -SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){ - static const char isFtsIdChar[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ - }; - return (c&0x80 || isFtsIdChar[(int)(c)]); + return rc; } -SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *zStr, int *pn){ - const char *z1; - const char *z2 = 0; - - /* Find the start of the next token. */ - z1 = zStr; - while( z2==0 ){ - char c = *z1; - switch( c ){ - case '\0': return 0; /* No more tokens here */ - case '\'': - case '"': - case '`': { - z2 = z1; - while( *++z2 && (*z2!=c || *++z2==c) ); - break; - } - case '[': - z2 = &z1[1]; - while( *z2 && z2[0]!=']' ) z2++; - if( *z2 ) z2++; - break; +/* +** One or more segments have just been removed from absolute level iAbsLevel. +** Update the 'idx' values of the remaining segments in the level so that +** the idx values are a contiguous sequence starting from 0. +*/ +static int fts3RepackSegdirLevel( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel /* Absolute level to repack */ +){ + int rc; /* Return code */ + int *aIdx = 0; /* Array of remaining idx values */ + int nIdx = 0; /* Valid entries in aIdx[] */ + int nAlloc = 0; /* Allocated size of aIdx[] */ + int i; /* Iterator variable */ + sqlite3_stmt *pSelect = 0; /* Select statement to read idx values */ + sqlite3_stmt *pUpdate = 0; /* Update statement to modify idx values */ - default: - if( sqlite3Fts3IsIdChar(*z1) ){ - z2 = &z1[1]; - while( sqlite3Fts3IsIdChar(*z2) ) z2++; - }else{ - z1++; + rc = fts3SqlStmt(p, SQL_SELECT_INDEXES, &pSelect, 0); + if( rc==SQLITE_OK ){ + int rc2; + sqlite3_bind_int64(pSelect, 1, iAbsLevel); + while( SQLITE_ROW==sqlite3_step(pSelect) ){ + if( nIdx>=nAlloc ){ + int *aNew; + nAlloc += 16; + aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); + if( !aNew ){ + rc = SQLITE_NOMEM; + break; } + aIdx = aNew; + } + aIdx[nIdx++] = sqlite3_column_int(pSelect, 0); } + rc2 = sqlite3_reset(pSelect); + if( rc==SQLITE_OK ) rc = rc2; } - *pn = (int)(z2-z1); - return z1; -} - -SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( - Fts3Hash *pHash, /* Tokenizer hash table */ - const char *zArg, /* Tokenizer name */ - sqlite3_tokenizer **ppTok, /* OUT: Tokenizer (if applicable) */ - char **pzErr /* OUT: Set to malloced error message */ -){ - int rc; - char *z = (char *)zArg; - int n = 0; - char *zCopy; - char *zEnd; /* Pointer to nul-term of zCopy */ - sqlite3_tokenizer_module *m; - - zCopy = sqlite3_mprintf("%s", zArg); - if( !zCopy ) return SQLITE_NOMEM; - zEnd = &zCopy[strlen(zCopy)]; - - z = (char *)sqlite3Fts3NextToken(zCopy, &n); - if( z==0 ){ - assert( n==0 ); - z = zCopy; + if( rc==SQLITE_OK ){ + rc = fts3SqlStmt(p, SQL_SHIFT_SEGDIR_ENTRY, &pUpdate, 0); + } + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pUpdate, 2, iAbsLevel); } - z[n] = '\0'; - sqlite3Fts3Dequote(z); - m = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash,z,(int)strlen(z)+1); - if( !m ){ - sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", z); - rc = SQLITE_ERROR; - }else{ - char const **aArg = 0; - int iArg = 0; - z = &z[n+1]; - while( zxCreate(iArg, aArg, ppTok); - assert( rc!=SQLITE_OK || *ppTok ); - if( rc!=SQLITE_OK ){ - sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer"); - }else{ - (*ppTok)->pModule = m; + assert( p->bIgnoreSavepoint==0 ); + p->bIgnoreSavepoint = 1; + for(i=0; rc==SQLITE_OK && ibIgnoreSavepoint = 0; - sqlite3_free(zCopy); + sqlite3_free(aIdx); return rc; } - -#ifdef SQLITE_TEST - -#if defined(INCLUDE_SQLITE_TCL_H) -# include "sqlite_tcl.h" -#else -# include "tcl.h" -#endif -/* #include */ +static void fts3StartNode(Blob *pNode, int iHeight, sqlite3_int64 iChild){ + pNode->a[0] = (char)iHeight; + if( iChild ){ + assert( pNode->nAlloc>=1+sqlite3Fts3VarintLen(iChild) ); + pNode->n = 1 + sqlite3Fts3PutVarint(&pNode->a[1], iChild); + }else{ + assert( pNode->nAlloc>=1 ); + pNode->n = 1; + } +} /* -** Implementation of a special SQL scalar function for testing tokenizers -** designed to be used in concert with the Tcl testing framework. This -** function must be called with two or more arguments: -** -** SELECT (, ..., ); -** -** where is the name passed as the second argument -** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer') -** concatenated with the string '_test' (e.g. 'fts3_tokenizer_test'). -** -** The return value is a string that may be interpreted as a Tcl -** list. For each token in the , three elements are -** added to the returned list. The first is the token position, the -** second is the token text (folded, stemmed, etc.) and the third is the -** substring of associated with the token. For example, -** using the built-in "simple" tokenizer: -** -** SELECT fts_tokenizer_test('simple', 'I don't see how'); -** -** will return the string: +** The first two arguments are a pointer to and the size of a segment b-tree +** node. The node may be a leaf or an internal node. ** -** "{0 i I 1 dont don't 2 see see 3 how how}" -** +** This function creates a new node image in blob object *pNew by copying +** all terms that are greater than or equal to zTerm/nTerm (for leaf nodes) +** or greater than zTerm/nTerm (for internal nodes) from aNode/nNode. */ -static void testFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv +static int fts3TruncateNode( + const char *aNode, /* Current node image */ + int nNode, /* Size of aNode in bytes */ + Blob *pNew, /* OUT: Write new node image here */ + const char *zTerm, /* Omit all terms smaller than this */ + int nTerm, /* Size of zTerm in bytes */ + sqlite3_int64 *piBlock /* OUT: Block number in next layer down */ ){ - Fts3Hash *pHash; - sqlite3_tokenizer_module *p; - sqlite3_tokenizer *pTokenizer = 0; - sqlite3_tokenizer_cursor *pCsr = 0; - - const char *zErr = 0; - - const char *zName; - int nName; - const char *zInput; - int nInput; - - const char *azArg[64]; + NodeReader reader; /* Reader object */ + Blob prev = {0, 0, 0}; /* Previous term written to new node */ + int rc = SQLITE_OK; /* Return code */ + int bLeaf; /* True for a leaf node */ - const char *zToken; - int nToken = 0; - int iStart = 0; - int iEnd = 0; - int iPos = 0; - int i; + if( nNode<1 ) return FTS_CORRUPT_VTAB; + bLeaf = aNode[0]=='\0'; - Tcl_Obj *pRet; + /* Allocate required output space */ + blobGrowBuffer(pNew, nNode, &rc); + if( rc!=SQLITE_OK ) return rc; + pNew->n = 0; - if( argc<2 ){ - sqlite3_result_error(context, "insufficient arguments", -1); - return; + /* Populate new node buffer */ + for(rc = nodeReaderInit(&reader, aNode, nNode); + rc==SQLITE_OK && reader.aNode; + rc = nodeReaderNext(&reader) + ){ + if( pNew->n==0 ){ + int res = fts3TermCmp(reader.term.a, reader.term.n, zTerm, nTerm); + if( res<0 || (bLeaf==0 && res==0) ) continue; + fts3StartNode(pNew, (int)aNode[0], reader.iChild); + *piBlock = reader.iChild; + } + rc = fts3AppendToNode( + pNew, &prev, reader.term.a, reader.term.n, + reader.aDoclist, reader.nDoclist + ); + if( rc!=SQLITE_OK ) break; + } + if( pNew->n==0 ){ + fts3StartNode(pNew, (int)aNode[0], reader.iChild); + *piBlock = reader.iChild; } + assert( pNew->n<=pNew->nAlloc ); - nName = sqlite3_value_bytes(argv[0]); - zName = (const char *)sqlite3_value_text(argv[0]); - nInput = sqlite3_value_bytes(argv[argc-1]); - zInput = (const char *)sqlite3_value_text(argv[argc-1]); + nodeReaderRelease(&reader); + sqlite3_free(prev.a); + return rc; +} - pHash = (Fts3Hash *)sqlite3_user_data(context); - p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); +/* +** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute +** level iAbsLevel. This may involve deleting entries from the %_segments +** table, and modifying existing entries in both the %_segments and %_segdir +** tables. +** +** SQLITE_OK is returned if the segment is updated successfully. Or an +** SQLite error code otherwise. +*/ +static int fts3TruncateSegment( + Fts3Table *p, /* FTS3 table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level of segment to modify */ + int iIdx, /* Index within level of segment to modify */ + const char *zTerm, /* Remove terms smaller than this */ + int nTerm /* Number of bytes in buffer zTerm */ +){ + int rc = SQLITE_OK; /* Return code */ + Blob root = {0,0,0}; /* New root page image */ + Blob block = {0,0,0}; /* Buffer used for any other block */ + sqlite3_int64 iBlock = 0; /* Block id */ + sqlite3_int64 iNewStart = 0; /* New value for iStartBlock */ + sqlite3_int64 iOldStart = 0; /* Old value for iStartBlock */ + sqlite3_stmt *pFetch = 0; /* Statement used to fetch segdir */ - if( !p ){ - char *zErr2 = sqlite3_mprintf("unknown tokenizer: %s", zName); - sqlite3_result_error(context, zErr2, -1); - sqlite3_free(zErr2); - return; + rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pFetch, 0); + if( rc==SQLITE_OK ){ + int rc2; /* sqlite3_reset() return code */ + sqlite3_bind_int64(pFetch, 1, iAbsLevel); + sqlite3_bind_int(pFetch, 2, iIdx); + if( SQLITE_ROW==sqlite3_step(pFetch) ){ + const char *aRoot = sqlite3_column_blob(pFetch, 4); + int nRoot = sqlite3_column_bytes(pFetch, 4); + iOldStart = sqlite3_column_int64(pFetch, 1); + rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock); + } + rc2 = sqlite3_reset(pFetch); + if( rc==SQLITE_OK ) rc = rc2; } - pRet = Tcl_NewObj(); - Tcl_IncrRefCount(pRet); - - for(i=1; ixCreate(argc-2, azArg, &pTokenizer) ){ - zErr = "error in xCreate()"; - goto finish; - } - pTokenizer->pModule = p; - if( sqlite3Fts3OpenTokenizer(pTokenizer, 0, zInput, nInput, &pCsr) ){ - zErr = "error in xOpen()"; - goto finish; + rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0); + if( rc==SQLITE_OK ){ + rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock); + } + if( rc==SQLITE_OK ){ + rc = fts3WriteSegment(p, iNewStart, block.a, block.n); + } + sqlite3_free(aBlock); } - while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){ - Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); - zToken = &zInput[iStart]; - nToken = iEnd-iStart; - Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); + /* Variable iNewStart now contains the first valid leaf node. */ + if( rc==SQLITE_OK && iNewStart ){ + sqlite3_stmt *pDel = 0; + rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pDel, 1, iOldStart); + sqlite3_bind_int64(pDel, 2, iNewStart-1); + sqlite3_step(pDel); + rc = sqlite3_reset(pDel); + } } - if( SQLITE_OK!=p->xClose(pCsr) ){ - zErr = "error in xClose()"; - goto finish; - } - if( SQLITE_OK!=p->xDestroy(pTokenizer) ){ - zErr = "error in xDestroy()"; - goto finish; + if( rc==SQLITE_OK ){ + sqlite3_stmt *pChomp = 0; + rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pChomp, 1, iNewStart); + sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC); + sqlite3_bind_int64(pChomp, 3, iAbsLevel); + sqlite3_bind_int(pChomp, 4, iIdx); + sqlite3_step(pChomp); + rc = sqlite3_reset(pChomp); + sqlite3_bind_null(pChomp, 2); + } } -finish: - if( zErr ){ - sqlite3_result_error(context, zErr, -1); - }else{ - sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT); - } - Tcl_DecrRefCount(pRet); + sqlite3_free(root.a); + sqlite3_free(block.a); + return rc; } -static -int registerTokenizer( - sqlite3 *db, - char *zName, - const sqlite3_tokenizer_module *p +/* +** This function is called after an incrmental-merge operation has run to +** merge (or partially merge) two or more segments from absolute level +** iAbsLevel. +** +** Each input segment is either removed from the db completely (if all of +** its data was copied to the output segment by the incrmerge operation) +** or modified in place so that it no longer contains those entries that +** have been duplicated in the output segment. +*/ +static int fts3IncrmergeChomp( + Fts3Table *p, /* FTS table handle */ + sqlite3_int64 iAbsLevel, /* Absolute level containing segments */ + Fts3MultiSegReader *pCsr, /* Chomp all segments opened by this cursor */ + int *pnRem /* Number of segments not deleted */ ){ - int rc; - sqlite3_stmt *pStmt; - const char zSql[] = "SELECT fts3_tokenizer(?, ?)"; + int i; + int nRem = 0; + int rc = SQLITE_OK; - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ){ - return rc; - } + for(i=pCsr->nSegment-1; i>=0 && rc==SQLITE_OK; i--){ + Fts3SegReader *pSeg = 0; + int j; - sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); - sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); - sqlite3_step(pStmt); + /* Find the Fts3SegReader object with Fts3SegReader.iIdx==i. It is hiding + ** somewhere in the pCsr->apSegment[] array. */ + for(j=0; ALWAYS(jnSegment); j++){ + pSeg = pCsr->apSegment[j]; + if( pSeg->iIdx==i ) break; + } + assert( jnSegment && pSeg->iIdx==i ); - return sqlite3_finalize(pStmt); -} + if( pSeg->aNode==0 ){ + /* Seg-reader is at EOF. Remove the entire input segment. */ + rc = fts3DeleteSegment(p, pSeg); + if( rc==SQLITE_OK ){ + rc = fts3RemoveSegdirEntry(p, iAbsLevel, pSeg->iIdx); + } + *pnRem = 0; + }else{ + /* The incremental merge did not copy all the data from this + ** segment to the upper level. The segment is modified in place + ** so that it contains no keys smaller than zTerm/nTerm. */ + const char *zTerm = pSeg->zTerm; + int nTerm = pSeg->nTerm; + rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm); + nRem++; + } + } + if( rc==SQLITE_OK && nRem!=pCsr->nSegment ){ + rc = fts3RepackSegdirLevel(p, iAbsLevel); + } -static -int queryTokenizer( - sqlite3 *db, - char *zName, - const sqlite3_tokenizer_module **pp -){ - int rc; - sqlite3_stmt *pStmt; - const char zSql[] = "SELECT fts3_tokenizer(?)"; + *pnRem = nRem; + return rc; +} - *pp = 0; - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( rc!=SQLITE_OK ){ - return rc; - } +/* +** Store an incr-merge hint in the database. +*/ +static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){ + sqlite3_stmt *pReplace = 0; + int rc; /* Return code */ - sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){ - memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); - } + rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT); + sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC); + sqlite3_step(pReplace); + rc = sqlite3_reset(pReplace); + sqlite3_bind_null(pReplace, 2); } - return sqlite3_finalize(pStmt); + return rc; } -SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); - /* -** Implementation of the scalar function fts3_tokenizer_internal_test(). -** This function is used for testing only, it is not included in the -** build unless SQLITE_TEST is defined. -** -** The purpose of this is to test that the fts3_tokenizer() function -** can be used as designed by the C-code in the queryTokenizer and -** registerTokenizer() functions above. These two functions are repeated -** in the README.tokenizer file as an example, so it is important to -** test them. -** -** To run the tests, evaluate the fts3_tokenizer_internal_test() scalar -** function with no arguments. An assert() will fail if a problem is -** detected. i.e.: -** -** SELECT fts3_tokenizer_internal_test(); +** Load an incr-merge hint from the database. The incr-merge hint, if one +** exists, is stored in the rowid==1 row of the %_stat table. ** +** If successful, populate blob *pHint with the value read from the %_stat +** table and return SQLITE_OK. Otherwise, if an error occurs, return an +** SQLite error code. */ -static void intTestFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ +static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){ + sqlite3_stmt *pSelect = 0; int rc; - const sqlite3_tokenizer_module *p1; - const sqlite3_tokenizer_module *p2; - sqlite3 *db = (sqlite3 *)sqlite3_user_data(context); - UNUSED_PARAMETER(argc); - UNUSED_PARAMETER(argv); - - /* Test the query function */ - sqlite3Fts3SimpleTokenizerModule(&p1); - rc = queryTokenizer(db, "simple", &p2); - assert( rc==SQLITE_OK ); - assert( p1==p2 ); - rc = queryTokenizer(db, "nosuchtokenizer", &p2); - assert( rc==SQLITE_ERROR ); - assert( p2==0 ); - assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); - - /* Test the storage function */ - if( fts3TokenizerEnabled(context) ){ - rc = registerTokenizer(db, "nosuchtokenizer", p1); - assert( rc==SQLITE_OK ); - rc = queryTokenizer(db, "nosuchtokenizer", &p2); - assert( rc==SQLITE_OK ); - assert( p2==p1 ); + pHint->n = 0; + rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pSelect, 0); + if( rc==SQLITE_OK ){ + int rc2; + sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT); + if( SQLITE_ROW==sqlite3_step(pSelect) ){ + const char *aHint = sqlite3_column_blob(pSelect, 0); + int nHint = sqlite3_column_bytes(pSelect, 0); + if( aHint ){ + blobGrowBuffer(pHint, nHint, &rc); + if( rc==SQLITE_OK ){ + if( ALWAYS(pHint->a!=0) ) memcpy(pHint->a, aHint, nHint); + pHint->n = nHint; + } + } + } + rc2 = sqlite3_reset(pSelect); + if( rc==SQLITE_OK ) rc = rc2; } - sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); + return rc; } -#endif - /* -** Set up SQL objects in database db used to access the contents of -** the hash table pointed to by argument pHash. The hash table must -** been initialized to use string keys, and to take a private copy -** of the key when a value is inserted. i.e. by a call similar to: -** -** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); -** -** This function adds a scalar function (see header comment above -** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is -** defined at compilation time, a temporary virtual table (see header -** comment above struct HashTableVtab) to the database schema. Both -** provide read/write access to the contents of *pHash. +** If *pRc is not SQLITE_OK when this function is called, it is a no-op. +** Otherwise, append an entry to the hint stored in blob *pHint. Each entry +** consists of two varints, the absolute level number of the input segments +** and the number of input segments. ** -** The third argument to this function, zName, is used as the name -** of both the scalar and, if created, the virtual table. +** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs, +** set *pRc to an SQLite error code before returning. */ -SQLITE_PRIVATE int sqlite3Fts3InitHashTable( - sqlite3 *db, - Fts3Hash *pHash, - const char *zName +static void fts3IncrmergeHintPush( + Blob *pHint, /* Hint blob to append to */ + i64 iAbsLevel, /* First varint to store in hint */ + int nInput, /* Second varint to store in hint */ + int *pRc /* IN/OUT: Error code */ ){ - int rc = SQLITE_OK; - void *p = (void *)pHash; - const int any = SQLITE_ANY; - -#ifdef SQLITE_TEST - char *zTest = 0; - char *zTest2 = 0; - void *pdb = (void *)db; - zTest = sqlite3_mprintf("%s_test", zName); - zTest2 = sqlite3_mprintf("%s_internal_test", zName); - if( !zTest || !zTest2 ){ - rc = SQLITE_NOMEM; + blobGrowBuffer(pHint, pHint->n + 2*FTS3_VARINT_MAX, pRc); + if( *pRc==SQLITE_OK ){ + pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], iAbsLevel); + pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], (i64)nInput); } -#endif +} - if( SQLITE_OK==rc ){ - rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0); - } - if( SQLITE_OK==rc ){ - rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0); - } -#ifdef SQLITE_TEST - if( SQLITE_OK==rc ){ - rc = sqlite3_create_function(db, zTest, -1, any, p, testFunc, 0, 0); - } - if( SQLITE_OK==rc ){ - rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0); - } -#endif +/* +** Read the last entry (most recently pushed) from the hint blob *pHint +** and then remove the entry. Write the two values read to *piAbsLevel and +** *pnInput before returning. +** +** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does +** not contain at least two valid varints, return SQLITE_CORRUPT_VTAB. +*/ +static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){ + const int nHint = pHint->n; + int i; -#ifdef SQLITE_TEST - sqlite3_free(zTest); - sqlite3_free(zTest2); -#endif + i = pHint->n-1; + if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB; + while( i>0 && (pHint->a[i-1] & 0x80) ) i--; + if( i==0 ) return FTS_CORRUPT_VTAB; + i--; + while( i>0 && (pHint->a[i-1] & 0x80) ) i--; - return rc; + pHint->n = i; + i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel); + i += fts3GetVarint32(&pHint->a[i], pnInput); + assert( i<=nHint ); + if( i!=nHint ) return FTS_CORRUPT_VTAB; + + return SQLITE_OK; } -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ -/************** End of fts3_tokenizer.c **************************************/ -/************** Begin file fts3_tokenizer1.c *********************************/ /* -** 2006 Oct 10 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** +** Attempt an incremental merge that writes nMerge leaf blocks. ** -** Implementation of the "simple" full-text-search tokenizer. +** Incremental merges happen nMin segments at a time. The segments +** to be merged are the nMin oldest segments (the ones with the smallest +** values for the _segdir.idx field) in the highest level that contains +** at least nMin segments. Multiple merges might occur in an attempt to +** write the quota of nMerge leaf blocks. */ +SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ + int rc; /* Return code */ + int nRem = nMerge; /* Number of leaf pages yet to be written */ + Fts3MultiSegReader *pCsr; /* Cursor used to read input data */ + Fts3SegFilter *pFilter; /* Filter used with cursor pCsr */ + IncrmergeWriter *pWriter; /* Writer object */ + int nSeg = 0; /* Number of input segments */ + sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */ + Blob hint = {0, 0, 0}; /* Hint read from %_stat table */ + int bDirtyHint = 0; /* True if blob 'hint' has been modified */ -/* -** The code in this file is only compiled if: -** -** * The FTS3 module is being built as an extension -** (in which case SQLITE_CORE is not defined), or -** -** * The FTS3 module is being built into the core of -** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). -*/ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + /* Allocate space for the cursor, filter and writer objects */ + const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); + pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); + if( !pWriter ) return SQLITE_NOMEM; + pFilter = (Fts3SegFilter *)&pWriter[1]; + pCsr = (Fts3MultiSegReader *)&pFilter[1]; -/* #include */ -/* #include */ -/* #include */ -/* #include */ + rc = fts3IncrmergeHintLoad(p, &hint); + while( rc==SQLITE_OK && nRem>0 ){ + const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; + sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */ + int bUseHint = 0; /* True if attempting to append */ + int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ -/* #include "fts3_tokenizer.h" */ + /* Search the %_segdir table for the absolute level with the smallest + ** relative level number that contains at least nMin segments, if any. + ** If one is found, set iAbsLevel to the absolute level number and + ** nSeg to nMin. If no level with at least nMin segments can be found, + ** set nSeg to -1. + */ + rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0); + sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin)); + if( sqlite3_step(pFindLevel)==SQLITE_ROW ){ + iAbsLevel = sqlite3_column_int64(pFindLevel, 0); + nSeg = sqlite3_column_int(pFindLevel, 1); + assert( nSeg>=2 ); + }else{ + nSeg = -1; + } + rc = sqlite3_reset(pFindLevel); -typedef struct simple_tokenizer { - sqlite3_tokenizer base; - char delim[128]; /* flag ASCII delimiters */ -} simple_tokenizer; + /* If the hint read from the %_stat table is not empty, check if the + ** last entry in it specifies a relative level smaller than or equal + ** to the level identified by the block above (if any). If so, this + ** iteration of the loop will work on merging at the hinted level. + */ + if( rc==SQLITE_OK && hint.n ){ + int nHint = hint.n; + sqlite3_int64 iHintAbsLevel = 0; /* Hint level */ + int nHintSeg = 0; /* Hint number of segments */ -typedef struct simple_tokenizer_cursor { - sqlite3_tokenizer_cursor base; - const char *pInput; /* input we are tokenizing */ - int nBytes; /* size of the input */ - int iOffset; /* current position in pInput */ - int iToken; /* index of next token to be returned */ - char *pToken; /* storage for current token */ - int nTokenAllocated; /* space allocated to zToken buffer */ -} simple_tokenizer_cursor; + rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg); + if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){ + /* Based on the scan in the block above, it is known that there + ** are no levels with a relative level smaller than that of + ** iAbsLevel with more than nSeg segments, or if nSeg is -1, + ** no levels with more than nMin segments. Use this to limit the + ** value of nHintSeg to avoid a large memory allocation in case the + ** merge-hint is corrupt*/ + iAbsLevel = iHintAbsLevel; + nSeg = MIN(MAX(nMin,nSeg), nHintSeg); + bUseHint = 1; + bDirtyHint = 1; + }else{ + /* This undoes the effect of the HintPop() above - so that no entry + ** is removed from the hint blob. */ + hint.n = nHint; + } + } + /* If nSeg is less that zero, then there is no level with at least + ** nMin segments and no hint in the %_stat table. No work to do. + ** Exit early in this case. */ + if( nSeg<=0 ) break; -static int simpleDelim(simple_tokenizer *t, unsigned char c){ - return c<0x80 && t->delim[c]; -} -static int fts3_isalnum(int x){ - return (x>='0' && x<='9') || (x>='A' && x<='Z') || (x>='a' && x<='z'); -} + assert( nMod<=0x7FFFFFFF ); + if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){ + rc = FTS_CORRUPT_VTAB; + break; + } -/* -** Create a new tokenizer instance. -*/ -static int simpleCreate( - int argc, const char * const *argv, - sqlite3_tokenizer **ppTokenizer -){ - simple_tokenizer *t; + /* Open a cursor to iterate through the contents of the oldest nSeg + ** indexes of absolute level iAbsLevel. If this cursor is opened using + ** the 'hint' parameters, it is possible that there are less than nSeg + ** segments available in level iAbsLevel. In this case, no work is + ** done on iAbsLevel - fall through to the next iteration of the loop + ** to start work on some other level. */ + memset(pWriter, 0, nAlloc); + pFilter->flags = FTS3_SEGMENT_REQUIRE_POS; - t = (simple_tokenizer *) sqlite3_malloc(sizeof(*t)); - if( t==NULL ) return SQLITE_NOMEM; - memset(t, 0, sizeof(*t)); + if( rc==SQLITE_OK ){ + rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); + assert( bUseHint==1 || bUseHint==0 ); + if( iIdx==0 || (bUseHint && iIdx==1) ){ + int bIgnore = 0; + rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore); + if( bIgnore ){ + pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY; + } + } + } - /* TODO(shess) Delimiters need to remain the same from run to run, - ** else we need to reindex. One solution would be a meta-table to - ** track such information in the database, then we'd only want this - ** information on the initial create. - */ - if( argc>1 ){ - int i, n = (int)strlen(argv[1]); - for(i=0; i=0x80 ){ - sqlite3_free(t); - return SQLITE_ERROR; + if( rc==SQLITE_OK ){ + rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); + } + if( SQLITE_OK==rc && pCsr->nSegment==nSeg + && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) + ){ + int bEmpty = 0; + rc = sqlite3Fts3SegReaderStep(p, pCsr); + if( rc==SQLITE_OK ){ + bEmpty = 1; + }else if( rc!=SQLITE_ROW ){ + sqlite3Fts3SegReaderFinish(pCsr); + break; + } + if( bUseHint && iIdx>0 ){ + const char *zKey = pCsr->zTerm; + int nKey = pCsr->nTerm; + rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); + }else{ + rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); + } + + if( rc==SQLITE_OK && pWriter->nLeafEst ){ + fts3LogMerge(nSeg, iAbsLevel); + if( bEmpty==0 ){ + do { + rc = fts3IncrmergeAppend(p, pWriter, pCsr); + if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr); + if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK; + }while( rc==SQLITE_ROW ); + } + + /* Update or delete the input segments */ + if( rc==SQLITE_OK ){ + nRem -= (1 + pWriter->nWork); + rc = fts3IncrmergeChomp(p, iAbsLevel, pCsr, &nSeg); + if( nSeg!=0 ){ + bDirtyHint = 1; + fts3IncrmergeHintPush(&hint, iAbsLevel, nSeg, &rc); + } + } + } + + if( nSeg!=0 ){ + pWriter->nLeafData = pWriter->nLeafData * -1; + } + fts3IncrmergeRelease(p, pWriter, &rc); + if( nSeg==0 && pWriter->bNoLeafData==0 ){ + fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData); } - t->delim[ch] = 1; - } - } else { - /* Mark non-alphanumeric ASCII characters as delimiters */ - int i; - for(i=1; i<0x80; i++){ - t->delim[i] = !fts3_isalnum(i) ? -1 : 0; } + + sqlite3Fts3SegReaderFinish(pCsr); } - *ppTokenizer = &t->base; - return SQLITE_OK; + /* Write the hint values into the %_stat table for the next incr-merger */ + if( bDirtyHint && rc==SQLITE_OK ){ + rc = fts3IncrmergeHintStore(p, &hint); + } + + sqlite3_free(pWriter); + sqlite3_free(hint.a); + return rc; } /* -** Destroy a tokenizer +** Convert the text beginning at *pz into an integer and return +** its value. Advance *pz to point to the first character past +** the integer. +** +** This function used for parameters to merge= and incrmerge= +** commands. */ -static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ - sqlite3_free(pTokenizer); - return SQLITE_OK; +static int fts3Getint(const char **pz){ + const char *z = *pz; + int i = 0; + while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0'; + *pz = z; + return i; } /* -** Prepare to begin tokenizing a particular string. The input -** string to be tokenized is pInput[0..nBytes-1]. A cursor -** used to incrementally tokenize this string is returned in -** *ppCursor. +** Process statements of the form: +** +** INSERT INTO table(table) VALUES('merge=A,B'); +** +** A and B are integers that decode to be the number of leaf pages +** written for the merge, and the minimum number of segments on a level +** before it will be selected for a merge, respectively. */ -static int simpleOpen( - sqlite3_tokenizer *pTokenizer, /* The tokenizer */ - const char *pInput, int nBytes, /* String to be tokenized */ - sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ +static int fts3DoIncrmerge( + Fts3Table *p, /* FTS3 table handle */ + const char *zParam /* Nul-terminated string containing "A,B" */ ){ - simple_tokenizer_cursor *c; + int rc; + int nMin = (MergeCount(p) / 2); + int nMerge = 0; + const char *z = zParam; - UNUSED_PARAMETER(pTokenizer); + /* Read the first integer value */ + nMerge = fts3Getint(&z); - c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); - if( c==NULL ) return SQLITE_NOMEM; + /* If the first integer value is followed by a ',', read the second + ** integer value. */ + if( z[0]==',' && z[1]!='\0' ){ + z++; + nMin = fts3Getint(&z); + } - c->pInput = pInput; - if( pInput==0 ){ - c->nBytes = 0; - }else if( nBytes<0 ){ - c->nBytes = (int)strlen(pInput); + if( z[0]!='\0' || nMin<2 ){ + rc = SQLITE_ERROR; }else{ - c->nBytes = nBytes; + rc = SQLITE_OK; + if( !p->bHasStat ){ + assert( p->bFts4==0 ); + sqlite3Fts3CreateStatTable(&rc, p); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3Incrmerge(p, nMerge, nMin); + } + sqlite3Fts3SegmentsClose(p); } - c->iOffset = 0; /* start tokenizing at the beginning */ - c->iToken = 0; - c->pToken = NULL; /* no space allocated, yet. */ - c->nTokenAllocated = 0; + return rc; +} - *ppCursor = &c->base; - return SQLITE_OK; +/* +** Process statements of the form: +** +** INSERT INTO table(table) VALUES('automerge=X'); +** +** where X is an integer. X==0 means to turn automerge off. X!=0 means +** turn it on. The setting is persistent. +*/ +static int fts3DoAutoincrmerge( + Fts3Table *p, /* FTS3 table handle */ + const char *zParam /* Nul-terminated string containing boolean */ +){ + int rc = SQLITE_OK; + sqlite3_stmt *pStmt = 0; + p->nAutoincrmerge = fts3Getint(&zParam); + if( p->nAutoincrmerge==1 || p->nAutoincrmerge>MergeCount(p) ){ + p->nAutoincrmerge = 8; + } + if( !p->bHasStat ){ + assert( p->bFts4==0 ); + sqlite3Fts3CreateStatTable(&rc, p); + if( rc ) return rc; + } + rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); + if( rc ) return rc; + sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); + sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + return rc; } /* -** Close a tokenization cursor previously opened by a call to -** simpleOpen() above. +** Return a 64-bit checksum for the FTS index entry specified by the +** arguments to this function. */ -static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ - simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; - sqlite3_free(c->pToken); - sqlite3_free(c); - return SQLITE_OK; +static u64 fts3ChecksumEntry( + const char *zTerm, /* Pointer to buffer containing term */ + int nTerm, /* Size of zTerm in bytes */ + int iLangid, /* Language id for current row */ + int iIndex, /* Index (0..Fts3Table.nIndex-1) */ + i64 iDocid, /* Docid for current row. */ + int iCol, /* Column number */ + int iPos /* Position */ +){ + int i; + u64 ret = (u64)iDocid; + + ret += (ret<<3) + iLangid; + ret += (ret<<3) + iIndex; + ret += (ret<<3) + iCol; + ret += (ret<<3) + iPos; + for(i=0; inIndex-1) */ + int *pRc /* OUT: Return code */ ){ - simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; - simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; - unsigned char *p = (unsigned char *)c->pInput; + Fts3SegFilter filter; + Fts3MultiSegReader csr; + int rc; + u64 cksum = 0; - while( c->iOffsetnBytes ){ - int iStartOffset; + assert( *pRc==SQLITE_OK ); - /* Scan past delimiter characters */ - while( c->iOffsetnBytes && simpleDelim(t, p[c->iOffset]) ){ - c->iOffset++; - } + memset(&filter, 0, sizeof(filter)); + memset(&csr, 0, sizeof(csr)); + filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; + filter.flags |= FTS3_SEGMENT_SCAN; - /* Count non-delimiter characters. */ - iStartOffset = c->iOffset; - while( c->iOffsetnBytes && !simpleDelim(t, p[c->iOffset]) ){ - c->iOffset++; - } + rc = sqlite3Fts3SegReaderCursor( + p, iLangid, iIndex, FTS3_SEGCURSOR_ALL, 0, 0, 0, 1,&csr + ); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); + } - if( c->iOffset>iStartOffset ){ - int i, n = c->iOffset-iStartOffset; - if( n>c->nTokenAllocated ){ - char *pNew; - c->nTokenAllocated = n+20; - pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); - if( !pNew ) return SQLITE_NOMEM; - c->pToken = pNew; - } - for(i=0; ipToken[i] = (char)((ch>='A' && ch<='Z') ? ch-'A'+'a' : ch); - } - *ppToken = c->pToken; - *pnBytes = n; - *piStartOffset = iStartOffset; - *piEndOffset = c->iOffset; - *piPosition = c->iToken++; + if( rc==SQLITE_OK ){ + while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){ + char *pCsr = csr.aDoclist; + char *pEnd = &pCsr[csr.nDoclist]; - return SQLITE_OK; + i64 iDocid = 0; + i64 iCol = 0; + u64 iPos = 0; + + pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid); + while( pCsrbDescIdx ){ + iDocid = (i64)((u64)iDocid - iVal); + }else{ + iDocid = (i64)((u64)iDocid + iVal); + } + } + }else{ + iPos += (iVal - 2); + cksum = cksum ^ fts3ChecksumEntry( + csr.zTerm, csr.nTerm, iLangid, iIndex, iDocid, + (int)iCol, (int)iPos + ); + } + } + } } } - return SQLITE_DONE; + sqlite3Fts3SegReaderFinish(&csr); + + *pRc = rc; + return cksum; } /* -** The set of routines that implement the simple tokenizer +** Check if the contents of the FTS index match the current contents of the +** content table. If no error occurs and the contents do match, set *pbOk +** to true and return SQLITE_OK. Or if the contents do not match, set *pbOk +** to false before returning. +** +** If an error occurs (e.g. an OOM or IO error), return an SQLite error +** code. The final value of *pbOk is undefined in this case. */ -static const sqlite3_tokenizer_module simpleTokenizerModule = { - 0, - simpleCreate, - simpleDestroy, - simpleOpen, - simpleClose, - simpleNext, - 0, -}; +static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){ + int rc = SQLITE_OK; /* Return code */ + u64 cksum1 = 0; /* Checksum based on FTS index contents */ + u64 cksum2 = 0; /* Checksum based on %_content contents */ + sqlite3_stmt *pAllLangid = 0; /* Statement to return all language-ids */ -/* -** Allocate a new simple tokenizer. Return a pointer to the new -** tokenizer in *ppModule -*/ -SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule( - sqlite3_tokenizer_module const**ppModule -){ - *ppModule = &simpleTokenizerModule; -} + /* This block calculates the checksum according to the FTS index. */ + rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); + if( rc==SQLITE_OK ){ + int rc2; + sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); + sqlite3_bind_int(pAllLangid, 2, p->nIndex); + while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){ + int iLangid = sqlite3_column_int(pAllLangid, 0); + int i; + for(i=0; inIndex; i++){ + cksum1 = cksum1 ^ fts3ChecksumIndex(p, iLangid, i, &rc); + } + } + rc2 = sqlite3_reset(pAllLangid); + if( rc==SQLITE_OK ) rc = rc2; + } -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ + /* This block calculates the checksum according to the %_content table */ + if( rc==SQLITE_OK ){ + sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule; + sqlite3_stmt *pStmt = 0; + char *zSql; + + zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + i64 iDocid = sqlite3_column_int64(pStmt, 0); + int iLang = langidFromSelect(p, pStmt); + int iCol; + + for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ + if( p->abNotindexed[iCol]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); + sqlite3_tokenizer_cursor *pT = 0; + + rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, -1, &pT); + while( rc==SQLITE_OK ){ + char const *zToken; /* Buffer containing token */ + int nToken = 0; /* Number of bytes in token */ + int iDum1 = 0, iDum2 = 0; /* Dummy variables */ + int iPos = 0; /* Position of token in zText */ + + rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); + if( rc==SQLITE_OK ){ + int i; + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, nToken, iLang, 0, iDocid, iCol, iPos + ); + for(i=1; inIndex; i++){ + if( p->aIndex[i].nPrefix<=nToken ){ + cksum2 = cksum2 ^ fts3ChecksumEntry( + zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos + ); + } + } + } + } + if( pT ) pModule->xClose(pT); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } + } + } + + sqlite3_finalize(pStmt); + } + + *pbOk = (cksum1==cksum2); + return rc; +} -/************** End of fts3_tokenizer1.c *************************************/ -/************** Begin file fts3_tokenize_vtab.c ******************************/ /* -** 2013 Apr 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains code for the "fts3tokenize" virtual table module. -** An fts3tokenize virtual table is created as follows: -** -** CREATE VIRTUAL TABLE USING fts3tokenize( -** , , ... -** ); +** Run the integrity-check. If no error occurs and the current contents of +** the FTS index are correct, return SQLITE_OK. Or, if the contents of the +** FTS index are incorrect, return SQLITE_CORRUPT_VTAB. ** -** The table created has the following schema: +** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite +** error code. ** -** CREATE TABLE (input, token, start, end, position) +** The integrity-check works as follows. For each token and indexed token +** prefix in the document set, a 64-bit checksum is calculated (by code +** in fts3ChecksumEntry()) based on the following: ** -** When queried, the query must include a WHERE clause of type: +** + The index number (0 for the main index, 1 for the first prefix +** index etc.), +** + The token (or token prefix) text itself, +** + The language-id of the row it appears in, +** + The docid of the row it appears in, +** + The column it appears in, and +** + The tokens position within that column. ** -** input = +** The checksums for all entries in the index are XORed together to create +** a single checksum for the entire index. ** -** The virtual table module tokenizes this , using the FTS3 -** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE -** statement and returns one row for each token in the result. With -** fields set as follows: +** The integrity-check code calculates the same checksum in two ways: ** -** input: Always set to a copy of -** token: A token from the input. -** start: Byte offset of the token within the input . -** end: Byte offset of the byte immediately following the end of the -** token within the input string. -** pos: Token offset of token within input. +** 1. By scanning the contents of the FTS index, and +** 2. By scanning and tokenizing the content table. ** +** If the two checksums are identical, the integrity-check is deemed to have +** passed. */ -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -/* #include */ -/* #include */ - -typedef struct Fts3tokTable Fts3tokTable; -typedef struct Fts3tokCursor Fts3tokCursor; +static int fts3DoIntegrityCheck( + Fts3Table *p /* FTS3 table handle */ +){ + int rc; + int bOk = 0; + rc = fts3IntegrityCheck(p, &bOk); + if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB; + return rc; +} /* -** Virtual table structure. +** Handle a 'special' INSERT of the form: +** +** "INSERT INTO tbl(tbl) VALUES()" +** +** Argument pVal contains the result of . Currently the only +** meaningful value to insert is the text 'optimize'. */ -struct Fts3tokTable { - sqlite3_vtab base; /* Base class used by SQLite core */ - const sqlite3_tokenizer_module *pMod; - sqlite3_tokenizer *pTok; -}; +static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ + int rc = SQLITE_ERROR; /* Return Code */ + const char *zVal = (const char *)sqlite3_value_text(pVal); + int nVal = sqlite3_value_bytes(pVal); + + if( !zVal ){ + return SQLITE_NOMEM; + }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ + rc = fts3DoOptimize(p, 0); + }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ + rc = fts3DoRebuild(p); + }else if( nVal==15 && 0==sqlite3_strnicmp(zVal, "integrity-check", 15) ){ + rc = fts3DoIntegrityCheck(p); + }else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){ + rc = fts3DoIncrmerge(p, &zVal[6]); + }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){ + rc = fts3DoAutoincrmerge(p, &zVal[10]); +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + }else{ + int v; + if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ + v = atoi(&zVal[9]); + if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v; + rc = SQLITE_OK; + }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ + v = atoi(&zVal[11]); + if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v; + rc = SQLITE_OK; + }else if( nVal>21 && 0==sqlite3_strnicmp(zVal,"test-no-incr-doclist=",21) ){ + p->bNoIncrDoclist = atoi(&zVal[21]); + rc = SQLITE_OK; + }else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){ + v = atoi(&zVal[11]); + if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v; + rc = SQLITE_OK; + } +#endif + } + return rc; +} +#ifndef SQLITE_DISABLE_FTS4_DEFERRED /* -** Virtual table cursor structure. +** Delete all cached deferred doclists. Deferred doclists are cached +** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function. */ -struct Fts3tokCursor { - sqlite3_vtab_cursor base; /* Base class used by SQLite core */ - char *zInput; /* Input string */ - sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */ - int iRowid; /* Current 'rowid' value */ - const char *zToken; /* Current 'token' value */ - int nToken; /* Size of zToken in bytes */ - int iStart; /* Current 'start' value */ - int iEnd; /* Current 'end' value */ - int iPos; /* Current 'pos' value */ -}; +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){ + Fts3DeferredToken *pDef; + for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){ + fts3PendingListDelete(pDef->pList); + pDef->pList = 0; + } +} /* -** Query FTS for the tokenizer implementation named zName. +** Free all entries in the pCsr->pDeffered list. Entries are added to +** this list using sqlite3Fts3DeferToken(). */ -static int fts3tokQueryTokenizer( - Fts3Hash *pHash, - const char *zName, - const sqlite3_tokenizer_module **pp, - char **pzErr -){ - sqlite3_tokenizer_module *p; - int nName = (int)strlen(zName); - - p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1); - if( !p ){ - sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer: %s", zName); - return SQLITE_ERROR; +SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){ + Fts3DeferredToken *pDef; + Fts3DeferredToken *pNext; + for(pDef=pCsr->pDeferred; pDef; pDef=pNext){ + pNext = pDef->pNext; + fts3PendingListDelete(pDef->pList); + sqlite3_free(pDef); } - - *pp = p; - return SQLITE_OK; + pCsr->pDeferred = 0; } /* -** The second argument, argv[], is an array of pointers to nul-terminated -** strings. This function makes a copy of the array and strings into a -** single block of memory. It then dequotes any of the strings that appear -** to be quoted. +** Generate deferred-doclists for all tokens in the pCsr->pDeferred list +** based on the row that pCsr currently points to. ** -** If successful, output parameter *pazDequote is set to point at the -** array of dequoted strings and SQLITE_OK is returned. The caller is -** responsible for eventually calling sqlite3_free() to free the array -** in this case. Or, if an error occurs, an SQLite error code is returned. -** The final value of *pazDequote is undefined in this case. +** A deferred-doclist is like any other doclist with position information +** included, except that it only contains entries for a single row of the +** table, not for all rows. */ -static int fts3tokDequoteArray( - int argc, /* Number of elements in argv[] */ - const char * const *argv, /* Input array */ - char ***pazDequote /* Output array */ -){ +SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){ int rc = SQLITE_OK; /* Return code */ - if( argc==0 ){ - *pazDequote = 0; - }else{ - int i; - int nByte = 0; - char **azDequote; + if( pCsr->pDeferred ){ + int i; /* Used to iterate through table columns */ + sqlite3_int64 iDocid; /* Docid of the row pCsr points to */ + Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */ - for(i=0; ibase.pVtab; + sqlite3_tokenizer *pT = p->pTokenizer; + sqlite3_tokenizer_module const *pModule = pT->pModule; + + assert( pCsr->isRequireSeek==0 ); + iDocid = sqlite3_column_int64(pCsr->pStmt, 0); + + for(i=0; inColumn && rc==SQLITE_OK; i++){ + if( p->abNotindexed[i]==0 ){ + const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1); + sqlite3_tokenizer_cursor *pTC = 0; + + rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC); + while( rc==SQLITE_OK ){ + char const *zToken; /* Buffer containing token */ + int nToken = 0; /* Number of bytes in token */ + int iDum1 = 0, iDum2 = 0; /* Dummy variables */ + int iPos = 0; /* Position of token in zText */ + + rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); + for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ + Fts3PhraseToken *pPT = pDef->pToken; + if( (pDef->iCol>=p->nColumn || pDef->iCol==i) + && (pPT->bFirst==0 || iPos==0) + && (pPT->n==nToken || (pPT->isPrefix && pPT->nz, pPT->n)) + ){ + fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); + } + } + } + if( pTC ) pModule->xClose(pTC); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + } } - *pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte); - if( azDequote==0 ){ - rc = SQLITE_NOMEM; - }else{ - char *pSpace = (char *)&azDequote[argc]; - for(i=0; ipDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ + if( pDef->pList ){ + rc = fts3PendingListAppendVarint(&pDef->pList, 0); } } } @@ -154465,321 +190355,278 @@ static int fts3tokDequoteArray( return rc; } -/* -** Schema of the tokenizer table. -*/ -#define FTS3_TOK_SCHEMA "CREATE TABLE x(input, token, start, end, position)" - -/* -** This function does all the work for both the xConnect and xCreate methods. -** These tables have no persistent representation of their own, so xConnect -** and xCreate are identical operations. -** -** argv[0]: module name -** argv[1]: database name -** argv[2]: table name -** argv[3]: first argument (tokenizer name) -*/ -static int fts3tokConnectMethod( - sqlite3 *db, /* Database connection */ - void *pHash, /* Hash table of tokenizers */ - int argc, /* Number of elements in argv array */ - const char * const *argv, /* xCreate/xConnect argument array */ - sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ - char **pzErr /* OUT: sqlite3_malloc'd error message */ +SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList( + Fts3DeferredToken *p, + char **ppData, + int *pnData ){ - Fts3tokTable *pTab = 0; - const sqlite3_tokenizer_module *pMod = 0; - sqlite3_tokenizer *pTok = 0; - int rc; - char **azDequote = 0; - int nDequote; - - rc = sqlite3_declare_vtab(db, FTS3_TOK_SCHEMA); - if( rc!=SQLITE_OK ) return rc; - - nDequote = argc-3; - rc = fts3tokDequoteArray(nDequote, &argv[3], &azDequote); - - if( rc==SQLITE_OK ){ - const char *zModule; - if( nDequote<1 ){ - zModule = "simple"; - }else{ - zModule = azDequote[0]; - } - rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr); - } - - assert( (rc==SQLITE_OK)==(pMod!=0) ); - if( rc==SQLITE_OK ){ - const char * const *azArg = (const char * const *)&azDequote[1]; - rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok); - } + char *pRet; + int nSkip; + sqlite3_int64 dummy; - if( rc==SQLITE_OK ){ - pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable)); - if( pTab==0 ){ - rc = SQLITE_NOMEM; - } - } + *ppData = 0; + *pnData = 0; - if( rc==SQLITE_OK ){ - memset(pTab, 0, sizeof(Fts3tokTable)); - pTab->pMod = pMod; - pTab->pTok = pTok; - *ppVtab = &pTab->base; - }else{ - if( pTok ){ - pMod->xDestroy(pTok); - } + if( p->pList==0 ){ + return SQLITE_OK; } - sqlite3_free(azDequote); - return rc; -} + pRet = (char *)sqlite3_malloc(p->pList->nData); + if( !pRet ) return SQLITE_NOMEM; -/* -** This function does the work for both the xDisconnect and xDestroy methods. -** These tables have no persistent representation of their own, so xDisconnect -** and xDestroy are identical operations. -*/ -static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){ - Fts3tokTable *pTab = (Fts3tokTable *)pVtab; + nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); + *pnData = p->pList->nData - nSkip; + *ppData = pRet; - pTab->pMod->xDestroy(pTab->pTok); - sqlite3_free(pTab); + memcpy(pRet, &p->pList->aData[nSkip], *pnData); return SQLITE_OK; } /* -** xBestIndex - Analyze a WHERE and ORDER BY clause. +** Add an entry for token pToken to the pCsr->pDeferred list. */ -static int fts3tokBestIndexMethod( - sqlite3_vtab *pVTab, - sqlite3_index_info *pInfo +SQLITE_PRIVATE int sqlite3Fts3DeferToken( + Fts3Cursor *pCsr, /* Fts3 table cursor */ + Fts3PhraseToken *pToken, /* Token to defer */ + int iCol /* Column that token must appear in (or -1) */ ){ - int i; - UNUSED_PARAMETER(pVTab); - - for(i=0; inConstraint; i++){ - if( pInfo->aConstraint[i].usable - && pInfo->aConstraint[i].iColumn==0 - && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ - ){ - pInfo->idxNum = 1; - pInfo->aConstraintUsage[i].argvIndex = 1; - pInfo->aConstraintUsage[i].omit = 1; - pInfo->estimatedCost = 1; - return SQLITE_OK; - } + Fts3DeferredToken *pDeferred; + pDeferred = sqlite3_malloc(sizeof(*pDeferred)); + if( !pDeferred ){ + return SQLITE_NOMEM; } + memset(pDeferred, 0, sizeof(*pDeferred)); + pDeferred->pToken = pToken; + pDeferred->pNext = pCsr->pDeferred; + pDeferred->iCol = iCol; + pCsr->pDeferred = pDeferred; - pInfo->idxNum = 0; - assert( pInfo->estimatedCost>1000000.0 ); + assert( pToken->pDeferred==0 ); + pToken->pDeferred = pDeferred; return SQLITE_OK; } +#endif /* -** xOpen - Open a cursor. +** SQLite value pRowid contains the rowid of a row that may or may not be +** present in the FTS3 table. If it is, delete it and adjust the contents +** of subsiduary data structures accordingly. */ -static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ - Fts3tokCursor *pCsr; - UNUSED_PARAMETER(pVTab); +static int fts3DeleteByRowid( + Fts3Table *p, + sqlite3_value *pRowid, + int *pnChng, /* IN/OUT: Decrement if row is deleted */ + u32 *aSzDel +){ + int rc = SQLITE_OK; /* Return code */ + int bFound = 0; /* True if *pRowid really is in the table */ - pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor)); - if( pCsr==0 ){ - return SQLITE_NOMEM; + fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound); + if( bFound && rc==SQLITE_OK ){ + int isEmpty = 0; /* Deleting *pRowid leaves the table empty */ + rc = fts3IsEmpty(p, pRowid, &isEmpty); + if( rc==SQLITE_OK ){ + if( isEmpty ){ + /* Deleting this row means the whole table is empty. In this case + ** delete the contents of all three tables and throw away any + ** data in the pendingTerms hash table. */ + rc = fts3DeleteAll(p, 1); + *pnChng = 0; + memset(aSzDel, 0, sizeof(u32) * (p->nColumn+1) * 2); + }else{ + *pnChng = *pnChng - 1; + if( p->zContentTbl==0 ){ + fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); + } + if( p->bHasDocsize ){ + fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); + } + } + } } - memset(pCsr, 0, sizeof(Fts3tokCursor)); - *ppCsr = (sqlite3_vtab_cursor *)pCsr; - return SQLITE_OK; + return rc; } /* -** Reset the tokenizer cursor passed as the only argument. As if it had -** just been returned by fts3tokOpenMethod(). +** This function does the work for the xUpdate method of FTS3 virtual +** tables. The schema of the virtual table being: +** +** CREATE TABLE
            ( +** , +**
            HIDDEN, +** docid HIDDEN, +** HIDDEN +** ); +** +** */ -static void fts3tokResetCursor(Fts3tokCursor *pCsr){ - if( pCsr->pCsr ){ - Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab); - pTab->pMod->xClose(pCsr->pCsr); - pCsr->pCsr = 0; - } - sqlite3_free(pCsr->zInput); - pCsr->zInput = 0; - pCsr->zToken = 0; - pCsr->nToken = 0; - pCsr->iStart = 0; - pCsr->iEnd = 0; - pCsr->iPos = 0; - pCsr->iRowid = 0; -} +SQLITE_PRIVATE int sqlite3Fts3UpdateMethod( + sqlite3_vtab *pVtab, /* FTS3 vtab object */ + int nArg, /* Size of argument array */ + sqlite3_value **apVal, /* Array of arguments */ + sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ +){ + Fts3Table *p = (Fts3Table *)pVtab; + int rc = SQLITE_OK; /* Return Code */ + u32 *aSzIns = 0; /* Sizes of inserted documents */ + u32 *aSzDel = 0; /* Sizes of deleted documents */ + int nChng = 0; /* Net change in number of documents */ + int bInsertDone = 0; -/* -** xClose - Close a cursor. -*/ -static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + /* At this point it must be known if the %_stat table exists or not. + ** So bHasStat may not be 2. */ + assert( p->bHasStat==0 || p->bHasStat==1 ); - fts3tokResetCursor(pCsr); - sqlite3_free(pCsr); - return SQLITE_OK; -} + assert( p->pSegments==0 ); + assert( + nArg==1 /* DELETE operations */ + || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */ + ); -/* -** xNext - Advance the cursor to the next row, if any. -*/ -static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); - int rc; /* Return code */ + /* Check for a "special" INSERT operation. One of the form: + ** + ** INSERT INTO xyz(xyz) VALUES('command'); + */ + if( nArg>1 + && sqlite3_value_type(apVal[0])==SQLITE_NULL + && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL + ){ + rc = fts3SpecialInsert(p, apVal[p->nColumn+2]); + goto update_out; + } - pCsr->iRowid++; - rc = pTab->pMod->xNext(pCsr->pCsr, - &pCsr->zToken, &pCsr->nToken, - &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos - ); + if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){ + rc = SQLITE_CONSTRAINT; + goto update_out; + } - if( rc!=SQLITE_OK ){ - fts3tokResetCursor(pCsr); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; + /* Allocate space to hold the change in document sizes */ + aSzDel = sqlite3_malloc64(sizeof(aSzDel[0])*((sqlite3_int64)p->nColumn+1)*2); + if( aSzDel==0 ){ + rc = SQLITE_NOMEM; + goto update_out; } + aSzIns = &aSzDel[p->nColumn+1]; + memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2); - return rc; -} + rc = fts3Writelock(p); + if( rc!=SQLITE_OK ) goto update_out; -/* -** xFilter - Initialize a cursor to point at the start of its data. -*/ -static int fts3tokFilterMethod( - sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ - int idxNum, /* Strategy index */ - const char *idxStr, /* Unused */ - int nVal, /* Number of elements in apVal */ - sqlite3_value **apVal /* Arguments for the indexing scheme */ -){ - int rc = SQLITE_ERROR; - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab); - UNUSED_PARAMETER(idxStr); - UNUSED_PARAMETER(nVal); + /* If this is an INSERT operation, or an UPDATE that modifies the rowid + ** value, then this operation requires constraint handling. + ** + ** If the on-conflict mode is REPLACE, this means that the existing row + ** should be deleted from the database before inserting the new row. Or, + ** if the on-conflict mode is other than REPLACE, then this method must + ** detect the conflict and return SQLITE_CONSTRAINT before beginning to + ** modify the database file. + */ + if( nArg>1 && p->zContentTbl==0 ){ + /* Find the value object that holds the new rowid value. */ + sqlite3_value *pNewRowid = apVal[3+p->nColumn]; + if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ + pNewRowid = apVal[1]; + } - fts3tokResetCursor(pCsr); - if( idxNum==1 ){ - const char *zByte = (const char *)sqlite3_value_text(apVal[0]); - int nByte = sqlite3_value_bytes(apVal[0]); - pCsr->zInput = sqlite3_malloc(nByte+1); - if( pCsr->zInput==0 ){ - rc = SQLITE_NOMEM; - }else{ - memcpy(pCsr->zInput, zByte, nByte); - pCsr->zInput[nByte] = 0; - rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr); - if( rc==SQLITE_OK ){ - pCsr->pCsr->pTokenizer = pTab->pTok; + if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( + sqlite3_value_type(apVal[0])==SQLITE_NULL + || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) + )){ + /* The new rowid is not NULL (in this case the rowid will be + ** automatically assigned and there is no chance of a conflict), and + ** the statement is either an INSERT or an UPDATE that modifies the + ** rowid column. So if the conflict mode is REPLACE, then delete any + ** existing row with rowid=pNewRowid. + ** + ** Or, if the conflict mode is not REPLACE, insert the new record into + ** the %_content table. If we hit the duplicate rowid constraint (or any + ** other error) while doing so, return immediately. + ** + ** This branch may also run if pNewRowid contains a value that cannot + ** be losslessly converted to an integer. In this case, the eventual + ** call to fts3InsertData() (either just below or further on in this + ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is + ** invoked, it will delete zero rows (since no row will have + ** docid=$pNewRowid if $pNewRowid is not an integer value). + */ + if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ + rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); + }else{ + rc = fts3InsertData(p, apVal, pRowid); + bInsertDone = 1; } } } + if( rc!=SQLITE_OK ){ + goto update_out; + } - if( rc!=SQLITE_OK ) return rc; - return fts3tokNextMethod(pCursor); -} - -/* -** xEof - Return true if the cursor is at EOF, or false otherwise. -*/ -static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - return (pCsr->zToken==0); -} + /* If this is a DELETE or UPDATE operation, remove the old record. */ + if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ + assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); + rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); + } -/* -** xColumn - Return a column value. -*/ -static int fts3tokColumnMethod( - sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ - sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ - int iCol /* Index of column to read value from */ -){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; + /* If this is an INSERT or UPDATE operation, insert the new record. */ + if( nArg>1 && rc==SQLITE_OK ){ + int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]); + if( bInsertDone==0 ){ + rc = fts3InsertData(p, apVal, pRowid); + if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ + rc = FTS_CORRUPT_VTAB; + } + } + if( rc==SQLITE_OK ){ + rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid); + } + if( rc==SQLITE_OK ){ + assert( p->iPrevDocid==*pRowid ); + rc = fts3InsertTerms(p, iLangid, apVal, aSzIns); + } + if( p->bHasDocsize ){ + fts3InsertDocsize(&rc, p, aSzIns); + } + nChng++; + } - /* CREATE TABLE x(input, token, start, end, position) */ - switch( iCol ){ - case 0: - sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT); - break; - case 1: - sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT); - break; - case 2: - sqlite3_result_int(pCtx, pCsr->iStart); - break; - case 3: - sqlite3_result_int(pCtx, pCsr->iEnd); - break; - default: - assert( iCol==4 ); - sqlite3_result_int(pCtx, pCsr->iPos); - break; + if( p->bFts4 ){ + fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng); } - return SQLITE_OK; -} -/* -** xRowid - Return the current rowid for the cursor. -*/ -static int fts3tokRowidMethod( - sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ - sqlite_int64 *pRowid /* OUT: Rowid value */ -){ - Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor; - *pRowid = (sqlite3_int64)pCsr->iRowid; - return SQLITE_OK; + update_out: + sqlite3_free(aSzDel); + sqlite3Fts3SegmentsClose(p); + return rc; } -/* -** Register the fts3tok module with database connection db. Return SQLITE_OK -** if successful or an error code if sqlite3_create_module() fails. -*/ -SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ - static const sqlite3_module fts3tok_module = { - 0, /* iVersion */ - fts3tokConnectMethod, /* xCreate */ - fts3tokConnectMethod, /* xConnect */ - fts3tokBestIndexMethod, /* xBestIndex */ - fts3tokDisconnectMethod, /* xDisconnect */ - fts3tokDisconnectMethod, /* xDestroy */ - fts3tokOpenMethod, /* xOpen */ - fts3tokCloseMethod, /* xClose */ - fts3tokFilterMethod, /* xFilter */ - fts3tokNextMethod, /* xNext */ - fts3tokEofMethod, /* xEof */ - fts3tokColumnMethod, /* xColumn */ - fts3tokRowidMethod, /* xRowid */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindFunction */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ - }; - int rc; /* Return code */ - - rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash); +/* +** Flush any data in the pending-terms hash table to disk. If successful, +** merge all segments in the database (including the new segment, if +** there was any data to flush) into a single segment. +*/ +SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){ + int rc; + rc = sqlite3_exec(p->db, "SAVEPOINT fts3", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = fts3DoOptimize(p, 1); + if( rc==SQLITE_OK || rc==SQLITE_DONE ){ + int rc2 = sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); + if( rc2!=SQLITE_OK ) rc = rc2; + }else{ + sqlite3_exec(p->db, "ROLLBACK TO fts3", 0, 0, 0); + sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); + } + } + sqlite3Fts3SegmentsClose(p); return rc; } -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ +#endif -/************** End of fts3_tokenize_vtab.c **********************************/ -/************** Begin file fts3_write.c **************************************/ +/************** End of fts3_write.c ******************************************/ +/************** Begin file fts3_snippet.c ************************************/ /* ** 2009 Oct 23 ** @@ -154791,12 +190638,6 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ ** May you share freely, never taking more than you give. ** ****************************************************************************** -** -** This file is part of the SQLite FTS3 extension module. Specifically, -** this file contains code to insert, update and delete rows from FTS3 -** tables. It also contains code to merge FTS3 b-tree segments. Some -** of the sub-routines used to merge segments are also used by the query -** code in fts3.c. */ /* #include "fts3Int.h" */ @@ -154804,5665 +190645,5208 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ /* #include */ /* #include */ -/* #include */ - - -#define FTS_MAX_APPENDABLE_HEIGHT 16 -/* -** When full-text index nodes are loaded from disk, the buffer that they -** are loaded into has the following number of bytes of padding at the end -** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer -** of 920 bytes is allocated for it. -** -** This means that if we have a pointer into a buffer containing node data, -** it is always safe to read up to two varints from it without risking an -** overread, even if the node data is corrupted. -*/ -#define FTS3_NODE_PADDING (FTS3_VARINT_MAX*2) - -/* -** Under certain circumstances, b-tree nodes (doclists) can be loaded into -** memory incrementally instead of all at once. This can be a big performance -** win (reduced IO and CPU) if SQLite stops calling the virtual table xNext() -** method before retrieving all query results (as may happen, for example, -** if a query has a LIMIT clause). -** -** Incremental loading is used for b-tree nodes FTS3_NODE_CHUNK_THRESHOLD -** bytes and larger. Nodes are loaded in chunks of FTS3_NODE_CHUNKSIZE bytes. -** The code is written so that the hard lower-limit for each of these values -** is 1. Clearly such small values would be inefficient, but can be useful -** for testing purposes. -** -** If this module is built with SQLITE_TEST defined, these constants may -** be overridden at runtime for testing purposes. File fts3_test.c contains -** a Tcl interface to read and write the values. -*/ -#ifdef SQLITE_TEST -int test_fts3_node_chunksize = (4*1024); -int test_fts3_node_chunk_threshold = (4*1024)*4; -# define FTS3_NODE_CHUNKSIZE test_fts3_node_chunksize -# define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold -#else -# define FTS3_NODE_CHUNKSIZE (4*1024) -# define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4) +#ifndef SQLITE_AMALGAMATION +typedef sqlite3_int64 i64; #endif /* -** The two values that may be meaningfully bound to the :1 parameter in -** statements SQL_REPLACE_STAT and SQL_SELECT_STAT. -*/ -#define FTS_STAT_DOCTOTAL 0 -#define FTS_STAT_INCRMERGEHINT 1 -#define FTS_STAT_AUTOINCRMERGE 2 - -/* -** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic -** and incremental merge operation that takes place. This is used for -** debugging FTS only, it should not usually be turned on in production -** systems. +** Characters that may appear in the second argument to matchinfo(). */ -#ifdef FTS3_LOG_MERGES -static void fts3LogMerge(int nMerge, sqlite3_int64 iAbsLevel){ - sqlite3_log(SQLITE_OK, "%d-way merge from level %d", nMerge, (int)iAbsLevel); -} -#else -#define fts3LogMerge(x, y) -#endif - - -typedef struct PendingList PendingList; -typedef struct SegmentNode SegmentNode; -typedef struct SegmentWriter SegmentWriter; +#define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ +#define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ +#define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ +#define FTS3_MATCHINFO_AVGLENGTH 'a' /* nCol values */ +#define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */ +#define FTS3_MATCHINFO_LCS 's' /* nCol values */ +#define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */ +#define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */ +#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */ /* -** An instance of the following data structure is used to build doclists -** incrementally. See function fts3PendingListAppend() for details. +** The default value for the second argument to matchinfo(). */ -struct PendingList { - int nData; - char *aData; - int nSpace; - sqlite3_int64 iLastDocid; - sqlite3_int64 iLastCol; - sqlite3_int64 iLastPos; -}; +#define FTS3_MATCHINFO_DEFAULT "pcx" /* -** Each cursor has a (possibly empty) linked list of the following objects. +** Used as an fts3ExprIterate() context when loading phrase doclists to +** Fts3Expr.aDoclist[]/nDoclist. */ -struct Fts3DeferredToken { - Fts3PhraseToken *pToken; /* Pointer to corresponding expr token */ - int iCol; /* Column token must occur in */ - Fts3DeferredToken *pNext; /* Next in list of deferred tokens */ - PendingList *pList; /* Doclist is assembled here */ +typedef struct LoadDoclistCtx LoadDoclistCtx; +struct LoadDoclistCtx { + Fts3Cursor *pCsr; /* FTS3 Cursor */ + int nPhrase; /* Number of phrases seen so far */ + int nToken; /* Number of tokens seen so far */ }; /* -** An instance of this structure is used to iterate through the terms on -** a contiguous set of segment b-tree leaf nodes. Although the details of -** this structure are only manipulated by code in this file, opaque handles -** of type Fts3SegReader* are also used by code in fts3.c to iterate through -** terms when querying the full-text index. See functions: -** -** sqlite3Fts3SegReaderNew() -** sqlite3Fts3SegReaderFree() -** sqlite3Fts3SegReaderIterate() -** -** Methods used to manipulate Fts3SegReader structures: -** -** fts3SegReaderNext() -** fts3SegReaderFirstDocid() -** fts3SegReaderNextDocid() +** The following types are used as part of the implementation of the +** fts3BestSnippet() routine. */ -struct Fts3SegReader { - int iIdx; /* Index within level, or 0x7FFFFFFF for PT */ - u8 bLookup; /* True for a lookup only */ - u8 rootOnly; /* True for a root-only reader */ - - sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */ - sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */ - sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */ - sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */ - - char *aNode; /* Pointer to node data (or NULL) */ - int nNode; /* Size of buffer at aNode (or 0) */ - int nPopulate; /* If >0, bytes of buffer aNode[] loaded */ - sqlite3_blob *pBlob; /* If not NULL, blob handle to read node */ - - Fts3HashElem **ppNextElem; +typedef struct SnippetIter SnippetIter; +typedef struct SnippetPhrase SnippetPhrase; +typedef struct SnippetFragment SnippetFragment; - /* Variables set by fts3SegReaderNext(). These may be read directly - ** by the caller. They are valid from the time SegmentReaderNew() returns - ** until SegmentReaderNext() returns something other than SQLITE_OK - ** (i.e. SQLITE_DONE). - */ - int nTerm; /* Number of bytes in current term */ - char *zTerm; /* Pointer to current term */ - int nTermAlloc; /* Allocated size of zTerm buffer */ - char *aDoclist; /* Pointer to doclist of current entry */ - int nDoclist; /* Size of doclist in current entry */ +struct SnippetIter { + Fts3Cursor *pCsr; /* Cursor snippet is being generated from */ + int iCol; /* Extract snippet from this column */ + int nSnippet; /* Requested snippet length (in tokens) */ + int nPhrase; /* Number of phrases in query */ + SnippetPhrase *aPhrase; /* Array of size nPhrase */ + int iCurrent; /* First token of current snippet */ +}; - /* The following variables are used by fts3SegReaderNextDocid() to iterate - ** through the current doclist (aDoclist/nDoclist). - */ - char *pOffsetList; - int nOffsetList; /* For descending pending seg-readers only */ - sqlite3_int64 iDocid; +struct SnippetPhrase { + int nToken; /* Number of tokens in phrase */ + char *pList; /* Pointer to start of phrase position list */ + i64 iHead; /* Next value in position list */ + char *pHead; /* Position list data following iHead */ + i64 iTail; /* Next value in trailing position list */ + char *pTail; /* Position list data following iTail */ }; -#define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0) -#define fts3SegReaderIsRootOnly(p) ((p)->rootOnly!=0) +struct SnippetFragment { + int iCol; /* Column snippet is extracted from */ + int iPos; /* Index of first token in snippet */ + u64 covered; /* Mask of query phrases covered */ + u64 hlmask; /* Mask of snippet terms to highlight */ +}; /* -** An instance of this structure is used to create a segment b-tree in the -** database. The internal details of this type are only accessed by the -** following functions: -** -** fts3SegWriterAdd() -** fts3SegWriterFlush() -** fts3SegWriterFree() +** This type is used as an fts3ExprIterate() context object while +** accumulating the data returned by the matchinfo() function. */ -struct SegmentWriter { - SegmentNode *pTree; /* Pointer to interior tree structure */ - sqlite3_int64 iFirst; /* First slot in %_segments written */ - sqlite3_int64 iFree; /* Next free slot in %_segments */ - char *zTerm; /* Pointer to previous term buffer */ - int nTerm; /* Number of bytes in zTerm */ - int nMalloc; /* Size of malloc'd buffer at zMalloc */ - char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ - int nSize; /* Size of allocation at aData */ - int nData; /* Bytes of data in aData */ - char *aData; /* Pointer to block from malloc() */ - i64 nLeafData; /* Number of bytes of leaf data written */ +typedef struct MatchInfo MatchInfo; +struct MatchInfo { + Fts3Cursor *pCursor; /* FTS3 Cursor */ + int nCol; /* Number of columns in table */ + int nPhrase; /* Number of matchable phrases in query */ + sqlite3_int64 nDoc; /* Number of docs in database */ + char flag; + u32 *aMatchinfo; /* Pre-allocated buffer */ }; /* -** Type SegmentNode is used by the following three functions to create -** the interior part of the segment b+-tree structures (everything except -** the leaf nodes). These functions and type are only ever used by code -** within the fts3SegWriterXXX() family of functions described above. -** -** fts3NodeAddTerm() -** fts3NodeWrite() -** fts3NodeFree() -** -** When a b+tree is written to the database (either as a result of a merge -** or the pending-terms table being flushed), leaves are written into the -** database file as soon as they are completely populated. The interior of -** the tree is assembled in memory and written out only once all leaves have -** been populated and stored. This is Ok, as the b+-tree fanout is usually -** very large, meaning that the interior of the tree consumes relatively -** little memory. +** An instance of this structure is used to manage a pair of buffers, each +** (nElem * sizeof(u32)) bytes in size. See the MatchinfoBuffer code below +** for details. */ -struct SegmentNode { - SegmentNode *pParent; /* Parent node (or NULL for root node) */ - SegmentNode *pRight; /* Pointer to right-sibling */ - SegmentNode *pLeftmost; /* Pointer to left-most node of this depth */ - int nEntry; /* Number of terms written to node so far */ - char *zTerm; /* Pointer to previous term buffer */ - int nTerm; /* Number of bytes in zTerm */ - int nMalloc; /* Size of malloc'd buffer at zMalloc */ - char *zMalloc; /* Malloc'd space (possibly) used for zTerm */ - int nData; /* Bytes of valid data so far */ - char *aData; /* Node data */ +struct MatchinfoBuffer { + u8 aRef[3]; + int nElem; + int bGlobal; /* Set if global data is loaded */ + char *zMatchinfo; + u32 aMatchinfo[1]; }; + /* -** Valid values for the second argument to fts3SqlStmt(). +** The snippet() and offsets() functions both return text values. An instance +** of the following structure is used to accumulate those values while the +** functions are running. See fts3StringAppend() for details. */ -#define SQL_DELETE_CONTENT 0 -#define SQL_IS_EMPTY 1 -#define SQL_DELETE_ALL_CONTENT 2 -#define SQL_DELETE_ALL_SEGMENTS 3 -#define SQL_DELETE_ALL_SEGDIR 4 -#define SQL_DELETE_ALL_DOCSIZE 5 -#define SQL_DELETE_ALL_STAT 6 -#define SQL_SELECT_CONTENT_BY_ROWID 7 -#define SQL_NEXT_SEGMENT_INDEX 8 -#define SQL_INSERT_SEGMENTS 9 -#define SQL_NEXT_SEGMENTS_ID 10 -#define SQL_INSERT_SEGDIR 11 -#define SQL_SELECT_LEVEL 12 -#define SQL_SELECT_LEVEL_RANGE 13 -#define SQL_SELECT_LEVEL_COUNT 14 -#define SQL_SELECT_SEGDIR_MAX_LEVEL 15 -#define SQL_DELETE_SEGDIR_LEVEL 16 -#define SQL_DELETE_SEGMENTS_RANGE 17 -#define SQL_CONTENT_INSERT 18 -#define SQL_DELETE_DOCSIZE 19 -#define SQL_REPLACE_DOCSIZE 20 -#define SQL_SELECT_DOCSIZE 21 -#define SQL_SELECT_STAT 22 -#define SQL_REPLACE_STAT 23 +typedef struct StrBuffer StrBuffer; +struct StrBuffer { + char *z; /* Pointer to buffer containing string */ + int n; /* Length of z in bytes (excl. nul-term) */ + int nAlloc; /* Allocated size of buffer z in bytes */ +}; -#define SQL_SELECT_ALL_PREFIX_LEVEL 24 -#define SQL_DELETE_ALL_TERMS_SEGDIR 25 -#define SQL_DELETE_SEGDIR_RANGE 26 -#define SQL_SELECT_ALL_LANGID 27 -#define SQL_FIND_MERGE_LEVEL 28 -#define SQL_MAX_LEAF_NODE_ESTIMATE 29 -#define SQL_DELETE_SEGDIR_ENTRY 30 -#define SQL_SHIFT_SEGDIR_ENTRY 31 -#define SQL_SELECT_SEGDIR 32 -#define SQL_CHOMP_SEGDIR 33 -#define SQL_SEGMENT_IS_APPENDABLE 34 -#define SQL_SELECT_INDEXES 35 -#define SQL_SELECT_MXLEVEL 36 -#define SQL_SELECT_LEVEL_RANGE2 37 -#define SQL_UPDATE_LEVEL_IDX 38 -#define SQL_UPDATE_LEVEL 39 +/************************************************************************* +** Start of MatchinfoBuffer code. +*/ /* -** This function is used to obtain an SQLite prepared statement handle -** for the statement identified by the second argument. If successful, -** *pp is set to the requested statement handle and SQLITE_OK returned. -** Otherwise, an SQLite error code is returned and *pp is set to 0. -** -** If argument apVal is not NULL, then it must point to an array with -** at least as many entries as the requested statement has bound -** parameters. The values are bound to the statements parameters before -** returning. +** Allocate a two-slot MatchinfoBuffer object. */ -static int fts3SqlStmt( - Fts3Table *p, /* Virtual table handle */ - int eStmt, /* One of the SQL_XXX constants above */ - sqlite3_stmt **pp, /* OUT: Statement handle */ - sqlite3_value **apVal /* Values to bind to statement */ -){ - const char *azSql[] = { -/* 0 */ "DELETE FROM %Q.'%q_content' WHERE rowid = ?", -/* 1 */ "SELECT NOT EXISTS(SELECT docid FROM %Q.'%q_content' WHERE rowid!=?)", -/* 2 */ "DELETE FROM %Q.'%q_content'", -/* 3 */ "DELETE FROM %Q.'%q_segments'", -/* 4 */ "DELETE FROM %Q.'%q_segdir'", -/* 5 */ "DELETE FROM %Q.'%q_docsize'", -/* 6 */ "DELETE FROM %Q.'%q_stat'", -/* 7 */ "SELECT %s WHERE rowid=?", -/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", -/* 9 */ "REPLACE INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", -/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", -/* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)", - - /* Return segments in order from oldest to newest.*/ -/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root " - "FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC", -/* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root " - "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?" - "ORDER BY level DESC, idx ASC", - -/* 14 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?", -/* 15 */ "SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", - -/* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?", -/* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?", -/* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%s)", -/* 19 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?", -/* 20 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", -/* 21 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?", -/* 22 */ "SELECT value FROM %Q.'%q_stat' WHERE id=?", -/* 23 */ "REPLACE INTO %Q.'%q_stat' VALUES(?,?)", -/* 24 */ "", -/* 25 */ "", - -/* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?", -/* 27 */ "SELECT ? UNION SELECT level / (1024 * ?) FROM %Q.'%q_segdir'", - -/* This statement is used to determine which level to read the input from -** when performing an incremental merge. It returns the absolute level number -** of the oldest level in the db that contains at least ? segments. Or, -** if no level in the FTS index contains more than ? segments, the statement -** returns zero rows. */ -/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' " - " GROUP BY level HAVING cnt>=?" - " ORDER BY (level %% 1024) ASC LIMIT 1", - -/* Estimate the upper limit on the number of leaf nodes in a new segment -** created by merging the oldest :2 segments from absolute level :1. See -** function sqlite3Fts3Incrmerge() for details. */ -/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) " - " FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?", - -/* SQL_DELETE_SEGDIR_ENTRY -** Delete the %_segdir entry on absolute level :1 with index :2. */ -/* 30 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", - -/* SQL_SHIFT_SEGDIR_ENTRY -** Modify the idx value for the segment with idx=:3 on absolute level :2 -** to :1. */ -/* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?", - -/* SQL_SELECT_SEGDIR -** Read a single entry from the %_segdir table. The entry from absolute -** level :1 with index value :2. */ -/* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root " - "FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?", - -/* SQL_CHOMP_SEGDIR -** Update the start_block (:1) and root (:2) fields of the %_segdir -** entry located on absolute level :3 with index :4. */ -/* 33 */ "UPDATE %Q.'%q_segdir' SET start_block = ?, root = ?" - "WHERE level = ? AND idx = ?", - -/* SQL_SEGMENT_IS_APPENDABLE -** Return a single row if the segment with end_block=? is appendable. Or -** no rows otherwise. */ -/* 34 */ "SELECT 1 FROM %Q.'%q_segments' WHERE blockid=? AND block IS NULL", - -/* SQL_SELECT_INDEXES -** Return the list of valid segment indexes for absolute level ? */ -/* 35 */ "SELECT idx FROM %Q.'%q_segdir' WHERE level=? ORDER BY 1 ASC", - -/* SQL_SELECT_MXLEVEL -** Return the largest relative level in the FTS index or indexes. */ -/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'", +static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ + MatchinfoBuffer *pRet; + sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) + + sizeof(MatchinfoBuffer); + sqlite3_int64 nStr = strlen(zMatchinfo); - /* Return segments in order from oldest to newest.*/ -/* 37 */ "SELECT level, idx, end_block " - "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? " - "ORDER BY level DESC, idx ASC", + pRet = sqlite3Fts3MallocZero(nByte + nStr+1); + if( pRet ){ + pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; + pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + + sizeof(u32)*((int)nElem+1); + pRet->nElem = (int)nElem; + pRet->zMatchinfo = ((char*)pRet) + nByte; + memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); + pRet->aRef[0] = 1; + } - /* Update statements used while promoting segments */ -/* 38 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=-1,idx=? " - "WHERE level=? AND idx=?", -/* 39 */ "UPDATE OR FAIL %Q.'%q_segdir' SET level=? WHERE level=-1" + return pRet; +} - }; - int rc = SQLITE_OK; - sqlite3_stmt *pStmt; +static void fts3MIBufferFree(void *p){ + MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); - assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); - assert( eStmt=0 ); - - pStmt = p->aStmt[eStmt]; - if( !pStmt ){ - char *zSql; - if( eStmt==SQL_CONTENT_INSERT ){ - zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); - }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ - zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); - }else{ - zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); - } - if( !zSql ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL); - sqlite3_free(zSql); - assert( rc==SQLITE_OK || pStmt==0 ); - p->aStmt[eStmt] = pStmt; - } + assert( (u32*)p==&pBuf->aMatchinfo[1] + || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] + ); + if( (u32*)p==&pBuf->aMatchinfo[1] ){ + pBuf->aRef[1] = 0; + }else{ + pBuf->aRef[2] = 0; } - if( apVal ){ - int i; - int nParam = sqlite3_bind_parameter_count(pStmt); - for(i=0; rc==SQLITE_OK && iaRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){ + sqlite3_free(pBuf); } - *pp = pStmt; - return rc; } +static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ + void (*xRet)(void*) = 0; + u32 *aOut = 0; -static int fts3SelectDocsize( - Fts3Table *pTab, /* FTS3 table handle */ - sqlite3_int64 iDocid, /* Docid to bind for SQL_SELECT_DOCSIZE */ - sqlite3_stmt **ppStmt /* OUT: Statement handle */ -){ - sqlite3_stmt *pStmt = 0; /* Statement requested from fts3SqlStmt() */ - int rc; /* Return code */ - - rc = fts3SqlStmt(pTab, SQL_SELECT_DOCSIZE, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pStmt, 1, iDocid); - rc = sqlite3_step(pStmt); - if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){ - rc = sqlite3_reset(pStmt); - if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB; - pStmt = 0; - }else{ - rc = SQLITE_OK; - } + if( p->aRef[1]==0 ){ + p->aRef[1] = 1; + aOut = &p->aMatchinfo[1]; + xRet = fts3MIBufferFree; } - - *ppStmt = pStmt; - return rc; -} - -SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal( - Fts3Table *pTab, /* Fts3 table handle */ - sqlite3_stmt **ppStmt /* OUT: Statement handle */ -){ - sqlite3_stmt *pStmt = 0; - int rc; - rc = fts3SqlStmt(pTab, SQL_SELECT_STAT, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); - if( sqlite3_step(pStmt)!=SQLITE_ROW - || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB - ){ - rc = sqlite3_reset(pStmt); - if( rc==SQLITE_OK ) rc = FTS_CORRUPT_VTAB; - pStmt = 0; + else if( p->aRef[2]==0 ){ + p->aRef[2] = 1; + aOut = &p->aMatchinfo[p->nElem+2]; + xRet = fts3MIBufferFree; + }else{ + aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32)); + if( aOut ){ + xRet = sqlite3_free; + if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); } } - *ppStmt = pStmt; - return rc; + + *paOut = aOut; + return xRet; } -SQLITE_PRIVATE int sqlite3Fts3SelectDocsize( - Fts3Table *pTab, /* Fts3 table handle */ - sqlite3_int64 iDocid, /* Docid to read size data for */ - sqlite3_stmt **ppStmt /* OUT: Statement handle */ -){ - return fts3SelectDocsize(pTab, iDocid, ppStmt); +static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ + p->bGlobal = 1; + memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); } /* -** Similar to fts3SqlStmt(). Except, after binding the parameters in -** array apVal[] to the SQL statement identified by eStmt, the statement -** is executed. -** -** Returns SQLITE_OK if the statement is successfully executed, or an -** SQLite error code otherwise. +** Free a MatchinfoBuffer object allocated using fts3MIBufferNew() */ -static void fts3SqlExec( - int *pRC, /* Result code */ - Fts3Table *p, /* The FTS3 table */ - int eStmt, /* Index of statement to evaluate */ - sqlite3_value **apVal /* Parameters to bind */ -){ - sqlite3_stmt *pStmt; - int rc; - if( *pRC ) return; - rc = fts3SqlStmt(p, eStmt, &pStmt, apVal); - if( rc==SQLITE_OK ){ - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); +SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){ + if( p ){ + assert( p->aRef[0]==1 ); + p->aRef[0] = 0; + if( p->aRef[0]==0 && p->aRef[1]==0 && p->aRef[2]==0 ){ + sqlite3_free(p); + } } - *pRC = rc; } - /* -** This function ensures that the caller has obtained an exclusive -** shared-cache table-lock on the %_segdir table. This is required before -** writing data to the fts3 table. If this lock is not acquired first, then -** the caller may end up attempting to take this lock as part of committing -** a transaction, causing SQLite to return SQLITE_LOCKED or -** LOCKED_SHAREDCACHEto a COMMIT command. -** -** It is best to avoid this because if FTS3 returns any error when -** committing a transaction, the whole transaction will be rolled back. -** And this is not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. -** It can still happen if the user locks the underlying tables directly -** instead of accessing them via FTS. -*/ -static int fts3Writelock(Fts3Table *p){ - int rc = SQLITE_OK; - - if( p->nPendingData==0 ){ - sqlite3_stmt *pStmt; - rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_null(pStmt, 1); - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); - } - } +** End of MatchinfoBuffer code. +*************************************************************************/ - return rc; -} /* -** FTS maintains a separate indexes for each language-id (a 32-bit integer). -** Within each language id, a separate index is maintained to store the -** document terms, and each configured prefix size (configured the FTS -** "prefix=" option). And each index consists of multiple levels ("relative -** levels"). +** This function is used to help iterate through a position-list. A position +** list is a list of unique integers, sorted from smallest to largest. Each +** element of the list is represented by an FTS3 varint that takes the value +** of the difference between the current element and the previous one plus +** two. For example, to store the position-list: ** -** All three of these values (the language id, the specific index and the -** level within the index) are encoded in 64-bit integer values stored -** in the %_segdir table on disk. This function is used to convert three -** separate component values into the single 64-bit integer value that -** can be used to query the %_segdir table. +** 4 9 113 ** -** Specifically, each language-id/index combination is allocated 1024 -** 64-bit integer level values ("absolute levels"). The main terms index -** for language-id 0 is allocate values 0-1023. The first prefix index -** (if any) for language-id 0 is allocated values 1024-2047. And so on. -** Language 1 indexes are allocated immediately following language 0. +** the three varints: ** -** So, for a system with nPrefix prefix indexes configured, the block of -** absolute levels that corresponds to language-id iLangid and index -** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024). +** 6 7 106 +** +** are encoded. +** +** When this function is called, *pp points to the start of an element of +** the list. *piPos contains the value of the previous entry in the list. +** After it returns, *piPos contains the value of the next element of the +** list and *pp is advanced to the following varint. */ -static sqlite3_int64 getAbsoluteLevel( - Fts3Table *p, /* FTS3 table handle */ - int iLangid, /* Language id */ - int iIndex, /* Index in p->aIndex[] */ - int iLevel /* Level of segments */ -){ - sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */ - assert( iLangid>=0 ); - assert( p->nIndex>0 ); - assert( iIndex>=0 && iIndexnIndex ); - - iBase = ((sqlite3_int64)iLangid * p->nIndex + iIndex) * FTS3_SEGDIR_MAXLEVEL; - return iBase + iLevel; +static void fts3GetDeltaPosition(char **pp, i64 *piPos){ + int iVal; + *pp += fts3GetVarint32(*pp, &iVal); + *piPos += (iVal-2); } /* -** Set *ppStmt to a statement handle that may be used to iterate through -** all rows in the %_segdir table, from oldest to newest. If successful, -** return SQLITE_OK. If an error occurs while preparing the statement, -** return an SQLite error code. -** -** There is only ever one instance of this SQL statement compiled for -** each FTS3 table. -** -** The statement returns the following columns from the %_segdir table: -** -** 0: idx -** 1: start_block -** 2: leaves_end_block -** 3: end_block -** 4: root +** Helper function for fts3ExprIterate() (see below). */ -SQLITE_PRIVATE int sqlite3Fts3AllSegdirs( - Fts3Table *p, /* FTS3 table */ - int iLangid, /* Language being queried */ - int iIndex, /* Index for p->aIndex[] */ - int iLevel, /* Level to select (relative level) */ - sqlite3_stmt **ppStmt /* OUT: Compiled statement */ +static int fts3ExprIterate2( + Fts3Expr *pExpr, /* Expression to iterate phrases of */ + int *piPhrase, /* Pointer to phrase counter */ + int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ + void *pCtx /* Second argument to pass to callback */ ){ - int rc; - sqlite3_stmt *pStmt = 0; - - assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel>=0 ); - assert( iLevel=0 && iIndexnIndex ); + int rc; /* Return code */ + int eType = pExpr->eType; /* Type of expression node pExpr */ - if( iLevel<0 ){ - /* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */ - rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); - sqlite3_bind_int64(pStmt, 2, - getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) - ); + if( eType!=FTSQUERY_PHRASE ){ + assert( pExpr->pLeft && pExpr->pRight ); + rc = fts3ExprIterate2(pExpr->pLeft, piPhrase, x, pCtx); + if( rc==SQLITE_OK && eType!=FTSQUERY_NOT ){ + rc = fts3ExprIterate2(pExpr->pRight, piPhrase, x, pCtx); } }else{ - /* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */ - rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel)); - } + rc = x(pExpr, *piPhrase, pCtx); + (*piPhrase)++; } - *ppStmt = pStmt; return rc; } - /* -** Append a single varint to a PendingList buffer. SQLITE_OK is returned -** if successful, or an SQLite error code otherwise. -** -** This function also serves to allocate the PendingList structure itself. -** For example, to create a new PendingList structure containing two -** varints: +** Iterate through all phrase nodes in an FTS3 query, except those that +** are part of a sub-tree that is the right-hand-side of a NOT operator. +** For each phrase node found, the supplied callback function is invoked. ** -** PendingList *p = 0; -** fts3PendingListAppendVarint(&p, 1); -** fts3PendingListAppendVarint(&p, 2); +** If the callback function returns anything other than SQLITE_OK, +** the iteration is abandoned and the error code returned immediately. +** Otherwise, SQLITE_OK is returned after a callback has been made for +** all eligible phrase nodes. */ -static int fts3PendingListAppendVarint( - PendingList **pp, /* IN/OUT: Pointer to PendingList struct */ - sqlite3_int64 i /* Value to append to data */ +static int fts3ExprIterate( + Fts3Expr *pExpr, /* Expression to iterate phrases of */ + int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ + void *pCtx /* Second argument to pass to callback */ ){ - PendingList *p = *pp; - - /* Allocate or grow the PendingList as required. */ - if( !p ){ - p = sqlite3_malloc(sizeof(*p) + 100); - if( !p ){ - return SQLITE_NOMEM; - } - p->nSpace = 100; - p->aData = (char *)&p[1]; - p->nData = 0; - } - else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ - int nNew = p->nSpace * 2; - p = sqlite3_realloc(p, sizeof(*p) + nNew); - if( !p ){ - sqlite3_free(*pp); - *pp = 0; - return SQLITE_NOMEM; - } - p->nSpace = nNew; - p->aData = (char *)&p[1]; - } - - /* Append the new serialized varint to the end of the list. */ - p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i); - p->aData[p->nData] = '\0'; - *pp = p; - return SQLITE_OK; + int iPhrase = 0; /* Variable used as the phrase counter */ + return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx); } + /* -** Add a docid/column/position entry to a PendingList structure. Non-zero -** is returned if the structure is sqlite3_realloced as part of adding -** the entry. Otherwise, zero. -** -** If an OOM error occurs, *pRc is set to SQLITE_NOMEM before returning. -** Zero is always returned in this case. Otherwise, if no OOM error occurs, -** it is set to SQLITE_OK. +** This is an fts3ExprIterate() callback used while loading the doclists +** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also +** fts3ExprLoadDoclists(). */ -static int fts3PendingListAppend( - PendingList **pp, /* IN/OUT: PendingList structure */ - sqlite3_int64 iDocid, /* Docid for entry to add */ - sqlite3_int64 iCol, /* Column for entry to add */ - sqlite3_int64 iPos, /* Position of term for entry to add */ - int *pRc /* OUT: Return code */ -){ - PendingList *p = *pp; +static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ int rc = SQLITE_OK; + Fts3Phrase *pPhrase = pExpr->pPhrase; + LoadDoclistCtx *p = (LoadDoclistCtx *)ctx; - assert( !p || p->iLastDocid<=iDocid ); + UNUSED_PARAMETER(iPhrase); - if( !p || p->iLastDocid!=iDocid ){ - sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0); - if( p ){ - assert( p->nDatanSpace ); - assert( p->aData[p->nData]==0 ); - p->nData++; - } - if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iDelta)) ){ - goto pendinglistappend_out; - } - p->iLastCol = -1; - p->iLastPos = 0; - p->iLastDocid = iDocid; - } - if( iCol>0 && p->iLastCol!=iCol ){ - if( SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, 1)) - || SQLITE_OK!=(rc = fts3PendingListAppendVarint(&p, iCol)) - ){ - goto pendinglistappend_out; - } - p->iLastCol = iCol; - p->iLastPos = 0; - } - if( iCol>=0 ){ - assert( iPos>p->iLastPos || (iPos==0 && p->iLastPos==0) ); - rc = fts3PendingListAppendVarint(&p, 2+iPos-p->iLastPos); - if( rc==SQLITE_OK ){ - p->iLastPos = iPos; - } - } + p->nPhrase++; + p->nToken += pPhrase->nToken; - pendinglistappend_out: - *pRc = rc; - if( p!=*pp ){ - *pp = p; - return 1; - } - return 0; + return rc; } /* -** Free a PendingList object allocated by fts3PendingListAppend(). +** Load the doclists for each phrase in the query associated with FTS3 cursor +** pCsr. +** +** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable +** phrases in the expression (all phrases except those directly or +** indirectly descended from the right-hand-side of a NOT operator). If +** pnToken is not NULL, then it is set to the number of tokens in all +** matchable phrases of the expression. */ -static void fts3PendingListDelete(PendingList *pList){ - sqlite3_free(pList); +static int fts3ExprLoadDoclists( + Fts3Cursor *pCsr, /* Fts3 cursor for current query */ + int *pnPhrase, /* OUT: Number of phrases in query */ + int *pnToken /* OUT: Number of tokens in query */ +){ + int rc; /* Return Code */ + LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */ + sCtx.pCsr = pCsr; + rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx); + if( pnPhrase ) *pnPhrase = sCtx.nPhrase; + if( pnToken ) *pnToken = sCtx.nToken; + return rc; +} + +static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ + (*(int *)ctx)++; + pExpr->iPhrase = iPhrase; + return SQLITE_OK; +} +static int fts3ExprPhraseCount(Fts3Expr *pExpr){ + int nPhrase = 0; + (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase); + return nPhrase; } /* -** Add an entry to one of the pending-terms hash tables. +** Advance the position list iterator specified by the first two +** arguments so that it points to the first element with a value greater +** than or equal to parameter iNext. */ -static int fts3PendingTermsAddOne( - Fts3Table *p, - int iCol, - int iPos, - Fts3Hash *pHash, /* Pending terms hash table to add entry to */ - const char *zToken, - int nToken -){ - PendingList *pList; - int rc = SQLITE_OK; +static void fts3SnippetAdvance(char **ppIter, i64 *piIter, int iNext){ + char *pIter = *ppIter; + if( pIter ){ + i64 iIter = *piIter; - pList = (PendingList *)fts3HashFind(pHash, zToken, nToken); - if( pList ){ - p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem)); - } - if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){ - if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){ - /* Malloc failed while inserting the new entry. This can only - ** happen if there was no previous entry for this token. - */ - assert( 0==fts3HashFind(pHash, zToken, nToken) ); - sqlite3_free(pList); - rc = SQLITE_NOMEM; + while( iIternPendingData += (pList->nData + nToken + sizeof(Fts3HashElem)); - } - return rc; } /* -** Tokenize the nul-terminated string zText and add all tokens to the -** pending-terms hash-table. The docid used is that currently stored in -** p->iPrevDocid, and the column is specified by argument iCol. -** -** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. +** Advance the snippet iterator to the next candidate snippet. */ -static int fts3PendingTermsAdd( - Fts3Table *p, /* Table into which text will be inserted */ - int iLangid, /* Language id to use */ - const char *zText, /* Text of document to be inserted */ - int iCol, /* Column into which text is being inserted */ - u32 *pnWord /* IN/OUT: Incr. by number tokens inserted */ -){ - int rc; - int iStart = 0; - int iEnd = 0; - int iPos = 0; - int nWord = 0; - - char const *zToken; - int nToken = 0; - - sqlite3_tokenizer *pTokenizer = p->pTokenizer; - sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; - sqlite3_tokenizer_cursor *pCsr; - int (*xNext)(sqlite3_tokenizer_cursor *pCursor, - const char**,int*,int*,int*,int*); - - assert( pTokenizer && pModule ); - - /* If the user has inserted a NULL value, this function may be called with - ** zText==0. In this case, add zero token entries to the hash table and - ** return early. */ - if( zText==0 ){ - *pnWord = 0; - return SQLITE_OK; - } - - rc = sqlite3Fts3OpenTokenizer(pTokenizer, iLangid, zText, -1, &pCsr); - if( rc!=SQLITE_OK ){ - return rc; - } +static int fts3SnippetNextCandidate(SnippetIter *pIter){ + int i; /* Loop counter */ - xNext = pModule->xNext; - while( SQLITE_OK==rc - && SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos)) - ){ - int i; - if( iPos>=nWord ) nWord = iPos+1; + if( pIter->iCurrent<0 ){ + /* The SnippetIter object has just been initialized. The first snippet + ** candidate always starts at offset 0 (even if this candidate has a + ** score of 0.0). + */ + pIter->iCurrent = 0; - /* Positions cannot be negative; we use -1 as a terminator internally. - ** Tokens must have a non-zero length. + /* Advance the 'head' iterator of each phrase to the first offset that + ** is greater than or equal to (iNext+nSnippet). */ - if( iPos<0 || !zToken || nToken<=0 ){ - rc = SQLITE_ERROR; - break; + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, pIter->nSnippet); + } + }else{ + int iStart; + int iEnd = 0x7FFFFFFF; + + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + if( pPhrase->pHead && pPhrase->iHeadiHead; + } + } + if( iEnd==0x7FFFFFFF ){ + return 1; } - /* Add the term to the terms index */ - rc = fts3PendingTermsAddOne( - p, iCol, iPos, &p->aIndex[0].hPending, zToken, nToken - ); - - /* Add the term to each of the prefix indexes that it is not too - ** short for. */ - for(i=1; rc==SQLITE_OK && inIndex; i++){ - struct Fts3Index *pIndex = &p->aIndex[i]; - if( nTokennPrefix ) continue; - rc = fts3PendingTermsAddOne( - p, iCol, iPos, &pIndex->hPending, zToken, pIndex->nPrefix - ); + pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1; + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1); + fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart); } } - pModule->xClose(pCsr); - *pnWord += nWord; - return (rc==SQLITE_DONE ? SQLITE_OK : rc); + return 0; } -/* -** Calling this function indicates that subsequent calls to -** fts3PendingTermsAdd() are to add term/position-list pairs for the -** contents of the document with docid iDocid. +/* +** Retrieve information about the current candidate snippet of snippet +** iterator pIter. */ -static int fts3PendingTermsDocid( - Fts3Table *p, /* Full-text table handle */ - int bDelete, /* True if this op is a delete */ - int iLangid, /* Language id of row being written */ - sqlite_int64 iDocid /* Docid of row being written */ +static void fts3SnippetDetails( + SnippetIter *pIter, /* Snippet iterator */ + u64 mCovered, /* Bitmask of phrases already covered */ + int *piToken, /* OUT: First token of proposed snippet */ + int *piScore, /* OUT: "Score" for this snippet */ + u64 *pmCover, /* OUT: Bitmask of phrases covered */ + u64 *pmHighlight /* OUT: Bitmask of terms to highlight */ ){ - assert( iLangid>=0 ); - assert( bDelete==1 || bDelete==0 ); + int iStart = pIter->iCurrent; /* First token of snippet */ + int iScore = 0; /* Score of this snippet */ + int i; /* Loop counter */ + u64 mCover = 0; /* Mask of phrases covered by this snippet */ + u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */ - /* TODO(shess) Explore whether partially flushing the buffer on - ** forced-flush would provide better performance. I suspect that if - ** we ordered the doclists by size and flushed the largest until the - ** buffer was half empty, that would let the less frequent terms - ** generate longer doclists. - */ - if( iDocidiPrevDocid - || (iDocid==p->iPrevDocid && p->bPrevDelete==0) - || p->iPrevLangid!=iLangid - || p->nPendingData>p->nMaxPendingData - ){ - int rc = sqlite3Fts3PendingTermsFlush(p); - if( rc!=SQLITE_OK ) return rc; - } - p->iPrevDocid = iDocid; - p->iPrevLangid = iLangid; - p->bPrevDelete = bDelete; - return SQLITE_OK; -} + for(i=0; inPhrase; i++){ + SnippetPhrase *pPhrase = &pIter->aPhrase[i]; + if( pPhrase->pTail ){ + char *pCsr = pPhrase->pTail; + i64 iCsr = pPhrase->iTail; -/* -** Discard the contents of the pending-terms hash tables. -*/ -SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){ - int i; - for(i=0; inIndex; i++){ - Fts3HashElem *pElem; - Fts3Hash *pHash = &p->aIndex[i].hPending; - for(pElem=fts3HashFirst(pHash); pElem; pElem=fts3HashNext(pElem)){ - PendingList *pList = (PendingList *)fts3HashData(pElem); - fts3PendingListDelete(pList); + while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){ + int j; + u64 mPhrase = (u64)1 << (i%64); + u64 mPos = (u64)1 << (iCsr - iStart); + assert( iCsr>=iStart && (iCsr - iStart)<=64 ); + assert( i>=0 ); + if( (mCover|mCovered)&mPhrase ){ + iScore++; + }else{ + iScore += 1000; + } + mCover |= mPhrase; + + for(j=0; jnToken; j++){ + mHighlight |= (mPos>>j); + } + + if( 0==(*pCsr & 0x0FE) ) break; + fts3GetDeltaPosition(&pCsr, &iCsr); + } } - fts3HashClear(pHash); } - p->nPendingData = 0; + + /* Set the output variables before returning. */ + *piToken = iStart; + *piScore = iScore; + *pmCover = mCover; + *pmHighlight = mHighlight; } /* -** This function is called by the xUpdate() method as part of an INSERT -** operation. It adds entries for each term in the new record to the -** pendingTerms hash table. -** -** Argument apVal is the same as the similarly named argument passed to -** fts3InsertData(). Parameter iDocid is the docid of the new row. +** This function is an fts3ExprIterate() callback used by fts3BestSnippet(). +** Each invocation populates an element of the SnippetIter.aPhrase[] array. */ -static int fts3InsertTerms( - Fts3Table *p, - int iLangid, - sqlite3_value **apVal, - u32 *aSz -){ - int i; /* Iterator variable */ - for(i=2; inColumn+2; i++){ - int iCol = i-2; - if( p->abNotindexed[iCol]==0 ){ - const char *zText = (const char *)sqlite3_value_text(apVal[i]); - int rc = fts3PendingTermsAdd(p, iLangid, zText, iCol, &aSz[iCol]); - if( rc!=SQLITE_OK ){ - return rc; - } - aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); +static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ + SnippetIter *p = (SnippetIter *)ctx; + SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; + char *pCsr; + int rc; + + pPhrase->nToken = pExpr->pPhrase->nToken; + rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); + assert( rc==SQLITE_OK || pCsr==0 ); + if( pCsr ){ + i64 iFirst = 0; + pPhrase->pList = pCsr; + fts3GetDeltaPosition(&pCsr, &iFirst); + if( iFirst<0 ){ + rc = FTS_CORRUPT_VTAB; + }else{ + pPhrase->pHead = pCsr; + pPhrase->pTail = pCsr; + pPhrase->iHead = iFirst; + pPhrase->iTail = iFirst; } + }else{ + assert( rc!=SQLITE_OK || ( + pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 + )); } - return SQLITE_OK; + + return rc; } /* -** This function is called by the xUpdate() method for an INSERT operation. -** The apVal parameter is passed a copy of the apVal argument passed by -** SQLite to the xUpdate() method. i.e: +** Select the fragment of text consisting of nFragment contiguous tokens +** from column iCol that represent the "best" snippet. The best snippet +** is the snippet with the highest score, where scores are calculated +** by adding: ** -** apVal[0] Not used for INSERT. -** apVal[1] rowid -** apVal[2] Left-most user-defined column -** ... -** apVal[p->nColumn+1] Right-most user-defined column -** apVal[p->nColumn+2] Hidden column with same name as table -** apVal[p->nColumn+3] Hidden "docid" column (alias for rowid) -** apVal[p->nColumn+4] Hidden languageid column +** (a) +1 point for each occurrence of a matchable phrase in the snippet. +** +** (b) +1000 points for the first occurrence of each matchable phrase in +** the snippet for which the corresponding mCovered bit is not set. +** +** The selected snippet parameters are stored in structure *pFragment before +** returning. The score of the selected snippet is stored in *piScore +** before returning. */ -static int fts3InsertData( - Fts3Table *p, /* Full-text table */ - sqlite3_value **apVal, /* Array of values to insert */ - sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ +static int fts3BestSnippet( + int nSnippet, /* Desired snippet length */ + Fts3Cursor *pCsr, /* Cursor to create snippet for */ + int iCol, /* Index of column to create snippet from */ + u64 mCovered, /* Mask of phrases already covered */ + u64 *pmSeen, /* IN/OUT: Mask of phrases seen */ + SnippetFragment *pFragment, /* OUT: Best snippet found */ + int *piScore /* OUT: Score of snippet pFragment */ ){ - int rc; /* Return code */ - sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ + int rc; /* Return Code */ + int nList; /* Number of phrases in expression */ + SnippetIter sIter; /* Iterates through snippet candidates */ + sqlite3_int64 nByte; /* Number of bytes of space to allocate */ + int iBestScore = -1; /* Best snippet score found so far */ + int i; /* Loop counter */ - if( p->zContentTbl ){ - sqlite3_value *pRowid = apVal[p->nColumn+3]; - if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ - pRowid = apVal[1]; - } - if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ - return SQLITE_CONSTRAINT; - } - *piDocid = sqlite3_value_int64(pRowid); - return SQLITE_OK; - } + memset(&sIter, 0, sizeof(sIter)); - /* Locate the statement handle used to insert data into the %_content - ** table. The SQL for this statement is: - ** - ** INSERT INTO %_content VALUES(?, ?, ?, ...) - ** - ** The statement features N '?' variables, where N is the number of user - ** defined columns in the FTS3 table, plus one for the docid field. + /* Iterate through the phrases in the expression to count them. The same + ** callback makes sure the doclists are loaded for each phrase. */ - rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); - if( rc==SQLITE_OK && p->zLanguageid ){ - rc = sqlite3_bind_int( - pContentInsert, p->nColumn+2, - sqlite3_value_int(apVal[p->nColumn+4]) - ); + rc = fts3ExprLoadDoclists(pCsr, &nList, 0); + if( rc!=SQLITE_OK ){ + return rc; } - if( rc!=SQLITE_OK ) return rc; - /* There is a quirk here. The users INSERT statement may have specified - ** a value for the "rowid" field, for the "docid" field, or for both. - ** Which is a problem, since "rowid" and "docid" are aliases for the - ** same value. For example: - ** - ** INSERT INTO fts3tbl(rowid, docid) VALUES(1, 2); - ** - ** In FTS3, this is an error. It is an error to specify non-NULL values - ** for both docid and some other rowid alias. + /* Now that it is known how many phrases there are, allocate and zero + ** the required space using malloc(). */ - if( SQLITE_NULL!=sqlite3_value_type(apVal[3+p->nColumn]) ){ - if( SQLITE_NULL==sqlite3_value_type(apVal[0]) - && SQLITE_NULL!=sqlite3_value_type(apVal[1]) - ){ - /* A rowid/docid conflict. */ - return SQLITE_ERROR; - } - rc = sqlite3_bind_value(pContentInsert, 1, apVal[3+p->nColumn]); - if( rc!=SQLITE_OK ) return rc; + nByte = sizeof(SnippetPhrase) * nList; + sIter.aPhrase = (SnippetPhrase *)sqlite3Fts3MallocZero(nByte); + if( !sIter.aPhrase ){ + return SQLITE_NOMEM; } - /* Execute the statement to insert the record. Set *piDocid to the - ** new docid value. + /* Initialize the contents of the SnippetIter object. Then iterate through + ** the set of phrases in the expression to populate the aPhrase[] array. */ - sqlite3_step(pContentInsert); - rc = sqlite3_reset(pContentInsert); - - *piDocid = sqlite3_last_insert_rowid(p->db); - return rc; -} - - + sIter.pCsr = pCsr; + sIter.iCol = iCol; + sIter.nSnippet = nSnippet; + sIter.nPhrase = nList; + sIter.iCurrent = -1; + rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter); + if( rc==SQLITE_OK ){ -/* -** Remove all data from the FTS3 table. Clear the hash table containing -** pending terms. -*/ -static int fts3DeleteAll(Fts3Table *p, int bContent){ - int rc = SQLITE_OK; /* Return code */ + /* Set the *pmSeen output variable. */ + for(i=0; iiCol = iCol; + while( !fts3SnippetNextCandidate(&sIter) ){ + int iPos; + int iScore; + u64 mCover; + u64 mHighlite; + fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite); + assert( iScore>=0 ); + if( iScore>iBestScore ){ + pFragment->iPos = iPos; + pFragment->hlmask = mHighlite; + pFragment->covered = mCover; + iBestScore = iScore; + } + } - /* Delete everything from the shadow tables. Except, leave %_content as - ** is if bContent is false. */ - assert( p->zContentTbl==0 || bContent==0 ); - if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); - fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); - fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); - if( p->bHasDocsize ){ - fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0); - } - if( p->bHasStat ){ - fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0); + *piScore = iBestScore; } + sqlite3_free(sIter.aPhrase); return rc; } -/* -** -*/ -static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){ - int iLangid = 0; - if( p->zLanguageid ) iLangid = sqlite3_column_int(pSelect, p->nColumn+1); - return iLangid; -} /* -** The first element in the apVal[] array is assumed to contain the docid -** (an integer) of a row about to be deleted. Remove all terms from the -** full-text index. +** Append a string to the string-buffer passed as the first argument. +** +** If nAppend is negative, then the length of the string zAppend is +** determined using strlen(). */ -static void fts3DeleteTerms( - int *pRC, /* Result code */ - Fts3Table *p, /* The FTS table to delete from */ - sqlite3_value *pRowid, /* The docid to be deleted */ - u32 *aSz, /* Sizes of deleted document written here */ - int *pbFound /* OUT: Set to true if row really does exist */ +static int fts3StringAppend( + StrBuffer *pStr, /* Buffer to append to */ + const char *zAppend, /* Pointer to data to append to buffer */ + int nAppend /* Size of zAppend in bytes (or -1) */ ){ - int rc; - sqlite3_stmt *pSelect; + if( nAppend<0 ){ + nAppend = (int)strlen(zAppend); + } - assert( *pbFound==0 ); - if( *pRC ) return; - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); - if( rc==SQLITE_OK ){ - if( SQLITE_ROW==sqlite3_step(pSelect) ){ - int i; - int iLangid = langidFromSelect(p, pSelect); - i64 iDocid = sqlite3_column_int64(pSelect, 0); - rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid); - for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){ - int iCol = i-1; - if( p->abNotindexed[iCol]==0 ){ - const char *zText = (const char *)sqlite3_column_text(pSelect, i); - rc = fts3PendingTermsAdd(p, iLangid, zText, -1, &aSz[iCol]); - aSz[p->nColumn] += sqlite3_column_bytes(pSelect, i); - } - } - if( rc!=SQLITE_OK ){ - sqlite3_reset(pSelect); - *pRC = rc; - return; - } - *pbFound = 1; + /* If there is insufficient space allocated at StrBuffer.z, use realloc() + ** to grow the buffer until so that it is big enough to accomadate the + ** appended data. + */ + if( pStr->n+nAppend+1>=pStr->nAlloc ){ + sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100; + char *zNew = sqlite3_realloc64(pStr->z, nAlloc); + if( !zNew ){ + return SQLITE_NOMEM; } - rc = sqlite3_reset(pSelect); - }else{ - sqlite3_reset(pSelect); + pStr->z = zNew; + pStr->nAlloc = nAlloc; } - *pRC = rc; + assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) ); + + /* Append the data to the string buffer. */ + memcpy(&pStr->z[pStr->n], zAppend, nAppend); + pStr->n += nAppend; + pStr->z[pStr->n] = '\0'; + + return SQLITE_OK; } /* -** Forward declaration to account for the circular dependency between -** functions fts3SegmentMerge() and fts3AllocateSegdirIdx(). -*/ -static int fts3SegmentMerge(Fts3Table *, int, int, int); - -/* -** This function allocates a new level iLevel index in the segdir table. -** Usually, indexes are allocated within a level sequentially starting -** with 0, so the allocated index is one greater than the value returned -** by: +** The fts3BestSnippet() function often selects snippets that end with a +** query term. That is, the final term of the snippet is always a term +** that requires highlighting. For example, if 'X' is a highlighted term +** and '.' is a non-highlighted term, BestSnippet() may select: ** -** SELECT max(idx) FROM %_segdir WHERE level = :iLevel +** ........X.....X ** -** However, if there are already FTS3_MERGE_COUNT indexes at the requested -** level, they are merged into a single level (iLevel+1) segment and the -** allocated index is 0. +** This function "shifts" the beginning of the snippet forward in the +** document so that there are approximately the same number of +** non-highlighted terms to the right of the final highlighted term as there +** are to the left of the first highlighted term. For example, to this: ** -** If successful, *piIdx is set to the allocated index slot and SQLITE_OK -** returned. Otherwise, an SQLite error code is returned. +** ....X.....X.... +** +** This is done as part of extracting the snippet text, not when selecting +** the snippet. Snippet selection is done based on doclists only, so there +** is no way for fts3BestSnippet() to know whether or not the document +** actually contains terms that follow the final highlighted term. */ -static int fts3AllocateSegdirIdx( - Fts3Table *p, - int iLangid, /* Language id */ - int iIndex, /* Index for p->aIndex */ - int iLevel, - int *piIdx +static int fts3SnippetShift( + Fts3Table *pTab, /* FTS3 table snippet comes from */ + int iLangid, /* Language id to use in tokenizing */ + int nSnippet, /* Number of tokens desired for snippet */ + const char *zDoc, /* Document text to extract snippet from */ + int nDoc, /* Size of buffer zDoc in bytes */ + int *piPos, /* IN/OUT: First token of snippet */ + u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */ ){ - int rc; /* Return Code */ - sqlite3_stmt *pNextIdx; /* Query for next idx at level iLevel */ - int iNext = 0; /* Result of query pNextIdx */ + u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */ - assert( iLangid>=0 ); - assert( p->nIndex>=1 ); + if( hlmask ){ + int nLeft; /* Tokens to the left of first highlight */ + int nRight; /* Tokens to the right of last highlight */ + int nDesired; /* Ideal number of tokens to shift forward */ - /* Set variable iNext to the next available segdir index at level iLevel. */ - rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pNextIdx, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64( - pNextIdx, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) - ); - if( SQLITE_ROW==sqlite3_step(pNextIdx) ){ - iNext = sqlite3_column_int(pNextIdx, 0); - } - rc = sqlite3_reset(pNextIdx); - } + for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++); + for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++); + assert( (nSnippet-1-nRight)<=63 && (nSnippet-1-nRight)>=0 ); + nDesired = (nLeft-nRight)/2; - if( rc==SQLITE_OK ){ - /* If iNext is FTS3_MERGE_COUNT, indicating that level iLevel is already - ** full, merge all segments in level iLevel into a single iLevel+1 - ** segment and allocate (newly freed) index 0 at level iLevel. Otherwise, - ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext. + /* Ideally, the start of the snippet should be pushed forward in the + ** document nDesired tokens. This block checks if there are actually + ** nDesired tokens to the right of the snippet. If so, *piPos and + ** *pHlMask are updated to shift the snippet nDesired tokens to the + ** right. Otherwise, the snippet is shifted by the number of tokens + ** available. */ - if( iNext>=FTS3_MERGE_COUNT ){ - fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel)); - rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel); - *piIdx = 0; - }else{ - *piIdx = iNext; + if( nDesired>0 ){ + int nShift; /* Number of tokens to shift snippet by */ + int iCurrent = 0; /* Token counter */ + int rc; /* Return Code */ + sqlite3_tokenizer_module *pMod; + sqlite3_tokenizer_cursor *pC; + pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; + + /* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired) + ** or more tokens in zDoc/nDoc. + */ + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC); + if( rc!=SQLITE_OK ){ + return rc; + } + while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){ + const char *ZDUMMY; int DUMMY1 = 0, DUMMY2 = 0, DUMMY3 = 0; + rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent); + } + pMod->xClose(pC); + if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; } + + nShift = (rc==SQLITE_DONE)+iCurrent-nSnippet; + assert( nShift<=nDesired ); + if( nShift>0 ){ + *piPos += nShift; + *pHlmask = hlmask >> nShift; + } } } - - return rc; + return SQLITE_OK; } /* -** The %_segments table is declared as follows: -** -** CREATE TABLE %_segments(blockid INTEGER PRIMARY KEY, block BLOB) -** -** This function reads data from a single row of the %_segments table. The -** specific row is identified by the iBlockid parameter. If paBlob is not -** NULL, then a buffer is allocated using sqlite3_malloc() and populated -** with the contents of the blob stored in the "block" column of the -** identified table row is. Whether or not paBlob is NULL, *pnBlob is set -** to the size of the blob in bytes before returning. -** -** If an error occurs, or the table does not contain the specified row, -** an SQLite error code is returned. Otherwise, SQLITE_OK is returned. If -** paBlob is non-NULL, then it is the responsibility of the caller to -** eventually free the returned buffer. -** -** This function may leave an open sqlite3_blob* handle in the -** Fts3Table.pSegments variable. This handle is reused by subsequent calls -** to this function. The handle may be closed by calling the -** sqlite3Fts3SegmentsClose() function. Reusing a blob handle is a handy -** performance improvement, but the blob handle should always be closed -** before control is returned to the user (to prevent a lock being held -** on the database file for longer than necessary). Thus, any virtual table -** method (xFilter etc.) that may directly or indirectly call this function -** must call sqlite3Fts3SegmentsClose() before returning. +** Extract the snippet text for fragment pFragment from cursor pCsr and +** append it to string buffer pOut. */ -SQLITE_PRIVATE int sqlite3Fts3ReadBlock( - Fts3Table *p, /* FTS3 table handle */ - sqlite3_int64 iBlockid, /* Access the row with blockid=$iBlockid */ - char **paBlob, /* OUT: Blob data in malloc'd buffer */ - int *pnBlob, /* OUT: Size of blob data */ - int *pnLoad /* OUT: Bytes actually loaded */ +static int fts3SnippetText( + Fts3Cursor *pCsr, /* FTS3 Cursor */ + SnippetFragment *pFragment, /* Snippet to extract */ + int iFragment, /* Fragment number */ + int isLast, /* True for final fragment in snippet */ + int nSnippet, /* Number of tokens in extracted snippet */ + const char *zOpen, /* String inserted before highlighted term */ + const char *zClose, /* String inserted after highlighted term */ + const char *zEllipsis, /* String inserted between snippets */ + StrBuffer *pOut /* Write output here */ ){ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; int rc; /* Return code */ + const char *zDoc; /* Document text to extract snippet from */ + int nDoc; /* Size of zDoc in bytes */ + int iCurrent = 0; /* Current token number of document */ + int iEnd = 0; /* Byte offset of end of current token */ + int isShiftDone = 0; /* True after snippet is shifted */ + int iPos = pFragment->iPos; /* First token of snippet */ + u64 hlmask = pFragment->hlmask; /* Highlight-mask for snippet */ + int iCol = pFragment->iCol+1; /* Query column to extract text from */ + sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */ + sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */ - /* pnBlob must be non-NULL. paBlob may be NULL or non-NULL. */ - assert( pnBlob ); - - if( p->pSegments ){ - rc = sqlite3_blob_reopen(p->pSegments, iBlockid); - }else{ - if( 0==p->zSegmentsTbl ){ - p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName); - if( 0==p->zSegmentsTbl ) return SQLITE_NOMEM; + zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol); + if( zDoc==0 ){ + if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){ + return SQLITE_NOMEM; } - rc = sqlite3_blob_open( - p->db, p->zDb, p->zSegmentsTbl, "block", iBlockid, 0, &p->pSegments - ); + return SQLITE_OK; } + nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol); - if( rc==SQLITE_OK ){ - int nByte = sqlite3_blob_bytes(p->pSegments); - *pnBlob = nByte; - if( paBlob ){ - char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); - if( !aByte ){ - rc = SQLITE_NOMEM; - }else{ - if( pnLoad && nByte>(FTS3_NODE_CHUNK_THRESHOLD) ){ - nByte = FTS3_NODE_CHUNKSIZE; - *pnLoad = nByte; - } - rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0); - memset(&aByte[nByte], 0, FTS3_NODE_PADDING); - if( rc!=SQLITE_OK ){ - sqlite3_free(aByte); - aByte = 0; + /* Open a token cursor on the document. */ + pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc,nDoc,&pC); + if( rc!=SQLITE_OK ){ + return rc; + } + + while( rc==SQLITE_OK ){ + const char *ZDUMMY; /* Dummy argument used with tokenizer */ + int DUMMY1 = -1; /* Dummy argument used with tokenizer */ + int iBegin = 0; /* Offset in zDoc of start of token */ + int iFin = 0; /* Offset in zDoc of end of token */ + int isHighlight = 0; /* True for highlighted terms */ + + /* Variable DUMMY1 is initialized to a negative value above. Elsewhere + ** in the FTS code the variable that the third argument to xNext points to + ** is initialized to zero before the first (*but not necessarily + ** subsequent*) call to xNext(). This is done for a particular application + ** that needs to know whether or not the tokenizer is being used for + ** snippet generation or for some other purpose. + ** + ** Extreme care is required when writing code to depend on this + ** initialization. It is not a documented part of the tokenizer interface. + ** If a tokenizer is used directly by any code outside of FTS, this + ** convention might not be respected. */ + rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_DONE ){ + /* Special case - the last token of the snippet is also the last token + ** of the column. Append any punctuation that occurred between the end + ** of the previous token and the end of the document to the output. + ** Then break out of the loop. */ + rc = fts3StringAppend(pOut, &zDoc[iEnd], -1); + } + break; + } + if( iCurrentiLangid, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask + ); + isShiftDone = 1; + + /* Now that the shift has been done, check if the initial "..." are + ** required. They are required if (a) this is not the first fragment, + ** or (b) this fragment does not begin at position 0 of its column. + */ + if( rc==SQLITE_OK ){ + if( iPos>0 || iFragment>0 ){ + rc = fts3StringAppend(pOut, zEllipsis, -1); + }else if( iBegin ){ + rc = fts3StringAppend(pOut, zDoc, iBegin); } } - *paBlob = aByte; + if( rc!=SQLITE_OK || iCurrent=(iPos+nSnippet) ){ + if( isLast ){ + rc = fts3StringAppend(pOut, zEllipsis, -1); + } + break; + } -/* -** Close the blob handle at p->pSegments, if it is open. See comments above -** the sqlite3Fts3ReadBlock() function for details. -*/ -SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){ - sqlite3_blob_close(p->pSegments); - p->pSegments = 0; -} - -static int fts3SegReaderIncrRead(Fts3SegReader *pReader){ - int nRead; /* Number of bytes to read */ - int rc; /* Return code */ + /* Set isHighlight to true if this term should be highlighted. */ + isHighlight = (hlmask & ((u64)1 << (iCurrent-iPos)))!=0; - nRead = MIN(pReader->nNode - pReader->nPopulate, FTS3_NODE_CHUNKSIZE); - rc = sqlite3_blob_read( - pReader->pBlob, - &pReader->aNode[pReader->nPopulate], - nRead, - pReader->nPopulate - ); + if( iCurrent>iPos ) rc = fts3StringAppend(pOut, &zDoc[iEnd], iBegin-iEnd); + if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zOpen, -1); + if( rc==SQLITE_OK ) rc = fts3StringAppend(pOut, &zDoc[iBegin], iFin-iBegin); + if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zClose, -1); - if( rc==SQLITE_OK ){ - pReader->nPopulate += nRead; - memset(&pReader->aNode[pReader->nPopulate], 0, FTS3_NODE_PADDING); - if( pReader->nPopulate==pReader->nNode ){ - sqlite3_blob_close(pReader->pBlob); - pReader->pBlob = 0; - pReader->nPopulate = 0; - } + iEnd = iFin; } - return rc; -} -static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){ - int rc = SQLITE_OK; - assert( !pReader->pBlob - || (pFrom>=pReader->aNode && pFrom<&pReader->aNode[pReader->nNode]) - ); - while( pReader->pBlob && rc==SQLITE_OK - && (pFrom - pReader->aNode + nByte)>pReader->nPopulate - ){ - rc = fts3SegReaderIncrRead(pReader); - } + pMod->xClose(pC); return rc; } + /* -** Set an Fts3SegReader cursor to point at EOF. +** This function is used to count the entries in a column-list (a +** delta-encoded list of term offsets within a single column of a single +** row). When this function is called, *ppCollist should point to the +** beginning of the first varint in the column-list (the varint that +** contains the position of the first matching term in the column data). +** Before returning, *ppCollist is set to point to the first byte after +** the last varint in the column-list (either the 0x00 signifying the end +** of the position-list, or the 0x01 that precedes the column number of +** the next column in the position-list). +** +** The number of elements in the column-list is returned. */ -static void fts3SegReaderSetEof(Fts3SegReader *pSeg){ - if( !fts3SegReaderIsRootOnly(pSeg) ){ - sqlite3_free(pSeg->aNode); - sqlite3_blob_close(pSeg->pBlob); - pSeg->pBlob = 0; +static int fts3ColumnlistCount(char **ppCollist){ + char *pEnd = *ppCollist; + char c = 0; + int nEntry = 0; + + /* A column-list is terminated by either a 0x01 or 0x00. */ + while( 0xFE & (*pEnd | c) ){ + c = *pEnd++ & 0x80; + if( !c ) nEntry++; } - pSeg->aNode = 0; + + *ppCollist = pEnd; + return nEntry; } /* -** Move the iterator passed as the first argument to the next term in the -** segment. If successful, SQLITE_OK is returned. If there is no next term, -** SQLITE_DONE. Otherwise, an SQLite error code. +** This function gathers 'y' or 'b' data for a single phrase. */ -static int fts3SegReaderNext( - Fts3Table *p, - Fts3SegReader *pReader, - int bIncr +static int fts3ExprLHits( + Fts3Expr *pExpr, /* Phrase expression node */ + MatchInfo *p /* Matchinfo context */ ){ - int rc; /* Return code of various sub-routines */ - char *pNext; /* Cursor variable */ - int nPrefix; /* Number of bytes in term prefix */ - int nSuffix; /* Number of bytes in term suffix */ + Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab; + int iStart; + Fts3Phrase *pPhrase = pExpr->pPhrase; + char *pIter = pPhrase->doclist.pList; + int iCol = 0; - if( !pReader->aDoclist ){ - pNext = pReader->aNode; + assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS ); + if( p->flag==FTS3_MATCHINFO_LHITS ){ + iStart = pExpr->iPhrase * p->nCol; }else{ - pNext = &pReader->aDoclist[pReader->nDoclist]; + iStart = pExpr->iPhrase * ((p->nCol + 31) / 32); } - if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){ - - if( fts3SegReaderIsPending(pReader) ){ - Fts3HashElem *pElem = *(pReader->ppNextElem); - sqlite3_free(pReader->aNode); - pReader->aNode = 0; - if( pElem ){ - char *aCopy; - PendingList *pList = (PendingList *)fts3HashData(pElem); - int nCopy = pList->nData+1; - pReader->zTerm = (char *)fts3HashKey(pElem); - pReader->nTerm = fts3HashKeysize(pElem); - aCopy = (char*)sqlite3_malloc(nCopy); - if( !aCopy ) return SQLITE_NOMEM; - memcpy(aCopy, pList->aData, nCopy); - pReader->nNode = pReader->nDoclist = nCopy; - pReader->aNode = pReader->aDoclist = aCopy; - pReader->ppNextElem++; - assert( pReader->aNode ); + if( pIter ) while( 1 ){ + int nHit = fts3ColumnlistCount(&pIter); + if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ + if( p->flag==FTS3_MATCHINFO_LHITS ){ + p->aMatchinfo[iStart + iCol] = (u32)nHit; + }else if( nHit ){ + p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); } - return SQLITE_OK; - } - - fts3SegReaderSetEof(pReader); - - /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf - ** blocks have already been traversed. */ - assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock ); - if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){ - return SQLITE_OK; - } - - rc = sqlite3Fts3ReadBlock( - p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode, - (bIncr ? &pReader->nPopulate : 0) - ); - if( rc!=SQLITE_OK ) return rc; - assert( pReader->pBlob==0 ); - if( bIncr && pReader->nPopulatenNode ){ - pReader->pBlob = p->pSegments; - p->pSegments = 0; - } - pNext = pReader->aNode; - } - - assert( !fts3SegReaderIsPending(pReader) ); - - rc = fts3SegReaderRequire(pReader, pNext, FTS3_VARINT_MAX*2); - if( rc!=SQLITE_OK ) return rc; - - /* Because of the FTS3_NODE_PADDING bytes of padding, the following is - ** safe (no risk of overread) even if the node data is corrupted. */ - pNext += fts3GetVarint32(pNext, &nPrefix); - pNext += fts3GetVarint32(pNext, &nSuffix); - if( nPrefix<0 || nSuffix<=0 - || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] - ){ - return FTS_CORRUPT_VTAB; - } - - if( nPrefix+nSuffix>pReader->nTermAlloc ){ - int nNew = (nPrefix+nSuffix)*2; - char *zNew = sqlite3_realloc(pReader->zTerm, nNew); - if( !zNew ){ - return SQLITE_NOMEM; } - pReader->zTerm = zNew; - pReader->nTermAlloc = nNew; - } - - rc = fts3SegReaderRequire(pReader, pNext, nSuffix+FTS3_VARINT_MAX); - if( rc!=SQLITE_OK ) return rc; - - memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix); - pReader->nTerm = nPrefix+nSuffix; - pNext += nSuffix; - pNext += fts3GetVarint32(pNext, &pReader->nDoclist); - pReader->aDoclist = pNext; - pReader->pOffsetList = 0; - - /* Check that the doclist does not appear to extend past the end of the - ** b-tree node. And that the final byte of the doclist is 0x00. If either - ** of these statements is untrue, then the data structure is corrupt. - */ - if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] - || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1]) - ){ - return FTS_CORRUPT_VTAB; + assert( *pIter==0x00 || *pIter==0x01 ); + if( *pIter!=0x01 ) break; + pIter++; + pIter += fts3GetVarint32(pIter, &iCol); + if( iCol>=p->nCol ) return FTS_CORRUPT_VTAB; } return SQLITE_OK; } /* -** Set the SegReader to point to the first docid in the doclist associated -** with the current term. +** Gather the results for matchinfo directives 'y' and 'b'. */ -static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){ +static int fts3ExprLHitGather( + Fts3Expr *pExpr, + MatchInfo *p +){ int rc = SQLITE_OK; - assert( pReader->aDoclist ); - assert( !pReader->pOffsetList ); - if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ - u8 bEof = 0; - pReader->iDocid = 0; - pReader->nOffsetList = 0; - sqlite3Fts3DoclistPrev(0, - pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList, - &pReader->iDocid, &pReader->nOffsetList, &bEof - ); - }else{ - rc = fts3SegReaderRequire(pReader, pReader->aDoclist, FTS3_VARINT_MAX); - if( rc==SQLITE_OK ){ - int n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid); - pReader->pOffsetList = &pReader->aDoclist[n]; + assert( (pExpr->pLeft==0)==(pExpr->pRight==0) ); + if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ + if( pExpr->pLeft ){ + rc = fts3ExprLHitGather(pExpr->pLeft, p); + if( rc==SQLITE_OK ) rc = fts3ExprLHitGather(pExpr->pRight, p); + }else{ + rc = fts3ExprLHits(pExpr, p); } } return rc; } /* -** Advance the SegReader to point to the next docid in the doclist -** associated with the current term. -** -** If arguments ppOffsetList and pnOffsetList are not NULL, then -** *ppOffsetList is set to point to the first column-offset list -** in the doclist entry (i.e. immediately past the docid varint). -** *pnOffsetList is set to the length of the set of column-offset -** lists, not including the nul-terminator byte. For example: +** fts3ExprIterate() callback used to collect the "global" matchinfo stats +** for a single query. +** +** fts3ExprIterate() callback to load the 'global' elements of a +** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements +** of the matchinfo array that are constant for all rows returned by the +** current query. +** +** Argument pCtx is actually a pointer to a struct of type MatchInfo. This +** function populates Matchinfo.aMatchinfo[] as follows: +** +** for(iCol=0; iColpOffsetList; - char c = 0; + MatchInfo *p = (MatchInfo *)pCtx; + return sqlite3Fts3EvalPhraseStats( + p->pCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol] + ); +} - assert( p ); +/* +** fts3ExprIterate() callback used to collect the "local" part of the +** FTS3_MATCHINFO_HITS array. The local stats are those elements of the +** array that are different for each row returned by the query. +*/ +static int fts3ExprLocalHitsCb( + Fts3Expr *pExpr, /* Phrase expression node */ + int iPhrase, /* Phrase number */ + void *pCtx /* Pointer to MatchInfo structure */ +){ + int rc = SQLITE_OK; + MatchInfo *p = (MatchInfo *)pCtx; + int iStart = iPhrase * p->nCol * 3; + int i; - if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){ - /* A pending-terms seg-reader for an FTS4 table that uses order=desc. - ** Pending-terms doclists are always built up in ascending order, so - ** we have to iterate through them backwards here. */ - u8 bEof = 0; - if( ppOffsetList ){ - *ppOffsetList = pReader->pOffsetList; - *pnOffsetList = pReader->nOffsetList - 1; - } - sqlite3Fts3DoclistPrev(0, - pReader->aDoclist, pReader->nDoclist, &p, &pReader->iDocid, - &pReader->nOffsetList, &bEof - ); - if( bEof ){ - pReader->pOffsetList = 0; + for(i=0; inCol && rc==SQLITE_OK; i++){ + char *pCsr; + rc = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i, &pCsr); + if( pCsr ){ + p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr); }else{ - pReader->pOffsetList = p; + p->aMatchinfo[iStart+i*3] = 0; } - }else{ - char *pEnd = &pReader->aDoclist[pReader->nDoclist]; + } - /* Pointer p currently points at the first byte of an offset list. The - ** following block advances it to point one byte past the end of - ** the same offset list. */ - while( 1 ){ - - /* The following line of code (and the "p++" below the while() loop) is - ** normally all that is required to move pointer p to the desired - ** position. The exception is if this node is being loaded from disk - ** incrementally and pointer "p" now points to the first byte past - ** the populated part of pReader->aNode[]. - */ - while( *p | c ) c = *p++ & 0x80; - assert( *p==0 ); - - if( pReader->pBlob==0 || p<&pReader->aNode[pReader->nPopulate] ) break; - rc = fts3SegReaderIncrRead(pReader); - if( rc!=SQLITE_OK ) return rc; - } - p++; - - /* If required, populate the output variables with a pointer to and the - ** size of the previous offset-list. - */ - if( ppOffsetList ){ - *ppOffsetList = pReader->pOffsetList; - *pnOffsetList = (int)(p - pReader->pOffsetList - 1); - } + return rc; +} - /* List may have been edited in place by fts3EvalNearTrim() */ - while( p=pEnd ){ - pReader->pOffsetList = 0; - }else{ - rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX); - if( rc==SQLITE_OK ){ - sqlite3_int64 iDelta; - pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta); - if( pTab->bDescIdx ){ - pReader->iDocid -= iDelta; - }else{ - pReader->iDocid += iDelta; - } - } - } +static int fts3MatchinfoCheck( + Fts3Table *pTab, + char cArg, + char **pzErr +){ + if( (cArg==FTS3_MATCHINFO_NPHRASE) + || (cArg==FTS3_MATCHINFO_NCOL) + || (cArg==FTS3_MATCHINFO_NDOC && pTab->bFts4) + || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bFts4) + || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize) + || (cArg==FTS3_MATCHINFO_LCS) + || (cArg==FTS3_MATCHINFO_HITS) + || (cArg==FTS3_MATCHINFO_LHITS) + || (cArg==FTS3_MATCHINFO_LHITS_BM) + ){ + return SQLITE_OK; } - - return SQLITE_OK; + sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); + return SQLITE_ERROR; } +static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ + size_t nVal; /* Number of integers output by cArg */ -SQLITE_PRIVATE int sqlite3Fts3MsrOvfl( - Fts3Cursor *pCsr, - Fts3MultiSegReader *pMsr, - int *pnOvfl -){ - Fts3Table *p = (Fts3Table*)pCsr->base.pVtab; - int nOvfl = 0; - int ii; - int rc = SQLITE_OK; - int pgsz = p->nPgsz; + switch( cArg ){ + case FTS3_MATCHINFO_NDOC: + case FTS3_MATCHINFO_NPHRASE: + case FTS3_MATCHINFO_NCOL: + nVal = 1; + break; - assert( p->bFts4 ); - assert( pgsz>0 ); + case FTS3_MATCHINFO_AVGLENGTH: + case FTS3_MATCHINFO_LENGTH: + case FTS3_MATCHINFO_LCS: + nVal = pInfo->nCol; + break; - for(ii=0; rc==SQLITE_OK && iinSegment; ii++){ - Fts3SegReader *pReader = pMsr->apSegment[ii]; - if( !fts3SegReaderIsPending(pReader) - && !fts3SegReaderIsRootOnly(pReader) - ){ - sqlite3_int64 jj; - for(jj=pReader->iStartBlock; jj<=pReader->iLeafEndBlock; jj++){ - int nBlob; - rc = sqlite3Fts3ReadBlock(p, jj, 0, &nBlob, 0); - if( rc!=SQLITE_OK ) break; - if( (nBlob+35)>pgsz ){ - nOvfl += (nBlob + 34)/pgsz; - } - } - } - } - *pnOvfl = nOvfl; - return rc; -} + case FTS3_MATCHINFO_LHITS: + nVal = pInfo->nCol * pInfo->nPhrase; + break; -/* -** Free all allocations associated with the iterator passed as the -** second argument. -*/ -SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ - if( pReader ){ - if( !fts3SegReaderIsPending(pReader) ){ - sqlite3_free(pReader->zTerm); - } - if( !fts3SegReaderIsRootOnly(pReader) ){ - sqlite3_free(pReader->aNode); - } - sqlite3_blob_close(pReader->pBlob); + case FTS3_MATCHINFO_LHITS_BM: + nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + break; + + default: + assert( cArg==FTS3_MATCHINFO_HITS ); + nVal = pInfo->nCol * pInfo->nPhrase * 3; + break; } - sqlite3_free(pReader); + + return nVal; } -/* -** Allocate a new SegReader object. -*/ -SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( - int iAge, /* Segment "age". */ - int bLookup, /* True for a lookup only */ - sqlite3_int64 iStartLeaf, /* First leaf to traverse */ - sqlite3_int64 iEndLeaf, /* Final leaf to traverse */ - sqlite3_int64 iEndBlock, /* Final block of segment */ - const char *zRoot, /* Buffer containing root node */ - int nRoot, /* Size of buffer containing root node */ - Fts3SegReader **ppReader /* OUT: Allocated Fts3SegReader */ +static int fts3MatchinfoSelectDoctotal( + Fts3Table *pTab, + sqlite3_stmt **ppStmt, + sqlite3_int64 *pnDoc, + const char **paLen, + const char **ppEnd ){ - Fts3SegReader *pReader; /* Newly allocated SegReader object */ - int nExtra = 0; /* Bytes to allocate segment root node */ + sqlite3_stmt *pStmt; + const char *a; + const char *pEnd; + sqlite3_int64 nDoc; + int n; - assert( iStartLeaf<=iEndLeaf ); - if( iStartLeaf==0 ){ - nExtra = nRoot + FTS3_NODE_PADDING; - } - pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); - if( !pReader ){ - return SQLITE_NOMEM; + if( !*ppStmt ){ + int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt); + if( rc!=SQLITE_OK ) return rc; } - memset(pReader, 0, sizeof(Fts3SegReader)); - pReader->iIdx = iAge; - pReader->bLookup = bLookup!=0; - pReader->iStartBlock = iStartLeaf; - pReader->iLeafEndBlock = iEndLeaf; - pReader->iEndBlock = iEndBlock; + pStmt = *ppStmt; + assert( sqlite3_data_count(pStmt)==1 ); - if( nExtra ){ - /* The entire segment is stored in the root node. */ - pReader->aNode = (char *)&pReader[1]; - pReader->rootOnly = 1; - pReader->nNode = nRoot; - memcpy(pReader->aNode, zRoot, nRoot); - memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING); - }else{ - pReader->iCurrentBlock = iStartLeaf-1; + n = sqlite3_column_bytes(pStmt, 0); + a = sqlite3_column_blob(pStmt, 0); + if( a==0 ){ + return FTS_CORRUPT_VTAB; } - *ppReader = pReader; + pEnd = a + n; + a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc); + if( nDoc<=0 || a>pEnd ){ + return FTS_CORRUPT_VTAB; + } + *pnDoc = nDoc; + + if( paLen ) *paLen = a; + if( ppEnd ) *ppEnd = pEnd; + return SQLITE_OK; +} + +/* +** An instance of the following structure is used to store state while +** iterating through a multi-column position-list corresponding to the +** hits for a single phrase on a single row in order to calculate the +** values for a matchinfo() FTS3_MATCHINFO_LCS request. +*/ +typedef struct LcsIterator LcsIterator; +struct LcsIterator { + Fts3Expr *pExpr; /* Pointer to phrase expression */ + int iPosOffset; /* Tokens count up to end of this phrase */ + char *pRead; /* Cursor used to iterate through aDoclist */ + int iPos; /* Current position */ +}; + +/* +** If LcsIterator.iCol is set to the following value, the iterator has +** finished iterating through all offsets for all columns. +*/ +#define LCS_ITERATOR_FINISHED 0x7FFFFFFF; + +static int fts3MatchinfoLcsCb( + Fts3Expr *pExpr, /* Phrase expression node */ + int iPhrase, /* Phrase number (numbered from zero) */ + void *pCtx /* Pointer to MatchInfo structure */ +){ + LcsIterator *aIter = (LcsIterator *)pCtx; + aIter[iPhrase].pExpr = pExpr; return SQLITE_OK; } /* -** This is a comparison function used as a qsort() callback when sorting -** an array of pending terms by term. This occurs as part of flushing -** the contents of the pending-terms hash table to the database. +** Advance the iterator passed as an argument to the next position. Return +** 1 if the iterator is at EOF or if it now points to the start of the +** position list for the next column. */ -static int SQLITE_CDECL fts3CompareElemByTerm( - const void *lhs, - const void *rhs -){ - char *z1 = fts3HashKey(*(Fts3HashElem **)lhs); - char *z2 = fts3HashKey(*(Fts3HashElem **)rhs); - int n1 = fts3HashKeysize(*(Fts3HashElem **)lhs); - int n2 = fts3HashKeysize(*(Fts3HashElem **)rhs); +static int fts3LcsIteratorAdvance(LcsIterator *pIter){ + char *pRead; + sqlite3_int64 iRead; + int rc = 0; - int n = (n1pRead; + pRead += sqlite3Fts3GetVarint(pRead, &iRead); + if( iRead==0 || iRead==1 ){ + pRead = 0; + rc = 1; + }else{ + pIter->iPos += (int)(iRead-2); } - return c; + + pIter->pRead = pRead; + return rc; } /* -** This function is used to allocate an Fts3SegReader that iterates through -** a subset of the terms stored in the Fts3Table.pendingTerms array. -** -** If the isPrefixIter parameter is zero, then the returned SegReader iterates -** through each term in the pending-terms table. Or, if isPrefixIter is -** non-zero, it iterates through each term and its prefixes. For example, if -** the pending terms hash table contains the terms "sqlite", "mysql" and -** "firebird", then the iterator visits the following 'terms' (in the order -** shown): -** -** f fi fir fire fireb firebi firebir firebird -** m my mys mysq mysql -** s sq sql sqli sqlit sqlite +** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag. ** -** Whereas if isPrefixIter is zero, the terms visited are: +** If the call is successful, the longest-common-substring lengths for each +** column are written into the first nCol elements of the pInfo->aMatchinfo[] +** array before returning. SQLITE_OK is returned in this case. ** -** firebird mysql sqlite +** Otherwise, if an error occurs, an SQLite error code is returned and the +** data written to the first nCol elements of pInfo->aMatchinfo[] is +** undefined. */ -SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( - Fts3Table *p, /* Virtual table handle */ - int iIndex, /* Index for p->aIndex */ - const char *zTerm, /* Term to search for */ - int nTerm, /* Size of buffer zTerm */ - int bPrefix, /* True for a prefix iterator */ - Fts3SegReader **ppReader /* OUT: SegReader for pending-terms */ -){ - Fts3SegReader *pReader = 0; /* Fts3SegReader object to return */ - Fts3HashElem *pE; /* Iterator variable */ - Fts3HashElem **aElem = 0; /* Array of term hash entries to scan */ - int nElem = 0; /* Size of array at aElem */ - int rc = SQLITE_OK; /* Return Code */ - Fts3Hash *pHash; +static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ + LcsIterator *aIter; + int i; + int iCol; + int nToken = 0; + int rc = SQLITE_OK; - pHash = &p->aIndex[iIndex].hPending; - if( bPrefix ){ - int nAlloc = 0; /* Size of allocated array at aElem */ + /* Allocate and populate the array of LcsIterator objects. The array + ** contains one element for each matchable phrase in the query. + **/ + aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase); + if( !aIter ) return SQLITE_NOMEM; + (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); - for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){ - char *zKey = (char *)fts3HashKey(pE); - int nKey = fts3HashKeysize(pE); - if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){ - if( nElem==nAlloc ){ - Fts3HashElem **aElem2; - nAlloc += 16; - aElem2 = (Fts3HashElem **)sqlite3_realloc( - aElem, nAlloc*sizeof(Fts3HashElem *) - ); - if( !aElem2 ){ - rc = SQLITE_NOMEM; - nElem = 0; - break; - } - aElem = aElem2; - } + for(i=0; inPhrase; i++){ + LcsIterator *pIter = &aIter[i]; + nToken -= pIter->pExpr->pPhrase->nToken; + pIter->iPosOffset = nToken; + } - aElem[nElem++] = pE; + for(iCol=0; iColnCol; iCol++){ + int nLcs = 0; /* LCS value for this column */ + int nLive = 0; /* Number of iterators in aIter not at EOF */ + + for(i=0; inPhrase; i++){ + LcsIterator *pIt = &aIter[i]; + rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead); + if( rc!=SQLITE_OK ) goto matchinfo_lcs_out; + if( pIt->pRead ){ + pIt->iPos = pIt->iPosOffset; + fts3LcsIteratorAdvance(pIt); + if( pIt->pRead==0 ){ + rc = FTS_CORRUPT_VTAB; + goto matchinfo_lcs_out; + } + nLive++; } } - /* If more than one term matches the prefix, sort the Fts3HashElem - ** objects in term order using qsort(). This uses the same comparison - ** callback as is used when flushing terms to disk. - */ - if( nElem>1 ){ - qsort(aElem, nElem, sizeof(Fts3HashElem *), fts3CompareElemByTerm); - } + while( nLive>0 ){ + LcsIterator *pAdv = 0; /* The iterator to advance by one position */ + int nThisLcs = 0; /* LCS for the current iterator positions */ - }else{ - /* The query is a simple term lookup that matches at most one term in - ** the index. All that is required is a straight hash-lookup. - ** - ** Because the stack address of pE may be accessed via the aElem pointer - ** below, the "Fts3HashElem *pE" must be declared so that it is valid - ** within this entire function, not just this "else{...}" block. - */ - pE = fts3HashFindElem(pHash, zTerm, nTerm); - if( pE ){ - aElem = &pE; - nElem = 1; + for(i=0; inPhrase; i++){ + LcsIterator *pIter = &aIter[i]; + if( pIter->pRead==0 ){ + /* This iterator is already at EOF for this column. */ + nThisLcs = 0; + }else{ + if( pAdv==0 || pIter->iPosiPos ){ + pAdv = pIter; + } + if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){ + nThisLcs++; + }else{ + nThisLcs = 1; + } + if( nThisLcs>nLcs ) nLcs = nThisLcs; + } + } + if( fts3LcsIteratorAdvance(pAdv) ) nLive--; } - } - if( nElem>0 ){ - int nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); - pReader = (Fts3SegReader *)sqlite3_malloc(nByte); - if( !pReader ){ - rc = SQLITE_NOMEM; - }else{ - memset(pReader, 0, nByte); - pReader->iIdx = 0x7FFFFFFF; - pReader->ppNextElem = (Fts3HashElem **)&pReader[1]; - memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *)); - } + pInfo->aMatchinfo[iCol] = nLcs; } - if( bPrefix ){ - sqlite3_free(aElem); - } - *ppReader = pReader; + matchinfo_lcs_out: + sqlite3_free(aIter); return rc; } /* -** Compare the entries pointed to by two Fts3SegReader structures. -** Comparison is as follows: -** -** 1) EOF is greater than not EOF. +** Populate the buffer pInfo->aMatchinfo[] with an array of integers to +** be returned by the matchinfo() function. Argument zArg contains the +** format string passed as the second argument to matchinfo (or the +** default value "pcx" if no second argument was specified). The format +** string has already been validated and the pInfo->aMatchinfo[] array +** is guaranteed to be large enough for the output. ** -** 2) The current terms (if any) are compared using memcmp(). If one -** term is a prefix of another, the longer term is considered the -** larger. +** If bGlobal is true, then populate all fields of the matchinfo() output. +** If it is false, then assume that those fields that do not change between +** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS) +** have already been populated. ** -** 3) By segment age. An older segment is considered larger. +** Return SQLITE_OK if successful, or an SQLite error code if an error +** occurs. If a value other than SQLITE_OK is returned, the state the +** pInfo->aMatchinfo[] buffer is left in is undefined. */ -static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ - int rc; - if( pLhs->aNode && pRhs->aNode ){ - int rc2 = pLhs->nTerm - pRhs->nTerm; - if( rc2<0 ){ - rc = memcmp(pLhs->zTerm, pRhs->zTerm, pLhs->nTerm); - }else{ - rc = memcmp(pLhs->zTerm, pRhs->zTerm, pRhs->nTerm); - } - if( rc==0 ){ - rc = rc2; - } - }else{ - rc = (pLhs->aNode==0) - (pRhs->aNode==0); - } - if( rc==0 ){ - rc = pRhs->iIdx - pLhs->iIdx; - } - assert( rc!=0 ); - return rc; -} +static int fts3MatchinfoValues( + Fts3Cursor *pCsr, /* FTS3 cursor object */ + int bGlobal, /* True to grab the global stats */ + MatchInfo *pInfo, /* Matchinfo context object */ + const char *zArg /* Matchinfo format string */ +){ + int rc = SQLITE_OK; + int i; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + sqlite3_stmt *pSelect = 0; -/* -** A different comparison function for SegReader structures. In this -** version, it is assumed that each SegReader points to an entry in -** a doclist for identical terms. Comparison is made as follows: -** -** 1) EOF (end of doclist in this case) is greater than not EOF. -** -** 2) By current docid. -** -** 3) By segment age. An older segment is considered larger. -*/ -static int fts3SegReaderDoclistCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ - int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); - if( rc==0 ){ - if( pLhs->iDocid==pRhs->iDocid ){ - rc = pRhs->iIdx - pLhs->iIdx; - }else{ - rc = (pLhs->iDocid > pRhs->iDocid) ? 1 : -1; - } - } - assert( pLhs->aNode && pRhs->aNode ); - return rc; -} -static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ - int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); - if( rc==0 ){ - if( pLhs->iDocid==pRhs->iDocid ){ - rc = pRhs->iIdx - pLhs->iIdx; - }else{ - rc = (pLhs->iDocid < pRhs->iDocid) ? 1 : -1; + for(i=0; rc==SQLITE_OK && zArg[i]; i++){ + pInfo->flag = zArg[i]; + switch( zArg[i] ){ + case FTS3_MATCHINFO_NPHRASE: + if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase; + break; + + case FTS3_MATCHINFO_NCOL: + if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol; + break; + + case FTS3_MATCHINFO_NDOC: + if( bGlobal ){ + sqlite3_int64 nDoc = 0; + rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0, 0); + pInfo->aMatchinfo[0] = (u32)nDoc; + } + break; + + case FTS3_MATCHINFO_AVGLENGTH: + if( bGlobal ){ + sqlite3_int64 nDoc; /* Number of rows in table */ + const char *a; /* Aggregate column length array */ + const char *pEnd; /* First byte past end of length array */ + + rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a, &pEnd); + if( rc==SQLITE_OK ){ + int iCol; + for(iCol=0; iColnCol; iCol++){ + u32 iVal; + sqlite3_int64 nToken; + a += sqlite3Fts3GetVarint(a, &nToken); + if( a>pEnd ){ + rc = SQLITE_CORRUPT_VTAB; + break; + } + iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc); + pInfo->aMatchinfo[iCol] = iVal; + } + } + } + break; + + case FTS3_MATCHINFO_LENGTH: { + sqlite3_stmt *pSelectDocsize = 0; + rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize); + if( rc==SQLITE_OK ){ + int iCol; + const char *a = sqlite3_column_blob(pSelectDocsize, 0); + const char *pEnd = a + sqlite3_column_bytes(pSelectDocsize, 0); + for(iCol=0; iColnCol; iCol++){ + sqlite3_int64 nToken; + a += sqlite3Fts3GetVarintBounded(a, pEnd, &nToken); + if( a>pEnd ){ + rc = SQLITE_CORRUPT_VTAB; + break; + } + pInfo->aMatchinfo[iCol] = (u32)nToken; + } + } + sqlite3_reset(pSelectDocsize); + break; + } + + case FTS3_MATCHINFO_LCS: + rc = fts3ExprLoadDoclists(pCsr, 0, 0); + if( rc==SQLITE_OK ){ + rc = fts3MatchinfoLcs(pCsr, pInfo); + } + break; + + case FTS3_MATCHINFO_LHITS_BM: + case FTS3_MATCHINFO_LHITS: { + size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); + memset(pInfo->aMatchinfo, 0, nZero); + rc = fts3ExprLHitGather(pCsr->pExpr, pInfo); + break; + } + + default: { + Fts3Expr *pExpr; + assert( zArg[i]==FTS3_MATCHINFO_HITS ); + pExpr = pCsr->pExpr; + rc = fts3ExprLoadDoclists(pCsr, 0, 0); + if( rc!=SQLITE_OK ) break; + if( bGlobal ){ + if( pCsr->pDeferred ){ + rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0); + if( rc!=SQLITE_OK ) break; + } + rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); + sqlite3Fts3EvalTestDeferred(pCsr, &rc); + if( rc!=SQLITE_OK ) break; + } + (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); + break; + } } + + pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]); } - assert( pLhs->aNode && pRhs->aNode ); + + sqlite3_reset(pSelect); return rc; } + /* -** Compare the term that the Fts3SegReader object passed as the first argument -** points to with the term specified by arguments zTerm and nTerm. -** -** If the pSeg iterator is already at EOF, return 0. Otherwise, return -** -ve if the pSeg term is less than zTerm/nTerm, 0 if the two terms are -** equal, or +ve if the pSeg term is greater than zTerm/nTerm. +** Populate pCsr->aMatchinfo[] with data for the current row. The +** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32). */ -static int fts3SegReaderTermCmp( - Fts3SegReader *pSeg, /* Segment reader object */ - const char *zTerm, /* Term to compare to */ - int nTerm /* Size of term zTerm in bytes */ +static void fts3GetMatchinfo( + sqlite3_context *pCtx, /* Return results here */ + Fts3Cursor *pCsr, /* FTS3 Cursor object */ + const char *zArg /* Second argument to matchinfo() function */ ){ - int res = 0; - if( pSeg->aNode ){ - if( pSeg->nTerm>nTerm ){ - res = memcmp(pSeg->zTerm, zTerm, nTerm); - }else{ - res = memcmp(pSeg->zTerm, zTerm, pSeg->nTerm); - } - if( res==0 ){ - res = pSeg->nTerm-nTerm; - } + MatchInfo sInfo; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int bGlobal = 0; /* Collect 'global' stats as well as local */ + + u32 *aOut = 0; + void (*xDestroyOut)(void*) = 0; + + memset(&sInfo, 0, sizeof(MatchInfo)); + sInfo.pCursor = pCsr; + sInfo.nCol = pTab->nColumn; + + /* If there is cached matchinfo() data, but the format string for the + ** cache does not match the format string for this request, discard + ** the cached data. */ + if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){ + sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); + pCsr->pMIBuffer = 0; } - return res; -} -/* -** Argument apSegment is an array of nSegment elements. It is known that -** the final (nSegment-nSuspect) members are already in sorted order -** (according to the comparison function provided). This function shuffles -** the array around until all entries are in sorted order. -*/ -static void fts3SegReaderSort( - Fts3SegReader **apSegment, /* Array to sort entries of */ - int nSegment, /* Size of apSegment array */ - int nSuspect, /* Unsorted entry count */ - int (*xCmp)(Fts3SegReader *, Fts3SegReader *) /* Comparison function */ -){ - int i; /* Iterator variable */ + /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the + ** matchinfo function has been called for this query. In this case + ** allocate the array used to accumulate the matchinfo data and + ** initialize those elements that are constant for every row. + */ + if( pCsr->pMIBuffer==0 ){ + size_t nMatchinfo = 0; /* Number of u32 elements in match-info */ + int i; /* Used to iterate through zArg */ - assert( nSuspect<=nSegment ); + /* Determine the number of phrases in the query */ + pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr); + sInfo.nPhrase = pCsr->nPhrase; - if( nSuspect==nSegment ) nSuspect--; - for(i=nSuspect-1; i>=0; i--){ - int j; - for(j=i; j<(nSegment-1); j++){ - Fts3SegReader *pTmp; - if( xCmp(apSegment[j], apSegment[j+1])<0 ) break; - pTmp = apSegment[j+1]; - apSegment[j+1] = apSegment[j]; - apSegment[j] = pTmp; + /* Determine the number of integers in the buffer returned by this call. */ + for(i=0; zArg[i]; i++){ + char *zErr = 0; + if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){ + sqlite3_result_error(pCtx, zErr, -1); + sqlite3_free(zErr); + return; + } + nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]); } - } -#ifndef NDEBUG - /* Check that the list really is sorted now. */ - for(i=0; i<(nSuspect-1); i++){ - assert( xCmp(apSegment[i], apSegment[i+1])<0 ); - } -#endif -} + /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */ + pCsr->pMIBuffer = fts3MIBufferNew(nMatchinfo, zArg); + if( !pCsr->pMIBuffer ) rc = SQLITE_NOMEM; -/* -** Insert a record into the %_segments table. -*/ -static int fts3WriteSegment( - Fts3Table *p, /* Virtual table handle */ - sqlite3_int64 iBlock, /* Block id for new block */ - char *z, /* Pointer to buffer containing block data */ - int n /* Size of buffer z in bytes */ -){ - sqlite3_stmt *pStmt; - int rc = fts3SqlStmt(p, SQL_INSERT_SEGMENTS, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pStmt, 1, iBlock); - sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC); - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); + pCsr->isMatchinfoNeeded = 1; + bGlobal = 1; } - return rc; -} - -/* -** Find the largest relative level number in the table. If successful, set -** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs, -** set *pnMax to zero and return an SQLite error code. -*/ -SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){ - int rc; - int mxLevel = 0; - sqlite3_stmt *pStmt = 0; - rc = fts3SqlStmt(p, SQL_SELECT_MXLEVEL, &pStmt, 0); if( rc==SQLITE_OK ){ - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - mxLevel = sqlite3_column_int(pStmt, 0); + xDestroyOut = fts3MIBufferAlloc(pCsr->pMIBuffer, &aOut); + if( xDestroyOut==0 ){ + rc = SQLITE_NOMEM; } - rc = sqlite3_reset(pStmt); } - *pnMax = mxLevel; - return rc; -} -/* -** Insert a record into the %_segdir table. -*/ -static int fts3WriteSegdir( - Fts3Table *p, /* Virtual table handle */ - sqlite3_int64 iLevel, /* Value for "level" field (absolute level) */ - int iIdx, /* Value for "idx" field */ - sqlite3_int64 iStartBlock, /* Value for "start_block" field */ - sqlite3_int64 iLeafEndBlock, /* Value for "leaves_end_block" field */ - sqlite3_int64 iEndBlock, /* Value for "end_block" field */ - sqlite3_int64 nLeafData, /* Bytes of leaf data in segment */ - char *zRoot, /* Blob value for "root" field */ - int nRoot /* Number of bytes in buffer zRoot */ -){ - sqlite3_stmt *pStmt; - int rc = fts3SqlStmt(p, SQL_INSERT_SEGDIR, &pStmt, 0); if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pStmt, 1, iLevel); - sqlite3_bind_int(pStmt, 2, iIdx); - sqlite3_bind_int64(pStmt, 3, iStartBlock); - sqlite3_bind_int64(pStmt, 4, iLeafEndBlock); - if( nLeafData==0 ){ - sqlite3_bind_int64(pStmt, 5, iEndBlock); - }else{ - char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); - if( !zEnd ) return SQLITE_NOMEM; - sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); + sInfo.aMatchinfo = aOut; + sInfo.nPhrase = pCsr->nPhrase; + rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg); + if( bGlobal ){ + fts3MIBufferSetGlobal(pCsr->pMIBuffer); } - sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); } - return rc; -} -/* -** Return the size of the common prefix (if any) shared by zPrev and -** zNext, in bytes. For example, -** -** fts3PrefixCompress("abc", 3, "abcdef", 6) // returns 3 -** fts3PrefixCompress("abX", 3, "abcdef", 6) // returns 2 -** fts3PrefixCompress("abX", 3, "Xbcdef", 6) // returns 0 -*/ -static int fts3PrefixCompress( - const char *zPrev, /* Buffer containing previous term */ - int nPrev, /* Size of buffer zPrev in bytes */ - const char *zNext, /* Buffer containing next term */ - int nNext /* Size of buffer zNext in bytes */ -){ - int n; - UNUSED_PARAMETER(nNext); - for(n=0; npMIBuffer->nElem * sizeof(u32); + sqlite3_result_blob(pCtx, aOut, n, xDestroyOut); + } } /* -** Add term zTerm to the SegmentNode. It is guaranteed that zTerm is larger -** (according to memcmp) than the previous term. +** Implementation of snippet() function. */ -static int fts3NodeAddTerm( - Fts3Table *p, /* Virtual table handle */ - SegmentNode **ppTree, /* IN/OUT: SegmentNode handle */ - int isCopyTerm, /* True if zTerm/nTerm is transient */ - const char *zTerm, /* Pointer to buffer containing term */ - int nTerm /* Size of term in bytes */ +SQLITE_PRIVATE void sqlite3Fts3Snippet( + sqlite3_context *pCtx, /* SQLite function call context */ + Fts3Cursor *pCsr, /* Cursor object */ + const char *zStart, /* Snippet start text - "" */ + const char *zEnd, /* Snippet end text - "" */ + const char *zEllipsis, /* Snippet ellipsis text - "..." */ + int iCol, /* Extract snippet from this column */ + int nToken /* Approximate number of tokens in snippet */ ){ - SegmentNode *pTree = *ppTree; - int rc; - SegmentNode *pNew; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + int rc = SQLITE_OK; + int i; + StrBuffer res = {0, 0, 0}; - /* First try to append the term to the current node. Return early if - ** this is possible. + /* The returned text includes up to four fragments of text extracted from + ** the data in the current row. The first iteration of the for(...) loop + ** below attempts to locate a single fragment of text nToken tokens in + ** size that contains at least one instance of all phrases in the query + ** expression that appear in the current row. If such a fragment of text + ** cannot be found, the second iteration of the loop attempts to locate + ** a pair of fragments, and so on. */ - if( pTree ){ - int nData = pTree->nData; /* Current size of node in bytes */ - int nReq = nData; /* Required space after adding zTerm */ - int nPrefix; /* Number of bytes of prefix compression */ - int nSuffix; /* Suffix length */ + int nSnippet = 0; /* Number of fragments in this snippet */ + SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */ + int nFToken = -1; /* Number of tokens in each fragment */ - nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm); - nSuffix = nTerm-nPrefix; + if( !pCsr->pExpr ){ + sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); + return; + } - nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix; - if( nReq<=p->nNodeSize || !pTree->zTerm ){ + /* Limit the snippet length to 64 tokens. */ + if( nToken<-64 ) nToken = -64; + if( nToken>+64 ) nToken = +64; - if( nReq>p->nNodeSize ){ - /* An unusual case: this is the first term to be added to the node - ** and the static node buffer (p->nNodeSize bytes) is not large - ** enough. Use a separately malloced buffer instead This wastes - ** p->nNodeSize bytes, but since this scenario only comes about when - ** the database contain two terms that share a prefix of almost 2KB, - ** this is not expected to be a serious problem. - */ - assert( pTree->aData==(char *)&pTree[1] ); - pTree->aData = (char *)sqlite3_malloc(nReq); - if( !pTree->aData ){ - return SQLITE_NOMEM; - } - } + for(nSnippet=1; 1; nSnippet++){ - if( pTree->zTerm ){ - /* There is no prefix-length field for first term in a node */ - nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nPrefix); - } + int iSnip; /* Loop counter 0..nSnippet-1 */ + u64 mCovered = 0; /* Bitmask of phrases covered by snippet */ + u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */ - nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nSuffix); - memcpy(&pTree->aData[nData], &zTerm[nPrefix], nSuffix); - pTree->nData = nData + nSuffix; - pTree->nEntry++; + if( nToken>=0 ){ + nFToken = (nToken+nSnippet-1) / nSnippet; + }else{ + nFToken = -1 * nToken; + } - if( isCopyTerm ){ - if( pTree->nMalloczMalloc, nTerm*2); - if( !zNew ){ - return SQLITE_NOMEM; - } - pTree->nMalloc = nTerm*2; - pTree->zMalloc = zNew; + for(iSnip=0; iSnipnColumn; iRead++){ + SnippetFragment sF = {0, 0, 0, 0}; + int iS = 0; + if( iCol>=0 && iRead!=iCol ) continue; + + /* Find the best snippet of nFToken tokens in column iRead. */ + rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS); + if( rc!=SQLITE_OK ){ + goto snippet_out; + } + if( iS>iBestScore ){ + *pFragment = sF; + iBestScore = iS; } - pTree->zTerm = pTree->zMalloc; - memcpy(pTree->zTerm, zTerm, nTerm); - pTree->nTerm = nTerm; - }else{ - pTree->zTerm = (char *)zTerm; - pTree->nTerm = nTerm; } - return SQLITE_OK; + + mCovered |= pFragment->covered; } + + /* If all query phrases seen by fts3BestSnippet() are present in at least + ** one of the nSnippet snippet fragments, break out of the loop. + */ + assert( (mCovered&mSeen)==mCovered ); + if( mSeen==mCovered || nSnippet==SizeofArray(aSnippet) ) break; } - /* If control flows to here, it was not possible to append zTerm to the - ** current node. Create a new node (a right-sibling of the current node). - ** If this is the first node in the tree, the term is added to it. - ** - ** Otherwise, the term is not added to the new node, it is left empty for - ** now. Instead, the term is inserted into the parent of pTree. If pTree - ** has no parent, one is created here. - */ - pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); - if( !pNew ){ - return SQLITE_NOMEM; + assert( nFToken>0 ); + + for(i=0; inData = 1 + FTS3_VARINT_MAX; - pNew->aData = (char *)&pNew[1]; - if( pTree ){ - SegmentNode *pParent = pTree->pParent; - rc = fts3NodeAddTerm(p, &pParent, isCopyTerm, zTerm, nTerm); - if( pTree->pParent==0 ){ - pTree->pParent = pParent; - } - pTree->pRight = pNew; - pNew->pLeftmost = pTree->pLeftmost; - pNew->pParent = pParent; - pNew->zMalloc = pTree->zMalloc; - pNew->nMalloc = pTree->nMalloc; - pTree->zMalloc = 0; + snippet_out: + sqlite3Fts3SegmentsClose(pTab); + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + sqlite3_free(res.z); }else{ - pNew->pLeftmost = pNew; - rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm); + sqlite3_result_text(pCtx, res.z, -1, sqlite3_free); } - - *ppTree = pNew; - return rc; } -/* -** Helper function for fts3NodeWrite(). -*/ -static int fts3TreeFinishNode( - SegmentNode *pTree, - int iHeight, - sqlite3_int64 iLeftChild -){ - int nStart; - assert( iHeight>=1 && iHeight<128 ); - nStart = FTS3_VARINT_MAX - sqlite3Fts3VarintLen(iLeftChild); - pTree->aData[nStart] = (char)iHeight; - sqlite3Fts3PutVarint(&pTree->aData[nStart+1], iLeftChild); - return nStart; -} -/* -** Write the buffer for the segment node pTree and all of its peers to the -** database. Then call this function recursively to write the parent of -** pTree and its peers to the database. -** -** Except, if pTree is a root node, do not write it to the database. Instead, -** set output variables *paRoot and *pnRoot to contain the root node. -** -** If successful, SQLITE_OK is returned and output variable *piLast is -** set to the largest blockid written to the database (or zero if no -** blocks were written to the db). Otherwise, an SQLite error code is -** returned. -*/ -static int fts3NodeWrite( - Fts3Table *p, /* Virtual table handle */ - SegmentNode *pTree, /* SegmentNode handle */ - int iHeight, /* Height of this node in tree */ - sqlite3_int64 iLeaf, /* Block id of first leaf node */ - sqlite3_int64 iFree, /* Block id of next free slot in %_segments */ - sqlite3_int64 *piLast, /* OUT: Block id of last entry written */ - char **paRoot, /* OUT: Data for root node */ - int *pnRoot /* OUT: Size of root node in bytes */ -){ - int rc = SQLITE_OK; +typedef struct TermOffset TermOffset; +typedef struct TermOffsetCtx TermOffsetCtx; - if( !pTree->pParent ){ - /* Root node of the tree. */ - int nStart = fts3TreeFinishNode(pTree, iHeight, iLeaf); - *piLast = iFree-1; - *pnRoot = pTree->nData - nStart; - *paRoot = &pTree->aData[nStart]; - }else{ - SegmentNode *pIter; - sqlite3_int64 iNextFree = iFree; - sqlite3_int64 iNextLeaf = iLeaf; - for(pIter=pTree->pLeftmost; pIter && rc==SQLITE_OK; pIter=pIter->pRight){ - int nStart = fts3TreeFinishNode(pIter, iHeight, iNextLeaf); - int nWrite = pIter->nData - nStart; - - rc = fts3WriteSegment(p, iNextFree, &pIter->aData[nStart], nWrite); - iNextFree++; - iNextLeaf += (pIter->nEntry+1); - } - if( rc==SQLITE_OK ){ - assert( iNextLeaf==iFree ); - rc = fts3NodeWrite( - p, pTree->pParent, iHeight+1, iFree, iNextFree, piLast, paRoot, pnRoot - ); - } - } +struct TermOffset { + char *pList; /* Position-list */ + i64 iPos; /* Position just read from pList */ + i64 iOff; /* Offset of this term from read positions */ +}; - return rc; -} +struct TermOffsetCtx { + Fts3Cursor *pCsr; + int iCol; /* Column of table to populate aTerm for */ + int iTerm; + sqlite3_int64 iDocid; + TermOffset *aTerm; +}; /* -** Free all memory allocations associated with the tree pTree. +** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets(). */ -static void fts3NodeFree(SegmentNode *pTree){ - if( pTree ){ - SegmentNode *p = pTree->pLeftmost; - fts3NodeFree(p->pParent); - while( p ){ - SegmentNode *pRight = p->pRight; - if( p->aData!=(char *)&p[1] ){ - sqlite3_free(p->aData); - } - assert( pRight==0 || p->zMalloc==0 ); - sqlite3_free(p->zMalloc); - sqlite3_free(p); - p = pRight; - } +static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ + TermOffsetCtx *p = (TermOffsetCtx *)ctx; + int nTerm; /* Number of tokens in phrase */ + int iTerm; /* For looping through nTerm phrase terms */ + char *pList; /* Pointer to position list for phrase */ + i64 iPos = 0; /* First position in position-list */ + int rc; + + UNUSED_PARAMETER(iPhrase); + rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pList); + nTerm = pExpr->pPhrase->nToken; + if( pList ){ + fts3GetDeltaPosition(&pList, &iPos); + assert_fts3_nc( iPos>=0 ); + } + + for(iTerm=0; iTermaTerm[p->iTerm++]; + pT->iOff = nTerm-iTerm-1; + pT->pList = pList; + pT->iPos = iPos; } + + return rc; } /* -** Add a term to the segment being constructed by the SegmentWriter object -** *ppWriter. When adding the first term to a segment, *ppWriter should -** be passed NULL. This function will allocate a new SegmentWriter object -** and return it via the input/output variable *ppWriter in this case. -** -** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. +** Implementation of offsets() function. */ -static int fts3SegWriterAdd( - Fts3Table *p, /* Virtual table handle */ - SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */ - int isCopyTerm, /* True if buffer zTerm must be copied */ - const char *zTerm, /* Pointer to buffer containing term */ - int nTerm, /* Size of term in bytes */ - const char *aDoclist, /* Pointer to buffer containing doclist */ - int nDoclist /* Size of doclist in bytes */ +SQLITE_PRIVATE void sqlite3Fts3Offsets( + sqlite3_context *pCtx, /* SQLite function call context */ + Fts3Cursor *pCsr /* Cursor object */ ){ - int nPrefix; /* Size of term prefix in bytes */ - int nSuffix; /* Size of term suffix in bytes */ - int nReq; /* Number of bytes required on leaf page */ - int nData; - SegmentWriter *pWriter = *ppWriter; - - if( !pWriter ){ - int rc; - sqlite3_stmt *pStmt; - - /* Allocate the SegmentWriter structure */ - pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); - if( !pWriter ) return SQLITE_NOMEM; - memset(pWriter, 0, sizeof(SegmentWriter)); - *ppWriter = pWriter; - - /* Allocate a buffer in which to accumulate data */ - pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); - if( !pWriter->aData ) return SQLITE_NOMEM; - pWriter->nSize = p->nNodeSize; + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule; + int rc; /* Return Code */ + int nToken; /* Number of tokens in query */ + int iCol; /* Column currently being processed */ + StrBuffer res = {0, 0, 0}; /* Result string */ + TermOffsetCtx sCtx; /* Context for fts3ExprTermOffsetInit() */ - /* Find the next free blockid in the %_segments table */ - rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pStmt, 0); - if( rc!=SQLITE_OK ) return rc; - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - pWriter->iFree = sqlite3_column_int64(pStmt, 0); - pWriter->iFirst = pWriter->iFree; - } - rc = sqlite3_reset(pStmt); - if( rc!=SQLITE_OK ) return rc; + if( !pCsr->pExpr ){ + sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); + return; } - nData = pWriter->nData; - nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); - nSuffix = nTerm-nPrefix; + memset(&sCtx, 0, sizeof(sCtx)); + assert( pCsr->isRequireSeek==0 ); - /* Figure out how many bytes are required by this new entry */ - nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */ - sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */ - nSuffix + /* Term suffix */ - sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ - nDoclist; /* Doclist data */ + /* Count the number of terms in the query */ + rc = fts3ExprLoadDoclists(pCsr, 0, &nToken); + if( rc!=SQLITE_OK ) goto offsets_out; - if( nData>0 && nData+nReq>p->nNodeSize ){ - int rc; + /* Allocate the array of TermOffset iterators. */ + sCtx.aTerm = (TermOffset *)sqlite3Fts3MallocZero(sizeof(TermOffset)*nToken); + if( 0==sCtx.aTerm ){ + rc = SQLITE_NOMEM; + goto offsets_out; + } + sCtx.iDocid = pCsr->iPrevId; + sCtx.pCsr = pCsr; - /* The current leaf node is full. Write it out to the database. */ - rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData); - if( rc!=SQLITE_OK ) return rc; - p->nLeafAdd++; + /* Loop through the table columns, appending offset information to + ** string-buffer res for each column. + */ + for(iCol=0; iColnColumn; iCol++){ + sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */ + const char *ZDUMMY; /* Dummy argument used with xNext() */ + int NDUMMY = 0; /* Dummy argument used with xNext() */ + int iStart = 0; + int iEnd = 0; + int iCurrent = 0; + const char *zDoc; + int nDoc; - /* Add the current term to the interior node tree. The term added to - ** the interior tree must: - ** - ** a) be greater than the largest term on the leaf node just written - ** to the database (still available in pWriter->zTerm), and - ** - ** b) be less than or equal to the term about to be added to the new - ** leaf node (zTerm/nTerm). - ** - ** In other words, it must be the prefix of zTerm 1 byte longer than - ** the common prefix (if any) of zTerm and pWriter->zTerm. + /* Initialize the contents of sCtx.aTerm[] for column iCol. This + ** operation may fail if the database contains corrupt records. */ - assert( nPrefixpTree, isCopyTerm, zTerm, nPrefix+1); - if( rc!=SQLITE_OK ) return rc; - - nData = 0; - pWriter->nTerm = 0; + sCtx.iCol = iCol; + sCtx.iTerm = 0; + rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); + if( rc!=SQLITE_OK ) goto offsets_out; - nPrefix = 0; - nSuffix = nTerm; - nReq = 1 + /* varint containing prefix size */ - sqlite3Fts3VarintLen(nTerm) + /* varint containing suffix size */ - nTerm + /* Term suffix */ - sqlite3Fts3VarintLen(nDoclist) + /* Size of doclist */ - nDoclist; /* Doclist data */ - } + /* Retreive the text stored in column iCol. If an SQL NULL is stored + ** in column iCol, jump immediately to the next iteration of the loop. + ** If an OOM occurs while retrieving the data (this can happen if SQLite + ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM + ** to the caller. + */ + zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1); + nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1); + if( zDoc==0 ){ + if( sqlite3_column_type(pCsr->pStmt, iCol+1)==SQLITE_NULL ){ + continue; + } + rc = SQLITE_NOMEM; + goto offsets_out; + } - /* Increase the total number of bytes written to account for the new entry. */ - pWriter->nLeafData += nReq; + /* Initialize a tokenizer iterator to iterate through column iCol. */ + rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, + zDoc, nDoc, &pC + ); + if( rc!=SQLITE_OK ) goto offsets_out; - /* If the buffer currently allocated is too small for this entry, realloc - ** the buffer to make it large enough. - */ - if( nReq>pWriter->nSize ){ - char *aNew = sqlite3_realloc(pWriter->aData, nReq); - if( !aNew ) return SQLITE_NOMEM; - pWriter->aData = aNew; - pWriter->nSize = nReq; - } - assert( nData+nReq<=pWriter->nSize ); + rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); + while( rc==SQLITE_OK ){ + int i; /* Used to loop through terms */ + int iMinPos = 0x7FFFFFFF; /* Position of next token */ + TermOffset *pTerm = 0; /* TermOffset associated with next token */ - /* Append the prefix-compressed term and doclist to the buffer. */ - nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix); - nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix); - memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix); - nData += nSuffix; - nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist); - memcpy(&pWriter->aData[nData], aDoclist, nDoclist); - pWriter->nData = nData + nDoclist; + for(i=0; ipList && (pT->iPos-pT->iOff)iPos-pT->iOff; + pTerm = pT; + } + } - /* Save the current term so that it can be used to prefix-compress the next. - ** If the isCopyTerm parameter is true, then the buffer pointed to by - ** zTerm is transient, so take a copy of the term data. Otherwise, just - ** store a copy of the pointer. - */ - if( isCopyTerm ){ - if( nTerm>pWriter->nMalloc ){ - char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); - if( !zNew ){ - return SQLITE_NOMEM; + if( !pTerm ){ + /* All offsets for this column have been gathered. */ + rc = SQLITE_DONE; + }else{ + assert_fts3_nc( iCurrent<=iMinPos ); + if( 0==(0xFE&*pTerm->pList) ){ + pTerm->pList = 0; + }else{ + fts3GetDeltaPosition(&pTerm->pList, &pTerm->iPos); + } + while( rc==SQLITE_OK && iCurrentxNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); + } + if( rc==SQLITE_OK ){ + char aBuffer[64]; + sqlite3_snprintf(sizeof(aBuffer), aBuffer, + "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart + ); + rc = fts3StringAppend(&res, aBuffer, -1); + }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){ + rc = FTS_CORRUPT_VTAB; + } } - pWriter->nMalloc = nTerm*2; - pWriter->zMalloc = zNew; - pWriter->zTerm = zNew; } - assert( pWriter->zTerm==pWriter->zMalloc ); - memcpy(pWriter->zTerm, zTerm, nTerm); + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + } + + pMod->xClose(pC); + if( rc!=SQLITE_OK ) goto offsets_out; + } + + offsets_out: + sqlite3_free(sCtx.aTerm); + assert( rc!=SQLITE_DONE ); + sqlite3Fts3SegmentsClose(pTab); + if( rc!=SQLITE_OK ){ + sqlite3_result_error_code(pCtx, rc); + sqlite3_free(res.z); }else{ - pWriter->zTerm = (char *)zTerm; + sqlite3_result_text(pCtx, res.z, res.n-1, sqlite3_free); } - pWriter->nTerm = nTerm; - - return SQLITE_OK; + return; } /* -** Flush all data associated with the SegmentWriter object pWriter to the -** database. This function must be called after all terms have been added -** to the segment using fts3SegWriterAdd(). If successful, SQLITE_OK is -** returned. Otherwise, an SQLite error code. +** Implementation of matchinfo() function. */ -static int fts3SegWriterFlush( - Fts3Table *p, /* Virtual table handle */ - SegmentWriter *pWriter, /* SegmentWriter to flush to the db */ - sqlite3_int64 iLevel, /* Value for 'level' column of %_segdir */ - int iIdx /* Value for 'idx' column of %_segdir */ +SQLITE_PRIVATE void sqlite3Fts3Matchinfo( + sqlite3_context *pContext, /* Function call context */ + Fts3Cursor *pCsr, /* FTS3 table cursor */ + const char *zArg /* Second arg to matchinfo() function */ ){ - int rc; /* Return code */ - if( pWriter->pTree ){ - sqlite3_int64 iLast = 0; /* Largest block id written to database */ - sqlite3_int64 iLastLeaf; /* Largest leaf block id written to db */ - char *zRoot = NULL; /* Pointer to buffer containing root node */ - int nRoot = 0; /* Size of buffer zRoot */ + Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; + const char *zFormat; - iLastLeaf = pWriter->iFree; - rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, pWriter->nData); - if( rc==SQLITE_OK ){ - rc = fts3NodeWrite(p, pWriter->pTree, 1, - pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot); - } - if( rc==SQLITE_OK ){ - rc = fts3WriteSegdir(p, iLevel, iIdx, - pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot); - } + if( zArg ){ + zFormat = zArg; }else{ - /* The entire tree fits on the root node. Write it to the segdir table. */ - rc = fts3WriteSegdir(p, iLevel, iIdx, - 0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData); - } - p->nLeafAdd++; - return rc; -} - -/* -** Release all memory held by the SegmentWriter object passed as the -** first argument. -*/ -static void fts3SegWriterFree(SegmentWriter *pWriter){ - if( pWriter ){ - sqlite3_free(pWriter->aData); - sqlite3_free(pWriter->zMalloc); - fts3NodeFree(pWriter->pTree); - sqlite3_free(pWriter); + zFormat = FTS3_MATCHINFO_DEFAULT; } -} -/* -** The first value in the apVal[] array is assumed to contain an integer. -** This function tests if there exist any documents with docid values that -** are different from that integer. i.e. if deleting the document with docid -** pRowid would mean the FTS3 table were empty. -** -** If successful, *pisEmpty is set to true if the table is empty except for -** document pRowid, or false otherwise, and SQLITE_OK is returned. If an -** error occurs, an SQLite error code is returned. -*/ -static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ - sqlite3_stmt *pStmt; - int rc; - if( p->zContentTbl ){ - /* If using the content=xxx option, assume the table is never empty */ - *pisEmpty = 0; - rc = SQLITE_OK; + if( !pCsr->pExpr ){ + sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC); + return; }else{ - rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); - if( rc==SQLITE_OK ){ - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - *pisEmpty = sqlite3_column_int(pStmt, 0); - } - rc = sqlite3_reset(pStmt); - } + /* Retrieve matchinfo() data. */ + fts3GetMatchinfo(pContext, pCsr, zFormat); + sqlite3Fts3SegmentsClose(pTab); } - return rc; } +#endif + +/************** End of fts3_snippet.c ****************************************/ +/************** Begin file fts3_unicode.c ************************************/ /* -** Set *pnMax to the largest segment level in the database for the index -** iIndex. +** 2012 May 24 ** -** Segment levels are stored in the 'level' column of the %_segdir table. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: ** -** Return SQLITE_OK if successful, or an SQLite error code if not. +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** Implementation of the "unicode" full-text-search tokenizer. */ -static int fts3SegmentMaxLevel( - Fts3Table *p, - int iLangid, - int iIndex, - sqlite3_int64 *pnMax -){ - sqlite3_stmt *pStmt; - int rc; - assert( iIndex>=0 && iIndexnIndex ); - /* Set pStmt to the compiled version of: - ** - ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? - ** - ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). - */ - rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); - if( rc!=SQLITE_OK ) return rc; - sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); - sqlite3_bind_int64(pStmt, 2, - getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) - ); - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - *pnMax = sqlite3_column_int64(pStmt, 0); - } - return sqlite3_reset(pStmt); -} +#ifndef SQLITE_DISABLE_FTS3_UNICODE + +/* #include "fts3Int.h" */ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) + +/* #include */ +/* #include */ +/* #include */ +/* #include */ + +/* #include "fts3_tokenizer.h" */ /* -** iAbsLevel is an absolute level that may be assumed to exist within -** the database. This function checks if it is the largest level number -** within its index. Assuming no error occurs, *pbMax is set to 1 if -** iAbsLevel is indeed the largest level, or 0 otherwise, and SQLITE_OK -** is returned. If an error occurs, an error code is returned and the -** final value of *pbMax is undefined. +** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied +** from the sqlite3 source file utf.c. If this file is compiled as part +** of the amalgamation, they are not required. */ -static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){ +#ifndef SQLITE_AMALGAMATION - /* Set pStmt to the compiled version of: - ** - ** SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? - ** - ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR). - */ - sqlite3_stmt *pStmt; - int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0); - if( rc!=SQLITE_OK ) return rc; - sqlite3_bind_int64(pStmt, 1, iAbsLevel+1); - sqlite3_bind_int64(pStmt, 2, - ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL - ); +static const unsigned char sqlite3Utf8Trans1[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, +}; - *pbMax = 0; - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - *pbMax = sqlite3_column_type(pStmt, 0)==SQLITE_NULL; +#define READ_UTF8(zIn, zTerm, c) \ + c = *(zIn++); \ + if( c>=0xc0 ){ \ + c = sqlite3Utf8Trans1[c-0xc0]; \ + while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ + c = (c<<6) + (0x3f & *(zIn++)); \ + } \ + if( c<0x80 \ + || (c&0xFFFFF800)==0xD800 \ + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ } - return sqlite3_reset(pStmt); + +#define WRITE_UTF8(zOut, c) { \ + if( c<0x00080 ){ \ + *zOut++ = (u8)(c&0xFF); \ + } \ + else if( c<0x00800 ){ \ + *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + } \ + else if( c<0x10000 ){ \ + *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \ + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + }else{ \ + *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \ + *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \ + *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ + *zOut++ = 0x80 + (u8)(c & 0x3F); \ + } \ } +#endif /* ifndef SQLITE_AMALGAMATION */ + +typedef struct unicode_tokenizer unicode_tokenizer; +typedef struct unicode_cursor unicode_cursor; + +struct unicode_tokenizer { + sqlite3_tokenizer base; + int eRemoveDiacritic; + int nException; + int *aiException; +}; + +struct unicode_cursor { + sqlite3_tokenizer_cursor base; + const unsigned char *aInput; /* Input text being tokenized */ + int nInput; /* Size of aInput[] in bytes */ + int iOff; /* Current offset within aInput[] */ + int iToken; /* Index of next token to be returned */ + char *zToken; /* storage for current token */ + int nAlloc; /* space allocated at zToken */ +}; + + /* -** Delete all entries in the %_segments table associated with the segment -** opened with seg-reader pSeg. This function does not affect the contents -** of the %_segdir table. +** Destroy a tokenizer allocated by unicodeCreate(). */ -static int fts3DeleteSegment( - Fts3Table *p, /* FTS table handle */ - Fts3SegReader *pSeg /* Segment to delete */ -){ - int rc = SQLITE_OK; /* Return code */ - if( pSeg->iStartBlock ){ - sqlite3_stmt *pDelete; /* SQL statement to delete rows */ - rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDelete, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pDelete, 1, pSeg->iStartBlock); - sqlite3_bind_int64(pDelete, 2, pSeg->iEndBlock); - sqlite3_step(pDelete); - rc = sqlite3_reset(pDelete); - } +static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){ + if( pTokenizer ){ + unicode_tokenizer *p = (unicode_tokenizer *)pTokenizer; + sqlite3_free(p->aiException); + sqlite3_free(p); } - return rc; + return SQLITE_OK; } /* -** This function is used after merging multiple segments into a single large -** segment to delete the old, now redundant, segment b-trees. Specifically, -** it: -** -** 1) Deletes all %_segments entries for the segments associated with -** each of the SegReader objects in the array passed as the third -** argument, and +** As part of a tokenchars= or separators= option, the CREATE VIRTUAL TABLE +** statement has specified that the tokenizer for this table shall consider +** all characters in string zIn/nIn to be separators (if bAlnum==0) or +** token characters (if bAlnum==1). ** -** 2) deletes all %_segdir entries with level iLevel, or all %_segdir -** entries regardless of level if (iLevel<0). +** For each codepoint in the zIn/nIn string, this function checks if the +** sqlite3FtsUnicodeIsalnum() function already returns the desired result. +** If so, no action is taken. Otherwise, the codepoint is added to the +** unicode_tokenizer.aiException[] array. For the purposes of tokenization, +** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all +** codepoints in the aiException[] array. ** -** SQLITE_OK is returned if successful, otherwise an SQLite error code. +** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic() +** identifies as a diacritic) occurs in the zIn/nIn string it is ignored. +** It is not possible to change the behavior of the tokenizer with respect +** to these codepoints. */ -static int fts3DeleteSegdir( - Fts3Table *p, /* Virtual table handle */ - int iLangid, /* Language id */ - int iIndex, /* Index for p->aIndex */ - int iLevel, /* Level of %_segdir entries to delete */ - Fts3SegReader **apSegment, /* Array of SegReader objects */ - int nReader /* Size of array apSegment */ +static int unicodeAddExceptions( + unicode_tokenizer *p, /* Tokenizer to add exceptions to */ + int bAlnum, /* Replace Isalnum() return value with this */ + const char *zIn, /* Array of characters to make exceptions */ + int nIn /* Length of z in bytes */ ){ - int rc = SQLITE_OK; /* Return Code */ - int i; /* Iterator variable */ - sqlite3_stmt *pDelete = 0; /* SQL statement to delete rows */ + const unsigned char *z = (const unsigned char *)zIn; + const unsigned char *zTerm = &z[nIn]; + unsigned int iCode; + int nEntry = 0; - for(i=0; rc==SQLITE_OK && i=0 || iLevel==FTS3_SEGCURSOR_ALL ); - if( iLevel==FTS3_SEGCURSOR_ALL ){ - rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0)); - sqlite3_bind_int64(pDelete, 2, - getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1) - ); - } - }else{ - rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pDelete, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64( - pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, iLevel) - ); + while( zaiException,(p->nException+nEntry)*sizeof(int)); + if( aNew==0 ) return SQLITE_NOMEM; + nNew = p->nException; + + z = (const unsigned char *)zIn; + while( zi; j--) aNew[j] = aNew[j-1]; + aNew[i] = (int)iCode; + nNew++; + } + } + p->aiException = aNew; + p->nException = nNew; } - return rc; + return SQLITE_OK; } /* -** When this function is called, buffer *ppList (size *pnList bytes) contains -** a position list that may (or may not) feature multiple columns. This -** function adjusts the pointer *ppList and the length *pnList so that they -** identify the subset of the position list that corresponds to column iCol. -** -** If there are no entries in the input position list for column iCol, then -** *pnList is set to zero before returning. -** -** If parameter bZero is non-zero, then any part of the input list following -** the end of the output list is zeroed before returning. +** Return true if the p->aiException[] array contains the value iCode. */ -static void fts3ColumnFilter( - int iCol, /* Column to filter on */ - int bZero, /* Zero out anything following *ppList */ - char **ppList, /* IN/OUT: Pointer to position list */ - int *pnList /* IN/OUT: Size of buffer *ppList in bytes */ -){ - char *pList = *ppList; - int nList = *pnList; - char *pEnd = &pList[nList]; - int iCurrent = 0; - char *p = pList; - - assert( iCol>=0 ); - while( 1 ){ - char c = 0; - while( pnException>0 ){ + int *a = p->aiException; + int iLo = 0; + int iHi = p->nException-1; - nList -= (int)(p - pList); - pList = p; - if( nList==0 ){ - break; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( iCode==a[iTest] ){ + return 1; + }else if( iCode>a[iTest] ){ + iLo = iTest+1; + }else{ + iHi = iTest-1; + } } - p = &pList[1]; - p += fts3GetVarint32(p, &iCurrent); } - if( bZero && &pList[nList]!=pEnd ){ - memset(&pList[nList], 0, pEnd - &pList[nList]); - } - *ppList = pList; - *pnList = nList; + return 0; } /* -** Cache data in the Fts3MultiSegReader.aBuffer[] buffer (overwriting any -** existing data). Grow the buffer if required. -** -** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered -** trying to resize the buffer, return SQLITE_NOMEM. +** Return true if, for the purposes of tokenization, codepoint iCode is +** considered a token character (not a separator). */ -static int fts3MsrBufferData( - Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ - char *pList, - int nList -){ - if( nList>pMsr->nBuffer ){ - char *pNew; - pMsr->nBuffer = nList*2; - pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); - if( !pNew ) return SQLITE_NOMEM; - pMsr->aBuffer = pNew; - } - - memcpy(pMsr->aBuffer, pList, nList); - return SQLITE_OK; +static int unicodeIsAlnum(unicode_tokenizer *p, int iCode){ + assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 ); + return sqlite3FtsUnicodeIsalnum(iCode) ^ unicodeIsException(p, iCode); } -SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( - Fts3Table *p, /* Virtual table handle */ - Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ - sqlite3_int64 *piDocid, /* OUT: Docid value */ - char **paPoslist, /* OUT: Pointer to position list */ - int *pnPoslist /* OUT: Size of position list in bytes */ +/* +** Create a new tokenizer instance. +*/ +static int unicodeCreate( + int nArg, /* Size of array argv[] */ + const char * const *azArg, /* Tokenizer creation arguments */ + sqlite3_tokenizer **pp /* OUT: New tokenizer handle */ ){ - int nMerge = pMsr->nAdvance; - Fts3SegReader **apSegment = pMsr->apSegment; - int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( - p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp - ); - - if( nMerge==0 ){ - *paPoslist = 0; - return SQLITE_OK; - } - - while( 1 ){ - Fts3SegReader *pSeg; - pSeg = pMsr->apSegment[0]; - - if( pSeg->pOffsetList==0 ){ - *paPoslist = 0; - break; - }else{ - int rc; - char *pList; - int nList; - int j; - sqlite3_int64 iDocid = apSegment[0]->iDocid; - - rc = fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); - j = 1; - while( rc==SQLITE_OK - && jpOffsetList - && apSegment[j]->iDocid==iDocid - ){ - rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); - j++; - } - if( rc!=SQLITE_OK ) return rc; - fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); + unicode_tokenizer *pNew; /* New tokenizer object */ + int i; + int rc = SQLITE_OK; - if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ - rc = fts3MsrBufferData(pMsr, pList, nList+1); - if( rc!=SQLITE_OK ) return rc; - assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); - pList = pMsr->aBuffer; - } + pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer)); + if( pNew==NULL ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(unicode_tokenizer)); + pNew->eRemoveDiacritic = 1; - if( pMsr->iColFilter>=0 ){ - fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList); - } + for(i=0; rc==SQLITE_OK && i0 ){ - *paPoslist = pList; - *piDocid = iDocid; - *pnPoslist = nList; - break; - } + if( n==19 && memcmp("remove_diacritics=1", z, 19)==0 ){ + pNew->eRemoveDiacritic = 1; + } + else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){ + pNew->eRemoveDiacritic = 0; + } + else if( n==19 && memcmp("remove_diacritics=2", z, 19)==0 ){ + pNew->eRemoveDiacritic = 2; + } + else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){ + rc = unicodeAddExceptions(pNew, 1, &z[11], n-11); + } + else if( n>=11 && memcmp("separators=", z, 11)==0 ){ + rc = unicodeAddExceptions(pNew, 0, &z[11], n-11); + } + else{ + /* Unrecognized argument */ + rc = SQLITE_ERROR; } } - return SQLITE_OK; + if( rc!=SQLITE_OK ){ + unicodeDestroy((sqlite3_tokenizer *)pNew); + pNew = 0; + } + *pp = (sqlite3_tokenizer *)pNew; + return rc; } -static int fts3SegReaderStart( - Fts3Table *p, /* Virtual table handle */ - Fts3MultiSegReader *pCsr, /* Cursor object */ - const char *zTerm, /* Term searched for (or NULL) */ - int nTerm /* Length of zTerm in bytes */ +/* +** Prepare to begin tokenizing a particular string. The input +** string to be tokenized is pInput[0..nBytes-1]. A cursor +** used to incrementally tokenize this string is returned in +** *ppCursor. +*/ +static int unicodeOpen( + sqlite3_tokenizer *p, /* The tokenizer */ + const char *aInput, /* Input string */ + int nInput, /* Size of string aInput in bytes */ + sqlite3_tokenizer_cursor **pp /* OUT: New cursor object */ ){ - int i; - int nSeg = pCsr->nSegment; + unicode_cursor *pCsr; - /* If the Fts3SegFilter defines a specific term (or term prefix) to search - ** for, then advance each segment iterator until it points to a term of - ** equal or greater value than the specified term. This prevents many - ** unnecessary merge/sort operations for the case where single segment - ** b-tree leaf nodes contain more than one term. - */ - for(i=0; pCsr->bRestart==0 && inSegment; i++){ - int res = 0; - Fts3SegReader *pSeg = pCsr->apSegment[i]; - do { - int rc = fts3SegReaderNext(p, pSeg, 0); - if( rc!=SQLITE_OK ) return rc; - }while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 ); + pCsr = (unicode_cursor *)sqlite3_malloc(sizeof(unicode_cursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(unicode_cursor)); - if( pSeg->bLookup && res!=0 ){ - fts3SegReaderSetEof(pSeg); - } + pCsr->aInput = (const unsigned char *)aInput; + if( aInput==0 ){ + pCsr->nInput = 0; + pCsr->aInput = (const unsigned char*)""; + }else if( nInput<0 ){ + pCsr->nInput = (int)strlen(aInput); + }else{ + pCsr->nInput = nInput; } - fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp); + *pp = &pCsr->base; + UNUSED_PARAMETER(p); return SQLITE_OK; } -SQLITE_PRIVATE int sqlite3Fts3SegReaderStart( - Fts3Table *p, /* Virtual table handle */ - Fts3MultiSegReader *pCsr, /* Cursor object */ - Fts3SegFilter *pFilter /* Restrictions on range of iteration */ -){ - pCsr->pFilter = pFilter; - return fts3SegReaderStart(p, pCsr, pFilter->zTerm, pFilter->nTerm); +/* +** Close a tokenization cursor previously opened by a call to +** simpleOpen() above. +*/ +static int unicodeClose(sqlite3_tokenizer_cursor *pCursor){ + unicode_cursor *pCsr = (unicode_cursor *) pCursor; + sqlite3_free(pCsr->zToken); + sqlite3_free(pCsr); + return SQLITE_OK; } -SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart( - Fts3Table *p, /* Virtual table handle */ - Fts3MultiSegReader *pCsr, /* Cursor object */ - int iCol, /* Column to match on. */ - const char *zTerm, /* Term to iterate through a doclist for */ - int nTerm /* Number of bytes in zTerm */ +/* +** Extract the next token from a tokenization cursor. The cursor must +** have been opened by a prior call to simpleOpen(). +*/ +static int unicodeNext( + sqlite3_tokenizer_cursor *pC, /* Cursor returned by simpleOpen */ + const char **paToken, /* OUT: Token text */ + int *pnToken, /* OUT: Number of bytes at *paToken */ + int *piStart, /* OUT: Starting offset of token */ + int *piEnd, /* OUT: Ending offset of token */ + int *piPos /* OUT: Position integer of token */ ){ - int i; - int rc; - int nSegment = pCsr->nSegment; - int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( - p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp - ); + unicode_cursor *pCsr = (unicode_cursor *)pC; + unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer); + unsigned int iCode = 0; + char *zOut; + const unsigned char *z = &pCsr->aInput[pCsr->iOff]; + const unsigned char *zStart = z; + const unsigned char *zEnd; + const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput]; - assert( pCsr->pFilter==0 ); - assert( zTerm && nTerm>0 ); + /* Scan past any delimiter characters before the start of the next token. + ** Return SQLITE_DONE early if this takes us all the way to the end of + ** the input. */ + while( z=zTerm ) return SQLITE_DONE; - /* Advance each segment iterator until it points to the term zTerm/nTerm. */ - rc = fts3SegReaderStart(p, pCsr, zTerm, nTerm); - if( rc!=SQLITE_OK ) return rc; + zOut = pCsr->zToken; + do { + int iOut; - /* Determine how many of the segments actually point to zTerm/nTerm. */ - for(i=0; iapSegment[i]; - if( !pSeg->aNode || fts3SegReaderTermCmp(pSeg, zTerm, nTerm) ){ - break; + /* Grow the output buffer if required. */ + if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){ + char *zNew = sqlite3_realloc64(pCsr->zToken, pCsr->nAlloc+64); + if( !zNew ) return SQLITE_NOMEM; + zOut = &zNew[zOut - pCsr->zToken]; + pCsr->zToken = zNew; + pCsr->nAlloc += 64; } - } - pCsr->nAdvance = i; - /* Advance each of the segments to point to the first docid. */ - for(i=0; inAdvance; i++){ - rc = fts3SegReaderFirstDocid(p, pCsr->apSegment[i]); - if( rc!=SQLITE_OK ) return rc; - } - fts3SegReaderSort(pCsr->apSegment, i, i, xCmp); + /* Write the folded case of the last character read to the output */ + zEnd = z; + iOut = sqlite3FtsUnicodeFold((int)iCode, p->eRemoveDiacritic); + if( iOut ){ + WRITE_UTF8(zOut, iOut); + } - assert( iCol<0 || iColnColumn ); - pCsr->iColFilter = iCol; + /* If the cursor is not at EOF, read the next character */ + if( z>=zTerm ) break; + READ_UTF8(z, zTerm, iCode); + }while( unicodeIsAlnum(p, (int)iCode) + || sqlite3FtsUnicodeIsdiacritic((int)iCode) + ); + /* Set the output variables and return. */ + pCsr->iOff = (int)(z - pCsr->aInput); + *paToken = pCsr->zToken; + *pnToken = (int)(zOut - pCsr->zToken); + *piStart = (int)(zStart - pCsr->aInput); + *piEnd = (int)(zEnd - pCsr->aInput); + *piPos = pCsr->iToken++; return SQLITE_OK; } /* -** This function is called on a MultiSegReader that has been started using -** sqlite3Fts3MsrIncrStart(). One or more calls to MsrIncrNext() may also -** have been made. Calling this function puts the MultiSegReader in such -** a state that if the next two calls are: -** -** sqlite3Fts3SegReaderStart() -** sqlite3Fts3SegReaderStep() -** -** then the entire doclist for the term is available in -** MultiSegReader.aDoclist/nDoclist. +** Set *ppModule to a pointer to the sqlite3_tokenizer_module +** structure for the unicode tokenizer. */ -SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){ - int i; /* Used to iterate through segment-readers */ - - assert( pCsr->zTerm==0 ); - assert( pCsr->nTerm==0 ); - assert( pCsr->aDoclist==0 ); - assert( pCsr->nDoclist==0 ); - - pCsr->nAdvance = 0; - pCsr->bRestart = 1; - for(i=0; inSegment; i++){ - pCsr->apSegment[i]->pOffsetList = 0; - pCsr->apSegment[i]->nOffsetList = 0; - pCsr->apSegment[i]->iDocid = 0; - } - - return SQLITE_OK; +SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){ + static const sqlite3_tokenizer_module module = { + 0, + unicodeCreate, + unicodeDestroy, + unicodeOpen, + unicodeClose, + unicodeNext, + 0, + }; + *ppModule = &module; } +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ +#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */ -SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( - Fts3Table *p, /* Virtual table handle */ - Fts3MultiSegReader *pCsr /* Cursor object */ -){ - int rc = SQLITE_OK; +/************** End of fts3_unicode.c ****************************************/ +/************** Begin file fts3_unicode2.c ***********************************/ +/* +** 2012-05-25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +*/ - int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY); - int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS); - int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); - int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); - int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); - int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST); +/* +** DO NOT EDIT THIS MACHINE GENERATED FILE. +*/ - Fts3SegReader **apSegment = pCsr->apSegment; - int nSegment = pCsr->nSegment; - Fts3SegFilter *pFilter = pCsr->pFilter; - int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( - p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp - ); +#ifndef SQLITE_DISABLE_FTS3_UNICODE +#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) - if( pCsr->nSegment==0 ) return SQLITE_OK; +/* #include */ - do { - int nMerge; - int i; - - /* Advance the first pCsr->nAdvance entries in the apSegment[] array - ** forward. Then sort the list in order of current term again. - */ - for(i=0; inAdvance; i++){ - Fts3SegReader *pSeg = apSegment[i]; - if( pSeg->bLookup ){ - fts3SegReaderSetEof(pSeg); +/* +** Return true if the argument corresponds to a unicode codepoint +** classified as either a letter or a number. Otherwise false. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ + /* Each unsigned integer in the following array corresponds to a contiguous + ** range of unicode codepoints that are not either letters or numbers (i.e. + ** codepoints for which this function should return 0). + ** + ** The most significant 22 bits in each 32-bit value contain the first + ** codepoint in the range. The least significant 10 bits are used to store + ** the size of the range (always at least 1). In other words, the value + ** ((C<<22) + N) represents a range of N codepoints starting with codepoint + ** C. It is not possible to represent a range larger than 1023 codepoints + ** using this format. + */ + static const unsigned int aEntry[] = { + 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, + 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, + 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, + 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, + 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, + 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, + 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, + 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, + 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, + 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, + 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, + 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, + 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, + 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, + 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, + 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, + 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, + 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, + 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, + 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, + 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, + 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, + 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, + 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, + 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, + 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, + 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, + 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, + 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, + 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, + 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, + 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, + 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, + 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, + 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, + 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, + 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, + 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, + 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, + 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, + 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, + 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, + 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, + 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, + 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, + 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, + 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, + 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, + 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, + 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, + 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, + 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, + 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, + 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, + 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, + 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, + 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, + 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, + 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, + 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, + 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, + 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, + 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, + 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, + 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, + 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, + 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, + 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, + 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, + 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, + 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, + 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, + 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, + 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, + 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, + 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, + 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, + 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, + 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, + 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, + 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, + 0x380400F0, + }; + static const unsigned int aAscii[4] = { + 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, + }; + + if( (unsigned int)c<128 ){ + return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 ); + }else if( (unsigned int)c<(1<<22) ){ + unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; + int iRes = 0; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aEntry[iTest] ){ + iRes = iTest; + iLo = iTest+1; }else{ - rc = fts3SegReaderNext(p, pSeg, 0); + iHi = iTest-1; } - if( rc!=SQLITE_OK ) return rc; } - fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp); - pCsr->nAdvance = 0; - - /* If all the seg-readers are at EOF, we're finished. return SQLITE_OK. */ - assert( rc==SQLITE_OK ); - if( apSegment[0]->aNode==0 ) break; + assert( aEntry[0]=aEntry[iRes] ); + return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); + } + return 1; +} - pCsr->nTerm = apSegment[0]->nTerm; - pCsr->zTerm = apSegment[0]->zTerm; - /* If this is a prefix-search, and if the term that apSegment[0] points - ** to does not share a suffix with pFilter->zTerm/nTerm, then all - ** required callbacks have been made. In this case exit early. - ** - ** Similarly, if this is a search for an exact match, and the first term - ** of segment apSegment[0] is not a match, exit early. - */ - if( pFilter->zTerm && !isScan ){ - if( pCsr->nTermnTerm - || (!isPrefix && pCsr->nTerm>pFilter->nTerm) - || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm) - ){ - break; - } - } +/* +** If the argument is a codepoint corresponding to a lowercase letter +** in the ASCII range with a diacritic added, return the codepoint +** of the ASCII letter only. For example, if passed 235 - "LATIN +** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER +** E"). The resuls of passing a codepoint that corresponds to an +** uppercase letter are undefined. +*/ +static int remove_diacritic(int c, int bComplex){ + unsigned short aDia[] = { + 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, + 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, + 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, + 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, + 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896, + 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106, + 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344, + 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198, + 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468, + 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704, + 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, + 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, + 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, + 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, + 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, + 63182, 63242, 63274, 63310, 63368, 63390, + }; +#define HIBIT ((unsigned char)0x80) + unsigned char aChar[] = { + '\0', 'a', 'c', 'e', 'i', 'n', + 'o', 'u', 'y', 'y', 'a', 'c', + 'd', 'e', 'e', 'g', 'h', 'i', + 'j', 'k', 'l', 'n', 'o', 'r', + 's', 't', 'u', 'u', 'w', 'y', + 'z', 'o', 'u', 'a', 'i', 'o', + 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o', + 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a', + 'e', 'i', 'o', 'r', 'u', 's', + 't', 'h', 'a', 'e', 'o'|HIBIT, 'o', + 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', 'a', 'b', + 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT, + 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT, + 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n', + 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's', + 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w', + 'w', 'x', 'y', 'z', 'h', 't', + 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT, + 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT, + 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y', + }; - nMerge = 1; - while( nMergeaNode - && apSegment[nMerge]->nTerm==pCsr->nTerm - && 0==memcmp(pCsr->zTerm, apSegment[nMerge]->zTerm, pCsr->nTerm) - ){ - nMerge++; + unsigned int key = (((unsigned int)c)<<3) | 0x00000007; + int iRes = 0; + int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; + int iLo = 0; + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + if( key >= aDia[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; } + } + assert( key>=aDia[iRes] ); + if( bComplex==0 && (aChar[iRes] & 0x80) ) return c; + return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F); +} - assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); - if( nMerge==1 - && !isIgnoreEmpty - && !isFirst - && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) - ){ - pCsr->nDoclist = apSegment[0]->nDoclist; - if( fts3SegReaderIsPending(apSegment[0]) ){ - rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); - pCsr->aDoclist = pCsr->aBuffer; - }else{ - pCsr->aDoclist = apSegment[0]->aDoclist; - } - if( rc==SQLITE_OK ) rc = SQLITE_ROW; - }else{ - int nDoclist = 0; /* Size of doclist */ - sqlite3_int64 iPrev = 0; /* Previous docid stored in doclist */ - /* The current term of the first nMerge entries in the array - ** of Fts3SegReader objects is the same. The doclists must be merged - ** and a single term returned with the merged doclist. - */ - for(i=0; ipOffsetList ){ - int j; /* Number of segments that share a docid */ - char *pList = 0; - int nList = 0; - int nByte; - sqlite3_int64 iDocid = apSegment[0]->iDocid; - fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList); - j = 1; - while( jpOffsetList - && apSegment[j]->iDocid==iDocid - ){ - fts3SegReaderNextDocid(p, apSegment[j], 0, 0); - j++; - } +/* +** Return true if the argument interpreted as a unicode codepoint +** is a diacritical modifier character. +*/ +SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){ + unsigned int mask0 = 0x08029FDF; + unsigned int mask1 = 0x000361F8; + if( c<768 || c>817 ) return 0; + return (c < 768+32) ? + (mask0 & ((unsigned int)1 << (c-768))) : + (mask1 & ((unsigned int)1 << (c-768-32))); +} - if( isColFilter ){ - fts3ColumnFilter(pFilter->iCol, 0, &pList, &nList); - } - if( !isIgnoreEmpty || nList>0 ){ +/* +** Interpret the argument as a unicode codepoint. If the codepoint +** is an upper case character that has a lower case equivalent, +** return the codepoint corresponding to the lower case version. +** Otherwise, return a copy of the argument. +** +** The results are undefined if the value passed to this function +** is less than zero. +*/ +SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){ + /* Each entry in the following array defines a rule for folding a range + ** of codepoints to lower case. The rule applies to a range of nRange + ** codepoints starting at codepoint iCode. + ** + ** If the least significant bit in flags is clear, then the rule applies + ** to all nRange codepoints (i.e. all nRange codepoints are upper case and + ** need to be folded). Or, if it is set, then the rule only applies to + ** every second codepoint in the range, starting with codepoint C. + ** + ** The 7 most significant bits in flags are an index into the aiOff[] + ** array. If a specific codepoint C does require folding, then its lower + ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF). + ** + ** The contents of this array are generated by parsing the CaseFolding.txt + ** file distributed as part of the "Unicode Character Database". See + ** http://www.unicode.org for details. + */ + static const struct TableEntry { + unsigned short iCode; + unsigned char flags; + unsigned char nRange; + } aEntry[] = { + {65, 14, 26}, {181, 64, 1}, {192, 14, 23}, + {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, + {313, 1, 16}, {330, 1, 46}, {376, 116, 1}, + {377, 1, 6}, {383, 104, 1}, {385, 50, 1}, + {386, 1, 4}, {390, 44, 1}, {391, 0, 1}, + {393, 42, 2}, {395, 0, 1}, {398, 32, 1}, + {399, 38, 1}, {400, 40, 1}, {401, 0, 1}, + {403, 42, 1}, {404, 46, 1}, {406, 52, 1}, + {407, 48, 1}, {408, 0, 1}, {412, 52, 1}, + {413, 54, 1}, {415, 56, 1}, {416, 1, 6}, + {422, 60, 1}, {423, 0, 1}, {425, 60, 1}, + {428, 0, 1}, {430, 60, 1}, {431, 0, 1}, + {433, 58, 2}, {435, 1, 4}, {439, 62, 1}, + {440, 0, 1}, {444, 0, 1}, {452, 2, 1}, + {453, 0, 1}, {455, 2, 1}, {456, 0, 1}, + {458, 2, 1}, {459, 1, 18}, {478, 1, 18}, + {497, 2, 1}, {498, 1, 4}, {502, 122, 1}, + {503, 134, 1}, {504, 1, 40}, {544, 110, 1}, + {546, 1, 18}, {570, 70, 1}, {571, 0, 1}, + {573, 108, 1}, {574, 68, 1}, {577, 0, 1}, + {579, 106, 1}, {580, 28, 1}, {581, 30, 1}, + {582, 1, 10}, {837, 36, 1}, {880, 1, 4}, + {886, 0, 1}, {902, 18, 1}, {904, 16, 3}, + {908, 26, 1}, {910, 24, 2}, {913, 14, 17}, + {931, 14, 9}, {962, 0, 1}, {975, 4, 1}, + {976, 140, 1}, {977, 142, 1}, {981, 146, 1}, + {982, 144, 1}, {984, 1, 24}, {1008, 136, 1}, + {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1}, + {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1}, + {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32}, + {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1}, + {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38}, + {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1}, + {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1}, + {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6}, + {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6}, + {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8}, + {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2}, + {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1}, + {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2}, + {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2}, + {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2}, + {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1}, + {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16}, + {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47}, + {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1}, + {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1}, + {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1}, + {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2}, + {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1}, + {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14}, + {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1}, + {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1}, + {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1}, + {65313, 14, 26}, + }; + static const unsigned short aiOff[] = { + 1, 2, 8, 15, 16, 26, 28, 32, + 37, 38, 40, 48, 63, 64, 69, 71, + 79, 80, 116, 202, 203, 205, 206, 207, + 209, 210, 211, 213, 214, 217, 218, 219, + 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, + 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, + 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, + 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, + 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, + 65514, 65521, 65527, 65528, 65529, + }; - /* Calculate the 'docid' delta value to write into the merged - ** doclist. */ - sqlite3_int64 iDelta; - if( p->bDescIdx && nDoclist>0 ){ - iDelta = iPrev - iDocid; - }else{ - iDelta = iDocid - iPrev; - } - assert( iDelta>0 || (nDoclist==0 && iDelta==iDocid) ); - assert( nDoclist>0 || iDelta==iDocid ); + int ret = c; - nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); - if( nDoclist+nByte>pCsr->nBuffer ){ - char *aNew; - pCsr->nBuffer = (nDoclist+nByte)*2; - aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); - if( !aNew ){ - return SQLITE_NOMEM; - } - pCsr->aBuffer = aNew; - } + assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); - if( isFirst ){ - char *a = &pCsr->aBuffer[nDoclist]; - int nWrite; - - nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); - if( nWrite ){ - iPrev = iDocid; - nDoclist += nWrite; - } - }else{ - nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); - iPrev = iDocid; - if( isRequirePos ){ - memcpy(&pCsr->aBuffer[nDoclist], pList, nList); - nDoclist += nList; - pCsr->aBuffer[nDoclist++] = '\0'; - } - } - } + if( c<128 ){ + if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); + }else if( c<65536 ){ + const struct TableEntry *p; + int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; + int iLo = 0; + int iRes = -1; - fts3SegReaderSort(apSegment, nMerge, j, xCmp); - } - if( nDoclist>0 ){ - pCsr->aDoclist = pCsr->aBuffer; - pCsr->nDoclist = nDoclist; - rc = SQLITE_ROW; + assert( c>aEntry[0].iCode ); + while( iHi>=iLo ){ + int iTest = (iHi + iLo) / 2; + int cmp = (c - aEntry[iTest].iCode); + if( cmp>=0 ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest-1; } } - pCsr->nAdvance = nMerge; - }while( rc==SQLITE_OK ); - - return rc; -} + assert( iRes>=0 && c>=aEntry[iRes].iCode ); + p = &aEntry[iRes]; + if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ + ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; + assert( ret>0 ); + } -SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish( - Fts3MultiSegReader *pCsr /* Cursor object */ -){ - if( pCsr ){ - int i; - for(i=0; inSegment; i++){ - sqlite3Fts3SegReaderFree(pCsr->apSegment[i]); + if( eRemoveDiacritic ){ + ret = remove_diacritic(ret, eRemoveDiacritic==2); } - sqlite3_free(pCsr->apSegment); - sqlite3_free(pCsr->aBuffer); + } - pCsr->nSegment = 0; - pCsr->apSegment = 0; - pCsr->aBuffer = 0; + else if( c>=66560 && c<66600 ){ + ret = c + 40; } + + return ret; } +#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */ +#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */ +/************** End of fts3_unicode2.c ***************************************/ +/************** Begin file json.c ********************************************/ /* -** Decode the "end_block" field, selected by column iCol of the SELECT -** statement passed as the first argument. +** 2015-08-12 ** -** The "end_block" field may contain either an integer, or a text field -** containing the text representation of two non-negative integers separated -** by one or more space (0x20) characters. In the first case, set *piEndBlock -** to the integer value and *pnByte to zero before returning. In the second, -** set *piEndBlock to the first value and *pnByte to the second. +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This SQLite JSON functions. +** +** This file began as an extension in ext/misc/json1.c in 2015. That +** extension proved so useful that it has now been moved into the core. +** +** For the time being, all JSON is stored as pure text. (We might add +** a JSONB type in the future which stores a binary encoding of JSON in +** a BLOB, but there is no support for JSONB in the current implementation. +** This implementation parses JSON text at 250 MB/s, so it is hard to see +** how JSONB might improve on that.) */ -static void fts3ReadEndBlockField( - sqlite3_stmt *pStmt, - int iCol, - i64 *piEndBlock, - i64 *pnByte -){ - const unsigned char *zText = sqlite3_column_text(pStmt, iCol); - if( zText ){ - int i; - int iMul = 1; - i64 iVal = 0; - for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ - iVal = iVal*10 + (zText[i] - '0'); - } - *piEndBlock = iVal; - while( zText[i]==' ' ) i++; - iVal = 0; - if( zText[i]=='-' ){ - i++; - iMul = -1; - } - for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ - iVal = iVal*10 + (zText[i] - '0'); - } - *pnByte = (iVal * (i64)iMul); - } -} - +#ifndef SQLITE_OMIT_JSON +/* #include "sqliteInt.h" */ /* -** A segment of size nByte bytes has just been written to absolute level -** iAbsLevel. Promote any segments that should be promoted as a result. +** Growing our own isspace() routine this way is twice as fast as +** the library isspace() function, resulting in a 7% overall performance +** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ -static int fts3PromoteSegments( - Fts3Table *p, /* FTS table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level just updated */ - sqlite3_int64 nByte /* Size of new segment at iAbsLevel */ -){ - int rc = SQLITE_OK; - sqlite3_stmt *pRange; +static const char jsonIsSpace[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define fast_isspace(x) (jsonIsSpace[(unsigned char)x]) - rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE2, &pRange, 0); +#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST) +# define VVA(X) +#else +# define VVA(X) X +#endif - if( rc==SQLITE_OK ){ - int bOk = 0; - i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1; - i64 nLimit = (nByte*3)/2; +/* Objects */ +typedef struct JsonString JsonString; +typedef struct JsonNode JsonNode; +typedef struct JsonParse JsonParse; - /* Loop through all entries in the %_segdir table corresponding to - ** segments in this index on levels greater than iAbsLevel. If there is - ** at least one such segment, and it is possible to determine that all - ** such segments are smaller than nLimit bytes in size, they will be - ** promoted to level iAbsLevel. */ - sqlite3_bind_int64(pRange, 1, iAbsLevel+1); - sqlite3_bind_int64(pRange, 2, iLast); - while( SQLITE_ROW==sqlite3_step(pRange) ){ - i64 nSize = 0, dummy; - fts3ReadEndBlockField(pRange, 2, &dummy, &nSize); - if( nSize<=0 || nSize>nLimit ){ - /* If nSize==0, then the %_segdir.end_block field does not not - ** contain a size value. This happens if it was written by an - ** old version of FTS. In this case it is not possible to determine - ** the size of the segment, and so segment promotion does not - ** take place. */ - bOk = 0; - break; - } - bOk = 1; - } - rc = sqlite3_reset(pRange); +/* An instance of this object represents a JSON string +** under construction. Really, this is a generic string accumulator +** that can be and is used to create strings other than JSON. +*/ +struct JsonString { + sqlite3_context *pCtx; /* Function context - put error messages here */ + char *zBuf; /* Append JSON content here */ + u64 nAlloc; /* Bytes of storage available in zBuf[] */ + u64 nUsed; /* Bytes of zBuf[] currently used */ + u8 bStatic; /* True if zBuf is static space */ + u8 bErr; /* True if an error has been encountered */ + char zSpace[100]; /* Initial static space */ +}; - if( bOk ){ - int iIdx = 0; - sqlite3_stmt *pUpdate1 = 0; - sqlite3_stmt *pUpdate2 = 0; +/* JSON type values +*/ +#define JSON_NULL 0 +#define JSON_TRUE 1 +#define JSON_FALSE 2 +#define JSON_INT 3 +#define JSON_REAL 4 +#define JSON_STRING 5 +#define JSON_ARRAY 6 +#define JSON_OBJECT 7 - if( rc==SQLITE_OK ){ - rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL_IDX, &pUpdate1, 0); - } - if( rc==SQLITE_OK ){ - rc = fts3SqlStmt(p, SQL_UPDATE_LEVEL, &pUpdate2, 0); - } +/* The "subtype" set for JSON values */ +#define JSON_SUBTYPE 74 /* Ascii for "J" */ - if( rc==SQLITE_OK ){ +/* +** Names of the various JSON types: +*/ +static const char * const jsonType[] = { + "null", "true", "false", "integer", "real", "text", "array", "object" +}; - /* Loop through all %_segdir entries for segments in this index with - ** levels equal to or greater than iAbsLevel. As each entry is visited, - ** updated it to set (level = -1) and (idx = N), where N is 0 for the - ** oldest segment in the range, 1 for the next oldest, and so on. - ** - ** In other words, move all segments being promoted to level -1, - ** setting the "idx" fields as appropriate to keep them in the same - ** order. The contents of level -1 (which is never used, except - ** transiently here), will be moved back to level iAbsLevel below. */ - sqlite3_bind_int64(pRange, 1, iAbsLevel); - while( SQLITE_ROW==sqlite3_step(pRange) ){ - sqlite3_bind_int(pUpdate1, 1, iIdx++); - sqlite3_bind_int(pUpdate1, 2, sqlite3_column_int(pRange, 0)); - sqlite3_bind_int(pUpdate1, 3, sqlite3_column_int(pRange, 1)); - sqlite3_step(pUpdate1); - rc = sqlite3_reset(pUpdate1); - if( rc!=SQLITE_OK ){ - sqlite3_reset(pRange); - break; - } - } - } - if( rc==SQLITE_OK ){ - rc = sqlite3_reset(pRange); - } +/* Bit values for the JsonNode.jnFlag field +*/ +#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ +#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ +#define JNODE_REMOVE 0x04 /* Do not output */ +#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */ +#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */ +#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */ +#define JNODE_LABEL 0x40 /* Is a label of an object */ - /* Move level -1 to level iAbsLevel */ - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pUpdate2, 1, iAbsLevel); - sqlite3_step(pUpdate2); - rc = sqlite3_reset(pUpdate2); - } - } - } +/* A single node of parsed JSON +*/ +struct JsonNode { + u8 eType; /* One of the JSON_ type values */ + u8 jnFlags; /* JNODE flags */ + u8 eU; /* Which union element to use */ + u32 n; /* Bytes of content, or number of sub-nodes */ + union { + const char *zJContent; /* 1: Content for INT, REAL, and STRING */ + u32 iAppend; /* 2: More terms for ARRAY and OBJECT */ + u32 iKey; /* 3: Key for ARRAY objects in json_tree() */ + u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */ + JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */ + } u; +}; - return rc; -} +/* A completely parsed JSON string +*/ +struct JsonParse { + u32 nNode; /* Number of slots of aNode[] used */ + u32 nAlloc; /* Number of slots of aNode[] allocated */ + JsonNode *aNode; /* Array of nodes containing the parse */ + const char *zJson; /* Original JSON string */ + u32 *aUp; /* Index of parent of each node */ + u8 oom; /* Set to true if out of memory */ + u8 nErr; /* Number of errors seen */ + u16 iDepth; /* Nesting depth */ + int nJson; /* Length of the zJson string in bytes */ + u32 iHold; /* Replace cache line with the lowest iHold value */ +}; /* -** Merge all level iLevel segments in the database into a single -** iLevel+1 segment. Or, if iLevel<0, merge all segments into a -** single segment with a level equal to the numerically largest level -** currently present in the database. +** Maximum nesting depth of JSON for this implementation. ** -** If this function is called with iLevel<0, but there is only one -** segment in the database, SQLITE_DONE is returned immediately. -** Otherwise, if successful, SQLITE_OK is returned. If an error occurs, -** an SQLite error code is returned. +** This limit is needed to avoid a stack overflow in the recursive +** descent parser. A depth of 2000 is far deeper than any sane JSON +** should go. */ -static int fts3SegmentMerge( - Fts3Table *p, - int iLangid, /* Language id to merge */ - int iIndex, /* Index in p->aIndex[] to merge */ - int iLevel /* Level to merge */ -){ - int rc; /* Return code */ - int iIdx = 0; /* Index of new segment */ - sqlite3_int64 iNewLevel = 0; /* Level/index to create new segment at */ - SegmentWriter *pWriter = 0; /* Used to write the new, merged, segment */ - Fts3SegFilter filter; /* Segment term filter condition */ - Fts3MultiSegReader csr; /* Cursor to iterate through level(s) */ - int bIgnoreEmpty = 0; /* True to ignore empty segments */ - i64 iMaxLevel = 0; /* Max level number for this index/langid */ - - assert( iLevel==FTS3_SEGCURSOR_ALL - || iLevel==FTS3_SEGCURSOR_PENDING - || iLevel>=0 - ); - assert( iLevel=0 && iIndexnIndex ); - - rc = sqlite3Fts3SegReaderCursor(p, iLangid, iIndex, iLevel, 0, 0, 1, 0, &csr); - if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished; - - if( iLevel!=FTS3_SEGCURSOR_PENDING ){ - rc = fts3SegmentMaxLevel(p, iLangid, iIndex, &iMaxLevel); - if( rc!=SQLITE_OK ) goto finished; - } - - if( iLevel==FTS3_SEGCURSOR_ALL ){ - /* This call is to merge all segments in the database to a single - ** segment. The level of the new segment is equal to the numerically - ** greatest segment level currently present in the database for this - ** index. The idx of the new segment is always 0. */ - if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){ - rc = SQLITE_DONE; - goto finished; - } - iNewLevel = iMaxLevel; - bIgnoreEmpty = 1; - - }else{ - /* This call is to merge all segments at level iLevel. find the next - ** available segment index at level iLevel+1. The call to - ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to - ** a single iLevel+2 segment if necessary. */ - assert( FTS3_SEGCURSOR_PENDING==-1 ); - iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1); - rc = fts3AllocateSegdirIdx(p, iLangid, iIndex, iLevel+1, &iIdx); - bIgnoreEmpty = (iLevel!=FTS3_SEGCURSOR_PENDING) && (iNewLevel>iMaxLevel); - } - if( rc!=SQLITE_OK ) goto finished; +#define JSON_MAX_DEPTH 2000 - assert( csr.nSegment>0 ); - assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); - assert( iNewLevelzBuf = p->zSpace; + p->nAlloc = sizeof(p->zSpace); + p->nUsed = 0; + p->bStatic = 1; +} - rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); - while( SQLITE_OK==rc ){ - rc = sqlite3Fts3SegReaderStep(p, &csr); - if( rc!=SQLITE_ROW ) break; - rc = fts3SegWriterAdd(p, &pWriter, 1, - csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist); - } - if( rc!=SQLITE_OK ) goto finished; - assert( pWriter || bIgnoreEmpty ); +/* Initialize the JsonString object +*/ +static void jsonInit(JsonString *p, sqlite3_context *pCtx){ + p->pCtx = pCtx; + p->bErr = 0; + jsonZero(p); +} - if( iLevel!=FTS3_SEGCURSOR_PENDING ){ - rc = fts3DeleteSegdir( - p, iLangid, iIndex, iLevel, csr.apSegment, csr.nSegment - ); - if( rc!=SQLITE_OK ) goto finished; - } - if( pWriter ){ - rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx); - if( rc==SQLITE_OK ){ - if( iLevel==FTS3_SEGCURSOR_PENDING || iNewLevelnLeafData); - } - } - } - finished: - fts3SegWriterFree(pWriter); - sqlite3Fts3SegReaderFinish(&csr); - return rc; +/* Free all allocated memory and reset the JsonString object back to its +** initial state. +*/ +static void jsonReset(JsonString *p){ + if( !p->bStatic ) sqlite3_free(p->zBuf); + jsonZero(p); } -/* -** Flush the contents of pendingTerms to level 0 segments. +/* Report an out-of-memory (OOM) condition */ -SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){ - int rc = SQLITE_OK; - int i; - - for(i=0; rc==SQLITE_OK && inIndex; i++){ - rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - } - sqlite3Fts3PendingTermsClear(p); +static void jsonOom(JsonString *p){ + p->bErr = 1; + sqlite3_result_error_nomem(p->pCtx); + jsonReset(p); +} - /* Determine the auto-incr-merge setting if unknown. If enabled, - ** estimate the number of leaf blocks of content to be written - */ - if( rc==SQLITE_OK && p->bHasStat - && p->nAutoincrmerge==0xff && p->nLeafAdd>0 - ){ - sqlite3_stmt *pStmt = 0; - rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); - rc = sqlite3_step(pStmt); - if( rc==SQLITE_ROW ){ - p->nAutoincrmerge = sqlite3_column_int(pStmt, 0); - if( p->nAutoincrmerge==1 ) p->nAutoincrmerge = 8; - }else if( rc==SQLITE_DONE ){ - p->nAutoincrmerge = 0; - } - rc = sqlite3_reset(pStmt); +/* Enlarge pJson->zBuf so that it can hold at least N more bytes. +** Return zero on success. Return non-zero on an OOM error +*/ +static int jsonGrow(JsonString *p, u32 N){ + u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; + char *zNew; + if( p->bStatic ){ + if( p->bErr ) return 1; + zNew = sqlite3_malloc64(nTotal); + if( zNew==0 ){ + jsonOom(p); + return SQLITE_NOMEM; + } + memcpy(zNew, p->zBuf, (size_t)p->nUsed); + p->zBuf = zNew; + p->bStatic = 0; + }else{ + zNew = sqlite3_realloc64(p->zBuf, nTotal); + if( zNew==0 ){ + jsonOom(p); + return SQLITE_NOMEM; } + p->zBuf = zNew; } - return rc; + p->nAlloc = nTotal; + return SQLITE_OK; } -/* -** Encode N integers as varints into a blob. +/* Append N bytes from zIn onto the end of the JsonString string. */ -static void fts3EncodeIntArray( - int N, /* The number of integers to encode */ - u32 *a, /* The integer values */ - char *zBuf, /* Write the BLOB here */ - int *pNBuf /* Write number of bytes if zBuf[] used here */ -){ - int i, j; - for(i=j=0; inUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; + memcpy(p->zBuf+p->nUsed, zIn, N); + p->nUsed += N; } -/* -** Decode a blob of varints into N integers +/* Append formatted text (not to exceed N bytes) to the JsonString. */ -static void fts3DecodeIntArray( - int N, /* The number of integers to decode */ - u32 *a, /* Write the integer values */ - const char *zBuf, /* The BLOB containing the varints */ - int nBuf /* size of the BLOB */ -){ - int i, j; - UNUSED_PARAMETER(nBuf); - for(i=j=0; inUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; + va_start(ap, zFormat); + sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); + va_end(ap); + p->nUsed += (int)strlen(p->zBuf+p->nUsed); } -/* -** Insert the sizes (in tokens) for each column of the document -** with docid equal to p->iPrevDocid. The sizes are encoded as -** a blob of varints. +/* Append a single character */ -static void fts3InsertDocsize( - int *pRC, /* Result code */ - Fts3Table *p, /* Table into which to insert */ - u32 *aSz /* Sizes of each column, in tokens */ -){ - char *pBlob; /* The BLOB encoding of the document size */ - int nBlob; /* Number of bytes in the BLOB */ - sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ - int rc; /* Result code from subfunctions */ - - if( *pRC ) return; - pBlob = sqlite3_malloc( 10*p->nColumn ); - if( pBlob==0 ){ - *pRC = SQLITE_NOMEM; - return; - } - fts3EncodeIntArray(p->nColumn, aSz, pBlob, &nBlob); - rc = fts3SqlStmt(p, SQL_REPLACE_DOCSIZE, &pStmt, 0); - if( rc ){ - sqlite3_free(pBlob); - *pRC = rc; - return; - } - sqlite3_bind_int64(pStmt, 1, p->iPrevDocid); - sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, sqlite3_free); - sqlite3_step(pStmt); - *pRC = sqlite3_reset(pStmt); +static void jsonAppendChar(JsonString *p, char c){ + if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; + p->zBuf[p->nUsed++] = c; } -/* -** Record 0 of the %_stat table contains a blob consisting of N varints, -** where N is the number of user defined columns in the fts3 table plus -** two. If nCol is the number of user defined columns, then values of the -** varints are set as follows: -** -** Varint 0: Total number of rows in the table. -** -** Varint 1..nCol: For each column, the total number of tokens stored in -** the column for all rows of the table. -** -** Varint 1+nCol: The total size, in bytes, of all text values in all -** columns of all rows of the table. -** +/* Append a comma separator to the output buffer, if the previous +** character is not '[' or '{'. */ -static void fts3UpdateDocTotals( - int *pRC, /* The result code */ - Fts3Table *p, /* Table being updated */ - u32 *aSzIns, /* Size increases */ - u32 *aSzDel, /* Size decreases */ - int nChng /* Change in the number of documents */ -){ - char *pBlob; /* Storage for BLOB written into %_stat */ - int nBlob; /* Size of BLOB written into %_stat */ - u32 *a; /* Array of integers that becomes the BLOB */ - sqlite3_stmt *pStmt; /* Statement for reading and writing */ - int i; /* Loop counter */ - int rc; /* Result code from subfunctions */ - - const int nStat = p->nColumn+2; - - if( *pRC ) return; - a = sqlite3_malloc( (sizeof(u32)+10)*nStat ); - if( a==0 ){ - *pRC = SQLITE_NOMEM; - return; - } - pBlob = (char*)&a[nStat]; - rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pStmt, 0); - if( rc ){ - sqlite3_free(a); - *pRC = rc; - return; - } - sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); - if( sqlite3_step(pStmt)==SQLITE_ROW ){ - fts3DecodeIntArray(nStat, a, - sqlite3_column_blob(pStmt, 0), - sqlite3_column_bytes(pStmt, 0)); - }else{ - memset(a, 0, sizeof(u32)*(nStat) ); - } - rc = sqlite3_reset(pStmt); - if( rc!=SQLITE_OK ){ - sqlite3_free(a); - *pRC = rc; - return; - } - if( nChng<0 && a[0]<(u32)(-nChng) ){ - a[0] = 0; - }else{ - a[0] += nChng; - } - for(i=0; inColumn+1; i++){ - u32 x = a[i+1]; - if( x+aSzIns[i] < aSzDel[i] ){ - x = 0; - }else{ - x = x + aSzIns[i] - aSzDel[i]; - } - a[i+1] = x; - } - fts3EncodeIntArray(nStat, a, pBlob, &nBlob); - rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); - if( rc ){ - sqlite3_free(a); - *pRC = rc; - return; - } - sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); - sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC); - sqlite3_step(pStmt); - *pRC = sqlite3_reset(pStmt); - sqlite3_free(a); +static void jsonAppendSeparator(JsonString *p){ + char c; + if( p->nUsed==0 ) return; + c = p->zBuf[p->nUsed-1]; + if( c!='[' && c!='{' ) jsonAppendChar(p, ','); } -/* -** Merge the entire database so that there is one segment for each -** iIndex/iLangid combination. +/* Append the N-byte string in zIn to the end of the JsonString string +** under construction. Enclose the string in "..." and escape +** any double-quotes or backslash characters contained within the +** string. */ -static int fts3DoOptimize(Fts3Table *p, int bReturnDone){ - int bSeenDone = 0; - int rc; - sqlite3_stmt *pAllLangid = 0; - - rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); - if( rc==SQLITE_OK ){ - int rc2; - sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid); - sqlite3_bind_int(pAllLangid, 2, p->nIndex); - while( sqlite3_step(pAllLangid)==SQLITE_ROW ){ - int i; - int iLangid = sqlite3_column_int(pAllLangid, 0); - for(i=0; rc==SQLITE_OK && inIndex; i++){ - rc = fts3SegmentMerge(p, iLangid, i, FTS3_SEGCURSOR_ALL); - if( rc==SQLITE_DONE ){ - bSeenDone = 1; - rc = SQLITE_OK; - } +static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ + u32 i; + if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return; + p->zBuf[p->nUsed++] = '"'; + for(i=0; inUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + }else if( c<=0x1f ){ + static const char aSpecial[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + assert( sizeof(aSpecial)==32 ); + assert( aSpecial['\b']=='b' ); + assert( aSpecial['\f']=='f' ); + assert( aSpecial['\n']=='n' ); + assert( aSpecial['\r']=='r' ); + assert( aSpecial['\t']=='t' ); + if( aSpecial[c] ){ + c = aSpecial[c]; + goto json_simple_escape; } + if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; + p->zBuf[p->nUsed++] = '\\'; + p->zBuf[p->nUsed++] = 'u'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0'; + p->zBuf[p->nUsed++] = '0' + (c>>4); + c = "0123456789abcdef"[c&0xf]; } - rc2 = sqlite3_reset(pAllLangid); - if( rc==SQLITE_OK ) rc = rc2; + p->zBuf[p->nUsed++] = c; } - - sqlite3Fts3SegmentsClose(p); - sqlite3Fts3PendingTermsClear(p); - - return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; + p->zBuf[p->nUsed++] = '"'; + assert( p->nUsednAlloc ); } /* -** This function is called when the user executes the following statement: -** -** INSERT INTO () VALUES('rebuild'); -** -** The entire FTS index is discarded and rebuilt. If the table is one -** created using the content=xxx option, then the new index is based on -** the current contents of the xxx table. Otherwise, it is rebuilt based -** on the contents of the %_content table. +** Append a function parameter value to the JSON string under +** construction. */ -static int fts3DoRebuild(Fts3Table *p){ - int rc; /* Return Code */ - - rc = fts3DeleteAll(p, 0); - if( rc==SQLITE_OK ){ - u32 *aSz = 0; - u32 *aSzIns = 0; - u32 *aSzDel = 0; - sqlite3_stmt *pStmt = 0; - int nEntry = 0; - - /* Compose and prepare an SQL statement to loop through the content table */ - char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); - if( !zSql ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); +static void jsonAppendValue( + JsonString *p, /* Append to this JSON string */ + sqlite3_value *pValue /* Value to append */ +){ + switch( sqlite3_value_type(pValue) ){ + case SQLITE_NULL: { + jsonAppendRaw(p, "null", 4); + break; } - - if( rc==SQLITE_OK ){ - int nByte = sizeof(u32) * (p->nColumn+1)*3; - aSz = (u32 *)sqlite3_malloc(nByte); - if( aSz==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(aSz, 0, nByte); - aSzIns = &aSz[p->nColumn+1]; - aSzDel = &aSzIns[p->nColumn+1]; - } + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + const char *z = (const char*)sqlite3_value_text(pValue); + u32 n = (u32)sqlite3_value_bytes(pValue); + jsonAppendRaw(p, z, n); + break; } - - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - int iCol; - int iLangid = langidFromSelect(p, pStmt); - rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0)); - memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1)); - for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ - if( p->abNotindexed[iCol]==0 ){ - const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); - rc = fts3PendingTermsAdd(p, iLangid, z, iCol, &aSz[iCol]); - aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); - } - } - if( p->bHasDocsize ){ - fts3InsertDocsize(&rc, p, aSz); - } - if( rc!=SQLITE_OK ){ - sqlite3_finalize(pStmt); - pStmt = 0; + case SQLITE_TEXT: { + const char *z = (const char*)sqlite3_value_text(pValue); + u32 n = (u32)sqlite3_value_bytes(pValue); + if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ + jsonAppendRaw(p, z, n); }else{ - nEntry++; - for(iCol=0; iCol<=p->nColumn; iCol++){ - aSzIns[iCol] += aSz[iCol]; - } + jsonAppendString(p, z, n); } + break; } - if( p->bFts4 ){ - fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry); - } - sqlite3_free(aSz); - - if( pStmt ){ - int rc2 = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ){ - rc = rc2; + default: { + if( p->bErr==0 ){ + sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); + p->bErr = 2; + jsonReset(p); } + break; } } - - return rc; } -/* -** This function opens a cursor used to read the input data for an -** incremental merge operation. Specifically, it opens a cursor to scan -** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute -** level iAbsLevel. +/* Make the JSON in p the result of the SQL function. */ -static int fts3IncrmergeCsr( - Fts3Table *p, /* FTS3 table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level to open */ - int nSeg, /* Number of segments to merge */ - Fts3MultiSegReader *pCsr /* Cursor object to populate */ -){ - int rc; /* Return Code */ - sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ - int nByte; /* Bytes allocated at pCsr->apSegment[] */ - - /* Allocate space for the Fts3MultiSegReader.aCsr[] array */ - memset(pCsr, 0, sizeof(*pCsr)); - nByte = sizeof(Fts3SegReader *) * nSeg; - pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte); - - if( pCsr->apSegment==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(pCsr->apSegment, 0, nByte); - rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0); - } - if( rc==SQLITE_OK ){ - int i; - int rc2; - sqlite3_bind_int64(pStmt, 1, iAbsLevel); - assert( pCsr->nSegment==0 ); - for(i=0; rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW && iapSegment[i] - ); - pCsr->nSegment++; - } - rc2 = sqlite3_reset(pStmt); - if( rc==SQLITE_OK ) rc = rc2; +static void jsonResult(JsonString *p){ + if( p->bErr==0 ){ + sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, + p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, + SQLITE_UTF8); + jsonZero(p); } - - return rc; + assert( p->bStatic ); } -typedef struct IncrmergeWriter IncrmergeWriter; -typedef struct NodeWriter NodeWriter; -typedef struct Blob Blob; -typedef struct NodeReader NodeReader; +/************************************************************************** +** Utility routines for dealing with JsonNode and JsonParse objects +**************************************************************************/ /* -** An instance of the following structure is used as a dynamic buffer -** to build up nodes or other blobs of data in. +** Return the number of consecutive JsonNode slots need to represent +** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and +** OBJECT types, the number might be larger. ** -** The function blobGrowBuffer() is used to extend the allocation. -*/ -struct Blob { - char *a; /* Pointer to allocation */ - int n; /* Number of valid bytes of data in a[] */ - int nAlloc; /* Allocated size of a[] (nAlloc>=n) */ -}; - -/* -** This structure is used to build up buffers containing segment b-tree -** nodes (blocks). +** Appended elements are not counted. The value returned is the number +** by which the JsonNode counter should increment in order to go to the +** next peer value. */ -struct NodeWriter { - sqlite3_int64 iBlock; /* Current block id */ - Blob key; /* Last key written to the current block */ - Blob block; /* Current block image */ -}; +static u32 jsonNodeSize(JsonNode *pNode){ + return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; +} /* -** An object of this type contains the state required to create or append -** to an appendable b-tree segment. +** Reclaim all memory allocated by a JsonParse object. But do not +** delete the JsonParse object itself. */ -struct IncrmergeWriter { - int nLeafEst; /* Space allocated for leaf blocks */ - int nWork; /* Number of leaf pages flushed */ - sqlite3_int64 iAbsLevel; /* Absolute level of input segments */ - int iIdx; /* Index of *output* segment in iAbsLevel+1 */ - sqlite3_int64 iStart; /* Block number of first allocated block */ - sqlite3_int64 iEnd; /* Block number of last allocated block */ - sqlite3_int64 nLeafData; /* Bytes of leaf page data so far */ - u8 bNoLeafData; /* If true, store 0 for segment size */ - NodeWriter aNodeWriter[FTS_MAX_APPENDABLE_HEIGHT]; -}; +static void jsonParseReset(JsonParse *pParse){ + sqlite3_free(pParse->aNode); + pParse->aNode = 0; + pParse->nNode = 0; + pParse->nAlloc = 0; + sqlite3_free(pParse->aUp); + pParse->aUp = 0; +} /* -** An object of the following type is used to read data from a single -** FTS segment node. See the following functions: -** -** nodeReaderInit() -** nodeReaderNext() -** nodeReaderRelease() +** Free a JsonParse object that was obtained from sqlite3_malloc(). */ -struct NodeReader { - const char *aNode; - int nNode; - int iOff; /* Current offset within aNode[] */ - - /* Output variables. Containing the current node entry. */ - sqlite3_int64 iChild; /* Pointer to child node */ - Blob term; /* Current term */ - const char *aDoclist; /* Pointer to doclist */ - int nDoclist; /* Size of doclist in bytes */ -}; +static void jsonParseFree(JsonParse *pParse){ + jsonParseReset(pParse); + sqlite3_free(pParse); +} /* -** If *pRc is not SQLITE_OK when this function is called, it is a no-op. -** Otherwise, if the allocation at pBlob->a is not already at least nMin -** bytes in size, extend (realloc) it to be so. -** -** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a -** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc -** to reflect the new size of the pBlob->a[] buffer. +** Convert the JsonNode pNode into a pure JSON string and +** append to pOut. Subsubstructure is also included. Return +** the number of JsonNode objects that are encoded. */ -static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ - if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ - int nAlloc = nMin; - char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); - if( a ){ - pBlob->nAlloc = nAlloc; - pBlob->a = a; - }else{ - *pRc = SQLITE_NOMEM; +static void jsonRenderNode( + JsonNode *pNode, /* The node to render */ + JsonString *pOut, /* Write JSON here */ + sqlite3_value **aReplace /* Replacement values */ +){ + assert( pNode!=0 ); + if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){ + if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){ + assert( pNode->eU==4 ); + jsonAppendValue(pOut, aReplace[pNode->u.iReplace]); + return; } + assert( pNode->eU==5 ); + pNode = pNode->u.pPatch; } -} - -/* -** Attempt to advance the node-reader object passed as the first argument to -** the next entry on the node. -** -** Return an error code if an error occurs (SQLITE_NOMEM is possible). -** Otherwise return SQLITE_OK. If there is no next entry on the node -** (e.g. because the current entry is the last) set NodeReader->aNode to -** NULL to indicate EOF. Otherwise, populate the NodeReader structure output -** variables for the new entry. -*/ -static int nodeReaderNext(NodeReader *p){ - int bFirst = (p->term.n==0); /* True for first term on the node */ - int nPrefix = 0; /* Bytes to copy from previous term */ - int nSuffix = 0; /* Bytes to append to the prefix */ - int rc = SQLITE_OK; /* Return code */ - - assert( p->aNode ); - if( p->iChild && bFirst==0 ) p->iChild++; - if( p->iOff>=p->nNode ){ - /* EOF */ - p->aNode = 0; - }else{ - if( bFirst==0 ){ - p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nPrefix); + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + jsonAppendRaw(pOut, "null", 4); + break; } - p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); - - blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); - if( rc==SQLITE_OK ){ - memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); - p->term.n = nPrefix+nSuffix; - p->iOff += nSuffix; - if( p->iChild==0 ){ - p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist); - p->aDoclist = &p->aNode[p->iOff]; - p->iOff += p->nDoclist; + case JSON_TRUE: { + jsonAppendRaw(pOut, "true", 4); + break; + } + case JSON_FALSE: { + jsonAppendRaw(pOut, "false", 5); + break; + } + case JSON_STRING: { + if( pNode->jnFlags & JNODE_RAW ){ + assert( pNode->eU==1 ); + jsonAppendString(pOut, pNode->u.zJContent, pNode->n); + break; + } + /* no break */ deliberate_fall_through + } + case JSON_REAL: + case JSON_INT: { + assert( pNode->eU==1 ); + jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); + break; + } + case JSON_ARRAY: { + u32 j = 1; + jsonAppendChar(pOut, '['); + for(;;){ + while( j<=pNode->n ){ + if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){ + jsonAppendSeparator(pOut); + jsonRenderNode(&pNode[j], pOut, aReplace); + } + j += jsonNodeSize(&pNode[j]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + assert( pNode->eU==2 ); + pNode = &pNode[pNode->u.iAppend]; + j = 1; } + jsonAppendChar(pOut, ']'); + break; + } + case JSON_OBJECT: { + u32 j = 1; + jsonAppendChar(pOut, '{'); + for(;;){ + while( j<=pNode->n ){ + if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){ + jsonAppendSeparator(pOut); + jsonRenderNode(&pNode[j], pOut, aReplace); + jsonAppendChar(pOut, ':'); + jsonRenderNode(&pNode[j+1], pOut, aReplace); + } + j += 1 + jsonNodeSize(&pNode[j+1]); + } + if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; + assert( pNode->eU==2 ); + pNode = &pNode[pNode->u.iAppend]; + j = 1; + } + jsonAppendChar(pOut, '}'); + break; } } - - assert( p->iOff<=p->nNode ); - - return rc; } /* -** Release all dynamic resources held by node-reader object *p. +** Return a JsonNode and all its descendents as a JSON string. */ -static void nodeReaderRelease(NodeReader *p){ - sqlite3_free(p->term.a); +static void jsonReturnJson( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ +){ + JsonString s; + jsonInit(&s, pCtx); + jsonRenderNode(pNode, &s, aReplace); + jsonResult(&s); + sqlite3_result_subtype(pCtx, JSON_SUBTYPE); } /* -** Initialize a node-reader object to read the node in buffer aNode/nNode. -** -** If successful, SQLITE_OK is returned and the NodeReader object set to -** point to the first entry on the node (if any). Otherwise, an SQLite -** error code is returned. +** Translate a single byte of Hex into an integer. +** This routine only works if h really is a valid hexadecimal +** character: 0..9a..fA..F */ -static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){ - memset(p, 0, sizeof(NodeReader)); - p->aNode = aNode; - p->nNode = nNode; - - /* Figure out if this is a leaf or an internal node. */ - if( p->aNode[0] ){ - /* An internal node. */ - p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild); - }else{ - p->iOff = 1; - } +static u8 jsonHexToInt(int h){ + assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); +#ifdef SQLITE_EBCDIC + h += 9*(1&~(h>>4)); +#else + h += 9*(1&(h>>6)); +#endif + return (u8)(h & 0xf); +} - return nodeReaderNext(p); +/* +** Convert a 4-byte hex string into an integer +*/ +static u32 jsonHexToInt4(const char *z){ + u32 v; + assert( sqlite3Isxdigit(z[0]) ); + assert( sqlite3Isxdigit(z[1]) ); + assert( sqlite3Isxdigit(z[2]) ); + assert( sqlite3Isxdigit(z[3]) ); + v = (jsonHexToInt(z[0])<<12) + + (jsonHexToInt(z[1])<<8) + + (jsonHexToInt(z[2])<<4) + + jsonHexToInt(z[3]); + return v; } /* -** This function is called while writing an FTS segment each time a leaf o -** node is finished and written to disk. The key (zTerm/nTerm) is guaranteed -** to be greater than the largest key on the node just written, but smaller -** than or equal to the first key that will be written to the next leaf -** node. -** -** The block id of the leaf node just written to disk may be found in -** (pWriter->aNodeWriter[0].iBlock) when this function is called. +** Make the JsonNode the return value of the function. */ -static int fts3IncrmergePush( - Fts3Table *p, /* Fts3 table handle */ - IncrmergeWriter *pWriter, /* Writer object */ - const char *zTerm, /* Term to write to internal node */ - int nTerm /* Bytes at zTerm */ +static void jsonReturn( + JsonNode *pNode, /* Node to return */ + sqlite3_context *pCtx, /* Return value for this function */ + sqlite3_value **aReplace /* Array of replacement values */ ){ - sqlite3_int64 iPtr = pWriter->aNodeWriter[0].iBlock; - int iLayer; - - assert( nTerm>0 ); - for(iLayer=1; ALWAYS(iLayeraNodeWriter[iLayer]; - int rc = SQLITE_OK; - int nPrefix; - int nSuffix; - int nSpace; - - /* Figure out how much space the key will consume if it is written to - ** the current node of layer iLayer. Due to the prefix compression, - ** the space required changes depending on which node the key is to - ** be added to. */ - nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm); - nSuffix = nTerm - nPrefix; - nSpace = sqlite3Fts3VarintLen(nPrefix); - nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; - - if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){ - /* If the current node of layer iLayer contains zero keys, or if adding - ** the key to it will not cause it to grow to larger than nNodeSize - ** bytes in size, write the key here. */ - - Blob *pBlk = &pNode->block; - if( pBlk->n==0 ){ - blobGrowBuffer(pBlk, p->nNodeSize, &rc); - if( rc==SQLITE_OK ){ - pBlk->a[0] = (char)iLayer; - pBlk->n = 1 + sqlite3Fts3PutVarint(&pBlk->a[1], iPtr); + switch( pNode->eType ){ + default: { + assert( pNode->eType==JSON_NULL ); + sqlite3_result_null(pCtx); + break; + } + case JSON_TRUE: { + sqlite3_result_int(pCtx, 1); + break; + } + case JSON_FALSE: { + sqlite3_result_int(pCtx, 0); + break; + } + case JSON_INT: { + sqlite3_int64 i = 0; + const char *z; + assert( pNode->eU==1 ); + z = pNode->u.zJContent; + if( z[0]=='-' ){ z++; } + while( z[0]>='0' && z[0]<='9' ){ + unsigned v = *(z++) - '0'; + if( i>=LARGEST_INT64/10 ){ + if( i>LARGEST_INT64/10 ) goto int_as_real; + if( z[0]>='0' && z[0]<='9' ) goto int_as_real; + if( v==9 ) goto int_as_real; + if( v==8 ){ + if( pNode->u.zJContent[0]=='-' ){ + sqlite3_result_int64(pCtx, SMALLEST_INT64); + goto int_done; + }else{ + goto int_as_real; + } + } } + i = i*10 + v; } - blobGrowBuffer(pBlk, pBlk->n + nSpace, &rc); - blobGrowBuffer(&pNode->key, nTerm, &rc); - - if( rc==SQLITE_OK ){ - if( pNode->key.n ){ - pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix); + if( pNode->u.zJContent[0]=='-' ){ i = -i; } + sqlite3_result_int64(pCtx, i); + int_done: + break; + int_as_real: ; /* no break */ deliberate_fall_through + } + case JSON_REAL: { + double r; +#ifdef SQLITE_AMALGAMATION + const char *z; + assert( pNode->eU==1 ); + z = pNode->u.zJContent; + sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); +#else + assert( pNode->eU==1 ); + r = strtod(pNode->u.zJContent, 0); +#endif + sqlite3_result_double(pCtx, r); + break; + } + case JSON_STRING: { +#if 0 /* Never happens because JNODE_RAW is only set by json_set(), + ** json_insert() and json_replace() and those routines do not + ** call jsonReturn() */ + if( pNode->jnFlags & JNODE_RAW ){ + assert( pNode->eU==1 ); + sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, + SQLITE_TRANSIENT); + }else +#endif + assert( (pNode->jnFlags & JNODE_RAW)==0 ); + if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ + /* JSON formatted without any backslash-escapes */ + assert( pNode->eU==1 ); + sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, + SQLITE_TRANSIENT); + }else{ + /* Translate JSON formatted string into raw text */ + u32 i; + u32 n = pNode->n; + const char *z; + char *zOut; + u32 j; + assert( pNode->eU==1 ); + z = pNode->u.zJContent; + zOut = sqlite3_malloc( n+1 ); + if( zOut==0 ){ + sqlite3_result_error_nomem(pCtx); + break; } - pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix); - memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix); - pBlk->n += nSuffix; - - memcpy(pNode->key.a, zTerm, nTerm); - pNode->key.n = nTerm; + for(i=1, j=0; i>6)); + zOut[j++] = 0x80 | (v&0x3f); + }else{ + u32 vlo; + if( (v&0xfc00)==0xd800 + && i>18); + zOut[j++] = 0x80 | ((v>>12)&0x3f); + zOut[j++] = 0x80 | ((v>>6)&0x3f); + zOut[j++] = 0x80 | (v&0x3f); + }else{ + zOut[j++] = 0xe0 | (v>>12); + zOut[j++] = 0x80 | ((v>>6)&0x3f); + zOut[j++] = 0x80 | (v&0x3f); + } + } + }else{ + if( c=='b' ){ + c = '\b'; + }else if( c=='f' ){ + c = '\f'; + }else if( c=='n' ){ + c = '\n'; + }else if( c=='r' ){ + c = '\r'; + }else if( c=='t' ){ + c = '\t'; + } + zOut[j++] = c; + } + } + } + zOut[j] = 0; + sqlite3_result_text(pCtx, zOut, j, sqlite3_free); } - }else{ - /* Otherwise, flush the current node of layer iLayer to disk. - ** Then allocate a new, empty sibling node. The key will be written - ** into the parent of this node. */ - rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); - - assert( pNode->block.nAlloc>=p->nNodeSize ); - pNode->block.a[0] = (char)iLayer; - pNode->block.n = 1 + sqlite3Fts3PutVarint(&pNode->block.a[1], iPtr+1); - - iNextPtr = pNode->iBlock; - pNode->iBlock++; - pNode->key.n = 0; + break; + } + case JSON_ARRAY: + case JSON_OBJECT: { + jsonReturnJson(pNode, pCtx, aReplace); + break; } - - if( rc!=SQLITE_OK || iNextPtr==0 ) return rc; - iPtr = iNextPtr; } - - assert( 0 ); - return 0; } +/* Forward reference */ +static int jsonParseAddNode(JsonParse*,u32,u32,const char*); + /* -** Append a term and (optionally) doclist to the FTS segment node currently -** stored in blob *pNode. The node need not contain any terms, but the -** header must be written before this function is called. -** -** A node header is a single 0x00 byte for a leaf node, or a height varint -** followed by the left-hand-child varint for an internal node. -** -** The term to be appended is passed via arguments zTerm/nTerm. For a -** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal -** node, both aDoclist and nDoclist must be passed 0. -** -** If the size of the value in blob pPrev is zero, then this is the first -** term written to the node. Otherwise, pPrev contains a copy of the -** previous term. Before this function returns, it is updated to contain a -** copy of zTerm/nTerm. -** -** It is assumed that the buffer associated with pNode is already large -** enough to accommodate the new entry. The buffer associated with pPrev -** is extended by this function if requrired. -** -** If an error (i.e. OOM condition) occurs, an SQLite error code is -** returned. Otherwise, SQLITE_OK. +** A macro to hint to the compiler that a function should not be +** inlined. */ -static int fts3AppendToNode( - Blob *pNode, /* Current node image to append to */ - Blob *pPrev, /* Buffer containing previous term written */ - const char *zTerm, /* New term to write */ - int nTerm, /* Size of zTerm in bytes */ - const char *aDoclist, /* Doclist (or NULL) to write */ - int nDoclist /* Size of aDoclist in bytes */ -){ - int rc = SQLITE_OK; /* Return code */ - int bFirst = (pPrev->n==0); /* True if this is the first term written */ - int nPrefix; /* Size of term prefix in bytes */ - int nSuffix; /* Size of term suffix in bytes */ - - /* Node must have already been started. There must be a doclist for a - ** leaf node, and there must not be a doclist for an internal node. */ - assert( pNode->n>0 ); - assert( (pNode->a[0]=='\0')==(aDoclist!=0) ); - - blobGrowBuffer(pPrev, nTerm, &rc); - if( rc!=SQLITE_OK ) return rc; +#if defined(__GNUC__) +# define JSON_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define JSON_NOINLINE __declspec(noinline) +#else +# define JSON_NOINLINE +#endif - nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm); - nSuffix = nTerm - nPrefix; - memcpy(pPrev->a, zTerm, nTerm); - pPrev->n = nTerm; - if( bFirst==0 ){ - pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nPrefix); +static JSON_NOINLINE int jsonParseAddNodeExpand( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + u32 nNew; + JsonNode *pNew; + assert( pParse->nNode>=pParse->nAlloc ); + if( pParse->oom ) return -1; + nNew = pParse->nAlloc*2 + 10; + pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew); + if( pNew==0 ){ + pParse->oom = 1; + return -1; } - pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nSuffix); - memcpy(&pNode->a[pNode->n], &zTerm[nPrefix], nSuffix); - pNode->n += nSuffix; + pParse->nAlloc = nNew; + pParse->aNode = pNew; + assert( pParse->nNodenAlloc ); + return jsonParseAddNode(pParse, eType, n, zContent); +} - if( aDoclist ){ - pNode->n += sqlite3Fts3PutVarint(&pNode->a[pNode->n], nDoclist); - memcpy(&pNode->a[pNode->n], aDoclist, nDoclist); - pNode->n += nDoclist; +/* +** Create a new JsonNode instance based on the arguments and append that +** instance to the JsonParse. Return the index in pParse->aNode[] of the +** new node, or -1 if a memory allocation fails. +*/ +static int jsonParseAddNode( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + JsonNode *p; + if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){ + return jsonParseAddNodeExpand(pParse, eType, n, zContent); } + p = &pParse->aNode[pParse->nNode]; + p->eType = (u8)eType; + p->jnFlags = 0; + VVA( p->eU = zContent ? 1 : 0 ); + p->n = n; + p->u.zJContent = zContent; + return pParse->nNode++; +} - assert( pNode->n<=pNode->nAlloc ); - - return SQLITE_OK; +/* +** Return true if z[] begins with 4 (or more) hexadecimal digits +*/ +static int jsonIs4Hex(const char *z){ + int i; + for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0; + return 1; } /* -** Append the current term and doclist pointed to by cursor pCsr to the -** appendable b-tree segment opened for writing by pWriter. +** Parse a single JSON value which begins at pParse->zJson[i]. Return the +** index of the first character past the end of the value parsed. ** -** Return SQLITE_OK if successful, or an SQLite error code otherwise. +** Return negative for a syntax error. Special cases: return -2 if the +** first non-whitespace character is '}' and return -3 if the first +** non-whitespace character is ']'. */ -static int fts3IncrmergeAppend( - Fts3Table *p, /* Fts3 table handle */ - IncrmergeWriter *pWriter, /* Writer object */ - Fts3MultiSegReader *pCsr /* Cursor containing term and doclist */ -){ - const char *zTerm = pCsr->zTerm; - int nTerm = pCsr->nTerm; - const char *aDoclist = pCsr->aDoclist; - int nDoclist = pCsr->nDoclist; - int rc = SQLITE_OK; /* Return code */ - int nSpace; /* Total space in bytes required on leaf */ - int nPrefix; /* Size of prefix shared with previous term */ - int nSuffix; /* Size of suffix (nTerm - nPrefix) */ - NodeWriter *pLeaf; /* Object used to write leaf nodes */ - - pLeaf = &pWriter->aNodeWriter[0]; - nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm); - nSuffix = nTerm - nPrefix; - - nSpace = sqlite3Fts3VarintLen(nPrefix); - nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; - nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; - - /* If the current block is not empty, and if adding this term/doclist - ** to the current block would make it larger than Fts3Table.nNodeSize - ** bytes, write this block out to the database. */ - if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){ - rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n); - pWriter->nWork++; - - /* Add the current term to the parent node. The term added to the - ** parent must: - ** - ** a) be greater than the largest term on the leaf node just written - ** to the database (still available in pLeaf->key), and - ** - ** b) be less than or equal to the term about to be added to the new - ** leaf node (zTerm/nTerm). - ** - ** In other words, it must be the prefix of zTerm 1 byte longer than - ** the common prefix (if any) of zTerm and pWriter->zTerm. - */ - if( rc==SQLITE_OK ){ - rc = fts3IncrmergePush(p, pWriter, zTerm, nPrefix+1); +static int jsonParseValue(JsonParse *pParse, u32 i){ + char c; + u32 j; + int iThis; + int x; + JsonNode *pNode; + const char *z = pParse->zJson; + while( fast_isspace(z[i]) ){ i++; } + if( (c = z[i])=='{' ){ + /* Parse object */ + iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + if( iThis<0 ) return -1; + for(j=i+1;;j++){ + while( fast_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; + x = jsonParseValue(pParse, j); + if( x<0 ){ + pParse->iDepth--; + if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } + if( pParse->oom ) return -1; + pNode = &pParse->aNode[pParse->nNode-1]; + if( pNode->eType!=JSON_STRING ) return -1; + pNode->jnFlags |= JNODE_LABEL; + j = x; + while( fast_isspace(z[j]) ){ j++; } + if( z[j]!=':' ) return -1; + j++; + x = jsonParseValue(pParse, j); + pParse->iDepth--; + if( x<0 ) return -1; + j = x; + while( fast_isspace(z[j]) ){ j++; } + c = z[j]; + if( c==',' ) continue; + if( c!='}' ) return -1; + break; } - - /* Advance to the next output block */ - pLeaf->iBlock++; - pLeaf->key.n = 0; - pLeaf->block.n = 0; - - nSuffix = nTerm; - nSpace = 1; - nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; - nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; - } - - pWriter->nLeafData += nSpace; - blobGrowBuffer(&pLeaf->block, pLeaf->block.n + nSpace, &rc); - if( rc==SQLITE_OK ){ - if( pLeaf->block.n==0 ){ - pLeaf->block.n = 1; - pLeaf->block.a[0] = '\0'; + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; + return j+1; + }else if( c=='[' ){ + /* Parse array */ + iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + if( iThis<0 ) return -1; + memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u)); + for(j=i+1;;j++){ + while( fast_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; + x = jsonParseValue(pParse, j); + pParse->iDepth--; + if( x<0 ){ + if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } + j = x; + while( fast_isspace(z[j]) ){ j++; } + c = z[j]; + if( c==',' ) continue; + if( c!=']' ) return -1; + break; } - rc = fts3AppendToNode( - &pLeaf->block, &pLeaf->key, zTerm, nTerm, aDoclist, nDoclist - ); + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; + return j+1; + }else if( c=='"' ){ + /* Parse string */ + u8 jnFlags = 0; + j = i+1; + for(;;){ + c = z[j]; + if( (c & ~0x1f)==0 ){ + /* Control characters are not allowed in strings */ + return -1; + } + if( c=='\\' ){ + c = z[++j]; + if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' + || c=='n' || c=='r' || c=='t' + || (c=='u' && jsonIs4Hex(z+j+1)) ){ + jnFlags = JNODE_ESCAPE; + }else{ + return -1; + } + }else if( c=='"' ){ + break; + } + j++; + } + jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); + if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; + return j+1; + }else if( c=='n' + && strncmp(z+i,"null",4)==0 + && !sqlite3Isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return i+4; + }else if( c=='t' + && strncmp(z+i,"true",4)==0 + && !sqlite3Isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + return i+4; + }else if( c=='f' + && strncmp(z+i,"false",5)==0 + && !sqlite3Isalnum(z[i+5]) ){ + jsonParseAddNode(pParse, JSON_FALSE, 0, 0); + return i+5; + }else if( c=='-' || (c>='0' && c<='9') ){ + /* Parse number */ + u8 seenDP = 0; + u8 seenE = 0; + assert( '-' < '0' ); + if( c<='0' ){ + j = c=='-' ? i+1 : i; + if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; + } + j = i+1; + for(;; j++){ + c = z[j]; + if( c>='0' && c<='9' ) continue; + if( c=='.' ){ + if( z[j-1]=='-' ) return -1; + if( seenDP ) return -1; + seenDP = 1; + continue; + } + if( c=='e' || c=='E' ){ + if( z[j-1]<'0' ) return -1; + if( seenE ) return -1; + seenDP = seenE = 1; + c = z[j+1]; + if( c=='+' || c=='-' ){ + j++; + c = z[j+1]; + } + if( c<'0' || c>'9' ) return -1; + continue; + } + break; + } + if( z[j-1]<'0' ) return -1; + jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, + j - i, &z[i]); + return j; + }else if( c=='}' ){ + return -2; /* End of {...} */ + }else if( c==']' ){ + return -3; /* End of [...] */ + }else if( c==0 ){ + return 0; /* End of file */ + }else{ + return -1; /* Syntax error */ } - - return rc; } /* -** This function is called to release all dynamic resources held by the -** merge-writer object pWriter, and if no error has occurred, to flush -** all outstanding node buffers held by pWriter to disk. -** -** If *pRc is not SQLITE_OK when this function is called, then no attempt -** is made to write any data to disk. Instead, this function serves only -** to release outstanding resources. +** Parse a complete JSON string. Return 0 on success or non-zero if there +** are any errors. If an error occurs, free all memory associated with +** pParse. ** -** Otherwise, if *pRc is initially SQLITE_OK and an error occurs while -** flushing buffers to disk, *pRc is set to an SQLite error code before -** returning. +** pParse is uninitialized when this routine is called. */ -static void fts3IncrmergeRelease( - Fts3Table *p, /* FTS3 table handle */ - IncrmergeWriter *pWriter, /* Merge-writer object */ - int *pRc /* IN/OUT: Error code */ +static int jsonParse( + JsonParse *pParse, /* Initialize and fill this JsonParse object */ + sqlite3_context *pCtx, /* Report errors here */ + const char *zJson /* Input JSON text to be parsed */ ){ - int i; /* Used to iterate through non-root layers */ - int iRoot; /* Index of root in pWriter->aNodeWriter */ - NodeWriter *pRoot; /* NodeWriter for root node */ - int rc = *pRc; /* Error code */ - - /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment - ** root node. If the segment fits entirely on a single leaf node, iRoot - ** will be set to 0. If the root node is the parent of the leaves, iRoot - ** will be 1. And so on. */ - for(iRoot=FTS_MAX_APPENDABLE_HEIGHT-1; iRoot>=0; iRoot--){ - NodeWriter *pNode = &pWriter->aNodeWriter[iRoot]; - if( pNode->block.n>0 ) break; - assert( *pRc || pNode->block.nAlloc==0 ); - assert( *pRc || pNode->key.nAlloc==0 ); - sqlite3_free(pNode->block.a); - sqlite3_free(pNode->key.a); + int i; + memset(pParse, 0, sizeof(*pParse)); + if( zJson==0 ) return 1; + pParse->zJson = zJson; + i = jsonParseValue(pParse, 0); + if( pParse->oom ) i = -1; + if( i>0 ){ + assert( pParse->iDepth==0 ); + while( fast_isspace(zJson[i]) ) i++; + if( zJson[i] ) i = -1; } - - /* Empty output segment. This is a no-op. */ - if( iRoot<0 ) return; - - /* The entire output segment fits on a single node. Normally, this means - ** the node would be stored as a blob in the "root" column of the %_segdir - ** table. However, this is not permitted in this case. The problem is that - ** space has already been reserved in the %_segments table, and so the - ** start_block and end_block fields of the %_segdir table must be populated. - ** And, by design or by accident, released versions of FTS cannot handle - ** segments that fit entirely on the root node with start_block!=0. - ** - ** Instead, create a synthetic root node that contains nothing but a - ** pointer to the single content node. So that the segment consists of a - ** single leaf and a single interior (root) node. - ** - ** Todo: Better might be to defer allocating space in the %_segments - ** table until we are sure it is needed. - */ - if( iRoot==0 ){ - Blob *pBlock = &pWriter->aNodeWriter[1].block; - blobGrowBuffer(pBlock, 1 + FTS3_VARINT_MAX, &rc); - if( rc==SQLITE_OK ){ - pBlock->a[0] = 0x01; - pBlock->n = 1 + sqlite3Fts3PutVarint( - &pBlock->a[1], pWriter->aNodeWriter[0].iBlock - ); + if( i<=0 ){ + if( pCtx!=0 ){ + if( pParse->oom ){ + sqlite3_result_error_nomem(pCtx); + }else{ + sqlite3_result_error(pCtx, "malformed JSON", -1); + } } - iRoot = 1; + jsonParseReset(pParse); + return 1; } - pRoot = &pWriter->aNodeWriter[iRoot]; + return 0; +} - /* Flush all currently outstanding nodes to disk. */ - for(i=0; iaNodeWriter[i]; - if( pNode->block.n>0 && rc==SQLITE_OK ){ - rc = fts3WriteSegment(p, pNode->iBlock, pNode->block.a, pNode->block.n); +/* Mark node i of pParse as being a child of iParent. Call recursively +** to fill in all the descendants of node i. +*/ +static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ + JsonNode *pNode = &pParse->aNode[i]; + u32 j; + pParse->aUp[i] = iParent; + switch( pNode->eType ){ + case JSON_ARRAY: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ + jsonParseFillInParentage(pParse, i+j, i); + } + break; + } + case JSON_OBJECT: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ + pParse->aUp[i+j] = i; + jsonParseFillInParentage(pParse, i+j+1, i); + } + break; + } + default: { + break; } - sqlite3_free(pNode->block.a); - sqlite3_free(pNode->key.a); } +} - /* Write the %_segdir record. */ - if( rc==SQLITE_OK ){ - rc = fts3WriteSegdir(p, - pWriter->iAbsLevel+1, /* level */ - pWriter->iIdx, /* idx */ - pWriter->iStart, /* start_block */ - pWriter->aNodeWriter[0].iBlock, /* leaves_end_block */ - pWriter->iEnd, /* end_block */ - (pWriter->bNoLeafData==0 ? pWriter->nLeafData : 0), /* end_block */ - pRoot->block.a, pRoot->block.n /* root */ - ); +/* +** Compute the parentage of all nodes in a completed parse. +*/ +static int jsonParseFindParents(JsonParse *pParse){ + u32 *aUp; + assert( pParse->aUp==0 ); + aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode ); + if( aUp==0 ){ + pParse->oom = 1; + return SQLITE_NOMEM; } - sqlite3_free(pRoot->block.a); - sqlite3_free(pRoot->key.a); - - *pRc = rc; + jsonParseFillInParentage(pParse, 0, 0); + return SQLITE_OK; } /* -** Compare the term in buffer zLhs (size in bytes nLhs) with that in -** zRhs (size in bytes nRhs) using memcmp. If one term is a prefix of -** the other, it is considered to be smaller than the other. -** -** Return -ve if zLhs is smaller than zRhs, 0 if it is equal, or +ve -** if it is greater. +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() */ -static int fts3TermCmp( - const char *zLhs, int nLhs, /* LHS of comparison */ - const char *zRhs, int nRhs /* RHS of comparison */ -){ - int nCmp = MIN(nLhs, nRhs); - int res; - - res = memcmp(zLhs, zRhs, nCmp); - if( res==0 ) res = nLhs - nRhs; +#define JSON_CACHE_ID (-429938) /* First cache entry */ +#define JSON_CACHE_SZ 4 /* Max number of cache entries */ - return res; +/* +** Obtain a complete parse of the JSON found in the first argument +** of the argv array. Use the sqlite3_get_auxdata() cache for this +** parse if it is available. If the cache is not available or if it +** is no longer valid, parse the JSON again and return the new parse, +** and also register the new parse so that it will be available for +** future sqlite3_get_auxdata() calls. +*/ +static JsonParse *jsonParseCached( + sqlite3_context *pCtx, + sqlite3_value **argv, + sqlite3_context *pErrCtx +){ + const char *zJson = (const char*)sqlite3_value_text(argv[0]); + int nJson = sqlite3_value_bytes(argv[0]); + JsonParse *p; + JsonParse *pMatch = 0; + int iKey; + int iMinKey = 0; + u32 iMinHold = 0xffffffff; + u32 iMaxHold = 0; + if( zJson==0 ) return 0; + for(iKey=0; iKeynJson==nJson + && memcmp(p->zJson,zJson,nJson)==0 + ){ + p->nErr = 0; + pMatch = p; + }else if( p->iHoldiHold; + iMinKey = iKey; + } + if( p->iHold>iMaxHold ){ + iMaxHold = p->iHold; + } + } + if( pMatch ){ + pMatch->nErr = 0; + pMatch->iHold = iMaxHold+1; + return pMatch; + } + p = sqlite3_malloc64( sizeof(*p) + nJson + 1 ); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } + memset(p, 0, sizeof(*p)); + p->zJson = (char*)&p[1]; + memcpy((char*)p->zJson, zJson, nJson+1); + if( jsonParse(p, pErrCtx, p->zJson) ){ + sqlite3_free(p); + return 0; + } + p->nJson = nJson; + p->iHold = iMaxHold+1; + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, + (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); } - /* -** Query to see if the entry in the %_segments table with blockid iEnd is -** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before -** returning. Otherwise, set *pbRes to 0. -** -** Or, if an error occurs while querying the database, return an SQLite -** error code. The final value of *pbRes is undefined in this case. -** -** This is used to test if a segment is an "appendable" segment. If it -** is, then a NULL entry has been inserted into the %_segments table -** with blockid %_segdir.end_block. +** Compare the OBJECT label at pNode against zKey,nKey. Return true on +** a match. */ -static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){ - int bRes = 0; /* Result to set *pbRes to */ - sqlite3_stmt *pCheck = 0; /* Statement to query database with */ - int rc; /* Return code */ - - rc = fts3SqlStmt(p, SQL_SEGMENT_IS_APPENDABLE, &pCheck, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pCheck, 1, iEnd); - if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1; - rc = sqlite3_reset(pCheck); +static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ + assert( pNode->eU==1 ); + if( pNode->jnFlags & JNODE_RAW ){ + if( pNode->n!=nKey ) return 0; + return strncmp(pNode->u.zJContent, zKey, nKey)==0; + }else{ + if( pNode->n!=nKey+2 ) return 0; + return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; } - - *pbRes = bRes; - return rc; } +/* forward declaration */ +static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); + /* -** This function is called when initializing an incremental-merge operation. -** It checks if the existing segment with index value iIdx at absolute level -** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the -** merge-writer object *pWriter is initialized to write to it. -** -** An existing segment can be appended to by an incremental merge if: -** -** * It was initially created as an appendable segment (with all required -** space pre-allocated), and +** Search along zPath to find the node specified. Return a pointer +** to that node, or NULL if zPath is malformed or if there is no such +** node. ** -** * The first key read from the input (arguments zKey and nKey) is -** greater than the largest key currently stored in the potential -** output segment. +** If pApnd!=0, then try to append new nodes to complete zPath if it is +** possible to do so and if no existing node corresponds to zPath. If +** new nodes are appended *pApnd is set to 1. */ -static int fts3IncrmergeLoad( - Fts3Table *p, /* Fts3 table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ - int iIdx, /* Index of candidate output segment */ - const char *zKey, /* First key to write */ - int nKey, /* Number of bytes in nKey */ - IncrmergeWriter *pWriter /* Populate this object */ +static JsonNode *jsonLookupStep( + JsonParse *pParse, /* The JSON to search */ + u32 iRoot, /* Begin the search at this node */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + const char **pzErr /* Make *pzErr point to any syntax error in zPath */ ){ - int rc; /* Return code */ - sqlite3_stmt *pSelect = 0; /* SELECT to read %_segdir entry */ - - rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pSelect, 0); - if( rc==SQLITE_OK ){ - sqlite3_int64 iStart = 0; /* Value of %_segdir.start_block */ - sqlite3_int64 iLeafEnd = 0; /* Value of %_segdir.leaves_end_block */ - sqlite3_int64 iEnd = 0; /* Value of %_segdir.end_block */ - const char *aRoot = 0; /* Pointer to %_segdir.root buffer */ - int nRoot = 0; /* Size of aRoot[] in bytes */ - int rc2; /* Return code from sqlite3_reset() */ - int bAppendable = 0; /* Set to true if segment is appendable */ - - /* Read the %_segdir entry for index iIdx absolute level (iAbsLevel+1) */ - sqlite3_bind_int64(pSelect, 1, iAbsLevel+1); - sqlite3_bind_int(pSelect, 2, iIdx); - if( sqlite3_step(pSelect)==SQLITE_ROW ){ - iStart = sqlite3_column_int64(pSelect, 1); - iLeafEnd = sqlite3_column_int64(pSelect, 2); - fts3ReadEndBlockField(pSelect, 3, &iEnd, &pWriter->nLeafData); - if( pWriter->nLeafData<0 ){ - pWriter->nLeafData = pWriter->nLeafData * -1; + u32 i, j, nKey; + const char *zKey; + JsonNode *pRoot = &pParse->aNode[iRoot]; + if( zPath[0]==0 ) return pRoot; + if( pRoot->jnFlags & JNODE_REPLACE ) return 0; + if( zPath[0]=='.' ){ + if( pRoot->eType!=JSON_OBJECT ) return 0; + zPath++; + if( zPath[0]=='"' ){ + zKey = zPath + 1; + for(i=1; zPath[i] && zPath[i]!='"'; i++){} + nKey = i-1; + if( zPath[i] ){ + i++; + }else{ + *pzErr = zPath; + return 0; } - pWriter->bNoLeafData = (pWriter->nLeafData==0); - nRoot = sqlite3_column_bytes(pSelect, 4); - aRoot = sqlite3_column_blob(pSelect, 4); }else{ - return sqlite3_reset(pSelect); + zKey = zPath; + for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} + nKey = i; } - - /* Check for the zero-length marker in the %_segments table */ - rc = fts3IsAppendable(p, iEnd, &bAppendable); - - /* Check that zKey/nKey is larger than the largest key the candidate */ - if( rc==SQLITE_OK && bAppendable ){ - char *aLeaf = 0; - int nLeaf = 0; - - rc = sqlite3Fts3ReadBlock(p, iLeafEnd, &aLeaf, &nLeaf, 0); - if( rc==SQLITE_OK ){ - NodeReader reader; - for(rc = nodeReaderInit(&reader, aLeaf, nLeaf); - rc==SQLITE_OK && reader.aNode; - rc = nodeReaderNext(&reader) - ){ - assert( reader.aNode ); - } - if( fts3TermCmp(zKey, nKey, reader.term.a, reader.term.n)<=0 ){ - bAppendable = 0; + if( nKey==0 ){ + *pzErr = zPath; + return 0; + } + j = 1; + for(;;){ + while( j<=pRoot->n ){ + if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ + return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); } - nodeReaderRelease(&reader); + j++; + j += jsonNodeSize(&pRoot[j]); } - sqlite3_free(aLeaf); + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + assert( pRoot->eU==2 ); + iRoot += pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; } - - if( rc==SQLITE_OK && bAppendable ){ - /* It is possible to append to this segment. Set up the IncrmergeWriter - ** object to do so. */ - int i; - int nHeight = (int)aRoot[0]; - NodeWriter *pNode; - - pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; - pWriter->iStart = iStart; - pWriter->iEnd = iEnd; - pWriter->iAbsLevel = iAbsLevel; - pWriter->iIdx = iIdx; - - for(i=nHeight+1; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; - } - - pNode = &pWriter->aNodeWriter[nHeight]; - pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; - blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc); - if( rc==SQLITE_OK ){ - memcpy(pNode->block.a, aRoot, nRoot); - pNode->block.n = nRoot; + if( pApnd ){ + u32 iStart, iLabel; + JsonNode *pNode; + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); + iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); + zPath += i; + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + assert( pRoot->eU==0 ); + pRoot->u.iAppend = iStart - iRoot; + pRoot->jnFlags |= JNODE_APPEND; + VVA( pRoot->eU = 2 ); + pParse->aNode[iLabel].jnFlags |= JNODE_RAW; } - - for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ - NodeReader reader; - pNode = &pWriter->aNodeWriter[i]; - - rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); - while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); - blobGrowBuffer(&pNode->key, reader.term.n, &rc); - if( rc==SQLITE_OK ){ - memcpy(pNode->key.a, reader.term.a, reader.term.n); - pNode->key.n = reader.term.n; - if( i>0 ){ - char *aBlock = 0; - int nBlock = 0; - pNode = &pWriter->aNodeWriter[i-1]; - pNode->iBlock = reader.iChild; - rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0); - blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc); - if( rc==SQLITE_OK ){ - memcpy(pNode->block.a, aBlock, nBlock); - pNode->block.n = nBlock; - } - sqlite3_free(aBlock); + return pNode; + } + }else if( zPath[0]=='[' ){ + i = 0; + j = 1; + while( sqlite3Isdigit(zPath[j]) ){ + i = i*10 + zPath[j] - '0'; + j++; + } + if( j<2 || zPath[j]!=']' ){ + if( zPath[1]=='#' ){ + JsonNode *pBase = pRoot; + int iBase = iRoot; + if( pRoot->eType!=JSON_ARRAY ) return 0; + for(;;){ + while( j<=pBase->n ){ + if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++; + j += jsonNodeSize(&pBase[j]); } + if( (pBase->jnFlags & JNODE_APPEND)==0 ) break; + assert( pBase->eU==2 ); + iBase += pBase->u.iAppend; + pBase = &pParse->aNode[iBase]; + j = 1; + } + j = 2; + if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ + unsigned int x = 0; + j = 3; + do{ + x = x*10 + zPath[j] - '0'; + j++; + }while( sqlite3Isdigit(zPath[j]) ); + if( x>i ) return 0; + i -= x; } - nodeReaderRelease(&reader); + if( zPath[j]!=']' ){ + *pzErr = zPath; + return 0; + } + }else{ + *pzErr = zPath; + return 0; } } - - rc2 = sqlite3_reset(pSelect); - if( rc==SQLITE_OK ) rc = rc2; - } - - return rc; -} - -/* -** Determine the largest segment index value that exists within absolute -** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus -** one before returning SQLITE_OK. Or, if there are no segments at all -** within level iAbsLevel, set *piIdx to zero. -** -** If an error occurs, return an SQLite error code. The final value of -** *piIdx is undefined in this case. -*/ -static int fts3IncrmergeOutputIdx( - Fts3Table *p, /* FTS Table handle */ - sqlite3_int64 iAbsLevel, /* Absolute index of input segments */ - int *piIdx /* OUT: Next free index at iAbsLevel+1 */ -){ - int rc; - sqlite3_stmt *pOutputIdx = 0; /* SQL used to find output index */ - - rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pOutputIdx, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pOutputIdx, 1, iAbsLevel+1); - sqlite3_step(pOutputIdx); - *piIdx = sqlite3_column_int(pOutputIdx, 0); - rc = sqlite3_reset(pOutputIdx); - } - - return rc; -} - -/* -** Allocate an appendable output segment on absolute level iAbsLevel+1 -** with idx value iIdx. -** -** In the %_segdir table, a segment is defined by the values in three -** columns: -** -** start_block -** leaves_end_block -** end_block -** -** When an appendable segment is allocated, it is estimated that the -** maximum number of leaf blocks that may be required is the sum of the -** number of leaf blocks consumed by the input segments, plus the number -** of input segments, multiplied by two. This value is stored in stack -** variable nLeafEst. -** -** A total of 16*nLeafEst blocks are allocated when an appendable segment -** is created ((1 + end_block - start_block)==16*nLeafEst). The contiguous -** array of leaf nodes starts at the first block allocated. The array -** of interior nodes that are parents of the leaf nodes start at block -** (start_block + (1 + end_block - start_block) / 16). And so on. -** -** In the actual code below, the value "16" is replaced with the -** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT. -*/ -static int fts3IncrmergeWriter( - Fts3Table *p, /* Fts3 table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level of input segments */ - int iIdx, /* Index of new output segment */ - Fts3MultiSegReader *pCsr, /* Cursor that data will be read from */ - IncrmergeWriter *pWriter /* Populate this object */ -){ - int rc; /* Return Code */ - int i; /* Iterator variable */ - int nLeafEst = 0; /* Blocks allocated for leaf nodes */ - sqlite3_stmt *pLeafEst = 0; /* SQL used to determine nLeafEst */ - sqlite3_stmt *pFirstBlock = 0; /* SQL used to determine first block */ - - /* Calculate nLeafEst. */ - rc = fts3SqlStmt(p, SQL_MAX_LEAF_NODE_ESTIMATE, &pLeafEst, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pLeafEst, 1, iAbsLevel); - sqlite3_bind_int64(pLeafEst, 2, pCsr->nSegment); - if( SQLITE_ROW==sqlite3_step(pLeafEst) ){ - nLeafEst = sqlite3_column_int(pLeafEst, 0); + if( pRoot->eType!=JSON_ARRAY ) return 0; + zPath += j + 1; + j = 1; + for(;;){ + while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ + if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--; + j += jsonNodeSize(&pRoot[j]); + } + if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; + assert( pRoot->eU==2 ); + iRoot += pRoot->u.iAppend; + pRoot = &pParse->aNode[iRoot]; + j = 1; } - rc = sqlite3_reset(pLeafEst); - } - if( rc!=SQLITE_OK ) return rc; - - /* Calculate the first block to use in the output segment */ - rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pFirstBlock, 0); - if( rc==SQLITE_OK ){ - if( SQLITE_ROW==sqlite3_step(pFirstBlock) ){ - pWriter->iStart = sqlite3_column_int64(pFirstBlock, 0); - pWriter->iEnd = pWriter->iStart - 1; - pWriter->iEnd += nLeafEst * FTS_MAX_APPENDABLE_HEIGHT; + if( j<=pRoot->n ){ + return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); } - rc = sqlite3_reset(pFirstBlock); - } - if( rc!=SQLITE_OK ) return rc; - - /* Insert the marker in the %_segments table to make sure nobody tries - ** to steal the space just allocated. This is also used to identify - ** appendable segments. */ - rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0); - if( rc!=SQLITE_OK ) return rc; - - pWriter->iAbsLevel = iAbsLevel; - pWriter->nLeafEst = nLeafEst; - pWriter->iIdx = iIdx; - - /* Set up the array of NodeWriter objects */ - for(i=0; iaNodeWriter[i].iBlock = pWriter->iStart + i*pWriter->nLeafEst; + if( i==0 && pApnd ){ + u32 iStart; + JsonNode *pNode; + iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); + pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); + if( pParse->oom ) return 0; + if( pNode ){ + pRoot = &pParse->aNode[iRoot]; + assert( pRoot->eU==0 ); + pRoot->u.iAppend = iStart - iRoot; + pRoot->jnFlags |= JNODE_APPEND; + VVA( pRoot->eU = 2 ); + } + return pNode; + } + }else{ + *pzErr = zPath; } - return SQLITE_OK; + return 0; } /* -** Remove an entry from the %_segdir table. This involves running the -** following two statements: -** -** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx -** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx -** -** The DELETE statement removes the specific %_segdir level. The UPDATE -** statement ensures that the remaining segments have contiguously allocated -** idx values. +** Append content to pParse that will complete zPath. Return a pointer +** to the inserted node, or return NULL if the append fails. */ -static int fts3RemoveSegdirEntry( - Fts3Table *p, /* FTS3 table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level to delete from */ - int iIdx /* Index of %_segdir entry to delete */ +static JsonNode *jsonLookupAppend( + JsonParse *pParse, /* Append content to the JSON parse */ + const char *zPath, /* Description of content to append */ + int *pApnd, /* Set this flag to 1 */ + const char **pzErr /* Make this point to any syntax error */ ){ - int rc; /* Return code */ - sqlite3_stmt *pDelete = 0; /* DELETE statement */ - - rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_ENTRY, &pDelete, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pDelete, 1, iAbsLevel); - sqlite3_bind_int(pDelete, 2, iIdx); - sqlite3_step(pDelete); - rc = sqlite3_reset(pDelete); + *pApnd = 1; + if( zPath[0]==0 ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; + } + if( zPath[0]=='.' ){ + jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + }else if( strncmp(zPath,"[0]",3)==0 ){ + jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + }else{ + return 0; } + if( pParse->oom ) return 0; + return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); +} - return rc; +/* +** Return the text of a syntax error message on a JSON path. Space is +** obtained from sqlite3_malloc(). +*/ +static char *jsonPathSyntaxError(const char *zErr){ + return sqlite3_mprintf("JSON path error near '%q'", zErr); } /* -** One or more segments have just been removed from absolute level iAbsLevel. -** Update the 'idx' values of the remaining segments in the level so that -** the idx values are a contiguous sequence starting from 0. +** Do a node lookup using zPath. Return a pointer to the node on success. +** Return NULL if not found or if there is an error. +** +** On an error, write an error message into pCtx and increment the +** pParse->nErr counter. +** +** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if +** nodes are appended. */ -static int fts3RepackSegdirLevel( - Fts3Table *p, /* FTS3 table handle */ - sqlite3_int64 iAbsLevel /* Absolute level to repack */ +static JsonNode *jsonLookup( + JsonParse *pParse, /* The JSON to search */ + const char *zPath, /* The path to search */ + int *pApnd, /* Append nodes to complete path if not NULL */ + sqlite3_context *pCtx /* Report errors here, if not NULL */ ){ - int rc; /* Return code */ - int *aIdx = 0; /* Array of remaining idx values */ - int nIdx = 0; /* Valid entries in aIdx[] */ - int nAlloc = 0; /* Allocated size of aIdx[] */ - int i; /* Iterator variable */ - sqlite3_stmt *pSelect = 0; /* Select statement to read idx values */ - sqlite3_stmt *pUpdate = 0; /* Update statement to modify idx values */ - - rc = fts3SqlStmt(p, SQL_SELECT_INDEXES, &pSelect, 0); - if( rc==SQLITE_OK ){ - int rc2; - sqlite3_bind_int64(pSelect, 1, iAbsLevel); - while( SQLITE_ROW==sqlite3_step(pSelect) ){ - if( nIdx>=nAlloc ){ - int *aNew; - nAlloc += 16; - aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); - if( !aNew ){ - rc = SQLITE_NOMEM; - break; - } - aIdx = aNew; - } - aIdx[nIdx++] = sqlite3_column_int(pSelect, 0); - } - rc2 = sqlite3_reset(pSelect); - if( rc==SQLITE_OK ) rc = rc2; - } - - if( rc==SQLITE_OK ){ - rc = fts3SqlStmt(p, SQL_SHIFT_SEGDIR_ENTRY, &pUpdate, 0); - } - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pUpdate, 2, iAbsLevel); - } + const char *zErr = 0; + JsonNode *pNode = 0; + char *zMsg; - assert( p->bIgnoreSavepoint==0 ); - p->bIgnoreSavepoint = 1; - for(i=0; rc==SQLITE_OK && ibIgnoreSavepoint = 0; - - sqlite3_free(aIdx); - return rc; -} + zPath++; + pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); + if( zErr==0 ) return pNode; -static void fts3StartNode(Blob *pNode, int iHeight, sqlite3_int64 iChild){ - pNode->a[0] = (char)iHeight; - if( iChild ){ - assert( pNode->nAlloc>=1+sqlite3Fts3VarintLen(iChild) ); - pNode->n = 1 + sqlite3Fts3PutVarint(&pNode->a[1], iChild); +lookup_err: + pParse->nErr++; + assert( zErr!=0 && pCtx!=0 ); + zMsg = jsonPathSyntaxError(zErr); + if( zMsg ){ + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); }else{ - assert( pNode->nAlloc>=1 ); - pNode->n = 1; + sqlite3_result_error_nomem(pCtx); } + return 0; } + /* -** The first two arguments are a pointer to and the size of a segment b-tree -** node. The node may be a leaf or an internal node. -** -** This function creates a new node image in blob object *pNew by copying -** all terms that are greater than or equal to zTerm/nTerm (for leaf nodes) -** or greater than zTerm/nTerm (for internal nodes) from aNode/nNode. +** Report the wrong number of arguments for json_insert(), json_replace() +** or json_set(). */ -static int fts3TruncateNode( - const char *aNode, /* Current node image */ - int nNode, /* Size of aNode in bytes */ - Blob *pNew, /* OUT: Write new node image here */ - const char *zTerm, /* Omit all terms smaller than this */ - int nTerm, /* Size of zTerm in bytes */ - sqlite3_int64 *piBlock /* OUT: Block number in next layer down */ +static void jsonWrongNumArgs( + sqlite3_context *pCtx, + const char *zFuncName ){ - NodeReader reader; /* Reader object */ - Blob prev = {0, 0, 0}; /* Previous term written to new node */ - int rc = SQLITE_OK; /* Return code */ - int bLeaf = aNode[0]=='\0'; /* True for a leaf node */ - - /* Allocate required output space */ - blobGrowBuffer(pNew, nNode, &rc); - if( rc!=SQLITE_OK ) return rc; - pNew->n = 0; - - /* Populate new node buffer */ - for(rc = nodeReaderInit(&reader, aNode, nNode); - rc==SQLITE_OK && reader.aNode; - rc = nodeReaderNext(&reader) - ){ - if( pNew->n==0 ){ - int res = fts3TermCmp(reader.term.a, reader.term.n, zTerm, nTerm); - if( res<0 || (bLeaf==0 && res==0) ) continue; - fts3StartNode(pNew, (int)aNode[0], reader.iChild); - *piBlock = reader.iChild; - } - rc = fts3AppendToNode( - pNew, &prev, reader.term.a, reader.term.n, - reader.aDoclist, reader.nDoclist - ); - if( rc!=SQLITE_OK ) break; - } - if( pNew->n==0 ){ - fts3StartNode(pNew, (int)aNode[0], reader.iChild); - *piBlock = reader.iChild; - } - assert( pNew->n<=pNew->nAlloc ); - - nodeReaderRelease(&reader); - sqlite3_free(prev.a); - return rc; + char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", + zFuncName); + sqlite3_result_error(pCtx, zMsg, -1); + sqlite3_free(zMsg); } /* -** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute -** level iAbsLevel. This may involve deleting entries from the %_segments -** table, and modifying existing entries in both the %_segments and %_segdir -** tables. -** -** SQLITE_OK is returned if the segment is updated successfully. Or an -** SQLite error code otherwise. +** Mark all NULL entries in the Object passed in as JNODE_REMOVE. */ -static int fts3TruncateSegment( - Fts3Table *p, /* FTS3 table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level of segment to modify */ - int iIdx, /* Index within level of segment to modify */ - const char *zTerm, /* Remove terms smaller than this */ - int nTerm /* Number of bytes in buffer zTerm */ -){ - int rc = SQLITE_OK; /* Return code */ - Blob root = {0,0,0}; /* New root page image */ - Blob block = {0,0,0}; /* Buffer used for any other block */ - sqlite3_int64 iBlock = 0; /* Block id */ - sqlite3_int64 iNewStart = 0; /* New value for iStartBlock */ - sqlite3_int64 iOldStart = 0; /* Old value for iStartBlock */ - sqlite3_stmt *pFetch = 0; /* Statement used to fetch segdir */ - - rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR, &pFetch, 0); - if( rc==SQLITE_OK ){ - int rc2; /* sqlite3_reset() return code */ - sqlite3_bind_int64(pFetch, 1, iAbsLevel); - sqlite3_bind_int(pFetch, 2, iIdx); - if( SQLITE_ROW==sqlite3_step(pFetch) ){ - const char *aRoot = sqlite3_column_blob(pFetch, 4); - int nRoot = sqlite3_column_bytes(pFetch, 4); - iOldStart = sqlite3_column_int64(pFetch, 1); - rc = fts3TruncateNode(aRoot, nRoot, &root, zTerm, nTerm, &iBlock); - } - rc2 = sqlite3_reset(pFetch); - if( rc==SQLITE_OK ) rc = rc2; - } - - while( rc==SQLITE_OK && iBlock ){ - char *aBlock = 0; - int nBlock = 0; - iNewStart = iBlock; - - rc = sqlite3Fts3ReadBlock(p, iBlock, &aBlock, &nBlock, 0); - if( rc==SQLITE_OK ){ - rc = fts3TruncateNode(aBlock, nBlock, &block, zTerm, nTerm, &iBlock); - } - if( rc==SQLITE_OK ){ - rc = fts3WriteSegment(p, iNewStart, block.a, block.n); - } - sqlite3_free(aBlock); - } - - /* Variable iNewStart now contains the first valid leaf node. */ - if( rc==SQLITE_OK && iNewStart ){ - sqlite3_stmt *pDel = 0; - rc = fts3SqlStmt(p, SQL_DELETE_SEGMENTS_RANGE, &pDel, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pDel, 1, iOldStart); - sqlite3_bind_int64(pDel, 2, iNewStart-1); - sqlite3_step(pDel); - rc = sqlite3_reset(pDel); +static void jsonRemoveAllNulls(JsonNode *pNode){ + int i, n; + assert( pNode->eType==JSON_OBJECT ); + n = pNode->n; + for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){ + switch( pNode[i].eType ){ + case JSON_NULL: + pNode[i].jnFlags |= JNODE_REMOVE; + break; + case JSON_OBJECT: + jsonRemoveAllNulls(&pNode[i]); + break; } } +} - if( rc==SQLITE_OK ){ - sqlite3_stmt *pChomp = 0; - rc = fts3SqlStmt(p, SQL_CHOMP_SEGDIR, &pChomp, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pChomp, 1, iNewStart); - sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC); - sqlite3_bind_int64(pChomp, 3, iAbsLevel); - sqlite3_bind_int(pChomp, 4, iIdx); - sqlite3_step(pChomp); - rc = sqlite3_reset(pChomp); - } - } - sqlite3_free(root.a); - sqlite3_free(block.a); - return rc; -} +/**************************************************************************** +** SQL functions used for testing and debugging +****************************************************************************/ +#ifdef SQLITE_DEBUG /* -** This function is called after an incrmental-merge operation has run to -** merge (or partially merge) two or more segments from absolute level -** iAbsLevel. -** -** Each input segment is either removed from the db completely (if all of -** its data was copied to the output segment by the incrmerge operation) -** or modified in place so that it no longer contains those entries that -** have been duplicated in the output segment. +** The json_parse(JSON) function returns a string which describes +** a parse of the JSON provided. Or it returns NULL if JSON is not +** well-formed. */ -static int fts3IncrmergeChomp( - Fts3Table *p, /* FTS table handle */ - sqlite3_int64 iAbsLevel, /* Absolute level containing segments */ - Fts3MultiSegReader *pCsr, /* Chomp all segments opened by this cursor */ - int *pnRem /* Number of segments not deleted */ +static void jsonParseFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv ){ - int i; - int nRem = 0; - int rc = SQLITE_OK; - - for(i=pCsr->nSegment-1; i>=0 && rc==SQLITE_OK; i--){ - Fts3SegReader *pSeg = 0; - int j; + JsonString s; /* Output string - not real JSON */ + JsonParse x; /* The parse */ + u32 i; - /* Find the Fts3SegReader object with Fts3SegReader.iIdx==i. It is hiding - ** somewhere in the pCsr->apSegment[] array. */ - for(j=0; ALWAYS(jnSegment); j++){ - pSeg = pCsr->apSegment[j]; - if( pSeg->iIdx==i ) break; + assert( argc==1 ); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + jsonParseFindParents(&x); + jsonInit(&s, ctx); + for(i=0; inSegment && pSeg->iIdx==i ); - - if( pSeg->aNode==0 ){ - /* Seg-reader is at EOF. Remove the entire input segment. */ - rc = fts3DeleteSegment(p, pSeg); - if( rc==SQLITE_OK ){ - rc = fts3RemoveSegdirEntry(p, iAbsLevel, pSeg->iIdx); - } - *pnRem = 0; + jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d", + i, zType, x.aNode[i].n, x.aUp[i]); + assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 ); + if( x.aNode[i].u.zJContent!=0 ){ + assert( x.aNode[i].eU==1 ); + jsonAppendRaw(&s, " ", 1); + jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); }else{ - /* The incremental merge did not copy all the data from this - ** segment to the upper level. The segment is modified in place - ** so that it contains no keys smaller than zTerm/nTerm. */ - const char *zTerm = pSeg->zTerm; - int nTerm = pSeg->nTerm; - rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm); - nRem++; + assert( x.aNode[i].eU==0 ); } + jsonAppendRaw(&s, "\n", 1); } - - if( rc==SQLITE_OK && nRem!=pCsr->nSegment ){ - rc = fts3RepackSegdirLevel(p, iAbsLevel); - } - - *pnRem = nRem; - return rc; + jsonParseReset(&x); + jsonResult(&s); } /* -** Store an incr-merge hint in the database. +** The json_test1(JSON) function return true (1) if the input is JSON +** text generated by another json function. It returns (0) if the input +** is not known to be JSON. */ -static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){ - sqlite3_stmt *pReplace = 0; - int rc; /* Return code */ - - rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT); - sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC); - sqlite3_step(pReplace); - rc = sqlite3_reset(pReplace); - } - - return rc; +static void jsonTest1Func( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); } +#endif /* SQLITE_DEBUG */ + +/**************************************************************************** +** Scalar SQL function implementations +****************************************************************************/ /* -** Load an incr-merge hint from the database. The incr-merge hint, if one -** exists, is stored in the rowid==1 row of the %_stat table. -** -** If successful, populate blob *pHint with the value read from the %_stat -** table and return SQLITE_OK. Otherwise, if an error occurs, return an -** SQLite error code. +** Implementation of the json_QUOTE(VALUE) function. Return a JSON value +** corresponding to the SQL value input. Mostly this means putting +** double-quotes around strings and returning the unquoted string "null" +** when given a NULL input. */ -static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){ - sqlite3_stmt *pSelect = 0; - int rc; - - pHint->n = 0; - rc = fts3SqlStmt(p, SQL_SELECT_STAT, &pSelect, 0); - if( rc==SQLITE_OK ){ - int rc2; - sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT); - if( SQLITE_ROW==sqlite3_step(pSelect) ){ - const char *aHint = sqlite3_column_blob(pSelect, 0); - int nHint = sqlite3_column_bytes(pSelect, 0); - if( aHint ){ - blobGrowBuffer(pHint, nHint, &rc); - if( rc==SQLITE_OK ){ - memcpy(pHint->a, aHint, nHint); - pHint->n = nHint; - } - } - } - rc2 = sqlite3_reset(pSelect); - if( rc==SQLITE_OK ) rc = rc2; - } +static void jsonQuoteFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString jx; + UNUSED_PARAMETER(argc); - return rc; + jsonInit(&jx, ctx); + jsonAppendValue(&jx, argv[0]); + jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* -** If *pRc is not SQLITE_OK when this function is called, it is a no-op. -** Otherwise, append an entry to the hint stored in blob *pHint. Each entry -** consists of two varints, the absolute level number of the input segments -** and the number of input segments. -** -** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs, -** set *pRc to an SQLite error code before returning. +** Implementation of the json_array(VALUE,...) function. Return a JSON +** array that contains all values given in arguments. Or if any argument +** is a BLOB, throw an error. */ -static void fts3IncrmergeHintPush( - Blob *pHint, /* Hint blob to append to */ - i64 iAbsLevel, /* First varint to store in hint */ - int nInput, /* Second varint to store in hint */ - int *pRc /* IN/OUT: Error code */ +static void jsonArrayFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv ){ - blobGrowBuffer(pHint, pHint->n + 2*FTS3_VARINT_MAX, pRc); - if( *pRc==SQLITE_OK ){ - pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], iAbsLevel); - pHint->n += sqlite3Fts3PutVarint(&pHint->a[pHint->n], (i64)nInput); + int i; + JsonString jx; + + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '['); + for(i=0; in; - int i; - - i = pHint->n-2; - while( i>0 && (pHint->a[i-1] & 0x80) ) i--; - while( i>0 && (pHint->a[i-1] & 0x80) ) i--; - - pHint->n = i; - i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel); - i += fts3GetVarint32(&pHint->a[i], pnInput); - if( i!=nHint ) return FTS_CORRUPT_VTAB; +static void jsonArrayLengthFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse *p; /* The parse */ + sqlite3_int64 n = 0; + u32 i; + JsonNode *pNode; - return SQLITE_OK; + p = jsonParseCached(ctx, argv, ctx); + if( p==0 ) return; + assert( p->nNode ); + if( argc==2 ){ + const char *zPath = (const char*)sqlite3_value_text(argv[1]); + pNode = jsonLookup(p, zPath, 0, ctx); + }else{ + pNode = p->aNode; + } + if( pNode==0 ){ + return; + } + if( pNode->eType==JSON_ARRAY ){ + assert( (pNode->jnFlags & JNODE_APPEND)==0 ); + for(i=1; i<=pNode->n; n++){ + i += jsonNodeSize(&pNode[i]); + } + } + sqlite3_result_int64(ctx, n); } +/* +** Bit values for the flags passed into jsonExtractFunc() or +** jsonSetFunc() via the user-data value. +*/ +#define JSON_JSON 0x01 /* Result is always JSON */ +#define JSON_SQL 0x02 /* Result is always SQL */ +#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ +#define JSON_ISSET 0x04 /* json_set(), not json_insert() */ /* -** Attempt an incremental merge that writes nMerge leaf blocks. +** json_extract(JSON, PATH, ...) +** "->"(JSON,PATH) +** "->>"(JSON,PATH) ** -** Incremental merges happen nMin segments at a time. The segments -** to be merged are the nMin oldest segments (the ones with the smallest -** values for the _segdir.idx field) in the highest level that contains -** at least nMin segments. Multiple merges might occur in an attempt to -** write the quota of nMerge leaf blocks. +** Return the element described by PATH. Return NULL if that PATH element +** is not found. +** +** If JSON_JSON is set or if more that one PATH argument is supplied then +** always return a JSON representation of the result. If JSON_SQL is set, +** then always return an SQL representation of the result. If neither flag +** is present and argc==2, then return JSON for objects and arrays and SQL +** for all other values. +** +** When multiple PATH arguments are supplied, the result is a JSON array +** containing the result of each PATH. +** +** Abbreviated JSON path expressions are allows if JSON_ABPATH, for +** compatibility with PG. */ -SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ - int rc; /* Return code */ - int nRem = nMerge; /* Number of leaf pages yet to be written */ - Fts3MultiSegReader *pCsr; /* Cursor used to read input data */ - Fts3SegFilter *pFilter; /* Filter used with cursor pCsr */ - IncrmergeWriter *pWriter; /* Writer object */ - int nSeg = 0; /* Number of input segments */ - sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */ - Blob hint = {0, 0, 0}; /* Hint read from %_stat table */ - int bDirtyHint = 0; /* True if blob 'hint' has been modified */ - - /* Allocate space for the cursor, filter and writer objects */ - const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); - pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); - if( !pWriter ) return SQLITE_NOMEM; - pFilter = (Fts3SegFilter *)&pWriter[1]; - pCsr = (Fts3MultiSegReader *)&pFilter[1]; - - rc = fts3IncrmergeHintLoad(p, &hint); - while( rc==SQLITE_OK && nRem>0 ){ - const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; - sqlite3_stmt *pFindLevel = 0; /* SQL used to determine iAbsLevel */ - int bUseHint = 0; /* True if attempting to append */ - int iIdx = 0; /* Largest idx in level (iAbsLevel+1) */ - - /* Search the %_segdir table for the absolute level with the smallest - ** relative level number that contains at least nMin segments, if any. - ** If one is found, set iAbsLevel to the absolute level number and - ** nSeg to nMin. If no level with at least nMin segments can be found, - ** set nSeg to -1. - */ - rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0); - sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin)); - if( sqlite3_step(pFindLevel)==SQLITE_ROW ){ - iAbsLevel = sqlite3_column_int64(pFindLevel, 0); - nSeg = sqlite3_column_int(pFindLevel, 1); - assert( nSeg>=2 ); - }else{ - nSeg = -1; - } - rc = sqlite3_reset(pFindLevel); - - /* If the hint read from the %_stat table is not empty, check if the - ** last entry in it specifies a relative level smaller than or equal - ** to the level identified by the block above (if any). If so, this - ** iteration of the loop will work on merging at the hinted level. - */ - if( rc==SQLITE_OK && hint.n ){ - int nHint = hint.n; - sqlite3_int64 iHintAbsLevel = 0; /* Hint level */ - int nHintSeg = 0; /* Hint number of segments */ +static void jsonExtractFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse *p; /* The parse */ + JsonNode *pNode; + const char *zPath; + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); + JsonString jx; - rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg); - if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){ - iAbsLevel = iHintAbsLevel; - nSeg = nHintSeg; - bUseHint = 1; - bDirtyHint = 1; + if( argc<2 ) return; + p = jsonParseCached(ctx, argv, ctx); + if( p==0 ) return; + if( argc==2 ){ + /* With a single PATH argument */ + zPath = (const char*)sqlite3_value_text(argv[1]); + if( zPath==0 ) return; + if( flags & JSON_ABPATH ){ + if( zPath[0]!='$' ){ + /* The -> and ->> operators accept abbreviated PATH arguments. This + ** is mostly for compatibility with PostgreSQL, but also for + ** convenience. + ** + ** NUMBER ==> $[NUMBER] // PG compatible + ** LABEL ==> $.LABEL // PG compatible + ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience + */ + jsonInit(&jx, ctx); + if( sqlite3Isdigit(zPath[0]) ){ + jsonAppendRaw(&jx, "$[", 2); + jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); + jsonAppendRaw(&jx, "]", 2); + }else{ + jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='[')); + jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); + jsonAppendChar(&jx, 0); + } + pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx); + jsonReset(&jx); }else{ - /* This undoes the effect of the HintPop() above - so that no entry - ** is removed from the hint blob. */ - hint.n = nHint; + pNode = jsonLookup(p, zPath, 0, ctx); } - } - - /* If nSeg is less that zero, then there is no level with at least - ** nMin segments and no hint in the %_stat table. No work to do. - ** Exit early in this case. */ - if( nSeg<0 ) break; - - /* Open a cursor to iterate through the contents of the oldest nSeg - ** indexes of absolute level iAbsLevel. If this cursor is opened using - ** the 'hint' parameters, it is possible that there are less than nSeg - ** segments available in level iAbsLevel. In this case, no work is - ** done on iAbsLevel - fall through to the next iteration of the loop - ** to start work on some other level. */ - memset(pWriter, 0, nAlloc); - pFilter->flags = FTS3_SEGMENT_REQUIRE_POS; - - if( rc==SQLITE_OK ){ - rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx); - assert( bUseHint==1 || bUseHint==0 ); - if( iIdx==0 || (bUseHint && iIdx==1) ){ - int bIgnore = 0; - rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore); - if( bIgnore ){ - pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY; + if( pNode ){ + if( flags & JSON_JSON ){ + jsonReturnJson(pNode, ctx, 0); + }else{ + jsonReturn(pNode, ctx, 0); + sqlite3_result_subtype(ctx, 0); } } + }else{ + pNode = jsonLookup(p, zPath, 0, ctx); + if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0); } - - if( rc==SQLITE_OK ){ - rc = fts3IncrmergeCsr(p, iAbsLevel, nSeg, pCsr); - } - if( SQLITE_OK==rc && pCsr->nSegment==nSeg - && SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter)) - && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr)) - ){ - if( bUseHint && iIdx>0 ){ - const char *zKey = pCsr->zTerm; - int nKey = pCsr->nTerm; - rc = fts3IncrmergeLoad(p, iAbsLevel, iIdx-1, zKey, nKey, pWriter); + }else{ + /* Two or more PATH arguments results in a JSON array with each + ** element of the array being the value selected by one of the PATHs */ + int i; + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '['); + for(i=1; inErr ) break; + jsonAppendSeparator(&jx); + if( pNode ){ + jsonRenderNode(pNode, &jx, 0); }else{ - rc = fts3IncrmergeWriter(p, iAbsLevel, iIdx, pCsr, pWriter); - } - - if( rc==SQLITE_OK && pWriter->nLeafEst ){ - fts3LogMerge(nSeg, iAbsLevel); - do { - rc = fts3IncrmergeAppend(p, pWriter, pCsr); - if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr); - if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK; - }while( rc==SQLITE_ROW ); - - /* Update or delete the input segments */ - if( rc==SQLITE_OK ){ - nRem -= (1 + pWriter->nWork); - rc = fts3IncrmergeChomp(p, iAbsLevel, pCsr, &nSeg); - if( nSeg!=0 ){ - bDirtyHint = 1; - fts3IncrmergeHintPush(&hint, iAbsLevel, nSeg, &rc); - } - } - } - - if( nSeg!=0 ){ - pWriter->nLeafData = pWriter->nLeafData * -1; - } - fts3IncrmergeRelease(p, pWriter, &rc); - if( nSeg==0 && pWriter->bNoLeafData==0 ){ - fts3PromoteSegments(p, iAbsLevel+1, pWriter->nLeafData); + jsonAppendRaw(&jx, "null", 4); } } - - sqlite3Fts3SegReaderFinish(pCsr); - } - - /* Write the hint values into the %_stat table for the next incr-merger */ - if( bDirtyHint && rc==SQLITE_OK ){ - rc = fts3IncrmergeHintStore(p, &hint); + if( i==argc ){ + jsonAppendChar(&jx, ']'); + jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); + } + jsonReset(&jx); } - - sqlite3_free(pWriter); - sqlite3_free(hint.a); - return rc; -} - -/* -** Convert the text beginning at *pz into an integer and return -** its value. Advance *pz to point to the first character past -** the integer. -*/ -static int fts3Getint(const char **pz){ - const char *z = *pz; - int i = 0; - while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0'; - *pz = z; - return i; } -/* -** Process statements of the form: -** -** INSERT INTO table(table) VALUES('merge=A,B'); -** -** A and B are integers that decode to be the number of leaf pages -** written for the merge, and the minimum number of segments on a level -** before it will be selected for a merge, respectively. +/* This is the RFC 7396 MergePatch algorithm. */ -static int fts3DoIncrmerge( - Fts3Table *p, /* FTS3 table handle */ - const char *zParam /* Nul-terminated string containing "A,B" */ +static JsonNode *jsonMergePatch( + JsonParse *pParse, /* The JSON parser that contains the TARGET */ + u32 iTarget, /* Node of the TARGET in pParse */ + JsonNode *pPatch /* The PATCH */ ){ - int rc; - int nMin = (FTS3_MERGE_COUNT / 2); - int nMerge = 0; - const char *z = zParam; - - /* Read the first integer value */ - nMerge = fts3Getint(&z); - - /* If the first integer value is followed by a ',', read the second - ** integer value. */ - if( z[0]==',' && z[1]!='\0' ){ - z++; - nMin = fts3Getint(&z); - } - - if( z[0]!='\0' || nMin<2 ){ - rc = SQLITE_ERROR; - }else{ - rc = SQLITE_OK; - if( !p->bHasStat ){ - assert( p->bFts4==0 ); - sqlite3Fts3CreateStatTable(&rc, p); + u32 i, j; + u32 iRoot; + JsonNode *pTarget; + if( pPatch->eType!=JSON_OBJECT ){ + return pPatch; + } + assert( iTarget>=0 && iTargetnNode ); + pTarget = &pParse->aNode[iTarget]; + assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); + if( pTarget->eType!=JSON_OBJECT ){ + jsonRemoveAllNulls(pPatch); + return pPatch; + } + iRoot = iTarget; + for(i=1; in; i += jsonNodeSize(&pPatch[i+1])+1){ + u32 nKey; + const char *zKey; + assert( pPatch[i].eType==JSON_STRING ); + assert( pPatch[i].jnFlags & JNODE_LABEL ); + assert( pPatch[i].eU==1 ); + nKey = pPatch[i].n; + zKey = pPatch[i].u.zJContent; + assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); + for(j=1; jn; j += jsonNodeSize(&pTarget[j+1])+1 ){ + assert( pTarget[j].eType==JSON_STRING ); + assert( pTarget[j].jnFlags & JNODE_LABEL ); + assert( (pPatch[i].jnFlags & JNODE_RAW)==0 ); + if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){ + if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break; + if( pPatch[i+1].eType==JSON_NULL ){ + pTarget[j+1].jnFlags |= JNODE_REMOVE; + }else{ + JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); + if( pNew==0 ) return 0; + pTarget = &pParse->aNode[iTarget]; + if( pNew!=&pTarget[j+1] ){ + assert( pTarget[j+1].eU==0 + || pTarget[j+1].eU==1 + || pTarget[j+1].eU==2 ); + testcase( pTarget[j+1].eU==1 ); + testcase( pTarget[j+1].eU==2 ); + VVA( pTarget[j+1].eU = 5 ); + pTarget[j+1].u.pPatch = pNew; + pTarget[j+1].jnFlags |= JNODE_PATCH; + } + } + break; + } } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3Incrmerge(p, nMerge, nMin); + if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ + int iStart, iPatch; + iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); + jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); + iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + if( pParse->oom ) return 0; + jsonRemoveAllNulls(pPatch); + pTarget = &pParse->aNode[iTarget]; + assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 ); + testcase( pParse->aNode[iRoot].eU==2 ); + pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; + VVA( pParse->aNode[iRoot].eU = 2 ); + pParse->aNode[iRoot].u.iAppend = iStart - iRoot; + iRoot = iStart; + assert( pParse->aNode[iPatch].eU==0 ); + VVA( pParse->aNode[iPatch].eU = 5 ); + pParse->aNode[iPatch].jnFlags |= JNODE_PATCH; + pParse->aNode[iPatch].u.pPatch = &pPatch[i+1]; } - sqlite3Fts3SegmentsClose(p); } - return rc; + return pTarget; } /* -** Process statements of the form: -** -** INSERT INTO table(table) VALUES('automerge=X'); -** -** where X is an integer. X==0 means to turn automerge off. X!=0 means -** turn it on. The setting is persistent. +** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON +** object that is the result of running the RFC 7396 MergePatch() algorithm +** on the two arguments. */ -static int fts3DoAutoincrmerge( - Fts3Table *p, /* FTS3 table handle */ - const char *zParam /* Nul-terminated string containing boolean */ +static void jsonPatchFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv ){ - int rc = SQLITE_OK; - sqlite3_stmt *pStmt = 0; - p->nAutoincrmerge = fts3Getint(&zParam); - if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){ - p->nAutoincrmerge = 8; + JsonParse x; /* The JSON that is being patched */ + JsonParse y; /* The patch */ + JsonNode *pResult; /* The result of the merge */ + + UNUSED_PARAMETER(argc); + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){ + jsonParseReset(&x); + return; } - if( !p->bHasStat ){ - assert( p->bFts4==0 ); - sqlite3Fts3CreateStatTable(&rc, p); - if( rc ) return rc; + pResult = jsonMergePatch(&x, 0, y.aNode); + assert( pResult!=0 || x.oom ); + if( pResult ){ + jsonReturnJson(pResult, ctx, 0); + }else{ + sqlite3_result_error_nomem(ctx); } - rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pStmt, 0); - if( rc ) return rc; - sqlite3_bind_int(pStmt, 1, FTS_STAT_AUTOINCRMERGE); - sqlite3_bind_int(pStmt, 2, p->nAutoincrmerge); - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); - return rc; + jsonParseReset(&x); + jsonParseReset(&y); } + /* -** Return a 64-bit checksum for the FTS index entry specified by the -** arguments to this function. +** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON +** object that contains all name/value given in arguments. Or if any name +** is not a string or if any value is a BLOB, throw an error. */ -static u64 fts3ChecksumEntry( - const char *zTerm, /* Pointer to buffer containing term */ - int nTerm, /* Size of zTerm in bytes */ - int iLangid, /* Language id for current row */ - int iIndex, /* Index (0..Fts3Table.nIndex-1) */ - i64 iDocid, /* Docid for current row. */ - int iCol, /* Column number */ - int iPos /* Position */ +static void jsonObjectFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv ){ int i; - u64 ret = (u64)iDocid; - - ret += (ret<<3) + iLangid; - ret += (ret<<3) + iIndex; - ret += (ret<<3) + iCol; - ret += (ret<<3) + iPos; - for(i=0; inIndex-1) */ - int *pRc /* OUT: Return code */ +static void jsonRemoveFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv ){ - Fts3SegFilter filter; - Fts3MultiSegReader csr; - int rc; - u64 cksum = 0; - - assert( *pRc==SQLITE_OK ); - - memset(&filter, 0, sizeof(filter)); - memset(&csr, 0, sizeof(csr)); - filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; - filter.flags |= FTS3_SEGMENT_SCAN; + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; - rc = sqlite3Fts3SegReaderCursor( - p, iLangid, iIndex, FTS3_SEGCURSOR_ALL, 0, 0, 0, 1,&csr - ); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts3SegReaderStart(p, &csr, &filter); + if( argc<1 ) return; + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i++){ + zPath = (const char*)sqlite3_value_text(argv[i]); + if( zPath==0 ) goto remove_done; + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto remove_done; + if( pNode ) pNode->jnFlags |= JNODE_REMOVE; } - - if( rc==SQLITE_OK ){ - while( SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, &csr)) ){ - char *pCsr = csr.aDoclist; - char *pEnd = &pCsr[csr.nDoclist]; - - i64 iDocid = 0; - i64 iCol = 0; - i64 iPos = 0; - - pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid); - while( pCsriPrevLangid); - sqlite3_bind_int(pAllLangid, 2, p->nIndex); - while( rc==SQLITE_OK && sqlite3_step(pAllLangid)==SQLITE_ROW ){ - int iLangid = sqlite3_column_int(pAllLangid, 0); - int i; - for(i=0; inIndex; i++){ - cksum1 = cksum1 ^ fts3ChecksumIndex(p, iLangid, i, &rc); - } - } - rc2 = sqlite3_reset(pAllLangid); - if( rc==SQLITE_OK ) rc = rc2; + if( argc<1 ) return; + if( (argc&1)==0 ) { + jsonWrongNumArgs(ctx, "replace"); + return; } - - /* This block calculates the checksum according to the %_content table */ - if( rc==SQLITE_OK ){ - sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule; - sqlite3_stmt *pStmt = 0; - char *zSql; - - zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); - if( !zSql ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - } - - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - i64 iDocid = sqlite3_column_int64(pStmt, 0); - int iLang = langidFromSelect(p, pStmt); - int iCol; - - for(iCol=0; rc==SQLITE_OK && iColnColumn; iCol++){ - if( p->abNotindexed[iCol]==0 ){ - const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1); - int nText = sqlite3_column_bytes(pStmt, iCol+1); - sqlite3_tokenizer_cursor *pT = 0; - - rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT); - while( rc==SQLITE_OK ){ - char const *zToken; /* Buffer containing token */ - int nToken = 0; /* Number of bytes in token */ - int iDum1 = 0, iDum2 = 0; /* Dummy variables */ - int iPos = 0; /* Position of token in zText */ - - rc = pModule->xNext(pT, &zToken, &nToken, &iDum1, &iDum2, &iPos); - if( rc==SQLITE_OK ){ - int i; - cksum2 = cksum2 ^ fts3ChecksumEntry( - zToken, nToken, iLang, 0, iDocid, iCol, iPos - ); - for(i=1; inIndex; i++){ - if( p->aIndex[i].nPrefix<=nToken ){ - cksum2 = cksum2 ^ fts3ChecksumEntry( - zToken, p->aIndex[i].nPrefix, iLang, i, iDocid, iCol, iPos - ); - } - } - } - } - if( pT ) pModule->xClose(pT); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - } - } + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto replace_err; + if( pNode ){ + assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 ); + testcase( pNode->eU!=0 && pNode->eU!=1 ); + pNode->jnFlags |= (u8)JNODE_REPLACE; + VVA( pNode->eU = 4 ); + pNode->u.iReplace = i + 1; } - - sqlite3_finalize(pStmt); } - - *pbOk = (cksum1==cksum2); - return rc; + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + assert( x.aNode[0].eU==4 ); + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +replace_err: + jsonParseReset(&x); } + /* -** Run the integrity-check. If no error occurs and the current contents of -** the FTS index are correct, return SQLITE_OK. Or, if the contents of the -** FTS index are incorrect, return SQLITE_CORRUPT_VTAB. -** -** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite -** error code. -** -** The integrity-check works as follows. For each token and indexed token -** prefix in the document set, a 64-bit checksum is calculated (by code -** in fts3ChecksumEntry()) based on the following: -** -** + The index number (0 for the main index, 1 for the first prefix -** index etc.), -** + The token (or token prefix) text itself, -** + The language-id of the row it appears in, -** + The docid of the row it appears in, -** + The column it appears in, and -** + The tokens position within that column. -** -** The checksums for all entries in the index are XORed together to create -** a single checksum for the entire index. +** json_set(JSON, PATH, VALUE, ...) ** -** The integrity-check code calculates the same checksum in two ways: +** Set the value at PATH to VALUE. Create the PATH if it does not already +** exist. Overwrite existing values that do exist. +** If JSON or PATH is malformed, throw an error. ** -** 1. By scanning the contents of the FTS index, and -** 2. By scanning and tokenizing the content table. +** json_insert(JSON, PATH, VALUE, ...) ** -** If the two checksums are identical, the integrity-check is deemed to have -** passed. +** Create PATH and initialize it to VALUE. If PATH already exists, this +** routine is a no-op. If JSON or PATH is malformed, throw an error. */ -static int fts3DoIntegrityCheck( - Fts3Table *p /* FTS3 table handle */ +static void jsonSetFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv ){ - int rc; - int bOk = 0; - rc = fts3IntegrityCheck(p, &bOk); - if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB; - return rc; + JsonParse x; /* The parse */ + JsonNode *pNode; + const char *zPath; + u32 i; + int bApnd; + int bIsSet = sqlite3_user_data(ctx)!=0; + + if( argc<1 ) return; + if( (argc&1)==0 ) { + jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); + return; + } + if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + bApnd = 0; + pNode = jsonLookup(&x, zPath, &bApnd, ctx); + if( x.oom ){ + sqlite3_result_error_nomem(ctx); + goto jsonSetDone; + }else if( x.nErr ){ + goto jsonSetDone; + }else if( pNode && (bApnd || bIsSet) ){ + testcase( pNode->eU!=0 && pNode->eU!=1 ); + assert( pNode->eU!=3 && pNode->eU!=5 ); + VVA( pNode->eU = 4 ); + pNode->jnFlags |= (u8)JNODE_REPLACE; + pNode->u.iReplace = i + 1; + } + } + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + assert( x.aNode[0].eU==4 ); + sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } +jsonSetDone: + jsonParseReset(&x); } /* -** Handle a 'special' INSERT of the form: -** -** "INSERT INTO tbl(tbl) VALUES()" +** json_type(JSON) +** json_type(JSON, PATH) ** -** Argument pVal contains the result of . Currently the only -** meaningful value to insert is the text 'optimize'. +** Return the top-level "type" of a JSON string. json_type() raises an +** error if either the JSON or PATH inputs are not well-formed. */ -static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ - int rc; /* Return Code */ - const char *zVal = (const char *)sqlite3_value_text(pVal); - int nVal = sqlite3_value_bytes(pVal); +static void jsonTypeFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse *p; /* The parse */ + const char *zPath; + JsonNode *pNode; - if( !zVal ){ - return SQLITE_NOMEM; - }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ - rc = fts3DoOptimize(p, 0); - }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ - rc = fts3DoRebuild(p); - }else if( nVal==15 && 0==sqlite3_strnicmp(zVal, "integrity-check", 15) ){ - rc = fts3DoIntegrityCheck(p); - }else if( nVal>6 && 0==sqlite3_strnicmp(zVal, "merge=", 6) ){ - rc = fts3DoIncrmerge(p, &zVal[6]); - }else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){ - rc = fts3DoAutoincrmerge(p, &zVal[10]); -#ifdef SQLITE_TEST - }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ - p->nNodeSize = atoi(&zVal[9]); - rc = SQLITE_OK; - }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ - p->nMaxPendingData = atoi(&zVal[11]); - rc = SQLITE_OK; - }else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){ - p->bNoIncrDoclist = atoi(&zVal[21]); - rc = SQLITE_OK; -#endif + p = jsonParseCached(ctx, argv, ctx); + if( p==0 ) return; + if( argc==2 ){ + zPath = (const char*)sqlite3_value_text(argv[1]); + pNode = jsonLookup(p, zPath, 0, ctx); }else{ - rc = SQLITE_ERROR; + pNode = p->aNode; + } + if( pNode ){ + sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); } +} - return rc; +/* +** json_valid(JSON) +** +** Return 1 if JSON is a well-formed JSON string according to RFC-7159. +** Return 0 otherwise. +*/ +static void jsonValidFunc( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonParse *p; /* The parse */ + UNUSED_PARAMETER(argc); + p = jsonParseCached(ctx, argv, 0); + sqlite3_result_int(ctx, p!=0); } -#ifndef SQLITE_DISABLE_FTS4_DEFERRED + +/**************************************************************************** +** Aggregate SQL function implementations +****************************************************************************/ /* -** Delete all cached deferred doclists. Deferred doclists are cached -** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function. +** json_group_array(VALUE) +** +** Return a JSON array composed of all values in the aggregate. */ -SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){ - Fts3DeferredToken *pDef; - for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){ - fts3PendingListDelete(pDef->pList); - pDef->pList = 0; +static void jsonArrayStep( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString *pStr; + UNUSED_PARAMETER(argc); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); + if( pStr ){ + if( pStr->zBuf==0 ){ + jsonInit(pStr, ctx); + jsonAppendChar(pStr, '['); + }else if( pStr->nUsed>1 ){ + jsonAppendChar(pStr, ','); + } + pStr->pCtx = ctx; + jsonAppendValue(pStr, argv[0]); + } +} +static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ + JsonString *pStr; + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); + if( pStr ){ + pStr->pCtx = ctx; + jsonAppendChar(pStr, ']'); + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); + }else if( isFinal ){ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); + pStr->bStatic = 1; + }else{ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); + pStr->nUsed--; + } + }else{ + sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} +static void jsonArrayValue(sqlite3_context *ctx){ + jsonArrayCompute(ctx, 0); +} +static void jsonArrayFinal(sqlite3_context *ctx){ + jsonArrayCompute(ctx, 1); } +#ifndef SQLITE_OMIT_WINDOWFUNC /* -** Free all entries in the pCsr->pDeffered list. Entries are added to -** this list using sqlite3Fts3DeferToken(). +** This method works for both json_group_array() and json_group_object(). +** It works by removing the first element of the group by searching forward +** to the first comma (",") that is not within a string and deleting all +** text through that comma. */ -SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){ - Fts3DeferredToken *pDef; - Fts3DeferredToken *pNext; - for(pDef=pCsr->pDeferred; pDef; pDef=pNext){ - pNext = pDef->pNext; - fts3PendingListDelete(pDef->pList); - sqlite3_free(pDef); +static void jsonGroupInverse( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + unsigned int i; + int inStr = 0; + int nNest = 0; + char *z; + char c; + JsonString *pStr; + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(argv); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); +#ifdef NEVER + /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will + ** always have been called to initalize it */ + if( NEVER(!pStr) ) return; +#endif + z = pStr->zBuf; + for(i=1; inUsed && ((c = z[i])!=',' || inStr || nNest); i++){ + if( c=='"' ){ + inStr = !inStr; + }else if( c=='\\' ){ + i++; + }else if( !inStr ){ + if( c=='{' || c=='[' ) nNest++; + if( c=='}' || c==']' ) nNest--; + } + } + if( inUsed ){ + pStr->nUsed -= i; + memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); + z[pStr->nUsed] = 0; + }else{ + pStr->nUsed = 1; } - pCsr->pDeferred = 0; } +#else +# define jsonGroupInverse 0 +#endif + /* -** Generate deferred-doclists for all tokens in the pCsr->pDeferred list -** based on the row that pCsr currently points to. +** json_group_obj(NAME,VALUE) ** -** A deferred-doclist is like any other doclist with position information -** included, except that it only contains entries for a single row of the -** table, not for all rows. +** Return a JSON object composed of all names and values in the aggregate. */ -SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){ - int rc = SQLITE_OK; /* Return code */ - if( pCsr->pDeferred ){ - int i; /* Used to iterate through table columns */ - sqlite3_int64 iDocid; /* Docid of the row pCsr points to */ - Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */ - - Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; - sqlite3_tokenizer *pT = p->pTokenizer; - sqlite3_tokenizer_module const *pModule = pT->pModule; - - assert( pCsr->isRequireSeek==0 ); - iDocid = sqlite3_column_int64(pCsr->pStmt, 0); - - for(i=0; inColumn && rc==SQLITE_OK; i++){ - if( p->abNotindexed[i]==0 ){ - const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1); - sqlite3_tokenizer_cursor *pTC = 0; - - rc = sqlite3Fts3OpenTokenizer(pT, pCsr->iLangid, zText, -1, &pTC); - while( rc==SQLITE_OK ){ - char const *zToken; /* Buffer containing token */ - int nToken = 0; /* Number of bytes in token */ - int iDum1 = 0, iDum2 = 0; /* Dummy variables */ - int iPos = 0; /* Position of token in zText */ - - rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); - for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ - Fts3PhraseToken *pPT = pDef->pToken; - if( (pDef->iCol>=p->nColumn || pDef->iCol==i) - && (pPT->bFirst==0 || iPos==0) - && (pPT->n==nToken || (pPT->isPrefix && pPT->nz, pPT->n)) - ){ - fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); - } - } - } - if( pTC ) pModule->xClose(pTC); - if( rc==SQLITE_DONE ) rc = SQLITE_OK; - } +static void jsonObjectStep( + sqlite3_context *ctx, + int argc, + sqlite3_value **argv +){ + JsonString *pStr; + const char *z; + u32 n; + UNUSED_PARAMETER(argc); + pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); + if( pStr ){ + if( pStr->zBuf==0 ){ + jsonInit(pStr, ctx); + jsonAppendChar(pStr, '{'); + }else if( pStr->nUsed>1 ){ + jsonAppendChar(pStr, ','); } - - for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ - if( pDef->pList ){ - rc = fts3PendingListAppendVarint(&pDef->pList, 0); - } + pStr->pCtx = ctx; + z = (const char*)sqlite3_value_text(argv[0]); + n = (u32)sqlite3_value_bytes(argv[0]); + jsonAppendString(pStr, z, n); + jsonAppendChar(pStr, ':'); + jsonAppendValue(pStr, argv[1]); + } +} +static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ + JsonString *pStr; + pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); + if( pStr ){ + jsonAppendChar(pStr, '}'); + if( pStr->bErr ){ + if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); + assert( pStr->bStatic ); + }else if( isFinal ){ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, + pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); + pStr->bStatic = 1; + }else{ + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); + pStr->nUsed--; } + }else{ + sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); } - - return rc; + sqlite3_result_subtype(ctx, JSON_SUBTYPE); +} +static void jsonObjectValue(sqlite3_context *ctx){ + jsonObjectCompute(ctx, 0); +} +static void jsonObjectFinal(sqlite3_context *ctx){ + jsonObjectCompute(ctx, 1); } -SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList( - Fts3DeferredToken *p, - char **ppData, - int *pnData + + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/**************************************************************************** +** The json_each virtual table +****************************************************************************/ +typedef struct JsonEachCursor JsonEachCursor; +struct JsonEachCursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + u32 iRowid; /* The rowid */ + u32 iBegin; /* The first node of the scan */ + u32 i; /* Index in sParse.aNode[] of current row */ + u32 iEnd; /* EOF when i equals or exceeds this value */ + u8 eType; /* Type of top-level element */ + u8 bRecursive; /* True for json_tree(). False for json_each() */ + char *zJson; /* Input JSON */ + char *zRoot; /* Path by which to filter zJson */ + JsonParse sParse; /* Parse of the input JSON */ +}; + +/* Constructor for the json_each virtual table */ +static int jsonEachConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr ){ - char *pRet; - int nSkip; - sqlite3_int64 dummy; + sqlite3_vtab *pNew; + int rc; - *ppData = 0; - *pnData = 0; +/* Column numbers */ +#define JEACH_KEY 0 +#define JEACH_VALUE 1 +#define JEACH_TYPE 2 +#define JEACH_ATOM 3 +#define JEACH_ID 4 +#define JEACH_PARENT 5 +#define JEACH_FULLKEY 6 +#define JEACH_PATH 7 +/* The xBestIndex method assumes that the JSON and ROOT columns are +** the last two columns in the table. Should this ever changes, be +** sure to update the xBestIndex method. */ +#define JEACH_JSON 8 +#define JEACH_ROOT 9 - if( p->pList==0 ){ - return SQLITE_OK; + UNUSED_PARAMETER(pzErr); + UNUSED_PARAMETER(argv); + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(pAux); + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," + "json HIDDEN,root HIDDEN)"); + if( rc==SQLITE_OK ){ + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); } + return rc; +} - pRet = (char *)sqlite3_malloc(p->pList->nData); - if( !pRet ) return SQLITE_NOMEM; +/* destructor for json_each virtual table */ +static int jsonEachDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} - nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); - *pnData = p->pList->nData - nSkip; - *ppData = pRet; - - memcpy(pRet, &p->pList->aData[nSkip], *pnData); +/* constructor for a JsonEachCursor object for json_each(). */ +static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + JsonEachCursor *pCur; + + UNUSED_PARAMETER(p); + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; return SQLITE_OK; } -/* -** Add an entry for token pToken to the pCsr->pDeferred list. -*/ -SQLITE_PRIVATE int sqlite3Fts3DeferToken( - Fts3Cursor *pCsr, /* Fts3 table cursor */ - Fts3PhraseToken *pToken, /* Token to defer */ - int iCol /* Column that token must appear in (or -1) */ -){ - Fts3DeferredToken *pDeferred; - pDeferred = sqlite3_malloc(sizeof(*pDeferred)); - if( !pDeferred ){ - return SQLITE_NOMEM; +/* constructor for a JsonEachCursor object for json_tree(). */ +static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + int rc = jsonEachOpenEach(p, ppCursor); + if( rc==SQLITE_OK ){ + JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; + pCur->bRecursive = 1; } - memset(pDeferred, 0, sizeof(*pDeferred)); - pDeferred->pToken = pToken; - pDeferred->pNext = pCsr->pDeferred; - pDeferred->iCol = iCol; - pCsr->pDeferred = pDeferred; + return rc; +} - assert( pToken->pDeferred==0 ); - pToken->pDeferred = pDeferred; +/* Reset a JsonEachCursor back to its original state. Free any memory +** held. */ +static void jsonEachCursorReset(JsonEachCursor *p){ + sqlite3_free(p->zJson); + sqlite3_free(p->zRoot); + jsonParseReset(&p->sParse); + p->iRowid = 0; + p->i = 0; + p->iEnd = 0; + p->eType = 0; + p->zJson = 0; + p->zRoot = 0; +} +/* Destructor for a jsonEachCursor object */ +static int jsonEachClose(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + jsonEachCursorReset(p); + sqlite3_free(cur); return SQLITE_OK; } -#endif -/* -** SQLite value pRowid contains the rowid of a row that may or may not be -** present in the FTS3 table. If it is, delete it and adjust the contents -** of subsiduary data structures accordingly. +/* Return TRUE if the jsonEachCursor object has been advanced off the end +** of the JSON object */ +static int jsonEachEof(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + return p->i >= p->iEnd; +} + +/* Advance the cursor to the next element for json_tree() */ +static int jsonEachNext(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + if( p->bRecursive ){ + if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; + p->i++; + p->iRowid++; + if( p->iiEnd ){ + u32 iUp = p->sParse.aUp[p->i]; + JsonNode *pUp = &p->sParse.aNode[iUp]; + p->eType = pUp->eType; + if( pUp->eType==JSON_ARRAY ){ + assert( pUp->eU==0 || pUp->eU==3 ); + testcase( pUp->eU==3 ); + VVA( pUp->eU = 3 ); + if( iUp==p->i-1 ){ + pUp->u.iKey = 0; + }else{ + pUp->u.iKey++; + } + } + } + }else{ + switch( p->eType ){ + case JSON_ARRAY: { + p->i += jsonNodeSize(&p->sParse.aNode[p->i]); + p->iRowid++; + break; + } + case JSON_OBJECT: { + p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); + p->iRowid++; + break; + } + default: { + p->i = p->iEnd; + break; + } + } + } + return SQLITE_OK; +} + +/* Append the name of the path for element i to pStr */ -static int fts3DeleteByRowid( - Fts3Table *p, - sqlite3_value *pRowid, - int *pnChng, /* IN/OUT: Decrement if row is deleted */ - u32 *aSzDel +static void jsonEachComputePath( + JsonEachCursor *p, /* The cursor */ + JsonString *pStr, /* Write the path here */ + u32 i /* Path to this element */ ){ - int rc = SQLITE_OK; /* Return code */ - int bFound = 0; /* True if *pRowid really is in the table */ + JsonNode *pNode, *pUp; + u32 iUp; + if( i==0 ){ + jsonAppendChar(pStr, '$'); + return; + } + iUp = p->sParse.aUp[i]; + jsonEachComputePath(p, pStr, iUp); + pNode = &p->sParse.aNode[i]; + pUp = &p->sParse.aNode[iUp]; + if( pUp->eType==JSON_ARRAY ){ + assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) ); + testcase( pUp->eU==0 ); + jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); + }else{ + assert( pUp->eType==JSON_OBJECT ); + if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; + assert( pNode->eType==JSON_STRING ); + assert( pNode->jnFlags & JNODE_LABEL ); + assert( pNode->eU==1 ); + jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); + } +} - fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound); - if( bFound && rc==SQLITE_OK ){ - int isEmpty = 0; /* Deleting *pRowid leaves the table empty */ - rc = fts3IsEmpty(p, pRowid, &isEmpty); - if( rc==SQLITE_OK ){ - if( isEmpty ){ - /* Deleting this row means the whole table is empty. In this case - ** delete the contents of all three tables and throw away any - ** data in the pendingTerms hash table. */ - rc = fts3DeleteAll(p, 1); - *pnChng = 0; - memset(aSzDel, 0, sizeof(u32) * (p->nColumn+1) * 2); +/* Return the value of a column */ +static int jsonEachColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + JsonEachCursor *p = (JsonEachCursor*)cur; + JsonNode *pThis = &p->sParse.aNode[p->i]; + switch( i ){ + case JEACH_KEY: { + if( p->i==0 ) break; + if( p->eType==JSON_OBJECT ){ + jsonReturn(pThis, ctx, 0); + }else if( p->eType==JSON_ARRAY ){ + u32 iKey; + if( p->bRecursive ){ + if( p->iRowid==0 ) break; + assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 ); + iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; + }else{ + iKey = p->iRowid; + } + sqlite3_result_int64(ctx, (sqlite3_int64)iKey); + } + break; + } + case JEACH_VALUE: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_TYPE: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); + break; + } + case JEACH_ATOM: { + if( pThis->jnFlags & JNODE_LABEL ) pThis++; + if( pThis->eType>=JSON_ARRAY ) break; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_ID: { + sqlite3_result_int64(ctx, + (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); + break; + } + case JEACH_PARENT: { + if( p->i>p->iBegin && p->bRecursive ){ + sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); + } + break; + } + case JEACH_FULLKEY: { + JsonString x; + jsonInit(&x, ctx); + if( p->bRecursive ){ + jsonEachComputePath(p, &x, p->i); }else{ - *pnChng = *pnChng - 1; - if( p->zContentTbl==0 ){ - fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); + if( p->zRoot ){ + jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); + }else{ + jsonAppendChar(&x, '$'); } - if( p->bHasDocsize ){ - fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); + if( p->eType==JSON_ARRAY ){ + jsonPrintf(30, &x, "[%d]", p->iRowid); + }else if( p->eType==JSON_OBJECT ){ + assert( pThis->eU==1 ); + jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); } } + jsonResult(&x); + break; + } + case JEACH_PATH: { + if( p->bRecursive ){ + JsonString x; + jsonInit(&x, ctx); + jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); + jsonResult(&x); + break; + } + /* For json_each() path and root are the same so fall through + ** into the root case */ + /* no break */ deliberate_fall_through + } + default: { + const char *zRoot = p->zRoot; + if( zRoot==0 ) zRoot = "$"; + sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); + break; + } + case JEACH_JSON: { + assert( i==JEACH_JSON ); + sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); + break; } } + return SQLITE_OK; +} - return rc; +/* Return the current rowid value */ +static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + JsonEachCursor *p = (JsonEachCursor*)cur; + *pRowid = p->iRowid; + return SQLITE_OK; } -/* -** This function does the work for the xUpdate method of FTS3 virtual -** tables. The schema of the virtual table being: -** -** CREATE TABLE
            ( -** , -**
            HIDDEN, -** docid HIDDEN, -** HIDDEN -** ); -** -** +/* The query strategy is to look for an equality constraint on the json +** column. Without such a constraint, the table cannot operate. idxNum is +** 1 if the constraint is found, 3 if the constraint and zRoot are found, +** and 0 otherwise. */ -SQLITE_PRIVATE int sqlite3Fts3UpdateMethod( - sqlite3_vtab *pVtab, /* FTS3 vtab object */ - int nArg, /* Size of argument array */ - sqlite3_value **apVal, /* Array of arguments */ - sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ +static int jsonEachBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo ){ - Fts3Table *p = (Fts3Table *)pVtab; - int rc = SQLITE_OK; /* Return Code */ - int isRemove = 0; /* True for an UPDATE or DELETE */ - u32 *aSzIns = 0; /* Sizes of inserted documents */ - u32 *aSzDel = 0; /* Sizes of deleted documents */ - int nChng = 0; /* Net change in number of documents */ - int bInsertDone = 0; - - /* At this point it must be known if the %_stat table exists or not. - ** So bHasStat may not be 2. */ - assert( p->bHasStat==0 || p->bHasStat==1 ); - - assert( p->pSegments==0 ); - assert( - nArg==1 /* DELETE operations */ - || nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */ - ); - - /* Check for a "special" INSERT operation. One of the form: - ** - ** INSERT INTO xyz(xyz) VALUES('command'); - */ - if( nArg>1 - && sqlite3_value_type(apVal[0])==SQLITE_NULL - && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL - ){ - rc = fts3SpecialInsert(p, apVal[p->nColumn+2]); - goto update_out; - } - - if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){ - rc = SQLITE_CONSTRAINT; - goto update_out; - } + int i; /* Loop counter or computed array index */ + int aIdx[2]; /* Index of constraints for JSON and ROOT */ + int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */ + int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */ + const struct sqlite3_index_constraint *pConstraint; - /* Allocate space to hold the change in document sizes */ - aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 ); - if( aSzDel==0 ){ - rc = SQLITE_NOMEM; - goto update_out; + /* This implementation assumes that JSON and ROOT are the last two + ** columns in the table */ + assert( JEACH_ROOT == JEACH_JSON+1 ); + UNUSED_PARAMETER(tab); + aIdx[0] = aIdx[1] = -1; + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + int iCol; + int iMask; + if( pConstraint->iColumn < JEACH_JSON ) continue; + iCol = pConstraint->iColumn - JEACH_JSON; + assert( iCol==0 || iCol==1 ); + testcase( iCol==0 ); + iMask = 1 << iCol; + if( pConstraint->usable==0 ){ + unusableMask |= iMask; + }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + aIdx[iCol] = i; + idxMask |= iMask; + } + } + if( (unusableMask & ~idxMask)!=0 ){ + /* If there are any unusable constraints on JSON or ROOT, then reject + ** this entire plan */ + return SQLITE_CONSTRAINT; + } + if( aIdx[0]<0 ){ + /* No JSON input. Leave estimatedCost at the huge value that it was + ** initialized to to discourage the query planner from selecting this + ** plan. */ + pIdxInfo->idxNum = 0; + }else{ + pIdxInfo->estimatedCost = 1.0; + i = aIdx[0]; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + if( aIdx[1]<0 ){ + pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */ + }else{ + i = aIdx[1]; + pIdxInfo->aConstraintUsage[i].argvIndex = 2; + pIdxInfo->aConstraintUsage[i].omit = 1; + pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */ + } } - aSzIns = &aSzDel[p->nColumn+1]; - memset(aSzDel, 0, sizeof(aSzDel[0])*(p->nColumn+1)*2); + return SQLITE_OK; +} - rc = fts3Writelock(p); - if( rc!=SQLITE_OK ) goto update_out; +/* Start a search on a new JSON string */ +static int jsonEachFilter( + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + JsonEachCursor *p = (JsonEachCursor*)cur; + const char *z; + const char *zRoot = 0; + sqlite3_int64 n; - /* If this is an INSERT operation, or an UPDATE that modifies the rowid - ** value, then this operation requires constraint handling. - ** - ** If the on-conflict mode is REPLACE, this means that the existing row - ** should be deleted from the database before inserting the new row. Or, - ** if the on-conflict mode is other than REPLACE, then this method must - ** detect the conflict and return SQLITE_CONSTRAINT before beginning to - ** modify the database file. - */ - if( nArg>1 && p->zContentTbl==0 ){ - /* Find the value object that holds the new rowid value. */ - sqlite3_value *pNewRowid = apVal[3+p->nColumn]; - if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ - pNewRowid = apVal[1]; + UNUSED_PARAMETER(idxStr); + UNUSED_PARAMETER(argc); + jsonEachCursorReset(p); + if( idxNum==0 ) return SQLITE_OK; + z = (const char*)sqlite3_value_text(argv[0]); + if( z==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[0]); + p->zJson = sqlite3_malloc64( n+1 ); + if( p->zJson==0 ) return SQLITE_NOMEM; + memcpy(p->zJson, z, (size_t)n+1); + if( jsonParse(&p->sParse, 0, p->zJson) ){ + int rc = SQLITE_NOMEM; + if( p->sParse.oom==0 ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); + if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; } - - if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( - sqlite3_value_type(apVal[0])==SQLITE_NULL - || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) - )){ - /* The new rowid is not NULL (in this case the rowid will be - ** automatically assigned and there is no chance of a conflict), and - ** the statement is either an INSERT or an UPDATE that modifies the - ** rowid column. So if the conflict mode is REPLACE, then delete any - ** existing row with rowid=pNewRowid. - ** - ** Or, if the conflict mode is not REPLACE, insert the new record into - ** the %_content table. If we hit the duplicate rowid constraint (or any - ** other error) while doing so, return immediately. - ** - ** This branch may also run if pNewRowid contains a value that cannot - ** be losslessly converted to an integer. In this case, the eventual - ** call to fts3InsertData() (either just below or further on in this - ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is - ** invoked, it will delete zero rows (since no row will have - ** docid=$pNewRowid if $pNewRowid is not an integer value). - */ - if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ - rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); + jsonEachCursorReset(p); + return rc; + }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ + jsonEachCursorReset(p); + return SQLITE_NOMEM; + }else{ + JsonNode *pNode = 0; + if( idxNum==3 ){ + const char *zErr = 0; + zRoot = (const char*)sqlite3_value_text(argv[1]); + if( zRoot==0 ) return SQLITE_OK; + n = sqlite3_value_bytes(argv[1]); + p->zRoot = sqlite3_malloc64( n+1 ); + if( p->zRoot==0 ) return SQLITE_NOMEM; + memcpy(p->zRoot, zRoot, (size_t)n+1); + if( zRoot[0]!='$' ){ + zErr = zRoot; }else{ - rc = fts3InsertData(p, apVal, pRowid); - bInsertDone = 1; + pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); } - } - } - if( rc!=SQLITE_OK ){ - goto update_out; - } - - /* If this is a DELETE or UPDATE operation, remove the old record. */ - if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ - assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); - rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); - isRemove = 1; - } - - /* If this is an INSERT or UPDATE operation, insert the new record. */ - if( nArg>1 && rc==SQLITE_OK ){ - int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]); - if( bInsertDone==0 ){ - rc = fts3InsertData(p, apVal, pRowid); - if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ - rc = FTS_CORRUPT_VTAB; + if( zErr ){ + sqlite3_free(cur->pVtab->zErrMsg); + cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); + jsonEachCursorReset(p); + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; + }else if( pNode==0 ){ + return SQLITE_OK; } + }else{ + pNode = p->sParse.aNode; } - if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ - rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid); - } - if( rc==SQLITE_OK ){ - assert( p->iPrevDocid==*pRowid ); - rc = fts3InsertTerms(p, iLangid, apVal, aSzIns); - } - if( p->bHasDocsize ){ - fts3InsertDocsize(&rc, p, aSzIns); + p->iBegin = p->i = (int)(pNode - p->sParse.aNode); + p->eType = pNode->eType; + if( p->eType>=JSON_ARRAY ){ + assert( pNode->eU==0 ); + VVA( pNode->eU = 3 ); + pNode->u.iKey = 0; + p->iEnd = p->i + pNode->n + 1; + if( p->bRecursive ){ + p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; + if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ + p->i--; + } + }else{ + p->i++; + } + }else{ + p->iEnd = p->i+1; } - nChng++; } + return SQLITE_OK; +} - if( p->bFts4 ){ - fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng); - } +/* The methods of the json_each virtual table */ +static sqlite3_module jsonEachModule = { + 0, /* iVersion */ + 0, /* xCreate */ + jsonEachConnect, /* xConnect */ + jsonEachBestIndex, /* xBestIndex */ + jsonEachDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + jsonEachOpenEach, /* xOpen - open a cursor */ + jsonEachClose, /* xClose - close a cursor */ + jsonEachFilter, /* xFilter - configure scan constraints */ + jsonEachNext, /* xNext - advance a cursor */ + jsonEachEof, /* xEof - check for end of scan */ + jsonEachColumn, /* xColumn - read data */ + jsonEachRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ +}; - update_out: - sqlite3_free(aSzDel); - sqlite3Fts3SegmentsClose(p); - return rc; +/* The methods of the json_tree virtual table. */ +static sqlite3_module jsonTreeModule = { + 0, /* iVersion */ + 0, /* xCreate */ + jsonEachConnect, /* xConnect */ + jsonEachBestIndex, /* xBestIndex */ + jsonEachDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + jsonEachOpenTree, /* xOpen - open a cursor */ + jsonEachClose, /* xClose - close a cursor */ + jsonEachFilter, /* xFilter - configure scan constraints */ + jsonEachNext, /* xNext - advance a cursor */ + jsonEachEof, /* xEof - check for end of scan */ + jsonEachColumn, /* xColumn - read data */ + jsonEachRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ +}; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ +#endif /* !defined(SQLITE_OMIT_JSON) */ + +/* +** Register JSON functions. +*/ +SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ +#ifndef SQLITE_OMIT_JSON + static FuncDef aJsonFunc[] = { + JFUNCTION(json, 1, 0, jsonRemoveFunc), + JFUNCTION(json_array, -1, 0, jsonArrayFunc), + JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc), + JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc), + JFUNCTION(json_extract, -1, 0, jsonExtractFunc), + JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc), + JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc), + JFUNCTION(json_insert, -1, 0, jsonSetFunc), + JFUNCTION(json_object, -1, 0, jsonObjectFunc), + JFUNCTION(json_patch, 2, 0, jsonPatchFunc), + JFUNCTION(json_quote, 1, 0, jsonQuoteFunc), + JFUNCTION(json_remove, -1, 0, jsonRemoveFunc), + JFUNCTION(json_replace, -1, 0, jsonReplaceFunc), + JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc), + JFUNCTION(json_type, 1, 0, jsonTypeFunc), + JFUNCTION(json_type, 2, 0, jsonTypeFunc), + JFUNCTION(json_valid, 1, 0, jsonValidFunc), +#if SQLITE_DEBUG + JFUNCTION(json_parse, 1, 0, jsonParseFunc), + JFUNCTION(json_test1, 1, 0, jsonTest1Func), +#endif + WAGGREGATE(json_group_array, 1, 0, 0, + jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS), + WAGGREGATE(json_group_object, 2, 0, 0, + jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) + }; + sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); +#endif } -/* -** Flush any data in the pending-terms hash table to disk. If successful, -** merge all segments in the database (including the new segment, if -** there was any data to flush) into a single segment. +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) +/* +** Register the JSON table-valued functions */ -SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){ - int rc; - rc = sqlite3_exec(p->db, "SAVEPOINT fts3", 0, 0, 0); - if( rc==SQLITE_OK ){ - rc = fts3DoOptimize(p, 1); - if( rc==SQLITE_OK || rc==SQLITE_DONE ){ - int rc2 = sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); - if( rc2!=SQLITE_OK ) rc = rc2; - }else{ - sqlite3_exec(p->db, "ROLLBACK TO fts3", 0, 0, 0); - sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0); - } +SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3 *db){ + int rc = SQLITE_OK; + static const struct { + const char *zName; + sqlite3_module *pModule; + } aMod[] = { + { "json_each", &jsonEachModule }, + { "json_tree", &jsonTreeModule }, + }; + unsigned int i; + for(i=0; i */ -/* #include */ - -/* -** Characters that may appear in the second argument to matchinfo(). -*/ -#define FTS3_MATCHINFO_NPHRASE 'p' /* 1 value */ -#define FTS3_MATCHINFO_NCOL 'c' /* 1 value */ -#define FTS3_MATCHINFO_NDOC 'n' /* 1 value */ -#define FTS3_MATCHINFO_AVGLENGTH 'a' /* nCol values */ -#define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */ -#define FTS3_MATCHINFO_LCS 's' /* nCol values */ -#define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */ -#define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */ -#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */ - -/* -** The default value for the second argument to matchinfo(). -*/ -#define FTS3_MATCHINFO_DEFAULT "pcx" - - -/* -** Used as an fts3ExprIterate() context when loading phrase doclists to -** Fts3Expr.aDoclist[]/nDoclist. -*/ -typedef struct LoadDoclistCtx LoadDoclistCtx; -struct LoadDoclistCtx { - Fts3Cursor *pCsr; /* FTS3 Cursor */ - int nPhrase; /* Number of phrases seen so far */ - int nToken; /* Number of tokens seen so far */ -}; - -/* -** The following types are used as part of the implementation of the -** fts3BestSnippet() routine. +************************************************************************* +** This file contains code for implementations of the r-tree and r*-tree +** algorithms packaged as an SQLite virtual table module. */ -typedef struct SnippetIter SnippetIter; -typedef struct SnippetPhrase SnippetPhrase; -typedef struct SnippetFragment SnippetFragment; - -struct SnippetIter { - Fts3Cursor *pCsr; /* Cursor snippet is being generated from */ - int iCol; /* Extract snippet from this column */ - int nSnippet; /* Requested snippet length (in tokens) */ - int nPhrase; /* Number of phrases in query */ - SnippetPhrase *aPhrase; /* Array of size nPhrase */ - int iCurrent; /* First token of current snippet */ -}; - -struct SnippetPhrase { - int nToken; /* Number of tokens in phrase */ - char *pList; /* Pointer to start of phrase position list */ - int iHead; /* Next value in position list */ - char *pHead; /* Position list data following iHead */ - int iTail; /* Next value in trailing position list */ - char *pTail; /* Position list data following iTail */ -}; - -struct SnippetFragment { - int iCol; /* Column snippet is extracted from */ - int iPos; /* Index of first token in snippet */ - u64 covered; /* Mask of query phrases covered */ - u64 hlmask; /* Mask of snippet terms to highlight */ -}; /* -** This type is used as an fts3ExprIterate() context object while -** accumulating the data returned by the matchinfo() function. -*/ -typedef struct MatchInfo MatchInfo; -struct MatchInfo { - Fts3Cursor *pCursor; /* FTS3 Cursor */ - int nCol; /* Number of columns in table */ - int nPhrase; /* Number of matchable phrases in query */ - sqlite3_int64 nDoc; /* Number of docs in database */ - char flag; - u32 *aMatchinfo; /* Pre-allocated buffer */ -}; +** Database Format of R-Tree Tables +** -------------------------------- +** +** The data structure for a single virtual r-tree table is stored in three +** native SQLite tables declared as follows. In each case, the '%' character +** in the table name is replaced with the user-supplied name of the r-tree +** table. +** +** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB) +** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) +** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...) +** +** The data for each node of the r-tree structure is stored in the %_node +** table. For each node that is not the root node of the r-tree, there is +** an entry in the %_parent table associating the node with its parent. +** And for each row of data in the table, there is an entry in the %_rowid +** table that maps from the entries rowid to the id of the node that it +** is stored on. If the r-tree contains auxiliary columns, those are stored +** on the end of the %_rowid table. +** +** The root node of an r-tree always exists, even if the r-tree table is +** empty. The nodeno of the root node is always 1. All other nodes in the +** table must be the same size as the root node. The content of each node +** is formatted as follows: +** +** 1. If the node is the root node (node 1), then the first 2 bytes +** of the node contain the tree depth as a big-endian integer. +** For non-root nodes, the first 2 bytes are left unused. +** +** 2. The next 2 bytes contain the number of entries currently +** stored in the node. +** +** 3. The remainder of the node contains the node entries. Each entry +** consists of a single 8-byte integer followed by an even number +** of 4-byte coordinates. For leaf nodes the integer is the rowid +** of a record. For internal nodes it is the node number of a +** child page. +*/ + +#if !defined(SQLITE_CORE) \ + || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE)) + +#ifndef SQLITE_CORE +/* #include "sqlite3ext.h" */ + SQLITE_EXTENSION_INIT1 +#else +/* #include "sqlite3.h" */ +#endif +SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */ /* -** An instance of this structure is used to manage a pair of buffers, each -** (nElem * sizeof(u32)) bytes in size. See the MatchinfoBuffer code below -** for details. +** If building separately, we will need some setup that is normally +** found in sqliteInt.h */ -struct MatchinfoBuffer { - u8 aRef[3]; - int nElem; - int bGlobal; /* Set if global data is loaded */ - char *zMatchinfo; - u32 aMatchinfo[1]; -}; +#if !defined(SQLITE_AMALGAMATION) +#include "sqlite3rtree.h" +typedef sqlite3_int64 i64; +typedef sqlite3_uint64 u64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 +#endif +#if defined(NDEBUG) && defined(SQLITE_DEBUG) +# undef NDEBUG +#endif +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +#elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +#else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +#endif +#endif /* !defined(SQLITE_AMALGAMATION) */ +/* #include */ +/* #include */ +/* #include */ +/* #include */ -/* -** The snippet() and offsets() functions both return text values. An instance -** of the following structure is used to accumulate those values while the -** functions are running. See fts3StringAppend() for details. +/* The following macro is used to suppress compiler warnings. */ -typedef struct StrBuffer StrBuffer; -struct StrBuffer { - char *z; /* Pointer to buffer containing string */ - int n; /* Length of z in bytes (excl. nul-term) */ - int nAlloc; /* Allocated size of buffer z in bytes */ -}; +#ifndef UNUSED_PARAMETER +# define UNUSED_PARAMETER(x) (void)(x) +#endif + +typedef struct Rtree Rtree; +typedef struct RtreeCursor RtreeCursor; +typedef struct RtreeNode RtreeNode; +typedef struct RtreeCell RtreeCell; +typedef struct RtreeConstraint RtreeConstraint; +typedef struct RtreeMatchArg RtreeMatchArg; +typedef struct RtreeGeomCallback RtreeGeomCallback; +typedef union RtreeCoord RtreeCoord; +typedef struct RtreeSearchPoint RtreeSearchPoint; + +/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ +#define RTREE_MAX_DIMENSIONS 5 +/* Maximum number of auxiliary columns */ +#define RTREE_MAX_AUX_COLUMN 100 -/************************************************************************* -** Start of MatchinfoBuffer code. +/* Size of hash table Rtree.aHash. This hash table is not expected to +** ever contain very many entries, so a fixed number of buckets is +** used. */ +#define HASHSIZE 97 -/* -** Allocate a two-slot MatchinfoBuffer object. +/* The xBestIndex method of this virtual table requires an estimate of +** the number of rows in the virtual table to calculate the costs of +** various strategies. If possible, this estimate is loaded from the +** sqlite_stat1 table (with RTREE_MIN_ROWEST as a hard-coded minimum). +** Otherwise, if no sqlite_stat1 entry is available, use +** RTREE_DEFAULT_ROWEST. */ -static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){ - MatchinfoBuffer *pRet; - int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer); - int nStr = (int)strlen(zMatchinfo); +#define RTREE_DEFAULT_ROWEST 1048576 +#define RTREE_MIN_ROWEST 100 - pRet = sqlite3_malloc(nByte + nStr+1); - if( pRet ){ - memset(pRet, 0, nByte); - pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; - pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1); - pRet->nElem = nElem; - pRet->zMatchinfo = ((char*)pRet) + nByte; - memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); - pRet->aRef[0] = 1; - } +/* +** An rtree virtual-table object. +*/ +struct Rtree { + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* Host database connection */ + int iNodeSize; /* Size in bytes of each node in the node table */ + u8 nDim; /* Number of dimensions */ + u8 nDim2; /* Twice the number of dimensions */ + u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ + u8 nBytesPerCell; /* Bytes consumed per cell */ + u8 inWrTrans; /* True if inside write transaction */ + u8 nAux; /* # of auxiliary columns in %_rowid */ +#ifdef SQLITE_ENABLE_GEOPOLY + u8 nAuxNotNull; /* Number of initial not-null aux columns */ +#endif +#ifdef SQLITE_DEBUG + u8 bCorrupt; /* Shadow table corruption detected */ +#endif + int iDepth; /* Current depth of the r-tree structure */ + char *zDb; /* Name of database containing r-tree table */ + char *zName; /* Name of r-tree table */ + u32 nBusy; /* Current number of users of this structure */ + i64 nRowEst; /* Estimated number of rows in this table */ + u32 nCursor; /* Number of open cursors */ + u32 nNodeRef; /* Number RtreeNodes with positive nRef */ + char *zReadAuxSql; /* SQL for statement to read aux data */ - return pRet; -} + /* List of nodes removed during a CondenseTree operation. List is + ** linked together via the pointer normally used for hash chains - + ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree + ** headed by the node (leaf nodes have RtreeNode.iNode==0). + */ + RtreeNode *pDeleted; + int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */ -static void fts3MIBufferFree(void *p){ - MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]); + /* Blob I/O on xxx_node */ + sqlite3_blob *pNodeBlob; - assert( (u32*)p==&pBuf->aMatchinfo[1] - || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2] - ); - if( (u32*)p==&pBuf->aMatchinfo[1] ){ - pBuf->aRef[1] = 0; - }else{ - pBuf->aRef[2] = 0; - } + /* Statements to read/write/delete a record from xxx_node */ + sqlite3_stmt *pWriteNode; + sqlite3_stmt *pDeleteNode; - if( pBuf->aRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){ - sqlite3_free(pBuf); - } -} + /* Statements to read/write/delete a record from xxx_rowid */ + sqlite3_stmt *pReadRowid; + sqlite3_stmt *pWriteRowid; + sqlite3_stmt *pDeleteRowid; -static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){ - void (*xRet)(void*) = 0; - u32 *aOut = 0; + /* Statements to read/write/delete a record from xxx_parent */ + sqlite3_stmt *pReadParent; + sqlite3_stmt *pWriteParent; + sqlite3_stmt *pDeleteParent; - if( p->aRef[1]==0 ){ - p->aRef[1] = 1; - aOut = &p->aMatchinfo[1]; - xRet = fts3MIBufferFree; - } - else if( p->aRef[2]==0 ){ - p->aRef[2] = 1; - aOut = &p->aMatchinfo[p->nElem+2]; - xRet = fts3MIBufferFree; - }else{ - aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32)); - if( aOut ){ - xRet = sqlite3_free; - if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32)); - } - } + /* Statement for writing to the "aux:" fields, if there are any */ + sqlite3_stmt *pWriteAux; - *paOut = aOut; - return xRet; -} + RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ +}; -static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){ - p->bGlobal = 1; - memcpy(&p->aMatchinfo[2+p->nElem], &p->aMatchinfo[1], p->nElem*sizeof(u32)); -} +/* Possible values for Rtree.eCoordType: */ +#define RTREE_COORD_REAL32 0 +#define RTREE_COORD_INT32 1 /* -** Free a MatchinfoBuffer object allocated using fts3MIBufferNew() +** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will +** only deal with integer coordinates. No floating point operations +** will be done. */ -SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){ - if( p ){ - assert( p->aRef[0]==1 ); - p->aRef[0] = 0; - if( p->aRef[0]==0 && p->aRef[1]==0 && p->aRef[2]==0 ){ - sqlite3_free(p); - } - } -} - -/* -** End of MatchinfoBuffer code. -*************************************************************************/ +#ifdef SQLITE_RTREE_INT_ONLY + typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ + typedef int RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0 +#else + typedef double RtreeDValue; /* High accuracy coordinate */ + typedef float RtreeValue; /* Low accuracy coordinate */ +# define RTREE_ZERO 0.0 +#endif +/* +** Set the Rtree.bCorrupt flag +*/ +#ifdef SQLITE_DEBUG +# define RTREE_IS_CORRUPT(X) ((X)->bCorrupt = 1) +#else +# define RTREE_IS_CORRUPT(X) +#endif /* -** This function is used to help iterate through a position-list. A position -** list is a list of unique integers, sorted from smallest to largest. Each -** element of the list is represented by an FTS3 varint that takes the value -** of the difference between the current element and the previous one plus -** two. For example, to store the position-list: -** -** 4 9 113 -** -** the three varints: +** When doing a search of an r-tree, instances of the following structure +** record intermediate results from the tree walk. ** -** 6 7 106 +** The id is always a node-id. For iLevel>=1 the id is the node-id of +** the node that the RtreeSearchPoint represents. When iLevel==0, however, +** the id is of the parent node and the cell that RtreeSearchPoint +** represents is the iCell-th entry in the parent node. +*/ +struct RtreeSearchPoint { + RtreeDValue rScore; /* The score for this node. Smallest goes first. */ + sqlite3_int64 id; /* Node ID */ + u8 iLevel; /* 0=entries. 1=leaf node. 2+ for higher */ + u8 eWithin; /* PARTLY_WITHIN or FULLY_WITHIN */ + u8 iCell; /* Cell index within the node */ +}; + +/* +** The minimum number of cells allowed for a node is a third of the +** maximum. In Gutman's notation: ** -** are encoded. +** m = M/3 ** -** When this function is called, *pp points to the start of an element of -** the list. *piPos contains the value of the previous entry in the list. -** After it returns, *piPos contains the value of the next element of the -** list and *pp is advanced to the following varint. +** If an R*-tree "Reinsert" operation is required, the same number of +** cells are removed from the overfull node and reinserted into the tree. */ -static void fts3GetDeltaPosition(char **pp, int *piPos){ - int iVal; - *pp += fts3GetVarint32(*pp, &iVal); - *piPos += (iVal-2); -} +#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3) +#define RTREE_REINSERT(p) RTREE_MINCELLS(p) +#define RTREE_MAXCELLS 51 /* -** Helper function for fts3ExprIterate() (see below). +** The smallest possible node-size is (512-64)==448 bytes. And the largest +** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates). +** Therefore all non-root nodes must contain at least 3 entries. Since +** 3^40 is greater than 2^64, an r-tree structure always has a depth of +** 40 or less. */ -static int fts3ExprIterate2( - Fts3Expr *pExpr, /* Expression to iterate phrases of */ - int *piPhrase, /* Pointer to phrase counter */ - int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ - void *pCtx /* Second argument to pass to callback */ -){ - int rc; /* Return code */ - int eType = pExpr->eType; /* Type of expression node pExpr */ +#define RTREE_MAX_DEPTH 40 - if( eType!=FTSQUERY_PHRASE ){ - assert( pExpr->pLeft && pExpr->pRight ); - rc = fts3ExprIterate2(pExpr->pLeft, piPhrase, x, pCtx); - if( rc==SQLITE_OK && eType!=FTSQUERY_NOT ){ - rc = fts3ExprIterate2(pExpr->pRight, piPhrase, x, pCtx); - } - }else{ - rc = x(pExpr, *piPhrase, pCtx); - (*piPhrase)++; - } - return rc; -} /* -** Iterate through all phrase nodes in an FTS3 query, except those that -** are part of a sub-tree that is the right-hand-side of a NOT operator. -** For each phrase node found, the supplied callback function is invoked. -** -** If the callback function returns anything other than SQLITE_OK, -** the iteration is abandoned and the error code returned immediately. -** Otherwise, SQLITE_OK is returned after a callback has been made for -** all eligible phrase nodes. +** Number of entries in the cursor RtreeNode cache. The first entry is +** used to cache the RtreeNode for RtreeCursor.sPoint. The remaining +** entries cache the RtreeNode for the first elements of the priority queue. */ -static int fts3ExprIterate( - Fts3Expr *pExpr, /* Expression to iterate phrases of */ - int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ - void *pCtx /* Second argument to pass to callback */ -){ - int iPhrase = 0; /* Variable used as the phrase counter */ - return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx); -} - +#define RTREE_CACHE_SZ 5 /* -** This is an fts3ExprIterate() callback used while loading the doclists -** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also -** fts3ExprLoadDoclists(). +** An rtree cursor object. */ -static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ - int rc = SQLITE_OK; - Fts3Phrase *pPhrase = pExpr->pPhrase; - LoadDoclistCtx *p = (LoadDoclistCtx *)ctx; - - UNUSED_PARAMETER(iPhrase); - - p->nPhrase++; - p->nToken += pPhrase->nToken; +struct RtreeCursor { + sqlite3_vtab_cursor base; /* Base class. Must be first */ + u8 atEOF; /* True if at end of search */ + u8 bPoint; /* True if sPoint is valid */ + u8 bAuxValid; /* True if pReadAux is valid */ + int iStrategy; /* Copy of idxNum search parameter */ + int nConstraint; /* Number of entries in aConstraint */ + RtreeConstraint *aConstraint; /* Search constraints. */ + int nPointAlloc; /* Number of slots allocated for aPoint[] */ + int nPoint; /* Number of slots used in aPoint[] */ + int mxLevel; /* iLevel value for root of the tree */ + RtreeSearchPoint *aPoint; /* Priority queue for search points */ + sqlite3_stmt *pReadAux; /* Statement to read aux-data */ + RtreeSearchPoint sPoint; /* Cached next search point */ + RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ + u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ +}; - return rc; -} +/* Return the Rtree of a RtreeCursor */ +#define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) /* -** Load the doclists for each phrase in the query associated with FTS3 cursor -** pCsr. -** -** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable -** phrases in the expression (all phrases except those directly or -** indirectly descended from the right-hand-side of a NOT operator). If -** pnToken is not NULL, then it is set to the number of tokens in all -** matchable phrases of the expression. +** A coordinate can be either a floating point number or a integer. All +** coordinates within a single R-Tree are always of the same time. */ -static int fts3ExprLoadDoclists( - Fts3Cursor *pCsr, /* Fts3 cursor for current query */ - int *pnPhrase, /* OUT: Number of phrases in query */ - int *pnToken /* OUT: Number of tokens in query */ -){ - int rc; /* Return Code */ - LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */ - sCtx.pCsr = pCsr; - rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx); - if( pnPhrase ) *pnPhrase = sCtx.nPhrase; - if( pnToken ) *pnToken = sCtx.nToken; - return rc; -} - -static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ - (*(int *)ctx)++; - pExpr->iPhrase = iPhrase; - return SQLITE_OK; -} -static int fts3ExprPhraseCount(Fts3Expr *pExpr){ - int nPhrase = 0; - (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase); - return nPhrase; -} +union RtreeCoord { + RtreeValue f; /* Floating point value */ + int i; /* Integer value */ + u32 u; /* Unsigned for byte-order conversions */ +}; /* -** Advance the position list iterator specified by the first two -** arguments so that it points to the first element with a value greater -** than or equal to parameter iNext. +** The argument is an RtreeCoord. Return the value stored within the RtreeCoord +** formatted as a RtreeDValue (double or int64). This macro assumes that local +** variable pRtree points to the Rtree structure associated with the +** RtreeCoord. */ -static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){ - char *pIter = *ppIter; - if( pIter ){ - int iIter = *piIter; - - while( iItereCoordType==RTREE_COORD_REAL32) ? \ + ((double)coord.f) : \ + ((double)coord.i) \ + ) +#endif /* -** Advance the snippet iterator to the next candidate snippet. +** A search constraint. */ -static int fts3SnippetNextCandidate(SnippetIter *pIter){ - int i; /* Loop counter */ - - if( pIter->iCurrent<0 ){ - /* The SnippetIter object has just been initialized. The first snippet - ** candidate always starts at offset 0 (even if this candidate has a - ** score of 0.0). - */ - pIter->iCurrent = 0; - - /* Advance the 'head' iterator of each phrase to the first offset that - ** is greater than or equal to (iNext+nSnippet). - */ - for(i=0; inPhrase; i++){ - SnippetPhrase *pPhrase = &pIter->aPhrase[i]; - fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, pIter->nSnippet); - } - }else{ - int iStart; - int iEnd = 0x7FFFFFFF; - - for(i=0; inPhrase; i++){ - SnippetPhrase *pPhrase = &pIter->aPhrase[i]; - if( pPhrase->pHead && pPhrase->iHeadiHead; - } - } - if( iEnd==0x7FFFFFFF ){ - return 1; - } +struct RtreeConstraint { + int iCoord; /* Index of constrained coordinate */ + int op; /* Constraining operation */ + union { + RtreeDValue rValue; /* Constraint value. */ + int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + } u; + sqlite3_rtree_query_info *pInfo; /* xGeom and xQueryFunc argument */ +}; - pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1; - for(i=0; inPhrase; i++){ - SnippetPhrase *pPhrase = &pIter->aPhrase[i]; - fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1); - fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart); - } - } +/* Possible values for RtreeConstraint.op */ +#define RTREE_EQ 0x41 /* A */ +#define RTREE_LE 0x42 /* B */ +#define RTREE_LT 0x43 /* C */ +#define RTREE_GE 0x44 /* D */ +#define RTREE_GT 0x45 /* E */ +#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ +#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ - return 0; -} +/* Special operators available only on cursors. Needs to be consecutive +** with the normal values above, but must be less than RTREE_MATCH. These +** are used in the cursor for contraints such as x=NULL (RTREE_FALSE) or +** x<'xyz' (RTREE_TRUE) */ +#define RTREE_TRUE 0x3f /* ? */ +#define RTREE_FALSE 0x40 /* @ */ /* -** Retrieve information about the current candidate snippet of snippet -** iterator pIter. +** An rtree structure node. */ -static void fts3SnippetDetails( - SnippetIter *pIter, /* Snippet iterator */ - u64 mCovered, /* Bitmask of phrases already covered */ - int *piToken, /* OUT: First token of proposed snippet */ - int *piScore, /* OUT: "Score" for this snippet */ - u64 *pmCover, /* OUT: Bitmask of phrases covered */ - u64 *pmHighlight /* OUT: Bitmask of terms to highlight */ -){ - int iStart = pIter->iCurrent; /* First token of snippet */ - int iScore = 0; /* Score of this snippet */ - int i; /* Loop counter */ - u64 mCover = 0; /* Mask of phrases covered by this snippet */ - u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */ - - for(i=0; inPhrase; i++){ - SnippetPhrase *pPhrase = &pIter->aPhrase[i]; - if( pPhrase->pTail ){ - char *pCsr = pPhrase->pTail; - int iCsr = pPhrase->iTail; - - while( iCsr<(iStart+pIter->nSnippet) ){ - int j; - u64 mPhrase = (u64)1 << i; - u64 mPos = (u64)1 << (iCsr - iStart); - assert( iCsr>=iStart ); - if( (mCover|mCovered)&mPhrase ){ - iScore++; - }else{ - iScore += 1000; - } - mCover |= mPhrase; - - for(j=0; jnToken; j++){ - mHighlight |= (mPos>>j); - } - - if( 0==(*pCsr & 0x0FE) ) break; - fts3GetDeltaPosition(&pCsr, &iCsr); - } - } - } +struct RtreeNode { + RtreeNode *pParent; /* Parent node */ + i64 iNode; /* The node number */ + int nRef; /* Number of references to this node */ + int isDirty; /* True if the node needs to be written to disk */ + u8 *zData; /* Content of the node, as should be on disk */ + RtreeNode *pNext; /* Next node in this hash collision chain */ +}; - /* Set the output variables before returning. */ - *piToken = iStart; - *piScore = iScore; - *pmCover = mCover; - *pmHighlight = mHighlight; -} +/* Return the number of cells in a node */ +#define NCELL(pNode) readInt16(&(pNode)->zData[2]) /* -** This function is an fts3ExprIterate() callback used by fts3BestSnippet(). -** Each invocation populates an element of the SnippetIter.aPhrase[] array. +** A single cell from a node, deserialized */ -static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ - SnippetIter *p = (SnippetIter *)ctx; - SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; - char *pCsr; - int rc; - - pPhrase->nToken = pExpr->pPhrase->nToken; - rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); - assert( rc==SQLITE_OK || pCsr==0 ); - if( pCsr ){ - int iFirst = 0; - pPhrase->pList = pCsr; - fts3GetDeltaPosition(&pCsr, &iFirst); - assert( iFirst>=0 ); - pPhrase->pHead = pCsr; - pPhrase->pTail = pCsr; - pPhrase->iHead = iFirst; - pPhrase->iTail = iFirst; - }else{ - assert( rc!=SQLITE_OK || ( - pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 - )); - } +struct RtreeCell { + i64 iRowid; /* Node or entry ID */ + RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2]; /* Bounding box coordinates */ +}; - return rc; -} /* -** Select the fragment of text consisting of nFragment contiguous tokens -** from column iCol that represent the "best" snippet. The best snippet -** is the snippet with the highest score, where scores are calculated -** by adding: -** -** (a) +1 point for each occurrence of a matchable phrase in the snippet. +** This object becomes the sqlite3_user_data() for the SQL functions +** that are created by sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() and which appear on the right of MATCH +** operators in order to constrain a search. ** -** (b) +1000 points for the first occurrence of each matchable phrase in -** the snippet for which the corresponding mCovered bit is not set. +** xGeom and xQueryFunc are the callback functions. Exactly one of +** xGeom and xQueryFunc fields is non-NULL, depending on whether the +** SQL function was created using sqlite3_rtree_geometry_callback() or +** sqlite3_rtree_query_callback(). ** -** The selected snippet parameters are stored in structure *pFragment before -** returning. The score of the selected snippet is stored in *piScore -** before returning. +** This object is deleted automatically by the destructor mechanism in +** sqlite3_create_function_v2(). */ -static int fts3BestSnippet( - int nSnippet, /* Desired snippet length */ - Fts3Cursor *pCsr, /* Cursor to create snippet for */ - int iCol, /* Index of column to create snippet from */ - u64 mCovered, /* Mask of phrases already covered */ - u64 *pmSeen, /* IN/OUT: Mask of phrases seen */ - SnippetFragment *pFragment, /* OUT: Best snippet found */ - int *piScore /* OUT: Score of snippet pFragment */ -){ - int rc; /* Return Code */ - int nList; /* Number of phrases in expression */ - SnippetIter sIter; /* Iterates through snippet candidates */ - int nByte; /* Number of bytes of space to allocate */ - int iBestScore = -1; /* Best snippet score found so far */ - int i; /* Loop counter */ - - memset(&sIter, 0, sizeof(sIter)); - - /* Iterate through the phrases in the expression to count them. The same - ** callback makes sure the doclists are loaded for each phrase. - */ - rc = fts3ExprLoadDoclists(pCsr, &nList, 0); - if( rc!=SQLITE_OK ){ - return rc; - } - - /* Now that it is known how many phrases there are, allocate and zero - ** the required space using malloc(). - */ - nByte = sizeof(SnippetPhrase) * nList; - sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte); - if( !sIter.aPhrase ){ - return SQLITE_NOMEM; - } - memset(sIter.aPhrase, 0, nByte); +struct RtreeGeomCallback { + int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*); + int (*xQueryFunc)(sqlite3_rtree_query_info*); + void (*xDestructor)(void*); + void *pContext; +}; - /* Initialize the contents of the SnippetIter object. Then iterate through - ** the set of phrases in the expression to populate the aPhrase[] array. - */ - sIter.pCsr = pCsr; - sIter.iCol = iCol; - sIter.nSnippet = nSnippet; - sIter.nPhrase = nList; - sIter.iCurrent = -1; - rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter); - if( rc==SQLITE_OK ){ +/* +** An instance of this structure (in the form of a BLOB) is returned by +** the SQL functions that sqlite3_rtree_geometry_callback() and +** sqlite3_rtree_query_callback() create, and is read as the right-hand +** operand to the MATCH operator of an R-Tree. +*/ +struct RtreeMatchArg { + u32 iSize; /* Size of this object */ + RtreeGeomCallback cb; /* Info about the callback functions */ + int nParam; /* Number of parameters to the SQL function */ + sqlite3_value **apSqlParam; /* Original SQL parameter values */ + RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ +}; - /* Set the *pmSeen output variable. */ - for(i=0; i (y) ? (y) : (x)) +#endif - /* Loop through all candidate snippets. Store the best snippet in - ** *pFragment. Store its associated 'score' in iBestScore. - */ - pFragment->iCol = iCol; - while( !fts3SnippetNextCandidate(&sIter) ){ - int iPos; - int iScore; - u64 mCover; - u64 mHighlite; - fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite); - assert( iScore>=0 ); - if( iScore>iBestScore ){ - pFragment->iPos = iPos; - pFragment->hlmask = mHighlite; - pFragment->covered = mCover; - iBestScore = iScore; - } - } +/* What version of GCC is being used. 0 means GCC is not being used . +** Note that the GCC_VERSION macro will also be set correctly when using +** clang, since clang works hard to be gcc compatible. So the gcc +** optimizations will also work when compiling with clang. +*/ +#ifndef GCC_VERSION +#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) +# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) +#else +# define GCC_VERSION 0 +#endif +#endif - *piScore = iBestScore; - } - sqlite3_free(sIter.aPhrase); - return rc; -} +/* The testcase() macro should already be defined in the amalgamation. If +** it is not, make it a no-op. +*/ +#ifndef SQLITE_AMALGAMATION +# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG) + unsigned int sqlite3RtreeTestcase = 0; +# define testcase(X) if( X ){ sqlite3RtreeTestcase += __LINE__; } +# else +# define testcase(X) +# endif +#endif +/* +** Make sure that the compiler intrinsics we desire are enabled when +** compiling with an appropriate version of MSVC unless prevented by +** the SQLITE_DISABLE_INTRINSIC define. +*/ +#if !defined(SQLITE_DISABLE_INTRINSIC) +# if defined(_MSC_VER) && _MSC_VER>=1400 +# if !defined(_WIN32_WCE) +/* # include */ +# pragma intrinsic(_byteswap_ulong) +# pragma intrinsic(_byteswap_uint64) +# else +/* # include */ +# endif +# endif +#endif /* -** Append a string to the string-buffer passed as the first argument. +** Macros to determine whether the machine is big or little endian, +** and whether or not that determination is run-time or compile-time. ** -** If nAppend is negative, then the length of the string zAppend is -** determined using strlen(). +** For best performance, an attempt is made to guess at the byte-order +** using C-preprocessor macros. If that is unsuccessful, or if +** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined +** at run-time. */ -static int fts3StringAppend( - StrBuffer *pStr, /* Buffer to append to */ - const char *zAppend, /* Pointer to data to append to buffer */ - int nAppend /* Size of zAppend in bytes (or -1) */ -){ - if( nAppend<0 ){ - nAppend = (int)strlen(zAppend); - } +#ifndef SQLITE_BYTEORDER +#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__arm__) +# define SQLITE_BYTEORDER 1234 +#elif defined(sparc) || defined(__ppc__) +# define SQLITE_BYTEORDER 4321 +#else +# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ +#endif +#endif - /* If there is insufficient space allocated at StrBuffer.z, use realloc() - ** to grow the buffer until so that it is big enough to accomadate the - ** appended data. - */ - if( pStr->n+nAppend+1>=pStr->nAlloc ){ - int nAlloc = pStr->nAlloc+nAppend+100; - char *zNew = sqlite3_realloc(pStr->z, nAlloc); - if( !zNew ){ - return SQLITE_NOMEM; - } - pStr->z = zNew; - pStr->nAlloc = nAlloc; - } - assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) ); - /* Append the data to the string buffer. */ - memcpy(&pStr->z[pStr->n], zAppend, nAppend); - pStr->n += nAppend; - pStr->z[pStr->n] = '\0'; +/* What version of MSVC is being used. 0 means MSVC is not being used */ +#ifndef MSVC_VERSION +#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) +# define MSVC_VERSION _MSC_VER +#else +# define MSVC_VERSION 0 +#endif +#endif - return SQLITE_OK; +/* +** Functions to deserialize a 16 bit integer, 32 bit real number and +** 64 bit integer. The deserialized value is returned. +*/ +static int readInt16(u8 *p){ + return (p[0]<<8) + p[1]; +} +static void readCoord(u8 *p, RtreeCoord *pCoord){ + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + pCoord->u = _byteswap_ulong(*(u32*)p); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + pCoord->u = __builtin_bswap32(*(u32*)p); +#elif SQLITE_BYTEORDER==4321 + pCoord->u = *(u32*)p; +#else + pCoord->u = ( + (((u32)p[0]) << 24) + + (((u32)p[1]) << 16) + + (((u32)p[2]) << 8) + + (((u32)p[3]) << 0) + ); +#endif +} +static i64 readInt64(u8 *p){ +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + u64 x; + memcpy(&x, p, 8); + return (i64)_byteswap_uint64(x); +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + u64 x; + memcpy(&x, p, 8); + return (i64)__builtin_bswap64(x); +#elif SQLITE_BYTEORDER==4321 + i64 x; + memcpy(&x, p, 8); + return x; +#else + return (i64)( + (((u64)p[0]) << 56) + + (((u64)p[1]) << 48) + + (((u64)p[2]) << 40) + + (((u64)p[3]) << 32) + + (((u64)p[4]) << 24) + + (((u64)p[5]) << 16) + + (((u64)p[6]) << 8) + + (((u64)p[7]) << 0) + ); +#endif } /* -** The fts3BestSnippet() function often selects snippets that end with a -** query term. That is, the final term of the snippet is always a term -** that requires highlighting. For example, if 'X' is a highlighted term -** and '.' is a non-highlighted term, BestSnippet() may select: -** -** ........X.....X -** -** This function "shifts" the beginning of the snippet forward in the -** document so that there are approximately the same number of -** non-highlighted terms to the right of the final highlighted term as there -** are to the left of the first highlighted term. For example, to this: -** -** ....X.....X.... -** -** This is done as part of extracting the snippet text, not when selecting -** the snippet. Snippet selection is done based on doclists only, so there -** is no way for fts3BestSnippet() to know whether or not the document -** actually contains terms that follow the final highlighted term. +** Functions to serialize a 16 bit integer, 32 bit real number and +** 64 bit integer. The value returned is the number of bytes written +** to the argument buffer (always 2, 4 and 8 respectively). */ -static int fts3SnippetShift( - Fts3Table *pTab, /* FTS3 table snippet comes from */ - int iLangid, /* Language id to use in tokenizing */ - int nSnippet, /* Number of tokens desired for snippet */ - const char *zDoc, /* Document text to extract snippet from */ - int nDoc, /* Size of buffer zDoc in bytes */ - int *piPos, /* IN/OUT: First token of snippet */ - u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */ -){ - u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */ - - if( hlmask ){ - int nLeft; /* Tokens to the left of first highlight */ - int nRight; /* Tokens to the right of last highlight */ - int nDesired; /* Ideal number of tokens to shift forward */ - - for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++); - for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++); - nDesired = (nLeft-nRight)/2; - - /* Ideally, the start of the snippet should be pushed forward in the - ** document nDesired tokens. This block checks if there are actually - ** nDesired tokens to the right of the snippet. If so, *piPos and - ** *pHlMask are updated to shift the snippet nDesired tokens to the - ** right. Otherwise, the snippet is shifted by the number of tokens - ** available. - */ - if( nDesired>0 ){ - int nShift; /* Number of tokens to shift snippet by */ - int iCurrent = 0; /* Token counter */ - int rc; /* Return Code */ - sqlite3_tokenizer_module *pMod; - sqlite3_tokenizer_cursor *pC; - pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; - - /* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired) - ** or more tokens in zDoc/nDoc. - */ - rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, iLangid, zDoc, nDoc, &pC); - if( rc!=SQLITE_OK ){ - return rc; - } - while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){ - const char *ZDUMMY; int DUMMY1 = 0, DUMMY2 = 0, DUMMY3 = 0; - rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent); - } - pMod->xClose(pC); - if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; } - - nShift = (rc==SQLITE_DONE)+iCurrent-nSnippet; - assert( nShift<=nDesired ); - if( nShift>0 ){ - *piPos += nShift; - *pHlmask = hlmask >> nShift; - } - } - } - return SQLITE_OK; +static void writeInt16(u8 *p, int i){ + p[0] = (i>> 8)&0xFF; + p[1] = (i>> 0)&0xFF; +} +static int writeCoord(u8 *p, RtreeCoord *pCoord){ + u32 i; + assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ + assert( sizeof(RtreeCoord)==4 ); + assert( sizeof(u32)==4 ); +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + i = __builtin_bswap32(pCoord->u); + memcpy(p, &i, 4); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + i = _byteswap_ulong(pCoord->u); + memcpy(p, &i, 4); +#elif SQLITE_BYTEORDER==4321 + i = pCoord->u; + memcpy(p, &i, 4); +#else + i = pCoord->u; + p[0] = (i>>24)&0xFF; + p[1] = (i>>16)&0xFF; + p[2] = (i>> 8)&0xFF; + p[3] = (i>> 0)&0xFF; +#endif + return 4; +} +static int writeInt64(u8 *p, i64 i){ +#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 + i = (i64)__builtin_bswap64((u64)i); + memcpy(p, &i, 8); +#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 + i = (i64)_byteswap_uint64((u64)i); + memcpy(p, &i, 8); +#elif SQLITE_BYTEORDER==4321 + memcpy(p, &i, 8); +#else + p[0] = (i>>56)&0xFF; + p[1] = (i>>48)&0xFF; + p[2] = (i>>40)&0xFF; + p[3] = (i>>32)&0xFF; + p[4] = (i>>24)&0xFF; + p[5] = (i>>16)&0xFF; + p[6] = (i>> 8)&0xFF; + p[7] = (i>> 0)&0xFF; +#endif + return 8; } /* -** Extract the snippet text for fragment pFragment from cursor pCsr and -** append it to string buffer pOut. +** Increment the reference count of node p. */ -static int fts3SnippetText( - Fts3Cursor *pCsr, /* FTS3 Cursor */ - SnippetFragment *pFragment, /* Snippet to extract */ - int iFragment, /* Fragment number */ - int isLast, /* True for final fragment in snippet */ - int nSnippet, /* Number of tokens in extracted snippet */ - const char *zOpen, /* String inserted before highlighted term */ - const char *zClose, /* String inserted after highlighted term */ - const char *zEllipsis, /* String inserted between snippets */ - StrBuffer *pOut /* Write output here */ -){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int rc; /* Return code */ - const char *zDoc; /* Document text to extract snippet from */ - int nDoc; /* Size of zDoc in bytes */ - int iCurrent = 0; /* Current token number of document */ - int iEnd = 0; /* Byte offset of end of current token */ - int isShiftDone = 0; /* True after snippet is shifted */ - int iPos = pFragment->iPos; /* First token of snippet */ - u64 hlmask = pFragment->hlmask; /* Highlight-mask for snippet */ - int iCol = pFragment->iCol+1; /* Query column to extract text from */ - sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */ - sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */ - - zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol); - if( zDoc==0 ){ - if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){ - return SQLITE_NOMEM; - } - return SQLITE_OK; - } - nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol); - - /* Open a token cursor on the document. */ - pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule; - rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, zDoc,nDoc,&pC); - if( rc!=SQLITE_OK ){ - return rc; - } - - while( rc==SQLITE_OK ){ - const char *ZDUMMY; /* Dummy argument used with tokenizer */ - int DUMMY1 = -1; /* Dummy argument used with tokenizer */ - int iBegin = 0; /* Offset in zDoc of start of token */ - int iFin = 0; /* Offset in zDoc of end of token */ - int isHighlight = 0; /* True for highlighted terms */ - - /* Variable DUMMY1 is initialized to a negative value above. Elsewhere - ** in the FTS code the variable that the third argument to xNext points to - ** is initialized to zero before the first (*but not necessarily - ** subsequent*) call to xNext(). This is done for a particular application - ** that needs to know whether or not the tokenizer is being used for - ** snippet generation or for some other purpose. - ** - ** Extreme care is required when writing code to depend on this - ** initialization. It is not a documented part of the tokenizer interface. - ** If a tokenizer is used directly by any code outside of FTS, this - ** convention might not be respected. */ - rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent); - if( rc!=SQLITE_OK ){ - if( rc==SQLITE_DONE ){ - /* Special case - the last token of the snippet is also the last token - ** of the column. Append any punctuation that occurred between the end - ** of the previous token and the end of the document to the output. - ** Then break out of the loop. */ - rc = fts3StringAppend(pOut, &zDoc[iEnd], -1); - } - break; - } - if( iCurrentiLangid, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask - ); - isShiftDone = 1; - - /* Now that the shift has been done, check if the initial "..." are - ** required. They are required if (a) this is not the first fragment, - ** or (b) this fragment does not begin at position 0 of its column. - */ - if( rc==SQLITE_OK ){ - if( iPos>0 || iFragment>0 ){ - rc = fts3StringAppend(pOut, zEllipsis, -1); - }else if( iBegin ){ - rc = fts3StringAppend(pOut, zDoc, iBegin); - } - } - if( rc!=SQLITE_OK || iCurrent=(iPos+nSnippet) ){ - if( isLast ){ - rc = fts3StringAppend(pOut, zEllipsis, -1); - } - break; - } - - /* Set isHighlight to true if this term should be highlighted. */ - isHighlight = (hlmask & ((u64)1 << (iCurrent-iPos)))!=0; - - if( iCurrent>iPos ) rc = fts3StringAppend(pOut, &zDoc[iEnd], iBegin-iEnd); - if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zOpen, -1); - if( rc==SQLITE_OK ) rc = fts3StringAppend(pOut, &zDoc[iBegin], iFin-iBegin); - if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zClose, -1); - - iEnd = iFin; +static void nodeReference(RtreeNode *p){ + if( p ){ + assert( p->nRef>0 ); + p->nRef++; } - - pMod->xClose(pC); - return rc; } - /* -** This function is used to count the entries in a column-list (a -** delta-encoded list of term offsets within a single column of a single -** row). When this function is called, *ppCollist should point to the -** beginning of the first varint in the column-list (the varint that -** contains the position of the first matching term in the column data). -** Before returning, *ppCollist is set to point to the first byte after -** the last varint in the column-list (either the 0x00 signifying the end -** of the position-list, or the 0x01 that precedes the column number of -** the next column in the position-list). -** -** The number of elements in the column-list is returned. +** Clear the content of node p (set all bytes to 0x00). */ -static int fts3ColumnlistCount(char **ppCollist){ - char *pEnd = *ppCollist; - char c = 0; - int nEntry = 0; - - /* A column-list is terminated by either a 0x01 or 0x00. */ - while( 0xFE & (*pEnd | c) ){ - c = *pEnd++ & 0x80; - if( !c ) nEntry++; - } - - *ppCollist = pEnd; - return nEntry; +static void nodeZero(Rtree *pRtree, RtreeNode *p){ + memset(&p->zData[2], 0, pRtree->iNodeSize-2); + p->isDirty = 1; +} + +/* +** Given a node number iNode, return the corresponding key to use +** in the Rtree.aHash table. +*/ +static unsigned int nodeHash(i64 iNode){ + return ((unsigned)iNode) % HASHSIZE; } /* -** This function gathers 'y' or 'b' data for a single phrase. +** Search the node hash table for node iNode. If found, return a pointer +** to it. Otherwise, return 0. */ -static void fts3ExprLHits( - Fts3Expr *pExpr, /* Phrase expression node */ - MatchInfo *p /* Matchinfo context */ -){ - Fts3Table *pTab = (Fts3Table *)p->pCursor->base.pVtab; - int iStart; - Fts3Phrase *pPhrase = pExpr->pPhrase; - char *pIter = pPhrase->doclist.pList; - int iCol = 0; +static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){ + RtreeNode *p; + for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext); + return p; +} - assert( p->flag==FTS3_MATCHINFO_LHITS_BM || p->flag==FTS3_MATCHINFO_LHITS ); - if( p->flag==FTS3_MATCHINFO_LHITS ){ - iStart = pExpr->iPhrase * p->nCol; - }else{ - iStart = pExpr->iPhrase * ((p->nCol + 31) / 32); - } +/* +** Add node pNode to the node hash table. +*/ +static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){ + int iHash; + assert( pNode->pNext==0 ); + iHash = nodeHash(pNode->iNode); + pNode->pNext = pRtree->aHash[iHash]; + pRtree->aHash[iHash] = pNode; +} - while( 1 ){ - int nHit = fts3ColumnlistCount(&pIter); - if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){ - if( p->flag==FTS3_MATCHINFO_LHITS ){ - p->aMatchinfo[iStart + iCol] = (u32)nHit; - }else if( nHit ){ - p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F)); - } - } - assert( *pIter==0x00 || *pIter==0x01 ); - if( *pIter!=0x01 ) break; - pIter++; - pIter += fts3GetVarint32(pIter, &iCol); +/* +** Remove node pNode from the node hash table. +*/ +static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){ + RtreeNode **pp; + if( pNode->iNode!=0 ){ + pp = &pRtree->aHash[nodeHash(pNode->iNode)]; + for( ; (*pp)!=pNode; pp = &(*pp)->pNext){ assert(*pp); } + *pp = pNode->pNext; + pNode->pNext = 0; } } /* -** Gather the results for matchinfo directives 'y' and 'b'. +** Allocate and return new r-tree node. Initially, (RtreeNode.iNode==0), +** indicating that node has not yet been assigned a node number. It is +** assigned a node number when nodeWrite() is called to write the +** node contents out to the database. */ -static void fts3ExprLHitGather( - Fts3Expr *pExpr, - MatchInfo *p -){ - assert( (pExpr->pLeft==0)==(pExpr->pRight==0) ); - if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){ - if( pExpr->pLeft ){ - fts3ExprLHitGather(pExpr->pLeft, p); - fts3ExprLHitGather(pExpr->pRight, p); - }else{ - fts3ExprLHits(pExpr, p); - } +static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ + RtreeNode *pNode; + pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode) + pRtree->iNodeSize); + if( pNode ){ + memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); + pNode->zData = (u8 *)&pNode[1]; + pNode->nRef = 1; + pRtree->nNodeRef++; + pNode->pParent = pParent; + pNode->isDirty = 1; + nodeReference(pParent); } + return pNode; } /* -** fts3ExprIterate() callback used to collect the "global" matchinfo stats -** for a single query. -** -** fts3ExprIterate() callback to load the 'global' elements of a -** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements -** of the matchinfo array that are constant for all rows returned by the -** current query. -** -** Argument pCtx is actually a pointer to a struct of type MatchInfo. This -** function populates Matchinfo.aMatchinfo[] as follows: -** -** for(iCol=0; iColpCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol] - ); +static void nodeBlobReset(Rtree *pRtree){ + if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + sqlite3_blob_close(pBlob); + } } /* -** fts3ExprIterate() callback used to collect the "local" part of the -** FTS3_MATCHINFO_HITS array. The local stats are those elements of the -** array that are different for each row returned by the query. +** Obtain a reference to an r-tree node. */ -static int fts3ExprLocalHitsCb( - Fts3Expr *pExpr, /* Phrase expression node */ - int iPhrase, /* Phrase number */ - void *pCtx /* Pointer to MatchInfo structure */ +static int nodeAcquire( + Rtree *pRtree, /* R-tree structure */ + i64 iNode, /* Node number to load */ + RtreeNode *pParent, /* Either the parent node or NULL */ + RtreeNode **ppNode /* OUT: Acquired node */ ){ int rc = SQLITE_OK; - MatchInfo *p = (MatchInfo *)pCtx; - int iStart = iPhrase * p->nCol * 3; - int i; + RtreeNode *pNode = 0; - for(i=0; inCol && rc==SQLITE_OK; i++){ - char *pCsr; - rc = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i, &pCsr); - if( pCsr ){ - p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr); - }else{ - p->aMatchinfo[iStart+i*3] = 0; + /* Check if the requested node is already in the hash table. If so, + ** increase its reference count and return it. + */ + if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ + if( pParent && pParent!=pNode->pParent ){ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; } - } - - return rc; -} - -static int fts3MatchinfoCheck( - Fts3Table *pTab, - char cArg, - char **pzErr -){ - if( (cArg==FTS3_MATCHINFO_NPHRASE) - || (cArg==FTS3_MATCHINFO_NCOL) - || (cArg==FTS3_MATCHINFO_NDOC && pTab->bFts4) - || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bFts4) - || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize) - || (cArg==FTS3_MATCHINFO_LCS) - || (cArg==FTS3_MATCHINFO_HITS) - || (cArg==FTS3_MATCHINFO_LHITS) - || (cArg==FTS3_MATCHINFO_LHITS_BM) - ){ + pNode->nRef++; + *ppNode = pNode; return SQLITE_OK; } - sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo request: %c", cArg); - return SQLITE_ERROR; -} - -static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ - int nVal; /* Number of integers output by cArg */ - - switch( cArg ){ - case FTS3_MATCHINFO_NDOC: - case FTS3_MATCHINFO_NPHRASE: - case FTS3_MATCHINFO_NCOL: - nVal = 1; - break; - - case FTS3_MATCHINFO_AVGLENGTH: - case FTS3_MATCHINFO_LENGTH: - case FTS3_MATCHINFO_LCS: - nVal = pInfo->nCol; - break; - - case FTS3_MATCHINFO_LHITS: - nVal = pInfo->nCol * pInfo->nPhrase; - break; - - case FTS3_MATCHINFO_LHITS_BM: - nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); - break; - default: - assert( cArg==FTS3_MATCHINFO_HITS ); - nVal = pInfo->nCol * pInfo->nPhrase * 3; - break; + if( pRtree->pNodeBlob ){ + sqlite3_blob *pBlob = pRtree->pNodeBlob; + pRtree->pNodeBlob = 0; + rc = sqlite3_blob_reopen(pBlob, iNode); + pRtree->pNodeBlob = pBlob; + if( rc ){ + nodeBlobReset(pRtree); + if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM; + } + } + if( pRtree->pNodeBlob==0 ){ + char *zTab = sqlite3_mprintf("%s_node", pRtree->zName); + if( zTab==0 ) return SQLITE_NOMEM; + rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0, + &pRtree->pNodeBlob); + sqlite3_free(zTab); + } + if( rc ){ + nodeBlobReset(pRtree); + *ppNode = 0; + /* If unable to open an sqlite3_blob on the desired row, that can only + ** be because the shadow tables hold erroneous data. */ + if( rc==SQLITE_ERROR ){ + rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); + } + }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ + pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize); + if( !pNode ){ + rc = SQLITE_NOMEM; + }else{ + pNode->pParent = pParent; + pNode->zData = (u8 *)&pNode[1]; + pNode->nRef = 1; + pRtree->nNodeRef++; + pNode->iNode = iNode; + pNode->isDirty = 0; + pNode->pNext = 0; + rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, + pRtree->iNodeSize, 0); + } } - return nVal; -} - -static int fts3MatchinfoSelectDoctotal( - Fts3Table *pTab, - sqlite3_stmt **ppStmt, - sqlite3_int64 *pnDoc, - const char **paLen -){ - sqlite3_stmt *pStmt; - const char *a; - sqlite3_int64 nDoc; + /* If the root node was just loaded, set pRtree->iDepth to the height + ** of the r-tree structure. A height of zero means all data is stored on + ** the root node. A height of one means the children of the root node + ** are the leaves, and so on. If the depth as specified on the root node + ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. + */ + if( rc==SQLITE_OK && pNode && iNode==1 ){ + pRtree->iDepth = readInt16(pNode->zData); + if( pRtree->iDepth>RTREE_MAX_DEPTH ){ + rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); + } + } - if( !*ppStmt ){ - int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt); - if( rc!=SQLITE_OK ) return rc; + /* If no error has occurred so far, check if the "number of entries" + ** field on the node is too large. If so, set the return code to + ** SQLITE_CORRUPT_VTAB. + */ + if( pNode && rc==SQLITE_OK ){ + if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ + rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); + } } - pStmt = *ppStmt; - assert( sqlite3_data_count(pStmt)==1 ); - a = sqlite3_column_blob(pStmt, 0); - a += sqlite3Fts3GetVarint(a, &nDoc); - if( nDoc==0 ) return FTS_CORRUPT_VTAB; - *pnDoc = (u32)nDoc; + if( rc==SQLITE_OK ){ + if( pNode!=0 ){ + nodeReference(pParent); + nodeHashInsert(pRtree, pNode); + }else{ + rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); + } + *ppNode = pNode; + }else{ + if( pNode ){ + pRtree->nNodeRef--; + sqlite3_free(pNode); + } + *ppNode = 0; + } - if( paLen ) *paLen = a; - return SQLITE_OK; + return rc; } /* -** An instance of the following structure is used to store state while -** iterating through a multi-column position-list corresponding to the -** hits for a single phrase on a single row in order to calculate the -** values for a matchinfo() FTS3_MATCHINFO_LCS request. -*/ -typedef struct LcsIterator LcsIterator; -struct LcsIterator { - Fts3Expr *pExpr; /* Pointer to phrase expression */ - int iPosOffset; /* Tokens count up to end of this phrase */ - char *pRead; /* Cursor used to iterate through aDoclist */ - int iPos; /* Current position */ -}; - -/* -** If LcsIterator.iCol is set to the following value, the iterator has -** finished iterating through all offsets for all columns. +** Overwrite cell iCell of node pNode with the contents of pCell. */ -#define LCS_ITERATOR_FINISHED 0x7FFFFFFF; - -static int fts3MatchinfoLcsCb( - Fts3Expr *pExpr, /* Phrase expression node */ - int iPhrase, /* Phrase number (numbered from zero) */ - void *pCtx /* Pointer to MatchInfo structure */ +static void nodeOverwriteCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node into which the cell is to be written */ + RtreeCell *pCell, /* The cell to write */ + int iCell /* Index into pNode into which pCell is written */ ){ - LcsIterator *aIter = (LcsIterator *)pCtx; - aIter[iPhrase].pExpr = pExpr; - return SQLITE_OK; + int ii; + u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; + p += writeInt64(p, pCell->iRowid); + for(ii=0; iinDim2; ii++){ + p += writeCoord(p, &pCell->aCoord[ii]); + } + pNode->isDirty = 1; } /* -** Advance the iterator passed as an argument to the next position. Return -** 1 if the iterator is at EOF or if it now points to the start of the -** position list for the next column. +** Remove the cell with index iCell from node pNode. */ -static int fts3LcsIteratorAdvance(LcsIterator *pIter){ - char *pRead = pIter->pRead; - sqlite3_int64 iRead; - int rc = 0; - - pRead += sqlite3Fts3GetVarint(pRead, &iRead); - if( iRead==0 || iRead==1 ){ - pRead = 0; - rc = 1; - }else{ - pIter->iPos += (int)(iRead-2); - } - - pIter->pRead = pRead; - return rc; +static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ + u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; + u8 *pSrc = &pDst[pRtree->nBytesPerCell]; + int nByte = (NCELL(pNode) - iCell - 1) * pRtree->nBytesPerCell; + memmove(pDst, pSrc, nByte); + writeInt16(&pNode->zData[2], NCELL(pNode)-1); + pNode->isDirty = 1; } - + /* -** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag. -** -** If the call is successful, the longest-common-substring lengths for each -** column are written into the first nCol elements of the pInfo->aMatchinfo[] -** array before returning. SQLITE_OK is returned in this case. +** Insert the contents of cell pCell into node pNode. If the insert +** is successful, return SQLITE_OK. ** -** Otherwise, if an error occurs, an SQLite error code is returned and the -** data written to the first nCol elements of pInfo->aMatchinfo[] is -** undefined. +** If there is not enough free space in pNode, return SQLITE_FULL. */ -static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){ - LcsIterator *aIter; - int i; - int iCol; - int nToken = 0; +static int nodeInsertCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* Write new cell into this node */ + RtreeCell *pCell /* The cell to be inserted */ +){ + int nCell; /* Current number of cells in pNode */ + int nMaxCell; /* Maximum number of cells for pNode */ - /* Allocate and populate the array of LcsIterator objects. The array - ** contains one element for each matchable phrase in the query. - **/ - aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase); - if( !aIter ) return SQLITE_NOMEM; - memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase); - (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); + nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell; + nCell = NCELL(pNode); - for(i=0; inPhrase; i++){ - LcsIterator *pIter = &aIter[i]; - nToken -= pIter->pExpr->pPhrase->nToken; - pIter->iPosOffset = nToken; + assert( nCell<=nMaxCell ); + if( nCellzData[2], nCell+1); + pNode->isDirty = 1; } - for(iCol=0; iColnCol; iCol++){ - int nLcs = 0; /* LCS value for this column */ - int nLive = 0; /* Number of iterators in aIter not at EOF */ + return (nCell==nMaxCell); +} - for(i=0; inPhrase; i++){ - int rc; - LcsIterator *pIt = &aIter[i]; - rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead); - if( rc!=SQLITE_OK ) return rc; - if( pIt->pRead ){ - pIt->iPos = pIt->iPosOffset; - fts3LcsIteratorAdvance(&aIter[i]); - nLive++; - } +/* +** If the node is dirty, write it out to the database. +*/ +static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ + int rc = SQLITE_OK; + if( pNode->isDirty ){ + sqlite3_stmt *p = pRtree->pWriteNode; + if( pNode->iNode ){ + sqlite3_bind_int64(p, 1, pNode->iNode); + }else{ + sqlite3_bind_null(p, 1); } - - while( nLive>0 ){ - LcsIterator *pAdv = 0; /* The iterator to advance by one position */ - int nThisLcs = 0; /* LCS for the current iterator positions */ - - for(i=0; inPhrase; i++){ - LcsIterator *pIter = &aIter[i]; - if( pIter->pRead==0 ){ - /* This iterator is already at EOF for this column. */ - nThisLcs = 0; - }else{ - if( pAdv==0 || pIter->iPosiPos ){ - pAdv = pIter; - } - if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){ - nThisLcs++; - }else{ - nThisLcs = 1; - } - if( nThisLcs>nLcs ) nLcs = nThisLcs; - } - } - if( fts3LcsIteratorAdvance(pAdv) ) nLive--; + sqlite3_bind_blob(p, 2, pNode->zData, pRtree->iNodeSize, SQLITE_STATIC); + sqlite3_step(p); + pNode->isDirty = 0; + rc = sqlite3_reset(p); + sqlite3_bind_null(p, 2); + if( pNode->iNode==0 && rc==SQLITE_OK ){ + pNode->iNode = sqlite3_last_insert_rowid(pRtree->db); + nodeHashInsert(pRtree, pNode); } - - pInfo->aMatchinfo[iCol] = nLcs; } - - sqlite3_free(aIter); - return SQLITE_OK; + return rc; } /* -** Populate the buffer pInfo->aMatchinfo[] with an array of integers to -** be returned by the matchinfo() function. Argument zArg contains the -** format string passed as the second argument to matchinfo (or the -** default value "pcx" if no second argument was specified). The format -** string has already been validated and the pInfo->aMatchinfo[] array -** is guaranteed to be large enough for the output. -** -** If bGlobal is true, then populate all fields of the matchinfo() output. -** If it is false, then assume that those fields that do not change between -** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS) -** have already been populated. -** -** Return SQLITE_OK if successful, or an SQLite error code if an error -** occurs. If a value other than SQLITE_OK is returned, the state the -** pInfo->aMatchinfo[] buffer is left in is undefined. +** Release a reference to a node. If the node is dirty and the reference +** count drops to zero, the node data is written to the database. */ -static int fts3MatchinfoValues( - Fts3Cursor *pCsr, /* FTS3 cursor object */ - int bGlobal, /* True to grab the global stats */ - MatchInfo *pInfo, /* Matchinfo context object */ - const char *zArg /* Matchinfo format string */ -){ +static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ int rc = SQLITE_OK; - int i; - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - sqlite3_stmt *pSelect = 0; - - for(i=0; rc==SQLITE_OK && zArg[i]; i++){ - pInfo->flag = zArg[i]; - switch( zArg[i] ){ - case FTS3_MATCHINFO_NPHRASE: - if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase; - break; - - case FTS3_MATCHINFO_NCOL: - if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol; - break; - - case FTS3_MATCHINFO_NDOC: - if( bGlobal ){ - sqlite3_int64 nDoc = 0; - rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0); - pInfo->aMatchinfo[0] = (u32)nDoc; - } - break; - - case FTS3_MATCHINFO_AVGLENGTH: - if( bGlobal ){ - sqlite3_int64 nDoc; /* Number of rows in table */ - const char *a; /* Aggregate column length array */ - - rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a); - if( rc==SQLITE_OK ){ - int iCol; - for(iCol=0; iColnCol; iCol++){ - u32 iVal; - sqlite3_int64 nToken; - a += sqlite3Fts3GetVarint(a, &nToken); - iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc); - pInfo->aMatchinfo[iCol] = iVal; - } - } - } - break; - - case FTS3_MATCHINFO_LENGTH: { - sqlite3_stmt *pSelectDocsize = 0; - rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize); - if( rc==SQLITE_OK ){ - int iCol; - const char *a = sqlite3_column_blob(pSelectDocsize, 0); - for(iCol=0; iColnCol; iCol++){ - sqlite3_int64 nToken; - a += sqlite3Fts3GetVarint(a, &nToken); - pInfo->aMatchinfo[iCol] = (u32)nToken; - } - } - sqlite3_reset(pSelectDocsize); - break; + if( pNode ){ + assert( pNode->nRef>0 ); + assert( pRtree->nNodeRef>0 ); + pNode->nRef--; + if( pNode->nRef==0 ){ + pRtree->nNodeRef--; + if( pNode->iNode==1 ){ + pRtree->iDepth = -1; } - - case FTS3_MATCHINFO_LCS: - rc = fts3ExprLoadDoclists(pCsr, 0, 0); - if( rc==SQLITE_OK ){ - rc = fts3MatchinfoLcs(pCsr, pInfo); - } - break; - - case FTS3_MATCHINFO_LHITS_BM: - case FTS3_MATCHINFO_LHITS: { - int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); - memset(pInfo->aMatchinfo, 0, nZero); - fts3ExprLHitGather(pCsr->pExpr, pInfo); - break; + if( pNode->pParent ){ + rc = nodeRelease(pRtree, pNode->pParent); } - - default: { - Fts3Expr *pExpr; - assert( zArg[i]==FTS3_MATCHINFO_HITS ); - pExpr = pCsr->pExpr; - rc = fts3ExprLoadDoclists(pCsr, 0, 0); - if( rc!=SQLITE_OK ) break; - if( bGlobal ){ - if( pCsr->pDeferred ){ - rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0); - if( rc!=SQLITE_OK ) break; - } - rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo); - sqlite3Fts3EvalTestDeferred(pCsr, &rc); - if( rc!=SQLITE_OK ) break; - } - (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo); - break; + if( rc==SQLITE_OK ){ + rc = nodeWrite(pRtree, pNode); } + nodeHashDelete(pRtree, pNode); + sqlite3_free(pNode); } - - pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]); } - - sqlite3_reset(pSelect); return rc; } - /* -** Populate pCsr->aMatchinfo[] with data for the current row. The -** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32). +** Return the 64-bit integer value associated with cell iCell of +** node pNode. If pNode is a leaf node, this is a rowid. If it is +** an internal node, then the 64-bit integer is a child page number. */ -static void fts3GetMatchinfo( - sqlite3_context *pCtx, /* Return results here */ - Fts3Cursor *pCsr, /* FTS3 Cursor object */ - const char *zArg /* Second argument to matchinfo() function */ +static i64 nodeGetRowid( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract the ID */ + int iCell /* The cell index from which to extract the ID */ ){ - MatchInfo sInfo; - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int rc = SQLITE_OK; - int bGlobal = 0; /* Collect 'global' stats as well as local */ - - u32 *aOut = 0; - void (*xDestroyOut)(void*) = 0; - - memset(&sInfo, 0, sizeof(MatchInfo)); - sInfo.pCursor = pCsr; - sInfo.nCol = pTab->nColumn; - - /* If there is cached matchinfo() data, but the format string for the - ** cache does not match the format string for this request, discard - ** the cached data. */ - if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){ - sqlite3Fts3MIBufferFree(pCsr->pMIBuffer); - pCsr->pMIBuffer = 0; - } - - /* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the - ** matchinfo function has been called for this query. In this case - ** allocate the array used to accumulate the matchinfo data and - ** initialize those elements that are constant for every row. - */ - if( pCsr->pMIBuffer==0 ){ - int nMatchinfo = 0; /* Number of u32 elements in match-info */ - int i; /* Used to iterate through zArg */ - - /* Determine the number of phrases in the query */ - pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr); - sInfo.nPhrase = pCsr->nPhrase; - - /* Determine the number of integers in the buffer returned by this call. */ - for(i=0; zArg[i]; i++){ - char *zErr = 0; - if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){ - sqlite3_result_error(pCtx, zErr, -1); - sqlite3_free(zErr); - return; - } - nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]); - } - - /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */ - pCsr->pMIBuffer = fts3MIBufferNew(nMatchinfo, zArg); - if( !pCsr->pMIBuffer ) rc = SQLITE_NOMEM; - - pCsr->isMatchinfoNeeded = 1; - bGlobal = 1; - } - - if( rc==SQLITE_OK ){ - xDestroyOut = fts3MIBufferAlloc(pCsr->pMIBuffer, &aOut); - if( xDestroyOut==0 ){ - rc = SQLITE_NOMEM; - } - } - - if( rc==SQLITE_OK ){ - sInfo.aMatchinfo = aOut; - sInfo.nPhrase = pCsr->nPhrase; - rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg); - if( bGlobal ){ - fts3MIBufferSetGlobal(pCsr->pMIBuffer); - } - } - - if( rc!=SQLITE_OK ){ - sqlite3_result_error_code(pCtx, rc); - if( xDestroyOut ) xDestroyOut(aOut); - }else{ - int n = pCsr->pMIBuffer->nElem * sizeof(u32); - sqlite3_result_blob(pCtx, aOut, n, xDestroyOut); - } + assert( iCellzData[4 + pRtree->nBytesPerCell*iCell]); } /* -** Implementation of snippet() function. +** Return coordinate iCoord from cell iCell in node pNode. */ -SQLITE_PRIVATE void sqlite3Fts3Snippet( - sqlite3_context *pCtx, /* SQLite function call context */ - Fts3Cursor *pCsr, /* Cursor object */ - const char *zStart, /* Snippet start text - "" */ - const char *zEnd, /* Snippet end text - "" */ - const char *zEllipsis, /* Snippet ellipsis text - "..." */ - int iCol, /* Extract snippet from this column */ - int nToken /* Approximate number of tokens in snippet */ +static void nodeGetCoord( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node from which to extract a coordinate */ + int iCell, /* The index of the cell within the node */ + int iCoord, /* Which coordinate to extract */ + RtreeCoord *pCoord /* OUT: Space to write result to */ ){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - int rc = SQLITE_OK; - int i; - StrBuffer res = {0, 0, 0}; - - /* The returned text includes up to four fragments of text extracted from - ** the data in the current row. The first iteration of the for(...) loop - ** below attempts to locate a single fragment of text nToken tokens in - ** size that contains at least one instance of all phrases in the query - ** expression that appear in the current row. If such a fragment of text - ** cannot be found, the second iteration of the loop attempts to locate - ** a pair of fragments, and so on. - */ - int nSnippet = 0; /* Number of fragments in this snippet */ - SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */ - int nFToken = -1; /* Number of tokens in each fragment */ - - if( !pCsr->pExpr ){ - sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); - return; - } - - for(nSnippet=1; 1; nSnippet++){ - - int iSnip; /* Loop counter 0..nSnippet-1 */ - u64 mCovered = 0; /* Bitmask of phrases covered by snippet */ - u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */ - - if( nToken>=0 ){ - nFToken = (nToken+nSnippet-1) / nSnippet; - }else{ - nFToken = -1 * nToken; - } - - for(iSnip=0; iSnipzData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); +} - /* Loop through all columns of the table being considered for snippets. - ** If the iCol argument to this function was negative, this means all - ** columns of the FTS3 table. Otherwise, only column iCol is considered. - */ - for(iRead=0; iReadnColumn; iRead++){ - SnippetFragment sF = {0, 0, 0, 0}; - int iS = 0; - if( iCol>=0 && iRead!=iCol ) continue; +/* +** Deserialize cell iCell of node pNode. Populate the structure pointed +** to by pCell with the results. +*/ +static void nodeGetCell( + Rtree *pRtree, /* The overall R-Tree */ + RtreeNode *pNode, /* The node containing the cell to be read */ + int iCell, /* Index of the cell within the node */ + RtreeCell *pCell /* OUT: Write the cell contents here */ +){ + u8 *pData; + RtreeCoord *pCoord; + int ii = 0; + pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); + pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); + pCoord = pCell->aCoord; + do{ + readCoord(pData, &pCoord[ii]); + readCoord(pData+4, &pCoord[ii+1]); + pData += 8; + ii += 2; + }while( iinDim2 ); +} - /* Find the best snippet of nFToken tokens in column iRead. */ - rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS); - if( rc!=SQLITE_OK ){ - goto snippet_out; - } - if( iS>iBestScore ){ - *pFragment = sF; - iBestScore = iS; - } - } - mCovered |= pFragment->covered; - } +/* Forward declaration for the function that does the work of +** the virtual table module xCreate() and xConnect() methods. +*/ +static int rtreeInit( + sqlite3 *, void *, int, const char *const*, sqlite3_vtab **, char **, int +); - /* If all query phrases seen by fts3BestSnippet() are present in at least - ** one of the nSnippet snippet fragments, break out of the loop. - */ - assert( (mCovered&mSeen)==mCovered ); - if( mSeen==mCovered || nSnippet==SizeofArray(aSnippet) ) break; - } +/* +** Rtree virtual table module xCreate method. +*/ +static int rtreeCreate( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 1); +} - assert( nFToken>0 ); +/* +** Rtree virtual table module xConnect method. +*/ +static int rtreeConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 0); +} - for(i=0; inBusy++; +} - snippet_out: - sqlite3Fts3SegmentsClose(pTab); - if( rc!=SQLITE_OK ){ - sqlite3_result_error_code(pCtx, rc); - sqlite3_free(res.z); - }else{ - sqlite3_result_text(pCtx, res.z, -1, sqlite3_free); +/* +** Decrement the r-tree reference count. When the reference count reaches +** zero the structure is deleted. +*/ +static void rtreeRelease(Rtree *pRtree){ + pRtree->nBusy--; + if( pRtree->nBusy==0 ){ + pRtree->inWrTrans = 0; + assert( pRtree->nCursor==0 ); + nodeBlobReset(pRtree); + assert( pRtree->nNodeRef==0 || pRtree->bCorrupt ); + sqlite3_finalize(pRtree->pWriteNode); + sqlite3_finalize(pRtree->pDeleteNode); + sqlite3_finalize(pRtree->pReadRowid); + sqlite3_finalize(pRtree->pWriteRowid); + sqlite3_finalize(pRtree->pDeleteRowid); + sqlite3_finalize(pRtree->pReadParent); + sqlite3_finalize(pRtree->pWriteParent); + sqlite3_finalize(pRtree->pDeleteParent); + sqlite3_finalize(pRtree->pWriteAux); + sqlite3_free(pRtree->zReadAuxSql); + sqlite3_free(pRtree); } } - -typedef struct TermOffset TermOffset; -typedef struct TermOffsetCtx TermOffsetCtx; - -struct TermOffset { - char *pList; /* Position-list */ - int iPos; /* Position just read from pList */ - int iOff; /* Offset of this term from read positions */ -}; - -struct TermOffsetCtx { - Fts3Cursor *pCsr; - int iCol; /* Column of table to populate aTerm for */ - int iTerm; - sqlite3_int64 iDocid; - TermOffset *aTerm; -}; +/* +** Rtree virtual table module xDisconnect method. +*/ +static int rtreeDisconnect(sqlite3_vtab *pVtab){ + rtreeRelease((Rtree *)pVtab); + return SQLITE_OK; +} /* -** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets(). +** Rtree virtual table module xDestroy method. */ -static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ - TermOffsetCtx *p = (TermOffsetCtx *)ctx; - int nTerm; /* Number of tokens in phrase */ - int iTerm; /* For looping through nTerm phrase terms */ - char *pList; /* Pointer to position list for phrase */ - int iPos = 0; /* First position in position-list */ +static int rtreeDestroy(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; int rc; - - UNUSED_PARAMETER(iPhrase); - rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pList); - nTerm = pExpr->pPhrase->nToken; - if( pList ){ - fts3GetDeltaPosition(&pList, &iPos); - assert( iPos>=0 ); + char *zCreate = sqlite3_mprintf( + "DROP TABLE '%q'.'%q_node';" + "DROP TABLE '%q'.'%q_rowid';" + "DROP TABLE '%q'.'%q_parent';", + pRtree->zDb, pRtree->zName, + pRtree->zDb, pRtree->zName, + pRtree->zDb, pRtree->zName + ); + if( !zCreate ){ + rc = SQLITE_NOMEM; + }else{ + nodeBlobReset(pRtree); + rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0); + sqlite3_free(zCreate); } - - for(iTerm=0; iTermaTerm[p->iTerm++]; - pT->iOff = nTerm-iTerm-1; - pT->pList = pList; - pT->iPos = iPos; + if( rc==SQLITE_OK ){ + rtreeRelease(pRtree); } return rc; } /* -** Implementation of offsets() function. +** Rtree virtual table module xOpen method. */ -SQLITE_PRIVATE void sqlite3Fts3Offsets( - sqlite3_context *pCtx, /* SQLite function call context */ - Fts3Cursor *pCsr /* Cursor object */ -){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule; - int rc; /* Return Code */ - int nToken; /* Number of tokens in query */ - int iCol; /* Column currently being processed */ - StrBuffer res = {0, 0, 0}; /* Result string */ - TermOffsetCtx sCtx; /* Context for fts3ExprTermOffsetInit() */ +static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + int rc = SQLITE_NOMEM; + Rtree *pRtree = (Rtree *)pVTab; + RtreeCursor *pCsr; - if( !pCsr->pExpr ){ - sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); - return; + pCsr = (RtreeCursor *)sqlite3_malloc64(sizeof(RtreeCursor)); + if( pCsr ){ + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = pVTab; + rc = SQLITE_OK; + pRtree->nCursor++; } + *ppCursor = (sqlite3_vtab_cursor *)pCsr; - memset(&sCtx, 0, sizeof(sCtx)); - assert( pCsr->isRequireSeek==0 ); + return rc; +} - /* Count the number of terms in the query */ - rc = fts3ExprLoadDoclists(pCsr, 0, &nToken); - if( rc!=SQLITE_OK ) goto offsets_out; - /* Allocate the array of TermOffset iterators. */ - sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken); - if( 0==sCtx.aTerm ){ - rc = SQLITE_NOMEM; - goto offsets_out; +/* +** Reset a cursor back to its initial state. +*/ +static void resetCursor(RtreeCursor *pCsr){ + Rtree *pRtree = (Rtree *)(pCsr->base.pVtab); + int ii; + sqlite3_stmt *pStmt; + if( pCsr->aConstraint ){ + int i; /* Used to iterate through constraint array */ + for(i=0; inConstraint; i++){ + sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; + if( pInfo ){ + if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); + sqlite3_free(pInfo); + } + } + sqlite3_free(pCsr->aConstraint); + pCsr->aConstraint = 0; } - sCtx.iDocid = pCsr->iPrevId; - sCtx.pCsr = pCsr; + for(ii=0; iiaNode[ii]); + sqlite3_free(pCsr->aPoint); + pStmt = pCsr->pReadAux; + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = (sqlite3_vtab*)pRtree; + pCsr->pReadAux = pStmt; - /* Loop through the table columns, appending offset information to - ** string-buffer res for each column. - */ - for(iCol=0; iColnColumn; iCol++){ - sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */ - const char *ZDUMMY; /* Dummy argument used with xNext() */ - int NDUMMY = 0; /* Dummy argument used with xNext() */ - int iStart = 0; - int iEnd = 0; - int iCurrent = 0; - const char *zDoc; - int nDoc; +} - /* Initialize the contents of sCtx.aTerm[] for column iCol. There is - ** no way that this operation can fail, so the return code from - ** fts3ExprIterate() can be discarded. - */ - sCtx.iCol = iCol; - sCtx.iTerm = 0; - (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); +/* +** Rtree virtual table module xClose method. +*/ +static int rtreeClose(sqlite3_vtab_cursor *cur){ + Rtree *pRtree = (Rtree *)(cur->pVtab); + RtreeCursor *pCsr = (RtreeCursor *)cur; + assert( pRtree->nCursor>0 ); + resetCursor(pCsr); + sqlite3_finalize(pCsr->pReadAux); + sqlite3_free(pCsr); + pRtree->nCursor--; + nodeBlobReset(pRtree); + return SQLITE_OK; +} - /* Retreive the text stored in column iCol. If an SQL NULL is stored - ** in column iCol, jump immediately to the next iteration of the loop. - ** If an OOM occurs while retrieving the data (this can happen if SQLite - ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM - ** to the caller. - */ - zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1); - nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1); - if( zDoc==0 ){ - if( sqlite3_column_type(pCsr->pStmt, iCol+1)==SQLITE_NULL ){ - continue; - } - rc = SQLITE_NOMEM; - goto offsets_out; - } +/* +** Rtree virtual table module xEof method. +** +** Return non-zero if the cursor does not currently point to a valid +** record (i.e if the scan has finished), or zero otherwise. +*/ +static int rtreeEof(sqlite3_vtab_cursor *cur){ + RtreeCursor *pCsr = (RtreeCursor *)cur; + return pCsr->atEOF; +} - /* Initialize a tokenizer iterator to iterate through column iCol. */ - rc = sqlite3Fts3OpenTokenizer(pTab->pTokenizer, pCsr->iLangid, - zDoc, nDoc, &pC - ); - if( rc!=SQLITE_OK ) goto offsets_out; +/* +** Convert raw bits from the on-disk RTree record into a coordinate value. +** The on-disk format is big-endian and needs to be converted for little- +** endian platforms. The on-disk record stores integer coordinates if +** eInt is true and it stores 32-bit floating point records if eInt is +** false. a[] is the four bytes of the on-disk record to be decoded. +** Store the results in "r". +** +** There are five versions of this macro. The last one is generic. The +** other four are various architectures-specific optimizations. +*/ +#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = _byteswap_ulong(*(u32*)a); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = __builtin_bswap32(*(u32*)a); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==1234 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + c.u = ((c.u>>24)&0xff)|((c.u>>8)&0xff00)| \ + ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#elif SQLITE_BYTEORDER==4321 +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + memcpy(&c.u,a,4); \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#else +#define RTREE_DECODE_COORD(eInt, a, r) { \ + RtreeCoord c; /* Coordinate decoded */ \ + c.u = ((u32)a[0]<<24) + ((u32)a[1]<<16) \ + +((u32)a[2]<<8) + a[3]; \ + r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +} +#endif - rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); - while( rc==SQLITE_OK ){ - int i; /* Used to loop through terms */ - int iMinPos = 0x7FFFFFFF; /* Position of next token */ - TermOffset *pTerm = 0; /* TermOffset associated with next token */ +/* +** Check the RTree node or entry given by pCellData and p against the MATCH +** constraint pConstraint. +*/ +static int rtreeCallbackConstraint( + RtreeConstraint *pConstraint, /* The constraint to test */ + int eInt, /* True if RTree holding integer coordinates */ + u8 *pCellData, /* Raw cell content */ + RtreeSearchPoint *pSearch, /* Container of this cell */ + sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ + int *peWithin /* OUT: visibility of the cell */ +){ + sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ + int nCoord = pInfo->nCoord; /* No. of coordinates */ + int rc; /* Callback return code */ + RtreeCoord c; /* Translator union */ + sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ - for(i=0; ipList && (pT->iPos-pT->iOff)iPos-pT->iOff; - pTerm = pT; - } - } + assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); + assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 ); - if( !pTerm ){ - /* All offsets for this column have been gathered. */ - rc = SQLITE_DONE; - }else{ - assert( iCurrent<=iMinPos ); - if( 0==(0xFE&*pTerm->pList) ){ - pTerm->pList = 0; - }else{ - fts3GetDeltaPosition(&pTerm->pList, &pTerm->iPos); - } - while( rc==SQLITE_OK && iCurrentxNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent); - } - if( rc==SQLITE_OK ){ - char aBuffer[64]; - sqlite3_snprintf(sizeof(aBuffer), aBuffer, - "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart - ); - rc = fts3StringAppend(&res, aBuffer, -1); - }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){ - rc = FTS_CORRUPT_VTAB; - } - } + if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){ + pInfo->iRowid = readInt64(pCellData); + } + pCellData += 8; +#ifndef SQLITE_RTREE_INT_ONLY + if( eInt==0 ){ + switch( nCoord ){ + case 10: readCoord(pCellData+36, &c); aCoord[9] = c.f; + readCoord(pCellData+32, &c); aCoord[8] = c.f; + case 8: readCoord(pCellData+28, &c); aCoord[7] = c.f; + readCoord(pCellData+24, &c); aCoord[6] = c.f; + case 6: readCoord(pCellData+20, &c); aCoord[5] = c.f; + readCoord(pCellData+16, &c); aCoord[4] = c.f; + case 4: readCoord(pCellData+12, &c); aCoord[3] = c.f; + readCoord(pCellData+8, &c); aCoord[2] = c.f; + default: readCoord(pCellData+4, &c); aCoord[1] = c.f; + readCoord(pCellData, &c); aCoord[0] = c.f; } - if( rc==SQLITE_DONE ){ - rc = SQLITE_OK; + }else +#endif + { + switch( nCoord ){ + case 10: readCoord(pCellData+36, &c); aCoord[9] = c.i; + readCoord(pCellData+32, &c); aCoord[8] = c.i; + case 8: readCoord(pCellData+28, &c); aCoord[7] = c.i; + readCoord(pCellData+24, &c); aCoord[6] = c.i; + case 6: readCoord(pCellData+20, &c); aCoord[5] = c.i; + readCoord(pCellData+16, &c); aCoord[4] = c.i; + case 4: readCoord(pCellData+12, &c); aCoord[3] = c.i; + readCoord(pCellData+8, &c); aCoord[2] = c.i; + default: readCoord(pCellData+4, &c); aCoord[1] = c.i; + readCoord(pCellData, &c); aCoord[0] = c.i; } - - pMod->xClose(pC); - if( rc!=SQLITE_OK ) goto offsets_out; } - - offsets_out: - sqlite3_free(sCtx.aTerm); - assert( rc!=SQLITE_DONE ); - sqlite3Fts3SegmentsClose(pTab); - if( rc!=SQLITE_OK ){ - sqlite3_result_error_code(pCtx, rc); - sqlite3_free(res.z); + if( pConstraint->op==RTREE_MATCH ){ + int eWithin = 0; + rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, + nCoord, aCoord, &eWithin); + if( eWithin==0 ) *peWithin = NOT_WITHIN; + *prScore = RTREE_ZERO; }else{ - sqlite3_result_text(pCtx, res.z, res.n-1, sqlite3_free); + pInfo->aCoord = aCoord; + pInfo->iLevel = pSearch->iLevel - 1; + pInfo->rScore = pInfo->rParentScore = pSearch->rScore; + pInfo->eWithin = pInfo->eParentWithin = pSearch->eWithin; + rc = pConstraint->u.xQueryFunc(pInfo); + if( pInfo->eWithin<*peWithin ) *peWithin = pInfo->eWithin; + if( pInfo->rScore<*prScore || *prScorerScore; + } } - return; + return rc; } /* -** Implementation of matchinfo() function. +** Check the internal RTree node given by pCellData against constraint p. +** If this constraint cannot be satisfied by any child within the node, +** set *peWithin to NOT_WITHIN. */ -SQLITE_PRIVATE void sqlite3Fts3Matchinfo( - sqlite3_context *pContext, /* Function call context */ - Fts3Cursor *pCsr, /* FTS3 table cursor */ - const char *zArg /* Second arg to matchinfo() function */ +static void rtreeNonleafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ ){ - Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; - const char *zFormat; + sqlite3_rtree_dbl val; /* Coordinate value convert to a double */ - if( zArg ){ - zFormat = zArg; - }else{ - zFormat = FTS3_MATCHINFO_DEFAULT; - } + /* p->iCoord might point to either a lower or upper bound coordinate + ** in a coordinate pair. But make pCellData point to the lower bound. + */ + pCellData += 8 + 4*(p->iCoord&0xfe); - if( !pCsr->pExpr ){ - sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC); - return; - }else{ - /* Retrieve matchinfo() data. */ - fts3GetMatchinfo(pContext, pCsr, zFormat); - sqlite3Fts3SegmentsClose(pTab); + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE + || p->op==RTREE_FALSE ); + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ + switch( p->op ){ + case RTREE_TRUE: return; /* Always satisfied */ + case RTREE_FALSE: break; /* Never satisfied */ + case RTREE_EQ: + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the lower bound of the coordinate pair */ + if( p->u.rValue>=val ){ + pCellData += 4; + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the upper bound of the coordinate pair */ + if( p->u.rValue<=val ) return; + } + break; + case RTREE_LE: + case RTREE_LT: + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the lower bound of the coordinate pair */ + if( p->u.rValue>=val ) return; + break; + + default: + pCellData += 4; + RTREE_DECODE_COORD(eInt, pCellData, val); + /* val now holds the upper bound of the coordinate pair */ + if( p->u.rValue<=val ) return; + break; } + *peWithin = NOT_WITHIN; } -#endif - -/************** End of fts3_snippet.c ****************************************/ -/************** Begin file fts3_unicode.c ************************************/ /* -** 2012 May 24 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** Check the leaf RTree cell given by pCellData against constraint p. +** If this constraint is not satisfied, set *peWithin to NOT_WITHIN. +** If the constraint is satisfied, leave *peWithin unchanged. ** -****************************************************************************** +** The constraint is of the form: xN op $val ** -** Implementation of the "unicode" full-text-search tokenizer. +** The op is given by p->op. The xN is p->iCoord-th coordinate in +** pCellData. $val is given by p->u.rValue. */ +static void rtreeLeafConstraint( + RtreeConstraint *p, /* The constraint to test */ + int eInt, /* True if RTree holds integer coordinates */ + u8 *pCellData, /* Raw cell content as appears on disk */ + int *peWithin /* Adjust downward, as appropriate */ +){ + RtreeDValue xN; /* Coordinate value converted to a double */ -#ifndef SQLITE_DISABLE_FTS3_UNICODE - -/* #include "fts3Int.h" */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) - -/* #include */ -/* #include */ -/* #include */ -/* #include */ - -/* #include "fts3_tokenizer.h" */ + assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE + || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE + || p->op==RTREE_FALSE ); + pCellData += 8 + p->iCoord*4; + assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ + RTREE_DECODE_COORD(eInt, pCellData, xN); + switch( p->op ){ + case RTREE_TRUE: return; /* Always satisfied */ + case RTREE_FALSE: break; /* Never satisfied */ + case RTREE_LE: if( xN <= p->u.rValue ) return; break; + case RTREE_LT: if( xN < p->u.rValue ) return; break; + case RTREE_GE: if( xN >= p->u.rValue ) return; break; + case RTREE_GT: if( xN > p->u.rValue ) return; break; + default: if( xN == p->u.rValue ) return; break; + } + *peWithin = NOT_WITHIN; +} /* -** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied -** from the sqlite3 source file utf.c. If this file is compiled as part -** of the amalgamation, they are not required. +** One of the cells in node pNode is guaranteed to have a 64-bit +** integer value equal to iRowid. Return the index of this cell. */ -#ifndef SQLITE_AMALGAMATION - -static const unsigned char sqlite3Utf8Trans1[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, -}; - -#define READ_UTF8(zIn, zTerm, c) \ - c = *(zIn++); \ - if( c>=0xc0 ){ \ - c = sqlite3Utf8Trans1[c-0xc0]; \ - while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ - c = (c<<6) + (0x3f & *(zIn++)); \ - } \ - if( c<0x80 \ - || (c&0xFFFFF800)==0xD800 \ - || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ +static int nodeRowidIndex( + Rtree *pRtree, + RtreeNode *pNode, + i64 iRowid, + int *piIndex +){ + int ii; + int nCell = NCELL(pNode); + assert( nCell<200 ); + for(ii=0; ii>6)&0x1F); \ - *zOut++ = 0x80 + (u8)(c & 0x3F); \ - } \ - else if( c<0x10000 ){ \ - *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); \ - *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ - *zOut++ = 0x80 + (u8)(c & 0x3F); \ - }else{ \ - *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); \ - *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); \ - *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); \ - *zOut++ = 0x80 + (u8)(c & 0x3F); \ - } \ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; } -#endif /* ifndef SQLITE_AMALGAMATION */ - -typedef struct unicode_tokenizer unicode_tokenizer; -typedef struct unicode_cursor unicode_cursor; - -struct unicode_tokenizer { - sqlite3_tokenizer base; - int bRemoveDiacritic; - int nException; - int *aiException; -}; - -struct unicode_cursor { - sqlite3_tokenizer_cursor base; - const unsigned char *aInput; /* Input text being tokenized */ - int nInput; /* Size of aInput[] in bytes */ - int iOff; /* Current offset within aInput[] */ - int iToken; /* Index of next token to be returned */ - char *zToken; /* storage for current token */ - int nAlloc; /* space allocated at zToken */ -}; - - /* -** Destroy a tokenizer allocated by unicodeCreate(). +** Return the index of the cell containing a pointer to node pNode +** in its parent. If pNode is the root node, return -1. */ -static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){ - if( pTokenizer ){ - unicode_tokenizer *p = (unicode_tokenizer *)pTokenizer; - sqlite3_free(p->aiException); - sqlite3_free(p); +static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){ + RtreeNode *pParent = pNode->pParent; + if( ALWAYS(pParent) ){ + return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); + }else{ + *piIndex = -1; + return SQLITE_OK; } - return SQLITE_OK; } /* -** As part of a tokenchars= or separators= option, the CREATE VIRTUAL TABLE -** statement has specified that the tokenizer for this table shall consider -** all characters in string zIn/nIn to be separators (if bAlnum==0) or -** token characters (if bAlnum==1). -** -** For each codepoint in the zIn/nIn string, this function checks if the -** sqlite3FtsUnicodeIsalnum() function already returns the desired result. -** If so, no action is taken. Otherwise, the codepoint is added to the -** unicode_tokenizer.aiException[] array. For the purposes of tokenization, -** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all -** codepoints in the aiException[] array. +** Compare two search points. Return negative, zero, or positive if the first +** is less than, equal to, or greater than the second. ** -** If a standalone diacritic mark (one that sqlite3FtsUnicodeIsdiacritic() -** identifies as a diacritic) occurs in the zIn/nIn string it is ignored. -** It is not possible to change the behavior of the tokenizer with respect -** to these codepoints. +** The rScore is the primary key. Smaller rScore values come first. +** If the rScore is a tie, then use iLevel as the tie breaker with smaller +** iLevel values coming first. In this way, if rScore is the same for all +** SearchPoints, then iLevel becomes the deciding factor and the result +** is a depth-first search, which is the desired default behavior. */ -static int unicodeAddExceptions( - unicode_tokenizer *p, /* Tokenizer to add exceptions to */ - int bAlnum, /* Replace Isalnum() return value with this */ - const char *zIn, /* Array of characters to make exceptions */ - int nIn /* Length of z in bytes */ +static int rtreeSearchPointCompare( + const RtreeSearchPoint *pA, + const RtreeSearchPoint *pB ){ - const unsigned char *z = (const unsigned char *)zIn; - const unsigned char *zTerm = &z[nIn]; - int iCode; - int nEntry = 0; - - assert( bAlnum==0 || bAlnum==1 ); - - while( zaiException, (p->nException+nEntry)*sizeof(int)); - if( aNew==0 ) return SQLITE_NOMEM; - nNew = p->nException; - - z = (const unsigned char *)zIn; - while( zi; j--) aNew[j] = aNew[j-1]; - aNew[i] = iCode; - nNew++; - } - } - p->aiException = aNew; - p->nException = nNew; - } - - return SQLITE_OK; + if( pA->rScorerScore ) return -1; + if( pA->rScore>pB->rScore ) return +1; + if( pA->iLeveliLevel ) return -1; + if( pA->iLevel>pB->iLevel ) return +1; + return 0; } /* -** Return true if the p->aiException[] array contains the value iCode. +** Interchange two search points in a cursor. */ -static int unicodeIsException(unicode_tokenizer *p, int iCode){ - if( p->nException>0 ){ - int *a = p->aiException; - int iLo = 0; - int iHi = p->nException-1; - - while( iHi>=iLo ){ - int iTest = (iHi + iLo) / 2; - if( iCode==a[iTest] ){ - return 1; - }else if( iCode>a[iTest] ){ - iLo = iTest+1; - }else{ - iHi = iTest-1; - } +static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ + RtreeSearchPoint t = p->aPoint[i]; + assert( iaPoint[i] = p->aPoint[j]; + p->aPoint[j] = t; + i++; j++; + if( i=RTREE_CACHE_SZ ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + }else{ + RtreeNode *pTemp = p->aNode[i]; + p->aNode[i] = p->aNode[j]; + p->aNode[j] = pTemp; } } +} - return 0; +/* +** Return the search point with the lowest current score. +*/ +static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){ + return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0; } /* -** Return true if, for the purposes of tokenization, codepoint iCode is -** considered a token character (not a separator). +** Get the RtreeNode for the search point with the lowest score. */ -static int unicodeIsAlnum(unicode_tokenizer *p, int iCode){ - assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 ); - return sqlite3FtsUnicodeIsalnum(iCode) ^ unicodeIsException(p, iCode); +static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){ + sqlite3_int64 id; + int ii = 1 - pCur->bPoint; + assert( ii==0 || ii==1 ); + assert( pCur->bPoint || pCur->nPoint ); + if( pCur->aNode[ii]==0 ){ + assert( pRC!=0 ); + id = ii ? pCur->aPoint[0].id : pCur->sPoint.id; + *pRC = nodeAcquire(RTREE_OF_CURSOR(pCur), id, 0, &pCur->aNode[ii]); + } + return pCur->aNode[ii]; } /* -** Create a new tokenizer instance. +** Push a new element onto the priority queue */ -static int unicodeCreate( - int nArg, /* Size of array argv[] */ - const char * const *azArg, /* Tokenizer creation arguments */ - sqlite3_tokenizer **pp /* OUT: New tokenizer handle */ +static RtreeSearchPoint *rtreeEnqueue( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ ){ - unicode_tokenizer *pNew; /* New tokenizer object */ - int i; - int rc = SQLITE_OK; - - pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer)); - if( pNew==NULL ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(unicode_tokenizer)); - pNew->bRemoveDiacritic = 1; - - for(i=0; rc==SQLITE_OK && ibRemoveDiacritic = 1; - } - else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){ - pNew->bRemoveDiacritic = 0; - } - else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){ - rc = unicodeAddExceptions(pNew, 1, &z[11], n-11); - } - else if( n>=11 && memcmp("separators=", z, 11)==0 ){ - rc = unicodeAddExceptions(pNew, 0, &z[11], n-11); - } - else{ - /* Unrecognized argument */ - rc = SQLITE_ERROR; - } + int i, j; + RtreeSearchPoint *pNew; + if( pCur->nPoint>=pCur->nPointAlloc ){ + int nNew = pCur->nPointAlloc*2 + 8; + pNew = sqlite3_realloc64(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); + if( pNew==0 ) return 0; + pCur->aPoint = pNew; + pCur->nPointAlloc = nNew; } - - if( rc!=SQLITE_OK ){ - unicodeDestroy((sqlite3_tokenizer *)pNew); - pNew = 0; + i = pCur->nPoint++; + pNew = pCur->aPoint + i; + pNew->rScore = rScore; + pNew->iLevel = iLevel; + assert( iLevel<=RTREE_MAX_DEPTH ); + while( i>0 ){ + RtreeSearchPoint *pParent; + j = (i-1)/2; + pParent = pCur->aPoint + j; + if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; + rtreeSearchPointSwap(pCur, j, i); + i = j; + pNew = pParent; } - *pp = (sqlite3_tokenizer *)pNew; - return rc; + return pNew; } /* -** Prepare to begin tokenizing a particular string. The input -** string to be tokenized is pInput[0..nBytes-1]. A cursor -** used to incrementally tokenize this string is returned in -** *ppCursor. +** Allocate a new RtreeSearchPoint and return a pointer to it. Return +** NULL if malloc fails. */ -static int unicodeOpen( - sqlite3_tokenizer *p, /* The tokenizer */ - const char *aInput, /* Input string */ - int nInput, /* Size of string aInput in bytes */ - sqlite3_tokenizer_cursor **pp /* OUT: New cursor object */ +static RtreeSearchPoint *rtreeSearchPointNew( + RtreeCursor *pCur, /* The cursor */ + RtreeDValue rScore, /* Score for the new search point */ + u8 iLevel /* Level for the new search point */ ){ - unicode_cursor *pCsr; - - pCsr = (unicode_cursor *)sqlite3_malloc(sizeof(unicode_cursor)); - if( pCsr==0 ){ - return SQLITE_NOMEM; + RtreeSearchPoint *pNew, *pFirst; + pFirst = rtreeSearchPointFirst(pCur); + pCur->anQueue[iLevel]++; + if( pFirst==0 + || pFirst->rScore>rScore + || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) + ){ + if( pCur->bPoint ){ + int ii; + pNew = rtreeEnqueue(pCur, rScore, iLevel); + if( pNew==0 ) return 0; + ii = (int)(pNew - pCur->aPoint) + 1; + assert( ii==1 ); + if( ALWAYS(iiaNode[ii]==0 ); + pCur->aNode[ii] = pCur->aNode[0]; + }else{ + nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); + } + pCur->aNode[0] = 0; + *pNew = pCur->sPoint; + } + pCur->sPoint.rScore = rScore; + pCur->sPoint.iLevel = iLevel; + pCur->bPoint = 1; + return &pCur->sPoint; + }else{ + return rtreeEnqueue(pCur, rScore, iLevel); } - memset(pCsr, 0, sizeof(unicode_cursor)); +} - pCsr->aInput = (const unsigned char *)aInput; - if( aInput==0 ){ - pCsr->nInput = 0; - }else if( nInput<0 ){ - pCsr->nInput = (int)strlen(aInput); +#if 0 +/* Tracing routines for the RtreeSearchPoint queue */ +static void tracePoint(RtreeSearchPoint *p, int idx, RtreeCursor *pCur){ + if( idx<0 ){ printf(" s"); }else{ printf("%2d", idx); } + printf(" %d.%05lld.%02d %g %d", + p->iLevel, p->id, p->iCell, p->rScore, p->eWithin + ); + idx++; + if( idxaNode[idx]); }else{ - pCsr->nInput = nInput; + printf("\n"); + } +} +static void traceQueue(RtreeCursor *pCur, const char *zPrefix){ + int ii; + printf("=== %9s ", zPrefix); + if( pCur->bPoint ){ + tracePoint(&pCur->sPoint, -1, pCur); + } + for(ii=0; iinPoint; ii++){ + if( ii>0 || pCur->bPoint ) printf(" "); + tracePoint(&pCur->aPoint[ii], ii, pCur); } - - *pp = &pCsr->base; - UNUSED_PARAMETER(p); - return SQLITE_OK; } +# define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B) +#else +# define RTREE_QUEUE_TRACE(A,B) /* no-op */ +#endif -/* -** Close a tokenization cursor previously opened by a call to -** simpleOpen() above. +/* Remove the search point with the lowest current score. */ -static int unicodeClose(sqlite3_tokenizer_cursor *pCursor){ - unicode_cursor *pCsr = (unicode_cursor *) pCursor; - sqlite3_free(pCsr->zToken); - sqlite3_free(pCsr); - return SQLITE_OK; +static void rtreeSearchPointPop(RtreeCursor *p){ + int i, j, k, n; + i = 1 - p->bPoint; + assert( i==0 || i==1 ); + if( p->aNode[i] ){ + nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); + p->aNode[i] = 0; + } + if( p->bPoint ){ + p->anQueue[p->sPoint.iLevel]--; + p->bPoint = 0; + }else if( ALWAYS(p->nPoint) ){ + p->anQueue[p->aPoint[0].iLevel]--; + n = --p->nPoint; + p->aPoint[0] = p->aPoint[n]; + if( naNode[1] = p->aNode[n+1]; + p->aNode[n+1] = 0; + } + i = 0; + while( (j = i*2+1)aPoint[k], &p->aPoint[j])<0 ){ + if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, k); + i = k; + }else{ + break; + } + }else{ + if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){ + rtreeSearchPointSwap(p, i, j); + i = j; + }else{ + break; + } + } + } + } } + /* -** Extract the next token from a tokenization cursor. The cursor must -** have been opened by a prior call to simpleOpen(). +** Continue the search on cursor pCur until the front of the queue +** contains an entry suitable for returning as a result-set row, +** or until the RtreeSearchPoint queue is empty, indicating that the +** query has completed. */ -static int unicodeNext( - sqlite3_tokenizer_cursor *pC, /* Cursor returned by simpleOpen */ - const char **paToken, /* OUT: Token text */ - int *pnToken, /* OUT: Number of bytes at *paToken */ - int *piStart, /* OUT: Starting offset of token */ - int *piEnd, /* OUT: Ending offset of token */ - int *piPos /* OUT: Position integer of token */ -){ - unicode_cursor *pCsr = (unicode_cursor *)pC; - unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer); - int iCode = 0; - char *zOut; - const unsigned char *z = &pCsr->aInput[pCsr->iOff]; - const unsigned char *zStart = z; - const unsigned char *zEnd; - const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput]; - - /* Scan past any delimiter characters before the start of the next token. - ** Return SQLITE_DONE early if this takes us all the way to the end of - ** the input. */ - while( z=zTerm ) return SQLITE_DONE; - - zOut = pCsr->zToken; - do { - int iOut; +static int rtreeStepToLeaf(RtreeCursor *pCur){ + RtreeSearchPoint *p; + Rtree *pRtree = RTREE_OF_CURSOR(pCur); + RtreeNode *pNode; + int eWithin; + int rc = SQLITE_OK; + int nCell; + int nConstraint = pCur->nConstraint; + int ii; + int eInt; + RtreeSearchPoint x; - /* Grow the output buffer if required. */ - if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){ - char *zNew = sqlite3_realloc(pCsr->zToken, pCsr->nAlloc+64); - if( !zNew ) return SQLITE_NOMEM; - zOut = &zNew[zOut - pCsr->zToken]; - pCsr->zToken = zNew; - pCsr->nAlloc += 64; + eInt = pRtree->eCoordType==RTREE_COORD_INT32; + while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ + u8 *pCellData; + pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); + if( rc ) return rc; + nCell = NCELL(pNode); + assert( nCell<200 ); + pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell); + while( p->iCellaConstraint + ii; + if( pConstraint->op>=RTREE_MATCH ){ + rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, + &rScore, &eWithin); + if( rc ) return rc; + }else if( p->iLevel==1 ){ + rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); + }else{ + rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); + } + if( eWithin==NOT_WITHIN ){ + p->iCell++; + pCellData += pRtree->nBytesPerCell; + break; + } + } + if( eWithin==NOT_WITHIN ) continue; + p->iCell++; + x.iLevel = p->iLevel - 1; + if( x.iLevel ){ + x.id = readInt64(pCellData); + for(ii=0; iinPoint; ii++){ + if( pCur->aPoint[ii].id==x.id ){ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; + } + } + x.iCell = 0; + }else{ + x.id = p->id; + x.iCell = p->iCell - 1; + } + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-S:"); + rtreeSearchPointPop(pCur); + } + if( rScoreeWithin = (u8)eWithin; + p->id = x.id; + p->iCell = x.iCell; + RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); + break; } - - /* Write the folded case of the last character read to the output */ - zEnd = z; - iOut = sqlite3FtsUnicodeFold(iCode, p->bRemoveDiacritic); - if( iOut ){ - WRITE_UTF8(zOut, iOut); + if( p->iCell>=nCell ){ + RTREE_QUEUE_TRACE(pCur, "POP-Se:"); + rtreeSearchPointPop(pCur); } - - /* If the cursor is not at EOF, read the next character */ - if( z>=zTerm ) break; - READ_UTF8(z, zTerm, iCode); - }while( unicodeIsAlnum(p, iCode) - || sqlite3FtsUnicodeIsdiacritic(iCode) - ); - - /* Set the output variables and return. */ - pCsr->iOff = (int)(z - pCsr->aInput); - *paToken = pCsr->zToken; - *pnToken = (int)(zOut - pCsr->zToken); - *piStart = (int)(zStart - pCsr->aInput); - *piEnd = (int)(zEnd - pCsr->aInput); - *piPos = pCsr->iToken++; + } + pCur->atEOF = p==0; return SQLITE_OK; } /* -** Set *ppModule to a pointer to the sqlite3_tokenizer_module -** structure for the unicode tokenizer. +** Rtree virtual table module xNext method. */ -SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){ - static const sqlite3_tokenizer_module module = { - 0, - unicodeCreate, - unicodeDestroy, - unicodeOpen, - unicodeClose, - unicodeNext, - 0, - }; - *ppModule = &module; -} - -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ -#endif /* ifndef SQLITE_DISABLE_FTS3_UNICODE */ +static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + int rc = SQLITE_OK; -/************** End of fts3_unicode.c ****************************************/ -/************** Begin file fts3_unicode2.c ***********************************/ -/* -** 2012 May 25 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -*/ + /* Move to the next entry that matches the configured constraints. */ + RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); + if( pCsr->bAuxValid ){ + pCsr->bAuxValid = 0; + sqlite3_reset(pCsr->pReadAux); + } + rtreeSearchPointPop(pCsr); + rc = rtreeStepToLeaf(pCsr); + return rc; +} /* -** DO NOT EDIT THIS MACHINE GENERATED FILE. +** Rtree virtual table module xRowid method. */ - -#ifndef SQLITE_DISABLE_FTS3_UNICODE -#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) - -/* #include */ +static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + if( rc==SQLITE_OK && ALWAYS(p) ){ + *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); + } + return rc; +} /* -** Return true if the argument corresponds to a unicode codepoint -** classified as either a letter or a number. Otherwise false. -** -** The results are undefined if the value passed to this function -** is less than zero. +** Rtree virtual table module xColumn method. */ -SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){ - /* Each unsigned integer in the following array corresponds to a contiguous - ** range of unicode codepoints that are not either letters or numbers (i.e. - ** codepoints for which this function should return 0). - ** - ** The most significant 22 bits in each 32-bit value contain the first - ** codepoint in the range. The least significant 10 bits are used to store - ** the size of the range (always at least 1). In other words, the value - ** ((C<<22) + N) represents a range of N codepoints starting with codepoint - ** C. It is not possible to represent a range larger than 1023 codepoints - ** using this format. - */ - static const unsigned int aEntry[] = { - 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, - 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, - 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, - 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, - 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, - 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, - 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, - 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, - 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, - 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, - 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, - 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, - 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, - 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, - 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, - 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, - 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, - 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, - 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, - 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, - 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, - 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, - 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, - 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, - 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, - 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, - 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, - 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, - 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, - 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, - 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, - 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, - 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, - 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, - 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, - 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, - 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, - 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, - 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, - 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, - 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, - 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, - 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, - 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, - 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, - 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, - 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, - 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, - 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, - 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, - 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, - 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, - 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, - 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, - 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, - 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, - 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, - 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, - 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, - 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, - 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, - 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, - 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, - 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, - 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, - 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, - 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, - 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, - 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, - 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, - 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, - 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, - 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, - 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, - 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, - 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, - 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, - 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, - 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, - 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, - 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, - 0x380400F0, - }; - static const unsigned int aAscii[4] = { - 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, - }; +static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ + Rtree *pRtree = (Rtree *)cur->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)cur; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + RtreeCoord c; + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); - if( c<128 ){ - return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); - }else if( c<(1<<22) ){ - unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; - int iRes = 0; - int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; - int iLo = 0; - while( iHi>=iLo ){ - int iTest = (iHi + iLo) / 2; - if( key >= aEntry[iTest] ){ - iRes = iTest; - iLo = iTest+1; + if( rc ) return rc; + if( NEVER(p==0) ) return SQLITE_OK; + if( i==0 ){ + sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); + }else if( i<=pRtree->nDim2 ){ + nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + sqlite3_result_double(ctx, c.f); + }else +#endif + { + assert( pRtree->eCoordType==RTREE_COORD_INT32 ); + sqlite3_result_int(ctx, c.i); + } + }else{ + if( !pCsr->bAuxValid ){ + if( pCsr->pReadAux==0 ){ + rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, + &pCsr->pReadAux, 0); + if( rc ) return rc; + } + sqlite3_bind_int64(pCsr->pReadAux, 1, + nodeGetRowid(pRtree, pNode, p->iCell)); + rc = sqlite3_step(pCsr->pReadAux); + if( rc==SQLITE_ROW ){ + pCsr->bAuxValid = 1; }else{ - iHi = iTest-1; + sqlite3_reset(pCsr->pReadAux); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; } } - assert( aEntry[0]=aEntry[iRes] ); - return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); + sqlite3_result_value(ctx, + sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1)); } - return 1; + return SQLITE_OK; } - /* -** If the argument is a codepoint corresponding to a lowercase letter -** in the ASCII range with a diacritic added, return the codepoint -** of the ASCII letter only. For example, if passed 235 - "LATIN -** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER -** E"). The resuls of passing a codepoint that corresponds to an -** uppercase letter are undefined. +** Use nodeAcquire() to obtain the leaf node containing the record with +** rowid iRowid. If successful, set *ppLeaf to point to the node and +** return SQLITE_OK. If there is no such record in the table, set +** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf +** to zero and return an SQLite error code. */ -static int remove_diacritic(int c){ - unsigned short aDia[] = { - 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, - 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, - 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, - 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, - 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, - 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, - 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, - 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, - 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, - 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, - 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, - 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, - 62924, 63050, 63082, 63274, 63390, - }; - char aChar[] = { - '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', - 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', - 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', - 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', - 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', - 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', - 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', - 'e', 'i', 'o', 'u', 'y', - }; - - unsigned int key = (((unsigned int)c)<<3) | 0x00000007; - int iRes = 0; - int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1; - int iLo = 0; - while( iHi>=iLo ){ - int iTest = (iHi + iLo) / 2; - if( key >= aDia[iTest] ){ - iRes = iTest; - iLo = iTest+1; - }else{ - iHi = iTest-1; - } +static int findLeafNode( + Rtree *pRtree, /* RTree to search */ + i64 iRowid, /* The rowid searching for */ + RtreeNode **ppLeaf, /* Write the node here */ + sqlite3_int64 *piNode /* Write the node-id here */ +){ + int rc; + *ppLeaf = 0; + sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); + if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ + i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); + if( piNode ) *piNode = iNode; + rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); + sqlite3_reset(pRtree->pReadRowid); + }else{ + rc = sqlite3_reset(pRtree->pReadRowid); } - assert( key>=aDia[iRes] ); - return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); + return rc; } - /* -** Return true if the argument interpreted as a unicode codepoint -** is a diacritical modifier character. +** This function is called to configure the RtreeConstraint object passed +** as the second argument for a MATCH constraint. The value passed as the +** first argument to this function is the right-hand operand to the MATCH +** operator. */ -SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){ - unsigned int mask0 = 0x08029FDF; - unsigned int mask1 = 0x000361F8; - if( c<768 || c>817 ) return 0; - return (c < 768+32) ? - (mask0 & (1 << (c-768))) : - (mask1 & (1 << (c-768-32))); +static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ + RtreeMatchArg *pBlob, *pSrc; /* BLOB returned by geometry function */ + sqlite3_rtree_query_info *pInfo; /* Callback information */ + + pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg"); + if( pSrc==0 ) return SQLITE_ERROR; + pInfo = (sqlite3_rtree_query_info*) + sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize ); + if( !pInfo ) return SQLITE_NOMEM; + memset(pInfo, 0, sizeof(*pInfo)); + pBlob = (RtreeMatchArg*)&pInfo[1]; + memcpy(pBlob, pSrc, pSrc->iSize); + pInfo->pContext = pBlob->cb.pContext; + pInfo->nParam = pBlob->nParam; + pInfo->aParam = pBlob->aParam; + pInfo->apSqlParam = pBlob->apSqlParam; + + if( pBlob->cb.xGeom ){ + pCons->u.xGeom = pBlob->cb.xGeom; + }else{ + pCons->op = RTREE_QUERY; + pCons->u.xQueryFunc = pBlob->cb.xQueryFunc; + } + pCons->pInfo = pInfo; + return SQLITE_OK; } - /* -** Interpret the argument as a unicode codepoint. If the codepoint -** is an upper case character that has a lower case equivalent, -** return the codepoint corresponding to the lower case version. -** Otherwise, return a copy of the argument. -** -** The results are undefined if the value passed to this function -** is less than zero. +** Rtree virtual table module xFilter method. */ -SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){ - /* Each entry in the following array defines a rule for folding a range - ** of codepoints to lower case. The rule applies to a range of nRange - ** codepoints starting at codepoint iCode. - ** - ** If the least significant bit in flags is clear, then the rule applies - ** to all nRange codepoints (i.e. all nRange codepoints are upper case and - ** need to be folded). Or, if it is set, then the rule only applies to - ** every second codepoint in the range, starting with codepoint C. - ** - ** The 7 most significant bits in flags are an index into the aiOff[] - ** array. If a specific codepoint C does require folding, then its lower - ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF). - ** - ** The contents of this array are generated by parsing the CaseFolding.txt - ** file distributed as part of the "Unicode Character Database". See - ** http://www.unicode.org for details. - */ - static const struct TableEntry { - unsigned short iCode; - unsigned char flags; - unsigned char nRange; - } aEntry[] = { - {65, 14, 26}, {181, 64, 1}, {192, 14, 23}, - {216, 14, 7}, {256, 1, 48}, {306, 1, 6}, - {313, 1, 16}, {330, 1, 46}, {376, 116, 1}, - {377, 1, 6}, {383, 104, 1}, {385, 50, 1}, - {386, 1, 4}, {390, 44, 1}, {391, 0, 1}, - {393, 42, 2}, {395, 0, 1}, {398, 32, 1}, - {399, 38, 1}, {400, 40, 1}, {401, 0, 1}, - {403, 42, 1}, {404, 46, 1}, {406, 52, 1}, - {407, 48, 1}, {408, 0, 1}, {412, 52, 1}, - {413, 54, 1}, {415, 56, 1}, {416, 1, 6}, - {422, 60, 1}, {423, 0, 1}, {425, 60, 1}, - {428, 0, 1}, {430, 60, 1}, {431, 0, 1}, - {433, 58, 2}, {435, 1, 4}, {439, 62, 1}, - {440, 0, 1}, {444, 0, 1}, {452, 2, 1}, - {453, 0, 1}, {455, 2, 1}, {456, 0, 1}, - {458, 2, 1}, {459, 1, 18}, {478, 1, 18}, - {497, 2, 1}, {498, 1, 4}, {502, 122, 1}, - {503, 134, 1}, {504, 1, 40}, {544, 110, 1}, - {546, 1, 18}, {570, 70, 1}, {571, 0, 1}, - {573, 108, 1}, {574, 68, 1}, {577, 0, 1}, - {579, 106, 1}, {580, 28, 1}, {581, 30, 1}, - {582, 1, 10}, {837, 36, 1}, {880, 1, 4}, - {886, 0, 1}, {902, 18, 1}, {904, 16, 3}, - {908, 26, 1}, {910, 24, 2}, {913, 14, 17}, - {931, 14, 9}, {962, 0, 1}, {975, 4, 1}, - {976, 140, 1}, {977, 142, 1}, {981, 146, 1}, - {982, 144, 1}, {984, 1, 24}, {1008, 136, 1}, - {1009, 138, 1}, {1012, 130, 1}, {1013, 128, 1}, - {1015, 0, 1}, {1017, 152, 1}, {1018, 0, 1}, - {1021, 110, 3}, {1024, 34, 16}, {1040, 14, 32}, - {1120, 1, 34}, {1162, 1, 54}, {1216, 6, 1}, - {1217, 1, 14}, {1232, 1, 88}, {1329, 22, 38}, - {4256, 66, 38}, {4295, 66, 1}, {4301, 66, 1}, - {7680, 1, 150}, {7835, 132, 1}, {7838, 96, 1}, - {7840, 1, 96}, {7944, 150, 8}, {7960, 150, 6}, - {7976, 150, 8}, {7992, 150, 8}, {8008, 150, 6}, - {8025, 151, 8}, {8040, 150, 8}, {8072, 150, 8}, - {8088, 150, 8}, {8104, 150, 8}, {8120, 150, 2}, - {8122, 126, 2}, {8124, 148, 1}, {8126, 100, 1}, - {8136, 124, 4}, {8140, 148, 1}, {8152, 150, 2}, - {8154, 120, 2}, {8168, 150, 2}, {8170, 118, 2}, - {8172, 152, 1}, {8184, 112, 2}, {8186, 114, 2}, - {8188, 148, 1}, {8486, 98, 1}, {8490, 92, 1}, - {8491, 94, 1}, {8498, 12, 1}, {8544, 8, 16}, - {8579, 0, 1}, {9398, 10, 26}, {11264, 22, 47}, - {11360, 0, 1}, {11362, 88, 1}, {11363, 102, 1}, - {11364, 90, 1}, {11367, 1, 6}, {11373, 84, 1}, - {11374, 86, 1}, {11375, 80, 1}, {11376, 82, 1}, - {11378, 0, 1}, {11381, 0, 1}, {11390, 78, 2}, - {11392, 1, 100}, {11499, 1, 4}, {11506, 0, 1}, - {42560, 1, 46}, {42624, 1, 24}, {42786, 1, 14}, - {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1}, - {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1}, - {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1}, - {65313, 14, 26}, - }; - static const unsigned short aiOff[] = { - 1, 2, 8, 15, 16, 26, 28, 32, - 37, 38, 40, 48, 63, 64, 69, 71, - 79, 80, 116, 202, 203, 205, 206, 207, - 209, 210, 211, 213, 214, 217, 218, 219, - 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, - 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, - 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, - 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, - 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, - 65514, 65521, 65527, 65528, 65529, - }; - - int ret = c; +static int rtreeFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeNode *pRoot = 0; + int ii; + int rc = SQLITE_OK; + int iCell = 0; - assert( c>=0 ); - assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 ); + rtreeReference(pRtree); - if( c<128 ){ - if( c>='A' && c<='Z' ) ret = c + ('a' - 'A'); - }else if( c<65536 ){ - int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; - int iLo = 0; - int iRes = -1; + /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ + resetCursor(pCsr); - while( iHi>=iLo ){ - int iTest = (iHi + iLo) / 2; - int cmp = (c - aEntry[iTest].iCode); - if( cmp>=0 ){ - iRes = iTest; - iLo = iTest+1; + pCsr->iStrategy = idxNum; + if( idxNum==1 ){ + /* Special case - lookup by rowid. */ + RtreeNode *pLeaf; /* Leaf on which the required cell resides */ + RtreeSearchPoint *p; /* Search point for the leaf */ + i64 iRowid = sqlite3_value_int64(argv[0]); + i64 iNode = 0; + int eType = sqlite3_value_numeric_type(argv[0]); + if( eType==SQLITE_INTEGER + || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid) + ){ + rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); + }else{ + rc = SQLITE_OK; + pLeaf = 0; + } + if( rc==SQLITE_OK && pLeaf!=0 ){ + p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); + assert( p!=0 ); /* Always returns pCsr->sPoint */ + pCsr->aNode[0] = pLeaf; + p->id = iNode; + p->eWithin = PARTLY_WITHIN; + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); + p->iCell = (u8)iCell; + RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); + }else{ + pCsr->atEOF = 1; + } + }else{ + /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array + ** with the configured constraints. + */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + if( rc==SQLITE_OK && argc>0 ){ + pCsr->aConstraint = sqlite3_malloc64(sizeof(RtreeConstraint)*argc); + pCsr->nConstraint = argc; + if( !pCsr->aConstraint ){ + rc = SQLITE_NOMEM; }else{ - iHi = iTest-1; + memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); + memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); + assert( (idxStr==0 && argc==0) + || (idxStr && (int)strlen(idxStr)==argc*2) ); + for(ii=0; iiaConstraint[ii]; + int eType = sqlite3_value_numeric_type(argv[ii]); + p->op = idxStr[ii*2]; + p->iCoord = idxStr[ii*2+1]-'0'; + if( p->op>=RTREE_MATCH ){ + /* A MATCH operator. The right-hand-side must be a blob that + ** can be cast into an RtreeMatchArg object. One created using + ** an sqlite3_rtree_geometry_callback() SQL user function. + */ + rc = deserializeGeometry(argv[ii], p); + if( rc!=SQLITE_OK ){ + break; + } + p->pInfo->nCoord = pRtree->nDim2; + p->pInfo->anQueue = pCsr->anQueue; + p->pInfo->mxLevel = pRtree->iDepth + 1; + }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ +#ifdef SQLITE_RTREE_INT_ONLY + p->u.rValue = sqlite3_value_int64(argv[ii]); +#else + p->u.rValue = sqlite3_value_double(argv[ii]); +#endif + }else{ + p->u.rValue = RTREE_ZERO; + if( eType==SQLITE_NULL ){ + p->op = RTREE_FALSE; + }else if( p->op==RTREE_LT || p->op==RTREE_LE ){ + p->op = RTREE_TRUE; + }else{ + p->op = RTREE_FALSE; + } + } + } } } - assert( iRes<0 || c>=aEntry[iRes].iCode ); - - if( iRes>=0 ){ - const struct TableEntry *p = &aEntry[iRes]; - if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){ - ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF; - assert( ret>0 ); + if( rc==SQLITE_OK ){ + RtreeSearchPoint *pNew; + assert( pCsr->bPoint==0 ); /* Due to the resetCursor() call above */ + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); + if( NEVER(pNew==0) ){ /* Because pCsr->bPoint was FALSE */ + return SQLITE_NOMEM; } + pNew->id = 1; + pNew->iCell = 0; + pNew->eWithin = PARTLY_WITHIN; + assert( pCsr->bPoint==1 ); + pCsr->aNode[0] = pRoot; + pRoot = 0; + RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); + rc = rtreeStepToLeaf(pCsr); } - - if( bRemoveDiacritic ) ret = remove_diacritic(ret); - } - - else if( c>=66560 && c<66600 ){ - ret = c + 40; } - return ret; + nodeRelease(pRtree, pRoot); + rtreeRelease(pRtree); + return rc; } -#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */ -#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */ - -/************** End of fts3_unicode2.c ***************************************/ -/************** Begin file rtree.c *******************************************/ -/* -** 2001 September 15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains code for implementations of the r-tree and r*-tree -** algorithms packaged as an SQLite virtual table module. -*/ /* -** Database Format of R-Tree Tables -** -------------------------------- -** -** The data structure for a single virtual r-tree table is stored in three -** native SQLite tables declared as follows. In each case, the '%' character -** in the table name is replaced with the user-supplied name of the r-tree -** table. -** -** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB) -** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) -** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER) +** Rtree virtual table module xBestIndex method. There are three +** table scan strategies to choose from (in order from most to +** least desirable): ** -** The data for each node of the r-tree structure is stored in the %_node -** table. For each node that is not the root node of the r-tree, there is -** an entry in the %_parent table associating the node with its parent. -** And for each row of data in the table, there is an entry in the %_rowid -** table that maps from the entries rowid to the id of the node that it -** is stored on. +** idxNum idxStr Strategy +** ------------------------------------------------ +** 1 Unused Direct lookup by rowid. +** 2 See below R-tree query or full-table scan. +** ------------------------------------------------ ** -** The root node of an r-tree always exists, even if the r-tree table is -** empty. The nodeno of the root node is always 1. All other nodes in the -** table must be the same size as the root node. The content of each node -** is formatted as follows: +** If strategy 1 is used, then idxStr is not meaningful. If strategy +** 2 is used, idxStr is formatted to contain 2 bytes for each +** constraint used. The first two bytes of idxStr correspond to +** the constraint in sqlite3_index_info.aConstraintUsage[] with +** (argvIndex==1) etc. ** -** 1. If the node is the root node (node 1), then the first 2 bytes -** of the node contain the tree depth as a big-endian integer. -** For non-root nodes, the first 2 bytes are left unused. +** The first of each pair of bytes in idxStr identifies the constraint +** operator as follows: ** -** 2. The next 2 bytes contain the number of entries currently -** stored in the node. +** Operator Byte Value +** ---------------------- +** = 0x41 ('A') +** <= 0x42 ('B') +** < 0x43 ('C') +** >= 0x44 ('D') +** > 0x45 ('E') +** MATCH 0x46 ('F') +** ---------------------- ** -** 3. The remainder of the node contains the node entries. Each entry -** consists of a single 8-byte integer followed by an even number -** of 4-byte coordinates. For leaf nodes the integer is the rowid -** of a record. For internal nodes it is the node number of a -** child page. -*/ - -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE) - -#ifndef SQLITE_CORE -/* #include "sqlite3ext.h" */ - SQLITE_EXTENSION_INIT1 -#else -/* #include "sqlite3.h" */ -#endif - -/* #include */ -/* #include */ -/* #include */ - -#ifndef SQLITE_AMALGAMATION -#include "sqlite3rtree.h" -typedef sqlite3_int64 i64; -typedef sqlite3_uint64 u64; -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -#endif - -/* The following macro is used to suppress compiler warnings. -*/ -#ifndef UNUSED_PARAMETER -# define UNUSED_PARAMETER(x) (void)(x) -#endif - -typedef struct Rtree Rtree; -typedef struct RtreeCursor RtreeCursor; -typedef struct RtreeNode RtreeNode; -typedef struct RtreeCell RtreeCell; -typedef struct RtreeConstraint RtreeConstraint; -typedef struct RtreeMatchArg RtreeMatchArg; -typedef struct RtreeGeomCallback RtreeGeomCallback; -typedef union RtreeCoord RtreeCoord; -typedef struct RtreeSearchPoint RtreeSearchPoint; - -/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ -#define RTREE_MAX_DIMENSIONS 5 - -/* Size of hash table Rtree.aHash. This hash table is not expected to -** ever contain very many entries, so a fixed number of buckets is -** used. +** The second of each pair of bytes identifies the coordinate column +** to which the constraint applies. The leftmost coordinate column +** is 'a', the second from the left 'b' etc. */ -#define HASHSIZE 97 +static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + Rtree *pRtree = (Rtree*)tab; + int rc = SQLITE_OK; + int ii; + int bMatch = 0; /* True if there exists a MATCH constraint */ + i64 nRow; /* Estimated rows returned by this scan */ -/* The xBestIndex method of this virtual table requires an estimate of -** the number of rows in the virtual table to calculate the costs of -** various strategies. If possible, this estimate is loaded from the -** sqlite_stat1 table (with RTREE_MIN_ROWEST as a hard-coded minimum). -** Otherwise, if no sqlite_stat1 entry is available, use -** RTREE_DEFAULT_ROWEST. -*/ -#define RTREE_DEFAULT_ROWEST 1048576 -#define RTREE_MIN_ROWEST 100 + int iIdx = 0; + char zIdxStr[RTREE_MAX_DIMENSIONS*8+1]; + memset(zIdxStr, 0, sizeof(zIdxStr)); -/* -** An rtree virtual-table object. -*/ -struct Rtree { - sqlite3_vtab base; /* Base class. Must be first */ - sqlite3 *db; /* Host database connection */ - int iNodeSize; /* Size in bytes of each node in the node table */ - u8 nDim; /* Number of dimensions */ - u8 nDim2; /* Twice the number of dimensions */ - u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ - u8 nBytesPerCell; /* Bytes consumed per cell */ - u8 inWrTrans; /* True if inside write transaction */ - int iDepth; /* Current depth of the r-tree structure */ - char *zDb; /* Name of database containing r-tree table */ - char *zName; /* Name of r-tree table */ - u32 nBusy; /* Current number of users of this structure */ - i64 nRowEst; /* Estimated number of rows in this table */ - u32 nCursor; /* Number of open cursors */ + /* Check if there exists a MATCH constraint - even an unusable one. If there + ** is, do not consider the lookup-by-rowid plan as using such a plan would + ** require the VDBE to evaluate the MATCH constraint, which is not currently + ** possible. */ + for(ii=0; iinConstraint; ii++){ + if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){ + bMatch = 1; + } + } - /* List of nodes removed during a CondenseTree operation. List is - ** linked together via the pointer normally used for hash chains - - ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree - ** headed by the node (leaf nodes have RtreeNode.iNode==0). - */ - RtreeNode *pDeleted; - int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */ + assert( pIdxInfo->idxStr==0 ); + for(ii=0; iinConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; - /* Blob I/O on xxx_node */ - sqlite3_blob *pNodeBlob; + if( bMatch==0 && p->usable + && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + /* We have an equality constraint on the rowid. Use strategy 1. */ + int jj; + for(jj=0; jjaConstraintUsage[jj].argvIndex = 0; + pIdxInfo->aConstraintUsage[jj].omit = 0; + } + pIdxInfo->idxNum = 1; + pIdxInfo->aConstraintUsage[ii].argvIndex = 1; + pIdxInfo->aConstraintUsage[jj].omit = 1; - /* Statements to read/write/delete a record from xxx_node */ - sqlite3_stmt *pWriteNode; - sqlite3_stmt *pDeleteNode; + /* This strategy involves a two rowid lookups on an B-Tree structures + ** and then a linear search of an R-Tree node. This should be + ** considered almost as quick as a direct rowid lookup (for which + ** sqlite uses an internal cost of 0.0). It is expected to return + ** a single row. + */ + pIdxInfo->estimatedCost = 30.0; + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + return SQLITE_OK; + } - /* Statements to read/write/delete a record from xxx_rowid */ - sqlite3_stmt *pReadRowid; - sqlite3_stmt *pWriteRowid; - sqlite3_stmt *pDeleteRowid; + if( p->usable + && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) + || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) + ){ + u8 op; + switch( p->op ){ + case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; + case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; + case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; + case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; + case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; + case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break; + default: op = 0; break; + } + if( op ){ + zIdxStr[iIdx++] = op; + zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); + pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); + pIdxInfo->aConstraintUsage[ii].omit = 1; + } + } + } - /* Statements to read/write/delete a record from xxx_parent */ - sqlite3_stmt *pReadParent; - sqlite3_stmt *pWriteParent; - sqlite3_stmt *pDeleteParent; + pIdxInfo->idxNum = 2; + pIdxInfo->needToFreeIdxStr = 1; + if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ + return SQLITE_NOMEM; + } - RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ -}; + nRow = pRtree->nRowEst >> (iIdx/2); + pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; + pIdxInfo->estimatedRows = nRow; -/* Possible values for Rtree.eCoordType: */ -#define RTREE_COORD_REAL32 0 -#define RTREE_COORD_INT32 1 + return rc; +} /* -** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will -** only deal with integer coordinates. No floating point operations -** will be done. +** Return the N-dimensional volumn of the cell stored in *p. */ -#ifdef SQLITE_RTREE_INT_ONLY - typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */ - typedef int RtreeValue; /* Low accuracy coordinate */ -# define RTREE_ZERO 0 -#else - typedef double RtreeDValue; /* High accuracy coordinate */ - typedef float RtreeValue; /* Low accuracy coordinate */ -# define RTREE_ZERO 0.0 +static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){ + RtreeDValue area = (RtreeDValue)1; + assert( pRtree->nDim>=1 && pRtree->nDim<=5 ); +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + switch( pRtree->nDim ){ + case 5: area = p->aCoord[9].f - p->aCoord[8].f; + case 4: area *= p->aCoord[7].f - p->aCoord[6].f; + case 3: area *= p->aCoord[5].f - p->aCoord[4].f; + case 2: area *= p->aCoord[3].f - p->aCoord[2].f; + default: area *= p->aCoord[1].f - p->aCoord[0].f; + } + }else #endif + { + switch( pRtree->nDim ){ + case 5: area = (i64)p->aCoord[9].i - (i64)p->aCoord[8].i; + case 4: area *= (i64)p->aCoord[7].i - (i64)p->aCoord[6].i; + case 3: area *= (i64)p->aCoord[5].i - (i64)p->aCoord[4].i; + case 2: area *= (i64)p->aCoord[3].i - (i64)p->aCoord[2].i; + default: area *= (i64)p->aCoord[1].i - (i64)p->aCoord[0].i; + } + } + return area; +} /* -** When doing a search of an r-tree, instances of the following structure -** record intermediate results from the tree walk. -** -** The id is always a node-id. For iLevel>=1 the id is the node-id of -** the node that the RtreeSearchPoint represents. When iLevel==0, however, -** the id is of the parent node and the cell that RtreeSearchPoint -** represents is the iCell-th entry in the parent node. +** Return the margin length of cell p. The margin length is the sum +** of the objects size in each dimension. */ -struct RtreeSearchPoint { - RtreeDValue rScore; /* The score for this node. Smallest goes first. */ - sqlite3_int64 id; /* Node ID */ - u8 iLevel; /* 0=entries. 1=leaf node. 2+ for higher */ - u8 eWithin; /* PARTLY_WITHIN or FULLY_WITHIN */ - u8 iCell; /* Cell index within the node */ -}; +static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){ + RtreeDValue margin = 0; + int ii = pRtree->nDim2 - 2; + do{ + margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); + ii -= 2; + }while( ii>=0 ); + return margin; +} /* -** The minimum number of cells allowed for a node is a third of the -** maximum. In Gutman's notation: -** -** m = M/3 -** -** If an R*-tree "Reinsert" operation is required, the same number of -** cells are removed from the overfull node and reinserted into the tree. +** Store the union of cells p1 and p2 in p1. */ -#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3) -#define RTREE_REINSERT(p) RTREE_MINCELLS(p) -#define RTREE_MAXCELLS 51 +static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ + int ii = 0; + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + do{ + p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f); + p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f); + ii += 2; + }while( iinDim2 ); + }else{ + do{ + p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i); + p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i); + ii += 2; + }while( iinDim2 ); + } +} /* -** The smallest possible node-size is (512-64)==448 bytes. And the largest -** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates). -** Therefore all non-root nodes must contain at least 3 entries. Since -** 2^40 is greater than 2^64, an r-tree structure always has a depth of -** 40 or less. +** Return true if the area covered by p2 is a subset of the area covered +** by p1. False otherwise. */ -#define RTREE_MAX_DEPTH 40 - +static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ + int ii; + int isInt = (pRtree->eCoordType==RTREE_COORD_INT32); + for(ii=0; iinDim2; ii+=2){ + RtreeCoord *a1 = &p1->aCoord[ii]; + RtreeCoord *a2 = &p2->aCoord[ii]; + if( (!isInt && (a2[0].fa1[1].f)) + || ( isInt && (a2[0].ia1[1].i)) + ){ + return 0; + } + } + return 1; +} /* -** Number of entries in the cursor RtreeNode cache. The first entry is -** used to cache the RtreeNode for RtreeCursor.sPoint. The remaining -** entries cache the RtreeNode for the first elements of the priority queue. -*/ -#define RTREE_CACHE_SZ 5 - -/* -** An rtree cursor object. +** Return the amount cell p would grow by if it were unioned with pCell. */ -struct RtreeCursor { - sqlite3_vtab_cursor base; /* Base class. Must be first */ - u8 atEOF; /* True if at end of search */ - u8 bPoint; /* True if sPoint is valid */ - int iStrategy; /* Copy of idxNum search parameter */ - int nConstraint; /* Number of entries in aConstraint */ - RtreeConstraint *aConstraint; /* Search constraints. */ - int nPointAlloc; /* Number of slots allocated for aPoint[] */ - int nPoint; /* Number of slots used in aPoint[] */ - int mxLevel; /* iLevel value for root of the tree */ - RtreeSearchPoint *aPoint; /* Priority queue for search points */ - RtreeSearchPoint sPoint; /* Cached next search point */ - RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ - u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ -}; +static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ + RtreeDValue area; + RtreeCell cell; + memcpy(&cell, p, sizeof(RtreeCell)); + area = cellArea(pRtree, &cell); + cellUnion(pRtree, &cell, pCell); + return (cellArea(pRtree, &cell)-area); +} -/* Return the Rtree of a RtreeCursor */ -#define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) +static RtreeDValue cellOverlap( + Rtree *pRtree, + RtreeCell *p, + RtreeCell *aCell, + int nCell +){ + int ii; + RtreeDValue overlap = RTREE_ZERO; + for(ii=0; iinDim2; jj+=2){ + RtreeDValue x1, x2; + x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); + x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); + if( x2eCoordType==RTREE_COORD_REAL32) ? \ - ((double)coord.f) : \ - ((double)coord.i) \ - ) -#endif +static int ChooseLeaf( + Rtree *pRtree, /* Rtree table */ + RtreeCell *pCell, /* Cell to insert into rtree */ + int iHeight, /* Height of sub-tree rooted at pCell */ + RtreeNode **ppLeaf /* OUT: Selected leaf page */ +){ + int rc; + int ii; + RtreeNode *pNode = 0; + rc = nodeAcquire(pRtree, 1, 0, &pNode); -/* -** A search constraint. -*/ -struct RtreeConstraint { - int iCoord; /* Index of constrained coordinate */ - int op; /* Constraining operation */ - union { - RtreeDValue rValue; /* Constraint value. */ - int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*); - int (*xQueryFunc)(sqlite3_rtree_query_info*); - } u; - sqlite3_rtree_query_info *pInfo; /* xGeom and xQueryFunc argument */ -}; + for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){ + int iCell; + sqlite3_int64 iBest = 0; -/* Possible values for RtreeConstraint.op */ -#define RTREE_EQ 0x41 /* A */ -#define RTREE_LE 0x42 /* B */ -#define RTREE_LT 0x43 /* C */ -#define RTREE_GE 0x44 /* D */ -#define RTREE_GT 0x45 /* E */ -#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */ -#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */ + RtreeDValue fMinGrowth = RTREE_ZERO; + RtreeDValue fMinArea = RTREE_ZERO; + int nCell = NCELL(pNode); + RtreeCell cell; + RtreeNode *pChild = 0; -/* -** An rtree structure node. -*/ -struct RtreeNode { - RtreeNode *pParent; /* Parent node */ - i64 iNode; /* The node number */ - int nRef; /* Number of references to this node */ - int isDirty; /* True if the node needs to be written to disk */ - u8 *zData; /* Content of the node, as should be on disk */ - RtreeNode *pNext; /* Next node in this hash collision chain */ -}; + RtreeCell *aCell = 0; -/* Return the number of cells in a node */ -#define NCELL(pNode) readInt16(&(pNode)->zData[2]) + /* Select the child node which will be enlarged the least if pCell + ** is inserted into it. Resolve ties by choosing the entry with + ** the smallest area. + */ + for(iCell=0; iCellpParent ){ + RtreeNode *pParent = p->pParent; + RtreeCell cell; + int iCell; + cnt++; + if( NEVER(cnt>100) ){ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; + } + rc = nodeParentIndex(pRtree, p, &iCell); + if( NEVER(rc!=SQLITE_OK) ){ + RTREE_IS_CORRUPT(pRtree); + return SQLITE_CORRUPT_VTAB; + } + + nodeGetCell(pRtree, pParent, iCell, &cell); + if( !cellContains(pRtree, &cell, pCell) ){ + cellUnion(pRtree, &cell, pCell); + nodeOverwriteCell(pRtree, pParent, &cell, iCell); + } + + p = pParent; + } + return SQLITE_OK; +} /* -** Value for the first field of every RtreeMatchArg object. The MATCH -** operator tests that the first field of a blob operand matches this -** value to avoid operating on invalid blobs (which could cause a segfault). +** Write mapping (iRowid->iNode) to the _rowid table. */ -#define RTREE_GEOMETRY_MAGIC 0x891245AB +static int rowidWrite(Rtree *pRtree, sqlite3_int64 iRowid, sqlite3_int64 iNode){ + sqlite3_bind_int64(pRtree->pWriteRowid, 1, iRowid); + sqlite3_bind_int64(pRtree->pWriteRowid, 2, iNode); + sqlite3_step(pRtree->pWriteRowid); + return sqlite3_reset(pRtree->pWriteRowid); +} /* -** An instance of this structure (in the form of a BLOB) is returned by -** the SQL functions that sqlite3_rtree_geometry_callback() and -** sqlite3_rtree_query_callback() create, and is read as the right-hand -** operand to the MATCH operator of an R-Tree. +** Write mapping (iNode->iPar) to the _parent table. */ -struct RtreeMatchArg { - u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ - RtreeGeomCallback cb; /* Info about the callback functions */ - int nParam; /* Number of parameters to the SQL function */ - sqlite3_value **apSqlParam; /* Original SQL parameter values */ - RtreeDValue aParam[1]; /* Values for parameters to the SQL function */ -}; - -#ifndef MAX -# define MAX(x,y) ((x) < (y) ? (y) : (x)) -#endif -#ifndef MIN -# define MIN(x,y) ((x) > (y) ? (y) : (x)) -#endif - -/* What version of GCC is being used. 0 means GCC is not being used */ -#ifndef GCC_VERSION -#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) -# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) -#else -# define GCC_VERSION 0 -#endif -#endif +static int parentWrite(Rtree *pRtree, sqlite3_int64 iNode, sqlite3_int64 iPar){ + sqlite3_bind_int64(pRtree->pWriteParent, 1, iNode); + sqlite3_bind_int64(pRtree->pWriteParent, 2, iPar); + sqlite3_step(pRtree->pWriteParent); + return sqlite3_reset(pRtree->pWriteParent); +} -/* What version of CLANG is being used. 0 means CLANG is not being used */ -#ifndef CLANG_VERSION -#if defined(__clang__) && !defined(_WIN32) && !defined(SQLITE_DISABLE_INTRINSIC) -# define CLANG_VERSION \ - (__clang_major__*1000000+__clang_minor__*1000+__clang_patchlevel__) -#else -# define CLANG_VERSION 0 -#endif -#endif +static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int); -/* The testcase() macro should already be defined in the amalgamation. If -** it is not, make it a no-op. -*/ -#ifndef SQLITE_AMALGAMATION -# define testcase(X) -#endif /* -** Macros to determine whether the machine is big or little endian, -** and whether or not that determination is run-time or compile-time. +** Arguments aIdx, aDistance and aSpare all point to arrays of size +** nIdx. The aIdx array contains the set of integers from 0 to +** (nIdx-1) in no particular order. This function sorts the values +** in aIdx according to the indexed values in aDistance. For +** example, assuming the inputs: ** -** For best performance, an attempt is made to guess at the byte-order -** using C-preprocessor macros. If that is unsuccessful, or if -** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined -** at run-time. +** aIdx = { 0, 1, 2, 3 } +** aDistance = { 5.0, 2.0, 7.0, 6.0 } +** +** this function sets the aIdx array to contain: +** +** aIdx = { 0, 1, 2, 3 } +** +** The aSpare array is used as temporary working space by the +** sorting algorithm. */ -#ifndef SQLITE_BYTEORDER -#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) -# define SQLITE_BYTEORDER 1234 -#elif defined(sparc) || defined(__ppc__) -# define SQLITE_BYTEORDER 4321 -#else -# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */ -#endif -#endif +static void SortByDistance( + int *aIdx, + int nIdx, + RtreeDValue *aDistance, + int *aSpare +){ + if( nIdx>1 ){ + int iLeft = 0; + int iRight = 0; + int nLeft = nIdx/2; + int nRight = nIdx-nLeft; + int *aLeft = aIdx; + int *aRight = &aIdx[nLeft]; -/* What version of MSVC is being used. 0 means MSVC is not being used */ -#ifndef MSVC_VERSION -#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) -# define MSVC_VERSION _MSC_VER -#else -# define MSVC_VERSION 0 -#endif -#endif + SortByDistance(aLeft, nLeft, aDistance, aSpare); + SortByDistance(aRight, nRight, aDistance, aSpare); -/* -** Functions to deserialize a 16 bit integer, 32 bit real number and -** 64 bit integer. The deserialized value is returned. -*/ -static int readInt16(u8 *p){ - return (p[0]<<8) + p[1]; -} -static void readCoord(u8 *p, RtreeCoord *pCoord){ - assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ -#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 - pCoord->u = _byteswap_ulong(*(u32*)p); -#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) - pCoord->u = __builtin_bswap32(*(u32*)p); -#elif SQLITE_BYTEORDER==4321 - pCoord->u = *(u32*)p; -#else - pCoord->u = ( - (((u32)p[0]) << 24) + - (((u32)p[1]) << 16) + - (((u32)p[2]) << 8) + - (((u32)p[3]) << 0) - ); -#endif -} -static i64 readInt64(u8 *p){ -#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 - u64 x; - memcpy(&x, p, 8); - return (i64)_byteswap_uint64(x); -#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) - u64 x; - memcpy(&x, p, 8); - return (i64)__builtin_bswap64(x); -#elif SQLITE_BYTEORDER==4321 - i64 x; - memcpy(&x, p, 8); - return x; -#else - return ( - (((i64)p[0]) << 56) + - (((i64)p[1]) << 48) + - (((i64)p[2]) << 40) + - (((i64)p[3]) << 32) + - (((i64)p[4]) << 24) + - (((i64)p[5]) << 16) + - (((i64)p[6]) << 8) + - (((i64)p[7]) << 0) - ); -#endif -} + memcpy(aSpare, aLeft, sizeof(int)*nLeft); + aLeft = aSpare; -/* -** Functions to serialize a 16 bit integer, 32 bit real number and -** 64 bit integer. The value returned is the number of bytes written -** to the argument buffer (always 2, 4 and 8 respectively). -*/ -static void writeInt16(u8 *p, int i){ - p[0] = (i>> 8)&0xFF; - p[1] = (i>> 0)&0xFF; -} -static int writeCoord(u8 *p, RtreeCoord *pCoord){ - u32 i; - assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ - assert( sizeof(RtreeCoord)==4 ); - assert( sizeof(u32)==4 ); -#if SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) - i = __builtin_bswap32(pCoord->u); - memcpy(p, &i, 4); -#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 - i = _byteswap_ulong(pCoord->u); - memcpy(p, &i, 4); -#elif SQLITE_BYTEORDER==4321 - i = pCoord->u; - memcpy(p, &i, 4); -#else - i = pCoord->u; - p[0] = (i>>24)&0xFF; - p[1] = (i>>16)&0xFF; - p[2] = (i>> 8)&0xFF; - p[3] = (i>> 0)&0xFF; -#endif - return 4; -} -static int writeInt64(u8 *p, i64 i){ -#if SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) - i = (i64)__builtin_bswap64((u64)i); - memcpy(p, &i, 8); -#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 - i = (i64)_byteswap_uint64((u64)i); - memcpy(p, &i, 8); -#elif SQLITE_BYTEORDER==4321 - memcpy(p, &i, 8); -#else - p[0] = (i>>56)&0xFF; - p[1] = (i>>48)&0xFF; - p[2] = (i>>40)&0xFF; - p[3] = (i>>32)&0xFF; - p[4] = (i>>24)&0xFF; - p[5] = (i>>16)&0xFF; - p[6] = (i>> 8)&0xFF; - p[7] = (i>> 0)&0xFF; -#endif - return 8; -} + while( iLeftnRef++; +#if 0 + /* Check that the sort worked */ + { + int jj; + for(jj=1; jjzData[2], 0, pRtree->iNodeSize-2); - p->isDirty = 1; +static void SortByDimension( + Rtree *pRtree, + int *aIdx, + int nIdx, + int iDim, + RtreeCell *aCell, + int *aSpare +){ + if( nIdx>1 ){ + + int iLeft = 0; + int iRight = 0; + + int nLeft = nIdx/2; + int nRight = nIdx-nLeft; + int *aLeft = aIdx; + int *aRight = &aIdx[nLeft]; + + SortByDimension(pRtree, aLeft, nLeft, iDim, aCell, aSpare); + SortByDimension(pRtree, aRight, nRight, iDim, aCell, aSpare); + + memcpy(aSpare, aLeft, sizeof(int)*nLeft); + aLeft = aSpare; + while( iLeftaHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext); - return p; -} + int iBestDim = 0; + int iBestSplit = 0; + RtreeDValue fBestMargin = RTREE_ZERO; -/* -** Add node pNode to the node hash table. -*/ -static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){ - int iHash; - assert( pNode->pNext==0 ); - iHash = nodeHash(pNode->iNode); - pNode->pNext = pRtree->aHash[iHash]; - pRtree->aHash[iHash] = pNode; -} + sqlite3_int64 nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); -/* -** Remove node pNode from the node hash table. -*/ -static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){ - RtreeNode **pp; - if( pNode->iNode!=0 ){ - pp = &pRtree->aHash[nodeHash(pNode->iNode)]; - for( ; (*pp)!=pNode; pp = &(*pp)->pNext){ assert(*pp); } - *pp = pNode->pNext; - pNode->pNext = 0; + aaSorted = (int **)sqlite3_malloc64(nByte); + if( !aaSorted ){ + return SQLITE_NOMEM; } -} -/* -** Allocate and return new r-tree node. Initially, (RtreeNode.iNode==0), -** indicating that node has not yet been assigned a node number. It is -** assigned a node number when nodeWrite() is called to write the -** node contents out to the database. -*/ -static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){ - RtreeNode *pNode; - pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize); - if( pNode ){ - memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize); - pNode->zData = (u8 *)&pNode[1]; - pNode->nRef = 1; - pNode->pParent = pParent; - pNode->isDirty = 1; - nodeReference(pParent); + aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell]; + memset(aaSorted, 0, nByte); + for(ii=0; iinDim; ii++){ + int jj; + aaSorted[ii] = &((int *)&aaSorted[pRtree->nDim])[ii*nCell]; + for(jj=0; jjnDim; ii++){ + RtreeDValue margin = RTREE_ZERO; + RtreeDValue fBestOverlap = RTREE_ZERO; + RtreeDValue fBestArea = RTREE_ZERO; + int iBestLeft = 0; + int nLeft; + + for( + nLeft=RTREE_MINCELLS(pRtree); + nLeft<=(nCell-RTREE_MINCELLS(pRtree)); + nLeft++ + ){ + RtreeCell left; + RtreeCell right; + int kk; + RtreeDValue overlap; + RtreeDValue area; + + memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); + memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); + for(kk=1; kk<(nCell-1); kk++){ + if( kkpNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ - sqlite3_blob *pBlob = pRtree->pNodeBlob; - pRtree->pNodeBlob = 0; - sqlite3_blob_close(pBlob); + +static int updateMapping( + Rtree *pRtree, + i64 iRowid, + RtreeNode *pNode, + int iHeight +){ + int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64); + xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); + if( iHeight>0 ){ + RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); + RtreeNode *p; + for(p=pNode; p; p=p->pParent){ + if( p==pChild ) return SQLITE_CORRUPT_VTAB; + } + if( pChild ){ + nodeRelease(pRtree, pChild->pParent); + nodeReference(pNode); + pChild->pParent = pNode; + } } + if( NEVER(pNode==0) ) return SQLITE_ERROR; + return xSetMapping(pRtree, iRowid, pNode->iNode); } -/* -** Obtain a reference to an r-tree node. -*/ -static int nodeAcquire( - Rtree *pRtree, /* R-tree structure */ - i64 iNode, /* Node number to load */ - RtreeNode *pParent, /* Either the parent node or NULL */ - RtreeNode **ppNode /* OUT: Acquired node */ +static int SplitNode( + Rtree *pRtree, + RtreeNode *pNode, + RtreeCell *pCell, + int iHeight ){ + int i; + int newCellIsRight = 0; + int rc = SQLITE_OK; - RtreeNode *pNode = 0; + int nCell = NCELL(pNode); + RtreeCell *aCell; + int *aiUsed; - /* Check if the requested node is already in the hash table. If so, - ** increase its reference count and return it. + RtreeNode *pLeft = 0; + RtreeNode *pRight = 0; + + RtreeCell leftbbox; + RtreeCell rightbbox; + + /* Allocate an array and populate it with a copy of pCell and + ** all cells from node pLeft. Then zero the original node. */ - if( (pNode = nodeHashLookup(pRtree, iNode)) ){ - assert( !pParent || !pNode->pParent || pNode->pParent==pParent ); - if( pParent && !pNode->pParent ){ - nodeReference(pParent); - pNode->pParent = pParent; - } - pNode->nRef++; - *ppNode = pNode; - return SQLITE_OK; + aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); + if( !aCell ){ + rc = SQLITE_NOMEM; + goto splitnode_out; } + aiUsed = (int *)&aCell[nCell+1]; + memset(aiUsed, 0, sizeof(int)*(nCell+1)); + for(i=0; ipNodeBlob ){ - sqlite3_blob *pBlob = pRtree->pNodeBlob; - pRtree->pNodeBlob = 0; - rc = sqlite3_blob_reopen(pBlob, iNode); - pRtree->pNodeBlob = pBlob; - if( rc ){ - nodeBlobReset(pRtree); - if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM; - } + if( pNode->iNode==1 ){ + pRight = nodeNew(pRtree, pNode); + pLeft = nodeNew(pRtree, pNode); + pRtree->iDepth++; + pNode->isDirty = 1; + writeInt16(pNode->zData, pRtree->iDepth); + }else{ + pLeft = pNode; + pRight = nodeNew(pRtree, pLeft->pParent); + pLeft->nRef++; } - if( pRtree->pNodeBlob==0 ){ - char *zTab = sqlite3_mprintf("%s_node", pRtree->zName); - if( zTab==0 ) return SQLITE_NOMEM; - rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0, - &pRtree->pNodeBlob); - sqlite3_free(zTab); + + if( !pLeft || !pRight ){ + rc = SQLITE_NOMEM; + goto splitnode_out; } - if( rc ){ - nodeBlobReset(pRtree); - *ppNode = 0; - /* If unable to open an sqlite3_blob on the desired row, that can only - ** be because the shadow tables hold erroneous data. */ - if( rc==SQLITE_ERROR ) rc = SQLITE_CORRUPT_VTAB; - }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ - pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize); - if( !pNode ){ - rc = SQLITE_NOMEM; - }else{ - pNode->pParent = pParent; - pNode->zData = (u8 *)&pNode[1]; - pNode->nRef = 1; - pNode->iNode = iNode; - pNode->isDirty = 0; - pNode->pNext = 0; - rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData, - pRtree->iNodeSize, 0); - nodeReference(pParent); - } + + memset(pLeft->zData, 0, pRtree->iNodeSize); + memset(pRight->zData, 0, pRtree->iNodeSize); + + rc = splitNodeStartree(pRtree, aCell, nCell, pLeft, pRight, + &leftbbox, &rightbbox); + if( rc!=SQLITE_OK ){ + goto splitnode_out; } - /* If the root node was just loaded, set pRtree->iDepth to the height - ** of the r-tree structure. A height of zero means all data is stored on - ** the root node. A height of one means the children of the root node - ** are the leaves, and so on. If the depth as specified on the root node - ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. + /* Ensure both child nodes have node numbers assigned to them by calling + ** nodeWrite(). Node pRight always needs a node number, as it was created + ** by nodeNew() above. But node pLeft sometimes already has a node number. + ** In this case avoid the all to nodeWrite(). */ - if( pNode && iNode==1 ){ - pRtree->iDepth = readInt16(pNode->zData); - if( pRtree->iDepth>RTREE_MAX_DEPTH ){ - rc = SQLITE_CORRUPT_VTAB; + if( SQLITE_OK!=(rc = nodeWrite(pRtree, pRight)) + || (0==pLeft->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pLeft))) + ){ + goto splitnode_out; + } + + rightbbox.iRowid = pRight->iNode; + leftbbox.iRowid = pLeft->iNode; + + if( pNode->iNode==1 ){ + rc = rtreeInsertCell(pRtree, pLeft->pParent, &leftbbox, iHeight+1); + if( rc!=SQLITE_OK ){ + goto splitnode_out; } + }else{ + RtreeNode *pParent = pLeft->pParent; + int iCell; + rc = nodeParentIndex(pRtree, pLeft, &iCell); + if( ALWAYS(rc==SQLITE_OK) ){ + nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); + rc = AdjustTree(pRtree, pParent, &leftbbox); + assert( rc==SQLITE_OK ); + } + if( NEVER(rc!=SQLITE_OK) ){ + goto splitnode_out; + } + } + if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){ + goto splitnode_out; } - /* If no error has occurred so far, check if the "number of entries" - ** field on the node is too large. If so, set the return code to - ** SQLITE_CORRUPT_VTAB. - */ - if( pNode && rc==SQLITE_OK ){ - if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ - rc = SQLITE_CORRUPT_VTAB; + for(i=0; iiRowid ){ + newCellIsRight = 1; + } + if( rc!=SQLITE_OK ){ + goto splitnode_out; + } + } + if( pNode->iNode==1 ){ + for(i=0; iiRowid, pLeft, iHeight); } if( rc==SQLITE_OK ){ - if( pNode!=0 ){ - nodeHashInsert(pRtree, pNode); - }else{ - rc = SQLITE_CORRUPT_VTAB; - } - *ppNode = pNode; - }else{ - sqlite3_free(pNode); - *ppNode = 0; + rc = nodeRelease(pRtree, pRight); + pRight = 0; + } + if( rc==SQLITE_OK ){ + rc = nodeRelease(pRtree, pLeft); + pLeft = 0; } +splitnode_out: + nodeRelease(pRtree, pRight); + nodeRelease(pRtree, pLeft); + sqlite3_free(aCell); return rc; } /* -** Overwrite cell iCell of node pNode with the contents of pCell. +** If node pLeaf is not the root of the r-tree and its pParent pointer is +** still NULL, load all ancestor nodes of pLeaf into memory and populate +** the pLeaf->pParent chain all the way up to the root node. +** +** This operation is required when a row is deleted (or updated - an update +** is implemented as a delete followed by an insert). SQLite provides the +** rowid of the row to delete, which can be used to find the leaf on which +** the entry resides (argument pLeaf). Once the leaf is located, this +** function is called to determine its ancestry. */ -static void nodeOverwriteCell( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node into which the cell is to be written */ - RtreeCell *pCell, /* The cell to write */ - int iCell /* Index into pNode into which pCell is written */ -){ - int ii; - u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; - p += writeInt64(p, pCell->iRowid); - for(ii=0; iinDim2; ii++){ - p += writeCoord(p, &pCell->aCoord[ii]); +static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){ + int rc = SQLITE_OK; + RtreeNode *pChild = pLeaf; + while( rc==SQLITE_OK && pChild->iNode!=1 && pChild->pParent==0 ){ + int rc2 = SQLITE_OK; /* sqlite3_reset() return code */ + sqlite3_bind_int64(pRtree->pReadParent, 1, pChild->iNode); + rc = sqlite3_step(pRtree->pReadParent); + if( rc==SQLITE_ROW ){ + RtreeNode *pTest; /* Used to test for reference loops */ + i64 iNode; /* Node number of parent node */ + + /* Before setting pChild->pParent, test that we are not creating a + ** loop of references (as we would if, say, pChild==pParent). We don't + ** want to do this as it leads to a memory leak when trying to delete + ** the referenced counted node structures. + */ + iNode = sqlite3_column_int64(pRtree->pReadParent, 0); + for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); + if( pTest==0 ){ + rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); + } + } + rc = sqlite3_reset(pRtree->pReadParent); + if( rc==SQLITE_OK ) rc = rc2; + if( rc==SQLITE_OK && !pChild->pParent ){ + RTREE_IS_CORRUPT(pRtree); + rc = SQLITE_CORRUPT_VTAB; + } + pChild = pChild->pParent; } - pNode->isDirty = 1; + return rc; } -/* -** Remove the cell with index iCell from node pNode. -*/ -static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){ - u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell]; - u8 *pSrc = &pDst[pRtree->nBytesPerCell]; - int nByte = (NCELL(pNode) - iCell - 1) * pRtree->nBytesPerCell; - memmove(pDst, pSrc, nByte); - writeInt16(&pNode->zData[2], NCELL(pNode)-1); - pNode->isDirty = 1; -} +static int deleteCell(Rtree *, RtreeNode *, int, int); -/* -** Insert the contents of cell pCell into node pNode. If the insert -** is successful, return SQLITE_OK. -** -** If there is not enough free space in pNode, return SQLITE_FULL. -*/ -static int nodeInsertCell( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* Write new cell into this node */ - RtreeCell *pCell /* The cell to be inserted */ -){ - int nCell; /* Current number of cells in pNode */ - int nMaxCell; /* Maximum number of cells for pNode */ +static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){ + int rc; + int rc2; + RtreeNode *pParent = 0; + int iCell; - nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell; - nCell = NCELL(pNode); + assert( pNode->nRef==1 ); - assert( nCell<=nMaxCell ); - if( nCellzData[2], nCell+1); - pNode->isDirty = 1; + /* Remove the entry in the parent cell. */ + rc = nodeParentIndex(pRtree, pNode, &iCell); + if( rc==SQLITE_OK ){ + pParent = pNode->pParent; + pNode->pParent = 0; + rc = deleteCell(pRtree, pParent, iCell, iHeight+1); + testcase( rc!=SQLITE_OK ); + } + rc2 = nodeRelease(pRtree, pParent); + if( rc==SQLITE_OK ){ + rc = rc2; + } + if( rc!=SQLITE_OK ){ + return rc; } - return (nCell==nMaxCell); -} + /* Remove the xxx_node entry. */ + sqlite3_bind_int64(pRtree->pDeleteNode, 1, pNode->iNode); + sqlite3_step(pRtree->pDeleteNode); + if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteNode)) ){ + return rc; + } -/* -** If the node is dirty, write it out to the database. -*/ -static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){ - int rc = SQLITE_OK; - if( pNode->isDirty ){ - sqlite3_stmt *p = pRtree->pWriteNode; - if( pNode->iNode ){ - sqlite3_bind_int64(p, 1, pNode->iNode); - }else{ - sqlite3_bind_null(p, 1); - } - sqlite3_bind_blob(p, 2, pNode->zData, pRtree->iNodeSize, SQLITE_STATIC); - sqlite3_step(p); - pNode->isDirty = 0; - rc = sqlite3_reset(p); - if( pNode->iNode==0 && rc==SQLITE_OK ){ - pNode->iNode = sqlite3_last_insert_rowid(pRtree->db); - nodeHashInsert(pRtree, pNode); - } + /* Remove the xxx_parent entry. */ + sqlite3_bind_int64(pRtree->pDeleteParent, 1, pNode->iNode); + sqlite3_step(pRtree->pDeleteParent); + if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteParent)) ){ + return rc; } - return rc; + + /* Remove the node from the in-memory hash table and link it into + ** the Rtree.pDeleted list. Its contents will be re-inserted later on. + */ + nodeHashDelete(pRtree, pNode); + pNode->iNode = iHeight; + pNode->pNext = pRtree->pDeleted; + pNode->nRef++; + pRtree->pDeleted = pNode; + + return SQLITE_OK; } -/* -** Release a reference to a node. If the node is dirty and the reference -** count drops to zero, the node data is written to the database. -*/ -static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){ +static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){ + RtreeNode *pParent = pNode->pParent; int rc = SQLITE_OK; - if( pNode ){ - assert( pNode->nRef>0 ); - pNode->nRef--; - if( pNode->nRef==0 ){ - if( pNode->iNode==1 ){ - pRtree->iDepth = -1; - } - if( pNode->pParent ){ - rc = nodeRelease(pRtree, pNode->pParent); - } - if( rc==SQLITE_OK ){ - rc = nodeWrite(pRtree, pNode); - } - nodeHashDelete(pRtree, pNode); - sqlite3_free(pNode); + if( pParent ){ + int ii; + int nCell = NCELL(pNode); + RtreeCell box; /* Bounding box for pNode */ + nodeGetCell(pRtree, pNode, 0, &box); + for(ii=1; iiiNode; + rc = nodeParentIndex(pRtree, pNode, &ii); + if( rc==SQLITE_OK ){ + nodeOverwriteCell(pRtree, pParent, &box, ii); + rc = fixBoundingBox(pRtree, pParent); } } return rc; } /* -** Return the 64-bit integer value associated with cell iCell of -** node pNode. If pNode is a leaf node, this is a rowid. If it is -** an internal node, then the 64-bit integer is a child page number. -*/ -static i64 nodeGetRowid( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node from which to extract the ID */ - int iCell /* The cell index from which to extract the ID */ -){ - assert( iCellzData[4 + pRtree->nBytesPerCell*iCell]); -} - -/* -** Return coordinate iCoord from cell iCell in node pNode. +** Delete the cell at index iCell of node pNode. After removing the +** cell, adjust the r-tree data structure if required. */ -static void nodeGetCoord( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node from which to extract a coordinate */ - int iCell, /* The index of the cell within the node */ - int iCoord, /* Which coordinate to extract */ - RtreeCoord *pCoord /* OUT: Space to write result to */ -){ - readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord); -} +static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){ + RtreeNode *pParent; + int rc; -/* -** Deserialize cell iCell of node pNode. Populate the structure pointed -** to by pCell with the results. -*/ -static void nodeGetCell( - Rtree *pRtree, /* The overall R-Tree */ - RtreeNode *pNode, /* The node containing the cell to be read */ - int iCell, /* Index of the cell within the node */ - RtreeCell *pCell /* OUT: Write the cell contents here */ -){ - u8 *pData; - RtreeCoord *pCoord; - int ii = 0; - pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell); - pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell); - pCoord = pCell->aCoord; - do{ - readCoord(pData, &pCoord[ii]); - readCoord(pData+4, &pCoord[ii+1]); - pData += 8; - ii += 2; - }while( iinDim2 ); -} + if( SQLITE_OK!=(rc = fixLeafParent(pRtree, pNode)) ){ + return rc; + } + /* Remove the cell from the node. This call just moves bytes around + ** the in-memory node image, so it cannot fail. + */ + nodeDeleteCell(pRtree, pNode, iCell); -/* Forward declaration for the function that does the work of -** the virtual table module xCreate() and xConnect() methods. -*/ -static int rtreeInit( - sqlite3 *, void *, int, const char *const*, sqlite3_vtab **, char **, int -); + /* If the node is not the tree root and now has less than the minimum + ** number of cells, remove it from the tree. Otherwise, update the + ** cell in the parent node so that it tightly contains the updated + ** node. + */ + pParent = pNode->pParent; + assert( pParent || pNode->iNode==1 ); + if( pParent ){ + if( NCELL(pNode)nBusy++; -} + memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS); -/* -** Decrement the r-tree reference count. When the reference count reaches -** zero the structure is deleted. -*/ -static void rtreeRelease(Rtree *pRtree){ - pRtree->nBusy--; - if( pRtree->nBusy==0 ){ - pRtree->inWrTrans = 0; - pRtree->nCursor = 0; - nodeBlobReset(pRtree); - sqlite3_finalize(pRtree->pWriteNode); - sqlite3_finalize(pRtree->pDeleteNode); - sqlite3_finalize(pRtree->pReadRowid); - sqlite3_finalize(pRtree->pWriteRowid); - sqlite3_finalize(pRtree->pDeleteRowid); - sqlite3_finalize(pRtree->pReadParent); - sqlite3_finalize(pRtree->pWriteParent); - sqlite3_finalize(pRtree->pDeleteParent); - sqlite3_free(pRtree); - } -} + nCell = NCELL(pNode)+1; + n = (nCell+1)&(~1); -/* -** Rtree virtual table module xDisconnect method. -*/ -static int rtreeDisconnect(sqlite3_vtab *pVtab){ - rtreeRelease((Rtree *)pVtab); - return SQLITE_OK; -} + /* Allocate the buffers used by this operation. The allocation is + ** relinquished before this function returns. + */ + aCell = (RtreeCell *)sqlite3_malloc64(n * ( + sizeof(RtreeCell) + /* aCell array */ + sizeof(int) + /* aOrder array */ + sizeof(int) + /* aSpare array */ + sizeof(RtreeDValue) /* aDistance array */ + )); + if( !aCell ){ + return SQLITE_NOMEM; + } + aOrder = (int *)&aCell[n]; + aSpare = (int *)&aOrder[n]; + aDistance = (RtreeDValue *)&aSpare[n]; -/* -** Rtree virtual table module xDestroy method. -*/ -static int rtreeDestroy(sqlite3_vtab *pVtab){ - Rtree *pRtree = (Rtree *)pVtab; - int rc; - char *zCreate = sqlite3_mprintf( - "DROP TABLE '%q'.'%q_node';" - "DROP TABLE '%q'.'%q_rowid';" - "DROP TABLE '%q'.'%q_parent';", - pRtree->zDb, pRtree->zName, - pRtree->zDb, pRtree->zName, - pRtree->zDb, pRtree->zName - ); - if( !zCreate ){ - rc = SQLITE_NOMEM; - }else{ - nodeBlobReset(pRtree); - rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0); - sqlite3_free(zCreate); + for(ii=0; iinDim; iDim++){ + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]); + aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]); + } } - if( rc==SQLITE_OK ){ - rtreeRelease(pRtree); + for(iDim=0; iDimnDim; iDim++){ + aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2)); } - return rc; -} + for(ii=0; iinDim; iDim++){ + RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - + DCOORD(aCell[ii].aCoord[iDim*2])); + aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); + } + } -/* -** Rtree virtual table module xOpen method. -*/ -static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ - int rc = SQLITE_NOMEM; - Rtree *pRtree = (Rtree *)pVTab; - RtreeCursor *pCsr; + SortByDistance(aOrder, nCell, aDistance, aSpare); + nodeZero(pRtree, pNode); - pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor)); - if( pCsr ){ - memset(pCsr, 0, sizeof(RtreeCursor)); - pCsr->base.pVtab = pVTab; - rc = SQLITE_OK; - pRtree->nCursor++; + for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){ + RtreeCell *p = &aCell[aOrder[ii]]; + nodeInsertCell(pRtree, pNode, p); + if( p->iRowid==pCell->iRowid ){ + if( iHeight==0 ){ + rc = rowidWrite(pRtree, p->iRowid, pNode->iNode); + }else{ + rc = parentWrite(pRtree, p->iRowid, pNode->iNode); + } + } + } + if( rc==SQLITE_OK ){ + rc = fixBoundingBox(pRtree, pNode); + } + for(; rc==SQLITE_OK && iiiNode currently contains + ** the height of the sub-tree headed by the cell. + */ + RtreeNode *pInsert; + RtreeCell *p = &aCell[aOrder[ii]]; + rc = ChooseLeaf(pRtree, p, iHeight, &pInsert); + if( rc==SQLITE_OK ){ + int rc2; + rc = rtreeInsertCell(pRtree, pInsert, p, iHeight); + rc2 = nodeRelease(pRtree, pInsert); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } } - *ppCursor = (sqlite3_vtab_cursor *)pCsr; + sqlite3_free(aCell); return rc; } - /* -** Free the RtreeCursor.aConstraint[] array and its contents. +** Insert cell pCell into node pNode. Node pNode is the head of a +** subtree iHeight high (leaf nodes have iHeight==0). */ -static void freeCursorConstraints(RtreeCursor *pCsr){ - if( pCsr->aConstraint ){ - int i; /* Used to iterate through constraint array */ - for(i=0; inConstraint; i++){ - sqlite3_rtree_query_info *pInfo = pCsr->aConstraint[i].pInfo; - if( pInfo ){ - if( pInfo->xDelUser ) pInfo->xDelUser(pInfo->pUser); - sqlite3_free(pInfo); +static int rtreeInsertCell( + Rtree *pRtree, + RtreeNode *pNode, + RtreeCell *pCell, + int iHeight +){ + int rc = SQLITE_OK; + if( iHeight>0 ){ + RtreeNode *pChild = nodeHashLookup(pRtree, pCell->iRowid); + if( pChild ){ + nodeRelease(pRtree, pChild->pParent); + nodeReference(pNode); + pChild->pParent = pNode; + } + } + if( nodeInsertCell(pRtree, pNode, pCell) ){ + if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ + rc = SplitNode(pRtree, pNode, pCell, iHeight); + }else{ + pRtree->iReinsertHeight = iHeight; + rc = Reinsert(pRtree, pNode, pCell, iHeight); + } + }else{ + rc = AdjustTree(pRtree, pNode, pCell); + if( ALWAYS(rc==SQLITE_OK) ){ + if( iHeight==0 ){ + rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); + }else{ + rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode); } } - sqlite3_free(pCsr->aConstraint); - pCsr->aConstraint = 0; } + return rc; } -/* -** Rtree virtual table module xClose method. -*/ -static int rtreeClose(sqlite3_vtab_cursor *cur){ - Rtree *pRtree = (Rtree *)(cur->pVtab); +static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){ int ii; - RtreeCursor *pCsr = (RtreeCursor *)cur; - assert( pRtree->nCursor>0 ); - freeCursorConstraints(pCsr); - sqlite3_free(pCsr->aPoint); - for(ii=0; iiaNode[ii]); - sqlite3_free(pCsr); - pRtree->nCursor--; - nodeBlobReset(pRtree); - return SQLITE_OK; -} + int rc = SQLITE_OK; + int nCell = NCELL(pNode); -/* -** Rtree virtual table module xEof method. -** -** Return non-zero if the cursor does not currently point to a valid -** record (i.e if the scan has finished), or zero otherwise. -*/ -static int rtreeEof(sqlite3_vtab_cursor *cur){ - RtreeCursor *pCsr = (RtreeCursor *)cur; - return pCsr->atEOF; + for(ii=0; rc==SQLITE_OK && iiiNode currently contains + ** the height of the sub-tree headed by the cell. + */ + rc = ChooseLeaf(pRtree, &cell, (int)pNode->iNode, &pInsert); + if( rc==SQLITE_OK ){ + int rc2; + rc = rtreeInsertCell(pRtree, pInsert, &cell, (int)pNode->iNode); + rc2 = nodeRelease(pRtree, pInsert); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + return rc; } /* -** Convert raw bits from the on-disk RTree record into a coordinate value. -** The on-disk format is big-endian and needs to be converted for little- -** endian platforms. The on-disk record stores integer coordinates if -** eInt is true and it stores 32-bit floating point records if eInt is -** false. a[] is the four bytes of the on-disk record to be decoded. -** Store the results in "r". -** -** There are five versions of this macro. The last one is generic. The -** other four are various architectures-specific optimizations. +** Select a currently unused rowid for a new r-tree record. */ -#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - c.u = _byteswap_ulong(*(u32*)a); \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ -} -#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000) -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - c.u = __builtin_bswap32(*(u32*)a); \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ -} -#elif SQLITE_BYTEORDER==1234 -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - memcpy(&c.u,a,4); \ - c.u = ((c.u>>24)&0xff)|((c.u>>8)&0xff00)| \ - ((c.u&0xff)<<24)|((c.u&0xff00)<<8); \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ -} -#elif SQLITE_BYTEORDER==4321 -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - memcpy(&c.u,a,4); \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ -} -#else -#define RTREE_DECODE_COORD(eInt, a, r) { \ - RtreeCoord c; /* Coordinate decoded */ \ - c.u = ((u32)a[0]<<24) + ((u32)a[1]<<16) \ - +((u32)a[2]<<8) + a[3]; \ - r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \ +static int rtreeNewRowid(Rtree *pRtree, i64 *piRowid){ + int rc; + sqlite3_bind_null(pRtree->pWriteRowid, 1); + sqlite3_bind_null(pRtree->pWriteRowid, 2); + sqlite3_step(pRtree->pWriteRowid); + rc = sqlite3_reset(pRtree->pWriteRowid); + *piRowid = sqlite3_last_insert_rowid(pRtree->db); + return rc; } -#endif /* -** Check the RTree node or entry given by pCellData and p against the MATCH -** constraint pConstraint. +** Remove the entry with rowid=iDelete from the r-tree structure. */ -static int rtreeCallbackConstraint( - RtreeConstraint *pConstraint, /* The constraint to test */ - int eInt, /* True if RTree holding integer coordinates */ - u8 *pCellData, /* Raw cell content */ - RtreeSearchPoint *pSearch, /* Container of this cell */ - sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */ - int *peWithin /* OUT: visibility of the cell */ -){ - sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */ - int nCoord = pInfo->nCoord; /* No. of coordinates */ - int rc; /* Callback return code */ - RtreeCoord c; /* Translator union */ - sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */ +static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ + int rc; /* Return code */ + RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ + int iCell; /* Index of iDelete cell in pLeaf */ + RtreeNode *pRoot = 0; /* Root node of rtree structure */ - assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY ); - assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 ); - if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){ - pInfo->iRowid = readInt64(pCellData); + /* Obtain a reference to the root node to initialize Rtree.iDepth */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + + /* Obtain a reference to the leaf node that contains the entry + ** about to be deleted. + */ + if( rc==SQLITE_OK ){ + rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); } - pCellData += 8; -#ifndef SQLITE_RTREE_INT_ONLY - if( eInt==0 ){ - switch( nCoord ){ - case 10: readCoord(pCellData+36, &c); aCoord[9] = c.f; - readCoord(pCellData+32, &c); aCoord[8] = c.f; - case 8: readCoord(pCellData+28, &c); aCoord[7] = c.f; - readCoord(pCellData+24, &c); aCoord[6] = c.f; - case 6: readCoord(pCellData+20, &c); aCoord[5] = c.f; - readCoord(pCellData+16, &c); aCoord[4] = c.f; - case 4: readCoord(pCellData+12, &c); aCoord[3] = c.f; - readCoord(pCellData+8, &c); aCoord[2] = c.f; - default: readCoord(pCellData+4, &c); aCoord[1] = c.f; - readCoord(pCellData, &c); aCoord[0] = c.f; - } - }else + +#ifdef CORRUPT_DB + assert( pLeaf!=0 || rc!=SQLITE_OK || CORRUPT_DB ); #endif - { - switch( nCoord ){ - case 10: readCoord(pCellData+36, &c); aCoord[9] = c.i; - readCoord(pCellData+32, &c); aCoord[8] = c.i; - case 8: readCoord(pCellData+28, &c); aCoord[7] = c.i; - readCoord(pCellData+24, &c); aCoord[6] = c.i; - case 6: readCoord(pCellData+20, &c); aCoord[5] = c.i; - readCoord(pCellData+16, &c); aCoord[4] = c.i; - case 4: readCoord(pCellData+12, &c); aCoord[3] = c.i; - readCoord(pCellData+8, &c); aCoord[2] = c.i; - default: readCoord(pCellData+4, &c); aCoord[1] = c.i; - readCoord(pCellData, &c); aCoord[0] = c.i; + + /* Delete the cell in question from the leaf node. */ + if( rc==SQLITE_OK && pLeaf ){ + int rc2; + rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); + if( rc==SQLITE_OK ){ + rc = deleteCell(pRtree, pLeaf, iCell, 0); + } + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; } } - if( pConstraint->op==RTREE_MATCH ){ - int eWithin = 0; - rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo, - nCoord, aCoord, &eWithin); - if( eWithin==0 ) *peWithin = NOT_WITHIN; - *prScore = RTREE_ZERO; - }else{ - pInfo->aCoord = aCoord; - pInfo->iLevel = pSearch->iLevel - 1; - pInfo->rScore = pInfo->rParentScore = pSearch->rScore; - pInfo->eWithin = pInfo->eParentWithin = pSearch->eWithin; - rc = pConstraint->u.xQueryFunc(pInfo); - if( pInfo->eWithin<*peWithin ) *peWithin = pInfo->eWithin; - if( pInfo->rScore<*prScore || *prScorerScore; + + /* Delete the corresponding entry in the _rowid table. */ + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); + sqlite3_step(pRtree->pDeleteRowid); + rc = sqlite3_reset(pRtree->pDeleteRowid); + } + + /* Check if the root node now has exactly one child. If so, remove + ** it, schedule the contents of the child for reinsertion and + ** reduce the tree height by one. + ** + ** This is equivalent to copying the contents of the child into + ** the root node (the operation that Gutman's paper says to perform + ** in this scenario). + */ + if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ + int rc2; + RtreeNode *pChild = 0; + i64 iChild = nodeGetRowid(pRtree, pRoot, 0); + rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); /* tag-20210916a */ + if( rc==SQLITE_OK ){ + rc = removeNode(pRtree, pChild, pRtree->iDepth-1); + } + rc2 = nodeRelease(pRtree, pChild); + if( rc==SQLITE_OK ) rc = rc2; + if( rc==SQLITE_OK ){ + pRtree->iDepth--; + writeInt16(pRoot->zData, pRtree->iDepth); + pRoot->isDirty = 1; } } + + /* Re-insert the contents of any underfull nodes removed from the tree. */ + for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ + if( rc==SQLITE_OK ){ + rc = reinsertNodeContent(pRtree, pLeaf); + } + pRtree->pDeleted = pLeaf->pNext; + pRtree->nNodeRef--; + sqlite3_free(pLeaf); + } + + /* Release the reference to the root node. */ + if( rc==SQLITE_OK ){ + rc = nodeRelease(pRtree, pRoot); + }else{ + nodeRelease(pRtree, pRoot); + } + return rc; } -/* -** Check the internal RTree node given by pCellData against constraint p. -** If this constraint cannot be satisfied by any child within the node, -** set *peWithin to NOT_WITHIN. +/* +** Rounding constants for float->double conversion. */ -static void rtreeNonleafConstraint( - RtreeConstraint *p, /* The constraint to test */ - int eInt, /* True if RTree holds integer coordinates */ - u8 *pCellData, /* Raw cell content as appears on disk */ - int *peWithin /* Adjust downward, as appropriate */ -){ - sqlite3_rtree_dbl val; /* Coordinate value convert to a double */ - - /* p->iCoord might point to either a lower or upper bound coordinate - ** in a coordinate pair. But make pCellData point to the lower bound. - */ - pCellData += 8 + 4*(p->iCoord&0xfe); - - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ ); - assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ - switch( p->op ){ - case RTREE_LE: - case RTREE_LT: - case RTREE_EQ: - RTREE_DECODE_COORD(eInt, pCellData, val); - /* val now holds the lower bound of the coordinate pair */ - if( p->u.rValue>=val ) return; - if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ - /* Fall through for the RTREE_EQ case */ +#define RNDTOWARDS (1.0 - 1.0/8388608.0) /* Round towards zero */ +#define RNDAWAY (1.0 + 1.0/8388608.0) /* Round away from zero */ - default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ - pCellData += 4; - RTREE_DECODE_COORD(eInt, pCellData, val); - /* val now holds the upper bound of the coordinate pair */ - if( p->u.rValue<=val ) return; +#if !defined(SQLITE_RTREE_INT_ONLY) +/* +** Convert an sqlite3_value into an RtreeValue (presumably a float) +** while taking care to round toward negative or positive, respectively. +*/ +static RtreeValue rtreeValueDown(sqlite3_value *v){ + double d = sqlite3_value_double(v); + float f = (float)d; + if( f>d ){ + f = (float)(d*(d<0 ? RNDAWAY : RNDTOWARDS)); } - *peWithin = NOT_WITHIN; + return f; +} +static RtreeValue rtreeValueUp(sqlite3_value *v){ + double d = sqlite3_value_double(v); + float f = (float)d; + if( fbase.zErrMsg) to an appropriate value and returns +** SQLITE_CONSTRAINT. ** -** The constraint is of the form: xN op $val +** Parameter iCol is the index of the leftmost column involved in the +** constraint failure. If it is 0, then the constraint that failed is +** the unique constraint on the id column. Otherwise, it is the rtree +** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. ** -** The op is given by p->op. The xN is p->iCoord-th coordinate in -** pCellData. $val is given by p->u.rValue. +** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. */ -static void rtreeLeafConstraint( - RtreeConstraint *p, /* The constraint to test */ - int eInt, /* True if RTree holds integer coordinates */ - u8 *pCellData, /* Raw cell content as appears on disk */ - int *peWithin /* Adjust downward, as appropriate */ -){ - RtreeDValue xN; /* Coordinate value converted to a double */ +static int rtreeConstraintError(Rtree *pRtree, int iCol){ + sqlite3_stmt *pStmt = 0; + char *zSql; + int rc; - assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE - || p->op==RTREE_GT || p->op==RTREE_EQ ); - pCellData += 8 + p->iCoord*4; - assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ - RTREE_DECODE_COORD(eInt, pCellData, xN); - switch( p->op ){ - case RTREE_LE: if( xN <= p->u.rValue ) return; break; - case RTREE_LT: if( xN < p->u.rValue ) return; break; - case RTREE_GE: if( xN >= p->u.rValue ) return; break; - case RTREE_GT: if( xN > p->u.rValue ) return; break; - default: if( xN == p->u.rValue ) return; break; + assert( iCol==0 || iCol%2 ); + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); + if( zSql ){ + rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); + }else{ + rc = SQLITE_NOMEM; } - *peWithin = NOT_WITHIN; + sqlite3_free(zSql); + + if( rc==SQLITE_OK ){ + if( iCol==0 ){ + const char *zCol = sqlite3_column_name(pStmt, 0); + pRtree->base.zErrMsg = sqlite3_mprintf( + "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol + ); + }else{ + const char *zCol1 = sqlite3_column_name(pStmt, iCol); + const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); + pRtree->base.zErrMsg = sqlite3_mprintf( + "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 + ); + } + } + + sqlite3_finalize(pStmt); + return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); } + + /* -** One of the cells in node pNode is guaranteed to have a 64-bit -** integer value equal to iRowid. Return the index of this cell. +** The xUpdate method for rtree module virtual tables. */ -static int nodeRowidIndex( - Rtree *pRtree, - RtreeNode *pNode, - i64 iRowid, - int *piIndex +static int rtreeUpdate( + sqlite3_vtab *pVtab, + int nData, + sqlite3_value **aData, + sqlite_int64 *pRowid ){ - int ii; - int nCell = NCELL(pNode); - assert( nCell<200 ); - for(ii=0; ii1 */ + int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ + + if( pRtree->nNodeRef ){ + /* Unable to write to the btree while another cursor is reading from it, + ** since the write might do a rebalance which would disrupt the read + ** cursor. */ + return SQLITE_LOCKED_VTAB; + } + rtreeReference(pRtree); + assert(nData>=1); + + cell.iRowid = 0; /* Used only to suppress a compiler warning */ + + /* Constraint handling. A write operation on an r-tree table may return + ** SQLITE_CONSTRAINT for two reasons: + ** + ** 1. A duplicate rowid value, or + ** 2. The supplied data violates the "x2>=x1" constraint. + ** + ** In the first case, if the conflict-handling mode is REPLACE, then + ** the conflicting row can be removed before proceeding. In the second + ** case, SQLITE_CONSTRAINT must be returned regardless of the + ** conflict-handling mode specified by the user. + */ + if( nData>1 ){ + int ii; + int nn = nData - 4; + + if( nn > pRtree->nDim2 ) nn = pRtree->nDim2; + /* Populate the cell.aCoord[] array. The first coordinate is aData[3]. + ** + ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared + ** with "column" that are interpreted as table constraints. + ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); + ** This problem was discovered after years of use, so we silently ignore + ** these kinds of misdeclared tables to avoid breaking any legacy. + */ + +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + for(ii=0; iicell.aCoord[ii+1].f ){ + rc = rtreeConstraintError(pRtree, ii+1); + goto constraint; + } + } + }else +#endif + { + for(ii=0; iicell.aCoord[ii+1].i ){ + rc = rtreeConstraintError(pRtree, ii+1); + goto constraint; + } + } + } + + /* If a rowid value was supplied, check if it is already present in + ** the table. If so, the constraint has failed. */ + if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){ + cell.iRowid = sqlite3_value_int64(aData[2]); + if( sqlite3_value_type(aData[0])==SQLITE_NULL + || sqlite3_value_int64(aData[0])!=cell.iRowid + ){ + int steprc; + sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); + steprc = sqlite3_step(pRtree->pReadRowid); + rc = sqlite3_reset(pRtree->pReadRowid); + if( SQLITE_ROW==steprc ){ + if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ + rc = rtreeDeleteRowid(pRtree, cell.iRowid); + }else{ + rc = rtreeConstraintError(pRtree, 0); + goto constraint; + } + } + } + bHaveRowid = 1; } } - return SQLITE_CORRUPT_VTAB; + + /* If aData[0] is not an SQL NULL value, it is the rowid of a + ** record to delete from the r-tree table. The following block does + ** just that. + */ + if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){ + rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0])); + } + + /* If the aData[] array contains more than one element, elements + ** (aData[2]..aData[argc-1]) contain a new record to insert into + ** the r-tree structure. + */ + if( rc==SQLITE_OK && nData>1 ){ + /* Insert the new record into the r-tree */ + RtreeNode *pLeaf = 0; + + /* Figure out the rowid of the new row. */ + if( bHaveRowid==0 ){ + rc = rtreeNewRowid(pRtree, &cell.iRowid); + } + *pRowid = cell.iRowid; + + if( rc==SQLITE_OK ){ + rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); + } + if( rc==SQLITE_OK ){ + int rc2; + pRtree->iReinsertHeight = -1; + rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + if( rc==SQLITE_OK && pRtree->nAux ){ + sqlite3_stmt *pUp = pRtree->pWriteAux; + int jj; + sqlite3_bind_int64(pUp, 1, *pRowid); + for(jj=0; jjnAux; jj++){ + sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]); + } + sqlite3_step(pUp); + rc = sqlite3_reset(pUp); + } + } + +constraint: + rtreeRelease(pRtree); + return rc; } /* -** Return the index of the cell containing a pointer to node pNode -** in its parent. If pNode is the root node, return -1. +** Called when a transaction starts. */ -static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){ - RtreeNode *pParent = pNode->pParent; - if( pParent ){ - return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); - } - *piIndex = -1; +static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; + assert( pRtree->inWrTrans==0 ); + pRtree->inWrTrans++; return SQLITE_OK; } /* -** Compare two search points. Return negative, zero, or positive if the first -** is less than, equal to, or greater than the second. -** -** The rScore is the primary key. Smaller rScore values come first. -** If the rScore is a tie, then use iLevel as the tie breaker with smaller -** iLevel values coming first. In this way, if rScore is the same for all -** SearchPoints, then iLevel becomes the deciding factor and the result -** is a depth-first search, which is the desired default behavior. +** Called when a transaction completes (either by COMMIT or ROLLBACK). +** The sqlite3_blob object should be released at this point. */ -static int rtreeSearchPointCompare( - const RtreeSearchPoint *pA, - const RtreeSearchPoint *pB -){ - if( pA->rScorerScore ) return -1; - if( pA->rScore>pB->rScore ) return +1; - if( pA->iLeveliLevel ) return -1; - if( pA->iLevel>pB->iLevel ) return +1; - return 0; +static int rtreeEndTransaction(sqlite3_vtab *pVtab){ + Rtree *pRtree = (Rtree *)pVtab; + pRtree->inWrTrans = 0; + nodeBlobReset(pRtree); + return SQLITE_OK; } /* -** Interchange two search points in a cursor. +** The xRename method for rtree module virtual tables. */ -static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){ - RtreeSearchPoint t = p->aPoint[i]; - assert( iaPoint[i] = p->aPoint[j]; - p->aPoint[j] = t; - i++; j++; - if( i=RTREE_CACHE_SZ ){ - nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); - p->aNode[i] = 0; - }else{ - RtreeNode *pTemp = p->aNode[i]; - p->aNode[i] = p->aNode[j]; - p->aNode[j] = pTemp; - } +static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){ + Rtree *pRtree = (Rtree *)pVtab; + int rc = SQLITE_NOMEM; + char *zSql = sqlite3_mprintf( + "ALTER TABLE %Q.'%q_node' RENAME TO \"%w_node\";" + "ALTER TABLE %Q.'%q_parent' RENAME TO \"%w_parent\";" + "ALTER TABLE %Q.'%q_rowid' RENAME TO \"%w_rowid\";" + , pRtree->zDb, pRtree->zName, zNewName + , pRtree->zDb, pRtree->zName, zNewName + , pRtree->zDb, pRtree->zName, zNewName + ); + if( zSql ){ + nodeBlobReset(pRtree); + rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0); + sqlite3_free(zSql); } + return rc; } /* -** Return the search point with the lowest current score. +** The xSavepoint method. +** +** This module does not need to do anything to support savepoints. However, +** it uses this hook to close any open blob handle. This is done because a +** DROP TABLE command - which fortunately always opens a savepoint - cannot +** succeed if there are any open blob handles. i.e. if the blob handle were +** not closed here, the following would fail: +** +** BEGIN; +** INSERT INTO rtree... +** DROP TABLE ; -- Would fail with SQLITE_LOCKED +** COMMIT; */ -static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){ - return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0; +static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ + Rtree *pRtree = (Rtree *)pVtab; + u8 iwt = pRtree->inWrTrans; + UNUSED_PARAMETER(iSavepoint); + pRtree->inWrTrans = 0; + nodeBlobReset(pRtree); + pRtree->inWrTrans = iwt; + return SQLITE_OK; } /* -** Get the RtreeNode for the search point with the lowest score. +** This function populates the pRtree->nRowEst variable with an estimate +** of the number of rows in the virtual table. If possible, this is based +** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. */ -static RtreeNode *rtreeNodeOfFirstSearchPoint(RtreeCursor *pCur, int *pRC){ - sqlite3_int64 id; - int ii = 1 - pCur->bPoint; - assert( ii==0 || ii==1 ); - assert( pCur->bPoint || pCur->nPoint ); - if( pCur->aNode[ii]==0 ){ - assert( pRC!=0 ); - id = ii ? pCur->aPoint[0].id : pCur->sPoint.id; - *pRC = nodeAcquire(RTREE_OF_CURSOR(pCur), id, 0, &pCur->aNode[ii]); - } - return pCur->aNode[ii]; -} +static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ + const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; + char *zSql; + sqlite3_stmt *p; + int rc; + i64 nRow = RTREE_MIN_ROWEST; -/* -** Push a new element onto the priority queue -*/ -static RtreeSearchPoint *rtreeEnqueue( - RtreeCursor *pCur, /* The cursor */ - RtreeDValue rScore, /* Score for the new search point */ - u8 iLevel /* Level for the new search point */ -){ - int i, j; - RtreeSearchPoint *pNew; - if( pCur->nPoint>=pCur->nPointAlloc ){ - int nNew = pCur->nPointAlloc*2 + 8; - pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0])); - if( pNew==0 ) return 0; - pCur->aPoint = pNew; - pCur->nPointAlloc = nNew; + rc = sqlite3_table_column_metadata( + db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 + ); + if( rc!=SQLITE_OK ){ + pRtree->nRowEst = RTREE_DEFAULT_ROWEST; + return rc==SQLITE_ERROR ? SQLITE_OK : rc; } - i = pCur->nPoint++; - pNew = pCur->aPoint + i; - pNew->rScore = rScore; - pNew->iLevel = iLevel; - assert( iLevel<=RTREE_MAX_DEPTH ); - while( i>0 ){ - RtreeSearchPoint *pParent; - j = (i-1)/2; - pParent = pCur->aPoint + j; - if( rtreeSearchPointCompare(pNew, pParent)>=0 ) break; - rtreeSearchPointSwap(pCur, j, i); - i = j; - pNew = pParent; + zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); + if( rc==SQLITE_OK ){ + if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); + rc = sqlite3_finalize(p); + } + sqlite3_free(zSql); } - return pNew; + pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); + return rc; } + /* -** Allocate a new RtreeSearchPoint and return a pointer to it. Return -** NULL if malloc fails. +** Return true if zName is the extension on one of the shadow tables used +** by this module. */ -static RtreeSearchPoint *rtreeSearchPointNew( - RtreeCursor *pCur, /* The cursor */ - RtreeDValue rScore, /* Score for the new search point */ - u8 iLevel /* Level for the new search point */ -){ - RtreeSearchPoint *pNew, *pFirst; - pFirst = rtreeSearchPointFirst(pCur); - pCur->anQueue[iLevel]++; - if( pFirst==0 - || pFirst->rScore>rScore - || (pFirst->rScore==rScore && pFirst->iLevel>iLevel) - ){ - if( pCur->bPoint ){ - int ii; - pNew = rtreeEnqueue(pCur, rScore, iLevel); - if( pNew==0 ) return 0; - ii = (int)(pNew - pCur->aPoint) + 1; - if( iiaNode[ii]==0 ); - pCur->aNode[ii] = pCur->aNode[0]; - }else{ - nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]); - } - pCur->aNode[0] = 0; - *pNew = pCur->sPoint; - } - pCur->sPoint.rScore = rScore; - pCur->sPoint.iLevel = iLevel; - pCur->bPoint = 1; - return &pCur->sPoint; - }else{ - return rtreeEnqueue(pCur, rScore, iLevel); +static int rtreeShadowName(const char *zName){ + static const char *azName[] = { + "node", "parent", "rowid" + }; + unsigned int i; + for(i=0; iiLevel, p->id, p->iCell, p->rScore, p->eWithin - ); - idx++; - if( idxaNode[idx]); - }else{ - printf("\n"); - } -} -static void traceQueue(RtreeCursor *pCur, const char *zPrefix){ - int ii; - printf("=== %9s ", zPrefix); - if( pCur->bPoint ){ - tracePoint(&pCur->sPoint, -1, pCur); - } - for(ii=0; iinPoint; ii++){ - if( ii>0 || pCur->bPoint ) printf(" "); - tracePoint(&pCur->aPoint[ii], ii, pCur); - } -} -# define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B) -#else -# define RTREE_QUEUE_TRACE(A,B) /* no-op */ -#endif +static sqlite3_module rtreeModule = { + 3, /* iVersion */ + rtreeCreate, /* xCreate - create a table */ + rtreeConnect, /* xConnect - connect to an existing table */ + rtreeBestIndex, /* xBestIndex - Determine search strategy */ + rtreeDisconnect, /* xDisconnect - Disconnect from a table */ + rtreeDestroy, /* xDestroy - Drop a table */ + rtreeOpen, /* xOpen - open a cursor */ + rtreeClose, /* xClose - close a cursor */ + rtreeFilter, /* xFilter - configure scan constraints */ + rtreeNext, /* xNext - advance a cursor */ + rtreeEof, /* xEof */ + rtreeColumn, /* xColumn - read data */ + rtreeRowid, /* xRowid - read data */ + rtreeUpdate, /* xUpdate - write data */ + rtreeBeginTransaction, /* xBegin - begin transaction */ + rtreeEndTransaction, /* xSync - sync transaction */ + rtreeEndTransaction, /* xCommit - commit transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ + 0, /* xFindFunction - function overloading */ + rtreeRename, /* xRename - rename the table */ + rtreeSavepoint, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + rtreeShadowName /* xShadowName */ +}; -/* Remove the search point with the lowest current score. -*/ -static void rtreeSearchPointPop(RtreeCursor *p){ - int i, j, k, n; - i = 1 - p->bPoint; - assert( i==0 || i==1 ); - if( p->aNode[i] ){ - nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]); - p->aNode[i] = 0; - } - if( p->bPoint ){ - p->anQueue[p->sPoint.iLevel]--; - p->bPoint = 0; - }else if( p->nPoint ){ - p->anQueue[p->aPoint[0].iLevel]--; - n = --p->nPoint; - p->aPoint[0] = p->aPoint[n]; - if( naNode[1] = p->aNode[n+1]; - p->aNode[n+1] = 0; +static int rtreeSqlInit( + Rtree *pRtree, + sqlite3 *db, + const char *zDb, + const char *zPrefix, + int isCreate +){ + int rc = SQLITE_OK; + + #define N_STATEMENT 8 + static const char *azSql[N_STATEMENT] = { + /* Write the xxx_node table */ + "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(?1, ?2)", + "DELETE FROM '%q'.'%q_node' WHERE nodeno = ?1", + + /* Read and write the xxx_rowid table */ + "SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = ?1", + "INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(?1, ?2)", + "DELETE FROM '%q'.'%q_rowid' WHERE rowid = ?1", + + /* Read and write the xxx_parent table */ + "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = ?1", + "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(?1, ?2)", + "DELETE FROM '%q'.'%q_parent' WHERE nodeno = ?1" + }; + sqlite3_stmt **appStmt[N_STATEMENT]; + int i; + const int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; + + pRtree->db = db; + + if( isCreate ){ + char *zCreate; + sqlite3_str *p = sqlite3_str_new(db); + int ii; + sqlite3_str_appendf(p, + "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno", + zDb, zPrefix); + for(ii=0; iinAux; ii++){ + sqlite3_str_appendf(p,",a%d",ii); + } + sqlite3_str_appendf(p, + ");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);", + zDb, zPrefix); + sqlite3_str_appendf(p, + "CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);", + zDb, zPrefix); + sqlite3_str_appendf(p, + "INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))", + zDb, zPrefix, pRtree->iNodeSize); + zCreate = sqlite3_str_finish(p); + if( !zCreate ){ + return SQLITE_NOMEM; } - i = 0; - while( (j = i*2+1)aPoint[k], &p->aPoint[j])<0 ){ - if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){ - rtreeSearchPointSwap(p, i, k); - i = k; - }else{ - break; - } - }else{ - if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){ - rtreeSearchPointSwap(p, i, j); - i = j; - }else{ - break; - } - } + rc = sqlite3_exec(db, zCreate, 0, 0, 0); + sqlite3_free(zCreate); + if( rc!=SQLITE_OK ){ + return rc; } } -} + appStmt[0] = &pRtree->pWriteNode; + appStmt[1] = &pRtree->pDeleteNode; + appStmt[2] = &pRtree->pReadRowid; + appStmt[3] = &pRtree->pWriteRowid; + appStmt[4] = &pRtree->pDeleteRowid; + appStmt[5] = &pRtree->pReadParent; + appStmt[6] = &pRtree->pWriteParent; + appStmt[7] = &pRtree->pDeleteParent; -/* -** Continue the search on cursor pCur until the front of the queue -** contains an entry suitable for returning as a result-set row, -** or until the RtreeSearchPoint queue is empty, indicating that the -** query has completed. -*/ -static int rtreeStepToLeaf(RtreeCursor *pCur){ - RtreeSearchPoint *p; - Rtree *pRtree = RTREE_OF_CURSOR(pCur); - RtreeNode *pNode; - int eWithin; - int rc = SQLITE_OK; - int nCell; - int nConstraint = pCur->nConstraint; - int ii; - int eInt; - RtreeSearchPoint x; - - eInt = pRtree->eCoordType==RTREE_COORD_INT32; - while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ - pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc); - if( rc ) return rc; - nCell = NCELL(pNode); - assert( nCell<200 ); - while( p->iCellzData + (4+pRtree->nBytesPerCell*p->iCell); - eWithin = FULLY_WITHIN; - for(ii=0; iiaConstraint + ii; - if( pConstraint->op>=RTREE_MATCH ){ - rc = rtreeCallbackConstraint(pConstraint, eInt, pCellData, p, - &rScore, &eWithin); - if( rc ) return rc; - }else if( p->iLevel==1 ){ - rtreeLeafConstraint(pConstraint, eInt, pCellData, &eWithin); - }else{ - rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin); + rc = rtreeQueryStat1(db, pRtree); + for(i=0; inAux==0 ){ + zFormat = azSql[i]; + }else { + /* An UPSERT is very slightly slower than REPLACE, but it is needed + ** if there are auxiliary columns */ + zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)" + "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno"; + } + zSql = sqlite3_mprintf(zFormat, zDb, zPrefix); + if( zSql ){ + rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0); + }else{ + rc = SQLITE_NOMEM; + } + sqlite3_free(zSql); + } + if( pRtree->nAux ){ + pRtree->zReadAuxSql = sqlite3_mprintf( + "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1", + zDb, zPrefix); + if( pRtree->zReadAuxSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + sqlite3_str *p = sqlite3_str_new(db); + int ii; + char *zSql; + sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); + for(ii=0; iinAux; ii++){ + if( ii ) sqlite3_str_append(p, ",", 1); +#ifdef SQLITE_ENABLE_GEOPOLY + if( iinAuxNotNull ){ + sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); + }else +#endif + { + sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); } - if( eWithin==NOT_WITHIN ) break; } - p->iCell++; - if( eWithin==NOT_WITHIN ) continue; - x.iLevel = p->iLevel - 1; - if( x.iLevel ){ - x.id = readInt64(pCellData); - x.iCell = 0; + sqlite3_str_appendf(p, " WHERE rowid=?1"); + zSql = sqlite3_str_finish(p); + if( zSql==0 ){ + rc = SQLITE_NOMEM; }else{ - x.id = p->id; - x.iCell = p->iCell - 1; - } - if( p->iCell>=nCell ){ - RTREE_QUEUE_TRACE(pCur, "POP-S:"); - rtreeSearchPointPop(pCur); + rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0); + sqlite3_free(zSql); } - if( rScoreeWithin = (u8)eWithin; - p->id = x.id; - p->iCell = x.iCell; - RTREE_QUEUE_TRACE(pCur, "PUSH-S:"); - break; - } - if( p->iCell>=nCell ){ - RTREE_QUEUE_TRACE(pCur, "POP-Se:"); - rtreeSearchPointPop(pCur); } } - pCur->atEOF = p==0; - return SQLITE_OK; -} - -/* -** Rtree virtual table module xNext method. -*/ -static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ - RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - int rc = SQLITE_OK; - /* Move to the next entry that matches the configured constraints. */ - RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); - rtreeSearchPointPop(pCsr); - rc = rtreeStepToLeaf(pCsr); return rc; } -/* -** Rtree virtual table module xRowid method. +/* +** The second argument to this function contains the text of an SQL statement +** that returns a single integer value. The statement is compiled and executed +** using database connection db. If successful, the integer value returned +** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error +** code is returned and the value of *piVal after returning is not defined. */ -static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){ - RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); - int rc = SQLITE_OK; - RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); - if( rc==SQLITE_OK && p ){ - *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); +static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){ + int rc = SQLITE_NOMEM; + if( zSql ){ + sqlite3_stmt *pStmt = 0; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + *piVal = sqlite3_column_int(pStmt, 0); + } + rc = sqlite3_finalize(pStmt); + } } return rc; } -/* -** Rtree virtual table module xColumn method. +/* +** This function is called from within the xConnect() or xCreate() method to +** determine the node-size used by the rtree table being created or connected +** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned. +** Otherwise, an SQLite error code is returned. +** +** If this function is being called as part of an xConnect(), then the rtree +** table already exists. In this case the node-size is determined by inspecting +** the root node of the tree. +** +** Otherwise, for an xCreate(), use 64 bytes less than the database page-size. +** This ensures that each node is stored on a single database page. If the +** database page-size is so large that more than RTREE_MAXCELLS entries +** would fit in a single node, use a smaller node-size. */ -static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ - Rtree *pRtree = (Rtree *)cur->pVtab; - RtreeCursor *pCsr = (RtreeCursor *)cur; - RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); - RtreeCoord c; - int rc = SQLITE_OK; - RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); - - if( rc ) return rc; - if( p==0 ) return SQLITE_OK; - if( i==0 ){ - sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); +static int getNodeSize( + sqlite3 *db, /* Database handle */ + Rtree *pRtree, /* Rtree handle */ + int isCreate, /* True for xCreate, false for xConnect */ + char **pzErr /* OUT: Error message, if any */ +){ + int rc; + char *zSql; + if( isCreate ){ + int iPageSize = 0; + zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb); + rc = getIntFromStmt(db, zSql, &iPageSize); + if( rc==SQLITE_OK ){ + pRtree->iNodeSize = iPageSize-64; + if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)iNodeSize ){ + pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS; + } + }else{ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } }else{ - nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); -#ifndef SQLITE_RTREE_INT_ONLY - if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ - sqlite3_result_double(ctx, c.f); - }else -#endif - { - assert( pRtree->eCoordType==RTREE_COORD_INT32 ); - sqlite3_result_int(ctx, c.i); + zSql = sqlite3_mprintf( + "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1", + pRtree->zDb, pRtree->zName + ); + rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); + if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + }else if( pRtree->iNodeSize<(512-64) ){ + rc = SQLITE_CORRUPT_VTAB; + RTREE_IS_CORRUPT(pRtree); + *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"", + pRtree->zName); } } - return SQLITE_OK; + + sqlite3_free(zSql); + return rc; } -/* -** Use nodeAcquire() to obtain the leaf node containing the record with -** rowid iRowid. If successful, set *ppLeaf to point to the node and -** return SQLITE_OK. If there is no such record in the table, set -** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf -** to zero and return an SQLite error code. +/* +** Return the length of a token */ -static int findLeafNode( - Rtree *pRtree, /* RTree to search */ - i64 iRowid, /* The rowid searching for */ - RtreeNode **ppLeaf, /* Write the node here */ - sqlite3_int64 *piNode /* Write the node-id here */ -){ - int rc; - *ppLeaf = 0; - sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); - if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ - i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); - if( piNode ) *piNode = iNode; - rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); - sqlite3_reset(pRtree->pReadRowid); - }else{ - rc = sqlite3_reset(pRtree->pReadRowid); - } - return rc; +static int rtreeTokenLength(const char *z){ + int dummy = 0; + return sqlite3GetToken((const unsigned char*)z,&dummy); } /* -** This function is called to configure the RtreeConstraint object passed -** as the second argument for a MATCH constraint. The value passed as the -** first argument to this function is the right-hand operand to the MATCH -** operator. +** This function is the implementation of both the xConnect and xCreate +** methods of the r-tree virtual table. +** +** argv[0] -> module name +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> column names... */ -static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){ - RtreeMatchArg *pBlob; /* BLOB returned by geometry function */ - sqlite3_rtree_query_info *pInfo; /* Callback information */ - int nBlob; /* Size of the geometry function blob */ - int nExpected; /* Expected size of the BLOB */ +static int rtreeInit( + sqlite3 *db, /* Database connection */ + void *pAux, /* One of the RTREE_COORD_* constants */ + int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ + sqlite3_vtab **ppVtab, /* OUT: New virtual table */ + char **pzErr, /* OUT: Error message, if any */ + int isCreate /* True for xCreate, false for xConnect */ +){ + int rc = SQLITE_OK; + Rtree *pRtree; + int nDb; /* Length of string argv[1] */ + int nName; /* Length of string argv[2] */ + int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32); + sqlite3_str *pSql; + char *zSql; + int ii = 4; + int iErr; - /* Check that value is actually a blob. */ - if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR; + const char *aErrMsg[] = { + 0, /* 0 */ + "Wrong number of columns for an rtree table", /* 1 */ + "Too few columns for an rtree table", /* 2 */ + "Too many columns for an rtree table", /* 3 */ + "Auxiliary rtree columns must be last" /* 4 */ + }; - /* Check that the blob is roughly the right size. */ - nBlob = sqlite3_value_bytes(pValue); - if( nBlob<(int)sizeof(RtreeMatchArg) ){ + assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ + if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){ + *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]); return SQLITE_ERROR; } - pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob ); - if( !pInfo ) return SQLITE_NOMEM; - memset(pInfo, 0, sizeof(*pInfo)); - pBlob = (RtreeMatchArg*)&pInfo[1]; - - memcpy(pBlob, sqlite3_value_blob(pValue), nBlob); - nExpected = (int)(sizeof(RtreeMatchArg) + - pBlob->nParam*sizeof(sqlite3_value*) + - (pBlob->nParam-1)*sizeof(RtreeDValue)); - if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){ - sqlite3_free(pInfo); - return SQLITE_ERROR; - } - pInfo->pContext = pBlob->cb.pContext; - pInfo->nParam = pBlob->nParam; - pInfo->aParam = pBlob->aParam; - pInfo->apSqlParam = pBlob->apSqlParam; + sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); - if( pBlob->cb.xGeom ){ - pCons->u.xGeom = pBlob->cb.xGeom; - }else{ - pCons->op = RTREE_QUERY; - pCons->u.xQueryFunc = pBlob->cb.xQueryFunc; + /* Allocate the sqlite3_vtab structure */ + nDb = (int)strlen(argv[1]); + nName = (int)strlen(argv[2]); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); + if( !pRtree ){ + return SQLITE_NOMEM; } - pCons->pInfo = pInfo; - return SQLITE_OK; -} - -/* -** Rtree virtual table module xFilter method. -*/ -static int rtreeFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv -){ - Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; - RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; - RtreeNode *pRoot = 0; - int ii; - int rc = SQLITE_OK; - int iCell = 0; - - rtreeReference(pRtree); + memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); + pRtree->nBusy = 1; + pRtree->base.pModule = &rtreeModule; + pRtree->zDb = (char *)&pRtree[1]; + pRtree->zName = &pRtree->zDb[nDb+1]; + pRtree->eCoordType = (u8)eCoordType; + memcpy(pRtree->zDb, argv[1], nDb); + memcpy(pRtree->zName, argv[2], nName); - /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ - freeCursorConstraints(pCsr); - sqlite3_free(pCsr->aPoint); - memset(pCsr, 0, sizeof(RtreeCursor)); - pCsr->base.pVtab = (sqlite3_vtab*)pRtree; - pCsr->iStrategy = idxNum; - if( idxNum==1 ){ - /* Special case - lookup by rowid. */ - RtreeNode *pLeaf; /* Leaf on which the required cell resides */ - RtreeSearchPoint *p; /* Search point for the leaf */ - i64 iRowid = sqlite3_value_int64(argv[0]); - i64 iNode = 0; - rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); - if( rc==SQLITE_OK && pLeaf!=0 ){ - p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); - assert( p!=0 ); /* Always returns pCsr->sPoint */ - pCsr->aNode[0] = pLeaf; - p->id = iNode; - p->eWithin = PARTLY_WITHIN; - rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); - p->iCell = (u8)iCell; - RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); + /* Create/Connect to the underlying relational database schema. If + ** that is successful, call sqlite3_declare_vtab() to configure + ** the r-tree table schema. + */ + pSql = sqlite3_str_new(db); + sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT", + rtreeTokenLength(argv[3]), argv[3]); + for(ii=4; iinAux++; + sqlite3_str_appendf(pSql, ",%.*s", rtreeTokenLength(zArg+1), zArg+1); + }else if( pRtree->nAux>0 ){ + break; }else{ - pCsr->atEOF = 1; - } - }else{ - /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array - ** with the configured constraints. - */ - rc = nodeAcquire(pRtree, 1, 0, &pRoot); - if( rc==SQLITE_OK && argc>0 ){ - pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc); - pCsr->nConstraint = argc; - if( !pCsr->aConstraint ){ - rc = SQLITE_NOMEM; - }else{ - memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); - memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); - assert( (idxStr==0 && argc==0) - || (idxStr && (int)strlen(idxStr)==argc*2) ); - for(ii=0; iiaConstraint[ii]; - p->op = idxStr[ii*2]; - p->iCoord = idxStr[ii*2+1]-'0'; - if( p->op>=RTREE_MATCH ){ - /* A MATCH operator. The right-hand-side must be a blob that - ** can be cast into an RtreeMatchArg object. One created using - ** an sqlite3_rtree_geometry_callback() SQL user function. - */ - rc = deserializeGeometry(argv[ii], p); - if( rc!=SQLITE_OK ){ - break; - } - p->pInfo->nCoord = pRtree->nDim2; - p->pInfo->anQueue = pCsr->anQueue; - p->pInfo->mxLevel = pRtree->iDepth + 1; - }else{ -#ifdef SQLITE_RTREE_INT_ONLY - p->u.rValue = sqlite3_value_int64(argv[ii]); -#else - p->u.rValue = sqlite3_value_double(argv[ii]); -#endif - } - } - } - } - if( rc==SQLITE_OK ){ - RtreeSearchPoint *pNew; - pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); - if( pNew==0 ) return SQLITE_NOMEM; - pNew->id = 1; - pNew->iCell = 0; - pNew->eWithin = PARTLY_WITHIN; - assert( pCsr->bPoint==1 ); - pCsr->aNode[0] = pRoot; - pRoot = 0; - RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); - rc = rtreeStepToLeaf(pCsr); + static const char *azFormat[] = {",%.*s REAL", ",%.*s INT"}; + pRtree->nDim2++; + sqlite3_str_appendf(pSql, azFormat[eCoordType], + rtreeTokenLength(zArg), zArg); } } + sqlite3_str_appendf(pSql, ");"); + zSql = sqlite3_str_finish(pSql); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else if( iinDim = pRtree->nDim2/2; + if( pRtree->nDim<1 ){ + iErr = 2; + }else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){ + iErr = 3; + }else if( pRtree->nDim2 % 2 ){ + iErr = 1; + }else{ + iErr = 0; + } + if( iErr ){ + *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); + goto rtreeInit_fail; + } + pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; - nodeRelease(pRtree, pRoot); + /* Figure out the node size to use. */ + rc = getNodeSize(db, pRtree, isCreate, pzErr); + if( rc ) goto rtreeInit_fail; + rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); + if( rc ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + goto rtreeInit_fail; + } + + *ppVtab = (sqlite3_vtab *)pRtree; + return SQLITE_OK; + +rtreeInit_fail: + if( rc==SQLITE_OK ) rc = SQLITE_ERROR; + assert( *ppVtab==0 ); + assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); return rc; } + /* -** Rtree virtual table module xBestIndex method. There are three -** table scan strategies to choose from (in order from most to -** least desirable): -** -** idxNum idxStr Strategy -** ------------------------------------------------ -** 1 Unused Direct lookup by rowid. -** 2 See below R-tree query or full-table scan. -** ------------------------------------------------ -** -** If strategy 1 is used, then idxStr is not meaningful. If strategy -** 2 is used, idxStr is formatted to contain 2 bytes for each -** constraint used. The first two bytes of idxStr correspond to -** the constraint in sqlite3_index_info.aConstraintUsage[] with -** (argvIndex==1) etc. +** Implementation of a scalar function that decodes r-tree nodes to +** human readable strings. This can be used for debugging and analysis. ** -** The first of each pair of bytes in idxStr identifies the constraint -** operator as follows: +** The scalar function takes two arguments: (1) the number of dimensions +** to the rtree (between 1 and 5, inclusive) and (2) a blob of data containing +** an r-tree node. For a two-dimensional r-tree structure called "rt", to +** deserialize all nodes, a statement like: ** -** Operator Byte Value -** ---------------------- -** = 0x41 ('A') -** <= 0x42 ('B') -** < 0x43 ('C') -** >= 0x44 ('D') -** > 0x45 ('E') -** MATCH 0x46 ('F') -** ---------------------- +** SELECT rtreenode(2, data) FROM rt_node; ** -** The second of each pair of bytes identifies the coordinate column -** to which the constraint applies. The leftmost coordinate column -** is 'a', the second from the left 'b' etc. +** The human readable string takes the form of a Tcl list with one +** entry for each cell in the r-tree node. Each entry is itself a +** list, containing the 8-byte rowid/pageno followed by the +** *2 coordinates. */ -static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ - Rtree *pRtree = (Rtree*)tab; - int rc = SQLITE_OK; +static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ + RtreeNode node; + Rtree tree; int ii; - int bMatch = 0; /* True if there exists a MATCH constraint */ - i64 nRow; /* Estimated rows returned by this scan */ - - int iIdx = 0; - char zIdxStr[RTREE_MAX_DIMENSIONS*8+1]; - memset(zIdxStr, 0, sizeof(zIdxStr)); - - /* Check if there exists a MATCH constraint - even an unusable one. If there - ** is, do not consider the lookup-by-rowid plan as using such a plan would - ** require the VDBE to evaluate the MATCH constraint, which is not currently - ** possible. */ - for(ii=0; iinConstraint; ii++){ - if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){ - bMatch = 1; - } - } - - assert( pIdxInfo->idxStr==0 ); - for(ii=0; iinConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ - struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; - - if( bMatch==0 && p->usable - && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ - ){ - /* We have an equality constraint on the rowid. Use strategy 1. */ - int jj; - for(jj=0; jjaConstraintUsage[jj].argvIndex = 0; - pIdxInfo->aConstraintUsage[jj].omit = 0; - } - pIdxInfo->idxNum = 1; - pIdxInfo->aConstraintUsage[ii].argvIndex = 1; - pIdxInfo->aConstraintUsage[jj].omit = 1; - - /* This strategy involves a two rowid lookups on an B-Tree structures - ** and then a linear search of an R-Tree node. This should be - ** considered almost as quick as a direct rowid lookup (for which - ** sqlite uses an internal cost of 0.0). It is expected to return - ** a single row. - */ - pIdxInfo->estimatedCost = 30.0; - pIdxInfo->estimatedRows = 1; - return SQLITE_OK; - } - - if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ - u8 op; - switch( p->op ){ - case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; - case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; - case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; - case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; - case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; - default: - assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH ); - op = RTREE_MATCH; - break; - } - zIdxStr[iIdx++] = op; - zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0'); - pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); - pIdxInfo->aConstraintUsage[ii].omit = 1; - } - } + int nData; + int errCode; + sqlite3_str *pOut; - pIdxInfo->idxNum = 2; - pIdxInfo->needToFreeIdxStr = 1; - if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ - return SQLITE_NOMEM; - } + UNUSED_PARAMETER(nArg); + memset(&node, 0, sizeof(RtreeNode)); + memset(&tree, 0, sizeof(Rtree)); + tree.nDim = (u8)sqlite3_value_int(apArg[0]); + if( tree.nDim<1 || tree.nDim>5 ) return; + tree.nDim2 = tree.nDim*2; + tree.nBytesPerCell = 8 + 8 * tree.nDim; + node.zData = (u8 *)sqlite3_value_blob(apArg[1]); + if( node.zData==0 ) return; + nData = sqlite3_value_bytes(apArg[1]); + if( nData<4 ) return; + if( nDatanRowEst >> (iIdx/2); - pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; - pIdxInfo->estimatedRows = nRow; + pOut = sqlite3_str_new(0); + for(ii=0; ii0 ) sqlite3_str_append(pOut, " ", 1); + sqlite3_str_appendf(pOut, "{%lld", cell.iRowid); + for(jj=0; jjnDim>=1 && pRtree->nDim<=5 ); -#ifndef SQLITE_RTREE_INT_ONLY - if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ - switch( pRtree->nDim ){ - case 5: area = p->aCoord[9].f - p->aCoord[8].f; - case 4: area *= p->aCoord[7].f - p->aCoord[6].f; - case 3: area *= p->aCoord[5].f - p->aCoord[4].f; - case 2: area *= p->aCoord[3].f - p->aCoord[2].f; - default: area *= p->aCoord[1].f - p->aCoord[0].f; - } - }else -#endif - { - switch( pRtree->nDim ){ - case 5: area = p->aCoord[9].i - p->aCoord[8].i; - case 4: area *= p->aCoord[7].i - p->aCoord[6].i; - case 3: area *= p->aCoord[5].i - p->aCoord[4].i; - case 2: area *= p->aCoord[3].i - p->aCoord[2].i; - default: area *= p->aCoord[1].i - p->aCoord[0].i; +static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ + UNUSED_PARAMETER(nArg); + if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB + || sqlite3_value_bytes(apArg[0])<2 + + ){ + sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); + }else{ + u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]); + if( zBlob ){ + sqlite3_result_int(ctx, readInt16(zBlob)); + }else{ + sqlite3_result_error_nomem(ctx); } } - return area; } /* -** Return the margin length of cell p. The margin length is the sum -** of the objects size in each dimension. +** Context object passed between the various routines that make up the +** implementation of integrity-check function rtreecheck(). */ -static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){ - RtreeDValue margin = 0; - int ii = pRtree->nDim2 - 2; - do{ - margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); - ii -= 2; - }while( ii>=0 ); - return margin; -} +typedef struct RtreeCheck RtreeCheck; +struct RtreeCheck { + sqlite3 *db; /* Database handle */ + const char *zDb; /* Database containing rtree table */ + const char *zTab; /* Name of rtree table */ + int bInt; /* True for rtree_i32 table */ + int nDim; /* Number of dimensions for this rtree tbl */ + sqlite3_stmt *pGetNode; /* Statement used to retrieve nodes */ + sqlite3_stmt *aCheckMapping[2]; /* Statements to query %_parent/%_rowid */ + int nLeaf; /* Number of leaf cells in table */ + int nNonLeaf; /* Number of non-leaf cells in table */ + int rc; /* Return code */ + char *zReport; /* Message to report */ + int nErr; /* Number of lines in zReport */ +}; + +#define RTREE_CHECK_MAX_ERROR 100 /* -** Store the union of cells p1 and p2 in p1. +** Reset SQL statement pStmt. If the sqlite3_reset() call returns an error, +** and RtreeCheck.rc==SQLITE_OK, set RtreeCheck.rc to the error code. */ -static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ - int ii = 0; - if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ - do{ - p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f); - p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f); - ii += 2; - }while( iinDim2 ); - }else{ - do{ - p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i); - p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i); - ii += 2; - }while( iinDim2 ); - } +static void rtreeCheckReset(RtreeCheck *pCheck, sqlite3_stmt *pStmt){ + int rc = sqlite3_reset(pStmt); + if( pCheck->rc==SQLITE_OK ) pCheck->rc = rc; } /* -** Return true if the area covered by p2 is a subset of the area covered -** by p1. False otherwise. +** The second and subsequent arguments to this function are a format string +** and printf style arguments. This function formats the string and attempts +** to compile it as an SQL statement. +** +** If successful, a pointer to the new SQL statement is returned. Otherwise, +** NULL is returned and an error code left in RtreeCheck.rc. */ -static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ - int ii; - int isInt = (pRtree->eCoordType==RTREE_COORD_INT32); - for(ii=0; iinDim2; ii+=2){ - RtreeCoord *a1 = &p1->aCoord[ii]; - RtreeCoord *a2 = &p2->aCoord[ii]; - if( (!isInt && (a2[0].fa1[1].f)) - || ( isInt && (a2[0].ia1[1].i)) - ){ - return 0; +static sqlite3_stmt *rtreeCheckPrepare( + RtreeCheck *pCheck, /* RtreeCheck object */ + const char *zFmt, ... /* Format string and trailing args */ +){ + va_list ap; + char *z; + sqlite3_stmt *pRet = 0; + + va_start(ap, zFmt); + z = sqlite3_vmprintf(zFmt, ap); + + if( pCheck->rc==SQLITE_OK ){ + if( z==0 ){ + pCheck->rc = SQLITE_NOMEM; + }else{ + pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0); } } - return 1; + + sqlite3_free(z); + va_end(ap); + return pRet; } /* -** Return the amount cell p would grow by if it were unioned with pCell. +** The second and subsequent arguments to this function are a printf() +** style format string and arguments. This function formats the string and +** appends it to the report being accumuated in pCheck. */ -static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ - RtreeDValue area; - RtreeCell cell; - memcpy(&cell, p, sizeof(RtreeCell)); - area = cellArea(pRtree, &cell); - cellUnion(pRtree, &cell, pCell); - return (cellArea(pRtree, &cell)-area); -} - -static RtreeDValue cellOverlap( - Rtree *pRtree, - RtreeCell *p, - RtreeCell *aCell, - int nCell -){ - int ii; - RtreeDValue overlap = RTREE_ZERO; - for(ii=0; iinDim2; jj+=2){ - RtreeDValue x1, x2; - x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); - x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); - if( x2rc==SQLITE_OK && pCheck->nErrrc = SQLITE_NOMEM; + }else{ + pCheck->zReport = sqlite3_mprintf("%z%s%z", + pCheck->zReport, (pCheck->zReport ? "\n" : ""), z + ); + if( pCheck->zReport==0 ){ + pCheck->rc = SQLITE_NOMEM; } } - overlap += o; + pCheck->nErr++; } - return overlap; + va_end(ap); } - /* -** This function implements the ChooseLeaf algorithm from Gutman[84]. -** ChooseSubTree in r*tree terminology. +** This function is a no-op if there is already an error code stored +** in the RtreeCheck object indicated by the first argument. NULL is +** returned in this case. +** +** Otherwise, the contents of rtree table node iNode are loaded from +** the database and copied into a buffer obtained from sqlite3_malloc(). +** If no error occurs, a pointer to the buffer is returned and (*pnNode) +** is set to the size of the buffer in bytes. +** +** Or, if an error does occur, NULL is returned and an error code left +** in the RtreeCheck object. The final value of *pnNode is undefined in +** this case. */ -static int ChooseLeaf( - Rtree *pRtree, /* Rtree table */ - RtreeCell *pCell, /* Cell to insert into rtree */ - int iHeight, /* Height of sub-tree rooted at pCell */ - RtreeNode **ppLeaf /* OUT: Selected leaf page */ -){ - int rc; - int ii; - RtreeNode *pNode; - rc = nodeAcquire(pRtree, 1, 0, &pNode); +static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){ + u8 *pRet = 0; /* Return value */ - for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){ - int iCell; - sqlite3_int64 iBest = 0; - - RtreeDValue fMinGrowth = RTREE_ZERO; - RtreeDValue fMinArea = RTREE_ZERO; - - int nCell = NCELL(pNode); - RtreeCell cell; - RtreeNode *pChild; - - RtreeCell *aCell = 0; + if( pCheck->rc==SQLITE_OK && pCheck->pGetNode==0 ){ + pCheck->pGetNode = rtreeCheckPrepare(pCheck, + "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", + pCheck->zDb, pCheck->zTab + ); + } - /* Select the child node which will be enlarged the least if pCell - ** is inserted into it. Resolve ties by choosing the entry with - ** the smallest area. - */ - for(iCell=0; iCellrc==SQLITE_OK ){ + sqlite3_bind_int64(pCheck->pGetNode, 1, iNode); + if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){ + int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0); + const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0); + pRet = sqlite3_malloc64(nNode); + if( pRet==0 ){ + pCheck->rc = SQLITE_NOMEM; + }else{ + memcpy(pRet, pNode, nNode); + *pnNode = nNode; } } - - sqlite3_free(aCell); - rc = nodeAcquire(pRtree, iBest, pNode, &pChild); - nodeRelease(pRtree, pNode); - pNode = pChild; + rtreeCheckReset(pCheck, pCheck->pGetNode); + if( pCheck->rc==SQLITE_OK && pRet==0 ){ + rtreeCheckAppendMsg(pCheck, "Node %lld missing from database", iNode); + } } - *ppLeaf = pNode; - return rc; + return pRet; } /* -** A cell with the same content as pCell has just been inserted into -** the node pNode. This function updates the bounding box cells in -** all ancestor elements. +** This function is used to check that the %_parent (if bLeaf==0) or %_rowid +** (if bLeaf==1) table contains a specified entry. The schemas of the +** two tables are: +** +** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) +** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...) +** +** In both cases, this function checks that there exists an entry with +** IPK value iKey and the second column set to iVal. +** */ -static int AdjustTree( - Rtree *pRtree, /* Rtree table */ - RtreeNode *pNode, /* Adjust ancestry of this node. */ - RtreeCell *pCell /* This cell was just inserted */ +static void rtreeCheckMapping( + RtreeCheck *pCheck, /* RtreeCheck object */ + int bLeaf, /* True for a leaf cell, false for interior */ + i64 iKey, /* Key for mapping */ + i64 iVal /* Expected value for mapping */ ){ - RtreeNode *p = pNode; - while( p->pParent ){ - RtreeNode *pParent = p->pParent; - RtreeCell cell; - int iCell; + int rc; + sqlite3_stmt *pStmt; + const char *azSql[2] = { + "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1", + "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1" + }; - if( nodeParentIndex(pRtree, p, &iCell) ){ - return SQLITE_CORRUPT_VTAB; - } + assert( bLeaf==0 || bLeaf==1 ); + if( pCheck->aCheckMapping[bLeaf]==0 ){ + pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck, + azSql[bLeaf], pCheck->zDb, pCheck->zTab + ); + } + if( pCheck->rc!=SQLITE_OK ) return; - nodeGetCell(pRtree, pParent, iCell, &cell); - if( !cellContains(pRtree, &cell, pCell) ){ - cellUnion(pRtree, &cell, pCell); - nodeOverwriteCell(pRtree, pParent, &cell, iCell); + pStmt = pCheck->aCheckMapping[bLeaf]; + sqlite3_bind_int64(pStmt, 1, iKey); + rc = sqlite3_step(pStmt); + if( rc==SQLITE_DONE ){ + rtreeCheckAppendMsg(pCheck, "Mapping (%lld -> %lld) missing from %s table", + iKey, iVal, (bLeaf ? "%_rowid" : "%_parent") + ); + }else if( rc==SQLITE_ROW ){ + i64 ii = sqlite3_column_int64(pStmt, 0); + if( ii!=iVal ){ + rtreeCheckAppendMsg(pCheck, + "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)", + iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal + ); } - - p = pParent; } - return SQLITE_OK; -} - -/* -** Write mapping (iRowid->iNode) to the _rowid table. -*/ -static int rowidWrite(Rtree *pRtree, sqlite3_int64 iRowid, sqlite3_int64 iNode){ - sqlite3_bind_int64(pRtree->pWriteRowid, 1, iRowid); - sqlite3_bind_int64(pRtree->pWriteRowid, 2, iNode); - sqlite3_step(pRtree->pWriteRowid); - return sqlite3_reset(pRtree->pWriteRowid); -} - -/* -** Write mapping (iNode->iPar) to the _parent table. -*/ -static int parentWrite(Rtree *pRtree, sqlite3_int64 iNode, sqlite3_int64 iPar){ - sqlite3_bind_int64(pRtree->pWriteParent, 1, iNode); - sqlite3_bind_int64(pRtree->pWriteParent, 2, iPar); - sqlite3_step(pRtree->pWriteParent); - return sqlite3_reset(pRtree->pWriteParent); + rtreeCheckReset(pCheck, pStmt); } -static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int); - - /* -** Arguments aIdx, aDistance and aSpare all point to arrays of size -** nIdx. The aIdx array contains the set of integers from 0 to -** (nIdx-1) in no particular order. This function sorts the values -** in aIdx according to the indexed values in aDistance. For -** example, assuming the inputs: -** -** aIdx = { 0, 1, 2, 3 } -** aDistance = { 5.0, 2.0, 7.0, 6.0 } -** -** this function sets the aIdx array to contain: -** -** aIdx = { 0, 1, 2, 3 } +** Argument pCell points to an array of coordinates stored on an rtree page. +** This function checks that the coordinates are internally consistent (no +** x1>x2 conditions) and adds an error message to the RtreeCheck object +** if they are not. ** -** The aSpare array is used as temporary working space by the -** sorting algorithm. +** Additionally, if pParent is not NULL, then it is assumed to point to +** the array of coordinates on the parent page that bound the page +** containing pCell. In this case it is also verified that the two +** sets of coordinates are mutually consistent and an error message added +** to the RtreeCheck object if they are not. */ -static void SortByDistance( - int *aIdx, - int nIdx, - RtreeDValue *aDistance, - int *aSpare +static void rtreeCheckCellCoord( + RtreeCheck *pCheck, + i64 iNode, /* Node id to use in error messages */ + int iCell, /* Cell number to use in error messages */ + u8 *pCell, /* Pointer to cell coordinates */ + u8 *pParent /* Pointer to parent coordinates */ ){ - if( nIdx>1 ){ - int iLeft = 0; - int iRight = 0; - - int nLeft = nIdx/2; - int nRight = nIdx-nLeft; - int *aLeft = aIdx; - int *aRight = &aIdx[nLeft]; - - SortByDistance(aLeft, nLeft, aDistance, aSpare); - SortByDistance(aRight, nRight, aDistance, aSpare); + RtreeCoord c1, c2; + RtreeCoord p1, p2; + int i; - memcpy(aSpare, aLeft, sizeof(int)*nLeft); - aLeft = aSpare; + for(i=0; inDim; i++){ + readCoord(&pCell[4*2*i], &c1); + readCoord(&pCell[4*(2*i + 1)], &c2); - while( iLeftbInt ? c1.i>c2.i : c1.f>c2.f ){ + rtreeCheckAppendMsg(pCheck, + "Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode + ); } -#if 0 - /* Check that the sort worked */ - { - int jj; - for(jj=1; jjbInt ? c1.ibInt ? c2.i>p2.i : c2.f>p2.f) + ){ + rtreeCheckAppendMsg(pCheck, + "Dimension %d of cell %d on node %lld is corrupt relative to parent" + , i, iCell, iNode + ); } } -#endif } } /* -** Arguments aIdx, aCell and aSpare all point to arrays of size -** nIdx. The aIdx array contains the set of integers from 0 to -** (nIdx-1) in no particular order. This function sorts the values -** in aIdx according to dimension iDim of the cells in aCell. The -** minimum value of dimension iDim is considered first, the -** maximum used to break ties. +** Run rtreecheck() checks on node iNode, which is at depth iDepth within +** the r-tree structure. Argument aParent points to the array of coordinates +** that bound node iNode on the parent node. ** -** The aSpare array is used as temporary working space by the -** sorting algorithm. +** If any problems are discovered, an error message is appended to the +** report accumulated in the RtreeCheck object. */ -static void SortByDimension( - Rtree *pRtree, - int *aIdx, - int nIdx, - int iDim, - RtreeCell *aCell, - int *aSpare +static void rtreeCheckNode( + RtreeCheck *pCheck, + int iDepth, /* Depth of iNode (0==leaf) */ + u8 *aParent, /* Buffer containing parent coords */ + i64 iNode /* Node to check */ ){ - if( nIdx>1 ){ - - int iLeft = 0; - int iRight = 0; - - int nLeft = nIdx/2; - int nRight = nIdx-nLeft; - int *aLeft = aIdx; - int *aRight = &aIdx[nLeft]; + u8 *aNode = 0; + int nNode = 0; - SortByDimension(pRtree, aLeft, nLeft, iDim, aCell, aSpare); - SortByDimension(pRtree, aRight, nRight, iDim, aCell, aSpare); + assert( iNode==1 || aParent!=0 ); + assert( pCheck->nDim>0 ); - memcpy(aSpare, aLeft, sizeof(int)*nLeft); - aLeft = aSpare; - while( iLeftRTREE_MAX_DEPTH ){ + rtreeCheckAppendMsg(pCheck, "Rtree depth out of range (%d)", iDepth); + sqlite3_free(aNode); + return; + } + } + nCell = readInt16(&aNode[2]); + if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){ + rtreeCheckAppendMsg(pCheck, + "Node %lld is too small for cell count of %d (%d bytes)", + iNode, nCell, nNode + ); }else{ - aIdx[iLeft+iRight] = aRight[iRight]; - iRight++; + for(i=0; inDim*2*4)]; + i64 iVal = readInt64(pCell); + rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent); + + if( iDepth>0 ){ + rtreeCheckMapping(pCheck, 0, iVal, iNode); + rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal); + pCheck->nNonLeaf++; + }else{ + rtreeCheckMapping(pCheck, 1, iVal, iNode); + pCheck->nLeaf++; + } + } } } + sqlite3_free(aNode); + } +} -#if 0 - /* Check that the sort worked */ - { - int jj; - for(jj=1; jjrc==SQLITE_OK ){ + sqlite3_stmt *pCount; + pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'", + pCheck->zDb, pCheck->zTab, zTbl + ); + if( pCount ){ + if( sqlite3_step(pCount)==SQLITE_ROW ){ + i64 nActual = sqlite3_column_int64(pCount, 0); + if( nActual!=nExpect ){ + rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table" + " - expected %lld, actual %lld" , zTbl, nExpect, nActual + ); + } } + pCheck->rc = sqlite3_finalize(pCount); } -#endif } } /* -** Implementation of the R*-tree variant of SplitNode from Beckman[1990]. +** This function does the bulk of the work for the rtree integrity-check. +** It is called by rtreecheck(), which is the SQL function implementation. */ -static int splitNodeStartree( - Rtree *pRtree, - RtreeCell *aCell, - int nCell, - RtreeNode *pLeft, - RtreeNode *pRight, - RtreeCell *pBboxLeft, - RtreeCell *pBboxRight +static int rtreeCheckTable( + sqlite3 *db, /* Database handle to access db through */ + const char *zDb, /* Name of db ("main", "temp" etc.) */ + const char *zTab, /* Name of rtree table to check */ + char **pzReport /* OUT: sqlite3_malloc'd report text */ ){ - int **aaSorted; - int *aSpare; - int ii; - - int iBestDim = 0; - int iBestSplit = 0; - RtreeDValue fBestMargin = RTREE_ZERO; + RtreeCheck check; /* Common context for various routines */ + sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */ + int bEnd = 0; /* True if transaction should be closed */ + int nAux = 0; /* Number of extra columns. */ - int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); + /* Initialize the context object */ + memset(&check, 0, sizeof(check)); + check.db = db; + check.zDb = zDb; + check.zTab = zTab; - aaSorted = (int **)sqlite3_malloc(nByte); - if( !aaSorted ){ - return SQLITE_NOMEM; + /* If there is not already an open transaction, open one now. This is + ** to ensure that the queries run as part of this integrity-check operate + ** on a consistent snapshot. */ + if( sqlite3_get_autocommit(db) ){ + check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); + bEnd = 1; } - aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell]; - memset(aaSorted, 0, nByte); - for(ii=0; iinDim; ii++){ - int jj; - aaSorted[ii] = &((int *)&aaSorted[pRtree->nDim])[ii*nCell]; - for(jj=0; jjnDim; ii++){ - RtreeDValue margin = RTREE_ZERO; - RtreeDValue fBestOverlap = RTREE_ZERO; - RtreeDValue fBestArea = RTREE_ZERO; - int iBestLeft = 0; - int nLeft; - - for( - nLeft=RTREE_MINCELLS(pRtree); - nLeft<=(nCell-RTREE_MINCELLS(pRtree)); - nLeft++ - ){ - RtreeCell left; - RtreeCell right; - int kk; - RtreeDValue overlap; - RtreeDValue area; - - memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); - memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); - for(kk=1; kk<(nCell-1); kk++){ - if( kk=1 ){ + if( check.rc==SQLITE_OK ){ + rtreeCheckNode(&check, 0, 0, 1); } + rtreeCheckCount(&check, "_rowid", check.nLeaf); + rtreeCheckCount(&check, "_parent", check.nNonLeaf); } - memcpy(pBboxLeft, &aCell[aaSorted[iBestDim][0]], sizeof(RtreeCell)); - memcpy(pBboxRight, &aCell[aaSorted[iBestDim][iBestSplit]], sizeof(RtreeCell)); - for(ii=0; ii); +** rtreecheck(, ); +** +** Invoking this SQL function runs an integrity-check on the named rtree +** table. The integrity-check verifies the following: +** +** 1. For each cell in the r-tree structure (%_node table), that: +** +** a) for each dimension, (coord1 <= coord2). +** +** b) unless the cell is on the root node, that the cell is bounded +** by the parent cell on the parent node. +** +** c) for leaf nodes, that there is an entry in the %_rowid +** table corresponding to the cell's rowid value that +** points to the correct node. +** +** d) for cells on non-leaf nodes, that there is an entry in the +** %_parent table mapping from the cell's child node to the +** node that it resides on. +** +** 2. That there are the same number of entries in the %_rowid table +** as there are leaf cells in the r-tree structure, and that there +** is a leaf cell that corresponds to each entry in the %_rowid table. +** +** 3. That there are the same number of entries in the %_parent table +** as there are non-leaf cells in the r-tree structure, and that +** there is a non-leaf cell that corresponds to each entry in the +** %_parent table. +*/ +static void rtreecheck( + sqlite3_context *ctx, + int nArg, + sqlite3_value **apArg ){ - int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64); - xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); - if( iHeight>0 ){ - RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); - if( pChild ){ - nodeRelease(pRtree, pChild->pParent); - nodeReference(pNode); - pChild->pParent = pNode; + if( nArg!=1 && nArg!=2 ){ + sqlite3_result_error(ctx, + "wrong number of arguments to function rtreecheck()", -1 + ); + }else{ + int rc; + char *zReport = 0; + const char *zDb = (const char*)sqlite3_value_text(apArg[0]); + const char *zTab; + if( nArg==1 ){ + zTab = zDb; + zDb = "main"; + }else{ + zTab = (const char*)sqlite3_value_text(apArg[1]); + } + rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport); + if( rc==SQLITE_OK ){ + sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT); + }else{ + sqlite3_result_error_code(ctx, rc); } + sqlite3_free(zReport); } - return xSetMapping(pRtree, iRowid, pNode->iNode); } -static int SplitNode( - Rtree *pRtree, - RtreeNode *pNode, - RtreeCell *pCell, - int iHeight -){ - int i; - int newCellIsRight = 0; +/* Conditionally include the geopoly code */ +#ifdef SQLITE_ENABLE_GEOPOLY +/************** Include geopoly.c in the middle of rtree.c *******************/ +/************** Begin file geopoly.c *****************************************/ +/* +** 2018-05-25 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file implements an alternative R-Tree virtual table that +** uses polygons to express the boundaries of 2-dimensional objects. +** +** This file is #include-ed onto the end of "rtree.c" so that it has +** access to all of the R-Tree internals. +*/ +/* #include */ - int rc = SQLITE_OK; - int nCell = NCELL(pNode); - RtreeCell *aCell; - int *aiUsed; +/* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */ +#ifdef GEOPOLY_ENABLE_DEBUG + static int geo_debug = 0; +# define GEODEBUG(X) if(geo_debug)printf X +#else +# define GEODEBUG(X) +#endif - RtreeNode *pLeft = 0; - RtreeNode *pRight = 0; +/* Character class routines */ +#ifdef sqlite3Isdigit + /* Use the SQLite core versions if this routine is part of the + ** SQLite amalgamation */ +# define safe_isdigit(x) sqlite3Isdigit(x) +# define safe_isalnum(x) sqlite3Isalnum(x) +# define safe_isxdigit(x) sqlite3Isxdigit(x) +#else + /* Use the standard library for separate compilation */ +#include /* amalgamator: keep */ +# define safe_isdigit(x) isdigit((unsigned char)(x)) +# define safe_isalnum(x) isalnum((unsigned char)(x)) +# define safe_isxdigit(x) isxdigit((unsigned char)(x)) +#endif - RtreeCell leftbbox; - RtreeCell rightbbox; +#ifndef JSON_NULL /* The following stuff repeats things found in json1 */ +/* +** Growing our own isspace() routine this way is twice as fast as +** the library isspace() function. +*/ +static const char geopolyIsSpace[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define fast_isspace(x) (geopolyIsSpace[(unsigned char)x]) +#endif /* JSON NULL - back to original code */ - /* Allocate an array and populate it with a copy of pCell and - ** all cells from node pLeft. Then zero the original node. - */ - aCell = sqlite3_malloc((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); - if( !aCell ){ - rc = SQLITE_NOMEM; - goto splitnode_out; - } - aiUsed = (int *)&aCell[nCell+1]; - memset(aiUsed, 0, sizeof(int)*(nCell+1)); - for(i=0; iiNode==1 ){ - pRight = nodeNew(pRtree, pNode); - pLeft = nodeNew(pRtree, pNode); - pRtree->iDepth++; - pNode->isDirty = 1; - writeInt16(pNode->zData, pRtree->iDepth); - }else{ - pLeft = pNode; - pRight = nodeNew(pRtree, pLeft->pParent); - nodeReference(pLeft); - } +/* Datatype for coordinates +*/ +typedef float GeoCoord; - if( !pLeft || !pRight ){ - rc = SQLITE_NOMEM; - goto splitnode_out; - } +/* +** Internal representation of a polygon. +** +** The polygon consists of a sequence of vertexes. There is a line +** segment between each pair of vertexes, and one final segment from +** the last vertex back to the first. (This differs from the GeoJSON +** standard in which the final vertex is a repeat of the first.) +** +** The polygon follows the right-hand rule. The area to the right of +** each segment is "outside" and the area to the left is "inside". +** +** The on-disk representation consists of a 4-byte header followed by +** the values. The 4-byte header is: +** +** encoding (1 byte) 0=big-endian, 1=little-endian +** nvertex (3 bytes) Number of vertexes as a big-endian integer +** +** Enough space is allocated for 4 coordinates, to work around over-zealous +** warnings coming from some compiler (notably, clang). In reality, the size +** of each GeoPoly memory allocate is adjusted as necessary so that the +** GeoPoly.a[] array at the end is the appropriate size. +*/ +typedef struct GeoPoly GeoPoly; +struct GeoPoly { + int nVertex; /* Number of vertexes */ + unsigned char hdr[4]; /* Header for on-disk representation */ + GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */ +}; - memset(pLeft->zData, 0, pRtree->iNodeSize); - memset(pRight->zData, 0, pRtree->iNodeSize); +/* The size of a memory allocation needed for a GeoPoly object sufficient +** to hold N coordinate pairs. +*/ +#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4)) - rc = splitNodeStartree(pRtree, aCell, nCell, pLeft, pRight, - &leftbbox, &rightbbox); - if( rc!=SQLITE_OK ){ - goto splitnode_out; - } +/* Macros to access coordinates of a GeoPoly. +** We have to use these macros, rather than just say p->a[i] in order +** to silence (incorrect) UBSAN warnings if the array index is too large. +*/ +#define GeoX(P,I) (((GeoCoord*)(P)->a)[(I)*2]) +#define GeoY(P,I) (((GeoCoord*)(P)->a)[(I)*2+1]) - /* Ensure both child nodes have node numbers assigned to them by calling - ** nodeWrite(). Node pRight always needs a node number, as it was created - ** by nodeNew() above. But node pLeft sometimes already has a node number. - ** In this case avoid the all to nodeWrite(). - */ - if( SQLITE_OK!=(rc = nodeWrite(pRtree, pRight)) - || (0==pLeft->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pLeft))) - ){ - goto splitnode_out; - } - rightbbox.iRowid = pRight->iNode; - leftbbox.iRowid = pLeft->iNode; +/* +** State of a parse of a GeoJSON input. +*/ +typedef struct GeoParse GeoParse; +struct GeoParse { + const unsigned char *z; /* Unparsed input */ + int nVertex; /* Number of vertexes in a[] */ + int nAlloc; /* Space allocated to a[] */ + int nErr; /* Number of errors encountered */ + GeoCoord *a; /* Array of vertexes. From sqlite3_malloc64() */ +}; - if( pNode->iNode==1 ){ - rc = rtreeInsertCell(pRtree, pLeft->pParent, &leftbbox, iHeight+1); - if( rc!=SQLITE_OK ){ - goto splitnode_out; - } - }else{ - RtreeNode *pParent = pLeft->pParent; - int iCell; - rc = nodeParentIndex(pRtree, pLeft, &iCell); - if( rc==SQLITE_OK ){ - nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); - rc = AdjustTree(pRtree, pParent, &leftbbox); - } - if( rc!=SQLITE_OK ){ - goto splitnode_out; - } - } - if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){ - goto splitnode_out; - } +/* Do a 4-byte byte swap */ +static void geopolySwab32(unsigned char *a){ + unsigned char t = a[0]; + a[0] = a[3]; + a[3] = t; + t = a[1]; + a[1] = a[2]; + a[2] = t; +} - for(i=0; iiRowid ){ - newCellIsRight = 1; - } - if( rc!=SQLITE_OK ){ - goto splitnode_out; - } +/* Skip whitespace. Return the next non-whitespace character. */ +static char geopolySkipSpace(GeoParse *p){ + while( fast_isspace(p->z[0]) ) p->z++; + return p->z[0]; +} + +/* Parse out a number. Write the value into *pVal if pVal!=0. +** return non-zero on success and zero if the next token is not a number. +*/ +static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ + char c = geopolySkipSpace(p); + const unsigned char *z = p->z; + int j = 0; + int seenDP = 0; + int seenE = 0; + if( c=='-' ){ + j = 1; + c = z[j]; } - if( pNode->iNode==1 ){ - for(i=0; i='0' && z[j+1]<='9' ) return 0; + for(;; j++){ + c = z[j]; + if( safe_isdigit(c) ) continue; + if( c=='.' ){ + if( z[j-1]=='-' ) return 0; + if( seenDP ) return 0; + seenDP = 1; + continue; + } + if( c=='e' || c=='E' ){ + if( z[j-1]<'0' ) return 0; + if( seenE ) return -1; + seenDP = seenE = 1; + c = z[j+1]; + if( c=='+' || c=='-' ){ + j++; + c = z[j+1]; } + if( c<'0' || c>'9' ) return 0; + continue; } - }else if( newCellIsRight==0 ){ - rc = updateMapping(pRtree, pCell->iRowid, pLeft, iHeight); - } - - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pRight); - pRight = 0; + break; } - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pLeft); - pLeft = 0; + if( z[j-1]<'0' ) return 0; + if( pVal ){ +#ifdef SQLITE_AMALGAMATION + /* The sqlite3AtoF() routine is much much faster than atof(), if it + ** is available */ + double r; + (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8); + *pVal = r; +#else + *pVal = (GeoCoord)atof((const char*)p->z); +#endif } - -splitnode_out: - nodeRelease(pRtree, pRight); - nodeRelease(pRtree, pLeft); - sqlite3_free(aCell); - return rc; + p->z += j; + return 1; } /* -** If node pLeaf is not the root of the r-tree and its pParent pointer is -** still NULL, load all ancestor nodes of pLeaf into memory and populate -** the pLeaf->pParent chain all the way up to the root node. +** If the input is a well-formed JSON array of coordinates with at least +** four coordinates and where each coordinate is itself a two-value array, +** then convert the JSON into a GeoPoly object and return a pointer to +** that object. ** -** This operation is required when a row is deleted (or updated - an update -** is implemented as a delete followed by an insert). SQLite provides the -** rowid of the row to delete, which can be used to find the leaf on which -** the entry resides (argument pLeaf). Once the leaf is located, this -** function is called to determine its ancestry. +** If any error occurs, return NULL. */ -static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){ +static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ + GeoParse s; int rc = SQLITE_OK; - RtreeNode *pChild = pLeaf; - while( rc==SQLITE_OK && pChild->iNode!=1 && pChild->pParent==0 ){ - int rc2 = SQLITE_OK; /* sqlite3_reset() return code */ - sqlite3_bind_int64(pRtree->pReadParent, 1, pChild->iNode); - rc = sqlite3_step(pRtree->pReadParent); - if( rc==SQLITE_ROW ){ - RtreeNode *pTest; /* Used to test for reference loops */ - i64 iNode; /* Node number of parent node */ - - /* Before setting pChild->pParent, test that we are not creating a - ** loop of references (as we would if, say, pChild==pParent). We don't - ** want to do this as it leads to a memory leak when trying to delete - ** the referenced counted node structures. - */ - iNode = sqlite3_column_int64(pRtree->pReadParent, 0); - for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); - if( !pTest ){ - rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); + memset(&s, 0, sizeof(s)); + s.z = z; + if( geopolySkipSpace(&s)=='[' ){ + s.z++; + while( geopolySkipSpace(&s)=='[' ){ + int ii = 0; + char c; + s.z++; + if( s.nVertex>=s.nAlloc ){ + GeoCoord *aNew; + s.nAlloc = s.nAlloc*2 + 16; + aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 ); + if( aNew==0 ){ + rc = SQLITE_NOMEM; + s.nErr++; + break; + } + s.a = aNew; } + while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){ + ii++; + if( ii==2 ) s.nVertex++; + c = geopolySkipSpace(&s); + s.z++; + if( c==',' ) continue; + if( c==']' && ii>=2 ) break; + s.nErr++; + rc = SQLITE_ERROR; + goto parse_json_err; + } + if( geopolySkipSpace(&s)==',' ){ + s.z++; + continue; + } + break; } - rc = sqlite3_reset(pRtree->pReadParent); - if( rc==SQLITE_OK ) rc = rc2; - if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB; - pChild = pChild->pParent; - } - return rc; -} - -static int deleteCell(Rtree *, RtreeNode *, int, int); - -static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){ - int rc; - int rc2; - RtreeNode *pParent = 0; - int iCell; - - assert( pNode->nRef==1 ); - - /* Remove the entry in the parent cell. */ - rc = nodeParentIndex(pRtree, pNode, &iCell); - if( rc==SQLITE_OK ){ - pParent = pNode->pParent; - pNode->pParent = 0; - rc = deleteCell(pRtree, pParent, iCell, iHeight+1); - } - rc2 = nodeRelease(pRtree, pParent); - if( rc==SQLITE_OK ){ - rc = rc2; - } - if( rc!=SQLITE_OK ){ - return rc; - } - - /* Remove the xxx_node entry. */ - sqlite3_bind_int64(pRtree->pDeleteNode, 1, pNode->iNode); - sqlite3_step(pRtree->pDeleteNode); - if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteNode)) ){ - return rc; - } - - /* Remove the xxx_parent entry. */ - sqlite3_bind_int64(pRtree->pDeleteParent, 1, pNode->iNode); - sqlite3_step(pRtree->pDeleteParent); - if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteParent)) ){ - return rc; - } - - /* Remove the node from the in-memory hash table and link it into - ** the Rtree.pDeleted list. Its contents will be re-inserted later on. - */ - nodeHashDelete(pRtree, pNode); - pNode->iNode = iHeight; - pNode->pNext = pRtree->pDeleted; - pNode->nRef++; - pRtree->pDeleted = pNode; - - return SQLITE_OK; -} - -static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){ - RtreeNode *pParent = pNode->pParent; - int rc = SQLITE_OK; - if( pParent ){ - int ii; - int nCell = NCELL(pNode); - RtreeCell box; /* Bounding box for pNode */ - nodeGetCell(pRtree, pNode, 0, &box); - for(ii=1; iiiNode; - rc = nodeParentIndex(pRtree, pNode, &ii); - if( rc==SQLITE_OK ){ - nodeOverwriteCell(pRtree, pParent, &box, ii); - rc = fixBoundingBox(pRtree, pParent); + if( geopolySkipSpace(&s)==']' + && s.nVertex>=4 + && s.a[0]==s.a[s.nVertex*2-2] + && s.a[1]==s.a[s.nVertex*2-1] + && (s.z++, geopolySkipSpace(&s)==0) + ){ + GeoPoly *pOut; + int x = 1; + s.nVertex--; /* Remove the redundant vertex at the end */ + pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) ); + x = 1; + if( pOut==0 ) goto parse_json_err; + pOut->nVertex = s.nVertex; + memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord)); + pOut->hdr[0] = *(unsigned char*)&x; + pOut->hdr[1] = (s.nVertex>>16)&0xff; + pOut->hdr[2] = (s.nVertex>>8)&0xff; + pOut->hdr[3] = s.nVertex&0xff; + sqlite3_free(s.a); + if( pRc ) *pRc = SQLITE_OK; + return pOut; + }else{ + s.nErr++; + rc = SQLITE_ERROR; } } - return rc; +parse_json_err: + if( pRc ) *pRc = rc; + sqlite3_free(s.a); + return 0; } /* -** Delete the cell at index iCell of node pNode. After removing the -** cell, adjust the r-tree data structure if required. +** Given a function parameter, try to interpret it as a polygon, either +** in the binary format or JSON text. Compute a GeoPoly object and +** return a pointer to that object. Or if the input is not a well-formed +** polygon, put an error message in sqlite3_context and return NULL. */ -static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){ - RtreeNode *pParent; - int rc; - - if( SQLITE_OK!=(rc = fixLeafParent(pRtree, pNode)) ){ - return rc; - } - - /* Remove the cell from the node. This call just moves bytes around - ** the in-memory node image, so it cannot fail. - */ - nodeDeleteCell(pRtree, pNode, iCell); - - /* If the node is not the tree root and now has less than the minimum - ** number of cells, remove it from the tree. Otherwise, update the - ** cell in the parent node so that it tightly contains the updated - ** node. - */ - pParent = pNode->pParent; - assert( pParent || pNode->iNode==1 ); - if( pParent ){ - if( NCELL(pNode)nDim; iDim++){ - aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]); - aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]); - } - } - for(iDim=0; iDimnDim; iDim++){ - aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2)); - } - - for(ii=0; iinDim; iDim++){ - RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - - DCOORD(aCell[ii].aCoord[iDim*2])); - aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); + GeoPoly *p = 0; + int nByte; + testcase( pCtx==0 ); + if( sqlite3_value_type(pVal)==SQLITE_BLOB + && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) + ){ + const unsigned char *a = sqlite3_value_blob(pVal); + int nVertex; + if( a==0 ){ + if( pCtx ) sqlite3_result_error_nomem(pCtx); + return 0; } - } - - SortByDistance(aOrder, nCell, aDistance, aSpare); - nodeZero(pRtree, pNode); - - for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){ - RtreeCell *p = &aCell[aOrder[ii]]; - nodeInsertCell(pRtree, pNode, p); - if( p->iRowid==pCell->iRowid ){ - if( iHeight==0 ){ - rc = rowidWrite(pRtree, p->iRowid, pNode->iNode); + nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; + if( (a[0]==0 || a[0]==1) + && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte + ){ + p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); + if( p==0 ){ + if( pRc ) *pRc = SQLITE_NOMEM; + if( pCtx ) sqlite3_result_error_nomem(pCtx); }else{ - rc = parentWrite(pRtree, p->iRowid, pNode->iNode); + int x = 1; + p->nVertex = nVertex; + memcpy(p->hdr, a, nByte); + if( a[0] != *(unsigned char*)&x ){ + int ii; + for(ii=0; iihdr[0] ^= 1; + } } } - } - if( rc==SQLITE_OK ){ - rc = fixBoundingBox(pRtree, pNode); - } - for(; rc==SQLITE_OK && iiiNode currently contains - ** the height of the sub-tree headed by the cell. - */ - RtreeNode *pInsert; - RtreeCell *p = &aCell[aOrder[ii]]; - rc = ChooseLeaf(pRtree, p, iHeight, &pInsert); - if( rc==SQLITE_OK ){ - int rc2; - rc = rtreeInsertCell(pRtree, pInsert, p, iHeight); - rc2 = nodeRelease(pRtree, pInsert); - if( rc==SQLITE_OK ){ - rc = rc2; - } + if( pRc ) *pRc = SQLITE_OK; + return p; + }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){ + const unsigned char *zJson = sqlite3_value_text(pVal); + if( zJson==0 ){ + if( pRc ) *pRc = SQLITE_NOMEM; + return 0; } + return geopolyParseJson(zJson, pRc); + }else{ + if( pRc ) *pRc = SQLITE_ERROR; + return 0; } - - sqlite3_free(aCell); - return rc; } /* -** Insert cell pCell into node pNode. Node pNode is the head of a -** subtree iHeight high (leaf nodes have iHeight==0). +** Implementation of the geopoly_blob(X) function. +** +** If the input is a well-formed Geopoly BLOB or JSON string +** then return the BLOB representation of the polygon. Otherwise +** return NULL. */ -static int rtreeInsertCell( - Rtree *pRtree, - RtreeNode *pNode, - RtreeCell *pCell, - int iHeight +static void geopolyBlobFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - int rc = SQLITE_OK; - if( iHeight>0 ){ - RtreeNode *pChild = nodeHashLookup(pRtree, pCell->iRowid); - if( pChild ){ - nodeRelease(pRtree, pChild->pParent); - nodeReference(pNode); - pChild->pParent = pNode; - } + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); } - if( nodeInsertCell(pRtree, pNode, pCell) ){ - if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){ - rc = SplitNode(pRtree, pNode, pCell, iHeight); - }else{ - pRtree->iReinsertHeight = iHeight; - rc = Reinsert(pRtree, pNode, pCell, iHeight); - } - }else{ - rc = AdjustTree(pRtree, pNode, pCell); - if( rc==SQLITE_OK ){ - if( iHeight==0 ){ - rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); - }else{ - rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode); - } +} + +/* +** SQL function: geopoly_json(X) +** +** Interpret X as a polygon and render it as a JSON array +** of coordinates. Or, if X is not a valid polygon, return NULL. +*/ +static void geopolyJsonFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_str *x = sqlite3_str_new(db); + int i; + sqlite3_str_append(x, "[", 1); + for(i=0; inVertex; i++){ + sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i)); } + sqlite3_str_appendf(x, "[%!g,%!g]]", GeoX(p,0), GeoY(p,0)); + sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); + sqlite3_free(p); } - return rc; } -static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){ - int ii; - int rc = SQLITE_OK; - int nCell = NCELL(pNode); - - for(ii=0; rc==SQLITE_OK && iiiNode currently contains - ** the height of the sub-tree headed by the cell. - */ - rc = ChooseLeaf(pRtree, &cell, (int)pNode->iNode, &pInsert); - if( rc==SQLITE_OK ){ - int rc2; - rc = rtreeInsertCell(pRtree, pInsert, &cell, (int)pNode->iNode); - rc2 = nodeRelease(pRtree, pInsert); - if( rc==SQLITE_OK ){ - rc = rc2; +/* +** SQL function: geopoly_svg(X, ....) +** +** Interpret X as a polygon and render it as a SVG . +** Additional arguments are added as attributes to the . +*/ +static void geopolySvgFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p; + if( argc<1 ) return; + p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_str *x = sqlite3_str_new(db); + int i; + char cSep = '\''; + sqlite3_str_appendf(x, ""); + sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); + sqlite3_free(p); } - return rc; } /* -** Select a currently unused rowid for a new r-tree record. +** SQL Function: geopoly_xform(poly, A, B, C, D, E, F) +** +** Transform and/or translate a polygon as follows: +** +** x1 = A*x0 + B*y0 + E +** y1 = C*x0 + D*y0 + F +** +** For a translation: +** +** geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset) +** +** Rotate by R around the point (0,0): +** +** geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0) */ -static int newRowid(Rtree *pRtree, i64 *piRowid){ - int rc; - sqlite3_bind_null(pRtree->pWriteRowid, 1); - sqlite3_bind_null(pRtree->pWriteRowid, 2); - sqlite3_step(pRtree->pWriteRowid); - rc = sqlite3_reset(pRtree->pWriteRowid); - *piRowid = sqlite3_last_insert_rowid(pRtree->db); - return rc; +static void geopolyXformFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + double A = sqlite3_value_double(argv[1]); + double B = sqlite3_value_double(argv[2]); + double C = sqlite3_value_double(argv[3]); + double D = sqlite3_value_double(argv[4]); + double E = sqlite3_value_double(argv[5]); + double F = sqlite3_value_double(argv[6]); + GeoCoord x1, y1, x0, y0; + int ii; + if( p ){ + for(ii=0; iinVertex; ii++){ + x0 = GeoX(p,ii); + y0 = GeoY(p,ii); + x1 = (GeoCoord)(A*x0 + B*y0 + E); + y1 = (GeoCoord)(C*x0 + D*y0 + F); + GeoX(p,ii) = x1; + GeoY(p,ii) = y1; + } + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } } /* -** Remove the entry with rowid=iDelete from the r-tree structure. +** Compute the area enclosed by the polygon. +** +** This routine can also be used to detect polygons that rotate in +** the wrong direction. Polygons are suppose to be counter-clockwise (CCW). +** This routine returns a negative value for clockwise (CW) polygons. */ -static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ - int rc; /* Return code */ - RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */ - int iCell; /* Index of iDelete cell in pLeaf */ - RtreeNode *pRoot; /* Root node of rtree structure */ - - - /* Obtain a reference to the root node to initialize Rtree.iDepth */ - rc = nodeAcquire(pRtree, 1, 0, &pRoot); - - /* Obtain a reference to the leaf node that contains the entry - ** about to be deleted. - */ - if( rc==SQLITE_OK ){ - rc = findLeafNode(pRtree, iDelete, &pLeaf, 0); +static double geopolyArea(GeoPoly *p){ + double rArea = 0.0; + int ii; + for(ii=0; iinVertex-1; ii++){ + rArea += (GeoX(p,ii) - GeoX(p,ii+1)) /* (x0 - x1) */ + * (GeoY(p,ii) + GeoY(p,ii+1)) /* (y0 + y1) */ + * 0.5; } + rArea += (GeoX(p,ii) - GeoX(p,0)) /* (xN - x0) */ + * (GeoY(p,ii) + GeoY(p,0)) /* (yN + y0) */ + * 0.5; + return rArea; +} - /* Delete the cell in question from the leaf node. */ - if( rc==SQLITE_OK ){ - int rc2; - rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); - if( rc==SQLITE_OK ){ - rc = deleteCell(pRtree, pLeaf, iCell, 0); - } - rc2 = nodeRelease(pRtree, pLeaf); - if( rc==SQLITE_OK ){ - rc = rc2; - } +/* +** Implementation of the geopoly_area(X) function. +** +** If the input is a well-formed Geopoly BLOB then return the area +** enclosed by the polygon. If the polygon circulates clockwise instead +** of counterclockwise (as it should) then return the negative of the +** enclosed area. Otherwise return NULL. +*/ +static void geopolyAreaFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + sqlite3_result_double(context, geopolyArea(p)); + sqlite3_free(p); } +} - /* Delete the corresponding entry in the _rowid table. */ - if( rc==SQLITE_OK ){ - sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); - sqlite3_step(pRtree->pDeleteRowid); - rc = sqlite3_reset(pRtree->pDeleteRowid); +/* +** Implementation of the geopoly_ccw(X) function. +** +** If the rotation of polygon X is clockwise (incorrect) instead of +** counter-clockwise (the correct winding order according to RFC7946) +** then reverse the order of the vertexes in polygon X. +** +** In other words, this routine returns a CCW polygon regardless of the +** winding order of its input. +** +** Use this routine to sanitize historical inputs that that sometimes +** contain polygons that wind in the wrong direction. +*/ +static void geopolyCcwFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + if( geopolyArea(p)<0.0 ){ + int ii, jj; + for(ii=1, jj=p->nVertex-1; iihdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); } +} - /* Check if the root node now has exactly one child. If so, remove - ** it, schedule the contents of the child for reinsertion and - ** reduce the tree height by one. - ** - ** This is equivalent to copying the contents of the child into - ** the root node (the operation that Gutman's paper says to perform - ** in this scenario). - */ - if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ - int rc2; - RtreeNode *pChild; - i64 iChild = nodeGetRowid(pRtree, pRoot, 0); - rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); - if( rc==SQLITE_OK ){ - rc = removeNode(pRtree, pChild, pRtree->iDepth-1); - } - rc2 = nodeRelease(pRtree, pChild); - if( rc==SQLITE_OK ) rc = rc2; - if( rc==SQLITE_OK ){ - pRtree->iDepth--; - writeInt16(pRoot->zData, pRtree->iDepth); - pRoot->isDirty = 1; - } - } +#define GEOPOLY_PI 3.1415926535897932385 - /* Re-insert the contents of any underfull nodes removed from the tree. */ - for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ - if( rc==SQLITE_OK ){ - rc = reinsertNodeContent(pRtree, pLeaf); - } - pRtree->pDeleted = pLeaf->pNext; - sqlite3_free(pLeaf); +/* Fast approximation for sine(X) for X between -0.5*pi and 2*pi +*/ +static double geopolySine(double r){ + assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI ); + if( r>=1.5*GEOPOLY_PI ){ + r -= 2.0*GEOPOLY_PI; } - - /* Release the reference to the root node. */ - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pRoot); + if( r>=0.5*GEOPOLY_PI ){ + return -geopolySine(r-GEOPOLY_PI); }else{ - nodeRelease(pRtree, pRoot); + double r2 = r*r; + double r3 = r2*r; + double r5 = r3*r2; + return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5; } - - return rc; } /* -** Rounding constants for float->double conversion. +** Function: geopoly_regular(X,Y,R,N) +** +** Construct a simple, convex, regular polygon centered at X, Y +** with circumradius R and with N sides. */ -#define RNDTOWARDS (1.0 - 1.0/8388608.0) /* Round towards zero */ -#define RNDAWAY (1.0 + 1.0/8388608.0) /* Round away from zero */ +static void geopolyRegularFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + double x = sqlite3_value_double(argv[0]); + double y = sqlite3_value_double(argv[1]); + double r = sqlite3_value_double(argv[2]); + int n = sqlite3_value_int(argv[3]); + int i; + GeoPoly *p; -#if !defined(SQLITE_RTREE_INT_ONLY) -/* -** Convert an sqlite3_value into an RtreeValue (presumably a float) -** while taking care to round toward negative or positive, respectively. -*/ -static RtreeValue rtreeValueDown(sqlite3_value *v){ - double d = sqlite3_value_double(v); - float f = (float)d; - if( f>d ){ - f = (float)(d*(d<0 ? RNDAWAY : RNDTOWARDS)); + if( n<3 || r<=0.0 ) return; + if( n>1000 ) n = 1000; + p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); + if( p==0 ){ + sqlite3_result_error_nomem(context); + return; } - return f; -} -static RtreeValue rtreeValueUp(sqlite3_value *v){ - double d = sqlite3_value_double(v); - float f = (float)d; - if( fhdr[0] = *(unsigned char*)&i; + p->hdr[1] = 0; + p->hdr[2] = (n>>8)&0xff; + p->hdr[3] = n&0xff; + for(i=0; ihdr, 4+8*n, SQLITE_TRANSIENT); + sqlite3_free(p); } -#endif /* !defined(SQLITE_RTREE_INT_ONLY) */ /* -** A constraint has failed while inserting a row into an rtree table. -** Assuming no OOM error occurs, this function sets the error message -** (at pRtree->base.zErrMsg) to an appropriate value and returns -** SQLITE_CONSTRAINT. +** If pPoly is a polygon, compute its bounding box. Then: ** -** Parameter iCol is the index of the leftmost column involved in the -** constraint failure. If it is 0, then the constraint that failed is -** the unique constraint on the id column. Otherwise, it is the rtree -** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. +** (1) if aCoord!=0 store the bounding box in aCoord, returning NULL +** (2) otherwise, compute a GeoPoly for the bounding box and return the +** new GeoPoly ** -** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. +** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from +** the bounding box in aCoord and return a pointer to that GeoPoly. */ -static int rtreeConstraintError(Rtree *pRtree, int iCol){ - sqlite3_stmt *pStmt = 0; - char *zSql; - int rc; - - assert( iCol==0 || iCol%2 ); - zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); - if( zSql ){ - rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); +static GeoPoly *geopolyBBox( + sqlite3_context *context, /* For recording the error */ + sqlite3_value *pPoly, /* The polygon */ + RtreeCoord *aCoord, /* Results here */ + int *pRc /* Error code here */ +){ + GeoPoly *pOut = 0; + GeoPoly *p; + float mnX, mxX, mnY, mxY; + if( pPoly==0 && aCoord!=0 ){ + p = 0; + mnX = aCoord[0].f; + mxX = aCoord[1].f; + mnY = aCoord[2].f; + mxY = aCoord[3].f; + goto geopolyBboxFill; }else{ - rc = SQLITE_NOMEM; + p = geopolyFuncParam(context, pPoly, pRc); } - sqlite3_free(zSql); - - if( rc==SQLITE_OK ){ - if( iCol==0 ){ - const char *zCol = sqlite3_column_name(pStmt, 0); - pRtree->base.zErrMsg = sqlite3_mprintf( - "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol - ); + if( p ){ + int ii; + mnX = mxX = GeoX(p,0); + mnY = mxY = GeoY(p,0); + for(ii=1; iinVertex; ii++){ + double r = GeoX(p,ii); + if( rmxX ) mxX = (float)r; + r = GeoY(p,ii); + if( rmxY ) mxY = (float)r; + } + if( pRc ) *pRc = SQLITE_OK; + if( aCoord==0 ){ + geopolyBboxFill: + pOut = sqlite3_realloc64(p, GEOPOLY_SZ(4)); + if( pOut==0 ){ + sqlite3_free(p); + if( context ) sqlite3_result_error_nomem(context); + if( pRc ) *pRc = SQLITE_NOMEM; + return 0; + } + pOut->nVertex = 4; + ii = 1; + pOut->hdr[0] = *(unsigned char*)ⅈ + pOut->hdr[1] = 0; + pOut->hdr[2] = 0; + pOut->hdr[3] = 4; + GeoX(pOut,0) = mnX; + GeoY(pOut,0) = mnY; + GeoX(pOut,1) = mxX; + GeoY(pOut,1) = mnY; + GeoX(pOut,2) = mxX; + GeoY(pOut,2) = mxY; + GeoX(pOut,3) = mnX; + GeoY(pOut,3) = mxY; }else{ - const char *zCol1 = sqlite3_column_name(pStmt, iCol); - const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); - pRtree->base.zErrMsg = sqlite3_mprintf( - "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 - ); + sqlite3_free(p); + aCoord[0].f = mnX; + aCoord[1].f = mxX; + aCoord[2].f = mnY; + aCoord[3].f = mxY; } + }else if( aCoord ){ + memset(aCoord, 0, sizeof(RtreeCoord)*4); } + return pOut; +} - sqlite3_finalize(pStmt); - return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); +/* +** Implementation of the geopoly_bbox(X) SQL function. +*/ +static void geopolyBBoxFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } } +/* +** State vector for the geopoly_group_bbox() aggregate function. +*/ +typedef struct GeoBBox GeoBBox; +struct GeoBBox { + int isInit; + RtreeCoord a[4]; +}; /* -** The xUpdate method for rtree module virtual tables. +** Implementation of the geopoly_group_bbox(X) aggregate SQL function. */ -static int rtreeUpdate( - sqlite3_vtab *pVtab, - int nData, - sqlite3_value **azData, - sqlite_int64 *pRowid +static void geopolyBBoxStep( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Rtree *pRtree = (Rtree *)pVtab; + RtreeCoord a[4]; int rc = SQLITE_OK; - RtreeCell cell; /* New cell to insert if nData>1 */ - int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ - - rtreeReference(pRtree); - assert(nData>=1); - - cell.iRowid = 0; /* Used only to suppress a compiler warning */ - - /* Constraint handling. A write operation on an r-tree table may return - ** SQLITE_CONSTRAINT for two reasons: - ** - ** 1. A duplicate rowid value, or - ** 2. The supplied data violates the "x2>=x1" constraint. - ** - ** In the first case, if the conflict-handling mode is REPLACE, then - ** the conflicting row can be removed before proceeding. In the second - ** case, SQLITE_CONSTRAINT must be returned regardless of the - ** conflict-handling mode specified by the user. - */ - if( nData>1 ){ - int ii; - - /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. - ** - ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared - ** with "column" that are interpreted as table constraints. - ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); - ** This problem was discovered after years of use, so we silently ignore - ** these kinds of misdeclared tables to avoid breaking any legacy. - */ - assert( nData<=(pRtree->nDim2 + 3) ); - -#ifndef SQLITE_RTREE_INT_ONLY - if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ - for(ii=0; iicell.aCoord[ii+1].f ){ - rc = rtreeConstraintError(pRtree, ii+1); - goto constraint; - } - } - }else -#endif - { - for(ii=0; iicell.aCoord[ii+1].i ){ - rc = rtreeConstraintError(pRtree, ii+1); - goto constraint; - } - } - } - - /* If a rowid value was supplied, check if it is already present in - ** the table. If so, the constraint has failed. */ - if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ - cell.iRowid = sqlite3_value_int64(azData[2]); - if( sqlite3_value_type(azData[0])==SQLITE_NULL - || sqlite3_value_int64(azData[0])!=cell.iRowid - ){ - int steprc; - sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); - steprc = sqlite3_step(pRtree->pReadRowid); - rc = sqlite3_reset(pRtree->pReadRowid); - if( SQLITE_ROW==steprc ){ - if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ - rc = rtreeDeleteRowid(pRtree, cell.iRowid); - }else{ - rc = rtreeConstraintError(pRtree, 0); - goto constraint; - } - } - } - bHaveRowid = 1; + (void)geopolyBBox(context, argv[0], a, &rc); + if( rc==SQLITE_OK ){ + GeoBBox *pBBox; + pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox)); + if( pBBox==0 ) return; + if( pBBox->isInit==0 ){ + pBBox->isInit = 1; + memcpy(pBBox->a, a, sizeof(RtreeCoord)*4); + }else{ + if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0]; + if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1]; + if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2]; + if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3]; } } - - /* If azData[0] is not an SQL NULL value, it is the rowid of a - ** record to delete from the r-tree table. The following block does - ** just that. - */ - if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ - rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0])); - } - - /* If the azData[] array contains more than one element, elements - ** (azData[2]..azData[argc-1]) contain a new record to insert into - ** the r-tree structure. - */ - if( rc==SQLITE_OK && nData>1 ){ - /* Insert the new record into the r-tree */ - RtreeNode *pLeaf = 0; - - /* Figure out the rowid of the new row. */ - if( bHaveRowid==0 ){ - rc = newRowid(pRtree, &cell.iRowid); - } - *pRowid = cell.iRowid; - - if( rc==SQLITE_OK ){ - rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); - } - if( rc==SQLITE_OK ){ - int rc2; - pRtree->iReinsertHeight = -1; - rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); - rc2 = nodeRelease(pRtree, pLeaf); - if( rc==SQLITE_OK ){ - rc = rc2; - } - } +} +static void geopolyBBoxFinal( + sqlite3_context *context +){ + GeoPoly *p; + GeoBBox *pBBox; + pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0); + if( pBBox==0 ) return; + p = geopolyBBox(context, 0, pBBox->a, 0); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); } - -constraint: - rtreeRelease(pRtree); - return rc; } -/* -** Called when a transaction starts. -*/ -static int rtreeBeginTransaction(sqlite3_vtab *pVtab){ - Rtree *pRtree = (Rtree *)pVtab; - assert( pRtree->inWrTrans==0 ); - pRtree->inWrTrans++; - return SQLITE_OK; -} /* -** Called when a transaction completes (either by COMMIT or ROLLBACK). -** The sqlite3_blob object should be released at this point. +** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). +** Returns: +** +** +2 x0,y0 is on the line segement +** +** +1 x0,y0 is beneath line segment +** +** 0 x0,y0 is not on or beneath the line segment or the line segment +** is vertical and x0,y0 is not on the line segment +** +** The left-most coordinate min(x1,x2) is not considered to be part of +** the line segment for the purposes of this analysis. */ -static int rtreeEndTransaction(sqlite3_vtab *pVtab){ - Rtree *pRtree = (Rtree *)pVtab; - pRtree->inWrTrans = 0; - nodeBlobReset(pRtree); - return SQLITE_OK; +static int pointBeneathLine( + double x0, double y0, + double x1, double y1, + double x2, double y2 +){ + double y; + if( x0==x1 && y0==y1 ) return 2; + if( x1x2 ) return 0; + }else if( x1>x2 ){ + if( x0<=x2 || x0>x1 ) return 0; + }else{ + /* Vertical line segment */ + if( x0!=x1 ) return 0; + if( y0y1 && y0>y2 ) return 0; + return 2; + } + y = y1 + (y2-y1)*(x0-x1)/(x2-x1); + if( y0==y ) return 2; + if( y0zDb, pRtree->zName, zNewName - , pRtree->zDb, pRtree->zName, zNewName - , pRtree->zDb, pRtree->zName, zNewName - ); - if( zSql ){ - rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0); - sqlite3_free(zSql); +static void geopolyContainsPointFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); + double x0 = sqlite3_value_double(argv[1]); + double y0 = sqlite3_value_double(argv[2]); + int v = 0; + int cnt = 0; + int ii; + if( p1==0 ) return; + for(ii=0; iinVertex-1; ii++){ + v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), + GeoX(p1,ii+1),GeoY(p1,ii+1)); + if( v==2 ) break; + cnt += v; + } + if( v!=2 ){ + v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii), + GeoX(p1,0), GeoY(p1,0)); + } + if( v==2 ){ + sqlite3_result_int(context, 1); + }else if( ((v+cnt)&1)==0 ){ + sqlite3_result_int(context, 0); + }else{ + sqlite3_result_int(context, 2); } - return rc; + sqlite3_free(p1); } +/* Forward declaration */ +static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2); /* -** This function populates the pRtree->nRowEst variable with an estimate -** of the number of rows in the virtual table. If possible, this is based -** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST. +** SQL function: geopoly_within(P1,P2) +** +** Return +2 if P1 and P2 are the same polygon +** Return +1 if P2 is contained within P1 +** Return 0 if any part of P2 is on the outside of P1 +** */ -static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ - const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; - char *zSql; - sqlite3_stmt *p; - int rc; - i64 nRow = 0; - - rc = sqlite3_table_column_metadata( - db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 - ); - if( rc!=SQLITE_OK ){ - pRtree->nRowEst = RTREE_DEFAULT_ROWEST; - return rc==SQLITE_ERROR ? SQLITE_OK : rc; - } - zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); - if( rc==SQLITE_OK ){ - if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); - rc = sqlite3_finalize(p); - }else if( rc!=SQLITE_NOMEM ){ - rc = SQLITE_OK; - } - - if( rc==SQLITE_OK ){ - if( nRow==0 ){ - pRtree->nRowEst = RTREE_DEFAULT_ROWEST; - }else{ - pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); - } +static void geopolyWithinFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); + GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); + if( p1 && p2 ){ + int x = geopolyOverlap(p1, p2); + if( x<0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); } - sqlite3_free(zSql); } - - return rc; + sqlite3_free(p1); + sqlite3_free(p2); } -static sqlite3_module rtreeModule = { - 0, /* iVersion */ - rtreeCreate, /* xCreate - create a table */ - rtreeConnect, /* xConnect - connect to an existing table */ - rtreeBestIndex, /* xBestIndex - Determine search strategy */ - rtreeDisconnect, /* xDisconnect - Disconnect from a table */ - rtreeDestroy, /* xDestroy - Drop a table */ - rtreeOpen, /* xOpen - open a cursor */ - rtreeClose, /* xClose - close a cursor */ - rtreeFilter, /* xFilter - configure scan constraints */ - rtreeNext, /* xNext - advance a cursor */ - rtreeEof, /* xEof */ - rtreeColumn, /* xColumn - read data */ - rtreeRowid, /* xRowid - read data */ - rtreeUpdate, /* xUpdate - write data */ - rtreeBeginTransaction, /* xBegin - begin transaction */ - rtreeEndTransaction, /* xSync - sync transaction */ - rtreeEndTransaction, /* xCommit - commit transaction */ - rtreeEndTransaction, /* xRollback - rollback transaction */ - 0, /* xFindFunction - function overloading */ - rtreeRename, /* xRename - rename the table */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ +/* Objects used by the overlap algorihm. */ +typedef struct GeoEvent GeoEvent; +typedef struct GeoSegment GeoSegment; +typedef struct GeoOverlap GeoOverlap; +struct GeoEvent { + double x; /* X coordinate at which event occurs */ + int eType; /* 0 for ADD, 1 for REMOVE */ + GeoSegment *pSeg; /* The segment to be added or removed */ + GeoEvent *pNext; /* Next event in the sorted list */ +}; +struct GeoSegment { + double C, B; /* y = C*x + B */ + double y; /* Current y value */ + float y0; /* Initial y value */ + unsigned char side; /* 1 for p1, 2 for p2 */ + unsigned int idx; /* Which segment within the side */ + GeoSegment *pNext; /* Next segment in a list sorted by y */ +}; +struct GeoOverlap { + GeoEvent *aEvent; /* Array of all events */ + GeoSegment *aSegment; /* Array of all segments */ + int nEvent; /* Number of events */ + int nSegment; /* Number of segments */ }; -static int rtreeSqlInit( - Rtree *pRtree, - sqlite3 *db, - const char *zDb, - const char *zPrefix, - int isCreate +/* +** Add a single segment and its associated events. +*/ +static void geopolyAddOneSegment( + GeoOverlap *p, + GeoCoord x0, + GeoCoord y0, + GeoCoord x1, + GeoCoord y1, + unsigned char side, + unsigned int idx +){ + GeoSegment *pSeg; + GeoEvent *pEvent; + if( x0==x1 ) return; /* Ignore vertical segments */ + if( x0>x1 ){ + GeoCoord t = x0; + x0 = x1; + x1 = t; + t = y0; + y0 = y1; + y1 = t; + } + pSeg = p->aSegment + p->nSegment; + p->nSegment++; + pSeg->C = (y1-y0)/(x1-x0); + pSeg->B = y1 - x1*pSeg->C; + pSeg->y0 = y0; + pSeg->side = side; + pSeg->idx = idx; + pEvent = p->aEvent + p->nEvent; + p->nEvent++; + pEvent->x = x0; + pEvent->eType = 0; + pEvent->pSeg = pSeg; + pEvent = p->aEvent + p->nEvent; + p->nEvent++; + pEvent->x = x1; + pEvent->eType = 1; + pEvent->pSeg = pSeg; +} + + + +/* +** Insert all segments and events for polygon pPoly. +*/ +static void geopolyAddSegments( + GeoOverlap *p, /* Add segments to this Overlap object */ + GeoPoly *pPoly, /* Take all segments from this polygon */ + unsigned char side /* The side of pPoly */ ){ - int rc = SQLITE_OK; - - #define N_STATEMENT 8 - static const char *azSql[N_STATEMENT] = { - /* Write the xxx_node table */ - "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)", - "DELETE FROM '%q'.'%q_node' WHERE nodeno = :1", - - /* Read and write the xxx_rowid table */ - "SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = :1", - "INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(:1, :2)", - "DELETE FROM '%q'.'%q_rowid' WHERE rowid = :1", - - /* Read and write the xxx_parent table */ - "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = :1", - "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(:1, :2)", - "DELETE FROM '%q'.'%q_parent' WHERE nodeno = :1" - }; - sqlite3_stmt **appStmt[N_STATEMENT]; - int i; - - pRtree->db = db; + unsigned int i; + GeoCoord *x; + for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ + x = &GeoX(pPoly,i); + geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); + } + x = &GeoX(pPoly,i); + geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i); +} - if( isCreate ){ - char *zCreate = sqlite3_mprintf( -"CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);" -"CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);" -"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY," - " parentnode INTEGER);" -"INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))", - zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize - ); - if( !zCreate ){ - return SQLITE_NOMEM; - } - rc = sqlite3_exec(db, zCreate, 0, 0, 0); - sqlite3_free(zCreate); - if( rc!=SQLITE_OK ){ - return rc; +/* +** Merge two lists of sorted events by X coordinate +*/ +static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){ + GeoEvent head, *pLast; + head.pNext = 0; + pLast = &head; + while( pRight && pLeft ){ + if( pRight->x <= pLeft->x ){ + pLast->pNext = pRight; + pLast = pRight; + pRight = pRight->pNext; + }else{ + pLast->pNext = pLeft; + pLast = pLeft; + pLeft = pLeft->pNext; } } + pLast->pNext = pRight ? pRight : pLeft; + return head.pNext; +} - appStmt[0] = &pRtree->pWriteNode; - appStmt[1] = &pRtree->pDeleteNode; - appStmt[2] = &pRtree->pReadRowid; - appStmt[3] = &pRtree->pWriteRowid; - appStmt[4] = &pRtree->pDeleteRowid; - appStmt[5] = &pRtree->pReadParent; - appStmt[6] = &pRtree->pWriteParent; - appStmt[7] = &pRtree->pDeleteParent; +/* +** Sort an array of nEvent event objects into a list. +*/ +static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){ + int mx = 0; + int i, j; + GeoEvent *p; + GeoEvent *a[50]; + for(i=0; ipNext = 0; + for(j=0; j=mx ) mx = j+1; + } + p = 0; + for(i=0; iy - pLeft->y; + if( r==0.0 ) r = pRight->C - pLeft->C; + if( r<0.0 ){ + pLast->pNext = pRight; + pLast = pRight; + pRight = pRight->pNext; }else{ - rc = SQLITE_NOMEM; + pLast->pNext = pLeft; + pLast = pLeft; + pLeft = pLeft->pNext; } - sqlite3_free(zSql); } + pLast->pNext = pRight ? pRight : pLeft; + return head.pNext; +} - return rc; +/* +** Sort a list of GeoSegments in order of increasing Y and in the event of +** a tie, increasing C (slope). +*/ +static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){ + int mx = 0; + int i; + GeoSegment *p; + GeoSegment *a[50]; + while( pList ){ + p = pList; + pList = pList->pNext; + p->pNext = 0; + for(i=0; i=mx ) mx = i+1; + } + p = 0; + for(i=0; inVertex + p2->nVertex + 2; + GeoOverlap *p; + sqlite3_int64 nByte; + GeoEvent *pThisEvent; + double rX; + int rc = 0; + int needSort = 0; + GeoSegment *pActive = 0; + GeoSegment *pSeg; + unsigned char aOverlap[4]; + + nByte = sizeof(GeoEvent)*nVertex*2 + + sizeof(GeoSegment)*nVertex + + sizeof(GeoOverlap); + p = sqlite3_malloc64( nByte ); + if( p==0 ) return -1; + p->aEvent = (GeoEvent*)&p[1]; + p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; + p->nEvent = p->nSegment = 0; + geopolyAddSegments(p, p1, 1); + geopolyAddSegments(p, p2, 2); + pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent); + rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0; + memset(aOverlap, 0, sizeof(aOverlap)); + while( pThisEvent ){ + if( pThisEvent->x!=rX ){ + GeoSegment *pPrev = 0; + int iMask = 0; + GEODEBUG(("Distinct X: %g\n", pThisEvent->x)); + rX = pThisEvent->x; + if( needSort ){ + GEODEBUG(("SORT\n")); + pActive = geopolySortSegmentsByYAndC(pActive); + needSort = 0; + } + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + if( pPrev ){ + if( pPrev->y!=pSeg->y ){ + GEODEBUG(("MASK: %d\n", iMask)); + aOverlap[iMask] = 1; + } + } + iMask ^= pSeg->side; + pPrev = pSeg; + } + pPrev = 0; + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + double y = pSeg->C*rX + pSeg->B; + GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y)); + pSeg->y = y; + if( pPrev ){ + if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){ + rc = 1; + GEODEBUG(("Crossing: %d.%d and %d.%d\n", + pPrev->side, pPrev->idx, + pSeg->side, pSeg->idx)); + goto geopolyOverlapDone; + }else if( pPrev->y!=pSeg->y ){ + GEODEBUG(("MASK: %d\n", iMask)); + aOverlap[iMask] = 1; + } + } + iMask ^= pSeg->side; + pPrev = pSeg; + } + } + GEODEBUG(("%s %d.%d C=%g B=%g\n", + pThisEvent->eType ? "RM " : "ADD", + pThisEvent->pSeg->side, pThisEvent->pSeg->idx, + pThisEvent->pSeg->C, + pThisEvent->pSeg->B)); + if( pThisEvent->eType==0 ){ + /* Add a segment */ + pSeg = pThisEvent->pSeg; + pSeg->y = pSeg->y0; + pSeg->pNext = pActive; + pActive = pSeg; + needSort = 1; + }else{ + /* Remove a segment */ + if( pActive==pThisEvent->pSeg ){ + pActive = ALWAYS(pActive) ? pActive->pNext : 0; + }else{ + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + if( pSeg->pNext==pThisEvent->pSeg ){ + pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0; + break; + } + } } - rc = sqlite3_finalize(pStmt); } + pThisEvent = pThisEvent->pNext; + } + if( aOverlap[3]==0 ){ + rc = 0; + }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){ + rc = 3; + }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){ + rc = 2; + }else if( aOverlap[1]==0 && aOverlap[2]==0 ){ + rc = 4; + }else{ + rc = 1; } + +geopolyOverlapDone: + sqlite3_free(p); return rc; } /* -** This function is called from within the xConnect() or xCreate() method to -** determine the node-size used by the rtree table being created or connected -** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned. -** Otherwise, an SQLite error code is returned. +** SQL function: geopoly_overlap(P1,P2) ** -** If this function is being called as part of an xConnect(), then the rtree -** table already exists. In this case the node-size is determined by inspecting -** the root node of the tree. +** Determine whether or not P1 and P2 overlap. Return value: ** -** Otherwise, for an xCreate(), use 64 bytes less than the database page-size. -** This ensures that each node is stored on a single database page. If the -** database page-size is so large that more than RTREE_MAXCELLS entries -** would fit in a single node, use a smaller node-size. +** 0 The two polygons are disjoint +** 1 They overlap +** 2 P1 is completely contained within P2 +** 3 P2 is completely contained within P1 +** 4 P1 and P2 are the same polygon +** NULL Either P1 or P2 or both are not valid polygons */ -static int getNodeSize( - sqlite3 *db, /* Database handle */ - Rtree *pRtree, /* Rtree handle */ - int isCreate, /* True for xCreate, false for xConnect */ - char **pzErr /* OUT: Error message, if any */ +static void geopolyOverlapFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - int rc; - char *zSql; - if( isCreate ){ - int iPageSize = 0; - zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb); - rc = getIntFromStmt(db, zSql, &iPageSize); - if( rc==SQLITE_OK ){ - pRtree->iNodeSize = iPageSize-64; - if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)iNodeSize ){ - pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS; - } + GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); + GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); + if( p1 && p2 ){ + int x = geopolyOverlap(p1, p2); + if( x<0 ){ + sqlite3_result_error_nomem(context); }else{ - *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); - } - }else{ - zSql = sqlite3_mprintf( - "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1", - pRtree->zDb, pRtree->zName - ); - rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); - if( rc!=SQLITE_OK ){ - *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + sqlite3_result_int(context, x); } } + sqlite3_free(p1); + sqlite3_free(p2); +} - sqlite3_free(zSql); - return rc; +/* +** Enable or disable debugging output +*/ +static void geopolyDebugFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ +#ifdef GEOPOLY_ENABLE_DEBUG + geo_debug = sqlite3_value_int(argv[0]); +#endif } -/* +/* ** This function is the implementation of both the xConnect and xCreate -** methods of the r-tree virtual table. +** methods of the geopoly virtual table. ** ** argv[0] -> module name ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> column names... */ -static int rtreeInit( +static int geopolyInit( sqlite3 *db, /* Database connection */ void *pAux, /* One of the RTREE_COORD_* constants */ int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ @@ -166380,29 +201479,18 @@ static int rtreeInit( ){ int rc = SQLITE_OK; Rtree *pRtree; - int nDb; /* Length of string argv[1] */ - int nName; /* Length of string argv[2] */ - int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32); - - const char *aErrMsg[] = { - 0, /* 0 */ - "Wrong number of columns for an rtree table", /* 1 */ - "Too few columns for an rtree table", /* 2 */ - "Too many columns for an rtree table" /* 3 */ - }; - - int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2; - if( aErrMsg[iErr] ){ - *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); - return SQLITE_ERROR; - } + sqlite3_int64 nDb; /* Length of string argv[1] */ + sqlite3_int64 nName; /* Length of string argv[2] */ + sqlite3_str *pSql; + char *zSql; + int ii; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ - nDb = (int)strlen(argv[1]); - nName = (int)strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); + nDb = strlen(argv[1]); + nName = strlen(argv[2]); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } @@ -166411,143 +201499,578 @@ static int rtreeInit( pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; - pRtree->nDim = (u8)((argc-4)/2); - pRtree->nDim2 = pRtree->nDim*2; - pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; - pRtree->eCoordType = (u8)eCoordType; + pRtree->eCoordType = RTREE_COORD_REAL32; + pRtree->nDim = 2; + pRtree->nDim2 = 4; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); - /* Figure out the node size to use. */ - rc = getNodeSize(db, pRtree, isCreate, pzErr); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ - if( rc==SQLITE_OK ){ - if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){ - *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + pSql = sqlite3_str_new(db); + sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape"); + pRtree->nAux = 1; /* Add one for _shape */ + pRtree->nAuxNotNull = 1; /* The _shape column is always not-null */ + for(ii=3; iinAux++; + sqlite3_str_appendf(pSql, ",%s", argv[ii]); + } + sqlite3_str_appendf(pSql, ");"); + zSql = sqlite3_str_finish(pSql); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + sqlite3_free(zSql); + if( rc ) goto geopolyInit_fail; + pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; + + /* Figure out the node size to use. */ + rc = getNodeSize(db, pRtree, isCreate, pzErr); + if( rc ) goto geopolyInit_fail; + rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); + if( rc ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + goto geopolyInit_fail; + } + + *ppVtab = (sqlite3_vtab *)pRtree; + return SQLITE_OK; + +geopolyInit_fail: + if( rc==SQLITE_OK ) rc = SQLITE_ERROR; + assert( *ppVtab==0 ); + assert( pRtree->nBusy==1 ); + rtreeRelease(pRtree); + return rc; +} + + +/* +** GEOPOLY virtual table module xCreate method. +*/ +static int geopolyCreate( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1); +} + +/* +** GEOPOLY virtual table module xConnect method. +*/ +static int geopolyConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0); +} + + +/* +** GEOPOLY virtual table module xFilter method. +** +** Query plans: +** +** 1 rowid lookup +** 2 search for objects overlapping the same bounding box +** that contains polygon argv[0] +** 3 search for objects overlapping the same bounding box +** that contains polygon argv[0] +** 4 full table scan +*/ +static int geopolyFilter( + sqlite3_vtab_cursor *pVtabCursor, /* The cursor to initialize */ + int idxNum, /* Query plan */ + const char *idxStr, /* Not Used */ + int argc, sqlite3_value **argv /* Parameters to the query plan */ +){ + Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeNode *pRoot = 0; + int rc = SQLITE_OK; + int iCell = 0; + + rtreeReference(pRtree); + + /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ + resetCursor(pCsr); + + pCsr->iStrategy = idxNum; + if( idxNum==1 ){ + /* Special case - lookup by rowid. */ + RtreeNode *pLeaf; /* Leaf on which the required cell resides */ + RtreeSearchPoint *p; /* Search point for the leaf */ + i64 iRowid = sqlite3_value_int64(argv[0]); + i64 iNode = 0; + rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); + if( rc==SQLITE_OK && pLeaf!=0 ){ + p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); + assert( p!=0 ); /* Always returns pCsr->sPoint */ + pCsr->aNode[0] = pLeaf; + p->id = iNode; + p->eWithin = PARTLY_WITHIN; + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); + p->iCell = (u8)iCell; + RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); }else{ - char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]); - char *zTmp; - int ii; - for(ii=4; zSql && iiatEOF = 1; + } + }else{ + /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array + ** with the configured constraints. + */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + if( rc==SQLITE_OK && idxNum<=3 ){ + RtreeCoord bbox[4]; + RtreeConstraint *p; + assert( argc==1 ); + assert( argv[0]!=0 ); + geopolyBBox(0, argv[0], bbox, &rc); + if( rc ){ + goto geopoly_filter_end; } - if( zSql ){ - zTmp = zSql; - zSql = sqlite3_mprintf("%s);", zTmp); - sqlite3_free(zTmp); + pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4); + pCsr->nConstraint = 4; + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4); + memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); + if( idxNum==2 ){ + /* Overlap query */ + p->op = 'B'; + p->iCoord = 0; + p->u.rValue = bbox[1].f; + p++; + p->op = 'D'; + p->iCoord = 1; + p->u.rValue = bbox[0].f; + p++; + p->op = 'B'; + p->iCoord = 2; + p->u.rValue = bbox[3].f; + p++; + p->op = 'D'; + p->iCoord = 3; + p->u.rValue = bbox[2].f; + }else{ + /* Within query */ + p->op = 'D'; + p->iCoord = 0; + p->u.rValue = bbox[0].f; + p++; + p->op = 'B'; + p->iCoord = 1; + p->u.rValue = bbox[1].f; + p++; + p->op = 'D'; + p->iCoord = 2; + p->u.rValue = bbox[2].f; + p++; + p->op = 'B'; + p->iCoord = 3; + p->u.rValue = bbox[3].f; + } } - if( !zSql ){ + } + if( rc==SQLITE_OK ){ + RtreeSearchPoint *pNew; + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); + if( pNew==0 ){ rc = SQLITE_NOMEM; - }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ - *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + goto geopoly_filter_end; } - sqlite3_free(zSql); + pNew->id = 1; + pNew->iCell = 0; + pNew->eWithin = PARTLY_WITHIN; + assert( pCsr->bPoint==1 ); + pCsr->aNode[0] = pRoot; + pRoot = 0; + RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); + rc = rtreeStepToLeaf(pCsr); } } - if( rc==SQLITE_OK ){ - *ppVtab = (sqlite3_vtab *)pRtree; - }else{ - assert( *ppVtab==0 ); - assert( pRtree->nBusy==1 ); - rtreeRelease(pRtree); - } +geopoly_filter_end: + nodeRelease(pRtree, pRoot); + rtreeRelease(pRtree); return rc; } - /* -** Implementation of a scalar function that decodes r-tree nodes to -** human readable strings. This can be used for debugging and analysis. -** -** The scalar function takes two arguments: (1) the number of dimensions -** to the rtree (between 1 and 5, inclusive) and (2) a blob of data containing -** an r-tree node. For a two-dimensional r-tree structure called "rt", to -** deserialize all nodes, a statement like: -** -** SELECT rtreenode(2, data) FROM rt_node; +** Rtree virtual table module xBestIndex method. There are three +** table scan strategies to choose from (in order from most to +** least desirable): ** -** The human readable string takes the form of a Tcl list with one -** entry for each cell in the r-tree node. Each entry is itself a -** list, containing the 8-byte rowid/pageno followed by the -** *2 coordinates. +** idxNum idxStr Strategy +** ------------------------------------------------ +** 1 "rowid" Direct lookup by rowid. +** 2 "rtree" R-tree overlap query using geopoly_overlap() +** 3 "rtree" R-tree within query using geopoly_within() +** 4 "fullscan" full-table scan. +** ------------------------------------------------ */ -static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ - char *zText = 0; - RtreeNode node; - Rtree tree; +static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; + int iRowidTerm = -1; + int iFuncTerm = -1; + int idxNum = 0; - UNUSED_PARAMETER(nArg); - memset(&node, 0, sizeof(RtreeNode)); - memset(&tree, 0, sizeof(Rtree)); - tree.nDim = (u8)sqlite3_value_int(apArg[0]); - tree.nDim2 = tree.nDim*2; - tree.nBytesPerCell = 8 + 8 * tree.nDim; - node.zData = (u8 *)sqlite3_value_blob(apArg[1]); + for(ii=0; iinConstraint; ii++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; + if( !p->usable ) continue; + if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + iRowidTerm = ii; + break; + } + if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ + /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap() + ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within(). + ** See geopolyFindFunction() */ + iFuncTerm = ii; + idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2; + } + } - for(ii=0; ii=0 ){ + pIdxInfo->idxNum = 1; + pIdxInfo->idxStr = "rowid"; + pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; + pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; + pIdxInfo->estimatedCost = 30.0; + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + return SQLITE_OK; + } + if( iFuncTerm>=0 ){ + pIdxInfo->idxNum = idxNum; + pIdxInfo->idxStr = "rtree"; + pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1; + pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0; + pIdxInfo->estimatedCost = 300.0; + pIdxInfo->estimatedRows = 10; + return SQLITE_OK; + } + pIdxInfo->idxNum = 4; + pIdxInfo->idxStr = "fullscan"; + pIdxInfo->estimatedCost = 3000000.0; + pIdxInfo->estimatedRows = 100000; + return SQLITE_OK; +} - nodeGetCell(&tree, &node, ii, &cell); - sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid); - nCell = (int)strlen(zCell); - for(jj=0; jjpVtab; + RtreeCursor *pCsr = (RtreeCursor *)cur; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + + if( rc ) return rc; + if( p==0 ) return SQLITE_OK; + if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK; + if( i<=pRtree->nAux ){ + if( !pCsr->bAuxValid ){ + if( pCsr->pReadAux==0 ){ + rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, + &pCsr->pReadAux, 0); + if( rc ) return rc; + } + sqlite3_bind_int64(pCsr->pReadAux, 1, + nodeGetRowid(pRtree, pNode, p->iCell)); + rc = sqlite3_step(pCsr->pReadAux); + if( rc==SQLITE_ROW ){ + pCsr->bAuxValid = 1; + }else{ + sqlite3_reset(pCsr->pReadAux); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; + } } + sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2)); } - - sqlite3_result_text(ctx, zText, -1, sqlite3_free); + return SQLITE_OK; } -/* This routine implements an SQL function that returns the "depth" parameter -** from the front of a blob that is an r-tree node. For example: + +/* +** The xUpdate method for GEOPOLY module virtual tables. ** -** SELECT rtreedepth(data) FROM rt_node WHERE nodeno=1; +** For DELETE: ** -** The depth value is 0 for all nodes other than the root node, and the root -** node always has nodeno=1, so the example above is the primary use for this -** routine. This routine is intended for testing and analysis only. +** argv[0] = the rowid to be deleted +** +** For INSERT: +** +** argv[0] = SQL NULL +** argv[1] = rowid to insert, or an SQL NULL to select automatically +** argv[2] = _shape column +** argv[3] = first application-defined column.... +** +** For UPDATE: +** +** argv[0] = rowid to modify. Never NULL +** argv[1] = rowid after the change. Never NULL +** argv[2] = new value for _shape +** argv[3] = new value for first application-defined column.... */ -static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ - UNUSED_PARAMETER(nArg); - if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB - || sqlite3_value_bytes(apArg[0])<2 +static int geopolyUpdate( + sqlite3_vtab *pVtab, + int nData, + sqlite3_value **aData, + sqlite_int64 *pRowid +){ + Rtree *pRtree = (Rtree *)pVtab; + int rc = SQLITE_OK; + RtreeCell cell; /* New cell to insert if nData>1 */ + i64 oldRowid; /* The old rowid */ + int oldRowidValid; /* True if oldRowid is valid */ + i64 newRowid; /* The new rowid */ + int newRowidValid; /* True if newRowid is valid */ + int coordChange = 0; /* Change in coordinates */ + + if( pRtree->nNodeRef ){ + /* Unable to write to the btree while another cursor is reading from it, + ** since the write might do a rebalance which would disrupt the read + ** cursor. */ + return SQLITE_LOCKED_VTAB; + } + rtreeReference(pRtree); + assert(nData>=1); + + oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;; + oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0; + newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL; + newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0; + cell.iRowid = newRowid; + + if( nData>1 /* not a DELETE */ + && (!oldRowidValid /* INSERT */ + || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ + || oldRowid!=newRowid) /* Rowid change */ ){ - sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); - }else{ - u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]); - sqlite3_result_int(ctx, readInt16(zBlob)); + assert( aData[2]!=0 ); + geopolyBBox(0, aData[2], cell.aCoord, &rc); + if( rc ){ + if( rc==SQLITE_ERROR ){ + pVtab->zErrMsg = + sqlite3_mprintf("_shape does not contain a valid polygon"); + } + goto geopoly_update_end; + } + coordChange = 1; + + /* If a rowid value was supplied, check if it is already present in + ** the table. If so, the constraint has failed. */ + if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){ + int steprc; + sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); + steprc = sqlite3_step(pRtree->pReadRowid); + rc = sqlite3_reset(pRtree->pReadRowid); + if( SQLITE_ROW==steprc ){ + if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ + rc = rtreeDeleteRowid(pRtree, cell.iRowid); + }else{ + rc = rtreeConstraintError(pRtree, 0); + } + } + } + } + + /* If aData[0] is not an SQL NULL value, it is the rowid of a + ** record to delete from the r-tree table. The following block does + ** just that. + */ + if( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){ + rc = rtreeDeleteRowid(pRtree, oldRowid); + } + + /* If the aData[] array contains more than one element, elements + ** (aData[2]..aData[argc-1]) contain a new record to insert into + ** the r-tree structure. + */ + if( rc==SQLITE_OK && nData>1 && coordChange ){ + /* Insert the new record into the r-tree */ + RtreeNode *pLeaf = 0; + if( !newRowidValid ){ + rc = rtreeNewRowid(pRtree, &cell.iRowid); + } + *pRowid = cell.iRowid; + if( rc==SQLITE_OK ){ + rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); + } + if( rc==SQLITE_OK ){ + int rc2; + pRtree->iReinsertHeight = -1; + rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + } + + /* Change the data */ + if( rc==SQLITE_OK && nData>1 ){ + sqlite3_stmt *pUp = pRtree->pWriteAux; + int jj; + int nChange = 0; + sqlite3_bind_int64(pUp, 1, cell.iRowid); + assert( pRtree->nAux>=1 ); + if( sqlite3_value_nochange(aData[2]) ){ + sqlite3_bind_null(pUp, 2); + }else{ + GeoPoly *p = 0; + if( sqlite3_value_type(aData[2])==SQLITE_TEXT + && (p = geopolyFuncParam(0, aData[2], &rc))!=0 + && rc==SQLITE_OK + ){ + sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); + }else{ + sqlite3_bind_value(pUp, 2, aData[2]); + } + sqlite3_free(p); + nChange = 1; + } + for(jj=1; jjnAux; jj++){ + nChange++; + sqlite3_bind_value(pUp, jj+2, aData[jj+2]); + } + if( nChange ){ + sqlite3_step(pUp); + rc = sqlite3_reset(pUp); + } + } + +geopoly_update_end: + rtreeRelease(pRtree); + return rc; +} + +/* +** Report that geopoly_overlap() is an overloaded function suitable +** for use in xBestIndex. +*/ +static int geopolyFindFunction( + sqlite3_vtab *pVtab, + int nArg, + const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg +){ + if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ + *pxFunc = geopolyOverlapFunc; + *ppArg = 0; + return SQLITE_INDEX_CONSTRAINT_FUNCTION; + } + if( sqlite3_stricmp(zName, "geopoly_within")==0 ){ + *pxFunc = geopolyWithinFunc; + *ppArg = 0; + return SQLITE_INDEX_CONSTRAINT_FUNCTION+1; + } + return 0; +} + + +static sqlite3_module geopolyModule = { + 3, /* iVersion */ + geopolyCreate, /* xCreate - create a table */ + geopolyConnect, /* xConnect - connect to an existing table */ + geopolyBestIndex, /* xBestIndex - Determine search strategy */ + rtreeDisconnect, /* xDisconnect - Disconnect from a table */ + rtreeDestroy, /* xDestroy - Drop a table */ + rtreeOpen, /* xOpen - open a cursor */ + rtreeClose, /* xClose - close a cursor */ + geopolyFilter, /* xFilter - configure scan constraints */ + rtreeNext, /* xNext - advance a cursor */ + rtreeEof, /* xEof */ + geopolyColumn, /* xColumn - read data */ + rtreeRowid, /* xRowid - read data */ + geopolyUpdate, /* xUpdate - write data */ + rtreeBeginTransaction, /* xBegin - begin transaction */ + rtreeEndTransaction, /* xSync - sync transaction */ + rtreeEndTransaction, /* xCommit - commit transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ + geopolyFindFunction, /* xFindFunction - function overloading */ + rtreeRename, /* xRename - rename the table */ + rtreeSavepoint, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + rtreeShadowName /* xShadowName */ +}; + +static int sqlite3_geopoly_init(sqlite3 *db){ + int rc = SQLITE_OK; + static const struct { + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + signed char nArg; + unsigned char bPure; + const char *zName; + } aFunc[] = { + { geopolyAreaFunc, 1, 1, "geopoly_area" }, + { geopolyBlobFunc, 1, 1, "geopoly_blob" }, + { geopolyJsonFunc, 1, 1, "geopoly_json" }, + { geopolySvgFunc, -1, 1, "geopoly_svg" }, + { geopolyWithinFunc, 2, 1, "geopoly_within" }, + { geopolyContainsPointFunc, 3, 1, "geopoly_contains_point" }, + { geopolyOverlapFunc, 2, 1, "geopoly_overlap" }, + { geopolyDebugFunc, 1, 0, "geopoly_debug" }, + { geopolyBBoxFunc, 1, 1, "geopoly_bbox" }, + { geopolyXformFunc, 7, 1, "geopoly_xform" }, + { geopolyRegularFunc, 4, 1, "geopoly_regular" }, + { geopolyCcwFunc, 1, 1, "geopoly_ccw" }, + }; + static const struct { + void (*xStep)(sqlite3_context*,int,sqlite3_value**); + void (*xFinal)(sqlite3_context*); + const char *zName; + } aAgg[] = { + { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, + }; + int i; + for(i=0; imagic = RTREE_GEOMETRY_MAGIC; + pBlob->iSize = nBlob; pBlob->cb = pGeomCtx[0]; pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg]; pBlob->nParam = nArg; @@ -166643,7 +202174,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){ sqlite3_result_error_nomem(ctx); rtreeMatchArgFree(pBlob); }else{ - sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree); + sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree); } } } @@ -166666,7 +202197,7 @@ SQLITE_API int sqlite3_rtree_geometry_callback( pGeomCtx->xQueryFunc = 0; pGeomCtx->xDestructor = 0; pGeomCtx->pContext = pContext; - return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, + return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY, (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback ); } @@ -166686,12 +202217,15 @@ SQLITE_API int sqlite3_rtree_query_callback( /* Allocate and populate the context object. */ pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); - if( !pGeomCtx ) return SQLITE_NOMEM; + if( !pGeomCtx ){ + if( xDestructor ) xDestructor(pContext); + return SQLITE_NOMEM; + } pGeomCtx->xGeom = 0; pGeomCtx->xQueryFunc = xQueryFunc; pGeomCtx->xDestructor = xDestructor; pGeomCtx->pContext = pContext; - return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, + return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY, (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback ); } @@ -166727,9 +202261,9 @@ SQLITE_API int sqlite3_rtree_init( ************************************************************************* ** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ ** -** This file implements an integration between the ICU library -** ("International Components for Unicode", an open-source library -** for handling unicode data) and SQLite. The integration uses +** This file implements an integration between the ICU library +** ("International Components for Unicode", an open-source library +** for handling unicode data) and SQLite. The integration uses ** ICU to provide the following to SQLite: ** ** * An implementation of the SQL regexp() function (and hence REGEXP @@ -166740,11 +202274,13 @@ SQLITE_API int sqlite3_rtree_init( ** ** * Integration of ICU and SQLite collation sequences. ** -** * An implementation of the LIKE operator that uses ICU to +** * An implementation of the LIKE operator that uses ICU to ** provide case-independent matching. */ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) +#if !defined(SQLITE_CORE) \ + || defined(SQLITE_ENABLE_ICU) \ + || defined(SQLITE_ENABLE_ICU_COLLATIONS) /* Include ICU headers */ #include @@ -166761,6 +202297,26 @@ SQLITE_API int sqlite3_rtree_init( /* #include "sqlite3.h" */ #endif +/* +** This function is called when an ICU function called from within +** the implementation of an SQL scalar function returns an error. +** +** The scalar function context passed as the first argument is +** loaded with an error message based on the following two args. +*/ +static void icuFunctionError( + sqlite3_context *pCtx, /* SQLite scalar function context */ + const char *zName, /* Name of ICU function that failed */ + UErrorCode e /* Error code returned by ICU function */ +){ + char zBuf[128]; + sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); + zBuf[127] = '\0'; + sqlite3_result_error(pCtx, zBuf, -1); +} + +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) + /* ** Maximum length (in bytes) of the pattern in a LIKE or GLOB ** operator. @@ -166810,7 +202366,7 @@ static const unsigned char icuUtf8Trans1[] = { /* ** Compare two UTF-8 strings for equality where the first string is -** a "LIKE" expression. Return true (1) if they are the same and +** a "LIKE" expression. Return true (1) if they are the same and ** false (0) if they are different. */ static int icuLikeCompare( @@ -166818,15 +202374,15 @@ static int icuLikeCompare( const uint8_t *zString, /* The UTF-8 string to compare against */ const UChar32 uEsc /* The escape character */ ){ - static const int MATCH_ONE = (UChar32)'_'; - static const int MATCH_ALL = (UChar32)'%'; + static const uint32_t MATCH_ONE = (uint32_t)'_'; + static const uint32_t MATCH_ALL = (uint32_t)'%'; int prevEscape = 0; /* True if the previous character was uEsc */ while( 1 ){ /* Read (and consume) the next character from the input pattern. */ - UChar32 uPattern; + uint32_t uPattern; SQLITE_ICU_READ_UTF8(zPattern, uPattern); if( uPattern==0 ) break; @@ -166837,12 +202393,12 @@ static int icuLikeCompare( ** 3. uPattern is an unescaped escape character, or ** 4. uPattern is to be handled as an ordinary character */ - if( !prevEscape && uPattern==MATCH_ALL ){ + if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){ /* Case 1. */ uint8_t c; /* Skip any MATCH_ALL or MATCH_ONE characters that follow a - ** MATCH_ALL. For each MATCH_ONE, skip one character in the + ** MATCH_ALL. For each MATCH_ONE, skip one character in the ** test string. */ while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ @@ -166863,21 +202419,21 @@ static int icuLikeCompare( } return 0; - }else if( !prevEscape && uPattern==MATCH_ONE ){ + }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){ /* Case 2. */ if( *zString==0 ) return 0; SQLITE_ICU_SKIP_UTF8(zString); - }else if( !prevEscape && uPattern==uEsc){ + }else if( uPattern==(uint32_t)uEsc && !prevEscape ){ /* Case 3. */ prevEscape = 1; }else{ /* Case 4. */ - UChar32 uString; + uint32_t uString; SQLITE_ICU_READ_UTF8(zString, uString); - uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT); - uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT); + uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT); + uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT); if( uString!=uPattern ){ return 0; } @@ -166895,15 +202451,15 @@ static int icuLikeCompare( ** ** A LIKE B ** -** is implemented as like(B, A). If there is an escape character E, +** is implemented as like(B, A). If there is an escape character E, ** ** A LIKE B ESCAPE E ** ** is mapped to like(B, A, E). */ static void icuLikeFunc( - sqlite3_context *context, - int argc, + sqlite3_context *context, + int argc, sqlite3_value **argv ){ const unsigned char *zA = sqlite3_value_text(argv[0]); @@ -166929,7 +202485,7 @@ static void icuLikeFunc( if( zE==0 ) return; U8_NEXT(zE, i, nE, uEsc); if( i!=nE){ - sqlite3_result_error(context, + sqlite3_result_error(context, "ESCAPE expression must be a single character", -1); return; } @@ -166940,24 +202496,6 @@ static void icuLikeFunc( } } -/* -** This function is called when an ICU function called from within -** the implementation of an SQL scalar function returns an error. -** -** The scalar function context passed as the first argument is -** loaded with an error message based on the following two args. -*/ -static void icuFunctionError( - sqlite3_context *pCtx, /* SQLite scalar function context */ - const char *zName, /* Name of ICU function that failed */ - UErrorCode e /* Error code returned by ICU function */ -){ - char zBuf[128]; - sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e)); - zBuf[127] = '\0'; - sqlite3_result_error(pCtx, zBuf, -1); -} - /* ** Function to delete compiled regexp objects. Registered as ** a destructor function with sqlite3_set_auxdata(). @@ -166970,7 +202508,7 @@ static void icuRegexpDelete(void *p){ /* ** Implementation of SQLite REGEXP operator. This scalar function takes ** two arguments. The first is a regular expression pattern to compile -** the second is a string to match against that pattern. If either +** the second is a string to match against that pattern. If either ** argument is an SQL NULL, then NULL Is returned. Otherwise, the result ** is 1 if the string matches the pattern, or 0 otherwise. ** @@ -166994,8 +202532,8 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ (void)nArg; /* Unused parameter */ - /* If the left hand side of the regexp operator is NULL, - ** then the result is also NULL. + /* If the left hand side of the regexp operator is NULL, + ** then the result is also NULL. */ if( !zString ){ return; @@ -167033,7 +202571,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ } /* Set the text that the regular expression operates on to a NULL - ** pointer. This is not really necessary, but it is tidier than + ** pointer. This is not really necessary, but it is tidier than ** leaving the regular expression object configured with an invalid ** pointer after this function returns. */ @@ -167044,7 +202582,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ } /* -** Implementations of scalar functions for case mapping - upper() and +** Implementations of scalar functions for case mapping - upper() and ** lower(). Function upper() converts its input to upper-case (ABC). ** Function lower() converts to lower-case (abc). ** @@ -167052,7 +202590,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ ** "language specific". Refer to ICU documentation for the differences ** between the two. ** -** To utilise "general" case mapping, the upper() or lower() scalar +** To utilise "general" case mapping, the upper() or lower() scalar ** functions are invoked with one argument: ** ** upper('ABC') -> 'abc' @@ -167123,6 +202661,8 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ assert( 0 ); /* Unreachable */ } +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ + /* ** Collation sequence destructor function. The pCtx argument points to ** a UCollator structure previously allocated using ucol_open(). @@ -167158,7 +202698,7 @@ static int icuCollationColl( /* ** Implementation of the scalar function icu_load_collation(). ** -** This scalar function is used to add ICU collation based collation +** This scalar function is used to add ICU collation based collation ** types to an SQLite database connection. It is intended to be called ** as follows: ** @@ -167169,8 +202709,8 @@ static int icuCollationColl( ** collation sequence to create. */ static void icuLoadCollation( - sqlite3_context *p, - int nArg, + sqlite3_context *p, + int nArg, sqlite3_value **apArg ){ sqlite3 *db = (sqlite3 *)sqlite3_user_data(p); @@ -167196,7 +202736,7 @@ static void icuLoadCollation( } assert(p); - rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, + rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator, icuCollationColl, icuCollationDel ); if( rc!=SQLITE_OK ){ @@ -167209,34 +202749,36 @@ static void icuLoadCollation( ** Register the ICU extension functions with database db. */ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ +# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) static const struct IcuScalar { const char *zName; /* Function name */ unsigned char nArg; /* Number of arguments */ - unsigned short enc; /* Optimal text encoding */ + unsigned int enc; /* Optimal text encoding */ unsigned char iContext; /* sqlite3_user_data() context */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } scalars[] = { - {"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation}, - {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc}, - {"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, - {"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, - {"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, - {"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, - {"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, - {"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, - {"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, - {"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, + {"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation}, +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) + {"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc}, + {"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16}, + {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16}, + {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, + {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc}, +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */ }; int rc = SQLITE_OK; int i; - for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ const struct IcuScalar *p = &scalars[i]; rc = sqlite3_create_function( - db, p->zName, p->nArg, p->enc, + db, p->zName, p->nArg, p->enc, p->iContext ? (void*)db : (void*)0, p->xFunc, 0, 0 ); @@ -167250,7 +202792,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){ __declspec(dllexport) #endif SQLITE_API int sqlite3_icu_init( - sqlite3 *db, + sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ @@ -167325,7 +202867,7 @@ static int icuCreate( if( argc>0 ){ n = strlen(argv[0])+1; } - p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n); + p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n); if( !p ){ return SQLITE_NOMEM; } @@ -167353,7 +202895,7 @@ static int icuDestroy(sqlite3_tokenizer *pTokenizer){ /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is pInput[0..nBytes-1]. A cursor -** used to incrementally tokenize this string is returned in +** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int icuOpen( @@ -167382,7 +202924,7 @@ static int icuOpen( nInput = strlen(zInput); } nChar = nInput+1; - pCsr = (IcuCursor *)sqlite3_malloc( + pCsr = (IcuCursor *)sqlite3_malloc64( sizeof(IcuCursor) + /* IcuCursor */ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ @@ -167395,7 +202937,7 @@ static int icuOpen( pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; pCsr->aOffset[iOut] = iInput; - U8_NEXT(zInput, iInput, nInput, c); + U8_NEXT(zInput, iInput, nInput, c); while( c>0 ){ int isError = 0; c = u_foldCase(c, opt); @@ -167541,7 +203083,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ************************************************************************* ** ** -** OVERVIEW +** OVERVIEW ** ** The RBU extension requires that the RBU update be packaged as an ** SQLite database. The tables it expects to find are described in @@ -167549,34 +203091,34 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** that the user wishes to write to, a corresponding data_xyz table is ** created in the RBU database and populated with one row for each row to ** update, insert or delete from the target table. -** +** ** The update proceeds in three stages: -** +** ** 1) The database is updated. The modified database pages are written ** to a *-oal file. A *-oal file is just like a *-wal file, except ** that it is named "-oal" instead of "-wal". ** Because regular SQLite clients do not look for file named ** "-oal", they go on using the original database in ** rollback mode while the *-oal file is being generated. -** +** ** During this stage RBU does not update the database by writing ** directly to the target tables. Instead it creates "imposter" ** tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses ** to update each b-tree individually. All updates required by each ** b-tree are completed before moving on to the next, and all ** updates are done in sorted key order. -** +** ** 2) The "-oal" file is moved to the equivalent "-wal" ** location using a call to rename(2). Before doing this the RBU ** module takes an EXCLUSIVE lock on the database file, ensuring ** that there are no other active readers. -** +** ** Once the EXCLUSIVE lock is released, any other database readers ** detect the new *-wal file and read the database in wal mode. At ** this point they see the new version of the database - including ** the updates made as part of the RBU update. -** -** 3) The new *-wal file is checkpointed. This proceeds in the same way +** +** 3) The new *-wal file is checkpointed. This proceeds in the same way ** as a regular database checkpoint, except that a single frame is ** checkpointed each time sqlite3rbu_step() is called. If the RBU ** handle is closed before the entire *-wal file is checkpointed, @@ -167585,7 +203127,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** the future. ** ** POTENTIAL PROBLEMS -** +** ** The rename() call might not be portable. And RBU is not currently ** syncing the directory after renaming the file. ** @@ -167607,7 +203149,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** fields are collected. This means we're probably writing a lot more ** data to disk when saving the state of an ongoing update to the RBU ** update database than is strictly necessary. -** +** */ /* #include */ @@ -167631,42 +203173,42 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** ************************************************************************* ** -** This file contains the public interface for the RBU extension. +** This file contains the public interface for the RBU extension. */ /* ** SUMMARY ** -** Writing a transaction containing a large number of operations on +** Writing a transaction containing a large number of operations on ** b-tree indexes that are collectively larger than the available cache -** memory can be very inefficient. +** memory can be very inefficient. ** ** The problem is that in order to update a b-tree, the leaf page (at least) ** containing the entry being inserted or deleted must be modified. If the -** working set of leaves is larger than the available cache memory, then a -** single leaf that is modified more than once as part of the transaction +** working set of leaves is larger than the available cache memory, then a +** single leaf that is modified more than once as part of the transaction ** may be loaded from or written to the persistent media multiple times. ** Additionally, because the index updates are likely to be applied in -** random order, access to pages within the database is also likely to be in +** random order, access to pages within the database is also likely to be in ** random order, which is itself quite inefficient. ** ** One way to improve the situation is to sort the operations on each index ** by index key before applying them to the b-tree. This leads to an IO ** pattern that resembles a single linear scan through the index b-tree, -** and all but guarantees each modified leaf page is loaded and stored +** and all but guarantees each modified leaf page is loaded and stored ** exactly once. SQLite uses this trick to improve the performance of ** CREATE INDEX commands. This extension allows it to be used to improve ** the performance of large transactions on existing databases. ** -** Additionally, this extension allows the work involved in writing the -** large transaction to be broken down into sub-transactions performed -** sequentially by separate processes. This is useful if the system cannot -** guarantee that a single update process will run for long enough to apply -** the entire update, for example because the update is being applied on a -** mobile device that is frequently rebooted. Even after the writer process +** Additionally, this extension allows the work involved in writing the +** large transaction to be broken down into sub-transactions performed +** sequentially by separate processes. This is useful if the system cannot +** guarantee that a single update process will run for long enough to apply +** the entire update, for example because the update is being applied on a +** mobile device that is frequently rebooted. Even after the writer process ** has committed one or more sub-transactions, other database clients continue -** to read from the original database snapshot. In other words, partially -** applied transactions are not visible to other clients. +** to read from the original database snapshot. In other words, partially +** applied transactions are not visible to other clients. ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction @@ -167682,9 +203224,9 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** ** * INSERT statements may not use any default values. ** -** * UPDATE and DELETE statements must identify their target rows by +** * UPDATE and DELETE statements must identify their target rows by ** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY -** KEY fields may not be updated or deleted. If the table being written +** KEY fields may not be updated or deleted. If the table being written ** has no PRIMARY KEY, affected rows must be identified by rowid. ** ** * UPDATE statements may not modify PRIMARY KEY columns. @@ -167701,10 +203243,10 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** PREPARATION ** ** An "RBU update" is stored as a separate SQLite database. A database -** containing an RBU update is an "RBU database". For each table in the +** containing an RBU update is an "RBU database". For each table in the ** target database to be updated, the RBU database should contain a table ** named "data_" containing the same set of columns as the -** target table, and one more - "rbu_control". The data_% table should +** target table, and one more - "rbu_control". The data_% table should ** have no PRIMARY KEY or UNIQUE constraints, but each column should have ** the same type as the corresponding column in the target database. ** The "rbu_control" column should have no type at all. For example, if @@ -167719,22 +203261,22 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** The order of the columns in the data_% table does not matter. ** ** Instead of a regular table, the RBU database may also contain virtual -** tables or view named using the data_ naming scheme. +** tables or view named using the data_ naming scheme. ** -** Instead of the plain data_ naming scheme, RBU database tables +** Instead of the plain data_ naming scheme, RBU database tables ** may also be named data_, where is any sequence ** of zero or more numeric characters (0-9). This can be significant because -** tables within the RBU database are always processed in order sorted by +** tables within the RBU database are always processed in order sorted by ** name. By judicious selection of the portion of the names ** of the RBU tables the user can therefore control the order in which they ** are processed. This can be useful, for example, to ensure that "external ** content" FTS4 tables are updated before their underlying content tables. ** ** If the target database table is a virtual table or a table that has no -** PRIMARY KEY declaration, the data_% table must also contain a column -** named "rbu_rowid". This column is mapped to the tables implicit primary -** key column - "rowid". Virtual tables for which the "rowid" column does -** not function like a primary key value cannot be updated using RBU. For +** PRIMARY KEY declaration, the data_% table must also contain a column +** named "rbu_rowid". This column is mapped to the tables implicit primary +** key column - "rowid". Virtual tables for which the "rowid" column does +** not function like a primary key value cannot be updated using RBU. For ** example, if the target db contains either of the following: ** ** CREATE VIRTUAL TABLE x1 USING fts3(a, b); @@ -167757,35 +203299,35 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control); ** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control); ** -** For each row to INSERT into the target database as part of the RBU +** For each row to INSERT into the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain integer value 0. The -** other columns should be set to the values that make up the new record -** to insert. +** other columns should be set to the values that make up the new record +** to insert. ** -** If the target database table has an INTEGER PRIMARY KEY, it is not -** possible to insert a NULL value into the IPK column. Attempting to +** If the target database table has an INTEGER PRIMARY KEY, it is not +** possible to insert a NULL value into the IPK column. Attempting to ** do so results in an SQLITE_MISMATCH error. ** -** For each row to DELETE from the target database as part of the RBU +** For each row to DELETE from the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain integer value 1. The ** real primary key values of the row to delete should be stored in the ** corresponding columns of the data_% table. The values stored in the ** other columns are not used. ** -** For each row to UPDATE from the target database as part of the RBU +** For each row to UPDATE from the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain a value of type text. -** The real primary key values identifying the row to update should be +** The real primary key values identifying the row to update should be ** stored in the corresponding columns of the data_% table row, as should -** the new values of all columns being update. The text value in the +** the new values of all columns being update. The text value in the ** "rbu_control" column must contain the same number of characters as ** there are columns in the target database table, and must consist entirely -** of 'x' and '.' characters (or in some special cases 'd' - see below). For +** of 'x' and '.' characters (or in some special cases 'd' - see below). For ** each column that is being updated, the corresponding character is set to ** 'x'. For those that remain as they are, the corresponding character of the -** rbu_control value should be set to '.'. For example, given the tables +** rbu_control value should be set to '.'. For example, given the tables ** above, the update statement: ** ** UPDATE t1 SET c = 'usa' WHERE a = 4; @@ -167799,30 +203341,30 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** target table with the value stored in the corresponding data_% column, the ** user-defined SQL function "rbu_delta()" is invoked and the result stored in ** the target table column. rbu_delta() is invoked with two arguments - the -** original value currently stored in the target table column and the +** original value currently stored in the target table column and the ** value specified in the data_xxx table. ** ** For example, this row: ** ** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d'); ** -** is similar to an UPDATE statement such as: +** is similar to an UPDATE statement such as: ** ** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4; ** -** Finally, if an 'f' character appears in place of a 'd' or 's' in an +** Finally, if an 'f' character appears in place of a 'd' or 's' in an ** ota_control string, the contents of the data_xxx table column is assumed ** to be a "fossil delta" - a patch to be applied to a blob value in the ** format used by the fossil source-code management system. In this case -** the existing value within the target database table must be of type BLOB. +** the existing value within the target database table must be of type BLOB. ** It is replaced by the result of applying the specified fossil delta to ** itself. ** ** If the target database table is a virtual table or a table with no PRIMARY -** KEY, the rbu_control value should not include a character corresponding +** KEY, the rbu_control value should not include a character corresponding ** to the rbu_rowid value. For example, this: ** -** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control) +** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control) ** VALUES(NULL, 'usa', 12, '.x'); ** ** causes a result similar to: @@ -167832,14 +203374,14 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** The data_xxx tables themselves should have no PRIMARY KEY declarations. ** However, RBU is more efficient if reading the rows in from each data_xxx ** table in "rowid" order is roughly the same as reading them sorted by -** the PRIMARY KEY of the corresponding target database table. In other -** words, rows should be sorted using the destination table PRIMARY KEY +** the PRIMARY KEY of the corresponding target database table. In other +** words, rows should be sorted using the destination table PRIMARY KEY ** fields before they are inserted into the data_xxx tables. ** ** USAGE ** -** The API declared below allows an application to apply an RBU update -** stored on disk to an existing target database. Essentially, the +** The API declared below allows an application to apply an RBU update +** stored on disk to an existing target database. Essentially, the ** application: ** ** 1) Opens an RBU handle using the sqlite3rbu_open() function. @@ -167850,24 +203392,24 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule( ** ** 3) Calls the sqlite3rbu_step() function one or more times on ** the new handle. Each call to sqlite3rbu_step() performs a single -** b-tree operation, so thousands of calls may be required to apply +** b-tree operation, so thousands of calls may be required to apply ** a complete update. ** ** 4) Calls sqlite3rbu_close() to close the RBU update handle. If ** sqlite3rbu_step() has been called enough times to completely ** apply the update to the target database, then the RBU database -** is marked as fully applied. Otherwise, the state of the RBU -** update application is saved in the RBU database for later +** is marked as fully applied. Otherwise, the state of the RBU +** update application is saved in the RBU database for later ** resumption. ** ** See comments below for more detail on APIs. ** ** If an update is only partially applied to the target database by the -** time sqlite3rbu_close() is called, various state information is saved +** time sqlite3rbu_close() is called, various state information is saved ** within the RBU database. This allows subsequent processes to automatically ** resume the RBU update from where it left off. ** -** To remove all RBU extension state information, returning an RBU database +** To remove all RBU extension state information, returning an RBU database ** to its original contents, it is sufficient to drop all tables that begin ** with the prefix "rbu_" ** @@ -167903,21 +203445,21 @@ typedef struct sqlite3rbu sqlite3rbu; ** the path to the RBU database. Each call to this function must be matched ** by a call to sqlite3rbu_close(). When opening the databases, RBU passes ** the SQLITE_CONFIG_URI flag to sqlite3_open_v2(). So if either zTarget -** or zRbu begin with "file:", it will be interpreted as an SQLite +** or zRbu begin with "file:", it will be interpreted as an SQLite ** database URI, not a regular file name. ** -** If the zState argument is passed a NULL value, the RBU extension stores -** the current state of the update (how many rows have been updated, which +** If the zState argument is passed a NULL value, the RBU extension stores +** the current state of the update (how many rows have been updated, which ** indexes are yet to be updated etc.) within the RBU database itself. This ** can be convenient, as it means that the RBU application does not need to -** organize removing a separate state file after the update is concluded. -** Or, if zState is non-NULL, it must be a path to a database file in which +** organize removing a separate state file after the update is concluded. +** Or, if zState is non-NULL, it must be a path to a database file in which ** the RBU extension can store the state of the update. ** ** When resuming an RBU update, the zState argument must be passed the same ** value as when the RBU update was started. ** -** Once the RBU update is finished, the RBU extension does not +** Once the RBU update is finished, the RBU extension does not ** automatically remove any zState database file, even if it created it. ** ** By default, RBU uses the default VFS to access the files on disk. To @@ -167930,7 +203472,7 @@ typedef struct sqlite3rbu sqlite3rbu; ** the zipvfs_create_vfs() API below for details on using RBU with zipvfs. */ SQLITE_API sqlite3rbu *sqlite3rbu_open( - const char *zTarget, + const char *zTarget, const char *zRbu, const char *zState ); @@ -167940,13 +203482,13 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open( ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** -** The second argument to this function identifies a database in which -** to store the state of the RBU vacuum operation if it is suspended. The +** The second argument to this function identifies a database in which +** to store the state of the RBU vacuum operation if it is suspended. The ** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum ** operation, the state database should either not exist or be empty -** (contain no tables). If an RBU vacuum is suspended by calling +** (contain no tables). If an RBU vacuum is suspended by calling ** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has -** returned SQLITE_DONE, the vacuum state is stored in the state database. +** returned SQLITE_DONE, the vacuum state is stored in the state database. ** The vacuum can be resumed by calling this function to open a new RBU ** handle specifying the same target and state databases. ** @@ -167956,25 +203498,51 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open( ** state database is not already present in the file-system, it is created ** with the same permissions as the target db is made. ** +** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the +** state database ends with "-vactmp". This name is reserved for internal +** use. +** ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, -** the next call to sqlite3rbu_vacuum() opens a handle that starts a +** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. ** ** As with sqlite3rbu_open(), Zipvfs users should rever to the comment -** describing the sqlite3rbu_create_vfs() API function below for -** a description of the complications associated with using RBU with +** describing the sqlite3rbu_create_vfs() API function below for +** a description of the complications associated with using RBU with ** zipvfs databases. */ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( - const char *zTarget, + const char *zTarget, const char *zState ); /* -** Internally, each RBU connection uses a separate SQLite database +** Configure a limit for the amount of temp space that may be used by +** the RBU handle passed as the first argument. The new limit is specified +** in bytes by the second parameter. If it is positive, the limit is updated. +** If the second parameter to this function is passed zero, then the limit +** is removed entirely. If the second parameter is negative, the limit is +** not modified (this is useful for querying the current limit). +** +** In all cases the returned value is the current limit in bytes (zero +** indicates unlimited). +** +** If the temp space limit is exceeded during operation, an SQLITE_FULL +** error is returned. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64); + +/* +** Return the current amount of temp file space, in bytes, currently used by +** the RBU handle passed as the only argument. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*); + +/* +** Internally, each RBU connection uses a separate SQLite database ** connection to access the target and rbu update databases. This ** API allows the application direct access to these database handles. ** @@ -167985,10 +203553,10 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( ** following scenarios: ** ** * If any target tables are virtual tables, it may be necessary to -** call sqlite3_create_module() on the target database handle to +** call sqlite3_create_module() on the target database handle to ** register the required virtual table implementations. ** -** * If the data_xxx tables in the RBU source database are virtual +** * If the data_xxx tables in the RBU source database are virtual ** tables, the application may need to call sqlite3_create_module() on ** the rbu update db handle to any required virtual table ** implementations. @@ -168007,12 +203575,12 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu); /* -** Do some work towards applying the RBU update to the target db. +** Do some work towards applying the RBU update to the target db. ** -** Return SQLITE_DONE if the update has been completely applied, or +** Return SQLITE_DONE if the update has been completely applied, or ** SQLITE_OK if no error occurs but there remains work to do to apply -** the RBU update. If an error does occur, some other error code is -** returned. +** the RBU update. If an error does occur, some other error code is +** returned. ** ** Once a call to sqlite3rbu_step() has returned a value other than ** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops @@ -168025,7 +203593,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu); ** ** If a power failure or application crash occurs during an update, following ** system recovery RBU may resume the update from the point at which the state -** was last saved. In other words, from the most recent successful call to +** was last saved. In other words, from the most recent successful call to ** sqlite3rbu_close() or this function. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. @@ -168033,7 +203601,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu); SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); /* -** Close an RBU handle. +** Close an RBU handle. ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the @@ -168041,26 +203609,26 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an -** SQLite error code is returned. Additionally, *pzErrmsg may be set to -** point to a buffer containing a utf-8 formatted English language error -** message. It is the responsibility of the caller to eventually free any -** such buffer using sqlite3_free(). +** SQLite error code is returned. Additionally, if pzErrmsg is not NULL, +** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted +** English language error message. It is the responsibility of the caller to +** eventually free any such buffer using sqlite3_free(). ** ** Otherwise, if no error occurs, this function returns SQLITE_OK if the -** update has been partially applied, or SQLITE_DONE if it has been +** update has been partially applied, or SQLITE_DONE if it has been ** completely applied. */ SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg); /* -** Return the total number of key-value operations (inserts, deletes or +** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current RBU update was started. */ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu); /* -** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100) +** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100) ** progress indications for the two stages of an RBU update. This API may ** be useful for driving GUI progress indicators and similar. ** @@ -168073,16 +203641,16 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu); ** The update is visible to non-RBU clients during stage 2. During stage 1 ** non-RBU reader clients may see the original database. ** -** If this API is called during stage 2 of the update, output variable +** If this API is called during stage 2 of the update, output variable ** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo) ** to a value between 0 and 10000 to indicate the permyriadage progress of -** stage 2. A value of 5000 indicates that stage 2 is half finished, +** stage 2. A value of 5000 indicates that stage 2 is half finished, ** 9000 indicates that it is 90% finished, and so on. ** -** If this API is called during stage 1 of the update, output variable +** If this API is called during stage 1 of the update, output variable ** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The -** value to which (*pnOne) is set depends on whether or not the RBU -** database contains an "rbu_count" table. The rbu_count table, if it +** value to which (*pnOne) is set depends on whether or not the RBU +** database contains an "rbu_count" table. The rbu_count table, if it ** exists, must contain the same columns as the following: ** ** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID; @@ -168099,7 +203667,7 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu); ** table exists but is not correctly populated, the value of the *pnOne ** output variable during stage 1 is undefined. */ -SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo); +SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo); /* ** Obtain an indication as to the current stage of an RBU update or vacuum. @@ -168141,20 +203709,20 @@ SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu); /* ** Create an RBU VFS named zName that accesses the underlying file-system -** via existing VFS zParent. Or, if the zParent parameter is passed NULL, +** via existing VFS zParent. Or, if the zParent parameter is passed NULL, ** then the new RBU VFS uses the default system VFS to access the file-system. -** The new object is registered as a non-default VFS with SQLite before +** The new object is registered as a non-default VFS with SQLite before ** returning. ** ** Part of the RBU implementation uses a custom VFS object. Usually, this -** object is created and deleted automatically by RBU. +** object is created and deleted automatically by RBU. ** ** The exception is for applications that also use zipvfs. In this case, ** the custom VFS must be explicitly created by the user before the RBU ** handle is opened. The RBU VFS should be installed so that the zipvfs -** VFS uses the RBU VFS, which in turn uses any other VFS layers in use +** VFS uses the RBU VFS, which in turn uses any other VFS layers in use ** (for example multiplexor) to access the file-system. For example, -** to assemble an RBU enabled VFS stack that uses both zipvfs and +** to assemble an RBU enabled VFS stack that uses both zipvfs and ** multiplexor (error checking omitted): ** ** // Create a VFS named "multiplex" (not the default). @@ -168176,9 +203744,9 @@ SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu); ** may be used by RBU clients. Attempting to use RBU with a zipvfs VFS stack ** that does not include the RBU layer results in an error. ** -** The overhead of adding the "rbu" VFS to the system is negligible for -** non-RBU users. There is no harm in an application accessing the -** file-system via "rbu" all the time, even if it only uses RBU functionality +** The overhead of adding the "rbu" VFS to the system is negligible for +** non-RBU users. There is no harm in an application accessing the +** file-system via "rbu" all the time, even if it only uses RBU functionality ** occasionally. */ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent); @@ -168209,6 +203777,13 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); /* Maximum number of prepared UPDATE statements held by this module */ #define SQLITE_RBU_UPDATE_CACHESIZE 16 +/* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM +** to enable checksum verification. +*/ +#ifndef RBU_ENABLE_DELTA_CKSUM +# define RBU_ENABLE_DELTA_CKSUM 0 +#endif + /* ** Swap two objects of type TYPE. */ @@ -168216,6 +203791,13 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); # define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} #endif +/* +** Name of the URI option that causes RBU to take an exclusive lock as +** part of the incremental checkpoint operation. +*/ +#define RBU_EXCLUSIVE_CHECKPOINT "rbu_exclusive_checkpoint" + + /* ** The rbu_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table consists of integer @@ -168224,17 +203806,17 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); ** RBU_STATE_STAGE: ** May be set to integer values 1, 2, 4 or 5. As follows: ** 1: the *-rbu file is currently under construction. -** 2: the *-rbu file has been constructed, but not yet moved +** 2: the *-rbu file has been constructed, but not yet moved ** to the *-wal path. ** 4: the checkpoint is underway. ** 5: the rbu update has been checkpointed. ** ** RBU_STATE_TBL: -** Only valid if STAGE==1. The target database name of the table +** Only valid if STAGE==1. The target database name of the table ** currently being written. ** ** RBU_STATE_IDX: -** Only valid if STAGE==1. The target database name of the index +** Only valid if STAGE==1. The target database name of the index ** currently being written, or NULL if the main table is currently being ** updated. ** @@ -168254,11 +203836,15 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); ** be continued if this happens). ** ** RBU_STATE_COOKIE: -** Valid if STAGE==1. The current change-counter cookie value in the +** Valid if STAGE==1. The current change-counter cookie value in the ** target db file. ** ** RBU_STATE_OALSZ: ** Valid if STAGE==1. The size in bytes of the *-oal file. +** +** RBU_STATE_DATATBL: +** Only valid if STAGE==1. The RBU database name of the table +** currently being read. */ #define RBU_STATE_STAGE 1 #define RBU_STATE_TBL 2 @@ -168269,6 +203855,7 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); #define RBU_STATE_COOKIE 7 #define RBU_STATE_OALSZ 8 #define RBU_STATE_PHASEONESTEP 9 +#define RBU_STATE_DATATBL 10 #define RBU_STAGE_OAL 1 #define RBU_STAGE_MOVE 2 @@ -168283,6 +203870,7 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName); typedef struct RbuFrame RbuFrame; typedef struct RbuObjIter RbuObjIter; typedef struct RbuState RbuState; +typedef struct RbuSpan RbuSpan; typedef struct rbu_vfs rbu_vfs; typedef struct rbu_file rbu_file; typedef struct RbuUpdateStmt RbuUpdateStmt; @@ -168311,6 +203899,7 @@ typedef sqlite3_int64 i64; struct RbuState { int eStage; char *zTbl; + char *zDataTbl; char *zIdx; i64 iWalCksum; int nRow; @@ -168326,12 +203915,17 @@ struct RbuUpdateStmt { RbuUpdateStmt *pNext; }; +struct RbuSpan { + const char *zSpan; + int nSpan; +}; + /* ** An iterator of this type is used to iterate through all objects in ** the target database that require updating. For each such table, the ** iterator visits, in order: ** -** * the table itself, +** * the table itself, ** * each index of the table (zero or more points to visit), and ** * a special "cleanup table" state. ** @@ -168340,7 +203934,12 @@ struct RbuUpdateStmt { ** it points to an array of flags nTblCol elements in size. The flag is ** set for each column that is either a part of the PK or a part of an ** index. Or clear otherwise. -** +** +** If there are one or more partial indexes on the table, all fields of +** this array set set to 1. This is because in that case, the module has +** no way to tell which fields will be required to add and remove entries +** from the partial indexes. +** */ struct RbuObjIter { sqlite3_stmt *pTblIter; /* Iterate through tables */ @@ -168370,6 +203969,9 @@ struct RbuObjIter { sqlite3_stmt *pInsert; /* Statement for INSERT operations */ sqlite3_stmt *pDelete; /* Statement for DELETE ops */ sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */ + int nIdxCol; + RbuSpan *aIdxCol; + char *zIdxSql; /* Last UPDATE used (for PK b-tree updates only), or NULL. */ RbuUpdateStmt *pRbuUpdate; @@ -168419,7 +204021,7 @@ struct RbuFrame { ** ** nPhaseOneStep: ** If the RBU database contains an rbu_count table, this value is set to -** a running estimate of the number of b-tree operations required to +** a running estimate of the number of b-tree operations required to ** finish populating the *-oal file. This allows the sqlite3_bp_progress() ** API to calculate the permyriadage progress of populating the *-oal file ** using the formula: @@ -168439,7 +204041,7 @@ struct RbuFrame { ** ** * the RBU update contains any UPDATE operations. If the PK specified ** for an UPDATE operation does not exist in the target table, then -** no b-tree operations are required on index b-trees. Or if the +** no b-tree operations are required on index b-trees. Or if the ** specified PK does exist, then (nIndex*2) such operations are ** required (one delete and one insert on each index b-tree). ** @@ -168469,6 +204071,7 @@ struct sqlite3rbu { RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created rbu vfs */ rbu_file *pTargetFd; /* File handle open on target db */ + int nPagePerSector; /* Pages per sector for pTargetFd */ i64 iOalSz; i64 nPhaseOneStep; @@ -168483,6 +204086,8 @@ struct sqlite3rbu { int pgsz; u8 *aBuf; i64 iWalCksum; + i64 szTemp; /* Current size of all temp files in use */ + i64 szTempLimit; /* Total size limit for temp files */ /* Used in RBU vacuum mode only */ int nRbu; /* Number of RBU VFS in the stack */ @@ -168491,23 +204096,34 @@ struct sqlite3rbu { /* ** An rbu VFS is implemented using an instance of this structure. +** +** Variable pRbu is only non-NULL for automatically created RBU VFS objects. +** It is NULL for RBU VFS objects created explicitly using +** sqlite3rbu_create_vfs(). It is used to track the total amount of temp +** space used by the RBU handle. */ struct rbu_vfs { sqlite3_vfs base; /* rbu VFS shim methods */ sqlite3_vfs *pRealVfs; /* Underlying VFS */ sqlite3_mutex *mutex; /* Mutex to protect pMain */ - rbu_file *pMain; /* Linked list of main db files */ + sqlite3rbu *pRbu; /* Owner RBU object */ + rbu_file *pMain; /* List of main db files */ + rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */ }; /* ** Each file opened by an rbu VFS is represented by an instance of ** the following structure. +** +** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable +** "sz" is set to the current size of the database file. */ struct rbu_file { sqlite3_file base; /* sqlite3_file methods */ sqlite3_file *pReal; /* Underlying file handle */ rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */ sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */ + i64 sz; /* Size of file in bytes (temp only) */ int openFlags; /* Flags this file was opened with */ u32 iCookie; /* Cookie value for main db files */ @@ -168521,6 +204137,7 @@ struct rbu_file { const char *zWal; /* Wal filename for this main db file */ rbu_file *pWalFd; /* Wal file descriptor for this main db */ rbu_file *pMainNext; /* Next MAIN_DB file */ + rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */ }; /* @@ -168570,6 +204187,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ return v; } +#if RBU_ENABLE_DELTA_CKSUM /* ** Compute a 32-bit checksum on the N-byte buffer. Return the result. */ @@ -168604,6 +204222,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){ } return sum3; } +#endif /* ** Apply a delta. @@ -168634,7 +204253,7 @@ static int rbuDeltaApply( ){ unsigned int limit; unsigned int total = 0; -#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST +#if RBU_ENABLE_DELTA_CKSUM char *zOrigOut = zOut; #endif @@ -168689,7 +204308,7 @@ static int rbuDeltaApply( case ';': { zDelta++; lenDelta--; zOut[0] = 0; -#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST +#if RBU_ENABLE_DELTA_CKSUM if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){ /* ERROR: bad checksum */ return -1; @@ -168767,6 +204386,7 @@ static void rbuFossilDeltaFunc( }else{ nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); if( nOut2!=nOut ){ + sqlite3_free(aOut); sqlite3_result_error(context, "corrupt fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); @@ -168778,7 +204398,7 @@ static void rbuFossilDeltaFunc( /* ** Prepare the SQL statement in buffer zSql against database handle db. ** If successful, set *ppStmt to point to the new statement and return -** SQLITE_OK. +** SQLITE_OK. ** ** Otherwise, if an error does occur, set *ppStmt to NULL and return ** an SQLite error code. Additionally, set output variable *pzErrmsg to @@ -168786,7 +204406,7 @@ static void rbuFossilDeltaFunc( ** of the caller to (eventually) free this buffer using sqlite3_free(). */ static int prepareAndCollectError( - sqlite3 *db, + sqlite3 *db, sqlite3_stmt **ppStmt, char **pzErrmsg, const char *zSql @@ -168818,9 +204438,9 @@ static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){ /* ** Unless it is NULL, argument zSql points to a buffer allocated using ** sqlite3_malloc containing an SQL statement. This function prepares the SQL -** statement against database db and frees the buffer. If statement -** compilation is successful, *ppStmt is set to point to the new statement -** handle and SQLITE_OK is returned. +** statement against database db and frees the buffer. If statement +** compilation is successful, *ppStmt is set to point to the new statement +** handle and SQLITE_OK is returned. ** ** Otherwise, if an error occurs, *ppStmt is set to NULL and an error code ** returned. In this case, *pzErrmsg may also be set to point to an error @@ -168831,7 +204451,7 @@ static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){ ** In this case SQLITE_NOMEM is returned and *ppStmt set to NULL. */ static int prepareFreeAndCollectError( - sqlite3 *db, + sqlite3 *db, sqlite3_stmt **ppStmt, char **pzErrmsg, char *zSql @@ -168886,13 +204506,18 @@ static void rbuObjIterClearStatements(RbuObjIter *pIter){ sqlite3_free(pUp); pUp = pTmp; } - + sqlite3_free(pIter->aIdxCol); + sqlite3_free(pIter->zIdxSql); + pIter->pSelect = 0; pIter->pInsert = 0; pIter->pDelete = 0; pIter->pRbuUpdate = 0; pIter->pTmpInsert = 0; pIter->nCol = 0; + pIter->nIdxCol = 0; + pIter->aIdxCol = 0; + pIter->zIdxSql = 0; } /* @@ -168910,16 +204535,16 @@ static void rbuObjIterFinalize(RbuObjIter *pIter){ /* ** Advance the iterator to the next position. ** -** If no error occurs, SQLITE_OK is returned and the iterator is left -** pointing to the next entry. Otherwise, an error code and message is -** left in the RBU handle passed as the first argument. A copy of the +** If no error occurs, SQLITE_OK is returned and the iterator is left +** pointing to the next entry. Otherwise, an error code and message is +** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){ int rc = p->rc; if( rc==SQLITE_OK ){ - /* Free any SQLite statements used while processing the previous object */ + /* Free any SQLite statements used while processing the previous object */ rbuObjIterClearStatements(pIter); if( pIter->zIdx==0 ){ rc = sqlite3_exec(p->dbMain, @@ -168978,7 +204603,7 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){ ** The implementation of the rbu_target_name() SQL function. This function ** accepts one or two arguments. The first argument is the name of a table - ** the name of a table in the RBU database. The second, if it is present, is 1 -** for a view or 0 for a table. +** for a view or 0 for a table. ** ** For a non-vacuum RBU handle, if the table name matches the pattern: ** @@ -169007,6 +204632,7 @@ static void rbuTargetNameFunc( zIn = (const char*)sqlite3_value_text(argv[0]); if( zIn ){ if( rbuIsVacuum(p) ){ + assert( argc==2 || argc==1 ); if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); } @@ -169025,19 +204651,19 @@ static void rbuTargetNameFunc( /* ** Initialize the iterator structure passed as the second argument. ** -** If no error occurs, SQLITE_OK is returned and the iterator is left -** pointing to the first entry. Otherwise, an error code and message is -** left in the RBU handle passed as the first argument. A copy of the +** If no error occurs, SQLITE_OK is returned and the iterator is left +** pointing to the first entry. Otherwise, an error code and message is +** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); - rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, + rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, sqlite3_mprintf( "SELECT rbu_target_name(name, type='view') AS target, name " - "FROM sqlite_master " + "FROM sqlite_schema " "WHERE type IN ('table', 'view') AND target IS NOT NULL " " %s " "ORDER BY name" @@ -169046,7 +204672,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' " - " FROM main.sqlite_master " + " FROM main.sqlite_schema " " WHERE type='index' AND tbl_name = ?" ); } @@ -169062,7 +204688,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ ** ** If an error has already occurred (p->rc is already set to something other ** than SQLITE_OK), then this function returns NULL without modifying the -** stored error code. In this case it still calls sqlite3_free() on any +** stored error code. In this case it still calls sqlite3_free() on any ** printf() parameters associated with %z conversions. */ static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){ @@ -169108,16 +204734,16 @@ static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){ } /* -** Attempt to allocate and return a pointer to a zeroed block of nByte -** bytes. +** Attempt to allocate and return a pointer to a zeroed block of nByte +** bytes. ** -** If an error (i.e. an OOM condition) occurs, return NULL and leave an -** error code in the rbu handle passed as the first argument. Or, if an -** error has already occurred when this function is called, return NULL +** If an error (i.e. an OOM condition) occurs, return NULL and leave an +** error code in the rbu handle passed as the first argument. Or, if an +** error has already occurred when this function is called, return NULL ** immediately without attempting the allocation or modifying the stored ** error code. */ -static void *rbuMalloc(sqlite3rbu *p, int nByte){ +static void *rbuMalloc(sqlite3rbu *p, sqlite3_int64 nByte){ void *pRet = 0; if( p->rc==SQLITE_OK ){ assert( nByte>0 ); @@ -169138,7 +204764,7 @@ static void *rbuMalloc(sqlite3rbu *p, int nByte){ ** error code in the RBU handle passed as the first argument. */ static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){ - int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; + sqlite3_int64 nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; char **azNew; azNew = (char**)rbuMalloc(p, nByte); @@ -169165,14 +204791,15 @@ static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){ static char *rbuStrndup(const char *zStr, int *pRc){ char *zRet = 0; - assert( *pRc==SQLITE_OK ); - if( zStr ){ - size_t nCopy = strlen(zStr) + 1; - zRet = (char*)sqlite3_malloc64(nCopy); - if( zRet ){ - memcpy(zRet, zStr, nCopy); - }else{ - *pRc = SQLITE_NOMEM; + if( *pRc==SQLITE_OK ){ + if( zStr ){ + size_t nCopy = strlen(zStr) + 1; + zRet = (char*)sqlite3_malloc64(nCopy); + if( zRet ){ + memcpy(zRet, zStr, nCopy); + }else{ + *pRc = SQLITE_NOMEM; + } } } @@ -169209,7 +204836,7 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){ ** RBU_PK_VTAB: Table is a virtual table. ** ** Argument *piPk is also of type (int*), and also points to an output -** parameter. Unless the table has an external primary key index +** parameter. Unless the table has an external primary key index ** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or, ** if the table does have an external primary key index, then *piPk ** is set to the root page number of the primary key index before @@ -169217,12 +204844,12 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){ ** ** ALGORITHM: ** -** if( no entry exists in sqlite_master ){ +** if( no entry exists in sqlite_schema ){ ** return RBU_PK_NOTABLE ** }else if( sql for the entry starts with "CREATE VIRTUAL" ){ ** return RBU_PK_VTAB ** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){ -** if( the index that is the pk exists in sqlite_master ){ +** if( the index that is the pk exists in sqlite_schema ){ ** *piPK = rootpage of that index. ** return RBU_PK_EXTERNAL ** }else{ @@ -169242,9 +204869,9 @@ static void rbuTableType( int *piPk ){ /* - ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q) + ** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q) ** 1) PRAGMA index_list = ? - ** 2) SELECT count(*) FROM sqlite_master where name=%Q + ** 2) SELECT count(*) FROM sqlite_schema where name=%Q ** 3) PRAGMA table_info = ? */ sqlite3_stmt *aStmt[4] = {0, 0, 0, 0}; @@ -169253,10 +204880,12 @@ static void rbuTableType( *piPk = 0; assert( p->rc==SQLITE_OK ); - p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg, + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg, sqlite3_mprintf( - "SELECT (sql LIKE 'create virtual%%'), rootpage" - " FROM sqlite_master" + "SELECT " + " (sql COLLATE nocase BETWEEN 'CREATE VIRTUAL' AND 'CREATE VIRTUAM')," + " rootpage" + " FROM sqlite_schema" " WHERE name=%Q", zTab )); if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){ @@ -169269,7 +204898,7 @@ static void rbuTableType( } *piTnum = sqlite3_column_int(aStmt[0], 1); - p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg, + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg, sqlite3_mprintf("PRAGMA index_list=%Q",zTab) ); if( p->rc ) goto rbuTableType_end; @@ -169277,9 +204906,9 @@ static void rbuTableType( const u8 *zOrig = sqlite3_column_text(aStmt[1], 3); const u8 *zIdx = sqlite3_column_text(aStmt[1], 1); if( zOrig && zIdx && zOrig[0]=='p' ){ - p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg, + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg, sqlite3_mprintf( - "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx + "SELECT rootpage FROM sqlite_schema WHERE name = %Q", zIdx )); if( p->rc==SQLITE_OK ){ if( sqlite3_step(aStmt[2])==SQLITE_ROW ){ @@ -169293,7 +204922,7 @@ static void rbuTableType( } } - p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg, + p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg, sqlite3_mprintf("PRAGMA table_info=%Q",zTab) ); if( p->rc==SQLITE_OK ){ @@ -169332,14 +204961,21 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){ pIter->nIndex = 0; while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ const char *zIdx = (const char*)sqlite3_column_text(pList, 1); + int bPartial = sqlite3_column_int(pList, 4); sqlite3_stmt *pXInfo = 0; if( zIdx==0 ) break; + if( bPartial ){ + memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); + } p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ int iCid = sqlite3_column_int(pXInfo, 1); if( iCid>=0 ) pIter->abIndexed[iCid] = 1; + if( iCid==-2 ){ + memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); + } } rbuFinalize(p, pXInfo); bIndex = 1; @@ -169362,7 +204998,7 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){ ** the table (not index) that the iterator currently points to. ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. If -** an error does occur, an error code and error message are also left in +** an error does occur, an error code and error message are also left in ** the RBU handle. */ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ @@ -169384,7 +205020,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ if( p->rc ) return p->rc; if( pIter->zIdx==0 ) pIter->iTnum = iTnum; - assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK + assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK || pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_WITHOUT_ROWID || pIter->eType==RBU_PK_VTAB ); @@ -169392,7 +205028,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ /* Populate the azTblCol[] and nTblCol variables based on the columns ** of the input table. Ignore any input table columns that begin with ** "rbu_". */ - p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, + p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl) ); if( p->rc==SQLITE_OK ){ @@ -169428,7 +205064,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ ** present in the input table. Populate the abTblPk[], azTblType[] and ** aiTblOrder[] arrays at the same time. */ if( p->rc==SQLITE_OK ){ - p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, + p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl) ); } @@ -169454,7 +205090,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ } pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc); - pIter->abTblPk[iOrder] = (iPk!=0); + assert( iPk>=0 ); + pIter->abTblPk[iOrder] = (u8)iPk; pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } @@ -169470,8 +205107,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ } /* -** This function constructs and returns a pointer to a nul-terminated -** string containing some SQL clause or list based on one or more of the +** This function constructs and returns a pointer to a nul-terminated +** string containing some SQL clause or list based on one or more of the ** column names currently stored in the pIter->azTblCol[] array. */ static char *rbuObjIterGetCollist( @@ -169490,23 +205127,232 @@ static char *rbuObjIterGetCollist( } /* -** This function is used to create a SELECT list (the list of SQL -** expressions that follows a SELECT keyword) for a SELECT statement -** used to read from an data_xxx or rbu_tmp_xxx table while updating the -** index object currently indicated by the iterator object passed as the -** second argument. A "PRAGMA index_xinfo = " statement is used +** Return a comma separated list of the quoted PRIMARY KEY column names, +** in order, for the current table. Before each column name, add the text +** zPre. After each column name, add the zPost text. Use zSeparator as +** the separator text (usually ", "). +*/ +static char *rbuObjIterGetPkList( + sqlite3rbu *p, /* RBU object */ + RbuObjIter *pIter, /* Object iterator for column names */ + const char *zPre, /* Before each quoted column name */ + const char *zSeparator, /* Separator to use between columns */ + const char *zPost /* After each quoted column name */ +){ + int iPk = 1; + char *zRet = 0; + const char *zSep = ""; + while( 1 ){ + int i; + for(i=0; inTblCol; i++){ + if( (int)pIter->abTblPk[i]==iPk ){ + const char *zCol = pIter->azTblCol[i]; + zRet = rbuMPrintf(p, "%z%s%s\"%w\"%s", zRet, zSep, zPre, zCol, zPost); + zSep = zSeparator; + break; + } + } + if( i==pIter->nTblCol ) break; + iPk++; + } + return zRet; +} + +/* +** This function is called as part of restarting an RBU vacuum within +** stage 1 of the process (while the *-oal file is being built) while +** updating a table (not an index). The table may be a rowid table or +** a WITHOUT ROWID table. It queries the target database to find the +** largest key that has already been written to the target table and +** constructs a WHERE clause that can be used to extract the remaining +** rows from the source table. For a rowid table, the WHERE clause +** is of the form: +** +** "WHERE _rowid_ > ?" +** +** and for WITHOUT ROWID tables: +** +** "WHERE (key1, key2) > (?, ?)" +** +** Instead of "?" placeholders, the actual WHERE clauses created by +** this function contain literal SQL values. +*/ +static char *rbuVacuumTableStart( + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter, /* RBU iterator object */ + int bRowid, /* True for a rowid table */ + const char *zWrite /* Target table name prefix */ +){ + sqlite3_stmt *pMax = 0; + char *zRet = 0; + if( bRowid ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, + sqlite3_mprintf( + "SELECT max(_rowid_) FROM \"%s%w\"", zWrite, pIter->zTbl + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ + sqlite3_int64 iMax = sqlite3_column_int64(pMax, 0); + zRet = rbuMPrintf(p, " WHERE _rowid_ > %lld ", iMax); + } + rbuFinalize(p, pMax); + }else{ + char *zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", " DESC"); + char *zSelect = rbuObjIterGetPkList(p, pIter, "quote(", "||','||", ")"); + char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", ""); + + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, + sqlite3_mprintf( + "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1", + zSelect, zWrite, pIter->zTbl, zOrder + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ + const char *zVal = (const char*)sqlite3_column_text(pMax, 0); + zRet = rbuMPrintf(p, " WHERE (%s) > (%s) ", zList, zVal); + } + rbuFinalize(p, pMax); + } + + sqlite3_free(zOrder); + sqlite3_free(zSelect); + sqlite3_free(zList); + } + return zRet; +} + +/* +** This function is called as part of restating an RBU vacuum when the +** current operation is writing content to an index. If possible, it +** queries the target index b-tree for the largest key already written to +** it, then composes and returns an expression that can be used in a WHERE +** clause to select the remaining required rows from the source table. +** It is only possible to return such an expression if: +** +** * The index contains no DESC columns, and +** * The last key written to the index before the operation was +** suspended does not contain any NULL values. +** +** The expression is of the form: +** +** (index-field1, index-field2, ...) > (?, ?, ...) +** +** except that the "?" placeholders are replaced with literal values. +** +** If the expression cannot be created, NULL is returned. In this case, +** the caller has to use an OFFSET clause to extract only the required +** rows from the sourct table, just as it does for an RBU update operation. +*/ +static char *rbuVacuumIndexStart( + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter /* RBU iterator object */ +){ + char *zOrder = 0; + char *zLhs = 0; + char *zSelect = 0; + char *zVector = 0; + char *zRet = 0; + int bFailed = 0; + const char *zSep = ""; + int iCol = 0; + sqlite3_stmt *pXInfo = 0; + + p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx) + ); + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ + int iCid = sqlite3_column_int(pXInfo, 1); + const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); + const char *zCol; + if( sqlite3_column_int(pXInfo, 3) ){ + bFailed = 1; + break; + } + + if( iCid<0 ){ + if( pIter->eType==RBU_PK_IPK ){ + int i; + for(i=0; pIter->abTblPk[i]==0; i++); + assert( inTblCol ); + zCol = pIter->azTblCol[i]; + }else{ + zCol = "_rowid_"; + } + }else{ + zCol = pIter->azTblCol[iCid]; + } + + zLhs = rbuMPrintf(p, "%z%s \"%w\" COLLATE %Q", + zLhs, zSep, zCol, zCollate + ); + zOrder = rbuMPrintf(p, "%z%s \"rbu_imp_%d%w\" COLLATE %Q DESC", + zOrder, zSep, iCol, zCol, zCollate + ); + zSelect = rbuMPrintf(p, "%z%s quote(\"rbu_imp_%d%w\")", + zSelect, zSep, iCol, zCol + ); + zSep = ", "; + iCol++; + } + rbuFinalize(p, pXInfo); + if( bFailed ) goto index_start_out; + + if( p->rc==SQLITE_OK ){ + sqlite3_stmt *pSel = 0; + + p->rc = prepareFreeAndCollectError(p->dbMain, &pSel, &p->zErrmsg, + sqlite3_mprintf("SELECT %s FROM \"rbu_imp_%w\" ORDER BY %s LIMIT 1", + zSelect, pIter->zTbl, zOrder + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSel) ){ + zSep = ""; + for(iCol=0; iColnCol; iCol++){ + const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol); + if( zQuoted==0 ){ + p->rc = SQLITE_NOMEM; + }else if( zQuoted[0]=='N' ){ + bFailed = 1; + break; + } + zVector = rbuMPrintf(p, "%z%s%s", zVector, zSep, zQuoted); + zSep = ", "; + } + + if( !bFailed ){ + zRet = rbuMPrintf(p, "(%s) > (%s)", zLhs, zVector); + } + } + rbuFinalize(p, pSel); + } + + index_start_out: + sqlite3_free(zOrder); + sqlite3_free(zSelect); + sqlite3_free(zVector); + sqlite3_free(zLhs); + return zRet; +} + +/* +** This function is used to create a SELECT list (the list of SQL +** expressions that follows a SELECT keyword) for a SELECT statement +** used to read from an data_xxx or rbu_tmp_xxx table while updating the +** index object currently indicated by the iterator object passed as the +** second argument. A "PRAGMA index_xinfo = " statement is used ** to obtain the required information. ** ** If the index is of the following form: ** ** CREATE INDEX i1 ON t1(c, b COLLATE nocase); ** -** and "t1" is a table with an explicit INTEGER PRIMARY KEY column +** and "t1" is a table with an explicit INTEGER PRIMARY KEY column ** "ipk", the returned string is: ** ** "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'" ** -** As well as the returned string, three other malloc'd strings are +** As well as the returned string, three other malloc'd strings are ** returned via output parameters. As follows: ** ** pzImposterCols: ... @@ -169543,36 +205389,44 @@ static char *rbuObjIterGetIndexCols( int iCid = sqlite3_column_int(pXInfo, 1); int bDesc = sqlite3_column_int(pXInfo, 3); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); - const char *zCol; + const char *zCol = 0; const char *zType; - if( iCid<0 ){ - /* An integer primary key. If the table has an explicit IPK, use - ** its name. Otherwise, use "rbu_rowid". */ - if( pIter->eType==RBU_PK_IPK ){ - int i; - for(i=0; pIter->abTblPk[i]==0; i++); - assert( inTblCol ); - zCol = pIter->azTblCol[i]; - }else if( rbuIsVacuum(p) ){ - zCol = "_rowid_"; + if( iCid==-2 ){ + int iSeq = sqlite3_column_int(pXInfo, 0); + zRet = sqlite3_mprintf("%z%s(%.*s) COLLATE %Q", zRet, zCom, + pIter->aIdxCol[iSeq].nSpan, pIter->aIdxCol[iSeq].zSpan, zCollate + ); + zType = ""; + }else { + if( iCid<0 ){ + /* An integer primary key. If the table has an explicit IPK, use + ** its name. Otherwise, use "rbu_rowid". */ + if( pIter->eType==RBU_PK_IPK ){ + int i; + for(i=0; pIter->abTblPk[i]==0; i++); + assert( inTblCol ); + zCol = pIter->azTblCol[i]; + }else if( rbuIsVacuum(p) ){ + zCol = "_rowid_"; + }else{ + zCol = "rbu_rowid"; + } + zType = "INTEGER"; }else{ - zCol = "rbu_rowid"; + zCol = pIter->azTblCol[iCid]; + zType = pIter->azTblType[iCid]; } - zType = "INTEGER"; - }else{ - zCol = pIter->azTblCol[iCid]; - zType = pIter->azTblType[iCid]; + zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom,zCol,zCollate); } - zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom, zCol, zCollate); if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){ const char *zOrder = (bDesc ? " DESC" : ""); - zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s", + zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s", zImpPK, zCom, nBind, zCol, zOrder ); } - zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q", + zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q", zImpCols, zCom, nBind, zCol, zType, zCollate ); zWhere = sqlite3_mprintf( @@ -169618,7 +205472,7 @@ static char *rbuObjIterGetIndexCols( ** the text ", old._rowid_" to the returned value. */ static char *rbuObjIterGetOldlist( - sqlite3rbu *p, + sqlite3rbu *p, RbuObjIter *pIter, const char *zObj ){ @@ -169659,7 +205513,7 @@ static char *rbuObjIterGetOldlist( ** "b = ?1 AND c = ?2" */ static char *rbuObjIterGetWhere( - sqlite3rbu *p, + sqlite3rbu *p, RbuObjIter *pIter ){ char *zList = 0; @@ -169674,7 +205528,7 @@ static char *rbuObjIterGetWhere( zSep = " AND "; } } - zList = rbuMPrintf(p, + zList = rbuMPrintf(p, "_rowid_ = (SELECT id FROM rbu_imposter2 WHERE %z)", zList ); @@ -169714,7 +205568,7 @@ static void rbuBadControlError(sqlite3rbu *p){ ** ** The memory for the returned string is obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free it using -** sqlite3_free(). +** sqlite3_free(). ** ** If an OOM error is encountered when allocating space for the new ** string, an error code is left in the rbu handle passed as the first @@ -169738,19 +205592,19 @@ static char *rbuObjIterGetSetlist( for(i=0; inTblCol; i++){ char c = zMask[pIter->aiSrcOrder[i]]; if( c=='x' ){ - zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", + zList = rbuMPrintf(p, "%z%s\"%w\"=?%d", zList, zSep, pIter->azTblCol[i], i+1 ); zSep = ", "; } else if( c=='d' ){ - zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)", + zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)", zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 ); zSep = ", "; } else if( c=='f' ){ - zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)", + zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)", zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1 ); zSep = ", "; @@ -169768,7 +205622,7 @@ static char *rbuObjIterGetSetlist( ** ** The memory for the returned string is obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free it using -** sqlite3_free(). +** sqlite3_free(). ** ** If an OOM error is encountered when allocating space for the new ** string, an error code is left in the rbu handle passed as the first @@ -169778,7 +205632,7 @@ static char *rbuObjIterGetSetlist( */ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ char *zRet = 0; - int nByte = nBind*2 + 1; + sqlite3_int64 nByte = 2*(sqlite3_int64)nBind + 1; zRet = (char*)rbuMalloc(p, nByte); if( zRet ){ @@ -169792,8 +205646,8 @@ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ } /* -** The iterator currently points to a table (not index) of type -** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY +** The iterator currently points to a table (not index) of type +** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY ** declaration for the corresponding imposter table. For example, ** if the iterator points to a table created as: ** @@ -169810,7 +205664,7 @@ static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){ const char *zSep = "PRIMARY KEY("; sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = */ - + p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) ); @@ -169848,7 +205702,7 @@ static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){ ** a table b-tree where the table has an external primary key. If the ** iterator passed as the second argument does not currently point to ** a table (not index) with an external primary key, this function is a -** no-op. +** no-op. ** ** Assuming the iterator does point to a table with an external PK, this ** function creates a WITHOUT ROWID imposter table named "rbu_imposter2" @@ -169875,8 +205729,8 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){ /* Figure out the name of the primary key index for the current table. ** This is needed for the argument to "PRAGMA index_xinfo". Set ** zIdx to point to a nul-terminated string containing this name. */ - p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg, - "SELECT name FROM sqlite_master WHERE rootpage = ?" + p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg, + "SELECT name FROM sqlite_schema WHERE rootpage = ?" ); if( p->rc==SQLITE_OK ){ sqlite3_bind_int(pQuery, 1, tnum); @@ -169897,7 +205751,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){ int iCid = sqlite3_column_int(pXInfo, 1); int bDesc = sqlite3_column_int(pXInfo, 3); const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); - zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %s", zCols, zComma, + zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma, iCid, pIter->azTblType[iCid], zCollate ); zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":""); @@ -169909,7 +205763,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum); rbuMPrintfExec(p, p->dbMain, - "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID", + "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID", zCols, zPk ); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); @@ -169917,7 +205771,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){ } /* -** If an error has already occurred when this function is called, it +** If an error has already occurred when this function is called, it ** immediately returns zero (without doing any work). Or, if an error ** occurs during the execution of this function, it sets the error code ** in the sqlite3rbu object indicated by the first argument and returns @@ -169930,9 +205784,9 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){ ** an imposter table are created, or zero otherwise. ** ** An imposter table is required in all cases except RBU_PK_VTAB. Only -** virtual tables are written to directly. The imposter table has the -** same schema as the actual target table (less any UNIQUE constraints). -** More precisely, the "same schema" means the same columns, types, +** virtual tables are written to directly. The imposter table has the +** same schema as the actual target table (less any UNIQUE constraints). +** More precisely, the "same schema" means the same columns, types, ** collation sequences. For tables that do not have an external PRIMARY ** KEY, it also means the same PRIMARY KEY declaration. */ @@ -169958,7 +205812,7 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){ ** "PRIMARY KEY" to the imposter table column declaration. */ zPk = "PRIMARY KEY "; } - zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s", + zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s", zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl, (pIter->abNotNull[iCol] ? " NOT NULL" : "") ); @@ -169973,8 +205827,8 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){ } sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum); - rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s", - pIter->zTbl, zSql, + rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s", + pIter->zTbl, zSql, (pIter->eType==RBU_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "") ); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0); @@ -169988,12 +205842,12 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){ ** INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...); ** ** The number of bound variables is equal to the number of columns in -** the target table, plus one (for the rbu_control column), plus one more -** (for the rbu_rowid column) if the target table is an implicit IPK or +** the target table, plus one (for the rbu_control column), plus one more +** (for the rbu_rowid column) if the target table is an implicit IPK or ** virtual table. */ static void rbuObjIterPrepareTmpInsert( - sqlite3rbu *p, + sqlite3rbu *p, RbuObjIter *pIter, const char *zCollist, const char *zRbuRowid @@ -170004,14 +205858,14 @@ static void rbuObjIterPrepareTmpInsert( assert( pIter->pTmpInsert==0 ); p->rc = prepareFreeAndCollectError( p->dbRbu, &pIter->pTmpInsert, &p->zErrmsg, sqlite3_mprintf( - "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)", + "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)", p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind )); } } static void rbuTmpInsertFunc( - sqlite3_context *pCtx, + sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ @@ -170020,8 +205874,8 @@ static void rbuTmpInsertFunc( int i; assert( sqlite3_value_int(apVal[0])!=0 - || p->objiter.eType==RBU_PK_EXTERNAL - || p->objiter.eType==RBU_PK_NONE + || p->objiter.eType==RBU_PK_EXTERNAL + || p->objiter.eType==RBU_PK_NONE ); if( sqlite3_value_int(apVal[0])!=0 ){ p->nPhaseOneStep += p->objiter.nIndex; @@ -170040,13 +205894,108 @@ static void rbuTmpInsertFunc( } } +static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ + sqlite3_stmt *pStmt = 0; + int rc = p->rc; + char *zRet = 0; + + assert( pIter->zIdxSql==0 && pIter->nIdxCol==0 && pIter->aIdxCol==0 ); + + if( rc==SQLITE_OK ){ + rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, + "SELECT trim(sql) FROM sqlite_schema WHERE type='index' AND name=?" + ); + } + if( rc==SQLITE_OK ){ + int rc2; + rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + char *zSql = (char*)sqlite3_column_text(pStmt, 0); + if( zSql ){ + pIter->zIdxSql = zSql = rbuStrndup(zSql, &rc); + } + if( zSql ){ + int nParen = 0; /* Number of open parenthesis */ + int i; + int iIdxCol = 0; + int nIdxAlloc = 0; + for(i=0; zSql[i]; i++){ + char c = zSql[i]; + + /* If necessary, grow the pIter->aIdxCol[] array */ + if( iIdxCol==nIdxAlloc ){ + RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc( + pIter->aIdxCol, (nIdxAlloc+16)*sizeof(RbuSpan) + ); + if( aIdxCol==0 ){ + rc = SQLITE_NOMEM; + break; + } + pIter->aIdxCol = aIdxCol; + nIdxAlloc += 16; + } + + if( c=='(' ){ + if( nParen==0 ){ + assert( iIdxCol==0 ); + pIter->aIdxCol[0].zSpan = &zSql[i+1]; + } + nParen++; + } + else if( c==')' ){ + nParen--; + if( nParen==0 ){ + int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; + pIter->aIdxCol[iIdxCol++].nSpan = nSpan; + i++; + break; + } + }else if( c==',' && nParen==1 ){ + int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan; + pIter->aIdxCol[iIdxCol++].nSpan = nSpan; + pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1]; + }else if( c=='"' || c=='\'' || c=='`' ){ + for(i++; 1; i++){ + if( zSql[i]==c ){ + if( zSql[i+1]!=c ) break; + i++; + } + } + }else if( c=='[' ){ + for(i++; 1; i++){ + if( zSql[i]==']' ) break; + } + }else if( c=='-' && zSql[i+1]=='-' ){ + for(i=i+2; zSql[i] && zSql[i]!='\n'; i++); + if( zSql[i]=='\0' ) break; + }else if( c=='/' && zSql[i+1]=='*' ){ + for(i=i+2; zSql[i] && (zSql[i]!='*' || zSql[i+1]!='/'); i++); + if( zSql[i]=='\0' ) break; + i++; + } + } + if( zSql[i] ){ + zRet = rbuStrndup(&zSql[i], &rc); + } + pIter->nIdxCol = iIdxCol; + } + } + + rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + } + + p->rc = rc; + return zRet; +} + /* -** Ensure that the SQLite statement handles required to update the -** target database object currently indicated by the iterator passed +** Ensure that the SQLite statement handles required to update the +** target database object currently indicated by the iterator passed ** as the second argument are available. */ static int rbuObjIterPrepareAll( - sqlite3rbu *p, + sqlite3rbu *p, RbuObjIter *pIter, int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */ ){ @@ -170069,9 +206018,11 @@ static int rbuObjIterPrepareAll( char *zImposterPK = 0; /* Primary key declaration for imposter */ char *zWhere = 0; /* WHERE clause on PK columns */ char *zBind = 0; + char *zPart = 0; int nBind = 0; assert( pIter->eType!=RBU_PK_VTAB ); + zPart = rbuObjIterGetIndexWhere(p, pIter); zCollist = rbuObjIterGetIndexCols( p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind ); @@ -170107,39 +206058,58 @@ static int rbuObjIterPrepareAll( if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ + char *zStart = 0; + if( nOffset ){ + zStart = rbuVacuumIndexStart(p, pIter); + if( zStart ){ + sqlite3_free(zLimit); + zLimit = 0; + } + } + zSql = sqlite3_mprintf( - "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s", - zCollist, + "SELECT %s, 0 AS rbu_control FROM '%q' %s %s %s ORDER BY %s%s", + zCollist, pIter->zDataTbl, + zPart, + (zStart ? (zPart ? "AND" : "WHERE") : ""), zStart, zCollist, zLimit ); + sqlite3_free(zStart); }else if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zSql = sqlite3_mprintf( - "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s", + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s", zCollist, p->zStateDb, pIter->zDataTbl, - zCollist, zLimit + zPart, zCollist, zLimit ); }else{ zSql = sqlite3_mprintf( - "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' " + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s " "UNION ALL " "SELECT %s, rbu_control FROM '%q' " - "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 " + "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 " "ORDER BY %s%s", - zCollist, p->zStateDb, pIter->zDataTbl, - zCollist, pIter->zDataTbl, + zCollist, p->zStateDb, pIter->zDataTbl, zPart, + zCollist, pIter->zDataTbl, + zPart, + (zPart ? "AND" : "WHERE"), zCollist, zLimit ); } - p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql); + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbRbu,&pIter->pSelect,pz,zSql); + }else{ + sqlite3_free(zSql); + } } sqlite3_free(zImposterCols); sqlite3_free(zImposterPK); sqlite3_free(zWhere); sqlite3_free(zBind); + sqlite3_free(zPart); }else{ int bRbuRowid = (pIter->eType==RBU_PK_VTAB) ||(pIter->eType==RBU_PK_NONE) @@ -170164,7 +206134,7 @@ static int rbuObjIterPrepareAll( if( p->rc==SQLITE_OK ){ p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pInsert, pz, sqlite3_mprintf( - "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)", + "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)", zWrite, zTbl, zCollist, (bRbuRowid ? ", _rowid_" : ""), zBindings ) ); @@ -170232,18 +206202,42 @@ static int rbuObjIterPrepareAll( /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ const char *zRbuRowid = ""; + char *zStart = 0; + char *zOrder = 0; if( bRbuRowid ){ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; } - p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, - sqlite3_mprintf( - "SELECT %s,%s rbu_control%s FROM '%q'%s", - zCollist, - (rbuIsVacuum(p) ? "0 AS " : ""), - zRbuRowid, - pIter->zDataTbl, zLimit - ) - ); + + if( rbuIsVacuum(p) ){ + if( nOffset ){ + zStart = rbuVacuumTableStart(p, pIter, bRbuRowid, zWrite); + if( zStart ){ + sqlite3_free(zLimit); + zLimit = 0; + } + } + if( bRbuRowid ){ + zOrder = rbuMPrintf(p, "_rowid_"); + }else{ + zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", ""); + } + } + + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, + sqlite3_mprintf( + "SELECT %s,%s rbu_control%s FROM '%q'%s %s %s %s", + zCollist, + (rbuIsVacuum(p) ? "0 AS " : ""), + zRbuRowid, + pIter->zDataTbl, (zStart ? zStart : ""), + (zOrder ? "ORDER BY" : ""), zOrder, + zLimit + ) + ); + } + sqlite3_free(zStart); + sqlite3_free(zOrder); } sqlite3_free(zWhere); @@ -170254,16 +206248,16 @@ static int rbuObjIterPrepareAll( sqlite3_free(zCollist); sqlite3_free(zLimit); } - + return p->rc; } /* ** Set output variable *ppStmt to point to an UPDATE statement that may ** be used to update the imposter table for the main table b-tree of the -** table object that pIter currently points to, assuming that the +** table object that pIter currently points to, assuming that the ** rbu_control column of the data_xyz table contains zMask. -** +** ** If the zMask string does not specify any columns to update, then this ** is not an error. Output variable *ppStmt is set to NULL in this case. */ @@ -170290,7 +206284,7 @@ static int rbuGetUpdateStmt( *pp = pUp->pNext; pUp->pNext = pIter->pRbuUpdate; pIter->pRbuUpdate = pUp; - *ppStmt = pUp->pUpdate; + *ppStmt = pUp->pUpdate; return SQLITE_OK; } nUp++; @@ -170320,7 +206314,7 @@ static int rbuGetUpdateStmt( const char *zPrefix = ""; if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_"; - zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s", + zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s", zPrefix, pIter->zTbl, zSet, zWhere ); p->rc = prepareFreeAndCollectError( @@ -170336,8 +206330,8 @@ static int rbuGetUpdateStmt( } static sqlite3 *rbuOpenDbhandle( - sqlite3rbu *p, - const char *zName, + sqlite3rbu *p, + const char *zName, int bUseVfs ){ sqlite3 *db = 0; @@ -170359,14 +206353,15 @@ static sqlite3 *rbuOpenDbhandle( static void rbuFreeState(RbuState *p){ if( p ){ sqlite3_free(p->zTbl); + sqlite3_free(p->zDataTbl); sqlite3_free(p->zIdx); sqlite3_free(p); } } /* -** Allocate an RbuState object and load the contents of the rbu_state -** table into it. Return a pointer to the new object. It is the +** Allocate an RbuState object and load the contents of the rbu_state +** table into it. Return a pointer to the new object. It is the ** responsibility of the caller to eventually free the object using ** sqlite3_free(). ** @@ -170382,7 +206377,7 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState)); if( pRet==0 ) return 0; - rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, + rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb) ); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ @@ -170422,13 +206417,17 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ break; case RBU_STATE_OALSZ: - pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1); + pRet->iOalSz = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_PHASEONESTEP: pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1); break; + case RBU_STATE_DATATBL: + pRet->zDataTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc); + break; + default: rc = SQLITE_CORRUPT; break; @@ -170445,13 +206444,19 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. +** +** If argument dbMain is not NULL, then it is a database handle already +** open on the target database. Use this handle instead of opening a new +** one. */ -static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ +static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); + assert( dbMain==0 || rbuIsVacuum(p)==0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); + p->dbMain = dbMain; if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); @@ -170486,9 +206491,9 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ int bOk = 0; sqlite3_stmt *pCnt = 0; p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg, - "SELECT count(*) FROM stat.sqlite_master" + "SELECT count(*) FROM stat.sqlite_schema" ); - if( p->rc==SQLITE_OK + if( p->rc==SQLITE_OK && sqlite3_step(pCnt)==SQLITE_ROW && 1==sqlite3_column_int(pCnt, 0) ){ @@ -170501,7 +206506,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("invalid state database"); } - + if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); } @@ -170555,7 +206560,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ if( *zExtra=='\0' ) zExtra = 0; } - zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", + zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s", sqlite3_db_filename(p->dbRbu, "main"), (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra) ); @@ -170570,19 +206575,19 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ } if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_create_function(p->dbMain, + p->rc = sqlite3_create_function(p->dbMain, "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0 ); } if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_create_function(p->dbMain, + p->rc = sqlite3_create_function(p->dbMain, "rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0 ); } if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_create_function(p->dbRbu, + p->rc = sqlite3_create_function(p->dbRbu, "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0 ); } @@ -170590,9 +206595,9 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p); } - rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master"); + rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_schema"); - /* Mark the database file just opened as an RBU target database. If + /* Mark the database file just opened as an RBU target database. If ** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use. ** This is an error. */ if( p->rc==SQLITE_OK ){ @@ -170640,10 +206645,10 @@ static void rbuFileSuffix3(const char *zBase, char *z){ } /* -** Return the current wal-index header checksum for the target database +** Return the current wal-index header checksum for the target database ** as a 64-bit integer. ** -** The checksum is store in the first page of xShmMap memory as an 8-byte +** The checksum is store in the first page of xShmMap memory as an 8-byte ** blob starting at byte offset 40. */ static i64 rbuShmChecksum(sqlite3rbu *p){ @@ -170661,11 +206666,11 @@ static i64 rbuShmChecksum(sqlite3rbu *p){ /* ** This function is called as part of initializing or reinitializing an -** incremental checkpoint. +** incremental checkpoint. ** -** It populates the sqlite3rbu.aFrame[] array with the set of -** (wal frame -> db page) copy operations required to checkpoint the -** current wal file, and obtains the set of shm locks required to safely +** It populates the sqlite3rbu.aFrame[] array with the set of +** (wal frame -> db page) copy operations required to checkpoint the +** current wal file, and obtains the set of shm locks required to safely ** perform the copy operations directly on the file-system. ** ** If argument pState is not NULL, then the incremental checkpoint is @@ -170683,7 +206688,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){ if( pState==0 ){ p->eStage = 0; if( p->rc==SQLITE_OK ){ - p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0); + p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_schema", 0, 0, 0); } } @@ -170700,19 +206705,19 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){ ** would be read/written are recorded in the sqlite3rbu.aFrame[] ** array. ** - ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, + ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, ** READ0 and CHECKPOINT locks taken as part of the checkpoint are ** no-ops. These locks will not be released until the connection ** is closed. ** - ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL + ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL ** error. ** ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[] - ** array populated with a set of (frame -> page) mappings. Because the - ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy - ** data from the wal file into the database file according to the + ** array populated with a set of (frame -> page) mappings. Because the + ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy + ** data from the wal file into the database file according to the ** contents of aFrame[]. */ if( p->rc==SQLITE_OK ){ @@ -170733,6 +206738,23 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){ if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){ p->rc = SQLITE_DONE; p->eStage = RBU_STAGE_DONE; + }else{ + int nSectorSize; + sqlite3_file *pDb = p->pTargetFd->pReal; + sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal; + assert( p->nPagePerSector==0 ); + nSectorSize = pDb->pMethods->xSectorSize(pDb); + if( nSectorSize>p->pgsz ){ + p->nPagePerSector = nSectorSize / p->pgsz; + }else{ + p->nPagePerSector = 1; + } + + /* Call xSync() on the wal file. This causes SQLite to sync the + ** directory in which the target database and the wal file reside, in + ** case it has not been synced since the rename() call in + ** rbuMoveOalFile(). */ + p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL); } } } @@ -170771,7 +206793,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ /* ** Called when a page of data is written to offset iOff of the database -** file while the rbu handle is in capture mode. Record the page number +** file while the rbu handle is in capture mode. Record the page number ** of the page being written in the aFrame[] array. */ static int rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){ @@ -170800,15 +206822,31 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){ /* -** Take an EXCLUSIVE lock on the database file. +** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if +** successful, or an SQLite error code otherwise. */ -static void rbuLockDatabase(sqlite3rbu *p){ - sqlite3_file *pReal = p->pTargetFd->pReal; - assert( p->rc==SQLITE_OK ); - p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED); - if( p->rc==SQLITE_OK ){ - p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE); +static int rbuLockDatabase(sqlite3 *db){ + int rc = SQLITE_OK; + sqlite3_file *fd = 0; + sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd); + + if( fd->pMethods ){ + rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED); + if( rc==SQLITE_OK ){ + rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE); + } } + return rc; +} + +/* +** Return true if the database handle passed as the only argument +** was opened with the rbu_exclusive_checkpoint=1 URI parameter +** specified. Or false otherwise. +*/ +static int rbuExclusiveCheckpoint(sqlite3 *db){ + const char *zUri = sqlite3_db_filename(db, 0); + return sqlite3_uri_boolean(zUri, RBU_EXCLUSIVE_CHECKPOINT, 0); } #if defined(_WIN32_WCE) @@ -170839,7 +206877,7 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){ ** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock ** on the database file. This proc moves the *-oal file to the *-wal path, ** then reopens the database file (this time in vanilla, non-oal, WAL mode). -** If an error occurs, leave an error code and error message in the rbu +** If an error occurs, leave an error code and error message in the rbu ** handle. */ static void rbuMoveOalFile(sqlite3rbu *p){ @@ -170861,23 +206899,29 @@ static void rbuMoveOalFile(sqlite3rbu *p){ }else{ /* Move the *-oal file to *-wal. At this point connection p->db is ** holding a SHARED lock on the target database file (because it is - ** in WAL mode). So no other connection may be writing the db. + ** in WAL mode). So no other connection may be writing the db. ** ** In order to ensure that there are no database readers, an EXCLUSIVE ** lock is obtained here before the *-oal is moved to *-wal. */ - rbuLockDatabase(p); - if( p->rc==SQLITE_OK ){ - rbuFileSuffix3(zBase, zWal); - rbuFileSuffix3(zBase, zOal); + sqlite3 *dbMain = 0; + rbuFileSuffix3(zBase, zWal); + rbuFileSuffix3(zBase, zOal); - /* Re-open the databases. */ - rbuObjIterFinalize(&p->objiter); - sqlite3_close(p->dbRbu); - sqlite3_close(p->dbMain); - p->dbMain = 0; - p->dbRbu = 0; + /* Re-open the databases. */ + rbuObjIterFinalize(&p->objiter); + sqlite3_close(p->dbRbu); + sqlite3_close(p->dbMain); + p->dbMain = 0; + p->dbRbu = 0; + dbMain = rbuOpenDbhandle(p, p->zTarget, 1); + if( dbMain ){ + assert( p->rc==SQLITE_OK ); + p->rc = rbuLockDatabase(dbMain); + } + + if( p->rc==SQLITE_OK ){ #if defined(_WIN32_WCE) { LPWSTR zWideOal; @@ -170904,11 +206948,19 @@ static void rbuMoveOalFile(sqlite3rbu *p){ #else p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK; #endif + } - if( p->rc==SQLITE_OK ){ - rbuOpenDatabase(p, 0); - rbuSetupCheckpoint(p, 0); - } + if( p->rc!=SQLITE_OK + || rbuIsVacuum(p) + || rbuExclusiveCheckpoint(dbMain)==0 + ){ + sqlite3_close(dbMain); + dbMain = 0; + } + + if( p->rc==SQLITE_OK ){ + rbuOpenDatabase(p, dbMain, 0); + rbuSetupCheckpoint(p, 0); } } @@ -171019,8 +207071,8 @@ static void rbuStepOneOp(sqlite3rbu *p, int eType){ /* If this is an INSERT into a table b-tree and the table has an ** explicit INTEGER PRIMARY KEY, check that this is not an attempt ** to write a NULL into the IPK column. That is not permitted. */ - if( eType==RBU_INSERT - && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] + if( eType==RBU_INSERT + && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL ){ p->rc = SQLITE_MISMATCH; @@ -171037,18 +207089,18 @@ static void rbuStepOneOp(sqlite3rbu *p, int eType){ if( p->rc ) return; } if( pIter->zIdx==0 ){ - if( pIter->eType==RBU_PK_VTAB - || pIter->eType==RBU_PK_NONE - || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)) + if( pIter->eType==RBU_PK_VTAB + || pIter->eType==RBU_PK_NONE + || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)) ){ - /* For a virtual table, or a table with no primary key, the + /* For a virtual table, or a table with no primary key, the ** SELECT statement is: ** ** SELECT , rbu_control, rbu_rowid FROM .... ** ** Hence column_value(pIter->nCol+1). */ - assertColumnName(pIter->pSelect, pIter->nCol+1, + assertColumnName(pIter->pSelect, pIter->nCol+1, rbuIsVacuum(p) ? "rowid" : "rbu_rowid" ); pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1); @@ -171112,8 +207164,8 @@ static int rbuStep(sqlite3rbu *p){ p->rc = sqlite3_bind_value(pUpdate, i+1, pVal); } } - if( p->rc==SQLITE_OK - && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) + if( p->rc==SQLITE_OK + && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) ){ /* Bind the rbu_rowid value to column _rowid_ */ assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid"); @@ -171143,7 +207195,7 @@ static void rbuIncrSchemaCookie(sqlite3rbu *p){ int iCookie = 1000000; sqlite3_stmt *pStmt; - p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg, + p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg, "PRAGMA schema_version" ); if( p->rc==SQLITE_OK ){ @@ -171175,7 +207227,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ int rc; assert( p->zErrmsg==0 ); - rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg, + rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg, sqlite3_mprintf( "INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES " "(%d, %d), " @@ -171186,17 +207238,19 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ "(%d, %lld), " "(%d, %lld), " "(%d, %lld), " - "(%d, %lld) ", + "(%d, %lld), " + "(%d, %Q) ", p->zStateDb, RBU_STATE_STAGE, eStage, - RBU_STATE_TBL, p->objiter.zTbl, - RBU_STATE_IDX, p->objiter.zIdx, - RBU_STATE_ROW, p->nStep, + RBU_STATE_TBL, p->objiter.zTbl, + RBU_STATE_IDX, p->objiter.zIdx, + RBU_STATE_ROW, p->nStep, RBU_STATE_PROGRESS, p->nProgress, RBU_STATE_CKPT, p->iWalCksum, RBU_STATE_COOKIE, (i64)pFd->iCookie, RBU_STATE_OALSZ, p->iOalSz, - RBU_STATE_PHASEONESTEP, p->nPhaseOneStep + RBU_STATE_PHASEONESTEP, p->nPhaseOneStep, + RBU_STATE_DATATBL, p->objiter.zDataTbl ) ); assert( pInsert==0 || rc==SQLITE_OK ); @@ -171211,7 +207265,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ /* -** The second argument passed to this function is the name of a PRAGMA +** The second argument passed to this function is the name of a PRAGMA ** setting - "page_size", "auto_vacuum", "user_version" or "application_id". ** This function executes the following on sqlite3rbu.dbRbu: ** @@ -171230,7 +207284,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){ static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){ if( p->rc==SQLITE_OK ){ sqlite3_stmt *pPragma = 0; - p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg, + p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.%s", zPragma) ); if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){ @@ -171243,7 +207297,7 @@ static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){ } /* -** The RBU handle passed as the only argument has just been opened and +** The RBU handle passed as the only argument has just been opened and ** the state database is empty. If this RBU handle was opened for an ** RBU vacuum operation, create the schema in the target db. */ @@ -171254,8 +207308,8 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){ assert( rbuIsVacuum(p) ); p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg); if( p->rc==SQLITE_OK ){ - p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, - "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0" + p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, + "SELECT sql FROM sqlite_schema WHERE sql!='' AND rootpage!=0" " AND name!='sqlite_sequence' " " ORDER BY type DESC" ); @@ -171269,14 +207323,14 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){ if( p->rc!=SQLITE_OK ) return; if( p->rc==SQLITE_OK ){ - p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, - "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL" + p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, + "SELECT * FROM sqlite_schema WHERE rootpage=0 OR rootpage IS NULL" ); } if( p->rc==SQLITE_OK ){ - p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, - "INSERT INTO sqlite_master VALUES(?,?,?,?,?)" + p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, + "INSERT INTO sqlite_schema VALUES(?,?,?,?,?)" ); } @@ -171316,11 +207370,11 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){ while( p->rc==SQLITE_OK && pIter->zTbl ){ if( pIter->bCleanup ){ - /* Clean up the rbu_tmp_xxx table for the previous table. It + /* Clean up the rbu_tmp_xxx table for the previous table. It ** cannot be dropped as there are currently active SQL statements. ** But the contents can be deleted. */ if( rbuIsVacuum(p)==0 && pIter->abIndexed ){ - rbuMPrintfExec(p, p->dbRbu, + rbuMPrintfExec(p, p->dbRbu, "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl ); } @@ -171370,10 +207424,10 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){ if( p->rc==SQLITE_OK ){ if( p->nStep>=p->nFrame ){ sqlite3_file *pDb = p->pTargetFd->pReal; - + /* Sync the db file */ p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL); - + /* Update nBackfill */ if( p->rc==SQLITE_OK ){ void volatile *ptr; @@ -171382,15 +207436,32 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){ ((u32 volatile*)ptr)[24] = p->iMaxFrame; } } - + if( p->rc==SQLITE_OK ){ p->eStage = RBU_STAGE_DONE; p->rc = SQLITE_DONE; } }else{ - RbuFrame *pFrame = &p->aFrame[p->nStep]; - rbuCheckpointFrame(p, pFrame); - p->nStep++; + /* At one point the following block copied a single frame from the + ** wal file to the database file. So that one call to sqlite3rbu_step() + ** checkpointed a single frame. + ** + ** However, if the sector-size is larger than the page-size, and the + ** application calls sqlite3rbu_savestate() or close() immediately + ** after this step, then rbu_step() again, then a power failure occurs, + ** then the database page written here may be damaged. Work around + ** this by checkpointing frames until the next page in the aFrame[] + ** lies on a different disk sector to the current one. */ + u32 iSector; + do{ + RbuFrame *pFrame = &p->aFrame[p->nStep]; + iSector = (pFrame->iDbPage-1) / p->nPagePerSector; + rbuCheckpointFrame(p, pFrame); + p->nStep++; + }while( p->nStepnFrame + && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector) + && p->rc==SQLITE_OK + ); } p->nProgress++; } @@ -171433,9 +207504,10 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){ RbuObjIter *pIter = &p->objiter; int rc = SQLITE_OK; - while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup + while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup || rbuStrCompare(pIter->zIdx, pState->zIdx) - || rbuStrCompare(pIter->zTbl, pState->zTbl) + || (pState->zDataTbl==0 && rbuStrCompare(pIter->zTbl, pState->zTbl)) + || (pState->zDataTbl && rbuStrCompare(pIter->zDataTbl, pState->zDataTbl)) )){ rc = rbuObjIterNext(p, pIter); } @@ -171487,6 +207559,7 @@ static void rbuCreateVfs(sqlite3rbu *p){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd); assert( pVfs ); p->zVfsName = pVfs->zName; + ((rbu_vfs*)pVfs)->pRbu = p; } } @@ -171507,7 +207580,7 @@ static void rbuDeleteVfs(sqlite3rbu *p){ ** the number of auxilliary indexes on the table. */ static void rbuIndexCntFunc( - sqlite3_context *pCtx, + sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ @@ -171515,11 +207588,12 @@ static void rbuIndexCntFunc( sqlite3_stmt *pStmt = 0; char *zErrmsg = 0; int rc; + sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain); assert( nVal==1 ); - - rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg, - sqlite3_mprintf("SELECT count(*) FROM sqlite_master " + + rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg, + sqlite3_mprintf("SELECT count(*) FROM sqlite_schema " "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0])) ); if( rc!=SQLITE_OK ){ @@ -171533,7 +207607,7 @@ static void rbuIndexCntFunc( if( rc==SQLITE_OK ){ sqlite3_result_int(pCtx, nIndex); }else{ - sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1); + sqlite3_result_error(pCtx, sqlite3_errmsg(db), -1); } } @@ -171552,7 +207626,7 @@ static void rbuIndexCntFunc( ** and the cnt column the number of rows it contains. ** ** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt -** for all rows in the rbu_count table, where nIndex is the number of +** for all rows in the rbu_count table, where nIndex is the number of ** indexes on the corresponding target database table. */ static void rbuInitPhaseOneSteps(sqlite3rbu *p){ @@ -171562,15 +207636,15 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){ p->nPhaseOneStep = -1; - p->rc = sqlite3_create_function(p->dbRbu, + p->rc = sqlite3_create_function(p->dbRbu, "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0 ); - + /* Check for the rbu_count table. If it does not exist, or if an error ** occurs, nPhaseOneStep will be left set to -1. */ if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, - "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'" + "SELECT 1 FROM sqlite_schema WHERE tbl_name = 'rbu_count'" ); } if( p->rc==SQLITE_OK ){ @@ -171579,7 +207653,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){ } p->rc = sqlite3_finalize(pStmt); } - + if( p->rc==SQLITE_OK && bExists ){ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg, "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))" @@ -171597,7 +207671,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){ static sqlite3rbu *openRbuHandle( - const char *zTarget, + const char *zTarget, const char *zRbu, const char *zState ){ @@ -171635,11 +207709,11 @@ static sqlite3rbu *openRbuHandle( ** to be a wal-mode db. But, this may have happened due to an earlier ** RBU vacuum operation leaving an old wal file in the directory. ** If this is the case, it will have been checkpointed and deleted - ** when the handle was closed and a second attempt to open the + ** when the handle was closed and a second attempt to open the ** database may succeed. */ - rbuOpenDatabase(p, &bRetry); + rbuOpenDatabase(p, 0, &bRetry); if( bRetry ){ - rbuOpenDatabase(p, 0); + rbuOpenDatabase(p, 0, 0); } } @@ -171648,7 +207722,7 @@ static sqlite3rbu *openRbuHandle( assert( pState || p->rc!=SQLITE_OK ); if( p->rc==SQLITE_OK ){ - if( pState->eStage==0 ){ + if( pState->eStage==0 ){ rbuDeleteOalFile(p); rbuInitPhaseOneSteps(p); p->eStage = RBU_STAGE_OAL; @@ -171672,15 +207746,15 @@ static sqlite3rbu *openRbuHandle( } } - if( p->rc==SQLITE_OK + if( p->rc==SQLITE_OK && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE) && pState->eStage!=0 ){ rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd); - if( pFd->iCookie!=pState->iCookie ){ + if( pFd->iCookie!=pState->iCookie ){ /* At this point (pTargetFd->iCookie) contains the value of the - ** change-counter cookie (the thing that gets incremented when a - ** transaction is committed in rollback mode) currently stored on + ** change-counter cookie (the thing that gets incremented when a + ** transaction is committed in rollback mode) currently stored on ** page 1 of the database file. */ p->rc = SQLITE_BUSY; p->zErrmsg = sqlite3_mprintf("database modified during rbu %s", @@ -171717,7 +207791,7 @@ static sqlite3rbu *openRbuHandle( } /* Check if the main database is a zipvfs db. If it is, set the upper - ** level pager to use "journal_mode=off". This prevents it from + ** level pager to use "journal_mode=off". This prevents it from ** generating a large journal using a temp file. */ if( p->rc==SQLITE_OK ){ int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0); @@ -171734,6 +207808,14 @@ static sqlite3rbu *openRbuHandle( }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ + if( !rbuIsVacuum(p) && rbuExclusiveCheckpoint(p->dbMain) ){ + /* If the rbu_exclusive_checkpoint=1 URI parameter was specified + ** and an incremental checkpoint is being resumed, attempt an + ** exclusive lock on the db file. If this fails, so be it. */ + p->eStage = RBU_STAGE_DONE; + rbuLockDatabase(p->dbMain); + p->eStage = RBU_STAGE_CKPT; + } rbuSetupCheckpoint(p, pState); }else if( p->eStage==RBU_STAGE_DONE ){ p->rc = SQLITE_DONE; @@ -171763,15 +207845,14 @@ static sqlite3rbu *rbuMisuseError(void){ } /* -** Open and return a new RBU handle. +** Open and return a new RBU handle. */ SQLITE_API sqlite3rbu *sqlite3rbu_open( - const char *zTarget, + const char *zTarget, const char *zRbu, const char *zState ){ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } - /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } @@ -171779,10 +207860,16 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open( ** Open a handle to begin or resume an RBU VACUUM operation. */ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( - const char *zTarget, + const char *zTarget, const char *zState ){ if( zTarget==0 ){ return rbuMisuseError(); } + if( zState ){ + int n = strlen(zState); + if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){ + return rbuMisuseError(); + } + } /* TODO: Check that both arguments are non-NULL */ return openRbuHandle(0, zTarget, zState); } @@ -171831,6 +207918,12 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg); } + /* Sync the db file if currently doing an incremental checkpoint */ + if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){ + sqlite3_file *pDb = p->pTargetFd->pReal; + p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL); + } + rbuSaveState(p, p->eStage); if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){ @@ -171841,8 +207934,8 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ rbuObjIterFinalize(&p->objiter); /* If this is an RBU vacuum handle and the vacuum has either finished - ** successfully or encountered an error, delete the contents of the - ** state table. This causes the next call to sqlite3rbu_vacuum() + ** successfully or encountered an error, delete the contents of the + ** state table. This causes the next call to sqlite3rbu_vacuum() ** specifying the current target and state databases to start a new ** vacuum from scratch. */ if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){ @@ -171853,13 +207946,18 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ /* Close the open database handle and VFS object. */ sqlite3_close(p->dbRbu); sqlite3_close(p->dbMain); + assert( p->szTemp==0 ); rbuDeleteVfs(p); sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; - *pzErrmsg = p->zErrmsg; + if( pzErrmsg ){ + *pzErrmsg = p->zErrmsg; + }else{ + sqlite3_free(p->zErrmsg); + } sqlite3_free(p->zState); sqlite3_free(p); }else{ @@ -171870,7 +207968,7 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){ } /* -** Return the total number of key-value operations (inserts, deletes or +** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current RBU update was started. */ @@ -171955,6 +208053,12 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0); } + /* Sync the db file */ + if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){ + sqlite3_file *pDb = p->pTargetFd->pReal; + rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL); + } + p->rc = rc; rbuSaveState(p, p->eStage); rc = p->rc; @@ -171962,7 +208066,10 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); - if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0); + if( rc==SQLITE_OK ){ + const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE"; + rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0); + } if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0); } @@ -171974,7 +208081,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ ** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour ** of a standard VFS in the following ways: ** -** 1. Whenever the first page of a main database file is read or +** 1. Whenever the first page of a main database file is read or ** written, the value of the change-counter cookie is stored in ** rbu_file.iCookie. Similarly, the value of the "write-version" ** database header field is stored in rbu_file.iWriteVer. This ensures @@ -171982,15 +208089,15 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ ** ** 2. Whenever an SQLITE_OPEN_WAL file is opened, the (rbu_file.pWalFd) ** member variable of the associated database file descriptor is set -** to point to the new file. A mutex protected linked list of all main -** db fds opened using a particular RBU VFS is maintained at +** to point to the new file. A mutex protected linked list of all main +** db fds opened using a particular RBU VFS is maintained at ** rbu_vfs.pMain to facilitate this. ** -** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file +** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file ** object can be marked as the target database of an RBU update. This ** turns on the following extra special behaviour: ** -** 3a. If xAccess() is called to check if there exists a *-wal file +** 3a. If xAccess() is called to check if there exists a *-wal file ** associated with an RBU target database currently in RBU_STAGE_OAL ** stage (preparing the *-oal file), the following special handling ** applies: @@ -172003,26 +208110,26 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ ** ** Then, when xOpen() is called to open the *-wal file associated with ** the RBU target in RBU_STAGE_OAL stage, instead of opening the *-wal -** file, the rbu vfs opens the corresponding *-oal file instead. +** file, the rbu vfs opens the corresponding *-oal file instead. ** ** 3b. The *-shm pages returned by xShmMap() for a target db file in ** RBU_STAGE_OAL mode are actually stored in heap memory. This is to ** avoid creating a *-shm file on disk. Additionally, xShmLock() calls ** are no-ops on target database files in RBU_STAGE_OAL mode. This is -** because assert() statements in some VFS implementations fail if +** because assert() statements in some VFS implementations fail if ** xShmLock() is called before xShmMap(). ** ** 3c. If an EXCLUSIVE lock is attempted on a target database file in any -** mode except RBU_STAGE_DONE (all work completed and checkpointed), it +** mode except RBU_STAGE_DONE (all work completed and checkpointed), it ** fails with an SQLITE_BUSY error. This is to stop RBU connections ** from automatically checkpointing a *-wal (or *-oal) file from within ** sqlite3_close(). ** ** 3d. In RBU_STAGE_CAPTURE mode, all xRead() calls on the wal file, and -** all xWrite() calls on the target database file perform no IO. +** all xWrite() calls on the target database file perform no IO. ** Instead the frame and page numbers that would be read and written ** are recorded. Additionally, successful attempts to obtain exclusive -** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target +** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target ** database file are recorded. xShmLock() calls to unlock the same ** locks are no-ops (so that once obtained, these locks are never ** relinquished). Finally, calls to xSync() on the target database @@ -172030,6 +208137,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){ */ static void rbuUnlockShm(rbu_file *p){ + assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); if( p->pRbu ){ int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock; int i; @@ -172042,6 +208150,81 @@ static void rbuUnlockShm(rbu_file *p){ } } +/* +*/ +static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){ + sqlite3rbu *pRbu = pFd->pRbu; + i64 nDiff = nNew - pFd->sz; + pRbu->szTemp += nDiff; + pFd->sz = nNew; + assert( pRbu->szTemp>=0 ); + if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL; + return SQLITE_OK; +} + +/* +** Add an item to the main-db lists, if it is not already present. +** +** There are two main-db lists. One for all file descriptors, and one +** for all file descriptors with rbu_file.pDb!=0. If the argument has +** rbu_file.pDb!=0, then it is assumed to already be present on the +** main list and is only added to the pDb!=0 list. +*/ +static void rbuMainlistAdd(rbu_file *p){ + rbu_vfs *pRbuVfs = p->pRbuVfs; + rbu_file *pIter; + assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) ); + sqlite3_mutex_enter(pRbuVfs->mutex); + if( p->pRbu==0 ){ + for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext); + p->pMainNext = pRbuVfs->pMain; + pRbuVfs->pMain = p; + }else{ + for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){} + if( pIter==0 ){ + p->pMainRbuNext = pRbuVfs->pMainRbu; + pRbuVfs->pMainRbu = p; + } + } + sqlite3_mutex_leave(pRbuVfs->mutex); +} + +/* +** Remove an item from the main-db lists. +*/ +static void rbuMainlistRemove(rbu_file *p){ + rbu_file **pp; + sqlite3_mutex_enter(p->pRbuVfs->mutex); + for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){} + if( *pp ) *pp = p->pMainNext; + p->pMainNext = 0; + for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){} + if( *pp ) *pp = p->pMainRbuNext; + p->pMainRbuNext = 0; + sqlite3_mutex_leave(p->pRbuVfs->mutex); +} + +/* +** Given that zWal points to a buffer containing a wal file name passed to +** either the xOpen() or xAccess() VFS method, search the main-db list for +** a file-handle opened by the same database connection on the corresponding +** database file. +** +** If parameter bRbu is true, only search for file-descriptors with +** rbu_file.pDb!=0. +*/ +static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){ + rbu_file *pDb; + sqlite3_mutex_enter(pRbuVfs->mutex); + if( bRbu ){ + for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){} + }else{ + for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} + } + sqlite3_mutex_leave(pRbuVfs->mutex); + return pDb; +} + /* ** Close an rbu file. */ @@ -172059,14 +208242,14 @@ static int rbuVfsClose(sqlite3_file *pFile){ sqlite3_free(p->zDel); if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ - rbu_file **pp; - sqlite3_mutex_enter(p->pRbuVfs->mutex); - for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext)); - *pp = p->pMainNext; - sqlite3_mutex_leave(p->pRbuVfs->mutex); + rbuMainlistRemove(p); rbuUnlockShm(p); p->pReal->pMethods->xShmUnmap(p->pReal, 0); } + else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ + rbuUpdateTempSize(p, 0); + } + assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p ); /* Close the underlying file handle */ rc = p->pReal->pMethods->xClose(p->pReal); @@ -172075,7 +208258,7 @@ static int rbuVfsClose(sqlite3_file *pFile){ /* -** Read and return an unsigned 32-bit big-endian integer from the buffer +** Read and return an unsigned 32-bit big-endian integer from the buffer ** passed as the only argument. */ static u32 rbuGetU32(u8 *aBuf){ @@ -172105,9 +208288,9 @@ static void rbuPutU16(u8 *aBuf, u16 iVal){ ** Read data from an rbuVfs-file. */ static int rbuVfsRead( - sqlite3_file *pFile, - void *zBuf, - int iAmt, + sqlite3_file *pFile, + void *zBuf, + int iAmt, sqlite_int64 iOfst ){ rbu_file *p = (rbu_file*)pFile; @@ -172118,20 +208301,20 @@ static int rbuVfsRead( assert( p->openFlags & SQLITE_OPEN_WAL ); rc = rbuCaptureWalRead(p->pRbu, iOfst, iAmt); }else{ - if( pRbu && pRbu->eStage==RBU_STAGE_OAL - && (p->openFlags & SQLITE_OPEN_WAL) - && iOfst>=pRbu->iOalSz + if( pRbu && pRbu->eStage==RBU_STAGE_OAL + && (p->openFlags & SQLITE_OPEN_WAL) + && iOfst>=pRbu->iOalSz ){ rc = SQLITE_OK; memset(zBuf, 0, iAmt); }else{ rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); #if 1 - /* If this is being called to read the first page of the target - ** database as part of an rbu vacuum operation, synthesize the + /* If this is being called to read the first page of the target + ** database as part of an rbu vacuum operation, synthesize the ** contents of the first page if it does not yet exist. Otherwise, ** SQLite will not check for a *-wal file. */ - if( pRbu && rbuIsVacuum(pRbu) + if( pRbu && rbuIsVacuum(pRbu) && rc==SQLITE_IOERR_SHORT_READ && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) && pRbu->rc==SQLITE_OK @@ -172171,9 +208354,9 @@ static int rbuVfsRead( ** Write data to an rbuVfs-file. */ static int rbuVfsWrite( - sqlite3_file *pFile, - const void *zBuf, - int iAmt, + sqlite3_file *pFile, + const void *zBuf, + int iAmt, sqlite_int64 iOfst ){ rbu_file *p = (rbu_file*)pFile; @@ -172184,11 +208367,19 @@ static int rbuVfsWrite( assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); rc = rbuCaptureDbWrite(p->pRbu, iOfst); }else{ - if( pRbu && pRbu->eStage==RBU_STAGE_OAL - && (p->openFlags & SQLITE_OPEN_WAL) - && iOfst>=pRbu->iOalSz - ){ - pRbu->iOalSz = iAmt + iOfst; + if( pRbu ){ + if( pRbu->eStage==RBU_STAGE_OAL + && (p->openFlags & SQLITE_OPEN_WAL) + && iOfst>=pRbu->iOalSz + ){ + pRbu->iOalSz = iAmt + iOfst; + }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){ + i64 szNew = iAmt+iOfst; + if( szNew>p->sz ){ + rc = rbuUpdateTempSize(p, szNew); + if( rc!=SQLITE_OK ) return rc; + } + } } rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){ @@ -172207,6 +208398,10 @@ static int rbuVfsWrite( */ static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ rbu_file *p = (rbu_file*)pFile; + if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ + int rc = rbuUpdateTempSize(p, size); + if( rc!=SQLITE_OK ) return rc; + } return p->pReal->pMethods->xTruncate(p->pReal, size); } @@ -172234,10 +208429,10 @@ static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ /* If this is an RBU vacuum operation and this is the target database, ** pretend that it has at least one page. Otherwise, SQLite will not - ** check for the existance of a *-wal file. rbuVfsRead() contains + ** check for the existance of a *-wal file. rbuVfsRead() contains ** similar logic. */ - if( rc==SQLITE_OK && *pSize==0 - && p->pRbu && rbuIsVacuum(p->pRbu) + if( rc==SQLITE_OK && *pSize==0 + && p->pRbu && rbuIsVacuum(p->pRbu) && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){ *pSize = 1024; @@ -172254,10 +208449,10 @@ static int rbuVfsLock(sqlite3_file *pFile, int eLock){ int rc = SQLITE_OK; assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); - if( eLock==SQLITE_LOCK_EXCLUSIVE + if( eLock==SQLITE_LOCK_EXCLUSIVE && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE)) ){ - /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this + /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this ** prevents it from checkpointing the database from sqlite3_close(). */ rc = SQLITE_BUSY; }else{ @@ -172313,6 +208508,7 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){ }else if( rc==SQLITE_NOTFOUND ){ pRbu->pTargetFd = p; p->pRbu = pRbu; + rbuMainlistAdd(p); if( p->pWalFd ) p->pWalFd->pRbu = pRbu; rc = SQLITE_OK; } @@ -172367,25 +208563,24 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ #endif assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); - if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){ - /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from - ** taking this lock also prevents any checkpoints from occurring. - ** todo: really, it's not clear why this might occur, as - ** wal_autocheckpoint ought to be turned off. */ + if( pRbu && ( + pRbu->eStage==RBU_STAGE_OAL + || pRbu->eStage==RBU_STAGE_MOVE + || pRbu->eStage==RBU_STAGE_DONE + )){ + /* Prevent SQLite from taking a shm-lock on the target file when it + ** is supplying heap memory to the upper layer in place of *-shm + ** segments. */ if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY; }else{ int bCapture = 0; - if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE) - && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE - && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0) - ){ + if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){ bCapture = 1; } - if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){ rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); if( bCapture && rc==SQLITE_OK ){ - pRbu->mLock |= (1 << ofst); + pRbu->mLock |= ((1<pRbu ? p->pRbu->eStage : 0); /* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this - ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space + ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space ** instead of a file on disk. */ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); - if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){ - if( iRegion<=p->nShm ){ - int nByte = (iRegion+1) * sizeof(char*); - char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); - if( apNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); - p->apShm = apNew; - p->nShm = iRegion+1; - } + if( eStage==RBU_STAGE_OAL ){ + sqlite3_int64 nByte = (iRegion+1) * sizeof(char*); + char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); + + /* This is an RBU connection that uses its own heap memory for the + ** pages of the *-shm file. Since no other process can have run + ** recovery, the connection must request *-shm pages in order + ** from start to finish. */ + assert( iRegion==p->nShm ); + if( apNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); + p->apShm = apNew; + p->nShm = iRegion+1; } - if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){ + if( rc==SQLITE_OK ){ char *pNew = (char*)sqlite3_malloc64(szRegion); if( pNew==0 ){ rc = SQLITE_NOMEM; @@ -172474,47 +208673,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){ return rc; } -/* -** Given that zWal points to a buffer containing a wal file name passed to -** either the xOpen() or xAccess() VFS method, return a pointer to the -** file-handle opened by the same database connection on the corresponding -** database file. -*/ -static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){ - rbu_file *pDb; - sqlite3_mutex_enter(pRbuVfs->mutex); - for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} - sqlite3_mutex_leave(pRbuVfs->mutex); - return pDb; -} - -/* -** A main database named zName has just been opened. The following -** function returns a pointer to a buffer owned by SQLite that contains -** the name of the *-wal file this db connection will use. SQLite -** happens to pass a pointer to this buffer when using xAccess() -** or xOpen() to operate on the *-wal file. -*/ -static const char *rbuMainToWal(const char *zName, int flags){ - int n = (int)strlen(zName); - const char *z = &zName[n]; - if( flags & SQLITE_OPEN_URI ){ - int odd = 0; - while( 1 ){ - if( z[0]==0 ){ - odd = 1 - odd; - if( odd && z[1]==0 ) break; - } - z++; - } - z += 2; - }else{ - while( *z==0 ) z++; - } - z += (n + 8 + 1); - return z; -} - /* ** Open an rbu file handle. */ @@ -172563,43 +208721,31 @@ static int rbuVfsOpen( ** the name of the *-wal file this db connection will use. SQLite ** happens to pass a pointer to this buffer when using xAccess() ** or xOpen() to operate on the *-wal file. */ - pFd->zWal = rbuMainToWal(zName, flags); + pFd->zWal = sqlite3_filename_wal(zName); } else if( flags & SQLITE_OPEN_WAL ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName); + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0); if( pDb ){ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ - /* This call is to open a *-wal file. Intead, open the *-oal. This - ** code ensures that the string passed to xOpen() is terminated by a - ** pair of '\0' bytes in case the VFS attempts to extract a URI - ** parameter from it. */ - const char *zBase = zName; - size_t nCopy; - char *zCopy; + /* This call is to open a *-wal file. Intead, open the *-oal. */ + size_t nOpen; if( rbuIsVacuum(pDb->pRbu) ){ - zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); - zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI); - } - nCopy = strlen(zBase); - zCopy = sqlite3_malloc64(nCopy+2); - if( zCopy ){ - memcpy(zCopy, zBase, nCopy); - zCopy[nCopy-3] = 'o'; - zCopy[nCopy] = '\0'; - zCopy[nCopy+1] = '\0'; - zOpen = (const char*)(pFd->zDel = zCopy); - }else{ - rc = SQLITE_NOMEM; + zOpen = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); + zOpen = sqlite3_filename_wal(zOpen); } + nOpen = strlen(zOpen); + ((char*)zOpen)[nOpen-3] = 'o'; pFd->pRbu = pDb->pRbu; } pDb->pWalFd = pFd; } } + }else{ + pFd->pRbu = pRbuVfs->pRbu; } - if( oflags & SQLITE_OPEN_MAIN_DB - && sqlite3_uri_boolean(zName, "rbu_memory", 0) + if( oflags & SQLITE_OPEN_MAIN_DB + && sqlite3_uri_boolean(zName, "rbu_memory", 0) ){ assert( oflags & SQLITE_OPEN_MAIN_DB ); oflags = SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | @@ -172616,10 +208762,7 @@ static int rbuVfsOpen( ** mutex protected linked list of all such files. */ pFile->pMethods = &rbuvfs_io_methods; if( flags & SQLITE_OPEN_MAIN_DB ){ - sqlite3_mutex_enter(pRbuVfs->mutex); - pFd->pMainNext = pRbuVfs->pMain; - pRbuVfs->pMain = pFd; - sqlite3_mutex_leave(pRbuVfs->mutex); + rbuMainlistAdd(pFd); } }else{ sqlite3_free(pFd->zDel); @@ -172641,9 +208784,9 @@ static int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ ** is available, or false otherwise. */ static int rbuVfsAccess( - sqlite3_vfs *pVfs, - const char *zPath, - int flags, + sqlite3_vfs *pVfs, + const char *zPath, + int flags, int *pResOut ){ rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs; @@ -172659,7 +208802,7 @@ static int rbuVfsAccess( ** a) if the *-wal file does exist, return SQLITE_CANTOPEN. This ** ensures that the RBU extension never tries to update a database ** in wal mode, even if the first page of the database file has - ** been damaged. + ** been damaged. ** ** b) if the *-wal file does not exist, claim that it does anyway, ** causing SQLite to call xOpen() to open it. This call will also @@ -172667,12 +208810,15 @@ static int rbuVfsAccess( ** file opened instead. */ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath); - if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1); + if( pDb && pDb->pRbu->eStage==RBU_STAGE_OAL ){ + assert( pDb->pRbu ); if( *pResOut ){ rc = SQLITE_CANTOPEN; }else{ - *pResOut = 1; + sqlite3_int64 sz = 0; + rc = rbuVfsFileSize(&pDb->base, &sz); + *pResOut = (sz>0); } } } @@ -172686,9 +208832,9 @@ static int rbuVfsAccess( ** of at least (DEVSYM_MAX_PATHNAME+1) bytes. */ static int rbuVfsFullPathname( - sqlite3_vfs *pVfs, - const char *zPath, - int nOut, + sqlite3_vfs *pVfs, + const char *zPath, + int nOut, char *zOut ){ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs; @@ -172706,7 +208852,7 @@ static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ /* ** Populate the buffer zErrMsg (size nByte bytes) with a human readable -** utf-8 string describing the most recent error encountered associated +** utf-8 string describing the most recent error encountered associated ** with dynamic libraries. */ static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ @@ -172718,8 +208864,8 @@ static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. */ static void (*rbuVfsDlSym( - sqlite3_vfs *pVfs, - void *pArg, + sqlite3_vfs *pVfs, + void *pArg, const char *zSym ))(void){ sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs; @@ -172736,7 +208882,7 @@ static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){ #endif /* SQLITE_OMIT_LOAD_EXTENSION */ /* -** Populate the buffer pointed to by zBufOut with nByte bytes of +** Populate the buffer pointed to by zBufOut with nByte bytes of ** random data. */ static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ @@ -172745,7 +208891,7 @@ static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ } /* -** Sleep for nMicro microseconds. Return the number of microseconds +** Sleep for nMicro microseconds. Return the number of microseconds ** actually slept. */ static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){ @@ -172861,6 +209007,20 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){ return rc; } +/* +** Configure the aggregate temp file size limit for this RBU handle. +*/ +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){ + if( n>=0 ){ + pRbu->szTempLimit = n; + } + return pRbu->szTempLimit; +} + +SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){ + return pRbu->szTemp; +} + /**************************************************************************/ @@ -172882,7 +209042,7 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){ ** ** This file contains an implementation of the "dbstat" virtual table. ** -** The dbstat virtual table is used to extract low-level formatting +** The dbstat virtual table is used to extract low-level storage ** information from an SQLite database in order to implement the ** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script ** for an example implementation. @@ -172895,24 +209055,33 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){ #if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \ && !defined(SQLITE_OMIT_VIRTUALTABLE) +/* +** The pager and btree modules arrange objects in memory so that there are +** always approximately 200 bytes of addressable memory following each page +** buffer. This way small buffer overreads caused by corrupt database pages +** do not cause undefined behaviour. This module pads each page buffer +** by the following number of bytes for the same purpose. +*/ +#define DBSTAT_PAGE_PADDING_BYTES 256 + /* ** Page paths: -** -** The value of the 'path' column describes the path taken from the -** root-node of the b-tree structure to each page. The value of the +** +** The value of the 'path' column describes the path taken from the +** root-node of the b-tree structure to each page. The value of the ** root-node path is '/'. ** ** The value of the path for the left-most child page of the root of ** a b-tree is '/000/'. (Btrees store content ordered from left to right ** so the pages to the left have smaller keys than the pages to the right.) ** The next to left-most child of the root page is -** '/001', and so on, each sibling page identified by a 3-digit hex +** '/001', and so on, each sibling page identified by a 3-digit hex ** value. The children of the 451st left-most sibling have paths such ** as '/1c2/000/, '/1c2/001/' etc. ** -** Overflow pages are specified by appending a '+' character and a +** Overflow pages are specified by appending a '+' character and a ** six-digit hexadecimal value to the path to the cell they are linked -** from. For example, the three overflow pages in a chain linked from +** from. For example, the three overflow pages in a chain linked from ** the left-most cell of the 450th child of the root page are identified ** by the paths: ** @@ -172926,27 +209095,30 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){ ** ** '/1c2/000/' // Left-most child of 451st child of root */ -#define VTAB_SCHEMA \ - "CREATE TABLE xx( " \ - " name TEXT, /* Name of table or index */" \ - " path TEXT, /* Path to page from root */" \ - " pageno INTEGER, /* Page number */" \ - " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \ - " ncell INTEGER, /* Cells on page (0 for overflow) */" \ - " payload INTEGER, /* Bytes of payload on this page */" \ - " unused INTEGER, /* Bytes of unused space on this page */" \ - " mx_payload INTEGER, /* Largest payload size of all cells */" \ - " pgoffset INTEGER, /* Offset of page in file */" \ - " pgsize INTEGER, /* Size of the page */" \ - " schema TEXT HIDDEN /* Database schema being analyzed */" \ - ");" - - +static const char zDbstatSchema[] = + "CREATE TABLE x(" + " name TEXT," /* 0 Name of table or index */ + " path TEXT," /* 1 Path to page from root (NULL for agg) */ + " pageno INTEGER," /* 2 Page number (page count for aggregates) */ + " pagetype TEXT," /* 3 'internal', 'leaf', 'overflow', or NULL */ + " ncell INTEGER," /* 4 Cells on page (0 for overflow) */ + " payload INTEGER," /* 5 Bytes of payload on this page */ + " unused INTEGER," /* 6 Bytes of unused space on this page */ + " mx_payload INTEGER," /* 7 Largest payload size of all cells */ + " pgoffset INTEGER," /* 8 Offset of page in file (NULL for agg) */ + " pgsize INTEGER," /* 9 Size of the page (sum for aggregate) */ + " schema TEXT HIDDEN," /* 10 Database schema being analyzed */ + " aggregate BOOLEAN HIDDEN" /* 11 aggregate info for each table */ + ")" +; + +/* Forward reference to data structured used in this module */ typedef struct StatTable StatTable; typedef struct StatCursor StatCursor; typedef struct StatPage StatPage; typedef struct StatCell StatCell; +/* Size information for a single cell within a btree page */ struct StatCell { int nLocal; /* Bytes of local payload */ u32 iChildPg; /* Child node (or 0 if this is a leaf) */ @@ -172956,11 +209128,11 @@ struct StatCell { int iOvfl; /* Iterates through aOvfl[] */ }; +/* Size information for a single btree page */ struct StatPage { - u32 iPgno; - DbPage *pPg; - int iCell; - + u32 iPgno; /* Page number */ + u8 *aPg; /* Page buffer from sqlite3_malloc() */ + int iCell; /* Current cell */ char *zPath; /* Path to this page */ /* Variables populated by statDecodePage(): */ @@ -172969,34 +209141,38 @@ struct StatPage { int nUnused; /* Number of unused bytes on page */ StatCell *aCell; /* Array of parsed cells */ u32 iRightChildPg; /* Right-child page number (or 0) */ - int nMxPayload; /* Largest payload of any cell on this page */ + int nMxPayload; /* Largest payload of any cell on the page */ }; +/* The cursor for scanning the dbstat virtual table */ struct StatCursor { - sqlite3_vtab_cursor base; + sqlite3_vtab_cursor base; /* base class. MUST BE FIRST! */ sqlite3_stmt *pStmt; /* Iterates through set of root pages */ - int isEof; /* After pStmt has returned SQLITE_DONE */ + u8 isEof; /* After pStmt has returned SQLITE_DONE */ + u8 isAgg; /* Aggregate results for each table */ int iDb; /* Schema used for this query */ - StatPage aPage[32]; + StatPage aPage[32]; /* Pages in path to current page */ int iPage; /* Current entry in aPage[] */ /* Values to return. */ + u32 iPageno; /* Value of 'pageno' column */ char *zName; /* Value of 'name' column */ char *zPath; /* Value of 'path' column */ - u32 iPageno; /* Value of 'pageno' column */ char *zPagetype; /* Value of 'pagetype' column */ + int nPage; /* Number of pages in current btree */ int nCell; /* Value of 'ncell' column */ - int nPayload; /* Value of 'payload' column */ - int nUnused; /* Value of 'unused' column */ int nMxPayload; /* Value of 'mx_payload' column */ + i64 nUnused; /* Value of 'unused' column */ + i64 nPayload; /* Value of 'payload' column */ i64 iOffset; /* Value of 'pgOffset' column */ - int szPage; /* Value of 'pgSize' column */ + i64 szPage; /* Value of 'pgSize' column */ }; +/* An instance of the DBSTAT virtual table */ struct StatTable { - sqlite3_vtab base; - sqlite3 *db; + sqlite3_vtab base; /* base class. MUST BE FIRST! */ + sqlite3 *db; /* Database connection that owns this vtab */ int iDb; /* Index of database to analyze */ }; @@ -173005,7 +209181,7 @@ struct StatTable { #endif /* -** Connect to or create a statvfs virtual table. +** Connect to or create a new DBSTAT virtual table. */ static int statConnect( sqlite3 *db, @@ -173029,7 +209205,8 @@ static int statConnect( }else{ iDb = 0; } - rc = sqlite3_declare_vtab(db, VTAB_SCHEMA); + sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); + rc = sqlite3_declare_vtab(db, zDbstatSchema); if( rc==SQLITE_OK ){ pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable)); if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; @@ -173047,7 +209224,7 @@ static int statConnect( } /* -** Disconnect from or destroy a statvfs virtual table. +** Disconnect from or destroy the DBSTAT virtual table. */ static int statDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); @@ -173055,16 +209232,20 @@ static int statDisconnect(sqlite3_vtab *pVtab){ } /* -** There is no "best-index". This virtual table always does a linear -** scan. However, a schema=? constraint should cause this table to -** operate on a different database schema, so check for it. +** Compute the best query strategy and return the result in idxNum. ** -** idxNum is normally 0, but will be 1 if a schema=? constraint exists. +** idxNum-Bit Meaning +** ---------- ---------------------------------------------- +** 0x01 There is a schema=? term in the WHERE clause +** 0x02 There is a name=? term in the WHERE clause +** 0x04 There is an aggregate=? term in the WHERE clause +** 0x08 Output should be ordered by name and path */ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; - - pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */ + int iSchema = -1; + int iName = -1; + int iAgg = -1; /* Look for a valid schema=? constraint. If found, change the idxNum to ** 1 and request the value of that constraint be sent to xFilter. And @@ -173072,19 +209253,44 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ** used. */ for(i=0; inConstraint; i++){ - if( pIdxInfo->aConstraint[i].usable==0 ) continue; if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue; - pIdxInfo->idxNum = 1; - pIdxInfo->estimatedCost = 1.0; - pIdxInfo->aConstraintUsage[i].argvIndex = 1; - pIdxInfo->aConstraintUsage[i].omit = 1; - break; + if( pIdxInfo->aConstraint[i].usable==0 ){ + /* Force DBSTAT table should always be the right-most table in a join */ + return SQLITE_CONSTRAINT; + } + switch( pIdxInfo->aConstraint[i].iColumn ){ + case 0: { /* name */ + iName = i; + break; + } + case 10: { /* schema */ + iSchema = i; + break; + } + case 11: { /* aggregate */ + iAgg = i; + break; + } + } } + i = 0; + if( iSchema>=0 ){ + pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i; + pIdxInfo->aConstraintUsage[iSchema].omit = 1; + pIdxInfo->idxNum |= 0x01; + } + if( iName>=0 ){ + pIdxInfo->aConstraintUsage[iName].argvIndex = ++i; + pIdxInfo->idxNum |= 0x02; + } + if( iAgg>=0 ){ + pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i; + pIdxInfo->idxNum |= 0x04; + } + pIdxInfo->estimatedCost = 1.0; - - /* Records are always returned in ascending order of (name, path). - ** If this will satisfy the client, set the orderByConsumed flag so that + /* Records are always returned in ascending order of (name, path). + ** If this will satisfy the client, set the orderByConsumed flag so that ** SQLite does not do an external sort. */ if( ( pIdxInfo->nOrderBy==1 @@ -173099,13 +209305,14 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ ) ){ pIdxInfo->orderByConsumed = 1; + pIdxInfo->idxNum |= 0x08; } return SQLITE_OK; } /* -** Open a new statvfs cursor. +** Open a new DBSTAT cursor. */ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ StatTable *pTab = (StatTable *)pVTab; @@ -173124,7 +209331,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ return SQLITE_OK; } -static void statClearPage(StatPage *p){ +static void statClearCells(StatPage *p){ int i; if( p->aCell ){ for(i=0; inCell; i++){ @@ -173132,25 +209339,48 @@ static void statClearPage(StatPage *p){ } sqlite3_free(p->aCell); } - sqlite3PagerUnref(p->pPg); + p->nCell = 0; + p->aCell = 0; +} + +static void statClearPage(StatPage *p){ + u8 *aPg = p->aPg; + statClearCells(p); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); + p->aPg = aPg; } static void statResetCsr(StatCursor *pCsr){ int i; - sqlite3_reset(pCsr->pStmt); + /* In some circumstances, specifically if an OOM has occurred, the call + ** to sqlite3_reset() may cause the pager to be reset (emptied). It is + ** important that statClearPage() is called to free any page refs before + ** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */ for(i=0; iaPage); i++){ statClearPage(&pCsr->aPage[i]); + sqlite3_free(pCsr->aPage[i].aPg); + pCsr->aPage[i].aPg = 0; } + sqlite3_reset(pCsr->pStmt); pCsr->iPage = 0; sqlite3_free(pCsr->zPath); pCsr->zPath = 0; pCsr->isEof = 0; } +/* Resize the space-used counters inside of the cursor */ +static void statResetCounts(StatCursor *pCsr){ + pCsr->nCell = 0; + pCsr->nMxPayload = 0; + pCsr->nUnused = 0; + pCsr->nPayload = 0; + pCsr->szPage = 0; + pCsr->nPage = 0; +} + /* -** Close a statvfs cursor. +** Close a DBSTAT cursor. */ static int statClose(sqlite3_vtab_cursor *pCursor){ StatCursor *pCsr = (StatCursor *)pCursor; @@ -173160,16 +209390,20 @@ static int statClose(sqlite3_vtab_cursor *pCursor){ return SQLITE_OK; } -static void getLocalPayload( +/* +** For a single cell on a btree page, compute the number of bytes of +** content (payload) stored on that page. That is to say, compute the +** number of bytes of content not found on overflow pages. +*/ +static int getLocalPayload( int nUsable, /* Usable bytes per page */ u8 flags, /* Page flags */ - int nTotal, /* Total record (payload) size */ - int *pnLocal /* OUT: Bytes stored locally */ + int nTotal /* Total record (payload) size */ ){ int nLocal; int nMinLocal; int nMaxLocal; - + if( flags==0x0D ){ /* Table leaf node */ nMinLocal = (nUsable - 12) * 32 / 255 - 23; nMaxLocal = nUsable - 35; @@ -173180,9 +209414,12 @@ static void getLocalPayload( nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4); if( nLocal>nMaxLocal ) nLocal = nMinLocal; - *pnLocal = nLocal; + return nLocal; } +/* Populate the StatPage object with information about the all +** cells found on the page currently under analysis. +*/ static int statDecodePage(Btree *pBt, StatPage *p){ int nUnused; int iOff; @@ -173190,26 +209427,37 @@ static int statDecodePage(Btree *pBt, StatPage *p){ int isLeaf; int szPage; - u8 *aData = sqlite3PagerGetData(p->pPg); + u8 *aData = p->aPg; u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; + if( p->flags==0x0A || p->flags==0x0D ){ + isLeaf = 1; + nHdr = 8; + }else if( p->flags==0x05 || p->flags==0x02 ){ + isLeaf = 0; + nHdr = 12; + }else{ + goto statPageIsCorrupt; + } + if( p->iPgno==1 ) nHdr += 100; p->nCell = get2byte(&aHdr[3]); p->nMxPayload = 0; - - isLeaf = (p->flags==0x0A || p->flags==0x0D); - nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; + szPage = sqlite3BtreeGetPageSize(pBt); nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; nUnused += (int)aHdr[7]; iOff = get2byte(&aHdr[1]); while( iOff ){ + int iNext; + if( iOff>=szPage ) goto statPageIsCorrupt; nUnused += get2byte(&aData[iOff+2]); - iOff = get2byte(&aData[iOff]); + iNext = get2byte(&aData[iOff]); + if( iNext0 ) goto statPageIsCorrupt; + iOff = iNext; } p->nUnused = nUnused; p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); - szPage = sqlite3BtreeGetPageSize(pBt); if( p->nCell ){ int i; /* Used to iterate through cells */ @@ -173226,6 +209474,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ StatCell *pCell = &p->aCell[i]; iOff = get2byte(&aData[nHdr+i*2]); + if( iOff=szPage ) goto statPageIsCorrupt; if( !isLeaf ){ pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); iOff += 4; @@ -173241,14 +209490,17 @@ static int statDecodePage(Btree *pBt, StatPage *p){ iOff += sqlite3GetVarint(&aData[iOff], &dummy); } if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; - getLocalPayload(nUsable, p->flags, nPayload, &nLocal); + nLocal = getLocalPayload(nUsable, p->flags, nPayload); + if( nLocal<0 ) goto statPageIsCorrupt; pCell->nLocal = nLocal; - assert( nLocal>=0 ); assert( nPayload>=(u32)nLocal ); assert( nLocal<=(nUsable-35) ); if( nPayload>(u32)nLocal ){ int j; int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); + if( iOff+nLocal+4>nUsable || nPayload>0x7fffffff ){ + goto statPageIsCorrupt; + } pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl); @@ -173262,7 +209514,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ if( rc!=SQLITE_OK ){ assert( pPg==0 ); return rc; - } + } pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg)); sqlite3PagerUnref(pPg); } @@ -173272,6 +209524,11 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } return SQLITE_OK; + +statPageIsCorrupt: + p->flags = 0; + statClearCells(p); + return SQLITE_OK; } /* @@ -173285,23 +209542,57 @@ static void statSizeAndOffset(StatCursor *pCsr){ sqlite3_file *fd; sqlite3_int64 x[2]; - /* The default page size and offset */ - pCsr->szPage = sqlite3BtreeGetPageSize(pBt); - pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1); - - /* If connected to a ZIPVFS backend, override the page size and - ** offset with actual values obtained from ZIPVFS. + /* If connected to a ZIPVFS backend, find the page size and + ** offset from ZIPVFS. */ fd = sqlite3PagerFile(pPager); x[0] = pCsr->iPageno; - if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ + if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ pCsr->iOffset = x[0]; - pCsr->szPage = (int)x[1]; + pCsr->szPage += x[1]; + }else{ + /* Not ZIPVFS: The default page size and offset */ + pCsr->szPage += sqlite3BtreeGetPageSize(pBt); + pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1); } } /* -** Move a statvfs cursor to the next entry in the file. +** Load a copy of the page data for page iPg into the buffer belonging +** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK +** if successful, or an SQLite error code otherwise. +*/ +static int statGetPage( + Btree *pBt, /* Load page from this b-tree */ + u32 iPg, /* Page number to load */ + StatPage *pPg /* Load page into this object */ +){ + int pgsz = sqlite3BtreeGetPageSize(pBt); + DbPage *pDbPage = 0; + int rc; + + if( pPg->aPg==0 ){ + pPg->aPg = (u8*)sqlite3_malloc(pgsz + DBSTAT_PAGE_PADDING_BYTES); + if( pPg->aPg==0 ){ + return SQLITE_NOMEM_BKPT; + } + memset(&pPg->aPg[pgsz], 0, DBSTAT_PAGE_PADDING_BYTES); + } + + rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPg, &pDbPage, 0); + if( rc==SQLITE_OK ){ + const u8 *a = sqlite3PagerGetData(pDbPage); + memcpy(pPg->aPg, a, pgsz); + sqlite3PagerUnref(pDbPage); + } + + return rc; +} + +/* +** Move a DBSTAT cursor to the next entry. Normally, the next +** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0), +** the next entry is the next btree. */ static int statNext(sqlite3_vtab_cursor *pCursor){ int rc; @@ -173316,7 +209607,9 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->zPath = 0; statNextRestart: - if( pCsr->aPage[0].pPg==0 ){ + if( pCsr->iPage<0 ){ + /* Start measuring space on the next btree */ + statResetCounts(pCsr); rc = sqlite3_step(pCsr->pStmt); if( rc==SQLITE_ROW ){ int nPage; @@ -173326,47 +209619,50 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } - rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0); + rc = statGetPage(pBt, iRoot, &pCsr->aPage[0]); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; - pCsr->aPage[0].zPath = z = sqlite3_mprintf("/"); + if( !pCsr->isAgg ){ + pCsr->aPage[0].zPath = z = sqlite3_mprintf("/"); + if( z==0 ) rc = SQLITE_NOMEM_BKPT; + } pCsr->iPage = 0; - if( z==0 ) rc = SQLITE_NOMEM_BKPT; + pCsr->nPage = 1; }else{ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } }else{ - - /* Page p itself has already been visited. */ + /* Continue analyzing the btree previously started */ StatPage *p = &pCsr->aPage[pCsr->iPage]; - + if( !pCsr->isAgg ) statResetCounts(pCsr); while( p->iCellnCell ){ StatCell *pCell = &p->aCell[p->iCell]; - if( pCell->iOvflnOvfl ){ - int nUsable; + while( pCell->iOvflnOvfl ){ + int nUsable, iOvfl; sqlite3BtreeEnter(pBt); - nUsable = sqlite3BtreeGetPageSize(pBt) - + nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserveNoMutex(pBt); sqlite3BtreeLeave(pBt); - pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); - pCsr->iPageno = pCell->aOvfl[pCell->iOvfl]; - pCsr->zPagetype = "overflow"; - pCsr->nCell = 0; - pCsr->nMxPayload = 0; - pCsr->zPath = z = sqlite3_mprintf( - "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl - ); + pCsr->nPage++; + statSizeAndOffset(pCsr); if( pCell->iOvflnOvfl-1 ){ - pCsr->nUnused = 0; - pCsr->nPayload = nUsable - 4; + pCsr->nPayload += nUsable - 4; }else{ - pCsr->nPayload = pCell->nLastOvfl; - pCsr->nUnused = nUsable - 4 - pCsr->nPayload; + pCsr->nPayload += pCell->nLastOvfl; + pCsr->nUnused += nUsable - 4 - pCell->nLastOvfl; } + iOvfl = pCell->iOvfl; pCell->iOvfl++; - statSizeAndOffset(pCsr); - return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; + if( !pCsr->isAgg ){ + pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); + pCsr->iPageno = pCell->aOvfl[iOvfl]; + pCsr->zPagetype = "overflow"; + pCsr->zPath = z = sqlite3_mprintf( + "%s%.3x+%.6x", p->zPath, p->iCell, iOvfl + ); + return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; + } } if( p->iRightChildPg ) break; p->iCell++; @@ -173374,11 +209670,19 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ if( !p->iRightChildPg || p->iCell>p->nCell ){ statClearPage(p); - if( pCsr->iPage==0 ) return statNext(pCursor); pCsr->iPage--; + if( pCsr->isAgg && pCsr->iPage<0 ){ + /* label-statNext-done: When computing aggregate space usage over + ** an entire btree, this is the exit point from this function */ + return SQLITE_OK; + } goto statNextRestart; /* Tail recursion */ } pCsr->iPage++; + if( pCsr->iPage>=ArraySize(pCsr->aPage) ){ + statResetCsr(pCsr); + return SQLITE_CORRUPT_BKPT; + } assert( p==&pCsr->aPage[pCsr->iPage-1] ); if( p->iCell==p->nCell ){ @@ -173386,11 +209690,14 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ }else{ p[1].iPgno = p->aCell[p->iCell].iChildPg; } - rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0); + rc = statGetPage(pBt, p[1].iPgno, &p[1]); + pCsr->nPage++; p[1].iCell = 0; - p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); + if( !pCsr->isAgg ){ + p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); + if( z==0 ) rc = SQLITE_NOMEM_BKPT; + } p->iCell++; - if( z==0 ) rc = SQLITE_NOMEM_BKPT; } @@ -173420,16 +209727,23 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->zPagetype = "corrupted"; break; } - pCsr->nCell = p->nCell; - pCsr->nUnused = p->nUnused; - pCsr->nMxPayload = p->nMxPayload; - pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath); - if( z==0 ) rc = SQLITE_NOMEM_BKPT; + pCsr->nCell += p->nCell; + pCsr->nUnused += p->nUnused; + if( p->nMxPayload>pCsr->nMxPayload ) pCsr->nMxPayload = p->nMxPayload; + if( !pCsr->isAgg ){ + pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath); + if( z==0 ) rc = SQLITE_NOMEM_BKPT; + } nPayload = 0; for(i=0; inCell; i++){ nPayload += p->aCell[i].nLocal; } - pCsr->nPayload = nPayload; + pCsr->nPayload += nPayload; + + /* If computing aggregate space usage by btree, continue with the + ** next page. The loop will exit via the return at label-statNext-done + */ + if( pCsr->isAgg ) goto statNextRestart; } } @@ -173441,38 +209755,63 @@ static int statEof(sqlite3_vtab_cursor *pCursor){ return pCsr->isEof; } +/* Initialize a cursor according to the query plan idxNum using the +** arguments in argv[0]. See statBestIndex() for a description of the +** meaning of the bits in idxNum. +*/ static int statFilter( - sqlite3_vtab_cursor *pCursor, + sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ StatCursor *pCsr = (StatCursor *)pCursor; StatTable *pTab = (StatTable*)(pCursor->pVtab); - char *zSql; - int rc = SQLITE_OK; - char *zMaster; + sqlite3_str *pSql; /* Query of btrees to analyze */ + char *zSql; /* String value of pSql */ + int iArg = 0; /* Count of argv[] parameters used so far */ + int rc = SQLITE_OK; /* Result of this operation */ + const char *zName = 0; /* Only provide analysis of this table */ - if( idxNum==1 ){ - const char *zDbase = (const char*)sqlite3_value_text(argv[0]); + statResetCsr(pCsr); + sqlite3_finalize(pCsr->pStmt); + pCsr->pStmt = 0; + if( idxNum & 0x01 ){ + /* schema=? constraint is present. Get its value */ + const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]); pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase); if( pCsr->iDb<0 ){ - sqlite3_free(pCursor->pVtab->zErrMsg); - pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase); - return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT; + pCsr->iDb = 0; + pCsr->isEof = 1; + return SQLITE_OK; } }else{ pCsr->iDb = pTab->iDb; } - statResetCsr(pCsr); - sqlite3_finalize(pCsr->pStmt); - pCsr->pStmt = 0; - zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master"; - zSql = sqlite3_mprintf( - "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" - " UNION ALL " - "SELECT name, rootpage, type" - " FROM \"%w\".%s WHERE rootpage!=0" - " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster); + if( idxNum & 0x02 ){ + /* name=? constraint is present */ + zName = (const char*)sqlite3_value_text(argv[iArg++]); + } + if( idxNum & 0x04 ){ + /* aggregate=? constraint is present */ + pCsr->isAgg = sqlite3_value_double(argv[iArg++])!=0.0; + }else{ + pCsr->isAgg = 0; + } + pSql = sqlite3_str_new(pTab->db); + sqlite3_str_appendf(pSql, + "SELECT * FROM (" + "SELECT 'sqlite_schema' AS name,1 AS rootpage,'table' AS type" + " UNION ALL " + "SELECT name,rootpage,type" + " FROM \"%w\".sqlite_schema WHERE rootpage!=0)", + pTab->db->aDb[pCsr->iDb].zDbSName); + if( zName ){ + sqlite3_str_appendf(pSql, "WHERE name=%Q", zName); + } + if( idxNum & 0x08 ){ + sqlite3_str_appendf(pSql, " ORDER BY name"); + } + zSql = sqlite3_str_finish(pSql); if( zSql==0 ){ return SQLITE_NOMEM_BKPT; }else{ @@ -173481,14 +209820,15 @@ static int statFilter( } if( rc==SQLITE_OK ){ + pCsr->iPage = -1; rc = statNext(pCursor); } return rc; } static int statColumn( - sqlite3_vtab_cursor *pCursor, - sqlite3_context *ctx, + sqlite3_vtab_cursor *pCursor, + sqlite3_context *ctx, int i ){ StatCursor *pCsr = (StatCursor *)pCursor; @@ -173497,13 +209837,21 @@ static int statColumn( sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT); break; case 1: /* path */ - sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT); + if( !pCsr->isAgg ){ + sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT); + } break; case 2: /* pageno */ - sqlite3_result_int64(ctx, pCsr->iPageno); + if( pCsr->isAgg ){ + sqlite3_result_int64(ctx, pCsr->nPage); + }else{ + sqlite3_result_int64(ctx, pCsr->iPageno); + } break; case 3: /* pagetype */ - sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC); + if( !pCsr->isAgg ){ + sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC); + } break; case 4: /* ncell */ sqlite3_result_int(ctx, pCsr->nCell); @@ -173518,17 +209866,23 @@ static int statColumn( sqlite3_result_int(ctx, pCsr->nMxPayload); break; case 8: /* pgoffset */ - sqlite3_result_int64(ctx, pCsr->iOffset); + if( !pCsr->isAgg ){ + sqlite3_result_int64(ctx, pCsr->iOffset); + } break; case 9: /* pgsize */ sqlite3_result_int(ctx, pCsr->szPage); break; - default: { /* schema */ + case 10: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); int iDb = pCsr->iDb; sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC); break; } + default: { /* aggregate */ + sqlite3_result_int(ctx, pCsr->isAgg); + break; + } } return SQLITE_OK; } @@ -173564,6 +209918,10 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; return sqlite3_create_module(db, "dbstat", &dbstat_module, 0); } @@ -173572,6 +209930,426 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; } #endif /* SQLITE_ENABLE_DBSTAT_VTAB */ /************** End of dbstat.c **********************************************/ +/************** Begin file dbpage.c ******************************************/ +/* +** 2017-10-11 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains an implementation of the "sqlite_dbpage" virtual table. +** +** The sqlite_dbpage virtual table is used to read or write whole raw +** pages of the database file. The pager interface is used so that +** uncommitted changes and changes recorded in the WAL file are correctly +** retrieved. +** +** Usage example: +** +** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123; +** +** This is an eponymous virtual table so it does not need to be created before +** use. The optional argument to the sqlite_dbpage() table name is the +** schema for the database file that is to be read. The default schema is +** "main". +** +** The data field of sqlite_dbpage table can be updated. The new +** value must be a BLOB which is the correct page size, otherwise the +** update fails. Rows may not be deleted or inserted. +*/ + +/* #include "sqliteInt.h" ** Requires access to internal data structures ** */ +#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \ + && !defined(SQLITE_OMIT_VIRTUALTABLE) + +typedef struct DbpageTable DbpageTable; +typedef struct DbpageCursor DbpageCursor; + +struct DbpageCursor { + sqlite3_vtab_cursor base; /* Base class. Must be first */ + int pgno; /* Current page number */ + int mxPgno; /* Last page to visit on this scan */ + Pager *pPager; /* Pager being read/written */ + DbPage *pPage1; /* Page 1 of the database */ + int iDb; /* Index of database to analyze */ + int szPage; /* Size of each page in bytes */ +}; + +struct DbpageTable { + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* The database */ +}; + +/* Columns */ +#define DBPAGE_COLUMN_PGNO 0 +#define DBPAGE_COLUMN_DATA 1 +#define DBPAGE_COLUMN_SCHEMA 2 + + + +/* +** Connect to or create a dbpagevfs virtual table. +*/ +static int dbpageConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + DbpageTable *pTab = 0; + int rc = SQLITE_OK; + + sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)"); + if( rc==SQLITE_OK ){ + pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable)); + if( pTab==0 ) rc = SQLITE_NOMEM_BKPT; + } + + assert( rc==SQLITE_OK || pTab==0 ); + if( rc==SQLITE_OK ){ + memset(pTab, 0, sizeof(DbpageTable)); + pTab->db = db; + } + + *ppVtab = (sqlite3_vtab*)pTab; + return rc; +} + +/* +** Disconnect from or destroy a dbpagevfs virtual table. +*/ +static int dbpageDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** idxNum: +** +** 0 schema=main, full table scan +** 1 schema=main, pgno=?1 +** 2 schema=?1, full table scan +** 3 schema=?1, pgno=?2 +*/ +static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + int i; + int iPlan = 0; + + /* If there is a schema= constraint, it must be honored. Report a + ** ridiculously large estimated cost if the schema= constraint is + ** unavailable + */ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; + if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue; + if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + if( !p->usable ){ + /* No solution. */ + return SQLITE_CONSTRAINT; + } + iPlan = 2; + pIdxInfo->aConstraintUsage[i].argvIndex = 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + break; + } + + /* If we reach this point, it means that either there is no schema= + ** constraint (in which case we use the "main" schema) or else the + ** schema constraint was accepted. Lower the estimated cost accordingly + */ + pIdxInfo->estimatedCost = 1.0e6; + + /* Check for constraints against pgno */ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; + if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + pIdxInfo->estimatedCost = 1.0; + pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1; + pIdxInfo->aConstraintUsage[i].omit = 1; + iPlan |= 1; + break; + } + } + pIdxInfo->idxNum = iPlan; + + if( pIdxInfo->nOrderBy>=1 + && pIdxInfo->aOrderBy[0].iColumn<=0 + && pIdxInfo->aOrderBy[0].desc==0 + ){ + pIdxInfo->orderByConsumed = 1; + } + sqlite3VtabWriteAll(pIdxInfo); + return SQLITE_OK; +} + +/* +** Open a new dbpagevfs cursor. +*/ +static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + DbpageCursor *pCsr; + + pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM_BKPT; + }else{ + memset(pCsr, 0, sizeof(DbpageCursor)); + pCsr->base.pVtab = pVTab; + pCsr->pgno = -1; + } + + *ppCursor = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; +} + +/* +** Close a dbpagevfs cursor. +*/ +static int dbpageClose(sqlite3_vtab_cursor *pCursor){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); + sqlite3_free(pCsr); + return SQLITE_OK; +} + +/* +** Move a dbpagevfs cursor to the next entry in the file. +*/ +static int dbpageNext(sqlite3_vtab_cursor *pCursor){ + int rc = SQLITE_OK; + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + pCsr->pgno++; + return rc; +} + +static int dbpageEof(sqlite3_vtab_cursor *pCursor){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + return pCsr->pgno > pCsr->mxPgno; +} + +/* +** idxNum: +** +** 0 schema=main, full table scan +** 1 schema=main, pgno=?1 +** 2 schema=?1, full table scan +** 3 schema=?1, pgno=?2 +** +** idxStr is not used +*/ +static int dbpageFilter( + sqlite3_vtab_cursor *pCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; + int rc; + sqlite3 *db = pTab->db; + Btree *pBt; + + /* Default setting is no rows of result */ + pCsr->pgno = 1; + pCsr->mxPgno = 0; + + if( idxNum & 2 ){ + const char *zSchema; + assert( argc>=1 ); + zSchema = (const char*)sqlite3_value_text(argv[0]); + pCsr->iDb = sqlite3FindDbName(db, zSchema); + if( pCsr->iDb<0 ) return SQLITE_OK; + }else{ + pCsr->iDb = 0; + } + pBt = db->aDb[pCsr->iDb].pBt; + if( pBt==0 ) return SQLITE_OK; + pCsr->pPager = sqlite3BtreePager(pBt); + pCsr->szPage = sqlite3BtreeGetPageSize(pBt); + pCsr->mxPgno = sqlite3BtreeLastPage(pBt); + if( idxNum & 1 ){ + assert( argc>(idxNum>>1) ); + pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]); + if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){ + pCsr->pgno = 1; + pCsr->mxPgno = 0; + }else{ + pCsr->mxPgno = pCsr->pgno; + } + }else{ + assert( pCsr->pgno==1 ); + } + if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1); + rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0); + return rc; +} + +static int dbpageColumn( + sqlite3_vtab_cursor *pCursor, + sqlite3_context *ctx, + int i +){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + int rc = SQLITE_OK; + switch( i ){ + case 0: { /* pgno */ + sqlite3_result_int(ctx, pCsr->pgno); + break; + } + case 1: { /* data */ + DbPage *pDbPage = 0; + rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); + if( rc==SQLITE_OK ){ + sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage, + SQLITE_TRANSIENT); + } + sqlite3PagerUnref(pDbPage); + break; + } + default: { /* schema */ + sqlite3 *db = sqlite3_context_db_handle(ctx); + sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC); + break; + } + } + return SQLITE_OK; +} + +static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ + DbpageCursor *pCsr = (DbpageCursor *)pCursor; + *pRowid = pCsr->pgno; + return SQLITE_OK; +} + +static int dbpageUpdate( + sqlite3_vtab *pVtab, + int argc, + sqlite3_value **argv, + sqlite_int64 *pRowid +){ + DbpageTable *pTab = (DbpageTable *)pVtab; + Pgno pgno; + DbPage *pDbPage = 0; + int rc = SQLITE_OK; + char *zErr = 0; + const char *zSchema; + int iDb; + Btree *pBt; + Pager *pPager; + int szPage; + + if( pTab->db->flags & SQLITE_Defensive ){ + zErr = "read-only"; + goto update_fail; + } + if( argc==1 ){ + zErr = "cannot delete"; + goto update_fail; + } + pgno = sqlite3_value_int(argv[0]); + if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ + zErr = "cannot insert"; + goto update_fail; + } + zSchema = (const char*)sqlite3_value_text(argv[4]); + iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1; + if( iDb<0 ){ + zErr = "no such schema"; + goto update_fail; + } + pBt = pTab->db->aDb[iDb].pBt; + if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){ + zErr = "bad page number"; + goto update_fail; + } + szPage = sqlite3BtreeGetPageSize(pBt); + if( sqlite3_value_type(argv[3])!=SQLITE_BLOB + || sqlite3_value_bytes(argv[3])!=szPage + ){ + zErr = "bad page value"; + goto update_fail; + } + pPager = sqlite3BtreePager(pBt); + rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3PagerWrite(pDbPage); + if( rc==SQLITE_OK ){ + memcpy(sqlite3PagerGetData(pDbPage), + sqlite3_value_blob(argv[3]), + szPage); + } + } + sqlite3PagerUnref(pDbPage); + return rc; + +update_fail: + sqlite3_free(pVtab->zErrMsg); + pVtab->zErrMsg = sqlite3_mprintf("%s", zErr); + return SQLITE_ERROR; +} + +/* Since we do not know in advance which database files will be +** written by the sqlite_dbpage virtual table, start a write transaction +** on them all. +*/ +static int dbpageBegin(sqlite3_vtab *pVtab){ + DbpageTable *pTab = (DbpageTable *)pVtab; + sqlite3 *db = pTab->db; + int i; + for(i=0; inDb; i++){ + Btree *pBt = db->aDb[i].pBt; + if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0); + } + return SQLITE_OK; +} + + +/* +** Invoke this routine to register the "dbpage" virtual table module +*/ +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ + static sqlite3_module dbpage_module = { + 0, /* iVersion */ + dbpageConnect, /* xCreate */ + dbpageConnect, /* xConnect */ + dbpageBestIndex, /* xBestIndex */ + dbpageDisconnect, /* xDisconnect */ + dbpageDisconnect, /* xDestroy */ + dbpageOpen, /* xOpen - open a cursor */ + dbpageClose, /* xClose - close a cursor */ + dbpageFilter, /* xFilter - configure scan constraints */ + dbpageNext, /* xNext - advance a cursor */ + dbpageEof, /* xEof - check for end of scan */ + dbpageColumn, /* xColumn - read data */ + dbpageRowid, /* xRowid - read data */ + dbpageUpdate, /* xUpdate */ + dbpageBegin, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ + }; + return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0); +} +#elif defined(SQLITE_ENABLE_DBPAGE_VTAB) +SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; } +#endif /* SQLITE_ENABLE_DBSTAT_VTAB */ + +/************** End of dbpage.c **********************************************/ /************** Begin file sqlite3session.c **********************************/ #if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK) @@ -173600,6 +210378,8 @@ typedef struct SessionInput SessionInput; # endif #endif +static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE; + typedef struct SessionHook SessionHook; struct SessionHook { void *pCtx; @@ -173615,12 +210395,16 @@ struct SessionHook { struct sqlite3_session { sqlite3 *db; /* Database handle session is attached to */ char *zDb; /* Name of database session is attached to */ + int bEnableSize; /* True if changeset_size() enabled */ int bEnable; /* True if currently recording */ int bIndirect; /* True if all changes are indirect */ int bAutoAttach; /* True to auto-attach tables */ int rc; /* Non-zero if an error has occurred */ void *pFilterCtx; /* First argument to pass to xTableFilter */ int (*xTableFilter)(void *pCtx, const char *zTab); + i64 nMalloc; /* Number of bytes of data allocated */ + i64 nMaxChangesetSize; + sqlite3_value *pZeroBlob; /* Value containing X'' */ sqlite3_session *pNext; /* Next session object on same db. */ SessionTable *pTable; /* List of attached tables */ SessionHook hook; /* APIs to grab new and old data with */ @@ -173636,13 +210420,13 @@ struct SessionBuffer { }; /* -** An object of this type is used internally as an abstraction for +** An object of this type is used internally as an abstraction for ** input data. Input data may be supplied either as a single large buffer ** (e.g. sqlite3changeset_start()) or using a stream function (e.g. ** sqlite3changeset_start_strm()). */ struct SessionInput { - int bNoDiscard; /* If true, discard no data */ + int bNoDiscard; /* If true, do not discard in InputBuffer() */ int iCurrent; /* Offset in aData[] of current change */ int iNext; /* Offset in aData[] of next change */ u8 *aData; /* Pointer to buffer containing changeset */ @@ -173661,6 +210445,8 @@ struct sqlite3_changeset_iter { SessionInput in; /* Input buffer or stream */ SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */ int bPatchset; /* True if this is a patchset */ + int bInvert; /* True to invert changeset */ + int bSkipEmpty; /* Skip noop UPDATE changes */ int rc; /* Iterator error code */ sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ char *zTab; /* Current table */ @@ -173688,6 +210474,7 @@ struct SessionTable { SessionTable *pNext; char *zName; /* Local name of table */ int nCol; /* Number of columns in table zName */ + int bStat1; /* True if this is sqlite_stat1 */ const char **azCol; /* Column names */ u8 *abPK; /* Array of primary key flags */ int nEntry; /* Total number of entries in hash table */ @@ -173695,11 +210482,11 @@ struct SessionTable { SessionChange **apChange; /* Hash table buckets */ }; -/* +/* ** RECORD FORMAT: ** -** The following record format is similar to (but not compatible with) that -** used in SQLite database files. This format is used as part of the +** The following record format is similar to (but not compatible with) that +** used in SQLite database files. This format is used as part of the ** change-set binary format, and so must be architecture independent. ** ** Unlike the SQLite database record format, each field is self-contained - @@ -173733,7 +210520,7 @@ struct SessionTable { ** Real values: ** An 8-byte big-endian IEEE 754-2008 real value. ** -** Varint values are encoded in the same way as varints in the SQLite +** Varint values are encoded in the same way as varints in the SQLite ** record format. ** ** CHANGESET FORMAT: @@ -173765,7 +210552,7 @@ struct SessionTable { ** ** The new.* record that is part of each INSERT change contains the values ** that make up the new row. Similarly, the old.* record that is part of each -** DELETE change contains the values that made up the row that was deleted +** DELETE change contains the values that made up the row that was deleted ** from the database. In the changeset format, the records that are part ** of INSERT or DELETE changes never contain any undefined (type byte 0x00) ** fields. @@ -173774,8 +210561,8 @@ struct SessionTable { ** associated with table columns that are not PRIMARY KEY columns and are ** not modified by the UPDATE change are set to "undefined". Other fields ** are set to the values that made up the row before the UPDATE that the -** change records took place. Within the new.* record, fields associated -** with table columns modified by the UPDATE change contain the new +** change records took place. Within the new.* record, fields associated +** with table columns modified by the UPDATE change contain the new ** values. Fields associated with table columns that are not modified ** are set to "undefined". ** @@ -173801,12 +210588,12 @@ struct SessionTable { ** ** As in the changeset format, each field of the single record that is part ** of a patchset change is associated with the correspondingly positioned -** table column, counting from left to right within the CREATE TABLE +** table column, counting from left to right within the CREATE TABLE ** statement. ** ** For a DELETE change, all fields within the record except those associated -** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields -** contain the values identifying the row to delete. +** with PRIMARY KEY columns are omitted. The PRIMARY KEY fields contain the +** values identifying the row to delete. ** ** For an UPDATE change, all fields except those associated with PRIMARY KEY ** columns and columns that are modified by the UPDATE are set to "undefined". @@ -173816,6 +210603,42 @@ struct SessionTable { ** The records associated with INSERT changes are in the same format as for ** changesets. It is not possible for a record associated with an INSERT ** change to contain a field set to "undefined". +** +** REBASE BLOB FORMAT: +** +** A rebase blob may be output by sqlite3changeset_apply_v2() and its +** streaming equivalent for use with the sqlite3_rebaser APIs to rebase +** existing changesets. A rebase blob contains one entry for each conflict +** resolved using either the OMIT or REPLACE strategies within the apply_v2() +** call. +** +** The format used for a rebase blob is very similar to that used for +** changesets. All entries related to a single table are grouped together. +** +** Each group of entries begins with a table header in changeset format: +** +** 1 byte: Constant 0x54 (capital 'T') +** Varint: Number of columns in the table. +** nCol bytes: 0x01 for PK columns, 0x00 otherwise. +** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated. +** +** Followed by one or more entries associated with the table. +** +** 1 byte: Either SQLITE_INSERT (0x12), DELETE (0x09). +** 1 byte: Flag. 0x01 for REPLACE, 0x00 for OMIT. +** record: (in the record format defined above). +** +** In a rebase blob, the first field is set to SQLITE_INSERT if the change +** that caused the conflict was an INSERT or UPDATE, or to SQLITE_DELETE if +** it was a DELETE. The second field is set to 0x01 if the conflict +** resolution strategy was REPLACE, or 0x00 if it was OMIT. +** +** If the change that caused the conflict was a DELETE, then the single +** record is a copy of the old.* record from the original changeset. If it +** was an INSERT, then the single record is a copy of the new.* record. If +** the conflicting change was an UPDATE, then the single record is a copy +** of the new.* record with the PK fields filled in based on the original +** old.* record. */ /* @@ -173823,15 +210646,16 @@ struct SessionTable { ** this structure stored in a SessionTable.aChange[] hash table. */ struct SessionChange { - int op; /* One of UPDATE, DELETE, INSERT */ - int bIndirect; /* True if this change is "indirect" */ + u8 op; /* One of UPDATE, DELETE, INSERT */ + u8 bIndirect; /* True if this change is "indirect" */ + int nMaxSize; /* Max size of eventual changeset record */ int nRecord; /* Number of bytes in buffer aRecord[] */ u8 *aRecord; /* Buffer containing old.* record */ SessionChange *pNext; /* For hash-table collisions */ }; /* -** Write a varint with value iVal into the buffer at aBuf. Return the +** Write a varint with value iVal into the buffer at aBuf. Return the ** number of bytes written. */ static int sessionVarintPut(u8 *aBuf, int iVal){ @@ -173846,7 +210670,7 @@ static int sessionVarintLen(int iVal){ } /* -** Read a varint value from aBuf[] into *piVal. Return the number of +** Read a varint value from aBuf[] into *piVal. Return the number of ** bytes read. */ static int sessionVarintGet(u8 *aBuf, int *piVal){ @@ -173885,34 +210709,34 @@ static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){ ** This function is used to serialize the contents of value pValue (see ** comment titled "RECORD FORMAT" above). ** -** If it is non-NULL, the serialized form of the value is written to +** If it is non-NULL, the serialized form of the value is written to ** buffer aBuf. *pnWrite is set to the number of bytes written before ** returning. Or, if aBuf is NULL, the only thing this function does is ** set *pnWrite. ** ** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs -** within a call to sqlite3_value_text() (may fail if the db is utf-16)) +** within a call to sqlite3_value_text() (may fail if the db is utf-16)) ** SQLITE_NOMEM is returned. */ static int sessionSerializeValue( u8 *aBuf, /* If non-NULL, write serialized value here */ sqlite3_value *pValue, /* Value to serialize */ - int *pnWrite /* IN/OUT: Increment by bytes written */ + sqlite3_int64 *pnWrite /* IN/OUT: Increment by bytes written */ ){ int nByte; /* Size of serialized value in bytes */ if( pValue ){ int eType; /* Value type (SQLITE_NULL, TEXT etc.) */ - + eType = sqlite3_value_type(pValue); if( aBuf ) aBuf[0] = eType; - + switch( eType ){ - case SQLITE_NULL: + case SQLITE_NULL: nByte = 1; break; - - case SQLITE_INTEGER: + + case SQLITE_INTEGER: case SQLITE_FLOAT: if( aBuf ){ /* TODO: SQLite does something special to deal with mixed-endian @@ -173929,14 +210753,14 @@ static int sessionSerializeValue( } sessionPutI64(&aBuf[1], i); } - nByte = 9; + nByte = 9; break; - + default: { u8 *z; int n; int nVarint; - + assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); if( eType==SQLITE_TEXT ){ z = (u8 *)sqlite3_value_text(pValue); @@ -173946,12 +210770,12 @@ static int sessionSerializeValue( n = sqlite3_value_bytes(pValue); if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM; nVarint = sessionVarintLen(n); - + if( aBuf ){ sessionVarintPut(&aBuf[1], n); - if( n ) memcpy(&aBuf[nVarint + 1], z, n); + if( n>0 ) memcpy(&aBuf[nVarint + 1], z, n); } - + nByte = 1 + nVarint + n; break; } @@ -173965,6 +210789,26 @@ static int sessionSerializeValue( return SQLITE_OK; } +/* +** Allocate and return a pointer to a buffer nByte bytes in size. If +** pSession is not NULL, increase the sqlite3_session.nMalloc variable +** by the number of bytes allocated. +*/ +static void *sessionMalloc64(sqlite3_session *pSession, i64 nByte){ + void *pRet = sqlite3_malloc64(nByte); + if( pSession ) pSession->nMalloc += sqlite3_msize(pRet); + return pRet; +} + +/* +** Free buffer pFree, which must have been allocated by an earlier +** call to sessionMalloc64(). If pSession is not NULL, decrease the +** sqlite3_session.nMalloc counter by the number of bytes freed. +*/ +static void sessionFree(sqlite3_session *pSession, void *pFree){ + if( pSession ) pSession->nMalloc -= sqlite3_msize(pFree); + sqlite3_free(pFree); +} /* ** This macro is used to calculate hash key values for data structures. In @@ -173993,7 +210837,7 @@ static unsigned int sessionHashAppendI64(unsigned int h, i64 i){ } /* -** Append the hash of the blob passed via the second and third arguments to +** Append the hash of the blob passed via the second and third arguments to ** the hash-key value passed as the first. Return the new hash-key value. */ static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){ @@ -174012,7 +210856,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){ /* ** This function may only be called from within a pre-update callback. -** It calculates a hash based on the primary key values of the old.* or +** It calculates a hash based on the primary key values of the old.* or ** new.* row currently available and, assuming no error occurs, writes it to ** *piHash before returning. If the primary key contains one or more NULL ** values, *pbNullPK is set to true before returning. @@ -174071,6 +210915,7 @@ static int sessionPreupdateHash( h = sessionHashAppendBlob(h, n, z); }else{ assert( eType==SQLITE_NULL ); + assert( pTab->bStat1==0 || i!=1 ); *pbNullPK = 1; } } @@ -174088,7 +210933,7 @@ static int sessionPreupdateHash( static int sessionSerialLen(u8 *a){ int e = *a; int n; - if( e==0 ) return 1; + if( e==0 || e==0xFF ) return 1; if( e==SQLITE_NULL ) return 1; if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9; return sessionVarintGet(&a[1], &n) + 1 + n; @@ -174118,12 +210963,12 @@ static unsigned int sessionChangeHash( int isPK = pTab->abPK[i]; if( bPkOnly && isPK==0 ) continue; - /* It is not possible for eType to be SQLITE_NULL here. The session + /* It is not possible for eType to be SQLITE_NULL here. The session ** module does not record changes for rows with NULL values stored in ** primary key columns. */ - assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT - || eType==SQLITE_TEXT || eType==SQLITE_BLOB - || eType==SQLITE_NULL || eType==0 + assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT + || eType==SQLITE_TEXT || eType==SQLITE_BLOB + || eType==SQLITE_NULL || eType==0 ); assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) ); @@ -174134,7 +210979,7 @@ static unsigned int sessionChangeHash( h = sessionHashAppendI64(h, sessionGetI64(a)); a += 8; }else{ - int n; + int n; a += sessionVarintGet(a, &n); h = sessionHashAppendBlob(h, n, a); a += n; @@ -174149,7 +210994,7 @@ static unsigned int sessionChangeHash( /* ** Arguments aLeft and aRight are pointers to change records for table pTab. ** This function returns true if the two records apply to the same row (i.e. -** have the same values stored in the primary key columns), or false +** have the same values stored in the primary key columns), or false ** otherwise. */ static int sessionChangeEqual( @@ -174168,7 +211013,7 @@ static int sessionChangeEqual( int n1 = sessionSerialLen(a1); int n2 = sessionSerialLen(a2); - if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){ + if( n1!=n2 || memcmp(a1, a2, n1) ){ return 0; } a1 += n1; @@ -174186,17 +211031,17 @@ static int sessionChangeEqual( ** Arguments aLeft and aRight both point to buffers containing change ** records with nCol columns. This function "merges" the two records into ** a single records which is written to the buffer at *paOut. *paOut is -** then set to point to one byte after the last byte written before +** then set to point to one byte after the last byte written before ** returning. ** -** The merging of records is done as follows: For each column, if the +** The merging of records is done as follows: For each column, if the ** aRight record contains a value for the column, copy the value from ** their. Otherwise, if aLeft contains a value, copy it. If neither ** record contains a value for a given column, then neither does the ** output record. */ static void sessionMergeRecord( - u8 **paOut, + u8 **paOut, int nCol, u8 *aLeft, u8 *aRight @@ -174226,13 +211071,13 @@ static void sessionMergeRecord( /* ** This is a helper function used by sessionMergeUpdate(). ** -** When this function is called, both *paOne and *paTwo point to a value -** within a change record. Before it returns, both have been advanced so +** When this function is called, both *paOne and *paTwo point to a value +** within a change record. Before it returns, both have been advanced so ** as to point to the next value in the record. ** ** If, when this function is called, *paTwo points to a valid value (i.e. ** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo -** pointer is returned and *pnVal is set to the number of bytes in the +** pointer is returned and *pnVal is set to the number of bytes in the ** serialized value. Otherwise, a copy of *paOne is returned and *pnVal ** set to the number of bytes in the value at *paOne. If *paOne points ** to the "no value" placeholder, *pnVal is set to 1. In other words: @@ -174331,8 +211176,8 @@ static int sessionMergeUpdate( aOld = sessionMergeValue(&aOld1, &aOld2, &nOld); aNew = sessionMergeValue(&aNew1, &aNew2, &nNew); - if( bPatchset==0 - && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew))) + if( bPatchset==0 + && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew))) ){ *(aOut++) = '\0'; }else{ @@ -174411,9 +211256,8 @@ static int sessionPreupdateEqual( }else{ z = sqlite3_value_blob(pVal); } - if( memcmp(a, z, n) ) return 0; + if( n>0 && memcmp(a, z, n) ) return 0; a += n; - break; } } } @@ -174422,7 +211266,7 @@ static int sessionPreupdateEqual( } /* -** If required, grow the hash table used to store changes on table pTab +** If required, grow the hash table used to store changes on table pTab ** (part of the session pSession). If a fatal OOM error occurs, set the ** session object to failed and return SQLITE_ERROR. Otherwise, return ** SQLITE_OK. @@ -174432,13 +211276,19 @@ static int sessionPreupdateEqual( ** Growing the hash table in this case is a performance optimization only, ** it is not required for correct operation. */ -static int sessionGrowHash(int bPatchset, SessionTable *pTab){ +static int sessionGrowHash( + sqlite3_session *pSession, /* For memory accounting. May be NULL */ + int bPatchset, + SessionTable *pTab +){ if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){ int i; SessionChange **apNew; - int nNew = (pTab->nChange ? pTab->nChange : 128) * 2; + sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128); - apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew); + apNew = (SessionChange**)sessionMalloc64( + pSession, sizeof(SessionChange*) * nNew + ); if( apNew==0 ){ if( pTab->nChange==0 ){ return SQLITE_ERROR; @@ -174459,7 +211309,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){ } } - sqlite3_free(pTab->apChange); + sessionFree(pSession, pTab->apChange); pTab->nChange = nNew; pTab->apChange = apNew; } @@ -174469,9 +211319,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){ /* ** This function queries the database for the names of the columns of table -** zThis, in schema zDb. It is expected that the table has nCol columns. If -** not, SQLITE_SCHEMA is returned and none of the output variables are -** populated. +** zThis, in schema zDb. ** ** Otherwise, if they are not NULL, variable *pnCol is set to the number ** of columns in the database table and variable *pzTab is set to point to a @@ -174492,11 +211340,10 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){ ** *pabPK = {1, 0, 0, 1} ** ** All returned buffers are part of the same single allocation, which must -** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then -** pointer *pazCol should be freed to release all memory. Otherwise, pointer -** *pabPK. It is illegal for both pazCol and pabPK to be NULL. +** be freed using sqlite3_free() by the caller */ static int sessionTableInfo( + sqlite3_session *pSession, /* For memory accounting. May be NULL */ sqlite3 *db, /* Database connection */ const char *zDb, /* Name of attached database (e.g. "main") */ const char *zThis, /* Table name */ @@ -174508,7 +211355,7 @@ static int sessionTableInfo( char *zPragma; sqlite3_stmt *pStmt; int rc; - int nByte; + sqlite3_int64 nByte; int nDbCol = 0; int nThis; int i; @@ -174519,12 +211366,44 @@ static int sessionTableInfo( assert( pazCol && pabPK ); nThis = sqlite3Strlen30(zThis); - zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); - if( !zPragma ) return SQLITE_NOMEM; + if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){ + rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0); + if( rc==SQLITE_OK ){ + /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */ + zPragma = sqlite3_mprintf( + "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL " + "SELECT 1, 'idx', '', 0, '', 2 UNION ALL " + "SELECT 2, 'stat', '', 0, '', 0" + ); + }else if( rc==SQLITE_ERROR ){ + zPragma = sqlite3_mprintf(""); + }else{ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; + return rc; + } + }else{ + zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); + } + if( !zPragma ){ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; + return SQLITE_NOMEM; + } rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); sqlite3_free(zPragma); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ){ + *pazCol = 0; + *pabPK = 0; + *pnCol = 0; + if( pzTab ) *pzTab = 0; + return rc; + } nByte = nThis + 1; while( SQLITE_ROW==sqlite3_step(pStmt) ){ @@ -174535,7 +211414,7 @@ static int sessionTableInfo( if( rc==SQLITE_OK ){ nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1); - pAlloc = sqlite3_malloc(nByte); + pAlloc = sessionMalloc64(pSession, nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; } @@ -174550,7 +211429,7 @@ static int sessionTableInfo( *pzTab = (char *)pAlloc; pAlloc += nThis+1; } - + i = 0; while( SQLITE_ROW==sqlite3_step(pStmt) ){ int nName = sqlite3_column_bytes(pStmt, 1); @@ -174563,7 +211442,7 @@ static int sessionTableInfo( i++; } rc = sqlite3_reset(pStmt); - + } /* If successful, populate the output variables. Otherwise, zero them and @@ -174578,7 +211457,7 @@ static int sessionTableInfo( *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; - sqlite3_free(azCol); + sessionFree(pSession, azCol); } sqlite3_finalize(pStmt); return rc; @@ -174593,14 +211472,14 @@ static int sessionTableInfo( ** If an error occurs, an error code is stored in sqlite3_session.rc and ** non-zero returned. Or, if no error occurs but the table has no primary ** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to -** indicate that updates on this table should be ignored. SessionTable.abPK +** indicate that updates on this table should be ignored. SessionTable.abPK ** is set to NULL in this case. */ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ if( pTab->nCol==0 ){ u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); - pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, + pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK ); if( pSession->rc==SQLITE_OK ){ @@ -174611,13 +211490,160 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){ break; } } + if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){ + pTab->bStat1 = 1; + } + + if( pSession->bEnableSize ){ + pSession->nMaxChangesetSize += ( + 1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1 + ); + } } } return (pSession->rc || pTab->abPK==0); } /* -** This function is only called from with a pre-update-hook reporting a +** Versions of the four methods in object SessionHook for use with the +** sqlite_stat1 table. The purpose of this is to substitute a zero-length +** blob each time a NULL value is read from the "idx" column of the +** sqlite_stat1 table. +*/ +typedef struct SessionStat1Ctx SessionStat1Ctx; +struct SessionStat1Ctx { + SessionHook hook; + sqlite3_session *pSession; +}; +static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){ + SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx; + sqlite3_value *pVal = 0; + int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal); + if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){ + pVal = p->pSession->pZeroBlob; + } + *ppVal = pVal; + return rc; +} +static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){ + SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx; + sqlite3_value *pVal = 0; + int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal); + if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){ + pVal = p->pSession->pZeroBlob; + } + *ppVal = pVal; + return rc; +} +static int sessionStat1Count(void *pCtx){ + SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx; + return p->hook.xCount(p->hook.pCtx); +} +static int sessionStat1Depth(void *pCtx){ + SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx; + return p->hook.xDepth(p->hook.pCtx); +} + +static int sessionUpdateMaxSize( + int op, + sqlite3_session *pSession, /* Session object pTab is attached to */ + SessionTable *pTab, /* Table that change applies to */ + SessionChange *pC /* Update pC->nMaxSize */ +){ + i64 nNew = 2; + if( pC->op==SQLITE_INSERT ){ + if( op!=SQLITE_DELETE ){ + int ii; + for(ii=0; iinCol; ii++){ + sqlite3_value *p = 0; + pSession->hook.xNew(pSession->hook.pCtx, ii, &p); + sessionSerializeValue(0, p, &nNew); + } + } + }else if( op==SQLITE_DELETE ){ + nNew += pC->nRecord; + if( sqlite3_preupdate_blobwrite(pSession->db)>=0 ){ + nNew += pC->nRecord; + } + }else{ + int ii; + u8 *pCsr = pC->aRecord; + for(ii=0; iinCol; ii++){ + int bChanged = 1; + int nOld = 0; + int eType; + sqlite3_value *p = 0; + pSession->hook.xNew(pSession->hook.pCtx, ii, &p); + if( p==0 ){ + return SQLITE_NOMEM; + } + + eType = *pCsr++; + switch( eType ){ + case SQLITE_NULL: + bChanged = sqlite3_value_type(p)!=SQLITE_NULL; + break; + + case SQLITE_FLOAT: + case SQLITE_INTEGER: { + if( eType==sqlite3_value_type(p) ){ + sqlite3_int64 iVal = sessionGetI64(pCsr); + if( eType==SQLITE_INTEGER ){ + bChanged = (iVal!=sqlite3_value_int64(p)); + }else{ + double dVal; + memcpy(&dVal, &iVal, 8); + bChanged = (dVal!=sqlite3_value_double(p)); + } + } + nOld = 8; + pCsr += 8; + break; + } + + default: { + int nByte; + nOld = sessionVarintGet(pCsr, &nByte); + pCsr += nOld; + nOld += nByte; + assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); + if( eType==sqlite3_value_type(p) + && nByte==sqlite3_value_bytes(p) + && (nByte==0 || 0==memcmp(pCsr, sqlite3_value_blob(p), nByte)) + ){ + bChanged = 0; + } + pCsr += nByte; + break; + } + } + + if( bChanged && pTab->abPK[ii] ){ + nNew = pC->nRecord + 2; + break; + } + + if( bChanged ){ + nNew += 1 + nOld; + sessionSerializeValue(0, p, &nNew); + }else if( pTab->abPK[ii] ){ + nNew += 2 + nOld; + }else{ + nNew += 2; + } + } + } + + if( nNew>pC->nMaxSize ){ + int nIncr = nNew - pC->nMaxSize; + pC->nMaxSize = nNew; + pSession->nMaxChangesetSize += nIncr; + } + return SQLITE_OK; +} + +/* +** This function is only called from with a pre-update-hook reporting a ** change on table pTab (attached to session pSession). The type of change ** (UPDATE, INSERT, DELETE) is specified by the first argument. ** @@ -174629,16 +211655,17 @@ static void sessionPreupdateOneChange( sqlite3_session *pSession, /* Session object pTab is attached to */ SessionTable *pTab /* Table that change applies to */ ){ - int iHash; - int bNull = 0; + int iHash; + int bNull = 0; int rc = SQLITE_OK; + SessionStat1Ctx stat1 = {{0,0,0,0,0},0}; if( pSession->rc ) return; /* Load table details if required */ if( sessionInitTable(pSession, pTab) ) return; - /* Check the number of columns in this xPreUpdate call matches the + /* Check the number of columns in this xPreUpdate call matches the ** number of columns in the table. */ if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ pSession->rc = SQLITE_SCHEMA; @@ -174646,11 +211673,30 @@ static void sessionPreupdateOneChange( } /* Grow the hash table if required */ - if( sessionGrowHash(0, pTab) ){ + if( sessionGrowHash(pSession, 0, pTab) ){ pSession->rc = SQLITE_NOMEM; return; } + if( pTab->bStat1 ){ + stat1.hook = pSession->hook; + stat1.pSession = pSession; + pSession->hook.pCtx = (void*)&stat1; + pSession->hook.xNew = sessionStat1New; + pSession->hook.xOld = sessionStat1Old; + pSession->hook.xCount = sessionStat1Count; + pSession->hook.xDepth = sessionStat1Depth; + if( pSession->pZeroBlob==0 ){ + sqlite3_value *p = sqlite3ValueNew(0); + if( p==0 ){ + rc = SQLITE_NOMEM; + goto error_out; + } + sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC); + pSession->pZeroBlob = p; + } + } + /* Calculate the hash-key for this change. If the primary key of the row ** includes a NULL value, exit early. Such changes are ignored by the ** session module. */ @@ -174668,13 +211714,12 @@ static void sessionPreupdateOneChange( /* Create a new change object containing all the old values (if ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK ** values (if this is an INSERT). */ - SessionChange *pChange; /* New change object */ - int nByte; /* Number of bytes to allocate */ + sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Used to iterate through columns */ - + assert( rc==SQLITE_OK ); pTab->nEntry++; - + /* Figure out how large an allocation is required */ nByte = sizeof(SessionChange); for(i=0; inCol; i++){ @@ -174692,17 +211737,17 @@ static void sessionPreupdateOneChange( rc = sessionSerializeValue(0, p, &nByte); if( rc!=SQLITE_OK ) goto error_out; } - + /* Allocate the change object */ - pChange = (SessionChange *)sqlite3_malloc(nByte); - if( !pChange ){ + pC = (SessionChange *)sessionMalloc64(pSession, nByte); + if( !pC ){ rc = SQLITE_NOMEM; goto error_out; }else{ - memset(pChange, 0, sizeof(SessionChange)); - pChange->aRecord = (u8 *)&pChange[1]; + memset(pC, 0, sizeof(SessionChange)); + pC->aRecord = (u8 *)&pC[1]; } - + /* Populate the change object. None of the preupdate_old(), ** preupdate_new() or SerializeValue() calls below may fail as all ** required values and encodings have already been cached in memory. @@ -174715,38 +211760,47 @@ static void sessionPreupdateOneChange( }else if( pTab->abPK[i] ){ pSession->hook.xNew(pSession->hook.pCtx, i, &p); } - sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte); + sessionSerializeValue(&pC->aRecord[nByte], p, &nByte); } /* Add the change to the hash-table */ if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){ - pChange->bIndirect = 1; + pC->bIndirect = 1; } - pChange->nRecord = nByte; - pChange->op = op; - pChange->pNext = pTab->apChange[iHash]; - pTab->apChange[iHash] = pChange; + pC->nRecord = nByte; + pC->op = op; + pC->pNext = pTab->apChange[iHash]; + pTab->apChange[iHash] = pC; }else if( pC->bIndirect ){ /* If the existing change is considered "indirect", but this current ** change is "direct", mark the change object as direct. */ - if( pSession->hook.xDepth(pSession->hook.pCtx)==0 - && pSession->bIndirect==0 + if( pSession->hook.xDepth(pSession->hook.pCtx)==0 + && pSession->bIndirect==0 ){ pC->bIndirect = 0; } } + + assert( rc==SQLITE_OK ); + if( pSession->bEnableSize ){ + rc = sessionUpdateMaxSize(op, pSession, pTab, pC); + } } + /* If an error has occurred, mark the session object as failed. */ error_out: + if( pTab->bStat1 ){ + pSession->hook = stat1.hook; + } if( rc!=SQLITE_OK ){ pSession->rc = rc; } } static int sessionFindTable( - sqlite3_session *pSession, + sqlite3_session *pSession, const char *zName, SessionTable **ppTab ){ @@ -174763,11 +211817,15 @@ static int sessionFindTable( /* If there is a table-filter configured, invoke it. If it returns 0, ** do not automatically add the new table. */ if( pSession->xTableFilter==0 - || pSession->xTableFilter(pSession->pFilterCtx, zName) + || pSession->xTableFilter(pSession->pFilterCtx, zName) ){ rc = sqlite3session_attach(pSession, zName); if( rc==SQLITE_OK ){ - for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext); + pRet = pSession->pTable; + while( ALWAYS(pRet) && pRet->pNext ){ + pRet = pRet->pNext; + } + assert( pRet!=0 ); assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ); } } @@ -174798,8 +211856,8 @@ static void xPreUpdate( for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){ SessionTable *pTab; - /* If this session is attached to a different database ("main", "temp" - ** etc.), or if it is not currently enabled, there is nothing to do. Skip + /* If this session is attached to a different database ("main", "temp" + ** etc.), or if it is not currently enabled, there is nothing to do. Skip ** to the next session object attached to this database. */ if( pSession->bEnable==0 ) continue; if( pSession->rc ) continue; @@ -174890,7 +211948,7 @@ static void sessionDiffHooks( static char *sessionExprComparePK( int nCol, - const char *zDb1, const char *zDb2, + const char *zDb1, const char *zDb2, const char *zTab, const char **azCol, u8 *abPK ){ @@ -174913,7 +211971,7 @@ static char *sessionExprComparePK( static char *sessionExprCompareOther( int nCol, - const char *zDb1, const char *zDb2, + const char *zDb1, const char *zDb2, const char *zTab, const char **azCol, u8 *abPK ){ @@ -174990,9 +212048,9 @@ static int sessionDiffFindNew( } static int sessionDiffFindModified( - sqlite3_session *pSession, - SessionTable *pTab, - const char *zFrom, + sqlite3_session *pSession, + SessionTable *pTab, + const char *zFrom, const char *zExpr ){ int rc = SQLITE_OK; @@ -175064,7 +212122,7 @@ SQLITE_API int sqlite3session_diff( int nCol; /* Columns in zFrom.zTbl */ u8 *abPK; const char **azCol = 0; - rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK); + rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK); if( rc==SQLITE_OK ){ if( pTo->nCol!=nCol ){ bMismatch = 1; @@ -175076,11 +212134,12 @@ SQLITE_API int sqlite3session_diff( if( abPK[i] ) bHasPk = 1; } } - } sqlite3_free((char*)azCol); if( bMismatch ){ - *pzErrMsg = sqlite3_mprintf("table schemas do not match"); + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("table schemas do not match"); + } rc = SQLITE_SCHEMA; } if( bHasPk==0 ){ @@ -175090,7 +212149,7 @@ SQLITE_API int sqlite3session_diff( } if( rc==SQLITE_OK ){ - zExpr = sessionExprComparePK(pTo->nCol, + zExpr = sessionExprComparePK(pTo->nCol, zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK ); } @@ -175136,7 +212195,7 @@ SQLITE_API int sqlite3session_create( *ppSession = 0; /* Allocate and populate the new session object. */ - pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1); + pNew = (sqlite3_session *)sqlite3_malloc64(sizeof(sqlite3_session) + nDb + 1); if( !pNew ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(sqlite3_session)); pNew->db = db; @@ -175145,7 +212204,7 @@ SQLITE_API int sqlite3session_create( memcpy(pNew->zDb, zDb, nDb+1); sessionPreupdateHooks(pNew); - /* Add the new session object to the linked list of session objects + /* Add the new session object to the linked list of session objects ** attached to database handle $db. Do this under the cover of the db ** handle mutex. */ sqlite3_mutex_enter(sqlite3_db_mutex(db)); @@ -175161,7 +212220,7 @@ SQLITE_API int sqlite3session_create( ** Free the list of table objects passed as the first argument. The contents ** of the changed-rows hash tables are also deleted. */ -static void sessionDeleteTable(SessionTable *pList){ +static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){ SessionTable *pNext; SessionTable *pTab; @@ -175173,12 +212232,12 @@ static void sessionDeleteTable(SessionTable *pList){ SessionChange *pNextChange; for(p=pTab->apChange[i]; p; p=pNextChange){ pNextChange = p->pNext; - sqlite3_free(p); + sessionFree(pSession, p); } } - sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */ - sqlite3_free(pTab->apChange); - sqlite3_free(pTab); + sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */ + sessionFree(pSession, pTab->apChange); + sessionFree(pSession, pTab); } } @@ -175202,12 +212261,15 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){ } } sqlite3_mutex_leave(sqlite3_db_mutex(db)); + sqlite3ValueFree(pSession->pZeroBlob); - /* Delete all attached table objects. And the contents of their + /* Delete all attached table objects. And the contents of their ** associated hash-tables. */ - sessionDeleteTable(pSession->pTable); + sessionDeleteTable(pSession, pSession->pTable); - /* Free the session object itself. */ + /* Assert that all allocations have been freed and then free the + ** session object itself. */ + assert( pSession->nMalloc==0 ); sqlite3_free(pSession); } @@ -175215,7 +212277,7 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){ ** Set a table filter on a Session Object. */ SQLITE_API void sqlite3session_table_filter( - sqlite3_session *pSession, + sqlite3_session *pSession, int(*xFilter)(void*, const char*), void *pCtx /* First argument passed to xFilter */ ){ @@ -175254,12 +212316,13 @@ SQLITE_API int sqlite3session_attach( if( !pTab ){ /* Allocate new SessionTable object. */ - pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1); + int nByte = sizeof(SessionTable) + nName + 1; + pTab = (SessionTable*)sessionMalloc64(pSession, nByte); if( !pTab ){ rc = SQLITE_NOMEM; }else{ /* Populate the new SessionTable object and link it into the list. - ** The new object must be linked onto the end of the list, not + ** The new object must be linked onto the end of the list, not ** simply added to the start of it in order to ensure that tables ** appear in the correct order when a changeset or patchset is ** eventually generated. */ @@ -175284,15 +212347,31 @@ SQLITE_API int sqlite3session_attach( ** If successful, return zero. Otherwise, if an OOM condition is encountered, ** set *pRc to SQLITE_NOMEM and return non-zero. */ -static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ - if( *pRc==SQLITE_OK && p->nAlloc-p->nBufnBuf + nByte; + if( *pRc==SQLITE_OK && nReq>p->nAlloc ){ u8 *aNew; - int nNew = p->nAlloc ? p->nAlloc : 128; + i64 nNew = p->nAlloc ? p->nAlloc : 128; + do { nNew = nNew*2; - }while( nNew<(p->nBuf+nByte) ); + }while( nNewSESSION_MAX_BUFFER_SZ ){ + nNew = SESSION_MAX_BUFFER_SZ; + if( nNewaBuf, nNew); + aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew); if( 0==aNew ){ *pRc = SQLITE_NOMEM; }else{ @@ -175314,7 +212393,7 @@ static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){ int rc = *pRc; if( rc==SQLITE_OK ){ - int nByte = 0; + sqlite3_int64 nByte = 0; rc = sessionSerializeValue(0, pVal, &nByte); sessionBufferGrow(p, nByte, &rc); if( rc==SQLITE_OK ){ @@ -175327,8 +212406,8 @@ static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){ } /* -** This function is a no-op if *pRc is other than SQLITE_OK when it is -** called. Otherwise, append a single byte to the buffer. +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a single byte to the buffer. ** ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before ** returning. @@ -175340,8 +212419,8 @@ static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){ } /* -** This function is a no-op if *pRc is other than SQLITE_OK when it is -** called. Otherwise, append a single varint to the buffer. +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a single varint to the buffer. ** ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before ** returning. @@ -175353,16 +212432,16 @@ static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){ } /* -** This function is a no-op if *pRc is other than SQLITE_OK when it is -** called. Otherwise, append a blob of data to the buffer. +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. Otherwise, append a blob of data to the buffer. ** ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before ** returning. */ static void sessionAppendBlob( - SessionBuffer *p, - const u8 *aBlob, - int nBlob, + SessionBuffer *p, + const u8 *aBlob, + int nBlob, int *pRc ){ if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){ @@ -175372,7 +212451,7 @@ static void sessionAppendBlob( } /* -** This function is a no-op if *pRc is other than SQLITE_OK when it is +** This function is a no-op if *pRc is other than SQLITE_OK when it is ** called. Otherwise, append a string to the buffer. All bytes in the string ** up to (but not including) the nul-terminator are written to the buffer. ** @@ -175380,8 +212459,8 @@ static void sessionAppendBlob( ** returning. */ static void sessionAppendStr( - SessionBuffer *p, - const char *zStr, + SessionBuffer *p, + const char *zStr, int *pRc ){ int nStr = sqlite3Strlen30(zStr); @@ -175392,7 +212471,7 @@ static void sessionAppendStr( } /* -** This function is a no-op if *pRc is other than SQLITE_OK when it is +** This function is a no-op if *pRc is other than SQLITE_OK when it is ** called. Otherwise, append the string representation of integer iVal ** to the buffer. No nul-terminator is written. ** @@ -175410,9 +212489,9 @@ static void sessionAppendInteger( } /* -** This function is a no-op if *pRc is other than SQLITE_OK when it is +** This function is a no-op if *pRc is other than SQLITE_OK when it is ** called. Otherwise, append the string zStr enclosed in quotes (") and -** with any embedded quote characters escaped to the buffer. No +** with any embedded quote characters escaped to the buffer. No ** nul-terminator byte is written. ** ** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before @@ -175485,8 +212564,8 @@ static void sessionAppendCol( /* ** -** This function appends an update change to the buffer (see the comments -** under "CHANGESET FORMAT" at the top of the file). An update change +** This function appends an update change to the buffer (see the comments +** under "CHANGESET FORMAT" at the top of the file). An update change ** consists of: ** ** 1 byte: SQLITE_UPDATE (0x17) @@ -175501,10 +212580,10 @@ static void sessionAppendCol( ** If all of the old.* values are equal to their corresponding new.* value ** (i.e. nothing has changed), then no data at all is appended to the buffer. ** -** Otherwise, the old.* record contains all primary key values and the -** original values of any fields that have been modified. The new.* record +** Otherwise, the old.* record contains all primary key values and the +** original values of any fields that have been modified. The new.* record ** contains the new values of only those fields that have been modified. -*/ +*/ static int sessionAppendUpdate( SessionBuffer *pBuf, /* Buffer to append to */ int bPatchset, /* True for "patchset", 0 for "changeset" */ @@ -175519,6 +212598,7 @@ static int sessionAppendUpdate( int i; /* Used to iterate through columns */ u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */ + assert( abPK!=0 ); sessionAppendByte(pBuf, SQLITE_UPDATE, &rc); sessionAppendByte(pBuf, p->bIndirect, &rc); for(i=0; ipTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ const char *zName = pTab->zName; - int nCol; /* Number of columns in table */ - u8 *abPK; /* Primary key array */ + int nCol = 0; /* Number of columns in table */ + u8 *abPK = 0; /* Primary key array */ const char **azCol = 0; /* Table columns */ int i; /* Used to iterate through hash buckets */ sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */ @@ -175837,7 +212933,7 @@ static int sessionGenerateChangeset( int nNoop; /* Size of buffer after writing tbl header */ /* Check the table schema is still Ok. */ - rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK); + rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK); if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){ rc = SQLITE_SCHEMA; } @@ -175867,6 +212963,7 @@ static int sessionGenerateChangeset( sessionAppendCol(&buf, pSel, iCol, &rc); } }else{ + assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */ rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK); } }else if( p->op!=SQLITE_INSERT ){ @@ -175876,12 +212973,12 @@ static int sessionGenerateChangeset( rc = sqlite3_reset(pSel); } - /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass + /* If the buffer is now larger than sessions_strm_chunk_size, pass ** its contents to the xOutput() callback. */ - if( xOutput - && rc==SQLITE_OK - && buf.nBuf>nNoop - && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE + if( xOutput + && rc==SQLITE_OK + && buf.nBuf>nNoop + && buf.nBuf>sessions_strm_chunk_size ){ rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf); nNoop = -1; @@ -175916,10 +213013,10 @@ static int sessionGenerateChangeset( } /* -** Obtain a changeset object containing all changes recorded by the +** Obtain a changeset object containing all changes recorded by the ** session object passed as the first argument. ** -** It is the responsibility of the caller to eventually free the buffer +** It is the responsibility of the caller to eventually free the buffer ** using sqlite3_free(). */ SQLITE_API int sqlite3session_changeset( @@ -175927,7 +213024,14 @@ SQLITE_API int sqlite3session_changeset( int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ){ - return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset); + int rc; + + if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE; + rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset); + assert( rc || pnChangeset==0 + || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize + ); + return rc; } /* @@ -175938,6 +213042,7 @@ SQLITE_API int sqlite3session_changeset_strm( int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ){ + if( xOutput==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0); } @@ -175949,14 +213054,15 @@ SQLITE_API int sqlite3session_patchset_strm( int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ){ + if( xOutput==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0); } /* -** Obtain a patchset object containing all changes recorded by the +** Obtain a patchset object containing all changes recorded by the ** session object passed as the first argument. ** -** It is the responsibility of the caller to eventually free the buffer +** It is the responsibility of the caller to eventually free the buffer ** using sqlite3_free(). */ SQLITE_API int sqlite3session_patchset( @@ -175964,6 +213070,7 @@ SQLITE_API int sqlite3session_patchset( int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ void **ppPatchset /* OUT: Buffer containing changeset */ ){ + if( pnPatchset==0 || ppPatchset==0 ) return SQLITE_MISUSE; return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset); } @@ -176012,6 +213119,46 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){ return (ret==0); } +/* +** Return the amount of heap memory in use. +*/ +SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession){ + return pSession->nMalloc; +} + +/* +** Configure the session object passed as the first argument. +*/ +SQLITE_API int sqlite3session_object_config(sqlite3_session *pSession, int op, void *pArg){ + int rc = SQLITE_OK; + switch( op ){ + case SQLITE_SESSION_OBJCONFIG_SIZE: { + int iArg = *(int*)pArg; + if( iArg>=0 ){ + if( pSession->pTable ){ + rc = SQLITE_MISUSE; + }else{ + pSession->bEnableSize = (iArg!=0); + } + } + *(int*)pArg = pSession->bEnableSize; + break; + } + + default: + rc = SQLITE_MISUSE; + } + + return rc; +} + +/* +** Return the maximum size of sqlite3session_changeset() output. +*/ +SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession){ + return pSession->nMaxChangesetSize; +} + /* ** Do the work for either sqlite3changeset_start() or start_strm(). */ @@ -176020,7 +213167,9 @@ static int sessionChangesetStart( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int nChangeset, /* Size of buffer pChangeset in bytes */ - void *pChangeset /* Pointer to buffer containing changeset */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int bInvert, /* True to invert changeset */ + int bSkipEmpty /* True to skip empty UPDATE changes */ ){ sqlite3_changeset_iter *pRet; /* Iterator to return */ int nByte; /* Number of bytes to allocate for iterator */ @@ -176040,6 +213189,8 @@ static int sessionChangesetStart( pRet->in.xInput = xInput; pRet->in.pIn = pIn; pRet->in.bEof = (xInput ? 0 : 1); + pRet->bInvert = bInvert; + pRet->bSkipEmpty = bSkipEmpty; /* Populate the output variable and return success. */ *pp = pRet; @@ -176054,7 +213205,16 @@ SQLITE_API int sqlite3changeset_start( int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset /* Pointer to buffer containing changeset */ ){ - return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0, 0); +} +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int nChangeset, /* Size of buffer pChangeset in bytes */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert, 0); } /* @@ -176065,7 +213225,16 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ){ - return sessionChangesetStart(pp, xInput, pIn, 0, 0); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0, 0); +} +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert, 0); } /* @@ -176073,7 +213242,7 @@ SQLITE_API int sqlite3changeset_start_strm( ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ - if( pIn->bEof && pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){ + if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){ int nMove = pIn->buf.nBuf - pIn->iNext; assert( nMove>=0 ); if( nMove>0 ){ @@ -176096,7 +213265,7 @@ static int sessionInputBuffer(SessionInput *pIn, int nByte){ int rc = SQLITE_OK; if( pIn->xInput ){ while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){ - int nNew = SESSIONS_STRM_CHUNK_SIZE; + int nNew = sessions_strm_chunk_size; if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn); if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){ @@ -176142,7 +213311,7 @@ static void sessionSkipRecord( /* ** This function sets the value of the sqlite3_value object passed as the -** first argument to a copy of the string or blob held in the aData[] +** first argument to a copy of the string or blob held in the aData[] ** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM ** error occurs. */ @@ -176153,10 +213322,10 @@ static int sessionValueSetStr( u8 enc /* String encoding (0 for blobs) */ ){ /* In theory this code could just pass SQLITE_TRANSIENT as the final - ** argument to sqlite3ValueSetStr() and have the copy created + ** argument to sqlite3ValueSetStr() and have the copy created ** automatically. But doing so makes it difficult to detect any OOM ** error. Hence the code to create the copy externally. */ - u8 *aCopy = sqlite3_malloc(nData+1); + u8 *aCopy = sqlite3_malloc64((sqlite3_int64)nData+1); if( aCopy==0 ) return SQLITE_NOMEM; memcpy(aCopy, aData, nData); sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free); @@ -176191,23 +213360,30 @@ static int sessionReadRecord( SessionInput *pIn, /* Input data */ int nCol, /* Number of values in record */ u8 *abPK, /* Array of primary key flags, or NULL */ - sqlite3_value **apOut /* Write values to this array */ + sqlite3_value **apOut, /* Write values to this array */ + int *pbEmpty ){ int i; /* Used to iterate through columns */ int rc = SQLITE_OK; + assert( pbEmpty==0 || *pbEmpty==0 ); + if( pbEmpty ) *pbEmpty = 1; for(i=0; iaData[pIn->iNext++]; - } - - assert( apOut[i]==0 ); - if( eType ){ - apOut[i] = sqlite3ValueNew(0); - if( !apOut[i] ) rc = SQLITE_NOMEM; + if( pIn->iNext>=pIn->nData ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + eType = pIn->aData[pIn->iNext++]; + assert( apOut[i]==0 ); + if( eType ){ + if( pbEmpty ) *pbEmpty = 0; + apOut[i] = sqlite3ValueNew(0); + if( !apOut[i] ) rc = SQLITE_NOMEM; + } + } } if( rc==SQLITE_OK ){ @@ -176217,10 +213393,14 @@ static int sessionReadRecord( pIn->iNext += sessionVarintGet(aVal, &nByte); rc = sessionInputBuffer(pIn, nByte); if( rc==SQLITE_OK ){ - u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0); - rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc); + if( nByte<0 || nByte>pIn->nData-pIn->iNext ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0); + rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc); + pIn->iNext += nByte; + } } - pIn->iNext += nByte; } if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ sqlite3_int64 v = sessionGetI64(aVal); @@ -176247,7 +213427,7 @@ static int sessionReadRecord( ** + array of PK flags (1 byte per column), ** + table name (nul terminated). ** -** This function ensures that all of the above is present in the input +** This function ensures that all of the above is present in the input ** buffer (i.e. that it can be accessed without any calls to xInput()). ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. ** The input pointer is not moved. @@ -176260,8 +213440,19 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){ rc = sessionInputBuffer(pIn, 9); if( rc==SQLITE_OK ){ nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol); - rc = sessionInputBuffer(pIn, nRead+nCol+100); - nRead += nCol; + /* The hard upper limit for the number of columns in an SQLite + ** database table is, according to sqliteLimit.h, 32676. So + ** consider any table-header that purports to have more than 65536 + ** columns to be corrupt. This is convenient because otherwise, + ** if the (nCol>65536) condition below were omitted, a sufficiently + ** large value for nCol may cause nRead to wrap around and become + ** negative. Leading to a crash. */ + if( nCol<0 || nCol>65536 ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + rc = sessionInputBuffer(pIn, nRead+nCol+100); + nRead += nCol; + } } while( rc==SQLITE_OK ){ @@ -176319,8 +213510,8 @@ static int sessionChangesetBufferRecord( ** + array of PK flags (1 byte per column), ** + table name (nul terminated). ** -** This function decodes the table-header and populates the p->nCol, -** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is +** This function decodes the table-header and populates the p->nCol, +** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is ** also allocated or resized according to the new value of p->nCol. The ** input pointer is left pointing to the byte following the table header. ** @@ -176338,51 +213529,57 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){ int nByte; int nVarint; nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol); - nCopy -= nVarint; - p->in.iNext += nVarint; - nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy; - p->tblhdr.nBuf = 0; - sessionBufferGrow(&p->tblhdr, nByte, &rc); + if( p->nCol>0 ){ + nCopy -= nVarint; + p->in.iNext += nVarint; + nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy; + p->tblhdr.nBuf = 0; + sessionBufferGrow(&p->tblhdr, nByte, &rc); + }else{ + rc = SQLITE_CORRUPT_BKPT; + } } if( rc==SQLITE_OK ){ - int iPK = sizeof(sqlite3_value*)*p->nCol*2; + size_t iPK = sizeof(sqlite3_value*)*p->nCol*2; memset(p->tblhdr.aBuf, 0, iPK); memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy); p->in.iNext += nCopy; } p->apValue = (sqlite3_value**)p->tblhdr.aBuf; - p->abPK = (u8*)&p->apValue[p->nCol*2]; - p->zTab = (char*)&p->abPK[p->nCol]; + if( p->apValue==0 ){ + p->abPK = 0; + p->zTab = 0; + }else{ + p->abPK = (u8*)&p->apValue[p->nCol*2]; + p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0; + } return (p->rc = rc); } /* -** Advance the changeset iterator to the next change. +** Advance the changeset iterator to the next change. The differences between +** this function and sessionChangesetNext() are that ** -** If both paRec and pnRec are NULL, then this function works like the public -** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the -** sqlite3changeset_new() and old() APIs may be used to query for values. -** -** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change -** record is written to *paRec before returning and the number of bytes in -** the record to *pnRec. +** * If pbEmpty is not NULL and the change is a no-op UPDATE (an UPDATE +** that modifies no columns), this function sets (*pbEmpty) to 1. ** -** Either way, this function returns SQLITE_ROW if the iterator is -** successfully advanced to the next change in the changeset, an SQLite -** error code if an error occurs, or SQLITE_DONE if there are no further -** changes in the changeset. +** * If the iterator is configured to skip no-op UPDATEs, +** sessionChangesetNext() does that. This function does not. */ -static int sessionChangesetNext( +static int sessionChangesetNextOne( sqlite3_changeset_iter *p, /* Changeset iterator */ u8 **paRec, /* If non-NULL, store record pointer here */ - int *pnRec /* If non-NULL, store size of record here */ + int *pnRec, /* If non-NULL, store size of record here */ + int *pbNew, /* If non-NULL, true if new table */ + int *pbEmpty ){ int i; u8 op; assert( (paRec==0 && pnRec==0) || (paRec && pnRec) ); + assert( pbEmpty==0 || *pbEmpty==0 ); /* If the iterator is in the error-state, return immediately. */ if( p->rc!=SQLITE_OK ) return p->rc; @@ -176411,21 +213608,30 @@ static int sessionChangesetNext( p->in.iCurrent = p->in.iNext; op = p->in.aData[p->in.iNext++]; - if( op=='T' || op=='P' ){ + while( op=='T' || op=='P' ){ + if( pbNew ) *pbNew = 1; p->bPatchset = (op=='P'); if( sessionChangesetReadTblhdr(p) ) return p->rc; if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc; p->in.iCurrent = p->in.iNext; + if( p->in.iNext>=p->in.nData ) return SQLITE_DONE; op = p->in.aData[p->in.iNext++]; } + if( p->zTab==0 || (p->bPatchset && p->bInvert) ){ + /* The first record in the changeset is not a table header. Must be a + ** corrupt changeset. */ + assert( p->in.iNext==1 || p->zTab ); + return (p->rc = SQLITE_CORRUPT_BKPT); + } + p->op = op; p->bIndirect = p->in.aData[p->in.iNext++]; if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){ return (p->rc = SQLITE_CORRUPT_BKPT); } - if( paRec ){ + if( paRec ){ int nVal; /* Number of values to buffer */ if( p->bPatchset==0 && op==SQLITE_UPDATE ){ nVal = p->nCol * 2; @@ -176440,39 +213646,76 @@ static int sessionChangesetNext( *paRec = &p->in.aData[p->in.iNext]; p->in.iNext += *pnRec; }else{ + sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue); + sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]); /* If this is an UPDATE or DELETE, read the old.* record. */ if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){ u8 *abPK = p->bPatchset ? p->abPK : 0; - p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue); + p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld, 0); if( p->rc!=SQLITE_OK ) return p->rc; } /* If this is an INSERT or UPDATE, read the new.* record. */ if( p->op!=SQLITE_DELETE ){ - p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]); + p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew, pbEmpty); if( p->rc!=SQLITE_OK ) return p->rc; } - if( p->bPatchset && p->op==SQLITE_UPDATE ){ + if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){ /* If this is an UPDATE that is part of a patchset, then all PK and ** modified fields are present in the new.* record. The old.* record ** is currently completely empty. This block shifts the PK fields from ** new.* to old.*, to accommodate the code that reads these arrays. */ for(i=0; inCol; i++){ - assert( p->apValue[i]==0 ); - assert( p->abPK[i]==0 || p->apValue[i+p->nCol] ); + assert( p->bPatchset==0 || p->apValue[i]==0 ); if( p->abPK[i] ){ + assert( p->apValue[i]==0 ); p->apValue[i] = p->apValue[i+p->nCol]; + if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT); p->apValue[i+p->nCol] = 0; } } + }else if( p->bInvert ){ + if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; + else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } } return SQLITE_ROW; } +/* +** Advance the changeset iterator to the next change. +** +** If both paRec and pnRec are NULL, then this function works like the public +** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the +** sqlite3changeset_new() and old() APIs may be used to query for values. +** +** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change +** record is written to *paRec before returning and the number of bytes in +** the record to *pnRec. +** +** Either way, this function returns SQLITE_ROW if the iterator is +** successfully advanced to the next change in the changeset, an SQLite +** error code if an error occurs, or SQLITE_DONE if there are no further +** changes in the changeset. +*/ +static int sessionChangesetNext( + sqlite3_changeset_iter *p, /* Changeset iterator */ + u8 **paRec, /* If non-NULL, store record pointer here */ + int *pnRec, /* If non-NULL, store size of record here */ + int *pbNew /* If non-NULL, true if new table */ +){ + int bEmpty; + int rc; + do { + bEmpty = 0; + rc = sessionChangesetNextOne(p, paRec, pnRec, pbNew, &bEmpty); + }while( rc==SQLITE_ROW && p->bSkipEmpty && bEmpty); + return rc; +} + /* ** Advance an iterator created by sqlite3changeset_start() to the next ** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE @@ -176482,7 +213725,7 @@ static int sessionChangesetNext( ** callback by changeset_apply(). */ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){ - return sessionChangesetNext(p, 0, 0); + return sessionChangesetNext(p, 0, 0, 0); } /* @@ -176586,7 +213829,7 @@ SQLITE_API int sqlite3changeset_new( /* ** This function may only be called with a changeset iterator that has been -** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT +** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT ** conflict-handler function. Otherwise, SQLITE_MISUSE is returned. ** ** If successful, *ppValue is set to point to an sqlite3_value structure @@ -176731,7 +213974,7 @@ static int sessionChangesetInvert( int iCol; if( 0==apVal ){ - apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2); + apVal = (sqlite3_value **)sqlite3_malloc64(sizeof(apVal[0])*nCol*2); if( 0==apVal ){ rc = SQLITE_NOMEM; goto finished_invert; @@ -176745,9 +213988,9 @@ static int sessionChangesetInvert( /* Read the old.* and new.* records for the update change. */ pInput->iNext += 2; - rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]); + rc = sessionReadRecord(pInput, nCol, 0, &apVal[0], 0); if( rc==SQLITE_OK ){ - rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]); + rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol], 0); } /* Write the new old.* record. Consists of the PK columns from the @@ -176783,7 +214026,7 @@ static int sessionChangesetInvert( } assert( rc==SQLITE_OK ); - if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ + if( xOutput && sOut.nBuf>=sessions_strm_chunk_size ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; @@ -176791,11 +214034,11 @@ static int sessionChangesetInvert( } assert( rc==SQLITE_OK ); - if( pnInverted ){ + if( pnInverted && ALWAYS(ppInverted) ){ *pnInverted = sOut.nBuf; *ppInverted = sOut.aBuf; sOut.aBuf = 0; - }else if( sOut.nBuf>0 ){ + }else if( sOut.nBuf>0 && ALWAYS(xOutput!=0) ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } @@ -176848,21 +214091,195 @@ SQLITE_API int sqlite3changeset_invert_strm( return rc; } + +typedef struct SessionUpdate SessionUpdate; +struct SessionUpdate { + sqlite3_stmt *pStmt; + u32 *aMask; + SessionUpdate *pNext; +}; + typedef struct SessionApplyCtx SessionApplyCtx; struct SessionApplyCtx { sqlite3 *db; sqlite3_stmt *pDelete; /* DELETE statement */ - sqlite3_stmt *pUpdate; /* UPDATE statement */ sqlite3_stmt *pInsert; /* INSERT statement */ sqlite3_stmt *pSelect; /* SELECT statement */ int nCol; /* Size of azCol[] and abPK[] arrays */ const char **azCol; /* Array of column names */ u8 *abPK; /* Boolean array - true if column is in PK */ - + u32 *aUpdateMask; /* Used by sessionUpdateFind */ + SessionUpdate *pUp; + int bStat1; /* True if table is sqlite_stat1 */ int bDeferConstraints; /* True to defer constraints */ + int bInvertConstraints; /* Invert when iterating constraints buffer */ SessionBuffer constraints; /* Deferred constraints are stored here */ + SessionBuffer rebase; /* Rebase information (if any) here */ + u8 bRebaseStarted; /* If table header is already in rebase */ + u8 bRebase; /* True to collect rebase information */ }; +/* Number of prepared UPDATE statements to cache. */ +#define SESSION_UPDATE_CACHE_SZ 12 + +/* +** Find a prepared UPDATE statement suitable for the UPDATE step currently +** being visited by the iterator. The UPDATE is of the form: +** +** UPDATE tbl SET col = ?, col2 = ? WHERE pk1 IS ? AND pk2 IS ? +*/ +static int sessionUpdateFind( + sqlite3_changeset_iter *pIter, + SessionApplyCtx *p, + int bPatchset, + sqlite3_stmt **ppStmt +){ + int rc = SQLITE_OK; + SessionUpdate *pUp = 0; + int nCol = pIter->nCol; + int nU32 = (pIter->nCol+33)/32; + int ii; + + if( p->aUpdateMask==0 ){ + p->aUpdateMask = sqlite3_malloc(nU32*sizeof(u32)); + if( p->aUpdateMask==0 ){ + rc = SQLITE_NOMEM; + } + } + + if( rc==SQLITE_OK ){ + memset(p->aUpdateMask, 0, nU32*sizeof(u32)); + rc = SQLITE_CORRUPT; + for(ii=0; iinCol; ii++){ + if( sessionChangesetNew(pIter, ii) ){ + p->aUpdateMask[ii/32] |= (1<<(ii%32)); + rc = SQLITE_OK; + } + } + } + + if( rc==SQLITE_OK ){ + if( bPatchset ) p->aUpdateMask[nCol/32] |= (1<<(nCol%32)); + + if( p->pUp ){ + int nUp = 0; + SessionUpdate **pp = &p->pUp; + while( 1 ){ + nUp++; + if( 0==memcmp(p->aUpdateMask, (*pp)->aMask, nU32*sizeof(u32)) ){ + pUp = *pp; + *pp = pUp->pNext; + pUp->pNext = p->pUp; + p->pUp = pUp; + break; + } + + if( (*pp)->pNext ){ + pp = &(*pp)->pNext; + }else{ + if( nUp>=SESSION_UPDATE_CACHE_SZ ){ + sqlite3_finalize((*pp)->pStmt); + sqlite3_free(*pp); + *pp = 0; + } + break; + } + } + } + + if( pUp==0 ){ + int nByte = sizeof(SessionUpdate) * nU32*sizeof(u32); + int bStat1 = (sqlite3_stricmp(pIter->zTab, "sqlite_stat1")==0); + pUp = (SessionUpdate*)sqlite3_malloc(nByte); + if( pUp==0 ){ + rc = SQLITE_NOMEM; + }else{ + const char *zSep = ""; + SessionBuffer buf; + + memset(&buf, 0, sizeof(buf)); + pUp->aMask = (u32*)&pUp[1]; + memcpy(pUp->aMask, p->aUpdateMask, nU32*sizeof(u32)); + + sessionAppendStr(&buf, "UPDATE main.", &rc); + sessionAppendIdent(&buf, pIter->zTab, &rc); + sessionAppendStr(&buf, " SET ", &rc); + + /* Create the assignments part of the UPDATE */ + for(ii=0; iinCol; ii++){ + if( p->abPK[ii]==0 && sessionChangesetNew(pIter, ii) ){ + sessionAppendStr(&buf, zSep, &rc); + sessionAppendIdent(&buf, p->azCol[ii], &rc); + sessionAppendStr(&buf, " = ?", &rc); + sessionAppendInteger(&buf, ii*2+1, &rc); + zSep = ", "; + } + } + + /* Create the WHERE clause part of the UPDATE */ + zSep = ""; + sessionAppendStr(&buf, " WHERE ", &rc); + for(ii=0; iinCol; ii++){ + if( p->abPK[ii] || (bPatchset==0 && sessionChangesetOld(pIter, ii)) ){ + sessionAppendStr(&buf, zSep, &rc); + if( bStat1 && ii==1 ){ + assert( sqlite3_stricmp(p->azCol[ii], "idx")==0 ); + sessionAppendStr(&buf, + "idx IS CASE " + "WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL " + "ELSE ?4 END ", &rc + ); + }else{ + sessionAppendIdent(&buf, p->azCol[ii], &rc); + sessionAppendStr(&buf, " IS ?", &rc); + sessionAppendInteger(&buf, ii*2+2, &rc); + } + zSep = " AND "; + } + } + + if( rc==SQLITE_OK ){ + char *zSql = (char*)buf.aBuf; + rc = sqlite3_prepare_v2(p->db, zSql, buf.nBuf, &pUp->pStmt, 0); + } + + if( rc!=SQLITE_OK ){ + sqlite3_free(pUp); + pUp = 0; + }else{ + pUp->pNext = p->pUp; + p->pUp = pUp; + } + sqlite3_free(buf.aBuf); + } + } + } + + assert( (rc==SQLITE_OK)==(pUp!=0) ); + if( pUp ){ + *ppStmt = pUp->pStmt; + }else{ + *ppStmt = 0; + } + return rc; +} + +/* +** Free all cached UPDATE statements. +*/ +static void sessionUpdateFree(SessionApplyCtx *p){ + SessionUpdate *pUp; + SessionUpdate *pNext; + for(pUp=p->pUp; pUp; pUp=pNext){ + pNext = pUp->pNext; + sqlite3_finalize(pUp->pStmt); + sqlite3_free(pUp); + } + p->pUp = 0; + sqlite3_free(p->aUpdateMask); + p->aUpdateMask = 0; +} + /* ** Formulate a statement to DELETE a row from database db. Assuming a table ** structure like this: @@ -176891,7 +214308,7 @@ static int sessionDeleteRow( SessionBuffer buf = {0, 0, 0}; int nPk = 0; - sessionAppendStr(&buf, "DELETE FROM ", &rc); + sessionAppendStr(&buf, "DELETE FROM main.", &rc); sessionAppendIdent(&buf, zTab, &rc); sessionAppendStr(&buf, " WHERE ", &rc); @@ -176932,102 +214349,6 @@ static int sessionDeleteRow( return rc; } -/* -** Formulate and prepare a statement to UPDATE a row from database db. -** Assuming a table structure like this: -** -** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); -** -** The UPDATE statement looks like this: -** -** UPDATE x SET -** a = CASE WHEN ?2 THEN ?3 ELSE a END, -** b = CASE WHEN ?5 THEN ?6 ELSE b END, -** c = CASE WHEN ?8 THEN ?9 ELSE c END, -** d = CASE WHEN ?11 THEN ?12 ELSE d END -** WHERE a = ?1 AND c = ?7 AND (?13 OR -** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND -** ) -** -** For each column in the table, there are three variables to bind: -** -** ?(i*3+1) The old.* value of the column, if any. -** ?(i*3+2) A boolean flag indicating that the value is being modified. -** ?(i*3+3) The new.* value of the column, if any. -** -** Also, a boolean flag that, if set to true, causes the statement to update -** a row even if the non-PK values do not match. This is required if the -** conflict-handler is invoked with CHANGESET_DATA and returns -** CHANGESET_REPLACE. This is variable "?(nCol*3+1)". -** -** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left -** pointing to the prepared version of the SQL statement. -*/ -static int sessionUpdateRow( - sqlite3 *db, /* Database handle */ - const char *zTab, /* Table name */ - SessionApplyCtx *p /* Session changeset-apply context */ -){ - int rc = SQLITE_OK; - int i; - const char *zSep = ""; - SessionBuffer buf = {0, 0, 0}; - - /* Append "UPDATE tbl SET " */ - sessionAppendStr(&buf, "UPDATE ", &rc); - sessionAppendIdent(&buf, zTab, &rc); - sessionAppendStr(&buf, " SET ", &rc); - - /* Append the assignments */ - for(i=0; inCol; i++){ - sessionAppendStr(&buf, zSep, &rc); - sessionAppendIdent(&buf, p->azCol[i], &rc); - sessionAppendStr(&buf, " = CASE WHEN ?", &rc); - sessionAppendInteger(&buf, i*3+2, &rc); - sessionAppendStr(&buf, " THEN ?", &rc); - sessionAppendInteger(&buf, i*3+3, &rc); - sessionAppendStr(&buf, " ELSE ", &rc); - sessionAppendIdent(&buf, p->azCol[i], &rc); - sessionAppendStr(&buf, " END", &rc); - zSep = ", "; - } - - /* Append the PK part of the WHERE clause */ - sessionAppendStr(&buf, " WHERE ", &rc); - for(i=0; inCol; i++){ - if( p->abPK[i] ){ - sessionAppendIdent(&buf, p->azCol[i], &rc); - sessionAppendStr(&buf, " = ?", &rc); - sessionAppendInteger(&buf, i*3+1, &rc); - sessionAppendStr(&buf, " AND ", &rc); - } - } - - /* Append the non-PK part of the WHERE clause */ - sessionAppendStr(&buf, " (?", &rc); - sessionAppendInteger(&buf, p->nCol*3+1, &rc); - sessionAppendStr(&buf, " OR 1", &rc); - for(i=0; inCol; i++){ - if( !p->abPK[i] ){ - sessionAppendStr(&buf, " AND (?", &rc); - sessionAppendInteger(&buf, i*3+2, &rc); - sessionAppendStr(&buf, "=0 OR ", &rc); - sessionAppendIdent(&buf, p->azCol[i], &rc); - sessionAppendStr(&buf, " IS ?", &rc); - sessionAppendInteger(&buf, i*3+1, &rc); - sessionAppendStr(&buf, ")", &rc); - } - } - sessionAppendStr(&buf, ")", &rc); - - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0); - } - sqlite3_free(buf.aBuf); - - return rc; -} - /* ** Formulate and prepare an SQL statement to query table zTab by primary ** key. Assuming the following table structure: @@ -177056,3418 +214377,1792 @@ static int sessionSelectRow( ** ** INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...); ** -** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left -** pointing to the prepared version of the SQL statement. -*/ -static int sessionInsertRow( - sqlite3 *db, /* Database handle */ - const char *zTab, /* Table name */ - SessionApplyCtx *p /* Session changeset-apply context */ -){ - int rc = SQLITE_OK; - int i; - SessionBuffer buf = {0, 0, 0}; - - sessionAppendStr(&buf, "INSERT INTO main.", &rc); - sessionAppendIdent(&buf, zTab, &rc); - sessionAppendStr(&buf, "(", &rc); - for(i=0; inCol; i++){ - if( i!=0 ) sessionAppendStr(&buf, ", ", &rc); - sessionAppendIdent(&buf, p->azCol[i], &rc); - } - - sessionAppendStr(&buf, ") VALUES(?", &rc); - for(i=1; inCol; i++){ - sessionAppendStr(&buf, ", ?", &rc); - } - sessionAppendStr(&buf, ")", &rc); - - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0); - } - sqlite3_free(buf.aBuf); - return rc; -} - -/* -** A wrapper around sqlite3_bind_value() that detects an extra problem. -** See comments in the body of this function for details. -*/ -static int sessionBindValue( - sqlite3_stmt *pStmt, /* Statement to bind value to */ - int i, /* Parameter number to bind to */ - sqlite3_value *pVal /* Value to bind */ -){ - int eType = sqlite3_value_type(pVal); - /* COVERAGE: The (pVal->z==0) branch is never true using current versions - ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either - ** the (pVal->z) variable remains as it was or the type of the value is - ** set to SQLITE_NULL. */ - if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){ - /* This condition occurs when an earlier OOM in a call to - ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within - ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */ - return SQLITE_NOMEM; - } - return sqlite3_bind_value(pStmt, i, pVal); -} - -/* -** Iterator pIter must point to an SQLITE_INSERT entry. This function -** transfers new.* values from the current iterator entry to statement -** pStmt. The table being inserted into has nCol columns. -** -** New.* value $i from the iterator is bound to variable ($i+1) of -** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1) -** are transfered to the statement. Otherwise, if abPK is not NULL, it points -** to an array nCol elements in size. In this case only those values for -** which abPK[$i] is true are read from the iterator and bound to the -** statement. -** -** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK. -*/ -static int sessionBindRow( - sqlite3_changeset_iter *pIter, /* Iterator to read values from */ - int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **), - int nCol, /* Number of columns */ - u8 *abPK, /* If not NULL, bind only if true */ - sqlite3_stmt *pStmt /* Bind values to this statement */ -){ - int i; - int rc = SQLITE_OK; - - /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the - ** argument iterator points to a suitable entry. Make sure that xValue - ** is one of these to guarantee that it is safe to ignore the return - ** in the code below. */ - assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); - - for(i=0; rc==SQLITE_OK && idb, pIter, p->abPK, p->pSelect); - }else{ - rc = SQLITE_OK; - } - - if( rc==SQLITE_ROW ){ - /* There exists another row with the new.* primary key. */ - pIter->pConflict = p->pSelect; - res = xConflict(pCtx, eType, pIter); - pIter->pConflict = 0; - rc = sqlite3_reset(p->pSelect); - }else if( rc==SQLITE_OK ){ - if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){ - /* Instead of invoking the conflict handler, append the change blob - ** to the SessionApplyCtx.constraints buffer. */ - u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent]; - int nBlob = pIter->in.iNext - pIter->in.iCurrent; - sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc); - res = SQLITE_CHANGESET_OMIT; - }else{ - /* No other row with the new.* primary key. */ - res = xConflict(pCtx, eType+1, pIter); - if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE; - } - } - - if( rc==SQLITE_OK ){ - switch( res ){ - case SQLITE_CHANGESET_REPLACE: - assert( pbReplace ); - *pbReplace = 1; - break; - - case SQLITE_CHANGESET_OMIT: - break; - - case SQLITE_CHANGESET_ABORT: - rc = SQLITE_ABORT; - break; - - default: - rc = SQLITE_MISUSE; - break; - } - } - - return rc; -} - -/* -** Attempt to apply the change that the iterator passed as the first argument -** currently points to to the database. If a conflict is encountered, invoke -** the conflict handler callback. -** -** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If -** one is encountered, update or delete the row with the matching primary key -** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs, -** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry -** to true before returning. In this case the caller will invoke this function -** again, this time with pbRetry set to NULL. -** -** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is -** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead. -** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such -** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true -** before retrying. In this case the caller attempts to remove the conflicting -** row before invoking this function again, this time with pbReplace set -** to NULL. -** -** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function -** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is -** returned. -*/ -static int sessionApplyOneOp( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - SessionApplyCtx *p, /* changeset_apply() context */ - int(*xConflict)(void *, int, sqlite3_changeset_iter *), - void *pCtx, /* First argument for the conflict handler */ - int *pbReplace, /* OUT: True to remove PK row and retry */ - int *pbRetry /* OUT: True to retry. */ -){ - const char *zDummy; - int op; - int nCol; - int rc = SQLITE_OK; - - assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect ); - assert( p->azCol && p->abPK ); - assert( !pbReplace || *pbReplace==0 ); - - sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); - - if( op==SQLITE_DELETE ){ - - /* Bind values to the DELETE statement. If conflict handling is required, - ** bind values for all columns and set bound variable (nCol+1) to true. - ** Or, if conflict handling is not required, bind just the PK column - ** values and, if it exists, set (nCol+1) to false. Conflict handling - ** is not required if: - ** - ** * this is a patchset, or - ** * (pbRetry==0), or - ** * all columns of the table are PK columns (in this case there is - ** no (nCol+1) variable to bind to). - */ - u8 *abPK = (pIter->bPatchset ? p->abPK : 0); - rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete); - if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){ - rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK)); - } - if( rc!=SQLITE_OK ) return rc; - - sqlite3_step(p->pDelete); - rc = sqlite3_reset(p->pDelete); - if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ - rc = sessionConflictHandler( - SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry - ); - }else if( (rc&0xff)==SQLITE_CONSTRAINT ){ - rc = sessionConflictHandler( - SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 - ); - } - - }else if( op==SQLITE_UPDATE ){ - int i; - - /* Bind values to the UPDATE statement. */ - for(i=0; rc==SQLITE_OK && ipUpdate, i*3+2, !!pNew); - if( pOld ){ - rc = sessionBindValue(p->pUpdate, i*3+1, pOld); - } - if( rc==SQLITE_OK && pNew ){ - rc = sessionBindValue(p->pUpdate, i*3+3, pNew); - } - } - if( rc==SQLITE_OK ){ - sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset); - } - if( rc!=SQLITE_OK ) return rc; - - /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict, - ** the result will be SQLITE_OK with 0 rows modified. */ - sqlite3_step(p->pUpdate); - rc = sqlite3_reset(p->pUpdate); - - if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ - /* A NOTFOUND or DATA error. Search the table to see if it contains - ** a row with a matching primary key. If so, this is a DATA conflict. - ** Otherwise, if there is no primary key match, it is a NOTFOUND. */ - - rc = sessionConflictHandler( - SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry - ); - - }else if( (rc&0xff)==SQLITE_CONSTRAINT ){ - /* This is always a CONSTRAINT conflict. */ - rc = sessionConflictHandler( - SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 - ); - } - - }else{ - assert( op==SQLITE_INSERT ); - rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert); - if( rc!=SQLITE_OK ) return rc; - - sqlite3_step(p->pInsert); - rc = sqlite3_reset(p->pInsert); - if( (rc&0xff)==SQLITE_CONSTRAINT ){ - rc = sessionConflictHandler( - SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace - ); - } - } - - return rc; -} - -/* -** Attempt to apply the change that the iterator passed as the first argument -** currently points to to the database. If a conflict is encountered, invoke -** the conflict handler callback. -** -** The difference between this function and sessionApplyOne() is that this -** function handles the case where the conflict-handler is invoked and -** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be -** retried in some manner. -*/ -static int sessionApplyOneWithRetry( - sqlite3 *db, /* Apply change to "main" db of this handle */ - sqlite3_changeset_iter *pIter, /* Changeset iterator to read change from */ - SessionApplyCtx *pApply, /* Apply context */ - int(*xConflict)(void*, int, sqlite3_changeset_iter*), - void *pCtx /* First argument passed to xConflict */ -){ - int bReplace = 0; - int bRetry = 0; - int rc; - - rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry); - assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) ); - - /* If the bRetry flag is set, the change has not been applied due to an - ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and - ** a row with the correct PK is present in the db, but one or more other - ** fields do not contain the expected values) and the conflict handler - ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation, - ** but pass NULL as the final argument so that sessionApplyOneOp() ignores - ** the SQLITE_CHANGESET_DATA problem. */ - if( bRetry ){ - assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE ); - rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0); - } - - /* If the bReplace flag is set, the change is an INSERT that has not - ** been performed because the database already contains a row with the - ** specified primary key and the conflict handler returned - ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row - ** before reattempting the INSERT. */ - else if( bReplace ){ - assert( pIter->op==SQLITE_INSERT ); - rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0); - if( rc==SQLITE_OK ){ - rc = sessionBindRow(pIter, - sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete); - sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1); - } - if( rc==SQLITE_OK ){ - sqlite3_step(pApply->pDelete); - rc = sqlite3_reset(pApply->pDelete); - } - if( rc==SQLITE_OK ){ - rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0); - } - } - - return rc; -} - -/* -** Retry the changes accumulated in the pApply->constraints buffer. -*/ -static int sessionRetryConstraints( - sqlite3 *db, - int bPatchset, - const char *zTab, - SessionApplyCtx *pApply, - int(*xConflict)(void*, int, sqlite3_changeset_iter*), - void *pCtx /* First argument passed to xConflict */ -){ - int rc = SQLITE_OK; - - while( pApply->constraints.nBuf ){ - sqlite3_changeset_iter *pIter2 = 0; - SessionBuffer cons = pApply->constraints; - memset(&pApply->constraints, 0, sizeof(SessionBuffer)); - - rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf); - if( rc==SQLITE_OK ){ - int nByte = 2*pApply->nCol*sizeof(sqlite3_value*); - int rc2; - pIter2->bPatchset = bPatchset; - pIter2->zTab = (char*)zTab; - pIter2->nCol = pApply->nCol; - pIter2->abPK = pApply->abPK; - sessionBufferGrow(&pIter2->tblhdr, nByte, &rc); - pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf; - if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte); - - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){ - rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx); - } - - rc2 = sqlite3changeset_finalize(pIter2); - if( rc==SQLITE_OK ) rc = rc2; - } - assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 ); - - sqlite3_free(cons.aBuf); - if( rc!=SQLITE_OK ) break; - if( pApply->constraints.nBuf>=cons.nBuf ){ - /* No progress was made on the last round. */ - pApply->bDeferConstraints = 0; - } - } - - return rc; -} - -/* -** Argument pIter is a changeset iterator that has been initialized, but -** not yet passed to sqlite3changeset_next(). This function applies the -** changeset to the main database attached to handle "db". The supplied -** conflict handler callback is invoked to resolve any conflicts encountered -** while applying the change. -*/ -static int sessionChangesetApply( - sqlite3 *db, /* Apply change to "main" db of this handle */ - sqlite3_changeset_iter *pIter, /* Changeset to apply */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of fifth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx /* First argument passed to xConflict */ -){ - int schemaMismatch = 0; - int rc; /* Return code */ - const char *zTab = 0; /* Name of current table */ - int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ - SessionApplyCtx sApply; /* changeset_apply() context object */ - int bPatchset; - - assert( xConflict!=0 ); - - pIter->in.bNoDiscard = 1; - memset(&sApply, 0, sizeof(sApply)); - sqlite3_mutex_enter(sqlite3_db_mutex(db)); - rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0); - } - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){ - int nCol; - int op; - const char *zNew; - - sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0); - - if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){ - u8 *abPK; - - rc = sessionRetryConstraints( - db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx - ); - if( rc!=SQLITE_OK ) break; - - sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ - sqlite3_finalize(sApply.pDelete); - sqlite3_finalize(sApply.pUpdate); - sqlite3_finalize(sApply.pInsert); - sqlite3_finalize(sApply.pSelect); - memset(&sApply, 0, sizeof(sApply)); - sApply.db = db; - sApply.bDeferConstraints = 1; - - /* If an xFilter() callback was specified, invoke it now. If the - ** xFilter callback returns zero, skip this table. If it returns - ** non-zero, proceed. */ - schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew))); - if( schemaMismatch ){ - zTab = sqlite3_mprintf("%s", zNew); - if( zTab==0 ){ - rc = SQLITE_NOMEM; - break; - } - nTab = (int)strlen(zTab); - sApply.azCol = (const char **)zTab; - }else{ - int nMinCol = 0; - int i; - - sqlite3changeset_pk(pIter, &abPK, 0); - rc = sessionTableInfo( - db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK - ); - if( rc!=SQLITE_OK ) break; - for(i=0; ibPatchset; - if( rc==SQLITE_OK ){ - rc = sqlite3changeset_finalize(pIter); - }else{ - sqlite3changeset_finalize(pIter); - } - - if( rc==SQLITE_OK ){ - rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx); - } - - if( rc==SQLITE_OK ){ - int nFk, notUsed; - sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, ¬Used, 0); - if( nFk!=0 ){ - int res = SQLITE_CHANGESET_ABORT; - sqlite3_changeset_iter sIter; - memset(&sIter, 0, sizeof(sIter)); - sIter.nCol = nFk; - res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter); - if( res!=SQLITE_CHANGESET_OMIT ){ - rc = SQLITE_CONSTRAINT; - } - } - } - sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0); - - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); - }else{ - sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0); - sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); - } - - sqlite3_finalize(sApply.pInsert); - sqlite3_finalize(sApply.pDelete); - sqlite3_finalize(sApply.pUpdate); - sqlite3_finalize(sApply.pSelect); - sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ - sqlite3_free((char*)sApply.constraints.aBuf); - sqlite3_mutex_leave(sqlite3_db_mutex(db)); - return rc; -} - -/* -** Apply the changeset passed via pChangeset/nChangeset to the main database -** attached to handle "db". Invoke the supplied conflict handler callback -** to resolve any conflicts encountered while applying the change. -*/ -SQLITE_API int sqlite3changeset_apply( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int nChangeset, /* Size of changeset in bytes */ - void *pChangeset, /* Changeset blob */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of fifth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx /* First argument passed to xConflict */ -){ - sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); - if( rc==SQLITE_OK ){ - rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx); - } - return rc; -} - -/* -** Apply the changeset passed via xInput/pIn to the main database -** attached to handle "db". Invoke the supplied conflict handler callback -** to resolve any conflicts encountered while applying the change. -*/ -SQLITE_API int sqlite3changeset_apply_strm( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ - void *pIn, /* First arg for xInput */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx /* First argument passed to xConflict */ -){ - sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); - if( rc==SQLITE_OK ){ - rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx); - } - return rc; -} - -/* -** sqlite3_changegroup handle. -*/ -struct sqlite3_changegroup { - int rc; /* Error code */ - int bPatch; /* True to accumulate patchsets */ - SessionTable *pList; /* List of tables in current patch */ -}; - -/* -** This function is called to merge two changes to the same row together as -** part of an sqlite3changeset_concat() operation. A new change object is -** allocated and a pointer to it stored in *ppNew. -*/ -static int sessionChangeMerge( - SessionTable *pTab, /* Table structure */ - int bPatchset, /* True for patchsets */ - SessionChange *pExist, /* Existing change */ - int op2, /* Second change operation */ - int bIndirect, /* True if second change is indirect */ - u8 *aRec, /* Second change record */ - int nRec, /* Number of bytes in aRec */ - SessionChange **ppNew /* OUT: Merged change */ -){ - SessionChange *pNew = 0; - - if( !pExist ){ - pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec); - if( !pNew ){ - return SQLITE_NOMEM; - } - memset(pNew, 0, sizeof(SessionChange)); - pNew->op = op2; - pNew->bIndirect = bIndirect; - pNew->nRecord = nRec; - pNew->aRecord = (u8*)&pNew[1]; - memcpy(pNew->aRecord, aRec, nRec); - }else{ - int op1 = pExist->op; - - /* - ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2. - ** op1=INSERT, op2=UPDATE -> INSERT. - ** op1=INSERT, op2=DELETE -> (none) - ** - ** op1=UPDATE, op2=INSERT -> Unsupported. Discard op2. - ** op1=UPDATE, op2=UPDATE -> UPDATE. - ** op1=UPDATE, op2=DELETE -> DELETE. - ** - ** op1=DELETE, op2=INSERT -> UPDATE. - ** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2. - ** op1=DELETE, op2=DELETE -> Unsupported. Discard op2. - */ - if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT) - || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT) - || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE) - || (op1==SQLITE_DELETE && op2==SQLITE_DELETE) - ){ - pNew = pExist; - }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){ - sqlite3_free(pExist); - assert( pNew==0 ); - }else{ - u8 *aExist = pExist->aRecord; - int nByte; - u8 *aCsr; - - /* Allocate a new SessionChange object. Ensure that the aRecord[] - ** buffer of the new object is large enough to hold any record that - ** may be generated by combining the input records. */ - nByte = sizeof(SessionChange) + pExist->nRecord + nRec; - pNew = (SessionChange *)sqlite3_malloc(nByte); - if( !pNew ){ - sqlite3_free(pExist); - return SQLITE_NOMEM; - } - memset(pNew, 0, sizeof(SessionChange)); - pNew->bIndirect = (bIndirect && pExist->bIndirect); - aCsr = pNew->aRecord = (u8 *)&pNew[1]; - - if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */ - u8 *a1 = aRec; - assert( op2==SQLITE_UPDATE ); - pNew->op = SQLITE_INSERT; - if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol); - sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1); - }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */ - assert( op2==SQLITE_INSERT ); - pNew->op = SQLITE_UPDATE; - if( bPatchset ){ - memcpy(aCsr, aRec, nRec); - aCsr += nRec; - }else{ - if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){ - sqlite3_free(pNew); - pNew = 0; - } - } - }else if( op2==SQLITE_UPDATE ){ /* UPDATE + UPDATE */ - u8 *a1 = aExist; - u8 *a2 = aRec; - assert( op1==SQLITE_UPDATE ); - if( bPatchset==0 ){ - sessionSkipRecord(&a1, pTab->nCol); - sessionSkipRecord(&a2, pTab->nCol); - } - pNew->op = SQLITE_UPDATE; - if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){ - sqlite3_free(pNew); - pNew = 0; - } - }else{ /* UPDATE + DELETE */ - assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE ); - pNew->op = SQLITE_DELETE; - if( bPatchset ){ - memcpy(aCsr, aRec, nRec); - aCsr += nRec; - }else{ - sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist); - } - } - - if( pNew ){ - pNew->nRecord = (int)(aCsr - pNew->aRecord); - } - sqlite3_free(pExist); - } - } - - *ppNew = pNew; - return SQLITE_OK; -} - -/* -** Add all changes in the changeset traversed by the iterator passed as -** the first argument to the changegroup hash tables. -*/ -static int sessionChangesetToHash( - sqlite3_changeset_iter *pIter, /* Iterator to read from */ - sqlite3_changegroup *pGrp /* Changegroup object to add changeset to */ -){ - u8 *aRec; - int nRec; - int rc = SQLITE_OK; - SessionTable *pTab = 0; - - - while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){ - const char *zNew; - int nCol; - int op; - int iHash; - int bIndirect; - SessionChange *pChange; - SessionChange *pExist = 0; - SessionChange **pp; - - if( pGrp->pList==0 ){ - pGrp->bPatch = pIter->bPatchset; - }else if( pIter->bPatchset!=pGrp->bPatch ){ - rc = SQLITE_ERROR; - break; - } - - sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect); - if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){ - /* Search the list for a matching table */ - int nNew = (int)strlen(zNew); - u8 *abPK; - - sqlite3changeset_pk(pIter, &abPK, 0); - for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ - if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break; - } - if( !pTab ){ - SessionTable **ppTab; - - pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1); - if( !pTab ){ - rc = SQLITE_NOMEM; - break; - } - memset(pTab, 0, sizeof(SessionTable)); - pTab->nCol = nCol; - pTab->abPK = (u8*)&pTab[1]; - memcpy(pTab->abPK, abPK, nCol); - pTab->zName = (char*)&pTab->abPK[nCol]; - memcpy(pTab->zName, zNew, nNew+1); - - /* The new object must be linked on to the end of the list, not - ** simply added to the start of it. This is to ensure that the - ** tables within the output of sqlite3changegroup_output() are in - ** the right order. */ - for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext); - *ppTab = pTab; - }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ - rc = SQLITE_SCHEMA; - break; - } - } - - if( sessionGrowHash(pIter->bPatchset, pTab) ){ - rc = SQLITE_NOMEM; - break; - } - iHash = sessionChangeHash( - pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange - ); - - /* Search for existing entry. If found, remove it from the hash table. - ** Code below may link it back in. - */ - for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){ - int bPkOnly1 = 0; - int bPkOnly2 = 0; - if( pIter->bPatchset ){ - bPkOnly1 = (*pp)->op==SQLITE_DELETE; - bPkOnly2 = op==SQLITE_DELETE; - } - if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){ - pExist = *pp; - *pp = (*pp)->pNext; - pTab->nEntry--; - break; - } - } - - rc = sessionChangeMerge(pTab, - pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange - ); - if( rc ) break; - if( pChange ){ - pChange->pNext = pTab->apChange[iHash]; - pTab->apChange[iHash] = pChange; - pTab->nEntry++; - } - } - - if( rc==SQLITE_OK ) rc = pIter->rc; - return rc; -} - -/* -** Serialize a changeset (or patchset) based on all changesets (or patchsets) -** added to the changegroup object passed as the first argument. -** -** If xOutput is not NULL, then the changeset/patchset is returned to the -** user via one or more calls to xOutput, as with the other streaming -** interfaces. -** -** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a -** buffer containing the output changeset before this function returns. In -** this case (*pnOut) is set to the size of the output buffer in bytes. It -** is the responsibility of the caller to free the output buffer using -** sqlite3_free() when it is no longer required. -** -** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite -** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut) -** are both set to 0 before returning. +** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left +** pointing to the prepared version of the SQL statement. */ -static int sessionChangegroupOutput( - sqlite3_changegroup *pGrp, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut, - int *pnOut, - void **ppOut +static int sessionInsertRow( + sqlite3 *db, /* Database handle */ + const char *zTab, /* Table name */ + SessionApplyCtx *p /* Session changeset-apply context */ ){ int rc = SQLITE_OK; + int i; SessionBuffer buf = {0, 0, 0}; - SessionTable *pTab; - assert( xOutput==0 || (ppOut==0 && pnOut==0) ); - - /* Create the serialized output changeset based on the contents of the - ** hash tables attached to the SessionTable objects in list p->pList. - */ - for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ - int i; - if( pTab->nEntry==0 ) continue; - sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc); - for(i=0; inChange; i++){ - SessionChange *p; - for(p=pTab->apChange[i]; p; p=p->pNext){ - sessionAppendByte(&buf, p->op, &rc); - sessionAppendByte(&buf, p->bIndirect, &rc); - sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); - } - } + sessionAppendStr(&buf, "INSERT INTO main.", &rc); + sessionAppendIdent(&buf, zTab, &rc); + sessionAppendStr(&buf, "(", &rc); + for(i=0; inCol; i++){ + if( i!=0 ) sessionAppendStr(&buf, ", ", &rc); + sessionAppendIdent(&buf, p->azCol[i], &rc); + } - if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ - rc = xOutput(pOut, buf.aBuf, buf.nBuf); - buf.nBuf = 0; - } + sessionAppendStr(&buf, ") VALUES(?", &rc); + for(i=1; inCol; i++){ + sessionAppendStr(&buf, ", ?", &rc); } + sessionAppendStr(&buf, ")", &rc); if( rc==SQLITE_OK ){ - if( xOutput ){ - if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); - }else{ - *ppOut = buf.aBuf; - *pnOut = buf.nBuf; - buf.aBuf = 0; - } + rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0); } sqlite3_free(buf.aBuf); - return rc; } -/* -** Allocate a new, empty, sqlite3_changegroup. -*/ -SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){ - int rc = SQLITE_OK; /* Return code */ - sqlite3_changegroup *p; /* New object */ - p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup)); - if( p==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(p, 0, sizeof(sqlite3_changegroup)); - } - *pp = p; - return rc; +static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){ + return sqlite3_prepare_v2(db, zSql, -1, pp, 0); } /* -** Add the changeset currently stored in buffer pData, size nData bytes, -** to changeset-group p. +** Prepare statements for applying changes to the sqlite_stat1 table. +** These are similar to those created by sessionSelectRow(), +** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for +** other tables. */ -SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){ - sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */ - int rc; /* Return code */ - - rc = sqlite3changeset_start(&pIter, nData, pData); +static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){ + int rc = sessionSelectRow(db, "sqlite_stat1", p); if( rc==SQLITE_OK ){ - rc = sessionChangesetToHash(pIter, pGrp); + rc = sessionPrepare(db, &p->pInsert, + "INSERT INTO main.sqlite_stat1 VALUES(?1, " + "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, " + "?3)" + ); + } + if( rc==SQLITE_OK ){ + rc = sessionPrepare(db, &p->pDelete, + "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS " + "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END " + "AND (?4 OR stat IS ?3)" + ); } - sqlite3changeset_finalize(pIter); return rc; } /* -** Obtain a buffer containing a changeset representing the concatenation -** of all changesets added to the group so far. +** A wrapper around sqlite3_bind_value() that detects an extra problem. +** See comments in the body of this function for details. */ -SQLITE_API int sqlite3changegroup_output( - sqlite3_changegroup *pGrp, - int *pnData, - void **ppData +static int sessionBindValue( + sqlite3_stmt *pStmt, /* Statement to bind value to */ + int i, /* Parameter number to bind to */ + sqlite3_value *pVal /* Value to bind */ ){ - return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData); + int eType = sqlite3_value_type(pVal); + /* COVERAGE: The (pVal->z==0) branch is never true using current versions + ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either + ** the (pVal->z) variable remains as it was or the type of the value is + ** set to SQLITE_NULL. */ + if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){ + /* This condition occurs when an earlier OOM in a call to + ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within + ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */ + return SQLITE_NOMEM; + } + return sqlite3_bind_value(pStmt, i, pVal); } /* -** Streaming versions of changegroup_add(). +** Iterator pIter must point to an SQLITE_INSERT entry. This function +** transfers new.* values from the current iterator entry to statement +** pStmt. The table being inserted into has nCol columns. +** +** New.* value $i from the iterator is bound to variable ($i+1) of +** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1) +** are transfered to the statement. Otherwise, if abPK is not NULL, it points +** to an array nCol elements in size. In this case only those values for +** which abPK[$i] is true are read from the iterator and bound to the +** statement. +** +** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK. */ -SQLITE_API int sqlite3changegroup_add_strm( - sqlite3_changegroup *pGrp, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn +static int sessionBindRow( + sqlite3_changeset_iter *pIter, /* Iterator to read values from */ + int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **), + int nCol, /* Number of columns */ + u8 *abPK, /* If not NULL, bind only if true */ + sqlite3_stmt *pStmt /* Bind values to this statement */ ){ - sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */ - int rc; /* Return code */ + int i; + int rc = SQLITE_OK; - rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); - if( rc==SQLITE_OK ){ - rc = sessionChangesetToHash(pIter, pGrp); + /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the + ** argument iterator points to a suitable entry. Make sure that xValue + ** is one of these to guarantee that it is safe to ignore the return + ** in the code below. */ + assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); + + for(i=0; rc==SQLITE_OK && ipList); - sqlite3_free(pGrp); - } -} + int rc; /* Return code */ + int nCol; /* Number of columns in table */ + int op; /* Changset operation (SQLITE_UPDATE etc.) */ + const char *zDummy; /* Unused */ -/* -** Combine two changesets together. -*/ -SQLITE_API int sqlite3changeset_concat( - int nLeft, /* Number of bytes in lhs input */ - void *pLeft, /* Lhs input changeset */ - int nRight /* Number of bytes in rhs input */, - void *pRight, /* Rhs input changeset */ - int *pnOut, /* OUT: Number of bytes in output changeset */ - void **ppOut /* OUT: changeset (left right) */ -){ - sqlite3_changegroup *pGrp; - int rc; + sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); + rc = sessionBindRow(pIter, + op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old, + nCol, abPK, pSelect + ); - rc = sqlite3changegroup_new(&pGrp); - if( rc==SQLITE_OK ){ - rc = sqlite3changegroup_add(pGrp, nLeft, pLeft); - } - if( rc==SQLITE_OK ){ - rc = sqlite3changegroup_add(pGrp, nRight, pRight); - } if( rc==SQLITE_OK ){ - rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); + rc = sqlite3_step(pSelect); + if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect); } - sqlite3changegroup_delete(pGrp); return rc; } /* -** Streaming version of sqlite3changeset_concat(). +** This function is called from within sqlite3changeset_apply_v2() when +** a conflict is encountered and resolved using conflict resolution +** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE).. +** It adds a conflict resolution record to the buffer in +** SessionApplyCtx.rebase, which will eventually be returned to the caller +** of apply_v2() as the "rebase" buffer. +** +** Return SQLITE_OK if successful, or an SQLite error code otherwise. */ -SQLITE_API int sqlite3changeset_concat_strm( - int (*xInputA)(void *pIn, void *pData, int *pnData), - void *pInA, - int (*xInputB)(void *pIn, void *pData, int *pnData), - void *pInB, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut +static int sessionRebaseAdd( + SessionApplyCtx *p, /* Apply context */ + int eType, /* Conflict resolution (OMIT or REPLACE) */ + sqlite3_changeset_iter *pIter /* Iterator pointing at current change */ ){ - sqlite3_changegroup *pGrp; - int rc; - - rc = sqlite3changegroup_new(&pGrp); - if( rc==SQLITE_OK ){ - rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA); - } - if( rc==SQLITE_OK ){ - rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB); - } - if( rc==SQLITE_OK ){ - rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut); + int rc = SQLITE_OK; + if( p->bRebase ){ + int i; + int eOp = pIter->op; + if( p->bRebaseStarted==0 ){ + /* Append a table-header to the rebase buffer */ + const char *zTab = pIter->zTab; + sessionAppendByte(&p->rebase, 'T', &rc); + sessionAppendVarint(&p->rebase, p->nCol, &rc); + sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc); + sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc); + p->bRebaseStarted = 1; + } + + assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT ); + assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE ); + + sessionAppendByte(&p->rebase, + (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc + ); + sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc); + for(i=0; inCol; i++){ + sqlite3_value *pVal = 0; + if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){ + sqlite3changeset_old(pIter, i, &pVal); + }else{ + sqlite3changeset_new(pIter, i, &pVal); + } + sessionAppendValue(&p->rebase, pVal, &rc); + } } - sqlite3changegroup_delete(pGrp); - return rc; } -#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ - -/************** End of sqlite3session.c **************************************/ -/************** Begin file json1.c *******************************************/ /* -** 2015-08-12 +** Invoke the conflict handler for the change that the changeset iterator +** currently points to. ** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: +** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT. +** If argument pbReplace is NULL, then the type of conflict handler invoked +** depends solely on eType, as follows: ** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. +** eType value Value passed to xConflict +** ------------------------------------------------- +** CHANGESET_DATA CHANGESET_NOTFOUND +** CHANGESET_CONFLICT CHANGESET_CONSTRAINT ** -****************************************************************************** +** Or, if pbReplace is not NULL, then an attempt is made to find an existing +** record with the same primary key as the record about to be deleted, updated +** or inserted. If such a record can be found, it is available to the conflict +** handler as the "conflicting" record. In this case the type of conflict +** handler invoked is as follows: ** -** This SQLite extension implements JSON functions. The interface is -** modeled after MySQL JSON functions: +** eType value PK Record found? Value passed to xConflict +** ---------------------------------------------------------------- +** CHANGESET_DATA Yes CHANGESET_DATA +** CHANGESET_DATA No CHANGESET_NOTFOUND +** CHANGESET_CONFLICT Yes CHANGESET_CONFLICT +** CHANGESET_CONFLICT No CHANGESET_CONSTRAINT ** -** https://dev.mysql.com/doc/refman/5.7/en/json.html +** If pbReplace is not NULL, and a record with a matching PK is found, and +** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace +** is set to non-zero before returning SQLITE_OK. ** -** For the time being, all JSON is stored as pure text. (We might add -** a JSONB type in the future which stores a binary encoding of JSON in -** a BLOB, but there is no support for JSONB in the current implementation. -** This implementation parses JSON text at 250 MB/s, so it is hard to see -** how JSONB might improve on that.) -*/ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) -#if !defined(SQLITEINT_H) -/* #include "sqlite3ext.h" */ -#endif -SQLITE_EXTENSION_INIT1 -/* #include */ -/* #include */ -/* #include */ -/* #include */ - -/* Mark a function parameter as unused, to suppress nuisance compiler -** warnings. */ -#ifndef UNUSED_PARAM -# define UNUSED_PARAM(X) (void)(X) -#endif - -#ifndef LARGEST_INT64 -# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) -# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64) -#endif - -/* -** Versions of isspace(), isalnum() and isdigit() to which it is safe -** to pass signed char values. -*/ -#ifdef sqlite3Isdigit - /* Use the SQLite core versions if this routine is part of the - ** SQLite amalgamation */ -# define safe_isdigit(x) sqlite3Isdigit(x) -# define safe_isalnum(x) sqlite3Isalnum(x) -# define safe_isxdigit(x) sqlite3Isxdigit(x) -#else - /* Use the standard library for separate compilation */ -#include /* amalgamator: keep */ -# define safe_isdigit(x) isdigit((unsigned char)(x)) -# define safe_isalnum(x) isalnum((unsigned char)(x)) -# define safe_isxdigit(x) isxdigit((unsigned char)(x)) -#endif - -/* -** Growing our own isspace() routine this way is twice as fast as -** the library isspace() function, resulting in a 7% overall performance -** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). -*/ -static const char jsonIsSpace[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 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, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; -#define safe_isspace(x) (jsonIsSpace[(unsigned char)x]) - -#ifndef SQLITE_AMALGAMATION - /* Unsigned integer types. These are already defined in the sqliteInt.h, - ** but the definitions need to be repeated for separate compilation. */ - typedef sqlite3_uint64 u64; - typedef unsigned int u32; - typedef unsigned char u8; -#endif - -/* Objects */ -typedef struct JsonString JsonString; -typedef struct JsonNode JsonNode; -typedef struct JsonParse JsonParse; - -/* An instance of this object represents a JSON string -** under construction. Really, this is a generic string accumulator -** that can be and is used to create strings other than JSON. -*/ -struct JsonString { - sqlite3_context *pCtx; /* Function context - put error messages here */ - char *zBuf; /* Append JSON content here */ - u64 nAlloc; /* Bytes of storage available in zBuf[] */ - u64 nUsed; /* Bytes of zBuf[] currently used */ - u8 bStatic; /* True if zBuf is static space */ - u8 bErr; /* True if an error has been encountered */ - char zSpace[100]; /* Initial static space */ -}; - -/* JSON type values -*/ -#define JSON_NULL 0 -#define JSON_TRUE 1 -#define JSON_FALSE 2 -#define JSON_INT 3 -#define JSON_REAL 4 -#define JSON_STRING 5 -#define JSON_ARRAY 6 -#define JSON_OBJECT 7 - -/* The "subtype" set for JSON values */ -#define JSON_SUBTYPE 74 /* Ascii for "J" */ - -/* -** Names of the various JSON types: -*/ -static const char * const jsonType[] = { - "null", "true", "false", "integer", "real", "text", "array", "object" -}; - -/* Bit values for the JsonNode.jnFlag field -*/ -#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ -#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ -#define JNODE_REMOVE 0x04 /* Do not output */ -#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */ -#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */ -#define JNODE_LABEL 0x20 /* Is a label of an object */ - - -/* A single node of parsed JSON -*/ -struct JsonNode { - u8 eType; /* One of the JSON_ type values */ - u8 jnFlags; /* JNODE flags */ - u8 iVal; /* Replacement value when JNODE_REPLACE */ - u32 n; /* Bytes of content, or number of sub-nodes */ - union { - const char *zJContent; /* Content for INT, REAL, and STRING */ - u32 iAppend; /* More terms for ARRAY and OBJECT */ - u32 iKey; /* Key for ARRAY objects in json_tree() */ - } u; -}; - -/* A completely parsed JSON string +** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is +** returned. Or, if the conflict handler returns an invalid value, +** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT, +** this function returns SQLITE_OK. */ -struct JsonParse { - u32 nNode; /* Number of slots of aNode[] used */ - u32 nAlloc; /* Number of slots of aNode[] allocated */ - JsonNode *aNode; /* Array of nodes containing the parse */ - const char *zJson; /* Original JSON string */ - u32 *aUp; /* Index of parent of each node */ - u8 oom; /* Set to true if out of memory */ - u8 nErr; /* Number of errors seen */ -}; +static int sessionConflictHandler( + int eType, /* Either CHANGESET_DATA or CONFLICT */ + SessionApplyCtx *p, /* changeset_apply() context */ + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int(*xConflict)(void *, int, sqlite3_changeset_iter*), + void *pCtx, /* First argument for conflict handler */ + int *pbReplace /* OUT: Set to true if PK row is found */ +){ + int res = 0; /* Value returned by conflict handler */ + int rc; + int nCol; + int op; + const char *zDummy; -/************************************************************************** -** Utility routines for dealing with JsonString objects -**************************************************************************/ + sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); -/* Set the JsonString object to an empty string -*/ -static void jsonZero(JsonString *p){ - p->zBuf = p->zSpace; - p->nAlloc = sizeof(p->zSpace); - p->nUsed = 0; - p->bStatic = 1; -} + assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA ); + assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT ); + assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND ); -/* Initialize the JsonString object -*/ -static void jsonInit(JsonString *p, sqlite3_context *pCtx){ - p->pCtx = pCtx; - p->bErr = 0; - jsonZero(p); -} + /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ + if( pbReplace ){ + rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect); + }else{ + rc = SQLITE_OK; + } + if( rc==SQLITE_ROW ){ + /* There exists another row with the new.* primary key. */ + pIter->pConflict = p->pSelect; + res = xConflict(pCtx, eType, pIter); + pIter->pConflict = 0; + rc = sqlite3_reset(p->pSelect); + }else if( rc==SQLITE_OK ){ + if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){ + /* Instead of invoking the conflict handler, append the change blob + ** to the SessionApplyCtx.constraints buffer. */ + u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent]; + int nBlob = pIter->in.iNext - pIter->in.iCurrent; + sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc); + return SQLITE_OK; + }else{ + /* No other row with the new.* primary key. */ + res = xConflict(pCtx, eType+1, pIter); + if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE; + } + } -/* Free all allocated memory and reset the JsonString object back to its -** initial state. -*/ -static void jsonReset(JsonString *p){ - if( !p->bStatic ) sqlite3_free(p->zBuf); - jsonZero(p); -} + if( rc==SQLITE_OK ){ + switch( res ){ + case SQLITE_CHANGESET_REPLACE: + assert( pbReplace ); + *pbReplace = 1; + break; + case SQLITE_CHANGESET_OMIT: + break; -/* Report an out-of-memory (OOM) condition -*/ -static void jsonOom(JsonString *p){ - p->bErr = 1; - sqlite3_result_error_nomem(p->pCtx); - jsonReset(p); -} + case SQLITE_CHANGESET_ABORT: + rc = SQLITE_ABORT; + break; -/* Enlarge pJson->zBuf so that it can hold at least N more bytes. -** Return zero on success. Return non-zero on an OOM error -*/ -static int jsonGrow(JsonString *p, u32 N){ - u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; - char *zNew; - if( p->bStatic ){ - if( p->bErr ) return 1; - zNew = sqlite3_malloc64(nTotal); - if( zNew==0 ){ - jsonOom(p); - return SQLITE_NOMEM; + default: + rc = SQLITE_MISUSE; + break; } - memcpy(zNew, p->zBuf, (size_t)p->nUsed); - p->zBuf = zNew; - p->bStatic = 0; - }else{ - zNew = sqlite3_realloc64(p->zBuf, nTotal); - if( zNew==0 ){ - jsonOom(p); - return SQLITE_NOMEM; + if( rc==SQLITE_OK ){ + rc = sessionRebaseAdd(p, res, pIter); } - p->zBuf = zNew; } - p->nAlloc = nTotal; - return SQLITE_OK; -} -/* Append N bytes from zIn onto the end of the JsonString string. -*/ -static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ - if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; - memcpy(p->zBuf+p->nUsed, zIn, N); - p->nUsed += N; + return rc; } -/* Append formatted text (not to exceed N bytes) to the JsonString. +/* +** Attempt to apply the change that the iterator passed as the first argument +** currently points to to the database. If a conflict is encountered, invoke +** the conflict handler callback. +** +** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If +** one is encountered, update or delete the row with the matching primary key +** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs, +** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry +** to true before returning. In this case the caller will invoke this function +** again, this time with pbRetry set to NULL. +** +** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is +** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead. +** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such +** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true +** before retrying. In this case the caller attempts to remove the conflicting +** row before invoking this function again, this time with pbReplace set +** to NULL. +** +** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function +** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is +** returned. */ -static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ - va_list ap; - if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; - va_start(ap, zFormat); - sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); - va_end(ap); - p->nUsed += (int)strlen(p->zBuf+p->nUsed); -} +static int sessionApplyOneOp( + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + SessionApplyCtx *p, /* changeset_apply() context */ + int(*xConflict)(void *, int, sqlite3_changeset_iter *), + void *pCtx, /* First argument for the conflict handler */ + int *pbReplace, /* OUT: True to remove PK row and retry */ + int *pbRetry /* OUT: True to retry. */ +){ + const char *zDummy; + int op; + int nCol; + int rc = SQLITE_OK; -/* Append a single character -*/ -static void jsonAppendChar(JsonString *p, char c){ - if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; - p->zBuf[p->nUsed++] = c; -} + assert( p->pDelete && p->pInsert && p->pSelect ); + assert( p->azCol && p->abPK ); + assert( !pbReplace || *pbReplace==0 ); -/* Append a comma separator to the output buffer, if the previous -** character is not '[' or '{'. -*/ -static void jsonAppendSeparator(JsonString *p){ - char c; - if( p->nUsed==0 ) return; - c = p->zBuf[p->nUsed-1]; - if( c!='[' && c!='{' ) jsonAppendChar(p, ','); -} + sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); -/* Append the N-byte string in zIn to the end of the JsonString string -** under construction. Enclose the string in "..." and escape -** any double-quotes or backslash characters contained within the -** string. -*/ -static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ - u32 i; - if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; - p->zBuf[p->nUsed++] = '"'; - for(i=0; inUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; - p->zBuf[p->nUsed++] = '\\'; - }else if( c<=0x1f ){ - static const char aSpecial[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - assert( sizeof(aSpecial)==32 ); - assert( aSpecial['\b']=='b' ); - assert( aSpecial['\f']=='f' ); - assert( aSpecial['\n']=='n' ); - assert( aSpecial['\r']=='r' ); - assert( aSpecial['\t']=='t' ); - if( aSpecial[c] ){ - c = aSpecial[c]; - goto json_simple_escape; - } - if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; - p->zBuf[p->nUsed++] = '\\'; - p->zBuf[p->nUsed++] = 'u'; - p->zBuf[p->nUsed++] = '0'; - p->zBuf[p->nUsed++] = '0'; - p->zBuf[p->nUsed++] = '0' + (c>>4); - c = "0123456789abcdef"[c&0xf]; - } - p->zBuf[p->nUsed++] = c; - } - p->zBuf[p->nUsed++] = '"'; - assert( p->nUsednAlloc ); -} + if( op==SQLITE_DELETE ){ -/* -** Append a function parameter value to the JSON string under -** construction. -*/ -static void jsonAppendValue( - JsonString *p, /* Append to this JSON string */ - sqlite3_value *pValue /* Value to append */ -){ - switch( sqlite3_value_type(pValue) ){ - case SQLITE_NULL: { - jsonAppendRaw(p, "null", 4); - break; - } - case SQLITE_INTEGER: - case SQLITE_FLOAT: { - const char *z = (const char*)sqlite3_value_text(pValue); - u32 n = (u32)sqlite3_value_bytes(pValue); - jsonAppendRaw(p, z, n); - break; - } - case SQLITE_TEXT: { - const char *z = (const char*)sqlite3_value_text(pValue); - u32 n = (u32)sqlite3_value_bytes(pValue); - if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ - jsonAppendRaw(p, z, n); - }else{ - jsonAppendString(p, z, n); - } - break; - } - default: { - if( p->bErr==0 ){ - sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); - p->bErr = 2; - jsonReset(p); - } - break; + /* Bind values to the DELETE statement. If conflict handling is required, + ** bind values for all columns and set bound variable (nCol+1) to true. + ** Or, if conflict handling is not required, bind just the PK column + ** values and, if it exists, set (nCol+1) to false. Conflict handling + ** is not required if: + ** + ** * this is a patchset, or + ** * (pbRetry==0), or + ** * all columns of the table are PK columns (in this case there is + ** no (nCol+1) variable to bind to). + */ + u8 *abPK = (pIter->bPatchset ? p->abPK : 0); + rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete); + if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){ + rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK)); } - } -} - - -/* Make the JSON in p the result of the SQL function. -*/ -static void jsonResult(JsonString *p){ - if( p->bErr==0 ){ - sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, - p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, - SQLITE_UTF8); - jsonZero(p); - } - assert( p->bStatic ); -} + if( rc!=SQLITE_OK ) return rc; -/************************************************************************** -** Utility routines for dealing with JsonNode and JsonParse objects -**************************************************************************/ + sqlite3_step(p->pDelete); + rc = sqlite3_reset(p->pDelete); + if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ + rc = sessionConflictHandler( + SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry + ); + }else if( (rc&0xff)==SQLITE_CONSTRAINT ){ + rc = sessionConflictHandler( + SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 + ); + } -/* -** Return the number of consecutive JsonNode slots need to represent -** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and -** OBJECT types, the number might be larger. -** -** Appended elements are not counted. The value returned is the number -** by which the JsonNode counter should increment in order to go to the -** next peer value. -*/ -static u32 jsonNodeSize(JsonNode *pNode){ - return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; -} + }else if( op==SQLITE_UPDATE ){ + int i; + sqlite3_stmt *pUp = 0; + int bPatchset = (pbRetry==0 || pIter->bPatchset); -/* -** Reclaim all memory allocated by a JsonParse object. But do not -** delete the JsonParse object itself. -*/ -static void jsonParseReset(JsonParse *pParse){ - sqlite3_free(pParse->aNode); - pParse->aNode = 0; - pParse->nNode = 0; - pParse->nAlloc = 0; - sqlite3_free(pParse->aUp); - pParse->aUp = 0; -} + rc = sessionUpdateFind(pIter, p, bPatchset, &pUp); -/* -** Convert the JsonNode pNode into a pure JSON string and -** append to pOut. Subsubstructure is also included. Return -** the number of JsonNode objects that are encoded. -*/ -static void jsonRenderNode( - JsonNode *pNode, /* The node to render */ - JsonString *pOut, /* Write JSON here */ - sqlite3_value **aReplace /* Replacement values */ -){ - switch( pNode->eType ){ - default: { - assert( pNode->eType==JSON_NULL ); - jsonAppendRaw(pOut, "null", 4); - break; - } - case JSON_TRUE: { - jsonAppendRaw(pOut, "true", 4); - break; - } - case JSON_FALSE: { - jsonAppendRaw(pOut, "false", 5); - break; - } - case JSON_STRING: { - if( pNode->jnFlags & JNODE_RAW ){ - jsonAppendString(pOut, pNode->u.zJContent, pNode->n); - break; - } - /* Fall through into the next case */ - } - case JSON_REAL: - case JSON_INT: { - jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); - break; - } - case JSON_ARRAY: { - u32 j = 1; - jsonAppendChar(pOut, '['); - for(;;){ - while( j<=pNode->n ){ - if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){ - if( pNode[j].jnFlags & JNODE_REPLACE ){ - jsonAppendSeparator(pOut); - jsonAppendValue(pOut, aReplace[pNode[j].iVal]); - } - }else{ - jsonAppendSeparator(pOut); - jsonRenderNode(&pNode[j], pOut, aReplace); - } - j += jsonNodeSize(&pNode[j]); - } - if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; - pNode = &pNode[pNode->u.iAppend]; - j = 1; + /* Bind values to the UPDATE statement. */ + for(i=0; rc==SQLITE_OK && iabPK[i] || (bPatchset==0 && pOld) ){ + rc = sessionBindValue(pUp, i*2+2, pOld); } - jsonAppendChar(pOut, ']'); - break; - } - case JSON_OBJECT: { - u32 j = 1; - jsonAppendChar(pOut, '{'); - for(;;){ - while( j<=pNode->n ){ - if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){ - jsonAppendSeparator(pOut); - jsonRenderNode(&pNode[j], pOut, aReplace); - jsonAppendChar(pOut, ':'); - if( pNode[j+1].jnFlags & JNODE_REPLACE ){ - jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]); - }else{ - jsonRenderNode(&pNode[j+1], pOut, aReplace); - } - } - j += 1 + jsonNodeSize(&pNode[j+1]); - } - if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; - pNode = &pNode[pNode->u.iAppend]; - j = 1; + if( rc==SQLITE_OK && pNew ){ + rc = sessionBindValue(pUp, i*2+1, pNew); } - jsonAppendChar(pOut, '}'); - break; } - } -} + if( rc!=SQLITE_OK ) return rc; -/* -** Return a JsonNode and all its descendents as a JSON string. -*/ -static void jsonReturnJson( - JsonNode *pNode, /* Node to return */ - sqlite3_context *pCtx, /* Return value for this function */ - sqlite3_value **aReplace /* Array of replacement values */ -){ - JsonString s; - jsonInit(&s, pCtx); - jsonRenderNode(pNode, &s, aReplace); - jsonResult(&s); - sqlite3_result_subtype(pCtx, JSON_SUBTYPE); -} + /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict, + ** the result will be SQLITE_OK with 0 rows modified. */ + sqlite3_step(pUp); + rc = sqlite3_reset(pUp); -/* -** Make the JsonNode the return value of the function. -*/ -static void jsonReturn( - JsonNode *pNode, /* Node to return */ - sqlite3_context *pCtx, /* Return value for this function */ - sqlite3_value **aReplace /* Array of replacement values */ -){ - switch( pNode->eType ){ - default: { - assert( pNode->eType==JSON_NULL ); - sqlite3_result_null(pCtx); - break; - } - case JSON_TRUE: { - sqlite3_result_int(pCtx, 1); - break; - } - case JSON_FALSE: { - sqlite3_result_int(pCtx, 0); - break; - } - case JSON_INT: { - sqlite3_int64 i = 0; - const char *z = pNode->u.zJContent; - if( z[0]=='-' ){ z++; } - while( z[0]>='0' && z[0]<='9' ){ - unsigned v = *(z++) - '0'; - if( i>=LARGEST_INT64/10 ){ - if( i>LARGEST_INT64/10 ) goto int_as_real; - if( z[0]>='0' && z[0]<='9' ) goto int_as_real; - if( v==9 ) goto int_as_real; - if( v==8 ){ - if( pNode->u.zJContent[0]=='-' ){ - sqlite3_result_int64(pCtx, SMALLEST_INT64); - goto int_done; - }else{ - goto int_as_real; - } - } - } - i = i*10 + v; - } - if( pNode->u.zJContent[0]=='-' ){ i = -i; } - sqlite3_result_int64(pCtx, i); - int_done: - break; - int_as_real: /* fall through to real */; - } - case JSON_REAL: { - double r; -#ifdef SQLITE_AMALGAMATION - const char *z = pNode->u.zJContent; - sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); -#else - r = strtod(pNode->u.zJContent, 0); -#endif - sqlite3_result_double(pCtx, r); - break; + if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){ + /* A NOTFOUND or DATA error. Search the table to see if it contains + ** a row with a matching primary key. If so, this is a DATA conflict. + ** Otherwise, if there is no primary key match, it is a NOTFOUND. */ + + rc = sessionConflictHandler( + SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry + ); + + }else if( (rc&0xff)==SQLITE_CONSTRAINT ){ + /* This is always a CONSTRAINT conflict. */ + rc = sessionConflictHandler( + SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 + ); } - case JSON_STRING: { -#if 0 /* Never happens because JNODE_RAW is only set by json_set(), - ** json_insert() and json_replace() and those routines do not - ** call jsonReturn() */ - if( pNode->jnFlags & JNODE_RAW ){ - sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, - SQLITE_TRANSIENT); - }else -#endif - assert( (pNode->jnFlags & JNODE_RAW)==0 ); - if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ - /* JSON formatted without any backslash-escapes */ - sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, - SQLITE_TRANSIENT); - }else{ - /* Translate JSON formatted string into raw text */ - u32 i; - u32 n = pNode->n; - const char *z = pNode->u.zJContent; - char *zOut; - u32 j; - zOut = sqlite3_malloc( n+1 ); - if( zOut==0 ){ - sqlite3_result_error_nomem(pCtx); - break; - } - for(i=1, j=0; i>6)); - zOut[j++] = 0x80 | (v&0x3f); - }else{ - zOut[j++] = (char)(0xe0 | (v>>12)); - zOut[j++] = 0x80 | ((v>>6)&0x3f); - zOut[j++] = 0x80 | (v&0x3f); - } - }else{ - if( c=='b' ){ - c = '\b'; - }else if( c=='f' ){ - c = '\f'; - }else if( c=='n' ){ - c = '\n'; - }else if( c=='r' ){ - c = '\r'; - }else if( c=='t' ){ - c = '\t'; - } - zOut[j++] = c; - } - } - } - zOut[j] = 0; - sqlite3_result_text(pCtx, zOut, j, sqlite3_free); + + }else{ + assert( op==SQLITE_INSERT ); + if( p->bStat1 ){ + /* Check if there is a conflicting row. For sqlite_stat1, this needs + ** to be done using a SELECT, as there is no PRIMARY KEY in the + ** database schema to throw an exception if a duplicate is inserted. */ + rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect); + if( rc==SQLITE_ROW ){ + rc = SQLITE_CONSTRAINT; + sqlite3_reset(p->pSelect); } - break; - } - case JSON_ARRAY: - case JSON_OBJECT: { - jsonReturnJson(pNode, pCtx, aReplace); - break; } - } -} - -/* Forward reference */ -static int jsonParseAddNode(JsonParse*,u32,u32,const char*); - -/* -** A macro to hint to the compiler that a function should not be -** inlined. -*/ -#if defined(__GNUC__) -# define JSON_NOINLINE __attribute__((noinline)) -#elif defined(_MSC_VER) && _MSC_VER>=1310 -# define JSON_NOINLINE __declspec(noinline) -#else -# define JSON_NOINLINE -#endif + if( rc==SQLITE_OK ){ + rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert); + if( rc!=SQLITE_OK ) return rc; -static JSON_NOINLINE int jsonParseAddNodeExpand( - JsonParse *pParse, /* Append the node to this object */ - u32 eType, /* Node type */ - u32 n, /* Content size or sub-node count */ - const char *zContent /* Content */ -){ - u32 nNew; - JsonNode *pNew; - assert( pParse->nNode>=pParse->nAlloc ); - if( pParse->oom ) return -1; - nNew = pParse->nAlloc*2 + 10; - pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); - if( pNew==0 ){ - pParse->oom = 1; - return -1; - } - pParse->nAlloc = nNew; - pParse->aNode = pNew; - assert( pParse->nNodenAlloc ); - return jsonParseAddNode(pParse, eType, n, zContent); -} + sqlite3_step(p->pInsert); + rc = sqlite3_reset(p->pInsert); + } -/* -** Create a new JsonNode instance based on the arguments and append that -** instance to the JsonParse. Return the index in pParse->aNode[] of the -** new node, or -1 if a memory allocation fails. -*/ -static int jsonParseAddNode( - JsonParse *pParse, /* Append the node to this object */ - u32 eType, /* Node type */ - u32 n, /* Content size or sub-node count */ - const char *zContent /* Content */ -){ - JsonNode *p; - if( pParse->nNode>=pParse->nAlloc ){ - return jsonParseAddNodeExpand(pParse, eType, n, zContent); + if( (rc&0xff)==SQLITE_CONSTRAINT ){ + rc = sessionConflictHandler( + SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace + ); + } } - p = &pParse->aNode[pParse->nNode]; - p->eType = (u8)eType; - p->jnFlags = 0; - p->iVal = 0; - p->n = n; - p->u.zJContent = zContent; - return pParse->nNode++; -} -/* -** Return true if z[] begins with 4 (or more) hexadecimal digits -*/ -static int jsonIs4Hex(const char *z){ - int i; - for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0; - return 1; + return rc; } /* -** Parse a single JSON value which begins at pParse->zJson[i]. Return the -** index of the first character past the end of the value parsed. +** Attempt to apply the change that the iterator passed as the first argument +** currently points to to the database. If a conflict is encountered, invoke +** the conflict handler callback. ** -** Return negative for a syntax error. Special cases: return -2 if the -** first non-whitespace character is '}' and return -3 if the first -** non-whitespace character is ']'. +** The difference between this function and sessionApplyOne() is that this +** function handles the case where the conflict-handler is invoked and +** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be +** retried in some manner. */ -static int jsonParseValue(JsonParse *pParse, u32 i){ - char c; - u32 j; - int iThis; - int x; - JsonNode *pNode; - while( safe_isspace(pParse->zJson[i]) ){ i++; } - if( (c = pParse->zJson[i])=='{' ){ - /* Parse object */ - iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); - if( iThis<0 ) return -1; - for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } - x = jsonParseValue(pParse, j); - if( x<0 ){ - if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; - return -1; - } - if( pParse->oom ) return -1; - pNode = &pParse->aNode[pParse->nNode-1]; - if( pNode->eType!=JSON_STRING ) return -1; - pNode->jnFlags |= JNODE_LABEL; - j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - if( pParse->zJson[j]!=':' ) return -1; - j++; - x = jsonParseValue(pParse, j); - if( x<0 ) return -1; - j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; - if( c==',' ) continue; - if( c!='}' ) return -1; - break; +static int sessionApplyOneWithRetry( + sqlite3 *db, /* Apply change to "main" db of this handle */ + sqlite3_changeset_iter *pIter, /* Changeset iterator to read change from */ + SessionApplyCtx *pApply, /* Apply context */ + int(*xConflict)(void*, int, sqlite3_changeset_iter*), + void *pCtx /* First argument passed to xConflict */ +){ + int bReplace = 0; + int bRetry = 0; + int rc; + + rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry); + if( rc==SQLITE_OK ){ + /* If the bRetry flag is set, the change has not been applied due to an + ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and + ** a row with the correct PK is present in the db, but one or more other + ** fields do not contain the expected values) and the conflict handler + ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation, + ** but pass NULL as the final argument so that sessionApplyOneOp() ignores + ** the SQLITE_CHANGESET_DATA problem. */ + if( bRetry ){ + assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE ); + rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0); } - pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; - return j+1; - }else if( c=='[' ){ - /* Parse array */ - iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); - if( iThis<0 ) return -1; - for(j=i+1;;j++){ - while( safe_isspace(pParse->zJson[j]) ){ j++; } - x = jsonParseValue(pParse, j); - if( x<0 ){ - if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; - return -1; + + /* If the bReplace flag is set, the change is an INSERT that has not + ** been performed because the database already contains a row with the + ** specified primary key and the conflict handler returned + ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row + ** before reattempting the INSERT. */ + else if( bReplace ){ + assert( pIter->op==SQLITE_INSERT ); + rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = sessionBindRow(pIter, + sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete); + sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1); } - j = x; - while( safe_isspace(pParse->zJson[j]) ){ j++; } - c = pParse->zJson[j]; - if( c==',' ) continue; - if( c!=']' ) return -1; - break; - } - pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; - return j+1; - }else if( c=='"' ){ - /* Parse string */ - u8 jnFlags = 0; - j = i+1; - for(;;){ - c = pParse->zJson[j]; - if( c==0 ) return -1; - if( c=='\\' ){ - c = pParse->zJson[++j]; - if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' - || c=='n' || c=='r' || c=='t' - || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){ - jnFlags = JNODE_ESCAPE; - }else{ - return -1; - } - }else if( c=='"' ){ - break; + if( rc==SQLITE_OK ){ + sqlite3_step(pApply->pDelete); + rc = sqlite3_reset(pApply->pDelete); } - j++; - } - jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]); - if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; - return j+1; - }else if( c=='n' - && strncmp(pParse->zJson+i,"null",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ - jsonParseAddNode(pParse, JSON_NULL, 0, 0); - return i+4; - }else if( c=='t' - && strncmp(pParse->zJson+i,"true",4)==0 - && !safe_isalnum(pParse->zJson[i+4]) ){ - jsonParseAddNode(pParse, JSON_TRUE, 0, 0); - return i+4; - }else if( c=='f' - && strncmp(pParse->zJson+i,"false",5)==0 - && !safe_isalnum(pParse->zJson[i+5]) ){ - jsonParseAddNode(pParse, JSON_FALSE, 0, 0); - return i+5; - }else if( c=='-' || (c>='0' && c<='9') ){ - /* Parse number */ - u8 seenDP = 0; - u8 seenE = 0; - j = i+1; - for(;; j++){ - c = pParse->zJson[j]; - if( c>='0' && c<='9' ) continue; - if( c=='.' ){ - if( pParse->zJson[j-1]=='-' ) return -1; - if( seenDP ) return -1; - seenDP = 1; - continue; + if( rc==SQLITE_OK ){ + rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0); } - if( c=='e' || c=='E' ){ - if( pParse->zJson[j-1]<'0' ) return -1; - if( seenE ) return -1; - seenDP = seenE = 1; - c = pParse->zJson[j+1]; - if( c=='+' || c=='-' ){ - j++; - c = pParse->zJson[j+1]; - } - if( c<'0' || c>'9' ) return -1; - continue; + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0); } - break; } - if( pParse->zJson[j-1]<'0' ) return -1; - jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, - j - i, &pParse->zJson[i]); - return j; - }else if( c=='}' ){ - return -2; /* End of {...} */ - }else if( c==']' ){ - return -3; /* End of [...] */ - }else if( c==0 ){ - return 0; /* End of file */ - }else{ - return -1; /* Syntax error */ } + + return rc; } /* -** Parse a complete JSON string. Return 0 on success or non-zero if there -** are any errors. If an error occurs, free all memory associated with -** pParse. -** -** pParse is uninitialized when this routine is called. +** Retry the changes accumulated in the pApply->constraints buffer. */ -static int jsonParse( - JsonParse *pParse, /* Initialize and fill this JsonParse object */ - sqlite3_context *pCtx, /* Report errors here */ - const char *zJson /* Input JSON text to be parsed */ +static int sessionRetryConstraints( + sqlite3 *db, + int bPatchset, + const char *zTab, + SessionApplyCtx *pApply, + int(*xConflict)(void*, int, sqlite3_changeset_iter*), + void *pCtx /* First argument passed to xConflict */ ){ - int i; - memset(pParse, 0, sizeof(*pParse)); - if( zJson==0 ) return 1; - pParse->zJson = zJson; - i = jsonParseValue(pParse, 0); - if( pParse->oom ) i = -1; - if( i>0 ){ - while( safe_isspace(zJson[i]) ) i++; - if( zJson[i] ) i = -1; - } - if( i<=0 ){ - if( pCtx!=0 ){ - if( pParse->oom ){ - sqlite3_result_error_nomem(pCtx); - }else{ - sqlite3_result_error(pCtx, "malformed JSON", -1); + int rc = SQLITE_OK; + + while( pApply->constraints.nBuf ){ + sqlite3_changeset_iter *pIter2 = 0; + SessionBuffer cons = pApply->constraints; + memset(&pApply->constraints, 0, sizeof(SessionBuffer)); + + rc = sessionChangesetStart( + &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints, 1 + ); + if( rc==SQLITE_OK ){ + size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*); + int rc2; + pIter2->bPatchset = bPatchset; + pIter2->zTab = (char*)zTab; + pIter2->nCol = pApply->nCol; + pIter2->abPK = pApply->abPK; + sessionBufferGrow(&pIter2->tblhdr, nByte, &rc); + pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf; + if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte); + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){ + rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx); } + + rc2 = sqlite3changeset_finalize(pIter2); + if( rc==SQLITE_OK ) rc = rc2; + } + assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 ); + + sqlite3_free(cons.aBuf); + if( rc!=SQLITE_OK ) break; + if( pApply->constraints.nBuf>=cons.nBuf ){ + /* No progress was made on the last round. */ + pApply->bDeferConstraints = 0; } - jsonParseReset(pParse); - return 1; } - return 0; + + return rc; } -/* Mark node i of pParse as being a child of iParent. Call recursively -** to fill in all the descendants of node i. +/* +** Argument pIter is a changeset iterator that has been initialized, but +** not yet passed to sqlite3changeset_next(). This function applies the +** changeset to the main database attached to handle "db". The supplied +** conflict handler callback is invoked to resolve any conflicts encountered +** while applying the change. */ -static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ - JsonNode *pNode = &pParse->aNode[i]; - u32 j; - pParse->aUp[i] = iParent; - switch( pNode->eType ){ - case JSON_ARRAY: { - for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ - jsonParseFillInParentage(pParse, i+j, i); +static int sessionChangesetApply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + sqlite3_changeset_iter *pIter, /* Changeset to apply */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of fifth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, /* OUT: Rebase information */ + int flags /* SESSION_APPLY_XXX flags */ +){ + int schemaMismatch = 0; + int rc = SQLITE_OK; /* Return code */ + const char *zTab = 0; /* Name of current table */ + int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ + SessionApplyCtx sApply; /* changeset_apply() context object */ + int bPatchset; + + assert( xConflict!=0 ); + + pIter->in.bNoDiscard = 1; + memset(&sApply, 0, sizeof(sApply)); + sApply.bRebase = (ppRebase && pnRebase); + sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ + rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0); + } + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){ + int nCol; + int op; + const char *zNew; + + sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0); + + if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){ + u8 *abPK; + + rc = sessionRetryConstraints( + db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx + ); + if( rc!=SQLITE_OK ) break; + + sessionUpdateFree(&sApply); + sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ + sqlite3_finalize(sApply.pDelete); + sqlite3_finalize(sApply.pInsert); + sqlite3_finalize(sApply.pSelect); + sApply.db = db; + sApply.pDelete = 0; + sApply.pInsert = 0; + sApply.pSelect = 0; + sApply.nCol = 0; + sApply.azCol = 0; + sApply.abPK = 0; + sApply.bStat1 = 0; + sApply.bDeferConstraints = 1; + sApply.bRebaseStarted = 0; + memset(&sApply.constraints, 0, sizeof(SessionBuffer)); + + /* If an xFilter() callback was specified, invoke it now. If the + ** xFilter callback returns zero, skip this table. If it returns + ** non-zero, proceed. */ + schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew))); + if( schemaMismatch ){ + zTab = sqlite3_mprintf("%s", zNew); + if( zTab==0 ){ + rc = SQLITE_NOMEM; + break; + } + nTab = (int)strlen(zTab); + sApply.azCol = (const char **)zTab; + }else{ + int nMinCol = 0; + int i; + + sqlite3changeset_pk(pIter, &abPK, 0); + rc = sessionTableInfo(0, + db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK + ); + if( rc!=SQLITE_OK ) break; + for(i=0; in; j += jsonNodeSize(pNode+j+1)+1){ - pParse->aUp[i+j] = i; - jsonParseFillInParentage(pParse, i+j+1, i); + + /* If there is a schema mismatch on the current table, proceed to the + ** next change. A log message has already been issued. */ + if( schemaMismatch ) continue; + + rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx); + } + + bPatchset = pIter->bPatchset; + if( rc==SQLITE_OK ){ + rc = sqlite3changeset_finalize(pIter); + }else{ + sqlite3changeset_finalize(pIter); + } + + if( rc==SQLITE_OK ){ + rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx); + } + + if( rc==SQLITE_OK ){ + int nFk, notUsed; + sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, ¬Used, 0); + if( nFk!=0 ){ + int res = SQLITE_CHANGESET_ABORT; + sqlite3_changeset_iter sIter; + memset(&sIter, 0, sizeof(sIter)); + sIter.nCol = nFk; + res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter); + if( res!=SQLITE_CHANGESET_OMIT ){ + rc = SQLITE_CONSTRAINT; } - break; } - default: { - break; + } + sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0); + + if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); + }else{ + sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0); + sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0); } } + + assert( sApply.bRebase || sApply.rebase.nBuf==0 ); + if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ + *ppRebase = (void*)sApply.rebase.aBuf; + *pnRebase = sApply.rebase.nBuf; + sApply.rebase.aBuf = 0; + } + sessionUpdateFree(&sApply); + sqlite3_finalize(sApply.pInsert); + sqlite3_finalize(sApply.pDelete); + sqlite3_finalize(sApply.pSelect); + sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ + sqlite3_free((char*)sApply.constraints.aBuf); + sqlite3_free((char*)sApply.rebase.aBuf); + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + return rc; } /* -** Compute the parentage of all nodes in a completed parse. +** Apply the changeset passed via pChangeset/nChangeset to the main +** database attached to handle "db". */ -static int jsonParseFindParents(JsonParse *pParse){ - u32 *aUp; - assert( pParse->aUp==0 ); - aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode ); - if( aUp==0 ){ - pParse->oom = 1; - return SQLITE_NOMEM; +SQLITE_API int sqlite3changeset_apply_v2( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +){ + sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ + int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1); + if( rc==SQLITE_OK ){ + rc = sessionChangesetApply( + db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags + ); } - jsonParseFillInParentage(pParse, 0, 0); - return SQLITE_OK; + return rc; } /* -** Compare the OBJECT label at pNode against zKey,nKey. Return true on -** a match. +** Apply the changeset passed via pChangeset/nChangeset to the main database +** attached to handle "db". Invoke the supplied conflict handler callback +** to resolve any conflicts encountered while applying the change. */ -static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ - if( pNode->jnFlags & JNODE_RAW ){ - if( pNode->n!=nKey ) return 0; - return strncmp(pNode->u.zJContent, zKey, nKey)==0; - }else{ - if( pNode->n!=nKey+2 ) return 0; - return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; +SQLITE_API int sqlite3changeset_apply( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of fifth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +){ + return sqlite3changeset_apply_v2( + db, nChangeset, pChangeset, xFilter, xConflict, pCtx, 0, 0, 0 + ); +} + +/* +** Apply the changeset passed via xInput/pIn to the main database +** attached to handle "db". Invoke the supplied conflict handler callback +** to resolve any conflicts encountered while applying the change. +*/ +SQLITE_API int sqlite3changeset_apply_v2_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +){ + sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse, 1); + if( rc==SQLITE_OK ){ + rc = sessionChangesetApply( + db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags + ); } + return rc; +} +SQLITE_API int sqlite3changeset_apply_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ +){ + return sqlite3changeset_apply_v2_strm( + db, xInput, pIn, xFilter, xConflict, pCtx, 0, 0, 0 + ); } -/* forward declaration */ -static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); +/* +** sqlite3_changegroup handle. +*/ +struct sqlite3_changegroup { + int rc; /* Error code */ + int bPatch; /* True to accumulate patchsets */ + SessionTable *pList; /* List of tables in current patch */ +}; /* -** Search along zPath to find the node specified. Return a pointer -** to that node, or NULL if zPath is malformed or if there is no such -** node. -** -** If pApnd!=0, then try to append new nodes to complete zPath if it is -** possible to do so and if no existing node corresponds to zPath. If -** new nodes are appended *pApnd is set to 1. +** This function is called to merge two changes to the same row together as +** part of an sqlite3changeset_concat() operation. A new change object is +** allocated and a pointer to it stored in *ppNew. */ -static JsonNode *jsonLookupStep( - JsonParse *pParse, /* The JSON to search */ - u32 iRoot, /* Begin the search at this node */ - const char *zPath, /* The path to search */ - int *pApnd, /* Append nodes to complete path if not NULL */ - const char **pzErr /* Make *pzErr point to any syntax error in zPath */ +static int sessionChangeMerge( + SessionTable *pTab, /* Table structure */ + int bRebase, /* True for a rebase hash-table */ + int bPatchset, /* True for patchsets */ + SessionChange *pExist, /* Existing change */ + int op2, /* Second change operation */ + int bIndirect, /* True if second change is indirect */ + u8 *aRec, /* Second change record */ + int nRec, /* Number of bytes in aRec */ + SessionChange **ppNew /* OUT: Merged change */ ){ - u32 i, j, nKey; - const char *zKey; - JsonNode *pRoot = &pParse->aNode[iRoot]; - if( zPath[0]==0 ) return pRoot; - if( zPath[0]=='.' ){ - if( pRoot->eType!=JSON_OBJECT ) return 0; - zPath++; - if( zPath[0]=='"' ){ - zKey = zPath + 1; - for(i=1; zPath[i] && zPath[i]!='"'; i++){} - nKey = i-1; - if( zPath[i] ){ - i++; - }else{ - *pzErr = zPath; - return 0; - } - }else{ - zKey = zPath; - for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} - nKey = i; - } - if( nKey==0 ){ - *pzErr = zPath; - return 0; + SessionChange *pNew = 0; + int rc = SQLITE_OK; + + if( !pExist ){ + pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec); + if( !pNew ){ + return SQLITE_NOMEM; } - j = 1; - for(;;){ - while( j<=pRoot->n ){ - if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ - return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); + memset(pNew, 0, sizeof(SessionChange)); + pNew->op = op2; + pNew->bIndirect = bIndirect; + pNew->aRecord = (u8*)&pNew[1]; + if( bIndirect==0 || bRebase==0 ){ + pNew->nRecord = nRec; + memcpy(pNew->aRecord, aRec, nRec); + }else{ + int i; + u8 *pIn = aRec; + u8 *pOut = pNew->aRecord; + for(i=0; inCol; i++){ + int nIn = sessionSerialLen(pIn); + if( *pIn==0 ){ + *pOut++ = 0; + }else if( pTab->abPK[i]==0 ){ + *pOut++ = 0xFF; + }else{ + memcpy(pOut, pIn, nIn); + pOut += nIn; } - j++; - j += jsonNodeSize(&pRoot[j]); + pIn += nIn; } - if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; - iRoot += pRoot->u.iAppend; - pRoot = &pParse->aNode[iRoot]; - j = 1; + pNew->nRecord = pOut - pNew->aRecord; } - if( pApnd ){ - u32 iStart, iLabel; - JsonNode *pNode; - iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); - iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); - zPath += i; - pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); - if( pParse->oom ) return 0; - if( pNode ){ - pRoot = &pParse->aNode[iRoot]; - pRoot->u.iAppend = iStart - iRoot; - pRoot->jnFlags |= JNODE_APPEND; - pParse->aNode[iLabel].jnFlags |= JNODE_RAW; + }else if( bRebase ){ + if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){ + *ppNew = pExist; + }else{ + sqlite3_int64 nByte = nRec + pExist->nRecord + sizeof(SessionChange); + pNew = (SessionChange*)sqlite3_malloc64(nByte); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + int i; + u8 *a1 = pExist->aRecord; + u8 *a2 = aRec; + u8 *pOut; + + memset(pNew, 0, nByte); + pNew->bIndirect = bIndirect || pExist->bIndirect; + pNew->op = op2; + pOut = pNew->aRecord = (u8*)&pNew[1]; + + for(i=0; inCol; i++){ + int n1 = sessionSerialLen(a1); + int n2 = sessionSerialLen(a2); + if( *a1==0xFF || (pTab->abPK[i]==0 && bIndirect) ){ + *pOut++ = 0xFF; + }else if( *a2==0 ){ + memcpy(pOut, a1, n1); + pOut += n1; + }else{ + memcpy(pOut, a2, n2); + pOut += n2; + } + a1 += n1; + a2 += n2; + } + pNew->nRecord = pOut - pNew->aRecord; } - return pNode; - } - }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){ - if( pRoot->eType!=JSON_ARRAY ) return 0; - i = 0; - j = 1; - while( safe_isdigit(zPath[j]) ){ - i = i*10 + zPath[j] - '0'; - j++; - } - if( zPath[j]!=']' ){ - *pzErr = zPath; - return 0; + sqlite3_free(pExist); } - zPath += j + 1; - j = 1; - for(;;){ - while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ - if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--; - j += jsonNodeSize(&pRoot[j]); + }else{ + int op1 = pExist->op; + + /* + ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2. + ** op1=INSERT, op2=UPDATE -> INSERT. + ** op1=INSERT, op2=DELETE -> (none) + ** + ** op1=UPDATE, op2=INSERT -> Unsupported. Discard op2. + ** op1=UPDATE, op2=UPDATE -> UPDATE. + ** op1=UPDATE, op2=DELETE -> DELETE. + ** + ** op1=DELETE, op2=INSERT -> UPDATE. + ** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2. + ** op1=DELETE, op2=DELETE -> Unsupported. Discard op2. + */ + if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT) + || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT) + || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE) + || (op1==SQLITE_DELETE && op2==SQLITE_DELETE) + ){ + pNew = pExist; + }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){ + sqlite3_free(pExist); + assert( pNew==0 ); + }else{ + u8 *aExist = pExist->aRecord; + sqlite3_int64 nByte; + u8 *aCsr; + + /* Allocate a new SessionChange object. Ensure that the aRecord[] + ** buffer of the new object is large enough to hold any record that + ** may be generated by combining the input records. */ + nByte = sizeof(SessionChange) + pExist->nRecord + nRec; + pNew = (SessionChange *)sqlite3_malloc64(nByte); + if( !pNew ){ + sqlite3_free(pExist); + return SQLITE_NOMEM; } - if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; - iRoot += pRoot->u.iAppend; - pRoot = &pParse->aNode[iRoot]; - j = 1; - } - if( j<=pRoot->n ){ - return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); - } - if( i==0 && pApnd ){ - u32 iStart; - JsonNode *pNode; - iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); - pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); - if( pParse->oom ) return 0; - if( pNode ){ - pRoot = &pParse->aNode[iRoot]; - pRoot->u.iAppend = iStart - iRoot; - pRoot->jnFlags |= JNODE_APPEND; + memset(pNew, 0, sizeof(SessionChange)); + pNew->bIndirect = (bIndirect && pExist->bIndirect); + aCsr = pNew->aRecord = (u8 *)&pNew[1]; + + if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */ + u8 *a1 = aRec; + assert( op2==SQLITE_UPDATE ); + pNew->op = SQLITE_INSERT; + if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol); + sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1); + }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */ + assert( op2==SQLITE_INSERT ); + pNew->op = SQLITE_UPDATE; + if( bPatchset ){ + memcpy(aCsr, aRec, nRec); + aCsr += nRec; + }else{ + if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){ + sqlite3_free(pNew); + pNew = 0; + } + } + }else if( op2==SQLITE_UPDATE ){ /* UPDATE + UPDATE */ + u8 *a1 = aExist; + u8 *a2 = aRec; + assert( op1==SQLITE_UPDATE ); + if( bPatchset==0 ){ + sessionSkipRecord(&a1, pTab->nCol); + sessionSkipRecord(&a2, pTab->nCol); + } + pNew->op = SQLITE_UPDATE; + if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){ + sqlite3_free(pNew); + pNew = 0; + } + }else{ /* UPDATE + DELETE */ + assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE ); + pNew->op = SQLITE_DELETE; + if( bPatchset ){ + memcpy(aCsr, aRec, nRec); + aCsr += nRec; + }else{ + sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist); + } } - return pNode; - } - }else{ - *pzErr = zPath; - } - return 0; -} -/* -** Append content to pParse that will complete zPath. Return a pointer -** to the inserted node, or return NULL if the append fails. -*/ -static JsonNode *jsonLookupAppend( - JsonParse *pParse, /* Append content to the JSON parse */ - const char *zPath, /* Description of content to append */ - int *pApnd, /* Set this flag to 1 */ - const char **pzErr /* Make this point to any syntax error */ -){ - *pApnd = 1; - if( zPath[0]==0 ){ - jsonParseAddNode(pParse, JSON_NULL, 0, 0); - return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; - } - if( zPath[0]=='.' ){ - jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); - }else if( strncmp(zPath,"[0]",3)==0 ){ - jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); - }else{ - return 0; + if( pNew ){ + pNew->nRecord = (int)(aCsr - pNew->aRecord); + } + sqlite3_free(pExist); + } } - if( pParse->oom ) return 0; - return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); -} -/* -** Return the text of a syntax error message on a JSON path. Space is -** obtained from sqlite3_malloc(). -*/ -static char *jsonPathSyntaxError(const char *zErr){ - return sqlite3_mprintf("JSON path error near '%q'", zErr); + *ppNew = pNew; + return rc; } /* -** Do a node lookup using zPath. Return a pointer to the node on success. -** Return NULL if not found or if there is an error. -** -** On an error, write an error message into pCtx and increment the -** pParse->nErr counter. -** -** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if -** nodes are appended. +** Add all changes in the changeset traversed by the iterator passed as +** the first argument to the changegroup hash tables. */ -static JsonNode *jsonLookup( - JsonParse *pParse, /* The JSON to search */ - const char *zPath, /* The path to search */ - int *pApnd, /* Append nodes to complete path if not NULL */ - sqlite3_context *pCtx /* Report errors here, if not NULL */ +static int sessionChangesetToHash( + sqlite3_changeset_iter *pIter, /* Iterator to read from */ + sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */ + int bRebase /* True if hash table is for rebasing */ ){ - const char *zErr = 0; - JsonNode *pNode = 0; - char *zMsg; + u8 *aRec; + int nRec; + int rc = SQLITE_OK; + SessionTable *pTab = 0; - if( zPath==0 ) return 0; - if( zPath[0]!='$' ){ - zErr = zPath; - goto lookup_err; - } - zPath++; - pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); - if( zErr==0 ) return pNode; + while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){ + const char *zNew; + int nCol; + int op; + int iHash; + int bIndirect; + SessionChange *pChange; + SessionChange *pExist = 0; + SessionChange **pp; -lookup_err: - pParse->nErr++; - assert( zErr!=0 && pCtx!=0 ); - zMsg = jsonPathSyntaxError(zErr); - if( zMsg ){ - sqlite3_result_error(pCtx, zMsg, -1); - sqlite3_free(zMsg); - }else{ - sqlite3_result_error_nomem(pCtx); - } - return 0; -} + if( pGrp->pList==0 ){ + pGrp->bPatch = pIter->bPatchset; + }else if( pIter->bPatchset!=pGrp->bPatch ){ + rc = SQLITE_ERROR; + break; + } + sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect); + if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){ + /* Search the list for a matching table */ + int nNew = (int)strlen(zNew); + u8 *abPK; -/* -** Report the wrong number of arguments for json_insert(), json_replace() -** or json_set(). -*/ -static void jsonWrongNumArgs( - sqlite3_context *pCtx, - const char *zFuncName -){ - char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", - zFuncName); - sqlite3_result_error(pCtx, zMsg, -1); - sqlite3_free(zMsg); -} + sqlite3changeset_pk(pIter, &abPK, 0); + for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ + if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break; + } + if( !pTab ){ + SessionTable **ppTab; + pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1); + if( !pTab ){ + rc = SQLITE_NOMEM; + break; + } + memset(pTab, 0, sizeof(SessionTable)); + pTab->nCol = nCol; + pTab->abPK = (u8*)&pTab[1]; + memcpy(pTab->abPK, abPK, nCol); + pTab->zName = (char*)&pTab->abPK[nCol]; + memcpy(pTab->zName, zNew, nNew+1); -/**************************************************************************** -** SQL functions used for testing and debugging -****************************************************************************/ + /* The new object must be linked on to the end of the list, not + ** simply added to the start of it. This is to ensure that the + ** tables within the output of sqlite3changegroup_output() are in + ** the right order. */ + for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext); + *ppTab = pTab; + }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ + rc = SQLITE_SCHEMA; + break; + } + } -#ifdef SQLITE_DEBUG -/* -** The json_parse(JSON) function returns a string which describes -** a parse of the JSON provided. Or it returns NULL if JSON is not -** well-formed. -*/ -static void jsonParseFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonString s; /* Output string - not real JSON */ - JsonParse x; /* The parse */ - u32 i; + if( sessionGrowHash(0, pIter->bPatchset, pTab) ){ + rc = SQLITE_NOMEM; + break; + } + iHash = sessionChangeHash( + pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange + ); - assert( argc==1 ); - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - jsonParseFindParents(&x); - jsonInit(&s, ctx); - for(i=0; iapChange[iHash]; *pp; pp=&(*pp)->pNext){ + int bPkOnly1 = 0; + int bPkOnly2 = 0; + if( pIter->bPatchset ){ + bPkOnly1 = (*pp)->op==SQLITE_DELETE; + bPkOnly2 = op==SQLITE_DELETE; + } + if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){ + pExist = *pp; + *pp = (*pp)->pNext; + pTab->nEntry--; + break; + } } - jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d", - i, zType, x.aNode[i].n, x.aUp[i]); - if( x.aNode[i].u.zJContent!=0 ){ - jsonAppendRaw(&s, " ", 1); - jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); + + rc = sessionChangeMerge(pTab, bRebase, + pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange + ); + if( rc ) break; + if( pChange ){ + pChange->pNext = pTab->apChange[iHash]; + pTab->apChange[iHash] = pChange; + pTab->nEntry++; } - jsonAppendRaw(&s, "\n", 1); } - jsonParseReset(&x); - jsonResult(&s); + + if( rc==SQLITE_OK ) rc = pIter->rc; + return rc; } /* -** The json_test1(JSON) function return true (1) if the input is JSON -** text generated by another json function. It returns (0) if the input -** is not known to be JSON. +** Serialize a changeset (or patchset) based on all changesets (or patchsets) +** added to the changegroup object passed as the first argument. +** +** If xOutput is not NULL, then the changeset/patchset is returned to the +** user via one or more calls to xOutput, as with the other streaming +** interfaces. +** +** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a +** buffer containing the output changeset before this function returns. In +** this case (*pnOut) is set to the size of the output buffer in bytes. It +** is the responsibility of the caller to free the output buffer using +** sqlite3_free() when it is no longer required. +** +** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite +** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut) +** are both set to 0 before returning. */ -static void jsonTest1Func( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +static int sessionChangegroupOutput( + sqlite3_changegroup *pGrp, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut, + int *pnOut, + void **ppOut ){ - UNUSED_PARAM(argc); - sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); -} -#endif /* SQLITE_DEBUG */ + int rc = SQLITE_OK; + SessionBuffer buf = {0, 0, 0}; + SessionTable *pTab; + assert( xOutput==0 || (ppOut==0 && pnOut==0) ); -/**************************************************************************** -** Scalar SQL function implementations -****************************************************************************/ + /* Create the serialized output changeset based on the contents of the + ** hash tables attached to the SessionTable objects in list p->pList. + */ + for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ + int i; + if( pTab->nEntry==0 ) continue; -/* -** Implementation of the json_QUOTE(VALUE) function. Return a JSON value -** corresponding to the SQL value input. Mostly this means putting -** double-quotes around strings and returning the unquoted string "null" -** when given a NULL input. -*/ -static void jsonQuoteFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonString jx; - UNUSED_PARAM(argc); + sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc); + for(i=0; inChange; i++){ + SessionChange *p; + for(p=pTab->apChange[i]; p; p=p->pNext){ + sessionAppendByte(&buf, p->op, &rc); + sessionAppendByte(&buf, p->bIndirect, &rc); + sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); + if( rc==SQLITE_OK && xOutput && buf.nBuf>=sessions_strm_chunk_size ){ + rc = xOutput(pOut, buf.aBuf, buf.nBuf); + buf.nBuf = 0; + } + } + } + } - jsonInit(&jx, ctx); - jsonAppendValue(&jx, argv[0]); - jsonResult(&jx); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); + if( rc==SQLITE_OK ){ + if( xOutput ){ + if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); + }else if( ppOut ){ + *ppOut = buf.aBuf; + if( pnOut ) *pnOut = buf.nBuf; + buf.aBuf = 0; + } + } + sqlite3_free(buf.aBuf); + + return rc; } /* -** Implementation of the json_array(VALUE,...) function. Return a JSON -** array that contains all values given in arguments. Or if any argument -** is a BLOB, throw an error. +** Allocate a new, empty, sqlite3_changegroup. */ -static void jsonArrayFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - int i; - JsonString jx; - - jsonInit(&jx, ctx); - jsonAppendChar(&jx, '['); - for(i=0; ieType==JSON_ARRAY ){ - assert( (pNode->jnFlags & JNODE_APPEND)==0 ); - for(i=1; i<=pNode->n; n++){ - i += jsonNodeSize(&pNode[i]); - } + rc = sqlite3changeset_start(&pIter, nData, pData); + if( rc==SQLITE_OK ){ + rc = sessionChangesetToHash(pIter, pGrp, 0); } - if( x.nErr==0 ) sqlite3_result_int64(ctx, n); - jsonParseReset(&x); + sqlite3changeset_finalize(pIter); + return rc; } /* -** json_extract(JSON, PATH, ...) -** -** Return the element described by PATH. Return NULL if there is no -** PATH element. If there are multiple PATHs, then return a JSON array -** with the result from each path. Throw an error if the JSON or any PATH -** is malformed. +** Obtain a buffer containing a changeset representing the concatenation +** of all changesets added to the group so far. */ -static void jsonExtractFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +SQLITE_API int sqlite3changegroup_output( + sqlite3_changegroup *pGrp, + int *pnData, + void **ppData ){ - JsonParse x; /* The parse */ - JsonNode *pNode; - const char *zPath; - JsonString jx; - int i; - - if( argc<2 ) return; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - jsonInit(&jx, ctx); - jsonAppendChar(&jx, '['); - for(i=1; i2 ){ - jsonAppendSeparator(&jx); - if( pNode ){ - jsonRenderNode(pNode, &jx, 0); - }else{ - jsonAppendRaw(&jx, "null", 4); - } - }else if( pNode ){ - jsonReturn(pNode, ctx, 0); - } - } - if( argc>2 && i==argc ){ - jsonAppendChar(&jx, ']'); - jsonResult(&jx); - sqlite3_result_subtype(ctx, JSON_SUBTYPE); - } - jsonReset(&jx); - jsonParseReset(&x); + return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData); } /* -** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON -** object that contains all name/value given in arguments. Or if any name -** is not a string or if any value is a BLOB, throw an error. +** Streaming versions of changegroup_add(). */ -static void jsonObjectFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +SQLITE_API int sqlite3changegroup_add_strm( + sqlite3_changegroup *pGrp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn ){ - int i; - JsonString jx; - const char *z; - u32 n; + sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */ + int rc; /* Return code */ - if( argc&1 ){ - sqlite3_result_error(ctx, "json_object() requires an even number " - "of arguments", -1); - return; - } - jsonInit(&jx, ctx); - jsonAppendChar(&jx, '{'); - for(i=0; ijnFlags |= JNODE_REMOVE; - } - if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ - jsonReturnJson(x.aNode, ctx, 0); +/* +** Delete a changegroup object. +*/ +SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ + if( pGrp ){ + sessionDeleteTable(0, pGrp->pList); + sqlite3_free(pGrp); } -remove_done: - jsonParseReset(&x); } /* -** json_replace(JSON, PATH, VALUE, ...) -** -** Replace the value at PATH with VALUE. If PATH does not already exist, -** this routine is a no-op. If JSON or PATH is malformed, throw an error. +** Combine two changesets together. */ -static void jsonReplaceFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +SQLITE_API int sqlite3changeset_concat( + int nLeft, /* Number of bytes in lhs input */ + void *pLeft, /* Lhs input changeset */ + int nRight /* Number of bytes in rhs input */, + void *pRight, /* Rhs input changeset */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: changeset (left right) */ ){ - JsonParse x; /* The parse */ - JsonNode *pNode; - const char *zPath; - u32 i; + sqlite3_changegroup *pGrp; + int rc; - if( argc<1 ) return; - if( (argc&1)==0 ) { - jsonWrongNumArgs(ctx, "replace"); - return; + rc = sqlite3changegroup_new(&pGrp); + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add(pGrp, nLeft, pLeft); } - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); - for(i=1; i<(u32)argc; i+=2){ - zPath = (const char*)sqlite3_value_text(argv[i]); - pNode = jsonLookup(&x, zPath, 0, ctx); - if( x.nErr ) goto replace_err; - if( pNode ){ - pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->iVal = (u8)(i+1); - } + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add(pGrp, nRight, pRight); } - if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); - }else{ - jsonReturnJson(x.aNode, ctx, argv); + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); } -replace_err: - jsonParseReset(&x); + sqlite3changegroup_delete(pGrp); + + return rc; } /* -** json_set(JSON, PATH, VALUE, ...) -** -** Set the value at PATH to VALUE. Create the PATH if it does not already -** exist. Overwrite existing values that do exist. -** If JSON or PATH is malformed, throw an error. -** -** json_insert(JSON, PATH, VALUE, ...) -** -** Create PATH and initialize it to VALUE. If PATH already exists, this -** routine is a no-op. If JSON or PATH is malformed, throw an error. +** Streaming version of sqlite3changeset_concat(). */ -static void jsonSetFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +SQLITE_API int sqlite3changeset_concat_strm( + int (*xInputA)(void *pIn, void *pData, int *pnData), + void *pInA, + int (*xInputB)(void *pIn, void *pData, int *pnData), + void *pInB, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut ){ - JsonParse x; /* The parse */ - JsonNode *pNode; - const char *zPath; - u32 i; - int bApnd; - int bIsSet = *(int*)sqlite3_user_data(ctx); + sqlite3_changegroup *pGrp; + int rc; - if( argc<1 ) return; - if( (argc&1)==0 ) { - jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); - return; + rc = sqlite3changegroup_new(&pGrp); + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA); } - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); - for(i=1; i<(u32)argc; i+=2){ - zPath = (const char*)sqlite3_value_text(argv[i]); - bApnd = 0; - pNode = jsonLookup(&x, zPath, &bApnd, ctx); - if( x.oom ){ - sqlite3_result_error_nomem(ctx); - goto jsonSetDone; - }else if( x.nErr ){ - goto jsonSetDone; - }else if( pNode && (bApnd || bIsSet) ){ - pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->iVal = (u8)(i+1); - } + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB); } - if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); - }else{ - jsonReturnJson(x.aNode, ctx, argv); + if( rc==SQLITE_OK ){ + rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut); } -jsonSetDone: - jsonParseReset(&x); + sqlite3changegroup_delete(pGrp); + + return rc; } /* -** json_type(JSON) -** json_type(JSON, PATH) -** -** Return the top-level "type" of a JSON string. Throw an error if -** either the JSON or PATH inputs are not well-formed. +** Changeset rebaser handle. */ -static void jsonTypeFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse x; /* The parse */ - const char *zPath; - JsonNode *pNode; - - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); - if( argc==2 ){ - zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); - }else{ - pNode = x.aNode; - } - if( pNode ){ - sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); - } - jsonParseReset(&x); -} +struct sqlite3_rebaser { + sqlite3_changegroup grp; /* Hash table */ +}; /* -** json_valid(JSON) -** -** Return 1 if JSON is a well-formed JSON string according to RFC-7159. -** Return 0 otherwise. +** Buffers a1 and a2 must both contain a sessions module record nCol +** fields in size. This function appends an nCol sessions module +** record to buffer pBuf that is a copy of a1, except that for +** each field that is undefined in a1[], swap in the field from a2[]. */ -static void jsonValidFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +static void sessionAppendRecordMerge( + SessionBuffer *pBuf, /* Buffer to append to */ + int nCol, /* Number of columns in each record */ + u8 *a1, int n1, /* Record 1 */ + u8 *a2, int n2, /* Record 2 */ + int *pRc /* IN/OUT: error code */ ){ - JsonParse x; /* The parse */ - int rc = 0; + sessionBufferGrow(pBuf, n1+n2, pRc); + if( *pRc==SQLITE_OK ){ + int i; + u8 *pOut = &pBuf->aBuf[pBuf->nBuf]; + for(i=0; inBuf = pOut-pBuf->aBuf; + assert( pBuf->nBuf<=pBuf->nAlloc ); } - jsonParseReset(&x); - sqlite3_result_int(ctx, rc); } - -/**************************************************************************** -** Aggregate SQL function implementations -****************************************************************************/ /* -** json_group_array(VALUE) +** This function is called when rebasing a local UPDATE change against one +** or more remote UPDATE changes. The aRec/nRec buffer contains the current +** old.* and new.* records for the change. The rebase buffer (a single +** record) is in aChange/nChange. The rebased change is appended to buffer +** pBuf. ** -** Return a JSON array composed of all values in the aggregate. +** Rebasing the UPDATE involves: +** +** * Removing any changes to fields for which the corresponding field +** in the rebase buffer is set to "replaced" (type 0xFF). If this +** means the UPDATE change updates no fields, nothing is appended +** to the output buffer. +** +** * For each field modified by the local change for which the +** corresponding field in the rebase buffer is not "undefined" (0x00) +** or "replaced" (0xFF), the old.* value is replaced by the value +** in the rebase buffer. */ -static void jsonArrayStep( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +static void sessionAppendPartialUpdate( + SessionBuffer *pBuf, /* Append record here */ + sqlite3_changeset_iter *pIter, /* Iterator pointed at local change */ + u8 *aRec, int nRec, /* Local change */ + u8 *aChange, int nChange, /* Record to rebase against */ + int *pRc /* IN/OUT: Return Code */ ){ - JsonString *pStr; - UNUSED_PARAM(argc); - pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); - if( pStr ){ - if( pStr->zBuf==0 ){ - jsonInit(pStr, ctx); - jsonAppendChar(pStr, '['); - }else{ - jsonAppendChar(pStr, ','); - pStr->pCtx = ctx; + sessionBufferGrow(pBuf, 2+nRec+nChange, pRc); + if( *pRc==SQLITE_OK ){ + int bData = 0; + u8 *pOut = &pBuf->aBuf[pBuf->nBuf]; + int i; + u8 *a1 = aRec; + u8 *a2 = aChange; + + *pOut++ = SQLITE_UPDATE; + *pOut++ = pIter->bIndirect; + for(i=0; inCol; i++){ + int n1 = sessionSerialLen(a1); + int n2 = sessionSerialLen(a2); + if( pIter->abPK[i] || a2[0]==0 ){ + if( !pIter->abPK[i] && a1[0] ) bData = 1; + memcpy(pOut, a1, n1); + pOut += n1; + }else if( a2[0]!=0xFF ){ + bData = 1; + memcpy(pOut, a2, n2); + pOut += n2; + }else{ + *pOut++ = '\0'; + } + a1 += n1; + a2 += n2; } - jsonAppendValue(pStr, argv[0]); - } -} -static void jsonArrayFinal(sqlite3_context *ctx){ - JsonString *pStr; - pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); - if( pStr ){ - pStr->pCtx = ctx; - jsonAppendChar(pStr, ']'); - if( pStr->bErr ){ - if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); - assert( pStr->bStatic ); - }else{ - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, - pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); - pStr->bStatic = 1; + if( bData ){ + a2 = aChange; + for(i=0; inCol; i++){ + int n1 = sessionSerialLen(a1); + int n2 = sessionSerialLen(a2); + if( pIter->abPK[i] || a2[0]!=0xFF ){ + memcpy(pOut, a1, n1); + pOut += n1; + }else{ + *pOut++ = '\0'; + } + a1 += n1; + a2 += n2; + } + pBuf->nBuf = (pOut - pBuf->aBuf); } - }else{ - sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } - sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* -** json_group_obj(NAME,VALUE) +** pIter is configured to iterate through a changeset. This function rebases +** that changeset according to the current configuration of the rebaser +** object passed as the first argument. If no error occurs and argument xOutput +** is not NULL, then the changeset is returned to the caller by invoking +** xOutput zero or more times and SQLITE_OK returned. Or, if xOutput is NULL, +** then (*ppOut) is set to point to a buffer containing the rebased changeset +** before this function returns. In this case (*pnOut) is set to the size of +** the buffer in bytes. It is the responsibility of the caller to eventually +** free the (*ppOut) buffer using sqlite3_free(). ** -** Return a JSON object composed of all names and values in the aggregate. +** If an error occurs, an SQLite error code is returned. If ppOut and +** pnOut are not NULL, then the two output parameters are set to 0 before +** returning. */ -static void jsonObjectStep( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv +static int sessionRebase( + sqlite3_rebaser *p, /* Rebaser hash table */ + sqlite3_changeset_iter *pIter, /* Input data */ + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut, /* Context for xOutput callback */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: Inverse of pChangeset */ ){ - JsonString *pStr; - const char *z; - u32 n; - UNUSED_PARAM(argc); - pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); - if( pStr ){ - if( pStr->zBuf==0 ){ - jsonInit(pStr, ctx); - jsonAppendChar(pStr, '{'); - }else{ - jsonAppendChar(pStr, ','); - pStr->pCtx = ctx; - } - z = (const char*)sqlite3_value_text(argv[0]); - n = (u32)sqlite3_value_bytes(argv[0]); - jsonAppendString(pStr, z, n); - jsonAppendChar(pStr, ':'); - jsonAppendValue(pStr, argv[1]); - } -} -static void jsonObjectFinal(sqlite3_context *ctx){ - JsonString *pStr; - pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); - if( pStr ){ - jsonAppendChar(pStr, '}'); - if( pStr->bErr ){ - if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); - assert( pStr->bStatic ); - }else{ - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, - pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); - pStr->bStatic = 1; - } - }else{ - sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); - } - sqlite3_result_subtype(ctx, JSON_SUBTYPE); -} - + int rc = SQLITE_OK; + u8 *aRec = 0; + int nRec = 0; + int bNew = 0; + SessionTable *pTab = 0; + SessionBuffer sOut = {0,0,0}; -#ifndef SQLITE_OMIT_VIRTUALTABLE -/**************************************************************************** -** The json_each virtual table -****************************************************************************/ -typedef struct JsonEachCursor JsonEachCursor; -struct JsonEachCursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - u32 iRowid; /* The rowid */ - u32 iBegin; /* The first node of the scan */ - u32 i; /* Index in sParse.aNode[] of current row */ - u32 iEnd; /* EOF when i equals or exceeds this value */ - u8 eType; /* Type of top-level element */ - u8 bRecursive; /* True for json_tree(). False for json_each() */ - char *zJson; /* Input JSON */ - char *zRoot; /* Path by which to filter zJson */ - JsonParse sParse; /* Parse of the input JSON */ -}; + while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, &bNew) ){ + SessionChange *pChange = 0; + int bDone = 0; -/* Constructor for the json_each virtual table */ -static int jsonEachConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr -){ - sqlite3_vtab *pNew; - int rc; + if( bNew ){ + const char *zTab = pIter->zTab; + for(pTab=p->grp.pList; pTab; pTab=pTab->pNext){ + if( 0==sqlite3_stricmp(pTab->zName, zTab) ) break; + } + bNew = 0; -/* Column numbers */ -#define JEACH_KEY 0 -#define JEACH_VALUE 1 -#define JEACH_TYPE 2 -#define JEACH_ATOM 3 -#define JEACH_ID 4 -#define JEACH_PARENT 5 -#define JEACH_FULLKEY 6 -#define JEACH_PATH 7 -#define JEACH_JSON 8 -#define JEACH_ROOT 9 + /* A patchset may not be rebased */ + if( pIter->bPatchset ){ + rc = SQLITE_ERROR; + } - UNUSED_PARAM(pzErr); - UNUSED_PARAM(argv); - UNUSED_PARAM(argc); - UNUSED_PARAM(pAux); - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," - "json HIDDEN,root HIDDEN)"); - if( rc==SQLITE_OK ){ - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - } - return rc; -} + /* Append a table header to the output for this new table */ + sessionAppendByte(&sOut, pIter->bPatchset ? 'P' : 'T', &rc); + sessionAppendVarint(&sOut, pIter->nCol, &rc); + sessionAppendBlob(&sOut, pIter->abPK, pIter->nCol, &rc); + sessionAppendBlob(&sOut,(u8*)pIter->zTab,(int)strlen(pIter->zTab)+1,&rc); + } -/* destructor for json_each virtual table */ -static int jsonEachDisconnect(sqlite3_vtab *pVtab){ - sqlite3_free(pVtab); - return SQLITE_OK; -} + if( pTab && rc==SQLITE_OK ){ + int iHash = sessionChangeHash(pTab, 0, aRec, pTab->nChange); -/* constructor for a JsonEachCursor object for json_each(). */ -static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - JsonEachCursor *pCur; + for(pChange=pTab->apChange[iHash]; pChange; pChange=pChange->pNext){ + if( sessionChangeEqual(pTab, 0, aRec, 0, pChange->aRecord) ){ + break; + } + } + } - UNUSED_PARAM(p); - pCur = sqlite3_malloc( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - *ppCursor = &pCur->base; - return SQLITE_OK; -} + if( pChange ){ + assert( pChange->op==SQLITE_DELETE || pChange->op==SQLITE_INSERT ); + switch( pIter->op ){ + case SQLITE_INSERT: + if( pChange->op==SQLITE_INSERT ){ + bDone = 1; + if( pChange->bIndirect==0 ){ + sessionAppendByte(&sOut, SQLITE_UPDATE, &rc); + sessionAppendByte(&sOut, pIter->bIndirect, &rc); + sessionAppendBlob(&sOut, pChange->aRecord, pChange->nRecord, &rc); + sessionAppendBlob(&sOut, aRec, nRec, &rc); + } + } + break; -/* constructor for a JsonEachCursor object for json_tree(). */ -static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - int rc = jsonEachOpenEach(p, ppCursor); - if( rc==SQLITE_OK ){ - JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; - pCur->bRecursive = 1; - } - return rc; -} + case SQLITE_UPDATE: + bDone = 1; + if( pChange->op==SQLITE_DELETE ){ + if( pChange->bIndirect==0 ){ + u8 *pCsr = aRec; + sessionSkipRecord(&pCsr, pIter->nCol); + sessionAppendByte(&sOut, SQLITE_INSERT, &rc); + sessionAppendByte(&sOut, pIter->bIndirect, &rc); + sessionAppendRecordMerge(&sOut, pIter->nCol, + pCsr, nRec-(pCsr-aRec), + pChange->aRecord, pChange->nRecord, &rc + ); + } + }else{ + sessionAppendPartialUpdate(&sOut, pIter, + aRec, nRec, pChange->aRecord, pChange->nRecord, &rc + ); + } + break; -/* Reset a JsonEachCursor back to its original state. Free any memory -** held. */ -static void jsonEachCursorReset(JsonEachCursor *p){ - sqlite3_free(p->zJson); - sqlite3_free(p->zRoot); - jsonParseReset(&p->sParse); - p->iRowid = 0; - p->i = 0; - p->iEnd = 0; - p->eType = 0; - p->zJson = 0; - p->zRoot = 0; -} + default: + assert( pIter->op==SQLITE_DELETE ); + bDone = 1; + if( pChange->op==SQLITE_INSERT ){ + sessionAppendByte(&sOut, SQLITE_DELETE, &rc); + sessionAppendByte(&sOut, pIter->bIndirect, &rc); + sessionAppendRecordMerge(&sOut, pIter->nCol, + pChange->aRecord, pChange->nRecord, aRec, nRec, &rc + ); + } + break; + } + } -/* Destructor for a jsonEachCursor object */ -static int jsonEachClose(sqlite3_vtab_cursor *cur){ - JsonEachCursor *p = (JsonEachCursor*)cur; - jsonEachCursorReset(p); - sqlite3_free(cur); - return SQLITE_OK; -} + if( bDone==0 ){ + sessionAppendByte(&sOut, pIter->op, &rc); + sessionAppendByte(&sOut, pIter->bIndirect, &rc); + sessionAppendBlob(&sOut, aRec, nRec, &rc); + } + if( rc==SQLITE_OK && xOutput && sOut.nBuf>sessions_strm_chunk_size ){ + rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); + sOut.nBuf = 0; + } + if( rc ) break; + } -/* Return TRUE if the jsonEachCursor object has been advanced off the end -** of the JSON object */ -static int jsonEachEof(sqlite3_vtab_cursor *cur){ - JsonEachCursor *p = (JsonEachCursor*)cur; - return p->i >= p->iEnd; -} + if( rc!=SQLITE_OK ){ + sqlite3_free(sOut.aBuf); + memset(&sOut, 0, sizeof(sOut)); + } -/* Advance the cursor to the next element for json_tree() */ -static int jsonEachNext(sqlite3_vtab_cursor *cur){ - JsonEachCursor *p = (JsonEachCursor*)cur; - if( p->bRecursive ){ - if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; - p->i++; - p->iRowid++; - if( p->iiEnd ){ - u32 iUp = p->sParse.aUp[p->i]; - JsonNode *pUp = &p->sParse.aNode[iUp]; - p->eType = pUp->eType; - if( pUp->eType==JSON_ARRAY ){ - if( iUp==p->i-1 ){ - pUp->u.iKey = 0; - }else{ - pUp->u.iKey++; - } - } - } - }else{ - switch( p->eType ){ - case JSON_ARRAY: { - p->i += jsonNodeSize(&p->sParse.aNode[p->i]); - p->iRowid++; - break; - } - case JSON_OBJECT: { - p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); - p->iRowid++; - break; - } - default: { - p->i = p->iEnd; - break; + if( rc==SQLITE_OK ){ + if( xOutput ){ + if( sOut.nBuf>0 ){ + rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } + }else if( ppOut ){ + *ppOut = (void*)sOut.aBuf; + *pnOut = sOut.nBuf; + sOut.aBuf = 0; } } - return SQLITE_OK; + sqlite3_free(sOut.aBuf); + return rc; } -/* Append the name of the path for element i to pStr +/* +** Create a new rebaser object. */ -static void jsonEachComputePath( - JsonEachCursor *p, /* The cursor */ - JsonString *pStr, /* Write the path here */ - u32 i /* Path to this element */ -){ - JsonNode *pNode, *pUp; - u32 iUp; - if( i==0 ){ - jsonAppendChar(pStr, '$'); - return; - } - iUp = p->sParse.aUp[i]; - jsonEachComputePath(p, pStr, iUp); - pNode = &p->sParse.aNode[i]; - pUp = &p->sParse.aNode[iUp]; - if( pUp->eType==JSON_ARRAY ){ - jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); +SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew){ + int rc = SQLITE_OK; + sqlite3_rebaser *pNew; + + pNew = sqlite3_malloc(sizeof(sqlite3_rebaser)); + if( pNew==0 ){ + rc = SQLITE_NOMEM; }else{ - assert( pUp->eType==JSON_OBJECT ); - if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; - assert( pNode->eType==JSON_STRING ); - assert( pNode->jnFlags & JNODE_LABEL ); - jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); + memset(pNew, 0, sizeof(sqlite3_rebaser)); } + *ppNew = pNew; + return rc; } -/* Return the value of a column */ -static int jsonEachColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ +/* +** Call this one or more times to configure a rebaser. +*/ +SQLITE_API int sqlite3rebaser_configure( + sqlite3_rebaser *p, + int nRebase, const void *pRebase ){ - JsonEachCursor *p = (JsonEachCursor*)cur; - JsonNode *pThis = &p->sParse.aNode[p->i]; - switch( i ){ - case JEACH_KEY: { - if( p->i==0 ) break; - if( p->eType==JSON_OBJECT ){ - jsonReturn(pThis, ctx, 0); - }else if( p->eType==JSON_ARRAY ){ - u32 iKey; - if( p->bRecursive ){ - if( p->iRowid==0 ) break; - iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; - }else{ - iKey = p->iRowid; - } - sqlite3_result_int64(ctx, (sqlite3_int64)iKey); - } - break; - } - case JEACH_VALUE: { - if( pThis->jnFlags & JNODE_LABEL ) pThis++; - jsonReturn(pThis, ctx, 0); - break; - } - case JEACH_TYPE: { - if( pThis->jnFlags & JNODE_LABEL ) pThis++; - sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); - break; - } - case JEACH_ATOM: { - if( pThis->jnFlags & JNODE_LABEL ) pThis++; - if( pThis->eType>=JSON_ARRAY ) break; - jsonReturn(pThis, ctx, 0); - break; - } - case JEACH_ID: { - sqlite3_result_int64(ctx, - (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); - break; - } - case JEACH_PARENT: { - if( p->i>p->iBegin && p->bRecursive ){ - sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); - } - break; - } - case JEACH_FULLKEY: { - JsonString x; - jsonInit(&x, ctx); - if( p->bRecursive ){ - jsonEachComputePath(p, &x, p->i); - }else{ - if( p->zRoot ){ - jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); - }else{ - jsonAppendChar(&x, '$'); - } - if( p->eType==JSON_ARRAY ){ - jsonPrintf(30, &x, "[%d]", p->iRowid); - }else{ - jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); - } - } - jsonResult(&x); - break; - } - case JEACH_PATH: { - if( p->bRecursive ){ - JsonString x; - jsonInit(&x, ctx); - jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); - jsonResult(&x); - break; - } - /* For json_each() path and root are the same so fall through - ** into the root case */ - } - default: { - const char *zRoot = p->zRoot; - if( zRoot==0 ) zRoot = "$"; - sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); - break; - } - case JEACH_JSON: { - assert( i==JEACH_JSON ); - sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); - break; - } + sqlite3_changeset_iter *pIter = 0; /* Iterator opened on pData/nData */ + int rc; /* Return code */ + rc = sqlite3changeset_start(&pIter, nRebase, (void*)pRebase); + if( rc==SQLITE_OK ){ + rc = sessionChangesetToHash(pIter, &p->grp, 1); } - return SQLITE_OK; -} - -/* Return the current rowid value */ -static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - JsonEachCursor *p = (JsonEachCursor*)cur; - *pRowid = p->iRowid; - return SQLITE_OK; + sqlite3changeset_finalize(pIter); + return rc; } -/* The query strategy is to look for an equality constraint on the json -** column. Without such a constraint, the table cannot operate. idxNum is -** 1 if the constraint is found, 3 if the constraint and zRoot are found, -** and 0 otherwise. +/* +** Rebase a changeset according to current rebaser configuration */ -static int jsonEachBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo +SQLITE_API int sqlite3rebaser_rebase( + sqlite3_rebaser *p, + int nIn, const void *pIn, + int *pnOut, void **ppOut ){ - int i; - int jsonIdx = -1; - int rootIdx = -1; - const struct sqlite3_index_constraint *pConstraint; + sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */ + int rc = sqlite3changeset_start(&pIter, nIn, (void*)pIn); - UNUSED_PARAM(tab); - pConstraint = pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->usable==0 ) continue; - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case JEACH_JSON: jsonIdx = i; break; - case JEACH_ROOT: rootIdx = i; break; - default: /* no-op */ break; - } - } - if( jsonIdx<0 ){ - pIdxInfo->idxNum = 0; - pIdxInfo->estimatedCost = 1e99; - }else{ - pIdxInfo->estimatedCost = 1.0; - pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1; - pIdxInfo->aConstraintUsage[jsonIdx].omit = 1; - if( rootIdx<0 ){ - pIdxInfo->idxNum = 1; - }else{ - pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2; - pIdxInfo->aConstraintUsage[rootIdx].omit = 1; - pIdxInfo->idxNum = 3; - } + if( rc==SQLITE_OK ){ + rc = sessionRebase(p, pIter, 0, 0, pnOut, ppOut); + sqlite3changeset_finalize(pIter); } - return SQLITE_OK; + + return rc; } -/* Start a search on a new JSON string */ -static int jsonEachFilter( - sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv +/* +** Rebase a changeset according to current rebaser configuration +*/ +SQLITE_API int sqlite3rebaser_rebase_strm( + sqlite3_rebaser *p, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut ){ - JsonEachCursor *p = (JsonEachCursor*)cur; - const char *z; - const char *zRoot = 0; - sqlite3_int64 n; + sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */ + int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); - UNUSED_PARAM(idxStr); - UNUSED_PARAM(argc); - jsonEachCursorReset(p); - if( idxNum==0 ) return SQLITE_OK; - z = (const char*)sqlite3_value_text(argv[0]); - if( z==0 ) return SQLITE_OK; - n = sqlite3_value_bytes(argv[0]); - p->zJson = sqlite3_malloc64( n+1 ); - if( p->zJson==0 ) return SQLITE_NOMEM; - memcpy(p->zJson, z, (size_t)n+1); - if( jsonParse(&p->sParse, 0, p->zJson) ){ - int rc = SQLITE_NOMEM; - if( p->sParse.oom==0 ){ - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); - if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; - } - jsonEachCursorReset(p); - return rc; - }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ - jsonEachCursorReset(p); - return SQLITE_NOMEM; - }else{ - JsonNode *pNode = 0; - if( idxNum==3 ){ - const char *zErr = 0; - zRoot = (const char*)sqlite3_value_text(argv[1]); - if( zRoot==0 ) return SQLITE_OK; - n = sqlite3_value_bytes(argv[1]); - p->zRoot = sqlite3_malloc64( n+1 ); - if( p->zRoot==0 ) return SQLITE_NOMEM; - memcpy(p->zRoot, zRoot, (size_t)n+1); - if( zRoot[0]!='$' ){ - zErr = zRoot; - }else{ - pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); - } - if( zErr ){ - sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); - jsonEachCursorReset(p); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; - }else if( pNode==0 ){ - return SQLITE_OK; - } - }else{ - pNode = p->sParse.aNode; - } - p->iBegin = p->i = (int)(pNode - p->sParse.aNode); - p->eType = pNode->eType; - if( p->eType>=JSON_ARRAY ){ - pNode->u.iKey = 0; - p->iEnd = p->i + pNode->n + 1; - if( p->bRecursive ){ - p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; - if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ - p->i--; - } - }else{ - p->i++; - } - }else{ - p->iEnd = p->i+1; - } + if( rc==SQLITE_OK ){ + rc = sessionRebase(p, pIter, xOutput, pOut, 0, 0); + sqlite3changeset_finalize(pIter); } - return SQLITE_OK; -} - -/* The methods of the json_each virtual table */ -static sqlite3_module jsonEachModule = { - 0, /* iVersion */ - 0, /* xCreate */ - jsonEachConnect, /* xConnect */ - jsonEachBestIndex, /* xBestIndex */ - jsonEachDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - jsonEachOpenEach, /* xOpen - open a cursor */ - jsonEachClose, /* xClose - close a cursor */ - jsonEachFilter, /* xFilter - configure scan constraints */ - jsonEachNext, /* xNext - advance a cursor */ - jsonEachEof, /* xEof - check for end of scan */ - jsonEachColumn, /* xColumn - read data */ - jsonEachRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ -}; -/* The methods of the json_tree virtual table. */ -static sqlite3_module jsonTreeModule = { - 0, /* iVersion */ - 0, /* xCreate */ - jsonEachConnect, /* xConnect */ - jsonEachBestIndex, /* xBestIndex */ - jsonEachDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - jsonEachOpenTree, /* xOpen - open a cursor */ - jsonEachClose, /* xClose - close a cursor */ - jsonEachFilter, /* xFilter - configure scan constraints */ - jsonEachNext, /* xNext - advance a cursor */ - jsonEachEof, /* xEof - check for end of scan */ - jsonEachColumn, /* xColumn - read data */ - jsonEachRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0 /* xRollbackTo */ -}; -#endif /* SQLITE_OMIT_VIRTUALTABLE */ + return rc; +} -/**************************************************************************** -** The following routines are the only publically visible identifiers in this -** file. Call the following routines in order to register the various SQL -** functions and the virtual table implemented by this file. -****************************************************************************/ +/* +** Destroy a rebaser object +*/ +SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){ + if( p ){ + sessionDeleteTable(0, p->grp.pList); + sqlite3_free(p); + } +} -SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){ +/* +** Global configuration +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg){ int rc = SQLITE_OK; - unsigned int i; - static const struct { - const char *zName; - int nArg; - int flag; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "json", 1, 0, jsonRemoveFunc }, - { "json_array", -1, 0, jsonArrayFunc }, - { "json_array_length", 1, 0, jsonArrayLengthFunc }, - { "json_array_length", 2, 0, jsonArrayLengthFunc }, - { "json_extract", -1, 0, jsonExtractFunc }, - { "json_insert", -1, 0, jsonSetFunc }, - { "json_object", -1, 0, jsonObjectFunc }, - { "json_quote", 1, 0, jsonQuoteFunc }, - { "json_remove", -1, 0, jsonRemoveFunc }, - { "json_replace", -1, 0, jsonReplaceFunc }, - { "json_set", -1, 1, jsonSetFunc }, - { "json_type", 1, 0, jsonTypeFunc }, - { "json_type", 2, 0, jsonTypeFunc }, - { "json_valid", 1, 0, jsonValidFunc }, - -#if SQLITE_DEBUG - /* DEBUG and TESTING functions */ - { "json_parse", 1, 0, jsonParseFunc }, - { "json_test1", 1, 0, jsonTest1Func }, -#endif - }; - static const struct { - const char *zName; - int nArg; - void (*xStep)(sqlite3_context*,int,sqlite3_value**); - void (*xFinal)(sqlite3_context*); - } aAgg[] = { - { "json_group_array", 1, jsonArrayStep, jsonArrayFinal }, - { "json_group_object", 2, jsonObjectStep, jsonObjectFinal }, - }; -#ifndef SQLITE_OMIT_VIRTUALTABLE - static const struct { - const char *zName; - sqlite3_module *pModule; - } aMod[] = { - { "json_each", &jsonEachModule }, - { "json_tree", &jsonTreeModule }, - }; -#endif - for(i=0; i0 ){ + sessions_strm_chunk_size = *pInt; + } + *pInt = sessions_strm_chunk_size; + break; + } + default: + rc = SQLITE_MISUSE; + break; } -#endif return rc; } +#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ -#ifndef SQLITE_CORE -#ifdef _WIN32 -__declspec(dllexport) -#endif -SQLITE_API int sqlite3_json_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi -){ - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - return sqlite3Json1Init(db); -} -#endif -#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */ - -/************** End of json1.c ***********************************************/ +/************** End of sqlite3session.c **************************************/ /************** Begin file fts5.c ********************************************/ -#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) -#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif #if defined(NDEBUG) && defined(SQLITE_DEBUG) @@ -180486,7 +216181,7 @@ SQLITE_API int sqlite3_json_init( ** ****************************************************************************** ** -** Interfaces to extend FTS5. Using the interfaces defined in this file, +** Interfaces to extend FTS5. Using the interfaces defined in this file, ** FTS5 may be extended with: ** ** * custom tokenizers, and @@ -180531,19 +216226,19 @@ struct Fts5PhraseIter { ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the context pointer the extension function was +** Return a copy of the context pointer the extension function was ** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the FTS5 table. Or, if iCol is ** non-negative but less than the number of columns in the table, return -** the total number of tokens in column iCol, considering all rows in +** the total number of tokens in column iCol, considering all rows in ** the FTS5 table. ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is +** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** xColumnCount(pFts): @@ -180557,7 +216252,7 @@ struct Fts5PhraseIter { ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is +** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** This function may be quite inefficient if used with an FTS5 table @@ -180584,8 +216279,8 @@ struct Fts5PhraseIter { ** an error code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always returns 0. ** ** xInst: @@ -180596,15 +216291,11 @@ struct Fts5PhraseIter { ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. The exception is if the table was created -** with the offsets=0 option specified. In this case *piOff is always -** set to -1. -** -** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) -** if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. +** "detail=none" or "detail=column" option. ** ** xRowid: ** Returns the rowid of the current row. @@ -180620,11 +216311,11 @@ struct Fts5PhraseIter { ** ** with $p set to a phrase equivalent to the phrase iPhrase of the ** current query is executed. Any column filter that applies to -** phrase iPhrase of the current query is included in $p. For each -** row visited, the callback function passed as the fourth argument -** is invoked. The context and API objects passed to the callback +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. -** Invoking Api.xUserData() returns a copy of the pointer passed as +** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the @@ -180639,14 +216330,14 @@ struct Fts5PhraseIter { ** ** xSetAuxdata(pFts5, pAux, xDelete) ** -** Save the pointer passed as the second argument as the extension functions +** Save the pointer passed as the second argument as the extension function's ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for -** each FTS query (MATCH expression). If the extension function is invoked -** more than once for a single FTS query, then all invocations share a +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a ** single auxiliary data context. ** ** If there is already an auxiliary data pointer when this function is @@ -180657,7 +216348,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -180665,7 +216356,7 @@ struct Fts5PhraseIter { ** ** xGetAuxdata(pFts5, bClear) ** -** Returns the current auxiliary data pointer for the fts5 extension +** Returns the current auxiliary data pointer for the fts5 extension ** function. See the xSetAuxdata() method for details. ** ** If the bClear argument is non-zero, then the auxiliary data is cleared @@ -180685,7 +216376,7 @@ struct Fts5PhraseIter { ** method, to iterate through all instances of a single query phrase within ** the current row. This is the same information as is accessible via the ** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient -** to use, this API may be faster under some circumstances. To iterate +** to use, this API may be faster under some circumstances. To iterate ** through instances of phrase iPhrase, use the following code: ** ** Fts5PhraseIter iter; @@ -180703,8 +216394,8 @@ struct Fts5PhraseIter { ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** @@ -180728,16 +216419,16 @@ struct Fts5PhraseIter { ** } ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" option. If the FTS5 table is created with either -** "detail=none" "content=" option (i.e. if it is a contentless table), -** then this API always iterates through an empty set (all calls to +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to ** xPhraseFirstColumn() set iCol to -1). ** ** The information accessed using this API and its companion ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext ** (or xInst/xInstCount). The chief advantage of this API is that it is ** significantly more efficient than those alternatives when used with -** "detail=column" tables. +** "detail=column" tables. ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. @@ -180751,7 +216442,7 @@ struct Fts5ExtensionApi { int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); - int (*xTokenize)(Fts5Context*, + int (*xTokenize)(Fts5Context*, const char *pText, int nText, /* Text to tokenize */ void *pCtx, /* Context passed to xToken() */ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ @@ -180780,15 +216471,15 @@ struct Fts5ExtensionApi { void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; -/* +/* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ /************************************************************************* ** CUSTOM TOKENIZERS ** -** Applications may also register custom tokenizer types. A tokenizer -** is registered by providing fts5 with a populated instance of the +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: @@ -180799,16 +216490,16 @@ struct Fts5ExtensionApi { ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object -** was registered with FTS5 (the third argument to xCreateTokenizer()). +** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used ** to create the FTS5 table. ** -** The final argument is an output variable. If successful, (*ppOut) +** The final argument is an output variable. If successful, (*ppOut) ** should be set to point to the new tokenizer handle and SQLITE_OK ** returned. If an error occurs, some value other than SQLITE_OK should -** be returned. In this case, fts5 assumes that the final value of *ppOut +** be returned. In this case, fts5 assumes that the final value of *ppOut ** is undefined. ** ** xDelete: @@ -180817,7 +216508,7 @@ struct Fts5ExtensionApi { ** be invoked exactly once for each successful call to xCreate(). ** ** xTokenize: -** This function is expected to tokenize the nText byte string indicated +** This function is expected to tokenize the nText byte string indicated ** by argument pText. pText may or may not be nul-terminated. The first ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). @@ -180831,8 +216522,8 @@ struct Fts5ExtensionApi { ** determine the set of tokens to add to (or delete from) the ** FTS index. ** -**
          • FTS5_TOKENIZE_QUERY - A MATCH query is being executed -** against the FTS index. The tokenizer is being called to tokenize +**
          • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize ** a bareword or quoted string specified as part of the query. ** **
          • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as @@ -180840,10 +216531,10 @@ struct Fts5ExtensionApi { ** followed by a "*" character, indicating that the last token ** returned by the tokenizer will be treated as a token prefix. ** -**
          • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +**
          • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to ** satisfy an fts5_api.xTokenize() request made by an auxiliary ** function. Or an fts5_api.xColumnSize() request made by the same -** on a columnsize=0 database. +** on a columnsize=0 database. ** ** ** For each token in the input string, the supplied callback xToken() must @@ -180855,10 +216546,10 @@ struct Fts5ExtensionApi { ** which the token is derived within the input. ** ** The second argument passed to the xToken() callback ("tflags") should -** normally be set to 0. The exception is if the tokenizer supports +** normally be set to 0. The exception is if the tokenizer supports ** synonyms. In this case see the discussion below for details. ** -** FTS5 assumes the xToken() callback is invoked for each token in the +** FTS5 assumes the xToken() callback is invoked for each token in the ** order that they occur within the input text. ** ** If an xToken() callback returns any value other than SQLITE_OK, then @@ -180872,7 +216563,7 @@ struct Fts5ExtensionApi { ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a -** user wishes to query for a phrase such as "first place". Using the +** user wishes to query for a phrase such as "first place". Using the ** built-in tokenizers, the FTS5 query 'first + place' will match instances ** of "first place" within the document set, but not alternative forms ** such as "1st place". In some applications, it would be better to match @@ -180881,8 +216572,8 @@ struct Fts5ExtensionApi { ** ** There are several ways to approach this in FTS5: ** -**
            1. By mapping all synonyms to a single token. In this case, the -** In the above example, this means that the tokenizer returns the +**
              1. By mapping all synonyms to a single token. In this case, using +** the above example, this means that the tokenizer returns the ** same token for inputs "first" and "1st". Say that token is in ** fact "first", so that when the user inserts the document "I won ** 1st place" entries are added to the index for tokens "i", "won", @@ -180890,37 +216581,37 @@ struct Fts5ExtensionApi { ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** -**
              2. By adding multiple synonyms for a single term to the FTS index. -** In this case, when tokenizing query text, the tokenizer may -** provide multiple synonyms for a single term within the document. -** FTS5 then queries the index for each synonym individually. For -** example, faced with the query: +**
              3. By querying the index for all synonyms of each query term +** separately. In this case, when tokenizing query text, the +** tokenizer may provide multiple synonyms for a single term +** within the document. FTS5 then queries the index for each +** synonym individually. For example, faced with the query: ** ** ** ... MATCH 'first place' ** ** the tokenizer offers both "1st" and "first" as synonyms for the -** first token in the MATCH query and FTS5 effectively runs a query +** first token in the MATCH query and FTS5 effectively runs a query ** similar to: ** ** ** ... MATCH '(first OR 1st) place' ** ** except that, for the purposes of auxiliary functions, the query -** still appears to contain just two phrases - "(first OR 1st)" +** still appears to contain just two phrases - "(first OR 1st)" ** being treated as a single phrase. ** **
              4. By adding multiple synonyms for a single term to the FTS index. ** Using this method, when tokenizing document text, the tokenizer -** provides multiple synonyms for each token. So that when a +** provides multiple synonyms for each token. So that when a ** document such as "I won first place" is tokenized, entries are ** added to the FTS index for "i", "won", "first", "1st" and ** "place". ** ** This way, even if the tokenizer does not provide synonyms -** when tokenizing query text (it should not - to do would be -** inefficient), it doesn't matter if the user queries for -** 'first + place' or '1st + place', as there are entires in the +** when tokenizing query text (it should not - to do so would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. **
              ** @@ -180940,15 +216631,15 @@ struct Fts5ExtensionApi { ** ** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time ** xToken() is called. Multiple synonyms may be specified for a single token -** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. ** There is no limit to the number of synonyms that may be provided for a ** single token. ** -** In many cases, method (1) above is the best approach. It does not add +** In many cases, method (1) above is the best approach. It does not add ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the -** token "first" is subsituted for "1st" by the tokenizer, then the query: +** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** ** ... MATCH '1s*' @@ -180956,18 +216647,18 @@ struct Fts5ExtensionApi { ** will not match documents that contain the token "1st" (as the tokenizer ** will probably not map "1s" to any prefix of "first"). ** -** For full prefix support, method (3) may be preferred. In this case, +** For full prefix support, method (3) may be preferred. In this case, ** because the index contains entries for both "first" and "1st", prefix ** queries such as 'fi*' or '1s*' will match correctly. However, because ** extra entries are added to the FTS index, this method uses more space ** within the database. ** ** Method (2) offers a midpoint between (1) and (3). Using this method, -** a query such as '1s*' will match documents that contain the literal +** a query such as '1s*' will match documents that contain the literal ** token "1st", but not "first" (assuming the tokenizer is not able to ** provide synonyms for prefixes). However, a non-prefix query like '1st' ** will match against "1st" and "first". This method does not require -** extra disk space, as no extra entries are added to the FTS index. +** extra disk space, as no extra entries are added to the FTS index. ** On the other hand, it may require more CPU cycles to run MATCH queries, ** as separate queries of the FTS index are required for each synonym. ** @@ -180981,10 +216672,10 @@ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, + int (*xTokenize)(Fts5Tokenizer*, void *pCtx, int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, + const char *pText, int nText, int (*xToken)( void *pCtx, /* Copy of 2nd argument to xTokenize() */ int tflags, /* Mask of FTS5_TOKEN_* flags */ @@ -181086,11 +216777,25 @@ typedef short i16; typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; -#define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) +#ifndef ArraySize +# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) +#endif #define testcase(x) -#define ALWAYS(x) 1 -#define NEVER(x) 0 + +#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) +# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1 +#endif +#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS) +# define ALWAYS(X) (1) +# define NEVER(X) (0) +#elif !defined(NDEBUG) +# define ALWAYS(X) ((X)?1:(assert(0),0)) +# define NEVER(X) ((X)?(assert(0),1):0) +#else +# define ALWAYS(X) (X) +# define NEVER(X) (X) +#endif #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) @@ -181103,7 +216808,7 @@ typedef sqlite3_uint64 u64; #endif -/* Truncate very long tokens to this many bytes. Hard limit is +/* Truncate very long tokens to this many bytes. Hard limit is ** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset ** field that occurs at the start of each leaf page (see fts5_index.c). */ #define FTS5_MAX_TOKEN_SIZE 32768 @@ -181115,6 +216820,11 @@ typedef sqlite3_uint64 u64; */ #define FTS5_MAX_PREFIX_INDEXES 31 +/* +** Maximum segments permitted in a single index +*/ +#define FTS5_MAX_SEGMENT 2000 + #define FTS5_DEFAULT_NEARDIST 10 #define FTS5_DEFAULT_RANK "bm25" @@ -181131,7 +216841,7 @@ static int sqlite3Fts5Corrupt(void); /* ** The assert_nc() macro is similar to the assert() macro, except that it -** is used for assert() conditions that are true only if it can be +** is used for assert() conditions that are true only if it can be ** guranteed that the database is not corrupt. */ #ifdef SQLITE_DEBUG @@ -181141,6 +216851,12 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt; # define assert_nc(x) assert(x) #endif +/* +** A version of memcmp() that does not cause asan errors if one of the pointer +** parameters is NULL and the number of bytes to compare is zero. +*/ +#define fts5Memcmp(s1, s2, n) ((n)<=0 ? 0 : memcmp((s1), (s2), (n))) + /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ #ifndef UNUSED_PARAM @@ -181154,7 +216870,7 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt; typedef struct Fts5Global Fts5Global; typedef struct Fts5Colset Fts5Colset; -/* If a NEAR() clump or phrase may only match a specific set of columns, +/* If a NEAR() clump or phrase may only match a specific set of columns, ** then an object of the following type is used to record the set of columns. ** Each entry in the aiCol[] array is a column that may be matched. ** @@ -181182,20 +216898,20 @@ typedef struct Fts5Config Fts5Config; ** ** nAutomerge: ** The minimum number of segments that an auto-merge operation should -** attempt to merge together. A value of 1 sets the object to use the +** attempt to merge together. A value of 1 sets the object to use the ** compile time default. Zero disables auto-merge altogether. ** ** zContent: ** ** zContentRowid: -** The value of the content_rowid= option, if one was specified. Or +** The value of the content_rowid= option, if one was specified. Or ** the string "rowid" otherwise. This text is not quoted - if it is ** used as part of an SQL statement it needs to be quoted appropriately. ** ** zContentExprlist: ** ** pzErrmsg: -** This exists in order to allow the fts5_index.c module to return a +** This exists in order to allow the fts5_index.c module to return a ** decent error message if it encounters a file-format version it does ** not understand. ** @@ -181219,13 +216935,15 @@ struct Fts5Config { int nPrefix; /* Number of prefix indexes */ int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */ int eContent; /* An FTS5_CONTENT value */ - char *zContent; /* content table */ - char *zContentRowid; /* "content_rowid=" option value */ + char *zContent; /* content table */ + char *zContentRowid; /* "content_rowid=" option value */ int bColumnsize; /* "columnsize=" option value (dflt==1) */ int eDetail; /* FTS5_DETAIL_XXX value */ char *zContentExprlist; Fts5Tokenizer *pTok; fts5_tokenizer *pTokApi; + int bLock; /* True when table is preparing statement */ + int ePattern; /* FTS_PATTERN_XXX constant */ /* Values loaded from the %_config table */ int iCookie; /* Incremented when %_config is modified */ @@ -181246,17 +216964,19 @@ struct Fts5Config { }; /* Current expected value of %_config table 'version' field */ -#define FTS5_CURRENT_VERSION 4 +#define FTS5_CURRENT_VERSION 4 #define FTS5_CONTENT_NORMAL 0 #define FTS5_CONTENT_NONE 1 #define FTS5_CONTENT_EXTERNAL 2 -#define FTS5_DETAIL_FULL 0 -#define FTS5_DETAIL_NONE 1 -#define FTS5_DETAIL_COLUMNS 2 - +#define FTS5_DETAIL_FULL 0 +#define FTS5_DETAIL_NONE 1 +#define FTS5_DETAIL_COLUMNS 2 +#define FTS5_PATTERN_NONE 0 +#define FTS5_PATTERN_LIKE 65 /* matches SQLITE_INDEX_CONSTRAINT_LIKE */ +#define FTS5_PATTERN_GLOB 66 /* matches SQLITE_INDEX_CONSTRAINT_GLOB */ static int sqlite3Fts5ConfigParse( Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char** @@ -181328,7 +217048,7 @@ static void sqlite3Fts5Put32(u8*, int); static int sqlite3Fts5Get32(const u8*); #define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) -#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF) +#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF) typedef struct Fts5PoslistReader Fts5PoslistReader; struct Fts5PoslistReader { @@ -181363,7 +217083,7 @@ static int sqlite3Fts5PoslistNext64( ); /* Malloc utility */ -static void *sqlite3Fts5MallocZero(int *pRc, int nByte); +static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte); static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn); /* Character set tests (like isspace(), isalpha() etc.) */ @@ -181421,27 +217141,27 @@ static int sqlite3Fts5IndexClose(Fts5Index *p); ** Return a simple checksum value based on the arguments. */ static u64 sqlite3Fts5IndexEntryCksum( - i64 iRowid, - int iCol, - int iPos, + i64 iRowid, + int iCol, + int iPos, int iIdx, const char *pTerm, int nTerm ); /* -** Argument p points to a buffer containing utf-8 text that is n bytes in +** Argument p points to a buffer containing utf-8 text that is n bytes in ** size. Return the number of bytes in the nChar character prefix of the ** buffer, or 0 if there are less than nChar characters in total. */ static int sqlite3Fts5IndexCharlenToBytelen( - const char *p, - int nByte, + const char *p, + int nByte, int nChar ); /* -** Open a new iterator to iterate though all rowids that match the +** Open a new iterator to iterate though all rowids that match the ** specified token or token prefix. */ static int sqlite3Fts5IndexQuery( @@ -181464,15 +217184,23 @@ static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch); */ static void sqlite3Fts5IterClose(Fts5IndexIter*); +/* +** Close the reader blob handle, if it is open. +*/ +static void sqlite3Fts5IndexCloseReader(Fts5Index*); + /* ** This interface is used by the fts5vocab module. */ static const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*); static int sqlite3Fts5IterNextScan(Fts5IndexIter*); +static void *sqlite3Fts5StructureRef(Fts5Index*); +static void sqlite3Fts5StructureRelease(void*); +static int sqlite3Fts5StructureTest(Fts5Index*, void*); /* -** Insert or remove data to or from the index. Each time a document is +** Insert or remove data to or from the index. Each time a document is ** added to or removed from the index, this function is called one or more ** times. ** @@ -181500,14 +217228,14 @@ static int sqlite3Fts5IndexBeginWrite( /* ** Flush any data stored in the in-memory hash tables to the database. -** If the bCommit flag is true, also close any open blob handles. +** Also close any open blob handles. */ -static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit); +static int sqlite3Fts5IndexSync(Fts5Index *p); /* ** Discard any data stored in the in-memory hash tables. Do not write it ** to the database. Additionally, assume that the contents of the %_data -** table may have changed on disk. So any in-memory caches of %_data +** table may have changed on disk. So any in-memory caches of %_data ** records must be invalidated. */ static int sqlite3Fts5IndexRollback(Fts5Index *p); @@ -181521,18 +217249,18 @@ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); /* ** Functions called by the storage module as part of integrity-check. */ -static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum); +static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum, int bUseCksum); -/* -** Called during virtual module initialization to register UDF -** fts5_decode() with SQLite +/* +** Called during virtual module initialization to register UDF +** fts5_decode() with SQLite */ static int sqlite3Fts5IndexInit(sqlite3*); static int sqlite3Fts5IndexSetCookie(Fts5Index*, int); /* -** Return the total number of entries read from the %_data table by +** Return the total number of entries read from the %_data table by ** this connection since it was created. */ static int sqlite3Fts5IndexReads(Fts5Index *p); @@ -181549,7 +217277,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p); **************************************************************************/ /************************************************************************** -** Interface to code in fts5_varint.c. +** Interface to code in fts5_varint.c. */ static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v); static int sqlite3Fts5GetVarintLen(u32 iVal); @@ -181574,26 +217302,37 @@ static int sqlite3Fts5PutVarint(unsigned char *p, u64 v); /************************************************************************** -** Interface to code in fts5.c. +** Interface to code in fts5_main.c. +*/ + +/* +** Virtual-table object. */ +typedef struct Fts5Table Fts5Table; +struct Fts5Table { + sqlite3_vtab base; /* Base class used by SQLite core */ + Fts5Config *pConfig; /* Virtual table configuration */ + Fts5Index *pIndex; /* Full-text index */ +}; static int sqlite3Fts5GetTokenizer( - Fts5Global*, + Fts5Global*, const char **azArg, int nArg, - Fts5Tokenizer**, - fts5_tokenizer**, + Fts5Config*, char **pzErr ); -static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **); +static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); + +static int sqlite3Fts5FlushToDisk(Fts5Table*); /* ** End of interface to code in fts5.c. **************************************************************************/ /************************************************************************** -** Interface to code in fts5_hash.c. +** Interface to code in fts5_hash.c. */ typedef struct Fts5Hash Fts5Hash; @@ -181619,8 +217358,9 @@ static void sqlite3Fts5HashClear(Fts5Hash*); static int sqlite3Fts5HashQuery( Fts5Hash*, /* Hash table to query */ + int nPre, const char *pTerm, int nTerm, /* Query term */ - const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + void **ppObj, /* OUT: Pointer to doclist for pTerm */ int *pnDoclist /* OUT: Size of doclist in bytes */ ); @@ -181642,7 +217382,7 @@ static void sqlite3Fts5HashScanEntry(Fts5Hash *, **************************************************************************/ /************************************************************************** -** Interface to code in fts5_storage.c. fts5_storage.c contains contains +** Interface to code in fts5_storage.c. fts5_storage.c contains contains ** code to access the data stored in the %_content and %_docsize tables. */ @@ -181663,7 +217403,7 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); -static int sqlite3Fts5StorageIntegrity(Fts5Storage *p); +static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg); static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**); static void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*); @@ -181672,7 +217412,7 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol); static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg); static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow); -static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit); +static int sqlite3Fts5StorageSync(Fts5Storage *p); static int sqlite3Fts5StorageRollback(Fts5Storage *p); static int sqlite3Fts5StorageConfigValue( @@ -181691,7 +217431,7 @@ static int sqlite3Fts5StorageReset(Fts5Storage *p); /************************************************************************** -** Interface to code in fts5_expr.c. +** Interface to code in fts5_expr.c. */ typedef struct Fts5Expr Fts5Expr; typedef struct Fts5ExprNode Fts5ExprNode; @@ -181707,11 +217447,20 @@ struct Fts5Token { /* Parse a MATCH expression. */ static int sqlite3Fts5ExprNew( - Fts5Config *pConfig, + Fts5Config *pConfig, + int bPhraseToAnd, + int iCol, /* Column on LHS of MATCH operator */ const char *zExpr, - Fts5Expr **ppNew, + Fts5Expr **ppNew, char **pzErr ); +static int sqlite3Fts5ExprPattern( + Fts5Config *pConfig, + int bGlob, + int iCol, + const char *zText, + Fts5Expr **pp +); /* ** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc); @@ -181728,6 +217477,7 @@ static int sqlite3Fts5ExprEof(Fts5Expr*); static i64 sqlite3Fts5ExprRowid(Fts5Expr*); static void sqlite3Fts5ExprFree(Fts5Expr*); +static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2); /* Called during startup to register a UDF with SQLite */ static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*); @@ -181769,21 +217519,23 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( ); static Fts5ExprPhrase *sqlite3Fts5ParseTerm( - Fts5Parse *pParse, - Fts5ExprPhrase *pPhrase, + Fts5Parse *pParse, + Fts5ExprPhrase *pPhrase, Fts5Token *pToken, int bPrefix ); +static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase*); + static Fts5ExprNearset *sqlite3Fts5ParseNearset( - Fts5Parse*, + Fts5Parse*, Fts5ExprNearset*, - Fts5ExprPhrase* + Fts5ExprPhrase* ); static Fts5Colset *sqlite3Fts5ParseColset( - Fts5Parse*, - Fts5Colset*, + Fts5Parse*, + Fts5Colset*, Fts5Token * ); @@ -181792,7 +217544,7 @@ static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); -static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); +static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*); static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*); static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); @@ -181804,7 +217556,7 @@ static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); /************************************************************************** -** Interface to code in fts5_aux.c. +** Interface to code in fts5_aux.c. */ static int sqlite3Fts5AuxInit(fts5_api*); @@ -181813,16 +217565,20 @@ static int sqlite3Fts5AuxInit(fts5_api*); **************************************************************************/ /************************************************************************** -** Interface to code in fts5_tokenizer.c. +** Interface to code in fts5_tokenizer.c. */ static int sqlite3Fts5TokenizerInit(fts5_api*); +static int sqlite3Fts5TokenizerPattern( + int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), + Fts5Tokenizer *pTok +); /* ** End of interface to code in fts5_tokenizer.c. **************************************************************************/ /************************************************************************** -** Interface to code in fts5_vocab.c. +** Interface to code in fts5_vocab.c. */ static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*); @@ -181833,11 +217589,14 @@ static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*); /************************************************************************** -** Interface to automatically generated code in fts5_unicode2.c. +** Interface to automatically generated code in fts5_unicode2.c. */ -static int sqlite3Fts5UnicodeIsalnum(int c); static int sqlite3Fts5UnicodeIsdiacritic(int c); static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); + +static int sqlite3Fts5UnicodeCatParse(const char*, u8*); +static int sqlite3Fts5UnicodeCategory(u32 iCode); +static void sqlite3Fts5UnicodeAscii(u8*, u8*); /* ** End of interface to code in fts5_unicode2.c. **************************************************************************/ @@ -181849,16 +217608,19 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); #define FTS5_NOT 3 #define FTS5_TERM 4 #define FTS5_COLON 5 -#define FTS5_LP 6 -#define FTS5_RP 7 -#define FTS5_MINUS 8 -#define FTS5_LCP 9 -#define FTS5_RCP 10 -#define FTS5_STRING 11 -#define FTS5_COMMA 12 -#define FTS5_PLUS 13 -#define FTS5_STAR 14 - +#define FTS5_MINUS 6 +#define FTS5_LCP 7 +#define FTS5_RCP 8 +#define FTS5_STRING 9 +#define FTS5_LP 10 +#define FTS5_RP 11 +#define FTS5_CARET 12 +#define FTS5_COMMA 13 +#define FTS5_PLUS 14 +#define FTS5_STAR 15 + +/* This file is automatically generated by Lemon from input grammar +** source file "fts5parse.y". */ /* ** 2000-05-29 ** @@ -181883,7 +217645,6 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); ** The following is the concatenation of all %include directives from the ** input grammar file: */ -/* #include */ /************ Begin %include sections from the grammar ************************/ /* #include "fts5Int.h" */ @@ -181913,11 +217674,26 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); #define fts5YYMALLOCARGTYPE u64 /**************** End of %include directives **********************************/ -/* These constants specify the various numeric values for terminal symbols -** in a format understandable to "makeheaders". This section is blank unless -** "lemon" is run with the "-m" command-line option. -***************** Begin makeheaders token definitions *************************/ -/**************** End makeheaders token definitions ***************************/ +/* These constants specify the various numeric values for terminal symbols. +***************** Begin token definitions *************************************/ +#ifndef FTS5_OR +#define FTS5_OR 1 +#define FTS5_AND 2 +#define FTS5_NOT 3 +#define FTS5_TERM 4 +#define FTS5_COLON 5 +#define FTS5_MINUS 6 +#define FTS5_LCP 7 +#define FTS5_RCP 8 +#define FTS5_STRING 9 +#define FTS5_LP 10 +#define FTS5_RP 11 +#define FTS5_CARET 12 +#define FTS5_COMMA 13 +#define FTS5_PLUS 14 +#define FTS5_STAR 15 +#endif +/**************** End token definitions ***************************************/ /* The next sections is a series of control #defines. ** various aspects of the generated parser. @@ -181942,7 +217718,7 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); ** the minor type might be the name of the identifier. ** Each non-terminal can have a different minor type. ** Terminal symbols all have the same minor type, though. -** This macros defines the minor type for terminal +** This macros defines the minor type for terminal ** symbols. ** fts5YYMINORTYPE is the data type used for all minor types. ** This is typically a union of many types, one of @@ -181952,26 +217728,30 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); ** zero the stack is dynamically sized using realloc() ** sqlite3Fts5ParserARG_SDECL A static variable declaration for the %extra_argument ** sqlite3Fts5ParserARG_PDECL A parameter declaration for the %extra_argument +** sqlite3Fts5ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter ** sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser ** sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser +** sqlite3Fts5ParserCTX_* As sqlite3Fts5ParserARG_ except for %extra_context ** fts5YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. ** fts5YYNSTATE the combined number of states. ** fts5YYNRULE the number of rules in the grammar +** fts5YYNFTS5TOKEN Number of terminal symbols ** fts5YY_MAX_SHIFT Maximum value for shift actions ** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions ** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** fts5YY_MIN_REDUCE Maximum value for reduce actions ** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error ** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept ** fts5YY_NO_ACTION The fts5yy_action[] code for no-op +** fts5YY_MIN_REDUCE Minimum value for reduce actions +** fts5YY_MAX_REDUCE Maximum value for reduce actions */ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ #define fts5YYCODETYPE unsigned char -#define fts5YYNOCODE 28 +#define fts5YYNOCODE 27 #define fts5YYACTIONTYPE unsigned char #define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token typedef union { @@ -181988,19 +217768,28 @@ typedef union { #endif #define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse; #define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse -#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse -#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse -#define fts5YYNSTATE 29 -#define fts5YYNRULE 26 -#define fts5YY_MAX_SHIFT 28 -#define fts5YY_MIN_SHIFTREDUCE 45 -#define fts5YY_MAX_SHIFTREDUCE 70 -#define fts5YY_MIN_REDUCE 71 -#define fts5YY_MAX_REDUCE 96 -#define fts5YY_ERROR_ACTION 97 -#define fts5YY_ACCEPT_ACTION 98 -#define fts5YY_NO_ACTION 99 +#define sqlite3Fts5ParserARG_PARAM ,pParse +#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse; +#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse; +#define sqlite3Fts5ParserCTX_SDECL +#define sqlite3Fts5ParserCTX_PDECL +#define sqlite3Fts5ParserCTX_PARAM +#define sqlite3Fts5ParserCTX_FETCH +#define sqlite3Fts5ParserCTX_STORE +#define fts5YYNSTATE 35 +#define fts5YYNRULE 28 +#define fts5YYNRULE_WITH_ACTION 28 +#define fts5YYNFTS5TOKEN 16 +#define fts5YY_MAX_SHIFT 34 +#define fts5YY_MIN_SHIFTREDUCE 52 +#define fts5YY_MAX_SHIFTREDUCE 79 +#define fts5YY_ERROR_ACTION 80 +#define fts5YY_ACCEPT_ACTION 81 +#define fts5YY_NO_ACTION 82 +#define fts5YY_MIN_REDUCE 83 +#define fts5YY_MAX_REDUCE 110 /************* End control #defines *******************************************/ +#define fts5YY_NLOOKAHEAD ((int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0]))) /* Define the fts5yytestcase() macro to be a no-op if is not already defined ** otherwise. @@ -182018,7 +217807,7 @@ typedef union { /* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an -** action integer. +** action integer. ** ** Suppose the action integer is N. Then the action is determined as ** follows @@ -182029,9 +217818,6 @@ typedef union { ** N between fts5YY_MIN_SHIFTREDUCE Shift to an arbitrary state then ** and fts5YY_MAX_SHIFTREDUCE reduce by rule N-fts5YY_MIN_SHIFTREDUCE. ** -** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE -** and fts5YY_MAX_REDUCE -** ** N == fts5YY_ERROR_ACTION A syntax error has occurred. ** ** N == fts5YY_ACCEPT_ACTION The parser accepts its input. @@ -182039,25 +217825,22 @@ typedef union { ** N == fts5YY_NO_ACTION No such action. Denotes unused ** slots in the fts5yy_action[] table. ** +** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE +** and fts5YY_MAX_REDUCE +** ** The action table is constructed as a single large table named fts5yy_action[]. ** Given state S and lookahead X, the action is computed as either: ** ** (A) N = fts5yy_action[ fts5yy_shift_ofst[S] + X ] ** (B) N = fts5yy_default[S] ** -** The (A) formula is preferred. The B formula is used instead if: -** (1) The fts5yy_shift_ofst[S]+X value is out of range, or -** (2) fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X, or -** (3) fts5yy_shift_ofst[S] equal fts5YY_SHIFT_USE_DFLT. -** (Implementation note: fts5YY_SHIFT_USE_DFLT is chosen so that -** fts5YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. -** Hence only tests (1) and (2) need to be evaluated.) +** The (A) formula is preferred. The B formula is used instead if +** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X. ** ** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of -** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of -** fts5YY_SHIFT_USE_DFLT. +** the fts5yy_shift_ofst[] array. ** ** The following are the tables generated in this section: ** @@ -182071,56 +217854,62 @@ typedef union { ** fts5yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define fts5YY_ACTTAB_COUNT (85) +#define fts5YY_ACTTAB_COUNT (105) static const fts5YYACTIONTYPE fts5yy_action[] = { - /* 0 */ 98, 16, 51, 5, 53, 27, 83, 7, 26, 15, - /* 10 */ 51, 5, 53, 27, 13, 69, 26, 48, 51, 5, - /* 20 */ 53, 27, 19, 11, 26, 9, 20, 51, 5, 53, - /* 30 */ 27, 13, 22, 26, 28, 51, 5, 53, 27, 68, - /* 40 */ 1, 26, 19, 11, 17, 9, 52, 10, 53, 27, - /* 50 */ 23, 24, 26, 54, 3, 4, 2, 26, 6, 21, - /* 60 */ 49, 71, 3, 4, 2, 7, 56, 59, 55, 59, - /* 70 */ 4, 2, 12, 69, 58, 60, 18, 67, 62, 69, - /* 80 */ 25, 66, 8, 14, 2, + /* 0 */ 81, 20, 96, 6, 28, 99, 98, 26, 26, 18, + /* 10 */ 96, 6, 28, 17, 98, 56, 26, 19, 96, 6, + /* 20 */ 28, 14, 98, 14, 26, 31, 92, 96, 6, 28, + /* 30 */ 108, 98, 25, 26, 21, 96, 6, 28, 78, 98, + /* 40 */ 58, 26, 29, 96, 6, 28, 107, 98, 22, 26, + /* 50 */ 24, 16, 12, 11, 1, 13, 13, 24, 16, 23, + /* 60 */ 11, 33, 34, 13, 97, 8, 27, 32, 98, 7, + /* 70 */ 26, 3, 4, 5, 3, 4, 5, 3, 83, 4, + /* 80 */ 5, 3, 63, 5, 3, 62, 12, 2, 86, 13, + /* 90 */ 9, 30, 10, 10, 54, 57, 75, 78, 78, 53, + /* 100 */ 57, 15, 82, 82, 71, }; static const fts5YYCODETYPE fts5yy_lookahead[] = { - /* 0 */ 16, 17, 18, 19, 20, 21, 5, 6, 24, 17, - /* 10 */ 18, 19, 20, 21, 11, 14, 24, 17, 18, 19, - /* 20 */ 20, 21, 8, 9, 24, 11, 17, 18, 19, 20, - /* 30 */ 21, 11, 12, 24, 17, 18, 19, 20, 21, 26, - /* 40 */ 6, 24, 8, 9, 22, 11, 18, 11, 20, 21, - /* 50 */ 24, 25, 24, 20, 1, 2, 3, 24, 23, 24, - /* 60 */ 7, 0, 1, 2, 3, 6, 10, 11, 10, 11, - /* 70 */ 2, 3, 9, 14, 11, 11, 22, 26, 7, 14, - /* 80 */ 13, 11, 5, 11, 3, + /* 0 */ 16, 17, 18, 19, 20, 22, 22, 24, 24, 17, + /* 10 */ 18, 19, 20, 7, 22, 9, 24, 17, 18, 19, + /* 20 */ 20, 9, 22, 9, 24, 13, 17, 18, 19, 20, + /* 30 */ 26, 22, 24, 24, 17, 18, 19, 20, 15, 22, + /* 40 */ 9, 24, 17, 18, 19, 20, 26, 22, 21, 24, + /* 50 */ 6, 7, 9, 9, 10, 12, 12, 6, 7, 21, + /* 60 */ 9, 24, 25, 12, 18, 5, 20, 14, 22, 5, + /* 70 */ 24, 3, 1, 2, 3, 1, 2, 3, 0, 1, + /* 80 */ 2, 3, 11, 2, 3, 11, 9, 10, 5, 12, + /* 90 */ 23, 24, 10, 10, 8, 9, 9, 15, 15, 8, + /* 100 */ 9, 9, 27, 27, 11, 27, 27, 27, 27, 27, + /* 110 */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + /* 120 */ 27, }; -#define fts5YY_SHIFT_USE_DFLT (85) -#define fts5YY_SHIFT_COUNT (28) +#define fts5YY_SHIFT_COUNT (34) #define fts5YY_SHIFT_MIN (0) -#define fts5YY_SHIFT_MAX (81) +#define fts5YY_SHIFT_MAX (93) static const unsigned char fts5yy_shift_ofst[] = { - /* 0 */ 34, 34, 34, 34, 34, 14, 20, 3, 36, 1, - /* 10 */ 59, 64, 64, 65, 65, 53, 61, 56, 58, 63, - /* 20 */ 68, 67, 70, 67, 71, 72, 67, 77, 81, + /* 0 */ 44, 44, 44, 44, 44, 44, 51, 77, 43, 12, + /* 10 */ 14, 83, 82, 14, 23, 23, 31, 31, 71, 74, + /* 20 */ 78, 81, 86, 91, 6, 53, 53, 60, 64, 68, + /* 30 */ 53, 87, 92, 53, 93, }; -#define fts5YY_REDUCE_USE_DFLT (-17) -#define fts5YY_REDUCE_COUNT (14) -#define fts5YY_REDUCE_MIN (-16) -#define fts5YY_REDUCE_MAX (54) +#define fts5YY_REDUCE_COUNT (17) +#define fts5YY_REDUCE_MIN (-17) +#define fts5YY_REDUCE_MAX (67) static const signed char fts5yy_reduce_ofst[] = { - /* 0 */ -16, -8, 0, 9, 17, 28, 26, 35, 33, 13, - /* 10 */ 13, 22, 54, 13, 51, + /* 0 */ -16, -8, 0, 9, 17, 25, 46, -17, -17, 37, + /* 10 */ 67, 4, 4, 8, 4, 20, 27, 38, }; static const fts5YYACTIONTYPE fts5yy_default[] = { - /* 0 */ 97, 97, 97, 97, 97, 76, 91, 97, 97, 96, - /* 10 */ 96, 97, 97, 96, 96, 97, 97, 97, 97, 97, - /* 20 */ 73, 89, 97, 90, 97, 97, 87, 97, 72, + /* 0 */ 80, 80, 80, 80, 80, 80, 95, 80, 80, 105, + /* 10 */ 80, 110, 110, 80, 110, 110, 80, 80, 80, 80, + /* 20 */ 80, 91, 80, 80, 80, 101, 100, 80, 80, 90, + /* 30 */ 103, 80, 80, 104, 80, }; /********** End of lemon-generated parsing tables *****************************/ -/* The next table maps tokens (terminal symbols) into fallback tokens. +/* The next table maps tokens (terminal symbols) into fallback tokens. ** If a construct like the following: -** +** ** %fallback ID X Y Z. ** ** appears in the grammar, then ID becomes a fallback token for X, Y, @@ -182173,16 +217962,19 @@ struct fts5yyParser { int fts5yyerrcnt; /* Shifts left before out of the error */ #endif sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */ + sqlite3Fts5ParserCTX_SDECL /* A place to hold %extra_context */ #if fts5YYSTACKDEPTH<=0 int fts5yystksz; /* Current side of the stack */ fts5yyStackEntry *fts5yystack; /* The parser's stack */ fts5yyStackEntry fts5yystk0; /* First stack entry */ #else fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */ + fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */ #endif }; typedef struct fts5yyParser fts5yyParser; +/* #include */ #ifndef NDEBUG /* #include */ static FILE *fts5yyTraceFILE = 0; @@ -182190,10 +217982,10 @@ static char *fts5yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG -/* +/* ** Turn parser tracing on by giving a stream to which to write the trace ** and a prompt to preface each trace message. Tracing is turned off -** by making either argument NULL +** by making either argument NULL ** ** Inputs: **
                @@ -182215,50 +218007,72 @@ static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){ } #endif /* NDEBUG */ -#ifndef NDEBUG +#if defined(fts5YYCOVERAGE) || !defined(NDEBUG) /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ -static const char *const fts5yyTokenName[] = { - "$", "OR", "AND", "NOT", - "TERM", "COLON", "LP", "RP", - "MINUS", "LCP", "RCP", "STRING", - "COMMA", "PLUS", "STAR", "error", - "input", "expr", "cnearset", "exprlist", - "nearset", "colset", "colsetlist", "nearphrases", - "phrase", "neardist_opt", "star_opt", +static const char *const fts5yyTokenName[] = { + /* 0 */ "$", + /* 1 */ "OR", + /* 2 */ "AND", + /* 3 */ "NOT", + /* 4 */ "TERM", + /* 5 */ "COLON", + /* 6 */ "MINUS", + /* 7 */ "LCP", + /* 8 */ "RCP", + /* 9 */ "STRING", + /* 10 */ "LP", + /* 11 */ "RP", + /* 12 */ "CARET", + /* 13 */ "COMMA", + /* 14 */ "PLUS", + /* 15 */ "STAR", + /* 16 */ "input", + /* 17 */ "expr", + /* 18 */ "cnearset", + /* 19 */ "exprlist", + /* 20 */ "colset", + /* 21 */ "colsetlist", + /* 22 */ "nearset", + /* 23 */ "nearphrases", + /* 24 */ "phrase", + /* 25 */ "neardist_opt", + /* 26 */ "star_opt", }; -#endif /* NDEBUG */ +#endif /* defined(fts5YYCOVERAGE) || !defined(NDEBUG) */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. */ static const char *const fts5yyRuleName[] = { /* 0 */ "input ::= expr", - /* 1 */ "expr ::= expr AND expr", - /* 2 */ "expr ::= expr OR expr", - /* 3 */ "expr ::= expr NOT expr", - /* 4 */ "expr ::= LP expr RP", - /* 5 */ "expr ::= exprlist", - /* 6 */ "exprlist ::= cnearset", - /* 7 */ "exprlist ::= exprlist cnearset", - /* 8 */ "cnearset ::= nearset", - /* 9 */ "cnearset ::= colset COLON nearset", - /* 10 */ "colset ::= MINUS LCP colsetlist RCP", - /* 11 */ "colset ::= LCP colsetlist RCP", - /* 12 */ "colset ::= STRING", - /* 13 */ "colset ::= MINUS STRING", - /* 14 */ "colsetlist ::= colsetlist STRING", - /* 15 */ "colsetlist ::= STRING", - /* 16 */ "nearset ::= phrase", - /* 17 */ "nearset ::= STRING LP nearphrases neardist_opt RP", - /* 18 */ "nearphrases ::= phrase", - /* 19 */ "nearphrases ::= nearphrases phrase", - /* 20 */ "neardist_opt ::=", - /* 21 */ "neardist_opt ::= COMMA STRING", - /* 22 */ "phrase ::= phrase PLUS STRING star_opt", - /* 23 */ "phrase ::= STRING star_opt", - /* 24 */ "star_opt ::= STAR", - /* 25 */ "star_opt ::=", + /* 1 */ "colset ::= MINUS LCP colsetlist RCP", + /* 2 */ "colset ::= LCP colsetlist RCP", + /* 3 */ "colset ::= STRING", + /* 4 */ "colset ::= MINUS STRING", + /* 5 */ "colsetlist ::= colsetlist STRING", + /* 6 */ "colsetlist ::= STRING", + /* 7 */ "expr ::= expr AND expr", + /* 8 */ "expr ::= expr OR expr", + /* 9 */ "expr ::= expr NOT expr", + /* 10 */ "expr ::= colset COLON LP expr RP", + /* 11 */ "expr ::= LP expr RP", + /* 12 */ "expr ::= exprlist", + /* 13 */ "exprlist ::= cnearset", + /* 14 */ "exprlist ::= exprlist cnearset", + /* 15 */ "cnearset ::= nearset", + /* 16 */ "cnearset ::= colset COLON nearset", + /* 17 */ "nearset ::= phrase", + /* 18 */ "nearset ::= CARET phrase", + /* 19 */ "nearset ::= STRING LP nearphrases neardist_opt RP", + /* 20 */ "nearphrases ::= phrase", + /* 21 */ "nearphrases ::= nearphrases phrase", + /* 22 */ "neardist_opt ::=", + /* 23 */ "neardist_opt ::= COMMA STRING", + /* 24 */ "phrase ::= phrase PLUS STRING star_opt", + /* 25 */ "phrase ::= STRING star_opt", + /* 26 */ "star_opt ::= STAR", + /* 27 */ "star_opt ::=", }; #endif /* NDEBUG */ @@ -182292,7 +218106,7 @@ static int fts5yyGrowStack(fts5yyParser *p){ #endif p->fts5yystksz = newSize; } - return pNew==0; + return pNew==0; } #endif @@ -182307,30 +218121,34 @@ static int fts5yyGrowStack(fts5yyParser *p){ /* Initialize a new parser that has already been allocated. */ -static void sqlite3Fts5ParserInit(void *fts5yypParser){ - fts5yyParser *pParser = (fts5yyParser*)fts5yypParser; +static void sqlite3Fts5ParserInit(void *fts5yypRawParser sqlite3Fts5ParserCTX_PDECL){ + fts5yyParser *fts5yypParser = (fts5yyParser*)fts5yypRawParser; + sqlite3Fts5ParserCTX_STORE #ifdef fts5YYTRACKMAXSTACKDEPTH - pParser->fts5yyhwm = 0; + fts5yypParser->fts5yyhwm = 0; #endif #if fts5YYSTACKDEPTH<=0 - pParser->fts5yytos = NULL; - pParser->fts5yystack = NULL; - pParser->fts5yystksz = 0; - if( fts5yyGrowStack(pParser) ){ - pParser->fts5yystack = &pParser->fts5yystk0; - pParser->fts5yystksz = 1; + fts5yypParser->fts5yytos = NULL; + fts5yypParser->fts5yystack = NULL; + fts5yypParser->fts5yystksz = 0; + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yypParser->fts5yystack = &fts5yypParser->fts5yystk0; + fts5yypParser->fts5yystksz = 1; } #endif #ifndef fts5YYNOERRORRECOVERY - pParser->fts5yyerrcnt = -1; + fts5yypParser->fts5yyerrcnt = -1; +#endif + fts5yypParser->fts5yytos = fts5yypParser->fts5yystack; + fts5yypParser->fts5yystack[0].stateno = 0; + fts5yypParser->fts5yystack[0].major = 0; +#if fts5YYSTACKDEPTH>0 + fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1]; #endif - pParser->fts5yytos = pParser->fts5yystack; - pParser->fts5yystack[0].stateno = 0; - pParser->fts5yystack[0].major = 0; } #ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK -/* +/* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like ** malloc. @@ -182342,11 +218160,14 @@ static void sqlite3Fts5ParserInit(void *fts5yypParser){ ** A pointer to a parser. This pointer is used in subsequent calls ** to sqlite3Fts5Parser and sqlite3Fts5ParserFree. */ -static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){ - fts5yyParser *pParser; - pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) ); - if( pParser ) sqlite3Fts5ParserInit(pParser); - return pParser; +static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE) sqlite3Fts5ParserCTX_PDECL){ + fts5yyParser *fts5yypParser; + fts5yypParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) ); + if( fts5yypParser ){ + sqlite3Fts5ParserCTX_STORE + sqlite3Fts5ParserInit(fts5yypParser sqlite3Fts5ParserCTX_PARAM); + } + return (void*)fts5yypParser; } #endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */ @@ -182354,7 +218175,7 @@ static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){ /* The following function deletes the "minor type" or semantic value ** associated with a symbol. The symbol can be either a terminal ** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is -** a pointer to the value to be deleted. The code used to do the +** a pointer to the value to be deleted. The code used to do the ** deletions is derived from the %destructor and/or %token_destructor ** directives of the input grammar. */ @@ -182363,12 +218184,13 @@ static void fts5yy_destructor( fts5YYCODETYPE fts5yymajor, /* Type code for object to destroy */ fts5YYMINORTYPE *fts5yypminor /* The object to be destroyed */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH switch( fts5yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a - ** reduce or during error processing or when a parser is + ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those @@ -182378,31 +218200,31 @@ static void fts5yy_destructor( /********* Begin destructor definitions ***************************************/ case 16: /* input */ { - (void)pParse; + (void)pParse; } break; case 17: /* expr */ case 18: /* cnearset */ case 19: /* exprlist */ { - sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24)); + sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24)); } break; - case 20: /* nearset */ - case 23: /* nearphrases */ + case 20: /* colset */ + case 21: /* colsetlist */ { - sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46)); + sqlite3_free((fts5yypminor->fts5yy11)); } break; - case 21: /* colset */ - case 22: /* colsetlist */ + case 22: /* nearset */ + case 23: /* nearphrases */ { - sqlite3_free((fts5yypminor->fts5yy11)); + sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46)); } break; case 24: /* phrase */ { - sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53)); + sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53)); } break; /********* End destructor definitions *****************************************/ @@ -182443,7 +218265,7 @@ static void sqlite3Fts5ParserFinalize(void *p){ } #ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK -/* +/* ** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. ** @@ -182473,28 +218295,73 @@ static int sqlite3Fts5ParserStackPeak(void *p){ } #endif +/* This array of booleans keeps track of the parser statement +** coverage. The element fts5yycoverage[X][Y] is set when the parser +** is in state X and has a lookahead token Y. In a well-tested +** systems, every element of this matrix should end up being set. +*/ +#if defined(fts5YYCOVERAGE) +static unsigned char fts5yycoverage[fts5YYNSTATE][fts5YYNFTS5TOKEN]; +#endif + +/* +** Write into out a description of every state/lookahead combination that +** +** (1) has not been used by the parser, and +** (2) is not a syntax error. +** +** Return the number of missed state/lookahead combinations. +*/ +#if defined(fts5YYCOVERAGE) +static int sqlite3Fts5ParserCoverage(FILE *out){ + int stateno, iLookAhead, i; + int nMissed = 0; + for(stateno=0; statenofts5yytos->stateno; - - if( stateno>=fts5YY_MIN_REDUCE ) return stateno; + + if( stateno>fts5YY_MAX_SHIFT ) return stateno; assert( stateno <= fts5YY_SHIFT_COUNT ); +#if defined(fts5YYCOVERAGE) + fts5yycoverage[stateno][iLookAhead] = 1; +#endif do{ i = fts5yy_shift_ofst[stateno]; + assert( i>=0 ); + assert( i<=fts5YY_ACTTAB_COUNT ); + assert( i+fts5YYNFTS5TOKEN<=(int)fts5YY_NLOOKAHEAD ); assert( iLookAhead!=fts5YYNOCODE ); + assert( iLookAhead < fts5YYNFTS5TOKEN ); i += iLookAhead; - if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){ + assert( i<(int)fts5YY_NLOOKAHEAD ); + if( fts5yy_lookahead[i]!=iLookAhead ){ #ifdef fts5YYFALLBACK fts5YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", @@ -182509,15 +218376,8 @@ static unsigned int fts5yy_find_shift_action( #ifdef fts5YYWILDCARD { int j = i - iLookAhead + fts5YYWILDCARD; - if( -#if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0 - j>=0 && -#endif -#if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT - j0 - ){ + assert( j<(int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0])) ); + if( fts5yy_lookahead[j]==fts5YYWILDCARD && iLookAhead>0 ){ #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n", @@ -182531,6 +218391,7 @@ static unsigned int fts5yy_find_shift_action( #endif /* fts5YYWILDCARD */ return fts5yy_default[stateno]; }else{ + assert( i>=0 && i<(int)(sizeof(fts5yy_action)/sizeof(fts5yy_action[0])) ); return fts5yy_action[i]; } }while(1); @@ -182540,8 +218401,8 @@ static unsigned int fts5yy_find_shift_action( ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. */ -static int fts5yy_find_reduce_action( - int stateno, /* Current state number */ +static fts5YYACTIONTYPE fts5yy_find_reduce_action( + fts5YYACTIONTYPE stateno, /* Current state number */ fts5YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; @@ -182553,7 +218414,6 @@ static int fts5yy_find_reduce_action( assert( stateno<=fts5YY_REDUCE_COUNT ); #endif i = fts5yy_reduce_ofst[stateno]; - assert( i!=fts5YY_REDUCE_USE_DFLT ); assert( iLookAhead!=fts5YYNOCODE ); i += iLookAhead; #ifdef fts5YYERRORSYMBOL @@ -182571,7 +218431,8 @@ static int fts5yy_find_reduce_action( ** The following routine is called if the stack overflows. */ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt); @@ -182584,27 +218445,29 @@ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){ sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow"); /******** End %stack_overflow code ********************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument var */ + sqlite3Fts5ParserCTX_STORE } /* ** Print tracing information for a SHIFT action */ #ifndef NDEBUG -static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){ +static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState, const char *zTag){ if( fts5yyTraceFILE ){ if( fts5yyNewStatefts5yytos->major], + fprintf(fts5yyTraceFILE,"%s%s '%s', go to state %d\n", + fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major], fts5yyNewState); }else{ - fprintf(fts5yyTraceFILE,"%sShift '%s'\n", - fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major]); + fprintf(fts5yyTraceFILE,"%s%s '%s', pending reduce %d\n", + fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major], + fts5yyNewState - fts5YY_MIN_REDUCE); } } } #else -# define fts5yyTraceShift(X,Y) +# define fts5yyTraceShift(X,Y,Z) #endif /* @@ -182612,8 +218475,8 @@ static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){ */ static void fts5yy_shift( fts5yyParser *fts5yypParser, /* The parser to be shifted */ - int fts5yyNewState, /* The new state to shift in */ - int fts5yyMajor, /* The major token to shift in */ + fts5YYACTIONTYPE fts5yyNewState, /* The new state to shift in */ + fts5YYCODETYPE fts5yyMajor, /* The major token to shift in */ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */ ){ fts5yyStackEntry *fts5yytos; @@ -182624,8 +218487,8 @@ static void fts5yy_shift( assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) ); } #endif -#if fts5YYSTACKDEPTH>0 - if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH] ){ +#if fts5YYSTACKDEPTH>0 + if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){ fts5yypParser->fts5yytos--; fts5yyStackOverflow(fts5yypParser); return; @@ -182643,45 +218506,76 @@ static void fts5yy_shift( fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; } fts5yytos = fts5yypParser->fts5yytos; - fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState; - fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor; + fts5yytos->stateno = fts5yyNewState; + fts5yytos->major = fts5yyMajor; fts5yytos->minor.fts5yy0 = fts5yyMinor; - fts5yyTraceShift(fts5yypParser, fts5yyNewState); -} + fts5yyTraceShift(fts5yypParser, fts5yyNewState, "Shift"); +} + +/* For rule J, fts5yyRuleInfoLhs[J] contains the symbol on the left-hand side +** of that rule */ +static const fts5YYCODETYPE fts5yyRuleInfoLhs[] = { + 16, /* (0) input ::= expr */ + 20, /* (1) colset ::= MINUS LCP colsetlist RCP */ + 20, /* (2) colset ::= LCP colsetlist RCP */ + 20, /* (3) colset ::= STRING */ + 20, /* (4) colset ::= MINUS STRING */ + 21, /* (5) colsetlist ::= colsetlist STRING */ + 21, /* (6) colsetlist ::= STRING */ + 17, /* (7) expr ::= expr AND expr */ + 17, /* (8) expr ::= expr OR expr */ + 17, /* (9) expr ::= expr NOT expr */ + 17, /* (10) expr ::= colset COLON LP expr RP */ + 17, /* (11) expr ::= LP expr RP */ + 17, /* (12) expr ::= exprlist */ + 19, /* (13) exprlist ::= cnearset */ + 19, /* (14) exprlist ::= exprlist cnearset */ + 18, /* (15) cnearset ::= nearset */ + 18, /* (16) cnearset ::= colset COLON nearset */ + 22, /* (17) nearset ::= phrase */ + 22, /* (18) nearset ::= CARET phrase */ + 22, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */ + 23, /* (20) nearphrases ::= phrase */ + 23, /* (21) nearphrases ::= nearphrases phrase */ + 25, /* (22) neardist_opt ::= */ + 25, /* (23) neardist_opt ::= COMMA STRING */ + 24, /* (24) phrase ::= phrase PLUS STRING star_opt */ + 24, /* (25) phrase ::= STRING star_opt */ + 26, /* (26) star_opt ::= STAR */ + 26, /* (27) star_opt ::= */ +}; -/* The following table contains information about every rule that -** is used during the reduce. -*/ -static const struct { - fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ -} fts5yyRuleInfo[] = { - { 16, 1 }, - { 17, 3 }, - { 17, 3 }, - { 17, 3 }, - { 17, 3 }, - { 17, 1 }, - { 19, 1 }, - { 19, 2 }, - { 18, 1 }, - { 18, 3 }, - { 21, 4 }, - { 21, 3 }, - { 21, 1 }, - { 21, 2 }, - { 22, 2 }, - { 22, 1 }, - { 20, 1 }, - { 20, 5 }, - { 23, 1 }, - { 23, 2 }, - { 25, 0 }, - { 25, 2 }, - { 24, 4 }, - { 24, 2 }, - { 26, 1 }, - { 26, 0 }, +/* For rule J, fts5yyRuleInfoNRhs[J] contains the negative of the number +** of symbols on the right-hand side of that rule. */ +static const signed char fts5yyRuleInfoNRhs[] = { + -1, /* (0) input ::= expr */ + -4, /* (1) colset ::= MINUS LCP colsetlist RCP */ + -3, /* (2) colset ::= LCP colsetlist RCP */ + -1, /* (3) colset ::= STRING */ + -2, /* (4) colset ::= MINUS STRING */ + -2, /* (5) colsetlist ::= colsetlist STRING */ + -1, /* (6) colsetlist ::= STRING */ + -3, /* (7) expr ::= expr AND expr */ + -3, /* (8) expr ::= expr OR expr */ + -3, /* (9) expr ::= expr NOT expr */ + -5, /* (10) expr ::= colset COLON LP expr RP */ + -3, /* (11) expr ::= LP expr RP */ + -1, /* (12) expr ::= exprlist */ + -1, /* (13) exprlist ::= cnearset */ + -2, /* (14) exprlist ::= exprlist cnearset */ + -1, /* (15) cnearset ::= nearset */ + -3, /* (16) cnearset ::= colset COLON nearset */ + -1, /* (17) nearset ::= phrase */ + -2, /* (18) nearset ::= CARET phrase */ + -5, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */ + -1, /* (20) nearphrases ::= phrase */ + -2, /* (21) nearphrases ::= nearphrases phrase */ + 0, /* (22) neardist_opt ::= */ + -2, /* (23) neardist_opt ::= COMMA STRING */ + -4, /* (24) phrase ::= phrase PLUS STRING star_opt */ + -2, /* (25) phrase ::= STRING star_opt */ + -1, /* (26) star_opt ::= STAR */ + 0, /* (27) star_opt ::= */ }; static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ @@ -182689,50 +218583,28 @@ static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */ /* ** Perform a reduce action and the shift that must immediately ** follow the reduce. +** +** The fts5yyLookahead and fts5yyLookaheadToken parameters provide reduce actions +** access to the lookahead token (if any). The fts5yyLookahead will be fts5YYNOCODE +** if the lookahead token has already been consumed. As this procedure is +** only called from one place, optimizing compilers will in-line it, which +** means that the extra parameters have no performance impact. */ -static void fts5yy_reduce( +static fts5YYACTIONTYPE fts5yy_reduce( fts5yyParser *fts5yypParser, /* The parser */ - unsigned int fts5yyruleno /* Number of the rule by which to reduce */ + unsigned int fts5yyruleno, /* Number of the rule by which to reduce */ + int fts5yyLookahead, /* Lookahead token, or fts5YYNOCODE if none */ + sqlite3Fts5ParserFTS5TOKENTYPE fts5yyLookaheadToken /* Value of the lookahead token */ + sqlite3Fts5ParserCTX_PDECL /* %extra_context */ ){ int fts5yygoto; /* The next state */ - int fts5yyact; /* The next action */ + fts5YYACTIONTYPE fts5yyact; /* The next action */ fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */ int fts5yysize; /* Amount to pop the stack */ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + (void)fts5yyLookahead; + (void)fts5yyLookaheadToken; fts5yymsp = fts5yypParser->fts5yytos; -#ifndef NDEBUG - if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ - fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs; - fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt, - fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno); - } -#endif /* NDEBUG */ - - /* Check that the stack is large enough to grow by a single entry - ** if the RHS of the rule is empty. This ensures that there is room - ** enough on the stack to push the LHS value */ - if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){ -#ifdef fts5YYTRACKMAXSTACKDEPTH - if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ - fts5yypParser->fts5yyhwm++; - assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)); - } -#endif -#if fts5YYSTACKDEPTH>0 - if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1] ){ - fts5yyStackOverflow(fts5yypParser); - return; - } -#else - if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){ - if( fts5yyGrowStack(fts5yypParser) ){ - fts5yyStackOverflow(fts5yypParser); - return; - } - fts5yymsp = fts5yypParser->fts5yytos; - } -#endif - } switch( fts5yyruleno ){ /* Beginning here are the reduction cases. A typical example @@ -182748,87 +218620,100 @@ static void fts5yy_reduce( case 0: /* input ::= expr */ { sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); } break; - case 1: /* expr ::= expr AND expr */ + case 1: /* colset ::= MINUS LCP colsetlist RCP */ +{ + fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); +} + break; + case 2: /* colset ::= LCP colsetlist RCP */ +{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; } + break; + case 3: /* colset ::= STRING */ +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); +} + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 4: /* colset ::= MINUS STRING */ +{ + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); +} + break; + case 5: /* colsetlist ::= colsetlist STRING */ +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); } + fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 6: /* colsetlist ::= STRING */ +{ + fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); +} + fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; + break; + case 7: /* expr ::= expr AND expr */ { fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 2: /* expr ::= expr OR expr */ + case 8: /* expr ::= expr OR expr */ { fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 3: /* expr ::= expr NOT expr */ + case 9: /* expr ::= expr NOT expr */ { fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0); } fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 4: /* expr ::= LP expr RP */ + case 10: /* expr ::= colset COLON LP expr RP */ +{ + sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[-4].minor.fts5yy11); + fts5yylhsminor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24; +} + fts5yymsp[-4].minor.fts5yy24 = fts5yylhsminor.fts5yy24; + break; + case 11: /* expr ::= LP expr RP */ {fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;} break; - case 5: /* expr ::= exprlist */ - case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6); + case 12: /* expr ::= exprlist */ + case 13: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==13); {fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;} fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 7: /* exprlist ::= exprlist cnearset */ + case 14: /* exprlist ::= exprlist cnearset */ { fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24); } fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 8: /* cnearset ::= nearset */ -{ - fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); + case 15: /* cnearset ::= nearset */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); } fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 9: /* cnearset ::= colset COLON nearset */ -{ - sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy46, fts5yymsp[-2].minor.fts5yy11); - fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); + case 16: /* cnearset ::= colset COLON nearset */ +{ + fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46); + sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy24, fts5yymsp[-2].minor.fts5yy11); } fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24; break; - case 10: /* colset ::= MINUS LCP colsetlist RCP */ -{ - fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); -} - break; - case 11: /* colset ::= LCP colsetlist RCP */ -{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; } + case 17: /* nearset ::= phrase */ +{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } + fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; - case 12: /* colset ::= STRING */ + case 18: /* nearset ::= CARET phrase */ { - fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); + sqlite3Fts5ParseSetCaret(fts5yymsp[0].minor.fts5yy53); + fts5yymsp[-1].minor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } - fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; break; - case 13: /* colset ::= MINUS STRING */ -{ - fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); - fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11); -} - break; - case 14: /* colsetlist ::= colsetlist STRING */ -{ - fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); } - fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11; - break; - case 15: /* colsetlist ::= STRING */ -{ - fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); -} - fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11; - break; - case 16: /* nearset ::= phrase */ -{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } - fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; - break; - case 17: /* nearset ::= STRING LP nearphrases neardist_opt RP */ + case 19: /* nearset ::= STRING LP nearphrases neardist_opt RP */ { sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0); sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0); @@ -182836,64 +218721,64 @@ static void fts5yy_reduce( } fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; - case 18: /* nearphrases ::= phrase */ -{ - fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); + case 20: /* nearphrases ::= phrase */ +{ + fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); } fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; - case 19: /* nearphrases ::= nearphrases phrase */ + case 21: /* nearphrases ::= nearphrases phrase */ { fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53); } fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46; break; - case 20: /* neardist_opt ::= */ + case 22: /* neardist_opt ::= */ { fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; } break; - case 21: /* neardist_opt ::= COMMA STRING */ + case 23: /* neardist_opt ::= COMMA STRING */ { fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; } break; - case 22: /* phrase ::= phrase PLUS STRING star_opt */ -{ + case 24: /* phrase ::= phrase PLUS STRING star_opt */ +{ fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); } fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53; break; - case 23: /* phrase ::= STRING star_opt */ -{ + case 25: /* phrase ::= STRING star_opt */ +{ fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4); } fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53; break; - case 24: /* star_opt ::= STAR */ + case 26: /* star_opt ::= STAR */ { fts5yymsp[0].minor.fts5yy4 = 1; } break; - case 25: /* star_opt ::= */ + case 27: /* star_opt ::= */ { fts5yymsp[1].minor.fts5yy4 = 0; } break; default: break; /********** End reduce actions ************************************************/ }; - assert( fts5yyrulenofts5YY_MAX_SHIFT ){ - fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE; - } - fts5yymsp -= fts5yysize-1; - fts5yypParser->fts5yytos = fts5yymsp; - fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; - fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; - fts5yyTraceShift(fts5yypParser, fts5yyact); - }else{ - assert( fts5yyact == fts5YY_ACCEPT_ACTION ); - fts5yypParser->fts5yytos -= fts5yysize; - fts5yy_accept(fts5yypParser); - } + assert( fts5yyrulenofts5YY_MAX_SHIFT && fts5yyact<=fts5YY_MAX_SHIFTREDUCE) ); + + /* It is not possible for a REDUCE to be followed by an error */ + assert( fts5yyact!=fts5YY_ERROR_ACTION ); + + fts5yymsp += fts5yysize+1; + fts5yypParser->fts5yytos = fts5yymsp; + fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact; + fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto; + fts5yyTraceShift(fts5yypParser, fts5yyact, "... then shift"); + return fts5yyact; } /* @@ -182903,7 +218788,8 @@ static void fts5yy_reduce( static void fts5yy_parse_failed( fts5yyParser *fts5yypParser /* The parser */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt); @@ -182914,7 +218800,8 @@ static void fts5yy_parse_failed( ** parser fails */ /************ Begin %parse_failure code ***************************************/ /************ End %parse_failure code *****************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserCTX_STORE } #endif /* fts5YYNOERRORRECOVERY */ @@ -182926,7 +218813,8 @@ static void fts5yy_syntax_error( int fts5yymajor, /* The major type of the error token */ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The minor type of the error token */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #define FTS5TOKEN fts5yyminor /************ Begin %syntax_error code ****************************************/ @@ -182935,7 +218823,8 @@ static void fts5yy_syntax_error( pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p ); /************ End %syntax_error code ******************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserCTX_STORE } /* @@ -182944,7 +218833,8 @@ static void fts5yy_syntax_error( static void fts5yy_accept( fts5yyParser *fts5yypParser /* The parser */ ){ - sqlite3Fts5ParserARG_FETCH; + sqlite3Fts5ParserARG_FETCH + sqlite3Fts5ParserCTX_FETCH #ifndef NDEBUG if( fts5yyTraceFILE ){ fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt); @@ -182958,7 +218848,8 @@ static void fts5yy_accept( ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ /*********** End %parse_accept code *******************************************/ - sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */ + sqlite3Fts5ParserCTX_STORE } /* The main parser program. @@ -182987,38 +218878,95 @@ static void sqlite3Fts5Parser( sqlite3Fts5ParserARG_PDECL /* Optional %extra_argument parameter */ ){ fts5YYMINORTYPE fts5yyminorunion; - unsigned int fts5yyact; /* The parser action. */ + fts5YYACTIONTYPE fts5yyact; /* The parser action. */ #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) int fts5yyendofinput; /* True if we are at the end of input */ #endif #ifdef fts5YYERRORSYMBOL int fts5yyerrorhit = 0; /* True if fts5yymajor has invoked an error */ #endif - fts5yyParser *fts5yypParser; /* The parser */ + fts5yyParser *fts5yypParser = (fts5yyParser*)fts5yyp; /* The parser */ + sqlite3Fts5ParserCTX_FETCH + sqlite3Fts5ParserARG_STORE - fts5yypParser = (fts5yyParser*)fts5yyp; assert( fts5yypParser->fts5yytos!=0 ); #if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY) fts5yyendofinput = (fts5yymajor==0); #endif - sqlite3Fts5ParserARG_STORE; + fts5yyact = fts5yypParser->fts5yytos->stateno; #ifndef NDEBUG if( fts5yyTraceFILE ){ - fprintf(fts5yyTraceFILE,"%sInput '%s'\n",fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]); + if( fts5yyact < fts5YY_MIN_REDUCE ){ + fprintf(fts5yyTraceFILE,"%sInput '%s' in state %d\n", + fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],fts5yyact); + }else{ + fprintf(fts5yyTraceFILE,"%sInput '%s' with pending reduce %d\n", + fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],fts5yyact-fts5YY_MIN_REDUCE); + } } #endif - do{ - fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor); - if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ - fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor); + while(1){ /* Exit by "break" */ + assert( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystack ); + assert( fts5yyact==fts5yypParser->fts5yytos->stateno ); + fts5yyact = fts5yy_find_shift_action((fts5YYCODETYPE)fts5yymajor,fts5yyact); + if( fts5yyact >= fts5YY_MIN_REDUCE ){ + unsigned int fts5yyruleno = fts5yyact - fts5YY_MIN_REDUCE; /* Reduce by this rule */ +#ifndef NDEBUG + assert( fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ); + if( fts5yyTraceFILE ){ + int fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno]; + if( fts5yysize ){ + fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n", + fts5yyTracePrompt, + fts5yyruleno, fts5yyRuleName[fts5yyruleno], + fts5yyrulenofts5yytos[fts5yysize].stateno); + }else{ + fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s.\n", + fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno], + fts5yyrulenofts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){ + fts5yypParser->fts5yyhwm++; + assert( fts5yypParser->fts5yyhwm == + (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)); + } +#endif +#if fts5YYSTACKDEPTH>0 + if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){ + fts5yyStackOverflow(fts5yypParser); + break; + } +#else + if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){ + if( fts5yyGrowStack(fts5yypParser) ){ + fts5yyStackOverflow(fts5yypParser); + break; + } + } +#endif + } + fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyruleno,fts5yymajor,fts5yyminor sqlite3Fts5ParserCTX_PARAM); + }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){ + fts5yy_shift(fts5yypParser,fts5yyact,(fts5YYCODETYPE)fts5yymajor,fts5yyminor); #ifndef fts5YYNOERRORRECOVERY fts5yypParser->fts5yyerrcnt--; #endif - fts5yymajor = fts5YYNOCODE; - }else if( fts5yyact <= fts5YY_MAX_REDUCE ){ - fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE); + break; + }else if( fts5yyact==fts5YY_ACCEPT_ACTION ){ + fts5yypParser->fts5yytos--; + fts5yy_accept(fts5yypParser); + return; }else{ assert( fts5yyact == fts5YY_ERROR_ACTION ); fts5yyminorunion.fts5yy0 = fts5yyminor; @@ -183033,7 +218981,7 @@ static void sqlite3Fts5Parser( #ifdef fts5YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". + ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** @@ -183064,15 +219012,13 @@ static void sqlite3Fts5Parser( fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion); fts5yymajor = fts5YYNOCODE; }else{ - while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack - && fts5yymx != fts5YYERRORSYMBOL - && (fts5yyact = fts5yy_find_reduce_action( - fts5yypParser->fts5yytos->stateno, - fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE - ){ + while( fts5yypParser->fts5yytos > fts5yypParser->fts5yystack ){ + fts5yyact = fts5yy_find_reduce_action(fts5yypParser->fts5yytos->stateno, + fts5YYERRORSYMBOL); + if( fts5yyact<=fts5YY_MAX_SHIFTREDUCE ) break; fts5yy_pop_parser_stack(fts5yypParser); } - if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){ + if( fts5yypParser->fts5yytos <= fts5yypParser->fts5yystack || fts5yymajor==0 ){ fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); fts5yy_parse_failed(fts5yypParser); #ifndef fts5YYNOERRORRECOVERY @@ -183085,6 +219031,8 @@ static void sqlite3Fts5Parser( } fts5yypParser->fts5yyerrcnt = 3; fts5yyerrorhit = 1; + if( fts5yymajor==fts5YYNOCODE ) break; + fts5yyact = fts5yypParser->fts5yytos->stateno; #elif defined(fts5YYNOERRORRECOVERY) /* If the fts5YYNOERRORRECOVERY macro is defined, then do not attempt to ** do any kind of error recovery. Instead, simply invoke the syntax @@ -183095,8 +219043,7 @@ static void sqlite3Fts5Parser( */ fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor); fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion); - fts5yymajor = fts5YYNOCODE; - + break; #else /* fts5YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** @@ -183118,10 +219065,10 @@ static void sqlite3Fts5Parser( fts5yypParser->fts5yyerrcnt = -1; #endif } - fts5yymajor = fts5YYNOCODE; + break; #endif } - }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ); + } #ifndef NDEBUG if( fts5yyTraceFILE ){ fts5yyStackEntry *i; @@ -183137,6 +219084,20 @@ static void sqlite3Fts5Parser( return; } +/* +** Return the fallback token corresponding to canonical token iToken, or +** 0 if iToken has no fallback. +*/ +static int sqlite3Fts5ParserFallback(int iToken){ +#ifdef fts5YYFALLBACK + assert( iToken<(int)(sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])) ); + return fts5yyFallback[iToken]; +#else + (void)iToken; + return 0; +#endif +} + /* ** 2014 May 31 ** @@ -183155,7 +219116,7 @@ static void sqlite3Fts5Parser( #include /* amalgamator: keep */ /* -** Object used to iterate through all "coalesced phrase instances" in +** Object used to iterate through all "coalesced phrase instances" in ** a single column of the current row. If the phrase instances in the ** column being considered do not overlap, this object simply iterates ** through them. Or, if they do overlap (share one or more tokens in @@ -183218,7 +219179,7 @@ static int fts5CInstIterNext(CInstIter *pIter){ } /* -** Initialize the iterator object indicated by the final parameter to +** Initialize the iterator object indicated by the final parameter to ** iterate through coalesced phrase instances in column iCol. */ static int fts5CInstIterInit( @@ -183263,19 +219224,19 @@ struct HighlightContext { /* ** Append text to the HighlightContext output string - p->zOut. Argument -** z points to a buffer containing n bytes of text to append. If n is +** z points to a buffer containing n bytes of text to append. If n is ** negative, everything up until the first '\0' is appended to the output. ** -** If *pRc is set to any value other than SQLITE_OK when this function is -** called, it is a no-op. If an error (i.e. an OOM condition) is encountered, -** *pRc is set to an error code before returning. +** If *pRc is set to any value other than SQLITE_OK when this function is +** called, it is a no-op. If an error (i.e. an OOM condition) is encountered, +** *pRc is set to an error code before returning. */ static void fts5HighlightAppend( - int *pRc, - HighlightContext *p, + int *pRc, + HighlightContext *p, const char *z, int n ){ - if( *pRc==SQLITE_OK ){ + if( *pRc==SQLITE_OK && z ){ if( n<0 ) n = (int)strlen(z); p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z); if( p->zOut==0 ) *pRc = SQLITE_NOMEM; @@ -183407,7 +219368,7 @@ static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){ int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64; int *aNew; - aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int)); + aNew = (int*)sqlite3_realloc64(p->aFirst, nNew*sizeof(int)); if( aNew==0 ) return SQLITE_NOMEM; p->aFirst = aNew; p->nFirstAlloc = nNew; @@ -183474,11 +219435,12 @@ static int fts5SnippetScore( int nInst; int nScore = 0; int iLast = 0; + sqlite3_int64 iEnd = (sqlite3_int64)iPos + nToken; rc = pApi->xInstCount(pFts, &nInst); for(i=0; ixInst(pFts, i, &ip, &ic, &iOff); - if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){ + if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOffnDocsize ) iAdj = nDocsize - nToken; if( iAdj<0 ) iAdj = 0; - *piPos = iAdj; + *piPos = (int)iAdj; } return rc; } +/* +** Return the value in pVal interpreted as utf-8 text. Except, if pVal +** contains a NULL value, return a pointer to a static string zero +** bytes in length instead of a NULL pointer. +*/ +static const char *fts5ValueToText(sqlite3_value *pVal){ + const char *zRet = (const char*)sqlite3_value_text(pVal); + return zRet ? zRet : ""; +} + /* ** Implementation of snippet() function. */ @@ -183532,9 +219504,9 @@ static void fts5SnippetFunction( nCol = pApi->xColumnCount(pFts); memset(&ctx, 0, sizeof(HighlightContext)); iCol = sqlite3_value_int(apVal[0]); - ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); - ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); - zEllips = (const char*)sqlite3_value_text(apVal[3]); + ctx.zOpen = fts5ValueToText(apVal[1]); + ctx.zClose = fts5ValueToText(apVal[2]); + zEllips = fts5ValueToText(apVal[3]); nToken = sqlite3_value_int(apVal[4]); iBestCol = (iCol>=0 ? iCol : 0); @@ -183557,7 +219529,7 @@ static void fts5SnippetFunction( sFinder.nFirst = 0; rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc); if( rc!=SQLITE_OK ) break; - rc = pApi->xTokenize(pFts, + rc = pApi->xTokenize(pFts, sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb ); if( rc!=SQLITE_OK ) break; @@ -183571,7 +219543,9 @@ static void fts5SnippetFunction( int jj; rc = pApi->xInst(pFts, ii, &ip, &ic, &io); - if( ic!=i || rc!=SQLITE_OK ) continue; + if( ic!=i ) continue; + if( io>nDocsize ) rc = FTS5_CORRUPT; + if( rc!=SQLITE_OK ) continue; memset(aSeen, 0, nPhrase); rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i, io, nToken, &nScore, &iAdj @@ -183590,7 +219564,7 @@ static void fts5SnippetFunction( if( sFinder.aFirst[jj]xGetAuxdata(pFts, 0); + p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0); if( p==0 ){ int nPhrase; /* Number of phrases in query */ sqlite3_int64 nRow = 0; /* Number of rows in table */ sqlite3_int64 nToken = 0; /* Number of tokens in table */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ int i; /* Allocate the Fts5Bm25Data object */ nPhrase = pApi->xPhraseCount(pFts); nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double); - p = (Fts5Bm25Data*)sqlite3_malloc(nByte); + p = (Fts5Bm25Data*)sqlite3_malloc64(nByte); if( p==0 ){ rc = SQLITE_NOMEM; }else{ - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->nPhrase = nPhrase; p->aIDF = (double*)&p[1]; p->aFreq = &p->aIDF[nPhrase]; @@ -183715,6 +219689,7 @@ static int fts5Bm25GetData( /* Calculate the average document length for this FTS5 table */ if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow); + assert( rc!=SQLITE_OK || nRow>0 ); if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken); if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow; @@ -183732,7 +219707,7 @@ static int fts5Bm25GetData( ** is the number that contain at least one instance of the phrase ** under consideration. ** - ** The problem with this is that if (N < 2*nHit), the IDF is + ** The problem with this is that if (N < 2*nHit), the IDF is ** negative. Which is undesirable. So the mimimum allowable IDF is ** (1e-6) - roughly the same as a term that appears in just over ** half of set of 5,000,000 documents. */ @@ -183765,7 +219740,7 @@ static void fts5Bm25Function( ){ const double k1 = 1.2; /* Constant "k1" from BM25 formula */ const double b = 0.75; /* Constant "b" from BM25 formula */ - int rc = SQLITE_OK; /* Error code */ + int rc; /* Error code */ double score = 0.0; /* SQL function return value */ Fts5Bm25Data *pData; /* Values allocated/calculated once only */ int i; /* Iterator variable */ @@ -183797,17 +219772,15 @@ static void fts5Bm25Function( D = (double)nTok; } - /* Determine the BM25 score for the current row. */ - for(i=0; rc==SQLITE_OK && inPhrase; i++){ - score += pData->aIDF[i] * ( - ( aFreq[i] * (k1 + 1.0) ) / - ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) - ); - } - - /* If no error has occurred, return the calculated score. Otherwise, - ** throw an SQL exception. */ + /* Determine and return the BM25 score for the current row. Or, if an + ** error has occurred, throw an exception. */ if( rc==SQLITE_OK ){ + for(i=0; inPhrase; i++){ + score += pData->aIDF[i] * ( + ( aFreq[i] * (k1 + 1.0) ) / + ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) + ); + } sqlite3_result_double(pCtx, -1.0 * score); }else{ sqlite3_result_error_code(pCtx, rc); @@ -183840,8 +219813,6 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ return rc; } - - /* ** 2014 May 31 ** @@ -183861,17 +219832,17 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){ static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ if( (u32)pBuf->nSpacenSpace ? pBuf->nSpace : 64; + u64 nNew = pBuf->nSpace ? pBuf->nSpace : 64; u8 *pNew; while( nNewp, nNew); + pNew = sqlite3_realloc64(pBuf->p, nNew); if( pNew==0 ){ *pRc = SQLITE_NOMEM; return 1; }else{ - pBuf->nSpace = nNew; + pBuf->nSpace = (int)nNew; pBuf->p = pNew; } } @@ -183896,34 +219867,35 @@ static void sqlite3Fts5Put32(u8 *aBuf, int iVal){ } static int sqlite3Fts5Get32(const u8 *aBuf){ - return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3]; + return (int)((((u32)aBuf[0])<<24) + (aBuf[1]<<16) + (aBuf[2]<<8) + aBuf[3]); } /* -** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set +** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set ** the error code in p. If an error has already occurred when this function ** is called, it is a no-op. */ static void sqlite3Fts5BufferAppendBlob( int *pRc, - Fts5Buffer *pBuf, - u32 nData, + Fts5Buffer *pBuf, + u32 nData, const u8 *pData ){ - assert_nc( *pRc || nData>=0 ); - if( fts5BufferGrow(pRc, pBuf, nData) ) return; - memcpy(&pBuf->p[pBuf->n], pData, nData); - pBuf->n += nData; + if( nData ){ + if( fts5BufferGrow(pRc, pBuf, nData) ) return; + memcpy(&pBuf->p[pBuf->n], pData, nData); + pBuf->n += nData; + } } /* ** Append the nul-terminated string zStr to the buffer pBuf. This function -** ensures that the byte following the buffer data is set to 0x00, even +** ensures that the byte following the buffer data is set to 0x00, even ** though this byte is not included in the pBuf->n count. */ static void sqlite3Fts5BufferAppendString( int *pRc, - Fts5Buffer *pBuf, + Fts5Buffer *pBuf, const char *zStr ){ int nStr = (int)strlen(zStr); @@ -183935,13 +219907,13 @@ static void sqlite3Fts5BufferAppendString( ** Argument zFmt is a printf() style format string. This function performs ** the printf() style processing, then appends the results to buffer pBuf. ** -** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte +** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte ** following the buffer data is set to 0x00, even though this byte is not ** included in the pBuf->n count. -*/ +*/ static void sqlite3Fts5BufferAppendPrintf( int *pRc, - Fts5Buffer *pBuf, + Fts5Buffer *pBuf, char *zFmt, ... ){ if( *pRc==SQLITE_OK ){ @@ -183968,12 +219940,12 @@ static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){ zRet = sqlite3_vmprintf(zFmt, ap); va_end(ap); if( zRet==0 ){ - *pRc = SQLITE_NOMEM; + *pRc = SQLITE_NOMEM; } } return zRet; } - + /* ** Free any buffer allocated by pBuf. Zero the structure before returning. @@ -183984,7 +219956,7 @@ static void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){ } /* -** Zero the contents of the buffer object. But do not free the associated +** Zero the contents of the buffer object. But do not free the associated ** memory allocation. */ static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){ @@ -183998,8 +219970,8 @@ static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){ */ static void sqlite3Fts5BufferSet( int *pRc, - Fts5Buffer *pBuf, - int nData, + Fts5Buffer *pBuf, + int nData, const u8 *pData ){ pBuf->n = 0; @@ -184015,18 +219987,31 @@ static int sqlite3Fts5PoslistNext64( if( i>=n ){ /* EOF */ *piOff = -1; - return 1; + return 1; }else{ i64 iOff = *piOff; - int iVal; + u32 iVal; fts5FastGetVarint32(a, i, iVal); - if( iVal==1 ){ + if( iVal<=1 ){ + if( iVal==0 ){ + *pi = i; + return 0; + } fts5FastGetVarint32(a, i, iVal); iOff = ((i64)iVal) << 32; + assert( iOff>=0 ); fts5FastGetVarint32(a, i, iVal); + if( iVal<2 ){ + /* This is a corrupt record. So stop parsing it here. */ + *piOff = -1; + return 1; + } + *piOff = iOff + ((iVal-2) & 0x7FFFFFFF); + }else{ + *piOff = (iOff & (i64)0x7FFFFFFF<<32)+((iOff + (iVal-2)) & 0x7FFFFFFF); } - *piOff = iOff + (iVal-2); *pi = i; + assert_nc( *piOff>=iOff ); return 0; } } @@ -184061,22 +220046,24 @@ static int sqlite3Fts5PoslistReaderInit( ** to iPos before returning. */ static void sqlite3Fts5PoslistSafeAppend( - Fts5Buffer *pBuf, - i64 *piPrev, + Fts5Buffer *pBuf, + i64 *piPrev, i64 iPos ){ - static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; - if( (iPos & colmask) != (*piPrev & colmask) ){ - pBuf->p[pBuf->n++] = 1; - pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); - *piPrev = (iPos & colmask); + if( iPos>=*piPrev ){ + static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32; + if( (iPos & colmask) != (*piPrev & colmask) ){ + pBuf->p[pBuf->n++] = 1; + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32)); + *piPrev = (iPos & colmask); + } + pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2); + *piPrev = iPos; } - pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2); - *piPrev = iPos; } static int sqlite3Fts5PoslistWriterAppend( - Fts5Buffer *pBuf, + Fts5Buffer *pBuf, Fts5PoslistWriter *pWriter, i64 iPos ){ @@ -184086,14 +220073,14 @@ static int sqlite3Fts5PoslistWriterAppend( return SQLITE_OK; } -static void *sqlite3Fts5MallocZero(int *pRc, int nByte){ +static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){ void *pRet = 0; if( *pRc==SQLITE_OK ){ - pRet = sqlite3_malloc(nByte); - if( pRet==0 && nByte>0 ){ - *pRc = SQLITE_NOMEM; + pRet = sqlite3_malloc64(nByte); + if( pRet==0 ){ + if( nByte>0 ) *pRc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } } return pRet; @@ -184105,7 +220092,7 @@ static void *sqlite3Fts5MallocZero(int *pRc, int nByte){ ** the length of the string is determined using strlen(). ** ** It is the responsibility of the caller to eventually free the returned -** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. +** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. */ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ char *zRet = 0; @@ -184172,9 +220159,9 @@ static int sqlite3Fts5TermsetNew(Fts5Termset **pp){ } static int sqlite3Fts5TermsetAdd( - Fts5Termset *p, + Fts5Termset *p, int iIdx, - const char *pTerm, int nTerm, + const char *pTerm, int nTerm, int *pbPresent ){ int rc = SQLITE_OK; @@ -184195,9 +220182,9 @@ static int sqlite3Fts5TermsetAdd( hash = hash % ArraySize(p->apHash); for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){ - if( pEntry->iIdx==iIdx - && pEntry->nTerm==nTerm - && memcmp(pEntry->pTerm, pTerm, nTerm)==0 + if( pEntry->iIdx==iIdx + && pEntry->nTerm==nTerm + && memcmp(pEntry->pTerm, pTerm, nTerm)==0 ){ *pbPresent = 1; break; @@ -184260,7 +220247,7 @@ static void sqlite3Fts5TermsetFree(Fts5Termset *p){ #define FTS5_DEFAULT_HASHSIZE (1024*1024) /* Maximum allowed page size */ -#define FTS5_MAX_PAGE_SIZE (128*1024) +#define FTS5_MAX_PAGE_SIZE (64*1024) static int fts5_iswhitespace(char x){ return (x==' '); @@ -184271,8 +220258,8 @@ static int fts5_isopenquote(char x){ } /* -** Argument pIn points to a character that is part of a nul-terminated -** string. Return a pointer to the first character following *pIn in +** Argument pIn points to a character that is part of a nul-terminated +** string. Return a pointer to the first character following *pIn in ** the string that is not a white-space character. */ static const char *fts5ConfigSkipWhitespace(const char *pIn){ @@ -184284,8 +220271,8 @@ static const char *fts5ConfigSkipWhitespace(const char *pIn){ } /* -** Argument pIn points to a character that is part of a nul-terminated -** string. Return a pointer to the first character following *pIn in +** Argument pIn points to a character that is part of a nul-terminated +** string. Return a pointer to the first character following *pIn in ** the string that is not a "bareword" character. */ static const char *fts5ConfigSkipBareword(const char *pIn){ @@ -184316,9 +220303,9 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){ p++; if( *p=='\'' ){ p++; - while( (*p>='a' && *p<='f') - || (*p>='A' && *p<='F') - || (*p>='0' && *p<='9') + while( (*p>='a' && *p<='f') + || (*p>='A' && *p<='F') + || (*p>='0' && *p<='9') ){ p++; } @@ -184349,7 +220336,7 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){ if( *p=='+' || *p=='-' ) p++; while( fts5_isdigit(*p) ) p++; - /* At this point, if the literal was an integer, the parse is + /* At this point, if the literal was an integer, the parse is ** finished. Or, if it is a floating point value, it may continue ** with either a decimal point or an 'E' character. */ if( *p=='.' && fts5_isdigit(p[1]) ){ @@ -184373,8 +220360,8 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){ ** nul-terminator byte. ** ** If the close-quote is found, the value returned is the byte offset of -** the character immediately following it. Or, if the close-quote is not -** found, -1 is returned. If -1 is returned, the buffer is left in an +** the character immediately following it. Or, if the close-quote is not +** found, -1 is returned. If -1 is returned, the buffer is left in an ** undefined state. */ static int fts5Dequote(char *z){ @@ -184385,9 +220372,9 @@ static int fts5Dequote(char *z){ /* Set stack variable q to the close-quote character */ assert( q=='[' || q=='\'' || q=='"' || q=='`' ); - if( q=='[' ) q = ']'; + if( q=='[' ) q = ']'; - while( ALWAYS(z[iIn]) ){ + while( z[iIn] ){ if( z[iIn]==q ){ if( z[iIn+1]!=q ){ /* Character iIn was the close quote. */ @@ -184395,7 +220382,7 @@ static int fts5Dequote(char *z){ break; }else{ /* Character iIn and iIn+1 form an escaped quote character. Skip - ** the input cursor past both and copy a single quote character + ** the input cursor past both and copy a single quote character ** to the output buffer. */ iIn += 2; z[iOut++] = q; @@ -184440,8 +220427,8 @@ struct Fts5Enum { typedef struct Fts5Enum Fts5Enum; static int fts5ConfigSetEnum( - const Fts5Enum *aEnum, - const char *zEnum, + const Fts5Enum *aEnum, + const char *zEnum, int *peVal ){ int nEnum = (int)strlen(zEnum); @@ -184532,7 +220519,7 @@ static int fts5ConfigParseSpecial( if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){ const char *p = (const char*)zArg; - int nArg = (int)strlen(zArg) + 1; + sqlite3_int64 nArg = strlen(zArg) + 1; char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg); char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2); char *pSpace = pDel; @@ -184561,8 +220548,8 @@ static int fts5ConfigParseSpecial( *pzErr = sqlite3_mprintf("parse error in tokenize directive"); rc = SQLITE_ERROR; }else{ - rc = sqlite3Fts5GetTokenizer(pGlobal, - (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi, + rc = sqlite3Fts5GetTokenizer(pGlobal, + (const char**)azArg, (int)nArg, pConfig, pzErr ); } @@ -184628,15 +220615,13 @@ static int fts5ConfigParseSpecial( } /* -** Allocate an instance of the default tokenizer ("simple") at +** Allocate an instance of the default tokenizer ("simple") at ** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error ** code if an error occurs. */ static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ assert( pConfig->pTok==0 && pConfig->pTokApi==0 ); - return sqlite3Fts5GetTokenizer( - pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0 - ); + return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0); } /* @@ -184662,8 +220647,8 @@ static const char *fts5ConfigGobbleWord( ){ const char *zRet = 0; - int nIn = (int)strlen(zIn); - char *zOut = sqlite3_malloc(nIn+1); + sqlite3_int64 nIn = strlen(zIn); + char *zOut = sqlite3_malloc64(nIn+1); assert( *pRc==SQLITE_OK ); *pbQuoted = 0; @@ -184672,7 +220657,7 @@ static const char *fts5ConfigGobbleWord( if( zOut==0 ){ *pRc = SQLITE_NOMEM; }else{ - memcpy(zOut, zIn, nIn+1); + memcpy(zOut, zIn, (size_t)(nIn+1)); if( fts5_isopenquote(zOut[0]) ){ int ii = fts5Dequote(zOut); zRet = &zIn[ii]; @@ -184695,14 +220680,14 @@ static const char *fts5ConfigGobbleWord( } static int fts5ConfigParseColumn( - Fts5Config *p, - char *zCol, - char *zArg, + Fts5Config *p, + char *zCol, + char *zArg, char **pzErr ){ int rc = SQLITE_OK; - if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME) - || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME) + if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME) + || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME) ){ *pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol); rc = SQLITE_ERROR; @@ -184745,14 +220730,14 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){ /* ** Arguments nArg/azArg contain the string arguments passed to the xCreate -** or xConnect method of the virtual table. This function attempts to +** or xConnect method of the virtual table. This function attempts to ** allocate an instance of Fts5Config containing the results of parsing ** those arguments. ** ** If successful, SQLITE_OK is returned and *ppOut is set to point to the -** new Fts5Config object. If an error occurs, an SQLite error code is +** new Fts5Config object. If an error occurs, an SQLite error code is ** returned, *ppOut is set to NULL and an error message may be left in -** *pzErr. It is the responsibility of the caller to eventually free any +** *pzErr. It is the responsibility of the caller to eventually free any ** such error message using sqlite3_free(). */ static int sqlite3Fts5ConfigParse( @@ -184766,7 +220751,7 @@ static int sqlite3Fts5ConfigParse( int rc = SQLITE_OK; /* Return code */ Fts5Config *pRet; /* New object to return */ int i; - int nByte; + sqlite3_int64 nByte; *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; @@ -184776,7 +220761,7 @@ static int sqlite3Fts5ConfigParse( nByte = nArg * (sizeof(char*) + sizeof(u8)); pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte); - pRet->abUnindexed = (u8*)&pRet->azCol[nArg]; + pRet->abUnindexed = pRet->azCol ? (u8*)&pRet->azCol[nArg] : 0; pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1); pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1); pRet->bColumnsize = 1; @@ -184801,6 +220786,7 @@ static int sqlite3Fts5ConfigParse( z = fts5ConfigSkipWhitespace(z); if( z && *z=='=' ){ bOption = 1; + assert( zOne!=0 ); z++; if( bMustBeCol ) z = 0; } @@ -184817,7 +220803,11 @@ static int sqlite3Fts5ConfigParse( rc = SQLITE_ERROR; }else{ if( bOption ){ - rc = fts5ConfigParseSpecial(pGlobal, pRet, zOne, zTwo?zTwo:"", pzErr); + rc = fts5ConfigParseSpecial(pGlobal, pRet, + ALWAYS(zOne)?zOne:"", + zTwo?zTwo:"", + pzErr + ); }else{ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr); zOne = 0; @@ -184839,8 +220829,8 @@ static int sqlite3Fts5ConfigParse( /* If no zContent option was specified, fill in the default values. */ if( rc==SQLITE_OK && pRet->zContent==0 ){ const char *zTail = 0; - assert( pRet->eContent==FTS5_CONTENT_NORMAL - || pRet->eContent==FTS5_CONTENT_NONE + assert( pRet->eContent==FTS5_CONTENT_NORMAL + || pRet->eContent==FTS5_CONTENT_NONE ); if( pRet->eContent==FTS5_CONTENT_NORMAL ){ zTail = "content"; @@ -184911,7 +220901,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){ const char *zSep = (i==0?"":", "); zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]); } - zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)", + zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)", zSql, pConfig->zName, FTS5_RANK_NAME ); @@ -184920,7 +220910,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){ rc = sqlite3_declare_vtab(pConfig->db, zSql); sqlite3_free(zSql); } - + return rc; } @@ -184938,7 +220928,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){ ** int iPos // Position of token in input (first token is 0) ** ** If the callback returns a non-zero value the tokenization is abandoned -** and no further callbacks are issued. +** and no further callbacks are issued. ** ** This function returns SQLITE_OK if successful or an SQLite error code ** if an error occurs. If the tokenization was abandoned early because @@ -184968,7 +220958,7 @@ static int sqlite3Fts5Tokenize( */ static const char *fts5ConfigSkipArgs(const char *pIn){ const char *p = pIn; - + while( 1 ){ p = fts5ConfigSkipWhitespace(p); p = fts5ConfigSkipLiteral(p); @@ -184985,7 +220975,7 @@ static const char *fts5ConfigSkipArgs(const char *pIn){ } /* -** Parameter zIn contains a rank() function specification. The format of +** Parameter zIn contains a rank() function specification. The format of ** this is: ** ** + Bareword (function name) @@ -185027,7 +221017,7 @@ static int sqlite3Fts5ConfigParseRank( p++; } if( rc==SQLITE_OK ){ - const char *pArgs; + const char *pArgs; p = fts5ConfigSkipWhitespace(p); pArgs = p; if( *p!=')' ){ @@ -185053,8 +221043,8 @@ static int sqlite3Fts5ConfigParseRank( } static int sqlite3Fts5ConfigSetValue( - Fts5Config *pConfig, - const char *zKey, + Fts5Config *pConfig, + const char *zKey, sqlite3_value *pVal, int *pbBadkey ){ @@ -185065,7 +221055,7 @@ static int sqlite3Fts5ConfigSetValue( if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){ pgsz = sqlite3_value_int(pVal); } - if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){ + if( pgsz<32 || pgsz>FTS5_MAX_PAGE_SIZE ){ *pbBadkey = 1; }else{ pConfig->pgsz = pgsz; @@ -185118,6 +221108,7 @@ static int sqlite3Fts5ConfigSetValue( *pbBadkey = 1; }else{ if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; + if( nCrisisMerge>=FTS5_MAX_SEGMENT ) nCrisisMerge = FTS5_MAX_SEGMENT-1; pConfig->nCrisisMerge = nCrisisMerge; } } @@ -185179,7 +221170,7 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ } rc = sqlite3_finalize(p); } - + if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){ rc = SQLITE_ERROR; if( pConfig->pzErrmsg ){ @@ -185235,6 +221226,7 @@ static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); /* #include */ static void sqlite3Fts5ParserTrace(FILE*, char*); #endif +static int sqlite3Fts5ParserFallback(int); struct Fts5Expr { @@ -185267,7 +221259,7 @@ struct Fts5ExprNode { i64 iRowid; /* Current rowid */ Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ - /* Child nodes. For a NOT node, this array always contains 2 entries. For + /* Child nodes. For a NOT node, this array always contains 2 entries. For ** AND or OR nodes, it contains 2 or more entries. */ int nChild; /* Number of child nodes */ Fts5ExprNode *apChild[1]; /* Array of child nodes */ @@ -185286,7 +221278,8 @@ struct Fts5ExprNode { ** or term prefix. */ struct Fts5ExprTerm { - int bPrefix; /* True for a prefix term */ + u8 bPrefix; /* True for a prefix term */ + u8 bFirst; /* True if token must be first in column */ char *zTerm; /* nul-terminated term */ Fts5IndexIter *pIter; /* Iterator for this term */ Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ @@ -185325,12 +221318,14 @@ struct Fts5Parse { int nPhrase; /* Size of apPhrase array */ Fts5ExprPhrase **apPhrase; /* Array of all phrases */ Fts5ExprNode *pExpr; /* Result of a successful parse */ + int bPhraseToAnd; /* Convert "a+b" to "a AND b" */ }; static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); if( pParse->rc==SQLITE_OK ){ + assert( pParse->zErr==0 ); pParse->zErr = sqlite3_vmprintf(zFmt, ap); pParse->rc = SQLITE_ERROR; } @@ -185345,7 +221340,7 @@ static int fts5ExprIsspace(char t){ ** Read the first token from the nul-terminated string at *pz. */ static int fts5ExprGetToken( - Fts5Parse *pParse, + Fts5Parse *pParse, const char **pz, /* IN/OUT: Pointer into buffer */ Fts5Token *pToken ){ @@ -185367,6 +221362,7 @@ static int fts5ExprGetToken( case '+': tok = FTS5_PLUS; break; case '*': tok = FTS5_STAR; break; case '-': tok = FTS5_MINUS; break; + case '^': tok = FTS5_CARET; break; case '\0': tok = FTS5_EOF; break; case '"': { @@ -185407,13 +221403,15 @@ static int fts5ExprGetToken( return tok; } -static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); } +static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc64((sqlite3_int64)t);} static void fts5ParseFree(void *p){ sqlite3_free(p); } static int sqlite3Fts5ExprNew( Fts5Config *pConfig, /* FTS5 Configuration */ + int bPhraseToAnd, + int iCol, const char *zExpr, /* Expression text */ - Fts5Expr **ppNew, + Fts5Expr **ppNew, char **pzErr ){ Fts5Parse sParse; @@ -185426,6 +221424,7 @@ static int sqlite3Fts5ExprNew( *ppNew = 0; *pzErr = 0; memset(&sParse, 0, sizeof(sParse)); + sParse.bPhraseToAnd = bPhraseToAnd; pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc); if( pEngine==0 ){ return SQLITE_NOMEM; } sParse.pConfig = pConfig; @@ -185436,6 +221435,18 @@ static int sqlite3Fts5ExprNew( }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); sqlite3Fts5ParserFree(pEngine, fts5ParseFree); + /* If the LHS of the MATCH expression was a user column, apply the + ** implicit column-filter. */ + if( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){ + int n = sizeof(Fts5Colset); + Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); + if( pColset ){ + pColset->nCol = 1; + pColset->aiCol[0] = iCol; + sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset); + } + } + assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); if( sParse.rc==SQLITE_OK ){ *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); @@ -185456,6 +221467,7 @@ static int sqlite3Fts5ExprNew( pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; pNew->nPhrase = sParse.nPhrase; + pNew->bDesc = 0; sParse.apPhrase = 0; } }else{ @@ -185467,6 +221479,81 @@ static int sqlite3Fts5ExprNew( return sParse.rc; } +/* +** This function is only called when using the special 'trigram' tokenizer. +** Argument zText contains the text of a LIKE or GLOB pattern matched +** against column iCol. This function creates and compiles an FTS5 MATCH +** expression that will match a superset of the rows matched by the LIKE or +** GLOB. If successful, SQLITE_OK is returned. Otherwise, an SQLite error +** code. +*/ +static int sqlite3Fts5ExprPattern( + Fts5Config *pConfig, int bGlob, int iCol, const char *zText, Fts5Expr **pp +){ + i64 nText = strlen(zText); + char *zExpr = (char*)sqlite3_malloc64(nText*4 + 1); + int rc = SQLITE_OK; + + if( zExpr==0 ){ + rc = SQLITE_NOMEM; + }else{ + char aSpec[3]; + int iOut = 0; + int i = 0; + int iFirst = 0; + + if( bGlob==0 ){ + aSpec[0] = '_'; + aSpec[1] = '%'; + aSpec[2] = 0; + }else{ + aSpec[0] = '*'; + aSpec[1] = '?'; + aSpec[2] = '['; + } + + while( i<=nText ){ + if( i==nText + || zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2] + ){ + if( i-iFirst>=3 ){ + int jj; + zExpr[iOut++] = '"'; + for(jj=iFirst; jj0 ){ + int bAnd = 0; + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ + bAnd = 1; + if( pConfig->eDetail==FTS5_DETAIL_NONE ){ + iCol = pConfig->nCol; + } + } + zExpr[iOut] = '\0'; + rc = sqlite3Fts5ExprNew(pConfig, bAnd, iCol, zExpr, pp,pConfig->pzErrmsg); + }else{ + *pp = 0; + } + sqlite3_free(zExpr); + } + + return rc; +} + /* ** Free the expression node object passed as the only argument. */ @@ -185492,6 +221579,42 @@ static void sqlite3Fts5ExprFree(Fts5Expr *p){ } } +static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){ + Fts5Parse sParse; + memset(&sParse, 0, sizeof(sParse)); + + if( *pp1 ){ + Fts5Expr *p1 = *pp1; + int nPhrase = p1->nPhrase + p2->nPhrase; + + p1->pRoot = sqlite3Fts5ParseNode(&sParse, FTS5_AND, p1->pRoot, p2->pRoot,0); + p2->pRoot = 0; + + if( sParse.rc==SQLITE_OK ){ + Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc( + p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*) + ); + if( ap==0 ){ + sParse.rc = SQLITE_NOMEM; + }else{ + int i; + memmove(&ap[p2->nPhrase], ap, p1->nPhrase*sizeof(Fts5ExprPhrase*)); + for(i=0; inPhrase; i++){ + ap[i] = p2->apExprPhrase[i]; + } + p1->nPhrase = nPhrase; + p1->apExprPhrase = ap; + } + } + sqlite3_free(p2->apExprPhrase); + sqlite3_free(p2); + }else{ + *pp1 = p2; + } + + return sParse.rc; +} + /* ** Argument pTerm must be a synonym iterator. Return the current rowid ** that it points to. @@ -185501,6 +221624,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ int bRetValid = 0; Fts5ExprTerm *p; + assert( pTerm ); assert( pTerm->pSynonym ); assert( bDesc==0 || bDesc==1 ); for(p=pTerm; p; p=p->pSynonym){ @@ -185521,7 +221645,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){ ** Argument pTerm must be a synonym iterator. */ static int fts5ExprSynonymList( - Fts5ExprTerm *pTerm, + Fts5ExprTerm *pTerm, i64 iRowid, Fts5Buffer *pBuf, /* Use this buffer for space if required */ u8 **pa, int *pn @@ -185539,8 +221663,8 @@ static int fts5ExprSynonymList( if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){ if( pIter->nData==0 ) continue; if( nIter==nAlloc ){ - int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; - Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nAlloc * 2; + Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc64(nByte); if( aNew==0 ){ rc = SQLITE_NOMEM; goto synonym_poslist_out; @@ -185594,13 +221718,13 @@ static int fts5ExprSynonymList( /* ** All individual term iterators in pPhrase are guaranteed to be valid and -** pointing to the same rowid when this function is called. This function +** pointing to the same rowid when this function is called. This function ** checks if the current rowid really is a match, and if so populates ** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch ** is set to true if this is really a match, or false otherwise. ** -** SQLITE_OK is returned if an error occurs, or an SQLite error code -** otherwise. It is not considered an error code if the current rowid is +** SQLITE_OK is returned if an error occurs, or an SQLite error code +** otherwise. It is not considered an error code if the current rowid is ** not a match. */ static int fts5ExprPhraseIsMatch( @@ -185613,14 +221737,15 @@ static int fts5ExprPhraseIsMatch( Fts5PoslistReader *aIter = aStatic; int i; int rc = SQLITE_OK; - + int bFirst = pPhrase->aTerm[0].bFirst; + fts5BufferZero(&pPhrase->poslist); /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pPhrase->nTerm>ArraySize(aStatic) ){ - int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; - aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm; + aIter = (Fts5PoslistReader*)sqlite3_malloc64(nByte); if( !aIter ) return SQLITE_NOMEM; } memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm); @@ -185667,8 +221792,10 @@ static int fts5ExprPhraseIsMatch( }while( bMatch==0 ); /* Append position iPos to the output */ - rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos); - if( rc!=SQLITE_OK ) goto ismatch_out; + if( bFirst==0 || FTS5_POS2OFFSET(iPos)==0 ){ + rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos); + if( rc!=SQLITE_OK ) goto ismatch_out; + } for(i=0; inTerm; i++){ if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out; @@ -185733,7 +221860,7 @@ struct Fts5NearTrimmer { ** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM) ** occurs within this function (*pRc) is set accordingly before returning. ** The return value is undefined in both these cases. -** +** ** If no error occurs and non-zero (a match) is returned, the position-list ** of each phrase object is edited to contain only those entries that ** meet the constraint before returning. @@ -185752,7 +221879,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ /* If the aStatic[] array is not large enough, allocate a large array ** using sqlite3_malloc(). This approach could be improved upon. */ if( pNear->nPhrase>ArraySize(aStatic) ){ - int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; + sqlite3_int64 nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase; a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte); }else{ memset(aStatic, 0, sizeof(aStatic)); @@ -185765,7 +221892,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ /* Initialize a lookahead iterator for each phrase. After passing the ** buffer and buffer size to the lookaside-reader init function, zero ** the phrase poslist buffer. The new poslist for the phrase (containing - ** the same entries as the original with some entries removed on account + ** the same entries as the original with some entries removed on account ** of the NEAR constraint) is written over the original even as it is ** being read. This is safe as the entries for the new poslist are a ** subset of the old, so it is not possible for data yet to be read to @@ -185922,7 +222049,9 @@ static int fts5ExprNearTest( ** phrase is not a match, break out of the loop early. */ for(i=0; rc==SQLITE_OK && inPhrase; i++){ Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; - if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){ + if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym + || pNear->pColset || pPhrase->aTerm[0].bFirst + ){ int bMatch = 0; rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch); if( bMatch==0 ) break; @@ -186068,7 +222197,7 @@ static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){ */ static int fts5NodeCompare( Fts5Expr *pExpr, - Fts5ExprNode *p1, + Fts5ExprNode *p1, Fts5ExprNode *p2 ){ if( p2->bEof ) return -1; @@ -186083,7 +222212,7 @@ static int fts5NodeCompare( ** If an EOF is reached before this happens, *pbEof is set to true before ** returning. ** -** SQLITE_OK is returned if an error occurs, or an SQLite error code +** SQLITE_OK is returned if an error occurs, or an SQLite error code ** otherwise. It is not considered an error code if an iterator reaches ** EOF. */ @@ -186100,9 +222229,10 @@ static int fts5ExprNodeTest_STRING( const int bDesc = pExpr->bDesc; /* Check that this node should not be FTS5_TERM */ - assert( pNear->nPhrase>1 - || pNear->apPhrase[0]->nTerm>1 + assert( pNear->nPhrase>1 + || pNear->apPhrase[0]->nTerm>1 || pNear->apPhrase[0]->aTerm[0].pSynonym + || pNear->apPhrase[0]->aTerm[0].bFirst ); /* Initialize iLast, the "lastest" rowid any iterator points to. If the @@ -186160,7 +222290,7 @@ static int fts5ExprNodeNext_STRING( Fts5Expr *pExpr, /* Expression pPhrase belongs to */ Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */ int bFromValid, - i64 iFrom + i64 iFrom ){ Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0]; int rc = SQLITE_OK; @@ -186178,8 +222308,8 @@ static int fts5ExprNodeNext_STRING( for(p=pTerm; p; p=p->pSynonym){ if( sqlite3Fts5IterEof(p->pIter)==0 ){ i64 ii = p->pIter->iRowid; - if( ii==iRowid - || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) + if( ii==iRowid + || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) ){ if( bFromValid ){ rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom); @@ -186225,9 +222355,9 @@ static int fts5ExprNodeTest_TERM( Fts5Expr *pExpr, /* Expression that pNear is a part of */ Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */ ){ - /* As this "NEAR" object is actually a single phrase that consists + /* As this "NEAR" object is actually a single phrase that consists ** of a single term only, grab pointers into the poslist managed by the - ** fts5_index.c iterator object. This is much faster than synthesizing + ** fts5_index.c iterator object. This is much faster than synthesizing ** a new poslist the way we have to for more complicated phrase or NEAR ** expressions. */ Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0]; @@ -186250,7 +222380,7 @@ static int fts5ExprNodeTest_TERM( ** xNext() method for a node of type FTS5_TERM. */ static int fts5ExprNodeNext_TERM( - Fts5Expr *pExpr, + Fts5Expr *pExpr, Fts5ExprNode *pNode, int bFromValid, i64 iFrom @@ -186293,7 +222423,7 @@ static void fts5ExprNodeTest_OR( } static int fts5ExprNodeNext_OR( - Fts5Expr *pExpr, + Fts5Expr *pExpr, Fts5ExprNode *pNode, int bFromValid, i64 iFrom @@ -186305,11 +222435,14 @@ static int fts5ExprNodeNext_OR( Fts5ExprNode *p1 = pNode->apChild[i]; assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 ); if( p1->bEof==0 ){ - if( (p1->iRowid==iLast) + if( (p1->iRowid==iLast) || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0) ){ int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ){ + pNode->bNomatch = 0; + return rc; + } } } } @@ -186340,7 +222473,10 @@ static int fts5ExprNodeTest_AND( if( cmp>0 ){ /* Advance pChild until it points to iLast or laster */ rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast); - if( rc!=SQLITE_OK ) return rc; + if( rc!=SQLITE_OK ){ + pAnd->bNomatch = 0; + return rc; + } } /* If the child node is now at EOF, so is the parent AND node. Otherwise, @@ -186371,7 +222507,7 @@ static int fts5ExprNodeTest_AND( } static int fts5ExprNodeNext_AND( - Fts5Expr *pExpr, + Fts5Expr *pExpr, Fts5ExprNode *pNode, int bFromValid, i64 iFrom @@ -186379,6 +222515,8 @@ static int fts5ExprNodeNext_AND( int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom); if( rc==SQLITE_OK ){ rc = fts5ExprNodeTest_AND(pExpr, pNode); + }else{ + pNode->bNomatch = 0; } return rc; } @@ -186412,7 +222550,7 @@ static int fts5ExprNodeTest_NOT( } static int fts5ExprNodeNext_NOT( - Fts5Expr *pExpr, + Fts5Expr *pExpr, Fts5ExprNode *pNode, int bFromValid, i64 iFrom @@ -186421,6 +222559,9 @@ static int fts5ExprNodeNext_NOT( if( rc==SQLITE_OK ){ rc = fts5ExprNodeTest_NOT(pExpr, pNode); } + if( rc!=SQLITE_OK ){ + pNode->bNomatch = 0; + } return rc; } @@ -186466,7 +222607,7 @@ static int fts5ExprNodeTest( return rc; } - + /* ** Set node pNode, which is part of expression pExpr, to point to the first ** match. If there are no matches, set the Node.bEof flag to indicate EOF. @@ -186520,8 +222661,8 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ /* ** Begin iterating through the set of documents in index pIdx matched by -** the MATCH expression passed as the first argument. If the "bDesc" -** parameter is passed a non-zero value, iteration is in descending rowid +** the MATCH expression passed as the first argument. If the "bDesc" +** parameter is passed a non-zero value, iteration is in descending rowid ** order. Or, if it is zero, in ascending order. ** ** If iterating in ascending rowid order (bDesc==0), the first document @@ -186543,23 +222684,23 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD /* If not at EOF but the current rowid occurs earlier than iFirst in ** the iteration order, move to document iFirst or later. */ - if( rc==SQLITE_OK - && 0==pRoot->bEof - && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 + if( rc==SQLITE_OK + && 0==pRoot->bEof + && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){ rc = fts5ExprNodeNext(p, pRoot, 1, iFirst); } /* If the iterator is not at a real match, skip forward until it is. */ - while( pRoot->bNomatch ){ - assert( pRoot->bEof==0 && rc==SQLITE_OK ); + while( pRoot->bNomatch && rc==SQLITE_OK ){ + assert( pRoot->bEof==0 ); rc = fts5ExprNodeNext(p, pRoot, 0, 0); } return rc; } /* -** Move to the next document +** Move to the next document ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. It ** is not considered an error if the query does not match any documents. @@ -186616,6 +222757,16 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){ } } +/* +** Set the "bFirst" flag on the first token of the phrase passed as the +** only argument. +*/ +static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase *pPhrase){ + if( pPhrase && pPhrase->nTerm ){ + pPhrase->aTerm[0].bFirst = 1; + } +} + /* ** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated ** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is @@ -186637,18 +222788,20 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( return pNear; } if( pNear==0 ){ - int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); - pRet = sqlite3_malloc(nByte); + sqlite3_int64 nByte; + nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); + pRet = sqlite3_malloc64(nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } }else if( (pNear->nPhrase % SZALLOC)==0 ){ int nNew = pNear->nPhrase + SZALLOC; - int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + sqlite3_int64 nByte; - pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte); + nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*); + pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte); if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; } @@ -186712,12 +222865,12 @@ static int fts5ParseTokenize( if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){ Fts5ExprTerm *pSyn; - int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; - pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1; + pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte); if( pSyn==0 ){ rc = SQLITE_NOMEM; }else{ - memset(pSyn, 0, nByte); + memset(pSyn, 0, (size_t)nByte); pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; @@ -186729,7 +222882,7 @@ static int fts5ParseTokenize( Fts5ExprPhrase *pNew; int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0); - pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase, + pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase, sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew ); if( pNew==0 ){ @@ -186779,6 +222932,20 @@ static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){ pParse->pExpr = p; } +static int parseGrowPhraseArray(Fts5Parse *pParse){ + if( (pParse->nPhrase % 8)==0 ){ + sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); + Fts5ExprPhrase **apNew; + apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte); + if( apNew==0 ){ + pParse->rc = SQLITE_NOMEM; + return SQLITE_NOMEM; + } + pParse->apPhrase = apNew; + } + return SQLITE_OK; +} + /* ** This function is called by the parser to process a string token. The ** string may or may not be quoted. In any case it is tokenized and a @@ -186814,16 +222981,9 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( }else{ if( pAppend==0 ){ - if( (pParse->nPhrase % 8)==0 ){ - int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); - Fts5ExprPhrase **apNew; - apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte); - if( apNew==0 ){ - pParse->rc = SQLITE_NOMEM; - fts5ExprPhraseFree(sCtx.pPhrase); - return 0; - } - pParse->apPhrase = apNew; + if( parseGrowPhraseArray(pParse) ){ + fts5ExprPhraseFree(sCtx.pPhrase); + return 0; } pParse->nPhrase++; } @@ -186833,7 +222993,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( ** no token characters at all. (e.g ... MATCH '""'). */ sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase)); }else if( sCtx.pPhrase->nTerm ){ - sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix; + sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; } pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; } @@ -186846,8 +223006,8 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( ** expression passed as the second argument. */ static int sqlite3Fts5ExprClonePhrase( - Fts5Expr *pExpr, - int iPhrase, + Fts5Expr *pExpr, + int iPhrase, Fts5Expr **ppNew ){ int rc = SQLITE_OK; /* Return code */ @@ -186858,24 +223018,26 @@ static int sqlite3Fts5ExprClonePhrase( pOrig = pExpr->apExprPhrase[iPhrase]; pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); if( rc==SQLITE_OK ){ - pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, + pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ - pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, + pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNode)); } if( rc==SQLITE_OK ){ - pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, + pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ - int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); - Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); - if( pColset ){ - memcpy(pColset, pColsetOrig, nByte); + sqlite3_int64 nByte; + Fts5Colset *pColset; + nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); + pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); + if( pColset ){ + memcpy(pColset, pColsetOrig, (size_t)nByte); } pNew->pRoot->pNear->pColset = pColset; } @@ -186894,6 +223056,7 @@ static int sqlite3Fts5ExprClonePhrase( } if( rc==SQLITE_OK ){ sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; + sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst; } } }else{ @@ -186902,7 +223065,7 @@ static int sqlite3Fts5ExprClonePhrase( sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase)); } - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){ /* All the allocations succeeded. Put the expression object together. */ pNew->pIndex = pExpr->pIndex; pNew->pConfig = pExpr->pConfig; @@ -186912,7 +223075,10 @@ static int sqlite3Fts5ExprClonePhrase( pNew->pRoot->pNear->nPhrase = 1; sCtx.pPhrase->pNode = pNew->pRoot; - if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){ + if( pOrig->nTerm==1 + && pOrig->aTerm[0].pSynonym==0 + && pOrig->aTerm[0].bFirst==0 + ){ pNew->pRoot->eType = FTS5_TERM; pNew->pRoot->xNext = fts5ExprNodeNext_TERM; }else{ @@ -186944,7 +223110,7 @@ static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){ } static void sqlite3Fts5ParseSetDistance( - Fts5Parse *pParse, + Fts5Parse *pParse, Fts5ExprNearset *pNear, Fts5Token *p ){ @@ -186973,7 +223139,7 @@ static void sqlite3Fts5ParseSetDistance( ** The second argument passed to this function may be NULL, or it may be ** an existing Fts5Colset object. This function returns a pointer to ** a new colset object containing the contents of (p) with new value column -** number iCol appended. +** number iCol appended. ** ** If an OOM error occurs, store an error code in pParse and return NULL. ** The old colset object (if any) is not freed in this case. @@ -186989,7 +223155,7 @@ static Fts5Colset *fts5ParseColset( assert( pParse->rc==SQLITE_OK ); assert( iCol>=0 && iColpConfig->nCol ); - pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol); + pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol); if( pNew==0 ){ pParse->rc = SQLITE_NOMEM; }else{ @@ -187023,7 +223189,7 @@ static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p Fts5Colset *pRet; int nCol = pParse->pConfig->nCol; - pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, + pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5Colset) + sizeof(int)*nCol ); if( pRet ){ @@ -187074,33 +223240,118 @@ static Fts5Colset *sqlite3Fts5ParseColset( return pRet; } -static void sqlite3Fts5ParseSetColset( - Fts5Parse *pParse, - Fts5ExprNearset *pNear, - Fts5Colset *pColset +/* +** If argument pOrig is NULL, or if (*pRc) is set to anything other than +** SQLITE_OK when this function is called, NULL is returned. +** +** Otherwise, a copy of (*pOrig) is made into memory obtained from +** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation +** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned. +*/ +static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ + Fts5Colset *pRet; + if( pOrig ){ + sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); + pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); + if( pRet ){ + memcpy(pRet, pOrig, (size_t)nByte); + } + }else{ + pRet = 0; + } + return pRet; +} + +/* +** Remove from colset pColset any columns that are not also in colset pMerge. +*/ +static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){ + int iIn = 0; /* Next input in pColset */ + int iMerge = 0; /* Next input in pMerge */ + int iOut = 0; /* Next output slot in pColset */ + + while( iInnCol && iMergenCol ){ + int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge]; + if( iDiff==0 ){ + pColset->aiCol[iOut++] = pMerge->aiCol[iMerge]; + iMerge++; + iIn++; + }else if( iDiff>0 ){ + iMerge++; + }else{ + iIn++; + } + } + pColset->nCol = iOut; +} + +/* +** Recursively apply colset pColset to expression node pNode and all of +** its decendents. If (*ppFree) is not NULL, it contains a spare copy +** of pColset. This function may use the spare copy and set (*ppFree) to +** zero, or it may create copies of pColset using fts5CloneColset(). +*/ +static void fts5ParseSetColset( + Fts5Parse *pParse, + Fts5ExprNode *pNode, + Fts5Colset *pColset, + Fts5Colset **ppFree ){ - if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ - pParse->rc = SQLITE_ERROR; - pParse->zErr = sqlite3_mprintf( - "fts5: column queries are not supported (detail=none)" + if( pParse->rc==SQLITE_OK ){ + assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING + || pNode->eType==FTS5_AND || pNode->eType==FTS5_OR + || pNode->eType==FTS5_NOT || pNode->eType==FTS5_EOF ); - sqlite3_free(pColset); - return; + if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){ + Fts5ExprNearset *pNear = pNode->pNear; + if( pNear->pColset ){ + fts5MergeColset(pNear->pColset, pColset); + if( pNear->pColset->nCol==0 ){ + pNode->eType = FTS5_EOF; + pNode->xNext = 0; + } + }else if( *ppFree ){ + pNear->pColset = pColset; + *ppFree = 0; + }else{ + pNear->pColset = fts5CloneColset(&pParse->rc, pColset); + } + }else{ + int i; + assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 ); + for(i=0; inChild; i++){ + fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree); + } + } } +} - if( pNear ){ - pNear->pColset = pColset; +/* +** Apply colset pColset to expression node pExpr and all of its descendents. +*/ +static void sqlite3Fts5ParseSetColset( + Fts5Parse *pParse, + Fts5ExprNode *pExpr, + Fts5Colset *pColset +){ + Fts5Colset *pFree = pColset; + if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ + sqlite3Fts5ParseError(pParse, + "fts5: column queries are not supported (detail=none)" + ); }else{ - sqlite3_free(pColset); + fts5ParseSetColset(pParse, pExpr, pColset, &pFree); } + sqlite3_free(pFree); } static void fts5ExprAssignXNext(Fts5ExprNode *pNode){ switch( pNode->eType ){ case FTS5_STRING: { Fts5ExprNearset *pNear = pNode->pNear; - if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 + if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 && pNear->apPhrase[0]->aTerm[0].pSynonym==0 + && pNear->apPhrase[0]->aTerm[0].bFirst==0 ){ pNode->eType = FTS5_TERM; pNode->xNext = fts5ExprNodeNext_TERM; @@ -187138,6 +223389,67 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ } } +/* +** This function is used when parsing LIKE or GLOB patterns against +** trigram indexes that specify either detail=column or detail=none. +** It converts a phrase: +** +** abc + def + ghi +** +** into an AND tree: +** +** abc AND def AND ghi +*/ +static Fts5ExprNode *fts5ParsePhraseToAnd( + Fts5Parse *pParse, + Fts5ExprNearset *pNear +){ + int nTerm = pNear->apPhrase[0]->nTerm; + int ii; + int nByte; + Fts5ExprNode *pRet; + + assert( pNear->nPhrase==1 ); + assert( pParse->bPhraseToAnd ); + + nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*); + pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); + if( pRet ){ + pRet->eType = FTS5_AND; + pRet->nChild = nTerm; + fts5ExprAssignXNext(pRet); + pParse->nPhrase--; + for(ii=0; iirc, sizeof(Fts5ExprPhrase) + ); + if( pPhrase ){ + if( parseGrowPhraseArray(pParse) ){ + fts5ExprPhraseFree(pPhrase); + }else{ + pParse->apPhrase[pParse->nPhrase++] = pPhrase; + pPhrase->nTerm = 1; + pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup( + &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1 + ); + pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING, + 0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase) + ); + } + } + } + + if( pParse->rc ){ + sqlite3Fts5ParseNodeFree(pRet); + pRet = 0; + }else{ + sqlite3Fts5ParseNearsetFree(pNear); + } + } + + return pRet; +} + /* ** Allocate and return a new expression object. If anything goes wrong (i.e. ** OOM error), leave an error code in pParse and return NULL. @@ -187153,8 +223465,8 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( pParse->rc==SQLITE_OK ){ int nChild = 0; /* Number of children of returned node */ - int nByte; /* Bytes of space to allocate for this node */ - + sqlite3_int64 nByte; /* Bytes of space to allocate for this node */ + assert( (eType!=FTS5_STRING && !pNear) || (eType==FTS5_STRING && !pLeft && !pRight) ); @@ -187162,48 +223474,55 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( eType!=FTS5_STRING && pLeft==0 ) return pRight; if( eType!=FTS5_STRING && pRight==0 ) return pLeft; - if( eType==FTS5_NOT ){ - nChild = 2; - }else if( eType==FTS5_AND || eType==FTS5_OR ){ - nChild = 2; - if( pLeft->eType==eType ) nChild += pLeft->nChild-1; - if( pRight->eType==eType ) nChild += pRight->nChild-1; - } + if( eType==FTS5_STRING + && pParse->bPhraseToAnd + && pNear->apPhrase[0]->nTerm>1 + ){ + pRet = fts5ParsePhraseToAnd(pParse, pNear); + }else{ + if( eType==FTS5_NOT ){ + nChild = 2; + }else if( eType==FTS5_AND || eType==FTS5_OR ){ + nChild = 2; + if( pLeft->eType==eType ) nChild += pLeft->nChild-1; + if( pRight->eType==eType ) nChild += pRight->nChild-1; + } - nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); - pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); + nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); + pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); - if( pRet ){ - pRet->eType = eType; - pRet->pNear = pNear; - fts5ExprAssignXNext(pRet); - if( eType==FTS5_STRING ){ - int iPhrase; - for(iPhrase=0; iPhrasenPhrase; iPhrase++){ - pNear->apPhrase[iPhrase]->pNode = pRet; - if( pNear->apPhrase[iPhrase]->nTerm==0 ){ - pRet->xNext = 0; - pRet->eType = FTS5_EOF; + if( pRet ){ + pRet->eType = eType; + pRet->pNear = pNear; + fts5ExprAssignXNext(pRet); + if( eType==FTS5_STRING ){ + int iPhrase; + for(iPhrase=0; iPhrasenPhrase; iPhrase++){ + pNear->apPhrase[iPhrase]->pNode = pRet; + if( pNear->apPhrase[iPhrase]->nTerm==0 ){ + pRet->xNext = 0; + pRet->eType = FTS5_EOF; + } } - } - if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL - && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1) - ){ - assert( pParse->rc==SQLITE_OK ); - pParse->rc = SQLITE_ERROR; - assert( pParse->zErr==0 ); - pParse->zErr = sqlite3_mprintf( - "fts5: %s queries are not supported (detail!=full)", - pNear->nPhrase==1 ? "phrase": "NEAR" - ); - sqlite3_free(pRet); - pRet = 0; + if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; + if( pNear->nPhrase!=1 + || pPhrase->nTerm>1 + || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst) + ){ + sqlite3Fts5ParseError(pParse, + "fts5: %s queries are not supported (detail!=full)", + pNear->nPhrase==1 ? "phrase": "NEAR" + ); + sqlite3_free(pRet); + pRet = 0; + } + } + }else{ + fts5ExprAddChildren(pRet, pLeft); + fts5ExprAddChildren(pRet, pRight); } - - }else{ - fts5ExprAddChildren(pRet, pLeft); - fts5ExprAddChildren(pRet, pRight); } } } @@ -187230,14 +223549,14 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( sqlite3Fts5ParseNodeFree(pRight); }else{ - assert( pLeft->eType==FTS5_STRING + assert( pLeft->eType==FTS5_STRING || pLeft->eType==FTS5_TERM || pLeft->eType==FTS5_EOF || pLeft->eType==FTS5_AND ); - assert( pRight->eType==FTS5_STRING - || pRight->eType==FTS5_TERM - || pRight->eType==FTS5_EOF + assert( pRight->eType==FTS5_STRING + || pRight->eType==FTS5_TERM + || pRight->eType==FTS5_EOF ); if( pLeft->eType==FTS5_AND ){ @@ -187245,9 +223564,9 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( }else{ pPrev = pLeft; } - assert( pPrev->eType==FTS5_STRING - || pPrev->eType==FTS5_TERM - || pPrev->eType==FTS5_EOF + assert( pPrev->eType==FTS5_STRING + || pPrev->eType==FTS5_TERM + || pPrev->eType==FTS5_EOF ); if( pRight->eType==FTS5_EOF ){ @@ -187281,8 +223600,9 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd( return pRet; } +#ifdef SQLITE_TEST static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ - int nByte = 0; + sqlite3_int64 nByte = 0; Fts5ExprTerm *p; char *zQuoted; @@ -187290,7 +223610,7 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){ for(p=pTerm; p; p=p->pSynonym){ nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; } - zQuoted = sqlite3_malloc(nByte); + zQuoted = sqlite3_malloc64(nByte); if( zQuoted ){ int i = 0; @@ -187329,20 +223649,20 @@ static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){ } /* -** Compose a tcl-readable representation of expression pExpr. Return a -** pointer to a buffer containing that representation. It is the -** responsibility of the caller to at some point free the buffer using +** Compose a tcl-readable representation of expression pExpr. Return a +** pointer to a buffer containing that representation. It is the +** responsibility of the caller to at some point free the buffer using ** sqlite3_free(). */ static char *fts5ExprPrintTcl( - Fts5Config *pConfig, + Fts5Config *pConfig, const char *zNearsetCmd, Fts5ExprNode *pExpr ){ char *zRet = 0; if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ Fts5ExprNearset *pNear = pExpr->pNear; - int i; + int i; int iTerm; zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd); @@ -187392,9 +223712,9 @@ static char *fts5ExprPrintTcl( switch( pExpr->eType ){ case FTS5_AND: zOp = "AND"; break; case FTS5_NOT: zOp = "NOT"; break; - default: + default: assert( pExpr->eType==FTS5_OR ); - zOp = "OR"; + zOp = "OR"; break; } @@ -187420,12 +223740,21 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ }else if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ Fts5ExprNearset *pNear = pExpr->pNear; - int i; + int i; int iTerm; if( pNear->pColset ){ - int iCol = pNear->pColset->aiCol[0]; - zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]); + int ii; + Fts5Colset *pColset = pNear->pColset; + if( pColset->nCol>1 ) zRet = fts5PrintfAppend(zRet, "{"); + for(ii=0; iinCol; ii++){ + zRet = fts5PrintfAppend(zRet, "%s%s", + pConfig->azCol[pColset->aiCol[ii]], ii==pColset->nCol-1 ? "" : " " + ); + } + if( zRet ){ + zRet = fts5PrintfAppend(zRet, "%s : ", pColset->nCol>1 ? "}" : ""); + } if( zRet==0 ) return 0; } @@ -187465,9 +223794,9 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ switch( pExpr->eType ){ case FTS5_AND: zOp = " AND "; break; case FTS5_NOT: zOp = " NOT "; break; - default: + default: assert( pExpr->eType==FTS5_OR ); - zOp = " OR "; + zOp = " OR "; break; } @@ -187479,7 +223808,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ }else{ int e = pExpr->apChild[i]->eType; int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF); - zRet = fts5PrintfAppend(zRet, "%s%s%z%s", + zRet = fts5PrintfAppend(zRet, "%s%s%z%s", (i==0 ? "" : zOp), (b?"(":""), z, (b?")":"") ); @@ -187530,7 +223859,7 @@ static void fts5ExprFunction( } nConfig = 3 + (nArg-iArg); - azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig); + azConfig = (const char**)sqlite3_malloc64(sizeof(char*) * nConfig); if( azConfig==0 ){ sqlite3_result_error_nomem(pCtx); return; @@ -187539,14 +223868,16 @@ static void fts5ExprFunction( azConfig[1] = "main"; azConfig[2] = "tbl"; for(i=3; iArgnCol, zExpr, &pExpr, &zErr); } if( rc==SQLITE_OK ){ char *zText; @@ -187595,7 +223926,7 @@ static void fts5ExprFunctionTcl( /* ** The implementation of an SQLite user-defined-function that accepts a -** single integer as an argument. If the integer is an alpha-numeric +** single integer as an argument. If the integer is an alpha-numeric ** unicode code point, 1 is returned. Otherwise 0. */ static void fts5ExprIsAlnum( @@ -187604,14 +223935,19 @@ static void fts5ExprIsAlnum( sqlite3_value **apVal /* Function arguments */ ){ int iCode; + u8 aArr[32]; if( nArg!=1 ){ - sqlite3_result_error(pCtx, + sqlite3_result_error(pCtx, "wrong number of arguments to function fts5_isalnum", -1 ); return; } + memset(aArr, 0, sizeof(aArr)); + sqlite3Fts5UnicodeCatParse("L*", aArr); + sqlite3Fts5UnicodeCatParse("N*", aArr); + sqlite3Fts5UnicodeCatParse("Co", aArr); iCode = sqlite3_value_int(apVal[0]); - sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode)); + sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory((u32)iCode)]); } static void fts5ExprFold( @@ -187620,7 +223956,7 @@ static void fts5ExprFold( sqlite3_value **apVal /* Function arguments */ ){ if( nArg!=1 && nArg!=2 ){ - sqlite3_result_error(pCtx, + sqlite3_result_error(pCtx, "wrong number of arguments to function fts5_fold", -1 ); }else{ @@ -187631,12 +223967,14 @@ static void fts5ExprFold( sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics)); } } +#endif /* ifdef SQLITE_TEST */ /* ** This is called during initialization to register the fts5_expr() scalar ** UDF with the SQLite handle passed as the only argument. */ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ +#ifdef SQLITE_TEST struct Fts5ExprFunc { const char *z; void (*x)(sqlite3_context*,int,sqlite3_value**); @@ -187654,11 +223992,17 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){ struct Fts5ExprFunc *p = &aFunc[i]; rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0); } +#else + int rc = SQLITE_OK; + UNUSED_PARAM2(pGlobal,db); +#endif - /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */ + /* Avoid warnings indicating that sqlite3Fts5ParserTrace() and + ** sqlite3Fts5ParserFallback() are unused */ #ifndef NDEBUG (void)sqlite3Fts5ParserTrace; #endif + (void)sqlite3Fts5ParserFallback; return rc; } @@ -187702,17 +224046,26 @@ struct Fts5PoslistPopulator { int bMiss; }; +/* +** Clear the position lists associated with all phrases in the expression +** passed as the first argument. Argument bLive is true if the expression +** might be pointing to a real entry, otherwise it has just been reset. +** +** At present this function is only used for detail=col and detail=none +** fts5 tables. This implies that all phrases must be at most 1 token +** in size, as phrase matches are not supported without detail=full. +*/ static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){ Fts5PoslistPopulator *pRet; - pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); + pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); if( pRet ){ int i; memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase); for(i=0; inPhrase; i++){ Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist; Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; - assert( pExpr->apExprPhrase[i]->nTerm==1 ); - if( bLive && + assert( pExpr->apExprPhrase[i]->nTerm<=1 ); + if( bLive && (pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof) ){ pRet[i].bMiss = 1; @@ -187779,9 +224132,9 @@ static int fts5ExprPopulatePoslistsCb( static int sqlite3Fts5ExprPopulatePoslists( Fts5Config *pConfig, - Fts5Expr *pExpr, + Fts5Expr *pExpr, Fts5PoslistPopulator *aPopulator, - int iCol, + int iCol, const char *z, int n ){ int i; @@ -187793,7 +224146,7 @@ static int sqlite3Fts5ExprPopulatePoslists( for(i=0; inPhrase; i++){ Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode; Fts5Colset *pColset = pNode->pNear->pColset; - if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) + if( (pColset && 0==fts5ExprColsetTest(pColset, iCol)) || aPopulator[i].bMiss ){ aPopulator[i].bOk = 0; @@ -187802,7 +224155,7 @@ static int sqlite3Fts5ExprPopulatePoslists( } } - return sqlite3Fts5Tokenize(pConfig, + return sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb ); } @@ -187867,12 +224220,12 @@ static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ } /* -** This function is only called for detail=columns tables. +** This function is only called for detail=columns tables. */ static int sqlite3Fts5ExprPhraseCollist( - Fts5Expr *pExpr, - int iPhrase, - const u8 **ppCollist, + Fts5Expr *pExpr, + int iPhrase, + const u8 **ppCollist, int *pnCollist ){ Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase]; @@ -187882,8 +224235,8 @@ static int sqlite3Fts5ExprPhraseCollist( assert( iPhrase>=0 && iPhrasenPhrase ); assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS ); - if( pNode->bEof==0 - && pNode->iRowid==pExpr->pRoot->iRowid + if( pNode->bEof==0 + && pNode->iRowid==pExpr->pRoot->iRowid && pPhrase->poslist.n>0 ){ Fts5ExprTerm *pTerm = &pPhrase->aTerm[0]; @@ -187904,7 +224257,6 @@ static int sqlite3Fts5ExprPhraseCollist( return rc; } - /* ** 2014 August 11 ** @@ -187942,10 +224294,11 @@ struct Fts5Hash { }; /* -** Each entry in the hash table is represented by an object of the -** following type. Each object, its key (zKey[]) and its current data -** are stored in a single memory allocation. The position list data -** immediately follows the key data in memory. +** Each entry in the hash table is represented by an object of the +** following type. Each object, its key (a nul-terminated string) and +** its current data are stored in a single memory allocation. The +** key immediately follows the object in memory. The position list +** data immediately follows the key data in memory. ** ** The data that follows the key is in a similar, but not identical format ** to the doclist data stored in the database. It is: @@ -187965,24 +224318,24 @@ struct Fts5Hash { struct Fts5HashEntry { Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */ Fts5HashEntry *pScanNext; /* Next entry in sorted order */ - + int nAlloc; /* Total size of allocation */ int iSzPoslist; /* Offset of space for 4-byte poslist size */ int nData; /* Total bytes of data (incl. structure) */ - int nKey; /* Length of zKey[] in bytes */ + int nKey; /* Length of key in bytes */ u8 bDel; /* Set delete-flag @ iSzPoslist */ u8 bContent; /* Set content-flag (detail=none mode) */ i16 iCol; /* Column of last value written */ int iPos; /* Position of last value written */ i64 iRowid; /* Rowid of last value written */ - char zKey[8]; /* Nul-terminated entry key */ }; /* -** Size of Fts5HashEntry without the zKey[] array. +** Eqivalent to: +** +** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; } */ -#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8) - +#define fts5EntryKey(p) ( ((char *)(&(p)[1])) ) /* @@ -187996,20 +224349,20 @@ static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ - int nByte; + sqlite3_int64 nByte; memset(pNew, 0, sizeof(Fts5Hash)); pNew->pnByte = pnByte; pNew->eDetail = pConfig->eDetail; pNew->nSlot = 1024; nByte = sizeof(Fts5HashEntry*) * pNew->nSlot; - pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte); + pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc64(nByte); if( pNew->aSlot==0 ){ sqlite3_free(pNew); *ppNew = 0; rc = SQLITE_NOMEM; }else{ - memset(pNew->aSlot, 0, nByte); + memset(pNew->aSlot, 0, (size_t)nByte); } } return rc; @@ -188071,16 +224424,17 @@ static int fts5HashResize(Fts5Hash *pHash){ Fts5HashEntry **apNew; Fts5HashEntry **apOld = pHash->aSlot; - apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*)); + apNew = (Fts5HashEntry**)sqlite3_malloc64(nNew*sizeof(Fts5HashEntry*)); if( !apNew ) return SQLITE_NOMEM; memset(apNew, 0, nNew*sizeof(Fts5HashEntry*)); for(i=0; inSlot; i++){ while( apOld[i] ){ - int iHash; + unsigned int iHash; Fts5HashEntry *p = apOld[i]; apOld[i] = p->pHashNext; - iHash = fts5HashKey(nNew, (u8*)p->zKey, (int)strlen(p->zKey)); + iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), + (int)strlen(fts5EntryKey(p))); p->pHashNext = apNew[iHash]; apNew[iHash] = p; } @@ -188092,19 +224446,25 @@ static int fts5HashResize(Fts5Hash *pHash){ return SQLITE_OK; } -static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ +static int fts5HashAddPoslistSize( + Fts5Hash *pHash, + Fts5HashEntry *p, + Fts5HashEntry *p2 +){ + int nRet = 0; if( p->iSzPoslist ){ - u8 *pPtr = (u8*)p; + u8 *pPtr = p2 ? (u8*)p2 : (u8*)p; + int nData = p->nData; if( pHash->eDetail==FTS5_DETAIL_NONE ){ - assert( p->nData==p->iSzPoslist ); + assert( nData==p->iSzPoslist ); if( p->bDel ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; if( p->bContent ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; } } }else{ - int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ + int nSz = (nData - p->iSzPoslist - 1); /* Size in bytes */ int nPos = nSz*2 + p->bDel; /* Value of nPos field */ assert( p->bDel==0 || p->bDel==1 ); @@ -188114,14 +224474,19 @@ static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ int nByte = sqlite3Fts5GetVarintLen((u32)nPos); memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); - p->nData += (nByte-1); + nData += (nByte-1); } } - p->iSzPoslist = 0; - p->bDel = 0; - p->bContent = 0; + nRet = nData - p->nData; + if( p2==0 ){ + p->iSzPoslist = 0; + p->bDel = 0; + p->bContent = 0; + p->nData = nData; + } } + return nRet; } /* @@ -188145,15 +224510,16 @@ static int sqlite3Fts5HashWrite( u8 *pPtr; int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ int bNew; /* If non-delete entry should be written */ - + bNew = (pHash->eDetail==FTS5_DETAIL_FULL); /* Attempt to locate an existing hash entry */ iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ - if( p->zKey[0]==bByte + char *zKey = fts5EntryKey(p); + if( zKey[0]==bByte && p->nKey==nToken - && memcmp(&p->zKey[1], pToken, nToken)==0 + && memcmp(&zKey[1], pToken, nToken)==0 ){ break; } @@ -188162,7 +224528,8 @@ static int sqlite3Fts5HashWrite( /* If an existing hash entry cannot be found, create a new one. */ if( p==0 ){ /* Figure out how much space to allocate */ - int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64; + char *zKey; + sqlite3_int64 nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64; if( nByte<128 ) nByte = 128; /* Grow the Fts5Hash.aSlot[] array if necessary. */ @@ -188173,16 +224540,17 @@ static int sqlite3Fts5HashWrite( } /* Allocate new Fts5HashEntry and add it to the hash table. */ - p = (Fts5HashEntry*)sqlite3_malloc(nByte); + p = (Fts5HashEntry*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; - memset(p, 0, FTS5_HASHENTRYSIZE); - p->nAlloc = nByte; - p->zKey[0] = bByte; - memcpy(&p->zKey[1], pToken, nToken); - assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) ); + memset(p, 0, sizeof(Fts5HashEntry)); + p->nAlloc = (int)nByte; + zKey = fts5EntryKey(p); + zKey[0] = bByte; + memcpy(&zKey[1], pToken, nToken); + assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) ); p->nKey = nToken; - p->zKey[nToken+1] = '\0'; - p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE; + zKey[nToken+1] = '\0'; + p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry); p->pHashNext = pHash->aSlot[iHash]; pHash->aSlot[iHash] = p; pHash->nEntry++; @@ -188197,11 +224565,10 @@ static int sqlite3Fts5HashWrite( p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); } - nIncr += p->nData; }else{ - /* Appending to an existing hash-entry. Check that there is enough - ** space to append the largest possible new entry. Worst case scenario + /* Appending to an existing hash-entry. Check that there is enough + ** space to append the largest possible new entry. Worst case scenario ** is: ** ** + 9 bytes for a new rowid, @@ -188211,12 +224578,12 @@ static int sqlite3Fts5HashWrite( ** + 5 bytes for the new position offset (32-bit max). */ if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ - int nNew = p->nAlloc * 2; + sqlite3_int64 nNew = p->nAlloc * 2; Fts5HashEntry *pNew; Fts5HashEntry **pp; - pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); + pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew); if( pNew==0 ) return SQLITE_NOMEM; - pNew->nAlloc = nNew; + pNew->nAlloc = (int)nNew; for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext); *pp = pNew; p = pNew; @@ -188230,8 +224597,9 @@ static int sqlite3Fts5HashWrite( /* If this is a new rowid, append the 4-byte size field for the previous ** entry, and the new rowid for this entry. */ if( iRowid!=p->iRowid ){ - fts5HashAddPoslistSize(pHash, p); - p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); + u64 iDiff = (u64)iRowid - (u64)p->iRowid; + fts5HashAddPoslistSize(pHash, p, 0); + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iDiff); p->iRowid = iRowid; bNew = 1; p->iSzPoslist = p->nData; @@ -188247,7 +224615,7 @@ static int sqlite3Fts5HashWrite( p->bContent = 1; }else{ /* Append a new column value, if necessary */ - assert( iCol>=p->iCol ); + assert_nc( iCol>=p->iCol ); if( iCol!=p->iCol ){ if( pHash->eDetail==FTS5_DETAIL_FULL ){ pPtr[p->nData++] = 0x01; @@ -188300,9 +224668,11 @@ static Fts5HashEntry *fts5HashEntryMerge( p1 = 0; }else{ int i = 0; - while( p1->zKey[i]==p2->zKey[i] ) i++; + char *zKey1 = fts5EntryKey(p1); + char *zKey2 = fts5EntryKey(p2); + while( zKey1[i]==zKey2[i] ) i++; - if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){ + if( ((u8)zKey1[i])>((u8)zKey2[i]) ){ /* p2 is smaller */ *ppOut = p2; ppOut = &p2->pScanNext; @@ -188327,7 +224697,7 @@ static Fts5HashEntry *fts5HashEntryMerge( ** list. */ static int fts5HashEntrySort( - Fts5Hash *pHash, + Fts5Hash *pHash, const char *pTerm, int nTerm, /* Query prefix, if any */ Fts5HashEntry **ppSorted ){ @@ -188338,14 +224708,16 @@ static int fts5HashEntrySort( int i; *ppSorted = 0; - ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot); + ap = sqlite3_malloc64(sizeof(Fts5HashEntry*) * nMergeSlot); if( !ap ) return SQLITE_NOMEM; memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot); for(iSlot=0; iSlotnSlot; iSlot++){ Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ - if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){ + if( pTerm==0 + || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) + ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; for(i=0; ap[i]; i++){ @@ -188373,23 +224745,36 @@ static int fts5HashEntrySort( */ static int sqlite3Fts5HashQuery( Fts5Hash *pHash, /* Hash table to query */ + int nPre, const char *pTerm, int nTerm, /* Query term */ - const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + void **ppOut, /* OUT: Pointer to new object */ int *pnDoclist /* OUT: Size of doclist in bytes */ ){ unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); + char *zKey = 0; Fts5HashEntry *p; for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ - if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break; + zKey = fts5EntryKey(p); + assert( p->nKey+1==(int)strlen(zKey) ); + if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break; } if( p ){ - fts5HashAddPoslistSize(pHash, p); - *ppDoclist = (const u8*)&p->zKey[nTerm+1]; - *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; + int nList = p->nData - nHashPre; + u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); + if( pRet ){ + Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre]; + memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList); + nList += fts5HashAddPoslistSize(pHash, p, pFaux); + *pnDoclist = nList; + }else{ + *pnDoclist = 0; + return SQLITE_NOMEM; + } }else{ - *ppDoclist = 0; + *ppOut = 0; *pnDoclist = 0; } @@ -188420,11 +224805,12 @@ static void sqlite3Fts5HashScanEntry( ){ Fts5HashEntry *p; if( (p = pHash->pScan) ){ - int nTerm = (int)strlen(p->zKey); - fts5HashAddPoslistSize(pHash, p); - *pzTerm = p->zKey; - *ppDoclist = (const u8*)&p->zKey[nTerm+1]; - *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1); + char *zKey = fts5EntryKey(p); + int nTerm = (int)strlen(zKey); + fts5HashAddPoslistSize(pHash, p, 0); + *pzTerm = zKey; + *ppDoclist = (const u8*)&zKey[nTerm+1]; + *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); }else{ *pzTerm = 0; *ppDoclist = 0; @@ -188432,7 +224818,6 @@ static void sqlite3Fts5HashScanEntry( } } - /* ** 2014 May 31 ** @@ -188445,7 +224830,7 @@ static void sqlite3Fts5HashScanEntry( ** ****************************************************************************** ** -** Low level access to the FTS index stored in the database file. The +** Low level access to the FTS index stored in the database file. The ** routines in this file file implement all read and write access to the ** %_data table. Other parts of the system access this functionality via ** the interface defined in fts5Int.h. @@ -188461,10 +224846,10 @@ static void sqlite3Fts5HashScanEntry( ** As well as the main term index, there may be up to 31 prefix indexes. ** The format is similar to FTS3/4, except that: ** -** * all segment b-tree leaf data is stored in fixed size page records -** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is -** taken to ensure it is possible to iterate in either direction through -** the entries in a doclist, or to seek to a specific entry within a +** * all segment b-tree leaf data is stored in fixed size page records +** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is +** taken to ensure it is possible to iterate in either direction through +** the entries in a doclist, or to seek to a specific entry within a ** doclist, without loading it into memory. ** ** * large doclists that span many pages have associated "doclist index" @@ -188497,14 +224882,14 @@ static void sqlite3Fts5HashScanEntry( ** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB); ** ** , contains the following 5 types of records. See the comments surrounding -** the FTS5_*_ROWID macros below for a description of how %_data rowids are +** the FTS5_*_ROWID macros below for a description of how %_data rowids are ** assigned to each fo them. ** ** 1. Structure Records: ** ** The set of segments that make up an index - the index structure - are ** recorded in a single record within the %_data table. The record consists -** of a single 32-bit configuration cookie value followed by a list of +** of a single 32-bit configuration cookie value followed by a list of ** SQLite varints. If the FTS table features more than one index (because ** there are one or more prefix indexes), it is guaranteed that all share ** the same cookie value. @@ -188536,7 +224921,7 @@ static void sqlite3Fts5HashScanEntry( ** ** TERM/DOCLIST FORMAT: ** -** Most of each segment leaf is taken up by term/doclist data. The +** Most of each segment leaf is taken up by term/doclist data. The ** general format of term/doclist, starting with the first term ** on the leaf page, is: ** @@ -188579,7 +224964,7 @@ static void sqlite3Fts5HashScanEntry( ** ** PAGE FORMAT ** -** Each leaf page begins with a 4-byte header containing 2 16-bit +** Each leaf page begins with a 4-byte header containing 2 16-bit ** unsigned integer fields in big-endian format. They are: ** ** * The byte offset of the first rowid on the page, if it exists @@ -188614,7 +224999,7 @@ static void sqlite3Fts5HashScanEntry( ** 5. Segment doclist indexes: ** ** Doclist indexes are themselves b-trees, however they usually consist of -** a single leaf record only. The format of each doclist index leaf page +** a single leaf record only. The format of each doclist index leaf page ** is: ** ** * Flags byte. Bits are: @@ -188624,8 +225009,8 @@ static void sqlite3Fts5HashScanEntry( ** ** * First rowid on page indicated by previous field. As a varint. ** -** * A list of varints, one for each subsequent termless page. A -** positive delta if the termless page contains at least one rowid, +** * A list of varints, one for each subsequent termless page. A +** positive delta if the termless page contains at least one rowid, ** or an 0x00 byte otherwise. ** ** Internal doclist index nodes are: @@ -188638,7 +225023,7 @@ static void sqlite3Fts5HashScanEntry( ** * Copy of first rowid on page indicated by previous field. As a varint. ** ** * A list of delta-encoded varints - the first rowid on each subsequent -** child page. +** child page. ** */ @@ -188655,7 +225040,7 @@ static void sqlite3Fts5HashScanEntry( ** ** Each segment has a unique non-zero 16-bit id. ** -** The rowid for each segment leaf is found by passing the segment id and +** The rowid for each segment leaf is found by passing the segment id and ** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered ** sequentially starting from 1. */ @@ -188674,11 +225059,6 @@ static void sqlite3Fts5HashScanEntry( #define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno) #define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno) -/* -** Maximum segments permitted in a single index -*/ -#define FTS5_MAX_SEGMENT 2000 - #ifdef SQLITE_DEBUG static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; } #endif @@ -188757,7 +225137,7 @@ struct Fts5DoclistIter { /* ** The contents of the "structure" record for each index are represented -** using an Fts5Structure record in memory. Which uses instances of the +** using an Fts5Structure record in memory. Which uses instances of the ** other Fts5StructureXXX types as components. */ struct Fts5StructureSegment { @@ -188830,10 +225210,10 @@ struct Fts5CResult { ** Current leaf page number within segment. ** ** iLeafOffset: -** Byte offset within the current leaf that is the first byte of the +** Byte offset within the current leaf that is the first byte of the ** position list data (one byte passed the position-list size field). ** rowid field of the current entry. Usually this is the size field of the -** position list data. The exception is if the rowid for the current entry +** position list data. The exception is if the rowid for the current entry ** is the last thing on the leaf page. ** ** pLeaf: @@ -188847,7 +225227,7 @@ struct Fts5CResult { ** Mask of FTS5_SEGITER_XXX values. Interpreted as follows: ** ** FTS5_SEGITER_ONETERM: -** If set, set the iterator to point to EOF after the current doclist +** If set, set the iterator to point to EOF after the current doclist ** has been exhausted. Do not proceed to the next term in the segment. ** ** FTS5_SEGITER_REVERSE: @@ -188871,12 +225251,12 @@ struct Fts5SegIter { int iLeafPgno; /* Current leaf page number */ Fts5Data *pLeaf; /* Current leaf data */ Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ - int iLeafOffset; /* Byte offset within current leaf */ + i64 iLeafOffset; /* Byte offset within current leaf */ /* Next method */ void (*xNext)(Fts5Index*, Fts5SegIter*, int*); - /* The page and offset from which the current term was read. The offset + /* The page and offset from which the current term was read. The offset ** is the offset of the first rowid in the current doclist. */ int iTermLeafPgno; int iTermLeafOffset; @@ -188899,7 +225279,7 @@ struct Fts5SegIter { }; /* -** Argument is a pointer to an Fts5Data structure that contains a +** Argument is a pointer to an Fts5Data structure that contains a ** leaf page. */ #define ASSERT_SZLEAF_OK(x) assert( \ @@ -188909,7 +225289,7 @@ struct Fts5SegIter { #define FTS5_SEGITER_ONETERM 0x01 #define FTS5_SEGITER_REVERSE 0x02 -/* +/* ** Argument is a pointer to an Fts5Data structure that contains a leaf ** page. This macro evaluates to true if the leaf contains no terms, or ** false if it contains at least one term. @@ -188931,13 +225311,13 @@ struct Fts5SegIter { ** on empty segments. ** ** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an -** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the +** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the ** comparison in this context is the index of the iterator that currently ** points to the smaller term/rowid combination. Iterators at EOF are ** considered to be greater than all other iterators. ** ** aFirst[1] contains the index in aSeg[] of the iterator that points to -** the smallest key overall. aFirst[0] is unused. +** the smallest key overall. aFirst[0] is unused. ** ** poslist: ** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. @@ -188947,7 +225327,6 @@ struct Fts5Iter { Fts5IndexIter base; /* Base class containing output vars */ Fts5Index *pIndex; /* Index that owns this iterator */ - Fts5Structure *pStruct; /* Database structure for this iterator */ Fts5Buffer poslist; /* Buffer containing current poslist */ Fts5Colset *pColset; /* Restrict matches to these columns */ @@ -189000,7 +225379,7 @@ static void fts5PutU16(u8 *aOut, u16 iVal){ static u16 fts5GetU16(const u8 *aIn){ return ((u16)aIn[0] << 8) + aIn[1]; -} +} /* ** Allocate and return a buffer at least nByte bytes in size. @@ -189008,7 +225387,7 @@ static u16 fts5GetU16(const u8 *aIn){ ** If an OOM error is encountered, return NULL and set the error code in ** the Fts5Index handle passed as the first argument. */ -static void *fts5IdxMalloc(Fts5Index *p, int nByte){ +static void *fts5IdxMalloc(Fts5Index *p, sqlite3_int64 nByte){ return sqlite3Fts5MallocZero(&p->rc, nByte); } @@ -189041,8 +225420,11 @@ static int fts5BufferCompareBlob( ** res = *pLeft - *pRight */ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){ - int nCmp = MIN(pLeft->n, pRight->n); - int res = memcmp(pLeft->p, pRight->p, nCmp); + int nCmp, res; + nCmp = MIN(pLeft->n, pRight->n); + assert( nCmp<=0 || pLeft->p!=0 ); + assert( nCmp<=0 || pRight->p!=0 ); + res = fts5Memcmp(pLeft->p, pRight->p, nCmp); return (res==0 ? (pLeft->n - pRight->n) : res); } @@ -189055,7 +225437,7 @@ static int fts5LeafFirstTermOff(Fts5Data *pLeaf){ /* ** Close the read-only blob handle, if it is open. */ -static void fts5CloseReader(Fts5Index *p){ +static void sqlite3Fts5IndexCloseReader(Fts5Index *p){ if( p->pReader ){ sqlite3_blob *pReader = p->pReader; p->pReader = 0; @@ -189063,11 +225445,10 @@ static void fts5CloseReader(Fts5Index *p){ } } - /* ** Retrieve a record from the %_data table. ** -** If an error occurs, NULL is returned and an error left in the +** If an error occurs, NULL is returned and an error left in the ** Fts5Index object. */ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ @@ -189085,16 +225466,16 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ assert( p->pReader==0 ); p->pReader = pBlob; if( rc!=SQLITE_OK ){ - fts5CloseReader(p); + sqlite3Fts5IndexCloseReader(p); } if( rc==SQLITE_ABORT ) rc = SQLITE_OK; } - /* If the blob handle is not open at this point, open it and seek + /* If the blob handle is not open at this point, open it and seek ** to the requested entry. */ if( p->pReader==0 && rc==SQLITE_OK ){ Fts5Config *pConfig = p->pConfig; - rc = sqlite3_blob_open(pConfig->db, + rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader ); } @@ -189102,15 +225483,15 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ /* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls ** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead. ** All the reasons those functions might return SQLITE_ERROR - missing - ** table, missing row, non-blob/text in block column - indicate + ** table, missing row, non-blob/text in block column - indicate ** backing store corruption. */ if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT; if( rc==SQLITE_OK ){ u8 *aOut = 0; /* Read blob data into this buffer */ int nByte = sqlite3_blob_bytes(p->pReader); - int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; - pRet = (Fts5Data*)sqlite3_malloc(nAlloc); + sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; + pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); if( pRet ){ pRet->nn = nByte; aOut = pRet->p = (u8*)&pRet[1]; @@ -189126,6 +225507,8 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ pRet = 0; }else{ /* TODO1: Fix this */ + pRet->p[nByte] = 0x00; + pRet->p[nByte+1] = 0x00; pRet->szLeaf = fts5GetU16(&pRet->p[2]); } } @@ -189137,6 +225520,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ return pRet; } + /* ** Release a reference to data record returned by an earlier call to ** fts5DataRead(). @@ -189148,7 +225532,7 @@ static void fts5DataRelease(Fts5Data *pData){ static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ Fts5Data *pRet = fts5DataRead(p, iRowid); if( pRet ){ - if( pRet->szLeaf>pRet->nn ){ + if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){ p->rc = FTS5_CORRUPT; fts5DataRelease(pRet); pRet = 0; @@ -189164,7 +225548,9 @@ static int fts5IndexPrepareStmt( ){ if( p->rc==SQLITE_OK ){ if( zSql ){ - p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0); + p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB, + ppStmt, 0); }else{ p->rc = SQLITE_NOMEM; } @@ -189183,7 +225569,7 @@ static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){ if( p->pWriter==0 ){ Fts5Config *pConfig = p->pConfig; fts5IndexPrepareStmt(p, &p->pWriter, sqlite3_mprintf( - "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)", + "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)", pConfig->zDb, pConfig->zName )); if( p->rc ) return; @@ -189193,6 +225579,7 @@ static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){ sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC); sqlite3_step(p->pWriter); p->rc = sqlite3_reset(p->pWriter); + sqlite3_bind_null(p->pWriter, 2); } /* @@ -189204,22 +225591,12 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){ if( p->rc!=SQLITE_OK ) return; if( p->pDeleter==0 ){ - int rc; Fts5Config *pConfig = p->pConfig; char *zSql = sqlite3_mprintf( - "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?", + "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?", pConfig->zDb, pConfig->zName ); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0); - sqlite3_free(zSql); - } - if( rc!=SQLITE_OK ){ - p->rc = rc; - return; - } + if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return; } sqlite3_bind_int64(p->pDeleter, 1, iFirst); @@ -189250,7 +225627,7 @@ static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){ } /* -** Release a reference to an Fts5Structure object returned by an earlier +** Release a reference to an Fts5Structure object returned by an earlier ** call to fts5StructureRead() or fts5StructureDecode(). */ static void fts5StructureRelease(Fts5Structure *pStruct){ @@ -189268,6 +225645,58 @@ static void fts5StructureRef(Fts5Structure *pStruct){ pStruct->nRef++; } +static void *sqlite3Fts5StructureRef(Fts5Index *p){ + fts5StructureRef(p->pStruct); + return (void*)p->pStruct; +} +static void sqlite3Fts5StructureRelease(void *p){ + if( p ){ + fts5StructureRelease((Fts5Structure*)p); + } +} +static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){ + if( p->pStruct!=(Fts5Structure*)pStruct ){ + return SQLITE_ABORT; + } + return SQLITE_OK; +} + +/* +** Ensure that structure object (*pp) is writable. +** +** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If +** an error occurs, (*pRc) is set to an SQLite error code before returning. +*/ +static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){ + Fts5Structure *p = *pp; + if( *pRc==SQLITE_OK && p->nRef>1 ){ + i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel); + Fts5Structure *pNew; + pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte); + if( pNew ){ + int i; + memcpy(pNew, p, nByte); + for(i=0; inLevel; i++) pNew->aLevel[i].aSeg = 0; + for(i=0; inLevel; i++){ + Fts5StructureLevel *pLvl = &pNew->aLevel[i]; + nByte = sizeof(Fts5StructureSegment) * pNew->aLevel[i].nSeg; + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(pRc, nByte); + if( pLvl->aSeg==0 ){ + for(i=0; inLevel; i++){ + sqlite3_free(pNew->aLevel[i].aSeg); + } + sqlite3_free(pNew); + return; + } + memcpy(pLvl->aSeg, p->aLevel[i].aSeg, nByte); + } + p->nRef--; + pNew->nRef = 1; + } + *pp = pNew; + } +} + /* ** Deserialize and return the structure record currently stored in serialized ** form within buffer pData/nData. @@ -189291,7 +225720,7 @@ static int fts5StructureDecode( int iLvl; int nLevel = 0; int nSegment = 0; - int nByte; /* Bytes of space to allocate at pRet */ + sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */ Fts5Structure *pRet = 0; /* Structure object to return */ /* Grab the cookie value */ @@ -189302,6 +225731,11 @@ static int fts5StructureDecode( ** structure record. */ i += fts5GetVarint32(&pData[i], nLevel); i += fts5GetVarint32(&pData[i], nSegment); + if( nLevel>FTS5_MAX_SEGMENT || nLevel<0 + || nSegment>FTS5_MAX_SEGMENT || nSegment<0 + ){ + return FTS5_CORRUPT; + } nByte = ( sizeof(Fts5Structure) + /* Main structure */ sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */ @@ -189324,25 +225758,35 @@ static int fts5StructureDecode( }else{ i += fts5GetVarint32(&pData[i], pLvl->nMerge); i += fts5GetVarint32(&pData[i], nTotal); - assert( nTotal>=pLvl->nMerge ); - pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, + if( nTotalnMerge ) rc = FTS5_CORRUPT; + pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, nTotal * sizeof(Fts5StructureSegment) ); + nSegment -= nTotal; } if( rc==SQLITE_OK ){ pLvl->nSeg = nTotal; for(iSeg=0; iSegaSeg[iSeg]; if( i>=nData ){ rc = FTS5_CORRUPT; break; } - i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid); - i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst); - i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast); + i += fts5GetVarint32(&pData[i], pSeg->iSegid); + i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst); + i += fts5GetVarint32(&pData[i], pSeg->pgnoLast); + if( pSeg->pgnoLastpgnoFirst ){ + rc = FTS5_CORRUPT; + break; + } } + if( iLvl>0 && pLvl[-1].nMerge && nTotal==0 ) rc = FTS5_CORRUPT; + if( iLvl==nLevel-1 && pLvl->nMerge ) rc = FTS5_CORRUPT; } } + if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT; + if( rc!=SQLITE_OK ){ fts5StructureRelease(pRet); pRet = 0; @@ -189354,18 +225798,20 @@ static int fts5StructureDecode( } /* -** +** Add a level to the Fts5Structure.aLevel[] array of structure object +** (*ppStruct). */ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ + fts5StructureMakeWritable(pRc, ppStruct); if( *pRc==SQLITE_OK ){ Fts5Structure *pStruct = *ppStruct; int nLevel = pStruct->nLevel; - int nByte = ( + sqlite3_int64 nByte = ( sizeof(Fts5Structure) + /* Main structure */ sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */ ); - pStruct = sqlite3_realloc(pStruct, nByte); + pStruct = sqlite3_realloc64(pStruct, nByte); if( pStruct ){ memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel)); pStruct->nLevel++; @@ -189381,19 +225827,19 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){ ** segments. */ static void fts5StructureExtendLevel( - int *pRc, - Fts5Structure *pStruct, - int iLvl, - int nExtra, + int *pRc, + Fts5Structure *pStruct, + int iLvl, + int nExtra, int bInsert ){ if( *pRc==SQLITE_OK ){ Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl]; Fts5StructureSegment *aNew; - int nByte; + sqlite3_int64 nByte; nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment); - aNew = sqlite3_realloc(pLvl->aSeg, nByte); + aNew = sqlite3_realloc64(pLvl->aSeg, nByte); if( aNew ){ if( bInsert==0 ){ memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra); @@ -189420,7 +225866,7 @@ static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){ /* TODO: Do we need this if the leaf-index is appended? Probably... */ memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); - if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){ + if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); } fts5DataRelease(pData); @@ -189438,7 +225884,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){ if( p->rc==SQLITE_OK ){ if( p->pDataVersion==0 ){ - p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, + p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion, sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb) ); if( p->rc ) return 0; @@ -189457,7 +225903,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){ ** Read, deserialize and return the structure record. ** ** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array -** are over-allocated as described for function fts5StructureDecode() +** are over-allocated as described for function fts5StructureDecode() ** above. ** ** If an error occurs, NULL is returned and an error code left in the @@ -189606,8 +226052,8 @@ static int fts5SegmentSize(Fts5StructureSegment *pSeg){ } /* -** Return a copy of index structure pStruct. Except, promote as many -** segments as possible to level iPromote. If an OOM occurs, NULL is +** Return a copy of index structure pStruct. Except, promote as many +** segments as possible to level iPromote. If an OOM occurs, NULL is ** returned. */ static void fts5StructurePromoteTo( @@ -189647,8 +226093,8 @@ static void fts5StructurePromoteTo( ** ** b) If the segment just written is larger than the newest segment on ** the next populated level, then that segment, and any other adjacent -** segments that are also smaller than the one just written, are -** promoted. +** segments that are also smaller than the one just written, are +** promoted. ** ** If one or more segments are promoted, the structure object is updated ** to reflect this. @@ -189682,7 +226128,7 @@ static void fts5StructurePromote( if( sz>szMax ) szMax = sz; } if( szMax>=szSeg ){ - /* Condition (a) is true. Promote the newest segment on level + /* Condition (a) is true. Promote the newest segment on level ** iLvl to level iTst. */ iPromote = iTst; szPromote = szMax; @@ -189701,7 +226147,7 @@ static void fts5StructurePromote( /* -** Advance the iterator passed as the only argument. If the end of the +** Advance the iterator passed as the only argument. If the end of the ** doclist-index page is reached, return non-zero. */ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){ @@ -189716,7 +226162,7 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){ }else{ int iOff; for(iOff=pLvl->iOff; iOffnn; iOff++){ - if( pData->p[iOff] ) break; + if( pData->p[iOff] ) break; } if( iOffnn ){ @@ -189746,7 +226192,7 @@ static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){ if( pLvl[1].bEof==0 ){ fts5DataRelease(pLvl->pData); memset(pLvl, 0, sizeof(Fts5DlidxLvl)); - pLvl->pData = fts5DataRead(p, + pLvl->pData = fts5DataRead(p, FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno) ); if( pLvl->pData ) fts5DlidxLvlNext(pLvl); @@ -189766,7 +226212,7 @@ static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){ ** points to the first rowid in the doclist-index. ** ** pData: -** pointer to doclist-index record, +** pointer to doclist-index record, ** ** When this function is called pIter->iLeafPgno is the page number the ** doclist is associated with (the one featuring the term). @@ -189797,7 +226243,7 @@ static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){ Fts5DlidxLvl *pChild = &pLvl[-1]; fts5DataRelease(pChild->pData); memset(pChild, 0, sizeof(Fts5DlidxLvl)); - pChild->pData = fts5DataRead(p, + pChild->pData = fts5DataRead(p, FTS5_DLIDX_ROWID(pIter->iSegid, i-1, pLvl->iLeafPgno) ); } @@ -189820,8 +226266,8 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){ int ii; int nZero = 0; - /* Currently iOff points to the first byte of a varint. This block - ** decrements iOff until it points to the first byte of the previous + /* Currently iOff points to the first byte of a varint. This block + ** decrements iOff until it points to the first byte of the previous ** varint. Taking care not to read any memory locations that occur ** before the buffer in memory. */ iLimit = (iOff>9 ? iOff-9 : 0); @@ -189866,7 +226312,7 @@ static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){ if( pLvl[1].bEof==0 ){ fts5DataRelease(pLvl->pData); memset(pLvl, 0, sizeof(Fts5DlidxLvl)); - pLvl->pData = fts5DataRead(p, + pLvl->pData = fts5DataRead(p, FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno) ); if( pLvl->pData ){ @@ -189907,10 +226353,10 @@ static Fts5DlidxIter *fts5DlidxIterInit( int bDone = 0; for(i=0; p->rc==SQLITE_OK && bDone==0; i++){ - int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); + sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl); Fts5DlidxIter *pNew; - pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte); + pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte); if( pNew==0 ){ p->rc = SQLITE_NOMEM; }else{ @@ -189965,7 +226411,7 @@ static void fts5SegIterNextPage( pIter->pLeaf = pIter->pNextLeaf; pIter->pNextLeaf = 0; }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){ - pIter->pLeaf = fts5LeafRead(p, + pIter->pLeaf = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno) ); }else{ @@ -190009,7 +226455,7 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){ ** Fts5SegIter.nPos ** Fts5SegIter.bDel ** -** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the +** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the ** position list content (if any). */ static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){ @@ -190043,7 +226489,7 @@ static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ - int iOff = pIter->iLeafOffset; + i64 iOff = pIter->iLeafOffset; ASSERT_SZLEAF_OK(pIter->pLeaf); if( iOff>=pIter->pLeaf->szLeaf ){ @@ -190060,7 +226506,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ } /* -** Fts5SegIter.iLeafOffset currently points to the first byte of the +** Fts5SegIter.iLeafOffset currently points to the first byte of the ** "nSuffix" field of a term. Function parameter nKeep contains the value ** of the "nPrefix" field (if there was one - it is passed 0 if this is ** the first term in the segment). @@ -190071,21 +226517,22 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ ** Fts5SegIter.rowid ** ** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of -** the first position list. The position list belonging to document +** the first position list. The position list belonging to document ** (Fts5SegIter.iRowid). */ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ - int iOff = pIter->iLeafOffset; /* Offset to read at */ + i64 iOff = pIter->iLeafOffset; /* Offset to read at */ int nNew; /* Bytes of new data */ iOff += fts5GetVarint32(&a[iOff], nNew); - if( iOff+nNew>pIter->pLeaf->nn ){ + if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){ p->rc = FTS5_CORRUPT; return; } pIter->term.n = nKeep; fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); + assert( pIter->term.n<=pIter->term.nSpace ); iOff += nNew; pIter->iTermLeafOffset = iOff; pIter->iTermLeafPgno = pIter->iLeafPgno; @@ -190118,10 +226565,10 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){ /* ** Initialize the iterator object pIter to iterate through the entries in -** segment pSeg. The iterator is left pointing to the first entry when +** segment pSeg. The iterator is left pointing to the first entry when ** this function returns. ** -** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If ** an error has already occurred when this function is called, it is a no-op. */ static void fts5SegIterInit( @@ -190149,8 +226596,9 @@ static void fts5SegIterInit( if( p->rc==SQLITE_OK ){ pIter->iLeafOffset = 4; + assert( pIter->pLeaf!=0 ); assert_nc( pIter->pLeaf->nn>4 ); - assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); + assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; fts5SegIterLoadTerm(p, pIter, 0); fts5SegIterLoadNPos(p, pIter); @@ -190166,8 +226614,8 @@ static void fts5SegIterInit( ** the position-list size field for the first relevant rowid on the page. ** Fts5SegIter.rowid is set, but nPos and bDel are not. ** -** This function advances the iterator so that it points to the last -** relevant rowid on the page and, if necessary, initializes the +** This function advances the iterator so that it points to the last +** relevant rowid on the page and, if necessary, initializes the ** aRowidOffset[] and iRowidOffset variables. At this point the iterator ** is in its regular state - Fts5SegIter.iLeafOffset points to the first ** byte of the position list content associated with said rowid. @@ -190185,7 +226633,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ ASSERT_SZLEAF_OK(pIter->pLeaf); while( 1 ){ - i64 iDelta = 0; + u64 iDelta = 0; if( eDetail==FTS5_DETAIL_NONE ){ /* todo */ @@ -190200,13 +226648,13 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ i += nPos; } if( i>=n ) break; - i += fts5GetVarint(&a[i], (u64*)&iDelta); + i += fts5GetVarint(&a[i], &iDelta); pIter->iRowid += iDelta; /* If necessary, grow the pIter->aRowidOffset[] array. */ if( iRowidOffset>=pIter->nRowidOffset ){ int nNew = pIter->nRowidOffset + 8; - int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int)); + int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int)); if( aNew==0 ){ p->rc = SQLITE_NOMEM; break; @@ -190251,8 +226699,12 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ int iRowidOff; iRowidOff = fts5LeafFirstRowidOff(pNew); if( iRowidOff ){ - pIter->pLeaf = pNew; - pIter->iLeafOffset = iRowidOff; + if( iRowidOff>=pNew->szLeaf ){ + p->rc = FTS5_CORRUPT; + }else{ + pIter->pLeaf = pNew; + pIter->iLeafOffset = iRowidOff; + } } } @@ -190299,7 +226751,7 @@ static void fts5SegIterNext_Reverse( if( pIter->iRowidOffset>0 ){ u8 *a = pIter->pLeaf->p; int iOff; - i64 iDelta; + u64 iDelta; pIter->iRowidOffset--; pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset]; @@ -190308,7 +226760,7 @@ static void fts5SegIterNext_Reverse( if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){ iOff += pIter->nPos; } - fts5GetVarint(&a[iOff], (u64*)&iDelta); + fts5GetVarint(&a[iOff], &iDelta); pIter->iRowid -= iDelta; }else{ fts5SegIterReverseNewPage(p, pIter); @@ -190387,10 +226839,10 @@ static void fts5SegIterNext_None( /* -** Advance iterator pIter to the next entry. +** Advance iterator pIter to the next entry. ** -** If an error occurs, Fts5Index.rc is set to an appropriate error code. It -** is not considered an error if the iterator reaches EOF. If an error has +** If an error occurs, Fts5Index.rc is set to an appropriate error code. It +** is not considered an error if the iterator reaches EOF. If an error has ** already occurred when this function is called, it is a no-op. */ static void fts5SegIterNext( @@ -190501,14 +226953,9 @@ static void fts5SegIterNext( }else{ /* The following could be done by calling fts5SegIterLoadNPos(). But ** this block is particularly performance critical, so equivalent - ** code is inlined. - ** - ** Later: Switched back to fts5SegIterLoadNPos() because it supports - ** detail=none mode. Not ideal. - */ + ** code is inlined. */ int nSz; - assert( p->rc==SQLITE_OK ); - assert( pIter->iLeafOffset<=pIter->pLeaf->nn ); + assert_nc( pIter->iLeafOffset<=pIter->pLeaf->nn ); fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz); pIter->bDel = (nSz & 0x0001); pIter->nPos = nSz>>1; @@ -190537,7 +226984,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); - pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); + pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast)); }else{ Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */ @@ -190564,7 +227011,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ ** forward to find the page containing the last rowid. */ for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){ i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno); - Fts5Data *pNew = fts5DataRead(p, iAbs); + Fts5Data *pNew = fts5LeafRead(p, iAbs); if( pNew ){ int iRowid, bTermless; iRowid = fts5LeafFirstRowidOff(pNew); @@ -190581,7 +227028,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ } /* If pLast is NULL at this point, then the last rowid for this doclist - ** lies on the page currently indicated by the iterator. In this case + ** lies on the page currently indicated by the iterator. In this case ** pIter->iLeafOffset is already set to point to the position-list size ** field associated with the first relevant rowid on the page. ** @@ -190595,6 +227042,10 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ pIter->pLeaf = pLast; pIter->iLeafPgno = pgnoLast; iOff = fts5LeafFirstRowidOff(pLast); + if( iOff>pLast->szLeaf ){ + p->rc = FTS5_CORRUPT; + return; + } iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); pIter->iLeafOffset = iOff; @@ -190603,7 +227054,6 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ }else{ pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast); } - } fts5SegIterReverseInitPage(p, pIter); @@ -190611,8 +227061,8 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){ /* ** Iterator pIter currently points to the first rowid of a doclist. -** There is a doclist-index associated with the final term on the current -** page. If the current term is the last term on the page, load the +** There is a doclist-index associated with the final term on the current +** page. If the current term is the last term on the page, load the ** doclist-index from disk and initialize an iterator at (pIter->pDlidx). */ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){ @@ -190626,8 +227076,8 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){ /* Check if the current doclist ends on this page. If it does, return ** early without loading the doclist-index (as it belongs to a different ** term. */ - if( pIter->iTermLeafPgno==pIter->iLeafPgno - && pIter->iEndofDoclistszLeaf + if( pIter->iTermLeafPgno==pIter->iLeafPgno + && pIter->iEndofDoclistszLeaf ){ return; } @@ -190655,21 +227105,20 @@ static void fts5LeafSeek( Fts5SegIter *pIter, /* Iterator to seek */ const u8 *pTerm, int nTerm /* Term to search for */ ){ - int iOff; + u32 iOff; const u8 *a = pIter->pLeaf->p; - int szLeaf = pIter->pLeaf->szLeaf; - int n = pIter->pLeaf->nn; + u32 n = (u32)pIter->pLeaf->nn; - int nMatch = 0; - int nKeep = 0; - int nNew = 0; - int iTermOff; - int iPgidx; /* Current offset in pgidx */ + u32 nMatch = 0; + u32 nKeep = 0; + u32 nNew = 0; + u32 iTermOff; + u32 iPgidx; /* Current offset in pgidx */ int bEndOfPage = 0; assert( p->rc==SQLITE_OK ); - iPgidx = szLeaf; + iPgidx = (u32)pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); iOff = iTermOff; if( iOff>n ){ @@ -190687,15 +227136,15 @@ static void fts5LeafSeek( assert( nKeep>=nMatch ); if( nKeep==nMatch ){ - int nCmp; - int i; - nCmp = MIN(nNew, nTerm-nMatch); + u32 nCmp; + u32 i; + nCmp = (u32)MIN(nNew, nTerm-nMatch); for(i=0; ipLeaf==0 ) return; a = pIter->pLeaf->p; if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ - iPgidx = pIter->pLeaf->szLeaf; + iPgidx = (u32)pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); - if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){ + if( iOff<4 || (i64)iOff>=pIter->pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; + return; }else{ nKeep = 0; iTermOff = iOff; - n = pIter->pLeaf->nn; + n = (u32)pIter->pLeaf->nn; iOff += fts5GetVarint32(&a[iOff], nNew); break; } @@ -190751,7 +227201,10 @@ static void fts5LeafSeek( } search_success: - + if( (i64)iOff+nNew>n || nNew<1 ){ + p->rc = FTS5_CORRUPT; + return; + } pIter->iLeafOffset = iOff + nNew; pIter->iTermLeafOffset = pIter->iLeafOffset; pIter->iTermLeafPgno = pIter->iLeafPgno; @@ -190788,7 +227241,7 @@ static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){ ** Initialize the object pIter to point to term pTerm/nTerm within segment ** pSeg. If there is no such term in the index, the iterator is set to EOF. ** -** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If ** an error has already occurred when this function is called, it is a no-op. */ static void fts5SegIterSeekInit( @@ -190820,6 +227273,7 @@ static void fts5SegIterSeekInit( bDlidx = (val & 0x0001); } p->rc = sqlite3_reset(pIdxSelect); + sqlite3_bind_null(pIdxSelect, 2); if( iPgpgnoFirst ){ iPg = pSeg->pgnoFirst; @@ -190858,7 +227312,7 @@ static void fts5SegIterSeekInit( ** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points ** to an entry with a term greater than or equal to (pTerm/nTerm). */ - assert( p->rc!=SQLITE_OK /* 1 */ + assert_nc( p->rc!=SQLITE_OK /* 1 */ || pIter->pLeaf==0 /* 2 */ || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */ || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */ @@ -190867,10 +227321,10 @@ static void fts5SegIterSeekInit( /* ** Initialize the object pIter to point to term pTerm/nTerm within the -** in-memory hash table. If there is no such term in the hash-table, the +** in-memory hash table. If there is no such term in the hash-table, the ** iterator is set to EOF. ** -** If an error occurs, Fts5Index.rc is set to an appropriate error code. If +** If an error occurs, Fts5Index.rc is set to an appropriate error code. If ** an error has already occurred when this function is called, it is a no-op. */ static void fts5SegIterHashInit( @@ -190879,31 +227333,40 @@ static void fts5SegIterHashInit( int flags, /* Mask of FTS5INDEX_XXX flags */ Fts5SegIter *pIter /* Object to populate */ ){ - const u8 *pList = 0; int nList = 0; const u8 *z = 0; int n = 0; + Fts5Data *pLeaf = 0; assert( p->pHash ); assert( p->rc==SQLITE_OK ); if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ + const u8 *pList = 0; + p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); n = (z ? (int)strlen((const char*)z) : 0); + if( pList ){ + pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); + if( pLeaf ){ + pLeaf->p = (u8*)pList; + } + } }else{ - pIter->flags |= FTS5_SEGITER_ONETERM; - sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList); + p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), + (const char*)pTerm, nTerm, (void**)&pLeaf, &nList + ); + if( pLeaf ){ + pLeaf->p = (u8*)&pLeaf[1]; + } z = pTerm; n = nTerm; + pIter->flags |= FTS5_SEGITER_ONETERM; } - if( pList ){ - Fts5Data *pLeaf; + if( pLeaf ){ sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z); - pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); - if( pLeaf==0 ) return; - pLeaf->p = (u8*)pList; pLeaf->nn = pLeaf->szLeaf = nList; pIter->pLeaf = pLeaf; pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); @@ -190941,7 +227404,7 @@ static void fts5SegIterClear(Fts5SegIter *pIter){ ** two iterators. */ static void fts5AssertComparisonResult( - Fts5Iter *pIter, + Fts5Iter *pIter, Fts5SegIter *p1, Fts5SegIter *p2, Fts5CResult *pRes @@ -190956,7 +227419,7 @@ static void fts5AssertComparisonResult( assert( pRes->iFirst==i1 ); }else{ int nMin = MIN(p1->term.n, p2->term.n); - int res = memcmp(p1->term.p, p2->term.p, nMin); + int res = fts5Memcmp(p1->term.p, p2->term.p, nMin); if( res==0 ) res = p1->term.n - p2->term.n; if( res==0 ){ @@ -190978,7 +227441,7 @@ static void fts5AssertComparisonResult( /* ** This function is a no-op unless SQLITE_DEBUG is defined when this module -** is compiled. In that case, this function is essentially an assert() +** is compiled. In that case, this function is essentially an assert() ** statement used to verify that the contents of the pIter->aFirst[] array ** are correct. */ @@ -190992,9 +227455,9 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){ /* Check that pIter->iSwitchRowid is set correctly. */ for(i=0; inSeg; i++){ Fts5SegIter *p1 = &pIter->aSeg[i]; - assert( p1==pFirst - || p1->pLeaf==0 - || fts5BufferCompare(&pFirst->term, &p1->term) + assert( p1==pFirst + || p1->pLeaf==0 + || fts5BufferCompare(&pFirst->term, &p1->term) || p1->iRowid==pIter->iSwitchRowid || (p1->iRowidiSwitchRowid)==pIter->bRev ); @@ -191024,7 +227487,7 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){ ** ** If the returned value is non-zero, then it is the index of an entry ** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing -** to a key that is a duplicate of another, higher priority, +** to a key that is a duplicate of another, higher priority, ** segment-iterator in the pSeg->aSeg[] array. */ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ @@ -191056,8 +227519,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ }else{ int res = fts5BufferCompare(&p1->term, &p2->term); if( res==0 ){ - assert( i2>i1 ); - assert( i2!=0 ); + assert_nc( i2>i1 ); + assert_nc( i2!=0 ); pRes->bTermEq = 1; if( p1->iRowid==p2->iRowid ){ p1->bDel = p2->bDel; @@ -191097,7 +227560,7 @@ static void fts5SegIterGotoPage( fts5SegIterNextPage(p, pIter); assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); - if( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){ int iOff; u8 *a = pIter->pLeaf->p; int n = pIter->pLeaf->szLeaf; @@ -191115,7 +227578,7 @@ static void fts5SegIterGotoPage( } /* -** Advance the iterator passed as the second argument until it is at or +** Advance the iterator passed as the second argument until it is at or ** past rowid iFrom. Regardless of the value of iFrom, the iterator is ** always advanced at least once. */ @@ -191179,7 +227642,6 @@ static void fts5MultiIterFree(Fts5Iter *pIter){ for(i=0; inSeg; i++){ fts5SegIterClear(&pIter->aSeg[i]); } - fts5StructureRelease(pIter->pStruct); fts5BufferFree(&pIter->poslist); sqlite3_free(pIter); } @@ -191212,7 +227674,7 @@ static void fts5MultiIterAdvanced( ** If non-zero is returned, the caller should call fts5MultiIterAdvanced() ** on the iterator instead. That function does the same as this one, except ** that it deals with more complicated cases as well. -*/ +*/ static int fts5MultiIterAdvanceRowid( Fts5Iter *pIter, /* Iterator to update aFirst[] array for */ int iChanged, /* Index of sub-iterator just advanced */ @@ -191263,14 +227725,14 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){ } /* -** Move the iterator to the next entry. +** Move the iterator to the next entry. ** -** If an error occurs, an error code is left in Fts5Index.rc. It is not -** considered an error if the iterator reaches EOF, or if it is already at +** If an error occurs, an error code is left in Fts5Index.rc. It is not +** considered an error if the iterator reaches EOF, or if it is already at ** EOF when this function is called. */ static void fts5MultiIterNext( - Fts5Index *p, + Fts5Index *p, Fts5Iter *pIter, int bFrom, /* True if argument iFrom is valid */ i64 iFrom /* Advance at least as far as this */ @@ -191288,7 +227750,7 @@ static void fts5MultiIterNext( pSeg->xNext(p, pSeg, &bNewTerm); } - if( pSeg->pLeaf==0 || bNewTerm + if( pSeg->pLeaf==0 || bNewTerm || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) ){ fts5MultiIterAdvanced(p, pIter, iFirst, 1); @@ -191308,27 +227770,26 @@ static void fts5MultiIterNext( } static void fts5MultiIterNext2( - Fts5Index *p, + Fts5Index *p, Fts5Iter *pIter, int *pbNewTerm /* OUT: True if *might* be new term */ ){ assert( pIter->bSkipEmpty ); if( p->rc==SQLITE_OK ){ - do { + *pbNewTerm = 0; + do{ int iFirst = pIter->aFirst[1].iFirst; Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; int bNewTerm = 0; assert( p->rc==SQLITE_OK ); pSeg->xNext(p, pSeg, &bNewTerm); - if( pSeg->pLeaf==0 || bNewTerm + if( pSeg->pLeaf==0 || bNewTerm || fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg) ){ fts5MultiIterAdvanced(p, pIter, iFirst, 1); fts5MultiIterSetEof(pIter); *pbNewTerm = 1; - }else{ - *pbNewTerm = 0; } fts5AssertMultiIterSetup(p, pIter); @@ -191348,7 +227809,7 @@ static Fts5Iter *fts5MultiIterAlloc( int nSlot; /* Power of two >= nSeg */ for(nSlot=2; nSlotaSeg[] */ sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */ @@ -191363,8 +227824,8 @@ static Fts5Iter *fts5MultiIterAlloc( } static void fts5PoslistCallback( - Fts5Index *pUnused, - void *pContext, + Fts5Index *pUnused, + void *pContext, const u8 *pChunk, int nChunk ){ UNUSED_PARAM(pUnused); @@ -191401,8 +227862,8 @@ static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){ } static void fts5PoslistOffsetsCallback( - Fts5Index *pUnused, - void *pContext, + Fts5Index *pUnused, + void *pContext, const u8 *pChunk, int nChunk ){ PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext; @@ -191425,7 +227886,7 @@ static void fts5PoslistOffsetsCallback( static void fts5PoslistFilterCallback( Fts5Index *pUnused, - void *pContext, + void *pContext, const u8 *pChunk, int nChunk ){ PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext; @@ -191488,7 +227949,7 @@ static void fts5ChunkIterate( int pgno = pSeg->iLeafPgno; int pgnoSave = 0; - /* This function does notmwork with detail=none databases. */ + /* This function does not work with detail=none databases. */ assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE ); if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){ @@ -191501,6 +227962,9 @@ static void fts5ChunkIterate( fts5DataRelease(pData); if( nRem<=0 ){ break; + }else if( pSeg->pSeg==0 ){ + p->rc = FTS5_CORRUPT; + return; }else{ pgno++; pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno)); @@ -191528,7 +227992,12 @@ static void fts5SegiterPoslist( Fts5Colset *pColset, Fts5Buffer *pBuf ){ - if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){ + assert( pBuf!=0 ); + assert( pSeg!=0 ); + if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){ + assert( pBuf->p!=0 ); + assert( pBuf->nSpace >= pBuf->n+pSeg->nPos+FTS5_DATA_ZERO_PADDING ); + memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING); if( pColset==0 ){ fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback); }else{ @@ -191551,66 +228020,72 @@ static void fts5SegiterPoslist( } /* -** IN/OUT parameter (*pa) points to a position list n bytes in size. If -** the position list contains entries for column iCol, then (*pa) is set -** to point to the sub-position-list for that column and the number of -** bytes in it returned. Or, if the argument position list does not -** contain any entries for column iCol, return 0. +** Parameter pPos points to a buffer containing a position list, size nPos. +** This function filters it according to pColset (which must be non-NULL) +** and sets pIter->base.pData/nData to point to the new position list. +** If memory is required for the new position list, use buffer pIter->poslist. +** Or, if the new position list is a contiguous subset of the input, set +** pIter->base.pData/nData to point directly to it. +** +** This function is a no-op if *pRc is other than SQLITE_OK when it is +** called. If an OOM error is encountered, *pRc is set to SQLITE_NOMEM +** before returning. */ -static int fts5IndexExtractCol( - const u8 **pa, /* IN/OUT: Pointer to poslist */ - int n, /* IN: Size of poslist in bytes */ - int iCol /* Column to extract from poslist */ +static void fts5IndexExtractColset( + int *pRc, + Fts5Colset *pColset, /* Colset to filter on */ + const u8 *pPos, int nPos, /* Position list */ + Fts5Iter *pIter ){ - int iCurrent = 0; /* Anything before the first 0x01 is col 0 */ - const u8 *p = *pa; - const u8 *pEnd = &p[n]; /* One byte past end of position list */ + if( *pRc==SQLITE_OK ){ + const u8 *p = pPos; + const u8 *aCopy = p; + const u8 *pEnd = &p[nPos]; /* One byte past end of position list */ + int i = 0; + int iCurrent = 0; - while( iCol>iCurrent ){ - /* Advance pointer p until it points to pEnd or an 0x01 byte that is - ** not part of a varint. Note that it is not possible for a negative - ** or extremely large varint to occur within an uncorrupted position - ** list. So the last byte of each varint may be assumed to have a clear - ** 0x80 bit. */ - while( *p!=0x01 ){ - while( *p++ & 0x80 ); - if( p>=pEnd ) return 0; - } - *pa = p++; - iCurrent = *p++; - if( iCurrent & 0x80 ){ - p--; - p += fts5GetVarint32(p, iCurrent); + if( pColset->nCol>1 && sqlite3Fts5BufferSize(pRc, &pIter->poslist, nPos) ){ + return; } - } - if( iCol!=iCurrent ) return 0; - /* Advance pointer p until it points to pEnd or an 0x01 byte that is - ** not part of a varint */ - while( paiCol[i]nCol ){ + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + return; + } + } -static int fts5IndexExtractColset ( - Fts5Colset *pColset, /* Colset to filter on */ - const u8 *pPos, int nPos, /* Position list */ - Fts5Buffer *pBuf /* Output buffer */ -){ - int rc = SQLITE_OK; - int i; + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint */ + while( pnCol; i++){ - const u8 *pSub = pPos; - int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]); - if( nSub ){ - fts5BufferAppendBlob(&rc, pBuf, nSub, pSub); + if( pColset->aiCol[i]==iCurrent ){ + if( pColset->nCol==1 ){ + pIter->base.pData = aCopy; + pIter->base.nData = p-aCopy; + return; + } + fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy); + } + if( p>=pEnd ){ + pIter->base.pData = pIter->poslist.p; + pIter->base.nData = pIter->poslist.n; + return; + } + aCopy = p++; + iCurrent = *p++; + if( iCurrent & 0x80 ){ + p--; + p += fts5GetVarint32(p, iCurrent); + } } } - return rc; + } /* @@ -191634,7 +228109,7 @@ static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){ assert( pIter->pColset==0 ); if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ - /* All data is stored on the current page. Populate the output + /* All data is stored on the current page. Populate the output ** variables to point into the body of the page object. */ pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset]; }else{ @@ -191670,13 +228145,13 @@ static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){ } /* -** xSetOutputs callback used when: +** xSetOutputs callback used when: ** ** * detail=col, ** * there is a column filter, and -** * the table contains 100 or fewer columns. +** * the table contains 100 or fewer columns. ** -** The last point is to ensure all column numbers are stored as +** The last point is to ensure all column numbers are stored as ** single-byte varints. */ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){ @@ -191688,7 +228163,7 @@ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){ fts5IterSetOutputs_Col(pIter, pSeg); }else{ u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset]; - u8 *pEnd = (u8*)&a[pSeg->nPos]; + u8 *pEnd = (u8*)&a[pSeg->nPos]; int iPrev = 0; int *aiCol = pIter->pColset->aiCol; int *aiColEnd = &aiCol[pIter->pColset->nCol]; @@ -191727,18 +228202,12 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){ assert( pColset ); if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){ - /* All data is stored on the current page. Populate the output + /* All data is stored on the current page. Populate the output ** variables to point into the body of the page object. */ const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset]; - if( pColset->nCol==1 ){ - pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]); - pIter->base.pData = a; - }else{ - fts5BufferZero(&pIter->poslist); - fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist); - pIter->base.pData = pIter->poslist.p; - pIter->base.nData = pIter->poslist.n; - } + int *pRc = &pIter->pIndex->rc; + fts5BufferZero(&pIter->poslist); + fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, pIter); }else{ /* The data is distributed over two or more pages. Copy it into the ** Fts5Iter.poslist buffer and then set the output pointer to point @@ -191751,6 +228220,7 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){ } static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){ + assert( pIter!=0 || (*pRc)!=SQLITE_OK ); if( *pRc==SQLITE_OK ){ Fts5Config *pConfig = pIter->pIndex->pConfig; if( pConfig->eDetail==FTS5_DETAIL_NONE ){ @@ -191790,7 +228260,7 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){ ** is zero or greater, data from the first nSegment segments on level iLevel ** is merged. ** -** The iterator initially points to the first term/rowid entry in the +** The iterator initially points to the first term/rowid entry in the ** iterated data. */ static void fts5MultiIterNew( @@ -191822,12 +228292,13 @@ static void fts5MultiIterNew( } } *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); - if( pNew==0 ) return; + if( pNew==0 ){ + assert( p->rc!=SQLITE_OK ); + goto fts5MultiIterNew_post_check; + } pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY)); - pNew->pStruct = pStruct; pNew->pColset = pColset; - fts5StructureRef(pStruct); if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){ fts5IterSetOutputCb(&p->rc, pNew); } @@ -191861,8 +228332,8 @@ static void fts5MultiIterNew( assert( iIter==nSeg ); } - /* If the above was successful, each component iterators now points - ** to the first entry in its segment. In this case initialize the + /* If the above was successful, each component iterators now points + ** to the first entry in its segment. In this case initialize the ** aFirst[] array. Or, if an error has occurred, free the iterator ** object and set the output variable to NULL. */ if( p->rc==SQLITE_OK ){ @@ -191888,6 +228359,10 @@ static void fts5MultiIterNew( fts5MultiIterFree(pNew); *ppOut = 0; } + +fts5MultiIterNew_post_check: + assert( (*ppOut)!=0 || p->rc!=SQLITE_OK ); + return; } /* @@ -191931,12 +228406,13 @@ static void fts5MultiIterNew2( } /* -** Return true if the iterator is at EOF or if an error has occurred. +** Return true if the iterator is at EOF or if an error has occurred. ** False otherwise. */ static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ - assert( p->rc - || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof + assert( pIter!=0 || p->rc!=SQLITE_OK ); + assert( p->rc!=SQLITE_OK + || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof ); return (p->rc || pIter->base.bEof); } @@ -191955,8 +228431,8 @@ static i64 fts5MultiIterRowid(Fts5Iter *pIter){ ** Move the iterator to the next entry at or following iMatch. */ static void fts5MultiIterNextFrom( - Fts5Index *p, - Fts5Iter *pIter, + Fts5Index *p, + Fts5Iter *pIter, i64 iMatch ){ while( 1 ){ @@ -191970,7 +228446,7 @@ static void fts5MultiIterNextFrom( } /* -** Return a pointer to a buffer containing the term associated with the +** Return a pointer to a buffer containing the term associated with the ** entry that the iterator currently points to. */ static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){ @@ -191981,11 +228457,11 @@ static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){ /* ** Allocate a new segment-id for the structure pStruct. The new segment -** id must be between 1 and 65335 inclusive, and must not be used by +** id must be between 1 and 65335 inclusive, and must not be used by ** any currently existing segment. If a free segment id cannot be found, ** SQLITE_FULL is returned. ** -** If an error has already occurred, this function is a no-op. 0 is +** If an error has already occurred, this function is a no-op. 0 is ** returned in this case. */ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ @@ -192005,24 +228481,24 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ for(iLvl=0; iLvlnLevel; iLvl++){ for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid; - if( iId<=FTS5_MAX_SEGMENT ){ - aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32); + if( iId<=FTS5_MAX_SEGMENT && iId>0 ){ + aUsed[(iId-1) / 32] |= (u32)1 << ((iId-1) % 32); } } } for(i=0; aUsed[i]==0xFFFFFFFF; i++); mask = aUsed[i]; - for(iSegid=0; mask & (1 << iSegid); iSegid++); + for(iSegid=0; mask & ((u32)1 << iSegid); iSegid++); iSegid += 1 + i*32; #ifdef SQLITE_DEBUG for(iLvl=0; iLvlnLevel; iLvl++){ for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ - assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ); + assert_nc( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ); } } - assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT ); + assert_nc( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT ); { sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p); @@ -192030,8 +228506,9 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){ u8 aBlob[2] = {0xff, 0xff}; sqlite3_bind_int(pIdxSelect, 1, iSegid); sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC); - assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); + assert_nc( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); p->rc = sqlite3_reset(pIdxSelect); + sqlite3_bind_null(pIdxSelect, 2); } } #endif @@ -192053,10 +228530,10 @@ static void fts5IndexDiscardData(Fts5Index *p){ } /* -** Return the size of the prefix, in bytes, that buffer +** Return the size of the prefix, in bytes, that buffer ** (pNew/) shares with buffer (pOld/nOld). ** -** Buffer (pNew/) is guaranteed to be greater +** Buffer (pNew/) is guaranteed to be greater ** than buffer (pOld/nOld). */ static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){ @@ -192068,7 +228545,7 @@ static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){ } static void fts5WriteDlidxClear( - Fts5Index *p, + Fts5Index *p, Fts5SegWriter *pWriter, int bFlush /* If true, write dlidx to disk */ ){ @@ -192079,7 +228556,7 @@ static void fts5WriteDlidxClear( if( pDlidx->buf.n==0 ) break; if( bFlush ){ assert( pDlidx->pgno!=0 ); - fts5DataWrite(p, + fts5DataWrite(p, FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno), pDlidx->buf.p, pDlidx->buf.n ); @@ -192099,13 +228576,13 @@ static int fts5WriteDlidxGrow( int nLvl ){ if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){ - Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc( + Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc64( pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl ); if( aDlidx==0 ){ p->rc = SQLITE_NOMEM; }else{ - int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); + size_t nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); memset(&aDlidx[pWriter->nDlidx], 0, nByte); pWriter->aDlidx = aDlidx; pWriter->nDlidx = nLvl; @@ -192133,8 +228610,8 @@ static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){ } /* -** This function is called whenever processing of the doclist for the -** last term on leaf page (pWriter->iBtPage) is completed. +** This function is called whenever processing of the doclist for the +** last term on leaf page (pWriter->iBtPage) is completed. ** ** The doclist-index for that term is currently stored in-memory within the ** Fts5SegWriter.aDlidx[] array. If it is large enough, this function @@ -192158,6 +228635,7 @@ static void fts5WriteFlushBtree(Fts5Index *p, Fts5SegWriter *pWriter){ sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1)); sqlite3_step(p->pIdxWriter); p->rc = sqlite3_reset(p->pIdxWriter); + sqlite3_bind_null(p->pIdxWriter, 2); } pWriter->iBtPage = 0; } @@ -192177,8 +228655,10 @@ static void fts5WriteBtreeTerm( int nTerm, const u8 *pTerm /* First term on new page */ ){ fts5WriteFlushBtree(p, pWriter); - fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm); - pWriter->iBtPage = pWriter->writer.pgno; + if( p->rc==SQLITE_OK ){ + fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm); + pWriter->iBtPage = pWriter->writer.pgno; + } } /* @@ -192216,8 +228696,8 @@ static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){ ** doclist-index. */ static void fts5WriteDlidxAppend( - Fts5Index *p, - Fts5SegWriter *pWriter, + Fts5Index *p, + Fts5SegWriter *pWriter, i64 iRowid ){ int i; @@ -192230,11 +228710,11 @@ static void fts5WriteDlidxAppend( if( pDlidx->buf.n>=p->pConfig->pgsz ){ /* The current doclist-index page is full. Write it to disk and push ** a copy of iRowid (which will become the first rowid on the next - ** doclist-index leaf page) up into the next level of the b-tree + ** doclist-index leaf page) up into the next level of the b-tree ** hierarchy. If the node being flushed is currently the root node, ** also push its first rowid upwards. */ pDlidx->buf.p[0] = 0x01; /* Not the root node */ - fts5DataWrite(p, + fts5DataWrite(p, FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno), pDlidx->buf.p, pDlidx->buf.n ); @@ -192280,9 +228760,6 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){ Fts5PageWriter *pPage = &pWriter->writer; i64 iRowid; -static int nCall = 0; -nCall++; - assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) ); /* Set the szLeaf header field. */ @@ -192321,17 +228798,18 @@ nCall++; ** Append term pTerm/nTerm to the segment being written by the writer passed ** as the second argument. ** -** If an error occurs, set the Fts5Index.rc error code. If an error has +** If an error occurs, set the Fts5Index.rc error code. If an error has ** already occurred, this function is a no-op. */ static void fts5WriteAppendTerm( - Fts5Index *p, + Fts5Index *p, Fts5SegWriter *pWriter, - int nTerm, const u8 *pTerm + int nTerm, const u8 *pTerm ){ int nPrefix; /* Bytes of prefix compression for term */ Fts5PageWriter *pPage = &pWriter->writer; Fts5Buffer *pPgidx = &pWriter->writer.pgidx; + int nMin = MIN(pPage->term.n, nTerm); assert( p->rc==SQLITE_OK ); assert( pPage->buf.n>=4 ); @@ -192341,10 +228819,11 @@ static void fts5WriteAppendTerm( if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){ if( pPage->buf.n>4 ){ fts5WriteFlushLeaf(p, pWriter); + if( p->rc!=SQLITE_OK ) return; } fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING); } - + /* TODO1: Updating pgidx here. */ pPgidx->n += sqlite3Fts5PutVarint( &pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx @@ -192360,11 +228839,11 @@ static void fts5WriteAppendTerm( if( pPage->pgno!=1 ){ /* This is the first term on a leaf that is not the leftmost leaf in ** the segment b-tree. In this case it is necessary to add a term to - ** the b-tree hierarchy that is (a) larger than the largest term + ** the b-tree hierarchy that is (a) larger than the largest term ** already written to the segment and (b) smaller than or equal to ** this term. In other words, a prefix of (pTerm/nTerm) that is one ** byte longer than the longest prefix (pTerm/nTerm) shares with the - ** previous term. + ** previous term. ** ** Usually, the previous term is available in pPage->term. The exception ** is if this is the first term written in an incremental-merge step. @@ -192373,13 +228852,14 @@ static void fts5WriteAppendTerm( ** inefficient, but still correct. */ int n = nTerm; if( pPage->term.n ){ - n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + n = 1 + fts5PrefixCompress(nMin, pPage->term.p, pTerm); } fts5WriteBtreeTerm(p, pWriter, n, pTerm); + if( p->rc!=SQLITE_OK ) return; pPage = &pWriter->writer; } }else{ - nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm); + nPrefix = fts5PrefixCompress(nMin, pPage->term.p, pTerm); fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix); } @@ -192400,10 +228880,10 @@ static void fts5WriteAppendTerm( } /* -** Append a rowid and position-list size field to the writers output. +** Append a rowid and position-list size field to the writers output. */ static void fts5WriteAppendRowid( - Fts5Index *p, + Fts5Index *p, Fts5SegWriter *pWriter, i64 iRowid ){ @@ -192414,7 +228894,7 @@ static void fts5WriteAppendRowid( fts5WriteFlushLeaf(p, pWriter); } - /* If this is to be the first rowid written to the page, set the + /* If this is to be the first rowid written to the page, set the ** rowid-pointer in the page-header. Also append a value to the dlidx ** buffer, in case a doclist-index is required. */ if( pWriter->bFirstRowidInPage ){ @@ -192426,7 +228906,7 @@ static void fts5WriteAppendRowid( if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); }else{ - assert( p->rc || iRowid>pWriter->iPrevRowid ); + assert_nc( p->rc || iRowid>pWriter->iPrevRowid ); fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid); } pWriter->iPrevRowid = iRowid; @@ -192436,18 +228916,18 @@ static void fts5WriteAppendRowid( } static void fts5WriteAppendPoslistData( - Fts5Index *p, - Fts5SegWriter *pWriter, - const u8 *aData, + Fts5Index *p, + Fts5SegWriter *pWriter, + const u8 *aData, int nData ){ Fts5PageWriter *pPage = &pWriter->writer; const u8 *a = aData; int n = nData; - + assert( p->pConfig->pgsz>0 ); - while( p->rc==SQLITE_OK - && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz + while( p->rc==SQLITE_OK + && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz ){ int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n; int nCopy = 0; @@ -192470,7 +228950,7 @@ static void fts5WriteAppendPoslistData( ** allocations associated with the writer. */ static void fts5WriteFinish( - Fts5Index *p, + Fts5Index *p, Fts5SegWriter *pWriter, /* Writer object */ int *pnLeaf /* OUT: Number of leaf pages in b-tree */ ){ @@ -192498,8 +228978,8 @@ static void fts5WriteFinish( } static void fts5WriteInit( - Fts5Index *p, - Fts5SegWriter *pWriter, + Fts5Index *p, + Fts5SegWriter *pWriter, int iSegid ){ const int nBuffer = p->pConfig->pgsz + FTS5_DATA_PADDING; @@ -192522,7 +229002,7 @@ static void fts5WriteInit( if( p->pIdxWriter==0 ){ Fts5Config *pConfig = p->pConfig; fts5IndexPrepareStmt(p, &p->pIdxWriter, sqlite3_mprintf( - "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)", + "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)", pConfig->zDb, pConfig->zName )); } @@ -192548,7 +229028,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ int i; Fts5Buffer buf; memset(&buf, 0, sizeof(Fts5Buffer)); - for(i=0; inSeg; i++){ + for(i=0; inSeg && p->rc==SQLITE_OK; i++){ Fts5SegIter *pSeg = &pIter->aSeg[i]; if( pSeg->pSeg==0 ){ /* no-op */ @@ -192566,35 +229046,44 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00}; iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno); - pData = fts5DataRead(p, iLeafRowid); + pData = fts5LeafRead(p, iLeafRowid); if( pData ){ - fts5BufferZero(&buf); - fts5BufferGrow(&p->rc, &buf, pData->nn); - fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); - fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); - fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); - fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]); - if( p->rc==SQLITE_OK ){ - /* Set the szLeaf field */ - fts5PutU16(&buf.p[2], (u16)buf.n); - } + if( iOff>pData->szLeaf ){ + /* This can occur if the pages that the segments occupy overlap - if + ** a single page has been assigned to more than one segment. In + ** this case a prior iteration of this loop may have corrupted the + ** segment currently being trimmed. */ + p->rc = FTS5_CORRUPT; + }else{ + fts5BufferZero(&buf); + fts5BufferGrow(&p->rc, &buf, pData->nn); + fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); + fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); + fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p); + fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]); + if( p->rc==SQLITE_OK ){ + /* Set the szLeaf field */ + fts5PutU16(&buf.p[2], (u16)buf.n); + } - /* Set up the new page-index array */ - fts5BufferAppendVarint(&p->rc, &buf, 4); - if( pSeg->iLeafPgno==pSeg->iTermLeafPgno - && pSeg->iEndofDoclistszLeaf - ){ - int nDiff = pData->szLeaf - pSeg->iEndofDoclist; - fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); - fts5BufferAppendBlob(&p->rc, &buf, - pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] - ); - } + /* Set up the new page-index array */ + fts5BufferAppendVarint(&p->rc, &buf, 4); + if( pSeg->iLeafPgno==pSeg->iTermLeafPgno + && pSeg->iEndofDoclistszLeaf + && pSeg->iPgidxOff<=pData->nn + ){ + int nDiff = pData->szLeaf - pSeg->iEndofDoclist; + fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); + fts5BufferAppendBlob(&p->rc, &buf, + pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] + ); + } + pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; + fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid); + fts5DataWrite(p, iLeafRowid, buf.p, buf.n); + } fts5DataRelease(pData); - pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; - fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid); - fts5DataWrite(p, iLeafRowid, buf.p, buf.n); } } } @@ -192602,8 +229091,8 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ } static void fts5MergeChunkCallback( - Fts5Index *p, - void *pCtx, + Fts5Index *p, + void *pCtx, const u8 *pChunk, int nChunk ){ Fts5SegWriter *pWriter = (Fts5SegWriter*)pCtx; @@ -192631,6 +229120,7 @@ static void fts5IndexMergeLevel( int bOldest; /* True if the output segment is the oldest */ int eDetail = p->pConfig->eDetail; const int flags = FTS5INDEX_QUERY_NOOUTPUT; + int bTermWritten = 0; /* True if current term already output */ assert( iLvlnLevel ); assert( pLvl->nMerge<=pLvl->nSeg ); @@ -192684,18 +229174,22 @@ static void fts5IndexMergeLevel( int nTerm; const u8 *pTerm; - /* Check for key annihilation. */ - if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; - pTerm = fts5MultiIterTerm(pIter, &nTerm); - if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){ + if( nTerm!=term.n || fts5Memcmp(pTerm, term.p, nTerm) ){ if( pnRem && writer.nLeafWritten>nRem ){ break; } + fts5BufferSet(&p->rc, &term, nTerm, pTerm); + bTermWritten =0; + } + + /* Check for key annihilation. */ + if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue; + if( p->rc==SQLITE_OK && bTermWritten==0 ){ /* This is a new term. Append a term to the output segment. */ fts5WriteAppendTerm(p, &writer, nTerm, pTerm); - fts5BufferSet(&p->rc, &term, nTerm, pTerm); + bTermWritten = 1; } /* Append the rowid to the output */ @@ -192721,6 +229215,7 @@ static void fts5IndexMergeLevel( ** and last leaf page number at the same time. */ fts5WriteFinish(p, &writer, &pSeg->pgnoLast); + assert( pIter!=0 || p->rc!=SQLITE_OK ); if( fts5MultiIterEof(p, pIter) ){ int i; @@ -192813,7 +229308,7 @@ static int fts5IndexMerge( ** segment. This function updates the write-counter accordingly and, if ** necessary, performs incremental merge work. ** -** If an error occurs, set the Fts5Index.rc error code. If an error has +** If an error occurs, set the Fts5Index.rc error code. If an error has ** already occurred, this function is a no-op. */ static void fts5IndexAutomerge( @@ -192821,7 +229316,7 @@ static void fts5IndexAutomerge( Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */ int nLeaf /* Number of output leaves just written */ ){ - if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){ + if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 && ALWAYS((*ppStruct)!=0) ){ Fts5Structure *pStruct = *ppStruct; u64 nWrite; /* Initial value of write-counter */ int nWork; /* Number of work-quanta to perform */ @@ -192864,12 +229359,12 @@ static int fts5IndexReturn(Fts5Index *p){ typedef struct Fts5FlushCtx Fts5FlushCtx; struct Fts5FlushCtx { Fts5Index *pIdx; - Fts5SegWriter writer; + Fts5SegWriter writer; }; /* ** Buffer aBuf[] contains a list of varints, all small enough to fit -** in a 32-bit integer. Return the size of the largest prefix of this +** in a 32-bit integer. Return the size of the largest prefix of this ** list nMax bytes or less in size. */ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){ @@ -192887,10 +229382,10 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){ } /* -** Flush the contents of in-memory hash table iHash to a new level-0 +** Flush the contents of in-memory hash table iHash to a new level-0 ** segment on disk. Also update the corresponding structure record. ** -** If an error occurs, set the Fts5Index.rc error code. If an error has +** If an error occurs, set the Fts5Index.rc error code. If an error has ** already occurred, this function is a no-op. */ static void fts5FlushOneHash(Fts5Index *p){ @@ -192936,6 +229431,7 @@ static void fts5FlushOneHash(Fts5Index *p){ /* Write the term for this entry to disk. */ sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm); + if( p->rc!=SQLITE_OK ) break; assert( writer.bFirstRowidInPage==0 ); if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){ @@ -192943,21 +229439,22 @@ static void fts5FlushOneHash(Fts5Index *p){ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist); }else{ i64 iRowid = 0; - i64 iDelta = 0; + u64 iDelta = 0; int iOff = 0; - /* The entire doclist will not fit on this leaf. The following - ** loop iterates through the poslists that make up the current + /* The entire doclist will not fit on this leaf. The following + ** loop iterates through the poslists that make up the current ** doclist. */ while( p->rc==SQLITE_OK && iOffp[0], (u16)pBuf->n); /* first rowid on page */ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid); writer.bFirstRowidInPage = 0; fts5WriteDlidxAppend(p, &writer, iRowid); + if( p->rc!=SQLITE_OK ) break; }else{ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta); } @@ -193015,7 +229512,7 @@ static void fts5FlushOneHash(Fts5Index *p){ /* TODO2: Doclist terminator written here. */ /* pBuf->p[pBuf->n++] = '\0'; */ assert( pBuf->n<=pBuf->nSpace ); - sqlite3Fts5HashScanNext(pHash); + if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash); } sqlite3Fts5HashClear(pHash); fts5WriteFinish(p, &writer, &pgnoLast); @@ -193055,18 +229552,18 @@ static void fts5IndexFlush(Fts5Index *p){ } static Fts5Structure *fts5IndexOptimizeStruct( - Fts5Index *p, + Fts5Index *p, Fts5Structure *pStruct ){ Fts5Structure *pNew = 0; - int nByte = sizeof(Fts5Structure); + sqlite3_int64 nByte = sizeof(Fts5Structure); int nSeg = pStruct->nSegment; int i; /* Figure out if this structure requires optimization. A structure does ** not require optimization if either: ** - ** + it consists of fewer than two segments, or + ** + it consists of fewer than two segments, or ** + all segments are on the same level, or ** + all segments except one are currently inputs to a merge operation. ** @@ -193143,7 +229640,7 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){ fts5StructureRelease(pNew); } - return fts5IndexReturn(p); + return fts5IndexReturn(p); } /* @@ -193189,11 +229686,13 @@ static void fts5AppendPoslist( Fts5Buffer *pBuf ){ int nData = pMulti->base.nData; + int nByte = nData + 9 + 9 + FTS5_DATA_ZERO_PADDING; assert( nData>0 ); - if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){ + if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nByte) ){ fts5BufferSafeAppendVarint(pBuf, iDelta); fts5BufferSafeAppendVarint(pBuf, nData*2); fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData); + memset(&pBuf->p[pBuf->n], 0, FTS5_DATA_ZERO_PADDING); } } @@ -193201,7 +229700,7 @@ static void fts5AppendPoslist( static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist; - assert( pIter->aPoslist ); + assert( pIter->aPoslist || (p==0 && pIter->aPoslist==0) ); if( p>=pIter->aEof ){ pIter->aPoslist = 0; }else{ @@ -193221,17 +229720,22 @@ static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ } pIter->aPoslist = p; + if( &pIter->aPoslist[pIter->nPoslist]>pIter->aEof ){ + pIter->aPoslist = 0; + } } } static void fts5DoclistIterInit( - Fts5Buffer *pBuf, + Fts5Buffer *pBuf, Fts5DoclistIter *pIter ){ memset(pIter, 0, sizeof(*pIter)); - pIter->aPoslist = pBuf->p; - pIter->aEof = &pBuf->p[pBuf->n]; - fts5DoclistIterNext(pIter); + if( pBuf->n>0 ){ + pIter->aPoslist = pBuf->p; + pIter->aEof = &pBuf->p[pBuf->n]; + fts5DoclistIterNext(pIter); + } } #if 0 @@ -193285,16 +229789,20 @@ static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){ static void fts5MergeRowidLists( Fts5Index *p, /* FTS5 backend object */ Fts5Buffer *p1, /* First list to merge */ - Fts5Buffer *p2 /* Second list to merge */ + int nBuf, /* Number of entries in apBuf[] */ + Fts5Buffer *aBuf /* Array of other lists to merge into p1 */ ){ int i1 = 0; int i2 = 0; i64 iRowid1 = 0; i64 iRowid2 = 0; i64 iOut = 0; - + Fts5Buffer *p2 = &aBuf[0]; Fts5Buffer out; + + (void)nBuf; memset(&out, 0, sizeof(out)); + assert( nBuf==1 ); sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n); if( p->rc ) return; @@ -193321,145 +229829,214 @@ static void fts5MergeRowidLists( fts5BufferFree(&out); } +typedef struct PrefixMerger PrefixMerger; +struct PrefixMerger { + Fts5DoclistIter iter; /* Doclist iterator */ + i64 iPos; /* For iterating through a position list */ + int iOff; + u8 *aPos; + PrefixMerger *pNext; /* Next in docid/poslist order */ +}; + +static void fts5PrefixMergerInsertByRowid( + PrefixMerger **ppHead, + PrefixMerger *p +){ + if( p->iter.aPoslist ){ + PrefixMerger **pp = ppHead; + while( *pp && p->iter.iRowid>(*pp)->iter.iRowid ){ + pp = &(*pp)->pNext; + } + p->pNext = *pp; + *pp = p; + } +} + +static void fts5PrefixMergerInsertByPosition( + PrefixMerger **ppHead, + PrefixMerger *p +){ + if( p->iPos>=0 ){ + PrefixMerger **pp = ppHead; + while( *pp && p->iPos>(*pp)->iPos ){ + pp = &(*pp)->pNext; + } + p->pNext = *pp; + *pp = p; + } +} + + /* -** Buffers p1 and p2 contain doclists. This function merges the content -** of the two doclists together and sets buffer p1 to the result before -** returning. -** -** If an error occurs, an error code is left in p->rc. If an error has -** already occurred, this function is a no-op. +** Array aBuf[] contains nBuf doclists. These are all merged in with the +** doclist in buffer p1. */ static void fts5MergePrefixLists( Fts5Index *p, /* FTS5 backend object */ Fts5Buffer *p1, /* First list to merge */ - Fts5Buffer *p2 /* Second list to merge */ -){ - if( p2->n ){ - i64 iLastRowid = 0; - Fts5DoclistIter i1; - Fts5DoclistIter i2; - Fts5Buffer out = {0, 0, 0}; - Fts5Buffer tmp = {0, 0, 0}; - - if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return; - fts5DoclistIterInit(p1, &i1); - fts5DoclistIterInit(p2, &i2); + int nBuf, /* Number of buffers in array aBuf[] */ + Fts5Buffer *aBuf /* Other lists to merge in */ +){ +#define fts5PrefixMergerNextPosition(p) \ + sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos) +#define FTS5_MERGE_NLIST 16 + PrefixMerger aMerger[FTS5_MERGE_NLIST]; + PrefixMerger *pHead = 0; + int i; + int nOut = 0; + Fts5Buffer out = {0, 0, 0}; + Fts5Buffer tmp = {0, 0, 0}; + i64 iLastRowid = 0; + + /* Initialize a doclist-iterator for each input buffer. Arrange them in + ** a linked-list starting at pHead in ascending order of rowid. Avoid + ** linking any iterators already at EOF into the linked list at all. */ + assert( nBuf+1<=sizeof(aMerger)/sizeof(aMerger[0]) ); + memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1)); + pHead = &aMerger[nBuf]; + fts5DoclistIterInit(p1, &pHead->iter); + for(i=0; in + 9 + 10*nBuf; + + /* The maximum size of the output is equal to the sum of the + ** input sizes + 1 varint (9 bytes). The extra varint is because if the + ** first rowid in one input is a large negative number, and the first in + ** the other a non-negative number, the delta for the non-negative + ** number will be larger on disk than the literal integer value + ** was. + ** + ** Or, if the input position-lists are corrupt, then the output might + ** include up to (nBuf+1) extra 10-byte positions created by interpreting -1 + ** (the value PoslistNext64() uses for EOF) as a position and appending + ** it to the output. This can happen at most once for each input + ** position-list, hence (nBuf+1) 10 byte paddings. */ + if( sqlite3Fts5BufferSize(&p->rc, &out, nOut) ) return; + + while( pHead ){ + fts5MergeAppendDocid(&out, iLastRowid, pHead->iter.iRowid); + + if( pHead->pNext && iLastRowid==pHead->pNext->iter.iRowid ){ + /* Merge data from two or more poslists */ + i64 iPrev = 0; + int nTmp = FTS5_DATA_ZERO_PADDING; + int nMerge = 0; + PrefixMerger *pSave = pHead; + PrefixMerger *pThis = 0; + int nTail = 0; + + pHead = 0; + while( pSave && pSave->iter.iRowid==iLastRowid ){ + PrefixMerger *pNext = pSave->pNext; + pSave->iOff = 0; + pSave->iPos = 0; + pSave->aPos = &pSave->iter.aPoslist[pSave->iter.nSize]; + fts5PrefixMergerNextPosition(pSave); + nTmp += pSave->iter.nPoslist + 10; + nMerge++; + fts5PrefixMergerInsertByPosition(&pHead, pSave); + pSave = pNext; + } + + if( pHead==0 || pHead->pNext==0 ){ + p->rc = FTS5_CORRUPT; + break; + } - while( 1 ){ - if( i1.iRowidrc, &tmp, nTmp+nMerge*10) ){ + break; } - else{ - /* Merge the two position lists. */ - i64 iPos1 = 0; - i64 iPos2 = 0; - int iOff1 = 0; - int iOff2 = 0; - u8 *a1 = &i1.aPoslist[i1.nSize]; - u8 *a2 = &i2.aPoslist[i2.nSize]; - - i64 iPrev = 0; - Fts5PoslistWriter writer; - memset(&writer, 0, sizeof(writer)); - - fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); - fts5BufferZero(&tmp); - sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist); - if( p->rc ) break; - - sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); - sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); - assert( iPos1>=0 && iPos2>=0 ); - - if( iPos1=0 && iPos2>=0 ){ - while( 1 ){ - if( iPos1pNext; + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos); + fts5PrefixMergerNextPosition(pThis); + fts5PrefixMergerInsertByPosition(&pHead, pThis); - if( iPos1>=0 ){ - if( iPos1!=iPrev ){ - sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); - } - fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1); - }else{ - assert( iPos2>=0 && iPos2!=iPrev ); - sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); - fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2); + while( pHead->pNext ){ + pThis = pHead; + if( pThis->iPos!=iPrev ){ + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos); } + fts5PrefixMergerNextPosition(pThis); + pHead = pThis->pNext; + fts5PrefixMergerInsertByPosition(&pHead, pThis); + } - /* WRITEPOSLISTSIZE */ - fts5BufferSafeAppendVarint(&out, tmp.n * 2); - fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); - fts5DoclistIterNext(&i1); - fts5DoclistIterNext(&i2); - if( i1.aPoslist==0 || i2.aPoslist==0 ) break; + if( pHead->iPos!=iPrev ){ + sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pHead->iPos); } - } + nTail = pHead->iter.nPoslist - pHead->iOff; - if( i1.aPoslist ){ - fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid); - fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist); - } - else if( i2.aPoslist ){ - fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); - fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist); - } + /* WRITEPOSLISTSIZE */ + assert_nc( tmp.n+nTail<=nTmp ); + assert( tmp.n+nTail<=nTmp+nMerge*10 ); + if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){ + if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; + break; + } + fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2); + fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); + if( nTail>0 ){ + fts5BufferSafeAppendBlob(&out, &pHead->aPos[pHead->iOff], nTail); + } + + pHead = pSave; + for(i=0; iiter.aPoslist && pX->iter.iRowid==iLastRowid ){ + fts5DoclistIterNext(&pX->iter); + fts5PrefixMergerInsertByRowid(&pHead, pX); + } + } - fts5BufferSet(&p->rc, p1, out.n, out.p); - fts5BufferFree(&tmp); - fts5BufferFree(&out); + }else{ + /* Copy poslist from pHead to output */ + PrefixMerger *pThis = pHead; + Fts5DoclistIter *pI = &pThis->iter; + fts5BufferSafeAppendBlob(&out, pI->aPoslist, pI->nPoslist+pI->nSize); + fts5DoclistIterNext(pI); + pHead = pThis->pNext; + fts5PrefixMergerInsertByRowid(&pHead, pThis); + } } + + fts5BufferFree(p1); + fts5BufferFree(&tmp); + memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING); + *p1 = out; } static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ int bDesc, /* True for "ORDER BY rowid DESC" */ - const u8 *pToken, /* Buffer containing prefix to match */ + int iIdx, /* Index to scan for data */ + u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ Fts5Colset *pColset, /* Restrict matches to these columns */ Fts5Iter **ppIter /* OUT: New iterator */ ){ Fts5Structure *pStruct; Fts5Buffer *aBuf; - const int nBuf = 32; + int nBuf = 32; + int nMerge = 1; - void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*); + void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*); void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*); if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ xMerge = fts5MergeRowidLists; xAppend = fts5AppendRowid; }else{ + nMerge = FTS5_MERGE_NLIST-1; + nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */ xMerge = fts5MergePrefixLists; xAppend = fts5AppendPoslist; } @@ -193468,8 +230045,8 @@ static void fts5SetupPrefixIter( pStruct = fts5StructureRead(p); if( aBuf && pStruct ){ - const int flags = FTS5INDEX_QUERY_SCAN - | FTS5INDEX_QUERY_SKIPEMPTY + const int flags = FTS5INDEX_QUERY_SCAN + | FTS5INDEX_QUERY_SKIPEMPTY | FTS5INDEX_QUERY_NOOUTPUT; int i; i64 iLastRowid = 0; @@ -193479,6 +230056,27 @@ static void fts5SetupPrefixIter( int bNewTerm = 1; memset(&doclist, 0, sizeof(doclist)); + if( iIdx!=0 ){ + int dummy = 0; + const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT; + pToken[0] = FTS5_MAIN_PREFIX; + fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1); + fts5IterSetOutputCb(&p->rc, p1); + for(; + fts5MultiIterEof(p, p1)==0; + fts5MultiIterNext2(p, p1, &dummy) + ){ + Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; + p1->xSetOutputs(p1, pSeg); + if( p1->base.nData ){ + xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist); + iLastRowid = p1->base.iRowid; + } + } + fts5MultiIterFree(p1); + } + + pToken[0] = FTS5_MAIN_PREFIX + iIdx; fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); fts5IterSetOutputCb(&p->rc, p1); for( /* no-op */ ; @@ -193499,13 +230097,21 @@ static void fts5SetupPrefixIter( if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ - assert( ibase.iRowid; } - for(i=0; irc==SQLITE_OK ){ - xMerge(p, &doclist, &aBuf[i]); + xMerge(p, &doclist, nMerge, &aBuf[i]); + } + for(iFree=i; iFreep = (u8*)&pData[1]; pData->nn = pData->szLeaf = doclist.n; - memcpy(pData->p, doclist.p, doclist.n); + if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n); fts5MultiIterNew2(p, pData, bDesc, ppIter); } fts5BufferFree(&doclist); @@ -193551,9 +230161,9 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ } /* Flush the hash table to disk if required */ - if( iRowidiWriteRowid + if( iRowidiWriteRowid || (iRowid==p->iWriteRowid && p->bDelete==0) - || (p->nPendingData > p->pConfig->nHashSize) + || (p->nPendingData > p->pConfig->nHashSize) ){ fts5IndexFlush(p); } @@ -193566,21 +230176,21 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){ /* ** Commit data to disk. */ -static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){ +static int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); - if( bCommit ) fts5CloseReader(p); + sqlite3Fts5IndexCloseReader(p); return fts5IndexReturn(p); } /* ** Discard any data stored in the in-memory hash tables. Do not write it ** to the database. Additionally, assume that the contents of the %_data -** table may have changed on disk. So any in-memory caches of %_data +** table may have changed on disk. So any in-memory caches of %_data ** records must be invalidated. */ static int sqlite3Fts5IndexRollback(Fts5Index *p){ - fts5CloseReader(p); + sqlite3Fts5IndexCloseReader(p); fts5IndexDiscardData(p); fts5StructureInvalidate(p); /* assert( p->rc==SQLITE_OK ); */ @@ -193595,6 +230205,7 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){ static int sqlite3Fts5IndexReinit(Fts5Index *p){ Fts5Structure s; fts5StructureInvalidate(p); + fts5IndexDiscardData(p); memset(&s, 0, sizeof(Fts5Structure)); fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); fts5StructureWrite(p, &s); @@ -193609,8 +230220,8 @@ static int sqlite3Fts5IndexReinit(Fts5Index *p){ ** Otherwise, set *pp to NULL and return an SQLite error code. */ static int sqlite3Fts5IndexOpen( - Fts5Config *pConfig, - int bCreate, + Fts5Config *pConfig, + int bCreate, Fts5Index **pp, char **pzErr ){ @@ -193627,8 +230238,8 @@ static int sqlite3Fts5IndexOpen( pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr ); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5CreateTable(pConfig, "idx", - "segid, term, pgno, PRIMARY KEY(segid, term)", + rc = sqlite3Fts5CreateTable(pConfig, "idx", + "segid, term, pgno, PRIMARY KEY(segid, term)", 1, pzErr ); } @@ -193668,13 +230279,13 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){ } /* -** Argument p points to a buffer containing utf-8 text that is n bytes in +** Argument p points to a buffer containing utf-8 text that is n bytes in ** size. Return the number of bytes in the nChar character prefix of the ** buffer, or 0 if there are less than nChar characters in total. */ static int sqlite3Fts5IndexCharlenToBytelen( - const char *p, - int nByte, + const char *p, + int nByte, int nChar ){ int n = 0; @@ -193682,7 +230293,14 @@ static int sqlite3Fts5IndexCharlenToBytelen( for(i=0; i=nByte ) return 0; /* Input contains fewer than nChar chars */ if( (unsigned char)p[n++]>=0xc0 ){ - while( (p[n] & 0xc0)==0x80 ) n++; + if( n>=nByte ) return 0; + while( (p[n] & 0xc0)==0x80 ){ + n++; + if( n>=nByte ){ + if( i+1==nChar ) break; + return 0; + } + } } } return n; @@ -193693,7 +230311,7 @@ static int sqlite3Fts5IndexCharlenToBytelen( ** unicode characters in the string. */ static int fts5IndexCharlen(const char *pIn, int nIn){ - int nChar = 0; + int nChar = 0; int i = 0; while( i=0xc0 ){ @@ -193705,7 +230323,7 @@ static int fts5IndexCharlen(const char *pIn, int nIn){ } /* -** Insert or remove data to or from the index. Each time a document is +** Insert or remove data to or from the index. Each time a document is ** added to or removed from the index, this function is called one or more ** times. ** @@ -193736,7 +230354,7 @@ static int sqlite3Fts5IndexWrite( const int nChar = pConfig->aPrefix[i]; int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar); if( nByte ){ - rc = sqlite3Fts5HashWrite(p->pHash, + rc = sqlite3Fts5HashWrite(p->pHash, p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken, nByte ); @@ -193747,7 +230365,7 @@ static int sqlite3Fts5IndexWrite( } /* -** Open a new iterator to iterate though all rowid that match the +** Open a new iterator to iterate though all rowid that match the ** specified token or token prefix. */ static int sqlite3Fts5IndexQuery( @@ -193766,7 +230384,8 @@ static int sqlite3Fts5IndexQuery( if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ int iIdx = 0; /* Index to search */ - memcpy(&buf.p[1], pToken, nToken); + int iPrefixIdx = 0; /* +1 prefix index */ + if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken); /* Figure out which index to search and set iIdx accordingly. If this ** is a prefix query for which there is no prefix index, set iIdx to @@ -193774,9 +230393,9 @@ static int sqlite3Fts5IndexQuery( ** satisfied by scanning multiple terms in the main index. ** ** If the QUERY_TEST_NOIDX flag was specified, then this must be a - ** prefix-query. Instead of using a prefix-index (if one exists), + ** prefix-query. Instead of using a prefix-index (if one exists), ** evaluate the prefix query using the main FTS index. This is used - ** for internal sanity checking by the integrity-check in debug + ** for internal sanity checking by the integrity-check in debug ** mode only. */ #ifdef SQLITE_DEBUG if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){ @@ -193787,7 +230406,9 @@ static int sqlite3Fts5IndexQuery( if( flags & FTS5INDEX_QUERY_PREFIX ){ int nChar = fts5IndexCharlen(pToken, nToken); for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){ - if( pConfig->aPrefix[iIdx-1]==nChar ) break; + int nIdxChar = pConfig->aPrefix[iIdx-1]; + if( nIdxChar==nChar ) break; + if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx; } } @@ -193796,7 +230417,7 @@ static int sqlite3Fts5IndexQuery( Fts5Structure *pStruct = fts5StructureRead(p); buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); if( pStruct ){ - fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, + fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, pColset, buf.p, nToken+1, -1, 0, &pRet ); fts5StructureRelease(pStruct); @@ -193804,23 +230425,26 @@ static int sqlite3Fts5IndexQuery( }else{ /* Scan multiple terms in the main index */ int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; - buf.p[0] = FTS5_MAIN_PREFIX; - fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet); - assert( p->rc!=SQLITE_OK || pRet->pColset==0 ); - fts5IterSetOutputCb(&p->rc, pRet); - if( p->rc==SQLITE_OK ){ - Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; - if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); + fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet); + if( pRet==0 ){ + assert( p->rc!=SQLITE_OK ); + }else{ + assert( pRet->pColset==0 ); + fts5IterSetOutputCb(&p->rc, pRet); + if( p->rc==SQLITE_OK ){ + Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst]; + if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg); + } } } if( p->rc ){ - sqlite3Fts5IterClose(&pRet->base); + sqlite3Fts5IterClose((Fts5IndexIter*)pRet); pRet = 0; - fts5CloseReader(p); + sqlite3Fts5IndexCloseReader(p); } - *ppIter = &pRet->base; + *ppIter = (Fts5IndexIter*)pRet; sqlite3Fts5BufferFree(&buf); } return fts5IndexReturn(p); @@ -193830,7 +230454,7 @@ static int sqlite3Fts5IndexQuery( ** Return true if the iterator passed as the only argument is at EOF. */ /* -** Move to the next matching rowid. +** Move to the next matching rowid. */ static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; @@ -193878,8 +230502,9 @@ static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ int n; const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); + assert_nc( z || n<=1 ); *pn = n-1; - return &z[1]; + return (z ? &z[1] : 0); } /* @@ -193890,12 +230515,12 @@ static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ Fts5Iter *pIter = (Fts5Iter*)pIndexIter; Fts5Index *pIndex = pIter->pIndex; fts5MultiIterFree(pIter); - fts5CloseReader(pIndex); + sqlite3Fts5IndexCloseReader(pIndex); } } /* -** Read and decode the "averages" record from the database. +** Read and decode the "averages" record from the database. ** ** Parameter anSize must point to an array of size nCol, where nCol is ** the number of user defined columns in the FTS table. @@ -193921,7 +230546,7 @@ static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){ } /* -** Replace the current "averages" record with the contents of the buffer +** Replace the current "averages" record with the contents of the buffer ** supplied as the second argument. */ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){ @@ -193939,7 +230564,7 @@ static int sqlite3Fts5IndexReads(Fts5Index *p){ } /* -** Set the 32-bit cookie value stored at the start of all structure +** Set the 32-bit cookie value stored at the start of all structure ** records to the value passed as the second argument. ** ** Return SQLITE_OK if successful, or an SQLite error code if an error @@ -193954,7 +230579,7 @@ static int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){ assert( p->rc==SQLITE_OK ); sqlite3Fts5Put32(aCookie, iNew); - rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, + rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, "block", FTS5_STRUCTURE_ROWID, 1, &pBlob ); if( rc==SQLITE_OK ){ @@ -193975,7 +230600,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){ /************************************************************************* ************************************************************************** -** Below this point is the implementation of the integrity-check +** Below this point is the implementation of the integrity-check ** functionality. */ @@ -193983,9 +230608,9 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){ ** Return a simple checksum value based on the arguments. */ static u64 sqlite3Fts5IndexEntryCksum( - i64 iRowid, - int iCol, - int iPos, + i64 iRowid, + int iCol, + int iPos, int iIdx, const char *pTerm, int nTerm @@ -194001,15 +230626,15 @@ static u64 sqlite3Fts5IndexEntryCksum( #ifdef SQLITE_DEBUG /* -** This function is purely an internal test. It does not contribute to +** This function is purely an internal test. It does not contribute to ** FTS functionality, or even the integrity-check, in any way. ** -** Instead, it tests that the same set of pgno/rowid combinations are +** Instead, it tests that the same set of pgno/rowid combinations are ** visited regardless of whether the doclist-index identified by parameters ** iSegid/iLeaf is iterated in forwards or reverse order. */ static void fts5TestDlidxReverse( - Fts5Index *p, + Fts5Index *p, int iSegid, /* Segment id to load from */ int iLeaf /* Load doclist-index for this leaf */ ){ @@ -194057,7 +230682,7 @@ static int fts5QueryCksum( Fts5IndexIter *pIter = 0; int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); - while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){ + while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){ i64 rowid = pIter->iRowid; if( eDetail==FTS5_DETAIL_NONE ){ @@ -194083,13 +230708,44 @@ static int fts5QueryCksum( return rc; } +/* +** Check if buffer z[], size n bytes, contains as series of valid utf-8 +** encoded codepoints. If so, return 0. Otherwise, if the buffer does not +** contain valid utf-8, return non-zero. +*/ +static int fts5TestUtf8(const char *z, int n){ + int i = 0; + assert_nc( n>0 ); + while( i=n || (z[i+1] & 0xC0)!=0x80 ) return 1; + i += 2; + }else + if( (z[i] & 0xF0)==0xE0 ){ + if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1; + i += 3; + }else + if( (z[i] & 0xF8)==0xF0 ){ + if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1; + if( (z[i+2] & 0xC0)!=0x80 ) return 1; + i += 3; + }else{ + return 1; + } + } + + return 0; +} /* -** This function is also purely an internal test. It does not contribute to +** This function is also purely an internal test. It does not contribute to ** FTS functionality, or even the integrity-check, in any way. */ static void fts5TestTerm( - Fts5Index *p, + Fts5Index *p, Fts5Buffer *pPrev, /* Previous term */ const char *z, int n, /* Possibly new term to test */ u64 expected, @@ -194118,13 +230774,19 @@ static void fts5TestTerm( if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT; /* If this is a prefix query, check that the results returned if the - ** the index is disabled are the same. In both ASC and DESC order. + ** the index is disabled are the same. In both ASC and DESC order. ** ** This check may only be performed if the hash table is empty. This ** is because the hash table only supports a single scan query at ** a time, and the multi-iter loop from which this function is called - ** is already performing such a scan. */ - if( p->nPendingData==0 ){ + ** is already performing such a scan. + ** + ** Also only do this if buffer zTerm contains nTerm bytes of valid + ** utf-8. Otherwise, the last part of the buffer contents might contain + ** a non-utf-8 sequence that happens to be a prefix of a valid utf-8 + ** character stored in the main fts index, which will cause the + ** test to fail. */ + if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){ if( iIdx>0 && rc==SQLITE_OK ){ int f = flags|FTS5INDEX_QUERY_TEST_NOIDX; ck2 = 0; @@ -194149,7 +230811,7 @@ static void fts5TestTerm( } p->rc = rc; } - + #else # define fts5TestDlidxReverse(x,y,z) # define fts5TestTerm(u,v,w,x,y,z) @@ -194247,7 +230909,8 @@ static void fts5IndexIntegrityCheckSegment( if( pSeg->pgnoFirst==0 ) return; fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf( - "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d", + "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d " + "ORDER BY 1, 2", pConfig->zDb, pConfig->zName, pSeg->iSegid )); @@ -194256,12 +230919,12 @@ static void fts5IndexIntegrityCheckSegment( i64 iRow; /* Rowid for this leaf */ Fts5Data *pLeaf; /* Data for this leaf */ + const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1); int nIdxTerm = sqlite3_column_bytes(pStmt, 1); - const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1); int iIdxLeaf = sqlite3_column_int(pStmt, 2); int bIdxDlidx = sqlite3_column_int(pStmt, 3); - /* If the leaf in question has already been trimmed from the segment, + /* If the leaf in question has already been trimmed from the segment, ** ignore this b-tree entry. Otherwise, load it into memory. */ if( iIdxLeafpgnoFirst ) continue; iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf); @@ -194282,11 +230945,11 @@ static void fts5IndexIntegrityCheckSegment( iOff = fts5LeafFirstTermOff(pLeaf); iRowidOff = fts5LeafFirstRowidOff(pLeaf); - if( iRowidOff>=iOff ){ + if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; }else{ iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); - res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); + res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); if( res==0 ) res = nTerm - nIdxTerm; if( res<0 ) p->rc = FTS5_CORRUPT; } @@ -194369,7 +231032,7 @@ static void fts5IndexIntegrityCheckSegment( /* -** Run internal checks to ensure that the FTS index (a) is internally +** Run internal checks to ensure that the FTS index (a) is internally ** consistent and (b) contains entries for which the XOR of the checksums ** as calculated by sqlite3Fts5IndexEntryCksum() is cksum. ** @@ -194378,12 +231041,13 @@ static void fts5IndexIntegrityCheckSegment( ** error, or some other SQLite error code if another error (e.g. OOM) ** occurs. */ -static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ +static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){ int eDetail = p->pConfig->eDetail; u64 cksum2 = 0; /* Checksum based on contents of indexes */ Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ Fts5Iter *pIter; /* Used to iterate through entire index */ Fts5Structure *pStruct; /* Index structure */ + int iLvl, iSeg; #ifdef SQLITE_DEBUG /* Used by extra internal tests only run if NDEBUG is not defined */ @@ -194391,18 +231055,19 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */ #endif const int flags = FTS5INDEX_QUERY_NOOUTPUT; - + /* Load the FTS index structure */ pStruct = fts5StructureRead(p); + if( pStruct==0 ){ + assert( p->rc!=SQLITE_OK ); + return fts5IndexReturn(p); + } /* Check that the internal nodes of each segment match the leaves */ - if( pStruct ){ - int iLvl, iSeg; - for(iLvl=0; iLvlnLevel; iLvl++){ - for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ - Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; - fts5IndexIntegrityCheckSegment(p, pSeg); - } + for(iLvl=0; iLvlnLevel; iLvl++){ + for(iSeg=0; iSegaLevel[iLvl].nSeg; iSeg++){ + Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; + fts5IndexIntegrityCheckSegment(p, pSeg); } } @@ -194413,7 +231078,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ ** ** Two versions of the same checksum are calculated. The first (stack ** variable cksum2) based on entries extracted from the full-text index - ** while doing a linear scan of each individual index in turn. + ** while doing a linear scan of each individual index in turn. ** ** As each term visited by the linear scans, a separate query for the ** same term is performed. cksum3 is calculated based on the entries @@ -194439,6 +231104,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ }else{ poslist.n = 0; fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); + fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0"); while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ int iCol = FTS5_POS2COLUMN(iPos); int iTokOff = FTS5_POS2OFFSET(iPos); @@ -194449,7 +231115,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); fts5MultiIterFree(pIter); - if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; + if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; fts5StructureRelease(pStruct); #ifdef SQLITE_DEBUG @@ -194465,6 +231131,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ ** function only. */ +#ifdef SQLITE_TEST /* ** Decode a segment-data rowid from the %_data table. This function is ** the opposite of macro FTS5_SEGMENT_ROWID(). @@ -194487,7 +231154,9 @@ static void fts5DecodeRowid( *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1)); } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */ fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno); @@ -194505,7 +231174,9 @@ static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){ ); } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST static void fts5DebugStructure( int *pRc, /* IN/OUT: error code */ Fts5Buffer *pBuf, @@ -194515,25 +231186,27 @@ static void fts5DebugStructure( for(iLvl=0; iLvlnLevel; iLvl++){ Fts5StructureLevel *pLvl = &p->aLevel[iLvl]; - sqlite3Fts5BufferAppendPrintf(pRc, pBuf, + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg ); for(iSeg=0; iSegnSeg; iSeg++){ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg]; - sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", + sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast ); } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** ** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This ** function appends a human-readable representation of the same object -** to the buffer passed as the second argument. +** to the buffer passed as the second argument. */ static void fts5DecodeStructure( int *pRc, /* IN/OUT: error code */ @@ -194552,13 +231225,15 @@ static void fts5DecodeStructure( fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** This is part of the fts5_decode() debugging aid. ** -** Arguments pBlob/nBlob contain an "averages" record. This function -** appends a human-readable representation of record to the buffer passed -** as the second argument. +** Arguments pBlob/nBlob contain an "averages" record. This function +** appends a human-readable representation of record to the buffer passed +** as the second argument. */ static void fts5DecodeAverages( int *pRc, /* IN/OUT: error code */ @@ -194575,7 +231250,9 @@ static void fts5DecodeAverages( zSpace = " "; } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** Buffer (a/n) is assumed to contain a list of serialized varints. Read ** each varint and append its string representation to buffer pBuf. Return @@ -194592,12 +231269,14 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ } return iOff; } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** The start of buffer (a/n) contains the start of a doclist. The doclist ** may or may not finish within the buffer. This function appends a text ** representation of the part of the doclist that is present to buffer -** pBuf. +** pBuf. ** ** The return value is the number of bytes read from the input buffer. */ @@ -194625,9 +231304,11 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){ return iOff; } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* -** This function is part of the fts5_decode() debugging function. It is +** This function is part of the fts5_decode() debugging function. It is ** only ever used with detail=none tables. ** ** Buffer (pData/nData) contains a doclist in the format used by detail=none @@ -194666,7 +231347,9 @@ static void fts5DecodeRowidList( sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); } } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** The implementation of user-defined scalar function fts5_decode(). */ @@ -194681,7 +231364,7 @@ static void fts5DecodeFunction( u8 *a = 0; Fts5Buffer s; /* Build up text to return here */ int rc = SQLITE_OK; /* Return code */ - int nSpace = 0; + sqlite3_int64 nSpace = 0; int eDetailNone = (sqlite3_user_data(pCtx)!=0); assert( nArg==2 ); @@ -194697,8 +231380,7 @@ static void fts5DecodeFunction( nSpace = n + FTS5_DATA_ZERO_PADDING; a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace); if( a==0 ) goto decode_out; - memcpy(a, aBlob, n); - + if( n>0 ) memcpy(a, aBlob, n); fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno); @@ -194715,7 +231397,7 @@ static void fts5DecodeFunction( lvl.iLeafPgno = iPgno; for(fts5DlidxLvlNext(&lvl); lvl.bEof==0; fts5DlidxLvlNext(&lvl)){ - sqlite3Fts5BufferAppendPrintf(&rc, &s, + sqlite3Fts5BufferAppendPrintf(&rc, &s, " %d(%lld)", lvl.iLeafPgno, lvl.iRowid ); } @@ -194793,6 +231475,9 @@ static void fts5DecodeFunction( iPgidxOff = szLeaf = fts5GetU16(&a[2]); if( iPgidxOffn ){ + rc = FTS5_CORRUPT; + goto decode_out; } } @@ -194804,18 +231489,26 @@ static void fts5DecodeFunction( }else{ iOff = szLeaf; } + if( iOff>n ){ + rc = FTS5_CORRUPT; + goto decode_out; + } fts5DecodePoslist(&rc, &s, &a[4], iOff-4); /* Decode any more doclist data that appears on the page before the ** first term. */ nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff; + if( nDoclist+iOff>n ){ + rc = FTS5_CORRUPT; + goto decode_out; + } fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist); - while( iPgidxOffszLeaf ){ + rc = FTS5_CORRUPT; + break; + } if( bFirst==0 ){ iOff += fts5GetVarint32(&a[iOff], nByte); + if( nByte>term.n ){ + rc = FTS5_CORRUPT; + break; + } term.n = nByte; } iOff += fts5GetVarint32(&a[iOff], nByte); + if( iOff+nByte>n ){ + rc = FTS5_CORRUPT; + break; + } fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]); iOff += nByte; @@ -194843,7 +231548,7 @@ static void fts5DecodeFunction( fts5BufferFree(&term); } - + decode_out: sqlite3_free(a); if( rc==SQLITE_OK ){ @@ -194853,7 +231558,9 @@ static void fts5DecodeFunction( } fts5BufferFree(&s); } +#endif /* SQLITE_TEST */ +#ifdef SQLITE_TEST /* ** The implementation of user-defined scalar function fts5_rowid(). */ @@ -194871,7 +231578,7 @@ static void fts5RowidFunction( i64 iRowid; int segid, pgno; if( nArg!=3 ){ - sqlite3_result_error(pCtx, + sqlite3_result_error(pCtx, "should be: fts5_rowid('segment', segid, pgno))", -1 ); }else{ @@ -194881,12 +231588,13 @@ static void fts5RowidFunction( sqlite3_result_int64(pCtx, iRowid); } }else{ - sqlite3_result_error(pCtx, + sqlite3_result_error(pCtx, "first arg to fts5_rowid() must be 'segment'" , -1 ); } } } +#endif /* SQLITE_TEST */ /* ** This is called as part of registering the FTS5 module with database @@ -194897,13 +231605,14 @@ static void fts5RowidFunction( ** SQLite error code is returned instead. */ static int sqlite3Fts5IndexInit(sqlite3 *db){ +#ifdef SQLITE_TEST int rc = sqlite3_create_function( db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0 ); if( rc==SQLITE_OK ){ rc = sqlite3_create_function( - db, "fts5_decode_none", 2, + db, "fts5_decode_none", 2, SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0 ); } @@ -194914,6 +231623,10 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){ ); } return rc; +#else + return SQLITE_OK; + UNUSED_PARAM(db); +#endif } @@ -194949,20 +231662,22 @@ static int sqlite3Fts5IndexReset(Fts5Index *p){ ** assert() conditions in the fts5 code are activated - conditions that are ** only true if it is guaranteed that the fts5 database is not corrupt. */ +#ifdef SQLITE_DEBUG SQLITE_API int sqlite3_fts5_may_be_corrupt = 1; +#endif typedef struct Fts5Auxdata Fts5Auxdata; typedef struct Fts5Auxiliary Fts5Auxiliary; typedef struct Fts5Cursor Fts5Cursor; +typedef struct Fts5FullTable Fts5FullTable; typedef struct Fts5Sorter Fts5Sorter; -typedef struct Fts5Table Fts5Table; typedef struct Fts5TokenizerModule Fts5TokenizerModule; /* -** NOTES ON TRANSACTIONS: +** NOTES ON TRANSACTIONS: ** -** SQLite invokes the following virtual table methods as transactions are +** SQLite invokes the following virtual table methods as transactions are ** opened and closed by the user: ** ** xBegin(): Start of a new transaction. @@ -194971,7 +231686,7 @@ typedef struct Fts5TokenizerModule Fts5TokenizerModule; ** xRollback(): Rollback the transaction. ** ** Anything that is required as part of a commit that may fail is performed -** in the xSync() callback. Current versions of SQLite ignore any errors +** in the xSync() callback. Current versions of SQLite ignore any errors ** returned by xCommit(). ** ** And as sub-transactions are opened/closed: @@ -194980,9 +231695,9 @@ typedef struct Fts5TokenizerModule Fts5TokenizerModule; ** xRelease(int S): Commit and close savepoint S. ** xRollbackTo(int S): Rollback to start of savepoint S. ** -** During a write-transaction the fts5_index.c module may cache some data +** During a write-transaction the fts5_index.c module may cache some data ** in-memory. It is flushed to disk whenever xSync(), xRelease() or -** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo() +** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo() ** is called. ** ** Additionally, if SQLITE_DEBUG is defined, an instance of the following @@ -194996,13 +231711,13 @@ struct Fts5TransactionState { }; /* -** A single object of this type is allocated when the FTS5 module is +** A single object of this type is allocated when the FTS5 module is ** registered with a database handle. It is used to store pointers to ** all registered FTS5 extensions - tokenizers and auxiliary functions. */ struct Fts5Global { fts5_api api; /* User visible part of object (see fts5.h) */ - sqlite3 *db; /* Associated database connection */ + sqlite3 *db; /* Associated database connection */ i64 iNextId; /* Used to allocate unique cursor ids */ Fts5Auxiliary *pAux; /* First in list of all aux. functions */ Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */ @@ -195037,13 +231752,8 @@ struct Fts5TokenizerModule { Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ }; -/* -** Virtual-table object. -*/ -struct Fts5Table { - sqlite3_vtab base; /* Base class used by SQLite core */ - Fts5Config *pConfig; /* Virtual table configuration */ - Fts5Index *pIndex; /* Full-text index */ +struct Fts5FullTable { + Fts5Table p; /* Public class members from fts5Int.h */ Fts5Storage *pStorage; /* Document store */ Fts5Global *pGlobal; /* Global (connection wide) data */ Fts5Cursor *pSortCsr; /* Sort data from this cursor */ @@ -195063,7 +231773,7 @@ struct Fts5MatchPhrase { ** ** aIdx[]: ** There is one entry in the aIdx[] array for each phrase in the query, -** the value of which is the offset within aPoslist[] following the last +** the value of which is the offset within aPoslist[] following the last ** byte of the position list for the corresponding phrase. */ struct Fts5Sorter { @@ -195079,8 +231789,8 @@ struct Fts5Sorter { ** Virtual-table cursor object. ** ** iSpecial: -** If this is a 'special' query (refer to function fts5SpecialMatch()), -** then this variable contains the result of the query. +** If this is a 'special' query (refer to function fts5SpecialMatch()), +** then this variable contains the result of the query. ** ** iFirstRowid, iLastRowid: ** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the @@ -195131,7 +231841,7 @@ struct Fts5Cursor { }; /* -** Bits that make up the "idxNum" parameter passed indirectly by +** Bits that make up the "idxNum" parameter passed indirectly by ** xBestIndex() to xFilter(). */ #define FTS5_BI_MATCH 0x0001 /* MATCH ? */ @@ -195181,7 +231891,7 @@ struct Fts5Auxdata { #define FTS5_SAVEPOINT 5 #define FTS5_RELEASE 6 #define FTS5_ROLLBACKTO 7 -static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ +static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){ switch( op ){ case FTS5_BEGIN: assert( p->ts.eState==0 ); @@ -195207,10 +231917,10 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ case FTS5_SAVEPOINT: assert( p->ts.eState==1 ); assert( iSavepoint>=0 ); - assert( iSavepoint>p->ts.iSavepoint ); + assert( iSavepoint>=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint; break; - + case FTS5_RELEASE: assert( p->ts.eState==1 ); assert( iSavepoint>=0 ); @@ -195220,8 +231930,11 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ case FTS5_ROLLBACKTO: assert( p->ts.eState==1 ); - assert( iSavepoint>=0 ); - assert( iSavepoint<=p->ts.iSavepoint ); + assert( iSavepoint>=-1 ); + /* The following assert() can fail if another vtab strikes an error + ** within an xSavepoint() call then SQLite calls xRollbackTo() - without + ** having called xSavepoint() on this vtab. */ + /* assert( iSavepoint<=p->ts.iSavepoint ); */ p->ts.iSavepoint = iSavepoint; break; } @@ -195233,18 +231946,18 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){ /* ** Return true if pTab is a contentless table. */ -static int fts5IsContentless(Fts5Table *pTab){ - return pTab->pConfig->eContent==FTS5_CONTENT_NONE; +static int fts5IsContentless(Fts5FullTable *pTab){ + return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE; } /* -** Delete a virtual table handle allocated by fts5InitVtab(). +** Delete a virtual table handle allocated by fts5InitVtab(). */ -static void fts5FreeVtab(Fts5Table *pTab){ +static void fts5FreeVtab(Fts5FullTable *pTab){ if( pTab ){ - sqlite3Fts5IndexClose(pTab->pIndex); + sqlite3Fts5IndexClose(pTab->p.pIndex); sqlite3Fts5StorageClose(pTab->pStorage); - sqlite3Fts5ConfigFree(pTab->pConfig); + sqlite3Fts5ConfigFree(pTab->p.pConfig); sqlite3_free(pTab); } } @@ -195253,7 +231966,7 @@ static void fts5FreeVtab(Fts5Table *pTab){ ** The xDisconnect() virtual table method. */ static int fts5DisconnectMethod(sqlite3_vtab *pVtab){ - fts5FreeVtab((Fts5Table*)pVtab); + fts5FreeVtab((Fts5FullTable*)pVtab); return SQLITE_OK; } @@ -195264,7 +231977,7 @@ static int fts5DestroyMethod(sqlite3_vtab *pVtab){ Fts5Table *pTab = (Fts5Table*)pVtab; int rc = sqlite3Fts5DropAll(pTab->pConfig); if( rc==SQLITE_OK ){ - fts5FreeVtab((Fts5Table*)pVtab); + fts5FreeVtab((Fts5FullTable*)pVtab); } return rc; } @@ -195293,28 +232006,28 @@ static int fts5InitVtab( const char **azConfig = (const char**)argv; int rc = SQLITE_OK; /* Return code */ Fts5Config *pConfig = 0; /* Results of parsing argc/argv */ - Fts5Table *pTab = 0; /* New virtual table object */ + Fts5FullTable *pTab = 0; /* New virtual table object */ /* Allocate the new vtab object and parse the configuration */ - pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table)); + pTab = (Fts5FullTable*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5FullTable)); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr); assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 ); } if( rc==SQLITE_OK ){ - pTab->pConfig = pConfig; + pTab->p.pConfig = pConfig; pTab->pGlobal = pGlobal; } /* Open the index sub-system */ if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr); + rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->p.pIndex, pzErr); } /* Open the storage sub-system */ if( rc==SQLITE_OK ){ rc = sqlite3Fts5StorageOpen( - pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr + pConfig, pTab->p.pIndex, bCreate, &pTab->pStorage, pzErr ); } @@ -195327,8 +232040,8 @@ static int fts5InitVtab( if( rc==SQLITE_OK ){ assert( pConfig->pzErrmsg==0 ); pConfig->pzErrmsg = pzErr; - rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); - sqlite3Fts5IndexRollback(pTab->pIndex); + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); + sqlite3Fts5IndexRollback(pTab->p.pIndex); pConfig->pzErrmsg = 0; } @@ -195393,21 +232106,62 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ #endif } +static int fts5UsePatternMatch( + Fts5Config *pConfig, + struct sqlite3_index_constraint *p +){ + assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB ); + assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE ); + if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){ + return 1; + } + if( pConfig->ePattern==FTS5_PATTERN_LIKE + && (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB) + ){ + return 1; + } + return 0; +} + /* -** Implementation of the xBestIndex method for FTS5 tables. Within the +** Implementation of the xBestIndex method for FTS5 tables. Within the ** WHERE constraint, it searches for the following: ** -** 1. A MATCH constraint against the special column. +** 1. A MATCH constraint against the table column. ** 2. A MATCH constraint against the "rank" column. -** 3. An == constraint against the rowid column. -** 4. A < or <= constraint against the rowid column. -** 5. A > or >= constraint against the rowid column. +** 3. A MATCH constraint against some other column. +** 4. An == constraint against the rowid column. +** 5. A < or <= constraint against the rowid column. +** 6. A > or >= constraint against the rowid column. ** -** Within the ORDER BY, either: +** Within the ORDER BY, the following are supported: ** ** 5. ORDER BY rank [ASC|DESC] ** 6. ORDER BY rowid [ASC|DESC] ** +** Information for the xFilter call is passed via both the idxNum and +** idxStr variables. Specifically, idxNum is a bitmask of the following +** flags used to encode the ORDER BY clause: +** +** FTS5_BI_ORDER_RANK +** FTS5_BI_ORDER_ROWID +** FTS5_BI_ORDER_DESC +** +** idxStr is used to encode data from the WHERE clause. For each argument +** passed to the xFilter method, the following is appended to idxStr: +** +** Match against table column: "m" +** Match against rank column: "r" +** Match against other column: "M" +** LIKE against other column: "L" +** GLOB against other column: "G" +** Equality constraint against the rowid: "=" +** A < or <= against the rowid: "<" +** A > or >= against the rowid: ">" +** +** This function ensures that there is at most one "r" or "=". And that if +** there exists an "=" then there is no "<" or ">". +** ** Costs are assigned as follows: ** ** a) If an unusable MATCH operator is present in the WHERE clause, the @@ -195433,58 +232187,110 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ Fts5Table *pTab = (Fts5Table*)pVTab; Fts5Config *pConfig = pTab->pConfig; + const int nCol = pConfig->nCol; int idxFlags = 0; /* Parameter passed through to xFilter() */ - int bHasMatch; - int iNext; int i; - struct Constraint { - int op; /* Mask against sqlite3_index_constraint.op */ - int fts5op; /* FTS5 mask for idxFlags */ - int iCol; /* 0==rowid, 1==tbl, 2==rank */ - int omit; /* True to omit this if found */ - int iConsIndex; /* Index in pInfo->aConstraint[] */ - } aConstraint[] = { - {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, - FTS5_BI_MATCH, 1, 1, -1}, - {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, - FTS5_BI_RANK, 2, 1, -1}, - {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1}, - {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE, - FTS5_BI_ROWID_LE, 0, 0, -1}, - {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE, - FTS5_BI_ROWID_GE, 0, 0, -1}, - }; + char *idxStr; + int iIdxStr = 0; + int iCons = 0; + + int bSeenEq = 0; + int bSeenGt = 0; + int bSeenLt = 0; + int bSeenMatch = 0; + int bSeenRank = 0; + + + assert( SQLITE_INDEX_CONSTRAINT_EQbLock ){ + pTab->base.zErrMsg = sqlite3_mprintf( + "recursively defined fts5 content table" + ); + return SQLITE_ERROR; + } - int aColMap[3]; - aColMap[0] = -1; - aColMap[1] = pConfig->nCol; - aColMap[2] = pConfig->nCol+1; + idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1); + if( idxStr==0 ) return SQLITE_NOMEM; + pInfo->idxStr = idxStr; + pInfo->needToFreeIdxStr = 1; - /* Set idxFlags flags for all WHERE clause terms that will be used. */ for(i=0; inConstraint; i++){ struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; - int j; - for(j=0; jiColumn==aColMap[pC->iCol] && p->op & pC->op ){ - if( p->usable ){ - pC->iConsIndex = i; - idxFlags |= pC->fts5op; - }else if( j==0 ){ - /* As there exists an unusable MATCH constraint this is an - ** unusable plan. Set a prohibitively high cost. */ - pInfo->estimatedCost = 1e50; - return SQLITE_OK; + int iCol = p->iColumn; + if( p->op==SQLITE_INDEX_CONSTRAINT_MATCH + || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol>=nCol) + ){ + /* A MATCH operator or equivalent */ + if( p->usable==0 || iCol<0 ){ + /* As there exists an unusable MATCH constraint this is an + ** unusable plan. Set a prohibitively high cost. */ + pInfo->estimatedCost = 1e50; + assert( iIdxStr < pInfo->nConstraint*6 + 1 ); + idxStr[iIdxStr] = 0; + return SQLITE_OK; + }else{ + if( iCol==nCol+1 ){ + if( bSeenRank ) continue; + idxStr[iIdxStr++] = 'r'; + bSeenRank = 1; + }else if( iCol>=0 ){ + bSeenMatch = 1; + idxStr[iIdxStr++] = 'M'; + sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); + idxStr += strlen(&idxStr[iIdxStr]); + assert( idxStr[iIdxStr]=='\0' ); + } + pInfo->aConstraintUsage[i].argvIndex = ++iCons; + pInfo->aConstraintUsage[i].omit = 1; + } + }else if( p->usable ){ + if( iCol>=0 && iColop==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB ); + idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G'; + sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); + idxStr += strlen(&idxStr[iIdxStr]); + pInfo->aConstraintUsage[i].argvIndex = ++iCons; + assert( idxStr[iIdxStr]=='\0' ); + }else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){ + idxStr[iIdxStr++] = '='; + bSeenEq = 1; + pInfo->aConstraintUsage[i].argvIndex = ++iCons; + } + } + } + + if( bSeenEq==0 ){ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; + if( p->iColumn<0 && p->usable ){ + int op = p->op; + if( op==SQLITE_INDEX_CONSTRAINT_LT || op==SQLITE_INDEX_CONSTRAINT_LE ){ + if( bSeenLt ) continue; + idxStr[iIdxStr++] = '<'; + pInfo->aConstraintUsage[i].argvIndex = ++iCons; + bSeenLt = 1; + }else + if( op==SQLITE_INDEX_CONSTRAINT_GT || op==SQLITE_INDEX_CONSTRAINT_GE ){ + if( bSeenGt ) continue; + idxStr[iIdxStr++] = '>'; + pInfo->aConstraintUsage[i].argvIndex = ++iCons; + bSeenGt = 1; } } } } + idxStr[iIdxStr] = '\0'; /* Set idxFlags flags for the ORDER BY clause */ if( pInfo->nOrderBy==1 ){ int iSort = pInfo->aOrderBy[0].iColumn; - if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){ + if( iSort==(pConfig->nCol+1) && bSeenMatch ){ idxFlags |= FTS5_BI_ORDER_RANK; }else if( iSort==-1 ){ idxFlags |= FTS5_BI_ORDER_ROWID; @@ -195498,33 +232304,22 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ } /* Calculate the estimated cost based on the flags set in idxFlags. */ - bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH); - if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){ - pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0; - if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo); - }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ - pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; - }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ - pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; + if( bSeenEq ){ + pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0; + if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo); + }else if( bSeenLt && bSeenGt ){ + pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0; + }else if( bSeenLt || bSeenGt ){ + pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0; }else{ - pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; - } - - /* Assign argvIndex values to each constraint in use. */ - iNext = 1; - for(i=0; iiConsIndex>=0 ){ - pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++; - pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit; - } + pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0; } pInfo->idxNum = idxFlags; return SQLITE_OK; } -static int fts5NewTransaction(Fts5Table *pTab){ +static int fts5NewTransaction(Fts5FullTable *pTab){ Fts5Cursor *pCsr; for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK; @@ -195536,19 +232331,19 @@ static int fts5NewTransaction(Fts5Table *pTab){ ** Implementation of xOpen method. */ static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ - Fts5Table *pTab = (Fts5Table*)pVTab; - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)pVTab; + Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = 0; /* New cursor object */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc; /* Return code */ rc = fts5NewTransaction(pTab); if( rc==SQLITE_OK ){ nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int); - pCsr = (Fts5Cursor*)sqlite3_malloc(nByte); + pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte); if( pCsr ){ Fts5Global *pGlobal = pTab->pGlobal; - memset(pCsr, 0, nByte); + memset(pCsr, 0, (size_t)nByte); pCsr->aColumnSize = (int*)&pCsr[1]; pCsr->pNext = pGlobal->pCsr; pGlobal->pCsr = pCsr; @@ -195570,20 +232365,20 @@ static int fts5StmtType(Fts5Cursor *pCsr){ /* ** This function is called after the cursor passed as the only argument -** is moved to point at a different row. It clears all cached data +** is moved to point at a different row. It clears all cached data ** specific to the previous row stored by the cursor object. */ static void fts5CsrNewrow(Fts5Cursor *pCsr){ - CsrFlagSet(pCsr, - FTS5CSR_REQUIRE_CONTENT - | FTS5CSR_REQUIRE_DOCSIZE - | FTS5CSR_REQUIRE_INST - | FTS5CSR_REQUIRE_POSLIST + CsrFlagSet(pCsr, + FTS5CSR_REQUIRE_CONTENT + | FTS5CSR_REQUIRE_DOCSIZE + | FTS5CSR_REQUIRE_INST + | FTS5CSR_REQUIRE_POSLIST ); } static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); Fts5Auxdata *pData; Fts5Auxdata *pNext; @@ -195617,6 +232412,7 @@ static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ sqlite3_free(pCsr->zRankArgs); } + sqlite3Fts5IndexCloseReader(pTab->p.pIndex); memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr)); } @@ -195627,7 +232423,7 @@ static void fts5FreeCursorComponents(Fts5Cursor *pCsr){ */ static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){ if( pCursor ){ - Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; Fts5Cursor **pp; @@ -195648,7 +232444,7 @@ static int fts5SorterNext(Fts5Cursor *pCsr){ rc = sqlite3_step(pSorter->pStmt); if( rc==SQLITE_DONE ){ rc = SQLITE_OK; - CsrFlagSet(pCsr, FTS5CSR_EOF); + CsrFlagSet(pCsr, FTS5CSR_EOF|FTS5CSR_REQUIRE_CONTENT); }else if( rc==SQLITE_ROW ){ const u8 *a; const u8 *aBlob; @@ -195681,14 +232477,14 @@ static int fts5SorterNext(Fts5Cursor *pCsr){ /* -** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors +** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors ** open on table pTab. */ -static void fts5TripCursors(Fts5Table *pTab){ +static void fts5TripCursors(Fts5FullTable *pTab){ Fts5Cursor *pCsr; for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ if( pCsr->ePlan==FTS5_PLAN_MATCH - && pCsr->base.pVtab==(sqlite3_vtab*)pTab + && pCsr->base.pVtab==(sqlite3_vtab*)pTab ){ CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK); } @@ -195697,25 +232493,25 @@ static void fts5TripCursors(Fts5Table *pTab){ /* ** If the REQUIRE_RESEEK flag is set on the cursor passed as the first -** argument, close and reopen all Fts5IndexIter iterators that the cursor +** argument, close and reopen all Fts5IndexIter iterators that the cursor ** is using. Then attempt to move the cursor to a rowid equal to or laster -** (in the cursors sort order - ASC or DESC) than the current rowid. +** (in the cursors sort order - ASC or DESC) than the current rowid. ** ** If the new rowid is not equal to the old, set output parameter *pbSkip ** to 1 before returning. Otherwise, leave it unchanged. ** -** Return SQLITE_OK if successful or if no reseek was required, or an +** Return SQLITE_OK if successful or if no reseek was required, or an ** error code if an error occurred. */ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ int rc = SQLITE_OK; assert( *pbSkip==0 ); if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int bDesc = pCsr->bDesc; i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr); - rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc); + rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc); if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){ *pbSkip = 1; } @@ -195732,7 +232528,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){ /* -** Advance the cursor to the next row in the table that matches the +** Advance the cursor to the next row in the table that matches the ** search criteria. ** ** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned @@ -195744,7 +232540,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ int rc; assert( (pCsr->ePlan<3)== - (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) + (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) ); assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) ); @@ -195761,31 +232557,40 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){ rc = SQLITE_OK; break; } - + case FTS5_PLAN_SORTED_MATCH: { rc = fts5SorterNext(pCsr); break; } - - default: + + default: { + Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig; + pConfig->bLock++; rc = sqlite3_step(pCsr->pStmt); + pConfig->bLock--; if( rc!=SQLITE_ROW ){ CsrFlagSet(pCsr, FTS5CSR_EOF); rc = sqlite3_reset(pCsr->pStmt); + if( rc!=SQLITE_OK ){ + pCursor->pVtab->zErrMsg = sqlite3_mprintf( + "%s", sqlite3_errmsg(pConfig->db) + ); + } }else{ rc = SQLITE_OK; } break; + } } } - + return rc; } static int fts5PrepareStatement( sqlite3_stmt **ppStmt, - Fts5Config *pConfig, + Fts5Config *pConfig, const char *zFmt, ... ){ @@ -195797,9 +232602,10 @@ static int fts5PrepareStatement( va_start(ap, zFmt); zSql = sqlite3_vmprintf(zFmt, ap); if( zSql==0 ){ - rc = SQLITE_NOMEM; + rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0); + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &pRet, 0); if( rc!=SQLITE_OK ){ *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); } @@ -195809,33 +232615,37 @@ static int fts5PrepareStatement( va_end(ap); *ppStmt = pRet; return rc; -} +} -static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ - Fts5Config *pConfig = pTab->pConfig; +static int fts5CursorFirstSorted( + Fts5FullTable *pTab, + Fts5Cursor *pCsr, + int bDesc +){ + Fts5Config *pConfig = pTab->p.pConfig; Fts5Sorter *pSorter; int nPhrase; - int nByte; + sqlite3_int64 nByte; int rc; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; - + nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); - pSorter = (Fts5Sorter*)sqlite3_malloc(nByte); + pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; - memset(pSorter, 0, nByte); + memset(pSorter, 0, (size_t)nByte); pSorter->nIdx = nPhrase; /* TODO: It would be better to have some system for reusing statement ** handles here, rather than preparing a new one for each query. But that ** is not possible as SQLite reference counts the virtual table objects. - ** And since the statement required here reads from this very virtual + ** And since the statement required here reads from this very virtual ** table, saving it creates a circular reference. ** ** If SQLite a built-in statement cache, this wouldn't be a problem. */ rc = fts5PrepareStatement(&pSorter->pStmt, pConfig, - "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", + "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(\"%w\"%s%s) %s", pConfig->zDb, pConfig->zName, zRank, pConfig->zName, (zRankArgs ? ", " : ""), (zRankArgs ? zRankArgs : ""), @@ -195859,10 +232669,10 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ return rc; } -static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ +static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){ int rc; Fts5Expr *pExpr = pCsr->pExpr; - rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc); + rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc); if( sqlite3Fts5ExprEof(pExpr) ){ CsrFlagSet(pCsr, FTS5CSR_EOF); } @@ -195877,8 +232687,8 @@ static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ ** parameters. */ static int fts5SpecialMatch( - Fts5Table *pTab, - Fts5Cursor *pCsr, + Fts5FullTable *pTab, + Fts5Cursor *pCsr, const char *zQuery ){ int rc = SQLITE_OK; /* Return code */ @@ -195888,18 +232698,18 @@ static int fts5SpecialMatch( while( z[0]==' ' ) z++; for(n=0; z[n] && z[n]!=' '; n++); - assert( pTab->base.zErrMsg==0 ); + assert( pTab->p.base.zErrMsg==0 ); pCsr->ePlan = FTS5_PLAN_SPECIAL; - if( 0==sqlite3_strnicmp("reads", z, n) ){ - pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex); + if( n==5 && 0==sqlite3_strnicmp("reads", z, n) ){ + pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex); } - else if( 0==sqlite3_strnicmp("id", z, n) ){ + else if( n==2 && 0==sqlite3_strnicmp("id", z, n) ){ pCsr->iSpecial = pCsr->iCsrId; } else{ /* An unrecognized directive. Return an error message. */ - pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z); + pTab->p.base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z); rc = SQLITE_ERROR; } @@ -195911,7 +232721,7 @@ static int fts5SpecialMatch( ** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary ** structure. Otherwise, if no such function exists, return NULL. */ -static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){ +static Fts5Auxiliary *fts5FindAuxiliary(Fts5FullTable *pTab, const char *zName){ Fts5Auxiliary *pAux; for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){ @@ -195924,8 +232734,8 @@ static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){ static int fts5FindRankFunction(Fts5Cursor *pCsr){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; Fts5Auxiliary *pAux = 0; const char *zRank = pCsr->zRank; @@ -195935,12 +232745,13 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){ char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs); if( zSql ){ sqlite3_stmt *pStmt = 0; - rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0); + rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, + SQLITE_PREPARE_PERSISTENT, &pStmt, 0); sqlite3_free(zSql); assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ - int nByte; + sqlite3_int64 nByte; pCsr->nRankArg = sqlite3_column_count(pStmt); nByte = sizeof(sqlite3_value*)*pCsr->nRankArg; pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte); @@ -195962,8 +232773,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){ if( rc==SQLITE_OK ){ pAux = fts5FindAuxiliary(pTab, zRank); if( pAux==0 ){ - assert( pTab->base.zErrMsg==0 ); - pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank); + assert( pTab->p.base.zErrMsg==0 ); + pTab->p.base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank); rc = SQLITE_ERROR; } } @@ -195975,7 +232786,7 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){ static int fts5CursorParseRank( Fts5Config *pConfig, - Fts5Cursor *pCsr, + Fts5Cursor *pCsr, sqlite3_value *pRank ){ int rc = SQLITE_OK; @@ -196024,7 +232835,7 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){ ** This is the xFilter interface for the virtual table. See ** the virtual table xFilter method documentation for additional ** information. -** +** ** There are three possible query strategies: ** ** 1. Full-text search using a MATCH operator. @@ -196034,26 +232845,32 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){ static int fts5FilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ - const char *zUnused, /* Unused */ + const char *idxStr, /* Unused */ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ - Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; int rc = SQLITE_OK; /* Error code */ - int iVal = 0; /* Counter for apVal[] */ int bDesc; /* True if ORDER BY [rank|rowid] DESC */ int bOrderByRank; /* True if ORDER BY rank */ - sqlite3_value *pMatch = 0; /* MATCH ? expression (or NULL) */ sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */ sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */ sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */ sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */ + int iCol; /* Column on LHS of MATCH operator */ char **pzErrmsg = pConfig->pzErrmsg; + int i; + int iIdxStr = 0; + Fts5Expr *pExpr = 0; - UNUSED_PARAM(zUnused); - UNUSED_PARAM(nVal); + if( pConfig->bLock ){ + pTab->p.base.zErrMsg = sqlite3_mprintf( + "recursively defined fts5 content table" + ); + return SQLITE_ERROR; + } if( pCsr->ePlan ){ fts5FreeCursorComponents(pCsr); @@ -196066,25 +232883,78 @@ static int fts5FilterMethod( assert( pCsr->pRank==0 ); assert( pCsr->zRank==0 ); assert( pCsr->zRankArgs==0 ); + assert( pTab->pSortCsr==0 || nVal==0 ); - assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg ); - pConfig->pzErrmsg = &pTab->base.zErrMsg; + assert( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg ); + pConfig->pzErrmsg = &pTab->p.base.zErrMsg; - /* Decode the arguments passed through to this function. - ** - ** Note: The following set of if(...) statements must be in the same - ** order as the corresponding entries in the struct at the top of - ** fts5BestIndexMethod(). */ - if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++]; - if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++]; - if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++]; - if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++]; - if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++]; - assert( iVal==nVal ); + /* Decode the arguments passed through to this function. */ + for(i=0; i='0' && idxStr[iIdxStr]<='9' ); + + if( zText[0]=='*' ){ + /* The user has issued a query of the form "MATCH '*...'". This + ** indicates that the MATCH expression is not a full text query, + ** but a request for an internal parameter. */ + rc = fts5SpecialMatch(pTab, pCsr, &zText[1]); + goto filter_out; + }else{ + char **pzErr = &pTab->p.base.zErrMsg; + rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); + pExpr = 0; + } + if( rc!=SQLITE_OK ) goto filter_out; + } + + break; + } + case 'L': + case 'G': { + int bGlob = (idxStr[iIdxStr-1]=='G'); + const char *zText = (const char*)sqlite3_value_text(apVal[i]); + iCol = 0; + do{ + iCol = iCol*10 + (idxStr[iIdxStr]-'0'); + iIdxStr++; + }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ); + if( zText ){ + rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); + pExpr = 0; + } + if( rc!=SQLITE_OK ) goto filter_out; + break; + } + case '=': + pRowidEq = apVal[i]; + break; + case '<': + pRowidLe = apVal[i]; + break; + default: assert( idxStr[iIdxStr-1]=='>' ); + pRowidGe = apVal[i]; + break; + } + } bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0); pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0); - /* Set the cursor upper and lower rowid limits. Only some strategies + /* Set the cursor upper and lower rowid limits. Only some strategies ** actually use them. This is ok, as the xBestIndex() method leaves the ** sqlite3_index_constraint.omit flag clear for range constraints ** on the rowid field. */ @@ -196100,42 +232970,35 @@ static int fts5FilterMethod( } if( pTab->pSortCsr ){ - /* If pSortCsr is non-NULL, then this call is being made as part of + /* If pSortCsr is non-NULL, then this call is being made as part of ** processing for a "... MATCH ORDER BY rank" query (ePlan is ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will - ** return results to the user for this query. The current cursor - ** (pCursor) is used to execute the query issued by function + ** return results to the user for this query. The current cursor + ** (pCursor) is used to execute the query issued by function ** fts5CursorFirstSorted() above. */ assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); - assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); + assert( nVal==0 && bOrderByRank==0 && bDesc==0 ); assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); + if( pTab->pSortCsr->bDesc ){ + pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid; + pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid; + }else{ + pCsr->iLastRowid = pTab->pSortCsr->iLastRowid; + pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid; + } pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); - }else if( pMatch ){ - const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); - if( zExpr==0 ) zExpr = ""; - + }else if( pCsr->pExpr ){ rc = fts5CursorParseRank(pConfig, pCsr, pRank); if( rc==SQLITE_OK ){ - if( zExpr[0]=='*' ){ - /* The user has issued a query of the form "MATCH '*...'". This - ** indicates that the MATCH expression is not a full text query, - ** but a request for an internal parameter. */ - rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]); + if( bOrderByRank ){ + pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; + rc = fts5CursorFirstSorted(pTab, pCsr, bDesc); }else{ - char **pzErr = &pTab->base.zErrMsg; - rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr); - if( rc==SQLITE_OK ){ - if( bOrderByRank ){ - pCsr->ePlan = FTS5_PLAN_SORTED_MATCH; - rc = fts5CursorFirstSorted(pTab, pCsr, bDesc); - }else{ - pCsr->ePlan = FTS5_PLAN_MATCH; - rc = fts5CursorFirst(pTab, pCsr, bDesc); - } - } + pCsr->ePlan = FTS5_PLAN_MATCH; + rc = fts5CursorFirst(pTab, pCsr, bDesc); } } }else if( pConfig->zContent==0 ){ @@ -196148,11 +233011,12 @@ static int fts5FilterMethod( ** by rowid (ePlan==FTS5_PLAN_ROWID). */ pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN); rc = sqlite3Fts5StorageStmt( - pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg + pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg ); if( rc==SQLITE_OK ){ - if( pCsr->ePlan==FTS5_PLAN_ROWID ){ - sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); + if( pRowidEq!=0 ){ + assert( pCsr->ePlan==FTS5_PLAN_ROWID ); + sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq); }else{ sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid); sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid); @@ -196161,12 +233025,14 @@ static int fts5FilterMethod( } } + filter_out: + sqlite3Fts5ExprFree(pExpr); pConfig->pzErrmsg = pzErrmsg; return rc; } -/* -** This is the xEof method of the virtual table. SQLite calls this +/* +** This is the xEof method of the virtual table. SQLite calls this ** routine to find out if it has reached the end of a result set. */ static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){ @@ -196178,9 +233044,9 @@ static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){ ** Return the rowid that the cursor currently points to. */ static i64 fts5CursorRowid(Fts5Cursor *pCsr){ - assert( pCsr->ePlan==FTS5_PLAN_MATCH - || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH - || pCsr->ePlan==FTS5_PLAN_SOURCE + assert( pCsr->ePlan==FTS5_PLAN_MATCH + || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH + || pCsr->ePlan==FTS5_PLAN_SOURCE ); if( pCsr->pSorter ){ return pCsr->pSorter->iRowid; @@ -196189,7 +233055,7 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){ } } -/* +/* ** This is the xRowid method. The SQLite core calls this routine to ** retrieve the rowid for the current row of the result set. fts5 ** exposes %_content.rowid as the rowid for the virtual table. The @@ -196198,7 +233064,7 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; int ePlan = pCsr->ePlan; - + assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); switch( ePlan ){ case FTS5_PLAN_SPECIAL: @@ -196229,22 +233095,25 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ int rc = SQLITE_OK; - /* If the cursor does not yet have a statement handle, obtain one now. */ + /* If the cursor does not yet have a statement handle, obtain one now. */ if( pCsr->pStmt==0 ){ - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int eStmt = fts5StmtType(pCsr); rc = sqlite3Fts5StorageStmt( - pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0) + pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0) ); - assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 ); + assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 ); assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ); } if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){ + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); assert( pCsr->pExpr ); sqlite3_reset(pCsr->pStmt); sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr)); + pTab->pConfig->bLock++; rc = sqlite3_step(pCsr->pStmt); + pTab->pConfig->bLock--; if( rc==SQLITE_ROW ){ rc = SQLITE_OK; CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT); @@ -196252,17 +233121,21 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ rc = sqlite3_reset(pCsr->pStmt); if( rc==SQLITE_OK ){ rc = FTS5_CORRUPT; + }else if( pTab->pConfig->pzErrmsg ){ + *pTab->pConfig->pzErrmsg = sqlite3_mprintf( + "%s", sqlite3_errmsg(pTab->pConfig->db) + ); } } } return rc; } -static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){ +static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ va_list ap; /* ... printf arguments */ va_start(ap, zFormat); - assert( p->base.zErrMsg==0 ); - p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap); + assert( p->p.base.zErrMsg==0 ); + p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); } @@ -196273,7 +233146,7 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){ ** INSERT INTO fts(fts) VALUES($pCmd) ** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal) ** -** Argument pVal is the value assigned to column "fts" by the INSERT +** Argument pVal is the value assigned to column "fts" by the INSERT ** statement. This function returns SQLITE_OK if successful, or an SQLite ** error code if an error occurs. ** @@ -196282,17 +233155,17 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){ ** more commands are added to this function. */ static int fts5SpecialInsert( - Fts5Table *pTab, /* Fts5 table object */ + Fts5FullTable *pTab, /* Fts5 table object */ const char *zCmd, /* Text inserted into table-name column */ sqlite3_value *pVal /* Value inserted into rank column */ ){ - Fts5Config *pConfig = pTab->pConfig; + Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; int bError = 0; if( 0==sqlite3_stricmp("delete-all", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ - fts5SetVtabError(pTab, + fts5SetVtabError(pTab, "'delete-all' may only be used with a " "contentless or external content fts5 table" ); @@ -196302,7 +233175,7 @@ static int fts5SpecialInsert( } }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){ if( pConfig->eContent==FTS5_CONTENT_NONE ){ - fts5SetVtabError(pTab, + fts5SetVtabError(pTab, "'rebuild' may not be used with a contentless fts5 table" ); rc = SQLITE_ERROR; @@ -196315,15 +233188,16 @@ static int fts5SpecialInsert( int nMerge = sqlite3_value_int(pVal); rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ - rc = sqlite3Fts5StorageIntegrity(pTab->pStorage); + int iArg = sqlite3_value_int(pVal); + rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg); #ifdef SQLITE_DEBUG }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif }else{ - rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex); + rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError); + rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError); } if( rc==SQLITE_OK ){ if( bError ){ @@ -196337,7 +233211,7 @@ static int fts5SpecialInsert( } static int fts5SpecialDelete( - Fts5Table *pTab, + Fts5FullTable *pTab, sqlite3_value **apVal ){ int rc = SQLITE_OK; @@ -196350,9 +233224,9 @@ static int fts5SpecialDelete( } static void fts5StorageInsert( - int *pRc, - Fts5Table *pTab, - sqlite3_value **apVal, + int *pRc, + Fts5FullTable *pTab, + sqlite3_value **apVal, i64 *piRowid ){ int rc = *pRc; @@ -196365,13 +233239,13 @@ static void fts5StorageInsert( *pRc = rc; } -/* -** This function is the implementation of the xUpdate callback used by +/* +** This function is the implementation of the xUpdate callback used by ** FTS3 virtual tables. It is invoked by SQLite each time a row is to be ** inserted, updated or deleted. ** ** A delete specifies a single argument - the rowid of the row to remove. -** +** ** Update and insert operations pass: ** ** 1. The "old" rowid, or NULL. @@ -196385,8 +233259,8 @@ static int fts5UpdateMethod( sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ - Fts5Table *pTab = (Fts5Table*)pVtab; - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; + Fts5Config *pConfig = pTab->p.pConfig; int eType0; /* value_type() of apVal[0] */ int rc = SQLITE_OK; /* Return code */ @@ -196395,24 +233269,23 @@ static int fts5UpdateMethod( assert( pVtab->zErrMsg==0 ); assert( nArg==1 || nArg==(2+pConfig->nCol+2) ); - assert( nArg==1 - || sqlite3_value_type(apVal[1])==SQLITE_INTEGER - || sqlite3_value_type(apVal[1])==SQLITE_NULL + assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER + || sqlite3_value_type(apVal[0])==SQLITE_NULL ); - assert( pTab->pConfig->pzErrmsg==0 ); - pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + assert( pTab->p.pConfig->pzErrmsg==0 ); + pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; /* Put any active cursors into REQUIRE_SEEK state. */ fts5TripCursors(pTab); eType0 = sqlite3_value_type(apVal[0]); - if( eType0==SQLITE_NULL - && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL + if( eType0==SQLITE_NULL + && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL ){ /* A "special" INSERT op. These are handled separately. */ const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]); - if( pConfig->eContent!=FTS5_CONTENT_NORMAL - && 0==sqlite3_stricmp("delete", z) + if( pConfig->eContent!=FTS5_CONTENT_NORMAL + && 0==sqlite3_stricmp("delete", z) ){ rc = fts5SpecialDelete(pTab, apVal); }else{ @@ -196420,7 +233293,7 @@ static int fts5UpdateMethod( } }else{ /* A regular INSERT, UPDATE or DELETE statement. The trick here is that - ** any conflict on the rowid value must be detected before any + ** any conflict on the rowid value must be detected before any ** modifications are made to the database file. There are 4 cases: ** ** 1) DELETE @@ -196441,8 +233314,8 @@ static int fts5UpdateMethod( /* Filter out attempts to run UPDATE or DELETE on contentless tables. ** This is not suported. */ if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){ - pTab->base.zErrMsg = sqlite3_mprintf( - "cannot %s contentless fts5 table: %s", + pTab->p.base.zErrMsg = sqlite3_mprintf( + "cannot %s contentless fts5 table: %s", (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName ); rc = SQLITE_ERROR; @@ -196454,69 +233327,75 @@ static int fts5UpdateMethod( rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); } - /* INSERT */ - else if( eType0!=SQLITE_INTEGER ){ - /* If this is a REPLACE, first remove the current entry (if any) */ - if( eConflict==SQLITE_REPLACE - && sqlite3_value_type(apVal[1])==SQLITE_INTEGER - ){ - i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + /* INSERT or UPDATE */ + else{ + int eType1 = sqlite3_value_numeric_type(apVal[1]); + + if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){ + rc = SQLITE_MISMATCH; } - fts5StorageInsert(&rc, pTab, apVal, pRowid); - } - /* UPDATE */ - else{ - i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ - i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ - if( iOld!=iNew ){ - if( eConflict==SQLITE_REPLACE ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); - } - fts5StorageInsert(&rc, pTab, apVal, pRowid); - }else{ - rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); - if( rc==SQLITE_OK ){ + else if( eType0!=SQLITE_INTEGER ){ + /* If this is a REPLACE, first remove the current entry (if any) */ + if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ + i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + } + + /* UPDATE */ + else{ + i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ + i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ + if( eType1==SQLITE_INTEGER && iOld!=iNew ){ + if( eConflict==SQLITE_REPLACE ){ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); + } + fts5StorageInsert(&rc, pTab, apVal, pRowid); + }else{ + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid); + } } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid); - } + }else{ + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); + fts5StorageInsert(&rc, pTab, apVal, pRowid); } - }else{ - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); - fts5StorageInsert(&rc, pTab, apVal, pRowid); } } } - pTab->pConfig->pzErrmsg = 0; + pTab->p.pConfig->pzErrmsg = 0; return rc; } /* -** Implementation of xSync() method. +** Implementation of xSync() method. */ static int fts5SyncMethod(sqlite3_vtab *pVtab){ int rc; - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_SYNC, 0); - pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg; + pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg; fts5TripCursors(pTab); - rc = sqlite3Fts5StorageSync(pTab->pStorage, 1); - pTab->pConfig->pzErrmsg = 0; + rc = sqlite3Fts5StorageSync(pTab->pStorage); + pTab->p.pConfig->pzErrmsg = 0; return rc; } /* -** Implementation of xBegin() method. +** Implementation of xBegin() method. */ static int fts5BeginMethod(sqlite3_vtab *pVtab){ - fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); - fts5NewTransaction((Fts5Table*)pVtab); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0); + fts5NewTransaction((Fts5FullTable*)pVtab); return SQLITE_OK; } @@ -196527,7 +233406,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){ */ static int fts5CommitMethod(sqlite3_vtab *pVtab){ UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0); return SQLITE_OK; } @@ -196537,7 +233416,7 @@ static int fts5CommitMethod(sqlite3_vtab *pVtab){ */ static int fts5RollbackMethod(sqlite3_vtab *pVtab){ int rc; - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); rc = sqlite3Fts5StorageRollback(pTab->pStorage); return rc; @@ -196556,24 +233435,24 @@ static int fts5ApiColumnCount(Fts5Context *pCtx){ } static int fts5ApiColumnTotalSize( - Fts5Context *pCtx, - int iCol, + Fts5Context *pCtx, + int iCol, sqlite3_int64 *pnToken ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken); } static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); } static int fts5ApiTokenize( - Fts5Context *pCtx, - const char *pText, int nText, + Fts5Context *pCtx, + const char *pText, int nText, void *pUserData, int (*xToken)(void*, int, const char*, int, int, int) ){ @@ -196595,14 +233474,16 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){ } static int fts5ApiColumnText( - Fts5Context *pCtx, - int iCol, - const char **pz, + Fts5Context *pCtx, + int iCol, + const char **pz, int *pn ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ + if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) + || pCsr->ePlan==FTS5_PLAN_SPECIAL + ){ *pz = 0; *pn = 0; }else{ @@ -196616,8 +233497,8 @@ static int fts5ApiColumnText( } static int fts5CsrPoslist( - Fts5Cursor *pCsr, - int iPhrase, + Fts5Cursor *pCsr, + int iPhrase, const u8 **pa, int *pn ){ @@ -196671,10 +233552,11 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ int rc = SQLITE_OK; Fts5PoslistReader *aIter; /* One iterator for each phrase */ int nIter; /* Number of iterators/phrases */ - + int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol; + nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); if( pCsr->aInstIter==0 ){ - int nByte = sizeof(Fts5PoslistReader) * nIter; + sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter; pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte); } aIter = pCsr->aInstIter; @@ -196686,7 +233568,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ /* Initialize all iterators */ for(i=0; i=pCsr->nInstAlloc ){ - pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; - aInst = (int*)sqlite3_realloc( - pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 + int nNewSize = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; + aInst = (int*)sqlite3_realloc64( + pCsr->aInst, nNewSize*sizeof(int)*3 ); if( aInst ){ pCsr->aInst = aInst; + pCsr->nInstAlloc = nNewSize; }else{ + nInst--; rc = SQLITE_NOMEM; break; } @@ -196724,6 +233608,10 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ aInst[0] = iBest; aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); + if( aInst[1]<0 || aInst[1]>=nCol ){ + rc = FTS5_CORRUPT; + break; + } sqlite3Fts5PoslistReaderNext(&aIter[iBest]); } } @@ -196737,7 +233625,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; int rc = SQLITE_OK; - if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){ *pnInst = pCsr->nInstCount; } @@ -196745,16 +233633,16 @@ static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){ } static int fts5ApiInst( - Fts5Context *pCtx, - int iIdx, - int *piPhrase, - int *piCol, + Fts5Context *pCtx, + int iIdx, + int *piPhrase, + int *piCol, int *piOff ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; int rc = SQLITE_OK; - if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 - || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 + || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){ if( iIdx<0 || iIdx>=pCsr->nInstCount ){ rc = SQLITE_RANGE; @@ -196796,8 +233684,8 @@ static int fts5ColumnSizeCb( static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); + Fts5Config *pConfig = pTab->p.pConfig; int rc = SQLITE_OK; if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){ @@ -196903,8 +233791,8 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){ } static void fts5ApiPhraseNext( - Fts5Context *pUnused, - Fts5PhraseIter *pIter, + Fts5Context *pUnused, + Fts5PhraseIter *pIter, int *piCol, int *piOff ){ UNUSED_PARAM(pUnused); @@ -196925,16 +233813,17 @@ static void fts5ApiPhraseNext( } static int fts5ApiPhraseFirst( - Fts5Context *pCtx, - int iPhrase, - Fts5PhraseIter *pIter, + Fts5Context *pCtx, + int iPhrase, + Fts5PhraseIter *pIter, int *piCol, int *piOff ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; int n; int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ - pIter->b = &pIter->a[n]; + assert( pIter->a || n==0 ); + pIter->b = (pIter->a ? &pIter->a[n] : 0); *piCol = 0; *piOff = 0; fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); @@ -196943,8 +233832,8 @@ static int fts5ApiPhraseFirst( } static void fts5ApiPhraseNextColumn( - Fts5Context *pCtx, - Fts5PhraseIter *pIter, + Fts5Context *pCtx, + Fts5PhraseIter *pIter, int *piCol ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; @@ -196973,9 +233862,9 @@ static void fts5ApiPhraseNextColumn( } static int fts5ApiPhraseFirstColumn( - Fts5Context *pCtx, - int iPhrase, - Fts5PhraseIter *pIter, + Fts5Context *pCtx, + int iPhrase, + Fts5PhraseIter *pIter, int *piCol ){ int rc = SQLITE_OK; @@ -196993,7 +233882,8 @@ static int fts5ApiPhraseFirstColumn( rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); } if( rc==SQLITE_OK ){ - pIter->b = &pIter->a[n]; + assert( pIter->a || n==0 ); + pIter->b = (pIter->a ? &pIter->a[n] : 0); *piCol = 0; fts5ApiPhraseNextColumn(pCtx, pIter, piCol); } @@ -197001,7 +233891,8 @@ static int fts5ApiPhraseFirstColumn( int n; rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ - pIter->b = &pIter->a[n]; + assert( pIter->a || n==0 ); + pIter->b = (pIter->a ? &pIter->a[n] : 0); if( n<=0 ){ *piCol = -1; }else if( pIter->a[0]==0x01 ){ @@ -197016,7 +233907,7 @@ static int fts5ApiPhraseFirstColumn( } -static int fts5ApiQueryPhrase(Fts5Context*, int, void*, +static int fts5ApiQueryPhrase(Fts5Context*, int, void*, int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) ); @@ -197047,13 +233938,13 @@ static const Fts5ExtensionApi sFts5Api = { ** Implementation of API function xQueryPhrase(). */ static int fts5ApiQueryPhrase( - Fts5Context *pCtx, - int iPhrase, + Fts5Context *pCtx, + int iPhrase, void *pUserData, int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*) ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); + Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); int rc; Fts5Cursor *pNew = 0; @@ -197119,7 +234010,7 @@ static void fts5ApiCallback( iCsrId = sqlite3_value_int64(argv[0]); pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); - if( pCsr==0 ){ + if( pCsr==0 || pCsr->ePlan==0 ){ char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); @@ -197130,25 +234021,19 @@ static void fts5ApiCallback( /* -** Given cursor id iId, return a pointer to the corresponding Fts5Index +** Given cursor id iId, return a pointer to the corresponding Fts5Table ** object. Or NULL If the cursor id does not exist. -** -** If successful, set *ppConfig to point to the associated config object -** before returning. */ -static Fts5Index *sqlite3Fts5IndexFromCsrid( +static Fts5Table *sqlite3Fts5TableFromCsrid( Fts5Global *pGlobal, /* FTS5 global context for db handle */ - i64 iCsrId, /* Id of cursor to find */ - Fts5Config **ppConfig /* OUT: Configuration object */ + i64 iCsrId /* Id of cursor to find */ ){ Fts5Cursor *pCsr; - Fts5Table *pTab; - pCsr = fts5CursorFromCsrid(pGlobal, iCsrId); - pTab = (Fts5Table*)pCsr->base.pVtab; - *ppConfig = pTab->pConfig; - - return pTab->pIndex; + if( pCsr ){ + return (Fts5Table*)pCsr->base.pVtab; + } + return 0; } /* @@ -197219,7 +234104,7 @@ static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){ return rc; } -/* +/* ** This is the xColumn method, called by SQLite to request a value from ** the row that the supplied cursor currently points to. */ @@ -197228,11 +234113,11 @@ static int fts5ColumnMethod( sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ int iCol /* Index of column to read value from */ ){ - Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); - Fts5Config *pConfig = pTab->pConfig; + Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab); + Fts5Config *pConfig = pTab->p.pConfig; Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; int rc = SQLITE_OK; - + assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){ @@ -197252,7 +234137,7 @@ static int fts5ColumnMethod( /* The value of the "rank" column. */ if( pCsr->ePlan==FTS5_PLAN_SOURCE ){ fts5PoslistBlob(pCtx, pCsr); - }else if( + }else if( pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH ){ @@ -197261,10 +234146,12 @@ static int fts5ColumnMethod( } } }else if( !fts5IsContentless(pTab) ){ + pConfig->pzErrmsg = &pTab->p.base.zErrMsg; rc = fts5SeekCursor(pCsr, 1); if( rc==SQLITE_OK ){ sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } + pConfig->pzErrmsg = 0; } return rc; } @@ -197281,7 +234168,7 @@ static int fts5FindFunctionMethod( void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; Fts5Auxiliary *pAux; UNUSED_PARAM(nUnused); @@ -197303,21 +234190,24 @@ static int fts5RenameMethod( sqlite3_vtab *pVtab, /* Virtual table handle */ const char *zName /* New name of table */ ){ - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; return sqlite3Fts5StorageRename(pTab->pStorage, zName); } +static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ + fts5TripCursors((Fts5FullTable*)pTab); + return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage); +} + /* ** The xSavepoint() method. ** ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5Table *pTab = (Fts5Table*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); - fts5TripCursors(pTab); - return sqlite3Fts5StorageSync(pTab->pStorage, 0); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint); + return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* @@ -197326,11 +234216,9 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** This is a no-op. */ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5Table *pTab = (Fts5Table*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ - fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); - fts5TripCursors(pTab); - return sqlite3Fts5StorageSync(pTab->pStorage, 0); + fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint); + return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); } /* @@ -197339,7 +234227,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ ** Discard the contents of the pending terms table. */ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ - Fts5Table *pTab = (Fts5Table*)pVtab; + Fts5FullTable *pTab = (Fts5FullTable*)pVtab; UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */ fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); fts5TripCursors(pTab); @@ -197360,14 +234248,14 @@ static int fts5CreateAux( int rc = sqlite3_overload_function(pGlobal->db, zName, -1); if( rc==SQLITE_OK ){ Fts5Auxiliary *pAux; - int nName; /* Size of zName in bytes, including \0 */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nName; /* Size of zName in bytes, including \0 */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ - nName = (int)strlen(zName) + 1; + nName = strlen(zName) + 1; nByte = sizeof(Fts5Auxiliary) + nName; - pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte); + pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte); if( pAux ){ - memset(pAux, 0, nByte); + memset(pAux, 0, (size_t)nByte); pAux->zFunc = (char*)&pAux[1]; memcpy(pAux->zFunc, zName, nName); pAux->pGlobal = pGlobal; @@ -197385,7 +234273,7 @@ static int fts5CreateAux( } /* -** Register a new tokenizer. This is the implementation of the +** Register a new tokenizer. This is the implementation of the ** fts5_api.xCreateTokenizer() method. */ static int fts5CreateTokenizer( @@ -197397,15 +234285,15 @@ static int fts5CreateTokenizer( ){ Fts5Global *pGlobal = (Fts5Global*)pApi; Fts5TokenizerModule *pNew; - int nName; /* Size of zName and its \0 terminator */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nName; /* Size of zName and its \0 terminator */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc = SQLITE_OK; - nName = (int)strlen(zName) + 1; + nName = strlen(zName) + 1; nByte = sizeof(Fts5TokenizerModule) + nName; - pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte); + pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte); if( pNew ){ - memset(pNew, 0, nByte); + memset(pNew, 0, (size_t)nByte); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName); pNew->pUserData = pUserData; @@ -197424,7 +234312,7 @@ static int fts5CreateTokenizer( } static Fts5TokenizerModule *fts5LocateTokenizer( - Fts5Global *pGlobal, + Fts5Global *pGlobal, const char *zName ){ Fts5TokenizerModule *pMod = 0; @@ -197441,7 +234329,7 @@ static Fts5TokenizerModule *fts5LocateTokenizer( } /* -** Find a tokenizer. This is the implementation of the +** Find a tokenizer. This is the implementation of the ** fts5_api.xFindTokenizer() method. */ static int fts5FindTokenizer( @@ -197466,11 +234354,10 @@ static int fts5FindTokenizer( } static int sqlite3Fts5GetTokenizer( - Fts5Global *pGlobal, + Fts5Global *pGlobal, const char **azArg, int nArg, - Fts5Tokenizer **ppTok, - fts5_tokenizer **ppTokApi, + Fts5Config *pConfig, char **pzErr ){ Fts5TokenizerModule *pMod; @@ -197482,16 +234369,22 @@ static int sqlite3Fts5GetTokenizer( rc = SQLITE_ERROR; *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); }else{ - rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok); - *ppTokApi = &pMod->x; - if( rc!=SQLITE_OK && pzErr ){ - *pzErr = sqlite3_mprintf("error in tokenizer constructor"); + rc = pMod->x.xCreate( + pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok + ); + pConfig->pTokApi = &pMod->x; + if( rc!=SQLITE_OK ){ + if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor"); + }else{ + pConfig->ePattern = sqlite3Fts5TokenizerPattern( + pMod->x.xCreate, pConfig->pTok + ); } } if( rc!=SQLITE_OK ){ - *ppTokApi = 0; - *ppTok = 0; + pConfig->pTokApi = 0; + pConfig->pTok = 0; } return rc; @@ -197520,15 +234413,14 @@ static void fts5ModuleDestroy(void *pCtx){ static void fts5Fts5Func( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ - sqlite3_value **apUnused /* Function arguments */ + sqlite3_value **apArg /* Function arguments */ ){ Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx); - char buf[8]; - UNUSED_PARAM2(nArg, apUnused); - assert( nArg==0 ); - assert( sizeof(buf)>=sizeof(pGlobal) ); - memcpy(buf, (void*)&pGlobal, sizeof(pGlobal)); - sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT); + fts5_api **ppApi; + UNUSED_PARAM(nArg); + assert( nArg==1 ); + ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr"); + if( ppApi ) *ppApi = &pGlobal->api; } /* @@ -197541,12 +234433,27 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2017-02-13 16:02:40 ada05cfa86ad7f5645450ac7a2a21c9aa6e57d2c", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2022-03-26 13:51:10 d33c709cc0af66bc5b6dc6216eba9f1f0b40960b9ae83694c986fbf4c1d6f08f", -1, SQLITE_TRANSIENT); +} + +/* +** Return true if zName is the extension on one of the shadow tables used +** by this module. +*/ +static int fts5ShadowName(const char *zName){ + static const char *azName[] = { + "config", "content", "data", "docsize", "idx" + }; + unsigned int i; + for(i=0; ipConfig->bColumnsize || ( - eStmt!=FTS5_STMT_REPLACE_DOCSIZE - && eStmt!=FTS5_STMT_DELETE_DOCSIZE - && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE + eStmt!=FTS5_STMT_REPLACE_DOCSIZE + && eStmt!=FTS5_STMT_DELETE_DOCSIZE + && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE )); assert( eStmt>=0 && eStmtaStmt) ); @@ -197749,32 +234657,32 @@ static int fts5StorageGetStmt( switch( eStmt ){ case FTS5_STMT_SCAN: - zSql = sqlite3_mprintf(azStmt[eStmt], + zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, pC->zContent ); break; case FTS5_STMT_SCAN_ASC: case FTS5_STMT_SCAN_DESC: - zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, + zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, pC->zContent, pC->zContentRowid, pC->zContentRowid, pC->zContentRowid ); break; case FTS5_STMT_LOOKUP: - zSql = sqlite3_mprintf(azStmt[eStmt], + zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, pC->zContent, pC->zContentRowid ); break; - case FTS5_STMT_INSERT_CONTENT: + case FTS5_STMT_INSERT_CONTENT: case FTS5_STMT_REPLACE_CONTENT: { int nCol = pC->nCol + 1; char *zBind; int i; - zBind = sqlite3_malloc(1 + nCol*2); + zBind = sqlite3_malloc64(1 + nCol*2); if( zBind ){ for(i=0; idb, zSql, -1, &p->aStmt[eStmt], 0); + int f = SQLITE_PREPARE_PERSISTENT; + if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; + p->pConfig->bLock++; + rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0); + p->pConfig->bLock--; sqlite3_free(zSql); if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); @@ -197838,7 +234750,7 @@ static int fts5ExecPrintf( ** code otherwise. */ static int sqlite3Fts5DropAll(Fts5Config *pConfig){ - int rc = fts5ExecPrintf(pConfig->db, 0, + int rc = fts5ExecPrintf(pConfig->db, 0, "DROP TABLE IF EXISTS %Q.'%q_data';" "DROP TABLE IF EXISTS %Q.'%q_idx';" "DROP TABLE IF EXISTS %Q.'%q_config';", @@ -197847,13 +234759,13 @@ static int sqlite3Fts5DropAll(Fts5Config *pConfig){ pConfig->zDb, pConfig->zName ); if( rc==SQLITE_OK && pConfig->bColumnsize ){ - rc = fts5ExecPrintf(pConfig->db, 0, + rc = fts5ExecPrintf(pConfig->db, 0, "DROP TABLE IF EXISTS %Q.'%q_docsize';", pConfig->zDb, pConfig->zName ); } if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ - rc = fts5ExecPrintf(pConfig->db, 0, + rc = fts5ExecPrintf(pConfig->db, 0, "DROP TABLE IF EXISTS %Q.'%q_content';", pConfig->zDb, pConfig->zName ); @@ -197868,7 +234780,7 @@ static void fts5StorageRenameOne( const char *zName /* New name of FTS5 table */ ){ if( *pRc==SQLITE_OK ){ - *pRc = fts5ExecPrintf(pConfig->db, 0, + *pRc = fts5ExecPrintf(pConfig->db, 0, "ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';", pConfig->zDb, pConfig->zName, zTail, zName, zTail ); @@ -197877,7 +234789,7 @@ static void fts5StorageRenameOne( static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){ Fts5Config *pConfig = pStorage->pConfig; - int rc = sqlite3Fts5StorageSync(pStorage, 1); + int rc = sqlite3Fts5StorageSync(pStorage); fts5StorageRenameOne(pConfig, &rc, "data", zName); fts5StorageRenameOne(pConfig, &rc, "idx", zName); @@ -197906,7 +234818,7 @@ static int sqlite3Fts5CreateTable( char *zErr = 0; rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", - pConfig->zDb, pConfig->zName, zPost, zDefn, + pConfig->zDb, pConfig->zName, zPost, zDefn, #ifndef SQLITE_FTS5_NO_WITHOUT_ROWID bWithout?" WITHOUT ROWID": #endif @@ -197914,7 +234826,7 @@ static int sqlite3Fts5CreateTable( ); if( zErr ){ *pzErr = sqlite3_mprintf( - "fts5: error creating shadow table %q_%s: %s", + "fts5: error creating shadow table %q_%s: %s", pConfig->zName, zPost, zErr ); sqlite3_free(zErr); @@ -197925,28 +234837,28 @@ static int sqlite3Fts5CreateTable( /* ** Open a new Fts5Index handle. If the bCreate argument is true, create -** and initialize the underlying tables +** and initialize the underlying tables ** ** If successful, set *pp to point to the new object and return SQLITE_OK. ** Otherwise, set *pp to NULL and return an SQLite error code. */ static int sqlite3Fts5StorageOpen( - Fts5Config *pConfig, - Fts5Index *pIndex, - int bCreate, + Fts5Config *pConfig, + Fts5Index *pIndex, + int bCreate, Fts5Storage **pp, char **pzErr /* OUT: Error message */ ){ int rc = SQLITE_OK; Fts5Storage *p; /* New object */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ nByte = sizeof(Fts5Storage) /* Fts5Storage object */ + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */ - *pp = p = (Fts5Storage*)sqlite3_malloc(nByte); + *pp = p = (Fts5Storage*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->aTotalSize = (i64*)&p[1]; p->pConfig = pConfig; p->pIndex = pIndex; @@ -197954,7 +234866,7 @@ static int sqlite3Fts5StorageOpen( if( bCreate ){ if( pConfig->eContent==FTS5_CONTENT_NORMAL ){ int nDefn = 32 + pConfig->nCol*10; - char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10); + char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10); if( zDefn==0 ){ rc = SQLITE_NOMEM; }else{ @@ -198045,8 +234957,8 @@ static int fts5StorageInsertCallback( ** remove the %_content row at this time though. */ static int fts5StorageDeleteFromIndex( - Fts5Storage *p, - i64 iDel, + Fts5Storage *p, + i64 iDel, sqlite3_value **apVal ){ Fts5Config *pConfig = p->pConfig; @@ -198072,21 +234984,32 @@ static int fts5StorageDeleteFromIndex( if( pConfig->abUnindexed[iCol-1]==0 ){ const char *zText; int nText; + assert( pSeek==0 || apVal==0 ); + assert( pSeek!=0 || apVal!=0 ); if( pSeek ){ zText = (const char*)sqlite3_column_text(pSeek, iCol); nText = sqlite3_column_bytes(pSeek, iCol); - }else{ + }else if( ALWAYS(apVal) ){ zText = (const char*)sqlite3_value_text(apVal[iCol-1]); nText = sqlite3_value_bytes(apVal[iCol-1]); + }else{ + continue; } ctx.szCol = 0; - rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, zText, nText, (void*)&ctx, fts5StorageInsertCallback ); p->aTotalSize[iCol-1] -= (i64)ctx.szCol; + if( p->aTotalSize[iCol-1]<0 ){ + rc = FTS5_CORRUPT; + } } } - p->nTotalRow--; + if( rc==SQLITE_OK && p->nTotalRow<1 ){ + rc = FTS5_CORRUPT; + }else{ + p->nTotalRow--; + } rc2 = sqlite3_reset(pSeek); if( rc==SQLITE_OK ) rc = rc2; @@ -198116,13 +235039,14 @@ static int fts5StorageInsertDocsize( sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); + sqlite3_bind_null(pReplace, 2); } } return rc; } /* -** Load the contents of the "averages" record from disk into the +** Load the contents of the "averages" record from disk into the ** p->nTotalRow and p->aTotalSize[] variables. If successful, and if ** argument bCache is true, set the p->bTotalsValid flag to indicate ** that the contents of aTotalSize[] and nTotalRow are valid until @@ -198141,7 +235065,7 @@ static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){ } /* -** Store the current contents of the p->nTotalRow and p->aTotalSize[] +** Store the current contents of the p->nTotalRow and p->aTotalSize[] ** variables in the "averages" record on disk. ** ** Return SQLITE_OK if successful, or an SQLite error code if an error @@ -198204,11 +235128,6 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap } } - /* Write the averages record */ - if( rc==SQLITE_OK ){ - rc = fts5StorageSaveTotals(p); - } - return rc; } @@ -198219,9 +235138,11 @@ static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ Fts5Config *pConfig = p->pConfig; int rc; + p->bTotalsValid = 0; + /* Delete the contents of the %_data and %_docsize tables. */ rc = fts5ExecPrintf(pConfig->db, 0, - "DELETE FROM %Q.'%q_data';" + "DELETE FROM %Q.'%q_data';" "DELETE FROM %Q.'%q_idx';", pConfig->zDb, pConfig->zName, pConfig->zDb, pConfig->zName @@ -198249,7 +235170,7 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pScan = 0; Fts5InsertCtx ctx; - int rc; + int rc, rc2; memset(&ctx, 0, sizeof(Fts5InsertCtx)); ctx.pStorage = p; @@ -198270,10 +235191,11 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - rc = sqlite3Fts5Tokenize(pConfig, + const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1); + int nText = sqlite3_column_bytes(pScan, ctx.iCol+1); + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, - (const char*)sqlite3_column_text(pScan, ctx.iCol+1), - sqlite3_column_bytes(pScan, ctx.iCol+1), + zText, nText, (void*)&ctx, fts5StorageInsertCallback ); @@ -198288,6 +235210,8 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){ } } sqlite3_free(buf.p); + rc2 = sqlite3_reset(pScan); + if( rc==SQLITE_OK ) rc = rc2; /* Write the averages record */ if( rc==SQLITE_OK ){ @@ -198339,8 +235263,8 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){ ** Insert a new row into the FTS content table. */ static int sqlite3Fts5StorageContentInsert( - Fts5Storage *p, - sqlite3_value **apVal, + Fts5Storage *p, + sqlite3_value **apVal, i64 *piRowid ){ Fts5Config *pConfig = p->pConfig; @@ -198374,8 +235298,8 @@ static int sqlite3Fts5StorageContentInsert( ** Insert new entries into the FTS index and %_docsize table. */ static int sqlite3Fts5StorageIndexInsert( - Fts5Storage *p, - sqlite3_value **apVal, + Fts5Storage *p, + sqlite3_value **apVal, i64 iRowid ){ Fts5Config *pConfig = p->pConfig; @@ -198393,10 +235317,11 @@ static int sqlite3Fts5StorageIndexInsert( for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - rc = sqlite3Fts5Tokenize(pConfig, + const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]); + int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]); + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, - (const char*)sqlite3_value_text(apVal[ctx.iCol+2]), - sqlite3_value_bytes(apVal[ctx.iCol+2]), + zText, nText, (void*)&ctx, fts5StorageInsertCallback ); @@ -198412,11 +235337,6 @@ static int sqlite3Fts5StorageIndexInsert( } sqlite3_free(buf.p); - /* Write the averages record */ - if( rc==SQLITE_OK ){ - rc = fts5StorageSaveTotals(p); - } - return rc; } @@ -198425,7 +235345,7 @@ static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){ char *zSql; int rc; - zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'", + zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'", pConfig->zDb, pConfig->zName, zSuffix ); if( zSql==0 ){ @@ -198532,97 +235452,104 @@ static int fts5StorageIntegrityCallback( ** some other SQLite error code if an error occurs while attempting to ** determine this. */ -static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ +static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){ Fts5Config *pConfig = p->pConfig; - int rc; /* Return code */ + int rc = SQLITE_OK; /* Return code */ int *aColSize; /* Array of size pConfig->nCol */ i64 *aTotalSize; /* Array of size pConfig->nCol */ Fts5IntegrityCtx ctx; sqlite3_stmt *pScan; + int bUseCksum; memset(&ctx, 0, sizeof(Fts5IntegrityCtx)); ctx.pConfig = p->pConfig; - aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64))); + aTotalSize = (i64*)sqlite3_malloc64(pConfig->nCol*(sizeof(int)+sizeof(i64))); if( !aTotalSize ) return SQLITE_NOMEM; aColSize = (int*)&aTotalSize[pConfig->nCol]; memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol); - /* Generate the expected index checksum based on the contents of the - ** %_content table. This block stores the checksum in ctx.cksum. */ - rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); - if( rc==SQLITE_OK ){ - int rc2; - while( SQLITE_ROW==sqlite3_step(pScan) ){ - int i; - ctx.iRowid = sqlite3_column_int64(pScan, 0); - ctx.szCol = 0; - if( pConfig->bColumnsize ){ - rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); - } - if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ - rc = sqlite3Fts5TermsetNew(&ctx.pTermset); - } - for(i=0; rc==SQLITE_OK && inCol; i++){ - if( pConfig->abUnindexed[i] ) continue; - ctx.iCol = i; + bUseCksum = (pConfig->eContent==FTS5_CONTENT_NORMAL + || (pConfig->eContent==FTS5_CONTENT_EXTERNAL && iArg) + ); + if( bUseCksum ){ + /* Generate the expected index checksum based on the contents of the + ** %_content table. This block stores the checksum in ctx.cksum. */ + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); + if( rc==SQLITE_OK ){ + int rc2; + while( SQLITE_ROW==sqlite3_step(pScan) ){ + int i; + ctx.iRowid = sqlite3_column_int64(pScan, 0); ctx.szCol = 0; - if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + if( pConfig->bColumnsize ){ + rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - (const char*)sqlite3_column_text(pScan, i+1), - sqlite3_column_bytes(pScan, i+1), - (void*)&ctx, - fts5StorageIntegrityCallback - ); - } - if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ - rc = FTS5_CORRUPT; + if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } - aTotalSize[i] += ctx.szCol; - if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - sqlite3Fts5TermsetFree(ctx.pTermset); - ctx.pTermset = 0; + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( pConfig->abUnindexed[i] ) continue; + ctx.iCol = i; + ctx.szCol = 0; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + if( rc==SQLITE_OK ){ + const char *zText = (const char*)sqlite3_column_text(pScan, i+1); + int nText = sqlite3_column_bytes(pScan, i+1); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + zText, nText, + (void*)&ctx, + fts5StorageIntegrityCallback + ); + } + if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ + rc = FTS5_CORRUPT; + } + aTotalSize[i] += ctx.szCol; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + } } - } - sqlite3Fts5TermsetFree(ctx.pTermset); - ctx.pTermset = 0; + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; - if( rc!=SQLITE_OK ) break; + if( rc!=SQLITE_OK ) break; + } + rc2 = sqlite3_reset(pScan); + if( rc==SQLITE_OK ) rc = rc2; } - rc2 = sqlite3_reset(pScan); - if( rc==SQLITE_OK ) rc = rc2; - } - /* Test that the "totals" (sometimes called "averages") record looks Ok */ - if( rc==SQLITE_OK ){ - int i; - rc = fts5StorageLoadTotals(p, 0); - for(i=0; rc==SQLITE_OK && inCol; i++){ - if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT; + /* Test that the "totals" (sometimes called "averages") record looks Ok */ + if( rc==SQLITE_OK ){ + int i; + rc = fts5StorageLoadTotals(p, 0); + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT; + } } - } - /* Check that the %_docsize and %_content tables contain the expected - ** number of rows. */ - if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ - i64 nRow = 0; - rc = fts5StorageCount(p, "content", &nRow); - if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; - } - if( rc==SQLITE_OK && pConfig->bColumnsize ){ - i64 nRow = 0; - rc = fts5StorageCount(p, "docsize", &nRow); - if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + /* Check that the %_docsize and %_content tables contain the expected + ** number of rows. */ + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "content", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "docsize", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } } /* Pass the expected checksum down to the FTS index module. It will ** verify, amongst other things, that it matches the checksum generated by ** inspecting the index itself. */ if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum); + rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum, bUseCksum); } sqlite3_free(aTotalSize); @@ -198634,13 +235561,13 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ ** %_content table. */ static int sqlite3Fts5StorageStmt( - Fts5Storage *p, - int eStmt, - sqlite3_stmt **pp, + Fts5Storage *p, + int eStmt, + sqlite3_stmt **pp, char **pzErrMsg ){ int rc; - assert( eStmt==FTS5_STMT_SCAN_ASC + assert( eStmt==FTS5_STMT_SCAN_ASC || eStmt==FTS5_STMT_SCAN_DESC || eStmt==FTS5_STMT_LOOKUP ); @@ -198658,8 +235585,8 @@ static int sqlite3Fts5StorageStmt( ** must match that passed to the sqlite3Fts5StorageStmt() call. */ static void sqlite3Fts5StorageStmtRelease( - Fts5Storage *p, - int eStmt, + Fts5Storage *p, + int eStmt, sqlite3_stmt *pStmt ){ assert( eStmt==FTS5_STMT_SCAN_ASC @@ -198702,8 +235629,9 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ assert( p->pConfig->bColumnsize ); rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0); - if( rc==SQLITE_OK ){ + if( pLookup ){ int bCorrupt = 1; + assert( rc==SQLITE_OK ); sqlite3_bind_int64(pLookup, 1, iRowid); if( SQLITE_ROW==sqlite3_step(pLookup) ){ const u8 *aBlob = sqlite3_column_blob(pLookup, 0); @@ -198716,6 +235644,8 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){ if( bCorrupt && rc==SQLITE_OK ){ rc = FTS5_CORRUPT; } + }else{ + assert( rc!=SQLITE_OK ); } return rc; @@ -198742,7 +235672,13 @@ static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){ static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ int rc = fts5StorageLoadTotals(p, 0); if( rc==SQLITE_OK ){ + /* nTotalRow being zero does not necessarily indicate a corrupt + ** database - it might be that the FTS5 table really does contain zero + ** rows. However this function is only called from the xRowCount() API, + ** and there is no way for that API to be invoked if the table contains + ** no rows. Hence the FTS5_CORRUPT return. */ *pnRow = p->nTotalRow; + if( p->nTotalRow<=0 ) rc = FTS5_CORRUPT; } return rc; } @@ -198750,13 +235686,18 @@ static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){ /* ** Flush any data currently held in-memory to disk. */ -static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){ - if( bCommit && p->bTotalsValid ){ - int rc = fts5StorageSaveTotals(p); +static int sqlite3Fts5StorageSync(Fts5Storage *p){ + int rc = SQLITE_OK; + i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db); + if( p->bTotalsValid ){ + rc = fts5StorageSaveTotals(p); p->bTotalsValid = 0; - if( rc!=SQLITE_OK ) return rc; } - return sqlite3Fts5IndexSync(p->pIndex, bCommit); + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5IndexSync(p->pIndex); + } + sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid); + return rc; } static int sqlite3Fts5StorageRollback(Fts5Storage *p){ @@ -198765,7 +235706,7 @@ static int sqlite3Fts5StorageRollback(Fts5Storage *p){ } static int sqlite3Fts5StorageConfigValue( - Fts5Storage *p, + Fts5Storage *p, const char *z, sqlite3_value *pVal, int iVal @@ -198781,6 +235722,7 @@ static int sqlite3Fts5StorageConfigValue( } sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); + sqlite3_bind_null(pReplace, 1); } if( rc==SQLITE_OK && pVal ){ int iNew = p->pConfig->iCookie + 1; @@ -198814,7 +235756,7 @@ static int sqlite3Fts5StorageConfigValue( /* ** For tokenizers with no "unicode" modifier, the set of token characters -** is the same as the set of ASCII range alphanumeric characters. +** is the same as the set of ASCII range alphanumeric characters. */ static unsigned char aAsciiTokenChar[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00..0x0F */ @@ -198833,8 +235775,8 @@ struct AsciiTokenizer { }; static void fts5AsciiAddExceptions( - AsciiTokenizer *p, - const char *zArg, + AsciiTokenizer *p, + const char *zArg, int bTokenChars ){ int i; @@ -198856,7 +235798,7 @@ static void fts5AsciiDelete(Fts5Tokenizer *p){ ** Create an "ascii" tokenizer. */ static int fts5AsciiCreate( - void *pUnused, + void *pUnused, const char **azArg, int nArg, Fts5Tokenizer **ppOut ){ @@ -198946,7 +235888,7 @@ static int fts5AsciiTokenize( nByte = ie-is; if( nByte>nFold ){ if( pFold!=aFold ) sqlite3_free(pFold); - pFold = sqlite3_malloc(nByte*2); + pFold = sqlite3_malloc64((sqlite3_int64)nByte*2); if( pFold==0 ){ rc = SQLITE_NOMEM; break; @@ -198959,7 +235901,7 @@ static int fts5AsciiTokenize( rc = xToken(pCtx, 0, pFold, nByte, is, ie); is = ie+1; } - + if( pFold!=aFold ) sqlite3_free(pFold); if( rc==SQLITE_DONE ) rc = SQLITE_OK; return rc; @@ -199028,11 +235970,18 @@ struct Unicode61Tokenizer { unsigned char aTokenChar[128]; /* ASCII range token characters */ char *aFold; /* Buffer to fold text into */ int nFold; /* Size of aFold[] in bytes */ - int bRemoveDiacritic; /* True if remove_diacritics=1 is set */ + int eRemoveDiacritic; /* True if remove_diacritics=1 is set */ int nException; int *aiException; + + unsigned char aCategory[32]; /* True for token char categories */ }; +/* Values for eRemoveDiacritic (must match internals of fts5_unicode2.c) */ +#define FTS5_REMOVE_DIACRITICS_NONE 0 +#define FTS5_REMOVE_DIACRITICS_SIMPLE 1 +#define FTS5_REMOVE_DIACRITICS_COMPLEX 2 + static int fts5UnicodeAddExceptions( Unicode61Tokenizer *p, /* Tokenizer object */ const char *z, /* Characters to treat as exceptions */ @@ -199043,25 +235992,26 @@ static int fts5UnicodeAddExceptions( int *aNew; if( n>0 ){ - aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int)); + aNew = (int*)sqlite3_realloc64(p->aiException, + (n+p->nException)*sizeof(int)); if( aNew ){ int nNew = p->nException; const unsigned char *zCsr = (const unsigned char*)z; const unsigned char *zTerm = (const unsigned char*)&z[n]; while( zCsraTokenChar[iCode] = (unsigned char)bTokenChars; }else{ - bToken = sqlite3Fts5UnicodeIsalnum(iCode); - assert( (bToken==0 || bToken==1) ); + bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]; + assert( (bToken==0 || bToken==1) ); assert( (bTokenChars==0 || bTokenChars==1) ); if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){ int i; for(i=0; iiCode ) break; + if( (u32)aNew[i]>iCode ) break; } memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int)); aNew[i] = iCode; @@ -199116,16 +236066,31 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){ return; } +static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){ + const char *z = zCat; + + while( *z ){ + while( *z==' ' || *z=='\t' ) z++; + if( *z && sqlite3Fts5UnicodeCatParse(z, p->aCategory) ){ + return SQLITE_ERROR; + } + while( *z!=' ' && *z!='\t' && *z!='\0' ) z++; + } + + sqlite3Fts5UnicodeAscii(p->aCategory, p->aTokenChar); + return SQLITE_OK; +} + /* ** Create a "unicode61" tokenizer. */ static int fts5UnicodeCreate( - void *pUnused, + void *pUnused, const char **azArg, int nArg, Fts5Tokenizer **ppOut ){ int rc = SQLITE_OK; /* Return code */ - Unicode61Tokenizer *p = 0; /* New tokenizer object */ + Unicode61Tokenizer *p = 0; /* New tokenizer object */ UNUSED_PARAM(pUnused); @@ -199134,32 +236099,54 @@ static int fts5UnicodeCreate( }else{ p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); if( p ){ + const char *zCat = "L* N* Co"; int i; memset(p, 0, sizeof(Unicode61Tokenizer)); - memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); - p->bRemoveDiacritic = 1; + + p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE; p->nFold = 64; - p->aFold = sqlite3_malloc(p->nFold * sizeof(char)); + p->aFold = sqlite3_malloc64(p->nFold * sizeof(char)); if( p->aFold==0 ){ rc = SQLITE_NOMEM; } + + /* Search for a "categories" argument */ + for(i=0; rc==SQLITE_OK && ieRemoveDiacritic = (zArg[0] - '0'); + assert( p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_NONE + || p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_SIMPLE + || p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_COMPLEX + ); } - p->bRemoveDiacritic = (zArg[0]=='1'); }else if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){ rc = fts5UnicodeAddExceptions(p, zArg, 1); }else if( 0==sqlite3_stricmp(azArg[i], "separators") ){ rc = fts5UnicodeAddExceptions(p, zArg, 0); + }else + if( 0==sqlite3_stricmp(azArg[i], "categories") ){ + /* no-op */ }else{ rc = SQLITE_ERROR; } } + }else{ rc = SQLITE_NOMEM; } @@ -199174,12 +236161,14 @@ static int fts5UnicodeCreate( /* ** Return true if, for the purposes of tokenizing with the tokenizer -** passed as the first argument, codepoint iCode is considered a token +** passed as the first argument, codepoint iCode is considered a token ** character (not a separator). */ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){ - assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 ); - return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode); + return ( + p->aCategory[sqlite3Fts5UnicodeCategory((u32)iCode)] + ^ fts5UnicodeIsException(p, iCode) + ); } static int fts5UnicodeTokenize( @@ -199206,7 +236195,7 @@ static int fts5UnicodeTokenize( /* Each iteration of this loop gobbles up a contiguous run of separators, ** then the next token. */ while( rc==SQLITE_OK ){ - int iCode; /* non-ASCII codepoint read from input */ + u32 iCode; /* non-ASCII codepoint read from input */ char *zOut = aFold; int is; int ie; @@ -199238,7 +236227,7 @@ static int fts5UnicodeTokenize( /* Grow the output buffer so that there is sufficient space to fit the ** largest possible utf-8 character. */ if( zOut>pEnd ){ - aFold = sqlite3_malloc(nFold*2); + aFold = sqlite3_malloc64((sqlite3_int64)nFold*2); if( aFold==0 ){ rc = SQLITE_NOMEM; goto tokenize_done; @@ -199257,14 +236246,14 @@ static int fts5UnicodeTokenize( READ_UTF8(zCsr, zTerm, iCode); if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){ non_ascii_tokenchar: - iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic); + iCode = sqlite3Fts5UnicodeFold(iCode, p->eRemoveDiacritic); if( iCode ) WRITE_UTF8(zOut, iCode); }else{ break; } }else if( a[*zCsr]==0 ){ /* An ascii-range separator character. End of token. */ - break; + break; }else{ ascii_tokenchar: if( *zCsr>='A' && *zCsr<='Z' ){ @@ -199278,9 +236267,9 @@ static int fts5UnicodeTokenize( } /* Invoke the token callback */ - rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie); + rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie); } - + tokenize_done: if( rc==SQLITE_DONE ) rc = SQLITE_OK; return rc; @@ -199318,7 +236307,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){ ** Create a "porter" tokenizer. */ static int fts5PorterCreate( - void *pCtx, + void *pCtx, const char **azArg, int nArg, Fts5Tokenizer **ppOut ){ @@ -199462,7 +236451,7 @@ static int fts5Porter_Ostar(char *zStem, int nStem){ /* porter rule condition: (m > 1 and (*S or *T)) */ static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){ assert( nStem>0 ); - return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t') + return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t') && fts5Porter_MGt1(zStem, nStem); } @@ -199487,16 +236476,16 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){ int ret = 0; int nBuf = *pnBuf; switch( aBuf[nBuf-2] ){ - - case 'a': + + case 'a': if( nBuf>2 && 0==memcmp("al", &aBuf[nBuf-2], 2) ){ if( fts5Porter_MGt1(aBuf, nBuf-2) ){ *pnBuf = nBuf - 2; } } break; - - case 'c': + + case 'c': if( nBuf>4 && 0==memcmp("ance", &aBuf[nBuf-4], 4) ){ if( fts5Porter_MGt1(aBuf, nBuf-4) ){ *pnBuf = nBuf - 4; @@ -199507,24 +236496,24 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){ } } break; - - case 'e': + + case 'e': if( nBuf>2 && 0==memcmp("er", &aBuf[nBuf-2], 2) ){ if( fts5Porter_MGt1(aBuf, nBuf-2) ){ *pnBuf = nBuf - 2; } } break; - - case 'i': + + case 'i': if( nBuf>2 && 0==memcmp("ic", &aBuf[nBuf-2], 2) ){ if( fts5Porter_MGt1(aBuf, nBuf-2) ){ *pnBuf = nBuf - 2; } } break; - - case 'l': + + case 'l': if( nBuf>4 && 0==memcmp("able", &aBuf[nBuf-4], 4) ){ if( fts5Porter_MGt1(aBuf, nBuf-4) ){ *pnBuf = nBuf - 4; @@ -199535,8 +236524,8 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){ } } break; - - case 'n': + + case 'n': if( nBuf>3 && 0==memcmp("ant", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt1(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; @@ -199555,8 +236544,8 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){ } } break; - - case 'o': + + case 'o': if( nBuf>3 && 0==memcmp("ion", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt1_and_S_or_T(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; @@ -199567,16 +236556,16 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){ } } break; - - case 's': + + case 's': if( nBuf>3 && 0==memcmp("ism", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt1(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; } } break; - - case 't': + + case 't': if( nBuf>3 && 0==memcmp("ate", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt1(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; @@ -199587,76 +236576,76 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){ } } break; - - case 'u': + + case 'u': if( nBuf>3 && 0==memcmp("ous", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt1(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; } } break; - - case 'v': + + case 'v': if( nBuf>3 && 0==memcmp("ive", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt1(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; } } break; - - case 'z': + + case 'z': if( nBuf>3 && 0==memcmp("ize", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt1(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; } } break; - + } return ret; } - + static int fts5PorterStep1B2(char *aBuf, int *pnBuf){ int ret = 0; int nBuf = *pnBuf; switch( aBuf[nBuf-2] ){ - - case 'a': + + case 'a': if( nBuf>2 && 0==memcmp("at", &aBuf[nBuf-2], 2) ){ memcpy(&aBuf[nBuf-2], "ate", 3); *pnBuf = nBuf - 2 + 3; ret = 1; } break; - - case 'b': + + case 'b': if( nBuf>2 && 0==memcmp("bl", &aBuf[nBuf-2], 2) ){ memcpy(&aBuf[nBuf-2], "ble", 3); *pnBuf = nBuf - 2 + 3; ret = 1; } break; - - case 'i': + + case 'i': if( nBuf>2 && 0==memcmp("iz", &aBuf[nBuf-2], 2) ){ memcpy(&aBuf[nBuf-2], "ize", 3); *pnBuf = nBuf - 2 + 3; ret = 1; } break; - + } return ret; } - + static int fts5PorterStep2(char *aBuf, int *pnBuf){ int ret = 0; int nBuf = *pnBuf; switch( aBuf[nBuf-2] ){ - - case 'a': + + case 'a': if( nBuf>7 && 0==memcmp("ational", &aBuf[nBuf-7], 7) ){ if( fts5Porter_MGt0(aBuf, nBuf-7) ){ memcpy(&aBuf[nBuf-7], "ate", 3); @@ -199669,8 +236658,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - - case 'c': + + case 'c': if( nBuf>4 && 0==memcmp("enci", &aBuf[nBuf-4], 4) ){ if( fts5Porter_MGt0(aBuf, nBuf-4) ){ memcpy(&aBuf[nBuf-4], "ence", 4); @@ -199683,8 +236672,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - - case 'e': + + case 'e': if( nBuf>4 && 0==memcmp("izer", &aBuf[nBuf-4], 4) ){ if( fts5Porter_MGt0(aBuf, nBuf-4) ){ memcpy(&aBuf[nBuf-4], "ize", 3); @@ -199692,8 +236681,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - - case 'g': + + case 'g': if( nBuf>4 && 0==memcmp("logi", &aBuf[nBuf-4], 4) ){ if( fts5Porter_MGt0(aBuf, nBuf-4) ){ memcpy(&aBuf[nBuf-4], "log", 3); @@ -199701,8 +236690,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - - case 'l': + + case 'l': if( nBuf>3 && 0==memcmp("bli", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt0(aBuf, nBuf-3) ){ memcpy(&aBuf[nBuf-3], "ble", 3); @@ -199730,8 +236719,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - - case 'o': + + case 'o': if( nBuf>7 && 0==memcmp("ization", &aBuf[nBuf-7], 7) ){ if( fts5Porter_MGt0(aBuf, nBuf-7) ){ memcpy(&aBuf[nBuf-7], "ize", 3); @@ -199749,8 +236738,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - - case 's': + + case 's': if( nBuf>5 && 0==memcmp("alism", &aBuf[nBuf-5], 5) ){ if( fts5Porter_MGt0(aBuf, nBuf-5) ){ memcpy(&aBuf[nBuf-5], "al", 2); @@ -199773,8 +236762,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - - case 't': + + case 't': if( nBuf>5 && 0==memcmp("aliti", &aBuf[nBuf-5], 5) ){ if( fts5Porter_MGt0(aBuf, nBuf-5) ){ memcpy(&aBuf[nBuf-5], "al", 2); @@ -199792,18 +236781,18 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){ } } break; - + } return ret; } - + static int fts5PorterStep3(char *aBuf, int *pnBuf){ int ret = 0; int nBuf = *pnBuf; switch( aBuf[nBuf-2] ){ - - case 'a': + + case 'a': if( nBuf>4 && 0==memcmp("ical", &aBuf[nBuf-4], 4) ){ if( fts5Porter_MGt0(aBuf, nBuf-4) ){ memcpy(&aBuf[nBuf-4], "ic", 2); @@ -199811,16 +236800,16 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){ } } break; - - case 's': + + case 's': if( nBuf>4 && 0==memcmp("ness", &aBuf[nBuf-4], 4) ){ if( fts5Porter_MGt0(aBuf, nBuf-4) ){ *pnBuf = nBuf - 4; } } break; - - case 't': + + case 't': if( nBuf>5 && 0==memcmp("icate", &aBuf[nBuf-5], 5) ){ if( fts5Porter_MGt0(aBuf, nBuf-5) ){ memcpy(&aBuf[nBuf-5], "ic", 2); @@ -199833,24 +236822,24 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){ } } break; - - case 'u': + + case 'u': if( nBuf>3 && 0==memcmp("ful", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt0(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; } } break; - - case 'v': + + case 'v': if( nBuf>5 && 0==memcmp("ative", &aBuf[nBuf-5], 5) ){ if( fts5Porter_MGt0(aBuf, nBuf-5) ){ *pnBuf = nBuf - 5; } } break; - - case 'z': + + case 'z': if( nBuf>5 && 0==memcmp("alize", &aBuf[nBuf-5], 5) ){ if( fts5Porter_MGt0(aBuf, nBuf-5) ){ memcpy(&aBuf[nBuf-5], "al", 2); @@ -199858,18 +236847,18 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){ } } break; - + } return ret; } - + static int fts5PorterStep1B(char *aBuf, int *pnBuf){ int ret = 0; int nBuf = *pnBuf; switch( aBuf[nBuf-2] ){ - - case 'e': + + case 'e': if( nBuf>3 && 0==memcmp("eed", &aBuf[nBuf-3], 3) ){ if( fts5Porter_MGt0(aBuf, nBuf-3) ){ memcpy(&aBuf[nBuf-3], "ee", 2); @@ -199882,8 +236871,8 @@ static int fts5PorterStep1B(char *aBuf, int *pnBuf){ } } break; - - case 'n': + + case 'n': if( nBuf>3 && 0==memcmp("ing", &aBuf[nBuf-3], 3) ){ if( fts5Porter_Vowel(aBuf, nBuf-3) ){ *pnBuf = nBuf - 3; @@ -199891,12 +236880,12 @@ static int fts5PorterStep1B(char *aBuf, int *pnBuf){ } } break; - + } return ret; } - -/* + +/* ** GENERATED CODE ENDS HERE (mkportersteps.tcl) *************************************************************************** **************************************************************************/ @@ -199905,7 +236894,7 @@ static void fts5PorterStep1A(char *aBuf, int *pnBuf){ int nBuf = *pnBuf; if( aBuf[nBuf-1]=='s' ){ if( aBuf[nBuf-2]=='e' ){ - if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s') + if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s') || (nBuf>3 && aBuf[nBuf-3]=='i' ) ){ *pnBuf = nBuf-2; @@ -199920,11 +236909,11 @@ static void fts5PorterStep1A(char *aBuf, int *pnBuf){ } static int fts5PorterCb( - void *pCtx, + void *pCtx, int tflags, - const char *pToken, - int nToken, - int iStart, + const char *pToken, + int nToken, + int iStart, int iEnd ){ PorterContext *p = (PorterContext*)pCtx; @@ -199942,8 +236931,8 @@ static int fts5PorterCb( if( fts5PorterStep1B(aBuf, &nBuf) ){ if( fts5PorterStep1B2(aBuf, &nBuf)==0 ){ char c = aBuf[nBuf-1]; - if( fts5PorterIsVowel(c, 0)==0 - && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2] + if( fts5PorterIsVowel(c, 0)==0 + && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2] ){ nBuf--; }else if( fts5Porter_MEq1(aBuf, nBuf) && fts5Porter_Ostar(aBuf, nBuf) ){ @@ -199965,7 +236954,7 @@ static int fts5PorterCb( /* Step 5a. */ assert( nBuf>0 ); if( aBuf[nBuf-1]=='e' ){ - if( fts5Porter_MGt1(aBuf, nBuf-1) + if( fts5Porter_MGt1(aBuf, nBuf-1) || (fts5Porter_MEq1(aBuf, nBuf-1) && !fts5Porter_Ostar(aBuf, nBuf-1)) ){ nBuf--; @@ -199973,8 +236962,8 @@ static int fts5PorterCb( } /* Step 5b. */ - if( nBuf>1 && aBuf[nBuf-1]=='l' - && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1) + if( nBuf>1 && aBuf[nBuf-1]=='l' + && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1) ){ nBuf--; } @@ -200005,6 +236994,133 @@ static int fts5PorterTokenize( ); } +/************************************************************************** +** Start of trigram implementation. +*/ +typedef struct TrigramTokenizer TrigramTokenizer; +struct TrigramTokenizer { + int bFold; /* True to fold to lower-case */ +}; + +/* +** Free a trigram tokenizer. +*/ +static void fts5TriDelete(Fts5Tokenizer *p){ + sqlite3_free(p); +} + +/* +** Allocate a trigram tokenizer. +*/ +static int fts5TriCreate( + void *pUnused, + const char **azArg, + int nArg, + Fts5Tokenizer **ppOut +){ + int rc = SQLITE_OK; + TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); + UNUSED_PARAM(pUnused); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + int i; + pNew->bFold = 1; + for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0'); + } + }else{ + rc = SQLITE_ERROR; + } + } + if( rc!=SQLITE_OK ){ + fts5TriDelete((Fts5Tokenizer*)pNew); + pNew = 0; + } + } + *ppOut = (Fts5Tokenizer*)pNew; + return rc; +} + +/* +** Trigram tokenizer tokenize routine. +*/ +static int fts5TriTokenize( + Fts5Tokenizer *pTok, + void *pCtx, + int unusedFlags, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int, int, int) +){ + TrigramTokenizer *p = (TrigramTokenizer*)pTok; + int rc = SQLITE_OK; + char aBuf[32]; + const unsigned char *zIn = (const unsigned char*)pText; + const unsigned char *zEof = &zIn[nText]; + u32 iCode; + + UNUSED_PARAM(unusedFlags); + while( 1 ){ + char *zOut = aBuf; + int iStart = zIn - (const unsigned char*)pText; + const unsigned char *zNext; + + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + zNext = zIn; + if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + }else{ + break; + } + if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + }else{ + break; + } + rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf); + if( rc!=SQLITE_OK ) break; + zIn = zNext; + } + + return rc; +} + +/* +** Argument xCreate is a pointer to a constructor function for a tokenizer. +** pTok is a tokenizer previously created using the same method. This function +** returns one of FTS5_PATTERN_NONE, FTS5_PATTERN_LIKE or FTS5_PATTERN_GLOB +** indicating the style of pattern matching that the tokenizer can support. +** In practice, this is: +** +** "trigram" tokenizer, case_sensitive=1 - FTS5_PATTERN_GLOB +** "trigram" tokenizer, case_sensitive=0 (the default) - FTS5_PATTERN_LIKE +** all other tokenizers - FTS5_PATTERN_NONE +*/ +static int sqlite3Fts5TokenizerPattern( + int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), + Fts5Tokenizer *pTok +){ + if( xCreate==fts5TriCreate ){ + TrigramTokenizer *p = (TrigramTokenizer*)pTok; + return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; + } + return FTS5_PATTERN_NONE; +} + /* ** Register all built-in tokenizers with FTS5. */ @@ -200016,8 +237132,9 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, + { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}}, }; - + int rc = SQLITE_OK; /* Return code */ int i; /* To iterate through builtin functions */ @@ -200033,10 +237150,8 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ return rc; } - - /* -** 2012 May 25 +** 2012-05-25 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -200055,135 +237170,6 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ /* #include */ -/* -** Return true if the argument corresponds to a unicode codepoint -** classified as either a letter or a number. Otherwise false. -** -** The results are undefined if the value passed to this function -** is less than zero. -*/ -static int sqlite3Fts5UnicodeIsalnum(int c){ - /* Each unsigned integer in the following array corresponds to a contiguous - ** range of unicode codepoints that are not either letters or numbers (i.e. - ** codepoints for which this function should return 0). - ** - ** The most significant 22 bits in each 32-bit value contain the first - ** codepoint in the range. The least significant 10 bits are used to store - ** the size of the range (always at least 1). In other words, the value - ** ((C<<22) + N) represents a range of N codepoints starting with codepoint - ** C. It is not possible to represent a range larger than 1023 codepoints - ** using this format. - */ - static const unsigned int aEntry[] = { - 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07, - 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01, - 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401, - 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01, - 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01, - 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802, - 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F, - 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401, - 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804, - 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403, - 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812, - 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001, - 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802, - 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805, - 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401, - 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03, - 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807, - 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001, - 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01, - 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804, - 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001, - 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802, - 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01, - 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06, - 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007, - 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006, - 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417, - 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14, - 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07, - 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01, - 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001, - 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802, - 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F, - 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002, - 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802, - 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006, - 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D, - 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802, - 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027, - 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403, - 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805, - 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04, - 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401, - 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005, - 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B, - 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A, - 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001, - 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59, - 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807, - 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01, - 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E, - 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100, - 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10, - 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402, - 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804, - 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012, - 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004, - 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002, - 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803, - 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07, - 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02, - 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802, - 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013, - 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06, - 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003, - 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01, - 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403, - 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009, - 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003, - 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003, - 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E, - 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046, - 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401, - 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401, - 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F, - 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C, - 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002, - 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025, - 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6, - 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46, - 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060, - 0x380400F0, - }; - static const unsigned int aAscii[4] = { - 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001, - }; - - if( (unsigned int)c<128 ){ - return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 ); - }else if( (unsigned int)c<(1<<22) ){ - unsigned int key = (((unsigned int)c)<<10) | 0x000003FF; - int iRes = 0; - int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1; - int iLo = 0; - while( iHi>=iLo ){ - int iTest = (iHi + iLo) / 2; - if( key >= aEntry[iTest] ){ - iRes = iTest; - iLo = iTest+1; - }else{ - iHi = iTest-1; - } - } - assert( aEntry[0]=aEntry[iRes] ); - return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF))); - } - return 1; -} /* @@ -200194,32 +237180,48 @@ static int sqlite3Fts5UnicodeIsalnum(int c){ ** E"). The resuls of passing a codepoint that corresponds to an ** uppercase letter are undefined. */ -static int fts5_remove_diacritic(int c){ +static int fts5_remove_diacritic(int c, int bComplex){ unsigned short aDia[] = { - 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, - 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, - 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, - 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, - 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928, - 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234, - 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504, - 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529, - 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, - 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, - 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, - 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, - 62924, 63050, 63082, 63274, 63390, + 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995, + 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286, + 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732, + 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336, + 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896, + 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106, + 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344, + 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198, + 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468, + 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704, + 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914, + 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218, + 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554, + 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766, + 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118, + 63182, 63242, 63274, 63310, 63368, 63390, }; - char aChar[] = { - '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c', - 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r', - 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o', - 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r', - 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h', - 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't', - 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a', - 'e', 'i', 'o', 'u', 'y', +#define HIBIT ((unsigned char)0x80) + unsigned char aChar[] = { + '\0', 'a', 'c', 'e', 'i', 'n', + 'o', 'u', 'y', 'y', 'a', 'c', + 'd', 'e', 'e', 'g', 'h', 'i', + 'j', 'k', 'l', 'n', 'o', 'r', + 's', 't', 'u', 'u', 'w', 'y', + 'z', 'o', 'u', 'a', 'i', 'o', + 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o', + 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a', + 'e', 'i', 'o', 'r', 'u', 's', + 't', 'h', 'a', 'e', 'o'|HIBIT, 'o', + 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', 'a', 'b', + 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT, + 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT, + 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n', + 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's', + 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w', + 'w', 'x', 'y', 'z', 'h', 't', + 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT, + 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT, + 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y', }; unsigned int key = (((unsigned int)c)<<3) | 0x00000007; @@ -200236,7 +237238,8 @@ static int fts5_remove_diacritic(int c){ } } assert( key>=aDia[iRes] ); - return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]); + if( bComplex==0 && (aChar[iRes] & 0x80) ) return c; + return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F); } @@ -200249,8 +237252,8 @@ static int sqlite3Fts5UnicodeIsdiacritic(int c){ unsigned int mask1 = 0x000361F8; if( c<768 || c>817 ) return 0; return (c < 768+32) ? - (mask0 & (1 << (c-768))) : - (mask1 & (1 << (c-768-32))); + (mask0 & ((unsigned int)1 << (c-768))) : + (mask1 & ((unsigned int)1 << (c-768-32))); } @@ -200263,7 +237266,7 @@ static int sqlite3Fts5UnicodeIsdiacritic(int c){ ** The results are undefined if the value passed to this function ** is less than zero. */ -static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ +static int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){ /* Each entry in the following array defines a rule for folding a range ** of codepoints to lower case. The rule applies to a range of nRange ** codepoints starting at codepoint iCode. @@ -200340,19 +237343,19 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ {42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1}, {42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1}, {42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1}, - {65313, 14, 26}, + {65313, 14, 26}, }; static const unsigned short aiOff[] = { - 1, 2, 8, 15, 16, 26, 28, 32, - 37, 38, 40, 48, 63, 64, 69, 71, - 79, 80, 116, 202, 203, 205, 206, 207, - 209, 210, 211, 213, 214, 217, 218, 219, - 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, - 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, - 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, - 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, - 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, - 65514, 65521, 65527, 65528, 65529, + 1, 2, 8, 15, 16, 26, 28, 32, + 37, 38, 40, 48, 63, 64, 69, 71, + 79, 80, 116, 202, 203, 205, 206, 207, + 209, 210, 211, 213, 214, 217, 218, 219, + 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721, + 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, + 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, + 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, + 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, + 65514, 65521, 65527, 65528, 65529, }; int ret = c; @@ -200386,9 +237389,11 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ assert( ret>0 ); } - if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret); + if( eRemoveDiacritic ){ + ret = fts5_remove_diacritic(ret, eRemoveDiacritic==2); + } } - + else if( c>=66560 && c<66600 ){ ret = c + 40; } @@ -200396,6 +237401,534 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){ return ret; } + +static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ + aArray[0] = 1; + switch( zCat[0] ){ + case 'C': + switch( zCat[1] ){ + case 'c': aArray[1] = 1; break; + case 'f': aArray[2] = 1; break; + case 'n': aArray[3] = 1; break; + case 's': aArray[4] = 1; break; + case 'o': aArray[31] = 1; break; + case '*': + aArray[1] = 1; + aArray[2] = 1; + aArray[3] = 1; + aArray[4] = 1; + aArray[31] = 1; + break; + default: return 1; } + break; + + case 'L': + switch( zCat[1] ){ + case 'l': aArray[5] = 1; break; + case 'm': aArray[6] = 1; break; + case 'o': aArray[7] = 1; break; + case 't': aArray[8] = 1; break; + case 'u': aArray[9] = 1; break; + case 'C': aArray[30] = 1; break; + case '*': + aArray[5] = 1; + aArray[6] = 1; + aArray[7] = 1; + aArray[8] = 1; + aArray[9] = 1; + aArray[30] = 1; + break; + default: return 1; } + break; + + case 'M': + switch( zCat[1] ){ + case 'c': aArray[10] = 1; break; + case 'e': aArray[11] = 1; break; + case 'n': aArray[12] = 1; break; + case '*': + aArray[10] = 1; + aArray[11] = 1; + aArray[12] = 1; + break; + default: return 1; } + break; + + case 'N': + switch( zCat[1] ){ + case 'd': aArray[13] = 1; break; + case 'l': aArray[14] = 1; break; + case 'o': aArray[15] = 1; break; + case '*': + aArray[13] = 1; + aArray[14] = 1; + aArray[15] = 1; + break; + default: return 1; } + break; + + case 'P': + switch( zCat[1] ){ + case 'c': aArray[16] = 1; break; + case 'd': aArray[17] = 1; break; + case 'e': aArray[18] = 1; break; + case 'f': aArray[19] = 1; break; + case 'i': aArray[20] = 1; break; + case 'o': aArray[21] = 1; break; + case 's': aArray[22] = 1; break; + case '*': + aArray[16] = 1; + aArray[17] = 1; + aArray[18] = 1; + aArray[19] = 1; + aArray[20] = 1; + aArray[21] = 1; + aArray[22] = 1; + break; + default: return 1; } + break; + + case 'S': + switch( zCat[1] ){ + case 'c': aArray[23] = 1; break; + case 'k': aArray[24] = 1; break; + case 'm': aArray[25] = 1; break; + case 'o': aArray[26] = 1; break; + case '*': + aArray[23] = 1; + aArray[24] = 1; + aArray[25] = 1; + aArray[26] = 1; + break; + default: return 1; } + break; + + case 'Z': + switch( zCat[1] ){ + case 'l': aArray[27] = 1; break; + case 'p': aArray[28] = 1; break; + case 's': aArray[29] = 1; break; + case '*': + aArray[27] = 1; + aArray[28] = 1; + aArray[29] = 1; + break; + default: return 1; } + break; + + } + return 0; +} + +static u16 aFts5UnicodeBlock[] = { + 0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760, + 1760, 1760, 1760, 1760, 1760, 1763, 1765, + }; +static u16 aFts5UnicodeMap[] = { + 0, 32, 33, 36, 37, 40, 41, 42, 43, 44, + 45, 46, 48, 58, 60, 63, 65, 91, 92, 93, + 94, 95, 96, 97, 123, 124, 125, 126, 127, 160, + 161, 162, 166, 167, 168, 169, 170, 171, 172, 173, + 174, 175, 176, 177, 178, 180, 181, 182, 184, 185, + 186, 187, 188, 191, 192, 215, 216, 223, 247, 248, + 256, 312, 313, 329, 330, 377, 383, 385, 387, 388, + 391, 394, 396, 398, 402, 403, 405, 406, 409, 412, + 414, 415, 417, 418, 423, 427, 428, 431, 434, 436, + 437, 440, 442, 443, 444, 446, 448, 452, 453, 454, + 455, 456, 457, 458, 459, 460, 461, 477, 478, 496, + 497, 498, 499, 500, 503, 505, 506, 564, 570, 572, + 573, 575, 577, 580, 583, 584, 592, 660, 661, 688, + 706, 710, 722, 736, 741, 748, 749, 750, 751, 768, + 880, 884, 885, 886, 890, 891, 894, 900, 902, 903, + 904, 908, 910, 912, 913, 931, 940, 975, 977, 978, + 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072, + 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369, + 1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473, + 1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545, + 1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611, + 1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758, + 1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791, + 1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984, + 1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075, + 2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210, + 2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369, + 2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416, + 2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482, + 2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519, + 2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561, + 2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622, + 2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677, + 2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749, + 2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790, + 2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869, + 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902, + 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947, + 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006, + 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059, + 3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134, + 3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199, + 3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263, + 3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302, + 3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402, + 3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458, + 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544, + 3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655, + 3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737, + 3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773, + 3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860, + 3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896, + 3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967, + 3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046, + 4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153, + 4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190, + 4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229, + 4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295, + 4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704, + 4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888, + 4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743, + 5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906, + 5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068, + 6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107, + 6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160, + 6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435, + 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480, + 6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679, + 6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754, + 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824, + 6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978, + 6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043, + 7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098, + 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168, + 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288, + 7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406, + 7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616, + 7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976, + 7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033, + 8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118, + 8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141, + 8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184, + 8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219, + 8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249, + 8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275, + 8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317, + 8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413, + 8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459, + 8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484, + 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500, + 8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523, + 8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597, + 8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623, + 8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972, + 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180, + 9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665, + 9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091, + 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101, + 10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217, + 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627, + 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637, + 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647, + 10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750, + 11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365, + 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393, + 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520, + 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696, + 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780, + 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800, + 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812, + 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904, + 11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296, + 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306, + 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317, + 12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347, + 12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449, + 12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736, + 12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938, + 12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981, + 40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528, + 42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624, + 42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800, + 42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912, + 43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043, + 43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136, + 43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264, + 43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395, + 43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472, + 43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588, + 43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643, + 43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713, + 43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762, + 43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003, + 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203, + 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112, + 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320, + 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020, + 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075, + 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086, + 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097, + 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118, + 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279, + 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294, + 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343, + 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378, + 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490, + 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529, + 65532, 0, 13, 40, 60, 63, 80, 128, 256, 263, + 311, 320, 373, 377, 394, 400, 464, 509, 640, 672, + 768, 800, 816, 833, 834, 842, 896, 927, 928, 968, + 976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103, + 2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432, + 2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623, + 2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912, + 2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178, + 4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285, + 4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416, + 4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760, + 5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216, + 9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248, + 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637, + 53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298, + 54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441, + 54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541, + 54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662, + 54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922, + 54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062, + 55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178, + 55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961, + 60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003, + 61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028, + 61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099, + 61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744, + 61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368, + 62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971, + 63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488, + 1, 32, 256, 0, 65533, + }; +static u16 aFts5UnicodeData[] = { + 1025, 61, 117, 55, 117, 54, 50, 53, 57, 53, + 49, 85, 333, 85, 121, 85, 841, 54, 53, 50, + 56, 48, 56, 837, 54, 57, 50, 57, 1057, 61, + 53, 151, 58, 53, 56, 58, 39, 52, 57, 34, + 58, 56, 58, 57, 79, 56, 37, 85, 56, 47, + 39, 51, 111, 53, 745, 57, 233, 773, 57, 261, + 1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126, + 126, 73, 69, 137, 37, 73, 37, 105, 101, 73, + 37, 73, 37, 190, 158, 37, 126, 126, 73, 37, + 126, 94, 37, 39, 94, 69, 135, 41, 40, 37, + 41, 40, 37, 41, 40, 37, 542, 37, 606, 37, + 41, 40, 37, 126, 73, 37, 1886, 197, 73, 37, + 73, 69, 126, 105, 37, 286, 2181, 39, 869, 582, + 152, 390, 472, 166, 248, 38, 56, 38, 568, 3596, + 158, 38, 56, 94, 38, 101, 53, 88, 41, 53, + 105, 41, 73, 37, 553, 297, 1125, 94, 37, 105, + 101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541, + 1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38, + 213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76, + 53, 76, 53, 44, 871, 103, 85, 162, 121, 85, + 55, 85, 90, 364, 53, 85, 1031, 38, 327, 684, + 333, 149, 71, 44, 3175, 53, 39, 236, 34, 58, + 204, 70, 76, 58, 140, 71, 333, 103, 90, 39, + 469, 34, 39, 44, 967, 876, 2855, 364, 39, 333, + 1063, 300, 70, 58, 117, 38, 711, 140, 38, 300, + 38, 108, 38, 172, 501, 807, 108, 53, 39, 359, + 876, 108, 42, 1735, 44, 42, 44, 39, 106, 268, + 138, 44, 74, 39, 236, 327, 76, 85, 333, 53, + 38, 199, 231, 44, 74, 263, 71, 711, 231, 39, + 135, 44, 39, 106, 140, 74, 74, 44, 39, 42, + 71, 103, 76, 333, 71, 87, 207, 58, 55, 76, + 42, 199, 71, 711, 231, 71, 71, 71, 44, 106, + 76, 76, 108, 44, 135, 39, 333, 76, 103, 44, + 76, 42, 295, 103, 711, 231, 71, 167, 44, 39, + 106, 172, 76, 42, 74, 44, 39, 71, 76, 333, + 53, 55, 44, 74, 263, 71, 711, 231, 71, 167, + 44, 39, 42, 44, 42, 140, 74, 74, 44, 44, + 42, 71, 103, 76, 333, 58, 39, 207, 44, 39, + 199, 103, 135, 71, 39, 71, 71, 103, 391, 74, + 44, 74, 106, 106, 44, 39, 42, 333, 111, 218, + 55, 58, 106, 263, 103, 743, 327, 167, 39, 108, + 138, 108, 140, 76, 71, 71, 76, 333, 239, 58, + 74, 263, 103, 743, 327, 167, 44, 39, 42, 44, + 170, 44, 74, 74, 76, 74, 39, 71, 76, 333, + 71, 74, 263, 103, 1319, 39, 106, 140, 106, 106, + 44, 39, 42, 71, 76, 333, 207, 58, 199, 74, + 583, 775, 295, 39, 231, 44, 106, 108, 44, 266, + 74, 53, 1543, 44, 71, 236, 55, 199, 38, 268, + 53, 333, 85, 71, 39, 71, 39, 39, 135, 231, + 103, 39, 39, 71, 135, 44, 71, 204, 76, 39, + 167, 38, 204, 333, 135, 39, 122, 501, 58, 53, + 122, 76, 218, 333, 335, 58, 44, 58, 44, 58, + 44, 54, 50, 54, 50, 74, 263, 1159, 460, 42, + 172, 53, 76, 167, 364, 1164, 282, 44, 218, 90, + 181, 154, 85, 1383, 74, 140, 42, 204, 42, 76, + 74, 76, 39, 333, 213, 199, 74, 76, 135, 108, + 39, 106, 71, 234, 103, 140, 423, 44, 74, 76, + 202, 44, 39, 42, 333, 106, 44, 90, 1225, 41, + 41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319, + 135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151, + 108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551, + 61, 839, 54, 50, 2407, 117, 110, 423, 135, 108, + 583, 108, 85, 583, 76, 423, 103, 76, 1671, 76, + 42, 236, 266, 44, 74, 364, 117, 38, 117, 55, + 39, 44, 333, 335, 213, 49, 149, 108, 61, 333, + 1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138, + 76, 106, 74, 44, 202, 108, 58, 85, 333, 967, + 167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76, + 106, 85, 1703, 42, 44, 42, 236, 44, 42, 44, + 74, 268, 202, 332, 44, 333, 333, 245, 38, 213, + 140, 42, 1511, 44, 42, 172, 42, 44, 170, 44, + 74, 231, 333, 245, 346, 300, 314, 76, 42, 967, + 42, 140, 74, 76, 42, 44, 74, 71, 333, 1415, + 44, 42, 76, 106, 44, 42, 108, 74, 149, 1159, + 266, 268, 74, 76, 181, 333, 103, 333, 967, 198, + 85, 277, 108, 53, 428, 42, 236, 135, 44, 135, + 74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260, + 140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265, + 261, 265, 197, 201, 261, 41, 41, 41, 94, 229, + 265, 453, 261, 264, 261, 264, 261, 264, 165, 69, + 137, 40, 56, 37, 120, 101, 69, 137, 40, 120, + 133, 69, 137, 120, 261, 169, 120, 101, 69, 137, + 40, 88, 381, 162, 209, 85, 52, 51, 54, 84, + 51, 54, 52, 277, 59, 60, 162, 61, 309, 52, + 51, 149, 80, 117, 57, 54, 50, 373, 57, 53, + 48, 341, 61, 162, 194, 47, 38, 207, 121, 54, + 50, 38, 335, 121, 54, 50, 422, 855, 428, 139, + 44, 107, 396, 90, 41, 154, 41, 90, 37, 105, + 69, 105, 37, 58, 41, 90, 57, 169, 218, 41, + 58, 41, 58, 41, 58, 137, 58, 37, 137, 37, + 135, 37, 90, 69, 73, 185, 94, 101, 58, 57, + 90, 37, 58, 527, 1134, 94, 142, 47, 185, 186, + 89, 154, 57, 90, 57, 90, 57, 250, 57, 1018, + 89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666, + 89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217, + 602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57, + 1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50, + 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, + 975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50, + 54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54, + 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, + 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, + 50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281, + 1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69, + 254, 105, 37, 94, 37, 94, 165, 70, 105, 37, + 3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221, + 37, 37, 1799, 38, 53, 44, 743, 231, 231, 231, + 231, 231, 231, 231, 231, 1036, 85, 52, 51, 52, + 51, 117, 52, 51, 53, 52, 51, 309, 49, 85, + 49, 53, 52, 51, 85, 52, 51, 54, 50, 54, + 50, 54, 50, 54, 50, 181, 38, 341, 81, 858, + 2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54, + 50, 54, 50, 54, 50, 54, 50, 54, 50, 90, + 54, 50, 54, 50, 54, 50, 54, 50, 49, 54, + 82, 58, 302, 140, 74, 49, 166, 90, 110, 38, + 39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887, + 53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178, + 519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274, + 495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38, + 36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333, + 71, 1502, 39, 44, 107, 53, 332, 53, 38, 798, + 44, 2247, 334, 76, 213, 760, 294, 88, 478, 69, + 2014, 38, 261, 190, 350, 38, 88, 158, 158, 382, + 70, 37, 231, 44, 103, 44, 135, 44, 743, 74, + 76, 42, 154, 207, 90, 55, 58, 1671, 149, 74, + 1607, 522, 44, 85, 333, 588, 199, 117, 39, 333, + 903, 268, 85, 743, 364, 74, 53, 935, 108, 42, + 1511, 44, 74, 140, 74, 44, 138, 437, 38, 333, + 85, 1319, 204, 74, 76, 74, 76, 103, 44, 263, + 44, 42, 333, 149, 519, 38, 199, 122, 39, 42, + 1543, 44, 39, 108, 71, 76, 167, 76, 39, 44, + 39, 71, 38, 85, 359, 42, 76, 74, 85, 39, + 70, 42, 44, 199, 199, 199, 231, 231, 1127, 74, + 44, 74, 44, 74, 53, 42, 44, 333, 39, 39, + 743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399, + 229, 165, 39, 44, 327, 57, 423, 167, 39, 71, + 71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55, + 58, 524, 245, 54, 50, 53, 236, 53, 81, 80, + 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, + 54, 50, 54, 50, 54, 50, 85, 54, 50, 149, + 112, 117, 149, 49, 54, 50, 54, 50, 54, 50, + 117, 57, 49, 121, 53, 55, 85, 167, 4327, 34, + 117, 55, 117, 54, 50, 53, 57, 53, 49, 85, + 333, 85, 121, 85, 841, 54, 53, 50, 56, 48, + 56, 837, 54, 57, 50, 57, 54, 50, 53, 54, + 50, 85, 327, 38, 1447, 70, 999, 199, 199, 199, + 103, 87, 57, 56, 58, 87, 58, 153, 90, 98, + 90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455, + 314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575, + 999, 143, 551, 46, 263, 46, 967, 53, 1159, 263, + 53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71, + 39, 743, 53, 271, 711, 207, 53, 839, 53, 1799, + 71, 39, 108, 76, 140, 135, 103, 871, 108, 44, + 271, 309, 935, 79, 53, 1735, 245, 711, 271, 615, + 271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655, + 333, 76, 42, 1447, 106, 140, 74, 76, 85, 34, + 149, 807, 333, 108, 1159, 172, 42, 268, 333, 149, + 76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383, + 44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182, + 149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898, + 1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236, + 986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837, + 841, 229, 581, 841, 837, 41, 73, 41, 73, 137, + 265, 133, 37, 229, 357, 841, 837, 73, 137, 265, + 233, 837, 73, 137, 169, 41, 233, 837, 841, 837, + 841, 837, 841, 837, 841, 837, 841, 837, 841, 901, + 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, + 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, + 809, 57, 805, 57, 197, 94, 1613, 135, 871, 71, + 39, 39, 327, 135, 39, 39, 39, 39, 39, 39, + 103, 71, 39, 39, 39, 39, 39, 39, 71, 39, + 135, 231, 135, 135, 39, 327, 551, 103, 167, 551, + 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946, + 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210, + 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266, + 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351, + 34, 3074, 7692, 63, 63, + }; + +static int sqlite3Fts5UnicodeCategory(u32 iCode) { + int iRes = -1; + int iHi; + int iLo; + int ret; + u16 iKey; + + if( iCode>=(1<<20) ){ + return 0; + } + iLo = aFts5UnicodeBlock[(iCode>>16)]; + iHi = aFts5UnicodeBlock[1+(iCode>>16)]; + iKey = (iCode & 0xFFFF); + while( iHi>iLo ){ + int iTest = (iHi + iLo) / 2; + assert( iTest>=iLo && iTest=aFts5UnicodeMap[iTest] ){ + iRes = iTest; + iLo = iTest+1; + }else{ + iHi = iTest; + } + } + + if( iRes<0 ) return 0; + if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0; + ret = aFts5UnicodeData[iRes] & 0x1F; + if( ret!=30 ) return ret; + return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? 5 : 9; +} + +static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ + int i = 0; + int iTbl = 0; + while( i<128 ){ + int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; + int n = (aFts5UnicodeData[iTbl] >> 5) + i; + for(; i<128 && i3 && n<=9 ); return n; } @@ -200702,7 +238235,7 @@ static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){ v >>= 7; } return 9; - } + } n = 0; do{ buf[n++] = (u8)((v & 0x7f) | 0x80); @@ -200741,7 +238274,6 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){ return 5; } - /* ** 2015 May 08 ** @@ -200755,7 +238287,7 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){ ****************************************************************************** ** ** This is an SQLite virtual table module implementing direct access to an -** existing FTS5 index. The module may create several different types of +** existing FTS5 index. The module may create several different types of ** tables: ** ** col: @@ -200763,16 +238295,21 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){ ** ** One row for each term/column combination. The value of $doc is set to ** the number of fts5 rows that contain at least one instance of term -** $term within column $col. Field $cnt is set to the total number of -** instances of term $term in column $col (in any row of the fts5 table). +** $term within column $col. Field $cnt is set to the total number of +** instances of term $term in column $col (in any row of the fts5 table). ** ** row: ** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term)); ** ** One row for each term in the database. The value of $doc is set to ** the number of fts5 rows that contain at least one instance of term -** $term. Field $cnt is set to the total number of instances of term +** $term. Field $cnt is set to the total number of instances of term ** $term in the database. +** +** instance: +** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY()); +** +** One row for each term instance in the database. */ @@ -200788,36 +238325,43 @@ struct Fts5VocabTable { char *zFts5Db; /* Db containing fts5 table */ sqlite3 *db; /* Database handle */ Fts5Global *pGlobal; /* FTS5 global object for this database */ - int eType; /* FTS5_VOCAB_COL or ROW */ + int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */ + unsigned bBusy; /* True if busy */ }; struct Fts5VocabCursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */ - Fts5Index *pIndex; /* Associated FTS5 index */ + Fts5Table *pFts5; /* Associated FTS5 table */ int bEof; /* True if this cursor is at EOF */ Fts5IndexIter *pIter; /* Term/rowid iterator object */ + void *pStruct; /* From sqlite3Fts5StructureRef() */ int nLeTerm; /* Size of zLeTerm in bytes */ char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */ /* These are used by 'col' tables only */ - Fts5Config *pConfig; /* Fts5 table configuration */ int iCol; i64 *aCnt; i64 *aDoc; - /* Output values used by 'row' and 'col' tables */ + /* Output values used by all tables. */ i64 rowid; /* This table's current rowid value */ Fts5Buffer term; /* Current value of 'term' column */ + + /* Output values Used by 'instance' tables only */ + i64 iInstPos; + int iInstOff; }; -#define FTS5_VOCAB_COL 0 -#define FTS5_VOCAB_ROW 1 +#define FTS5_VOCAB_COL 0 +#define FTS5_VOCAB_ROW 1 +#define FTS5_VOCAB_INSTANCE 2 #define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt" #define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt" +#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset" /* ** Bits for the mask used as the idxNum value by xBestIndex/xFilter. @@ -200828,7 +238372,7 @@ struct Fts5VocabCursor { /* -** Translate a string containing an fts5vocab table type to an +** Translate a string containing an fts5vocab table type to an ** FTS5_VOCAB_XXX constant. If successful, set *peType to the output ** value and return SQLITE_OK. Otherwise, set *pzErr to an error message ** and return SQLITE_ERROR. @@ -200845,6 +238389,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){ if( sqlite3_stricmp(zCopy, "row")==0 ){ *peType = FTS5_VOCAB_ROW; }else + if( sqlite3_stricmp(zCopy, "instance")==0 ){ + *peType = FTS5_VOCAB_INSTANCE; + }else { *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy); rc = SQLITE_ERROR; @@ -200903,9 +238450,10 @@ static int fts5VocabInitVtab( sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ - const char *azSchema[] = { - "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")", - "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")" + const char *azSchema[] = { + "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")", + "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")", + "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")" }; Fts5VocabTable *pRet = 0; @@ -200922,10 +238470,10 @@ static int fts5VocabInitVtab( const char *zDb = bDb ? argv[3] : argv[1]; const char *zTab = bDb ? argv[4] : argv[3]; const char *zType = bDb ? argv[5] : argv[4]; - int nDb = (int)strlen(zDb)+1; + int nDb = (int)strlen(zDb)+1; int nTab = (int)strlen(zTab)+1; int eType = 0; - + rc = fts5VocabTableType(zType, pzErr, &eType); if( rc==SQLITE_OK ){ assert( eType>=0 && eType= ? +** +** are interpreted. Less-than and less-than-or-equal are treated +** identically, as are greater-than and greater-than-or-equal. */ static int fts5VocabBestIndexMethod( sqlite3_vtab *pUnused, @@ -201028,8 +238585,8 @@ static int fts5VocabBestIndexMethod( ** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the ** sqlite3_index_info.orderByConsumed flag to tell the core the results ** are already in sorted order. */ - if( pInfo->nOrderBy==1 - && pInfo->aOrderBy[0].iColumn==0 + if( pInfo->nOrderBy==1 + && pInfo->aOrderBy[0].iColumn==0 && pInfo->aOrderBy[0].desc==0 ){ pInfo->orderByConsumed = 1; @@ -201043,17 +238600,22 @@ static int fts5VocabBestIndexMethod( ** Implementation of xOpen method. */ static int fts5VocabOpenMethod( - sqlite3_vtab *pVTab, + sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr ){ Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; - Fts5Index *pIndex = 0; - Fts5Config *pConfig = 0; + Fts5Table *pFts5 = 0; Fts5VocabCursor *pCsr = 0; int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; char *zSql = 0; + if( pTab->bBusy ){ + pVTab->zErrMsg = sqlite3_mprintf( + "recursive definition for %s.%s", pTab->zFts5Db, pTab->zFts5Tbl + ); + return SQLITE_ERROR; + } zSql = sqlite3Fts5Mprintf(&rc, "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'", pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl @@ -201065,33 +238627,38 @@ static int fts5VocabOpenMethod( assert( rc==SQLITE_OK || pStmt==0 ); if( rc==SQLITE_ERROR ) rc = SQLITE_OK; + pTab->bBusy = 1; if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ i64 iId = sqlite3_column_int64(pStmt, 0); - pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig); + pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId); } + pTab->bBusy = 0; - if( rc==SQLITE_OK && pIndex==0 ){ - rc = sqlite3_finalize(pStmt); - pStmt = 0; - if( rc==SQLITE_OK ){ - pVTab->zErrMsg = sqlite3_mprintf( - "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl - ); - rc = SQLITE_ERROR; + if( rc==SQLITE_OK ){ + if( pFts5==0 ){ + rc = sqlite3_finalize(pStmt); + pStmt = 0; + if( rc==SQLITE_OK ){ + pVTab->zErrMsg = sqlite3_mprintf( + "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl + ); + rc = SQLITE_ERROR; + } + }else{ + rc = sqlite3Fts5FlushToDisk(pFts5); } } if( rc==SQLITE_OK ){ - int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor); + i64 nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor); pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte); } if( pCsr ){ - pCsr->pIndex = pIndex; + pCsr->pFts5 = pFts5; pCsr->pStmt = pStmt; - pCsr->pConfig = pConfig; pCsr->aCnt = (i64*)&pCsr[1]; - pCsr->aDoc = &pCsr->aCnt[pConfig->nCol]; + pCsr->aDoc = &pCsr->aCnt[pFts5->pConfig->nCol]; }else{ sqlite3_finalize(pStmt); } @@ -201103,10 +238670,13 @@ static int fts5VocabOpenMethod( static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){ pCsr->rowid = 0; sqlite3Fts5IterClose(pCsr->pIter); + sqlite3Fts5StructureRelease(pCsr->pStruct); + pCsr->pStruct = 0; pCsr->pIter = 0; sqlite3_free(pCsr->zLeTerm); pCsr->nLeTerm = -1; pCsr->zLeTerm = 0; + pCsr->bEof = 0; } /* @@ -201122,6 +238692,56 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){ return SQLITE_OK; } +static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){ + int rc = SQLITE_OK; + + if( sqlite3Fts5IterEof(pCsr->pIter) ){ + pCsr->bEof = 1; + }else{ + const char *zTerm; + int nTerm; + zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + if( pCsr->nLeTerm>=0 ){ + int nCmp = MIN(nTerm, pCsr->nLeTerm); + int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); + if( bCmp<0 || (bCmp==0 && pCsr->nLeTermbEof = 1; + } + } + + sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm); + } + return rc; +} + +static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){ + int eDetail = pCsr->pFts5->pConfig->eDetail; + int rc = SQLITE_OK; + Fts5IndexIter *pIter = pCsr->pIter; + i64 *pp = &pCsr->iInstPos; + int *po = &pCsr->iInstOff; + + assert( sqlite3Fts5IterEof(pIter)==0 ); + assert( pCsr->bEof==0 ); + while( eDetail==FTS5_DETAIL_NONE + || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp) + ){ + pCsr->iInstPos = 0; + pCsr->iInstOff = 0; + + rc = sqlite3Fts5IterNextScan(pCsr->pIter); + if( rc==SQLITE_OK ){ + rc = fts5VocabInstanceNewTerm(pCsr); + if( pCsr->bEof || eDetail==FTS5_DETAIL_NONE ) break; + } + if( rc ){ + pCsr->bEof = 1; + break; + } + } + + return rc; +} /* ** Advance the cursor to the next row in the table. @@ -201129,18 +238749,24 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; - int rc = SQLITE_OK; - int nCol = pCsr->pConfig->nCol; + int nCol = pCsr->pFts5->pConfig->nCol; + int rc; + rc = sqlite3Fts5StructureTest(pCsr->pFts5->pIndex, pCsr->pStruct); + if( rc!=SQLITE_OK ) return rc; pCsr->rowid++; + if( pTab->eType==FTS5_VOCAB_INSTANCE ){ + return fts5VocabInstanceNext(pCsr); + } + if( pTab->eType==FTS5_VOCAB_COL ){ for(pCsr->iCol++; pCsr->iColiCol++){ if( pCsr->aDoc[pCsr->iCol] ) break; } } - if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){ + if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){ if( sqlite3Fts5IterEof(pCsr->pIter) ){ pCsr->bEof = 1; }else{ @@ -201148,6 +238774,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ int nTerm; zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); + assert( nTerm>=0 ); if( pCsr->nLeTerm>=0 ){ int nCmp = MIN(nTerm, pCsr->nLeTerm); int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp); @@ -201164,26 +238791,29 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW ); while( rc==SQLITE_OK ){ + int eDetail = pCsr->pFts5->pConfig->eDetail; const u8 *pPos; int nPos; /* Position list */ i64 iPos = 0; /* 64-bit position read from poslist */ int iOff = 0; /* Current offset within position list */ pPos = pCsr->pIter->pData; nPos = pCsr->pIter->nData; - switch( pCsr->pConfig->eDetail ){ - case FTS5_DETAIL_FULL: - pPos = pCsr->pIter->pData; - nPos = pCsr->pIter->nData; - if( pTab->eType==FTS5_VOCAB_ROW ){ + + switch( pTab->eType ){ + case FTS5_VOCAB_ROW: + if( eDetail==FTS5_DETAIL_FULL ){ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ pCsr->aCnt[0]++; } - pCsr->aDoc[0]++; - }else{ + } + pCsr->aDoc[0]++; + break; + + case FTS5_VOCAB_COL: + if( eDetail==FTS5_DETAIL_FULL ){ int iCol = -1; while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ int ii = FTS5_POS2COLUMN(iPos); - pCsr->aCnt[ii]++; if( iCol!=ii ){ if( ii>=nCol ){ rc = FTS5_CORRUPT; @@ -201192,14 +238822,9 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ pCsr->aDoc[ii]++; iCol = ii; } + pCsr->aCnt[ii]++; } - } - break; - - case FTS5_DETAIL_COLUMNS: - if( pTab->eType==FTS5_VOCAB_ROW ){ - pCsr->aDoc[0]++; - }else{ + }else if( eDetail==FTS5_DETAIL_COLUMNS ){ while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){ assert_nc( iPos>=0 && iPos=nCol ){ @@ -201208,22 +238833,27 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ } pCsr->aDoc[iPos]++; } + }else{ + assert( eDetail==FTS5_DETAIL_NONE ); + pCsr->aDoc[0]++; } break; - default: - assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE ); - pCsr->aDoc[0]++; + default: + assert( pTab->eType==FTS5_VOCAB_INSTANCE ); break; } if( rc==SQLITE_OK ){ rc = sqlite3Fts5IterNextScan(pCsr->pIter); } + if( pTab->eType==FTS5_VOCAB_INSTANCE ) break; if( rc==SQLITE_OK ){ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm); - if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){ + if( nTerm!=pCsr->term.n + || (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm)) + ){ break; } if( sqlite3Fts5IterEof(pCsr->pIter) ) break; @@ -201233,8 +238863,10 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ } if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ - while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; - assert( pCsr->iColpConfig->nCol ); + for(/* noop */; pCsr->iColaDoc[pCsr->iCol]==0; pCsr->iCol++); + if( pCsr->iCol==nCol ){ + rc = FTS5_CORRUPT; + } } return rc; } @@ -201249,7 +238881,9 @@ static int fts5VocabFilterMethod( int nUnused, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ + Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab; Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; + int eType = pTab->eType; int rc = SQLITE_OK; int iVal = 0; @@ -201279,6 +238913,7 @@ static int fts5VocabFilterMethod( } if( pLe ){ const char *zCopy = (const char *)sqlite3_value_text(pLe); + if( zCopy==0 ) zCopy = ""; pCsr->nLeTerm = sqlite3_value_bytes(pLe); pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ @@ -201289,19 +238924,28 @@ static int fts5VocabFilterMethod( } } - if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); + Fts5Index *pIndex = pCsr->pFts5->pIndex; + rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); + if( rc==SQLITE_OK ){ + pCsr->pStruct = sqlite3Fts5StructureRef(pIndex); + } } - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){ + rc = fts5VocabInstanceNewTerm(pCsr); + } + if( rc==SQLITE_OK && !pCsr->bEof + && (eType!=FTS5_VOCAB_INSTANCE + || pCsr->pFts5->pConfig->eDetail!=FTS5_DETAIL_NONE) + ){ rc = fts5VocabNextMethod(pCursor); } return rc; } -/* -** This is the xEof method of the virtual table. SQLite calls this +/* +** This is the xEof method of the virtual table. SQLite calls this ** routine to find out if it has reached the end of a result set. */ static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){ @@ -201315,7 +238959,7 @@ static int fts5VocabColumnMethod( int iCol /* Index of column to read value from */ ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; - int eDetail = pCsr->pConfig->eDetail; + int eDetail = pCsr->pFts5->pConfig->eDetail; int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType; i64 iVal = 0; @@ -201327,7 +238971,7 @@ static int fts5VocabColumnMethod( assert( iCol==1 || iCol==2 || iCol==3 ); if( iCol==1 ){ if( eDetail!=FTS5_DETAIL_NONE ){ - const char *z = pCsr->pConfig->azCol[pCsr->iCol]; + const char *z = pCsr->pFts5->pConfig->azCol[pCsr->iCol]; sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); } }else if( iCol==2 ){ @@ -201335,26 +238979,54 @@ static int fts5VocabColumnMethod( }else{ iVal = pCsr->aCnt[pCsr->iCol]; } - }else{ + }else if( eType==FTS5_VOCAB_ROW ){ assert( iCol==1 || iCol==2 ); if( iCol==1 ){ iVal = pCsr->aDoc[0]; }else{ iVal = pCsr->aCnt[0]; } + }else{ + assert( eType==FTS5_VOCAB_INSTANCE ); + switch( iCol ){ + case 1: + sqlite3_result_int64(pCtx, pCsr->pIter->iRowid); + break; + case 2: { + int ii = -1; + if( eDetail==FTS5_DETAIL_FULL ){ + ii = FTS5_POS2COLUMN(pCsr->iInstPos); + }else if( eDetail==FTS5_DETAIL_COLUMNS ){ + ii = (int)pCsr->iInstPos; + } + if( ii>=0 && iipFts5->pConfig->nCol ){ + const char *z = pCsr->pFts5->pConfig->azCol[ii]; + sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC); + } + break; + } + default: { + assert( iCol==3 ); + if( eDetail==FTS5_DETAIL_FULL ){ + int ii = FTS5_POS2OFFSET(pCsr->iInstPos); + sqlite3_result_int(pCtx, ii); + } + break; + } + } } if( iVal>0 ) sqlite3_result_int64(pCtx, iVal); return SQLITE_OK; } -/* +/* ** This is the xRowid method. The SQLite core calls this routine to ** retrieve the rowid for the current row of the result set. The ** rowid should be written to *pRowid. */ static int fts5VocabRowidMethod( - sqlite3_vtab_cursor *pCursor, + sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid ){ Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor; @@ -201387,6 +239059,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0, + /* xShadowName */ 0 }; void *p = (void*)pGlobal; @@ -201395,8 +239068,312 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){ - - #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */ /************** End of fts5.c ************************************************/ +/************** Begin file stmt.c ********************************************/ +/* +** 2017-05-31 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file demonstrates an eponymous virtual table that returns information +** about all prepared statements for the database connection. +** +** Usage example: +** +** .load ./stmt +** .mode line +** .header on +** SELECT * FROM stmt; +*/ +#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) +#if !defined(SQLITEINT_H) +/* #include "sqlite3ext.h" */ +#endif +SQLITE_EXTENSION_INIT1 +/* #include */ +/* #include */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +/* stmt_vtab is a subclass of sqlite3_vtab which will +** serve as the underlying representation of a stmt virtual table +*/ +typedef struct stmt_vtab stmt_vtab; +struct stmt_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this stmt vtab */ +}; + +/* stmt_cursor is a subclass of sqlite3_vtab_cursor which will +** serve as the underlying representation of a cursor that scans +** over rows of the result +*/ +typedef struct stmt_cursor stmt_cursor; +struct stmt_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this cursor */ + sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */ + sqlite3_int64 iRowid; /* The rowid */ +}; + +/* +** The stmtConnect() method is invoked to create a new +** stmt_vtab that describes the stmt virtual table. +** +** Think of this routine as the constructor for stmt_vtab objects. +** +** All this routine needs to do is: +** +** (1) Allocate the stmt_vtab object and initialize all fields. +** +** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the +** result set of queries against stmt will look like. +*/ +static int stmtConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + stmt_vtab *pNew; + int rc; + +/* Column numbers */ +#define STMT_COLUMN_SQL 0 /* SQL for the statement */ +#define STMT_COLUMN_NCOL 1 /* Number of result columns */ +#define STMT_COLUMN_RO 2 /* True if read-only */ +#define STMT_COLUMN_BUSY 3 /* True if currently busy */ +#define STMT_COLUMN_NSCAN 4 /* SQLITE_STMTSTATUS_FULLSCAN_STEP */ +#define STMT_COLUMN_NSORT 5 /* SQLITE_STMTSTATUS_SORT */ +#define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */ +#define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */ +#define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */ +#define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */ +#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ + + + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep," + "reprep,run,mem)"); + if( rc==SQLITE_OK ){ + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + pNew->db = db; + } + return rc; +} + +/* +** This method is the destructor for stmt_cursor objects. +*/ +static int stmtDisconnect(sqlite3_vtab *pVtab){ + sqlite3_free(pVtab); + return SQLITE_OK; +} + +/* +** Constructor for a new stmt_cursor object. +*/ +static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + stmt_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + pCur->db = ((stmt_vtab*)p)->db; + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a stmt_cursor. +*/ +static int stmtClose(sqlite3_vtab_cursor *cur){ + sqlite3_free(cur); + return SQLITE_OK; +} + + +/* +** Advance a stmt_cursor to its next row of output. +*/ +static int stmtNext(sqlite3_vtab_cursor *cur){ + stmt_cursor *pCur = (stmt_cursor*)cur; + pCur->iRowid++; + pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt); + return SQLITE_OK; +} + +/* +** Return values of columns for the row at which the stmt_cursor +** is currently pointing. +*/ +static int stmtColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + stmt_cursor *pCur = (stmt_cursor*)cur; + switch( i ){ + case STMT_COLUMN_SQL: { + sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT); + break; + } + case STMT_COLUMN_NCOL: { + sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt)); + break; + } + case STMT_COLUMN_RO: { + sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt)); + break; + } + case STMT_COLUMN_BUSY: { + sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt)); + break; + } + default: { + assert( i==STMT_COLUMN_MEM ); + i = SQLITE_STMTSTATUS_MEMUSED + + STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP; + /* Fall thru */ + } + case STMT_COLUMN_NSCAN: + case STMT_COLUMN_NSORT: + case STMT_COLUMN_NAIDX: + case STMT_COLUMN_NSTEP: + case STMT_COLUMN_REPREP: + case STMT_COLUMN_RUN: { + sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt, + i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0)); + break; + } + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + stmt_cursor *pCur = (stmt_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int stmtEof(sqlite3_vtab_cursor *cur){ + stmt_cursor *pCur = (stmt_cursor*)cur; + return pCur->pStmt==0; +} + +/* +** This method is called to "rewind" the stmt_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to stmtColumn() or stmtRowid() or +** stmtEof(). +*/ +static int stmtFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + stmt_cursor *pCur = (stmt_cursor *)pVtabCursor; + pCur->pStmt = 0; + pCur->iRowid = 0; + return stmtNext(pVtabCursor); +} + +/* +** SQLite will invoke this method one or more times while planning a query +** that uses the stmt virtual table. This routine needs to create +** a query plan for each invocation and compute an estimated cost for that +** plan. +*/ +static int stmtBestIndex( + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo +){ + pIdxInfo->estimatedCost = (double)500; + pIdxInfo->estimatedRows = 500; + return SQLITE_OK; +} + +/* +** This following structure defines all the methods for the +** stmt virtual table. +*/ +static sqlite3_module stmtModule = { + 0, /* iVersion */ + 0, /* xCreate */ + stmtConnect, /* xConnect */ + stmtBestIndex, /* xBestIndex */ + stmtDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + stmtOpen, /* xOpen - open a cursor */ + stmtClose, /* xClose - close a cursor */ + stmtFilter, /* xFilter - configure scan constraints */ + stmtNext, /* xNext - advance a cursor */ + stmtEof, /* xEof - check for end of scan */ + stmtColumn, /* xColumn - read data */ + stmtRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0, /* xShadowName */ +}; + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3 *db){ + int rc = SQLITE_OK; +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0); +#endif + return rc; +} + +#ifndef SQLITE_CORE +#ifdef _WIN32 +__declspec(dllexport) +#endif +SQLITE_API int sqlite3_stmt_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3StmtVtabInit(db); +#endif + return rc; +} +#endif /* SQLITE_CORE */ +#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ + +/************** End of stmt.c ************************************************/ +/* Return the source-id for this library */ +SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +/************************** End of sqlite3.c ******************************/ diff --git a/vendor/libraries/sqlite3/sqlite3.h b/vendor/libraries/sqlite3/sqlite3.h index c062c0a3d1..33dbec2c09 100644 --- a/vendor/libraries/sqlite3/sqlite3.h +++ b/vendor/libraries/sqlite3/sqlite3.h @@ -1,5 +1,5 @@ /* -** 2001 September 15 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -43,7 +43,30 @@ extern "C" { /* -** Provide the ability to override linkage features of the interface. +** Facilitate override of interface linkage and calling conventions. +** Be aware that these macros may not be used within this particular +** translation of the amalgamation and its associated header file. +** +** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the +** compiler that the target identifier should have external linkage. +** +** The SQLITE_CDECL macro is used to set the calling convention for +** public functions that accept a variable number of arguments. +** +** The SQLITE_APICALL macro is used to set the calling convention for +** public functions that accept a fixed number of arguments. +** +** The SQLITE_STDCALL macro is no longer used and is now deprecated. +** +** The SQLITE_CALLBACK macro is used to set the calling convention for +** function pointers. +** +** The SQLITE_SYSAPI macro is used to set the calling convention for +** functions provided by the operating system. +** +** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and +** SQLITE_SYSAPI macros are used only when building for environments +** that require non-default calling conventions. */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern @@ -108,22 +131,24 @@ extern "C" { ** be held constant and Z will be incremented or else Y will be incremented ** and Z will be reset to zero. ** -** Since [version 3.6.18] ([dateof:3.6.18]), +** Since [version 3.6.18] ([dateof:3.6.18]), ** SQLite source code has been stored in the ** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID -** string contains the date and time of the check-in (UTC) and an SHA1 -** hash of the entire source tree. +** string contains the date and time of the check-in (UTC) and a SHA1 +** or SHA3-256 hash of the entire source tree. If the source code has +** been edited in any way since it was last checked in, then the last +** four hexadecimal digits of the hash may be modified. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.17.0" -#define SQLITE_VERSION_NUMBER 3017000 -#define SQLITE_SOURCE_ID "2017-02-13 16:02:40 ada05cfa86ad7f5645450ac7a2a21c9aa6e57d2c" +#define SQLITE_VERSION "3.38.2" +#define SQLITE_VERSION_NUMBER 3038002 +#define SQLITE_SOURCE_ID "2022-03-26 13:51:10 d33c709cc0af66bc5b6dc6216eba9f1f0b40960b9ae83694c986fbf4c1d6f08f" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -139,7 +164,7 @@ extern "C" { ** **
                 ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
                -** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
                +** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
                 ** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
                 ** 
                )^ ** @@ -149,9 +174,11 @@ extern "C" { ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to -** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns -** a pointer to a string constant whose value is the same as the -** [SQLITE_SOURCE_ID] C preprocessor macro. +** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns +** a pointer to a string constant whose value is the same as the +** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built +** using an edited copy of [the amalgamation], then the last four characters +** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ @@ -163,20 +190,20 @@ SQLITE_API int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics ** -** ^The sqlite3_compileoption_used() function returns 0 or 1 -** indicating whether the specified option was defined at -** compile time. ^The SQLITE_ prefix may be omitted from the -** option name passed to sqlite3_compileoption_used(). +** ^The sqlite3_compileoption_used() function returns 0 or 1 +** indicating whether the specified option was defined at +** compile time. ^The SQLITE_ prefix may be omitted from the +** option name passed to sqlite3_compileoption_used(). ** ** ^The sqlite3_compileoption_get() function allows iterating ** over the list of options that were defined at compile time by ** returning the N-th compile time option string. ^If N is out of range, -** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ -** prefix is omitted from any strings returned by +** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ +** prefix is omitted from any strings returned by ** sqlite3_compileoption_get(). ** ** ^Support for the diagnostic functions sqlite3_compileoption_used() -** and sqlite3_compileoption_get() may be omitted by specifying the +** and sqlite3_compileoption_get() may be omitted by specifying the ** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. ** ** See also: SQL functions [sqlite_compileoption_used()] and @@ -185,6 +212,9 @@ SQLITE_API int sqlite3_libversion_number(void); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); +#else +# define sqlite3_compileoption_used(X) 0 +# define sqlite3_compileoption_get(X) ((void*)0) #endif /* @@ -197,7 +227,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N); ** SQLite can be compiled with or without mutexes. When ** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes ** are enabled and SQLite is threadsafe. When the -** [SQLITE_THREADSAFE] macro is 0, +** [SQLITE_THREADSAFE] macro is 0, ** the mutexes are omitted. Without the mutexes, it is not safe ** to use SQLite concurrently from more than one thread. ** @@ -254,14 +284,14 @@ typedef struct sqlite3 sqlite3; ** ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The -** sqlite3_uint64 and sqlite_uint64 types can store integer values +** sqlite3_uint64 and sqlite_uint64 types can store integer values ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; # ifdef SQLITE_UINT64_TYPE typedef SQLITE_UINT64_TYPE sqlite_uint64; -# else +# else typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; # endif #elif defined(_MSC_VER) || defined(__BORLANDC__) @@ -292,26 +322,22 @@ typedef sqlite_uint64 sqlite3_uint64; ** the [sqlite3] object is successfully destroyed and all associated ** resources are deallocated. ** -** ^If the database connection is associated with unfinalized prepared -** statements or unfinished sqlite3_backup objects then sqlite3_close() -** will leave the database connection open and return [SQLITE_BUSY]. -** ^If sqlite3_close_v2() is called with unfinalized prepared statements -** and/or unfinished sqlite3_backups, then the database connection becomes -** an unusable "zombie" which will automatically be deallocated when the -** last prepared statement is finalized or the last sqlite3_backup is -** finished. The sqlite3_close_v2() interface is intended for use with -** host languages that are garbage collected, and where the order in which -** destructors are called is arbitrary. -** -** Applications should [sqlite3_finalize | finalize] all [prepared statements], -** [sqlite3_blob_close | close] all [BLOB handles], and +** Ideally, applications should [sqlite3_finalize | finalize] all +** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated -** with the [sqlite3] object prior to attempting to close the object. ^If -** sqlite3_close_v2() is called on a [database connection] that still has -** outstanding [prepared statements], [BLOB handles], and/or -** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation -** of resources is deferred until all [prepared statements], [BLOB handles], -** and [sqlite3_backup] objects are also destroyed. +** with the [sqlite3] object prior to attempting to close the object. +** ^If the database connection is associated with unfinalized prepared +** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then +** sqlite3_close() will leave the database connection open and return +** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared +** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups, +** it returns [SQLITE_OK] regardless, but instead of deallocating the database +** connection immediately, it marks the database connection as an unusable +** "zombie" and makes arrangements to automatically deallocate the database +** connection after all prepared statements are finalized, all BLOB handles +** are closed, and all backups have finished. The sqlite3_close_v2() interface +** is intended for use with host languages that are garbage collected, and +** where the order in which destructors are called is arbitrary. ** ** ^If an [sqlite3] object is destroyed while a transaction is open, ** the transaction is automatically rolled back. @@ -341,7 +367,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** The sqlite3_exec() interface is a convenience wrapper around ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], ** that allows an application to run multiple statements of SQL -** without having to use a lot of C code. +** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, ** semicolon-separate SQL statements passed into its 2nd argument, @@ -381,7 +407,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer -** to an empty string, or a pointer that contains only whitespace and/or +** to an empty string, or a pointer that contains only whitespace and/or ** SQL comments, then no SQL statements are evaluated and the database ** is not changed. ** @@ -417,7 +443,7 @@ SQLITE_API int sqlite3_exec( */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_ERROR 1 /* Generic error */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ @@ -432,7 +458,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_EMPTY 16 /* Internal use only */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ @@ -440,7 +466,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_FORMAT 24 /* Not used */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ @@ -466,6 +492,9 @@ SQLITE_API int sqlite3_exec( ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ +#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) +#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) +#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) @@ -494,18 +523,31 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) +#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) +#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) +#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) +#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) +#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ +#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8)) +#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) +#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8)) +#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) @@ -517,11 +559,14 @@ SQLITE_API int sqlite3_exec( #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) +#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8)) +#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ /* ** CAPI3REF: Flags For File Open Operations @@ -529,6 +574,19 @@ SQLITE_API int sqlite3_exec( ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. +** +** Only those flags marked as "Ok for sqlite3_open_v2()" may be +** used as the third argument to the [sqlite3_open_v2()] interface. +** The other flags have historically been ignored by sqlite3_open_v2(), +** though future versions of SQLite might change so that an error is +** raised if any of the disallowed bits are passed into sqlite3_open_v2(). +** Applications should not depend on the historical behavior. +** +** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into +** [sqlite3_open_v2()] does *not* cause the underlying database file +** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into +** [sqlite3_open_v2()] has historically be a no-op and might become an +** error in future versions of SQLite. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ @@ -544,14 +602,19 @@ SQLITE_API int sqlite3_exec( #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ #define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ -#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ +#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */ #define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ +#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */ /* Reserved: 0x00F00000 */ +/* Legacy compatibility: */ +#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ + /* ** CAPI3REF: Device Characteristics @@ -580,6 +643,11 @@ SQLITE_API int sqlite3_exec( ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on ** read-only media and cannot be changed even by processes with ** elevated privileges. +** +** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying +** filesystem supports doing multiple write operations atomically when those +** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and +** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 @@ -595,6 +663,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000 #define SQLITE_IOCAP_IMMUTABLE 0x00002000 +#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels @@ -642,7 +711,7 @@ SQLITE_API int sqlite3_exec( /* ** CAPI3REF: OS Interface Open File Handle ** -** An [sqlite3_file] object represents an open file in the +** An [sqlite3_file] object represents an open file in the ** [sqlite3_vfs | OS interface layer]. Individual OS interface ** implementations will ** want to subclass this object by appending additional fields @@ -664,7 +733,7 @@ struct sqlite3_file { ** This object defines the methods used to perform various operations ** against the open file represented by the [sqlite3_file] object. ** -** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method ** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The ** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] @@ -729,6 +798,7 @@ struct sqlite3_file { **
              • [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN] **
              • [SQLITE_IOCAP_POWERSAFE_OVERWRITE] **
              • [SQLITE_IOCAP_IMMUTABLE] +**
              • [SQLITE_IOCAP_BATCH_ATOMIC] **
              ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of @@ -801,10 +871,19 @@ struct sqlite3_io_methods { ** file space based on this hint in order to help writes to the database ** file run faster. ** +**
            2. [[SQLITE_FCNTL_SIZE_LIMIT]] +** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that +** implements [sqlite3_deserialize()] to set an upper bound on the size +** of the in-memory database. The argument is a pointer to a [sqlite3_int64]. +** If the integer pointed to is negative, then it is filled in with the +** current limit. Otherwise the limit is set to the larger of the value +** of the integer pointed to and the current database size. The integer +** pointed to is set to the new limit. +** **
            3. [[SQLITE_FCNTL_CHUNK_SIZE]] ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified -** by the user. The fourth argument to [sqlite3_file_control()] should +** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and @@ -827,24 +906,24 @@ struct sqlite3_io_methods { **
            4. [[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and ** sent to the VFS immediately before the xSync method is invoked on a -** database file descriptor. Or, if the xSync method is not invoked -** because the user has configured SQLite with -** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place +** database file descriptor. Or, if the xSync method is not invoked +** because the user has configured SQLite with +** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place ** of the xSync method. In most cases, the pointer argument passed with ** this file-control is NULL. However, if the database file is being synced ** as part of a multi-database commit, the argument points to a nul-terminated -** string containing the transactions master-journal file name. VFSes that -** do not need this signal should silently ignore this opcode. Applications -** should not call [sqlite3_file_control()] with this opcode as doing so may -** disrupt the operation of the specialized VFSes that do require it. +** string containing the transactions super-journal file name. VFSes that +** do not need this signal should silently ignore this opcode. Applications +** should not call [sqlite3_file_control()] with this opcode as doing so may +** disrupt the operation of the specialized VFSes that do require it. ** **
            5. [[SQLITE_FCNTL_COMMIT_PHASETWO]] ** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite ** and sent to the VFS after a transaction has been committed immediately ** but before the database is unlocked. VFSes that do not need this signal ** should silently ignore this opcode. Applications should not call -** [sqlite3_file_control()] with this opcode as doing so may disrupt the -** operation of the specialized VFSes that do require it. +** [sqlite3_file_control()] with this opcode as doing so may disrupt the +** operation of the specialized VFSes that do require it. ** **
            6. [[SQLITE_FCNTL_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic @@ -857,7 +936,7 @@ struct sqlite3_io_methods { ** opcode allows these two values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two -** integers where the first integer i the new retry count and the second +** integers where the first integer is the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be @@ -866,7 +945,8 @@ struct sqlite3_io_methods { **
            7. [[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary -** write ahead log and shared memory files used for transaction control +** write ahead log ([WAL file]) and shared memory +** files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not @@ -891,13 +971,13 @@ struct sqlite3_io_methods { **
            8. [[SQLITE_FCNTL_OVERWRITE]] ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** a write transaction to indicate that, unless it is rolled back for some -** reason, the entire database file will be overwritten by the current +** reason, the entire database file will be overwritten by the current ** transaction. This is used by VACUUM operations. ** **
            9. [[SQLITE_FCNTL_VFSNAME]] ** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of ** all [VFSes] in the VFS stack. The names are of all VFS shims and the -** final bottom-level VFS are written into memory obtained from +** final bottom-level VFS are written into memory obtained from ** [sqlite3_malloc()] and the result is stored in the char* variable ** that the fourth parameter of [sqlite3_file_control()] points to. ** The caller is responsible for freeing the memory when done. As with @@ -916,7 +996,7 @@ struct sqlite3_io_methods { ** upper-most shim only. ** **
            10. [[SQLITE_FCNTL_PRAGMA]] -** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] +** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] ** file control is sent to the open [sqlite3_file] object corresponding ** to the database file to which the pragma statement refers. ^The argument ** to the [SQLITE_FCNTL_PRAGMA] file control is an array of @@ -927,7 +1007,7 @@ struct sqlite3_io_methods { ** of the char** argument point to a string obtained from [sqlite3_mprintf()] ** or the equivalent and that string will become the result of the pragma or ** the error message if the pragma fails. ^If the -** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal +** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] ** file control returns [SQLITE_OK], then the parser assumes that the ** VFS has handled the PRAGMA itself and the parser generates a no-op @@ -944,16 +1024,16 @@ struct sqlite3_io_methods { ** ^The [SQLITE_FCNTL_BUSYHANDLER] ** file-control may be invoked by SQLite on the database file handle ** shortly after it is opened in order to provide a custom VFS with access -** to the connections busy-handler callback. The argument is of type (void **) +** to the connection's busy-handler callback. The argument is of type (void**) ** - an array of two (void *) values. The first (void *) actually points -** to a function of type (int (*)(void *)). In order to invoke the connections +** to a function of type (int (*)(void *)). In order to invoke the connection's ** busy-handler, this function should be invoked with the second (void *) in ** the array as the only argument. If it returns non-zero, then the operation ** should be retried. If it returns zero, the custom VFS should abandon the ** current operation. ** **
            11. [[SQLITE_FCNTL_TEMPFILENAME]] -** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control +** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control ** to have SQLite generate a ** temporary filename using the same algorithm that is followed to generate ** temporary filenames for TEMP tables and other internal uses. The @@ -967,7 +1047,7 @@ struct sqlite3_io_methods { ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if -** the value originally pointed to is negative, and so the current limit +** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** @@ -1011,7 +1091,97 @@ struct sqlite3_io_methods { **
            12. [[SQLITE_FCNTL_RBU]] ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for -** this opcode. +** this opcode. +** +**
            13. [[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] +** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then +** the file descriptor is placed in "batch write mode", which +** means all subsequent write operations will be deferred and done +** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems +** that do not support batch atomic writes will return SQLITE_NOTFOUND. +** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to +** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or +** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make +** no VFS interface calls on the same [sqlite3_file] file descriptor +** except for calls to the xWrite method and the xFileControl method +** with [SQLITE_FCNTL_SIZE_HINT]. +** +**
            14. [[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. +** This file control returns [SQLITE_OK] if and only if the writes were +** all performed successfully and have been committed to persistent storage. +** ^Regardless of whether or not it is successful, this file control takes +** the file descriptor out of batch write mode so that all subsequent +** write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +**
            15. [[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] +** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write +** operations since the previous successful call to +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back. +** ^This file control takes the file descriptor out of batch write mode +** so that all subsequent write operations are independent. +** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. +** +**
            16. [[SQLITE_FCNTL_LOCK_TIMEOUT]] +** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS +** to block for up to M milliseconds before failing when attempting to +** obtain a file lock using the xLock or xShmLock methods of the VFS. +** The parameter is a pointer to a 32-bit signed integer that contains +** the value that M is to be set to. Before returning, the 32-bit signed +** integer is overwritten with the previous value of M. +** +**
            17. [[SQLITE_FCNTL_DATA_VERSION]] +** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to +** a database file. The argument is a pointer to a 32-bit unsigned integer. +** The "data version" for the pager is written into the pointer. The +** "data version" changes whenever any change occurs to the corresponding +** database file, either through SQL statements on the same database +** connection or through transactions committed by separate database +** connections possibly in other processes. The [sqlite3_total_changes()] +** interface can be used to find if any database on the connection has changed, +** but that interface responds to changes on TEMP as well as MAIN and does +** not provide a mechanism to detect changes to MAIN only. Also, the +** [sqlite3_total_changes()] interface responds to internal changes only and +** omits changes made by other database connections. The +** [PRAGMA data_version] command provides a mechanism to detect changes to +** a single attached database that occur due to other database connections, +** but omits changes implemented by the database connection on which it is +** called. This file control is the only mechanism to detect changes that +** happen either internally or externally and that are associated with +** a particular attached database. +** +**
            18. [[SQLITE_FCNTL_CKPT_START]] +** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint +** in wal mode before the client starts to copy pages from the wal +** file to the database file. +** +**
            19. [[SQLITE_FCNTL_CKPT_DONE]] +** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint +** in wal mode after the client has finished copying pages from the wal +** file to the database file, but before the *-shm file is updated to +** record the fact that the pages have been checkpointed. +** +** +**
            20. [[SQLITE_FCNTL_EXTERNAL_READER]] +** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect +** whether or not there is a database client in another process with a wal-mode +** transaction open on the database or not. It is only available on unix.The +** (void*) argument passed with this file-control should be a pointer to a +** value of type (int). The integer value is set to 1 if the database is a wal +** mode database and there exists at least one client in another process that +** currently has an SQL transaction open on the database. It is set to 0 if +** the database is not a wal-mode db, or if there is no such connection in any +** other process. This opcode cannot be used to detect transactions opened +** by clients within the current process, only within other processes. +** +** +**
            21. [[SQLITE_FCNTL_CKSM_FILE]] +** Used by the cksmvfs VFS module only. ** */ #define SQLITE_FCNTL_LOCKSTATE 1 @@ -1043,6 +1213,17 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_JOURNAL_POINTER 28 #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 +#define SQLITE_FCNTL_LOCK_TIMEOUT 34 +#define SQLITE_FCNTL_DATA_VERSION 35 +#define SQLITE_FCNTL_SIZE_LIMIT 36 +#define SQLITE_FCNTL_CKPT_DONE 37 +#define SQLITE_FCNTL_RESERVE_BYTES 38 +#define SQLITE_FCNTL_CKPT_START 39 +#define SQLITE_FCNTL_EXTERNAL_READER 40 +#define SQLITE_FCNTL_CKSM_FILE 41 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE @@ -1080,12 +1261,18 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. ** -** The value of the iVersion field is initially 1 but may be larger in -** future versions of SQLite. Additional fields may be appended to this -** object when the iVersion value is increased. Note that the structure -** of the sqlite3_vfs object changes in the transaction between -** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not -** modified. +** The VFS interface is sometimes extended by adding new methods onto +** the end. Each time such an extension occurs, the iVersion field +** is incremented. The iVersion value started out as 1 in +** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2 +** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased +** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields +** may be appended to the sqlite3_vfs object and the iVersion value +** may increase again in future versions of SQLite. +** Note that due to an oversight, the structure +** of the sqlite3_vfs object changed in the transition from +** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0] +** and yet the iVersion field was not increased. ** ** The szOsFile field is the size of the subclassed [sqlite3_file] ** structure used by this VFS. mxPathname is the maximum length of @@ -1120,14 +1307,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** the [sqlite3_file] can safely store a pointer to the ** filename if it needs to remember the filename for some reason. ** If the zFilename parameter to xOpen is a NULL pointer then xOpen -** must invent its own temporary name for the file. ^Whenever the +** must invent its own temporary name for the file. ^Whenever the ** xFilename parameter is NULL it will also be the case that the ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. ** ** The flags argument to xOpen() includes all bits set in ** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] ** or [sqlite3_open16()] is used, then flags includes at least -** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. +** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. ** If xOpen() opens a file read-only then it sets *pOutFlags to ** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. ** @@ -1141,7 +1328,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; **
            22. [SQLITE_OPEN_TEMP_JOURNAL] **
            23. [SQLITE_OPEN_TRANSIENT_DB] **
            24. [SQLITE_OPEN_SUBJOURNAL] -**
            25. [SQLITE_OPEN_MASTER_JOURNAL] +**
            26. [SQLITE_OPEN_SUPER_JOURNAL] **
            27. [SQLITE_OPEN_WAL] ** )^ ** @@ -1169,14 +1356,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction ** with the [SQLITE_OPEN_CREATE] flag, which are both directly ** analogous to the O_EXCL and O_CREAT flags of the POSIX open() -** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the +** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the ** SQLITE_OPEN_CREATE, is used to indicate that file should always ** be created, and that it is an error if it already exists. -** It is not used to indicate the file should be opened +** It is not used to indicate the file should be opened ** for exclusive access. ** ** ^At least szOsFile bytes of memory are allocated by SQLite -** to hold the [sqlite3_file] structure passed as the third +** to hold the [sqlite3_file] structure passed as the third ** argument to xOpen. The xOpen method does not have to ** allocate the structure; it should just fill it in. Note that ** the xOpen method must set the sqlite3_file.pMethods to either @@ -1189,8 +1376,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] -** to test whether a file is at least readable. The file can be a -** directory. +** to test whether a file is at least readable. The SQLITE_ACCESS_READ +** flag is never actually used and is not implemented in the built-in +** VFSes of SQLite. The file is named by the second argument and can be a +** directory. The xAccess method returns [SQLITE_OK] on success or some +** non-zero error code if there is an I/O error or if the name of +** the file given in the second argument is illegal. If SQLITE_OK +** is returned, then non-zero or zero is written into *pResOut to indicate +** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer @@ -1210,16 +1403,16 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** method returns a Julian Day Number for the current date and time as ** a floating point value. ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian -** Day Number multiplied by 86400000 (the number of milliseconds in -** a 24-hour day). +** Day Number multiplied by 86400000 (the number of milliseconds in +** a 24-hour day). ** ^SQLite will use the xCurrentTimeInt64() method to get the current -** date and time if that method is available (if iVersion is 2 or +** date and time if that method is available (if iVersion is 2 or ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided -** by some VFSes to facilitate testing of the VFS code. By overriding +** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can ** simulate faults and error conditions that would otherwise be difficult ** or impossible to induce. The set of system calls that can be overridden @@ -1266,7 +1459,7 @@ struct sqlite3_vfs { /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in future versions. The iVersion - ** value will increment whenever this happens. + ** value will increment whenever this happens. */ }; @@ -1310,7 +1503,7 @@ struct sqlite3_vfs { ** ** ** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as -** was given on the corresponding lock. +** was given on the corresponding lock. ** ** The xShmLock method can transition between unlocked and SHARED or ** between unlocked and EXCLUSIVE. It cannot transition between SHARED @@ -1455,7 +1648,7 @@ SQLITE_API int sqlite3_config(int, ...); ** [database connection] (specified in the first argument). ** ** The second argument to sqlite3_db_config(D,V,...) is the -** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code +** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code ** that indicates what aspect of the [database connection] is being configured. ** Subsequent arguments vary depending on the configuration verb. ** @@ -1473,7 +1666,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); ** This object is used in only one place in the SQLite interface. ** A pointer to an instance of this object is the argument to ** [sqlite3_config()] when the configuration option is -** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. +** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. ** By creating an instance of this object ** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) ** during configuration, an application can specify an alternative @@ -1503,17 +1696,17 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] -** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, +** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. For example, -** it might allocate any require mutexes or initialize internal data +** it might allocate any required mutexes or initialize internal data ** structures. The xShutdown method is invoked (indirectly) by ** [sqlite3_shutdown()] and should deallocate any resources acquired ** by xInit. The pAppData pointer is used as the only parameter to ** xInit and xShutdown. ** -** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes +** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes ** the xInit method, so the xInit method need not be threadsafe. The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. For all other methods, SQLite @@ -1561,7 +1754,7 @@ struct sqlite3_mem_methods { ** by a single thread. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to change the [threading mode] from its default -** value of Single-thread and so [sqlite3_config()] will return +** value of Single-thread and so [sqlite3_config()] will return ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD ** configuration option. ** @@ -1596,7 +1789,7 @@ struct sqlite3_mem_methods { ** SQLITE_CONFIG_SERIALIZED configuration option. ** ** [[SQLITE_CONFIG_MALLOC]]
              SQLITE_CONFIG_MALLOC
              -**
              ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is +**
              ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is ** a pointer to an instance of the [sqlite3_mem_methods] structure. ** The argument specifies ** alternative low-level memory allocation routines to be used in place of @@ -1613,12 +1806,23 @@ struct sqlite3_mem_methods { ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
              ** +** [[SQLITE_CONFIG_SMALL_MALLOC]]
              SQLITE_CONFIG_SMALL_MALLOC
              +**
              ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of +** type int, interpreted as a boolean, which if true provides a hint to +** SQLite that it should avoid large memory allocations if possible. +** SQLite will run faster if it is free to make large memory allocations, +** but some application might prefer to run slower in exchange for +** guarantees about memory fragmentation that are possible if large +** allocations are avoided. This hint is normally off. +**
              +** ** [[SQLITE_CONFIG_MEMSTATUS]]
              SQLITE_CONFIG_MEMSTATUS
              **
              ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int, ** interpreted as a boolean, which enables or disables the collection of ** memory allocation statistics. ^(When memory allocation statistics are ** disabled, the following SQLite interfaces become non-operational: **
                +**
              • [sqlite3_hard_heap_limit64()] **
              • [sqlite3_memory_used()] **
              • [sqlite3_memory_highwater()] **
              • [sqlite3_soft_heap_limit64()] @@ -1630,32 +1834,14 @@ struct sqlite3_mem_methods { **
              ** ** [[SQLITE_CONFIG_SCRATCH]]
              SQLITE_CONFIG_SCRATCH
              -**
              ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer -** that SQLite can use for scratch memory. ^(There are three arguments -** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte -** aligned memory buffer from which the scratch allocations will be -** drawn, the size of each scratch allocation (sz), -** and the maximum number of scratch allocations (N).)^ -** The first argument must be a pointer to an 8-byte aligned buffer -** of at least sz*N bytes of memory. -** ^SQLite will not use more than one scratch buffers per thread. -** ^SQLite will never request a scratch buffer that is more than 6 -** times the database page size. -** ^If SQLite needs needs additional -** scratch memory beyond what is provided by this configuration option, then -** [sqlite3_malloc()] will be used to obtain the memory needed.

              -** ^When the application provides any amount of scratch memory using -** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large -** [sqlite3_malloc|heap allocations]. -** This can help [Robson proof|prevent memory allocation failures] due to heap -** fragmentation in low-memory embedded systems. +**

              The SQLITE_CONFIG_SCRATCH option is no longer used. **
              ** ** [[SQLITE_CONFIG_PAGECACHE]]
              SQLITE_CONFIG_PAGECACHE
              **
              ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool ** that SQLite can use for the database page cache with the default page -** cache implementation. -** This configuration option is a no-op if an application-define page +** cache implementation. +** This configuration option is a no-op if an application-defined page ** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]. ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to ** 8-byte aligned memory (pMem), the size of each page cache line (sz), @@ -1682,10 +1868,9 @@ struct sqlite3_mem_methods { ** additional cache line.
              ** ** [[SQLITE_CONFIG_HEAP]]
              SQLITE_CONFIG_HEAP
              -**
              ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer +**
              ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs -** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and -** [SQLITE_CONFIG_PAGECACHE]. +** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. @@ -1738,7 +1923,7 @@ struct sqlite3_mem_methods { ** configuration on individual connections.)^
              ** ** [[SQLITE_CONFIG_PCACHE2]]
              SQLITE_CONFIG_PCACHE2
              -**
              ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is +**
              ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is ** a pointer to an [sqlite3_pcache_methods2] object. This object specifies ** the interface to a custom page cache implementation.)^ ** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.
              @@ -1752,7 +1937,7 @@ struct sqlite3_mem_methods { **
              The SQLITE_CONFIG_LOG option is used to configure the SQLite ** global [error log]. ** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a -** function with a call signature of void(*)(void*,int,const char*), +** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. @@ -1861,7 +2046,7 @@ struct sqlite3_mem_methods { ** [[SQLITE_CONFIG_STMTJRNL_SPILL]] **
              SQLITE_CONFIG_STMTJRNL_SPILL **
              ^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which -** becomes the [statement journal] spill-to-disk threshold. +** becomes the [statement journal] spill-to-disk threshold. ** [Statement journals] are held in memory until their size (in bytes) ** exceeds this threshold, at which point they are written to disk. ** Or if the threshold is -1, statement journals are always held @@ -1871,6 +2056,33 @@ struct sqlite3_mem_methods { ** I/O required to support statement rollback. ** The default value for this setting is controlled by the ** [SQLITE_STMTJRNL_SPILL] compile-time option. +** +** [[SQLITE_CONFIG_SORTERREF_SIZE]] +**
              SQLITE_CONFIG_SORTERREF_SIZE +**
              The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter +** of type (int) - the new value of the sorter-reference size threshold. +** Usually, when SQLite uses an external sort to order records according +** to an ORDER BY clause, all fields required by the caller are present in the +** sorted records. However, if SQLite determines based on the declared type +** of a table column that its values are likely to be very large - larger +** than the configured sorter-reference size threshold - then a reference +** is stored in each sorted record and the required column values loaded +** from the database as records are returned in sorted order. The default +** value for this option is to never use this optimization. Specifying a +** negative value for this option restores the default behaviour. +** This option is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option. +** +** [[SQLITE_CONFIG_MEMDB_MAXSIZE]] +**
              SQLITE_CONFIG_MEMDB_MAXSIZE +**
              The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter +** [sqlite3_int64] parameter which is the default maximum size for an in-memory +** database created using [sqlite3_deserialize()]. This default maximum +** size can be adjusted up or down for individual databases using the +** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this +** configuration setting is never used, then the default maximum is determined +** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that +** compile-time option is not set, then the default maximum is 1073741824. ** */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -1878,13 +2090,13 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ -#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ -/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ +/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ #define SQLITE_CONFIG_PCACHE 14 /* no-op */ #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ @@ -1899,6 +2111,9 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */ #define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */ #define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */ +#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */ +#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ +#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options @@ -1914,8 +2129,9 @@ struct sqlite3_mem_methods { ** is invoked. ** **
              +** [[SQLITE_DBCONFIG_LOOKASIDE]] **
              SQLITE_DBCONFIG_LOOKASIDE
              -**
              ^This option takes three additional arguments that determine the +**
              ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. ** ^The first argument (the third parameter to [sqlite3_db_config()] is a ** pointer to a memory buffer to use for lookaside memory. @@ -1933,9 +2149,10 @@ struct sqlite3_mem_methods { ** when the "current value" returned by ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside -** memory is in use leaves the configuration unchanged and returns +** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
              ** +** [[SQLITE_DBCONFIG_ENABLE_FKEY]] **
              SQLITE_DBCONFIG_ENABLE_FKEY
              **
              ^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. @@ -1946,6 +2163,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
              ** +** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]] **
              SQLITE_DBCONFIG_ENABLE_TRIGGER
              **
              ^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. @@ -1954,11 +2172,35 @@ struct sqlite3_mem_methods { ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in -** which case the trigger setting is not reported back.
              +** which case the trigger setting is not reported back. ** +**

              Originally this option disabled all triggers. ^(However, since +** SQLite version 3.35.0, TEMP triggers are still allowed even if +** this option is off. So, in other words, this option now only disables +** triggers in the main database schema or in the schemas of ATTACH-ed +** databases.)^

              +** +** [[SQLITE_DBCONFIG_ENABLE_VIEW]] +**
              SQLITE_DBCONFIG_ENABLE_VIEW
              +**
              ^This option is used to enable or disable [CREATE VIEW | views]. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable views, +** positive to enable views or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether views are disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the view setting is not reported back. +** +**

              Originally this option disabled all views. ^(However, since +** SQLite version 3.35.0, TEMP views are still allowed even if +** this option is off. So, in other words, this option now only disables +** views in the main database schema or in the schemas of ATTACH-ed +** databases.)^

              +** +** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] **
              SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
              -**
              ^This option is used to enable or disable the two-argument -** version of the [fts3_tokenizer()] function which is part of the +**
              ^This option is used to enable or disable the +** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or @@ -1969,6 +2211,7 @@ struct sqlite3_mem_methods { ** following this call. The second parameter may be a NULL pointer, in ** which case the new setting is not reported back.
              ** +** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]] **
              SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
              **
              ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. @@ -1986,7 +2229,7 @@ struct sqlite3_mem_methods { ** be a NULL pointer, in which case the new setting is not reported back. **
              ** -**
              SQLITE_DBCONFIG_MAINDBNAME
              +** [[SQLITE_DBCONFIG_MAINDBNAME]]
              SQLITE_DBCONFIG_MAINDBNAME
              **
              ^This option is used to change the name of the "main" database ** schema. ^The sole argument is a pointer to a constant UTF8 string ** which will become the new schema name in place of "main". ^SQLite @@ -1995,18 +2238,162 @@ struct sqlite3_mem_methods { ** until after the database connection closes. **
              ** +** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]] **
              SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
              -**
              Usually, when a database in wal mode is closed or detached from a -** database handle, SQLite checks if this will mean that there are now no -** connections at all to the database. If so, it performs a checkpoint +**
              Usually, when a database in wal mode is closed or detached from a +** database handle, SQLite checks if this will mean that there are now no +** connections at all to the database. If so, it performs a checkpoint ** operation before closing the connection. This option may be used to ** override this behaviour. The first parameter passed to this operation -** is an integer - non-zero to disable checkpoints-on-close, or zero (the -** default) to enable them. The second parameter is a pointer to an integer +** is an integer - positive to disable checkpoints-on-close, or zero (the +** default) to enable them, and negative to leave the setting unchanged. +** The second parameter is a pointer to an integer ** into which is written 0 or 1 to indicate whether checkpoints-on-close ** have been disabled - 0 if they are not disabled, 1 if they are. **
              ** +** [[SQLITE_DBCONFIG_ENABLE_QPSG]]
              SQLITE_DBCONFIG_ENABLE_QPSG
              +**
              ^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates +** the [query planner stability guarantee] (QPSG). When the QPSG is active, +** a single SQL query statement will always use the same algorithm regardless +** of values of [bound parameters].)^ The QPSG disables some query optimizations +** that look at the values of bound parameters, which can make some queries +** slower. But the QPSG has the advantage of more predictable behavior. With +** the QPSG active, SQLite will always use the same query plan in the field as +** was used during testing in the lab. +** The first argument to this setting is an integer which is 0 to disable +** the QPSG, positive to enable QPSG, or negative to leave the setting +** unchanged. The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether the QPSG is disabled or enabled +** following this call. +**
              +** +** [[SQLITE_DBCONFIG_TRIGGER_EQP]]
              SQLITE_DBCONFIG_TRIGGER_EQP
              +**
              By default, the output of EXPLAIN QUERY PLAN commands does not +** include output for any operations performed by trigger programs. This +** option is used to set or clear (the default) a flag that governs this +** behavior. The first parameter passed to this operation is an integer - +** positive to enable output for trigger programs, or zero to disable it, +** or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which is written +** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if +** it is not disabled, 1 if it is. +**
              +** +** [[SQLITE_DBCONFIG_RESET_DATABASE]]
              SQLITE_DBCONFIG_RESET_DATABASE
              +**
              Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run +** [VACUUM] in order to reset a database back to an empty database +** with no schema and no content. The following process works even for +** a badly corrupted database file: +**
                +**
              1. If the database connection is newly opened, make sure it has read the +** database schema by preparing then discarding some query against the +** database, or calling sqlite3_table_column_metadata(), ignoring any +** errors. This step is only necessary if the application desires to keep +** the database in WAL mode after the reset if it was in WAL mode before +** the reset. +**
              2. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); +**
              3. [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); +**
              4. sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); +**
              +** Because resetting a database is destructive and irreversible, the +** process requires the use of this obscure API and multiple steps to help +** ensure that it does not happen by accident. +** +** [[SQLITE_DBCONFIG_DEFENSIVE]]
              SQLITE_DBCONFIG_DEFENSIVE
              +**
              The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the +** "defensive" flag for a database connection. When the defensive +** flag is enabled, language features that allow ordinary SQL to +** deliberately corrupt the database file are disabled. The disabled +** features include but are not limited to the following: +**
                +**
              • The [PRAGMA writable_schema=ON] statement. +**
              • The [PRAGMA journal_mode=OFF] statement. +**
              • Writes to the [sqlite_dbpage] virtual table. +**
              • Direct writes to [shadow tables]. +**
              +**
              +** +** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]]
              SQLITE_DBCONFIG_WRITABLE_SCHEMA
              +**
              The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the +** "writable_schema" flag. This has the same effect and is logically equivalent +** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. +** The first argument to this setting is an integer which is 0 to disable +** the writable_schema, positive to enable writable_schema, or negative to +** leave the setting unchanged. The second parameter is a pointer to an +** integer into which is written 0 or 1 to indicate whether the writable_schema +** is enabled or disabled following this call. +**
              +** +** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] +**
              SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
              +**
              The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates +** the legacy behavior of the [ALTER TABLE RENAME] command such it +** behaves as it did prior to [version 3.24.0] (2018-06-04). See the +** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for +** additional information. This feature can also be turned on and off +** using the [PRAGMA legacy_alter_table] statement. +**
              +** +** [[SQLITE_DBCONFIG_DQS_DML]] +**
              SQLITE_DBCONFIG_DQS_DML +**
              The SQLITE_DBCONFIG_DQS_DML option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DML statements +** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +**
              +** +** [[SQLITE_DBCONFIG_DQS_DDL]] +**
              SQLITE_DBCONFIG_DQS_DDL +**
              The SQLITE_DBCONFIG_DQS option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DDL statements, +** such as CREATE TABLE and CREATE INDEX. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +**
              +** +** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]] +**
              SQLITE_DBCONFIG_TRUSTED_SCHEMA +**
              The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to +** assume that database schemas are untainted by malicious content. +** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite +** takes additional defensive steps to protect the application from harm +** including: +**
                +**
              • Prohibit the use of SQL functions inside triggers, views, +** CHECK constraints, DEFAULT clauses, expression indexes, +** partial indexes, or generated columns +** unless those functions are tagged with [SQLITE_INNOCUOUS]. +**
              • Prohibit the use of virtual tables inside of triggers or views +** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS]. +**
              +** This setting defaults to "on" for legacy compatibility, however +** all applications are advised to turn it off if possible. This setting +** can also be controlled using the [PRAGMA trusted_schema] statement. +**
              +** +** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]] +**
              SQLITE_DBCONFIG_LEGACY_FILE_FORMAT +**
              The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates +** the legacy file format flag. When activated, this flag causes all newly +** created database file to have a schema format version number (the 4-byte +** integer found at offset 44 into the database header) of 1. This in turn +** means that the resulting database file will be readable and writable by +** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting, +** newly created databases are generally not understandable by SQLite versions +** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there +** is now scarcely any need to generated database files that are compatible +** all the way back to version 3.0.0, and so this setting is of little +** practical use, but is provided so that SQLite can continue to claim the +** ability to generate new database files that are compatible with version +** 3.0.0. +**

              Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on, +** the [VACUUM] command will fail with an obscure error when attempting to +** process a table with generated columns and a descending index. This is +** not considered a bug since SQLite versions 3.3.0 and earlier do not support +** either generated columns or decending indexes. +**

              ** */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2016,7 +2403,18 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */ #define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */ - +#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */ +#define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ +#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ +#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */ +#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -2040,20 +2438,30 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** -** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the -** most recent successful [INSERT] into a rowid table or [virtual table] -** on database connection D. -** ^Inserts into [WITHOUT ROWID] tables are not recorded. -** ^If no successful [INSERT]s into rowid tables -** have ever occurred on the database connection D, -** then sqlite3_last_insert_rowid(D) returns zero. -** -** ^(If an [INSERT] occurs within a trigger or within a [virtual table] -** method, then this routine will return the [rowid] of the inserted -** row as long as the trigger or virtual table method is running. -** But once the trigger or virtual table method ends, the value returned -** by this routine reverts to what it was before the trigger or virtual -** table method began.)^ +** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of +** the most recent successful [INSERT] into a rowid table or [virtual table] +** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not +** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred +** on the database connection D, then sqlite3_last_insert_rowid(D) returns +** zero. +** +** As well as being set automatically as rows are inserted into database +** tables, the value returned by this function may be set explicitly by +** [sqlite3_set_last_insert_rowid()] +** +** Some virtual table implementations may INSERT rows into rowid tables as +** part of committing a transaction (e.g. to flush data accumulated in memory +** to disk). In this case subsequent calls to this function return the rowid +** associated with these internal INSERT operations, which leads to +** unintuitive results. Virtual table implementations that do write to rowid +** tables in this way can avoid this problem by restoring the original +** rowid value using [sqlite3_set_last_insert_rowid()] before returning +** control to the user. +** +** ^(If an [INSERT] occurs within a trigger then this routine will +** return the [rowid] of the inserted row as long as the trigger is +** running. Once the trigger program ends, the value returned +** by this routine reverts to what it was before the trigger was fired.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this @@ -2080,82 +2488,119 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); */ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); +/* +** CAPI3REF: Set the Last Insert Rowid value. +** METHOD: sqlite3 +** +** The sqlite3_set_last_insert_rowid(D, R) method allows the application to +** set the value returned by calling sqlite3_last_insert_rowid(D) to R +** without inserting a row into the database. +*/ +SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); + /* ** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** -** ^This function returns the number of rows modified, inserted or +** ^These functions return the number of rows modified, inserted or ** deleted by the most recently completed INSERT, UPDATE or DELETE ** statement on the database connection specified by the only parameter. -** ^Executing any other type of SQL statement does not modify the value -** returned by this function. +** The two functions are identical except for the type of the return value +** and that if the number of rows modified by the most recent INSERT, UPDATE +** or DELETE is greater than the maximum value supported by type "int", then +** the return value of sqlite3_changes() is undefined. ^Executing any other +** type of SQL statement does not modify the value returned by these functions. ** ** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are -** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], +** considered - auxiliary changes caused by [CREATE TRIGGER | triggers], ** [foreign key actions] or [REPLACE] constraint resolution are not counted. -** -** Changes to a view that are intercepted by -** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value -** returned by sqlite3_changes() immediately after an INSERT, UPDATE or -** DELETE statement run on a view is always zero. Only changes made to real +** +** Changes to a view that are intercepted by +** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value +** returned by sqlite3_changes() immediately after an INSERT, UPDATE or +** DELETE statement run on a view is always zero. Only changes made to real ** tables are counted. ** ** Things are more complicated if the sqlite3_changes() function is ** executed while a trigger program is running. This may happen if the ** program uses the [changes() SQL function], or if some other callback ** function invokes sqlite3_changes() directly. Essentially: -** +** **
                **
              • ^(Before entering a trigger program the value returned by -** sqlite3_changes() function is saved. After the trigger program +** sqlite3_changes() function is saved. After the trigger program ** has finished, the original value is restored.)^ -** -**
              • ^(Within a trigger program each INSERT, UPDATE and DELETE -** statement sets the value returned by sqlite3_changes() -** upon completion as normal. Of course, this value will not include -** any changes performed by sub-triggers, as the sqlite3_changes() +** +**
              • ^(Within a trigger program each INSERT, UPDATE and DELETE +** statement sets the value returned by sqlite3_changes() +** upon completion as normal. Of course, this value will not include +** any changes performed by sub-triggers, as the sqlite3_changes() ** value will be saved and restored after each sub-trigger has run.)^ **
              -** +** ** ^This means that if the changes() SQL function (or similar) is used -** by the first INSERT, UPDATE or DELETE statement within a trigger, it +** by the first INSERT, UPDATE or DELETE statement within a trigger, it ** returns the value as set when the calling statement began executing. -** ^If it is used by the second or subsequent such statement within a trigger -** program, the value returned reflects the number of rows modified by the +** ^If it is used by the second or subsequent such statement within a trigger +** program, the value returned reflects the number of rows modified by the ** previous INSERT, UPDATE or DELETE statement within the same trigger. ** -** See also the [sqlite3_total_changes()] interface, the -** [count_changes pragma], and the [changes() SQL function]. -** ** If a separate thread makes changes on the same database connection ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. +** +** See also: +**
                +**
              • the [sqlite3_total_changes()] interface +**
              • the [count_changes pragma] +**
              • the [changes() SQL function] +**
              • the [data_version pragma] +**
              */ SQLITE_API int sqlite3_changes(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** -** ^This function returns the total number of rows inserted, modified or +** ^These functions return the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed ** since the database connection was opened, including those executed as -** part of trigger programs. ^Executing any other type of SQL statement -** does not affect the value returned by sqlite3_total_changes(). -** +** part of trigger programs. The two functions are identical except for the +** type of the return value and that if the number of rows modified by the +** connection exceeds the maximum value supported by type "int", then +** the return value of sqlite3_total_changes() is undefined. ^Executing +** any other type of SQL statement does not affect the value returned by +** sqlite3_total_changes(). +** ** ^Changes made as part of [foreign key actions] are included in the ** count, but those made as part of REPLACE constraint resolution are -** not. ^Changes to a view that are intercepted by INSTEAD OF triggers +** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. -** -** See also the [sqlite3_changes()] interface, the -** [count_changes pragma], and the [total_changes() SQL function]. +** +** The [sqlite3_total_changes(D)] interface only reports the number +** of rows that changed due to SQL statement run against database +** connection D. Any changes by other database connections are ignored. +** To detect changes against a database file from other database +** connections use the [PRAGMA data_version] command or the +** [SQLITE_FCNTL_DATA_VERSION] [file control]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. +** +** See also: +**
                +**
              • the [sqlite3_changes()] interface +**
              • the [count_changes pragma] +**
              • the [changes() SQL function] +**
              • the [data_version pragma] +**
              • the [SQLITE_FCNTL_DATA_VERSION] [file control] +**
              */ SQLITE_API int sqlite3_total_changes(sqlite3*); +SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query @@ -2183,17 +2628,14 @@ SQLITE_API int sqlite3_total_changes(sqlite3*); ** ** ^The sqlite3_interrupt(D) call is in effect until all currently running ** SQL statements on [database connection] D complete. ^Any new SQL statements -** that are started after the sqlite3_interrupt() call and before the -** running statements reaches zero are interrupted as if they had been +** that are started after the sqlite3_interrupt() call and before the +** running statement count reaches zero are interrupted as if they had been ** running prior to the sqlite3_interrupt() call. ^New SQL statements ** that are started after the running statement count reaches zero are ** not effected by the sqlite3_interrupt(). ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. -** -** If the database connection closes while [sqlite3_interrupt()] -** is running then bad things will likely happen. */ SQLITE_API void sqlite3_interrupt(sqlite3*); @@ -2218,7 +2660,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3*); ** ^These routines do not parse the SQL statements thus ** will not detect syntactically incorrect SQL. ** -** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior +** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked ** automatically by sqlite3_complete16(). If that initialization fails, ** then the return value from sqlite3_complete16() will be non-zero @@ -2263,7 +2705,7 @@ SQLITE_API int sqlite3_complete16(const void *sql); ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] -** to the application instead of invoking the +** to the application instead of invoking the ** busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and @@ -2288,7 +2730,7 @@ SQLITE_API int sqlite3_complete16(const void *sql); ** database connection that invoked the busy handler. In other words, ** the busy handler is not reentrant. Any such actions ** result in undefined behavior. -** +** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ @@ -2355,9 +2797,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); ** Cindy | 21 ** ** -** There are two column (M==2) and three rows (N==3). Thus the +** There are two columns (M==2) and three rows (N==3). Thus the ** result table has 8 entries. Suppose the result table is stored -** in an array names azResult. Then azResult holds this content: +** in an array named azResult. Then azResult holds this content: ** **
               **        azResult[0] = "Name";
              @@ -2405,16 +2847,16 @@ SQLITE_API void sqlite3_free_table(char **result);
               **
               ** These routines are work-alikes of the "printf()" family of functions
               ** from the standard C library.
              -** These routines understand most of the common K&R formatting options,
              -** plus some additional non-standard formats, detailed below.
              -** Note that some of the more obscure formatting options from recent
              -** C-library standards are omitted from this implementation.
              +** These routines understand most of the common formatting options from
              +** the standard library printf()
              +** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]).
              +** See the [built-in printf()] documentation for details.
               **
               ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
              -** results into memory obtained from [sqlite3_malloc()].
              +** results into memory obtained from [sqlite3_malloc64()].
               ** The strings returned by these two routines should be
               ** released by [sqlite3_free()].  ^Both routines return a
              -** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
              +** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough
               ** memory to hold the resulting string.
               **
               ** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
              @@ -2438,71 +2880,7 @@ SQLITE_API void sqlite3_free_table(char **result);
               **
               ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
               **
              -** These routines all implement some additional formatting
              -** options that are useful for constructing SQL statements.
              -** All of the usual printf() formatting options apply.  In addition, there
              -** is are "%q", "%Q", "%w" and "%z" options.
              -**
              -** ^(The %q option works like %s in that it substitutes a nul-terminated
              -** string from the argument list.  But %q also doubles every '\'' character.
              -** %q is designed for use inside a string literal.)^  By doubling each '\''
              -** character it escapes that character and allows it to be inserted into
              -** the string.
              -**
              -** For example, assume the string variable zText contains text as follows:
              -**
              -** 
              -**  char *zText = "It's a happy day!";
              -** 
              -** -** One can use this text in an SQL statement as follows: -** -**
              -**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
              -**  sqlite3_exec(db, zSQL, 0, 0, 0);
              -**  sqlite3_free(zSQL);
              -** 
              -** -** Because the %q format string is used, the '\'' character in zText -** is escaped and the SQL generated is as follows: -** -**
              -**  INSERT INTO table1 VALUES('It''s a happy day!')
              -** 
              -** -** This is correct. Had we used %s instead of %q, the generated SQL -** would have looked like this: -** -**
              -**  INSERT INTO table1 VALUES('It's a happy day!');
              -** 
              -** -** This second example is an SQL syntax error. As a general rule you should -** always use %q instead of %s when inserting text into a string literal. -** -** ^(The %Q option works like %q except it also adds single quotes around -** the outside of the total string. Additionally, if the parameter in the -** argument list is a NULL pointer, %Q substitutes the text "NULL" (without -** single quotes).)^ So, for example, one could say: -** -**
              -**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
              -**  sqlite3_exec(db, zSQL, 0, 0, 0);
              -**  sqlite3_free(zSQL);
              -** 
              -** -** The code above will render a correct SQL statement in the zSQL -** variable even if the zText variable is a NULL pointer. -** -** ^(The "%w" formatting option is like "%q" except that it expects to -** be contained within double-quotes instead of single quotes, and it -** escapes the double-quote character instead of the single-quote -** character.)^ The "%w" formatting option is intended for safely inserting -** table and column names into a constructed SQL statement. -** -** ^(The "%z" formatting option works like "%s" but with the -** addition that after the string has been read and copied into -** the result, [sqlite3_free()] is called on the input string.)^ +** See also: [built-in printf()], [printf() SQL function] */ SQLITE_API char *sqlite3_mprintf(const char*,...); SQLITE_API char *sqlite3_vmprintf(const char*, va_list); @@ -2514,7 +2892,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** ** The SQLite core uses these three routines for all of its own ** internal memory allocation needs. "Core" in the previous sentence -** does not include operating-system specific VFS implementation. The +** does not include operating-system specific [VFS] implementation. The ** Windows VFS uses native malloc() and free() for some operations. ** ** ^The sqlite3_malloc() routine returns a pointer to a block @@ -2575,19 +2953,6 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. ** -** In SQLite version 3.5.0 and 3.5.1, it was possible to define -** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in -** implementation of these routines to be omitted. That capability -** is no longer provided. Only built-in memory allocators can be used. -** -** Prior to SQLite version 3.7.10, the Windows OS interface layer called -** the system malloc() and free() directly when converting -** filenames between the UTF-8 encoding used by SQLite -** and whatever filename encoding is used by the particular Windows -** installation. Memory allocation errors were detected, but -** they were reported back as [SQLITE_CANTOPEN] or -** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. -** ** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] ** must be either NULL or else pointers obtained from a prior ** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have @@ -2636,7 +3001,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for -** the build-in random() and randomblob() SQL functions. This interface allows +** the built-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. @@ -2656,12 +3021,14 @@ SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** METHOD: sqlite3 +** KEYWORDS: {authorizer callback} ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], -** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()], +** and [sqlite3_prepare16_v3()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should @@ -2677,14 +3044,16 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** requested is ok. ^When the callback returns [SQLITE_DENY], the ** [sqlite3_prepare_v2()] or equivalent call that triggered the ** authorizer will fail with an error message explaining that -** access is denied. +** access is denied. ** ** ^The first parameter to the authorizer callback is a copy of the third ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter ** to the callback is an integer [SQLITE_COPY | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters -** to the callback are zero-terminated strings that contain additional -** details about the action to be authorized. +** to the callback are either NULL pointers or zero-terminated strings +** that contain additional details about the action to be authorized. +** Applications must always be prepared to encounter a NULL pointer in any +** of the third through the sixth parameters of the authorization callback. ** ** ^If the action code is [SQLITE_READ] ** and the callback returns [SQLITE_IGNORE] then the @@ -2693,6 +3062,10 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] ** return can be used to deny an untrusted user access to individual ** columns of a table. +** ^When a table is referenced by a [SELECT] but no column values are +** extracted from that table (for example in a query like +** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback +** is invoked once for that table with a column name that is an empty string. ** ^If the action code is [SQLITE_DELETE] and the callback returns ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the ** [truncate optimization] is disabled and all rows are deleted individually. @@ -2724,7 +3097,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** database connections for the meaning of "modify" in this paragraph. ** ** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the -** statement might be re-prepared during [sqlite3_step()] due to a +** statement might be re-prepared during [sqlite3_step()] due to a ** schema change. Hence, the application should ensure that the ** correct authorizer callback remains in place during the [sqlite3_step()]. ** @@ -2838,9 +3211,9 @@ SQLITE_API int sqlite3_set_authorizer( ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite -** might provide greater resolution on the profiler callback. The -** sqlite3_profile() function is considered experimental and is -** subject to change in future versions of SQLite. +** might provide greater resolution on the profiler callback. Invoking +** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the +** profile callback. */ SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); @@ -2852,8 +3225,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** KEYWORDS: SQLITE_TRACE ** ** These constants identify classes of events that can be monitored -** using the [sqlite3_trace_v2()] tracing logic. The third argument -** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of +** using the [sqlite3_trace_v2()] tracing logic. The M argument +** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of ** the following constants. ^The first argument to the trace callback ** is one of the following constants. ** @@ -2872,7 +3245,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** execution of the prepared statement, such as at the start of each ** trigger subprogram. ^The P argument is a pointer to the ** [prepared statement]. ^The X argument is a pointer to a string which -** is the unexpanded SQL text of the prepared statement or an SQL comment +** is the unexpanded SQL text of the prepared statement or an SQL comment ** that indicates the invocation of a trigger. ^The callback can compute ** the same text that would have been returned by the legacy [sqlite3_trace()] ** interface by using the X argument when X begins with "--" and invoking @@ -2888,7 +3261,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** ** [[SQLITE_TRACE_ROW]]
              SQLITE_TRACE_ROW
              **
              ^An SQLITE_TRACE_ROW callback is invoked whenever a prepared -** statement generates a single row of result. +** statement generates a single row of result. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument is unused. ** @@ -2915,10 +3288,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** -** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides +** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides ** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). ** -** ^The X callback is invoked whenever any of the events identified by +** ^The X callback is invoked whenever any of the events identified by ** mask M occur. ^The integer return value from the callback is currently ** ignored, though this may change in future releases. Callback ** implementations should return zero to ensure future compatibility. @@ -2950,8 +3323,8 @@ SQLITE_API int sqlite3_trace_v2( ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** -** ^The parameter P is passed through as the only parameter to the -** callback function X. ^The parameter N is the approximate number of +** ^The parameter P is passed through as the only parameter to the +** callback function X. ^The parameter N is the approximate number of ** [virtual machine instructions] that are evaluated between successive ** invocations of the callback X. ^If N is less than one then the progress ** handler is disabled. @@ -2978,7 +3351,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** CAPI3REF: Opening A New Database Connection ** CONSTRUCTOR: sqlite3 ** -** ^These routines open an SQLite database file as specified by the +** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte ** order for sqlite3_open16(). ^(A [database connection] handle is usually @@ -3002,10 +3375,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to -** sqlite3_open_v2() can take one of -** the following three values, optionally combined with the -** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], -** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ +** sqlite3_open_v2() must include, at a minimum, one of the following +** three flag combinations:)^ ** **
              ** ^(
              [SQLITE_OPEN_READONLY]
              @@ -3023,22 +3394,66 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** sqlite3_open() and sqlite3_open16().
              )^ ** ** +** In addition to the required flags, the following optional flags are +** also supported: +** +**
              +** ^(
              [SQLITE_OPEN_URI]
              +**
              The filename can be interpreted as a URI if this flag is set.
              )^ +** +** ^(
              [SQLITE_OPEN_MEMORY]
              +**
              The database will be opened as an in-memory database. The database +** is named by the "filename" argument for the purposes of cache-sharing, +** if shared cache mode is enabled, but the "filename" is otherwise ignored. +**
              )^ +** +** ^(
              [SQLITE_OPEN_NOMUTEX]
              +**
              The new database connection will use the "multi-thread" +** [threading mode].)^ This means that separate threads are allowed +** to use SQLite at the same time, as long as each thread is using +** a different [database connection]. +** +** ^(
              [SQLITE_OPEN_FULLMUTEX]
              +**
              The new database connection will use the "serialized" +** [threading mode].)^ This means the multiple threads can safely +** attempt to use the same database connection at the same time. +** (Mutexes will block any actual concurrency, but in this mode +** there is no harm in trying.) +** +** ^(
              [SQLITE_OPEN_SHAREDCACHE]
              +**
              The database is opened [shared cache] enabled, overriding +** the default shared cache setting provided by +** [sqlite3_enable_shared_cache()].)^ +** +** ^(
              [SQLITE_OPEN_PRIVATECACHE]
              +**
              The database is opened [shared cache] disabled, overriding +** the default shared cache setting provided by +** [sqlite3_enable_shared_cache()].)^ +** +** [[OPEN_EXRESCODE]] ^(
              [SQLITE_OPEN_EXRESCODE]
              +**
              The database connection comes up in "extended result code mode". +** In other words, the database behaves has if +** [sqlite3_extended_result_codes(db,1)] where called on the database +** connection as soon as the connection is created. In addition to setting +** the extended result code mode, this flag also causes [sqlite3_open_v2()] +** to return an extended result code.
              +** +** [[OPEN_NOFOLLOW]] ^(
              [SQLITE_OPEN_NOFOLLOW]
              +**
              The database filename is not allowed to be a symbolic link
              +**
              )^ +** ** If the 3rd parameter to sqlite3_open_v2() is not one of the -** combinations shown above optionally combined with other +** required combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] -** then the behavior is undefined. -** -** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection -** opens in the multi-thread [threading mode] as long as the single-thread -** mode has not been set at compile-time or start-time. ^If the -** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens -** in the serialized [threading mode] unless single-thread was -** previously selected at compile-time or start-time. -** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be -** eligible to use [shared cache mode], regardless of whether or not shared -** cache is enabled using [sqlite3_enable_shared_cache()]. ^The -** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not -** participate in [shared cache mode] even if it is enabled. +** then the behavior is undefined. Historic versions of SQLite +** have silently ignored surplus bits in the flags parameter to +** sqlite3_open_v2(), however that behavior might not be carried through +** into future versions of SQLite and so applications should not rely +** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op +** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause +** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE +** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not +** by sqlite3_open_v2(). ** ** ^The fourth parameter to sqlite3_open_v2() is the name of the ** [sqlite3_vfs] object that defines the operating system interface that @@ -3062,26 +3477,26 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is -** set in the fourth argument to sqlite3_open_v2(), or if it has +** set in the third argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. -** As of SQLite version 3.7.7, URI filename interpretation is turned off +** URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. ** ** URI filenames are parsed according to RFC 3986. ^If the URI contains an -** authority, then it must be either an empty string or the string -** "localhost". ^If the authority is not an empty string or "localhost", an -** error is returned to the caller. ^The fragment component of a URI, if +** authority, then it must be either an empty string or the string +** "localhost". ^If the authority is not an empty string or "localhost", an +** error is returned to the caller. ^The fragment component of a URI, if ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file -** which contains the database. ^If the path begins with a '/' character, -** then it is interpreted as an absolute path. ^If the path does not begin +** which contains the database. ^If the path begins with a '/' character, +** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) -** then the path is interpreted as a relative path. -** ^(On windows, the first component of an absolute path +** then the path is interpreted as a relative path. +** ^(On windows, the first component of an absolute path ** is a drive specification (e.g. "C:").)^ ** ** [[core URI query parameters]] @@ -3101,13 +3516,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** **
            28. mode: ^(The mode parameter may be set to either "ro", "rw", ** "rwc", or "memory". Attempting to set it to any other value is -** an error)^. -** ^If "ro" is specified, then the database is opened for read-only -** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the -** third argument to sqlite3_open_v2(). ^If the mode option is set to -** "rw", then the database is opened for read-write (but not create) -** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had -** been set. ^Value "rwc" is equivalent to setting both +** an error)^. +** ^If "ro" is specified, then the database is opened for read-only +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the +** third argument to sqlite3_open_v2(). ^If the mode option is set to +** "rw", then the database is opened for read-write (but not create) +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had +** been set. ^Value "rwc" is equivalent to setting both ** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is ** set to "memory" then a pure [in-memory database] that never reads ** or writes from disk is used. ^It is an error to specify a value for @@ -3117,7 +3532,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); **
            29. cache: ^The cache parameter may be set to either "shared" or ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to -** sqlite3_open_v2(). ^Setting the cache parameter to "private" is +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behavior requested by setting @@ -3143,7 +3558,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** property on a database file that does in fact change can result ** in incorrect query results and/or [SQLITE_CORRUPT] errors. ** See also: [SQLITE_IOCAP_IMMUTABLE]. -** +** ** ** ** ^Specifying an unknown parameter in the query component of a URI is not an @@ -3155,36 +3570,37 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** **
          • **
            URI filenames Results -**
            file:data.db +**
            file:data.db ** Open the file "data.db" in the current directory. **
            file:/home/fred/data.db
            -** file:///home/fred/data.db
            -** file://localhost/home/fred/data.db
            +** file:///home/fred/data.db
            +** file://localhost/home/fred/data.db
            ** Open the database file "/home/fred/data.db". -**
            file://darkstar/home/fred/data.db +**
            file://darkstar/home/fred/data.db ** An error. "darkstar" is not a recognized authority. -**
            +**
            ** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db ** Windows only: Open the file "data.db" on fred's desktop on drive -** C:. Note that the %20 escaping in this example is not strictly +** C:. Note that the %20 escaping in this example is not strictly ** necessary - space characters can be used literally ** in URI filenames. -**
            file:data.db?mode=ro&cache=private +**
            file:data.db?mode=ro&cache=private ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. **
            file:/home/fred/data.db?vfs=unix-dotfile ** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile" ** that uses dot-files in place of posix advisory locking. -**
            file:data.db?mode=readonly +**
            file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. +** Use "ro" instead: "file:data.db?mode=ro". **
            ** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and ** query components of a URI. A hexadecimal escape sequence consists of a -** percent sign - "%" - followed by exactly two hexadecimal digits +** percent sign - "%" - followed by exactly two hexadecimal digits ** specifying an octet value. ^Before the path or query components of a -** URI filename are interpreted, they are encoded using UTF-8 and all +** URI filename are interpreted, they are encoded using UTF-8 and all ** hexadecimal escape sequences replaced by a single byte containing the ** corresponding octet. If this process generates an invalid UTF-8 encoding, ** the results are undefined. @@ -3219,17 +3635,27 @@ SQLITE_API int sqlite3_open_v2( /* ** CAPI3REF: Obtain Values For URI Parameters ** -** These are utility routines, useful to VFS implementations, that check -** to see if a database file was a URI that contained a specific query +** These are utility routines, useful to [VFS|custom VFS implementations], +** that check if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** -** If F is the database filename pointer passed into the xOpen() method of -** a VFS implementation when the flags parameter to xOpen() has one or -** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and -** P is the name of the query parameter, then +** The first parameter to these interfaces (hereafter referred to +** as F) must be one of: +**
              +**
            • A database filename pointer created by the SQLite core and +** passed into the xOpen() method of a VFS implemention, or +**
            • A filename obtained from [sqlite3_db_filename()], or +**
            • A new filename constructed using [sqlite3_create_filename()]. +**
            +** If the F parameter is not one of the above, then the behavior is +** undefined and probably undesirable. Older versions of SQLite were +** more tolerant of invalid F parameters than newer versions. +** +** If F is a suitable filename (as described in the previous paragraph) +** and if P is the name of the query parameter, then ** sqlite3_uri_parameter(F,P) returns the value of the P -** parameter if it exists or a NULL pointer if P does not appear as a -** query parameter on F. If P is a query parameter of F +** parameter if it exists or a NULL pointer if P does not appear as a +** query parameter on F. If P is a query parameter of F and it ** has no explicit value, then sqlite3_uri_parameter(F,P) returns ** a pointer to an empty string. ** @@ -3237,44 +3663,177 @@ SQLITE_API int sqlite3_open_v2( ** parameter and returns true (1) or false (0) according to the value ** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the ** value of query parameter P is one of "yes", "true", or "on" in any -** case or if the value begins with a non-zero number. The +** case or if the value begins with a non-zero number. The ** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of ** query parameter P is one of "no", "false", or "off" in any case or ** if the value begins with a numeric zero. If P is not a query -** parameter on F or if the value of P is does not match any of the +** parameter on F or if the value of P does not match any of the ** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0). ** ** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a ** 64-bit signed integer and returns that integer, or D if P does not ** exist. If the value of P is something other than an integer, then ** zero is returned. -** +** +** The sqlite3_uri_key(F,N) returns a pointer to the name (not +** the value) of the N-th query parameter for filename F, or a NULL +** pointer if N is less than zero or greater than the number of query +** parameters minus 1. The N value is zero-based so N should be 0 to obtain +** the name of the first query parameter, 1 for the second parameter, and +** so forth. +** ** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and ** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and -** is not a database file pathname pointer that SQLite passed into the xOpen -** VFS method, then the behavior of this routine is undefined and probably -** undesirable. +** is not a database file pathname pointer that the SQLite core passed +** into the xOpen VFS method, then the behavior of this routine is undefined +** and probably undesirable. +** +** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F +** parameter can also be the name of a rollback journal file or WAL file +** in addition to the main database file. Prior to version 3.31.0, these +** routines would only work if F was the name of the main database file. +** When the F parameter is the name of the rollback journal or WAL file, +** it has access to all the same query parameters as were found on the +** main database file. +** +** See the [URI filename] documentation for additional information. */ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault); SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64); +SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N); + +/* +** CAPI3REF: Translate filenames +** +** These routines are available to [VFS|custom VFS implementations] for +** translating filenames between the main database file, the journal file, +** and the WAL file. +** +** If F is the name of an sqlite database file, journal file, or WAL file +** passed by the SQLite core into the VFS, then sqlite3_filename_database(F) +** returns the name of the corresponding database file. +** +** If F is the name of an sqlite database file, journal file, or WAL file +** passed by the SQLite core into the VFS, or if F is a database filename +** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F) +** returns the name of the corresponding rollback journal file. +** +** If F is the name of an sqlite database file, journal file, or WAL file +** that was passed by the SQLite core into the VFS, or if F is a database +** filename obtained from [sqlite3_db_filename()], then +** sqlite3_filename_wal(F) returns the name of the corresponding +** WAL file. +** +** In all of the above, if F is not the name of a database, journal or WAL +** filename passed into the VFS from the SQLite core and F is not the +** return value from [sqlite3_db_filename()], then the result is +** undefined and is likely a memory access violation. +*/ +SQLITE_API const char *sqlite3_filename_database(const char*); +SQLITE_API const char *sqlite3_filename_journal(const char*); +SQLITE_API const char *sqlite3_filename_wal(const char*); + +/* +** CAPI3REF: Database File Corresponding To A Journal +** +** ^If X is the name of a rollback or WAL-mode journal file that is +** passed into the xOpen method of [sqlite3_vfs], then +** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file] +** object that represents the main database file. +** +** This routine is intended for use in custom [VFS] implementations +** only. It is not a general-purpose interface. +** The argument sqlite3_file_object(X) must be a filename pointer that +** has been passed into [sqlite3_vfs].xOpen method where the +** flags parameter to xOpen contains one of the bits +** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use +** of this routine results in undefined and probably undesirable +** behavior. +*/ +SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); +/* +** CAPI3REF: Create and Destroy VFS Filenames +** +** These interfces are provided for use by [VFS shim] implementations and +** are not useful outside of that context. +** +** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of +** database filename D with corresponding journal file J and WAL file W and +** with N URI parameters key/values pairs in the array P. The result from +** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that +** is safe to pass to routines like: +**
              +**
            • [sqlite3_uri_parameter()], +**
            • [sqlite3_uri_boolean()], +**
            • [sqlite3_uri_int64()], +**
            • [sqlite3_uri_key()], +**
            • [sqlite3_filename_database()], +**
            • [sqlite3_filename_journal()], or +**
            • [sqlite3_filename_wal()]. +**
            +** If a memory allocation error occurs, sqlite3_create_filename() might +** return a NULL pointer. The memory obtained from sqlite3_create_filename(X) +** must be released by a corresponding call to sqlite3_free_filename(Y). +** +** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array +** of 2*N pointers to strings. Each pair of pointers in this array corresponds +** to a key and value for a query parameter. The P parameter may be a NULL +** pointer if N is zero. None of the 2*N pointers in the P array may be +** NULL pointers and key pointers should not be empty strings. +** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may +** be NULL pointers, though they can be empty strings. +** +** The sqlite3_free_filename(Y) routine releases a memory allocation +** previously obtained from sqlite3_create_filename(). Invoking +** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op. +** +** If the Y parameter to sqlite3_free_filename(Y) is anything other +** than a NULL pointer or a pointer previously acquired from +** sqlite3_create_filename(), then bad things such as heap +** corruption or segfaults may occur. The value Y should not be +** used again after sqlite3_free_filename(Y) has been called. This means +** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y, +** then the corresponding [sqlite3_module.xClose() method should also be +** invoked prior to calling sqlite3_free_filename(Y). +*/ +SQLITE_API char *sqlite3_create_filename( + const char *zDatabase, + const char *zJournal, + const char *zWal, + int nParam, + const char **azParam +); +SQLITE_API void sqlite3_free_filename(char*); /* ** CAPI3REF: Error Codes And Messages ** METHOD: sqlite3 ** -** ^If the most recent sqlite3_* API call associated with +** ^If the most recent sqlite3_* API call associated with ** [database connection] D failed, then the sqlite3_errcode(D) interface ** returns the numeric [result code] or [extended result code] for that ** API call. -** If the most recent API call was successful, -** then the return value from sqlite3_errcode() is undefined. ** ^The sqlite3_extended_errcode() -** interface is the same except that it always returns the +** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. ** +** The values returned by sqlite3_errcode() and/or +** sqlite3_extended_errcode() might change with each API call. +** Except, there are some interfaces that are guaranteed to never +** change the value of the error code. The error-code preserving +** interfaces include the following: +** +**
              +**
            • sqlite3_errcode() +**
            • sqlite3_extended_errcode() +**
            • sqlite3_errmsg() +**
            • sqlite3_errmsg16() +**
            • sqlite3_error_offset() +**
            +** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(Memory to hold the error message string is managed internally. @@ -3287,6 +3846,13 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** +** ^If the most recent error references a specific token in the input +** SQL, the sqlite3_error_offset() interface returns the byte offset +** of the start of that token. ^The byte offset returned by +** sqlite3_error_offset() assumes that the input SQL is UTF8. +** ^If the most recent error does not reference a specific token in the input +** SQL, then the sqlite3_error_offset() function returns -1. +** ** When the serialized [threading mode] is in use, it might be the ** case that a second error occurs on a separate thread in between ** the time of the first error and the call to these interfaces. @@ -3306,6 +3872,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); SQLITE_API const char *sqlite3_errmsg(sqlite3*); SQLITE_API const void *sqlite3_errmsg16(sqlite3*); SQLITE_API const char *sqlite3_errstr(int); +SQLITE_API int sqlite3_error_offset(sqlite3 *db); /* ** CAPI3REF: Prepared Statement Object @@ -3315,7 +3882,7 @@ SQLITE_API const char *sqlite3_errstr(int); ** has been compiled into binary form and is ready to be evaluated. ** ** Think of each SQL statement as a separate computer program. The -** original SQL text is source code. A prepared statement object +** original SQL text is source code. A prepared statement object ** is the compiled object code. All SQL must be converted into a ** prepared statement before it can be run. ** @@ -3345,7 +3912,7 @@ typedef struct sqlite3_stmt sqlite3_stmt; ** new limit for that construct.)^ ** ** ^If the new limit is a negative number, the limit is unchanged. -** ^(For each limit category SQLITE_LIMIT_NAME there is a +** ^(For each limit category SQLITE_LIMIT_NAME there is a ** [limits | hard upper bound] ** set at compile-time by a C preprocessor macro called ** [limits | SQLITE_MAX_NAME]. @@ -3353,7 +3920,7 @@ typedef struct sqlite3_stmt sqlite3_stmt; ** ^Attempts to increase a limit above its hard upper bound are ** silently truncated to the hard upper bound. ** -** ^Regardless of whether or not the limit was changed, the +** ^Regardless of whether or not the limit was changed, the ** [sqlite3_limit()] interface returns the prior value of the limit. ** ^Hence, to find the current value of a limit without changing it, ** simply invoke this interface with the third parameter set to -1. @@ -3404,9 +3971,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_VDBE_OP]] ^(
            SQLITE_LIMIT_VDBE_OP
            **
            The maximum number of instructions in a virtual machine program -** used to implement an SQL statement. This limit is not currently -** enforced, though that might be added in some future release of -** SQLite.
            )^ +** used to implement an SQL statement. If [sqlite3_prepare_v2()] or +** the equivalent tries to allocate space for more than this many opcodes +** in a single prepared statement, an SQLITE_NOMEM error is returned.
    )^ ** ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
    SQLITE_LIMIT_FUNCTION_ARG
    **
    The maximum number of arguments on a function.
    )^ @@ -3444,23 +4011,74 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +/* +** CAPI3REF: Prepare Flags +** +** These constants define various flags that can be passed into +** "prepFlags" parameter of the [sqlite3_prepare_v3()] and +** [sqlite3_prepare16_v3()] interfaces. +** +** New flags may be added in future releases of SQLite. +** +**
    +** [[SQLITE_PREPARE_PERSISTENT]] ^(
    SQLITE_PREPARE_PERSISTENT
    +**
    The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner +** that the prepared statement will be retained for a long time and +** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()] +** and [sqlite3_prepare16_v3()] assume that the prepared statement will +** be used just once or at most a few times and then destroyed using +** [sqlite3_finalize()] relatively soon. The current implementation acts +** on this hint by avoiding the use of [lookaside memory] so as not to +** deplete the limited store of lookaside memory. Future versions of +** SQLite may act on this hint differently. +** +** [[SQLITE_PREPARE_NORMALIZE]]
    SQLITE_PREPARE_NORMALIZE
    +**
    The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used +** to be required for any prepared statement that wanted to use the +** [sqlite3_normalized_sql()] interface. However, the +** [sqlite3_normalized_sql()] interface is now available to all +** prepared statements, regardless of whether or not they use this +** flag. +** +** [[SQLITE_PREPARE_NO_VTAB]]
    SQLITE_PREPARE_NO_VTAB
    +**
    The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler +** to return an error (error code SQLITE_ERROR) if the statement uses +** any virtual tables. +**
    +*/ +#define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 +#define SQLITE_PREPARE_NO_VTAB 0x04 + /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** METHOD: sqlite3 ** CONSTRUCTOR: sqlite3_stmt ** -** To execute an SQL query, it must first be compiled into a byte-code -** program using one of these routines. +** To execute an SQL statement, it must first be compiled into a byte-code +** program using one of these routines. Or, in other words, these routines +** are constructors for the [prepared statement] object. +** +** The preferred routine to use is [sqlite3_prepare_v2()]. The +** [sqlite3_prepare()] interface is legacy and should be avoided. +** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used +** for special purposes. +** +** The use of the UTF-8 interfaces is preferred, as SQLite currently +** does all parsing using UTF-8. The UTF-16 interfaces are provided +** as a convenience. The UTF-16 interfaces work by converting the +** input text into UTF-8, then invoking the corresponding UTF-8 interface. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded -** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() -** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() -** use UTF-16. +** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(), +** and sqlite3_prepare_v3() +** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() use UTF-16. ** ** ^If the nByte argument is negative, then zSql is read up to the ** first zero terminator. ^If nByte is positive, then it is the @@ -3487,10 +4105,11 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** -** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are -** recommended for all new programs. The two older interfaces are retained -** for backwards compatibility, but their use is discouraged. -** ^In the "v2" interfaces, the prepared statement +** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(), +** and sqlite3_prepare16_v3() interfaces are recommended for all new programs. +** The older interfaces (sqlite3_prepare() and sqlite3_prepare16()) +** are retained for backwards compatibility, but their use is discouraged. +** ^In the "vX" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: @@ -3513,17 +4132,23 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
  • ** **
  • -** ^If the specific value bound to [parameter | host parameter] in the +** ^If the specific value bound to a [parameter | host parameter] in the ** WHERE clause might influence the choice of query plan for a statement, -** then the statement will be automatically recompiled, as if there had been -** a schema change, on the first [sqlite3_step()] call following any change -** to the [sqlite3_bind_text | bindings] of that [parameter]. -** ^The specific value of WHERE-clause [parameter] might influence the +** then the statement will be automatically recompiled, as if there had been +** a schema change, on the first [sqlite3_step()] call following any change +** to the [sqlite3_bind_text | bindings] of that [parameter]. +** ^The specific value of a WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column -** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. +** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled. **
  • ** +** +**

    ^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having +** the extra prepFlags parameter, which is a bit array consisting of zero or +** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The +** sqlite3_prepare_v2() interface works exactly the same as +** sqlite3_prepare_v3() with a zero prepFlags parameter. */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ @@ -3539,6 +4164,14 @@ SQLITE_API int sqlite3_prepare_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare_v3( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ @@ -3553,6 +4186,14 @@ SQLITE_API int sqlite3_prepare16_v2( sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); +SQLITE_API int sqlite3_prepare16_v3( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); /* ** CAPI3REF: Retrieving Statement SQL @@ -3560,10 +4201,16 @@ SQLITE_API int sqlite3_prepare16_v2( ** ** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 ** SQL text used to create [prepared statement] P if P was -** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. +** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 +** string containing the normalized SQL text of prepared statement P. The +** semantics used to normalize a SQL statement are unspecified and subject +** to change. At a minimum, literal values will be replaced with suitable +** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 @@ -3579,14 +4226,21 @@ SQLITE_API int sqlite3_prepare16_v2( ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** -** ^The string returned by sqlite3_sql(P) is managed by SQLite and is -** automatically freed when the prepared statement is finalized. +** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) +** are managed by SQLite and are automatically freed when the prepared +** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, -** is obtained from [sqlite3_malloc()] and must be free by the application +** is obtained from [sqlite3_malloc()] and must be freed by the application ** by passing it to [sqlite3_free()]. +** +** ^The sqlite3_normalized_sql() interface is only available if +** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +#ifdef SQLITE_ENABLE_NORMALIZE +SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); +#endif /* ** CAPI3REF: Determine If An SQL Statement Writes The Database @@ -3597,8 +4251,8 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); ** the content of the database file. ** ** Note that [application-defined SQL functions] or -** [virtual tables] might change the database indirectly as a side effect. -** ^(For example, if an application defines a function "eval()" that +** [virtual tables] might change the database indirectly as a side effect. +** ^(For example, if an application defines a function "eval()" that ** calls [sqlite3_exec()], then the following SQL statement would ** change the database file through side-effects: ** @@ -3612,35 +4266,60 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); ** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], ** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, ** since the statements themselves do not actually modify the database but -** rather they control the timing of when other statements modify the +** rather they control the timing of when other statements modify the ** database. ^The [ATTACH] and [DETACH] statements also cause ** sqlite3_stmt_readonly() to return true since, while those statements -** change the configuration of a database connection, they do not make +** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. ** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since ** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and ** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so ** sqlite3_stmt_readonly() returns false for those commands. +** +** ^This routine returns false if there is any possibility that the +** statement might change the database file. ^A false return does +** not guarantee that the statement will change the database file. +** ^For example, an UPDATE statement might have a WHERE clause that +** makes it a no-op, but the sqlite3_stmt_readonly() result would still +** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a +** read-only no-op if the table already exists, but +** sqlite3_stmt_readonly() still returns false for such a statement. +** +** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN] +** statement, then sqlite3_stmt_readonly(X) returns the same value as +** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted. */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); +/* +** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the +** prepared statement S is an EXPLAIN statement, or 2 if the +** statement S is an EXPLAIN QUERY PLAN. +** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is +** an ordinary statement or a NULL pointer. +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); + /* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the -** [prepared statement] S has been stepped at least once using +** [prepared statement] S has been stepped at least once using ** [sqlite3_step(S)] but has neither run to completion (returned ** [SQLITE_DONE] from [sqlite3_step(S)]) nor ** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S) -** interface returns false if S is a NULL pointer. If S is not a +** interface returns false if S is a NULL pointer. If S is not a ** NULL pointer and is not a pointer to a valid [prepared statement] ** object, then the behavior is undefined and probably undesirable. ** ** This interface can be used in combination [sqlite3_next_stmt()] -** to locate all prepared statements associated with a database +** to locate all prepared statements associated with a database ** connection that are in need of being reset. This can be used, -** for example, in diagnostic routines to search for prepared +** for example, in diagnostic routines to search for prepared ** statements that are holding a transaction open. */ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); @@ -3659,7 +4338,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** will accept either a protected or an unprotected sqlite3_value. ** Every interface that accepts sqlite3_value arguments specifies ** whether or not it requires a protected sqlite3_value. The -** [sqlite3_value_dup()] interface can be used to construct a new +** [sqlite3_value_dup()] interface can be used to construct a new ** protected sqlite3_value from an unprotected sqlite3_value. ** ** The terms "protected" and "unprotected" refer to whether or not @@ -3667,7 +4346,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** sqlite3_value object but no mutex is held for an unprotected ** sqlite3_value object. If SQLite is compiled to be single-threaded ** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) -** or if SQLite is run in one of reduced mutex modes +** or if SQLite is run in one of reduced mutex modes ** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] ** then there is no distinction between protected and unprotected ** sqlite3_value objects and they can be used interchangeably. However, @@ -3677,14 +4356,17 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*); ** ** ^The sqlite3_value objects that are passed as parameters into the ** implementation of [application-defined SQL functions] are protected. +** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()] +** are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. -** Unprotected sqlite3_value objects may only be used with -** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** Unprotected sqlite3_value objects may only be used as arguments +** to [sqlite3_result_value()], [sqlite3_bind_value()], and +** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ -typedef struct Mem sqlite3_value; +typedef struct sqlite3_value sqlite3_value; /* ** CAPI3REF: SQL Function Context Object @@ -3735,12 +4417,30 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_bind_parameter_index()] API if desired. ^The index ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] -** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). +** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766). ** ** ^The third argument is the value to bind to the parameter. ** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter ** is ignored and the end result is the same as sqlite3_bind_null(). +** ^If the third parameter to sqlite3_bind_text() is not NULL, then +** it should be a pointer to well-formed UTF8 text. +** ^If the third parameter to sqlite3_bind_text16() is not NULL, then +** it should be a pointer to well-formed UTF16 text. +** ^If the third parameter to sqlite3_bind_text64() is not NULL, then +** it should be a pointer to a well-formed unicode string that is +** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 +** otherwise. +** +** [[byte-order determination rules]] ^The byte-order of +** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) +** found in first character, which is removed, or in the absence of a BOM +** the byte order is the native byte order of the host +** machine for sqlite3_bind_text16() or the byte order specified in +** the 6th parameter for sqlite3_bind_text64().)^ +** ^If UTF16 input text contains invalid unicode +** characters, then SQLite might change those invalid characters +** into the unicode replacement character: U+FFFD. ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the @@ -3754,21 +4454,27 @@ typedef struct sqlite3_context sqlite3_context; ** or sqlite3_bind_text16() or sqlite3_bind_text64() then ** that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL -** terminated. If any NUL characters occur at byte offsets less than +** terminated. If any NUL characters occurs at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** -** ^The fifth argument to the BLOB and string binding interfaces -** is a destructor used to dispose of the BLOB or -** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to bind API fails. -** ^If the fifth argument is -** the special value [SQLITE_STATIC], then SQLite assumes that the -** information is in static, unmanaged space and does not need to be freed. -** ^If the fifth argument has the value [SQLITE_TRANSIENT], then -** SQLite makes its own private copy of the data immediately, before -** the sqlite3_bind_*() routine returns. +** ^The fifth argument to the BLOB and string binding interfaces controls +** or indicates the lifetime of the object referenced by the third parameter. +** These three options exist: +** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished +** with it may be passed. ^It is called to dispose of the BLOB or string even +** if the call to the bind API fails, except the destructor is not called if +** the third parameter is a NULL pointer or the fourth parameter is negative. +** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that +** the application remains responsible for disposing of the object. ^In this +** case, the object and the provided pointer to it must remain valid until +** either the prepared statement is finalized or the same SQL parameter is +** bound to something else, whichever occurs sooner. +** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the +** object is to be copied prior to the return from sqlite3_bind_*(). ^The +** object and pointer to it must remain valid until then. ^SQLite will then +** manage the lifetime of its private copy. ** ** ^The sixth argument to sqlite3_bind_text64() must be one of ** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] @@ -3786,6 +4492,15 @@ typedef struct sqlite3_context sqlite3_context; ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** +** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in +** [prepared statement] S to have an SQL value of NULL, but to also be +** associated with the pointer P of type T. ^D is either a NULL pointer or +** a pointer to a destructor function for P. ^SQLite will invoke the +** destructor D with a single argument of P when it is finished using +** P. The T parameter should be a static string, preferably a string +** literal. The sqlite3_bind_pointer() routine is part of the +** [pointer passing interface] added for SQLite 3.20.0. +** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], @@ -3819,6 +4534,7 @@ SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*) SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); @@ -3862,8 +4578,8 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was -** originally specified as UTF-16 in [sqlite3_prepare16()] or -** [sqlite3_prepare16_v2()]. +** originally specified as UTF-16 in [sqlite3_prepare16()], +** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -3880,7 +4596,8 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement -** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or +** [sqlite3_prepare16_v3()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and @@ -3903,7 +4620,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); ** METHOD: sqlite3_stmt ** ** ^Return the number of columns in the result set returned by the -** [prepared statement]. ^If this routine returns 0, that means the +** [prepared statement]. ^If this routine returns 0, that means the ** [prepared statement] returns no data (for example an [UPDATE]). ** ^However, just because this routine returns a positive number does not ** mean that one or more rows of data will be returned. ^A SELECT statement @@ -3971,7 +4688,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** ** ^If the Nth column returned by the statement is an expression or ** subquery and is not a column value, then all of these functions return -** NULL. ^These routine might also return NULL if a memory allocation error +** NULL. ^These routines might also return NULL if a memory allocation error ** occurs. ^Otherwise, they return the name of the attached database, table, ** or column that query result column was extracted from. ** @@ -3981,10 +4698,6 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); ** ^These APIs are only available if the library was compiled with the ** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. ** -** If two or more threads call one or more of these routines against the same -** prepared statement and column at the same time then the results are -** undefined. -** ** If two or more threads call one or more ** [sqlite3_column_database_name | column metadata interfaces] ** for the same [prepared statement] and result column @@ -4034,16 +4747,18 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** CAPI3REF: Evaluate An SQL Statement ** METHOD: sqlite3_stmt ** -** After a [prepared statement] has been prepared using either -** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** After a [prepared statement] has been prepared using any of +** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()], +** or [sqlite3_prepare16_v3()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend -** on whether the statement was prepared using the newer "v2" interface -** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy -** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the -** new "v2" interface is recommended for new applications but the legacy +** on whether the statement was prepared using the newer "vX" interfaces +** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()], +** [sqlite3_prepare16_v2()] or the older legacy +** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "vX" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], @@ -4087,7 +4802,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of -** sqlite3_step(). Failure to reset the prepared statement using +** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from ** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1], ** sqlite3_step() began @@ -4104,10 +4819,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements -** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()] +** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly -** by sqlite3_step(). The use of the "v2" interface is recommended. +** by sqlite3_step(). The use of the "vX" interfaces is recommended. */ SQLITE_API int sqlite3_step(sqlite3_stmt*); @@ -4118,7 +4834,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*); ** ^The sqlite3_data_count(P) interface returns the number of columns in the ** current row of the result set of [prepared statement] P. ** ^If prepared statement P does not have results ready to return -** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of +** (via calls to the [sqlite3_column_int | sqlite3_column()] family of ** interfaces) then sqlite3_data_count(P) returns 0. ** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. ** ^The sqlite3_data_count(P) routine returns 0 if the previous call to @@ -4169,6 +4885,28 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** KEYWORDS: {column access functions} ** METHOD: sqlite3_stmt ** +** Summary: +**

    +**
    sqlite3_column_blobBLOB result +**
    sqlite3_column_doubleREAL result +**
    sqlite3_column_int32-bit INTEGER result +**
    sqlite3_column_int6464-bit INTEGER result +**
    sqlite3_column_textUTF-8 TEXT result +**
    sqlite3_column_text16UTF-16 TEXT result +**
    sqlite3_column_valueThe result as an +** [sqlite3_value|unprotected sqlite3_value] object. +**
        +**
    sqlite3_column_bytesSize of a BLOB +** or a UTF-8 TEXT result in bytes +**
    sqlite3_column_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_column_typeDefault +** datatype of the result +**
    +** +** Details: +** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] @@ -4190,16 +4928,29 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** +** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16) +** each return the value of a result column in a specific data format. If +** the result column is not initially in the requested format (for example, +** if the query returns an integer but the sqlite3_column_text() interface +** is used to extract the value) then an automatic type conversion is performed. +** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], -** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value -** returned by sqlite3_column_type() is only meaningful if no type -** conversions have occurred as described below. After a type conversion, -** the value returned by sqlite3_column_type() is undefined. Future +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. +** The return value of sqlite3_column_type() can be used to decide which +** of the first six interface should be used to extract the column value. +** The value returned by sqlite3_column_type() is only meaningful if no +** automatic type conversions have occurred for the value in question. +** After a type conversion, the result of calling sqlite3_column_type() +** is undefined, though harmless. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** +** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes() +** or sqlite3_column_bytes16() interfaces can be used to determine the size +** of that BLOB or string. +** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts @@ -4218,7 +4969,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** the number of bytes in that string. ** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. ** -** ^The values returned by [sqlite3_column_bytes()] and +** ^The values returned by [sqlite3_column_bytes()] and ** [sqlite3_column_bytes16()] do not include the zero terminators at the end ** of the string. ^For clarity: the values returned by ** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of @@ -4228,6 +4979,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** even empty strings, are always zero-terminated. ^The return ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. ** +** ^Strings returned by sqlite3_column_text16() always have the endianness +** which is native to the platform, regardless of the text encoding set +** for the database. +** ** Warning: ^The object returned by [sqlite3_column_value()] is an ** [unprotected sqlite3_value] object. In a multithreaded environment, ** an unprotected sqlite3_value object may only be used safely with @@ -4236,9 +4991,13 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. +** Hence, the sqlite3_column_value() interface +** is normally only useful within the implementation of +** [application-defined SQL functions] or [virtual tables], not within +** top-level application code. ** -** These routines attempt to convert the value where appropriate. ^For -** example, if the internal representation is FLOAT and a text result +** These routines may attempt to convert the datatype of the result. +** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: @@ -4262,7 +5021,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** TEXT BLOB No change ** BLOB INTEGER [CAST] to INTEGER ** BLOB FLOAT [CAST] to REAL -** BLOB TEXT Add a zero terminator if needed +** BLOB TEXT [CAST] to TEXT, ensure zero terminator ** ** )^ ** @@ -4310,26 +5069,40 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings -** and BLOBs is freed automatically. Do not pass the pointers returned +** and BLOBs is freed automatically. Do not pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** -** ^(If a memory allocation error occurs during the evaluation of any -** of these routines, a default value is returned. The default value -** is either the integer 0, the floating point number 0.0, or a NULL -** pointer. Subsequent calls to [sqlite3_errcode()] will return -** [SQLITE_NOMEM].)^ +** As long as the input parameters are correct, these routines will only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_column_blob() +**
    • sqlite3_column_text() +**
    • sqlite3_column_text16() +**
    • sqlite3_column_bytes() +**
    • sqlite3_column_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); -SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object @@ -4389,17 +5162,17 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} -** KEYWORDS: {application-defined SQL function} -** KEYWORDS: {application-defined SQL functions} ** METHOD: sqlite3 ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior -** of existing SQL functions or aggregates. The only differences between -** these routines are the text encoding expected for -** the second parameter (the name of the function being created) -** and the presence or absence of a destructor callback for -** the application data pointer. +** of existing SQL functions or aggregates. The only differences between +** the three "sqlite3_create_function*" routines are the text encoding +** expected for the second parameter (the name of the function being +** created) and the presence or absence of a destructor callback for +** the application data pointer. Function sqlite3_create_window_function() +** is similar, but allows the user to supply the extra callback functions +** needed by [aggregate window functions]. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database @@ -4409,7 +5182,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ^The second parameter is the name of the SQL function to be created or ** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 ** representation, exclusive of the zero-terminator. ^Note that the name -** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. +** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. ** ^Any attempt to create a function with a longer name ** will result in [SQLITE_MISUSE] being returned. ** @@ -4424,7 +5197,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. The application should set this parameter to -** [SQLITE_UTF16LE] if the function implementation invokes +** [SQLITE_UTF16LE] if the function implementation invokes ** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the ** implementation invokes [sqlite3_value_text16be()] on an input, or ** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] @@ -4442,10 +5215,26 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** +** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY] +** flag, which if present prevents the function from being invoked from +** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions, +** index expressions, or the WHERE clause of partial indexes. +** +** For best security, the [SQLITE_DIRECTONLY] flag is recommended for +** all application-defined SQL functions that do not need to be +** used inside of triggers, view, CHECK constraints, or other elements of +** the database schema. This flags is especially recommended for SQL +** functions that have side effects or reveal internal application state. +** Without this flag, an attacker might be able to modify the schema of +** a database file to include invocations of the function with parameters +** chosen by the attacker, which the application will then execute when +** the database file is opened and read. +** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** -** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are +** ^The sixth, seventh and eighth parameters passed to the three +** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal @@ -4454,15 +5243,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** -** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, -** then it is destructor for the application data pointer. -** The destructor is invoked when the function is deleted, either by being -** overloaded or when the database connection closes.)^ -** ^The destructor is also invoked if the call to -** sqlite3_create_function_v2() fails. -** ^When the destructor callback of the tenth parameter is invoked, it -** is passed a single argument which is a copy of the application data -** pointer which was the fifth parameter to sqlite3_create_function_v2(). +** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue +** and xInverse) passed to sqlite3_create_window_function are pointers to +** C-language callbacks that implement the new function. xStep and xFinal +** must both be non-NULL. xValue and xInverse may either both be NULL, in +** which case a regular aggregate function is created, or must both be +** non-NULL, in which case the new function may be used as either an aggregate +** or aggregate window function. More details regarding the implementation +** of aggregate window functions are +** [user-defined window functions|available here]. +** +** ^(If the final parameter to sqlite3_create_function_v2() or +** sqlite3_create_window_function() is not NULL, then it is destructor for +** the application data pointer. The destructor is invoked when the function +** is deleted, either by being overloaded or when the database connection +** closes.)^ ^The destructor is also invoked if the call to +** sqlite3_create_function_v2() fails. ^When the destructor callback is +** invoked, it is passed a single argument which is a copy of the application +** data pointer which was the fifth parameter to sqlite3_create_function_v2(). ** ** ^It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of @@ -4472,7 +5270,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** nArg parameter is a better match than a function implementation with ** a negative nArg. ^A function where the preferred text encoding ** matches the database encoding is a better -** match than a function where the encoding is different. +** match than a function where the encoding is different. ** ^A function where the encoding difference is between UTF16le and UTF16be ** is a closer match than a function where the encoding difference is ** between UTF8 and UTF16. @@ -4515,6 +5313,18 @@ SQLITE_API int sqlite3_create_function_v2( void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*) ); +SQLITE_API int sqlite3_create_window_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) +); /* ** CAPI3REF: Text Encodings @@ -4532,19 +5342,79 @@ SQLITE_API int sqlite3_create_function_v2( /* ** CAPI3REF: Function Flags ** -** These constants may be ORed together with the +** These constants may be ORed together with the ** [SQLITE_UTF8 | preferred text encoding] as the fourth argument ** to [sqlite3_create_function()], [sqlite3_create_function16()], or ** [sqlite3_create_function_v2()]. +** +**
    +** [[SQLITE_DETERMINISTIC]]
    SQLITE_DETERMINISTIC
    +** The SQLITE_DETERMINISTIC flag means that the new function always gives +** the same output when the input parameters are the same. +** The [abs|abs() function] is deterministic, for example, but +** [randomblob|randomblob()] is not. Functions must +** be deterministic in order to be used in certain contexts such as +** with the WHERE clause of [partial indexes] or in [generated columns]. +** SQLite might also optimize deterministic functions by factoring them +** out of inner loops. +**
    +** +** [[SQLITE_DIRECTONLY]]
    SQLITE_DIRECTONLY
    +** The SQLITE_DIRECTONLY flag means that the function may only be invoked +** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in +** schema structures such as [CHECK constraints], [DEFAULT clauses], +** [expression indexes], [partial indexes], or [generated columns]. +** The SQLITE_DIRECTONLY flags is a security feature which is recommended +** for all [application-defined SQL functions], and especially for functions +** that have side-effects or that could potentially leak sensitive +** information. +**
    +** +** [[SQLITE_INNOCUOUS]]
    SQLITE_INNOCUOUS
    +** The SQLITE_INNOCUOUS flag means that the function is unlikely +** to cause problems even if misused. An innocuous function should have +** no side effects and should not depend on any values other than its +** input parameters. The [abs|abs() function] is an example of an +** innocuous function. +** The [load_extension() SQL function] is not innocuous because of its +** side effects. +**

    SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not +** exactly the same. The [random|random() function] is an example of a +** function that is innocuous but not deterministic. +**

    Some heightened security settings +** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF]) +** disable the use of SQL functions inside views and triggers and in +** schema structures such as [CHECK constraints], [DEFAULT clauses], +** [expression indexes], [partial indexes], and [generated columns] unless +** the function is tagged with SQLITE_INNOCUOUS. Most built-in functions +** are innocuous. Developers are advised to avoid using the +** SQLITE_INNOCUOUS flag for application-defined functions unless the +** function has been carefully audited and found to be free of potentially +** security-adverse side-effects and information-leaks. +**

    +** +** [[SQLITE_SUBTYPE]]
    SQLITE_SUBTYPE
    +** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call +** [sqlite3_value_subtype()] to inspect the sub-types of its arguments. +** Specifying this flag makes no difference for scalar or aggregate user +** functions. However, if it is not specified for a user-defined window +** function, then any sub-types belonging to arguments passed to the window +** function may be discarded before the window function is called (i.e. +** sqlite3_value_subtype() will always return 0). +**
    +**
    */ -#define SQLITE_DETERMINISTIC 0x800 +#define SQLITE_DETERMINISTIC 0x000000800 +#define SQLITE_DIRECTONLY 0x000080000 +#define SQLITE_SUBTYPE 0x000100000 +#define SQLITE_INNOCUOUS 0x000200000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain -** backwards compatibility with older code, these functions continue +** backwards compatibility with older code, these functions continue ** to be supported. However, new applications should avoid ** the use of these functions. To encourage programmers to avoid ** these functions, we will not explain what they do. @@ -4563,21 +5433,45 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** CAPI3REF: Obtaining SQL Values ** METHOD: sqlite3_value ** -** The C-language implementation of SQL functions and aggregates uses -** this set of interface routines to access the parameter values on -** the function or aggregate. -** -** The xFunc (for scalar functions) or xStep (for aggregates) parameters -** to [sqlite3_create_function()] and [sqlite3_create_function16()] -** define callbacks that implement the SQL functions and aggregates. -** The 3rd parameter to these callbacks is an array of pointers to -** [protected sqlite3_value] objects. There is one [sqlite3_value] object for -** each parameter to the SQL function. These routines are used to -** extract values from the [sqlite3_value] objects. +** Summary: +**
    +**
    sqlite3_value_blobBLOB value +**
    sqlite3_value_doubleREAL value +**
    sqlite3_value_int32-bit INTEGER value +**
    sqlite3_value_int6464-bit INTEGER value +**
    sqlite3_value_pointerPointer value +**
    sqlite3_value_textUTF-8 TEXT value +**
    sqlite3_value_text16UTF-16 TEXT value in +** the native byteorder +**
    sqlite3_value_text16beUTF-16be TEXT value +**
    sqlite3_value_text16leUTF-16le TEXT value +**
        +**
    sqlite3_value_bytesSize of a BLOB +** or a UTF-8 TEXT in bytes +**
    sqlite3_value_bytes16   +** →  Size of UTF-16 +** TEXT in bytes +**
    sqlite3_value_typeDefault +** datatype of the value +**
    sqlite3_value_numeric_type   +** →  Best numeric datatype of the value +**
    sqlite3_value_nochange   +** →  True if the column is unchanged in an UPDATE +** against a virtual table. +**
    sqlite3_value_frombind   +** →  True if value originated from a [bound parameter] +**
    +** +** Details: +** +** These routines extract type, size, and content information from +** [protected sqlite3_value] objects. Protected sqlite3_value objects +** are used to pass parameter information into the functions that +** implement [application-defined SQL functions] and [virtual tables]. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] -** object results in undefined behavior. +** is not threadsafe. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object @@ -4588,6 +5482,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** +** ^If [sqlite3_value] object V was initialized +** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)] +** and if X and Y are strings that compare equal according to strcmp(X,Y), +** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise, +** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** +** ^(The sqlite3_value_type(V) interface returns the +** [SQLITE_INTEGER | datatype code] for the initial datatype of the +** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ +** Other interfaces might change the datatype for an sqlite3_value object. +** For example, if the datatype is initially SQLITE_INTEGER and +** sqlite3_value_text(V) is called to extract a text value for that +** integer, then subsequent calls to sqlite3_value_type(V) might return +** SQLITE_TEXT. Whether or not a persistent internal datatype conversion +** occurs is undefined and may change from one release of SQLite to the next. +** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If @@ -4596,6 +5508,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** +** ^Within the [xUpdate] method of a [virtual table], the +** sqlite3_value_nochange(X) interface returns true if and only if +** the column corresponding to X is unchanged by the UPDATE operation +** that the xUpdate method call was invoked to implement and if +** and the prior [xColumn] method call that was invoked to extracted +** the value for that column returned without setting a result (probably +** because it queried [sqlite3_vtab_nochange()] and found that the column +** was unchanging). ^Within an [xUpdate] method, any value for which +** sqlite3_value_nochange(X) is true will in all other respects appear +** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other +** than within an [xUpdate] method call for an UPDATE statement, then +** the return value is arbitrary and meaningless. +** +** ^The sqlite3_value_frombind(X) interface returns non-zero if the +** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] +** interfaces. ^If X comes from an SQL literal value, or a table column, +** or an expression, then sqlite3_value_frombind(X) returns zero. +** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to @@ -4604,19 +5534,44 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. +** +** As long as the input parameter is correct, these routines can only +** fail if an out-of-memory error occurs during a format conversion. +** Only the following subset of interfaces are subject to out-of-memory +** errors: +** +**
      +**
    • sqlite3_value_blob() +**
    • sqlite3_value_text() +**
    • sqlite3_value_text16() +**
    • sqlite3_value_text16le() +**
    • sqlite3_value_text16be() +**
    • sqlite3_value_bytes() +**
    • sqlite3_value_bytes16() +**
    +** +** If an out-of-memory error occurs, then the return value from these +** routines is the same as if the column had contained an SQL NULL value. +** Valid SQL NULL returns can be distinguished from out-of-memory errors +** by invoking the [sqlite3_errcode()] immediately after the suspect +** return value is obtained and before any +** other SQLite interface is called on the same [database connection]. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes(sqlite3_value*); -SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); SQLITE_API int sqlite3_value_int(sqlite3_value*); SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*); SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); +SQLITE_API int sqlite3_value_nochange(sqlite3_value*); +SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -4627,10 +5582,6 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. -** -** SQLite makes no use of subtype itself. It merely passes the subtype -** from the result of one [application-defined SQL function] into the -** input of another. */ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*); @@ -4658,9 +5609,9 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*); ** Implementations of aggregate SQL functions use this ** routine to allocate memory for storing their state. ** -** ^The first time the sqlite3_aggregate_context(C,N) routine is called -** for a particular aggregate function, SQLite -** allocates N of memory, zeroes out that memory, and returns a pointer +** ^The first time the sqlite3_aggregate_context(C,N) routine is called +** for a particular aggregate function, SQLite allocates +** N bytes of memory, zeroes out that memory, and returns a pointer ** to the new memory. ^On second and subsequent calls to ** sqlite3_aggregate_context() for the same aggregate function instance, ** the same buffer is returned. Sqlite3_aggregate_context() is normally @@ -4671,19 +5622,19 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*); ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** -** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer +** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer ** when first called if N is less than or equal to zero or if a memory ** allocate error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the -** value of N in subsequent call to sqlite3_aggregate_context() within +** value of N in any subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ Within the xFinal callback, it is customary to set -** N=0 in calls to sqlite3_aggregate_context(C,N) so that no +** N=0 in calls to sqlite3_aggregate_context(C,N) so that no ** pointless memory allocations occur. ** -** ^SQLite automatically frees the memory allocated by +** ^SQLite automatically frees the memory allocated by ** sqlite3_aggregate_context() when the aggregate query concludes. ** ** The first parameter must be a copy of the @@ -4733,15 +5684,16 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** some circumstances the associated metadata may be preserved. An example ** of where this might be useful is in a regular-expression matching ** function. The compiled version of the regular expression can be stored as -** metadata associated with the pattern string. +** metadata associated with the pattern string. ** Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata -** associated by the sqlite3_set_auxdata() function with the Nth argument -** value to the application-defined function. ^If there is no metadata -** associated with the function argument, this sqlite3_get_auxdata() interface +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument +** value to the application-defined function. ^N is zero for the left-most +** function argument. ^If there is no metadata +** associated with the function argument, the sqlite3_get_auxdata(C,N) interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th @@ -4758,10 +5710,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** SQL statement)^, or **
  • ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or -**
  • ^(during the original sqlite3_set_auxdata() call when a memory +**
  • ^(during the original sqlite3_set_auxdata() call when a memory ** allocation error occurs.)^ ** -** Note the last bullet in particular. The destructor X in +** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the @@ -4772,6 +5724,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** +** The value of the N parameter to these interfaces should be non-negative. +** Future enhancements may make use of negative N values to define new +** kinds of function caching behavior. +** ** These routines must be called from the same thread in which ** the SQL function is running. */ @@ -4829,8 +5785,9 @@ typedef void (*sqlite3_destructor_type)(void*); ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() ** as the text of an error message. ^SQLite interprets the error ** message string from sqlite3_result_error() as UTF-8. ^SQLite -** interprets the string from sqlite3_result_error16() as UTF-16 in native -** byte order. ^If the third parameter to sqlite3_result_error() +** interprets the string from sqlite3_result_error16() as UTF-16 using +** the same [byte-order determination rules] as [sqlite3_bind_text16()]. +** ^If the third parameter to sqlite3_result_error() ** or sqlite3_result_error16() is negative then SQLite takes as the error ** message all text up through the first zero character. ** ^If the third parameter to sqlite3_result_error() or @@ -4895,9 +5852,28 @@ typedef void (*sqlite3_destructor_type)(void*); ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT -** then SQLite makes a copy of the result into space obtained from +** then SQLite makes a copy of the result into space obtained ** from [sqlite3_malloc()] before it returns. ** +** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and +** sqlite3_result_text16be() routines, and for sqlite3_result_text64() +** when the encoding is not UTF8, if the input UTF16 begins with a +** byte-order mark (BOM, U+FEFF) then the BOM is removed from the +** string and the rest of the string is interpreted according to the +** byte-order specified by the BOM. ^The byte-order specified by +** the BOM at the beginning of the text overrides the byte-order +** specified by the interface procedure. ^So, for example, if +** sqlite3_result_text16le() is invoked with text that begins +** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the +** first two bytes of input are skipped and the remaining input +** is interpreted as UTF16BE text. +** +** ^For UTF16 input text to the sqlite3_result_text16(), +** sqlite3_result_text16be(), sqlite3_result_text16le(), and +** sqlite3_result_text64() routines, if the text contains invalid +** UTF16 characters, the invalid characters might be converted +** into the unicode replacement character, U+FFFD. +** ** ^The sqlite3_result_value() interface sets the result of ** the application-defined function to be a copy of the ** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The @@ -4908,6 +5884,17 @@ typedef void (*sqlite3_destructor_type)(void*); ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** +** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an +** SQL NULL value, just like [sqlite3_result_null(C)], except that it +** also associates the host-language pointer P or type T with that +** NULL value such that the pointer can be retrieved within an +** [application-defined SQL function] using [sqlite3_value_pointer()]. +** ^If the D parameter is not NULL, then it is a pointer to a destructor +** for the P parameter. ^SQLite invokes D with P as its only argument +** when SQLite is finished with P. The T parameter should be a static +** string and preferably a string literal. The sqlite3_result_pointer() +** routine is part of the [pointer passing interface] added for SQLite 3.20.0. +** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. @@ -4931,6 +5918,7 @@ SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(* SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); @@ -4940,8 +5928,8 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); ** METHOD: sqlite3_context ** ** The sqlite3_result_subtype(C,T) function causes the subtype of -** the result from the [application-defined SQL function] with -** [sqlite3_context] C to be the value T. Only the lower 8 bits +** the result from the [application-defined SQL function] with +** [sqlite3_context] C to be the value T. Only the lower 8 bits ** of the subtype T are preserved in current versions of SQLite; ** higher order bits are discarded. ** The number of subtype bytes preserved by SQLite might increase @@ -4971,7 +5959,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); **
  • [SQLITE_UTF16_ALIGNED]. ** )^ ** ^The eTextRep argument determines the encoding of strings passed -** to the collating function callback, xCallback. +** to the collating function callback, xCompare. ** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep ** force strings to be UTF16 with native byte order. ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin @@ -4980,18 +5968,19 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); ** ^The fourth argument, pArg, is an application data pointer that is passed ** through as the first argument to the collating function callback. ** -** ^The fifth argument, xCallback, is a pointer to the collating function. +** ^The fifth argument, xCompare, is a pointer to the collating function. ** ^Multiple collating functions can be registered using the same name but ** with different eTextRep parameters and SQLite will use whichever ** function requires the least amount of data transformation. -** ^If the xCallback argument is NULL then the collating function is +** ^If the xCompare argument is NULL then the collating function is ** deleted. ^When all collating functions having the same name are deleted, ** that collation is no longer usable. ** -** ^The collating function callback is invoked with a copy of the pArg +** ^The collating function callback is invoked with a copy of the pArg ** application data pointer and with two strings in the encoding specified -** by the eTextRep argument. The collating function must return an -** integer that is negative, zero, or positive +** by the eTextRep argument. The two integer parameters to the collating +** function callback are the length of the two strings, in bytes. The collating +** function must return an integer that is negative, zero, or positive ** if the first string is less than, equal to, or greater than the second, ** respectively. A collating function must always return the same answer ** given the same inputs. If two or more collating functions are registered @@ -5008,7 +5997,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); ** ** ** If a collating function fails any of the above constraints and that -** collating function is registered and used, then the behavior of SQLite +** collating function is registered and used, then the behavior of SQLite ** is undefined. ** ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() @@ -5018,36 +6007,36 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); ** calls to the collation creation functions or when the ** [database connection] is closed using [sqlite3_close()]. ** -** ^The xDestroy callback is not called if the +** ^The xDestroy callback is not called if the ** sqlite3_create_collation_v2() function fails. Applications that invoke -** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should +** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should ** check the return code and dispose of the application data pointer ** themselves rather than expecting SQLite to deal with it for them. -** This is different from every other SQLite interface. The inconsistency -** is unfortunate but cannot be changed without breaking backwards +** This is different from every other SQLite interface. The inconsistency +** is unfortunate but cannot be changed without breaking backwards ** compatibility. ** ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. */ SQLITE_API int sqlite3_create_collation( - sqlite3*, - const char *zName, - int eTextRep, + sqlite3*, + const char *zName, + int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); SQLITE_API int sqlite3_create_collation_v2( - sqlite3*, - const char *zName, - int eTextRep, + sqlite3*, + const char *zName, + int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDestroy)(void*) ); SQLITE_API int sqlite3_create_collation16( - sqlite3*, + sqlite3*, const void *zName, - int eTextRep, + int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); @@ -5080,67 +6069,22 @@ SQLITE_API int sqlite3_create_collation16( ** [sqlite3_create_collation_v2()]. */ SQLITE_API int sqlite3_collation_needed( - sqlite3*, - void*, + sqlite3*, + void*, void(*)(void*,sqlite3*,int eTextRep,const char*) ); SQLITE_API int sqlite3_collation_needed16( - sqlite3*, + sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) ); -#ifdef SQLITE_HAS_CODEC -/* -** Specify the key for an encrypted database. This routine should be -** called right after sqlite3_open(). -** -** The code to implement this API is not available in the public release -** of SQLite. -*/ -SQLITE_API int sqlite3_key( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The key */ -); -SQLITE_API int sqlite3_key_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The key */ -); - -/* -** Change the key on an open database. If the current database is not -** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the -** database is decrypted. -** -** The code to implement this API is not available in the public release -** of SQLite. -*/ -SQLITE_API int sqlite3_rekey( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The new key */ -); -SQLITE_API int sqlite3_rekey_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The new key */ -); - +#ifdef SQLITE_ENABLE_CEROD /* -** Specify the activation key for a SEE database. Unless -** activated, none of the SEE routines will work. +** Specify the activation key for a CEROD database. Unless +** activated, none of the CEROD routines will work. */ -SQLITE_API void sqlite3_activate_see( - const char *zPassPhrase /* Activation phrase */ -); -#endif - -#ifdef SQLITE_ENABLE_CEROD -/* -** Specify the activation key for a CEROD database. Unless -** activated, none of the CEROD routines will work. -*/ -SQLITE_API void sqlite3_activate_cerod( +SQLITE_API void sqlite3_activate_cerod( const char *zPassPhrase /* Activation phrase */ ); #endif @@ -5193,7 +6137,7 @@ SQLITE_API int sqlite3_sleep(int); ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string -** that this variable points to is held in memory obtained from +** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be @@ -5250,7 +6194,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory; ** ^The [data_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [data_store_directory pragma] always assumes that any string -** that this variable points to is held in memory obtained from +** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be @@ -5259,6 +6203,41 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory; */ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory; +/* +** CAPI3REF: Win32 Specific Interface +** +** These interfaces are available only on Windows. The +** [sqlite3_win32_set_directory] interface is used to set the value associated +** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to +** zValue, depending on the value of the type parameter. The zValue parameter +** should be NULL to cause the previous value to be freed via [sqlite3_free]; +** a non-NULL value will be copied into memory obtained from [sqlite3_malloc] +** prior to being used. The [sqlite3_win32_set_directory] interface returns +** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported, +** or [SQLITE_NOMEM] if memory could not be allocated. The value of the +** [sqlite3_data_directory] variable is intended to act as a replacement for +** the current directory on the sub-platforms of Win32 where that concept is +** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and +** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the +** sqlite3_win32_set_directory interface except the string parameter must be +** UTF-8 or UTF-16, respectively. +*/ +SQLITE_API int sqlite3_win32_set_directory( + unsigned long type, /* Identifier for directory being set or reset */ + void *zValue /* New value for directory being set or reset */ +); +SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); +SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); + +/* +** CAPI3REF: Win32 Directory Types +** +** These macros are only available on Windows. They define the allowed values +** for the type argument to the [sqlite3_win32_set_directory] interface. +*/ +#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1 +#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2 + /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} @@ -5300,16 +6279,31 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** CAPI3REF: Return The Filename For A Database Connection ** METHOD: sqlite3 ** -** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename -** associated with database N of connection D. ^The main database file -** has the name "main". If there is no attached database N on the database +** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename +** associated with database N of connection D. +** ^If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then -** a NULL pointer is returned. +** this function will return either a NULL pointer or an empty string. +** +** ^The string value returned by this routine is owned and managed by +** the database connection. ^The value will be valid until the database N +** is [DETACH]-ed or until the database connection closes. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename ** will be an absolute pathname, even if the filename used ** to open the database originally was a URI or relative pathname. +** +** If the filename pointer returned by this routine is not NULL, then it +** can be used as the filename input parameter to these routines: +**
      +**
    • [sqlite3_uri_parameter()] +**
    • [sqlite3_uri_boolean()] +**
    • [sqlite3_uri_int64()] +**
    • [sqlite3_filename_database()] +**
    • [sqlite3_filename_journal()] +**
    • [sqlite3_filename_wal()] +**
    */ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); @@ -5323,6 +6317,57 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +/* +** CAPI3REF: Determine the transaction state of a database +** METHOD: sqlite3 +** +** ^The sqlite3_txn_state(D,S) interface returns the current +** [transaction state] of schema S in database connection D. ^If S is NULL, +** then the highest transaction state of any schema on database connection D +** is returned. Transaction states are (in order of lowest to highest): +**
      +**
    1. SQLITE_TXN_NONE +**
    2. SQLITE_TXN_READ +**
    3. SQLITE_TXN_WRITE +**
    +** ^If the S argument to sqlite3_txn_state(D,S) is not the name of +** a valid schema, then -1 is returned. +*/ +SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); + +/* +** CAPI3REF: Allowed return values from [sqlite3_txn_state()] +** KEYWORDS: {transaction state} +** +** These constants define the current transaction state of a database file. +** ^The [sqlite3_txn_state(D,S)] interface returns one of these +** constants in order to describe the transaction state of schema S +** in [database connection] D. +** +**
    +** [[SQLITE_TXN_NONE]]
    SQLITE_TXN_NONE
    +**
    The SQLITE_TXN_NONE state means that no transaction is currently +** pending.
    +** +** [[SQLITE_TXN_READ]]
    SQLITE_TXN_READ
    +**
    The SQLITE_TXN_READ state means that the database is currently +** in a read transaction. Content has been read from the database file +** but nothing in the database file has changed. The transaction state +** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** no other conflicting concurrent write transactions. The transaction +** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or +** [COMMIT].
    +** +** [[SQLITE_TXN_WRITE]]
    SQLITE_TXN_WRITE
    +**
    The SQLITE_TXN_WRITE state means that the database is currently +** in a write transaction. Content has been written to the database file +** but has not yet committed. The transaction state will change to +** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
    +*/ +#define SQLITE_TXN_NONE 0 +#define SQLITE_TXN_READ 1 +#define SQLITE_TXN_WRITE 2 + /* ** CAPI3REF: Find the next prepared statement ** METHOD: sqlite3 @@ -5389,6 +6434,72 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); +/* +** CAPI3REF: Autovacuum Compaction Amount Callback +** METHOD: sqlite3 +** +** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback +** function C that is invoked prior to each autovacuum of the database +** file. ^The callback is passed a copy of the generic data pointer (P), +** the schema-name of the attached database that is being autovacuumed, +** the the size of the database file in pages, the number of free pages, +** and the number of bytes per page, respectively. The callback should +** return the number of free pages that should be removed by the +** autovacuum. ^If the callback returns zero, then no autovacuum happens. +** ^If the value returned is greater than or equal to the number of +** free pages, then a complete autovacuum happens. +** +**

    ^If there are multiple ATTACH-ed database files that are being +** modified as part of a transaction commit, then the autovacuum pages +** callback is invoked separately for each file. +** +**

    The callback is not reentrant. The callback function should +** not attempt to invoke any other SQLite interface. If it does, bad +** things may happen, including segmentation faults and corrupt database +** files. The callback function should be a simple function that +** does some arithmetic on its input parameters and returns a result. +** +** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional +** destructor for the P parameter. ^If X is not NULL, then X(P) is +** invoked whenever the database connection closes or when the callback +** is overwritten by another invocation of sqlite3_autovacuum_pages(). +** +**

    ^There is only one autovacuum pages callback per database connection. +** ^Each call to the sqlite3_autovacuum_pages() interface overrides all +** previous invocations for that database connection. ^If the callback +** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer, +** then the autovacuum steps callback is cancelled. The return value +** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might +** be some other error code if something goes wrong. The current +** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other +** return codes might be added in future releases. +** +**

    If no autovacuum pages callback is specified (the usual case) or +** a NULL pointer is provided for the callback, +** then the default behavior is to vacuum all free pages. So, in other +** words, the default behavior is the same as if the callback function +** were something like this: +** +**

    +**     unsigned int demonstration_autovac_pages_callback(
    +**       void *pClientData,
    +**       const char *zSchema,
    +**       unsigned int nDbPage,
    +**       unsigned int nFreePage,
    +**       unsigned int nBytePerPage
    +**     ){
    +**       return nFreePage;
    +**     }
    +** 
    +*/ +SQLITE_API int sqlite3_autovacuum_pages( + sqlite3 *db, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, + void(*)(void*) +); + + /* ** CAPI3REF: Data Change Notification Callbacks ** METHOD: sqlite3 @@ -5413,7 +6524,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are -** modified (i.e. sqlite_master and sqlite_sequence).)^ +** modified (i.e. sqlite_sequence).)^ ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook @@ -5439,7 +6550,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** and [sqlite3_preupdate_hook()] interfaces. */ SQLITE_API void *sqlite3_update_hook( - sqlite3*, + sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* ); @@ -5453,25 +6564,29 @@ SQLITE_API void *sqlite3_update_hook( ** and disabled if the argument is false.)^ ** ** ^Cache sharing is enabled and disabled for an entire process. -** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). +** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]). ** In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. -** Existing database connections continue use the sharing mode +** Existing database connections continue to use the sharing mode ** that was in effect at the time they were opened.)^ ** ** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled ** successfully. An [error code] is returned otherwise.)^ ** -** ^Shared cache is disabled by default. But this might change in -** future releases of SQLite. Applications that care about shared -** cache setting should set it explicitly. +** ^Shared cache is disabled by default. It is recommended that it stay +** that way. In other words, do not use this routine. This interface +** continues to be provided for historical compatibility, but its use is +** discouraged. Any use of shared cache is discouraged. If shared cache +** must be used, it is recommended that shared cache only be enabled for +** individual database connections using the [sqlite3_open_v2()] interface +** with the [SQLITE_OPEN_SHAREDCACHE] flag. ** ** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0 -** and will always return SQLITE_MISUSE. On those systems, -** shared cache mode should be enabled per-database connection via +** and will always return SQLITE_MISUSE. On those systems, +** shared cache mode should be enabled per-database connection via ** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE]. ** ** This interface is threadsafe on processors where writing a @@ -5514,6 +6629,9 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size ** +** These interfaces impose limits on the amount of heap memory that will be +** by all database connections within a single process. +** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. ** ^SQLite strives to keep heap memory utilization below the soft heap @@ -5521,23 +6639,44 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** as heap memory usages approaches the limit. ** ^The soft heap limit is "soft" because even though SQLite strives to stay ** below the limit, it will exceed the limit rather than generate -** an [SQLITE_NOMEM] error. In other words, the soft heap limit +** an [SQLITE_NOMEM] error. In other words, the soft heap limit ** is advisory only. ** -** ^The return value from sqlite3_soft_heap_limit64() is the size of -** the soft heap limit prior to the call, or negative in the case of an -** error. ^If the argument N is negative -** then no change is made to the soft heap limit. Hence, the current -** size of the soft heap limit can be determined by invoking -** sqlite3_soft_heap_limit64() with a negative argument. +** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of +** N bytes on the amount of memory that will be allocated. ^The +** sqlite3_hard_heap_limit64(N) interface is similar to +** sqlite3_soft_heap_limit64(N) except that memory allocations will fail +** when the hard heap limit is reached. ** -** ^If the argument N is zero then the soft heap limit is disabled. -** -** ^(The soft heap limit is not enforced in the current implementation +** ^The return value from both sqlite3_soft_heap_limit64() and +** sqlite3_hard_heap_limit64() is the size of +** the heap limit prior to the call, or negative in the case of an +** error. ^If the argument N is negative +** then no change is made to the heap limit. Hence, the current +** size of heap limits can be determined by invoking +** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1). +** +** ^Setting the heap limits to zero disables the heap limiter mechanism. +** +** ^The soft heap limit may not be greater than the hard heap limit. +** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N) +** is invoked with a value of N that is greater than the hard heap limit, +** the the soft heap limit is set to the value of the hard heap limit. +** ^The soft heap limit is automatically enabled whenever the hard heap +** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and +** the soft heap limit is outside the range of 1..N, then the soft heap +** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the +** hard heap limit is enabled makes the soft heap limit equal to the +** hard heap limit. +** +** The memory allocation limits can also be adjusted using +** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit]. +** +** ^(The heap limits are not enforced in the current implementation ** if one or more of following conditions are true: ** **
      -**
    • The soft heap limit is set to zero. +**
    • The limit value is set to zero. **
    • Memory accounting is disabled using a combination of the ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. @@ -5548,21 +6687,11 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*); ** from the heap. **
    )^ ** -** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), -** the soft heap limit is enforced -** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] -** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], -** the soft heap limit is enforced on every memory allocation. Without -** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced -** when memory is allocated by the page cache. Testing suggests that because -** the page cache is the predominate memory user in SQLite, most -** applications will achieve adequate soft heap limit enforcement without -** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. -** -** The circumstances under which SQLite will enforce the soft heap limit may +** The circumstances under which SQLite will enforce the heap limits may ** changes in future releases of SQLite. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); +SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface @@ -5586,11 +6715,13 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns -** SQLITE_ERROR and if the specified column does not exist. +** SQLITE_ERROR if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a ** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it -** does not. +** does not. If the table name parameter T in a call to +** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is +** undefined behavior. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database @@ -5624,7 +6755,7 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** ** ^If the specified table is actually a view, an [error code] is returned. ** -** ^If the specified column is "rowid", "oid" or "_rowid_" and the table +** ^If the specified column is "rowid", "oid" or "_rowid_" and the table ** is not a [WITHOUT ROWID] table and an ** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output ** parameters are set for the explicitly declared column. ^(If there is no @@ -5690,7 +6821,7 @@ SQLITE_API int sqlite3_table_column_metadata( ** prior to calling this API, ** otherwise an error will be returned. ** -** Security warning: It is recommended that the +** Security warning: It is recommended that the ** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this ** interface. The use of the [sqlite3_enable_load_extension()] interface ** should be avoided. This will keep the SQL function [load_extension()] @@ -5726,7 +6857,7 @@ SQLITE_API int sqlite3_load_extension( ** to enable or disable only the C-API.)^ ** ** Security warning: It is recommended that extension loading -** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method +** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method ** rather than this interface, so the [load_extension()] SQL function ** remains disabled. This will prevent SQL injections from giving attackers ** access to extension loading capabilities. @@ -5777,7 +6908,7 @@ SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)); ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the ** initialization routine X that was registered using a prior call to ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] -** routine returns 1 if initialization routine X was successfully +** routine returns 1 if initialization routine X was successfully ** unregistered and it returns 0 if X was not on the list of initialization ** routines. */ @@ -5812,8 +6943,8 @@ typedef struct sqlite3_module sqlite3_module; ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** -** This structure, sometimes called a "virtual table module", -** defines the implementation of a [virtual tables]. +** This structure, sometimes called a "virtual table module", +** defines the implementation of a [virtual table]. ** This structure consists mostly of methods for the module. ** ** ^A virtual table module is created by filling in a persistent @@ -5852,11 +6983,14 @@ struct sqlite3_module { void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); - /* The methods above are in version 1 of the sqlite_module object. Those + /* The methods above are in version 1 of the sqlite_module object. Those ** below are for version 2 and greater. */ int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. + ** Those below are for version 3 and greater. */ + int (*xShadowName)(const char*); }; /* @@ -5899,7 +7033,7 @@ struct sqlite3_module { ** required by SQLite. If the table has at least 64 columns and any column ** to the right of the first 63 is required, then bit 63 of colUsed is also ** set. In other words, column iCol may be required if the expression -** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to +** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to ** non-zero. ** ** The [xBestIndex] method must fill aConstraintUsage[] with information @@ -5907,7 +7041,13 @@ struct sqlite3_module { ** the right-hand side of the corresponding aConstraint[] is evaluated ** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit ** is true, then the constraint is assumed to be fully handled by the -** virtual table and is not checked again by SQLite.)^ +** virtual table and might not be checked again by the byte code.)^ ^(The +** aConstraintUsage[].omit flag is an optimization hint. When the omit flag +** is left in its default setting of false, the constraint will always be +** checked separately in byte code. If the omit flag is change to true, then +** the constraint may or may not be checked in byte code. In other words, +** when the omit flag is true there is no guarantee that the constraint will +** not be checked again using byte code.)^ ** ** ^The idxNum and idxPtr values are recorded and passed into the ** [xFilter] method. @@ -5920,17 +7060,17 @@ struct sqlite3_module { ** ** ^The estimatedCost value is an estimate of the cost of a particular ** strategy. A cost of N indicates that the cost of the strategy is similar -** to a linear scan of an SQLite table with N rows. A cost of log(N) +** to a linear scan of an SQLite table with N rows. A cost of log(N) ** indicates that the expense of the operation is similar to that of a ** binary search on a unique indexed field of an SQLite table with N rows. ** ** ^The estimatedRows value is an estimate of the number of rows that ** will be returned by the strategy. ** -** The xBestIndex method may optionally populate the idxFlags field with a +** The xBestIndex method may optionally populate the idxFlags field with a ** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - ** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite -** assumes that the strategy may visit at most one row. +** assumes that the strategy may visit at most one row. ** ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then ** SQLite also assumes that if a call to the xUpdate() method is made as @@ -5943,14 +7083,14 @@ struct sqlite3_module { ** the xUpdate method are automatically rolled back by SQLite. ** ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info -** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). +** structure for SQLite [version 3.8.2] ([dateof:3.8.2]). ** If a virtual table extension is -** used with an SQLite version earlier than 3.8.2, the results of attempting -** to read or write the estimatedRows field are undefined (but are likely -** to included crashing the application). The estimatedRows field should +** used with an SQLite version earlier than 3.8.2, the results of attempting +** to read or write the estimatedRows field are undefined (but are likely +** to include crashing the application). The estimatedRows field should ** therefore only be used if [sqlite3_libversion_number()] returns a ** value greater than or equal to 3008002. Similarly, the idxFlags field -** was added for [version 3.9.0] ([dateof:3.9.0]). +** was added for [version 3.9.0] ([dateof:3.9.0]). ** It may therefore only be used if ** sqlite3_libversion_number() returns a value greater than or equal to ** 3009000. @@ -5989,26 +7129,68 @@ struct sqlite3_index_info { /* ** CAPI3REF: Virtual Table Scan Flags +** +** Virtual table implementations are allowed to set the +** [sqlite3_index_info].idxFlags field to some combination of +** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** -** These macros defined the allowed values for the +** These macros define the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents -** an operator that is part of a constraint term in the wHERE clause of +** an operator that is part of a constraint term in the WHERE clause of ** a query that uses a [virtual table]. -*/ -#define SQLITE_INDEX_CONSTRAINT_EQ 2 -#define SQLITE_INDEX_CONSTRAINT_GT 4 -#define SQLITE_INDEX_CONSTRAINT_LE 8 -#define SQLITE_INDEX_CONSTRAINT_LT 16 -#define SQLITE_INDEX_CONSTRAINT_GE 32 -#define SQLITE_INDEX_CONSTRAINT_MATCH 64 -#define SQLITE_INDEX_CONSTRAINT_LIKE 65 -#define SQLITE_INDEX_CONSTRAINT_GLOB 66 -#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +** +** ^The left-hand operand of the operator is given by the corresponding +** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand +** operand is the rowid. +** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET +** operators have no left-hand operand, and so for those operators the +** corresponding aConstraint[].iColumn is meaningless and should not be +** used. +** +** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through +** value 255 are reserved to represent functions that are overloaded +** by the [xFindFunction|xFindFunction method] of the virtual table +** implementation. +** +** The right-hand operands for each constraint might be accessible using +** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand +** operand is only available if it appears as a single constant literal +** in the input SQL. If the right-hand operand is another column or an +** expression (even a constant expression) or a parameter, then the +** sqlite3_vtab_rhs_value() probably will not be able to extract it. +** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and +** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand +** and hence calls to sqlite3_vtab_rhs_value() for those operators will +** always return SQLITE_NOTFOUND. +** +** The collating sequence to be used for comparison can be found using +** the [sqlite3_vtab_collation()] interface. For most real-world virtual +** tables, the collating sequence of constraints does not matter (for example +** because the constraints are numeric) and so the sqlite3_vtab_collation() +** interface is no commonly needed. +*/ +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 +#define SQLITE_INDEX_CONSTRAINT_LIKE 65 +#define SQLITE_INDEX_CONSTRAINT_GLOB 66 +#define SQLITE_INDEX_CONSTRAINT_REGEXP 67 +#define SQLITE_INDEX_CONSTRAINT_NE 68 +#define SQLITE_INDEX_CONSTRAINT_ISNOT 69 +#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 +#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 +#define SQLITE_INDEX_CONSTRAINT_IS 72 +#define SQLITE_INDEX_CONSTRAINT_LIMIT 73 +#define SQLITE_INDEX_CONSTRAINT_OFFSET 74 +#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation @@ -6020,7 +7202,7 @@ struct sqlite3_index_info { ** preexisting [virtual table] for the module. ** ** ^The module name is registered on the [database connection] specified -** by the first parameter. ^The name of the module is given by the +** by the first parameter. ^The name of the module is given by the ** second parameter. ^The third parameter is a pointer to ** the implementation of the [virtual table module]. ^The fourth ** parameter is an arbitrary client data pointer that is passed through @@ -6035,6 +7217,12 @@ struct sqlite3_index_info { ** ^The sqlite3_create_module() ** interface is equivalent to sqlite3_create_module_v2() with a NULL ** destructor. +** +** ^If the third parameter (the pointer to the sqlite3_module object) is +** NULL then no new module is created and any existing modules with the +** same name are dropped. +** +** See also: [sqlite3_drop_modules()] */ SQLITE_API int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ @@ -6050,6 +7238,23 @@ SQLITE_API int sqlite3_create_module_v2( void(*xDestroy)(void*) /* Module destructor function */ ); +/* +** CAPI3REF: Remove Unnecessary Virtual Table Implementations +** METHOD: sqlite3 +** +** ^The sqlite3_drop_modules(D,L) interface removes all virtual +** table modules from database connection D except those named on list L. +** The L parameter must be either NULL or a pointer to an array of pointers +** to strings where the array is terminated by a single NULL pointer. +** ^If the L parameter is NULL, then all virtual table modules are removed. +** +** See also: [sqlite3_create_module()] +*/ +SQLITE_API int sqlite3_drop_modules( + sqlite3 *db, /* Remove modules from this connection */ + const char **azKeep /* Except, do not remove the ones named here */ +); + /* ** CAPI3REF: Virtual Table Instance Object ** KEYWORDS: sqlite3_vtab @@ -6112,7 +7317,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); ** METHOD: sqlite3 ** ** ^(Virtual tables can provide alternative implementations of functions -** using the [xFindFunction] method of the [virtual table module]. +** using the [xFindFunction] method of the [virtual table module]. ** But global versions of those functions ** must exist in order to be overloaded.)^ ** @@ -6163,7 +7368,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** )^ ** -** ^(Parameter zDb is not the filename that contains the database, but +** ^(Parameter zDb is not the filename that contains the database, but ** rather the symbolic name of the database. For attached databases, this is ** the name that appears after the AS keyword in the [ATTACH] statement. ** For the main database file, the database name is "main". For TEMP @@ -6176,28 +7381,28 @@ typedef struct sqlite3_blob sqlite3_blob; ** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored ** in *ppBlob. Otherwise an [error code] is returned and, unless the error ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided -** the API is not misused, it is always safe to call [sqlite3_blob_close()] +** the API is not misused, it is always safe to call [sqlite3_blob_close()] ** on *ppBlob after this function it returns. ** ** This function fails with SQLITE_ERROR if any of the following are true: **
      -**
    • ^(Database zDb does not exist)^, -**
    • ^(Table zTable does not exist within database zDb)^, -**
    • ^(Table zTable is a WITHOUT ROWID table)^, +**
    • ^(Database zDb does not exist)^, +**
    • ^(Table zTable does not exist within database zDb)^, +**
    • ^(Table zTable is a WITHOUT ROWID table)^, **
    • ^(Column zColumn does not exist)^, **
    • ^(Row iRow is not present in the table)^, **
    • ^(The specified column of row iRow contains a value that is not ** a TEXT or BLOB value)^, -**
    • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE +**
    • ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE ** constraint and the blob is being opened for read/write access)^, -**
    • ^([foreign key constraints | Foreign key constraints] are enabled, +**
    • ^([foreign key constraints | Foreign key constraints] are enabled, ** column zColumn is part of a [child key] definition and the blob is ** being opened for read/write access)^. **
    ** -** ^Unless it returns SQLITE_MISUSE, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** ^Unless it returns SQLITE_MISUSE, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** A BLOB referenced by sqlite3_blob_open() may be read using the ** [sqlite3_blob_read()] interface and modified by using @@ -6223,7 +7428,7 @@ typedef struct sqlite3_blob sqlite3_blob; ** blob. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces -** and the built-in [zeroblob] SQL function may be used to create a +** and the built-in [zeroblob] SQL function may be used to create a ** zero-filled blob to read or write using the incremental-blob interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually @@ -6273,7 +7478,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); ** DESTRUCTOR: sqlite3_blob ** ** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed -** unconditionally. Even if this routine returns an error code, the +** unconditionally. Even if this routine returns an error code, the ** handle is still closed.)^ ** ** ^If the blob handle being closed was opened for read-write access, and if @@ -6283,10 +7488,10 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); ** code is returned and the transaction rolled back. ** ** Calling this function with an argument that is not a NULL pointer or an -** open blob handle results in undefined behaviour. ^Calling this routine -** with a null pointer (such as would be returned by a failed call to +** open blob handle results in undefined behaviour. ^Calling this routine +** with a null pointer (such as would be returned by a failed call to ** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function -** is passed a valid open blob handle, the values returned by the +** is passed a valid open blob handle, the values returned by the ** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning. */ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); @@ -6295,7 +7500,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); ** CAPI3REF: Return The Size Of An Open BLOB ** METHOD: sqlite3_blob ** -** ^Returns the size in bytes of the BLOB accessible via the +** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The ** incremental blob I/O routines can only read or overwriting existing ** blob content; they cannot change the size of a blob. @@ -6346,9 +7551,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); ** ** ^(On success, sqlite3_blob_write() returns SQLITE_OK. ** Otherwise, an [error code] or an [extended error code] is returned.)^ -** ^Unless SQLITE_MISUSE is returned, this function sets the -** [database connection] error code and message accessible via -** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. +** ^Unless SQLITE_MISUSE is returned, this function sets the +** [database connection] error code and message accessible via +** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** ^If the [BLOB handle] passed as the first argument was not opened for ** writing (the flags parameter to [sqlite3_blob_open()] was zero), @@ -6357,9 +7562,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); ** This function may only modify the contents of the BLOB; it is ** not possible to increase the size of a BLOB using this API. ** ^If offset iOffset is less than N bytes from the end of the BLOB, -** [SQLITE_ERROR] is returned and no data is written. The size of the -** BLOB (and hence the maximum value of N+iOffset) can be determined -** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less +** [SQLITE_ERROR] is returned and no data is written. The size of the +** BLOB (and hence the maximum value of N+iOffset) can be determined +** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less ** than zero [SQLITE_ERROR] is returned and no data is written. ** ** ^An attempt to write to an expired [BLOB handle] fails with an @@ -6453,7 +7658,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); **
      **
    • SQLITE_MUTEX_FAST **
    • SQLITE_MUTEX_RECURSIVE -**
    • SQLITE_MUTEX_STATIC_MASTER +**
    • SQLITE_MUTEX_STATIC_MAIN **
    • SQLITE_MUTEX_STATIC_MEM **
    • SQLITE_MUTEX_STATIC_OPEN **
    • SQLITE_MUTEX_STATIC_PRNG @@ -6511,7 +7716,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() ** will always return SQLITE_BUSY. The SQLite core only ever uses -** sqlite3_mutex_try() as an optimization so this is acceptable +** sqlite3_mutex_try() as an optimization so this is acceptable ** behavior.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was @@ -6576,7 +7781,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); ** The only difference is that the public sqlite3_XXX functions enumerated ** above silently ignore any invocations that pass a NULL pointer instead ** of a valid mutex handle. The implementations of the methods defined -** by this structure are not required to handle this case, the results +** by this structure are not required to handle this case. The results ** of passing a NULL pointer instead of a valid mutex handle are undefined ** (i.e. it is acceptable to provide an implementation that segfaults if ** it is passed a NULL pointer). @@ -6655,7 +7860,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 -#define SQLITE_MUTEX_STATIC_MASTER 2 +#define SQLITE_MUTEX_STATIC_MAIN 2 #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ @@ -6670,11 +7875,15 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); #define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */ #define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */ +/* Legacy compatibility: */ +#define SQLITE_MUTEX_STATIC_MASTER 2 + + /* ** CAPI3REF: Retrieve the mutex for a database connection ** METHOD: sqlite3 ** -** ^This interface returns a pointer the [sqlite3_mutex] object that +** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. ** ^If the [threading mode] is Single-thread or Multi-thread then this @@ -6685,6 +7894,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** METHOD: sqlite3 +** KEYWORDS: {file control} ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated @@ -6699,11 +7909,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** -** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes +** A few opcodes for [sqlite3_file_control()] are handled directly +** by the SQLite core and never invoke the +** sqlite3_io_methods.xFileControl method. +** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into -** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER -** case is a short-circuit path which does not actually invoke the -** underlying sqlite3_io_methods.xFileControl method. +** the space pointed to by the 4th parameter. The +** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns +** the [sqlite3_file] object associated with the journal file instead of +** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns +** a pointer to the underlying [sqlite3_vfs] object for the file. +** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter +** from the pager. ** ** ^If the second parameter (zDbName) does not match the name of any ** open database file, then SQLITE_ERROR is returned. ^This error @@ -6713,7 +7930,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); ** an incorrect zDbName and an SQLITE_ERROR return from the underlying ** xFileControl method. ** -** See also: [SQLITE_FCNTL_LOCKSTATE] +** See also: [file control opcodes] */ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); @@ -6750,17 +7967,18 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 -#define SQLITE_TESTCTRL_PRNG_RESET 7 +#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */ #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 -#define SQLITE_TESTCTRL_RESERVE 14 +#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 -#define SQLITE_TESTCTRL_ISKEYWORD 16 -#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 +#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ +#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ +#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 @@ -6770,7 +7988,198 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 -#define SQLITE_TESTCTRL_LAST 25 +#define SQLITE_TESTCTRL_PARSER_COVERAGE 26 +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_PRNG_SEED 28 +#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 +#define SQLITE_TESTCTRL_SEEK_COUNT 30 +#define SQLITE_TESTCTRL_TRACEFLAGS 31 +#define SQLITE_TESTCTRL_TUNE 32 +#define SQLITE_TESTCTRL_LOGEST 33 +#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */ + +/* +** CAPI3REF: SQL Keyword Checking +** +** These routines provide access to the set of SQL language keywords +** recognized by SQLite. Applications can uses these routines to determine +** whether or not a specific identifier needs to be escaped (for example, +** by enclosing in double-quotes) so as not to confuse the parser. +** +** The sqlite3_keyword_count() interface returns the number of distinct +** keywords understood by SQLite. +** +** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and +** makes *Z point to that keyword expressed as UTF8 and writes the number +** of bytes in the keyword into *L. The string that *Z points to is not +** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns +** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z +** or L are NULL or invalid pointers then calls to +** sqlite3_keyword_name(N,Z,L) result in undefined behavior. +** +** The sqlite3_keyword_check(Z,L) interface checks to see whether or not +** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero +** if it is and zero if not. +** +** The parser used by SQLite is forgiving. It is often possible to use +** a keyword as an identifier as long as such use does not result in a +** parsing ambiguity. For example, the statement +** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and +** creates a new table named "BEGIN" with three columns named +** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid +** using keywords as identifiers. Common techniques used to avoid keyword +** name collisions include: +**
        +**
      • Put all identifier names inside double-quotes. This is the official +** SQL way to escape identifier names. +**
      • Put identifier names inside [...]. This is not standard SQL, +** but it is what SQL Server does and so lots of programmers use this +** technique. +**
      • Begin every identifier with the letter "Z" as no SQL keywords start +** with "Z". +**
      • Include a digit somewhere in every identifier name. +**
      +** +** Note that the number of keywords understood by SQLite can depend on +** compile-time options. For example, "VACUUM" is not a keyword if +** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also, +** new keywords may be added to future releases of SQLite. +*/ +SQLITE_API int sqlite3_keyword_count(void); +SQLITE_API int sqlite3_keyword_name(int,const char**,int*); +SQLITE_API int sqlite3_keyword_check(const char*,int); + +/* +** CAPI3REF: Dynamic String Object +** KEYWORDS: {dynamic string} +** +** An instance of the sqlite3_str object contains a dynamically-sized +** string under construction. +** +** The lifecycle of an sqlite3_str object is as follows: +**
        +**
      1. ^The sqlite3_str object is created using [sqlite3_str_new()]. +**
      2. ^Text is appended to the sqlite3_str object using various +** methods, such as [sqlite3_str_appendf()]. +**
      3. ^The sqlite3_str object is destroyed and the string it created +** is returned using the [sqlite3_str_finish()] interface. +**
      +*/ +typedef struct sqlite3_str sqlite3_str; + +/* +** CAPI3REF: Create A New Dynamic String Object +** CONSTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_new(D)] interface allocates and initializes +** a new [sqlite3_str] object. To avoid memory leaks, the object returned by +** [sqlite3_str_new()] must be freed by a subsequent call to +** [sqlite3_str_finish(X)]. +** +** ^The [sqlite3_str_new(D)] interface always returns a pointer to a +** valid [sqlite3_str] object, though in the event of an out-of-memory +** error the returned object might be a special singleton that will +** silently reject new text, always return SQLITE_NOMEM from +** [sqlite3_str_errcode()], always return 0 for +** [sqlite3_str_length()], and always return NULL from +** [sqlite3_str_finish(X)]. It is always safe to use the value +** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter +** to any of the other [sqlite3_str] methods. +** +** The D parameter to [sqlite3_str_new(D)] may be NULL. If the +** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum +** length of the string contained in the [sqlite3_str] object will be +** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead +** of [SQLITE_MAX_LENGTH]. +*/ +SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); + +/* +** CAPI3REF: Finalize A Dynamic String +** DESTRUCTOR: sqlite3_str +** +** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X +** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()] +** that contains the constructed string. The calling application should +** pass the returned value to [sqlite3_free()] to avoid a memory leak. +** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any +** errors were encountered during construction of the string. ^The +** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** string in [sqlite3_str] object X is zero bytes long. +*/ +SQLITE_API char *sqlite3_str_finish(sqlite3_str*); + +/* +** CAPI3REF: Add Content To A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces add content to an sqlite3_str object previously obtained +** from [sqlite3_str_new()]. +** +** ^The [sqlite3_str_appendf(X,F,...)] and +** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] +** functionality of SQLite to append formatted text onto the end of +** [sqlite3_str] object X. +** +** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S +** onto the end of the [sqlite3_str] object X. N must be non-negative. +** S must contain at least N non-zero bytes of content. To append a +** zero-terminated string in its entirety, use the [sqlite3_str_appendall()] +** method instead. +** +** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of +** zero-terminated string S onto the end of [sqlite3_str] object X. +** +** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the +** single-byte character C onto the end of [sqlite3_str] object X. +** ^This method can be used, for example, to add whitespace indentation. +** +** ^The [sqlite3_str_reset(X)] method resets the string under construction +** inside [sqlite3_str] object X back to zero bytes in length. +** +** These methods do not return a result code. ^If an error occurs, that fact +** is recorded in the [sqlite3_str] object and can be recovered by a +** subsequent call to [sqlite3_str_errcode(X)]. +*/ +SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...); +SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list); +SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); +SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); +SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); +SQLITE_API void sqlite3_str_reset(sqlite3_str*); + +/* +** CAPI3REF: Status Of A Dynamic String +** METHOD: sqlite3_str +** +** These interfaces return the current status of an [sqlite3_str] object. +** +** ^If any prior errors have occurred while constructing the dynamic string +** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return +** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns +** [SQLITE_NOMEM] following any out-of-memory error, or +** [SQLITE_TOOBIG] if the size of the dynamic string exceeds +** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors. +** +** ^The [sqlite3_str_length(X)] method returns the current length, in bytes, +** of the dynamic string under construction in [sqlite3_str] object X. +** ^The length returned by [sqlite3_str_length(X)] does not include the +** zero-termination byte. +** +** ^The [sqlite3_str_value(X)] method returns a pointer to the current +** content of the dynamic string under construction in X. The value +** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X +** and might be freed or altered by any subsequent method on the same +** [sqlite3_str] object. Applications must not used the pointer returned +** [sqlite3_str_value(X)] after any subsequent method call on the same +** object. ^Applications may change the content of the string returned +** by [sqlite3_str_value(X)] as long as they do not write into any bytes +** outside the range of 0 to [sqlite3_str_length(X)] and do not read or +** write any byte after any subsequent sqlite3_str method call. +*/ +SQLITE_API int sqlite3_str_errcode(sqlite3_str*); +SQLITE_API int sqlite3_str_length(sqlite3_str*); +SQLITE_API char *sqlite3_str_value(sqlite3_str*); /* ** CAPI3REF: SQLite Runtime Status @@ -6819,8 +8228,7 @@ SQLITE_API int sqlite3_status64( **
      This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application -** and internal memory usage by the SQLite library. Scratch memory -** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** and internal memory usage by the SQLite library. Auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].
      )^ @@ -6829,7 +8237,7 @@ SQLITE_API int sqlite3_status64( **
      This parameter records the largest memory allocation request ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their ** internal equivalents). Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. +** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
      )^ ** ** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
      SQLITE_STATUS_MALLOC_COUNT
      @@ -6838,11 +8246,11 @@ SQLITE_API int sqlite3_status64( ** ** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
      SQLITE_STATUS_PAGECACHE_USED
      **
      This parameter returns the number of pages used out of the -** [pagecache memory allocator] that was configured using +** [pagecache memory allocator] that was configured using ** [SQLITE_CONFIG_PAGECACHE]. The ** value returned is in pages, not in bytes.
      )^ ** -** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] ** ^(
      SQLITE_STATUS_PAGECACHE_OVERFLOW
      **
      This parameter returns the number of bytes of page cache ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] @@ -6854,36 +8262,21 @@ SQLITE_API int sqlite3_status64( ** ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
      SQLITE_STATUS_PAGECACHE_SIZE
      **
      This parameter records the largest memory allocation request -** handed to [pagecache memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. +** handed to the [pagecache memory allocator]. Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
      )^ ** -** [[SQLITE_STATUS_SCRATCH_USED]] ^(
      SQLITE_STATUS_SCRATCH_USED
      -**
      This parameter returns the number of allocations used out of the -** [scratch memory allocator] configured using -** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not -** in bytes. Since a single thread may only have one scratch allocation -** outstanding at time, this parameter also reports the number of threads -** using scratch memory at the same time.
      )^ +** [[SQLITE_STATUS_SCRATCH_USED]]
      SQLITE_STATUS_SCRATCH_USED
      +**
      No longer used.
      ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
      SQLITE_STATUS_SCRATCH_OVERFLOW
      -**
      This parameter returns the number of bytes of scratch memory -** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] -** buffer and where forced to overflow to [sqlite3_malloc()]. The values -** returned include overflows because the requested allocation was too -** larger (that is, because the requested allocation was larger than the -** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer -** slots were available. -**
      )^ +**
      No longer used.
      ** -** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
      SQLITE_STATUS_SCRATCH_SIZE
      -**
      This parameter records the largest memory allocation request -** handed to [scratch memory allocator]. Only the value returned in the -** *pHighwater parameter to [sqlite3_status()] is of interest. -** The value written into the *pCurrent parameter is undefined.
      )^ +** [[SQLITE_STATUS_SCRATCH_SIZE]]
      SQLITE_STATUS_SCRATCH_SIZE
      +**
      No longer used.
      ** ** [[SQLITE_STATUS_PARSER_STACK]] ^(
      SQLITE_STATUS_PARSER_STACK
      -**
      The *pHighwater parameter records the deepest parser stack. +**
      The *pHighwater parameter records the deepest parser stack. ** The *pCurrent value is undefined. The *pHighwater value is only ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
      )^ **
    @@ -6893,24 +8286,24 @@ SQLITE_API int sqlite3_status64( #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 -#define SQLITE_STATUS_SCRATCH_USED 3 -#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */ +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */ #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 -#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */ #define SQLITE_STATUS_MALLOC_COUNT 9 /* ** CAPI3REF: Database Connection Status ** METHOD: sqlite3 ** -** ^This interface is used to retrieve runtime status information +** ^This interface is used to retrieve runtime status information ** about a single [database connection]. ^The first argument is the ** database connection object to be interrogated. ^The second argument ** is an integer constant, taken from the set of ** [SQLITE_DBSTATUS options], that -** determines the parameter to interrogate. The set of +** determines the parameter to interrogate. The set of ** [SQLITE_DBSTATUS options] is likely ** to grow in future releases of SQLite. ** @@ -6945,7 +8338,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** checked out.)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
    SQLITE_DBSTATUS_LOOKASIDE_HIT
    -**
    This parameter returns the number malloc attempts that were +**
    This parameter returns the number of malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; ** the current value is always zero.)^ ** @@ -6970,7 +8363,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** -** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] +** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] ** ^(
    SQLITE_DBSTATUS_CACHE_USED_SHARED
    **
    This parameter is similar to DBSTATUS_CACHE_USED, except that if a ** pager cache is shared between two or more connections the bytes of heap @@ -6985,7 +8378,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
    SQLITE_DBSTATUS_SCHEMA_USED
    **
    This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated -** with the connection - main, temp, and any [ATTACH]-ed databases.)^ +** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. @@ -7000,13 +8393,13 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** ** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(
    SQLITE_DBSTATUS_CACHE_HIT
    **
    This parameter returns the number of pager cache hits that have -** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT ** is always 0. **
    ** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(
    SQLITE_DBSTATUS_CACHE_MISS
    **
    This parameter returns the number of pager cache misses that have -** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS +** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. **
    ** @@ -7021,6 +8414,15 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. ** ** +** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(
    SQLITE_DBSTATUS_CACHE_SPILL
    +**
    This parameter returns the number of dirty cache entries that have +** been written to disk in the middle of a transaction due to the page +** cache overflowing. Transactions are more efficient if they are written +** to disk all at once. When pages spill mid-transaction, that introduces +** additional overhead. This parameter can be used help identify +** inefficiencies that can be resolved by increasing the cache size. +**
    +** ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(
    SQLITE_DBSTATUS_DEFERRED_FKS
    **
    This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been @@ -7040,7 +8442,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 -#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ +#define SQLITE_DBSTATUS_CACHE_SPILL 12 +#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */ /* @@ -7054,7 +8457,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r ** statements. For example, if the number of table steps greatly exceeds ** the number of table searches or result rows, that would tend to indicate ** that the prepared statement is using a full table scan rather than -** an index. +** an index. ** ** ^(This interface is used to retrieve and reset counter values from ** a [prepared statement]. The first argument is the prepared statement @@ -7081,7 +8484,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
    SQLITE_STMTSTATUS_FULLSCAN_STEP
    **
    ^This is the number of times that SQLite has stepped forward in ** a table as part of a full table scan. Large numbers for this counter -** may indicate opportunities for performance improvement through +** may indicate opportunities for performance improvement through ** careful use of indices.
    ** ** [[SQLITE_STMTSTATUS_SORT]]
    SQLITE_STMTSTATUS_SORT
    @@ -7099,10 +8502,38 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); ** [[SQLITE_STMTSTATUS_VM_STEP]]
    SQLITE_STMTSTATUS_VM_STEP
    **
    ^This is the number of virtual machine operations executed ** by the prepared statement if that number is less than or equal -** to 2147483647. The number of virtual machine operations can be +** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. +** +** [[SQLITE_STMTSTATUS_REPREPARE]]
    SQLITE_STMTSTATUS_REPREPARE
    +**
    ^This is the number of times that the prepare statement has been +** automatically regenerated due to schema changes or changes to +** [bound parameters] that might affect the query plan. +** +** [[SQLITE_STMTSTATUS_RUN]]
    SQLITE_STMTSTATUS_RUN
    +**
    ^This is the number of times that the prepared statement has +** been run. A single "run" for the purposes of this counter is one +** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()]. +** The counter is incremented on the first [sqlite3_step()] call of each +** cycle. +** +** [[SQLITE_STMTSTATUS_FILTER_MISS]] +** [[SQLITE_STMTSTATUS_FILTER HIT]] +**
    SQLITE_STMTSTATUS_FILTER_HIT
    +** SQLITE_STMTSTATUS_FILTER_MISS
    +**
    ^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join +** step was bypassed because a Bloom filter returned not-found. The +** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of +** times that the Bloom filter returned a find, and thus the join step +** had to be processed as normal. +** +** [[SQLITE_STMTSTATUS_MEMUSED]]
    SQLITE_STMTSTATUS_MEMUSED
    +**
    ^This is the approximate number of bytes of heap memory +** used to store the prepared statement. ^This value is not actually +** a counter, and so the resetFlg parameter to sqlite3_stmt_status() +** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. **
    ** */ @@ -7110,6 +8541,11 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 +#define SQLITE_STMTSTATUS_REPREPARE 5 +#define SQLITE_STMTSTATUS_RUN 6 +#define SQLITE_STMTSTATUS_FILTER_MISS 7 +#define SQLITE_STMTSTATUS_FILTER_HIT 8 +#define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object @@ -7145,15 +8581,15 @@ struct sqlite3_pcache_page { ** KEYWORDS: {page cache} ** ** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can -** register an alternative page cache implementation by passing in an +** register an alternative page cache implementation by passing in an ** instance of the sqlite3_pcache_methods2 structure.)^ -** In many applications, most of the heap memory allocated by +** In many applications, most of the heap memory allocated by ** SQLite is used for the page cache. -** By implementing a +** By implementing a ** custom page cache using this API, an application can better control -** the amount of memory consumed by SQLite, the way in which -** that memory is allocated and released, and the policies used to -** determine exactly which parts of a database file are cached and for +** the amount of memory consumed by SQLite, the way in which +** that memory is allocated and released, and the policies used to +** determine exactly which parts of a database file are cached and for ** how long. ** ** The alternative page cache mechanism is an @@ -7166,19 +8602,19 @@ struct sqlite3_pcache_page { ** [sqlite3_config()] returns.)^ ** ** [[the xInit() page cache method]] -** ^(The xInit() method is called once for each effective +** ^(The xInit() method is called once for each effective ** call to [sqlite3_initialize()])^ ** (usually only once during the lifetime of the process). ^(The xInit() ** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^ -** The intent of the xInit() method is to set up global data structures -** required by the custom page cache implementation. -** ^(If the xInit() method is NULL, then the +** The intent of the xInit() method is to set up global data structures +** required by the custom page cache implementation. +** ^(If the xInit() method is NULL, then the ** built-in default page cache is used instead of the application defined ** page cache.)^ ** ** [[the xShutdown() page cache method]] ** ^The xShutdown() method is called by [sqlite3_shutdown()]. -** It can be used to clean up +** It can be used to clean up ** any outstanding resources before process shutdown, if required. ** ^The xShutdown() method may be NULL. ** @@ -7197,7 +8633,7 @@ struct sqlite3_pcache_page { ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must ** be allocated by the cache. ^szPage will always a power of two. ^The -** second parameter szExtra is a number of bytes of extra storage +** second parameter szExtra is a number of bytes of extra storage ** associated with each page cache entry. ^The szExtra parameter will ** a number less than 250. SQLite will use the ** extra szExtra bytes on each page to store metadata about the underlying @@ -7210,7 +8646,7 @@ struct sqlite3_pcache_page { ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to -** false will always have the "discard" flag set to true. +** false will always have the "discard" flag set to true. ** ^Hence, a cache created with bPurgeable false will ** never contain any unpinned pages. ** @@ -7225,12 +8661,12 @@ struct sqlite3_pcache_page { ** [[the xPagecount() page cache methods]] ** The xPagecount() method must return the number of pages currently ** stored in the cache, both pinned and unpinned. -** +** ** [[the xFetch() page cache methods]] -** The xFetch() method locates a page in the cache and returns a pointer to +** The xFetch() method locates a page in the cache and returns a pointer to ** an sqlite3_pcache_page object associated with that page, or a NULL pointer. ** The pBuf element of the returned sqlite3_pcache_page object will be a -** pointer to a buffer of szPage bytes used to store the content of a +** pointer to a buffer of szPage bytes used to store the content of a ** single database page. The pExtra element of sqlite3_pcache_page will be ** a pointer to the szExtra bytes of extra storage that SQLite has requested ** for each entry in the page cache. @@ -7256,7 +8692,7 @@ struct sqlite3_pcache_page { ** ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite ** will only use a createFlag of 2 after a prior call with a createFlag of 1 -** failed.)^ In between the to xFetch() calls, SQLite may +** failed.)^ In between the xFetch() calls, SQLite may ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. ** @@ -7269,8 +8705,8 @@ struct sqlite3_pcache_page { ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** -** The cache must not perform any reference counting. A single -** call to xUnpin() unpins the page regardless of the number of prior calls +** The cache must not perform any reference counting. A single +** call to xUnpin() unpins the page regardless of the number of prior calls ** to xFetch(). ** ** [[the xRekey() page cache methods]] @@ -7310,7 +8746,7 @@ struct sqlite3_pcache_methods2 { int (*xPagecount)(sqlite3_pcache*); sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); - void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, unsigned oldKey, unsigned newKey); void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); void (*xDestroy)(sqlite3_pcache*); @@ -7355,7 +8791,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** ** The backup API copies the content of one database into another. ** It is useful either for creating backups of databases or -** for copying in-memory databases to or from persistent files. +** for copying in-memory databases to or from persistent files. ** ** See Also: [Using the SQLite Online Backup API] ** @@ -7366,36 +8802,36 @@ typedef struct sqlite3_backup sqlite3_backup; ** ^Thus, the backup may be performed on a live source database without ** preventing other database connections from ** reading or writing to the source database while the backup is underway. -** -** ^(To perform a backup operation: +** +** ^(To perform a backup operation: **
      **
    1. sqlite3_backup_init() is called once to initialize the -** backup, -**
    2. sqlite3_backup_step() is called one or more times to transfer +** backup, +**
    3. sqlite3_backup_step() is called one or more times to transfer ** the data between the two databases, and finally -**
    4. sqlite3_backup_finish() is called to release all resources -** associated with the backup operation. +**
    5. sqlite3_backup_finish() is called to release all resources +** associated with the backup operation. **
    )^ ** There should be exactly one call to sqlite3_backup_finish() for each ** successful call to sqlite3_backup_init(). ** ** [[sqlite3_backup_init()]] sqlite3_backup_init() ** -** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the -** [database connection] associated with the destination database +** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the +** [database connection] associated with the destination database ** and the database name, respectively. ** ^The database name is "main" for the main database, "temp" for the ** temporary database, or the name specified after the AS keyword in ** an [ATTACH] statement for an attached database. -** ^The S and M arguments passed to +** ^The S and M arguments passed to ** sqlite3_backup_init(D,N,S,M) identify the [database connection] ** and database name of the source database, respectively. ** ^The source and destination [database connections] (parameters S and D) ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** -** ^A call to sqlite3_backup_init() will fail, returning NULL, if -** there is already a read or read-write transaction open on the +** ^A call to sqlite3_backup_init() will fail, returning NULL, if +** there is already a read or read-write transaction open on the ** destination database. ** ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is @@ -7407,14 +8843,14 @@ typedef struct sqlite3_backup sqlite3_backup; ** ^A successful call to sqlite3_backup_init() returns a pointer to an ** [sqlite3_backup] object. ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and -** sqlite3_backup_finish() functions to perform the specified backup +** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** ** [[sqlite3_backup_step()]] sqlite3_backup_step() ** -** ^Function sqlite3_backup_step(B,N) will copy up to N pages between +** ^Function sqlite3_backup_step(B,N) will copy up to N pages between ** the source and destination databases specified by [sqlite3_backup] object B. -** ^If N is negative, all remaining source pages are copied. +** ^If N is negative, all remaining source pages are copied. ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there ** are still more pages to be copied, then the function returns [SQLITE_OK]. ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages @@ -7436,8 +8872,8 @@ typedef struct sqlite3_backup sqlite3_backup; ** ** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then ** the [sqlite3_busy_handler | busy-handler function] -** is invoked (if one is specified). ^If the -** busy-handler returns non-zero before the lock is available, then +** is invoked (if one is specified). ^If the +** busy-handler returns non-zero before the lock is available, then ** [SQLITE_BUSY] is returned to the caller. ^In this case the call to ** sqlite3_backup_step() can be retried later. ^If the source ** [database connection] @@ -7445,15 +8881,15 @@ typedef struct sqlite3_backup sqlite3_backup; ** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this ** case the call to sqlite3_backup_step() can be retried later on. ^(If ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or -** [SQLITE_READONLY] is returned, then -** there is no point in retrying the call to sqlite3_backup_step(). These -** errors are considered fatal.)^ The application must accept -** that the backup operation has failed and pass the backup operation handle +** [SQLITE_READONLY] is returned, then +** there is no point in retrying the call to sqlite3_backup_step(). These +** errors are considered fatal.)^ The application must accept +** that the backup operation has failed and pass the backup operation handle ** to the sqlite3_backup_finish() to release associated resources. ** ** ^The first call to sqlite3_backup_step() obtains an exclusive lock -** on the destination file. ^The exclusive lock is not released until either -** sqlite3_backup_finish() is called or the backup operation is complete +** on the destination file. ^The exclusive lock is not released until either +** sqlite3_backup_finish() is called or the backup operation is complete ** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to ** sqlite3_backup_step() obtains a [shared lock] on the source database that ** lasts for the duration of the sqlite3_backup_step() call. @@ -7462,18 +8898,18 @@ typedef struct sqlite3_backup sqlite3_backup; ** through the backup process. ^If the source database is modified by an ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically -** restarted by the next call to sqlite3_backup_step(). ^If the source +** restarted by the next call to sqlite3_backup_step(). ^If the source ** database is modified by the using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** ** [[sqlite3_backup_finish()]] sqlite3_backup_finish() ** -** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the +** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the ** application wishes to abandon the backup operation, the application ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). ** ^The sqlite3_backup_finish() interfaces releases all -** resources associated with the [sqlite3_backup] object. +** resources associated with the [sqlite3_backup] object. ** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any ** active write-transaction on the destination database is rolled back. ** The [sqlite3_backup] object is invalid @@ -7513,8 +8949,8 @@ typedef struct sqlite3_backup sqlite3_backup; ** connections, then the source database connection may be used concurrently ** from within other threads. ** -** However, the application must guarantee that the destination -** [database connection] is not passed to any other API (by any thread) after +** However, the application must guarantee that the destination +** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] @@ -7525,11 +8961,11 @@ typedef struct sqlite3_backup sqlite3_backup; ** If running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means -** that the application must guarantee that the disk file being +** that the application must guarantee that the disk file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). ** -** The [sqlite3_backup] object itself is partially threadsafe. Multiple +** The [sqlite3_backup] object itself is partially threadsafe. Multiple ** threads may safely make multiple concurrent calls to sqlite3_backup_step(). ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** APIs are not strictly speaking threadsafe. If they are invoked at the @@ -7554,8 +8990,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ^When running in shared-cache mode, a database operation may fail with ** an [SQLITE_LOCKED] error if the required locks on the shared-cache or ** individual tables within the shared-cache cannot be obtained. See -** [SQLite Shared-Cache Mode] for a description of shared-cache locking. -** ^This API may be used to register a callback that SQLite will invoke +** [SQLite Shared-Cache Mode] for a description of shared-cache locking. +** ^This API may be used to register a callback that SQLite will invoke ** when the connection currently holding the required lock relinquishes it. ** ^This API is only available if the library was compiled with the ** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. @@ -7563,18 +8999,18 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** See Also: [Using the SQLite Unlock Notification Feature]. ** ** ^Shared-cache locks are released when a database connection concludes -** its current transaction, either by committing it or rolling it back. +** its current transaction, either by committing it or rolling it back. ** ** ^When a connection (known as the blocked connection) fails to obtain a ** shared-cache lock and SQLITE_LOCKED is returned to the caller, the ** identity of the database connection (the blocking connection) that -** has locked the required resource is stored internally. ^After an +** has locked the required resource is stored internally. ^After an ** application receives an SQLITE_LOCKED error, it may call the -** sqlite3_unlock_notify() method with the blocked connection handle as +** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked ** when the blocking connections current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] -** call that concludes the blocking connections transaction. +** call that concludes the blocking connection's transaction. ** ** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, ** there is a chance that the blocking connection will have already @@ -7584,15 +9020,15 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ** ^If the blocked connection is attempting to obtain a write-lock on a ** shared-cache table, and more than one other connection currently holds -** a read-lock on the same table, then SQLite arbitrarily selects one of +** a read-lock on the same table, then SQLite arbitrarily selects one of ** the other connections to use as the blocking connection. ** -** ^(There may be at most one unlock-notify callback registered by a +** ^(There may be at most one unlock-notify callback registered by a ** blocked connection. If sqlite3_unlock_notify() is called when the ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing -** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback is canceled. ^The blocked connections ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** @@ -7605,25 +9041,25 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ** Callback Invocation Details ** -** When an unlock-notify callback is registered, the application provides a +** When an unlock-notify callback is registered, the application provides a ** single void* pointer that is passed to the callback when it is invoked. ** However, the signature of the callback function allows SQLite to pass ** it an array of void* context pointers. The first argument passed to ** an unlock-notify callback is a pointer to an array of void* pointers, ** and the second is the number of entries in the array. ** -** When a blocking connections transaction is concluded, there may be +** When a blocking connection's transaction is concluded, there may be ** more than one blocked connection that has registered for an unlock-notify ** callback. ^If two or more such blocked connections have specified the ** same callback function, then instead of invoking the callback function ** multiple times, it is invoked once with the set of void* context pointers ** specified by the blocked connections bundled together into an array. -** This gives the application an opportunity to prioritize any actions +** This gives the application an opportunity to prioritize any actions ** related to the set of unblocked database connections. ** ** Deadlock Detection ** -** Assuming that after registering for an unlock-notify callback a +** Assuming that after registering for an unlock-notify callback a ** database waits for the callback to be issued before taking any further ** action (a reasonable assumption), then using this API may cause the ** application to deadlock. For example, if connection X is waiting for @@ -7646,7 +9082,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** ** The "DROP TABLE" Exception ** -** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost +** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost ** always appropriate to call sqlite3_unlock_notify(). There is however, ** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, ** SQLite checks if there are any currently executing SELECT statements @@ -7659,7 +9095,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** One way around this problem is to check the extended error code returned ** by an sqlite3_step() call. ^(If there is a blocking connection, then the ** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in -** the special "DROP TABLE/INDEX" case, the extended error code is just +** the special "DROP TABLE/INDEX" case, the extended error code is just ** SQLITE_LOCKED.)^ */ SQLITE_API int sqlite3_unlock_notify( @@ -7750,8 +9186,8 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** ^The [sqlite3_wal_hook()] function is used to register a callback that ** is invoked each time data is committed to a database in wal mode. ** -** ^(The callback is invoked by SQLite after the commit has taken place and -** the associated write-lock on the database released)^, so the implementation +** ^(The callback is invoked by SQLite after the commit has taken place and +** the associated write-lock on the database released)^, so the implementation ** may read, write or [checkpoint] the database as required. ** ** ^The first parameter passed to the callback function when it is invoked @@ -7770,15 +9206,16 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** -** A single database handle may have at most a single write-ahead log callback +** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any -** previously registered write-ahead log callback. ^Note that the -** [sqlite3_wal_autocheckpoint()] interface and the +** previously registered write-ahead log callback. ^The return value is +** a copy of the third parameter from the previous call, if any, or 0. +** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will ** overwrite any prior [sqlite3_wal_hook()] settings. */ SQLITE_API void *sqlite3_wal_hook( - sqlite3*, + sqlite3*, int(*)(void *,sqlite3*,const char*,int), void* ); @@ -7791,7 +9228,7 @@ SQLITE_API void *sqlite3_wal_hook( ** [sqlite3_wal_hook()] that causes any database on [database connection] D ** to automatically [checkpoint] ** after committing a transaction if there are N or -** more frames in the [write-ahead log] file. ^Passing zero or +** more frames in the [write-ahead log] file. ^Passing zero or ** a negative value as the nFrame parameter disables automatic ** checkpoints entirely. ** @@ -7821,7 +9258,7 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); ** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to ** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^ ** -** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the +** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the ** [write-ahead log] for database X on [database connection] D to be ** transferred into the database file and for the write-ahead log to ** be reset. See the [checkpointing] documentation for addition @@ -7847,10 +9284,10 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** **
    **
    SQLITE_CHECKPOINT_PASSIVE
    -** ^Checkpoint as many frames as possible without waiting for any database -** readers or writers to finish, then sync the database file if all frames +** ^Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish, then sync the database file if all frames ** in the log were checkpointed. ^The [busy-handler callback] -** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. +** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode. ** ^On the other hand, passive mode might leave the checkpoint unfinished ** if there are concurrent readers or writers. ** @@ -7864,9 +9301,9 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** **
    SQLITE_CHECKPOINT_RESTART
    ** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition -** that after checkpointing the log file it blocks (calls the +** that after checkpointing the log file it blocks (calls the ** [busy-handler callback]) -** until all readers are reading from the database file only. ^This ensures +** until all readers are reading from the database file only. ^This ensures ** that the next writer will restart the log file from the beginning. ** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new ** database writer attempts while it is pending, but does not impede readers. @@ -7888,31 +9325,31 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero. ** ** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If -** any other process is running a checkpoint operation at the same time, the -** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a +** any other process is running a checkpoint operation at the same time, the +** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a ** busy-handler configured, it will not be invoked in this case. ** -** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the +** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the ** exclusive "writer" lock on the database file. ^If the writer lock cannot be ** obtained immediately, and a busy-handler is configured, it is invoked and ** the writer lock retried until either the busy-handler returns 0 or the lock ** is successfully obtained. ^The busy-handler is also invoked while waiting for ** database readers as described above. ^If the busy-handler returns 0 before ** the writer lock is obtained or while waiting for database readers, the -** checkpoint operation proceeds from that point in the same way as -** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible +** checkpoint operation proceeds from that point in the same way as +** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible ** without blocking any further. ^SQLITE_BUSY is returned in this case. ** ** ^If parameter zDb is NULL or points to a zero length string, then the -** specified operation is attempted on all WAL databases [attached] to +** specified operation is attempted on all WAL databases [attached] to ** [database connection] db. In this case the -** values written to output parameters *pnLog and *pnCkpt are undefined. ^If -** an SQLITE_BUSY error is encountered when processing one or more of the -** attached WAL databases, the operation is still attempted on any remaining -** attached databases and SQLITE_BUSY is returned at the end. ^If any other -** error occurs while processing an attached database, processing is abandoned -** and the error code is returned to the caller immediately. ^If no error -** (SQLITE_BUSY or otherwise) is encountered while processing the attached +** values written to output parameters *pnLog and *pnCkpt are undefined. ^If +** an SQLITE_BUSY error is encountered when processing one or more of the +** attached WAL databases, the operation is still attempted on any remaining +** attached databases and SQLITE_BUSY is returned at the end. ^If any other +** error occurs while processing an attached database, processing is abandoned +** and the error code is returned to the caller immediately. ^If no error +** (SQLITE_BUSY or otherwise) is encountered while processing the attached ** databases, SQLITE_OK is returned. ** ** ^If database zDb is the name of an attached database that is not in WAL @@ -7960,21 +9397,28 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( ** If this interface is invoked outside the context of an xConnect or ** xCreate virtual table method then the behavior is undefined. ** -** At present, there is only one option that may be configured using -** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options -** may be added in the future. +** In the call sqlite3_vtab_config(D,C,...) the D parameter is the +** [database connection] in which the virtual table is being created and +** which is passed in as the first argument to the [xConnect] or [xCreate] +** method that is invoking sqlite3_vtab_config(). The C parameter is one +** of the [virtual table configuration options]. The presence and meaning +** of parameters after C depend on which [virtual table configuration option] +** is used. */ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options +** KEYWORDS: {virtual table configuration options} +** KEYWORDS: {virtual table configuration option} ** ** These macros define the various options to the ** [sqlite3_vtab_config()] interface that [virtual table] implementations ** can use to customize and optimize their behavior. ** **
    -**
    SQLITE_VTAB_CONSTRAINT_SUPPORT +** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]] +**
    SQLITE_VTAB_CONSTRAINT_SUPPORT
    **
    Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, ** where X is an integer. If X is zero, then the [virtual table] whose @@ -7988,24 +9432,46 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); ** If X is non-zero, then the virtual table implementation guarantees ** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before ** any modifications to internal or persistent data structures have been made. -** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite ** is able to roll back a statement or database transaction, and abandon -** or continue processing the current SQL statement as appropriate. +** or continue processing the current SQL statement as appropriate. ** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns ** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode ** had been ABORT. ** ** Virtual table implementations that are required to handle OR REPLACE -** must do so within the [xUpdate] method. If a call to the -** [sqlite3_vtab_on_conflict()] function indicates that the current ON -** CONFLICT policy is REPLACE, the virtual table implementation should +** must do so within the [xUpdate] method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should ** silently replace the appropriate rows within the xUpdate callback and ** return SQLITE_OK. Or, if this is not possible, it may return -** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT ** constraint handling. +**
    +** +** [[SQLITE_VTAB_DIRECTONLY]]
    SQLITE_VTAB_DIRECTONLY
    +**
    Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation +** prohibits that virtual table from being used from within triggers and +** views. +**
    +** +** [[SQLITE_VTAB_INNOCUOUS]]
    SQLITE_VTAB_INNOCUOUS
    +**
    Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the +** the [xConnect] or [xCreate] methods of a [virtual table] implmentation +** identify that virtual table as being safe to use from within triggers +** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the +** virtual table can do no serious harm even if it is controlled by a +** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS +** flag unless absolutely necessary. +**
    **
    */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 +#define SQLITE_VTAB_INNOCUOUS 2 +#define SQLITE_VTAB_DIRECTONLY 3 /* ** CAPI3REF: Determine The Virtual Table Conflict Policy @@ -8019,6 +9485,297 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); +/* +** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE +** +** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] +** method of a [virtual table], then it might return true if the +** column is being fetched as part of an UPDATE operation during which the +** column value will not change. The virtual table implementation can use +** this hint as permission to substitute a return value that is less +** expensive to compute and that the corresponding +** [xUpdate] method understands as a "no-change" value. +** +** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that +** the column is not changed by the UPDATE statement, then the xColumn +** method can optionally return without setting a result, without calling +** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. +** In that case, [sqlite3_value_nochange(X)] will return true for the +** same column in the [xUpdate] method. +** +** The sqlite3_vtab_nochange() routine is an optimization. Virtual table +** implementations should continue to give a correct answer even if the +** sqlite3_vtab_nochange() interface were to always return false. In the +** current implementation, the sqlite3_vtab_nochange() interface does always +** returns false for the enhanced [UPDATE FROM] statement. +*/ +SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); + +/* +** CAPI3REF: Determine The Collation For a Virtual Table Constraint +** METHOD: sqlite3_index_info +** +** This function may only be called from within a call to the [xBestIndex] +** method of a [virtual table]. This function returns a pointer to a string +** that is the name of the appropriate collation sequence to use for text +** comparisons on the constraint identified by its arguments. +** +** The first argument must be the pointer to the [sqlite3_index_info] object +** that is the first parameter to the xBestIndex() method. The second argument +** must be an index into the aConstraint[] array belonging to the +** sqlite3_index_info structure passed to xBestIndex. +** +** Important: +** The first parameter must be the same pointer that is passed into the +** xBestMethod() method. The first parameter may not be a pointer to a +** different [sqlite3_index_info] object, even an exact copy. +** +** The return value is computed as follows: +** +**
      +**
    1. If the constraint comes from a WHERE clause expression that contains +** a [COLLATE operator], then the name of the collation specified by +** that COLLATE operator is returned. +**

    2. If there is no COLLATE operator, but the column that is the subject +** of the constraint specifies an alternative collating sequence via +** a [COLLATE clause] on the column definition within the CREATE TABLE +** statement that was passed into [sqlite3_declare_vtab()], then the +** name of that alternative collating sequence is returned. +**

    3. Otherwise, "BINARY" is returned. +**

    +*/ +SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); + +/* +** CAPI3REF: Determine if a virtual table query is DISTINCT +** METHOD: sqlite3_index_info +** +** This API may only be used from within an [xBestIndex|xBestIndex method] +** of a [virtual table] implementation. The result of calling this +** interface from outside of xBestIndex() is undefined and probably harmful. +** +** ^The sqlite3_vtab_distinct() interface returns an integer that is +** either 0, 1, or 2. The integer returned by sqlite3_vtab_distinct() +** gives the virtual table additional information about how the query +** planner wants the output to be ordered. As long as the virtual table +** can meet the ordering requirements of the query planner, it may set +** the "orderByConsumed" flag. +** +**
    1. +** ^If the sqlite3_vtab_distinct() interface returns 0, that means +** that the query planner needs the virtual table to return all rows in the +** sort order defined by the "nOrderBy" and "aOrderBy" fields of the +** [sqlite3_index_info] object. This is the default expectation. If the +** virtual table outputs all rows in sorted order, then it is always safe for +** the xBestIndex method to set the "orderByConsumed" flag, regardless of +** the return value from sqlite3_vtab_distinct(). +**

    2. +** ^(If the sqlite3_vtab_distinct() interface returns 1, that means +** that the query planner does not need the rows to be returned in sorted order +** as long as all rows with the same values in all columns identified by the +** "aOrderBy" field are adjacent.)^ This mode is used when the query planner +** is doing a GROUP BY. +**

    3. +** ^(If the sqlite3_vtab_distinct() interface returns 2, that means +** that the query planner does not need the rows returned in any particular +** order, as long as rows with the same values in all "aOrderBy" columns +** are adjacent.)^ ^(Furthermore, only a single row for each particular +** combination of values in the columns identified by the "aOrderBy" field +** needs to be returned.)^ ^It is always ok for two or more rows with the same +** values in all "aOrderBy" columns to be returned, as long as all such rows +** are adjacent. ^The virtual table may, if it chooses, omit extra rows +** that have the same value for all columns identified by "aOrderBy". +** ^However omitting the extra rows is optional. +** This mode is used for a DISTINCT query. +**

    +** +** ^For the purposes of comparing virtual table output values to see if the +** values are same value for sorting purposes, two NULL values are considered +** to be the same. In other words, the comparison operator is "IS" +** (or "IS NOT DISTINCT FROM") and not "==". +** +** If a virtual table implementation is unable to meet the requirements +** specified above, then it must not set the "orderByConsumed" flag in the +** [sqlite3_index_info] object or an incorrect answer may result. +** +** ^A virtual table implementation is always free to return rows in any order +** it wants, as long as the "orderByConsumed" flag is not set. ^When the +** the "orderByConsumed" flag is unset, the query planner will add extra +** [bytecode] to ensure that the final results returned by the SQL query are +** ordered correctly. The use of the "orderByConsumed" flag and the +** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful +** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed" +** flag might help queries against a virtual table to run faster. Being +** overly aggressive and setting the "orderByConsumed" flag when it is not +** valid to do so, on the other hand, might cause SQLite to return incorrect +** results. +*/ +SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*); + +/* +** CAPI3REF: Identify and handle IN constraints in xBestIndex +** +** This interface may only be used from within an +** [xBestIndex|xBestIndex() method] of a [virtual table] implementation. +** The result of invoking this interface from any other context is +** undefined and probably harmful. +** +** ^(A constraint on a virtual table of the form +** "[IN operator|column IN (...)]" is +** communicated to the xBestIndex method as a +** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use +** this constraint, it must set the corresponding +** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under +** the usual mode of handling IN operators, SQLite generates [bytecode] +** that invokes the [xFilter|xFilter() method] once for each value +** on the right-hand side of the IN operator.)^ Thus the virtual table +** only sees a single value from the right-hand side of the IN operator +** at a time. +** +** In some cases, however, it would be advantageous for the virtual +** table to see all values on the right-hand of the IN operator all at +** once. The sqlite3_vtab_in() interfaces facilitates this in two ways: +** +**
      +**
    1. +** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero) +** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint +** is an [IN operator] that can be processed all at once. ^In other words, +** sqlite3_vtab_in() with -1 in the third argument is a mechanism +** by which the virtual table can ask SQLite if all-at-once processing +** of the IN operator is even possible. +** +**

    2. +** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates +** to SQLite that the virtual table does or does not want to process +** the IN operator all-at-once, respectively. ^Thus when the third +** parameter (F) is non-negative, this interface is the mechanism by +** which the virtual table tells SQLite how it wants to process the +** IN operator. +**

    +** +** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times +** within the same xBestIndex method call. ^For any given P,N pair, +** the return value from sqlite3_vtab_in(P,N,F) will always be the same +** within the same xBestIndex call. ^If the interface returns true +** (non-zero), that means that the constraint is an IN operator +** that can be processed all-at-once. ^If the constraint is not an IN +** operator or cannot be processed all-at-once, then the interface returns +** false. +** +** ^(All-at-once processing of the IN operator is selected if both of the +** following conditions are met: +** +**
      +**
    1. The P->aConstraintUsage[N].argvIndex value is set to a positive +** integer. This is how the virtual table tells SQLite that it wants to +** use the N-th constraint. +** +**

    2. The last call to sqlite3_vtab_in(P,N,F) for which F was +** non-negative had F>=1. +**

    )^ +** +** ^If either or both of the conditions above are false, then SQLite uses +** the traditional one-at-a-time processing strategy for the IN constraint. +** ^If both conditions are true, then the argvIndex-th parameter to the +** xFilter method will be an [sqlite3_value] that appears to be NULL, +** but which can be passed to [sqlite3_vtab_in_first()] and +** [sqlite3_vtab_in_next()] to find all values on the right-hand side +** of the IN constraint. +*/ +SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle); + +/* +** CAPI3REF: Find all elements on the right-hand side of an IN constraint. +** +** These interfaces are only useful from within the +** [xFilter|xFilter() method] of a [virtual table] implementation. +** The result of invoking these interfaces from any other context +** is undefined and probably harmful. +** +** The X parameter in a call to sqlite3_vtab_in_first(X,P) or +** sqlite3_vtab_in_next(X,P) must be one of the parameters to the +** xFilter method which invokes these routines, and specifically +** a parameter that was previously selected for all-at-once IN constraint +** processing use the [sqlite3_vtab_in()] interface in the +** [xBestIndex|xBestIndex method]. ^(If the X parameter is not +** an xFilter argument that was selected for all-at-once IN constraint +** processing, then these routines return [SQLITE_MISUSE])^ or perhaps +** exhibit some other undefined or harmful behavior. +** +** ^(Use these routines to access all values on the right-hand side +** of the IN constraint using code like the following: +** +**
    +**    for(rc=sqlite3_vtab_in_first(pList, &pVal);
    +**        rc==SQLITE_OK && pVal
    +**        rc=sqlite3_vtab_in_next(pList, &pVal)
    +**    ){
    +**      // do something with pVal
    +**    }
    +**    if( rc!=SQLITE_OK ){
    +**      // an error has occurred
    +**    }
    +** 
    )^ +** +** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P) +** routines return SQLITE_OK and set *P to point to the first or next value +** on the RHS of the IN constraint. ^If there are no more values on the +** right hand side of the IN constraint, then *P is set to NULL and these +** routines return [SQLITE_DONE]. ^The return value might be +** some other value, such as SQLITE_NOMEM, in the event of a malfunction. +** +** The *ppOut values returned by these routines are only valid until the +** next call to either of these routines or until the end of the xFilter +** method from which these routines were called. If the virtual table +** implementation needs to retain the *ppOut values for longer, it must make +** copies. The *ppOut values are [protected sqlite3_value|protected]. +*/ +SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut); +SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut); + +/* +** CAPI3REF: Constraint values in xBestIndex() +** METHOD: sqlite3_index_info +** +** This API may only be used from within the [xBestIndex|xBestIndex method] +** of a [virtual table] implementation. The result of calling this interface +** from outside of an xBestIndex method are undefined and probably harmful. +** +** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within +** the [xBestIndex] method of a [virtual table] implementation, with P being +** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and +** J being a 0-based index into P->aConstraint[], then this routine +** attempts to set *V to the value of the right-hand operand of +** that constraint if the right-hand operand is known. ^If the +** right-hand operand is not known, then *V is set to a NULL pointer. +** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if +** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) +** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th +** constraint is not available. ^The sqlite3_vtab_rhs_value() interface +** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if +** something goes wrong. +** +** The sqlite3_vtab_rhs_value() interface is usually only successful if +** the right-hand operand of a constraint is a literal value in the original +** SQL statement. If the right-hand operand is an expression or a reference +** to some other column or a [host parameter], then sqlite3_vtab_rhs_value() +** will probably return [SQLITE_NOTFOUND]. +** +** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and +** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such +** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^ +** +** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value +** and remains valid for the duration of the xBestIndex method call. +** ^When xBestIndex returns, the sqlite3_value object returned by +** sqlite3_vtab_rhs_value() is automatically deallocated. +** +** The "_rhs_" in the name of this routine is an abbreviation for +** "Right-Hand Side". +*/ +SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); + /* ** CAPI3REF: Conflict resolution modes ** KEYWORDS: {conflict resolution mode} @@ -8051,15 +9808,15 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** **
    ** [[SQLITE_SCANSTAT_NLOOP]]
    SQLITE_SCANSTAT_NLOOP
    -**
    ^The [sqlite3_int64] variable pointed to by the T parameter will be +**
    ^The [sqlite3_int64] variable pointed to by the V parameter will be ** set to the total number of times that the X-th loop has run.
    ** ** [[SQLITE_SCANSTAT_NVISIT]]
    SQLITE_SCANSTAT_NVISIT
    -**
    ^The [sqlite3_int64] variable pointed to by the T parameter will be set +**
    ^The [sqlite3_int64] variable pointed to by the V parameter will be set ** to the total number of rows examined by all iterations of the X-th loop.
    ** ** [[SQLITE_SCANSTAT_EST]]
    SQLITE_SCANSTAT_EST
    -**
    ^The "double" variable pointed to by the T parameter will be set to the +**
    ^The "double" variable pointed to by the V parameter will be set to the ** query planner's estimate for the average number of rows output from each ** iteration of the X-th loop. If the query planner's estimates was accurate, ** then this value will approximate the quotient NVISIT/NLOOP and the @@ -8067,17 +9824,17 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** be the NLOOP value for the current loop. ** ** [[SQLITE_SCANSTAT_NAME]]
    SQLITE_SCANSTAT_NAME
    -**
    ^The "const char *" variable pointed to by the T parameter will be set +**
    ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the name of the index or table ** used for the X-th loop. ** ** [[SQLITE_SCANSTAT_EXPLAIN]]
    SQLITE_SCANSTAT_EXPLAIN
    -**
    ^The "const char *" variable pointed to by the T parameter will be set +**
    ^The "const char *" variable pointed to by the V parameter will be set ** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] ** description for the X-th loop. ** ** [[SQLITE_SCANSTAT_SELECTID]]
    SQLITE_SCANSTAT_SELECT
    -**
    ^The "int" variable pointed to by the T parameter will be set to the +**
    ^The "int" variable pointed to by the V parameter will be set to the ** "select-id" for the X-th loop. The select-id identifies which query or ** subquery the loop is part of. The main query has a select-id of zero. ** The select-id is the same value as is output in the first column @@ -8127,7 +9884,7 @@ SQLITE_API int sqlite3_stmt_scanstatus( int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ void *pOut /* Result written here */ -); +); /* ** CAPI3REF: Zero Scan-Status Counters @@ -8142,18 +9899,19 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction +** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty -** pages in the pager-cache that are not currently in use are written out +** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database ** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)] ** interface flushes caches for all schemas - "main", "temp", and ** any [attached] databases. ** -** ^If this function needs to obtain extra database locks before dirty pages -** can be flushed to disk, it does so. ^If those locks cannot be obtained +** ^If this function needs to obtain extra database locks before dirty pages +** can be flushed to disk, it does so. ^If those locks cannot be obtained ** immediately and there is a busy-handler callback configured, it is invoked ** in the usual manner. ^If the required lock still cannot be obtained, then ** the database is skipped and an attempt made to flush any dirty pages @@ -8174,6 +9932,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. +** METHOD: sqlite3 ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. @@ -8191,7 +9950,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** ** ^The preupdate hook only fires for changes to real database tables; the ** preupdate hook is not invoked for changes to [virtual tables] or to -** system tables like sqlite_master or sqlite_stat1. +** system tables like sqlite_sequence or sqlite_stat1. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. @@ -8200,21 +9959,21 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** kind of update operation that is about to occur. ** ^(The fourth parameter to the preupdate callback is the name of the ** database within the database connection that is being modified. This -** will be "main" for the main database or "temp" for TEMP tables or +** will be "main" for the main database or "temp" for TEMP tables or ** the name given after the AS keyword in the [ATTACH] statement for attached ** databases.)^ ** ^The fifth parameter to the preupdate callback is the name of the ** table that is being modified. ** ** For an UPDATE or DELETE operation on a [rowid table], the sixth -** parameter passed to the preupdate callback is the initial [rowid] of the +** parameter passed to the preupdate callback is the initial [rowid] of the ** row being modified or deleted. For an INSERT operation on a rowid table, -** or any operation on a WITHOUT ROWID table, the value of the sixth +** or any operation on a WITHOUT ROWID table, the value of the sixth ** parameter is undefined. For an INSERT or UPDATE on a rowid table the ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for -** INSERT operations on rowid tables. +** DELETE operations on rowid tables. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces @@ -8248,10 +10007,19 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** ** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate ** callback was invoked as a result of a direct insert, update, or delete -** operation; or 1 for inserts, updates, or deletes invoked by top-level +** operation; or 1 for inserts, updates, or deletes invoked by top-level ** triggers; or 2 for changes resulting from triggers called by top-level ** triggers; and so forth. ** +** When the [sqlite3_blob_write()] API is used to update a blob column, +** the pre-update hook is invoked with SQLITE_DELETE. This is because the +** in this case the new values are not available. In this case, when a +** callback made with op==SQLITE_DELETE is actuall a write using the +** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns +** the index of the column being written. In other cases, where the +** pre-update hook is being invoked for some other reason, including a +** regular DELETE, sqlite3_preupdate_blobwrite() returns -1. +** ** See also: [sqlite3_update_hook()] */ #if defined(SQLITE_ENABLE_PREUPDATE_HOOK) @@ -8272,24 +10040,25 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); SQLITE_API int sqlite3_preupdate_count(sqlite3 *); SQLITE_API int sqlite3_preupdate_depth(sqlite3 *); SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); +SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *); #endif /* ** CAPI3REF: Low-level system error code +** METHOD: sqlite3 ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. ** The return value is OS-dependent. For example, on unix systems, after ** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be ** called to get back the underlying "errno" that caused the problem, such -** as ENOSPC, EAUTH, EISDIR, and so forth. +** as ENOSPC, EAUTH, EISDIR, and so forth. */ SQLITE_API int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot ** KEYWORDS: {snapshot} {sqlite3_snapshot} -** EXPERIMENTAL ** ** An instance of the snapshot object records the state of a [WAL mode] ** database for some specific point in history. @@ -8306,11 +10075,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*); ** version of the database file so that it is possible to later open a new read ** transaction that sees that historical version of the database rather than ** the most recent version. -** -** The constructor for this object is [sqlite3_snapshot_get()]. The -** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer -** to an historical snapshot (if possible). The destructor for -** sqlite3_snapshot objects is [sqlite3_snapshot_free()]. */ typedef struct sqlite3_snapshot { unsigned char hidden[48]; @@ -8318,7 +10082,7 @@ typedef struct sqlite3_snapshot { /* ** CAPI3REF: Record A Database Snapshot -** EXPERIMENTAL +** CONSTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of @@ -8326,15 +10090,15 @@ typedef struct sqlite3_snapshot { ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. ** If there is not already a read-transaction open on schema S when -** this function is called, one is opened automatically. +** this function is called, one is opened automatically. ** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined -** in this case. +** in this case. ** **
      -**
    • The database handle must be in [autocommit mode]. +**
    • The database handle must not be in [autocommit mode]. ** **
    • Schema S of [database connection] D must be a [WAL mode] database. ** @@ -8343,13 +10107,13 @@ typedef struct sqlite3_snapshot { ** **
    • One or more transactions must have been written to the current wal ** file since it was created on disk (by any connection). This means -** that a snapshot cannot be taken on a wal mode database with no wal +** that a snapshot cannot be taken on a wal mode database with no wal ** file immediately after it is first opened. At least one transaction ** must be written to it first. **
    ** ** This function may also return SQLITE_NOMEM. If it is called with the -** database handle in autocommit mode but fails for some other reason, +** database handle in autocommit mode but fails for some other reason, ** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to @@ -8357,7 +10121,7 @@ typedef struct sqlite3_snapshot { ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, @@ -8367,35 +10131,46 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( /* ** CAPI3REF: Start a read transaction on an historical snapshot -** EXPERIMENTAL +** METHOD: sqlite3_snapshot +** +** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read +** transaction or upgrades an existing one for schema S of +** [database connection] D such that the read transaction refers to +** historical [snapshot] P, rather than the most recent change to the +** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK +** on success or an appropriate [error code] if it fails. +** +** ^In order to succeed, the database connection must not be in +** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there +** is already a read transaction open on schema S, then the database handle +** must have no active statements (SELECT statements that have been passed +** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). +** SQLITE_ERROR is returned if either of these conditions is violated, or +** if schema S does not exist, or if the snapshot object is invalid. +** +** ^A call to sqlite3_snapshot_open() will fail to open if the specified +** snapshot has been overwritten by a [checkpoint]. In this case +** SQLITE_ERROR_SNAPSHOT is returned. +** +** If there is already a read transaction open when this function is +** invoked, then the same read transaction remains open (on the same +** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT +** is returned. If another error code - for example SQLITE_PROTOCOL or an +** SQLITE_IOERR error code - is returned, then the final state of the +** read transaction is undefined. If SQLITE_OK is returned, then the +** read transaction is now open on database snapshot P. ** -** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a -** read transaction for schema S of -** [database connection] D such that the read transaction -** refers to historical [snapshot] P, rather than the most -** recent change to the database. -** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success -** or an appropriate [error code] if it fails. -** -** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be -** the first operation following the [BEGIN] that takes the schema S -** out of [autocommit mode]. -** ^In other words, schema S must not currently be in -** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the -** database connection D must be out of [autocommit mode]. -** ^A [snapshot] will fail to open if it has been overwritten by a -** [checkpoint]. ** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the ** database connection D does not know that the database file for ** schema S is in [WAL mode]. A database connection might not know ** that the database file is in [WAL mode] if there has been no prior -** I/O on that database connection, or if the database entered [WAL mode] +** I/O on that database connection, or if the database entered [WAL mode] ** after the most recent I/O on the database connection.)^ ** (Hint: Run "[PRAGMA application_id]" against a newly opened ** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, @@ -8405,38 +10180,41 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( /* ** CAPI3REF: Destroy a snapshot -** EXPERIMENTAL +** DESTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. ** The application must eventually free every [sqlite3_snapshot] object ** using this routine to avoid a memory leak. ** ** The [sqlite3_snapshot_free()] interface is only available when the -** SQLITE_ENABLE_SNAPSHOT compile-time option is used. +** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages -** of two valid snapshot handles. +** of two valid snapshot handles. ** -** If the two snapshot handles are not associated with the same database -** file, the result of the comparison is undefined. +** If the two snapshot handles are not associated with the same database +** file, the result of the comparison is undefined. ** ** Additionally, the result of the comparison is only valid if both of the ** snapshot handles were obtained by calling sqlite3_snapshot_get() since the ** last time the wal file was deleted. The wal file is deleted when the ** database is changed back to rollback mode or when the number of database -** clients drops to zero. If either snapshot handle was obtained before the -** wal file was last deleted, the value returned by this function +** clients drops to zero. If either snapshot handle was obtained before the +** wal file was last deleted, the value returned by this function ** is undefined. ** ** Otherwise, this API returns a negative value if P1 refers to an older ** snapshot than P2, zero if the two handles refer to the same database ** snapshot, and a positive value if P1 is a newer snapshot than P2. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, @@ -8445,26 +10223,155 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( /* ** CAPI3REF: Recover snapshots from a wal file -** EXPERIMENTAL +** METHOD: sqlite3_snapshot ** -** If all connections disconnect from a database file but do not perform -** a checkpoint, the existing wal file is opened along with the database -** file the next time the database is opened. At this point it is only -** possible to successfully call sqlite3_snapshot_open() to open the most -** recent snapshot of the database (the one at the head of the wal file), -** even though the wal file may contain other valid snapshots for which -** clients have sqlite3_snapshot handles. +** If a [WAL file] remains on disk after all database connections close +** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] +** or because the last process to have the database opened exited without +** calling [sqlite3_close()]) and a new connection is subsequently opened +** on that database and [WAL file], the [sqlite3_snapshot_open()] interface +** will only be able to open the last transaction added to the WAL file +** even though the WAL file contains other valid transactions. ** -** This function attempts to scan the wal file associated with database zDb +** This function attempts to scan the WAL file associated with database zDb ** of database handle db and make all valid snapshots available to ** sqlite3_snapshot_open(). It is an error if there is already a read -** transaction open on the database, or if the database is not a wal mode +** transaction open on the database, or if the database is not a WAL mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +** +** This interface is only available if SQLite is compiled with the +** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); +/* +** CAPI3REF: Serialize a database +** +** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory +** that is a serialization of the S database on [database connection] D. +** If P is not a NULL pointer, then the size of the database in bytes +** is written into *P. +** +** For an ordinary on-disk database file, the serialization is just a +** copy of the disk file. For an in-memory database or a "TEMP" database, +** the serialization is the same sequence of bytes which would be written +** to disk if that database where backed up to disk. +** +** The usual case is that sqlite3_serialize() copies the serialization of +** the database into memory obtained from [sqlite3_malloc64()] and returns +** a pointer to that memory. The caller is responsible for freeing the +** returned value to avoid a memory leak. However, if the F argument +** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations +** are made, and the sqlite3_serialize() function will return a pointer +** to the contiguous memory representation of the database that SQLite +** is currently using for that database, or NULL if the no such contiguous +** memory representation of the database exists. A contiguous memory +** representation of the database will usually only exist if there has +** been a prior call to [sqlite3_deserialize(D,S,...)] with the same +** values of D and S. +** The size of the database is written into *P even if the +** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy +** of the database exists. +** +** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the +** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory +** allocation error occurs. +** +** This interface is omitted if SQLite is compiled with the +** [SQLITE_OMIT_DESERIALIZE] option. +*/ +SQLITE_API unsigned char *sqlite3_serialize( + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ + sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ + unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3_serialize +** +** Zero or more of the following constants can be OR-ed together for +** the F argument to [sqlite3_serialize(D,S,P,F)]. +** +** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return +** a pointer to contiguous in-memory database that it is currently using, +** without making a copy of the database. If SQLite is not currently using +** a contiguous in-memory database, then this option causes +** [sqlite3_serialize()] to return a NULL pointer. SQLite will only be +** using a contiguous in-memory database if it has been initialized by a +** prior call to [sqlite3_deserialize()]. +*/ +#define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */ + +/* +** CAPI3REF: Deserialize a database +** +** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the +** [database connection] D to disconnect from database S and then +** reopen S as an in-memory database based on the serialization contained +** in P. The serialized database P is N bytes in size. M is the size of +** the buffer P, which might be larger than N. If M is larger than N, and +** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is +** permitted to add content to the in-memory database as long as the total +** size does not exceed M bytes. +** +** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will +** invoke sqlite3_free() on the serialization buffer when the database +** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then +** SQLite will try to increase the buffer size using sqlite3_realloc64() +** if writes on the database cause it to grow larger than M bytes. +** +** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the +** database is currently in a read transaction or is involved in a backup +** operation. +** +** It is not possible to deserialized into the TEMP database. If the +** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the +** function returns SQLITE_ERROR. +** +** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the +** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then +** [sqlite3_free()] is invoked on argument P prior to returning. +** +** This interface is omitted if SQLite is compiled with the +** [SQLITE_OMIT_DESERIALIZE] option. +*/ +SQLITE_API int sqlite3_deserialize( + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which DB to reopen with the deserialization */ + unsigned char *pData, /* The serialized database content */ + sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szBuf, /* Total size of buffer pData[] */ + unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3_deserialize() +** +** The following are allowed values for 6th argument (the F argument) to +** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. +** +** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization +** in the P argument is held in memory obtained from [sqlite3_malloc64()] +** and that SQLite should take ownership of this memory and automatically +** free it when it has finished using it. Without this flag, the caller +** is responsible for freeing any dynamically allocated memory. +** +** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to +** grow the size of the database using calls to [sqlite3_realloc64()]. This +** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. +** Without this flag, the deserialized database cannot increase in size beyond +** the number of bytes specified by the M parameter. +** +** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database +** should be treated as read-only. +*/ +#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */ +#define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */ +#define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */ + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. @@ -8539,7 +10446,7 @@ struct sqlite3_rtree_geometry { }; /* -** Register a 2nd-generation geometry callback named zScore that can be +** Register a 2nd-generation geometry callback named zScore that can be ** used as part of an R-Tree geometry query as follows: ** ** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) @@ -8554,7 +10461,7 @@ SQLITE_API int sqlite3_rtree_query_callback( /* -** A pointer to a structure of the following type is passed as the +** A pointer to a structure of the following type is passed as the ** argument to scored geometry callback registered using ** sqlite3_rtree_query_callback(). ** @@ -8576,7 +10483,7 @@ struct sqlite3_rtree_query_info { sqlite3_int64 iRowid; /* Rowid for current entry */ sqlite3_rtree_dbl rParentScore; /* Score of parent node */ int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visiblity */ + int eWithin; /* OUT: Visibility */ sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ /* The following fields are only available in 3.8.11 and later */ sqlite3_value **apSqlParam; /* Original SQL values of parameters */ @@ -8612,16 +10519,23 @@ extern "C" { /* ** CAPI3REF: Session Object Handle +** +** An instance of this object is a [session] that can be used to +** record changes to a database. */ typedef struct sqlite3_session sqlite3_session; /* ** CAPI3REF: Changeset Iterator Handle +** +** An instance of this object acts as a cursor for iterating +** over the elements of a [changeset] or [patchset]. */ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; /* ** CAPI3REF: Create A New Session Object +** CONSTRUCTOR: sqlite3_session ** ** Create a new session object attached to database handle db. If successful, ** a pointer to the new object is written to *ppSession and SQLITE_OK is @@ -8642,7 +10556,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; ** is not possible for an application to register a pre-update hook on a ** database handle that has one or more session objects attached. Nor is ** it possible to create a session object attached to a database handle for -** which a pre-update hook is already defined. The results of attempting +** which a pre-update hook is already defined. The results of attempting ** either of these things are undefined. ** ** The session object will be used to create changesets for tables in @@ -8658,21 +10572,55 @@ SQLITE_API int sqlite3session_create( /* ** CAPI3REF: Delete A Session Object +** DESTRUCTOR: sqlite3_session ** -** Delete a session object previously allocated using +** Delete a session object previously allocated using ** [sqlite3session_create()]. Once a session object has been deleted, the ** results of attempting to use pSession with any other session module ** function are undefined. ** ** Session objects must be deleted before the database handle to which they -** are attached is closed. Refer to the documentation for +** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); +/* +** CAPIREF: Conigure a Session Object +** METHOD: sqlite3_session +** +** This method is used to configure a session object after it has been +** created. At present the only valid value for the second parameter is +** [SQLITE_SESSION_OBJCONFIG_SIZE]. +** +** Arguments for sqlite3session_object_config() +** +** The following values may passed as the the 4th parameter to +** sqlite3session_object_config(). +** +**
    SQLITE_SESSION_OBJCONFIG_SIZE
    +** This option is used to set, clear or query the flag that enables +** the [sqlite3session_changeset_size()] API. Because it imposes some +** computational overhead, this API is disabled by default. Argument +** pArg must point to a value of type (int). If the value is initially +** 0, then the sqlite3session_changeset_size() API is disabled. If it +** is greater than 0, then the same API is enabled. Or, if the initial +** value is less than zero, no change is made. In all cases the (int) +** variable is set to 1 if the sqlite3session_changeset_size() API is +** enabled following the current call, or 0 otherwise. +** +** It is an error (SQLITE_MISUSE) to attempt to modify this setting after +** the first table has been attached to the session object. +*/ +SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg); + +/* +*/ +#define SQLITE_SESSION_OBJCONFIG_SIZE 1 /* ** CAPI3REF: Enable Or Disable A Session Object +** METHOD: sqlite3_session ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When @@ -8682,16 +10630,17 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession); ** the eventual changesets. ** ** Passing zero to this function disables the session. Passing a value -** greater than zero enables it. Passing a value less than zero is a +** greater than zero enables it. Passing a value less than zero is a ** no-op, and may be used to query the current state of the session. ** -** The return value indicates the final state of the session object: 0 if +** The return value indicates the final state of the session object: 0 if ** the session is disabled, or 1 if it is enabled. */ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Set Or Clear the Indirect Change Flag +** METHOD: sqlite3_session ** ** Each change recorded by a session object is marked as either direct or ** indirect. A change is marked as indirect if either: @@ -8699,7 +10648,7 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); **
      **
    • The session object "indirect" flag is set when the change is ** made, or -**
    • The change is made by an SQL trigger or foreign key action +**
    • The change is made by an SQL trigger or foreign key action ** instead of directly as a result of a users SQL statement. **
    ** @@ -8711,32 +10660,33 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable); ** flag. If the second argument passed to this function is zero, then the ** indirect flag is cleared. If it is greater than zero, the indirect flag ** is set. Passing a value less than zero does not modify the current value -** of the indirect flag, and may be used to query the current state of the +** of the indirect flag, and may be used to query the current state of the ** indirect flag for the specified session object. ** -** The return value indicates the final state of the indirect flag: 0 if +** The return value indicates the final state of the indirect flag: 0 if ** it is clear, or 1 if it is set. */ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); /* ** CAPI3REF: Attach A Table To A Session Object +** METHOD: sqlite3_session ** ** If argument zTab is not NULL, then it is the name of a table to attach -** to the session object passed as the first argument. All subsequent changes -** made to the table while the session object is enabled will be recorded. See +** to the session object passed as the first argument. All subsequent changes +** made to the table while the session object is enabled will be recorded. See ** documentation for [sqlite3session_changeset()] for further details. ** ** Or, if argument zTab is NULL, then changes are recorded for all tables -** in the database. If additional tables are added to the database (by -** executing "CREATE TABLE" statements) after this call is made, changes for +** in the database. If additional tables are added to the database (by +** executing "CREATE TABLE" statements) after this call is made, changes for ** the new tables are also recorded. ** ** Changes can only be recorded for tables that have a PRIMARY KEY explicitly -** defined as part of their CREATE TABLE statement. It does not matter if the +** defined as part of their CREATE TABLE statement. It does not matter if the ** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY ** KEY may consist of a single column, or may be a composite key. -** +** ** It is not an error if the named table does not exist in the database. Nor ** is it an error if the named table does not have a PRIMARY KEY. However, ** no changes will be recorded in either of these scenarios. @@ -8744,8 +10694,37 @@ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect) ** Changes are not recorded for individual rows that have NULL values stored ** in one or more of their PRIMARY KEY columns. ** -** SQLITE_OK is returned if the call completes without error. Or, if an error +** SQLITE_OK is returned if the call completes without error. Or, if an error ** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned. +** +**

    Special sqlite_stat1 Handling

    +** +** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to +** some of the rules above. In SQLite, the schema of sqlite_stat1 is: +**
    +**        CREATE TABLE sqlite_stat1(tbl,idx,stat)
    +**  
    +** +** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are +** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes +** are recorded for rows for which (idx IS NULL) is true. However, for such +** rows a zero-length blob (SQL value X'') is stored in the changeset or +** patchset instead of a NULL value. This allows such changesets to be +** manipulated by legacy implementations of sqlite3changeset_invert(), +** concat() and similar. +** +** The sqlite3changeset_apply() function automatically converts the +** zero-length blob back to a NULL value when updating the sqlite_stat1 +** table. However, if the application calls sqlite3changeset_new(), +** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset +** iterator directly (including on a changeset iterator passed to a +** conflict-handler callback) then the X'' value is returned. The application +** must translate X'' to NULL itself if required. +** +** Legacy (older than 3.22.0) versions of the sessions module cannot capture +** changes made to the sqlite_stat1 table. Legacy versions of the +** sqlite3changeset_apply() function silently ignore any modifications to the +** sqlite_stat1 table that are part of a changeset or patchset. */ SQLITE_API int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ @@ -8754,11 +10733,12 @@ SQLITE_API int sqlite3session_attach( /* ** CAPI3REF: Set a table filter on a Session Object. +** METHOD: sqlite3_session ** -** The second argument (xFilter) is the "filter callback". For changes to rows +** The second argument (xFilter) is the "filter callback". For changes to rows ** in tables that are not attached to the Session object, the filter is called -** to determine whether changes to the table's rows should be tracked or not. -** If xFilter returns 0, changes is not tracked. Note that once a table is +** to determine whether changes to the table's rows should be tracked or not. +** If xFilter returns 0, changes are not tracked. Note that once a table is ** attached, xFilter will not be called again. */ SQLITE_API void sqlite3session_table_filter( @@ -8772,10 +10752,11 @@ SQLITE_API void sqlite3session_table_filter( /* ** CAPI3REF: Generate A Changeset From A Session Object +** METHOD: sqlite3_session ** -** Obtain a changeset containing changes to the tables attached to the -** session object passed as the first argument. If successful, -** set *ppChangeset to point to a buffer containing the changeset +** Obtain a changeset containing changes to the tables attached to the +** session object passed as the first argument. If successful, +** set *ppChangeset to point to a buffer containing the changeset ** and *pnChangeset to the size of the changeset in bytes before returning ** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to ** zero and return an SQLite error code. @@ -8790,7 +10771,7 @@ SQLITE_API void sqlite3session_table_filter( ** modifies the values of primary key columns. If such a change is made, it ** is represented in a changeset as a DELETE followed by an INSERT. ** -** Changes are not recorded for rows that have NULL values stored in one or +** Changes are not recorded for rows that have NULL values stored in one or ** more of their PRIMARY KEY columns. If such a row is inserted or deleted, ** no corresponding change is present in the changesets returned by this ** function. If an existing row with one or more NULL values stored in @@ -8843,14 +10824,14 @@ SQLITE_API void sqlite3session_table_filter( **
      **
    • For each record generated by an insert, the database is queried ** for a row with a matching primary key. If one is found, an INSERT -** change is added to the changeset. If no such row is found, no change +** change is added to the changeset. If no such row is found, no change ** is added to the changeset. ** -**
    • For each record generated by an update or delete, the database is +**
    • For each record generated by an update or delete, the database is ** queried for a row with a matching primary key. If such a row is ** found and one or more of the non-primary key fields have been -** modified from their original values, an UPDATE change is added to -** the changeset. Or, if no such row is found in the table, a DELETE +** modified from their original values, an UPDATE change is added to +** the changeset. Or, if no such row is found in the table, a DELETE ** change is added to the changeset. If there is a row with a matching ** primary key in the database, but all fields contain their original ** values, no change is added to the changeset. @@ -8858,7 +10839,7 @@ SQLITE_API void sqlite3session_table_filter( ** ** This means, amongst other things, that if a row is inserted and then later ** deleted while a session object is active, neither the insert nor the delete -** will be present in the changeset. Or if a row is deleted and then later a +** will be present in the changeset. Or if a row is deleted and then later a ** row with the same primary key values inserted while a session object is ** active, the resulting changeset will contain an UPDATE change instead of ** a DELETE and an INSERT. @@ -8867,10 +10848,10 @@ SQLITE_API void sqlite3session_table_filter( ** it does not accumulate records when rows are inserted, updated or deleted. ** This may appear to have some counter-intuitive effects if a single row ** is written to more than once during a session. For example, if a row -** is inserted while a session object is enabled, then later deleted while +** is inserted while a session object is enabled, then later deleted while ** the same session object is disabled, no INSERT record will appear in the ** changeset, even though the delete took place while the session was disabled. -** Or, if one field of a row is updated while a session is disabled, and +** Or, if one field of a row is updated while a session is disabled, and ** another field of the same row is updated while the session is enabled, the ** resulting changeset will contain an UPDATE change that updates both fields. */ @@ -8881,7 +10862,24 @@ SQLITE_API int sqlite3session_changeset( ); /* -** CAPI3REF: Load The Difference Between Tables Into A Session +** CAPI3REF: Return An Upper-limit For The Size Of The Changeset +** METHOD: sqlite3_session +** +** By default, this function always returns 0. For it to return +** a useful result, the sqlite3_session object must have been configured +** to enable this API using sqlite3session_object_config() with the +** SQLITE_SESSION_OBJCONFIG_SIZE verb. +** +** When enabled, this function returns an upper limit, in bytes, for the size +** of the changeset that might be produced if sqlite3session_changeset() were +** called. The final changeset size might be equal to or smaller than the +** size in bytes returned by this function. +*/ +SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession); + +/* +** CAPI3REF: Load The Difference Between Tables Into A Session +** METHOD: sqlite3_session ** ** If it is not already attached to the session object passed as the first ** argument, this function attaches table zTbl in the same manner as the @@ -8890,7 +10888,7 @@ SQLITE_API int sqlite3session_changeset( ** an error). ** ** Argument zFromDb must be the name of a database ("main", "temp" etc.) -** attached to the same database handle as the session object that contains +** attached to the same database handle as the session object that contains ** a table compatible with the table attached to the session by this function. ** A table is considered compatible if it: ** @@ -8906,33 +10904,33 @@ SQLITE_API int sqlite3session_changeset( ** APIs, tables without PRIMARY KEYs are simply ignored. ** ** This function adds a set of changes to the session object that could be -** used to update the table in database zFrom (call this the "from-table") -** so that its content is the same as the table attached to the session +** used to update the table in database zFrom (call this the "from-table") +** so that its content is the same as the table attached to the session ** object (call this the "to-table"). Specifically: ** **
        -**
      • For each row (primary key) that exists in the to-table but not in +**
      • For each row (primary key) that exists in the to-table but not in ** the from-table, an INSERT record is added to the session object. ** -**
      • For each row (primary key) that exists in the to-table but not in +**
      • For each row (primary key) that exists in the to-table but not in ** the from-table, a DELETE record is added to the session object. ** -**
      • For each row (primary key) that exists in both tables, but features +**
      • For each row (primary key) that exists in both tables, but features ** different non-PK values in each, an UPDATE record is added to the -** session. +** session. **
      ** ** To clarify, if this function is called and then a changeset constructed -** using [sqlite3session_changeset()], then after applying that changeset to -** database zFrom the contents of the two compatible tables would be +** using [sqlite3session_changeset()], then after applying that changeset to +** database zFrom the contents of the two compatible tables would be ** identical. ** ** It an error if database zFrom does not exist or does not contain the ** required compatible table. ** -** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite +** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg -** may be set to point to a buffer containing an English language error +** may be set to point to a buffer containing an English language error ** message. It is the responsibility of the caller to free this buffer using ** sqlite3_free(). */ @@ -8946,23 +10944,24 @@ SQLITE_API int sqlite3session_diff( /* ** CAPI3REF: Generate A Patchset From A Session Object +** METHOD: sqlite3_session ** ** The differences between a patchset and a changeset are that: ** **
        -**
      • DELETE records consist of the primary key fields only. The +**
      • DELETE records consist of the primary key fields only. The ** original values of other fields are omitted. -**
      • The original values of any modified fields are omitted from +**
      • The original values of any modified fields are omitted from ** UPDATE records. **
      ** -** A patchset blob may be used with up to date versions of all -** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), +** A patchset blob may be used with up to date versions of all +** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(), ** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly, ** attempting to use a patchset blob with old versions of the -** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. +** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error. ** -** Because the non-primary key "old.*" fields are omitted, no +** Because the non-primary key "old.*" fields are omitted, no ** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset ** is passed to the sqlite3changeset_apply() API. Other conflict types work ** in the same way as for changesets. @@ -8974,36 +10973,45 @@ SQLITE_API int sqlite3session_diff( */ SQLITE_API int sqlite3session_patchset( sqlite3_session *pSession, /* Session object */ - int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */ - void **ppPatchset /* OUT: Buffer containing changeset */ + int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void **ppPatchset /* OUT: Buffer containing patchset */ ); /* ** CAPI3REF: Test if a changeset has recorded any changes. ** -** Return non-zero if no changes to attached tables have been recorded by -** the session object passed as the first argument. Otherwise, if one or +** Return non-zero if no changes to attached tables have been recorded by +** the session object passed as the first argument. Otherwise, if one or ** more changes have been recorded, return zero. ** ** Even if this function returns zero, it is possible that calling ** [sqlite3session_changeset()] on the session handle may still return a -** changeset that contains no changes. This can happen when a row in -** an attached table is modified and then later on the original values +** changeset that contains no changes. This can happen when a row in +** an attached table is modified and then later on the original values ** are restored. However, if this function returns non-zero, then it is -** guaranteed that a call to sqlite3session_changeset() will return a +** guaranteed that a call to sqlite3session_changeset() will return a ** changeset containing zero changes. */ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); /* -** CAPI3REF: Create An Iterator To Traverse A Changeset +** CAPI3REF: Query for the amount of heap memory used by a session object. +** +** This API returns the total amount of heap memory in bytes currently +** used by the session object passed as the only argument. +*/ +SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession); + +/* +** CAPI3REF: Create An Iterator To Traverse A Changeset +** CONSTRUCTOR: sqlite3_changeset_iter ** ** Create an iterator used to iterate through the contents of a changeset. ** If successful, *pp is set to point to the iterator handle and SQLITE_OK ** is returned. Otherwise, if an error occurs, *pp is set to zero and an ** SQLite error code is returned. ** -** The following functions can be used to advance and query a changeset +** The following functions can be used to advance and query a changeset ** iterator created by this function: ** **
        @@ -9020,25 +11028,52 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession); ** ** Assuming the changeset blob was created by one of the ** [sqlite3session_changeset()], [sqlite3changeset_concat()] or -** [sqlite3changeset_invert()] functions, all changes within the changeset -** that apply to a single table are grouped together. This means that when -** an application iterates through a changeset using an iterator created by -** this function, all changes that relate to a single table are visited -** consecutively. There is no chance that the iterator will visit a change -** the applies to table X, then one for table Y, and then later on visit +** [sqlite3changeset_invert()] functions, all changes within the changeset +** that apply to a single table are grouped together. This means that when +** an application iterates through a changeset using an iterator created by +** this function, all changes that relate to a single table are visited +** consecutively. There is no chance that the iterator will visit a change +** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +SQLITE_API int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
        SQLITE_CHANGESETAPPLY_INVERT
        +** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* ** CAPI3REF: Advance A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** -** This function may only be used with iterators created by function +** This function may only be used with iterators created by the function ** [sqlite3changeset_start()]. If it is called on an iterator passed to ** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE ** is returned and the call has no effect. @@ -9049,18 +11084,19 @@ SQLITE_API int sqlite3changeset_start( ** point to the first change in the changeset. Each subsequent call advances ** the iterator to point to the next change in the changeset (if any). If ** no error occurs and the iterator points to a valid change after a call -** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. +** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned. ** Otherwise, if all changes in the changeset have already been visited, ** SQLITE_DONE is returned. ** -** If an error occurs, an SQLite error code is returned. Possible error -** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or +** If an error occurs, an SQLite error code is returned. Possible error +** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or ** SQLITE_NOMEM. */ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Obtain The Current Operation From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator @@ -9068,18 +11104,23 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this ** is not the case, this function returns [SQLITE_MISUSE]. ** -** If argument pzTab is not NULL, then *pzTab is set to point to a -** nul-terminated utf-8 encoded string containing the name of the table -** affected by the current change. The buffer remains valid until either -** sqlite3changeset_next() is called on the iterator or until the -** conflict-handler function returns. If pnCol is not NULL, then *pnCol is -** set to the number of columns in the table affected by the change. If -** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change +** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three +** outputs are set through these pointers: +** +** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], +** depending on the type of change that the iterator currently points to; +** +** *pnCol is set to the number of columns in the table affected by the change; and +** +** *pzTab is set to point to a nul-terminated utf-8 encoded string containing +** the name of the table affected by the current change. The buffer remains +** valid until either sqlite3changeset_next() is called on the iterator +** or until the conflict-handler function returns. +** +** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change ** is an indirect change, or false (0) otherwise. See the documentation for ** [sqlite3session_indirect()] for a description of direct and indirect -** changes. Finally, if pOp is not NULL, then *pOp is set to one of -** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the -** type of change that the iterator currently points to. +** changes. ** ** If no error occurs, SQLITE_OK is returned. If an error does occur, an ** SQLite error code is returned. The values of the output variables may not @@ -9095,6 +11136,7 @@ SQLITE_API int sqlite3changeset_op( /* ** CAPI3REF: Obtain The Primary Key Definition Of A Table +** METHOD: sqlite3_changeset_iter ** ** For each modified table, a changeset includes the following: ** @@ -9126,11 +11168,12 @@ SQLITE_API int sqlite3changeset_pk( /* ** CAPI3REF: Obtain old.* Values From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent -** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. @@ -9140,9 +11183,9 @@ SQLITE_API int sqlite3changeset_pk( ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the vector of +** sqlite3_value object containing the iVal'th value from the vector of ** original row values stored as part of the UPDATE or DELETE change and -** returns SQLITE_OK. The name of the function comes from the fact that this +** returns SQLITE_OK. The name of the function comes from the fact that this ** is similar to the "old.*" columns available to update or delete triggers. ** ** If some other error occurs (e.g. an OOM condition), an SQLite error code @@ -9156,11 +11199,12 @@ SQLITE_API int sqlite3changeset_old( /* ** CAPI3REF: Obtain new.* Values From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent -** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. +** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, ** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL. @@ -9170,12 +11214,12 @@ SQLITE_API int sqlite3changeset_old( ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the vector of +** sqlite3_value object containing the iVal'th value from the vector of ** new row values stored as part of the UPDATE or INSERT change and ** returns SQLITE_OK. If the change is an UPDATE and does not include -** a new value for the requested column, *ppValue is set to NULL and -** SQLITE_OK returned. The name of the function comes from the fact that -** this is similar to the "new.*" columns available to update or delete +** a new value for the requested column, *ppValue is set to NULL and +** SQLITE_OK returned. The name of the function comes from the fact that +** this is similar to the "new.*" columns available to update or delete ** triggers. ** ** If some other error occurs (e.g. an OOM condition), an SQLite error code @@ -9189,6 +11233,7 @@ SQLITE_API int sqlite3changeset_new( /* ** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** This function should only be used with iterator objects passed to a ** conflict-handler callback by [sqlite3changeset_apply()] with either @@ -9201,7 +11246,7 @@ SQLITE_API int sqlite3changeset_new( ** [SQLITE_RANGE] is returned and *ppValue is set to NULL. ** ** If successful, this function sets *ppValue to point to a protected -** sqlite3_value object containing the iVal'th value from the +** sqlite3_value object containing the iVal'th value from the ** "conflicting row" associated with the current conflict-handler callback ** and returns SQLITE_OK. ** @@ -9216,6 +11261,7 @@ SQLITE_API int sqlite3changeset_conflict( /* ** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations +** METHOD: sqlite3_changeset_iter ** ** This function may only be called with an iterator passed to an ** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case @@ -9232,6 +11278,7 @@ SQLITE_API int sqlite3changeset_fk_conflicts( /* ** CAPI3REF: Finalize A Changeset Iterator +** METHOD: sqlite3_changeset_iter ** ** This function is used to finalize an iterator allocated with ** [sqlite3changeset_start()]. @@ -9243,19 +11290,21 @@ SQLITE_API int sqlite3changeset_fk_conflicts( ** call has no effect. ** ** If an error was encountered within a call to an sqlite3changeset_xxx() -** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an +** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an ** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding ** to that error is returned by this function. Otherwise, SQLITE_OK is ** returned. This is to allow the following pattern (pseudo-code): ** +**
         **   sqlite3changeset_start();
         **   while( SQLITE_ROW==sqlite3changeset_next() ){
         **     // Do something with change.
         **   }
         **   rc = sqlite3changeset_finalize();
         **   if( rc!=SQLITE_OK ){
        -**     // An error has occurred 
        +**     // An error has occurred
         **   }
        +** 
        */ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); @@ -9281,7 +11330,7 @@ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); ** zeroed and an SQLite error code returned. ** ** It is the responsibility of the caller to eventually call sqlite3_free() -** on the *ppOut pointer to free the buffer allocation following a successful +** on the *ppOut pointer to free the buffer allocation following a successful ** call to this function. ** ** WARNING/TODO: This function currently assumes that the input is a valid @@ -9295,14 +11344,15 @@ SQLITE_API int sqlite3changeset_invert( /* ** CAPI3REF: Concatenate Two Changeset Objects ** -** This function is used to concatenate two changesets, A and B, into a +** This function is used to concatenate two changesets, A and B, into a ** single changeset. The result is a changeset equivalent to applying -** changeset A followed by changeset B. +** changeset A followed by changeset B. ** -** This function combines the two input changesets using an +** This function combines the two input changesets using an ** sqlite3_changegroup object. Calling it produces similar results as the ** following code fragment: ** +**
         **   sqlite3_changegroup *pGrp;
         **   rc = sqlite3_changegroup_new(&pGrp);
         **   if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
        @@ -9313,6 +11363,7 @@ SQLITE_API int sqlite3changeset_invert(
         **     *ppOut = 0;
         **     *pnOut = 0;
         **   }
        +** 
        ** ** Refer to the sqlite3_changegroup documentation below for details. */ @@ -9328,11 +11379,15 @@ SQLITE_API int sqlite3changeset_concat( /* ** CAPI3REF: Changegroup Handle +** +** A changegroup is an object used to combine two or more +** [changesets] or [patchsets] */ typedef struct sqlite3_changegroup sqlite3_changegroup; /* ** CAPI3REF: Create A New Changegroup Object +** CONSTRUCTOR: sqlite3_changegroup ** ** An sqlite3_changegroup object is used to combine two or more changesets ** (or patchsets) into a single changeset (or patchset). A single changegroup @@ -9341,7 +11396,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; ** ** If successful, this function returns SQLITE_OK and populates (*pp) with ** a pointer to a new sqlite3_changegroup object before returning. The caller -** should eventually free the returned object using a call to +** should eventually free the returned object using a call to ** sqlite3changegroup_delete(). If an error occurs, an SQLite error code ** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL. ** @@ -9353,7 +11408,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; **
      • Zero or more changesets (or patchsets) are added to the object ** by calling sqlite3changegroup_add(). ** -**
      • The result of combining all input changesets together is obtained +**
      • The result of combining all input changesets together is obtained ** by the application via a call to sqlite3changegroup_output(). ** **
      • The object is deleted using a call to sqlite3changegroup_delete(). @@ -9362,17 +11417,18 @@ typedef struct sqlite3_changegroup sqlite3_changegroup; ** Any number of calls to add() and output() may be made between the calls to ** new() and delete(), and in any order. ** -** As well as the regular sqlite3changegroup_add() and +** As well as the regular sqlite3changegroup_add() and ** sqlite3changegroup_output() functions, also available are the streaming ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). */ -int sqlite3changegroup_new(sqlite3_changegroup **pp); +SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp); /* ** CAPI3REF: Add A Changeset To A Changegroup +** METHOD: sqlite3_changegroup ** ** Add all changes within the changeset (or patchset) in buffer pData (size -** nData bytes) to the changegroup. +** nData bytes) to the changegroup. ** ** If the buffer contains a patchset, then all prior calls to this function ** on the same changegroup object must also have specified patchsets. Or, if @@ -9399,7 +11455,7 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp); ** changeset was recorded immediately after the changesets already ** added to the changegroup. ** INSERT UPDATE -** The INSERT change remains in the changegroup. The values in the +** The INSERT change remains in the changegroup. The values in the ** INSERT change are modified as if the row was inserted by the ** existing change and then updated according to the new change. ** INSERT DELETE @@ -9410,17 +11466,17 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp); ** changeset was recorded immediately after the changesets already ** added to the changegroup. ** UPDATE UPDATE -** The existing UPDATE remains within the changegroup. It is amended -** so that the accompanying values are as if the row was updated once +** The existing UPDATE remains within the changegroup. It is amended +** so that the accompanying values are as if the row was updated once ** by the existing change and then again by the new change. ** UPDATE DELETE ** The existing UPDATE is replaced by the new DELETE within the ** changegroup. ** DELETE INSERT ** If one or more of the column values in the row inserted by the -** new change differ from those in the row deleted by the existing +** new change differ from those in the row deleted by the existing ** change, the existing DELETE is replaced by an UPDATE within the -** changegroup. Otherwise, if the inserted row is exactly the same +** changegroup. Otherwise, if the inserted row is exactly the same ** as the deleted row, the existing DELETE is simply discarded. ** DELETE UPDATE ** The new change is ignored. This case does not occur if the new @@ -9438,15 +11494,16 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp); ** case, this function fails with SQLITE_SCHEMA. If the input changeset ** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is ** returned. Or, if an out-of-memory condition occurs during processing, this -** function returns SQLITE_NOMEM. In all cases, if an error occurs the -** final contents of the changegroup is undefined. +** function returns SQLITE_NOMEM. In all cases, if an error occurs the state +** of the final contents of the changegroup is undefined. ** ** If no error occurs, SQLITE_OK is returned. */ -int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); +SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup +** METHOD: sqlite3_changegroup ** ** Obtain a buffer containing a changeset (or patchset) representing the ** current contents of the changegroup. If the inputs to the changegroup @@ -9464,12 +11521,12 @@ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); ** ** If an error occurs, an SQLite error code is returned and the output ** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK -** is returned and the output variables are set to the size of and a +** is returned and the output variables are set to the size of and a ** pointer to the output buffer, respectively. In this case it is the ** responsibility of the caller to eventually free the buffer using a ** call to sqlite3_free(). */ -int sqlite3changegroup_output( +SQLITE_API int sqlite3changegroup_output( sqlite3_changegroup*, int *pnData, /* OUT: Size of output buffer in bytes */ void **ppData /* OUT: Pointer to output buffer */ @@ -9477,36 +11534,36 @@ int sqlite3changegroup_output( /* ** CAPI3REF: Delete A Changegroup Object +** DESTRUCTOR: sqlite3_changegroup */ -void sqlite3changegroup_delete(sqlite3_changegroup*); +SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); /* ** CAPI3REF: Apply A Changeset To A Database ** -** Apply a changeset to a database. This function attempts to update the -** "main" database attached to handle db with the changes found in the -** changeset passed via the second and third arguments. +** Apply a changeset or patchset to a database. These functions attempt to +** update the "main" database attached to handle db with the changes found in +** the changeset passed via the second and third arguments. ** -** The fourth argument (xFilter) passed to this function is the "filter +** The fourth argument (xFilter) passed to these functions is the "filter ** callback". If it is not NULL, then for each table affected by at least one ** change in the changeset, the filter callback is invoked with ** the table name as the second argument, and a copy of the context pointer -** passed as the sixth argument to this function as the first. If the "filter -** callback" returns zero, then no attempt is made to apply any changes to -** the table. Otherwise, if the return value is non-zero or the xFilter -** argument to this function is NULL, all changes related to the table are -** attempted. -** -** For each table that is not excluded by the filter callback, this function -** tests that the target database contains a compatible table. A table is +** passed as the sixth argument as the first. If the "filter callback" +** returns zero, then no attempt is made to apply any changes to the table. +** Otherwise, if the return value is non-zero or the xFilter argument to +** is NULL, all changes related to the table are attempted. +** +** For each table that is not excluded by the filter callback, this function +** tests that the target database contains a compatible table. A table is ** considered compatible if all of the following are true: ** **
          -**
        • The table has the same name as the name recorded in the +**
        • The table has the same name as the name recorded in the ** changeset, and -**
        • The table has at least as many columns as recorded in the +**
        • The table has at least as many columns as recorded in the ** changeset, and -**
        • The table has primary key columns in the same position as +**
        • The table has primary key columns in the same position as ** recorded in the changeset. **
        ** @@ -9515,11 +11572,11 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most ** one such warning is issued for each table in the changeset. ** -** For each change for which there is a compatible table, an attempt is made -** to modify the table contents according to the UPDATE, INSERT or DELETE -** change. If a change cannot be applied cleanly, the conflict handler -** function passed as the fifth argument to sqlite3changeset_apply() may be -** invoked. A description of exactly when the conflict handler is invoked for +** For each change for which there is a compatible table, an attempt is made +** to modify the table contents according to the UPDATE, INSERT or DELETE +** change. If a change cannot be applied cleanly, the conflict handler +** function passed as the fifth argument to sqlite3changeset_apply() may be +** invoked. A description of exactly when the conflict handler is invoked for ** each type of change is below. ** ** Unlike the xFilter argument, xConflict may not be passed NULL. The results @@ -9527,23 +11584,23 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** argument are undefined. ** ** Each time the conflict handler function is invoked, it must return one -** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or +** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or ** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned ** if the second argument passed to the conflict handler is either ** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler ** returns an illegal value, any changes already made are rolled back and -** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different +** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different ** actions are taken by sqlite3changeset_apply() depending on the value ** returned by each invocation of the conflict-handler function. Refer to -** the documentation for the three +** the documentation for the three ** [SQLITE_CHANGESET_OMIT|available return values] for details. ** **
        **
        DELETE Changes
        -** For each DELETE change, this function checks if the target database -** contains a row with the same primary key value (or values) as the -** original row values stored in the changeset. If it does, and the values -** stored in all non-primary key columns also match the values stored in +** For each DELETE change, the function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values +** stored in all non-primary key columns also match the values stored in ** the changeset the row is deleted from the target database. ** ** If a row with matching primary key values is found, but one or more of @@ -9572,22 +11629,22 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** database table, the trailing fields are populated with their default ** values. ** -** If the attempt to insert the row fails because the database already +** If the attempt to insert the row fails because the database already ** contains a row with the same primary key values, the conflict handler -** function is invoked with the second argument set to +** function is invoked with the second argument set to ** [SQLITE_CHANGESET_CONFLICT]. ** ** If the attempt to insert the row fails because of some other constraint -** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is +** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is ** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT]. -** This includes the case where the INSERT operation is re-attempted because -** an earlier call to the conflict handler function returned +** This includes the case where the INSERT operation is re-attempted because +** an earlier call to the conflict handler function returned ** [SQLITE_CHANGESET_REPLACE]. ** **
        UPDATE Changes
        -** For each UPDATE change, this function checks if the target database -** contains a row with the same primary key value (or values) as the -** original row values stored in the changeset. If it does, and the values +** For each UPDATE change, the function checks if the target database +** contains a row with the same primary key value (or values) as the +** original row values stored in the changeset. If it does, and the values ** stored in all modified non-primary key columns also match the values ** stored in the changeset the row is updated within the target database. ** @@ -9603,24 +11660,41 @@ void sqlite3changegroup_delete(sqlite3_changegroup*); ** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND] ** passed as the second argument. ** -** If the UPDATE operation is attempted, but SQLite returns -** SQLITE_CONSTRAINT, the conflict-handler function is invoked with +** If the UPDATE operation is attempted, but SQLite returns +** SQLITE_CONSTRAINT, the conflict-handler function is invoked with ** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument. -** This includes the case where the UPDATE operation is attempted after +** This includes the case where the UPDATE operation is attempted after ** an earlier call to the conflict handler function returned -** [SQLITE_CHANGESET_REPLACE]. +** [SQLITE_CHANGESET_REPLACE]. **
        ** ** It is safe to execute SQL statements, including those that write to the ** table that the callback related to, from within the xConflict callback. -** This can be used to further customize the applications conflict +** This can be used to further customize the application's conflict ** resolution strategy. ** -** All changes made by this function are enclosed in a savepoint transaction. +** All changes made by these functions are enclosed in a savepoint transaction. ** If any other error (aside from a constraint failure when attempting to ** write to the target database) occurs, then the savepoint transaction is -** rolled back, restoring the target database to its original state, and an +** rolled back, restoring the target database to its original state, and an ** SQLite error code returned. +** +** If the output parameters (ppRebase) and (pnRebase) are non-NULL and +** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2() +** may set (*ppRebase) to point to a "rebase" that may be used with the +** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase) +** is set to the size of the buffer in bytes. It is the responsibility of the +** caller to eventually free any such buffer using sqlite3_free(). The buffer +** is only allocated and populated if one or more conflicts were encountered +** while applying the patchset. See comments surrounding the sqlite3_rebaser +** APIs for further details. +** +** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter. +** +** Note that the sqlite3changeset_apply_v2() API is still experimental +** and therefore subject to change. */ SQLITE_API int sqlite3changeset_apply( sqlite3 *db, /* Apply change to "main" db of this handle */ @@ -9637,8 +11711,49 @@ SQLITE_API int sqlite3changeset_apply( ), void *pCtx /* First argument passed to xConflict */ ); +SQLITE_API int sqlite3changeset_apply_v2( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, /* OUT: Rebase data */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ +); -/* +/* +** CAPI3REF: Flags for sqlite3changeset_apply_v2 +** +** The following flags may passed via the 9th parameter to +** [sqlite3changeset_apply_v2] and [sqlite3changeset_apply_v2_strm]: +** +**
        +**
        SQLITE_CHANGESETAPPLY_NOSAVEPOINT
        +** Usually, the sessions module encloses all operations performed by +** a single call to apply_v2() or apply_v2_strm() in a [SAVEPOINT]. The +** SAVEPOINT is committed if the changeset or patchset is successfully +** applied, or rolled back if an error occurs. Specifying this flag +** causes the sessions module to omit this savepoint. In this case, if the +** caller has an open transaction or savepoint when apply_v2() is called, +** it may revert the partially applied changeset by rolling it back. +** +**
        SQLITE_CHANGESETAPPLY_INVERT
        +** Invert the changeset before applying it. This is equivalent to inverting +** a changeset using sqlite3changeset_invert() before applying it. It is +** an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 + +/* ** CAPI3REF: Constants Passed To The Conflict Handler ** ** Values that may be passed as the second argument to a conflict-handler. @@ -9647,32 +11762,32 @@ SQLITE_API int sqlite3changeset_apply( **
        SQLITE_CHANGESET_DATA
        ** The conflict handler is invoked with CHANGESET_DATA as the second argument ** when processing a DELETE or UPDATE change if a row with the required -** PRIMARY KEY fields is present in the database, but one or more other -** (non primary-key) fields modified by the update do not contain the +** PRIMARY KEY fields is present in the database, but one or more other +** (non primary-key) fields modified by the update do not contain the ** expected "before" values. -** +** ** The conflicting row, in this case, is the database row with the matching ** primary key. -** +** **
        SQLITE_CHANGESET_NOTFOUND
        ** The conflict handler is invoked with CHANGESET_NOTFOUND as the second ** argument when processing a DELETE or UPDATE change if a row with the ** required PRIMARY KEY fields is not present in the database. -** +** ** There is no conflicting row in this case. The results of invoking the ** sqlite3changeset_conflict() API are undefined. -** +** **
        SQLITE_CHANGESET_CONFLICT
        ** CHANGESET_CONFLICT is passed as the second argument to the conflict -** handler while processing an INSERT change if the operation would result +** handler while processing an INSERT change if the operation would result ** in duplicate primary key values. -** +** ** The conflicting row in this case is the database row with the matching ** primary key. ** **
        SQLITE_CHANGESET_FOREIGN_KEY
        ** If foreign key handling is enabled, and applying a changeset leaves the -** database in a state containing foreign key violations, the conflict +** database in a state containing foreign key violations, the conflict ** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument ** exactly once before the changeset is committed. If the conflict handler ** returns CHANGESET_OMIT, the changes, including those that caused the @@ -9682,12 +11797,12 @@ SQLITE_API int sqlite3changeset_apply( ** No current or conflicting row information is provided. The only function ** it is possible to call on the supplied sqlite3_changeset_iter handle ** is sqlite3changeset_fk_conflicts(). -** +** **
        SQLITE_CHANGESET_CONSTRAINT
        -** If any other constraint violation occurs while applying a change (i.e. -** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is +** If any other constraint violation occurs while applying a change (i.e. +** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is ** invoked with CHANGESET_CONSTRAINT as the second argument. -** +** ** There is no conflicting row in this case. The results of invoking the ** sqlite3changeset_conflict() API are undefined. ** @@ -9699,7 +11814,7 @@ SQLITE_API int sqlite3changeset_apply( #define SQLITE_CHANGESET_CONSTRAINT 4 #define SQLITE_CHANGESET_FOREIGN_KEY 5 -/* +/* ** CAPI3REF: Constants Returned By The Conflict Handler ** ** A conflict handler callback must return one of the following three values. @@ -9707,13 +11822,13 @@ SQLITE_API int sqlite3changeset_apply( **
        **
        SQLITE_CHANGESET_OMIT
        ** If a conflict handler returns this value no special action is taken. The -** change that caused the conflict is not applied. The session module +** change that caused the conflict is not applied. The session module ** continues to the next change in the changeset. ** **
        SQLITE_CHANGESET_REPLACE
        ** This value may only be returned if the second argument to the conflict ** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this -** is not the case, any changes applied so far are rolled back and the +** is not the case, any changes applied so far are rolled back and the ** call to sqlite3changeset_apply() returns SQLITE_MISUSE. ** ** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict @@ -9726,7 +11841,7 @@ SQLITE_API int sqlite3changeset_apply( ** the original row is restored to the database before continuing. ** **
        SQLITE_CHANGESET_ABORT
        -** If this value is returned, any changes applied so far are rolled back +** If this value is returned, any changes applied so far are rolled back ** and the call to sqlite3changeset_apply() returns SQLITE_ABORT. **
        */ @@ -9734,27 +11849,183 @@ SQLITE_API int sqlite3changeset_apply( #define SQLITE_CHANGESET_REPLACE 1 #define SQLITE_CHANGESET_ABORT 2 +/* +** CAPI3REF: Rebasing changesets +** EXPERIMENTAL +** +** Suppose there is a site hosting a database in state S0. And that +** modifications are made that move that database to state S1 and a +** changeset recorded (the "local" changeset). Then, a changeset based +** on S0 is received from another site (the "remote" changeset) and +** applied to the database. The database is then in state +** (S1+"remote"), where the exact state depends on any conflict +** resolution decisions (OMIT or REPLACE) made while applying "remote". +** Rebasing a changeset is to update it to take those conflict +** resolution decisions into account, so that the same conflicts +** do not have to be resolved elsewhere in the network. +** +** For example, if both the local and remote changesets contain an +** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)": +** +** local: INSERT INTO t1 VALUES(1, 'v1'); +** remote: INSERT INTO t1 VALUES(1, 'v2'); +** +** and the conflict resolution is REPLACE, then the INSERT change is +** removed from the local changeset (it was overridden). Or, if the +** conflict resolution was "OMIT", then the local changeset is modified +** to instead contain: +** +** UPDATE t1 SET b = 'v2' WHERE a=1; +** +** Changes within the local changeset are rebased as follows: +** +**
        +**
        Local INSERT
        +** This may only conflict with a remote INSERT. If the conflict +** resolution was OMIT, then add an UPDATE change to the rebased +** changeset. Or, if the conflict resolution was REPLACE, add +** nothing to the rebased changeset. +** +**
        Local DELETE
        +** This may conflict with a remote UPDATE or DELETE. In both cases the +** only possible resolution is OMIT. If the remote operation was a +** DELETE, then add no change to the rebased changeset. If the remote +** operation was an UPDATE, then the old.* fields of change are updated +** to reflect the new.* values in the UPDATE. +** +**
        Local UPDATE
        +** This may conflict with a remote UPDATE or DELETE. If it conflicts +** with a DELETE, and the conflict resolution was OMIT, then the update +** is changed into an INSERT. Any undefined values in the new.* record +** from the update change are filled in using the old.* values from +** the conflicting DELETE. Or, if the conflict resolution was REPLACE, +** the UPDATE change is simply omitted from the rebased changeset. +** +** If conflict is with a remote UPDATE and the resolution is OMIT, then +** the old.* values are rebased using the new.* values in the remote +** change. Or, if the resolution is REPLACE, then the change is copied +** into the rebased changeset with updates to columns also updated by +** the conflicting remote UPDATE removed. If this means no columns would +** be updated, the change is omitted. +**
        +** +** A local change may be rebased against multiple remote changes +** simultaneously. If a single key is modified by multiple remote +** changesets, they are combined as follows before the local changeset +** is rebased: +** +**
          +**
        • If there has been one or more REPLACE resolutions on a +** key, it is rebased according to a REPLACE. +** +**
        • If there have been no REPLACE resolutions on a key, then +** the local changeset is rebased according to the most recent +** of the OMIT resolutions. +**
        +** +** Note that conflict resolutions from multiple remote changesets are +** combined on a per-field basis, not per-row. This means that in the +** case of multiple remote UPDATE operations, some fields of a single +** local change may be rebased for REPLACE while others are rebased for +** OMIT. +** +** In order to rebase a local changeset, the remote changeset must first +** be applied to the local database using sqlite3changeset_apply_v2() and +** the buffer of rebase information captured. Then: +** +**
          +**
        1. An sqlite3_rebaser object is created by calling +** sqlite3rebaser_create(). +**
        2. The new object is configured with the rebase buffer obtained from +** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure(). +** If the local changeset is to be rebased against multiple remote +** changesets, then sqlite3rebaser_configure() should be called +** multiple times, in the same order that the multiple +** sqlite3changeset_apply_v2() calls were made. +**
        3. Each local changeset is rebased by calling sqlite3rebaser_rebase(). +**
        4. The sqlite3_rebaser object is deleted by calling +** sqlite3rebaser_delete(). +**
        +*/ +typedef struct sqlite3_rebaser sqlite3_rebaser; + +/* +** CAPI3REF: Create a changeset rebaser object. +** EXPERIMENTAL +** +** Allocate a new changeset rebaser object. If successful, set (*ppNew) to +** point to the new object and return SQLITE_OK. Otherwise, if an error +** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew) +** to NULL. +*/ +SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew); + +/* +** CAPI3REF: Configure a changeset rebaser object. +** EXPERIMENTAL +** +** Configure the changeset rebaser object to rebase changesets according +** to the conflict resolutions described by buffer pRebase (size nRebase +** bytes), which must have been obtained from a previous call to +** sqlite3changeset_apply_v2(). +*/ +SQLITE_API int sqlite3rebaser_configure( + sqlite3_rebaser*, + int nRebase, const void *pRebase +); + +/* +** CAPI3REF: Rebase a changeset +** EXPERIMENTAL +** +** Argument pIn must point to a buffer containing a changeset nIn bytes +** in size. This function allocates and populates a buffer with a copy +** of the changeset rebased according to the configuration of the +** rebaser object passed as the first argument. If successful, (*ppOut) +** is set to point to the new buffer containing the rebased changeset and +** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the +** responsibility of the caller to eventually free the new buffer using +** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) +** are set to zero and an SQLite error code returned. +*/ +SQLITE_API int sqlite3rebaser_rebase( + sqlite3_rebaser*, + int nIn, const void *pIn, + int *pnOut, void **ppOut +); + +/* +** CAPI3REF: Delete a changeset rebaser object. +** EXPERIMENTAL +** +** Delete the changeset rebaser object and all associated resources. There +** should be one call to this function for each successful invocation +** of sqlite3rebaser_create(). +*/ +SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p); + /* ** CAPI3REF: Streaming Versions of API functions. ** -** The six streaming API xxx_strm() functions serve similar purposes to the +** The six streaming API xxx_strm() functions serve similar purposes to the ** corresponding non-streaming API functions: ** ** ** -**
        Streaming functionNon-streaming equivalent
        sqlite3changeset_apply_str[sqlite3changeset_apply] -**
        sqlite3changeset_concat_str[sqlite3changeset_concat] -**
        sqlite3changeset_invert_str[sqlite3changeset_invert] -**
        sqlite3changeset_start_str[sqlite3changeset_start] -**
        sqlite3session_changeset_str[sqlite3session_changeset] -**
        sqlite3session_patchset_str[sqlite3session_patchset] +**
        sqlite3changeset_apply_strm[sqlite3changeset_apply] +**
        sqlite3changeset_apply_strm_v2[sqlite3changeset_apply_v2] +**
        sqlite3changeset_concat_strm[sqlite3changeset_concat] +**
        sqlite3changeset_invert_strm[sqlite3changeset_invert] +**
        sqlite3changeset_start_strm[sqlite3changeset_start] +**
        sqlite3session_changeset_strm[sqlite3session_changeset] +**
        sqlite3session_patchset_strm[sqlite3session_patchset] **
        ** ** Non-streaming functions that accept changesets (or patchsets) as input -** require that the entire changeset be stored in a single buffer in memory. -** Similarly, those that return a changeset or patchset do so by returning -** a pointer to a single large buffer allocated using sqlite3_malloc(). -** Normally this is convenient. However, if an application running in a +** require that the entire changeset be stored in a single buffer in memory. +** Similarly, those that return a changeset or patchset do so by returning +** a pointer to a single large buffer allocated using sqlite3_malloc(). +** Normally this is convenient. However, if an application running in a ** low-memory environment is required to handle very large changesets, the ** large contiguous memory allocations required can become onerous. ** @@ -9776,12 +12047,12 @@ SQLITE_API int sqlite3changeset_apply( ** ** ** Each time the xInput callback is invoked by the sessions module, the first -** argument passed is a copy of the supplied pIn context pointer. The second -** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no -** error occurs the xInput method should copy up to (*pnData) bytes of data -** into the buffer and set (*pnData) to the actual number of bytes copied -** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) -** should be set to zero to indicate this. Or, if an error occurs, an SQLite +** argument passed is a copy of the supplied pIn context pointer. The second +** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no +** error occurs the xInput method should copy up to (*pnData) bytes of data +** into the buffer and set (*pnData) to the actual number of bytes copied +** before returning SQLITE_OK. If the input is completely exhausted, (*pnData) +** should be set to zero to indicate this. Or, if an error occurs, an SQLite ** error code should be returned. In all cases, if an xInput callback returns ** an error, all processing is abandoned and the streaming API function ** returns a copy of the error code to the caller. @@ -9789,7 +12060,7 @@ SQLITE_API int sqlite3changeset_apply( ** In the case of sqlite3changeset_start_strm(), the xInput callback may be ** invoked by the sessions module at any point during the lifetime of the ** iterator. If such an xInput callback returns an error, the iterator enters -** an error state, whereby all subsequent calls to iterator functions +** an error state, whereby all subsequent calls to iterator functions ** immediately fail with the same error code as returned by xInput. ** ** Similarly, streaming API functions that return changesets (or patchsets) @@ -9819,7 +12090,7 @@ SQLITE_API int sqlite3changeset_apply( ** is immediately abandoned and the streaming API function returns a copy ** of the xOutput error code to the application. ** -** The sessions module never invokes an xOutput callback with the third +** The sessions module never invokes an xOutput callback with the third ** parameter set to a value less than or equal to zero. Other than this, ** no guarantees are made as to the size of the chunks of data returned. */ @@ -9838,6 +12109,23 @@ SQLITE_API int sqlite3changeset_apply_strm( ), void *pCtx /* First argument passed to xConflict */ ); +SQLITE_API int sqlite3changeset_apply_v2_strm( + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags +); SQLITE_API int sqlite3changeset_concat_strm( int (*xInputA)(void *pIn, void *pData, int *pnData), void *pInA, @@ -9857,6 +12145,12 @@ SQLITE_API int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +SQLITE_API int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); SQLITE_API int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), @@ -9867,15 +12161,61 @@ SQLITE_API int sqlite3session_patchset_strm( int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); -int sqlite3changegroup_add_strm(sqlite3_changegroup*, +SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); -int sqlite3changegroup_output_strm(sqlite3_changegroup*, - int (*xOutput)(void *pOut, const void *pData, int nData), +SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, + int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ); +SQLITE_API int sqlite3rebaser_rebase_strm( + sqlite3_rebaser *pRebaser, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut +); + +/* +** CAPI3REF: Configure global parameters +** +** The sqlite3session_config() interface is used to make global configuration +** changes to the sessions module in order to tune it to the specific needs +** of the application. +** +** The sqlite3session_config() interface is not threadsafe. If it is invoked +** while any other thread is inside any other sessions method then the +** results are undefined. Furthermore, if it is invoked after any sessions +** related objects have been created, the results are also undefined. +** +** The first argument to the sqlite3session_config() function must be one +** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The +** interpretation of the (void*) value passed as the second parameter and +** the effect of calling this function depends on the value of the first +** parameter. +** +**
        +**
        SQLITE_SESSION_CONFIG_STRMSIZE
        +** By default, the sessions module streaming interfaces attempt to input +** and output data in approximately 1 KiB chunks. This operand may be used +** to set and query the value of this configuration setting. The pointer +** passed as the second argument must point to a value of type (int). +** If this value is greater than 0, it is used as the new streaming data +** chunk size for both input and output. Before returning, the (int) value +** pointed to by pArg is set to the final value of the streaming interface +** chunk size. +**
        +** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +SQLITE_API int sqlite3session_config(int op, void *pArg); +/* +** CAPI3REF: Values for sqlite3session_config(). +*/ +#define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. @@ -9900,7 +12240,7 @@ int sqlite3changegroup_output_strm(sqlite3_changegroup*, ** ****************************************************************************** ** -** Interfaces to extend FTS5. Using the interfaces defined in this file, +** Interfaces to extend FTS5. Using the interfaces defined in this file, ** FTS5 may be extended with: ** ** * custom tokenizers, and @@ -9944,19 +12284,19 @@ struct Fts5PhraseIter { ** EXTENSION API FUNCTIONS ** ** xUserData(pFts): -** Return a copy of the context pointer the extension function was +** Return a copy of the context pointer the extension function was ** registered with. ** ** xColumnTotalSize(pFts, iCol, pnToken): ** If parameter iCol is less than zero, set output variable *pnToken ** to the total number of tokens in the FTS5 table. Or, if iCol is ** non-negative but less than the number of columns in the table, return -** the total number of tokens in column iCol, considering all rows in +** the total number of tokens in column iCol, considering all rows in ** the FTS5 table. ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is +** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** xColumnCount(pFts): @@ -9970,7 +12310,7 @@ struct Fts5PhraseIter { ** ** If parameter iCol is greater than or equal to the number of columns ** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g. -** an OOM condition or IO error), an appropriate SQLite error code is +** an OOM condition or IO error), an appropriate SQLite error code is ** returned. ** ** This function may be quite inefficient if used with an FTS5 table @@ -9997,8 +12337,8 @@ struct Fts5PhraseIter { ** an error code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always returns 0. ** ** xInst: @@ -10009,15 +12349,11 @@ struct Fts5PhraseIter { ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. The exception is if the table was created -** with the offsets=0 option specified. In this case *piOff is always -** set to -1. -** -** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) -** if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. +** "detail=none" or "detail=column" option. ** ** xRowid: ** Returns the rowid of the current row. @@ -10033,11 +12369,11 @@ struct Fts5PhraseIter { ** ** with $p set to a phrase equivalent to the phrase iPhrase of the ** current query is executed. Any column filter that applies to -** phrase iPhrase of the current query is included in $p. For each -** row visited, the callback function passed as the fourth argument -** is invoked. The context and API objects passed to the callback +** phrase iPhrase of the current query is included in $p. For each +** row visited, the callback function passed as the fourth argument +** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. -** Invoking Api.xUserData() returns a copy of the pointer passed as +** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the @@ -10052,14 +12388,14 @@ struct Fts5PhraseIter { ** ** xSetAuxdata(pFts5, pAux, xDelete) ** -** Save the pointer passed as the second argument as the extension functions +** Save the pointer passed as the second argument as the extension function's ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for -** each FTS query (MATCH expression). If the extension function is invoked -** more than once for a single FTS query, then all invocations share a +** each FTS query (MATCH expression). If the extension function is invoked +** more than once for a single FTS query, then all invocations share a ** single auxiliary data context. ** ** If there is already an auxiliary data pointer when this function is @@ -10070,7 +12406,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -10078,7 +12414,7 @@ struct Fts5PhraseIter { ** ** xGetAuxdata(pFts5, bClear) ** -** Returns the current auxiliary data pointer for the fts5 extension +** Returns the current auxiliary data pointer for the fts5 extension ** function. See the xSetAuxdata() method for details. ** ** If the bClear argument is non-zero, then the auxiliary data is cleared @@ -10098,7 +12434,7 @@ struct Fts5PhraseIter { ** method, to iterate through all instances of a single query phrase within ** the current row. This is the same information as is accessible via the ** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient -** to use, this API may be faster under some circumstances. To iterate +** to use, this API may be faster under some circumstances. To iterate ** through instances of phrase iPhrase, use the following code: ** ** Fts5PhraseIter iter; @@ -10116,8 +12452,8 @@ struct Fts5PhraseIter { ** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below). ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" or "detail=column" option. If the FTS5 table is created -** with either "detail=none" or "detail=column" and "content=" option +** "detail=none" or "detail=column" option. If the FTS5 table is created +** with either "detail=none" or "detail=column" and "content=" option ** (i.e. if it is a contentless table), then this API always iterates ** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** @@ -10141,16 +12477,16 @@ struct Fts5PhraseIter { ** } ** ** This API can be quite slow if used with an FTS5 table created with the -** "detail=none" option. If the FTS5 table is created with either -** "detail=none" "content=" option (i.e. if it is a contentless table), -** then this API always iterates through an empty set (all calls to +** "detail=none" option. If the FTS5 table is created with either +** "detail=none" "content=" option (i.e. if it is a contentless table), +** then this API always iterates through an empty set (all calls to ** xPhraseFirstColumn() set iCol to -1). ** ** The information accessed using this API and its companion ** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext ** (or xInst/xInstCount). The chief advantage of this API is that it is ** significantly more efficient than those alternatives when used with -** "detail=column" tables. +** "detail=column" tables. ** ** xPhraseNextColumn() ** See xPhraseFirstColumn above. @@ -10164,7 +12500,7 @@ struct Fts5ExtensionApi { int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); - int (*xTokenize)(Fts5Context*, + int (*xTokenize)(Fts5Context*, const char *pText, int nText, /* Text to tokenize */ void *pCtx, /* Context passed to xToken() */ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ @@ -10193,15 +12529,15 @@ struct Fts5ExtensionApi { void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; -/* +/* ** CUSTOM AUXILIARY FUNCTIONS *************************************************************************/ /************************************************************************* ** CUSTOM TOKENIZERS ** -** Applications may also register custom tokenizer types. A tokenizer -** is registered by providing fts5 with a populated instance of the +** Applications may also register custom tokenizer types. A tokenizer +** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: @@ -10212,16 +12548,16 @@ struct Fts5ExtensionApi { ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object -** was registered with FTS5 (the third argument to xCreateTokenizer()). +** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used ** to create the FTS5 table. ** -** The final argument is an output variable. If successful, (*ppOut) +** The final argument is an output variable. If successful, (*ppOut) ** should be set to point to the new tokenizer handle and SQLITE_OK ** returned. If an error occurs, some value other than SQLITE_OK should -** be returned. In this case, fts5 assumes that the final value of *ppOut +** be returned. In this case, fts5 assumes that the final value of *ppOut ** is undefined. ** ** xDelete: @@ -10230,7 +12566,7 @@ struct Fts5ExtensionApi { ** be invoked exactly once for each successful call to xCreate(). ** ** xTokenize: -** This function is expected to tokenize the nText byte string indicated +** This function is expected to tokenize the nText byte string indicated ** by argument pText. pText may or may not be nul-terminated. The first ** argument passed to this function is a pointer to an Fts5Tokenizer object ** returned by an earlier call to xCreate(). @@ -10244,8 +12580,8 @@ struct Fts5ExtensionApi { ** determine the set of tokens to add to (or delete from) the ** FTS index. ** -**
      • FTS5_TOKENIZE_QUERY - A MATCH query is being executed -** against the FTS index. The tokenizer is being called to tokenize +**
      • FTS5_TOKENIZE_QUERY - A MATCH query is being executed +** against the FTS index. The tokenizer is being called to tokenize ** a bareword or quoted string specified as part of the query. ** **
      • (FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX) - Same as @@ -10253,10 +12589,10 @@ struct Fts5ExtensionApi { ** followed by a "*" character, indicating that the last token ** returned by the tokenizer will be treated as a token prefix. ** -**
      • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to +**
      • FTS5_TOKENIZE_AUX - The tokenizer is being invoked to ** satisfy an fts5_api.xTokenize() request made by an auxiliary ** function. Or an fts5_api.xColumnSize() request made by the same -** on a columnsize=0 database. +** on a columnsize=0 database. **
      ** ** For each token in the input string, the supplied callback xToken() must @@ -10268,10 +12604,10 @@ struct Fts5ExtensionApi { ** which the token is derived within the input. ** ** The second argument passed to the xToken() callback ("tflags") should -** normally be set to 0. The exception is if the tokenizer supports +** normally be set to 0. The exception is if the tokenizer supports ** synonyms. In this case see the discussion below for details. ** -** FTS5 assumes the xToken() callback is invoked for each token in the +** FTS5 assumes the xToken() callback is invoked for each token in the ** order that they occur within the input text. ** ** If an xToken() callback returns any value other than SQLITE_OK, then @@ -10285,7 +12621,7 @@ struct Fts5ExtensionApi { ** SYNONYM SUPPORT ** ** Custom tokenizers may also support synonyms. Consider a case in which a -** user wishes to query for a phrase such as "first place". Using the +** user wishes to query for a phrase such as "first place". Using the ** built-in tokenizers, the FTS5 query 'first + place' will match instances ** of "first place" within the document set, but not alternative forms ** such as "1st place". In some applications, it would be better to match @@ -10294,8 +12630,8 @@ struct Fts5ExtensionApi { ** ** There are several ways to approach this in FTS5: ** -**
      1. By mapping all synonyms to a single token. In this case, the -** In the above example, this means that the tokenizer returns the +**
        1. By mapping all synonyms to a single token. In this case, using +** the above example, this means that the tokenizer returns the ** same token for inputs "first" and "1st". Say that token is in ** fact "first", so that when the user inserts the document "I won ** 1st place" entries are added to the index for tokens "i", "won", @@ -10303,37 +12639,37 @@ struct Fts5ExtensionApi { ** the tokenizer substitutes "first" for "1st" and the query works ** as expected. ** -**
        2. By adding multiple synonyms for a single term to the FTS index. -** In this case, when tokenizing query text, the tokenizer may -** provide multiple synonyms for a single term within the document. -** FTS5 then queries the index for each synonym individually. For -** example, faced with the query: +**
        3. By querying the index for all synonyms of each query term +** separately. In this case, when tokenizing query text, the +** tokenizer may provide multiple synonyms for a single term +** within the document. FTS5 then queries the index for each +** synonym individually. For example, faced with the query: ** ** ** ... MATCH 'first place' ** ** the tokenizer offers both "1st" and "first" as synonyms for the -** first token in the MATCH query and FTS5 effectively runs a query +** first token in the MATCH query and FTS5 effectively runs a query ** similar to: ** ** ** ... MATCH '(first OR 1st) place' ** ** except that, for the purposes of auxiliary functions, the query -** still appears to contain just two phrases - "(first OR 1st)" +** still appears to contain just two phrases - "(first OR 1st)" ** being treated as a single phrase. ** **
        4. By adding multiple synonyms for a single term to the FTS index. ** Using this method, when tokenizing document text, the tokenizer -** provides multiple synonyms for each token. So that when a +** provides multiple synonyms for each token. So that when a ** document such as "I won first place" is tokenized, entries are ** added to the FTS index for "i", "won", "first", "1st" and ** "place". ** ** This way, even if the tokenizer does not provide synonyms -** when tokenizing query text (it should not - to do would be -** inefficient), it doesn't matter if the user queries for -** 'first + place' or '1st + place', as there are entires in the +** when tokenizing query text (it should not - to do so would be +** inefficient), it doesn't matter if the user queries for +** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. **
        ** @@ -10353,15 +12689,15 @@ struct Fts5ExtensionApi { ** ** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time ** xToken() is called. Multiple synonyms may be specified for a single token -** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. +** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. ** There is no limit to the number of synonyms that may be provided for a ** single token. ** -** In many cases, method (1) above is the best approach. It does not add +** In many cases, method (1) above is the best approach. It does not add ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the -** token "first" is subsituted for "1st" by the tokenizer, then the query: +** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** ** ... MATCH '1s*' @@ -10369,18 +12705,18 @@ struct Fts5ExtensionApi { ** will not match documents that contain the token "1st" (as the tokenizer ** will probably not map "1s" to any prefix of "first"). ** -** For full prefix support, method (3) may be preferred. In this case, +** For full prefix support, method (3) may be preferred. In this case, ** because the index contains entries for both "first" and "1st", prefix ** queries such as 'fi*' or '1s*' will match correctly. However, because ** extra entries are added to the FTS index, this method uses more space ** within the database. ** ** Method (2) offers a midpoint between (1) and (3). Using this method, -** a query such as '1s*' will match documents that contain the literal +** a query such as '1s*' will match documents that contain the literal ** token "1st", but not "first" (assuming the tokenizer is not able to ** provide synonyms for prefixes). However, a non-prefix query like '1st' ** will match against "1st" and "first". This method does not require -** extra disk space, as no extra entries are added to the FTS index. +** extra disk space, as no extra entries are added to the FTS index. ** On the other hand, it may require more CPU cycles to run MATCH queries, ** as separate queries of the FTS index are required for each synonym. ** @@ -10394,10 +12730,10 @@ typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, + int (*xTokenize)(Fts5Tokenizer*, void *pCtx, int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, + const char *pText, int nText, int (*xToken)( void *pCtx, /* Copy of 2nd argument to xTokenize() */ int tflags, /* Mask of FTS5_TOKEN_* flags */ diff --git a/vendor/libraries/zlib/Library.cmake b/vendor/libraries/zlib/Library.cmake index f4819c3014..70a4bd2853 100644 --- a/vendor/libraries/zlib/Library.cmake +++ b/vendor/libraries/zlib/Library.cmake @@ -7,7 +7,12 @@ else(DUNE_CXX_GNU AND DUNE_OS_WINDOWS) set(ZLIB_CFLAGS "") endif(DUNE_CXX_GNU AND DUNE_OS_WINDOWS) +check_cxx_compiler_flag(-Wimplicit-fallthrough=0 _has_wimplicit_fallthrough_0) +if(_has_wimplicit_fallthrough_0) + set(_zlib_extra_cflags -Wimplicit-fallthrough=0) +endif() + set_source_files_properties(${DUNE_ZLIB_FILES} - PROPERTIES COMPILE_FLAGS "${DUNE_C_FLAGS} ${DUNE_C_FLAGS_STRICT} ${ZLIB_CFLAGS}") + PROPERTIES COMPILE_FLAGS "${DUNE_C_FLAGS} ${DUNE_C_FLAGS_STRICT} ${ZLIB_CFLAGS} ${_zlib_extra_cflags}") list(APPEND DUNE_VENDOR_FILES ${DUNE_ZLIB_FILES}) diff --git a/vendor/matlab/llftools-1.2.0/filter_entity.m b/vendor/matlab/llftools-1.2.0/filter_entity.m index d107219c3a..1da3e21fd9 100644 --- a/vendor/matlab/llftools-1.2.0/filter_entity.m +++ b/vendor/matlab/llftools-1.2.0/filter_entity.m @@ -1,5 +1,5 @@ %+--------------------------------------------------------------------------+ -%| Copyright (C) 2007-2017 Laboratório de Sistemas e Tecnologia Subaquática | +%| Copyright (C) 2007-2023 Laboratório de Sistemas e Tecnologia Subaquática | %| Departamento de Engenharia Electrotécnica e de Computadores | %| Rua Dr. Roberto Frias, 4200-465 Porto, Portugal | %+--------------------------------------------------------------------------+ diff --git a/vendor/matlab/llftools-1.2.0/llfload.m b/vendor/matlab/llftools-1.2.0/llfload.m index 4dc97d32f4..836241f3c2 100644 --- a/vendor/matlab/llftools-1.2.0/llfload.m +++ b/vendor/matlab/llftools-1.2.0/llfload.m @@ -1,5 +1,5 @@ %+--------------------------------------------------------------------------+ -%| Copyright (C) 2007-2017 Laboratório de Sistemas e Tecnologia Subaquática | +%| Copyright (C) 2007-2023 Laboratório de Sistemas e Tecnologia Subaquática | %| Departamento de Engenharia Electrotécnica e de Computadores | %| Rua Dr. Roberto Frias, 4200-465 Porto, Portugal | %+--------------------------------------------------------------------------+ diff --git a/www/css/default.css b/www/css/default.css index f505e7922f..4b458040ed 100644 --- a/www/css/default.css +++ b/www/css/default.css @@ -1,5 +1,5 @@ /*************************************************************************** -* Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +* Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * * Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * **************************************************************************** * This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/index.html b/www/index.html index 11d229adfc..3ced0779a9 100644 --- a/www/index.html +++ b/www/index.html @@ -56,7 +56,7 @@ diff --git a/www/index.js b/www/index.js index 0233791617..013aacc17a 100644 --- a/www/index.js +++ b/www/index.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/AbbrevToLabel.js b/www/js/AbbrevToLabel.js index 5e9b60ab82..9efa66ed9c 100644 --- a/www/js/AbbrevToLabel.js +++ b/www/js/AbbrevToLabel.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Angles.js b/www/js/Angles.js index 3bb4e538e9..4b9e2c198f 100644 --- a/www/js/Angles.js +++ b/www/js/Angles.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/BasicSection.js b/www/js/BasicSection.js index c0da30b8b2..3fc579c976 100644 --- a/www/js/BasicSection.js +++ b/www/js/BasicSection.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Date.js b/www/js/Date.js index 2393698b62..cab3213502 100644 --- a/www/js/Date.js +++ b/www/js/Date.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Gauge.js b/www/js/Gauge.js index 5ec4b713b0..cc582e9a37 100644 --- a/www/js/Gauge.js +++ b/www/js/Gauge.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/HTTP.js b/www/js/HTTP.js index 61682c5bb0..64d43440b8 100644 --- a/www/js/HTTP.js +++ b/www/js/HTTP.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Icons.js b/www/js/Icons.js index bca2bab33b..280e26860a 100644 --- a/www/js/Icons.js +++ b/www/js/Icons.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Logbook.js b/www/js/Logbook.js index b52f7f9d0a..b803cd17b4 100644 --- a/www/js/Logbook.js +++ b/www/js/Logbook.js @@ -14,12 +14,13 @@ Logbook.prototype.update = function() { continue; var msgType = typeAsString(msg.type); - logbookStr += "

        " + + logbookStr = "

        " + "[" + dateToString(msg.timestamp) + "] - " + msgType + " " + "[" + msg.context + "] >> " + msg.text + - "<\p>"; + "<\p>" + + logbookStr; } this.m_base.innerHTML = logbookStr; diff --git a/www/js/Logs.js b/www/js/Logs.js index 96cb059a43..bc857e13ad 100644 --- a/www/js/Logs.js +++ b/www/js/Logs.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Main.js b/www/js/Main.js index c37801d657..e943d4d777 100644 --- a/www/js/Main.js +++ b/www/js/Main.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Power.js b/www/js/Power.js index 97dc701698..0d48b27003 100644 --- a/www/js/Power.js +++ b/www/js/Power.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/ScreenDetection.js b/www/js/ScreenDetection.js index 8fad68a956..8fc3efeb36 100644 --- a/www/js/ScreenDetection.js +++ b/www/js/ScreenDetection.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Sections.js b/www/js/Sections.js index 58e5326811..90459de2e9 100644 --- a/www/js/Sections.js +++ b/www/js/Sections.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Sensors.js b/www/js/Sensors.js index 24801f413f..88a1ded48a 100644 --- a/www/js/Sensors.js +++ b/www/js/Sensors.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/TextLabel.js b/www/js/TextLabel.js index 35ad8880ff..d2b276bb79 100644 --- a/www/js/TextLabel.js +++ b/www/js/TextLabel.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. * diff --git a/www/js/Utils.js b/www/js/Utils.js index 0e41810c2b..4f2bf76e98 100644 --- a/www/js/Utils.js +++ b/www/js/Utils.js @@ -1,5 +1,5 @@ //*************************************************************************** -// Copyright 2007-2017 Universidade do Porto - Faculdade de Engenharia * +// Copyright 2007-2023 Universidade do Porto - Faculdade de Engenharia * // Laboratório de Sistemas e Tecnologia Subaquática (LSTS) * //*************************************************************************** // This file is part of DUNE: Unified Navigation Environment. *